Move gtk plugin from -bad

https://bugzilla.gnome.org/show_bug.cgi?id=754094
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..62aa724
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,67 @@
+aclocal.m4
+autom4te.cache
+config.h
+config.h.in
+config.h-new
+config.log
+config.status
+config.guess
+config.sub
+config.rpath
+configure
+libtool
+stamp-h
+stamp-h.in
+stamp-h1
+gst-element-check-*.m4
+ltmain.sh
+missing
+mkinstalldirs
+compile
+install-sh
+depcomp
+autoregen.sh
+ABOUT-NLS
+/INSTALL
+_stdint.h
+gst-plugins-good-*.tar.*
+.dirstamp
+
+/m4
+
+.deps
+.libs
+*.lo
+*.la
+*.o
+Makefile.in
+Makefile
+*~
+*.swp
+*.gc??
+
+/m4
+
+/ext/dv/smpte_test
+/gst/multifile/test-splitmux-part-reader
+/gst/deinterlace/tvtime.h
+
+tmp-orc.c
+*orc.h
+
+/tests/examples/jack/jack_client
+
+Build
+*.user
+*.suo
+*.ipch
+*.sdf
+*.opensdf
+*.DS_Store
+
+/test-driver
+*.log
+*.trs
+
+/build
+/subprojects
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..1e46cf5
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "common"]
+        path = common
+        url = https://anongit.freedesktop.org/git/gstreamer/common.git
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..5cef5a3
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,21 @@
+Erik Walthinsen <omega@temple-baptist.com>
+Matt Howell <mhowell@users.sourceforge.net>
+Brent Bradburn <bbradburn@users.sourceforge.net>
+Wim Taymans <wim.taymans@chello.be>
+Richard Boulton <richard@tartarus.org>
+Zaheer Abbas Merali <zaheerabbas at merali dot org>
+David I. Lehn <dlehn@users.sourceforge.net>
+Chris Emerson <chris@tartarus.org>
+Jens Thiele <karme@unforgettable.com>
+Thomas Nyberg <thomas@codefactory.se>
+Bastien Nocera <hadess@hadess.net>
+Christian Fredrik Kalager Schaller <Uraeus@linuxrising.org>
+Thomas Vander Stichele <thomas@apestaart.org>
+Andy Wingo <wingo@pobox.com>
+Cameron Hutchison <camh@xdna.net>
+David Schleef <ds@schleef.org>
+Benjamin Otte <in7y118@public.uni-hamburg.de>
+Ronald Bultje <rbultje@ronald.bitfreak.net>
+Julien MOUTTE <julien@moutte.net>
+Jan Schmidt <thaytan@mad.scientist.com>
+Arwed v. Merkatz <v.merkatz@gmx.net>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..1414846
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,130505 @@
+=== release 1.12.0 ===
+
+2017-05-04  Sebastian Dröge <slomo@coaxion.net>
+
+	* configure.ac:
+	  releasing 1.12.0
+
+2017-05-04 13:47:20 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/el.po:
+	  po: Update translations
+
+2017-05-02 10:32:30 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix crash on mss stream caused by invalid stsd entry access
+	  Since mss has no moov, default stsd entry should be created with media-caps.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=782042
+
+=== release 1.11.91 ===
+
+2017-04-27 17:29:58 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* meson.build:
+	  Release 1.11.91
+
+2017-04-27 15:58:47 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/fur.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2017-04-27 15:28:02 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/LINGUAS:
+	* po/el.po:
+	* po/fur.po:
+	  po: Update translations
+
+2017-04-27 12:56:27 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Don't crash in debug output if stream==NULL
+	  That case is correctly handled below but not in the debug output.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=781270
+
+2017-04-25 17:11:27 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Don't perform seeks with inconsistent seek values
+	  If gst_segment_do_seek() fails, we shouldn't try seeking on that
+	  resulting segment but just error out. Crashes further down the line
+	  otherwise.
+
+2017-04-24 20:27:49 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From 60aeef6 to 48a5d85
+
+2017-04-24 17:31:04 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/rtp-payloading.c:
+	  tests: rtp-payloading: add test for rtph264depay avc/byte-stream output
+	  Make sure avc output doesn't contain SPS/PPS inline, but
+	  byte-stream output does.
+
+2017-04-24 17:29:37 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: don't insert SPS/PPS inline for AVC output
+	  SPS/PPS are in the caps in this case and shouldn't be in
+	  the stream data.
+
+2017-04-21 19:09:14 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Chain up to the parent class' provide_clock() implementation
+	  If no clock was provided directly by rtspsrc. This behaviour was removed
+	  by f8013487c91a6ffc552a4b25aa1a70f0bd5377f8 and results in rtspsrc not
+	  providing the system clock via the rtpjitterbuffer.
+	  As a result, if another element like an audio sink, provides a clock,
+	  the pipeline would select that (when going to PAUSED/PLAYING again later).
+	  Audio clocks usually don't progress in PAUSED, and thus our live source
+	  won't be able to use the clock to produce data, making the sink never
+	  preroll and everything is stuck.
+
+2017-04-20 11:22:15 +0200  Jürgen Sachs <juergen.sachs@metz-ce.de>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: reset sample_description_id to default
+	  Fixes stream where sample_description_id is specified in the tfhd
+	  https://bugzilla.gnome.org/show_bug.cgi?id=778337
+
+2017-04-20 13:16:24 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Don't use an explicit name for requesting audio pads
+	  ... unless the muxer uses the same audio pad template name as
+	  splitmuxsink. We can't request a pad called "audio_0" on a muxer that
+	  wants pads to be "sink_%d".
+
+2017-02-23 09:31:36 +0900  ChangBok Chae <changbok.chea@gmail.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: remove duplicated segment initialization
+	  It's also done in gst_flv_demux_cleanup().
+	  https://bugzilla.gnome.org/show_bug.cgi?id=779106
+
+2017-04-20 20:17:35 +1000  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Correctly catch FLUSH events in probes
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767498
+
+2017-04-19 12:28:12 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  Revert "rtpbin: pipeline gets an EOS when any rtpsources byes"
+	  This reverts commit eeea2a7fe88a17b15318d5b6ae6e190b2f777030.
+	  It breaks EOS in some sender pipelines, see
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773218#c20
+
+2017-04-14 17:01:49 +0200  Edward Hervey <edward@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Reset adapter in more discontinuity cases
+	  In push mode we process as much as possible in the adapter. When we receive
+	  a DISCONT buffer which we can't match to an actual sample (based on the existing
+	  sample table) and there is still data remaining in the incoming adapter,there is
+	  one of two cases happening:
+	  1) We are doing reverse playback, in which case we should flush out all pending
+	  data
+	  2) We have leftover data from the previous incoming buffer... which we can't do
+	  anything about.
+	  For the second case, make sure we flush out the remaining data so that we can start
+	  parsing again from scratch.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=781319
+
+2017-04-14 10:56:41 +0200  Edward Hervey <edward@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Use GST_ELEMENT_ERROR_WITH_DETAILS
+	  Allows the application to know the exact status code that was returned
+	  by the server in a programmatic fashion.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=781304
+
+2017-04-16 18:47:56 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix leak on QtDemuxStreamStsdEntry
+	  Fix unit test failure
+	  https://bugzilla.gnome.org/show_bug.cgi?id=781362
+
+2017-04-14 13:38:53 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Fix timescale of timecode tracks
+	  They should have ideally the same timescale of the video track, which we
+	  can't guarantee here as in theory timecode configuration and video
+	  framerate could be different. However we should set a correct timescale
+	  based on the framerate given in the timecode configuration, and not just
+	  use the framerate numerator.
+
+2017-04-13 13:25:06 +0200  Edward Hervey <edward@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Properly reset demuxer when all streams are EOS
+	  Make sure offset and neededbytes are properly resetted when all
+	  streams are EOS in push-mode.
+	  Avoids cases when some data might still be pushed by upstream (because
+	  it didn't yet see the resulting GST_FLOW_EOS yet) and qtdemux gets
+	  completely lost.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=781266
+
+2017-04-13 08:00:30 +0200  Edward Hervey <edward@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Make more usage of error macro
+	  And make sure we actually use the provided soup_msg argument in the macro
+
+2017-04-12 18:46:53 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* ext/meson.build:
+	  meson: Print message when disabling taglib on MSVC
+
+2017-04-12 13:26:59 +0200  Edward Hervey <edward@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Don't forget to update pad->last_buf
+	  buf is the current pad->last_buf value. If ever it gets copied/unreffed,
+	  we need to make sure to write back the new  pointer to the last_buf
+	  variable.
+	  Fixes using wrong pointer values in the case of decrasing DTS value
+
+2017-04-12 11:33:05 +0200  Edward Hervey <edward@centricular.com>
+
+	* tests/check/elements/.gitignore:
+	  tests: Add vp9enc to gitignore
+
+2017-04-11 13:41:48 +0200  Jürgen Sachs <juergen.sachs@metz-ce.de>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix: sample description index override in tfhd not evaluated
+	  https://bugzilla.gnome.org/show_bug.cgi?id=778337
+
+2017-04-12 11:03:24 +0200  Edward Hervey <edward@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Add out-of-bound check
+	  Make sure we don't read invalid memory
+
+2016-04-27 12:17:37 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: move parsing of tkhd out of stsd entry loop
+	  It needs only to be read once.
+
+2016-04-07 12:23:35 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: check for a different stsd entry before pushing a sample
+	  Before pushing a sample, check if there was a change in the current
+	  stsd entry. This patch also assumes that the first stsd entry is
+	  used as default for the first sample. It might cause an uneeded
+	  caps renegotiation when this isn't the case.
+
+2016-04-06 12:55:18 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: parse all stsd entries
+	  stsd can have multiple format entries, parse them all.
+	  This is required to play DVB DASH profile that uses multiple entries
+	  to identify the different available bitrates/options on dash streams
+	  The stream format-specific data is not stored into QtDemuxStreamStsdEntry
+
+2016-04-05 14:34:00 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: rework stsd sample entries access
+	  Instead of using the stsd as a base pointer, use the actual stsd
+	  entry as the stsd can have multiple entries. This is rarely used
+	  for file playback but is a possible profile with in DVB DASH specs.
+	  This still doesn't support stsd with multiple entries but makes it
+	  easier to do so.
+
+2016-04-05 18:00:10 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: get stsd child by index instead of type
+	  There might be multiple children with the same type
+
+2017-04-07 16:33:18 +0300  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/check/elements/rtprtx.c:
+	  tests/check/rtprtx: add checks for rtprtxqueue's max-size-{time,packets} properties
+	  https://bugzilla.gnome.org/show_bug.cgi?id=780867
+
+2017-04-04 17:33:31 +0300  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxqueue.c:
+	* gst/rtpmanager/gstrtprtxqueue.h:
+	  rtprtxqueue: implement handling of the max-size-time property
+	  https://bugzilla.gnome.org/show_bug.cgi?id=780867
+
+2017-04-10 23:49:06 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* autogen.sh:
+	* common:
+	  Automatic update of common submodule
+	  From 39ac2f5 to 60aeef6
+
+2017-04-10 08:56:00 +0000  Todor Tomov <todor.tomov@linaro.org>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2object: Copy timestamp when importing buffers
+	  This is needed for V4L2_OUTPUT interface, and is harmless of
+	  V4L2_CAPTURE interfaces. This will fix timestamp in cases like:
+	  v4l2src io-mode=dmabuf ! v4l2videoNenc output-io-mode=dmabuf-import !  ...
+	  Same apply for userptr.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=781119
+
+2017-04-10 15:55:30 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Fix last_dts tracking for raw audio and similar formats
+	  Accumulate the durations directly and don't scale yet another time by
+	  the number of samples.
+
+2017-04-07 10:48:50 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* tests/check/elements/splitmux.c:
+	  tests: fix leak in splitmux test
+	  https://bugzilla.gnome.org/show_bug.cgi?id=781025
+
+2017-04-07 15:29:43 +0800  Lyon Wang <lyon.wang@nxp.com>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: Scale GAP event timestamp and duration like for buffers
+	  https://bugzilla.gnome.org/show_bug.cgi?id=781008
+
+2017-02-17 10:01:08 -0300  Thibault Saunier <thibault.saunier@osg.samsung.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	* sys/v4l2/gstv4l2videodec.h:
+	  v4l2dec: Fix race when going from PAUSED to READY
+	  Running `gst-validate-launcher -t validate.file.playback.change_state_intensive.vorbis_vp8_1_webm`
+	  on odroid XU4 (s5p-mfc v4l2 driver) often leads to:
+	  ERROR:../subprojects/gst-plugins-good/sys/v4l2/gstv4l2videodec.c:215:gst_v4l2_video_dec_stop: assertion failed: (g_atomic_int_get (&self->processing) == FALSE)
+	  This happens when the following race happens:
+	  - T0: Main thread
+	  - T1: Upstream streaming thread
+	  - T2. v4l2dec processing thread)
+	  [The decoder is in PAUSED state]
+	  T0. The validate scenario runs `Executing (36/40) set-state: state=null repeat=40`
+	  T1- The decoder handles a frame
+	  T2- A decoded frame is push downstream
+	  T2- Downstream returns FLUSHING as it is already flushing changing state
+	  T2- The decoder stops its processing thread and sets `->processing = FALSE`
+	  T1- The decoder handles another frame
+	  T1- `->process` is FALSE so the decoder restarts its streaming thread
+	  T0- In v4l2dec-> stop the processing thread is stopped
+	  NOTE: At this point the processing thread loop never started.
+	  T0- assertion failed: (g_atomic_int_get (&self->processing) == FALSE)
+	  Here I am removing the whole ->processing logic to base it all on the
+	  GstTask state to avoid duplicating the knowledge.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=778830
+
+=== release 1.11.90 ===
+
+2017-04-07 16:31:56 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* meson.build:
+	  Release 1.11.90
+
+2017-04-07 15:18:11 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2017-04-07 15:06:30 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/el.po:
+	  po: Update translations
+
+2017-04-06 12:01:00 +0200  Edward Hervey <edward@centricular.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: streamline and improve AudioSpecificConfig parsing
+	  AudioSpecifigConfig is used in a variety of AAC streams but was
+	  being parsed differently. Instead, make everyone use the same parsing.
+	  * Remove unused 'bits' field (it was always set to 0 if present)
+	  * Add proper GAConfig parsing (to know the  number of samples per frame
+	  if present).
+	  Fixes wrong rate/channels configuration in streams coming from qtdemux
+	  https://bugzilla.gnome.org/show_bug.cgi?id=780966
+
+2017-04-05 09:46:31 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Fix 32bit only printf format
+	  The previous patch was using %llu for 64bits printf, which is 32bit
+	  specific. We also trace the latency in time human readable form now.
+
+2016-03-16 16:22:48 +0100  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: set streamparm for outputs that support it
+	  Without a specified framerate from the sink, the decoder frame interval
+	  should be set using the framerate of the encoded video stream.
+	  Therefore, the v4l2object should be able to change the framerate on the
+	  output if the V4L2 device accepts it.
+	  This is also necessary for mem2mem encoders so that their bitrate
+	  calculation code may work correctly and they may report the correct
+	  frame duration on the capture queue.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=779466
+
+2016-03-16 16:24:55 +0100  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: only set latency if the frame duration is valid
+	  If the duration of the v4l2object is GST_CLOCK_TIME_NONE, because the
+	  sink did not specify a framerate in the caps and the driver accepts the
+	  framerate, the decoder element uses GST_CLOCK_TIME_NONE to calculate and
+	  set the element latency.
+	  While this is a bug of the capture driver, the decoder element should
+	  not use the invalid duration to calculate a latency, but print a warning
+	  instead.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=779466
+
+2016-11-23 12:17:55 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: Block in preroll_wait on unlock
+	  The correct behaviour of anything stuck in the ->render() function
+	  between ->unlock() and ->unlock_stop() is to call
+	  gst_base_sink_wait_preroll() and only return an error if this returns an
+	  error, otherwise, it must continue where it left off!
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774945
+
+2017-04-05 15:55:20 +1000  Jan Schmidt <jan@centricular.com>
+
+	* ext/vpx/gstvp9dec.c:
+	  vp9dec: Add warnings for unsupported frame formats
+	  At least output an element warning on the bus when we
+	  encounter a frame format GStreamer doesn't currently support.
+
+2017-04-04 17:55:13 +0200  Edward Hervey <edward@centricular.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Handle Parametric Stereo with HE-AAC(v2)
+	  According to ISO/IEC:14496-2:2009 , in the case of HE-AACv2 (audioObjecType
+	  29) parametric stereo is used (a single mono track is used and then
+	  transformations are applied to it to provide a stereo output).
+	  We therefore report two channels in the case where there is one reported
+	  in the audioChannelConfiguration.
+	  Fixes the various issues where a demuxer would report two channels, but
+	  then the parser would say there's only one channel, and then the decoder
+	  would output two channels.
+
+2017-04-04 15:22:25 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Simplify buffer refcounting in add_buffer() and remove unneeded NULL checks
+
+2017-04-04 15:08:33 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Select the best pad based on the cached last_buf if any
+	  last_buf is the one we're going to write next, not buf. As such we
+	  should check timestamps against that one if there is one to select the
+	  earliest pad.
+	  Also remember the currently selected pad in the very beginning when
+	  storing the first last_buf.
+	  This both solves some edge cases where not the correct next pad was
+	  selected corresponding to the target interleave.
+
+2017-04-04 15:07:40 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Error out immediately if a timecode is to be written but downstream return not-OK
+
+2017-04-03 11:34:49 +0200  Edward Hervey <edward@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Update variables before early exit
+	  This is an update of d78d5896272d78df41e696fac929e7dfb3bb3dfa
+	  We still exit as early as possible in case of non-ok/non-unlinked combined
+	  flow, but we first make sure that we update the internal position variables.
+	  This ensures that if upstreams "ignores" the flow return (and carries on pushing),
+	  we don't end up processing data with completely bogus variables/positions.
+
+2017-03-24 00:11:13 +1300  Douglas Bagnall <douglas@halo.gen.nz>
+
+	* gst/interleave/interleave.c:
+	* gst/interleave/interleave.h:
+	  interleave: avoid using uninitialised ordering_map
+	  If self->channel_positions == NULL (which seems unlikely),
+	  self->default_channels_ordering_map will be used unintialised.
+	  We avoid that by keeping track of the channel_mask, which is set when
+	  the ordering map is initialised.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=780331
+
+2017-03-23 23:56:31 +1300  Douglas Bagnall <douglas@halo.gen.nz>
+
+	* gst/interleave/interleave.c:
+	  interleave: don't overflow channel map with >64 channels
+	  When there are more than 64 channels, we don't want to exceed the
+	  bounds of the ordering_map buffer, and in these cases we don't want to
+	  rempa at all. Here we avoid doing that.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=780331
+
+2017-03-28 14:23:16 -0300  Thibault Saunier <thibault.saunier@osg.samsung.com>
+
+	* tests/check/meson.build:
+	  meson: Use get_pkgconfig_variable instead of calling pkg-config ourself
+	  It is avalaible in meson 0.36 which is now are requirement
+
+2017-03-28 14:22:41 -0300  Thibault Saunier <thibault.saunier@osg.samsung.com>
+
+	* pkgconfig/gstreamer-plugins-good.pc.in:
+	* pkgconfig/meson.build:
+	  pkgconfig: Do not ever build an installed .pc file
+
+2017-03-28 11:15:53 -0300  Thibault Saunier <thibault.saunier@osg.samsung.com>
+
+	* tests/check/meson.build:
+	  meson: test: Fix environment object usage
+
+2017-03-28 11:14:47 -0300  Thibault Saunier <thibault.saunier@osg.samsung.com>
+
+	* meson.build:
+	* pkgconfig/gstreamer-plugins-good.pc.in:
+	* pkgconfig/meson.build:
+	  pkgconfig: Generate the pkg-config with meson too
+
+2017-03-27 21:52:00 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: In gap mode, consider the mdat offset when calculating the remaining mdat size
+	  The mdat generally does not start at offset 0, we have to include the
+	  size of the moof and whatever else was in front of the mdat.
+
+2017-03-27 11:43:31 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/atomsrecovery.c:
+	  atomsrecovery: Error out when fseek() fails instead of silently ignoring
+	  CID 1403262
+
+2017-03-23 22:13:05 +0100  Carlos Rafael Giani <dv@pseudoterminal.org>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Also add videometa if there is padding to the right and bottom
+	  https://bugzilla.gnome.org/show_bug.cgi?id=780478
+
+2017-03-21 12:54:27 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: fix output segment and buffer DTS to correspond to the flattened PTS
+	  https://bugzilla.gnome.org/show_bug.cgi?id=780347
+
+2017-03-23 17:53:19 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  qtmux: Remove some unused variables
+
+2017-03-23 15:01:16 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Remove a couple of unneeded levels of indentation
+
+2017-03-22 18:18:40 +0000  Enrique Ocaña González <eocanha@igalia.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: distinguish TFDT with value 0 from no TFDT at all
+	  TFDTs with time 0 are being ignored since commit 1fc3d42f. They're
+	  mistaken with the case of not having TFDT, but those two cases
+	  must be distinguished in some way.
+	  This patch passes an extra boolean flag when the TFDT is present.
+	  This is now the condition being evaluated, instead of checking for
+	  0 time.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=780410
+
+2017-03-22 19:15:09 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Reset current chunk after writing out timecode
+	  If we have multiple tracks with timecodes, or it's not the first track
+	  that has timecodes, or not the first buffer, we already started a chunk
+	  for media data. We now need to "close" that chunk because we wrote data
+	  for the timecode track and a new chunk has to be started for the
+	  original track the next time it has data.
+
+2017-03-22 18:52:51 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  qtmux: Do timecode handling per track, not per muxer instance
+	  There could be multiple video tracks with timecodes.
+
+2017-03-22 00:38:51 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	  qtdemux: matroskademux: Ignore repeated seek events
+	  Similar to what was done in adaptivedemux, ignore seek
+	  events we've already handled - such as when they are received
+	  on every srcpad of files with lots of streams.
+
+2017-03-21 14:55:32 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  dashdemux: Update mdatleft from overall mdatsize and offset when observing a gap
+	  Otherwise mdatleft will have a value calculated from the initial
+	  mdatsize minus the parts of the stream that we saw, which is not
+	  including all the parts of the stream that might've been skipped.
+
+2017-03-20 17:03:32 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  docs: update two references to the removed 'mad' plugin
+	  https://bugzilla.gnome.org/show_bug.cgi?id=776140
+
+2017-03-20 12:03:29 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxqueue.c:
+	  rtprtxqueue: add basic documentation and example pipelines
+	  Mostly explaining the difference between rtprtxqueue and rtprtxsend.
+
+2017-03-17 20:58:28 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/meson.build:
+	  v4l2: Fix meson plugin shared object name
+	  It didn't match between AutoMake and Meson, and the Meson name
+	  didn't math the plugin name (video4linux2).
+
+2017-03-16 18:20:54 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	  rtprtxreceive: fix example pipelines and improve the documentation
+	  https://bugzilla.gnome.org/show_bug.cgi?id=771383
+
+2017-03-17 14:10:40 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstflacparse.h:
+	  flacparse: fix playback if sample number does not start at 0
+	  This reverts commit 29b807685d3c962bbe8afe351c5dca97d59eb5e0, while
+	  fixing the original breaking tests/check/pipelines/flacdec.
+
+2017-03-17 11:30:04 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstflacparse.h:
+	  Revert "flacparse: fix playback if sample number does not start at 0"
+	  This breaks gst-validate on the build server (though not locally),
+	  and a unit test, and I can't run unit tests right now for some
+	  unrelated reason.
+	  This reverts commit 0747b56f8e7f4731d67f8d13a4bdc453dde0fdf7.
+
+2017-03-16 17:44:41 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: print the correct variable in debug statement
+	  This debug statement is meant to print the time since the last (early)
+	  RTCP transmission, not the last regular RTCP transmission (which also
+	  happens to be set a few lines above to current_time, so the debug output
+	  is just confusing)
+
+2017-03-16 17:42:27 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: convert LOG message to TRACE
+	  This is printed too often (for every chained buffer!) and just clutters the logs.
+
+2017-03-16 14:58:45 +0100  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: fix warning message
+	  https://bugzilla.gnome.org/show_bug.cgi?id=780105
+
+2017-03-16 13:54:54 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstflacparse.h:
+	  flacparse: fix playback if sample number does not start at 0
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777738
+
+2017-03-15 18:58:55 +0100  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpsource: get clock-rate from pt if needed to generate SR
+	  https://bugzilla.gnome.org/show_bug.cgi?id=780105
+
+2017-03-16 13:52:48 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Include GStreamer souphttpsrc version in default User-Agent string
+
+2017-03-16 00:41:44 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: fix crash with empty sprops-parameters
+	  https://bugzilla.gnome.org/show_bug.cgi?id=780040
+
+2017-03-11 21:20:40 -0800  Thiago Santos <thiagossantos@gmail.com>
+
+	* gst/isomp4/atomsrecovery.c:
+	* gst/isomp4/atomsrecovery.h:
+	  atomsrecovery: also handle extra atoms after 'mdia' in a 'trak'
+	  Take into account the atoms at the end of the 'trak' atom when
+	  recovering it. So that its size (already computed and added in the trak
+	  size) isn't making offsets wrong.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=771478
+
+2017-03-11 12:56:33 -0800  Thiago Santos <thiagossantos@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: avoid fallthrough to moovrecovery failure section
+	  Return before that to preserve our successfull results, otherwise no
+	  moov recovery information would be written
+	  https://bugzilla.gnome.org/show_bug.cgi?id=771478
+
+2017-03-11 12:27:28 -0800  Thiago Santos <thiagossantos@gmail.com>
+
+	* gst/isomp4/atomsrecovery.c:
+	  atomsrecovery: expect more atom types at the headers
+	  Skip more atoms at the header until it finds the 'mdat' to continue the
+	  moov recovery
+	  https://bugzilla.gnome.org/show_bug.cgi?id=771478
+
+2017-03-14 16:42:25 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* Makefile.am:
+	* configure.ac:
+	* tests/examples/Makefile.am:
+	* tests/examples/pulse/.gitignore:
+	* tests/examples/pulse/Makefile.am:
+	* tests/examples/pulse/pulse.c:
+	  pulse example: Remove
+	  That example only tested the property probe interface, which has been removed.
+	  The same kind of thing can now be done with the generic gst-device-monitor tool.
+
+2017-03-14 16:38:02 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2: Remove unused macro
+
+2017-03-14 16:35:25 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2: Remove unused definitions
+
+2017-03-14 10:10:19 +0100  Emeric Grange <egrange@gopro.com>
+
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmuxmap.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_types.c:
+	  qtmux: add CineForm support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=780024
+
+2017-03-14 15:09:44 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Only create new chunks if we have more than a single stream
+	  There's no point in creating multiple chunks otherwise, it only wastes
+	  some bytes for storing the chunk offsets.
+
+2017-03-14 10:09:46 +0100  Emeric Grange <egrange@gopro.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: add S16L support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=780022
+
+2017-03-14 15:48:08 +1100  Jan Schmidt <jan@centricular.com>
+
+	* tests/check/elements/splitmux.c:
+	  splitmux test: Use passed first/last timestamps
+	  Don't hard-code the expected timestamp range, use the
+	  values the caller is passing in.
+
+2017-03-12 11:42:25 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* Makefile.am:
+	* docs/plugins/inspect/plugin-soup.xml:
+	  Add old plugin names to cruft list
+	  This will help fixing uninstalled setup. Also fix missing path
+	  correction in one of the plugin xml.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=779344
+
+2016-12-15 12:38:40 +0100  Michael Dutka <mail@michael-dutka.de>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph265depay.c:
+	  rtph264depay, rtph265depay: remove stray g_debug()
+	  https://bugzilla.gnome.org/show_bug.cgi?id=779858
+
+2017-03-10 11:24:14 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: init fourcc
+	  Initialize the fourcc to 0 so that we can detect failure later.
+
+2017-03-08 22:50:52 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/level.c:
+	* tests/check/elements/rglimiter.c:
+	  tests: Add missing LDADD for libm in tests using math.h
+	  Also, remove the math.h include for the one that just prentend to need
+	  it.
+
+2017-03-08 22:15:46 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  Fix shout2 plugin doc generation
+	  In the previous patch, we also renamed shout2send to shout2, so it does
+	  not clash with it's feature. Though we forgot to rename it in the doc
+	  reference. This patch also add a cruft detection on the xml that made me
+	  miss this error.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=779344
+
+2017-03-04 10:52:47 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-shout2.xml:
+	* ext/pulse/Makefile.am:
+	* ext/pulse/meson.build:
+	* ext/shout2/gstshout2.c:
+	* ext/soup/Makefile.am:
+	* ext/soup/meson.build:
+	* sys/oss4/Makefile.am:
+	  Fix plugin filenames to match plugin names
+	  - libgstpulse.so becomes libgstpulseaudio.so
+	  - libgstsouphttpsrc.so becomes libgstsoup.so
+	  - libgstoss4audio.so becomes libgstoss4.so
+	  https://bugzilla.gnome.org/show_bug.cgi?id=779344
+
+2017-03-08 16:01:02 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	  qtmux: Free EDTS instead of just clearing it and setting it to NULL
+
+2017-03-08 15:27:32 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Fix some memory leaks related to timecode tracks
+
+2017-03-04 00:34:44 +1100  Jan Schmidt <jan@centricular.com>
+
+	* tests/check/elements/splitmux.c:
+	  splitmux: Add unit test for reverse playback
+	  Ensure that reverse playback works and generates the range
+	  of timestamps (0-3s) we expect, in monotonically descending order.
+
+2017-02-28 11:50:45 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsrc.c:
+	  splitmuxsrc: Fix reverse playback
+	  Fix the check for whether the start time of the segment has
+	  been reached when playing in reverse. Otherwise, playback
+	  stops after reaching the start of any file part, instead of
+	  continuing until all parts within the segment have played
+
+2017-02-22 03:01:31 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Don't lose crypto info on a new moof
+	  We parse the next moof in advance of having pushed
+	  all samples from the previous one in some cases, and
+	  we'll still need the crypto info from the previous
+	  fragment so keep around any unused crypto info entries
+	  when adding new ones
+
+2017-02-27 13:55:58 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Update modification times when sending the moov
+	  https://bugzilla.gnome.org/show_bug.cgi?id=779422
+
+2017-03-01 16:11:47 -0800  Michael Smith <mlrsmith@gmail.com>
+
+	* gst/audioparsers/gstsbcparse.h:
+	  sbcparse: Fix up values for allocation enumeration.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=779389
+
+2017-02-28 13:10:50 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	  rtprtxreceive: fix potential leak of old, unassociated, association requests
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722560
+
+2017-02-28 15:47:23 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Don't increment -1 / unset indices
+	  CID 1398545
+
+2017-02-28 15:20:31 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Protect against NULL pointer dereference for streams without caps
+	  CID 1363332
+
+2017-02-28 12:57:02 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: Free mac on errors
+	  CID 1212149
+
+2017-02-28 12:45:24 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	  rtpvorbispay: Add missing break to for loop
+
+2017-02-28 11:02:54 +0100  Edward Hervey <edward@centricular.com>
+
+	* tests/check/Makefile.am:
+	  check: Fix splitmux test CFLAGS
+	  Needs to know where the gstapp headers are
+
+2017-02-27 21:02:51 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix compilation with gcc 7
+	  qtdemux.c: In function ‘qtdemux_parse_samples’:
+	  qtdemux.c:8450:39: error: ‘*’ in boolean context, suggest ‘&&’ instead [-Werror=int-in-bool-context]
+	  if (stream->samples_per_frame * stream->bytes_per_frame) {
+	  ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
+
+2017-02-27 21:01:23 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: Fix compilation with gcc 7
+	  gstmpegaudioparse.c: In function ‘gst_mpeg_audio_parse_reset’:
+	  gstmpegaudioparse.c:209:3: error: ‘memset’ used with length equal to number of elements without multiplication by element size [-Werror=memset-elt-size]
+	  memset (mp3parse->xing_seek_table_inverse, 0, 256);
+	  ^~~~~~
+	  gstmpegaudioparse.c: In function ‘gst_mpeg_audio_parse_handle_first_frame’:
+	  gstmpegaudioparse.c:951:7: error: ‘memset’ used with length equal to number of elements without multiplication by element size [-Werror=memset-elt-size]
+	  memset (mp3parse->xing_seek_table_inverse, 0, 256);
+	  ^~~~~~
+
+2017-02-27 19:31:39 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	  rtpvorbispay: When getting new headers, replace the old version of them
+	  This prevents storing an infinite amount of e.g. comment headers if they
+	  come without a new initialization header in front of them. There can
+	  only be one header of each type.
+
+2017-02-27 19:25:35 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/rtp-payloading.c:
+	  rtp-payloading: Add new test for Vorbis renegotiation
+	  Check if encoding, payloading, depayloading and decoding works if the
+	  stream configuration (and thus the headers) change.
+
+2017-02-27 19:24:07 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	  vorbispay: Only replace headers when receiving a new config header
+	  If we also replace all headers when receiving any possibly following
+	  comments header, we would throw away the config header before being able
+	  to make use of it.
+
+2017-02-23 12:11:15 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/splitmux.c:
+	  tests: splitmux: add unit test for content with sparse streams
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761086
+
+2017-02-22 11:23:19 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	  splitmuxpartreader: ignore sparse streams when calculating the end offset of a part
+	  A sparse stream's ending timestamp can be considerably smaller
+	  than the ending timestamps of the other streams, which can lead
+	  to skipping considerable time from the next part.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761086
+
+2017-02-22 11:21:06 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	  splitmuxpartreader: identify sparse streams
+
+2017-02-25 21:47:03 -0300  Edgard Lima <edgard.lima@gmail.com>
+
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726depay.h:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpg726pay.h:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmadepay.h:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmapay.h:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtppcmudepay.h:
+	* gst/rtp/gstrtppcmupay.c:
+	* gst/rtp/gstrtppcmupay.h:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexdepay.h:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpspeexpay.h:
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2colorbalance.c:
+	* sys/v4l2/gstv4l2colorbalance.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/gstv4l2tuner.c:
+	* sys/v4l2/gstv4l2tuner.h:
+	* sys/v4l2/gstv4l2vidorient.c:
+	* sys/v4l2/gstv4l2vidorient.h:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2_calls.h:
+	  Update Edgard Lima's email
+	  https://bugzilla.gnome.org/show_bug.cgi?id=779230
+
+2017-02-08 13:36:00 +0000  Andrew <nifigase@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  rtpjitterbuffer: Don't always reset PTS to 0 after a gap
+	  In function rtp_jitter_buffer_calculate_pts: If gap in incoming RTP
+	  timestamps is more than (3 * jbuf->clock_rate) we call
+	  rtp_jitter_buffer_reset_skew which resets pts to 0. So components down
+	  the pipeline (playes, mixers) just skip frames/samples until pts becomes
+	  equal to pts before gap.
+	  In version 1.10.2 and before this checking was bypassed for packets with
+	  "estimated dts", and gaps were handled correctly.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=778341
+
+2017-02-24 15:59:41 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* meson.build:
+	  meson: Update version
+
+2017-02-24 15:37:36 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.11.2 ===
+
+2017-02-24 15:07:23 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	  Release 1.11.2
+
+2017-02-24 12:50:21 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2017-02-24 12:44:58 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/el.po:
+	  po: Update translations
+
+2017-02-10 20:50:17 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Extract redirection uri on libsoup's restarted callback
+	  Let libsoup handle redirection automatically.
+	  And then, to figure out redirection uri, extract it on "restarted"
+	  callback which will be fired before soup_session_send() is returned.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=778428
+
+2017-01-02 19:29:04 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Update image size when extrapolating
+	  Update the image size according the amount of data we are going to
+	  read/write. This workaround bugs in driver where the sizeimage provided
+	  by TRY/S_FMT represent the buffer length (maximum size) rather then the expected
+	  bytesused (buffer size).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775564
+
+2017-02-17 15:50:32 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: fix typo in _acquire_format() error messages
+	  Fixes:
+	  https://bugzilla.gnome.org/show_bug.cgi?id=778815
+
+2017-02-07 17:27:56 +0100  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* tests/check/elements/matroskamux.c:
+	* tests/check/elements/qtmux.c:
+	  tests: matroskamux, qtmux: don't add codec_data buffers to template caps
+	  streamheader and codec_data buffers fields are only meant to be
+	  in the negotiated caps, not the template caps.
+	  Fixes false-positive leaks of those buffers detected by the leaks
+	  tracer, as template caps are static, and we decided to not include
+	  code in gstreamer core to handle this unusual case of template caps
+	  having buffers in them.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768762
+
+2017-02-09 12:46:54 +0000  Jochen Henneberg <jh@henneberg-systemdesign.com>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	  rtpvorbispay: Update and send out headers when new headers are received
+	  The payloader needs to reset and update the vorbis config data which is
+	  pushed on the network if it receives new headers, or at least, it may
+	  have to do so.
+	  Without this, the stream configuration could change without the
+	  payloader sending the new configuration to the other side.
+
+2017-02-15 14:48:58 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmuxsink: Change files on incompatible caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761761
+
+2017-02-15 16:35:01 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Reset ready_for_output on state change
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761761
+
+2017-02-15 15:09:06 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmuxsink: Remove unused next_max_out_running_time
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761761
+
+2017-02-15 15:07:32 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmuxsink: Remove unused muxed_out_time
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761761
+
+2017-02-17 13:07:05 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  Revert "qtdemux: Always snap to the start of the keyframe"
+	  This reverts commit 107902ec514bd826aa29d2298107e2c091e1c779.
+	  This commit intended to ensure that keyframe seeks land at the
+	  start timestamp of a keyframe, rather than in the middle of one,
+	  but they cause trouble on files with sparse streams, or with
+	  JPEG 'cover art' tracks that have only one or a few JPEG samples
+	  with very long durations.
+	  That's still desirable for doing seamless cutting of videos,
+	  but needs a rethink for implementation.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=778690
+
+2017-02-17 01:22:11 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audioecho.h:
+	  audiofx/echo: added surround-delay and surround-mask
+	  Add a new boolean surround-delay property that makes
+	  audioecho just apply a delay to certain channels to create
+	  a surround effect, rather than an echo on all
+	  channels. This is useful when upmixing from stereo - for example.
+	  Add a surround-mask property to control which channels
+	  are considered surround sound channels when adding a
+	  delay with surround-delay = true
+	  Original patch from Jochen Henneberg <jh@henneberg-systemdesign.com>
+
+2017-02-15 00:13:30 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Use IP_MULTICAST_ALL for filtering IPv4 packets if available
+	  This goes around the inefficient control message based filtering and
+	  does all the filtering kernel-side. Unfortunately this is Linux-only and
+	  there is no IPv6 variant of it (yet).
+
+2017-02-14 19:53:30 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* Makefile.am:
+	  meson: dist meson build files
+	  Ship meson build files in tarballs, so people who use tarballs
+	  in their builds can start playing with meson already.
+
+2017-02-10 10:53:05 +0100  Søren Juul <zpon.dk@gmail.com>
+
+	* gst/icydemux/gsticydemux.c:
+	* tests/check/elements/icydemux.c:
+	  icydemux: reset tags on empty value
+	  Some radio streams uses StreamTitle='' to reset the title after a
+	  track stopped playing, e.g. while the host talks between tracks or
+	  during news segments.
+	  This change forces an empty tag object to be distributed if
+	  StreamTitle or StreamUrl is received with empty value, thus allowing
+	  downstream elements to get notified about this.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=778437
+
+2017-02-13 11:17:25 +0100  Edward Hervey <edward@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Properly notify missing elements
+	  If the srtp elements are not present, post a message on the bus
+	  informing about the missing plugins.
+
+2017-02-10 10:32:57 -0300  Juan Pablo Ugarte <ugarte@endlessm.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: mark singleton caps as "may be leaked" objects.
+	  Set MAY_BE_LEAKED flag on static pads returned by gst_v4l2_object_get_*_caps()
+	  functions. Made functions thread safe by using g_once_init[enter|leave]
+	  funtions.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=778453
+
+2017-02-09 14:18:30 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Remove now unused done label
+
+2017-02-09 12:55:32 +0100  Nick Kallen <nickkallen@me.com>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: do not cache caps
+	  Upstream elements like videoflip can transform caps, such as changing width and height.
+	  When an imagefreeze downstream receives an ACCEPT_CAPS query it will NOW return
+	  all caps that it can accept.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=778389
+
+2017-02-09 11:29:43 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Add a comment about how atom_trak_set_elst_entry() works
+
+2014-08-22 09:55:43 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux_dump.c:
+	  qtdemux: demote some log messages to TRACE level
+	  Don't spam debug log with uninteresting stuff.
+
+2017-02-08 17:24:26 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Clear edit lists every time we recalculate them
+	  We recalculate them, so any old information has to be forgotten.
+	  Otherwise we write invalid edit lists when writing headers multiple
+	  times.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=778330
+
+2017-02-07 13:10:18 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	  splitmuxsrc: Allow for buffers before the segment when measuring
+	  Used signed calculations when measuring the max_ts of an input
+	  fragment, so as to calculate the correct duration and offset
+	  when buffers have timestamps preceding their segment
+
+2017-02-02 12:55:25 +0100  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpsession: relate received FIRs and PLIs to source
+	  This is needed in order to:
+	  - Avoid ignoring requests for different media sources.
+	  - Add SSRC field in the GstForceKeyUnit event.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=778013
+
+2017-01-30 20:20:08 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: sanity check number of segments in edit list
+	  Fixes crash with fuzzed file.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777940
+
+2017-01-02 22:16:39 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Skip seeking query if upstream format is time
+	  Don't need to querying byte-format seeking for time-format
+	  upstream case
+	  https://bugzilla.gnome.org/show_bug.cgi?id=776715
+
+2016-12-01 12:47:08 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Use upstream's StreamFlags if there are
+	  When multiple demuxer's are used, upstream might want to indicate
+	  default streams using GST_STREAM_FLAG_{SELECT, UNSELECT}
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775440
+
+2017-01-27 16:14:16 +0200  Vivia Nikolaidou <vivia@toolsonair.com>
+
+	* gst/isomp4/atoms.c:
+	  qtmux: Timecode track fixes for STSD entry
+	  The n_frames field (frames per second) should follow the nominal frame
+	  rate for drop-frame timecodes.
+	  Also, the trak's timescale (and duration, accordingly) should follow the
+	  STSD entry's timescale and frame duration (fps_n and fps_d accordingly),
+	  not the other way around.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777832
+
+2017-01-19 11:08:11 +0100  Arnaud Vrac <avrac@freebox.fr>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: retry request on early termination from the server
+	  Fix a regression introduced by commit 183695c61a54f1 (refactor to use
+	  Soup's sync API). The code previously attempted to reconnect when the
+	  server closed the connection early, for example when the stream was put
+	  in pause for some time.
+	  Reintroduce this feature by checking if EOS is received before the
+	  expected content size is downloaded. In this case, do the request
+	  starting at the previous read position.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=776720
+
+2017-01-10 09:40:56 -0700  Matt Staples <staples255@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: find_stream_by_channel should ignore unconfigured streams
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777101
+
+2017-01-25 18:43:00 +0000  Brendan Shanks <brendan.shanks@teradek.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Fix debug typo and remove misleading warning
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777362
+
+2017-01-25 20:56:24 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/examples/rtp/client-PCMA.c:
+	  rtp: Remove unused variable in example
+	  client-PCMA.c:84:22: warning: unused variable 'isrc' [-Wunused-variable]
+	  GObject *session, *isrc, *osrc;
+	  ^
+
+2017-01-09 11:32:35 +0530  Rahul Bedarkar <rahul.bedarkar@imgtec.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: check for not NULL before clearing adapter
+	  In case wavparse receives a manually injected FLUSH_STOP event
+	  while operating in pull mode we get criticals because we'd try
+	  to clear a NULL adapter.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777123
+
+2017-01-24 19:23:44 -0300  Thibault Saunier <thibault.saunier@osg.samsung.com>
+
+	* tests/check/meson.build:
+	  meson: Properly use ':' for defining keywords
+
+2017-01-17 16:41:58 +0100  Jean-Christophe Trotin <jean-christophe.trotin@st.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: reference memory before the buffer is queued
+	  In gst_v4l2_allocator_qbuf(), the memory is referenced after the
+	  buffer is queued. Once queued (VIDIOC_QBUF), the buffer might be handled
+	  by the V4L2 driver (e.g. decoded) and dequeued (gst_v4l2_allocator_dqbuf),
+	  through a different thread, before the memory is referenced (gst_memory_ref).
+	  In this case, in gst_v4l2_allocator_dqbuf(), the memory is unreferenced
+	  (gst_memory_unref) before having been referenced: the memory refcount
+	  reaches 0, and the memory is freed.
+	  So, to avoid this crossing case, in gst_v4l2_allocator_qbuf(), the
+	  memory shall be referenced before the buffer is queued.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777399
+
+2017-01-24 17:59:59 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	  qtmux: Only write 4 byte zero padding to the Video Sample Description in MOV
+	  For MP4 this is not defined, and it actually breaks things for MSE in
+	  Chrome if we do this. For MOV this is required by some broken software
+	  but the official specification says it's optional:
+	  https://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777540
+
+2017-01-02 13:42:04 +0100  Santiago Carot-Nemesio <scarot@twilio.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpstats: Keep number of nacks sent/received per source
+	  Currently, the nack packets sent or received are kept at session level,
+	  which makes it impossible to distinguish how many of these packages were
+	  sent/received per ssrc when several sources are in the same session. This
+	  patch is aligned with the https://www.w3.org/TR/webrtc-stats/#dom-rtcrtpstreamstats
+	  https://bugzilla.gnome.org/show_bug.cgi?id=776714
+
+2016-12-08 15:59:33 +0100  Jonas Holmberg <jonashg@axis.com>
+
+	* gst/rtp/gstrtph265pay.c:
+	  rtph265pay: Fix handling of config-interval
+	  Insert VPS/SPS/PPS before the first NAL unit containing an I-frame in an
+	  access unit only. If an access unit consists of several such NAL units
+	  (tiles) VPS/SPS/PPS should only be inserted before the first of them so
+	  that parameters are only updated between frames.
+	  Do not insert VPS/SPS/PPS before P-frames when config-interval is -1.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775817
+
+2017-01-19 12:29:44 +0100  Arnaud Vrac <avrac@freebox.fr>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: report a useful error message when soup_session_send fails
+	  This helps to understand cases where libsoup doesn't set the message
+	  status code after running soup_session_send.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777222
+
+2017-01-19 11:05:00 +0100  Arnaud Vrac <avrac@freebox.fr>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: properly check that seek range was respected
+	  This check must be done only when we are sure the request was
+	  successfully sent. soup_session_send() might fail without setting the
+	  status code. In this case status code is 0 so we would only catch the
+	  error after the seek range check. In this case we would report an error
+	  saying that the seek range was not respected, instead of reporting the
+	  underlying error that triggered the soup_session_send() failure.
+	  https://bugzilla.gnome.org/attachment.cgi?bugid=777222
+
+2017-01-09 21:04:51 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.h:
+	  gdkpixbufoverlay: add a positioning coefficient pair
+	  ... so as to allow one clearly defined (absolute) positioning mode
+	  that can cater for a variety of absolute but also relative positioning
+	  with respect to edge or center.
+
+2017-01-21 20:48:22 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	  gdkpixbufoverlay: update composition in _before_transform
+	  ... since we need to determine passthrough mode for buffer preparation before
+	  calling into _transform_ip.
+
+2017-01-07 20:11:13 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	  gdkpixbufoverlay: handle setting NULL gdkpixbuf
+	  ... which is a clearer way to clear any current overlay, other than
+	  fiddling with alpha or positioning properties to make it virtually go away.
+
+2017-01-20 17:16:10 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Stop reading a ncdt sub-tag if it goes behind the surrounding tag
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777532
+
+2017-01-20 07:58:26 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Fix various out of bounds reads when parsing ncdt tags
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777500
+
+2017-01-19 13:46:58 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Increment current stts index whenever we finished one stts entry
+	  Otherwise we could read more chunks than there are available, doing an
+	  out of bounds read and potentially crash.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777469
+
+2017-01-19 13:25:53 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  Revert "qtdemux: Increment current stts index in all code paths after reading one chunk"
+	  This reverts commit 99d5d7570d0b53dad3bc8eb653b1320ee422aace. It broke
+	  playback of various valid files.
+
+2017-01-19 07:52:33 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Increment current stts index in all code paths after reading one chunk
+	  Otherwise we could read more chunks than there are available, doing an
+	  out of bounds read and potentially crash.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777469
+
+2017-01-19 08:37:37 +0100  Edward Hervey <edward@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Initialize return variable
+	  In the normal use-case we would end up with ret being unitialized
+	  causing havoc.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777222
+
+2017-01-13 12:27:40 +0000  David Warman <dwarman@manglebit.org>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: avoid XMP tag parsing fatal error.
+	  qtdemux_handle_xmp_taglist() requires a writable taglist,
+	  but qtdemux->tag_list can become non-writable, specifically
+	  after sending global tags (qtdemux.c:958), which adds a
+	  second reference.  Ensure the list is made writable before
+	  calling (make_writable will copy the list if necessary).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766177
+
+2016-05-31 13:17:45 -0300  Thiago Santos <thiagossantos@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: rework taglist handling
+	  Keep taglist around during element existance to avoid having to
+	  create it at different places before usage. Makes code simpler to handle.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766177
+
+2017-01-16 11:58:02 +0100  Arnaud Vrac <avrac@freebox.fr>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: make flow return values handling clearer
+	  The flow return values was stored in the element before because the
+	  result had to be set from callbacks. This is not the case anymore, we
+	  can return the flow result directly from functions, making the code
+	  easier to understand.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777222
+
+2017-01-13 16:40:43 +0100  Arnaud Vrac <avrac@freebox.fr>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: properly track redirections
+	  The current code configures libsoup to handle redirections
+	  transparently, without informing the caller, thus preventing the element
+	  to record the redirect code and location uri.
+	  Fix this by always setting the SOUP_MESSAGE_NO_REDIRECT, preventing
+	  libsoup from handling the redirection. When we receive a redirection
+	  request and libsoup can safely handle it, return a custom error which
+	  triggers a retry with the new URI.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777222
+
+2017-01-17 10:53:39 +0100  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* gst/isomp4/gstqtmuxmap.c:
+	  qtmux: add 4444 and 4444xq variants to video/x-prores pad template caps
+	  They are handled since commit 7b565475bf551c53b8eed46f7086f3b372f1f6c4
+	  (qt: Add support for ProRes 4444 XQ).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777377
+
+2017-01-17 10:48:57 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/matroska/ebml-read.c:
+	  matroska: Quiet a WARN when parsing push mode
+	  This warning was noisy when returning EOS, which is
+	  just used to indicate more data is needed from upstream.
+
+2017-01-16 14:50:22 +0100  Georg Lippitsch <glippitsch@toolsonair.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Don't write Sync Sample Atom for ProRes
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777331
+
+2015-01-28 08:58:26 +0100  Enrico Jorns <ejo@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2_calls.h:
+	  v4l2: Remove usage and definition of LOG_CAPS macro
+	  Unlike former definitions of LOG_CAPS, the current implementation simply
+	  expands to GST_DEBUG_OBJECT. The LOG_CAPS macro is rarely used and most
+	  uses duplicate already existing GST_DEBUG_OBJECT lines. Therefore, the
+	  caps are often printed twice which unnecessarily clutters the debug log.
+	  Replace LOG_CAPS calls with GST_DEBUG_OBJECT, remove LOG_CAPS calls, and
+	  delete the definition of LOG_CAPS.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=776899
+
+2017-01-16 15:40:43 +0100  Jean-Christophe Trotin <jean-christophe.trotin@st.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: remove duplicated line of code
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777330
+
+2017-01-16 15:17:15 +0100  Jean-Christophe Trotin <jean-christophe.trotin@st.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: fix memory type in allocator probe
+	  The buffer memory type provided to the VIDIOC_CREATE_BUFS ioctl shall
+	  be set with the value ("memory") given as input parameter of the
+	  gst_v4l2_allocator_probe() function.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777327
+
+2017-01-14 15:27:19 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: fix other icon counter check
+	  It's never going to be 0 if we first increment and then check.
+
+2017-01-14 15:16:53 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: boldly assume that first 'covr' image is the front cover
+
+2017-01-14 15:09:07 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: extract cover art images into GST_TAG_IMAGE not PREVIEW_IMAGE
+	  These are usually much bigger than icon size and required by
+	  iTunes to be certain fairly large sizes. In qtmux it is also
+	  the IMAGE tags which we write out as 'covr' atoms.
+
+2017-01-14 15:05:36 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: also set PICTURE tag width and height if available
+
+2017-01-14 14:58:52 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: fix encoder init error with some GST_TAG_PREVIEW_IMAGEs
+	  The encoder fails to initialise when we try to set GST_TAG_PREVIEW_IMAGEs
+	  sent to use by qtdemux from iTunes-generated m4a files. We should
+	  not just blindly translate the PREVIEW tag to file icon image types,
+	  but check if the specific conditions required are met (i.e. image
+	  type 1 must be a 32x32 PNG icon, and what we're getting is 500x500).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=776962
+
+2017-01-13 12:39:00 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* meson.build:
+	  meson: bump version
+
+2016-12-22 17:40:40 +0200  Vivia Nikolaidou <vivia@toolsonair.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmuxsink: Add option for timecode-based split
+	  If this option is given, it will calculate the next split point based on
+	  timecode difference.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774209
+
+2017-01-13 00:01:06 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Don't reset request pad numbering across uses
+	  When reset, don't restart request pad numberings, as
+	  request pads can survive across state changes. Only
+	  restart at 0 if all request pads are handed back first.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777174
+
+2017-01-11 18:52:28 +0100  Mathieu Duponchelle <mathieu.duponchelle@opencreed.com>
+
+	* gst/rtpmanager/gstrtprtxqueue.c:
+	* gst/rtpmanager/gstrtprtxqueue.h:
+	  rtxqueue: Expose basic statistics as properties.
+	  Statistics about the total number of retransmission requests
+	  and the actual number of retransmitted packets can be helpful
+	  at application-level.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777182
+
+2017-01-12 17:45:35 +0100  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: simplify video/x-h264 caps handling
+	  'stream-format' and 'alignment' are defined in pad template caps so
+	  there is no need to check them again here. Also remove bitrate parsing from
+	  caps as bitrate in caps doesn't make sense but from tags, which is
+	  actually the case.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777181
+
+2016-12-08 17:02:22 +0100  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmuxmap.c:
+	  qtmux: add basic HEVC/H.265 muxing support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736752
+
+2017-01-11 18:29:05 +0100  Georg Lippitsch <glippitsch@toolsonair.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Calculate clean aperture size
+	  Calculate clean aperture dimensions by first guessing
+	  display aspect ratio based on pixel aspect ratio and
+	  frame size.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777100
+
+2017-01-10 18:19:55 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux_types.c:
+	  qtmux: Write tapt atom for MOV files if PAR not 1/1
+	  Needed for QuickTime 7 to properly play files.
+	  Also write the clap atom for MOV files always, not only when ProRes is
+	  used as a video codec. It's mandatory for MOV.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777100
+
+2017-01-12 16:32:45 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.11.1 ===
+
+2017-01-12 15:31:02 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	  Release 1.11.1
+
+2017-01-12 14:38:55 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2017-01-12 14:36:22 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/el.po:
+	* po/hr.po:
+	* po/id.po:
+	* po/zh_CN.po:
+	  po: Update translations
+
+2017-01-11 17:53:32 -0800  Andre McCurdy <armccurdy@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: free seqh after calling qtdemux_parse_svq3_stsd_data()
+	  The seqh buffer allocated in qtdemux_parse_svq3_stsd_data() needs to
+	  be freed by the caller after use.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777157
+	  Signed-off-by: Andre McCurdy <armccurdy@gmail.com>
+
+2017-01-10 16:01:35 +0100  Edward Hervey <edward@centricular.com>
+
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/qtdemux.c:
+	  isomp4: Don't spam debug log with knonw/padding atoms
+	  Only output WARNING messages for atoms we don't know how to handle
+	  instead of for padding/known atoms we don't need to do any processing
+	  on
+	  https://bugzilla.gnome.org/show_bug.cgi?id=777095
+
+2017-01-09 19:05:10 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtpsbcdepay.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  Fix indentation
+
+2017-01-09 19:04:04 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: rtpjitterbuffer: fix compiler warning due to c99-ism
+	  rtpjitterbuffer.c:592:3: error: ‘for’ loop initial declarations are only allowed in C99 mode
+
+2016-11-11 14:31:03 +1100  Matthew Waters <matthew@centricular.com>
+
+	* gst/autodetect/gstautodetect.c:
+	  autodetect: bring the element state down after success
+	  Otherwise some messages that are emitted by the element on NULL->READY
+	  will not reach the application.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=764947
+
+2017-01-08 01:13:32 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Write tfdt atom into fragmented files.
+	  The DASH spec requires that tfdt atoms be present, so
+	  write one out. ISO/IEC 23009-1:2014 6.3.4.2
+	  https://bugzilla.gnome.org/show_bug.cgi?id=708221
+
+2017-01-07 23:55:42 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Don't reset output timestamps when no tfdt
+	  If a fragmented stream doesn't have a tfdt, don't
+	  reset the output timestamps at each fragment boundary
+	  by erroneously using the default value of 0. Introduced
+	  by commit 69fc48
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754230
+
+2016-12-16 16:51:48 -0300  Thibault Saunier <thibault.saunier@osg.samsung.com>
+
+	* ext/vpx/meson.build:
+	* gst/equalizer/meson.build:
+	* gst/isomp4/meson.build:
+	* meson.build:
+	  meson: Install presets files
+
+2017-01-03 10:12:30 +0530  Garima Gaur <garima.g@samsung.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix some caps leaks
+	  https://bugzilla.gnome.org//show_bug.cgi?id=776789
+
+2016-12-22 17:34:08 +0200  Vivia Nikolaidou <vivia@ahiru.eu>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Return a bin with a "location" property as a sink
+	  Splitmuxsink might be called with a custom bin as a sink. If it has a
+	  "location" property, it can be used.
+
+2016-11-18 22:42:18 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmux: Rewrite buffer collection and scheduling
+	  Majorly change the way that splitmuxsink collects
+	  incoming data and sends it to the output, so that it
+	  makes all decisions about when / where to split files
+	  on the input side.
+	  Use separate queues for each stream, so they can be
+	  grown individually and kept as small as possible.
+	  This removes raciness I observed where sometimes
+	  some data would end up put in a different output file
+	  over multiple runs with the same input.
+	  Also fixes hangs with input queues getting full
+	  and causing muxing to stall out.
+
+2016-11-17 23:40:27 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	* tests/check/elements/splitmux.c:
+	  splitmuxsink: Add format-location-full signal
+	  Add a new signal for formatting the filename, which receives
+	  a GstSample containing the first buffer from the reference
+	  stream that will be muxed into that file.
+	  Useful for creating filenames that are based on the
+	  running time or other attributes of the buffer.
+	  To make it work, opening of files and setting filenames is
+	  now deferred until there is some data to write to it,
+	  which also requires some changes to how async state changes
+	  and gap events are handled.
+
+2016-12-31 01:54:01 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Always snap to the start of the keyframe
+	  When performing a key-unit seek, always snap to the start ts
+	  of the keyframe buffer we landed on so that the keyframe is
+	  entirely within the resulting outgoing segment. That seems
+	  the most sensible result, since the user requested snapping
+	  to the keyframe position.
+
+2016-12-31 01:48:04 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Omit cslg_shift when snapping seeks
+	  Segments times and seek requests are stored and handled
+	  in raw 'PTS' time, without the cslg_shift - which only applies
+	  to outgoing samples. Omit the cslg_shift portion when
+	  extracting PTS to compare for internal seek snaps.
+	  If the cslg_shift is included, then keyframe+snap-before seeks
+	  generate a segment start/stop time that already includes the
+	  cslg_shift, and it's then added a 2nd time, causing the
+	  first buffer(s) to have timestamps that are out of segment.
+
+2016-12-30 22:31:38 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	  qtmux: Remove bogus check in atom_stsc_add_new_entry()
+	  Remove an old check from atom_stsc_add_new_entry() that
+	  extends the last entry in the STSC if the samples per chunk
+	  matches, as the new interleave merging logic requires that
+	  the final entry by updateable. There's already code
+	  below which simply merges the final entry into the previous
+	  one when needed, so rely on that instead.
+	  Fixes asserts like:
+	  ERROR:atoms.c:2940:atom_stsc_update_entry: assertion failed:
+	  (atom_array_index (&stsc->entries, len - 1).first_chunk == first_chunk)
+
+2016-04-24 21:38:51 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix key_time in gst_qtdemux_adjust_seek()
+	  time in segment should be PTS based (not DTS).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765498
+
+2016-12-28 22:49:27 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	* gst/multifile/gstsplitmuxpartreader.h:
+	* gst/multifile/gstsplitmuxsrc.c:
+	  splitmuxsrc: Pass seek flags when activating.
+	  Pass all seek flags when activating a part
+	  based on a seek, so that SNAP flags are preserved.
+
+2016-11-26 01:13:19 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	  splitmux: Fix a small race in the splitmuxsrc
+	  Make sure the state of the parser is set to
+	  collecting streams before chaining up to the
+	  parent change_state() method, to close a
+	  small window that can cause playback to
+	  never commence.
+
+2017-01-02 15:06:33 +0100  Edward Hervey <edward@centricular.com>
+
+	* tests/check/elements/amrparse.c:
+	  check: Remove dead code
+
+2016-12-31 09:52:25 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesink.h:
+	  multifilesink: refactor max_files handling a bit
+	  Use GQueue instead of a GSList so we don't have to traverse
+	  the whole list to append something every time. And it also
+	  keeps track of the number of items in it for us.
+	  Add a function to add filenames to the list of old files and
+	  use it in more places, so that memory doesn't build up in
+	  other modes either if no max_files limit is specified.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766991
+
+2016-05-29 17:21:47 +0100  Ursula Maplehurst <ursula@kangatronix.co.uk>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: don't leak memory when no max-files limit is set
+	  Technically we weren't leaking the memory, just storing it internally
+	  and never using it until the element is freed. But we'd still use more
+	  and more memory over time, so this is not good over longer periods
+	  of time. Only keep track of files if there's actually a limit set,
+	  so that we will prune the list from time to time.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766991
+
+2016-12-29 12:39:20 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: adjust segment stop for KEY_UNIT negative rate seeking
+
+2016-12-29 12:25:35 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: implement pull mode SNAP flag seeking
+
+2016-12-29 11:26:33 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: tweak KEY_UNIT SNAP seek handling
+	  Previously, seeking to position y where y is (strictly) within a keyframe
+	  would seek to that keyframe both with SNAP_BEFORE and SNAP_AFTER,
+	  where the latter is now adjusted to really snap to the next keyframe.
+
+2016-12-28 13:23:11 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: correctly perform pull mode KEY_UNIT seeking
+	  Rather amazingly (and equally unnoticed), keyunit seeking resulted in segments
+	  where start != time (which is bogus for simple avi timeline).  So, properly
+	  adjust the segment (start) rather than fiddling with segment time (only).
+
+2016-12-28 13:04:54 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: restore considering of pull mode KEY_UNIT seeking
+	  ... by using the original seek event's flags rather than the corresponding
+	  segment flags, which do not have such counterpart flags (and
+	  do no longer have them covertly sneaking in nowadays).
+
+2015-05-08 12:44:01 +0200  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: only drop actual streamheader buffers with xiph codecs
+	  With Xiph codecs the stream header buffers are both in the caps and are
+	  usually also at the beginning of each input stream, but it's perfectly
+	  possible that the input stream does not have the stream header buffers
+	  inline in the data. Matroskamux would drop the first N buffers assuming
+	  they're stream headers, but this meant it would drop actual payload data
+	  when the stream didn't contain the stream headers inline. Fix this by
+	  only dropping leading buffers if they're flagged as stream headers. This
+	  fixes issues with streams that are being tapped into after streaming
+	  has started.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749098
+
+2016-12-21 17:43:58 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* tests/check/elements/matroskamux.c:
+	  matroskamux: adjust unit test to modified behaviour
+	  Now matroskamux mark all packets of audio-only streams as keyframes so
+	  in test_block_group after pushing the test audio data 4 buffers are produced
+	  and not more 2. The last buffer is the original data and must match with what
+	  pushed. The remaining ones are matroskamux headers
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754696
+
+2016-05-30 01:15:31 +0200  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: mark all packets of audio-only streams as keyframes
+	  This helps with streaming audio-only streams via multifdsink,
+	  tcpserversink and such.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754696
+
+2015-03-28 18:15:36 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: add G722 audio support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746574
+
+2016-12-13 11:11:07 +0900  Wonchul Lee <wonchul.lee@collabora.com>
+
+	* gst/udp/gstudpsrc.c:
+	  updsrc: Add to join multiple multicast interfaces
+	  https://bugzilla.gnome.org/show_bug.cgi?id=776030
+
+2015-03-25 13:51:30 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpklvdepay.c:
+	  rtpklvdepay: add the SPARSE flag to the outgoing stream-start event
+
+2016-12-14 14:37:45 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpmanager: place content before Since-version API marker
+	  Avoids confusing the parser
+
+2016-12-14 14:16:53 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* ext/shout2/gstshout2.c:
+	  shout2: fix 404 in package origin
+
+2016-12-14 21:45:15 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Check if we have enough data available when parsing edit lists
+	  Also consume the data entry by entry to get complicated indexing out of
+	  the code.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=776107
+
+2016-12-14 19:15:03 +0100  Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't check size in a non-list value
+	  After commit 1ea9735a I see these error while using the webcam
+	  integrated in my laptop:
+	  GStreamer-CRITICAL **: gst_value_list_get_size: assertion 'GST_VALUE_HOLDS_LIST (value)' failed
+	  The issue is gst_v4l2src_value_simplify() was doing its job of
+	  generating a single value, rather than the original list. That why,
+	  when getting the list size, a critical warning was raised.
+	  This patch takes advantage of the compiler optimizations to verify
+	  first if the list was simplified, thus use it directly, otherwise,
+	  if it is a list, verify its size.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=776106
+
+2016-12-14 10:39:12 +0100  Havard Graff <havard.graff@gmail.com>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests/jitterbuffer: Major refactoring and cleanups
+	  * Changed PCMU->TEST for common macros
+	  * Changed verify-functions (lost & rtx) into macros.
+	  * Remove option to add marker-bit for test-buffers (not used anywhere)
+	  * Add new push_test_buffer function that makes sure there are correlation
+	  between dts and the time on the clock. (classic test-mistake)
+	  * Established a generic starting-point for tests with the
+	  construct_deterministic_initial_state function and use it where
+	  applicable, which removes lots of "boilerplate" everywhere.
+	  * Add basic lost-event test
+	  * Remove as much "magic constants" as possible.
+	  * Remove 3 tests that no longer are testing anything that others don't,
+	  and was completely unmaintainable.
+	  * Remove unnecessary use of the testclock
+	  * Verify each test is testing what it actually says it does (and modify
+	  where it doesn't)
+	  In general, make the tests much smaller, better, more maintainable and
+	  readable.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774409
+
+2016-12-14 09:54:11 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* .gitignore:
+	* Makefile.am:
+	* configure.ac:
+	* gst-plugins-good.spec.in:
+	  Remove generated .spec file
+	  Likely extremely bitrotten, and we should not ship this anyway.
+
+2016-12-14 10:15:10 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Check that the XiTh size is big enough
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775794
+
+2016-12-09 20:27:53 +0900  Heekyoung Seo <heekyoung.seo@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Check node length of video sample description
+	  Add check for node length of video sample description and its fields and
+	  for the XiTh atom.
+	  Also unify the code a bit.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775794
+
+2016-12-08 18:50:52 +0900  Heekyoung Seo <heekyoung.seo@lge.com>
+
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Enable xvid/mp2 codec support
+	  Add support for xvid video and mp2 audio, add m2v1 fourcc.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775794
+
+2016-12-13 22:32:46 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpvp9depay.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	* tests/check/elements/rtprtx.c:
+	* tests/check/elements/vp9enc.c:
+	  gst: Don't declare variables inside the for loop header
+	  This is a C99 feature.
+
+2016-12-11 13:27:27 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: Ensure to reinit buffers whenever they were not allocated yet
+	  That is, whenever we go through start/stop we have to ensure that on the
+	  next opportunity the buffers are reallocated again. Otherwise the
+	  buffers might be NULL because the element was reused with the same
+	  configuration as before (i.e. set_caps() wouldn't have reinited the
+	  buffers).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775898
+
+2016-12-10 12:52:18 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* docs/design/Makefile.am:
+	* docs/design/design-rtpauxiliary.txt:
+	* docs/design/design-rtpcollision.txt:
+	* docs/design/design-rtpretransmission.txt:
+	  docs: design: remove, moved to gst-docs
+
+2016-12-09 17:17:35 -0300  Thibault Saunier <tsaunier@gnome.org>
+
+	* meson.build:
+	  meson: Support building without Gst debug
+
+2016-12-09 17:55:39 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/flx/gstflxdec.c:
+	* gst/flx/gstflxdec.h:
+	  flxdec: Only send SEGMENT events after CAPS
+	  I.e., don't just forward the event but delay it if we don't have caps on
+	  the srcpad yet.
+
+2016-12-09 17:49:40 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/flx/gstflxdec.c:
+	  flxdec: Unref and unmap buffers in all code paths as needed
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775888
+
+2016-12-06 17:42:31 +0530  Arun Raghavan <arun@osg.samsung.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't set empty interlace-mode list
+	  If for some reason we fail to probe formats (all try_fmt calls fail, for
+	  example), this is not a critical error, but we end up with an empty list
+	  of interlace modes. This causes all subsequent negotiation to fail.
+	  This patch fixes interlace-mode setting to be skipped if we failed to
+	  detect any.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775702
+
+2016-12-07 17:22:22 +0530  Garima Gaur <garima.g@samsung.com>
+
+	* gst/monoscope/gstmonoscope.c:
+	  monoscope: Unref allocation query after finished with it
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775752
+
+2016-12-06 07:48:47 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/flx/gstflxdec.c:
+	  flxdec: Allocate 0-initialized memory for the decoded frame
+	  Otherwise we might leak arbitrary information from the uninitialized
+	  memory if not every pixel is written.
+	  https://scarybeastsecurity.blogspot.gr/2016/12/1days-0days-pocs-more-gstreamer-flic.html
+
+2016-12-05 07:57:19 -0700  Matt Staples <staples255@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Fix session cleanup when handling redirect on PLAY
+	  Redirect on PLAY wasn't doing the necessary session cleanup. Fixed by
+	  removing code from gst_rtspsrc_send that changed the state varable upon
+	  encountering a redirect. Better to let the redirect handlers in
+	  gst_rtspsrc_retrieve_sdp and gst_rtspsrc_play do their own
+	  state-dependent cleanup.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775543
+
+2016-09-07 16:10:27 +0300  Aleix Conchillo Flaque <aleix@oblong.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: always send teardown request
+	  Allow CMD_CLOSE to cancel all commands not only CMD_PAUSE
+	  and ignore CMD_WAIT while closing.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=748360
+
+2016-12-03 08:19:27 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* README:
+	* common:
+	  Automatic update of common submodule
+	  From f980fd9 to 39ac2f5
+
+2016-12-01 17:08:09 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  jitterbuffer: Don't leak duplicate items
+	  When providing items with a seqnum, there is a (very small) probability
+	  that an element with the same seqnum already exists. Don't forget
+	  to free that item if it wasn't inserted.
+	  And avoid returning undefined values when dealing with duplicate items
+
+2016-12-01 11:23:02 +0100  Edward Hervey <edward@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Sanitize unknown codec caps
+	  We might have non-printable characters in the unknown fourcc, replace
+	  them with '_', in the same way we do it for unknown tags.
+
+2016-12-01 20:04:28 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Free vprp chunk also if it existed but we made no use of it
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775479
+
+2016-12-01 17:38:33 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: Fix memory leak when parsing attachments
+	  gst_tag_image_data_to_image_sample() does not take ownership of the
+	  passed memory, so don't set it to NULL to allow us to free it later.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775472
+
+2016-12-01 14:56:18 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: Unify zlib/bzip2 decompress loops with the ones from qtdemux
+	  Especially, simplify the code a bit.
+
+2016-12-01 14:41:48 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Increase inflate buffer in bigger steps
+	  1024 bytes is quite small, let's do 4096 bytes (or one page).
+	  Also remove redundant if, we're always in that case when getting here.
+
+2016-12-01 14:30:49 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Ensure that size of the pasp atom is as much as we need
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775455
+
+2016-12-01 14:30:10 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Free compressed moov node and it's corresponding decompressed data
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775455
+
+2016-12-01 14:29:21 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Check size of compressed MOOV header against available data
+	  And actually read the size of the cmvd atom from the right position.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775455
+
+2016-12-01 14:27:55 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix zlib inflate loop
+	  Handle errors cleanly, deallocate all memory and return the actual size
+	  of the inflated data.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775455
+
+2016-12-01 13:38:16 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Make sure we have enough data in the codec_data to be able to parse it
+	  Also error out cleanly if mapping the buffer failed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775450
+
+2016-12-01 13:32:22 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix out of bounds read in tag parsing code
+	  We can't simply assume that the length of the tag value as given
+	  inside the stream is correct but should also check against the amount of
+	  data we have actually available.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775451
+
+2016-12-01 15:06:06 +0530  Garima Gaur <garima.g@samsung.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtpsbcdepay.c:
+	  rtp: Fix some memory leaks in usage of gst_pad_get_current_caps()
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775071
+
+2016-11-30 17:56:02 +0200  Vivia Nikolaidou <vivia@ahiru.eu>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Read interlacing information from 'fiel' atom
+	  Read interlacing and TFF/BFF information from the 'fiel' atom and pass it
+	  into the caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775414
+
+2016-11-29 13:55:40 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix compiler warning
+	  qtdemux.c: In function ‘qtdemux_parse_trak’:
+	  qtdemux.c:10184:38: error: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 9 has type ‘gint {aka const int}’ [-Werror=format=]
+	  GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %lu", len,
+	  ^
+
+2016-11-28 13:45:24 -0800  Scott D Phillips <scott.d.phillips@intel.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Change off_t type to gint
+	  off_t is a signed integer type provided by sys/types.h on posix systems.
+	  Replace with gint for building on non-posix systems (like windows).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775287
+
+2016-11-22 21:00:25 -0800  Scott D Phillips <scott.d.phillips@intel.com>
+
+	* meson.build:
+	  meson: add libm to has_function checks
+	  The functions from math.h may be implemented in libm.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774876
+
+2016-10-27 23:02:37 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* ext/meson.build:
+	  Revert "meson: dv plugin now works on MSVC"
+	  This reverts commit 05a89613feff70cff416367f5aa807a1d5c68b63.
+	  Let's not put in stuff that needs unreleased Meson. This can go in
+	  for the next cycle.
+
+2016-11-28 13:51:41 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Ensure that tags are valid UTF-8 before adding them to the taglist
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775219
+
+2016-11-28 12:22:49 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/multipart/multipartdemux.c:
+	  multipartdemux: Post an error message on the bus if we got EOS without having added any pads
+
+2016-11-28 12:00:09 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Handle non-UTF8 headers and error reasons more gracefully
+	  Especially don't put them into GstStructures in one way or another, just
+	  ignore them or error out cleanly depending on the importance of their
+	  content.
+
+2016-11-28 09:30:25 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpvrawpay.c:
+	  vrawpay: Error out cleanly if mapping the video frame fails
+	  Instead of later dereferencing NULL and crashing.
+
+2016-11-27 11:14:13 +0100  Edward Hervey <edward@centricular.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: Update statistics before pushing
+	  If an element queries the number of retransmission buffers pushed
+	  *while* the push is still taking place (and before the object lock
+	  is taken just after) it would end up with the wrong statistic
+	  being reported.
+	  Increment it just before the push, avoids races when getting statistics
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768723
+
+2016-11-26 11:20:51 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* .gitmodules:
+	  common: use https protocol for common submodule
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775110
+
+2016-07-28 18:51:24 +0200  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  gstv4l2bufferpool: lock flush_stop against regular qbuf
+	  These can be called from different threads and both manipulate the
+	  pool->buffers array. Lock them properly and let flush_stop move the
+	  array contents into a temporary array on the stack to avoid having
+	  to call release_buffer under the object lock.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775015
+
+2016-11-24 14:25:22 +0100  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  gstv4l2bufferpool: remove critical error message when process is called on an inactive pool
+	  If the pool is inactive, it is guaranteed to also be flushing, so the
+	  following check will return GST_FLOW_FLUSHING anyway.
+	  This can happen if a v4l2src is blocking on DQBUF in create and is sent
+	  an EOS event on another thread. In that case the pool is set to
+	  flushing/inactive without locking, the v4l2src is unblocked, and may
+	  call pool_process with a valid buffer on the already inactive pool.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775014
+
+2016-11-24 14:41:52 +0100  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: release buffer if create fails
+	  gst_base_src_get_range does not expect a buffer to be returned in
+	  the error case, so we are leaking a reference here if create fails.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=775014
+
+2016-11-23 18:34:04 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Handle create_session() returning NULL in bundle code
+	  CID 1394492.
+
+2016-11-22 16:42:55 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Make sure to only change DTS of writable buffers
+	  And trivial cleanup
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774840
+
+2016-11-22 16:42:26 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Error out much earlier if we don't have a valid PTS
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774840
+
+2016-11-22 16:18:41 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Only use buffer durations if they are actually valid
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774840
+
+2016-11-22 15:59:19 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Revert commits that set DTS and duration on buffers unconditionally
+	  39f7e52266fde3b3c035e22cbcbb2bb1fa207b17 was setting the buffer duration
+	  to 0 if is not valid, under the assumption that this is "the last"
+	  buffer and no others are coming next. This is wrong, last_buf is the
+	  previous buffer and not the very last one.
+	  4e3c13c87c258c9c95e2217d32ab314d12b5fffc was setting DTS to 0 if there
+	  was none. This will set DTS to 0 for all e.g. audio streams, completely
+	  messing up calculations if streams don't start at 0.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774840
+
+2016-11-22 15:58:37 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Only write "gap" edit list if there is a non-zero gap
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774840
+
+2016-11-23 07:09:06 +1100  Matthew Waters <matthew@centricular.com>
+
+	* gst/flx/flx_color.c:
+	* gst/flx/flx_fmt.h:
+	* gst/flx/gstflxdec.c:
+	* gst/flx/gstflxdec.h:
+	  flxdec: rewrite logic based on GstByteReader/Writer
+	  Solves overreading/writing the given arrays and will error out if the
+	  streams asks to do that.
+	  Also does more error checking that the stream is valid and won't
+	  overrun any allocated arrays.  Also mitigate integer overflow errors
+	  calculating allocation sizes.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774859
+
+2016-11-23 11:20:49 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/flx/gstflxdec.c:
+	  flxdec: Don't unref() parent in the chain function
+	  We don't own the reference here, it is owned by the caller and given to
+	  us for the scope of this function. Leftover mistake from 0.10 porting.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774897
+
+2016-11-22 20:33:29 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/vpx/gstvpxdec.c:
+	  vpxdec: libvpx's release buffer is sometimes called with fb->priv==NULL
+	  Don't assert on this but just ignore these cases.
+
+2016-11-22 20:24:59 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Fix cluster searching if we search multiple times in one chunk
+	  After finding a cluster id in the byte reader, we skip ahead the reader
+	  position by one further byte to be able to continue searching from there
+	  inside the same chunk if the cluster candidate was a false positive.
+	  We have to accomodate for that additional byte when resuming the search,
+	  otherwise all following pulls are off-by-one for every resume and we run
+	  into an assertion.
+
+2016-11-22 20:01:20 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-ids.c:
+	  matroska: Add size checks to the parsing of FLAC headers
+
+2016-11-22 23:46:00 +1100  Matthew Waters <matthew@centricular.com>
+
+	* gst/flx/gstflxdec.c:
+	  flxdec: fix some warnings comparing unsigned < 0
+	  bf43f44fcfada5ec4a3ce60cb374340486fe9fac was comparing an unsigned
+	  expression to be < 0 which was always false.
+	  gstflxdec.c: In function ‘flx_decode_brun’:
+	  gstflxdec.c:322:33: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
+	  if ((glong) row - count < 0) {
+	  ^
+	  gstflxdec.c:332:33: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
+	  if ((glong) row - count < 0) {
+	  ^
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774834
+
+2016-11-21 16:17:31 +0200  Vivia Nikolaidou <vivia@ahiru.eu>
+
+	* gst/isomp4/gstqtmuxmap.c:
+	  qtmux: Enable up to 16 unpositioned raw audio channels
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774789
+
+2016-11-22 19:05:00 +1100  Matthew Waters <matthew@centricular.com>
+
+	* gst/flx/gstflxdec.c:
+	  flxdec: add some write bounds checking
+	  Without checking the bounds of the frame we are writing into, we can
+	  write off the end of the destination buffer.
+	  https://scarybeastsecurity.blogspot.dk/2016/11/0day-exploit-advancing-exploitation.html
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774834
+
+2016-11-21 15:25:23 +0000  David Evans <bbcrddave@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Be sure not to read off end of FLAC dfLa box
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773712
+
+2016-11-21 11:48:58 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: add support for skipping invalid data in push mode
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774566
+
+2016-11-21 11:48:29 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroskaparse: add support for skipping invalid data
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774566
+
+2016-11-18 17:00:59 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Move to new helper function to parse authentication responses
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774416
+
+2016-11-20 14:12:16 +0100  christophecvr <stefansat@telenet.be>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix wrong compiler warning with gcc 6.2
+	  | ../../../git/gst/isomp4/qtdemux.c: In function 'qtdemux_parse_tree':
+	  | ../../../git/gst/isomp4/qtdemux.c:10224:24: error: 'size' may be used uninitialized in this function [-Werror=maybe-uninitialized]
+	  |                  offset += size;
+	  |                         ^~
+	  | ../../../git/gst/isomp4/qtdemux.c:10197:25: note: 'size' was declared here
+	  |                  guint32 size, tag;
+	  |                          ^~~~
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774747
+
+2016-11-20 16:15:07 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* Makefile.am:
+	* configure.ac:
+	* win32/MANIFEST:
+	* win32/common/config.h:
+	  win32: remove copies of generated headers
+
+2016-11-20 13:14:08 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: Ensure that raw video have properly aligned buffers
+	  That is, aligned to to 32 bytes for video. Fixes crashes if the raw
+	  buffers are passed to SIMD processing functions.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774428
+
+2016-11-20 13:08:27 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Ensure that raw audio and video have properly aligned buffers
+	  That is, aligned to the basic type for audio and to 32 bytes for video.
+	  Fixes crashes if the raw buffers are passed to SIMD processing functions.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774428
+
+2016-11-14 14:44:11 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Always write edit lists for the tracks to give a more accurate duration
+	  Always write an edit list for the whole track. In general this is not
+	  necessary except for the case of having a gap or DTS adjustment but
+	  it allows to give the whole track's duration in the usually more
+	  accurate media timescale.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774403
+
+2016-11-18 22:45:45 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Remove useless return variable
+	  qtdemux_expose_streams() returns flow error immediately, if there is an error.
+	  So, the variable for the flow return is not needed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774674
+
+2016-11-17 13:59:48 +0000  David Evans <bbcrddave@gmail.com>
+
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_dump.c:
+	* gst/isomp4/qtdemux_dump.h:
+	* gst/isomp4/qtdemux_types.c:
+	  qtdemux: Add support for FLAC encapsulated in ISOBMFF
+	  As defined by
+	  https://git.xiph.org/?p=flac.git;a=blob_plain;f=doc/isoflac.txt
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773712
+
+2016-11-17 19:59:53 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Mark pad as needing reconfiguration again if it failed
+	  And return FLUSHING instead of NOT_NEGOTIATED on flushing pads.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774623
+
+2016-11-17 19:59:26 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/monoscope/gstmonoscope.c:
+	  monoscope: Mark pad as needing reconfiguration again if it failed
+	  And return FLUSHING instead of NOT_NEGOTIATED on flushing pads.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774623
+
+2016-11-17 19:58:52 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Mark pad as needing reconfiguration again if reconfiguration failed
+	  And consider negotiation failures on flushing pads as FLUSHING, not as
+	  NOT_NEGOTIATED.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774623
+
+2016-11-17 19:56:23 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/dv/gstdvdec.c:
+	  dvdec: Fix handling of negotiation failures
+	  Return NOT_NEGOTIATED if sending the caps event fails, or FLUSHING if
+	  the pad was flushing at that point.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774623
+
+2016-11-17 17:16:26 -0800  Scott D Phillips <scott.d.phillips@intel.com>
+
+	* meson.build:
+	  meson: add_global_arguments -> add_project_arguments
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774656
+
+2016-11-16 10:53:51 +0530  Vinod Kesti <vinodkesti@yahoo.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: pad request fails for flvmux
+	  splitmuxsink requests pad from element using pad template like "video_%u", "audio_%u" and "sink_%d". This is true for most of the muxers.
+	  But splitmuxsink not able to request pad to flvmux as flvmux has "audio" and "video" as pad templates.
+	  fix: splitmuxsink should fallback to "audio" and  "video" when template not found.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774507
+
+2016-11-17 10:24:28 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-parse.c:
+	  matroskaparse: Add remaining relevant parts from a3a55305 to the parser
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774566
+
+2016-11-16 22:39:01 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-parse.c:
+	  matroskaparse: ignore parsing errors at the end of the file
+	  This is the same change as a3a55305 for the parser.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774566
+
+2016-11-16 08:56:34 +0100  Philippe Normand <philn@igalia.com>
+
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/rtpbundle.c:
+	* tests/check/meson.build:
+	* tests/examples/rtp/.gitignore:
+	* tests/examples/rtp/Makefile.am:
+	* tests/examples/rtp/client-rtpbundle.c:
+	* tests/examples/rtp/server-rtpbundle.c:
+	  rtpbin: receive bundle support
+	  A new signal named on-bundled-ssrc is provided and can be
+	  used by the application to redirect a stream to a different
+	  GstRtpSession or to keep the RTX stream grouped within the
+	  GstRtpSession of the same media type.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772740
+
+2016-11-15 16:52:39 +0530  Vinod Kesti <vinodkesti@yahoo.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: assertion while converting ADTS stream to RAW
+	  aacparse resizes input buffer while converting ADTS stream to RAW,
+	  During buffer resize buffer write permission is not checked.
+	  This throws gst_buffer_is_writable assertion and leads to AV sync issue some times.
+	  It is corrected by making buffer writeable using gst_buffer_make_writable
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774129
+
+2016-11-15 21:17:51 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Don't modify upstream TIME segment
+	  TIME segment implies that stream/running time is being handled by upstream.
+	  So, we shouldn't override it without any clue.
+	  This patch is for fixing seek in DASH streaming.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774196
+
+2016-11-14 22:33:27 +0530  Arun Raghavan <arun@osg.samsung.com>
+
+	* config.h.meson:
+	  meson: Add define for v4l2-probe config option
+
+2016-11-14 17:37:51 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/interleave/deinterleave.c:
+	  deinterleave: Reset caps accumulator to ANY when resyncing the adapter, not EMPTY
+	  The accumulator is filled by intersecting with all the pad caps, as such
+	  it must be initialized with ANY (like it is before the iteration is
+	  started) and not to EMPTY.
+	  Fixes the CAPS query always returning EMPTY caps when resyncing happened
+	  during the query, e.g. because pads were added/removed.
+
+2016-11-14 12:13:14 +0100  Petr Kulhavy <brain@jikos.cz>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: remove redundant saddr unref
+	  The g_object_unref (saddr) before receiving message seems to be redundant as it
+	  is done just before jumping to retry
+	  Though not directly related, part of
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772841
+
+2016-11-12 23:34:23 +0100  Petr Kulhavy <brain@jikos.cz>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: receive control messages only in multicast
+	  Control messages are used only in multicast mode - to detect if the destination
+	  address is not ours and possibly drop the packet. However in non-multicast
+	  modes the messages are still allocated and freed even if not used. Therefore
+	  request control messages from g_socket_receive_message() only in multicast
+	  mode.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772841
+
+2016-11-11 10:45:01 -0800  Scott D Phillips <scott.d.phillips@intel.com>
+
+	* gst/matroska/matroska-mux.c:
+	  Use intermediate guint when handling GstVideoMultiviewFlags
+	  The underlying integer type of the enum GstVideoMultiviewFlags is
+	  implementation defined and may not have the same size as guint.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774293
+
+2016-11-11 10:44:18 -0800  Scott D Phillips <scott.d.phillips@intel.com>
+
+	* gst/multifile/gstsplitfilesrc.c:
+	  splitfilesrc: update uri_get_type to match the prototype in GstURIHandlerInterface
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774293
+
+2016-10-26 22:37:34 -0700  Scott D Phillips <scott.d.phillips@intel.com>
+
+	* meson.build:
+	  meson: don't add_global_arguments when being built as a subproject
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773568
+
+2016-10-21 15:49:36 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstflacparse.h:
+	  flacparse: fix header rewriting being ignored
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727802
+
+2016-11-09 06:25:27 +0000  Sean DuBois <sean@siobud.com>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  flvmux: Add metadatacreator property
+	  Allow users to set metadatacreator value in the meta packet
+	  https://bugzilla.gnome.org/show_bug.cgi?id=774131
+
+2016-11-01 19:56:36 +0200  Vivia Nikolaidou <vivia@toolsonair.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmuxsink: Use first buffer TS as mux start time
+	  Do not use last buffer TS + buffer duration because buffer duration
+	  might be inaccurate, especially for frame rates like 30fps where a
+	  rounding error is observed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773785
+
+2016-11-03 15:03:59 +0100  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: fix timer-reuse bug
+	  When doing rtx, the jitterbuffer will always add an rtx-timer for the next
+	  sequence number.
+	  In the case of the packet corresponding to that sequence number arriving,
+	  that same timer will be reused, and simply moved on to wait for the
+	  following sequence number etc.
+	  Once an rtx-timer expires (after all retries), it will be rescheduled as
+	  a lost-timer instead for the same sequence number.
+	  Now, if this particular sequence-number now arrives (after the timer has
+	  become a lost-timer), the reuse mechanism *should* now set a new
+	  rtx-timer for the next sequence number, but the bug is that it does
+	  not change the timer-type, and hence schedules a lost-timer for that
+	  following sequence number, with the result that you will have a very
+	  early lost-event for a packet that might still arrive, and you will
+	  never be able to send any rtx for this packet.
+	  Found by Erlend Graff - erlend@pexip.com
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773891
+
+2016-10-09 15:59:05 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: fix lost-event using dts instead of pts
+	  The lost-event was using a different time-domain (dts) than the outgoing
+	  buffers (pts). Given certain network-conditions these two would become
+	  sufficiently different and the lost-event contained timestamp/duration
+	  that was really wrong. As an example GstAudioDecoder could produce
+	  a stream that jumps back and forth in time after receiving a lost-event.
+	  The previous behavior calculated the pts (based on the rtptime) inside the
+	  rtp_jitter_buffer_insert function, but now this functionality has been
+	  refactored into a new function rtp_jitter_buffer_calculate_pts that is
+	  called much earlier in the _chain function to make pts available to
+	  various calculations that wrongly used dts previously
+	  (like the lost-event).
+	  There are however two calculations where using dts is the right thing to
+	  do: calculating the receive-jitter and the rtx-round-trip-time, where the
+	  arrival time of the buffer from the network is the right metric
+	  (and is what dts in fact is today).
+	  The patch also adds two tests regarding B-frames or the
+	  “rtptime-going-backwards”-scenario, as there were some concerns that this
+	  patch might break this behavior (which the tests shows it does not).
+
+2016-11-03 16:33:53 +0100  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: fix bug in reschedule_timer
+	  The new timeout is always going to be (timeout + delay), however, the
+	  old behavior compared the current timeout to just (timeout), basically
+	  being (delay) off.
+	  This would happen if rtx-delay == rtx-retry-timeout, with the result that
+	  a second rtx attempt for any buffers would be scheduled immediately instead
+	  of after rtx-delay ms.
+	  Simply calculate (new_timeout = timeout + delay) and then use that instead.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773905
+
+2016-11-03 13:27:51 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/wavparse.c:
+	* tests/files/Makefile.am:
+	* tests/files/audiotestsrc.wav:
+	  tests: wavparse: add test for processing an actual .wav file
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773861
+
+2016-11-03 12:34:51 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Don't set caps to NULL after setting them on the srcpad
+	  We would like to check later on EOS if we found a known stream type or
+	  not, to possibly post an error message.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773861
+
+2016-11-02 14:33:28 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Don't deref NULL pads in debug output
+	  That tends to crash.
+
+2016-11-02 11:46:07 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  isomp4: Don't use gst_video_colorimetry_to_string_full()
+	  The API was reverted. Just use the plain
+	  gst_video_colorimetry_to_string() function.
+
+2016-11-02 11:00:13 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Fix GObject warnings on shutdown.
+	  Commit 83e718 added a pad template to splitmux request
+	  pads, which means that GstElement now releases the pads on
+	  dispose, but after having removed all elements in the bin
+	  and unlinked them. Make sure we can handle cleanup in that case
+	  without throwing assertions.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773784
+
+2016-11-02 02:25:51 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsrc.c:
+	* gst/multifile/gstsplitmuxsrc.h:
+	  splitmuxsrc: Store seek seqnum and send it on EOS / segment events.
+	  GES relies on the EOS event having the seqnum of the seek that
+	  caused it.
+
+2016-11-02 02:25:00 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsrc.c:
+	  splitmuxsrc: Forward a not-linked error on the bus
+	  Handle not-linked as for other fatal errors and post it
+	  onto the bus so the app knows
+
+2016-11-01 21:00:15 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix compiler warning
+	  qtdemux.c: In function ‘qtdemux_parse_tree’:
+	  qtdemux.c:10139:16: error: ‘color_table_id’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
+	  if (color_table_id != 0) {
+	  ^
+	  qtdemux.c:10121:19: note: ‘color_table_id’ was declared here
+	  guint16 color_table_id;
+	  ^~~~~~~~~~~~~~
+
+2016-10-20 17:40:59 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Use a default interleave of 250ms for all codecs
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773217
+
+2016-10-19 14:33:33 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Use a default interleave when ProRes is used
+	  The ProRes guidelines suggest an interleave of 0.5s is common, but
+	  specifies that for ProRes at most 2MB (for SD) and 4MB (for HD) should
+	  be used per chunk.
+	  It might also make sense to use similar numbers in general.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773217
+
+2016-10-19 14:25:28 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  qtmux: Allow configuring the interleave size in bytes/time
+	  Previously we were switching from one chunk to another on every single
+	  buffer. This wastes some space in the headers and, depending on the
+	  software, might depend in more reads (e.g. if the software is reading
+	  multiple samples in one go if they're in the same chunk).
+	  The ProRes guidelines suggest an interleave of 0.5s is common, but
+	  specifies that for ProRes at most 2MB (for SD) and 4MB (for HD) should
+	  be used per chunk. This will be handled in a follow-up commit.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773217
+
+2016-09-30 18:22:27 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Set compressor name, horizontal/vertical resolution and depth for ProRes
+	  This is also required by some software to handle ProRes files.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769048
+
+2016-09-30 18:05:38 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux.c:
+	  qt: Add support for ProRes 4444 XQ
+	  And also 4444 in the muxer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769048
+
+2016-09-30 17:58:37 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux_types.c:
+	  qtmux: Write 'clap' atom for ProRes
+	  It's required for ProRes to work with other software.
+	  It is also in the MP4 standard, but inventing values here seems a bit
+	  tricky for the general case and it does not really give any extra
+	  information.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769048
+
+2016-09-30 09:55:58 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Read colorimetry information from colr atom if available
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772181
+
+2016-09-29 21:56:18 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Always write colr atom with the colorimetry information
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772181
+
+2016-09-29 18:16:18 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Fix writing of the 'fiel' extension atom
+	  This was also wrong for JPEG2000. Also write it for all MOV files and
+	  JPEG2000, not only for ProRes.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769048
+
+2016-09-29 17:40:23 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	  qtmux: Write 4 bytes of zeroes at the end of the sample description extensions
+	  This is working around some broken software.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769048
+
+2016-09-28 20:55:24 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	  atoms: 'pasp' atom is also part of MP4, write it always
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769048
+
+2016-07-11 19:30:12 +0300  Vivia Nikolaidou <vivia@ahiru.eu>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Write additional atoms for prores video
+	  These required atoms are: colorimetry, field information, spatial/temporal
+	  quality, and vendor.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769048
+
+2014-06-16 17:20:32 +0200  Stian Selnes <stian.selnes@gmail.com>
+
+	* gst/rtp/gstrtph263depay.c:
+	  rtph263depay: Don't drop mode b packets with picture start code
+	  Some buggy payloaders, e.g. rtph263pay, may use mode B for packets
+	  that starts with a picture (or GOB) start code although it's not
+	  allowed. Let's be nice and not drop these packets/frames.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773516
+
+2016-06-22 13:59:35 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtp/gstrtph263ppay.c:
+	* tests/check/elements/rtph263.c:
+	  rtph263ppay: Fix caps leak
+	  Fix leaking caps when downstream has not-fixed caps.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773515
+
+2016-10-26 16:42:19 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: Fix indentation
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773514
+
+2016-10-18 11:35:58 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: Use GST_TRACE_OBJECT for logging bitstream parsing
+	  Bump the bitstream parsing to TRACE log level so it doesn't flood the
+	  output when trying to read the more useful DEBUG and LOG messages.
+	  Also use GST_DEBUG_OBJECT instead of GST_DEBUG in various places
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773514
+
+2016-10-18 11:09:10 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: Fix leak for B-fragments
+	  Altough commits 6a16be7, 64f9d08 and 0c7e3a8 fixed some issues they
+	  introduced others. This patch fixes the leak of one macroblock for every
+	  B fragment.
+	  Macroblock structures must not be freed immediately after finding the
+	  boundaries as they are stored and used later. However the inital dummy
+	  structure (used for finding the first boundary) must be freed.
+	  CID #1212156
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773512
+
+2016-10-20 13:14:13 +0200  Alejandro G. Castro <alex@igalia.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpbin: avoid generating errors when rtcp messages are empty and check the queue is not empty
+	  Add a check to verify all the output buffers were empty for the
+	  session in a timout and log an error.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773269
+
+2016-10-26 13:21:29 +0200  Alejandro G. Castro <alex@igalia.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpbin: pipeline gets an EOS when any rtpsources byes
+	  Instead of sending EOS when a source byes we have to wait for
+	  all the sources to be gone, which means they already sent BYE and
+	  were removed from the session. We now handle the EOS in the rtcp
+	  loop checking the amount of sources in the session.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773218
+
+2016-10-21 17:31:00 +0000  Matt Staples <staples255@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Also handle redirect on PLAY
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772610
+
+2016-08-30 10:24:43 +0200  Petr Kulhavy <brain@jikos.cz>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: allow missing control attribute in case of a single stream
+	  Improve RFC2326 - chapter C.3 compatibility:
+	  In case just a single stream is specified in SDP and the control attribute
+	  is missing do not drop the stream but rather assume "a=control:*"
+	  https://bugzilla.gnome.org/show_bug.cgi?id=770568
+
+2016-10-08 18:11:17 +0200  William Manley <will@williammanley.net>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2: Warn, don't assert if v4l gives us a buffer with a too large size
+	  I've seen problems where the `bytesused` field of `v4l2_buffer` would be
+	  a silly number causing the later call to:
+	  gst_memory_resize (group->mem[i], 0, group->planes[i].bytesused);
+	  to result in this error to be printed:
+	  (pulsevideo:11): GStreamer-CRITICAL **: gst_memory_resize: assertion 'size + mem->offset + offset <= mem->maxsize' failed
+	  besides causing who-knows what other problems.
+	  We make the assumption that this buffer has still been dequeued correctly
+	  so just clamp to a valid size so downstream elements won't end up in
+	  undefined behaviour.
+	  The invalid `v4l2_buffer` I saw from my capture device was:
+	  buffer = {
+	  index = 0,
+	  type = 1,
+	  bytesused = 534748928, // <- Invalid
+	  flags = 8260, // V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC | V4L2_BUF_FLAG_ERROR | V4L2_BUF_FLAG_DONE
+	  field = 01330, // <- Invalid
+	  timestamp = {
+	  tv_sec = 0,
+	  tv_usec = 0
+	  },
+	  timecode = {
+	  type = 0,
+	  flags = 0,
+	  frames = 0 '\000',
+	  seconds = 0 '\000',
+	  minutes = 0 '\000',
+	  hours = 0 '\000',
+	  userbits = "\000\000\000"
+	  },
+	  sequence = 0,
+	  memory = 2,
+	  m = {
+	  offset = 3537219584,
+	  userptr = 140706665836544, // Could be nonsense, not sure
+	  planes = 0x7ff8d2d5b000,
+	  fd = -757747712
+	  },
+	  length = 2764800,
+	  reserved2 = 0,
+	  reserved = 0
+	  }
+	  This is from gdb with my own annotations added.
+	  This was with gst-plugins-good 1.8.1, a Magewell XI100DUSB-HDMI video
+	  capture device and kernel 3.13 using a dodgy HDMI cable which is great at
+	  breaking HDMI capture devices.  I'm using io-mode=userptr and have built
+	  gst-plugins-good without libv4l.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769765
+
+2016-10-20 20:41:07 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Use a better default value for the movie header timescale
+	  Take the maximum video timescale, or if no video track is present the
+	  previous value of 1800.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769041
+
+2016-10-20 20:07:19 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Be more clever with the default video track timescale
+	  Use the number of milliframes per second for integral and drop-frame
+	  framerates, as suggested by the QT file format specification and other
+	  places. We already did that for integral framerates before, but not for
+	  drop-frame framerates. This now keeps precision better.
+	  For all other framerates, check if it's close to a well-known framerate
+	  and use that instead.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769041
+
+2016-10-10 13:00:01 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: extract interlaced information from jpeg video
+	  This information is hidden in a small chunk of data.
+	  Format found at https://developer.apple.com/standards/qtff-2001.pdf,
+	  page 92, "Video Sample Description", under table 3.1.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767771
+
+2016-10-26 12:46:28 +0530  Jagadish <jagadishkamathk@gmail.com>
+
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	  gdkpixbufoverlay: Fixing x and y offset computation
+	  While computing the x and y offsets, it's the video resolution and
+	  resized overlay resolution to be used instead of actual overlay image
+	  resoltuion. Due to this, the overlay image used to get wrongly overlayed
+	  in undesired location
+	  https://bugzilla.gnome.org/show_bug.cgi?id=757292
+
+2016-11-01 18:09:00 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* meson.build:
+	  meson: update version
+
+2016-10-24 16:56:31 +0000  Enrique Ocaña González <eocanha@igalia.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Use the tfdt decode time on byte streams when it's significantly different than the time in the last sample
+	  We consider there's a sifnificant difference when it's larger than on second
+	  or than half the duration of the last processed fragment in case the latter is
+	  larger.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754230
+
+=== release 1.11.0 ===
+
+2016-11-01 18:53:15 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.10.0 ===
+
+2016-11-01 17:57:44 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.10.0
+
+2016-11-01 17:47:31 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2016-11-01 17:41:51 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/el.po:
+	  po: Update translations
+
+2016-10-27 12:01:55 +0200  Tobias Schneider <tobias.schneider@voiceinterconnect.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: fix extra-controls leak
+	  Gst struct v4l2object->extra_controls is created if user sets appropriate
+	  option but it is not freed on destruction of v4l2object.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773580
+
+2016-10-31 18:00:07 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  Revert "souphttpsrc: reduce reading latency by using non-blocking read"
+	  This reverts commit 8816764112408766889c8b680a3af51115df4bf5.
+	  It causes issues with the timeouts, and causes connections to be closed
+	  without actual reason. Needs further investigation.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773509
+
+2016-10-31 09:00:49 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Don't try to add srcpad if we don't know valid caps yet
+	  Otherwise we'll run into an assertion on specially crafted files.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773643
+
+2016-10-27 11:23:51 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* meson.build:
+	  meson: Remove uselessly duplicated dep checks
+	  These checks are done inside the meson.build files for each plugin.
+
+2016-10-27 11:22:59 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* ext/meson.build:
+	  meson: dv plugin now works on MSVC
+	  Needs a Meson patch to filter out the useless -lpthread
+	  https://github.com/mesonbuild/meson/pull/962
+
+2016-10-27 14:03:48 +0200  Branko Subasic <branko@axis.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: allow resolutions above 4096
+	  Modify the caps string to allow width and height greater than 4096.
+	  There is no need to restrict it since the matroska format allows the
+	  width and height values to be up to eight bytes long.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773582
+
+2016-10-23 17:23:10 -0700  Scott D Phillips <scott.d.phillips@intel.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Check for G_PLATFORM_WIN32 for presence of ipi_spec_dest
+	  G_OS_WIN32 is only set when not building with cygwin, but
+	  ipi_spec_dest is missing both with and without cygwin.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773114
+
+2016-10-26 08:51:40 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: reset read_position when reading fails
+	  souphttpsrc maintains two variables for the position:
+	  * 'request_position' is where we want to be
+	  * 'read_position' is where we are
+	  During Normal operations both are updated in sync when data arrives. A seek
+	  changes 'request_position' but not 'read_position'.
+	  When the two positions get out of sync, then a new request is send and the
+	  'Range' header is adjusted to the current 'request_position'.
+	  Without this patch, if reading fails, then the source is destroyed. This
+	  triggers a new request, but the range remains unchanged. As a result, the
+	  old range is used and old data will be read.
+	  Changing the 'read_position' to -1 makes it explicitly different from
+	  'request_position' and as a result the 'Range' header is updated correctly.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773509
+
+2016-10-25 08:54:34 -0700  Scott D Phillips <scott.d.phillips@intel.com>
+
+	* meson.build:
+	  meson: Don't depend on gstreamer-check-1.0 on windows
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773114
+
+2016-10-25 15:24:20 +0200  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: reset connection info to non-flushing when closing
+	  This solves a hanging mainloop in following scenario:
+	  * connect to source
+	  * network/server drops
+	  * pipeline set to NULL (and connection to flushing as part)
+	  * pipeline set to PAUSED/PLAYING (connection to non-flushing, but not recorded)
+	  * [connecting still not possible]
+	  * pipeline set to NULL => mainloop hangs (since no actual flushing is done)
+
+2016-10-26 14:32:48 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmuxsink: Only allow one video request pad
+	  The pacing of the overall muxing is controlled
+	  by the video GOPs arriving, so we can only handle
+	  1 video stream, and the request pad is named accordingly.
+	  Ignore a request for a 2nd video pad if there's already
+	  an active one.
+
+2016-10-26 11:59:32 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Take ownership of floating refs
+	  sink the floating ref when handed a muxer or sink to use so
+	  we clearly take ownership.
+
+2016-10-25 14:51:52 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Set child elements to NULL when removing.
+	  Make sure that elements are in the NULL state when removing.
+	  Fixes critical warnings when errors occur early on in starting up.
+
+2016-10-25 14:50:53 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Set pad template on request sink pads
+	  Ensure that the ghost pad returned as a request pad
+	  has the template that was requested
+
+2016-10-25 10:50:47 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* meson.build:
+	* tests/check/meson.build:
+	  Revert "meson: move gstreamer-check-1.0 dependency to tests/check"
+	  This reverts commit 46632694662b96fddb848a1f2091a215b28a2d35.
+	  Does not actually work. See:
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773114#c31
+
+2016-06-08 11:24:37 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Assume PTS is DTS when PTS is missing
+	  This fixes issue for encoders that only sets the DTS. We assume that
+	  there was no re-ordering when that happens.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762207
+
+2016-10-24 00:34:15 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/meson.build:
+	  meson: fix build outside of gst-all
+
+2016-10-21 00:42:54 -0700  Scott D Phillips <scott.d.phillips@intel.com>
+
+	* sys/directsound/meson.build:
+	  meson: directsound: Add ole32 library dependency
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773114
+
+2016-10-21 00:42:18 -0700  Scott D Phillips <scott.d.phillips@intel.com>
+
+	* meson.build:
+	* tests/check/meson.build:
+	  meson: move gstreamer-check-1.0 dependency to tests/check
+	  https://bugzilla.gnome.org/show_bug.cgi?id=773114
+
+2016-10-20 22:08:14 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/videomixer.c:
+	  tests: videomixer: disable racy flush_start_flush_stop test
+	  It's been broken for years, and it's unlikely it will ever
+	  be fixed for collectpads/videomixer now that there's compositor
+	  which works fine. So let's disable it, since all it does
+	  is that it creates noise that distracts from other failures.
+	  Also see the corresponding adder bug as it failed in the same way:
+	  https://bugzilla.gnome.org/show_bug.cgi?id=708891
+
+2016-10-09 16:56:10 +0200  Jan Alexander Steffens (heftig) <jan.steffens@gmail.com>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: Fix souphttpsrc tests without CK_FORK=no
+	  It seems that the forked processes all attempt to handle the listening
+	  socket from the server, and only one has to shutdown the socket to break
+	  the server completely.
+	  Create a new server inside each test to avoid this.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772656
+
+2016-10-09 15:23:51 +0200  Jan Alexander Steffens (heftig) <jan.steffens@gmail.com>
+
+	* tests/check/elements/level.c:
+	  tests: Fix level test in CK_FORK=no mode
+	  The tests accumulate buffers in GstCheck's buffers list, and the list is
+	  not (consistently) reset between tests. Do that and remove the now
+	  conflicting unrefs for outbuffers.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772644
+
+2016-10-07 13:04:27 +0530  Gaurav Gupta <g.gupta@samsung.com>
+
+	* sys/waveform/gstwaveformsink.c:
+	  waveformsink: Fix Memory leak using GST_PTR_FORMAT
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772497
+
+2016-10-18 12:23:42 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* gst/monoscope/meson.build:
+	  meson: Add missing gstaudio dep to monoscope
+	  In file included from ../subprojects/gst-plugins-good/gst/monoscope/gstmonoscope.c:42:0:
+	  ../subprojects/gst-plugins-base/gst-libs/gst/audio/audio.h:26:39: fatal error: gst/audio/audio-enumtypes.h: No such file or directory
+	  #include <gst/audio/audio-enumtypes.h>
+	  ^
+	  compilation terminated.
+	  https://ci.gstreamer.net/job/GStreamer-master-meson/271/console
+
+2016-10-16 02:18:22 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* gst/multifile/meson.build:
+	  meson: Add missing pbutils dependency to multifile
+	  Found via the Jenkins CI:
+	  FAILED: subprojects/gst-plugins-good/gst/multifile/gstmultifile@sha/gstsplitmuxsink.c.o
+	  [...]
+	  In file included from ../subprojects/gst-plugins-good/gst/multifile/gstsplitmuxsink.h:24:0,
+	  from ../subprojects/gst-plugins-good/gst/multifile/gstsplitmuxsink.c:59:
+	  ../subprojects/gst-plugins-base/gst-libs/gst/pbutils/pbutils.h:30:43: fatal error: gst/pbutils/pbutils-enumtypes.h: No such file or directory
+	  #include <gst/pbutils/pbutils-enumtypes.h>
+	  ^
+	  compilation terminated.
+	  https://ci.gstreamer.net/job/GStreamer-master-meson/263/console
+
+2016-10-15 22:11:08 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* meson.build:
+	  meson: Don't set c_std to gnu99
+	  Use the default for each compiler on every platform instead. This
+	  improves our compatibility with compilers that don't have gnu99 as
+	  a c_std.
+
+2016-10-04 18:04:11 -0300  Thibault Saunier <thibault.saunier@osg.samsung.com>
+
+	* meson.build:
+	* tests/check/getpluginsdir:
+	* tests/check/meson.build:
+	  meson: Make use of new environment object and set plugin path to builddir
+	  Workaround source_root being the root directory of all projects in the subproject
+	  case and remove now unneeded getpluginsdir
+	  Bump meson requirement to 0.35
+
+2016-10-06 11:15:54 +0530  Gaurav Gupta <g.gupta@samsung.com>
+
+	* tests/examples/rtp/client-rtpaux.c:
+	  tests: Fix memory leak in test rtpaux test
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772496
+
+2016-10-03 11:27:54 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Forward latency queries to upstream
+	  Without this, latency queries to imagefreeze will fail.
+
+2016-09-30 11:35:39 -0300  Thibault Saunier <thibault.saunier@osg.samsung.com>
+
+	* hooks/pre-commit.hook:
+	* meson.build:
+	* tests/check/getpluginsdir:
+	  meson: Setup pre commit hook and fix getpluginsdir for standalone case
+
+2016-09-29 04:55:14 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsrc.c:
+	  splitmuxsrc: Handle stop point from segment
+	  If the seek stop point (or start, during reverse play)
+	  was within the segment we just finished, go EOS immediately
+	  instead of proceeding through all other parts and sending
+	  0 length seeks to them.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772138
+
+2016-09-29 03:21:26 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsrc.c:
+	  splitmuxsrc: Drop lock shutting down pads
+	  Avoid a sporadic deadlock on shutdown by dropping
+	  the splitmux lock around pad shutdown
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772138
+
+2016-09-29 02:47:36 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	  splitmuxsrc: Fix extra unref handling queries
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772138
+
+2016-09-29 04:50:25 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	* gst/multifile/gstsplitmuxpartreader.h:
+	* gst/multifile/gstsplitmuxsrc.c:
+	  splitmuxsrc: Avoid stall when parts get out of sync
+	  When one part moves ahead of the others - due to excessive
+	  downstream queueing, or really small input files - then
+	  we can end up activating parts more than once. That can lead to
+	  effects like shutting down pad tasks prematurely.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772138
+
+2016-09-30 11:41:19 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* meson.build:
+	  meson: update version
+
+=== release 1.9.90 ===
+
+2016-09-30 13:02:19 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.9.90
+
+2016-09-30 12:17:26 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2016-09-30 11:43:54 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/el.po:
+	  po: Update translations
+
+2016-09-30 13:22:32 +0530  Arun Raghavan <arun@osg.samsung.com>
+
+	* tests/check/pipelines/tagschecking.c:
+	  tests: Fix tagschecking failure due to missing PTS
+	  qtmux now needs the PTS (commit a993883b7), so let's make sure we
+	  produce one with our buffers.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772228
+
+2016-09-28 23:03:58 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Don't calculate PTS offset and DTS with GST_CLOCK_TIME_NONE
+	  Just error out if there is no valid PTS.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=772143
+
+2016-09-29 17:37:28 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux_types.c:
+	  qtdemux: Add JPEG2000 ihdr atom to the list of known ones
+	  Otherwise qtdemux is always going to complain about it being unknown.
+
+2016-09-29 10:19:56 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Always write the default frame duration for VP8/9 too
+	  The WebM spec allows this now, and it allows us to guess a framerate.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=772141 and
+	  also https://bugzilla.gnome.org/show_bug.cgi?id=654379
+
+2016-09-27 15:26:19 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph265depay.c:
+	  rtph26[45]depay: Don't handle NALs inside STAP units twice
+	  They've already been handled before pushing them into the adapter.
+
+2016-09-27 12:39:12 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/meson.build:
+	  meson: tests: fix vp8 availability checks
+	  Those variables are not defined if vp8 was not found.
+
+2016-09-27 10:23:38 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	  Revert "multifilesink: streamline the file-switch code a bit"
+	  This reverts commit f1ceaab02f3f557e23b77b14771a575788f92bb4.
+	  This broke atomic file writes in "buffer" mode. It did make
+	  sure that any streamheaders are prepended to each file in
+	  buffer mode as well, but that's not really needed in practice,
+	  whereas atomic file writes are, so let's restore the status
+	  quo ante for now since this was primarily a code cleanup anyway,
+	  and if anyone needs to streamheaders in buffer mode too they
+	  can make a patch to implement that differently. Re-implementing
+	  the atomic writes in the element also seems way too much work.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766990
+
+2016-09-27 10:22:57 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	  Revert "multifilesink: close file on write error with next-file mode is set to buffer"
+	  This reverts commit 84e441d2685cf223d348a95be0c5ba693bbf6624.
+	  This will no longer be needed once we revert f1ceaab02.
+
+2016-09-26 13:22:29 -0300  Thibault Saunier <thibault.saunier@osg.samsung.com>
+
+	* tests/check/meson.build:
+	  meson: Add gst-plugins-base plugins directories to be used by tests
+
+2016-09-26 14:30:00 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/vpx/meson.build:
+	* meson.build:
+	* tests/check/getpluginsdir:
+	* tests/check/meson.build:
+	  meson: add unit tests
+	  Only works properly in an installed setup currently, most
+	  likely won't work with a subprojects setup yet.
+
+2016-09-24 09:36:24 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* meson.build:
+	* po/meson.build:
+	  meson: hook up translations
+
+2016-09-08 17:30:41 +0530  Arun Raghavan <arun@arunraghavan.net>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: Don't negotiate to less than two segments
+	  GstAudioRingBuffer doesn't needs us to have at least 2 segments. We make
+	  sure that if our buffer parameters are such that the maxlength is not at
+	  least 2x fragsize, we still request the ringbuffer to keep that much
+	  space so it continues to work.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=770446
+
+2016-09-24 23:22:01 +0530  Arun Raghavan <arun@arunraghavan.net>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	* gst/rtp/gstrtpsbcpay.h:
+	  rtpsbcpay: Fix timestamping
+	  We were just picking the timestamp of the last buffer pushed into our
+	  adapter before we had enough data to push out.
+	  This fixes things to figure out how large each frame is and what
+	  duration it covers, so we can set both the timestamp and duration
+	  correctly.
+	  Also adds some DISCONT handling.
+
+2016-07-12 18:14:52 +0200  Georg Lippitsch <glippitsch@toolsonair.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Fix fourcc for ProRes Proxy
+	  This is apco, according to
+	  https://wiki.multimedia.cx/index.php?title=Apple_ProRes
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769048
+
+2016-09-18 20:55:31 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/vpx/meson.build:
+	  meson: fix build with vpx 1.3.x
+	  vpx >= 1.4.0 is optional
+
+2016-09-15 18:19:35 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Use new bin suppressed flags API for managing the element flags
+
+2016-09-15 09:52:31 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/jack/gstjackaudioclient.c:
+	* gst/rtp/dboolhuff.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/videofilter/gstvideoflip.c:
+	  ext, gst: fix indentation
+
+2016-09-15 09:52:17 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/flvmux.c:
+	* tests/check/elements/rtph263.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	* tests/check/elements/rtpsession.c:
+	* tests/check/elements/rtpvp9.c:
+	  tests: fix indentation
+
+2016-08-11 11:04:22 -0600  Thomas Bluemel <tbluemel@control4.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Fix calculating next_seqnum when dropping old buffers from a full queue.
+	  Fixes calculating the next sequence number when a ITEM_TYPE_LOST with more than one
+	  definitely lost packets is encountered.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769757
+
+2016-08-11 23:07:44 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: improved rtx-rtt averaging
+	  The basic idea is this:
+	  1. For *larger* rtx-rtt, weigh a new measurement as before
+	  2. For *smaller* rtx-rtt, be a bit more conservative and weigh a bit less
+	  3. For very large measurements, consider them "outliers"
+	  and count them a lot less
+	  The idea being that reducing the rtx-rtt is much more harmful then
+	  increasing it, since we don't want to be underestimating the rtt of the
+	  network, and when using this number to estimate the latency you need for
+	  you jitterbuffer, you would rather want it to be a bit larger then a bit
+	  smaller, potentially losing rtx-packets. The "outlier-detector" is there
+	  to prevent a single skewed measurement to affect the outcome too much.
+	  On wireless networks, these are surprisingly common.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769768
+
+2016-08-05 12:51:59 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Detect whether to assume equidistant spacing when loss
+	  Assuming equidistant packet spacing when that's not true leads to more
+	  loss than necessary in the case of reordering and jitter. Typically this
+	  is true for video where one frame often consists of multiple packets
+	  with the same rtp timestamp. In this case it's better to assume that the
+	  missing packets have the same timestamp as the last received packet, so
+	  that the scheduled lost timer does not time out too early causing the
+	  packets to be considered lost even though they may arrive in time.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769768
+
+2016-07-27 10:39:50 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Don't request rtx if 'now' is past retry period
+	  There is no need to schedule another EXPECTED timer if we're already
+	  past the retry period. Under normal operation this won't happen, but if
+	  there are more timers than the jitterbuffer is able to process in
+	  real-time, scheduling more timers will just make the situation worse.
+	  Instead, consider this packet as lost and move on. This scenario can
+	  occur with high loss rate, low rtt and high configured latency.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769768
+
+2016-07-26 18:01:48 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Fix lost duration when gap after lost timer
+	  This patch fixes an issue with the estimated gap duration when there is
+	  a gap immediately after a lost timer has been processed. Previously
+	  there was a discrepancy beteen the gap in seqnum and gap in dts which
+	  would cause wrong calculated duration. The issue would only be seen with
+	  retranmission enabled since when it's disabled lost timers are only
+	  created when a packet is received and the actual gap length and last dts
+	  is known.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769768
+
+2016-07-19 01:11:58 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Expose rtx-deadline as a property
+	  The default -1 gives the old behavior.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769768
+
+2016-08-11 12:02:19 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Improved expected-timer handling when gap > 0
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769768
+
+2016-08-11 11:51:50 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Major improvements for RTX stats
+	  Stats should also be collected for unsuccessful packets.
+	  rtx-rtt is very important for determining the necessary configured
+	  latency on the jitterbuffer. It's especially important to be able to
+	  increase the latency when retransmitted packets arrive too late and are
+	  considered lost. This patch includes these late packets in the
+	  calculation of the various rtx stats, making them more correct and
+	  useful.
+	  Also in the case where the original packet arrives after a NACK is sent,
+	  the received RTX packet should update the stats since it provides useful
+	  information about RTT.
+	  The RTT is only updated if and only if all requested retranmissions are
+	  received. That way the RTT is guaranteed to make sense. If not we don't
+	  know which request the packet is a response to and the RTT may be bogus.
+	  A consequence of this patch is that RTT is not updated for a request
+	  when one of the RTX packets for that seqnum is lost, but that since
+	  measured RTT will be more accurate.
+	  The implementation store the RTX information from the timed out timers
+	  and use this when the retransmitted packet arrives. For performance
+	  these timers are stored separately from the "normal" timers in order to
+	  not impact performance (see attached performance test).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769768
+
+2016-08-11 11:02:44 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Add and expose more stats and increase testing of it
+	  Add num-pushed and num-lost.
+	  Expose num-late, num-duplicates and avg-jitter.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769768
+
+2016-07-07 10:20:02 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	  rtxreceive: Set buffer flag for retransmitted packets
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769768
+
+2016-07-09 23:47:41 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Option to disable rtx-delay-reorder
+	  When disabled we can save some iterations over timers.
+	  There is probably an argument for rtx-delay-reorder to exist, but
+	  for normal operations, handling jitter (reordering) is something a
+	  jitterbuffer should do, and this variable feels like functionality that
+	  is not "in-sync" with what the jitterbuffer is trying to achieve.
+	  Example: You have 50ms jitter on your network, and are receiving
+	  audio packets with 10ms durations. An audio packet should not be
+	  considered late until its rtx-timeout has expired (and hence a rtx-event
+	  is sent), but with rtx-delay-reorder, events will be sent pretty much
+	  all the time due to the jitter on the network.
+	  Point being: The jitterbuffer should adapt its size to the measured network
+	  jitter, and then rtx-delay-reorder needs to adapt as well, or simply
+	  get out of the way and let the other (better) rtx-mechanisms do their job.
+	  Also change find_timer to only use seqnum as an argument, since there
+	  will only ever be one timer per seqnum at any given time. In the
+	  one case where the type matters, the caller simply checks the type.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769768
+
+2016-09-14 09:58:41 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: Fix double free from coverity
+	  CID #1372887
+
+2016-09-14 09:58:37 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: Indent as per gst-indent
+
+2016-09-14 11:30:41 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  configure: Depend on gstreamer 1.9.2.1
+
+2016-09-14 10:17:02 +0900  Wonchul Lee <wonchul.lee@collabora.com>
+
+	* gst/autodetect/gstautodetect.c:
+	  autodetect: Use gst_bin_set_suppressed_flags() API
+	  https://bugzilla.gnome.org/show_bug.cgi?id=771395
+
+2016-09-09 15:36:12 +0200  Thomas Scheuermann <Thomas.Scheuermann@barco.com>
+
+	* ext/jack/gstjackaudioclient.c:
+	  jack: Fix pipeline hang when jack changes sample rate or buffer size
+	  If jackd changes the buffer size or sample rate, jackaudiosink hangs
+	  and can't be stopped. This also happens if jack is configured as slave
+	  and a gstreamer pipeline is started on the slave machine while the jack
+	  master isn't running yet. If the the jack master is started it changes
+	  the buffer size / sample rate and jackaudiosink can't be stopped.
+	  This fix calls jack_shutdown_cb when jack_sample_rate_cb or
+	  jack_buffer_size_cb is called.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=771272
+
+2016-09-12 20:08:36 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Fix field ordering for reverse playback
+	  And actually calculate the field duration instead of a frame duration so
+	  that we can properly timestamp output frames in fields=all mode.
+	  This is probably still broken for reverse playback in telecine mode.
+
+2016-09-12 09:02:00 +0000  Thomas Klausner <tk@giga.or.at>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Fix compilation on NetBSD
+	  https://bugzilla.gnome.org/show_bug.cgi?id=771278
+
+2016-09-10 20:51:10 +1000  Jan Schmidt <jan@centricular.com>
+
+	* autogen.sh:
+	* common:
+	  Automatic update of common submodule
+	  From b18d820 to f980fd9
+
+2016-09-09 14:02:25 +0200  Xabier Rodriguez Calvar <calvaris@igalia.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: offset is irrelevant when no crypto info
+	  Cause later it will try to use the crypto info array to get an index and
+	  attach on of the positions as buffer's crypto info.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=770951
+
+2016-09-10 09:53:57 +1000  Jan Schmidt <jan@centricular.com>
+
+	* autogen.sh:
+	* common:
+	  Automatic update of common submodule
+	  From f49c55e to b18d820
+
+2016-09-07 15:33:30 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/osxaudio/Makefile.am:
+	  osxaudio: Distribute device provider files
+	  Those where missing the the dev release tarballs for 1.9.2 which
+	  prevented building from tarball on OSX platform
+
+2016-09-06 09:49:39 +0200  Xabier Rodriguez Calvar <calvaris@igalia.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix crash with no cenc aux offset
+	  https://bugzilla.gnome.org/show_bug.cgi?id=770951
+
+2016-09-05 09:39:33 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: parse a bit more of the humongous LOAS data
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769278
+
+2016-09-05 09:39:08 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: make it clear when a potential LOAS frame is not one
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769278
+
+2016-09-05 09:38:26 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: add a few comments to anchor parsing to the spec
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769278
+
+2016-09-05 09:37:02 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstaacparse.h:
+	  aacparse: improve channel/rate handling
+	  Keep track of the last parsed channels/rate fields so they can be
+	  used even if the element was not yet configured.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769278
+
+2016-09-05 09:35:53 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: fix varlength number reading as per spec
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769278
+
+2016-09-05 09:35:02 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: strip uneeded static arrays slack
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769278
+
+2016-07-18 19:18:58 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4adepay.h:
+	  rtpmp4adepay: Only declare a stream to be framed once a marker bit has been seen
+	  This may cause a few packets to be processed by the parser, but it's
+	  better than never pushing out buffers from a slightly broken stream
+	  where no marker bits are set.
+
+2016-09-06 14:25:42 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: Fix timestamping in reverse playback mode
+	  This is only supported right now if after a demuxer that supports reverse
+	  playback, e.g. with DV container inside AVI container.
+
+2016-09-05 12:23:54 -0300  Thibault Saunier <thibault.saunier@osg.samsung.com>
+
+	* meson.build:
+	  meson: Bump version to 1.9.2
+
+2015-06-26 20:13:17 +0200  Mathieu Duponchelle <mathieu.duponchelle@opencreed.com>
+
+	* gst/isomp4/GstQTMux.prs:
+	* gst/isomp4/Makefile.am:
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Implement the preset interface.
+	  + And provide a "youtube" preset, which based on
+	  https://support.google.com/youtube/answer/1722171 sets
+	  faststart to True.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751559
+
+2016-09-01 12:27:35 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.9.2 ===
+
+2016-09-01 12:27:15 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.9.2
+
+2016-09-01 11:23:33 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: Update translations
+
+2016-09-01 10:59:51 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/examples/equalizer/demo.c:
+	* tests/examples/spectrum/demo-audiotest.c:
+	* tests/examples/spectrum/demo-osssrc.c:
+	  tests/examples: #define GDK_DISABLE_DEPRECATION_WARNINGS
+	  We use gdk_cairo_create() which is deprecated since 3.22.
+
+2016-08-31 05:50:44 +1000  Jan Schmidt <jan@centricular.com>
+
+	* sys/osxvideo/Makefile.am:
+	* sys/osxvideo/cocoawindow.h:
+	* sys/osxvideo/osxvideosink.h:
+	  osxvideo: Remove QuickTime references.
+	  QuickTime.h is no longer available on OS X 10.12 (Sierra),
+	  and both the header and the framework seem unnecessary
+	  for compilation - at least as of 10.11 (El Capitan).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=770526
+
+2016-08-19 11:11:03 -0700  Thibault Saunier <thibault.saunier@osg.samsung.com>
+
+	* ext/dv/gstdvdemux.c:
+	* ext/gdk_pixbuf/gstgdkpixbufdec.c:
+	* gst/avi/gstavidemux.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/multifile/gstsplitmuxsrc.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/wavparse/gstwavparse.c:
+	  Use the new API to post flow ERROR messages on the bus
+	  https://bugzilla.gnome.org/show_bug.cgi?id=770158
+
+2016-08-26 21:32:07 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* tests/check/elements/.gitignore:
+	  gitignore: ignore qtdemux, rtph261 and rtpvp9 tests
+
+2016-08-26 21:22:16 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* tests/check/Makefile.am:
+	  tests: use GST_NET_LIBS instead of hardcoded -lgstnet
+	  Fixes build in OSX when running 'make check' in gst-uninstalled.
+
+2016-08-26 21:14:47 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* tests/check/elements/rtp-payloading.c:
+	  tests: remove a wrong 'const' specifier
+	  Fixes "error: duplicate 'const' declaration specifier"
+
+2016-08-26 21:11:59 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* configure.ac:
+	* tests/check/Makefile.am:
+	  build: silence error about pthread for 'make check' in osx
+	  Fixes "clang: error: argument unused during compilation: '-pthread'"
+
+2016-08-26 20:31:10 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/Makefile.am:
+	  vp9enc: Fix build of unit test by letting it link to libgstvideo
+
+2016-08-26 12:06:35 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	  Revert "rtpmux: fix PROP_TIMESTAMP_OFFSET range problems"
+	  This broke API, so we need a better solution!
+	  This reverts commit c7579d31a6e9d788e94b83258309063d0aae481e.
+
+2016-06-08 15:06:28 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtp/gstrtpvp9depay.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/rtpvp9.c:
+	  rtpvp9depay: Support flexible mode
+
+2016-06-06 17:03:36 +0200  Stian Selnes <stian@pexip.com>
+
+	* ext/vpx/gstvp9enc.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/vp9enc.c:
+	  vp9enc: Fix leak of vpx_image_t
+
+2016-05-06 13:33:22 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtp/gstrtph263pdepay.c:
+	* tests/check/elements/rtph263.c:
+	  rtph263pdepay: Don't try to push empty frame
+	  If the result of depayloading is an empty frame, just drop it. This is
+	  likely the result of a buggy payloader.
+
+2016-05-06 16:06:53 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	  rtpmux: fix PROP_TIMESTAMP_OFFSET range problems
+	  It could not set the offset for the full guint32 range.
+
+2016-05-06 09:44:42 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: introduce max-streams property
+	  To be able to cap the number of allowed streams for one session.
+	  This is useful for preventing DoS attacks, where a sender can change
+	  SSRC for every buffer, effectively bringing rtpbin to a halt.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=770292
+
+2016-03-31 00:10:49 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: reordered packets are very normal, and should not be a warning
+
+2016-02-05 14:19:25 +0100  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: degrade g_warning to GST_ERROR
+	  So we don't blow up while investigating
+
+2016-02-04 14:16:40 +0100  Stian Selnes <stian@pexip.com>
+
+	* gst/rtp/gstrtph263pdepay.c:
+	* tests/check/elements/rtph263.c:
+	  rtph263pdepay: Fix picture header for non-writable payload
+	  Under certain conditions gst_rtp_buffer_get_payload() returns a copy of
+	  the payload. In this case the payload modifications will not affect the
+	  rtp buffer. So instead of modifying the payload buffer directly we
+	  should modify the buffer that actually gets pushed on the adapter.
+
+2015-11-19 11:50:47 +0100  Stian Selnes <stian@pexip.com>
+
+	* gst/rtp/gstrtph261depay.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/rtph261.c:
+	  rtph261depay: Fix check of valid payload length
+	  Packets with no H.261 payload should be dropped to avoid invalid
+	  write/reads.
+
+2015-11-09 10:06:21 +0100  Stian Selnes <stian@pexip.com>
+
+	* gst/rtp/gstrtph263pay.c:
+	* tests/check/elements/rtph263.c:
+	  rtph263pay: Fix double free, invalid reads and leak
+
+2014-06-30 15:43:58 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: sanity check RTT before ignoring PLI/FIR
+
+2014-06-30 15:07:45 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: handle sdes messages with non-utf8 more gracefully
+
+2014-06-17 08:52:50 +0200  Stian Selnes <stian.selnes@gmail.com>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: change log level on bitstream parsing messages
+
+2016-07-07 11:13:18 +0200  Mikhail Fludkov <misha@pexip.com>
+
+	* tests/check/elements/rtprtx.c:
+	  tests/rtprtx: refactor the tests to use gstharness
+	  The functionality of all the tests was kept exactly the same. Some tests
+	  were renamed:
+	  test_push_forward_seq -> test_rtxsend_rtxreceive
+	  test_drop_one_sender -> test_rtxsend_rtxreceive_with_packet_loss
+	  test_drop_multiple_sender -> test_multi_rtxsend_rtxreceive_with_packet_loss
+	  test_rtxreceive_data_reconstruction was testing that retransmitted
+	  buffer produced by rtxsend was correctly transformed to the original
+	  buffer by rtxreceive. Now we are checking for this in all the tests
+	  where both rtxsend & rtxreceive are involved. That's why the test was
+	  removed.
+
+2016-08-25 15:52:36 +0200  Jonas Holmberg <jonashg@axis.com>
+
+	* gst/rtp/gstrtph265pay.c:
+	  rtph265pay: Set RTP marker bit
+	  Set the RTP marker bit on the last RTP packet of an H.265 access unit.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=770394
+
+2016-07-26 19:39:58 +0200  Xabier Rodriguez Calvar <calvaris@igalia.com>
+
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videofilter/gstvideoflip.h:
+	  videoflip: added GstVideoDirection interface
+	  It implements now this interface with its video-direction
+	  property. Values are changed to GstVideoOrientationMethod but they have
+	  the same value than the originals.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768687
+
+2015-11-06 10:39:16 +0100  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  gstrtpsession: refactor duplicate code into a function
+	  Less code, easier to read, more consistent.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=770293
+
+2016-08-23 17:06:44 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: fix typo in max-misorder-time property name
+
+2016-08-22 00:05:52 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: fix printf format compiler warning in debug message
+	  On 32-bit x86: gstsplitmuxsink.c:966:31: warning: format ‘%u’ expects
+	  argument of type ‘unsigned int’, but argument 9 has type
+	  ‘guint64 {aka long long unsigned int}’
+
+2016-08-12 21:12:30 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* .gitignore:
+	* config.h.meson:
+	* ext/cairo/meson.build:
+	* ext/dv/meson.build:
+	* ext/flac/meson.build:
+	* ext/gdk_pixbuf/meson.build:
+	* ext/jack/meson.build:
+	* ext/jpeg/meson.build:
+	* ext/libpng/meson.build:
+	* ext/meson.build:
+	* ext/pulse/meson.build:
+	* ext/shout2/meson.build:
+	* ext/soup/meson.build:
+	* ext/speex/meson.build:
+	* ext/taglib/meson.build:
+	* ext/vpx/meson.build:
+	* ext/wavpack/meson.build:
+	* gst/alpha/meson.build:
+	* gst/apetag/meson.build:
+	* gst/audiofx/meson.build:
+	* gst/audioparsers/meson.build:
+	* gst/auparse/meson.build:
+	* gst/autodetect/meson.build:
+	* gst/avi/meson.build:
+	* gst/cutter/meson.build:
+	* gst/debugutils/meson.build:
+	* gst/deinterlace/meson.build:
+	* gst/dtmf/meson.build:
+	* gst/effectv/meson.build:
+	* gst/equalizer/meson.build:
+	* gst/flv/meson.build:
+	* gst/flx/meson.build:
+	* gst/goom/meson.build:
+	* gst/goom2k1/meson.build:
+	* gst/icydemux/meson.build:
+	* gst/id3demux/meson.build:
+	* gst/imagefreeze/meson.build:
+	* gst/interleave/meson.build:
+	* gst/isomp4/meson.build:
+	* gst/law/meson.build:
+	* gst/level/meson.build:
+	* gst/matroska/meson.build:
+	* gst/meson.build:
+	* gst/monoscope/meson.build:
+	* gst/multifile/meson.build:
+	* gst/multipart/meson.build:
+	* gst/replaygain/meson.build:
+	* gst/rtp/meson.build:
+	* gst/rtpmanager/meson.build:
+	* gst/rtsp/meson.build:
+	* gst/shapewipe/meson.build:
+	* gst/smpte/meson.build:
+	* gst/spectrum/meson.build:
+	* gst/udp/meson.build:
+	* gst/videobox/meson.build:
+	* gst/videocrop/meson.build:
+	* gst/videofilter/meson.build:
+	* gst/videomixer/meson.build:
+	* gst/wavenc/meson.build:
+	* gst/wavparse/meson.build:
+	* gst/y4m/meson.build:
+	* meson.build:
+	* meson_options.txt:
+	* sys/directsound/meson.build:
+	* sys/meson.build:
+	* sys/v4l2/meson.build:
+	* sys/ximage/meson.build:
+	* tests/check/meson.build:
+	* tests/meson.build:
+	  Add support for Meson as alternative/parallel build system
+	  https://github.com/mesonbuild/meson
+	  With contributions from:
+	  Tim-Philipp Müller <tim@centricular.com>
+	  Jussi Pakkanen <jpakkane@gmail.com> (original port)
+	  Highlights of the features provided are:
+	  * Faster builds on Linux (~40-50% faster)
+	  * The ability to build with MSVC on Windows
+	  * Generate Visual Studio project files
+	  * Generate XCode project files
+	  * Much faster builds on Windows (on-par with Linux)
+	  * Seriously fast configure and building on embedded
+	  ... and many more. For more details see:
+	  http://blog.nirbheek.in/2016/05/gstreamer-and-meson-new-hope.html
+	  http://blog.nirbheek.in/2016/07/building-and-developing-gstreamer-using.html
+	  Building with Meson should work on both Linux and Windows, but may
+	  need a few more tweaks on other operating systems.
+
+2016-08-20 16:59:30 +0800  Jie Jiang <jiangjie@nudt.edu.cn>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  Fixed splitmuxsink 32-bit overflow bug
+	  Extend the byte tracking counters to 64-bit on
+	  all platforms, instead of using gsize, which overflows
+	  after 4GB.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=770019
+
+2016-08-19 17:18:16 +0300  Vivia Nikolaidou <vivia@toolsonair.com>
+
+	* gst/isomp4/atoms.c:
+	  isomp4: Fix coverity warning
+	  If atom_copy_data fails to write anything, return 0
+	  CID #1371458
+
+2016-04-09 07:51:03 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* sys/v4l2/gstv4l2deviceprovider.c:
+	* sys/v4l2/v4l2-utils.c:
+	  v4l2: consistently check #ifdef HAVE_GUDEV instead of #if
+	  Both work with autotools but they definitely don't mean the same thing, cause
+	  problems with other build systems, and are bad form. Existence should always be
+	  checked with #ifdef or #if defined.
+
+2016-04-19 10:53:05 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/directsound/gstdirectsoundsink.h:
+	  directsound: port away from old DirectX API
+	  D3DX has been deprecated for the last 4 years and latest versions of
+	  Windows no longer ship headers for it. This is fine as long as you're
+	  building with Cerbero's Wine-based DirectX headers, but sucks if you
+	  want to build against the actual Windows SDK.
+	  We were just using it to get error strings anyway, so just use the
+	  generic error string API.
+
+2016-08-18 12:02:01 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  Revert "flacparse: Add maximum bitrate tag"
+	  This reverts commit c703ab69f526092bb26cce41ca691a896c8383d8.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769392
+
+2016-08-18 09:57:51 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Fix unit test by disabling adaptive misorder/dropout calculations
+	  Need to set max-misorder-time and max-dropout-time to 0 so the
+	  jitterbuffer does not base them on packet rate calculations.
+	  If it does, out gap is big enough to be considered a new stream and
+	  we wait for a few consecutive packets just to be sure
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751311
+
+2016-08-09 12:55:59 +0300  Vivia Nikolaidou <vivia@ahiru.eu>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmuxsink: Add option to split at exactly max-size-time
+	  Will try to request a keyframe from the encoder to be sent at the target
+	  running time.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769664
+
+2016-08-09 20:16:16 +0300  Vivia Nikolaidou <vivia@ahiru.eu>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Allow time and bytes to reach their respective thresholds
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769664
+
+2016-08-17 09:49:04 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Allow mimetypes with properties as long as they're application/sdp
+	  Some servers add properties like charset, e.g.
+	  application/sdp; charset=utf8
+	  Ideally we should also parse the charset and do conversion of all messages,
+	  but that's for a later time.
+
+2016-06-24 16:32:37 +0300  Vivia Nikolaidou <vivia@toolsonair.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  qtmux: Added support for writing timecode track
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767950
+
+2016-08-11 16:32:21 -0600  Thomas Bluemel <tbluemel@control4.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: Initialize bytes_sent field.
+	  This fixes endpoints not receiving any data intermittently.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769773
+
+2016-08-10 11:45:13 -0600  Thomas Bluemel <tbluemel@control4.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpstats.c:
+	  rtpjitterbuffer: Actually calculate the packet rate for max-dropout and max-misorder calculations.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751311
+
+2016-08-10 11:26:17 -0600  Thomas Bluemel <tbluemel@control4.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Don't warn for duplicate packets
+	  This is a normal scenario and should not be a warning.  This can
+	  happen frequently when re-transmits of lost packets are enabled.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762208
+
+2016-08-08 13:49:19 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmux: Fix typo converting to running time.
+	  Use the correct collected timestamp.
+
+2016-08-08 02:53:48 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  Revert "splitmuxsink: Use GstBin async-handling instead of our own."
+	  This reverts commit fa008f271a52f82dededc28bd81b020ca7939b47.
+	  async-handling in GstBin causes the pipeline to spin at 100%
+	  CPU as the top-level pipeline tries to change that state
+	  to PLAYING constantly. This is a workaround for a core
+	  problem, essentially, but an improvement in this case for now.
+
+2016-08-08 00:56:38 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmux: Recheck state after unlocking mutex.
+	  After dropping the splitmux lock, re-check the state,
+	  don't just fall through and sleep unconditionally,
+	  as we may have already missed the wakeup.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769514
+
+2016-08-03 03:32:07 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsrc.c:
+	  splitmuxsrc: Don't stop and error on EOS flow return
+	  Don't immediately halt on EOS flow return from downstream
+	  due to out of segment. Let the demuxer handle it and send
+	  EOS.
+
+2016-08-04 00:36:28 -0300  Thiago Santos <thiagossantos@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: avoid unref of null buffer
+	  The current 'l' pointer will be NULL when the loop
+	  is interrupted with a 'break' statement. Need to have
+	  it advance to the next list item before interrupting.
+
+2016-08-02 14:01:14 +0200  Carlos Rafael Giani <dv@pseudoterminal.org>
+
+	* gst/wavparse/Makefile.am:
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Add tags for container format and bitrate for uncompressed PCM
+	  The PCM bitrate is added to help downstream elements (like uridecodebin)
+	  figure out a proper network buffer size
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769390
+
+2016-08-01 18:52:26 +0200  Carlos Rafael Giani <dv@pseudoterminal.org>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Add maximum bitrate tag
+	  https://bugzilla.gnome.org/show_bug.cgi?id=769392
+
+2016-07-28 17:58:16 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: When receiving a DISCONT buffer that does not point to a sample, remember the offset
+	  And don't just reset everything. This makes sure that we can continue to
+	  handle data in the following scenario:
+	  moov: discont
+	  moof: discont
+	  mdat: continuous
+	  Previously this would fail because the offset would be the accumulated offset
+	  from moov and moof at the mdat position, while the buffer offset might be
+	  something completely different.
+
+2016-07-25 13:34:02 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph265pay.c:
+	* gst/rtp/gstrtpilbcpay.c:
+	  rtp: Filter with the filter caps in the payloader's getcaps
+
+2016-03-03 11:35:06 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: include http-status-code in error message details
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763038
+
+2016-07-25 18:20:03 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Fix debug statement signedness.
+	  The ts variable is a GstClockTime, don't print it
+	  as a GstClockTimeDiff.
+
+2016-07-17 22:41:02 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmuxsink: Handle negative running time
+	  Use signed clock times for running time everywhere
+	  so that we handle negative running times without
+	  going haywire, similar to what queue and multiqueue
+	  do these days.
+
+2016-07-18 00:12:55 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Drop lock when sending dummy event
+	  When pushing the dummy event into the multiqueue,
+	  drop the splitmux lock or else we might deadlock.
+
+2016-06-30 01:56:41 +1000  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: Intersect with filter caps in getcaps function.
+	  Always intersect with the filter caps in the getcaps function
+	  to make sure we return a subset of what was requested.
+	  Other payloaders also have this problem and need fixing
+	  in future commits.
+
+2016-07-12 17:30:56 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* tests/check/elements/qtdemux.c:
+	  tests: qtdemux: fix element and pad leak
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768739
+
+2016-07-12 16:45:36 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* tests/check/elements/audiofirfilter.c:
+	* tests/check/elements/audioiirfilter.c:
+	* tests/check/elements/rtp-payloading.c:
+	* tests/check/elements/videobox.c:
+	* tests/check/pipelines/effectv.c:
+	  tests: fix bus leaks
+	  gst_bus_add_signal_watch() takes a ref on the bus which should be
+	  released using gst_bus_remove_signal_watch().
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768739
+
+2016-07-14 03:07:11 +0800  Ting-Wei Lan <lantw@src.gnome.org>
+
+	* configure.ac:
+	  configure: Call AG_GST_PKG_CONFIG_PATH to set GST_PKG_CONFIG_PATH
+	  GST_PKG_CONFIG_PATH is used in docs/plugins directory, so
+	  AG_GST_PKG_CONFIG_PATH must be called to set it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768787
+
+2016-07-12 07:39:58 +0200  Edward Hervey <edward@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Don't drop final bytes of a range request
+	  At the end of a range request, we don't want to return GST_FLOW_EOS otherwise
+	  the last bytes we just read will be dropped by basesrc.
+	  Instead just return GST_FLOW_OK (which was set just before) and let basesrc
+	  handle the fact we are at the end of the segment.
+
+2016-07-11 18:30:18 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2deviceprovider.c:
+	  v4l2provider: Fix device type detection
+	  The type detection would lead to assertion as it would try
+	  to create a device without having found any type for it. It
+	  also didn't detect MPLANE devices properly.
+
+2016-07-11 18:29:01 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't assert when used by the monitor
+	  The monitor sets the object->element object as a GstObject. This
+	  works for debug traces, but will assert for ELEMENT_ERROR. This
+	  was the only case where that could happen. Add a check for that.
+
+2016-07-11 17:38:00 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Indent very long line
+
+2016-07-12 00:42:02 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: At the end of a range request, read another time to finalize the request
+	  If we're at the end of a range request, read again to let libsoup
+	  finalize the request. This allows to reuse the connection again later,
+	  otherwise we would have to cancel the message and close the connection.
+
+2016-07-11 21:13:47 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From f363b32 to f49c55e
+
+2016-07-11 19:57:18 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Fix keep-alive handling
+	  We have to get rid of the message on EOS when the complete stream is read to
+	  remember that we successfully finished handling this specific message.
+	  Otherwise we will cancel it later and close the connection instead of reusing
+	  it at a later time.
+	  It might also make sense to reuse connections if a non-200 response is
+	  received. As long as there was no connection error, the HTTP connection should
+	  be re-usable.
+
+2016-07-11 12:05:06 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* configure.ac:
+	  Also enable V4L2 probe on aarch64 (aka ARM 64bit)
+
+2016-07-11 11:59:19 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* tests/examples/rtp/client-PCMA.c:
+	  rtp example: Fix leak
+	  Also stop fetching the internal source as this
+	  functionality has been broken.
+
+2016-07-08 14:58:37 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* configure.ac:
+	  Enable v4l2 probe on Linux/ARM
+	  Most of those have V4L2 drivers these days enabling it make sure that it
+	  this code is enabled in major distribution, hence that HW accelerated
+	  decoder/encoder can be used on platforms that support it. The probes are
+	  slightly increasing the first init of gstreamer library, though the
+	  result is cached in the registry for later use.
+
+2016-07-11 09:46:49 +0200  Jonas Holmberg <jonashg@axis.com>
+
+	* gst/rtp/gstrtph265pay.c:
+	* tests/check/elements/rtp-payloading.c:
+	  rtph265pay: Accept array_completeness=1
+	  When parsing NAL unit type in codec_data, check the 6bits of
+	  NAL_unit_type only and do not require the array_completeness bit to be
+	  0, since the default and mandatory value of array_completeness is 1 for
+	  hvc1.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768653
+
+2016-07-10 21:35:06 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: Also copy device_caps in gst_v4l2_dup
+	  This fixes regression where M2M error out saying they have no output
+	  format (the V4L2 CAPTURE side).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768195
+
+2016-07-10 21:30:27 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Use correct in6_pktinfo struct instead of in_pktinfo
+	  Fixes the build on FreeBSD, which does not have the latter.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768623
+
+2016-07-08 17:28:19 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: fix multiplanar capture
+	  After switching to using V4L2_CAP_DEVICE_CAPS we lost support for
+	  multiplanar device types. After some research, it looks like
+	  vcap.capabilities treated the multiplanar flag of output and capture
+	  devices equally, but not the new device_caps.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768195
+
+2016-07-08 14:56:30 +0200  Mats Lindestam <matslm@axis.com>
+
+	* gst/multipart/multipartmux.c:
+	* gst/multipart/multipartmux.h:
+	  multipartmux: Use PTS and DTS instead of timestamp
+	  And pass-through both of them.
+	  Based on a patch by Göran Jönsson <goranjn@axis.com>
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767900
+
+2016-06-30 14:40:40 +0200  Thomas Scheuermann <Thomas.Scheuermann@barco.com>
+
+	* ext/jack/gstjackaudioclient.c:
+	  jack: don't wait for callbacks if the jack server shut down
+	  Otherwise we'll wait forever.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747275
+
+2016-06-23 15:30:19 +0200  Edward Hervey <edward@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Let upstream events go through upstream
+	  There's no real reason to avoid sending QOS/NAVIGATION events upstrea.
+	  Some elements might want to have that information.
+
+2016-06-23 15:22:56 +0200  Edward Hervey <edward@centricular.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Let upstream events go through upstream
+	  There's no real reason to avoid sending QOS/NAVIGATION events upstrea.
+	  Some elements might want to have that information.
+
+2016-06-23 15:17:36 +0200  Edward Hervey <edward@centricular.com>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: Let upstream events go through upstream
+	  There's no real reason to avoid sending QOS/NAVIGATION events upstrea.
+	  Some elements might want to have that information.
+	  Also remove downstream-only CAPS event handling and minimize code
+
+2016-07-07 23:53:54 +0100  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* sys/v4l2/gstv4l2.c:
+	  v4l2: fix v4l2 probe build error
+	  A typo in gst_v4l2_probe_and_register() caused a build error when building
+	  with --enable-v4l2-probe. Fixing it.
+	  gstv4l2.c: In function 'gst_v4l2_probe_and_register':
+	  gstv4l2.c:150:25: error: 'struct v4l2_capability' has no member named 'capabilitites'
+	  device_caps = vcap.capabilitites;
+
+2016-07-01 22:53:33 -0700  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: use gst_caps_intersect_full in negotiate()
+	  Instead of reimplementing the GST_CAPS_INTERSECT_FIRST
+	  interection mode.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768195
+
+2016-07-02 01:56:07 -0700  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2deviceprovider.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2radio.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: use opened device caps instead of physical device ones
+	  The same physical device can export multiple devices. In
+	  this case, the capabilities field now contains a union of
+	  all caps available from all exported V4L2 devices alongside
+	  a V4L2_CAP_DEVICE_CAPS flag that should be used to decide
+	  what capabilities to consider. In our case, we need the
+	  ones from the exported device we are using.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768195
+
+2016-07-07 18:24:59 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Remove suspicious checks for pads being active and linked
+	  We should add all pads, no matter if they are linked or active or not at this
+	  point. Skipping some that are not will cause different behaviour than with
+	  other muxers.
+
+2016-07-07 18:23:07 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Error out if we start writing data with some pads not having a codec id yet
+	  This can only happen if a) upstream somehow gets around the CAPS event failing
+	  or b) there never being any CAPS event.
+	  The following code assumes that all pads have a codec-id.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768509
+
+2016-07-07 18:14:43 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Consistently use gst_matroska_mux_set_codec_id() for setting the codec id
+
+2016-07-04 09:50:11 +0200  Jonas Holmberg <jonashg@axis.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	* gst/rtp/gstrtph265pay.c:
+	* gst/rtp/gstrtph265pay.h:
+	* tests/check/elements/rtp-payloading.c:
+	  rtph265pay/depay: Sync against RFC 7798
+	  Handle sprop-vps, sprop-sps and sprop-pps in caps instead of
+	  sprop-parameter-sets.
+	  rtph265pay works with byte-stream and hvc1 formats but not hev1 yet. It
+	  handles profile-id, tier-flag and level-id in caps query.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753760
+
+2016-07-06 09:25:00 +0200  Jan Alexander Steffens (heftig) <jan.steffens@gmail.com>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	  flvdemux: Push nominal bitrate tags
+	  Add per-stream tag lists, which are used to send nominal
+	  bitrate tags. When remuxing FLV => FLV, this now passes
+	  through the upstream bitrate.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768440
+
+2016-07-06 09:24:49 +0200  Jan Alexander Steffens (heftig) <jan.steffens@gmail.com>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	  flvdemux: Refactor metadata tag handling
+	  The FLV header cannot be trusted to indicate video or
+	  audio presence, as the comments already mention. Don't
+	  delay pushing tags waiting for streams that might never
+	  appear.
+	  Tags are now pushed immediately after they change:
+	  - After parsing an onMetaData script object
+	  - After negotiating caps on a pad
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768440
+
+2016-07-06 12:44:10 +0100  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix AAC codec_data values
+	  As seen in the parent switch for object_type_id, the 4 possible values are
+	  0x40, 0x66, 0x67 and 0x68. Fixing the nested switch to match these values.
+	  Looks like it was a typo making them decimal instead of hexadecimal.
+	  CID 1363328
+
+2016-07-06 13:51:03 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.9.1 ===
+
+2016-07-06 13:06:44 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.9.1
+
+2016-07-06 11:46:26 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2016-07-06 11:22:53 +0300  Steven Hoving <sh@bigbrother.nl>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Fix error messages to first convert to doubles before division
+
+2016-07-06 10:18:30 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/da.po:
+	* po/hr.po:
+	* po/pt_BR.po:
+	* po/sk.po:
+	  po: Update translations
+
+2016-07-05 21:11:35 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Set to PLAYING after a seek again after setting up the segment and everything else
+	  There's a small window for a race condition otherwise.
+
+2016-07-04 17:45:40 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/qtmux.c:
+	  qtmux: Use complete AAC caps with codec_data in the tests
+
+2016-07-04 16:58:38 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Reject raw AAC if no codec_data is found in the caps
+	  If necessary, a demuxer will have to invent something here but this is only a
+	  problem with non-conformant files anyway.
+
+2016-07-04 16:55:32 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Invent AAC codec_data if none is present
+	  Without, raw AAC can't be handled and we have some information available in
+	  the decoder that most likely allows us to decode the stream in one way or
+	  another. This is the same code already used by matroskademux for the same
+	  reasons, and ffmpeg/vlc play such files just fine too by guesswork.
+
+2016-07-04 14:54:13 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Reject raw AAC caps without codec_data
+	  The resulting file is not going to be playable without guesswork and raw caps
+	  should always have codec_data.
+
+2016-05-10 15:48:49 +0200  Edward Hervey <edward@centricular.com>
+
+	  qtdemux: Handle upstream GAP in push-mode/time segment
+	  This is to handle cases where upstream handles the fragmented streaming in TIME
+	  segments and sends us data with gaps within fragments. This would happen when dealing
+	  with trick-modes.
+	  When upstream (push-based, TIME SEGMENT) wishes to send discontinuous samples,
+	  it must obey the following rules:
+	  * The buffer containing the [moof] must have a valid GST_BUFFER_OFFSET
+	  * The buffers containing the first sample after a gap:
+	  * MUST start at the beginning of a sample,
+	  * MUST have the DISCONT flag set,
+	  * MUST have a valid GST_BUFFER_OFFSET relative to the beginning of the fragment.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767354
+
+2016-07-01 11:54:57 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* sys/v4l2/v4l2-utils.c:
+	  v4l2: fix potential double-free of error debug string
+	  gst_v4l2_clear_error() doesn't work like g_clear_error(), it
+	  doesn't NULLify the pointer, so set freed debug string to NULL
+	  so it doesn't get freed again if gst_v4l2_clear_error() is
+	  called twice on the error.
+	  CID 1362901
+
+2016-07-01 10:05:00 +0000  Brad Lackey <blackey@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Don't disable UDP protocols on redirecting
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768232
+
+2016-07-01 17:28:17 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Push caps only when it was updated
+	  Commit 7873bede3134b15e5066e8d14e54d1f5054d2063 caused new caps
+	  event per moof without consideration of duplication.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768268
+
+2016-06-30 15:01:46 +0200  Jonas Holmberg <jonashg@axis.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	  rtph265depay: fix invalid memory access
+	  10 bytes was allocated for stream_format but size of "byte-stream" is
+	  more. Use g_strdup() instead.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753760
+
+2016-06-29 23:31:20 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/shout2/gstshout2.c:
+	  shout2: Use a non-timer GstPoll
+	  Otherwise set_flushing() will have undefined semantics and nowadays causes a
+	  g_critical() to warn about that.
+
+2016-06-19 02:08:25 -0300  Thiago Santos <thiagossantos@gmail.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: dynamically adjust blocksize
+	  Update the blocksize depending on how much is obtained from a read
+	  of the input stream. This avoids doing too many reads in small chunks
+	  when larger amounts of data are available and also prevents using
+	  a very large memory area to read a small chunk of data.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767833
+
+2016-06-28 16:44:50 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Windows has no ipi_spec_dst in struct in_pktinfo
+
+2016-06-28 15:15:14 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: #define __APPLE_USE_RFC_3542 to be able to use IPV6_PKTINFO on OSX/iOS
+
+2016-06-28 15:08:04 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Move #includes around to a) work around broken glibc header and b) Windows
+
+2016-06-28 14:25:03 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Fix compilation on Windows and *BSD/OSX
+
+2016-06-23 20:21:59 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Filter out multicast packets that are not for our multicast address
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767980
+
+2016-06-28 10:57:27 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: When seeking, consider the current element state or pending state instead of the RTSP state
+	  If we consider the RTSP state, what can happen is that it is PLAYING but the
+	  element already asynchronously tried to PAUSE and it just did not happen yet.
+	  We would then override this setting to PAUSED (while the element actually is
+	  in PAUSED) and set the RTSP state to PLAYING again. This would then cause us
+	  to produce packets while the sinks are all PAUSED, piling up thousands of
+	  packets in the rtpjitterbuffer and other elements and finally failing.
+
+2016-06-27 09:20:35 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Add comment about H263/MPEG4P2 being non-standard for FLV
+	  They are however supported by ffmpeg and apparently used out there.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768006
+
+2016-06-24 14:48:53 +0300  Vivia Nikolaidou <vivia@ahiru.eu>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Add support for H263 and MPEG4 part2
+	  https://bugzilla.gnome.org/show_bug.cgi?id=768006
+
+2016-06-21 17:10:56 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  Update plugins doc
+	  This is partly automated using "make update" in docs/plugins, but also
+	  required manual merge. Additionally, missing plugins and elements have
+	  been added.
+
+2016-06-21 17:51:38 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/splitmux.c:
+	  tests: splitmux: skip tests if theora or ogg plugins are not available
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767861
+
+2016-06-21 11:46:13 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From ac2f647 to f363b32
+
+2016-06-21 07:40:42 -0400  Aaron Boxer <boxerab@gmail.com>
+
+	* gst/rtp/gstrtpj2kpay.c:
+	  gstrtpj2kpay: use tile bit and tile number to determine if there are multiple tiles in packet
+	  Now we don't have to rely on a special value for the tile number.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767817
+
+2016-06-21 09:34:56 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpj2kpay.c:
+	  rtpj2kpay: fix compiler warning on OS/X
+	  gstrtpj2kpay.c:364:21: error: implicit truncation from 'int' to bitfield changes value from -1 to 65535
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767817
+
+2016-06-21 09:34:37 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/gst-plugins-good-plugins.prerequisites:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	  docs: update
+
+2016-05-16 17:31:58 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* tests/check/elements/capssetter.c:
+	* tests/check/elements/icydemux.c:
+	* tests/check/elements/jpegenc.c:
+	* tests/check/elements/level.c:
+	* tests/check/elements/multifile.c:
+	* tests/check/elements/qtmux.c:
+	* tests/check/elements/rtprtx.c:
+	* tests/check/elements/udpsrc.c:
+	  fix buffer leaks in tests
+	  Need to call gst_check_drop_buffers() to release the buffers exchanged
+	  during the test.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766561
+
+2016-05-17 12:52:43 +0300  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* tests/check/elements/interleave.c:
+	  interleave: fix message leaks in test
+	  Flush the bus when cleaning up so pending messages are destroyed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766561
+
+2016-05-17 12:58:06 +0300  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* tests/check/elements/videomixer.c:
+	  videomixer: fix event leaks in test
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766561
+
+2016-05-13 15:12:22 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* tests/check/elements/deinterleave.c:
+	  deinterleave: fix leaks
+	  - Flush the bus so messages aren't leaked
+	  - Fix pad leak
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766561
+
+2016-06-17 15:29:16 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: Deprecated sprop-parameter-set property
+	  This is supposed to be either in the codec_data (avc stream format) or inside
+	  the stream, and we extract it from there. It should not be set from a
+	  property as it's stream specific.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767789
+
+2016-06-17 12:16:32 -0700  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: make all srtp encoder properties explicit
+	  The Session Data Protocol doesn't allow specifying a cipher for the
+	  SRTCP, so it will use the SRTP one. In the "srtpenc" element the cipher
+	  "aes-128-icm" is the default for SRTP and SRTCP, but if we want to have
+	  an SRTCP with the "aes-256-icm" cipher then we also need to set the SRTP
+	  cipher to "aes-256-icm", otherwise "aes-128-icm" will be used instead.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767799
+
+2016-06-17 19:59:13 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/soup/gstsoup.c:
+	  soup: work around frequent deadlocks in GLib type initialisation
+	  .. by registering the types from the plugin init function. This
+	  seems to help, but we'll see if it's enough (might need similar
+	  things elsewhere).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=693911
+	  https://bugzilla.gnome.org/show_bug.cgi?id=674885
+
+2016-06-17 16:08:08 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: The prores variant is stored in the variant field, not format
+	  And the caps in the sink pad template already used variant (only).
+
+2016-06-17 13:00:48 +0200  Jonas Holmberg <jonashg@axis.com>
+
+	* gst/rtp/gstrtph265pay.c:
+	* gst/rtp/gstrtph265pay.h:
+	  rtph265pay: Remove sprop-parameter-sets property
+	  There is no valid use case when this property is needed since the values
+	  must be in either codec_data or buffer data.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753760
+
+2016-06-10 16:17:26 +0200  Jonas Holmberg <jonashg@axis.com>
+
+	* docs/plugins/scanobj-build.stamp:
+	* gst/rtp/gstrtph265pay.c:
+	  rtph265pay: Read NALU type the same way everywhere
+	  Cosmetic change to read NALU type in gst_rtp_h265_pay_decode_nal() the
+	  same way as in other places.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753760
+
+2016-06-17 13:58:33 +0200  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  rtpjitterbuffer: fix RTPJitterBufferMode documentation
+	  Documentation lacks '@' before each enum values and there was an extra
+	  line after symbol section which confuses GTK-Doc parser.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767788
+
+2016-05-23 10:18:48 +0200  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: take the lock when changing stats
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766025
+
+2016-06-15 11:19:43 +0200  Jürgen Slowack <jurgen.slowack@barco.com>
+
+	* gst/rtp/gstrtph265pay.c:
+	  rtph265: fix NAL unit type parsing and SPS/PPS/VPS detection
+	  Fixes sps/pps/vps insertion via the config-interval property.
+	  https://bugzilla.gnome.org//show_bug.cgi?id=767680
+
+2016-06-11 12:16:03 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/pipelines/simple-launch-lines.c:
+	  simple-launch-lines: Use correct JPEG2000 caps
+
+2016-06-10 13:43:09 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: fix indentation
+
+2016-06-10 13:42:01 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: fix date parsing when there are trailing spaces
+	  Fixes parsing of "Thu May 11 15:57:46 2006 ".
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767496
+
+2016-05-13 15:08:24 -0400  Aaron Boxer <boxerab@gmail.com>
+
+	* gst/rtp/gstrtpj2kcommon.h:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	  gstrtpj2k: set sampling field required by RFC
+	  This field is now required in the sink caps.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766236
+
+2016-06-09 09:30:48 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Fix unref assertion failure
+	  Fix unref assertion failure
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767424
+
+2016-05-14 14:46:17 +0200  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Work with non-TIME segments
+	  With non-time segments, it now assumes that the arrival time of packets
+	  is not relevant and that only the RTP timestamp matter and it produces
+	  an output segment start at running time 0.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766438
+
+2016-06-07 20:53:34 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: Wait for segment event before checking it
+	  The heuristic to choose between packetise or not was changed to use the
+	  segment format. The problem is that this change is reading the segment
+	  during the caps event handling. The segment event will only be sent
+	  after. That prevented the decoder to go in packetize mode, and avoid
+	  useless parsing.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736252
+
+2016-06-06 17:00:22 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Wait for segment event before checking it
+	  The heuristic to choose between packetise or not was change to use the
+	  segment format. The problem is that this change is reading the segment
+	  during the caps event handling. The segment event will only be sent
+	  after. That prevented the decoder to go in packetize mode, and avoid
+	  useless parsing.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736252
+
+2016-06-07 16:42:09 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Keep part of the input buffer
+	  Instead of completely getting rid of the input buffer, copy
+	  the metadata, the flags and the timestamp into an empty buffer.
+	  This way the decoder base class can copy that information again
+	  to the output buffer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758424
+
+2016-06-07 16:41:58 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Coding style fixes
+
+2016-06-07 16:09:23 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Coding style fixes
+
+2016-06-07 16:04:52 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2transform.c:
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2: Add an error return to _try/_set_format
+	  This way one can easily ignore errors. Previously, error were always
+	  posted ont he bus.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766172
+
+2016-06-07 16:01:55 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/v4l2-utils.c:
+	* sys/v4l2/v4l2-utils.h:
+	  v4l2-util: Introduce GstV4l2Error
+	  This is to allow returning an error that can easily be sent as
+	  message to the application if the element needs it. Using this
+	  also allow ignoring errors.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766172
+
+2016-06-07 12:41:19 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: Avoid decide allocation on active pool
+	  v4l2src will renegotiate only if the format have changed. As of now,
+	  it's not possible to change the allocationw without resetting the
+	  camera. To avoid unwanted side effect, simply keep the old allocation
+	  if no renegotiation is taking place. This fixes assertion and possible
+	  failures in USERPTR or DMABUF import mode (when using downstream pools).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754042
+
+2016-04-28 13:44:49 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: Show state name in debugging
+	  Makes it easier to trace what's going on
+
+2016-05-10 15:45:42 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Remove useless variable
+	  That variable is only needed for a debug statement, move it there
+
+2016-05-10 15:10:36 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: Add/Fix comments on the various structure variables
+	  No variables were added/removed. This was just a good excuse to:
+	  * Comment what most variables are used for (and when)
+	  * Order them in such a way as to show first the common variables used
+	  in all cases, followed by those only used in push-mode
+
+2016-05-10 15:07:40 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Remove unused structure
+	  Let's just remove it, been commented for 7+ years :)
+
+2015-09-02 11:48:29 +0200  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: use decoder stop command instead of queueing empty buffers
+	  Only if the decoder stop command fails, keep queueing empty buffers to
+	  signal end of stream as before.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733864
+
+2014-12-12 14:31:36 +0100  Peter Seiderer <ps.report@gmx.net>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: add gst_v4l2_decoder_cmd helper
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733864
+
+2016-06-01 20:28:39 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Forward segments directly if we are operating in PUSH mode on fragmented streams
+	  We shouldn't go through segment activation as we will only have a limited
+	  understanding of how the whole stream timeline looks like from the moof. We
+	  only know about the current fragment, while upstream knows about the whole
+	  stream.
+	  This fixes seeking in DASH streams, both for seeks after the current moof and
+	  for seeks into the current moof. The former would fail because the moof ends
+	  and we can't activate any segment, the latter would cause a segment that stops
+	  at the moof end, and no further fragments would be played because we end up
+	  being EOS.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767071
+
+2016-06-06 17:54:10 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Use looser caps for upstream
+	  When we fixate for upstream, try to not introduce new fields when not
+	  needed. This was imported from videoconvert element.
+
+2015-01-28 12:07:58 +0100  Enrico Jorns <ejo@pengutronix.de>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  gstv4l2transform: format fixation for preferring passthrough
+	  * If outgoing format is unfixated, try to set it to input format.
+	  * Call gst_caps_fixate () at end of fixation routine
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766719
+
+2016-05-20 12:49:53 +0200  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: allow to change pixel aspect ratio
+	  Scalers may change width and height independently,
+	  allow to change pixel aspect ratio.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766712
+
+2016-05-20 12:32:25 +0200  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: fix scaling in case of fixed pixel aspect ratio
+	  To change pixel aspect ratio from DAR to PAR, the necessary scaling factor
+	  is DAR/PAR, not DAR*PAR.
+	  For good measure, add debug output similar to the fixed-width and
+	  fixed-height cases.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766711
+
+2016-05-13 16:39:25 +0200  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: fill colorimetry in gst_v4l2_object_acquire_format
+	  Instead of relying on the default colorimetry chosen by
+	  gst_video_info_set_format(), set info.colorimetry from the
+	  values returned by G_FMT. This allows decoders to propagate
+	  their input colorimetry downstream.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766383
+
+2016-05-18 10:17:12 +0200  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: refactor gst_v4l2_object_get_colorspace to take a v4l2_format parameter
+	  Move the extraction of colorimetry parameters from struct v4l2_format and the
+	  setting of the identity matrix for RGB formats into the function to avoid code
+	  duplication.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766383
+
+2016-05-13 14:58:41 +0200  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: use visible size, not coded size, for downstream negotiation filter
+	  gst_v4l2_probe_caps() returns the coded size, not the visible size. Subtract
+	  the known padding from probed caps with the coded size before using them as
+	  filter for caps negotiation with downstream elements.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766382
+
+2016-05-13 14:45:02 +0200  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: use G_SELECTION instead of G_CROP in gst_v4l2_object_acquire_format
+	  The gst_v4l2_object_acquire_format() function is used by v4l2videodec to obtain
+	  the currently set capture format. Since G_FMT returns the coded size, the
+	  visible size needs to be obtained from the compose rectangle in order to
+	  negotiate it with downstream elements. The G_CROP call hasn't worked on mem2mem
+	  capture queues for a long time. Instead use the G_SELECTION call to obtain the
+	  compose rectangle and only fall back to G_CROP for ancient kernels.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766381
+
+2016-01-27 09:57:38 +0100  Andreas Naumann <anaumann@ultratronik.de>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: Use V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY if driver advertises it.
+	  On modern kernels, the G/S_FMT ioctls will always fail using
+	  V4L2_BUF_TYPE_VIDEO_OVERLAY with VFL_DIR_TX (e.g. real overlay out drivers)
+	  since this is not the intented use (rather rx, according to v4l2 API doc).
+	  Probably this is why the Video Output Overlay interface was created, so if
+	  the driver advertises it we might as well use.
+	  For old kernels (pre 2012) the old way might still work so keeping this for
+	  compatibility.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761165
+
+2016-06-06 18:52:01 +0100  Kieran Bingham <kieran@bingham.xyz>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Use non-deprecated V4L2 type for RGB15
+	  Support for the updated V4L2_PIX_FMT_XRGB555 was added in commit
+	  2538fee2fd8fdb74b05f0a511281bc4707e7cc44 however, when setting the format
+	  for use in v4l2 ioctls, the old deprecated format is still used. Convert
+	  this to the new accepted format type, as the preferred format.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767300
+
+2016-05-04 14:50:32 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: preserve seek flags
+	  Without this some flags get lost in streaming mode.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767194
+
+2016-06-06 10:47:52 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/Makefile.am:
+	* ext/soup/gstsouphttpclientsink.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  Revert "WIP revert soup"
+	  This reverts commit fdac3a7a231f3848665636cf8122f96103b46e3b.
+	  Was not supposed to be pushed but a local workaround for
+	  https://bugzilla.gnome.org/show_bug.cgi?id=693911#c13
+
+2016-06-03 13:09:35 +0200  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: complete warn log with SSRC
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767195
+
+2016-05-31 15:29:13 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/Makefile.am:
+	* ext/soup/gstsouphttpclientsink.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  WIP revert soup
+
+2016-06-03 13:18:31 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: Unref seek event in any case
+	  It would be leaked if no seek handler was currently set.
+
+2016-06-03 10:49:17 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/dv/gstdvdemux.c:
+	* ext/dv/gstdvdemux.h:
+	  dvdemux: Properly set event/message sequence numbers based on the previous seek
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=765935
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767157
+
+2016-06-03 10:36:32 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/dv/gstdvdemux.c:
+	* ext/dv/gstdvdemux.h:
+	  dvdemux: Remember if upstream had a time segment and if not properly create time segments
+	  Previously the segment.time was wrong, and the position was not updated
+	  correctly, resulting in seeks in PUSH mode with upstream providing a BYTES
+	  segment to not work at all.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767157
+
+2016-06-03 09:54:53 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: Implement SEEKING query so we can actually seek if upstream can't seek in TIME
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767157
+
+2016-06-02 14:19:15 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: Recalculate the frame offsets at the beginning of each BYTE segment and whenever upstream gives us a timestamp
+	  This fixes seeking in DV streams where upstream operates in PUSH mode with a
+	  TIME segment (e.g. avidemux). Without this, we would generate wrong durations
+	  and timestamps after a seek.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767157
+
+2016-06-02 13:53:44 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/dv/gstdvdemux.c:
+	* ext/dv/gstdvdemux.h:
+	  dvdemux: Pass-through buffer DISCONT flags
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767157
+
+2016-06-02 16:16:45 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpvp9depay.c:
+	  rtpvp9depay: Don't assert on flexible mode packets
+	  Instead just post a warning on the bus for now.
+
+2016-06-02 15:03:17 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* tests/check/elements/rtpbin.c:
+	  tests: rtpbin: fix caps leak
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767156
+
+2016-06-02 15:00:01 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* tests/check/elements/amrparse.c:
+	  tests: amrparse: clean up test
+	  - use GST_CHECK_MAIN() to reduce boilerplate
+	  - unref the input caps using a teardown function to prevent leaks
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767156
+
+2016-05-20 15:22:35 +0200  Edward Hervey <edward@centricular.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  deinterlace: Ensure DISCONT flag is properly propagated
+	  The output of deinterlace at startup, or when receiving a new DISCONT
+	  buffer, should have the DISCONT flag set on the first buffer.
+
+2016-05-31 21:34:04 +0200  Josep Torra <adn770@gmail.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2src: check for valid size on raw video buffers
+	  Discard buffers that doesn't contain enough data when dealing
+	  with raw video inputs.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767086
+
+2016-05-31 17:10:36 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Use the demuxer segment instead of a new one for MSS streams
+	  Upstream might have told us something about the to be expected segment, so
+	  let's use that information instead of coming up with a [0,-1] segment.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767071
+
+2016-05-31 17:04:32 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Only activate segments and send SEGMENT events if we have streams
+	  But in that case also remove the pending newsegment event, otherwise we would
+	  later send a possibly outdated event.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767071
+
+2016-05-31 16:53:50 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: In PULL mode, nothing is ever going to send us a SEGMENT event
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767071
+
+2016-05-31 16:38:34 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Don't override TIME segments from upstream that we just saw
+	  The point of d8fb7a9c96b108814beeaa0e63f818d4648c7fe9 was to not have any
+	  spurious segments stored for later if we do BYTES->TIME conversion, but
+	  overriding any TIME segments from upstream does not make any sense.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=763165
+	  https://bugzilla.gnome.org/show_bug.cgi?id=767071
+
+2015-07-16 09:48:46 +0530  Prashant Gotarne <ps.gotarne@samsung.com>
+
+	* gst/multifile/gstmultifilesrc.c:
+	  multifilesrc: set position as offset from start-index
+	  query position in GST_FORMAT_BUFFER returns
+	  offset from start-index rather than index.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752462
+
+2016-05-27 12:49:32 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/pipelines/simple-launch-lines.c:
+	* tests/files/Makefile.am:
+	* tests/files/gradient.j2k:
+	  tests: add unit test for JPEG-2000 rtp payloader leak
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766870
+
+2016-05-25 17:11:13 +0200  Pierre Lamot <pierre.lamot@openwide.fr>
+
+	* gst/rtp/gstrtpj2kpay.c:
+	  rtpj2kpay: Fix buffer memory leak
+	  Input buffer memory was not unmapped
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766870
+
+2016-05-18 12:12:15 +0300  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: fix caps leak
+	  gst_v4l2_object_probe_caps() was taking an extra ref on the returned
+	  caps for no reason.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766610
+
+2016-05-22 20:14:18 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/videocrop/gstvideocrop.c:
+	  videocrop mark crop properties as mutable in playing state
+
+2016-05-20 16:47:35 +0300  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: fix buffer leak when flushing
+	  When early returning in gst_soup_http_src_read_buffer() because the
+	  element is FLUSHING, we need to unmap and unref the buffer which was just created.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766718
+
+2016-05-20 11:15:44 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Set seek event seqnum on all SEGMENT events
+	  Some were forgotten.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=765935
+
+2016-05-20 11:12:44 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: Pass through seek event seqnums in all SEGMENT/EOS events and SEGMENT_DONE messages/events
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=765935
+
+2016-05-20 10:56:52 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Set seek event seqnum in EOS and SEGMENT_DONE messages/events
+	  Also actually store the seqnum in pull mode seeks.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=765935
+
+2016-05-17 13:40:38 +0300  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: fix caps leak
+	  The caps returned by gst_pad_get_current_caps() was never unreffed when
+	  not early returning.
+	  Fix a leak with the elements/deinterlace test.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766558
+
+2016-01-25 16:25:51 +0100  Mikhail Fludkov <misha@pexip.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/rtpsession.c:
+	  rtpsession: don't act on suspicious BYE RTCP
+	  Some endpoints (like Tandberg E20) can send BYE packet containing our
+	  internal SSRC. I this case we would detect SSRC collision and get rid
+	  of the source at some point. But because we are still sending packets
+	  with that SSRC the source will be recreated immediately.
+	  This brand new internal source will not have some variables incorrectly
+	  set in its state. For example 'seqnum-base` and `clock-rate` values will be
+	  -1.
+	  The fix is not to act on BYE RTCP if it contains internal or unknown
+	  SSRC.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762219
+
+2015-11-15 14:54:28 +0100  Mikhail Fludkov <misha@pexip.com>
+
+	* tests/check/elements/rtpsession.c:
+	  rtpsession: Add test for locking of the stats signal
+	  Keeping the lock while emitting the stats signal introduces potential
+	  deadlock in those situations when the signal callback wants the access
+	  to rtpsession's properties which also requre the lock.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762216
+
+2016-05-19 15:36:57 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: don't hold object lock whilst pushing out headers
+	  matroskademux would take the GST_OBJECT_LOCK in
+	  - gst_matroska_demux_push_codec_data_all()
+	  - gst_matroska_demux_query()
+	  Some parse element such as FLAC checks upstream seekability, and
+	  there is some use cases that matroska-demux is linked to a parse element
+	  (e.g.,FLAC format) without intermediate elements (e.g., queue).
+	  In this case, matroska-demux never returns from _push_codec_data_all()
+	  because the parser can return only after it receives the response to
+	  the upstream query, but that's not going to happen because it's
+	  deadlocked.
+	  Elements must not hold the object lock whilst pushing out events
+	  or data.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766645
+
+2016-05-19 12:43:01 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	  souphttpclientsink: Set sent_buffers and streamheader_buffers to NULL after freeing
+	  Otherwise we might use an already freed list later and crash or worse.
+
+2016-05-18 18:32:57 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: fix Since version for new "loop" property
+
+2016-05-16 16:18:37 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* gst/rtsp/gstrtpdec.c:
+	  rtpdec: fix clock leak
+	  gst_system_clock_obtain() returns a new ref.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766521
+
+2016-05-17 05:33:35 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: add doc blurb with since marker for new "loop" property
+
+2015-11-13 15:52:35 +0100  Dimitrios Katsaros <patcherwork@gmail.com>
+
+	* gst/avi/gstavimux.c:
+	  avimux: add support for png
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758059
+
+2016-05-15 22:07:14 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	  splitmuxsrc: Connect to demux signals before activating
+	  Fix a race in splitmuxsrc by properly connecting to the
+	  demuxer signals we're interested in *before* setting it running.
+
+2016-05-15 13:31:37 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	  docs: Update for git master
+
+2016-05-15 12:16:23 +0200  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4gpay.h:
+	  rtpmp4gpay: Don't produce timestamps based on byte count
+	  The GST_BUFFER_OFFSET of output buffers returned to GstRtpBasePayload
+	  should reflect the number of "samples" in the unit of the RTP clock in this
+	  buffer. If this is not true, then it shouldn't be set.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761943
+
+2016-05-15 12:24:03 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroska-mux: Fix strcmp usage
+	  Just use g_strcmp0 which can handle NULL entries
+
+2016-03-04 10:14:00 +0100  Carlos Rafael Giani <dv@pseudoterminal.org>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Use audio/x-unaligned-raw instead of audio/x-raw for L16 data
+	  Directly setting audio/x-raw caps leads to problems when the delivered
+	  data blocks do not align properly at sample boundaries (for example, a
+	  data block with 391 bytes). So, instead, set audio/x-unaligned-raw to
+	  let a parser be autoplugged.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=689460
+
+2016-05-12 11:52:09 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Parsing elst box based on version
+	  segment_duration and media_time should be parsed based on version
+	  of elst box. Specification defines that an elst box with version 1
+	  has uint64 and int64 values for segment_duration and media_time,
+	  respectively.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766301
+
+2016-05-14 12:57:41 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: check if request was cancelled when sending message
+	  It might be that the request was aborted by the application and
+	  we can return immediatelly
+
+2016-05-14 12:43:54 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: proxy resolver is on by default
+	  Remove from the session creation parameters
+
+2016-05-14 12:15:48 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/soup/Makefile.am:
+	  soup: update build to warn about newer deprecated functions
+	  We already depend on 2.48
+
+2016-05-14 11:09:33 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: reduce reading latency by using non-blocking read
+	  Non-blocking read will return the amount of data available without
+	  blocking to wait for the full requested size.
+	  The downside is that now it souphttpsrc needs to have a waiting
+	  mechanism in case there is no data available yet to avoid busy
+	  looping arond the inputstream.
+
+2016-05-15 12:30:50 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Take the lock already when reading the other stats, not just for the hash table
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766025
+
+2016-05-14 17:04:57 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/matroska/ebml-read.c:
+	  matroska: use math-compat.h for NAN define
+
+2016-05-14 23:39:22 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmuxsink: Use GstBin async-handling instead of our own.
+	  Set the async-handling property on GstBin to let it manage
+	  async-handling instead of the local handling from the previous
+	  commit. Works because of #174a5e in core
+
+2016-05-13 10:17:33 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: refactor to use Soup's sync API
+	  Replace the async API with the sync API to remove all the extra mainloop
+	  and context handling. Currently it blocks reading until 'blocksize'
+	  bytes are available but that can be improved by using:
+	  https://developer.gnome.org/gio/unstable/GPollableInputStream.html#g-pollable-input-stream-read-nonblocking
+	  https://bugzilla.gnome.org/show_bug.cgi?id=693911
+
+2016-05-14 04:50:36 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: souphttpsrc: replace deprecated API
+	  Avoid using soup_server_run_async and old get_port() APIs,
+	  replace with me soup_server_listen and get the port through the
+	  URIs list returned from the server.
+
+2016-05-14 12:34:10 +0200  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: Upgrade debug message to error
+	  It causes the entire pipeline to fail, it should be easier to find.
+
+2016-05-14 18:32:52 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmuxsink: Hide internal async state changes.
+	  When switching fragments, hide the async-start/async-done
+	  messages from the parent bin, as otherwise we sometimes (very rarely)
+	  hang in PAUSED instead of returning / continuing to PLAYING
+	  state.
+
+2016-05-13 21:20:28 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Remove stray carriage-return from debug
+
+2016-05-13 16:43:21 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/Makefile.am:
+	  rtp: Ship gstrtpj2kcommon.h file to fix distcheck
+
+2015-04-30 14:43:04 +0200  Jesper Larsen <knorr.jesper@gmail.com>
+
+	* gst/avi/gstavimux.c:
+	  avimux: Do not write index and header if idx is NULL
+	  Fixes criticals with e.g.
+	  videotestsrc num-buffers=1 ! identity drop-probability=1.0 ! avimux ! fakesink
+	  https://bugzilla.gnome.org/show_bug.cgi?id=748700
+
+2016-05-12 08:43:39 -0400  Aaron Boxer <boxerab@gmail.com>
+
+	* gst/rtp/gstrtpj2kpay.c:
+	  rtpj2kpay: manage T tile invalidation bit correctly, update tile id in header correctly.
+	  1. according to RFC, T bit is only set when either the RTP packet only contains the J2K main header, or the packet contains tile parts from multiple tiles. This is now being managed correctly in the code. The second scenario cannot happen with our payloader, since tile headers are always placed in their own RTP packet, and so a packet cannot contain tile parts from multiple tiles.
+	  However, I have added code to track if multiple tile parts are included in a single RTP packet, in case in the future we want to put header and data in same packet.
+	  2. Old code would set the tile id to zero for all J2K packets. This is now set correctly to the appropriate tile id.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745187
+
+2016-05-12 08:41:51 -0400  Aaron Boxer <boxerab@gmail.com>
+
+	* gst/rtp/gstrtpj2kpay.c:
+	  rtpj2kpay: manage fragmented headers correctly
+	  J2K main header framentation across multiple RTP packets is now handled correctly
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745187
+
+2016-05-11 15:04:26 -0400  Aaron Boxer <boxerab@gmail.com>
+
+	* gst/rtp/gstrtpj2kcommon.h:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kdepay.h:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpj2kpay.h:
+	  rtpj2k: move common code to shared header, code clean up
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745187
+
+2016-05-11 15:01:32 -0400  Aaron Boxer <boxerab@gmail.com>
+
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	  rtpj2k: update documentation
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745187
+
+2016-05-12 14:43:43 +0200  Patricia Muscalu <patricia@axis.com>
+
+	* gst/auparse/gstauparse.c:
+	* gst/auparse/gstauparse.h:
+	  auparse: Fix sticky event misordering warning
+	  Make sure that src pad has caps before sending segment event.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766359
+
+2016-05-11 09:28:13 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Don't notify about stats property changes while taking the session lock
+	  The signal handlers might want to actually get the value of the stats
+	  property, which would take the session lock again and deadlock.
+	  This was introduced by 2e960e70750a0cb7e1117d0c09d08597866a29ee.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766025
+
+2016-05-03 13:59:54 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: improve edts segment handling after seeks in push mode
+	  Properly handle edts segments for push-based operation seeking.
+	  We only support edts that a single segment that has media at the end,
+	  being preceeded by any number of gap segments.
+	  This also allows the qt segment rate to be respected after seeks
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765669
+
+2016-05-03 10:41:06 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: properly activate segment with rate != 1.0
+	  Also use the qt rate to identify the position within a qt segment
+	  to properly translate playback time to qt media time
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765669
+
+2016-05-03 11:45:01 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Fix stall when receiving already lost packet
+	  When a packet arrives that has already been considered lost as part of a
+	  large gap the "lost timer" for this will be cancelled. If the remaining
+	  packets of this large gap never arrives, there will be missing entries
+	  in the queue and the loop function will keep waiting for these packets
+	  to arrive and never push another packet, effectively stalling the
+	  pipeline.
+	  The proposed fix conciders parts of a large gap definitely lost (since
+	  they are calculated from latency) and ignores the late arrivals.
+	  In practice the issue is rare since large gaps are scheduled immediately,
+	  and for the stall to happen the late arrival needs to be processed
+	  before this times out.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765933
+
+2016-05-05 14:18:21 +0200  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Take session lock when creating stats
+	  The access to the session hash table must happen while the session lock is
+	  taken, otherwise another thread might modify the hash table while we're
+	  creating the stats.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=766025
+
+2016-05-03 21:17:01 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: update segment when new duration is found
+	  Otherwise the old segment will have a shorter stop time and would
+	  cause the stream to end too early.
+
+2016-05-04 11:37:29 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: dismember activate_segment into 2 parts
+	  One that updates and push a new segment, the other will move the
+	  stream to the new segment starting position
+
+2016-05-04 09:30:27 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/dv/gstdvdec.c:
+	* ext/dv/gstdvdemux.c:
+	  dv: Use correct pixel-aspect-ratio values
+	  The previous ones resulted in odd display aspect ratios and were different
+	  from the ones used by e.g. ffmpeg. The new ones now result in display aspect
+	  ratios of 4:3 and 16:9.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765946
+
+2015-11-09 17:55:09 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/check/elements/splitmux.c:
+	  tests: add splitmuxsrc test for new "format-location" signal
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753625
+
+2015-11-09 17:51:12 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/multifile/gstsplitmuxsrc.c:
+	  splitmuxsrc: add a format-location signal that allows bypassing the location property
+	  This signal allows a user to directly return a sorted list of
+	  files to be joined, so that they don't have to follow the
+	  filename pattern that the "location" property expects.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753625
+
+2016-05-04 11:15:20 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Fix deadlock case when source reaches EOS
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765072
+
+2016-05-03 22:59:27 -0700  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: simplify and correct header scanning
+	  The wav spec tells that 'fmt' (and 'bext' if present) must come before 'data'.
+	  There is no requirement for 'fmt' to be first. We already had a list of chunks
+	  to skip, but it is easier to just skip any chunk while seeking for 'fmt'.
+	  This fixes reading files generated by ProTools.
+
+2016-04-30 22:15:13 +0900  Hyunjun Ko <zzoon@igalia.com>
+
+	* sys/osxaudio/Makefile.am:
+	* sys/osxaudio/gstosxaudio.c:
+	* sys/osxaudio/gstosxaudiodeviceprovider.c:
+	* sys/osxaudio/gstosxaudiodeviceprovider.h:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosink.h:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxaudio/gstosxaudiosrc.h:
+	  osxaudio: Support audio device provider on osx
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753265
+
+2016-05-01 15:09:27 +0200  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/avi/gstavimux.c:
+	  avimux: set audio header rate according to calculated bps in stop_file
+	  ... now that set_fields is no longer called there by
+	  e538608b3f90539003de21c1db238f3c9b946e30
+
+2016-04-29 15:04:11 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: Store the segment sequence number in the EOS events and SEGMENT_DONE events/message
+	  Also instead of storing it per stream, store it globally in the demuxer. It's
+	  the same for each stream anyway.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765806
+
+2016-04-11 10:54:38 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Always bind to ANY when address is a multicast address and not only on Windows
+	  For IPv6 addresses, binding to a multicast group does not work on Linux
+	  either. Always bind to ANY and then later join the multicast group.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=764679
+
+2016-04-26 17:01:49 +0800  Song Bing <b06498@freescale.com>
+
+	* sys/ximage/ximageutil.c:
+	  ximageutil: shouldn't implement transform if don't support it
+	  shouldn't implement transform if don't support it. Or gst_buffer_copy_into()
+	  will print ERROR log.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765583
+
+2016-04-28 16:24:52 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmuxmap.c:
+	  qtmux: Allow MPEG-1 Layer 1 and 2 in addition to 3 in MP4
+	  Via the MPEG-4 Part 3 spec we can support the other layers too.
+	  Also correct the samples per frame calculation for MP3 if it's MPEG-2 or
+	  MPEG-2.5.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765725
+
+2016-04-27 20:46:34 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Update caps for TCP whenever they change
+	  We only changed them for UDP so far, which caused the wrong seqnum-base and
+	  other information to be passed to rtpjitterbuffer/etc when seeking. This
+	  usually wasn't that much of a problem as the code there is robust enough, but
+	  every now and then it causes us to drop up to 32756 packets before we
+	  continue doing anything meaningful.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765689
+
+2016-04-27 20:33:38 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Ensure to not take caps with the wrong pt for getting the clock-rate
+	  Especially the caps on the pad might be out of date, and the new caps would be
+	  provided for the current pt via the request-pt-map signal.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765689
+
+2016-04-27 18:27:17 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Don't propagate spurious state change returns from internal elements further
+	  We handle them inside rtspsrc and override them in all other cases anyway, so
+	  do the same for "internal" state changes like PAUSED->PAUSED and
+	  PLAYING->PLAYING.
+	  This keeps unexpected NO_PREROLL to confuse state changes in GstBin.
+	  See also https://bugzilla.gnome.org/show_bug.cgi?id=760532
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765689
+
+2016-04-27 14:09:03 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/avi/gstavimux.c:
+	  avimux: Don't override maximum audio chunk size with the scale again just before writing it
+	  set_fields() should only be called in the beginning, otherwise we will never
+	  remember the maximum audio chunk size and write a wrong block align... which
+	  then causes wrong timestamps and other problems.
+
+2016-04-27 13:53:00 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/avi/gstavimux.c:
+	  avimux: Actually store the largest audio chunk size for the VBR case of MP2/MP3
+	  3ea338ce271e1f6a96d2ed49d4472b091f6f8b7e changed avimux to do that, but it
+	  never actually kept track of the max audio chunk for MP3 and MP2. These are
+	  knowing the hdr.scale only after parsing the frames instead of at setcaps
+	  time.
+
+2016-04-25 15:03:14 +0200  Mats Lindestam <matslm@axis.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: Allow setting "socket-v6" without setting "socket" too
+	  https://bugzilla.gnome.org/show_bug.cgi?id=764897
+
+2016-04-22 15:02:16 +0100  Mario Sanchez Prada <mario@endlessm.com>
+
+	* ext/vpx/gstvpxenc.c:
+	  vpxenc: Properly handle frames with too low duration
+	  When a frame's duration is too low, calling gst_util_uint64_scale()
+	  to scale its value can result into it being truncated to zero, which
+	  will cause the vpx encoder to return an VPX_CODEC_INVALID_PARAM error
+	  when trying to encode.
+	  To prevent this from happening, we simply ignore the duration when
+	  encoding if it becomes zero after scaling, logging a warning message.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765391
+
+2016-04-22 15:48:08 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: fix description of linear interlacing method
+
+2016-04-21 14:08:19 -0300  Thibault Saunier <tsaunier@gnome.org>
+
+	* gst/flv/gstflvmux.c:
+	  flv: Handle the case where we do not get any CollectData in handle_buffer
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765320
+
+2016-04-11 22:41:20 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Do not use unreliable framerate
+	  timescale/1 is unreliable value for framerate. Due to downstream
+	  element usually use framerate generated by qtdemux, let it be omitted
+	  until the framerate can be reliably calculated.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=764733
+
+2016-04-21 12:53:33 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  Revert "qtdemux: expose streams with first moof for fragmented format"
+	  This reverts commit d8bb6687ea251570c331038279a43d448167d6ad.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=764733
+
+2016-02-09 17:17:09 +0000  Alex Ashley <bugzilla@ashley-family.net>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: support seeking of CENC encrypted streams
+	  When playing a stream that has been protected by DASH CENC, playback
+	  will fail if a seek is performed. Qtdemux produces the error "stream
+	  is protected using cenc, but no cenc protection system information
+	  has been found" and playback stops.
+	  The problem is that gst_qtdemux_reset() gets called as part of the
+	  FLUSH during a seek. This function frees the protection_system_ids
+	  array. When gst_qtdemux_configure_protected_caps() is called after the
+	  seek has completed, the protection_system_ids array is empty and
+	  qtdemux is unable to create the correct output caps for the protected
+	  stream.
+	  This commit changes it to only free the protection_system_ids on
+	  hard resets.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761787
+
+2016-04-18 14:33:10 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	* gst/udp/gstudpsrc.h:
+	  udpsrc: add "retrieve-sender-address" property
+	  This allows disabling of sender address retrieval, which might
+	  be useful in certain scenarios, like when the socket is connected,
+	  or the sender address is not of interest (e.g. when receiving an
+	  MPEG-TS stream). Disabling sender address retrieval in those
+	  cases can have minor performance advantages.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=563323
+
+2015-11-26 13:15:06 +0100  Dimitrios Katsaros <patcherwork@gmail.com>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: Change warning handling to break infinite message loop
+	  v4l2src can cause an "infinite message loop" when a base control exposed as a
+	  property is not provided by the device. In these cases, if in the warning message
+	  handling for the bus, the GST_DEBUG_BIN_TO_DOT_FILE* category of functions are used,
+	  the src lookup causes a new warning to be posted on the bus, causing a loop.
+	  This patch changes the warning for these controls so they are not posted on the bus.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758703
+
+2016-04-15 10:44:02 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  spitmuxsink: Avoid creating small file at EOS
+	  When EOS is reached, the current file get closed and the last
+	  GOP in the mq was written in a new file.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765072
+
+2016-04-15 19:59:15 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: S16 uses S32 temporary buffers, float/double their own type
+	  Make sure to allocate not only a S16 buffer for S16 but a twice as big one to
+	  hold S32.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=765116
+
+2016-04-16 02:17:26 +1000  Jan Schmidt <jan@centricular.com>
+
+	* ext/pulse/pulsesink.c:
+	  Revert "pulsesink: uncork if needed upon commit"
+	  This reverts commit 0dd46accf6d282ff07065852bd91c85c78af3394.
+	  With some audiosinks, starting the ringbuffer on the first commit
+	  causes audio glitches at startup by starting to output segments
+	  from the ringbuffer before it has been filled / fully prerolled. This
+	  doesn't usually happen with pulsesink because we map the pulseaudio
+	  ringbuffer directly, but we should keep things consistent with
+	  other sinks with regards to startup latency, plus it gives more
+	  headway to avoid glitching, should the initial 2nd segment take
+	  more than 10ms to generate.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=657076
+
+2016-04-15 00:46:56 -0700  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: add srtp rollover counters from mikey crypto sessions
+	  The server can send multiple crypto sessions, one for each SSRC with its
+	  own rollover counter. We parse this information and pass it to the SRTP
+	  decoder via the "request-key" signal.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730540
+
+2016-04-15 14:35:07 +0000  Jan Schmidt <jan@centricular.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Fix debug output when resyncing
+	  Don't output the pointer value of the time() function as a timestamp
+	  by using the correct variable.
+	  Fixes build on Raspberry Pi 3.
+
+2016-04-15 11:36:36 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	  souphttpclientsink: If no proxy is set by properties, use the default libsoup proxy resolver
+	  That is, use whatever system settings there might exist. This is the same
+	  behaviour we use in the HTTP source.
+
+2016-04-14 10:01:28 +0100  Julien Isorce <j.isorce@samsung.com>
+
+	* README:
+	* common:
+	  Automatic update of common submodule
+	  From 6f2d209 to ac2f647
+
+2016-04-13 18:45:07 +0100  Damian Ziobro <damian@xmementoit.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmuxsink: Add max_files_number property
+	  https://bugzilla.gnome.org/show_bug.cgi?id=744612
+
+2016-04-13 10:57:03 -0700  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: drop reference to videomixer 2
+	  Fix a small grammar mistake on "overlayed" while at it.
+
+2016-04-13 09:57:16 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* sys/ximage/ximageutil.c:
+	  ximage: Initialize all fields in the meta explicitly
+	  The meta is not allocated with all fields initialized to zeroes.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=764902
+
+2016-04-12 09:41:00 +0000  Paolo Pettinato <ppettina@cisco.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Forward sticky events on buffer lists too, not only on buffers
+	  https://bugzilla.gnome.org/show_bug.cgi?id=764933
+
+2016-04-12 15:01:28 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Drain the field history if the caps are changing
+	  Otherwise we will use fields from the old caps with everything set up for the
+	  new caps, causing crashes and worse.
+	  Also don't do anything if the same caps are set twice.
+
+2016-04-12 15:00:31 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Instead of confusing crashes later, just error out immediately if mapping a video frame fails
+	  This probably still crashes but at least we get some hint about what goes
+	  wrong instead of random behaviour later.
+
+2016-04-12 11:38:51 +0100  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: check stream is available in PIFF parser
+	  qtdemux->streams is an array, it will never evaluate to true when comparing
+	  to NULL. Instead we want to check the number of streams to make sure the
+	  stream is available.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753614
+	  CID 1358389
+
+2016-04-12 11:37:36 +0100  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  Revert "qtdemux: redundant check in PIFF parser"
+	  This reverts commit 41e10524f3babdd92aac8c8c9d5b9cdf184c2d4e.
+
+2016-04-12 11:05:50 +0100  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: redundant check in PIFF parser
+	  qtdemux->streams is an array of size GST_QTDEMUX_MAX_STREAMS, it will never
+	  evaluate to true when comparing to NULL.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753614
+	  CID 1358389
+
+2016-04-12 11:56:08 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: avoid leaking GValues
+	  unset the GValue if we don't use it any more to avoid leaks.
+
+2016-04-12 10:15:39 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Fix rtp_jitter_buffer_get_ts_diff() fill level calculation
+	  The head of the queue is the oldest packet (as in lowest seqnum), the tail is
+	  the newest packet. To calculate the fill level, we should calculate tail-head
+	  while considering wraparounds. Not the other way around.
+	  Other code is already doing this in the correct order.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=764889
+
+2016-04-11 10:44:56 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/Makefile.am:
+	  rtpmanager: It's GST_LIBS, not GST_LIBS_LIBS
+
+2016-04-11 08:33:17 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix parsing segment duration of empty edit list box
+	  For empty edit list, segment-duration in edit list box should not be
+	  used for segment event.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=764870
+
+2016-04-08 13:05:57 +0200  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: make timecodescale configurable
+	  In some use cases the default timecodescale will produce blocks with the same timestamp
+	  https://bugzilla.gnome.org/show_bug.cgi?id=764769
+
+2016-04-07 13:01:52 +0200  Edward Hervey <edward@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jiterbuffer: Move assertion to the right location
+	  We shouldn't have "late" lost timers at that point
+
+2016-03-02 14:25:24 +0100  Edward Hervey <edward@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: Speed up lost timeout handling
+	  When downstream blocks, "lost" timers are created to notify the
+	  outgoing thread that packets are lost.
+	  The problem is that for high packet-rate streams, we might end up with
+	  a big list of lost timeouts (had a use-case with ~1000...).
+	  The problem isn't so much the amount of lost timeouts to handle, but
+	  rather the way they were handled. All timers would first be iterated,
+	  then the one selected would be handled ... to re-iterate the list again.
+	  All of this is being done while the jbuf lock is taken, which in some use-cases
+	  would return in holding that lock for 10s... blocking any buffers from
+	  being accepted in input... which would then arrive late ... which would
+	  create plenty of lost timers ... which would cause the same issue.
+	  In order to avoid that situation, handle the lost timers immediately when
+	  iterating the list of pending timers. This modifies the complexity from
+	  a quadratic to a linear complexity.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762988
+
+2016-03-02 14:23:01 +0100  Edward Hervey <edward@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: Don't create lost events if we don't need them
+	  When "do-lost" is set to FALSE we don't use/send the lost events.
+	  In that case, don't create them to start with :)
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762988
+
+2016-03-02 13:57:07 +0100  Edward Hervey <edward@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: Add tracing of lock usage
+	  Helps with debugging lock usage
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762988
+
+2016-02-10 19:56:59 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* sys/v4l2/gstv4l2deviceprovider.c:
+	  v4l2: Don't leak v4l2 objects and props on probe errors
+
+2016-04-04 17:42:03 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/rtp-payloading.c:
+	  tests: add unit test for jpeg depayloader packet loss handling
+	  Make sure it always outputs something that looks like a valid
+	  JPEG frame, ie. starts with an SOI marker and ends with an EOI
+	  marker.
+
+2016-03-15 03:25:26 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	  rtpjpegdepay: Don't send invalid frames downstream after packet loss or a DISCONT
+	  After clearing the adapter due to a DISCONT, as might happen when some packet(s)
+	  have been lost, the depayloader was pushing data into the adapter (which had no
+	  header due to the clear), creating a headerless frame out of it, and sending it
+	  downstream. The downstream decoder would then usually ignore it; unless there
+	  were lots of DISCONTs from the jitterbuffer in which case the decoder would reach
+	  its max_errors limit and throw an element error. Now we just discard that data.
+	  It is probaby not worth trying to salvage this data because non-progressive
+	  jpeg does not degrade gracefully and makes the video unwatchable even with
+	  low packet loss such as 3-5%.
+
+2016-01-05 16:15:16 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtpjitterbuffer: Add RFC7273 media clock handling
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762259
+
+2015-07-10 09:44:15 +0200  Philippe Normand <philn@igalia.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: PIFF box detection and parsing support
+	  The PIFF data is stored in a custom UUID box which is parsed and the
+	  crypto_info of the element is updated accordingly. This allows
+	  downstream decryptors to process and decrypt the protected content.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753614
+
+2016-04-01 12:15:05 +0100  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/rtp/gstrtpvorbisdepay.c:
+	  rtpvorbisdepay: remove dead code
+	  payload_buffer hasn't been assigned a value before the jumps to
+	  switch_failed or packet_short. So the value must be NULL. No need
+	  to unmap and unref.
+	  CID #1316476
+
+2016-03-31 14:57:20 +0100  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: fix leak
+	  Free memory of current macroblock once it isn't needed so it isn't leaked
+	  by the call of the gst_rtp_h263_pay_B_mbfinder function.
+	  if (!(mac = gst_rtp_h263_pay_B_mbfinder (context, gob, mac, mb))) {
+	  CID 1212156
+
+2016-03-31 02:15:04 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmux: Handle a hang draining out at EOS
+	  Make sure that all data is drained out when the reference pad
+	  goes EOS. Fixes a problem where data that arrives on other
+	  pads after the reference pad finishes can stall forever and
+	  never pass EOS.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763711
+
+2016-03-18 15:45:01 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Fix occasional deadlock when ending file with subtitle
+	  Deadlock occurs when splitting files if one stream received no buffer during
+	  the first GOP of the next file. That can happen in that scenario for example:
+	  1) The first GOP of video is collected, it has a duration of 10s.
+	  max_in_running_time is set to 10s.
+	  2) Other streams catchup and we receive the first subtitle buffer at ts=0 and
+	  has a duration of 1min.
+	  3) We receive the 2nd subtitle buffer with a ts=1min. in_running_time is set to
+	  1min. That buffer is blocked in handle_mq_input() because
+	  max_in_running_time is still 10s.
+	  4) Since all in_running_time are now > 10s, max_out_running_time is now set to
+	  10s. That first GOP gets recorded into the file. The muxer pop buffers out
+	  of the mq, when it tries to pop a 2nd subtitle buffer it blocks because the
+	  GstDataQueue is empty.
+	  5) A 2nd GOP of video is collected and has a duration of 10s as well.
+	  max_in_running_time is now 20s. Since subtitle's in_running_time is already
+	  1min, that GOP is already complete.
+	  6) But let's say we overran the max file size, we thus set state to
+	  SPLITMUX_STATE_ENDING_FILE now. As soon as a buffer with ts > 10s (end of
+	  previous GOP) arrives in handle_mq_output(), EOS event is sent downstream
+	  instead. But since the subtitle queue is empty, that's never going to
+	  happen. Pipeline is now deadlocked.
+	  To fix this situation we have to:
+	  - Send a dummy event through the queue to wakeup output thread.
+	  - Update out_running_time to at least max_out_running_time so it sends EOS.
+	  - Respect time order, so we set out_running_tim=max_in_running_time because
+	  that's bigger than previous buffer and smaller than next.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763711
+
+2015-11-17 18:17:35 +0100  Stian Selnes <stian@pexip.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* tests/check/elements/rtpsession.c:
+	  rtpsession: Add new signal 'on-app-rtcp'
+	  Similar to the 'on-feedback-rtcp' signal, but emitted for RTCP APP
+	  packets.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762217
+
+2016-03-24 15:57:11 +0900  Minjae Kim <nate.kim@lge.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpmanager: Set to initial value for 'ntpns' in get_current_times()
+	  Initialize "ntpns" variable to -1 as the OE compiler for some reason doesn't
+	  realize that the variable is set in all code paths.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=764119
+
+2016-01-31 11:08:38 +1100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: Allow different quantization tables for components 2 and 3
+	  RFC 2435 mentions in section 4.1 that U/V use table number 1, but this seems
+	  just like an example. Some encoders are not following that and there seems to
+	  be no reason to reject their streams.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761345
+
+2016-03-24 19:23:12 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* ext/vpx/gstvpxdec.c:
+	  vpxdec: Use threads on multi-core systems
+	  This is a redo of commit b848c1b6ffd1e508228820a013f94fb445e4777f. The
+	  code was lost when the elements where ported to use a baseclass.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=764169
+
+2016-02-29 23:40:03 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* tests/check/elements/splitmux.c:
+	  splitmuxsink: only try to create internal sink if it doesn't exist
+	  This allows splitmuxsink to be reused after being put to NULL.
+	  Test included
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762893
+
+2015-10-01 13:41:23 +0200  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: probe all colorspace supported by device
+	  A device can support more than one colorspace for a given image
+	  dimension and pixel format. So we have to probe all the supported
+	  colorspace and not only rely on the default one. Otherwise we could end
+	  up with negotiation failure if the caps colorimetry field don't match
+	  the v4l2 device default one even if the v4l2 could support such
+	  colorimetry.
+	  This patch enable probing if colorspace for both capture and output
+	  device. It really makes sense for output device since the colorspace
+	  shall be set by the application and a little less for capture device
+	  which, at the moment, shall provide the colorspace; ie: the v4l2
+	  specification seems to not take into account the fact that a capture
+	  device could do colorspace conversion.
+	  As a side effet, probing takes some times and so sligthly delay v4l2
+	  initialization. Note that this patch only probe colorspace and not all
+	  colorspace, matrix, transfer and range combination to avoid taking too
+	  much time, especially with low-speed devices as full probing do 1782
+	  ioctl.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755937
+
+2016-03-24 16:21:56 +0100  Edward Hervey <edward@centricular.com>
+
+	* tests/check/elements/flvdemux.c:
+	  check: Fix indentation
+
+2016-03-24 16:20:39 +0100  Edward Hervey <edward@centricular.com>
+
+	* tests/check/elements/flvdemux.c:
+	  tests: Remove unused variables
+
+2016-03-16 20:26:16 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/interleave/deinterleave.c:
+	  deinterleave: Return the current caps on the srcpads on caps queries
+	  It's not like we could accept any other caps here. The caps are decided by the
+	  upstream caps event.
+	  Also keep the filter order intact when filtering the results against the
+	  filter caps.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763326
+
+2016-03-24 15:14:23 +0900  Jimmy Ohn <yongjin.ohn@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix qtdemux memory leak in src_convert function
+	  If we don't find the index of the sample correctly in src_convert function,
+	  we have to unref about the qtdemux before returning value.
+	  So, I have modify it about instead pass qtdemux as a parameter into
+	  src_convert function.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763973
+
+2016-03-22 13:15:20 +0900  Jimmy Ohn <yongjin.ohn@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Add check condition for fail case in get_duration function
+	  Currently, get_duration function always return the TRUE even though
+	  it can't be set duration correctly. So, we need to add the else condition
+	  about the fail case. Also, we already set the GST_CLOCK_TIME_NONE
+	  in this function. So I have modify it which is related code in some
+	  function.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763968
+
+2016-03-21 10:11:23 +0900  Jimmy Ohn <yongjin.ohn@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Modify data type of duration in handle_src_query function
+	  Data type of duration need to modify from guint64 to GstClockTime
+	  for consistency in handle_src_query function.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763965
+
+2016-03-18 14:40:58 +0200  Vivia Nikolaidou <vivia@ahiru.eu>
+
+	* tests/check/elements/deinterlace.c:
+	  deinterlace: Added unit tests for field=auto
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763869
+
+2016-03-17 21:21:02 +0200  Vivia Nikolaidou <vivia@toolsonair.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  deinterlace: Added "auto" fields mode
+	  The "auto" fields mode will detect the upstream and downstream framerates and
+	  will decide to deinterlace all or only top fields.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763869
+
+2016-03-16 20:17:55 +0100  Havard Graff <havard.graff@gmail.com>
+
+	* gst/flv/gstflvdemux.c:
+	* tests/check/elements/flvdemux.c:
+	  flvdemux: don't emit pad-added until caps are ready
+	  In other words, gst_pad_get_current_caps should never return NULL
+	  in a pad-added callback from the demuxer.
+	  Added tests for the two special cases with AAC and H.264 where this
+	  would happen every time.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763780
+
+2016-03-04 10:30:12 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* ext/aalib/gstaasink.c:
+	* ext/cairo/gstcairooverlay.c:
+	* ext/dv/gstdvdec.c:
+	* ext/dv/gstdvdemux.c:
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflactag.c:
+	* ext/gdk_pixbuf/gstgdkpixbufdec.c:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstsmokedec.c:
+	* ext/jpeg/gstsmokeenc.c:
+	* ext/libcaca/gstcacasink.c:
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngenc.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	* ext/shout2/gstshout2.c:
+	* ext/soup/gstsouphttpclientsink.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	* ext/taglib/gstapev2mux.cc:
+	* ext/taglib/gstid3v2mux.cc:
+	* ext/vpx/gstvp8dec.c:
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp9dec.c:
+	* ext/vpx/gstvp9enc.c:
+	* ext/wavpack/gstwavpackdec.c:
+	* ext/wavpack/gstwavpackenc.c:
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalphacolor.c:
+	* gst/apetag/gstapedemux.c:
+	* gst/audiofx/audiopanorama.c:
+	* gst/audiofx/gstscaletempo.c:
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstsbcparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	* gst/auparse/gstauparse.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavisubtitle.c:
+	* gst/cutter/gstcutter.c:
+	* gst/debugutils/breakmydata.c:
+	* gst/debugutils/cpureport.c:
+	* gst/debugutils/gstcapsdebug.c:
+	* gst/debugutils/gstcapssetter.c:
+	* gst/debugutils/gstnavigationtest.c:
+	* gst/debugutils/gstnavseek.c:
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/debugutils/gsttaginject.c:
+	* gst/debugutils/progressreport.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/debugutils/testplugin.c:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstop.c:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstripple.c:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gststreak.c:
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstwarp.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/id3demux/gstid3demux.c:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/interleave/deinterleave.c:
+	* gst/interleave/interleave.c:
+	* gst/isomp4/gstrtpxqtdepay.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/level/gstlevel.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/webm-mux.c:
+	* gst/monoscope/gstmonoscope.c:
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/multifile/gstsplitfilesrc.c:
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsrc.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartmux.c:
+	* gst/replaygain/gstrganalysis.c:
+	* gst/replaygain/gstrglimiter.c:
+	* gst/replaygain/gstrgvolume.c:
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpL24depay.c:
+	* gst/rtp/gstrtpL24pay.c:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpg722depay.c:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtpg723depay.c:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtph261depay.c:
+	* gst/rtp/gstrtph261pay.c:
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtph265depay.c:
+	* gst/rtp/gstrtph265pay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpklvdepay.c:
+	* gst/rtp/gstrtpklvpay.c:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmparobustdepay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtpopusdepay.c:
+	* gst/rtp/gstrtpopuspay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtppcmupay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpsbcdepay.c:
+	* gst/rtp/gstrtpsbcpay.c:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpsirenpay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpstreamdepay.c:
+	* gst/rtp/gstrtpstreampay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvp8depay.c:
+	* gst/rtp/gstrtpvp8pay.c:
+	* gst/rtp/gstrtpvp9depay.c:
+	* gst/rtp/gstrtpvp9pay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtprtxqueue.c:
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	* gst/rtpmanager/gstrtprtxsend.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtsp/gstrtpdec.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/smpte/gstsmpte.c:
+	* gst/smpte/gstsmptealpha.c:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	* gst/videobox/gstvideobox.c:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videofilter/gstvideomedian.c:
+	* gst/videomixer/videomixer2.c:
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavparse/gstwavparse.c:
+	* gst/y4m/gsty4mencode.c:
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/oss/gstosssink.c:
+	* sys/oss/gstosssrc.c:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxvideo/osxvideosink.m:
+	* sys/sunaudio/gstsunaudiosink.c:
+	* sys/sunaudio/gstsunaudiosrc.c:
+	* sys/waveform/gstwaveformsink.c:
+	* sys/ximage/gstximagesrc.c:
+	* tests/check/elements/autodetect.c:
+	* tests/check/elements/qtmux.c:
+	  good: use new gst_element_class_add_static_pad_template()
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763076
+
+2016-03-04 09:42:44 +0100  David Buchmann <david.buchmann@gmail.com>
+
+	* tests/check/elements/flvmux.c:
+	  flvmux: Test to verify flvmux handles DTS with GST_CLOCK_TIME NONE
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762207
+
+2015-11-04 14:51:19 +0900  Jihae Yi <jihae.yi@samsung.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: avoid potentially overflowing expression
+	  https://bugzilla.gnome.org/show_bug.cgi?id=757569
+
+2016-03-22 10:43:45 +0900  Jimmy Ohn <yongjin.ohn@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Add the function to get channels and sample rate for AAC
+	  Add aac_get_channels and sample_rate function to get these value for
+	  AAC.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749110
+
+2016-03-24 13:33:02 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.8.0 ===
+
+2016-03-24 12:27:33 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.8.0
+
+2016-03-24 12:02:59 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2016-03-16 20:18:41 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/interleave/deinterleave.c:
+	  deinterleave: Use GstIterator for iterating all pads instead of manually iterating them while holding the object lock all the time
+	  Doing queries while holding the object lock is a bit dangerous, and in this
+	  case causes deadlocks.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763326
+
+2016-03-17 20:53:27 +0200  Vivia Nikolaidou <vivia@toolsonair.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Fix typo to not change the input caps but our filtered caps
+	  Changing the input caps and not using them anymore afterwards is useless, and
+	  it breaks negotiation in pipelines like:
+	  gst-launch-1.0 videotestsrc ! "video/x-raw,framerate=25/1,interlace-mode=interleaved" !
+	  deinterlace fields=all ! "video/x-raw,framerate=50/1,interlace-mode=progressive" !
+	  fakesink
+
+=== release 1.7.91 ===
+
+2016-03-15 12:04:39 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.7.91
+
+2016-03-15 11:53:37 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2016-03-15 11:41:22 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/hu.po:
+	* po/sr.po:
+	  po: Update translations
+
+2016-03-15 03:26:14 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/rtpsource.c:
+	  rtpmanager: Some comment and documentation clarifications/fixes
+
+2016-03-13 10:33:13 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  Revert "flacparse: push tags in pre_push_frame"
+	  This reverts commit 4065fcb80a49924b70f0c8fc159dec0ff47943a1.
+	  flacparse should not push tags by itself, the base class is going to do that
+	  while properly merging in upstream tags. It just didn't because of a bug in
+	  the base class, which was hidden by this commit.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763553
+
+2016-02-25 05:17:51 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* gst/rtp/dboolhuff.c:
+	* gst/rtp/dboolhuff.h:
+	* gst/rtp/gstrtpsbcpay.c:
+	  win32: Don't use __attribute__ on MSVC
+	  Use MSVC-equivalents for alignment and packing compiler directives when building
+	  on MSVC
+
+2016-02-25 05:16:42 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* gst/matroska/ebml-read.c:
+	  win32: Don't try to include xmath.h on newer Visual Studio
+
+2016-02-25 05:16:09 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* gst/flx/gstflxdec.c:
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/monoscope/gstmonoscope.c:
+	  gst Factor out endian-order RGB formats
+	  MSVC seems to ignore preprocessor conditionals inside static pad
+	  template macros.
+
+2016-03-08 17:37:17 +0100  Thomas Roos <thomas.roos@industronic.de>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  dirctsoundsink: Setting volume should not unmute
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755106
+
+2016-03-08 13:57:24 +0100  Thomas Roos <thomas.roos@industronic.de>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  dirctsoundsink: Fix volume reset on unmute
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755106
+
+2016-03-08 13:03:55 +0100  Alban Bedel <alban.bedel@avionic-design.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: fix capture with bayer formats other than bggr
+	  gst_v4l2_object_get_caps_info() always return V4L2_PIX_FMT_SBGGR8
+	  for all bayer formats. This is obviously broken if the device use
+	  another ordering. Fix this by properly reading the format parameter.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763318
+
+2016-03-07 10:28:06 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: reset pending segment if we are already pushing one
+	  When upstream is running in bytes in push-mode, qtdemux will
+	  convert seeks from time to bytes and send it upstream. Upstream
+	  element will perform a byte seek and send a byte segment to qtdemux
+	  that will convert it to time and push it downstream.
+	  There is, however, the pending_segment variable that stores a new
+	  segment event to be pushed before the next data. When handling seeks
+	  as mentioned above this variable was being ignored and, if it contained
+	  some segment event, it would override the one resulting from the seek.
+	  This would restore a previous segment and would cause the seek segment
+	  to be discarded downstream.
+	  This patch fixes this issue by unrefing any pending segment as the
+	  seek from upstream should contain the latest one that should be
+	  used, as requested by the application.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763165
+
+2016-03-07 10:27:41 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: run gst-indent
+	  Otherwise commits will fail with our indent check hook
+
+2016-03-04 15:09:45 +0100  Josep Torra <n770galaxy@gmail.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: fix colorimetry for NV12
+	  Replicate V4L2_MAP_QUANTIZATION_DEFAULT macro behavior.
+	  At #v4l it was described that documentation might be wrong and that
+	  we should trust this macro instead.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762529
+
+2016-03-04 14:07:19 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Fix multicast group joining with provided sockets on Windows
+	  On Windows the socket will be bound to ANY instead of the multicast group,
+	  as binding to a multicast group does not work. Which would mean that we
+	  override src->addr to become ANY and won't automatically join a multicast
+	  group anymore on Windows.
+	  On Linux we would automatically join a multicast group, keep it consistent.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=763093
+
+2016-03-02 13:13:24 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  Revert "rtpjitterbuffer: don't forget to unlock mutex in error code path in two cases"
+	  This reverts commit a7fb7b53592d87f7983544debb74d364fc3257ad.
+	  The mutex is taken by the caller, we should keep it locked when returning so
+	  the caller can unlock it again.
+
+2016-03-01 15:01:22 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: push tags in pre_push_frame
+	  Push a tag event before pre-roll if we have tags.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762660
+
+=== release 1.7.90 ===
+
+2016-03-01 18:15:43 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.7.90
+
+2016-03-01 17:03:59 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/ca.po:
+	* po/da.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/or.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/tr.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2016-03-01 16:53:27 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/bg.po:
+	* po/cs.po:
+	* po/de.po:
+	* po/fr.po:
+	* po/nl.po:
+	* po/pl.po:
+	* po/ru.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	  po: Update translations
+
+2016-03-01 14:14:02 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: don't forget to unlock mutex in error code path in two cases
+
+2016-02-29 10:10:24 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: remove impossible condition
+	  It is impossible for a guint to have a negative value, no need to check for
+	  this. Introduced in commit 6861d11c49ea0f30d2432cf4ebf6108bc89897f1
+	  CID 1354509
+
+2016-02-28 10:12:36 +0100  Petr Viktorin <encukou@gmail.com>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Fix sample pipeline
+	  Use the zorder pad property to make sure the semitransparent
+	  video is on top of the background.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762809
+
+2016-02-28 13:42:28 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/replaygain/gstrgvolume.c:
+	* tests/check/elements/rgvolume.c:
+	  rgvolume: make tag list writable before modifying it
+	  Making the event itself writable is not enough, it won't make
+	  the actual taglist in the event writable as well. Instead, just
+	  make a copy of the taglist and then create a new tag event from
+	  that if required, replacing the old one. Before we would
+	  inadvertently modify taglists upstream elements might still
+	  be holding on to. Add unit test for this as well.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762793
+
+2016-02-28 13:01:34 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Properly error out if binding the UDP sockets fails
+	  udpsrc is not returning us a socket in that case.
+
+2016-02-27 20:33:32 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/goom/gstgoom.c:
+	  goom: Use goom_set_resolution() instead of recreating the goom instance when the resolution changes
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762765
+
+2016-02-27 20:32:45 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/goom/gstgoom.c:
+	  Revert "goom: Initialize the goom struct only once we know width/height and recreate it if those change"
+	  This reverts commit cc6e102643c1bae928316dca9f34db028fb9a67e.
+
+2016-02-27 20:31:15 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/goom/gstgoom.c:
+	  goom: Initialize the goom struct only once we know width/height and recreate it if those change
+	  Fixes crash when the width and/or height is changing.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762765
+
+2016-02-26 12:41:07 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From b64f03f to 6f2d209
+
+2016-02-25 22:54:18 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	  docs: add rtpopusdepay and rtpopuspay to documentation
+
+2016-02-17 15:15:11 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpopusdepay.c:
+	* gst/rtp/gstrtpopusdepay.h:
+	* gst/rtp/gstrtpopuspay.c:
+	* gst/rtp/gstrtpopuspay.h:
+	  rtp: opus: move Opus RTP payloader/depayloader from -bad to -good
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756282
+
+2016-02-17 15:10:00 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	  Merge branch 'plugin-move-rtp-opus'
+	  Move Opus RTP depayloader/payloader from -bad to -good.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756282
+
+2016-02-25 11:33:13 +0100  Philippe Normand <philn@igalia.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: cenc aux info parsing from mdat support in PULL mode
+	  This is already supported for PUSH mode but was failing in PULL mode.
+	  The aux info is sometimes stored in the mdat before the first sample,
+	  so the loop task needs to pull data stored at that location and
+	  perform the aux info cenc parsing.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761700
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762516
+
+2016-02-24 11:28:09 +0100  Philippe Normand <philn@igalia.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: prevent buffer flow if any stream failed to be exposed
+	  In some cases the stream configuration can fail, for instance if the
+	  stream is protected and no decryptor was found. For those situations
+	  the demuxer shouldn't emit any data on the corresponding source pad of
+	  the stream and bail out.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762516
+
+2016-02-24 09:12:03 +0100  Philippe Normand <philn@igalia.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: don't push encrypted buffer without cenc metadata
+	  When the cenc metadata is stored outside of the moof box and the
+	  stream is exposed it is possible that the cenc metadata hasn't been
+	  processed yet while the first buffer is being pushed. When this
+	  happens the buffer can't possibly be decrypted downstream so don't
+	  push it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762516
+
+2015-10-21 16:21:45 +0200  Philippe Normand <philn@igalia.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: read saio aux_info_type as a FOURCC
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756897
+
+2016-02-23 18:27:47 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/dv/gstdvdec.c:
+	* ext/gdk_pixbuf/gstgdkpixbufdec.c:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/smpte/gstsmpte.c:
+	  gst: Handle gst_pad_get_current_caps() returning NULL gracefully
+
+2016-02-23 18:12:54 +0200  Dave Craig <dcraig@brightsign.biz>
+
+	* gst/rtp/gstrtph265depay.c:
+	  rtph265depay: Don't assume that get_current_caps() returns non-NULL caps after has_current_caps()
+	  Remove calls to gst_pad_has_current_caps() which then go on to call
+	  gst_pad_get_current_caps() as the caps can go to NULL in between. Instead just
+	  use gst_pad_get_current_caps() and check for NULL.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=759539
+
+2015-12-16 12:40:39 +0000  Dave Craig <dcraig@brightsign.biz>
+
+	* ext/flac/gstflacenc.c:
+	* gst/flv/gstflvmux.c:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/videocrop/gstaspectratiocrop.c:
+	  gst: Don't assume that get_current_caps() returns non-NULL caps after has_current_caps()
+	  Remove calls to gst_pad_has_current_caps() which then go on to call
+	  gst_pad_get_current_caps() as the caps can go to NULL in between. Instead just
+	  use gst_pad_get_current_caps() and check for NULL.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=759539
+
+2015-12-16 10:54:17 +0000  Dave Craig <dcraig@brightsign.biz>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Handle gst_pad_get_current_caps() returning NULL gracefully
+	  This can happen when the pipeline is currently shutting down.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=759539
+
+2016-02-23 15:57:18 +0100  Linus Svensson <linussn@axis.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: Don't handle seek until ready
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762542
+
+2016-02-23 15:55:13 +0100  Linus Svensson <linussn@axis.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: Unref seek event
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762542
+
+2016-02-22 11:01:40 +0100  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: close file on write error with next-file mode is set to buffer
+	  If we have an error during fwrite call, file stays open and thus next
+	  incoming buffer will trigger an assert when trying to opening a new
+	  file.
+	  This happens if we do not restart element, file is closed at stop, and
+	  if application handles the returned GST_FLOW_ERROR to keep bin alive.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762434
+
+2016-02-19 23:44:42 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: don't output empty tags/tag elements
+	  Such files will not play on Android, because of bug in libwebm matroska parsing, which is still present in 6.0.1
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762349
+
+2016-02-04 15:59:04 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: make up an OpusHead block if possible when missing
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761489
+
+2016-02-04 10:43:15 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroska-mux: make up an OpusHead block if possible when missing
+	  This block is needed in the Matroska file, but data coming from
+	  RTP may not have one.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761489
+
+2016-02-22 13:53:21 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: make stream-id more readable and order-friendly
+	  ... as streams are so ordered by id by e.g. decodebin
+	  (and as typically already honoured by other demuxers).
+
+2016-02-22 13:25:51 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.c:
+	  matroska: remove confusing duplicate track uid field
+
+2016-02-22 14:03:02 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/rtp/gstrtpvp9pay.c:
+	  rtpvp9pay: add missing break
+	  VP9_PAY_PICTURE_ID_7BITS and VP9_PAY_PICTURE_ID_15BITS are mutually
+	  exclusive options of the picture-id-mode. We can break after the
+	  first case.
+	  1 or 2 bytes need to be added to the header length depending on the
+	  PictureID size.
+	  https://tools.ietf.org/html/draft-uberti-payload-vp9-00#section-4.2
+	  CID 1353479
+
+2016-02-22 09:09:01 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Fix buffer memory leak
+	  buffer being mapped is not being unmapped in some cases
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762420
+
+2015-11-04 10:19:03 +0100  Stian Selnes <stian@pexip.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpmanager: Don't warn for duplicate/reordered packets
+	  This is a normal scenario and should not be a warning.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762208
+
+2016-02-21 09:47:43 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/alpha/alpha.vcproj:
+	* gst/auparse/auparse.vcproj:
+	* gst/avi/avi.vcproj:
+	* gst/cutter/cutter.vcproj:
+	* gst/debugutils/debug.vcproj:
+	* gst/debugutils/navigationtest.vcproj:
+	* gst/effectv/effectv.vcproj:
+	* gst/flx/flxdec.vcproj:
+	* gst/goom/goom.vcproj:
+	* gst/goom2k1/goom.vcproj:
+	* gst/interleave/interleave.vcproj:
+	* gst/isomp4/qtdemux.vcproj:
+	* gst/law/alaw.vcproj:
+	* gst/law/mulaw.vcproj:
+	* gst/matroska/matroska.vcproj:
+	* gst/multipart/multipart.vcproj:
+	* gst/rtp/rtp.vcproj:
+	* gst/smpte/smpte.vcproj:
+	* gst/spectrum/spectrum.vcproj:
+	* gst/udp/udp.vcproj:
+	* gst/videobox/videobox.vcproj:
+	* gst/videocrop/videocrop.vcproj:
+	* gst/videofilter/gamma.vcproj:
+	* gst/videofilter/videobalance.vcproj:
+	* gst/videofilter/videofilter.vcproj:
+	* gst/videofilter/videoflip.vcproj:
+	* gst/videomixer/videomixer.vcproj:
+	* gst/wavenc/wavenc.vcproj:
+	* gst/wavparse/wavparse.vcproj:
+	* gst/y4m/y4menc.vcproj:
+	* win32/MANIFEST:
+	* win32/vs6/autogen.dsp:
+	* win32/vs6/gst_plugins_good.dsw:
+	* win32/vs6/libgstalaw.dsp:
+	* win32/vs6/libgstalpha.dsp:
+	* win32/vs6/libgstalphacolor.dsp:
+	* win32/vs6/libgstapetag.dsp:
+	* win32/vs6/libgstaudiofx.dsp:
+	* win32/vs6/libgstauparse.dsp:
+	* win32/vs6/libgstautodetect.dsp:
+	* win32/vs6/libgstavi.dsp:
+	* win32/vs6/libgstcutter.dsp:
+	* win32/vs6/libgstdirectsound.dsp:
+	* win32/vs6/libgsteffectv.dsp:
+	* win32/vs6/libgstflx.dsp:
+	* win32/vs6/libgstgoom.dsp:
+	* win32/vs6/libgsticydemux.dsp:
+	* win32/vs6/libgstid3demux.dsp:
+	* win32/vs6/libgstinterleave.dsp:
+	* win32/vs6/libgstjpeg.dsp:
+	* win32/vs6/libgstlevel.dsp:
+	* win32/vs6/libgstmatroska.dsp:
+	* win32/vs6/libgstmedian.dsp:
+	* win32/vs6/libgstmonoscope.dsp:
+	* win32/vs6/libgstmulaw.dsp:
+	* win32/vs6/libgstmultipart.dsp:
+	* win32/vs6/libgstpng.dsp:
+	* win32/vs6/libgstqtdemux.dsp:
+	* win32/vs6/libgstrtp.dsp:
+	* win32/vs6/libgstrtsp.dsp:
+	* win32/vs6/libgstsmpte.dsp:
+	* win32/vs6/libgstspeex.dsp:
+	* win32/vs6/libgstudp.dsp:
+	* win32/vs6/libgstvideobalance.dsp:
+	* win32/vs6/libgstvideobox.dsp:
+	* win32/vs6/libgstvideocrop.dsp:
+	* win32/vs6/libgstvideoflip.dsp:
+	* win32/vs6/libgstvideomixer.dsp:
+	* win32/vs6/libgstwaveform.dsp:
+	* win32/vs6/libgstwavenc.dsp:
+	* win32/vs6/libgstwavparse.dsp:
+	* win32/vs7/libgstdirectsound.vcproj:
+	* win32/vs8/gst-plugins-good.sln:
+	* win32/vs8/libgst1394.vcproj:
+	* win32/vs8/libgstaasink.vcproj:
+	* win32/vs8/libgstalaw.vcproj:
+	* win32/vs8/libgstalpha.vcproj:
+	* win32/vs8/libgstalphacolor.vcproj:
+	* win32/vs8/libgstannodex.vcproj:
+	* win32/vs8/libgstapetag.vcproj:
+	* win32/vs8/libgstaudiofx.vcproj:
+	* win32/vs8/libgstauparse.vcproj:
+	* win32/vs8/libgstautodetect.vcproj:
+	* win32/vs8/libgstavi.vcproj:
+	* win32/vs8/libgstcacasink.vcproj:
+	* win32/vs8/libgstcdio.vcproj:
+	* win32/vs8/libgstcutter.vcproj:
+	* win32/vs8/libgstdirectsound.vcproj:
+	* win32/vs8/libgstdv.vcproj:
+	* win32/vs8/libgsteffectv.vcproj:
+	* win32/vs8/libgstflac.vcproj:
+	* win32/vs8/libgstflxdec.vcproj:
+	* win32/vs8/libgstgoom.vcproj:
+	* win32/vs8/libgsticydemux.vcproj:
+	* win32/vs8/libgstid3demux.vcproj:
+	* win32/vs8/libgstjpeg.vcproj:
+	* win32/vs8/libgstladspa.vcproj:
+	* win32/vs8/libgstlevel.vcproj:
+	* win32/vs8/libgstmatroska.vcproj:
+	* win32/vs8/libgstmng.vcproj:
+	* win32/vs8/libgstmonoscope.vcproj:
+	* win32/vs8/libgstmulaw.vcproj:
+	* win32/vs8/libgstmultipart.vcproj:
+	* win32/vs8/libgstpng.vcproj:
+	* win32/vs8/libgstrtp.vcproj:
+	* win32/vs8/libgstrtsp.vcproj:
+	* win32/vs8/libgstshout2.vcproj:
+	* win32/vs8/libgstsmpte.vcproj:
+	* win32/vs8/libgstspeex.vcproj:
+	* win32/vs8/libgsttaglib.vcproj:
+	* win32/vs8/libgstudp.vcproj:
+	* win32/vs8/libgstvideobalance.vcproj:
+	* win32/vs8/libgstvideobox.vcproj:
+	* win32/vs8/libgstvideoflip.vcproj:
+	* win32/vs8/libgstvideomixer.vcproj:
+	* win32/vs8/libgstwavenc.vcproj:
+	* win32/vs8/libgstwavparse.vcproj:
+	  win32: remove outdated build cruft
+	  This hasn't been touched for generations, doesn't work,
+	  and is just causing confusion. We also don't want to
+	  maintain these files manually.
+
+2016-02-20 11:51:56 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: don't use undeclared core debug category symbols
+
+2016-02-06 14:39:05 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: workaround for files with wrong color_table_id value
+	  Instead of erroring out, just use the default color table.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761637
+
+2016-02-19 15:02:04 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/flv/gstflvmux.c:
+	* gst/rtp/gstrtpvp9depay.c:
+	  flvmux, rtpvp9depay: fix indentation
+
+2016-02-19 15:03:04 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2src: fix indentation
+
+2015-12-04 00:46:34 +1100  Havard Graff <havard.graff@gmail.com>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: plug leak(s) in error-scenario
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762210
+
+2015-12-04 00:46:12 +1100  Havard Graff <havard.graff@gmail.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: fix eos event leak
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762209
+
+2016-02-19 14:41:07 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/flvdemux.c:
+	* tests/check/elements/flvmux.c:
+	* tests/check/elements/rtph263.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: fix indentation
+
+2016-02-18 16:09:29 +0100  Havard Graff <havard.graff@gmail.com>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: rtpjitterbuffer: port testharness to GstHarness and cleanup/improve
+	  Probably found a bug as well, in that there are some timestamps in
+	  there that are looking very wrong. (marked with FIXME)
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762267
+
+2016-02-18 10:27:19 +0100  Havard Graff <havard.graff@gmail.com>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: rtpjitterbuffer: test cleanups/improvements
+	  Use fail_unless and friends instead of g_assert
+	  Factor seq-num checking out to separate function
+	  Check more return-values from push and crank and others
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762254
+
+2015-12-03 11:07:05 +0100  Stian Selnes <stian@pexip.com>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: rtpjitterbuffer: fix leaks in unit test
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762214
+
+2016-02-19 12:38:28 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.7.2 ===
+
+2016-02-19 11:49:55 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.7.2
+
+2016-02-19 10:31:48 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: Update translations
+
+2016-02-18 18:33:13 +0100  Philippe Normand <philn@igalia.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: plug leaks in cenc aux info parsing
+
+2016-02-18 13:43:07 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/Makefile.am:
+	  tests: fix spurious souphttpsrc test timouts
+	  Set GSETTINGS_BACKEND=memory, apparently there's something
+	  about fork() and the dconf backend (or whatever else that
+	  drags in or activates) that messes up locking and causes
+	  timeouts due to deadlocks in g_mutex_lock(), since
+	  everything works fine with CK_FORK=no as well.
+
+2016-02-18 11:10:14 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Unmap wavpack header buffer after creating it
+	  Otherwise it will be mapped writable all the time and we can't read from it
+	  anywhere.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762239
+
+2015-12-08 18:49:40 +0100  Stian Selnes <stian@pexip.com>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Add test for big seqnum gap handling
+	  Make sure that the packets queued when detecting a big gap are pushed
+	  after reset (5 consective seqnums) and not dropped.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762211
+
+2016-02-17 15:03:13 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtputils.h:
+	  rtp: sprinkle some G_GNUC_INTERNAL for internal utils functions
+
+2016-02-09 13:17:00 +0000  Alex Ashley <bugzilla@ashley-family.net>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: only transform protected caps once
+	  Commit 7873bede3134b15e5066e8d14e54d1f5054d2063
+	  (https://bugzilla.gnome.org/show_bug.cgi?id=760774) changed the
+	  behaviour of qtdemux to call gst_qtdemux_configure_stream() for
+	  every new moof.
+	  When playing a protected stream, gst_qtdemux_configure_stream()
+	  calls gst_qtdemux_configure_protected_caps(). The
+	  gst_qtdemux_configure_protected_caps() function takes the original
+	  media format, puts this in a field called "original-media-type"
+	  and then changes the caps to "application/x-cenc".
+	  The gst_qtdemux_configure_protected_caps() did not handle the case
+	  of being called multiple times, causing it to incorrectly set the
+	  caps. The second call was causing the caps to be set to:
+	  application/x-cenc, original-media-type"application/x-cenc"
+	  This commit makes gst_qtdemux_configure_protected_caps() check that
+	  the caps have already been transformed, so that it only gets
+	  changed once.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761769
+
+2015-11-03 14:50:53 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpopusdepay.c:
+	* gst/rtp/gstrtpopuspay.c:
+	  opus: Add proper support for multichannel audio
+	  https://bugzilla.gnome.org/show_bug.cgi?id=757152
+
+2015-06-30 13:51:33 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpopusdepay.c:
+	* gst/rtp/gstrtpopuspay.c:
+	  opus: Copy metadata in the (de)payloader, but only the relevant ones
+	  The payloader didn't copy anything so far, the depayloader copied every
+	  possible meta. Let's make it consistent and just copy all metas without tags or
+	  with only the audio tag.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751774
+
+2015-05-04 11:23:16 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpopusdepay.c:
+	  opusdepay: Set multistream=FALSE on the Opus caps
+	  The RTP Opus mapping only allows mono/stereo, and not multistream Opus
+	  streams.
+
+2015-03-24 13:57:54 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpopuspay.c:
+	  rtpopuspay: Forward stereo preferences from caps upstream
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746617
+
+2015-03-24 13:56:21 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpopuspay.c:
+	  rtpopuspay: Set the number of channels to 2 as per RFC draft
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746617
+
+2015-03-23 12:24:55 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpopusdepay.c:
+	* gst/rtp/gstrtpopuspay.c:
+	  opus: Handle sprop-stereo and sprop-maxcapturerate RTP caps fields
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746617
+
+2015-02-19 14:30:10 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtpopuspay.c:
+	  rtpopuspay: default encoding name to OPUS
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737810
+
+2015-02-19 14:05:06 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtpopuspay.c:
+	  rtpopuspay: make caps writable before truncating them
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737810
+
+2015-02-05 10:27:51 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtpopuspay.c:
+	  rtpopuspay: negotiate the encoding name
+	  Chrome uses a different encoding name that gstreamer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737810
+
+2014-11-01 10:10:27 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/rtp/gstrtpopusdepay.c:
+	* gst/rtp/gstrtpopuspay.c:
+	  rtpopus: Use OPUS encoding name
+	  Both Firefox and Chrome uses OPUS as the encoding in their SDP.
+	  Adding this now defacto standard name remove the need for special
+	  case in SDP parsing code.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737810
+
+2013-01-31 12:30:49 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpopuspay.c:
+	  opuspay: fix timestamps
+	  Copy timestamps to payloaded buffer.
+	  Avoid input buffer memory leak.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=692929
+
+2012-11-03 20:38:00 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/rtp/gstrtpopusdepay.c:
+	* gst/rtp/gstrtpopusdepay.h:
+	* gst/rtp/gstrtpopuspay.c:
+	* gst/rtp/gstrtpopuspay.h:
+	  Fix FSF address
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687520
+
+2012-10-22 12:08:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpopuspay.c:
+	  opuspay: remove pointless caps serialization
+	  Remove the caps serialization in the rtp caps. the spec nor the receiver
+	  does anything with it.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=686547
+
+2012-10-17 17:34:26 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtpopusdepay.c:
+	* gst/rtp/gstrtpopuspay.c:
+	  Use gst_element_class_set_static_metadata()
+	  where possible. Avoids some string copies. Also re-indent
+	  some stuff. Also some indent fixes here and there.
+
+2012-09-20 18:41:24 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpopuspay.c:
+	  rtpopuspay: Allocate the rtp buffer correctly
+	  Use the right functions to allocate the rtp buffer
+
+2012-09-14 17:08:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpopusdepay.c:
+	* gst/rtp/gstrtpopuspay.c:
+	  replace gst_element_class_set_details_simple with gst_element_class_set_metadata
+
+2012-03-07 17:14:29 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpopuspay.c:
+	  opus: port to updated 0.11
+
+2011-12-30 11:41:17 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/rtp/gstrtpopusdepay.c:
+	* gst/rtp/gstrtpopusdepay.h:
+	* gst/rtp/gstrtpopuspay.c:
+	* gst/rtp/gstrtpopuspay.h:
+	  Merge remote-tracking branch 'origin/master' into 0.11-premerge
+	  Conflicts:
+	  docs/libs/Makefile.am
+	  ext/kate/gstkatetiger.c
+	  ext/opus/gstopusdec.c
+	  ext/xvid/gstxvidenc.c
+	  gst-libs/gst/basecamerabinsrc/Makefile.am
+	  gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.c
+	  gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.h
+	  gst-libs/gst/video/gstbasevideocodec.c
+	  gst-libs/gst/video/gstbasevideocodec.h
+	  gst-libs/gst/video/gstbasevideodecoder.c
+	  gst-libs/gst/video/gstbasevideoencoder.c
+	  gst/asfmux/gstasfmux.c
+	  gst/audiovisualizers/gstwavescope.c
+	  gst/camerabin2/gstcamerabin2.c
+	  gst/debugutils/gstcompare.c
+	  gst/frei0r/gstfrei0rmixer.c
+	  gst/mpegpsmux/mpegpsmux.c
+	  gst/mpegtsmux/mpegtsmux.c
+	  gst/mxf/mxfmux.c
+	  gst/videomeasure/gstvideomeasure_ssim.c
+	  gst/videoparsers/gsth264parse.c
+	  gst/videoparsers/gstmpeg4videoparse.c
+
+2011-12-09 17:25:41 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtpopuspay.c:
+	  opusenc: add upstream negotiation for multistream ability
+	  This will help elements that cannot deal with multistream,
+	  such as the RTP payloader.
+	  The caps now do not include a "streams" field anymore, but
+	  a "multistream" boolean, since we have no real use for knowing
+	  the exact amount of streams.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=665078
+
+2011-12-07 15:13:11 -0200  Danilo Cesar Lemes de Paula <danilo.cesar@collabora.co.uk>
+
+	* gst/rtp/gstrtpopusdepay.c:
+	* gst/rtp/gstrtpopusdepay.h:
+	* gst/rtp/gstrtpopuspay.c:
+	* gst/rtp/gstrtpopuspay.h:
+	  Adding opus RTP payloader/depayloader element
+	  Adding OPUS RTP module based on the current draft:
+	  http://tools.ietf.org/id/draft-spittka-payload-rtp-opus-00.txt
+	  https://bugzilla.gnome.org/show_bug.cgi?id=664817
+
+2016-02-17 13:26:02 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph265depay.c:
+	* gst/rtp/gstrtputils.c:
+	* gst/rtp/gstrtputils.h:
+	  rtp: h264/h265: avoid duplication of read_golomb()
+	  There is no need to have two identical implementations of the read_golomb
+	  function.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761606
+
+2016-02-17 14:37:44 +0100  Ognyan Tonchev <ognyan@axis.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Simple implementation of TRICKMODE_KEY_UNITS
+	  When the trickmode key-units flag is set on the segment, simply skip
+	  any sample on a video stream that isn't a keyframe
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762185
+
+2015-08-21 14:15:18 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: send GAP events for lagging audio and video streams too
+	  Send GAP events for non-subtitle streams too if they lag too much
+	  behind, but use a higher threshold than for subtitles.
+	  This helps with fixing prerolling with a file where one of the
+	  audio streams only has data starting from 19s onwards. It's not
+	  a complete fix yet, it also requires changes elsewhere, such as
+	  in baseparse, to make sure caps are propagated.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=614460
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753899
+
+2015-12-23 19:54:13 +0100  Stian Selnes <stian@pexip.com>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpvp9depay.c:
+	* gst/rtp/gstrtpvp9depay.h:
+	* gst/rtp/gstrtpvp9pay.c:
+	* gst/rtp/gstrtpvp9pay.h:
+	  rtpvp9pay: rtpvp9depay: Initial implementation of draft 01
+	  Quick and dirty implementation of an RTP payloader and depayloader
+	  for VP9. In particalur it assumes no spatial or temporal layering,
+	  non-flexible mode, and some other bits and pieces.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754773
+
+2016-02-16 09:02:30 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Fix string memory leak
+	  codec_name is not being freed in all conditions leading to memory leak
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762117
+
+2015-12-10 12:15:52 +0100  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: add "get-session" signal
+	  This gets the GstRTPSession element, as compared to the RTPSession object
+	  that is returned by get-internal-session.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=759293
+
+2016-02-16 00:19:00 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	  rtp: h265: hook up move RTP H.265 payloader/depayloader to build
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761606
+
+2016-02-16 00:14:27 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	* gst/rtp/gstrtph265depay.h:
+	* gst/rtp/gstrtph265pay.c:
+	  rtp: h265: use common meta utility functions
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761606
+
+2016-02-05 18:18:31 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtph265depay.h:
+	* gst/rtp/gstrtph265pay.h:
+	* gst/rtp/gstrtph265types.h:
+	  rtp: h265: remove codecparser dependency from h265 payloader/depayloader
+	  Looks like it just uses the NAL enums and nothing else from
+	  the codecparsers, and that's the only reason it had to be
+	  moved from -good to -bad when it was originally added. We
+	  can probably keep those NAL enums up to date enough, so let's
+	  remove the codecparser dependency so it can be moved back into
+	  -good.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761606
+
+2016-02-16 00:24:58 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	  Merge branch 'plugin-move-rtp-h265'
+	  Move RTP H.265 payloader/depayloader from -bad to -good.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761606
+
+2016-02-05 15:34:51 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	* gst/rtp/gstrtph265depay.h:
+	  gstrtph265depay: keep consistency with rtph264depay
+	  Use gst_rtp_drop_meta() and the same function prototype for
+	  gst_rtp_copy_meta() to keep consistency with the RTP elements in
+	  gst-plugins-good
+
+2016-02-05 13:56:34 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	  rtph265depay: fix termination of access unit
+	  Only consider the access unit complete when the next-occurring VCL NAL unit
+	  has the first bit after its NAL unit header equal to 1.
+
+2016-01-15 16:10:02 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	  rtph265depay: fix unneeded sub-buffer creation
+	  We create a sub-buffer just to copy over its metas and then throw it
+	  away immediately, just use the original input buffer directly.
+
+2016-01-15 15:56:59 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/rtp/gstrtph265pay.c:
+	  rtph265pay: add "send VPS/SPS/PPS with every key frame" mode
+	  It's not enough to have timeout or event based VPS/SPS/PPS information
+	  sent in RTP packets. There are some scenarios when key frames may appear
+	  more frequently than once a second, in which case the minimum timeout
+	  for "config-interval" of 1 second for sending VPS/SPS/PPS isn't enough.
+	  It might also be desirable in general to make sure the VPS/SPS/PPS is
+	  available with every keyframe (packet loss aside), so receivers can
+	  actually pick up decoding immediately from the first keyframe if
+	  VPS/SPS/PPS is not signaled out of band.
+	  This commit adds the possibility to send VPS/SPS/PPS with every key frame.
+	  This mode can be enabled by setting "config-interval" property to -1. In
+	  this case the payloader will add VPS, SPS and PPS before every key (IDR)
+	  frame.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=757892
+
+2016-01-15 15:19:41 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/rtp/gstrtph265pay.c:
+	* gst/rtp/gstrtph265pay.h:
+	  rtph265pay: change config-interval property type from uint to int
+	  This way we can use -1 as special value, which is nicer than MAXUINT.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=757892
+
+2015-08-15 16:22:20 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	  rtph265depay: make sure we call handle_nal for each NAL
+	  Call handle_nal for each NAL in the STAP-A RTP packet. This makes sure
+	  we correctly extract the SPS and PPS.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730999
+
+2015-08-15 14:45:34 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtph265pay.c:
+	  rtph265pay: Copy metadata in the payloader, but only the relevant ones
+	  The payloader didn't copy anything so far, the depayloader copied every
+	  possible meta. Let's make it consistent and just copy all metas without
+	  tags or with only the video tag.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751774
+
+2015-08-15 11:41:40 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtph265pay.c:
+	  rtph265pay: Use GST_WARNING_OBJECT() instead of GST_WARNING()
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753228
+
+2015-08-15 11:30:36 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtph265pay.c:
+	  rtph265pay: fix potential crash when shutting down
+	  A race condition in the state change function may cause buffers to be
+	  unreffed while they are still used by the streaming thread in
+	  gst_rtp_h265_pay_send_vps_sps_pps() resulting in a crash. Chain up to the
+	  parent class first in the state change function to make sure streaming
+	  has stopped and only then free those buffers.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=741381
+
+2015-08-14 15:08:08 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtph265pay.c:
+	  rtph265pay: fix buffer leak when using SPS/PPS
+	  Fixes a buffer leak that would occur if the pipeline was shutdown while a
+	  SPS/PPS header was being created.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=741271
+
+2015-08-14 11:49:51 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	* gst/rtp/gstrtph265depay.h:
+	  rtph265depay: copy metadata in the depayloader, but only the relevant ones
+	  The payloader didn't copy anything so far, the depayloader copied every
+	  possible meta. Let's make it consistent and just copy all metas without
+	  tags or with only the video tag.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751774
+
+2015-08-12 17:54:52 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	  rtph265depay: checking if depay has sps/pps nals before insertion
+	  Related to: https://bugzilla.gnome.org/show_bug.cgi?id=753430
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753228
+
+2015-08-12 17:22:42 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	  rtph265depay: only update the srcpad caps if something else than the codec_data changed
+	  h264parse and gstrtph264depay do the same, let's keep the behaviour
+	  consistent. As we now include the codec_data inside the stream, this causes
+	  less caps renegotiation.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753228
+
+2015-08-12 16:43:48 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	  rtph265depay: PPS replaces old PPS if it has the same id
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753228
+
+2015-08-12 16:11:00 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	  rtph265depay: Insert SPS/PPS NALs into the stream
+	  rtph264depay does the same and this fixes decoding of some streams with 32
+	  SPS (or 256 PPS). It is allowed to have SPS ID 0 to 31 (or PPS ID 0 to 255),
+	  but the field in the codec_data for the number of SPS or PPS is only 5
+	  (or 8) bit. As such, 32 SPS (or 256 PPS) are interpreted as 0 everywhere.
+	  This looks like a mistake in the part of the spect about the codec_data.
+
+2015-08-12 15:49:50 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	  rtph265depay: implement process_rtp_packet() vfunc
+	  For more optimised RTP packet handling: means we don't need to map the
+	  input buffer again but can just re-use the mapping the base class has
+	  already done.
+	  Based on: https://bugzilla.gnome.org/show_bug.cgi?id=750235
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753228
+
+2015-08-12 15:14:50 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	  rtph265depay: Use GST_BUFFER_PTS() instead of GST_BUFFER_TIMESTAMP()
+	  Switching to GST_BUFFER_TIMESTAMP() to be consistent with other rtp code.
+
+2015-08-12 14:59:53 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	  rtph265depay: prevent trying to get 0 bytes from adapter
+	  This causes an assertion and would lead to getting a NULL instead
+	  of a buffer. Without proper checking this would easily lead to a
+	  segfault.
+	  Related to rpth264depay: https://bugzilla.gnome.org/show_bug.cgi?id=737199
+
+2015-07-29 17:29:28 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtph265pay.c:
+	  rtp: remove dead assignment
+	  Value set to ret will be overwritten at least once at the end of the while
+	  loop, removing assignment.
+
+2015-04-24 16:48:23 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/rtp/gstrtph265pay.c:
+	  remove unused enum items PROP_LAST
+	  This were probably added to the enums due to cargo cult programming and are
+	  unused.
+
+2015-03-06 14:54:41 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	  rtp: donl_present variable unused
+	  donl_present is not implemented, yet the value is set and checked a few times.
+	  Cleaning this.
+	  CID #1249687
+
+2015-01-08 15:36:04 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/rtp/gstrtph265pay.c:
+	  rtp: value truncated too short creates dead code
+	  type is truncated to 0-31 with "& 0x1f", but right after that it is checks if
+	  the value is equivalent to GST_H265_NAL_VPS, GST_H265_NAL_SPS, and
+	  GST_H265_NAL_PPS (which are 32, 33, and 34 respectively). Obviously, this will
+	  never be True if the value is maximum 31 after the truncation.
+	  The intention of the code was to truncate to 0-63.
+
+2015-01-08 15:27:44 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	  rtp: fix nal unit type check
+	  After further investigation the previous commit is wrong. The code intended to
+	  check if the type is 39 or the ranges 41-44 and 48-55. Just like gsth265parse.c
+	  does. Type 40 would not be complete.
+
+2015-01-08 13:47:09 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	  rtp: fix dead code and check for impossible values
+	  nal_type is the index for a GstH265NalUnitType enum. There are two types of dead
+	  code here:
+	  First, after checking if nal_type is >= 39 there are two OR conditionals that
+	  check if the value is in ranges higher than that number, so if nal_type >= 39
+	  falls in the True branch those other conditions aren't checked and if it falls
+	  in the False branch and they are checked, they will always also be False. They
+	  are redundant.
+	  Second, the enum has a range of 0 to 40. So the checks for ranges higher than 41
+	  should never be True.
+	  Removing this redundant checks.
+	  CID 1249684
+
+2014-10-16 10:34:01 +0200  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/rtp/gstrtph265depay.c:
+	* gst/rtp/gstrtph265depay.h:
+	* gst/rtp/gstrtph265pay.c:
+	* gst/rtp/gstrtph265pay.h:
+	  rtp: add h265 RTP payloader + depayloader
+
+2016-02-15 11:51:46 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* tests/check/elements/rtpmux.c:
+	  tests: rtpmux: Fix element memory leak
+	  https://bugzilla.gnome.org/show_bug.cgi?id=762057
+
+2016-02-12 20:57:29 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/monoscope/monoscope.c:
+	  monoscope: rework the scaling code
+	  The running average was wrong and the resulting scaling factor was only held in
+	  place using the CLAMP. In addtion we are now convering quickly to volume
+	  changes.
+	  FInally now with this change, we can change the resolution defines and
+	  everythign adjusts.
+
+2016-01-28 17:00:55 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/monoscope/convolve.c:
+	* gst/monoscope/monoscope.c:
+	* gst/monoscope/monoscope.h:
+	  monoscope: use constants in the drawing code
+	  Make all the drawing ops be based on the constants. This way we can change
+	  the fixed size at least at compile time.
+
+2016-01-28 09:51:17 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/monoscope/gstmonoscope.c:
+	  monoscope: replace hardcoded values by constants
+	  This at least establishes the relationship.
+
+2016-01-28 09:43:12 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/monoscope/convolve.c:
+	* gst/monoscope/convolve.h:
+	* gst/monoscope/monoscope.c:
+	* gst/monoscope/monoscope.h:
+	  monoscpe: make the convolver use dynamic memory
+	  Replace all #defines with members and initialize the convolver with a parameter.
+
+2016-01-28 08:56:44 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/monoscope/README:
+	  monoscope: update README
+	  We can already create multiple instances.
+
+2016-01-28 08:53:35 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/monoscope/convolve.c:
+	* gst/monoscope/monoscope.c:
+	  monoscope: code cleanup
+	  Use constants more often. Cleanup comments and add more to explain how things
+	  work.
+
+2016-02-08 23:41:32 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: remove check for impossible condition
+	  Commit bd27a1f30b4458f2edee53c76dd07fb35904b61d added a few error handling
+	  memory management checks. These check srccaps to see if it needs to be
+	  unreferenced before returning, in the case of invalid_caps this goto jump
+	  always happens before srccaps is set, so it will always be NULL in this
+	  error label.
+	  CID #1352035
+
+2016-02-08 12:48:46 +0100  Piotr Drąg <piotrdrag@gmail.com>
+
+	* po/POTFILES.in:
+	  po: update POTFILES
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761705
+
+2016-02-08 15:31:55 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Fix spelling of reenqueueing
+	  To match commit 7d7074cef0272cd5155098bfc2bda6849dd89267. I love the idea
+	  of aiming for the maximum number of consecutive vowels.
+
+2016-02-08 10:17:49 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Fix spelling of queueing
+	  Didn't know which one to choose between queuing and queueing, so I picked
+	  the one with the biggest amount of vowels in a row ;-P (both are
+	  acceptable apparently)
+
+2016-02-07 15:02:35 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Don't pass the same data over and over
+	  We already pass the entire frame to the decoder. If the decoder ask for
+	  more data, don't pass the same data again as this leads to infinit loop.
+	  Instead, simply fail the fill function to signal the problem with that
+	  frame. It will then be skipped properly.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761670
+
+2016-02-08 00:10:33 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/matroska/lzo.c:
+	  matroska: get rid of _stdint.h include
+
+2016-02-05 20:00:57 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/Makefile.am:
+	  tests: extend the AM_TESTS_ENVIRONMENT from check.mak
+	  To get the CK_DEFAULT_TIMEOUT defined for all tests
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761472
+
+2016-02-05 18:04:31 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* autogen.sh:
+	* common:
+	  Automatic update of common submodule
+	  From 86e4663 to b64f03f
+
+2016-01-30 18:43:30 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: Skip APP and JPG markers and print warnings for unknown markers
+	  For APP/JPG markers the size is following and we have to skip that. This is
+	  not really a problem unless the marker contains e.g. a preview JPEG or
+	  something else that we might interprete as another marker.
+
+2016-01-26 22:37:30 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix framerate calculation for fragmented format
+	  qtdemux calculates framerate using duration and the number of sample.
+	  In case of fragmented mp4 format, however, the number of sample can
+	  be figure out after parsing every moof box. Because qtdemux does not
+	  parse every moof in QTDEMUX_STATE_HEADER state, it will cause incorrect
+	  framerate calculation.
+	  This patch will triger gst_qtdemux_configure_stream() for every new moof.
+	  Then, framerate will be calculated by using duration and n_samples of the moof.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=760774
+
+2016-01-28 22:36:23 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: handling zero segment-duration edit list
+	  Based on document ISO_IEC_14496-12, edit list box can have
+	  segment duration as zero. It does not imply that media_start equals to
+	  media_stop. But, it just indicates a sample which should be presented
+	  at the first. This patch derives segment duration using media_time
+	  and duration of file. And set derived duration to segment-duration.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=760781
+
+2016-01-28 21:36:54 +0900  Seungha Yang <sh.yang@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: expose streams with first moof for fragmented format
+	  In case of push mode, qtdemux expose streams after got moov box.
+	  We can not guarantee that a moov box has sample data such as sample duration
+	  and the number of sample in stbl box for fragmented format case.
+	  So, if a moov has no sample data, streams will not be exposed until get the first moof.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=760779
+
+2016-01-27 18:48:17 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Check for subset instead of non-empty intersection for ACCEPT_CAPS
+
+2016-01-27 18:44:23 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Unset RECONFIGURE flag on srcpad whenever we configure new caps
+	  Prevents double-negotiation during startup and in some other cases.
+
+2016-01-27 16:43:22 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/deinterlace.c:
+	  deinterlace: Add negotiation unit tests for all 4 modes
+	  These now check the output caps based on the input caps and a following
+	  capsfilter and make sure the caps are exactly as expected.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=760995
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720388
+
+2016-01-26 17:39:20 +0100  Vivia Nikolaidou <vivia@toolsonair.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Do passthrough in auto mode if downstream only supports interlaced
+	  If the following conditions are met:
+	  1) upstream and downstream caps are compatible
+	  2) upstream is interlaced
+	  3) downstream doesn't support progressive mode
+	  then deinterlace will just do passthrough instead of failing to link.
+	  This is done with the following scenario in mind:
+	  videotestsrc ! "video/x-raw,interlace-mode=interleaved" ! deinterlace
+	  name=dein_src ! tee name=t ! queue ! deinterlace name=dein_file ! filesink t. !
+	  queue ! deinterlace name=dein_desktop ! autovideosink
+	  In this case, dein_src will do the deinterlacing. However,
+	  videotestsrc ! "video/x-raw,interlace-mode=interleaved" ! deinterlace
+	  name=dein_src ! tee name=t ! queue ! deinterlace name=dein_file ! filesink t. !
+	  queue ! deinterlace name=dein_desktop ! autovideosink t. ! queue !
+	  "video/x-raw,interlace-mode=interleaved" ! fakesink
+	  In this case, caps auto-negotiation will make dein_file and dein_desktop do
+	  the deinterlacing, while dein_src will be passthrough.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=760995
+
+2016-01-26 18:05:51 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  deinterlace: Add mode=auto-strict
+	  In this mode we will passthrough all progressive caps but interlaced caps must be
+	  caps where we actually support deinterlacing.
+	  This is the only difference between auto and auto-strict, auto would
+	  passthrough all unsupported interlaced caps.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720388
+
+2016-01-26 17:50:30 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Implement reconfiguration a bit better
+	  And e.g. consider reconfiguration caused by RECONFIGURE events too.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720388
+
+2016-01-26 11:57:09 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Rewrite caps negotiation
+	  Previously the result of the CAPS query and ACCEPT_CAPS depended on what kind
+	  of caps were last set, and e.g. if we last had interlaced caps or not. That's
+	  just broken.
+	  Also previously the handling of non-sysmem caps features was rather random and
+	  unusuable.
+	  Now the behaviour is the following, depending on the mode property:
+	  1) mode=disabled
+	  Completely do passthrough of everything
+	  2) mode=interlaced
+	  Only accept formats we can actually deinterlace, and accept interlaced
+	  and progressive content and always run the deinterlacer and output
+	  progressive content
+	  3) mode=auto (i.e. playbin)
+	  Accept all progressive formats as passthrough, accept all formats that we
+	  can deinterlace ourselves (which we do then), but also accept everything
+	  else for which we then just passthrough. In auto mode, deinterlacing is best
+	  effort: If we can, we deinterlace, if we can't we just output interlaced
+	  content.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720388
+	  https://bugzilla.gnome.org/show_bug.cgi?id=760553
+
+2016-01-26 11:34:40 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Remove unused, obsolete bufferalloc code
+
+2016-01-26 18:50:38 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: use A_AAC instead of A_AAC/MPEGx/y
+	  Some GoogleCast compatible devices ignore A_AAC/MPEGx/y tracks; Also according to http://wiki.multimedia.cx/index.php?title=Matroska A_AAC/MPEGx/y is obsolete
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761144
+
+2016-01-25 17:21:24 +0100  Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/rtp/gstrtph261pay.c:
+	  gst: Fix unintialized variable warnings
+	  While cross-compiling with Linaro GCC 5.1-2015.08, it complained
+	  about a couple unitialized variables.
+	  This patch initializes them to zero.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=761094
+
+2016-01-25 15:03:23 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	  splitmuxsrc: print potentially negative offset with a sign
+
+2016-01-21 17:41:55 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Re-add colorimetry field for RGB formats
+	  This time, check if it's an RGB format and sets the transformation
+	  matrix to identity. The rest of the colorimetry information is
+	  meaningfull and shall be kept.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=759624
+
+2016-01-22 10:03:50 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: fix sRGB colorspace definition
+	  V4l2 can also use the sRGB colorspace for YUV formats and thus needs a
+	  default matrix.
+
+2016-01-21 15:29:46 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/debugutils/gsttaginject.c:
+	  taginject: fix sample pipeline in docs
+	  https://bugzilla.gnome.org/show_bug.cgi?id=679571
+
+2016-01-21 10:49:44 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Add adobe colorspace support
+	  Use the new primaries and transfer function for Adobe RGB.
+	  Explicitly list the colorimetry instead of using the default GStreamer
+	  ones. The defaults for BT2020, for example, do not match.
+	  Explicitly set the matrix of SRGB to RGB.
+
+2016-01-20 13:41:33 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: Ensure that we always have valid frame user data before using it
+	  Otherwise we're going to dereference NULL pointers.
+
+2016-01-20 10:02:48 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/vpx/gstvpxdec.c:
+	  vpxdec: Unref frame in all code paths of handle_frame()
+	  https://bugzilla.gnome.org/show_bug.cgi?id=760666
+
+2016-01-19 22:49:20 +0100  Thibault Saunier <tsaunier@gnome.org>
+
+	* ext/vpx/gstvpxenc.c:
+	  vpxenc: Unref frame on ERROR
+	  All code paths for handle_frame() must somehow take ownership of the frame, be
+	  it by actually unreffing, forwarding the frame elsewhere or storing it for
+	  later.
+	  http://bugzilla.gnome.org/show_bug.cgi?id=760666
+
+2016-01-20 18:20:43 +1100  Jan Schmidt <jan@centricular.com>
+
+	* sys/v4l2/gstv4l2deviceprovider.c:
+	  v4l2: Don't free props structure twice.
+	  gst_v4l2_device_provider_probe_device() frees the passed props
+	  structure, don't free it again in the caller.
+
+2016-01-19 15:15:35 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Cleanup uneeded return statement
+
+2016-01-19 15:14:59 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't set colorimetry for non YUV formats
+	  Setting colormetry in caps for RGB have no meaning, but worst it
+	  confuses the converters downstream.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=759624
+
+2016-01-19 13:01:17 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpchannels.c:
+	* gst/rtp/gstrtpchannels.h:
+	  rtp: fix compiler warnings with gcc-6
+	  In file included from gstrtpL16depay.h:27:0,
+	  from gstrtp.c:73:
+	  gstrtpchannels.h:154:33: error: 'channel_orders' defined but not used [-Werror=unused-const-variable]
+	  static const GstRTPChannelOrder channel_orders[] =
+
+2016-01-19 14:57:03 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Don't play anything after the end of the data chunk even when seeking
+	  Especially in push mode we would completely ignore the size of the data chunk
+	  when not stop position is given for the seek. Instead make sure that the end
+	  offset is at most the end of the data chunk if known.
+	  Without this we would output anything after the data chunk, possibly causing
+	  loud noises if the media file is followed by an INFO chunk or an ID3 tag.
+
+2016-01-19 14:55:57 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Don't do calculations with -1 offsets when handling SEGMENT events
+	  We use that to signal "infinity", taking the difference between that and some
+	  other value is not going to give us any useful result for the end offsets of
+	  segments.
+
+2016-01-18 11:30:45 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  Revert "WIP: rtpjitterbuffer: Add RFC7273 media clock handling"
+	  This reverts commit 271501f6576de4d141e7c2f618e28b9e3b1e5b38.
+	  It wasn't meant to be pushed yet as the commit message indicates.
+
+2016-01-12 14:01:21 -0800  Aleix Conchillo Flaqué <aconchillo@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: handle rtcp/srtcp caps properly when using interleaved data
+	  We check the stream profile and use the proper RTCP caps:
+	  application/x-srtcp if we are using a secure profile and
+	  application/x-rtcp otherwise.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=760556
+
+2016-01-05 16:15:16 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  WIP: rtpjitterbuffer: Add RFC7273 media clock handling
+
+2016-01-15 11:36:35 +0000  Thibault Saunier <tsaunier@gnome.org>
+
+	* ext/vpx/gstvpxenc.c:
+	  vp8enc: Return FLOW_ERROR when an error accures
+	  FALSE would mean FLOW_OK
+	  https://bugzilla.gnome.org/show_bug.cgi?id=760666
+
+2016-01-15 03:57:45 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* sys/osxaudio/gstosxcoreaudiohal.c:
+	  osxaudio: break as soon as the device is found
+	  No need to loop further if there's no side-effects for it
+
+2016-01-15 03:56:49 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* sys/osxaudio/gstosxaudioringbuffer.c:
+	* sys/osxaudio/gstosxcoreaudiohal.c:
+	  osxaudio: Fix error handling when selecting/opening devices
+	  Post an element error when the CoreAudio device cannot be selected or opened.
+	  Also ensure that we post a GST_ERROR with more detail.
+
+2016-01-13 23:40:20 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: When flushing on EOS, don't process more data than the "data" size
+	  Even if we have more data queued up when flushing than the size of the data
+	  chunk, don't process and output it. If the data size is known, this likely
+	  contains another chunk (e.g. an INFO chunk) or things like ID3 tags. Just
+	  outputting them as if they were data is going to cause unexpected behaviour
+	  and unpleasant audio noises.
+
+2014-08-29 15:40:23 +0200  Antonio Ospite <ao2@ao2.it>
+
+	* tests/check/pipelines/wavenc.c:
+	  tests: fix a thinko in the wavenc example
+	  The code is supposed to follow somehow what the comment above says, that
+	  is to have one channel with a wave of freq 440 and the other channel
+	  with a wave of freq 880, but an off by one error results in frequencies
+	  of 0 and 440.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735673
+
+2014-08-29 15:07:58 +0200  Antonio Ospite <ao2@ao2.it>
+
+	* gst/interleave/interleave.c:
+	  interleave: Fix the example by setting channel-masks in the sink pads
+	  The current example does not work, it fails with:
+	  ERROR: from element /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstWavParse:wavparse0: Internal data flow error.
+	  gstwavparse.c(2178): gst_wavparse_loop (): /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstWavParse:wavparse0:
+	  streaming task paused, reason not-negotiated (-4)
+	  This is because negotiation with wavenc gets messed up by the missing
+	  channel positions configuration.
+	  The proper way to define the channel layout when using the interleave
+	  element in code would be to set the channel-positions property, but
+	  gst-launch-1.0 does not know how to deal with arrays; so the example
+	  pipeline works around the issue by setting the channel-masks in the sink
+	  pads.
+	  Also fix a repetition in the deinterleave example description
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735673
+
+2016-01-11 16:29:55 +0000  Tim Sheridan <tim.sheridan@imgtec.com>
+
+	* gst/audioparsers/gstsbcparse.c:
+	  sbcparse: Fix frame length calculation
+	  SBC frame length calculation wasn't being rounded up to the nearest byte
+	  (as specified in the A2DP 1.0 specification, section 12.9). This could
+	  cause 'stereo' and 'joint stereo' mode SBC streams to have incorrectly
+	  calculated frame lengths.
+	  Incorrect frame length calculation causes frame coalescing to fail, as
+	  subsequent frames in the stream aren't found in the expected locations.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742446
+
+2016-01-10 22:54:12 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: demote warning on wrong reserved value to fixme
+	  We are likely just parsing a backward-compatible stream we
+	  don't fully support.
+
+2016-01-08 16:27:05 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: simplify caps selection
+	  The downstream caps query with a filter alraedy gives us the possible
+	  intersection so there is no need to check it again with downstream
+	  if it is supported. Just try to set it directly.
+
+2016-01-07 20:42:41 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: fix unnecessary sub-buffer creation
+	  We create a sub-buffer just to copy over its metas and then
+	  throw it away immediately, just use the original input buffer
+	  directly.
+
+2016-01-07 20:38:27 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpdvdepay.c:
+	  rtpdvdepay: fix unnecessary sub-buffer creation
+	  We create a sub-buffer just to copy over its metas and then
+	  throw it away immediately, just use the original input buffer
+	  directly.
+
+2016-01-07 20:34:05 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpamrdepay.c:
+	  rtpamrdepay: fix unnecessary sub-buffer creation
+	  We create a sub-buffer just to copy over its metas and then
+	  throw it away immediately, just use the original input buffer
+	  directly.
+
+2016-01-07 20:27:29 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  rtpvrawdepay: fix major memory leak and performance issue
+	  We call gst_rtp_buffer_get_payload() which creates a sub-buffer
+	  of each input buffer, just to copy over metas, and then leak it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=760289
+
+2016-01-08 15:32:47 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/rganalysis.c:
+	  rganalysis: Fix compiler warnings in the unit test
+	  elements/rganalysis.c:919:66: error: shifting a negative signed value is undefined
+	  [-Werror,-Wshift-negative-value]
+	  push_buffer (test_buffer_const_int16_stereo (8000, 16, 512, -1 << 14, 0));
+	  ~~ ^
+	  elements/rganalysis.c:929:69: error: shifting a negative signed value is undefined
+	  [-Werror,-Wshift-negative-value]
+	  push_buffer (test_buffer_const_int16_stereo (8000, 16, 512, 0, -1 << 14));
+	  ~~ ^
+	  elements/rganalysis.c:939:64: error: shifting a negative signed value is undefined
+	  [-Werror,-Wshift-negative-value]
+	  push_buffer (test_buffer_const_int16_mono (8000, 16, 512, -1 << 14));
+	  ~~ ^
+
+2016-01-05 18:13:06 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: don't map buffer multiple times when parsing
+
+2016-01-07 18:20:30 +0200  Steven Hoving <sh@bigbrother.nl>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroska: Store subtitle stream count in the correct variable
+	  And don't override the video stream count instead.
+
+2016-01-05 18:59:06 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/equalizer/gstiirequalizernbands.c:
+	  equalizer: The child-proxy API is GObject based in 1.x
+	  Not GstObject anymore.
+
+2015-05-21 17:41:12 +0200  Pablo Anton <pablo.anton@vodalys-labs.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2-*: Configuring output pool correctly for using drivers min_buffer if present.
+	  Signed-off-by: Pablo Anton <pablo.anton@vodalys-labs.com>
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755736
+
+2015-12-31 15:46:31 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: add debug msg on CRC mismatch while validating frame header
+
+2015-12-31 16:00:49 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: drop unneeded braces at _parse_frame() exit
+	  Additionally, drop redundant comment & line break
+
+2015-12-31 15:55:18 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: minor grammar correction
+
+2015-12-31 15:34:57 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: update URLs on pointers to online spec
+
+2015-12-31 14:40:15 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: make buffer DTS setting explicitly unconditional
+	  We are setting it to PTS regardless of block_strategy
+
+2015-12-31 14:21:40 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: add actual invalid block type to warning
+	  For someone that read the spec is clear the only *invalid*
+	  data block type is 127. For the rest, its useful information.
+	  Additionally. values 7-126 are currently reserved by the
+	  spec so the situation might change in the future.
+
+2015-12-31 14:12:36 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: use shift instead of mask & comp
+	  We are only interested on the first bit of the first
+	  byte of the metadata block header to figure out whether
+	  is marked as the last one. The shift makes it quite
+	  clearer.
+
+2015-12-31 12:52:13 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: warn on wishful parsing of weird headers
+	  If we get anything from 7 to 126 as type when parsing
+	  a metadata block header, we are likely dealing with a
+	  FLAC stream version we don't fully understand. Issue
+	  a warning if so.
+	  Document function assumptions regarding the passed-on
+	  type while at this.
+
+2015-12-31 11:33:45 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: show meaningful info on frame CRC check
+	  As CRCs are calculated for the comparition already, we
+	  might as well (cheaply) inform the user how the numbers
+	  differ if a missmatched pair is found.
+	  While at it:
+	  Rephrase candidate-frame message to make more sense
+
+2015-12-31 02:40:43 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: drop remaining trailing whitespace
+
+2015-12-31 02:15:06 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: drop superflous else clauses
+
+2015-12-31 01:09:51 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: factor out buffer time and offset resetting
+	  Avoids multiple occurrences of the same resetting pattern
+
+2015-12-31 00:54:48 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: move block handling by type out of _parse_frame()
+
+2015-10-07 18:51:25 +0900  Hyunjun Ko <zzoon.ko@samsung.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: replace duplicated codes to call new base sdp apis
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745880
+
+2015-12-30 12:16:56 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: drop redundant return statement on _header_is_valid()
+	  Fix the rather vague error message while at it.
+
+2015-12-30 01:56:26 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: rework gst_flac_parse_frame_is_valid()
+	  drop unnecessary nesting looking for end of frame
+
+2015-12-30 00:37:04 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: factor out context clearing routine
+
+2015-12-29 18:05:56 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Guard against no codec data in prores caps creation
+	  CID 1346532
+
+2015-12-29 17:58:38 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/vpx/gstvpxdec.c:
+	  vpxdec: Initialize buffer variable to NULL
+	  False positive but trivial to fix and possibly causing compiler warnings at
+	  some point in the future too.
+	  CID 1346535
+
+2015-07-27 15:53:26 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* sys/v4l2/gstv4l2deviceprovider.c:
+	  v4l2deviceprovider: add properties to the device
+	  Add properties to the device with exactly the same keys and sematics
+	  as what pulseaudio uses as property keys.
+	  Also handle the case when a device is probed manually and not through gudev.
+	  https://bugzilla.gnome.org//show_bug.cgi?id=759780
+
+2015-12-25 11:41:19 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: Free the various buffers in GstBaseTransform::stop()
+	  Previously we leaked them completely, but as they're specific to the caps
+	  freeing them in stop() instead of finalize() makes most sense.
+
+2015-12-24 15:28:06 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.7.1 ===
+
+2015-12-24 14:16:21 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.7.1
+
+2015-12-24 13:19:24 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2015-12-24 12:22:32 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/cs.po:
+	* po/de.po:
+	* po/el.po:
+	* po/hu.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/pl.po:
+	* po/ru.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	  po: Update translations
+
+2015-12-21 09:57:33 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: drop flushes from our own offset seek
+	  Prevents downstream from receiving flushes for a seek only in
+	  upstream. Those seeks are only to start reading from the right
+	  offset when skipping or returning to qt atoms.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758928
+
+2015-11-11 16:53:19 +0100  Thibault Saunier <tsaunier@gnome.org>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Always set the channel mask for PCM streams
+	  Just use the gst_audio_channel_get_fallback_mask function for now as
+	  the specification is too complicated and nobody implements it.
+
+2015-12-21 11:37:26 +0100  Thomas Roos <thomas.roos@industronic.de>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: Fix sleep for buffer-time lower than 200000
+	  https://bugzilla.gnome.org/show_bug.cgi?id=748680
+
+2015-12-21 12:31:19 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  configure: Use -Bsymbolic-functions if available
+	  While this is more useful for libraries, some of our plugins with multiple
+	  files and some internal API can also benefit from this.
+
+2015-12-18 15:34:52 +0000  William Manley <will@williammanley.net>
+
+	* gst/debugutils/progressreport.c:
+	* gst/debugutils/progressreport.h:
+	  progressreport: add support for using format=buffers with do-query=false
+	  This is useful for investigating and debugging pipelines which are
+	  producing buffers at a slower/faster rate than you would expect.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=759635
+
+2015-12-18 15:49:43 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Update formats table
+	  This change add all the new RGB based format. Those format removes the
+	  ambiguity with the ALPHA channel. Some other missing multiplanar format
+	  has been added with some additional cleanup.
+
+2015-12-18 05:17:15 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Don't write invalid edit list start time.
+	  Avoid writing a negative number as a large positive
+	  integer in an edit list when the first_ts is smaller
+	  than the first_dts - which can happen when the first
+	  packet received has a PTS but no DTS.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=759615
+
+2015-12-04 23:16:45 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Only update running time when it increases.
+	  Don't increment running time from every buffer. The correct
+	  logic to only increment when running time advances is a
+	  little further down, so delete this left-over line.
+
+2015-11-18 11:01:20 +0100  Thibault Saunier <tsaunier@gnome.org>
+
+	* gst/matroska/matroska-mux.c:
+	  matroska-mux: Implement prores support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758258
+
+2015-11-18 16:20:38 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	  matroska-demux: Play ProRes video streams
+	  Generate video/x-prores caps for ProRes video streams.
+	  Every frame needs an 8 byte header prepended, as described in
+	  http://wiki.multimedia.cx/index.php?title=Apple_ProRes#Frame_layout
+	  so do that in a post-processing callback.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758258
+
+2015-12-18 10:18:09 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* ext/dv/gstdvdec.h:
+	  dvdec: Remove unused fields
+	  Remove unused fields frame_len and space
+	  https://bugzilla.gnome.org/show_bug.cgi?id=759614
+
+2015-12-17 16:03:04 +0100  Vincent Dehors <vincent.dehors@openwide.fr>
+
+	* gst/rtp/gstrtpj2kdepay.c:
+	  rtpj2kdepay: Push one JPEG2000 frame per buffer, not a buffer list with multiple buffers
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758943
+
+2015-12-16 11:43:58 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	  dv1394: log error if failed to set socket status flag
+	  Log an error message if failed to set write or read socket as
+	  non-blocking.
+	  CID 1139608
+	  CID 1139609
+
+2015-12-15 17:10:00 +0000  Dave Craig <davecraig@unbalancedaudio.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstsbcparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	  audioparsers: Check for NULL return value of gst_pad_get_current_caps()
+	  https://bugzilla.gnome.org/show_bug.cgi?id=759503
+
+2015-12-16 09:35:53 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	  docs: update to git
+
+2015-12-15 14:27:22 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* ext/vpx/Makefile.am:
+	  vpx: Add missing headers in Makefile.am
+	  This fixes distcheck.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755510
+
+2015-09-24 12:57:00 +0530  Prashant Gotarne <ps.gotarne@samsung.com>
+
+	* ext/vpx/Makefile.am:
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp8enc.h:
+	* ext/vpx/gstvp9enc.c:
+	* ext/vpx/gstvp9enc.h:
+	* ext/vpx/gstvpxenc.c:
+	* ext/vpx/gstvpxenc.h:
+	  vpx: created common baseclass GstVPXEnc
+	  GstVP8Enc and GstVP9Enc has almost 80% code in common.
+	  created common baseclass GstVPXEnc for GstVP8Enc and GstVP9Enc
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755510
+
+2015-12-15 12:57:53 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* ext/vpx/gstvp9dec.c:
+	* ext/vpx/gstvpxdec.c:
+	* ext/vpx/gstvpxdec.h:
+	  vpxdec: Remove unneeded add video_meta
+	  This also remove copies for VP8, which was not correctly in place
+	  in previous related patch.
+
+2015-12-15 09:49:24 +0530  Prashant Gotarne <ps.gotarne@samsung.com>
+
+	* ext/vpx/Makefile.am:
+	* ext/vpx/gstvp8dec.c:
+	* ext/vpx/gstvp8dec.h:
+	* ext/vpx/gstvp9dec.c:
+	* ext/vpx/gstvp9dec.h:
+	* ext/vpx/gstvpxdec.c:
+	* ext/vpx/gstvpxdec.h:
+	  vpx: created common base class GstVPXdec for vpx decoders
+	  Base class for the vp8dec and vp9dec.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755510
+
+2015-06-10 09:17:08 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* configure.ac:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: Add GTlsInteraction property
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750709
+
+2015-12-14 09:05:06 -0500  Evan Callaway <evan.callaway@ipconfigure.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Retry connection if tunneling needs authentication
+	  Leverage response from gst_rtsp_connection_connect_with_response to
+	  determine if the connection should be retried using authentication.  If
+	  so, add the appropriate authentication headers based upon the response
+	  and retry the connection.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749596
+
+2015-12-14 14:19:05 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: check port-range format
+	  The string could exist but with a wrong format, in that case we still want
+	  to reset the values of client_port_range.min and max like we do if there is
+	  no string.
+	  CID 1139593
+
+2015-12-14 14:55:12 +0100  Thomas Roos <thomas.roos@industronic.de>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: Check device property and fail if device can't be found
+	  Don't use default if a specific device is set but it can't be found.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=759452
+
+2015-12-14 14:15:00 +0100  Thomas Roos <thomas.roos@industronic.de>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: Fix handling of the mute property
+	  - set mute value at startup
+	  - correct set and get mute functions
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755106
+
+2015-12-11 11:23:13 +0100  Thomas Roos <thomas.roos@industronic.de>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: Check the return value of GetStatus() too to decide if there was an error
+	  If GetStatus() fails, the status itself won't be very meaningful but we also
+	  have to look at its return value. This fixes blocking pipelines when removing
+	  sound devices or during other errors, where we wouldn't notice the error and
+	  then wait forever.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=734098
+
+2015-12-10 17:41:46 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/gstqtmux.c:
+	  isomp4: remove unused parameters in build_*_extension
+	  AtomTRAK parameter is not used by build_mov_alac_extension(),
+	  build_jp2h_extension(), or build_mov_alac_extension()  and can be
+	  removed.
+
+2015-12-10 15:11:07 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  isomp4: replace variable only used once
+	  Replace has_shift variable with value since it is only use once.
+
+2015-12-09 12:24:09 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Fix packet dropping after a big discont
+	  We would queue 5 consective packets before considering a reset and a proper
+	  discont here. Instead of expecting the next output packet to have the current
+	  seqnum (i.e. the fifth), expect it to have the first seqnum. Otherwise we're
+	  going to drop all queued up packets.
+
+2015-12-09 11:49:02 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* gst/interleave/interleave.h:
+	  interleave: Remove unsed field
+	  Remove unused field collect_event in interleave.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=759226
+
+2015-12-07 16:33:14 +0100  Edward Hervey <edward@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Stop pushing data as soon as possible in push-mode
+	  When working in push-mode, we attempt to push out everything currently
+	  buffered in the adapter.
+	  This has two pitfalls:
+	  * We could stop earlier (the moment we get a non-ok or non-not-linked)
+	  * We return the last combined flow return, which might be completely
+	  different from the previous combined flow return
+
+2015-12-07 09:08:09 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* autogen.sh:
+	* common:
+	  Automatic update of common submodule
+	  From b319909 to 86e4663
+
+2015-12-07 14:41:51 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Add a warning if an empty RTCP packet is tried to be sent
+	  https://bugzilla.gnome.org/show_bug.cgi?id=759119
+
+2015-11-30 19:20:13 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* configure.ac:
+	* ext/vpx/gstvp8dec.c:
+	* ext/vpx/gstvp8dec.h:
+	* ext/vpx/gstvp9dec.c:
+	* ext/vpx/gstvp9dec.h:
+	  vpxdec: Use GstMemory to avoid copies
+	  With the VPX decoders it's not simple to use downstream buffer pool,
+	  because we don't know the image size and alignment when buffers get
+	  allocated. We can though use GstAllocator (for downstream, or the system
+	  allocator) to avoid a copy before pushing if downstream supports
+	  GstVideoMeta. This would still cause a copy for sink that requires
+	  specialized memory and does not have a GstAllocator for that, though
+	  it will greatly improve performance for sink like glimagesink and
+	  cluttersink. To avoid allocating for every buffer, we also use a
+	  internal buffer pool.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745372
+
+2015-11-30 08:42:35 +0100  Edward Hervey <edward@centricular.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Avoid over-skipping when checking LOAS config
+	  There might be multiple LOAS config in a row in a full frame. The first
+	  one might be a multi-layer config (which we can't properly parse yet)...
+	  but then followed by a valid (single-layer) one.
+	  The code was previously skipping whole frames (instead of just the LOAS
+	  config we failed to read) resulting in multiple frames (seen up to 6s in
+	  some situation) being dropped before finally getting the configuration.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758826
+
+2015-11-25 17:08:56 +0100  Edward Hervey <edward@centricular.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Properly set SPARSE stream flags for subpicture/subtitle
+	  And while we're at it, also detect 'DXSA' as being a variant fourcc
+	  of 'DXSB' for XSUB
+
+2015-11-30 21:23:52 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: souphttpsrc: grammar fix
+
+2015-11-30 21:01:17 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: souphttpsrc: switch shoutcast stream provider
+	  Fixes failing ICY test. Previous provider has
+	  streaming disabled outside UK.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758114
+
+2015-11-18 16:10:11 +0100  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* gst/avi/gstavimux.c:
+	  avimux: don't crash if we never got audio caps before stopping
+	  auds.blockalign is set once the first caps arrive. If
+	  gst_avi_mux_stop_file() is called before this happens then auds.blockalign
+	  is zero and gst_avi_mux_audsink_set_fields() cause a crash:
+	  [...]
+	  avipad->parent.hdr.rate = avipad->auds.av_bps / avipad->auds.blockalign;
+	  [...]
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758912
+
+2015-12-01 18:20:23 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: don't block when resurecting a buffer
+	  When we are resurecting a buffer, don't block. instead let us copy a
+	  buffer.
+
+2015-12-01 00:30:08 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: remove extra variable to improve readability
+	  Makes it easier to see that the event is being replaced/unrefed
+
+2015-12-01 00:22:36 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: respect seqnum in seek events
+	  Propagate the original seek seqnum to events originated from
+	  seeking to make sure they have the same value
+
+2015-12-01 00:03:21 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: flush upstream when seeking in pull mode
+	  Makes sure upstream will unblock and return the thread so that
+	  seeking can continue
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758861
+
+2015-11-27 09:27:29 +0100  Anton Bondarenko <antonbo@axis.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: add "send SPS/PPS with every key frame" mode
+	  It's not enough to have timeout or event based SPS/PPS information sent
+	  in RTP packets. There are some scenarios when key frames may appear
+	  more frequently than once a second, in which case the minimum timeout
+	  for "config-interval" of 1 second for sending SPS/PPS is not sufficient.
+	  It might also be desirable in general to make sure the SPS/PPS is
+	  available with every keyframe (packet loss aside), so receivers can
+	  actually pick up decoding immediately from the first keyframe if
+	  SPS/PPS is not signaled out of band.
+	  This patch adds the possibility to send SPS/PPS with every key frame. This
+	  mode can be enabled by setting "config-interval" property to -1. In this
+	  case the payloader will add SPS and PPS before every key (IDR) frame.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=757892
+
+2015-11-27 09:03:51 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtph264pay.h:
+	* tests/check/elements/rtp-payloading.c:
+	  rtph264pay: change config-interval property type from uint to int
+	  This way we can use -1 as special value, which is nicer than MAXUINT.
+	  This is backwards compatible even with the GValue API, as shown by
+	  a unit test.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=757892
+
+2015-11-26 21:46:11 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: add support for Opus
+	  Add support for demuxing Opus encapsulated in MP4 files, based on the
+	  following spec: https://www.opus-codec.org/docs/opus_in_isobmff.html
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742643
+
+2015-11-25 22:48:32 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: use macro for codec_name
+	  Use _codec() macro instead of duplicating code.
+
+2015-03-25 16:32:55 +0100  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2: videodec: choose format from caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733827
+
+2015-03-27 15:02:33 +0100  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2: add gst_v4l2_object_probe_caps
+	  Add a variant of gst_v4l2_object_get_caps that bypasses the probed_caps cache.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733827
+
+2015-11-19 17:20:55 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2.c:
+	  v4l2-probe: Skip devices without supported formats
+
+2015-11-13 12:35:59 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* configure.ac:
+	* sys/v4l2/gstv4l2.c:
+	  v4l2: Track /dev/video* to triggered required probe
+	  If something in /dev/video* get added, removed or replaced, we need to
+	  probe the devices again in order to ensure the dynamic devices are up to
+	  date.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758085
+
+2015-11-25 14:51:40 +1100  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpmanager: rtpsession: don't send empty RTCP packets
+	  generate_rtcp can produce empty packets when reduced size RTCP is turned on.
+	  Skip them since it doesn't make sense to push them and they cause errors with
+	  elements that expect RTCP packets to contain data (like srtpenc).
+
+2015-11-24 10:57:28 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: restore the segment on case of soft reset
+	  When seeking back to restore the mdat position a flush is pushed
+	  through and it resets downstream segment information. Make sure
+	  that after the flush (that does a soft reset) a segment will
+	  be pushed again
+	  Fixes regressions spotted at
+	  https://ci.gstreamer.net/job/GStreamer-master-validate/2100/
+
+2015-11-20 12:44:22 +0000  Graham Leggett <minfrin@sharp.fm>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: fix spelling of variable
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758390
+
+2015-11-20 11:05:51 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: unite duplicate FourCC
+	  Unite in fourcc.h the FourCCs that are used twice or more in qtdemux
+
+2015-11-19 15:33:45 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2: Fix capture/output-io-mode properties
+	  There was some miss-match in the implementation. This makes it
+	  concistent, though functionally it worked, except the video decoder
+	  output-io-mode getter.
+
+2015-11-19 19:48:06 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/isomp4/atoms.c:
+	  atoms: remove unused argument of build_mov_wave_extension()
+	  AtomTrak * trak argument of build_move_wave_extension() isn't used.
+	  Removing it.
+
+2015-11-19 19:28:20 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: remove duplicate FourCC
+	  Use the available FourCCs in fourcc.h instead of duplicating them.
+
+2015-11-19 18:36:39 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/gstqtmux.c:
+	  isomp4: centralize all FourCC
+	  10 FourCCs generated with GST_MAKE_FOURCC() in gstqtmux.c and atoms.c
+	  already exist in fourcc.h. Don't duplicate these and use them directly.
+	  Plus moving 6 to fourcc.h, to centralize them all.
+
+2015-11-19 17:32:12 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/matroska/webm-mux.c:
+	  matroska/webmmux: fix outdated example launch lines
+	  Update gst-launch-0.10 lines to gst-launch-1.0
+
+2015-11-16 13:26:50 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmuxmap.c:
+	  isomp4: add support for Opus in mp4mpux
+	  Add support for muxing MP4 files containing Opus. Based on the spec
+	  detailed here:
+	  https://www.opus-codec.org/docs/opus_in_isobmff.html
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742643
+
+2015-11-18 19:10:56 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Replace tabs with spaces
+
+2015-11-18 19:07:53 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Cast to signed integers to prevent unsigned compare between negative and positive numbers
+	  This fixes seeking if the first entries in the samples table are negative. The
+	  binary search would always fail on this as the array would not be sorted if
+	  interpreting the negative numbers as huge positive numbers. This caused us to
+	  always output buffers from the beginning after a seek instead of close to the
+	  seek position.
+	  Also add a case to the comparison function for equality.
+
+2015-11-18 16:01:48 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: remove duplicate check
+	  We want 1 or 2 streamheaders, the check  if (bufarr->len != 1 &&
+	  bufarr->len != 2) is enough. Not need to check if bufarr->len is <= 0 or
+	  > 255.
+
+2015-11-18 14:48:36 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	  souphttpclientsink: Fix error leak and handle error
+	  g_thread_try_new allows for possiblity of failures. In case it fails,
+	  error is not handled and leaked.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758260
+
+2015-11-15 17:16:29 -0800  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	  rtpgstdepay: Properly handle backward compat for event deserialization
+	  Actual code is checking for a NULL terminator and a ';' terminator,
+	  for backward compat, in a chained way that cause all events being rejected.
+	  The proper condition is to reject the events when terminator isn't
+	  in ['\0', ';'] set.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758151
+
+2015-11-15 17:11:02 -0800  Josep Torra <n770galaxy@gmail.com>
+
+	* tests/check/elements/rtp-payloading.c:
+	  tests: rtp-payloading: Test for handling of custom events in rtpgst
+	  Add a simple test that checks proper serialization/deserialization
+	  of custom events with rtpgstpay and rtpgstdepay.
+
+2015-11-16 16:23:43 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* ext/vpx/gstvp8dec.c:
+	* ext/vpx/gstvp9dec.c:
+	  vpxdec: Use threads on multi-core systems
+	  This adds an automatic mode to the threads property of vpxdec in order to
+	  use as many threads as there is CPU on the platform. This brings back
+	  GStreamer VPX decoding performance closer to what is achieved by other
+	  players, including Chromium.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758195
+
+2015-11-16 10:58:32 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: only send initial gaps for non-fragmented streams
+	  It would be unusual to have the header segment with an 'edts' atom
+	  indicating gaps at the beginning when handling fragmented streams.
+	  The header usually doesn't contain any timestamping information, this
+	  should come from the playlist/manifest and the segments with media
+	  in those scenarios.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758171
+
+2015-11-17 09:41:34 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  Revert "Revert "qtdemux: respect qt segments in push-mode for empty starts""
+	  This reverts commit d842ff288a9d01214a046becbfd9cbff3a4acea0.
+	  This was reverted by accident
+
+2015-11-17 12:39:05 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	* gst/udp/gstudpsrc.h:
+	  udpsrc: Add "loop" property for enabling/disabling multicast loopback
+	  On POSIX, IP_MULTICAST_LOOP is a setting for the sender socket. On Windows it
+	  is a setting for the receiver socket. As such we will need it on udpsrc too to
+	  allow filtering out our own multicast packets.
+
+2015-11-16 13:52:05 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  Revert "qtdemux: respect qt segments in push-mode for empty starts"
+	  This reverts commit 142d8e2d23e5602e7382977af1043d621625f8c8.
+
+2015-11-16 16:56:04 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix string memory leak
+	  The string got using g_strdup_printf will be allocated memory
+	  and should be freed after use.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758161
+
+2015-11-14 21:51:11 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2/object: remove unnecessary NULL check before g_free()
+
+2015-11-14 21:45:29 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* sys/oss/gstosssrc.c:
+	  osssrc: remove unnecessary NULL check before g_free()
+
+2015-11-14 21:43:24 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* sys/sunaudio/gstsunaudiosrc.c:
+	  sunaudiosrc: remove unnecessary NULL checks before g_free()
+
+2015-11-14 21:36:30 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: remove unnecessary NULL checks before g_free()
+
+2015-11-14 21:31:08 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: remove unnecessary NULL checks before g_free()
+
+2015-11-14 21:26:21 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroska/read-common: remove unnecessary NULL checks before g_free()
+
+2015-11-14 20:43:10 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/isomp4/atoms.c:
+	  isomp4/atoms: remove unnecessary NULL checks before g_free()
+
+2015-11-14 20:35:54 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/rtp/gstrtptheorapay.c:
+	  rtp/theorapay: remove unnecessary NULL checks before g_free()
+
+2015-11-14 20:33:54 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	  rtp/vorbispay: remove unnecessary NULL checks before g_free()
+
+2015-11-14 20:31:34 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtp/jpegpay: remove unnecessary NULL checks before g_free()
+
+2015-11-14 20:27:04 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: remove unnecessary NULL checks before g_free()
+
+2015-11-14 20:22:09 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: remove unnecessary NULL checks before g_free()
+
+2015-11-14 20:14:25 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/flx/gstflxdec.c:
+	  flxdec: remove unnecessary NULL check before g_free()
+
+2015-11-14 20:09:54 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/effectv/gstop.c:
+	  effectv/optv: remove unnecessary NULL checks before g_free()
+
+2015-11-14 20:05:03 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/effectv/gstshagadelic.c:
+	  effectv/shagadelictv: remove unnecessary NULL checks before g_free()
+
+2015-11-14 20:01:43 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/effectv/gstripple.c:
+	  effectv/ripple: remove unnecessary NULL checks before g_free()
+
+2015-11-14 19:56:57 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/effectv/gstradioac.c:
+	  effectv/radioac: remove unnecessary NULL checks before g_free()
+
+2015-11-14 19:52:12 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/effectv/gststreak.c:
+	  effectv/streak: remove unnecessary NULL check before g_free()
+
+2015-11-14 17:04:55 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* ext/shout2/gstshout2.c:
+	  shout2: remove unnecessary NULL checks before g_free()
+
+2015-11-14 16:57:13 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* ext/vpx/gstvp9enc.c:
+	  vp9enc: remove unnecessary NULL check before g_free()
+
+2015-11-14 16:54:42 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: remove unnecessary NULL check before g_free()
+
+2015-11-14 16:20:33 -0800  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: remove unnecessary NULL checks before g_free()
+
+2015-11-13 13:34:02 +0100  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: add support of NV16, NV61 and NV24 formats
+	  Mapped respectively to V4L2_PIX_FMT_NV16/V4L2_PIX_FMT_NV16M,
+	  V4L2_PIX_FMT_NV61,V4L2_PIX_FMT_NV61M and V4L2_PIX_FMT_NV24 v4l2 formats.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=758058
+
+2015-11-11 14:10:53 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	  splitmuxpartreader: Fix GCond leak
+	  inactive_cond is not being cleared resulting in memory leak.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=757924
+
+2015-08-06 12:44:20 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fix output state memory leak
+	  When jpeg_finish_decompress is called, output state reference is being created.
+	  But if there is any failures in finishing decompress, it jumps to setjmp,
+	  and at that point state was not referenced. Resulting in leak of output state.
+	  Hence adding another setjmp after output state is referenced.
+	  Similarly adding another setjmp to unmap the frame in case error happens before
+	  finish_decompress
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753087
+
+2015-08-10 11:23:45 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: respect qt segments in push-mode for empty starts
+	  In push-mode it is hard to support qt segments overall but it is
+	  possible to support when the file isn't heavily edited but just contain
+	  a segment to indicate a gap at the beginning. This also allows properly
+	  timestamping data that has negative DTS in push-mode.
+	  It is relevant to support those for 2 scenarios:
+	  1) fragmented streaming
+	  2) HTTP playback of 'regular' mp4
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753484
+
+2015-11-05 18:39:33 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* ext/pulse/pulsedeviceprovider.c:
+	  pulse: Don't leak caps and structures in the device provider
+
+2015-11-04 19:01:20 +0530  Arun Raghavan <arun@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpmanager: Document properties that are expressed in bits per second
+	  This changed in 928cd110bcea5d143cab3ea747991851d52ecbad and
+	  73c0c2920f9aca96982a4de0c20b3417aa148b81 but was not documented.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747863
+
+2015-11-04 18:51:32 +0530  Arun Raghavan <arun@centricular.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	  rtpmanager: Trivial gst-indent fixes
+
+2015-08-12 13:35:40 +0200  Philippe Normand <philn@igalia.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: support for cenc auxiliary info parsing outside of moof box
+	  When the cenc aux info index is out of moof boundaries, keep track of
+	  it and parse the beginning of the mdat box, before the first sample.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755614
+
+2015-11-03 20:33:10 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Use codecutils helpers for creating Opus caps
+	  Also fix up codec data with values from the container.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=757152
+
+2015-11-03 14:51:48 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: There is no multistream field for Opus anymore
+	  https://bugzilla.gnome.org/show_bug.cgi?id=757152
+
+2015-11-03 12:42:52 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/webm-mux.c:
+	  matroska/webmmux: Support Opus in webmmux and VP9 in matroskamux
+	  https://bugzilla.gnome.org/show_bug.cgi?id=729950
+
+2015-11-03 12:40:15 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Parse and handle CodecDelay, SeekPreroll and DiscardPadding
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727305
+
+2015-11-03 12:18:19 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Write CodecDelay, DiscardPadding and SeekPreroll for Opus
+	  And also adjust timestamps and durations according to the codec delay, both
+	  should include it for whatever reason.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727305
+
+2015-11-03 11:49:54 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Opus headers are not in-band
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727305
+
+2015-11-03 22:01:07 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* sys/v4l2/gstv4l2.c:
+	  v4l2: Set O_CLOEXEC on the device fd
+	  This is needed to make sure that child processes don't inherit the video
+	  device fd which can cause problems with some drivers.
+
+2015-11-03 14:46:30 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpmanager: switch G_GINT64_FORMAT for GST_STIME_ARGS
+	  No need to use G_GINT64_FORMAT for potentially negative values of
+	  GstClockTimeDiff. Since 1.6 these can be handled with GST_STIME_ARGS.
+	  Plus it creates more readable values in the logs.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=757480
+
+2015-11-03 14:26:29 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpmanager: use GST_STIME_ARGS for GstClockTimeDiff
+	  No need to manually handle negative values of diff, GST_STIME_ARGS does
+	  exactly this.
+
+2015-11-02 16:53:15 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: use GST_STIME_ARGS for GstClockTimeDiff
+	  No need to manually handle negative values of diff, GST_STIME_ARGS does
+	  exactly this.
+
+2015-11-02 16:43:46 +0000  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: use GST_STIME_ARGS for GstClockTimeDiff
+	  No need to manually handle negative values of diff, GST_STIME_ARGS is
+	  available for this.
+
+2015-10-30 10:05:37 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* gst/audiofx/audiochebband.c:
+	  audiochebband: Fix typo in example pipeline
+	  Fix typo in example pipeline.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=757340
+
+2015-10-28 23:47:30 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* sys/v4l2/gstv4l2deviceprovider.c:
+	  v4l2: fix double-unref in the v4l2 device provider
+
+2015-10-27 10:48:00 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-ids.c:
+	  matroskamux: don't drop JPEG frames that only have PTS but no DTS set
+	  For the MS/VfW codec ids, we want to write DTS timestamps instead
+	  of PTS because that's what everyone else seems to do (and it's also
+	  how it is in AVI). So for those input formats we use the buffer DTS
+	  instead of the PTS. However, if there's no DTS set but only the PTS
+	  then just take the PTS instead of dropping the input buffer. This
+	  is useful especially for I-frame only codecs like JPEG and huffyuv,
+	  but should also be fine as fallback in general.
+	  Fixes regression with input JPEG frames that only have PTS set on them.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756967
+
+2015-10-24 23:57:38 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/check/elements/splitmux.c:
+	  tests/check/splitmux: test that the release_pad vfunc of splitmuxsink actually releases pads
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753622
+
+2015-10-24 23:57:29 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: do not destroy the multiqueue & muxer when going to NULL
+	  Instead, delay it until all request pads have been released. This is
+	  because the release_pad() vfunc requires the multiqueue and muxer to
+	  be there in order to release their request pads as well. If those
+	  elements are destroyed earlier, release_pad() does not work, no
+	  pads are released and some resources are leaked.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753622
+
+2015-10-20 15:28:10 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Read buffer timestamp *after* actually setting it
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756809
+
+2015-10-24 17:14:07 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audiofx/gstscaletempo.c:
+	* gst/audiofx/gstscaletempo.h:
+	  scaletempo: Fix handling of rate < 0
+	  We have to reverse all samples in a buffer before processing them to properly
+	  have continuous data from one buffer to another. As a result we will have a
+	  negative applied rate and a rate of 1.0.
+	  Also make sure that input buffers are correctly clipped to the segment,
+	  otherwise our calculations are going to go wrong.
+	  Also copy over the segment event's sequence number to the output segment while
+	  we're at it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=757033
+
+2015-10-19 18:04:56 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: break as soon as non-interlaced if found
+	  It looks for a non-interlaced entry on the filter caps, break
+	  as soon as one is found to avoid wasting cpu
+
+2015-10-19 17:50:28 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: implement accept-caps
+	  Implement accept-caps handler to avoid doing a full caps query
+	  downstream to handle it.
+	  This commit implements accept-caps as a simplification of the _getcaps
+	  function, so it exposes the same limitations that getcaps would.
+	  For example, not accepting renegotiation to caps with capsfeatures when
+	  it was last configured to a caps that it has to deinterlace.
+
+2015-10-19 17:06:28 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/deinterlace.c:
+	  tests: deinterlace: fix small typo in comment
+
+2015-10-26 00:41:28 +1100  Jan Schmidt <jan@centricular.com>
+
+	* tests/files/Makefile.am:
+	  check: Dist splitvideo0[012].ogg test files.
+
+2015-10-23 20:16:17 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audiofx/gstscaletempo.c:
+	* gst/audiofx/gstscaletempo.h:
+	  scaletempo: Add support for F64
+
+2015-10-22 17:40:38 -0700  Mischa Spiegelmock <mspiegelmock@gmail.com>
+
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* gst/multipart/multipartdemux.c:
+	* gst/rtp/README:
+	* gst/rtp/gstrtpvp8pay.c:
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	* gst/udp/gstudpsrc.c:
+	  docs: Minor fixes in various places
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756996
+
+2015-10-21 17:43:31 +0100  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/goom/plugin_info.c:
+	  goom: remove compiler trick
+	  After commit 2cb6cfed22166b262ae50cb58f3ff11dd8ba91f9 there is no need to
+	  trick the compiler anymore about the usage of variable cpuFlavour.
+
+2015-10-21 14:35:02 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From b99800a to b319909
+
+2015-10-21 17:41:38 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* gst/audiofx/audiofxbaseiirfilter.h:
+	  audiofx: remove unused variable
+	  Remove unsued variable have_coeffs in audiofxbaseiirfilter
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756905
+
+2015-10-20 17:29:42 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Use new GST_ENABLE_EXTRA_CHECKS #define
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756870
+
+2015-10-21 14:25:55 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* README:
+	* common:
+	  Automatic update of common submodule
+	  From 9aed1d7 to b99800a
+
+2015-10-21 11:53:09 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: relax creation time parsing
+	  Parse wrong timestamps like we used to write as well,
+	  e.g. 10:9:42, and the hour might be without a leading
+	  zero in any case.
+
+2015-10-21 11:45:35 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: fix indentation
+
+2015-10-21 11:44:50 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: extract both creation date and time
+	  Before we only extracted the date part.
+
+2015-10-21 11:16:01 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: fix writing of creation time
+	  Don't write time as e.g. 11:9:42
+
+2015-10-13 12:42:56 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/rtp/gstrtpj2kpay.c:
+	  rtpj2kpay: update fragment offset
+	  It was always being set to 0, making the resulting stream broken
+	  for the receiver
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756422
+
+2015-10-19 15:36:37 +0300  Ryan Hendrickson <ryan.hendrickson@alum.mit.edu>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Don't unconditionally use strnlen()
+	  It's not available on older OSX and we can as well use memchr() here.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756154
+
+2015-10-19 17:38:32 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/auparse/gstauparse.c:
+	  auparse: Fix event memory leak
+	  Free the event after being handled to prevent memory leak.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756799
+
+2015-10-19 09:14:19 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/gstqtmuxmap.c:
+	  qtmux: unify raw audio caps into a single caps structure
+
+2015-10-14 15:42:50 -0700  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: add support for FFV1 coded streams in mov
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752495
+
+2015-10-14 15:53:26 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: EOS immediately if we have an empty seek segment
+	  https://bugzilla.gnome.org/show_bug.cgi?id=748316
+
+2015-10-14 10:43:19 +0300  Stavros Vagionitis <stavrosv@digisoft.tv>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Make non-inclusive segment boundaries inclusive
+	  The problem is that the filesrc and souphttpsrc are behaving
+	  differently regarding the calculation of the segment boundaries. The
+	  filesrc is using a non-inclusive boundaries, while the souphttpsrc
+	  uses inclusive. Currently the hlsdemux calculates the boundaries as
+	  inclusive, so for this reason there is no problem with the souphttpsrc,
+	  but there is an issue in the filesrc.
+	  The GstSegment is non-inclusive, so the proposed solution is to use
+	  non-inclusive boundaries in the hlsdemux in order to be consistent.
+	  Make the change in the hlsdemux, will break the souphttpsrc, which
+	  will expect inclusive boundaries, but the hlsdemux will offer
+	  non-inclusive. This change makes sure that the non-inclusive
+	  boundaries are converted to inclusive.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=748316
+
+2015-10-11 22:07:54 +0000  Graham Leggett <minfrin@sharp.fm>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	* ext/soup/gstsouphttpclientsink.h:
+	  souphttpclientsink: Add the retry and retry-delay properties
+	  These allow a failed request to be retried after the given number of seconds
+	  instead of failing the pipeline. Take account of the Retry-After header if
+	  present. Add retries parameter that controls the number of times an HTTP
+	  request will be retried before failing.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756318
+
+2015-10-14 12:03:15 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix caps leak
+	  If the QtDemuxStream are re-used they may already have caps which used
+	  to be leaked.
+	  Reproduced using the
+	  validate.dash.playback.seek_forward.dash_exMPD_BIP_TC1 validate
+	  scenario.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756561
+
+2015-10-14 09:29:50 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix taglist memory leak
+	  Free the stream and its sub items instead of just the stream
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756544
+
+2015-10-11 12:06:26 +0100  Thibault Saunier <tsaunier@gnome.org>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmuxmap.c:
+	  qtmux: Allow negotiating to S8 as a raw format but stop making it best choice
+	  Negotiation to audio/x-raw,format=S8 was not possible because S8 does
+	  not have a bit order so we ended up doing `if (!entry.fourcc) goto refuse_caps;`
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756387
+
+2015-10-11 09:18:40 +0100  Thibault Saunier <tsaunier@gnome.org>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmuxmap.c:
+	  qtmux: Add prores support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756388
+
+2015-10-12 18:56:32 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/Makefile.am:
+	  tests: add GST_PLUGINS_BASE_LIBS for flvdemux check
+	  So it pulls in the right libgsttag-1.0.
+
+2015-10-11 22:27:47 +0100  Julien Isorce <j.isorce@samsung.com>
+
+	* gst/goom/Makefile.am:
+	* gst/goom/gstaudiovisualizer.c:
+	* gst/goom/gstaudiovisualizer.h:
+	* gst/goom/gstgoom.h:
+	* gst/goom2k1/Makefile.am:
+	* gst/goom2k1/gstaudiovisualizer.c:
+	* gst/goom2k1/gstaudiovisualizer.h:
+	* gst/goom2k1/gstgoom.h:
+	  goom/goom2k1: remove obsolete left over files
+	  They now use the new GstAudioVisualizer base class
+	  from gst-plugins-base/gst-libs/gst/pbutils
+	  Also fixed undefined reference to gst_audio_visualizer_get_type
+	  Added GST_PLUGINS_BASE_LIBS to Makefile.am and re-order LIBADD.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742875
+
+2015-10-12 10:48:23 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: Fix buffer memory leak during failures
+	  mapped buffer is not being unmapped during failures
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756231
+
+2015-10-12 11:18:51 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	  souphttpclientsink: Check if soup message is created
+	  If soup message is not created then the same should not be passed
+	  on, which is resulting in segfault. Hence throwing a warning message
+	  and returning
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755326
+
+2015-10-12 11:15:15 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	  souphttpclientsink: Check if location being set is valid
+	  Adding a check in set_property to find if the location uri is valid
+	  and printing warning if not valid.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755326
+
+2015-10-12 11:09:30 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	  souphttpclientsink: Fix memory leaks during failures
+	  freeing streamheader_buffers and sent_buffers during failure cases.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755326
+
+2015-10-12 11:03:17 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	  souphttpclientsink: Replace redundant free_buffer_list function
+	  Removing free_buffer_list and replacing it with already available function
+	  g_list_free_full
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755326
+
+2015-10-11 16:40:01 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* tests/check/Makefile.am:
+	  check: Don't forget base CFLAGS for flvdemux check
+	  elements/flvdemux.c:25:25: fatal error: gst/tag/tag.h: No such file or directory
+
+2015-10-11 11:37:51 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/ebml-write.h:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: Create a TIME segment when creating streamable output
+	  Related to https://bugzilla.gnome.org/show_bug.cgi?id=754435 which
+	  does the same for flvmux.
+
+2015-09-23 13:50:52 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/flv/Makefile.am:
+	* gst/flv/gstflvdemux.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/flvdemux.c:
+	  flvdemux: output speex vorbiscomment as a GstTagList
+	  This is what speexdec expects.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755478
+
+2015-09-22 22:59:16 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/flv/gstflvmux.c:
+	* tests/check/elements/flvmux.c:
+	  flvmux: GST_BUFFER_OFFSETs should be GST_BUFFER_OFFSET_NONE
+	  Or else flvdemux don't understand it
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754435
+
+2015-09-02 10:44:59 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/flv/gstflvmux.c:
+	* tests/check/elements/flvmux.c:
+	  flvmux: use time segment and copy timestamps when streamable
+	  Add a basic test using speex data to verify timestamping.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754435
+
+2015-09-23 13:14:03 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: speex is also always 16KHz
+	  This is just a cosmetic change for the logs, since the right caps
+	  for Speex is being set elsewhere.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755479
+
+2015-07-14 15:19:44 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	  rtpmanager: Add 'source-stats' to stats and notify
+	  Add statitics from each rtp source to the rtp session property.
+	  'source-stats' is a GValueArray where each element is a GstStructure of
+	  stats for one rtp source.
+	  The availability of new stats is signaled via g_object_notify.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752669
+
+2015-06-05 17:20:33 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Implement sending of reduced size RTCP packets
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750456
+
+2015-10-08 15:01:13 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* gst/audiofx/audiodynamic.h:
+	  audiofx: Remove unused variable
+	  Remove unused variable 'degree' in audiodynamic
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756234
+
+2015-10-08 14:44:07 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix memory leak for corrupted file
+	  Free brands before overriding them.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756226
+
+2015-10-08 11:44:04 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* ext/gdk_pixbuf/gstgdkpixbufdec.c:
+	  gdkpixbufdec: Fix pixbuf_loader leak during failures
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756219
+
+2015-10-07 23:23:45 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Add missing break
+
+2015-10-07 13:03:02 +0200  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	* gst/rtpmanager/rtpstats.c:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpmanager: Take into account packet rate for max-dropout and max-misorder calculations
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751311
+
+2015-10-07 13:02:12 +0200  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpmanager: add "max-dropout-time" and "max-misorder-time" props
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751311
+
+2015-10-07 17:14:57 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Fix date memory leak
+	  When getting date from taglist, the memory should be freed after
+	  using it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756171
+
+2015-10-05 11:03:38 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Fix sample memory leak
+	  When getting sample from taglist, the memory should be freed after
+	  using it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=756068
+
+2015-10-05 13:10:56 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/cutter/gstcutter.c:
+	  cutter: Fix buffer leak
+	  Buffer is added to the internal cache, and pushed only when accumulated
+	  buffer duration crosses 200 ms. So when the chain ends, the buffer accumulated
+	  is not freed. Freeing the cache when the state changes from PAUSED to READY.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754212
+
+2015-08-31 21:10:16 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Use default upstream event handling
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752694
+
+2015-08-31 21:05:03 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	  rtpmux: As 0xFFFFFFFF is a valid ssrc, check if it has been set
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752694
+
+2015-07-22 09:47:22 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	* tests/check/elements/rtpmux.c:
+	  gstrtpmux: allow the ssrc-property to decide ssrc on outgoing buffers
+	  By not doing this, the muxer is not effectively a rtpmuxer, rather a
+	  funnel, since it should be a single stream that exists the muxer.
+	  If not specified, take the first ssrc seen on a sinkpad, allowing upstream
+	  to decide ssrc in "passthrough" with only one sinkpad.
+	  Also, let downstream ssrc overrule internal configured one
+	  We hence has the following order for determining the ssrc used by
+	  rtpmux:
+	  0. Suggestion from GstRTPCollision event
+	  1. Downstream caps
+	  2. ssrc-Property
+	  3. (First) upstream caps containing ssrc
+	  4. Randomly generated
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752694
+
+2015-10-02 22:42:20 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Fixup last commit
+
+2015-10-02 22:21:45 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	* gst/udp/gstudpsrc.c:
+	  Update GLib dependency to 2.40.0
+
+2015-06-30 16:56:19 +0200  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/rtpstats.c:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpstats: add utility for calculating RTP packet rate
+
+2015-08-10 18:14:39 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: handle empty segments in seeking adjust
+	  If seeking targets an empty segment skip it as there is no media
+	  offset to get from it. Instead look for the next one.
+	  This doesn't make seeking in push-mode work if you seek to an
+	  empty segment but at least won't get you to wrong offsets.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753484
+
+2015-04-17 14:25:43 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmuxsink: post messages when fragments are being opened and closed
+	  This can be useful for applications that need to track the created fragments
+	  (to log them in a recording database, for example)
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750108
+
+2015-04-29 18:23:28 +0100  Ramiro Polla <ramiro.polla@collabora.co.uk>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmuxsink: allow non-video streams to serve as reference
+	  In the absence of a video stream, the first stream will be used as
+	  reference.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753617
+
+2015-07-22 17:45:12 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: initialize mux_start_time properly
+	  mux_start_time refers to the running_time of the buffer
+	  that goes first in the output file. Normally this time is
+	  0, so this variable is initialized to 0 during the state
+	  change to PAUSED.
+	  However, when dealing with dynamic pipelines and starting
+	  a recording while the pipeline has already run for a while,
+	  the running_time of the first buffer is > 0 and this causes
+	  a problem with detecting the end of the first file(s) when
+	  splitting by duration, because the code will later compare
+	  the threshold_time with (last buffer running_time - mux_start_time)
+	  and will get it wrong until mux_start_time advances enough
+	  to make this difference < threshold_time, creating empty files
+	  in the meantime.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753624
+
+2015-09-16 16:03:02 +0900  Vineeth T M <vineeth.tm@samsung.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Reverse playback does not consider segment.start
+	  During reverse playback, the media should stop playing at segment.start
+	  This does not happen, and avidemux continues to process data even when
+	  current timestamp is less that segment.start.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755094
+
+2015-09-23 12:39:35 +0900  Manasa Athreya <manasa.athreya@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Check multi trex to find track id in mp4 mpeg-dash stream
+	  If stream has more than one trex box which is not matched to actual
+	  track id, it makes qtdemux crashed.
+	  Author : Manasa Athreya (manasa.athreya@lge.com)
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754864
+
+2015-09-04 14:24:45 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* gst/smpte/gstsmpte.c:
+	  smpte: get size, stride info using VideoInfo
+	  Use VideoInfo data to get size stride and
+	  offset, instead of hard coded macros.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754558
+
+2015-09-04 14:18:50 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* gst/smpte/gstsmpte.c:
+	  smpte: free mask
+	  Free the memory allocated to 'mask' to avoid
+	  memory leak.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754555
+
+2015-08-20 11:02:58 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* tests/examples/equalizer/demo.c:
+	* tests/icles/equalizer-test.c:
+	* tests/icles/gdkpixbufoverlay-test.c:
+	* tests/icles/gdkpixbufsink-test.c:
+	* tests/icles/test-oss4.c:
+	* tests/icles/videocrop-test.c:
+	  gstreamer: good: tests: Fix memory leaks when context parse fails.
+	  When g_option_context_parse fails, context and error variables are not getting free'd
+	  which results in memory leaks. Free'ing the same.
+	  And replacing g_error_free with g_clear_error, which checks if the error being passed
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753853
+
+2015-10-02 16:18:15 +0900  Hyunjun Ko <zzoon.ko@samsung.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: doesn't handle probation and rtp gap in case of sender
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754548
+
+2015-10-02 16:16:32 +0900  Hyunjun Ko <zzoon.ko@samsung.com>
+
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpsession.h:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpmanager: add new on-new-sender-ssrc, on-sender-ssrc-active signals
+	  Allows for applications to get internal source's RTP statistics.
+	  (eg. sender sources for a server/client)
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746747
+
+2015-10-02 14:17:48 +1000  Jan Schmidt <jan@centricular.com>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximagesrc: Gather and coalesce all damaged areas before retrieving.
+	  These days the xserver seems to give us the same damage regions
+	  over and over for entire windows, and we retrieve them multiple
+	  times, which gives time for more damage to appear. Instead, just
+	  quickly gather all damaged areas into a region list and copy
+	  out once.
+
+2015-10-01 16:24:32 +0100  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/goom2k1/Makefile.am:
+	* gst/goom2k1/gstgoom.h:
+	  goom2k1: use the new audiovisualizer base class
+	  Rebase to have goom using the GstAudioVisualizer base class in
+	  gst-plugins-base/gst-libs/gst/pbutils
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742875
+
+2015-10-01 16:16:08 +0100  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/goom/Makefile.am:
+	* gst/goom/gstgoom.h:
+	  goom: use the new audiovisualizer base class
+	  Rebase to have goom using the GstAudioVisualizer base class in
+	  gst-plugins-base/gst-libs/gst/pbutils
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742875
+
+2015-09-30 17:35:33 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/interleave/deinterleave.c:
+	* tests/check/elements/deinterleave.c:
+	  deinterleave: implement accept-caps
+	  Avoid using default accept-caps handler that will query downstream
+	  and is more expensive. Just check if the caps is compatible with
+	  the template and check if the channels are the same.
+
+2015-09-30 09:35:39 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/deinterleave.c:
+	  tests: deinterleave: also check for caps query results
+
+2015-09-30 12:30:59 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/interleave/deinterleave.c:
+	  deinterleave: use the caps query filter
+	  It was being ignored and would lead to wrong results if the
+	  element doing the query would rely on the intersection being made.
+
+2015-09-30 10:00:31 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/interleave/deinterleave.c:
+	  deinterleave: implement a caps query handler for the sinkpad
+	  It was missing and apparently code relied on having it there
+	  for not allowing a change in the number of channels
+
+2015-09-30 09:05:03 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/interleave/deinterleave.c:
+	  deinterleave: fix caps leak
+	  Caps from the pad template are being leaked. In any case it is
+	  from a static pad template and will 'leak' in the end, just doing
+	  the cleanup for the good practice.
+
+2015-09-29 11:15:01 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/gdkpixbufoverlay.c:
+	  tests: gdkpixbufoverlay: add minimal unit test
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755773
+
+2015-09-29 11:12:48 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	  gdkpixbufsink: don't leak old pixel buffer when setting a new overlay
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755773
+
+2015-09-28 20:25:22 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: avoid potential string overflow
+	  We don't necessarily have full control over the input tags, so
+	  it's possible that the ISRC tag contains a longer string than
+	  expected, in which case we'd write over the end of the static-size
+	  13 byte buffer that is FLAC__StreamMetadata_CueSheet_Track::isrc.
+	  Make sure to only copy the ISRC if it's not too long, and make
+	  sure the buffer we write to is always NUL-terminated by using
+	  g_strlcpy().
+	  CID 1324931.
+
+2015-09-28 18:03:51 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Remove leftover assertion from 0.10
+	  We now allocate memory via GstAllocator and as such can handle arbitrary
+	  alignments, not only <= G_MEM_ALIGN.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755708
+
+2015-09-25 10:01:37 +0200  Guillaume Marquebielle <guillaume.marquebielle@parrot.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: fix uninitialized variables in LOAS config reading
+	  On reading LOAS config, flag v=1 and vA=1 combination can occur, leading to warning
+	  "Spec says "TBD"...". Returning TRUE on this case while parameters 'sample_rate' and
+	  'channels' are pointing to uninitialized values can end on setting random values as
+	  rate and channels on src caps.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755611
+
+2015-09-18 00:58:23 +1000  Jan Schmidt <thaytan@noraisin.net>
+
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	  Fix some compiler warnings when building with G_DISABLE_ASSERT
+	  Touches rtpmanager and gdkpixbufsink
+
+2015-08-18 14:30:57 +0100  Chris Bass <floobleflam@gmail.com>
+
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_types.c:
+	  qtdemux: support timed-text subtitle tracks.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752818
+
+2015-09-26 00:12:46 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  gst: Don't use deprecated gst_segment_to_position()
+
+2015-09-21 13:47:21 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtpbin/rtpjitterbuffer/rtspsrc: Add property to set maximum ms between RTCP SR RTP time and last observed RTP time
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755125
+
+2015-09-16 19:28:11 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpbin/session: Allow RTCP sync to happen based on capture time or send time
+	  Send time is the previous behaviour and the default, but there are use cases
+	  where you want to synchronize based on the capture time.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755125
+
+2015-09-25 23:51:09 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.6.0 ===
+
+2015-09-25 23:15:55 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.6.0
+
+2015-09-25 22:57:34 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2015-09-25 14:08:09 +0200  Thibault Saunier <tsaunier@gnome.org>
+
+	* gst/smpte/gstsmptealpha.c:
+	  smptealpha: Do not set width/height before comparing with old values
+	  Otherwise we end up considering the values did not change and we wrongly
+	  work with the old video format (which will lead to wrong
+	  behaviour/segfaults).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755621
+
+2015-09-23 20:59:00 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Accumulate segments for edit lists before activating the next segment
+	  eceb2ccc739092d964d78945e19c2ecedbd214e2 broke segment seeks by always
+	  accumulating segments manually when activating a segment. This is only
+	  needed when handling edit lists, not when activating a segment because of a
+	  seek. Do the accumulation when switching edit list segments instead.
+	  This fixes segment seeks again, while keeping edit lists playback working.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755471
+
+2015-09-23 17:43:51 +0530  Vikram Fugro <vikram.fugro@gmail.com>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: send phase values in the GstMessage for Phase info
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755463
+
+2015-09-22 00:46:01 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroska-mux: Don't output a warning on MONO multiview mode.
+
+2015-09-19 17:02:18 +0200  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	  rtptheoradepay: Fix memory leaks
+	  The same memory leaks were fixed in identical fashion for
+	  vorbisdepay in 06efeff5d979576a252e5dae57f46d6445b1df12 in 2009.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=755277
+
+2015-09-19 17:04:07 +0200  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	  rtp{vorbis,theora}{pay,depay}: Cosmetic cleanup
+	  * use g_list_free_full(), don't iterate elements maually when freeing
+	  * call gst_rtp_*_pay_clear_packet(), don't duplicate its code
+	  * use gst_buffer_unref() to clarify that it is buffers being released,
+	  instead of refering directly to gst_mini_object_unref()
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=755277
+
+2015-09-19 18:44:22 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	  rtp{vorbis,theora}pay: Store headers in the packet buffers lists, not a NULL buffer
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755265
+
+=== release 1.5.91 ===
+
+2015-09-18 19:33:13 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.5.91
+
+2015-09-18 19:23:57 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2015-09-18 11:50:31 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/zh_CN.po:
+	  po: Update translations
+
+2015-09-17 10:50:01 +0900  Eunhae Choi <eunhae1.choi@samsung.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Fix taglist leak
+	  gst_tag_list_insert() does not take ownership of the inserted taglist.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=755138
+
+2015-09-16 07:05:36 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Skip LOAS AAC until a valid config is seen.
+	  It's normal when dropping into the middle of a stream to
+	  not always have the config available immediately, so skip LOAS
+	  until a valid config is seen without either setting invalid
+	  caps or erroring out.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751386
+
+2015-09-13 15:41:38 +0200  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: reset just a bit more upon flush_stop
+
+2015-09-13 15:40:09 +0200  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: remove dead struct member
+
+2015-09-11 17:09:28 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: fix GError memory leak when hostname resolution fails
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754869
+
+2015-09-10 15:26:54 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/matroska/ebml-write.c:
+	  matroskamux: drop HEADER flag from output buffers
+	  Drop HEADER flag from output buffers if they are not indeed
+	  headers.
+	  Fixes resending of headers in tcp connection handling
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754768
+
+2015-09-10 16:00:50 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/matroska/ebml-write.c:
+	  matroskamux: fix matroskamux ! matroskademux
+	  Don't carry over DISCONT flags from the input buffers to the
+	  output buffer, or the demuxer might reset its state when it
+	  receives the first data buffer just after parsing the simple
+	  block header, and then expect sane data to follow.
+	  Fixes matroskamux ! demux erroring out.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754768
+	  https://bugzilla.gnome.org/show_bug.cgi?id=657805
+
+2015-09-09 12:51:40 -0700  Martin Kelly <martin@surround.io>
+
+	* gst/rtsp/README:
+	  rtsp: fix small README typo
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754807
+
+2015-09-04 19:45:37 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/audioparsers/gstwavpackparse.c:
+	  wavpackparse: set both pts and dts so baseparse doesn't make up wrong dts after seeks
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752106
+
+2015-09-04 19:34:41 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: set both pts and dts so baseparse doesn't make up wrong dts after a seek
+	  flac contains the sample offset in the frame header, so after a seek
+	  without index flacparse will know the exact position we landed on and
+	  timestamp buffers accordingly. It only set the pts though, which means
+	  the baseparse-set dts which was set to the seek position prevails, and
+	  since the seek was based on an estimate, there's likely a discrepancy
+	  between where we wanted to land and where we did land, so from here on
+	  that dts/pts difference will be maintained, with dts possibly multiple
+	  seconds ahead of pts, which is just wrong. The easiest way to fix this
+	  is to just set both pts and dts based on the sample offset, but perhaps
+	  parsed audio should just not have dts set at all.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752106
+
+2015-09-06 16:33:02 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	  docs: remove properties and signals that no longer exist
+	  https://bugzilla.gnome.org/show_bug.cgi?id=726443
+
+2013-10-11 15:13:00 +0000  George Chriss <gschriss@gmail.com>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Make the element count in arrays not include end
+	  One-line removal of tags_written++
+	  This should fix rtmp output to crtmpserver, and hopefully
+	  noone is expecting that the element count includes the end
+	  element, as different bits of documentation say different
+	  things about whether it should or not.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=661624
+
+2015-07-30 00:59:15 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  flvmux: Store incoming bitrate tags and send in the metadata
+	  Apparently the Microsoft Azure RTMP server requires that the
+	  videodatarate and audiodatarate metadata be provided, so
+	  set those, even if it's to 0. Use the actual input bitrate
+	  tags if available.
+
+2015-09-04 00:06:29 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Don't parse key data more than needed.
+	  When an auxilliary streams are present in the SDP media,
+	  there's no need to re-parse the SDP attributes multiple
+	  times.
+
+2015-09-03 20:56:55 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Fix SRTP + RTX, auth access, a leak, and an invalid memory access.
+	  In parse_keymgmt(), don't mutate the input string that's been passed
+	  as const, especially since we might need the original value again if
+	  the same key info applies to multiple streams (RTX, for example).
+	  When a resource is 404, and we have auth info - retry with the auth
+	  info the same as if we had receive unauthorised, in case the resource
+	  isn't even visible until credentials are supplied.
+	  Fix a memory leak handling Mikey data.
+	  When generating a random keystring, don't overrun the 30 byte
+	  buffer by generating 32 bytes into it.
+
+2015-09-04 15:18:05 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Fix build with GLib < 2.44
+	  G_IO_ERROR_CONNECTION_CLOSED was added in 2.44.
+
+2015-09-04 12:01:52 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Ignore G_IO_ERROR_CONNECTION_CLOSED when receiving data
+	  This happens on Windows if we use the same socket for sending packets,
+	  and the remote sends ICMP port/host unreachable messages.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754534
+
+2015-09-02 21:12:41 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	  rtpvorbis/theoradepay: Fix handling of fragmented packets
+	  This was broken in b1089fb520 by not considering the full packet length of a
+	  fragmented packet but only the length of the first one.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754417
+
+2015-09-01 15:39:22 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  dtmfsrc: Reply to latency query
+
+2015-08-31 16:42:30 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* tests/check/elements/rtpsession.c:
+	  tests: Fix rtpsession test failure
+	  The time of the first RTCP packet is semi-random, so
+	  sometimes it was produced before enough packets from
+	  the second SSRC were received. First drop queued RTCP
+	  packets, then advance the clock enough to ensure
+	  that at least one new RTCP packet is produced.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750731
+
+2015-08-31 13:56:04 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/check/elements/level.c:
+	  level: improve the test for multi-channel mode
+	  Change the test to verify the read-index for multiple messages per buffer.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=754144
+
+2015-08-31 12:46:52 +0200  Jan Alexander Steffens (heftig) <jan.steffens@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Align raw video frames to 32 bytes
+	  Outputting unaligned video frames causes videoscale et al to
+	  crash when attempting SIMD-accelerated conversion.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736965
+
+2015-08-26 23:16:46 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/level/gstlevel.c:
+	  level: fix level calculations for mutliple channels
+	  This was broken with 7b90bf32150897a141a29a12ecab555d8c5b7fab.
+
+2015-08-27 10:28:55 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* gst/smpte/gstsmpte.c:
+	  smpte: Fix memory leak
+	  In gst_smpte_collected(), check upfront if input formats are same
+	  or not. This avoids allocation of in1 and in2 buffers and
+	  subsequent memory leak when input formats do not match.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=754153
+
+2015-08-21 11:52:19 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: souphttpsrc: don't try to connect to dead radio server
+
+2015-08-21 16:29:16 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Trivial fix to check correct condition
+	  When checking for describe method, because of missing parentheses, wrong
+	  condition is being checked, which will result in wrong behavior.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753912
+
+2015-08-21 13:19:02 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroska: read: fix tag list memory leak
+	  gst_toc_entry_merge_tags makes a new ref of the taglist, so it should
+	  be unref'ed as soon as the tags are merged to the tocentry
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753904
+
+2015-08-21 12:20:59 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* ext/wavpack/gstwavpackdec.c:
+	  wavpackdec: fix taglist memory leak
+	  When passing the taglist to gst_audio_decoder_merge_tags, the reference is increased
+	  by audiodecoder and the caller should free the taglist being passed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753903
+
+2015-08-20 14:45:33 +0200  Jean-Michel Hautbois <jean-michel.hautbois@veo-labs.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: fix pad closing
+	  Signed-off-by: Jean-Michel Hautbois <jean-michel.hautbois@veo-labs.com>
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753875
+
+=== release 1.5.90 ===
+
+2015-08-19 13:29:53 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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.signals:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.5.90
+
+2015-08-19 12:47:42 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2015-08-19 11:29:55 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/el.po:
+	* po/zh_CN.po:
+	  po: Update translations
+
+2015-08-13 17:29:58 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/multifile/gstmultifilesrc.c:
+	  multifilesrc: fix regression with starting from index set via index property
+	  When we haven't started yet, set the start_index when we set the index property,
+	  so that we start at the right index position after the initial seek. The index
+	  property was never really meant to be for writing, but it used to work, so let's
+	  support it for backwards compatibility.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739472
+
+2015-08-18 10:52:11 +0100  Alex Ashley <bugzilla@ashley-family.net>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix offset calculation when parsing CENC aux info
+	  Commit 7d7e54ce6863ff53e188d0276d2651b65082ffdb added support for
+	  DASH common encryption, however commit
+	  bb336840c0b0b02fa18dc4437ce0ded3d9142801 that went onto master
+	  shortly before the CENC commit caused the calculation of the CENC
+	  aux info offset to be incorrect.
+	  The base_offset was being added if present, but if the base_offset
+	  is relative to the start of the moof, the offset was being added twice.
+	  The correct approach is to calculate the offset from the start of the
+	  moof and use that offset when parsing the CENC aux info.
+
+2015-08-17 14:28:24 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: actually return true for accept-caps query handling
+
+2015-08-17 14:07:10 +0900  Hyunjun Ko <zzoon.ko@samsung.com>
+
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtpklvpay.c:
+	  rtp: copy metadata in the (de)payloaders which is missed before
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753706
+
+2015-08-16 15:21:51 -0400  Dustin Spicuzza <dustin@virtualroadside.com>
+
+	* configure.ac:
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/directsound/gstdirectsoundsink.h:
+	  directsoundsink: allow specifying audio playback device
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753670
+
+2015-08-16 13:51:47 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: remove single entry if from loop
+	  Iterate from the 2nd channel on and create the 1 channel struct
+	  outside to make loop structure simpler and only slightly faster.
+
+2015-08-16 13:21:41 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: implement proper accept-caps
+	  Should just compare with what can be immediatelly accepted by
+	  the element. flacenc can't renegotiate so if it has a caps already
+	  it should only accept if it is that caps otherwise just use the
+	  template caps
+
+2015-08-16 13:03:36 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: improve sink pad template caps
+	  Removes the need for custom caps query handling and makes it more
+	  correct from the beginning on the template. It is a bit uglier
+	  to read because there is 1 entry per channel but makes code easier
+	  to maintain.
+
+2015-08-16 12:41:56 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/y4m/gsty4mencode.c:
+	  y4mencode: fix gst-launch version in documentation
+
+2015-08-15 22:32:21 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/speex/gstspeexenc.c:
+	* ext/wavpack/gstwavpackenc.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/mulaw-encode.c:
+	  audioencoders: use template subset check for accept-caps
+	  It is faster than doing a query that propagates downstream and
+	  should be enough
+	  Elements: speexenc, wavpackenc, mulawenc, alawenc
+
+2015-08-15 22:29:41 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/jpeg/gstjpegenc.c:
+	* ext/libpng/gstpngenc.c:
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp9enc.c:
+	* gst/y4m/gsty4mencode.c:
+	  videoencoders: use template subset check for accept-caps
+	  It is faster than doing a query that propagates downstream and
+	  should be enough
+	  Elements: jpegenc, pngenc, vp8enc, vp9enc, y4menc
+
+2015-08-16 17:21:24 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: use new baseparse API to fix tag handling
+	  https://bugzilla.gnome.org/show_bug.cgi?id=679768
+
+2015-03-17 17:50:37 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstsbcparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	  audioparsers: use new base parse API to fix tag handling
+	  https://bugzilla.gnome.org/show_bug.cgi?id=679768
+
+2015-08-16 14:37:53 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: use new baseparse API and fix tag handling
+	  https://bugzilla.gnome.org/show_bug.cgi?id=679768
+
+2015-08-16 13:04:02 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Use signed integer type to be able to check for negative subtraction results
+	  CID 1315829
+
+2015-08-16 11:50:34 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtpvorbisdepay.c:
+	  rtpvorbisdepay: remove dead code
+	  payload_buffer must be NULL in ignore_reserved. Check will always be false.
+	  Introduced by b1089fb5207697ba26edb4ff66ed0f465c6df3cf
+	  CID #1316476
+
+2015-08-15 22:45:53 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/law/alaw-encode.c:
+	* gst/law/alaw-encode.h:
+	  alawenc: port to AudioEncoder base class
+
+2015-08-15 09:16:23 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/flac/gstflacdec.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/wavpack/gstwavpackdec.c:
+	* gst/law/alaw-decode.c:
+	* gst/law/mulaw-decode.c:
+	  audiodecoders: use default pad accept-caps handling
+	  Avoids useless check of downstream caps when handling an
+	  accept-caps query
+	  Elements: flacdec, speexdec, wavpackdec, mulawdec, alawdec
+
+2015-08-15 08:49:57 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/libpng/gstpngdec.c:
+	* ext/vpx/gstvp8dec.c:
+	* ext/vpx/gstvp9dec.c:
+	  videodecoders: use default pad accept-caps handling
+	  Avoids useless check of downstream caps when handling an
+	  accept-caps query
+	  Elements: jpegdec, pngdec, vp8dec, vp9dec
+
+2015-08-15 11:31:04 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/law/alaw-decode.c:
+	  alawdec: make error handling a bit nicer
+	  Print the element along with the debug to make it easier to trace
+	  the failures
+
+2015-08-15 11:04:16 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-decode.h:
+	  alawdec: port to audiodecoder base class
+	  mulawdec was already ported, alawdec was left behind.
+
+2015-08-15 10:34:14 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: only look for more samples in moofs in pull-mode
+	  For playback of some fragmented formats with qtdemux it will
+	  try to look for the next moof after finishing one but it is only
+	  possible for pull-mode. For playback of streaming fragmented formats
+	  such as DASH it should just not try to look for another moof but
+	  instead wait for more data.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752602
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752603
+
+2015-08-15 12:58:50 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstdcaparse.c:
+	  dcaparse: Don't look for a second syncword
+	  There are streams out there that consistently contain garbage between
+	  every frame so we never ever find a second consecutive syncword.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=738237
+
+2015-08-15 11:12:05 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp9enc.c:
+	  vp8enc, vp9enc: reset multipass file index when stopping encoder
+	  Fixes multipass encoding when re-using the same element/pipeline
+	  for subsequent encoding runs.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747728
+
+2015-08-15 11:09:42 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/vpx/gstvp9enc.c:
+	* ext/vpx/gstvp9enc.h:
+	  vp9enc: provide support for multiple pass cache files
+	  Some files may provide different caps insight of one stream. Since
+	  vp9enc support caps reinit, we should support cache reinit too.
+	  If more then file cache file will be created, the naming will be:
+	  cache cache.1 cache.2 ...
+	  Based on patch by: Oleksij Rempel <linux@rempel-privat.de>
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747728
+
+2015-08-14 11:41:42 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/aacparse.c:
+	  tests: aacparse: use caps query instead of accept-caps
+	  The accept-caps query just does a shallow check at the current
+	  element while at this test we want it to also look at downstream.
+	  So use caps query there.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753623
+
+2015-08-14 11:40:22 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstsbcparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	  audioparsers: enable accept-template flag
+	  Do a quick check with the pad template caps as it is enough. Users
+	  should have figured the appropriate full caps on a previous caps query
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753623
+
+2015-08-14 15:46:53 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: send the User-Agent header
+	  Sometimes it is useful to know this information on the
+	  server side. Other popular implementations (vlc, ffmpeg, ...)
+	  also send this header on every message.
+	  This includes a new "user-agent" property that the user
+	  can set to use a custom User-Agent string. The default
+	  is "GStreamer/<version>"
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750101
+
+2015-08-14 15:42:42 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: wrap gst_rtsp_message_init_request in a local function
+	  This will allow adding common request initialization, like the
+	  user agent string, in just one place.
+
+2015-08-14 09:36:09 +0530  Prashant Gotarne <ps.gotarne@samsung.com>
+
+	* gst/audiofx/audioecho.c:
+	  audioecho: make sure buffer gets reallocated if max_delay changes
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753490
+
+2015-07-09 09:51:26 +0200  Oleksij Rempel <linux@rempel-privat.de>
+
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp8enc.h:
+	  vp8enc: provide support for multiple pass cache files
+	  Some files may provide different caps insight of one stream. Since vp8enc
+	  support caps reinit, we should support cache reinit too.
+	  If more then file cache file will be created, the naming will be:
+	  cache
+	  cache.1
+	  cache.2
+	  ...
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747728
+
+2015-04-15 22:51:51 +0200  Ramiro Polla <ramiro.polla@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4gdepay.c:
+	  rtpmp4gdepay: fix timestamps for RTP packets with multiple AUs
+	  Use constantDuration to calculate the timestamp of non-first AU in the
+	  RTP packet.
+	  If constantDuration is not present in the MIME parameters, its value
+	  must be calculated based on the timing information from two consecutive
+	  RTP packets with AU-Index equal to 0.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747881
+
+2015-08-14 06:43:13 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: remove unnecessary if, g_free is null safe
+
+2015-08-14 08:33:56 +0100  Alex Ashley <bugzilla@ashley-family.net>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: add property to set HTTP method
+	  To allow souphttpsrc to be use HTTP methods other than GET
+	  (e.g. HEAD), add a "method" property that is a string. If this
+	  property is not set, GET is used.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752413
+
+2015-08-14 11:13:01 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* tests/check/generic/states.c:
+	  check: Rename states unit test
+	  Makes it easier to differentiate from other modules states unit test
+
+2015-08-14 09:21:25 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/goom/gstaudiovisualizer.c:
+	* gst/goom/gstaudiovisualizer.h:
+	* gst/goom2k1/gstaudiovisualizer.c:
+	* gst/goom2k1/gstaudiovisualizer.h:
+	  goom: Rename get_type() function of base class to prevent symbol conflicts
+	  This is a problem when statically linking.
+
+2015-08-13 16:32:55 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Keep the DTS estimate if we got no DTS after a jitterbuffer reset
+	  Otherwise we will just output buffers without timestamps after a reset if no
+	  timestamps are provided by upstream, e.g. when using RTSP over TCP.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749536
+
+2015-08-12 17:16:01 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* gst/matroska/matroska-demux.h:
+	* gst/matroska/matroska-parse.h:
+	  matroska: Remove unused variable
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753556
+
+2015-08-04 20:59:17 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL24depay.c:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpg722depay.c:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtph261depay.c:
+	* gst/rtp/gstrtph261pay.c:
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpsbcdepay.c:
+	* gst/rtp/gstrtpsbcpay.c:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtptheorapay.h:
+	* gst/rtp/gstrtputils.c:
+	* gst/rtp/gstrtputils.h:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvorbispay.h:
+	* gst/rtp/gstrtpvp8depay.c:
+	* gst/rtp/gstrtpvp8pay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	  rtp: Copy metadata in the (de)payloader, but only the relevant ones
+	  The payloader didn't copy anything so far, the depayloader copied every
+	  possible meta. Let's make it consistent and just copy all metas without
+	  tags or with only the video tag.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751774
+
+2015-08-10 18:20:15 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix small typo in comment
+
+2015-08-10 16:19:18 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/goom2k1/gstgoom.c:
+	  goom2k1/doc: Fixup previous commit
+
+2015-08-10 15:55:19 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* gst/goom2k1/gstgoom.c:
+	* gst/goom2k1/gstgoom.h:
+	  goom2k1/doc: Use GstGoom2k1 namespace
+	  The doc generator isn't happy when we have class name clash. Simply
+	  use it's own namespace.
+
+2015-08-10 17:10:42 +0530  Prashant Gotarne <ps.gotarne@samsung.com>
+
+	* gst/audiofx/audioecho.c:
+	  audioecho: removed unused variable in set_property
+	  unused local variable 'delay' is removed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753450
+
+2015-08-10 12:45:27 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix suboptimal queue iteration code
+
+2015-08-09 17:25:45 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: don't use glib 2.44-only API
+
+2015-07-29 14:14:50 +0100  Alex Ashley <bugzilla@ashley-family.net>
+
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	* gst/isomp4/qtdemux_types.c:
+	  qtdemux: add support for ISOBMFF Common Encryption
+	  This commit adds support for ISOBMFF Common Encryption (cenc), as
+	  defined in ISO/IEC 23001-7. It uses a GstProtection event to
+	  pass the contents of PSSH boxes to downstream decryptor elements
+	  and attached GstProtectionMeta to each sample.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=705991
+
+2015-08-10 14:13:50 +0900  Hyunjun Ko <zzoon.ko@samsung.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: checking if depay has sps/pps nals before insertion
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753430
+
+2015-08-08 16:44:49 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: fix outdated comment
+	  The default behaviour was changed in the 0.10 -> 1.x
+	  transition, but the comment was not updated.
+
+2015-08-08 17:42:22 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtptheorapay.c:
+	  rtptheorapay: If flushing a packet failed, go out of the loop immediately
+
+2015-08-08 17:41:02 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	  rtpvorbispay: If flushing a packet failed, go out of the loop immediately
+
+2015-08-08 17:34:50 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtptheorapay.h:
+	  rtptheorapay: Extract pixel format from the ident header to put it into the sampling field of the caps
+	  We always put 4:2:0 into the caps before, which obviously is wrong for 4:2:2
+	  and 4:4:4 formats.
+
+2015-08-06 17:46:13 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtp/gstrtpklvdepay.c:
+	* gst/rtp/gstrtpklvpay.c:
+	  rtpklv(de)pay: add "RTP" in the klass string
+	  GstRTSPMedia uses this classification to detect the real payloader
+	  inside a dynpay bin and asserts if it doesn't find it, therefore
+	  it is required
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753325
+
+2015-08-05 11:13:09 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/rtpaux.c:
+	  tests: rtpaux: use a dynamic pt in the test
+	  1) Tests that using dynamic PT instead of the default ones work
+	  2) If we ever decide to change the codec here we don't need to
+	  worry about change the PT for the default one of the new codec
+	  in the test
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746445
+
+2015-08-05 10:53:15 +0900  Hyunjun Ko <zzoon.ko@samsung.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: print valid type where guint32 is expected
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746445
+
+2015-08-06 11:33:37 +0900  Hyunjun Ko <zzoon.ko@samsung.com>
+
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtph261pay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmupay.c:
+	  rtppayload: set standard payload type as default
+	  Initialize the PT to the default value of the codec and check if
+	  it is still the default before declaring the pt to be dynamic or
+	  not when setting the caps.
+	  Also use the PT constants from the rtp lib when possible
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747965
+
+2015-07-26 12:07:56 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: store the moof-offset also for push mode
+	  It will be used in some cases for getting the correct offsets
+	  from trun atoms.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752603
+
+2015-07-26 02:09:24 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_types.h:
+	  qtdemux: handle default-base-is-moof flag
+	  Handle the flag from the tfhd that signals the base offset to
+	  start from the moof atom
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752603
+
+2015-07-29 18:54:35 -0600  Glen Diener <grd@loganmill.net>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroskademux: Preserve forward referenced track tags
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752850
+
+2015-08-04 18:07:35 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/rtpaux.c:
+	  tests: rtpaux: fix test failure
+	  The RTP PT for alaw is 8.
+	  Less than 50 packets are received in the length of this test so it
+	  would never drop a buffer or would drop only the last buffer and
+	  it would fail sometimes when the received wouldn't receive the
+	  retransmission packet in time.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746445
+
+2015-08-04 20:59:17 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpstreamdepay.c:
+	  rtpstreamdepay: Only allow activation in push mode
+	  We need a proper caps event from upstream with the full RTP caps as we can't
+	  create caps ourselves from thin air. Fixes usage of rtpstreamdepay after e.g.
+	  a filesrc or any other element that supports pull mode.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753066
+
+2015-08-04 16:28:17 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  soup: fix typo in translated string
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753240
+
+2015-08-04 12:25:46 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: Put the profile and level into the caps
+
+2015-08-04 12:09:12 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: Only update the srcpad caps if something else than the codec_data changed
+	  h264parse does the same, let's keep the behaviour consistent. As we now
+	  include the codec_data inside the stream too here, this causes less caps
+	  renegotiation.
+
+2015-08-04 11:48:27 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: PPS replaces and old PPS if it has the same id, independent of SPS id
+	  The spec says:
+	  When a picture parameter set NAL unit with a particular value of
+	  pic_parameter_set_id is received, its content replaces the content of the
+	  previous picture parameter set NAL unit, in decoding order, with the same
+	  value of pic_parameter_set_id (when a previous picture parameter set NAL unit
+	  with the same value of pic_parameter_set_id was present in the bitstream).
+
+2015-08-03 13:45:59 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: remove extra \n at debug message
+
+2015-08-03 13:42:20 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: prevent deadlock when states change too fast
+	  If the GOP is completed, pads have to start gathering for the
+	  next one but it is possible that the the state might go to
+	  COLLECTING_GOP_START and back to WAITING_GOP_COMPLETE before the
+	  thread has a chance to wake up and proceed, leaving it trapped in
+	  the check_completed_gop loop and deadlocking the other threads
+	  waiting for it to advance.
+	  To solve it, this patch also checks that tha input running time
+	  hasn't changed to prevent this scenario.
+
+2015-08-03 17:55:01 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: Insert SPS/PPS NALs into the stream
+	  h264parse does the same and this fixes decoding of some streams with 32 SPS
+	  (or 256 PPS). It is allowed to have SPS ID 0 to 31 (or PPS ID 0 to 255), but
+	  the field in the codec_data for the number of SPS or PPS is only 5 (or 8) bit.
+	  As such, 32 SPS (or 256 PPS) are interpreted as 0 everywhere.
+	  This looks like a mistake in the part of the spec about the codec_data.
+
+2015-07-30 11:29:27 +0900  Eunhae Choi <eunhae1.choi@samsung.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: handle empty http proxy string
+	  1) If the system http_proxy environment variable is not set
+	  or set to an empty string, we must not set proxy to avoid
+	  http connection error.
+	  2) In case of proxy property setting, if user want to clear
+	  the proxy setting, they should be able to set it to NULL or
+	  an empty string again, so this is fixed too.
+	  3) Check if the proxy string was parsed correctly.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752866
+
+2015-07-29 15:46:20 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* ext/dv/gstdvdemux.c:
+	* ext/dv/gstdvdemux.h:
+	  dvdemux: remove unused variable
+	  Remove unused variable 'framecount' from dvdemux
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753008
+
+2015-07-30 15:32:09 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: assertion error due to wrong condition check
+	  In media to caps function, reserved_keys array is being used for variable i,
+	  leading to GLib-CRITICAL **: g_ascii_strcasecmp: assertion 's1 != NULL' failed
+	  changed it to variable j
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753009
+
+2015-07-30 15:21:20 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/rtp/gstrtpmp4vdepay.c:
+	  rtpmp4vdepay: rtpbuffer is being unref'ed twice
+	  process_rtp_packet doesn't transfer the rtp buffer to mp4v_process_depay
+	  the refernce should not be removed here
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753042
+
+2015-07-29 11:26:46 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Strip keys from the fmtp that we use internally in our caps
+	  Skip keys from the fmtp, which we already use ourselves for the
+	  caps. Some software is adding random things like clock-rate into
+	  the fmtp, and we would otherwise here set a string-typed clock-rate
+	  in the caps... and thus fail to create valid RTP caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=753009
+
+2015-07-29 19:28:33 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Support mpegtsmux as a muxer.
+	  As a fallback, look for a pad template sink_%d on
+	  the muxer when requesting pads, to support mpegtsmux
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752999
+
+2015-06-25 01:35:27 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	* gst/multifile/gstsplitmuxpartreader.h:
+	  splitmuxsrc: Use a separate lock to delay typefind.
+	  Don't hold the main splitmux part lock over
+	  the parent state change function, as it prevents
+	  posting error messages that happen. Since the purpose
+	  is to prevent typefinding from proceeding, use a
+	  separate mutex just for that.
+
+2015-07-29 13:43:50 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroska: fix memory leak
+	  After adding to tag list, key_val is not being free'd
+	  resulting in memory leak
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752992
+
+2015-07-27 13:34:14 +0900  Manasa Athreya <manasa.athreya@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix 16-bit PCM audio advertised with 'raw ' fourcc
+	  'NONE' and 'raw ' fourcc don't always contain U8 audio, it can
+	  be more bits as well, in which case it's just like 'twos'.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752613
+
+2015-07-24 15:10:05 +0200  Dimitrios Katsaros <patcherwork@gmail.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: Allow framerate to be large then 100pfs
+	  This limit was arbitrary. We still fixate near 100pfs for compatibility.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752825
+
+2015-07-25 03:25:28 -0400  Olivier Crête <olivier.crete@ocrete.ca>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Stop without posting error on flushing
+	  This could just be a normal pipeline shutdown.
+
+2015-07-23 15:00:08 +0900  Hyunjun Ko <zzoon.ko@samsung.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: set GST_BUFFER_COPY_FLAGS to copy flags also
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752618
+
+2015-07-16 18:09:30 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/matroskademux.c:
+	  tests: add minmal matroskademux test for subtitle output
+	  Some of the subtitle chunks will have embedded
+	  NUL-terminators (last three), some don't (first three),
+	  some will have markup, some won't, some will be valid
+	  UTF-8 (all but last), some won't (last stanza).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752421
+
+2015-07-16 18:49:26 +0300  Dimitrios Christidis <dchristidis@mykolab.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: fix for subtitle buffers with NUL terminators
+	  Commit 45892ec8 created a regression where g_utf8_validate() would fail
+	  if the subtitle buffer had a NUL terminator as part of the data.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752421
+
+2015-07-21 13:31:05 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtp/gstrtpvp8depay.c:
+	  rtpvp8depay: Check available bytes before copy
+	  Need to check that the number of bytes we want to copy from the adapter
+	  actually is available and handle the error case gracefully. This error
+	  may happen if malformed packets are received and we don't have a
+	  complete frame.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752663
+
+2015-07-16 09:32:36 +0900  Paul Hyunil <paul.hyunil@lge.com>
+
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Support subtitle when track subtype is fourcc_subt
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752655
+
+2015-07-20 16:59:40 +0800  Song Bing <b06498@freescale.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Set timestamp when queue buffer.
+	  Should set timestamp when queue buffer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752618
+
+2015-07-16 15:12:17 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* tests/check/elements/rtpmux.c:
+	  rtpmux: handle different ssrc's on sinkpads
+	  Do this by not putting the ssrc from the src pads in the caps used to
+	  probe other sinkpads, and then  intersecting with it later.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752491
+
+2015-07-16 17:19:03 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/avi/gstavimux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/webm-mux.c:
+	  Update mailing list address from sourceforge to freedesktop
+
+2015-07-15 13:44:52 +0300  Dimitrios Christidis <dchristidis@mykolab.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: fix trailing '*' displayed with some text subtitles
+	  The subtitle buffer we push out should not include a NUL terminator
+	  as part of the data, we just add such a terminator for safety, but
+	  it should not be included in the buffer size.
+	  A NUL terminator is not valid UTF-8, so checks will fail if it's
+	  included in the size, and the NUL will be replaced by the fallback
+	  character specified when converting, i.e. '*'.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752421
+
+2015-07-15 18:23:05 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* ext/pulse/pulsedeviceprovider.c:
+	* ext/pulse/pulseutil.c:
+	* ext/pulse/pulseutil.h:
+	  pulse: add properties to GstDevice
+	  Add the extra properties we get from pulse to the GstDevice we expose
+	  with the device monitor
+
+2015-07-15 17:20:20 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* gst/audiofx/audioinvert.c:
+	* gst/audiofx/audiowsincband.c:
+	  audiofx: Fix typo in example pipelines
+	  Fix typo in example pipelines of audiowsincband and audioinvert.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752416
+
+2015-04-15 18:27:04 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: add a "format-location" signal that allows better control over filenames
+	  In certain applications, splitting into files named after a base
+	  location template and an incremental sequence number is not enough.
+	  This signal gives more fine-grained control to the application to
+	  decide how to name the files.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750106
+
+2015-04-15 20:13:27 +0300  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxcoreaudio.c:
+	  osxaudiosrc: no resampling on OS X
+	  Unlike Remote IO, AUHAL doesn't have built-in resampling
+	  for sources -- confirmed by Core Audio engineer Doug Wyatt:
+	  http://lists.apple.com/archives/coreaudio-api/2006/Sep/msg00088.html
+	  https://bugzilla.gnome.org/show_bug.cgi?id=743758
+
+2015-04-15 18:29:14 +0300  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxcoreaudio.c:
+	  osxaudiosrc: avoid get_channel_layout
+	  This only produces a warning and serves no purpose.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=743758
+
+2015-04-07 15:40:14 +0530  Arun Raghavan <arun@centricular.com>
+
+	* sys/osxaudio/gstosxcoreaudio.c:
+	  osxaudio: Avoid making a duplicate structure in caps for mono/stereo case
+	  For 1ch or 2ch devices, we just need to set the caps to allow both
+	  options since CoreAudio will up/downmix appropriately.
+	  Also fixes the condition for the 2ch case to be exact, rather than at
+	  least 2 channels since the downmix will not take place in the >stereo
+	  case.
+
+2015-04-06 16:22:34 +0530  Arun Raghavan <arun@centricular.com>
+
+	* sys/osxaudio/gstosxcoreaudio.c:
+	* sys/osxaudio/gstosxcoreaudiocommon.c:
+	* sys/osxaudio/gstosxcoreaudiohal.c:
+	* sys/osxaudio/gstosxcoreaudioremoteio.c:
+	  osxaudio: Don't set the format on an initialized AudioUnit
+	  We need to initialize the AudioUnit early to be able to probe the
+	  underlying device, but according to the AudioUnitInitialize() and
+	  AudioUnitUninitialize() documentation, format changes should be done
+	  while the AudioUnit is uninitialized. So we explicitly uninitialize the
+	  AudioUnit during a format change and reinitialize it when we're done.
+
+2015-04-06 15:55:59 +0530  Arun Raghavan <arun@centricular.com>
+
+	* sys/osxaudio/gstosxaudioringbuffer.c:
+	* sys/osxaudio/gstosxcoreaudio.c:
+	* sys/osxaudio/gstosxcoreaudio.h:
+	  osxaudio: Minor spelling fix (unitialize -> uninitialize)
+
+2015-03-21 20:34:25 +0200  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxaudio/gstosxcoreaudio.c:
+	* sys/osxaudio/gstosxcoreaudio.h:
+	  osxaudio: Fix lockup in _audio_unit_property_listener
+	  _audio_unit_property_listener is called either from a Core Audio thread
+	  or as a result of a Core Audio API (e.g. AudioUnitInitialize)
+	  from our own thread. In the latter case, osxbuf can be already locked
+	  (GStreamer's mutex is not recursive).
+	  We introduce the flag cached_caps_valid and use it instead of nullifying
+	  cached_caps when we cannot lock on osxbuf.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=743758
+
+2015-03-12 12:15:12 +0200  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxcoreaudio.c:
+	  osxaudio: Invalidate cached caps on format change
+	  Listen for changes in hardware stream format and channel layout, and
+	  invalidate cached caps (since they contain the preferred caps).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=743758
+
+2015-03-09 23:34:06 +0200  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxaudioringbuffer.c:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosink.h:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxaudio/gstosxaudiosrc.h:
+	* sys/osxaudio/gstosxcoreaudio.c:
+	* sys/osxaudio/gstosxcoreaudio.h:
+	* sys/osxaudio/gstosxcoreaudiocommon.c:
+	* sys/osxaudio/gstosxcoreaudiocommon.h:
+	* sys/osxaudio/gstosxcoreaudiohal.c:
+	* sys/osxaudio/gstosxcoreaudioremoteio.c:
+	  osxaudio: Overhaul of probing caps
+	  - Probing caps is unified between source and sink
+	  - Hardware stream format is now reported as preferred capabilities
+	  (dynamically updated when hardware configuration changes)
+	  - Get hardware channel layout from Remote IO just like from HAL
+	  - More comprehensive mapping between AudioChannelLabel and
+	  GstAudioChannelPosition
+	  - Support for unpositioned channel layouts
+	  - Announce stereo-mono upmixing/downmixing in caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=743758
+
+2015-03-09 23:15:56 +0200  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxcoreaudio.c:
+	  osxaudio: AudioUnitInitialize on open
+	  Call AudioUnitInitialize upon open. Otherwise, we cannot get
+	  (hardware) stream format nor channel layout from the outer scope.
+
+2015-07-12 14:27:15 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL24depay.c:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpg722depay.c:
+	* gst/rtp/gstrtpg723depay.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtph261depay.c:
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpklvdepay.c:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmparobustdepay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpsbcdepay.c:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvp8depay.c:
+	  rtp: depayloaders: implement process_rtp_packet() vfunc
+	  For more optimised RTP packet handling: means we don't
+	  need to map the input buffer again but can just re-use
+	  the mapping the base class has already done.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750235
+
+2015-05-27 19:19:27 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  rtpvrawdepay: implement process_rtp_packet() vfunc
+	  For more optimised RTP packet handling: means we don't
+	  need to map the input buffer again but can just re-use
+	  the map the base class has already done.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750235
+
+2015-07-10 00:13:32 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Fix indention
+
+2015-07-09 23:59:10 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Always estimate DTS from the current clock time
+	  Estimating it from the RTP time will give us the PTS, so in cases of PTS!=DTS
+	  we would produce wrong DTS. As now the estimated DTS is based on the clock,
+	  don't store it in the jitterbuffer items as it would otherwise be used in the
+	  skew calculations and would influence the results. We only really need the DTS
+	  for timer calculations.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749536
+
+2015-07-09 09:26:09 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/.gitignore:
+	  gitignore: ignore rtph263 test
+
+2015-07-08 23:47:44 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: fix build error with gcc (Debian 4.9.2-21) 4.9.2
+	  Replace static constants with macros to make gcc happy
+	  CC       elements/elements_rtpjitterbuffer-rtpjitterbuffer.o
+	  elements/rtpjitterbuffer.c:387:1: error: initializer element is not constant
+	  static const GstClockTime PCMU_BUF_DURATION = PCMU_BUF_MS * GST_MSECOND;
+	  ^
+	  elements/rtpjitterbuffer.c:388:1: error: initializer element is not constant
+	  static const guint PCMU_BUF_SIZE = 64000 * PCMU_BUF_MS / 1000;
+	  ^
+	  elements/rtpjitterbuffer.c:390:5: error: initializer element is not constant
+	  PCMU_BUF_CLOCK_RATE * PCMU_BUF_MS / 1000;
+
+2015-07-08 23:40:45 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: run indent and fix some comments
+	  Fix indent on this file and break some comment lines into two to make
+	  it fit 80 chars per line
+
+2015-07-08 15:02:24 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: rework segment event handling for adaptive streaming
+	  When a new time segment is received upstream is going to restart
+	  with a new atom. Make the neededbytes and todrop variables
+	  reflect that to avoid waiting too much or dropping the
+	  initial bytes that contain the header.
+
+2015-07-08 12:35:55 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: push data from adapter before starting new segment
+	  The adapter might have data remaining from the previous segment,
+	  push it all before clearing the adapter and starting a new segment.
+	  It can accumulate data if it had pushed and got not-linked, returning
+	  immediately without processing all the data. Before starting a new
+	  segment this data should be handled.
+
+2015-07-08 19:59:13 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Calculate DTS from the clock if we had none for the first packet after a reset
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749536
+
+2015-07-08 21:08:36 +0200  Havard Graff <havard.graff@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: fix gap-time calculation and remove "late"
+	  The amount of time that is completely expired and not worth waiting for,
+	  is the duration of the packets in the gap (gap * duration) - the
+	  latency (size) of the jitterbuffer (priv->latency_ns). This is the duration
+	  that we make a "multi-lost" packet for.
+	  The "late" concept made some sense in 0.10 as it reflected that a buffer
+	  coming in had not been waited for at all, but had a timestamp that was
+	  outside the jitterbuffer to wait for. With the rewrite of the waiting
+	  (timeout) mechanism in 1.0, this no longer makes any sense, and the
+	  variable no longer reflects anything meaningful (num > 0 is useless,
+	  the duration is what matters)
+	  Fixed up the tests that had been slightly modified in 1.0 to allow faulty
+	  behavior to sneak in, and port some of them to use GstHarness.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=738363
+
+2015-06-30 11:21:31 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  Revert "rtpjitterbuffer: Fix expected_dts calc in calculate_expected"
+	  This reverts commit 05bd708fc5e881390fe839803b53144393d95ab0.
+	  The reverted patch is wrong and introduces a regression because there
+	  may still be time to receive some of the packets included in the gap
+	  if they are reordered.
+
+2015-07-07 23:53:02 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: flush samples before adding more from moof
+	  Avoids accumulating all samples from a fragmented stream that could
+	  lead to a 'index-too-big' error once it goes over 50MB of data. It
+	  could reach that before 2h of playback so it doesn't take that long.
+	  As upstream elements are providing data in time format they should
+	  be the ones that have more information about the full media index
+	  and should be able to seek if possible.
+
+2015-07-07 23:56:12 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: rename upstream_newsegment to upstream_format_is_time
+	  upstream_newsegment isn't really clear on what it means, it is set
+	  to TRUE when the upstream element sends a segment in TIME format, so
+	  rename it to be more clear about it.
+	  It is important to know this because it means that upstream has
+	  a notion of time and qtdemux is likely being driven by an upstream
+	  element that is reading from a higher level abstraction than a file,
+	  such as a DASH, MSS or DLNA element.
+
+2015-07-07 21:31:08 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix leak by flushing previous sample info from trak
+	  In fragmented streaming, multiple moov/moof will be parsed and their
+	  previously stored samples array might leak when new values are parsed.
+	  The parse_trak and callees won't free the previously stored values
+	  before parsing the new ones.
+	  In step-by-step, this is what happens:
+	  1) initial moov is parsed, traks as well, streams are created. The
+	  trak doesn't contain samples because they are in the moof's trun
+	  boxes. n_samples is set to 0 while parsing the trak and the samples
+	  array is still NULL.
+	  2) moofs are parsed, and their trun boxes will increase n_samples and
+	  create/extend the samples array
+	  3) At some point a new moov might be sent (bitrate switching, for example)
+	  and parsing the trak will overwrite n_samples with the values from
+	  this trak. If the n_samples is set to 0 qtdemux will assume that
+	  the samples array is NULL and will leak it when a new one is
+	  created for the subsequent moofs.
+	  This patch makes qtdemux properly free previous sample data before
+	  creating new ones and adds an assert to catch future occurrences of
+	  this issue when the code changes.
+
+2015-07-07 16:46:33 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix index size check and debug message
+	  It is allocating samples_count + n_samples, not only n_samples
+
+2015-07-08 17:02:05 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Calculate receive time if we don't have any
+	  This is required to properly schedule packet loss timers and make
+	  sure all our calculations work properly.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749536
+
+2015-07-08 15:13:17 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Handle seqnum gaps in TCP streams without erroring out or overflowing calculations
+	  That is, handle DTS==GST_CLOCK_TIME_NONE correctly.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749536
+
+2015-07-08 20:31:42 +0900  Vineeth T M <vineeth.tm@samsung.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix event leak
+	  when seek fails in avidemux, event is not being freed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752117
+
+2015-07-08 12:02:22 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtp/gstrtph263depay.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/rtph263.c:
+	  rtph263depay: Make sure payload is large enough
+	  Plus new unit test.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752112
+
+2015-07-08 08:59:49 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/rtp/gstrtpklvdepay.c:
+	  rtpklvdepay: fix printf format compiler warning
+	  v_len is of type guint64, but while print the value(16 + len_size + v_len)
+	  G_GSIZE_FORMAT is being used instead of G_GUINT64_FORMAT
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752100
+
+2015-07-07 20:25:47 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	  docs: add new RTP elements to docs
+
+2015-07-07 20:07:31 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/rtp-payloading.c:
+	  tests: rtp-payloading: add basic unit test for KLV payloading
+	  Also make it so that the mtu is always set if specified, not
+	  only in case of the rather weird bufferlist test code path.
+	  This allows us to easily make the payloader fragment a payload
+	  across multiple output packets by setting a small MTU on it.
+
+2015-07-07 19:58:42 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpklvdepay.c:
+	* gst/rtp/gstrtpklvdepay.h:
+	  rtpklvdepay: improve start detection and handle fragmented KLV units
+
+2015-07-05 20:25:10 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpklvdepay.c:
+	* gst/rtp/gstrtpklvdepay.h:
+	  rtp: add SMPTE 336M KLV metadata depayloader
+	  http://tools.ietf.org/html/rfc6597
+
+2014-08-09 10:08:42 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpklvpay.c:
+	* gst/rtp/gstrtpklvpay.h:
+	  rtp: add SMPTE 336M KLV metadata payloader
+	  http://tools.ietf.org/html/rfc6597
+
+2015-07-07 16:59:20 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/atomsrecovery.c:
+	* gst/isomp4/properties.h:
+	* gst/matroska/matroska-mux.c:
+	* gst/rtpmanager/rtpsource.c:
+	  docs: fix "Symbol name not found at the start of the comment block"
+	  Add symbols or change comment into a regular comment.
+
+2015-07-07 16:58:53 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/audioparsers/gstamrparse.h:
+	  docs: remove outdated doc strings
+
+2015-07-03 23:10:40 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  docs: add missing plugins and ensure master doc is sorted
+
+2015-07-07 15:54:41 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  Revert "imagefreeze: Remove impossible error condition"
+	  This reverts commit d46631c5c7312ad613397f8238c7a9714ae3ae94.
+	  pad only handle EOS events but not EOS flow, and will push the buffer again
+	  resulting in an assertion error. So we should not handle the buffer
+	  and return EOS flow.
+
+2015-07-07 15:50:50 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpg729depay.c:
+	  rtpg729depay: unmap rtp buffer in error path
+
+2015-07-07 15:48:40 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpg729pay.c:
+	  rtpg729pay: fix buffer leak
+	  The handle_buffer vfunc takes ownership of the input buffer.
+	  Fixes elements/rtp-payloading under valgrind.
+
+2015-07-02 08:52:43 +0200  Tobias Mueller <muelli@cryptobitch.de>
+
+	* gst/goom/goom_core.c:
+	  goom: Initialised variables to remove compiler warnings
+	  goom_core.c: In function 'goom_update':
+	  goom_core.c:685:5: error: 'param2' may be used uninitialized in this function [-Werror=maybe-uninitialized]
+	  goom_lines_switch_to (goomInfo->gmline2, mode, param2, amplitude, couleur);
+	  ^
+	  goom_core.c:684:5: error: 'param1' may be used uninitialized in this function [-Werror=maybe-uninitialized]
+	  goom_lines_switch_to (goomInfo->gmline1, mode, param1, amplitude, couleur);
+	  ^
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752053
+
+2015-07-07 09:18:39 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtph261pay.c:
+	  rtph261pay: fix indentation
+
+2015-07-06 19:11:00 +0900  Jimmy Ohn <yongjin.ohn@lge.com>
+
+	* gst/rtp/gstrtph261pay.c:
+	  rtph261pay: Fix uninitialized variable compiler error
+	  endpos variable does not correctly understand in the
+	  4.6.3 GCC version. So compile error appears when we do
+	  compile rtph261pay using jhbuild.
+	  This patch is fixed the compile error in 4.6.3 GCC version.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751985
+
+2014-11-12 12:08:58 +0100  Jan Alexander Steffens (heftig) <jsteffens@make.tv>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Handle seek flags properly
+	  Allows for non-keyframe seeks.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=738570
+
+2015-02-24 10:50:52 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: avoid looping reading the 'moof' atom forever
+	  It gets stuck if it only finds a moof and no mfra/mfro or moov
+	  atoms. Skip the moof to continue the parsing to have it either
+	  play or error out.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745089
+
+2015-06-26 13:24:17 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: improve error handling
+	  for files which have corrupted header, libflac is not able to
+	  process the metadata properly. We just try to ignore the error
+	  and continue with the processing, since metadata parsing is not
+	  making much of a difference to libflac
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751334
+
+2015-07-06 20:16:38 +0900  Hyunjun Ko <zzoon.ko@samsung.com>
+
+	* sys/ximage/ximageutil.c:
+	  ximagesrc: add meta transform function
+	  ximage metadata can't be transformed or copied, but provide an empty
+	  transformation function instead of NULL to allow unconditional calling
+	  of metas' transform functions.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751778
+
+2014-06-16 16:14:28 +0200  Stian Selnes <stian.selnes@gmail.com>
+
+	* gst/rtp/gstrtph263pdepay.c:
+	  rtph263pdepay: init debug category
+	  https://bugzilla.gnome.org/show_bug.cgi?id=752012
+
+2014-06-20 10:59:14 +0200  Stian Selnes <stian@pexip.com>
+
+	* gst/rtp/gstrtpvp8depay.c:
+	  rtpv8depay: ignore reserved bit in payload descriptor
+	  Draft 16 of "RTP Payload Format for VP8" states in section 4.2 that:
+	  R: Bit reserved for future use.  MUST be set to zero and MUST be
+	  ignored by the receiver.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751929
+
+2015-07-04 20:56:42 +0200  Stian Selnes <stian@pexip.com>
+
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* gst/rtp/gstrtph261depay.c:
+	* gst/rtp/gstrtph261pay.c:
+	  rtph261pay: rtph261depay: Add documentation
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751982
+
+2015-07-03 21:58:14 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From f74b2df to 9aed1d7
+
+2015-07-03 14:29:16 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtph261pay.c:
+	  rtph261pay: Fix compiler warning
+	  gstrtph261pay.c: In function 'gst_rtp_h261_pay_class_init':
+	  gstrtph261pay.c:1003:17: error: variable 'gobject_class' set but not used [-Werror=unused-but-set-variable]
+	  GObjectClass *gobject_class;
+
+2015-07-03 14:03:05 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtph261depay.c:
+	  rtph261depay: Let the base class push the buffer so it can deal with the flow return
+
+2015-07-03 14:11:35 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtph261pay.c:
+	  rtph261pay: Remove unused adapter
+
+2015-07-03 13:17:24 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpspeexpay.c:
+	  speexpay: Directly attach payload to the output buffer instead of copying it
+
+2015-07-03 13:07:20 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	  sbcpay: Attach payload directly to the output instead of copying
+
+2014-12-01 14:18:40 +0100  Stian Selnes <stian@pexip.com>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtph261depay.c:
+	* gst/rtp/gstrtph261depay.h:
+	* gst/rtp/gstrtph261pay.c:
+	* gst/rtp/gstrtph261pay.h:
+	* tests/check/elements/rtp-payloading.c:
+	  rtp: add H.261 RTP payloader and depayloader
+	  Implementation according to RFC 4587.
+	  Payloader create fragments on MB boundaries in order to match MTU size
+	  the best it can. Some decoders/depayloaders in the wild are very strict
+	  about receiving a continuous bit-stream (e.g. no no-op bits between
+	  frames), so the payloader will shift the compressed bit-stream of a
+	  frame to align with the last significant bit of the previous frame.
+	  Depayloader does not try to be fancy in case of packet loss. It simply
+	  drops all packets for a frame if there is a loss, keeping it simple.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751886
+
+2015-07-03 12:18:52 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpmpvdepay.c:
+	  rtpmpvdepay: Don't forget to unmap the input buffer
+
+2015-07-03 12:14:47 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpmpvpay.c:
+	  rtpmpvpay: Create buffer lists instead of pushing each buffer individually
+
+2015-07-03 12:03:59 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpmpapay.c:
+	  rtpmpapay: Use buffer lists instead of pushing each fragment individually
+
+2015-07-03 10:51:57 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpmp4apay.c:
+	  rtpmp4apay: Create buffer lists and don't copy payload memory
+
+2015-06-29 16:14:18 +0200  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Consider timers len to compare with RTP_MAX_DROPOUT
+	  When there are a lot of small gaps, we can consider that there is
+	  a big gap (too losses) to reset the buffer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751636
+
+2015-06-29 15:53:52 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: If possible, always update the current time before looping over all timers
+	  If we have a clock, update "now" now with the very latest running time we have.
+	  If timers are unscheduled below we otherwise wouldn't update now (it's only updated
+	  when timers expire), and also for the very first loop iteration now would otherwise
+	  always be 0.
+	  Also the time is used for the timeout functions, e.g. to calculate any times
+	  for the next timeouts and we would otherwise pass too old times there.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751636
+
+2015-07-02 14:34:57 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: fix memory leak
+	  tmp needs to be freed before going out of scope in 'done'.
+	  CID #1308954
+
+2015-07-02 12:23:45 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtph263ppay.c:
+	  rtph263ppay: Generate buffer lists and attach the payload directly instead of copying it
+
+2015-07-02 09:48:02 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtph263pdepay.c:
+	  rtph263pdepay: Simplify code a bit and do less direct memcpy and let GstBuffer do that for us
+
+2015-07-02 09:17:59 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pay.h:
+	  rtph263pay: Stop using an adapter and directly use the buffer
+	  We always pushed one buffer into the adapter, then handled exactly that one
+	  buffer and flushed it from the adapter. Now also don't memcpy() the actual
+	  payload but just attach the input buffer's data to the output buffer.
+	  This code still needs some serious refactoring/rewriting.
+
+2015-07-01 21:57:28 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpgsmpay.c:
+	  rtpgsmpay: Remove non-existing includes for now
+	  git add -p mistake.
+
+2015-07-01 19:29:07 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: Use the return value of gst_buffer_append()
+
+2015-07-01 19:19:13 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpgsmpay.c:
+	  rtpgsmpay: Attach payload to the output buffer instead of copying it
+
+2015-07-01 17:58:56 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpg729pay.c:
+	  rtpg729pay: Attach payload directly to output buffers instead of copying
+
+2015-07-01 17:43:51 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpg723pay.c:
+	  rtpg723pay: Attach payload buffer to the output instead of copying
+
+2015-07-01 17:30:39 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpdvdepay.c:
+	  rtpdvdepay: Map the output buffer once instead of once every 80 bytes
+
+2015-07-01 21:46:46 +0900  Jimmy Ohn <yongjin.ohn@lge.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix return type of index_entry_offset_search()
+	  It's a compare function and may return a negative value,
+	  so should for correctness and consistency return a signed
+	  integer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751780
+
+2015-07-01 14:12:57 +0200  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: refactor handle_next_buffer
+	  The goal of this patch is making handle_next_buffer function
+	  more readable avoiding unnecesary gotos and adding other
+	  cosmetic changes.
+
+2015-07-01 15:40:25 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpac3pay.c:
+	  rtpac3pay: Attach the payload to the output buffer instead of copying it
+	  Might also want to produce buffer lists here if needed.
+
+2015-07-01 15:38:47 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpsirendepay.c:
+	  rtp: Fix indention
+
+2015-07-01 12:37:11 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/examples/rtp/Makefile.am:
+	* tests/examples/rtp/client-VP8-OPUS.sh:
+	* tests/examples/rtp/server-VTS-VP8-ATS-OPUS.sh:
+	  rtp: Add examples with VTS/ATS for VP8/OPUS
+	  Let's have an example with modern codecs.
+
+2015-06-30 18:11:33 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: Use GST_WARNING_OBJECT() instead of GST_WARNING()
+
+2015-06-30 14:06:20 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpvp8depay.c:
+	  vp8depay: Don't lock/map every non-keyframe buffer twice
+	  Just copy the complete header instead of first looking at the first byte
+	  and then at the remaining 10 bytes.
+
+2015-06-29 16:05:44 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: document fallthrough cases
+	  Pacify coverity and document fallthrough cases in switch statements.
+	  CID #1308948, #1308947, #1308946
+
+2015-06-29 10:36:58 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  Revert "rtpjitterbuffer: If we have an immediate timeout, don't try to find an earlier timeout"
+	  This reverts commit 0c21cd7177ea883c710999147ddcedb19004d182.
+	  If we have multiple immediate timers, we want to first handle the one with the
+	  lowest sequence number... which would be broken now.
+	  Instead of this we should just use a GSequence for the timers, and have them
+	  sorted first by timestamp, and for equal timestamps by sequence number. Then
+	  we would always only have to take the very first timer from the list and never
+	  have to look at any others.
+
+2015-06-29 10:14:05 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: If we have an immediate timeout, don't try to find an earlier timeout
+	  If we have lots of such immediate timeouts, we would otherwise have quadratic
+	  runtime in the number of timeouts.
+
+2015-06-19 18:01:03 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/multifile/gstsplitmuxsrc.c:
+	  splitmuxsrc: sticky events are sent automatically from the pad
+	  No need to send them explicitly from the element
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751240
+
+2015-06-19 18:00:40 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/multifile/gstsplitmuxsrc.c:
+	  splitmuxsrc: make sure to push sticky events before adding pad
+	  It allows the caps to be set on the pad before being added for
+	  dynamic autoplugging to work.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751240
+
+2015-06-26 00:05:29 +0900  Hyunjun Ko <zzoon.ko@samsung.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Add new ntp-time-source property and deprecate use-pipeline-clock property
+	  Enable to use new ntp-time-source property of rtpbin
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751496
+
+2015-06-25 23:19:58 +0900  Hyunjun Ko <zzoon.ko@samsung.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpbin/session: fix description
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751496
+
+2015-06-25 10:57:25 +0100  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/matroska/matroska-demux.c:
+	* tests/examples/shapewipe/shapewipe-example.c:
+	  docs: decodebin2 -> decodebin
+
+2015-06-25 10:47:06 +0100  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: update example pipeline
+	  Update reference to decodebin2 to decodebin
+
+2015-06-25 10:45:35 +0100  Luis de Bethencourt <luisbg@osg.samsung.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: remove dead assignments
+	  Values in fields_required and same_buffer are overwritten before used. Removing
+	  assignment
+
+2015-06-25 10:06:07 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/Makefile.am:
+	* ext/mikmod/Makefile.am:
+	* ext/mikmod/README:
+	* ext/mikmod/drv_gst.c:
+	* ext/mikmod/gstmikmod.c:
+	* ext/mikmod/gstmikmod.h:
+	* ext/mikmod/mikmod_reader.c:
+	* ext/mikmod/mikmod_types.c:
+	* ext/mikmod/mikmod_types.h:
+	* m4/Makefile.am:
+	* m4/libmikmod.m4:
+	* win32/MANIFEST:
+	* win32/vs8/libgstmikmod.vcproj:
+	  mikmod: remove ancient unported plugin
+	  This hasn't been touched in 11 years, and
+	  clearly no one's been missing it.
+
+2015-06-23 20:15:13 +0900  Gilbok Lee <gilbok.lee@samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: does not detect orientation
+	  Most files don't contain the values for transposing the coordinates
+	  back to the positive quadrant so qtdemux was ignoring the rotation
+	  tag. To be able to properly handle those files qtdemux will also ignore
+	  the transposing values to only detect the rotation using the values
+	  abde from the transformation matrix:
+	  [a b c]
+	  [d e f]
+	  [g h i]
+	  https://bugzilla.gnome.org/show_bug.cgi?id=738681
+
+2015-06-25 00:04:16 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.5.2 ===
+
+2015-06-24 23:30:41 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.5.2
+
+2015-06-24 22:56:12 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2015-06-24 11:15:00 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/nl.po:
+	  po: Update translations
+
+2015-06-23 18:42:59 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/elements/qtmux.c:
+	  qtmux: Correctly test each segments
+	  In presence of gaps, qtdemux will emit multiple segments. The
+	  second segment start should match the CTTS.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751361
+
+2015-06-23 17:54:31 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  qtmux: Correctly calculate the elst media start
+	  The media start has nothing to do with the shift we have applied
+	  but with the value of the first PTS. This is defined as:
+	  Dt(0) = 0
+	  Ct(0) = Dt(0) + CTTS(0)
+	  So the media start is always the first CTTS.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751361
+
+2015-06-23 11:49:32 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: accumulate previous edts entries into segment.base
+	  Allows playing edts editted files with proper synchronization of
+	  streams. This patch fixes the regression introduced by
+	  bf95f93c0189aa04f18e264b86b6527e431c5d53 that was added to fix
+	  segment seeks handling.
+	  Having the accumulated_base separated from the main segment.base
+	  allows handling both segment seeks and edts editted files.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751361
+
+2015-06-23 00:56:16 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: improve some debug messages
+	  Those messages are about the stream, use the pad as the
+	  debug object to make it clear from the logs
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751361
+
+2015-06-22 22:22:09 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: store last_dts of the first buffer
+	  Buffers need not to start at running-time 0 so the last_dts needs
+	  to be the value of the first buffer's dts as it is used to compute
+	  the duration of the buffers. If it was left at 0 the first buffer
+	  would have a larger duration when it shouldn't
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751361
+
+2015-06-23 17:11:57 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: fix possible memory leak
+	  when buffer is stored to seektable, and stop gets called due to
+	  corrupt flac file, then the seektable is not being released
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751364
+
+2015-06-23 16:28:40 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  Revert "splitmuxsink: Mask async-start/done while switching files."
+	  This reverts commit d61e5393f110ed482815d77807245d78b52eff46.
+	  Causes failures muxing larger GOP sizes for some reason. Reverting
+	  while I figure it out
+
+2015-06-18 23:22:06 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	* gst/multifile/gstsplitmuxsrc.c:
+	  splitmuxsrc: Fix startup and shutdown races.
+	  Fix 2 startup races when things happen too quickly, and 1
+	  at shutdown by holding a ref to the pads in use until the
+	  loop functions exit.
+	  Handle errors activating file parts and publish them on
+	  the bus.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750747
+
+2015-06-18 09:26:13 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmuxsink: Mask async-start/done while switching files.
+	  Sometimes, extra async-start/done from the internal sink
+	  while the element is still starting up can cause splitmuxsink
+	  to stall in PAUSED state when it has been set to PLAYING
+	  by the app. Drop the child's async-start/done messages while
+	  switching, so they don't cause state changes at the
+	  splitmuxsink level.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750747
+
+2015-06-15 16:12:10 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: Use gst_video_multiview_guess_half_aspect()
+	  Use the gst_video_multiview_guess_half_aspect() utility function
+	  to set the half-aspect flag (or not) on stereoscopic frame-packed
+	  videos.
+
+2015-06-15 16:10:37 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Move multiview caps calculations, add half-aspect heuristics
+	  Move the multiview caps calculations to the configure_stream()
+	  function, so the rest of the video info is available, and
+	  use the gst_video_multiview_guess_half_aspect() function to
+	  determine if the half-aspect flag should be set on frame-packed
+	  video.
+
+2015-06-18 16:06:02 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Add cslg support
+	  The cslg atom provide information about the DTS shift. This is
+	  needed in recent version of ctts atom where the offset can be
+	  negative. When cslg is missing, we parse the CTTS table as proposed
+	  in the spec to calculate these values.
+	  In this implementation, we only need to know the shift. As GStreamer
+	  cannot transport negative timestamps, we shift the timestamps forward
+	  using that value and adapt the segment to compensate. This patch also
+	  removes bogus offset of ctts_soffset, this offset shall be included
+	  in the edit list.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751103
+
+2015-06-19 18:37:59 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/elements/qtmux.c:
+	  qtmux: Test gaps at start of stream
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751242
+
+2015-06-19 18:40:43 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Use PTS to figure-out presence of gaps
+	  We need to look at the presentation timestamp in order to conclude if
+	  there is a gap at the start of a stream.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751242
+
+2015-06-19 16:45:02 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Set edit list to compensate DTS shift
+	  We shift DTS forward to avoid negative timestamps which cannot be
+	  represented with version 0 of the CTTS table. To stick with that
+	  version (backward compatibility), the spec recommend using an
+	  edit list entry to move back the presentation time to where it
+	  should be.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751242
+
+2015-06-22 14:35:52 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Insert AVC end of sequence
+	  This FLV specific mark is needed to prevent Flow Player (most likely
+	  all Flash base player) from going into buffering state when near EOS.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751320
+
+2015-06-22 13:05:29 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	  matroska: remove useless check
+	  No need to check for context availability while freeing. We are inside
+	  inside a code block with a condition that dereferences context.
+	  if (context->type == 0 ...
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751306
+
+2015-06-22 19:35:57 +0900  Vineeth T M <vineeth.tm@samsung.com>
+
+	* gst/matroska/lzo.c:
+	  lzo: fix memory leak
+	  the opened file is not being closed during test, which will result
+	  in memory leak.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751306
+
+2015-06-22 19:30:58 +0900  Vineeth T M <vineeth.tm@samsung.com>
+
+	* ext/mikmod/mikmod_reader.c:
+	  mikmod_reader: Possible null pointer dereference:
+	  gst_reader variable is being used before actually checking if it
+	  allocated properly
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751306
+
+2015-06-22 19:45:14 +0900  Sangkyu Park <sk1122.park@samsung.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Minor clean-up
+	  1. Fix the code which is wrong coding style.
+	  2. Fix a typing error of comment.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751316
+
+2015-06-22 11:28:13 +0200  Jose Antonio Santos Cadenas <santoscadenas@gmail.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: Do not try to push NULL buffers
+	  If update_receiver_stats() fails, we can't really do anything with this buffer
+	  anymore and have to drop it. This happens if there's a big seqnum
+	  discontinuity for example.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751311
+
+2015-06-22 13:10:02 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: trivial cleanup
+	  trivial patch to add proper ( while checking for if(G_UNLIKELY())
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751306
+
+2015-06-22 13:16:08 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/audioparsers/gstdcaparse.c:
+	  dcaparse: initialize size variable
+	  size can be used in cleanup without being initialized. Hence
+	  setting it to 0 when declaring
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751306
+
+2015-06-22 13:13:29 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: initialze bpf variable
+	  bpf variable might be used in cleanup without being intialized.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751306
+
+2015-06-19 14:50:59 +0200  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/gstrtprtxqueue.c:
+	  rtprtxqueue: reverse pending list before pushing buffers
+	  With this we send the RTX buffers in the same order
+	  that they were requested.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751297
+
+2015-06-21 19:22:10 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Fix DTS validity check
+	  This check was up-side-down, causing a bad timestamp at start
+	  and then all timestamp being delayed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751298
+
+2015-06-17 15:19:47 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/qtdemux_dump.c:
+	* gst/isomp4/qtdemux_dump.h:
+	* gst/isomp4/qtdemux_types.c:
+	  cslg: Add Composition Shift Least Greatest Atom
+	  This simply add fourcc and dump function for the cslg Atom.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751103
+
+2015-06-17 15:18:38 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/isomp4/qtdemux_dump.c:
+	  ctts_dump: Fix signess issues
+	  It didn't bug, but use correct signess in traces. The number of
+	  entries is unsigned while the offset can be signed according to
+	  recent spec.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=751103
+
+2015-06-16 17:48:08 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 6015d26 to f74b2df
+
+2015-06-16 11:43:39 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: gst_rtp_buffer_ext_timestamp() modifies its first argument, keep a copy around
+
+2015-06-16 10:30:34 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Compare ext RTP times, not plain RTP time and ext RTP time when calculating elapsed time
+	  Otherwise all RTP times after a wraparound would be considered as going
+	  backwards, they will always be smaller than the ext RTP time.
+
+2015-06-15 19:25:12 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: The default rtp-profile should be AVP, not AVPF
+
+2015-06-15 14:32:21 +0900  Sangkyu Park <sk1122.park@samsung.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Minor cleanup
+	  1. Add Null check in 'free_item' function.
+	  2. Fix a typing error of comment.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750965
+
+2015-06-12 17:44:51 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/flv/gstflvmux.c:
+	  flmux: Make sure best_time is initialized
+
+2015-06-12 23:29:19 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpsession.h:
+	  rtpbin/session: Add new ntp-time-source property and deprecate use-pipeline-clock property
+	  The new property allows to select the time source that should be used for the
+	  NTP time in RTCP packets. By default it will continue to calculate the NTP
+	  timestamp (1900 epoch) based on the realtime clock. Alternatively it can use
+	  the UNIX timestamp (1970 epoch), the pipeline's running time or the pipeline's
+	  clock time. The latter is especially useful for synchronizing multiple
+	  receivers if all of them share the same clock.
+	  If use-pipeline-clock is set to TRUE, it will override the ntp-time-source
+	  setting and continue to use the running time plus 70 years. This is only kept
+	  for backwards compatibility.
+
+2015-04-07 16:03:42 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/qtmux.c:
+	  tests: qtmux: test for muxing with DTS outside the segment
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740575
+
+2015-06-11 17:26:49 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Adjust segment according to ctts offset
+	  In presence of a CTTS, the segment start/stop must be offset so
+	  the segment start/stop include the PTS. This is needed since the
+	  PTS cannot be negative in this format. This fixes issues where the
+	  running time of the first buffer isn't at the start.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740575
+
+2015-04-03 20:34:42 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  qtmux: Handle DTS with negative running time
+	  As QT works with duration, simply bring back first DTS to 0 and shift
+	  forward the PTS of the same amount.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740575
+
+2015-06-10 18:15:52 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  flvmux: Add negative runtime DTS support
+	  This is done by using new feature of the CollectPad clip function
+	  which sets the DTS as a gint64 in the collected data. It also simplify
+	  the code a bit.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740575
+
+2015-06-12 23:06:24 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Rename some variables and debug output to make more sense
+	  Local and remote were mixed up in a few places, and the time we store here is
+	  not UNIX time (1970 epoch), but NTP time (1900 epoch) in nanoseconds.
+
+2015-06-12 19:21:10 +0300  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxcoreaudioremoteio.c:
+	  osxaudio: fix latency property query on RemoteIO
+	  AudioUnitGetProperty would fail with kParamErr (-50) every time,
+	  simply because size wasn't initialized.
+	  Now it returns zero latency, but at least it doesn't fail.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750868
+
+2015-04-07 14:06:16 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: Fix mapping of latency parameters to buffer attributes
+
+2015-06-12 01:56:37 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: Actually set detected 3D info into output caps.
+	  Use the information read from the StereoMode info
+	  to configure multiview-mode and multiview-flags in the
+	  video caps.
+
+2015-06-11 13:36:54 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	  splitmuxsink: Take released-but-not-yet-output bytes into account
+	  When deciding whether it's time to switch to a new file, take into
+	  account data that's been released for pushing, but hasn't yet
+	  been pushed - because downstream is slow or the threads haven't been
+	  scheduled.
+	  Fixes a race in the unit test and probably in practice - sometimes
+	  failing to switch when it should for an extra GOP or two.
+	  Also fix a problem in splitmuxsrc where playback sometimes
+	  stalls at startup if types are found too quickly.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750747
+
+2015-06-11 01:04:51 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/atoms.c:
+	  atoms: remove custom gst_buffer_new function in favor of core version
+	  Remove a custom specialized version of gst_buffer_new_wrapped by
+	  using gst_buffer_new_wrapped_full inside a macro to simplify
+	  parameters and give it a more meaningful name.
+	  It is only used to create temporary buffers to have its data copied.
+
+2015-06-11 00:14:41 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/atoms.c:
+	  atoms: simplify free form data atoms creation
+	  Avoid creating an intermediary buffer or memory area just
+	  to copy into an atom's data area.
+
+2015-06-10 22:27:27 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	* gst/isomp4/gstqtmuxmap.c:
+	  qtmux: add AC-3 muxing support
+	  Adds AC-3 muxing support. It is defined for mp4 and 3gp formats.
+	  One extra feature that was added was the ability to add extension
+	  atoms after set_caps as the AC-3 extension atom needs some data
+	  that has to be extracted from the stream itself and is not
+	  present on caps.
+
+2015-06-10 22:36:59 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	  qtmux: remove unused type MP4S
+
+2015-06-10 22:29:01 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: remove duplicate attribute value set
+	  It is also set a few lines below
+
+2015-06-11 00:22:54 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.c:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.c:
+	  matroska: Implement basic stereoscopic video support
+	  Implement support for the packed video formats WebM
+	  uses, not all the values that Matroska might use.
+	  In practice, it's really hard to find any samples in the
+	  wild of any.
+	  Supported in both the muxer and demuxer.
+
+2015-06-10 01:26:15 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_dump.c:
+	* gst/isomp4/qtdemux_dump.h:
+	* gst/isomp4/qtdemux_types.c:
+	  qtdemux: Add basic support for MPEG-A stereoscopic video
+	  The MPEG-A format provides an extension to the ISO base media
+	  file format to store stereoscopic content encoded with different
+	  codecs like H.264 and MPEG-4:2. The stereo video media information(svmi)
+	  atom declares the presence and storage method for the video.
+	  Stereo video information for MPEG-A can also be supplied through
+	  the 'stvi' atom (ref: ISO/IEC_14496-12, ISO/IEC_23000-11), which
+	  is not implemented in this patch.
+	  Also missing is support for stereo video encoded as separate video tracks
+	  for now.
+	  Based on a patch by Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+	  https://bugzilla.gnome.org/show_bug.cgi?id=611157
+
+2015-06-02 16:15:35 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: Add tls-database property
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750298
+
+2015-06-10 14:33:50 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmparobustdepay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpsbcpay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	  rtp: Use GST_BUFFER_PTS() instead of GST_BUFFER_TIMESTAMP()
+	  The mix between all these in the RTP code is confusing, let's try to be
+	  consistent.
+
+2015-06-10 14:49:50 +0300  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpmanager: clarify negative lost packets in stats
+	  Also:
+	  - Move notes on units before field documentation.
+	  - Unify documentation style.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750653
+
+2015-06-10 06:38:39 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: fix getter of "ssl-use-system-ca-file"
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750298
+
+2015-06-10 09:49:47 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix reverse playback
+	  When performing seek, segment->start is being updated with desired_offset,
+	  but in case of reverse playback segment->start should be 0 and
+	  segment->stop should be updated with desired offset.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750675
+
+2015-01-21 18:09:03 +0100  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2allocator.h:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  gstv4l2bufferpool: handle -EPIPE from DQBUF to signal EOS
+	  The V4L2 decoder signals EOS by returning -EPIPE from DQBUF after the
+	  last buffer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=743338
+
+2015-06-06 21:09:19 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Add a GTlsInteraction property
+	  It can be used for TLS client authentication.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750471
+
+2015-01-09 11:36:11 +0100  Enrico Jorns <ejo@pengutronix.de>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2: Allow scaling in the v4l2*convert element
+	  This is inspired of videoscale and videoconvert elements.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742917
+
+2015-06-09 19:02:55 +0300  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpmanager: document units of stats and arguments
+	  Also, minor spelling and style corrections.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750653
+
+2015-06-09 14:42:27 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* Makefile.am:
+	  cruft: add the obsolete tmpl dir to cruft-dirs
+
+2015-06-09 11:30:22 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From d9a3353 to 6015d26
+
+2015-06-09 07:04:07 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* common:
+	  Fix common version
+	  Was accidently downgraded by 87a4884acd8655a6591d735a1d944ecb5ea3de16
+
+2015-06-08 19:11:41 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Also set colorimetry on output devices
+	  This completes the code that set the colorimetry on output
+	  device.
+
+2015-06-08 19:10:34 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* common:
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Add missing SMTP240M matrix
+	  This is missing in the doc, but was in the header.
+
+2015-06-08 23:00:16 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/goom/goom_core.c:
+	  goom: possible uninitialized variables warning
+	  Build fails with the latest snapshot of gcc-4.9 because param1 and param2 might
+	  possibly be used uninitialized. They are set depending on the cases of a switch
+	  statement and the compiler sees this as not a complete guarantee.
+	  Set them to 0 if the switch statement falls down to the default case.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750566#c6
+
+2015-06-08 17:24:38 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Fully implement colorimetry support
+	  This fixes wrong mapping for sRGB as in GStreamer sRGB correctly
+	  apply to RGB formats, while in V4L2 it's an alias for sYCC. Also
+	  add support for the new quantization (range), ycbcr_encoding (matrix)
+	  and xfer_func (transfer) enumeration.
+
+2015-06-08 17:01:15 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/ext/types-compat.h:
+	* sys/v4l2/ext/v4l2-common.h:
+	* sys/v4l2/ext/v4l2-controls.h:
+	* sys/v4l2/ext/videodev2.h:
+	  v4l2: Update kernel headers to latest from media tree
+	  This is the latest from media tree. This should enable more development
+	  of the v4l2 elements. This includes new flags requires to fix draining
+	  path in decoder, colorimetry and much more.
+
+2015-06-08 23:07:55 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From d37af32 to d9a3353
+
+2015-06-08 19:42:30 +0100  Chris Clayton <chris2553@googlemail.com>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8depay: potential access beyond end of array
+	  Compiling (with gcc-4.9-20150603) produces an error because of an access beyond
+	  the end of an array. This patch fixes the error by initializing the loop
+	  control/array index variable (i) to 1 and returning i - 1 when a match is found.
+	  Also, because the values stored in the array increase in value as the index
+	  increases, the >= test unnecessary, so it is removed.
+
+2015-04-30 02:52:58 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Don't accumulate more than 2 GOPs
+	  Don't allow large amounts of data to queue up - we only need
+	  the GOP we're writing, and the GOP we're accumulating.
+
+2015-04-16 10:44:49 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  isomp4: fsync after sending updates in robust mode
+	  Use the new GstBuffer SYNC_AFTER flag to trigger an fsync
+	  after updating the moov or mdat atom, and after updating the free
+	  atom to make it visible.
+
+2015-04-03 00:57:20 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  isomp4: Only set moov header into streamheader at EOS
+	  Only update the moov header into the caps if it's the finalised
+	  moov at EOS time. Avoids posting a bogus moov at startup and
+	  repeated updates in robust-recording mode
+
+2015-04-03 01:44:15 +1100  Jan Schmidt <jan@centricular.com>
+
+	* tests/check/elements/qtmux.c:
+	  tests: Update mp4 mux test for mdat placeholder change
+	  The mp4 muxer now writes a place-holder mdat as a free
+	  atom followed by a 0-byte mdat that covers the rest of the
+	  file, making it possible to rewrite it as 64-bit, or leave
+	  it as-is if nothing else is written afterward
+
+2015-04-01 11:15:38 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/atomsrecovery.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  isomp4: Implement robust muxing using ping-pong strategy
+	  Implement a robust recording mode, where the output
+	  file is always in a playable state, seeking and rewriting
+	  the moov header at a configurable interval. Rewriting
+	  moov is done using reserved space at the start of
+	  the file, and a ping-pong strategy where the moov
+	  is replaced atomically so it's never invalid.
+	  Track when tags have actually changed, and don't write them into
+	  the moov unless they've changed. Clear any existing tags when
+	  re-writing them, so we can do progressive moov updating in robust
+	  recording mode.
+	  Write placeholder mdat as a free atom plus a 32-bit mdat
+	  with '0' size, which means "rest of the file" in the spec.
+	  Re-write it later to a full 64-bit extended size atom if needed.
+
+2015-04-01 00:58:52 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/gstqtmux.c:
+	  isomp4: Update edit list when re-writing moov
+	  Correctly update any edit lists each time the moov is recalculated,
+	  updating existing table entries if they already exist instead of just
+	  adding new ones.
+
+2015-04-08 01:41:18 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  isomp4: Remove an extra bracket in a comment.
+
+2015-03-19 20:29:44 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsrc.c:
+	  splitmuxsrc: Protect total_duration state variable with the object lock.
+	  Prevent deadlocks from downstream querying duration from the streaming thread.
+
+2015-06-07 23:06:20 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 21ba2e5 to d37af32
+
+2015-06-07 19:24:20 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/goom/gstaudiovisualizer.c:
+	  goom: clean dereferences of private structure
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742875
+
+2015-06-07 19:20:04 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/goom2k1/gstaudiovisualizer.c:
+	  goom2k1: clean dereferences of private structure
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742875
+
+2015-06-07 17:32:01 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From c408583 to 21ba2e5
+
+2015-06-07 17:01:37 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* docs/plugins/Makefile.am:
+	  docs: remove variables that we define in the snippet from common
+	  This is syncing our Makefile.am with upstream gtkdoc.
+
+2015-06-07 17:16:19 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* autogen.sh:
+	* common:
+	  Automatic update of common submodule
+	  From d676993 to c408583
+
+2015-06-07 16:44:37 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.5.1 ===
+
+2015-06-07 10:46:34 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* gst/deinterlace/tvtime-dist.c:
+	* gst/videomixer/videomixerorc-dist.c:
+	* win32/common/config.h:
+	  Release 1.5.1
+
+2015-06-07 10:38:28 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2015-06-07 10:32:38 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* tests/check/elements/rtpsession.c:
+	  rtpsession: Override the SSRC from the packets' SSRC if none was given via caps or property
+
+2015-06-07 09:35:38 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: Update translations
+
+2015-06-05 15:32:10 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Don't warn when optional CID are not implement
+	  gst_v4l2_get_attributre() shall only be used when the CID is expected
+	  to be supported. Otherwise, we get unwanted warning posted to the bus.
+
+2015-06-05 16:43:08 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Only suggest our internal ssrc if it's not a random one and was selected as internal ssrc
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749581
+
+2015-06-04 14:18:01 +0900  Vineeth TM <vineeth.tm@samsung.com>
+
+	* gst/interleave/interleave.c:
+	  interleave: error when channel-positions-from-input=False
+	  self->channels is being incremented only when
+	  channel-positions-from-input is set as TRUE. So in case of FALSE
+	  self->func is not set and hence creating assertion error.
+	  Hence removing the condition to increment self->channels.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=744211
+
+2015-06-05 10:33:11 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Add support for receiving reduced size RTCP
+	  It worked before but gave warnings, now we just ignore RTCP
+	  packets that don't start with a SR. As all we're interested
+	  in here are SRs.
+
+2015-06-03 12:22:42 +0200  Jose Antonio Santos Cadenas <santoscadenas@gmail.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Add support for reduce size rtcp
+	  According to RFC 5506, reduce size packages can be sent, this
+	  packages may not be compound, so we need to add support for
+	  getting ssrc from other types of packages.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750327
+
+2015-06-03 13:14:44 +0200  Jose Antonio Santos Cadenas <santoscadenas@gmail.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Add support for receiving reduced size rtcp
+	  See RFC 5506
+	  https://bugzilla.gnome.org/show_bug.cgi?id=750332
+
+2015-06-04 16:09:41 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Add support for channel configurations 11, 12 and 14 and 7 actually has 8 channels
+	  ISO/IEC 14496-3:2009/PDAM 4 added 11, 12 and 14.
+
+2015-06-03 08:57:57 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/rtp/gstasteriskh263.c:
+	  asteriskh263: Un-rank clashing depayloader
+	  This depayloader clash with the standard one for H263p. It produces an
+	  H263p stream with a modified header. It uses encoding-name that is the
+	  same as H263p (H263-1998) though the resulting ES is not decodable or
+	  parsable in GStreamer, making it unsuable in dynamic pipeline. This
+	  patch unrank this specialized depayloader since it can only be used in
+	  custom pipeline.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739935
+
+2015-06-02 18:09:48 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/goom2k1/gstgoom.c:
+	* gst/goom2k1/gstgoom.h:
+	  goom2k1: remove variables not needed anymore
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742875
+
+2015-06-02 17:52:46 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/goom2k1/Makefile.am:
+	* gst/goom2k1/gstaudiovisualizer.c:
+	* gst/goom2k1/gstaudiovisualizer.h:
+	* gst/goom2k1/gstgoom.c:
+	* gst/goom2k1/gstgoom.h:
+	  goom2k1: rebase to use the audiovisualizer class
+	  Rebase to have goom2k1 using the common GstAudioVisualizer class
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742875
+
+2015-06-02 17:29:36 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/goom/Makefile.am:
+	* gst/goom/gstaudiovisualizer.c:
+	* gst/goom/gstaudiovisualizer.h:
+	* gst/goom/gstgoom.c:
+	* gst/goom/gstgoom.h:
+	  goom: rebase to use the audiovisualizer class
+
+2015-06-02 16:27:24 +0200  Edward Hervey <edward@centricular.com>
+
+	* tests/check/elements/aacparse.c:
+	* tests/check/elements/ac3parse.c:
+	* tests/check/elements/apev2mux.c:
+	* tests/check/elements/aspectratiocrop.c:
+	* tests/check/elements/audioamplify.c:
+	* tests/check/elements/audiochebband.c:
+	* tests/check/elements/audiocheblimit.c:
+	* tests/check/elements/audiodynamic.c:
+	* tests/check/elements/audioinvert.c:
+	* tests/check/elements/audiowsincband.c:
+	* tests/check/elements/audiowsinclimit.c:
+	* tests/check/elements/avimux.c:
+	* tests/check/elements/equalizer.c:
+	* tests/check/elements/flacparse.c:
+	* tests/check/elements/id3v2mux.c:
+	* tests/check/elements/jpegdec.c:
+	* tests/check/elements/jpegenc.c:
+	* tests/check/elements/matroskamux.c:
+	* tests/check/elements/mpegaudioparse.c:
+	* tests/check/elements/rganalysis.c:
+	* tests/check/elements/rglimiter.c:
+	* tests/check/elements/rgvolume.c:
+	* tests/check/elements/rtpbin.c:
+	* tests/check/elements/rtpsession.c:
+	* tests/check/elements/spectrum.c:
+	* tests/check/elements/videobox.c:
+	* tests/check/elements/videocrop.c:
+	* tests/check/elements/videofilter.c:
+	* tests/check/elements/wavpackdec.c:
+	* tests/check/elements/wavpackenc.c:
+	* tests/check/elements/wavpackparse.c:
+	* tests/check/elements/y4menc.c:
+	* tests/check/pipelines/simple-launch-lines.c:
+	* tests/check/pipelines/tagschecking.c:
+	* tests/check/pipelines/wavpack.c:
+	  check: Use GST_CHECK_MAIN () macro everywhere
+	  Makes source code smaller, and ensures we go through common initialization
+	  path (like the one that sets up XML unit test output ...)
+
+2015-05-26 14:47:31 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Only schedule a timer when we actually have to send RTCP
+	  Otherwise we will have 10s-100s of thread wakeups in feedback profiles, create
+	  RTCP packets, etc. just to suppress them in 99% of the cases (i.e. if no
+	  feedback is actually pending and no regular RTCP has to be sent).
+	  This improves CPU usage and battery life quite a lot.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746543
+
+2015-05-22 13:44:03 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Remove useless goto
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746543
+
+2015-05-21 12:54:47 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/examples/rtp/Makefile.am:
+	* tests/examples/rtp/client-H264-rtx.sh:
+	* tests/examples/rtp/client-rtpaux.c:
+	* tests/examples/rtp/server-VTS-H264-rtx.sh:
+	* tests/examples/rtp/server-rtpaux.c:
+	  examples: Set RTP profile to AVPF for rtpaux examples
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746543
+
+2015-05-04 16:41:50 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Set RTP profile on the rtpsession objects
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746543
+
+2015-05-21 14:13:56 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: Add rtp-profile property for setting the default profile of newly created sessions
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746543
+
+2015-05-04 11:51:41 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Only put RRs and full SDES into regular RTCP packets
+	  If we may suppress the packet due to the rules of RFC4585 (i.e. when
+	  below the t-rr-int), we can send a smaller RTCP packet without RRs
+	  and full SDES. In theory we could even send a minimal RTCP packet
+	  according to RFC5506, but we don't support that yet.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746543
+
+2015-05-04 13:51:50 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Keep track of tp/tn and t_rr_last separately
+	  Otherwise we can't properly schedule RTCP in feedback profiles as we need to
+	  distinguish the time when we last checked for sending RTCP (tp) but might have
+	  suppressed it, and the time when we last actually sent a non-early RTCP
+	  packet.
+	  This together with the other changes should now properly implement RTCP
+	  scheduling according to RFC4585, and especially allow us to send feedback
+	  packets a lot if needed but only send regular RTCP packets every once in a
+	  while.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746543
+
+2015-05-04 11:42:08 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.h:
+	* gst/rtpmanager/rtpstats.c:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpsession: Add property for selecting RTP profile (AVP/AVPF/etc)
+	  And modify our RTCP scheduling algorithm accordingly. We now can send more
+	  RTCP packets if needed for feedback, but will throttle full RTCP packets by
+	  rtcp-min-interval (t-rr-int from RFC4585).
+	  In non-feedback mode, rtcp-min-interval is Tmin from RFC3550, which is
+	  statically set to 1s or 0s by RFC4585. Tmin defines how often we should
+	  send RTCP packets at most.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746543
+
+2015-05-30 17:41:05 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/law/mulaw-decode.c:
+	  mulawdec: Let baseclass estimate bitrate
+	  This makes playback directly from a file work with the right caps.
+
+2015-05-27 16:31:23 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstdynudpsink.h:
+	  dynudpsink: keep GCancellable fd around instead of re-creating it constantly
+	  And create it only when starting the element.
+
+2015-05-27 15:55:56 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	  udpsink, multiudpsink: keep GCancellable fd around instead of re-creating it constantly
+	  Otherwise we constantly create/close event file descriptors,
+	  every time we call g_socket_condition_timed_wait() or
+	  g_socket_send_message(s)(), i.e. a lot. Which is not
+	  particularly good for performance.
+	  Can't create GCancellable in ::start() here because it's used
+	  in client_new() which may be called via the add-client action
+	  signal which may be called before the element is up and running.
+
+2015-05-19 18:13:16 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	* gst/udp/gstudpsrc.h:
+	  udpsrc: keep GCancellable fd around instead of re-creating it constantly
+	  Otherwise we constantly create/close event file descriptors,
+	  every single time we call g_socket_condition_timed_wait() or
+	  g_socket_receive_message(), i.e. twice per packet received!
+	  This was not particularly good for performance.
+	  Also only create GCancellable on start-up.
+
+2015-05-26 15:33:37 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroska: overwritten value assignment
+	  curpos is set and immediately after, set again. Remove the redundant
+	  assignment.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749909
+
+2015-05-23 13:47:17 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  rtpvrawdepay: don't shadow existing outbuf variable
+	  And fix unref of the wrong one which will contain NULL
+	  in an error code path.
+
+2015-05-23 13:23:22 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawdepay.h:
+	  rtpvrawdepay: map/unmap output frame only once, not for every input packet
+	  Map output buffer after creating it and keep it mapped
+	  until we're done with it instead of mapping/unmapping
+	  it for every single input buffer.
+
+2015-05-25 08:47:47 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: remove fixme from 2006
+	  It has been verified by use over time.
+
+2015-05-23 14:36:41 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix reverse playback of fragmented media
+	  qtdemux creates a samples array and gets the timestamps for buffers by
+	  accumulating their durations. When doing reverse playback of fragments,
+	  accumulating samples will lead to wrong timestamps as the timestamps
+	  should go decreasing from fragment to fragment and the accumulation
+	  will produce wrong results.
+	  In this case, when receiving a discont for fragmented reverse playback,
+	  the previous samples information should be flushed before new data
+	  is processed.
+
+2015-05-23 01:03:18 +0900  Jimmy Ohn <yongjin.ohn@lge.com>
+
+	* gst/multifile/gstsplitfilesrc.c:
+	  splitfilesrc: Implement binary search in find_part_for_offset
+	  Implement binary search using gst_util_array_binary_search
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749690
+
+2015-05-21 13:26:53 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Don't crash if we receive FIR/PLI from a source we don't know
+
+2015-05-21 09:35:58 +0200  Santiago Carot-Nemesio <sancane@gmail.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Fix collection of statistics
+	  Stats should be collected on the media rtp source not in the
+	  sender one.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749669
+
+2015-04-20 10:07:30 +0200  Edward Hervey <edward@centricular.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesink.h:
+	  multifilesink: Add a new max-duration file switching mode
+	  This new mode ensures that files will never exceed a certain duration
+	  based on incoming buffer PTS (and duration if present)
+	  Note:
+	  * You need timestamped buffers (duh). If some of the incoming buffers don't
+	  have PTS, then it will just accept them in the current file
+
+2015-04-17 16:18:32 +0200  Edward Hervey <edward@centricular.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: streamline the file-switch code a bit
+	  Use the same functions regardless of the mode we are using
+
+2015-04-02 13:35:18 +0100  Edward Hervey <edward@centricular.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesink.h:
+	  multifilesink: add "aggregate-gops" property to process GOPs as a whole
+	  This property can be used in combination with next-file=max-size
+	  (and perhaps a future next-file=max-duration) to make sure that
+	  each file part starts cleanly with a key frame and the appropriate headers.
+	  In order for this property to work correctly, upstream elements should make
+	  sure than any headers that need to be written in a standalone file are:
+	  1) in the streamheader caps field
+	  2) and/or in the stream as one or more buffers marked with GST_BUFFER_FLAG_HEADER
+	  that are just before the keyframe buffer
+	  This is useful for MPEG-TS/MPEG-PS file segmenting in
+	  combination with mpegtsmux or mpegpsmux.
+	  Original patch by: Tim-Philipp Müller <tim@centricular.com>
+
+2015-05-20 16:37:22 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Use single-include header for the RTSP library
+
+2014-10-24 23:47:21 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	  udp: don't use soon-to-be-deprecated g_cancellable_reset()
+	  From the API documentation: "Note that it is generally not
+	  a good idea to reuse an existing cancellable for more
+	  operations after it has been cancelled once, as this
+	  function might tempt you to do. The recommended practice
+	  is to drop the reference to a cancellable after cancelling
+	  it, and let it die with the outstanding async operations.
+	  You should create a fresh cancellable for further async
+	  operations."
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739132
+
+2015-05-18 20:13:01 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/cutter/gstcutter.c:
+	* gst/equalizer/gstiirequalizernbands.c:
+	* gst/multifile/gstmultifilesink.c:
+	  Revert "doc: Workaround gtkdoc issue"
+	  This reverts commit 1797c8f8b12d7f4c7a9444c94f34f4d08ec85945.
+	  This is fixed by the gtk-doc 1.23 release.
+	  <para> cannot contain <refsect2>:
+	  http://www.docbook.org/tdg/en/html/para.html
+	  http://www.docbook.org/tdg/en/html/refsect2.html
+
+2015-05-18 16:40:21 +0200  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/rtp/gstrtpg726pay.c:
+	  rtpg726pay: fix caps leak
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749544
+
+2015-05-18 16:34:13 +0200  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/rtp/gstrtpg726depay.c:
+	  rtpg726depay: don't leak input buffer
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749543
+
+2015-05-18 17:38:31 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: Queue bad packets instead of dropping them
+	  So we can send them out once we found the next, consecutive sequence number in
+	  case one is following.
+
+2015-05-18 17:38:14 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: Use g_queue_foreach() to unref all buffers in queues
+
+2015-05-18 17:19:31 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: Refactor seqnum comparison code a bit
+
+2015-05-18 17:08:53 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: Allow sequence number wraparound during probation
+
+2015-05-18 17:07:23 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: Make sequence number comparison code more readable
+	  ... by using gst_rtp_buffer_compare_seqnum() and signed integers
+	  instead of implictly using effects of integer over/underflows.
+
+2015-04-22 18:54:06 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: When detecting a huge seqnum gap, wait for 5 consecutive packets before resetting everything
+	  It might just be a late retransmission or spurious packet from elsewhere, but
+	  resetting everything would mean that we will cause a noticeable hickup. Let's
+	  get some confidence first that the sequence numbers changed for whatever
+	  reason.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747922
+
+2015-05-16 23:37:06 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/cutter/gstcutter.c:
+	* gst/equalizer/gstiirequalizernbands.c:
+	* gst/multifile/gstmultifilesink.c:
+	  doc: Workaround gtkdoc issue
+	  With gtkdoc 1.22, the XML generator fails when a itemizedlist is
+	  followed by a refsect2. Workaround the issue by wrapping the
+	  refsect2 into para.
+
+2015-01-23 13:57:40 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/isomp4/qtdemux_types.c:
+	  qtdemux: avoid wrong warnings on unknown node types
+	  Add 'name' and 'mean' fourccs, as we handle them. Right now each use would
+	  trigger a warning.
+
+2015-05-08 19:13:00 +0200  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726depay.h:
+	  rtpg726depay: add block_align to output caps
+	  It is needed to correctly negotiate caps with matroskamux
+	  and most other muxers.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749129
+
+2015-05-12 13:41:58 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	  audiofxbasefirfilter: Fix time-domain convolution with >1 channels
+	  input_samples is the number of frames, but we used it as the number of
+	  samples.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747204
+
+2015-05-12 12:13:16 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp9enc.c:
+	  vp[89]enc: Properly convert between GStreamer and encoder timebase
+	  ... by switching numerator and denominator when scaling.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749122
+
+2015-05-11 13:33:26 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp9enc.c:
+	  vp[89]enc: Don't set timebase from the framerate
+	  The framerate very often is just an indication of the ideal framerate, not the
+	  actual framerate of the stream. By just using the framerate, we confuse the
+	  rate control algorithm algorithm as multiple frames will map to the same PTS
+	  or have durations of 0.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749122
+
+2015-05-10 14:21:04 +0200  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* tests/check/elements/wavpackparse.c:
+	  tests: wavpackparse: fix unit test
+	  See also https://bugzilla.gnome.org/show_bug.cgi?id=738237
+
+2015-05-10 11:05:00 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/shout2/gstshout2.c:
+	* ext/vpx/gstvp8dec.c:
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp9dec.c:
+	* ext/vpx/gstvp9enc.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpL24depay.c:
+	* gst/rtp/gstrtpL24pay.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	* tests/check/pipelines/wavenc.c:
+	* tests/examples/rtp/client-PCMA.c:
+	* tests/examples/rtp/server-alsasrc-PCMA.c:
+	  docs: update example pipelines in element docs
+	  Mostly gst-launch -> gst-launch-1.0
+	  Use autovideosink/autoaudiosink more often.
+	  Sprinkle some converters here and there.
+
+2015-05-09 19:48:55 +0200  Piotr Drąg <piotrdrag@gmail.com>
+
+	* po/POTFILES.in:
+	  po: update POTFILES.in
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749163
+
+2015-05-10 10:52:18 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/multifile/gstsplitmuxsrc.c:
+	  splitmuxsrc: minor error message clean-up
+	  Don't put filename in error message shown to user.
+
+2015-05-07 16:25:36 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: fix buffer leak when stored to seektable
+	  Fix a leak with the
+	  validate.file.playback.change_state_intensive.samples_multimedia_cx_flac_Yesterday_flac
+	  scenario.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749072
+
+2015-05-07 17:10:37 +0900  Paul Hyunil <paul.hyunil@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix example pipeline in docs
+	  The gst-launch script for example launch line to test qtdemux is
+	  missing a queue before the decodebins, otherwise the gst-launch-1.0
+	  command won't work.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=749054
+
+2015-05-07 14:51:45 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  Revert "rtpsession: Also report internal sources in on-new-ssrc and on-ssrc-active"
+	  This reverts commit d22ec496328e6ba8edbf2d071d5608b2af2831e8.
+	  Application code might expect that it only gets external sources on those
+	  signals, and get confused by this. If anything we would need to add new
+	  signals.
+
+2015-03-25 15:27:34 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Also report internal sources in on-new-ssrc and on-ssrc-active
+	  Without this it seems impossible for an application to easily get notified
+	  about the internal ssrcs that are created, e.g. sender sources, and also
+	  to know when they are active and produce RTCP packets.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746747
+
+2015-05-04 19:26:14 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fix frame leaks in handle_frame() implementation
+	  handle_frame() is supposed to consume @frame, so if we don't call
+	  gst_video_decoder_drop_frame() or gst_video_decoder_finish_frame() we have to
+	  release it manually.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=748909
+
+2015-05-04 16:50:38 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Fix up last commit
+
+2015-05-04 16:46:02 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Only do RTX when using a feedback profile
+
+2015-05-04 13:50:31 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: The stats min_interval is in seconds, not nanoseconds
+	  We have to scale it to compare it against our clock times.
+
+2015-05-04 11:38:27 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Only return TRUE if early feedback was requested already and it's early enough
+
+2015-04-30 15:42:34 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/matroska/matroska-parse.c:
+	  matroska: remove unused property enum items
+
+2015-04-30 12:13:59 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix buffer leak on eos in push mode
+	  Based on patch by Guillaume Desmottes.
+	  scenario: validate.http.playback.seek_with_stop.raw_h264_1_mp4
+	  https://bugzilla.gnome.org/show_bug.cgi?id=748617
+
+2015-04-29 19:41:29 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Check for sizes of the rdrf (redirect) atom before accessing the data and use g_strndup() instead of g_strdup()
+	  Thanks to Ralph Giles for reporting this.
+
+2015-04-29 15:52:27 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Only enable retransmissions if there is retransmission info in the SDP
+	  Otherwise we're going to send early RTCP and NACKs in non-feedback sessions
+	  too, which will confuse servers.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=748627
+
+2015-02-11 18:09:24 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: extract recording time
+	  Extracts the recorded time of the dv file from
+	  the metadata and puts it into the global tags.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=743657
+
+2015-04-28 15:59:25 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: fix seek event leak
+	  gst_matroska_demux_handle_seek_event() doesn't consume the
+	  event so we have to unref it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=748584
+
+2015-04-28 15:42:49 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: Send pending tags when adding a new pad
+	  We might've parsed those tags before already and tried to push them to
+	  non-existing pads before. Now let's do it for real.
+
+2015-04-23 18:57:37 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpstats.c:
+	  rtpstats: Average RTCP packet size is in bytes, bandwidths in bits
+	  We need to convert the size to bits for our calculations.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747863
+
+2015-04-23 18:53:39 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpstats.c:
+	  rtpstats: Use the same lower limit for RTCP bandwidth to stop sending RTCP everywhere
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747863
+
+2015-04-14 18:41:07 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Use bandwidth calculation by default instead of some arbitrary hardcoded value
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747863
+
+2015-04-23 18:49:37 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Bandwidth is supposed to be in bits/s, not bytes/s
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747863
+
+2015-04-27 16:36:27 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Fix RTX unit test
+	  The calculations were a bit off everywhere, even before the changes done
+	  recently to the delay for RTX of expected future packets. It only worked by
+	  accident, but now the calculations are all correct again. Hopefully.
+
+2015-04-27 11:22:11 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/avi/gstavimux.c:
+	* gst/debugutils/breakmydata.c:
+	* gst/debugutils/cpureport.c:
+	* gst/debugutils/gstnavseek.c:
+	* gst/debugutils/progressreport.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/flv/gstindex.c:
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/id3demux/gstid3demux.c:
+	* gst/isomp4/gstrtpxqtdepay.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/multipart/multipartmux.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpg723depay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videofilter/gstvideotemplate.c:
+	* gst/y4m/gsty4mencode.c:
+	  Rename property enums from ARG_ to PROP_
+	  Property enum items should be named PROP_ for consistency and readability.
+
+2015-04-25 02:49:58 +0300  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Fix "stats" property docs
+	  https://bugzilla.gnome.org/show_bug.cgi?id=748436
+
+2015-04-26 17:54:52 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* Android.mk:
+	* gst/alpha/Makefile.am:
+	* gst/apetag/Makefile.am:
+	* gst/audiofx/Makefile.am:
+	* gst/auparse/Makefile.am:
+	* gst/autodetect/Makefile.am:
+	* gst/avi/Makefile.am:
+	* gst/cutter/Makefile.am:
+	* gst/debugutils/Makefile.am:
+	* gst/deinterlace/Makefile.am:
+	* gst/dtmf/Makefile.am:
+	* gst/effectv/Makefile.am:
+	* gst/equalizer/Makefile.am:
+	* gst/flv/Makefile.am:
+	* gst/flx/Makefile.am:
+	* gst/goom/Makefile.am:
+	* gst/goom2k1/Makefile.am:
+	* gst/icydemux/Makefile.am:
+	* gst/id3demux/Makefile.am:
+	* gst/imagefreeze/Makefile.am:
+	* gst/interleave/Makefile.am:
+	* gst/isomp4/Makefile.am:
+	* gst/law/Makefile.am:
+	* gst/level/Makefile.am:
+	* gst/matroska/Makefile.am:
+	* gst/monoscope/Makefile.am:
+	* gst/multifile/Makefile.am:
+	* gst/multipart/Makefile.am:
+	* gst/replaygain/Makefile.am:
+	* gst/rtp/Makefile.am:
+	* gst/rtpmanager/Makefile.am:
+	* gst/rtsp/Makefile.am:
+	* gst/shapewipe/Makefile.am:
+	* gst/smpte/Makefile.am:
+	* gst/spectrum/Makefile.am:
+	* gst/udp/Makefile.am:
+	* gst/videobox/Makefile.am:
+	* gst/videocrop/Makefile.am:
+	* gst/videofilter/Makefile.am:
+	* gst/videomixer/Makefile.am:
+	* gst/wavenc/Makefile.am:
+	* gst/wavparse/Makefile.am:
+	* gst/y4m/Makefile.am:
+	  Remove obsolete Android build cruft
+	  This is not needed any longer.
+
+2015-04-24 13:55:08 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/videocrop/gstvideocrop.c:
+	  videocrop: print the property values when set
+	  Instead of printing the currently used values. The log is meant
+	  to show what the properties changed to, not what is being currently
+	  used.
+
+2015-04-24 17:01:10 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/alpha/gstalpha.c:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/multifile/gstmultifilesink.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtprtxqueue.c:
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	* gst/rtpmanager/gstrtprtxsend.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/smpte/gstsmpte.c:
+	* gst/smpte/gstsmptealpha.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	  remove unused enum items PROP_LAST
+	  This were probably added to the enums due to cargo cult programming and are
+	  unused. Removing them.
+
+2015-04-24 00:30:35 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/level/gstlevel.c:
+	  level: fix infinite loop for very low interval values
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745515
+
+2015-04-23 16:08:54 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/Makefile.am:
+	  tests: define GST_CHECK_TEST_ENVIRONMENT_BEACON
+	  Make sure the test environment is set up.
+	  https://bugzilla.gnome.org//show_bug.cgi?id=747624
+
+2015-04-23 16:08:32 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* configure.ac:
+	  configure: bump automake requirement to 1.14 and autoconf to 2.69
+	  This is only required for builds from git, people can still
+	  build tarballs if they only have older autotools.
+	  https://bugzilla.gnome.org//show_bug.cgi?id=747624
+
+2015-04-23 16:06:57 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* .gitignore:
+	  Update .gitignore
+
+2015-04-23 09:55:59 +0200  Jesper Larsen <knorr.jesper@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Fix RTCP caps leak
+	  https://bugzilla.gnome.org//show_bug.cgi?id=748353
+
+2015-04-22 20:24:20 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: When request retransmissions for future packets, consider the packet spacing in the extra delay
+	  We now take the maximum of 2*jitter and 0.5*packet_spacing for the extra
+	  delay. If jitter is very low, this should prevent unnecessary retransmission
+	  requests to some degree.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=748041
+
+2015-04-22 19:41:07 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Take a running average of the packet spacings instead of just the latest
+	  https://bugzilla.gnome.org/show_bug.cgi?id=748041
+
+2015-04-13 11:20:40 +0200  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Add "rtx-next-seqnum" property
+	  If this is set to FALSE, rtpjitterbuffer will not request retransmissions for
+	  future packets based on when they are estimated to arrive.
+	  See also https://bugzilla.gnome.org/show_bug.cgi?id=748041
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739868
+
+2015-04-22 19:29:34 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	  rtxreceive: Put debug output for retransmission requests at the right place
+	  Before it was only ever printed once for every time a ssrc was associated with
+	  a specific stream.
+
+2015-04-22 18:05:24 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: don't add the same interlace mode twice
+	  Some drivers modify the interlace mode to progressive, no matter what
+	  input you give them, make sure that we don't add the same interlace mode
+	  twice.
+
+2015-04-21 16:34:21 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/equalizer/gstiirequalizer.c:
+	  equalizer: fix dynamic changes on bands
+	  When we are in passthrough, the transform function doesn't run and if the
+	  passthrough check is in this function it will never be deactivated. Fix this by
+	  checking directly whenever a gain is changed.
+	  Also set the passthrough to TRUE at init because the gains default to 0, so we
+	  can passthrough until any gain property is changed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=748068
+
+2015-04-22 10:30:52 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* INSTALL:
+	  Remove INSTALL file
+	  autotools automatically generate this, and when using different versions
+	  for autogen.sh there will always be changes to a file tracked by git.
+
+2015-04-22 10:30:14 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* LICENSE_readme:
+	  Remove LICENSE_readme
+	  It's completely outdated and just confusing, better if people are
+	  forced to look at the actual code in question than trusting this file.
+
+2015-04-21 15:21:33 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: cast unused return to void
+	  Quell unchecked return value defect by casting the return value to void and
+	  making it explicit it is going to be ignored.
+	  CID #206031
+
+2015-04-17 13:08:02 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/vpx/gstvp8dec.c:
+	  vp8dec: optimize vpx image to gstbuffer copy when strides match
+	  Solving this FIXME. Copy the full plane when strides are the same
+
+2015-04-16 15:11:05 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/vpx/gstvp9dec.c:
+	  vp9dec: optimize vpx image to gstbuffer copy when strides match
+	  Solving this FIXME. Copy the full plane when strides are the same
+
+2015-04-17 13:32:54 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: fix memory leak
+
+2015-04-17 06:51:46 +0000  Alex O'Konski <alexanderokonski@gmail.com>
+
+	* gst/icydemux/gsticydemux.c:
+	  icydemux: Fix segfault if metadata-interval is 0
+	  Prevents an extra unref of GstBuffer when passing a non-icy stream through
+	  icydemux with metadata-interval set to 0.
+	  Reproducible with:
+	  gst-launch-1.0 filesrc location=~/testsong.mp3 ! \
+	  'application/x-icy,metadata-interval=(int)0' ! icydemux ! decodebin ! wavenc ! \
+	  filesink location=~/testsong.wav
+	  https://bugzilla.gnome.org/show_bug.cgi?id=748024
+
+2015-04-17 11:54:23 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audiodynamic.c:
+	  audiofx: fix typo in example pipelines
+	  Fix typo in example pipelines
+	  https://bugzilla.gnome.org/show_bug.cgi?id=748022
+
+2015-04-15 18:22:37 +0300  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxcoreaudiohal.c:
+	  osxaudio: fix spelling in debug message
+	  https://bugzilla.gnome.org//show_bug.cgi?id=747936
+
+2015-04-16 16:33:44 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* tests/examples/equalizer/demo.c:
+	  tests: selectable amount of bands in equalizer demo
+	  Adding an option in the equalizer demo to make the number of bands selectable.
+
+2015-04-16 15:31:25 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource/rtprtxsend: Also pass correct seqnum-offset and payload to the RTX rtpsource
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747394
+
+2015-04-06 12:56:50 +0530  Arun Raghavan <arun@centricular.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Track RTX ssrc caps
+	  This is needed so that we can generate SR for RTX stream correctly (the
+	  clock rate is required).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747394
+
+2015-04-14 13:56:38 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: Copy over timestamps from the orignal buffers to the RTX buffers
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747394
+
+2015-04-16 16:01:50 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* tests/examples/equalizer/demo.c:
+	  tests: switch equalizer demo to play from uri
+	  Switch the equalizer-nbands demo to use uridecodebin, so users can listen to
+	  something more pleasant than white noise. If anybody misses the white noise
+	  a uri handler to audiotestsrc can be used.
+
+2015-04-16 11:17:38 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* tests/examples/equalizer/demo.c:
+	  tests: improve readability of equalizer demo
+	  Rename variable name to make it more readable, add comments for the three
+	  scales created per block, and set the window title.
+
+2015-04-15 17:32:37 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* tests/examples/equalizer/demo.c:
+	  tests: add missing license header for equalizer demo
+
+2015-04-16 13:09:19 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix tag list leaks on error paths
+
+2015-04-16 12:23:38 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix tag list leak on unknown stream type
+
+2015-04-09 13:19:49 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* tests/check/gst-plugins-good.supp:
+	  suppressions: ignore an apparent bug in strtod
+	  A buffer overread.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747554
+
+2015-04-15 11:07:27 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: do not access property variable without the object lock, use the local stack copy instead
+
+2015-04-14 18:45:44 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: add probe on the multiqueue's sink pad instead of the ghost pad
+	  because _release_pad tries to release it from ctx->sinkpad, which is
+	  multiqueue's sink pad, and currently fails because the probe is not
+	  installed there
+
+2015-04-14 19:08:24 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtx*: Fix typos
+
+2015-04-14 17:24:46 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Not sending early RTCP now because of dithering means we send it with the next compound packet
+
+2015-04-14 16:27:18 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Improve debug output a bit if we can't allow early feedback
+
+2015-04-07 18:00:53 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpvp8depay.c:
+	  rtpvp8depay: When dropping intra packet, request keyframe
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747208
+
+2015-04-13 20:25:00 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Change resyncing GST_WARNING to GST_INFO
+	  This also happens in the very beginning when we receive the first packet, a
+	  warning would be very confusing here. In all places where we should warn about
+	  this, we would've printed a warning already before.
+
+2015-04-02 13:26:41 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: minor docs improvement
+
+2014-11-06 12:08:03 +0100  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Add "rtx-max-retries" property
+	  This property allows to limit the maximum number of retransmission
+	  for a specific packet.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739868
+
+2014-11-04 15:00:52 +0100  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Fix expected_dts calc in calculate_expected
+	  Right above we consider lost_packet packets, each of them having duration,
+	  as lost and triggered their timers immediately. Below we use expected_dts
+	  to schedule retransmission or schedule lost timers for the packets that
+	  come after expected_dts.
+	  As we just triggered lost_packets packets as lost, there's no point in
+	  scheduling new timers for them and we can just skip over all lost packets.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739868
+
+2015-03-20 18:21:57 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Make the next output buffer discont after resetting the jitterbuffer
+	  Resetting the jitterbuffer drops all packets and other things, and will cause
+	  a discontinuity in the packets received by the depayloaders. They should now
+	  also flush anything they had pending as the new data will start at a different
+	  position.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739868
+
+2015-04-10 09:17:26 +0900  Hyunjun Ko <zzoon.ko@samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Update segment.start after key-unit seek
+	  When doing key uint seek, qtdemux calls gst_qtdemux_adjust_seek
+	  to get proper offset. And then this offset is set to
+	  segment.position and segment.time in gst_qtdemux_perform_seek but
+	  segment.start is not updated.
+	  After that, application sends segment query,
+	  qtdemux sets start and stop to query using gst_segment_to_stream_time. Due
+	  to the wrong value in segment.start, the stop position is smaller than
+	  it should.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746822
+
+2015-04-07 16:12:40 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: remove useless variable do_pts
+	  We always write the CTTS in qtmux. Ideally we only want to do that
+	  for streams that need DTS, it should be present on the track information
+	  rather than be decided based on each buffer
+
+2015-04-07 00:53:35 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: remove subtraction that makes PTS/DTS start from 0
+	  As qt uses durations, it doesn't matter, only the difference
+	  between consecutive buffers is important. Also, collectpads
+	  already replaces PTS/DTS with the running times for them.
+
+2015-04-06 22:36:43 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/qtmux.c:
+	  tests: qtmux: add tests to verify it handles non-0 segments
+	  Both input streams in this test have a segment.start = 10s, so
+	  output should start from 0 anyway.
+	  Another test has both starting at non-0 segments, but the running
+	  time of both streams should still start from 0
+
+2015-04-06 20:03:19 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/qtmux.c:
+	  tests: qtmux: simple muxing test
+	  Adds a new simple test that verifies that data is properly muxed
+	  and preserved.  PTS, DTS, duration and caps are verified.
+
+2015-04-10 10:59:26 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* gst/smpte/gstsmpte.h:
+	  smpte: remove unused fields
+	  Remove the fields - format and fps from smpte
+	  as they are unused.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747597
+
+2015-04-10 10:29:47 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/alpha.c:
+	  tests: add test suite for alpha
+	  Added test suite for alpha element with test cases
+	  1. alpha
+	  2. chroma keying
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747595
+
+2015-04-09 12:58:46 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* tests/check/gst-plugins-good.supp:
+	  suppressions: add a well known zlib inflate bug
+
+2015-04-09 12:58:26 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: fix mutex leak
+
+2015-04-09 12:58:04 +1000  Jan Schmidt <jan@centricular.com>
+
+	* tests/check/elements/rtprtx.c:
+	  tests: Fix rtprtx test by handling buffer lists
+	  Commit #1018aa made rtprtxsend handle buffer lists, breaking
+	  the test which probes for buffers, but not buffer lists.
+	  Use a utility function to run the probe callback on each buffer
+	  in the list in turn and remove any buffers that are dropped.
+
+2015-04-01 11:15:38 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  isomp4: Refactor various state variables into a mux_mode var
+	  Instead of checking various state variables around the muxer,
+	  track the current muxing mode in a single 'mux_mode' enum.
+	  Add some implementation notes about the different mux modes
+
+2015-04-08 16:40:02 +0200  Edward Hervey <edward@centricular.com>
+
+	* common:
+	* tests/check/Makefile.am:
+	  tests: Use AM_TESTS_ENVIRONMENT
+	  Needed by the new automake test runner
+
+2015-04-08 11:17:31 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtph263depay.c:
+	  rtph263depay: Fix framesize parsing
+	  The string passed to the parsing function only contains a framesize, and
+	  not <pt> + <framesize>
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726416
+
+2015-03-20 12:18:37 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: clip chunk size above the valid maximum (0x7fffffff)
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722567
+
+2015-03-20 09:07:35 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: clip chunk length to available data (when known)
+	  This prevents silly chunk lengths from possibly overflowing
+	  (at least when we know the actual data length).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722567
+
+2015-04-06 20:17:52 -0700  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Don't accumulate segment bases manually
+	  gst_segment_do_seek() does that for us already, and doing it twice
+	  will break non-flushing seeks in interesting ways. Leftover from 1.0
+	  porting.
+	  Also copy over segment offset and applied_rate, just in case.
+
+2015-04-06 19:08:10 -0700  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/icles/test-segment-seeks.c:
+	  icles: Fix waiting for segment-done if it happens too fast
+	  Sometimes we can get segment-done before we got async-done. If we waited
+	  for async-done only, the segment-done would be dropped and we would wait
+	  forever for it a few lines below.
+
+2015-04-06 18:55:08 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: stbl_index is valid from 0 onwards
+	  It indicates the last sample parsed, not the next one to parse.
+	  As it starts in -1, any value from 0 onwards means that it has
+	  some valid data.
+
+2015-04-05 20:06:09 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  docs: make GstRTCPSync enum show up in rtpbin docs
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747358
+
+2015-04-05 11:45:45 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  docs: add RTPJitterBufferMode enum to rtpbin docs
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747358
+
+2015-04-04 11:55:00 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: close files before posting message
+	  Makes sure the files were properly flushed and closed before
+	  the message reaches the application
+
+2015-03-30 13:54:23 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/multifile.c:
+	  tests: multifile: increment tests to check for multifile messages
+	  Also verify that the multifilesink file messages are being correctly
+	  posted to the bus
+
+2015-03-30 12:51:35 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/multifile.c:
+	  tests: multifile: handle FIXME for proper checking when test finished
+	  Use a GstBus and wait for EOS to finish the tests instead of
+	  relying on sleeping
+
+2015-03-30 11:14:09 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: post file message on EOS
+	  When multifilesink is operating in any mode other than one file
+	  per buffer, the last file created won't have a file message posted
+	  as multifilesink doesn't handle the EOS event.
+	  This patch fixes it by using the last position to post a file
+	  message when EOS is received. This should ensure at least the
+	  time related data and the filename are posted to the application
+	  or other elements
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747000
+
+2015-04-03 18:57:50 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* autogen.sh:
+	* common:
+	  Automatic update of common submodule
+	  From bc76a8b to c8fb372
+
+2015-04-03 02:08:50 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Guard against 64-bit overflow
+	  For large-file atoms, guard against overflow in the size field,
+	  which could make us jump backward in the file and cause
+	  infinite loops.
+
+2015-04-01 23:46:13 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	* tests/check/elements/qtmux.c:
+	  isomp4: Make non-seekable downstream an error in normal mode
+	  When not in fast-start or fragmented mode, we need to be able
+	  to rewrite the size of the mdat atom, or else the output just
+	  won't be playable - the mdat placeholder with size == 0 will
+	  cover the rest of the file, including any moov atom we write out.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=708808
+
+2014-03-15 15:23:01 +0100  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* tests/check/elements/rtp-payloading.c:
+	  rtph263pay/-depay: add framesize SDP attribute
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726416
+
+2014-03-15 13:33:56 +0100  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay/-depay: Remove incorrectly introduced framesize SDP attribute
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726415
+
+2015-03-27 21:09:44 +0100  Peter Seiderer <ps.report@gmx.net>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	  v4l2src: device sequence/offset correction in case of renegotiation
+	  The v4l2 device restarts the sequence counter in case of streamoff/streamon,
+	  the GST offset values are supposed to increment strictly monotonic, so
+	  adjust the sequence counter/offset values in case of caps
+	  renegotiation.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745441
+
+2014-11-14 14:18:51 +0100  Peter Seiderer <ps.report@gmx.net>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: add frame loss detection
+	  In case of v4l2 driver filled offset/sequence values add frame
+	  loss detection (and write a warning message).
+	  Move offset meta data setting and frame loss checking after the
+	  timestamp adjustment code to get proper timestamps for the
+	  warning message.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745441
+
+2014-11-14 13:48:51 +0100  Peter Seiderer <ps.report@gmx.net>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: use v4l2 capture device sequence counter
+	  Use the v4l2 capture device sequence counter for
+	  setting the GstBuffer offset/offset_end values.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745441
+
+2015-03-30 13:12:35 +0200  Tobias Modschiedler <tobias.modschiedler@cetitec.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Ask the driver about its requirements for min_buffers before initiating buffer pool.
+	  If propose_allocation() had not been called yet, it was possible that the driver was not asked at all.
+	  In buffer pool: Consider minimum number of buffers requested by driver when setting config.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746834
+
+2015-04-01 19:30:27 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpvp8depay.c:
+	* gst/rtp/gstrtpvp8depay.h:
+	  rtpvp8depay: Parse width/height/profile from keyframes
+	  This makes it possible to mux the result into a container
+	  such as matroska.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=747208
+
+2015-04-01 19:01:49 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: Expose VP8 width/height limitations in the caps template
+	  The VP8 format specification (RFC 6386 section 18.1) specifies
+	  that the maximum size is 16383x16383.
+
+2015-03-31 00:20:13 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flv: When passing seek event upstream, hold a ref.
+	  In case upstream can't handle the seek, make sure we
+	  keep a ref on the event to attempt to handle it ourselves.
+
+2015-03-26 13:34:53 +0100  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroska: fix GValue leaks when parsing tags
+	  gst_tag_list_add_value() doesn't consume the GValue we pass to it so there is
+	  no point copying it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746810
+
+2015-03-23 20:58:25 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: resurrect some flow return handling
+	  https://bugzilla.gnome.org/show_bug.cgi?id=744572
+
+2015-03-23 20:57:56 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: resurrect some flow return handling
+	  https://bugzilla.gnome.org/show_bug.cgi?id=744572
+
+2015-03-23 20:56:41 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: resurrect some flow return handling
+	  https://bugzilla.gnome.org/show_bug.cgi?id=744572
+
+2015-03-27 18:58:31 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.c:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-read-common.c:
+	  matroska: store stream tags and push as updated
+	  New tags can be found on different parts of the file, so this patch
+	  keeps the stream taglists around for the life cycle of the pad
+	  and adds those new tags as found. Then a new tag is found, the
+	  pad's is marked with a tags changed flag, making the element push
+	  a new tag event on the next check. Before this, we were sending
+	  only the newly found tags, as the element was losing its taglist
+	  when pushing the event.
+
+2015-03-15 14:40:36 +0100  Ramiro Polla <ramiro.polla@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: send global tags incrementally
+	  Instead of sending only new tags once they are found, merge the taglist
+	  and send them incrementally.
+
+2015-03-14 17:07:05 +0100  Ramiro Polla <ramiro.polla@collabora.co.uk>
+
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroskaparse: send global tags
+	  Global tags are already being read in matroskaparse, but they are not
+	  currently being sent.
+	  This patch makes global tags get sent incrementally whenever new ones
+	  are found.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746242
+
+2015-02-03 10:18:58 +0530  Vineeth T M <vineeth.tm@samsung.com>
+
+	* gst/effectv/gstquark.c:
+	  quarktv: fix "planes" property range, a value of 0 is not allowed
+	  When planes property is set to 0, the pipeline executes in
+	  an infinite loop and never exits. Since planes must never
+	  be 0, set the minimum value in the property description
+	  to 1.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=743906
+
+2015-03-26 13:42:02 -0700  David Schleef <ds@schleef.org>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Fix up comments regarding DTS
+
+2015-03-25 15:11:34 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Fix segment in TCP mode
+	  It is expected that buffers are time-stamped with running time. Set
+	  a segment accordingly. In this case we pick 0,-1 as this is what udpsrc
+	  would do. Depayloaders will update the segment to reflect the playback
+	  position.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=635701
+
+2015-03-26 12:21:25 -0700  David Schleef <ds@schleef.org>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: be more strict about typefinding DTS
+	  Code now matches comments.
+
+2015-03-25 15:10:53 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Remove useless function
+	  This function didn't do anything special, let's not use a function for
+	  that.
+
+2015-03-20 13:03:09 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitter: Account for rtx_retry in overflow check
+	  As rtx_retry is part of the substraction, we need to take it into
+	  account, otherwise we may endup with a big value.
+
+2015-03-24 23:15:15 +0000  Julien Isorce <j.isorce@samsung.com>
+
+	* sys/osxvideo/cocoawindow.m:
+	  osxvideosink: check for deprecated constants prior to OSX 10.10
+	  cocoawindow.m:339:5: error: 'NSOpenGLPFAWindow'
+	  is deprecated: first deprecated in OS X 10.9
+	  cocoawindow.m:576:7: error: 'NSOpenGLPFAFullScreen'
+	  is deprecated: first deprecated in OS X 10.6
+	  cocoawindow.m:605:24: error: 'setFullScreen'
+	  is deprecated: first deprecated in OS X 10.7
+
+2015-03-24 16:51:12 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Fix seeking query
+	  The segment start/stop in the query is meant to represent the seekable
+	  portion of the stream. It does not match the segment start/stop. Instead
+	  export 0 to duration.
+
+2015-03-24 16:18:53 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Only set caps once if they don't change
+	  Previously we were setting new caps with the same content for every H264 or
+	  AAC codec_data we found in the stream, spamming everything and causing
+	  renegotiations.
+
+2015-03-24 12:46:19 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Don't create AAC/H264 caps without codec_data
+	  Instead delay creating the caps until we read the codec_data from the stream,
+	  or fail if we get normal data before the codec_data.
+	  AAC raw caps and H264 avc caps always need codec_data, setting caps on the pad
+	  without them is going to make negotiation fail most of the time. Even if we
+	  later set new caps with the codec_data, that's usually going to be too late.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746682
+
+2015-03-24 15:39:22 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Fix indention
+
+2015-03-22 13:23:44 +0200  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxcoreaudio.h:
+	  osxaudio: Fix string format warning on 32-bit
+	  UInt32 (Darwin, not C99's uint32_t) is 'unsigned long' on 32-bit
+	  platforms.
+
+2015-03-21 17:50:40 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: Fix another instance of sticky event misordering warnings
+	  Make sure that the sync_src pad has caps before the segment event.
+	  Otherwise we might get a segment event before caps from the receive
+	  RTCP pad, and then later when receiving RTCP packets will set caps.
+	  This will results in a sticky event misordering warning
+	  This fixes warnings in the rtpaux unit test but also in the
+	  rtpaux and rtx examples in tests/examples/rtp
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746445
+
+2015-03-21 17:18:47 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: Also start the RTCP send thread when receiving RTP or RTCP
+	  Before we only started it when either:
+	  - there is no send RTP stream
+	  or
+	  - we received an RTP packet for sending
+	  This could mean that if the send RTP pads are connected but never receive any
+	  RTP data, and the same session is also used for receiving RTP/RTCP, we would
+	  never start the RTCP thread and would never send RTCP for the receiving part
+	  of the session.
+	  This can be reproduced with a pipeline like:
+	  gst-launch-1.0 rtpbin name=rtpbin \
+	  udpsrc port=5000 ! "application/x-rtp, media=video, clock-rate=90000, encoding-name=H264" ! rtpbin.recv_rtp_sink_0 \
+	  udpsrc port=5001 ! rtpbin.recv_rtcp_sink_0 \
+	  rtpbin.send_rtcp_src_0 ! fakesink name=rtcp_fakesink silent=false async=false sync=false \
+	  rtpbin.recv_rtp_src_0_2553225531_96 ! decodebin ! xvimagesink \
+	  fakesrc ! valve drop=true ! rtpbin.send_rtp_sink_0 \
+	  rtpbin.send_rtp_src_0 ! fakesink name=rtp_fakesink silent=false async=false sync=false -v
+	  Before this change the rtcp_fakesink would never send RTCP for the receiving
+	  part of the session (i.e. no receiver reports!), after the change it does.
+	  And before and after this change it would send RTCP for the receiving part of
+	  the session if the sender part was omitted (the last two lines).
+
+2015-03-19 11:54:12 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: Add support for buffer lists
+
+2015-03-19 11:39:38 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtprtxqueue.c:
+	  rtprtxqueue: Implement support for buffer lists
+
+2015-03-18 17:32:36 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Improve trace readability
+	  Change the command number into strings.
+
+2015-01-20 10:18:56 +0100  Jan Alexander Steffens (heftig) <jsteffens@make.tv>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	  flvdemux: Don't repeatedly warn after no_more_pads (v2)
+	  This can get rather spammy for such a high log level.
+	  Only warn once per stream.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746274
+
+2015-03-16 11:23:52 +0100  Jan Alexander Steffens (heftig) <jsteffens@make.tv>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Introduce constant for no-more-pads threshold
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746274
+
+2015-01-20 10:18:29 +0100  Jan Alexander Steffens (heftig) <jsteffens@make.tv>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Fix warning to contain 'video'
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746274
+
+2015-03-11 21:25:40 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	  matroskademux: for dts only stream set pts=dts for intra only formats
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745192
+
+2015-03-14 16:39:09 +0100  Ramiro Polla <ramiro.polla@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: fix sending of tags
+	  * Fix critical when new tags are found after segment event has already
+	  been sent.
+	  * Send global tags before stream tags.
+	  * Split sending of tags out of gst_matroska_demux_send_event() into its
+	  own function.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745973
+
+2015-03-13 18:26:06 +0000  Ramiro Polla <ramiro.polla@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: properly escape percent sign in documentation
+
+2015-03-13 18:26:44 +0000  Ramiro Polla <ramiro.polla@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpdtmfmux: properly escape percent sign in documentation
+
+2015-03-13 18:48:03 +0000  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	  v4l2src: delay renegotiation until it is likely buffers were reclaimed
+	  Allow renegotiation to happen when buffers have returned after an allocation
+	  query. As the allocation query is serialized, all buffers from the pool
+	  should have returned and we can stop it to create a new one for the
+	  new format
+	  https://bugzilla.gnome.org/show_bug.cgi?id=682770
+
+2015-03-13 18:47:55 +0000  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2object: add gst_v4l2_object_try_format
+	  Similar to set_format but it uses TRY_FMT instead of S_FMT
+	  https://bugzilla.gnome.org/show_bug.cgi?id=682770
+
+2015-03-13 18:38:42 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: fix crash with GST_DEBUG enabled
+	  g_inet_socket_address_get_address() does not give
+	  us a ref to the address, so don't unref it.
+
+2015-03-12 13:49:56 +0000  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/level/gstlevel.c:
+	  level: Don't read over the end of the input memory
+	  Previously we advanced the in_data pointer by bps for every channel, and then
+	  later again for block_size*bps. This caused us to be one sample further than
+	  expected if an input buffer covered two analysis frames. And in the end lead
+	  to completely bogus values reported by level.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=746065
+
+2015-03-12 01:37:08 +1100  Jan Schmidt <jan@centricular.com>
+
+	* sys/oss/gstossdmabuffer.c:
+	  Remove a couple of superfluous trailing semi-colons
+
+2015-03-10 09:31:20 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/alpha/gstalpha.c:
+	* gst/avi/gstavidemux.c:
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/isomp4/gstisoff.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/udp/gstmultiudpsink.c:
+	* sys/osxaudio/gstosxaudioringbuffer.c:
+	* sys/osxaudio/gstosxcoreaudiocommon.c:
+	  Fix double semicolons
+
+2015-03-10 15:46:40 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsrc.c:
+	  splitmux: Shut down element before downward state change
+	  Make sure the state change won't hang trying to shut down pads
+	  by making sure the streaming has stopped before chaining up.
+
+2015-03-09 22:58:05 +0200  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxcoreaudio.h:
+	  osxaudio: stream format is an SPDIF-only field
+
+2015-03-09 22:53:41 +0200  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxaudiosrc.h:
+	  osxaudio: fix spaces
+
+2015-03-09 22:52:46 +0200  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxaudiosrc.h:
+	  osxaudio: add type check macro
+
+2015-03-09 22:51:51 +0200  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxcoreaudiocommon.c:
+	* sys/osxaudio/gstosxcoreaudiocommon.h:
+	* sys/osxaudio/gstosxcoreaudiohal.c:
+	  osxaudio: rename gst_core_audio_set_channels_layout()
+	  to gst_core_audio_get_channel_layout().
+
+2015-03-09 22:30:28 +0200  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxaudioringbuffer.c:
+	  osxaudio: remove unused finalize
+
+2015-03-09 16:25:43 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* ext/vpx/gstvp9enc.c:
+	  vp9enc: remove duplicate declaration of function
+
+2015-03-09 16:22:29 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: remove unused value
+	  CID #1226474
+
+2015-03-09 16:14:34 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: fix leak
+	  CID 1212156
+
+2015-03-09 15:58:33 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: remove uneeded variable
+	  We just need to save the ebit information in case there is an error decoding.
+
+2015-03-09 16:46:02 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp9enc.c:
+	  vp[89]enc: Reset the encoder when flushing
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745704
+
+2015-03-09 12:51:17 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/matroska/matroska-parse.c:
+	  matroska: error mode if can't push buffer
+	  If gst_pad_push() fails, inform and return flow error.
+
+2015-03-09 12:13:34 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/matroska/matroska-parse.c:
+	  matroska: unused value
+	  Value set in ret will be overwritten just before exiting the function.
+	  CID #1226469
+
+2015-03-09 11:10:35 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Drop packets with sequence numbers before the seqnum-base
+	  These are outside the expected range of sequence numbers and should be
+	  clipped, especially for RTSP they might belong to packets from before a seek
+	  or a previous stream in general.
+
+2014-02-27 10:52:16 +0100  Linus Svensson <linussn@axis.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Don't include payload type in the caps for framesize
+	  When the sdp media attribute framesize are converted to caps
+	  the <payload> should not be included.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=725335
+
+2015-03-09 10:05:14 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Don't forget to unlock the mutex when receiving GAPs in TCP streams
+
+2015-03-09 11:24:58 +0530  Arun Raghavan <arun@centricular.com>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Make sure to filter caps in all cases during CAPS query
+	  We were skipping the filter step while returning template caps, for
+	  example.
+
+2015-03-08 21:15:53 +0000  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Don't update buffer for OUTPUT
+	  For output device, we should not update the buffer with flags and
+	  timestamp when we dequeue. The information in the v4l2_buffer is not
+	  meaningful and it breaks the case where the buffer is rendered at
+	  multiple places.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745438
+
+2015-03-08 18:04:34 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	  souphttpclientsink: Implement cookies property
+
+2015-03-08 18:02:51 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	  souphttpclientsink: Implement automatic-redirect property
+
+2015-03-08 17:54:07 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	  souphttpclientsink: Implement proxy support
+	  The properties were there before, but not used anywhere.
+
+2015-02-21 20:05:24 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: resurrect some flow return handling
+
+2015-03-04 10:27:17 +0100  Nicolas Huet <nicolas.huet@parrot.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: fix LOAS parsing issue
+	  Fix missing index in syncword searching
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745585
+
+2015-03-05 17:54:43 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: fix modulo math with ringbuffer parameters
+	  To get a multiple of bpf use a subtraction and not an addition
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745684
+
+2015-03-07 00:55:47 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: Protect property variables with the object lock.
+	  Use the object lock instead of the splitmux lock to protect
+	  internal property variables, so they're not locked when
+	  switching to a new file.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=744420
+
+2015-03-06 11:39:39 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  check: add jitterbuffer unit test
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=745539
+
+2015-03-05 09:18:52 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Fix handling of interleaved (TCP) streams
+	  We need to set up the transport in any case, not just if we have a container
+	  stream or a non-interleaved stream. Only if we have an interleaved stream and
+	  are retrying, we should not set up the stream again.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745599
+
+2015-03-05 10:00:33 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/vpx/gstvp8dec.c:
+	* ext/vpx/gstvp9dec.c:
+	  vp[89]dec: Drop frames that have no output buffer because of errors
+	  finish_frame() assumes that there is an output buffer.
+
+2015-03-05 09:56:23 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Don't unref caps we don't own
+
+2015-03-05 09:46:17 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Push RTCP caps on the RTCP pads
+	  Otherwise we will get not-negotiated later from rtpbin, and will never be able
+	  to send RTCP packets back to the server. Note that error flow returns from the
+	  RTCP pads are ignored, that's why it didn't fail more visible before.
+
+2015-03-05 09:35:32 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Make sure to send SEGMENT events on all pads
+
+2015-03-03 16:23:15 +0100  Santiago Carot-Nemesio <sancane@gmail.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpstats.h:
+	  rtp: Add Full Intra Request (FIR) packets to statistics
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745587
+
+2015-03-03 16:01:53 +0100  Santiago Carot-Nemesio <sancane@gmail.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpstats.h:
+	  rtp: Add Packet Loss Indication (PLI) to statistics
+	  This is helpful to provide statistics in the format defined in
+	  http://w3c.github.io/webrtc-stats/#dictionary-rtcrtpstreamstats-members.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745587
+
+2015-03-03 19:19:50 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: Remove duration accumulation logic
+	  Duration accumulation can cause rounding errors and generate wrong
+	  duration with different buffers that share the same timestamp.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745192
+
+2015-03-03 18:40:16 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.c:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.c:
+	  matroska: Add an helper method to get buffer timestamps
+	  ... and replace GST_BUFFER_TIMESTAMP that always return PTS with this method
+	  that return PTS or DTS based on stream type.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745192
+
+2015-03-04 11:28:12 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Add explanation why we have space for 32 hash tables
+	  And also create only one, there's no need yet to create all 32 until
+	  we implement RFC2762.
+
+2015-03-04 11:26:57 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  Revert "rtpsession: Do not use an array of maps if they are not being used"
+	  This reverts commit 1591adf4cd843d13d8622a30c619425691a84128.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745586#c1:
+	  It's the beginning of an implementation of RFC 2762, which is needed for
+	  large multicast groups. The implementation is not yet complete but why
+	  not leave what is there and implement RFC 2762 instead?
+
+2015-03-04 10:35:12 +0100  Santiago Carot-Nemesio <sancane@gmail.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Do not use an array of maps if they are not being used
+	  rtpsession declares an array of maps to store srrcs but only the
+	  the key 0 is being used. This patch replaces the array of maps
+	  for just one map and remove useless parameters in rtpsession
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745586
+
+2015-02-27 18:12:09 +0900  Jimmy Ohn <yongjin.ohn@lge.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: remove not needed code
+	  In gst_avi_demux_handle_src_query, there is not needed code.
+	  We already check about stream is vbr or not at the upper line.
+	  o, we don't need to check this condition becase stream is not
+	  vbr 100% in this case.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745276
+
+2015-03-03 23:25:35 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/icles/gdkpixbufoverlay-test.c:
+	  tests: gdkpixbufoverlay-test: replace deprecated function
+	  Just avoid using the deprecated function entirely,
+	  it's easy enough. Defining the macro is not enough.
+
+2015-03-03 19:04:48 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/icles/gdkpixbufoverlay-test.c:
+	  tests: gdkpixbufoverlay-test: fix compilation against newer gdk-pixbuf
+	  gdk_pixbuf_new_from_inline() has been deprecated in favour
+	  of GResource.
+
+2015-03-03 18:39:15 +0530  Arun Raghavan <arun@centricular.com>
+
+	* sys/osxaudio/gstosxaudiosrc.c:
+	  osxaudiosrc: Allow caps renegotiation
+	  The ringbuffer does allow renegotiation, so we do not have to report
+	  fixed caps once it is acquired (based on a similar patch for the sink
+	  side by Ilya Konstantinov <ilya.konstantinov@gmail.com>).
+
+2015-02-21 14:41:08 +0200  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	  osxaudiosink: Allow renegotiating caps
+	  Once osxaudiosink's device is open, it fixates on the initial caps and
+	  refuses to accept new caps. This is erroneous since the Audio Unit is
+	  can accept a new ASBD, and GstAudioRingBuffer supports reconfiguration
+	  as well.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=743925
+
+2015-03-02 12:04:00 +0100  Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2allocator: fix fd leak in DMABUF import mode.
+	  Ensure gst_v4l2_buffer_pool_release_buffer() releases the associated
+	  GstV4l2MemoryGroup. In particular, this allows for closing the DMABUF
+	  handles prior to instantiating new ones.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745443
+
+2015-03-02 15:06:09 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: Use 0 as duration for the EOS "frame"
+
+2015-03-02 15:02:20 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp8enc.h:
+	* ext/vpx/gstvp9enc.c:
+	* ext/vpx/gstvp9enc.h:
+	  vp{8,9}enc: Tell the encoder about actual timestamps and durations of frames
+	  ... instead of just counting frames. The values are supposed to be in timebase
+	  units, not frame units. This fixes various quality problems with VP8/VP9
+	  encoding and in general makes the encoder behave better.
+	  Thanks to Nirbheek Chauhan for noticing this bug.
+
+2015-03-01 13:56:17 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* ext/vpx/gstvp8dec.c:
+	* ext/vpx/gstvp9dec.c:
+	  vpxdec: Fix calculation of width in bytes
+	  Right now we only support I420, but vpx seems to support more formats.
+	  This will prevent hard to find bug in the future.
+
+2015-03-01 13:52:50 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* ext/vpx/gstvp8dec.c:
+	* ext/vpx/gstvp9dec.c:
+	  vpxdec: Don't memcpy in frame map failed
+	  This avoid a crash if mapping the frame failed.
+
+2015-03-01 13:48:45 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Add missing break
+	  This is cosmetic change.
+
+2015-03-01 13:46:18 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2: Workaround driver not setting field correctly
+	  As it's very common, handle driver not setting field in buffers
+	  by using the field value from the format. This workaround a long time
+	  bug in UVC driver. For even buggier driver, we simply assume
+	  progressive as before. We also only warn once, to avoid spamming.
+
+2015-02-28 18:10:06 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix key unit seek
+	  Unlike many other seek flags, the KEY_UNIT seek
+	  flag is not copied over into the GstSegment,
+	  since it's only relevant for the seek itself,
+	  so we need to pass it explicitly to the seek
+	  handler here.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745339
+
+2015-02-27 09:38:01 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	  docs/plugins: Updates
+
+2015-02-26 23:41:47 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	  matroskamux/demux: initialize dts_only
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745192
+
+2015-02-26 23:28:11 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: store DTS for V_MS/VFW/FOURCC streams
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745192
+
+2015-02-26 19:48:33 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsrc.c:
+	  multifile: attempt to fix docs build issue on build bot
+
+2015-02-27 00:41:46 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* gst/interleave/interleave.c:
+	  interleave: Drop custom latency query handling
+	  This is implemented by the default query handler now.
+
+2015-02-27 00:40:05 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Drop custom latency querying logic
+	  This is now implemented in the default latency query handler.
+
+2015-02-26 16:10:41 +0100  Sebastian Rasmussen <sebrn@axis.com>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	  rtpvorbispay: fix payloader description and author e-mail
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745226
+
+2014-09-05 16:34:26 +0200  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2: query crop configuration after each call of S_CROP
+	  S_CROP ioctl is write-only and the device can adjust crop rectangle so
+	  we query back the crop configuration after each S_CROP to know what has
+	  been done.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736133
+
+2015-02-26 02:12:18 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	  matroskademux: V_MS/VFW/FOURCC streams have DTS instead of PTS
+	  When such stream is present demuxer should set DTS on buffers instead
+	  of PTS. This is consistent with how VLC and libav/ffmpeg handle VFW
+	  streams.
+	  Sample file
+	  https://s3.amazonaws.com/MatejK/Samples/Matroska-VFW-DTS-Only.mkv
+	  https://bugzilla.gnome.org/show_bug.cgi?id=745192
+
+2015-02-25 16:45:11 -0800  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Check corruption flag on the right buffer
+	  We where checking the buffer we are copying to instead of the buffer we
+	  are copying from.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740040
+
+2015-01-19 15:29:24 +0100  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: set colorspace in caps for capture devices
+	  This information is set by the driver for a capture device, and so could
+	  be forwarded to pipeline by setting the colorimetry in caps.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=743186
+
+2014-10-06 17:30:06 +0200  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2bufferpool: fix import_userptr() in single-planar API when n_planes > 1
+	  In the V4L2 single-planar API, when format is semi-planar/planar,
+	  drivers expect the planes to be contiguous in memory.
+	  So this commit change the way we handle semi-planar/planar format
+	  (n_planes > 1) when we use the single-planar API (group->n_mem == 1).
+	  To check that planes are contiguous and have expected size, ie: no
+	  padding. We test the fact that plane 'i' start address + plane 'i'
+	  expected size equals to plane 'i + 1' start address. If not, we return
+	  in error.
+	  Math are done in bufferpool rather than in allocator because the
+	  former is aware of video info.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=738013
+
+2015-01-23 10:15:46 +0100  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2allocator.h:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2allocator: let bufferpool calculate image size when importing userptr
+	  Offset are relative to the buffer and there is no guarantee substracting
+	  them will give us the plane size. So we let bufferpool make the math as
+	  it is more aware of video info than allocator and pass a size array to
+	  allocator import function.
+	  Pointed out by Nicolas Dufresne <nicolas.dufresne@collabora.com>
+	  https://bugzilla.gnome.org/show_bug.cgi?id=738013
+
+2014-12-11 16:13:15 +0100  Philippe De Muyter <phdm@macqel.be>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: recognize and distinguish all bayer arrangements
+	  Up to now, v4l2src recognized only "bggr" amongst the bayer arrangements.
+	  Recognize now also the "rggb", "gbrg" and "grbg" arrangements.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742363
+
+2015-01-15 16:11:53 +0100  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: set v4l2_buffer.field when queuing buffer in an output device
+	  According to the current specification, application must set this field
+	  for an output device.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=743013
+
+2015-02-24 05:57:24 +0200  Ilya Konstantinov <ilya.konstantinov@gmail.com>
+
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxaudio/gstosxcoreaudio.c:
+	* sys/osxaudio/gstosxcoreaudio.h:
+	* sys/osxaudio/gstosxcoreaudiocommon.c:
+	* sys/osxaudio/gstosxcoreaudiocommon.h:
+	  osxaudiosrc: iOS resampling causes stuttering
+	  Fixes stuttering audio when iOS AU is resampling. To make AU resample,
+	  one has to request a rate that differs from AVAudioSession's
+	  sampleRate. The resampling itself is not the culprit, but rather our
+	  API misuse.
+	  AudioUnitRender modifies the mDataByteSize members with the
+	  actual read bytes count. Therefore, they must be reinitialized
+	  before each AudioUnitRender. (The buffers themselves can be
+	  preallocated.)
+	  The "stutter" was caused by one AudioUnitRender making the buffer
+	  too small for other AudioUnitRender invocations, making them fail
+	  with -50 (paramErr). By way of luck, when AU didn't resample, all
+	  AudioUnitRender invocations read the same number of bytes.
+	  (This patch addresses some non-interleaved audio concerns, but
+	  at this moment the elements do not support non-interleaved audio
+	  and non-interleaved is untested.)
+	  https://bugzilla.gnome.org/show_bug.cgi?id=744922
+
+2015-02-22 01:49:52 +0100  Krzysztof Kotlenga <pocek@users.sf.net>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: improve error message when unauthorized
+	  Make use of NOT_AUTHORIZED error code instead of falling back to generic
+	  READ error.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=601733
+
+2015-02-23 20:06:25 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* sys/ximage/ximageutil.c:
+	  ximagesrc: remove pointless g_return_val_if_fail()
+	  ximage won't ever be NULL here because the dispose
+	  function is called via ximage->dispose().
+
+2015-02-23 19:40:25 +0100  Thibault Saunier <tsaunier@gnome.org>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: All segment resulting from a seek should have the same seqnum
+	  https://bugzilla.gnome.org/show_bug.cgi?id=744983
+
+2015-02-19 23:12:31 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Enable copy when no known allocation params
+	  When there is no allocation parameters in the query, enable copy
+	  threshold. When this threshold is reached, the buffer pool will start
+	  copying when the pool reaches a critical level. If the driver supports
+	  CREATE_BUFS, this will be used instead.
+
+2015-02-19 23:08:34 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Update allocator flags
+	  When we hit emulated formats, we disable CREATE_BUFS since libv4l2
+	  cope very badly with it. Also clear the allocator flags so we will
+	  never try to allocate more buffers. This fixes failure when the copy
+	  threshold is reached as we where calling CREATE_BUFS, which lead to
+	  libv4l2 instability.
+
+2015-02-19 23:07:23 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Use specific debug category
+	  The pool has grown enough that it is now handy to seperate v4l2object
+	  trace from v4l2bufferpool trace.
+
+2015-02-19 14:29:02 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8pay: default encoding name to VP8
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737810
+
+2015-02-19 14:06:51 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8pay: make caps writable before truncating them
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737810
+
+2015-02-05 10:29:26 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8pay: negotiate encoding name
+	  Chrome uses a different one than gstreamer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737810
+
+2015-02-19 12:35:07 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: Send initial events on sync_rtcp pad when using RTP/RTCP muxing
+	  Otherwise we will just send buffers on the pad without any events beforehand
+	  and will get g_warnings() about that.
+
+2015-02-19 11:20:51 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: case missing break statement
+	  commit b1098c2ea5eabea7af08ce51d22b867eaed2bbe2 added a new case in
+	  gst_jack_audio_src_get_property() but forgot to add the break statement to it.
+
+2015-02-18 19:18:00 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* sys/v4l2/v4l2_calls.c:
+	  Revert "v4l2: fraction is reversed"
+	  This reverts commit b91fe36644b15ae070d72b9e8a9c7087e82aef12.
+
+2015-02-18 17:49:29 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: fraction is reversed
+	  In the fraction 1 / 2. 1 is the numerator and 2 is the denominator.
+	  The arguments of fraction gst_value_set_fractions() are value,
+	  numerator and denominator.
+	  Also, gst_value_set_fraction() fails if denominator is 0 for obvious
+	  reasons.
+
+2015-02-17 20:26:55 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2pool: Deactivate other pool
+	  When importing buffers from a downstream pool, we need to deactivate
+	  that pool to ensure it will be usable again later. Relying on the
+	  refcount to reach zero does not work, since elements like xvimagesink
+	  keeps a reference on their proposed pool.
+
+2015-02-18 10:10:53 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux.c:
+	  qtmux: remove not needed condition
+	  gst_buffer_replace can handle NULL inputs by itself
+
+2015-02-18 09:40:14 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: prefer the tfdt timestamp over the buffer's that is less accurate
+	  The tfdt should be more accurate as the buffer timestamp is provided
+	  by the fragmented format manifest and it might just be an approximation.
+
+2015-02-17 16:57:55 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: When resetting the jitterbuffer because of packet discont, don't flush sticky events
+	  We will otherwise flush away STREAM_START, CAPS or SEGMENT events and will
+	  confuse downstream with buffers that come before such events.
+
+2015-02-17 12:20:57 +0100  hark <hark@puscii.nl>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosink.h:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jack/gstjackaudiosrc.h:
+	  jack: Add property port-pattern to specify which JACK ports to connect to
+	  https://bugzilla.gnome.org/show_bug.cgi?id=690719
+
+2015-02-17 12:31:06 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/gstisoff.c:
+	* gst/isomp4/gstisoff.h:
+	* gst/isomp4/qtdemux.c:
+	  isomp4: Redefine gst_isoff_ symbols to gst_isoff_qt_
+	  We need different symbol names, because these symbols are also present
+	  in the fragmented plugin ... which will cause conflicts when doing
+	  static linking
+
+2015-02-16 14:31:05 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/goom2k1/lines.c:
+	  goom2k1: use fractional part of float division
+
+2015-02-16 13:59:14 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsin: remove dead code
+	  Every instance of goto beach has buf_info equal NULL. Don't check
+	  for a condition that never happens.
+	  CID #1268399
+
+2015-02-15 21:45:24 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* tests/check/elements/splitmux.c:
+	  splitmux-test: Parse error message
+	  The test had a function to print the error, but was not parsing it.
+	  This was causing warning about dbg_info being used uninitialized. If
+	  the test was testing any errors, this would have crashed.
+
+2015-02-15 21:34:28 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: Fix min and max for bands property
+	  The number of FFTs is calculated with the following formula:
+	  guint nfft = 2 * bands - 2;
+	  nfft is passed to gst_fft_f32_new() as the len argument and is of type
+	  unsigned integer. This method required that len is at leas 1, then
+	  maximum G_MAXINT, as other values would be negative. If we extrapolate
+	  from the formula above it means we need "bands" to be between 2 and
+	  ((guint)G_MAXINT + 2) / 2).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=744213
+
+2015-02-15 15:51:55 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Fix freeing of shared memory
+	  When memory (that has been shared using gst_memory_share()) are freed,
+	  the memory (or the DMABUF FD) should not bee freed. These memories have
+	  a parent. This also removes the extra _v4l2mem_free function and avoid
+	  calling close twice on the DMABUF FD.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=744573
+
+2015-02-14 11:11:30 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: do not use sparse streams in push-based seeking
+	  Using the sparse streams can make the push-based seeking return
+	  too far in the stream. It also can lead to issues as the
+	  sparse streams will be ignored when restarting playback and,
+	  if the sparse stream is the one that has the earliest sample,
+	  it will confuse qtdemux's offsets as one stream will have
+	  an earlier offset than the demuxer's one which might lead to
+	  early EOS.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742661
+
+2015-02-13 19:43:16 +0900  Jimmy Ohn <yongjin.ohn@lge.com>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Enhance code readability in pulsesink_query
+	  In pulsesink_query function, we use a switch for the query
+	  type. In the CAPS case, there is no 'break', instead we
+	  return right away. Use a break and return at the end of
+	  the function instead for better code readability.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=744461
+
+2015-02-13 20:40:48 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: flag as sink from the start
+
+2015-02-11 15:30:44 +0100  Philippe Normand <philn@igalia.com>
+
+	* gst/isomp4/Makefile.am:
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/gstisoff.c:
+	* gst/isomp4/gstisoff.h:
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: Initial 'sidx' atom parsing support
+	  Parse the 'sidx' atom and update the total duration according to the
+	  parser result. The isoff parser code is imported from
+	  gst-plugins-bad's dashdemux and a gst_isoff_sidx_parser_add_data()
+	  function was factored out of the gst_isoff_sidx_parser_add_buffer()
+	  function.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=743578
+
+2015-02-11 05:06:45 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/flv/Makefile.am:
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Use gst_video_guess_framerate()
+	  Use gst_video_guess_framerate() from libgstvideo to guess
+	  sensible common framerates where possible from the
+	  floating point fps in the stream.
+
+2015-02-11 13:53:02 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/raw1394/gstdv1394src.c:
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp9enc.c:
+	* gst/interleave/interleave.c:
+	* gst/rtsp/gstrtpdec.c:
+	* gst/videomixer/videomixer2.c:
+	  Improve and fix LATENCY query handling
+	  This now follows the design docs everywhere, especially the maximum latency
+	  handling.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=744106
+
+2015-02-11 10:29:55 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Handle first RTCP packet and early feedback correctly
+	  According to RFC 4585 section 3.5.3 step 1 we are not allowed to send
+	  an early RTCP packet for the very first one. It must be a regular one.
+	  Also make sure to not use last_rtcp_send_time in any calculations until
+	  we actually sent an RTCP packet already. In specific this means that we
+	  must not use it for forward reconsideration of the current RTCP send time.
+	  Instead we don't do any forward reconsideration for the first RTCP packet.
+
+2015-02-10 18:53:53 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtp/gstrtph263depay.c:
+	  rtph263depay: fix compilation with gcc 5.0
+
+2015-02-10 16:00:07 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmuxsink: fix example pipeline properly
+	  x264enc might not have a max-key-int property, but it
+	  has a key-int-max property...
+
+2015-02-10 14:57:55 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/multifile/gstsplitmuxsrc.c:
+	  splitmux: fix typo
+
+2015-02-10 14:56:23 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmux: update example pipeline
+	  Element x264enc doesn't have a max-key-int property
+
+2015-02-10 13:29:32 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/multifile/gstsplitmuxsink.c:
+	  splitmux: fix memory leak
+	  If execution goes to the beach in line 981, buf_info goes out of scope without
+	  the memory being free'd. Handle this case.
+	  CID #1268403
+
+2015-02-08 12:03:10 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix awkward if clause
+
+2015-02-07 01:41:49 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	* gst/multifile/gstsplitmuxsink.c:
+	* tests/check/elements/splitmux.c:
+	  splitmux: Add unit test for file splitting
+	  Add a unit test for file splitting, and fix the leaks in the
+	  splitmuxsink it found
+
+2015-02-06 14:43:22 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: fix which stop variable is used in assignment
+	  Assignment is done to variable segment.stop when the intention was to assign to
+	  local variable stop. Instead of overwriting it, the value is now clamped and
+	  segment.stop is set to it soon after.
+	  CID #1265773
+
+2015-02-07 00:19:36 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	* gst/multifile/gstsplitmuxsrc.c:
+	* tests/check/elements/splitmux.c:
+	  splitmux: Fix memory leaks until the test valgrinds clean
+
+2015-02-06 06:42:17 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/multifile/gstsplitmuxpartreader.c:
+	  splitmux: Handle early EOS during part preparation
+	  Handle the case where a short file reaches EOS while we're still
+	  waiting for no-more-pads, and make sure we continue to the internal
+	  READY state for real playback to work properly later.
+
+2015-02-06 05:03:19 +1100  Jan Schmidt <jan@centricular.com>
+
+	* tests/files/splitvideo00.ogg:
+	* tests/files/splitvideo01.ogg:
+	* tests/files/splitvideo02.ogg:
+	  tests: Change splitmux test video files
+	  Avoid test failure by changing the stored video resolution
+	  from 80x60 to 80x64, which needs bug 741030 to be fixed.
+
+2014-08-01 00:07:53 +1000  Jan Schmidt <jan@centricular.com>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* gst/multifile/Makefile.am:
+	* gst/multifile/gstmultifile.c:
+	* gst/multifile/gstsplitfilesrc.c:
+	* gst/multifile/gstsplitmuxpartreader.c:
+	* gst/multifile/gstsplitmuxpartreader.h:
+	* gst/multifile/gstsplitmuxsink.c:
+	* gst/multifile/gstsplitmuxsink.h:
+	* gst/multifile/gstsplitmuxsrc.c:
+	* gst/multifile/gstsplitmuxsrc.h:
+	* gst/multifile/gstsplitutils.c:
+	* gst/multifile/gstsplitutils.h:
+	* gst/multifile/test-splitmuxpartreader.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/splitmux.c:
+	* tests/files/splitvideo00.ogg:
+	* tests/files/splitvideo01.ogg:
+	* tests/files/splitvideo02.ogg:
+	  splitmux: Implement new elements for splitting files at mux level.
+	  Implement 2 new elements - splitmuxsink and splitmuxsrc.
+	  splitmuxsink is a bin which wraps a muxer and takes 1 video stream,
+	  plus audio/subtitle streams, and starts a new file
+	  whenever necessary to avoid overrunning a threshold of either bytes
+	  or time. New files are started at a keyframe, and corresponding audio
+	  and subtitle streams are split at packet boundaries to match
+	  video GOP timestamps.
+	  splitmuxsrc is a corresponding source element which handles
+	  the splitmux:// URL and plays back all component files,
+	  reconstructing the original elementary streams as it goes.
+
+2015-02-04 16:32:14 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/souphttpsrc.c:
+	* tests/files/test-cert.pem:
+	* tests/files/test-key.pem:
+	  tests: souphttpsrc: update ssl key/cert pair
+	  Our ones were expired. The new ones were copied from libsoup's
+	  tests files.
+	  Also sets the property to use our own cert to validate the
+	  server, otherwise the default system certs would be used
+	  and it would fail.
+
+2015-02-04 02:25:44 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: prevent trying to get 0 bytes from adapter
+	  This causes an assertion and would lead to getting a NULL instead
+	  of a buffer. Without proper checking this would easily lead to
+	  a segfault
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737199
+
+2015-02-04 21:50:51 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Simple implementation of GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS
+	  When the trickmode key-units flag is set on the segment, simply skip
+	  any sample on a video stream that isn't a keyframe
+
+2015-02-03 17:35:52 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix container handling
+	  We detect a container correctly now so we need to revert the weird
+	  check there was before.
+	  Use gst_rtspsrc_stream_push_event() to push the caps event on the
+	  right pad.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=739391
+
+2015-02-02 19:46:27 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: store and write stream tags
+	  Separate global from stream tags storage and write them to the
+	  appropriate tags entry in the output
+
+2015-02-02 13:35:59 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: parse stream tags
+	  Keep global and stream tags separately and parse the udta node
+	  that can be found under the trak atom. The udta will contain
+	  stream specific tags and will be pushed as such
+	  https://bugzilla.gnome.org/show_bug.cgi?id=692473
+
+2015-01-31 14:32:34 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  qtmux: store stream and container tags separately
+	  Tags received via events, when marked as stream tags, will
+	  be stored on that stream's trak atom instead of being stored
+	  in the main tags atom. This allows the resulting file to have
+	  global and stream tags stored.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=692473
+
+2015-01-31 13:14:44 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: refactor tags functions to accomodata UDTA at trak level
+	  Refactor the functions that were bound to the 'moov' atom to
+	  directly pass the desired 'udta' that should receive the tags.
+	  This allows the tags to be written to 'udta' at the 'moov' or
+	  the 'trak' level, creating tags that are for the container or
+	  for a stream only.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=692473
+
+2015-01-31 10:47:40 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: map application name to _swr tag
+	  It refers to the application name and version used to create the
+	  file
+	  https://bugzilla.gnome.org/show_bug.cgi?id=692473
+
+2015-01-31 02:30:40 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: Fix seeking past the end of the file in reverse mode.
+	  Snap to the end of the file when seeking past the end in reverse mode,
+	  and also fix GST_SEEK_TYPE_END and GST_SEEK_TYPE_NONE handling
+	  for the stop position by always seeking on a segment in stream time
+
+2015-01-30 18:22:31 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Fix signal name
+	  This wasn't meant to be pushed at all yet, but now that it's there
+	  already it won't hurt to make it correct at least.
+
+2015-01-30 16:56:35 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpstats.h:
+	  rtpstats: Fix typo in documentation
+
+2015-01-30 16:50:36 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Add new on-receiving-rtcp signal
+	  This will be emitted whenever an RTCP packet is received. Different to
+	  on-feedback-rtcp, this signal gets every complete RTCP packet and not
+	  just the individual feedback packets.
+
+2015-01-28 14:02:15 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: simplify segment.base math
+	  Remove a fix for heavily edited files added for fixing
+	  https://bugzilla.gnome.org/show_bug.cgi?id=345830 to work
+	  with seeks and proper gaps playback. The fix was replaced
+	  for a more general solution that bases on using previous
+	  segment's duration, just like it works for media segments
+	  playback.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=743518
+
+2015-01-27 14:00:35 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/videomixer/videomixerorc-dist.c:
+	  videomixer: update orc files
+
+2015-01-26 17:08:12 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix data dropping for fragmented streams
+	  For fragmented streams with extra data at the end of the mdat
+	  qtdemux was not dropping those bytes and would try to use
+	  that extra data as the beginning of a new atom, causing the
+	  stream to fail.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=743407
+
+2015-01-25 17:30:33 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Deprecate rtcp-immediate-feedback-threshold property
+	  It had no effect since quite some time and also is not needed in general,
+	  especially not to switch between immediate feedback mode and early feedback
+	  mode. The latest understanding of the RFC is that from the endpoint point of
+	  view, both modes are exactly the same. RTCP is only allowed to use the
+	  bandwidth as given by the RFC constraints, as such it is only ever possible
+	  to schedule a RTCP packet early but it's against the RFC to schedule more RTCP
+	  packets.
+	  The difference between immediate feedback mode and early feedback mode is that
+	  the former guarantees that an RTCP packet can be sent for every event
+	  "immediately", which means that the bandwidth calculations from the RFC have
+	  resulted in an RTCP scheduling interval that is small enough. Early feedback
+	  mode on the other hand means that we can schedule some packets early to make
+	  that happen, but it's not guaranteed at all that it's possible to schedule
+	  an RTCP packet per event (i.e. they need to be accumulated or dropped).
+
+2015-01-22 10:29:39 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Delay the next regular RTCP packet after early RTCP
+	  This is required to not exceed the short term average RTCP bitrate when
+	  using early feedback as compared to without early feedback.
+
+2015-01-22 10:28:52 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Add new send-rtcp-full signal
+	  This indicates with a boolean return value if scheduling a new RTCP packet
+	  within the requested delay was possible. Otherwise it behaves exactly like
+	  send-rtcp. The only reason for adding a new signal is ABI compatibility.
+
+2015-01-20 00:32:00 +0000  Jimmy Ohn <yongjin.ohn@lge.com>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Free format_info in query_getcaps
+	  If we can not create probe stream in query_getcaps function, it will appear
+	  memory leakage from format info.
+	  The following patch prevent memory leakage in pulsesink.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=743178
+
+2015-01-23 17:35:51 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: remove unnecessary check
+	  No matter if gst_matroska_read_common_parse_index_cuetrack () returns that the
+	  flow is OK or not, the check there will be a break from the switch. Removing the
+	  check since the outcome is the same.
+	  CID #1265762
+
+2015-01-23 15:16:25 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Avoid using freed variable
+	  the name variable might have been attributed to pad_name, make sure we
+	  free it only *after* pad_name has been used.
+	  Coverity CID : 1265774
+
+2015-01-23 15:13:55 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavimux.c:
+	  avimux: Avoid using freed variable
+	  the name variable might have been attributed to pad_name, make sure we
+	  free it only *after* pad_name has been used.
+	  Coverity CID : 1265775
+
+2014-11-14 12:59:31 +0100  Peter Seiderer <ps.report@gmx.net>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: reuse caps framerate if not overwritten by v4l2 device
+	  Enables duration setting in v4l2src.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740403
+
+2015-01-22 10:29:24 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Fix indention
+
+2015-01-21 17:36:26 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux_dump.c:
+	  qtdemux_dump: Bypass even more code if debugging is disabled
+	  And avoid using variables that won't exist when debugging is disabled
+
+2015-01-21 15:30:33 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux_dump.c:
+	  qtdemux: Only traverse/dump nodes if guaranteed to be used
+	  __gst_debug_min is the "global" lowest debug level set. There's no
+	  guarantee the qtdemux debug category is actually set at that level.
+
+2014-12-20 17:09:14 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/matroska/ebml-read.c:
+	  matroska: Avoid debugging below category threshold
+	  This part alone was what made the matroska thread take a full core
+	  on an android phone ...
+
+2015-01-21 09:55:30 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/dv/gstsmptetimecode.c:
+	* ext/mikmod/mikmod_types.c:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audiopanorama.c:
+	* gst/effectv/gstradioac.c:
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/gstqtmuxmap.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/videofilter/gstvideotemplate.c:
+	* gst/wavparse/gstwavparse.c:
+	  Constify some static arrays everywhere
+
+2015-01-19 17:49:54 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix deadlock seeking in files without seek entries
+	  A mutex unlock was missing.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739975
+
+2015-01-19 12:34:25 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/videomixer/blend.c:
+	  videomixer: fix illegal memory access in blend function with negative ypos
+	  https://bugzilla.gnome.org/show_bug.cgi?id=741115
+
+2015-01-13 16:49:34 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Proxy getcaps
+	  Replace the sink_query with new getcaps() virtual and use the proxy
+	  helper with the probed caps. This allow upstream element taking decision
+	  base on what is supported downstream.
+
+2015-01-13 19:05:20 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmuxmap.c:
+	  qtmux: Add support for v210
+
+2015-01-13 18:58:01 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: v210 is v210, not UYVY and yuv2 is YUY2, not I420
+	  Also add a few other raw video formats we support: v308, v216
+	  and add comments for a few others we don't support yet.
+	  https://developer.apple.com/library/mac/technotes/tn2162/
+
+2015-01-12 15:56:29 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From f2c6b95 to bc76a8b
+
+2015-01-10 15:51:16 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* sys/osxvideo/cocoawindow.h:
+	* sys/osxvideo/cocoawindow.m:
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: Disable hack for NSApp iteration with a special #define
+	  The hack causes deadlocks and other interesting problems and it really
+	  can only be fixed properly inside GLib. We will include a patch for
+	  GLib in our builds for now that handles this, and hopefully at some
+	  point GLib will also merge a proper solution.
+	  A proper solution would first require to refactor the polling in
+	  GMainContext to only provide a single fd, e.g. via epoll/kqueue
+	  or a thread like the one added by our patch. Then this single
+	  fd could be retrieved from the GMainContext and directly integrated
+	  into a NSRunLoop.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=741450
+	  https://bugzilla.gnome.org/show_bug.cgi?id=704374
+
+2015-01-08 21:07:05 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: uncork if needed upon commit
+	  ... to provide for a running clock.
+
+2015-01-09 16:59:53 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Prevent renegotiation
+	  Renegotiation isn't supported, simply prevent it the way we do in
+	  v4l2src.
+
+2015-01-06 13:54:25 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Don't unlock the stream lock twice
+
+2015-01-09 11:40:40 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix stream time conversion
+	  Use the right macro to convert to the correct scale or the
+	  segment information will be wrong
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742572
+
+2015-01-07 18:48:58 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Add protection against driver bug
+	  v4l2loopback driver has a this nasty bug that if the queue is larger
+	  then 2 buffers, it returns random index on dqbuf. So far we assumed
+	  that the index was always right, which would lead to memory being
+	  unref twice, and eventually crash.
+
+2015-01-07 17:58:05 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2allocator.h:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: Don't use allocator size to iterate
+	  As the buffer array is fixed size and small, it's safer to simply
+	  use this static size to cleanup the buffers. This is also more
+	  consistent with the rest. The associated method is no longer
+	  required and can be dropped.
+
+2015-01-07 17:55:14 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Don't clean buffer array in dispose
+	  This should already have been done, plus this code is incorrect
+	  and may lead to crash.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742074
+
+2015-01-07 17:48:31 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Don't ref queued output buffer
+	  This partly revert to the old 1.2 behavior. Instead of keeping a
+	  reference to the output buffer queued, we simply release them but
+	  don't forward it to GstBufferPool. This way, the buffer pool don't
+	  need to be flushed to be stopped.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742074
+
+2015-01-08 11:37:23 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Never fail on streamoff
+	  Failing streamoff prevents allocator from being disposed hence
+	  lead to device FD leak. There is no known cases where streamoff
+	  may fails for which we'd still be streaming. streamoff is known
+	  to fail when a device is being unplugged (in which case errno
+	  19/ENODEV is set).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=732734
+
+2015-01-07 21:52:17 -0500  Brad Smith <brad@comstyle.com>
+
+	* configure.ac:
+	  v4l2: Add support for detecting the presence of V4L2 support on OpenBSD
+	  https://bugzilla.gnome.org/review?bug=742503
+
+2015-01-04 15:57:10 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: request at least 8 bytes to properly parse header
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742325
+
+2015-01-07 16:20:03 -0800  Michael Smith <michael.smith@rdio.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: skip an additional uninteresting chunk type before the fmt chunk.
+
+2015-01-07 18:16:12 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/audiofx/audiodynamic.c:
+	  audiodynamic: assert func_index is inside bounds
+	  Bringing back the check removed in the previous commit but have that check be a
+	  g_assert. Changing the function to static void since return can never be False,
+	  because audio format will never be unkown.
+
+2015-01-07 17:31:39 +0000  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/audiofx/audiodynamic.c:
+	  audiodynamic: remove always-true conditional
+	  func_index is set by the sum of three ternary operators which add, 0:4, 0:2,
+	  and 1:0. Minimum value would be 0+0+0=0, and maximum would be 4+2+1=7.
+	  The conditional checking if func_index is >= 0 and < 8 will always be true.
+	  Removing it.
+	  CID 1226442
+
+2015-01-07 18:05:18 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: If we get a gap with a buffer without DTS, error out
+	  We (currently?) can't really handle gaps between RTP packets if they're not
+	  properly timestamped. The current code would go into calculations with
+	  GST_CLOCK_TIME_NONE and then cause assertions everywhere. It's probably
+	  better to error out cleanly instead.
+
+2014-11-21 11:39:19 -0800  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: set PLAYING state after configuring caps
+	  We set to PLAYING after we have configured the caps, otherwise we
+	  might end up calling request_key (with SRTP) while caps are still
+	  being configured, ending in a crash.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740505
+
+2014-12-30 18:03:22 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/icles/gdkpixbufoverlay-test.c:
+	  tests: gdkpixbufoverlay-test: remove outdated FIXME
+
+2014-12-30 17:19:42 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/rtpcollision.c:
+	  tests: rtpcollision: use alawenc/dec in these tests instead of Speex
+	  They should always be built, while the speex elements are not.
+	  Need to check for a smaller number of buffers then (7->4) because
+	  speexenc will add 3 header buffers while alawenc will just output
+	  as many buffers as it receives as input.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742098
+
+2014-12-30 16:36:02 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/pipelines/simple-launch-lines.c:
+	  tests: simple-launch-lines: only run jpeg/png tests if elements are available
+
+2014-12-30 16:26:58 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Don't return a buffer when returning not GST_FLOW_OK
+	  basesrc assumes that we don't return a buffer if
+	  something else than OK is returned. It will just
+	  leak any buffer we might accidentially provide
+	  here.
+	  This can potentially happen during flushing.
+	  Maybe fixes https://bugzilla.gnome.org/show_bug.cgi?id=741993
+
+2014-12-30 14:52:42 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/rtpaux.c:
+	  tests: rtpaux: use alawenc/dec in these tests instead of Speex
+	  They should always be built, while the speex elements are not.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=742098
+
+2014-12-29 15:35:19 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Improve detection of being stuck at the same offset
+	  Only error out if we read from the same position again and got the
+	  same length. Just the same position is not necessarily enough.
+
+2014-12-29 15:00:02 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Don't get stuck at the same offset when searching for clusters
+	  This could happen if there is an invalid cluster with size 0, and in that
+	  case just error out instead of looping forever.
+
+2014-12-25 21:32:40 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: fix ALAC muxing
+	  Actually copy the codec data instead of copying nothing
+	  and then bombing out because there's no data.
+	  Fixes: gst-launch-1.0 audiotestsrc ! avenc_alac ! qtmux ! fakesink
+	  https://bugzilla.gnome.org/show_bug.cgi?id=741783
+
+2014-12-25 15:48:04 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtpmanager/gstrtpptdemux.c:
+	  rtpptdemux: just drop invalid rtp packets instead of erroring out
+	  Apparently linphone sends an invalid RTP packet as very
+	  first packet. We want to ignore that instead of erroring
+	  out (same for any other invalid packets really).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=741398
+
+2014-12-25 15:44:15 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtpmanager/gstrtpptdemux.c:
+	  rtpptdemux: fix 0.10-ism in docs
+
+2014-12-25 14:58:12 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/icles/gdkpixbufoverlay-test.c:
+	  tests: gdkpixbufoverlay-test: use absolute positioning to fix demo
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739566
+
+2014-12-25 14:53:09 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.h:
+	  gdkpixbufoverlay: add "positioning-mode" property to allow absolute positions
+	  Set positioning-mode=pixels-absolute to allow positioning with
+	  absolute coordinates, meaning negative x/y offsets will be
+	  interpreted as being to the left/above the video frame instead
+	  of being interpreted as relative to the right/bottom edge of
+	  the video frame (which is a silly default, but that's how it is).
+	  This means we can nicely slide images into and out of the frame,
+	  see gdkpixbufoverlay-test.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739566
+
+2014-12-22 15:33:51 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	  osxaudio: Directly return the ringbuffer's caps if it is acquired
+
+2014-12-22 12:56:19 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	  osxaudio: Put all audio formats into the template caps
+	  We report the proper caps later from the get_caps() vfunc implementation after
+	  probing the selected device.
+
+2014-12-22 12:56:05 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* sys/osxaudio/gstosxaudioringbuffer.c:
+	  osxaudio: Also set the big endian flag for floating point samples
+
+2014-12-22 11:45:59 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* MAINTAINERS:
+	  MAINTAINERS: Update my mail address
+
+2014-12-22 10:23:01 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	  osxaudio: Fix deadlock and property change notification in device selection code
+	  After creating the ringbuffer we have to set the device on the ringbuffer as
+	  it defaults to kAudioDeviceUnknown. At this point it can't have changed to
+	  anything else yet and we don't have to notify about changes to the sink/src
+	  "device" property. It's also not a good idea because GstAudioBaseSrc has the
+	  object lock taken while the ringbuffer is created, which might cause a
+	  deadlock if something calls back into the element from "notify::device".
+	  Once the base class is done with the NULL_TO_READY state change, it has opened
+	  the device via the ringbuffer and this might have chosen a different device.
+	  Especially if we initially used kAudioDeviceUnknown. Also notify about this
+	  property change as initially intended by this code.
+
+2014-12-19 12:30:03 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2pool: Update configuration size
+	  We already update our copy of VideoInfo.size to proper size, now also
+	  the configuration so the size matches on release.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=741420
+
+2014-12-19 10:57:29 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroska-demux: Cache upstream length
+	  Instead of constantly querying upstream, just cache the last duration,
+	  and in the unlikelyness we might have gone over query again before
+	  deciding we are EOS.
+	  Cut 15% cpu off matroskademux streaming thread (srsly...)
+
+2014-12-17 17:36:18 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.c:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.c:
+	  matroska: mux/demux the OpusHead header
+	  This is meant to be so (https://wiki.xiph.org/MatroskaOpus - while
+	  it is marked as a draft, this part was confirmed to be correct on
+	  IRC), and allows one to determine whether a demuxed stream is
+	  multistream or not, and thus set the multistream caps field
+	  accordingly. In turn, this means downstream does not have to guess.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740744
+
+2014-12-18 11:50:33 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Don't dereference NULL if a suitable stream for the AUX element can't be found
+	  CID 1258717
+
+2014-12-18 10:53:39 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From ef1ffdc to f2c6b95
+
+2014-12-12 23:06:07 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	  udpsink: allocate scratch space for render functions on the heap
+	  and not the stack. Our allocations could get a bit too large
+	  to be sure it's not going to cause trouble using the stack.
+
+2014-06-24 01:16:37 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: re-use send_buffers() code path for render() function
+	  It's like rendering a buffer list, just with one buffer.
+	  Has the added advantage that if there are multiple clients
+	  we can send the buffer to all the clients in one go.
+
+2014-06-24 01:15:25 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	  multiudpsink: keep client list consistent during removals
+	  We unlock and re-lock the client lock while emitting the
+	  removed signal, which causes inconsistencies in the client
+	  list vs. the client counts. Instead, remove the client from
+	  the list already before emitting the signal and put it into
+	  a temporary list of clients to be removed. That way things
+	  look consistent to the streaming thread, but signal callbacks
+	  can still do things like get stats from removed clients.
+
+2014-06-24 00:56:27 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: fix client count after removal
+
+2014-06-23 18:43:21 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: keep client list sorted by socket family
+	  We make use of in the send_buffers() function if we
+	  need to use different sockets to send to IPv4 and
+	  IPv6 destinations.
+
+2014-06-20 11:36:19 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	  multiudpsink: add sendmmsg-ready render_list function prototype
+	  Add prototype for a render_list() function that can use a
+	  sendmmsg-style g_socket_send_messages() function once it lands
+	  in GLib. We can use this infrastructure to send multiple buffers
+	  made up by multiple memories to multiple clients in one go, which
+	  drastically reduces the number of syscalls made when sending
+	  high-bitrate video streams.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=732152
+
+2014-06-19 19:16:01 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	  multiudpsink: make udp client structure refcounted
+	  Use the refcount for memory management and keep track
+	  of the number of duplicate clients in a separate
+	  variable. This will be useful later, and means we
+	  don't have to hold the OBJECT_LOCK all the time.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=732866
+
+2014-06-19 18:31:05 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	  multiudpsink: keep count of number of unique and non-unique IPv4 and IPv6 clients
+	  This will come in handy later.
+
+2014-12-16 15:00:22 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Disable create_buf with libv4l2
+	  Libv4l2 does not work with CREATE_BUFS. Instead of failing on random
+	  error caused by libv4l2, disable CREATE_BUFS when an emulated format is
+	  detected.
+
+2014-12-09 17:39:12 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Add protection against broken libv4l2
+	  It looks like libv4l2 support for CREATE_BUF is incomplete. That
+	  combine with existing bugs may lead to crash in GStreamer. These
+	  check will make it robust by:
+	  - Checking create buf index isn't an already in used index
+	  - Checking that the index out of QUERYBUF matches the requested
+	  index
+
+2014-12-16 16:37:24 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Add something to the debug logs if an RTX AUX element can't be added
+	  ... because the application already has a signal handler set up here.
+
+2014-11-21 14:13:34 +1100  Matthew Waters <matthew@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: add retransmission support according to RFC4588
+	  Based on the client-rtpaux example
+
+2014-12-16 13:25:01 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: clear rectangle structures before use
+
+2014-12-09 15:09:56 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Always set format
+	  Right now we try to be clever by detecting if device format have
+	  changed or not, and skip setting format in this case. This is valid
+	  behaviour with V4L2, but it's also very error prone. The rational
+	  for not setting these all the time is for speed, though I can't
+	  measure any noticeable gain on any HW I own. Also, until recently,
+	  we where doing get/set on the format for each format we where
+	  probing, making it near to impossible that the format would match.
+	  This also fixes bug where we where skipping frame-rate setting if
+	  format didn't change.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740636
+
+2014-12-15 18:30:01 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/videocrop/gstvideocrop.c:
+	  videocrop: Remove todo about caps filter
+	  The filter is already interected.
+
+2014-12-15 18:19:05 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videocrop/gstvideocrop.h:
+	  videocrop: Make sure new crop is applied
+	  Since "basetransform: Fix caps equality check" commit a7f357,
+	  set_info() will not be called anymore if crop didn't change
+	  the caps. This is fixed by setting "need_update" boolean when
+	  cropping properties has been changed, and then applying these
+	  if they where not applied before rendering the next frame. This
+	  patch also fixed the locking, dropping un-needed custom lock,
+	  and no holding needless lock while doing the operation as we
+	  already hold the streaming lock.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740787
+
+2014-12-12 18:10:35 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	  osxaudiosink: Prefer filter caps order while getting caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740987
+
+2014-12-09 13:38:26 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	  osxaudiosink: Add some error handling around channel layout parsing
+	  For now we just spit a warning and ignore the channel layout if we can't
+	  support it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740987
+
+2014-12-08 22:38:22 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	  osxaudio: Take lock around sink/source before accessing the ringbuffer
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740987
+
+2014-12-01 21:06:27 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosink.h:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxaudio/gstosxcoreaudio.c:
+	* sys/osxaudio/gstosxcoreaudio.h:
+	* sys/osxaudio/gstosxcoreaudioremoteio.c:
+	  osxaudiosrc: Probe channel layout too
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740987
+
+2014-12-01 20:32:04 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	  osxaudiosink: Only fix up channels/layout for PCM caps while probing
+	  It's unlikely that setting a channel layout will do much for AC3/DTS
+	  streams. If we find at some point that it does make sense, we can
+	  perform the structure copying unconditionally (i.e., the current code is
+	  wrong, since AC3/DTS will get two structures now - one with the channel
+	  layout, one without).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740987
+
+2014-12-01 19:41:35 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxaudio/gstosxaudiosrc.h:
+	* sys/osxaudio/gstosxcoreaudio.c:
+	* sys/osxaudio/gstosxcoreaudio.h:
+	  osxaudiosrc: Implement caps probing
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740987
+
+2014-12-01 19:29:57 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* sys/osxaudio/gstosxcoreaudiohal.c:
+	  osxaudio: Bind audio device to audio unit early
+	  We want to bind the device during open so that subsequent format queries
+	  on the audio unit are as specific as possible from that point onwards.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740987
+
+2014-11-29 23:16:30 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	  osxaudiosink: Fix up caps querying a bit
+	  This should make caps queries correct in PAUSED and higher as well.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740987
+
+2014-11-28 22:32:36 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxaudio/gstosxcoreaudio.c:
+	  osxaudio: Move osxaudiosrc-specific code out of the generic path
+	  Avoids one layering violation (GstCoreAudio referring to
+	  GstOsxAudioSrc).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740987
+
+2014-11-28 22:23:17 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* sys/osxaudio/gstosxaudioringbuffer.c:
+	* sys/osxaudio/gstosxaudioringbuffer.h:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxaudio/gstosxcoreaudio.c:
+	* sys/osxaudio/gstosxcoreaudio.h:
+	* sys/osxaudio/gstosxcoreaudiohal.c:
+	* sys/osxaudio/gstosxcoreaudioremoteio.c:
+	  osxaudio: Clean up a GstCoreAudio -> GstOsxAudioSrc/Sink reference
+	  Now that device selection has no sink/source-specific bits, we can have
+	  generic device selection for this path. We do need to now track state
+	  changes so we can look up the final device_id once the device is open,
+	  though.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740987
+
+2014-11-28 19:40:52 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	  osxaudiosink: Move device caps probing to get_caps()
+	  This should be preferred to running the probe at device open time.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740987
+
+2014-11-28 18:37:02 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* sys/osxaudio/gstosxcoreaudiohal.c:
+	  osxaudio: Make some debug code compile conditionally
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740987
+
+2014-11-28 15:06:35 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* sys/osxaudio/gstosxaudioringbuffer.c:
+	* sys/osxaudio/gstosxaudioringbuffer.h:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	  osxaudio: Move device selection to ringbuffer->open_device()
+	  This is conceptually the right thing to do, and allows us to correctly
+	  catch errors in device selection as well, which we could not do while
+	  creating the ringbuffer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740987
+
+2014-11-28 14:34:34 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxaudio/gstosxcoreaudio.c:
+	* sys/osxaudio/gstosxcoreaudio.h:
+	* sys/osxaudio/gstosxcoreaudiohal.c:
+	* sys/osxaudio/gstosxcoreaudioremoteio.c:
+	  osxaudio: Consolidate input and output code paths a bit
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740987
+
+2014-11-21 11:54:18 +0100  Thibault Saunier <tsaunier@gnome.org>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  Deinterlace: in query_caps return only supported formats if filter is interlaced
+	  In some cases the currently set GstVideoInfo is not interlaced, but
+	  upstream caps are interlaced and the info is passed in the filter,
+	  we should take that info into account and make sure that we do not
+	  consider that case as a "pass through" case.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=741407
+
+2014-12-12 11:06:17 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix debug statement
+	  It was using the non-increasing offset variable, which made that statement
+	  not so useful :)
+
+2014-12-12 11:03:15 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Add macros for the various timescale conversions
+	  This helps make the code more readable and avoid future bad usage of
+	  scaling function argument order.
+
+2014-12-11 10:16:06 +0100  Patrick Radizi <patrickr@axis.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: fix potential crash when shutting down
+	  A race condition in the state change function may cause buffers
+	  to be unreffed while they are still used by the streaming thread
+	  in gst_rtp_h264_pay_send_sps_pps() resulting in a crash. Chain
+	  up to the parent class first in the state change function to
+	  make sure streaming has stopped and only then free those buffers.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=741381
+
+2014-12-12 00:42:06 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Copy flags of the overall segment to output segments
+	  Preserve the segment flags of the overall demux segment on the output
+	  segments for each pad.
+
+2014-12-09 02:43:00 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: use 64bit chunk_offset
+	  https://bugzilla.gnome.org/show_bug.cgi?id=741279
+
+2014-12-10 17:39:17 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix rounding errors in duration update
+	  Make sure we store updated segment stop/duration with the same
+	  granularity as the duration timescale.
+	  And add more debug
+
+2014-12-10 16:55:44 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Update duration when we get more information
+	  When dealing with fragmented files, we will get more accurate duration
+	  information via the mfra and moof atoms.
+	  In order for playback to not stop at the initial duration (from the
+	  moov atom), we need to check and update the various duration variables
+	  when we find more information.
+	  Fixes playback of fragmented files in pull mode
+
+2014-12-10 15:08:40 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Remove variable assignments never read
+	  As detected by clang/scan-build
+
+2014-12-10 14:56:06 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: Use GstClockTime for nanosecond-based time variables/fields
+	  Avoids confusion with timescaled-based variables and bytes (offset)
+	  variables.
+	  And use GST_CLOCK_TIME_NONE where applicable
+
+2014-12-03 14:47:05 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/debugutils/gstpushfilesrc.h:
+	  pushfilesrc: Add TIME SEGMENT capability
+	  Adds a new set of properties to make pushfilesrc output a TIME SEGMENT
+	  (instead of the filesrc BYTE SEGMENT).
+	  When time-segment is set to True the following will happen:
+	  * Seeks are refused (data starts from the beginning of the file)
+	  * The BYTE segment will be replaced by a TIME segment with the values
+	  specified in the various properties
+	  * The first outgoing buffer will have a timestamp set on it (by default
+	  it has a value of GST_CLOCK_TIME_NONE)
+
+2014-12-10 11:35:29 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Also only unref caps if they're not NULL
+
+2014-12-10 11:34:42 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: gst_pad_get_allowed_caps() will return NULL if there is no peer
+
+2014-12-09 16:38:38 +0100  Thibault Saunier <tsaunier@gnome.org>
+
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp9enc.c:
+	  vpXenc: CLOCK_TIME_NONE is not a valid min_latency value
+	  We should just use 0 if we do not have the information
+
+2014-12-03 17:26:56 +0100  Thibault Saunier <tsaunier@gnome.org>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: Use an empty iterator in iterate_internal_link when no links
+	  And not a NULL Iterator, so it is consistent with the way it usually
+	  works and avoid user to need a different code paths to handle that.
+
+2014-12-09 14:01:50 +0100  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: set buffer interlace flags when field is V4L2_FIELD_INTERLACED
+	  If v4l2_buffer.field is V4L2_FIELD_INTERLACED, we set corresponding
+	  GstVideoBuffer flags depending on the video standard.
+	  According to V4L2 specification, M/NTSC transmits the bottom field
+	  first, all other standards the top field first.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737603
+
+2014-12-08 21:26:18 +0100  Patrick Radizi <patrickr@axis.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: Fixes buffer leak when using SPS/PPS
+	  Fixes a buffer leak that would occurr if the pipeline was shutdown
+	  while a SPS/PPS header was being created.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=741271
+
+2014-12-09 04:43:29 +0100  Mathieu Duponchelle <mathieu.duponchelle@opencreed.com>
+
+	* gst/effectv/gstaging.c:
+	  agingtv: fix memcpy when no color aging requested.
+	  video_size is the size in pixels, actual size of the memcpy
+	  has to be stride * height.
+
+2014-12-07 17:33:51 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: Workaround libv4l2 RW emulation bug
+	  When libv4l2 emulates RW mode on top of MMAP devices, the queues are
+	  only initialized on first read. The problem is that poll() will fail
+	  if called before the queues are initialized and streaming. Workaround
+	  this by doing a zero size read when pool is started in that IO mode.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740633
+
+2014-12-07 17:27:37 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: Fix RW io mode
+	  In RW, allocator can be null, max_buffers can be zero, and we need not
+	  to wait while the queue is empty since there is no queue.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740633
+
+2014-12-03 16:40:49 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Cleanup uneeded check and cases
+	  There is nothing in between the break and the "done:" anymore, plus
+	  USERPTR and DMABUF_IMPORT case is exactly the same.
+
+2014-12-03 17:07:49 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2pool: Fix CREATE_BUFS support for capture
+	  This patch fixes CREATE_BUFS support for capture devices. Initially we
+	  would only try and allocate more buffers when the copy threshold
+	  is reached. When the threshold was not set (needed) it would never
+	  happen. Another problem is that on capture side, acquire returns
+	  filled buffer, hence need to pool. We need to set a special flag to
+	  force allocation to happen.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=741134
+
+2014-12-03 16:27:59 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Fix CREATE_BUF probing
+	  Current for every memory type we where probing MMAP CREATE_BUFS ioct.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=741134
+
+2014-11-18 16:52:40 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: set framerate 0/1 when duration is not known
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740130
+
+2014-12-04 17:25:55 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: More fixes for reverse playback
+	  When seeking or finding the previous keyframe, do
+	  comparisons against targets and segments using composition time
+	  to correctly decide which sample times match.
+
+2014-12-03 11:12:55 +0100  Thibault Saunier <tsaunier@gnome.org>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Use an empty iterator in iterate_internal_link when no links
+	  We used to setup an iterator with 1 GValue set with a NULL object
+	  pointer which is not the normal way to do that. Instead we should make
+	  sure that the first call to gst_iterator_next returns GST_ITERATOR_DONE.
+
+2014-12-03 13:20:57 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Handle seeks past EOS as a seek to the end
+	  Fix reverse playback of every frame by making seeks past/to EOS
+	  find the last segment and start there.
+
+2014-12-02 15:33:25 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpmpadepay.c:
+	  rtpmpadepay: Relax caps to allow any clock-rate
+	  Some Wowza setups seem to send an invalid non-90000 clock-rate.
+
+2014-12-01 21:04:02 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: don't use GST_CLOCK_TIME_NONE in non GstClockTime variables
+	  Use -1 instead as those are gint64/guint64 variables and not GstClockTime
+
+2014-11-07 17:06:49 +0100  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2allocator.h:
+	  v4l2allocator: fix gst_v4l2_allocator_stop prototype
+	  gst_v4l2_allocator_stop returns a GstV4l2Return, not a gboolean.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739792
+
+2014-11-07 16:41:52 +0100  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: unref pool when v4l2_allocator_new() fails
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739791
+
+2014-11-30 17:52:47 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/v4l2_calls.h:
+	  v4l2: Remove last include to linux/videodev2.h
+	  We now use and update our internal copy so we no longer have to ifdef
+	  the entire code for features and defines that where added over the
+	  years.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740905
+
+2014-08-24 13:38:08 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: implement seeking in fragmented mp4 files in pull mode based on the mfra table
+
+2014-11-29 15:25:51 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: use track fragment decoding time (tfdt) in parse_trun() for interpolation
+	  As fallback if we don't have any existing samples
+	  as reference point yet.
+	  Based on patch by David Corvoysier <david.corvoysier@orange.com>
+
+2014-11-29 14:37:25 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: parse mfra random access box for fragmented mp4 files
+	  If it's present, and we operate in pull mode.
+
+2014-08-15 14:58:26 +0200  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: stop parsing headers for fragmented mp4s at the first moof
+	  Currently during header parsing, we scan through the entire file
+	  and skip every moof+mdat chunk for fragmented mp4s, which makes
+	  start-up incredibly slow. Instead, just stop at the first moof
+	  chunk when have a moov, and start exposing the streams, so we
+	  can go and start handling the moofs for real.
+
+2014-11-29 13:59:35 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/icles/.gitignore:
+	* tests/icles/Makefile.am:
+	* tests/icles/gdkpixbufoverlay-test.c:
+	  tests: add interactive gdkpixbufoverlay test
+	  Just need to fix the coordinate system now so
+	  that negative offsets are actually negative
+	  and not flipped to position things from the
+	  opposite border.
+
+2014-11-29 13:53:03 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.h:
+	  gdkpixbufoverlay: add "pixbuf" property
+	  So we can set a GdkPixbuf directly instead of
+	  reading it from an image file on the file system.
+
+2014-11-29 13:23:50 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/gdk_pixbuf/Makefile.am:
+	* ext/gdk_pixbuf/pixbufscale.c:
+	* ext/gdk_pixbuf/pixbufscale.h:
+	  gdkpixbuf: remove pixbufscale code that was never ported
+	  Don't think we'll need this again.
+
+2014-11-29 18:35:42 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	  rtprtxreceive: Use offset when copying header
+	  The header is not always at the start of the packet, so we need to compute
+	  the offset first.
+
+2014-11-28 13:12:46 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/taglib/gstapev2mux.cc:
+	  apev2mux: write APE tags at end for wavpack files
+	  http://www.wavpack.com/file_format.txt:
+	  "Both the APEv2 tags and/or ID3v1 tags must come at the end of the
+	  WavPack file, with the ID3v1 coming last if both are present."
+	  WavPack files that contain APEv2 tags at the beginning of the files
+	  are unplayable on players that use FFmpeg (like VLC) and most other
+	  software (except Banshee). Players that use libwavpack directly can
+	  play the files because it skips the tags, but does not recognize the
+	  tag data at that location.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=711437
+
+2014-11-28 10:41:55 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/icles/.gitignore:
+	* tests/icles/Makefile.am:
+	* tests/icles/test-segment-seeks.c:
+	  tests: add interactive test for gapless playback using SEGMENT seeks
+	  Not working too well yet, there are glitches even with WAV or FLAC.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=692368
+
+2014-11-26 10:33:09 +0300  Andrei Sarakeev <sarakusha@gmail.com>
+
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videocrop/gstaspectratiocrop.h:
+	  aspectratiocrop: Handle resolution changes properly
+	  When an caps-event is received, we must immediately change the crop
+	  to videocrop correctly changed caps-event dimension, otherwise the
+	  videocrop will first use the previous value of the crop that when
+	  resizing video to a smaller resolution may cause an error.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740671
+
+2014-11-27 17:10:53 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From 7bb2bce to ef1ffdc
+
+2014-11-27 11:20:36 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/icles/test-accurate-seek.c:
+	  test: use gst_util_uint64_scale_round() for timestamp to sample calculation
+
+2014-11-27 11:16:35 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/icles/.gitignore:
+	* tests/icles/Makefile.am:
+	* tests/icles/test-accurate-seek.c:
+	  tests: add interactive test for accurate seeking
+	  For some audio formats.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=655276
+
+2014-11-26 16:04:26 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux.c:
+	  isomp4: Check presence of mfhd in moof
+	  The 'mfhd' atom is mandatory in 'moof'. We can later on check whether
+	  the fragment number properly increases
+
+2014-11-26 15:59:36 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux_dump.c:
+	  isomp4: Fix mfro and tfra atom dumping
+	  mfro was skipping the version/flags
+	  tfra had wrong byte_reader return value checks
+
+2014-11-26 15:58:26 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux_dump.c:
+	* gst/isomp4/qtdemux_dump.h:
+	* gst/isomp4/qtdemux_types.c:
+	  isomp4: Add mfhd atom dumping
+
+2014-11-27 00:15:02 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Handle empty segments when seeking in reverse play.
+	  Empty segments in an edit list have a media_start time of -1,
+	  as they don't actually play any media. Allow for that when
+	  aligning to the reference stream in reverse play.
+
+2014-11-24 10:36:54 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  Revert "v4l2allocator: Remove unused variable"
+	  This reverts commit ad4480d53408a4d97ab531174ef37f258f3253c0.
+
+2014-11-24 10:36:30 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2allocator.h:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  Revert "v4l2: move vb_queue probing from allocator to v4l2object"
+	  This reverts commit ec6b8b84af719d828ddd91c724e715c0b4a556bc.
+
+2014-11-24 10:33:29 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	  Revert "v4l2object: allow to automatic selection of dmabuf"
+	  This reverts commit e6c2ad5571e5dedb212287efe238eb450032cd4f.
+
+2014-11-23 16:34:15 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* REQUIREMENTS:
+	  REQUIREMENTS: update a little
+	  People actually look at that it seems.
+
+2014-11-23 16:22:12 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/icydemux/Makefile.am:
+	  icydemux: does not need to link against zlib
+
+2014-11-22 21:28:35 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* configure.ac:
+	* ext/speex/gstspeexdec.h:
+	* ext/speex/gstspeexenc.h:
+	  speex: remove support for ancient speex versions
+
+2014-11-21 11:21:18 +0100  Branislav Katreniak <bkatreniak@nuvotechnologies.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: log connection events at info level
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739305
+
+2014-10-20 13:00:37 +0200  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: ensure rtx_retry_period >= 0
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739344
+
+2014-11-21 11:44:24 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Remove unused variable
+	  this was introduced by commit ec6b8b
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699382
+
+2014-11-16 12:34:17 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2transform.c:
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2: Handle corrupted buffer with empty payload
+	  This allow skipping buffer flagged with ERROR that has no payload.
+	  This is typical behaviour when a recovererable error occured during
+	  capture in the driver, but that no valid data was ever written into that
+	  buffer. This patch also translate V4L2_BUF_FLAG_ERROR into
+	  GST_BUFFER_FLAG_CORRUPTED. Hence decoding error produce
+	  by decoder due to missing frames will now be correctly marked. Finally,
+	  this fixes a buffer leak when EOS is reached.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740040
+
+2014-11-21 16:36:15 +0100  Benjamin Gaignard <benjamin.gaignard@linaro.org>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: allow to automatic selection of dmabuf
+	  If the v4l2 queue support dmabuf select this buffer pool mode
+	  and update the query with allocator.
+	  This patch only concern exporting dmabuf and not importing dmabuf
+	  fd from downstream element.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699382
+
+2014-11-21 16:13:05 +0100  Benjamin Gaignard <benjamin.gaignard@linaro.org>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2allocator.h:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2: move vb_queue probing from allocator to v4l2object
+	  The goal is to make those information available in v4l2_object
+	  to be able later to select the best allocation method for the pool
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699382
+
+2014-11-20 22:42:59 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: Fix up new_jitterbuffer signal prototype
+
+2014-11-20 20:19:25 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Document how to control per-SSRC retransmission
+
+2014-11-20 20:18:45 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* docs/design/design-rtpretransmission.txt:
+	  doc: Trivial spelling and consistency update
+
+2014-11-20 13:14:14 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: put 0-byte at the end of events
+	  Put a 0-byte at the end of the event string. Does not break ABI because
+	  old depayloaders will skip the 0 byte (which is included in the length).
+	  Expect a 0-byte at the end of the event string or a ; for old
+	  payloaders.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=737591
+
+2014-11-20 12:40:28 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	  rtpgstdepay: avoid buffer overread.
+	  Check that a caps event string is 0 terminated and the event string is
+	  terminated with a ; to avoid buffer overreads.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=737591
+
+2014-11-20 10:45:07 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/gstqtmuxmap.c:
+	  qtmux: don't limit max video resolution to 4096x4096
+	  MAX isn't entirely correct as upper limit either,
+	  it should really be MAXUINT32, but it's unlikely
+	  to be a problem in the near future.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740407
+
+2014-11-19 15:06:00 -0800  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix leak for mikey base64 decoded key-mgmt
+	  https://bugzilla.gnome.org/show_bug.cgi?id=740392
+
+2014-11-20 09:01:38 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: fix unhandled format in passthrough
+	  In passthrough we can handle all formats.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=740387
+
+2014-11-19 16:12:38 +0100  Jan Alexander Steffens (heftig) <jsteffens@make.tv>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Restrict resyncing to TS regressions
+	  The behavior of resyncing video and audio indepen-
+	  dently can cause A/V desyncs. Lets restrict resyncs
+	  to jumps backward for now.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736397
+
+2014-11-17 23:16:03 +1100  Matthew Waters <matthew@centricular.com>
+
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	  videomixer: fix up QoS handling for live sources
+	  Only attempt adaptive drop when we are not live
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739996
+
+2014-11-10 22:34:39 +0100  Henning Heinold <henning@itconsulting-heinold.de>
+
+	* tests/examples/rtp/client-PCMA.py:
+	* tests/examples/rtp/server-alsasrc-PCMA.py:
+	  examples: port python rtp PCMA client/server tests to 1.0
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739930
+
+2014-06-04 12:11:10 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: set the channel positions using the appropriate API
+	  This avoids _set_format setting the unpositioned flag when passed
+	  NULL as channel positions, as it would not be cleared when setting
+	  actual channel positions later.
+
+2014-11-01 22:39:41 +0100  Aurélien Zanelli <aurelien.zanelli@darkosphere.fr>
+
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp9enc.c:
+	  vpx: mark arnr-type properties as deprecated and set them to no-op
+	  ARNR type control in libvpx has been deprecated so this commit mark the
+	  vp8enc and vp9enc associated properties as deprecated and change their
+	  behavior to just display a warning message.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739476
+
+2014-11-10 13:16:01 +0530  Arun Raghavan <git@arunraghavan.net>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpmanager: Trivial typo fix
+
+2014-11-09 11:04:33 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroska-mux: Use G_DEFINE_TYPE() to register the pad instead of manually registering it
+
+2014-11-06 15:37:28 +0100  Göran Jönsson <goranjn@axis.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: make GstMatroskamuxPad get_type() function thread-safe
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739722
+
+2014-11-07 16:11:24 +0100  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: fix error message if allocator is already active
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739789
+
+2014-11-06 21:21:40 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Improve buffer validation
+	  Improve buffer validation by making sure each memory are the right
+	  one and that each memory is writable. This fixes tearing issues in
+	  case downstream uses gst_buffer_make_writable() or other type
+	  of GstBuffer copy where memory are only reffed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739754
+
+2014-11-06 21:38:43 +0100  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/rtsp/Makefile.am:
+	  rtsp: fix build in gst-uninstalled setup
+
+2014-10-29 18:44:43 +0100  Thibault Saunier <tsaunier@gnome.org>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/imagefreeze/gstimagefreeze.h:
+	  imagefreeze: Handle seqnums
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739366
+
+2014-11-04 08:18:41 +0530  Vineeth T M <vineeth.tm@samsung.com>
+
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngdec.h:
+	  pngdec: change parse logic
+	  Right now in parse logic the signature is checked every time the parse function
+	  is called, and the whole data is the scanned each and every time, even though the
+	  data is scanned in the previous instance. Changing the logic such that, we skip
+	  the bytes which are already scanned in the previous instances of parse. This
+	  helps in avoiding multiple scan of already scanned data/signature.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737708
+
+2014-11-03 15:26:06 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer2: reverse order of params for converter
+
+2014-11-03 11:44:28 +0100  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: fix typo in flags
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739549
+
+2014-11-02 23:33:23 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2src: fix a couple of minor leaks
+
+2014-11-02 19:42:03 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/goom2k1/gstgoom.c:
+	* gst/goom2k1/gstgoom.h:
+	  goom2k1: post QoS messages when dropping frames due to QoS
+
+2014-11-02 19:29:52 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/goom/gstgoom.c:
+	* gst/goom/gstgoom.h:
+	  goom: post QoS messages when dropping frames due to QoS
+
+2014-11-02 19:02:35 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: tweak writing app tag string a little
+
+2014-11-02 16:51:23 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/level/gstlevel.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	  Sprinkle some G_PARAM_DEPRECATED and #ifndef GST_REMOVE_DEPRECATED
+
+2014-11-02 16:58:07 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/level.c:
+	  tests: don't use deprecated property in level unit test
+
+2014-11-02 13:06:33 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: implement get/set for new rtx-min-retry-timeout property
+	  Properties are so much more useful if you can actually set
+	  and get their values.
+
+2014-10-30 17:41:19 +0000  Simon Farnsworth <simon.farnsworth@onelan.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: Clean up interlace support
+	  Rather than try and guess interlace support as part of checking supported
+	  sizes, look for interlace support specifically in its own function.
+	  As a cleanup, use V4L2_FIELD_ANY when probing sizes, which should result in
+	  the driver doing the right thing.
+	  With my capture setup, this gets me the following sample caps:
+	  For 1080i resolution:
+	  video/x-raw, format=(string)YUY2, width=(int)1920, height=(int)1080, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)interleaved, framerate=(fraction){ 25/1, 30/1 }
+	  For 720p resolution:
+	  video/x-raw, format=(string)YUY2, width=(int)1280, height=(int)720, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction){ 50/1, 60/1 }
+	  For 576i/p resolution (both possible at the point of query):
+	  video/x-raw, format=(string)YUY2, width=(int)720, height=(int)576, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string){ progressive, interleaved }, framerate=(fraction){ 25/1, 50/1 }
+	  This, in turn, makes 576i work correctly; with the old code,
+	  the caps would be interlace-mode=progressive for interlaced video.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=726194
+
+2014-11-01 12:18:02 +0100  Aurélien Zanelli <aurelien.zanelli@darkosphere.fr>
+
+	* ext/vpx/gstvp8utils.h:
+	  vpx: remove compatibility defines
+	  We are guaranteed to have VPX_IMG_FMT_I420, VPX_PLANE_Y,
+	  VPX_PLANE_U and VPX_PLANE_V as we require libvpx > 1.1.0.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739476
+
+2014-11-01 15:33:23 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* configure.ac:
+	* ext/wavpack/gstwavpackcommon.c:
+	* ext/wavpack/gstwavpackdec.c:
+	* ext/wavpack/gstwavpackenc.c:
+	  wavpack: remove support for ancient API version
+
+2014-11-01 10:14:31 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/rtp/gstrtpvp8depay.c:
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8: Use VP8 encoding name
+	  Both Firefox and Chrome uses VP8 as the encoding in their SDP.
+	  Adding this now defacto standard name removes the need for special
+	  case in SDP parsing code.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737810
+
+2014-11-01 11:59:26 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpmp2tpay.c:
+	  rtpmp2tpay: fix up template caps so we can output the default pt 33
+	  Add fixed payload type for mp2t to template caps as well, so
+	  our output caps match the advertised default pt. Fixes a
+	  regression from 1.2.
+	  There's still something wrong with caps negotiation though,
+	  rtpmp2tpay payload=96 ! fakesink will not output caps with
+	  payload=96.
+
+2014-10-30 15:37:36 -0700  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: mikey related memory leaks
+	  https://bugzilla.gnome.org/show_bug.cgi?id=739430
+
+2014-06-10 10:04:07 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/speex/gstspeexenc.c:
+	* ext/speex/gstspeexenc.h:
+	  speexenc: update output segment stop time to match clipped samples
+	  This will let oggmux generate a granpos on the last page that properly
+	  represents the clipped samples at the end of the stream.
+
+2014-06-10 10:59:13 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflacenc.h:
+	  flacenc: update output segment stop time to match clipped samples
+	  This will let oggmux generate a granpos on the last page that properly
+	  represents the clipped samples at the end of the stream.
+
+2014-10-07 15:29:33 +0200  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: cleanly handle streamon failure for output device
+	  On streamon failure, the queued buffer is not released from the
+	  bufferpool class point of view because it is queued to the driver and
+	  the flush logic is not performed since we are not in streaming state.
+	  It causes the v4l2 bufferpool to always return that stop method failed
+	  and to leak v4l2 objects and buffers.
+	  This commit solve this by performing the flush logic in error case, ie
+	  flushing the allocator and restoring queued buffer state to non-queued.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=738102
+
+2014-10-08 10:31:21 +0200  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: implement dispose method
+	  Unref objects in dispose method rather than in finalize in order to
+	  prevent circular reference.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=738102
+
+2014-10-08 10:35:14 +0200  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: check that allocator is non null when stopping pool
+	  Otherwise, we could dereference NULL allocator when the stop method is
+	  called by the GstBufferPool's finalize method.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=738102
+
+2014-10-09 12:15:05 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: Implement unlock/unlock_stop
+	  This will prevent deadlocks, but will also properly flush the pool and allocator
+	  when going to READY state. It should also fix issues reported on mailing list
+	  when seeking is performed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=738152
+
+2014-10-28 21:32:06 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/pulse/pulsedeviceprovider.h:
+	* sys/v4l2/gstv4l2deviceprovider.h:
+	* sys/v4l2/gstv4l2tuner.h:
+	  pulse, v4l2: add missing G_END_DECLS in some places
+
+2014-10-27 17:57:20 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From 84d06cd to 7bb2bce
+
+2014-10-27 11:08:20 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/aacparse.c:
+	  aacparse: Fix unit test now that we always have profile/level in the caps
+
+2014-10-26 14:55:49 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* Makefile.am:
+	  Parallelise 'make check-valgrind'
+	  Some of the RTP unit tests are very flaky and will
+	  fail more often with the CPU maxed out fully. Those
+	  tests need to be fixed in any case though, they also
+	  fail on slower machines and also occasionally with
+	  normal 'make check'.
+
+2014-10-26 11:47:25 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Always set profile/level on the caps
+	  We have the information already, so why not use it?
+
+2014-10-25 12:36:02 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: fix crash on some 32-bit systems
+	  Make sure to pass right number of bits to gst_structure_new()
+	  which is a vararg function.
+	  Fixes elements/rtpaux unit test on ppc32.
+
+2014-10-25 00:56:02 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/rgvolume.c:
+	  tests: fix rgvolume test on big-endian systems
+
+2014-10-25 00:53:39 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/mulawdec.c:
+	* tests/check/elements/mulawenc.c:
+	  tests: fix mulawdec/mulawenc test for big endian systems
+
+2014-10-24 23:48:30 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/interleave/interleave.c:
+	  interleave: intersect result with filter caps in caps query
+	  Fixes crash in audiotestsrc because of an unsupported format
+	  getting negotiated on big-endian systems with
+	  audiotestsrc ! interleave ! audioconvert ! wavenc
+
+2014-10-23 15:46:13 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/pulse/pulsedeviceprovider.c:
+	* ext/pulse/pulsedeviceprovider.h:
+	  pulse: remove some unused typedefs
+
+2014-10-22 15:28:44 +0200  Ananda <ananda@latelier23.com>
+
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	  speex: Fix segfault when resetting the codecs multiple times
+	  https://bugzilla.gnome.org/show_bug.cgi?id=738793
+
+2014-10-22 22:50:54 +0530  Arun Raghavan <arun@accosted.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Temporarily disable stream status posting
+	  We need a mechanism in PulseAudio to allow running code outside the
+	  mainloop lock. Then we'd be able to post to the bus (taking the
+	  GST_OBJECT_LOCK), without worrying about locking order with the mainloop
+	  lock, which is the current cause of deadlocks while trying to post the
+	  stream status messages.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736071
+
+2014-10-22 15:04:24 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: limit the retry frequency
+	  When the RTT and jitter are very low (such as on a local network), the
+	  calculated retransmission timeout is very small. Set some sensible lower
+	  boundary to the timeout by adding a new property. We use the packet
+	  spacing as a lower boundary by default.
+
+2014-10-22 13:40:58 +0200  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  gstrtpjitterbuffer: add "rtx-min-delay" property
+	  This property is useful to set a min time to wait before sending a
+	  retransmission event.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=735378
+
+2014-10-22 13:29:48 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: Refactor code
+	  Refactor some code dealing with calculating various timeouts.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=735378
+
+2014-10-10 19:50:06 +0200  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: fix Early Feedback Transmission
+	  In early retransmission we are allowed to schedule 1 regular RTCP packet
+	  at an earlier time. When we do that, we need to set allow_early to FALSE
+	  and ignore/drop (or merge) all future requests for early transmission.
+	  We now first check if we can schedule an early RTCP and if we can,
+	  actually prepare the data for the next RTCP interval.
+	  After we send the next regular RTCP after the early RTCP, we set
+	  allow_early to TRUE again to allow more early requests.
+	  Remove the condition for the immediate feedback for now.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=738319
+
+2014-10-21 13:01:32 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From a8c8939 to 84d06cd
+
+2014-10-21 13:10:24 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: make debug line less confusing
+
+2014-10-21 12:58:13 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* README:
+	* common:
+	  Automatic update of common submodule
+	  From 36388a1 to a8c8939
+
+2014-07-02 17:50:35 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  jitterbuffer: rework resync handling
+	  Add a need-resync state, this is when we need to try to lock on to a
+	  time/RTPtime pair.
+	  Always check the RTP timestamps and if they go backwards, mark ourselves
+	  as need-resync.
+	  Only resync when need-resync is TRUE and we have a valid time. Otherwise
+	  we keep the old values. This avoids locking on to an invalid time and
+	  causing us to timestamp everything with -1.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=730417
+
+2014-10-03 17:28:06 -0700  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: set full stream caps on internal src TCP pads
+	  Set the complete stream caps on the TCP internal src pads. Otherwise,
+	  ptdemux will not properly detect the caps change.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737868
+
+2014-10-17 22:23:27 +0200  Sjoerd Simons <sjoerd@luon.net>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* tests/check/elements/rtpmux.c:
+	  rtpmux: Don't set PROXY_CAPS flag on the src pad
+	  rtpmux behaves like a funnel in that it forwards whatever upstream is
+	  sending buffers. So setting proxy caps doesn't make sense as the
+	  upstream don't have to have compatible caps, thus resulting in an empty
+	  caps set as a result of a caps query. Instead set fixed caps just
+	  as funnel does.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=738722
+
+2014-10-20 11:57:38 +0530  Vineeth T M <vineeth.tm@samsung.com>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: critical error when element properties set as max/min
+	  left, right, top, bottom can be set from range of -2147483648 to 2147483647
+	  when i launch the videobox element with that values, it gives a critical error
+	  (gst-check-1.0:29869): GStreamer-CRITICAL **: gst_value_set_int_range_step: assertion 'start < end' failed
+	  This happens because min cannot be equal to max.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=738838
+
+2014-10-15 17:45:24 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtph265depay.c:
+	* gst/rtp/gstrtph265depay.h:
+	* gst/rtp/gstrtph265pay.c:
+	* gst/rtp/gstrtph265pay.h:
+	  Revert "rtp: add h265 RTP payloader + depayloader"
+	  This reverts commit d06ba9051f904a7eb482c07a97a1827169158663.
+	  This breaks the build, as it depends on parser API in -bad.
+
+2014-10-15 17:34:50 +0200  Jurgen Slowack <jurgen.slowack@barco.com>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtph265depay.c:
+	* gst/rtp/gstrtph265depay.h:
+	* gst/rtp/gstrtph265pay.c:
+	* gst/rtp/gstrtph265pay.h:
+	  rtp: add h265 RTP payloader + depayloader
+
+2014-10-05 21:24:27 +0200  Peter G. Baum <peter@dr-baum.net>
+
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavenc/gstwavenc.h:
+	  wavenc: Support RF64 format
+	  https://bugzilla.gnome.org/show_bug.cgi?id=725145
+
+2014-10-11 11:18:42 +1100  David Sansome <me@davidsansome.com>
+
+	* gst/equalizer/gstiirequalizer.c:
+	  equalizer: Don't call iirequalizer's transform_ip in passthrough mode
+	  It tries to map the read-only buffer with GST_MAP_READWRITE and crashes.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737886
+
+2014-10-10 18:30:07 -0400  Olivier Crête <olivier.crete@ocrete.ca>
+
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpsource: Rename seqnum-base to seqnum-offset in caps
+	  This was modified back in 1.0 in GstRtpBasePayload
+
+2014-10-10 18:11:19 -0400  Olivier Crête <olivier.crete@ocrete.ca>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* tests/check/elements/dtmf.c:
+	  rtpdtmfsrc: clock-base and seqnum-base -> timestamp-offset and seqnum-offset
+	  These were renamed in GstRTPBasePayload in 1.0
+
+2014-10-10 17:30:24 -0400  Olivier Crête <olivier.crete@ocrete.ca>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	* tests/check/elements/rtpmux.c:
+	  rtpmux: clock-base and seqnum-base -> timestamp-offset and seqnum-offset
+	  These were renamed in GstRTPBasePayload in 1.0
+
+2014-10-06 14:23:22 +0100  Luis de Bethencourt <luis.bg@samsung.com>
+
+	* gst/goom2k1/filters.c:
+	  goom2k1: removing block of code that does nothing
+	  The loop in zoomFilterSetResolution is meant to change the values in the
+	  zf->firedec[] array. Each iteration writes the value of decc onto the arrya,
+	  but no conditions that change the value of decc are ever met and the array is
+	  filled with zero for each element. Which is the initial state of the
+	  array before the loop begins.
+	  The loop does nothing.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=728353
+
+2014-10-04 17:17:13 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: don't log all clock_rate changes as warnings.
+	  We never initialize clock_rate explicitly, therefore it is 0 by default. The
+	  parameter is a uint32 and the only caller ensure that it is >0, therefore it
+	  won't become -1 ever.
+
+2014-10-02 14:26:08 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	  souphttpclientsink: Fix lifetime of stream headers and queued buffers
+	  Stream headers are updated whenever ::set_caps is called, so we can't assume
+	  they'll be valid before the message body is written out. We *can* assume that
+	  for queued buffers, but SOUP_MEMORY_STATIC is still wrong for those.
+	  Also, add some debug logging for stream header interactions.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737771
+
+2014-10-02 03:26:22 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: fix memory leak when prepending ADTS headers
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737761
+
+2014-09-23 10:48:09 +0200  Antonio Ospite <ao2@ao2.it>
+
+	* gst/interleave/interleave.c:
+	* gst/interleave/interleave.h:
+	  interleave: interleave samples following the Default Channel Ordering
+	  In order to have a full mapping between channel positions in the audio
+	  stream and loudspeaker positions, the channel-mask alone is not enough:
+	  the channels must be interleaved following some Default Channel Ordering
+	  as mentioned in the WAVEFORMATEXTENSIBLE[1] specification.
+	  As a Default Channel Ordering use the one implied by
+	  GstAudioChannelPosition which follows the ordering defined in SMPTE
+	  2036-2-2008[2].
+	  NOTE that the relative order in the Top Layer is not exactly the same as
+	  the one from the WAVEFORMATEXTENSIBLE[1] specification; let's hope users
+	  using so may channels are already aware of such discrepancies.
+	  [1] http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308%28v=vs.85%29.aspx
+	  [2] http://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BS.2159-2-2011-PDF-E.pdf
+	  Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=737127
+
+2014-10-02 10:10:11 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: Send CAPS event after the pad was activated
+	  Otherwise the CAPS event will be dropped and we never configure any caps at
+	  all, leading to weird behaviour in many situations. Especially header
+	  rewriting is not going to work if a capsfilter is after wavenc.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737735
+
+2014-10-01 23:12:30 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	  souphttpclientsink: Add some more useful debug logging
+
+2014-10-01 23:05:03 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	  souphttpclientsink: Free queued buffers in ::reset
+	  ::render sets a new callback for writing out new buffers only if there aren't
+	  already buffers queued for writing with a previously-scheduled callback.
+	  However, if the previously-scheduled callback is interrupted by a state change
+	  (either manually or due to an error) and there are still buffers in the queue,
+	  restarting the pipeline will result in buffers being queued forever, and no
+	  callbacks will ever be scheduled, and no buffers will be written out.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737739
+
+2014-10-01 17:29:29 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Actually use the correct GstVideoInfo for conversion
+
+2014-10-01 17:24:59 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Revert the last commit and handle resolutions differences properly
+	  This is about converting the format, not about converting any widths and
+	  heights. Subclasses are expected to handler different resolutions themselves,
+	  like the videomixers already do properly.
+
+2014-10-01 17:12:59 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: GstVideoConverter currently can't rescale and will assert
+	  Leads to ugly assertions instead of properly erroring out:
+	  CRITICAL **: gst_video_converter_new: assertion 'in_info->width == out_info->width' failed
+
+2014-09-30 11:35:12 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp9enc.c:
+	  vp8enc/vp9enc: Protect the encoder with a mutex in all situations
+
+2014-09-30 11:31:43 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/vpx/gstvp9enc.c:
+	  vp9enc: Allow caps renegotiation
+	  https://bugzilla.gnome.org/show_bug.cgi?id=726329
+
+2014-09-30 11:28:39 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: finish() and drain() should return a GstFlowReturn
+
+2014-03-14 12:59:02 +0100  Jose Antonio Santos Cadenas <santoscadenas@gmail.com>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: Allow caps renegotiation
+	  https://bugzilla.gnome.org/show_bug.cgi?id=726329
+
+2014-09-29 11:49:45 +0200  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: set colorspace for output devices
+	  When the v4l2 device is an output device, the application shall set the
+	  colorspace. So map GStreamer colorimetry info to V4L2 colorspace and set
+	  on set_format. In case we have no colorimetry information, we try to
+	  guess it according to pixel format and video size.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737579
+
+2014-09-29 22:48:16 +0530  Arun Raghavan <arun@accosted.net>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	  pulse: Add some documentation about threading and synchronisation
+	  This gives a quick introduction to how the pulsesink/pulsesrc code
+	  interacts with the pa_threaded_mainloop that we start up to communicate
+	  with the server.
+
+2014-09-29 20:18:08 +0530  Arun Raghavan <arun@accosted.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Make emitting stream status messages synchronous
+	  The stream status messages are emitted in the PA mainloop thread, which
+	  means the mainloop lock is taken, followed by the Gst object lock (by
+	  gst_element_post_message()). In all other locations, the order of
+	  locking is reversed (this is unavoidable in a bunch of cases where the
+	  object lock is taken by GstBaseSink or GstAudioBaseSink, and then we get
+	  control to take the mainloop lock).
+	  The only way to guarantee that the defer callback for stream status
+	  messages doesn't deadlock is to either stop posting those messages, or
+	  make sure that the message emission is completed before we proceed to
+	  any point that might take the object lock before the mainloop lock
+	  (which is what we do after this patch).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736071
+
+2014-09-16 12:12:49 +0200  Antonio Ospite <ao2@ao2.it>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: print channel masks in hexadecimal
+
+2014-09-27 16:01:21 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* sys/v4l2/gstv4l2deviceprovider.h:
+	  v4l2: remove redundant struct declaration
+
+2014-09-26 13:46:16 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Fix compiler warnings
+	  gstrtspsrc.c:7939:11: error: implicit conversion from enumeration type 'GstSDPResult' to different enumeration type
+	  'GstRTSPResult' [-Werror,-Wenum-conversion]
+	  res = gst_sdp_message_new (&sdp);
+	  ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~
+	  gstrtspsrc.c:7944:11: error: implicit conversion from enumeration type 'GstSDPResult' to different enumeration type
+	  'GstRTSPResult' [-Werror,-Wenum-conversion]
+	  res = gst_sdp_message_parse_uri (uri, sdp);
+	  ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+2014-09-25 15:01:14 +0200  Jonas Holmberg <jonashg@axis.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: make demuxer reusable
+	  Remove pads from flow combiner and reset last
+	  flow return to FLOW_OK by resetting the flow combiner.
+	  This prevents FLOW_FLUSHING when trying to re-use the
+	  demuxer after setting it back to NULL/READY state.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737359
+
+2014-09-24 16:46:36 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/gstcms.c:
+	* gst/videomixer/gstcms.h:
+	* gst/videomixer/videoconvert.c:
+	* gst/videomixer/videoconvert.h:
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2pad.h:
+	* gst/videomixer/videomixerorc-dist.c:
+	* gst/videomixer/videomixerorc-dist.h:
+	* gst/videomixer/videomixerorc.orc:
+	  videomixer: use video library code instead of copy
+
+2014-09-18 16:39:19 +0530  Sanjay NM <sanjay.nm@samsung.com>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  audioparsers: Added index check before using the index
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736878
+
+2014-09-23 23:33:37 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Do not infer DTS on buffers from sparse streams.
+	  DTS delta is used to calculate sample duration. If buffer has missing DTS, we take either segment start or previous buffer end time, whichever is later.
+	  This must only be done for non sparse streams, sparse streams can have gaps between buffers (which is handled later by adding extra empty buffer with duration that fills the gap)
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737095
+
+2014-09-18 17:08:37 +0530  Sanjay NM <sanjay.nm@samsung.com>
+
+	* gst/goom/ifs.c:
+	  goom: Clarified precedence between % and ?
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736887
+
+2014-09-18 17:59:31 +0530  Sanjay NM <sanjay.nm@samsung.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtsp: clarify expression so operator precedence is clear
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736903
+
+2014-09-18 16:04:03 +0530  Sanjay NM <sanjay.nm@samsung.com>
+
+	* ext/libpng/gstpngdec.c:
+	* gst/alpha/gstalpha.c:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/gstscaletempo.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavimux.c:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	* gst/rtpmanager/rtpsession.c:
+	  Miscellaneous minor cleanups
+	  Fix redundant variables and assignments,
+	  and unreachable breaks.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736875
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736876
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736879
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736880
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736881
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736888
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736890
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736892
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736893
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736894
+
+2014-09-24 00:12:14 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: remove duplicate assignments
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736897
+
+2014-09-23 22:55:48 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Only calculate with durations != -1
+
+2014-09-23 19:08:48 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: collect pad for sparse stream should be created with lock set to false
+	  Avoids waiting for buffers from sparse streams
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737095
+
+2014-09-23 19:07:25 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: fix subtitle buffer duration and strip null termination
+	  Strip the \0 off the subtitle as we already know the size and also remember
+	  to set the duration as buffer copying doesn't do it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737095
+
+2014-09-23 19:06:18 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/atoms.c:
+	  qtmux: move subtitle layer above video and set alternate group
+	  layer -1 is above video, that is 0
+	  And having all subtitles in alternate group 2 means that only one
+	  should be selected at a time.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=737095
+
+2014-09-23 09:47:31 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* tests/check/elements/souphttpsrc.c:
+	  check/soup: Temporarily disable G_ENABLE_DIAGNOSTIC
+	  The SOUP_SERVER_PORT property has been deprecated in recent libsoup
+	  versions.
+
+2014-09-23 09:43:05 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* tests/check/elements/souphttpsrc.c:
+	  check/soup: Define minimum version required
+	  To avoid deprecation warnings
+
+2014-09-19 19:14:28 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Handle mp4a without ESDS atom
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736986
+
+2014-09-22 16:15:27 +0200  Linus Svensson <linussn@axis.com>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximagesrc: Fix build problem without XFIXES
+
+2014-09-19 14:34:13 +0530  Sanjay NM <sanjay.nm@samsung.com>
+
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  dtmf: Removed unused structure members
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736883
+
+2014-09-11 13:48:44 -0300  Reynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>
+
+	* gst/isomp4/atoms.c:
+	  isomp4: fix wrong DAR calculation for PAR <= 1
+	  CID #1226452
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736396
+
+2014-09-18 16:59:52 +0530  Sanjay NM <sanjay.nm@samsung.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flv: Removed unreachable break statements
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736884
+
+2014-09-17 16:37:11 +0200  Ognyan Tonchev <ognyan@axis.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: do not leak encsink pad in error case
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736807
+
+2014-09-17 16:23:21 +0200  Ognyan Tonchev <ognyan@axis.com>
+
+	* gst/multipart/multipartdemux.c:
+	  multipartdemux: do not leak new stream event
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736805
+
+2014-09-15 09:08:18 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* gst/y4m/gsty4mencode.c:
+	* gst/y4m/gsty4mencode.h:
+	  y4menc: port y4menc to use GstVideoEncoder base class
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735085
+
+2014-09-17 13:55:18 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* sys/osxaudio/gstosxcoreaudio.c:
+	* sys/osxaudio/gstosxcoreaudiocommon.c:
+	* sys/osxaudio/gstosxcoreaudiohal.c:
+	* sys/osxaudio/gstosxcoreaudioremoteio.c:
+	  osxaudio: OSStatus is not a fourcc, so don't print it as one...
+
+2014-09-16 14:26:08 +0200  Ognyan Tonchev <ognyan@axis.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: do not leak uid after parsing TOC event
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736739
+
+2014-09-16 22:47:13 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  rtpvrawdepay: Declare some more required caps fields in the sink template caps
+	  Now only missing are width and height, which are expressed as strings
+	  for RTP... so we can't put them into the template caps.
+
+2014-09-16 16:46:07 +0530  Vineeth T M <vineeth.tm@samsung.com>
+
+	* ext/gdk_pixbuf/gstgdkpixbufdec.c:
+	* ext/gdk_pixbuf/gstgdkpixbufdec.h:
+	  gdkpixbufdec: modify wrong packetized mode logic
+	  packetized mode is being set when framerate is being set
+	  which is not correct. Changing the same by checking the
+	  input segement format. If input segment is in TIME it is
+	  Packetized, and if it is in BYTES it is not.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736252
+
+2014-09-16 11:26:22 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Remove unused variable and use correct decoder variable name
+
+2014-09-16 11:25:42 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: Remove unused variable
+
+2014-09-16 13:24:15 +0530  Vineeth T M <vineeth.tm@samsung.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpeggdec: modify wrong packetized mode logic
+	  packetized mode is being set when framerate is being set
+	  which is not correct. Changing the same by checking the
+	  input segement format. If input segment is in TIME it is
+	  Packetized, and if it is in BYTES it is not.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736252
+
+2014-09-16 13:23:16 +0530  Vineeth T M <vineeth.tm@samsung.com>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: modify wrong packetized mode logic
+	  packetized mode is being set when framerate is being set
+	  which is not correct. Changing the same by checking the
+	  input segement format. If input segment is in TIME it is
+	  Packetized, and if it is in BYTES it is not.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736252
+
+2014-09-15 14:39:41 +0200  Antonio Ospite <ao2@ao2.it>
+
+	* sys/ximage/gstximagesrc.c:
+	* sys/ximage/gstximagesrc.h:
+	* sys/ximage/ximageutil.c:
+	* sys/ximage/ximageutil.h:
+	  ximagesrc: Remove unused screen-num property
+	  The screen number can be still specified as part of the display-name
+	  property (e.g. for screen 1 of display 0 use display-name=":0.1").
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736122
+
+2014-09-04 16:10:51 +0200  Antonio Ospite <ao2@ao2.it>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximagesrc: Draw the cursor only when it is active in the capturing region
+	  Use XQueryPointer to check that the pointer is actually active inside
+	  the capturing region.
+	  This prevents drawing the cursor when the pointer is partially outside
+	  of the captured region but not active inside the region; in particular
+	  this avoids drawing the "window resize" cursor shapes to the captured
+	  image when the mouse pointer crosses a window border.
+	  NOTE that this is not only an optimization, this also happen to fix
+	  a serious problem in multi-screen setups.
+	  Because XFixes gives no information of what screen the pointer is on,
+	  ximagesrc was always drawing the cursor on the captured screen even if
+	  the mouse pointer was on another screen.
+	  For example, when capturing from screen 1 (i.e. display-name=":0.1") the
+	  cursor was drawn in the captured image even when the mouse pointer was
+	  actually on screen 0, which is wrong and visually confusing.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=690646
+
+2014-09-05 11:33:31 +0200  Antonio Ospite <ao2@ao2.it>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximagesrc: Fix drawing the cursor when it is outside the capturing region
+	  When the cursor is partially or totally out of the capturing region on
+	  the top side or on the left side, it gets drawn fully inside of the
+	  region with its coordinates rounded up to the left or to the top border.
+	  This is immediately noticeable when using the xid property to capture
+	  a specific window.
+	  To fix the issue, allow negative cx and cx coordinates when checking the
+	  boundaries before drawing the cursor.
+	  NOTE that the boundaries checking calculations still allows the cursor
+	  to be drawn when it is only partially outside of the capturing region,
+	  but this makes sense and gives a more pleasing visual behaviour.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=690646
+
+2014-09-05 00:15:30 +0200  Antonio Ospite <ao2@ao2.it>
+
+	* sys/ximage/gstximagesrc.c:
+	* sys/ximage/gstximagesrc.h:
+	  ximagesrc: Fix the destination coordinates of the cursor
+	  XFixes provides the cursor coordinates relative to the root window, this
+	  is not taken into account when using the xid property to capture
+	  a specific window, the result is that the cursor gets drawn at the wrong
+	  position.
+	  In order to fix this consider the window location when calculating the
+	  cursor position in the destination image.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=690646
+
+2014-09-15 14:51:24 +0200  Peter Korsgaard <peter@korsgaard.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: O_CLOEXEC needs _GNU_SOURCE
+	  Similar to 94f3d6fc / bz 709423
+	  On some systems (E.G. uClibc and older Glibc versions), O_CLOEXEC is only
+	  defined when _GNU_SOURCE is specified, so do so.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736670
+
+2014-09-15 18:11:37 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/debugutils/gstcapssetter.c:
+	  capssetter: update to 1.0 transform_caps sematics
+	  In 1.0, we pass the complete caps to transform_caps to allow for better
+	  optimizations. Make this function actually work on non-simple caps
+	  instead of just ignoring the configured filter caps.
+
+2014-09-08 14:06:00 +0200  Peter G. Baum <peter@dr-baum.net>
+
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavenc/gstwavenc.h:
+	  wavenc: use WAVE_FORMAT_EXTENSIBLE for more than 2 channels
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733444
+
+2014-09-12 15:06:50 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Fix parsing of adtl chunks
+	  We have to skip 12 bytes of data for the chunk, and the data size
+	  passed to the sub-chunk parsing functions should have 4 bytes less
+	  than the data size.
+	  Also when parsing the sub-chunks, check if we actually have enough
+	  data to read instead of just crashing.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736266
+
+2014-09-12 10:55:23 +0530  Sanjay NM <sanjay.nm@samsung.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udp: include string.h for memcmp and memset
+	  https://bugzilla.gnome.org//show_bug.cgi?id=736528
+
+2014-09-12 13:36:18 +0530  Anuj Jaiswal <anuj.jaiswal@samsung.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: don't bitwise OR the same flag twice
+	  https://bugzilla.gnome.org//show_bug.cgi?id=736543
+
+2014-09-12 10:35:36 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: handle real audio 28_8
+	  Fixes duplicate check for 14_4.
+	  https://bugzilla.gnome.org//show_bug.cgi?id=736543
+
+2014-09-11 14:46:09 +0530  Anuj Jaiswal <anuj.jaiswal@samsung.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: don't OR the same flag twice
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736462
+
+2014-09-11 12:52:11 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: If the server reports "Accept-Ranges: none" don't try range requests
+
+2014-09-10 09:50:45 +0200  Ognyan Tonchev <ognyan@axis.com>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: Unref pool after usage
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736384
+
+2014-09-09 19:03:50 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Don't rank it for now
+	  This will prevent the converter to be picked automatically in case
+	  someone implement dynamic converter selection support. I'd like this
+	  to be ranked only for known device, as it's hard to be sure a device is
+	  a converter suited for general purpose. Re-negotiation is also needed
+	  before we can rank it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733607
+
+2014-09-05 08:29:20 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	  v4l2: Detect bad drivers timestamps
+	  Even though the UVC driver do a great deal of effort to prevent bad
+	  timestamp to be sent to userspace, there still exist UVC hardware that
+	  are so buggy that the timestamp endup nearly random. This code detect
+	  and ignore timestamp from these drivers, making these camera usable.
+	  This has been tested on both invalid and valid cameras, making sure it
+	  does not trigger for valid cameras.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=732910
+
+2014-08-29 17:09:30 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Workaround driver that don't support REQBUFS(0)
+	  There is still around 18 drivers not yet ported to videobuf2. These driver
+	  don't support freeing buffetrs through REQBUFS(0) hence for these the
+	  memory type probing fails. In order to gain back our previous behaviour in
+	  presence of these, we implement a workaround that assuming MMAP is
+	  supported. Note that an allocator is only created for device with
+	  STREAMING support in the device capabilities. In such case one of MMAP,
+	  USERPTR and DMABUF is required. Though DMABUF came afterward, so is
+	  not an option and in practice none of these drivers will only do USERPTR.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735660
+	  Also-by: Hans de Goede <hdegoede@redhat.com>
+
+2014-09-04 15:11:40 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2: Merge min_buffers_for* variable into one
+	  Reuse the same min_buffers variable for both capture and output, this
+	  reduce the length of lines and make the code more readable.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736072
+
+2014-09-04 18:35:46 +0200  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2: set min_latency for output device according to required minimum number of buffers
+	  Since we can get the minimum number of buffers needed by an output
+	  device to work, use it to set min_latency which will determine how many
+	  buffers are queued.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736072
+
+2014-09-09 16:10:56 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/udpsrc.c:
+	  tests: udpsrc: add check to make sure multiple memory chunks are used
+
+2014-09-09 15:55:18 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/udpsrc.c:
+	  tests: udpsrc: wait for buffers with GCond instead of sleeping
+	  Avoids half-second sleep for no reason.
+
+2014-09-09 15:31:32 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/udpsrc.c:
+	  tests: udpsrc: split out socket setup
+
+2014-09-09 13:46:56 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: more efficient memory handling
+	  Drop use of g_socket_get_available_bytes() which is
+	  not useful on all systems (where it returns the size
+	  of the entire buffer not that of the next pending
+	  packet), and is yet another syscall and apparently
+	  very inefficient on Windows in the UDP case.
+	  Instead, when reading UDP packets, use the more featureful
+	  g_socket_receive_message() call that allows to read into
+	  scattered memory, and allocate one memory chunk which is
+	  likely to be large enough for a packet, while also providing
+	  a larger allocated memory chunk just in case the packet
+	  is larger than expected. If the received data fits into the
+	  first chunk, we'll just add that to the buffer we return
+	  and re-use the fallback buffer for next time, otherwise we
+	  add both chunks to the buffer.
+	  This reduces memory waste more reliably on systems where
+	  get_available_bytes() doesn't work properly.
+	  In a multimedia streaming scenario, incoming UDP packets
+	  are almost never fragmented and thus almost always smaller
+	  than the MTU size, which is also why we don't try to do
+	  something smarter with more fallback memory chunks of
+	  different sizes. The fallback scenario is just for when
+	  someone built a broken sender pipeline (not using a
+	  payloader or somesuch)
+	  https://bugzilla.gnome.org/show_bug.cgi?id=610364
+
+2014-09-09 12:15:43 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	* gst/udp/gstudpsrc.h:
+	  udpsrc: rework memory allocation bits and ensure we always have two chunks of memories to read into
+	  First chunk is the likely/expected buffer size, second is as
+	  fallback in case the packet is larger in the end.
+	  Next step: actually use these.
+
+2014-09-09 09:42:15 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	* gst/udp/gstudpsrc.h:
+	  udpsrc: track max packet size and save allocator negotiated by GstBaseSrc
+
+2014-09-08 16:15:05 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/audiofx/audioecho.c:
+	  audioecho: fix example command line
+
+2014-09-07 12:46:08 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix crash with certain videos
+	  This is a regression from 1.2 caused by the port
+	  to the pad flow combiner.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=736192
+
+2014-09-04 16:21:20 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska-demux: Don't handle parse errors at the end of file as an error
+	  But only if they happen after the Matroska segment.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735833
+
+2014-09-04 12:14:11 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Include redirection target in error messages
+	  Just giving the original URI can give the false impression that e.g.
+	  that one failed host name resolution, while actually the redirection target
+	  did.
+
+2014-09-02 11:13:44 +0400  Andrei Sarakeev <sarakusha@gmail.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Fix synchronization if dynamically changing the FPS
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735859
+
+2014-09-02 13:52:43 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* gst/smpte/gstsmpte.c:
+	  smpte: Check if input caps are the same and create output caps from video info
+	  This makes sure that also properties like the pixel-aspect-ratio are the same
+	  between both streams and that the output caps contain all fields necessary for
+	  complete video caps.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735804
+
+2014-09-02 17:22:07 +0530  Vineeth T M <vineeth.tm@samsung.com>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: replace with gst_buffer_copy
+	  gst_buffer_ref and gst_buffer_writable is being used to create a writable copy of source buffer.
+	  replacing the same with gst_buffer_copy as the functionality is same.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735880
+
+2014-09-03 23:06:53 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: mark jpeg and png as parsed so avdec_mjpeg can be used too
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735971
+
+2014-09-03 11:46:13 +0530  Vineeth T M <vineeth.tm@samsung.com>
+
+	* ext/gdk_pixbuf/gstgdkpixbufdec.c:
+	  gdkpixbufdec: free query after use
+	  In gst_gdk_pixbuf_dec_setup_pool(), query is being allocated using
+	  gst_query_new_allocation(), but the same is not unreferenced
+	  hence calling gst_query_unref() after usage of query.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735950
+
+2014-09-03 23:46:34 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_types.c:
+	  qtdemux: Silence some warnings for normal file contents
+
+2014-09-01 09:56:02 +0200  Nicolas Huet <nicolas.huet@parrot.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Fix parsing issue when the buffer does not have a complete ADTS/LOAS frame
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735520
+
+2014-09-02 09:09:49 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/vpx/gstvp9dec.c:
+	  vp9dec: Get input width/height from the codec instead of the input caps
+	  They are reported properly by libvpx if the correct struct members are used.
+	  This also fixes handling of resolution changes without input caps changes.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=719359
+
+2013-10-22 18:49:22 +0100  Tom Greenwood <tcdgreenwood@hotmail.com>
+
+	* ext/vpx/gstvp8dec.c:
+	  vp8dec: Fix for handling resolution changes when decoding VP8
+	  If the resolution changes in the bitstream without the input caps changing we
+	  would previously output corrupted video or crash.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=719359
+
+2014-09-02 00:55:17 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* ext/vpx/gstvp9dec.c:
+	  vp9dec: Fix segfault when a new caps is received
+	  Remember to unref the output caps when a new caps event is received
+	  as it should generate a new one based on the new caps.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=734266
+
+2014-09-02 00:54:35 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* tests/check/elements/vp8dec.c:
+	  tests: vp8dec: add test for caps renegotiation
+	  Check that vp8dec can properly accept a new caps when upstream
+	  changes it
+	  https://bugzilla.gnome.org/show_bug.cgi?id=734266
+
+2014-08-05 10:34:39 +0200  Jose Antonio Santos Cadenas <santoscadenas@gmail.com>
+
+	* ext/vpx/gstvp8dec.c:
+	  vp8dec: Reset output and input states when changing format
+	  https://bugzilla.gnome.org/show_bug.cgi?id=734266
+
+2014-09-01 16:39:23 +0530  Vineeth T M <vineeth.tm@samsung.com>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Don't call gst_caps_unref() on template caps when already unreferenced
+	  Adding an extra condition while calling gst_caps_unref (templ)
+	  and replacing gst_caps_make_writable (gst_caps_ref (caps)) with
+	  gst_caps_copy (caps) in line 177, since the functionality is same.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735795
+
+2014-08-29 12:01:27 +0200  Hans de Goede <hdegoede@redhat.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: get_nearest_size: Fix "Unsupported field type" errors
+	  Most V4L2 ioctls like try_fmt will adjust input fields to match what the
+	  hardware can do rather then returning -EINVAL. As is docmented here:
+	  http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-g-fmt.html
+	  EINVAL is only returned if the buffer type field is invalid or not supported.
+	  So upon requesting V4L2_FIELD_NONE devices which can only do interlaced
+	  mode will change the field value to e.g. V4L2_FIELD_BOTTOM as only returning
+	  half the lines is the closest they can do to progressive modes.
+	  In essence this means that we've failed to get a (usable) progessive mode
+	  and should fall back to interlaced mode.
+	  This commit adds a check for having gotten a usable field value after the first
+	  try_fmt, to force fallback to interlaced mode even if the try_fmt succeeded,
+	  thereby fixing get_nearest_size failing on these devices.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735660
+
+2014-08-29 10:57:20 +0200  Hans de Goede <hdegoede@redhat.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: get_nearest_size: Always reinit all struct fields on retry
+	  They may have been modified by the ioctl even if it failed. This also makes
+	  the S_FMT fallback path try progressive first, making it consistent with the
+	  preferred TRY_FMT path.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735660
+
+2014-08-29 11:55:26 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Store size of data tag in a 64 bit integer locally too
+	  Otherwise we will clip the DS64 value of RF64 files to 32 bits again.
+
+2014-08-29 11:53:23 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Use 64 bit scaling functions now that fact is a 64 bit integer
+
+2014-08-27 18:55:18 +0200  Peter G. Baum <peter@dr-baum.net>
+
+	* gst/wavparse/gstwavparse.c:
+	* gst/wavparse/gstwavparse.h:
+	  wavparse: support rf64 format
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735627
+
+2014-08-28 13:48:50 -0600  Jason Litzinger <jlitzinger@control4.com>
+
+	* gst/multipart/multipartdemux.c:
+	  multipartdemux: Ensure caps before pad added.
+	  This stores the stream-start, sets caps, and then adds the pad,
+	  which ensures that the caps are set for the "pad-added" callback.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735626
+
+2014-08-28 15:03:50 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Fallback to PTS if DTS is missing
+	  Fixing a regression introduce when fixing:
+	  https://bugzilla.gnome.org/show_bug.cgi?id=731352
+
+2014-08-28 16:13:29 +0530  Vineeth T M <vineeth.tm@samsung.com>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Remove impossible error condition
+	  We return EOS after the first buffer, and GstPad will make sure now that we
+	  won't get any other buffer afterwards until a flush happens. No need to check
+	  for it ourselves.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735581
+
+2014-08-28 13:53:23 +0530  Vineeth T M <vineeth.tm@samsung.com>
+
+	* ext/gdk_pixbuf/gstgdkpixbufdec.c:
+	  gdkpixbufdec: EOS and NOT_LINKED are no errors in general
+	  Don't post an error message for them but let upstream handle
+	  anything accordingly.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=735564
+
+2014-08-27 21:07:26 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  flvmux: Correctly offset timestamp
+	  The previous method would break AV sync in the case audio or video
+	  didn't start at the same point in running time.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=731352
+
+2014-08-27 20:56:12 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Save dts from buffer
+	  We no longer set dts in muxed buffer. This would lead to encoding tags
+	  with timestamp 0 instead of the timestamp of previous buffer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=731352
+
+2014-07-28 20:58:59 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  flvmux: Ensure Timestamp starts at 0
+	  FLV documentation stipulates that timestamp must start at zero.
+	  In order to respect this rule, keep the first timestamp around
+	  and offset the timestamp from this value. This allow for longer
+	  recording time in presence of timestamp that does not start
+	  at 0 already.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=731352
+
+2014-06-06 23:17:52 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	* gst/flv/gstflvmux.c:
+	  flv: Tag timestamp are DTS not PTS
+	  The tags in FLV are DTS. In audio cases, and for many video format this makes
+	  no difference, but for AVC with B-Frames, PTS need to be computed from
+	  composition timestamp CTS, with PTS = DTS + CTS.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=731352
+
+2014-08-07 21:58:14 -0400  Youness Alaoui <kakaroto@kakaroto.homelinux.net>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: Allow rtp caps without clock-rate
+	  The jitterbuffer shouldn't force clock-rate on its sink pad, this will cause a negotiation issue since rtpssrcdemux doesn't have the clock-rate and doesn't add it to the caps. The documentation states that the clock-rate can either be specified through the caps or through the request-pt-map signal, so we must remove clock-rate from the pad templates and we must accept the GST_EVENT_CAPS if the caps don't have the clock-rate.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=734322
+
+2014-08-18 14:05:52 -0300  Thiago Santos <thiagoss@osg.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: avoid crashing on dash streams
+	  DASH/fragmented moov might have no samples as those are carried
+	  in moof fragments. Avoid crashing or failing the stream because
+	  of that.
+
+2014-08-18 10:33:48 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* tests/examples/equalizer/demo.c:
+	* tests/examples/spectrum/demo-audiotest.c:
+	* tests/examples/spectrum/demo-osssrc.c:
+	  examples: use 'post-messages' property instead of deprecated 'message' property
+	  https://bugzilla.gnome.org/show_bug.cgi?id=734979
+
+2014-08-18 11:45:54 +0200  Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udp: fix udpsrc documentation
+	  udpsrc gtk-doc documentation refers to sockfd and closefd properties which has
+	  been removed. This patch replaces those references to socket and close-socket
+	  respectively.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=734987
+
+2014-08-15 10:09:56 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Make the default timescale 1/1800 second
+	  The old default timescale of 1 millisecond produces irrational
+	  numbers for a lot of framerate/audio-packet-duration multiples.
+	  1/1800 is a nicer number, as it tends to produce better fractions
+	  and therefore slightly higher accuracy overall
+
+2014-08-15 01:17:27 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska: Use gst_video_guess_framerate() function
+	  Remove local framerate guessing function in favour of
+	  the new gst_video_guess_framerate() function.
+
+2014-08-15 01:12:20 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/Makefile.am:
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Improve framerate calculation/guessing
+	  Change the way the output framerate is calculated
+	  to ignore the first sample (which is sometimes truncated
+	  in my testing) and use the new gst_video_guess_framerate()
+	  function to recognise common standard framerates better.
+	  Remove the code that was sorting the first 20 sample
+	  durations and then ignoring the result.
+
+2014-08-14 16:36:44 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Use the best width/height/etc if downstream can handle that
+	  Before it was always using whatever downstream preferred, while
+	  the code and documentation claimed something different.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727180
+
+2014-08-14 11:29:00 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Avoid double free of VideoConvert
+	  https://bugzilla.gnome.org/show_bug.cgi?id=734764
+
+2014-08-13 11:58:35 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: fix indentation
+
+2014-08-13 11:54:26 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: un-break duration querying
+	  Commit 2b9493b5 broke this in two ways: a) we should only
+	  pass duration queries in TIME format upstream (or at least
+	  not those in DEFAULT or BYTE format), and b) we mustn't
+	  overwrite the default value of 'res' from TRUE to FALSE
+	  and not set it again later. This led to bogus durations
+	  being reported for FLV playback from file, because TIME
+	  queries would fail (as 'res' had been set to FALSE) and
+	  parsers then do a BYTE query as fallback and try to
+	  guesstimate something in return, which of course goes
+	  horribly wrong since the BYTE size returned is for the
+	  muxed file.
+
+2014-08-13 13:23:10 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: Allow any raw caps in passthrough mode, not just the ones we handle
+
+2014-08-13 13:04:21 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: Allow ANY capsfeatures, but only in passthrough mode
+	  When changing the properties to not be in passthrough mode anymore,
+	  we will only accept caps we can process ourselves, potentially causing
+	  a not-negotiated error.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720345
+
+2014-08-12 11:34:30 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	  docs: update for git
+
+2014-08-12 11:33:56 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* configure.ac:
+	  configure: build ximagesrc again when checks succeed
+	  Third time lucky, hopefully.
+
+2014-08-11 09:26:17 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* configure.ac:
+	  configure: fix x11 checks to be non-fatal again
+	  Must pass an action-if-not-found argument to
+	  PKG_CHECK_MODULES or it will error out when
+	  it can't find the module requested. Also fix
+	  AC_CHECK_LIB usage, extra libs argument was
+	  in the wrong place.
+
+2014-08-07 17:12:38 +0300  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: forward DISCONT from upstream to the output streams
+	  This makes sense in DASH reverse playback, where the upstream dashdemux
+	  will download DASH segments in reverse order, but push their buffers
+	  forward to qtdemux and mark each segment start as DISCONT. This needs
+	  to be forwarded downstream to the parser/decoder, otherwise it won't work.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=734443
+
+2014-08-10 18:55:07 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* configure.ac:
+	  configure: use pkg-config to detect x11 and simplify checks
+	  AC_PATH_XTRA macro unnecessarily pulls in libSM and libICE.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=731047
+
+2014-08-10 12:30:07 +0200  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* tests/check/elements/rtp-payloading.c:
+	  tests: rtp-payloading: adjust test data to avoid NAL chopping
+	  ... and correspondingly unexpected buffer sizes.
+
+2014-08-09 14:22:42 +0200  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* ext/speex/gstspeexenc.c:
+	  speexenc: Improve annotation of internal function
+	  https://bugzilla.gnome.org/show_bug.cgi?id=734542
+
+2014-08-08 12:54:30 +0200  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* gst/shapewipe/gstshapewipe.c:
+	* tests/examples/shapewipe/shapewipe-example.c:
+	  shapewipe: Unref caps and element after usage
+	  https://bugzilla.gnome.org/show_bug.cgi?id=734478
+
+2014-08-09 20:47:30 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: improve debug logging of fourccs
+	  If we can't show ASCII, at least show them
+	  in big endian order.
+
+2014-08-09 20:46:04 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: add support for 'wma ' mapping as found in some ismv files
+	  e.g. To_The_Limit_720_2962.ismv
+
+2014-08-09 18:31:20 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: add support for 'vc-1' mapping as found in some ismv files
+	  e.g. To_The_Limit_720_2962.ismv
+
+2014-08-07 16:34:36 +0200  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* gst/rtp/gstrtph263ppay.c:
+	  rtph263ppay: Unref pad template caps after use
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=734435
+
+2014-08-08 12:36:01 +0200  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Unref allowed caps after usage
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=734474
+
+2014-08-08 12:40:49 +0200  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Unref pad template caps after usage
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=734475
+
+2014-08-08 12:44:09 +0200  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* gst/debugutils/gstnavseek.c:
+	  navseek: Unref peer pad after usage
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=734476
+
+2014-08-08 12:29:52 +0200  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Unref pad template caps after usage
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=734473
+
+2014-08-05 11:47:39 +0200  Srimanta Panda <srimanta@axis.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: append packetization mode parameter to SDP
+	  Append packetization-mode parameter to SDP description.
+	  Packetization mode signals the properties of an RTP payload type.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733556
+
+2014-08-08 03:58:14 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux.c:
+	  isomp4/qtmux: Write correct file duration when gaps exist.
+	  When writing out a trak with an edit list, make sure the
+	  overall file duration is also updated to reflect the
+	  lengthening of the stream.
+	  Add some more debug to qtdemux to warn about streams that
+	  are longer than the file and get truncated.
+
+2014-08-04 15:39:17 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Push the correct segment in TCP mode when seeking
+
+2014-08-03 12:33:32 +0200  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: unbreak au aligned byte-stream payloading
+
+2014-07-22 13:24:09 +0200  Srimanta Panda <srimanta@axis.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: append profile-level-id to SDP
+	  Append profile-level-id to SDP if available.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733539
+
+2014-07-31 18:47:49 +0200  Edward Hervey <edward@collabora.com>
+
+	* Makefile.am:
+	* common:
+	  Makefile: Add usage of build-checks step
+	  Allows building checks without running them
+
+2014-07-31 09:53:53 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/ximage/ximageutil.c:
+	  ximagesrc: Fix warning about missing return value
+
+2014-07-24 15:28:09 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/ximage/gstximagesrc.c:
+	* sys/ximage/ximageutil.c:
+	* sys/ximage/ximageutil.h:
+	  ximagesrc: Add missing return value to Buffer dispose function
+	  Depending ont he build, the method could return FALSE, hence never
+	  free the buffers, or already TRUE and lead to a crash:
+	  Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=733695
+
+2014-07-28 16:49:16 +0200  Philippe Normand <philn@igalia.com>
+
+	* gst/interleave/interleave.c:
+	* tests/check/elements/interleave.c:
+	  interleave: set output caps layout to interleaved
+	  Set output caps layout independently from input caps layout which can
+	  be either non-interleaved or interleaved.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733866
+
+2014-07-26 12:06:39 -0300  Thiago Santos <ts.santos@osg.sisa.samsung.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: clear gcond
+
+2014-07-25 14:30:33 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  Revert "v4l2bufferpool: Workaround elements not requesting any buffers"
+	  This was a tempory workaround, we should fix the encoders that do not
+	  negotatiate the amount of buffers they need.
+	  This reverts commit d03bcba3db15d06dbdea6b776a6f28ed2f03272a.
+
+2014-07-08 14:31:59 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't share own pool if min exceed V4L2 capacity
+	  If the minimum required buffer exceed V4L2 capacity, don't share down
+	  pool. This allow support very high latency, like with x264enc default
+	  encoding settings.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=732288
+
+2014-07-25 17:42:20 +0200  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: query minimum required buffers for output
+	  Some v4l2 devices could require a minimum buffers different from default
+	  values. Rather than blindly propose a pool with min-buffers set to the
+	  default value, it ask the device using control ioctl.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733750
+
+2014-07-23 18:40:10 +0200  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: use directly 'obj' instead of 'v4l2sink->v4l2object'
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733616
+
+2014-07-23 18:39:50 +0200  Aurélien Zanelli <aurelien.zanelli@parrot.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2: set debug messages according to device type and IO mode
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733616
+
+2014-05-24 19:02:59 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Remove is_active checks
+	  These checks are no longer required with recent change to the bufferpool. This
+	  should allow changing the configuartion, hence the way forward renegotiation
+	  support.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=728268
+
+2014-07-21 18:11:16 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_lang.c:
+	  qtdemux: fix language code parsing for 3-letter codes starting with 'a'
+	  And handle special value for 'unspecified' explicitly.
+	  https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap4/qtff4.html
+
+2014-07-08 02:18:27 +0200  Nicola Murino <nicola.murino@gmail.com>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: Add support for encoding from NV21 and NV12
+	  https://bugzilla.gnome.org/show_bug.cgi?id=732870
+
+2014-07-19 18:04:38 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.4.0 ===
+
+2014-07-19 17:20:34 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.4.0
+
+2014-07-19 16:35:41 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2014-07-19 12:32:22 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: Update translations
+
+2014-07-19 11:30:30 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Don't overwrite the first component with the alpha value for BGRx
+	  Instead leave the x component unset when filling the borders.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733380
+
+2014-07-16 17:18:59 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Properly report in the CAPS query that we can convert ADTS<->RAW
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733190
+
+2014-07-13 16:05:56 +0200  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* gst/replaygain/gstrgvolume.c:
+	  rgvolume: Avoid taking unnecessary refs
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=733122
+
+2014-07-13 16:04:23 +0200  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpdtmfmux: Avoid taking an unnecessary ref
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=733122
+
+2014-07-15 16:59:06 +0200  Piotr Drąg <piotrdrag@gmail.com>
+
+	* po/POTFILES.in:
+	  po: update POTFILES
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733208
+
+2014-07-11 13:35:10 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Fix copy threshold implementation
+	  We cannot allocate new buffer in acquire, otherwise the base class
+	  is not aware and get confused. Instead, copy in _process(). This leads
+	  to crash on finalize.
+	  Fixes regression, see https://bugzilla.gnome.org/show_bug.cgi?id=732912
+
+=== release 1.3.91 ===
+
+2014-07-11 11:38:57 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.3.91
+
+2014-07-11 10:58:08 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2014-07-10 18:11:20 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2allocator.h:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2allocator: Use qdata instead of parenting to DmabufMemory
+	  Parenting V4l2Memory to DmabufMemory was in conflict with recent
+	  optimization in DmabufMemory to avoid dup(), and didn't work with
+	  memory sharing. Instead, use a qdata and it's destroy notify.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730441
+
+2014-07-11 08:52:39 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/da.po:
+	* po/de.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/pl.po:
+	* po/ru.po:
+	* po/uk.po:
+	* po/vi.po:
+	  po: Update translations
+
+2014-07-08 17:50:47 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Workaround elements not requesting any buffers
+	  This is a workaround for element that don't request buffers when
+	  they should.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=732288
+
+2014-07-06 11:27:36 +0200  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* tests/icles/videocrop-test.c:
+	  tests: fix pipeline leak in videocrop test
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=732976
+
+2014-07-06 11:26:46 +0200  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* tests/examples/rtp/client-rtpaux.c:
+	  examples: client-rtpaux: Release reference to parent when done
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=732976
+
+2014-07-10 17:19:42 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix query leak
+	  https://bugzilla.gnome.org/show_bug.cgi?id=733003
+
+2014-07-10 12:10:45 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: Return not-negotiated if we got no caps or caps negotiation failed
+	  And do it always, not inside a g_return_val_if_fail().
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=732939
+
+2014-07-08 13:34:28 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: Ensure internal pool activation
+	  Before we would hit an assertion "'gst_buffer_pool_is_active (bpool)' failed"
+	  if the internal pool was not used to push buffer downstrea, hence not
+	  given to the baseclass.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=732912
+
+2014-07-04 20:22:10 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: fix double unlock in segment seek segment code path
+	  We only want to unlock if we push an event downstream and
+	  jump to done_unlock label afterwards. We would also unlock
+	  in case of a segment seek and then unlock again later, and
+	  nothing good can come of that.
+	  (This code looks a bit dodgy anyway though, shouldn't it
+	  also bail out with FLOW_EOS here in case of a segment seek
+	  scenario, just without the event?)
+
+2014-07-04 19:45:55 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/qtmux.c:
+	  tests: qtmux: suppress glib criticals caused by testing deprecated dts methods
+
+2014-07-04 03:21:30 +0200  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* gst/avi/gstavidemux.c:
+	* gst/wavparse/gstwavparse.c:
+	  avidemux, wavparse: Print invalid fourcc in hex
+	  Previously this was printed as characters which caused later processing
+	  of the error message to sometimes warn about non-UTF-8 characters.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=732714
+
+2014-07-03 15:21:18 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Pool might be NULL in decide allocation
+	  If special stride is needed and downstream don't support VideoMeta,
+	  pool might be NULL in order to let the baseclass create a generic
+	  pool­. This would lead to assertion with on Exynos with:
+	  gst-launch-1.0 -v filesrc location=mov ! qtdemux ! h264parse ! \
+	  v4l2video8dec ! fakesink
+	  https://bugzilla.gnome.org/show_bug.cgi?id=732707
+
+2014-07-03 15:29:54 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2bufferpool: Handle FD error during poll
+	  This will ensure we fail earlier if something unrecoverable
+	  happens.
+
+2014-07-03 15:28:45 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2bufferpool: Wait before polling if queue is empty
+	  In kernel before 3.17, polling during queue underrun would unblock right
+	  away and trigger POLLERR. As we are not handling POLLERR, we would endup
+	  blocking in DQBUF call, which won't be unblocked correctly when going
+	  to NULL state. A deadlock at start caused by locking error in libv4l2 was
+	  also seen before this patch. Instead, we wait until the queue is no longer
+	  empty before polling.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=731015
+
+2014-07-02 16:01:47 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix for mikey api change
+
+2014-06-30 10:29:54 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: fix probing and enumeration of stepwise frame sizes
+	  The code enumerating STEPWISE framesizes would start from
+	  (min_w, min_h) and then add (step_w, step_h) to get the
+	  next framesize. However, it should really allow any width
+	  from min_w to max_w with step_w and same for heights.
+	  Secondly, we would add and probe each individual stepped
+	  frame size to the caps as separate structure, which would
+	  lead to hundreds if not thousands of structs ending up in
+	  the probed caps. Use integer ranges with steps instead.
+	  This was particularly noticable with the Raspberry Pi Cam.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=724521
+	  https://bugzilla.gnome.org/show_bug.cgi?id=732458
+	  https://bugzilla.gnome.org/show_bug.cgi?id=726521
+
+2014-06-27 11:33:06 +0100  Daniel Drake <drake@endlessm.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: drop workaround for misbehaving TRY_FMT
+	  This workaround from 2011 was causing 25 S_FMT ioctls to be sent
+	  to my UVC webcam from under gst_v4l2_object_get_caps as it probes
+	  all the formats. In total, this adds up to about 5 seconds of
+	  execution time, or a 10 second delay while starting up cheese.
+	  These ioctls come from a workaround from 2011 where TRY_FMT might
+	  make changes to hardware settings, so S_FMT was used to restore
+	  the original config:
+	  https://bugzilla.gnome.org/show_bug.cgi?id=649067
+	  The driver bug is now assumed fixed. Remove the workaround to fix the
+	  long startup delay.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=732326
+
+2014-07-01 12:50:31 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: reset QoS on segment event
+	  https://bugzilla.gnome.org/show_bug.cgi?id=732540
+
+2014-07-01 15:14:34 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: send gap events instead of segment tricks
+	  This fixes missing frames from being time skipped.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=732372
+
+2014-06-30 00:00:32 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/rtpsession.c:
+	  rtpsession: Fix memory leaks in unit test
+
+2014-06-29 23:55:19 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Don't leak caps
+
+2014-06-29 20:02:14 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: Fix compiler warning when compiling with G_DISABLE_ASSERT
+
+2014-06-29 19:59:53 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Fix compiler warning when compiling with G_DISABLE_ASSERT
+
+2014-06-29 19:57:57 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Fix compiler warnings when compiling with G_DISABLE_ASSERT
+
+2014-06-29 19:54:44 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	  deinterlace: Fix compiler warnings when compiling with G_DISABLE_ASSERT
+
+2014-06-29 17:05:13 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/pulse/pulsedeviceprovider.c:
+	  pulse: fix compiler warnings when compiling with -DG_DISABLE_ASSERT
+	  Compiler complains about uninitialised variables in the impossible
+	  'default' code path in device provider source/sink switch-case.
+
+2014-06-29 17:03:17 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* sys/v4l2/gstv4l2deviceprovider.c:
+	  v4l2: fix compiler warnings when compiling with -DG_DISABLE_ASSERT
+	  Compiler complains about uninitialised variables in the impossible
+	  'default' code path in device provider source/sink switch-case.
+
+2014-06-28 17:40:45 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/matroskaparse.c:
+	  tests: matroskaparse: fail on errors and disable pull mode test
+	  Actually look for error messages on the bus and fail if there
+	  is one before the EOS message. Disable pull mode test which is
+	  pointless as long as matroskaparse only supports push mode
+	  (pull mode support has not been ported over to 1.0).
+
+2014-06-28 17:37:23 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/matroska/matroska-parse.c:
+	  matroskaparse: don't error out if there's not enough data in the adapter
+	  gst_matroska_parse_take() would return FLOW_ERROR instead of
+	  FLOW_EOS in case there's less data in the adapter than requested,
+	  because buffer is NULL in that case which triggers the error
+	  code path. This made the unit test fail (occasionally at least,
+	  because of a bug in the unit test there's a race and it would
+	  happen only sporadically).
+
+2014-06-28 16:53:58 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/videomixer/videomixerorc-dist.c:
+	* gst/videomixer/videomixerorc-dist.h:
+	  videomixer: Update dist generated ORC files
+
+2014-06-28 16:48:13 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/videomixer/gstcms.c:
+	* gst/videomixer/gstcms.h:
+	* gst/videomixer/videoconvert.c:
+	* gst/videomixer/videoconvert.h:
+	* gst/videomixer/videomixerorc.orc:
+	  videomixer: Update videoconvert code from -base
+	  And also rename the remaining symbols to prevent conflicts
+	  during static linking.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=728443
+
+2014-06-28 13:01:46 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/autodetect/gstautovideosrc.c:
+	  autovideosrc: use videotestsrc as fallback element instead of fakesrc
+	  fakesrc doesn't announce video caps, so most video pipelines will
+	  just error out with not-negotiated if a fallback element is created.
+
+2014-06-28 12:44:31 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautodetect.c:
+	* gst/autodetect/gstautodetect.h:
+	  autoaudiosrc: use audiotestsrc as fallback element instead of fakesrc
+	  fakesrc doesn't announce audio caps, so most audio pipelines will
+	  just error out with not-negotiated if a fallback element is created.
+
+=== release 1.3.90 ===
+
+2014-06-28 11:21:15 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.3.90
+
+2014-06-28 11:08:33 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2014-06-26 14:52:57 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* ext/pulse/Makefile.am:
+	* ext/pulse/plugin.c:
+	* ext/pulse/pulsedeviceprovider.c:
+	* ext/pulse/pulsedeviceprovider.h:
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2deviceprovider.c:
+	* sys/v4l2/gstv4l2deviceprovider.h:
+	  Rename GstDeviceMonitor to GstDeviceProvider
+
+2014-06-24 09:14:40 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/videobox.c:
+	  videobox: Add unit test
+	  https://bugzilla.gnome.org/show_bug.cgi?id=732144
+
+2014-06-16 11:35:39 +0200  Thibault Saunier <tsaunier@gnome.org>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Declare as Compositor in 'klass'
+
+2014-06-26 13:50:19 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: fix speex caps
+	  Decoder complains about "notification: Invalid mode encountered.
+	  The stream is corrupted" though, even if it works, so there's
+	  probably something wrong with the generated codec headers.
+
+2014-06-26 13:43:33 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: fix speex in FLV
+	  Speex in FLV is always mono @ 16kHz, see
+	  http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf
+	  section E.4.2.1: "If the SoundFormat indicates Speex, the audio is
+	  compressed mono sampled at 16 kHz, the SoundRate shall be 0, the
+	  SoundSize shall be 1, and the SoundType shall be 0"
+	  Also see https://bugzilla.gnome.org/show_bug.cgi?id=683622
+
+2014-06-26 05:19:57 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  isomp4: Add object type id and fourcc for DTS/DTS-HD
+	  Enables playback for files with DTS audio tracks.
+	  Also add an extra AC-3 variant fourcc from Nero
+
+2014-03-13 10:35:30 +0100  David Fernandez <d.fernandezlop@gmail.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer2: Solve segmentation fault when src caps are configured
+	  Change function pointers to NULL while holding the lock to avoid
+	  race conditions
+	  https://bugzilla.gnome.org/show_bug.cgi?id=701110
+
+2014-06-25 14:34:21 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: improve SR packet handling
+	  Implement 3 different cases for handling the SR:
+	  1) we don't have enough timing information to handle the SR packet and
+	  we need to wait a little for more RTP packets. In that case we keep
+	  the SR packet around and retry when we get an RTP packet in the
+	  chain function.
+	  2) the SR packet has a too old timestamp and should be discarded. It is
+	  labeled invalid and the last_sr is cleared.
+	  3) the SR packet is ok and there is enough timing information, proceed
+	  with processing the SR packet.
+	  Before this patch, case 2) and 1) were handled in the same way,
+	  resulting that SR packets with too old timestamps were checked over and
+	  over again for each RTP packet.
+
+2014-06-24 10:47:33 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/udpsink.c:
+	  tests: add udpsink test to check client add/remove
+
+2014-06-23 16:13:27 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/udpsink.c:
+	  tests: port udpsink tests to 1.0
+	  They all seem a bit pointless though.
+
+2014-06-23 19:55:29 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/avi/gstavimux.c:
+	  avimux: Add UYVY format
+
+2014-06-06 11:20:21 +0200  Miguel París Díaz <mparisdiaz@gmail.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  gstrtpssrcdemux: manage ssrc of RTCP RR packets
+	  https://bugzilla.gnome.org/show_bug.cgi?id=731324
+
+2014-06-23 20:53:50 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Update offset after parsing adtl chunk
+	  Otherwise we will parse it over and over again without ever
+	  getting past it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=731533
+
+2013-07-07 20:18:27 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: remove legacy code for passing a window handle
+	  "have-ns-view" and the "embed" property was kept in 0.10 for
+	  backwards compatibility but it's no longer used in favor of
+	  the GstVideoOverlay interface
+	  https://bugzilla.gnome.org/show_bug.cgi?id=703753
+
+2014-06-22 19:36:14 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Back to development
+
+2014-06-22 19:26:03 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: Don't call GST_DEBUG_OBJECT() and other macros with non-GObject objects
+	  It will crash with latest GLib GIT and was never supposed to work before
+	  either.
+
+=== release 1.3.3 ===
+
+2014-06-22 18:08:03 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.3.3
+
+2014-06-22 17:36:28 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2014-06-22 14:24:24 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: Update translations
+
+2014-06-21 01:32:03 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/pulse/pulsedevicemonitor.c:
+	* sys/v4l2/gstv4l2devicemonitor.c:
+	  pulse, v4l2: update for device "klass" -> "device-class" rename
+
+2014-06-20 12:21:05 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: optimisation: avoid unnecessary memory ref/unrefs
+	  We know the buffer will stay valid and we will also not
+	  modify the buffer, we just want to send out the data.
+
+2014-06-19 14:59:48 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	  multiudpsink: avoid some unnecessary run-time type checks
+
+2014-06-19 16:17:23 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: pass the stream id when asking for crypto params
+	  This way the app can choose different parameters for each stream.
+
+2014-05-20 14:58:07 -0700  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: add support for key length parameters
+	  This patch adds supports for the incoming key management parameters for
+	  encryption and authentication key lengths.
+	  It also adds a new signal request-rtcp-key that allows the user to
+	  provide the crypto parameters and key for the RTCP stream.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730473
+
+2014-06-19 15:25:01 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtp/gstrtpvp8depay.c:
+	  vp8depay: fix header size checking
+	  Use a different variable name to make it clear that we are calculating
+	  the header size.
+	  Correctly check that we have enough bytes to read the header bits. We
+	  were checking if there were 5 bytes available in the header while we
+	  only needed 3, causing the packet to be discarded as too small.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=723595
+
+2014-05-20 12:39:31 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtph264pay.h:
+	  rtph264pay: propagate the GST_BUFFER_FLAG_DISCONT flag
+	  Similarly to what we did with the DELTA_UNIT flag, this patch
+	  propagates the DISCONT flag to the first RTP packet being used to transfer a
+	  DISCONT buffer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730563
+
+2014-05-06 17:42:14 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtph264pay.h:
+	  rtph264pay: propagate the GST_BUFFER_FLAG_DELTA_UNIT flag
+	  Downstream elements may be interested knowing if a RTP packet is the start
+	  of a key frame (to implement a RTP extension as defined in the
+	  ONVIF Streaming Spec for example).
+	  We do this by checking the GST_BUFFER_FLAG_DELTA_UNIT flag we receive from
+	  upstream and propagate it to the *first* RTP packet outputted to transfer this
+	  buffer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730563
+
+2014-05-20 13:58:20 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4gpay.h:
+	  gstrtpmp4gpay: propagate the GST_BUFFER_FLAG_DISCONT flag
+	  Propagate the DISCONT flag to the first RTP packet being used to transfer
+	  a DISCONT buffer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730563
+
+2014-05-20 13:58:20 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: propagate the GST_BUFFER_FLAG_DISCONT flag
+	  Propagate the DISCONT flag to the first RTP packet being used to transfer
+	  a DISCONT buffer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730563
+
+2014-06-18 15:03:25 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: don't leak flow combiner
+
+2014-06-18 14:38:55 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpj2kpay.c:
+	  rtpjp2kpay: pre-allocate buffer-list of the right size
+
+2014-06-18 14:34:09 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: pre-allocate buffer list of the right size
+
+2014-06-18 14:19:28 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpmp4vpay.c:
+	  rtpmp4vpay: pre-allocate buffer list of the right size
+
+2014-06-18 13:44:31 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8pay: allocate bitreader on the stack
+
+2014-06-18 13:29:47 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8pay: post error message on bus on error and don't use g_message()
+
+2014-06-18 13:20:44 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8pay: couple of minor optimisations
+	  Pre-allocate buffer list of the right size to avoid re-allocs.
+	  Avoid plenty of double runtime cast checks and re-doing the
+	  same calculation over and over again in rtp_vp8_calc_payload_len().
+	  Only call gst_buffer_get_size() once.
+
+2014-06-18 08:10:03 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: pre-allocate buffer list of the right size
+	  To avoid re-allocs.
+
+2014-06-18 07:52:05 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: pre-allocate bufferlist of the right size
+	  To avoid unnecessary re-allocs.
+
+2014-06-16 20:15:43 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	* tests/check/elements/rtp-payloading.c:
+	  rtph264pay: push single buffer directly, no need to wrap it in a bufferlist
+	  No point in a buffer list if we just have one single
+	  buffer to push. Fix up unit test to handle that case
+	  as well.
+
+2014-06-16 15:35:12 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpvrawpay.c:
+	* gst/rtp/gstrtpvrawpay.h:
+	  rtpvrawpay: make chunks per frame configurable
+	  Bit of a misnomer because it's really chunks per field
+	  and not per frame, but we're going to ignore that for
+	  the time being.
+
+2014-06-16 14:52:16 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpvrawpay.c:
+	* gst/rtp/gstrtpvrawpay.h:
+	  rtpvrawpay: remove unused variables
+
+2014-06-16 14:44:27 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpvrawpay.c:
+	  rtpvrawpay: pre-allocate buffer lists of sufficient size
+	  Avoids unnecessary reallocs when appending buffers
+	  to the bufferlist.
+
+2014-06-16 13:51:03 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpvrawpay.c:
+	  rtpvrawpay: micro-optimise variable access in inner loop
+	  Store some values that don't change during the execution
+	  of the inner loops locally, so the compiler knows that too.
+
+2014-06-16 13:38:47 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtpvrawpay.c:
+	  rtpvrawpay: use buffer lists
+	  Collect buffers to send out in buffer lists instead of
+	  pushing out single buffers one at a time. For HD video
+	  each frame might easily add up to a couple of thousand
+	  packets, multiply that by the frame rate and that's a
+	  lot of push() and sendmsg() calls per second.
+	  A good reason to push out buffers as early as possible is
+	  latency, so we don't accumulate the whole frame in a single
+	  buffer list, but instead push it out in a few chunks, which
+	  is hopefully a reasonable compromise.
+
+2014-06-16 16:40:07 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	  udp: improve element descriptions for dynudpsink and multiudpsink
+
+2014-06-16 16:17:16 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	  udp: remove suppression of compiler warnings for deprecated GLib API
+	  Not needed any more.
+
+2014-06-17 13:16:27 +0530  Ravi Kiran K N <ravi.kiran@samsung.com>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Fix caps negotiation issue
+	  Make sure that if AYUV is received it will detect that it can produce
+	  both RGB and YUV formats
+	  Signed-off-by: Ravi Kiran K N <ravi.kiran@samsung.com>
+	  https://bugzilla.gnome.org/show_bug.cgi?id=725248
+
+2014-06-16 12:02:41 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	  rtptheoradepay: fix double frees
+	  Fix double-frees introduced to fix another coverity report.
+	  CID 1223053
+
+2014-06-13 10:12:07 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstdynudpsink.c:
+	  dynudpsink: return FLUSHING when sendto got canceled, not an error
+
+2014-06-13 09:52:03 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* sys/oss/gstosshelper.c:
+	  oss: simplify probed caps before returning them
+	  Exposes all formats in the first structure if the
+	  rest is the same for all of them.
+
+2014-06-13 09:45:28 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* sys/oss/gstosshelper.c:
+	  oss: make sure 16-bit formats are before 8-bit formats in probed caps
+	  Probe supported formats in order of desirability rather than in
+	  what order they may happen to be in the formats bitmask. Fixes
+	  accidentally exposure of 8-bit formats in caps before 16-bit formats
+	  (in case where U16 was not supported S8 might be listed before S16).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=706884
+
+2014-06-12 16:36:24 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Cleanly handle v4l2_allocator_new failure
+
+2014-06-12 11:24:15 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	  rtptheordepay: fix leaks
+	  Coverity 1212163
+
+2014-06-12 11:16:08 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtpg729pay.c:
+	  rtpg729pay: leak fixes
+	  Coverity 1212159
+
+2014-06-12 11:11:38 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: fix leak
+	  Coverity 1212157
+
+2014-06-12 10:43:53 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: fix leaks
+	  Coverity 1212149
+
+2014-06-12 10:31:47 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtpdvpay.c:
+	  rtpdvpay: catch failures to map buffer
+	  Coverity 1139741
+
+2014-06-11 17:43:42 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/multipart/multipartdemux.c:
+	  multipartdemux: guard against having no MIME type
+	  The code would previously crash trying to insert a NULL string
+	  into a hash table.
+	  It does seem a little broken that indexing is done by MIME type
+	  and not by index though, unless the spec says there cannot be
+	  two parts with the same MIME type.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=659573
+
+2014-06-10 15:42:14 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartdemux.h:
+	  multipartdemux: Send stream-start event
+	  This event was not sent. Send it before caps, this requires the pad to
+	  be parented. This removes warning like: "Got data flow before
+	  stream-start event".
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=731475
+
+2014-06-10 15:33:33 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: avoid looping indefinitely in broken svq3 files
+	  Abort if an atom with size 0 is read from within the svq3 stsd
+	  atoms
+	  https://bugzilla.gnome.org/show_bug.cgi?id=726512
+
+2014-06-10 10:52:23 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: add const where appropriate
+
+2014-06-09 10:39:20 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/speex/gstspeexenc.c:
+	  speexenc: add missing va_end in variadic function
+	  Coverity 1139944
+
+2014-06-09 10:04:38 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Attempt upstream seek first
+	  If we have an upstream element that can handle the seek (such as
+	  rtmpsrc), try to do that first before attempting it ourself.
+
+2014-06-04 11:34:27 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: do not include codec_data on raw audio caps
+	  If the wav header contains an extended chunk, we want to keep
+	  the codec_data field, but not for raw audio.
+	  This fixes some elements (such as adder) from failing to intersect
+	  raw audio caps which would otherwise be intersectable.
+
+2014-06-05 09:38:29 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Query duration upstream first
+	  Upstream elements (like rtmpsrc) might be able to provide the duration
+	  more accurately than flvdemux. Especially with index-less vod files
+
+2014-05-30 19:37:57 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Cleanup poll method and retry on EINTR/EAGAIN
+	  https://bugzilla.gnome.org/show_bug.cgi?id=731015
+
+2014-03-06 16:37:51 +0100  Jan Alexander Steffens (heftig) <jan.steffens@gmail.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: set RESYNC buffer flag when bridging large PTS gaps
+	  So downstream gets notified when this happens.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=725903
+
+2014-06-03 17:59:32 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* tests/check/elements/rtprtx.c:
+	  rtprtx: Reset state on each iteration
+	  Otherwise it didn't wait for the test to finish before checking the results.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=728501
+
+2014-05-09 14:22:42 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: don't leak doctype string in error code path
+	  CID 1212145.
+
+2014-05-20 08:20:42 +0200  Edward Hervey <edward@collabora.com>
+
+	* ext/vpx/gstvp9enc.c:
+	  vp9enc: Don't dereference NULL checks
+	  CID #1197703
+
+2014-05-20 08:23:06 +0200  Edward Hervey <edward@collabora.com>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: Don't dereference NULL variable
+	  CID #1139838
+
+2014-05-30 14:32:42 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: upstream handles seek if fragmented and on time segment
+	  Otherwise we can reject seeks on local files that contain fragmented-like
+	  atoms like 'mvex'. Also improve a message log
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730722
+
+2014-05-30 16:43:44 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  h264depay: make sure we call handle_nal for each NAL
+	  Call handle_nal for each NAL in the STAP-A RTP packet. This makes
+	  sure we correctly extract the SPS and PPS.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=730999
+
+2014-05-07 14:09:06 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: Add custom sticky event to contain the HTTP request and response headers
+	  This can be useful to e.g. get cookie information downstream.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=729707
+
+2014-05-26 19:47:39 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: remove stream last flow return
+	  GstPad already stores that information
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709224
+
+2014-05-26 19:37:46 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: remove last flow return from stream struct
+	  It is already stored on GstPad on core
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709224
+
+2014-05-26 19:19:45 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	  flvdemux: Use GstFlowCombiner
+	  Use the flow combiner to have the standard combination results and avoid
+	  repeating the same code
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709224
+
+2014-05-26 13:21:25 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: use GstFlowCombiner
+	  Use the flow combiner to have the standard combination results and avoid
+	  repeating the same code
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709224
+
+2014-05-26 13:04:10 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: use GstFlowCombiner
+	  Removes flow return combination code to use the newly added GstFlowCombiner
+
+2014-05-23 17:53:00 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: use GstFlowCombiner
+	  Removes the common code to combining flow returns to let it be
+	  handled by core gstutils' GstFlowCombiner
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709224
+
+2014-05-26 10:59:55 -0400  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: implement gstvideosink.show_frame instead of gstbasesink.render
+	  It allows to show preroll frame. Especially it allows to update the
+	  frame when seeking in PAUSED state.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722303
+
+2014-05-26 10:59:06 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: Cleanup old pad alloc declaration
+
+2014-05-26 12:34:42 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2bufferpool: Copy already queued buffer
+	  This is required as during preroll we pass the first buffer twice, hence already
+	  queued. It is also useful, to allow filters replaying a previous rendered buffers.
+	  This will require 1 more buffer in sink if last-sample is enabled, since the last
+	  sample will not be the same as the currently queued buffer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722303
+
+2014-05-24 20:20:07 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2transform.c:
+	* sys/v4l2/gstv4l2videodec.c:
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2bufferpool: Port to bufferpool flush_start/stop method
+	  Port the buffer pool to use the new flush_start/flush_stop virtual
+	  methods added to GstBufferPool.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727611
+
+2014-05-25 17:40:58 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: update
+
+2014-05-25 16:54:18 +0200  Piotr Drąg <piotrdrag@gmail.com>
+
+	* po/POTFILES.in:
+	  po: update POTFILES
+	  https://bugzilla.gnome.org/show_bug.cgi?id=726556
+
+2014-05-24 23:51:58 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Don't queue all the buffers before dequeueing first
+	  For output device, we where queuing all the buffers, and then we would
+	  dequeue one. This means we only have 1 buffer for the pipeline, no matter
+	  the size of the queue. Instead, start dequeued when min_latency is reached.
+	  Eventually, this the min_latency should also be affected by control
+	  MIN_BUFFERS_FOR_OUTPUT (use by encoders).
+
+2014-05-24 23:49:19 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Simply read back the config to update the query
+	  It's easy to get the min/max outdate when hacking decide allocation. In
+	  order to avoid this, simply read back the choosen value from the config.
+
+2014-05-24 23:31:24 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: Cleanup and fix calculation of latency
+	  Calculation of num_buffers (the max latency in buffers) was
+	  up-side-down.  If we can allcoate, then our maximum latency match
+	  pool maximum number of buffers. Also renamed it to max latency. Finally
+	  introduced a min_latency for clarity.
+
+2014-05-24 20:00:14 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2transform.c:
+	* sys/v4l2/gstv4l2videodec.c:
+	* sys/v4l2/v4l2_calls.c:
+	  Revert "v4l2bufferpool: Port to bufferpool flush_start/stop method"
+	  This reverts commit 2e0fb42e868fc9f6d98b028def80a3e953527307.
+	  Conflicts:
+	  sys/v4l2/gstv4l2allocator.c
+	  sys/v4l2/gstv4l2bufferpool.c
+	  sys/v4l2/gstv4l2videodec.c
+
+2014-05-24 18:56:32 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Fix configuration of other_pool and importation case
+	  Fix the choice of min/max, don't override the min/max with own pool selected
+	  size, correct other_pool is_active check, start from other_pool config when
+	  configuring the other pool and finally validate the configuration.
+
+2014-05-24 18:45:30 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Use proposed allocator as default
+
+2014-05-24 18:43:28 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Fix USERPTR map flags
+	  We need to map READ only for output and write only for capture, we where
+	  doing the opposite. This fixing USERPTR with glimagesink
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730698
+
+2014-05-24 11:16:35 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: parse tkhd transformation matrix and add tags if appropriate
+	  Handle the transformation matrix cases where there are only simple rotations
+	  (90, 180 or 270 degrees) and use a tag for those cases. This is a common scenario
+	  when recording with mobile devices
+	  https://bugzilla.gnome.org/show_bug.cgi?id=679522
+
+2014-05-23 19:10:21 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Prevent num_queued from going negative
+
+2014-05-23 18:25:49 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: don't stop if loop returned FLUSHING
+	  The decodeing thread returning flushing isn't an error, we should simply
+	  try starting the task again. If it's actually flushing, it will stop again by itself.
+
+2014-05-23 17:54:20 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Handle early task stop
+
+2014-05-23 17:28:13 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Handle gst_pad_start_task() failure
+
+2014-05-23 17:19:07 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Add trace for FLUSH_START/STOP handling
+
+2014-05-23 17:18:16 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Fix use of atomic value
+
+2014-05-23 17:01:53 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Improve debugging
+	  No need to use obj->element, the pool now have a significant name. Also don't
+	  warn if flushing.
+
+2014-05-23 17:01:02 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Fix handle_frame error handling
+
+2014-05-23 15:56:24 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Add a trace when _start() is called
+
+2014-05-23 15:56:02 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Add debug assert to detect calls in the wrong state
+
+2014-05-23 15:55:26 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Reset count when stopped
+
+2014-05-23 15:55:08 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2allocator: Return a GstFlowReturn instead of boolean in alloc
+
+2014-05-23 15:17:27 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't leak config structure
+
+2014-05-23 14:12:10 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2transform.c:
+	* sys/v4l2/gstv4l2videodec.c:
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2bufferpool: Port to bufferpool flush_start/stop method
+
+2014-05-23 03:00:50 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: add tag mappings for _swr, _mak and _mod tags
+	  swr -> Application name
+	  mak -> device manufacturer
+	  mod -> device model
+
+2014-05-20 17:37:49 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximagesrc: Fix ximage leaks when buffer has more then one ximage
+	  From time to time, when the image_pool list has more then 1 element
+	  and I suppose at start, all but 1 pooled ximage are leaked. This is
+	  due to broken algorithm in gst_ximagesink_src_ximage_get(). There was
+	  also a risk of use after free for the case where the ximage size has
+	  changed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=728502
+
+2014-05-21 13:23:27 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.3.2 ===
+
+2014-05-21 13:06:35 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* common:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect-build.stamp:
+	* docs/plugins/inspect.stamp:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.3.2
+
+2014-05-21 12:19:39 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2014-05-21 10:51:10 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From 211fa5f to 1f5d3c3
+
+2014-05-20 08:23:06 +0200  Edward Hervey <edward@collabora.com>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: Don't dereference NULL variable
+	  CID #1139838
+
+2014-05-20 08:20:42 +0200  Edward Hervey <edward@collabora.com>
+
+	* ext/vpx/gstvp9enc.c:
+	  vp9enc: Don't dereference NULL checks
+	  CID #1197703
+
+2014-05-19 11:26:46 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Explicitly cast enum "subtype" to its "supertype"
+	  gstv4l2bufferpool.c:608:18: error: implicit conversion from enumeration type
+	  'enum _GstV4l2BufferPoolAcquireFlags' to different enumeration type
+	  'GstBufferPoolAcquireFlags' [-Werror,-Wenum-conversion]
+	  params.flags = GST_V4L2_POOL_ACQUIRE_FLAG_RESURECT;
+	  ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+2014-05-19 11:24:06 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/goom/tentacle3d.c:
+	  goom: Use fabs() instead of abs() to calculate the floating point absolute value
+	  tentacle3d.c:268:7: error: using integer absolute value function 'abs' when
+	  argument is of floating point type [-Werror,-Wabsolute-value]
+	  if (abs (tmp - fx_data->rot) > abs (tmp - (fx_data->rot + 2.0 * G_PI))) {
+	  ^
+
+2014-05-19 11:21:36 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/debugutils/tests.c:
+	  debugutils: Properly calculate the difference with unsigned types
+	  tests.c:161:16: error: taking the absolute value of unsigned type
+	  'unsigned long' has no effect [-Werror,-Wabsolute-value]
+	  t->diff += labs (GST_BUFFER_TIMESTAMP (buffer) - t->expected);
+
+2014-05-16 17:46:30 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Handle flush while in start_streaming
+	  We need to handle the case where a flush occure while the streaming
+	  thread is being brought up. In this case, the flushing state of the poll
+	  object is cleared. To solve this, we simply set the capture poll to flushing
+	  again, this way we know the thread will exit. The decoder streamlock
+	  is used to synchronize with handle frame.
+
+2014-05-16 16:44:37 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Don't trace twice the same message
+
+2014-05-15 11:25:50 -0700  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: always use a random ssrc for the internal session
+	  Use a random SSRC different than 0 for the internal session SSRC.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730212
+
+2014-05-16 16:52:25 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: update last_activity when sending RTP
+	  Also update last_activity when doing something with the internal
+	  source to make sure don't timeout early.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=730217
+
+2014-05-15 18:08:53 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2transform.c:
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2: Cleanup M2M properties
+	  M2M devices were sharing the same properties as src and sink. Most of
+	  these made no sense. This patch reduces the number of propeties and
+	  makes io-mode clearer by having capture-io-mode and output-io-mode. This
+	  also accidently fixed a bug in gstv4l2transform io-mode code, where the
+	  capture io-mode could not be set.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=729591
+
+2014-05-15 17:39:39 +0200  Benjamin Gaignard <benjamin.gaignard@linaro.org>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Update pool limit with hardware requiremenst
+	  If the driver need more buffers than requested by the config,
+	  update the pool min/max values. The minimum value for the pool
+	  could be provided either by the driver or by the pool. This is
+	  best effort for drivers that don't support
+	  CID V4L2_CID_MIN_BUFFERS_FOR_CAPTURE.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730200
+
+2014-05-15 10:44:29 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Handle start_streaming error
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730207
+
+2014-05-15 10:39:40 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Print the flow return causing the loop to leave
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730207
+
+2014-05-15 10:31:40 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Don't lock the decoder when stopping task
+	  That src pad task may need to take the lock when being pulled
+	  down. takeing that lock can lead to a deadlock.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730207
+
+2014-05-14 17:18:52 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Don't leak pool if activation failed
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730207
+
+2014-05-14 17:18:35 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2transform.c:
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2: Split flush in start/stop_streaming
+	  This allow calling start streaming later for capture device. Currently it breaks
+	  in dmabuf-import because downstream is holding a buffer that will only be
+	  released after stream-start.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730207
+
+2014-05-14 15:12:26 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Flush buffer pools on flush stop
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730207
+
+2014-05-14 13:28:31 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Fix use of atomic active marker
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730207
+
+2014-05-14 13:05:42 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Don't deactivate otherpool
+	  We should not stop the otherpool unless we also stop our own
+	  pool, otherwise it will never get restarted.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730207
+
+2014-05-14 12:33:58 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Also update num_buffers for import cases
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730207
+
+2014-05-14 13:42:25 -0700  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: update rtp encoder/decoder docs
+	  Use %u in RTP encoder/decoder pads to match other rtpbin pads.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=730146
+
+2013-12-27 11:55:18 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/check/elements/rtpsession.c:
+	  tests/check: rtpsession: test internal sources timing out
+
+2013-12-26 17:30:42 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: remove unused if branch
+	  1) sources that have sent BYE in the past cannot be senders, since
+	  they would have timed out to being receivers in the meantime...
+	  2) sources that have sent BYE are now being removed earlier inside
+	  this function
+
+2013-12-26 17:29:42 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: cleanup sources that have sent BYE
+
+2013-12-26 17:24:51 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: unify nested if clauses
+
+2013-12-26 17:21:44 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: timeout internal sources that are inactive for a long time and send BYE
+
+2014-05-13 12:25:04 -0700  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: don't stop looping if event found in the queue
+	  If we are inserting a packet into the jitter queue we need to keep
+	  looping through the items until the right position is found. Currently,
+	  the code stops as soon as an event is found in the queue.
+	  Regarding events, we should only move packets before an event if there
+	  is another packet before the event that has a larger seqnum.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=730078
+
+2014-04-17 13:04:00 +0000  Adrien SCH <adrien.schwartzentruber@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: fix the memory leak of language attribute
+	  https://bugzilla.gnome.org/show_bug.cgi?id=728418
+
+2014-05-13 13:44:20 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Fix regression in offset extrapolation
+	  When extrapolating the offset, we need to use the extrapolate
+	  stride rather then the base stride. This should fix support for format
+	  with more then two planes (I420, Y42B, etc).
+
+2014-05-12 18:03:18 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2bufferpool: Use default VideoInfo for frame operation
+	  When doing frame operation, we need to use the default VideoInfo
+	  and let the frame API read the video meta in order to get the stride
+	  and offset right. Currently we where using the specialized VideoInfo
+	  which reflects what the HW is setup to.
+
+2014-05-12 17:23:19 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2src: minor GValue handling optimisation in probing code
+
+2014-05-12 17:20:14 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2src: avoid lists with one single framerate in probed caps
+	  Simplify framerate field if possible, so we don't end up with
+	  e.g. framerate = (fraction) { 30/1 }. Maybe the helper function
+	  should be moved to core, but we can do this later.
+
+2014-05-12 16:56:35 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix leak of palette_data in error cases
+	  CID #1212151
+
+2014-05-12 16:53:32 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Free node_header in error cases
+	  CID #1212134
+
+2014-05-12 13:46:01 +0200  Edward Hervey <edward@collabora.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Don't use WARNING for not-linked flow return
+	  Pollutes debug logs for no reason. It's only an error if all pads
+	  return not-linked
+
+2014-05-12 13:45:06 +0200  Edward Hervey <edward@collabora.com>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	  flvdemux: Skip unknown tags in push-mode
+	  We add a new mode (SKIP) in push-mode to skip tags that we don't known about
+	  Partially fixes https://bugzilla.gnome.org/show_bug.cgi?id=670712
+
+2014-05-10 09:14:33 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: Add support for variable block size files and remove dead code
+	  This dead code wasn't used since the 1.0 port and would need to
+	  be modified heavily for variable block size support.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=729894
+
+2014-05-09 12:14:23 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Fix NULL check copy paste error
+	  CID 1212129
+
+2014-05-09 12:11:54 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Fix potential deadlock due to missing break
+	  CID 1212131
+
+2014-05-09 18:01:28 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: increment accepted packets after loss
+	  When we detect a lost packet, expect packets with higher
+	  seqnum on the input.
+	  Also update the unit test.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=729524
+
+2014-05-04 11:12:54 -0600  Jason Litzinger <jlitzingerdev@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  Add new test case.
+
+2014-05-09 16:14:21 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* tests/check/elements/shapewipe.c:
+	  shapewipe: no need to activate pads
+	  Activation will happen in the state change
+
+2014-05-09 12:10:04 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't leak config structure
+	  this fixes a leak of the config structure and take care of making sure
+	  caps can't reach ref 0 before we are done doing our check.
+	  CID 1212144
+
+2014-05-09 12:08:11 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Remove uneeded cast for code clarity
+
+2014-05-09 11:56:52 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2pool: Fix leak of config structure in error case
+	  CIDs 1212167 and  1212167
+
+2014-05-09 11:51:26 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Fix use of unitilized pool pointer
+	  CID #1212173
+
+2014-05-09 16:48:58 +0200  Eric Trousset <etrousset@awox.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: don't respond to a position query in BYTE format with a TIME position
+	  https://bugzilla.gnome.org/show_bug.cgi?id=729553
+
+2014-05-09 14:22:42 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: don't leak doctype string in error code path
+	  CID 1212145.
+
+2014-05-06 13:37:47 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Readback pool config if used within the baseclass
+
+2014-05-06 12:58:59 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2transform.c:
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2: Replace miss-use of crop meta in favour of proper offset
+	  This moves away from copying information and store everything inside
+	  the GstVideoInfo structure. The alignement exposed by v4l2 api
+	  is now handled using proper offset.
+
+2014-05-06 12:55:30 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2object: Style fix
+
+2014-05-05 12:38:33 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Reset imported buffer size with expected size
+	  This ensure that the buffer pool won't always discard buffer with these
+	  memory when they are released.
+
+2014-05-05 12:37:43 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Reset flushed group
+	  This ensure that a flushed group memory are the same size as when they
+	  where originally allocated / imported.
+
+2014-05-05 12:07:31 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2bufferpool: Get number of allocated buffers from allocator
+	  The value of num_allocated buffer would get confused when
+	  buffer are being discarded.
+
+2014-05-05 12:06:44 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2allocator.h:
+	  v4l2allocator: Add a method to read number of allocated group
+
+2014-05-04 20:23:42 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Improve debugging
+
+2014-05-04 19:51:48 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2bufferpool: Ensure we don't re-enqueue buffer during flush
+
+2014-05-04 19:13:37 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Initilialize debug category
+
+2014-05-04 16:11:09 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Fix libv4l2 support
+	  Need to include config.h, otherwise we endup directly using the
+	  ioct/mmap/munmap calls and need to vall v4l2_munmap.
+
+2014-05-01 13:04:08 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Set the flags on the object
+	  We where not setting the probed flags on the allocator, which mean even if
+	  CREATE_BUFS was supported on some driver, it would endup being ignored.
+
+2014-04-29 16:49:52 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Re-enqueue buffer at stream start
+
+2014-04-29 16:06:00 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: There is not group on error
+
+2014-04-29 14:56:31 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Handle FLUSH_STOP event
+
+2014-04-29 13:05:41 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2bufferpool: Acquire cannot return a buffer from another pool
+	  Return a buffer from an otherpool has unwanted side effects that lead to leaks and
+	  prevents deactivating the pool. Instead, we change the _process() API so it can
+	  replace the internal buffer with the buffer from the downstream pool. This implied
+	  moving from _fill() to _create() method in the src.
+
+2014-04-29 13:00:32 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Remove unreached acquire code
+	  The acquire is done in _prepare now.
+
+2014-04-29 12:57:08 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Sanetize buffer refount handling
+	  Buffer refcounting is a bit hard, because of the duality between CAPTURE and
+	  OUTPUT mode. In the long term, we should consider having two seperate pool
+	  instead of this mess. At least state should be better kept this way.
+
+2014-04-29 12:48:04 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Add more traces
+
+2014-04-28 08:48:26 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2allocator.h:
+	  v4l2-allocator: Add S to REQBUFS/CREATE_BUFS enum
+	  All enum that has REQBUFS and CREATE_BUFS where missing S, which was
+	  confusing since they are supposed to match with associcated ioctl name. This
+	  also fixes the yet unused CAN_REQUEST flag check.
+
+2014-04-18 17:51:07 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Enabled QoS
+
+2014-04-18 17:02:50 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2allocator.h:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: Fixup USERPTR/DMABUF capture support
+
+2014-04-18 14:45:00 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Improve selecton of min/max in decide allocation
+
+2014-04-18 13:09:00 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Update config if meta is missing
+	  Rather then hard failure, we should update the config with the meta option we
+	  need and return false.
+
+2014-04-11 17:10:11 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2allocator.h:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2: Add DMABUF and USERPTR importation
+
+2014-04-17 21:45:58 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Valid FD are bigger or equal to zero
+
+2014-04-16 17:04:42 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't leak downstream pool in propose_allocation
+	  parse_nth_allocation_pool() give a ref on the pool, we need to unref it
+	  when done.
+
+2014-04-14 12:19:39 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2: Introduce DMABUF_IMPORT IO mode
+
+2014-04-10 16:26:34 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2allocator.h:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: Add dmabuf export support
+	  This can be enabled sing io-mode=dmabuf. This will enabled mmap base
+	  drivers to export the buffers as dmabuf.
+
+2014-04-16 15:51:03 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2allocator.c:
+	  v4l2allocator: Guaranty queued state integrety
+	  Because of the buf in videobuf2, dqbuf may leave the DONE flag being,
+	  which would implied that the buffer is queued. As this has been broken
+	  for 4 years, simply guaranty the state flags integrity when doing
+	  qbuf/dqbuf.
+	  See https://patchwork.linuxtv.org/patch/23641/
+
+2014-04-15 17:31:42 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Implement open/close
+
+2014-04-15 16:43:41 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Ensure output pool is configured
+
+2014-04-15 16:43:15 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	* sys/v4l2/gstv4l2transform.h:
+	  v4l2transform: Check if caps have changes before asserting
+	  In set_caps, now checks if caps actually changed and succeed if they didn't
+	  change.
+
+2014-04-15 16:41:46 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Ensure pool is configured
+
+2014-04-08 18:54:09 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Always set a size when deciding allocation
+
+2014-04-08 18:20:25 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Improved decide allocation
+	  Improve decide allocation so it properly configure both local and downstream
+	  buffer pools. Also read back the pool config if it was changed to to driver
+	  limitations.
+
+2014-04-15 13:30:02 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Do not pre-configure the pool
+	  Pre-configuring the pool is error prone, since it may hide a configuration failure and
+	  endup with a pool that is not configured the way it should (e.g. no video meta, wrong
+	  queue size, etc.)
+
+2014-04-15 13:23:33 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Preserve downstream minimum even in RW
+
+2014-04-15 13:20:12 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2bufferpool: Turn cropmeta into a custom option
+	  Turn crop meta into a custom option and make sure it's there is needed.
+
+2014-04-09 12:53:19 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2bufferpool: Early catch short allocation
+	  Catch short allocation after saving the format. This is not a catch all, but should catch
+	  most of the miss-behaving drivers when doing S_FMT/G_FMT and avoid potential crash.
+
+2014-04-04 22:46:40 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2bufferpool: Port to use GstV4l2Allocator
+
+2014-04-04 22:35:48 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2allocator.c:
+	* sys/v4l2/gstv4l2allocator.h:
+	* sys/v4l2/v4l2_calls.h:
+	  Implement V4l2 Allocator
+	  This goal of this allocator is mainly to allow tracking the memory.
+	  Currently, when a buffer memory has been modified, the buffer and it's
+	  memory is disposed and lost until the stream is restarted.
+
+2014-04-16 16:35:49 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't advertise crop meta
+	  Currently we advertise crop meta, but not element handle support this meta.
+
+2014-04-08 18:18:57 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Setup pool already send element error
+
+2014-04-08 18:17:31 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Workaround decoder that set num_planes to 0 in the format
+	  Some well known decoder wrongly set num_planes to 0 in their format instead of
+	  one. In this case we would endup with no size when deciding buffer allocation.
+
+2014-04-08 17:34:19 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Ensure size before configuring the pool
+
+2014-04-04 22:38:05 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2object: Set minimum buffers to 2
+	  All the element requires at least two buffers. This is not used for RW mode.
+
+2014-04-04 22:37:14 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2object: Remove unused MAX_BUFFERS define
+
+2014-04-04 22:36:37 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't hardcode min/max use default instead
+
+2014-04-10 17:49:41 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Install PROP_CAPTURE_IO_MODE with right ID
+
+2014-04-08 18:54:50 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: decide_allocation returns a boolean
+
+2014-04-10 17:49:29 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Install PROP_CAPTURE_IO_MODE with right ID
+
+2014-03-27 13:21:25 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Add propose_allocation
+	  This should remove 1 copy between the decoder and the transform.
+
+2014-03-27 13:20:53 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2: Move propose allocation to v4l2object
+
+2014-03-20 17:26:05 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Fixup caps query
+
+2014-03-20 15:31:22 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Setup cropping if needed
+
+2014-03-19 17:25:16 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2.c:
+	  v4l2transform: Expose BGRA and ARGB formats
+
+2014-03-18 17:33:38 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Ensure output pool is activated
+	  That pool may be different then the internal pool.
+
+2014-03-16 19:11:16 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Ensure internal buffer pools actication
+
+2014-03-16 11:36:19 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Move subinstance subclass init near other init
+
+2014-03-15 18:56:51 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: Stop stream before closing the devices.
+
+2014-03-15 16:53:54 +0000  Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
+
+	* sys/v4l2/gstv4l2transform.c:
+	  v4l2transform: copy metdata
+
+2014-03-04 18:31:27 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2transform.c:
+	* sys/v4l2/gstv4l2transform.h:
+	  Implement GstV4l2Transform
+	  Implement a v4l2 element that wraps HW video converters.
+
+2014-03-27 18:41:07 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2: Probe for CREATE_BUFS in order to correctly set pool min/max
+	  In order to correctly set the pool min/max, we need to probe for CREATE_BUFS
+	  ioctl. This can be done as soon as the format has been negotiated using a
+	  count of 0.
+
+2014-03-25 15:21:03 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2: Move capture eos handling in _process()
+	  Now that we might be copying out buffer (e.g. downstream don't support video
+	  meta bug we need it) we need to move the EOS handling inside the process
+	  method.
+
+2014-03-25 10:49:39 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Fix support for planar format in 1 v4l2 mplane
+	  So far we where only setting saving the first plane stride in the meta. This was
+	  leading to wrong values in GstVideoMeta.
+
+2014-03-19 17:52:08 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Cleanly fail if set_format is never called
+
+2014-03-19 17:00:56 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: Expose RGB32 formats with and without alpha
+	  As soon a the alpha component can be set, we can expose the RGB32 and BGR32
+	  format as ARGB and BGRA as long we can deterministically set the alpha padding
+	  value.
+
+2014-03-18 15:49:49 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Correctly check if video meta is needed
+	  Correctly check if video meta is needed. In buffer pool, trust need_video_meta
+	  flag in order to decide if configuration should succeed.
+
+2014-03-18 15:45:18 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Fix tiled stride request
+	  Fix stride request for tiled format and improve logging.
+
+2014-03-18 11:53:57 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Ensure video and crop meta are enabled if needed
+	  In certain cases we cannot live without video meta and/or crop meta
+	  being enabled in our internal buffer pool. Ensure this is always the case,
+	  regardless of having support for allocation query.
+
+2014-03-16 18:39:32 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Ensure internal pool are activated
+
+2014-03-16 17:01:10 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Check that pool where allocated before flushing them
+	  Upon error, the pools might not have been allocated yet, hence we should not
+	  try and flush them (even though we still want to make sure the processing thread
+	  is fully stopped).
+
+2014-03-16 16:55:43 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2bufferpool: Enforce activation outside of process
+	  Enforce pool being activate from before calling pool process. This should
+	  help catching basic errors in the usage of buffer pool.
+
+2014-03-16 12:44:14 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: don't use own pool if downstream don't support video meta
+
+2014-03-14 00:31:32 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Use obj->n_v4l2_planes for correct number of planes
+	  Buffer pool was guessing wrongly the number of planes rather
+	  then reading the value from obj->n_v4l2_planes. This was causing
+	  format YU12 (I420) to fail upon check.
+
+2014-03-07 16:39:29 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Fix handling of contiuous vs non-contiguous support
+	  The complex mechanic to try and choose the right thing did not work. Instead,
+	  simply probe the non-contiguous format first and then the contiguous one.
+	  This is in fact very low overhead, as there is a relatively small number of
+	  pixel format supported by each devices.
+
+2014-04-15 15:07:23 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2videodec.h:
+	  v4l2: Add initial support for alignment and cropping
+
+2014-03-13 19:24:51 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2object: Rename setup_format() method into acquire_format()
+	  The setup_format() was confusing since it does not set anything, in fact
+	  it reads the setup from the driver and save it.
+
+2014-03-13 18:21:41 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Move type declaration to the top
+
+2014-03-12 18:07:38 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Protect NULL pool while going to READY
+	  When the pipeline fails early, the pool might be unset before the processing
+	  thread has run once. Add protection against that.
+
+2014-03-12 18:01:09 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Fail cleanly if pixel format is unkown or not raw video
+	  Certain decoder has been found to not choose a format automatically. Running
+	  v4l2videodec on these would assert. This patch will make it fail cleanly
+	  instead.
+
+2014-03-12 17:56:18 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Clear the input state pointer after unref
+	  If caps are set again, we have a risk od returning from set_format with a
+	  input_state pointing to dead memory. Clearing the pointer after unref fix
+	  this issue.
+
+2014-03-12 17:11:16 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: handle stop being called without flush
+	  Uppon certain downstream error, stop() is called without a flush(). This mean that
+	  the streaming thread may still be running even though unlock has been called.
+	  Now calling flush to reset the decoder state if we are processing.
+
+2014-03-06 18:13:14 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Default to template in caps query
+
+2014-03-11 14:23:32 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Ensure processing thread has stopped when draining
+
+2014-03-11 14:01:27 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Don't drain if processing thread is inactive
+
+2014-05-08 09:49:24 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Clean up all pending operations from libsoup before unreffing our context
+	  When we cancel connection attempts and similar things, there are still
+	  some operations pending on our main context from the GCancellables. We
+	  should let them all run before unreffing our context, otherwise we leak
+	  file descriptors.
+	  Unfortunately this requires libsoup 2.47.0 or newer as earlier versions
+	  steal our main context from us and we can't use it for cleanup later
+	  without assertions and funny crashes.
+	  Based on a patch by Dmitry Shatrov <shatrov@gmail.com>.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=663944
+
+2014-05-07 15:49:39 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: fix compilation of souphttpsrc test for libsoup 2.40 for real
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727329
+
+2014-05-07 13:23:50 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: fix compilation of souphttpsrc test for libsoup 2.40
+	  SOUP_CHECK_VERSION was only added in 2.41, but we only
+	  depend on 2.40.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727329
+
+2014-05-07 00:58:15 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: skip PICTURE headers without any image data
+	  Fixes warning if the image length is 0.
+
+2014-05-06 09:22:18 +0000  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* configure.ac:
+	  configure: use X11 detection macro from common
+	  https://bugzilla.gnome.org/show_bug.cgi?id=729621
+
+2014-04-30 11:13:12 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* gst/rtp/README:
+	  rtp/README: update pipelines to work with 1.0
+	  - Use gst-libav encoders/decoders instead of gst-ffmpeg
+	  - gstrtpjitterbuffer -> rtpjitterbuffer
+	  - gst-launch-0.10 -> gst-launch-1.0
+	  - Add 'videoconvert' element
+	  - xvimagesink -> autovideosink
+	  https://bugzilla.gnome.org/show_bug.cgi?id=729247
+
+2014-05-05 14:41:05 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/ebml-write.c:
+	  matroska: rejig test to avoid undefined shift behavior
+	  Coverity 1195121, 1195120
+
+2014-05-05 14:33:38 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/vpx/gstvp9enc.c:
+	  vp9enc: do not dereference NULL pointer
+	  Coverity 1197703
+
+2014-05-05 14:32:06 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: ensure we don't dereference a NULL pointer
+	  while working out the codec ID.
+	  Coverity 1195148
+
+2014-05-05 12:07:25 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* sys/v4l2/gstv4l2.c:
+	  v4l2: minor fix for closing the fd
+	  The fd returned by open() could theoretically be 0 as well.
+	  Coverity CID 1211823.
+
+2014-05-04 20:23:29 -0400  Olivier Crête <olivier.crete@ocrete.ca>
+
+	* tests/check/elements/rtpaux.c:
+	* tests/check/elements/rtprtx.c:
+	  rtpaux/rtprtx: Make tests non-racy
+	  Fix the raciness by iterating on a condition instead of using the gmainloop.
+	  Don't use the EOS as the target, otherwise the retransmission of the last
+	  packets are lost. Also count the retranmissions requests that are dropped.
+	  Check the condition before blocking on the GCond
+	  https://bugzilla.gnome.org/show_bug.cgi?id=728501
+
+2014-05-04 22:32:54 -0400  Olivier Crête <olivier.crete@ocrete.ca>
+
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	* gst/rtpmanager/gstrtprtxreceive.h:
+	  rtprtxreceive: Wait until timeout to clear association requests
+	  If two streams request a retranmission for the same SSRC, ignore the second
+	  one if the first oen is less than one second old, otherwise time out the first
+	  one and ignore the second.
+
+2014-05-04 18:59:33 -0400  Olivier Crête <olivier.crete@ocrete.ca>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* tests/check/elements/rtpmux.c:
+	  rtpmux: Always let upstream chose the ssrc if it wishes
+
+2014-05-04 13:37:46 +0200  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: avoid stall by corrupted seqnum accounting
+
+2014-05-04 01:14:33 -0400  Olivier Crête <olivier.crete@ocrete.ca>
+
+	* ext/pulse/pulsedevicemonitor.c:
+	* ext/pulse/pulsedevicemonitor.h:
+	  pulsedevicemonitor: Index are per facility, not global
+	  So need to keep the type of device in the device object
+
+2014-05-04 01:13:24 -0400  Olivier Crête <olivier.crete@ocrete.ca>
+
+	* ext/pulse/pulsedevicemonitor.c:
+	  pulsedevicemonitor: pa_subscription_event_t are enums, not flags
+	  Coverity 1195132
+
+2014-05-02 22:42:54 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2devicemonitor.c:
+	  v4l2devicemonitor: Port to use GstV4l2Iterator
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727925
+
+2014-05-02 21:38:30 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2videodec.c:
+	* sys/v4l2/gstv4l2videodec.h:
+	  v4l2: Use single pass iterator for M2M probe
+	  Instead of having each M2M class do their own probing, use the
+	  GstV4l2Iterator and probe all devices in a single pass.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727925
+
+2014-05-02 16:55:05 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/v4l2-utils.c:
+	* sys/v4l2/v4l2-utils.h:
+	  v4l2: Add a common device enumerator
+	  This will allow removing code duplication (hence bugs duplication).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727925
+
+2014-03-16 11:38:07 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	* sys/v4l2/gstv4l2videodec.h:
+	  v4l2videodec: Simplify sub-instanciation mechanism
+	  Simplify sub-instanciation by defining an absract type and using subtype
+	  class and instance init callback. This also fixes a bug where the template
+	  pads get initialized too late.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727925
+
+2014-05-02 18:18:26 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2.c:
+	  v4l2: Cleanup plugin registration
+	  There is no plan to introduce special sources for jpeg, te v4l2src works fine
+	  for this.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727925
+
+2014-05-03 18:30:20 -0400  Olivier Crête <olivier.crete@ocrete.ca>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	* tests/check/elements/rtpcollision.c:
+	  rtpsession: Keep local conflicting addresses in the session
+	  As we now replace the local RTPSource on a conflict, it's no longer possible
+	  to keep local conflicts in the RTPSource, so they instead need to be kept
+	  in the RTPSession.
+	  Also fix the rtpcollision test to generate multiple collisions instead of
+	  one by change the address, as otherwise we detected that it was a single one.
+
+2014-05-03 20:48:30 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.3.1 ===
+
+2014-05-03 18:02:23 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* gst/audiofx/audiopanoramaorc-dist.c:
+	* gst/deinterlace/tvtime-dist.c:
+	* gst/videobox/gstvideoboxorc-dist.c:
+	* gst/videomixer/videomixerorc-dist.c:
+	* win32/common/config.h:
+	  Release 1.3.1
+
+2014-05-03 18:02:01 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2014-05-03 17:22:45 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/lv.po:
+	* po/nb.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sr.po:
+	* po/zh_CN.po:
+	  po: Update translations
+
+2014-05-03 11:43:21 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/shapewipe.c:
+	  shapewipe: Send initial events after setting the elements to PLAYING
+	  Otherwise we send them too early, and setting the elements to PLAYING
+	  afterwards will drop all the events again.
+
+2014-05-03 10:15:03 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From bcb1518 to 211fa5f
+
+2014-05-02 17:12:29 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Set segment position to the stop position of the buffer
+
+2014-05-02 17:10:18 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Properly report errors before stopping the srcpad task
+
+2014-05-02 17:02:02 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Error out if we have no caps yet
+
+2014-05-02 14:49:27 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: avoid dividing by a 0 blockalign
+	  This can be 0. In that case, do not try to cut off the last few
+	  bytes from the last buffer.
+	  Coverity 1146971
+
+2014-05-02 14:25:01 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: do not use uinitialized clut on error
+	  If we're missing part of the clut, do not try to use it. It seems
+	  very likely the break was meant to break out of the switch rather
+	  than from the loop.
+	  Coverity 1139878
+
+2014-05-02 14:18:08 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/flx/gstflxdec.c:
+	  flxdec: fix integer overflow
+	  Coverity 1139859
+
+2014-05-02 14:09:02 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtpqdmdepay.c:
+	  rtpqdmdepay: remove pointless check
+	  Besides, the pointer was dereferenced earlier anyway.
+	  Coverity 1139853
+
+2014-05-02 14:06:25 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: remove duplicate test
+	  item was dereference previously.
+	  While there, reorder some test for faster early out.
+	  Coverity 1139844
+
+2014-05-02 14:02:52 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: guard against NULL pointer dereference
+	  Coverity 1139838
+
+2014-05-02 13:59:07 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: fix theoretical integer overflow
+	  This code isn't actually used at the moment, unsure if I should
+	  just remove it or not...
+	  Coverity 1139811
+
+2014-05-02 13:33:02 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/ebml-write.c:
+	  matroska: blindly fix writing variable length negative values
+	  Spotted while fixing something else in the area.
+	  Nothing calls this with a negative value.
+
+2014-05-02 13:29:33 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/ebml-write.c:
+	  matroska: do not lose the top bits when writing a > 32 bit value
+	  Coverity 1139806
+
+2014-05-02 12:10:26 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: add missing break in switch
+	  Coverity 1139755
+
+2014-05-02 11:39:39 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-parse.c:
+	  matroska: do not try to call gst_pad_query_default on a NULL pad
+	  gst_matroska_parse_query can be called explicitely with a NULL pad.
+	  If we reach this point with a NULL pad, fail the query.
+	  Coverity 1139715
+
+2014-05-02 11:28:01 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-parse.c:
+	  matroska: do not return GST_FLOW_OK if we did not get a buffer
+	  Coverity 1139714 (which will likely come back in another guise,
+	  as the _read_init call can have a failing _map)
+
+2014-05-02 11:20:33 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/ebml-write.c:
+	  matroska: catch failure to map buffer
+	  Avoids dereferencing NULL.
+	  Coverity 1139712
+
+2014-05-02 10:52:44 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: refuse caps with invalid framerate
+	  Coverity 1139701
+
+2014-05-02 10:21:09 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: handle 0 size packets without dividing by 0
+	  Coverity 1139691
+
+2014-05-02 09:49:32 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: guard against invalid frame size to avoid division by 0
+	  Coverity 1139690
+
+2014-05-02 09:49:17 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: trivial typo fix
+
+2014-05-02 09:43:54 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	  speexdec: remove dead code
+	  fpp can never equal 0 here, or the loop would not execute at all.
+	  Zero fpp was possible before as the loop condition was allowing
+	  it specifically, but no more.
+	  Coverity 1139681
+
+2014-05-02 09:41:19 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/oss4/oss4-property-probe.c:
+	  oss4: remove dead mixer code
+	  This was partly removed in the port to 0.11. If still needed,
+	  it's still there in the history.
+	  Coverity 1139687
+
+2014-05-02 09:33:51 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/oss4/oss4-property-probe.c:
+	  oss4: fix a missing unlock and a return-only-when-assertions-enabled
+	  Spotted on the side while looking at another issue.
+
+2014-03-07 17:31:29 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Correctly map RGB32 format
+	  In v4l2 specification, RGB32 has the alpha, or pading, first, not last.
+	  See http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html .
+	  https://bugzilla.gnome.org/show_bug.cgi?id=540941
+
+2014-04-30 18:06:40 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: remove dead code
+	  For 8 bit width, we always have depth==gdepth==width==8.
+	  Coverity 1139678
+
+2014-04-30 17:48:53 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: remove dead code
+	  A stricer check is already done earlier, and integer overflows
+	  do not seem possible here.
+	  Coverity 1139675
+
+2014-04-30 14:50:44 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawpay.c:
+	  rtpvrawpay: guard against pathological "no space" condition
+	  Even if one woul hope one pixel can fit in a MTU, ensure we do not
+	  overwrite a buffer if this is not the case.
+	  Spotted while looking at Coverity 1208786
+
+2014-04-30 11:52:10 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	  rtpjpegdepay: sanity check for NULL qtable
+	  Can happen (at least in crafted stream)
+	  Coverity 1208778
+
+2014-04-30 01:08:41 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: pass on tags from upstream if there are any
+	  Don't just ignore upstream tags from e.g. an ID3 tag before
+	  the .wav data, pass them on downstream.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=729223
+
+2014-04-29 16:26:53 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: optimize timer update
+	  When we are not doing retransmission, we just need to find the current
+	  seqnum so we can stop when we found it.
+
+2014-04-29 16:21:44 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.h:
+	  rtpjitterbuffer: small optimizations
+	  Small optimizations where we can.
+	  Add some more debug.
+
+2014-04-29 16:16:17 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: signal when next_seqnum changed
+	  Signal the pushing thread when the next_seqnum changed and we might be
+	  able to push a buffer now.
+
+2014-04-29 16:12:29 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: only signal event when head changed
+	  After adding a buffer, only signal the pushing thread when the head
+	  buffer changed or else we cause a useless wakeup.
+
+2014-04-29 15:29:31 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  rtpjitterbuffer: rework packet insert
+	  Rework the packet queue so that the most common action (insert a packet
+	  at the tail of the queue) goes very fast.
+	  Report if a packet was inserted at the head instead of the tail so that
+	  we can know when to retry _pop or _peek.
+
+2014-04-28 14:41:10 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	  rtpvraw: use plane pointers when needed
+	  Pack/unpack planar formats to/from the first plane.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=729058
+
+2014-04-28 09:47:10 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: Remember if a redirect is permanent or not and store it in the query
+
+2014-04-27 21:57:31 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/goom/config_param.c:
+	  goom: Remove french comment saying to prefix functions
+	  All non-static function in this file are already prefixed with goom_.
+
+2014-04-28 00:20:47 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/goom/filters.c:
+	  goom: fix compilation on ios-arm7-10.9 and osx-x86_64
+	  uint is not a standard type, and the rest of the code uses
+	  Uint which is locally typedefed to unsigned int.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=729067
+
+2014-04-27 18:29:11 -0400  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/goom/filters.c:
+	  goom: fix undefined behaviour of left-shift
+	  Don't left-shift into the sign bit, the result is undefined and potentially
+	  an overflow could flip the sign.
+
+2014-04-26 20:51:36 -0400  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: check return from qt_demux_video_caps
+	  Now qtdemux_video_caps() can return NULL. We need to check this return before
+	  using it's value.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=728987
+
+2014-04-26 23:35:17 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/dv/gstdvdec.c:
+	* ext/dv/gstdvdemux.c:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/speex/gstspeexdec.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavisubtitle.c:
+	* gst/isomp4/gstqtmoovrecover.c:
+	* gst/isomp4/gstqtmux-doc.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/multifile/gstmultifilesink.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtsp/gstrtpdec.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/spectrum/gstspectrum.c:
+	* gst/udp/gstudpsrc.c:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/wavparse/gstwavparse.c:
+	* sys/osxaudio/gstosxaudiosink.c:
+	  docs: remove outdated and pointless 'Last reviewed' lines from docs
+	  They are very confusing for people, and more often than not
+	  also just not very accurate. Seeing 'last reviewed: 2005' in
+	  your docs is not very confidence-inspiring. Let's just remove
+	  those comments.
+
+2014-04-25 17:58:42 -0400  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: initialize caps pointer to null
+	  Make sure the caps pointer returns initialized when using it in
+	  qtdemux_parse_tree ().
+	  https://bugzilla.gnome.org/show_bug.cgi?id=728987
+
+2014-04-22 17:07:38 +1000  Jan Schmidt <jan@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Clear last_pt on flush-stop.
+	  Otherwise, we don't recheck the buffer caps for clock-rate
+	  properly on the next chain.
+
+2014-04-22 17:29:02 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Fix compiler warning
+	  gstdeinterlace.c: In function 'gst_deinterlace_output_frame':
+	  gstdeinterlace.c:1537:57: error: 'pattern.length' may be used uninitialized in this function [-Werror=maybe-uninitialized]
+	  This actually is always initialized before it is used there, but
+	  let's just silence gcc here.
+
+2014-04-21 15:58:45 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: fix buffer list drop check
+	  While porting to 0.11, the check was mistakenly made constant,
+	  instead of testing for the return value of process_buffer_locked.
+	  Coverity 1139663
+
+2014-04-21 13:44:15 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroska: fix content encoding scope validity check
+	  It's 3 bits, and http://matroska.org/technical/specs/index.html
+	  says it can't be 0.
+	  Coverity 1139660
+
+2014-04-21 13:34:37 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: fix PAR fraction sanity check
+	  It was checking par_num twice, and never par_denum.
+	  Coverity 1139634
+
+2014-04-21 13:32:40 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiidpsink: warn when setsockopt fails
+	  This doesn't seem to be fatal, but it's good to let the user know
+	  in the logs.
+	  Coverity 1139630
+
+2014-04-21 13:27:24 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/interleave/deinterleave.c:
+	  interlace: catch failure to create audio info from caps
+	  Coverity 1139627, 1139628
+
+2014-03-13 09:37:48 +0100  Göran Jönsson <goranjn@axis.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  gstrtph264pay: Reset sps pps variable when state change.
+	  Reset last_spspps and sps/pps arrays  when state transition
+	  GST_STATE_CHANGE_PAUSED_TO_READY.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726015
+
+2014-04-18 11:11:14 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  jitterbuffer: improve EOS handling
+	  Make a new method to disable the jitterbuffer buffering.
+	  Rework the update_estimated_eos() method. Calculate how much time
+	  there is left to play. If we have less than the delay of the
+	  jitterbuffer, we disabled buffering because we might never be able to
+	  fill the complete jitterbuffer again.
+	  If we receive an EOS event, disable buffering. We will drain the
+	  buffer and eventually push the EOS event out.
+	  When we reach the estimated NPT timeout and we didn't receive an EOS
+	  event, make one and queue it so that it can be pushed.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=728017
+
+2014-04-18 10:21:27 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: send reconfigure when internal-ssrc changes
+	  When the internal-ssrc property changes, we want to send a reconfigure
+	  upstream to make payloaders use the new suggested ssrc.
+	  Using the internal-ssrc property to change the SSRC of a stream is not a
+	  good idea and doesn't work when there are multiple senders, we want to
+	  set the SSRC directly on the payloaders. Therefore, deprecate this
+	  property.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=725361
+
+2014-04-18 04:23:26 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: assume a full buffer when eos
+	  Rework the logic to make buffering messages a little, make sure we
+	  don't make the same message multiple times.
+	  Consider the buffer full when EOS was received.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=728017
+
+2014-04-17 18:07:09 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/rtprtx.c:
+	  rtprtx: Don't forget to unmap rtp buffer in the test
+
+2014-04-17 17:58:58 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: Require clock-rate in the caps and handle no ssrc in the caps properly
+
+2014-04-17 17:43:12 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/rtprtx.c:
+	  rtprtx: Provide an ssrc in the test
+	  And increase timeout to allow all tests to run in valgrind.
+
+2014-04-17 17:33:46 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/rtpsession.c:
+	  rtpsession: Fix memory leaks in test
+
+2014-04-17 17:26:36 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Fix hundreds of memory leaks in the test
+
+2014-04-17 17:00:37 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Unref clock id when waiting for the clock is interrupted
+
+2014-04-17 16:39:59 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/rtpcollision.c:
+	  rtpcollision: Fix memory leaks in unit test
+
+2014-04-16 21:40:45 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: name collectpads object based on videomixer name
+	  Makes it easier to track things in debug logs when there
+	  are multiple mixers and muxers.
+
+2014-04-16 21:37:12 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: better logging of incoming events
+	  The pad and parent names are already logged as part of logging
+	  the object. Instead log the full event details.
+
+2014-04-16 19:03:47 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/videomixer.c:
+	  videomixer: Fix memory leak in unit test
+
+2014-04-16 18:49:43 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/level/gstlevel.c:
+	  level: Use the correct number of samples to iterate over the input array
+	  Fixes invalid memory accesses and accesses to uninitialised data.
+
+2014-04-16 18:00:49 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/icydemux/gsticydemux.c:
+	  icydemux: Unref dropped events
+
+2014-04-16 17:29:30 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/ebml-read.c:
+	  matroska: fix check for amount of data to read
+	  History shows length==0 should set data to NULL and return,
+	  so we do that too instead of trying to read nothing.
+	  Coverity 206205
+
+2014-04-16 17:25:44 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: fix sign comparison
+	  history_count is unsigned, so the whole comparison will be made
+	  as unsigned, and fail to reject what it was meant to.
+	  Coverity 206204
+
+2014-04-16 17:04:50 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: remove dead code
+	  sub may not be NULL in this switch, there is a bail out just
+	  before it if so.
+	  Coverity 206098
+
+2014-04-16 16:59:43 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: remove dead code
+	  The block_size == 0 was shortcut earlier, and the variable is not
+	  modified in the meantime.
+	  Coverity 206097
+
+2014-04-16 16:56:54 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/videomixer/videoconvert.c:
+	  videomixer: remove dead code
+	  While it seems to keep a compile time selection, I traced it
+	  to some code copied from videoconvert, where it was removed,
+	  with the following comment:
+	  Also remove the high-quality I420 to BGRA fast-path as it needs
+	  the same fix, which causes an additional instruction, which causes
+	  orc to emit more than 96 variables, which then just crashes.
+	  This can only be fixed in orc by breaking ABI and allowing more
+	  variables.
+	  Thus, I remove it here as well.
+	  Coverity 206064
+
+2014-04-16 16:50:30 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  isomp4: fix incorrect masking for multiple tags
+	  Coverity 206058
+
+2014-04-16 16:45:08 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/atoms.c:
+	  isomp4: fix wrong atom flags set when adding samples
+	  Coverity 206057
+
+2014-04-16 16:40:02 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	  audiofx: fix comparison of delta time to a threshold
+	  Coverity 206055
+
+2014-04-16 16:32:26 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: do not rely on call failure keeping return data unmodified
+	  This is clearer this way too.
+	  Coverity 206029
+
+2014-04-16 16:28:49 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/atomsrecovery.c:
+	  isomp4: catch fseek error
+	  Coverity 206028
+
+2014-04-16 16:25:44 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/atoms.c:
+	  isomp4: report failures to caller
+	  Coverity 206027
+
+2014-04-16 18:05:46 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: refuse serialied query when buffering
+	  When we are buffering, we can't block and wait for the serialized query
+	  to complete because the jitterbuffer will not try to forward the query
+	  while buffering. Instead, just refuse the query.
+
+2014-04-16 16:51:15 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: don't free the serialized query
+	  We should never free a serialized query in the queue, it is the upstream
+	  caller that will free it.
+
+2014-04-16 17:35:42 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/aacparse.c:
+	  aacparse: Fix memory leak in the test
+
+2014-04-16 17:33:46 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Create hashtable only when we actually use it
+	  In error cases we previously returned without freeing it.
+
+2014-04-16 17:30:59 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Chain up to the parent class' dispose function
+
+2014-04-16 17:23:27 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Initialise ioctl struct with zeroes before passing it to ioctl()
+
+2014-04-16 13:47:43 +0200  Marc Leeman <marc.leeman@gmail.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: correct LOG msg for -1
+	  Signed-off-by: Marc Leeman <marc.leeman@gmail.com>
+
+2014-04-15 21:36:30 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/interleave/interleave.c:
+	  interleave: Fix negotiation to work at all again
+	  The caps query handling function for the sinkpads was called for
+	  the srcpad, and the sinkpads had none. This commit moves it to the
+	  right pad, but nonetheless the negotiation still looks wrong.
+	  This makes the test pass again after the recent coverity fix
+	  and also allows interleave to work again, but someone should
+	  really review the negotiation code and fix it.
+
+2014-04-13 09:03:41 +0200  Edward Hervey <edward@collabora.com>
+
+	* sys/oss4/oss4-audio.c:
+	  oss4: Maximum number of channels support is 8
+	  Avoids doing potential overwrites in ch_layout (which only has 8
+	  fields).
+	  CID #1139826
+
+2014-04-12 22:16:37 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: Set rank to MARGINAL
+	  If available we prefer using glimagesink over osxvideosink. It supports
+	  more formats and in general has more features than osxvideosink.
+
+2014-04-11 18:19:49 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: only guess AU boundaries when aren't indicated by marker
+	  The marker bit isn't mandatory and we had in place code to guess AU
+	  boundaries by detecting a new picture start. This guessing code
+	  didn't work with interlaced content that has proper marker bits
+	  to indicate the AU boundaries. It was leaking the first field buffer
+	  and producing a corrupted output.
+	  fixes: https://bugzilla.gnome.org/show_bug.cgi?id=728041
+
+2014-04-10 10:38:19 -0300  Rafał Mużyło <galtgendo@o2.pl>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: enable libpng interlaced picture handling
+	  Makes libpng deinterlace Adam7 interlaced pictures
+	  by default. It is the only interlaced format available
+	  and if the picture isn't interlaced the code should behave
+	  as before.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=726161
+
+2014-04-11 13:27:42 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Only keep-alive the connection in stop() if we have finished all previous messages
+	  After cancelling a request we need to create a new connection.
+
+2014-04-11 11:54:12 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/dv/gstdvdec.c:
+	  dvdec: Don't set bogus timestamp/duration
+	  This will happen if we have an incoming stream with a non-TIME segment
+	  Could be improved later to figure out proper pts/duration.
+	  CID #1199702
+	  CID #1199703
+
+2014-04-11 11:53:42 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/dv/gstdvdec.c:
+	  dvdec: Properly refuse incoming stream without framerate
+	  The return value wasn't properly propagated back if the caps
+	  didn't contain a framerate
+
+2014-04-10 16:35:28 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Also retry on unexpected network failures
+
+2014-04-10 15:45:41 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: New property to specify the maximum number of retries before we give up
+
+2014-03-13 10:56:11 +0100  Alexander Zallesov <zallesov@gmail.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Change default timeout to 15 seconds
+	  If nothing happens after 15 seconds, chances are good that
+	  our connection will never will work. Stop after 15 seconds
+	  instead of waiting until the system's default timeout, which
+	  can be > 1 minute.
+
+2014-04-09 17:30:54 +0900  Jimmy Ohn <yongjin.ohn@lge.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: replace duplicated variable when parsing trex atom
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727878
+
+2014-04-09 10:56:29 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Use GST_FLOW_FLUSHING when flushing, not GST_FLOW_EOS
+	  ... and reset it properly after flushing is done. Fixes playback
+	  in many cases when buffering is used.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727821
+
+2014-04-09 08:58:04 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Properly return stream flags when parsing trex atom
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727867
+
+2014-03-19 19:18:11 +0000  Matthieu Bouron <matthieu.bouron@collabora.com>
+
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: use the video frame API instead of the video meta API
+	  https://bugzilla.gnome.org/show_bug.cgi?id=726738
+
+2014-03-19 18:47:39 +0000  Matthieu Bouron <matthieu.bouron@collabora.com>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: advertize video meta API support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=726737
+
+2014-04-08 11:31:06 +0200  Edward Hervey <edward@collabora.com>
+
+	* gst/interleave/interleave.c:
+	  interleave: Add missing break in switch statement
+	  The caps query is handled entirely already before.
+	  CID #1139757
+
+2014-04-06 18:03:11 -0300  Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: souphttpsrc: use SoupKnownStatusCode if needed
+	  From libsoup docs:
+	  Prior to 2.44 SoupStatus was called SoupKnownStatusCode,
+	  but the individual values have always had the names they
+	  have now.
+	  Fixes:
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727329
+
+2014-04-07 12:58:23 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: use frames, not bytes, for position query in VBR streams
+	  Coverity 1139648
+
+2014-04-07 12:42:14 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/smpte/gstsmpte.c:
+	  smpte: fix copy/paste error causing unmap on wrong buffer
+	  Coverity 1139647
+
+2014-04-07 12:16:17 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: guard against finding no suitable pattern
+	  The code handles a -1 pattern index, and it seems plausible
+	  that a pattern might be found later, so it seems best to not
+	  send an element error here.
+	  Coverity 1139766
+
+2014-04-04 17:38:14 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: update for new MIKEY API
+
+2014-04-03 17:40:01 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: send sender SSRC in the MIKEY message
+	  Allocate a new SSRC for our RTCP messages back to the server and set
+	  this in the MIKEY message.
+
+2014-04-03 17:39:30 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: make random number for the CSB
+	  As recommended in the RFC
+
+2014-03-26 12:10:44 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: don't put spaces in keymgmt header
+
+2014-03-25 17:47:49 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: create and send the RTCP encryption key
+	  Create and make a key for encrypting the RTCP packets back to the server
+	  and wrap this in a MIKEY message that we send as a header in the SETUP
+	  request.
+
+2014-04-03 12:18:39 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: free the srtpdec element
+
+2014-04-03 12:16:25 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: cleanup stream_free function
+	  There is no reason to NULL all fields, we will free the stream anyway.
+
+2014-04-03 12:07:31 +0200  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: demote warning to debug
+	  For TCP, it is normal that we don't have timestamps so don't WARN on
+	  it.
+
+2014-03-29 19:13:06 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: Fix support for caps without width, height, framerate or format
+	  For format like mpegts, width and height is rarely in the negotiated caps. This
+	  patch fixes failure when setting format, and prevent introducing width, height,
+	  framerate and format to the caps when fixating.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=725860
+
+2014-03-31 18:34:13 +0200  Thibault Saunier <tsaunier@gnome.org>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: Always set PTS=DTS on raw video streams
+
+2014-03-31 18:31:22 +0200  Thibault Saunier <tsaunier@gnome.org>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Always set pixel-aspect-ratio on raw video streams
+	  That field is mandatory in caps and if it is not present in the
+	  AVI container, it means square pixels thus 1/1.
+
+2014-03-30 00:35:07 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroska-mux: add mapping for Opus audio
+	  Might want to consider adding channels/rate
+	  requirement to template caps, but requires
+	  fixing up of encoder and parser first.
+
+2014-03-30 00:31:11 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	  matroska-demux: add mapping for Opus audio codec
+	  https://bugzilla.gnome.org/show_bug.cgi?id=727305
+
+2014-03-29 17:21:17 -0400  William Manley <will@williammanley.net>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2src: Fix support for mpegts streams
+	  It seems that GStreamer's mpegts elements (tsdemux, tsparse) require caps
+	  `video/mpegts,systemstream=true`.  As far as I can see the significance
+	  of systemstream is to indicate that this is a container format rather than
+	  an elementary stream.  As this is the case (and I can't understand how it
+	  could not be the case with mpegts) I add systemstream=true to v4l2src's
+	  caps.
+	  This allows v4l2src to be linked with tsdemux for playback from my
+	  Hauppauge HD-PVR with the pipeline:
+	  v4l2src ! queue ! tsdemux ! video/x-h264 ! decodebin ! xvimagesink
+	  In combination with the next commit this fixes using Hauppauge HD-PVR with
+	  GStreamer 1.0+.
+
+2014-01-14 14:48:42 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: attempt to fix infinite (for small version of infinite) loop
+
+2014-03-29 13:20:30 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpmanager: copy sticky events when exposing pads in more places
+	  https://bugzilla.gnome.org/show_bug.cgi?id=724712
+
+2014-03-28 20:11:36 +0100  Rico Tzschichholz <ricotz@ubuntu.com>
+
+	* sys/v4l2/Makefile.am:
+	  v4l2: fix distcheck
+	  Make sure ext/*.h are dist'ed
+
+2014-03-27 19:51:50 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximagesrc: only extrapolate alpha mask for 32-bit depth
+	  Instead of passing bogus alpha mask values when there's no alpha.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=726833
+
+2014-03-21 13:03:17 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximagesrc: Add ARGB/BGRA support
+
+2014-03-20 15:28:26 +0100  Ognyan Tonchev <ognyan@axis.com>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  jpegpay: consider header len when calculating payload len
+	  Fixed https://bugzilla.gnome.org/show_bug.cgi?id=726777
+
+2014-03-26 08:03:22 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: All frames are sync points
+
+2014-03-26 08:02:43 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: All frames are sync points
+
+2014-03-22 17:07:46 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: segment closing not needed in 1.x
+	  ... as sender should keep track of segment base accumulation.
+	  Rather, it may have some adverse effects as a spurious segment event,
+	  e.g. in collectpads.
+
+2014-03-22 17:05:17 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: early sending pending codec-data for all streams
+	  ... at least before syncing across all streams might cause some gap
+	  activity on any of those streams, notably sparse streams.
+	  See also #712134
+
+2014-03-22 17:01:27 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: handle both sticky and non-sticky custom event
+
+2014-03-25 11:44:27 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: only expose streams on dataflow
+	  Only probe on buffers, we don't want to expose the streams on events.
+
+2014-03-25 11:36:40 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: copy sticky events to ghostpad
+	  When we expose internal pads as ghostpads, first copy the sticky events
+	  so that we have the caps and segment etc.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=724712
+
+2014-03-24 14:25:43 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: srtp handling
+
+2014-03-25 10:23:00 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: set SSRC on caps if known
+
+2014-03-24 16:58:25 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: put caps on udpsrc instead of using the signals
+	  Try to avoid using the request-pt-map to get caps but set them directly
+	  on the udpsrc element. That way, the caps get nicely transformed as they
+	  pass through the different elements in the rtpbin, including the AUX and
+	  decoder/encoder elements.
+
+2014-03-24 15:35:09 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: use profile to set rtcp caps
+	  Use the negotiated profile to set x-rtcp or x-srtcp caps
+
+2014-03-24 15:34:26 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: set udpsrc to READY
+	  READY is enough to allocate ports now
+
+2014-03-24 14:25:28 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: improve caps handling
+	  Protect caps with the lock.
+	  Don't push the caps event from the set_property function but mark the
+	  pad for reconfiguration so that it will renegotiate and push the new
+	  caps event in the streaming thread.
+
+2014-03-24 15:15:34 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: open/close socket in NULL<->READY state
+	  We should open the socket when going to NULL<->READY and not in the
+	  start/stop vemthod, which is called in READY<->PAUSED. This makes it
+	  possible to allocate a socket without going to PAUSED (and starting the
+	  negotiation).
+
+2014-03-24 14:35:01 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: free caps in ptmap array
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726696
+
+2014-03-20 11:12:51 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: handle NULL rtpmap and parse error better
+
+2014-03-16 23:46:22 -0400  Olivier Crête <tester@tester.ca>
+
+	* configure.ac:
+	  configure: Don't check for gudev if video4linux2 is not present
+
+2014-03-16 23:19:55 -0400  Olivier Crête <tester@tester.ca>
+
+	* configure.ac:
+	  configure: Don't fail if gudev is not present
+	  PKG_CHECK_MODULES has the bad habit of failing the build if it doesn't
+	  get what it wants, prevent that.
+
+2012-11-02 13:33:13 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* configure.ac:
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2devicemonitor.c:
+	* sys/v4l2/gstv4l2devicemonitor.h:
+	  v4l2: Implement GstDeviceMonitor subclass
+	  https://bugzilla.gnome.org/show_bug.cgi?id=678402
+
+2013-08-12 11:49:21 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* ext/pulse/Makefile.am:
+	* ext/pulse/plugin.c:
+	* ext/pulse/pulsedevicemonitor.c:
+	* ext/pulse/pulsedevicemonitor.h:
+	  pulse: Add device monitors
+	  https://bugzilla.gnome.org/show_bug.cgi?id=678402
+
+2014-03-16 19:24:26 -0400  Olivier Crête <tester@tester.ca>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Remove GstPropertyProbe leftovers
+
+2014-02-19 03:04:03 +0100  Mathieu Duponchelle <mduponchelle1@gmail.com>
+
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	  videomixer: Port to new collectpads API
+	  See: https://bugzilla.gnome.org/show_bug.cgi?id=724705
+
+2014-03-16 15:26:04 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/ext/types-compat.h:
+	* sys/v4l2/ext/videodev2.h:
+	  v4l2: Add types compatiblity for other OS
+	  Adds type compatiblity with other OS like BSD. This uses types mapping macro to
+	  avoid conflict with existing defined types. We resuse glib types as these are
+	  already available on supported platforms. This is GCC only because of the
+	  le32 type that uses bitwise attribute.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=726453
+
+2014-03-16 15:55:00 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/pulse/pulseutil.c:
+	  pulse: fix format info to caps conversion for mulaw
+
+2013-08-13 12:10:42 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulseutil.c:
+	* ext/pulse/pulseutil.h:
+	  pulse: Make gst_pulse_format_info_to_caps() shared
+	  https://bugzilla.gnome.org/show_bug.cgi?id=678402
+
+2014-03-15 18:41:16 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/Makefile.am:
+	  v4l2: Fix typo V4L_DIR intead of V4L2_DIR
+
+2014-03-15 18:05:32 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* configure.ac:
+	  v4l2-build: Set HAVE_GST_V4L2 if headers are present
+	  The name of HAVE_ need to match the USE_. Now set HAVE_GST_V4L2 if
+	  videodev2.h is found.
+
+2014-03-15 16:47:51 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* configure.ac:
+	* sys/Makefile.am:
+	  v4l2: Actually build the plugin
+	  The checks were removed inadvertedly in previous patch and not replaced.
+	  Re-introduce the configure checks and some of the checks in order to enable
+	  this plugin again. We only check if videodev2.h exist on the platform to
+	  avoid building on Windows or OSX, though we build against our own copy. This
+	  was breaking the build on built-bot.
+
+2014-03-15 13:47:42 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  translation: PO file changes caused by POTFILE.in update
+
+2014-03-15 13:17:21 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* configure.ac:
+	* po/POTFILES.in:
+	* po/POTFILES.skip:
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2videooverlay.c:
+	* sys/v4l2/gstv4l2videooverlay.h:
+	  v4l2: Remove XV support
+	  XV support for v4l2 never became upstream and ended up being
+	  commented out with an undef for a long time now.
+
+2014-03-15 11:13:05 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* configure.ac:
+	* gst-plugins-good.spec.in:
+	* sys/Makefile.am:
+	* sys/v4l2/ext/v4l2-common.h:
+	* sys/v4l2/ext/v4l2-controls.h:
+	* sys/v4l2/ext/videodev2.h:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2vidorient.c:
+	* sys/v4l2/v4l2_calls.c:
+	* tests/icles/Makefile.am:
+	  v4l2: Use a copy of videodev2.h header
+	  With years the amount of ifdef have grown up and we are not even sure if the
+	  old code path compiles. Each time we need to update the v4l2 framework to add
+	  the new feature, we break compilation on older kernel. With exception of two
+	  controls in the video orientation control, this patch get rid of all ifdef by
+	  including the latest version of videodev2.h inside GStreamer.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=723446
+
+2014-03-12 15:32:55 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: Add properties for selecting SSL/TLS certificate checking
+	  And by default properly check certificates against the system's CA
+	  certificates. Everything else is not a good default at all.
+
+2014-03-11 14:56:30 +0100  Per x Johansson <perxjoh@axis.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: fix assert on fps lower than 1
+	  Fixes assert caused by gst_duration_to_fraction calling
+	  gst_util_uint64_scale_int with a denominator of 0 when fps is less
+	  than 1.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=726106
+
+2014-03-11 00:46:06 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer2: store video info with buffers to keep it in sync
+	  Instead the queued buffer might have an old caps while the pad
+	  is already storing the information for a new caps. Mixing those
+	  while handling buffers will often lead to issues
+	  https://bugzilla.gnome.org/show_bug.cgi?id=725948
+
+2014-03-08 19:29:58 -0500  William Manley <will@williammanley.net>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: Fix typo contol -> control
+	  https://bugzilla.gnome.org/show_bug.cgi?id=725632
+
+2014-03-04 01:15:49 +0000  William Manley <will@williammanley.net>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: Normalise control names in the same way as v4l2-ctl
+	  V4L2 kernel drivers allow configuration of the hardware settings via a
+	  mechanism called controls.  These can be referred to by name such as
+	  "Brightness" and "White Balance Temperature".  The user-space command line
+	  client for setting these controls (v4l2-ctl) normalises these names such
+	  that they only contain lower case alphanumeric characters and the
+	  underscore '_'.  e.g:
+	  Kernel                     v4l2-ctl
+	  ----------------------------------------------------
+	  Brightness                 brightness
+	  White Balance Temperature  white_balance_temperature
+	  Focus (absolute)           focus_absolute
+	  GStreamer seems to want to follow this pattern but failed for controls with
+	  more than one consecutive non-alphanum character.  e.g. GStreamer would
+	  produce "focus__absolute_" rather than "focus_absolute".
+	  This commit fixes that issue.  Backwards compatibility is preserved by
+	  normalising all control names before comparison.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=725632
+
+2014-03-07 16:17:29 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Make sure to not return EOS immediately if we finished a range request
+	  Only return EOS the next time create() is called, if at all. basesrc
+	  should already take care of not calling it again.
+	  Also always return immediately if the previous flow return was
+	  not OK. This indicates an error somewhere.
+
+2014-03-06 12:06:43 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	  rtp: Remove caps restrictions from RTP depayloader sink caps
+	  Remove caps restrictions that correspond to the default and are not
+	  required in SDP. With the new usage of having pads require a subset
+	  of the caps, they will make the negotiation fail.
+
+2014-03-06 11:02:09 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpspeexdepay.c:
+	  rtpspeexdepay: Remove caps restrictions for depayloader
+	  The "encoding-params" is optional in the SDP, because we now require
+	  a subset of the caps, it would fail caps negotiatioin if it wasn't present.
+	  So removed it from the template caps.
+
+2014-03-06 13:38:09 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Don't forget to quit mainloop after we cancelled when we got data after the stop position
+
+2014-03-06 13:35:47 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: If we had a stop position, allow for the server to finish our connection instead of just cancelling
+	  Otherwise keep-alive does not make much sense and also the server will have
+	  confusing things in the logs.
+
+2014-03-06 12:24:01 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: skip streams with same control url
+	  Keep track of what streams we did the SETUP for. We only need to
+	  configure caps, wait for pads and push events on setup streams. We can
+	  remove the disabled state of the stream and simplify some checks.
+	  After we setup a stream, skip the other streams that have the same
+	  control url. Use a skipped flag to mark streams that should be skipped.
+
+2014-03-06 12:22:47 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: remove obsolete code
+
+2014-03-05 16:19:19 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: just use the SDP index as the stream id
+	  Use the index of the media stream in the SDP as the stream id instead of
+	  keeping a separate counter.
+
+2014-03-05 13:35:19 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* sys/osxvideo/cocoawindow.m:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideo: fix build on Mac OSX Mavericks and put new window in front
+	  GetCurrentProcess/SetFrontProcess/TransformProcessType was deprecated
+	  and now removed in Mac OSX 10.9. orderFrontRegardless is used to make
+	  the video window the most front window.
+
+2014-03-05 17:33:56 +0100  Christian Fredrik Kalager Schaller <uraeus@linuxrising.org>
+
+	* gst-plugins-good.spec.in:
+	  Add docs directory to spec file
+
+2014-03-05 15:44:25 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: handle NULL control urls better
+
+2014-03-05 14:28:26 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: small cleanups
+	  It's nicer to explicitly check for NULL on pointer types to make it
+	  clear that it's a pointer and not a boolean.
+
+2014-03-05 14:26:02 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: handle unknown SSRC in FIR
+	  https://bugzilla.gnome.org/show_bug.cgi?id=725712
+
+2014-03-05 11:39:09 +0100  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix seeking
+	  Call gst_rtspsrc_connection_flush (src, FALSE) to reset connections as
+	  non-flushing before sending PAUSE and PLAY with the new npt range. Without this
+	  patch, those commands would fail with EINTR as the connections were still
+	  flushing.
+
+2014-03-03 16:39:26 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: expose xsub as a subtitle instead of as a video
+	  It is placed inside a 'vids' struct, so it was being exposed on
+	  a pad named video_%d. XSUB are subtitles and this patch adds
+	  an special case for it to be exposed in a subpicture_%d pad
+
+2014-03-03 16:38:45 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: do not try to add a tag with tag_name set to NULL
+	  This can happen if there are subtitles in the stream, leading to
+	  an assertion
+
+2014-03-04 16:40:34 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Add support for multiple payload types
+	  A media stream can have multiple payload types. Parse all the payload
+	  types and collect the caps information. We then have to store the
+	  pt<->caps mapping instead of 1 pt and 1 caps.
+	  Parse the profile from the SDP and use that to negotiate the transport
+	  instead of always using AVP.
+	  Rework how we do some tweaks for ASF and Realmedia.
+
+2014-03-04 11:34:39 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: refactor payload handling
+
+2014-03-03 11:34:00 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  jitterbuffer: fix buffer level with invalid DTS
+	  It is possible that the DTS is invalid (when we receive RTP packets from
+	  TCP, for example). As a fallback, use the reconstructed PTS value to
+	  calculate the buffer level.
+
+2014-03-02 05:10:13 +0100  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* .gitignore:
+	  .gitignore: Ignore gcov intermediate files
+	  https://bugzilla.gnome.org/show_bug.cgi?id=725480
+
+2014-02-28 09:34:46 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From fe1672e to bcb1518
+
+2014-02-27 23:15:04 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  Revert "aacparse: put codec data on caps for loas format"
+	  This reverts commit e459cf3e01a08f1a3ef1fb954a41cfa36b3e510c.
+	  This was pushed by accident, the bug should likely be fixed in
+	  libav https://bugzilla.libav.org/show_bug.cgi?id=644
+
+2014-02-27 18:55:04 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: mark all parsed frames as sync points
+	  all jpeg frames are sync points, so mark them as such so
+	  reverse playback can properly work with the video decoder
+	  base class
+	  https://bugzilla.gnome.org/show_bug.cgi?id=725104
+
+2014-02-25 01:12:05 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: put codec data on caps for loas format
+	  gst-libav audio decoder also needs codec data for LOAS format, otherwise
+	  it will complain about not having a decoder config and skip all packets
+	  https://bugzilla.gnome.org/show_bug.cgi?id=596772
+
+2014-02-27 00:43:48 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: align raw audio memory to powers of two
+	  https://bugzilla.gnome.org/show_bug.cgi?id=725008
+
+2014-02-27 00:37:20 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: calculate alignment properly for audio depths not a multiple of 8
+
+2014-02-23 19:09:24 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: fix crash with 24-bit raw audio
+	  Do not try to align audio buffers to odd numbers,
+	  which will get us a NULL buffer which we then
+	  crash on.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=725008
+
+2014-02-27 00:11:42 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtpmanager/Makefile.am:
+	  rtpmanager: re-enable -Werror
+
+2014-02-27 00:11:11 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: fix compiler warning
+	  gstrtpjitterbuffer.c: In function 'gst_rtp_jitter_buffer_loop':
+	  gstrtpjitterbuffer.c:2978:3: error: 'result' may be used uninitialized in this function
+	  while (result == GST_FLOW_OK);
+	  ^
+
+2014-02-26 22:11:41 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 1a07da9 to fe1672e
+
+2014-02-26 21:11:23 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Fix uninitialized variable compiler warning
+
+2014-02-26 07:32:32 -0500  Jake Foytik <jake.foytik@ipconfigure.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Remove raw comparisons of RTP sequence numbers
+	  Several conditional statements perform comparison on RTP sequence
+	  numbers without taking the sequence number rollover into account.
+	  Instead, use the gst_rtp_buffer_compare_seqnum function to perform the
+	  comparison.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=725159
+
+2014-02-03 01:44:21 +0100  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* tests/check/Makefile.am:
+	  tests: Don't build disabled plugins' check tests
+	  https://bugzilla.gnome.org/show_bug.cgi?id=723502
+
+2014-02-26 11:29:45 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* docs/Makefile.am:
+	  docs: install prebuilt plugin docs if gtk-doc is disabled
+	  Sync to the Makefile.am from gst-plugin-base where it is done right.
+	  Fixes #725034
+
+2014-02-25 16:10:54 -0500  Hugues Fruchet <hugues.fruchet@st.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: do not emit "parsed" caps for vp8
+	  VP8 doesn't require parsing (vp8parse doesn't exist, so negotiation with demux fails
+	  if "parsed" is set in caps).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=724636
+
+2014-02-11 16:27:08 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Don't require parser for VP8
+	  Until GStreamer has one (see bug722760), we should not require a parser for VP8.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722128
+
+2014-02-10 17:08:25 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: CAPTURE_MPLANE is well tested now
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722128
+
+2013-12-18 09:56:35 +0100  Benjamin Gaignard <benjamin.gaignard@linaro.org>
+
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2videodec.c:
+	* sys/v4l2/gstv4l2videodec.h:
+	  v4l2videodec: Create one element per device
+	  For each videoCdevice probe it input/output capabilities
+	  if it match with video decoder requirement register a new element.
+	  Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722128
+
+2013-12-19 15:26:52 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2videodec.c:
+	  v4l2videodec: Calculate latency from device information
+	  Decoders or other devices that expose a minimum buffers required produce
+	  an first output. We use this information to calculate latency.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722128
+
+2013-11-28 17:14:18 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2videodec.c:
+	* sys/v4l2/gstv4l2videodec.h:
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2videodec: Implement v4l2videodec
+	  Implement an element that can driver V4L2 M2M decoder device.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722128
+
+2014-02-11 12:41:29 +0100  Göran Jönsson <goranjn@axis.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: only update last_spspps time if all sps/pps got sent successfully
+	  This fixes an issue with gst-rtsp-server where no sps and pps are
+	  sent for the first intra frame, because the payloader starts working
+	  already when receiving DESCRIBE but there is no transports so it tries
+	  to send sps and pps, but that fails with a FLUSHING flow. But the time
+	  for last sent sps and pps would still be set, so when PLAY arrives and
+	  the first intra frame is to be sent there is no sps and pps sent due to
+	  that time since last sps pps is less than spspps_interval.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=724213
+
+2014-02-25 09:00:45 +0100  Santiago Carot-Nemesio <sancane@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Fix deadlock when task creation is no successful
+	  https://bugzilla.gnome.org/show_bug.cgi?id=725124
+
+2014-02-22 20:19:49 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/autodetect/gstautodetect.c:
+	  autodetect: demote candidate error to warning and plug fake{sink,src}
+	  In the case where we have no suitable candidate we post a warning and plug a
+	  fake-element. Do the same when non of the candidate work.
+	  This is more consistent and plugin the fakesink as a fallback is probably
+	  helpful for running unit tests without requiring hardware src/sink elements.
+	  Fixes #722981
+
+2014-02-23 12:34:48 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: make some more controls configurable
+	  ... at least if one tries hard enough using extra-controls property.
+
+2014-02-23 10:39:20 +0100  Dan Kegel <dank@kegel.com>
+
+	* configure.ac:
+	  v4l2: Require mplanar support for now in configure
+	  The code fails to compile without currently, see
+	  https://bugzilla.gnome.org/show_bug.cgi?id=723446
+	  It's better to disable it instead of failing compilation
+	  until this is fixed properly.
+
+2014-02-23 00:14:04 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/jack/gstjackaudioclient.c:
+	  jack: add some simple log handlers for jack
+	  Add log handlers for jack that write to the gst debug log. This avoids spamming
+	  the console when e.g. using autoaudiosink, having the jack elements installed,
+	  but not running jack.
+
+2014-02-22 21:31:21 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2src: handle old and odd driver behaviour when listing controls
+
+2013-11-28 16:54:58 -0800  Darryl Gamroth <dgamroth@uvic.ca>
+
+	* gst/audiofx/audiofxbaseiirfilter.c:
+	  audiofxbaseiirfilter: check if coefficients are provided inside filter lock
+	  https://bugzilla.gnome.org/show_bug.cgi?id=719524
+
+2014-02-21 19:46:44 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2src: also unset INTERLACED flag on buffers if frame is not interlaced
+	  https://bugzilla.gnome.org/show_bug.cgi?id=724899
+
+2014-02-21 14:31:59 +0000  Simon Farnsworth <simon.farnsworth@onelan.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2src: Flag interlaced buffers as interlaced.
+	  We correctly indicate the field ordering on interlaced buffers, but fail to
+	  flag them as containing interlaced video, which we need to do here because
+	  we signal interlace-mode=mixed in our caps. This means that downstream
+	  elements (like vaapipostproc from gstreamer-vaapi) don't recognise these
+	  buffers as in need of deinterlacing.
+	  Fix this by setting the interlaced flag on all interlaced buffers.
+	  Signed-off-by: Simon Farnsworth <simon.farnsworth@onelan.co.uk>
+	  https://bugzilla.gnome.org/show_bug.cgi?id=724899
+
+2014-02-19 13:56:37 -0300  Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: be more strict at ADTS header parsing
+	  Adds two extra checks:
+	  - Sampling frequency on header can't be 15.
+	  - Frame size should be at least 9 or 7, depending
+	  on whether CRC protection is present.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=724638
+
+2014-02-19 13:35:59 -0300  Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: make sure we have enough ADTS data
+	  We need at least 6 bytes to pass over to _get_frame_len()
+	  but we were just checking for a minimum of 2 bytes for the
+	  syncword.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=724638
+
+2014-02-20 22:52:57 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/autodetect/gstautodetect.c:
+	* gst/autodetect/gstautodetect.h:
+	  autodetect: check if the kid has a sync property
+	  previously autovideosrc did not have a sync property and v4l2src has none either.
+
+2014-02-19 21:55:52 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosink.h:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautoaudiosrc.h:
+	* gst/autodetect/gstautodetect.c:
+	* gst/autodetect/gstautodetect.h:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosink.h:
+	* gst/autodetect/gstautovideosrc.c:
+	* gst/autodetect/gstautovideosrc.h:
+	  autodetect: use a common baseclass
+	  This makes the actual elements super simple. We're using the ELEMENT_FLAG to
+	  configure source/sink and a string for the Audio/Video type.
+
+2014-02-14 17:14:42 -0800  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: add tls-database property
+	  Add support for a new property: tls-database. If the property is set,
+	  the certificate database will be given to the rtsp connection if TLS
+	  protocol is being used. If the server certificate can't be verified with
+	  the default database, this additional database will be used.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=724396
+
+2014-02-19 22:21:54 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* sys/osxaudio/gstosxaudioringbuffer.c:
+	* sys/osxaudio/gstosxaudiosink.c:
+	  osxaudio: remove unused variables
+
+2014-02-19 21:26:03 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautodetect.c:
+	* gst/autodetect/gstautodetect.h:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	  autodetect: extract common helper code
+	  The function to generate the pretty names is basically the same. Use one and add
+	  a parameter.
+
+2014-02-19 21:01:39 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/autodetect.c:
+	  autodetect: improve the tests
+	  Add fake audio/video sinks. Previously running the test might be flaky due to
+	  the use of real elements (hardware in use), which we don't want to test here.
+	  Add two more tests that check that the fakes are chosen.
+
+2014-02-19 15:19:30 +0100  Branislav Katreniak <bkatreniak@nuvotechnologies.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: do not emit error when connection with unknown size ends
+	  Commit 46fd12ae5ec53200b16dfd7f17048d6bc60fbfbc introduced connection
+	  recovery. But when server does not specify content-size,
+	  souphttpsrc tries to reconnect even after regular end of stream.
+	  Http server replies  with SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE
+	  but souphttpsrc still emits error instead of EOS.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=724717
+	  Signed-off-by: Branislav Katreniak <bkatreniak@nuvotechnologies.com>
+
+2014-02-19 11:26:22 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/check/elements/autodetect.c:
+	  autodetect: fix the disabled test
+	  Use a shared helper for both tests. It turns out that the valgrind variant is
+	  fine (maybe due to picking up pulsesink though).
+
+2014-02-19 11:05:35 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/check/elements/autodetect.c:
+	  autodetect: remove cruft from the test
+	  Remove the obsolete version check and use the ignore macro for the disabled test.
+
+2014-02-18 22:54:45 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/audiofx/audiofirfilter.c:
+	* gst/audiofx/audioiirfilter.c:
+	* gst/level/gstlevel.c:
+	* gst/spectrum/gstspectrum.c:
+	  docs: use docbook markup for xi:include
+	  It turns out that the change in gtk-doc-1.20 which wraps the |[]| content in
+	  CDATA break xi:inlcude examples. As in a whole jhbuild checkout these where
+	  the only 4, we're fixing them instead.
+
+2014-02-18 22:35:45 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/isomp4/gstqtmux-doc.h:
+	  isomp4mux: fix copy and paste
+	  This fixes doc warnings.
+
+2014-02-18 21:44:24 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/debugutils/gstcapssetter.c:
+	* gst/isomp4/gstqtmux-doc.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/level/gstlevel.c:
+	* gst/replaygain/gstrganalysis.c:
+	* gst/replaygain/gstrgvolume.c:
+	  docs: use the gtk-doc syntax to link to properties
+	  Don't use docbook unless needed. Also stip other docbook tags in the the files we fix.
+
+2014-02-18 11:28:18 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: fix crash when getting the current-device in NULL->READY
+	  The "goto unlock" is wrong as in this code path we haven't take the lock yet.
+	  Fixes #724619
+
+2014-02-14 22:50:49 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  soup: We need libsoup >= 2.40 for proper usage of the content decoder
+	  Previous versions did not consider our chunk allocator and allocated
+	  memory by themselves, which caused crashes and broken behaviour.
+
+2014-02-14 15:27:20 -0500  William Jon McCann <william.jon.mccann@gmail.com>
+
+	* gst/audiofx/audiocheblimit.c:
+	* gst/udp/gstudpsrc.c:
+	  docs: fix mismatched para tags
+	  newer gtkdoc is more sensitive to mismatched docbook tags.
+	  This fixes the build in master.
+
+2014-02-14 15:59:46 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: add support for serialized queries
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=723850
+
+2014-02-14 15:53:55 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: fix typecast to fix compilation
+
+2014-02-14 12:01:00 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: proxy caps and allocation on RTP pads
+	  recv_rtp_sink: allow proxying of the allocation query.
+	  send_rtp_sink: allow proxying of caps and allocation. This allows us to
+	  query caps downstream as well as get an allocator from downstream.
+	  send_rtp_src: allow proxy of caps, this makes the caps query do
+	  upstream.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=723850
+
+2014-02-13 12:29:13 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: handle tags in mac encoding
+	  Check the charset from (C)*** tags and set the charset
+	  to convert from MAC encoding if suitable.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=723166
+
+2014-02-13 12:09:13 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Use new automatic_eos API from basesrc
+	  We want to notice ourselves that we're EOS. Otherwise we will
+	  always cancel requests in the very end and confuse the server...
+	  and also make it impossible to use persistent connections.
+
+2014-02-13 11:11:13 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Consistently use have_size instead of content_size!=0
+
+2014-02-13 10:30:09 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Free extra headers when finalizing the element
+	  It's set as property by the application, we should not just reset
+	  properties when going back to READY.
+
+2014-02-13 10:28:13 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Properly close the session when going back to NULL
+	  Don't wait for that until the element is disposed.
+
+2013-02-28 12:20:52 +0100  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: add support for keep-alive sessions
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699926
+
+2014-02-12 13:00:13 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: Add "compress" property to enable/disable automatic gzip/deflate content encoding handling
+
+2014-02-12 12:39:10 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Retry connection if we're finished before the content size only if we actually have a content size
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722185
+
+2014-02-12 10:08:50 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouputils.c:
+	  souputils: Fix compiler warning
+	  gstsouputils.c:35:25: error: comparison of constant 9 with expression of type
+	  'SoupLoggerLogLevel' is always false
+	  [-Werror,-Wtautological-constant-out-of-range-compare]
+
+2014-01-07 23:00:56 -0300  Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+
+	* ext/soup/Makefile.am:
+	* ext/soup/gstsoup.c:
+	* ext/soup/gstsouphttpclientsink.c:
+	* ext/soup/gstsouphttpclientsink.h:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	* ext/soup/gstsouputils.c:
+	* ext/soup/gstsouputils.h:
+	  souphttp*: add ability to do HTTP session logging
+	  This changeset adds the loggin infrastructure and
+	  mods both souphttpsrc and souphttclientsink to use it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=721764
+
+2014-02-07 14:00:15 +0100  divhaere <dirk.vanhaerenborgh@ugent.be>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	  matroska: add support for GRAY8, BGR and RGB video colourspaces in V_UNCOMPRESSED codec
+	  https://bugzilla.gnome.org/show_bug.cgi?id=723849
+
+2014-02-11 13:25:46 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Add mapping for NOT_FOUND and NOT_AUTHORIZED errors
+
+2014-02-11 13:25:22 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Don't duplicate status_code to GStreamer error mapping
+
+2014-02-09 23:38:44 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/goom/filters.c:
+	* gst/goom2k1/filters.c:
+	  goom: Remove unused functions
+
+2014-02-09 23:21:20 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-parse.c:
+	  matroskaparse: Comment out some unused functions used only from the commented out pull-mode code
+
+2014-02-08 21:01:32 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/taglib/gstid3v2mux.cc:
+	  id3v2mux: Fix another compiler warning
+
+2014-02-08 17:43:32 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/souphttpsrc.c:
+	  souphttpsrc: Fix implicit enum conversion compiler warning
+	  error: implicit conversion from enumeration type
+	  'SoupStatus' to different enumeration type 'SoupKnownStatusCode'
+
+2014-02-08 17:41:21 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/interleave.c:
+	  interleave: Fix unitialized variable compiler warning in test
+	  error: variable 'mask' is used uninitialized
+	  whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized]
+
+2014-02-08 17:27:51 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/taglib/gstid3v2mux.cc:
+	  id3v2mux: Fix unitialized variable compiler warning
+	  error: variable 'image_type' is used uninitialized
+	  whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized]
+
+2014-02-08 17:25:27 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* sys/oss4/oss4-audio.h:
+	  oss4: Fix typo in header include guard
+	  error: 'GST_OSS4_AUDIO_H' is used as a header guard here,
+	  followed by #define of a different macro [-Werror,-Wheader-guard]
+
+2014-02-08 17:24:06 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: Fix unitialized variable compiler warning
+	  variable 'rtx_ssrc' is used uninitialized whenever
+	  'if' condition is false [-Werror,-Wsometimes-uninitialized]
+
+2014-02-08 17:21:19 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpac3depay.c:
+	  rtpac3depay: Remove unused variable
+
+2014-02-08 17:19:19 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/flx/flx_fmt.h:
+	  flx: Fix typo in header include guard
+	  error: '__GST_FLX_FMT__H__' is used as a header guard here,
+	  followed by #define of a different macro [-Werror,-Wheader-guard]
+
+2014-02-07 10:07:41 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  qtmux: remove have_dts flag from pads
+	  It was used in the past in 0.10 when there was no explicit DTS
+	  field in buffers, now we have it in 1.x series and we can
+	  check it directly with GST_BUFFER_DTS_IS_VALID
+
+2014-02-07 01:49:26 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  qtmux: improve support for sparse streams
+	  Do not try to use subsequent buffer timestamps to calculate
+	  sparse streams durations because the stream is sparse and
+	  the buffers might not be 'time adjacent'. So rely on the
+	  duration and give the option to the pad to provide
+	  custom 'empty' buffers to represent the gaps in the
+	  stream, this can vary on how the data is represented.
+	  Right now, the only sparse stream supported is tx3g subtitles.
+
+2014-02-06 12:15:22 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmuxmap.c:
+	  qtmux: add support for text/x-raw subtitles
+	  Adds it to mp4mux, qtmux and gppmux.
+	  Buffers need to be prefixed with 2 bytes for the text length before
+	  being muxed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=581295
+
+2014-02-06 12:09:01 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/fourcc.h:
+	  qtmux: add support for the TX3G atoms
+	  Adds functions for creating and setting values related to the
+	  tx3g atom for raw text subtitle support.
+	  QTFF spec has information on those atoms
+	  https://bugzilla.gnome.org/show_bug.cgi?id=581295
+
+2014-02-05 10:27:54 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	* gst/isomp4/gstqtmuxmap.c:
+	* gst/isomp4/gstqtmuxmap.h:
+	  qtmux: add subtitle support to qtmuxmap structures
+	  adds basic stubs for subtitle support around the qtmux and
+	  qtmuxmap structures. Still no real subtitle implemented, but
+	  basic functions in place
+	  https://bugzilla.gnome.org/show_bug.cgi?id=581295
+
+2014-01-20 17:31:14 -0300  Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.c:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: factor out read context init/reset
+	  While at this, move _track_reset() to track-ids
+	  so it can be called from the common read context
+	  reset routine.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722705
+
+2014-02-06 12:21:07 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/effectv/gstrev.c:
+	  effectv: fix doc section of revtv element
+
+2014-02-05 12:46:54 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* sys/osxvideo/Makefile.am:
+	  osxvideo: Fix libtool usage
+	  --tag=CC is needed for static build
+
+2014-01-16 11:26:41 +0000  Matthieu Bouron <matthieu.bouron@collabora.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: do not try set deinterlace method if passthrough is enabled
+	  Fixes an issue with progressive content and unsupported video formats
+	  for the deinterlace method.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=719636
+
+2014-02-04 21:26:56 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: order format in template caps by preference
+	  To minimise risk of bad fixation, though audioconvert
+	  at least should be smart enough to avoid it.
+
+2014-02-02 09:57:03 -0800  Dan Kegel <dank@kegel.com>
+
+	* configure.ac:
+	  v4l2: Remove obsolete definition GST_V4L2_MISSING_BUFDECL
+	  The only use was removed by 9edc0c0365f79ab07ff2e65461c6696e3931a3f0
+	  https://bugzilla.gnome.org/show_bug.cgi?id=723446
+
+2014-02-04 13:43:56 +0100  Rafał Mużyło <galtgendo@o2.pl>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacenc.c:
+	* gst/cutter/gstcutter.c:
+	  gst: Don't use endianness-specific S8 audio format
+	  It does not exist.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=723331
+
+2014-01-31 14:17:54 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* ext/cairo/gstcairooverlay.c:
+	  cairooverlay: add support for RGB16
+	  https://bugzilla.gnome.org/show_bug.cgi?id=723289
+
+2014-01-30 09:43:50 +0100  Per x Johansson <perxjoh@axis.com>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: Fix constantly growing used uid list
+	  Moves the used uid list to the class to avoid having it grow forever.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=723269
+
+2014-01-30 10:44:05 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From d48bed3 to 1a07da9
+
+2014-01-24 01:52:08 +0000  Mike Sheldon <elleo@gnu.org>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Ignore Broadcast Wave Format (BWF) tags when searching for 'fmt' chunk
+	  https://bugzilla.gnome.org/show_bug.cgi?id=723125
+
+2014-01-29 10:37:53 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* tests/check/elements/rtpaux.c:
+	  check: Use fakesink sync=True instead of an audio sink
+	  Ensures the test can run on systems without alsa (or any audio output for
+	  that matter), and will avoid people running build slaves wondering what
+	  the hell was beeping during the night :)
+
+2014-01-27 20:05:42 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: custom get_sink_caps handling for private stream caps
+	  ... now that those are transformed rather than parsed, some transforming
+	  of caps is required as well to make auto-plugging succeed.
+
+2014-01-25 02:06:00 -0500  Ryan Lortie <desrt@desrt.ca>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: guard use of ENODATA with #ifdef
+	  Not all systems with v4l have ENODATA defined, so check that we have it
+	  before attempting to use it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722953
+
+2014-01-24 12:37:39 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  Revert "rtspsrc: Proxy rtpjitterbuffer do-retransmission property"
+	  This reverts commit 9f7b1128b1f00a2b87a232ff890867549ab95ba5.
+	  This should be handled automatically be rtspsrc if the AVPF profile
+	  is used, and manual enabling of it can be done with the new-manager
+	  signal.
+
+2014-01-24 10:21:11 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: add signal to notify of new manager
+	  So that you can configure and connect to signals on the rtpbin.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=722866
+
+2014-01-23 15:17:58 -0800  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Proxy rtpjitterbuffer do-retransmission property
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722866
+
+2014-01-21 17:52:44 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: handle expected packet being an RTX packet
+	  If the expected packet (do_next_seqnum is TRUE) is the one we requested
+	  for retranmission earlier, do the logic to update the retransmission
+	  statistics as well before setting up the timers for the next expected
+	  packet.
+	  Also reset the retransmission counter if the timer is reused for another
+	  seqnum.
+
+2014-01-21 15:48:20 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: add a caps accumulator for the request-pt-map signal
+	  Add an accumulator that stops the signal emission as soon as a caps has
+	  been retrieved. Otherwise the default handler would continue emitting
+	  the signal and possibly overwrite the result with NULL again.
+
+2014-01-21 15:25:54 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	  rtxreceive: copy flags and timestamps from original buffer
+
+2014-01-21 15:24:52 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: ignore invalid timestamps in rtt calculation
+	  When the input buffer does not have a valid timestamp, don't try to
+	  calculate the round-trip-time.
+
+2014-01-16 14:23:13 -0300  Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroskaparse: better default caps when none set
+	  Uses information gathered during EBML parsing to
+	  forge a more suitable set of caps instead of blindly
+	  assuming everything is video/x-matroska.
+	  For consistency, stream type reset was added to
+	  matroska-demux too.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722311
+
+2014-01-15 17:29:35 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/check/elements/rtprtx.c:
+	  tests: rtprtx::test_rtxreceive_data_reconstruction: remove useless code for triggering retransmission
+	  There is no need anymore to push yet another buffer in rtxsend
+	  in order to trigger the previously requested retransmissions
+	  to actually happen.
+
+2014-01-15 17:27:19 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/check/elements/rtprtx.c:
+	  tests: rtprtx::test_rtxreceive_data_reconstruction: fix race condition
+	  Now with rtprtxsend pushing rtx buffers from a different thread,
+	  this is necessary to ensure that the result of the test is deterministic.
+	  This code makes use of GstCheck's global GMutex and GCond that are
+	  being used inside GstCheck's sink pad chain() function in order
+	  to synchronize with it.
+
+2014-01-15 17:17:57 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/check/elements/rtprtx.c:
+	  tests: rtprtx::test_rtxsender_packet_retention: fix race condition
+	  Now with rtprtxsend pushing rtx buffers from a different thread,
+	  this is necessary to ensure that the result of the test is deterministic.
+	  This code makes use of GstCheck's global GMutex and GCond that are
+	  being used inside GstCheck's sink pad chain() function in order
+	  to synchronize with it.
+
+2014-01-15 11:26:33 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/check/elements/rtprtx.c:
+	  tests: rtprtx::test_push_forward_seq: fix race condition
+	  Now with rtprtxsend pushing rtx buffers from a different thread,
+	  this is necessary to ensure that the result of the test is deterministic.
+	  This code makes use of GstCheck's global GMutex and GCond that are
+	  being used inside GstCheck's sink pad chain() function in order
+	  to synchronize with it.
+
+2014-01-15 09:47:03 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/check/elements/rtprtx.c:
+	  tests: rtprtx::test_push_forward_seq: fix buffer refcounting
+
+2014-01-21 13:42:38 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: ensure that no rtx buffers are sent after EOS
+	  To do that, enqueue the EOS event to be sent from the srcpad task
+	  thread and flush the queue right afterwards, so that no more rtx
+	  buffers can be sent, even if there are more requests coming in.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=722370
+
+2014-01-15 09:46:14 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	* gst/rtpmanager/gstrtprtxsend.h:
+	  rtprtxsend: run a new GstTask on the src pad
+	  The reason behind this is to minimize the retransmission delay.
+	  Previously, when a NACK was received, rtprtxsend would put a
+	  retransmission packet in a queue and it would send it from chain(),
+	  i.e. only after a new buffer would arrive.
+	  This unfortunately was causing big delays, in the order of 60-100 ms,
+	  which can be critical for the receiver side.
+	  By having a separate GstTask for pushing buffers out of rtxsend,
+	  we can push buffers out right after receiving the event, without
+	  waiting for chain() to get called.
+
+2014-01-03 17:47:55 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/shout2/gstshout2.c:
+	* ext/shout2/gstshout2.h:
+	  shout2send: error out if no caps were received
+	  Instead of assuming that input is ogg.
+
+2014-01-03 17:30:12 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/shout2/gstshout2.c:
+	  shout2send: accept audio/webm, audio/ogg and video/ogg as well
+	  Those are advertised in the template caps, but the
+	  setcaps handler didn't handle them. But then oggmux
+	  and oggparse at least for now still always output
+	  application/ogg anyway, so that wasn't a real problem.
+
+2014-01-20 10:12:45 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8pay: Don't leak input buffers
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722414
+
+2014-01-19 17:40:56 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/avi/gstavimux.c:
+	  avimux: reset some more audio pad data when needed
+
+2014-01-19 17:38:59 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavimux.h:
+	  avimux: write correct blockalign for vbr audio
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=720659
+
+2014-01-16 17:36:12 -0800  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: do not drop serialized events when latency is set
+	  Serialized events are now queued in the jitter buffer, so we don't
+	  want to drop them even latency is set.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722372
+
+2013-12-11 09:36:22 +0100  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* gst/avi/gstavimux.c:
+	  avimux: don't make the buffer writable unless absolutely necessary
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722396
+
+2013-09-12 16:56:56 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: set GST_BUFFER_FLAG_DELTA_UNIT when appropriate
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722394
+
+2014-01-17 07:46:09 +0100  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: don't ref the newly created allocator
+	  Otherwise the allocator will never be deleted.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=712612
+
+2014-01-15 22:47:12 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Don't skip all video frames until the first keyframe
+	  Instead do it like all other demuxers and let parsers and decoders
+	  handle that. The keyframe information inside the container might
+	  be completely wrong like in the sample file of the bug report,
+	  and if it is correct and we push no keyframes, then the parsers
+	  and decoders will handle that properly anyway.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=682276
+
+2014-01-13 10:08:09 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: remove elst_offset variables
+	  They are not used anymore
+
+2014-01-06 21:36:17 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: remember reverse playback when verifying the segment end
+	  Check if the rate is positive or negative to correctly compare the current
+	  position with the segment to make reverse playback work
+
+2014-01-03 10:59:35 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: do not ignore empty segments
+	  Make sure empty segments are used and pushed with a gap event
+	  to represent its data (or lack of it)
+	  Each QtSegment is mapped into a GstSegment with the corresponding
+	  media range. For empty QtSegments a gap event is pushed instead
+	  of GstBuffers and it advances to the next QtSegment.
+	  To make this work with seeks, need to keep track of the starting
+	  'base' to make sure it remains consistently increasing when
+	  pushing new segment events.
+	  For example: if a seek makes qtdemux start from 5s, the first
+	  segment will have a base=0. When the next segment is activated,
+	  its base time will be QtSegment.time - qtdemux.segment_base so
+	  that it doesn't include the first 5s that weren't played and
+	  shouldn't be accounted on the running time
+	  This purposedly will remove the fix made for
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700264, at this
+	  point it was decided to respect the gaps, even if they cause
+	  a delay on playback, because that's the way the file was crafted.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=345830
+
+2013-12-12 23:05:43 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* tests/check/elements/rtprtx.c:
+	  tests: Remove usage of the system clock from the rtprtx test
+
+2013-12-12 23:22:41 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* tests/check/elements/rtpcollision.c:
+	  tests: Initial segment in rtpcollision test
+
+2014-01-14 15:56:42 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/examples/rtp/client-rtpaux.c:
+	* tests/examples/rtp/server-rtpaux.c:
+	  examples/*-rtpaux: specify payload type association for the audio stream, so that rtx works also for audio
+
+2014-01-14 13:08:18 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: remove wrong check for payload type not having been set
+	  1) pt can be lower than 96
+	  2) there is no point in checking that because rtprtxsend will not
+	  even store buffers for payload types that it doesn't know about,
+	  so this case will never be reached
+
+2014-01-14 13:01:41 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: fix data locking when creating rtx packets
+	  This patch moves the creation of rtx packets to be done early,
+	  in the src_event() function, when they are requested. The purpose
+	  is to run gst_rtp_rtx_buffer_new() with the object locked to
+	  protect internal data, because if it is done at the pushing stage,
+	  we would have to lock and unlock multiple times in a row while we
+	  are pushing the rtx buffers.
+	  Previously there was no locking at all, which was terribly wrong.
+
+2014-01-14 12:50:23 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: lock access to internal data in sink_event() function
+
+2014-01-14 12:44:06 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: remove unnecessary call to reset() from finalize()
+	  ...and use _free_full() on the pending buffers queue now that
+	  reset() is not being called
+
+2014-01-14 12:38:51 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: remove unused parameter from the internal reset() method
+
+2014-01-14 12:32:38 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: Use g_slice_* for allocating internal structures
+
+2014-01-14 12:28:01 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	  rtprtxreceive: remove stupid mutex unlock in the middle of chain()
+
+2014-01-14 12:25:36 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	  rtprtxreceive: use GST_DEBUG_OBJECT / GST_WARNING_OBJECT instead of GST_DEBUG / g_warning
+
+2014-01-14 12:19:58 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	  rtprtxreceive: fix integer format specifiers in GST_DEBUG
+	  seqnum in this function is 32-bit, so G_GUINT16_FORMAT would
+	  produce undefined output on big endian systems
+
+2014-01-14 12:13:49 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	* gst/rtpmanager/gstrtprtxsend.h:
+	  rtprtxsend: change the rtx_pt_map directly in set_property() instead of delaying it for chain()
+	  The same lock is held, so there is no point in complicating it...
+
+2014-01-14 12:07:58 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	* gst/rtpmanager/gstrtprtxreceive.h:
+	  rtprtxreceive: change the rtx_pt_map directly in set_property() instead of delaying it for chain()
+	  The same lock is held, so there is no point in complicating it...
+
+2014-01-14 11:55:00 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	  rtprtxreceive: simplify the code of finalize()
+
+2014-01-14 11:52:21 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	* gst/rtpmanager/gstrtprtxreceive.h:
+	  rtprtxreceive: use the GstObject lock instead of a new one
+
+2014-01-14 11:45:52 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	* gst/rtpmanager/gstrtprtxsend.h:
+	  rtprtxsend: use the GstObject lock instead of a new one
+
+2013-12-10 14:29:55 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Add NV12_64Z32 support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722127
+
+2014-01-14 19:08:49 +0900  Justin Joy <justin.joy.9to5@gmail.com>
+
+	* sys/oss/gstosshelper.c:
+	  osshelper: Don't leak fd when getting card name
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722163
+
+2014-01-14 09:43:33 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  Revert "aacparse: relax the detection of ADTS"
+	  This was pushed by mistake along with the V4L2 fix.
+	  This reverts commit 8eb4b032bef444397c4d211f2095c173ba114187.
+
+2014-01-14 15:42:01 +0900  Justin Joy <justin.joy.9to5@gmail.com>
+
+	* gst/rtp/gstrtpg726pay.c:
+	  rtpg726pay: don't leak encoding_name string
+	  https://bugzilla.gnome.org/show_bug.cgi?id=722159
+
+2014-01-13 09:14:00 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: fix build break using V4L2_CAP_VIDEO_M2M_MPLANE
+	  This may not be defined. Since the previous version used
+	  only the other define (V4L2_CAP_VIDEO_OUTPUT_MPLANE), fall
+	  back on this only when not available.
+
+2013-02-27 01:45:52 +0900  Akihiro Tsukada <atsukada@users.sourceforge.net>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: relax the detection of ADTS
+	  According to ISO/IEC 13818-7, "channel_config" field in ADTS header
+	  may have value of 0, as in the case of frame with PCE.
+	  gst_aac_parse_detect_streams() returned FALSE for those frames
+	  and discarded them.
+
+2014-01-07 11:58:23 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: check set_config return value in gst_v4l2_buffer_pool_new
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2014-01-10 12:40:31 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Add parsed=1 field for encoded output
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2014-01-10 12:39:16 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't leak empty caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2014-01-08 16:51:21 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: do not stop a stream not previously started
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-12 16:27:21 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't enforce dimension field on encoded formats
+	  Don't enforce having width, height and framerate in template caps for encoded
+	  formats. These don't always need to be exposed and may break negotiation for
+	  decoder and decoding sink. If needed, these field will be automatically added
+	  when probed caps are known.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-12 17:09:59 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: unref downstream pool
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-18 13:37:23 -0500  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2bufferpool: add gst_v4l2_buffer_pool_flush
+	  STREAMOFF set all v4l2buffers to DEQUEUE state.
+	  Then for CAPTURE we call QBUF on each buffer.
+	  For OUTPUT the buffers are just push back in the GstBufferPool
+	  base class 's queue.
+	  But the loop actually looks like the same.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-16 17:29:30 -0500  Benjamin Gaignard <benjamin.gaignard@linaro.org>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Add vp8 support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-12 16:46:09 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't force framerate field for OUTPUT
+	  If there is nothing that seems to force a certain framerate on output device, it is
+	  preferable to simply not set that feild. This allow negotiation with tsdemux in a
+	  decoder for example.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-12 14:07:03 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2object: _v4l2fourcc_to_structure() can be static
+	  This function is not used anymore outside v4l2object.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-12 14:22:26 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Add MPEG1/2 support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-12 12:18:45 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Ask for a decent buffer size when dealing with encoded formats
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-07 14:03:53 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: On warn on size change if n_planes > 1
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-31 16:38:09 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: check if translated format is valid
+	  Also add a FIXME in gst_v4l2_object_setup_format
+	  to note that the whole function has to be improved
+	  in order to support ENCODED formats.
+	  It requires to have an encoder device which we do not
+	  have right now.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-07 10:31:15 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Validate returned dimensions
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-05 19:36:25 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Ensure max is not smaller then min in decide_allocation
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-05 19:36:06 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't keep the max paramter when using our own pool
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-05 19:34:44 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Respect the suggested min buffer
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-05 18:48:44 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Allocate pool if needed in decide_allocation
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-05 18:49:19 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Add V4L2_CID_MIN_BUFFERS_FOR_CAPTURE support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-05 18:48:15 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: Move decide allocation into v4l2object
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-05 13:51:13 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2object: Implement _setup_format()
+	  This method allow setting up the object from the currently configured format on the
+	  device. This is useful for M2M element where input data decides the format that will
+	  be set on capture side.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-10 14:34:17 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Split out saving format from set_format()
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-31 15:37:26 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: set only one plane for encoded format
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-04 16:49:13 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Move code block where it belongs
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-04 16:26:12 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't check format specific information
+	  The number of plane, and the stride does not represent a capability change. Same caps
+	  can have different stride from the default GstVideoInfo and the number of planes will
+	  never change for 1 format.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-04 16:23:18 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Move the extrapolation of stride at the right place
+	  Now that we have a stride array, we should extrapolate only when
+	  eeded (non multi-planar buffer).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-04 15:09:44 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Move back assertions where they should be
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-04 15:09:10 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Move mplane logic into gst_v4l2_object_get_caps_info()
+	  It makes the gst_v4l2_object_set_format() slightly simplier and will make that
+	  logic reusable. Note that gst_v4l2_object_has_mplane() will always return the
+	  same value for one device. There is no need to check against the caps as this
+	  has already been done by _open.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-03 18:27:47 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2object: Split _v4l2fourcc_to_video_format
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-02 18:05:11 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Request buffers only once
+	  VIDIOC_REQBUFS allocates buffer, it has no place inside set_config. Also, some driver do
+	  no allow multiple calls to this ioctl.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-02 15:26:50 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't validate dimension for encoded format
+	  We set the dimensions just in case but don't validate them
+	  afterwards. For some codecs the dimensions are *not* in the
+	  bitstream, IIRC VC1 in ASF mode for example.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-11-28 17:10:29 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2object: Quirks for dev without initial format
+	  Most M2M have undefined behaviour initially when VIDIOC_G_FMT is called.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-11-28 17:09:26 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2object: Add gst_v4l2_object_open_shared()
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-11-28 17:07:05 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2_calls.h:
+	  v4l2object: Implement gst_v4l2_dup()
+	  This will duplicated the FD from another object and copy over the probed result.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-11-28 16:59:59 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2object: make IO_MODE enum public
+	  This is to allow adding a second io-mode property on M2M device like decoder so
+	  input and output can be controlled separatly.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-06-04 23:42:24 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: better handle quirks activation
+	  This way we can activate deactivate those quirks all at once at one
+	  place.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-06-04 23:34:04 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Fix h264 caps
+	  V4L2_PIX_FMT_H264 is documentated as byte-stream (with start code). The ensure proper
+	  negotiation with element like h264parse.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2013-12-06 14:44:51 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2object: Split caps in different categories
+	  This is need to correctly expose capabilities on specialized devices
+	  like decoders and encoders.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720568
+
+2014-01-10 14:16:00 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: don't leak TOC chapter list
+
+2014-01-10 08:52:16 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: remove obsolete write-dummy-and-overwrite-on-eos code
+	  The need for rewriting apparently is obsolete 0.10 leftover.
+	  We now have caps for subtitles when we create the headers,
+	  so we always write the correct data in the first place.
+
+2014-01-09 23:55:16 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: remove duplicate assignment
+	  Coverity CID 1151680
+
+2014-01-09 18:25:04 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: write subtitle codec ID and data at start when known
+	  This avoids issues with writing dummy data first, then having
+	  to come back and write correct data later. Doing so prevents
+	  the muxed stream from being actually streamable.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=712134
+
+2014-01-09 17:32:15 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  configure: Include AvailabilityMacros.h for osxvideo check
+	  Otherwise MAC_OS_X_VERSION_MIN_REQUIRED might not be defined
+
+2014-01-09 11:56:31 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	  qtmux: respect the HDLR box string format for mov and isomedia
+	  Mov spec says it uses a pascal style string, while isomedia uses
+	  a null terminated one. Store the current atoms flavor into the HDLR
+	  to be able to generate the correct output.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=705982
+
+2014-01-08 11:28:04 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/matroska/matroska-mux.c:
+	  Revert "matroskamux: Use the running time for container timestamps, not buffer timestamps"
+	  This reverts commit b3aa8755fe07639f22e4104f4932d769d6c9075a.
+	  We are already using the running-time because they were placed on the
+	  buffers with gst_collect_pads_clip_running_time(). Arguably it would be
+	  better to not modify the incomming buffers but collectpads seems to want
+	  to use absolute timestamps from the buffers for finding the best buffer
+	  (this can be changed with a custom compare function..).
+
+2014-01-08 10:41:24 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  configure: Fix AC_COMPILE_IFELSE usage
+
+2014-01-08 10:31:18 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  osxvideosink: Improve configure check for OSX >= 10.6
+	  https://bugzilla.gnome.org/show_bug.cgi?id=721245
+
+2014-01-07 12:13:51 -0800  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: remove unused list of decoders
+	  remove list of decoders, which are already handled by the list of elements.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=719938
+
+2014-01-08 09:46:55 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Error out if ADPCM caps don't contain the layout field
+
+2014-01-03 15:25:23 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Add support for g726 ADPCM
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720995
+
+2014-01-07 15:04:02 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: use new method to get media-type
+	  Use the new method to get the media type of a transport.
+
+2014-01-06 21:12:17 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/check/elements/wavparse.c:
+	  wavparse: split the test
+	  This way one failure won't shadow the other test and also if one fails we get
+	  better disgnostics through the test-name.
+
+2014-01-06 14:54:46 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Add HEVC / h265 support
+
+2014-01-06 14:54:38 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	  matroskademux: Add HEVC / h265 support
+
+2014-01-06 13:36:38 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: remove ifdef'ed code
+	  We do have adtl and cue parse as part of toc handling alreday. The fmt code is a left over from <0.10 times.
+
+2014-01-06 13:32:58 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/avi/gstavidemux.c:
+	* gst/wavparse/gstwavparse.c:
+	  avidemux, waveparse: more logging for unhandled chunks
+	  Always print a warning with the tag and if possible do a memdump.
+
+2014-01-05 22:47:42 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: expose 'strn' - stream name - as title tag
+
+2014-01-05 22:41:24 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: parse fuji strd
+	  We can get maker, model and capture date from this chunk.
+	  Fixes #636143
+
+2014-01-05 21:46:33 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: ... and use the local api both times
+
+2014-01-05 21:38:14 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: copy the riff api for ncdt into the element
+	  This chunk is avi specific, no need to expose this as public api.
+
+2014-01-05 10:28:21 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Add missing semicolon from last commit
+
+2014-01-05 10:22:37 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Use the running time for container timestamps, not buffer timestamps
+	  Buffer timestamps have no real meaning here, and for selecting the next
+	  buffer we already use the running time anyway.
+
+2014-01-04 21:34:38 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/avi/gstavidemux.c:
+	  avi: use new riff api to extract nikon metadata
+	  Fixes #636143
+
+2013-11-01 16:41:43 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	  rtprtxsend/rtprtxreceive: generate gtk doc
+
+2013-12-02 11:26:09 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/check/elements/rtprtx.c:
+	  test/check: Verify rtprtxsend::ssrc-map property works as expected
+
+2013-11-29 19:35:44 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	* gst/rtpmanager/gstrtprtxreceive.h:
+	* tests/check/elements/rtpaux.c:
+	* tests/check/elements/rtprtx.c:
+	* tests/examples/rtp/client-rtpaux.c:
+	  rtprtxreceive: modify to use a payload-type map like rtprtxsend
+
+2013-11-29 19:58:26 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: do not keep history of packets with an unknown payload type
+	  This allows to disable retransmission per payload type by not putting
+	  a certain payload type in the map.
+
+2014-01-02 15:18:52 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	* gst/rtpmanager/gstrtprtxsend.h:
+	* tests/check/elements/rtpaux.c:
+	* tests/check/elements/rtpcollision.c:
+	* tests/check/elements/rtprtx.c:
+	* tests/examples/rtp/server-rtpaux.c:
+	  rtprtxsend: Allow SSRC-multiplexing and multiple payload types in the original stream
+	  Conflicts:
+	  tests/examples/rtp/server-rtpaux.c
+
+2013-11-25 15:00:45 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: Add an rtx-ssrc property to allow external control of the ssrc
+	  This is useful when one needs to know the SSRC beforehands, so that it can
+	  be used for SRTP for example.
+
+2013-11-13 15:11:35 -0500  Torrie Fischer <torrie.fischer@collabora.co.uk>
+
+	* tests/examples/rtp/.gitignore:
+	* tests/examples/rtp/Makefile.am:
+	* tests/examples/rtp/client-rtpaux.c:
+	* tests/examples/rtp/server-rtpaux.c:
+	  examples: rtp: Add end-to-end rtpbin example with RTX elements
+	  This example demonstrates how to use rtpbin with retransmission (rtx)
+	  elements set in the place of rtpbin's "aux" elements in order to
+	  enable RTP retransmission according to the rules of RFC4588.
+
+2013-11-05 17:35:01 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* docs/design/Makefile.am:
+	* docs/design/design-rtpauxiliary.txt:
+	  doc: add design-rtpauxiliary.txt to describe how rtpbin deals with auxiliary elements
+
+2014-01-02 14:48:49 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  session: also push EOS event to RTCP srcpad
+
+2014-01-02 14:46:11 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  session: place SSRC in Retransmission event
+
+2013-11-01 16:57:15 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/rtpaux.c:
+	  tests/check: add rtpaux::test_simple_rtpbin_aux
+	  It shows how to use "set-aux-receive" and "set-aux-send"
+	  properties of rtpbin to set rtprtxsend and rtprtxreceive
+	  Build 2 pipelines, one for rtpbin as a sender and one for
+	  rtobin as a receive. Then transmit an audio stream.
+	  It also drops some packets to activate restransmission and
+	  check they are actually retransmited.
+
+2013-11-01 17:09:42 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* tests/check/elements/rtpcollision.c:
+	  tests/check: add rtpcollision::test_rtx_ssrc_collision unit test
+	  check that rtxrtpsend changes its retransmission ssrc when
+	  collision happens
+
+2013-11-06 12:34:13 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/check/elements/rtprtx.c:
+	  tests/check: add rtprtx::test_rtxreceive_data_reconstruction
+	  This unit test verifies that retransmitted rtp packets coming out
+	  of rtprtxreceive are the same as the original ones.
+
+2013-11-05 09:33:51 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: use a realistic limit for the value of max-size-packets
+	  G_MAXINT16 is chosen because if the queue contains more than
+	  G_MAXINT16 packets, seqnum comparison will not work properly.
+
+2013-11-04 20:05:03 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	* gst/rtpmanager/gstrtprtxsend.h:
+	  rtprtxsend: use a GSequence to implement the buffer queue
+	  This has the advantage that searching the queue to find the
+	  buffer with the requested seqnum is done with binary search.
+
+2013-11-04 18:38:24 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	* gst/rtpmanager/gstrtprtxsend.h:
+	* tests/check/elements/rtprtx.c:
+	  rtprtxsend: retransmit packets in the same order as the rtx requests
+
+2013-11-02 19:56:44 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/check/elements/rtprtx.c:
+	  tests/check: Add unit test for rtxsend's max_size_time property
+
+2013-10-29 18:27:00 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	* gst/rtpmanager/gstrtprtxsend.h:
+	  rtprtxsend: Handle the max_size_time property
+	  This property allows you to specify the amount of buffers
+	  to keep in the retransmission queue expressed as time (ms)
+	  instead of buffer count (which is the max_size_buffers property).
+
+2013-11-02 15:21:08 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtprtxsend.c:
+	  rtprtxsend: keep important buffer information in a private structure
+	  This is to avoid mapping a buffer every time we need to read a seqnum
+	  or a timestamp.
+
+2013-11-01 11:58:47 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/check/elements/rtprtx.c:
+	  tests/check: Add rtprtx::test_rtxsender_packet_retention
+	  This unit test verifies that the rtxsend element correctly maintains
+	  a buffer of already transmitted rtp packets and that it can
+	  re-transmit all of them correctly on demand. It also verifies
+	  that the limit of this buffer (max-size-packets property) is respected.
+
+2013-11-01 16:22:13 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* tests/check/elements/rtprtx.c:
+	  tests/check: add rtprtx::test_drop_multiple_sender unit test
+	  Several senders / one receiver
+	  Similar than test_drop_one_sender but with multiple senders
+	  mixed through the funnel element.
+	  It drops some packets and checks that they are retransmited
+	  correctly.
+
+2013-11-01 16:21:00 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* tests/check/elements/rtprtx.c:
+	  tests/check: add rtprtx::test_drop_one_sender unit test
+	  Test for one sender / one receiver
+	  Build the pipeline
+	  videotestsrc ! rtpvrawpay ! rtprtxsend ! rtprtxreceive ! fakesink
+	  and drop some buffers between rtprtxsend and rtprtxreceive
+	  Then it checks that every dropped packet has been re-sent.
+	  It also checks that not too much requests has been sent.
+
+2013-11-01 16:17:51 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/rtprtx.c:
+	  tests/check: add rtprtx::test_push_forward_seq
+	  add simple unit test that manually push buffers
+	  in rtprtxsend connected to rtprtxreceive.
+	  Drops some buffers and make sure they are retransmisted.
+
+2013-11-01 15:52:03 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* gst/rtpmanager/Makefile.am:
+	* gst/rtpmanager/gstrtpmanager.c:
+	* gst/rtpmanager/gstrtprtxreceive.c:
+	* gst/rtpmanager/gstrtprtxreceive.h:
+	* gst/rtpmanager/gstrtprtxsend.c:
+	* gst/rtpmanager/gstrtprtxsend.h:
+	  rtpmanager: add new rtprtxsend / rtprtxreceive elements
+	  The purpose of the sender RTX object is to keep a history
+	  of RTP packets up to a configurable limit (in time). It will
+	  listen for custom retransmission events from downstream. When
+	  it receives a request for retransmission, it will look up the
+	  requested seqnum in its list of stored packets. If the packet
+	  is available, it will create a RTX packet according to RFC 4588
+	  and send this as an auxiliary stream.
+	  The receiver will listen to the custom retransmission events
+	  from the downstream jitterbuffer and will remember the SSRC1
+	  of the stream and seqnum that was requested. When it sees a
+	  packet with one of the stored seqnum, it associates the SSRC2
+	  of the stream with the SSRC1 of the master stream. From then
+	  on it knows that SSRC2 is the retransmission stream of SSRC1.
+	  This algorithm is stated in RFC 4588. For this algorithm to
+	  work, RFC4588 also states that no two pending retransmission
+	  requests can exist for the same seqnum and different SSRCs or
+	  else it would be impossible to associate the retransmission with
+	  the original requester SSRC.
+	  When the RTX receiver has associated the retransmission packets,
+	  it can depayload and forward them to the source pad of the element.
+	  RTX is SSRC-multiplexed
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=711084
+
+2013-11-05 16:36:46 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* docs/design/Makefile.am:
+	* docs/design/design-rtpretransmission.txt:
+	  doc: add design for rtp retransmission
+	  Describe how rtprtxsend and rtprtxreceive generally work
+	  but also how the association algorithm is implemented.
+
+2014-01-02 20:23:05 -0300  Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: use status code macro instead of 407
+	  Rest of the code is using the _PROXY_AUTHENTICATION_REQUIRED
+	  macro too. Easier to understand if you don't recall HTTP
+	  error codes by heart.
+
+2013-12-31 21:31:43 -0300  Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+
+	* ext/shout2/gstshout2.c:
+	* ext/shout2/gstshout2.h:
+	  shout2send: change audio_format field to format
+	  This element and the underlying libshout2 library
+	  can handle video media files too. The code already
+	  handles video/webm so the name gets confusing. Also
+	  add and use DEFAULT_FORMAT macro Instead of hardwiring
+	  SHOUT_FORMAT_VORBIS at init
+	  https://bugzilla.gnome.org/show_bug.cgi?id=721342
+
+2013-12-31 20:09:29 -0300  Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+
+	* ext/shout2/gstshout2.c:
+	  shout2send: clarify meaning of the URL prop
+	  https://bugzilla.gnome.org/show_bug.cgi?id=721342
+
+2013-12-27 12:27:32 -0300  Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* ext/shout2/gstshout2.c:
+	  shout2send: docs, add a sample pipeline
+	  And finish adding shout2send to the docs while at it
+	  https://bugzilla.gnome.org/show_bug.cgi?id=721342
+
+2013-12-31 15:00:22 -0300  Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	  gdkpixbufoverlay: remove spurious @see_also
+
+2013-12-06 17:08:54 +0000  Matthieu Bouron <matthieu.bouron@collabora.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: support any video formats and any caps features if deinterlace mode allows it
+	  https://bugzilla.gnome.org/show_bug.cgi?id=719636
+
+2013-12-31 13:31:52 +0100  Sebastian Rasmussen <sebras@hotmail.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Handle v4l2_ioctl() errors even in error handling
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=721268
+
+2014-01-01 12:11:43 -0800  Jeremy Huddleston Sequoia <jeremyhu@apple.com>
+
+	* sys/osxvideo/Makefile.am:
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideo: unifdef -DRUN_NS_APP_THREAD
+
+2014-01-01 12:10:01 -0800  Jeremy Huddleston Sequoia <jeremyhu@apple.com>
+
+	* sys/osxvideo/cocoawindow.m:
+	* sys/osxvideo/osxvideosink.h:
+	  osxvideo: Assume SDK and deployment target are at least Snow Leopard
+
+2014-01-01 12:23:50 -0800  Jeremy Huddleston Sequoia <jeremyhu@apple.com>
+
+	* configure.ac:
+	  configure: Disable osxvideo on Leopard and earlier
+	  This also moves the "other platforms" check in OS X video to before the
+	  variable is read
+	  https://bugzilla.gnome.org/show_bug.cgi?id=721245
+
+2013-12-31 14:57:27 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* tests/check/elements/rtpbin.c:
+	  tests: add AUX receiver unit test
+
+2013-12-31 13:20:01 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* tests/check/elements/rtpbin.c:
+	  tests: improve rtpbin test
+
+2013-12-31 13:16:46 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: add some docs about AUX elements
+
+2013-12-31 13:01:22 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* tests/check/elements/rtpbin.c:
+	  tests: add AUX sender unit test
+
+2013-12-31 12:31:25 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: add support for AUX sender and receiver
+	  AUX elements are elements that can be inserted into the rtpbin
+	  pipeline right before or after 1 or more session elements.
+	  The AUX elements are essential for implementing functionality such
+	  as error correction (FEC) and retransmission (RTX).
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=711087
+
+2013-12-31 12:22:39 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* tests/check/elements/rtpbin.c:
+	  tests: add decoder test
+
+2013-12-30 17:36:42 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: make request_element method internally
+	  We can use the same method to create encoder and decoder elements, they
+	  are just internal elements that we create.
+
+2013-12-31 10:25:28 +0100  Stéphane Cerveau <scerveau@gmail.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Skip id3 tag
+	  Skip id3 tag during wav parse.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=721241
+
+2013-12-31 10:10:05 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* sys/osxaudio/gstosxcoreaudio.h:
+	* sys/osxvideo/cocoawindow.m:
+	* sys/osxvideo/osxvideosink.h:
+	  osx: Make OSX version checks more consistent
+	  And especially also consider update versions, e.g. 10.5 with updates
+	  will be 1051 or similar and thus bigger than MAC_OS_X_VERSION_10_5 but
+	  still won't have the API we want to use.
+
+2013-12-31 10:07:22 +0100  Jeremy Huddleston <jeremyhu@freedesktop.org>
+
+	* sys/osxvideo/osxvideosink.h:
+	  osxvideosink: Fix build on updated OS X Leopard
+	  https://bugzilla.gnome.org/show_bug.cgi?id=721245
+
+2013-12-30 17:23:22 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavimux.c:
+	  avimux: Add missing break
+	  I guess no-one noticed we no longer could mux WMV3 ...
+	  COVERITY CID 1139759
+
+2013-12-30 17:20:37 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpvrawpay.c:
+	  rtpvrawpay: Add missing break
+	  COVERITY CID 1139762
+
+2013-12-30 17:00:45 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: internal-ssrc is no longer deprecated
+
+2013-12-30 16:59:20 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: add Since tags
+
+2013-12-30 16:52:28 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: add signal for new jitterbuffer
+	  Emit a signal when a new jitterbuffer is created so that the app can
+	  have a chance to configure it.
+
+2013-12-30 16:28:57 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* tests/check/elements/rtpbin.c:
+	  rtpbin: handle multiple encoder instances
+	  Keep track of elements that are added to multiple sessions and make sure
+	  we only add them to the rtpbin once and that we clean them when no
+	  session refers to them anymore.
+
+2013-12-30 15:16:09 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* tests/check/elements/rtpbin.c:
+	  tests: add unit test for encoder element
+
+2013-12-30 15:15:43 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: fix memory leaks
+
+2013-12-30 15:03:34 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* tests/check/elements/rtpbin.c:
+	  tests: fix leak
+
+2013-12-30 15:00:50 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: expect the pads on the encoders
+	  Don't use request pads for the encoder elements, the signal handler
+	  should request the pads and make sure they are available with the right
+	  name.
+
+2013-12-30 14:56:07 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: request-rtp-encoder are no action signals
+	  The request-rtp-encoder signals are not action signals so mark them
+	  correctly and use an accumulator to collect the result value.
+
+2013-12-30 14:36:45 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: emit midi-base-note tag from data in 'smpl' chunk
+	  Add parsing of the 'smpl' chunk. Right now we only grab the midi-base-note and
+	  emit it as a tag.
+
+2013-12-26 12:05:19 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  gstrtpsession: suggest upstream to use the new "internal-ssrc" after a collision
+	  When a collision is found on the internal ssrc, we have to change it.
+	  Ideally, we want also the payloader upstream to follow this change and use
+	  the new internal ssrc. Ideally we want this condition to be always met:
+	  if there is one payloader sending on this session, its ssrc should match the
+	  internal ssrc.
+
+2013-12-26 11:04:29 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: allow setting internal-ssrc again
+
+2013-12-30 13:31:45 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/y4m/gsty4mencode.c:
+	  y4mencode: Remove dead code
+	  set/get property isn't used
+
+2013-12-30 13:30:24 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpqcelpdepay.c:
+	  rtpqcelpdepay: Remove uneeded variable
+
+2013-12-05 15:53:52 -0800  Aleix Conchillo Flaqué <aleix@oblong.com>
+
+	  rtpbin: allow dynamic RTP/RTCP encoders/decoders
+	  * gst/rtpmanager/gstrtpbin.[ch]: four new action signals have been
+	  added (request-rtp-encoder, request-rtp-decoder, request-rtcp-encoder
+	  and request-rtcp-decoder). The user will be able to provide encoders
+	  or decoders dynamically. The encoders must follow the srtpenc API and
+	  the decoders the srtpdec API. Having separate signals for RTP and RTCP
+	  allows the user to use different encoders/decoders or provide the same
+	  one (e.g. that would be the case for srtpenc).
+	  Also, rtpbin now allows application/x-srtp in its pads.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=719938
+
+2013-12-27 16:51:32 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: dynamically recalculate RTX parameters
+	  Use the round-trip-time and average jitter to dynamically calculate the
+	  retransmission interval and expected packet arrival time.
+	  Based on patches from Torrie Fischer <torrie.fischer@collabora.co.uk>
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=711412
+
+2013-12-27 16:50:52 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: calculate average jitter
+
+2013-12-27 16:48:48 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: use RTT from the Retransmission event
+	  Place the estimated RTT in the Retransmission event and let the session
+	  manager use that instead of the hardcoded value.
+
+2013-12-27 15:57:39 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: take more accurate running-time for NACK
+	  Don't use the current time calculated from the tmieout loop for when we
+	  last scheduled the NACK because it might be unscheduled because of a max
+	  packet misorder and then we don't accurately calculate the current time.
+	  Instead, take the current element running time using the clock.
+
+2013-12-30 11:06:38 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* tests/check/elements/wavpackdec.c:
+	  wavpackdec: Send a CAPS event in the unit test
+
+2013-12-27 02:14:02 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: improve mss_mode/fragmented special handling
+	  Make it clear what should be handled purely by mss mode:
+	  1) Expose the streams on the first moof as there are no moov atoms
+	  2) Properly cleanup streams on flushes
+	  Add a note about the meaning of upstream_newsegment and mss_mode
+	  for future reference.
+	  Make all other special fragment handling shared for both dash
+	  and mss streams.
+
+2013-12-12 10:50:27 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: drain the adapter before pushing EOS
+	  In a fragmented scenario, qtdemux is operating in push mode
+	  and it gets a fragmented buffer. While processing its data
+	  downstream gets unlinked (or a input-selector changes its
+	  active pad and returns not-linked). Qtdemux stops processing
+	  this fragment and returns not-linked upstream, leaving the
+	  remaining data in its adapter.
+	  When it gets an EOS it should make sure that all the data it
+	  had received is pushed before pushing EOS.
+
+2013-12-26 23:21:47 -0300  Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+
+	* ext/shout2/gstshout2.c:
+	  shout2send: drop IP only requirement for _set_host()
+	  libshout2 (we require > 2.0 at config time) supports
+	  both IP and hostname for _set_host(). Dropped an
+	  outdated FIXME regarding this limitation, adjusted
+	  some comments and changed the param blurb to reflect
+	  this too.
+
+2013-12-26 21:43:34 -0300  Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+
+	* ext/shout2/gstshout2.c:
+	  shout2send: Retarget FIXME to 2.0
+
+2013-12-26 11:21:36 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: use aggregate control for PLAY/PAUSE/TEARDOWN
+	  Use the aggregate control instead of the original request url to perform
+	  PAUSE/PLAY and TEARDOWN.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=721003
+
+2013-12-24 14:40:25 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/debugutils/rndbuffersize.c:
+	  rndbuffersize: Proxy CAPS, ALLOCATION, SCHEDULING and srcpad events properly
+
+2013-12-24 00:43:39 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: adpcm max block align is 8192
+
+2013-12-23 12:23:27 -0600  Brendan Long <b.long@cablelabs.com>
+
+	* configure.ac:
+	  vp9dec: Require vpx >= 1.3.0 for building vp9dec and vp9enc
+	  Previous versions did not have a stable bitstream for VP9.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720986
+
+2013-12-23 15:46:48 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Use correct codec id for ADPCM/DVI
+
+2013-12-23 15:44:30 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Check for the correct size of codec_data in the ACM case
+
+2012-01-14 19:58:17 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: basic adpcm support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=664339
+
+2013-12-20 11:45:38 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/isomp4/descriptors.c:
+	  qtdemux: Fix calcuation of descriptor length
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720813
+
+2013-12-22 22:33:39 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* autogen.sh:
+	* common:
+	  Automatic update of common submodule
+	  From dbedaa0 to d48bed3
+
+2013-12-22 21:56:03 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* po/Makevars:
+	  po: set gettext domain in Makevars so we don't have to patch the generated Makefile.in.in
+	  https://bugzilla.gnome.org/show_bug.cgi?id=705455
+
+2013-12-19 16:50:10 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: on receive error only unmap and unref buffer if one was alloced and mapped
+	  coverity CID 1139866.
+
+2013-12-19 12:47:22 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: fix misleading comment
+	  Those are not allocated on the stack.
+
+2013-12-17 18:28:25 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* configure.ac:
+	  vpx: Mark VP9 support as non-experimental
+	  There was a libvpx release with VP9 support now and the bitstream
+	  is frozen too.
+
+2013-12-15 21:04:11 -0800  Todd Agulnick <todd@agulnick.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  Some compiler warning fixes to satisfy XCode compiler
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720513
+
+2013-12-16 16:17:07 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/taglib/gstid3v2mux.cc:
+	  id3v2mux: Set picture type in the APIC frames
+
+2013-12-16 16:14:52 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/taglib/gstid3v2mux.cc:
+	  id3v2mux: Set image-description from the info struct, not the caps
+
+2013-12-16 10:02:37 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstwavpackparse.c:
+	* gst/audioparsers/gstwavpackparse.h:
+	  wavpackparse: Post AUDIO_CODEC tag
+
+2013-12-16 10:00:37 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstsbcparse.c:
+	* gst/audioparsers/gstsbcparse.h:
+	  sbcparse: Post AUDIO_CODEC tag
+
+2013-12-16 09:58:31 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstflacparse.h:
+	  flacparse: Post AUDIO_CODEC tag
+	  https://bugzilla.gnome.org/show_bug.cgi?id=720512
+
+2013-12-16 09:56:29 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstdcaparse.h:
+	  dcaparse: Post AUDIO_CODEC tag
+
+2013-12-16 09:54:38 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstamrparse.h:
+	  amrparse: Post AUDIO_CODEC tag
+
+2013-12-16 09:49:48 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstac3parse.h:
+	  ac3parse: Post AUDIO_CODEC tag
+
+2013-12-16 09:46:16 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstaacparse.h:
+	  aacparse: Post AUDIO_CODEC tag
+
+2013-12-16 09:41:14 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: Use pbutils functionality to create the AUDIO_CODEC tag
+
+2013-12-13 17:36:36 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Add error message if the app tries to set the internal-ssrc
+
+2013-12-13 16:08:35 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Only count nacks when a nack packet is received
+	  Not when any RTCP feedback packet is.
+
+2013-12-12 23:22:41 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* tests/check/elements/rtpcollision.c:
+	  tests: Initialize segment in rtpcollision test
+
+2013-12-13 15:57:36 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Process PSFB FIR requests which lack the media ssrc
+	  According to RFC 5104 section 4.3.1.2, RTCP PSFB FIR message SHALL
+	  have a media_ssrc field set to 0. The actual media ssrc is in the FCI.
+	  So in that case, we ignore the retained feedback and just let it through
+	  to the rtp_session_process_fir() function which will check for the actual
+	  SSRC inside the FCI.
+	  Fixes a regression introduced by commit 57c27ec3
+
+2013-11-14 16:19:29 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpsession: fix rb blocks disappearing after the first rtcp cycle with multiple senders
+	  Previously, when the session had multiple internal sender SSRCs, it would
+	  issue SR reports with RB blocks only on the first RTCP timeout and afterwards
+	  SR reports would be sent empty. This was because the "generation" number
+	  in RTPSource would increase more than once during the same cycle and afterwards
+	  it would always be greater than the session's generation, which would cause
+	  it to be skipped from being included in RBs.
+	  This commit fixes this problem by:
+	  1) Increasing the RTPSource generation only at the end of each cycle,
+	  which essentially fixes the problem but only when the internal senders
+	  are less than GST_RTCP_MAX_RB_COUNT.
+	  2) Keeping for each RTPSource a set of SSRCs which stores which SSRC's
+	  SR the given RTPSource has been reported in, which also fixes the problem
+	  when the internal senders are more than GST_RTCP_MAX_RB_COUNT. This is
+	  necessary because of the fact that any RTPSource is marked as reported
+	  in itself's SR and makes it impossible to know if it has been reported
+	  in other SRs too or not, and which.
+
+2013-11-14 16:23:35 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* tests/check/elements/rtpsession.c:
+	  tests/check: add an rtpsession unit test to verify all RBs are included in all SRs, roundrobin
+	  This test checks that when we have multiple internal sender sources
+	  in rtpsession, SRs contain RBs for every other sender source, and that
+	  they are included roundrobin when they exceed ST_RTCP_MAX_RB_COUNT,
+	  which is the max number of RBs that can fit in a SR.
+
+2013-12-12 16:01:10 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* docs/design/design-rtpcollision.txt:
+	  docs: improve docs
+
+2013-11-05 18:03:48 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* docs/design/Makefile.am:
+	* docs/design/design-rtpcollision.txt:
+	  doc: add design-rtpcollision.txt that explains when GstRTPCollision is created
+	  It also talks about "BYE only the corresponding source, not the whole session."
+
+2013-11-05 12:31:54 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* tests/check/elements/rtpcollision.c:
+	  tests/check: improve rtpcollision::test_master_ssrc_collision to ensure that a collision does not BYE the whole session
+	  Conflicts:
+	  tests/check/elements/rtpcollision.c
+
+2013-11-01 17:07:57 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/rtpcollision.c:
+	  tests/check: add rtpcollision::test_master_ssrc_collision unit test
+	  It checks the payloader changes its ssrc when collision happens
+
+2013-12-12 10:38:43 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: keep extra stats for scheduling BYE
+	  Keep an extra stats structure for scheduling the BYE packets. When we
+	  decide to schedule BYE, make a copy of the current stats into the
+	  bye_stats. Then while we schedule the BYE, update and use only the
+	  bye_stats. When we finished scheduling the BYE packet, we use the
+	  regular stats again.
+
+2013-12-12 10:34:38 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: when we schedule BYE, only deal with BYE sources
+	  When we are doing the RTCP timeout to schedule BYE packets, don't
+	  generate RTCP for all sources but only for the sources marked as BYE.
+
+2013-12-12 10:32:48 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: reset state after scheduling BYE
+	  After we do RTCP, we are not scheduling bye anymore.
+
+2013-12-12 10:31:38 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: also count NACKS when no signal was pending
+
+2013-12-12 10:09:25 +0100  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: ignore RTCP packets for the BYE sources
+	  When we are scheduling BYE packets, ignore all RTCP for the sources that
+	  are scheduling a BYE packet. Other sources that are not scheduling BYE
+	  should continue receiving RTCP packets as usual.
+
+2013-11-04 11:48:21 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: determine if the session is doing point-to-point
+	  In this case T_dither_max is set to 0 according to RFC 4585
+
+2013-12-10 11:57:37 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: serialize events in the buffer
+	  Serialize events into the jitterbuffer by inserting them with a -1
+	  seqnum.
+	  Update unit test to expect events from the streaming thread.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=652986
+
+2013-12-10 11:04:06 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: detect -1 seqnum
+	  Keep the seqnum as a full guint so that we can check for -1 entries and
+	  deal with them correctly.
+	  Immediately try to push -1 seqnum.
+
+2013-12-10 11:01:03 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: reorganize jitterbuffer items
+	  Keep the oldest item at the head and the newest items on the tail. This
+	  makes it easier to deal with -1 seqnums.
+
+2013-12-09 23:34:10 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  jitterbuffer: correctly check for invalid values
+	  Check for -1 on the guint from the buffer item instead of on the guint16
+	  or guint32.
+	  Also insert -1 seqnum at the head of the jitterbuffer.
+
+2013-12-08 16:49:55 +0100  Alessandro Decina <alessandro.d@gmail.com>
+
+	* sys/osxvideo/cocoawindow.m:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: fix segfault when dealing with padded frames
+	  Fixes crashes with vtdec ! osxvideosink where VideoToolbox outputs padded UYVY
+
+2013-12-05 12:15:29 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/law/mulaw-decode.c:
+	  mulawdec: Require caps to be set before accepting any data
+
+2013-12-05 12:15:19 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/wavpack/gstwavpackdec.c:
+	  wavpackdec: Require caps to be set before accepting any data
+
+2013-12-05 12:13:33 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/speex/gstspeexdec.c:
+	  speexdec: Require caps to be set before accepting any data
+
+2013-12-05 12:13:10 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: Require caps to be set before accepting any data
+
+2013-12-05 11:42:15 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/vpx/gstvp8dec.c:
+	* ext/vpx/gstvp9dec.c:
+	  vpx: Use new gst_video_decoder_set_needs_format() API
+
+2013-12-04 16:23:43 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Free device_info in accepts caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=719811
+
+2013-12-04 21:57:48 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtptheorapay.c:
+	  rtptheorapay: Don't send headers twice if we got them from the caps already
+
+2013-12-04 21:57:04 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtptheorapay.c:
+	  rtptheorapay: Don't leak config data when receiving a second CAPS event
+
+2013-12-04 21:55:53 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	  rtpvorbispay: Don't send headers twice if we got them from the caps already
+
+2013-12-04 21:54:16 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	  rtpvorbispay: Don't leak config data when receiving a second CAPS event
+
+2013-12-04 21:17:03 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpstreamdepay.c:
+	* gst/rtp/gstrtpstreamdepay.h:
+	  rtpstreamdepay: Add RFC4571 RTP stream depayloading element
+	  https://bugzilla.gnome.org/show_bug.cgi?id=719829
+
+2013-12-04 10:12:46 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpstreampay.c:
+	* gst/rtp/gstrtpstreampay.h:
+	  rtpstreampay: Add RFC4571 RTP stream payloading element
+	  https://bugzilla.gnome.org/show_bug.cgi?id=719829
+
+2013-12-03 15:08:25 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: improve fragment-start tracking
+	  Some buffers can have multiple moov atoms inside and the strategy
+	  of using the gst_adapter_prev_pts timestamp to get the base timestamp
+	  for the media of the fragment would fail as it would reuse the same
+	  base timestamp for all moofs in the buffer instead of accumulating
+	  the durations for all of them.
+	  Heres a better explanation of the issue:
+	  qtdemux receives a buffer where PTS(buf) = X
+	  buf -> moofA | moofB | moofC
+	  The problem was that PTS(buf) was used as the base timestamp for
+	  all 3 moofs, causing all buffers to be X based. In this case we want
+	  only moofA to be X based as it is what the PTS on buf means, and the
+	  other moofB and moofC just use the accumulated timestamp from the
+	  previous moofs durations.
+	  To solve this, this patch uses gst_adapter_prev_pts distance
+	  result, this allows qtdemux to calculate if it should use the
+	  resulting pts or just accumulate the samples as it can identify
+	  if the moofs belong to the same upstream buffer or not.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=719783
+
+2013-11-21 12:29:28 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: add support for multi-planar V4l2 API in DMABUF mode
+	  Fixes bug https://bugzilla.gnome.org/show_bug.cgi?id=712754
+
+2013-11-19 17:16:27 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2: refactor by emulating one v4l2_plane in non-MPLANE mode
+	  so that the buffer informations can be retrieved the same way
+	  in both MPLANE and non-MPLANE mode.
+	  Here "emulating" means "manually fill in the plane".
+	  Fixes bug https://bugzilla.gnome.org/show_bug.cgi?id=712754
+
+2013-11-13 12:05:40 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: add support for multi-planar V4L2 API
+	  This api is in linux kernel since version 2.6.39,
+	  and present in all version 3.
+	  The commit that adds the API in master branch of the
+	  linux kernel source is:
+	  https://github.com/torvalds/linux/commit/f8f3914cf922f5f9e1d60e9e10f6fb92742907ad
+	  v4l2 doc: "Some devices require data for each input
+	  or output video frame to be placed in discontiguous
+	  memory buffers"
+	  There are newer structures 'struct v4l2_pix_format_mplane'
+	  and 'struct v4l2_plane'.
+	  So the pixel format is not setup with the same API when using
+	  multi-planar.
+	  Also for gst-v4l2, one of the difference is that in GstV4l2Meta
+	  there are now one mem pointer for each maped plane.
+	  When not using multi-planar, this commit takes care of keeping
+	  the same code path than previously. So that the 2 cases are
+	  in two different blocks triggered from V4L2_TYPE_IS_MULTIPLANAR.
+	  Fixes bug https://bugzilla.gnome.org/show_bug.cgi?id=712754
+
+2013-12-04 09:12:07 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstsbcparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	  audioparsers: don't leak template caps
+
+2013-12-03 21:41:28 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstsbcparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	* tests/check/elements/aacparse.c:
+	  audioparsers: use ACCEPT_INTERSECT flag
+	  The parser can accept input that is not completely specified. Use the
+	  ACCEPT_INTERSECT flag on the sinkpad to tweak the acceptcaps function to
+	  check for intersection only. This allows us to proxy downstream
+	  constraints while still allowing non-subset caps as input.
+	  We can then also remove the appended template caps workaround.
+	  Make a unit-test to check the new feature.
+	  This reverts commit 26040ee38cb9e7c42f3d9a0282b3e5cace7ca42d
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=705024
+
+2013-12-03 21:36:54 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstsbcparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	  audioparsers: remove fields from filter
+	  We need to remove the fields from the filter when we can convert
+	  between them.
+
+2013-12-03 21:29:13 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstsbcparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	  audioparsers: refactor code to remove caps fields
+
+2013-12-02 00:10:43 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: microoptimisation: avoid some unnecessary GValue copies
+
+2013-12-01 23:32:20 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: fix off-by-one crash when downstream caps contain a list of framerates
+	  https://bugzilla.gnome.org/show_bug.cgi?id=719544
+
+2013-11-29 11:26:05 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Use the timestamp of the moof as the base fragment start
+	  In SmoothStreaming fragmented scenario, the timestamps are calculated
+	  starting from the fragment buffer timestamp. When there is a not-linked
+	  return from downstream, qtdemux will return upstream and will keep the
+	  non-pushed data into its adapter.
+	  On a new fragment buffer pushed to qtdemux, the new buffer timestamp
+	  would overwrite the previous one that should be used on the still
+	  to be pushed buffers. Because of this, this patch will also
+	  update the fragment_start timestamp from the adapter last pts
+	  to make sure the moof and timestamps are in sync and will result
+	  in correct timestamps for all fragments.
+
+2013-11-15 08:54:07 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: avoid re-reading the same moov and entering into loop
+	  In the scenario of "mdat | moov (with fragmented artifacts)" qtdemux
+	  could read the moov again after the mdat because it was considering the
+	  media as a fragmented one.
+	  To avoid this loop this patch makes it store
+	  the last processed moov_offset to avoid parsing it again.
+	  And it also checks if there are any samples to play before
+	  resturning to the mdat, so that it knows there is new data to be played.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=691570
+
+2013-11-15 00:52:53 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: do not free streams if they were not created locally
+	  When parsing a trak only free streams on failures if those streams
+	  were created locally. They could have been created from a previous
+	  fragment, in this case we they have valid info from the other fragment.
+	  Including pads.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=691570
+
+2013-11-29 19:57:46 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/videomixer/blend.c:
+	  videomixer: Simplify NV12/21 blending code macros
+
+2013-11-29 19:50:24 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/videomixer/blend.c:
+	  videomixer: Fix segfault when filling the background of a UYVY frame
+	  https://bugzilla.gnome.org/show_bug.cgi?id=712401
+
+2013-11-29 09:21:52 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix compilation with gst debuging disabled
+	  qtdemux.c:9452:1: error: label at end of compound statement
+
+2013-11-27 17:02:00 +0100  Jonas Holmberg <jonashg@axis.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: Map inbuffer once only
+	  Do not call gst_buffer_extract() twice since each call will map and
+	  unmap the biffer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=719434
+
+2013-11-28 11:58:42 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/elements/videofilter.c:
+	  videoflip: Add unit test for the 'automatic' method
+	  These new tests send a tag event before seding the buffer. Tested case are an
+	  empty tag list, a tag list with orientation-180 set and an invalid orientation value.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=719497
+
+2013-11-28 16:09:04 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: don't crash on tag events without orientation tag
+	  Would crash in g_free() trying to free an uninitialised pointer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=719497
+
+2013-11-28 16:50:42 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: don't unref buffer twice
+	  Cleaning the packet info will already unref the buffer.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=715078
+
+2013-11-28 22:35:02 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Add HydrogenAudio ReplayGain tags
+	  Identical to the itunes (tm) version, but labelled with
+	  org.hydrogenaudio.replaygain as the producer.
+
+2013-11-27 16:15:12 +0100  Mathieu Duponchelle <mduponchelle1@gmail.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: explicitly fail when alpha information would have been lost.
+
+2013-05-29 16:06:05 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* .gitignore:
+	  gitignore: Updated to ignore *.swp and .dirstamp
+
+2013-11-26 11:17:42 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: Allow a bit more variation when detecting common framerates
+	  Instead of +/- 1ns we allow 2ns now. Due to rounding errors there are
+	  some Matroska files out there with 33.333331ms per frame for 30fps.
+
+2013-11-26 10:20:31 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: Use gst_util_double_to_fraction() instead of GValue magic
+
+2013-11-25 14:03:21 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: Set default method at contruction
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=712333
+
+2013-05-29 15:57:09 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Use space instead of tabs
+	  https://bugzilla.gnome.org/show_bug.cgi?id=712754
+
+2013-05-29 15:44:31 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2object: Fix header indentation so it's readable again
+	  It's unfortunate to have to do this, but with the mix of tabs and space, plus all the random
+	  indentation this header has become very hard to read.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=712754
+
+2013-11-25 17:38:06 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  check: fix jitterbuffer check
+	  Don't advance the clock to 240ms too early.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=710013
+
+2013-11-25 11:45:33 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: deprecate max-errors
+	  The property wasn't use internally, let the base class handle the
+	  number of errors to tolerate.
+
+2013-11-25 15:49:07 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: improve clear-pt-map handling
+	  Don't reset the expected output seqnum when clearing the pt map because this
+	  could stall the jitterbuffer forever.
+	  Add a unit test for this.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=709800
+
+2013-10-28 21:33:22 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: let the base class decide when to return an error
+	  The base videodecoder class has an error counting feature to tolerate
+	  a few errors before posting an error message. So don't force the
+	  error and let the base class decide when it should happen
+	  https://bugzilla.gnome.org/show_bug.cgi?id=710762
+
+2013-10-28 21:28:33 -0300  Thiago Santos <ts.santos@sisa.samsung.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Add data skipping on input
+	  Add missing bytes skipping when bad input is received.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=710762
+
+2013-11-25 12:13:43 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Discard 2 byte subpicture packets
+	  As for text subtitles and as suggested in #712643, throw
+	  away the 2 byte terminator packets that some encoders insert.
+	  This will make things better when remuxing and causes generation
+	  of gap events.
+
+2013-11-25 00:34:21 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: fix wake-up when new buffers come in after running empty
+	  Spotted by 'gratias' on IRC. Probably introduced in recent refactoring.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=715039
+
+2013-11-23 12:15:40 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: correctly handle negative relative timestamps
+	  ... rather than scaling these as unsigned.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=712744
+	  Based on patch by Krzysztof Kotlenga <pocek@users.sf.net>
+
+2013-09-14 03:27:09 +0200  MathieuDuponchelle <mathieu.duponchelle@epitech.eu>
+
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	  videomixer2: Merge tag events to send them in collected.
+	  Otherwise there were race conditions where we would send tags
+	  on a flushing srcpad.
+	  We have a test for that in GES, but this should be tested
+	  systematically with harness in the future as I believe it
+	  is useful for exactly that kind of cases.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=708165
+
+2013-11-14 17:29:50 -0300  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Use GstVideoInfo helper to create caps for raw video
+	  This way we do not miss mandatory fields in caps.
+	  At the same time use the gst_pb_utils_get_codec_description
+	  helper to get codec description.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=712335
+
+2013-11-14 16:11:38 -0300  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* gst/matroska/Makefile.am:
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Use GstVideoInfo helper to create caps for raw video
+	  This way we do not miss mandatory fields in caps.
+	  At the same time use the gst_pb_utils_get_codec_description helper to
+	  get codec description.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=712328
+
+2013-11-13 20:18:17 -0300  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/multifile/gstmultifilesrc.h:
+	  multifilesrc: Implement seeking in case of multiple images
+	  https://bugzilla.gnome.org/show_bug.cgi?id=712254
+
+2013-11-22 12:26:21 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: pass downstream flowreturn to upstream
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=712722
+
+2013-11-18 14:27:48 +0100  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: clear cached caps on close
+	  A different device with different caps may be used for the next open.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=712611
+
+2013-11-21 15:30:34 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/wavpack/gstwavpackcommon.c:
+	* ext/wavpack/gstwavpackstreamreader.c:
+	* gst/apetag/gstapedemux.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/isomp4/atoms.c:
+	* gst/matroska/matroska-demux.c:
+	  g_memmove() is deprecated
+	  Just use plain memmove(), g_memmove() is deprecated in
+	  recent GLib versions.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=712811
+
+2013-11-21 11:32:15 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	  rtpvorbisdepay: handle packets > 0xffff
+	  Handle input packet sizes larger than 16 bits in the depayloader.
+	  Remove size restrictions on the payloader.
+
+2013-11-21 11:30:28 +0100  Wim Taymans <wtaymans@redhat.com>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	  rtptheoradepay: handle packets > 0xffff
+	  Reorganize some things in the depayloader so that it can handle packets larger
+	  than 16 bits.
+	  Remove the size restriction on the payloader.
+
+2013-11-21 02:28:27 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_dump.c:
+	* gst/isomp4/qtdemux_types.c:
+	  isomp4: Handle mp4s subpicture streams better.
+	  Clean up the handling of mp4s streams. Use the generic esds
+	  descriptor function to extract the palette, instead of hard coding
+	  a wrong magic offset.
+	  Add some more size safety checks when parsing ES descriptors, and
+	  replace magic numbers with the descriptive constants that are already
+	  defined.
+	  Enhance dump output for stsd atoms.
+	  Streams from both bug 712643 and historic bug 568278 now both work
+	  correctly.
+	  Fixes: #712643
+
+2013-11-20 22:08:25 +1100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/isomp4/fourcc.h:
+	  qtdemux: Sort fourcc declarations and remove duplicates
+
+2013-11-20 21:41:47 +1100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/isomp4/Makefile.am:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/ftypcc.h:
+	* gst/isomp4/gstqtmuxmap.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_dump.c:
+	* gst/isomp4/qtdemux_fourcc.h:
+	* gst/isomp4/qtdemux_types.c:
+	  qtdemux: Merge all the fourcc headers into one
+	  Remove qtdemux_fourcc.h and ftypcc.h and put it all in fourcc.h
+
+2013-11-19 10:10:51 +0100  Wim Taymans <wim.taymans@gmail.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: avoid mapping the buffer
+	  Reuse the parsed structure to get the timestamps.
+
+2013-11-18 17:13:49 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix 'make check'
+	  Fix generic/states check. Also, g_return_if_fail() is
+	  not for internal state checking.
+
+2013-11-18 14:44:36 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiopanorama.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/flv/gstflvmux.c:
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesink.h:
+	* gst/multifile/gstsplitfilesrc.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/smpte/gstsmptealpha.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/videobox/gstvideobox.c:
+	* gst/wavparse/gstwavparse.c:
+	* sys/oss4/oss4-sink.c:
+	* sys/oss4/oss4-source.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/ximage/gstximagesrc.c:
+	  docs: get rid of 'Since: 0.10.x' markers
+	  And some gtk-doc markup fixes.
+
+2013-11-16 12:15:14 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	  rtpmanager: fix Since markers
+	  Should be next stable release series version
+
+2013-11-15 13:48:07 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Fix stats property field names and documentation
+
+2013-11-15 15:20:14 +0100  Torrie Fischer <torrie.fischer@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpstats.c:
+	* gst/rtpmanager/rtpstats.h:
+	  gstrtpsession: Implement a number of feedback packet statistics
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=711693
+
+2013-11-13 17:11:08 -0300  Thiago Santos <ts.santos@partner.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: remove math operation from loop
+	  The elst_offset doesn't change inside the loop, so compute it
+	  outside
+
+2013-11-14 20:54:32 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/isomp4/qtdemux.c:
+	  qtmux: fix playback regression
+	  In ae1150e85cf99d7482933aa6f7e4f012fe45a3ec flipping a condition misaligned the
+	  else branch, where for there condition that was change there is none.
+	  Fixes #712303
+
+2013-11-14 09:20:06 +0100  Wim Taymans <wim.taymans@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: rename property to 'stats'
+	  This makes the unit test work.
+	  We can later also add more stats, not specific to retransmission.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=711411
+
+2013-11-12 11:19:25 -0500  Torrie Fischer <torrie.fischer@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: implement rtx statistics
+
+2013-11-13 10:42:21 +0000  Marc Leeman <marc.leeman@gmail.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: print FOURCC_FORMAT when enumerating
+	  https://bugzilla.gnome.org/show_bug.cgi?id=712206
+
+2013-11-06 12:40:06 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: advance expected seqnum after dropping
+	  After dropping a buffer, move our expected seqnum
+	  Conflicts:
+	  gst/rtpmanager/gstrtpjitterbuffer.c
+
+2013-11-04 15:46:22 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  gstpay: only send one caps
+	  Only send one caps in a packet. Two caps can happen when setcaps is called and
+	  the config-interval expires at the same time.
+
+2013-11-13 10:23:19 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Use the synced buffer mode in auto mode if a clock provider is in the SDP
+
+2013-11-08 11:09:21 +0000  Marc Leeman <marc.leeman@gmail.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: init v4l2_buffer to 0x0 before ioctl
+	  https://bugzilla.gnome.org/show_bug.cgi?id=712137
+
+2013-11-11 15:27:18 +0100  Wim Taymans <wim.taymans@gmail.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: remove collision reconfigure event
+	  Remove bogus reconfigure event on collision, we don't want to send the event on
+	  the receiving RTP pad and the collision event is now handling this
+	  case.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=711560
+
+2013-11-01 17:04:28 +0000  Julien Isorce <julien.isorce@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  gstrtpsession: send custom upstream event "GstRTPCollision" on send_rtp_sink pad
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=711560
+
+2013-11-11 14:25:51 +0100  Wim Taymans <wim.taymans@gmail.com>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/rtpsession.c:
+	  check: add rtpsession test
+	  Add a basic rtpsession test to ensure that RR blocks are generated when
+	  multiple SSRC senders are active.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=711270
+
+2013-11-11 13:17:25 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: correctly handle timestamps when parsing x-private1-ac3
+	  ... the way it has always worked fine in a52dec.
+
+2013-11-05 10:48:33 +0200  George Kiagiadakis <george.kiagiadakis@collabora.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: fix crash when do-retransmission=true and a lot of buffers are lost
+	  The problem here was that the jitterbuffer lock was unlocked to push
+	  the event, but that caused another thread to remove the timer currently
+	  being processed, probably because the amount of rtx events
+	  (and therefore timers) was getting too high. The solution is to
+	  unlock and push the event only after timer processing has finished.
+	  fixes https://bugzilla.gnome.org/show_bug.cgi?id=711131
+
+2013-10-24 13:16:42 +0200  Per x Johansson <perxjoh@axis.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Avoid division by zero assert in gst_matroska_demux_search_pos
+	  https://bugzilla.gnome.org/show_bug.cgi?id=711829
+
+2013-11-08 17:59:24 +0100  Philippe Normand <philn@igalia.com>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: generate a non-empty data header
+	  Restore the behavior of the element to the state before commit
+	  db29522a430e44450415ca3676abd1b77ee923d9. A non-empty header is
+	  generated and when the EOS event is received the header is generated
+	  again, this time with the correct size.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=711699
+
+2013-11-07 16:17:16 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: update receiver stats for sender
+	  An internal sender in a session is also a receiver of its own packets so update
+	  the receiver stats. Other senders in the session will use this info to generate
+	  correct RB blocks in their SR reports.
+
+2013-11-07 16:13:16 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: refactor receiver stats update
+
+2013-10-25 18:22:00 -0300  Thiago Santos <ts.santos@partner.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: handle fragmented files with mdat before moofs
+	  Assume a file with atoms in the following order: moov, mdat, moof,
+	  mdat, moof ...
+	  The first moov usually doesn't contain any sample entries atoms (or
+	  they are all set to 0 length), because the real samples are signaled
+	  at the moofs. In push mode, qtdemux parses the moov and then finds the mdat,
+	  but then it has 0 entries and assumes it is EOS.
+	  This patch makes it continue parsing in case it is a fragmented file so that
+	  it might find the moofs and play the media.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=710623
+
+2013-10-25 11:42:37 -0300  Thiago Santos <ts.santos@partner.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: When using a buffered mdat, store all received data for later use
+	  In push mode, when qtdemux can't use a seek to skip the mdat buffer it has
+	  to buffer it for later use.
+	  The issue is that after parsing the next moov/moof, there might be some
+	  trailing bytes from the next atom in the file. This data was being discarded
+	  along with the already parsed moov/moof and playback would fail to continue
+	  after the contents of this moov/moof are played.
+	  This is particularly bad on fragmented files that have the mdat before the
+	  corresponding moof. So you'd get:
+	  mdat|moof|mdat|moof ...
+	  When a moof was received, it usually came with some extra bytes that would
+	  belong to the next mdat (because upstream doesn't care about atoms alignment).
+	  So those bytes were being discarded and playback would fail.
+	  This patch makes qtdemux store those extra bytes to reuse them later after the
+	  mdat is emptied.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=710623
+
+2013-11-07 09:49:55 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: Also use the bind-port property if no bind-address was given
+
+2013-11-07 00:51:12 +0100  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxaudio/gstosxcoreaudiohal.c:
+	  osxaudiosink: fix segfault when we can't get the channels layout
+
+2013-11-05 17:26:49 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8pay: Make Picture ID mode configurable and default to no picture ID
+	  Some implementations (linphone) only support no picture at all in the
+	  stream and will fail if one is provided.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=711497
+
+2013-11-05 11:18:34 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From 865aa20 to dbedaa0
+
+2013-01-29 10:51:07 +0100  Paul HENRYS <visechelle@gmail.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  Add call to gst_rtp_h264_pay_clear_sps_pps() when receiving a STREAM_START event
+	  https://bugzilla.gnome.org/show_bug.cgi?id=692787
+
+2013-11-02 22:50:47 +0100  Rico Tzschichholz <ricotz@ubuntu.com>
+
+	* gst/rtsp/Makefile.am:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtsp: Add missing gio-2.0 deps and includes
+
+2013-11-01 18:31:36 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audiofx/audioiirfilter.c:
+	  audioiirfilter: Fix initialization coefficient handling
+	  Broke unit test.
+
+2013-10-31 14:05:43 -0700  Aleix Conchillo Flaque <aleix@oblong.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: allow setting tls certificate validation flags
+	  Added a new property "tls-validation-flags". If the url transport is
+	  TLS, the validation flags will be set to the rtsp connection.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=711230
+
+2013-10-31 22:43:49 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/audiofx/audiofxbaseiirfilter.c:
+	* gst/audiofx/audioiirfilter.c:
+	  audioiirfilter: Don't crash if no filter coefficients are provided
+	  ...and by default use a identity filter.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=710215
+
+2013-10-31 19:15:12 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* ext/wavpack/gstwavpackenc.c:
+	  wavpackenc: Fix writing of MD5 sums and other metadata blocks
+	  These don't have the FINAL_BLOCK flag set.
+
+2013-10-31 13:02:11 -0200  Djalma Lúcio Soares da Silva <dlucio@impa.br>
+
+	* ext/raw1394/gsthdv1394src.c:
+	  hdv1394src: Make it possible to select a camera by its GUID
+	  The source hdv1394src has the guid property that permits select a camera
+	  connected from its GUID number.
+	  However when this property is setted the selected camera is not changed.
+	  The source continues using the default camera.
+	  This problem was solved using the function iec61883_cmp_connect.
+	  The reference for the function could be found here:
+	  http://www.dennedy.org/libiec61883/API-iec61883-cmp-connect.html
+	  The solution came from dvgrab source code.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=710415
+
+2013-10-31 13:20:41 -0300  Thiago Santos <ts.santos@partner.samsung.com>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: souphttpsrc: add explicit cast to silence warning
+	  Silencing this warning:
+	  elements/souphttpsrc.c:533:14: error: comparison between ‘SoupKnownStatusCode’ and ‘enum <anonymous>’ [-Werror=enum-compare]
+	  if (status != SOUP_STATUS_OK && !send_error_doc)
+	  With gcc 4.8.2 (debian)
+
+2013-10-31 10:38:35 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: proxy new buffer mode
+
+2013-10-30 16:49:36 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  jitterbuffer: add new timestamp mode
+	  Add a new timestamp mode that assumes the local and remote clock are
+	  synchronized. It takes the first timestamp as a base time and then uses the RTP
+	  timestamps for the output PTS.
+
+2013-10-30 22:12:45 +0100  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: Fix compiler warning
+	  matroska-demux.c: In function 'gst_matroska_demux_add_stream':
+	  matroska-demux.c:1379:7: error: format '%u' expects argument of type 'unsigned int', but argument 4 has type 'guint64' [-Werror=format=]
+	  "%03u", context->uid);
+	  ^
+
+2013-10-28 13:21:15 +0000  Matthieu Bouron <matthieu.bouron@collabora.com>
+
+	* gst/videomixer/videoconvert.c:
+	  videomixer: remove unneeded guint comparaison
+	  https://bugzilla.gnome.org/show_bug.cgi?id=711010
+
+2013-10-28 14:13:12 +0000  Matthieu Bouron <matthieu.bouron@collabora.com>
+
+	* sys/osxvideo/cocoawindow.h:
+	* sys/osxvideo/cocoawindow.m:
+	  osxvideosink: fix missing selector name warnings
+	  The spaces matter in ObjC
+	  https://bugzilla.gnome.org/show_bug.cgi?id=711013
+
+2013-10-28 13:31:34 +0000  Matthieu Bouron <matthieu.bouron@collabora.com>
+
+	* gst/y4m/gsty4mencode.c:
+	  y4menc: fix uninitialized variable warning
+	  https://bugzilla.gnome.org/show_bug.cgi?id=711011
+
+2013-10-25 11:30:36 -0300  Thiago Santos <ts.santos@partner.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: check if the end_time is defined before using it
+	  Avoids sending EOS too soon because of overflow. Can happen on
+	  fragmented mp4 playback.
+
+2013-10-23 13:38:20 -0300  Thiago Santos <ts.santos@partner.samsung.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: use correct unref function
+	  Events aren't GstObjects, but GstMiniObjects
+
+2013-10-15 08:16:20 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: rename chunks_are_chunks to chunks_are_samples and flip the logic
+	  As the variable name suggests, sometimes chunks are chunks. Rename the variable
+	  to tell what they are when they are not chunks.
+
+2013-10-09 08:04:20 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix typos and add more logging for unhandled parts
+
+2013-10-14 16:23:25 +0200  Ognyan Tonchev <ognyan@axis.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: Fix memory leak
+	  Unmap all GstMemory of the current buffer when flushing.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=710110
+
+2013-10-12 20:44:31 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: fix broken sample pipeline
+	  which was muxing raw audio and video into flvmux, which won't work,
+	  even if there were converters.
+
+2013-10-12 20:37:41 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: require stream-format=raw for mpeg-2 too, but don't require framed field
+	  raw implies that it's framed already. Fixes .. ! faac ! flvmux
+
+2013-10-07 14:27:21 -0300  Thiago Santos <ts.santos@partner.samsung.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: do not emit EOS when connection drops
+	  If the pipeline is stalled for too long, souphttpsrc will block and
+	  stop fetching data from the network. This can cause the connection to
+	  drop and souphttpsrc would handle it as an EOS. This patch makes it
+	  persist and try to fetch more data until the end of the content length
+	  or until receiving an error that it is beyong limits in case the content
+	  is unknown.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=683536
+
+2013-10-10 13:52:35 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ext/dv/gstdvdec.c:
+	* ext/dv/gstdvdec.h:
+	  dvdec: Don't send segment event before caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709728
+
+2013-10-09 17:46:33 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: Send stream-start, caps and segment events in the right order
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709728
+
+2013-10-08 11:28:04 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: A-Law and Mu-Law don't have width/depth/signed caps fields
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709614
+
+2013-10-07 12:54:11 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/deinterlace/tvtime/greedyh.c:
+	  deinterlace: Fix handling of planar video formats in greedyh method
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709507
+
+2013-10-06 10:01:26 -0700  Reynaldo H. Verdejo Pinochet <r.verdejo@partner.samsung.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroska: Trivial grammar fix on debug msg
+
+2013-10-06 09:17:00 -0700  Reynaldo H. Verdejo Pinochet <r.verdejo@partner.samsung.com>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	* gst/matroska/webm-mux.c:
+	  matroskamux: Add context flag for WebM
+	  WebM has a couple of specific requirements we need to handle.
+	  Idea is to set this flag once and just rely on mux->is_webm
+	  at run time instead of repeatedly figuring this out from
+	  GST_MATROSKA_DOCTYPE_WEBM (which requires a strcmp()).
+
+2013-10-04 14:42:59 -0700  Reynaldo H. Verdejo Pinochet <r.verdejo@partner.samsung.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroska: Do not write SegmentUID for WebM mux
+	  WebM spec states SegmentUID is Unsupported. Files produced
+	  with gstreamer without this change will spit an error like
+	  this when passed to mkvalidator:
+	  ERR201: Invalid 'SegmentUID' for profile 'webm' in Info at 192
+
+2013-10-05 00:00:03 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: make dvd palette change event sticky
+	  So they don't get lost.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709454
+
+2013-10-03 16:39:26 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videofilter/gstvideoflip.h:
+	  videoflip: Add automatic flip mode driven by image-orientation tag
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709312
+
+2013-10-04 13:34:09 +0200  Peter Korsgaard <peter@korsgaard.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: O_CLOEXEC needs _GNU_SOURCE
+	  On some systems (E.G. uClibc and older Glibc versions), O_CLOEXEC is only
+	  defined when _GNU_SOURCE is specified, so do so.
+	  _GNU_SOURCE needs to be defined before any system headers are included,
+	  so move the fcntl.h section up.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709423
+
+2013-10-04 12:11:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: fix race in flush-start/flush-stop
+	  When flush-stop arrives before we process the result of the _push() in the
+	  loop function, we might pause even though we are not flushing anymore. Fix this
+	  race by waiting for the srcpad loop function to completely pause after doing the
+	  flush-start.
+
+2013-10-03 22:38:43 +0200  Mathieu Duponchelle <mduponchelle1@gmail.com>
+
+	* gst/videomixer/videoconvert.c:
+	  videomixer: Update videoconvert copy
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709390
+
+2013-10-03 21:36:34 +0200  Mathieu Duponchelle <mduponchelle1@gmail.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Check if the pad needs reconfiguration in collected
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709384
+
+2013-10-03 14:39:35 +0100  Matthieu Bouron <matthieu.bouron@collabora.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Relax sink caps
+	  Since jpegdec already parse the jpeg stream, the sink caps could be
+	  relaxed. This will allow jpegdec to be selected in more case and in
+	  particular when the jpeg typefinder does not find the width and height.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709352
+
+2013-10-03 18:33:01 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2src: print probed caps as caps again in debug log
+	  This got lost during refactoring.
+
+2013-10-03 11:59:25 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Add support for the mp2v fourcc for MPEG-2 video
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709270
+
+2013-10-02 15:56:53 +0200  Ognyan Tonchev <ognyan@axis.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Fix memory leak
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709266
+
+2013-09-30 12:31:42 +0300  Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_fourcc.h:
+	* gst/isomp4/qtdemux_types.c:
+	  qtdemux: Add HEVC support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709093
+
+2013-09-30 12:24:32 +0200  Ognyan Tonchev <ognyan@axis.com>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: Fix memory leak
+	  We were leaking the GList nodes of the pending buffers.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=709079
+
+2013-09-30 12:31:00 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  rtpjitterbuffer: fix race when updating the next_seqnum
+	  If we were not waiting for the missing seqnum when we insert the lost packet
+	  event in the jitterbuffer, we end up not updating the next_seqnum and wait
+	  forever for the lost packets to arrive. Instead, keep track of the amount of
+	  packets contained by the jitterbuffer item and update the next expected
+	  seqnum only after pushing the buffer/event. This makes sure we correctly handle
+	  GAPS in the sequence numbers.
+
+2013-09-30 12:30:23 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: small debug improvement
+
+2013-09-30 11:53:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: reset skew does not reset clock-rate
+	  Don't reset the clock-rate when we reset the skew correction algorithm.
+	  Reset the skew correction algorithm when we change the clock-rate.
+
+2013-09-30 11:16:32 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: pause timer when PAUSED
+	  Also pause the timer when we go to the PAUSED state. It is possible that we
+	  don't have a clock or base-time in PAUSED to perform the timeouts.
+
+2013-09-30 11:15:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: improve debug
+
+2013-09-26 20:41:26 +0200  Hans Månsson <hansm@axis.com>
+
+	* gst/isomp4/gstqtmuxmap.c:
+	  mp4mux: Do not require framerate in peer video caps
+	  Remove the framerate restriction on the caps.
+	  Reference: https://bugzilla.gnome.org/show_bug.cgi?id=708864
+
+2013-09-27 15:05:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: also go into the loop function after connect
+	  When we have opened the stream, go into the loop function so that we can
+	  receive messages from the server.
+
+2013-09-27 12:53:06 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: move the check for subtitle buffer being null terminated before validating UTF-8
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707933
+
+2013-09-26 16:20:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: don't calculate skew without rtptime
+	  Skip trying to calculate the skew when we don't have an rtptime.
+	  It causes problems when lost packet events are placed in the jitterbuffer.
+
+2013-09-25 23:46:14 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* configure.ac:
+	  configure: get rid of AS_SCRUB_INCLUDE
+	  Should not be needed any more.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707658
+
+2013-09-25 17:42:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: disable checks when linking pads
+	  We know the pad links will work (and we don't check the return value
+	  anyway).
+
+2013-09-25 17:36:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: avoid some pad link checks
+	  Link pads without checks, we know it will work.
+
+2013-09-25 12:55:21 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Don't error out if downstream is not seekable for non-fragmented variants
+	  Doing so would be a regression over 1.0 and breaks the unit test.
+	  However the result will be most likely unusable, so let's post
+	  a warning message on the bus.
+
+2013-09-24 04:02:09 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: calculate some stats
+
+2013-09-23 17:05:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: move send_lost_event function
+	  Move the send_lost_event function to the do_lost_event handling, there is no
+	  need to have a separate function.
+
+2013-09-16 11:20:51 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: add code to parse creation time earlier than 1970
+	  Use g_date_time seconds manipulation to allow to cover the quicktime
+	  spec for creation_time. It uses seconds since 1904.
+	  Both paths could be done using the generic approach of seconds since
+	  1904 with GDateTime handling, but the first path using seconds from
+	  1970 should be more commonly found and avoids a few objects creation and
+	  ref/unref, so keep it there for performance.
+	  Additionally, the code for handling seconds since 1970 changed from >
+	  to >= because having 0 seconds since 1970 is also a valid case for that
+	  path to handle.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707975
+
+2013-09-21 00:55:26 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: update stream->pos when sending buffers so that gap events are not sent unnecessarily
+	  https://bugzilla.gnome.org/show_bug.cgi?id=708505
+
+2013-09-24 18:30:04 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* README:
+	* common:
+	  Automatic update of common submodule
+	  From 6b03ba7 to 865aa20
+
+2013-09-24 15:05:24 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* configure.ac:
+	  configure: Actually use 1.3.0.1 as version to make configure happy
+
+2013-09-24 15:00:24 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.2.0 ===
+
+2013-09-24 14:21:08 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.2.0
+
+2013-09-24 14:20:51 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2013-09-20 19:43:21 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: fix segfault releasing the sink
+	  show_frame is deferred to the main thread and can be called
+	  when the sink has been released, so we need to keep an extra ref
+	  on ObjectiveC object helper.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=708501
+
+2013-09-19 17:11:34 -0400  Robert Krakora <rob.krakora@messagenetsystems.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Restore original GstMemory in buffer if it has been changed
+	  https://bugzilla.gnome.org/show_bug.cgi?id=706083
+
+2013-09-23 16:34:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpmanager: update docs
+
+2013-09-23 15:36:32 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  docs: update docs with 1.0 element names
+
+2013-09-23 14:13:30 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: add test for retransmission because of reordering
+
+2013-09-23 14:12:03 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: always store lost event in jitterbuffer
+	  Always prepare a lost event in the jitterbuffer, it is to wake up and make the
+	  pushing thread continue. We drop the event when we are not supposed to push lost
+	  events downstream.
+
+2013-09-23 11:18:46 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: schedule lost event differently
+	  Schedule the lost event by placing it inside the jitterbuffer with the seqnum
+	  that was lost so that the pushing thread can interleave and push it properly.
+
+2013-09-23 11:17:34 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: remove timeouts from check
+	  Timeouts make the test unreliable and are not needed.
+
+2013-09-23 11:15:30 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: remove list debug
+
+2013-09-23 11:14:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  rtpjitterbuffer: add type to the item
+	  So that the upper layer can know what data is contained in the item.
+
+2013-09-23 09:58:32 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  rtpjitterbuffer: fix flush
+	  Pass function to flush to properly free the queue items.
+
+2013-09-21 00:08:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: append seqnum -1 packets
+
+2013-09-20 23:48:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  rtpjitterbuffer: use structure to hold packet information
+	  Make the jitterbuffer operate on a structure containing all the packet
+	  information. This avoids mapping the buffer multiple times just to get the RTP
+	  information. It will also make it possible to store other miniobjects such as
+	  events later.
+
+2013-09-20 17:48:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: update expected timer when possible
+	  When we receive a packet and we have some missing packets, we can update their
+	  estimated arrival times based on the timestamp difference.
+
+2013-09-20 17:18:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: fix order of timeout events
+	  Improve the order of the timeout events, if there are timers with the same
+	  timeout, we want to trigger the lowest seqnum first. For this we need to loop
+	  over the complete array of timers to find the best one before triggering the
+	  timeout.
+
+2013-09-20 16:58:38 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: send lost event before signaling next buffer
+	  First send the lost event, then update the next_seqnum counter and then
+	  send the signal to the pushing thread that it can retry to push a buffer. This
+	  avoids pushing out buffers before the lost event is pushed.
+
+2013-09-20 15:35:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  jitterbuffer: configure clock-rate on jitterbuffer
+	  Add a get and setter to configure the clock-rate in the jitterbuffer instead of
+	  passing it as an argument to the insert method.
+
+2013-09-20 12:29:39 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: add test for packet delay and retransmission
+
+2013-09-20 12:27:26 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: add option to reset retransmission timers
+
+2013-09-20 12:25:43 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: stop the timer thread
+	  The timeout code could release the lock so we need to check if we are allowed to
+	  wait for the clock some more.
+
+2013-09-20 12:25:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: unlock only once
+
+2013-09-20 11:30:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: check both PTS and DTS
+
+2013-09-20 10:55:03 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: add unit-test for multiple missing packets
+	  Check if multiple missing packets generate retransmission events and that the
+	  retranmission requests are canceled when the missing packet arrives.
+
+2013-09-20 10:53:29 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: improve flush and shutdown
+	  There is no need to unschedule the timer in flush-start, flush-stop will remove
+	  the timers and unschedule.
+	  Unschedule the current timer before attempting to join the timer thread.
+
+2013-09-20 10:43:53 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: improve debug
+
+2013-09-20 10:42:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: set correct expected time
+	  When we already have a timer for a packet, skip it but don't forget to adjust
+	  the dts to the expected dts of the next packet.
+
+2013-09-20 10:41:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: improve debug
+
+2013-09-19 16:55:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: use POFFSET instead of OFFSET
+	  Use the more correct POFFSET macro to get the offset of a component in its
+	  plane. The offset macro gives the offset of the component relative to the start
+	  of the frame.
+
+2013-09-21 18:46:29 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/goom/mmx.h:
+	  goom: Fix MMX assembly compilation with clang
+	  clang does not want or need a clobber list for emms:
+	  error: clobbers must be last on the x87 stack
+	  Patch taken from the FreeBSD ports, provided by
+	  Dan McGregor <dan.mcgregor@usask.ca>
+
+2013-09-20 16:16:57 +0200  Edward Hervey <edward@collabora.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From b613661 to 6b03ba7
+
+2013-09-20 10:19:22 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: Make sure that subtitle buffers are \0-terminated
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707933
+
+2013-09-17 12:17:54 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: handle issues correctly when downstream is not seekable
+	  The streamable property only make sense for fragmented formats.
+	  For regular MP4, when downstream is not seekable we can't rewrite
+	  the headers, so qtmux can only work with fast-start=TRUE, where
+	  the headers are written finishing the file.
+	  For fragmented MP4, when streamable is not seekable and the streamable
+	  property is FALSE, we must enforce streamable=TRUE warning the user
+	  about this change
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707242
+
+2013-09-17 12:06:06 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: make "streamable" TRUE as default
+	  The most common use case for fragmented MP4 (Dash and Smooth Streaming)
+	  is producing streamable content (even for VOD). streamable=FALSE would only
+	  be used to generate fragmented MP4 with and index of MOOF's that could
+	  be reproduced without a playlist/manifest
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707242
+
+2013-09-17 12:01:30 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: deprecate the streamable property for non-fragmented MP4
+	  The streamable property only makes sense for fragmented MP4.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707242
+
+2013-09-19 17:08:19 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2: Remove commented out line
+
+2013-09-19 18:43:08 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 74a6857 to b613661
+
+2013-09-19 17:35:27 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* autogen.sh:
+	* common:
+	  Automatic update of common submodule
+	  From 098c0d7 to 74a6857
+
+2013-09-19 16:50:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: don't assume planar formats have just 1 block
+	  Don't assume planar formats have just one memory block with the data but use the
+	  macros to access the right memory block where a component can be found.
+
+2013-09-19 14:14:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: add retransmission jitterbuffer test
+	  Store both DTS and PTS on buffers.
+	  Make a queue for srcpad events.
+	  Activate pads after linking so that we don't get RECONFIGURE events.
+	  Add test for retransmission.
+
+2013-09-19 14:12:18 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: keep delay as a separate variable in timer
+	  Keep a separate delay in the timer so that we still know the original timestamp
+	  of the packet that this timer refers to. We can then place the correct
+	  running-time in the Retransmission event.
+
+2013-09-19 14:08:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: fix writability of properties
+
+2013-09-19 11:34:57 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.1.90 ===
+
+2013-09-19 10:50:23 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.1.90
+
+2013-09-19 10:21:42 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2013-09-19 09:45:18 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* po/cs.po:
+	* po/nl.po:
+	* po/pl.po:
+	* po/uk.po:
+	* po/vi.po:
+	  po: Update translations
+
+2013-09-11 14:27:02 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: dmabuf is not a singleton anymore
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707793
+
+2013-09-16 13:53:45 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: do not do http requests in READY
+	  HEAD requests to discover if the server is seekable shouldn't be done in
+	  READY as it might lock the main thread that is doing the state change.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=705371
+
+2013-09-18 16:32:28 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: reevaluate the current timer after timeout
+	  When we trigger the timeout logic of a timer, reevaluate it because it is
+	  possible that it still has the lowest timeout.
+
+2013-09-18 16:31:26 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: don't update time when unscheduled
+	  Don't try to estimate the current time when we got unscheduled.
+
+2013-09-18 16:29:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: init packet spacing on first buffer
+	  Already init the packet spacing variables on the first buffer so that we can
+	  calculate the spacing on the second buffer already.
+
+2013-09-18 15:08:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: fix comments
+
+2013-09-18 14:57:09 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: push the lost event from the timer thread
+	  Instead of pushing the lost event from the chain function, schedule a timeout
+	  that will push the lost event from the timer thread. This avoid blocking the
+	  upstream thread while we push and sync the event.
+
+2013-09-18 14:23:55 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: add another test
+	  The test is modified slightly because the late lost packets are only
+	  generated now when a large gap is received.
+
+2013-09-18 14:12:47 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: round gap duration to multiple of duration
+	  Make sure the gap duration in the lost event is a multiple of the packet
+	  duration.
+	  Enable another test.
+
+2013-09-18 12:29:38 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: keep track of duration
+	  Keep track of the estimated duration of missing packets and use it in the lost
+	  event.
+	  Enable another unit test
+
+2013-09-18 11:59:28 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer: handle large gaps with one lost event
+	  When we have a large number of missing packets, generate one lost event for all
+	  the packets that have no chance of being pushed out in time.
+	  Fix and activate unit test for large gaps.
+
+2013-09-18 11:56:38 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: refactor lost event sending
+	  Also make sure we only increment the expected seqnum and last
+	  output timestamp.
+
+2013-09-17 23:21:09 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: refactor timeout triggers
+
+2013-09-17 23:03:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: simplify the timeout code
+	  Keep track of the current time in the timeout loop.
+	  Loop over all timers and trigger all the expired ones, we can do this in the
+	  same loop that selects the new best timer.
+
+2013-09-17 23:01:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: rearrange timer update code
+	  Also update the timers when retransmission is disabled. We need to
+	  do this because when we added LOST timers when we detected missing packets and
+	  we need to remove those timers when the packet finally arrives.
+
+2013-09-17 22:02:04 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/videomixer/Makefile.am:
+	  videomixer: link to libm for maths stuff
+	  Fixes undefined references to rint and pow on ubuntu
+	  build bot.
+
+2013-09-17 15:19:42 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: release lock on shutdown
+
+2013-09-17 15:11:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	  check: change for videomixer renamed orc file
+
+2013-09-14 16:03:20 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: remove MAX_TOLERATED_LATENESS
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707411
+
+2013-09-16 15:54:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/examples/rtp/client-H264-rtx.sh:
+	  examples: we don't need the queue anymore
+
+2013-09-16 15:53:47 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: use separate thread for timeouts
+	  Use a separate thread for scheduling the timeouts instead of using the
+	  downstream streaming thread that might block at any time.
+
+2013-09-14 15:56:04 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: set first_ts to DTS for streams that have DTS
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707340
+
+2013-09-14 15:55:22 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: make sure duration is a valid number for last buffer
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707340
+
+2013-09-14 15:54:29 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: use segment.start or last buffer end time in case of missing DTS
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707340
+
+2013-09-03 18:14:04 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  Revert qtmux: Use buffer PTS if DTS is not set"
+	  This reverts commit f72c3cf71fde622067f41f31a53978ba4c94469d.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707340
+
+2013-09-16 11:03:06 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/videomixer/videomixerorc-dist.c:
+	* gst/videomixer/videomixerorc-dist.h:
+	  videomixer: Update orc generated files
+	  https://bugzilla.gnome.org/show_bug.cgi?id=708131
+
+2013-09-13 16:25:49 +0200  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Demux RTCP buffers from the RTP stream
+	  If there are RTCP buffers in the RTP stream, process them as
+	  RTCP. This way, we want receive streams following RFC 5761
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687657
+
+2013-09-13 23:26:21 +1000  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/rtp/gstrtpL24depay.c:
+	  rtp: Remove bogus extra caps from L24 template.
+	  The extra caps entry in the template was making it sometimes
+	  get plugged for any dynamically allocated payload type.
+
+2013-09-13 12:40:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpbin: use PacketInfo for the sender
+	  Avoid mapping the packet multiple times when sending RTP.
+
+2013-09-13 12:22:36 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpbin: store more in the PacketInfo
+	  Store all info in the PacketInfo so that we can avoid mapping the packet
+	  multiple times.
+
+2013-09-13 11:32:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpstats.h:
+	  session: store more in the PacketInfo structure
+
+2013-09-13 11:08:55 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpbin: RTPArrivalStats -> RTPPacketInfo
+	  Rename a structure because we are also going to use this for the sender
+	  bits.
+
+2013-09-13 10:55:31 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  source: small cleanups
+
+2013-09-12 13:31:01 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: only update stop position if seek requests it
+	  Check for GST_SEEK_TYPE_NONE for stop poistion and only update
+	  the stop time if it is requested. Otherwise just maintain whatever
+	  was stored at the segment
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707530
+
+2013-09-13 08:53:25 +0200  Rico Tzschichholz <ricotz@ubuntu.com>
+
+	* gst/rtp/Makefile.am:
+	  rtp: Add missing headers tp fix make dist
+	  In addition to a956a6ceb2deb87cc1361aee1d6626449f46dab2
+
+2013-09-12 15:07:48 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Make sure we have enough data to read image tags
+	  Thanks to iputinei for reporting this on IRC.
+
+2013-09-12 15:01:36 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: handle segments with non-0 start
+	  We keep the DTS and PTS in running-time inside the jitterbuffer. Make sure to
+	  transform it back to a buffer timestamp before pushing out the buffer.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=707931
+
+2013-09-11 13:11:58 -0600  Seán de Búrca <leftmostcat@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Fix off-by-one in validation of UTF-8
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707933
+
+2013-09-11 14:32:17 -0300  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Do not check if caps are empty when they are NULL
+	  In the case the caps are actually NULL, we should just concider it the
+	  same way as empty caps in that case.
+
+2013-09-10 16:44:53 -0600  Seán de Búrca <leftmostcat@gmail.com>
+
+	* gst/videomixer/videomixerorc-dist.c:
+	* gst/videomixer/videomixerorc-dist.h:
+	  videomixer: fix build if orc is not installed
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707886
+
+2013-09-10 17:57:49 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Preserve seqnum when pushing seek upstream
+	  After converting a seek from time to bytes, use the same seqnum
+	  on the event that goes upstream
+
+2013-09-05 00:17:16 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: track streams that are EOS on push mode to finish earlier
+	  When the segment has a defined stop position, qtdemux should check
+	  when streams reach this position and mark those as EOS. When all
+	  streams are EOS it will return GST_FLOW_EOS to upstream to allow
+	  the pipeline to finish instead of continuously consume buffers
+	  from upstream that are not useful for the segment.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707530
+
+2013-09-04 15:34:35 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: preserve stop of segment when doing seeks in push mode
+	  When handling seeks in push mode, qtdemux converts the seek to bytes
+	  and pushes upstream. It needs to keep track of the seek and the
+	  subsequent segment to be able to map them back to the requested
+	  seek time and properly preserve the segment stop of the seek.
+	  This is done by using the start offset in bytes of the seek,
+	  that should be the same of the segment from upstream. And this
+	  is also backwards compatible with what qtdemux already was using.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707530
+
+2013-07-26 19:40:53 +0200  Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
+
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2pad.h:
+	  videomixer: Add colorspace conversion
+	  https://bugzilla.gnome.org/show_bug.cgi?id=704950
+
+2013-08-06 15:38:39 +0200  Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Don't send reconfigure event when formats or PAR are different
+	  It is racy with multiple pads.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=704950
+
+2013-07-25 13:49:57 +0200  Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
+
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/blend.c:
+	* gst/videomixer/blendorc.orc:
+	* gst/videomixer/gstcms.c:
+	* gst/videomixer/gstcms.h:
+	* gst/videomixer/videoconvert.c:
+	* gst/videomixer/videoconvert.h:
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixerorc.orc:
+	  videomixer: Bundle private copies of videoconvert code
+	  Ideally, this would be part of libgstvideo.
+	  Prefixes videoconvert symbols with videomixer_.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=704950
+
+2013-08-22 00:03:48 +0200  Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: Use newly #defined metadata names.
+
+2013-09-09 15:11:51 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: only wait if we flushed
+	  Only wait for the STREAM_LOCK when we flushed something when sending
+	  a command for PAUSED or PLAYING.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=707611
+
+2013-09-09 15:09:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: return when a flush was issued
+	  Make gst_rtspsrc_loop_send_cmd() return TRUE when the current
+	  action has been flushed
+
+2013-09-09 11:16:40 +0200  David Holroyd <dave@badgers-in-foil.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpL24depay.c:
+	* gst/rtp/gstrtpL24depay.h:
+	* gst/rtp/gstrtpL24pay.c:
+	* gst/rtp/gstrtpL24pay.h:
+	* tests/check/elements/rtp-payloading.c:
+	  rtp: add L24 pay and depayloader
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=707734
+
+2013-09-09 14:46:42 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Fix missing condition in previous commit
+
+2013-09-09 14:44:58 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Also fix strides for other semi-planar video formats
+
+2013-09-09 14:41:42 +0200  Andreea Fulger <andreea.fulger@parrot.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2bufferpool: Fix stride for NV12/NV21
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707758
+
+2013-09-07 16:37:03 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: fix leaking buffer and caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707688
+
+2013-09-05 19:46:37 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: fix build on win32
+	  gstudpsrc.c:855:15: error: #if with no expression
+
+2013-09-04 15:50:42 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: handle unseekable streams
+	  Handle streams that we can't seek in and ignore them in the
+	  seek logic.
+
+2013-09-04 15:25:39 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: only check video compression for video streams
+	  Or else we might deref a stream with a NULL strf.vids and segfault
+
+2013-06-18 13:27:20 +0100  Alex Ashley <bugzilla@ashley-family.net>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/ftypcc.h:
+	* gst/isomp4/gstrtpxqtdepay.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_fourcc.h:
+	* gst/isomp4/qtdemux_types.c:
+	  qtdemux: Add support for the avc3 sample entry format of the AVC file format
+	  Amendment 2 of ISO/IEC 14496-15 (AVC file format) is defining a new
+	  structure for fragmented MP4 called "avc3". The principal difference
+	  between AVC1 and AVC3 is the location of the codec initialisation
+	  data (e.g. SPS, PPS). In AVC1 this data is placed in the initial
+	  MOOV box (moov.trak.mdia.minf.stbl.stsd.avc1) but in AVC3 this data
+	  goes in the first sample of every fragment (i.e. the first sample in
+	  each mdat box).  The principal reason for avc3 is to make it easier
+	  for client implementations, because it removes the requirement to
+	  insert the SPS+PPS in to the decoder pipeline every time there is a
+	  representation change.
+	  This commit adds support for the "avc3" atom, which is almost identical
+	  to the "avc1" atom, except it does not contain any SPS or PPS data.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=702004
+
+2013-09-04 00:27:50 +0200  Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Don't set EOS to FALSE when the collectpad *is* EOS
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707238
+
+2013-09-03 17:32:41 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: cleanup on error after state change
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707229
+
+2013-09-03 11:23:24 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/udp/gstudpsrc.c:
+	* gst/udp/gstudpsrc.h:
+	  udpsrc: Bind to multicast addresses on non-Windows systems
+	  On Windows it's not possible to bind to a multicast address
+	  but the OS will make sure to filter out all packets that
+	  arrive not for the multicast address the socket joined.
+	  On Linux and others it is necessary to bind to a multicast
+	  address to let the OS filter out all packets that are received
+	  on the same port but for different addresses than the multicast
+	  address
+	  And deprecate the multicast-group property and replace it with the
+	  address property.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707042
+
+2013-09-03 10:10:01 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Free GstBaseParseFrame if pushing a header failed
+
+2013-09-02 16:02:37 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Refactor address resolval into its own function
+
+2013-09-02 23:00:29 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/replaygain/gstrganalysis.c:
+	  replaygain: fix taglist leak in rganalysis
+	  And add some FIXMEs.
+
+2013-09-02 22:50:58 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/rganalysis.c:
+	  tests: rganalysis: rename function for clarity
+
+2013-03-18 14:32:07 +0100  Christoph Reiter <reiter.christoph@gmail.com>
+
+	* tests/check/elements/rganalysis.c:
+	  tests: fix skipped rganalysis tests
+	  In 0.10 elements would post tag messages on the bus
+	  directly, and rganalysis would only post a tag message
+	  when it changed tags. In 1.0, only sinks post tag
+	  messages when they receive the serialised tag event.
+	  This means that we get an additional tag message on
+	  the bus now where we didn't expect one before.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=695090
+
+2013-09-02 11:46:52 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Properly propagate downstream flow returns upstream
+	  https://bugzilla.gnome.org/show_bug.cgi?id=707229
+
+2013-09-01 21:18:38 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/shout2/gstshout2.c:
+	* gst/avi/gstavi.c:
+	* gst/isomp4/isomp4-plugin.c:
+	* gst/rtsp/gstrtsp.c:
+	* sys/sunaudio/gstsunaudio.c:
+	* sys/v4l2/gstv4l2.c:
+	  Don't use setlocale in plugins()
+	  Only apps should call setlocale(), not libraries.
+
+2013-08-29 13:15:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmpvpay.c:
+	  rtpmpvpay: Fix RTP buffer allocation in rtpmpvpay
+	  RTP buffer allocation should not be done with padding for the specific MPEG2
+	  header as the padding is done at the end of the buffer and the last byte is
+	  the size of the padding.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=706970
+
+2013-08-28 10:51:32 +0200  Bernhard Miller <bernhard.miller@streamunlimited.com>
+
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosink.h:
+	  autovideosink: add sync property
+	  https://bugzilla.gnome.org/show_bug.cgi?id=706955
+
+2013-08-28 07:15:00 +0200  Bernhard Miller <bernhard.miller@streamunlimited.com>
+
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosink.h:
+	  autoaudiosink: introduce sync property
+	  https://bugzilla.gnome.org/show_bug.cgi?id=706955
+
+2013-08-27 17:33:40 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: push buffers after segment stop until reaching a keyframe
+	  This should make decoders able to precisely push buffers until the stop
+	  time in case they need the next keyframe to do it.
+	  Also, according to gst_segment_clip, it should only push a buffer that
+	  the starting ts is strictly smaller than the segment stop, so we change
+	  the min < comparison for <=
+
+2013-08-28 13:26:47 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.1.4 ===
+
+2013-08-28 12:52:25 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* gst/audiofx/audiopanoramaorc-dist.c:
+	* win32/common/config.h:
+	  Release 1.1.4
+
+2013-08-28 12:52:16 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2013-08-28 12:32:10 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* po/pt_BR.po:
+	  po: update translations
+
+2013-08-27 15:25:16 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroska-mux: remove framerate restriction
+	  Remove the framerate restriction on the caps.
+
+2013-08-27 09:38:16 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: only update next check time when reconsidering
+	  Don't update the next RTCP check time in all cases but only when we
+	  reconsidered. This avoids delaying sending a full RTCP packet when we
+	  are doing early feedback.
+
+2013-08-27 09:37:33 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: add more debug
+
+2013-08-27 09:34:46 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	  jitterbuffer: fix types of the retransmission event
+
+2013-08-27 09:33:03 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: only timeout EXPECTED timers on gap
+	  Only timeout the EXPECTED timers when we detect a large seqnum gap.
+
+2013-08-26 13:47:53 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* configure.ac:
+	  configure.ac: Don't set BZ2_LIBS if bz2 is not found
+
+2013-08-26 11:50:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtsession: fix locking
+	  We need to take the session lock when getting and manipulating the
+	  source.
+
+2013-08-26 11:50:13 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: add some more debug
+
+2013-08-20 22:12:03 +0200  Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: don't send flush_stop twice.
+	  If we get flush start and a seek we need to only send flush_stop once.
+	  More info at #706441
+
+2013-08-23 15:56:43 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartdemux.h:
+	  multipartdemux: propagate discont
+
+2013-08-23 15:49:47 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/multipart/multipartdemux.c:
+	  multipartdemux: remove dynamic sourcpads when going from PAUSED to READY
+
+2013-08-23 15:29:28 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartdemux.h:
+	  multipartdemux: timestamp output buffers based on first input buffer that provided bytes not last
+	  https://bugzilla.gnome.org/show_bug.cgi?id=637754
+
+2013-08-23 15:47:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtprtxqueue.c:
+	* gst/rtpmanager/gstrtprtxqueue.h:
+	  rtxqueue: add property to configure queue size
+
+2013-08-23 12:07:55 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/examples/rtp/client-H264-rtx.sh:
+	* tests/examples/rtp/server-VTS-H264-rtx.sh:
+	  tests: add retransmission example
+
+2013-08-23 11:55:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: proxy jitterbuffer do-retransmission property
+
+2013-08-23 11:17:45 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* gst/avi/gstavimux.c:
+	  avimux: unmap the correct buffer
+	  The audio buffer was mapped so unmap it and not the video buffer
+	  https://bugzilla.gnome.org/show_bug.cgi?id=706642
+
+2013-08-18 23:32:22 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	  pulsesink: Add property to find out the device currently in use
+	  https://bugzilla.gnome.org/show_bug.cgi?id=590768
+
+2013-08-18 23:31:15 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: De-duplicate code to get the current sink input info
+	  https://bugzilla.gnome.org/show_bug.cgi?id=590768
+
+2013-08-18 22:27:37 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Implement changing the device while playing
+	  https://bugzilla.gnome.org/show_bug.cgi?id=590768
+
+2013-08-18 23:32:22 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulsesrc.h:
+	  pulsesrc: Add property to find out the device currently in use
+	  https://bugzilla.gnome.org/show_bug.cgi?id=590768
+
+2013-08-18 23:31:15 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: De-duplicate code to get the current source output info
+	  https://bugzilla.gnome.org/show_bug.cgi?id=590768
+
+2013-08-18 22:27:37 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: Implement changing the device while playing
+	  https://bugzilla.gnome.org/show_bug.cgi?id=590768
+
+2013-08-22 14:55:14 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* configure.ac:
+	  configure: Fix bz2 configure check for Windows
+	  Due to function decorations on Windows AC_CHECK_LIB can't be used to check for bz2.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=465924
+
+2013-02-22 20:57:00 +0900  Akihiro Tsukada <atsukada@users.sourceforge.net>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	* ext/pulse/pulseutil.c:
+	* ext/pulse/pulseutil.h:
+	  pulsesink: Add support for AAC pass-through
+	  https://bugzilla.gnome.org/show_bug.cgi?id=694445
+
+2013-06-24 17:29:37 +0200  Kishore Arepalli <kishore.arepalli@gmail.com>
+
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	  gdkpixbufoverlay: crashes if any property changes during playback when location property is not set
+	  https://bugzilla.gnome.org/show_bug.cgi?id=702988
+
+2013-08-21 14:54:26 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulseutil.h:
+	  pulse: Share static caps definition between src and sink
+	  The src was also missing 24-bit sample formats
+
+2013-08-21 16:53:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtprtxqueue.c:
+	* gst/rtpmanager/gstrtprtxqueue.h:
+	  rtx: various improvements
+	  Use locking
+	  Don't push from the event handler, collected packets in a queue and push from
+	  the chain function.
+	  Clear queues on shutdown.
+
+2013-08-21 16:50:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  session: generate events correctly
+	  Do correct shifting of the bitmask for lost packets.
+
+2013-08-21 16:47:40 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmanager.c:
+	  rtp: register rtx element better
+
+2013-08-21 16:32:50 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: WAVEFORMATEX is unsigned for 8 bit integers, and signed for others
+	  Probably fixes
+	  https://bugzilla.gnome.org/show_bug.cgi?id=705477
+
+2013-08-21 13:03:34 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: don't ignore return value from _finish_frame()
+	  gst_video_encoder_finish_frame() will return FLOW_OK here if
+	  there's no output buffer.
+
+2013-08-21 12:56:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	  jpegdepay: add some more debug
+
+2013-08-21 12:10:00 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtpgstdepay.h:
+	  rtpgstdepay: only push events when they changed
+	  Keep track of the STREAM_START and TAG events and only push them
+	  when they changed.
+
+2013-08-21 10:52:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: taglists should not be merged in 1.0
+
+2013-08-21 10:28:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	  rtpgstdepay: flush on FLUSH_STOP event
+
+2013-08-21 10:03:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: reset on state change
+	  Do full reset on state change to READY
+
+2013-08-21 09:55:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: reset on FLUSH_STOP
+	  Clear the adapter and pending buffer list on FLUSH_STOP.
+
+2013-08-21 09:39:30 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: don't use clock for config interval
+	  We can't use the clock to time our config-interval because we are not
+	  live (or there might not be a clock or the clock might not be running).
+	  Instead just simply take the timestamp diff.
+
+2013-08-21 09:33:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.h:
+	  rtpgstay: don't use // comments
+
+2013-08-08 11:55:22 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Fix response argument in handle-request signal
+
+2013-08-08 11:54:41 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Add sdes property and proxy it to rtpbin
+
+2013-08-07 09:47:35 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtpgstpay.h:
+	  Send a stream-start whenever we send tags This is to make sure tags are cleared on the client if the stream-start was previously lost, otherwise, the client may end up with a merged taglist of multiple songs
+
+2013-07-25 21:12:05 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtpgstpay.h:
+	  rtpgstpay: Add a config-interval property to resend the caps/tags at a regular interval This is useful in case the packet containing the inlined caps was lost or if new client joins an already running RTP stream and they missed the previous tag events. This also makes the payloader keep a list of merged tags so the retransmitted tag event contains all previously received. A STREAM_START event will flush the list of tags.
+
+2013-07-25 21:10:10 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: Refactor the setcaps and use new method to send arbitrary caps at any time
+
+2013-07-25 21:03:34 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: Do not flush events for stream-start and avoid conflict between event and pending inline caps
+
+2013-07-25 20:54:50 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtpgstpay.h:
+	  rtpgstpay: Add a create_from_adapter API and use a list of GstBufferList This is necessary to fix event/caps sending. If we send a STREAM_START packet, it will cause an error because the stream didn't receive its caps and new-segment events, so we must wait for the first buffer before sending the stream-start event buffer. However, the caps will be sent at the same time and so the 'inline caps' will be set for the event. We need to be able to payload individual packets (data, caps or events) and only send them when we call flush.
+
+2013-07-25 17:56:38 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: Add etype=4 for payloading GST_EVENT_STREAM_START
+
+2013-07-25 17:52:16 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: Fix typo, GST_EVENT_CUSTOM_BOTH has etype of 3
+
+2013-08-20 14:36:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: handle EOS
+	  When the queue is empty, and we received EOS, pause and push an EOS
+	  event downstream.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=706387
+
+2013-08-20 10:26:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: update docs
+
+2013-08-20 10:25:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: update all timers
+	  Keep looping over all registered timers so that we can mark them lost instead of
+	  stopping as soon as we find the timer for the current seqnum.
+
+2013-08-20 08:55:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: remove unused variables
+
+2013-08-19 21:10:00 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: reorganize timer handling
+	  Restructure handling of incomming packet and the gap with the expected seqnum
+	  and register all timers from the _chain function.
+	  Convert a timer to a LOST packet timer when the max amount of retransmission
+	  requests has been reached.
+
+2013-08-19 21:37:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: refactor packet spacing calculation
+
+2013-08-19 21:34:38 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: keep track of last seqnum and dts
+
+2013-08-19 21:29:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: small cleanups
+
+2013-08-19 21:21:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: reset retransmission timers in add/reschedule
+	  Reset the retransmission timers when adding and rescheduling a timer.
+
+2013-08-19 21:12:13 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: rename variables for packet spacing
+
+2013-08-19 14:58:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: remove lost timer when we get the packet
+	  When we receive a packet, also remove the LOST timer for it.
+
+2013-08-19 14:56:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: expected seqnum must increase
+	  Only update the expected seqnum when it is bigger than the previous expected
+	  seqnum.
+
+2013-08-19 14:55:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: add more debug
+
+2013-08-12 16:15:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/Makefile.am:
+	* gst/rtpmanager/gstrtpmanager.c:
+	* gst/rtpmanager/gstrtprtxqueue.c:
+	* gst/rtpmanager/gstrtprtxqueue.h:
+	  rtxqueue: add retransmission queue element
+
+2013-08-12 14:53:33 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: add some docs
+
+2013-08-06 16:29:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  session: handle NACK feedback and generate events
+	  Handle and parse the feedback NACK packets and generate a Retransmission
+	  event for each NACKed packet
+
+2013-08-19 13:19:42 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Add forward declaration for gst_v4l2_object_get_format_list
+
+2012-10-22 17:58:07 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2sink.h:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	  v4l2: De-duplicate caps probing between src and sink
+
+2013-08-13 17:32:17 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* ext/pulse/Makefile.am:
+	* ext/pulse/pulseprobe.c:
+	* ext/pulse/pulseprobe.h:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulsesrc.h:
+	  pulse: Remove unused GstPulseProbe
+
+2013-08-19 12:46:45 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* sys/v4l2/gstv4l2tuner.c:
+	* sys/v4l2/tuner.c:
+	* sys/v4l2/tunerchannel.c:
+	* sys/v4l2/tunernorm.c:
+	  v4l2: Use G_DEFINE_ macros for added thread safety
+
+2013-08-17 11:28:13 +0200  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	  videomixer: Do not send flush_stop ourself after a flush_start
+	  When we receive a flush_start, we should wait for the next flush_stop
+	  and foward it, not create a flush_stop ourself.
+
+2013-08-16 17:10:31 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	  h264depay: init debug category early
+	  Init the debug variable when we register the element because it is also used by
+	  the payloader element when it calls the add_sps_pps method.
+
+2013-08-16 13:26:28 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: Properly set headers via the base class instead of just pushing them downstream
+	  Prevents buffers from being send before the caps and segment events.
+
+2013-08-15 10:59:10 +0100  Chris Bass <floobleflam@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: check denominator isn't zero before scaling duration.
+	  When gst_qtdemux_configure_stream sets fps_d, check that n_samples is
+	  non-zero before using it as a denominator to scale the stream duration.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=706076
+
+2013-08-15 15:08:05 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/libpng/gstpngdec.c:
+	* ext/vpx/gstvp8dec.c:
+	* ext/vpx/gstvp9dec.c:
+	  ext: Use new flush vfunc of video codec base classes and remove reset implementations
+
+2013-08-14 16:19:32 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: forward flush before stopping dataflow
+	  First forward the flush event and then stop our loop function.
+
+2013-08-14 13:10:32 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* configure.ac:
+	  configure: require libsoup >= 2.38
+	  Bump libsoup requirement for newer API used, like headers_get_one().
+	  2.38 is from early 2012 and is in linen with our GLib requirement.
+
+2013-08-14 11:54:19 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  soup: don't use deprecated soup_message_headers_get() API
+
+2013-08-13 17:44:50 +0200  Edward Hervey <edward@collabora.com>
+
+	* .gitignore:
+	  .gitignore: Ignore files from automake test-driver
+
+2013-08-12 15:28:34 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtph264pay.h:
+	  rtph264pay: Use the SPS/PPS handling function from the depayloader
+	  Remove duplicated copies
+	  https://bugzilla.gnome.org/show_bug.cgi?id=705553
+
+2013-08-12 15:26:08 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264depay.h:
+	  rtph264depay: Make the SPS/PPS deduplication function generic
+	  Make it not touch any internals of the depayloader
+	  https://bugzilla.gnome.org/show_bug.cgi?id=705553
+
+2013-08-13 14:09:20 +0100  Chris Bass <floobleflam@gmail.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: allow conversion from raw AAC to ADTS
+	  This patch will prepend ADTS headers to raw AAC audio frames, allowing
+	  upstream elements to link to decoders that only support AAC in ADTS format.
+	  Note that no error correction bits are added to ADTS frames in this code.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=615740
+
+2013-08-13 12:44:11 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Only free GCheckSum after its last usage
+	  https://bugzilla.gnome.org/show_bug.cgi?id=705760
+
+2013-08-13 12:02:29 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: fix critical setting a NULL uri redirection
+
+2013-07-13 01:50:56 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: add redirection to the URI query
+
+2013-07-31 10:42:07 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: elst should offset samples instead of buffers
+	  The current approach where buffers are offset is not ideal, as during seek
+	  and loop current time is compared to sample times.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700264
+
+2013-08-07 19:32:07 +0200  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* gst/videomixer/videomixer2.c:
+	* tests/check/elements/videomixer.c:
+	  videomixer: Send EOS if buf_end >= segment.stop
+	  That means the whole segment is already played, and we are sure we
+	  are EOS at that point.
+	  Also handle segment seeks, and do not send EOS in that case.
+
+2013-08-04 14:40:38 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: send proper stream_start event
+	  https://bugzilla.gnome.org//show_bug.cgi?id=705449
+
+2013-08-08 11:51:17 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/matroska/ebml-read.c:
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Don't print warnings during flushing and stop as soon as possible
+	  https://bugzilla.gnome.org//show_bug.cgi?id=705442
+
+2013-08-07 11:14:38 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/rtp/gstrtpvp8depay.c:
+	  rtpvp8depay: mark key frames and delta frames properly
+	  https://bugzilla.gnome.org/show_bug.cgi?id=705550
+
+2013-08-05 23:23:57 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: add NACK feedback in RTCP
+
+2013-08-05 23:22:16 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  source: add methods to register NACK
+	  Add a method to register a missing packet for an ssrc along with
+	  methods to get the missing packets and clear them.
+
+2013-08-04 23:05:36 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  session: handle Retransmission event and schedule NACK
+	  Handle the retransmission event from downstream and use it to schedule a NACK
+	  request.
+
+2013-08-05 23:20:29 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: pass data to remove func
+	  Pass the data to the remove function because we are going to deref it when there
+	  is pli or fir.
+
+2013-08-06 15:28:50 +0200  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix compilation
+
+2013-08-06 15:17:44 +0200  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Raw buffer DTS should always be CLOCK_TIME_NONE
+
+2013-08-06 11:58:38 +0200  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Make sure to send EOS if the buffer end time equals the segment end time
+	  Otherwize EOS never gets sent in that particular case.
+
+2013-08-05 08:49:50 +0200  Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+
+	* gst/goom/gstgoom.c:
+	  goom: Ensure src caps are writable
+	  In some cases the src caps determined by goom weren't writable, causing
+	  a bunch of assertion failures and failed caps. Fixed by always
+	  explicitely making the caps writable
+	  https://bugzilla.gnome.org/show_bug.cgi?id=705475
+
+2013-08-04 23:18:29 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  session: use common send_rtcp method
+	  Reuse the send_rtcp method that already asks for the current time when
+	  requesting a keyframe.
+
+2013-08-04 23:12:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  session: Don't use ClockTimeDiff for unsigned delays
+
+2013-08-04 16:52:15 +0200  Edward Hervey <edward@collabora.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Use buffer PTS if DTS is not set
+	  Avoids ending up with completely bogus scaled duration/pts when new
+	  buffers have invalid DTS.
+
+2013-08-04 14:32:47 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: skip https test if there's no TLS support in soup/glib
+
+2013-08-04 11:20:41 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/rtsp/gstrtpdec.c:
+	  rtpdec: use generic marshaller
+
+2013-08-04 10:52:33 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* Makefile.am:
+	* sys/v4l2/.gitignore:
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2-marshal.list:
+	* sys/v4l2/tuner-marshal.list:
+	* sys/v4l2/tuner.c:
+	* sys/v4l2/tuner.h:
+	* win32/MANIFEST:
+	* win32/common/tuner-enumtypes.c:
+	* win32/common/tuner-enumtypes.h:
+	* win32/common/tuner-marshal.c:
+	* win32/common/tuner-marshal.h:
+	  v4l2: remove unused enumtypes and use generic marshaller
+
+2013-08-04 10:47:38 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* Makefile.am:
+	* gst/udp/.gitignore:
+	* win32/common/gstudp-enumtypes.c:
+	* win32/common/gstudp-enumtypes.h:
+	* win32/common/gstudp-marshal.c:
+	* win32/common/gstudp-marshal.h:
+	  udp: remove unused marshal and enumtypes files
+
+2013-08-04 09:38:19 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* Makefile.am:
+	* gst/rtpmanager/.gitignore:
+	* gst/rtpmanager/Makefile.am:
+	* gst/rtpmanager/gstrtpbin-marshal.list:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtpmanager/rtpsession.c:
+	* win32/MANIFEST:
+	* win32/common/gstrtpbin-marshal.c:
+	* win32/common/gstrtpbin-marshal.h:
+	  rtpmanager: use generic marshaller
+
+2013-08-04 00:13:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: send event in right direction
+
+2013-08-02 17:38:34 -0700  David Schleef <ds@schleef.org>
+
+	* configure.ac:
+	* tests/check/Makefile.am:
+	  tests: create/remove orc directory at proper time
+	  Before automake creates .deps directories, and during distclean.
+
+2013-08-03 00:25:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: add FIR and PLI like other RTCP packets
+	  Add the FIR and PLI packets like the other RTCP packet instead of from the
+	  on-sending-rtcp default signal handler.
+
+2013-08-02 17:22:55 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: fix property ranges
+
+2013-08-02 16:42:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: push retransmission events
+
+2013-08-02 14:12:16 +0200  Lubosz Sarnecki <lubosz@gmail.com>
+
+	* configure.ac:
+	  build: add subdir-objects to AM_INIT_AUTOMAKE
+	  Fixes warnings with automake 1.14
+	  https://bugzilla.gnome.org/show_bug.cgi?id=705350
+
+2013-08-02 14:54:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: add support for retransmission retry
+	  When we didn't receive a packet after requesting retransmission, retry
+	  asking for retransmission for a certain period.
+
+2013-08-02 14:19:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: add properties
+	  Add properties to control retransmission parameters
+
+2013-08-02 12:44:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: use corrected timeout when rescheduling
+	  When we recalculate the timeout, use the corrected timeout value depending on
+	  the timer type.
+
+2013-08-02 12:43:00 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: update timers after queueing
+	  Else we might update the timer needlessly for duplicates.
+
+2013-08-02 12:42:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: move method up
+
+2013-08-02 06:28:32 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: small cleanup
+
+2013-08-01 23:26:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: unschedule old expected packets
+	  When we receive a new packet, unschedule old outstanding packets when their
+	  seqnum is too far away.
+
+2013-08-01 23:29:23 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: refactor timer update
+
+2013-08-01 23:24:29 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: update timers when removing
+	  Update the timers when we remove a timer.
+	  Handle canceled timers, make them unschedule the current timer and
+	  trigger the timeout code.
+
+2013-08-01 23:22:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: fix typo
+
+2013-08-01 15:40:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: improve timeout management
+	  If we change the seqnum of an existing timer and we were waiting for
+	  that timer, unschedule it. If we change the timeout of an existing timer and we
+	  were waiting on it, only unschedule when the new time is smaller.
+
+2013-08-01 15:05:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: install timer for expected arrival
+	  Install a timer that is triggered when the expected arrival time of a packet
+	  expired.
+
+2013-08-01 14:56:00 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: improve unschedule of timers
+	  Conflicts:
+	  gst/rtpmanager/gstrtpjitterbuffer.c
+
+2013-08-01 12:21:53 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: move code around
+
+2013-08-01 12:07:11 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: estimate inter packet spacing
+	  When we see two packets with consecutive seqnums and a different RTP time, use
+	  the DTS difference as the inter packet spacing estimate.
+
+2013-08-01 12:01:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: keep track of current timeout
+
+2013-08-01 11:49:10 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: cleanup timer handling
+
+2013-08-01 11:40:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: reset is only possible with a GAP
+
+2013-08-01 11:29:32 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  jitterbuffer: operate on DTS
+	  Make the jitterbuffer schedule the timeouts based on the DTS instead
+	  of the PTS. This makes it all smoother with reordered frames and gives
+	  the decoder time to reorder the frames in time.
+
+2013-08-01 11:14:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: rename timout variable
+
+2013-07-31 17:08:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: small cleanup
+
+2013-07-31 16:59:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: block output in paused or buffering
+
+2013-07-31 16:59:09 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: store pts in timer
+	  Only store the pts in the timer so that we can both do timeouts with timings on
+	  the input and output of the jitterbuffer.
+
+2013-07-30 23:14:24 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: refactor jitterbuffer
+	  Refactor the jitterbuffer code. Make separate function for peeking a buffer,
+	  pushing the next buffer, waiting for timeouts and handling the timeouts.
+	  The main loop now tries to push as many buffers as it can until it runs out of
+	  buffers or when it detects a seqnum discont. Then it will wait for some event to
+	  happen before attempting to push more buffers.
+	  Make methods to register timeouts in an array. These timeouts are registered
+	  when we detect a missing packet, sync for the first packet or when we find an
+	  estimation for the end-of-stream.
+	  This greatly simplifies and clarifies the code and also makes it possible to
+	  register more complicated timeout schemes later.
+
+2013-07-30 18:52:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: use NULL to ignore percent
+	  If we pass NULL to pop and push we ignore the percent result.
+
+2013-07-30 07:00:19 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: refactor
+	  Move eos estimation into separate function
+
+2013-07-30 14:28:19 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: don't leak stream_id string
+	  https://bugzilla.gnome.org/show_bug.cgi?id=705142
+
+2013-07-29 19:53:52 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* po/LINGUAS:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/gl.po:
+	* po/hr.po:
+	* po/hu.po:
+	* po/ja.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/pl.po:
+	* po/ru.po:
+	* po/sl.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	  po: update translations
+
+2013-07-29 19:48:54 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/.gitignore:
+	  tests: ignore new test binaries
+
+2013-07-29 14:47:49 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.1.3 ===
+
+2013-07-29 13:42:18 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.1.3
+
+2013-07-29 13:42:05 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2013-07-29 12:12:41 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/avi/gstavidemux.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	  gst: Don't swap start/stop for negative rates in the SEGMENT query
+
+2013-07-29 11:18:40 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Check for data size when parsing h264 codec data from strf atom
+
+2013-07-29 10:53:54 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Implement SEGMENT query
+
+2013-07-29 10:53:47 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Implement SEGMENT query
+
+2013-07-29 10:50:59 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Implement SEGMENT query
+
+2013-07-27 18:10:22 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_fourcc.h:
+	  qtdemux: Support H264 fourcc
+	  https://bugzilla.gnome.org/show_bug.cgi?id=704996
+
+2013-07-28 18:09:33 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: Fix handling of image tags
+	  The caps should be used to get the mimetype and there is
+	  only an info structure for the GstSample if the image-type
+	  is not NONE.
+
+2013-07-28 18:04:32 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: Don't crash if there is no image tag information
+	  https://bugzilla.gnome.org/show_bug.cgi?id=705018
+
+2013-07-28 17:38:56 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Fix duration reporting in push mode
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700933
+
+2013-07-28 17:32:27 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Don't forget unmapping and unreffing buffer
+
+2013-07-26 21:06:17 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: unmap buffer
+	  https://bugzilla.gnome.org/show_bug.cgi?id=704951
+
+2013-07-26 22:31:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: don't make buffer writable prematurely
+	  There is no reason to make the SR buffer writable at this point. This is better
+	  delayed until needed.
+
+2013-07-26 22:25:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: ignore RTCP for inactive sources
+
+2013-07-26 22:25:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: small cleanup
+
+2013-07-26 17:17:31 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.h:
+	  session: handle partial RTCP report blocks
+	  When we have more SSRCs to report than what fit in an RTCP packet, use a
+	  generation counter to make sure all of them end up in a packet eventually.
+
+2013-07-26 17:23:10 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: create SSRC before doing session cleanup
+	  Make the internal source before we do session cleanup
+
+2013-07-26 17:21:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: reorganize the report block code
+
+2013-07-26 16:02:01 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: fix memory leak in check_subtitle_buffer
+	  https://bugzilla.gnome.org/show_bug.cgi?id=704921
+
+2013-07-26 14:21:40 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: refactor active and sender checks
+
+2013-07-26 12:06:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: remove internal sources on timeout
+	  When an internal source times out and becomes a receiver, remove it.
+
+2013-07-26 11:47:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: create an internal source for RTCP
+	  When we need to do RTCP and we don't have an internal source yet,
+	  make one.
+
+2013-07-26 10:47:28 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	  session: remove old code to change SSRC
+	  Remove code used to change the SSRC after a collision. We now send
+	  a RECONFIGURE event upstream to make the upstream element change the SSRC.
+
+2013-07-26 10:42:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  source: don't update packet SSRC
+	  Remove the code to update the SSRC in packets, it can never be called now that
+	  we always use a source with matching packet SSRC.
+
+2013-07-26 10:24:22 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  session: delay allocation of internal source
+	  Allocate the internal source when we receive a caps with the SSRC or when we see
+	  a buffer with the SSRC.
+
+2013-07-26 10:00:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	  session: generate reconfigure on collision
+	  When we detect a collision, change the SSRC that we suggest upstream
+	  and trigger RECONFIGURE. This should make upstream select a new SSRC.
+
+2013-07-26 09:37:24 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  session: produce RTCP for all internal sources
+	  Loop over all the internal sources and produce RTCP. We also need
+	  to queue the RTCP packets and send them when we are finished.
+
+2013-07-26 01:40:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  session: deprecate internal source and ssrc properties
+	  Deprecate the internal source and internal ssrc properties. There might
+	  be more than one internal source.
+
+2013-07-26 01:29:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: internal sources don't use probation
+
+2013-07-26 01:24:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	  session: give caps to session
+	  Let the session parse the caps and update its SSRC when needed.
+
+2013-07-26 01:14:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  session: make method to suggest available SSRC
+	  Make a method to suggest the best available SSRC. This is the SSRC of the last
+	  created internal source and is used to instruct upstream to produce this
+	  SSRC.
+
+2013-07-26 01:01:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  session: keep SDES and set on new internal sources
+	  Keep track of the SDES ourselves and set it on all newly created
+	  internal sources.
+
+2013-07-26 00:48:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: make method to make internal sources
+	  Add a method to obtain an internal source and use it to create
+	  our internal source
+
+2013-07-26 00:29:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpstats.h:
+	  session: count internal sources and how many are senders
+
+2013-07-26 00:14:29 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: separate BYE marking and scheduling
+	  First mark sources with BYE and then schedule the BYE RTCP message.
+
+2013-07-25 23:56:46 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: get SSRC from RTCP packet itself
+	  Get the SSRC from the RTCP packet instead.
+
+2013-07-25 23:51:34 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: fix bandwidth calculation
+	  We iterate over all sources and the internal one is also in the
+	  hashtable so avoid adding it twice.
+
+2013-07-25 23:38:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: add some docs
+
+2013-07-25 23:11:05 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: Rearrange RTCP reporting a little
+	  Make a function to generate an RTCP packet for a source, pass the source as a
+	  parameter.
+	  Move timeout of collisions to session cleanup phase.
+
+2013-07-25 22:39:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: move check for is_early around
+	  Move the check for the early RTCP to where it is needed and used.
+
+2013-07-25 17:35:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: parse packet outside of the session lock
+
+2013-07-25 17:34:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: do nicer checks for internal sources
+
+2013-07-25 17:15:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  session: let source keep track if it sent BYE
+
+2013-07-25 17:06:22 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  source: reset more
+
+2013-07-25 16:49:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  source: also use the source for bye_reason
+	  Store the BYE reason in our internal source object. Rename the methods on the
+	  source object a little because now the BYE can be received in RTCP or
+	  set when the session wants to send BYE.
+
+2013-07-25 16:24:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  session: configure sdes with structure only
+	  Remove code to configure the SDES with methods and types, only
+	  allow configuration with GstStructure
+
+2013-07-25 15:56:39 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: refactor add and find source
+	  Make functions to find and add a source to the hashtable.
+
+2013-07-25 15:43:11 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  session: remove source from sync_rtcp
+	  We don't need to know the sender source of the session in the
+	  callback, the SR packet is for all participants in the session.
+
+2013-07-24 14:18:14 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: add some more debug
+
+2013-07-15 17:11:45 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/Makefile.am:
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstaacparse.h:
+	  aacparse: allow conversion from ADTS to raw AAC
+	  Some muxers (eg, qtmux) only support raw AAC, so this allows linking
+	  an encoder that outputs ADTS only to those muxers.
+	  The conversion is simple (omit the first 7 or 9 bytes of the frame),
+	  but has to be done in pre_push instead of handle_frame as 1.0 does
+	  not seem to allow skipping bytes there as 0.10 used to.
+	  Other conversions are not supported (yet).
+
+2013-07-15 17:15:44 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: fix object_type parsing off-by-one in ADTS frame
+	  According to http://wiki.multimedia.cx/index.php?title=ADTS,
+	  the value stored in ADTS headers is one less than the object
+	  type of the AAC stream.
+	  A look at ffmpeg shows it also adds 1 to the value read off
+	  the ADTS header.
+	  Note that this might break other things that happen to have
+	  an inverse off by one to match the existing code.
+
+2013-07-25 11:13:01 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix seqnum handling for seeks
+	  Use the same seqnum as the seek for flushes/segments that are
+	  caused by the seek. Also do the same for segment events
+	  Fixes #676242
+
+2013-07-25 01:39:58 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: fix seqnum handling for seeks
+	  Use the same seqnum as the seek for flushes/segments that are
+	  caused by the seek. Also do the same for segment events
+	  Fixes #676242
+
+2013-07-25 01:11:31 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: correctly handle seqnum for seeks and segments
+	  Use the same seqnum on messages and events for derived events.
+	  Fixed for flushes / stream-start / segment after a seek, and segment
+	  after a segment.
+	  Fixes #676242
+
+2013-07-12 20:01:42 +0200  Arnaud Vrac <avrac@freebox.fr>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: always ignore HEAD errors
+	  https://bugzilla.gnome.org/show_bug.cgi?id=704241
+
+2013-07-25 14:26:07 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: Clean up reset/start/stop handling
+
+2013-07-25 14:13:10 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: Use base class error handling function instead of replicating it here
+
+2013-07-25 14:12:56 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Clean up handling of reset/start/stop
+
+2013-07-25 10:41:22 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/files/id3-407349-1.tag:
+	* tests/files/id3-407349-2.tag:
+	* tests/files/id3-447000-wcop.tag:
+	  tests: fix test ID3 tags up not to rely on dodgy typefinding code
+	  Change 0xff 0xfb 'mp3' marker to 'fLaC' marker, so we can fix
+	  the typefinder.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=681368
+
+2013-07-25 08:22:45 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	  osxaudiosink: intersect the probed caps with the filter passed to get_caps()
+
+2013-07-24 14:17:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  bin: fix compilation
+
+2013-07-24 12:42:31 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  vrawdepay: fix UYVP format
+
+2013-07-24 12:41:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawpay.c:
+	  vrawpay: fix UYVP format
+
+2013-07-24 12:41:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawpay.c:
+	  vrawpay: fix caps
+
+2013-07-24 10:49:03 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: fix locking
+	  Take the lock earlier so that we do things that follow with the right
+	  locking.
+
+2013-07-23 17:40:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: don't use invalid times in RTCP timeouts
+	  An invalid timeout can be calculated when we disabled RTCP by setting the
+	  bandwidth to 0. Make sure all code can handle this case.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=674626
+
+2013-07-23 17:38:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: lock session when changing bandwidth
+	  Take the session lock when changing the bandwidth properties so that we don't
+	  end up with inconsistent behaviour.
+
+2013-07-23 17:37:05 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: reset some RTCP variables
+	  The early_send time was set to 0 and always triggering an early RTCP packet.
+
+2013-07-23 15:03:31 +0200  Edward Hervey <edward@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Add all the mpeg XDCAM variants
+	  This should cover all known XDCAM variants (which are all mpeg2 video)
+	  Fixes #672227
+
+2013-07-03 18:41:42 +0200  Carlos Rafael Giani <dv@pseudoterminal.org>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: added custom downstream sync event
+	  rtpbin can now send a custom in-band downstream event which informs
+	  downstream that the bin has received an RTCP SR packet. This is useful
+	  for applications which want to drop the initial unsynchronized received
+	  RTP packets.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=703560
+	  Signed-off-by: Carlos Rafael Giani <dv@pseudoterminal.org>
+
+2013-07-22 18:00:16 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: fix on-the-fly changing of "mode" and "fields" properties
+	  We call setcaps() to reconfigure ourselves, but we need to pass
+	  the current *sink* caps, not the source caps then. Also fix a
+	  caps leak.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=641599
+
+2013-07-22 15:23:39 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Add support for group-id in the stream-start event
+
+2013-07-22 15:23:20 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Add support for group-id in the stream-start event
+
+2013-07-22 15:23:11 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: Add support for group-id in the stream-start event
+
+2013-07-22 15:22:55 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: Add support for group-id in the stream-start event
+
+2013-07-22 15:22:47 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: Add support for group-id in the stream-start event
+
+2013-07-22 15:22:36 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	  flvdemux: Add support for group-id in the stream-start event
+
+2013-07-22 15:22:16 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: Add support for group-id in the stream-start event
+
+2013-07-22 15:21:49 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ext/dv/gstdvdemux.c:
+	* ext/dv/gstdvdemux.h:
+	  dvdemux: Add support for group-id in the stream-start event
+
+2013-07-19 22:59:15 +0200  Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: use gst_util_uint64_scale*_round.
+	  There could be a case where:
+	  1) you do a new set_caps after buffers have been processed.
+	  2) ts_offset gets set to a different value, eg 0.033333333
+	  3) your pads get EOS, but the check dor that doesn't work
+	  because you use ts_offset + a truncated value < segment.stop
+	  4) so in the next collected, you end up comparing for example:
+	  0.9999999999 > 1., which is false and means you don't send EOS.
+	  Also adds scale_round in two other places where it potentially could
+	  have caused problems.
+
+2013-07-15 17:55:19 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_fourcc.h:
+	  qtdemux: Add WRLE support
+
+2013-07-19 19:35:26 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_fourcc.h:
+	  qtdemux: make files from Vivotek camera play
+	  Skip tracks of 'vivo' subtype with empty stsd instead of
+	  erroring out saying that the file is broken.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699791
+
+2013-07-19 17:14:06 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: when streaming don't try to seek when stopping
+	  It might cause errors in sinks that are not seekable and
+	  have reported this (like e.g. fdsink)
+	  https://bugzilla.gnome.org/show_bug.cgi?id=696228
+
+2013-07-19 17:26:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: simplify some helpers
+	  Some helper functions are not needed anymore or can be simplified.
+
+2013-07-19 17:12:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: for non-raw video, move palette in caps
+	  We only need to append the palette to raw video buffers, non-raw video has the
+	  palette in the caps still.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=704292
+
+2013-07-19 01:49:20 +0200  Arnaud Vrac <avrac@freebox.fr>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: nitpicking in esds parsing
+
+2013-07-19 01:49:07 +0200  Arnaud Vrac <avrac@freebox.fr>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: set proper caps for mpeg-1 audio
+	  Remove AAC specific fields from mpeg-1 audio caps, remove assumption
+	  that the mpeg1 audio layer is 3, and set `parsed' field.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=704548
+
+2013-06-17 21:27:37 +0200  Arnaud Vrac <avrac@freebox.fr>
+
+	* ext/vpx/gstvp8dec.h:
+	* ext/vpx/gstvp8enc.h:
+	* ext/vpx/gstvp9dec.h:
+	* ext/vpx/gstvp9enc.h:
+	  vpx: fix compilation when encoder or decoder headers are not installed
+	  https://bugzilla.gnome.org/show_bug.cgi?id=704547
+
+2013-07-16 20:41:15 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/elements/videocrop.c:
+	  videocrop: Fix unit for GRAY16 formats
+
+2013-07-16 22:17:17 +0200  Arnaud Vrac <avrac@freebox.fr>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: remove chapter stream
+	  Remove all streams that are actually table of contents, since we will
+	  never need the data after parsing them.
+
+2013-07-16 21:59:37 +0200  Arnaud Vrac <avrac@freebox.fr>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: send gap event for sparse streams in push mode
+	  This allows to pre-roll at least if the next subtitle buffer
+	  is far away.
+
+2013-07-16 21:56:07 +0200  Arnaud Vrac <avrac@freebox.fr>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: do not use indexes from sparse stream when seeking in push mode
+	  This makes seeking more accurate in push mode, since the previous
+	  keyframe on a sparse stream might be far away.
+
+2013-07-16 21:04:07 +0200  Arnaud Vrac <avrac@freebox.fr>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: advertise subtitle streams as sparse
+
+2013-07-17 17:11:44 +0200  Arnaud Vrac <avrac@freebox.fr>
+
+	* gst/matroska/matroska-demux.c:
+	  mastrokademux: do not push discont buffers if they aren't discont
+	  Unset the discont flag instead of posssibly pushing a buffer with
+	  a flag that's still set.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=682110
+
+2013-07-17 15:10:00 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: extract the palette from stsd
+	  Sometimes a palette is inside the stsd, extract it instead of always using
+	  the default one
+
+2013-07-17 14:30:16 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/goom2k1/gstgoom.c:
+	  goom2k1: Fix event handling and negotiate as soon as possible
+
+2013-07-17 14:27:57 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/goom/gstgoom.c:
+	  goom: Fix event handling and negotiate as soon as possible
+
+2013-07-11 19:45:17 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: warn about the future deprecation of the "embed" property
+
+2013-07-17 09:56:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: add support for WRAW
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=704292
+
+2013-07-17 09:54:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: palette is appended to buffers, not in caps
+	  Fix the palette handling, in 1.0 we append the palette to the buffer instead of
+	  placing it on the caps.
+	  See also https://bugzilla.gnome.org/show_bug.cgi?id=704292
+
+2013-07-16 15:37:49 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	  rtp: Use gst_adapter_take_buffer_fast() where possible in RTP payloaders
+
+2013-07-15 16:24:07 +0200  Arnaud Vrac <avrac@freebox.fr>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: reset segment on flush stop
+	  cca2f555d14 introduces a regression, where the demux segment is not
+	  reset on flush stop, so the next upstream segment event will calculate
+	  an invalid base time on the new segment to be sent downstream.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=704255
+
+2013-07-06 17:20:49 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: offset samples according to edit list
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700264
+
+2013-07-14 12:50:13 +1200  Douglas Bagnall <douglas@halo.gen.nz>
+
+	* tests/examples/spectrum/spectrum-example.c:
+	  level: Fix the spectrum example for 1.0
+	  The "message" property has been replaced by "post-messages".
+	  Pre-patch output:
+	  (test_spectrum:23101): GLib-GObject-WARNING **: g_object_set_valist:
+	  object class `GstSpectrum' has no property named `message'
+	  New spectrum message, endtime 0:00:00.100000000
+	  (test_spectrum:23101): GStreamer-CRITICAL **:
+	  gst_value_list_get_value: assertion `GST_VALUE_HOLDS_LIST (value)' failed
+	  [...]
+	  Post-patch:
+	  New spectrum message, endtime 0:00:00.100000000
+	  band 0 (freq 400): magnitude -65.988777 dB phase 1.533397
+	  band 1 (freq 1200): magnitude -65.545563 dB phase -0.780900
+	  band 2 (freq 2000): magnitude -64.791946 dB phase -0.799611
+	  band 3 (freq 2800): magnitude -64.556175 dB phase -0.063615
+	  [...]
+	  https://bugzilla.gnome.org/show_bug.cgi?id=704179
+
+2013-07-13 20:56:26 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: be less verbose when parsing LOAS streams
+	  https://bugzilla.gnome.org/show_bug.cgi?id=704162
+
+2013-07-12 12:31:39 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.h:
+	  sink: alaw/mulaw caps don't have a layout property
+
+2013-07-12 12:27:53 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulseutil.c:
+	  pulse: relax mulaw and alaw format checks
+	  The audio library considers them as encoded formats and does not fill in the
+	  sample width. The audio ringbuffers identifies the format as alaw/mulaw and that
+	  is always 8 bits.
+
+2013-07-11 16:13:05 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	* gst/isomp4/qtdemux_fourcc.h:
+	* gst/isomp4/qtdemux_types.c:
+	  qtdemux: unselect instead of ignoring disabled track, detect chapter track
+	  https://bugzilla.gnome.org/show_bug.cgi?id=704007
+
+2013-07-11 20:41:23 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: ignore errors from HEAD request
+	  HEAD requests are used to check the server headers to see if it
+	  seekable. Ignore errors from those requests as they shouldn't be
+	  critical.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=704053
+
+2013-07-12 03:24:08 +0800  Kyosuke Nekomura <supercatexpert@gmail.com>
+
+	* gst/audiofx/audioecho.c:
+	  audioecho: Fix handling of delay property in PLAYING/PAUSED state
+	  https://bugzilla.gnome.org/show_bug.cgi?id=703901
+
+2013-07-09 17:56:57 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Enable proxy caps on the src pads
+
+2013-07-11 16:57:15 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.1.2 ===
+
+2013-07-11 15:58:51 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.1.2
+
+2013-07-11 15:58:29 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2013-07-09 15:34:04 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: defer the window handle setup to the main thread
+
+2013-07-09 15:33:18 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: default to the main in case we are not setup yet
+
+2013-07-07 22:16:05 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: close the internal window correctly
+
+2013-07-07 21:14:22 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: only create the NS app thread for Cocoa once
+	  The helper thread for Cocoa, in case no NS run loop is running,
+	  should be started only once and shared across all the instances
+	  running
+
+2013-07-09 19:10:17 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: correct argument order in gst_util_uint64_scale_int_round
+	  https://bugzilla.gnome.org/show_bug.cgi?id=703350
+
+2013-07-09 17:42:59 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Keep caps order from the peer or the filter
+
+2013-07-09 12:42:17 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Fix handling of buffers without a duration
+	  We'll have to pop buffer from collectpads and store it
+	  internally only to get the timestamp of the next buffer.
+	  If we continue to keep it in collectpads, no new buffer
+	  to calculate the end time will ever arrive.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=703743
+
+2013-07-09 11:53:07 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Fix negotiation with 0/1 framerates
+	  https://bugzilla.gnome.org/show_bug.cgi?id=703743
+
+2013-07-09 11:17:59 +0200  Jonas Holmberg <jonashg@axis.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Unlock stream lock after use
+	  Stream lock of sink pad was not unlocked after non-updating seek.
+
+2013-06-27 13:26:31 +0200  Ognyan Tonchev <ognyan@axis.com>
+
+	* gst/multipart/multipartmux.c:
+	  multipartmux: Re-set need_segment flag after FLUSH_STOP
+	  https://bugzilla.gnome.org/show_bug.cgi?id=703182
+
+2013-07-05 11:51:04 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: bufferpool: don't forget to release buffer on error
+	  If the pool is stopped while gst_v4l2_buffer_pool_dqbuf() waits for a
+	  buffer then the return value is GST_FLOW_FLUSHING. In this case the buffer
+	  to queue must also be released. Otherwise is will never be deleted or
+	  returned to its pool.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=703764
+
+2013-07-08 14:15:10 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* tests/check/elements/rtp-payloading.c:
+	  rtp: Fail payloading unit test if an error message is received
+
+2013-07-08 14:09:37 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/rtp/gstrtph263ppay.c:
+	  rtph263ppay: Don't pass upstream filter caps to downstream
+	  Downstream usually can't accept video/x-h263 but only application/x-rtp,
+	  so we would always get an empty intersection here.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=702632
+
+2013-07-05 22:00:37 +0200  Piotr Drąg <piotrdrag@gmail.com>
+
+	* po/POTFILES.in:
+	  po: update POTFILES.in
+	  https://bugzilla.gnome.org/show_bug.cgi?id=703685
+
+2013-07-02 11:13:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: avoid some strdup
+
+2013-07-02 10:37:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: add select-stream signal
+	  Add a signal to let the app select what streams will be selected.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=634419
+
+2013-07-02 10:37:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: avoid strdup
+
+2013-07-02 10:12:17 +0200  J. Rick Ramstetter <rick.ramstetter@gmail.com>
+
+	* gst/rtp/README:
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtp: Fix documentation and comments to use rtpbin instead of old gstrtpbin
+	  https://bugzilla.gnome.org/show_bug.cgi?id=703426
+
+2013-07-01 16:55:01 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: don't extract data from caps twice
+	  gst_video_info_from_caps() always extract width, height, interlace mode and
+	  framerate now. It is no longer necessary to do it again for encoded
+	  formats.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=703399
+
+2013-06-20 09:41:48 -0300  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: also consider stop positions in seeks
+	  Use seek stop position as range end for requests
+	  https://bugzilla.gnome.org/show_bug.cgi?id=702206
+
+2013-06-19 14:06:40 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: allow seeks in ready
+	  On is_seekable, check if the server's headers have already been
+	  received. If not, do a HEAD request to get them before responding
+	  to basesrc.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=702206
+
+2013-07-01 17:28:55 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: add signal to notify of the SDP
+	  This way, the app can look and modify the SDP.
+
+2013-06-21 18:10:28 +0200  Kishore Arepalli <kishore.arepalli@gmail.com>
+
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	  gdkpixbufoverlay: Allow negative offsets to specify offset from bottom/right
+	  https://bugzilla.gnome.org/show_bug.cgi?id=702826
+
+2013-06-30 21:01:20 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/Makefile.am:
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: compute framerate from average sample duration
+	  https://bugzilla.gnome.org/show_bug.cgi?id=703350
+
+2013-06-25 21:16:38 +0200  Alban Browaeys <prahal@yahoo.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Add flvversion 1 to the flash-video caps
+	  This allows using avdec_flv which requires this field to be
+	  present in the caps. FLV only supports flash-video version 1
+	  right now.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=703076
+
+2013-07-01 11:37:00 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/interleave/deinterleave.c:
+	  deinterleave: Don't hold object lock while sending events downstream
+	  Based on a patch by Kishore Arepalli <kishore.arepalli@gmail.com>
+	  https://bugzilla.gnome.org/show_bug.cgi?id=703114
+
+2013-07-01 10:59:07 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Add MPEG4 video profile/level to the caps
+
+2013-07-01 10:56:28 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Add AAC profile/level to the caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=703312
+
+2013-06-28 15:21:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvorbispay.h:
+	  vorbispay: add support for config-interval
+	  Align code with the theora payloader and add support for the config-interval to
+	  periodically send out the config headers.
+
+2013-06-28 15:21:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtptheorapay.c:
+	  theorapay: small cleanups
+
+2013-06-28 12:08:19 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtptheorapay.c:
+	  theorapay: handle streamheaders as well
+
+2013-06-28 12:06:21 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	  vorbispay: always collect headers on data
+	  When we see a data packet, always check if we need to collect any previous
+	  headers.
+
+2013-06-28 11:43:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	  vorbispay: handle streamheader as well
+	  Take config strings from the streamheader when we can
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=664312
+
+2013-06-27 07:40:29 +0200  David Svensson Fors <davidsf@axis.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: avoid double buffer unmap on error
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=703171
+
+2013-06-27 17:02:14 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: reset-sync before play
+	  Call reset-sync on the rtpbin before we go to playing. This makes us require SR
+	  packets for all streams again before we attempt to sync them. If we don't reset,
+	  it might be that we combine SR packets from before and after the PAUSE/PLAYING
+	  state change and end up with huge bogus offsets.
+
+2013-06-27 16:23:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: improve sync on first packets
+	  Don't throw away the first RTCP packet if it arrives before the first
+	  RTP packet but remember and use it to signal sync once we get the
+	  RTP packet.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=691400
+
+2013-06-27 16:15:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: only signal loop when active
+	  Only signal the loop function when it is active.
+
+2013-06-27 16:13:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: signal timestamp discont
+	  We can now use the RESYNC buffer flag to mark a timestamp discont when we update
+	  the ts-offset property.
+
+2013-06-26 20:49:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  jpegpay: turn some errors into warnings
+	  Turn some errors into warnings, we can continue processing so this should
+	  not be fatal.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=657079
+
+2013-06-26 14:58:53 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: avoid some flushes
+
+2013-06-26 14:41:00 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: handle data message when waiting for reply
+	  When we are waiting for a server reply, handle data messages instead of
+	  ignoring them.
+
+2013-06-26 14:27:34 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: handle data messages in separate method
+	  Refactor and make a method to handle a data message.
+
+2013-06-25 20:36:18 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: add some more docs to handle-request signal
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=702705
+
+2013-06-10 17:20:30 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  Send a clock_provide message on the bus when we get a netclock
+
+2013-06-10 17:20:14 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Expose use-pipeline-clock property
+
+2013-06-24 17:11:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  udpsink: bind to the given interface
+	  Actually call BINDTODEVICE to bind to the interface as given by the
+	  property.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702819
+
+2013-06-22 10:59:17 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ext/vpx/gstvp8dec.c:
+	  vp8dec: Error out gracefully if we get an unsupported color format
+	  In theory we can only get I420 though, just to be on the safe side.
+
+2013-06-22 10:57:41 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ext/vpx/gstvp9dec.c:
+	* ext/vpx/gstvp9enc.c:
+	  vp9: Add support for YV12, Y42B and Y444 color formats
+	  The encoder does not work with Y42B and Y444 yet it seems.
+
+2013-06-22 10:26:18 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ext/vpx/gstvp9dec.c:
+	  vp9dec: Update default postproc settings from vp9_dx_iface.c
+
+2013-06-21 13:11:32 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/webm-mux.c:
+	  matroska: Add initial VP9 support
+
+2013-06-21 13:07:30 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* configure.ac:
+	* ext/vpx/Makefile.am:
+	* ext/vpx/gstvp9dec.c:
+	* ext/vpx/gstvp9dec.h:
+	* ext/vpx/gstvp9enc.c:
+	* ext/vpx/gstvp9enc.h:
+	* ext/vpx/plugin.c:
+	  vpx: Add initial, experimental VP9 support
+
+2013-06-21 10:32:30 +0200  Youness Alaoui <youness.alaoui at collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtsp: go back into the loop after doing pause
+	  After we do a pause request, go back to loop mode so that we can listen
+	  for server messages again.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=702705
+
+2013-06-20 23:16:17 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpptdemux.c:
+	  rtpptdemux: Wait after the caps to forward the other events
+	  First forward the stream-start, then the caps, then the rest
+
+2013-06-21 00:42:02 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximagesrc: clear dts on buffer acquired from pool
+	  When setting timestamps on outgoing buffers, clear the
+	  dts explicitly, otherwise it may end up being set to a
+	  bogus value from last time it was used. Avoids every
+	  second or so buffer's dts being set to 0. Not that it
+	  should matter for raw video.
+
+2013-06-20 15:35:11 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2.c:
+	  v4l2: don't redefine the PERFORMANCE debug variable
+	  It is already defined in core.
+	  fixes https://bugzilla.gnome.org/show_bug.cgi?id=702732
+
+2013-06-20 14:43:47 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix race in state change to paused
+	  When we go to paused, we first flush the connection and then send the pause
+	  command. As a result of the flushing, the scheduled paused command can get
+	  lost. Wait until the connection is completely flushed and the rtsp task is
+	  waiting before issuing the paused or playing request.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702705
+
+2013-06-20 11:31:22 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: handle SEGMENT query
+
+2013-06-19 12:37:31 +0200  Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: Optimize negotiation by removing the query filter
+	  As cameras tend to have a quite specific set of capabilities (specific
+	  framerates for each resolution), getting the peer caps filtered by our
+	  probed caps can cause a big increase in the caps size which slows down
+	  things quire a bit.
+	  As for negotiation v4l2 iterates through the caps of the peer to find the
+	  first intersection with the probed caps, getting the fully expanded
+	  intersection of capabilities is not useful.
+	  Using the same testcase as for bug #702632, adding this patch on top of
+	  the patches suggested there speeds up getting the inital frame from
+	  around ~14-15 seconds to around ~3-4 seconds.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=702638
+
+2013-06-19 10:30:56 +0200  Kishore Arepalli <kishore.arepalli@gmail.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: duration query returns zero for DV video in avi
+	  https://bugzilla.gnome.org/show_bug.cgi?id=702625
+
+2013-06-19 11:06:37 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Disable usage of allocation queries
+	  This can only reliably work if demuxers have a
+	  separate streaming thread per srcpad. This should be
+	  done in a demuxer base class, which integrates parts
+	  of multiqueue
+	  https://bugzilla.gnome.org/show_bug.cgi?id=701856
+
+2013-06-11 15:02:21 +0100  Alex Ashley <bugzilla@ashley-family.net>
+
+	* gst/isomp4/qtdemux.c:
+	  Avoid skipping moov atoms for fragmented MP4 files.
+	  bug #700505
+	  Following a representation change that causes a resolution change,
+	  the video decoder fails to decode correctly. Dashdemux detects the
+	  representation change and pushes a new caps event and an
+	  initialization segment (a new moov atom) to the downstream qtdemux,
+	  but it doesn't handle this new moov yet, it will only parse the
+	  first one it receives.
+	  This commit changes qtdemux to accept a new moov in a dash bitstream
+	  switching scenario.
+
+2013-06-19 00:42:54 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: send stream-start only once for each stream
+	  Do not send stream start again when reconfiguring a pad for new caps.
+	  That is common for adaptive streams
+
+2013-06-05 17:02:49 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/cocoawindow.m:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: fix support in VM's without hardware acceleration
+
+2013-06-15 12:29:31 +0200  Jens Georg <mail@jensge.org>
+
+	* gst/rtp/gstrtpmp2tdepay.c:
+	  rtpmp2tdepay: accept mislabelled streams from GStreamer 0.10 as well
+	  The mp2t payloader in 0.10 mislabelled the streams as MP2T-ES
+	  instead of MP2T, so accept that as well for compatibility reasons.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=702457
+
+2013-06-16 05:40:13 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: manage element state ourselves
+	  Lock the state of the all our elements and manage their states
+	  outselves. Because we are working async, we can't rely on the state
+	  change function to set the state at the right time or to return the
+	  right return value from the state change function.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=702046
+
+2013-06-14 14:09:50 +0200  Bruno Gonzalez <stenyak@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Don't unlock stream lock without locking it first
+	  https://bugzilla.gnome.org/show_bug.cgi?id=702167
+
+2013-06-13 16:00:33 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Use the right hashtable to calculate bandwidth
+	  Don't use an unused hashtable to iterate source to calculate bandwidth.
+	  Remove unused code.
+
+2013-06-12 16:27:24 -0600  Brendan Long <b.long@cablelabs.com>
+
+	* configure.ac:
+	  pulsesink: Require PulseAudio >= 2.0
+	  This is needed for pa_format_info_get_prop_* functions.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=686459
+
+2013-06-13 14:23:08 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* configure.ac:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulseutil.c:
+	  Revert "pulsesink: Make 2.0 dependency optional"
+	  This reverts commit 01457027e0d384aca3e551ae684e0aa074ee5498.
+	  We'll just depend on PulseAudio 2.0 or above instead of having the bug
+	  partially fixed based on the installed libpulse version.
+
+2013-06-13 12:40:15 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* configure.ac:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulseutil.c:
+	  pulsesink: Make 2.0 dependency optional
+	  The getcaps function we added uses some pa_format_info_get_prop...
+	  accessor functions that were only added in 2.0, so we only have our
+	  getcaps implementation exist if we're compiling against libpulse 2.0 or
+	  above.
+	  Eventually, we could bump the minimum requirement to 2.0 or above.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=686459
+
+2013-06-12 18:23:46 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/videomixer/videomixer2.c:
+	  Revert "videomixer: When all sinkpads are eos, update output segment stop and forward it"
+	  This reverts commit 2d3910fc7901b5f29e16c0fdd4e9067a6d7f66fe.
+	  It's not solving any problem and instead causes code to fall apart.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=701519
+
+2013-01-09 09:39:33 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: mark subtitle streams as sparse in stream-start event
+	  And also mark the streams that should be selected by default if
+	  marked so in the headers.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=600648
+
+2013-06-11 22:12:58 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/audiofx/audiopanoramaorc-dist.c:
+	* gst/audiofx/audiopanoramaorc-dist.h:
+	  audiopanorama: add prebuilt files
+
+2013-06-11 20:27:51 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/check/elements/audiopanorama.c:
+	  audiopanorama: cleanup and expand the tests
+	  Split out two more tests. Extract more common code into helpers. Add coverage for float.
+
+2013-06-10 21:15:20 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/audiofx/audiopanorama.c:
+	  audiopanorama: cleanup of transform()
+	  Only map input if we are reading it. Cleanup the logging and the comments a bit.
+
+2013-06-09 20:35:18 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/audiofx/Makefile.am:
+	* gst/audiofx/audiopanorama.c:
+	* gst/audiofx/audiopanorama.h:
+	* gst/audiofx/audiopanoramaorc.orc:
+	  audiopanorama: use orc to speedup processing
+	  Use special variants for the case when we don't change the panorama (pan=0.0).
+	  Simplify the processing functions by passing the panorama value directy instead
+	  of the instance. Use orc for clearing buffers too.
+
+2013-06-11 19:24:49 +0200  Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: check last end_time after conversion to running segment
+	  The last end_time was saved after conversion, so the comparison
+	  had to be made after conversion for it to make sense.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=701385
+
+2013-06-11 19:22:20 +0200  Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: add mix->segment.start to output_end_time
+	  When the segment start is not 0, this created a situation where
+	  the output_end_time is inferior to output_start_time, and the duration
+	  of the next buffer ended up underflowing.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=701385
+
+2013-06-11 13:54:53 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Send stream headers after the segment event
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700799
+
+2013-06-11 12:26:24 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Do allocation query after exposing all pads and no-more-pads
+	  Also configure video streams as early as possible.
+	  Related https://bugzilla.gnome.org/show_bug.cgi?id=701856
+	  but not fixing that.
+
+2013-06-11 12:25:46 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Don't forward CAPS events from upstream
+	  Just use the default pad event handler.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=701976
+
+2013-05-26 08:18:04 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Cache the getcaps/acceptcaps probe stream
+	  getcaps is called frequently during stream setup, and creating a new
+	  stream each time is very inefficient. There's some more room for
+	  optimisation by caching the queried sink formats as well, but this needs
+	  some more changes to listen for format changes on the sink (for when
+	  supported formats change between probe stream creation and sink
+	  querying).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=686459
+
+2013-05-23 21:39:08 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	* ext/pulse/pulseutil.c:
+	* ext/pulse/pulseutil.h:
+	  pulsesink: Add a getcaps function
+	  This allows us to have more fine-tuned caps in READY or above. However,
+	  this is _really_ inefficient since we create a new stream and query sink
+	  for every getcaps in READY, which on a simple gst-launch line happens
+	  about 35 times. The next step is to cache getcaps results.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=686459
+
+2013-05-10 11:32:44 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Take a lock on the ringbuffer in acceptcaps
+	  This is needed as a concurrent state change could pull the context or
+	  stream out from under our feet.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=686459
+
+2013-06-09 20:29:09 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/audiofx/audiopanorama.c:
+	* gst/audiofx/audiopanorama.h:
+	  audiopanorama: move the enum to the header and use instead of gint
+	  Move the enum for the processing method to the header so that we can use the
+	  type for the instance struct.
+
+2013-06-09 20:32:22 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/check/elements/level.c:
+	  level: rework the tests to cover other formats too
+
+2013-06-05 16:32:30 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: make sure the element is not deleted before the pool
+	  The pool accesses data from the v4l2object so it must exist at least
+	  as long as the pool. Refcount the element which controls the object
+	  live-time.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=701650
+
+2013-06-07 15:38:25 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/libpng/Makefile.am:
+	  png: Link with libgstbase for GstByteReader and GstAdapter
+
+2013-06-07 15:15:15 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/wavenc/Makefile.am:
+	  wavenc: Link with libgstbase for GstByteWriter
+
+2013-06-07 13:26:35 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Push stream-start event in pull mode before anything else
+
+2013-05-10 12:09:19 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	  pulsesink: Get rid of acceptcaps side-effects
+	  The sink info callback should not have side-effects on the GstPulseSink
+	  object since we are sometimes using with a dummy stream in acceptcaps.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=686459
+
+2013-06-05 18:36:40 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  Back to development
+
+=== release 1.1.1 ===
+
+2013-06-05 17:58:51 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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.signals:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* gst/deinterlace/tvtime-dist.c:
+	* gst/deinterlace/tvtime-dist.h:
+	* gst/videobox/gstvideoboxorc-dist.c:
+	* gst/videobox/gstvideoboxorc-dist.h:
+	* gst/videomixer/blendorc-dist.c:
+	* gst/videomixer/blendorc-dist.h:
+	* win32/common/config.h:
+	  Release 1.1.1
+
+2013-06-05 16:35:19 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2013-06-05 15:50:04 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: Fix taglist ref handling that made the unit test fail
+
+2013-06-05 15:14:54 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* common:
+	  Automatic update of common submodule
+	  From 098c0d7 to 01a7a46
+
+2013-06-03 09:17:43 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: iterate controls with V4L2_CTRL_FLAG_NEXT_CTRL if possible
+	  In v2.6.18 control classes where added to the v4l2 API.
+	  Iterating over CIDs starting with V4L2_CID_BASE will only find controls for
+	  the first control class.
+	  By iterating with V4L2_CTRL_FLAG_NEXT_CTRL all controls are found.
+	  This is necessary to make controls from other control classes available in
+	  the extra-controls property.
+	  If V4L2_CTRL_FLAG_NEXT_CTRL is not defined at compile time or not supported
+	  at runtime then the old mechanism for iterating is used.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=701540
+
+2013-06-05 12:12:53 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpsink.c:
+	  udpsink: avoid leaking the host
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701586
+
+2013-06-04 08:26:33 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2: improve pixel aspect ratio handling
+	  Instead of just assuming a aspect ratio of 1/1 use VIDIOC_CROPCAP to ask
+	  the device.
+	  This also add a pixel-aspect-ratio property to overwrite the value from the
+	  driver and a force-aspect-ratio property to ignore it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700285
+
+2013-06-04 17:04:11 +0200  Stirling Westrup <swestrup@gmail.com>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: Fix compilation with older kernels
+	  https://bugzilla.gnome.org/show_bug.cgi?id=701595
+
+2013-06-03 17:07:10 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: call VIDIOC_REQBUFS with count = 0 in pool_finalize
+	  Without this the following sequence fails:
+	  - set_caps()
+	  - object_stop() (does nothing)
+	  - set_format() -> VIDIOC_S_FMT
+	  - set_config() -> VIDIOC_REQBUFS with count = N
+	  - set_caps()
+	  - object_stop()
+	  - pool_finalize()
+	  - set_format() -> VIDIOC_S_FMT => EBUSY
+	  Usually the pool is started after set_config(), in which case object_stop()
+	  will result in a pool_stop and therefore VIDIOC_REQBUFS with count = 0 but
+	  that is not guaranteed.
+	  Also calling VIDIOC_REQBUFS with count = 0 in pool_finalize() if necessary
+	  fixes this problem.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701543
+
+2013-05-28 19:14:15 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: rework sink buffer refcounting
+	  This is a followup patch for #700781, which is not quite correct.
+	  The buffer handling is quite complicated here.
+	  The original code intended to the the following:
+	  - gst_v4l2_buffer_pool_process() calls QBUF and adds the buffer to the
+	  local list.
+	  - The sink calls gst_buffer_unref() which returns the buffer to the pool
+	  but not the 'free list'.
+	  - Some time later DQBUF returns the buffer and
+	  gst_v4l2_buffer_pool_release_buffer() puts in on the 'free list'.
+	  If the buffer must be copied then (parent_class)->acquire_buffer() is
+	  called directly to keep the buffer in the pool.
+	  This has two problems:
+	  1. If gst_v4l2_buffer_pool_release_buffer() is called before the buffer is
+	  returned to the pool, then the buffer is put on the 'free list' twice.
+	  This can happen if a reference to the buffer is kept outside the sink,
+	  of if DQBUF returns the buffer, that was just queued with QBUF.
+	  2. If buffers are copied, then all buffers are in the pool at all times. As
+	  a result gst_v4l2_buffer_pool_stop() and gst_v4l2_buffer_pool_dqbuf()
+	  can access pool->buffers at the same time, which can lead to memory
+	  corruption.
+	  The patch for #700781 fixes those problems, but with the side effect that
+	  there are always buffers outside the pool (because they are queued) and
+	  the pool is never stopped.
+	  This patch fixes this by releasing the reference to the buffer after
+	  handling it (to avoid problem 2.) so it can be returned to the pool.
+	  gst_v4l2_buffer_pool_release_buffer() is only called if the buffer is
+	  already in the pool (to avoid problem 1.).
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701375
+
+2013-06-02 15:24:38 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: make sure taglist is writable before adding tags
+	  Avoids assertions
+
+2013-05-30 19:24:13 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: effectively skip tracks that weren't listed on the 1st moov
+	  Without this, stream is NULL and the code will try to access it, leading
+	  to segfaults.
+
+2013-05-30 19:23:50 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: skip redundant check
+	  !got_moov is already checked the line above
+
+2013-06-02 13:03:40 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/check/elements/level.c:
+	  tests: cleanup level tests
+	  Split out a few more tests to avoid checking the same stuff over and over again.
+
+2013-06-01 21:33:46 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/level/gstlevel.h:
+	  level: remove unused variables in instance struct
+
+2013-05-31 18:13:02 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/check/elements/level.c:
+	  level: add a test for continous timestamps
+	  A test that checks that msg[n].ts + msg[n].dur == msg[n+1].ts.
+
+2013-04-12 16:02:44 +0300  Anton Belka <antonbelka@gmail.com>
+
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavenc/gstwavenc.h:
+	  wavenc: add tags & toc support
+	  Write tags as LIST INFO chunk. Format the toc as cue + LIST adtl chunk. Remove
+	  old #ifdef'ed code.
+
+2013-05-31 15:12:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  Revert "rtph264pay: Restructuring to allow for adding optional caps"
+	  This reverts commit 61666898cfe89a1b21d3e6850ab44f5b1633ed79.
+	  This commit changes what the set_sps_pps() function does, not it doesn't
+	  set caps anymore (and should have been renamed). The main problem is that
+	  not all call sites are updated and thus leak the string.
+
+2013-05-31 15:11:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264depay.h:
+	* gst/rtp/gstrtph264pay.c:
+	* tests/check/elements/rtp-payloading.c:
+	  Revert "rtph264pay/depay: Add frame dimensions a payloaded caps"
+	  This reverts commit 3dca756a5dba55266256f239e3e12a3d058e185a.
+	  The H264 RTP spec has no attributes for width and height.
+
+2013-05-31 15:09:51 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264depay.h:
+	* gst/rtp/gstrtph264pay.c:
+	  Revert "rtph264pay/depay: Add optional framerate caps for use in SDP"
+	  This reverts commit d8825e2a5c0bfb883ff88e2c9da499c800ebca0a.
+	  There is no framerate attribute in the h264 RTP spec.
+
+2013-05-31 15:08:16 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	  Revert "rtpjpegpay/depay: Replace framesize caps with width/height"
+	  This reverts commit 0075d111b475ca27895ee9476154260b6902940b.
+	  Extra application/x-rtp are SDP fields, which are strings.
+
+2013-05-31 15:05:51 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* tests/check/elements/rtp-payloading.c:
+	  Revert "rtpjpegpay/depay: Replace framerate caps field with fraction"
+	  This reverts commit 9fd25a810b859e0ec205176578735100d83de4af.
+	  We deal with sdp attributes in application/sdp, which are always strings.
+
+2013-05-31 12:33:21 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: add extra TLS url protocols
+	  We also support TLS protocols now.
+
+2013-05-30 14:48:42 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Add FIXME comment about the DURATION query from adder
+	  Currently the code just takes with maximum upstream duration, which
+	  is wrong. It should be the maximum upstream duration in running time.
+
+2013-05-30 21:20:59 +0200  Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Set a reference to mix->current_caps as the QUERY_CAPS result.
+
+2013-05-30 17:37:13 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/level/gstlevel.c:
+	  level: misc cleanups
+	  Fix some oudated comments. Sort out some confusion of interval_frames and num_frames.
+
+2013-05-29 20:35:41 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: Only conditionally use V4L2_CTRL_TYPE_INTEGER_MENU, it's not available in older versions
+
+2013-05-20 16:45:37 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2_calls.h:
+	  v4l2: add a property for arbitrary v4l2 controls
+	  This makes it possible to set any controls that can be set with
+	  VIDIOC_S_CTRL.
+	  The controls are set when the property is set (if the device is open)
+	  and when the device is opened.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=698837
+
+2013-05-28 18:31:07 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/level/gstlevel.c:
+	  level: fix discontinuities in timestamps
+
+2013-05-28 15:46:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/gdk_pixbuf/gstgdkanimation.c:
+	* ext/gdk_pixbuf/gstgdkpixbufdec.c:
+	* ext/gdk_pixbuf/gstgdkpixbufdec.h:
+	  gdkpixbufdec: Keep serialized events in order, and don't send SEGMENT before CAPS
+
+2013-05-28 15:45:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: create and push stream-start in TCP mode
+
+2013-05-28 15:10:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: remove some obsolete code
+	  It is not needed to do a state change from the _play() function on
+	  ourselves. The state change function already did that and we don't want to
+	  interfere with that (or use hacks to avoid interference).
+
+2013-05-28 12:24:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: set RTCP caps on the RTCP pads
+
+2013-05-28 12:23:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: send stream-start and segment events
+	  Also send stream-start and segment event on the RTCP pad.
+	  We don't need to send anything on the sync_src pad because we
+	  already forwarded all incomming events.
+
+2013-04-25 15:25:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: add signal to handle server requests
+	  Add a signal to be notified of a server request. The signal handler can then
+	  construct the response message for the server.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=632207
+
+2013-05-27 22:43:25 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Maintain z-order when new pad are added
+	  https://bugzilla.gnome.org/show_bug.cgi?id=701109
+
+2013-03-06 13:17:54 +0000  Tom Greenwood <tcdgreenwood@hotmail.com>
+
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp8enc.h:
+	  vp8enc: Add property to manually specify the timebase of the encoder
+	  https://bugzilla.gnome.org/show_bug.cgi?id=695709
+
+2013-05-25 12:17:40 -0400  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Always handle flush_stop_pending atomically
+	  It is not protected with the COLLECT_PADS_STREAM_LOCK anymore
+
+2013-05-23 18:14:17 -0400  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/videomixer.c:
+	  tests: videomixer: Add a testsuite for videomixer
+	  This is mostly copy pasted from -base/tests/check/elements/adder.c
+
+2013-05-25 10:57:02 -0400  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Do not take COLLECT_PADS_STREAM_LOCK when unnecessary
+	  Collectpad takes the lock itself when receiving serialized events
+	  and we should not take it for not serialized ones
+
+2013-05-24 19:34:05 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/flx/gstflxdec.c:
+	  flxdec: Properly skip non-frame chunks
+
+2013-05-24 19:31:14 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/flx/gstflxdec.c:
+	  flxdec: Flush data from adapter after reading it
+	  Otherwise we're going in an infinite loop, reading the same data
+	  over and over again.
+
+2013-04-24 15:39:54 +0000  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* gst/goom2k1/Makefile.am:
+	  goom2k1: fix more duplicated symbols
+
+2013-05-22 02:40:52 +0200  Sebastian Rasmussen <sebrn@axis.com>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* tests/check/elements/rtp-payloading.c:
+	  rtpjpegpay/depay: Replace framerate caps field with fraction
+	  The previous implementation had the formatting of SDP attributes happen
+	  in each RTP payloader, now instead the constituent values are propagated
+	  as caps fields. This allows for applications to do SDP offer/answer
+	  based on caps negotiation.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=700748
+
+2013-05-22 01:58:57 +0200  Sebastian Rasmussen <sebrn@axis.com>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay/depay: Replace framesize caps with width/height
+	  The previous implementation had the formatting of SDP attributes happen
+	  in each RTP payloader, now instead the constituent values are propagated
+	  as caps fields. This allows for applications to do SDP offer/answer
+	  based on caps negotiation.
+	  Keep parsing a-framerate, x-framerate and x-dimensions in rtpjpegdepay
+	  to be backwards compatible with previous payloaders.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=700748
+
+2013-05-22 03:18:07 +0200  Sebastian Rasmussen <sebrn@axis.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264depay.h:
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay/depay: Add optional framerate caps for use in SDP
+	  This allows for applications to format SDP attributes and still do SDP
+	  offer/answer based on caps negotiation.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=700749
+
+2013-05-22 03:09:44 +0200  Sebastian Rasmussen <sebrn@axis.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264depay.h:
+	* gst/rtp/gstrtph264pay.c:
+	* tests/check/elements/rtp-payloading.c:
+	  rtph264pay/depay: Add frame dimensions a payloaded caps
+	  This allows for applications to format SDP attributes and still do SDP
+	  offer/answer based on caps negotiation.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=700749
+
+2013-05-20 22:14:44 +0200  Sebastian Rasmussen <sebrn@axis.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: Restructuring to allow for adding optional caps
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=700749
+
+2013-05-23 18:42:09 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstdynudpsink.h:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	  (dyn|multi)udpsink: Add properties to specify the bind address and port
+	  By default we use the any addresses and a random port for binding the socket.
+
+2013-05-23 18:05:07 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	  (dyn|multi)udpsink: Bind socket before using it
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700878
+
+2013-05-23 17:25:29 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/udp/gstmultiudpsink.c:
+	  (multi)udpsink: Add missing getters for socket-v6 and used-socket-v6 properties
+
+2013-05-22 21:01:48 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Don't hold stream-lock while pushing non-serialized events
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700868
+
+2013-05-22 21:00:45 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Don't hold object lock while sending events
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700868
+
+2013-05-22 17:32:33 +0200  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: The return value of gst_pad_set_caps() is not relevant anymore
+	  Caps can fail to be set because the pad is not linked yet for example.
+
+2013-05-15 16:39:36 -0700  David Schleef <ds@schleef.org>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Add error if file has playready drm
+
+2013-05-18 15:06:49 -0400  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Send a reconfigure event upstream if sinkpad caps are not usable
+	  https://bugzilla.gnome.org/show_bug.cgi?id=684237
+
+2013-05-21 12:02:51 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: keep a reference to all queued buffers
+	  Without this, a queued buffer may be required, filled and queued before it
+	  is dequeued.
+	  Calling gst_buffer_pool_acquire_buffer() ensures that the buffer is set up
+	  correctly and gst_buffer_unref() calls buffer_release().
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700781
+
+2013-05-21 13:33:59 +0200  Alexander Schrab <alexas@axis.com>
+
+	* gst/law/mulaw-decode.c:
+	  mulawdec: Handle NULL buffers in handle_frame
+	  https://bugzilla.gnome.org/show_bug.cgi?id=698894
+
+2013-05-20 21:44:13 +0200  Sebastian Rasmussen <sebrn@axis.com>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay/depay: Add framesize caps for use in SDP
+	  The format of the value adheres to RFC6064 and it is meant to be parsed
+	  and included in the SDP sent by gst-rtsp-server to its clients.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=700748
+
+2013-05-20 21:34:13 +0200  Sebastian Rasmussen <sebrn@axis.com>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: Add optional framerate caps for use in SDP
+	  The format of the value adheres to RFC4566 and it is meant to be parsed
+	  and included in the SDP sent by gst-rtsp-server to its clients.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=700748
+
+2013-05-20 19:59:13 +0200  Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: When all sinkpads are eos, update output segment stop and forward it
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699793
+
+2013-05-20 19:51:07 +0200  Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Don't reset the output segment on flush stop
+	  Only init it when getting from READY to PAUSED, and change it on seek events.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699793
+
+2013-05-17 10:16:48 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: Don't stop streaming when set_caps is called with unchanged caps
+	  This can happen if other parts of the pipeline are reconfigured.
+	  Stop streaming even for a short amount of time can be quite visible, so it
+	  should be avoided if possible.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700503
+
+2013-05-18 15:39:36 -0400  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* tests/check/pipelines/simple-launch-lines.c:
+	  tests: Re-enable videomixer test
+	  https://bugzilla.gnome.org/show_bug.cgi?id=684237
+
+2013-05-18 14:36:39 -0400  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	  videomixer: Send caps event from the streaming thread
+	  This way we avoid races in caps negotiation and we make sure
+	  that the caps are sent after stream-start.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=684237
+
+2013-05-05 20:25:20 +0100  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Do not send flush_stop when receiving a seek
+	  There is no reason to send a flush-stop when receiving a seek event.
+	  In the case of a flushing seek, we could eventually want to, but in
+	  the code path were we check if the seek is "flushing", we have the
+	  following comment that makes sense:
+	  "we can't send FLUSH_STOP here since upstream could start pushing data
+	  after we unlock mix->collect.
+	  We set flush_stop_pending to TRUE instead and send FLUSH_STOP after
+	  forwarding the seek upstream or from gst_videomixer_collected,
+	  whichever happens first."
+	  https://bugzilla.gnome.org/show_bug.cgi?id=684237
+
+2013-05-05 20:24:49 +0100  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer2: Protect flush_stop_pending with the collectpad stream lock
+	  And make sure to expect a flush-stop after a flush-start
+	  https://bugzilla.gnome.org/show_bug.cgi?id=684237
+
+2013-05-17 12:37:59 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* gst/rtp/gstrtpmp4apay.c:
+	  rtpmp4apay: clear config buffer before using it
+	  This is necessary because parts of the memory are only modified with "|="
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700514
+
+2013-05-14 17:30:07 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Do not expect EOS after a segment event if upstream is mss
+	  In case qtdemux is handling a mss stream, do not mark the stream to wait
+	  for EOS after a segment. Even if it seems to be the last one according to
+	  the current streams information.
+	  MSS handling is different here because there is another demuxer driving
+	  the pipeline
+
+2013-05-14 16:32:51 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: only set channels and rate if qtdemux knows it
+	  Setting both of those to 0 is pointless and means that qtdemux
+	  doesn't know the real value. Avoid setting it in this case.
+
+2013-05-14 15:23:08 +0200  Arnaud Vrac <avrac@freebox.fr>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: set alac caps using info from codec buffer
+	  The samplerate field in the STSD atom is not right for some ALAC files
+	  (usually when audio is 96kHz/24bits), so the audio caps must be
+	  extracted from the codec data.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700382
+
+2013-05-15 11:13:12 +0200  Arnaud Vrac <avrac@freebox.fr>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: do not push discont buffers if they aren't discont
+	  https://bugzilla.gnome.org/show_bug.cgi?id=682110
+
+2013-05-15 10:51:38 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 5edcd85 to 098c0d7
+
+2013-05-14 10:28:10 -0400  Joshua M. Doe <oss@nvl.army.mil>
+
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videocrop/gstvideocrop.c:
+	  videocrop: Add support for GRAY16_LE/GRAY16_BE
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700331
+
+2013-05-14 17:29:58 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/replaygain/gstrgvolume.c:
+	  rgvolume: Send all events through the proxypads instead of just sending to the target
+	  Otherwise the sticky events are missing on the proxypads.
+
+2013-05-14 17:29:18 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/rgvolume.c:
+	  rgvolume: Fix event handling in the unit test
+
+2013-05-14 16:34:54 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/rglimiter.c:
+	  rglimiter: Fix event handling in unit tests
+
+2013-05-14 16:31:57 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/rganalysis.c:
+	  rganalysis: Fix event handling in unit test
+
+2013-05-14 16:08:54 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/qtmux.c:
+	  qtmux: Fix event handling in unit test
+
+2013-05-14 16:00:58 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/multifile.c:
+	  multifile: Fix event handling in unit test
+
+2013-05-14 13:58:01 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/mulawdec.c:
+	* tests/check/elements/mulawenc.c:
+	  mulaw: Fix event handling in unit test
+
+2013-05-14 13:52:18 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-parse.c:
+	  matroskaparse: Make sure to send a segment event before dataflow
+
+2013-05-14 10:52:19 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: only add interlace-mode to the caps for raw formats
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700280
+
+2013-05-14 12:03:03 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: copy and set the actual size of the content
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700282
+
+2013-05-14 10:25:56 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/interleave.c:
+	  interleave: Fix event handling in unit test
+
+2013-05-14 09:45:12 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Improve handling of min/max buffer numbers of the buffer pool
+
+2013-05-14 03:42:59 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: set caps for buffer pool config
+
+2013-05-13 13:30:38 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: Let the base class do get_times
+	  This will make sync=TRUE work, the default is still sync=FALSE
+
+2013-05-11 23:08:23 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/interleave/interleave.c:
+	  interleave: Send stream-start before caps event
+
+2013-05-11 23:24:36 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	* tests/check/elements/rtpmux.c:
+	  rtpmux: Send stream-start before caps
+
+2013-05-11 23:28:12 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffer-test: Send stream-start before caps followed by segment
+
+2013-05-11 23:34:36 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* tests/check/elements/rtpbin.c:
+	  rtpbin-test: Send missing stream-start and segment events
+
+2013-05-13 15:36:19 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/level.c:
+	* tests/check/elements/matroskamux.c:
+	  tests: Fix some more event handling in tests
+
+2013-05-13 15:19:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/icydemux.c:
+	  icydemux: Fix event handling in unit test
+
+2013-05-13 15:19:25 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/icydemux/gsticydemux.c:
+	  icydemux: Fix sticky event handling
+
+2013-05-13 15:06:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Push sticky events in the right order
+
+2013-05-13 14:55:14 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/deinterleave.c:
+	  deinterleave: Fix event handling in test
+
+2013-05-13 14:07:11 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/interleave/deinterleave.c:
+	  deinterleave: Fix sticky event handling
+
+2013-05-13 13:55:44 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/interleave/deinterleave.c:
+	  deinterleave: Code style fixes
+
+2013-05-13 10:43:32 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: First let baseclass handle events, then put them into the stream
+	  Fixes handling of sticky events.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700213
+
+2013-05-09 22:05:24 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* tests/check/elements/shapewipe.c:
+	  shapewipe-test: Send inital events
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700033
+
+2013-05-09 18:32:23 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/elements/spectrum.c:
+	  spectrum-test: Send inital events
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700033
+
+2013-05-09 18:25:17 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/elements/videofilter.c:
+	  videofilter-test: Send inital events
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700033
+
+2013-05-09 18:23:30 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/elements/wavpackparse.c:
+	  wavpackparse-test: Send inital events
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700033
+
+2013-05-09 18:21:54 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/elements/y4menc.c:
+	  y4menc-test: Send inital events
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700033
+
+2013-05-10 14:00:33 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/multipart/multipartdemux.c:
+	  multipartdemux: fix example pipeline
+	  Need jpegparse.
+
+2013-05-10 13:34:16 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/alphacolor.c:
+	* tests/check/elements/aspectratiocrop.c:
+	* tests/check/elements/audioamplify.c:
+	* tests/check/elements/audiochebband.c:
+	* tests/check/elements/audiocheblimit.c:
+	* tests/check/elements/audiodynamic.c:
+	* tests/check/elements/audioecho.c:
+	* tests/check/elements/audioinvert.c:
+	* tests/check/elements/audiopanorama.c:
+	* tests/check/elements/audiowsincband.c:
+	* tests/check/elements/audiowsinclimit.c:
+	* tests/check/elements/avimux.c:
+	* tests/check/elements/avisubtitle.c:
+	* tests/check/elements/capssetter.c:
+	* tests/check/elements/deinterlace.c:
+	* tests/check/elements/dtmf.c:
+	* tests/check/elements/equalizer.c:
+	  tests: Fix some more unit tests
+
+2013-05-10 13:10:29 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/parser.c:
+	  tests: Fix parser tests
+
+2013-05-09 22:20:28 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  shapewipe: Can't map twice the same buffer for writing
+	  I took the opportunity to simplify that code a bit. We now use
+	  gst_buffer_make_writable() to make the buffer writable and map twice the
+	  same buffer, with first map being read/write, and second read only. This
+	  get rid of the critical:
+	  GStreamer-CRITICAL **: gst_structure_set_name: assertion `IS_MUTABLE
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700044
+
+2013-05-09 22:15:54 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  shapewipe: Ensure caps are writable
+	  The exist one case where that we endup with original caps in ret, in which
+	  case we are not guaratied to have writable caps. Simply ensure this is the
+	  caps are writable before entering the loop.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700044
+
+2013-05-09 22:13:51 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  shapewipe: Fix sample pipeline in documentation
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700044
+
+2013-05-09 18:05:02 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/elements/jpegenc.c:
+	  jpegenc-test: Send inital events
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700033
+
+2013-05-09 17:49:03 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/elements/vp8enc.c:
+	  vp8enc-test: Send inital events
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700033
+
+2013-05-09 17:20:18 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/elements/vp8dec.c:
+	  vp8dec-test: Send inital events
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700033
+
+2013-05-09 17:19:53 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/elements/wavpackdec.c:
+	  wavpackdec-test: Send initial events
+	  https://bugzilla.gnome.org/show_bug.cgi?id=700033
+
+2013-05-09 16:26:19 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  Revert "videomixer2: Take into account new segments"
+	  This reverts commit 84ae670ab40b258a10e1e21471e6dc9d786bf086.
+	  Actually this is not how it is supposed to work. videomixer
+	  creates a [0,-1] segment and then puts frames of the different
+	  streams there based on their running times in their own segments.
+
+2013-05-06 23:43:03 +0200  Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer2: Take into account new segments
+	  Also forward the event downstream on the next opportunity.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699793
+
+2013-05-09 09:07:38 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  Revert "gstrtspsrc: set buffer-size for multicast buffers"
+	  This reverts commit 2481e95d038b42297a016f1d2dc1af26d2175b42.
+	  This is already done five lines above, it was added a year
+	  ago in commit 561b131e.
+
+2013-05-08 19:54:19 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* tests/check/elements/videofilter.c:
+	  videofilter: Unit test send SEGMENT before CAPS
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699966
+
+2013-05-08 19:22:31 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* tests/check/elements/avimux.c:
+	  avimux: Unit test sends SEGMENT before caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699966
+
+2013-05-08 19:08:24 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* tests/check/elements/audiowsincband.c:
+	  audiowsincband: Test should send segment after CAPS
+	  This makes the unit test pass again.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699966
+
+2013-05-08 19:00:28 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* tests/check/elements/audiowsinclimit.c:
+	  audiowsinclimit: Test should send segment after CAPS
+	  This makes the unit test pass again.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699966
+
+2013-05-08 18:44:32 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/audiofx/audiowsinclimit.c:
+	  audiowsinclimit: Frequence property renamed cutoff
+	  Updating the documentation to reflect this change.
+	  See: https://bugzilla.gnome.org/show_bug.cgi?id=699964
+
+2013-05-08 15:25:58 -0300  Aha Unsworth <aha.unsworth@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  gstrtspsrc: set buffer-size for multicast buffers
+	  For receiving video data via RTSP when the video is sent via
+	  multicast there is no way to specify the udpsrc buffer-size.
+	  On windows the native network buffer is not large and with video
+	  i-frames being huge the buffer is to small and you get i-frame corruption,
+	  it looks terrible, and there is no (easy) way to set the udpsrc buffer-size.
+	  https://bugs.freedesktop.org/show_bug.cgi?id=52264
+
+2013-05-08 16:02:05 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer2: Send stream-start before caps event
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699895
+
+2013-05-07 19:15:49 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fix compiler warning on type check
+
+2013-04-18 07:49:54 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: push new caps events when caps change
+	  Whenever the demuxer has a new caps on a stream, it should set the
+	  new_caps variable to true and a new caps event will be pushed before
+	  the next buffer
+
+2013-04-17 16:54:22 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: do not push discont buffers if they aren't discont
+	  qtdemux takes its buffers from a GstAdapter. Those buffers are created
+	  from the larger buffer that it obtained from upstream and they carry
+	  the same flags, including DISCONT if it is set. In these cases, all
+	  buffers that qtdemux is going to push would be marked as DISCONT.
+	  This scenario can make parsers/decoders flush on every buffer leading
+	  to no decoding at all hapenning. This patch prevents this by unsetting
+	  the flag if it shouldn't be set.
+
+2013-04-12 09:08:16 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: some code cleanup for mss handling code
+	  * Explicitly init variables for fragmented formats at init
+	  * Do not use GstClockTime type if the variable isn't a timestamp
+	  * Fix a style/readability issue at an if block
+	  * Group 2 mss mode conditional blocks together to improve readability
+	  Conflicts:
+	  gst/isomp4/qtdemux.c
+
+2013-04-12 10:21:11 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: avoid storing non-time newsegments to push later
+	  This can confuse downstream when they get a byte segment after receiving
+	  the natural time segment from qtdemux that it sends when starting to
+	  push buffers. This is specially the case with parsers that try to
+	  convert the position from byte to time format and might miss the
+	  correct position for playback to start.
+
+2013-04-10 18:02:28 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: avoid setting fields to non-writable caps
+
+2013-03-10 04:15:06 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: don't send so many segment events
+	  Only send one segment event in the beginning of the stream, not
+	  after each moov and moof atom.
+	  Conflicts:
+	  gst/isomp4/qtdemux.c
+
+2013-03-08 16:02:26 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: place incomming timestamps on output
+	  Place the incomming timestamp (if any) directly onto the outgoing buffers
+	  and interpollate other timestamps.
+	  Conflicts:
+	  gst/isomp4/qtdemux.c
+
+2013-05-07 10:16:18 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: improve reset of internal status
+	  Reset different variables on state changes to ready and when
+	  handling a flush-stop. For handling flush stops we should check
+	  if there is an upstream adaptive demuxer driving the pipeline as this
+	  means that qtdemux will get a new moov atom. For 'standard' isomedia
+	  streams this isn't true and qtdemux should keep the previous moov
+	  information around.
+	  Conflicts:
+	  gst/isomp4/qtdemux.c
+
+2013-02-08 00:29:20 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: prepare qtdemux to accept multiple dash moovs in a row
+	  Whenever dashdemux switches bitrates it sends a new moov with the
+	  new stream configuration. qtdemux should now handle this by splitting
+	  the exposing and configuration of streams into separate functions. When
+	  the stream is new it is configured and exposed, when it is a new bitrate
+	  of an existing stream it is only reconfigured.
+	  Conflicts:
+	  gst/isomp4/qtdemux.c
+
+2013-02-07 14:12:53 -0200  Andre Moreira Magalhaes (andrunko) <andre.magalhaes@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Move FLUSH_STOP/PAUSED_TO_READY handling to a reset method.
+	  Conflicts:
+	  gst/isomp4/qtdemux.c
+
+2013-01-23 10:55:33 -0500  Louis-Francis Ratté-Boulianne <louis-francis.ratte-boulianne@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: Remove old pads when exposing streams and other general fixes.
+	  Conflicts:
+	  gst/isomp4/qtdemux.c
+
+2013-04-16 10:41:43 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: handle mss streams
+	  smoothstreaming streams should be handled as a special kind of
+	  fragmented isomedia. In MSS the fragments will not contain a
+	  'moov' atom with the media descriptions, this has to be extracted
+	  from the caps.
+	  Additionally, there should be another demuxer upstream that is likely
+	  going to be the one to answer/act on queries and events, so qtdemux has
+	  to forward those upstream.
+
+2013-05-06 16:54:02 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: request 0 buffers when stopping
+	  Without this stopping the pool in *_set_caps() is useless.
+	  S_FMT will still fail with EBUSY.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699835
+
+2013-05-07 16:32:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: By default assume that we're working on non-packetized input
+	  Only detecting this in set_format() does not work because we might
+	  not get any caps at all, e.g. from filesrc.
+
+2013-05-07 16:30:59 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: Implement parsing functionality
+	  This allows to plug pngdec directly without a parser if that
+	  is desired.
+	  Parsing code is based on pngparse.
+
+2013-05-07 15:54:24 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/libcaca/gstcacasink.c:
+	  cacasink: Fix support for RGB formats and add support for more of them
+
+2013-05-04 13:19:53 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Don't consider the content size from the HTTP headers as absolutely correct
+	  The HTTP server could give wrong information, e.g. if the HTTP stream is
+	  chunk-encoded or compressed, or if the server does not know the complete size
+	  at the time when the file is requested by the client.
+	  Also see
+	  https://bugs.webkit.org/show_bug.cgi?id=115354
+
+2012-08-20 09:52:32 +0200  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: fill out v4l2_buffer.bytesused field for v4l2sink
+	  When queuing a buffer for a sink, bytesused must contain the actual
+	  amount of data.
+	  For a source, the driver must overwrite this, so it doesn't matter
+	  what is set here.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699598
+
+2013-05-03 23:43:26 +0200  Sebastian Rasmussen <sebras@gmail.com>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: fix invalid memory access in event handler
+	  First process event in payloader, then hand it to the
+	  base class which takes ownership of the event.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699637
+
+2013-05-04 09:48:02 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	  ac3parse, dcaparse: check buffer size before trimming
+	  and unref old buffer as soon as possible.
+
+2013-05-02 15:00:22 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstdcaparse.h:
+	  dcaparse: add support for "audio/x-private1-dts"
+
+2013-05-02 14:56:02 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstac3parse.h:
+	  ac3parse: add support for "audio/x-private1-ac3"
+
+2013-05-03 12:46:37 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: always generate video info from caps
+	  In the past gst_video_info_from_caps() only video/x-raw. Now it also
+	  supports other video/* and image/* formats.
+	  With this patch the format won't be GST_VIDEO_FORMAT_UNKOWN and
+	  gst_v4l2_buffer_pool_set_config() handles strides correctly.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699570
+
+2013-05-02 09:41:01 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2: try to allocate new buffers with VIDIOC_CREATE_BUFS if needed
+	  If max_buffers is 0 then an arbitrary number of buffers (currently 4) is
+	  allocated. If this is not enough v4l2src starts copying buffers.
+	  With this patch VIDIOC_CREATE_BUFS is used to allocate a new buffer. If
+	  this fails v4l2src falls back to copying buffers.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699447
+
+2013-04-15 17:37:01 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: fix setting window handle after transition
+	  The destroyed flag was not reset properly and it's also not needed
+	  as we can check osxwindow != NULL
+
+2013-05-02 13:45:55 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* gst/rtp/Makefile.am:
+	  rtp: fix duplicated symbols with libvpx
+
+2013-04-29 10:58:08 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* gst/goom2k1/Makefile.am:
+	  goom2k1: fix duplicated symbols with goom
+
+2013-05-01 15:49:45 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: If the adapter is empty on EOS don't try to map its content
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699314
+
+2013-04-30 14:36:38 +0200  Ognyan Tonchev <ognyan@axis.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: add stream-format=raw to aac caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699303
+
+2013-04-30 13:07:37 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: fix and cleanup VIDIOC_EXPBUF handling
+	  clear the struct, and provide a correct error message
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699337
+
+2012-07-05 18:02:27 +0200  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: handle return value -ENOTTY for unimplemented VIDIOC_G_PARM
+	  Newer kernels return -ENOTTY, older kernels return -EINVAL if the ioctl
+	  is not implemented. With this patch, GStreamer handles both cases.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=698825
+
+2013-04-30 09:16:07 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: fix broken boolean expression to detect non-frame buffers
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699294
+
+2013-04-29 11:07:56 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Better error message when server version is too old
+	  We check for the library version at configure time, but the server
+	  version can only really be checked at run-time.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=698768
+
+2013-04-27 11:24:38 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/udp/gstudp.c:
+	  udp: log WARNING debug message if UDP multicast is likely to be broken
+
+2013-04-27 11:16:54 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: add includes to get socklen_t defined on Windows
+	  https://bugzilla.gnome.org/show_bug.cgi?id=692400
+
+2013-04-27 09:39:45 +0100  Yury Delendik <async.processingjs@yahoo.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: add support for VP6F VP6 flash codec
+	  https://bugzilla.gnome.org/show_bug.cgi?id=699010
+
+2012-09-05 16:39:31 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: also poll for output devices
+	  Note that the V4L2 API defines that for output devices POLLOUT
+	  indicates that a buffer is ready to be dequeued.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=698992
+
+2012-08-20 09:52:34 +0200  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: fix copying of encoded buffers
+	  The existence of a GstVideoFormatInfo does not guarantee, that
+	  the buffer contains video frames, so the format must be checked.
+	  Also, for encoded buffers the length is variable and must be set.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=698949
+
+2012-07-10 15:29:40 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: add support for mpeg4 and H.263
+	  https://bugzilla.gnome.org/show_bug.cgi?id=698826
+
+2013-04-26 12:16:49 +0200  Edward Hervey <edward@collabora.com>
+
+	* gst/monoscope/gstmonoscope.c:
+	  monoscope: Fix debug statement
+
+2013-04-25 21:50:33 +0200  Alexander Schrab <meros@meros-desktop.(none)>
+
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-decode.h:
+	* tests/check/Makefile.am:
+	* tests/check/elements/mulawdec.c:
+	  mulawdec: change base class to GstAudioDecoder
+	  https://bugzilla.gnome.org/show_bug.cgi?id=698894
+
+2013-04-25 20:59:52 +0200  Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
+
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	  videomixer: send stream-start event.
+
+2012-10-18 10:37:35 +0200  Philipp Zabel <p.zabel@pengutronix.de>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: handle ENODATA return value for VIDIOC_ENUMSTD
+	  In kernel v3.7-rc1, VIDIOC_ENUMSTD returns ENODATA if the current input
+	  does not support the STD API.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=698827
+
+2013-04-25 13:19:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpbvpay.c:
+	  docs: add some pay/depayloaders
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=551631
+
+2013-04-25 12:44:15 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/law/mulaw-encode.c:
+	* tests/check/elements/mulawenc.c:
+	  mulaw: Some minor memleak fixes and cleanup
+
+2013-04-24 13:56:56 +0200  Alexander Schrab <alexas@axis.com>
+
+	* gst/law/mulaw-encode.c:
+	* gst/law/mulaw-encode.h:
+	* tests/check/Makefile.am:
+	* tests/check/elements/mulawenc.c:
+	  mulawenc: change to gstaudioencoder base, added bitrate tags
+
+2012-05-03 16:07:27 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: bufferpool: reset buffer size in release_buffer
+	  The buffer might still be in use elsewhere when dequeuing buffers for
+	  outputs.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=698822
+
+2012-04-20 09:53:35 +0200  Michael Olbrich <m.olbrich@pengutronix.de>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: bufferpool: remove unused includes
+	  The hacks that needed these are long gone.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=698821
+
+2013-04-25 12:12:23 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	  (multi)udpsink: Use separate sockets for IPv4 and IPv6
+	  https://bugzilla.gnome.org/show_bug.cgi?id=534243
+
+2013-04-25 10:44:44 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstdynudpsink.h:
+	  dynudpsink: Use separate sockets for IPv4 and IPv6
+	  https://bugzilla.gnome.org/show_bug.cgi?id=534243
+
+2013-04-25 10:43:56 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/udp/Makefile.am:
+	  udp: Don't include removed gstudp.h in noinst_HEADERS
+
+2013-04-17 16:47:31 -0700  Todd Agulnick <todd@agulnick.com>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	  osxaudio: Use gst_audio_channel_positions_to_mask() to create mask
+	  https://bugzilla.gnome.org/show_bug.cgi?id=698807
+
+2013-04-17 16:12:26 -0700  Todd Agulnick <todd@agulnick.com>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	  osxaudio: Remove unused code
+
+2013-04-25 09:16:14 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/udp/Makefile.am:
+	* gst/udp/gstdynudpsink.h:
+	* gst/udp/gstmultiudpsink.h:
+	* gst/udp/gstudp.h:
+	* gst/udp/gstudpsink.h:
+	* gst/udp/gstudpsrc.h:
+	  udp: Remove unused enum type
+
+2013-04-25 09:13:51 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/udp/Makefile.am:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudp-marshal.list:
+	  udp: Use the generic marshaller instead of generating marshallers
+
+2013-04-25 09:07:41 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	* gst/udp/gstudpsrc.h:
+	  udpsrc: Rename instance variable from host to multi_group
+	  This is more consistent as it's used for the multicast-group property.
+
+2013-04-25 09:03:56 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Add bind-address property
+	  This is equivalent to multicast-group currently for backwards compatibility.
+	  In 2.0 this should be handled separately, the former only being the multicast
+	  group and the latter always being the address the socket is bound to, even if
+	  a multicast group is given.
+
+2013-04-24 16:24:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  vrawdepay: return output buffer from process
+	  Return the output buffer from the process function instead of pushing
+	  it ourselves. This way, the subclass can actually deal with the return
+	  value of the push.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=693727
+
+2012-10-01 09:29:21 -0300  Diogo Carbonera Luvizon <diogo.luvizon@ensitec.com.br>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: save the format correctly
+	  If TRY_FMT is not implemented,  gst_v4l2_object_get_nearest_size will
+	  use S_FMT and will change the device's operation mode. To save the
+	  old device mode we need to set the type field or else it will fail
+	  to save the previous format.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=685209
+
+2013-04-24 15:38:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpg722depay.c:
+	* gst/rtp/gstrtpg723depay.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	  rtp: a marker bit should translate to RESYNC
+	  A marker bit on an audio packet does not mean a DISCONT (in the GStreamer sense
+	  of missing data) but it means that the packet is the end of a talkspurt and thus
+	  a good opportunity to resync to the clock. Use the RESYNC buffer flag to note
+	  this.
+	  Real discontinuities are marked with DISCONT still when the seqnum has a GAP or
+	  when the input buffer has the DISCONT flag set.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=627204
+
+2013-04-22 23:51:38 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* MAINTAINERS:
+	* README:
+	* README.static-linking:
+	* common:
+	  Automatic update of common submodule
+	  From 3cb3d3c to 5edcd85
+
+2013-04-22 10:19:29 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	  rtpjpegdepay: Drop frame if it's less than 2 bytes large
+	  https://bugzilla.gnome.org/show_bug.cgi?id=677560
+
+2013-04-18 12:20:08 +0300  Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	  autodetect: use _plugin_feature_rank_compare API instead of duplicating the code.
+
+2013-04-18 09:37:30 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/osxaudio/gstosxaudioringbuffer.h:
+	  osxaudio: Include gstaudioringbuffer.h to fix compilation in 1.0
+
+2013-04-17 21:05:14 +0200  Philippe Normand <philn@igalia.com>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	  osxaudiosink: channel-mask configuration fixes
+	  Set channel-mask according to sink's layout in case of stereo layout.
+	  Also initialize and reset the mask when an unrecognized channel is detected.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=698224
+
+2013-04-15 19:53:28 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: Disable renegotiation in the negotiate method
+	  This way, we don't block the initial negotiation.
+	  Thanks to Jeremy Whiting for doing all the testing.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=695981
+
+2013-04-15 19:46:12 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* sys/v4l2/gstv4l2src.c:
+	  Revert "v4l2: disable renegotiation"
+	  This reverts commit d1b26e1d594ab2b63324e43a36330475e98cdf18.
+	  This causes the initial negotiation to never happen if a reconfigure
+	  event is received after gst_base_src_start_complete() but before the loop
+	  starts.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=695981
+
+2013-04-17 21:12:55 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/flac/gstflactag.c:
+	  flactag: forward caps event
+	  This ensures that the downstream element will get the event and negotiates. Add
+	  a FIXME for updating the streamheader field on th caps.
+
+2013-04-17 07:50:27 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflactag.c:
+	  flac: add more logging
+
+2013-04-17 20:24:48 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/osxaudio/gstosxcoreaudiocommon.h:
+	  osxaudio: Fix merge conflicts
+
+2013-04-17 10:10:46 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  osxaudio: Fix configure check for osxaudio plugin
+
+2013-04-17 09:50:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/osxaudio/gstosxaudioringbuffer.c:
+	  osxaudioringbuffer: First check the type, then cast
+
+2013-04-16 22:46:00 +0900  Takashi Nakajima <ted.nakajima@gmail.com>
+
+	* sys/osxaudio/gstosxaudioringbuffer.c:
+	* sys/osxaudio/gstosxaudiosink.h:
+	  osxaudio: use GST_IS_OSX_AUDIO_SINK in ring buffer.
+
+2013-04-10 21:06:16 +0900  Takashi Nakajima <ted.nakajima@gmail.com>
+
+	* sys/osxaudio/gstosxaudioringbuffer.c:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosink.h:
+	  osxaudio: call set_channel_positions() in osxaudioringbuffer acquire()
+
+2013-04-12 12:18:04 -0700  Todd Agulnick <todd@agulnick.com>
+
+	* sys/osxaudio/gstosxaudioringbuffer.c:
+	  osxaudio: use GST_AUDIO_INFO_* accessors
+	  Changes include the following:
+	  * Update classname references
+	  * Replace GST_BOILERPLATE_FULL with G_DEFINE_TYPE
+	  * Use new GstAudioInfo struct and methods
+	  * Use new buffer memory allocation scheme
+	  Conflicts:
+	  sys/osxaudio/gstosxaudioringbuffer.c
+
+2013-04-12 11:51:46 -0700  Todd Agulnick <todd@agulnick.com>
+
+	* sys/osxaudio/gstosxcoreaudiocommon.h:
+	* sys/osxaudio/gstosxcoreaudiohal.c:
+	  osxaudio: adjust for changes to glib mutex api.
+
+2013-04-10 01:21:49 +0900  Takashi Nakajima <ted.nakajima@gmail.com>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	  osxaudio: try to fix up according to Sebastian's comments
+
+2013-04-05 10:02:38 +0200  Philippe Normand <philn@igalia.com>
+
+	* configure.ac:
+	* sys/osxaudio/gstosxaudioringbuffer.h:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosink.h:
+	* sys/osxaudio/gstosxaudiosrc.h:
+	  osxaudio: build fixes
+	  Enable the osxaudio plugin build in configure.ac and fix some
+	  include directive order issues.
+
+2013-04-02 22:28:09 +0900  ted-n <ted.nakajima@gmail.com>
+
+	* sys/osxaudio/gstosxaudiosrc.c:
+	  osxaudio: fix layout for osxaudiosrc
+
+2013-03-30 22:49:34 +0900  ted-n <ted.nakajima@gmail.com>
+
+	* sys/osxaudio/Makefile.am:
+	* sys/osxaudio/gstosxaudioelement.c:
+	* sys/osxaudio/gstosxaudioringbuffer.c:
+	* sys/osxaudio/gstosxaudioringbuffer.h:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosink.h:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxaudio/gstosxaudiosrc.h:
+	* sys/osxaudio/gstosxcoreaudiocommon.c:
+	* sys/osxaudio/gstosxcoreaudiocommon.h:
+	  osxaudio: port to v.1.0
+
+2013-04-16 19:29:48 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Don't unref query, we don't own it
+	  Fixes double-unref bug. Bug found by Youness Alaoui
+
+2013-04-16 20:41:10 +0200  Philippe Normand <philn@igalia.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: fix SCHEDULING query support
+	  Chain the query up to parent before adding _BANDWIDTH_LIMITED flag,
+	  so that all the other flags get set, and push mode gets added as
+	  supported activation mode.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=693484
+	  https://bugzilla.gnome.org/show_bug.cgi?id=698156
+
+2013-03-31 12:05:49 +0200  Philippe Normand <philn@igalia.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: basic scheduling query support
+	  Answer to scheduling queries with default parameters and the new
+	  _BANDWIDTH_LIMITED_FLAG so that downstream is advised to minimize seek
+	  operations and perform on-disk buffering if possible.
+	  Bug 693484
+
+2013-04-15 14:32:46 +0000  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: fix segfault accessing osxwindow when not set yet
+
+2012-10-24 12:14:50 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* ext/aalib/Makefile.am:
+	* ext/cairo/Makefile.am:
+	* ext/dv/Makefile.am:
+	* ext/flac/Makefile.am:
+	* ext/gdk_pixbuf/Makefile.am:
+	* ext/jack/Makefile.am:
+	* ext/jpeg/Makefile.am:
+	* ext/libcaca/Makefile.am:
+	* ext/libpng/Makefile.am:
+	* ext/mikmod/Makefile.am:
+	* ext/pulse/Makefile.am:
+	* ext/raw1394/Makefile.am:
+	* ext/shout2/Makefile.am:
+	* ext/soup/Makefile.am:
+	* ext/speex/Makefile.am:
+	* ext/taglib/Makefile.am:
+	* ext/vpx/Makefile.am:
+	* ext/wavpack/Makefile.am:
+	* gst/alpha/Makefile.am:
+	* gst/apetag/Makefile.am:
+	* gst/audiofx/Makefile.am:
+	* gst/audioparsers/Makefile.am:
+	* gst/auparse/Makefile.am:
+	* gst/autodetect/Makefile.am:
+	* gst/avi/Makefile.am:
+	* gst/cutter/Makefile.am:
+	* gst/debugutils/Makefile.am:
+	* gst/deinterlace/Makefile.am:
+	* gst/dtmf/Makefile.am:
+	* gst/effectv/Makefile.am:
+	* gst/equalizer/Makefile.am:
+	* gst/flv/Makefile.am:
+	* gst/flx/Makefile.am:
+	* gst/goom/Makefile.am:
+	* gst/goom2k1/Makefile.am:
+	* gst/icydemux/Makefile.am:
+	* gst/id3demux/Makefile.am:
+	* gst/imagefreeze/Makefile.am:
+	* gst/interleave/Makefile.am:
+	* gst/isomp4/Makefile.am:
+	* gst/law/Makefile.am:
+	* gst/level/Makefile.am:
+	* gst/matroska/Makefile.am:
+	* gst/monoscope/Makefile.am:
+	* gst/multifile/Makefile.am:
+	* gst/multipart/Makefile.am:
+	* gst/replaygain/Makefile.am:
+	* gst/rtp/Makefile.am:
+	* gst/rtpmanager/Makefile.am:
+	* gst/rtsp/Makefile.am:
+	* gst/shapewipe/Makefile.am:
+	* gst/smpte/Makefile.am:
+	* gst/spectrum/Makefile.am:
+	* gst/udp/Makefile.am:
+	* gst/videobox/Makefile.am:
+	* gst/videocrop/Makefile.am:
+	* gst/videofilter/Makefile.am:
+	* gst/videomixer/Makefile.am:
+	* gst/wavenc/Makefile.am:
+	* gst/wavparse/Makefile.am:
+	* gst/y4m/Makefile.am:
+	* sys/directsound/Makefile.am:
+	* sys/oss/Makefile.am:
+	* sys/oss4/Makefile.am:
+	* sys/osxaudio/Makefile.am:
+	* sys/osxvideo/Makefile.am:
+	* sys/sunaudio/Makefile.am:
+	* sys/v4l2/Makefile.am:
+	* sys/waveform/Makefile.am:
+	* sys/ximage/Makefile.am:
+	  gst: Add better support for static plugins
+
+2013-04-12 19:26:11 +0000  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* gst/goom2k1/Makefile.am:
+	  goom2k1: fix duplicated symbol with goom
+
+2013-03-10 17:17:17 +0000  Josep Torra <n770galaxy@gmail.com>
+
+	* sys/osxaudio/gstosxaudioelement.c:
+	* sys/osxaudio/gstosxcoreaudiocommon.h:
+	  osxaudio: Fixes error: "GST_LEVEL_DEFAULT" redefined
+
+2013-03-10 17:27:30 +0000  Josep Torra <n770galaxy@gmail.com>
+
+	* sys/osxaudio/gstosxcoreaudiohal.c:
+	  osxaudio: fixes implicit declaration of function 'getpid'
+
+2013-04-14 17:55:02 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* autogen.sh:
+	* common:
+	  Automatic update of common submodule
+	  From aed87ae to 3cb3d3c
+
+2013-04-14 12:32:06 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: add back "iradio-mode" property to disable sending of icecast request headers
+	  In 1.0 we now always send the icecast request headers by default, which
+	  makes the server send icecasts metadata inserted into the stream if it
+	  supports that. However, there are some use cases where this is not
+	  desirable, like when just saving a radio stream to disk, so add back
+	  the "iradio-mode" property to allow people to disable this.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=697984
+
+2013-04-12 16:16:41 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtp.c:
+	  rtp: register tag image types
+	  The rtpgstdepay needs the type to be available in order to deserialize the
+	  event.
+
+2013-04-12 16:08:58 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	  rtpgstdepay: handle event parse failures better
+
+2013-04-11 22:25:05 +0300  Anton Belka <antonbelka@gmail.com>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: add TOC setter support
+
+2013-04-12 12:31:30 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: small cleanups for toc handling
+	  Don't add empty labl/note chunks. Always pass instance as the first param. Add more logging.
+
+2013-04-12 12:58:50 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Proxy the ntp-sync property of rtpbin
+
+2013-04-12 12:51:05 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Give the manager always the name "manager"
+	  This allows to use the GstChildProxy interface to adjust
+	  properties on it.
+
+2013-04-11 22:53:28 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/alphacolor.c:
+	* tests/check/elements/apev2mux.c:
+	* tests/check/elements/id3v2mux.c:
+	* tests/check/pipelines/flacdec.c:
+	  tests: fix some printf format issues in debug messages
+
+2013-04-11 19:27:15 +0300  Anton Belka <antonbelka@gmail.com>
+
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavenc/gstwavenc.h:
+	  wavenc: add 'note' chunk support
+
+2013-04-11 20:46:26 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: add a little more docs to the audioclock
+
+2013-04-11 15:00:05 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/Makefile.am:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: add support for NetClientClock
+	  When the server suggests a GstNetTimeProvider in the SDP, set up a
+	  GstNetClientClock that slaves to the remote clock and suggest this clock in
+	  provide_clock.
+
+2013-04-11 14:57:11 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	  udpsink: avoid alloc and free in render function
+	  Avoid doing alloc and free in the render function for each buffer. Instead,
+	  allocate the needed arrays in _init and use those.
+
+2013-04-10 08:36:00 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/wavparse/gstwavparse.c:
+	  waveparse: remove superfluous g_list_first() calls
+	  The variables already point to the start of the list.
+
+2013-04-09 23:13:18 +0100  Andreas Fenkart <andreas.fenkart@streamunlimited.com>
+
+	* gst/rtp/gstrtpsbcdepay.c:
+	  rtpsbcdepay: fix sbc frame length calculation for mono and stereo modes
+	  https://bugzilla.gnome.org/show_bug.cgi?id=697463
+
+2013-03-25 14:35:02 +0300  Anton Belka <antonbelka@gmail.com>
+
+	* gst/wavparse/gstwavparse.c:
+	* gst/wavparse/gstwavparse.h:
+	  wavparse: add 'note' chunk support
+	  Add 'note' chunk support in TOC as GST_TAG_COMMENT
+	  https://bugzilla.gnome.org/show_bug.cgi?id=696549
+
+2013-04-08 17:53:09 -0700  David Schleef <ds@schleef.org>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: check value inside enda to set endianness
+
+2013-04-09 21:00:12 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 04c7a1e to aed87ae
+
+2013-04-09 17:34:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/icydemux/gsticydemux.c:
+	  icydemux: avoid copy when we can
+
+2013-04-09 16:52:21 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  gstpay: use bufferlist to avoid memcpy
+
+2013-04-09 16:50:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  udpsink: improve debug
+
+2013-04-09 00:28:54 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/wavparse.c:
+	  tests: refactor new wavparse test a little
+	  Use fakesrc instead of filesrc with /dev/null.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=696684
+
+2013-04-08 11:38:33 +0200  Alexander Schrab <alexas@axis.com>
+
+	* gst/wavparse/gstwavparse.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/wavparse.c:
+	  wavparse: error out if we receive eos before any valid data
+	  https://bugzilla.gnome.org/show_bug.cgi?id=696684
+
+2013-04-07 01:47:56 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: force deinterlacing in "interlaced" mode
+	  https://bugzilla.gnome.org/show_bug.cgi?id=697467
+
+2013-04-06 12:45:28 -0300  Thibault Saunier <thibault.saunier@collabora.com>
+
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	  gdkpixbufsink: Add timestamp/running-time/stream-time to the emited message
+
+2013-04-05 14:38:43 +0200  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/rtp/gstrtpsbcdepay.c:
+	  rtpsbcdepay: fix printf format compiler warnings
+	  https://bugzilla.gnome.org/show_bug.cgi?id=697343
+
+2013-04-05 09:34:23 +0100  Todd Agulnick <todd@agulnick.com>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideo: include pthread.h to fix compiler warning
+	  https://bugzilla.gnome.org/show_bug.cgi?id=697303
+
+2013-04-04 22:48:45 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/level/gstlevel.c:
+	* gst/level/gstlevel.h:
+	  level: resync on discont
+	  Drop pending data on discont and start a new cycle with a new base timestamp.
+	  Cleanup some variables.
+
+2013-04-03 23:52:47 +0100  Tom Greenwood <tgreenwood@Toms-MacBook-Pro.local>
+
+	* ext/vpx/gstvp8dec.c:
+	  vp8dec: Improve logging when vpx_codec_peek_stream_info fails
+	  Decode failures and missing keyframes should get different debug
+	  output.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=697232
+
+2013-04-03 18:24:29 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpsbcdepay.c:
+	  rtpsbcdepay: Rank as secondary
+	  This way, it will be selected by decodebin
+	  Bug reported by andreas.fenkart@streamunlimited.com
+	  https://bugzilla.gnome.org/show_bug.cgi?id=697227
+
+2013-04-03 19:05:38 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/level/gstlevel.c:
+	* tests/check/elements/level.c:
+	  level: subdivide buffers for sample accurate interval handling
+	  Previously we would skip level message when processing buffers > the requested
+	  interval. Also the message frequency would contain quite some jitter due to only
+	  considering them at the end of buffers.
+	  Cleanup the tests while we're at it.
+
+2013-03-19 08:23:25 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: remove old since comments and update logging
+	  Don't pretend that we have a timestamp on a buffer when we never set one.
+
+2013-03-18 20:59:23 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: remove old since comment
+
+2013-04-03 17:53:13 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Proxy the multicast-iface property of udpsrc
+
+2013-04-03 11:09:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: free all queued buffers
+	  Don't just loop over the first num_queued buffers but loop over
+	  all the buffers and check if they need to be freed. It is possible that
+	  not all buffers are queued and then the entry in our array will be NULL.
+	  Those buffers that are not queued were freed in stop().
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=696651
+
+2013-04-03 11:09:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: improve debug
+
+2013-04-02 23:42:23 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Only forward stick events while holding the sinkpad stream lock
+	  Otherwise we get a race where if the RTCP packet comes in first and while
+	  it is added the pads, the segment event arrives on the RTP stream, the event
+	  may be lost completely and never forwarded.
+
+2013-04-02 23:35:06 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: No need to explicitely forward the caps
+	  They are forwarded with the other events
+
+2013-04-02 22:29:38 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtpmanager/gstrtpssrcdemux.h:
+	  rtpssrcdemux: Remove unused GstSegment
+
+2013-04-02 22:26:02 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Simplify event forwarding
+	  Use the gst_pad_forward() mechanic, this way we won't miss pads that are
+	  added while we are pushing
+
+2013-04-02 21:53:10 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Don't cross the internal links
+	  We had the wrong condition to check for the internal links, so RTP and RTCP
+	  pads got crossed!
+
+2013-03-31 17:54:16 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: fix some debug messages
+
+2013-04-02 23:36:22 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: fix printf format compiler warning in debug message
+
+2012-08-29 17:24:00 +0200  Arnaud Vrac <avrac@freebox.fr>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	  matroskademux: handle TrueHD audio codec id
+	  https://bugzilla.gnome.org/show_bug.cgi?id=697113
+
+2013-03-31 19:14:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	  theorapay: add delta-unit to output frames
+
+2013-03-23 05:22:23 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: use timestamp delta as duration if possible
+	  https://bugzilla.gnome.org/show_bug.cgi?id=696437
+
+2013-03-30 09:44:41 +0100  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/rtp/gstrtpsbcdepay.c:
+	  rtp: fixes debug message printf related compiler warnings in SBC depayloader
+
+2013-03-28 16:46:36 +0000  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpsbcdepay.c:
+	* gst/rtp/gstrtpsbcdepay.h:
+	  rtp: Add an rtpsbcdepay element
+	  Pretty straightforward - takes SBC encapsulated in RTP, depayloads, and
+	  pushes out SBC buffers.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=690582
+
+2013-03-27 22:18:34 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	  rtp: fix SBC payloader
+	  Init RTP buffer on stack correctly, so mapping it works
+	  without criticals and the payloader actually works.
+
+2013-03-26 14:44:36 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: Check for a subset instead of non-empty intersection in accept-caps
+
+2013-03-26 14:39:53 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: Properly handle the filter caps in get_caps()
+
+2013-03-26 14:35:38 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: Don't unnecessarily get the parent class in class_init
+	  The trampoline generated by G_DEFINE_TYPE does that already.
+
+2013-03-25 18:02:10 -0700  David Schleef <ds@schleef.org>
+
+	* gst/avi/gstavidemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	  Use %03u for format in gst_pad_create_stream_id_printf()
+
+2013-03-25 10:12:03 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/debugutils/gstcapssetter.c:
+	  capssetter: Prevent unneeded caps copying and allocation
+
+2013-02-01 14:33:41 +0100  Dirk Van Haerenborgh <vhdirk@gmail.com>
+
+	* gst/debugutils/gstcapssetter.c:
+	  capssetter: Pass any or filter caps upstream
+	  capsetter accepts anything and just forwards different caps,
+	  as such it should return ANY caps on the sinkpad.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=693005
+
+2013-03-06 13:17:54 +0000  Tom Greenwood <tgreenwood@Toms-MacBook-Pro.local>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: Fix for divide by zero when using 0/1 framerate
+	  https://bugzilla.gnome.org/show_bug.cgi?id=695709
+
+2013-03-24 17:55:55 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: expose CUE sheet items as tracks not chapter entries in TOC
+	  https://bugzilla.gnome.org/show_bug.cgi?id=677306
+
+2013-03-23 13:11:02 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: add more example pipelines
+
+2013-03-23 12:59:26 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: add some example pipelines
+
+2013-03-20 21:38:40 +0300  Anton Belka <antonbelka@gmail.com>
+
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavenc/gstwavenc.h:
+	  wavenc: add TOC support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=680998
+
+2013-03-23 04:56:36 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: make empty subtitle buffer recognition more robust
+	  https://bugzilla.gnome.org/show_bug.cgi?id=696244
+
+2013-03-04 15:49:06 -0800  David Schleef <ds@schleef.org>
+
+	* ext/libpng/gstpngenc.c:
+	  pngenc: unmap source frame when done
+
+2013-03-22 15:14:15 -0700  David Schleef <ds@schleef.org>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Fix test regression with one buffer streams
+
+2013-03-05 17:00:17 -0800  David Schleef <ds@schleef.org>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: split large raw audio samples
+	  In order to deal with a file that has samples that are 24 seconds
+	  long.  Seeking still doesn't work with such files.
+
+2013-03-22 11:54:08 -0700  David Schleef <ds@schleef.org>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Remove documentation for dts-method
+
+2013-03-22 13:24:33 -0700  David Schleef <ds@schleef.org>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  qtmux: deprecate dts-method property
+
+2013-03-13 17:08:03 -0700  David Schleef <ds@schleef.org>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Fix problems causing bad durations in file
+	  - Fix up out-of-order incoming DTS values.
+	  - Fix duration of initial sample.
+
+2013-03-12 19:08:26 -0700  David Schleef <ds@schleef.org>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: fix all timestamps once first_ts is determined
+
+2013-02-14 16:34:34 -0800  David Schleef <ds@schleef.org>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  qtmux: Use PTS/DTS from incoming buffers
+	  Remove old DTS guessing code.
+
+2013-03-18 12:30:50 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/isomp4/gstqtmuxmap.c:
+	  qtmux: expose mulaw caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=696052
+
+2013-03-22 10:50:34 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  Require Orc >= 0.4.17
+	  Orc 0.4.17 fixes a bunch crashes on i386 and RPi when orc
+	  functions can't be compiled and the fallback function is
+	  supposed to be used. Also fixes some issues on PowerPC.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=684399
+	  https://bugzilla.gnome.org/show_bug.cgi?id=693862
+
+2013-03-22 08:47:17 +0000  Rodolfo Schulz de Lima <rodolfo@rodsoft.org>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix sample leak when processing private qt tags
+	  https://bugzilla.gnome.org/show_bug.cgi?id=696355
+
+2013-03-22 02:24:01 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: set stream language code from tag
+	  https://bugzilla.gnome.org/show_bug.cgi?id=696358
+
+2013-03-21 02:55:06 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: send GAP events for subtitle streams
+	  https://bugzilla.gnome.org/show_bug.cgi?id=696244
+
+2013-03-21 02:53:24 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: ignore empty subtitle buffers
+	  https://bugzilla.gnome.org/show_bug.cgi?id=696244
+
+2013-03-21 02:52:07 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_fourcc.h:
+	  qtdemux: recognize SBTL subtype for subtitles
+	  https://bugzilla.gnome.org/show_bug.cgi?id=696244
+
+2013-03-17 16:27:03 +0300  Anton Belka <antonbelka@gmail.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: add support for the toc-select event
+	  Select tracks from the CUE sheet by sending a toc-select
+	  event based on the uid in the TOC.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=540891
+
+2013-03-19 18:09:31 -0700  Michael Smith <msmith@rdio.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  mp4mux: in faststart mode, don't output up to 4 kB of garbage at the end.
+
+2013-03-20 00:35:17 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/audioparsers/gstsbcparse.c:
+	  sbcparse: pack multiple frames into one output buffer
+	  Don't output a single buffer for every tiny SBC frame
+
+2013-03-18 14:59:35 +0000  Bastien Nocera <hadess@hadess.net>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: fix compilation against newer kernel headers as on FC19
+
+2013-03-14 14:12:05 +0100  Kishore Arepalli <kishore.arepalli@gmail.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: fix infinite loop on EOS with non-default methods or fields
+	  Fixes problem of infinite loop in gst_deinterlace_reset_history.
+	  Last field in the history was never deinterlaced because idx becomes negative.
+	  Happens e.g. with method=scalerbob fields=bottom or
+	  method=greedyl fields=top
+	  https://bugzilla.gnome.org/show_bug.cgi?id=695644
+	  https://bugzilla.gnome.org/show_bug.cgi?id=693173
+
+2013-03-12 09:48:31 +0000  Kishore Arepalli <kishore.arepalli@gmail.com>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: don't return FALSE when dropping sink events
+	  Fixes problem in conjunction with avidemux.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=695643
+
+2013-03-12 00:16:18 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/avi/gstavimux.c:
+	  avimux: change raw video caps order so that GRAY8 is last
+	  People like colours.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=695543
+
+2013-03-11 14:50:41 +0100  Ognyan Tonchev <ognyan@axis.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: Don't use upstream caps with peer_query_caps ()
+	  Calling gst_pad_peer_query_caps () on the src pad with the caps
+	  upstream can produce as a filter from gst_rtp_h264_pay_getcaps ()
+	  is wrong and makes caps negotiation fail if upstream caps are not
+	  NULL.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=695629
+
+2013-03-10 09:10:18 +0100  Dirk Van Haerenborgh <vhdirk@gmail.com>
+
+	* gst/avi/gstavimux.c:
+	  avimux: support raw BGR
+	  https://bugzilla.gnome.org/show_bug.cgi?id=695543
+
+2013-03-10 09:25:34 +0100  Dirk Van Haerenborgh <vhdirk@gmail.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: support raw video with negative height
+	  https://bugzilla.gnome.org/show_bug.cgi?id=695541
+
+2013-03-05 14:40:56 +0100  Jonas Holmberg <jonashg@axis.com>
+
+	* tests/check/elements/autodetect.c:
+	  autodetect checktest: Do not fail without videosink
+	  If there is no videosink available autovideosink will contain a
+	  fakesink instead which needs special treatment in the unit test.
+
+2013-03-09 01:18:30 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* Android.mk:
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-dtmf.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* gst-plugins-good.spec.in:
+	* gst/dtmf/gstdtmf.c:
+	* gst/dtmf/gstdtmfcommon.h:
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	  dtmf: move dtmf plugin from -bad to -good
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687416
+
+2013-03-09 00:30:38 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Merge branch 'dtmf-moved-from-bad'
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687416
+
+2013-03-05 21:22:18 +0100  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* configure.ac:
+	* sys/osxaudio/Makefile.am:
+	* sys/osxaudio/gstosxaudioelement.h:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxcoreaudio.c:
+	* sys/osxaudio/gstosxcoreaudioremoteio.c:
+	  osxaudio: add support for iOS using the RemoteIO AudioUnit
+
+2013-03-05 21:17:52 +0100  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxaudio/Makefile.am:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxaudio/gstosxcoreaudio.c:
+	* sys/osxaudio/gstosxcoreaudio.h:
+	* sys/osxaudio/gstosxcoreaudiocommon.c:
+	* sys/osxaudio/gstosxcoreaudiocommon.h:
+	* sys/osxaudio/gstosxcoreaudiohal.c:
+	* sys/osxaudio/gstosxringbuffer.c:
+	* sys/osxaudio/gstosxringbuffer.h:
+	  osxaudio: add a façade for the CoreAudio API
+
+2013-03-07 00:00:41 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 2de221c to 04c7a1e
+
+2013-03-03 11:59:31 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/lzo.c:
+	  matroska: Include config.h, it's needed for _stdint.h
+
+2013-03-03 11:53:04 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Fix (wrong) use of uninitialized variable compiler warning
+
+2013-03-02 13:59:52 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: add variant field to H.263 caps
+	  avdec_h263 won't get plugged otherwise.
+
+2013-02-22 19:06:52 +0100  Arnaud Vrac <avrac@freebox.fr>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: skip disabled tracks
+	  ISO/IEC 14496-12 specifies disabled tracks should be completely
+	  ignored, so just do it.
+	  Avoids deadlock during prerolling for some files.
+	  Also prevents 'chapter' subtitle tracks from showing up.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=693993
+	  https://bugzilla.gnome.org/show_bug.cgi?id=628790
+
+2013-02-25 09:58:13 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/level.c:
+	  tests: re-add suppression for GValueArray warnings to unit test as well
+
+2013-02-28 13:25:06 +0100  Jonas Holmberg <jonashg@axis.com>
+
+	* tests/check/elements/dtmf.c:
+	  tests: use relative include for out-of-tree builds in dtmf test
+
+2013-02-28 08:46:59 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: remove the since doc-comment from 0.10
+
+2013-02-28 08:44:18 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/level/gstlevel.c:
+	* gst/level/gstlevel.h:
+	* tests/examples/level/level-example.c:
+	  level: add a "post-messages" property and deprecate "message"
+	  In spectrum this was changed from 0.10 to 1.0, lets do this here too.
+
+2013-02-27 18:56:50 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* tests/check/elements/dtmf.c:
+	  tests: Add tests for dtmfsrc
+
+2013-02-27 16:15:27 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* tests/check/elements/dtmf.c:
+	  tests: Fix ref leak in dtmf test
+
+2013-02-26 14:18:20 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpmp4gdepay.c:
+	  rtpmp4gdepay: streamtype is not put by all RTSP server, not make it optional
+	  Specific case here is Wowza 3.5.0
+
+2013-02-25 00:35:58 +0100  Thomas Vander Stichele <thomas (at) apestaart (dot) org>
+
+	* gst/level/gstlevel.c:
+	  level: put back deprecation warnings
+
+2013-02-24 17:00:14 +0100  Thomas Vander Stichele <thomas (at) apestaart (dot) org>
+
+	* gst/level/gstlevel.c:
+	* tests/check/elements/level.c:
+	  level: send last message on EOS
+
+2013-02-23 14:34:35 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: push mode: handle some more 0-size buffer cases
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=684944
+
+2013-02-23 18:50:52 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: fix up example pipeline in docs
+
+2012-11-20 12:14:07 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Update segdone periodically
+	  This makes sure that we update segdone based on the read index received
+	  during latency updates. As the comment notes, we make some compromises
+	  to deal with the fact that segdone is a segment multiple, while the read
+	  index offers finer granularity. The updates are also not very often
+	  (100ms since that is how often automatic timing updates are provided).
+	  All this is required for the baseaudiosink sample alignment code to work
+	  at all.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=694257
+
+2013-02-13 10:46:54 +0100  Paul HENRYS <visechelle@gmail.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Fix wrong code organisation in case of collision
+	  change_ssrc field of RTPSession should be set before calling
+	  rtp_session_schedule_bye_locked () as this function will call reconsider function
+	  that will wake up rtcp_thread which will call rtp_session_on_timeout () that will
+	  check change_ssrc to change the ssrc.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=694184
+
+2013-02-21 11:15:23 -0500  Jean-François Fortin Tam <nekohayo@gmail.com>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: improve descriptions of chroma keying-related properties and enums
+	  https://bugzilla.gnome.org/show_bug.cgi?id=694374
+
+2013-02-21 15:01:15 -0500  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Do not override the method with custom r/g/b values
+	  Depending on the order g_object_set() calls aare made, the
+	  target r/g/b settings will override the method if set to
+	  green/blue. Change that so we do not use the target-r/g/b values
+	  unless the method is set to custom.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=694374
+
+2013-02-20 15:46:43 +0100  Ognyan Tonchev <ognyan@axis.com>
+
+	* gst/auparse/gstauparse.c:
+	  auparse: do not leak src_caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=694275
+
+2013-02-20 21:03:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: only delay RTCP when we are a sender
+	  Only delay the RTCP thread when we are a sender, which we can know because we
+	  have a send_rtp_src pad. Otherwise we might delay the RTCP thread if we
+	  are only a receiver and then there is no code path that wakes up the
+	  RTCP thread and we end up without RTCP packets.
+
+2013-02-19 11:47:20 +0100  Benjamin Gaignard <benjamin.gaignard@linaro.org>
+
+	* configure.ac:
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: Add support of dmabuf
+	  v4l has add a new IOCTL to export a buffer by using dmabuf.
+	  This patch allow to use this new IOTCL if it has been defined in videodev2.h
+	  I introduce a new IO mode (GST_V4L2_IO_DMABUF) to enable this way of working.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=693826
+
+2013-02-18 20:04:05 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix up dodgy code that tries to fix up a broken moov atom
+	  After gst_buffer_new_and_alloc() gst_buffer_copy_into() will likely
+	  append to the already-existing memory instead of filling it.
+
+2013-02-18 16:32:13 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix potential crash on short MOOV atom
+	  Don't unmap short MOOV atom buffer twice, which happened
+	  in the case where we don't fix up the MOOV atom.
+	  Fixes crashes when thumbnailing partial mp4 file where
+	  the MOOV atom is still incomplete.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=694010
+
+2013-02-16 16:49:22 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/soup/Makefile.am:
+	  souphttpsrc: set SOUP_VERSION_{MIN_REQUIRED,MAX_ALLOWED} to suppress deprecations with newer versions
+	  https://bugzilla.gnome.org/show_bug.cgi?id=693911
+
+2013-02-16 15:47:02 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* configure.ac:
+	* ext/soup/gstsouphttpsrc.c:
+	  soup: use default proxy resolver instead of deprecated GNOME proxy resolver
+	  Apparently there's no reason to use it any longer. Drop libsoup-gnome
+	  dependency while at it, now that we don't need anything from it any
+	  more (it only consists entirely of deprecated API now anyways).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=693911
+
+2013-02-15 15:43:43 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/pipelines/tagschecking.c:
+	  tests: fix some h264 caps
+	  Doesn't fix anything in particular, but is
+	  still needed here for correctness.
+
+2013-02-15 08:19:24 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/audiofx/audiopanorama.c:
+	  audiopanorama: remove channel-mask from caps
+	  The channel-mask is only needed for channels>2 which we don't do.
+
+2013-02-15 16:21:21 +0100  Benjamin Gaignard <benjamin.gaignard@stericsson.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: don't check stride for encoded formats
+	  Don't try to check the stride for encoded formats. Some drivers output
+	  something != 0 and then we don't want to fail on that.
+
+2013-02-15 14:11:36 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: use g_socket_set_option() to set buffer size with newer GLib versions
+	  So we have to worry less about portability.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=692400
+
+2013-02-14 14:13:27 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: remove sof-marker from template caps for now
+	  Now that the subset check actually works, this breaks
+	  things with demuxers that don't put a "sof-marker"
+	  in their jpeg caps, and we don't have a good parser
+	  to plug either yet.
+
+2013-02-13 12:32:10 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstjpegenc.h:
+	  jpegenc: Put the SOF marker into the caps
+
+2013-02-13 12:02:46 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtp/gstrtpamrdepay.c:
+	* tests/check/elements/rtp-payloading.c:
+	  rtp-payloading: Fix unit test caps and AMR depayloader sink template caps
+	  Fields were missing from the actual caps, or too many fields
+	  existed in the template caps.
+
+2013-02-13 11:53:01 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/aacparse.c:
+	  aacparse: Fix caps used in the unit test
+	  The AAC caps passed were incomplete.
+
+2013-02-13 11:49:40 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/wavpackenc.c:
+	* tests/check/elements/wavpackparse.c:
+	  wavpack: Fix unit tests, width is now called depth in the caps in 1.0
+
+2013-02-12 23:31:22 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: make souphttpsrc unit test work even if http_proxy is set
+	  We're testing with an http server on localhost, but don't support
+	  an exception list for the http_proxy, so just unset the environment
+	  variable to make sure we can run this test properly even if the
+	  environment has http_proxy set.
+	  Also, don't skip all tests if there is an issue with the SSL server,
+	  just run the non-SSL tests then.
+	  https://jenkins.qa.ubuntu.com/view/Raring/view/JHBuild%20Gnome/job/jhbuild-amd64-gst-plugins-good/
+
+2013-02-12 12:53:52 -0800  Michael Smith <msmith@rdio.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: extract codec_data for ProRes
+
+2013-02-08 01:02:10 +1100  Tim 'mithro' Ansell <mithro@mithis.com>
+
+	* gst/avi/gstavimux.c:
+	  avimux: Fixing buffer leak in gst_avi_mux_do_buffer
+	  gst_avi_mux_do_buffer was leaking data from gst_collect_pads_pop.
+
+2013-02-10 15:10:32 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: correct duration for audio VBR buffers in pull mode
+
+2013-02-08 21:28:02 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: proper position reporting and push mode timestamping
+	  ... and align current_total semantics in push and pull mode,
+	  which tracks bytes for CBR and blocks for VBR.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=691481
+
+2013-02-08 17:05:27 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: delay RTCP until first RTP packet
+	  Delay sending the first RTCP packet until we have sent the first RTP packet.
+	  Otherwise we will send out a Receiver Report instead of a sender report.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=691400
+
+2013-02-07 15:06:40 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: remove dead code
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=668355
+
+2013-01-29 10:48:17 +0100  Paul HENRYS <visechelle@gmail.com>
+
+	* gst/rtpmanager/gstrtpptdemux.c:
+	  rtpptdemux: forward sticky events and then set caps
+	  When a new src pad is added, first forward the sticky events and then
+	  set the caps on the src pad
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=692786
+
+2013-02-07 14:32:26 +0100  Markovtsev Vadim <v.markovtsev at samsung.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: improve debug output
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=688935
+
+2011-09-26 14:42:51 -0700  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: rework cleanup of streams
+	  Move the work of cleaning up the client streams in the free_stream
+	  function. This allows us to properly clean up the client streams when we
+	  remove an RTP stream as well.
+	  Based on patch by Sujay <sdatar@cisco.com>
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=660156
+
+2013-02-07 11:40:35 +0100  Tim 'mithro' Ansell <gnome at mithis.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer2: avoid caps leak
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=693307
+
+2013-02-06 17:15:11 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  jitterbuffer: do skew estimation only for new timestamps
+	  Only run the skew estimation code when we have a new RTP timestamp. If we have
+	  the same RTP timestamp, we simply use the previous estimation. This works
+	  because the new observation with the same RTP timestamp has to have a bigger
+	  receiver time and is thus not going to influence the estimation except for
+	  causing more jitter.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=640023
+
+2013-02-06 13:52:26 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: only EOS when our source sends BYE
+	  Only EOS when we receive a BYE event from the SSRC of our stream.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=675453
+
+2013-02-06 13:47:51 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: save the stream SSRC
+	  Conflicts:
+	  gst/rtsp/gstrtspsrc.c
+
+2013-02-06 13:18:18 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: flush connection when stopping
+	  When we stop, we can flush all pending commands so that we can stop and
+	  join the task.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=684924
+
+2013-02-05 22:02:13 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/spectrum/README:
+	  spectrum: remove outdates readme
+	  Lets remove the readme from pre-0.1.0 that is completely irrelevant now.
+
+2013-02-05 07:32:29 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/audiofx/audiopanorama.c:
+	  audiopanorama: add more debug logging
+
+2013-02-05 08:26:14 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/examples/level/level-example.c:
+	  level-example. avoid taking the arrays again for each channel for clarity
+	  Also introduce some blank lines for better readability and update the comments.
+
+2013-02-04 18:38:41 +0000  Rico Tzschichholz <ricotz@ubuntu.com>
+
+	* gst/audioparsers/Makefile.am:
+	  audioparsers: fix typo in noinst_headers
+
+2013-02-04 11:08:23 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/audiofx/audiopanorama.c:
+	  audiopanorama: further port to 1.0
+	  Transformcaps is not called with caps containing single structures anymore. Also add missing filter handling. Still does not negotiate though.
+
+2013-02-03 22:45:52 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/audiofx/audiopanorama.c:
+	  audiopanorama: fix caps
+	  We don't turn float into 32bit pcm. Looks like a typo from updating the caps.
+
+2013-02-03 13:14:50 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/level/gstlevel.c:
+	  level: Add missing coma between formats
+
+2013-01-31 22:55:18 +1100  Matthew Waters <ystreet00@gmail.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: fix eos timestamp check
+	  fixes hang in videotestsrc num-buffers=20 ! videomixer ! fakesink
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=692935
+
+2013-01-31 11:35:09 +0100  Dirk Van Haerenborgh <vhdirk@gmail.com>
+
+	* gst/avi/gstavimux.c:
+	  avimux: add support for raw monochrome 8-bit video
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=692932
+
+2013-01-18 21:08:12 +0400  Alexey Chernov <achernov@neosphere.com>
+
+	* sys/osxvideo/cocoawindow.h:
+	* sys/osxvideo/cocoawindow.m:
+	  osxvideosink: Make GstNavigation key input events in osxvideosink compatible with x(v)imagesink ones
+
+2013-01-29 10:30:32 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: avoid '...is used uninitialized'
+
+2013-01-09 13:24:49 -0500  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: set interleaved layout correctly for LPCM audio
+	  https://bugzilla.gnome.org/show_bug.cgi?id=663458
+
+2013-01-08 20:45:21 -0500  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: add support for LPCM fourcc (uncompressed audio in Quicktime7)
+	  https://bugzilla.gnome.org/show_bug.cgi?id=663458
+
+2013-01-08 20:42:35 -0500  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: print all debug for sound sample description v2
+	  https://bugzilla.gnome.org/show_bug.cgi?id=663458
+
+2013-01-08 20:14:17 -0500  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: sound sample description v2 doesn't override samples_per_packet
+	  https://bugzilla.gnome.org/show_bug.cgi?id=663458
+
+2013-01-08 19:57:50 -0500  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: pass stsd data to qtdemux_audio_caps()
+	  We will need that later for LPCM format support. Disable
+	  QDM2 parsing of stsd data which dead code before as well
+	  because data was always NULL.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=663458
+
+2013-01-08 19:56:46 -0500  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: add len check for sound sample descriptions v1 and v2
+	  https://bugzilla.gnome.org/show_bug.cgi?id=663458
+
+2013-01-28 22:42:25 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpmanager: use C89-style comments
+
+2013-01-28 18:06:15 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  gstrtpsession: Fix double-declared variable
+
+2013-01-28 17:58:20 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtp: Fix compilation errors in previous patches
+
+2011-04-28 22:59:28 +0200  Haakon Sporsheim <haakon.sporsheim@gmail.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: Ensure MT safe event handling and plug event leak.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=667826
+
+2011-10-17 23:45:37 +0200  Idar Tollefsen <itollefs@cisco.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: mt-safe event-push
+	  By taking a ref of the sink-pad under lock, it won't dissappear
+	  while the push is taking place
+	  https://bugzilla.gnome.org/show_bug.cgi?id=667816
+
+2012-01-04 10:29:45 +0100  Pascal Buhler <pabuhler@cisco.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Safely push on pads that might be removed due to a RTCP BYE
+	  https://bugzilla.gnome.org/show_bug.cgi?id=667815
+
+2013-01-28 20:42:26 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From a942293 to 2de221c
+
+2013-01-28 11:54:54 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstsbcparse.c:
+	  sbcparse: init some variables to avoid bogus compiler warnings
+
+2013-01-28 12:41:04 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpg722depay.c:
+	* gst/rtp/gstrtpg723depay.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmparobustdepay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvp8depay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	  rtpdepay: remove payload type restrictions
+	  Remove the pt restrictions for all the depayloaders that have an
+	  encoding-name. We can use this to autoplug decoders.
+	  Remove the encoding-name for all the payloaders with a fixed payload
+	  type.
+	  We now either have an encoding-name or a pt in the sinkpad caps of
+	  a depayloader.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=639292
+
+2013-01-28 12:23:41 +0100  Marc Leeman <marc.leeman@gmail.com>
+
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	  rtp: remove payload requirements from selected depayloaders
+	  encoding name is required in the caps and is a better fit for autoplugging than
+	  the pt value. Hardware manufacturers have a bad habit of skimming through RFCs
+	  and in this case; use unassigned numbers for encoders instead of dynamic
+	  numbers.
+	  In essence, this patch will add support for a lot of Bosch hardware encoders
+	  without breaking autoplugging.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=639292
+
+2013-01-27 10:17:59 +0530  B.Prathibha <bosslinux@cdac.in>
+
+	* tests/examples/jack/jack_client.c:
+	* tests/examples/rtp/server-alsasrc-PCMA.c:
+	* tests/icles/ximagesrc-test.c:
+	  tests: use g_timeout_add_seconds instead of g_timeout_add
+	  https://bugzilla.gnome.org/show_bug.cgi?id=692615
+
+2013-01-27 12:54:15 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: push mode: only parse moov 1 once
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=691570
+
+2013-01-26 22:58:29 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  rtpdtmfsrc: fix compiler warning
+	  gstrtpdtmfsrc.c: In function 'gst_dtmf_src_prepare_message.isra.1':
+	  gstrtpdtmfsrc.c:669:3: error: 's' may be used uninitialized in this function
+
+2013-01-25 21:06:05 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  rtpdtmfdepay: Fix missing work in doc
+
+2013-01-24 21:00:08 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* tests/check/elements/dtmf.c:
+	  tests: Add test for rtpdtmfdepay and rtpdtmfsrc
+
+2013-01-25 20:39:33 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  rtpdtmfsrc: Post the messages after the clock wait
+	  This way, the messages will be closer in time to when the packets are sent out
+
+2013-01-25 20:37:53 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  rtpdtmfsrc: Only set the duration when starting to send
+	  The duration depends on the clock rate, which could change due to renegotiation
+
+2013-01-25 20:37:09 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  rtpdtmfsrc: remove "ssrc" from caps
+	  ssrc is uint and we don't have a uint range type
+
+2013-01-24 21:08:51 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/isomp4/atoms.h:
+	  qtmux: set language to 'undefined' instead of English by default
+
+2013-01-23 21:35:25 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* sys/ximage/gstximagesrc.c:
+	* sys/ximage/ximageutil.c:
+	* sys/ximage/ximageutil.h:
+	  ximagesrc: Set the pixel aspect ratio correctly in the caps
+
+2013-01-08 08:56:45 +0100  Sjoerd Simons <sjoerd@luon.net>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: Re-enable prepare-format emission
+	  With the port to gstreamer 1.0 the prepare-format signal stopped being
+	  emitted. Start emitting this again for use in uvch264src.  While there
+	  change the emission to include the caps for extra flexibility instead of
+	  fource, width, height.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=692042
+
+2013-01-22 18:12:10 +0100  Benjamin Gaignard <benjamin.gaignard@st.com>
+
+	* autogen.sh:
+	  autogen.sh: allow calling from out-of-tree
+	  Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
+	  https://bugzilla.gnome.org/show_bug.cgi?id=692309
+
+2013-01-22 19:26:09 +0100  Mark Nauwelaerts <mnauw@users.sourceforge.net>
+
+	* gst/audioparsers/gstsbcparse.c:
+	  audioparsers: sbc: fix bogus compiler warning
+	  gst-plugins-good/gst/audioparsers/gstsbcparse.c: In function 'gst_sbc_parse_handle_frame':
+	  gst-plugins-good/gst/audioparsers/gstsbcparse.c:210:32: error: 'ch_mode' may be used uninitialized i
+
+2013-01-19 13:27:48 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: don't error out if pa_stream_proplist_update() with new tags fails
+	  Shouldn't really happen these days, but if it does, it's not really
+	  a problem either.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=656068
+
+2013-01-16 18:01:23 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: skip souphttpsrc tests if there is no local http server to use
+	  Skip tests if the server couldn't be started or we can't connect
+	  to it for some reason (e.g. draconic build bot environments).
+
+2013-01-16 14:32:56 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/audioparsers/gstsbcparse.c:
+	  autoparsers: use appropriate printf format for gsize
+
+2013-01-15 15:05:43 +0100  Martin Pitt <martinpitt@gnome.org>
+
+	* tests/check/Makefile.am:
+	  tests: use _1_0 variants for the various registry variables
+	  These override the variants without version suffix. Makes 'make check' work
+	  properly in environments that set the suffixed variant for 1.0, such as
+	  jhbuild.
+
+2013-01-11 19:24:43 +0400  Alexey Chernov <achernov@neosphere.com>
+
+	* sys/osxvideo/cocoawindow.m:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: Fix crash in osxvideosink with external window output
+
+2013-01-16 12:04:59 +0400  Alexey Chernov <achernov@neosphere.com>
+
+	* sys/osxvideo/cocoawindow.m:
+	  osxvideosink: Make GstGLView propagate input events to its parent view
+	  Fixes bug #691832
+
+2013-01-16 10:19:36 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	  rtpsbcpay: update some fields in the caps to their new name
+	  and to match the parser. "mode" got renamed to "channel-mode"
+	  and "allocation" to "allocation-method".
+
+2013-01-15 17:44:33 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	  docs: add sbcparse and rtpsbcpay to plugin docs
+
+2013-01-15 17:38:24 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/Makefile.am:
+	* gst/audioparsers/gstsbcparse.c:
+	* gst/audioparsers/gstsbcparse.h:
+	* gst/audioparsers/plugin.c:
+	  audioparsers: add SBC audio parser
+	  From-scratch rewrite, the bluez one was useless and broken.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=690582
+
+2013-01-15 15:05:04 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From a72faea to a942293
+
+2013-01-10 12:38:13 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpsbcpay.c:
+	* gst/rtp/gstrtpsbcpay.h:
+	  rtp: import rtpsbcpay from bluez and port to 1.0
+	  Compiles, but not tested yet (sbc elements still need to be ported).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=690582
+
+2013-01-09 19:59:16 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/Makefile.am:
+	* gst/dtmf/gstdtmf.c:
+	* gst/dtmf/gstdtmfdetect.c:
+	* gst/dtmf/gstdtmfdetect.h:
+	* gst/dtmf/tone_detect.c:
+	* gst/dtmf/tone_detect.h:
+	  dtmf/spandsp: Move dtmfdetect to use libspandsp
+	  Remove our copy of the tone_detect.c file and use the original
+	  from libspandsp. Also move the element to the spandsp plugin.
+
+2011-02-13 17:51:45 -0800  Marcel Holtmann <marcel@holtmann.org>
+
+	* gst/rtp/gstrtpsbcpay.h:
+	  rtpsbcpay: Remove workaround for compiler warnings
+
+2010-05-19 16:59:30 +0200  Marcel Holtmann <marcel@holtmann.org>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	  rtpsbcpay: Add pragma based workaround for GStreamer warnings
+
+2010-01-01 17:08:17 -0800  Marcel Holtmann <marcel@holtmann.org>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	* gst/rtp/gstrtpsbcpay.h:
+	  rtpsbcpay: Update copyright information
+
+2009-01-30 00:31:15 +0100  Marcel Holtmann <marcel@holtmann.org>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	  rtpsbcpay: Fix signed/unsigned comparison issue within GStreamer plugin
+
+2009-01-01 19:33:20 +0100  Marcel Holtmann <marcel@holtmann.org>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	* gst/rtp/gstrtpsbcpay.h:
+	  rtpsbcpay: Update copyright information
+
+2008-12-23 05:25:50 +0100  Marcel Holtmann <marcel@holtmann.org>
+
+	* gst/rtp/gstrtpsbcpay.h:
+	  rtpsbcpay: First attempt in fixing compiler warnings (still needs cleanup)
+
+2008-12-20 21:42:49 +0200  Johan Hedberg <johan.hedberg@nokia.com>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	  rtpsbcpay: More coding style fixes
+
+2008-02-29 19:37:15 +0000  Luiz Augusto von Dentz <luiz.dentz@openbossa.org>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	  rtpsbcpay: Remove possible extra memcpy for gstreamer plugin.
+
+2008-02-28 19:38:53 +0000  Luiz Augusto von Dentz <luiz.dentz@openbossa.org>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	  rtpsbcpay: Fix bug sending empty packages and remove a buffer copy.
+
+2008-02-20 13:37:00 +0000  Luiz Augusto von Dentz <luiz.dentz@openbossa.org>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	  rtpsbcpay: Fix runtime warnings of gstreamer plugin.
+
+2008-02-19 19:49:24 +0000  Luiz Augusto von Dentz <luiz.dentz@openbossa.org>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	  rtpsbcpay: Update gstreamer plugin to use new sbc API.
+
+2008-02-02 03:37:05 +0000  Marcel Holtmann <marcel@holtmann.org>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	* gst/rtp/gstrtpsbcpay.h:
+	  rtpsbcpay: Update copyright information
+
+2008-01-30 14:21:43 +0000  Luiz Augusto von Dentz <luiz.dentz@openbossa.org>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	  rtpsbcpay: Fixes gstreamer caps and code cleanup.
+
+2008-01-24 14:25:29 +0000  Luiz Augusto von Dentz <luiz.dentz@openbossa.org>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	  rtpsbcpay: Fix gtreamer payloader sending fragmented frames.
+
+2008-01-23 19:17:33 +0000  Luiz Augusto von Dentz <luiz.dentz@openbossa.org>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	* gst/rtp/gstrtpsbcpay.h:
+	  rtpsbcpay: Fix use of gstreamer plugin with rhythmbox and banshee and rtp timestamps.
+
+2008-01-23 13:14:02 +0000  Luiz Augusto von Dentz <luiz.dentz@openbossa.org>
+
+	* gst/rtp/gstrtpsbcpay.c:
+	* gst/rtp/gstrtpsbcpay.h:
+	  rtpsbcpay: Make a2dpsink to act like a bin and split the payloader.
+
+2013-01-08 16:27:42 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtp: small improvements
+
+2013-01-07 15:50:33 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: refactor handle sync code
+	  Move the code that combines the last SR packet and the current jitterbuffer sync
+	  values into a sync structure, into its own function. We want to reuse this bit
+	  later.
+
+2013-01-07 15:45:10 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtp: include downstream latency in SR calculations
+	  When we make a mapping between an RTP timestamp and an NTP timestamp, include
+	  the downstream latency applied to the sinks. This makes it possible to have
+	  both sinks run with different latencies and still have correct sync on the
+	  client. It also is more correct because the RTP timestamp in the SR report will
+	  actually correspond more closely to the NTP time it was sent on the server.
+	  For pipelines with high latency on the sender side, this actually allows a
+	  GStreamer receiver to perform synchronisation instead of dropping the RTCP
+	  packets.
+
+2013-01-07 14:25:14 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: don't cast event functions
+	  There is no need to cast the event functions and only causes problems later when
+	  we change the signature later and things silently compiles wrong code.
+
+2013-01-07 14:23:34 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtp: more debug
+
+2013-01-07 14:22:48 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: improve debug
+
+2013-01-02 00:03:27 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: sanity check size of available packet data for reading to avoid memory waste
+	  On Windows and OS/X, _get_available_bytes() may not return the size
+	  of the next pending packet, but the size of all pending packets in
+	  the kernel-side buffer, which might be rather large depending on
+	  configuration. Sanity-check the size returned by _get_available_bytes()
+	  to make sure we never allocate more memory than the max. size for
+	  a packet, if it's an IPv4 socket.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=610364
+
+2013-01-04 10:03:32 +0100  Robert Krakora <rob.krakora@messagenetsystems.com>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: Also handle the new ENOENT return value of VIDIOC_QUERYCTRL
+	  https://bugzilla.gnome.org/show_bug.cgi?id=691098
+
+2013-01-01 19:14:36 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: add test for souphttpsrc error handling with data
+	  https://bugzilla.gnome.org/show_bug.cgi?id=678429
+
+2012-06-22 21:56:52 +0000  Norbert Waschbuesch <nwaschbu@opentv.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: error out properly when receiving data along with an error status
+	  When receiving an error code from the http server, such as 404,
+	  data might be sent along with it, like a web page. We don't want
+	  to output that data in this case, and we also want to pass the
+	  FLOW_ERROR return back to the base class, so it can stop properly.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=678429
+
+2013-01-01 12:20:20 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* docs/plugins/gst-plugins-good-plugins.args:
+	  docs: update for new rtspsrc proxy-id and proxy-pw properties
+
+2013-01-01 12:19:23 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	  docs: fix docs build and update after removal of old cairo elements
+
+2013-01-01 12:12:02 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/cairo/Makefile.am:
+	* ext/cairo/gstcairo.c:
+	* ext/cairo/gstcairorender.c:
+	* ext/cairo/gstcairorender.h:
+	* ext/cairo/gsttextoverlay.c:
+	* ext/cairo/gsttextoverlay.h:
+	* ext/cairo/gsttimeoverlay.c:
+	* ext/cairo/gsttimeoverlay.h:
+	  cairo: remove old cairo-based text renderering element
+	  They haven't worked well or at all in a very long time
+	  and were rather bit-rotten, and there's no need for them
+	  any more.
+
+2013-01-01 11:52:09 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* configure.ac:
+	* ext/cairo/.gitignore:
+	* ext/cairo/Makefile.am:
+	* ext/cairo/gstcairo-marshal.list:
+	* ext/cairo/gstcairo.c:
+	* ext/cairo/gstcairooverlay.c:
+	* ext/cairo/gstcairooverlay.h:
+	* tests/examples/Makefile.am:
+	* tests/examples/cairo/Makefile.am:
+	* tests/examples/cairo/cairo_overlay.c:
+	  cairo: port cairooverlay to 0.11
+	  The other elements are not that interesting now that we're
+	  using pangocairo in the pango plugin, and should probably
+	  just be removed.
+
+2012-12-31 18:59:18 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/examples/rtp/server-decodebin-H263p-AMR.sh:
+	  examples: check for uri argument in decodebin-h264p-amr server example
+	  Otherwise people get a rather confusing error message.
+
+2012-12-31 00:22:27 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: add "proxy-id" and "proxy-pw" properties
+	  to match souphttpsrc. user/password passed via the URI
+	  will still take precedence though.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=395427
+
+2012-12-25 16:48:43 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* sys/oss4/oss4-sink.c:
+	  oss4sink: notify "volume" property on open to make apps query initial volume
+	  The initial volume might not be the property default, so
+	  emit a notify on the volume property to make apps get
+	  an up-to-date reading of the current volume.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=631053
+
+2012-12-20 17:12:30 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix cmd comparison
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=690476
+
+2012-12-20 17:12:20 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: add some more debug
+
+2012-12-20 16:44:24 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/raw1394/gst1394clock.c:
+	  1394clock: mark our clock type as OTHER
+
+2012-12-20 16:15:13 +0100  Jonas Holmberg <jonashg@axis.com>
+
+	* tests/check/elements/rtp-payloading.c:
+	  tests: add jpegpay unit test
+	  See also https://bugzilla.gnome.org/show_bug.cgi?id=684955
+
+2012-12-20 15:55:02 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstjpegenc.h:
+	  jpegenc: pass flowreturn upstream
+
+2012-09-27 15:42:56 +0200  Jonas Holmberg <jonashg@axis.com>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: handle width and height > 2040
+	  If width or height is greater than 2040 set width and height to zero in
+	  the rtp header and add x-dimensions to outcaps.
+	  Solves #684955
+
+2012-12-20 13:03:41 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: cleanup in flag define
+
+2012-12-20 13:02:57 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: improve debug
+
+2012-12-18 15:56:59 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* ext/wavpack/gstwavpackenc.c:
+	  wavpack: use appropriate printf format for gsize
+
+2012-12-18 15:55:43 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* ext/taglib/gstid3v2mux.cc:
+	  taglib: use appropriate printf format for gsize
+
+2012-12-18 15:54:08 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* ext/gdk_pixbuf/gstgdkpixbufdec.c:
+	  gdkpixbuf: use appropriate printf format for gsize
+
+2012-12-18 15:51:46 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	  rtp: use appropriate printf format for gsize
+
+2012-12-18 15:46:56 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: use appropriate printf format for gsize
+
+2012-12-17 16:35:56 +0100  Philippe Normand <philn@igalia.com>
+
+	* gst/interleave/interleave.c:
+	* gst/interleave/interleave.h:
+	  interleave: set src pad caps upon last sink pad CAPS event
+	  Gather caps on all sink pads before setting the src pad caps. This is
+	  specially needed when the audio channel mapping is set on the sink
+	  pads and the element needs to preserve it on its src pad.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=690267
+
+2012-12-17 22:55:12 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: skip empty tags
+	  instead of trying to add tags with empty strings, which
+	  causes criticals at runtime.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=690358
+
+2012-12-17 15:17:12 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	  audioparsers: Make sure the caps are actually writable before changing them
+
+2012-12-17 15:01:02 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	  audioparsers: Use the peer caps for restrictions instead of the srcpad allowed caps
+	  Otherwise we will intersect with the srcpad template caps and add all the caps fields
+	  that the parser will ever set, no matter if downstream restricts this field or not.
+	  This requires upstream to set this field on the caps to successfully negotiate.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=690184
+
+2012-12-14 22:25:08 +0000  Koop Mast <kwm@rainbow-runner.nl>
+
+	* configure.ac:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2: Teach where the videodev2.h header lives on freebsd.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=690233
+
+2012-12-16 23:27:41 +0000  Alexey Fisher <bug-track@fisher-privat.net>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: set appropriate block header flag for VP8 invisible frames
+	  Useful for debugging mostly.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=654259
+
+2012-12-16 15:25:03 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  docs: add rtpmux and rtpdtmfmux to plugin docs
+	  https://bugzilla.gnome.org/show_bug.cgi?id=629117
+
+2012-12-16 15:13:38 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/rtpmanager/Makefile.am:
+	* gst/rtpmanager/gstrtpmanager.c:
+	* gst/rtpmanager/gstrtpmuxer.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	  rtpmanager: move rtpmux and rtpdtmfmux elements from -bad
+	  https://bugzilla.gnome.org/show_bug.cgi?id=629117
+
+2012-11-03 20:38:00 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpdtmfmux.h:
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	* gst/rtpmanager/gstrtpmuxer.c:
+	* tests/check/elements/rtpmux.c:
+	  rtpmux: Fix FSF address
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687520
+
+2012-10-17 17:34:26 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Use gst_element_class_set_static_metadata()
+	  where possible. Avoids some string copies. Also re-indent
+	  some stuff. Also some indent fixes here and there.
+
+2012-09-10 20:38:14 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* tests/check/elements/rtpmux.c:
+	  rtpmux: Misc fix for 0.11
+	  Convert the incoming caps before proxying them
+	  Clear the last_pad when going to ready
+	  tests: Implement accept_caps, don't leak event
+
+2012-07-17 16:39:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: update for RTP buffer api changes
+
+2012-04-05 18:02:56 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmuxer.c:
+	  rtpmux: Update for GST_PLUGIN_DEFINE() API changes
+
+2012-04-02 11:07:18 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: fix compilation
+
+2012-03-11 19:06:59 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: fix for caps api changes
+
+2012-01-26 06:58:46 -0500  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Fix compiler warnings
+
+2012-01-29 18:01:05 +0000  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Unref non-forwarded events
+	  Also, don't unref forwarded ones
+
+2012-01-28 16:57:03 +0000  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: resync iterator on resync
+
+2012-01-27 12:08:52 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	  rtpmux: Re-push sticky events on input pad change
+
+2012-01-25 15:43:01 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Don't leak gvalue from iterator
+
+2012-01-25 16:46:44 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: more porting
+
+2012-01-24 14:20:52 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	* tests/check/elements/rtpmux.c:
+	  rtpmux: port to 0.11
+
+2011-11-04 12:22:37 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: make request pads take _%u
+
+2011-04-14 14:34:26 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	  rtpdtmfmux: Add last-stop to dtmf-event upstream events
+	  Add the running time of the last outputted buffer to the
+	  upstream "dtmf-event" events so that the dtmf source does not
+	  leave a gap.
+
+2010-11-25 19:21:11 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Remove dead assignments
+
+2010-10-19 13:43:14 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: add missing G_PARAM_STATIC_STRINGS flags
+	  Canonicalize property names as needed.
+
+2010-09-30 16:07:29 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Improve documentation
+	  Add an example pipeline, and try to explain a bit more what it does.
+
+2010-09-24 13:29:55 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpdtmfmux: remove unused variable
+
+2010-09-24 13:25:22 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpdtmfmux: remove unused signal boilerplate
+
+2010-09-24 13:24:48 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: no need to ref pad in _chain()
+
+2010-08-25 22:56:03 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Unlock the right mutex
+	  The mutex locked is for the 'mux' object, but we unlock the
+	  pad, which means that if the rtpmux gets a flush, then the
+	  object lock will stay locked forever, causing it to freeze
+	  the next time it tries to take it.
+	  Fixes bug #627991
+
+2010-07-01 15:19:12 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	  rtpmux: Add support for GstBufferList
+	  Factor out most of the buffer handling and implement a chain_list
+	  function. Also, the DTMF muxer has been modified to just have a
+	  function to accept or reject a buffer instead of having to subclass
+	  both chain and chain_list.
+
+2010-07-01 15:15:49 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Don't leak invalid buffers
+
+2010-06-03 10:43:20 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpmux: fix missing debug log message argument
+
+2010-05-10 18:37:55 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpdtmfmux: Add some debug messages
+
+2010-05-07 18:56:57 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpdtmfmux.h:
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	  rtpdtmfmux: Remove stream-lock event handling
+
+2010-05-07 18:54:49 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpdtmfmux: Update doc for simplification
+
+2010-05-07 18:40:30 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* tests/check/elements/rtpmux.c:
+	  tests: Change tests to not use the priority pads instead of the events
+
+2010-05-06 19:51:59 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpdtmfmux.h:
+	  rtpdtmfmux: Drop buffers on non-priority sinks when something is incoming on the priority sink
+
+2010-05-06 18:11:40 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	  rtpdtmfmux: Add priority sink pads
+
+2010-05-07 17:15:47 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpdtmfmux: Cleanup event function
+
+2010-05-07 16:42:22 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	* tests/check/elements/rtpmux.c:
+	  rtpmux: Aggregate incoming segments
+
+2010-05-06 19:09:48 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpdtmfmux: Update documentation
+
+2010-05-06 18:10:45 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	  rtpmux: Simplify request pad creation
+
+2010-03-21 21:39:18 +0100  Benjamin Otte <otte@redhat.com>
+
+	* tests/check/elements/rtpmux.c:
+	  Add -Wmissing-declarations -Wmissing-prototypes to configure flags
+	  And fix all warnings
+
+2010-03-18 17:30:26 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: gst_element_class_set_details => gst_element_class_set_details_simple
+
+2009-11-18 16:38:33 +0100  unknown <havard.graff@.eu.tandberg.int>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: update the current_ssrc from the caps
+	  Fixes #604101
+
+2009-12-09 14:42:21 +0100  Håvard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: release pads when disposing
+	  Because of an allocated priv (GstRTPMuxPadPrivate), the element will
+	  leak memory if not gst_rtp_mux_release_pad() is called. This would
+	  previously only happen if release_request_pad() was called explicitly,
+	  somthing that should not be neccesary.
+	  Fixes #604099
+
+2009-12-09 13:40:43 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  dtmfmux: method name cleanups
+
+2009-10-08 19:06:26 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* tests/check/elements/rtpmux.c:
+	  tests: Add test for rtpdtmfmux locking
+
+2009-09-28 19:54:53 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* tests/check/elements/rtpmux.c:
+	  tests: Add unit test for rtpmux
+
+2009-09-28 13:36:44 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Don't ignore requested pad name
+
+2009-07-29 17:23:31 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Remove empty finalize
+
+2009-07-21 15:31:33 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Free the pad private data on pad release
+	  Free the pad private data on pad release instead of using a weak ref,
+	  which is not thread safe. Also, lock the content of the pad private using the element's
+	  object lock.
+
+2009-04-28 16:10:21 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Reject wrong caps
+
+2009-04-28 16:03:19 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Fix leak Fixed a leak discovered by Laurent Glayal <spegle@yahoo.fr>
+
+2009-04-28 15:58:41 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Fix leak
+	  Fixed a leak discovered by Laurent Glayal <spegle@yahoo.fr>
+
+2009-04-22 18:01:07 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Fix warning
+
+2009-04-20 20:00:15 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Set different caps depending on the input
+
+2009-04-22 16:25:07 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Only free pad private when pad is disposed
+
+2009-04-20 18:41:39 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Remove useless caps mangling
+
+2009-04-20 18:36:42 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Rename variable for more clarity
+
+2009-04-20 17:43:39 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Use GST_BOILERPLATE
+
+2009-04-20 17:42:40 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpdtmfmux.h:
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Do the includes locally
+
+2009-04-15 13:23:01 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Add GST_DEBUG_FUNCPTRs
+
+2009-04-15 13:15:55 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpdtmfmux: Release locked pad on release_pad
+	  Release the special pad if the pad is removed from the muxer.
+
+2009-04-15 13:09:27 -0400  Laurent Glayal <spglegle@yahoo.fr>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpdtmfmux: Release special on pad dispose
+	  Fixes #577690
+
+2009-02-25 11:45:05 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	  docs: various doc fixes
+	  No short-desc as we have them in the element details.
+	  Also keep things (Makefile.am and sections.txt) sorted.
+	  Reword ambigous returns. No text after since please.
+
+2009-02-10 17:02:24 +0000  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpmuxer.c:
+	  rtpmux: Move rtpmux from gst-plugins-farsight to -bad
+
+2009-02-20 17:45:50 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpdtmfmux.h:
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	* gst/rtpmanager/gstrtpmuxer.c:
+	  rtpmux: Re-indent to Gst style
+
+2009-02-10 19:11:15 +0000  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Document rtp muxer a bit
+
+2009-02-20 13:30:49 -0500  Laurent Glayal <spglegle@yahoo.fr>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpdtmfmux.h:
+	  rtpmux: Add signals before stream lock and after unlocking
+
+2009-02-18 20:18:46 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Let ssrc through getcaps
+
+2009-02-18 19:58:58 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Rename have_base to have_ts_base
+
+2009-02-18 18:14:52 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	  rtpmux: Protect the seqnum with object lock in rtpmux
+
+2009-02-18 18:07:44 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.h:
+	  rtpmux: Remove unused sink_ts_base
+
+2009-02-18 15:20:58 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Have getcaps to force the same clockrate on all pads
+
+2009-02-18 17:05:13 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Validate RTP data in RTP Mux
+
+2009-02-18 14:16:00 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	  rtpmux: Remove unused clock-rate property
+
+2009-02-18 13:56:36 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpdtmfmux.h:
+	  rtpmux: Clarify locking in rtpdtmfmux
+
+2009-02-18 13:32:56 -0500  Laurent Glayal <spglegle@yahoo.fr>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Missing format parameter
+
+2008-12-01 17:55:22 -0500  Håvard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Update seqnum base in rtp muxer
+	  With help from Wim
+
+2008-12-01 17:54:58 -0500  Håvard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Fix some more leaks
+
+2008-12-01 17:48:29 -0500  Håvard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpmux: Fix leak
+
+2008-09-29 15:03:05 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Don't unref caps we don't know (thanks Wim)
+
+2008-08-12 12:48:02 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Put per-buffer debug at level LOG
+
+2008-08-12 12:47:14 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Make debug print accurate
+
+2008-08-12 12:46:23 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Set our caps on the buffers
+
+2008-08-12 12:46:07 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Take the clock-base stored from the last setcaps
+
+2008-08-12 12:41:59 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Store the clock-base on setcaps
+
+2008-08-12 12:30:52 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Add padprivate to the request pads
+
+2008-08-11 21:20:06 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Make indentation more correct
+
+2008-08-11 21:05:34 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Fix typo
+
+2008-08-11 21:03:22 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Set seqnum-base and clock-base in caps from rtpmuxer
+
+2007-08-15 13:50:38 +0000  Zeeshan Ali <first.last@nokia.com>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpmux: more debug
+	  20070815135038-f3f1e-9c7a5490a525c6e8753cb1b8c03354df99132b5c.gz
+
+2007-08-20 18:50:32 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: missing comment
+	  20070820185032-4f0f6-0ab67b6ac40dd4e35a8fe53f3cb6daff65ce43b9.gz
+
+2007-07-12 19:53:36 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Make buffer writable before writing into it
+	  20070712195336-3e2dc-91a5fb797cfa4919d4e2f9a728c6d6fbd3b83d93.gz
+
+2007-07-06 20:24:59 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Set pads active when adding them to a potentially running element
+	  20070706202459-3e2dc-a3731f885725594def0a7be997fc7b3a739ee967.gz
+
+2007-06-07 12:01:21 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Fix multiple ref leaks (patches by SP GLE)
+	  20070607120121-3e2dc-061e9ef7a47b1b84fa8f8092f4b8bcc0e6db8c8c.gz
+
+2007-05-28 15:25:05 +0000  Zeeshan Ali <first.last@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: send event to all src pads
+	  20070528152505-f3f1e-039216c73dc93f64c49962c77a0253cb9cfec4d3.gz
+
+2007-05-28 12:37:49 +0000  Zeeshan Ali <first.last@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: print a warning if receive an error iterating sinkpads
+	  20070528123749-f3f1e-4c1eb3f511b5610143610a65a94d117f2c3d2580.gz
+
+2007-05-28 12:28:08 +0000  Zeeshan Ali <first.last@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: deal with all the gst_iterator_next() return values
+	  20070528122808-f3f1e-d301644c3be7633ec6dc5e28596e9346d2da6a50.gz
+
+2007-05-25 12:31:16 +0000  Zeeshan Ali <first.last@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Return correct value from the event handler
+	  20070525123116-f3f1e-131b37b5f4521618fe2f1320409a47e65b35ad2d.gz
+
+2007-05-25 10:27:09 +0000  Zeeshan Ali <first.last@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Ville's original patch to fix the traversal of dtmf event
+	  20070525102709-f3f1e-6c41d1ef934068a4f4e810e7e981b420075b0c98.gz
+
+2007-03-29 13:52:50 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Set the correct ts-offset on the get_prop value
+	  20070329135250-65035-a43e222d91d57c0a61cb3287586aaa29abf78674.gz
+
+2007-03-29 13:52:23 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Refactorize state_change
+	  20070329135223-65035-23a0107b2e397710f035c6e88cc0e49b65bb4d5d.gz
+
+2007-03-29 13:36:22 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	  rtpmux: set SSRC on the packets
+	  20070329133622-65035-1be6e0aa85a71389f7d257b9cd3e13a73d6b745b.gz
+
+2007-03-29 13:19:36 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Code clean-up and more debug output
+	  20070329131936-65035-9d499e209e0d7a409c3aa0d1040778babf076179.gz
+
+2007-03-28 11:22:19 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	  rtpmux: Use own clock-base
+	  20070328112219-65035-1ba5fefbc65059e9b0c860528a31062ceb6a7331.gz
+
+2007-03-23 16:31:39 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	  rtpmux: Only accept RTP streams that have the same clock-rate
+	  20070323163139-65035-fc0b17b0b8a7a041f48994c4f26e96568168bf95.gz
+
+2007-03-22 16:15:52 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpmux: Some more code-cleanups
+	  20070322161552-65035-bda96165e146b4f1d5fea1cc9576a7ab3abebc9e.gz
+
+2007-03-22 15:42:51 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: return newpad instead of NULL and warn if failed to create a pad
+	  20070322154251-65035-cdb6651e61c2eb0205cc8c24693b43f98a2da718.gz
+
+2007-03-22 12:41:32 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Refactorize the RTPMux code
+	  20070322124132-65035-0a3278147546e33f687097a43b775b3f6aa99f93.gz
+
+2007-03-22 12:14:53 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpmux: Some more doc fixing
+	  20070322121453-65035-12d602272217b51bd97df4e5790024c399622dd3.gz
+
+2007-03-22 11:32:28 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpmux: More Refactoring
+	  20070322113228-65035-bae34a79599e7de5293ed77b022361ccff822bb9.gz
+
+2007-03-22 11:31:54 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpmux: More documentation
+	  20070322113154-65035-624850541a5b5fc3df231204be5a83d07239db28.gz
+
+2007-03-21 16:33:11 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	  rtpmux: Refactor the event handler function
+	  20070321163311-65035-987e7f25d1ab5335b79f44b277abf15e4e37d317.gz
+
+2007-03-21 14:52:44 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpdtmfmux.c:
+	* gst/rtpmanager/gstrtpdtmfmux.h:
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	* gst/rtpmanager/gstrtpmuxer.c:
+	  rtpmux: Add RTPDTMFMux element
+	  20070321145244-65035-9a01390b0dee3398e53199a1fa1d9352004f338e.gz
+
+2007-03-21 12:31:49 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	* gst/rtpmanager/gstrtpmux.h:
+	  rtpmux: Remove DTMF-specific code from RTP muxer and make it extendable
+	  20070321123149-65035-b8a8f55ff78eed8cbb0042e827885edfc5438242.gz
+
+2007-03-20 12:05:24 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Put more helpful description
+	  20070320120524-65035-db27a7cf6307b511aeb3d996d26e790e367a7bad.gz
+
+2007-03-16 15:16:41 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: remove the (commented-out) code for blocking the pads
+	  20070316151641-65035-0123af387951f88594797c722e882cfe70240aff.gz
+
+2007-03-16 13:14:44 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Drop buffers instead of blocking the sinkpads
+	  20070316131444-65035-9c1345ad96108881f455d4b55a7f623cd302d0ed.gz
+
+2007-03-14 17:16:18 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Implement stream locking, needed for DTMF
+	  20070314171618-65035-e4d24b1606ce0a3e2e739f01833f61e4d7555eac.gz
+
+2007-03-14 10:20:58 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: use GST_*_OBJECT instead of g_*
+	  20070314102058-65035-e2442888f2e3e5a3a7659ad7954a4fba34749ce2.gz
+
+2007-03-14 10:18:54 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: No need to manage pads, parent does that for us
+	  20070314101854-65035-ef5f4abde227102a1128835ab325905eae4c3726.gz
+
+2007-03-14 09:03:58 +0000  zeenix@gmail.com <zeenix@gmail.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: Fix copyright header
+	  20070314090358-d014a-3a6d3eeeaaf5cb8ca3bca6a33e99a551f598bd48.gz
+
+2007-03-07 08:53:07 +0000  zeeshan.ali@nokia.com <zeeshan.ali@nokia.com>
+
+	* gst/rtpmanager/gstrtpmux.c:
+	  rtpmux: The first implementation of RTP muxer
+	  20070307085307-65035-833402413f99cb3f8be4883e92bad4c8722510c9.gz
+
+2012-12-15 21:27:01 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/audiofx/gstscaletempo.c:
+	* gst/audiofx/gstscaletempo.h:
+	  scaletempo: no need for a private struct
+
+2012-12-14 15:13:31 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	  docs: update plugin docs
+
+2012-12-14 15:13:19 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	  docs: add scaletempo to docs
+
+2012-11-06 13:36:39 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audiofx/Makefile.am:
+	* gst/audiofx/audiofx.c:
+	  audiofx: move scaletempo element from -bad
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687262
+
+2012-10-23 14:33:21 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: Fix event leak
+
+2012-10-23 14:32:24 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: Fix timestamp tracking
+
+2012-10-23 14:06:37 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: Implement LATENCY query
+
+2012-10-23 13:39:17 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/gstscaletempo.c:
+	* gst/audiofx/gstscaletempo.h:
+	  scaletempo: Store instance private data in the instance struct
+	  Getting it over and over again via G_TYPE_INSTANCE_GET_PRIVATE()
+	  is really slow.
+
+2012-10-17 17:34:26 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: use gst_element_class_set_static_metadata()
+	  where possible. Avoids some string copies. Also re-indent
+	  some stuff. Also some indent fixes here and there.
+
+2012-09-14 17:08:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: replace gst_element_class_set_details_simple with gst_element_class_set_metadata
+
+2012-09-14 16:45:34 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: ffmpegcolorspace is no more
+
+2012-04-05 18:02:56 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/gstscaletempoplugin.c:
+	  scaletempo: Update for GST_PLUGIN_DEFINE() API changes
+
+2012-03-18 18:32:55 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: port to 0.11
+
+2011-07-07 10:52:50 -0700  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: improve the docs
+	  Fix the syntax, add more explanation and xref the properties.
+
+2011-03-22 13:46:42 +0100  Chris E Jones <chris@chrisejones.com>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: Correctly handle newsegment events with stop==-1
+	  Fixes bug #645420.
+
+2010-10-19 13:43:14 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: add missing G_PARAM_STATIC_STRINGS flags
+	  Canonicalize property names as needed.
+
+2010-03-18 17:30:26 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: gst_element_class_set_details => gst_element_class_set_details_simple
+
+2009-11-05 13:40:38 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: properly update new segments
+	  Scaletempo was missing an update of 'stop' in
+	  new segment parameters when pushing it downstream,
+	  which caused files to end earlier when rate < 1.
+	  Fixes #599903
+	  Based on patch by: Bastian Hecht <hechtb@gmail.com>
+
+2009-06-14 20:00:51 +0200  Maximilian Högner <pbmaxi@hoegners.de>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: Explicitely cast to signed integers to fix a segfault
+	  Fixes bug #585660.
+
+2009-02-13 12:18:48 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/audiofx/gstscaletempo.c:
+	  scaletempo: Do not use void pointer arithmetic.
+
+2008-10-30 12:13:18 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  scaletempo: Return the result of parent_class->event()
+	  Original commit message from CVS:
+	  * gst/audiofx/gstscaletempo.c:
+	  Return the result of parent_class->event().
+
+2008-08-31 12:20:33 +0000  Rov Juvano <rovjuvano@users.sourceforge.net>
+
+	  Add scaletempo plugin, which allows to scale the speed of audio without changing the pitch by handling seeks with a r...
+	  Original commit message from CVS:
+	  Patch by: Rov Juvano <rovjuvano at users dot sourceforge dot net>
+	  * configure.ac:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * docs/plugins/inspect/plugin-scaletempo.xml:
+	  * examples/scaletempo/Makefile.am:
+	  * examples/scaletempo/demo-gui.c: (pop_status_bar),
+	  (status_bar_printf), (demo_gui_seek_bar_format), (update_position),
+	  (demo_gui_seek_bar_change), (demo_gui_do_change_rate),
+	  (demo_gui_do_set_rate), (demo_gui_do_rate_entered),
+	  (demo_gui_do_toggle_advanced), (demo_gui_do_toggle_disabled),
+	  (demo_gui_do_seek), (demo_gui_do_play), (demo_gui_do_pause),
+	  (demo_gui_do_play_pause), (demo_gui_do_open_file),
+	  (demo_gui_do_playlist_prev), (demo_gui_do_playlist_next),
+	  (demo_gui_do_about_dialog), (demo_gui_do_quit),
+	  (demo_gui_request_set_stride), (demo_gui_request_set_overlap),
+	  (demo_gui_request_set_search), (demo_gui_rate_changed),
+	  (demo_gui_playing_started), (demo_gui_playing_paused),
+	  (demo_gui_playing_ended), (demo_gui_player_errored),
+	  (demo_gui_stride_changed), (demo_gui_overlap_changed),
+	  (demo_gui_search_changed), (demo_gui_set_player_func),
+	  (demo_gui_set_playlist_func), (build_gvalue_array),
+	  (create_action), (demo_gui_show_func), (demo_gui_set_player),
+	  (demo_gui_set_playlist), (demo_gui_show), (demo_gui_get_property),
+	  (demo_gui_set_property), (demo_gui_init), (demo_gui_class_init),
+	  (demo_gui_get_type):
+	  * examples/scaletempo/demo-gui.h:
+	  * examples/scaletempo/demo-main.c: (handle_error_message),
+	  (handle_quit), (main):
+	  * examples/scaletempo/demo-player.c: (no_pipeline),
+	  (demo_player_event_listener), (demo_player_state_changed_cb),
+	  (demo_player_eos_cb), (demo_player_build_pipeline), (_set_rate),
+	  (demo_player_scale_rate_func), (demo_player_set_rate_func),
+	  (_set_state_and_wait), (demo_player_load_uri_func),
+	  (demo_player_play_func), (demo_player_pause_func), (_seek_to),
+	  (demo_player_seek_by_func), (demo_player_seek_to_func),
+	  (demo_player_get_position_func), (demo_player_get_duration_func),
+	  (demo_player_scale_rate), (demo_player_set_rate),
+	  (demo_player_load_uri), (demo_player_play), (demo_player_pause),
+	  (demo_player_seek_by), (demo_player_seek_to),
+	  (demo_player_get_position), (demo_player_get_duration),
+	  (demo_player_get_property), (demo_player_set_property),
+	  (demo_player_init), (demo_player_class_init),
+	  (demo_player_get_type):
+	  * examples/scaletempo/demo-player.h:
+	  * gst/audiofx/Makefile.am:
+	  * gst/audiofx/gstscaletempo.c: (best_overlap_offset_float),
+	  (best_overlap_offset_s16), (output_overlap_float),
+	  (output_overlap_s16), (fill_queue), (reinit_buffers),
+	  (gst_scaletempo_transform), (gst_scaletempo_transform_size),
+	  (gst_scaletempo_sink_event), (gst_scaletempo_set_caps),
+	  (gst_scaletempo_get_property), (gst_scaletempo_set_property),
+	  (gst_scaletempo_base_init), (gst_scaletempo_class_init),
+	  (gst_scaletempo_init):
+	  * gst/audiofx/gstscaletempo.h:
+	  * gst/audiofx/gstscaletempoplugin.c: (plugin_init):
+	  Add scaletempo plugin, which allows to scale the speed of audio without
+	  changing the pitch by handling seeks with a rate!=1.0.
+	  Integrate it into the docs and add the example application for it.
+	  Fixes bug #537700.
+
+2012-12-13 12:36:20 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  check: add (but disable) more rtp jitterbuffer tests
+	  Tests need to be ported to 1.0 before they can be enabled but added here so they
+	  don't get forgotten.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=667838
+
+2012-01-13 01:11:31 +0100  Havard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: bundle together late lost-events
+	  The scenario where you have a gap in a steady flow of packets of
+	  say 10 seconds (500 packets of with duration of 20ms), the jitterbuffer
+	  will idle up until it receives the first buffer after the gap, but will
+	  then go on to produce 499 lost-events, to "cover up" the gap.
+	  Now this is obviously wrong, since the last possible time for the earliest
+	  lost-events to be played out has obviously expired, but the fact that
+	  the jitterbuffer has a "length", represented with its own latency combined
+	  with the total latency downstream, allows for covering up at least some
+	  of this gap.
+	  So in the case of the "length" being 200ms, while having received packet
+	  500, the jitterbuffer should still create a timeout for packet 491, which
+	  will have its time expire at 10,02 seconds, specially since it might
+	  actually arrive in time! But obviously, waiting for packet 100, that had
+	  its time expire at 2 seconds, (remembering that the current time is 10)
+	  is useless...
+	  The patch will create one "big" lost-event for the first 490 packets,
+	  and then go on to create single ones if they can reach their
+	  playout deadline.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=667838
+
+2012-12-13 09:27:14 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix TCP reconnect
+	  Ignore other commands when reconnecting, otherwise the loop function would pause
+	  and the reconnection would not happen. Continue looping after doing a reconnect
+	  so that we have a chance to actually read the new data.
+
+2012-12-13 01:02:34 +0400  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/directsound/gstdirectsoundsink.h:
+	* sys/waveform/gstwaveformsink.h:
+	  directsound, waveform: fix compilation errors caused by circular includes
+	  https://bugzilla.gnome.org/show_bug.cgi?id=690124
+
+2012-12-12 17:35:04 +0000  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jack/gstjackutil.h:
+	* ext/libpng/gstpngenc.c:
+	* ext/pulse/pulseprobe.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulseutil.c:
+	* ext/vpx/gstvp8enc.c:
+	* sys/oss/common.h:
+	* sys/oss/gstossaudio.c:
+	* sys/oss/gstosssrc.c:
+	* sys/oss4/oss4-audio.h:
+	  ext/sys: Fix some compilation errors caused by circular includes
+
+2012-12-12 12:07:34 +0100  Philippe Normand <philn@igalia.com>
+
+	* gst/interleave/deinterleave.c:
+	  deinterleave: properly set srcpad channel position
+	  The src pad caps always describe a single audio channel so only the
+	  first position matters if deinterleave is configured to keep channel
+	  positions in its src pads.
+
+2012-12-12 11:09:42 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: timeout on udpsrc is in nanoseconds
+
+2012-12-12 11:08:13 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: improve timeouts
+	  Make it possible to set the timeout after we went to the READY state by using
+	  the timeout when checking the condition. This also makes it possible to set the
+	  timeout with a higher granularity than seconds.
+
+2012-12-11 13:00:46 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	* gst/deinterlace/gstdeinterlacemethod.h:
+	* gst/deinterlace/tvtime/greedy.c:
+	* gst/deinterlace/tvtime/greedyh.c:
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/scalerbob.c:
+	* gst/deinterlace/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	* gst/deinterlace/tvtime/vfir.c:
+	* gst/deinterlace/tvtime/weave.c:
+	* gst/deinterlace/tvtime/weavebff.c:
+	* gst/deinterlace/tvtime/weavetff.c:
+	  deinterlace: add support for strides
+	  Implement stride support correctly by taking it from the GstVideoFrame.
+	  Propose a bufferpool upstream when not operating in passthrough.
+
+2012-09-27 12:17:58 -0700  Aleix Conchillo Flaque <aleix@oblong.com>
+
+	  rtspsrc: do not change state to PLAYING if currently chaning state
+	  * gst/rtsp/gstrtspsrc.c (gst_rtspsrc_play): state change might be
+	  happening in the application thread, so we don't change the state to
+	  PLAYING in the gstrtspsrc thread unless it is safe.
+	  A specific case is when chaning the state to NULL from the application
+	  thread. This will synchronously try to stop the task (with the element
+	  state lock acquired), but we will try a gst_element_set_state from
+	  gstrtspsrc thread which will block on the element state lock causing a
+	  deadlock.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=684312
+
+2012-12-10 11:44:26 +0000  Alexey Chernov <4ernov@gmail.com>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: Fix resizing the Cocoa window on receiving new caps
+	  Fixes bug #689732.
+
+2012-11-30 20:37:47 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* sys/v4l2/Makefile.am:
+	  v4l2src: link against -lrt for clock_gettime()
+	  Need to explicitly link against -lrt for clock_gettime(), which
+	  we don't get in the libs any more, because core moved the
+	  gmodule-no-export-2.0 bit into Requires.Private.
+	  Not required for newer glibc, but for older ones, so check for that.
+
+2012-11-30 17:22:59 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/shout2/gstshout2.c:
+	  shout2send: accept audio/webm as well as video/webm
+	  https://bugzilla.gnome.org/show_bug.cgi?id=689336
+
+2012-11-30 17:20:18 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	* tests/check/elements/matroskamux.c:
+	  webmux: fix linking with shout2send element
+	  Shout2send only accepts webm format, not matroska, but due
+	  to a bug in matroskamux, webmmux's source pad is also created
+	  with the matroska source pad template as pad template, which
+	  makes the link function think it can't link webmmux to shout2send.
+	  Also add unit test.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=689336
+
+2012-11-27 11:13:37 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: use new option parser function
+
+2012-11-26 15:17:13 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/law/mulaw-conversion.c:
+	  law: fix accidental file permissions change
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687469
+
+2012-11-25 16:05:11 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: remove unused define
+
+2012-11-25 14:16:09 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: avoid criticals if unknown fourcc has space at beginning or end
+	  https://bugzilla.gnome.org/show_bug.cgi?id=682936
+
+2012-11-24 19:32:51 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: fix border filling for planar YUV formats
+	  We would get a green border instead of a black one, for
+	  example.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=684991
+
+2012-11-24 14:27:33 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/law/mulaw-conversion.c:
+	  mulaw: const-ify some arrays
+
+2012-11-02 12:38:44 -0400  Roland Krikava <rkrikava@gmail.com>
+
+	* gst/law/mulaw-conversion.c:
+	  mulawdec: fix integer overrun
+	  There might be more than 65535 samples in a chunk of data.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687469
+
+2012-11-22 11:34:31 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: pause the task instead of spinning
+	  Actually pause the loop task instead of spinning forever.
+
+2012-11-19 03:31:37 -0500  Joshua M. Doe <oss@nvl.army.mil>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: Add gray 8/16 support
+
+2012-11-19 11:25:14 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From b497c4f to a72faea
+
+2012-11-16 15:38:29 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: handle segment event
+	  Make a segment event when we send a new range header to a client (first PLAY
+	  request or after a seek). Send the segment event in interleaved mode.
+	  Clean the segment event on cleanup
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=688382
+
+2012-11-16 15:18:07 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix check for active streams
+	  A stream can be active without a srcpad yet and we want to send
+	  events on those streams as well.
+
+2012-11-16 13:31:04 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: create and add pads outside of lock
+	  Create and add the ghostpad for the new stream outside of the lock because it
+	  is not needed and causes deadlocks.
+
+2012-09-12 22:11:20 -0700  Aleix Conchillo Flaque <aleix@oblong.com>
+
+	  rtspsrc: allow client to disable reconnection
+	  * gst/rtsp/gstrtspsrc.[ch]: added new "udp-reconnect" property. Before,
+	  rtspsrc always tried to reconnect to the server when the RTSP
+	  connection was closed by the server. This property lets the user
+	  decide whether it wants rtspsrc to reconnect or not.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=683912
+
+2012-11-16 12:16:05 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: clear variables before retrying
+	  Else we might unref an old udpsrc twice in cleanup.
+
+2012-11-16 12:00:14 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: propose ports in multicast
+	  When the user configured a port-range, propose ports from this range
+	  as the multicast ports. The server is free to ignore this request but if it
+	  honours it, increment our ports so that we suggest the next port pair for the
+	  next stream.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=639420
+
+2012-11-16 11:58:53 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: add more debug
+
+2012-11-16 09:09:38 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: post messages in max-size mode as well
+	  No reason not to really.
+
+2012-11-15 14:37:44 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: post error before stopping
+
+2012-11-14 00:13:36 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmparobustdepay.c:
+	  gst_adapter_prev_timestamp -> gst_adapter_prev_pts
+	  https://bugzilla.gnome.org/show_bug.cgi?id=675598
+
+2012-11-12 19:23:41 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: Add NV12/NV21 support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=688225
+
+2012-11-12 13:01:23 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: Don't leak GstVideoCodecFrames that cause the creation of invisible frames
+	  Fixes bug #682714.
+
+2012-11-12 11:47:17 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulse: Use new GType for GThread instead of just G_TYPE_POINTER
+
+2012-11-12 11:14:34 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: protect against invalid RTP packets
+
+2012-11-12 10:44:01 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: Actually use the stop() vfunc implementation
+
+2012-11-12 10:31:59 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vpx/gstvp8dec.c:
+	  vp8dec: Fix last commit
+
+2012-11-12 10:10:15 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: Keep the input state in reset()
+	  It's still valid after a flush and we might not get a new one.
+
+2012-11-12 10:08:57 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vpx/gstvp8dec.c:
+	  vp8dec: Also destroy decoder in set_format() if it was created already
+	  Fixes a memory leak.
+
+2012-11-12 09:48:45 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vpx/gstvp8dec.c:
+	  vp8dec: Don't clear input state in reset()
+	  The input state is still valid after flushing until
+	  new caps arrive.
+	  Fixes bug #688092.
+
+2012-11-10 18:21:28 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/videocrop/gstvideocrop.c:
+	  videocrop: add support for YV12
+	  We can do I420, so we can do YV12 as well.
+
+2012-11-10 12:39:08 +0100  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: don't write stream headers with key-unit-event
+	  Don't write stream headers, let upstream elements insert them in the stream if
+	  all_headers=true is set in key unit events.
+
+2012-11-09 13:27:16 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videocrop/gstvideocrop.h:
+	  videocrop: Add NV12/NV21 support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687964
+
+2012-11-09 16:31:05 +0100  Debarshi Ray <rishi@gnu.org>
+
+	* ext/vpx/gstvp8dec.c:
+	  vp8dec: Don't give up so easily if failed to decode a frame
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687436
+
+2012-11-09 11:22:30 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Also clear GError
+
+2012-11-09 11:20:27 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Don't error out if we get an ICMP destination-unreachable message when trying to read packets
+	  See bug #529454 and #687782 and commit
+	  751f2bb3646f2beff3698c9f09900dbd0ea08abb
+
+2012-11-07 20:35:50 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* configure.ac:
+	  configure.ac: update courtesy of autoupdate
+
+2012-11-07 18:48:49 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	* configure.ac:
+	  configure: let AG_GST_PLUGIN_DOCS check for python
+	  And update common for move from AS_PATH_PYTHON to AM_PATH_PYTHON,
+	  which as a side-effect should pick up newer python versions as
+	  well.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=563903
+
+2012-11-07 13:36:33 +0100  Christian Fredrik Kalager Schaller <uraeus@linuxrisin.org>
+
+	* gst/rtp/Makefile.am:
+	  Fix vp8rtp header names in Makefile
+
+2012-11-06 15:03:55 +0100  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videocrop/gstvideocrop.h:
+	* tests/check/elements/videocrop.c:
+	  videocrop: Add support for automatic cropping
+	  This change enable automatic cropping using -1 set to left, top, right or
+	  bottom property. In the case both side are set to automatic cropping, the
+	  croping will be done equally on both side (in the odd case, right and
+	  bottom cropping will be 1 pixel more).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687761
+
+2012-11-02 16:39:28 +0100  Debarshi Ray <rishi@gnu.org>
+
+	* ext/speex/gstspeexdec.c:
+	  speexdec: Don't unmap or finish_frame an invalid GstBuffer
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687464
+
+2012-11-06 13:22:58 +0100  Marc Leeman <marc.leeman@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtsp: the RTCP port number is inclusive
+	  The configured port number pair has its upper bound set to the maximum
+	  allowed RTCP port, inclusive.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=639420
+
+2012-11-03 20:38:00 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/dtmf/gstdtmfdetect.c:
+	* gst/dtmf/gstdtmfdetect.h:
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfdepay.h:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  Fix FSF address
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687520
+
+2012-11-04 00:07:18 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/aalib/gstaasink.c:
+	* ext/aalib/gstaasink.h:
+	* ext/cairo/gstcairo.c:
+	* ext/cairo/gstcairooverlay.c:
+	* ext/cairo/gstcairooverlay.h:
+	* ext/cairo/gstcairorender.c:
+	* ext/cairo/gstcairorender.h:
+	* ext/cairo/gsttextoverlay.c:
+	* ext/cairo/gsttimeoverlay.c:
+	* ext/cairo/gsttimeoverlay.h:
+	* ext/dv/gstdv.c:
+	* ext/dv/gstdvdec.c:
+	* ext/dv/gstdvdec.h:
+	* ext/dv/gstdvdemux.c:
+	* ext/dv/gstdvdemux.h:
+	* ext/dv/gstsmptetimecode.c:
+	* ext/dv/gstsmptetimecode.h:
+	* ext/flac/gstflac.c:
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacdec.h:
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflacenc.h:
+	* ext/flac/gstflactag.c:
+	* ext/flac/gstflactag.h:
+	* ext/gdk_pixbuf/gstgdkanimation.c:
+	* ext/gdk_pixbuf/gstgdkanimation.h:
+	* ext/gdk_pixbuf/gstgdkpixbufdec.c:
+	* ext/gdk_pixbuf/gstgdkpixbufdec.h:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.h:
+	* ext/gdk_pixbuf/gstgdkpixbufplugin.c:
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	* ext/gdk_pixbuf/gstgdkpixbufsink.h:
+	* ext/gdk_pixbuf/pixbufscale.c:
+	* ext/gdk_pixbuf/pixbufscale.h:
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	* ext/jack/gstjackaudioclient.c:
+	* ext/jack/gstjackaudioclient.h:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosink.h:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jack/gstjackaudiosrc.h:
+	* ext/jack/gstjackringbuffer.h:
+	* ext/jack/gstjackutil.c:
+	* ext/jack/gstjackutil.h:
+	* ext/jpeg/gstjpeg.c:
+	* ext/jpeg/gstjpeg.h:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstjpegenc.h:
+	* ext/jpeg/gstsmokedec.c:
+	* ext/jpeg/gstsmokedec.h:
+	* ext/jpeg/gstsmokeenc.c:
+	* ext/jpeg/gstsmokeenc.h:
+	* ext/jpeg/smokecodec.c:
+	* ext/jpeg/smokecodec.h:
+	* ext/jpeg/smokeformat.h:
+	* ext/libcaca/gstcacasink.c:
+	* ext/libcaca/gstcacasink.h:
+	* ext/libpng/gstpng.c:
+	* ext/libpng/gstpng.h:
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngdec.h:
+	* ext/libpng/gstpngenc.c:
+	* ext/libpng/gstpngenc.h:
+	* ext/mikmod/README:
+	* ext/mikmod/gstmikmod.c:
+	* ext/mikmod/gstmikmod.h:
+	* ext/mikmod/mikmod_types.c:
+	* ext/mikmod/mikmod_types.h:
+	* ext/pulse/plugin.c:
+	* ext/pulse/pulseprobe.c:
+	* ext/pulse/pulseprobe.h:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulsesrc.h:
+	* ext/pulse/pulseutil.c:
+	* ext/pulse/pulseutil.h:
+	* ext/raw1394/gst1394.c:
+	* ext/raw1394/gst1394clock.c:
+	* ext/raw1394/gst1394clock.h:
+	* ext/raw1394/gst1394probe.c:
+	* ext/raw1394/gst1394probe.h:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gstdv1394src.h:
+	* ext/raw1394/gsthdv1394src.c:
+	* ext/raw1394/gsthdv1394src.h:
+	* ext/shout2/gstshout2.c:
+	* ext/shout2/gstshout2.h:
+	* ext/soup/gstsouphttpclientsink.h:
+	* ext/speex/gstspeex.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexdec.h:
+	* ext/speex/gstspeexenc.c:
+	* ext/speex/gstspeexenc.h:
+	* ext/taglib/gstapev2mux.cc:
+	* ext/taglib/gstapev2mux.h:
+	* ext/taglib/gstid3v2mux.cc:
+	* ext/taglib/gstid3v2mux.h:
+	* ext/taglib/gsttaglibplugin.c:
+	* ext/vpx/gstvp8dec.c:
+	* ext/vpx/gstvp8dec.h:
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp8enc.h:
+	* ext/vpx/gstvp8utils.c:
+	* ext/vpx/gstvp8utils.h:
+	* ext/vpx/plugin.c:
+	* ext/wavpack/gstwavpack.c:
+	* ext/wavpack/gstwavpackcommon.c:
+	* ext/wavpack/gstwavpackcommon.h:
+	* ext/wavpack/gstwavpackdec.c:
+	* ext/wavpack/gstwavpackdec.h:
+	* ext/wavpack/gstwavpackenc.c:
+	* ext/wavpack/gstwavpackenc.h:
+	* ext/wavpack/gstwavpackstreamreader.c:
+	* ext/wavpack/gstwavpackstreamreader.h:
+	* gst-libs/gst/gettext.h:
+	* gst-libs/gst/glib-compat-private.h:
+	* gst-libs/gst/gst-i18n-plugin.h:
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalpha.h:
+	* gst/alpha/gstalphacolor.c:
+	* gst/alpha/gstalphacolor.h:
+	* gst/apetag/gstapedemux.c:
+	* gst/apetag/gstapedemux.h:
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audioamplify.h:
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiochebband.h:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/audiofx/audiocheblimit.h:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audiodynamic.h:
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audioecho.h:
+	* gst/audiofx/audiofirfilter.c:
+	* gst/audiofx/audiofirfilter.h:
+	* gst/audiofx/audiofx.c:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbasefirfilter.h:
+	* gst/audiofx/audiofxbaseiirfilter.c:
+	* gst/audiofx/audiofxbaseiirfilter.h:
+	* gst/audiofx/audioiirfilter.c:
+	* gst/audiofx/audioiirfilter.h:
+	* gst/audiofx/audioinvert.c:
+	* gst/audiofx/audioinvert.h:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/audiofx/audiokaraoke.h:
+	* gst/audiofx/audiopanorama.c:
+	* gst/audiofx/audiopanorama.h:
+	* gst/audiofx/audiowsincband.c:
+	* gst/audiofx/audiowsincband.h:
+	* gst/audiofx/audiowsinclimit.c:
+	* gst/audiofx/audiowsinclimit.h:
+	* gst/audiofx/math_compat.h:
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstaacparse.h:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstac3parse.h:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstamrparse.h:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstdcaparse.h:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstflacparse.h:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstmpegaudioparse.h:
+	* gst/audioparsers/gstwavpackparse.c:
+	* gst/audioparsers/gstwavpackparse.h:
+	* gst/audioparsers/plugin.c:
+	* gst/auparse/gstauparse.c:
+	* gst/auparse/gstauparse.h:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosink.h:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautoaudiosrc.h:
+	* gst/autodetect/gstautodetect.c:
+	* gst/autodetect/gstautodetect.h:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosink.h:
+	* gst/autodetect/gstautovideosrc.c:
+	* gst/autodetect/gstautovideosrc.h:
+	* gst/avi/avi-ids.h:
+	* gst/avi/gstavi.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavimux.h:
+	* gst/avi/gstavisubtitle.c:
+	* gst/cutter/gstcutter.c:
+	* gst/cutter/gstcutter.h:
+	* gst/debugutils/breakmydata.c:
+	* gst/debugutils/cpureport.c:
+	* gst/debugutils/cpureport.h:
+	* gst/debugutils/gstcapsdebug.c:
+	* gst/debugutils/gstcapsdebug.h:
+	* gst/debugutils/gstdebug.c:
+	* gst/debugutils/gstnavigationtest.c:
+	* gst/debugutils/gstnavigationtest.h:
+	* gst/debugutils/gstnavseek.c:
+	* gst/debugutils/gstnavseek.h:
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/debugutils/gstpushfilesrc.h:
+	* gst/debugutils/gsttaginject.c:
+	* gst/debugutils/gsttaginject.h:
+	* gst/debugutils/progressreport.c:
+	* gst/debugutils/progressreport.h:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/debugutils/testplugin.c:
+	* gst/debugutils/tests.c:
+	* gst/debugutils/tests.h:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	* gst/deinterlace/gstdeinterlacemethod.h:
+	* gst/deinterlace/tvtime/greedy.c:
+	* gst/deinterlace/tvtime/greedyh.asm:
+	* gst/deinterlace/tvtime/greedyh.c:
+	* gst/deinterlace/tvtime/greedyhmacros.h:
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/plugins.h:
+	* gst/deinterlace/tvtime/scalerbob.c:
+	* gst/deinterlace/tvtime/tomsmocomp.c:
+	* gst/deinterlace/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	* gst/deinterlace/tvtime/vfir.c:
+	* gst/deinterlace/tvtime/weave.c:
+	* gst/deinterlace/tvtime/weavebff.c:
+	* gst/deinterlace/tvtime/weavetff.c:
+	* gst/deinterlace/tvtime/x86-64_macros.inc:
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstaging.h:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstdice.h:
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstedge.h:
+	* gst/effectv/gsteffectv.c:
+	* gst/effectv/gsteffectv.h:
+	* gst/effectv/gstop.c:
+	* gst/effectv/gstop.h:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstquark.h:
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstradioac.h:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstrev.h:
+	* gst/effectv/gstripple.c:
+	* gst/effectv/gstripple.h:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gstshagadelic.h:
+	* gst/effectv/gststreak.c:
+	* gst/effectv/gststreak.h:
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstvertigo.h:
+	* gst/effectv/gstwarp.c:
+	* gst/effectv/gstwarp.h:
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/equalizer/gstiirequalizer.h:
+	* gst/equalizer/gstiirequalizer10bands.c:
+	* gst/equalizer/gstiirequalizer10bands.h:
+	* gst/equalizer/gstiirequalizer3bands.c:
+	* gst/equalizer/gstiirequalizer3bands.h:
+	* gst/equalizer/gstiirequalizernbands.c:
+	* gst/equalizer/gstiirequalizernbands.h:
+	* gst/flv/amfdefs.h:
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	* gst/flv/gstindex.c:
+	* gst/flv/gstindex.h:
+	* gst/flv/gstmemindex.c:
+	* gst/flx/flx_color.c:
+	* gst/flx/flx_color.h:
+	* gst/flx/flx_fmt.h:
+	* gst/flx/gstflxdec.c:
+	* gst/flx/gstflxdec.h:
+	* gst/goom/config_param.c:
+	* gst/goom/convolve_fx.c:
+	* gst/goom/drawmethods.c:
+	* gst/goom/drawmethods.h:
+	* gst/goom/filters.c:
+	* gst/goom/filters_mmx.s:
+	* gst/goom/flying_stars_fx.c:
+	* gst/goom/goom.h:
+	* gst/goom/goom_config.h:
+	* gst/goom/goom_config_param.h:
+	* gst/goom/goom_core.c:
+	* gst/goom/goom_filters.h:
+	* gst/goom/goom_fx.h:
+	* gst/goom/goom_graphic.h:
+	* gst/goom/goom_plugin_info.h:
+	* gst/goom/goom_tools.c:
+	* gst/goom/goom_tools.h:
+	* gst/goom/goom_typedefs.h:
+	* gst/goom/goom_visual_fx.h:
+	* gst/goom/graphic.c:
+	* gst/goom/gstgoom.c:
+	* gst/goom/gstgoom.h:
+	* gst/goom/lines.c:
+	* gst/goom/lines.h:
+	* gst/goom/mathtools.c:
+	* gst/goom/mathtools.h:
+	* gst/goom/motif_goom1.h:
+	* gst/goom/motif_goom2.h:
+	* gst/goom/plugin_info.c:
+	* gst/goom/ppc_drawings.h:
+	* gst/goom/ppc_drawings.s:
+	* gst/goom/ppc_zoom_ultimate.h:
+	* gst/goom/ppc_zoom_ultimate.s:
+	* gst/goom/sound_tester.c:
+	* gst/goom/sound_tester.h:
+	* gst/goom/surf3d.c:
+	* gst/goom/surf3d.h:
+	* gst/goom/tentacle3d.c:
+	* gst/goom/tentacle3d.h:
+	* gst/goom/v3d.c:
+	* gst/goom/v3d.h:
+	* gst/goom2k1/gstgoom.c:
+	* gst/goom2k1/gstgoom.h:
+	* gst/icydemux/gsticydemux.c:
+	* gst/icydemux/gsticydemux.h:
+	* gst/id3demux/gstid3demux.c:
+	* gst/id3demux/gstid3demux.h:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/imagefreeze/gstimagefreeze.h:
+	* gst/interleave/deinterleave.c:
+	* gst/interleave/deinterleave.h:
+	* gst/interleave/interleave.c:
+	* gst/interleave/interleave.h:
+	* gst/interleave/plugin.c:
+	* gst/interleave/plugin.h:
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/atomsrecovery.c:
+	* gst/isomp4/atomsrecovery.h:
+	* gst/isomp4/descriptors.c:
+	* gst/isomp4/descriptors.h:
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/ftypcc.h:
+	* gst/isomp4/gstqtmoovrecover.c:
+	* gst/isomp4/gstqtmoovrecover.h:
+	* gst/isomp4/gstqtmux-doc.c:
+	* gst/isomp4/gstqtmux-doc.h:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	* gst/isomp4/gstqtmuxmap.c:
+	* gst/isomp4/gstqtmuxmap.h:
+	* gst/isomp4/gstrtpxqtdepay.c:
+	* gst/isomp4/gstrtpxqtdepay.h:
+	* gst/isomp4/isomp4-plugin.c:
+	* gst/isomp4/properties.c:
+	* gst/isomp4/properties.h:
+	* gst/isomp4/qtatomparser.h:
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	* gst/isomp4/qtdemux_dump.c:
+	* gst/isomp4/qtdemux_dump.h:
+	* gst/isomp4/qtdemux_fourcc.h:
+	* gst/isomp4/qtdemux_lang.c:
+	* gst/isomp4/qtdemux_lang.h:
+	* gst/isomp4/qtdemux_types.c:
+	* gst/isomp4/qtdemux_types.h:
+	* gst/isomp4/qtpalette.h:
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-decode.h:
+	* gst/law/alaw-encode.c:
+	* gst/law/alaw-encode.h:
+	* gst/law/alaw.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-decode.h:
+	* gst/law/mulaw-encode.c:
+	* gst/law/mulaw-encode.h:
+	* gst/law/mulaw.c:
+	* gst/level/gstlevel.c:
+	* gst/level/gstlevel.h:
+	* gst/matroska/ebml-ids.h:
+	* gst/matroska/ebml-read.c:
+	* gst/matroska/ebml-read.h:
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/ebml-write.h:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	* gst/matroska/matroska-ids.c:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-parse.h:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	* gst/matroska/matroska.c:
+	* gst/matroska/webm-mux.c:
+	* gst/matroska/webm-mux.h:
+	* gst/monoscope/convolve.c:
+	* gst/monoscope/convolve.h:
+	* gst/monoscope/gstmonoscope.c:
+	* gst/monoscope/gstmonoscope.h:
+	* gst/multifile/gstmultifile.c:
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesink.h:
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/multifile/gstmultifilesrc.h:
+	* gst/multifile/gstsplitfilesrc.c:
+	* gst/multifile/gstsplitfilesrc.h:
+	* gst/multifile/patternspec.c:
+	* gst/multifile/patternspec.h:
+	* gst/multipart/multipart.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartdemux.h:
+	* gst/multipart/multipartmux.c:
+	* gst/multipart/multipartmux.h:
+	* gst/rtp/fnv1hash.c:
+	* gst/rtp/fnv1hash.h:
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstasteriskh263.h:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16depay.h:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpL16pay.h:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpac3depay.h:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpac3pay.h:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrdepay.h:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpamrpay.h:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpbvdepay.h:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpbvpay.h:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpchannels.c:
+	* gst/rtp/gstrtpchannels.h:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpdvdepay.h:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpdvpay.h:
+	* gst/rtp/gstrtpg722depay.c:
+	* gst/rtp/gstrtpg722depay.h:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtpg722pay.h:
+	* gst/rtp/gstrtpg723depay.c:
+	* gst/rtp/gstrtpg723depay.h:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg723pay.h:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpg729depay.h:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpg729pay.h:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmdepay.h:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtpgsmpay.h:
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtpgstdepay.h:
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtpgstpay.h:
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263depay.h:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pay.h:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263pdepay.h:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph263ppay.h:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264depay.h:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtph264pay.h:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpilbcdepay.h:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpilbcpay.h:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kdepay.h:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpj2kpay.h:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegdepay.h:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpjpegpay.h:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp1sdepay.h:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.h:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp2tpay.h:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4adepay.h:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4apay.h:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gdepay.h:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4gpay.h:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmp4vdepay.h:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmp4vpay.h:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpadepay.h:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmpapay.h:
+	* gst/rtp/gstrtpmparobustdepay.c:
+	* gst/rtp/gstrtpmparobustdepay.h:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtpmpvdepay.h:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtpmpvpay.h:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtppcmupay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpqcelpdepay.h:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpqdmdepay.h:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpsirendepay.h:
+	* gst/rtp/gstrtpsirenpay.c:
+	* gst/rtp/gstrtpsirenpay.h:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtpsv3vdepay.h:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheoradepay.h:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtptheorapay.h:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbisdepay.h:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvorbispay.h:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawdepay.h:
+	* gst/rtp/gstrtpvrawpay.c:
+	* gst/rtp/gstrtpvrawpay.h:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.h:
+	* gst/rtpmanager/gstrtpmanager.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtpptdemux.h:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpsession.h:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtpmanager/gstrtpssrcdemux.h:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	* gst/rtpmanager/rtpstats.c:
+	* gst/rtpmanager/rtpstats.h:
+	* gst/rtsp/gstrtpdec.c:
+	* gst/rtsp/gstrtpdec.h:
+	* gst/rtsp/gstrtsp.c:
+	* gst/rtsp/gstrtsp.h:
+	* gst/rtsp/gstrtspext.c:
+	* gst/rtsp/gstrtspext.h:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/shapewipe/gstshapewipe.h:
+	* gst/smpte/barboxwipes.c:
+	* gst/smpte/gstmask.c:
+	* gst/smpte/gstmask.h:
+	* gst/smpte/gstsmpte.c:
+	* gst/smpte/gstsmpte.h:
+	* gst/smpte/gstsmptealpha.c:
+	* gst/smpte/gstsmptealpha.h:
+	* gst/smpte/paint.c:
+	* gst/smpte/paint.h:
+	* gst/smpte/plugin.c:
+	* gst/spectrum/gstspectrum.c:
+	* gst/spectrum/gstspectrum.h:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstdynudpsink.h:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	* gst/udp/gstudp.c:
+	* gst/udp/gstudp.h:
+	* gst/udp/gstudpnetutils.c:
+	* gst/udp/gstudpnetutils.h:
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsink.h:
+	* gst/udp/gstudpsrc.c:
+	* gst/udp/gstudpsrc.h:
+	* gst/videobox/gstvideobox.c:
+	* gst/videobox/gstvideobox.h:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videocrop/gstaspectratiocrop.h:
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videocrop/gstvideocrop.h:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstgamma.h:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideobalance.h:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videofilter/gstvideoflip.h:
+	* gst/videofilter/gstvideomedian.c:
+	* gst/videofilter/gstvideomedian.h:
+	* gst/videofilter/gstvideotemplate.c:
+	* gst/videofilter/plugin.c:
+	* gst/videomixer/blend.c:
+	* gst/videomixer/blend.h:
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	* gst/videomixer/videomixer2pad.h:
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavenc/gstwavenc.h:
+	* gst/wavparse/gstwavparse.c:
+	* gst/wavparse/gstwavparse.h:
+	* gst/y4m/gsty4mencode.c:
+	* gst/y4m/gsty4mencode.h:
+	* sys/directsound/gstdirectsoundplugin.c:
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/directsound/gstdirectsoundsink.h:
+	* sys/oss/common.h:
+	* sys/oss/gstossaudio.c:
+	* sys/oss/gstossdmabuffer.c:
+	* sys/oss/gstossdmabuffer.h:
+	* sys/oss/gstosshelper.c:
+	* sys/oss/gstosshelper.h:
+	* sys/oss/gstosssink.c:
+	* sys/oss/gstosssink.h:
+	* sys/oss/gstosssrc.c:
+	* sys/oss/gstosssrc.h:
+	* sys/oss4/oss4-audio.c:
+	* sys/oss4/oss4-audio.h:
+	* sys/oss4/oss4-property-probe.c:
+	* sys/oss4/oss4-property-probe.h:
+	* sys/oss4/oss4-sink.c:
+	* sys/oss4/oss4-sink.h:
+	* sys/oss4/oss4-source.c:
+	* sys/oss4/oss4-source.h:
+	* sys/osxaudio/gstosxaudio.c:
+	* sys/osxaudio/gstosxaudioelement.c:
+	* sys/osxaudio/gstosxaudioelement.h:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosink.h:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxaudio/gstosxaudiosrc.h:
+	* sys/osxaudio/gstosxcoreaudio.h:
+	* sys/osxaudio/gstosxringbuffer.c:
+	* sys/osxaudio/gstosxringbuffer.h:
+	* sys/osxvideo/cocoawindow.h:
+	* sys/osxvideo/cocoawindow.m:
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	* sys/sunaudio/gstsunaudio.c:
+	* sys/sunaudio/gstsunaudiomixer.c:
+	* sys/sunaudio/gstsunaudiomixer.h:
+	* sys/sunaudio/gstsunaudiomixerctrl.c:
+	* sys/sunaudio/gstsunaudiomixerctrl.h:
+	* sys/sunaudio/gstsunaudiomixeroptions.c:
+	* sys/sunaudio/gstsunaudiomixeroptions.h:
+	* sys/sunaudio/gstsunaudiomixertrack.c:
+	* sys/sunaudio/gstsunaudiomixertrack.h:
+	* sys/sunaudio/gstsunaudiosink.c:
+	* sys/sunaudio/gstsunaudiosink.h:
+	* sys/sunaudio/gstsunaudiosrc.c:
+	* sys/sunaudio/gstsunaudiosrc.h:
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2colorbalance.c:
+	* sys/v4l2/gstv4l2colorbalance.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2radio.c:
+	* sys/v4l2/gstv4l2radio.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2sink.h:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/gstv4l2tuner.c:
+	* sys/v4l2/gstv4l2tuner.h:
+	* sys/v4l2/gstv4l2videooverlay.c:
+	* sys/v4l2/gstv4l2videooverlay.h:
+	* sys/v4l2/gstv4l2vidorient.c:
+	* sys/v4l2/gstv4l2vidorient.h:
+	* sys/v4l2/tuner.c:
+	* sys/v4l2/tuner.h:
+	* sys/v4l2/tunerchannel.c:
+	* sys/v4l2/tunerchannel.h:
+	* sys/v4l2/tunernorm.c:
+	* sys/v4l2/tunernorm.h:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2_calls.h:
+	* sys/waveform/gstwaveformplugin.c:
+	* sys/waveform/gstwaveformsink.c:
+	* sys/waveform/gstwaveformsink.h:
+	* sys/ximage/gstximagesrc.c:
+	* sys/ximage/gstximagesrc.h:
+	* sys/ximage/ximageutil.c:
+	* sys/ximage/ximageutil.h:
+	* tests/check/elements/aacparse.c:
+	* tests/check/elements/ac3parse.c:
+	* tests/check/elements/alphacolor.c:
+	* tests/check/elements/amrparse.c:
+	* tests/check/elements/apev2mux.c:
+	* tests/check/elements/aspectratiocrop.c:
+	* tests/check/elements/audioamplify.c:
+	* tests/check/elements/audiodynamic.c:
+	* tests/check/elements/audioecho.c:
+	* tests/check/elements/audioinvert.c:
+	* tests/check/elements/audiopanorama.c:
+	* tests/check/elements/autodetect.c:
+	* tests/check/elements/avimux.c:
+	* tests/check/elements/avisubtitle.c:
+	* tests/check/elements/capssetter.c:
+	* tests/check/elements/deinterlace.c:
+	* tests/check/elements/deinterleave.c:
+	* tests/check/elements/flacparse.c:
+	* tests/check/elements/flvdemux.c:
+	* tests/check/elements/flvmux.c:
+	* tests/check/elements/gdkpixbufsink.c:
+	* tests/check/elements/icydemux.c:
+	* tests/check/elements/id3demux.c:
+	* tests/check/elements/id3v2mux.c:
+	* tests/check/elements/imagefreeze.c:
+	* tests/check/elements/interleave.c:
+	* tests/check/elements/jpegdec.c:
+	* tests/check/elements/jpegenc.c:
+	* tests/check/elements/level.c:
+	* tests/check/elements/matroskamux.c:
+	* tests/check/elements/matroskaparse.c:
+	* tests/check/elements/mpegaudioparse.c:
+	* tests/check/elements/multifile.c:
+	* tests/check/elements/parser.c:
+	* tests/check/elements/parser.h:
+	* tests/check/elements/qtmux.c:
+	* tests/check/elements/rtp-payloading.c:
+	* tests/check/elements/rtpbin.c:
+	* tests/check/elements/rtpbin_buffer_list.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	* tests/check/elements/shapewipe.c:
+	* tests/check/elements/souphttpsrc.c:
+	* tests/check/elements/spectrum.c:
+	* tests/check/elements/sunaudio.c:
+	* tests/check/elements/udpsink.c:
+	* tests/check/elements/udpsrc.c:
+	* tests/check/elements/videocrop.c:
+	* tests/check/elements/videofilter.c:
+	* tests/check/elements/vp8dec.c:
+	* tests/check/elements/vp8enc.c:
+	* tests/check/elements/wavpackdec.c:
+	* tests/check/elements/wavpackenc.c:
+	* tests/check/elements/wavpackparse.c:
+	* tests/check/elements/y4menc.c:
+	* tests/check/generic/states.c:
+	* tests/check/pipelines/effectv.c:
+	* tests/check/pipelines/flacdec.c:
+	* tests/check/pipelines/simple-launch-lines.c:
+	* tests/check/pipelines/tagschecking.c:
+	* tests/check/pipelines/wavenc.c:
+	* tests/check/pipelines/wavpack.c:
+	* tests/examples/audiofx/firfilter-example.c:
+	* tests/examples/audiofx/iirfilter-example.c:
+	* tests/examples/cairo/cairo_overlay.c:
+	* tests/examples/level/level-example.c:
+	* tests/examples/pulse/pulse.c:
+	* tests/examples/rtp/client-PCMA.c:
+	* tests/examples/rtp/server-alsasrc-PCMA.c:
+	* tests/examples/shapewipe/shapewipe-example.c:
+	* tests/examples/spectrum/demo-audiotest.c:
+	* tests/examples/spectrum/demo-osssrc.c:
+	* tests/examples/spectrum/spectrum-example.c:
+	* tests/examples/v4l2/camctrl.c:
+	* tests/icles/equalizer-test.c:
+	* tests/icles/gdkpixbufsink-test.c:
+	* tests/icles/test-oss4.c:
+	* tests/icles/v4l2src-test.c:
+	* tests/icles/videobox-test.c:
+	* tests/icles/videocrop-test.c:
+	* tests/icles/videocrop2-test.c:
+	* tests/icles/ximagesrc-test.c:
+	  Fix FSF address
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687520
+
+2012-11-02 18:47:26 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  vrawdepay: don't access rtp buffer after unmap
+	  Read the marker bit before we unmap the rtp packet.
+
+2012-11-02 09:34:25 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vpx/gstvp8dec.c:
+	  vp8dec: Immediately return if opening the decoder failed
+	  Instead of ignoring any errors.
+
+2012-11-01 22:02:39 +0100  Debarshi Ray <rishi@gnu.org>
+
+	* ext/vpx/gstvp8dec.c:
+	  vp8dec: Short circuit gst_vp8_dec_handle_frame if keyframe is missing
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687376
+
+2012-11-02 10:53:57 +1300  Douglas Bagnall <douglas@paradise.net.nz>
+
+	* gst/videomixer/blend.c:
+	  videoconvert: Compare y offset with height, not width, when testing for overlap
+	  This could have prevented images showing that should have when the
+	  source height is greater than its width.
+	  When width exceeds height, as is common, it probably only caused a
+	  miniscule amount of unnecessary work.  I haven't tested.
+
+2012-11-01 21:09:56 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/rtp/gstrtpvp8depay.c:
+	* gst/rtp/gstrtpvp8depay.h:
+	* gst/rtp/gstrtpvp8pay.c:
+	* gst/rtp/gstrtpvp8pay.h:
+	  rtpvp8: include config.h and minor style fixes
+
+2012-11-01 20:13:43 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/rtp/Makefile.am:
+	  rtp: fix tabs/space mess in Makefile.am
+
+2012-11-01 20:05:49 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpvp8.c:
+	  rtp: move VP8 payloader and depayloader from -bad
+	  Spec is still in draft state, but should hopefully not
+	  change much now. Besides, we announce things as VP8-DRAFT-IETF-01
+	  in our caps, so even if things change in incompatible ways it
+	  should not break anything.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687263
+
+2012-10-17 17:34:26 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtpvp8depay.c:
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8: use gst_element_class_set_static_metadata()
+	  where possible. Avoids some string copies. Also re-indent
+	  some stuff. Also some indent fixes here and there.
+
+2012-09-14 17:08:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8: replace gst_element_class_set_details_simple with gst_element_class_set_metadata
+
+2012-04-05 18:02:56 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtp/gstrtpvp8.c:
+	  rtpvp8: update for GST_PLUGIN_DEFINE() API changes
+
+2012-03-28 12:49:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8: update for buffer changes
+
+2012-03-01 14:59:55 -0300  Danilo Cesar Lemes de Paula <danilo.cesar@collabora.co.uk>
+
+	* gst/rtp/gstrtpvp8depay.c:
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8; fix compatibility with the third draft
+	  https://bugzilla.gnome.org/show_bug.cgi?id=671073
+
+2012-01-25 16:20:41 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8: port some more to new memory API
+
+2012-01-25 10:45:51 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpvp8depay.c:
+	* gst/rtp/gstrtpvp8depay.h:
+	* gst/rtp/gstrtpvp8pay.c:
+	* gst/rtp/gstrtpvp8pay.h:
+	  rtpvp8: port to 0.11
+
+2011-10-03 12:06:27 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8pay: Fix typo
+
+2011-09-23 22:58:30 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/rtp/gstrtpvp8depay.c:
+	* gst/rtp/gstrtpvp8pay.c:
+	* gst/rtp/gstrtpvp8pay.h:
+	  rtpvp8: Update the pay/depay to the ietf-draft-01 spec
+
+2011-09-10 11:31:20 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/dboolhuff.c:
+	* gst/rtp/dboolhuff.h:
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8: fix bitstream parsing using the wrong kind of bitreader
+	  VP8 uses a probabilistic bool coder, not a straight bit coder.
+	  This fixes parsing when error-resilient is set.
+	  This commit includes a copy of libvpx's bool coder, BSD licensed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=652694
+
+2011-07-12 18:03:53 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8: Reject unknown bitstream versions
+
+2011-03-04 11:59:44 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	  rtpvp8: Fix unitialized variable
+	  Makes macosx compiler happy.
+
+2011-01-23 17:02:38 +0000  Sjoerd Simons <sjoerd@luon.net>
+
+	* gst/rtp/gstrtpvp8depay.c:
+	  rtpvp8depay: Accept packets with only one byte of data
+	  When fragmenting partions it can happen that an RTP packet only caries 1
+	  byte of RTP data.
+
+2011-01-23 16:42:17 +0000  Sjoerd Simons <sjoerd@luon.net>
+
+	* gst/rtp/gstrtpvp8pay.c:
+	* gst/rtp/gstrtpvp8pay.h:
+	  rtpvp8pay: Treat the frame header just like any other partition
+	  When setting up the initial mapping just act as if the global frame
+	  information is another partition. This saves special-casing it later in
+	  the actual packetizing code.
+
+2010-05-16 17:23:17 +0100  Sjoerd Simons <sjoerd@luon.net>
+
+	* gst/rtp/dboolhuff.LICENSE:
+	* gst/rtp/gstrtpvp8.c:
+	* gst/rtp/gstrtpvp8depay.c:
+	* gst/rtp/gstrtpvp8depay.h:
+	* gst/rtp/gstrtpvp8pay.c:
+	* gst/rtp/gstrtpvp8pay.h:
+	  rtpvp8: Add simple payloaders and depayloaders for VP8
+	  Minimal implementation of http://www.webmproject.org/code/specs/rtp/,
+	  version 0.3.2
+
+2012-11-01 18:42:39 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  gstpay: fix for 1.0 events
+	  Caps events are sometimes not followed by a buffer but by an event. Flush any
+	  pending caps before we make a packet with the event.
+	  Chain up to the parent event handler before we attempt to push RTP packets, it
+	  might be a segment event.
+
+2012-11-01 18:42:24 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	  gstdepay: fix small leak
+
+2012-11-01 17:44:11 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	  gstdepay: add support for events
+	  Conflicts:
+	  gst/rtp/gstrtpgstdepay.c
+
+2012-11-01 17:40:31 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtpgstpay.h:
+	  rtpgstpay: add support for sending events
+	  We currently only send tags and custom events. The other events
+	  might interfere with the receiver timings or are otherwise handled
+	  by RTP.
+	  Conflicts:
+	  gst/rtp/gstrtpgstpay.c
+
+2012-11-01 15:54:58 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtpgstpay.h:
+	  gstpay: rewrite payloader
+	  Use adapter to assemble the payload and make a flush function to
+	  turn this payload into (fragmented) packets.
+	  Conflicts:
+	  gst/rtp/gstrtpgstpay.c
+	  gst/rtp/gstrtpgstpay.h
+
+2012-11-01 13:03:44 +0000  Douglas Bagnall <douglas@paradise.net.nz>
+
+	* gst/videomixer/blend.c:
+	  videomixer: get height via GST_VIDEO_FRAME_HEIGHT, not _WIDTH
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687330
+
+2012-11-01 13:02:16 +0000  Douglas Bagnall <douglas@paradise.net.nz>
+
+	* gst/videobox/gstvideobox.c:
+	  videbox: fix border filling for gray formats
+	  Get the height via GST_VIDEO_FRAME_HEIGHT, not _WIDTH.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687330
+
+2012-11-01 11:58:57 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	  gstdepay: check for correct fragment offset
+	  Make sure we only insert the rtp packet in the adapter when the
+	  frag_offset matches. When the first packet of a fragment is dropped,
+	  it avoids putting the remaining packets in the adapter and processing
+	  the partial fragment.
+	  Conflicts:
+	  gst/rtp/gstrtpgstdepay.c
+
+2012-11-01 11:54:50 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  gstpay: set C flag on all buffers of the fragment
+	  Set the C flags on all the fragments instead of only those with
+	  caps in them. This makes it easier in the receiver to check if there
+	  is a caps in the assembled fragments just by looking at the last RTP
+	  packet flags.
+
+2012-11-01 10:55:03 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	  gstdepay: use the capsversion
+	  Take the caps from the input caps and store it in the slot given
+	  by capsversion.
+
+2012-11-01 10:52:25 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtpgstpay.h:
+	  gstpay: send caps inline
+	  Place the capsversion on the outgoing caps so that they end up in
+	  an SDP as well. Receivers need to know what capsversion a particular
+	  caps is for to be able to match the caps to the CV in the RTP packets.
+	  Place the caps inside the RTP packet whenever the caps change.
+	  Based on patch by Andrzej Bieniek <andrzej.bieniek@pure.com>
+	  Conflicts:
+	  gst/rtp/gstrtpgstpay.c
+	  gst/rtp/gstrtpgstpay.h
+
+2012-10-31 16:17:48 +0000  Andrzej Bieniek <andrzej.bieniek@pure.com>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  gstpay: add debug
+	  Conflicts:
+	  gst/rtp/gstrtpgstpay.c
+
+2012-10-31 16:09:26 +0000  Andrzej Bieniek <andrzej.bieniek@pure.com>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	  depay: correctly skip caps header size
+	  Conflicts:
+	  gst/rtp/gstrtpgstdepay.c
+
+2012-09-28 00:43:38 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.c:
+	* gst/matroska/matroska-ids.h:
+	  matroskademux: put streamheaders on vorbis/speex/flac/theora caps to make remuxing work
+	  https://bugzilla.gnome.org/show_bug.cgi?id=640589
+
+2012-10-28 00:07:46 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: don't assert in get_time() when called after shutdown
+	  Which might happen if the source gets set to NULL state before
+	  the rest of the pipeline.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=686985
+
+2012-10-30 11:10:49 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/examples/level/level-example.c:
+	  tests: fix level example
+	  Use the GValueArray in the message.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=687154
+
+2012-10-27 23:22:36 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/auparse/Makefile.am:
+	* gst/level/Makefile.am:
+	* gst/y4m/Makefile.am:
+	  gst: fix variable order in some Makefile.am
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687013
+
+2012-10-27 17:27:16 -0400  Antoine Tremblay <hexa00@gmail.com>
+
+	* ext/libcaca/Makefile.am:
+	* gst/auparse/Makefile.am:
+	* gst/level/Makefile.am:
+	* gst/videocrop/Makefile.am:
+	* gst/y4m/Makefile.am:
+	  gst: add various missing GST_PLUGINS_BASE_LIBS in Makefile.am
+	  Those plugins depend on either libgstaudio or libgstvideo,
+	  which are in gst-plugins-base.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=687013
+
+2012-10-27 13:24:24 +0100  Alexey Fisher <bug-track@fisher-privat.net>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: mark invisible VP8 frames with the DECODE_ONLY flag
+	  https://bugzilla.gnome.org/show_bug.cgi?id=654259
+
+2012-10-26 10:55:28 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/multifile.c:
+	  tests: add multifilesrc test for fix in previous commit
+	  Make sure the stop-index set is honoured.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=654853
+
+2012-10-26 10:33:03 +0100  Stas Sergeev <stsp@aknet.ru>
+
+	* gst/multifile/gstmultifilesrc.c:
+	  multifilesrc: fix stop index handling
+	  Make sure the stop index is always honoured. Avoids
+	  endless loop if one wants to read and output the same
+	  file N times, for example.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=654853
+
+2012-08-25 02:26:29 +0400  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: Support recursive SimpleTags
+	  Fixes #682644
+	  Depends on #682615
+
+2012-08-24 13:55:41 +0400  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: Expand the tag mapping.
+	  * Also expose unknown tags as key=value pairs.
+	  * Arrange tag map in the same order tags are listed in Matroska spec, leaving
+	  unmapped tags as comments.
+	  * More specific TODOs.
+	  * Remove duplicate DATE define.
+	  Fixes #682615
+	  Depends on #682524
+
+2012-10-26 10:09:39 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: Fix uninitialized variable compiler warning
+
+2012-08-23 15:07:22 +0400  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: Matroska tag TargetType support
+	  * Reads TargetType and TargetTypeValue from a Tag.
+	  * After Tag is completely read, processes taglist, substituting some of the
+	  tags depending on target type value and the presence of video/subtitle streams.
+	  * Supports reading two new simpletags - PART_NUMBER and TOTAL_PARTS
+	  Depends on #682448
+	  Fixes #682524
+
+2012-08-22 15:32:41 +0400  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: Per-track tags for Matroska
+	  Requires Matroska file to have sane layout (track info before tag info).
+	  Uses replace-merge.
+	  Makes track UIDs 64-bit.
+	  Fixes #682448
+
+2012-10-25 20:18:36 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/multifile/gstmultifilesrc.c:
+	  multifilesrc: fix typo in property description
+
+2012-10-25 12:18:03 -0700  Michael Smith <msmith@rdio.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_fourcc.h:
+	  qtdemux: read video format header fully (so we can find 'pasp' atoms) for more fourccs. Fixes aspect ratio of prores files.
+
+2012-10-25 00:44:34 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: the new get_caps already does the filter intersection
+	  It should be faster to pass the caps to intersect as the filter caps,
+	  rather than using NULL and intersecting 'manually' later.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=686837
+
+2012-10-25 00:43:51 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: avoid assertion when using accept caps query
+	  This query must receive a fixed caps, so imagefreeze should
+	  fixate its framerate before sending the query downstream.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=686837
+
+2012-10-25 12:33:24 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	  Back to feature development
+
+=== release 1.0.2 ===
+
+2012-10-25 01:01:09 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.0.2
+
+2012-10-24 13:50:00 +0200  Arnaud Vrac <avrac@freebox.fr>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: use correct type for channel-mask bitmask
+	  Fixes crash on 32-bit systems.
+
+2012-10-24 11:17:55 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Flush the ringbuffer on GAP events without duration
+	  This is required to properly start the ringbuffer and clock.
+
+2012-10-02 20:51:29 +0200  Oleksij Rempel <bug-track@fisher-privat.net>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: set DECODE_ONLY flag on invisible AltRef frames
+	  https://bugzilla.gnome.org/show_bug.cgi?id=654216
+
+2012-10-23 16:02:05 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: fix coverart extraction if vorbis comments come after picture header
+	  See sample file for bug #684701.
+
+2012-10-23 13:45:17 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: ignore bad headers if we have a valid STREAMINFO header
+	  If we run into any header parsing issues and we have a valid
+	  STREAMINFO header already, don't error out, but just stop
+	  header parsing and try to find some audio frames.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=684701
+
+2012-10-23 13:43:10 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: post proper error message and fix buffer leak on header parsing error
+	  https://bugzilla.gnome.org/show_bug.cgi?id=684701
+
+2012-10-22 22:32:49 -0700  Michael Smith <msmith@rdio.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: with raw audio, set a default channel-mask for multichannel audio. This doesn't actually parse 'chan' because it's absurdly complex.
+
+2012-10-22 15:54:17 +0200  Sebastian Rasmussen <sebrn@axis.com>
+
+	* gst/udp/gstudpsrc.c:
+	  updsrc: fix typo causing compilation error
+	  gstudpsrc.c: In function 'gst_udpsrc_create':
+	  gstudpsrc.c:365: error: 'ret' may be used uninitialized in this function
+	  https://bugzilla.gnome.org/show_bug.cgi?id=686642
+
+2012-10-22 11:55:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avi_ fix invert function
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=686550
+
+2012-10-22 11:55:22 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avi: fix debug
+
+2012-10-22 11:39:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_fourcc.h:
+	  qtdemux: add support for 'generic' samples
+	  Add support for stuffing a complete stream into 1 sample.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=686550
+
+2012-10-20 13:01:41 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: remove superfluous g_type_init() call
+	  It's deprecated in newer GLib and not needed here.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=686456
+
+2012-10-20 11:32:27 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: fix caps leak in acceptcaps function
+
+2012-10-19 19:24:23 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: don't leak gst_riff_strf_auds in case of MS/RIFF audio
+	  https://bugzilla.gnome.org/show_bug.cgi?id=681192
+
+2012-10-18 22:20:39 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: unsigned subtitle template
+
+2012-10-18 11:32:10 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: in accept_caps() check if ring buffer is NULL before de-referencing
+	  And sprinkle some thread-safety (take object lock for
+	  accessing ring buffer, and pa main loop lock for the
+	  context).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=683782
+
+2012-09-13 00:10:00 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	  videomixer2: Fix race condition where a src setcaps is ignored
+	  If both pads receive data at the same time, they will both get their
+	  sink_setcaps called which will call the src_setcaps, but there is
+	  a race condition where the second one might not be called.
+	  Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=683842
+
+2011-10-31 15:43:25 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: do not use unoffical V_MJPEG codec id
+	  Since it's not spec'ed, consider it a VfW compatibility
+	  case. Many applications (e.g. avidemux) don't understand
+	  the unofficial V_MJPEG id.
+	  Fixes #659837.
+	  Conflicts:
+	  gst/matroska/matroska-mux.c
+
+2012-10-17 17:34:26 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfdetect.c:
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  Use gst_element_class_set_static_metadata()
+	  where possible. Avoids some string copies. Also re-indent
+	  some stuff. Also some indent fixes here and there.
+
+2012-10-17 17:03:39 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngenc.c:
+	* ext/vpx/gstvp8dec.c:
+	* ext/vpx/gstvp8enc.c:
+	  jpeg, png, vpx: use gst_element_class_set_static_metadata()
+	  Avoids some string copies.
+
+2012-10-17 14:23:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	  jpegdepay: store quant tables in zigzag order
+
+2012-10-17 13:55:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtsession: fix compiler warning
+
+2012-10-17 13:35:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: clarify the ntp-sync option
+
+2012-10-17 13:15:48 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: update caps in the source
+	  Inform the source when caps changed. This was removed in the port to 1.0
+	  leaving the source unaware of the clock-rate and unable to interpollate
+	  rtp timestamps for SR packets.
+
+2012-10-17 12:46:32 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpbin: set PTS and DTS in jitterbufffer
+
+2012-10-17 12:24:22 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: disable check for ntp-sync
+	  Disable the check for the ntp-sync method. It is expected that
+	  a rather larger offset needs to be applied with this method.
+
+2012-10-17 12:17:32 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpbin: use running-time for NTP time
+	  When use-pipeline-clock is set, use the running-time of the
+	  pipeline to calculate the NTP timestamps. This method would previously
+	  only work when the base-time is set to 0 but with this change it can
+	  also work with different offsets and we can also implement pause/resume
+	  of the sender and receiver now.
+
+2012-10-17 10:20:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videocrop/gstvideocrop.h:
+	  videocrop: port to videofilter
+
+2012-10-17 09:36:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: use out_info for out properties
+
+2012-10-16 14:40:19 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videofilter/gstvideomedian.c:
+	* gst/videofilter/gstvideomedian.h:
+	  median: small cleanups
+
+2012-10-16 13:56:19 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* Makefile.am:
+	* gst/median/.gitignore:
+	* gst/median/Makefile.am:
+	* gst/median/gstmedian.c:
+	* gst/median/gstmedian.h:
+	* gst/median/median.vcproj:
+	  median: remove now that it is in videofilter
+
+2012-10-16 13:49:11 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	  configure: remove median from build
+
+2012-10-16 13:47:24 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videofilter/Makefile.am:
+	* gst/videofilter/gstvideomedian.c:
+	* gst/videofilter/gstvideomedian.h:
+	* gst/videofilter/plugin.c:
+	  videomedian: copy media to videomedian
+	  Copy the median video filter to videofilters and rename to
+	  videomedian.
+
+2012-10-16 13:12:21 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* gst/median/Makefile.am:
+	* gst/median/gstmedian.c:
+	* gst/median/gstmedian.h:
+	  media: port to 1.0
+
+2012-10-16 01:02:11 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: append palette data to paletted 8-bit RGB frames
+	  Fixes playback of 8-bit indexed RGB videos, with fixes in -base.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=686046
+
+2012-10-15 15:36:04 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: And this time fix the default target-bitrate value for real
+
+2012-10-15 15:30:33 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: Fix default target-bitrate value
+
+2012-10-13 00:03:29 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: don't assert if upstream size is not available when guessing bitrates
+	  Fixes abort in push mode where the source is not seekable and the
+	  size of the file is not available, as with
+	  cat foo.mp4 | gst-launch-1.0 playbin uri=fd://0
+	  Less noticable with releases, since we disable all
+	  g_assert() there.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=686008
+
+2012-10-12 14:38:33 -0700  Michael Smith <msmith@rdio.com>
+
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: allow more streams. Bump this constant to 32, which should be enough for real-world files.
+
+2012-10-12 14:35:24 -0700  Michael Smith <msmith@rdio.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: support more different fourcc values for other ProRes variants.
+
+2012-10-11 22:36:21 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/examples/rtp/client-H263p-AMR.sh:
+	* tests/examples/rtp/client-H263p-PCMA.sh:
+	* tests/examples/rtp/client-H263p.sh:
+	* tests/examples/rtp/client-H264-PCMA.sh:
+	* tests/examples/rtp/client-H264.sh:
+	* tests/examples/rtp/client-PCMA.c:
+	* tests/examples/rtp/client-PCMA.sh:
+	* tests/examples/rtp/server-VTS-H263p-ATS-PCMA.sh:
+	* tests/examples/rtp/server-VTS-H263p.sh:
+	* tests/examples/rtp/server-alsasrc-PCMA.sh:
+	* tests/examples/rtp/server-decodebin-H263p-AMR.sh:
+	* tests/examples/rtp/server-v4l2-H263p-alsasrc-AMR.sh:
+	* tests/examples/rtp/server-v4l2-H264-alsasrc-PCMA.sh:
+	  examples: update some element names for 1.0 in RTP examples
+	  gstrtpbin -> rtpbin
+	  ffdec_*   -> avdec_*
+	  ffenc_*   -> avenc_*
+
+2012-10-10 12:05:34 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: remove unused include
+
+2012-10-10 10:55:28 +0200  Rasmus Rohde <rohde@duff.dk>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	  multiudpsink: add multicast-iface property
+	  udpsrc already has support for setting the multicast interface, which
+	  is useful for multi-homed machines. This patch adds the same code to
+	  the multiudpsink.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=685864
+
+2012-10-10 11:32:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: don't error on send errors but only warn
+	  Don't error on send errors but simply post a warning, it's possible
+	  that the next packet will be fine.
+
+2012-10-10 10:28:24 +0200  Rasmus Rohde <rohde@duff.dk>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	  multiudpsink: add force-ipv4 option
+	  Add an option to the multiudpsink that makes it possible to force
+	  the use of an IPv4 socket.
+	  This can e.g. be used to handle the issue described in
+	  https://bugzilla.gnome.org/show_bug.cgi?id=682481
+
+2012-10-10 10:18:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	  multiudpsink: remove unused field
+
+2012-10-10 10:10:26 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: use negotiated allocator or pool
+	  Use the base class to allocate a buffer for us because it knows how
+	  to use the negotiated allocator or bufferpool.
+
+2012-10-10 10:09:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: post error when something goes wrong
+
+2012-10-10 10:09:10 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: elements post element messages
+
+2012-10-07 16:56:38 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	  Back to development (bug fixing)
+
+=== release 1.0.1 ===
+
+2012-10-07 15:31:12 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.0.1
+
+2012-10-06 14:57:10 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 6c0b52c to 6bb6951
+
+2012-10-05 15:12:27 -0700  Michael Smith <msmith@rdio.com>
+
+	* gst/interleave/deinterleave.c:
+	  deinterleave: output channels should be marked as MONO, not FRONT_LEFT, if we're not preserving input channel positions.
+
+2012-10-04 15:13:20 -0700  Michael Smith <msmith@rdio.com>
+
+	* gst/interleave/interleave.c:
+	  interleave: use gst_audio_channel_positions_to_mask instead of a local copy of half of it. Handles some values more correctly.
+
+2012-10-04 20:32:45 +0200  Rasmus Rohde <rohde@duff.dk>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	  gstrtpdepay: don't leak input buffer
+	  The rtp buffer is never unmapped in the normal code exit path
+	  of gst_rtp_gst_depay_process(..) resulting in a memory leak.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=685512
+
+2012-10-04 18:37:18 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: Add support for NV12 and NV21
+
+2012-10-01 15:11:05 +0200  Patricia Muscalu <patricia@axis.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	* tests/check/elements/rtp-payloading.c:
+	  rtph264pay: do not push unmapped data
+	  Also do not use a GstBuffer after it has been pushed into the adapter.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=685213
+
+2012-10-03 10:51:45 -0700  Michael Smith <msmith@rdio.com>
+
+	* gst/interleave/deinterleave.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/ximage/ximageutil.c:
+	  meta info: threadsafe registration using g_once
+
+2012-10-01 15:44:01 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: push mode; handle some initial junk before hdrl list
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=685059
+
+2012-10-01 14:03:19 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/icles/gdkpixbufsink-test.c:
+	  tests: port gdkpixbufsink test
+
+2012-09-29 11:59:31 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/level/gstlevel.c:
+	* tests/check/elements/videocrop.c:
+	  Purge references to liboil
+	  https://bugzilla.gnome.org/show_bug.cgi?id=673285
+
+2012-09-28 16:51:01 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/avi-ids.h:
+	* gst/avi/gstavidemux.c:
+	  avidemux: recognize all xsub frames as keyframes
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=684977
+
+2012-09-28 16:50:25 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: push mode: find the correct chunk for segment following seek
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=684977
+
+2012-09-27 22:17:49 +0100  Arnaud Vrac <rawoul@gmail.com>
+
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: fix parsing in push mode when moov atom is at the end
+	  When playing an mp4 file with the MOOV atom at the end of the file, playback
+	  fails with the error message "no 'moov' atom within the first 10 MB". This is
+	  due to a mistake in the upstream_size typing, making the seek to the end of
+	  file never happening.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=684972
+
+2012-09-27 15:50:49 -0300  Andre Moreira Magalhaes (andrunko) <andre.magalhaes@collabora.co.uk>
+
+	* gst/videofilter/gstgamma.c:
+	  gamma: remove duplicate entries at format at caps
+	  Avoids extra caps/structures processing
+
+2012-09-27 14:13:42 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  rtpvrawdepay: negotiate pool with srcpad caps
+
+2012-09-27 11:02:51 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: The convert and duration queries are not supposed to change the format
+
+2012-09-26 09:28:59 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: clear video frame more correctly
+	  Make sure not to touch memory that doesn't belong to
+	  our frame, we might be one part of a side-by-side 3D
+	  frame, or in a picture-in-picture scenario.
+
+2012-09-26 00:44:59 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: minor clean-up
+	  Use GstByteWriter, because we can, and g_value_take_boxed.
+
+2012-09-10 10:27:28 +0400  Dmitriy Samonenko <dmitriy.samonenko@teligent.ru>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: fix speex audio decoding by creating fake stream header
+	  https://bugzilla.gnome.org/show_bug.cgi?id=683622
+
+2012-09-25 21:21:15 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/videomixer/videomixer2.c:
+	* tests/check/pipelines/simple-launch-lines.c:
+	  videomixer: fix warnings when using transparent background
+	  gst_video_frame_map() increases the refcount, which makes
+	  the buffer not writable any more technically, so calling
+	  gst_buffer_memset() on it will cause nasty warnings.
+	  Unit test disabled because it very rarely (for me)
+	  fails, possibly negotiation-related.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=684398
+
+2012-09-25 10:43:28 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Add some useful debug logging
+
+2012-09-25 10:41:44 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Fix telecine
+	  This only affects behaviour in telecine cases with pattern locking
+	  enabled. The default case should be untouched.
+	  This works with the output from fieldanalysis at least, but the field
+	  order looks swapped for telecine mixed buffers with the
+	  David_slides_Schleef clip.
+
+2012-09-25 14:43:15 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: Disable GLIB deprecation warnings
+	  GValueArray has been deprecated since 2.32 ... but there's no usable
+	  replacement for it.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=667228
+
+2012-09-25 14:18:35 +0200  Edward Hervey <edward@collabora.com>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Fix leak
+
+2012-09-24 16:46:18 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	  Back to development (bug fixing)
+
+=== release 1.0.0 ===
+
+2012-09-24 14:06:42 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 1.0.0
+
+2012-09-24 11:56:56 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/rganalysis.c:
+	  tests: remove g_printerr() that's not needed any longer
+	  now that tcase_skip_broken_test() prints it as well.
+
+2012-09-23 19:50:42 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/rganalysis.c:
+	  tests: disable failing replaygain tests
+
+2012-09-23 16:31:37 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/smpte/gstsmpte.c:
+	* gst/smpte/gstsmpte.h:
+	  smpte: send stream-start event
+
+2012-09-23 16:10:36 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/multipart/multipartmux.c:
+	* gst/multipart/multipartmux.h:
+	  multipartmux: send stream-start event
+
+2012-09-23 16:02:19 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: send stream-start
+
+2012-09-23 15:57:35 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: send stream-start event
+
+2012-09-23 15:48:54 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/interleave/interleave.c:
+	* gst/interleave/interleave.h:
+	  interleave: add a bunch of FIXMEs
+	  Needs some more work, so stream-start, caps and tags are
+	  sent in the right order.
+
+2012-09-23 15:18:54 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: send stream-start event
+
+2012-09-23 15:16:14 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/avi/gstavimux.c:
+	  avimux: send stream-start event
+
+2012-09-22 15:00:27 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  rtpdtmfdepay: Use 1.0-style caps negotiation and audio/x-raw
+
+2012-09-22 16:08:05 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 4f962f7 to 6c0b52c
+
+2012-09-21 21:54:36 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: answer URI query
+	  Without this, something also answered the query
+	  with TRUE but without setting a uri, not sure
+	  what that was..
+
+2012-09-20 17:28:47 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: Make sure the caps don't have duplicated sps/pps
+
+2012-09-20 19:58:12 +0200  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: Mute stream post-connection if required
+	  A bug in PulseAudio causes PA_STREAM_START_MUTED to be rejected on
+	  record streams. Until this is fixed upstream, we mute the stream
+	  manually at startup. Based on a patch by Alban Browaeys
+	  <prahal@yahoo.com>.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=684469
+
+2012-09-20 18:00:59 -0700  Michael Smith <msmith@rdio.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: 24 bit audio here is S24LE, not S24_3LE.
+
+2012-09-20 10:07:24 +0200  Sjoerd Simons <sjoerd@luon.net>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: handle latency query before setting up the bufferpool
+	  Fixes crash if no bufferpool is set up yet.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=684430
+
+2012-09-19 09:17:03 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	  osxaudiosink: Specify endianness in IEC 61937 payloading
+	  Corresponds to an API change in gst-plugins-base. This needs to be fixed
+	  to query the expected byte order using appropriate API.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=678021
+
+2012-09-19 09:15:53 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: Specify endianness in IEC 61937 payloading
+	  DirectSound expects native endian byte order.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=678021
+
+2012-09-19 09:13:11 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Specify endianness in IEC 61937 payloading
+	  Corresponds to an API change in gst-plugins-base.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=678021
+
+2012-09-19 00:39:01 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Remove incorrect logic
+	  I don't understand why these lines were added, they don't make sense to
+	  me now and both David and I agree that removing them moves closer to
+	  related logic being correct, therefore, they're being removed.
+	  I've tested a few progressive, interlaced and telecine clips and they
+	  all behave properly timestamp-wise and visually after these changes.
+
+2012-09-19 00:17:49 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Fix field duration
+	  The frame rate fraction is correctly adjusted in the cases preceding the
+	  field duration calculation and so the factor of 2 is incorrect.
+
+2012-09-18 10:34:03 -0700  Michael Smith <msmith@rdio.com>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Fix U/V strides for a number of cases.
+
+2012-09-18 12:13:21 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: init videoinfo
+	  ... to prevent random bogus caps fields.
+
+2012-09-18 12:12:39 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: chain up to collectpads query function
+
+2012-09-17 13:17:00 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: Don't let GstCollectPad shadow custom sink pad query func
+	  In the current implementation, the custom pad query function is not called.
+	  This patch, set that query function on the GstCollectPads to avoid this
+	  shadowing.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=684237
+
+2012-09-17 18:23:11 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/files/Makefile.am:
+	  tests: dist image.jpg for jpeg test
+
+=== release 0.11.99 ===
+
+2012-09-17 17:57:58 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.11.99
+
+2012-09-17 16:53:04 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.types:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	  docs: update
+
+2012-09-17 13:30:15 +0200  Christian Fredrik Kalager Schaller <uraeus@linuxrisin.org>
+
+	* gst-plugins-good.spec.in:
+	  Fix spec file for vp8 move
+
+2012-09-17 13:23:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* Makefile.am:
+	  annodex: Add to the CRUFT_DIRS
+
+2012-09-17 12:14:07 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	  docs: update
+
+2012-09-17 09:48:56 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: Correctly finish frames
+	  Previously we would always get the same frame if multiple frames are pending,
+	  leaking memory of the previous frames and breaking timestamps.
+
+2012-09-17 09:40:41 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: Allow changing bitrate and other parameters during playback
+	  Fixes bug #648276.
+
+2012-09-17 09:16:39 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp8enc.h:
+	  vp8enc: Store configuration in the vpx_codec_enc_cfg_t struct instead of duplicating all variables
+	  Also protect encoder with a mutex.
+
+2012-09-16 16:03:06 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: Update documentation to reflect new property names
+	  ...and also link to the WebM encoder parameters website.
+
+2012-09-16 15:57:58 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vpx/gstvp8enc.c:
+	  vp8enc: Make some property names more readable
+
+2012-09-16 15:47:16 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/.gitignore:
+	  vp8: Add tests to .gitignore
+
+2012-09-16 15:46:31 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/vp8enc.c:
+	  vp8enc: Update patch to the new property names
+
+2012-09-16 15:46:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	  vpx: Integrate test into the build system too
+
+2012-02-07 17:00:26 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/vp8dec.c:
+	* tests/check/elements/vp8enc.c:
+	  [MOVED FROM BAD 6/6] tests: fix more unit tests
+
+2011-11-24 21:42:39 +0100  René Stadler <rene.stadler@collabora.co.uk>
+
+	* tests/check/elements/vp8dec.c:
+	* tests/check/elements/vp8enc.c:
+	  [MOVED FROM BAD 5/6] tests: update for gstcheck API change
+
+2010-07-10 15:46:51 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/vp8dec.c:
+	  [MOVED FROM BAD 4/6] vp8dec: Add simple unit test for vp8dec
+
+2010-07-10 15:46:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/vp8enc.c:
+	  [MOVED FROM BAD 3/6] vp8enc: Improve unit test a bit
+
+2010-07-10 15:32:29 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/vp8enc.c:
+	  [MOVED FROM BAD 2/6] vp8enc: Also check the output caps in the unit test
+
+2010-07-10 15:29:46 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/vp8enc.c:
+	  [MOVED FROM BAD 1/6] vp8enc: Add simple unit test
+
+2012-09-16 15:43:39 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-vpx.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* ext/Makefile.am:
+	  vpx: Integrate into the build system
+
+2012-09-16 15:33:57 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vpx/GstVP8Enc.prs:
+	* ext/vpx/Makefile.am:
+	* ext/vpx/gstvp8dec.c:
+	* ext/vpx/gstvp8dec.h:
+	* ext/vpx/gstvp8enc.c:
+	* ext/vpx/gstvp8enc.h:
+	* ext/vpx/gstvp8utils.c:
+	* ext/vpx/gstvp8utils.h:
+	* ext/vpx/plugin.c:
+	  vpx: Rename vp8 plugin to vpx
+	  This is using libvpx, which can support more codecs than just VP8
+	  and will likely support future codecs.
+
+2012-09-16 15:32:24 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	  vp8: Apply remaining changes that got lost while moving the plugin via git am thanks to merges
+
+2012-09-16 15:25:08 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 134/134] vp8dec: Unref input/output states when stopping the decoder
+
+2012-09-16 15:18:20 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/GstVP8Enc.prs:
+	  [MOVED FROM BAD 133/134] vp8enc: Update realtime profile to the new properties
+
+2012-09-16 10:56:07 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 132/134] vp8: Require latest libvpx release (1.1.0 from May 2012)
+	  Fixes bug #684116 and simplifies configure checks.
+
+2012-09-15 20:23:13 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 131/134] vp8enc: Use a string field for the profile in the caps
+	  Just for consistency with all the other codecs.
+
+2012-09-15 00:04:07 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 130/134] vp8enc: Correctly set profile in caps
+
+2012-09-14 23:41:48 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 129/134] vp8: Update copyright and authors
+
+2012-09-08 15:38:40 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8enc.h:
+	  [MOVED FROM BAD 128/134] vp8enc: Rework encoder properties to be more in line with the libvpx tools and API
+	  Also add all available properties.
+
+2012-09-14 17:08:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 127/134] replace gst_element_class_set_details_simple with gst_element_class_set_metadata
+
+2012-07-19 09:05:28 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 126/134] vp8dec: Call gst_video_decoder_negotiate()
+
+2012-08-14 11:17:25 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8dec.h:
+	  [MOVED FROM BAD 125/134] vp8dec: Add support for multiple decoding threads
+
+2012-08-14 11:09:46 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 124/134] vp8dec: Add support for the MFQE postprocessing flag
+	  Which is enabled by default if postprocessing is enabled.
+
+2012-08-09 13:37:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/Makefile.am:
+	  [MOVED FROM BAD 123/134] vp8: Use pkg-config file for getting the LIBS and CFLAGS
+
+2012-08-08 17:06:20 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 122/134] vp8enc: Update the per-component strides for every frame too
+	  This is necessary because of GstVideoAlignment
+
+2012-07-26 19:31:14 +0200  Oleksij Rempel <bug-track@fisher-privat.net>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 121/134] vp8enc: initiate encoder to fix a crash.
+	  Without this patch vp8enc send header before and after first
+	  key frame. On second keyframe vp8dec will crash without getting
+	  decoded frame. With this pipe it is easy to reproduce this issue:
+	  gst-launch-1.0 videotestsrc ! vp8enc ! vp8dec ! fakesink
+	  https://bugzilla.gnome.org/show_bug.cgi?id=680667
+
+2012-07-28 00:32:58 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 120/134] tag: Update for taglist/tag event API changes
+
+2012-07-23 10:35:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 119/134] ext: Update for video base classes API changes
+
+2012-07-21 19:59:21 +0200  Oleksij Rempel <bug-track@fisher-privat.net>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 118/134] vp8enc: fix memory leak
+	  unref frame. i hope it is correct place to do it.
+	  Signed-off-by: Oleksij Rempel <bug-track@fisher-privat.net>
+
+2012-07-06 11:50:53 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 117/134] update for query api changes
+
+2012-07-06 11:26:55 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 116/134] update for query api changes
+
+2012-07-06 11:03:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 115/134] update for allocation query changes
+
+2012-06-07 12:33:31 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 114/134] vp8: fix codec state leaks
+	  I only tested that vp8enc ! vp8dec does not crash, as valgrind does not grok
+	  at least one of the instructions used by vp8enc, preventing me from checking
+	  a leak, and the lack of one after the patch.
+
+2012-06-06 13:02:40 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 113/134] update for tag event change
+
+2012-05-28 16:05:21 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8enc.h:
+	  [MOVED FROM BAD 112/134] vp8: Port to 0.11 again
+
+2012-05-18 12:46:55 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 111/134] vp8enc: fix target bitrate config with libvpx 1.1.0
+	  libvpx 1.1.0 disallows a bitrate of 0, which was used by
+	  vp8enc as a default value.
+	  Instead, we use the default libvpx bitrate, scaled to our
+	  video size, if no bitrate was specified.
+	  This fixes encoding VP8 video with libvpx 1.1.0.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=676245
+
+2012-05-16 14:04:28 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 110/134] vp8enc: Update for GstVideoCodecFrame API changes
+
+2012-04-27 18:22:42 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8dec.h:
+	  [MOVED FROM BAD 109/134] vp8dec: Improve output_state handling
+	  Avoid getting output_state for every buffer as that requires
+	  getting the objectlock and doing reference counting. Store it locally
+	  when it is created and use it.
+
+2012-04-27 09:05:57 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 108/134] vp8dec: Use outputstate when copying output buffer data
+	  Using the input state was causing a crash because the strides/offsets
+	  would be wrong. Fix it by using the output as we are dealing with
+	  the decoded frame.
+
+2012-04-24 11:08:41 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 107/134] vp8: Port to -base video base classes
+	  Conflicts:
+	  ext/vp8/Makefile.am
+	  ext/vp8/gstvp8dec.c
+	  ext/vp8/gstvp8enc.c
+	  Back to 0.10 state for now, need to be ported again.
+
+2012-05-18 12:46:55 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 106/134] vp8enc: fix target bitrate config with libvpx 1.1.0
+	  libvpx 1.1.0 disallows a bitrate of 0, which was used by
+	  vp8enc as a default value.
+	  Instead, we use the default libvpx bitrate, scaled to our
+	  video size, if no bitrate was specified.
+	  This fixes encoding VP8 video with libvpx 1.1.0.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=676245
+
+2012-04-05 18:02:56 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/plugin.c:
+	  [MOVED FROM BAD 105/134] gst: Update for GST_PLUGIN_DEFINE() API changes
+
+2012-04-04 14:41:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/Makefile.am:
+	  [MOVED FROM BAD 104/134] gst: Update versioning
+
+2012-03-06 15:21:17 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 103/134] vp8enc: Fix 'argument to 'sizeof' in 'memset' call is the same expression as the destination' compiler warning
+
+2012-01-30 17:17:16 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 102/134] update for HEADER flag
+
+2012-01-25 18:49:58 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 101/134] port some more to new memory API
+	  Fixes #668677.
+
+2012-01-24 11:22:46 +0100  Oleksij Rempel (Alexey Fisher) <bug-track@fisher-privat.net>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 100/134] vp8enc: trace outgoing timestamps
+	  add info level prints for outgoing timestamps.
+	  Signed-off-by: Oleksij Rempel (Alexey Fisher) <bug-track@fisher-privat.net>
+
+2012-01-04 11:05:48 +0100  Oleksij Rempel (Alexey Fisher) <bug-track@fisher-privat.net>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 099/134] vp8dec: use is_alt_data option to prevent timestamp collisions
+	  altref/invisible frames usually stored in container with same timestamp as
+	  dependet frame. This make basevideodecoder to update timestamp for dependet
+	  frame and couse TS colision on next frame:
+	  ^- here is altref
+	  time     : 1 2 3 4 5 6 7 8 9
+	  webm ts  : 1   3 5 5   7   9
+	  vp8dec ts: 1   3   7   7   9
+	  Fix bug: https://bugzilla.gnome.org/show_bug.cgi?id=655245
+	  Signed-off-by: Oleksij Rempel (Alexey Fisher) <bug-track@fisher-privat.net>
+
+2012-01-02 08:28:13 +0100  Oleksij Rempel (Alexey Fisher) <bug-track@fisher-privat.net>
+
+	* ext/vp8/GstVP8Enc.prs:
+	* ext/vp8/Makefile.am:
+	  [MOVED FROM BAD 098/134] vp8: add initial preset file
+	  This is initial preset file, currently with only one profile
+	  for realtime encoding.
+	  Signed-off-by: Oleksij Rempel (Alexey Fisher) <bug-track@fisher-privat.net>
+
+2011-11-28 13:08:27 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 097/134] various: fix pad template ref leaks
+	  https://bugzilla.gnome.org/show_bug.cgi?id=662664
+
+2011-11-25 11:36:14 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 096/134] vp8dec: use new basevideodecoder API to drop frames and get QoS messages posted
+
+2011-11-10 15:13:34 +0200  Mart Raudsepp <leio@gentoo.org>
+
+	* ext/vp8/Makefile.am:
+	  [MOVED FROM BAD 095/134] mimic, opencv, vp8, acmmp3dec, linsys: Don't build static plugins
+	  Pass --tag=disable-static to libtool everywhere where it's been forgotten
+	  https://bugzilla.gnome.org/show_bug.cgi?id=663768
+
+2011-11-03 14:01:41 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 094/134] vp8: Port to 0.11
+
+2011-08-21 20:15:25 -0700  David Schleef <ds@schleef.org>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 093/134] vp8enc: fix drop-frame property
+	  Fixes #656929.
+
+2011-08-19 19:17:15 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8enc.h:
+	  [MOVED FROM BAD 092/134] vp8: probe for the new tuning API to keep building with older libvpx
+	  https://bugzilla.gnome.org/show_bug.cgi?id=656928
+
+2011-08-18 10:39:26 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 091/134] vp8enc: Remove unused and useless variable in tags handling
+
+2011-08-12 12:08:08 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 090/134] vp8enc: Update for basevideoencoder ::get_caps() removal
+
+2011-07-09 18:53:24 -0700  David Schleef <ds@schleef.org>
+
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8enc.h:
+	  [MOVED FROM BAD 089/134] vp8enc: Add more properties
+
+2011-06-19 16:06:46 +0200  Alexey Fisher <bug-track@fisher-privat.net>
+
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8enc.h:
+	  [MOVED FROM BAD 088/134] vp8enc: add min/maxsection-pct option
+	  This options should be good to redeuce decode CPU load.
+	  for lowend hardware:
+	  minsection-pct=15 maxsection-pct=400
+	  for hiend hw:
+	  minsection-pct=5 maxsection-pct=800
+	  see example:
+	  http://www.webmproject.org/tools/encoder-parameters/#2-pass_vbr_encoding_for_smooth_playback_on_low-end_hardware
+	  Signed-off-by: Alexey Fisher <bug-track@fisher-privat.net>
+	  Signed-off-by: David Schleef <ds@schleef.org>
+
+2011-06-19 11:05:36 +0200  Alexey Fisher <bug-track@fisher-privat.net>
+
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8enc.h:
+	  [MOVED FROM BAD 087/134] vp8enc: add lag-in-frames option.
+	  This option set maximum of frames codec should remember,
+	  to make better prediktion for alt-ref frames.
+	  See example:
+	  http://www.webmproject.org/tools/encoder-parameters/#2-pass_best_quality_vbr_encoding
+	  Signed-off-by: Alexey Fisher <bug-track@fisher-privat.net>
+	  Signed-off-by: David Schleef <ds@schleef.org>
+
+2011-06-19 07:16:57 +0200  Alexey Fisher <bug-track@fisher-privat.net>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 086/134] vp8enc: use multipass.cache file name as default for multipass mode.
+	  Signed-off-by: Alexey Fisher <bug-track@fisher-privat.net>
+	  Signed-off-by: David Schleef <ds@schleef.org>
+
+2011-07-21 08:03:51 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 085/134] vp8enc: Update for GstBaseVideoEncoder::finish() signature change
+
+2011-07-12 18:05:25 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 084/134] vp8: Fix set-but-unused warnings
+
+2011-07-09 11:31:02 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 083/134] vp8enc: Use destroy notify to free the coder hook
+
+2011-06-18 15:56:49 -0700  David Schleef <ds@schleef.org>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 082/134] vp8enc: update for new libvpx api
+
+2011-06-26 15:15:54 +0200  Alexey Fisher <bug-track@fisher-privat.net>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 081/134] vp8enc: generate a timestamp for alt-ref frames.
+	  It will fix handling of altref/invisible frames since matroska-mux
+	  drop any fram with no timestamp.
+	  see also:
+	  http://www.webmproject.org/code/specs/container/
+	  The encoder will currently set the AR's timestamp as close as possible
+	  to the previous frame while attempting to provide a timestamp that is
+	  strictly increasing. In cases where the time base given to the encoder
+	  at configure time is not granular enough to allow for this the AR
+	  will share the same timestamp as D, but should be
+	  treated as having no duration.
+	  Fixes bug #652951
+	  Signed-off-by: Alexey Fisher <bug-track@fisher-privat.net>
+
+2011-06-18 17:47:36 +0200  Alexey Fisher <bug-track@fisher-privat.net>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 080/134] vp8dec: add check if we have legal aspect-ratio before reset it.
+	  the commit f9b552f0494e (vp8dec: set par to 1/1)
+	  will fix situation where no aspect-ratio is set, but it brake
+	  stream with available aspect-ratio. This patch fix it.
+	  Fixes: #652902.
+	  Signed-off-by: Alexey Fisher <bug-track@fisher-privat.net>
+
+2011-06-03 19:36:59 -0700  David Schleef <ds@schleef.org>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 079/134] vp8dec: set par to 1/1
+
+2011-05-18 13:27:20 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 078/134] vp8enc: Name max/min quantizer properties {max,min}-quantizer
+	  Also improve quality property description.
+
+2011-05-18 13:26:23 +0200  Alexey Fisher <bug-track@fisher-privat.net>
+
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8enc.h:
+	  [MOVED FROM BAD 077/134] vp8enc: Add properties to select a maximum and minimum quantizer
+	  Fixes bug #641405.
+
+2011-05-18 13:18:58 +0200  Alexey Fisher <bug-track@fisher-privat.net>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 076/134] vp8enc: Fix quality to (constant) quantizer mapping
+	  This now allows to select all possible quantizers between
+	  0 and 63.
+	  See bug #641405.
+
+2011-04-01 22:13:55 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 075/134] vp8dec: debug code style fixes
+
+2011-04-01 22:13:00 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 074/134] vp8dec: propagate downstream flow return to upstream
+
+2011-03-30 10:18:23 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 073/134] basevideodecoder: really and only set src pad caps whenever requested
+	  ... since subclass is expected to be wise enough to know when to do so.
+
+2011-03-29 10:41:54 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 072/134] basevideodecoder: invoke subclass start method at state change and use set_format
+	  While this changes API slightly (e.g. actually uses set_format now), which is OK
+	  for unstable API, it has following merits:
+	  * symmetric w.r.t. stop at state change
+	  * in line with other base class practice
+	  * otherwise no subclass method at state change (global activation time)
+	  Moreover, subclassese are either unaffected or trivially adjusted accordingly.
+
+2011-03-28 08:59:20 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 071/134] basevideodecoder: subsume skip_frame into finish_frame
+
+2011-03-24 14:10:07 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 070/134] basevideoencoder: provide proper upstream flow return handling
+
+2011-03-24 13:59:35 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8enc.h:
+	  [MOVED FROM BAD 069/134] vp8enc: minor optimization in setting up image buffer
+
+2011-03-24 12:50:23 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 068/134] vp8enc: refactor frame processing
+
+2011-03-24 11:55:41 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 067/134] vp8enc: do init at set_format time
+
+2011-03-24 10:15:55 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8enc.h:
+	  [MOVED FROM BAD 066/134] vp8enc: fix keyframe forcing
+
+2011-03-23 09:45:20 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 065/134] basevideocodec: remove redundant caps field
+	  ... as it is already at hand as the src pad's negotiated caps.
+
+2011-03-23 08:50:31 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8enc.h:
+	  [MOVED FROM BAD 064/134] vp8enc: use baseclass event virtual handler
+
+2011-02-20 14:16:18 -0800  David Schleef <ds@schleef.org>
+
+	* ext/vp8/gstvp8dec.h:
+	* ext/vp8/gstvp8enc.h:
+	  [MOVED FROM BAD 063/134] basevideo: merge utils header into basevideocodec
+
+2011-03-17 16:34:02 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/vp8/Makefile.am:
+	  [MOVED FROM BAD 062/134] vp8: fix LIBADD order in Makefile.am
+
+2011-02-04 09:08:26 +0100  Alexey Fisher <bug-track@fisher-privat.net>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 061/134] vp8enc: Add description for bitrate units.
+
+2010-11-30 18:43:24 -0800  David Schleef <ds@schleef.org>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 060/134] vp8enc: Readd setting of granulepos
+	  Revert parts of last patch that removed setting of granulepos.
+	  oggmux still requires correct granulepos in incoming packet.
+
+2010-11-29 20:21:31 -0800  David Schleef <ds@schleef.org>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 059/134] vp8enc: Don't override timestamps set by base class
+	  Because the base class does it correctly.
+	  Fixes: #635720, #625558.
+
+2010-11-25 18:52:47 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 058/134] vp8: Remove dead assignments
+
+2010-10-09 17:36:07 -0700  David Schleef <ds@schleef.org>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 057/134] basevideo: Move common fields/functions to basecodec
+
+2010-09-18 17:28:48 -0700  David Schleef <ds@schleef.org>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 056/134] basevideo: Move deadline to frame structure
+
+2010-08-13 14:34:21 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 055/134] vp8dec: Set GstBaseVideoDecoder::packetized to TRUE as soon as possible
+	  This fixes an infinite loop if an EOS event is received before
+	  GstBaseVideoDecoder::start() is called, e.g. immediately when the
+	  pads are activated.
+	  Fixes bug #626815.
+
+2010-07-10 16:52:10 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8enc.h:
+	  [MOVED FROM BAD 054/134] vp8enc: Add support for enabling automatic insertion of alt-ref frames by the encoder
+
+2010-07-10 16:51:53 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 053/134] vp8enc: Fix handling of invisible/alt ref frames
+
+2010-07-03 17:47:29 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8dec.h:
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8enc.h:
+	  [MOVED FROM BAD 052/134] vp8: Add initial documentation, based on the theoradec/theoraenc documentation
+
+2010-07-03 17:34:58 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/Makefile.am:
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8dec.h:
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8enc.h:
+	* ext/vp8/plugin.c:
+	  [MOVED FROM BAD 051/134] vp8: Move structure definitions, etc to public header files for gtk-doc
+
+2010-06-12 09:02:29 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 050/134] vp8enc: Implement multipass encoding
+	  Fixes bug #621348.
+
+2010-06-14 15:56:24 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 049/134] vp8enc: Set VP8E_SET_CPUUSED to 0
+	  This setting controls how much CPU can be used by the encoder, specified
+	  in fractions of 16. Negative values mean strict enforcement of this
+	  while positive values are adaptive.
+	  The default value is -4, which means that we're not running as fast
+	  as possible and probably are wasting some quality. 0 is the recommended
+	  default by libvpx upstream.
+
+2010-06-14 15:51:30 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 048/134] vp8enc: Use VPX defines for REALTIME, GOOD/BEST quality deadlines instead of our own
+	  These are the values used for the speed property.
+
+2010-06-03 10:49:40 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 047/134] vp8enc: fix printf format warning in log message
+	  gstvp8enc.c:564: error: format ‘%d’ expects type ‘int’, but argument 8 has type ‘size_t’
+	  gstvp8enc.c:744: error: format ‘%d’ expects type ‘int’, but argument 8 has type ‘size_t’
+
+2009-07-03 16:08:38 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/vp8/Makefile.am:
+	  [MOVED FROM BAD 046/134] basevideo, vp8: guard unstable API with GST_USE_UNSTABLE_API
+	  Add some guards and fat warnings to the header files with still unstable
+	  API, so people who just look at the installed headers know that it
+	  actually is unstable API.
+	  Merging previous commit into current codebase.
+
+2010-06-01 15:54:51 -0700  David Schleef <ds@schleef.org>
+
+	* ext/vp8/Makefile.am:
+	* ext/vp8/gst/video/gstbasevideocodec.c:
+	* ext/vp8/gst/video/gstbasevideocodec.h:
+	* ext/vp8/gst/video/gstbasevideodecoder.c:
+	* ext/vp8/gst/video/gstbasevideodecoder.h:
+	* ext/vp8/gst/video/gstbasevideoencoder.c:
+	* ext/vp8/gst/video/gstbasevideoencoder.h:
+	* ext/vp8/gst/video/gstbasevideoparse.c:
+	* ext/vp8/gst/video/gstbasevideoparse.h:
+	* ext/vp8/gst/video/gstbasevideoutils.c:
+	* ext/vp8/gst/video/gstbasevideoutils.h:
+	* ext/vp8/gst/video/gstvideocompat.c:
+	* ext/vp8/gst/video/gstvideocompat.h:
+	  [MOVED FROM BAD 045/134] basevideo: Move base video from vp8 to gst-libs
+
+2010-05-26 06:52:15 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8utils.h:
+	  [MOVED FROM BAD 044/134] vp8: Use VPX_PLANE_* instead of PLANE_*
+
+2010-05-24 11:04:02 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8utils.h:
+	  [MOVED FROM BAD 043/134] vp8: Add compatilibity defines to work with older versions of libvpx too
+
+2010-05-23 09:28:13 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 042/134] vp8dec: s/IMG_FMT_I420/VPX_IMG_FMT_I420/
+	  This corresponds to upstream libvpx commit 6cd4a10e167203d1deb79abf60ee72599e97891b
+
+2010-05-22 12:55:45 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 041/134] vp8enc: Allow a maximum keyframe distance of 0, i.e. all frames are keyframes
+
+2010-05-22 08:45:35 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 040/134] vp8dec: Set decoder deadline from the QoS information
+
+2010-05-28 16:35:12 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 039/134] vp8enc: Move debug output one line above where the packet is still valid
+
+2010-05-28 15:53:30 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 038/134] vp8enc: Correctly ignore non-frame packets from the encoder
+	  Fixes bug #619916.
+
+2010-05-22 07:44:27 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gst/video/gstbasevideodecoder.c:
+	  [MOVED FROM BAD 037/134] basevideodecoder: Take the frame duration into account when calculating the earliest time
+	  This formula is used in many other elements too.
+	  Fixes bug #619318.
+
+2010-05-22 07:35:01 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gst/video/gstbasevideodecoder.c:
+	  [MOVED FROM BAD 036/134] basevideodecoder: Reset QoS values when necessary
+
+2010-05-22 09:35:24 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 035/134] vp8enc: Use GST_VIDEO_CAPS_YUV(I420) instead of handwritten I420 caps for the pad template
+	  Fixes bug #619344.
+
+2010-05-21 20:53:36 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* ext/vp8/gst/video/gstbasevideodecoder.c:
+	* ext/vp8/gst/video/gstbasevideodecoder.h:
+	* ext/vp8/gst/video/gstbasevideoutils.h:
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 034/134] vp8dec: drop late frames after decoding them
+	  This saves a memcpy, which is always something.
+
+2010-05-21 21:28:29 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 033/134] vp8enc: threads property
+	  Increasing from 1 to 2 threads on an Thinkpad X60s decreased encode time
+	  in a test from ~24 s to ~19 s, so this is quite useful.
+	  Ideally we should let 0 be the default and automatically match the number
+	  of CPU cores (or something).
+
+2010-05-21 15:17:46 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 032/134] vp8enc: add mode property to switch between CBR/VBR
+	  Always using CBR when bitrate is used isn't that great, VBR mode
+	  can produce meaningful results too.
+
+2010-05-21 10:54:57 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 031/134] vp8dec: Only enable postprocessing if the decoder supports it
+
+2010-05-21 08:23:58 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* ext/vp8/plugin.c:
+	  [MOVED FROM BAD 030/134] vp8: typo: s/HAVE_VP8_DECODER/HAVE_VP8_ENCODER/
+	  Fixup for bug #619172.
+
+2010-05-21 08:13:06 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 029/134] vp8: move #ifdef HAVE_VP8_ENCODER/DECODER
+	  Otherwise we'll try including e.g. <vpx/vp8cx.h> which doesn't exist.
+
+2010-05-20 20:06:09 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 028/134] vp8enc: Write GStreamer element and version in the vorbiscomment vendor string
+
+2010-05-20 16:49:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/plugin.c:
+	  [MOVED FROM BAD 027/134] vp8: Only enable the encoder or decoder if it's available in libvpx
+	  Fixes bug #619172.
+
+2010-05-20 10:19:54 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/plugin.c:
+	  [MOVED FROM BAD 026/134] vp8: exlcude dec/enc based on CONFIG_VP8_DECODER/ENCODER
+	  This may not be very autotoolish, but works with libvpx in the state
+	  that libvpx is actually in. Moved the debug init to the elements
+	  themselves to minimize amount of #ifdefs
+
+2010-05-20 09:24:53 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 025/134] vp8enc: Limit max-latency to 25 to match libvpx
+	  From libvpx/vp8/encoder/onyx_int.h:
+	  #define MAX_LAG_BUFFERS (CONFIG_REALTIME_ONLY? 1 : 25)
+	  While we don't need to be tied to what libvpx does internally, it
+	  doesn't make sense to pretend to support longer frame lags than are
+	  actually possible.
+
+2010-05-20 09:56:25 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8utils.c:
+	  [MOVED FROM BAD 024/134] vp8: Undef HAVE_CONFIG_H before including libvpx headers
+	  A public libvpx header includes private headers if this is
+	  defined, causing compilation failures because the private headers
+	  are not installed of course.
+
+2010-05-20 08:53:12 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 023/134] vp8enc: Some more minor adjustments for the Ogg mapping
+
+2010-05-19 23:02:19 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 022/134] vp8dec: Fix memory leak
+
+2010-05-19 21:34:42 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 021/134] vp8enc: Adjust Ogg mapping for the changes
+
+2010-05-19 18:12:18 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 020/134] vp8dec: Add properties to control the VP8 decoder post processing feature
+	  This is disabled by default for now.
+
+2010-05-19 17:16:54 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 019/134] vp8enc: Rename keyframe-interval to max-keyframe-distance
+	  And use default settings for buffer sizes until we expose this
+	  somehow.
+
+2010-05-19 17:13:17 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/Makefile.am:
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/gstvp8utils.c:
+	* ext/vp8/gstvp8utils.h:
+	  [MOVED FROM BAD 018/134] vp8: Improve error handling and debug output
+
+2010-05-19 14:46:48 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 017/134] vp8: Use correct strides and plane offsets for GStreamer
+
+2010-05-18 14:47:54 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 016/134] vp8enc: Implement GstTagSetter interface
+
+2010-05-18 14:33:49 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 015/134] vp8enc: Fix setting of the keyframe flag on encoded frames
+
+2010-05-18 14:30:15 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 014/134] vp8enc: Post an error message on the bus if encoder initialization fails
+
+2010-05-18 14:28:55 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 013/134] vp8dec: Fix memory leaks and fail if initializing the decoder fails
+
+2010-05-18 02:44:54 -0700  David Schleef <ds@schleef.org>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 012/134] vp8enc: Set timebase
+	  Also misc cleanup.
+
+2010-05-16 10:36:12 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 011/134] vp8dec: Fix decoding of invisible frames
+
+2010-05-14 14:26:34 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 010/134] vp8enc: Update the latency when initializing the encoder
+
+2010-05-14 14:02:53 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 009/134] vp8dec: Correctly initialize stream info before peeking at the stream
+	  Otherwise peeking will fail and we'll get invalid values
+
+2010-05-14 11:01:29 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 008/134] vp8dec: Make sure to pass a keyframe as first frame to the decoder, copy output frames only once and require width/height/etc on the input caps
+
+2010-05-14 10:30:18 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 007/134] vp8enc: Add support for invisible frames and the Ogg mapping
+
+2010-05-14 01:14:46 -0700  David Schleef <ds@schleef.org>
+
+	* ext/vp8/gstvp8dec.c:
+	  [MOVED FROM BAD 006/134] vp8dec: Fix reset after seeking
+	  Also remove some unused code.
+
+2010-05-13 21:19:32 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 005/134] vp8enc: Set frame numbers as buffer offsets
+
+2010-05-13 21:18:08 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 004/134] vp8enc: Always get as many frames as possible from the encoder
+
+2010-05-13 21:08:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 003/134] vp8enc: Fill the oldest pending frame instead of the newest
+
+2010-05-13 20:20:32 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/vp8/gstvp8enc.c:
+	  [MOVED FROM BAD 002/134] vp8enc: Correctly set delta unit flag for non-keyframes
+
+2010-05-13 01:04:04 -0700  David Schleef <ds@schleef.org>
+
+	* ext/vp8/Makefile.am:
+	* ext/vp8/gst/video/gstbasevideocodec.c:
+	* ext/vp8/gst/video/gstbasevideocodec.h:
+	* ext/vp8/gst/video/gstbasevideodecoder.c:
+	* ext/vp8/gst/video/gstbasevideodecoder.h:
+	* ext/vp8/gst/video/gstbasevideoencoder.c:
+	* ext/vp8/gst/video/gstbasevideoencoder.h:
+	* ext/vp8/gst/video/gstbasevideoparse.c:
+	* ext/vp8/gst/video/gstbasevideoparse.h:
+	* ext/vp8/gst/video/gstbasevideoutils.c:
+	* ext/vp8/gst/video/gstbasevideoutils.h:
+	* ext/vp8/gst/video/gstvideocompat.c:
+	* ext/vp8/gst/video/gstvideocompat.h:
+	* ext/vp8/gstvp8dec.c:
+	* ext/vp8/gstvp8enc.c:
+	* ext/vp8/plugin.c:
+	  [MOVED FROM BAD 001/134] vp8: Add encoder/decoder
+
+2012-09-15 22:16:52 +0200  Christian Fredrik Kalager Schaller <uraeus@linuxrisin.org>
+
+	* gst-plugins-good.spec.in:
+	  Update spec file with F18 name change and add deinterlacer
+
+2012-09-15 19:06:06 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	  use gst_element_factory_get_metadata to replace obsolete API
+
+2012-09-14 17:55:16 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	  replace _get_caps_reffed with _get_caps
+
+2012-09-14 17:08:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  replace gst_element_class_set_details_simple with gst_element_class_set_metadata
+
+2012-09-14 17:07:26 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngenc.c:
+	* tests/check/elements/qtmux.c:
+	  replace gst_element_class_set_details_simple with gst_element_class_set_metadata
+
+2012-09-14 13:30:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	* gst/multipart/multipartmux.c:
+	* gst/rtp/README:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/y4m/gsty4mencode.c:
+	* tests/examples/equalizer/demo.c:
+	* tests/examples/rtp/server-VTS-H263p-ATS-PCMA.sh:
+	* tests/examples/rtp/server-VTS-H263p.sh:
+	* tests/examples/rtp/server-decodebin-H263p-AMR.sh:
+	* tests/examples/rtp/server-v4l2-H263p-alsasrc-AMR.sh:
+	* tests/examples/rtp/server-v4l2-H264-alsasrc-PCMA.sh:
+	* tests/examples/shapewipe/shapewipe-example.c:
+	* tests/examples/v4l2/camctrl.c:
+	* tests/icles/gdkpixbufsink-test.c:
+	  fix more caps
+
+2012-09-14 02:57:44 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* configure.ac:
+	  Back to development
+
+=== release 0.11.94 ===
+
+2012-09-14 02:48:43 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ChangeLog:
+	* configure.ac:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.11.94
+
+2012-09-14 01:50:44 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: update translations
+
+2012-09-14 01:46:14 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	  docs: update docs
+
+2012-09-14 00:47:38 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/wavpackenc.c:
+	  tests: push stream-start and segment events in wavpackenc test
+
+2012-09-13 10:56:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	  v4l2: remove unused properties
+
+2012-09-13 10:15:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: disable reconfigure
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=683902
+
+2012-09-10 22:09:59 -0700  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Don't treat every custom-downstream event as EOS
+	  Don't fall through to the EOS handling after receiving a
+	  custom-downstream event.
+
+2012-09-12 21:05:44 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/cairo/gsttextoverlay.c:
+	* gst/avi/gstavimux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/interleave/interleave.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/multipart/multipartmux.c:
+	* gst/smpte/gstsmpte.c:
+	* gst/videomixer/videomixer2.c:
+	  collectpads: remove gst_collect_pads_add_pad_full
+	  Rename gst_collect_pads_add_pad_full() to gst_collect_pads_add_pad() and fix all
+	  invocations.
+
+2012-09-12 17:14:46 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  udp: add include for IPPROTO_*
+
+2012-09-12 16:39:08 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  udp: properly match braces and cpp directives
+	  Fixes compilation where IPV6_TCLASS not defined.
+
+2012-09-12 14:42:07 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  shapewipe: Use default query handler where needed
+	  And clean up get_caps code while I'm at it
+
+2012-09-12 13:28:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: improve framerate transform
+	  Handle G_MAXINT in the framerates better. If we cannot double or divide the
+	  framerate, clamp to the smallest/largest possible value we can express instead
+	  of failing.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=683861
+
+2012-09-12 13:17:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: small cleanup
+
+2012-09-07 17:20:57 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/videomixer/blend.c:
+	* gst/videomixer/blend.h:
+	* gst/videomixer/videomixer2.c:
+	  videomixer2: Adding nv12 and nv21 support
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=683841
+
+2012-09-12 10:18:53 +0200  Michael Smith <msmith@rdio.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_fourcc.h:
+	  qtdemux: add support for prores
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=683839
+
+2012-09-12 00:16:31 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/rganalysis.c:
+	  tests: fix most of the rganalysis unit tests
+	  Before the element would post messages on the bus itself, now
+	  the sinks do that based on the tag events they receive. But
+	  since we don't have proper sink elements in these unit tests,
+	  but just dangling pads, we have to post the tag messages the
+	  test checks for ourselves.
+	  Down from 52/55 failing to 7/52 failing.
+
+2012-09-11 17:36:51 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	* gst/avi/gstavidemux.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/wavparse/gstwavparse.c:
+	  ext, gst: only activate in pull mode if upstream is seekable
+
+2012-09-11 15:38:23 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: disable renegotiation
+	  We can't yet wait for the bufferpool to DRAIN before starting renegotiation so
+	  disable it for now.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=682770
+
+2012-09-11 12:48:39 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/rtpbin.c:
+	  tests: rtpbin: port to the new GLib thread API
+
+2012-09-11 12:36:56 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/directsound/gstdirectsoundsink.h:
+	  directsoundsink: port to the new GLib thread API
+
+2012-09-11 11:59:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: don't reset segment
+	  Don't reset the segment because we need the values for accumulation. the segment
+	  is reset at start and after a flushing seek. Fixes some problems with files with
+	  quicktime segments.
+
+2012-09-10 17:14:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/id3demux.c:
+	  tests: fix id3demux test
+
+2012-09-10 14:31:02 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/amfdefs.h:
+	* gst/flv/gstflvdemux.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	  gst: adjust comment style
+
+2012-09-10 14:30:42 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: remove defunct commented code
+
+2012-09-10 13:35:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: consider stream alive when not connected yet
+	  When we start and renegotiate, there is a moment where the stream is created but
+	  not yet connected. Make sure all functions deal with this situation correctly
+	  instead of erroring out.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=681247
+
+2012-09-10 12:15:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: don't fail when not negotiated yet
+	  When get_time is called but we are not yet negotiated, return 0 instead of
+	  posting an error. It's possible that the base class is still negotiating when
+	  our get_time is called.
+
+2012-09-10 11:32:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	* sys/oss/gstosssrc.c:
+	* sys/oss4/oss4-source.c:
+	  update for audio base src api change
+
+2012-09-10 00:42:52 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/avi/gstavimux.c:
+	* gst/isomp4/qtdemux.c:
+	  video/x-3ivx and video/x-xvid -> video/mpeg,mpegversion=4
+	  If it ever turns out that we really must use thoe specific
+	  fourccs and not the generic one, we can still add a flavor
+	  field to the caps later.
+
+2012-09-07 16:15:42 +0200  Daniela <daniela.muzzu@selexelsag.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: avoid leak
+	  When setup fails, make sure to cleanup afterwards.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=673509
+
+2012-09-07 15:23:44 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpamrdepay.c:
+	  rtpamrdepay: unmap rtp buffer
+	  ... thereby plugging a memleak.
+
+2012-09-07 14:13:17 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/rtp-payloading.c:
+	  tests: rtp-payloading: adjust to modified bufferlist semantics
+	  ... now implemented by buffer memory blocks.
+
+2012-09-07 14:11:39 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: avoid crashing on NULL access in debug message
+
+2012-09-07 14:11:02 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph263ppay.c:
+	  rtph263ppay: plug caps leak
+
+2012-09-06 17:09:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: remove redundant _set_allocation call
+
+2012-09-06 17:05:00 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/deinterlace.c:
+	  tests: deinterlace: do not leak deinterlace pads
+
+2012-09-06 17:04:39 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: plug some leaks
+
+2012-09-06 16:49:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: reuse core function for GCD
+
+2012-09-06 16:31:00 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: support filter in getcaps
+
+2012-09-06 16:30:44 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: do not leak getcaps result
+
+2012-09-06 16:23:28 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  deinterlace: add support for bufferpool
+	  Add bufferpool support to avoid a memcpy in the videosink when actively
+	  interlacing.
+	  Remove some commented obsolete code.
+
+2012-09-06 13:38:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: proxy allocation query in passthrough
+	  We can let the allocation query pass when we are operating in passthrough mode.
+
+2012-09-06 13:23:46 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: use default event functions
+	  instead of blindly forwarding unknown events.
+
+2012-09-06 13:23:30 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: small cleanups
+
+2012-09-06 12:56:30 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: call default query handlers
+	  Call the default query handler instead of forwarding the query blindly. Fixes
+	  issues of strides because of proxying the allocation query wrongly.
+
+2012-09-06 10:42:21 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: remove unused code.
+
+2012-09-06 10:42:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulse: improve debug
+
+2012-09-05 11:50:05 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: remove obsolete update newsegment handling code
+
+2012-09-04 12:35:53 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: avoid deadlock
+	  _update_properties takes the object lock and should not be called when the
+	  object lock is already taken.
+
+2012-09-03 12:46:03 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: extract interlaced-ness of video track from interlace-mode field
+	  instead of the old boolean "interlaced" field.
+
+2012-09-03 02:51:24 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/avi/gstavimux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* tests/check/elements/avimux.c:
+	  video/x-xvid -> video/mpeg,mpegversion=4
+
+2012-09-02 02:50:50 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	  text/plain + text/x-pango-markup -> text/x-raw
+
+2012-09-02 01:31:53 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* gst/matroska/matroska-demux.c:
+	  gst_message_new_duration -> gst_message_new_duration_changed
+
+2012-08-30 22:07:24 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: also stop probatation on existing sources
+	  Receiving an RTCP packet should also stop probation on sources we have seen
+	  before.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=683065
+
+2012-08-22 16:36:21 -0700  Aleix Conchillo Flaque <aleix@oblong.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtp: make rtp packet probation configurable (bug #682512)
+
+2012-08-30 12:21:01 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	  gdkpixbuf: adjust to modified video overlay composition API
+
+2012-08-30 11:30:01 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: fixup 0.11 port of suspect frame checking
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=682959
+
+2012-08-28 18:56:19 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: avoid invalid H264 bytestream codec_data
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=681369
+
+2012-08-28 19:00:44 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: port segment event creation to 0.11
+
+2012-08-28 16:28:13 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: release extra event ref when replacing pending newsegment event
+
+2012-07-03 17:50:24 +0200  David Corvoysier <david.corvoysier@orange.com>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_dump.c:
+	* gst/isomp4/qtdemux_dump.h:
+	* gst/isomp4/qtdemux_fourcc.h:
+	* gst/isomp4/qtdemux_types.c:
+	  isomp4: add DASH tfdt box support
+	  MPEG DASH has defined a set of new boxes to specify duration, indexes and
+	  offsets of ISOBMFF fragments.
+	  The Track Fragment Base Media Decode Time (tfdt) Box can in particular be
+	  included inside a traf box to specify the absolute decode time, measured on the
+	  media timeline, of the first sample in decode order in the track fragment.
+	  This information can be used by the isomp4 demux to find out the current position of
+	  an MP4 fragment in the timeline.
+	  This patch adds code to isomp4 to:
+	  - parse the tfdt box
+	  - adjust the time/position member of the new segment sent when playback starts
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=677535
+
+2012-08-26 22:39:55 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/aalib/gstaasink.c:
+	* ext/cairo/gstcairorender.c:
+	* ext/cairo/gsttextoverlay.c:
+	* ext/cairo/gsttimeoverlay.c:
+	* ext/dv/gstdvdec.c:
+	* ext/dv/gstdvdemux.c:
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflactag.c:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	* ext/gdk_pixbuf/pixbufscale.c:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/libcaca/gstcacasink.c:
+	* ext/libpng/gstpngdec.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	* ext/soup/gstsouphttpclientsink.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	* ext/taglib/gstapev2mux.cc:
+	* ext/taglib/gstid3v2mux.cc:
+	* ext/wavpack/gstwavpackdec.c:
+	* ext/wavpack/gstwavpackenc.c:
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalphacolor.c:
+	* gst/apetag/gstapedemux.c:
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audioinvert.c:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/audiofx/audiopanorama.c:
+	* gst/audiofx/audiowsincband.c:
+	* gst/audiofx/audiowsinclimit.c:
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavisubtitle.c:
+	* gst/cutter/gstcutter.c:
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/debugutils/gsttaginject.c:
+	* gst/debugutils/progressreport.c:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstop.c:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstripple.c:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gststreak.c:
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstwarp.c:
+	* gst/equalizer/gstiirequalizer10bands.c:
+	* gst/equalizer/gstiirequalizer3bands.c:
+	* gst/equalizer/gstiirequalizernbands.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/id3demux/gstid3demux.c:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/interleave/deinterleave.c:
+	* gst/interleave/interleave.c:
+	* gst/isomp4/atomsrecovery.c:
+	* gst/isomp4/gstqtmux-doc.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/webm-mux.c:
+	* gst/monoscope/gstmonoscope.c:
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/multifile/gstsplitfilesrc.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartmux.c:
+	* gst/replaygain/gstrganalysis.c:
+	* gst/replaygain/gstrglimiter.c:
+	* gst/replaygain/gstrgvolume.c:
+	* gst/rtp/README:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/smpte/gstsmpte.c:
+	* gst/smpte/gstsmptealpha.c:
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	* gst/videobox/gstvideobox.c:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/wavparse/gstwavparse.c:
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/oss/gstosssink.c:
+	* sys/oss/gstosssrc.c:
+	* sys/oss4/oss4-sink.c:
+	* sys/oss4/oss4-source.c:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/sunaudio/gstsunaudiosink.c:
+	* sys/sunaudio/gstsunaudiosrc.c:
+	* sys/v4l2/gstv4l2radio.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/waveform/gstwaveformsink.c:
+	* sys/ximage/gstximagesrc.c:
+	* tests/examples/cairo/cairo_overlay.c:
+	* tests/examples/rtp/client-H263p-AMR.sh:
+	* tests/examples/rtp/client-H263p-PCMA.sh:
+	* tests/examples/rtp/client-H263p.sh:
+	* tests/examples/rtp/client-H264-PCMA.sh:
+	* tests/examples/rtp/client-H264.sh:
+	* tests/examples/rtp/client-PCMA.sh:
+	* tests/examples/rtp/server-VTS-H263p-ATS-PCMA.sh:
+	* tests/examples/rtp/server-VTS-H263p.sh:
+	* tests/examples/rtp/server-alsasrc-PCMA.sh:
+	* tests/examples/rtp/server-decodebin-H263p-AMR.sh:
+	* tests/examples/rtp/server-v4l2-H263p-alsasrc-AMR.sh:
+	* tests/examples/rtp/server-v4l2-H264-alsasrc-PCMA.sh:
+	* tests/examples/shapewipe/shapewipe-example.c:
+	* tests/icles/gdkpixbufsink-test.c:
+	* tests/icles/videocrop-test.c:
+	  docs: gst-launch -> gst-launch-1.0 and ffmpegcolorspace -> videoconvert
+
+2012-08-26 22:32:54 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/flac/gstflacdec.c:
+	* gst/videomixer/videomixer2.c:
+	  docs: gst-launch-0.11 -> gst-launch-1.0
+
+2012-08-26 22:08:54 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* tests/check/elements/deinterlace.c:
+	  deinterlace: the field in caps is "interlace-mode" not "interlace-method"
+	  Fix deinterlace unit test. Need to set right field on output caps.
+	  Also remove right field (not old 0.10 "interlaced" boolean field)
+	  from caps in unit test before comparing old and new.
+
+2012-08-26 21:45:44 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/icydemux.c:
+	  tests: fix icydemux unit test
+	  Was waiting for a tag message on the bus, which would never
+	  come, because elements don't post those themselves any more
+	  but let sinks post them from tag events. Only that there are
+	  no sinks in this unit test.
+
+2012-08-26 21:27:00 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/videocrop.c:
+	  tests: fix videocrop crop_to_1x1 unit test for GRAY8 format
+	  Update table with pixel values with the value actually produced
+	  by videotestsrc.
+
+2012-08-27 09:00:45 +0200  Sjoerd Simons <sjoerd@luon.net>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: Only print caps if they're provided
+
+2012-08-24 19:43:08 +0100  Michael Rubinstein <mrubinstein@rai-dev.com>
+
+	* gst/videomixer/blend.c:
+	  videomixer: fix endianness check on systems where non-glib endianness defines are not set
+	  On Windows LITTLE_ENDIAN without the G_ in was not defined,  so the
+	  test comes out wrong.
+
+2012-08-22 17:23:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  udpsink: don't crash on NULL error
+	  Check if there is an error before retrieving its message.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=682481
+
+2012-08-22 13:30:19 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 668acee to 4f962f7
+
+2012-08-22 13:18:00 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* configure.ac:
+	  configure: bump gtk-doc req to 1.12 (mar-2009)
+	  This allows us to e.g. unconditionally use gtkdoc-rebase.
+
+2012-08-22 11:21:38 +0200  Martin Ertsaas <mertsas@cisco.com>
+
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: Make osxvideosink use the non-deprecated threading api from glib.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=682446
+
+2012-08-14 15:40:31 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: Handle negotiation events
+	  This makes sure that we:
+	  a) Destroy an existing stream if a negotiate() request comes in: this is
+	  required when receiving a downstream renegotiation request after a
+	  stream has been created.
+	  b) Create a new stream on prepare(): this is required since we do a
+	  setcaps() in negotiate(), which causes the stream to be dropped by a
+	  ringbuffer release() call (this does not happen during first negotiation
+	  since the release is only done on a running ringbuffer). The subsequent
+	  call to ringbuffer acquire() fails because the stream was lost on
+	  release().
+	  https://bugzilla.gnome.org/show_bug.cgi?id=681247
+
+2012-08-14 15:38:27 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulseutil.c:
+	  pulse: Clear unpositioned flag when setting positions
+	  If converting a PA channel map to gst channel positions results in a
+	  valid set of channel positions, we clear the unpositioned flag from the
+	  ringbuffer spec.
+
+2012-08-14 09:37:45 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: Remove redundant channel-mask setting for stereo case
+	  The gstaudio helper libraries already take care of this case for us.
+
+2012-08-14 09:36:30 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: Don't use memset to set invalid channel positions
+	  This itereates over the GstAudioInfo to set invalid channel positions
+	  rather than use memset() which works right now because it assumes that
+	  GST_AUDIO_CHANNEL_POSITION_INVALID is -1.
+
+2012-08-22 10:30:04 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	  gdkpixbufsink: minor docs improvement
+
+2012-08-22 10:23:24 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/gdk_pixbuf/Makefile.am:
+	* ext/gdk_pixbuf/gstgdkpixbufplugin.c:
+	  gdkpixbuf: re-enable already-ported gdkpixbufsink
+
+2012-08-22 10:08:08 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/gdk_pixbuf/Makefile.am:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.h:
+	* ext/gdk_pixbuf/gstgdkpixbufplugin.c:
+	  gdkpixbuf: port gdkpixbufoverlay element to 0.11
+
+2012-08-22 00:00:46 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* configure.ac:
+	* ext/gdk_pixbuf/Makefile.am:
+	* ext/gdk_pixbuf/gstgdkpixbufdec.c:
+	* ext/gdk_pixbuf/gstgdkpixbufdec.h:
+	* ext/gdk_pixbuf/gstgdkpixbufplugin.c:
+	  gdkpixbuf: re-enable already-ported gdkpixbuf element as gdkpixbufdec
+	  Not sure why it as disabled exactly given that it had already
+	  been ported (though without metas or baseclass).
+	  Move plugin_init bits into separate source file, and rename
+	  decoder element to gdkpixbufdec.
+
+2012-08-21 23:25:47 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/gdk_pixbuf/gst_loader.c:
+	  gdkpixbuf: remove old and unused gst_loader source file
+	  Once upon a time used to load GStreamer vids via GdkPixbuf API.
+
+2012-08-16 16:51:16 -0700  Aleix Conchillo Flaque <aleix@oblong.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: make jitterbuffer drop-on-latency available (fix #682055)
+	  Conflicts:
+	  gst/rtsp/gstrtspsrc.h
+
+2012-08-21 19:47:45 +0800  Huacai Chen <chenhc@lemote.com>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: make gst_v4l2_fill_lists() adapt to kernel 3.3+
+	  When do v4l2_ioctl() with VIDIOC_ENUMINPUT fails on some devices,
+	  kernels before 3.3.0 return EINVAL, but newer kernels return ENOTTY.
+	  This patch make those devices work well on kernel 3.3+.
+	  Related kernel commit:
+	  http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=07d106d0a33d6063d2061305903deb02489eba20
+	  Signed-off-by: Huacai Chen <chenhc@lemote.com>
+	  Signed-off-by: Rui Wang <wangr@lemote.com>
+	  Signed-off-by: Jie Chen <chenj@lemote.com>
+
+2012-08-20 23:30:38 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	  video/x-dvd-subpicture -> subpicture/x-dvd
+
+2012-08-17 20:52:42 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/multifile/gstmultifilesrc.c:
+	  multifilesrc: fix example pipeline in docs
+
+2012-08-17 14:59:57 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/equalizer/gstiirequalizer10bands.c:
+	* gst/equalizer/gstiirequalizer3bands.c:
+	* tests/check/elements/equalizer.c:
+	  equalizer: enable presets for the n-band equalizer
+	  Add a test for saving and restoring the preset.
+
+2012-08-14 01:20:19 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: fix not-negotiated errors on variable or missing framerate in input caps
+	  Remove some bogus code I added during porting that would error out
+	  on missing or variable framerates in input caps. Handle this like
+	  we do in 0.10
+	  Fixes test_mode_disabled_passthrough unit test check.
+
+2012-08-12 13:16:32 +0200  Sjoerd Simons <sjoerd@luon.net>
+
+	* gst/law/alaw-decode.c:
+	* gst/law/mulaw-decode.c:
+	  law: Filter layout caps field
+	  The layout caps field shouldn't be passed through to the sink pad
+	  of {mu,a}lawdec.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=681677
+
+2012-08-09 19:41:34 +0300  Anton Belka <antonbelka@gmail.com>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: allow a TOC with single alternative top-level entry
+	  Allow a TOC that has a single alternative top-level entry
+	  with multiple sequence sub-entries
+	  https://bugzilla.gnome.org/show_bug.cgi?id=540891
+
+2012-08-09 10:31:39 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: And fix the GTK check to use the correct pkg-config package name
+
+2012-08-09 10:25:38 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Fix GTK required version variable name
+
+2012-08-09 08:35:23 +0100  Matthias Clasen <mclasen@redhat.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: fix build with recent kernels, the v4l2_buffer input field was removed
+	  This was unused apparently and removed in the kernel in commit:
+	  From 2b719d7baf490e24ce7d817c6337b7c87fda84c1 Mon Sep 17 00:00:00 2001
+	  From: Sakari Ailus <sakari.ailus@iki.fi>
+	  Date: Wed, 2 May 2012 09:40:03 -0300
+	  Subject: [PATCH] [media] v4l: drop v4l2_buffer.input and V4L2_BUF_FLAG_INPUT
+	  Remove input field in struct v4l2_buffer and flag V4L2_BUF_FLAG_INPUT which
+	  tells the former is valid. The flag is used by no driver currently.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=681491
+	  Conflicts:
+	  sys/v4l2/gstv4l2bufferpool.c
+
+2012-08-08 17:25:36 -0700  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	* tests/check/elements/rtp-payloading.c:
+	  rtph264pay: Make it actually work after cleanups
+
+2012-08-08 17:40:34 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  gst: Set alignment at the correct place of GstAllocationParams
+
+2012-08-08 17:39:07 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/multipart/multipartmux.c:
+	* gst/videomixer/videomixer2.c:
+	  gst: Set alignment at the correct place of GstAllocationParams
+
+2012-08-08 16:25:58 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  Back to development
+
+=== release 0.11.93 ===
+
+2012-08-08 15:22:04 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.11.93
+
+2012-08-08 15:17:22 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* Makefile.am:
+	* win32/MANIFEST:
+	* win32/common/tuner-enumtypes.c:
+	* win32/common/tuner-enumtypes.h:
+	* win32/common/tuner-marshal.c:
+	* win32/common/tuner-marshal.h:
+	  win32: add generated tuner-marshal/enumtypes files for v4l2src and update
+	  And gst-indent the right rtp marshal files; add missing files to MANIFEST.
+
+2012-08-08 15:10:37 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/deinterlace/tvtime-dist.c:
+	* gst/videobox/gstvideoboxorc-dist.c:
+	* gst/videomixer/blendorc-dist.c:
+	  gst: update disted orc files
+
+2012-08-08 11:31:59 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/wavpack/gstwavpackdec.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* sys/oss4/oss4-audio.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	  Silence some 'variable may be used uninitialized' compiler warnings
+	  When compiling with -DG_DISABLE_ASSERT
+
+2012-08-08 10:56:51 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/libpng/gstpngdec.c:
+	* gst/isomp4/gstqtmoovrecover.c:
+	* tests/icles/ximagesrc-test.c:
+	  No code with side-effects inside g_assert() please
+
+2012-08-07 11:14:21 -0700  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: Return FLUSHING instead of ERROR on unlock
+	  If the base class asks multiudpsink to unlock, then it should return
+	  FLUSHING, not ERROR
+
+2012-07-26 16:19:57 +0300  Anton Belka <antonbelka@gmail.com>
+
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflacenc.h:
+	  flacenc: add TOC support
+	  Add TOC as embedded cuesheets in flac files.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=54089
+
+2012-08-07 12:12:09 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: generate empty vorbiscomment for complete streamheaders if needed
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=681335
+
+2012-08-06 18:02:50 -0700  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Block pad while it is announced.
+	  Block the RTP pad and associated RTCP pads while they are being
+	  announced. This it to prevent a race where one is announced and
+	  before the callback has connected it, the other one gets a buffer.
+	  We can't use the "padlock" of ssrcdemux because it causes deadlocks.
+
+2012-08-06 15:00:57 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  common: un-do accidental common update revert in commit 7b5925b5
+
+2012-08-06 14:50:53 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmparobustdepay.c:
+	  rtpmparobustdepay: set correct data_size for generated dummy frame
+	  ... which prevents getting stuck in a loop if such one is needed.
+
+2012-08-06 14:50:03 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmparobustdepay.c:
+	  rtpmparobustdepay: improve and fix debug statement
+	  ... so it really informs about next rather than past frame.
+
+2012-08-06 12:34:55 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmparobustdepay.c:
+	  rtpmparobustdepay: update available bytewriter space when repositioning
+	  ... and add some more assert to catch potential surprises early on.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=680558
+
+2012-08-04 12:47:44 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	* ext/dv/gstdvdemux.c:
+	* gst/avi/gstavidemux.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	  gst: Add stream-id to stream-start events
+
+2012-08-04 12:54:32 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Chain up to the parent class' query handler if no pad is provided
+
+2012-08-02 01:48:29 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: add a better detection for the main run loop
+
+2012-07-27 16:13:49 +0200  Xavi Artigas <xartigas@fluendo.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: Do not overwrite the DS buffer when testing for AC3 support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=680706
+	  Conflicts:
+	  sys/directsound/gstdirectsoundsink.c
+
+2012-08-05 16:39:23 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 94ccf4c to 668acee
+
+2012-08-03 16:13:52 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Release lock before signalling new pad
+	  This prevents a deadlock where something would try to push an event
+	  through the SSRC demux from the callback, causing the pads to be iterated
+	  and the lock taken.
+
+2012-08-04 16:10:16 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflactag.c:
+	* ext/shout2/gstshout2.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavimux.c:
+	* gst/debugutils/gsttaginject.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/wavparse/gstwavparse.c:
+	* tests/check/elements/apev2mux.c:
+	* tests/check/elements/icydemux.c:
+	* tests/check/elements/id3demux.c:
+	* tests/check/elements/id3v2mux.c:
+	* tests/check/elements/qtmux.c:
+	* tests/check/elements/rganalysis.c:
+	* tests/check/pipelines/tagschecking.c:
+	  gst_tag_list_free -> gst_tag_list_unref
+
+2012-08-03 14:10:32 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: manage race between connection closing and flushing
+	  ... where the former can happen in task thread and the latter in mainloop
+	  upon downward state change.
+
+2012-08-03 14:02:23 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: improve and relax audio frame parsing
+	  ... so as to properly recognize first audio frame.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=681077
+	  Conflicts:
+	  ext/flac/gstflacdec.c
+
+2012-08-01 12:16:41 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix double unref of private tag buffer
+
+2012-07-30 17:54:51 +0300  Anton Belka <antonbelka@gmail.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: create TOC as needed
+	  Avoid creating the toc if the wav has no or empty cue chunk.
+	  Also a small code cleanup.
+
+2012-07-28 11:26:01 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: update for TOC API changes
+
+2012-07-28 11:22:43 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroska: update for TOC API changes
+
+2012-07-28 11:20:08 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: update for TOC API changes
+
+2012-07-28 00:19:51 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	* ext/flac/gstflactag.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/wavpack/gstwavpackdec.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavisubtitle.c:
+	* gst/debugutils/gsttaginject.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/replaygain/gstrganalysis.c:
+	* gst/wavparse/gstwavparse.c:
+	* tests/check/elements/rganalysis.c:
+	* tests/check/elements/rgvolume.c:
+	  tag: Update for taglist/tag event API changes
+
+2012-07-27 12:05:44 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/isomp4-plugin.c:
+	* gst/isomp4/qtdemux.c:
+	  qt(de)mux: pass private blob tags in a sample
+	  ... rather than a buffer, and the detailed info in the sample info
+	  rather than caps.
+
+2012-07-27 11:31:13 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/videocrop/gstvideocrop.c:
+	  videocrop: Don't return NULL from _transform_caps
+	  If _transform_caps () returns NULL, the basetransform _transform_caps
+	  tries to call gst_caps_is_subset () with a NULL subset which hits an
+	  assertion.
+
+2012-07-27 11:26:18 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: obtain image type from the sample info
+
+2012-07-27 11:25:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: remove extraneous _unref
+	  ... since we did not obtain a buffer ref from the GstSample.
+
+2012-07-27 10:14:23 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: Update to use GstSample tag setting API
+
+2012-07-26 16:34:21 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmparobustdepay.c:
+	  rtpmparobustdepay: modify buffer data rather than buffer itself
+
+2012-07-26 16:28:33 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmparobustdepay.c:
+	  rtpmparobustdepay: avoid leaking bytewriter instance
+
+2012-07-26 16:04:23 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Fix timestamp adjustment and caps
+
+2012-07-26 16:03:57 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Fix/simplify telecine state checks
+
+2012-07-26 12:08:58 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Improve debug output
+
+2012-07-26 12:08:36 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Fix low-latency pattern locking
+
+2012-07-24 16:19:53 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: RFF should be ignored in deinterlace
+	  RFF only occurs on progressive frames in telecine sequences. For
+	  deinterlace, we don't want these repeated fields as we will simply be
+	  pushing the progressive frame and then moving on.
+	  However, we need to consider RFF in order to correctly identify patterns
+	  and adjust the timestamps.
+
+2012-07-24 14:59:47 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Improve process logic
+	  The logic now works better if we filter orphans, then progressive, then
+	  telecine interlaced fields which need to be woven and fall through to
+	  interlace. Telecine interlaced fields will be regularly deinterlaced if
+	  there is no pattern lock for us to be sure that we have a telecine
+	  pattern.
+	  Telecine sequences that aren't 24fps progressive with RFF flags can't
+	  really be tested until fieldanalysis is ported.
+
+2012-07-25 16:02:34 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: only set complete output caps once
+	  ... so as to avoid downstream complaints about missing streamheaders.
+
+2012-07-25 15:29:04 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: also support S24_32 output
+
+2012-07-25 15:28:14 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: pass correct parameters to encoder lib
+
+2012-07-25 14:57:13 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: adjust to modified audioencoder getcaps helper API
+
+2012-07-25 12:50:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtsp: go and stay in the loop function on PLAY
+	  When we have a PLAY request, go into the LOOP function next. When we are
+	  looping, keep on looping until we are told otherwise.
+	  This fixed rtsp and TCP connections.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=680551
+
+2012-07-25 12:49:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtsp: set caps after activating the pad
+
+2012-07-25 12:49:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	  h264depay: small cleanups
+
+2012-07-25 10:08:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/gstrtpxqtdepay.c:
+	  xqtdepay: fix buffer refcount error
+	  After pushing the buffer into the adapter, we should not let the baseclass push
+	  it out anymore. This error was introduced while porting to 0.11.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=680540
+
+2012-07-24 21:41:53 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/level/gstlevel.c:
+	  level: remove obsolete liboil comment
+
+2012-07-24 21:11:18 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: push mode: increase segment accuracy following seek
+	  Conflicts:
+	  gst/matroska/matroska-demux.c
+
+2012-07-24 16:41:51 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: perform proper KEY_UNIT seek also in push mode
+	  Conflicts:
+	  gst/matroska/matroska-demux.c
+
+2012-07-24 19:04:39 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: don't crash dereferencing NULL error when leaving multicast group on shutdown
+	  Strangely enough, if we do pass an error variable to be filled, we
+	  no longer get an error on leaving.
+
+2012-07-24 15:55:12 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: rearrange some checks to avoid NULL use
+
+2012-07-24 15:38:24 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: use same fourcc to determine caps in determining uncompressed-ness
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=673898
+	  Conflicts:
+	  gst/avi/gstavidemux.c
+
+2012-07-24 15:36:54 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  Revert "avidemux: Don't consider 0 fcc_handler as uncompressed."
+	  This reverts commit c6b9f5b25ab435669816a07049b0e5a8f01e09ca.
+	  fourcc GST_RIFF_rgb = 0 still leads to raw uncompressed rgb caps.
+	  See also https://bugzilla.gnome.org/show_bug.cgi?id=673898
+
+2012-07-24 12:10:46 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fix up example pipeline some more
+	  No more ffmpegcolorspace
+
+2012-07-20 16:30:00 +0300  Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Fix the example gst-launch pipeline.
+
+2012-07-24 12:33:33 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: avoid NULL access when checking subtitle
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=680388
+
+2012-07-24 12:22:08 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Reset parser when we have caps without codec_data
+	  This ensures the detection (and proper downstream caps settings) will
+	  actually happen when we have new incoming caps without codec_data.
+	  This was easily triggered by streams from matroskademux which initially
+	  provided caps with a constructed codec_data, but then pushed new caps
+	  without the codec_data once it detected the stream was adts.
+
+2012-07-24 09:17:09 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videomixer/blend.c:
+	* gst/videomixer/blendorc-dist.c:
+	* gst/videomixer/blendorc-dist.h:
+	* gst/videomixer/blendorc.orc:
+	  videomixer: prefix orc functions with video_mixer_orc_
+
+2012-07-24 09:13:48 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	* gst/videobox/gstvideoboxorc-dist.c:
+	* gst/videobox/gstvideoboxorc-dist.h:
+	* gst/videobox/gstvideoboxorc.orc:
+	  videobox: prefix orc functions with video_box_orc_
+
+2012-07-23 18:51:00 +0200  Christian Fredrik Kalager Schaller <uraeus@linuxrisin.org>
+
+	* gst-plugins-good.spec.in:
+	  Update spec file with latest changes
+
+2012-07-23 17:37:58 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: generate correct segment stream time
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=680275
+
+2012-07-23 16:42:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kdepay.h:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpj2kpay.h:
+	  rtp: always use buffer lists
+
+2012-07-23 15:24:17 +0200  Patricia Muscalu <patricia@axis.com>
+
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmp4vpay.h:
+	  rtpmp4vpay: always enable buffer-lists
+
+2012-07-23 15:22:24 +0200  Patricia Muscalu <patricia@axis.com>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpjpegpay.h:
+	  rtpjpegpay: always enable buffer-lists
+
+2012-07-23 15:49:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: get frame flags correctly
+	  Also move the deinterlace plugin to ported status
+
+2012-07-23 15:33:54 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: proper parse recovery after seek
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=680427
+
+2012-07-23 12:39:05 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: clear old segment event when requesting new one
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=680283
+
+2012-07-23 10:32:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/libpng/gstpngdec.c:
+	  ext: Update for video base classes API changes
+
+2012-07-23 08:49:07 +0200  Alban Browaeys <prahal@yahoo.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: convert all non GST_FORMAT_BYTES to format bytes.
+	  Convert all non GST_FORMAT_BYTES to format bytes:
+	  fixes:
+	  GStreamer-CRITICAL **: gst_query_set_duration: assertion `format ==
+	  g_value_get_enum (gst_structure_id_get_value (s, GST_QUARK (FORMAT)))'
+	  failed
+	  when playing more than one wav stream.
+	  gst-plugins-base/tests/icles/playback/test7 uri1.wav uri2.wav
+
+2012-07-23 09:25:23 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Don't fail if more data then needed is available when parsing cue chunks
+	  Fixes bug #680328.
+
+2012-07-23 09:22:20 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Some minor cleanup to the cue/labl parsing
+
+2012-07-23 08:45:28 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 98e386f to 94ccf4c
+
+2012-07-19 14:55:45 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	* gst/deinterlace/gstdeinterlacemethod.h:
+	* gst/deinterlace/tvtime/greedyh.c:
+	* gst/deinterlace/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	  deinterlace: Port to 1.0
+	  This requires the additional INTERLACED buffer flag recently added to
+	  -base
+
+2012-07-20 15:18:46 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/interleave/interleave.c:
+	  interleave: convert the output segment to time
+	  Convert the stored input segment to time before pushing it out.
+	  Conflicts:
+	  gst/interleave/interleave.c
+
+2012-07-20 13:12:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/interleave/interleave.c:
+	* gst/interleave/interleave.h:
+	  interleave: try to fix segment handling
+	  Conflicts:
+	  gst/interleave/interleave.c
+
+2012-07-20 15:28:21 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Non-update seeks should still make sure that reverse playback status is reset
+	  Conflicts:
+	  gst/matroska/matroska-demux.c
+
+2012-07-20 15:18:21 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Properly initialize from_offset and from_time
+
+2012-07-20 14:25:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: We need an index and index entry for reverse playback
+	  Reverse playback does not work with index-less files yet.
+
+2012-07-20 14:10:41 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: clean up push mode segment handling
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=680277
+
+2012-07-20 13:35:29 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: properly transform incoming segment event
+	  ... which is really useful for proper push mode seeking.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=680278
+
+2012-07-20 11:07:58 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: Fix reverse playback for seeks without stop position
+	  Conflicts:
+	  gst/matroska/matroska-demux.c
+	  gst/matroska/matroska-demux.h
+
+2012-07-20 10:48:34 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Only take the stream_start_time into account for SET seeks
+	  For other seeks the stream_start_time is already added to the
+	  segment values.
+	  Conflicts:
+	  gst/matroska/matroska-demux.c
+
+2012-07-08 20:36:22 +0300  Anton Belka <antonbelka@gmail.com>
+
+	* gst/wavparse/gstwavparse.c:
+	* gst/wavparse/gstwavparse.h:
+	  wavparse: Add TOC support
+	  Add support for:
+	  * Cue Chunk
+	  * Associated Data List Chunk
+	  * Label Chunk
+	  https://bugzilla.gnome.org/show_bug.cgi?id=677306
+
+2012-05-09 15:58:16 +0200  Maria Giovanna Chiossa <mariagiovanna.chiossa at selexelsag.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: also set UDP buffer size in multicast
+	  Also set the UDP buffer size in multicast mode.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=675448
+
+2012-07-18 23:43:59 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix header parsing in push mode
+	  Fix 'break' that got warped to the wrong place,
+	  probably as part of a merge. Fixes GST_IS_BUFFER
+	  criticals in parse_idit() when being accidentally
+	  passed a NULL buffer because of the missing break.
+	  gst-launch-1.0 playbin uri=http://docs.gstreamer.com/media/sintel_trailer-480i.avi
+
+2012-07-18 22:47:22 +0200  Alban Browaeys <prahal@yahoo.com>
+
+	* configure.ac:
+	* ext/soup/gstsouphttpsrc.c:
+	  soup: deprecated soup_message_headers _get -> _get_one
+	  https://bugzilla.gnome.org/show_bug.cgi?id=680206
+
+2012-07-18 18:27:40 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/libpng/gstpngdec.c:
+	  jpeg/png: Call video_decoder_negotiate()
+
+2012-07-18 17:57:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/debugutils/gstpushfilesrc.c:
+	  update for ghostpad changes
+
+2012-07-18 11:36:27 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Pass seek rate to upstream seek events in push mode
+	  Fixes bug #679435.
+	  Conflicts:
+	  gst/matroska/matroska-demux.c
+
+2012-07-17 16:39:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  update for RTP buffer api changes
+
+2012-07-17 16:38:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/gstrtpxqtdepay.c:
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtsp/gstrtpdec.c:
+	  update for RTP buffer api changes
+
+2012-07-16 11:07:44 +0200  Patricia Muscalu <patricia@axis.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: use buffer lists
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=679994
+
+2012-07-17 10:01:54 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Fix parsing of ISRC from the cuesheets
+
+2012-07-05 14:15:25 +0300  Anton Belka <antonbelka@gmail.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstflacparse.h:
+	  flacparse: add TOC support
+	  Add support embedded cuesheets in flac files.
+	  Parsing METADATA_BLOCK_CUESHEET as TOC.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=540891
+
+2012-07-13 14:43:31 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: avoid some more frame misparsing by additional header sanity check
+	  ... using a required constant blocking_strategy bit.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=679807
+
+2012-07-13 13:51:48 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	* gst/avi/gstavidemux.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	  demux: Push STREAM_START event when needed
+
+2012-07-11 13:10:07 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: avoid warning if both ts are equal
+
+2012-07-11 12:28:23 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: check the right size when warning about too large udp packets
+	  What matters is the total size, not the size of any of the
+	  individual memory chunks that make up the packet.
+
+2012-07-10 14:38:21 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosink.h:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosink.h:
+	  autodetect: proxy ts-offset properties
+	  Proxy the ts-offset property in the audio*sink elements.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=679343
+
+2012-07-09 16:27:10 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  fix for allocator API changes
+
+2012-07-09 12:22:02 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/wavparse/gstwavparse.c:
+	  update for riff field rename
+
+2012-05-21 13:54:51 +0200  Mathias Hasselmann <mathias@openismus.com>
+
+	* tests/check/Makefile.am:
+	  tests: drop redundant elements_level_LDADD line
+	  https://bugzilla.gnome.org/show_bug.cgi?id=676302
+
+2012-07-08 13:30:34 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/jpegdec.c:
+	  tests: minor jpegdec clean-ups and fixes
+	  Fix race condition in eos checking and a leak. And
+	  build pipeline without parse_launch.
+
+2012-05-21 13:53:54 +0200  Mathias Hasselmann <mathias@openismus.com>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/jpegdec.c:
+	* tests/files/image.jpg:
+	  tests: Add some basic tests for jpegdec
+	  https://bugzilla.gnome.org/show_bug.cgi?id=676302
+
+2012-07-08 00:08:55 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  dtmfsrc: pass unhandled non-custom events to the base class
+	  https://bugzilla.gnome.org/show_bug.cgi?id=666626
+
+2012-07-06 19:11:02 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: avoid some relocations
+
+2012-07-06 14:49:18 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4vpay.c:
+	  rtpmp4vpay: remove deprecated send-config property
+	  Use config-interval instead.
+
+2012-07-06 14:42:19 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: remove deprecated "byte-stream" and "access-unit" properties
+	  These will be picked automatically based on downstream caps now, so
+	  if you want the depayloader to output a specific format, make sure
+	  the element downstream advertises that preference or use a capsfilter
+	  after the depayloader to force it.
+
+2012-07-06 14:13:54 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: remove deprecated and non-functional "profile-level-id" property
+	  This is now optionally taken from downstream caps, so can be
+	  specified via a capsfilter after the payloader.
+
+2012-07-06 15:07:51 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: perform additional sanity check before confirming ADTS format
+	  ... and tweak confusing debug message.
+
+2012-07-06 15:29:14 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: remove unhelpful stray debug message
+
+2012-07-06 13:16:00 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: remove deprecated and unused "ntp-ns-base" property
+
+2012-07-06 12:57:20 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux-doc.c:
+	  docs: update isomp4 docs for gppmux -> 3gppmux change as well
+
+2012-07-06 12:54:02 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmuxmap.c:
+	* tests/check/pipelines/tagschecking.c:
+	  isomp4: remove gppmux, which was deprecated in favour of 3gppmux
+
+2012-07-06 12:49:54 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/smpte/gstsmpte.c:
+	  smtp: remove deprecated "fps" property
+
+2012-07-06 12:46:30 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartdemux.h:
+	  multipartdemux: remove deprecated and unused "autoscan" property
+	  Replaced by boundary=NULL.
+
+2012-07-06 09:07:41 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/rtp/gstrtph263ppay.c:
+	* tests/check/elements/rtp-payloading.c:
+	  rtph263ppay: accept any h263 input unless downstream forces specific requirements
+	  rtph263ppay should accept any input compatible with its sink template
+	  caps if it just outputs to e.g. udpsink or fakesink.
+	  rtph263ppay ! rtph263pdepay should also work with any compatible input.
+	  This would fail before with not-negotiated errors because the get_caps
+	  function would see the encoding-name in the depayloader's template caps
+	  and default to baseline H.263 because there's no profile/level information
+	  in those caps, which is the right thing to do if downstream has filtercaps
+	  from an SDP, but not if those fields are absent because they can be
+	  anything like with the depayloader's template caps. Makes
+	  videotestsrc ! avenc_h263p ! rtph263ppay ! rtph263pdepay ! fakesink
+	  work.
+
+2012-07-05 22:57:05 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/rtp-payloading.c:
+	  tests: fix h263p payload ! depayload unit test
+	  Need to add h263version field to input caps since the
+	  payloader sink get_caps function will contain it in the
+	  the caps, and the stricter caps subset check requires
+	  this to be present in the input caps as well then.
+
+2012-07-06 11:50:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/aalib/gstaasink.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/libpng/gstpngenc.c:
+	* sys/v4l2/gstv4l2sink.c:
+	  update for query api changes
+
+2012-07-06 11:26:46 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/dv/gstdvdec.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/libpng/gstpngdec.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* sys/v4l2/gstv4l2src.c:
+	  update for query api changes
+
+2012-07-06 11:02:24 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/aalib/gstaasink.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/libpng/gstpngenc.c:
+	* sys/v4l2/gstv4l2sink.c:
+	  update for allocation query changes
+
+2012-07-05 15:14:33 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/rgvolume.c:
+	  tests: fix rgvolume unit test event handling
+	  Must flush after EOS before sending more buffers or
+	  another EOS event, or the event or buffer will be
+	  rejected. Also send a SEGMENT event at the start
+	  of each stream for good measure.
+
+2012-07-05 13:13:09 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	* gst/avi/gstavidemux.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/wavparse/gstwavparse.c:
+	  gst: Implement segment-done event
+
+2012-07-05 12:35:49 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Remove the TOC query handling
+
+2012-07-04 19:52:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-read-common.c:
+	  matroska: Update for new GstToc API
+	  TOC support in matroskamux is disabled for now as it was broken anyway.
+
+2012-07-04 23:57:18 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* tests/check/elements/rganalysis.c:
+	  tests: fix rganalysis unit test event handling
+	  Must flush after EOS before sending more buffers or
+	  another EOS event, or the event or buffer will be
+	  rejected. Also send a SEGMENT event at the start
+	  of each stream for good measure.
+
+2012-07-04 18:58:46 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: clear 0 DTS on buffers output, as sinks will prefer DTS over PTS for syncing
+	  Since the initial decoded still image buffer will have dts=pts=0, and
+	  we only set PTS on buffers we push out, all buffers pushed out would
+	  have a DTS of 0. Sinks, however, will prefer DTS over PTS if both are
+	  set, and will therefore always see a timestamp of 0 no matter what
+	  the PTS is set to.
+	  Fixes unit test too.
+
+2012-07-04 20:59:03 +0400  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: Fix query function implementation; more debugging
+
+2012-07-04 19:41:52 +0400  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: Fix spec stuff in directsoundsink
+
+2012-05-31 19:22:47 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: fix access to invalid pointer in set_volume
+
+2012-06-13 12:12:39 +0200  Sebastian Dr=C3=B6ge <sebastian.droege@collabora.co.uk>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: Fix caps leaks
+
+2012-05-29 11:37:59 +0000  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: fix acceptcaps check
+
+2012-05-25 10:14:57 +0000  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: use helper function to check for spdif formats
+
+2012-05-25 10:19:09 +0000  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: add support for DTS
+
+2012-05-08 16:23:42 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: force 48000 kHz force AC-3 over spdif
+
+2012-07-04 17:42:49 +0400  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: add support for ac-3 over spdif
+
+2012-07-04 12:37:40 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/deinterlace.c:
+	  tests: disable deinterlace test for now, element still needs to be ported
+	  But leave it active and print a FIXME. Porting is in progress.
+
+2012-07-03 19:38:39 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/interleave/deinterleave.c:
+	  deinterleave; downgrade caps change failure debug message
+	  Add some more info and downgrade to warning, so
+	  it doesn't look like the unit test failed.
+
+2012-07-03 17:52:11 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audiofx/audiopanorama.c:
+	  audiopanorama: fix negotiation and unit test
+	  Must remove a possibly-fixed channel-mask field if
+	  we're going to set unfixed channels on the structure,
+	  or a different channel count.
+
+2012-07-03 17:26:26 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Only push the TOC event, the message is handled by the sinks
+
+2012-07-03 12:47:58 +0900  Javier Jardón <jjardon@gnome.org>
+
+	* tests/examples/equalizer/demo.c:
+	* tests/examples/spectrum/demo-audiotest.c:
+	* tests/icles/gdkpixbufsink-test.c:
+	  tests: do not use deprecated gtk+ symbols
+	  https://bugzilla.gnome.org/show_bug.cgi?id=679301
+
+2012-07-03 09:27:17 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* configure.ac:
+	  configure: require Gtk+ 3.0 for tests/examples
+
+2012-07-03 12:57:18 +0900  Javier Jardón <jjardon@gnome.org>
+
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	  rtp: remove some outdated comments
+	  https://bugzilla.gnome.org/show_bug.cgi?id=679301
+
+2012-06-29 11:51:30 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: default to force-aspect-ratio=true
+
+2012-06-28 20:03:05 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/debugutils/rndbuffersize.c:
+	  rndbuffersize: add push mode support
+	  https://bugzilla.gnome.org/show_bug.cgi?id=656317
+
+2012-06-28 11:29:55 +0200  David Corvoysier <david.corvoysier@orange.com>
+
+	* gst/isomp4/qtdemux.c:
+	  isomp4: Try to seek upstream before processing seek push event
+	  When it receives a seek in push mode, the qtdemux should first try to push the event upstream, and only if upstream fails fall back to
+	  its own seek logic.
+
+2012-06-28 11:47:20 +0200  David Corvoysier <david.corvoysier@orange.com>
+
+	* gst/isomp4/qtdemux.c:
+	  isomp4: Allow duration queries to be forwarded upstream
+	  When receiving a duration query for TIME format, try to query upstream, and only if upstream fails fall back to qtdemux duration handling.
+
+2012-06-28 11:59:11 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtph264pay.h:
+	  rtph264pay: cleanups
+	  Use the caps properties for alignment and format.
+	  Remove some old properties, we always want to use bufferlists when we can now.
+
+2012-06-28 11:32:03 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  h264pay: prefer AVC, it's easier to parse etc
+
+2012-06-27 09:09:32 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: mark all output frames as keyframes
+
+2012-06-26 18:48:11 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroska: update for GstToc API additions
+
+2012-06-26 17:04:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska: set interlace-mode
+
+2012-06-26 13:19:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: improve debug
+
+2012-06-26 13:02:13 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  Revert "v4l2: free kernel buffers before allocating new ones"
+	  This reverts commit 1b09bc609a578e731f0dbc8f6e698e25d8f4c5f8.
+	  Seems to make libv4l2 complain, maybe because we call REQBUFS with 0 buffers
+	  before we allocated buffers.
+
+2012-06-26 12:07:47 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: free kernel buffers before allocating new ones
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=670257
+
+2012-06-26 12:07:29 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: improve debug
+
+2012-06-26 11:14:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: setup strides and offsets for all planes
+
+2012-06-25 20:11:53 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/matroska/matroska-mux.c:
+	  matroska-mux: update for GstTocSetter changes
+
+2012-06-25 13:31:16 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Return FALSE from queries if we can't answer POSITION/DURATION queries
+
+2012-06-21 17:15:11 +0300  Anton Belka <antonbelka@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Return FALSE from TOC query if no TOC exists instead of an empty TOC
+
+2012-06-24 22:51:16 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-read-common.c:
+	  matroska: update for GstToc API changes
+
+2012-06-23 14:57:28 +0100  Tim-Philipp Müller <tim@centricular.net>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: update for gst_element_make_from_uri() changes
+
+2012-06-20 12:31:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/flvdemux.c:
+	* tests/check/elements/flvmux.c:
+	* tests/check/elements/id3demux.c:
+	  update for bus api changes
+
+2012-06-20 10:33:42 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	* gst/avi/gstavidemux.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/isomp4/gstqtmoovrecover.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/wavparse/gstwavparse.c:
+	  update for task api change
+
+2012-06-20 09:59:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/examples/spectrum/demo-audiotest.c:
+	* tests/examples/spectrum/demo-osssrc.c:
+	  update for clock api changes
+
+2012-06-19 12:15:33 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* sys/osxaudio/Makefile.am:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosink.h:
+	* sys/osxaudio/gstosxcoreaudio.h:
+	* sys/osxaudio/gstosxringbuffer.c:
+	* sys/osxaudio/gstosxringbuffer.h:
+	  osxaudiosink: respect the prefered channel layout
+	  In OSX is allowed to configure the default audio output device,
+	  prefered channel layout and speaker positions through the tool
+	  "Audio MIDI Setup".
+
+2012-04-30 22:59:58 +0200  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: Send gap events for subtitle streams
+
+2012-06-17 01:00:40 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/multifile/gstsplitfilesrc.c:
+	  splitfilesrc: fix up docs for 0.11
+
+2012-06-16 23:29:41 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/multifile/gstsplitfilesrc.c:
+	  splitfilesrc: small uri handler fixup and some more docs
+	  Get URI location using gst_uri_get_location(), so any
+	  escaped bits get unescaped.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=609049
+
+2012-06-17 00:59:21 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/multifile/gstsplitfilesrc.c:
+	  splitfilesrc: re-port to 0.11
+
+2012-06-16 19:06:25 +0100  Bastien Nocera <hadess@hadess.net>
+
+	* gst/multifile/gstsplitfilesrc.c:
+	  splitfilesrc: Implement splitfile:// URI scheme
+	  https://bugzilla.gnome.org/show_bug.cgi?id=609049
+	  Conflicts:
+	  gst/multifile/gstsplitfilesrc.c
+
+2012-06-14 10:43:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	  theoradepay: fix buffer memory
+	  The memory was added to the input buffer instead of the output buffer.
+
+2012-06-13 13:36:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Don't reset time in flush-stop
+	  Don't reset the time in flush-stop. Live sources can do this flush in the
+	  playing state and so the pipeline will never have a chance to update the
+	  base_time of the elements, which only happens when going from paused to
+	  playing.
+
+2012-06-12 12:42:31 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* sys/osxaudio/Makefile.am:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosink.h:
+	* sys/osxaudio/gstosxcoreaudio.h:
+	* sys/osxaudio/gstosxringbuffer.c:
+	* sys/osxaudio/gstosxringbuffer.h:
+	  osxaudiosink: Add support for SPDIF output
+	  A big refactoring to allow passthrough AC3/DTS over SPDIF.
+	  Several random cleanups and minor fixes.
+
+2011-09-01 15:41:26 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  deinterlace: send QoS messages when dropping a frame
+	  https://bugzilla.gnome.org/show_bug.cgi?id=657941
+
+2012-06-12 16:05:40 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Rework the async state handling
+	  Always send the flushing events to the udp elements now that basesrc supports
+	  this. This makes sure a segment event is sent correctly after a flush.
+	  Keep track of the currently executing command and make it possible to specify
+	  what command you want to cancel when starting a new async command.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=677905
+
+2012-06-11 18:24:20 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/equalizer/gstiirequalizer10bands.c:
+	* gst/equalizer/gstiirequalizer3bands.c:
+	* gst/videomixer/videomixer2.c:
+	  childproxy: update api use
+
+2012-06-11 12:54:27 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: always perform full seek if seek is flushing
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=677838
+
+2012-06-11 11:20:18 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/debugutils/rndbuffersize.c:
+	  rndbuffersize: printf format fix for long -> int change
+
+2012-06-08 20:38:34 +0200  Hans de Goede <hdegoede@redhat.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2object: Don't probe UVC devices for being interlaced
+	  UVC devices are never interlaced, and doing VIDIOC_TRY_FMT on them
+	  causes expensive and slow USB IO, so don't probe them for interlaced.
+	  This shaves 2 seconds of the startup time of cheese with a Logitech
+	  Webcam Pro 9000.
+	  Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=677722
+
+2012-06-09 16:53:54 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/debugutils/rndbuffersize.c:
+	  debug: change rndbuffersize properties from long to int
+	  These should all be int instead of long, to avoid bugs
+	  when passing these as varargs with g_object_set(), and
+	  there was no reason to use long in the first place here.
+	  Fixes FIXME.
+
+2012-06-08 15:54:42 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/monoscope/gstmonoscope.c:
+	* gst/rtsp/gstrtpdec.c:
+	  elements: Use gst_pad_set_caps() instead of manual event fiddling
+
+2012-06-08 15:04:59 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 03a0e57 to 98e386f
+
+2012-06-08 10:11:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	* ext/wavpack/gstwavpackenc.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	* sys/oss4/oss4-audio.c:
+	* tests/check/elements/interleave.c:
+	  update for audio api change
+
+2012-06-07 16:12:34 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  Back to development
+
+=== release 0.11.92 ===
+
+2012-06-07 16:12:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.11.92
+
+2012-06-07 16:11:17 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2012-06-07 15:03:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: improve clock handling
+	  Post the notify outside of the pa_lock to avoid a deadlock caused by basesrc
+	  calling get_time with the object lock.
+	  Reset the clock on connect.
+	  Post clock-lost and clock-provide messages.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=673977
+	  Conflicts:
+	  ext/pulse/pulsesrc.c
+
+2012-04-12 13:21:17 +0300  Mohammed Sameer <msameer@foolab.org>
+
+	* ext/pulse/pulsesrc.c:
+	  Better GstClock for pulsesrc
+	  This clock uses the actual stream time (pa_stream_get_time) to get a more accurate timestamp.
+	  Conflicts:
+	  ext/pulse/pulsesrc.c
+
+2012-06-07 11:16:50 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngenc.c:
+	  png: fix video state leaks
+
+2012-06-07 11:16:37 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fix video state leak
+
+2012-06-07 12:11:14 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: only reset the manager object when we did a seek
+	  Only reset the manager object when we used a Range header, ie. when we did a
+	  seek. Otherwise we just paused and we can resume just fine.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=677475
+
+2012-06-06 16:13:29 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpbin.c:
+	  tests: add test for rtpsession cleanup
+
+2012-06-06 18:18:41 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 1fab359 to 03a0e57
+
+2012-06-06 14:17:08 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Update for TOC event API change
+
+2012-06-06 13:02:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	* ext/flac/gstflactag.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavisubtitle.c:
+	* gst/debugutils/gsttaginject.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/replaygain/gstrganalysis.c:
+	* gst/wavparse/gstwavparse.c:
+	* tests/check/elements/rganalysis.c:
+	* tests/check/elements/rgvolume.c:
+	  update for tag event change
+
+2012-06-06 13:00:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videocrop/gstvideocrop.c:
+	* tests/check/elements/aspectratiocrop.c:
+	* tests/check/elements/videocrop.c:
+	  fix Y800 format
+
+2012-06-01 01:19:35 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* configure.ac:
+	* sys/osxvideo/cocoawindow.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideo: straightforward port to 0.11
+
+2012-05-31 18:39:25 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* ext/libpng/gstpngdec.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	  Some printf variable format fixes
+	  The osx compiler complains about those
+
+2012-06-05 09:18:12 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	  audioparsers: Fix GstBaseParse::get_sink_caps() implementations
+	  They should take the filter caps into account and always return
+	  the template caps appended to the actual caps. Otherwise the
+	  parsers stop to accept unparsed streams where upstream does not
+	  know about channels, rate, etc.
+	  Fixes bug #677401.
+
+2012-06-04 16:17:51 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: set colorimetry on output info
+
+2012-06-04 08:10:15 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* sys/osxaudio/gstosxringbuffer.c:
+	  osxaudiosink: Handle endianness correctly
+
+2012-06-01 16:37:00 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxringbuffer.c:
+	  osxaudiosink: Add support for int audio
+
+2012-06-01 10:28:53 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From f1b5a96 to 1fab359
+
+2012-05-31 13:36:32 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: set the palette size correctly
+
+2012-05-31 10:15:43 +0200  Michael Jones <michael.jones@matrix-vision.de>
+
+	* sys/v4l2/gstv4l2colorbalance.h:
+	* sys/v4l2/gstv4l2vidorient.h:
+	  v4l2: add missing G_END_DECLS
+	  G_BEGIN_DECLS didn't have matching G_END_DECLS
+	  https://bugzilla.gnome.org/show_bug.cgi?id=677165
+
+2012-05-31 13:08:19 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 92b7266 to f1b5a96
+
+2012-05-31 10:26:27 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* sys/osxvideo/osxvideosink.h:
+	  osxvideosink: Really fix the build on 10.5
+	  The API that we use to run the Cocoa loop in another
+	  thread does not exist in 10.5 or earlier.
+
+2012-05-26 12:21:18 +0200  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: fix race in starting the runloop thread
+	  Block gst_osx_video_sink_run_cocoa_loop until the loop thread has started and
+	  finished initializing NSApp. Fixes occasional warnings/crashes due to two
+	  threads going inside NSApp before finishLaunching had completed.
+
+2012-05-30 16:03:55 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* sys/osxvideo/osxvideosink.h:
+	  osxvideosink: Fix last commit to actually work
+	  MAC_OS_X_VERSION_10_6 is obviously not defined on 10.5.
+
+2012-05-30 13:51:35 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/osxvideo/Makefile.am:
+	  osxvideosink: Put the right flags in the right variable
+
+2012-05-30 13:24:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Fix GST_OBJCFLAGS
+
+2012-05-30 12:45:23 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From ec1c4a8 to 92b7266
+
+2012-05-30 12:43:37 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/osxvideo/osxvideosink.h:
+	  osxvideosink: NSWindowDelegate is available in all OSX versions newer than 10.6
+
+2012-05-30 12:40:57 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* sys/osxvideo/osxvideosink.h:
+	  osxvideosink: Fix build with older OSX versions
+
+2012-05-30 11:09:25 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* sys/osxvideo/Makefile.am:
+	  configure: Add OBJC specific compiler flags
+	  See bug #643939.
+
+2012-05-30 11:23:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 3429ba6 to ec1c4a8
+
+2012-05-29 17:50:21 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videocrop/gstvideocrop.c:
+	  video: remove duplicate format
+
+2012-05-29 16:52:02 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Post error message if EOS before pads were created
+	  Happens with some files with only headers
+
+2012-05-28 15:22:26 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngdec.h:
+	* ext/libpng/gstpngenc.c:
+	* ext/libpng/gstpngenc.h:
+	  png: Port to 0.11 again
+
+2012-05-14 12:46:57 +0200  Jens Georg <mail@jensge.org>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  soup: Drop transferMode.dlna.org header
+	  Leave it to the application to decide on the header. No header at all
+	  is better than having the wrong header as DLNA mandates that a missing
+	  header has to be tolerated while a wrong header is an error.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=676020
+
+2012-04-07 09:52:09 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngdec.h:
+	* ext/libpng/gstpngenc.c:
+	* ext/libpng/gstpngenc.h:
+	  png: Port to base video classes
+	  Conflicts:
+	  ext/libpng/gstpngdec.c
+	  ext/libpng/gstpngdec.h
+	  ext/libpng/gstpngenc.c
+	  ext/libpng/gstpngenc.h
+	  Reverted to 0.10, needs to be ported again.
+
+2012-05-27 00:02:08 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	* gst/matroska/matroska-read-common.c:
+	  flv, matroska: don't use GstStructure API on tag lists
+
+2012-05-26 11:57:16 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp2tdepay.c:
+	  rtpmp2tdepay: Only output integral mpeg-ts packets
+	  From RFC 2250
+	  2. Encapsulation of MPEG System and Transport Streams
+	  ...
+	  For MPEG2 Transport Streams the RTP payload will contain an integral
+	  number of MPEG transport packets.  To avoid end system
+	  inefficiencies, data from multiple small MTS packets (normally fixed
+	  in size at 188 bytes) are aggregated into a single RTP packet.  The
+	  number of transport packets contained is computed by dividing RTP
+	  payload length by the length of an MTS packet (188).
+	  ....
+	  Since it needs to contain "an integral number of MPEG transport packets", a
+	  simple fix is to check that's the case, and strip off any leftover data.
+	  Fixes #676799
+	  Conflicts:
+	  gst/rtp/gstrtpmp2tdepay.c
+
+2012-05-24 20:43:16 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/cocoawindow.h:
+	* sys/osxvideo/cocoawindow.m:
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: make sure all selectors are performed on the same thread
+	  When we are using a dedicated thread to run the main run loop we
+	  must make sure that all selectors are performed on this same thread.
+	  For instance if performSelectorOnMainThread is called from the real
+	  main thread, it will not go through the message queue and will be
+	  executed from the real main thread. By forcing the target thread,
+	  we ensure that all functions will be called either from the real
+	  main thread when the main run loop is running or from our thread
+	  spinning the main loop.
+
+2012-05-24 16:09:54 +0200  Mathias Hasselmann <mathias.hasselmann at gmx.de>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: remove framerate
+	  The jpeg decoder doesn't need/care about the framerate to so it should
+	  not be in the caps.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=676302
+
+2012-05-24 13:08:35 +0200  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: start the loop before calling [gstview haveSuperview]
+	  ...as haveSuperview requires the mainloop to be running
+
+2012-05-24 13:08:13 +0200  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: fix indentation
+
+2012-05-22 16:47:36 +0200  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* sys/osxvideo/Makefile.am:
+	  osxvideosink: enable running the cocoa main runloop in a thread
+
+2012-05-22 16:45:28 +0200  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: add code to optionally run the cocoa main runloop in a separate thread
+	  Add a little hack to run the cocoa main runloop from a separate thread _when_
+	  the main runloop is not being run (which means that the app doesn't use cocoa).
+	  Runloops are thread specific, so the hack boils down to getting the runloop for
+	  the main thread and setting it as the runloop for our dedicated thread.
+
+2012-05-22 16:32:53 +0200  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: reset app_started to FALSE when shutting down
+
+2012-05-22 14:49:17 +0200  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: rename cocoa runloop helper funcs
+
+2012-05-22 14:26:13 +0200  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: don't create application menus
+
+2012-05-16 21:52:45 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: reset the embed property for backward compatilibity
+
+2012-05-16 21:12:22 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/cocoawindow.h:
+	* sys/osxvideo/cocoawindow.m:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: fix navigation when force-aspect-ratio is activated
+
+2012-05-16 18:52:45 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/cocoawindow.h:
+	* sys/osxvideo/cocoawindow.m:
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: add force-aspect-ratio property
+
+2012-05-14 18:01:02 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/cocoawindow.h:
+	* sys/osxvideo/cocoawindow.m:
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: start internal window if no view is provided
+
+2012-05-14 14:27:58 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/cocoawindow.h:
+	* sys/osxvideo/cocoawindow.m:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: implement the navigation interface
+
+2012-05-11 18:24:08 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osvideosink: create, destroy, resize and draw from the main thread
+
+2012-04-19 08:37:28 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: increase NEWSEGMENT accuracy after seeking
+	  demux->common.segment is populated during seek handling with the target
+	  start/stop positions. Don't override them when sending out a NEWSEGMENT.
+	  Conflicts:
+	  gst/matroska/matroska-demux.c
+
+2012-04-19 08:31:00 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: don't discard the incoming seek segment on push based seeking
+	  The incoming seek segment was being discarded leading to push based seeking
+	  being potentially inaccurate.
+
+2012-05-23 18:12:24 +0200  Sebastian Rasmussen <sebrn@axis.com>
+
+	* common:
+	  common: Update so the plugin scanner changes are included
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=676674
+
+2012-05-23 18:07:35 +0200  Sebastian Rasmussen <sebrn@axis.com>
+
+	* configure.ac:
+	  configure: suppress some warnings when debug is disabled
+	  Warnings about unused variables should be suppressed if core has the
+	  debug system disabled.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=676671
+
+2012-05-24 09:29:25 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtp: fix build issue in gstrtph264pay.c
+
+2012-05-21 12:17:35 +0200  Jonas Holmberg <jonashg@axis.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: Add unrestricted caps
+	  If there are no profile restrictions downstream, return caps with
+	  profile=constrained-baseline in the first structure and append
+	  unrestricted caps as the last structure.
+	  Fixes bug #672019
+
+2012-05-24 09:57:31 +0200  Maria Giovanna Chiossa <mariagiovanna.chiossa at selexelsag.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtsp: add the Scale header when needed
+	  Setting GST_SEEK_FLAG_SKIP when sending a seek event in rtspsrc should
+	  set the "Scale" field in the rtsp PLAY header.
+	  Because the boolean "src->skip" is set after the call, "Speed" instead
+	  of "Scale" is always set. Move the assignment before issuing the _play
+	  request.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=676618
+
+2012-05-17 16:23:59 +0300  Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Fix the sample pipeline.
+
+2012-05-22 12:35:04 +0400  Anton Novikov <random.plant@gmail.com>
+
+	* gst/icydemux/gsticydemux.c:
+	  icydemux: warning if setting srcpad caps fails
+
+2012-05-22 12:35:29 +0400  Anton Novikov <random.plant@gmail.com>
+
+	* gst/icydemux/gsticydemux.c:
+	  icydemux: activate srcpad before setting caps
+	  Before gst_pad_set_active() is called, the pad has
+	  FLUSHING flag set, so setting the caps fails
+
+2012-05-22 13:46:27 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* ext/Makefile.am:
+	* ext/libmng/Makefile.am:
+	* ext/libmng/gstmng.c:
+	* ext/libmng/gstmng.h:
+	* ext/libmng/gstmngdec.c:
+	* ext/libmng/gstmngdec.h:
+	* ext/libmng/gstmngenc.c:
+	* ext/libmng/gstmngenc.h:
+	  mng: remove ext/libmng
+	  Port to 0.10 was never finished.
+	  Interest was lost.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=324364
+
+2012-05-18 16:37:04 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/avi/gstavimux.c:
+	  avimux: fix assertion when handling a date tag as a string
+	  Date tags are GDate, not strings. Add a special case to convert
+	  it to the exif date format representation in string to avoid
+	  the assertion
+
+2012-05-21 11:47:07 +0200  Sjoerd Simons <sjoerd@luon.net>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: Listen to source output events, not sink input
+
+2012-05-18 12:53:44 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp2tpay.c:
+	  rtpmp2tpay: respect mtu and packet boundaries
+	  See #659915.
+
+2012-05-18 11:10:46 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpeg: Remove dead code
+	  Conflicts:
+	  ext/jpeg/gstjpegdec.c
+
+2012-05-18 11:05:35 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Fix compilation
+
+2012-05-18 11:02:52 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: When dropping frames on EOS, flush out data
+	  Cleaner way of handling stray data
+
+2012-05-17 09:34:03 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: Remove unused variable
+	  Conflicts:
+	  ext/jpeg/gstjpegdec.c
+
+2012-05-17 09:33:18 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Only parse for SOI when we didn't see it before
+
+2012-05-17 09:31:41 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Remember if we saw SOI and handle stray data on EOS
+
+2012-05-15 20:58:25 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: Allow U and V components to use different quant tables if they contain the same data
+	  This allows some cameras (Logitech C920) that specify different quant
+	  tables but both with the same data, to work.
+	  Bug reported by Robert Krakora
+
+2012-05-14 15:51:29 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: fix possible data corruption after seeking
+	  Consider a downstream element that may issue seeks in very short
+	  succession (e.g. queue2), depending on the access pattern of
+	  the downstream element (e.g. qtdemux with audio/video chunks
+	  interleaved so that there's always a sizeable gap between the
+	  current chunks for each stream). In this case, queue2 will maintain
+	  two ranges, and even when it serves a chunk from memory, it will
+	  switch ranges and make souphttpsrc seek to the end of the available
+	  data for that range, assuming that that's where we'll want to
+	  continue reading from next.
+	  This may lead to the following seek request pattern:
+	  - source reading position A
+	  - seek to B
+	  - now reading position still A, requested_postion is B
+	  - streaming thread to be restarted to continue from B
+	  - seek to A, before streaming thread had time to do the seek
+	  - do_seek() now sees reading position == seek position and
+	  returns early.
+	  - however, requested position is still B from the earlier
+	  seek request
+	  - streaming thread starts up, sees that a seek to B is pending
+	  and requests data from B from the server, while the GstBaseSrc
+	  segment has of course been updated/reset to position A, which
+	  was the last seek request.
+	  - we will now send data for position B and pretend that's the
+	  data from position A (via the newsegment event, etc.)
+	  - this causes data corruption
+	  Reproducible doing seek-emulated fast-forward/backward on 006648.
+
+2012-05-16 09:12:55 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Require core/base 0.11.91
+
+2012-01-13 18:09:50 -0500  Matej Knopp <matej.knopp@gmail.com>
+
+	* .gitignore:
+	  .gitignore: add visual studio IDE files and OS X .DS_Store files
+	  https://bugzilla.gnome.org/show_bug.cgi?id=667899
+
+2012-05-03 09:32:50 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstjpegenc.h:
+	  jpeg: Port to 0.11 again
+
+2012-04-06 12:13:24 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstjpegenc.h:
+	  jpeg: Port jpegdec/jpegenc to base video classes
+	  Conflicts:
+	  ext/jpeg/gstjpegdec.c
+	  ext/jpeg/gstjpegdec.h
+	  ext/jpeg/gstjpegenc.c
+	  ext/jpeg/gstjpegenc.h
+	  Reverted to 0.10 versions for now, next port again.
+
+2012-05-13 19:21:19 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* ext/Makefile.am:
+	* ext/annodex/Makefile.am:
+	* ext/annodex/gstannodex.c:
+	* ext/annodex/gstannodex.h:
+	* ext/annodex/gstcmmldec.c:
+	* ext/annodex/gstcmmldec.h:
+	* ext/annodex/gstcmmlenc.c:
+	* ext/annodex/gstcmmlenc.h:
+	* ext/annodex/gstcmmlparser.c:
+	* ext/annodex/gstcmmlparser.h:
+	* ext/annodex/gstcmmltag.c:
+	* ext/annodex/gstcmmltag.h:
+	* ext/annodex/gstcmmlutils.c:
+	* ext/annodex/gstcmmlutils.h:
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/cmmldec.c:
+	* tests/check/elements/cmmlenc.c:
+	  annodex: remove annodex plugin and CMML elements
+	  This never really took off and is most likely completely
+	  unused. If there is still a need for this, it should
+	  probably be done differently, perhaps inside oggdemux/mux.
+
+2012-05-13 16:59:58 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  Back to development
+
+=== release 0.11.91 ===
+
+2012-05-13 16:31:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* common:
+	* configure.ac:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.11.91
+
+2012-05-13 16:30:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2012-05-13 15:56:05 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From dc70203 to 3429ba6
+
+2012-05-09 15:14:55 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/debugutils/rndbuffersize.c:
+	  rndbuffersize: only send flush-stop if it was a flushing seek
+
+2012-05-09 12:54:11 +0200  Peter Seiderer <ps.report@gmx.net>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2src: fix v4l2_std_id logging
+	  input.std is of type v4l2_std_id which is defined as 64-bit unsigned integer.
+	  Casting to uint means the higher bits, wich are used for the private video
+	  standards of the TI video capture/display driver for example, are lost.
+
+2012-05-09 12:24:37 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/debugutils/rndbuffersize.c:
+	  rndbuffersize: must send flush-stop after acquiring the stream lock
+	  Otherwise the streaming thread might just keep on going and we
+	  might never get the stream lock.
+
+2012-05-09 11:15:21 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/debugutils/rndbuffersize.c:
+	  rndbuffersize: port seeking code to 0.11
+
+2012-05-08 19:07:04 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/debugutils/rndbuffersize.c:
+	  rndbuffersize: add support for seeks
+	  Useful for e.g. filesrc ! rndbuffersize ! queue2 ! ...
+
+2012-05-08 18:45:34 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/debugutils/rndbuffersize.c:
+	  rndbuffersize: send SEGMENT event before pushing buffers
+	  Conflicts:
+	  gst/debugutils/rndbuffersize.c
+
+2012-05-09 11:15:57 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/interleave/interleave.c:
+	  interleave: fix compilation again
+
+2012-01-13 10:49:43 +0100  Pascal Buhler <pabuhler@cisco.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: creation should be signaled before validation
+	  https://bugzilla.gnome.org/show_bug.cgi?id=667850
+
+2012-05-04 15:20:47 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: do not proxy our filter caps downstream on caps queries
+	  Downstream likely won't accept video/x-raw and the caps query
+	  will return EMPTY caps. Instead, create a copy of the caps that
+	  has all structure names replaced by 'image/jpeg'
+	  Simple pipeline that shows the problem:
+	  gst-launch-1.0 videotestsrc num-buffers=1 ! "video/x-raw, \
+	  width=(int)640, height=(int)480" ! videoscale ! jpegenc ! \
+	  "image/jpeg, width=(int)800, height=(int)600" ! filesink \
+	  location=/tmp/image.jpg
+
+2012-05-02 21:17:43 +0200  Alban Browaeys <prahal@yahoo.com>
+
+	* gst/isomp4/qtdemux.c:
+	  isomp4: set layout=interleaved on raw audio caps
+	  This fixes a not-negotiated error at least on mov files with
+	  twos audio with two channels and video dvcp. As playbin and gst-launch
+	  sample coming from the qtdemux.c file uses audioconvert and the latter
+	  require format interleaved.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=675326
+
+2012-05-02 21:49:56 +0400  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* sys/waveform/Makefile.am:
+	  waveform: No more gstinterfaces
+	  Fixes #675319
+
+2012-05-02 20:14:24 +0400  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* sys/directsound/Makefile.am:
+	  directsound: No more gstinterfaces
+	  Fixes #675319
+
+2012-05-01 18:58:03 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	  videomixer: change sink pad template name from sink_%d to sink_%u
+
+2012-04-30 11:00:19 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/interleave/interleave.c:
+	  interleave: handle EOS on all pads
+	  When all pads go to EOS immediately, we are not negotiated and our collected
+	  function is called (without any available data). Handle this case gracefully.
+	  Conflicts:
+	  gst/interleave/interleave.c
+
+2012-04-30 10:59:31 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/interleave/interleave.c:
+	  interleave: improve debugging
+
+2012-05-01 13:31:51 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: Update for basesrc API changes
+
+2012-04-30 23:57:28 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: don't set up stuff before the input and output formats are known
+	  Fixes crash on startup.
+
+2012-04-30 14:09:23 +0200  Peter Seiderer <ps.report@gmx.net>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: don't write stream header twice for first file
+
+2012-04-30 13:32:41 +0200  Peter Seiderer <ps.report@gmx.net>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: fix buffer list size calculation in render_list
+	  Fix uninitialized 'size' variable in call to gst_buffer_list_foreach().
+
+2012-04-30 21:58:00 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/multifile/gstmultifilesrc.c:
+	  multifile: unnecessary size check
+
+2012-04-30 21:30:56 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* gst/avi/gstavidemux.c:
+	  avi: fix build errors
+	  fix redundant declarations
+	  and also style/indent issues
+
+2012-04-26 12:47:27 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: implement forward snapping keyframe seeking
+	  Requires an index.
+
+2012-04-26 12:46:11 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avi: implement forward snapping keyframe seeking
+	  In pull mode with an index.
+
+2012-04-28 23:14:24 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/matroskamux.c:
+	  tests: fix matroskamux unit test after media type changes
+
+2012-04-28 19:57:51 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/webm-mux.c:
+	  matroska: update for media type changes
+
+2012-04-24 16:08:47 +0200  idc-dragon <idc-dragon at gmx.de>
+
+	* gst/rtp/gstrtpceltdepay.c:
+	  celtdepay: calculate size correctly
+	  The summation was done wrong, causing the de-payloader to exit its loop too
+	  early, before all frames are processed.
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=674472
+
+2012-04-24 15:57:19 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: improve debug
+
+2012-04-24 15:34:57 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: start unmuted when requested
+	  When we explicitely set the mute property to FALSE, connect to pulseaudio with
+	  the PA_STREAM_START_UNMUTED flag set, otherwise pulseaudio will use its
+	  previously used value (which might start the stream muted).
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=672401
+
+2012-04-25 09:41:46 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: improve timestamp code
+	  Sample the pipeline clock and device clock closer to eachother to reduce jitter.
+	  Don't subtract the frame duration from the timestamp when we can use the device
+	  timestamps.
+	  Assume a delay of 1 frame in read-write mode.
+
+2012-04-24 12:37:33 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: use driver timestamps
+	  Use the drive timestamps for timestamping outgoing buffers.
+
+2012-04-23 18:01:31 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: Improve buffer management
+	  Query the amount of available buffers when doing set_config(). This allows us to
+	  configure the parent bufferpool with the number of buffers to preallocate.
+	  Keep track of the provided allocator and use it when we need to allocate a
+	  buffer in RW mode.
+	  When we are can not allocate the requested max_buffers amount of buffers, make
+	  sure we keep 2 buffers around in the pool and copy them into an output buffer.
+	  This makes sure that we always have a buffer to capture into. We also need to
+	  detect those copied buffers and unref them when they return to the pool.
+
+2012-04-23 16:51:28 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: free the queued buffers
+	  Only free the queued buffers that we keep track of in our buffer array. for rw
+	  io-mode, we do allocate buffers but we don't keep track of them in the buffer
+	  array.
+
+2012-04-23 16:10:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: mark memory as no-share
+	  We don't support sharing our mmapped memory so mark it as NO_SHARE.
+
+2012-04-23 16:09:55 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2: remove old unused file
+
+2012-04-23 13:32:48 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2: remove unused function
+
+2012-04-11 12:42:17 +0100  Bastien Nocera <hadess@hadess.net>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  soup: Handle icy and icyx URI schemes
+	  As handled by QuickTime (for icy), and Orban/Coding Technologies
+	  AAC/aacPlus Player (for icyx). See also:
+	  https://bugzilla.gnome.org/show_bug.cgi?id=394207
+	  https://bugzilla.gnome.org/show_bug.cgi?id=403285
+	  https://bugzilla.gnome.org/show_bug.cgi?id=673899
+
+2012-04-23 10:03:19 +0300  Mart Raudsepp <mart.raudsepp@collabora.com>
+
+	* sys/v4l2/gstv4l2src.c:
+	  docs: Add Since tag for new GstV4l2Src::prepare-format signal
+
+2012-04-23 10:07:12 +0200  Chris Pankow <kain2396@gmail.com>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	  audiofxbasefirfilter: Fix time-domain convolution for multichannel input
+	  Fixes bug #674025.
+
+2012-04-21 11:08:51 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* po/POTFILES.in:
+	  po: remove some more non-existent files from the list
+
+2012-04-21 10:05:45 +0400  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* po/POTFILES.in:
+	  po: Remove non-existent potfiles from the list
+	  Fixes #674518
+
+2012-04-20 18:13:15 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/icles/test-oss4.c:
+	  tests: oss4: limit test scope
+
+2012-04-20 18:13:01 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* sys/oss4/Makefile.am:
+	* sys/oss4/oss4-audio.c:
+	* sys/oss4/oss4-audio.h:
+	* sys/oss4/oss4-mixer-enum.c:
+	* sys/oss4/oss4-mixer-enum.h:
+	* sys/oss4/oss4-mixer-slider.c:
+	* sys/oss4/oss4-mixer-slider.h:
+	* sys/oss4/oss4-mixer-switch.c:
+	* sys/oss4/oss4-mixer-switch.h:
+	* sys/oss4/oss4-mixer.c:
+	* sys/oss4/oss4-mixer.h:
+	* sys/oss4/oss4-property-probe.c:
+	* sys/oss4/oss4-property-probe.h:
+	* sys/oss4/oss4-sink.c:
+	* sys/oss4/oss4-sink.h:
+	* sys/oss4/oss4-source.c:
+	* sys/oss4/oss4-source.h:
+	  oss4: port to 0.11
+
+2012-04-20 18:12:54 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* sys/oss/Makefile.am:
+	* sys/oss/gstossaudio.c:
+	* sys/oss/gstosshelper.c:
+	* sys/oss/gstosshelper.h:
+	* sys/oss/gstossmixer.c:
+	* sys/oss/gstossmixer.h:
+	* sys/oss/gstossmixerelement.c:
+	* sys/oss/gstossmixerelement.h:
+	* sys/oss/gstossmixertrack.c:
+	* sys/oss/gstossmixertrack.h:
+	* sys/oss/gstosssink.c:
+	* sys/oss/gstosssrc.c:
+	* sys/oss/gstosssrc.h:
+	  oss: port to 0.11
+
+2012-04-20 16:49:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/multipart/multipartdemux.c:
+	  multipartdemux: first activate pad then set caps
+
+2012-04-20 13:35:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: set caps on srcpad
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=674219
+
+2012-04-19 14:16:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: update for video api change
+
+2012-04-19 12:38:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: fix compilation on older v4l2
+	  Fix compilation on systems where the H264 format is not defined.
+
+2012-04-19 12:20:59 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/dv/gstdvdec.c:
+	* ext/raw1394/Makefile.am:
+	* gst/rtp/gstrtpvrawpay.c:
+	* gst/y4m/gsty4mencode.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	  video: Update for libgstvideo API changes
+
+2012-04-19 08:27:01 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2src: Allow mpeg-ts cameras to negociate format
+	  This removes an ugly hack until the reason for the hack can be documented
+
+2012-04-19 09:50:25 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2src: Fix merge
+
+2012-04-19 09:40:53 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2src: Rename pre-set-format signal to prepare-format
+
+2012-04-16 22:08:21 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2src: Add H264 encoded stream support to the caps
+	  This is not enough to properly support H264 cameras, but it will
+	  allow an H264 stream to be generated by v4l2src using the default
+	  settings of the camera. If used with the pre-set-format signal, the
+	  H264 encoder can be fully configured.
+	  Conflicts:
+	  sys/v4l2/gstv4l2object.c
+
+2012-04-16 22:06:21 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* sys/v4l2/.gitignore:
+	* sys/v4l2/gstv4l2-marshal.list:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2src: Adding a pre-set-format signal
+	  In order to support UVC H264 encoding cameras, an H264 Probe&Commit
+	  must happen before the normal v4l2 set-format. This new signal is
+	  meant to allow an external application or bin to do it.
+	  It also serves to expose the file descriptor used by v4l2src in case
+	  some custom ioctls need to be called.
+	  Conflicts:
+	  sys/v4l2/Makefile.am
+	  sys/v4l2/gstv4l2src.c
+	  sys/v4l2/v4l2src_calls.c
+
+2012-04-18 17:09:45 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* ext/raw1394/gst1394probe.c:
+	* ext/raw1394/gst1394probe.h:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	  dv1394: port to 0.11
+
+2012-04-17 15:14:27 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/cairo/gsttextoverlay.c:
+	* ext/cairo/gsttextoverlay.h:
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavimux.h:
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	* gst/interleave/interleave.c:
+	* gst/interleave/interleave.h:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	* gst/multipart/multipartmux.c:
+	* gst/multipart/multipartmux.h:
+	* gst/smpte/gstsmpte.c:
+	* gst/smpte/gstsmpte.h:
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	* gst/videomixer/videomixer2pad.h:
+	  collectpads2: rename to collectpads
+
+2012-04-16 16:37:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/interleave/interleave.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/smpte/gstsmpte.c:
+	* gst/videomixer/videomixer2.c:
+	  misc: chain up to collectpads event handler
+
+2012-04-16 09:09:11 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 6db25be to dc70203
+
+2012-04-15 22:49:47 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/shout2/gstshout2.c:
+	  shout2: update for ogg media type changes
+
+2012-04-13 16:54:53 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/smpte/gstsmpte.c:
+	* gst/smpte/gstsmpte.h:
+	  smpte: use some more boilerplate
+
+2012-04-13 16:54:50 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flx/gstflxdec.c:
+	  flxdec: improve segment handling
+	  ... to send a proper TIME segment downstream.
+
+2012-04-13 16:54:46 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* gst/flx/gstflxdec.c:
+	* gst/flx/gstflxdec.h:
+	  flxdec: port to 0.11
+
+2012-04-13 16:54:42 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	* gst/videobox/gstvideobox.h:
+	  videobox: adjust to deprecated GMutex setup
+
+2012-04-13 16:54:38 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* gst/videobox/gstvideobox.c:
+	* gst/videobox/gstvideobox.h:
+	  videobox: port to 0.11
+
+2012-04-13 16:54:31 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalphacolor.c:
+	* gst/smpte/gstsmptealpha.c:
+	  alpha, smpte: adjust to removed color-matrix caps field
+
+2012-04-13 16:27:34 +0200  Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
+
+	* sys/v4l2/Makefile.am:
+	  v4l2: ensure autogenerated files are created
+	  The tuner marshal and enumtypes are autogenerated, and they need
+	  to be created before the compilation of gstv4l2tuner.c
+	  This patch adds the automake instruction for ensuring the
+	  autogeneration of those files previous the compilation.
+
+2012-04-13 13:41:44 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* autogen.sh:
+	* configure.ac:
+	  configure: Modernize autotools setup a bit
+	  Also we now only create tar.bz2 and tar.xz tarballs.
+
+2012-04-13 13:37:10 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 464fe15 to 6db25be
+
+2012-04-13 13:04:12 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* ext/pulse/Makefile.am:
+	* ext/pulse/plugin.c:
+	* ext/pulse/pulsemixer.c:
+	* ext/pulse/pulsemixer.h:
+	* ext/pulse/pulsemixerctrl.c:
+	* ext/pulse/pulsemixerctrl.h:
+	* ext/pulse/pulsemixertrack.c:
+	* ext/pulse/pulsemixertrack.h:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulsesrc.h:
+	* gst/rtsp/Makefile.am:
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2tuner.h:
+	* sys/v4l2/gstv4l2videooverlay.c:
+	* sys/v4l2/gstv4l2videooverlay.h:
+	* sys/v4l2/tuner-marshal.list:
+	* sys/v4l2/tuner.c:
+	* sys/v4l2/tuner.h:
+	* sys/v4l2/tunerchannel.c:
+	* sys/v4l2/tunerchannel.h:
+	* sys/v4l2/tunernorm.c:
+	* sys/v4l2/tunernorm.h:
+	* tests/check/Makefile.am:
+	* tests/examples/pulse/Makefile.am:
+	* tests/icles/Makefile.am:
+	* tests/icles/v4l2src-test.c:
+	  Update everything for the removal of the interface library and mixer/tuner interfaces
+
+2012-04-12 15:50:16 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/rtp/gstrtpmparobustdepay.c:
+	  rtp: Use unchecked variant of GstByteWriter where applicable
+	  The size was checked before
+
+2012-04-12 15:49:44 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/matroska/ebml-read.c:
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/matroska-demux.c:
+	  matroska: Check return value of GstByteReader/Writer
+
+2012-04-12 15:48:57 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_dump.c:
+	  isomp4: Check return value of GstByteWriter
+	  And use unchecked variant of GstByteReader where applicable
+
+2012-04-12 15:48:00 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Use unchecked variant of GstByteReader
+	  We know there's at least 7 bytes (checked above)
+
+2012-04-12 15:47:49 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avi: Check return value of GstByteWriter
+
+2012-04-12 15:47:24 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	  audioparsers: Check return value of GstBitReader/GstByteReader
+
+2012-04-12 11:57:59 +0100  uraeus <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  Add interleave plugin to spec file
+
+2012-04-12 11:19:01 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  Back to development
+
+=== release 0.11.90 ===
+
+2012-04-12 10:27:31 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/gst-plugins-good-plugins.prerequisites:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* gst/deinterlace/tvtime-dist.c:
+	* gst/videobox/gstvideoboxorc-dist.c:
+	* gst/videomixer/blendorc-dist.c:
+	* win32/common/config.h:
+	  Release 0.11.90
+
+2012-04-12 10:26:52 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2012-04-11 00:19:30 +0400  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* ext/jpeg/gstjpegenc.c:
+	  Fix format string
+	  Fixes #673859
+
+2012-04-11 00:19:16 +0400  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* sys/waveform/gstwaveformsink.c:
+	  Remove unused variable
+	  Fixes #673859
+
+2012-04-10 11:57:53 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  Merge remote-tracking branch 'origin/0.10'
+	  Conflicts:
+	  gst/flv/gstflvdemux.c
+	  gst/matroska/matroska-demux.c
+
+2012-04-10 11:37:48 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: some more segment handling tweaking
+
+2012-04-10 00:51:41 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/aalib/gstaasink.c:
+	* ext/annodex/gstcmmldec.c:
+	* ext/annodex/gstcmmlenc.c:
+	* ext/cairo/gstcairooverlay.c:
+	* ext/cairo/gstcairorender.c:
+	* ext/cairo/gsttextoverlay.c:
+	* ext/cairo/gsttimeoverlay.c:
+	* ext/dv/gstdvdec.c:
+	* ext/dv/gstdvdemux.c:
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflactag.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	* ext/gdk_pixbuf/pixbufscale.c:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstsmokedec.c:
+	* ext/jpeg/gstsmokeenc.c:
+	* ext/libcaca/gstcacasink.c:
+	* ext/libmng/gstmngdec.c:
+	* ext/libmng/gstmngenc.c:
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngenc.c:
+	* ext/mikmod/gstmikmod.c:
+	* ext/pulse/pulsemixer.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	* ext/shout2/gstshout2.c:
+	* ext/soup/gstsouphttpclientsink.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	* ext/taglib/gstapev2mux.cc:
+	* ext/taglib/gstid3v2mux.cc:
+	* ext/wavpack/gstwavpackdec.c:
+	* ext/wavpack/gstwavpackenc.c:
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalphacolor.c:
+	* gst/apetag/gstapedemux.c:
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audiofirfilter.c:
+	* gst/audiofx/audioiirfilter.c:
+	* gst/audiofx/audioinvert.c:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/audiofx/audiopanorama.c:
+	* gst/audiofx/audiowsincband.c:
+	* gst/audiofx/audiowsinclimit.c:
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	* gst/auparse/gstauparse.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavisubtitle.c:
+	* gst/cutter/gstcutter.c:
+	* gst/debugutils/breakmydata.c:
+	* gst/debugutils/cpureport.c:
+	* gst/debugutils/gstcapsdebug.c:
+	* gst/debugutils/gstcapssetter.c:
+	* gst/debugutils/gstnavigationtest.c:
+	* gst/debugutils/gstnavseek.c:
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/debugutils/gsttaginject.c:
+	* gst/debugutils/progressreport.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/debugutils/testplugin.c:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstop.c:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstripple.c:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gststreak.c:
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstwarp.c:
+	* gst/equalizer/gstiirequalizer10bands.c:
+	* gst/equalizer/gstiirequalizer3bands.c:
+	* gst/equalizer/gstiirequalizernbands.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/flx/gstflxdec.c:
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/id3demux/gstid3demux.c:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/interleave/deinterleave.c:
+	* gst/interleave/interleave.c:
+	* gst/isomp4/gstqtmoovrecover.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstrtpxqtdepay.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/level/gstlevel.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/webm-mux.c:
+	* gst/median/gstmedian.c:
+	* gst/monoscope/gstmonoscope.c:
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/multifile/gstsplitfilesrc.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartmux.c:
+	* gst/replaygain/gstrganalysis.c:
+	* gst/replaygain/gstrglimiter.c:
+	* gst/replaygain/gstrgvolume.c:
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpg722depay.c:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtpg723depay.c:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmparobustdepay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtppcmupay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpsirenpay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtsp/gstrtpdec.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/smpte/gstsmpte.c:
+	* gst/smpte/gstsmptealpha.c:
+	* gst/spectrum/gstspectrum.c:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	* gst/videobox/gstvideobox.c:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videofilter/gstvideotemplate.c:
+	* gst/videomixer/videomixer2.c:
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavparse/gstwavparse.c:
+	* gst/y4m/gsty4mencode.c:
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/oss/gstossmixerelement.c:
+	* sys/oss/gstosssink.c:
+	* sys/oss/gstosssrc.c:
+	* sys/oss4/oss4-mixer.c:
+	* sys/oss4/oss4-sink.c:
+	* sys/oss4/oss4-source.c:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxvideo/osxvideosink.m:
+	* sys/sunaudio/gstsunaudiomixer.c:
+	* sys/sunaudio/gstsunaudiosink.c:
+	* sys/sunaudio/gstsunaudiosrc.c:
+	* sys/v4l2/gstv4l2radio.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/waveform/gstwaveformsink.c:
+	* sys/ximage/gstximagesrc.c:
+	  Use new gst_element_class_set_static_metadata()
+
+2012-04-09 12:55:34 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/pipelines/simple-launch-lines.c:
+	  tests: disable simple smokeenc/dec launch lines test
+	  Disable test for smoke elements, which aren't ported yet
+	  (and maybe shouldn't be ported).
+
+2012-04-09 00:14:48 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/interleave/interleave.c:
+	* gst/interleave/interleave.h:
+	* tests/check/elements/interleave.c:
+	  interleave: make channel-poisitions property a GValueArray again
+	  Or perhaps it should just be a guint64 channel mask, which would
+	  be nicer in C, but more awkward for bindings (even more so since
+	  we can't add a flags type for it, since that only supports guint
+	  size flags). Fixes wavenc unit test.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=669643
+
+2012-04-06 16:03:47 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: cleanly initialize and set needed segment
+	  Fixes #673165.
+
+2012-04-05 17:17:22 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Fix threading issue in index handling
+
+2012-04-06 09:13:31 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Don't use static variables to hold index associations
+	  This not really threadsafe in any way.
+
+2012-04-05 19:17:48 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/flvmux.c:
+	* tests/check/elements/interleave.c:
+	  tests: make few tests more valgrind-friendly
+
+2012-04-05 19:17:42 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* tests/check/elements/deinterleave.c:
+	  (de)interleave: fix ported unit test and enable as ported
+
+2012-04-05 19:17:38 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/cmmldec.c:
+	  tests: cmmldec: adjust to tag events no longer posted on bus by element
+
+2012-04-05 19:17:29 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  updsrc: clear error
+
+2012-04-05 18:42:53 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 7fda524 to 464fe15
+
+2012-04-05 18:02:56 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/dtmf/gstdtmf.c:
+	  gst: Update for GST_PLUGIN_DEFINE() API changes
+
+2012-04-05 17:36:38 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/aalib/gstaasink.c:
+	* ext/annodex/gstannodex.c:
+	* ext/cairo/gstcairo.c:
+	* ext/dv/gstdv.c:
+	* ext/flac/gstflac.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/jack/gstjack.c:
+	* ext/jpeg/gstjpeg.c:
+	* ext/libcaca/gstcacasink.c:
+	* ext/libmng/gstmng.c:
+	* ext/libpng/gstpng.c:
+	* ext/mikmod/gstmikmod.c:
+	* ext/pulse/plugin.c:
+	* ext/raw1394/gst1394.c:
+	* ext/shout2/gstshout2.c:
+	* ext/soup/gstsoup.c:
+	* ext/speex/gstspeex.c:
+	* ext/taglib/gsttaglibplugin.c:
+	* ext/wavpack/gstwavpack.c:
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalphacolor.c:
+	* gst/apetag/gstapedemux.c:
+	* gst/audiofx/audiofx.c:
+	* gst/audioparsers/plugin.c:
+	* gst/auparse/gstauparse.c:
+	* gst/autodetect/gstautodetect.c:
+	* gst/avi/gstavi.c:
+	* gst/cutter/gstcutter.c:
+	* gst/debugutils/gstdebug.c:
+	* gst/debugutils/gstnavigationtest.c:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/effectv/gsteffectv.c:
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/flx/gstflxdec.c:
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/id3demux/gstid3demux.c:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/interleave/plugin.c:
+	* gst/isomp4/isomp4-plugin.c:
+	* gst/law/alaw.c:
+	* gst/law/mulaw.c:
+	* gst/level/gstlevel.c:
+	* gst/matroska/matroska.c:
+	* gst/median/gstmedian.c:
+	* gst/monoscope/gstmonoscope.c:
+	* gst/multifile/gstmultifile.c:
+	* gst/multipart/multipart.c:
+	* gst/replaygain/replaygain.c:
+	* gst/rtp/gstrtp.c:
+	* gst/rtpmanager/gstrtpmanager.c:
+	* gst/rtsp/gstrtsp.c:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/smpte/plugin.c:
+	* gst/spectrum/gstspectrum.c:
+	* gst/udp/gstudp.c:
+	* gst/videobox/gstvideobox.c:
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videofilter/gstvideotemplate.c:
+	* gst/videofilter/plugin.c:
+	* gst/videomixer/videomixer2.c:
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavparse/gstwavparse.c:
+	* gst/y4m/gsty4mencode.c:
+	* sys/directsound/gstdirectsoundplugin.c:
+	* sys/oss/gstossaudio.c:
+	* sys/oss4/oss4-audio.c:
+	* sys/osxaudio/gstosxaudio.c:
+	* sys/osxvideo/osxvideosink.m:
+	* sys/sunaudio/gstsunaudio.c:
+	* sys/v4l2/gstv4l2.c:
+	* sys/waveform/gstwaveformplugin.c:
+	* sys/ximage/gstximagesrc.c:
+	  gst: Update for GST_PLUGIN_DEFINE() API changes
+
+2012-04-05 13:26:19 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Update version to 0.11.89.1
+
+2012-04-04 20:06:58 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/qtmux.c:
+	  tests: qtmux: ensure initialized test buffer memory
+
+2012-04-04 14:41:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/dtmf/Makefile.am:
+	  gst: Update versioning
+
+2012-04-04 14:33:23 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/version.entities.in:
+	* ext/aalib/Makefile.am:
+	* ext/cairo/Makefile.am:
+	* ext/dv/Makefile.am:
+	* ext/flac/Makefile.am:
+	* ext/gdk_pixbuf/Makefile.am:
+	* ext/jack/Makefile.am:
+	* ext/jpeg/Makefile.am:
+	* ext/libcaca/Makefile.am:
+	* ext/libpng/Makefile.am:
+	* ext/pulse/Makefile.am:
+	* ext/raw1394/Makefile.am:
+	* ext/soup/Makefile.am:
+	* ext/speex/Makefile.am:
+	* ext/taglib/Makefile.am:
+	* ext/wavpack/Makefile.am:
+	* gst-plugins-good.spec.in:
+	* gst/alpha/Makefile.am:
+	* gst/apetag/Makefile.am:
+	* gst/audiofx/Makefile.am:
+	* gst/audioparsers/Makefile.am:
+	* gst/auparse/Makefile.am:
+	* gst/avi/Makefile.am:
+	* gst/cutter/Makefile.am:
+	* gst/debugutils/Makefile.am:
+	* gst/deinterlace/Makefile.am:
+	* gst/effectv/Makefile.am:
+	* gst/equalizer/Makefile.am:
+	* gst/flv/Makefile.am:
+	* gst/icydemux/Makefile.am:
+	* gst/id3demux/Makefile.am:
+	* gst/interleave/Makefile.am:
+	* gst/isomp4/Makefile.am:
+	* gst/law/Makefile.am:
+	* gst/level/Makefile.am:
+	* gst/matroska/Makefile.am:
+	* gst/multifile/Makefile.am:
+	* gst/replaygain/Makefile.am:
+	* gst/rtp/Makefile.am:
+	* gst/rtpmanager/Makefile.am:
+	* gst/rtsp/Makefile.am:
+	* gst/shapewipe/Makefile.am:
+	* gst/smpte/Makefile.am:
+	* gst/spectrum/Makefile.am:
+	* gst/videobox/Makefile.am:
+	* gst/videocrop/Makefile.am:
+	* gst/videofilter/Makefile.am:
+	* gst/videomixer/Makefile.am:
+	* gst/wavenc/Makefile.am:
+	* gst/wavparse/Makefile.am:
+	* gst/y4m/Makefile.am:
+	* pkgconfig/Makefile.am:
+	* pkgconfig/gstreamer-plugins-good-uninstalled.pc.in:
+	* sys/directsound/Makefile.am:
+	* sys/oss/Makefile.am:
+	* sys/oss4/Makefile.am:
+	* sys/osxaudio/Makefile.am:
+	* sys/osxvideo/Makefile.am:
+	* sys/sunaudio/Makefile.am:
+	* sys/v4l2/Makefile.am:
+	* sys/waveform/Makefile.am:
+	* sys/ximage/Makefile.am:
+	* tests/check/Makefile.am:
+	* tests/examples/audiofx/Makefile.am:
+	* tests/examples/cairo/Makefile.am:
+	* tests/examples/pulse/Makefile.am:
+	* tests/examples/spectrum/Makefile.am:
+	* tests/icles/Makefile.am:
+	  gst: Update versioning
+
+2012-04-04 12:10:45 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	  Merge remote-tracking branch 'origin/0.10'
+	  Conflicts:
+	  gst/matroska/matroska-demux.c
+	  gst/matroska/matroska-mux.c
+	  gst/matroska/matroska-read-common.c
+	  gst/matroska/matroska-read-common.h
+
+2012-04-03 18:36:50 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: plug template caps leak
+
+2012-04-03 11:50:00 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: avi only knows about DTS
+	  Only set DTS on outgoing buffers unless we have a keyframe and then we can set
+	  the PTS to DTS as well.
+
+2012-04-02 23:35:43 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/matroska/matroska-read-common.c:
+	  mkv: port toc changes to 0.11
+
+2012-04-02 23:18:00 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	  Merge branch '0.10'
+	  Conflicts:
+	  gst/matroska/matroska-demux.c
+	  gst/matroska/matroska-mux.c
+	  gst/matroska/matroska-read-common.c
+	  gst/matroska/matroska-read-common.h
+
+2012-03-29 23:22:28 +0400  Alexander Saprykin <xelfium@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroska: add GstToc support for muxer
+
+2012-03-29 23:12:13 +0400  Alexander Saprykin <xelfium@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska: add support for GstToc in demuxer
+
+2012-03-29 23:05:14 +0400  Alexander Saprykin <xelfium@gmail.com>
+
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: add chapter support in GstMatroskaReadCommon
+
+2012-04-02 13:00:19 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/goom2k1/lines.c:
+	  goom2k1: Fix 'may be used uninitialized in this function' compiler warning
+
+2012-04-02 11:13:09 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audiofxbaseiirfilter.c:
+	* gst/audiofx/audioinvert.c:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	  use transform_ip_on_passthrough
+
+2012-03-31 15:43:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/equalizer/gstiirequalizer10bands.c:
+	* gst/equalizer/gstiirequalizer3bands.c:
+	* gst/videomixer/videomixer2.c:
+	* tests/check/elements/equalizer.c:
+	* tests/examples/equalizer/demo.c:
+	* tests/icles/equalizer-test.c:
+	  update for child proxy api change
+
+2012-03-30 18:13:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavisubtitle.c:
+	* gst/flv/gstflvmux.c:
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/udp/gstudpsrc.c:
+	* gst/y4m/gsty4mencode.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/ximage/ximageutil.c:
+	* tests/check/elements/deinterleave.c:
+	* tests/check/elements/interleave.c:
+	  update for buffer api change
+
+2012-03-30 12:53:44 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/speex/gstspeexenc.c:
+	* ext/speex/gstspeexenc.h:
+	  speexenc: Use new gst_audio_encoder_set_headers() API
+
+2012-03-30 12:18:45 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	* ext/speex/gstspeexenc.c:
+	* ext/wavpack/gstwavpackenc.c:
+	  ext: Update for GstAudioEncoder API changes
+
+2012-03-29 23:22:28 +0400  Alexander Saprykin <xelfium@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroska: add GstToc support for muxer
+
+2012-03-29 23:12:13 +0400  Alexander Saprykin <xelfium@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska: add support for GstToc in demuxer
+
+2012-03-29 23:05:14 +0400  Alexander Saprykin <xelfium@gmail.com>
+
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: add chapter support in GstMatroskaReadCommon
+
+2012-03-29 17:22:23 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/pipelines/wavpack.c:
+	  tests: wavpack: fewer buffers are also adequate and more convenient
+
+2012-03-29 17:22:19 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/videocrop.c:
+	  tests: videocrop: unmap video frame and unref caps
+
+2012-03-29 17:22:04 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/audiowsincband.c:
+	  tests: audiowsincband: unmap examined output buffers
+
+2012-03-29 17:21:53 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: plug ref leak
+
+2012-03-29 17:21:50 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audiofx/audiopanorama.c:
+	  audiopanorama: fix supported template caps and sample processing
+
+2012-03-29 17:21:43 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	  alphacolor: plug structure leak
+
+2012-03-29 16:04:26 +0100  uraeus <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  Update spec file with latest ported plugins
+
+2012-03-29 15:03:09 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	  Merge remote-tracking branch 'origin/0.10'
+	  Conflicts:
+	  configure.ac
+
+2012-03-28 16:26:56 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/pipelines/tagschecking.c:
+	  tests: tagschecking: muxers need TIME format
+
+2012-03-28 16:26:15 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/pipelines/flacdec.c:
+	  tests: flacdec: needs flacparse nowadays
+
+2012-03-28 14:49:03 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackenc.c:
+	  wavpackenc: query downstream for BYTE seeking support
+
+2012-03-28 14:48:46 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: query downstream for BYTE seeking support
+
+2012-03-28 14:46:03 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: clean up obsolete log statement
+
+2012-03-28 12:49:19 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/mikmod/gstmikmod.c:
+	* ext/wavpack/gstwavpackenc.c:
+	* gst/avi/gstavimux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/y4m/gsty4mencode.c:
+	* tests/check/elements/parser.c:
+	  update for buffer changes
+
+2012-03-28 12:16:45 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/audiodynamic.c:
+	  tests: audiodynamic: correctly port original test to mind in place transform
+
+2012-03-28 11:05:43 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	  audiofx: more adjustment to changed semantics of audiofilter _setup method
+
+2012-03-28 11:10:24 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/audiofirfilter.c:
+	  tests: audiofirfilter: negotiate the intended raw audio format
+
+2012-03-27 18:41:45 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/audioparsers/gstwavpackparse.c:
+	  wavpackparse: init datastructure
+
+2012-03-27 17:18:40 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstwarp.c:
+	  effectv: fix strides
+
+2012-03-27 16:41:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/smpte/gstsmpte.c:
+	* sys/oss/gstosssink.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/ximage/gstximagesrc.c:
+	* tests/check/elements/qtmux.c:
+	  caps: improve caps handling
+	  Avoid caps copy and leaks
+
+2012-03-27 14:04:48 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/icydemux.c:
+	  tests: icydemux: activate internal test helper src pad
+
+2012-03-27 12:44:46 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: update for get_param
+	  Remove const from the GstCaps.
+	  Plug some GstStructure leaks
+
+2012-03-27 00:02:08 +0300  Raimo Järvi <raimo.jarvi@gmail.com>
+
+	* configure.ac:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	  udp: Fix compiling with mingw.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=672880
+
+2012-03-26 18:31:41 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/rganalysis.c:
+	* tests/check/elements/rgvolume.c:
+	  tests: replaygain: misc compatibility fixes
+	  Discard caps event when checking for and counting various tag events,
+	  and remove all testing of 8 bits depth in 16 bits width format since
+	  it no longer exists.
+
+2012-03-26 18:28:26 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/rtp-payloading.c:
+	* tests/check/elements/rtpbin.c:
+	  tests: rtp: misc compatibiliy fixes
+	  ... such as always setting pad caps and providing needed caps fields.
+
+2012-03-26 18:26:40 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/videofilter.c:
+	  tests: videofilter: ensure initial segment event
+
+2012-03-26 18:25:28 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/shapewipe/gstshapewipe.h:
+	  shapewipe: proper video info and frame management
+	  ... particularly since each incoming pad has a distinct format.
+
+2012-03-26 18:24:08 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: ensure output caps are set when pushing output data
+	  ... even if some SPS/PPS has not passed by yet.
+
+2012-03-26 18:22:53 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	  videofilter: avoid holding object lock when calling basetransform function
+
+2012-03-26 18:22:03 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: fix some lock management
+	  ... to avoid trying to take a non-recursive lock twice.
+
+2012-03-26 18:21:11 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16pay.c:
+	  rtpL16(de)pay: fix raw audio format in template caps
+
+2012-03-26 18:20:40 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/replaygain/gstrganalysis.c:
+	  replaygain: also still post the results of the analysis
+
+2012-03-26 15:59:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: don't error in shutdown
+	  Don't log with the ERROR category when we are stopping because we are shutting
+	  down.
+	  Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=672824
+
+2012-03-26 15:51:28 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: fix latency
+
+2012-03-26 15:30:00 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2: called base class start
+	  Chain up to the base class start method so that metadata is properly tagged.
+	  Remove an unused variable.
+	  fixes: https://bugzilla.gnome.org/show_bug.cgi?id=672813
+
+2012-03-26 12:12:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Replace master with 0.11
+
+2012-03-25 00:00:59 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.h:
+	  gdkpixbufoverlay: add "alpha" property to set alpha of overlay image
+	  .. or turn the overlay off by setting alpha to 0.0
+
+2012-03-24 09:51:06 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: plug caps leak
+
+2012-03-23 18:47:45 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/imagefreeze.c:
+	  tests: imagefreeze: remove extraneous _unref
+
+2012-03-23 18:47:03 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/avimux.c:
+	  tests: avimux: adjust to modified sink pad template name
+
+2012-03-23 18:46:36 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/qtmux.c:
+	  tests: qtmux: cleanup element sooner
+	  ... to avoid stray refs in sticky caps events.
+
+2012-03-23 18:45:56 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/audiowsincband.c:
+	* tests/check/elements/audiowsinclimit.c:
+	* tests/check/elements/avimux.c:
+	* tests/check/elements/qtmux.c:
+	  tests: arrange for sending an initial segment event
+	  ... which is needed nowadays since various gst_segment_to_...
+	  no longer automatically set the format to the specified one
+	  (from _UNDEFINED).
+
+2012-03-23 18:44:15 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: immediately return GST_FLOW_EOS
+	  ... rather than _OK since we will not be caring about subsequent buffer
+	  anyway.
+
+2012-03-23 18:43:36 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: fix query and _getcaps handling
+
+2012-03-23 18:42:48 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/audiofx/audiofirfilter.c:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbasefirfilter.h:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/audiofx/audiowsincband.c:
+	* gst/audiofx/audiowsinclimit.c:
+	  audiofx: adjust to changed semantics of audiofilter _setup method
+	  ... in that it will now call subclass with info on proposed audio format
+	  without having set that info already in base class.  As such,
+	  subclass can not rely on audio format info being available there.
+
+2011-07-14 16:23:49 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264depay.h:
+	  rtph264depay: Make output in AVC stream format work even without complete sprop-parameter-set
+	  This allows outputting streams in AVC format even if the SPS/PPS are sent inside
+	  the RTP stream.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=654850
+	  Ported from master
+
+2012-01-29 18:39:54 +0000  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  udpsink: Unlock on error
+
+2012-03-22 18:27:30 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	  audioparsers: use sink pad template caps rather than src
+
+2012-03-22 18:23:22 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2012-03-22 18:21:52 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* gst/smpte/gstsmpte.c:
+	* gst/smpte/gstsmpte.h:
+	* gst/smpte/gstsmptealpha.c:
+	* gst/smpte/gstsmptealpha.h:
+	  smpte: port to 0.11
+
+2012-03-22 16:10:33 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	  audioparsers: intersect downstream allowed peer caps with sink pad template
+
+2012-03-22 15:55:28 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	  back to development
+
+=== release 0.11.2 ===
+
+2012-03-22 15:51:13 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	* win32/common/config.h:
+	* win32/common/gstudp-marshal.c:
+	  Release 0.11.2
+
+2012-03-22 11:55:28 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2012-03-22 11:53:24 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  unport gdkpixbuf
+	  not merged: https://bugzilla.gnome.org/show_bug.cgi?id=654850
+	  Conflicts:
+	  docs/plugins/Makefile.am
+	  docs/plugins/gst-plugins-good-plugins-docs.sgml
+	  docs/plugins/gst-plugins-good-plugins-sections.txt
+	  docs/plugins/gst-plugins-good-plugins.hierarchy
+	  docs/plugins/inspect/plugin-avi.xml
+	  docs/plugins/inspect/plugin-png.xml
+	  ext/flac/gstflacdec.c
+	  ext/flac/gstflacdec.h
+	  ext/libpng/gstpngdec.c
+	  ext/libpng/gstpngenc.c
+	  ext/speex/gstspeexdec.c
+	  gst/audioparsers/gstflacparse.c
+	  gst/flv/gstflvmux.c
+	  gst/rtp/gstrtpdvdepay.c
+	  gst/rtp/gstrtph264depay.c
+
+2012-03-22 11:45:11 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/smpte/gstsmpte.c:
+	  smpte: only start collectpads2 at state change rather than init
+
+2012-03-21 13:22:43 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/audioamplify.c:
+	* tests/check/elements/audiodynamic.c:
+	* tests/check/elements/audioecho.c:
+	* tests/check/elements/audiopanorama.c:
+	* tests/check/elements/rtp-payloading.c:
+	  tests: update for memory api changes
+
+2012-03-20 10:24:05 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  update for memory api changes
+
+2012-03-19 12:01:40 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: perform additional frame crc check if applicable
+	  ... such as a frame header parsing throwing some suspicious warnings.
+	  So we can be a bit more convinced we determine the right frame end.
+
+2012-03-19 11:58:15 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: avoid indefinite extended search for frame end if possible
+	  ... which is particularly useful if locked on to the wrong frame start
+	  and/or corrupt frame being crc checked.
+
+2012-03-16 18:23:29 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacdec.h:
+	  flacdec: improve error handling and resilience
+	  ... by noting that one occurred in the first place, and then appropriately
+	  ignoring some transient ones.
+
+2012-03-19 10:33:48 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: negotiate an allocator on the srcpads
+	  We do an ALLOCATION query to find out an allocator and parameters on the
+	  srcpads. This way decoders (and sinks) can specify the memory and parameters
+	  they want us to write into.
+
+2012-03-17 20:53:31 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.h:
+	  docs: update docs for new properties and add gdkpixbufoverlay element
+	  Somewhat at least. No idea why it doesn't pick up the description
+	  or example pipeline.
+
+2012-03-18 00:11:19 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/gdk_pixbuf/Makefile.am:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	  gdkpixbufoverlay: make most properties controllable and flag them as mutable-playing
+
+2012-03-17 23:41:38 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.h:
+	  gdkpixbufoverlay: add properties for positioning and sizing
+
+2012-03-17 20:18:19 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/gdk_pixbuf/Makefile.am:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.c:
+	* ext/gdk_pixbuf/gstgdkpixbufoverlay.h:
+	  gdkpixbuf: add gdkpixbufoverlay element
+	  Still lacks features such as positioning or resizing, or
+	  animations, but it's usable already, and supports lots of
+	  formats.
+
+2012-03-16 22:52:02 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	  don't poke into basetransform internals
+	  But use the methods
+
+2012-03-16 21:47:21 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/libpng/gstpngdec.c:
+	* gst/avi/gstavidemux.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/wavparse/gstwavparse.c:
+	  don't pass random pointers to pull_range
+
+2012-03-15 22:15:47 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/monoscope/gstmonoscope.c:
+	  updarte for bufferpool changes
+
+2012-03-15 22:11:17 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/dv/gstdvdec.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/libpng/gstpngdec.c:
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	  update for bufferpool changes
+
+2012-03-15 20:37:56 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/aalib/gstaasink.c:
+	* ext/dv/gstdvdec.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/libpng/gstpngdec.c:
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/monoscope/gstmonoscope.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	  update for allocation query changes
+
+2011-07-14 16:23:49 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264depay.h:
+	  rtph264depay: Make output in AVC stream format work even without complete sprop-parameter-set
+	  This allows outputting streams in AVC format even if the SPS/PPS are sent inside
+	  the RTP stream.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=654850
+
+2012-03-15 14:06:40 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  update for bufferpool api change
+
+2012-03-15 13:37:36 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  update for memory api changes
+
+2012-03-15 13:36:17 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/annodex/gstcmmldec.c:
+	* ext/annodex/gstcmmlenc.c:
+	* ext/flac/gstflacdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	* gst/interleave/deinterleave.c:
+	* gst/interleave/interleave.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/multifile/gstsplitfilesrc.c:
+	* gst/multipart/multipartmux.c:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/videomixer/videomixer2.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* tests/check/elements/audiochebband.c:
+	* tests/check/elements/audiocheblimit.c:
+	  update for memory api changes
+
+2012-03-14 21:36:03 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	  update for memory api changes
+
+2012-03-14 19:55:32 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/aalib/gstaasink.c:
+	* ext/dv/gstdvdec.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/libpng/gstpngdec.c:
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	  take padding into account
+
+2012-03-14 17:07:50 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/imagefreeze/gstimagefreeze.h:
+	  imagefreeze: port to 0.11
+
+2012-03-14 15:45:38 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: reply FALSe on serialized queries
+
+2012-03-13 23:08:38 +0100  Andrej Gelenberg <andrej.gelenberg@udo.edu>
+
+	* ext/libpng/gstpngenc.c:
+	* ext/libpng/gstpngenc.h:
+	  pngenc: add support for 8- and 16-bit gray images
+	  Add support for direct encoding of 8- and 16-bit big endian gray images.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=672025
+
+2012-03-14 11:21:32 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4vpay.c:
+	  mp4vpay: we can also handle x-divx
+
+2012-03-14 10:39:53 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackenc.c:
+	  wavpackenc: do not set output caps directly
+	  ... but use base class function instead.
+
+2012-03-13 21:31:48 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4vdepay.c:
+	  mp4vdepay: fix buffer handling
+	  Don't always output the payload subbuffer, use a separate variable to
+	  make things clearer and without the error.
+
+2012-03-13 20:49:43 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  udpsink: make buffer-size work again
+
+2012-03-13 20:36:56 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: fix SO_RCVBUF handling
+
+2012-03-13 19:26:47 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: don't leak the address
+
+2012-03-13 19:26:23 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	  h264depay: unmap on empty packet
+
+2012-03-13 18:07:18 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: do DTS and PTS correctly
+
+2012-03-13 17:54:50 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: set DTS and PTS on output buffers
+	  Set PTS and DTS on output buffers instead of just the PTS. In streaming cases
+	  you want to synchronized encoded data based on the DTS because that is
+	  monotonically increasing.
+
+2012-03-13 17:54:28 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux_dump.c:
+	  qtdemux: debug additional sdtp flag
+
+2012-03-13 17:27:32 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	  rtp: fix unmap calls
+
+2012-03-13 13:25:09 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.h:
+	  pulse: fix formats, we can not handle S8 but only U8
+
+2012-03-13 12:40:37 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: fix streamheaders
+	  Fix the caps of flacenc, the reference encoder only support 24 bits in
+	  32 bits.
+	  Set streamheader on output caps.
+
+2012-03-12 17:17:01 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/monoscope/gstmonoscope.c:
+	  update for caps api changes
+
+2012-03-12 16:43:27 +0200  Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+
+	* configure.ac:
+	  configure.ac : bump GLib requirement to 2.31.14
+	  Fixes https://bugzilla.gnome.org/show_bug.cgi?id=671911
+
+2012-03-12 15:27:27 +0100  Ross Burton <ross at burtonini.com>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: generate seektables every 10 sec by default
+	  Since this is what the command line tool does as well, it seems like
+	  a better default.
+
+2012-03-10 13:44:08 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: only unlock pad when it was locked
+	  This fixes the mutex being unlocked too much and ending up allowing
+	  other threads when they should not.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=671776
+
+2012-03-07 13:39:50 +0100  Andrej Gelenberg <andrej.gelenberg@udo.edu>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: add support for video/x-raw-gray formats
+	  pngdec can now decode gray 8- and 16-bit images without alpha channel
+	  direct to video/x-raw-gray format. 16-bit gray images have big-endian
+	  format, because it's native PNG endianness. Gray images with alpha
+	  channel still converted to RGBA.
+	  Signed-off-by: Andrej Gelenberg <andrej.gelenberg@udo.edu>
+
+2012-03-08 17:07:51 +0100  Marc Leeman <marc.leeman@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  gstrtspsrc: disable RTSP keep-alive on request
+
+2012-03-12 14:48:47 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/smpte/gstsmpte.c:
+	  smpte: fix stride handling
+
+2012-03-12 12:23:15 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* tests/check/elements/videocrop.c:
+	* tests/check/elements/videofilter.c:
+	  fix for caps _normalize changes
+
+2012-03-12 11:47:35 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	* gst/matroska/matroska-demux.c:
+	  fix for caps api change
+
+2012-03-12 10:43:57 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	* gst/matroska/matroska-demux.c:
+	* sys/oss4/oss4-audio.c:
+	  fix for _do_simplify changes
+
+2012-03-12 08:48:32 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/flv/gstflvmux.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/matroska/matroska-mux.c:
+	  gst: Fix some query leaks
+
+2012-03-11 19:06:59 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  fix for caps api changes
+
+2012-03-11 19:06:37 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/aalib/gstaasink.c:
+	* ext/gdk_pixbuf/pixbufscale.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/pulse/pulsesrc.c:
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/videomixer/videomixer2.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/ximage/gstximagesrc.c:
+	  fix for caps api changes
+
+2012-03-10 10:51:44 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* gst/alpha/gstalphacolor.c:
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstwavpackparse.c:
+	* gst/auparse/gstauparse.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	  fix template caps refcount
+
+2012-03-09 15:53:32 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: fix use of AC_LANG_PROGRAM
+	  No need to include the int main () { } bits, the body is enough.
+
+2012-03-09 15:25:02 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: fix autogen.sh warnings
+	  configure.ac:410: warning: AC_LANG_CONFTEST: no AC_LANG_SOURCE call detected in body
+
+2012-03-08 13:06:13 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/aalib/gstaasink.c:
+	* ext/aalib/gstaasink.h:
+	  aasink: propose videometa uptream
+	  subclass from videosink.
+	  Propose videometa upstream because we can handle it with the video api.
+
+2012-03-08 01:53:50 -0500  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: do not unref sample caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=671534
+
+2012-03-08 11:36:01 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/autodetect.c:
+	* tests/check/elements/videocrop.c:
+	  tests: improve more tests
+
+2012-03-08 11:20:43 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/capssetter.c:
+	* tests/check/elements/gdkpixbufsink.c:
+	  tests: fix some more tests
+
+2012-03-07 15:22:36 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: improve cleanup
+	  Reuse cleanup methods to make sure we remove all pads correctly
+
+2012-03-07 15:00:26 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: set caps without the lock
+	  Release the lock before setting the caps on the srcpad, which triggers an event,
+	  which could eventually call back into us and cause a deadlock.
+
+2012-03-07 14:55:08 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpptdemux.c:
+	  ptdemux: set caps after activating the pad
+	  Set the caps after we activated the pad or else it will just fail.
+
+2012-03-07 14:54:15 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/law/alaw.c:
+	* gst/law/mulaw.c:
+	  law: add layout to audio caps
+
+2012-03-07 14:51:09 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-decode.h:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-decode.h:
+	  law: use GstAudioInfo
+	  Use GstAudioInfo to generate output caps.
+
+2012-03-07 04:20:00 -0500  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtdemux: covert art tag type is GstSample not GstBuffer now
+	  https://bugzilla.gnome.org/show_bug.cgi?id=671534
+
+2012-03-07 10:28:58 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/POTFILES.in:
+	  po: fix POTFILES.in for new wavpackparse location in source tree
+
+2012-03-06 21:44:36 -0800  David Schleef <ds@schleef.org>
+
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	  udp: Change the default port to 5004
+	  udpsrc/udpsink are almost always used with RTP, so let's use an
+	  RTP port as the default port.  It's unclear why 4951 was used, it
+	  goes back to early commits in CVS.
+
+2012-03-06 21:36:02 -0800  David Schleef <ds@schleef.org>
+
+	  Merge branch '0.11' of ssh://git.freedesktop.org/git/gstreamer/gst-plugins-good into 0.11
+
+2012-03-06 15:58:20 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	  speexdec: use base class tag handling helper
+	  ... so as to ensure these to be handled and sent at proper time.
+
+2012-03-06 14:25:27 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackstreamreader.c:
+	  wavpack: Fix possible underflow of unsigned integer variable
+
+2012-03-06 14:22:43 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximagesrc: Fix 'comparison of unsigned expression >= 0 is always true'
+	  This variable can never be below zero anyway.
+
+2012-03-06 14:18:33 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Use correct enum for return values
+
+2012-03-06 14:16:21 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtp/gstrtpdvdepay.c:
+	  dvdepay: Fix 'comparison of unsigned expression >= 0 is always true' compiler warning
+	  This was an actual bug as it could've caused reading from
+	  invalid memory areas when the input is broken.
+
+2012-03-06 13:21:12 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/tvtime/greedyh.asm:
+	* gst/deinterlace/tvtime/tomsmocomp/SearchLoopTop.inc:
+	  deinterlace: Fix 'variable 'oldbx' is uninitialized when used here' compiler warnings
+
+2012-03-06 13:19:24 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Fix 'implicit conversion from enumeration type 'GstDeinterlaceFields' to different enumeration type 'GstDeinterlaceMode'' compiler warning
+
+2012-03-05 15:29:56 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.h:
+	  gdk: cleanups and fix rowstride
+	  Fix the output rowstride, we need to take the stride of the output video frame.
+	  Since we are also dealing with planes, take the plane data and stride.
+	  Don't store the same info twice in different variables.
+
+2012-03-05 13:31:44 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	  gdkpixbuf: fix event handling
+
+2012-03-05 12:20:07 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/wavpackdec.c:
+	* tests/check/elements/wavpackenc.c:
+	* tests/check/elements/wavpackparse.c:
+	* tests/check/pipelines/wavpack.c:
+	  tests: port wavpack tests to 0.11
+
+2012-03-05 13:36:39 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* ext/wavpack/gstwavpackdec.c:
+	* ext/wavpack/gstwavpackdec.h:
+	  wavpackdec: port to 0.11
+
+2012-03-05 12:17:39 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackcommon.c:
+	* ext/wavpack/gstwavpackcommon.h:
+	* ext/wavpack/gstwavpackenc.c:
+	  wavpackenc: port to 0.11
+
+2012-03-05 13:34:36 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* ext/wavpack/Makefile.am:
+	* ext/wavpack/gstwavpack.c:
+	* ext/wavpack/gstwavpackparse.c:
+	* ext/wavpack/gstwavpackparse.h:
+	  wavpack: remove legacy wavpackparse
+
+2012-03-05 12:15:44 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/Makefile.am:
+	* gst/audioparsers/gstwavpackparse.c:
+	* gst/audioparsers/gstwavpackparse.h:
+	* gst/audioparsers/plugin.c:
+	  audioparsers: port wavpackparse to 0.11
+
+2012-03-05 13:29:59 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/wavpack/gstwavpackparse.c
+	  sys/v4l2/gstv4l2bufferpool.c
+	  sys/v4l2/gstv4l2bufferpool.h
+	  sys/v4l2/gstv4l2videooverlay.c
+
+2012-03-05 12:43:17 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  x-raw-bayer -> x-bayer
+
+2012-03-05 11:17:30 +0100  Oleksij Rempel (Alexey Fisher) <bug-track@fisher-privat.net>
+
+	* sys/v4l2/gstv4l2xoverlay.c:
+	  v4l2sink: don't use deprecated XKeycodeToKeysym
+	  https://bugzilla.gnome.org/show_bug.cgi?id=671299
+	  Signed-off-by: Oleksij Rempel (Alexey Fisher) <bug-track@fisher-privat.net>
+
+2012-03-05 12:03:01 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/ximage/Makefile.am:
+	* sys/ximage/gstximagesrc.c:
+	  ximage: use new style caps
+
+2012-03-05 10:49:33 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackdec.c:
+	  wavpackdec: allow some timestamp tolerance to arrange for perfect timestamping
+	  ... which also happens to make some more unit tests pass.
+
+2012-03-05 10:47:44 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackdec.c:
+	  wavpackdec: fix copying output data
+
+2012-03-05 10:46:51 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackenc.c:
+	  wavpackenc: restore legacy buffer offset decorating somewhat
+	  ... at least sufficiently to aid in recognizing rewritten header buffer
+	  making unit test pass.
+
+2012-03-05 10:51:33 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/audioparsers/gstwavpackparse.c:
+	  wavpackparse: initialize header to silence older gcc versions
+
+2012-03-05 10:45:46 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/wavpack/gstwavpackparse.c:
+	  wavpackparse: remove empty lines in varable declarations caused by old indent
+
+2012-03-05 10:44:54 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/jack/gstjack.h:
+	  jack: fix obvious wrong definition for the master flag
+
+2012-03-04 19:55:26 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	* ext/jack/gstjackaudioclient.c:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosink.h:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jack/gstjackaudiosrc.h:
+	  jack: change the transport-mode enum into flags
+	  One can use (or not use) master and slave mode independently.
+
+2012-03-02 11:49:02 -0500  Antoine Tremblay <hexa00@gmail.com>
+
+	* gst/avi/gstavimux.c:
+	  avimux: support up to 6 channels of AC-3
+	  https://bugzilla.gnome.org/show_bug.cgi?id=671220
+
+2012-03-03 13:04:48 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: clear DISCONT flag when recycling buffers into the buffer pool
+	  The base class may have set the DISCONT flag on the first buffer pushed
+	  out. We need to clear that when recycling buffers back into the buffer
+	  pool, otherwise we constantly push out buffers with the discont flag
+	  set, which might upset downstream elements, esp. for compressed
+	  formats like mpeg-ts.
+
+2012-03-01 14:15:29 +0100  Oleksij Rempel (Alexey Fisher) <bug-track@fisher-privat.net>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2src: fix v4l2_munmap() for compressed formats
+	  Make sure we always call munmap() with the same size we called mmap()
+	  with before.
+	  Current v4l2src uses the same structure for VIDIOC_QUERYBUF, VIDIOC_QBUF
+	  and v4l2_munmap calls. The problem is that the video buffer size (length)
+	  may vary for compressed or emulated bufs. VIDIOC_QBUF will change it if
+	  we pass the pointer of a v4l2_buffer. This is why we should avoid using
+	  same variable for mmap and video buffers.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=671126
+
+2012-03-02 11:17:33 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiofirfilter.c:
+	* gst/audiofx/audioiirfilter.c:
+	* gst/flv/gstindex.c:
+	  gst: Update for the gstmarshal.[ch] removal
+
+2012-03-02 10:13:08 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsemixerctrl.h:
+	* gst/videofilter/gstvideobalance.c:
+	* sys/v4l2/gstv4l2colorbalance.h:
+	  mixer/colorbalance: Update for API changes
+
+2012-03-01 17:15:57 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/aalib/gstaasink.c:
+	  aasink: fix stride
+
+2012-03-01 11:36:34 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/Makefile.am:
+	* gst/audioparsers/plugin.c:
+	  audioparsers: disable non-ported wavpackparse
+
+2012-03-01 11:29:50 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/wavpack/gstwavpackenc.c
+	  tests/check/elements/audioiirfilter.c
+	  tests/examples/v4l2/probe.c
+
+2012-02-29 22:31:21 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	  gdkpixbufsink: remove deprecated property
+
+2012-02-29 22:30:56 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	  gdkpixbufscale: remove deprecated property
+
+2012-02-29 22:28:01 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	* ext/gdk_pixbuf/gstgdkpixbufsink.h:
+	  gdkpixbufsink: port to 0.11
+
+2012-02-29 22:25:23 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/gdk_pixbuf/pixbufscale.c:
+	* ext/gdk_pixbuf/pixbufscale.h:
+	  gdkpixbufscale: port to 0.11
+
+2012-02-29 22:24:46 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.h:
+	  gdkpixbufdec: port to 0.11
+
+2012-02-29 17:26:01 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/ximage/ximageutil.c:
+	* sys/ximage/ximageutil.h:
+	  update for metadata API changes
+
+2012-02-28 13:51:10 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/Makefile.am:
+	* gst/audioparsers/gstwavpackparse.c:
+	* gst/audioparsers/gstwavpackparse.h:
+	* gst/audioparsers/plugin.c:
+	  audioparsers: add baseparse based wavpackparse
+
+2012-02-28 11:38:59 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/ximage/ximageutil.c:
+	  update for metadata tags
+
+2012-02-27 23:46:15 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackdec.c:
+	* ext/wavpack/gstwavpackdec.h:
+	* tests/check/elements/wavpackdec.c:
+	  wavpackdec: adjust to audio format limitations
+	  ... which does not allow expressing arbitrary depth in a GstAudioFormat.
+	  Also adjust unit test to modified behaviour.
+
+2012-02-27 23:46:08 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackdec.c:
+	* ext/wavpack/gstwavpackenc.c:
+	  wavpackdec: determine depth from bytes per sample
+	  ... rather than from bits per sample, since spec states values are already
+	  left justified w.r.t. bits per sample but not w.r.t. bytes per sample
+	  (and so the latter determines the normalization, or indicated depth).
+
+2012-02-27 23:46:03 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackdec.c:
+	* ext/wavpack/gstwavpackdec.h:
+	  wavpackdec: port to audiodecoder
+
+2012-02-27 23:45:54 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackenc.c:
+	* ext/wavpack/gstwavpackenc.h:
+	* tests/check/elements/wavpackenc.c:
+	  wavpackenc: port to audioencoder
+	  Also adjust unit test to slightly modified behaviour.
+
+2012-02-27 14:47:25 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/annodex/gstannodex.c:
+	* ext/annodex/gstcmmlparser.c:
+	* ext/annodex/gstcmmltag.c:
+	* ext/pulse/pulseprobe.c:
+	* gst/audiofx/audiofirfilter.c:
+	* gst/audiofx/audioiirfilter.c:
+	* gst/interleave/interleave.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	* sys/oss4/oss4-audio.c:
+	* sys/oss4/oss4-property-probe.c:
+	* sys/v4l2/gstv4l2object.c:
+	* tests/check/elements/audiofirfilter.c:
+	* tests/check/elements/audioiirfilter.c:
+	* tests/check/elements/cmmldec.c:
+	* tests/check/elements/interleave.c:
+	* tests/check/pipelines/wavenc.c:
+	* tests/examples/audiofx/firfilter-example.c:
+	* tests/examples/audiofx/iirfilter-example.c:
+	* tests/examples/pulse/pulse.c:
+	* tests/examples/rtp/server-alsasrc-PCMA.c:
+	* tests/examples/v4l2/probe.c:
+	* tests/icles/test-oss4.c:
+	  Suppress deprecation warnings in selected files, for g_value_array_* mostly
+
+2012-02-27 13:09:31 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/speex/gstspeexenc.c:
+	  speexenc: chain up to parent event handler
+
+2012-02-27 13:05:33 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: fix event handling
+	  Fix dodgy segment event handling
+	  Chain up to parent event handler
+
+2012-02-27 09:14:04 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: use public api
+	  instead of poking into the private structures of the base class
+
+2012-02-27 01:09:11 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/matroska/matroska-mux.c:
+	  flvmux, matroskamux, qtmux: if in doubt about downstream seekability default to streaming=true
+	  If downstream didn't answer our SEEKING query and told us
+	  it's seekable, default to streaming=true. We couldn't do
+	  this in 0.10 for backwards compatibility reasons, but we
+	  can in 0.11. Play it safe.
+
+2012-02-27 01:00:03 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  Merge remote-tracking branch 'origin/master' into 0.11
+	  Conflicts:
+	  gst/audioparsers/gstmpegaudioparse.c
+
+2012-02-27 00:56:37 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  Merge commit 'f9207722ca8fd8dcc1e7215d8af85efe4debfdf4' into 0.11
+
+2012-02-27 00:55:38 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: fix up after merge
+
+2012-02-27 00:48:57 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  Merge commit '38516ad367128d83f9e156529018adb4433cd328' into 0.11
+	  Conflicts:
+	  ext/pulse/pulseaudiosink.c
+	  gst/audioparsers/gstmpegaudioparse.c
+
+2012-02-26 20:39:52 +0100  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/goom2k1/gstgoom.c:
+	  goom2k1: fix compiler warning
+
+2012-02-26 20:30:24 +0100  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: fix compiler warning
+
+2012-02-25 15:55:15 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: create streamable output if downstream is not seekable
+	  Ignore the "streamable" property setting and create streamable
+	  output if downstream is known not to be seekable (as queried
+	  via a SEEKABLE query).
+	  Fixes pipelines like qtmux ! appsink possibly creating seemingly
+	  corrupted output if streamable has not been set to true.
+
+2012-02-25 15:48:44 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: create streamable output if downstream is not seekable
+	  Ignore the "streamable" property setting and create streamable
+	  output if downstream is known not to be seekable (as queried
+	  via a SEEKABLE query).
+	  Fixes pipelines like flvmux ! appsink possibly creating seemingly
+	  corrupted output if streamable has not been set to true.
+
+2012-02-25 15:40:39 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: create streamable output if downstream is not seekable
+	  Ignore the "streamable" property setting and create streamable
+	  output if downstream is known not to be seekable (as queried
+	  via a SEEKABLE query).
+	  Fixes pipelines like webmmux ! appsink creating seemingly
+	  corrupted output if streamable has not been set to true.
+
+2012-02-24 11:03:48 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	* gst/debugutils/gstcapssetter.c:
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videofilter/gstvideoflip.c:
+	  update for basetransform change
+
+2012-02-24 10:26:26 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/ximage/ximageutil.c:
+	  update for metadata change
+
+2012-02-23 08:42:25 -0800  David Schleef <ds@schleef.org>
+
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* gst/debugutils/Makefile.am:
+	* gst/debugutils/efence.c:
+	* gst/debugutils/efence.h:
+	* gst/debugutils/efence.vcproj:
+	  efence: remove plugin
+	  Valgrind is much more useful these days.
+
+2012-02-23 12:05:20 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* NEWS:
+	* RELEASE:
+	  Update NEWS and RELEASE as well
+
+2012-02-23 11:07:35 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* 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/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	  Bump version after release
+
+2012-02-23 12:03:24 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audioecho.h:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbasefirfilter.h:
+	* gst/audiofx/audiofxbaseiirfilter.c:
+	* gst/audiofx/audiofxbaseiirfilter.h:
+	  audiofx: remove transform lock usage
+
+2012-02-23 11:16:21 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/spectrum/gstspectrum.c:
+	* gst/spectrum/gstspectrum.h:
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videocrop/gstvideocrop.h:
+	* gst/videofilter/gstvideobalance.c:
+	  update for basetransform lock removal
+
+2012-02-22 23:36:54 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/debugutils/Makefile.am:
+	  debugutils: disable efence plugin properly
+	  We don't want it built if mmap isn't available either..
+
+2012-02-22 17:39:16 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: fix get_caps function some more so that all structures have channel info
+	  Set channels and channel-layout on the right structure; that is, the
+	  structure we are going to append to the caps we are building, and not
+	  the structure we are using as a template for all the structures. Fixes
+	  first structure of the returned caps not having any channel info set
+	  on it.
+
+2012-02-22 17:09:25 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: microoptimisation: avoid unnecessary list and string copies
+
+2012-02-22 17:03:42 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: audio caps have a *list* of formats, not an array of formats
+	  A list of things in caps is something where one is picked in the
+	  course of negotiation. An array is always something that only makes
+	  sense as a whole in that order.
+
+2012-02-22 18:02:27 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: remove post-port bogus _unref
+
+2012-02-22 17:00:19 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: remove bogus pad locking that causes deadlocks
+	  It's not clear why the pad object lock is taken here. But
+	  gst_pad_{has,get}_current_caps() will try to take the lock
+	  as well and deadlock, since it's not recursive.
+
+2012-02-22 16:59:42 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: set right number of channels on caps in get_caps function
+
+2012-02-21 17:16:32 -0800  David Schleef <ds@schleef.org>
+
+	* autogen.sh:
+	  autogen: avoid touching .po files during 'make'
+	  A simple workaround to deal with GNU gettext automake integration
+	  failing to deal with git.  Fixes: #669207
+
+2012-02-22 02:06:17 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavisubtitle.c:
+	* gst/flv/gstflvmux.c:
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/udp/gstudpsrc.c:
+	* gst/y4m/gsty4mencode.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/ximage/ximageutil.c:
+	* tests/check/elements/deinterleave.c:
+	* tests/check/elements/interleave.c:
+	  update for new memory api
+
+2012-02-21 17:57:44 +0100  Vincent Untz <vuntz@gnome.org>
+
+	* ext/pulse/pulseaudiosink.c:
+	  pulse: Fix a build warning when compiling with asserts disabled
+	  Return a value even if the code will never be reached, to make compilers
+	  happy.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=670561
+
+2012-02-21 18:42:31 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstmpegaudioparse.h:
+	  mpegaudioparse: support parsing freeform bitrate stream
+
+2012-02-21 18:39:18 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* gst/monoscope/gstmonoscope.c:
+	* gst/monoscope/gstmonoscope.h:
+	  monoscope: port to 0.11
+
+2012-02-21 10:53:56 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2012-02-20 12:22:12 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: Force baseline is profile-level-id is unspecified
+
+2012-02-21 10:40:00 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/taglib/gstid3v2mux.cc:
+	  id3v2mux: Fix merge error
+
+2012-02-20 12:22:12 -0500  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: Force baseline is profile-level-id is unspecified
+
+2012-02-20 16:35:18 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  fix compiler warnings
+
+2012-01-26 03:29:28 -0500  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/udp/gstudpsrc.c:
+	  fix compiler warnings
+
+2012-01-26 06:58:46 -0500  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  Fix compiler warnings
+
+2012-02-18 11:38:36 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/level.c:
+	  tests: fix up level test for GstValueList -> GValueArray change
+	  https://bugzilla.gnome.org/show_bug.cgi?id=670303
+
+2012-02-16 18:01:29 +0200  Peteris Krisjanis <pecisk@gmail.com>
+
+	* gst/level/gstlevel.c:
+	  level: use GValueArray instead of GstValueList in messages
+	  Updated GstLevel element to use GValueArray instead of
+	  GstValueList for rms/peak/decay keys attached to element
+	  message.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=670303
+
+2012-02-18 00:00:54 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* win32/common/config.h:
+	  win32: back to development
+
+2012-02-17 23:54:29 +0100  Dominique Leuenberger <dominique-gnomezilla at leuenberger.net>
+
+	* docs/plugins/Makefile.am:
+	  No longer reference deprecated header files while building docs.
+
+2012-02-17 23:49:21 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  gst/equalizer/gstiirequalizer.c
+
+2012-02-17 17:21:53 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/equalizer/gstiirequalizer.c:
+	  equalizer: fix switching from passthrough to non-passthrough when parameters change
+	  commit b5bf0294 moved the if(need_new_coefficients) set_passthrough(equ)
+	  after the if(is_passthrough) return FLOW_OK shortcut, so the passthrough
+	  mode would never get updated even if the coefficients change.
+	  Fixes equalizer-test doing .. nothing.
+
+2012-02-17 17:57:03 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	  goom*: fix leaked caps event
+
+2012-02-17 13:26:53 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: parse either Xing or VBRI data
+	  ... and avoid confusing debug message claiming neither present.
+
+2012-02-17 14:38:03 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matrosk: fix segment update
+
+2012-02-17 11:05:27 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	  back to development
+
+=== release 0.11.1 ===
+
+2012-02-17 11:04:47 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/eo.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	* win32/common/config.h:
+	* win32/common/gstrtpbin-marshal.c:
+	* win32/common/gstrtpbin-marshal.h:
+	  RELEASE 0.11.1
+
+2012-02-16 23:33:15 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/goom/gstgoom.c:
+	  goom: fix buffer leak
+
+2012-02-16 23:40:58 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/goom2k1/gstgoom.c:
+	  goom2k1: use some more boilerplate
+
+2012-02-16 23:33:01 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* gst/goom2k1/gstgoom.c:
+	* gst/goom2k1/gstgoom.h:
+	  goom2k1: port to 0.11
+
+2012-02-16 15:31:53 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/shout2/gstshout2.c:
+	  shout2: use some more boilerplate
+
+2012-02-16 15:29:34 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* ext/shout2/gstshout2.c:
+	  shout2: port to 0.11
+
+2012-02-14 11:56:00 +0100  Philippe Normand <philn@igalia.com>
+
+	* gst/interleave/Makefile.am:
+	* gst/interleave/interleave.c:
+	* gst/interleave/interleave.h:
+	* gst/interleave/plugin.c:
+	* gst/interleave/plugin.h:
+	* tests/check/elements/interleave.c:
+	  interleave: port to 0.11
+	  Port of the interleave element and its unittests.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=669643
+
+2012-02-16 14:23:50 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2012-02-16 17:14:20 +0800  Gary Ching-Pang Lin <chingpang@gmail.com>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2src: failure to query some optional controls is not a fatal error
+	  Don't post a (fatal) error message on the bus just because we
+	  failed to query some control. Fixes issue with built-in
+	  Suyin Corp webcam for HP notebook (usbid 064e:e28a) on
+	  OpenSuse 12.1, where querying red/blue balance fails.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=670197
+
+2012-02-16 12:59:10 +0000  Tuukka Pasanen <tuukka.pasanen@ilmi.fi>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2src: fix for webcamstudio vloopback
+	  Because vlooback emits 25 - ENOTTY and no EINVAL v4l2src thought it
+	  can't handle this and does not work.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=669455
+
+2012-02-16 11:21:28 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: declare variables at the beginning of the block
+	  It's how we roll. Fixes 'ISO C90 forbids mixed declarations and code'
+	  compiler warning.
+
+2012-02-15 23:55:44 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/examples/spectrum/Makefile.am:
+	  examples: fix spectrum example build issues
+	  Find fft headers in uninstalled setup, fix LIBS order.
+
+2012-02-15 12:41:43 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: remove some unused declarations
+
+2012-02-15 11:25:45 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/examples/spectrum/Makefile.am:
+	* tests/examples/spectrum/demo-audiotest.c:
+	  spectrum-demo: show the effect of fast-mode
+
+2012-02-14 12:26:37 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videocrop/gstaspectratiocrop.c:
+	  aspectratiocrop: fix caps refcount
+
+2012-02-14 11:22:46 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/pipelines/effectv.c:
+	  tests: fix test, use videoconvert
+
+2012-02-14 10:51:38 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  tests/check/elements/flacparse.c
+
+2012-02-09 13:41:53 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  audioparsers: adjust to modified baseparse API
+
+2012-02-13 17:13:17 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/multifile/gstmultifilesink.c:
+	* gst/udp/gstmultiudpsink.c:
+	  update for memory api change
+
+2012-02-13 12:06:37 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/flacparse.c:
+	  tests: flacparse: check and compare intended data
+
+2012-02-12 17:03:37 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  Merge remote-tracking branch 'origin/master' into 0.11
+	  Conflicts:
+	  ext/taglib/gstapev2mux.cc
+	  ext/taglib/gstid3v2mux.cc
+	  ext/taglib/gsttaglibmux.c
+	  ext/taglib/gsttaglibmux.h
+
+2012-02-12 16:22:21 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/taglib/Makefile.am:
+	* ext/taglib/gstapev2mux.cc:
+	* ext/taglib/gstapev2mux.h:
+	* ext/taglib/gstid3v2mux.cc:
+	* ext/taglib/gstid3v2mux.h:
+	* ext/taglib/gsttaglibmux.c:
+	* ext/taglib/gsttaglibmux.h:
+	* ext/taglib/gsttaglibplugin.c:
+	  taglib: port to GstTagMux base class
+
+2012-02-12 12:24:50 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/taglib/gsttaglibmux.c:
+	  taglib: finish off a few missed variable changes
+	  Local variables are now unused, and the values from the segment copy
+	  are used instead, so remove the now useless local variables and write
+	  to the segment where appropriate.
+
+2012-02-10 16:23:14 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/flac/gstflacenc.c
+	  ext/jack/gstjackaudioclient.c
+	  ext/jack/gstjackaudiosink.c
+	  ext/jack/gstjackaudiosrc.c
+	  ext/pulse/plugin.c
+	  ext/shout2/gstshout2.c
+	  gst/matroska/matroska-mux.c
+	  gst/rtp/gstrtph264pay.c
+
+2012-02-08 23:03:28 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: add stream-format and alignment to h264 sink caps
+	  We're happy to accept both byte-stream and avc, advertise
+	  that on the sink caps and fix up _get_caps() function to
+	  not just return "video/x-h264".
+	  https://bugzilla.gnome.org/show_bug.cgi?id=606662
+
+2012-02-08 20:58:04 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: add stream-format and alignment fields to src template caps
+	  Because we can. And so we get a warning if we try to output avc with
+	  nal alignment or somesuch.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=606662
+
+2012-02-10 13:44:43 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/rtp-payloading.c:
+	  tests: clean up rtp-payloading test a little
+	  Feed data into the pipeline using appsrc instead of fdsrc and
+	  a pipe. Store unsigned byte values in guint8 instead of char.
+	  Getting rid of the capsfilter also helps to avoid 'format is
+	  not fully specified' warnings when pushing "video/x-h264" data
+	  into rtph264pay with fully specified h264 caps in the sink template.
+
+2012-02-10 10:07:34 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flv: use default pad query
+	  We need to chain up unknown queries to the default query handler instead of
+	  blindly forwarding them. In this case it caused the caps query to be forwarded
+	  to the upstream typefind and return the wrong type for the audio/video pad.
+
+2012-02-09 22:12:14 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/mpegaudioparse.c:
+	  tests: mpegaudioparse: remove stray declaration
+
+2012-02-09 22:07:48 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: correctly set ADIF src caps
+
+2012-02-09 22:10:07 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: prevent a few direct exits without cleanup
+
+2012-02-09 22:07:18 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: shift in proper direction for audio sample conversion
+
+2012-02-09 18:09:45 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/deinterleave.c:
+	  tests: fix compilation
+
+2012-02-09 10:11:48 +0100  Marc Leeman <marc.leeman@gmail.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: typo fix (bytes send -> bytes sent)
+
+2012-02-08 16:34:00 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/libpng/gstpngdec.c:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	* ext/wavpack/gstwavpackenc.c:
+	* gst/effectv/gstquark.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/multifile/gstsplitfilesrc.c:
+	* gst/replaygain/gstrganalysis.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/udp/gstudpsrc.c:
+	* gst/wavenc/gstwavenc.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/ximage/gstximagesrc.c:
+	  GST_FLOW_WRONG_STATE -> GST_FLOW_FLUSHING
+
+2012-02-08 16:37:13 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  GST_FLOW_WRONG_STATE -> GST_FLOW_FLUSHING
+
+2012-02-07 14:10:44 -0800  Ralph Giles <giles@mozilla.com>
+
+	* ext/shout2/gstshout2.c:
+	  shout2send: send video/webm through libshout.
+	  This requires SHOUT_FORMAT_WEBM, added in libshout 2.3.0,
+	  so video/webm support is contingent on that symbol being
+	  defined.
+	  Also an indentation change required by the pre-commit hook.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=669590
+
+2012-01-30 16:40:19 +0100  Philippe Normand <philn@igalia.com>
+
+	* configure.ac:
+	* gst/interleave/Makefile.am:
+	* gst/interleave/deinterleave.c:
+	* gst/interleave/deinterleave.h:
+	* gst/interleave/plugin.c:
+	* gst/interleave/plugin.h:
+	* tests/check/elements/deinterleave.c:
+	  deinterleave: port to 0.11
+	  Port of the deinterleave element and its unittests. The interleave
+	  element will be ported as part of another patch, hence disabling it
+	  for now.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=668847
+
+2012-02-07 23:41:13 +0200  Raimo Järvi <raimo.jarvi@gmail.com>
+
+	* sys/directsound/gstdirectsoundsink.h:
+	  directsoundsink: Fix compiling
+	  https://bugzilla.gnome.org/show_bug.cgi?id=669607
+
+2012-02-08 00:08:49 +0200  Raimo Järvi <raimo.jarvi@gmail.com>
+
+	* sys/waveform/gstwaveformsink.c:
+	  waveformsink: Port to 0.11
+	  https://bugzilla.gnome.org/show_bug.cgi?id=669612
+
+2012-02-07 21:57:47 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/jack/gstjackaudioclient.c:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: rework transport support
+	  Move common code to jackclient. There we can also handle the request state
+	  message in a better way, as the element callbacks are only run if the element is
+	  active.
+
+2012-02-07 10:47:19 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/apev2mux.c:
+	* tests/check/elements/id3v2mux.c:
+	  tests: improve tagmux tests
+
+2012-02-07 10:29:11 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/taglib/gsttaglibmux.c:
+	  taglib: fix object registration
+	  We can't use G_DEFINE_TYPE because the class is not set in the class_init and we
+	  need it to get the srcpad template.
+	  Fix a caps leak
+
+2012-02-07 10:16:32 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/jpegenc.c:
+	  tests: fix jpeg test
+
+2012-02-07 10:15:51 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  soup: fix caps
+
+2012-02-07 09:54:00 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstshagadelic.c:
+	  effecttv: fix initialisation
+
+2012-02-07 09:42:04 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/y4m/gsty4mencode.c:
+	  y4m: fix negotiation
+
+2012-02-07 09:41:51 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/videofilter.c:
+	* tests/check/elements/y4menc.c:
+	  tests: fix more tests
+
+2012-02-06 22:13:53 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* ext/dv/Makefile.am:
+	* ext/dv/gstdvdec.c:
+	* ext/dv/gstdvdec.h:
+	* ext/dv/gstdvdemux.c:
+	* ext/dv/gstdvdemux.h:
+	  dv: port to 0.11
+
+2012-02-06 18:35:01 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rglimiter.c:
+	* tests/check/elements/rgvolume.c:
+	* tests/check/elements/spectrum.c:
+	* tests/check/elements/videocrop.c:
+	  test: fix more tests
+
+2012-02-06 15:52:49 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/id3demux.c:
+	* tests/check/elements/level.c:
+	* tests/check/elements/multifile.c:
+	  tests: fix more tests
+
+2012-02-06 15:52:36 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/flv/Makefile.am:
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvmux.c:
+	  flv: fix caps
+
+2012-02-06 15:20:55 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/equalizer/gstiirequalizer.c:
+	* tests/check/elements/equalizer.c:
+	  iirequalizer: fix equalizer and unit test
+
+2012-02-06 13:44:20 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/audiopanorama.c:
+	* tests/check/elements/audiowsincband.c:
+	* tests/check/elements/audiowsinclimit.c:
+	  tests: fix some more tests
+
+2012-02-06 13:43:49 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: take the pad from collectpads2 correctly
+
+2012-02-06 13:29:24 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/audioiirfilter.c:
+	* tests/check/elements/audioinvert.c:
+	  tests: fix more unit tests
+
+2012-02-06 13:28:55 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/audiofx/audiodynamic.c:
+	  audiodynamic: fix negotiation
+
+2012-01-28 11:13:16 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: avoid posting invalid duration for each frame
+	  https://bugzilla.gnome.org/show_bug.cgi?id=666583
+
+2012-02-06 10:07:06 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/audioamplify.c:
+	* tests/check/elements/audiochebband.c:
+	* tests/check/elements/audiocheblimit.c:
+	* tests/check/elements/audiodynamic.c:
+	* tests/check/elements/audioecho.c:
+	  tests: fix more tests
+
+2012-02-06 09:49:38 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/aspectratiocrop.c:
+	* tests/check/elements/rganalysis.c:
+	  tests: improve some tests
+
+2012-02-06 09:23:49 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: fix jitterbuffer test
+
+2012-02-06 09:23:07 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: fix caps after pt change
+
+2012-02-06 09:18:17 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: fix caps leak
+
+2012-02-03 22:05:59 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/plugin.c:
+	  pulseaudiosink: Lower rank to prevent autoplugging
+	  pulseaudiosink breaks visualisations in its current form, so let's
+	  prevent it from being autoplugged for the time being.
+	  The best we can hope to do in the 0.10 series is query the list of
+	  available sinks and their formats, and expose these as the bin's sinkpad
+	  caps. While this is not a comprehensive solution, it will make sure that
+	  we're only trying to support compressed formats if we're certain that
+	  one exists.
+	  The long-term fix for this will be in the form of proper upstream
+	  renegotiation support in the 0.11/1.0 series.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=666361
+
+2012-02-03 17:23:48 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/cmmldec.c:
+	  tests: fix more tests
+
+2012-02-03 16:13:51 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/apev2mux.c:
+	* tests/check/elements/audiofirfilter.c:
+	* tests/check/elements/audioiirfilter.c:
+	* tests/check/elements/cmmldec.c:
+	* tests/check/elements/id3v2mux.c:
+	* tests/check/elements/interleave.c:
+	* tests/check/elements/parser.c:
+	* tests/check/pipelines/wavenc.c:
+	  tests: fix some more tests
+
+2012-02-03 16:12:59 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: fix srcpad caps handling
+
+2012-02-03 16:12:24 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/annodex/gstcmmlenc.c:
+	  cmmlenc: fix caps handling
+
+2012-02-03 14:53:31 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: fix event leak when there is no peer on the src pad
+
+2012-02-02 16:21:29 +0000  Christian Fredrik Kalager Schaller <christian.schaller@collabora.co.uk>
+
+	* gst-plugins-good.spec.in:
+	  Update spec file
+
+2012-02-02 12:27:09 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: specify we only accept raw AAC in template caps
+	  No header seems to be added, and the codec ID is the same as used
+	  for raw by flvdemux, so raw seems the only supported case.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=665394
+
+2012-02-02 12:25:21 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: specify we only output raw AAC in template caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=665394
+
+2012-02-01 18:01:27 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* ext/taglib/gstapev2mux.cc:
+	* ext/taglib/gstid3v2mux.cc:
+	* ext/taglib/gsttaglibmux.c:
+	* ext/taglib/gsttaglibmux.h:
+	  taglib: port to 0.11
+
+2012-02-01 16:40:51 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/annodex/Makefile.am:
+	* gst/audiofx/Makefile.am:
+	* gst/rtpmanager/Makefile.am:
+	* tests/examples/audiofx/Makefile.am:
+	* tests/examples/rtp/Makefile.am:
+	  build: ignore GValueArray deprecation warnings for the time being
+	  until this gets sorted out with the GLib folks and we have a
+	  viable alternative.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=667228
+
+2012-02-01 16:36:53 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulseprobe.c:
+	* ext/pulse/pulseprobe.h:
+	  pulse: disable some unused property probe code
+	  which was using GValueArray
+
+2012-02-01 16:11:14 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	  speex: Use new audio encoder/decoder base class API for srcpad caps
+
+2012-02-01 16:05:51 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacenc.c:
+	  flac: Use new audio encoder/decoder base class API for srcpad caps
+
+2012-01-31 15:39:09 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/equalizer.c:
+	* tests/check/elements/id3demux.c:
+	* tests/check/elements/interleave.c:
+	* tests/check/elements/level.c:
+	* tests/check/elements/rganalysis.c:
+	* tests/check/elements/rglimiter.c:
+	* tests/check/elements/rgvolume.c:
+	* tests/check/elements/rtpbin.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	* tests/check/elements/shapewipe.c:
+	* tests/check/elements/spectrum.c:
+	* tests/check/elements/udpsrc.c:
+	* tests/check/elements/y4menc.c:
+	* tests/check/pipelines/flacdec.c:
+	* tests/check/pipelines/wavenc.c:
+	  tests: fix more tests
+
+2012-01-30 14:52:37 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp2tpay.c:
+	  rtpmp2tpay: do not try to flush a packet when no data is available
+	  https://bugzilla.gnome.org/show_bug.cgi?id=668874
+
+2012-01-31 13:41:45 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/alphacolor.c:
+	* tests/check/elements/audiochebband.c:
+	* tests/check/elements/audiocheblimit.c:
+	* tests/check/elements/audiofirfilter.c:
+	* tests/check/elements/audioiirfilter.c:
+	* tests/check/elements/audioinvert.c:
+	* tests/check/elements/audiowsincband.c:
+	* tests/check/elements/audiowsinclimit.c:
+	* tests/check/elements/avimux.c:
+	* tests/check/elements/deinterlace.c:
+	* tests/check/elements/deinterleave.c:
+	  tests: update some tests for new memory api
+
+2012-01-31 12:22:19 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/examples/shapewipe/shapewipe-example.c:
+	* tests/examples/v4l2/camctrl.c:
+	  controller: adapt to control-source type changes
+
+2012-01-30 21:39:34 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/examples/shapewipe/shapewipe-example.c:
+	* tests/examples/v4l2/camctrl.c:
+	  controller: rename control-bindings
+	  gst_control_binding_xxx -> gst_xxx_control_binding for consistency.
+
+2012-01-30 17:16:51 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/annodex/gstcmmlenc.c:
+	* ext/flac/gstflacenc.c:
+	* ext/soup/gstsouphttpclientsink.c:
+	* ext/speex/gstspeexenc.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/flv/gstflvmux.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-parse.c:
+	* tests/check/elements/cmmldec.c:
+	* tests/check/elements/cmmlenc.c:
+	  update for HEADER flag
+
+2010-06-11 08:36:33 +0200  Pascal Buhler <pascal.buhler@tandberg.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: Exclude NALu size from payload length on truncated packets.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=667846
+
+2012-01-28 23:35:50 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: remove obsolete variable, set but not used
+	  Reported by andredieb on #gstreamer.
+
+2012-01-28 13:05:09 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: avoid wrapping opaque to transparent
+
+2012-01-28 12:35:13 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: do not free memory twice
+	  A recent change to fix leaking codec ID string accidentally caused
+	  one of the very few places that weren't leaking to now free twice.
+
+2012-01-27 16:27:49 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/law/alaw-decode.c:
+	  alawdec: Each output sample is 2 bytes
+
+2012-01-27 12:14:49 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Don't leak caps event when not pushing
+
+2012-01-27 12:04:53 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpptdemux.c:
+	  rtpptdemux: Forward sticky events
+
+2012-01-27 12:04:05 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpptdemux.c:
+	  rtpptdemux: Protect all uses pad list with OBJECT LOCK
+	  Actually protect the entire pad list and use it in a thread safe
+	  way.
+
+2012-01-27 12:02:25 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Forward sticky events to new pads
+
+2012-01-27 12:01:40 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Add ssrc to forwarded CAPS events
+	  Also iterate the list of GstRtpSsrcDemuxPad safely
+
+2012-01-27 11:59:08 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrccdemux: Factor out getting dpad by pad
+
+2012-01-26 18:35:48 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Keep the buffer mapped while it is being modified
+
+2012-01-26 18:35:27 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpsession: Initialise the address pointer to NULL
+
+2012-01-27 12:07:43 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstdtmfdetect.c:
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  dtmf: Use new-style caps
+
+2012-01-27 16:37:19 +0100  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/directsound/gstdirectsoundsink.h:
+	  direcsoundsink: Port element to 0.11
+
+2012-01-26 19:48:14 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer2: remove pad event function
+	  We use the one from collectpads
+
+2012-01-26 18:26:02 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  Revert "qtdemux: fix GstDateTime/GDateTime mixup"
+	  This reverts commit 53261261120b4c008de61691c70e94354b28004a.
+	  The GstDateTime->GDateTime change in core was apparently accidental,
+	  and is now reverted.
+
+2012-01-26 18:25:21 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  Revert "avidemux: fix GstDateTime/GDateTime mixup"
+	  This reverts commit acc9f150968b25c5ae5a6940b34ad2d51b174fd2.
+	  The GstDateTime->GDateTime change in core was apparently accidental,
+	  and is now reverted.
+
+2012-01-26 17:50:30 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix GstDateTime/GDateTime mixup
+	  This is a blind fix to match the one I just made to qtdemux,
+	  as I do not have an AVI file where the code gets executed.
+
+2012-01-26 17:47:29 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix GstDateTime/GDateTime mixup
+
+2012-01-26 18:51:30 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: more fixes
+
+2012-01-26 18:43:06 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer: make videomixer work somewhat
+
+2012-01-26 18:15:51 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* gst/videomixer/blend.c:
+	* gst/videomixer/blend.h:
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	  videomixer: port to 0.11
+	  It builds and gst-inspect-0.11 works.. otherwise untested
+
+2012-01-26 15:48:01 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/udp/gstdynudpsink.c:
+	  dynudpsink: fix get-stats signal registration some more
+
+2012-01-26 15:46:13 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  Revert "udp: mark action signals as RUN_FIRST"
+	  This reverts commit 5c8308599129d9e1606eedb2d3543617658dc306.
+
+2012-01-26 15:39:33 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  udp: mark action signals as RUN_FIRST
+
+2012-01-26 15:37:23 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/udp/gstdynudpsink.c:
+	  udp: mark "get-stats" as action signal
+
+2012-01-26 15:30:41 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstdynudpsink.h:
+	* gst/udp/gstmultiudpsink.c:
+	  udp: fix get-stats action signal registration
+	  It returns a GstStructure now, not a GValueArray
+
+2012-01-26 16:05:34 +0100  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: fix print format
+
+2012-01-26 11:50:19 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/ebml-write.c:
+	  matroskamux: Fix size of output buffers
+
+2012-01-26 11:33:07 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: include right collectpads version
+
+2012-01-26 11:29:11 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Properly use the alignment parameter of gst_buffer_new_allocate()
+	  It's a bitmask for the alignment, not the alignment itself.
+
+2012-01-26 11:18:40 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/ebml-write.c:
+	  matroskamux: Properly unmap WRITE maps of the output buffers
+
+2012-01-26 10:44:28 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer2: Update for the new collectpads2 event handling API
+
+2012-01-26 10:40:06 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Update for the new collectpads2 event handling API
+
+2012-01-26 10:37:52 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Update for the new collectpads2 event handling API
+
+2012-01-26 10:28:51 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Update for new collectpads2 event handling API
+
+2012-01-26 10:27:40 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: Update for new collectpads2 event handling API
+
+2012-01-25 18:41:38 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Only forward the event when we didn't handle it ourselves
+
+2012-01-25 18:40:03 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	* gst/videomixer/videomixer2pad.h:
+	  videomixer: some more porting
+
+2012-01-25 18:00:52 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videomixer/blend.c:
+	* gst/videomixer/blend.h:
+	  videomixer: port blend function
+
+2012-01-25 16:58:12 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flv: Fix unitialized variables
+	  (or rather circumvent issues with naive compilers ...)
+
+2012-01-25 15:21:44 +0000  Jayakrishnan M <jay.krishnanm@gmail.com>
+
+	* ext/cairo/Makefile.am:
+	  cairo: fix build, make sure libgstvideo can be found
+	  https://bugzilla.gnome.org/show_bug.cgi?id=668648
+
+2012-01-25 14:50:50 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfdetect.c:
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  port to new memory API
+
+2012-01-25 13:19:12 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/rtpsession.c:
+	  rtpmanager: don't pretend our random hostnames are fully-qualified domain names
+
+2012-01-25 13:47:30 +0100  Thomas Vander Stichele <thomas (at) apestaart (dot) org>
+
+	* common:
+	  Automatic update of common submodule
+	  From c463bc0 to 7fda524
+
+2012-01-25 12:49:34 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	  Merge branch '0.11' of ssh://git.freedesktop.org/git/gstreamer/gst-plugins-good into 0.11
+
+2012-01-25 12:49:11 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/flac/gstflacdec.c
+	  ext/jpeg/gstjpegenc.c
+	  ext/pulse/pulsesink.c
+	  sys/v4l2/gstv4l2src.c
+
+2012-01-25 12:41:42 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngenc.c:
+	  png: port to new memory API
+
+2012-01-25 12:41:30 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska: port to new memory API
+
+2012-01-24 14:38:58 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/annodex/gstcmmldec.c:
+	* ext/annodex/gstcmmlenc.c:
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflactag.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstjpegenc.h:
+	* ext/pulse/pulsesink.c:
+	* ext/soup/gstsouphttpclientsink.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/spectrum/gstspectrum.c:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/videocrop/gstvideocrop.c:
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavparse/gstwavparse.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/ximage/gstximagesrc.c:
+	* tests/check/elements/parser.c:
+	  more memory API porting
+
+2012-01-23 17:25:37 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/apetag/gstapedemux.c:
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbaseiirfilter.c:
+	* gst/audiofx/audioinvert.c:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/audiofx/audiopanorama.c:
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavisubtitle.c:
+	* gst/cutter/gstcutter.c:
+	* gst/debugutils/breakmydata.c:
+	* gst/debugutils/tests.c:
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/id3demux/gstid3demux.c:
+	* gst/isomp4/atomsrecovery.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmuxmap.c:
+	* gst/isomp4/gstrtpxqtdepay.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/level/gstlevel.c:
+	* gst/matroska/ebml-read.c:
+	* gst/matroska/ebml-read.h:
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstsplitfilesrc.c:
+	* gst/replaygain/gstrganalysis.c:
+	* gst/replaygain/gstrglimiter.c:
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmparobustdepay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	  update for new memory API
+
+2012-01-25 11:21:50 +0100  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstdtmfdetect.c:
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfdepay.h:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  dtmf: port to 0.11
+
+2012-01-25 11:38:11 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 2a59016 to c463bc0
+
+2012-01-24 18:24:13 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/libpng/gstpngenc.c:
+	  pngenc: disably snapshot behaviour by default
+	  ... since such behaviour is not consistent, if allowable at all.
+
+2012-01-24 18:23:22 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngdec.h:
+	  pngdec: port to 0.11
+
+2012-01-24 18:21:08 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/libpng/gstpngenc.c:
+	* ext/libpng/gstpngenc.h:
+	  pngenc: port to 0.11
+
+2012-01-24 14:53:38 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: fix string leak
+
+2012-01-24 14:52:09 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: fix use of freed memory
+
+2011-12-01 15:49:40 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  Don't crash on empty laces
+	  https://bugzilla.gnome.org/show_bug.cgi?id=665224
+
+2012-01-23 13:15:46 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/rtpsession.c:
+	  rtpmanager: don't reveal the user's username, hostname or real name by default
+	  Send a randomly made-up user@hostname as CNAME and don't
+	  send a NAME at all by default.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=668320
+
+2012-01-21 20:07:56 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/examples/shapewipe/shapewipe-example.c:
+	* tests/examples/v4l2/camctrl.c:
+	  controller: move from control-binding to control-binding-direct
+
+2012-01-22 23:31:19 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst-libs/gst/glib-compat-private.h:
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiochebband.h:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/audiofx/audiocheblimit.h:
+	* gst/audiofx/audiofirfilter.c:
+	* gst/audiofx/audiofirfilter.h:
+	* gst/audiofx/audioiirfilter.c:
+	* gst/audiofx/audioiirfilter.h:
+	* gst/audiofx/audiowsincband.c:
+	* gst/audiofx/audiowsincband.h:
+	* gst/audiofx/audiowsinclimit.c:
+	* gst/audiofx/audiowsinclimit.h:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videocrop/gstaspectratiocrop.h:
+	  Don't use deprecated GLib API
+
+2012-01-22 23:15:19 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	* gst-libs/gst/glib-compat-private.h:
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalpha.h:
+	* gst/interleave/interleave.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* sys/oss4/oss4-mixer.c:
+	* tests/check/elements/multifile.c:
+	* tests/check/elements/souphttpsrc.c:
+	* tests/icles/equalizer-test.c:
+	* tests/icles/gdkpixbufsink-test.c:
+	* tests/icles/test-oss4.c:
+	* tests/icles/v4l2src-test.c:
+	* tests/icles/videocrop-test.c:
+	  Use new GLib API unconditionally
+
+2012-01-20 17:06:42 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: simplify internal src event debug logging
+	  ... which avoids almost superfluous obtaining of rtsp element.
+
+2012-01-20 17:03:50 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: avoid NULL string comparison
+
+2012-01-20 17:03:21 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: arrange for initialized variables
+
+2012-01-20 17:02:15 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4adepay.c:
+	  rtpmp4adepay: prevent out-of-bound array access
+
+2012-01-20 17:01:37 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/atomsrecovery.c:
+	  isomp4: recovery: add sanity check
+	  ... on possibly bogus/corrupt input data.
+
+2012-01-20 17:00:51 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	  rtptheoradepay: remove dead code
+
+2012-01-20 16:58:28 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: remove redundant variable
+
+2012-01-20 16:57:52 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: fix arithmetic for unsigned comparison
+
+2012-01-20 16:55:06 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: add various missing break
+
+2012-01-20 16:54:06 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: tweak DEFAULT format duration query response
+
+2012-01-20 16:49:14 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	  alphacolor: remove redundant statement
+
+2012-01-20 16:48:49 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: improve upstream peer duration querying
+	  ... to avoid accepting unhandled duration query result.
+
+2012-01-20 16:47:36 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: additional error condition checking
+
+2012-01-20 16:46:21 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: additional error condition checking
+
+2012-01-20 16:44:21 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: check _alloc_buffer result and perform fallback alloc if needed
+	  ... rather than carrying on with NULL buffer.
+
+2012-01-20 14:45:01 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/examples/shapewipe/shapewipe-example.c:
+	* tests/examples/v4l2/camctrl.c:
+	  controller: adapt to control binding changes
+
+2012-01-20 11:37:38 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/examples/shapewipe/shapewipe-example.c:
+	* tests/examples/v4l2/camctrl.c:
+	  controller: adapt to controller api changes
+	  Don't use the convenience api for control sources.
+
+2012-01-19 14:24:04 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	* configure.ac:
+	  Add --disable-fatal-warnings configure option
+
+2012-01-19 12:44:39 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	* gst/udp/gstmultiudpsink.c:
+	  update for memory API
+
+2012-01-19 11:33:53 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	* ext/flac/gstflacdec.c:
+	* ext/jack/gstjackaudioclient.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	* ext/soup/gstsouphttpclientsink.c:
+	* ext/soup/gstsouphttpclientsink.h:
+	* ext/wavpack/gstwavpackparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/equalizer/gstiirequalizer.h:
+	* gst/flv/gstflvdemux.c:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/isomp4/gstqtmoovrecover.c:
+	* gst/isomp4/gstqtmoovrecover.h:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtpmanager/gstrtpssrcdemux.h:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/shapewipe/gstshapewipe.h:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	* gst/videomixer/videomixer2.c:
+	* gst/wavparse/gstwavparse.c:
+	* sys/v4l2/gstv4l2videooverlay.c:
+	* sys/ximage/gstximagesrc.c:
+	* sys/ximage/gstximagesrc.h:
+	* tests/check/elements/deinterleave.c:
+	  port to new gthread API
+
+2012-01-18 16:58:12 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure.ac: Remove GIO check, this is in gst-glib2.m4 now
+
+2012-01-18 16:46:17 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 0807187 to 2a59016
+
+2012-01-18 16:15:59 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure.ac: Require GLib 2.31.10 and improve GIO check
+
+2012-01-17 16:58:07 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Remove unneeded socket.h include
+
+2012-01-17 16:53:31 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstasteriskh263.c:
+	  configure: Remove socket/winsock specific checks
+	  Not necessary anymore.
+
+2012-01-17 16:49:10 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtsp/Makefile.am:
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Update for the new GIO versions of the udp elements
+
+2012-01-17 13:08:42 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	* gst/rtpmanager/rtpstats.c:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpmanager: Port to GIO
+
+2012-01-17 11:19:33 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* gst/udp/Makefile.am:
+	  configure: Require GIO 2.31.10
+
+2012-01-17 11:18:33 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/udp/gstudp.c:
+	* gst/udp/gstudpnetutils.c:
+	* gst/udp/gstudpnetutils.h:
+	  udp: Remove now unecessary code
+
+2012-01-17 11:18:15 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsink.h:
+	  udpsink/multiudpsink: Port to GIO
+
+2012-01-17 09:38:33 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstdynudpsink.h:
+	* gst/udp/gstudpsrc.c:
+	  dynudpsink: Port to GIO
+
+2012-01-17 09:32:27 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstdynudpsink.h:
+	  dynudpsink: Port to GIO
+
+2012-01-17 09:03:38 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/udp/Makefile.am:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstudpnetutils.c:
+	* gst/udp/gstudpnetutils.h:
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	* gst/udp/gstudpsrc.h:
+	  udpsrc: Port to GIO
+
+2012-01-16 17:51:18 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/cutter/gstcutter.c:
+	  cutter: fix leak of unused GValue
+
+2012-01-16 16:10:08 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* tests/check/elements/autodetect.c:
+	  tests: fix autodetect test not testing correctly for state change success
+	  State change to PAUSED can be done async, so if this happens, we need
+	  to wait for the change to be done (or failed).
+
+2012-01-16 15:42:46 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtp/gstrtph263ppay.c:
+	  rtph263ppay: fix caps leak
+
+2012-01-16 12:13:50 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: make interlacedness test deterministic
+	  If the interlaced flag is not present in the caps, we assume the
+	  data is not interlaced, instead of leaving the boolean uninitialized.
+
+2012-01-13 18:12:05 -0500  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/multifile/gstmultifilesink.c:
+	  matroska: fix printf format compiler warnings
+	  https://bugzilla.gnome.org/show_bug.cgi?id=662615
+
+2012-01-13 18:11:36 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: fix wrong error check
+	  pa_stream_* functions return negative on error, despite the defines
+	  for error codes being positive.
+	  I only got to repro the error twice, so I'm not sure 100% sure this
+	  fixes the issue (the negative var being uninitialized after returning
+	  from pa_stream_get_latency).
+
+2012-01-13 17:43:49 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/oss4/oss4-sink.c:
+	* sys/oss4/oss4-source.c:
+	  oss4: fix caps leaks
+
+2012-01-13 17:25:59 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: fix caps leak
+
+2012-01-13 15:57:20 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* tests/check/elements/videocrop.c:
+	  tests: fix caps leak in videotestsrc test
+
+2012-01-13 12:50:06 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: clean up obsolete closing segment handling
+
+2012-01-13 10:32:59 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpptdemux.c:
+	  rtpptdemux: plug pad leak in error code path
+	  Based on patch by: Stig Sandnes <stig.sandnes@cisco.com>
+	  Don't leak srcpad if there are no caps.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=667820
+
+2011-10-04 10:00:02 +0200  Stig Sandnes <stigsand@cisco.com>
+
+	* sys/osxvideo/cocoawindow.m:
+	  osxvideo: Fix leak of NSOpenGLPixelFormat object
+	  https://bugzilla.gnome.org/show_bug.cgi?id=667818
+
+2011-09-05 10:43:19 +0200  Havard Graff <havard.graff@tandberg.com>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: Don't assert when the interface is not implemented.
+	  Simply return FALSE instead.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=667817
+
+2012-01-12 00:18:39 +0200  Raimo Järvi <raimo.jarvi@gmail.com>
+
+	* sys/waveform/gstwaveformsink.c:
+	* sys/waveform/gstwaveformsink.h:
+	  waveformsink: Fix mingw warnings
+	  https://bugzilla.gnome.org/show_bug.cgi?id=667719
+
+2012-01-12 23:55:31 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/apetag/gstapedemux.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/matroska/matroska-read-common.c:
+	  GST_TYPE_DATE -> G_TYPE_DATE
+
+2012-01-12 23:48:50 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  eqMerge remote-tracking branch 'origin/master' into 0.11
+	  Conflicts:
+	  ext/jack/gstjackaudiosink.c
+	  ext/jack/gstjackaudiosrc.c
+	  gst/matroska/matroska-mux.c
+	  gst/matroska/matroska-read-common.c
+	  gst/rtpmanager/gstrtpssrcdemux.c
+
+2012-01-12 18:23:42 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  gstrtpssrcdemux: fix element leak
+
+2012-01-12 14:19:22 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroska: do not leak attachment buffers
+
+2012-01-12 13:17:55 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: remove obsolete FIXME comments
+
+2012-01-12 10:30:11 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: do not drop the first data buffer on the floor (and leak it either)
+
+2012-01-12 11:08:38 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstindex.c:
+	* gst/flv/gstmemindex.c:
+	  flvdemux: add prefix to local GstIndex related copies
+	  ... to avoid duplicate type names with other such local copies in the wild.
+
+2012-01-12 11:07:33 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: activate pad before setting caps
+	  ... rather than the usual 0.10 other way around.
+	  Fixes #667558.
+
+2012-01-11 18:45:33 -0300  Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>
+
+	* Android.mk:
+	  Temporarily disabling multifile for the Android build
+	  There is a hard dependency on inotify comming from gio. We
+	  are not currently bundling inotify with the Android dist so
+	  I'm disabling multifile for now until someone gets around
+	  to sort this out.
+	  This change fixes building on Android
+
+2010-10-20 02:17:43 -0700  Leo Singer <leo.singer@ligo.org>
+
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/audiofx/audiofxbaseiirfilter.c:
+	* gst/audiofx/audioiirfilter.c:
+	* tests/check/elements/audioiirfilter.c:
+	  audiofx: Use most common convention for definitions of IIR filter coefficients.
+	  Most signal processing texts, including MATLAB, use the following convention for IIR filter coefficients:
+	  a_0 y[n] + a_1 y[n-1] + ... + a_M y[n-M] = b_0 x[n] + b_1 x[n-1] + ... + b[N] x[n-N]
+	  Usually, a_0 is set to 1 because the coefficients can always be rescaled, giving
+	  y[n] = b_0 x[n] + b_1 x[n-1] + ... + b[N] x[n-N] - a_1 y[n-1] - ... - a_M y[n-M]
+	  The convention that was previously used by audiofxbaseiirfilter and derived class had the a and b coefficients swapped, and did not have the minus signs.
+	  This change makes the audiofx plugin use the more common convention described above.
+
+2012-01-11 14:47:36 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosink.h:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jack/gstjackaudiosrc.h:
+	  jack: add a transport mode enum
+	  Clients can configure the desired behaviour via "transport" property. The
+	  default behaviour is ignoring the transport state. Other modes are master and
+	  slave.
+
+2012-01-11 14:10:46 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Fix buffer handling
+	  souphttpsrc is now usable again and doesn't crash anymore
+	  whenever something is read from a HTTP connection.
+
+2012-01-11 01:45:34 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/pipelines/wavenc.c:
+	  tests: fix wavenc test on big endian
+	  wavenc only accepts little-endian PCM, but most of our
+	  elements such as audiotestsrc only produce or process
+	  audio in native endianness, so we need to plug a
+	  converter before wavenc on big endian systems.
+
+2012-01-10 23:02:45 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: deactivate the request_state code
+	  When qjackctl is started, transport is stopped by default. This would be a
+	  regression for gstreamer apps that before just started to play right away.
+
+2012-01-10 22:27:11 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/jack/gstjackaudioclient.c:
+	* ext/jack/gstjackaudioclient.h:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: add transport control handling
+	  This feature allows to start and stop playback from other jack applications (e.g. qjackctl).
+
+2012-01-10 18:50:27 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: fix codec_priv leaks
+	  https://bugzilla.gnome.org/show_bug.cgi?id=667419
+
+2012-01-10 15:06:39 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/jack/gstjackaudioclient.c:
+	  jack: use jack type for the callback
+	  Jack headers have a typedef for the shutdown callback as well.
+
+2012-01-10 14:32:32 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/cairo/gsttextoverlay.c
+	  ext/pulse/pulseaudiosink.c
+	  gst/audioparsers/gstaacparse.c
+	  gst/avi/gstavimux.c
+	  gst/flv/gstflvmux.c
+	  gst/interleave/interleave.c
+	  gst/isomp4/gstqtmux.c
+	  gst/matroska/matroska-demux.c
+	  gst/matroska/matroska-mux.c
+	  gst/matroska/matroska-mux.h
+	  gst/matroska/matroska-read-common.c
+	  gst/multifile/gstmultifilesink.c
+	  gst/multipart/multipartmux.c
+	  gst/shapewipe/gstshapewipe.c
+	  gst/smpte/gstsmpte.c
+	  gst/udp/gstmultiudpsink.c
+	  gst/videobox/gstvideobox.c
+	  gst/videocrop/gstaspectratiocrop.c
+	  gst/videomixer/videomixer.c
+	  gst/videomixer/videomixer2.c
+	  gst/wavparse/gstwavparse.c
+	  po/ja.po
+	  po/lv.po
+	  po/sr.po
+	  tests/check/Makefile.am
+	  tests/check/elements/qtmux.c
+	  tests/check/elements/rgvolume.c
+
+2012-01-09 22:58:32 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	  docs: Remove old videomixer headers
+	  These got removed in the transition to videomixer2.
+
+2012-01-09 17:28:17 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: fix codec string leaks
+
+2012-01-09 14:51:44 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer.h:
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	* gst/videomixer/videomixerpad.h:
+	  videomixer: Remove videomixer and register videomixer2 as videomixer
+
+2012-01-09 11:36:58 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: initialize variable to avoid undefined use
+
+2012-01-06 09:40:22 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacdec.h:
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflacenc.h:
+	  flac: Port to the new raw audio caps
+
+2012-01-05 19:25:33 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  isomp4: fix caps leak
+
+2012-01-05 19:08:03 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  isomp4: remove dead assignment
+
+2012-01-05 14:18:03 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/auparse/gstauparse.c:
+	* gst/wavenc/gstwavenc.c:
+	  fix pad templates
+
+2012-01-04 15:05:41 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	  speex: Update for the new raw audio caps
+
+2012-01-04 14:54:10 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: Add the new layout field to the raw audio caps
+
+2012-01-04 14:52:46 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jack/gstjackutil.c:
+	* ext/jack/gstjackutil.h:
+	  jackaudiosrc: Port to the new multichannel audio caps
+
+2012-01-04 14:13:54 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Add FLAC and interleave to the non-ported plugins list
+	  Both need to be updated to the audio/x-raw caps and were only
+	  half-ported before.
+
+2012-01-04 13:48:36 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16depay.h:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpL16pay.h:
+	* gst/rtp/gstrtpchannels.c:
+	* gst/rtp/gstrtpchannels.h:
+	* gst/rtp/gstrtpg722depay.c:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	  rtp: Update for the new audio caps
+
+2012-01-04 12:06:12 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Update for libgstriff API changes
+	  Still needs to handle raw audio channel reordering
+
+2012-01-04 12:05:16 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: Update for the new raw audio caps
+
+2012-01-04 12:03:50 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: Update for the new raw audio caps layout field
+
+2012-01-04 11:57:20 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/replaygain/gstrganalysis.c:
+	* gst/replaygain/gstrglimiter.c:
+	* gst/replaygain/gstrgvolume.c:
+	  replaygain: Update for the new audio caps
+
+2012-01-04 11:52:29 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	  matroska: Update for the new raw audio interleaved caps field
+	  Still needs to be fixed to handle the multichannel channel-mask
+	  and reordering.
+
+2012-01-04 11:31:07 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/level/gstlevel.c:
+	  level: Update for the new raw audio layout field
+
+2012-01-04 11:29:26 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmuxmap.c:
+	* gst/isomp4/qtdemux.c:
+	  isomp4: Port to the new audio caps
+	  Still needs to handle the channel positions/masks and
+	  channel reordering.
+
+2012-01-04 11:11:06 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/cutter/gstcutter.c:
+	  cutter: Update for the new raw audio layout field
+
+2012-01-04 11:09:32 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/goom/gstgoom.c:
+	  goom: Port to the new multichannel caps and update for the new raw audio layout field
+
+2012-01-04 11:08:18 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/equalizer/gstiirequalizer.c:
+	  equalizer: Update for the new raw audio layout field
+
+2012-01-04 11:07:29 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Update for the libgstriff API changes
+	  Still needs to do reordering of channels for raw audio.
+
+2012-01-04 11:06:28 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/auparse/gstauparse.c:
+	  auparse: Port to the new multichannel caps and the new raw audio layout field
+
+2012-01-04 11:02:43 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbaseiirfilter.c:
+	* gst/audiofx/audioinvert.c:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/audiofx/audiopanorama.c:
+	  audiofx: Port to the new multichannel caps and the new raw audio layout field
+
+2012-01-04 10:54:46 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/oss/gstosssink.c:
+	* sys/oss/gstosssrc.c:
+	  oss: Port to the new multichannel caps and the raw audio caps interleaved field
+
+2012-01-04 10:27:09 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.h:
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulseutil.c:
+	  pulse: Port to the new multichannel caps
+
+2012-01-04 19:51:46 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 762b692 to 0807187
+
+2012-01-04 17:59:55 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/qtmux.c:
+	  tests: fix some leaks and remove files when done in qtmux test
+
+2011-12-14 10:14:20 +0100  Peter Seiderer <ps.report@gmx.net>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: post better error message when we run out of disk space
+	  Map write errno ENOSPC to GST_RESOURCE_ERROR_NO_SPACE_LEFT.
+
+2012-01-04 13:26:45 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	* tests/check/elements/alphacolor.c:
+	  alphacolor: More fixes/cleanup
+
+2012-01-04 13:25:40 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Refactor param/process functions
+	  When ::set_info() is called, the input/output VideoInfo aren't set
+	  yet on the videofilter.
+
+2012-01-04 10:01:48 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/cairo/gsttextoverlay.c:
+	* ext/dv/gstdvdemux.c:
+	* ext/libpng/gstpngdec.c:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	* ext/wavpack/gstwavpackparse.c:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/interleave/interleave.c:
+	* gst/videomixer/videomixer2.c:
+	  GST_FLOW_UNEXPECTED -> GST_FLOW_EOS
+
+2011-12-31 23:33:33 -0500  Matej Knopp <matej.knopp@gmail.com>
+
+	* gst/audioparsers/gstdcaparse.c:
+	  dcaparse: use right variable
+	  Fixes use of unitialized variable.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=667085
+
+2012-01-03 15:26:21 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavisubtitle.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/ebml-read.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/multifile/gstsplitfilesrc.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartmux.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/wavparse/gstwavparse.c:
+	  GST_FLOW_UNEXPECTED -> GST_FLOW_EOS
+
+2012-01-03 14:42:28 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/pipelines/tagschecking.c:
+	  tests: rewrite test a little
+	  Rewrite the tag check so that we don't need to deal with tag lists.
+
+2012-01-03 14:16:28 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/jpegenc.c:
+	* tests/check/elements/multifile.c:
+	* tests/check/elements/qtmux.c:
+	* tests/check/elements/rtp-payloading.c:
+	* tests/check/elements/rtpbin.c:
+	* tests/check/elements/rtpbin_buffer_list.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	* tests/check/elements/shapewipe.c:
+	* tests/check/elements/souphttpsrc.c:
+	* tests/check/elements/udpsink.c:
+	* tests/check/elements/videocrop.c:
+	* tests/check/elements/videofilter.c:
+	* tests/check/elements/y4menc.c:
+	* tests/check/pipelines/flacdec.c:
+	* tests/check/pipelines/tagschecking.c:
+	  tests: make more tests compile
+
+2012-01-03 11:56:25 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/equalizer.c:
+	* tests/check/elements/flacparse.c:
+	* tests/check/elements/flvdemux.c:
+	* tests/check/elements/flvmux.c:
+	* tests/check/elements/icydemux.c:
+	* tests/check/elements/imagefreeze.c:
+	* tests/check/elements/interleave.c:
+	* tests/check/elements/level.c:
+	* tests/check/elements/multifile.c:
+	* tests/check/elements/qtmux.c:
+	* tests/check/elements/rganalysis.c:
+	* tests/check/elements/rglimiter.c:
+	* tests/check/elements/rgvolume.c:
+	  test: make more unit tests compile
+
+2012-01-03 10:26:48 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/audiofirfilter.c:
+	* tests/check/elements/audioiirfilter.c:
+	* tests/check/elements/audioinvert.c:
+	* tests/check/elements/audiowsincband.c:
+	* tests/check/elements/audiowsinclimit.c:
+	* tests/check/elements/autodetect.c:
+	* tests/check/elements/avimux.c:
+	* tests/check/elements/avisubtitle.c:
+	* tests/check/elements/capssetter.c:
+	* tests/check/elements/deinterlace.c:
+	* tests/check/elements/deinterleave.c:
+	* tests/check/generic/index.c:
+	* tests/check/generic/states.c:
+	  tests: fix some unit tests
+	  Remove unit test for GstIndex.
+	  Make some other unit tests compile
+
+2012-01-02 14:32:40 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	* gst/rtsp/gstrtspext.c:
+	  autodetect, rtsp: gst_registry_get_default() -> gst_registry_get()
+
+2011-12-31 10:00:41 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/examples/v4l2/camctrl.c:
+	  controller: port to API changes
+
+2011-12-30 17:41:46 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: update for GstIndex removal
+
+2011-12-30 17:23:43 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: update for GstIndex removal
+
+2011-12-30 17:20:57 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/flv/Makefile.am:
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	* gst/flv/gstindex.c:
+	* gst/flv/gstindex.h:
+	* gst/flv/gstmemindex.c:
+	  flvdemux: update for GstIndex removal
+	  Add private GstMemIndex for now.
+
+2011-12-30 17:12:03 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: update for GstIndex removal
+
+2011-12-27 22:59:03 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/waveform/gstwaveformsink.c:
+	  waveformsink: fix compiler warnings with MingW
+	  https://bugzilla.gnome.org/show_bug.cgi?id=666485
+
+2011-12-27 12:06:16 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/.gitignore:
+	  tests: make git ignore new unit test binary
+
+2011-12-27 11:50:03 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: fix valgrind warning
+	  https://bugzilla.gnome.org/show_bug.cgi?id=666644
+
+2011-12-27 11:49:10 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/udpsrc.c:
+	  udpsrc: add unit test that sends 0-size packet
+	  https://bugzilla.gnome.org/show_bug.cgi?id=666644
+
+2011-12-21 13:22:03 +0100  John Ogness <john.ogness@linutronix.de>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: drop dataless UDP packets
+	  It is allowed to send/receive UDP packets with no data. When such
+	  a packet is available, select() will return with success but
+	  ioctl(FIONREAD) will return 0. But a read() must still occur in
+	  order to clear off the UDP packet from the queue.
+	  This patch will read the dataless packet from the socket. If
+	  select() was woken for other reasons (and FIONREAD returns 0),
+	  this may result in a UDP packet getting accidentally dropped.
+	  But since UDP is not reliable, this is acceptable.
+	  NOTE: This patch fixes a nasty bug where sending a dataless
+	  UDP packet to a udpsrc instance will cause an infinite
+	  loop.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=666644
+	  Signed-off-by: John Ogness <john.ogness@linutronix.de>
+
+2011-12-26 22:22:59 +0000  Yaakov Selkowitz <yselkowitz@users.sourceforge.net>
+
+	* configure.ac:
+	* sys/Makefile.am:
+	* sys/waveform/Makefile.am:
+	  waveform: add autotools bits for waveform plugin
+	  https://bugzilla.gnome.org/show_bug.cgi?id=666485
+
+2011-12-21 20:50:21 +0100  Nicola Murino <nicola.murino@gmail.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fix peer_caps leak
+	  https://bugzilla.gnome.org/show_bug.cgi?id=666688
+
+2011-12-25 23:52:46 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: remove unnecessary check for gdp library
+
+2011-12-25 22:17:53 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* ext/pulse/Makefile.am:
+	* ext/pulse/plugin.c:
+	* ext/pulse/pulseaudiosink.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	  pulse: remove pulseaudiosink helper bin
+	  This is causing us lots of headaches in 0.10 and needs to be done
+	  differently and properly in 0.11. playbin or decodebin should
+	  reconfigure themselves based on reconfigure events, for example.
+
+2011-12-25 21:45:45 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulseutil.c:
+	  pulse: update for ring buffer audio format type enum rename
+
+2011-12-25 20:34:52 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/examples/v4l2/camctrl.c:
+	  controller: port to new control source api
+
+2011-12-25 14:23:29 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: don't try to push already-freed buffers
+	  Fixes unit test.
+
+2011-12-24 10:57:42 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Use scale_ceil() functions from core instead of custom ones
+
+2011-12-21 23:51:03 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalpha.h:
+	* gst/alpha/gstalphacolor.c:
+	* gst/alpha/gstalphacolor.h:
+	* gst/debugutils/gstnavigationtest.c:
+	* gst/debugutils/gstnavigationtest.h:
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstaging.h:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstdice.h:
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstedge.h:
+	* gst/effectv/gstop.c:
+	* gst/effectv/gstop.h:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstquark.h:
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstradioac.h:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstrev.h:
+	* gst/effectv/gstripple.c:
+	* gst/effectv/gstripple.h:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gstshagadelic.h:
+	* gst/effectv/gststreak.c:
+	* gst/effectv/gststreak.h:
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstvertigo.h:
+	* gst/effectv/gstwarp.c:
+	* gst/effectv/gstwarp.h:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstgamma.h:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideobalance.h:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videofilter/gstvideoflip.h:
+	  update for videofilter changes.
+
+2011-12-21 17:43:10 +0100  Branko Subasic <branko@axis.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: do not consider duration of non-finalized file
+	  ... to avoid it clamping requested seek position.
+	  Non-finalized file case, determined by whether
+	  _parse_blockgroup_or_simpleblock ever updates the segment duration.
+	  Fixes #652195.
+
+2011-12-21 15:06:57 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: improve decision to fall back to scanning when seeking
+	  ... which is basically iff not streaming and no entry found in index
+
+2011-12-21 09:09:27 +0100  Oleksij Rempel (Alexey Fisher) <bug-track@fisher-privat.net>
+
+	* gst/audioparsers/gstaacparse.c:
+	  ac3parse: remove unused variable
+	  remove unused variable to fix compile error:
+	  make -C audioparsers
+	  make[3]: Betrete Verzeichnis '/home/lex/tmp/gst-plugins-good/gst/audioparsers'
+	  CC     libgstaudioparsers_la-gstaacparse.lo
+	  gstaacparse.c: In function 'gst_aac_parse_read_loas_audio_specific_config':
+	  gstaacparse.c:446:12: error: variable 'sbr' set but not used [-Werror=unused-but-set-variable]
+	  cc1: all warnings being treated as errors
+	  Signed-off-by: Oleksij Rempel (Alexey Fisher) <bug-track@fisher-privat.net>
+
+2011-12-21 11:59:46 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsemixer.c:
+	* ext/pulse/pulseprobe.h:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2radio.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* tests/examples/pulse/pulse.c:
+	* tests/examples/v4l2/Makefile.am:
+	* tests/examples/v4l2/probe.c:
+	  update for removed property probe
+
+2011-09-09 11:42:09 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: let bsid 9 and 10 through
+	  Files with 9 and 10 happen, and seem to comply with the <= 8
+	  format, so let them through.
+	  The spec says nothing about 9 and 10.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=658546
+
+2011-12-19 23:50:19 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/examples/v4l2/camctrl.c:
+	  controller: port to new interpolation-mode api
+
+2011-12-19 22:53:57 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/examples/v4l2/camctrl.c:
+	  controller: port to new controller api
+
+2011-12-19 19:03:52 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: update for new interlaced caps
+
+2011-12-16 19:15:38 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: properly determine final duration
+	  ... which can be authoratively obtained from our own written timestamps.
+
+2011-12-19 13:56:30 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: only write full metadata at start
+	  ... rather than having (potentially) unnecessary duplicates written all over,
+	  or even contradictory varying filesize info, or duration info that will not
+	  be rewritten upon header rewrite.
+
+2011-12-16 19:15:03 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: use GstCollectPads2 buffer callback and running time clipper
+	  ... since the default collection heuristics suffice.
+
+2011-12-16 18:03:01 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: use GstCollectPads2 buffer callback and running time clipper
+	  ... since default collection heuristics suffice.
+
+2011-12-16 17:20:51 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: bring a few debug statements up to specs
+	  ... and minor spelling fix.
+
+2011-12-16 16:56:37 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: additional subtitle support
+
+2011-12-15 21:50:42 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: additional buffer handling cleanup
+
+2011-12-15 21:45:17 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: use GstCollectPads2 buffer callback and running time clipper
+
+2011-12-07 13:24:55 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstaacparse.h:
+	  aacparse: parse LOAS variant
+	  The LOAS variant seems to have three different subvariants itself,
+	  only one of them is implemented as my two samples happen to be
+	  using that one.
+	  The sample rate is not always reported correctly, as the "main"
+	  sample rate is apparently sometimes half what it should be (both
+	  of my samples report 24000 Hz there), and there are two other
+	  parts of the subvariant with different sampling rates. One of them
+	  is parsed, but not the other, as it's located after some other
+	  large amount of variable data that needs parsing first, and there
+	  seems to be a LOT of it, which is useless for our needs here.
+	  This ends up being rather inconsequential, as ffdec_aac_latm,
+	  which is the only decoder that can decode such streams, does not
+	  need the sample rate on the caps anyway.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=665394
+
+2011-12-19 10:48:54 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: don't remove srcpad
+	  Don't remove the always srcpad in ready and make the element reusable.
+
+2011-12-15 16:40:21 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  flvmux: use GstCollectPads2 event callback
+	  ... in stead of local HACK.
+
+2011-12-15 16:30:17 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: use GstCollectPads2 event callback
+	  ... in stead of local HACK.
+
+2011-12-15 16:16:52 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavimux.h:
+	  avimux: use GstCollectPads2 event callback
+	  ... in stead of local HACK.
+
+2011-12-15 16:15:22 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  qtmux: use GstCollectPads2 event callback
+	  ... in stead of local HACK.
+
+2011-12-14 19:13:21 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/smpte/gstsmpte.c:
+	* gst/smpte/gstsmpte.h:
+	  smpte: port to GstCollectPads2
+
+2011-12-14 19:10:53 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/multipart/multipartmux.c:
+	* gst/multipart/multipartmux.h:
+	  multipartmux: port to GstCollectPads2
+
+2011-12-14 19:07:23 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: port to GstCollectPads2
+
+2011-12-14 19:02:23 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  qtmux: port to GstCollectPads2
+
+2011-12-14 18:55:36 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/interleave/interleave.c:
+	* gst/interleave/interleave.h:
+	  interleave: port to GstCollectPads2
+
+2011-12-14 18:52:37 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  flxmux: port to GstCollectPads2
+
+2011-12-14 18:38:09 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavimux.h:
+	  avimux: port to GstCollectPads2
+
+2011-12-14 18:34:25 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/cairo/gsttextoverlay.c:
+	* ext/cairo/gsttextoverlay.h:
+	  cairotextoverlay: port to GstCollectPads2
+
+2011-12-13 18:18:45 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: filter bogus index entries with missing block number
+	  ... to avoid contradictory information resulting in seeks sending more
+	  downstream than needed for the corresponding segment.
+
+2011-12-13 18:15:18 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: cater for safer arithmetic with global start time
+
+2011-12-13 17:02:01 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: tweak final closing segment sending
+	  ... to avoid it interfering with (sparse) stream syncing.
+
+2011-12-12 11:51:06 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: make debug message more useful
+	  Add information about the taglist and which pad received the
+	  tag event on the debug logging.
+
+2011-12-13 11:46:43 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: avoid using floating point unnecessarily
+	  https://bugzilla.gnome.org/show_bug.cgi?id=665911
+
+2011-12-13 11:42:40 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: fix format specifier signedness
+	  Use unsigned specifiers for all unsigned values.
+	  A lot of the values used here are unsigned, and some can take
+	  high enough values that their signed counterpart will be negative.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=665911
+
+2011-12-12 16:49:19 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	* gst/wavparse/gstwavparse.h:
+	  wavparse: add a ignore-length property
+	  This allows playing broken streams which write an incorrect
+	  length in their data chunks (such as, at least, one streaming
+	  camera).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=665911
+
+2011-12-12 11:54:56 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst-libs/gst/glib-compat-private.h:
+	  glib-compat: Add license boilerplate for LGPL
+
+2011-12-12 15:15:46 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: mind (un)signed in some timestamp arithmetic
+	  ... to avoid ending up with invalid (negative) duration.
+
+2011-02-09 15:31:22 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: increase parse tolerance for fuzzy file cases
+
+2011-12-12 10:38:20 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* Makefile.am:
+	  build: dist glib-compat-private.h properly
+	  Add missing slash.
+
+2011-12-12 10:18:14 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: use atexit, g_atexit has been deprecated in glib master
+
+2011-12-12 02:52:13 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	* ext/flac/gstflacdec.c:
+	* ext/wavpack/gstwavpackparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/isomp4/gstqtmoovrecover.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/videomixer/videomixer2.c:
+	* gst/wavparse/gstwavparse.c:
+	  Suppress deprecation warnings in selected files, for g_static_rec_mutex_* mostly
+	  GStaticRecMutex is part of our API/ABI, not much we can do here
+	  in 0.10 for most of these.
+
+2011-12-12 02:41:37 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/souphttpsrc.c:
+	* tests/icles/equalizer-test.c:
+	* tests/icles/gdkpixbufsink-test.c:
+	* tests/icles/test-oss4.c:
+	* tests/icles/videocrop-test.c:
+	  tests: g_thread_init() is deprecated in glib master
+	  It's not needed any longer.
+
+2011-12-12 02:38:37 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* sys/oss4/oss4-mixer.c:
+	* tests/icles/v4l2src-test.c:
+	  Use g_thread_try_new() instead of g_thread_crate() with newer glib versions
+
+2011-12-12 02:31:36 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalpha.h:
+	  alpha: use new glib API for static mutex if available
+
+2011-12-12 02:30:45 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* Makefile.am:
+	* ext/jack/gstjackaudioclient.c:
+	* ext/pulse/pulseaudiosink.c:
+	* ext/pulse/pulsesink.c:
+	* ext/soup/gstsouphttpclientsink.c:
+	* gst-libs/gst/glib-compat-private.h:
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/audiofx/audiofirfilter.c:
+	* gst/audiofx/audioiirfilter.c:
+	* gst/audiofx/audiowsincband.c:
+	* gst/audiofx/audiowsinclimit.c:
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/videobox/gstvideobox.c:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer2.c:
+	* sys/oss4/oss4-mixer.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2xoverlay.c:
+	* sys/ximage/gstximagesrc.c:
+	  Work around deprecated thread API in glib master
+	  Add private replacements for deprecated functions such as
+	  g_mutex_new(), g_mutex_free(), g_cond_new() etc., mostly
+	  to avoid the deprecation warnings. We'll change these
+	  over to the new API once we depend on glib >= 2.32.
+
+2011-12-12 10:24:45 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Require GLib >= 2.24
+	  All other modules require this already and nobody is testing with
+	  older versions anyway.
+
+2011-12-11 18:40:31 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	  gdkpixbufsink: fix inverted pixel-aspect-ratio
+	  Spotted by Mike Morrison.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=665882
+
+2011-12-11 17:55:14 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	  pulseaudiosink: don't leak pad template
+
+2011-12-10 14:48:57 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	  soup: fix start/stop race in souphttpclientsink
+	  Fix crash or hang in generic/states unit test when doing stop()
+	  right after start(). Create main loop in the start function already
+	  and not just in the thread function, so that stop() always has a
+	  valid main loop to quit on. Also, calling g_main_loop_quit() before
+	  g_main_loop_run() won't work and result in the stop function waiting
+	  for the thread to join forever. Therefore, wait for the thread to
+	  be ready and get the main loop running in the start() function, to
+	  be sure stop() always works.
+
+2011-12-10 13:35:08 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/files/Makefile.am:
+	  tests: dist test file used in matroskaparse unit test
+
+2011-12-10 12:32:32 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/rgvolume.c:
+	  tests: fix up rgvolume test for basetransform event caching
+	  Some tests assumed that tag events would always pushed through
+	  immediately, which isn't the case any longer, so push a newsegment
+	  event and an empty buffer first.
+
+2011-12-10 11:12:01 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  ssrcdemux: fix iterator and caps
+
+2011-12-10 11:11:00 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: forward the caps event
+
+2011-12-10 11:09:43 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: simply forward the caps event
+	  forward the caps event we get as input instead of making a new event etc..
+
+2011-12-09 20:10:19 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: forward caps
+
+2011-12-09 19:46:02 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtp: pass parent to setcaps methods
+
+2011-12-10 02:21:02 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/LINGUAS:
+	* po/eo.po:
+	* po/ja.po:
+	* po/lv.po:
+	* po/sr.po:
+	  po: update translations
+
+2011-12-09 16:04:56 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	  pulse: rename "client" properties to "client-name"
+	  Better name, but also matches the property on the jack
+	  elements (where "client" is used for something else).
+
+2011-12-09 15:50:28 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: don't leak client name when freeing the element
+	  And add gtk-doc chunks for the new property.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=665872
+
+2011-12-09 15:45:03 +0000  Nicolas Baron <hoggins@radiom.fr>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosink.h:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jack/gstjackaudiosrc.h:
+	  jack: add "client-name" property to jackaudiosink and jackaudiosrc
+	  https://bugzilla.gnome.org/show_bug.cgi?id=665872
+
+2011-12-09 12:19:13 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/law/Makefile.am:
+	  law: fix CFLAGS and LIBS order in Makefile.am
+
+2011-12-09 12:15:30 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  Merge remote-tracking branch 'origin/master' into 0.11
+
+2011-12-09 10:51:14 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin-marshal.list:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	  rtp: fix marshallers
+	  Remove custom marshallers for minobject.
+	  Init RTCP buffer correctly.
+	  Handle results from setcaps
+	  Remove asserts.
+
+2011-12-09 10:50:18 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/law/Makefile.am:
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/alaw.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	  law: fix negotiation
+
+2011-12-08 11:00:45 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: stream-format=raw goes with aac caps, not mp3 caps
+
+2011-12-08 01:28:26 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  Merge remote-tracking branch 'origin/master' into 0.11
+	  Conflicts:
+	  sys/v4l2/gstv4l2object.c
+
+2011-12-02 12:07:24 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2src: do not ignore the highest frame interval
+	  https://bugzilla.gnome.org/show_bug.cgi?id=665387
+
+2011-12-02 11:59:03 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2src: do not ignore the largest resolution
+	  The 'max' value isn't an STL style "one after the end" bound,
+	  but the largest allowed value.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=665387
+
+2011-12-06 16:47:25 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/multifile/gstmultifilesink.h:
+	  docs: add add the two enum values that were just added too
+
+2011-12-06 16:14:54 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* gst/multifile/gstmultifilesink.h:
+	  multifilesink: expose the enum property docs for splitting mode.
+	  Fixes #665666.
+
+2011-12-06 14:23:30 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph263pay.c:
+	  h263pay: fix invalid return value
+
+2011-12-06 13:59:52 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: remove unused flush param
+
+2011-12-05 18:40:26 +0100  Edward Hervey <edward@collabora.com>
+
+	* gst/isomp4/gstrtpxqtdepay.c:
+	  rtpxqtdepay: Initialize GstRTPBuffer before usage
+
+2011-12-05 18:40:12 +0100  Edward Hervey <edward@collabora.com>
+
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	  rtpmanager: Initialize GstRTPBuffer before usage
+
+2011-12-05 18:39:59 +0100  Edward Hervey <edward@collabora.com>
+
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	  rtp: Initialize GstRTPBuffer before usage
+
+2011-12-05 12:15:21 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: replace deprecated GST_CLASS_LOCK
+
+2011-11-24 13:58:01 +0100  Sebastian Rasmussen <sebrn@axis.com>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: Ceil jpeg dimensions, instead of floor
+	  A JPEG image inside an RTP stream has a preceeding RFC2435 header that
+	  conveys width/height. The dimensions in this header are limited to be
+	  multiples of 8. Since JPEG uses an MCU of 8x8 pixels any image must
+	  already indirectly have image data dimensions that are rounded up in
+	  order to contain enough data to render the image. Therefore this fix
+	  safely rounds the image dimensions in the RFC2435 header up to the
+	  closest multiple of 8.
+
+2011-12-04 12:50:57 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstflacparse.h:
+	  flacparse: ensure we only check for sample/block mixup at start
+	  Otherwise we might trigger at some point within the file, but the
+	  check is only making sense for the second block.
+
+2011-12-03 18:14:59 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-parse.c:
+	  matroskaparse: warn if accumulating headers after they were pushed
+	  https://bugzilla.gnome.org/show_bug.cgi?id=665412
+
+2011-10-25 12:54:43 -0700  David Schleef <ds@schleef.org>
+
+	* gst/matroska/matroska-parse.c:
+	  matroskaparse: fix parsing
+	  Mark more parts as belonging to streamheaders.
+
+2011-12-03 17:30:10 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: fix discontinuity threshold check when timestamps go backwards
+	  Since unsigned types are used, a negative value would show as very, very
+	  positive.
+	  Fixes A/V sync on some... less than well made files where timestamps go
+	  backwards.
+
+2011-12-02 22:25:17 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/soup/gstsouphttpclientsink.c:
+	* gst/debugutils/testplugin.c:
+	* gst/multifile/gstmultifilesink.c:
+	  update for basesink event handler changes
+
+2011-12-02 12:01:22 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2src: add a comment about a "hidden" assumption on rank values
+	  https://bugzilla.gnome.org/show_bug.cgi?id=665387
+
+2011-12-02 01:58:30 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  Merge remote-tracking branch 'origin/master' into 0.11
+	  Conflicts:
+	  docs/plugins/inspect/plugin-esdsink.xml
+	  docs/plugins/inspect/plugin-gconfelements.xml
+	  ext/pulse/pulseaudiosink.c
+	  gst/matroska/matroska-demux.c
+	  gst/matroska/matroska-mux.c
+	  gst/multifile/gstmultifilesink.c
+
+2011-12-01 18:55:45 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-read-common.c:
+	* tests/check/elements/id3demux.c:
+	  update for tag API changes
+
+2011-12-01 15:29:15 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: placate gcc since -Werror is used
+	  Initialize values that GCC cannot prove are not used without
+	  being initialized, and assert that I did not mess up my proof.
+
+2011-12-01 14:13:05 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	  tests: fix up LIBS order som more`
+
+2011-12-01 13:22:42 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroska-mux: fix name of new property and the unit test
+	  https://bugzilla.gnome.org/show_bug.cgi?id=654379
+
+2011-09-25 14:57:56 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: add basic buffer list handling
+	  We assume for now that all buffers in a buffer list
+	  should end up in the same file (so we can group GOPs
+	  in buffer lists, for example). Could optimise this
+	  a bit to avoid the memcpy.
+
+2011-09-23 18:43:35 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: write stream-headers when switching to the next file in max-size mode
+
+2011-09-23 18:31:01 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesink.h:
+	  multifilesink: add new 'max-size' mode for switching to the next file
+
+2011-09-23 17:49:05 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesink.h:
+	  multifilesink: add "max-file-size" property for new next-file mode
+
+2011-12-01 13:38:06 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Don't forget SSA subtitles in last commit
+
+2011-12-01 13:34:52 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	  matroskademux: Only check for markup and escape if necessary for plaintext subtitles
+	  Otherwise we break USF and ASS/SSA subtitles.
+
+2011-12-01 13:23:33 +0100  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/multifile/Makefile.am:
+	  multifile: fix build in uninstalled setup
+	  Add -base libs includes to CFLAGS, fix order of LIBS <cit>.
+
+2011-12-01 13:08:01 +0100  Alessandro Decina <alessandro.d@gmail.com>
+
+	* tests/check/elements/multifile.c:
+	  tests: fix g_mkdtemp presence check in multifile tests
+	  g_mkdtemp was added in glib 2.30 even though the doc claims it was added in
+	  2.26.
+
+2011-07-17 23:56:04 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/multifile/Makefile.am:
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesink.h:
+	* tests/check/Makefile.am:
+	* tests/check/elements/multifile.c:
+	  multifilesink: add flag to cut after a force key unit event
+
+2011-12-01 12:47:26 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Copy all buffer flags when creating a subtitle buffer copy after postprocessing
+	  This also copies the caps. Otherwise we could end up pusing
+	  the first buffer without any caps, which causes downstream
+	  to not get notified about the caps.
+	  Fixes bug #664892.
+
+2011-10-11 02:07:13 +0200  Alexey Fisher <bug-track@fisher-privat.net>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: make default framerate optional per stream
+	  there is at least two use cases where default frame rate
+	  should or may be disabled:
+	  - vp8 stream with altref frame enabled. If default frame rate
+	  is enabled, some players will missinterprete it (critical!)
+	  - for webm container, to reduce micro overhead
+	  - for stream with variable frame rate.
+	  Signed-off-by: Alexey Fisher <bug-track@fisher-privat.net>
+
+2011-11-30 22:13:11 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/effectv/gstripple.c:
+	  rippletv: fix CLAMP end-values
+
+2011-11-30 19:25:37 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* 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.signals:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	  docs: update docs
+
+2011-11-30 19:00:42 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/multifile/Makefile.am:
+	* gst/multifile/gstsplitfilesrc.c:
+	* gst/multifile/patternspec.c:
+	* gst/multifile/patternspec.h:
+	  splitfilesrc: specify filenames via normal wildcards instead of regular expressions
+	  Less cracktastic in the end.
+
+2011-10-10 18:28:11 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/multifile/gstsplitfilesrc.c:
+	  splitfilesrc: check bytes actually read, just in case
+	  Handle corner case where we try to read beyond the end of the
+	  last file part, in which case we want to return a short read.
+	  If we get fewer bytes than expected for any other file part,
+	  we should just error out, since something fishy's going on
+	  then.
+
+2011-10-06 08:33:19 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/multifile/gstsplitfilesrc.c:
+	  splitfilesrc: set offsets on buffers
+	  Looks like some parsers (in some versions at least) expect the
+	  offsets to be set, and behave weird if that's not the case
+	  (e.g. off-by-one in h264parse).
+
+2011-07-28 20:19:56 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* gst/multifile/Makefile.am:
+	* gst/multifile/gstmultifile.c:
+	* gst/multifile/gstsplitfilesrc.c:
+	* gst/multifile/gstsplitfilesrc.h:
+	  multifile: add splitfilesrc element
+	  Add new splitfilesrc element that presents multiple files
+	  (selectable via a location regex) as one single contiguous
+	  file.
+
+2011-11-30 07:57:40 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsemixerctrl.h:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	  update for moved audio interfaces
+
+2011-11-29 17:34:10 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* ext/pulse/pulseaudiosink.c:
+	  Revert "pulseaudiosink: fix caps leak"
+	  This reverts commit d6a9de9e2aedc8b66ab3219902b5a37e8d65ada2.
+	  setcaps functions aren't supposed to take ownership of the caps passed
+
+2011-11-29 19:10:58 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videofilter/Makefile.am:
+	* gst/videofilter/gstvideobalance.c:
+	* sys/v4l2/gstv4l2colorbalance.h:
+	* sys/v4l2/gstv4l2videooverlay.h:
+	* sys/v4l2/gstv4l2vidorient.h:
+	* tests/icles/Makefile.am:
+	* tests/icles/v4l2src-test.c:
+	  fix for moved interfaces
+
+2011-11-28 23:20:32 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  Merge commit '7521b597f4dc49d8d168f368f0e7ebaf98a72156' into 0.11
+
+2011-11-28 21:27:53 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  Merge remote-tracking branch 'origin/master' into 0.11
+
+2011-11-28 21:27:40 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  Merge commit 'a2337b8af45cb5e8c091ff0e1c3ef4b6cc7b20a3' into 0.11
+
+2011-11-28 18:25:52 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	  Update for indexable change
+
+2011-11-28 17:52:06 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtsp/gstrtpdec.c:
+	  update for clock provider API change
+
+2011-11-28 16:57:24 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	* gst/rtsp/gstrtspsrc.c:
+	  fix for element flag updates
+
+2011-11-28 12:58:44 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/aalib/gstaasink.c:
+	* ext/annodex/gstcmmldec.c:
+	* ext/annodex/gstcmmlenc.c:
+	* ext/cairo/gstcairooverlay.c:
+	* ext/cairo/gstcairorender.c:
+	* ext/cairo/gsttextoverlay.c:
+	* ext/cairo/gsttimeoverlay.c:
+	* ext/dv/gstdvdec.c:
+	* ext/dv/gstdvdemux.c:
+	* ext/esd/esdmon.c:
+	* ext/esd/esdsink.c:
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflactag.c:
+	* ext/gconf/gstswitchsink.c:
+	* ext/gconf/gstswitchsrc.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	* ext/gdk_pixbuf/pixbufscale.c:
+	* ext/hal/gsthalaudiosink.c:
+	* ext/hal/gsthalaudiosrc.c:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstsmokedec.c:
+	* ext/jpeg/gstsmokeenc.c:
+	* ext/libcaca/gstcacasink.c:
+	* ext/libmng/gstmngdec.c:
+	* ext/libmng/gstmngenc.c:
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngenc.c:
+	* ext/mikmod/gstmikmod.c:
+	* ext/pulse/pulseaudiosink.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	* ext/shout2/gstshout2.c:
+	* ext/soup/gstsouphttpclientsink.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	* ext/taglib/gstapev2mux.cc:
+	* ext/taglib/gstid3v2mux.cc:
+	* ext/taglib/gsttaglibmux.c:
+	* ext/wavpack/gstwavpackdec.c:
+	* ext/wavpack/gstwavpackenc.c:
+	* ext/wavpack/gstwavpackparse.c:
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalphacolor.c:
+	* gst/apetag/gstapedemux.c:
+	* gst/audiofx/audiopanorama.c:
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/auparse/gstauparse.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavisubtitle.c:
+	* gst/cutter/gstcutter.c:
+	* gst/debugutils/breakmydata.c:
+	* gst/debugutils/cpureport.c:
+	* gst/debugutils/efence.c:
+	* gst/debugutils/gstcapsdebug.c:
+	* gst/debugutils/gstcapssetter.c:
+	* gst/debugutils/gstnavigationtest.c:
+	* gst/debugutils/gstnavseek.c:
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/debugutils/gsttaginject.c:
+	* gst/debugutils/progressreport.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/debugutils/testplugin.c:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstop.c:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstripple.c:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gststreak.c:
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstwarp.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/flx/gstflxdec.c:
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/id3demux/gstid3demux.c:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/interleave/deinterleave.c:
+	* gst/interleave/interleave.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstrtpxqtdepay.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/level/gstlevel.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/webm-mux.c:
+	* gst/median/gstmedian.c:
+	* gst/monoscope/gstmonoscope.c:
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartmux.c:
+	* gst/replaygain/gstrganalysis.c:
+	* gst/replaygain/gstrglimiter.c:
+	* gst/replaygain/gstrgvolume.c:
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpdepay.c:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpg722depay.c:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtpg723depay.c:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmparobustdepay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtppcmupay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpsirenpay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtsp/gstrtpdec.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/smpte/gstsmpte.c:
+	* gst/smpte/gstsmptealpha.c:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	* gst/videobox/gstvideobox.c:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer2.c:
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavparse/gstwavparse.c:
+	* gst/y4m/gsty4mencode.c:
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/oss/gstosssink.c:
+	* sys/oss/gstosssrc.c:
+	* sys/oss4/oss4-sink.c:
+	* sys/oss4/oss4-source.c:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxvideo/osxvideosink.m:
+	* sys/sunaudio/gstsunaudiosink.c:
+	* sys/sunaudio/gstsunaudiosrc.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/waveform/gstwaveformsink.c:
+	* sys/ximage/gstximagesrc.c:
+	* tests/check/elements/qtmux.c:
+	  various: fix pad template leaks
+	  https://bugzilla.gnome.org/show_bug.cgi?id=662664
+
+2011-11-28 13:08:27 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfdetect.c:
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  various: fix pad template ref leaks
+	  https://bugzilla.gnome.org/show_bug.cgi?id=662664
+
+2011-11-28 11:47:11 +0100  Chad <channa@caltech.edu>
+
+	* gst/debugutils/gsttaginject.c:
+	  taginject: set gap-aware
+	  The element does not modify the data anyway.
+
+2011-11-27 23:32:18 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: update po files
+
+2011-11-27 23:31:43 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  Merge remote-tracking branch 'origin/master' into 0.11
+	  Conflicts:
+	  gst/equalizer/gstiirequalizer.c
+
+2011-11-26 21:39:33 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/equalizer/gstiirequalizer.c:
+	  equalizer: also sync the parameters for the filter bands
+
+2011-11-26 16:06:59 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-ids.c:
+	  matroskademux: initialise seen_markup_tag field on subtitle stream context
+
+2011-11-26 10:01:07 +0100  René Stadler <rene.stadler@collabora.co.uk>
+
+	* configure.ac:
+	* gst/matroska/ebml-read.c:
+	* gst/matroska/ebml-read.h:
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	* gst/matroska/webm-mux.c:
+	* tests/check/elements/matroskamux.c:
+	  matroska: port to 0.11
+	  Support for TAG_IMAGE and TAG_ATTACHMENT is commented out; this requires caps
+	  on buffers which is gone from 0.11.
+	  Segment handling in the demuxer is a bit complex; I added some FIXME comments
+	  in places where I'm not yet sure if I ported correctly.
+
+2011-11-26 13:54:22 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* ext/pulse/plugin.c:
+	* ext/pulse/pulseaudiosink.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulsesrc.h:
+	* ext/pulse/pulseutil.c:
+	* ext/pulse/pulseutil.h:
+	  pulseaudio: require pulseaudio >= 1.0
+
+2011-11-26 13:34:10 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  Merge remote-tracking branch 'origin/master' into 0.11
+	  Conflicts:
+	  ext/pulse/pulseaudiosink.c
+	  ext/pulse/pulsesrc.c
+	  gst/audioparsers/gstaacparse.c
+	  gst/audioparsers/gstamrparse.c
+	  gst/audioparsers/gstdcaparse.c
+	  gst/audioparsers/gstflacparse.c
+	  gst/effectv/gstradioac.c
+	  gst/effectv/gstradioac.h
+	  gst/effectv/gstripple.c
+	  Some possible FIXMEs remaining in the audio parser getcaps functions.
+
+2011-11-25 19:28:55 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/gstqtmuxmap.c:
+	  ismlmux: Use iso-fragmented as variant type
+	  Using 'iso' conflicts with mp4mux variant type, ismlmux now
+	  uses iso-fragmented
+	  Fixes #656823
+
+2011-11-24 12:05:33 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulsesrc.h:
+	  pulsesrc: Implement GstStreamVolume interface
+	  PulseAudio 1.0 supports per-source-output volumes, and this exposes the
+	  functionality via the GstStreamVolume interface.
+	  When compiled against pre-1.0 PulseAudio, the interface is not
+	  implemented, and the "volume" or "mute" properties are not available.
+	  This bit of ugliness will go away when we can depend on PulseAudio 1.0
+	  or greater.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=595055
+
+2011-09-10 21:21:38 -0700  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: Trivial comment copy-paste-o fix
+
+2011-11-14 12:43:27 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	  pulseaudiosink: Remove redundant code
+
+2011-11-14 12:41:41 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	  pulseaudiosink: Clean up refcounting in event probe
+	  Makes sure we don't leak a refcount if the object is disposed before a
+	  NEWSEGMENT turns up.
+
+2011-11-24 16:31:38 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: fix seeking
+	  Which I accidentally broke when fixing flv videos breaking on
+	  spurious timestamp discontinuities in broken files.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=631430
+
+2011-11-25 13:13:47 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstradioac.h:
+	  effectv: repair color modes in radioactv by taking rgb,bgr into account
+
+2011-11-25 11:44:49 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/effectv/gstradioac.c:
+	  radioactv: add one more set of caps
+	  It also work in this format. Avoids the need for conversion.
+
+2011-11-25 11:44:18 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstshagadelic.c:
+	  effecttv: fix reverse negotiation
+	  The plugins were using _fixed_caps_ and thus not adjusting to new upstream
+	  sizes. Spotted by Tim Müller.
+
+2011-11-25 11:43:16 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/effectv/gstwarp.c:
+	  warptv: remove not needed ifdef
+
+2011-11-25 10:15:35 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/effectv/gstripple.c:
+	  rippletv: clean up the rendering code a bit
+	  This is corrrupts the memoy when resizing. Add a FIXME to make it resizeable
+	  once that is solved.
+
+2011-11-24 21:41:03 +0100  René Stadler <rene.stadler@collabora.co.uk>
+
+	* tests/check/elements/alphacolor.c:
+	* tests/check/elements/audioamplify.c:
+	* tests/check/elements/audiochebband.c:
+	* tests/check/elements/audiocheblimit.c:
+	* tests/check/elements/audiodynamic.c:
+	* tests/check/elements/audioecho.c:
+	* tests/check/elements/audioinvert.c:
+	* tests/check/elements/audiopanorama.c:
+	* tests/check/elements/audiowsincband.c:
+	* tests/check/elements/audiowsinclimit.c:
+	* tests/check/elements/avimux.c:
+	* tests/check/elements/avisubtitle.c:
+	* tests/check/elements/capssetter.c:
+	* tests/check/elements/cmmldec.c:
+	* tests/check/elements/cmmlenc.c:
+	* tests/check/elements/equalizer.c:
+	* tests/check/elements/icydemux.c:
+	* tests/check/elements/jpegenc.c:
+	* tests/check/elements/level.c:
+	* tests/check/elements/parser.c:
+	* tests/check/elements/qtmux.c:
+	* tests/check/elements/rganalysis.c:
+	* tests/check/elements/rglimiter.c:
+	* tests/check/elements/rgvolume.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	* tests/check/elements/spectrum.c:
+	* tests/check/elements/videofilter.c:
+	* tests/check/elements/y4menc.c:
+	  tests: update for gstcheck API change
+
+2011-11-24 20:42:49 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gststreak.c:
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstwarp.c:
+	  effecttv: fix reverse negotiation
+	  The plugins were using _fixed_caps_ and thus not adjusting to new upstream
+	  sizes. Spotted by Tim Müller.
+
+2011-11-24 14:14:53 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: Fix leak of filename strings
+	  Do not forget to free the filename strings when deleting
+	  the list of files.
+
+2011-11-24 14:11:33 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* tests/check/elements/multifile.c:
+	  multifile: fix build of tests
+	  Tests fail to build because g_mkdtemp is available from glib since
+	  2.26.
+	  This patch adds a condition around the redefinition of
+	  g_mkdtemp on the tests to only build it if glib is older than
+	  2.26.
+
+2011-09-27 16:49:45 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: skip id32 tags
+	  This allows decoding at least one sample where something has
+	  stuffed some ID3 tag before the (supposedly initial) FMT\ .
+	  https://bugzilla.gnome.org/show_bug.cgi?id=660249
+
+2011-10-31 17:06:18 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/effectv/gstedge.c:
+	  edgetv: trivial comment fix for clarity
+	  https://bugzilla.gnome.org/show_bug.cgi?id=661841
+
+2011-10-31 17:04:23 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/effectv/gstedge.c:
+	  edgetv: don't leave bits of the output buffer uninitialized
+	  Let's initialize them to zero. It looks alright, but then it
+	  also looks alright with v3, or with the corresponding pixels
+	  from the source. I don't know what the original intent would
+	  be, and the original effectv source also has this bug/feature.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=661841
+
+2011-11-24 10:25:02 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  audioparse: Use the sinkpad template caps as fallback, not the srcpad ones
+
+2011-11-24 09:59:40 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: Implement ::get_sink_caps vfunc to propagate downstream caps constraints upstream
+
+2011-11-24 09:57:57 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Implement ::get_sink_caps vfunc to propagate downstream caps constraints upstream
+
+2011-11-24 09:55:47 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstdcaparse.c:
+	  dcaparse: Implement ::get_sink_caps vfunc to propagate downstream caps constraints upstream
+
+2011-11-24 09:53:18 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstamrparse.c:
+	  amrparse: Implement ::get_sink_caps vfunc to propagate downstream caps constraints upstream
+
+2011-11-24 09:49:27 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstamrparse.c:
+	  amrparse: Mark some more functions as static
+
+2011-11-24 09:48:33 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: Implement ::get_sink_caps vfunc to propagate downstream caps constraints upstream
+
+2011-11-24 09:44:58 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Mark some functions as static and remove unused function declarations
+
+2011-11-24 09:43:14 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Implement ::get_sink_caps vfunc to propagate downstream caps constraints upstream
+
+2011-11-24 01:48:25 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: update soup test for removed iradio-mode property
+
+2011-11-24 01:45:43 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: get rid of iradio-* properties, post tags instead
+
+2011-11-24 01:40:06 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: always send icecast request header, drop iradio-mode property
+	  Server should ignore unknown/unhandled headers..
+
+2011-11-24 01:19:32 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: make connection-speed property a guint64
+
+2011-11-24 00:52:40 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/inspect/plugin-rtpmanager.xml:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpmanager.c:
+	* tests/check/elements/rtpbin.c:
+	* tests/examples/rtp/client-PCMA.c:
+	* tests/examples/rtp/client-PCMA.py:
+	* tests/examples/rtp/server-alsasrc-PCMA.c:
+	* tests/examples/rtp/server-alsasrc-PCMA.py:
+	  rtpmanager: rename gstrtp* -> rtp*
+	  This was done in 0.10 to avoid conflict with the rtp elements in
+	  farsight, but the gst-prefixing is no longer needed in 0.11
+
+2011-11-23 10:23:28 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-11-23 09:26:17 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	  pulseaudiosink: avoid endless caps loop
+	  Check if the caps are the same before adding a new probe. Because of reconfigure
+	  events, upstreams sends multiple caps events.
+
+2011-11-23 00:57:39 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/matroskaparse.c:
+	* tests/files/pinknoise-vorbis.mkv:
+	  tests: add basic unit test for matroskaparse
+
+2011-11-23 00:56:26 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-parse.c:
+	  matroskaparse: don't leak stream headers
+	  https://bugzilla.gnome.org/show_bug.cgi?id=664548
+
+2011-11-22 01:40:39 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/annodex/gstcmmldec.c:
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflactag.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/ximage/gstximagesrc.c:
+	  More printf format warning fixes
+
+2011-11-21 20:31:31 +0100  Matej Knopp <matej.knopp@gmail.com>
+
+	* configure.ac:
+	* gst/alpha/gstalpha.c:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/auparse/gstauparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavisubtitle.c:
+	* gst/debugutils/breakmydata.c:
+	* gst/debugutils/gstnavigationtest.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/goom/gstgoom.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpg723depay.c:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/spectrum/gstspectrum.c:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavparse/gstwavparse.c:
+	* sys/ximage/gstximagesrc.c:
+	  Fix printf format compiler warnings on OS X / 64bit
+	  https://bugzilla.gnome.org/show_bug.cgi?id=662615
+
+2011-11-21 13:37:01 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/wavparse/gstwavparse.c:
+	  update for activation changes
+
+2011-11-18 17:59:16 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/wavparse/gstwavparse.c:
+	  update for new scheduling query
+
+2011-11-18 13:57:20 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	* gst/avi/gstavidemux.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/wavparse/gstwavparse.c:
+	  add parent to activate functions
+
+2011-11-17 17:36:05 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: activate pad before setting caps
+	  Seting caps on an inactive flushing pad does nothing.
+
+2011-11-17 17:17:11 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/speex/gstspeexenc.c
+	  gst/rtpmanager/rtpsession.c
+
+2011-11-17 15:02:55 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/annodex/gstcmmldec.c:
+	* ext/annodex/gstcmmlenc.c:
+	* ext/flac/gstflactag.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/pulse/pulseaudiosink.c:
+	* gst/auparse/gstauparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavisubtitle.c:
+	* gst/cutter/gstcutter.c:
+	* gst/debugutils/gstnavigationtest.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/goom/gstgoom.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartmux.c:
+	* gst/replaygain/gstrgvolume.c:
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtsp/gstrtpdec.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavparse/gstwavparse.c:
+	* gst/y4m/gsty4mencode.c:
+	  add parent to pad functions
+
+2011-11-17 08:24:58 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/cairo/gsttextoverlay.c:
+	* gst/avi/gstavimux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/interleave/interleave.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/multipart/multipartmux.c:
+	* gst/smpte/gstsmpte.c:
+	* gst/videomixer/videomixer.c:
+	  collectpads: port API changes
+
+2011-11-16 19:08:05 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/speex/gstspeexenc.c:
+	  speexenc: ensure to free allocated padded data
+
+2011-11-16 18:57:38 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/speex/gstspeexenc.c:
+	  speexenc: reset tag setter interface when appropriate
+
+2011-11-16 18:57:21 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: reset tag setter interface when appropriate
+
+2011-11-16 17:54:49 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  add parent to internal links
+
+2011-11-16 17:27:13 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/annodex/gstcmmldec.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/pulse/pulseaudiosink.c:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/auparse/gstauparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/goom/gstgoom.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtsp/gstrtpdec.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/wavparse/gstwavparse.c:
+	  add parent to query function
+
+2011-11-16 12:40:08 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/goom/gstgoom.c:
+	  goom: update for renamed flags
+	  Use the _check_reconfigure method instead of checking flags.
+	  Don't need to ref the parent anymore, core does that.
+
+2011-11-15 18:01:16 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/auparse/gstauparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/debugutils/progressreport.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/wavparse/gstwavparse.c:
+	  _query_peer_*() -> _peer_query_*()
+
+2011-11-15 17:45:31 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	  _accept_caps() -> _query_accept_caps()
+
+2011-11-15 17:29:45 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	* ext/pulse/pulseaudiosink.c:
+	* ext/pulse/pulsesrc.c:
+	* gst/goom/gstgoom.c:
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/shapewipe/gstshapewipe.c:
+	* sys/v4l2/gstv4l2src.c:
+	  _peer_get_caps() -> _peer_query_caps()
+
+2011-11-15 16:55:27 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/pulse/pulseaudiosink.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* sys/v4l2/gstv4l2src.c:
+	* tests/icles/gdkpixbufsink-test.c:
+	  update for _get_caps() -> _query_caps()
+
+2011-11-15 16:31:45 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/videocrop/gstaspectratiocrop.c:
+	  change getcaps to query
+	  Chain up event function in payloaders.
+
+2011-11-15 13:23:56 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: fix spurious timestamp discontinuity
+	  We need to tell the base class that we're dropping buffers,
+	  so it drops the input timestamps corresponding to these.
+	  Otherwise, the first actual audio buffers we output will be
+	  stamped with those - GST_CLOCK_TIMESTAMP_NONE. That mismatch
+	  between input buffer count and output buffer count will stay
+	  while playing. With enough headers and long enough buffer
+	  durations, the sink will have played enough before receiving
+	  the first valid timestamp (usually 0), and will trigger an
+	  audible discontinuity.
+
+2011-11-14 15:34:57 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstflacparse.h:
+	  flacparse: detect when a file lies about fixed block size
+	  If the sample/block number happens to be the same as the block
+	  size, we assume variable block size, and thus counters in samples
+	  in the headers. This can only get us a false positive for a block
+	  size of 1, which is invalid. We can get false negatives more
+	  often though (eg, if not starting at the start of the stream),
+	  but then that's already GIGO.
+
+2011-09-02 19:20:07 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  gstrtpsession: Add special mode to use FIR as repair as Google does
+	  https://bugzilla.gnome.org/show_bug.cgi?id=658419
+
+2011-09-01 17:47:38 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpsession: Send FIR requests in response to key unit requests with all-headers=TRUE
+	  https://bugzilla.gnome.org/show_bug.cgi?id=658419
+
+2011-09-01 16:25:21 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpsession: Put the PLI requests in each RTPSource
+	  Also refactor a bit and put all the keyframe request code in one
+	  place inside rtpsession.c
+	  https://bugzilla.gnome.org/show_bug.cgi?id=658419
+
+2011-08-31 14:35:33 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Hack to FIR because Google doesn't set the sender ssrc correctly
+	  https://bugzilla.gnome.org/show_bug.cgi?id=658419
+
+2011-08-30 19:06:13 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Process received Full Intra Requests
+	  Process FIR requests according to RFC 5104
+	  https://bugzilla.gnome.org/show_bug.cgi?id=658419
+
+2011-11-07 18:43:26 +0000  Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Set pixel-aspect-ratio to 1/1
+	  We don't currently support setting the pixel-aspect-ratio from V4L2. So
+	  simply set it to be 1/1 in the caps to prevent negotiation failures when
+	  fixating to weird values (e.g. when the downstream caps has
+	  pixel-aspect-ratio = [ MIN, MAX ] )
+	  https://bugzilla.gnome.org/show_bug.cgi?id=663580
+
+2011-11-14 09:39:15 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/id3demux.c:
+	  tests: make id3demux test compile
+	  Still fails though.
+
+2011-11-12 15:42:27 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/examples/shapewipe/shapewipe-example.c:
+	* tests/examples/v4l2/camctrl.c:
+	  controller: no need to explicitely add controlled properties anymore
+
+2011-11-13 23:42:44 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	* sys/v4l2/gstv4l2radio.c:
+	* sys/v4l2/gstv4l2src.c:
+	  Update for GstURIHandler get_protocols() changes
+
+2011-11-13 18:50:51 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	* sys/v4l2/gstv4l2radio.c:
+	* sys/v4l2/gstv4l2src.c:
+	  soup, pushfile, rtsp, udp, v4l2: update for GstURIHandler API changes
+
+2011-11-11 19:24:27 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/pulse/pulseaudiosink.c
+
+2011-11-11 19:21:50 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpg729pay.c:
+	  rtp: fix for rtp header changes
+
+2011-11-11 10:06:25 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* ext/pulse/pulseaudiosink.c:
+	  pulseaudiosink: fix caps leak
+
+2011-11-11 14:55:48 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: do not leak clientname when setting up property
+
+2011-11-11 18:05:35 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	  pulse: Chain up dispose() in pulseaudiosink
+
+2011-11-11 12:32:41 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/gstrtpxqtdepay.h:
+	* gst/rtp/fnv1hash.h:
+	* gst/rtp/gstrtpL16depay.h:
+	* gst/rtp/gstrtpL16pay.h:
+	* gst/rtp/gstrtpac3depay.h:
+	* gst/rtp/gstrtpac3pay.h:
+	* gst/rtp/gstrtpamrdepay.h:
+	* gst/rtp/gstrtpamrpay.h:
+	* gst/rtp/gstrtpbvdepay.h:
+	* gst/rtp/gstrtpbvpay.h:
+	* gst/rtp/gstrtpceltdepay.h:
+	* gst/rtp/gstrtpceltpay.h:
+	* gst/rtp/gstrtpdvdepay.h:
+	* gst/rtp/gstrtpdvpay.h:
+	* gst/rtp/gstrtpg722depay.h:
+	* gst/rtp/gstrtpg722pay.h:
+	* gst/rtp/gstrtpg723depay.h:
+	* gst/rtp/gstrtpg723pay.h:
+	* gst/rtp/gstrtpg726depay.h:
+	* gst/rtp/gstrtpg726pay.h:
+	* gst/rtp/gstrtpg729depay.h:
+	* gst/rtp/gstrtpg729pay.h:
+	* gst/rtp/gstrtpgsmdepay.h:
+	* gst/rtp/gstrtpgsmpay.h:
+	* gst/rtp/gstrtpgstdepay.h:
+	* gst/rtp/gstrtpgstpay.h:
+	* gst/rtp/gstrtph263depay.h:
+	* gst/rtp/gstrtph263pay.h:
+	* gst/rtp/gstrtph263pdepay.h:
+	* gst/rtp/gstrtph263ppay.h:
+	* gst/rtp/gstrtph264depay.h:
+	* gst/rtp/gstrtph264pay.h:
+	* gst/rtp/gstrtpilbcdepay.h:
+	* gst/rtp/gstrtpilbcpay.h:
+	* gst/rtp/gstrtpj2kdepay.h:
+	* gst/rtp/gstrtpj2kpay.h:
+	* gst/rtp/gstrtpjpegdepay.h:
+	* gst/rtp/gstrtpjpegpay.h:
+	* gst/rtp/gstrtpmp1sdepay.h:
+	* gst/rtp/gstrtpmp2tdepay.h:
+	* gst/rtp/gstrtpmp2tpay.h:
+	* gst/rtp/gstrtpmp4adepay.h:
+	* gst/rtp/gstrtpmp4apay.h:
+	* gst/rtp/gstrtpmp4gdepay.h:
+	* gst/rtp/gstrtpmp4gpay.h:
+	* gst/rtp/gstrtpmp4vdepay.h:
+	* gst/rtp/gstrtpmp4vpay.h:
+	* gst/rtp/gstrtpmpadepay.h:
+	* gst/rtp/gstrtpmpapay.h:
+	* gst/rtp/gstrtpmparobustdepay.h:
+	* gst/rtp/gstrtpmpvdepay.h:
+	* gst/rtp/gstrtpmpvpay.h:
+	* gst/rtp/gstrtppcmadepay.h:
+	* gst/rtp/gstrtppcmapay.h:
+	* gst/rtp/gstrtppcmudepay.h:
+	* gst/rtp/gstrtppcmupay.h:
+	* gst/rtp/gstrtpqcelpdepay.h:
+	* gst/rtp/gstrtpqdmdepay.h:
+	* gst/rtp/gstrtpsirendepay.h:
+	* gst/rtp/gstrtpsirenpay.h:
+	* gst/rtp/gstrtpspeexdepay.h:
+	* gst/rtp/gstrtpspeexpay.h:
+	* gst/rtp/gstrtpsv3vdepay.h:
+	* gst/rtp/gstrtptheoradepay.h:
+	* gst/rtp/gstrtptheorapay.h:
+	* gst/rtp/gstrtpvorbisdepay.h:
+	* gst/rtp/gstrtpvorbispay.h:
+	* gst/rtp/gstrtpvrawdepay.h:
+	* gst/rtp/gstrtpvrawpay.h:
+	  update for base class rename
+
+2011-11-11 12:25:01 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/gstrtpxqtdepay.c:
+	* gst/isomp4/gstrtpxqtdepay.h:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16depay.h:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpL16pay.h:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpac3depay.h:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpac3pay.h:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrdepay.h:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpamrpay.h:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpbvdepay.h:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpbvpay.h:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltdepay.h:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpceltpay.h:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpdvdepay.h:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpdvpay.h:
+	* gst/rtp/gstrtpg722depay.c:
+	* gst/rtp/gstrtpg722depay.h:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtpg722pay.h:
+	* gst/rtp/gstrtpg723depay.c:
+	* gst/rtp/gstrtpg723depay.h:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg723pay.h:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726depay.h:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpg726pay.h:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpg729depay.h:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpg729pay.h:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmdepay.h:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtpgsmpay.h:
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtpgstdepay.h:
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtpgstpay.h:
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263depay.h:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pay.h:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263pdepay.h:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph263ppay.h:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264depay.h:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtph264pay.h:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpilbcdepay.h:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpilbcpay.h:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kdepay.h:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpj2kpay.h:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegdepay.h:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpjpegpay.h:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp1sdepay.h:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.h:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp2tpay.h:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4adepay.h:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4apay.h:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gdepay.h:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4gpay.h:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmp4vdepay.h:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmp4vpay.h:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpadepay.h:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmpapay.h:
+	* gst/rtp/gstrtpmparobustdepay.c:
+	* gst/rtp/gstrtpmparobustdepay.h:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtpmpvdepay.h:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtpmpvpay.h:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmadepay.h:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmapay.h:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtppcmudepay.h:
+	* gst/rtp/gstrtppcmupay.c:
+	* gst/rtp/gstrtppcmupay.h:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpqcelpdepay.h:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpqdmdepay.h:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpsirendepay.h:
+	* gst/rtp/gstrtpsirenpay.c:
+	* gst/rtp/gstrtpsirenpay.h:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexdepay.h:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpspeexpay.h:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtpsv3vdepay.h:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheoradepay.h:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtptheorapay.h:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbisdepay.h:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvorbispay.h:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawdepay.h:
+	* gst/rtp/gstrtpvrawpay.c:
+	* gst/rtp/gstrtpvrawpay.h:
+	  update for base class rename
+
+2011-11-11 12:01:17 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosink.h:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/pulse/pulsesink.c:
+	  update for audiobase* rename
+
+2011-11-11 11:53:45 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosink.h:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jack/gstjackaudiosrc.h:
+	* ext/pulse/pulseaudiosink.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	* ext/pulse/pulsesrc.c:
+	  audio: update for base class rename
+
+2011-11-11 11:33:44 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulseutil.h:
+	* gst/equalizer/gstiirequalizer.h:
+	  fix for ringbuffer rename
+
+2011-11-11 11:24:00 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jack/gstjackringbuffer.h:
+	* ext/pulse/pulseaudiosink.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulseutil.c:
+	* ext/pulse/pulseutil.h:
+	  update for ringbuffer change
+
+2011-11-10 23:15:30 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/examples/shapewipe/shapewipe-example.c:
+	* tests/examples/v4l2/camctrl.c:
+	  controller: port api changes
+
+2011-11-10 23:09:23 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/annodex/gstannodex.c:
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/audiofx/audiofxbaseiirfilter.c:
+	* gst/audiofx/audiopanorama.c:
+	* gst/equalizer/gstiirequalizer.c:
+	  various: add missing includes
+
+2011-11-10 21:35:24 +0100  René Stadler <rene.stadler@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: fix compilation with pulseaudio 0.9
+
+2011-11-10 18:32:58 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/flac/gstflactag.c:
+	* gst/auparse/gstauparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/goom/gstgoom.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/wavparse/gstwavparse.c:
+	  update for adapter api changes
+
+2011-11-10 17:23:47 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmupay.c:
+	* gst/rtp/gstrtpsirenpay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	  update for changed base classes
+
+2011-11-10 13:50:34 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  fix for audio clock change
+
+2011-11-10 11:03:18 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/aalib/gstaasink.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/pulse/pulsesrc.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/ximage/gstximagesrc.c:
+	  update for removed fixate function
+
+2011-11-09 17:40:10 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-11-09 17:38:03 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	* ext/pulse/pulsesink.c:
+	  updates for new acceptcaps query
+
+2011-11-08 15:35:26 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix wrong stride when inverting uncompressed video
+	  Such frames have a stride multiple of 4, see
+	  http://lscube.org/pipermail/ffmpeg-issues/2010-April/010247.html.
+	  This showed up on a sample using a odd width of 24 bit video.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=652288
+
+2011-11-09 12:25:01 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph263ppay.c:
+	  h263ppay: report to 0.11
+
+2011-11-09 12:18:01 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/flac/gstflacdec.c
+	  gst/audioparsers/gstflacparse.c
+	  gst/isomp4/qtdemux.c
+
+2011-11-09 11:56:07 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  dtmf: fix compiler warning for uninitialized values
+
+2011-11-09 11:53:01 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/annodex/gstcmmldec.c:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/avi/gstavidemux.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/wavparse/gstwavparse.c:
+	  remove query types
+
+2011-11-09 10:32:06 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: minimal sanity check on creation datetime
+
+2011-11-04 17:54:04 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  dtmfsrc: Reject start/stop requests that come out of order
+
+2011-10-29 18:24:26 +0200  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  dtmf: Post messages when starting to send/receive DTMF
+	  This way, the UI can display the DTMF events as they as being sent.
+
+2011-11-02 12:58:12 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtph263ppay.c:
+	  rtph263ppay: Return the sink pad template as sink caps, not the src's
+	  https://bugzilla.gnome.org/show_bug.cgi?id=577784
+
+2009-03-15 19:26:48 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtph263ppay.c:
+	  rtph263ppay: Also implement size/framerate restrictions in getcaps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=577784
+
+2009-03-04 20:50:19 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtph263ppay.c:
+	  rtph263ppay: Implement getcaps following RFC 4629, picks the right annexes
+	  https://bugzilla.gnome.org/show_bug.cgi?id=577784
+
+2011-11-08 14:31:34 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: also set segment stop at startup rather than only post seek
+	  ... so as to ensure consistent playback with or without seek, especially
+	  in presence of some bogus edit list entries.
+
+2011-11-08 11:18:06 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	* gst/rtsp/gstrtspsrc.c:
+	  update for probe api changes
+
+2011-11-08 08:50:19 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/goom/gstgoom.c:
+	  goom: code cleanups
+	  Move variables to the scope where they are needed. Use our macros and functions
+	  more.
+
+2011-11-08 08:49:05 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* gst/goom/gstgoom.c:
+	  goom: add a sink_query to eat allocation queries
+	  We should not forward allocation queries for audio to the video sink.
+
+2011-11-02 17:02:54 +0000  Raul Gutierrez Segales <rgs@collabora.co.uk>
+
+	* gst/flv/Makefile.am:
+	  gst/flv/: add amfdefs.h to noinst_HEADERS
+	  https://bugzilla.gnome.org/show_bug.cgi?id=663334
+
+2011-11-07 17:14:17 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	* gst/rtsp/gstrtspsrc.c:
+	  fix for probe updates
+
+2011-10-03 17:50:43 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	  flvdemux: detect large pts gaps and resync
+	  Should work on multiple gaps, but tested on only one.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=631430
+
+2011-08-22 10:40:45 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: fix off by one between granpos and last_stop
+
+2011-10-07 19:41:35 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: fix last frame timestamp in fixed block size mode
+	  The last block may have a different block size, so we should not
+	  use it to scale or we'll end up with a wrong timestamp.
+	  See comment and quote from the FLAC format documentation in the code.
+	  Fixes looped playback of FLAC files (via about-to-finish).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=661215
+
+2011-10-27 15:52:47 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/cairo/gsttextoverlay.c:
+	* ext/cairo/gsttextoverlay.h:
+	  cairotextoverlay: add a 'silent' property to skip rendering
+	  https://bugzilla.gnome.org/show_bug.cgi?id=662856
+
+2011-11-07 12:00:12 +0100  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/matroska/ebml-write.c:
+	  matroskamux: fix regression causing malformed files
+	  This was caused by me in 1b213d. It seems I was too focused on 0.11 when I did
+	  this and tested the wrong branch.
+	  The problem was reported by Alexey Fisher.
+
+2011-11-04 18:41:36 +0100  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/annodex/gstcmmldec.h:
+	* gst/alpha/Makefile.am:
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalpha.h:
+	* gst/audiofx/Makefile.am:
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audiofirfilter.c:
+	* gst/audiofx/audiofx.c:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbaseiirfilter.c:
+	* gst/audiofx/audioiirfilter.c:
+	* gst/audiofx/audioinvert.c:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/audiofx/audiopanorama.c:
+	* gst/audiofx/audiowsincband.c:
+	* gst/audiofx/audiowsinclimit.c:
+	* gst/effectv/Makefile.am:
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstop.c:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstripple.c:
+	* gst/effectv/gstvertigo.c:
+	* gst/equalizer/Makefile.am:
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/equalizer/gstiirequalizer.h:
+	* gst/shapewipe/Makefile.am:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/smpte/Makefile.am:
+	* gst/smpte/gstsmptealpha.c:
+	* gst/videobox/Makefile.am:
+	* gst/videobox/gstvideobox.c:
+	* gst/videofilter/Makefile.am:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videofilter/plugin.c:
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer2.c:
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2src.c:
+	* tests/examples/shapewipe/shapewipe-example.c:
+	* tests/examples/v4l2/camctrl.c:
+	  controller: port to new controller location and api
+
+2011-11-04 17:39:15 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  more template fixes
+
+2011-11-04 16:21:13 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	  pulseaudiosink: more 0.11 fixing
+	  Make sure the caps event gets to the sink.
+
+2011-11-04 15:35:42 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	  pulseaudiosink: port some more
+	  Rename decodebin2 -> decodebin some more
+	  Cleanup up sinkpad event handling
+
+2011-11-04 13:56:06 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	  pulseaudiosink: port some more to 0.11
+	  We must not forward the caps event. instead we will decide what to do when the
+	  pad block is taken.
+	  Use decodebin instead of decodebin2
+
+2011-11-04 13:12:37 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/interleave/deinterleave.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartdemux.h:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  more template fixes
+
+2011-11-04 11:58:22 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	* gst/interleave/interleave.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/webm-mux.c:
+	* gst/multipart/multipartmux.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtsp/gstrtpdec.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/videomixer/videomixer.c:
+	* tests/check/elements/avimux.c:
+	* tests/check/elements/interleave.c:
+	* tests/check/elements/matroskamux.c:
+	* tests/check/elements/qtmux.c:
+	* tests/check/elements/rtpbin.c:
+	  make %u in all request pad templates
+
+2011-11-04 11:01:01 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  gst/rtp/gstrtpvrawdepay.c
+
+2011-11-04 10:32:46 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* configure.ac:
+	* gst/apetag/gstapedemux.c:
+	  Port apedemux
+
+2011-11-03 23:28:31 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  rtp: use GLib's G_BIG_ENDIAN define instead of BIG_ENDIAN
+	  Fixes compiler warning on mingw32
+
+2011-11-03 16:43:00 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* common:
+	* configure.ac:
+	* gst/rtpmanager/Makefile.am:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.h:
+	* gst/rtpmanager/rtpstats.h:
+	* gst/udp/Makefile.am:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstudp.c:
+	* gst/udp/gstudpsrc.c:
+	  update for new net library
+
+2011-11-02 12:09:20 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/annodex/gstcmmldec.c:
+	* ext/flac/gstflactag.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/speex/gstspeexdec.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/debugutils/gsttaginject.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/replaygain/gstrganalysis.c:
+	* gst/wavparse/gstwavparse.c:
+	  tags: update for tag API removal
+
+2011-11-02 10:40:12 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-10-31 02:40:08 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	  update for netbuffer api change
+
+2011-10-31 02:35:51 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstudp.c:
+	* gst/udp/gstudpsrc.c:
+	  update for netaddress change
+
+2011-10-31 02:24:04 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstwarp.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawdepay.h:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	  update for meta api change
+
+2011-10-29 09:29:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/gstqtmoovrecover.c:
+	* gst/rtsp/gstrtspsrc.c:
+	  update for new task api
+
+2011-10-29 09:09:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* sys/v4l2/gstv4l2object.c:
+	  structure: fix for api update
+
+2011-10-29 08:25:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	  bufferlist: update for new API
+
+2011-11-01 00:40:40 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	* gst/rtsp/gstrtspsrc.c:
+	  Update for pad API changes
+	  GstProbeType, GstProbeReturn and GstActivateMode -> GstPad*
+
+2011-10-31 18:38:55 +0100  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: fix obvious crash
+
+2011-10-31 16:18:32 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: avoid shortcut evaluation when adding paired mp4 tag
+	  Fixes (part of) #638711.
+
+2011-10-31 15:43:25 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: do not use unoffical V_MJPEG codec id
+	  ... but as not spec'ed especially, consider it a VfW compatibility case.
+	  Fixes #659837.
+
+2011-10-30 19:30:14 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacenc.h:
+	  flacenc: remove dead code from header
+	  We require a new-enough libflac that this condition will never apply.
+
+2011-10-30 19:09:03 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: parse stream headers from caps in set_format function
+	  Not that this seems to be actually needed, libflac happily decodes
+	  stuff even if we just drop all headers and never feed it to the
+	  library.
+
+2011-10-30 18:49:21 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacdec.h:
+	  flacdec: don't extract metadata, leave that to the parser or container
+
+2011-10-30 18:45:45 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacdec.h:
+	  flacdec: we expect framed input now, remove some more code
+
+2011-10-09 16:18:09 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacdec.h:
+	  flacdec: naive port to GstAudioDecoder
+	  This would probably have been too invasive to do in the 0.10
+	  branch, with all the pull-mode and parser handling code in
+	  there.
+
+2011-10-30 11:44:53 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/annodex/gstcmmldec.c:
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacenc.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavisubtitle.c:
+	* gst/debugutils/gsttaginject.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/replaygain/gstrganalysis.c:
+	* gst/wavparse/gstwavparse.c:
+	  ext, gst: update for taglist API changes
+
+2011-10-30 11:41:32 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	  tests: fix compilation of audio tests in uninstalled setup
+
+2011-10-28 21:26:33 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/audiofx/audiopanorama.c:
+	  audiopanorama: simplify get_unit_size
+
+2011-10-28 21:19:42 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* tests/check/elements/audioecho.c:
+	  tests: audioecho: port to 0.11
+
+2011-10-28 21:18:33 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/audiofx/audioecho.c:
+	  audioecho: fix internal buffer size calculation
+
+2011-10-28 14:05:48 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* tests/check/elements/audiochebband.c:
+	  tests: audiochebband: port to 0.11
+
+2011-10-28 16:52:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-10-28 15:08:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	  pulseaudiosink: fix porting errors
+	  The probes were ported wrongly and caused deadlocks.
+
+2011-10-28 09:57:36 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: add sof-marker to template caps, so we don't get plugged for lossless jpeg
+	  jpegdec (using libjpeg 6.2/8) can't decode some lossless types of JPEG.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=556648
+
+2011-10-28 13:06:20 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* tests/check/elements/audiocheblimit.c:
+	  tests: audiocheblimit: port to 0.11
+
+2011-10-28 13:02:56 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/audiofx/audiofxbaseiirfilter.c:
+	  audiofx: fix crash in process()
+
+2011-10-28 11:48:31 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* tests/check/elements/audioamplify.c:
+	  tests: audioamplify: port to 0.11
+
+2011-10-28 12:51:31 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	  pulse: fix check for empty caps
+
+2011-10-28 12:30:33 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: elaborate some debug statements
+
+2011-10-11 20:56:51 +0400  Stas Sergeev <stsp@users.sourceforge.net>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: be careful with negative cts
+	  Fixes #661477.
+
+2011-10-06 13:04:54 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: tune non-update seek handling cases
+	  Fixes #661049.
+
+2011-10-28 11:46:40 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  gst/videomixer/gstcollectpads2.c
+
+2011-10-28 11:16:38 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/audiofx/audiodynamic.c:
+	  audiodynamic: don't set process function too early
+	  GstAudioInfo and GstAudioFilter have been changed so that this code doesn't
+	  crash anymore when a property is set in NULL state.
+
+2011-10-28 10:42:04 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* tests/check/elements/audiodynamic.c:
+	  tests: audiodynamic: port to 0.11
+
+2011-10-28 00:24:14 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* tests/check/elements/spectrum.c:
+	  tests: spectrum: port to 0.11
+
+2011-10-27 23:57:17 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* tests/check/elements/audiopanorama.c:
+	  tests: audiopanorama: port to 0.11
+
+2011-10-27 23:56:12 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/audiofx/audiopanorama.c:
+	  audiopanorama: fix get_unit_size
+
+2011-10-28 10:40:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer2: Use the clip function instead of the prepare_buffer function
+
+2011-10-28 09:05:27 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* sys/v4l2/gstv4l2object.c:
+	  rtpmanager, v4l2: fix compiler warnings after gst_caps_new_simple() change
+
+2011-10-28 09:01:57 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fix compiler warnings after gst_caps_new_simple() change
+
+2011-10-28 09:36:17 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/gstcollectpads2.c:
+	* gst/videomixer/gstcollectpads2.h:
+	* gst/videomixer/videomixer2.h:
+	* gst/videomixer/videomixer2pad.h:
+	  videomixer2: Use collectpads2 from core
+
+2011-10-27 19:39:20 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/wavenc/Makefile.am:
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: port to 0.11 raw audio caps
+
+2011-10-27 19:06:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  gst/flv/gstflvmux.c
+
+2011-10-27 19:00:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/rtp/README:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	  make some more things compile again
+
+2011-10-27 16:08:22 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/pulse/pulseaudiosink.c
+	  ext/pulse/pulsesink.c
+
+2011-10-27 16:03:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	* sys/v4l2/gstv4l2object.c:
+	  fix compilation
+
+2011-10-28 00:41:45 +1100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Don't pointlessly hold object lock over caps operations
+	  Avoids a deadlock when getcaps is recursive due to the getcaps being
+	  reflected upstream/downstream. The lock isn't actually protecting
+	  anything here.
+
+2011-10-27 00:37:03 +1100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/flv/amfdefs.h:
+	* gst/flv/gstflvmux.c:
+	  flvmux: add some comments and defines to clarify code.
+
+2011-10-10 15:36:14 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/matroska/ebml-write.c:
+	  matroska: refactor ebml-write to be more 0.11 friendly
+	  Switching to a more 0.11-friendly pattern, where getting the buffer's data
+	  pointer and setting the size many times is less natural. This is of course in
+	  preparation to the upcoming port of the plugin.
+
+2011-10-11 21:45:46 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/matroska/ebml-write.c:
+	  matroska: remove stale floatcast include
+	  GDOUBLE_TO_BE was moved to core a long time ago.
+
+2011-10-11 22:10:27 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: fix possible crash with malformed dirac codec_data
+	  Since size is unsigned, we need to safeguard against wrapping below zero.
+
+2011-10-21 22:33:34 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/equalizer/gstiirequalizer.c:
+	  equalizer: remove avoidable call to gst_object_set_name
+
+2011-10-21 22:32:38 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: remove avoidable call to gst_object_set_name
+
+2011-10-21 14:51:23 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* ext/pulse/pulsemixerctrl.h:
+	* gst/videofilter/gstvideobalance.c:
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/oss/gstossmixer.h:
+	* sys/oss4/oss4-mixer.c:
+	* sys/oss4/oss4-source.c:
+	* sys/osxaudio/gstosxaudioelement.c:
+	* sys/sunaudio/gstsunaudiomixerctrl.h:
+	* sys/v4l2/gstv4l2colorbalance.h:
+	* sys/v4l2/gstv4l2radio.c:
+	* sys/v4l2/gstv4l2tuner.h:
+	* sys/v4l2/gstv4l2videooverlay.c:
+	* sys/v4l2/gstv4l2videooverlay.h:
+	* sys/v4l2/gstv4l2vidorient.c:
+	* sys/v4l2/gstv4l2vidorient.h:
+	  interfaces: clean up the use of iface and class/klass
+
+2011-10-21 11:37:05 +0100  Christian Fredrik Kalager Schaller <christian.schaller@collabora.co.uk>
+
+	* gst-plugins-good.spec.in:
+	  Update spec file so its paralel-installable and only tries to package ported plugins
+
+2011-10-16 20:30:25 +0200  René Stadler <mail@renestadler.de>
+
+	* ext/libpng/gstpngenc.c:
+	  pngenc: increase arbitrary resolution limits
+	  Apparently libpng can technically do up to 2^31-1 rows and columns. However it
+	  imposes an (arbitrary) default limit of 1 million (that could theoretically be
+	  lifted by using some additional API).
+	  Moved array allocation to the heap now.
+
+2011-10-16 20:25:41 +0200  René Stadler <mail@renestadler.de>
+
+	* ext/libpng/gstpngenc.c:
+	  pngenc: don't unconditionally allocate 4096 pointers on the stack
+	  Instead allocate as many as needed (on the stack still).
+
+2011-10-16 20:05:28 +0200  René Stadler <mail@renestadler.de>
+
+	* ext/libpng/gstpngenc.c:
+	  pngenc: ensure setcaps was called before chain function
+	  This is needed to properly error out for e.g. "fakesrc ! pngenc ! fakesink".
+
+2011-10-16 19:44:27 +0200  René Stadler <mail@renestadler.de>
+
+	* ext/libpng/gstpngenc.c:
+	  pngenc: validate input buffer size
+	  Just for safety; of course such mismatch represents a bug in another element.
+
+2011-10-16 19:41:28 +0200  René Stadler <mail@renestadler.de>
+
+	* ext/libpng/Makefile.am:
+	* ext/libpng/gstpngenc.c:
+	* ext/libpng/gstpngenc.h:
+	  pngenc: make setcaps more robust, use gstvideo functions
+	  A setcaps function needs to actually verify the caps carefully. In this case,
+	  it was possible to e.g. link a video decoder with YUV+RGB template caps to
+	  pngenc.  That would cause a crash when the decoder pushes a YUV buffer. Same
+	  thing when pushing a valid buffer that exceeds the resolution limits.
+	  Also, missing framerate caps field would cause a glib critical warning due to
+	  invalid GValue. This fails hard now.
+
+2011-10-21 10:01:43 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/matroska/matroska-read-common.c:
+	  ebml: small correction to previous commit
+	  Signal a short read with UNEXPECTED, exactly like the peek_bytes function.
+
+2011-10-19 13:09:51 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/matroska/matroska-read-common.c:
+	  ebml: Fix push-based behaviour
+	  The 'peek' method was completely wrong (!?)
+
+2011-10-18 18:31:17 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulseaudiosink.c:
+	  pulse: Get caps correctly on pad block
+	  Instead of always going upstream, we should first see if already got
+	  caps from a setcaps() call.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=661262
+
+2011-10-18 12:25:14 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackenc.c:
+	  wavpackenc: don't unref buffer with gst_object_unref()
+
+2011-10-18 12:05:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: only use is_pcm for 1.0 of pulseaudio
+
+2011-10-18 11:58:57 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: only disable trickmodes for !pcm
+	  Only disable trickmodes when we are not dealing with raw PCM samples.
+
+2011-10-16 15:32:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videocrop/gstvideocrop.c:
+	  videocrop: fix compilation
+
+2011-10-16 15:26:38 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  gst/rtp/gstrtpvrawdepay.c
+
+2011-10-14 10:56:16 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer2: Fix a leak
+	  Buffers weren't being unref'ed in one case inside, causing memory usage
+	  to blow up.
+
+2011-10-14 09:10:01 +0200  Marc Leeman <marc.leeman@gmail.com>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  set colour masks for video/x-raw-rgb in rtpvrawdepay
+
+2011-10-13 01:05:13 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* configure.ac:
+	  configure: re-enable videocrop plugin
+	  Already ported to 0.11
+
+2011-10-13 01:05:04 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videocrop/gstaspectratiocrop.h:
+	  aspectratiocrop: Port to 0.11
+
+2011-10-13 00:39:28 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/videocrop/Makefile.am:
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videocrop/gstvideocrop.h:
+	  videocrop: Port to 0.11
+
+2011-10-12 17:43:47 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* tests/check/elements/aspectratiocrop.c:
+	  tests: aspectratiocrop: Port to 0.11
+
+2011-10-12 08:24:28 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* tests/check/elements/alphacolor.c:
+	  tests: alphacolor: Port to 0.11
+
+2011-10-13 17:12:23 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: Properly register type
+	  It's a subclass of GstAudioEncoder and not of GstElement
+
+2011-10-13 16:59:50 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer2: Fix incorrect gst_buffer_replace() call
+	  This got exposed when gst_buffer_replace() was changed from a macro to a
+	  function.
+
+2011-10-13 09:34:04 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Fix wrong usage of gst_iterator_filter
+	  It takes a GValue* as the user_data.
+	  And don't forget to unref the demuxer before returning.
+
+2011-10-13 09:02:47 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  fix compile
+
+2011-10-13 08:58:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/jpeg/gstjpegdec.c
+	  gst/rtp/gstrtpvrawpay.c
+
+2011-10-12 08:09:20 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* tests/check/elements/cmmlenc.c:
+	  tests: cmmlenc: Port to 0.11
+
+2011-10-12 08:02:08 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* tests/check/elements/cmmldec.c:
+	  tests: cmmldec: Port to 0.11
+
+2011-10-12 07:29:30 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* ext/pulse/pulseaudiosink.c:
+	  pulseaudiosink: Use new GstIterator API correctly
+	  GstIterator now uses GValue, use it correctly.
+
+2011-10-12 11:26:50 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawpay.c:
+	  rtpvrawpay: Only use 24 LSB for depth=24 RGB caps
+	  ... and indent the masks for clarity
+
+2011-10-11 14:58:43 +0200  René Stadler <rene.stadler@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: fix segment handling, so we actually use running time
+	  gst_matroska_mux_best_pad adjusts the buffer timestamp to running time using
+	  the segment stored in the pad's collect data. However, the event handler didn't
+	  pass the newsegment event on to collectpads' handler, so this segment was never
+	  updated at all.
+	  Re-fixes bug #432612.
+
+2011-10-10 19:01:23 +0100  Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+
+	* gst/rtp/gstrtpg722pay.c:
+	  gstrtpg722pay: Compensate for clockrate vs. samplerate difference
+	  The RTP clock-rate used for G722 is 8000, even though the samplerate is
+	  16000. Compensate for this by pretending G722 has 8 bits per sample
+	  instead of the 4 bits as if it were a codec that ran at half the speed,
+	  but with twice the number of bits. Fixes #661376
+
+2011-09-27 19:25:53 +0100  Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Implement upstream negotiation
+	  Add upstream negotiation for jpegdec. Fixes #660275
+
+2011-10-10 19:02:58 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: don't leak audio codec_data buffer
+
+2011-10-10 17:41:10 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	  alpha: Don't use start() vmethod
+	  The only thing we're doing is initializing parameters ...
+	  * which won't work because we don't have upstream/downstream caps
+	  * which will be initialized when ::set_caps() is called
+
+2011-10-10 14:08:29 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-10-10 13:22:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* gst/id3demux/gstid3demux.c:
+	  id3demux: port to 0.11
+
+2011-10-10 13:20:04 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* tests/examples/cairo/Makefile.am:
+	  tests: add missing PLUGIN_ASE_LIBS to LDADD
+
+2011-10-10 12:54:22 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* gst/icydemux/gsticydemux.c:
+	  icydemux: port to 0.11
+
+2011-10-10 12:27:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* ext/annodex/gstcmmldec.c:
+	* ext/annodex/gstcmmlenc.c:
+	  annodex: port to 0.11
+
+2011-10-10 11:48:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/speex/gstspeexenc.c
+
+2011-10-10 00:18:56 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* ext/pulse/pulseutil.c:
+	* ext/pulse/pulseutil.h:
+	  pulse: port pulseutil to 0.11
+
+2011-10-09 21:17:24 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* ext/pulse/pulseaudiosink.c:
+	  pulseaudiosink: port to 0.11
+
+2011-10-09 18:58:29 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Fixing getcaps function
+	  Update getcaps function to 0.11 API
+
+2011-10-09 21:31:27 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/speex/gstspeexenc.c:
+	* ext/speex/gstspeexenc.h:
+	  speexenc: only push header buffers following initial events
+
+2011-10-09 16:29:05 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  Merge remote-tracking branch 'origin/master' into 0.11
+
+2011-10-09 16:24:36 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/isomp4/qtdemux_dump.c:
+	  qtdemux: update for __gst_debug_min name change
+
+2011-10-09 11:18:18 -0300  Thiago Santos <thiago.sousa.santos@collabora.com>
+
+	* gst/isomp4/atomsrecovery.c:
+	  qtmux: Fix memory leak on atoms recovery function
+	  Remember to free the ftyp data after writing it to a file.
+	  Fixes #660969
+
+2011-10-06 12:26:33 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: report new bits
+
+2011-10-06 12:23:39 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/speex/gstspeexdec.c
+	  ext/speex/gstspeexenc.c
+	  gst/isomp4/atoms.c
+	  gst/isomp4/gstqtmux.c
+
+2011-09-21 18:45:42 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: improve segment handling with non-zero starting timestamp
+	  ... as well as related items, such as seeking and position reporting.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=659808
+
+2011-09-29 18:41:53 +0400  Stas Sergeev <stsp@users.sourceforge.net>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/ximage/gstximagesrc.c:
+	  v4l2, ximagesrc: fix some printf format compiler warnings
+	  https://bugzilla.gnome.org/show_bug.cgi?id=660150
+
+2011-09-30 12:42:22 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* tests/check/elements/qtmux.c:
+	  tests: qtmux: Refactor bitrate check test
+	  Refactor bitrate check test to accomodate multiple tests
+	  for bitrate
+
+2011-09-30 13:02:31 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/isomp4/atoms.c:
+	  qtmux: update esds atom under wave atom for aac bitrates
+	  AAC in mov format puts an ESDS atom inside of a WAVE atom in
+	  STSD atom, we need to update the bitrate on this ESDS. This patch
+	  fixes it.
+
+2011-09-30 12:41:52 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/fourcc.h:
+	  qtmux: Also update btrt atom
+	  When rewriting bitrates, also update the btrt atom under stsd
+
+2011-09-30 10:55:53 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* tests/check/elements/qtmux.c:
+	  tests: qtmux: add tests for bitrate average calculation
+	  Adds tests to make sure qtmux/mp4mux sets average bitrate
+	  correctly
+
+2011-09-28 11:41:49 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	  qtmux: Calculate average bitrate for streams
+	  Calculate and use average bitrate for streams when no
+	  bitrate tag was received
+
+2011-09-28 10:41:14 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Avoid a buffer metadata copy if possible
+	  If first_ts is 0 there is no need to subtract, so we might
+	  skip some copying to make the buffer metadata writable.
+
+2011-09-29 23:21:46 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/speex/gstspeexenc.c:
+	  speexenc: initialise variable before adding to it
+
+2011-09-29 17:21:22 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexdec.h:
+	  speexdec: port to audiodecoder
+
+2011-09-29 16:33:01 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/speex/gstspeexenc.h:
+	  speexenc: clean up some unused remnants
+
+2011-09-29 17:32:23 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/speex/Makefile.am:
+	* ext/speex/gstspeexenc.c:
+	* ext/speex/gstspeexenc.h:
+	  speexenc: port to audioencoder
+
+2011-09-28 19:10:27 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: get rid of granulepos handling
+	  Leave that to the parser or demuxer. There's still some
+	  code for operating in DEFAULT (samples) format, but that
+	  will be removed later.
+
+2011-09-28 18:32:00 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacdec.h:
+	  flacdec: get rid of pull-mode support and focus on being a decoder
+	  Leave all the other stuff to flacparse.
+
+2011-09-28 17:29:08 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflactag.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	  flac, jpeg: fix compiler warning
+
+2011-09-28 17:40:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflactag.c:
+	  flac: port to 0.11
+
+2011-09-28 17:39:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/flac/gstflacenc.c
+
+2011-09-28 16:18:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-09-28 16:09:58 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/Makefile.am:
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflacenc.h:
+	  flacenc: port to audioencoder
+
+2011-09-27 15:59:24 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-parse.c:
+	  matroskademux: ensure minimal alignment for audio/x-raw-* buffers
+	  Since matroskademux will attempt to push unaligned buffers,
+	  downstream might have trouble with those, especially if downstream
+	  uses ORC, such as audioconvert.
+	  Ensure we push buffers aligned to the basic type at least for
+	  those raw buffers.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=659798
+
+2011-09-28 12:44:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  common
+	  ext/pulse/pulsesink.c
+	  ext/soup/gstsouphttpclientsink.c
+	  gst/audioparsers/gstaacparse.c
+	  gst/audioparsers/gstac3parse.c
+	  gst/rtp/gstrtph264depay.c
+	  gst/rtpmanager/gstrtpjitterbuffer.c
+	  gst/rtpmanager/rtpjitterbuffer.c
+	  gst/rtsp/gstrtspsrc.c
+	  sys/ximage/gstximagesrc.c
+
+2011-09-28 00:10:09 +0300  Raimo Järvi <raimo.jarvi@gmail.com>
+
+	* gst/goom2k1/goom_core.c:
+	  goom2k1: Fix compiler warnings on 64 bit mingw-w64
+	  Fixes bug #660294.
+
+2011-09-25 15:13:39 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/Makefile.am:
+	* ext/soup/gstsoup.c:
+	* ext/soup/gstsouphttpclientsink.c:
+	* ext/soup/gstsouphttpclientsink.h:
+	  soup: rename souphttpsink to souphttpclientsink
+	  To avoid confusion, and because we might want a server
+	  sink at some point too.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=659947
+
+2011-09-23 16:39:46 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsink.c:
+	* ext/soup/gstsouphttpsink.h:
+	  souphttpsink: don't create unused second sink pad object
+	  The base class will create the sink pad.
+
+2011-09-23 15:36:36 +0200  Julien Isorce <julien.isorce@gmail.com>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: correctly check for ac3/e-ac3 switch
+	  https://bugzilla.gnome.org/show_bug.cgi?id=659943
+
+2011-09-21 14:01:20 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* common:
+	  Update common to 0.11 branch
+
+2011-09-20 13:38:53 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: improve downstream flow return feedback to upstream
+	  ... although basertpdepay does not really make it easy/possible to do so
+	  all the way.
+
+2011-09-20 12:11:47 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/ximage/gstximagesrc.c:
+	* sys/ximage/gstximagesrc.h:
+	  ximagesrc: add xid and xname properties to allow capturing a particular window
+	  A particular window may be selected using the new xid (X-Window
+	  XID, eg a pointer) and xname (window title) properties. If both
+	  are specified, the XID is used in preference, falling back to
+	  xname if not found.
+	  Default (if none of xid and xname are specified, or if no such
+	  window is found) is to capture the root window.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=546932
+
+2011-08-02 17:39:44 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/qtmux.c:
+	  tests: add unit test to make sure encodebin picks mp4mux for variant=iso
+	  https://bugzilla.gnome.org/show_bug.cgi?id=651496
+
+2011-09-19 12:15:11 +0200  Ha Nguyen <hanguytv@gmail.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Fix a leaked clock for each buffering message
+	  Fixes bug #659237.
+
+2011-09-19 12:11:32 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux_fourcc.h:
+	  qtdemux: parse embedded ID32 tags
+
+2011-09-02 13:41:41 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsession: avoid source premature timing out
+	  Use slightly adjusted sender interval to determine sender timeout rather than
+	  our own sender side interval (which may have been forced small).
+
+2011-08-25 12:40:52 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: avoid timing out source too quickly
+	  ... following a PAUSE/PLAY cycle, particularly applicable when operating
+	  with a short RTCP interval (possibly forced so server-side).
+
+2011-08-24 14:37:52 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer/rtpbin: relax dropping rtcp packets
+	  ... to at least having it trigger a/v synchronization, possibly without
+	  using provided values which are still not considered sane
+	  (as previously dropped).
+
+2011-08-24 14:34:23 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: some more reset when clearing pt map
+	  ... which in particular caters for some more reset following a possible
+	  rtsp PLAY.
+
+2011-08-21 21:58:38 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: do not set elements to PLAYING when doing seek in PAUSED
+
+2011-09-01 14:47:48 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: only reset skew on gap if input ts available
+
+2011-08-18 14:12:21 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: check some more for possible rtp timestamp discontinuity
+	  ... when operating in non slave mode, and reset if detected.
+	  This should avoid some (large) bogus outgoing timestamp due to jumps
+	  in rtp time, as result of PAUSE/PLAY or seek or ...
+
+2011-08-08 12:48:50 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: switch to rtp time based syncing when guessed appropriate
+
+2011-08-08 12:15:20 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: alternative inter-stream syncing methods
+	  ... at least if not syncing to NPT time:
+	  * either sync using RTCP SR data (as currently)
+	  * only perform the above once using initial RTCP SR packets
+	  * discard RTCP and sync by equating provided stream's clock-base rtptime,
+	  as provided by jitterbuffer (typically obtained from RTP-Info in RTSP).
+
+2011-08-08 12:11:24 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: also provide clock-base to sync signal
+
+2011-08-08 12:09:41 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: allow configurable rtcp stream syncing interval
+	  ... rather than necessarily syncing at each RTCP SR.
+
+2011-08-01 08:35:01 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: trigger reconsideration if rtcp interval set
+
+2011-08-01 08:32:24 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: configure rtcp interval if provided
+	  ... in PLAY response.
+
+2011-09-16 16:53:22 +0300  Lasse Laukkanen <lasse.laukkanen@digia.com>
+
+	* gst/isomp4/gstqtmux.c:
+	  isomp4: Fix allowing zero duration tracks
+	  https://bugzilla.gnome.org/show_bug.cgi?id=637486
+
+2011-09-05 10:11:18 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/udp/gstudpnetutils.c:
+	  udpsrc: error out when no protocol is specified in the uri
+	  It is certainly better than to crash.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=658178
+
+2011-09-19 09:37:58 +0200  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/speex/gstspeexenc.c:
+	  speexenc: do not use invalid buffer timestamps
+
+2011-03-29 12:09:18 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/Makefile.am:
+	* ext/pulse/plugin.c:
+	* ext/pulse/pulseaudiosink.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	* ext/pulse/pulseutil.h:
+	  pulse: New pulseaudiosink element to handle format changes
+	  This introduces a new bin which wraps around pulsesink and depending on
+	  the formats supported by the sink, plugs in/out a decodebin2 as
+	  required. This allows users to switch sinks on the stream and adapts
+	  accordingly (for example, you could watch a movie in passthrough mode on
+	  your receiver which supports AC3 decode, then plug out and switch to a
+	  non-digital profile to continue uninterrupted on analog output).
+	  The bin is required because doing the same with playbin2/playsink will
+	  require API changes that cannot be made in 0.10. With 0.11/1.0, we
+	  should be able to ask for upstream caps renegotiation to deal with all
+	  this.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=657179
+
+2011-09-16 15:03:23 +0200  Branko Subasic <branko@axis.com>
+
+	* gst/matroska/ebml-read.c:
+	* gst/matroska/ebml-read.h:
+	* gst/matroska/matroska-read-common.c:
+	  matroskademux: Avoid sending EOS when in paused state
+	  Changed the ebml reader's gst_ebml_peek_id_length() function so
+	  that it returns the actual reason for why the peek failed, instead
+	  of (almost) always returning GST_FLOW_UNEXPECTED. This prevents
+	  the pulling task from sending EOS when doing a flushing seek.
+
+2011-09-15 15:53:47 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: fix stuttering A/V
+	  Someone got had by implicit promotion to unsigned in ops with
+	  a signed and an unsigned value.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=659153
+
+2011-09-14 16:37:12 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/debugutils/gstnavseek.c:
+	  navseek: toggle pause/play on space bar
+	  A useful thing to have.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=659065
+
+2011-09-14 14:46:00 +0200  David Svensson Fors <davidsf@axis.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: configurable timestamp gap handling
+	  matroskademux performs segment tricks to skip gaps in streams,
+	  notably at start for non 0 based files.  There may however be
+	  cases when full presentation (including intermediate gaps) is
+	  desired, so a property allows to configure as of which gap
+	  to act (or not at all).
+	  API: GstMatroskaDemux::max-gap-time
+	  Fixes #659009.
+
+2011-09-12 09:21:47 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* tests/check/elements/flvmux.c:
+	  tests: flvmux: Fix flvmux's tests after fix for request pads handling
+	  Now that flvmux doesn't release its request pads on PAUSED->READY the
+	  test doesn't need to re-request them for every reuse test start.
+
+2011-09-09 09:12:56 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Fix ctts generation for streams that don't start at 0 timestamps
+	  Subtract the first timestamp of a stream from all input buffers to
+	  get 0-based timestamps for creating a sane ctts table. Without this
+	  patch the ctts could have larger values than needed, causing the
+	  playback to have a delay at startup.
+	  As the first timestamp is only found after a few buffers are queued
+	  (due to possible reordered buffers), once we find the first timestamp
+	  we subtract it from all buffers on the queue, from that point on,
+	  all buffers have their timestamps subtract when they are collected.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=658659
+
+2011-09-12 07:55:19 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: don't release request pads going PAUSED->READY
+	  Don't release request pads but just reset them. This makes pipelines using
+	  flvmux reusable.
+
+2011-09-09 12:35:50 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: use bsid 9 and 10 to control sample rate
+	  See http://matroska.org/technical/specs/codecid/index.html
+	  The spec is silent about this though...
+	  https://bugzilla.gnome.org/show_bug.cgi?id=658546
+
+2011-09-07 14:13:03 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: ensure some initial state variable setup
+	  ... which might otherwise be skipped if the PLAY command is issued before
+	  the OPEN command had a chance to actually be acted upon.
+	  Fixes #657376.
+
+2011-09-08 15:02:05 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: tweak gap handling
+	  ... so as to avoid buffers before and after gap to have identical running time.
+
+2011-09-08 13:28:24 +0200  Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: use GST_RESOURCE_ERROR_BUSY if v4l2_ioctl fails with EBUSY
+	  https://bugzilla.gnome.org/show_bug.cgi?id=658543
+
+2011-09-07 08:54:17 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: remove one G_UNLIKELY for user property
+	  Using G_UNLIKELY on user properties isn't nice, specially when
+	  that is the default option.
+
+2011-03-15 11:03:53 +0100  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: handle GstForceKeyUnit event
+	  ... by starting a new cluster after forwarding event.
+	  Fixes #644154.
+
+2011-09-07 14:27:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/cmmldec.c:
+	* tests/check/elements/cmmlenc.c:
+	  cmml: Use complete cmml caps in the unit test
+
+2011-09-07 14:26:01 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/qtmux.c:
+	  qtmux: Use complete MPEG caps in the unit test
+
+2011-09-07 14:18:58 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* docs/plugins/Makefile.am:
+	  docs: cleanup makefiles
+	  Remove commented out parts that we don't need. Remove "the wingo addition" - no
+	  so useful after all. Narrow down file-globs for plugin docs.
+
+2011-08-29 14:12:22 +0200  Konstantin Miller <konstantin.miller@gmail.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Don't handle HTTP response 407 as error if proxy authentication data is available
+	  Fixes bug #657422.
+
+2011-09-07 12:11:39 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: Add Converter to the classification because it can convert between different alignments
+	  This allows decodebin2 to let it negotiate properly.
+
+2011-09-07 12:10:48 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  audioparsers: Improve src template caps
+	  Remove the parsed/framed fields and add all fields to the template
+	  caps that always exist.
+
+2011-09-06 15:59:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstaacparse.h:
+	  aacparse: parse codec_data to determine number of samples per frame
+	  Fixes #656734.
+
+2011-09-06 21:24:46 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From a39eb83 to 11f0cd5
+
+2011-09-06 16:57:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	  configure: try to disable deinterlace..
+
+2011-09-06 15:40:32 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 605cd9a to a39eb83
+
+2011-09-06 16:37:03 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  common
+
+2011-09-06 16:06:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  gst/audioparsers/gstamrparse.c
+	  gst/isomp4/qtdemux.c
+
+2011-09-06 15:40:32 +0200  Stefan Sauer <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 605cd9a to a39eb83
+
+2011-09-06 15:05:37 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: make default duration check less sensitive
+	  Frame duration might vary for 1 usecond, in this case matroskamux
+	  decides to create BLOCKGROUP instead of SIMPLEBLOCK.
+	  Convert duration to timecodescale which is (typically) less precise, and
+	  then also allow the difference of 1/-1 to arrange for less sensitive check.
+	  Based on patch by Alexey Fisher <bug-track@fisher-privat.net>
+	  Fixes #653080.
+
+2011-09-06 13:18:40 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4gdepay.c:
+	  rtpmp4gdepay: improve bogus interleaved index compensating
+	  Patch by <gudake@gmail.com>
+	  Fixes #654585.
+
+2011-09-06 13:16:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jack/gstjack.h:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulseutil.c:
+	* gst/audiofx/audiopanorama.c:
+	* gst/audiofx/audiopanorama.h:
+	* gst/auparse/gstauparse.c:
+	* gst/avi/gstavimux.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/law/alaw.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw.c:
+	* gst/spectrum/gstspectrum.c:
+	* gst/wavparse/gstwavparse.c:
+	  -good: port to new audio caps
+
+2011-09-06 10:33:21 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Allow positive, non-1.0 segment rates
+	  Only negative rates are not supported. Fixes bug #658305.
+
+2011-09-05 15:50:56 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/parser.c:
+	  tests: parsers: provide more real data when testing draining of garbage
+
+2011-09-05 15:50:04 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstamrparse.c:
+	  amrparse: fix and streamline valid frame checking
+	  ... to handle various combinations of sync or not, and sufficient data
+	  or not as might be expected.
+	  Fixes #650714.
+
+2011-09-05 14:49:32 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fragmented support; avoid adjustment for keyframe seek
+	  ... since all index data may not yet be available at that time.
+
+2011-09-05 14:48:02 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fragmented support; mark all audio track samples as keyframe
+
+2011-09-05 14:46:29 +0200  Brian Li <brian7003@gmail.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: fragmented support; properly init return variable value
+	  Fixes #655918.
+
+2011-09-05 13:31:20 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: add gtk-doc for new short-header property
+
+2011-09-05 13:18:39 +0200  Marc Leeman <marc.leeman@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: allow sending short RTSP requests to a server
+	  Some encoders (Arecont) do not like the long OPTIONS sent at startup as sent by
+	  GStreamer, but do accept the short header as sent by Live555.
+	  This patch makes the extending the request optional by adding a property
+	  (short-header).
+	  Fixes #655805.
+	  API: GstRTSPSrc:short-header
+
+2009-03-04 14:51:09 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtph263ppay.c:
+	  rtph263ppay: Set H263-2000 if thats what the other side wants
+	  The static caps states this element supports H263-2000, but setcaps never
+	  sets it, so it was lie.
+	  See https://bugzilla.gnome.org/show_bug.cgi?id=577784
+
+2011-08-30 19:02:51 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Initialise the last_keyframe_request variable
+
+2011-08-31 16:04:24 +0200  Peter Korsgaard <jacmet@sunsite.dk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: make add/remove/clear/get-stats action signals
+	  http://bugzilla.gnome.org/show_bug.cgi?id=657830
+	  Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
+
+2011-08-31 18:45:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	  mp2t: fix encoding name according to RFC3551
+
+2011-08-30 13:33:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: push mode; perform some extra checks prior to upstream seeking
+
+2011-08-30 13:28:21 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: push mode; fix buffered streaming
+	  That is, in case where no seek is peformed to moov, but preceding
+	  limited mdat is buffered.
+
+2011-08-30 14:06:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/shapewipe/gstshapewipe.h:
+	  shapewipe: port to 0.11
+
+2011-08-30 12:49:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	  law is ported now
+
+2011-08-30 12:25:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/law/alaw.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/law/mulaw.c:
+	  law: port to 0.11
+
+2011-08-29 19:11:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-encode.c:
+	  alaw: port to 0.11
+
+2011-08-29 19:10:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/goom/gstgoom.c:
+	  goom: fix comment
+
+2011-08-29 18:02:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* ext/soup/gstsouphttpsink.c:
+	* ext/soup/gstsouphttpsrc.c:
+	  soup: port soup elements to 0.11
+
+2011-08-29 15:13:56 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: avoid overflow wraparound in timestamp when adding durations
+	  Do some type juggling to avoid overflow, while still allowing for 'negative'
+	  durations (which would need a wraparound effect).
+
+2011-08-29 13:43:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  sys/v4l2/v4l2src_calls.c
+
+2011-08-26 14:20:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstwarp.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	  allocation: fix for vmethod changes
+
+2011-08-25 23:37:47 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2src: make this work more than once in a row
+	  We used to skip frame rate setup if the camera was already setup
+	  with the requested frame rate. This breaks some cameras though,
+	  causing them to not output data (several models of Thinkpad cameras
+	  have this problem at least).
+	  So, don't skip.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=638300
+
+2011-08-25 16:41:23 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/y4m/gsty4mencode.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  port to new video flags
+
+2011-08-24 18:40:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulseutil.c:
+	  pulse: add some more channels
+
+2011-07-12 21:48:37 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  dtmf: Add more debug
+
+2011-07-12 19:09:02 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstdtmfcommon.h:
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  dtmf: Max event type is 15
+
+2011-04-14 15:46:08 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	  dtmfsrc: Align DTMF sound buffers with last-stop from event
+	  Also make sure the timestamps never go backwards
+
+2011-07-11 21:31:07 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  rtpdtmfsrc: Correctly recognize the end of a buffer
+
+2011-07-11 20:47:23 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  rtpdtmfsrc: Make sure rtpdtmfsrc timestamps don't overlap
+
+2011-07-11 20:46:20 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  rtpdtmfsrc: Put the inter digit interval at the end, not at the start
+	  The reason is to let rtpdtmfmux drop buffers during the inter digit interval,
+	  this way, there will be more silence around the DTMF tones so IVFs will have
+	  a better chance recognizing them.
+
+2011-04-14 17:08:57 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  rtpdtmfsrc: Start at the last_stop from the start event if there was one
+	  The goal is to try to not have a GAP between the audio and the DTMF
+
+2011-04-14 16:49:39 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  rtpdtmfsrc: Respect ptime from the caps
+	  Respect the ptime from the caps for the DTMF packets
+
+2011-07-11 21:30:28 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  rtpdtmfsrc: Just error out if there is no clock
+
+2011-08-24 14:16:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-08-23 12:12:15 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: only require two frames in a row when we do not have sync
+	  This avoids a single bit error dropping two frames unnecessarily.
+	  The two consecutive frames check is still required when we don't
+	  have sync.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=657080
+
+2011-08-23 21:41:15 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Trivial indentation fix
+
+2011-08-23 19:09:31 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalphacolor.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	  video: port to new colorimetry info
+
+2011-07-21 17:23:28 -0400  Monty Montgomery <cmontgom@redhat.com>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: Correct sample number rounding resulting in timestamp jitter
+	  flacdec converts the src timestamp to a sample number, uses that internally, then reconverts the sample number to a timestamp for the output buffer.  Unfortunately, sample numbers can't be represented in an integer number of nanoseconds, and the conversion process was truncating rather than rounding, resulting in sample numbers and output timestamps that were often off by a full sample.
+	  This corrects the time->sample convesion
+
+2011-08-22 13:10:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-08-22 12:24:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/rtp/gstrtpj2kdepay.c:
+	  fourcc: remove fourcc from caps
+
+2011-08-20 14:48:20 -0700  David Schleef <ds@schleef.org>
+
+	* gst/debugutils/breakmydata.c:
+	  breakmydata: element is not passthrough
+
+2011-07-13 11:20:34 -0700  David Schleef <ds@schleef.org>
+
+	* gst/multifile/gstmultifilesrc.c:
+	  multifilesrc: quiet debugging
+
+2011-07-10 21:40:20 -0700  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	* gst/deinterlace/gstdeinterlacemethod.h:
+	* gst/deinterlace/tvtime/greedy.c:
+	* gst/deinterlace/tvtime/greedyh.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/scalerbob.c:
+	* gst/deinterlace/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	* gst/deinterlace/tvtime/vfir.c:
+	* gst/deinterlace/tvtime/weave.c:
+	* gst/deinterlace/tvtime/weavebff.c:
+	* gst/deinterlace/tvtime/weavetff.c:
+	  deinterlace: change field handling through methods
+	  This likely breaks stuff.  The good: all of the methods now create
+	  field images aligned with input frames, without timestamp mangling.
+	  The bad: this touches a lot of code, much of which is hairy and in
+	  need of cleanup.  However, at this point we can reasonably create a
+	  PSNR-based test.
+
+2011-08-21 14:41:14 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: reset ->streamheaders to NULL on _stop
+	  Fixes invalid memory access reusing multifilesink
+
+2011-08-20 10:46:18 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/cutter/gstcutter.c:
+	* gst/cutter/gstcutter.h:
+	  cutter: bring cutter somewhat into this millennium
+
+2011-08-19 16:27:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/replaygain/gstrganalysis.c:
+	  rg: fix caps
+
+2011-08-19 16:13:23 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: port after merge
+
+2011-08-19 16:12:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-08-19 16:09:48 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audiofirfilter.c:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbaseiirfilter.c:
+	* gst/audiofx/audioiirfilter.c:
+	* gst/audiofx/audioinvert.c:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/audiofx/audiowsincband.c:
+	* gst/audiofx/audiowsinclimit.c:
+	* gst/auparse/Makefile.am:
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/goom/gstgoom.c:
+	* gst/level/Makefile.am:
+	* gst/replaygain/Makefile.am:
+	* gst/replaygain/gstrganalysis.c:
+	* gst/replaygain/gstrglimiter.c:
+	* gst/replaygain/gstrgvolume.c:
+	* gst/spectrum/gstspectrum.c:
+	  port to more audio api changes
+
+2011-08-19 14:01:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	* gst/auparse/gstauparse.c:
+	* gst/auparse/gstauparse.h:
+	* gst/cutter/gstcutter.c:
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/level/gstlevel.c:
+	* gst/level/gstlevel.h:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/spectrum/gstspectrum.c:
+	* sys/oss/gstosshelper.c:
+	* sys/oss/gstosssink.c:
+	* sys/oss/gstosssrc.c:
+	* tests/check/elements/audioinvert.c:
+	* tests/check/elements/level.c:
+	* tests/check/elements/rtp-payloading.c:
+	* tests/check/elements/rtpjitterbuffer.c:
+	* tests/examples/level/level-example.c:
+	* tests/examples/spectrum/spectrum-example.c:
+	  port more elements to new audio caps and API
+
+2011-08-19 11:49:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audioamplify.h:
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audiofirfilter.c:
+	* gst/audiofx/audiofirfilter.h:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbaseiirfilter.c:
+	* gst/audiofx/audioiirfilter.c:
+	* gst/audiofx/audioiirfilter.h:
+	* gst/audiofx/audioinvert.c:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/audiofx/audiokaraoke.h:
+	* gst/audiofx/audiowsincband.c:
+	* gst/audiofx/audiowsincband.h:
+	* gst/audiofx/audiowsinclimit.c:
+	  port to new audio API and caps
+
+2011-08-18 13:37:39 +0200  David Henningsson <david.henningsson@canonical.com>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Allow writes in bigger chunks
+	  There's no use in splitting the incoming data down to the segsize
+	  limit - by writing as much as possible in one chunk, we increase
+	  performance and avoid PulseAudio unnecessary rewinds.
+	  Signed-off-by: David Henningsson <david.henningsson@canonical.com>
+
+2011-08-18 19:37:39 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-08-18 19:21:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jack/gstjack.h:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulseutil.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	  port to new audio caps.
+
+2011-08-08 22:14:28 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: ensure no-more-pads is always emitted
+	  In particular, do so even if failing to read while prerolling,
+	  such as when reading from a partial file (eg, while it is being
+	  downloaded).
+	  This fixes a wedge in playbin2.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=651965
+
+2011-08-17 17:57:11 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: improve fixate function
+	  Use new core function to fixate a field.
+	  Chain up to parent fixate function.
+
+2011-08-17 15:52:18 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/flac/gstflacdec.c
+
+2011-08-17 15:39:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* ext/jpeg/Makefile.am:
+	* ext/jpeg/gstjpeg.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstjpegenc.h:
+	  jpeg: port to 0.11
+	  Also disable smoke for now.
+
+2011-08-16 17:27:13 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: avoid timestamp/offset tracking going out of sync
+	  The libFLAC API is callback based, and we must only call it to
+	  output data when we know we have enough input data. For this
+	  reason, a single processing step is done when receiving a buffer.
+	  However, if there were metadata buffers still pending, a step
+	  intended for the first audio frame might end up writing that
+	  leftover metadata. Since a single step is done per buffer, this
+	  will cause every buffer to be written one step late.
+	  This would add some latency (a bufferfull's worth), possibly
+	  lose a buffer when seeking or the like, and also cause timestamp
+	  and offset to be applied to the wrong buffer, as updates to
+	  the "current" segment last_stop (from incoming buffer timestamp)
+	  will be applied to an output buffer originating from the previous
+	  incoming buffer.
+	  This fixes the issue by ensuring that, upon receiving the first
+	  audio frame, processing is done till all metadata is processed,
+	  so the next "single step" done will be for the audio frame. After
+	  this, we should keep to 1 input buffer -> 1 output buffer and so
+	  avoid getting out of sync.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650960
+
+2011-08-17 11:17:38 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-08-16 15:32:07 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: bail on reserved value
+	  Now that we look at the right bits, we can test against the reserved
+	  value as we do for other fields.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650960
+
+2011-08-16 15:27:43 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: fix bit twiddling
+	  Right shifting a 8 bit value by 8 bits is twice too much
+	  to get the high 4 bits.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650960
+
+2011-08-16 15:22:46 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: warn if we see a variable block size where unsupported
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650960
+
+2011-08-16 18:25:29 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: avoid crashing by resetting the correct number of channels
+	  https://bugzilla.gnome.org/show_bug.cgi?id=656606
+
+2011-08-16 18:35:53 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  sys/v4l2/v4l2src_calls.c
+
+2011-08-16 13:16:22 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: fix off by one in frame size check
+	  Yes, I was tracking another bug and the small test file I generated
+	  to test with improbably just happened to trigger this, with a second
+	  and last frame of 1615 bytes.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=656649
+
+2011-08-15 12:19:14 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/parser.c:
+	  tests: update for _negotiated_caps() change
+
+2011-08-14 20:46:01 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/id3demux/id3v2.3.0.html:
+	* gst/id3demux/id3v2.4.0-frames.txt:
+	* gst/id3demux/id3v2.4.0-structure.txt:
+	  id3demux: remove specs from git as well now that parsing code is in -base
+
+2011-07-14 15:42:36 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	* gst/id3demux/Makefile.am:
+	* gst/id3demux/gstid3demux.c:
+	* gst/id3demux/id3tags.c:
+	* gst/id3demux/id3tags.h:
+	* gst/id3demux/id3v2frames.c:
+	  id3demux: use -base provided id3 tag parsing
+	  https://bugzilla.gnome.org/show_bug.cgi?id=654388
+
+2011-08-13 16:51:22 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jack/gstjackaudiosrc.c:
+	  jackaudiosrc: fix error message code
+	  And also post 'not found' error if jackd is not even installed.
+
+2011-08-12 16:32:58 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: initialize bitrate variable and reset for each loop
+	  Don't check eventually unset variable and don't accidentially use values from last
+	  cycle.
+
+2011-08-10 11:28:26 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/aalib/gstaasink.c:
+	  aasink: Remove unused variables
+
+2011-08-09 11:28:17 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Properly error out if SDP contains no streams
+	  Also fixes unitialized variable error on macosx.
+
+2011-08-09 09:05:31 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximagesrc: clear flags on buffer reuse
+	  This will ensure a logically new buffer does not keep flags from
+	  a previous use of that buffer (eg, DISCONT would be set on the first
+	  buffer, and mistakenly kept when reused).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=653709
+
+2011-08-08 10:54:26 +0100  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: take care not to change the current format where appropriate
+	  Some drivers are buggy are will change the current format when
+	  processing VIDIOC_TRY_FMT. Save and restore the current format
+	  to ensure the format is kept unchanged.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=649067
+
+2011-08-08 15:27:11 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: update translations
+
+2011-08-08 15:26:00 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/aalib/Makefile.am:
+	  aalib: make sure -DGST_USE_UNSTABLE_API is defined
+	  So we don't get warnings.
+
+2011-08-08 15:25:31 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2videooverlay.c:
+	* sys/v4l2/gstv4l2videooverlay.h:
+	  v4l2: update for GstXOverlay => GstVideoOverlay rename
+
+2011-08-07 12:23:26 +0200  Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2src: Use fraction compare util function.
+	  Use the fraction compare utility to compare function, not the
+	  handcrafted one. The handcrafted one is buggy as it doesn't take into
+	  account rounding error. For example comparing a framerate of 20/1 on a
+	  camera configured as 30/1 fps would yield true: 1 == (1 * 20)/30 and not
+	  re-configure the camera. Fixes #656104
+
+2011-08-07 11:14:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulsesrc.h:
+	  pulsesrc: avoid race in starting
+	  Sine the base class now does the negotiation from the streaming thread we have
+	  to be careful and check if the stream is ready before changing its corked state.
+
+2011-08-05 12:27:18 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	  check: Use GST_CFLAGS when building tests
+	  Ensures we have the proper define for using unstable API
+
+2011-08-05 08:59:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/qtdemux.c:
+	  isomp4: fixup after small api changes
+	  Port to recently changed api so that it compiles again.
+
+2011-08-05 11:32:45 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/y4m/Makefile.am:
+	  y4menc: Now depends on libgstvideo
+
+2011-08-04 18:41:29 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulse: more cleanups
+
+2011-08-04 18:15:55 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: small cleanups
+
+2011-08-04 16:35:46 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: call set_caps method of baseclass
+	  Call the baseclass set_caps function to make it send the caps event and
+	  properly trigger the negotiation functions.
+
+2011-08-04 16:25:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: small cleanups
+
+2011-08-04 15:25:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* gst/goom/gstgoom.c:
+	  goom: port to new caps
+
+2011-08-04 13:52:18 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: Size variable should be a guint and not a gsize
+
+2011-08-04 12:50:01 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2sink.h:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: activate the pool in fallback
+	  When nobody is using our pool, activate it ourselves.
+	  Avoid leaking the buffer array.
+	  Set default pool configuration with caps.
+	  Don't keep current_caps, core does that for us now.
+
+2011-08-03 22:57:48 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* tests/icles/videocrop-test.c:
+	  fix compilation
+	  hal elements were removed, remove them from docs too
+	  change example for pad-block API (actually remove the pad block, an application
+	  should not be bothered with working around bugs in elements)
+
+2011-08-03 18:37:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/rtp/gstrtph264depay.c:
+	  port to new API
+
+2011-08-03 18:25:30 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/pulse/pulsesink.c
+	  ext/pulse/pulsesrc.c
+	  gst/audioparsers/gstac3parse.c
+	  gst/rtp/gstrtph264depay.c
+	  gst/rtp/gstrtph264pay.c
+	  gst/rtpmanager/gstrtpssrcdemux.c
+
+2011-08-03 22:50:05 +1000  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	* gst/matroska/matroska.c:
+	  matroska: Register new debug category
+	  Register the matroskareadcommon debug category when the
+	  plugin is loaded to avoid assertion output when debug is turned on.
+
+2011-08-03 13:38:01 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* tests/icles/gdkpixbufsink-test.c:
+	  test/ickles: Port gdkpixbufsink test
+
+2011-08-03 13:33:59 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/autodetect.c:
+	  Revert "tests/check/Makefile.am: Disable autodetect test temporarily, so that the build bots update -bad and the ranks of unr..."
+	  This reverts commit 475aed8af6d2a57c1d21490c824e754a6b2367a9.
+	  It won't consider elements from anywhere else anymore
+
+2011-08-03 13:10:46 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/parser.c:
+	  check: Update parser mini-lib to 0.11 API
+
+2011-08-03 13:09:07 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* po/POTFILES.in:
+	  po: update for modified source file location
+
+2011-08-03 13:08:43 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* configure.ac:
+	  configure.ac: cairo_gobject isn't ported either
+
+2011-08-03 10:59:56 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/hal/Makefile.am:
+	* ext/hal/gsthalaudiosink.c:
+	* ext/hal/gsthalaudiosink.h:
+	* ext/hal/gsthalaudiosrc.c:
+	* ext/hal/gsthalaudiosrc.h:
+	* ext/hal/gsthalelements.c:
+	* ext/hal/gsthalelements.h:
+	* ext/hal/hal.c:
+	* ext/hal/hal.h:
+	  hal: Remove hal plugin
+	  hal is not developed anymore and nobody is using the plugin nowadays.
+
+2011-07-29 13:03:55 +0200  Philippe Normand <pnormand@igalia.com>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: soften assertion check on stream size
+	  https://bugzilla.gnome.org/show_bug.cgi?id=655570
+
+2011-08-03 10:09:42 +0200  Robert Krakora <rob.krakora@messagenetsystems.com>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: Add support for H.264 payload in MJPEG container
+	  See http://www.quickcamteam.net/uvc-h264/USB_Video_Payload_H.264_0.87.pdf
+	  Fixes bug #655530.
+
+2011-08-02 22:05:08 -0400  Tristan Matthews <tristan@sat.qc.ca>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosink.h:
+	  jackaudiosink: Don't call g_alloca() in process_cb
+	  g_alloca() is not RT-safe, so instead we should allocate the
+	  memory needed in advance. Fixes #655866
+
+2011-08-03 08:58:00 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Add hal to the list of non-ported plugins
+
+2011-08-03 08:53:24 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Add monoscope to the list of non-ported plugins
+
+2011-08-03 08:51:19 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstwarp.c:
+	  effectv: Fix unused but set variable compiler warnings
+
+2011-08-02 23:42:58 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/multipart/multipartdemux.c:
+	* sys/v4l2/gstv4l2object.c:
+	  docs: fix two more Since: tags
+
+2011-07-31 04:19:00 +0300  Mart Raudsepp <leio@gentoo.org>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Fix Since tags for fieldanalysis related new properties
+	  commit c1b100cf9c is after 0.10.29 and 0.10.30 was a branched release.
+	  So fix Since tags from 0.10.29 to 0.10.31 for the new properties.
+
+2011-08-02 11:51:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	  rtpvorbispay: fix porting error
+
+2011-08-02 11:29:40 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* configure.ac:
+	  configure.ac: Define list of non-ported plugins
+
+2011-08-02 11:29:25 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* common:
+	  Update common submodule
+
+2011-08-02 11:17:38 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* configure.ac:
+	  configure.ac: Sort AG_GST_CHECK_PLUGIN alphabetically
+
+2011-07-29 17:27:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstwarp.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawdepay.h:
+	  -good: fix for bufferpool API change
+
+2011-07-29 17:21:03 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l: change for new API
+
+2011-07-29 13:05:42 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: fix variable-set-but-not-used compiler warning with older pulse versions
+
+2011-07-29 12:07:24 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: properly init rtcp_min_interval
+
+2011-03-09 11:04:36 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	* ext/pulse/pulseutil.c:
+	  pulsesink: Add support for compressed formats
+	  This adds support for various compressed formats (AC3, E-AC3, DTS and
+	  MP3) payloaded in IEC 61937 format (used for transmission over S/PDIF,
+	  HDMI and Bluetooth).
+	  The acceptcaps() function allows bins to probe for what formats the sink
+	  being connected to support. This only works after the element is set to
+	  at least READY.
+	  If the underlying sink changes and the format we are streaming is not
+	  available, we emit a message that will allow upstream elements/bins to
+	  block and renegotiate a new format.
+
+2011-03-01 15:34:46 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* configure.ac:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulseutil.c:
+	* ext/pulse/pulseutil.h:
+	  pulsesink: Use the extended stream API if available
+	  This uses the new extended API for creating streams. This will allow us
+	  to support compressed formats natively in pulsesink as well.
+
+2011-07-29 00:07:52 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulsesrc.h:
+	  pulsesrc: Add a source-output-index property
+	  This exposes the source output index of the record stream that we open
+	  so that clients can use this with the introspection if they want (to
+	  move the stream, for example).
+
+2011-07-28 14:44:57 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: keep a ref on the src pad while using it
+	  Prevent a possible race if clear_ssrc() is called between getting the pad and
+	  doing the push.
+	  Based on patch by <olivier.crete@collabora.com>
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650916
+
+2011-05-24 11:29:57 +0300  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtpmanager/gstrtpssrcdemux.h:
+	  rtpssrcdemux: Make the pads lock recursive and hold it across the signal emit
+	  We need to keep the lock held because we don't want a push before the "new-ssrc-pad"
+	  handler has completed. But we may want to push an event from inside that handler, hence
+	  the recursive mutex.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650916
+
+2011-05-24 11:17:25 +0300  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Use PADs lock
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650916
+
+2011-07-28 11:09:08 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	  speex: update for position/query/convert API changes
+
+2011-07-28 10:54:38 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/auparse/gstauparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/debugutils/gstnavseek.c:
+	* gst/debugutils/progressreport.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/wavparse/gstwavparse.c:
+	  gst: udpate for position/duration/convert query API changes
+
+2011-07-28 00:37:13 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix compiler warning
+	  gstavidemux.c: In function 'gst_avi_demux_parse_stream':
+	  gstavidemux.c:1261:24: error: 'data' may be used uninitialized in this function [-Werror=uninitialized]
+	  gstavidemux.c:1204:11: note: 'data' was declared here
+
+2011-07-27 18:15:20 +0100  Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264depay.h:
+	  rtph264depay: Cope with FU-A E bit not being set
+	  Some h264 payloaders are unfortunately buggy and don't correctly set the
+	  E bit in FU-A NAL when they have ended. Work around this by assuming
+	  such a fragmentation unit has ended when there was no packet loss and a
+	  new NAL is started
+
+2011-04-12 17:01:47 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstac3parse.h:
+	  ac3parse: Support switching alignment on-the-fly
+	  This allows switching of alignment for E-AC3 streams at run-time. This
+	  is requested by downstream elements via a custom event.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650313
+
+2011-07-27 16:46:46 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: remove unused variables
+	  Use the more specialized type for the bufferpool.
+	  Use the size from the driver as the size of the image to read.
+	  Don't configure the pool when created. This will be done in the setup_allocation
+	  method later or by upstream for sinks.
+	  Remove unused properties and variables. Bufferpool sizes are now configured in
+	  the bufferpool by the elements in the pipeline. We might want to influence the
+	  pool size later somehow.
+
+2011-07-27 13:46:09 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2bufferpool: remove unused variable
+
+2011-07-27 13:43:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: add metadata
+
+2011-07-27 13:41:28 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  bufferpool: check for metadata
+	  Only add video metadata when it was configured in the pool. Fail if there was no
+	  video metadata configured and the strides are not the default ones.
+
+2011-07-27 12:42:21 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstwarp.c:
+	* gst/effectv/gstwarp.h:
+	  warp: add stride support
+
+2011-07-27 12:41:33 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: add colorspace to debug
+
+2011-07-26 17:45:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtp: fix compilation
+
+2011-07-26 16:15:05 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: rename a variable
+	  Rename the size variable to sizeimage and fill it with the size that has been
+	  given to use by the v4l2 driver instead of making something up..
+
+2011-07-26 13:18:55 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2: use new setup_allocation vmethod
+
+2011-07-26 10:56:07 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: implement more bits of RW I/O mode
+	  Implement the relaese of RW buffers in the pool.
+	  Warn for unsupported write() mode for sinks.
+
+2011-07-26 10:54:23 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: improve IO mode error handling
+	  Error out when an unsupported IO mode was selected
+
+2011-04-09 12:26:56 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstac3parse.h:
+	* tests/check/elements/ac3parse.c:
+	  ac3parse: Add support for IEC 61937 alignment
+	  When pushing out buffers over S/PDIF or HDMI, IEC 61937 payloading
+	  requires each buffer to contain 6 blocks from each substream. This adds
+	  code to collect all the frames needed to meet this requirement before
+	  pushing out a buffer.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650313
+
+2011-06-08 15:57:37 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Always send application requested feedback in immediate mode
+	  Send as many application requested feedback messages in immediate mode, even if they
+	  have already been sent.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=654583
+
+2011-06-08 14:48:01 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Don't let the computed RTP bandwidth fall too low
+	  If it falls too low, the computed RTCP bandwidth will be near zero and
+	  the RTCP thread will be stopped.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=654583
+
+2011-04-25 16:13:38 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Wait longer to timeout SSRC collision
+	  Using the current RTCP interval to timeout SSRC collision can lead to
+	  collisions being timed out immediately if a BYE packet is sent because
+	  it is sent immediately, so the interval is 0. This is not what we
+	  want. So just set a static 10 times the default RTCP interval, it
+	  should be enough
+	  https://bugzilla.gnome.org/show_bug.cgi?id=648642
+
+2011-07-25 15:51:22 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2: remove unused method
+
+2011-07-25 15:38:38 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: fix flushing start and stop
+	  Move the flushing calls to the right place in the bufferpool.
+	  Fix the min and max buffer sizes.
+
+2011-07-25 14:47:05 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2: dequeue buffers when all are queued
+	  Prefer to always use the default bufferpool queue for the _acquire function
+	  because it properly supports unblocking when setting inactive etc. As a result,
+	  we need to dequeue buffers and put them back in the bufferpool queue when we
+	  have queued all buffers in the sink.
+	  Rename some variables to more meaningfull names to avoid a problem with
+	  freeing the wrong amount of buffers.
+
+2011-07-19 13:38:01 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: set SOURCE flag at init time
+	  Fixes #654816.
+
+2011-07-25 10:10:58 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstvertigo.c:
+	  vertigotv: add stride support
+
+2011-07-19 18:25:29 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: only to STREAMOFF when streaming
+	  Only call STREAMOFF when we previously called STREAMON
+
+2011-07-22 21:26:32 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/replaygain/gstrganalysis.c:
+	  replay: fix for event handler
+
+2011-07-22 21:19:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/debugutils/gstnavseek.c:
+	* gst/debugutils/progressreport.c:
+	  fixes for event handler changes
+
+2011-07-18 16:46:27 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: Complete merged AU on marker bit
+	  The marker bit on a RTP packet means the AU has been completed, so push it out
+	  immediately to reduce the latency.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=654850
+
+2011-07-18 20:27:38 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtph264pay.h:
+	  rtph264pay: Only set the marker bit on the last NALU of a multi-NALU access unit
+	  An access unit could contain multiple NAL units, in that case, only the last
+	  RTP packet of the last NALU should have its marker bit set.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=654850
+
+2011-07-20 08:52:58 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/multipart/multipartmux.c:
+	  multipart: fix compiler warning
+
+2011-07-19 18:20:43 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2: handle unsupported formats
+
+2011-07-19 16:59:55 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2: Fix sink bufferpool handling
+	  Remove old method, use neww _process method for the sink.
+	  Inform the parent bufferpool class about the settings too. This is needed to let
+	  it know about the max-buffers.
+	  Allocate the negotiated max-buffers and initially mmap min-buffers. The idea is
+	  that the bufferpool will allocate more when needed.
+	  Improve debugging.
+	  Only poll in capture mode, it does not seem to work in playback mode on this
+	  beagleboard.
+
+2011-07-19 12:05:51 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/auparse/gstauparse.c:
+	  auparse: avoid hanging on invalid short input
+	  ... as in such case there is no srcpad yet on which to forward EOS.
+
+2011-07-18 15:13:33 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: Fix default value leaking
+	  Remember to free the default value of client name, avoiding a
+	  leak
+
+2011-07-18 18:54:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	  v4l2: More work on bufferpools
+	  Add different transport methods to the bufferpool (MMAP and READ/WRITE)
+	  Do more parsing of the bufferpool config.
+	  Start and stop streaming based on the bufferpool state.
+	  Make separate methods for getting a buffer from the pool and filling it with
+	  data. This allows us to fill buffers from other pools too. Either use copy or
+	  read to fill up the target buffers.
+	  Add property to force a transfer mode in v4l2src.
+	  Increase default number of buffers to 4.
+	  Negotiate bufferpool and its properties in v4l2src.
+
+2011-07-18 14:24:48 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: reset upon FLUSH_STOP
+	  ... which is particularly needed when merging NAL units, where not resetting
+	  would lead to output of an older (pre-flush) AU (with unintended timestamp).
+
+2011-07-18 14:30:51 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: do not use g_slist_free_full
+	  ... as that is only in GLib 2.28, which is not yet required at this time.
+
+2011-07-18 10:52:23 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2: add IO method enum
+
+2011-07-18 10:51:21 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  bufferpool: improve _new function
+
+2011-07-18 09:38:26 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesink.h:
+	* tests/check/elements/multifile.c:
+	  multifilesink: add max-files property
+	  Add max-files property to limit the number of files saved on disk.
+	  API: multifilesink::max-files
+
+2011-07-17 23:36:55 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/multifile/gstmultifilesink.c:
+	  multifilesink: refactor file opening and closing code
+
+2011-07-16 19:38:51 +0200  Alexey Fisher <bug-track@fisher-privat.net>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: fix pixel-aspect-ratio if header has only one display variable
+	  Current matroska demux calculates the pixel aspect ratio only if both
+	  DisplayHeight and DisplayWidth are set, but it is legal to use only
+	  one variable if the other is equal to PixelWidth or PixelHeight, at
+	  least the mkclean utility is doing that. So this makse mkcleaned
+	  files play correctly.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=654744
+
+2011-07-16 23:47:50 +0100  Antoine Jacoutot <ajacoutot@openbsd.org>
+
+	* gst/goom/plugin_info.c:
+	  goom: fix build on PPC on openbsd
+	  A missing sys/param.h include results in:
+	  /usr/include/sys/proc.h:64: error: 'MAXLOGNAME' undeclared here (not in a
+	  function)
+	  /usr/include/sys/proc.h:285: error: 'MAXCOMLEN' undeclared here (not in a
+	  function)
+	  when compiling goom on openbsd/ppc. We can just remove the two sys/ includes
+	  here, they are not needed for anything.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=654749
+
+2011-07-15 17:06:39 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-07-15 16:55:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: implement setup_allocation
+	  Implement the setup_allocation vmethod, we'll hopefully do something clever in
+	  there later.
+
+2011-07-15 16:26:06 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: improve bufferpool config setting
+	  Pass the caps and the default video size to the bufferpool config.
+	  Don't activate the bufferpool, this will be done by the object that decides to
+	  use the bufferpool.
+	  Improve debugging and error reporting.
+
+2011-07-15 13:52:38 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: handle dequeueing correcly
+	  First clean up the buffers in the queue, then the remaining ones in the
+	  device.
+
+2011-07-15 13:29:42 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: unref copied buffer
+	  After we copy the incomming buffer to one of our bufferpool buffers, unref the
+	  target buffer after rendering so that it is put back in the pool.
+
+2011-07-15 13:07:11 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2: dequeue buffers for the sink
+	  When we have all buffers queued for playback and we need a new empty buffer,
+	  dequeue one and return it.
+	  Set the right size for sink buffers.
+	  Improve counting of queued buffers.
+
+2011-07-15 12:35:14 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: use the parent queue for the sink
+	  We want to maintain a queue of free buffers for the sink, use the parent methods
+	  to do that.
+
+2011-07-15 12:00:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: fix error messages
+
+2011-07-15 11:30:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2: add ALLOCATION query to the sink
+
+2011-07-15 11:27:18 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2: convert to GstBufferPool
+	  Extend from GstBufferPool.
+	  Handle the lifetime of the pool buffers correctly with the start/stop vmethods.
+	  Map acquire and release directly to QBUF and DQBUF. We still expose an explicit
+	  qbuf for the v4l2sink for now.
+
+2011-07-15 11:18:03 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: remove experimental markers
+
+2011-07-14 20:10:02 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtppcmupay.c:
+	  rtppcmApay/depay: Static clock rates on static payloads, dynamic on dynamic
+	  Partially reverts 397dc60b
+
+2011-07-14 16:21:36 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: merge code
+
+2011-07-14 16:12:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2sink.h:
+	  v4l2: Move output details to device object
+	  Move the details of how a buffer is rendered to the device object.
+
+2011-03-04 15:41:22 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: Implement getcaps
+	  Convert profile-level-id from RTP caps into video/x-h264 style caps (with profile and level)
+
+2011-07-13 18:32:00 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/gstv4l2tuner.c:
+	* sys/v4l2/gstv4l2vidorient.c:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/v4l2/v4l2src_calls.h:
+	  v4l2: move capture code to device object
+	  Move the details of how to capture to the device object. Remove the
+	  v4l2src_calls.[ch] files because they are empty now.
+	  Provide two simple methods to get and return a buffer to the device.
+	  Also do a slow copy when the buffer is not from our pool.
+
+2011-07-13 16:58:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: add some more debug
+
+2011-07-13 16:56:21 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2: stop streaming in READY and NULL
+
+2011-07-13 16:40:39 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: start streaming for the output as well
+
+2011-07-13 16:33:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2radio.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2sink.h:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/v4l2/v4l2src_calls.h:
+	  v4l2: Let the device object manage the pool
+	  Rename start and stop methods to open and close because that is what they do.
+	  After setting the format on the device object, setup the bufferpools. Move this
+	  code from the v4l2src_calls.c file, it is shared between source and sink.
+	  Make new device start and stop method that merges various bits of common code
+	  spread over several files.
+
+2011-07-13 13:52:30 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2: don't store stride in the videoinfo
+	  We want to keep the default strides in the videoinfo. Keep the stride of the
+	  video frames separate so that we can use both to copy a video frame and do
+	  correct stride conversion.
+
+2011-07-13 13:38:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2: Use video frame copy for raw video
+	  Use the video frame copy API for raw video frames so that we copy with the right
+	  strides.
+
+2011-07-13 13:37:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: add video metadata to raw video buffers
+
+2011-07-13 13:15:05 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: small cleanups
+
+2011-07-13 13:00:42 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2: improve caps parsing
+	  Use GstVideoInfo to store the parsed caps.
+	  Remove outsize from the caps parsing code, it's wrong because it does not use
+	  the stride given by the driver.
+
+2011-07-13 11:40:11 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: use errno
+
+2011-07-13 11:36:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: handle EINVAL without posting a warning
+	  EINVAL means that a call is not supported, we only want to post a WARNING when
+	  something is really wrong.
+
+2011-07-13 11:29:26 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: only set framerate for capture for now
+
+2011-07-13 11:19:28 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/v4l2_calls.h:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/v4l2/v4l2src_calls.h:
+	  v4l2: Move configuration of framerate to _set_format
+	  Move the configuration of the framerate to where we set the other format
+	  parameters.
+	  Remove hack to check if the device is active.
+	  Store streamparm in the device info.
+	  Use some macros to access the current device configuration.
+	  Remove some duplicate fields in src and sink and use the device configuration
+	  instead.
+
+2011-07-12 19:13:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: fix return value...
+
+2011-07-12 19:03:32 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/v4l2/v4l2src_calls.h:
+	  v4l2: simplify setting the capture format
+	  Pass the caps to the set_format function and make _set_format parse the caps.
+	  Also keep the parsed values in the v4l2object so that we can refer to them when
+	  we want.
+
+2011-07-12 18:41:47 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/v4l2/v4l2src_calls.h:
+	  v4l2: remove more unused parameters
+
+2011-07-12 18:29:35 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l: handle object out of the normal flow
+
+2011-07-12 18:13:42 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2: Let the bufferpool own the V4l2Object
+	  Keep track of the currently configured format and setting in the
+	  v4l2object.
+	  Pass the v4l2object to the bufferpool constructor so that the bufferpool can
+	  know everything about the currently configured settings. This also allows us
+	  to remove some awkward code.
+
+2011-07-12 17:06:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l: remove caps argument, it's not needed
+	  Remove the caps parameter, we don't need it anymore because we don't set
+	  caps on buffers anymore.
+
+2011-07-12 16:46:21 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l: pass the bytesperline around
+	  When setting a format, return the bytesperline to the caller so that it can be
+	  used to allocate buffers.
+
+2011-07-12 16:43:04 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  pool: make buffer writable
+	  We need writable buffers when we need to do a slow memcpy.
+
+2011-07-12 15:04:38 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix seeking regression
+	  ... introduced when shuffling around code for the async implementation
+	  by setting state of source (and udp sources) in _play before downstream
+	  flushing is undone.
+
+2011-07-11 15:23:41 +0300  René Stadler <rene.stadler@nokia.com>
+
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstac3parse.h:
+	  ac3parse: fix buffer duration on blocks-per-frame change
+	  The gst_base_parse_set_frame_rate call was predicated on a change to
+	  sample rate, duration or profile. However, the block count per frame can
+	  also change between packets, which would result in incorrect buffer
+	  durations.
+
+2011-07-11 13:51:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: handle pools
+	  Create a new pool in setcaps and stop/destroy the old one.
+	  Remove buffer_alloc functions.
+	  Check that we have v4l2 metadata in show_frame and fall back to memcpy into a
+	  buffer from our pool if we don't receive one of our own buffers.
+
+2011-07-11 12:04:57 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2: various cleanups
+	  Various cleanups, avoids useless casts, move error handling outside of the main
+	  code flow.
+	  Negotiate to a resonable resolution instead of the max resolution.
+
+2011-07-10 21:50:19 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpsirenpay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawdepay.h:
+	* gst/rtp/gstrtpvrawpay.c:
+	* gst/rtp/gstrtpvrawpay.h:
+	  rtp: port remaining to 0.11
+
+2011-07-10 14:56:00 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/ximage/gstximagesrc.c:
+	* sys/ximage/ximageutil.c:
+	  ximage: port to 0.11
+
+2011-07-10 13:44:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/y4m/gsty4mencode.c:
+	* gst/y4m/gsty4mencode.h:
+	  y4m: port some more
+	  Use video helpers.
+
+2011-07-10 13:28:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/y4m/gsty4mencode.c:
+	  y4m: port to 0.11
+
+2011-07-10 12:46:03 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartmux.c:
+	* gst/multipart/multipartmux.h:
+	  multipart: port to 0.11
+
+2011-07-10 11:42:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-07-10 11:40:40 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/debugutils/Makefile.am:
+	* gst/debugutils/breakmydata.c:
+	* gst/debugutils/efence.c:
+	* gst/debugutils/gstcapssetter.c:
+	* gst/debugutils/gstdebug.c:
+	* gst/debugutils/gstnavigationtest.c:
+	* gst/debugutils/gstnavigationtest.h:
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/debugutils/progressreport.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/debugutils/tests.c:
+	  debug: port to 0.11, disable others
+	  Diasable the efence and capsdebug elements, port them later.
+
+2011-07-09 19:23:41 -0700  David Schleef <ds@schleef.org>
+
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/multifile/gstmultifilesrc.h:
+	  multifilesrc: Improve looping
+	  Add start-index and stop-index properties.
+
+2011-06-16 13:57:03 +0100  Jonny Lamb <jonnylamb@jonnylamb.com>
+
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/multifile/gstmultifilesrc.h:
+	  multifile: add loop property to multifilesrc
+	  Fixes: #652727
+	  Signed-off-by: Jonny Lamb <jonnylamb@jonnylamb.com>
+	  Signed-off-by: David Schleef <ds@schleef.org>
+
+2009-11-20 10:07:43 +0100  Philip Jägenstedt <philipj@opera.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: 16-bit audio is signed, 8-bit is unsigned.
+	  Pretending to handle 8-bit signed causes distorted audio when
+	  actually given such audio, which you will get if passing 8-bit
+	  unsigned through audioconvert ! audioresample, as audioresample
+	  only handles 8-bit signed.  Fixes #605834.
+	  Signed-off-by: David Schleef <ds@schleef.org>
+
+2011-07-08 16:37:11 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2: fix gray format, use filter in getcaps
+
+2011-07-08 16:10:47 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2: port and enable v4l2sink
+
+2011-07-08 14:34:40 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: port to new video formats
+
+2011-07-08 12:51:14 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-07-08 12:49:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2colorbalance.c:
+	* sys/v4l2/gstv4l2radio.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2: port to 0.11
+
+2011-07-07 18:27:36 +0200  Alexey Fisher <bug-track@fisher-privat.net>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: handle blocks with duration=0
+	  Some video frames, for example alt-ref frame in VP8, will be
+	  never displayed. This is why it has duration=0.
+	  This patch allow to use this duration.
+	  Bug: 654175
+	  Signed-off-by: Alexey Fisher <bug-track@fisher-privat.net>
+
+2011-07-06 17:18:05 -0700  David Schleef <ds@schleef.org>
+
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmuxmap.c:
+	  qtmux: Add direct dirac mapping
+
+2011-07-07 17:59:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstripple.c:
+	* gst/effectv/gstripple.h:
+	  effectv: port last effectv element to 0.11
+
+2011-07-07 17:49:34 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gststreak.c:
+	* gst/effectv/gststreak.h:
+	  effectv: port streaktv to 0.11
+
+2011-07-07 17:40:22 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstradioac.h:
+	  effectv: port radioactv to 0.11
+
+2011-07-07 17:29:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstripple.c:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gststreak.c:
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstwarp.c:
+	  effectv: fix docs
+
+2011-07-07 17:29:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstop.c:
+	* gst/effectv/gstop.h:
+	  effectv: port op to 0.11
+
+2011-07-07 17:18:21 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstquark.h:
+	* gst/effectv/gstrev.c:
+	  effectv: port quark tv
+
+2011-07-07 16:57:39 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstrev.h:
+	  effectv: port revtv to 0.11
+
+2011-07-07 16:46:51 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstvertigo.h:
+	  effectv: port vertigotv to 0.11
+
+2011-07-07 16:38:10 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gstshagadelic.h:
+	  effectv: port shagadelictv to 0.11
+
+2011-07-07 11:22:26 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/auparse/gstauparse.c:
+	  auparse: use ALWAYS src pad rather than SOMETIMES
+
+2011-07-07 11:14:16 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/auparse/gstauparse.c:
+	  auparse: port to 0.11
+
+2011-07-06 19:03:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  shapewipe: beginnings of porting
+
+2011-07-06 18:50:26 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstwarp.c:
+	* gst/effectv/gstwarp.h:
+	  warptv: port to 0.11
+
+2011-07-06 18:50:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstdice.c:
+	  dice: keep track of info
+
+2011-07-06 18:32:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstdice.h:
+	  effectv: port dice
+
+2011-07-06 18:09:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstaging.h:
+	  effectv: port agingtv
+
+2011-07-06 17:50:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/aalib/Makefile.am:
+	* ext/aalib/gstaasink.c:
+	* ext/aalib/gstaasink.h:
+	  aasink: port to new video API
+
+2011-07-06 17:40:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/libcaca/Makefile.am:
+	* ext/libcaca/gstcacasink.c:
+	* ext/libcaca/gstcacasink.h:
+	  cacasink: port to 0.11
+
+2011-07-06 16:50:32 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpeg: beginnings of porting to 0.11
+
+2011-07-06 16:31:18 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: use ALWAYS source pad rather than SOMETIMES
+
+2011-07-06 16:10:34 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	* gst/wavparse/gstwavparse.h:
+	  wavparse: port to 0.11
+
+2011-07-06 16:10:23 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: port to 0.11
+
+2011-07-06 12:22:43 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: adjust to unsigned segment fields
+
+2011-07-06 15:57:23 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	  speex: port speex elements
+
+2011-07-06 12:05:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-07-06 10:11:52 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	  rtpmanager: port to 0.11
+	  * use G_DEFINE_TYPE
+	  * adjust to new GstBuffer and corresponding rtp and rtcp buffer interfaces
+	  * misc caps and segment handling changes
+	  FIXME: also relies on being able to pass caps along with a buffer,
+	  which has no evident equivalent yet, so that either needs one,
+	  or still needs quite some code path modification to drag along caps.
+
+2011-06-29 20:59:26 +0300  René Stadler <rene.stadler@nokia.com>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	  pulsesink: prevent race condition causing ref leak
+	  Since commit 8bfd80, gst_pulseringbuffer_stop doesn't wait for the
+	  deferred call to be run before returning. This causes a race when
+	  READY->NULL is executed shortly after, which stops the mainloop. This
+	  leaks the element reference which is passed as userdata for the callback
+	  (introduced in commit 7cf996, bug #614765).
+	  The correct fix is to wait in READY->NULL for all outstanding calls to
+	  be fired (since libpulse doesn't provide a DestroyNotify for the
+	  userdata). We get rid of the reference passing from 7cf996 altogether,
+	  since finalization from the callback would anyways lead to a deadlock.
+	  Re-fixes bug #614765.
+
+2011-07-04 08:58:14 +0300  René Stadler <rene.stadler@nokia.com>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: small cleanup of copy-paste code
+
+2011-06-29 19:50:42 +0300  René Stadler <rene.stadler@nokia.com>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	  pulsesink: remove unused member variable and misleading log message
+	  Wim changed it in commit 8bfd80 so that pa_defer_ran is not read
+	  anywhere.
+	  The log message used to annotate a mainloop_wait call which is gone.
+
+2011-07-05 15:37:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: fix caps
+
+2011-07-05 11:40:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstedge.h:
+	  effectv: port edgetv
+
+2011-07-05 10:12:25 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  Add -DGST_USE_UNSTABLE_API to the compiler flags to avoid warnings
+
+2011-07-04 12:58:38 -0700  David Schleef <ds@schleef.org>
+
+	* gst/goom/gstgoom.c:
+	  goom: Don't answer lantency queries before negotiation
+
+2011-07-04 18:15:42 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	  udp: port to new API
+
+2011-07-04 18:12:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsemixer.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	  pulse: remove implementsinterface
+
+2011-07-04 18:10:55 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: fix caps
+
+2011-07-04 18:06:48 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalphacolor.c:
+	* gst/alpha/gstalphacolor.h:
+	  alpha: port to new video API
+
+2011-07-04 17:00:34 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: more porting
+
+2011-07-04 16:09:33 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalpha.h:
+	  port to new video api
+
+2011-06-28 14:03:43 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstgamma.h:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideobalance.h:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videofilter/gstvideoflip.h:
+	  video: port to new video apis
+
+2011-07-04 14:30:09 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: avoid crashing on invalid input without components
+
+2011-07-04 11:09:19 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	* gst/flv/gstflvmux.c:
+	  flv: port to 0.11
+	  * use G_DEFINE_TYPE
+	  * adjust to new GstBuffer
+	  * misc segment and caps changes
+
+2011-07-04 11:48:13 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  ext/pulse/pulsesink.c
+
+2011-07-04 11:25:28 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: pass along segment info to collectpads
+	  ... so it can track this and be subsequently used to determine running time etc.
+
+2011-07-04 11:24:23 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: indicate raw format in aac caps
+
+2011-07-04 11:07:13 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: mind requested name for request pad
+
+2011-07-04 11:06:54 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: free scheduling query
+
+2011-07-03 19:51:32 -0700  David Schleef <ds@schleef.org>
+
+	* ext/pulse/plugin.c:
+	  pulse: Increase ranks to PRIMARY + 10
+	  So that pulsesrc/pulsesink get chosen over other possible PRIMARY
+	  src/sinks by autoaudiosink.  Presumably, if pulse is available, it
+	  is always preferred over another src/sink.
+	  Fixes: #647540.
+
+2011-06-30 18:47:48 -0700  David Schleef <ds@schleef.org>
+
+	* gst/multipart/multipartmux.c:
+	  multipartmux: Add \r\n to tail of pushed buffers
+	  Clients such as Firefox require the \r\n after the payload.
+
+2011-06-16 14:52:51 +0200  Branko Subasic <branko@axis.com>
+
+	* gst/matroska/ebml-read.c:
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: avoid looping when searching for clusters
+	  Fixes some bugs that results in the demuxer looping when seaching
+	  for clusters in non-finalized files.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=652195
+
+2011-06-30 12:30:22 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesrc.c:
+	  multifile: port to 0.10
+	  * use G_DEFINE_TYPE
+	  * adjust to new GstBuffer
+	  * misc caps handling
+
+2011-06-30 11:35:21 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/cutter/gstcutter.c:
+	  cutter: port to 0.11
+	  * use G_DEFINE_TYPE
+	  * adjust to new GstBuffer
+	  * minor misc
+
+2011-06-30 11:17:19 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/replaygain/gstrganalysis.c:
+	* gst/replaygain/gstrglimiter.c:
+	* gst/replaygain/gstrgvolume.c:
+	  replaygain: port to 0.11
+	  * use G_DEFINE_TYPE
+	  * adjust to new GstBuffer
+
+2011-06-30 10:53:09 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: remove deprecated property
+
+2011-06-30 10:51:55 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: port to 0.11
+	  * use G_DEFINE_TYPE
+	  * adjust to new GstBuffer
+
+2011-06-30 10:38:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/level/gstlevel.c:
+	  level: port to 0.11
+	  * use G_DEFINE_TYPE
+	  * adjust to new GstBuffer
+
+2011-06-30 10:30:16 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/equalizer/gstiirequalizer10bands.c:
+	* gst/equalizer/gstiirequalizer3bands.c:
+	* gst/equalizer/gstiirequalizernbands.c:
+	  equalizer: port to 0.11
+
+2011-06-10 18:54:48 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-parse.c:
+	  matroskaparse: fix reference counting of parse->streamheader
+	  https://bugzilla.gnome.org/show_bug.cgi?id=652286
+	  Signed-off-by: David Schleef <ds@schleef.org>
+
+2011-06-29 14:39:52 -0700  David Schleef <ds@schleef.org>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: Don't round up size of encoded buffers
+	  For some reason, in code dating to 2001, encoded jpeg buffers were
+	  rounded up to multiples of 4 bytes.  With the added bonus that the
+	  extra bytes are unwritten, causing valgrind issues.  Oops.  I can't
+	  think of any reason why JPEG buffers need to be multiples of 4 bytes,
+	  so I removed the padding.  There might be some code somewhere that
+	  depends on this behavior, so if this needs to be reverted, please fix
+	  the valgrind issues.
+
+2011-06-29 12:46:20 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/Makefile.am:
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atomsrecovery.c:
+	* gst/isomp4/gstqtmoovrecover.c:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	* gst/isomp4/gstqtmuxmap.c:
+	* gst/isomp4/gstrtpxqtdepay.c:
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  isomp4: port to 0.11
+
+2011-06-28 12:55:45 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: tweak some ported segment handling
+	  ... to avoid losing duration during push mode seeking, and to properly
+	  accumulate running time when segment seeking.
+
+2011-06-29 12:05:04 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: free date tag
+
+2011-06-28 12:26:37 +0200  Jonas Larsson <jonas.larsson@hiq.se>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: not so greedy minimum frame size
+	  Fixes #653559.
+
+2011-06-25 11:39:23 -0700  David Schleef <ds@schleef.org>
+
+	* configure.ac:
+	  configure: remove non-pkg-config check for shout
+	  Fixes: 653327
+
+2011-06-20 18:49:57 +0200  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* ext/raw1394/gst1394clock.c:
+	  dv1394src: make the internal clock thread safe
+	  Fixes: #653091.
+
+2011-06-24 11:54:29 +0200  Miguel Angel Cabrera Moya <madmac2501@gmail.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: return correct type when assertion fails
+
+2011-06-23 11:28:27 -0700  David Schleef <ds@schleef.org>
+
+	* common:
+	  Automatic update of common submodule
+	  From 69b981f to 605cd9a
+
+2011-06-22 16:41:13 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtsp: fix for uri changes
+
+2011-02-02 16:18:54 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* configure.ac:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulseutil.c:
+	* ext/pulse/pulseutil.h:
+	  pulse: Drop support for PA versions before 0.9.16
+	  This drops support fof PulseAudio versions prior to 0.9.16, which was
+	  released about 1.5 years ago. Testing with very old versions is not
+	  feasible and we don't want to maintain 2 independent code-paths.
+
+2011-06-21 18:24:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  configure.ac
+	  docs/plugins/inspect/plugin-esdsink.xml
+	  docs/plugins/inspect/plugin-gconfelements.xml
+
+2011-06-21 18:19:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: fix for header cleanups
+
+2011-06-21 15:15:06 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4adepay.c:
+	  rtpmp4adepay: fix output buffer timestamps in case of multiple frames
+
+2011-06-20 16:47:36 -0400  Olivier Crête <olivier.crete@collabora.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: The signal has 5 arguments, not 4
+
+2011-06-20 12:13:11 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: use string for video format now
+
+2011-06-20 12:04:48 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/Makefile.am:
+	  avi: link against gstvideo now
+
+2011-06-20 12:03:24 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avi: port to new caps
+
+2011-06-18 13:43:02 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  Bump git version after unplanned 0.10.30 release
+	  Merge branch '0.10.30'
+	  Conflicts:
+	  configure.ac
+	  docs/plugins/inspect/plugin-1394.xml
+	  docs/plugins/inspect/plugin-aasink.xml
+	  docs/plugins/inspect/plugin-alaw.xml
+	  docs/plugins/inspect/plugin-alpha.xml
+	  docs/plugins/inspect/plugin-alphacolor.xml
+	  docs/plugins/inspect/plugin-annodex.xml
+	  docs/plugins/inspect/plugin-apetag.xml
+	  docs/plugins/inspect/plugin-audiofx.xml
+	  docs/plugins/inspect/plugin-audioparsers.xml
+	  docs/plugins/inspect/plugin-auparse.xml
+	  docs/plugins/inspect/plugin-autodetect.xml
+	  docs/plugins/inspect/plugin-avi.xml
+	  docs/plugins/inspect/plugin-cacasink.xml
+	  docs/plugins/inspect/plugin-cairo.xml
+	  docs/plugins/inspect/plugin-cutter.xml
+	  docs/plugins/inspect/plugin-debug.xml
+	  docs/plugins/inspect/plugin-deinterlace.xml
+	  docs/plugins/inspect/plugin-dv.xml
+	  docs/plugins/inspect/plugin-efence.xml
+	  docs/plugins/inspect/plugin-effectv.xml
+	  docs/plugins/inspect/plugin-equalizer.xml
+	  docs/plugins/inspect/plugin-esdsink.xml
+	  docs/plugins/inspect/plugin-flac.xml
+	  docs/plugins/inspect/plugin-flv.xml
+	  docs/plugins/inspect/plugin-flxdec.xml
+	  docs/plugins/inspect/plugin-gconfelements.xml
+	  docs/plugins/inspect/plugin-gdkpixbuf.xml
+	  docs/plugins/inspect/plugin-goom.xml
+	  docs/plugins/inspect/plugin-goom2k1.xml
+	  docs/plugins/inspect/plugin-gstrtpmanager.xml
+	  docs/plugins/inspect/plugin-halelements.xml
+	  docs/plugins/inspect/plugin-icydemux.xml
+	  docs/plugins/inspect/plugin-id3demux.xml
+	  docs/plugins/inspect/plugin-imagefreeze.xml
+	  docs/plugins/inspect/plugin-interleave.xml
+	  docs/plugins/inspect/plugin-isomp4.xml
+	  docs/plugins/inspect/plugin-jack.xml
+	  docs/plugins/inspect/plugin-jpeg.xml
+	  docs/plugins/inspect/plugin-level.xml
+	  docs/plugins/inspect/plugin-matroska.xml
+	  docs/plugins/inspect/plugin-mulaw.xml
+	  docs/plugins/inspect/plugin-multifile.xml
+	  docs/plugins/inspect/plugin-multipart.xml
+	  docs/plugins/inspect/plugin-navigationtest.xml
+	  docs/plugins/inspect/plugin-oss4.xml
+	  docs/plugins/inspect/plugin-ossaudio.xml
+	  docs/plugins/inspect/plugin-png.xml
+	  docs/plugins/inspect/plugin-pulseaudio.xml
+	  docs/plugins/inspect/plugin-replaygain.xml
+	  docs/plugins/inspect/plugin-rtp.xml
+	  docs/plugins/inspect/plugin-rtsp.xml
+	  docs/plugins/inspect/plugin-shapewipe.xml
+	  docs/plugins/inspect/plugin-shout2send.xml
+	  docs/plugins/inspect/plugin-smpte.xml
+	  docs/plugins/inspect/plugin-soup.xml
+	  docs/plugins/inspect/plugin-spectrum.xml
+	  docs/plugins/inspect/plugin-speex.xml
+	  docs/plugins/inspect/plugin-taglib.xml
+	  docs/plugins/inspect/plugin-udp.xml
+	  docs/plugins/inspect/plugin-video4linux2.xml
+	  docs/plugins/inspect/plugin-videobox.xml
+	  docs/plugins/inspect/plugin-videocrop.xml
+	  docs/plugins/inspect/plugin-videofilter.xml
+	  docs/plugins/inspect/plugin-videomixer.xml
+	  docs/plugins/inspect/plugin-wavenc.xml
+	  docs/plugins/inspect/plugin-wavpack.xml
+	  docs/plugins/inspect/plugin-wavparse.xml
+	  docs/plugins/inspect/plugin-ximagesrc.xml
+	  docs/plugins/inspect/plugin-y4menc.xml
+	  win32/common/config.h
+
+2011-06-17 10:37:33 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/sunaudio/gstsunaudiosink.c:
+	* sys/sunaudio/gstsunaudiosink.h:
+	  sunaudio: fix typo in comment
+
+2011-06-17 18:12:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-06-17 18:11:38 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	  autodetect: fix caps
+
+2011-06-16 15:38:10 +0200  Luis de Bethencourt <luis.debethencourt@collabora.com>
+
+	* gst/goom/gstgoom.c:
+	  goom: fix unused-but-set-compiler warnings
+	  Remove unnecessary res variables, core checks existance
+	  and type of these fields for us already via the template
+	  caps, and we know that these fields exist because we've
+	  fixated them before in _negotiate().
+
+2011-06-17 03:07:09 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/audiofx/audioecho.c:
+	  audioecho: fix param flags
+	  If the parameter cannot be changed in paused&playing, it is not controlable. Set
+	  the appropriate mutability flag instead.
+
+=== release 0.10.30 ===
+
+2011-06-15 23:57:34 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.10.30
+	  This is an ad-hoc release that is almost identical to 0.10.29:
+	  * work around GLib atomic ops API change
+	  * better handling of malformed buffers in RTP depayloders
+	  * some minor compilation fixes
+
+2011-06-08 18:33:10 +0300  Raimo Järvi <raimo.jarvi@gmail.com>
+
+	* gst/udp/gstudpnetutils.h:
+	  udp: Fix compiler warning on mingw-w64
+	  Fixes: #652144.
+	  gstudpnetutils.h:32:0: error: "WINVER" redefined
+	  /usr/i686-w64-mingw32/sys-root/mingw/include/_mingw.h:231:0: note: this is the
+	  location of the previous definition
+
+2011-06-04 13:49:52 -0700  David Schleef <ds@schleef.org>
+
+	* gst/interleave/interleave.c:
+	  interleave: Work around changes in g_atomic API
+	  See #651514 for details.
+
+2011-05-18 12:36:40 +0200  Jose Antonio Santos Cadenas <santoscadenas@gmail.com>
+
+	* 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/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	  rtp: Fix segmentation fault processing payload buffers
+	  This commit checks if the value returned by
+	  gst_rtp_buffer_get_payload_buffer and
+	  gst_rtp_buffer_get_payload_subbuffer is NULL before using it.
+
+2011-05-16 09:04:31 +0200  Pino Toscano <toscano.pino@tiscali.it>
+
+	* ext/pulse/pulseutil.c:
+	  pulse: Define PATH_MAX if it isn't defined
+	  GNU Hurd for example doesn't define it.
+
+2011-04-29 08:55:19 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: Allow setcaps to be called after a format was negotiated if it's compatible
+	  Otherwise wavenc will fail if upstream decides to set equivalent caps or caps
+	  with additional information later.
+	  Thanks to Alexander Schremmer for finding this bug.
+
+2011-06-15 15:06:23 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* REQUIREMENTS:
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* ext/Makefile.am:
+	* ext/esd/Makefile.am:
+	* ext/esd/esdmon.c:
+	* ext/esd/esdmon.h:
+	* ext/esd/esdsink.c:
+	* ext/esd/esdsink.h:
+	* ext/esd/gstesd.c:
+	* gst-plugins-good.spec.in:
+	* m4/Makefile.am:
+	* m4/as-arts.m4:
+	* m4/esd.m4:
+	* po/POTFILES.in:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Remove esound/esdsink plugin
+
+2011-06-15 14:37:29 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* Makefile.am:
+	* REQUIREMENTS:
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* ext/Makefile.am:
+	* ext/gconf/Makefile.am:
+	* ext/gconf/gstgconf.c:
+	* ext/gconf/gstgconf.h:
+	* ext/gconf/gstgconfaudiosink.c:
+	* ext/gconf/gstgconfaudiosink.h:
+	* ext/gconf/gstgconfaudiosrc.c:
+	* ext/gconf/gstgconfaudiosrc.h:
+	* ext/gconf/gstgconfelements.c:
+	* ext/gconf/gstgconfelements.h:
+	* ext/gconf/gstgconfvideosink.c:
+	* ext/gconf/gstgconfvideosink.h:
+	* ext/gconf/gstgconfvideosrc.c:
+	* ext/gconf/gstgconfvideosrc.h:
+	* ext/gconf/gstswitchsink.c:
+	* ext/gconf/gstswitchsink.h:
+	* ext/gconf/gstswitchsrc.c:
+	* ext/gconf/gstswitchsrc.h:
+	* gconf/.gitignore:
+	* gconf/Makefile.am:
+	* gconf/gstreamer.schemas.in:
+	* gst-plugins-good.spec.in:
+	* m4/Makefile.am:
+	* m4/gconf-2.m4:
+	* po/POTFILES.in:
+	* tests/check/Makefile.am:
+	  Remove gconf elements and plugin
+	  GConf was deprecated in favour of GSettings etc.
+
+2011-06-15 15:17:19 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: fix unitialized access
+
+2011-06-09 21:06:28 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/matroska/matroska-read-common.c:
+	  matroska: add missing stdio include for sscanf
+
+2011-06-13 19:08:38 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-06-13 17:51:40 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/audiofx/audiopanorama.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  -good: port some more plugins
+
+2011-06-13 17:14:51 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtsp: fix for flush_stop API change
+
+2011-06-13 17:14:00 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	  rtp: port some more (de)payloader
+
+2011-06-13 17:05:19 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  audioparsers: not so greedy minimum frame size
+	  ... which will be determined by parsing anyway, and avoids introducing
+	  redundant additional latency.
+
+2011-06-13 16:33:57 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavisubtitle.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/udp/gstudpsrc.c:
+	  -good: update for buffer API change
+
+2011-06-13 16:33:46 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264pay.c:
+	  rtp: port to 0.11
+
+2011-06-13 13:25:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpdepay.c:
+	* gst/rtp/gstrtpdepay.h:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	  rtp: fix for API changes in the base classes
+
+2011-06-13 13:07:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: use caps event for negotiation
+
+2011-06-13 13:07:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix for flush stop event changes
+
+2011-06-08 18:33:10 +0300  Raimo Järvi <raimo.jarvi@gmail.com>
+
+	* gst/udp/gstudpnetutils.h:
+	  udp: Fix compiler warning on mingw-w64
+	  Fixes: #652144.
+	  gstudpnetutils.h:32:0: error: "WINVER" redefined
+	  /usr/i686-w64-mingw32/sys-root/mingw/include/_mingw.h:231:0: note: this is the
+	  location of the previous definition
+
+2011-06-11 18:58:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/goom/gstgoom.c:
+	  goom: fix for bufferpool update
+
+2011-06-10 18:05:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/goom/gstgoom.c:
+	  goom: update for alignment change
+
+2011-06-09 17:56:18 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: port some more
+
+2011-06-09 17:52:34 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtpdec.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtsp: port to 0.11
+
+2011-06-09 17:50:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udp: port to 0.11
+
+2011-06-09 11:37:47 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/aalib/gstaasink.c:
+	  aasink: register template and klass correctly
+
+2011-06-09 10:50:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/goom/gstgoom.c:
+	* gst/goom/gstgoom.h:
+	  goom: port goom
+
+2011-06-08 18:06:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-06-08 18:05:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/aalib/gstaasink.c:
+	  assink: port aasink to 0.11
+
+2011-06-07 12:06:08 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/debugutils/breakmydata.c:
+	* gst/debugutils/cpureport.c:
+	* gst/debugutils/gstcapsdebug.c:
+	* gst/debugutils/gstcapssetter.c:
+	* gst/debugutils/gstnavseek.c:
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/debugutils/gsttaginject.c:
+	* gst/debugutils/progressreport.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/debugutils/testplugin.c:
+	  debugutils: Switch from GST_BOILERPLATE to G_DEFINE_TYPE
+
+2011-06-07 11:25:18 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videofilter: Use new GstBaseTransform::transform_caps API
+
+2011-06-07 11:23:55 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/auparse/gstauparse.c:
+	  auparse: Don't use GST_BOILERPLATE
+
+2011-06-07 11:22:35 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	  audiofxbasefirfilter: Buffers no longer have caps
+
+2011-06-07 11:20:00 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalphacolor.c:
+	  alpha: Use new transform_caps vmethod (with filter)
+
+2011-06-06 20:43:31 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  audioparsers: fix some more parsers
+
+2011-06-06 18:21:04 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following function to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_parse_chapters
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-06-06 14:47:27 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* 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:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following function to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_parse_attachments
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-06-06 12:43:14 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following function to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_parse_attached_file
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-06-05 22:45:55 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* 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:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following function to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_parse_info
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-06-05 10:15:23 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* 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:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following function to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_parse_metadata
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-06-05 09:54:42 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following function to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_parse_metadata_id_tag
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-06-05 02:24:41 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following function to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_parse_metadata_id_simple_tag
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-06-06 12:42:53 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: reset state tracking variable when appropriate
+	  ... so we don't end up interrupting an operation that should not be interrupted
+	  based on the indication of a previous interruptable operation.
+
+2011-06-04 13:49:52 -0700  David Schleef <ds@schleef.org>
+
+	* gst/interleave/interleave.c:
+	  interleave: Work around changes in g_atomic API
+	  See #651514 for details.
+
+2011-06-04 13:43:00 -0700  David Schleef <ds@schleef.org>
+
+	* ext/soup/gstsouphttpsink.c:
+	* ext/soup/gstsouphttpsink.h:
+	  souphttpsink: code cleanup
+
+2011-06-05 02:00:08 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-parse.c:
+	  matroskaparse: Use ARTIST tag instead of AUTHOR for GST_TAG_ARTIST
+	  AUTHOR only existed in an old version of the spec and ARTIST is
+	  the new replacement for this. We are still reading both to still
+	  be compatible with old files.
+	  Fixes bug #644875.
+
+2011-06-02 18:51:29 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  sys/ximage/ximageutil.c
+
+2011-06-02 18:47:36 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavisubtitle.c:
+	  avi: port AVI elements to new API
+
+2011-06-02 13:38:30 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: First query the peer duration in the requested format before converting to BYTES
+	  Fixes usage of dvdemux after another demuxer, e.g. mxfdemux.
+	  Fixes bug #650503.
+
+2011-06-02 10:41:52 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsink.c:
+	  souphttpsink: Fix refcounting of the "session" property
+	  Properties should never take ownership of the values
+	  passed to them.
+
+2011-06-01 17:04:27 -0700  David Schleef <ds@schleef.org>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: For streaming files, push tags first
+
+2011-05-24 14:52:01 -0700  David Schleef <ds@schleef.org>
+
+	* ext/soup/Makefile.am:
+	* ext/soup/gstsoup.c:
+	* ext/soup/gstsouphttpsink.c:
+	* ext/soup/gstsouphttpsink.h:
+	* ext/soup/gstsouphttpsrc.c:
+	  soup: Add souphttpsink
+
+2011-06-01 10:19:31 +0200  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: allow skip-first-bytes of full buffer size
+
+2011-05-30 18:31:50 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following functions to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_parse_header
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-30 12:09:31 +0200  Antonio Frediani <antonio.frediani@inwind.it>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Use GST_TAG_IMAGE for coverart too
+	  Fixes bug #638107.
+
+2011-05-30 10:40:08 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following functions to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_get_seek_track
+	  - gst_matroska_{demux,parse}_reset_streams
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-28 22:04:34 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* 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:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following function to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska{demux,parse}_found_global_tag
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-28 10:59:09 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following functions to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_index_seek_find
+	  - gst_matroska{demux,parse}_do_index_seek
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-27 23:15:23 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following function to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_tracknumber_unique
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-27 20:28:19 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following function to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_decode_data
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-27 19:30:48 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following function to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_get_length
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-27 09:17:46 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: Revert 1a90a6c4 and drop Dirac support again
+	  It does not work at all (A/V sync issues), is not very useful,
+	  other containers work much better with Dirac and Dirac in AVI
+	  is not supported by other software.
+	  Fixes bug #541215.
+
+2011-05-26 23:35:52 +0530  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following functions to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_encoding_cmp
+	  - gst_matroska_{demux,parse}_read_track_encodings
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-23 18:06:44 +0300  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following functions to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_peek_id_length_pull
+	  - gst_matroska_{demux,parse}_peek_id_length_push
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-23 18:06:44 +0300  Debarshi Ray <rishi@gnu.org>
+
+	* 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:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following function to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_peek_adapter
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-26 12:48:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/ximage/ximageutil.c:
+	  xvimagesink: Fallback to non-XShm mode if allocating the XShm image failed
+	  Fixes bug #630456.
+
+2011-05-26 12:22:52 +0200  Marc Leeman <marc.leeman@gmail.com>
+
+	* gst/rtp/gstrtpmp4vpay.c:
+	  rtpmp4vpay: Deprecated send-config property and replace by config-interval
+	  Fixes bug #622412.
+
+2010-06-23 11:12:00 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	  matroskademux: UTF-8 subtitles may have markup
+	  Fixes #616936.
+
+2011-01-23 15:56:49 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/cairo/gsttextoverlay.c:
+	* ext/cairo/gsttextoverlay.h:
+	  cairotextoverlay: forward new segment events from the sink to the source
+	  Not doing so will cause buffers to be received by downstream without
+	  a time base set.
+	  We use the same method avimux uses to get access to the event when
+	  collectpads got the sink event function.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=640323
+
+2011-01-24 11:11:48 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/cairo/gsttextoverlay.c:
+	  textoverlay: forward source events to sinks
+	  Events are passed to the video sink, and to the text sink if it is
+	  linked.
+	  This will allow seeking, for instance.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=586450
+
+2011-05-25 21:12:12 +0200  David Hoyt <dhoyt@llnl.gov>
+
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartdemux.h:
+	  multipartdemux: Add property to assume a single stream and emit no-more-pads
+	  Fixes bug #616686.
+
+2011-05-25 14:50:26 +0200  Miguel Angel Cabrera Moya <madmac2501@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: uniform unknown message handling
+	  Do the same processing in all the cases when an unknown message is received.
+	  That is, give a warning.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=651059
+
+2011-05-23 18:06:44 +0300  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following function to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_peek_pull
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-23 18:06:44 +0300  Debarshi Ray <rishi@gnu.org>
+
+	* 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:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following function to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_peek_bytes
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-23 18:06:44 +0300  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following functions to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_{demux,parse}_encoding_order_unique
+	  - gst_matroska_{demux,parse}_read_track_encoding
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-24 18:27:10 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	  autodetect: port to new API
+
+2011-05-24 17:34:19 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  gst/avi/gstavidemux.c
+	  gst/rtp/gstrtpac3depay.c
+	  gst/rtp/gstrtpg726depay.c
+	  gst/rtp/gstrtpmpvdepay.c
+	  gst/videofilter/gstgamma.c
+
+2011-05-24 13:12:19 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtppcmudepay.c:
+	  pcmudepay: allow variable sample rate
+
+2011-05-24 13:11:54 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtppcmadepay.c:
+	  pcmadepay: allow variable sample rate
+
+2010-04-04 06:43:41 -0500  Rob Clark <rob@ti.com>
+
+	* 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:
+	  v4l2: add norm property
+	  Based on a patch by Guennadi Liakhovetski.
+	  v2: updates because I forgot to add GstTuner interface to v4l2sink
+	  v3: update to add all possible values to norm enum
+
+2011-05-23 20:46:04 +0300  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: fixed copyright headers
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-23 18:06:44 +0300  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-read-common.c:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Move the following functions to matroska-read-common.[ch] from
+	  matroska-demux.c and matroska-parse.c:
+	  - gst_matroska_decode_content_encodings
+	  - gst_matroska_decompress_data
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-23 18:48:57 +0300  Debarshi Ray <rishi@gnu.org>
+
+	* 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.h:
+	  matroska: move GstMatroska{Demux,Parse}::state to GstMatroskaReadCommon
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-24 09:48:56 +0200  Jonas Larsson <jonas.larsson@hiq.se>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Fix buffer leak with corrupted files
+	  Fixes bug #650912.
+
+2011-05-23 02:46:38 -0700  Miguel Angel Cabrera Moya <madmac2501@gmail.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: fix parameter type in trace
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650937
+
+2011-05-23 18:06:44 +0300  Debarshi Ray <rishi@gnu.org>
+
+	* 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:
+	* gst/matroska/matroska-read-common.h:
+	  matroska: refactor code common to matroskademux and matroskaparse
+	  Replace the following functions with their gst_matroska_read_common_*
+	  counterparts:
+	  - gst_matroska_{demux,parse}_parse_index
+	  - gst_matroska_{demux,parse}_parse_skip
+	  - gst_matroska_{demux,parse}_stream_from_num
+	  Introduce GstMatroskaReadCommon to contain those members of
+	  GstMatroskaDemux and GstMatroskaParse that were used by the above
+	  functions.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650877
+
+2011-05-23 13:50:46 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: tell baseparse the duration in samples for better accuracy
+	  Tell GstBaseParse the duration in samples instead of time, so that
+	  a duration query in DEFAULT format will return the correct number
+	  of samples without rounding errors. Baseparse will convert this
+	  into time itself when needed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650785
+
+2011-05-23 13:25:44 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: also try upstream first for duration query in DEFAULT format
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650785
+
+2011-05-23 13:23:21 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: make conversion from TIME to DEFAULT format (samples) work
+	  Fix copy'n'paste error in the previous commit.
+
+2011-05-23 11:36:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Implement conversions between TIME and DEFAULT format
+	  Fixes bug #650785.
+
+2011-05-22 18:50:51 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: don't error out on invalid minimum_blocksize value in streaminfo header
+	  We don't use it, so may just as well accept an invalid value
+	  of 0 here, which is likely inconsequential anyway.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650691
+
+2011-05-20 10:34:47 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	  rtp: fix static array overruns in a nicer way
+	  Use G_N_ELEMENTS instead of hard-coding the array size.
+
+2011-05-20 00:53:44 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	  rtp: fix static array overruns
+	  Yes array[10] has elements from 0...9.
+
+2011-05-19 23:31:19 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* 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:
+	  docs: update plugin introspection data
+	  Now more files are merged and produced in a canonical fashion, which hopefully
+	  creates less or no delta in the future.
+
+2011-05-19 22:57:15 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 9e5bbd5 to 69b981f
+
+2011-05-19 18:21:33 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: add missing break
+
+2010-11-08 14:06:15 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  deinterlace: Add support for deinterlacing using buffer caps/flags
+	  When not using the fieldanalysis element immediately upstream of deinterlace,
+	  behaviour should remain unchanged. fieldanalysis will set the caps and flags on
+	  the buffers such that they can be interpreted and acted upon to produce
+	  progressive output.
+	  There are two main modes of operation:
+	  - Passive pattern locking
+	  Passive pattern locking is a non-blocking, low-latency mode of operation that
+	  is suitable for close-to-live usage. Initially a telecine stream will be
+	  output as variable framerate with naïve timestamp adjustment. With each
+	  incoming buffer, an attempt is made to lock onto a pattern. When a lock is
+	  obtained, the src pad and output buffer caps will reflect the pattern and
+	  timestamps will be accurately interpolated between pattern repeats. This
+	  means that initially and at pattern transitions there will be short periods
+	  of inaccurate timestamping.
+	  - Active pattern locking
+	  Active pattern locking is a blocking, high-latency mode of operation that is
+	  targeted at use-cases where timestamp accuracy is paramount. Buffers will be
+	  queued until enough are present to make a lock. When locked, timestamps will
+	  be accurately interpolated between pattern repeats. Orphan fields can be
+	  dropped or deinterlaced. If no lock can be obtained, a single field might be
+	  pushed through to be deinterlaced.
+	  Locking can also be disabled or 'auto' chooses between passive and active
+	  locking modes depending on whether upstream is live.
+
+2011-05-10 16:25:40 -0700  David Schleef <ds@schleef.org>
+
+	* configure.ac:
+	  configure: Remove config script check for caca
+
+2011-05-18 12:36:40 +0200  Jose Antonio Santos Cadenas <santoscadenas@gmail.com>
+
+	* 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/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	  rtp: Fix segmentation fault processing payload buffers
+	  This commit checks if the value returned by
+	  gst_rtp_buffer_get_payload_buffer and
+	  gst_rtp_buffer_get_payload_subbuffer is NULL before using it.
+
+2011-05-18 16:10:07 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From fd35073 to 9e5bbd5
+
+2011-05-18 12:52:31 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: ensure 0-padding when correcting dubious list size
+
+2011-05-18 12:24:25 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 46dfcea to fd35073
+
+2011-05-18 10:22:27 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: use EINVAL for missing url parameter
+	  Fixes gcc warning about using uninitialized variable 'res'.
+
+2011-04-28 15:37:40 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/debugutils/rndbuffersize.c:
+	* gst/videofilter/gstgamma.c:
+	  various: fix author tag in element details
+
+2011-04-20 15:25:58 -0400  Chris E Jones <chris@chrisejones.com>
+
+	* gst/auparse/gstauparse.c:
+	  auparse: implement seeking
+	  Implement seeking and seeking query. Fixes #644512
+
+2011-05-17 16:13:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-04-06 16:05:55 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: also allow PAUSE to be interrupted
+	  ... as it is on the way out to NULL.
+	  See #632504.
+
+2011-04-06 15:51:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: ensure proper closing and cleanup
+	  ... since the TEARDOWN sequence might not have had a chance to even start,
+	  but at least connections should be closed (synchronously) and state cleaned up.
+	  See #632504.
+
+2011-04-06 15:49:01 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: fix and improve async handling
+	  Simplify the command handling; passing a command to thread means we really
+	  want it to get the message, which means to always flush provided the command
+	  can handle being interrupted.  Command thread indicates whether command
+	  allows interruption and ensure non-flushing connection as it subsequently
+	  needs it.
+	  In particular, this also makes the TEARDOWN sequence interruptable
+	  and also prevents races where _loop_ could miss a command and would
+	  continue receiving (or at least trying to).
+	  See #632504.
+
+2011-04-06 14:53:27 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: tweak post-seek loop handling
+
+2011-01-10 12:46:37 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: open on play and pause when not done yet
+	  With the async state changes, it is possible that we need to open the stream
+	  before play and pause.
+	  Also make sure we remember a previous open failure so that we don't keep trying
+	  again.
+
+2011-01-10 11:45:03 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: improve async handling
+	  Simplify the command handling, only continue looping when we have not received
+	  another command or when the previous loop was successfull.
+	  Avoid looping on a disconnected socket.
+
+2011-01-07 18:02:49 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: rework reconnect code
+	  Use the same async code path to implement reconnects.
+	  Make sure we only post progress messages when doing async things.
+
+2011-01-07 17:19:59 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: small cleanups
+	  Make sure we cancel the previous task when queuing a new one.
+	  Move the messages to a central place so we can more easily post them.
+
+2011-01-07 15:15:49 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: don't post errors when interrupting
+
+2011-01-07 13:43:06 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: implement more async handling
+	  Remove some old locks.
+	  Make sure we never go into the loop function when flushing.
+
+2011-01-07 11:40:32 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: first attempt at async implementation
+
+2011-01-07 11:40:11 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: small header cleanups
+
+2011-05-17 10:47:32 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  ssrcdemux: Fix uninitialized variable compiler warning for (pre-) releases too
+
+2011-04-28 15:57:04 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2objects: Only allow mpeg-ts on source objects
+	  Ugly fix for #648312
+
+2011-05-17 09:24:08 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Fix uninitialized variable compiler warning
+
+2011-05-06 19:09:17 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  ssrcdemux: Implement iterate internal links for sink pads
+	  https://bugzilla.gnome.org/show_bug.cgi?id=649617
+
+2011-05-06 18:41:01 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: iterate pad function is only valid for src pads
+	  The iterate function is only used for src pads, so mark it as such and remove
+	  dead code.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=649617
+
+2011-05-06 18:12:53 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Release lock before emitting signal
+	  If the lock is not released before emitting a signal, it may cause a deadlock
+	  if any other function in the element is called.
+	  Also removed an unused timestamp parameter
+	  https://bugzilla.gnome.org/show_bug.cgi?id=649617
+
+2011-05-15 23:25:15 +0300  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-parse.c:
+	  matroskaparse: calculate segment duration after parsing all the IDs
+	  Since the segment duration is given in terms of the
+	  GST_MATROSKA_ID_TIMECODESCALE we should only convert it into
+	  nanoseconds when we are sure that any scale specified in the file has
+	  been read.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650258
+
+2011-05-16 17:52:11 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  configure.ac
+
+2011-05-16 17:50:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	  -good: fix for new API
+
+2011-05-04 11:55:21 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: additional lock safety
+	  Fixes #619590.
+
+2011-04-26 16:06:56 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: also check for bitrate info in caps
+
+2010-05-25 01:04:43 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	  qtdemux: guess bitrate if only one stream's bitrate is unknown
+	  If the bitrates for all but one audio/video streams are known, and the
+	  total stream size and duration can be determined, this calculates the
+	  unkown bitrate as (stream size / duration) - (sum of known bitrates).
+	  While this is not guaranteed to be very accurate, it should be good
+	  enough for most purposes.
+	  For example, this is useful for H.263 + AAC streams where no 'btrt' atom
+	  is available for the video portion.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=619548
+
+2010-05-31 23:59:59 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/isomp4/qtdemux.c:
+	  qtdemux: Export max bitrate for AMR-NB/-WB streams
+	  This parses the 'damr' atom if present, and exports the maximum bitrate
+	  of the stream using the mode set field to determine the highest bitrate
+	  frame type that might be present.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=620186
+
+2011-05-16 09:04:31 +0200  Pino Toscano <toscano.pino@tiscali.it>
+
+	* ext/pulse/pulseutil.c:
+	  pulse: Define PATH_MAX if it isn't defined
+	  GNU Hurd for example doesn't define it.
+
+2011-05-15 23:25:15 +0300  Debarshi Ray <rishi@gnu.org>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: calculate segment duration after parsing all the IDs
+	  Since the segment duration is given in terms of the
+	  GST_MATROSKA_ID_TIMECODESCALE we should only convert it into
+	  nanoseconds when we are sure that any scale specified in the file has
+	  been read.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=650258
+
+2011-05-09 19:00:45 +0200  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Add support for mpegversion 2, which is also AAC
+
+2011-05-11 10:25:15 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacdec.h:
+	  flacdec: Send EOS when seeking after the end of file instead of failing
+	  Fixes bug #649780.
+
+2011-04-29 08:59:20 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: Set fixedcaps getcaps function on the sinkpad
+	  wavenc does not allow to change the caps during playback
+	  and always returning the template caps is just wrong.
+
+2011-04-29 08:55:19 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: Allow setcaps to be called after a format was negotiated if it's compatible
+	  Otherwise wavenc will fail if upstream decides to set equivalent caps or caps
+	  with additional information later.
+	  Thanks to Alexander Schremmer for finding this bug.
+
+2011-05-14 10:02:22 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	  Back to development
+
+=== release 0.10.29 ===
+
+2011-05-10 10:04:28 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/gst-plugins-good-plugins.prerequisites:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	* win32/common/config.h:
+	  Release 0.10.29
+	  Highlights:
+	  - amrparse, aacparse, ac3parse, flacparse, mpegaudioparse, dcaparse audio parsers (moved from -bad)
+	  - muxers now mux based on running time
+	  - ISO MP4 muxers: mp4mux/3gppmux/qtmux/mj2mux (moved from -bad)
+	  - new matroskaparse element
+	  - new v4l2radio element
+	  - rtpsession: support RTCP Early Feedback (the AVPF profile)
+	  - orc 0.4.14 or newer recommended
+	  - many other fixes and improvements
+
+2011-05-05 13:24:23 +0200  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/isomp4/gstqtmux.c:
+	  qtmux: Fix signed floating point values writing
+	  You would end up on some architectures with 0 being written out
+	  instead of the proper value.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=649449
+
+2011-05-04 12:04:15 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: avoid building index when streamable
+	  ... as it will not be written anyway.
+	  Fixes #648937 (?).
+
+2011-05-02 12:09:02 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* Makefile.am:
+	  build: add old qtdemux/quicktime directories to CRUFT_DIRS and CRUFT_FILES
+
+2011-05-01 00:04:03 -0400  Tom Janiszewski <tom.janiszewski@alcatel-lucent.com>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: don't overwrite metadata tag with duration in streaming mode
+	  A duration tag gets inserted only for streamable=false, so only
+	  update/write the duration later if we actually inserted that tag,
+	  otherwise we write garbage into other tags.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=649060
+
+2011-04-30 18:16:36 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/gst-plugins-good-plugins.prerequisites:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* po/fr.po:
+	* win32/common/config.h:
+	  0.10.28.4 pre-release
+
+2011-04-30 17:46:36 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* Android.mk:
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/inspect/plugin-isomp4.xml:
+	* gst-plugins-good.spec.in:
+	* gst/isomp4/LEGAL:
+	* gst/isomp4/Makefile.am:
+	* gst/isomp4/atoms.c:
+	* gst/isomp4/atoms.h:
+	* gst/isomp4/atomsrecovery.c:
+	* gst/isomp4/atomsrecovery.h:
+	* gst/isomp4/descriptors.c:
+	* gst/isomp4/descriptors.h:
+	* gst/isomp4/fourcc.h:
+	* gst/isomp4/ftypcc.h:
+	* gst/isomp4/gstqtmoovrecover.c:
+	* gst/isomp4/gstqtmoovrecover.h:
+	* gst/isomp4/gstqtmux-doc.c:
+	* gst/isomp4/gstqtmux-doc.h:
+	* gst/isomp4/gstqtmux.c:
+	* gst/isomp4/gstqtmux.h:
+	* gst/isomp4/gstqtmuxmap.c:
+	* gst/isomp4/gstqtmuxmap.h:
+	* gst/isomp4/gstrtpxqtdepay.c:
+	* gst/isomp4/gstrtpxqtdepay.h:
+	* gst/isomp4/isomp4-plugin.c:
+	* gst/isomp4/properties.c:
+	* gst/isomp4/properties.h:
+	* gst/isomp4/qtatomparser.h:
+	* gst/isomp4/qtdemux.c:
+	* gst/isomp4/qtdemux.h:
+	* gst/isomp4/qtdemux.vcproj:
+	* gst/isomp4/qtdemux_dump.c:
+	* gst/isomp4/qtdemux_dump.h:
+	* gst/isomp4/qtdemux_fourcc.h:
+	* gst/isomp4/qtdemux_lang.c:
+	* gst/isomp4/qtdemux_lang.h:
+	* gst/isomp4/qtdemux_types.c:
+	* gst/isomp4/qtdemux_types.h:
+	* gst/isomp4/qtpalette.h:
+	* po/POTFILES.in:
+	  quicktime: rename plugin to isomp4
+	  https://bugzilla.gnome.org/show_bug.cgi?id=648004
+
+2011-04-29 17:55:28 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	  audioparsers: fix some parsers
+
+2011-04-29 17:54:42 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	  fix error caused by merging
+
+2011-04-29 15:49:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  configure.ac
+	  gst/rtp/gstrtpgstpay.c
+
+2011-04-29 15:46:21 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	  audiofx: fix pad_alloc
+
+2011-04-27 12:45:51 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* 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:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* po/bg.po:
+	* po/ja.po:
+	* po/nl.po:
+	* po/ru.po:
+	* win32/common/config.h:
+	  0.10.28.3 pre-release
+
+2011-04-26 15:58:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: fix buffer leak
+
+2011-04-26 15:58:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: fix buffer leak
+
+2011-04-26 15:42:47 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: port jack elements
+
+2011-04-25 10:04:52 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: documentation typo "jpegddec"
+	  https://bugzilla.gnome.org/show_bug.cgi?id=648589
+
+2011-04-25 18:14:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	  rtp: port some more elements
+
+2011-04-25 17:27:40 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpg722depay.c:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtpg723depay.c:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pay.h:
+	* gst/rtp/gstrtpmparobustdepay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtppcmupay.c:
+	  rtp: port more to 0.11
+
+2011-04-25 13:16:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpdepay.c:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	  rtp: port some more (de)payloaders
+
+2011-04-25 12:49:36 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalphacolor.c:
+	* gst/apetag/gstapedemux.c:
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audiofirfilter.c:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbaseiirfilter.c:
+	* gst/audiofx/audioiirfilter.c:
+	* gst/audiofx/audioinvert.c:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/audiofx/audiopanorama.c:
+	* gst/audiofx/audiowsincband.c:
+	* gst/audiofx/audiowsinclimit.c:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideoflip.c:
+	  port some more elements to 0.11
+
+2011-04-25 11:38:28 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-04-24 16:45:07 -0700  David Schleef <ds@schleef.org>
+
+	* gst/avi/gstavimux.c:
+	* gst/matroska/matroska-mux.c:
+	  avimux,matroskamux: Add stream-format to h264 caps
+	  Fixes #606662.
+
+2011-02-20 12:13:49 -0800  David Schleef <ds@schleef.org>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: Remove temporary code
+	  Now that we depend on (what will be) -base-0.10.33.
+
+2011-04-24 14:03:56 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: don't pass -Waddress to ObjC compiler on OSX when compiling osxvideosink
+	  Temporary workaround until we fix this properly and check for
+	  the ObjC warning/error flags instead of just passing CFLAGS to the
+	  ObjC compiler.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=643939
+
+2011-04-24 13:29:32 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* gst-plugins-good.spec.in:
+	* gst/quicktime/Makefile.am:
+	  quicktime: rename plugin filename from *qtdemux* to *quicktime*
+	  https://bugzilla.gnome.org/show_bug.cgi?id=648004
+
+2011-04-24 14:03:41 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From c3cafe1 to 46dfcea
+
+2011-04-21 23:30:26 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* gst/quicktime/Makefile.am:
+	* gst/quicktime/gstqtmoovrecover.c:
+	* gst/quicktime/gstqtmux-doc.c:
+	* gst/quicktime/gstqtmux-doc.h:
+	  docs: add various qtmux variants to documentation
+
+2011-04-21 22:51:52 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmuxmap.c:
+	* gst/quicktime/gstqtmuxmap.h:
+	  quicktime: register 3gppmux element in addition to the misnamed gppmux
+
+2011-04-18 18:08:30 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Remove incomplete support for RTCP FIR
+	  Remove bits that were meant to suppport RTCP FIR
+	  https://bugzilla.gnome.org/show_bug.cgi?id=648160
+
+2011-04-19 18:55:31 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflactag.c:
+	  flac: port to 0.11
+
+2011-04-19 17:35:47 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtpdec.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	  use G_DEFINE_TYPE some more
+
+2011-04-19 17:20:19 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavisubtitle.c:
+	  avi: use G_DEFINE_TYPE
+
+2011-04-19 17:07:18 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsemixer.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	  use G_DEFINE_TYPE
+
+2011-04-19 16:25:28 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-04-19 14:33:25 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/generic/.gitignore:
+	* tests/check/generic/index.c:
+	  tests: add generic set_index test
+
+2011-04-19 14:33:42 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: fix deadlock on setting index on flvdemux
+
+2011-04-19 14:16:11 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/flacparse.c:
+	  tests: add index-setting test for baseparse/flacparse
+	  https://bugzilla.gnome.org/show_bug.cgi?id=646811
+
+2011-04-18 11:29:15 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/pipelines/wavpack.c:
+	  wavpack: Remove bus GSource to prevent a valgrind warning
+
+2011-04-18 11:14:32 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/pipelines/wavenc.c:
+	  wavenc: Remove bus GSource to prevent a valgrind warning
+
+2011-04-18 11:11:53 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/pipelines/tagschecking.c:
+	  tagschecking: Remove bus GSource to prevent a valgrind warning
+
+2011-04-18 11:10:01 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/imagefreeze.c:
+	  imagefreeze: Remove bus GSource to prevent a valgrind warning
+
+2011-04-18 10:54:43 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/audiofx/audiopanorama.c:
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	  port more plugins to 0.11
+
+2011-04-18 10:23:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  android/apetag.mk
+	  android/avi.mk
+	  android/flv.mk
+	  android/icydemux.mk
+	  android/id3demux.mk
+	  android/qtdemux.mk
+	  android/rtp.mk
+	  android/rtpmanager.mk
+	  android/rtsp.mk
+	  android/soup.mk
+	  android/udp.mk
+	  android/wavenc.mk
+	  android/wavparse.mk
+	  configure.ac
+
+2011-04-17 01:29:01 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix 'variable may be used uninitialized' warnings caused by -DG_DISABLE_ASSERT
+
+2011-04-16 18:50:11 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	* win32/common/gstrtpbin-marshal.c:
+	* win32/common/gstrtpbin-marshal.h:
+	  0.10.28.2 pre-release
+
+2011-04-16 18:49:27 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/deinterlace/tvtime-dist.c:
+	* gst/deinterlace/tvtime-dist.h:
+	* gst/videobox/gstvideoboxorc-dist.c:
+	* gst/videobox/gstvideoboxorc-dist.h:
+	* gst/videomixer/blendorc-dist.c:
+	* gst/videomixer/blendorc-dist.h:
+	  gst: update disted orc backup code
+
+2011-04-16 18:29:45 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* 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:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	  docs: update for pre-release
+
+2011-04-16 18:27:54 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/bg.po:
+	* po/cs.po:
+	* po/de.po:
+	* po/es.po:
+	* po/id.po:
+	* po/sl.po:
+	  po: update translations
+
+2011-04-16 18:17:01 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: refuse incomplete legacy h264 caps
+	  Refuse h264 caps without stream-format and codec_data fields for
+	  now, to avoid creating broken files. This might cause some pipelines
+	  that worked previously to fail. However, the move from -bad to -good
+	  is our only chance to fix this up, so make it strict for now. We can
+	  always change it back to be less strict in future.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=647919
+
+2011-04-16 18:16:11 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: fix another unused-but-set-variable warning
+
+2011-04-16 18:10:24 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* ext/speex/gstspeexenc.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	  pulse, speexenc, rtpgsmpay: don't use g_assert() for error handling
+	  Don't use g_assert() for error handling, even if they're highly unlikely.
+	  Either we *know* that something can't happen, in which case we
+	  should just not handle it, or we think something can happen, but it is
+	  very very unlikely that it will ever happen, in which case we should
+	  handle it like any other error instead of asserting.
+	  g_assert() is best left for conditions we have control of, like checking
+	  internal consistency of our code, not checking return values of external
+	  code.
+	  Fixes a bunch of warnings when compiling with -DG_DISABLE_ASSERT:
+	  gstrtpgsmpay.c: In function 'gst_rtp_gsm_pay_handle_buffer':
+	  gstrtpgsmpay.c:130:17: warning: variable 'rtpgsmpay' set but not used
+	  gstspeexenc.c: In function 'gst_speex_enc_encode':
+	  gstspeexenc.c:904:19: warning: variable 'written' set but not used
+	  pulsesink.c: In function 'gst_pulsesink_change_state':
+	  pulsesink.c:2725:9: warning: variable 'res' set but not used
+	  pulsesrc.c: In function 'gst_pulsesrc_change_state':
+	  pulsesrc.c:1253:7: warning: variable 'e' set but not used
+
+2011-04-16 18:07:35 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/examples/rtp/server-alsasrc-PCMA.c:
+	  examples: fix some warnings in rtp example
+	  Caused by -DG_DISABLE_ASSERT
+
+2011-04-16 17:57:32 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/examples/level/level-example.c:
+	  examples: don't put code with side-effects into g_assert()
+	  Otherwise things won't work too well when compiling with
+	  -DG_DISABLE_ASSERT (as we do for pre-releases and releases).
+
+2011-04-16 16:51:32 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/deinterlace/tvtime/greedyh.c:
+	* gst/matroska/matroska-mux.c:
+	  deinterlace, matroska: fix two variable-may-be-used-uninitialized compiler warnings
+	  We use -DG_DISABLE_ASSERT for the pre-releases, which makes these
+	  warnings pop up in cases that were previously covered by g_assert_not_reached()
+	  and the like:
+	  tvtime/greedyh.c:801:14: warning: 'scanline' may be used uninitialized in this function
+	  matroska-mux.c:501:19: warning: 'context' may be used uninitialized in this function
+
+2011-04-16 14:45:25 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/apetag/gstapedemux.c:
+	  apedemux: Port to 0.11
+
+2011-04-16 13:33:45 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: fix unused-but-set-variable warnings with gcc-4.6
+
+2011-04-16 13:23:50 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/examples/cairo/cairo_overlay.c:
+	  examples: fix 'control reaches end of non-void function' warning in cairo example
+
+2011-04-15 15:47:24 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: Address unused but set variable
+	  The v4l2object formats list was being obtained into a local variable and
+	  then still used from the context. Make use of the local variable.
+
+2011-04-15 15:17:34 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* sys/oss4/oss4-mixer-slider.c:
+	* sys/oss4/oss4-mixer-switch.c:
+	* sys/oss4/oss4-property-probe.c:
+	* sys/oss4/oss4-source.c:
+	  oss4: Address unused but set variables
+	  GCC 4.6.x complains about such variable usage. Unused but set variables
+	  were removed except that gst_oss4_mixer_slider_set_mute () now returns
+	  the value from the call to gst_oss4_mixer_set_control_val ().
+
+2011-04-15 15:14:13 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	* ext/pulse/pulsesink.c:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	  jpegenc: pulsesink: raw1394: Address unused but set variables
+	  GCC 4.6.x spits warnings about such usage of variables. The variables in
+	  raw1394 were marked with G_GNUC_UNUSED as this seemed omre appropriate.
+	  The others were removed.
+
+2011-04-15 15:12:44 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/y4m/gsty4mencode.c:
+	  y4mencode: shapewipe: Address unused but set variables
+	  GCC 4.6.x complains about such usage.
+
+2011-04-15 15:11:35 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* tests/check/elements/deinterlace.c:
+	* tests/check/elements/rtp-payloading.c:
+	* tests/check/pipelines/flacdec.c:
+	* tests/examples/level/level-example.c:
+	* tests/icles/videocrop-test.c:
+	* tests/icles/ximagesrc-test.c:
+	  tests: Address unused but set variables
+	  GCC 4.6.x spits warnings about such usage of variables.
+
+2011-04-15 15:36:41 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/videomixer/blendorc.orc:
+	  videomixer: Fix argb/rgba overlay orc code
+	  Remove some redundant operations (convubw) and use the correct variable,
+	  t2, in the orc_overlay_bgra function.
+
+2011-04-15 15:33:35 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/videomixer/blend.c:
+	* gst/videomixer/gstcollectpads2.c:
+	* gst/videomixer/videomixer2.c:
+	  videomixer: address unused but set variables
+	  GCC 4.6.x spits warnings about variables that are set but unused. Such
+	  variables have been removed in blend, collectpads2 and videomixer2.
+
+2011-04-15 14:57:20 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtp, rtpmanager: Address unused but set variables
+	  GCC 4.6.x spits warnings about variables that are unused but set. Such
+	  variables have been removed where trivial but with comments left behind
+	  for informational purposes in some cases.
+	  gst_rtp_session_chain_recv_rtcp () was changed in commit 490113d4
+	  to always return GST_FLOW_OK instead of the return value of
+	  rtp_session_process_rtcp (), so we'll keep it that way.
+
+2011-04-15 11:29:30 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/quicktime/descriptors.c:
+	* gst/quicktime/gstrtpxqtdepay.c:
+	* gst/quicktime/qtdemux.c:
+	  quicktime: Remove unused but set variables
+	  GCC 4.6.x spits warnings about such variable usage. Note that some
+	  calculations are left as comments for informative purposes.
+
+2011-04-15 11:23:38 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-parse.c:
+	  matroska: Remove unused but set variables
+	  GCC 4.6.x spits warnings about such variable usage.
+
+2011-04-15 11:19:26 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Remove unused but set duration variable
+	  GCC 4.6.x spits warnings about such variable usage.
+
+2011-04-15 11:18:19 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flxdemux: Remove unused but set keyframe variables
+	  The FIXMEs about the keyframe flag never being used are left for later
+	  fixing, at which point the keyframe variables could be added back.
+
+2011-04-15 11:16:42 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/effectv/gstedge.c:
+	  edgetv: Remove unused but set height variable
+	  GCC 4.6.x spits warnings about such variables.
+
+2011-04-15 18:51:20 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: update for gst_base_parse_frame_init() API change
+
+2011-02-01 15:57:01 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Use existing functions to parse RTCP FB packets
+	  Use existing functions to get the FCI from FB packets.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=622553
+
+2011-02-01 16:23:52 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin-marshal.list:
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: marshal GstBuffer as a MiniObject instead of a pointer
+	  https://bugzilla.gnome.org/show_bug.cgi?id=622553
+
+2011-04-14 23:24:56 -0700  David Schleef <ds@schleef.org>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Better calculation of framerate
+	  https://bugzilla.gnome.org/show_bug.cgi?id=647833
+
+2011-04-13 12:37:09 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: default to dts-method=reorder and presentation-time=true
+	  https://bugzilla.gnome.org/show_bug.cgi?id=636699
+
+2011-04-15 12:47:52 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/qtmux.c:
+	  tests: qtmux: test various dts-methods
+
+2011-04-15 12:34:05 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: fix corner case buffer handling for reorder method
+
+2011-04-14 13:47:05 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Don't leak the SEEKING query
+
+2011-04-14 13:43:06 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/quicktime/gstqtmoovrecover.c:
+	* gst/quicktime/gstqtmoovrecover.h:
+	  qtmoovrecover: Don't leak the static recursive mutex
+
+2011-04-14 13:37:52 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2radio.c:
+	  v4l2radio: Free videodev string before replacing it
+
+2011-04-14 13:24:21 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-parse.c:
+	  matroskaparse: Allow webm and matroska caps and don't leak caps
+
+2011-04-14 07:35:29 +0100  Christian Fredrik Kalager Schaller <christian.schaller@collabora.co.uk>
+
+	* gst-plugins-good.spec.in:
+	  Add parser plugin
+
+2011-04-13 21:58:36 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/Makefile.am:
+	* gst/dtmf/gstdtmfcommon.h:
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfdepay.h:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  dtmf: Move duplicate #defines into a common include
+	  Centralize duplicated constants so they have the same value.
+	  Also standardise minimum tone duration to 250ms and minimum inter-tone
+	  interval to 100ms.
+
+2011-03-24 14:34:24 -0700  David Schleef <ds@entropywave.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: Add conditionals on WAVE_FORMAT_DOLBY_AC3_SPDIF
+
+2011-04-11 20:09:14 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/debugutils/gstcapsdebug.c:
+	  capsdebug: fix unused-but-set-variable warnings with gcc 4.6
+
+2011-04-11 20:05:54 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix unused-but-set-variable warning with gcc 4.6
+	  Most likely a leftover from when the index parsing code was rewritten.
+
+2011-04-11 19:54:00 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: fix unused-but-set-variable warning with gcc 4.6
+
+2011-04-11 19:50:07 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: fix handling of YUV images with 'odd' widths
+	  Fixes unused-but-set-variable warnings with gcc 4.6.
+
+2011-04-11 19:49:22 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: fix unused-but-set-variable warnings with gcc 4.6
+
+2011-04-13 18:11:34 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiowsincband.c:
+	* gst/audiofx/audiowsinclimit.c:
+	  audiowsinc{band,limit}: Fix check for divison by zero
+
+2011-04-13 18:01:01 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiowsincband.c:
+	  audiowsincband: Fix range of kernel elements (lim -> lim-1)
+
+2011-04-13 18:00:44 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiowsinclimit.c:
+	  audiowsinclimit: Add some more braces to make the code more readable
+
+2011-04-11 18:40:30 -0500  Jordi Burguet-Castell <jordi.burguet-castell@ligo.org>
+
+	* gst/audiofx/audiowsinclimit.c:
+	  audiowsinclimit: Fix range of kernel elements (lim -> lim-1) in high/low-pass filters
+
+2011-04-13 17:49:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiowsincband.c:
+	  audiowsincband: Add new windowing functions: gaussian, cos and hann
+
+2011-04-11 18:41:43 -0500  Jordi Burguet-Castell <jordi.burguet-castell@ligo.org>
+
+	* gst/audiofx/audiowsinclimit.c:
+	  audiowsinclimimt: Add new windows to high/low-pass filters: gaussian, cosine, hann
+
+2011-04-13 16:47:05 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: set stream-format=byte-stream on h264 caps if there's no codec data
+	  https://bugzilla.gnome.org/show_bug.cgi?id=606662
+
+2011-04-13 16:37:07 +0100  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmuxmap.c:
+	  qtmux: restrict h264 some more to only accept AU-aligned AVC
+	  https://bugzilla.gnome.org/show_bug.cgi?id=606662
+
+2011-04-13 17:11:26 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: The VBRI header is always at offset 0x20, independent of MPEG version
+	  Also clean up advancing of the data pointer a bit.
+	  Fixes bug #647659.
+
+2011-04-13 15:18:11 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmuxmap.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/qtmux.c:
+	  qtmux: add variant-less video/quicktime to source pad template caps
+	  This is needed for automatic transcoding using encodebin. Our typefinder
+	  does not always add a variant to the found caps, and encodebin needs
+	  an *exact* match to the caps on the source pad template, so we need
+	  to add the variant-less video/quicktime caps to the template as well
+	  for encodebin to be able to find it. Add unit test for this as well.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=642879
+
+2011-04-13 16:17:41 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: Properly interprete the result of strcmp()
+
+2011-04-13 16:09:04 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: Don't store image tags inside the vorbiscomments and the flac metadata
+	  Instead only store them inside the flac metadata. There's
+	  no point in storing them twice and the flac metadata is
+	  still the official way to store image tags inside flac.
+
+2011-04-13 12:38:15 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/.gitignore:
+	* tests/check/pipelines/.gitignore:
+	  tests: ignore new qtmux-related test binaries
+
+2011-04-13 11:25:11 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* gst/quicktime/Makefile.am:
+	* gst/quicktime/gstqtmuxplugin.c:
+	* gst/quicktime/quicktime.c:
+	* tests/check/Makefile.am:
+	  quicktime: move qtmux plugin from -bad to -good
+	  https://bugzilla.gnome.org/show_bug.cgi?id=636699
+
+2011-04-12 16:42:17 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  dtmf: Remove leftover MAEMO_BROKEN defines
+	  Remove defines to work around bugs in old Maemo releases
+
+2011-04-04 12:21:23 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: more helpful debug error message when no needed duration on input buffers
+	  Fixes #646256.
+
+2011-03-21 10:56:51 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Adding GstTagXmpWriter interface
+	  Adds GstTagXmpWriter interface support to qtmux
+
+2011-03-22 20:53:08 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: use running time for synchronization
+	  See also #432612.
+
+2011-03-10 16:03:58 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: provide for PTS metadata when so configured
+	  ... and not only when sort-of feeling like it.
+	  In any case, if it turns out all really is in order,
+	  and presumably DTS == PTS, then no ctts will be produced anyway.
+
+2011-03-10 16:02:42 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: also track original PTS buffer timestamp in reorder dts-method
+
+2011-02-21 12:14:59 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  Revert "Check that collectpads exists before removing pad"
+	  This reverts commit 6d8740476ccd3a3498dc4f18c19733643825c7b8.
+	  Depends on a core commit that was reverted
+
+2011-02-20 23:57:19 -0800  David Schleef <ds@schleef.org>
+
+	* gst/quicktime/gstqtmux.c:
+	  Check that collectpads exists before removing pad
+	  The core now calls release pad from finalize, at which point
+	  the collectpads might have already been freed.
+
+2011-01-13 11:28:32 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* tests/check/elements/qtmux.c:
+	  test: qtmux: Tests qtmux reuse
+	  Forces the use of qtmux after it has been put to PLAYING and back
+	  to NULL once
+	  https://bugzilla.gnome.org/show_bug.cgi?id=639338
+
+2011-01-13 15:27:36 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: set src pads when starting file
+	  ... rather than at _init time, so they are also available following a
+	  pad (de)activation cycle.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=639338
+
+2011-01-03 17:24:23 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmux.h:
+	  qtmux: adjust nasty case timestamp tracking
+	  That is, all sorts of problems arise with re-ordered input timestamps that
+	  tend to defy automagic handling for every case, so allow for a few variations
+	  that can be tried depending on circumstances.
+	  Also try to document accordingly.
+	  Also fixes #638288.
+
+2010-12-30 21:48:41 +0200  Felipe Contreras <felipe.contreras@nokia.com>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: get rid of timestamp overprotectiveness
+	  Signed-off-by: Felipe Contreras <felipe.contreras@nokia.com>
+
+2011-01-03 16:56:57 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/atomsrecovery.c:
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: simplify and fix pts_offset storing
+	  In particular, only write a ctts atom if and only if ever a non-zero offset.
+
+2011-01-03 10:43:15 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: add some more documentation
+
+2010-12-03 15:23:00 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmux.h:
+	  qtmux: remove large-file property
+	  Rather, auto-determine if 64-bits fields are needed for a valid result, and
+	  stick to plain 32-bits if not needed.
+	  API: GstQTMux:large-file (removed)
+
+2010-12-19 12:53:34 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Free AtomInfo structs
+
+2010-12-19 12:50:30 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Free tag string after use
+
+2010-12-19 12:12:25 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/pipelines/tagschecking.c:
+	  tagschecking: Fix some more memory leaks
+
+2010-12-17 19:41:25 +0200  Lasse Laukkanen <lasse.laukkanen@digia.com>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: allow zero duration tracks
+
+2010-12-03 18:09:41 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: add documentation
+
+2010-12-01 10:45:49 +0100  David Hoyt <dhoyt@llnl.gov>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: handle msvc ftruncate incompatibility
+	  Fixes #636185.
+
+2010-11-27 16:07:19 -0600  Alejandro Gonzalez <agonzalez@dextratech.com>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: gst_qtmux_check_difference verify before subtract
+	  Avoid negative overflow by checking the order of operands
+	  on subtraction of unsigned integers.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=635878
+
+2010-11-19 17:55:36 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: remove remnant of obsolete property
+
+2010-11-19 15:18:58 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/qtmux.c:
+	  tests: qtmux: also unit test fragmented file cases
+
+2010-07-30 12:48:29 +0200  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmux.h:
+	  qtmux: allow specifying trak timescale
+	  This is mainly because Smoothstreaming client are broken and don't
+	  take the TimeScale property into account.
+
+2010-11-19 17:41:41 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: include sdtp atoms for ismv fragmented files
+	  Based on patch by Marc-André Lureau <mlureau@flumotion.com>
+
+2010-11-19 19:17:45 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: enable default fragmented file for ismlmux
+
+2010-09-02 13:58:05 +0200  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/ftypcc.h:
+	* gst/quicktime/gstqtmuxmap.c:
+	* gst/quicktime/gstqtmuxmap.h:
+	  qtmux: add ismlmux, for fragmented isml major brand
+
+2010-11-19 14:44:45 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: finalize sinkpads list
+
+2010-07-22 19:40:07 +0200  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: add moov in streamheader
+
+2010-08-06 13:26:27 +0200  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmux.h:
+	  qtmux: add streamable property to avoid building fragmented mfra index
+
+2010-11-18 16:48:06 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmux.h:
+	  qtmux: add mfra to fragmented file
+	  Based on patch by Marc-André Lureau <mlureau@flumotion.com>
+
+2010-11-15 15:17:59 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmux.h:
+	  qtmux: optionally create fragmented file
+	  In this mode, an initial empty moov (containing only stream metadata) is written,
+	  followed by fragments containing actual data (along with required metadata).
+	  New fragments are started either at keyframe (if such are sparse) or when
+	  property configured duration exceeded.
+	  Based on patch by Marc-André Lureau <mlureau@flumotion.com>
+	  Fixes #632911.
+
+2010-11-15 15:12:45 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	  qtmux: use helper to set atom flags from given uint
+
+2010-11-09 16:49:07 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: refactor configuring and sending of moov
+	  Based on patch by Marc-André Lureau <mlureau@flumotion.com>
+
+2010-11-09 15:54:44 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: refactor extra top-level atom handling
+	  Also check a bit more for possible errors, and free proper items in such case.
+
+2010-11-09 15:01:15 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: refactor slightly using buffer helper
+
+2010-11-05 13:48:57 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: fix misinforming comment
+
+2010-11-05 12:08:15 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: delegate mvex handling to atoms
+	  ... which keeps qtmux simpler.
+
+2009-09-28 16:11:35 +0200  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: add mvex/trex in header if fragmented
+	  One "trex" is added per "trak". We don't support default values,
+	  but the "trex" box is mandatory.
+
+2009-09-28 13:01:30 +0200  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/quicktime/fourcc.h:
+	  qtmux: add a couple of fourcc for fragmented mp4
+
+2010-11-05 11:08:01 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: avoid removing temp file when error occurred
+
+2009-09-30 17:16:30 +0200  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: truncate buffer file after each send
+
+2009-09-28 16:53:51 +0200  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: remove temp file when reset/finalize
+
+2010-10-19 13:43:14 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/quicktime/gstqtmoovrecover.c:
+	  various (gst): add missing G_PARAM_STATIC_STRINGS flags
+	  Canonicalize property names as needed.
+
+2010-10-13 17:47:29 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: prevent infinite loop when adjusting framerate
+	  Fixes #632070.
+
+2010-10-03 23:45:46 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Add G_PARAM_STATIC_STRINGS
+	  Add G_PARAM_STATIC_STRINGS to qtmux properties
+
+2010-09-15 17:54:49 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/fourcc.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmux.h:
+	  qtmux: Follow xmp serialization guidelines closer
+	  qt and isom variants have different ways of serializing
+	  xmp, follow these guidelines.
+	  Those can be found in Adobe's xmp docs.
+
+2010-08-16 12:36:24 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: autodetect out-of-order input timestamps and determine DTS accordingly
+	  Favour using input buffer timestamps for DTS, but fallback to using buffer
+	  duration (accumulation) if input ts detected out-of-order.
+	  Fixes #624212.
+
+2010-07-28 16:15:53 +0200  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: use caps bitrate at last chance
+	  If we didn't get the stream's bitrate from one of the atoms,
+	  try getting it from the caps as a last resort.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=625496
+
+2010-07-28 16:12:11 +0200  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/quicktime/atoms.c:
+	  qtmux: btrt - max bitrate before average
+	  According to iso base media file format, the max bitrate
+	  is before the avg
+	  https://bugzilla.gnome.org/show_bug.cgi?id=625496
+
+2010-07-06 14:48:08 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Write 'btrt' atom for H.264 media if possible
+	  This writes out the optional 'btrt' atom (MPEG4BitrateBox) for H.264
+	  media if either or both of average and maximum bitrate are available for
+	  the stream.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=623678
+
+2010-07-05 14:09:50 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmux.h:
+	  qtmux: Write avg/max bitrate to ESDS if available
+	  This collects the 'bitrate' and 'maximum-bitrate' tags on the
+	  corresponding pad and uses these to populate these fields in the ESDS
+	  where applicable.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=623678
+
+2010-07-02 12:45:20 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Don't use bogus codec/format tags
+	  https://bugzilla.gnome.org/show_bug.cgi?id=623365
+
+2010-06-25 20:19:20 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Write uint tags that don't have a complement
+	  Write uint tags that have complements (e.g. track-number/
+	  track-count) even when we only have one of them available
+	  and set the other one to 0.
+	  Fixes #622484
+
+2010-06-21 19:39:54 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Remove the pad from our internal list before calling collectpads
+	  Previously we would end up with the collectpaddata structure already freed.
+	  This would result in a bogus iteration of mux->sinkpads (all the
+	  GstQTPad being freed) and it wouldn't be removed from that list.
+	  Finally, due to it not being removed from that list, we would end up
+	  calling a bogus gst_qt_mux_pad_reset on those structures => SEGFAULT
+
+2010-05-12 18:50:34 -0700  David Schleef <ds@schleef.org>
+
+	* gst/quicktime/fourcc.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmuxmap.c:
+	  qtmux: Add VP8
+
+2010-05-11 13:15:37 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/pipelines/tagschecking.c:
+	  tests: don't fail tagschecking test if qtdemux is not available or too old
+
+2010-03-27 09:46:30 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/quicktime/gstqtmuxplugin.c:
+	  qtmux: use GStreamer package name and origin in the plugin info
+
+2010-03-23 17:34:30 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* tests/check/pipelines/tagschecking.c:
+	  tests: tagschecking: New tags tests
+	  Adds new tags checking tests.
+
+2010-03-25 00:20:54 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: init debug category before using it
+
+2010-03-22 16:56:03 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/quicktime/atoms.c:
+	  Add -Wold-style-definition
+	  and fix the warnings
+
+2010-03-22 13:16:33 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/gstqtmuxmap.h:
+	* tests/check/elements/qtmux.c:
+	  Add -Wwrite-strings
+	  and fix its warnings
+
+2010-03-21 21:39:18 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/atomsrecovery.c:
+	* gst/quicktime/descriptors.c:
+	* tests/check/elements/qtmux.c:
+	* tests/check/pipelines/tagschecking.c:
+	  Add -Wmissing-declarations -Wmissing-prototypes to configure flags
+	  And fix all warnings
+
+2010-03-18 17:30:26 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/quicktime/gstqtmoovrecover.c:
+	* gst/quicktime/gstqtmux.c:
+	  gst_element_class_set_details => gst_element_class_set_details_simple
+
+2010-03-12 11:28:51 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* tests/check/pipelines/tagschecking.c:
+	  tests: tagschecking: Improvements and new geo-location tests
+	  Makes some improvements to tagschecking.c, making it use
+	  fakesrc instead of videotestsrc and allowing to set input
+	  caps so that more muxers can be used. Previously we could
+	  only use those that accepted raw video caps.
+	  Also adds some tests for geo-location tags
+
+2010-03-12 10:53:36 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Use xmp on mp4mux and gppmux too
+	  Do not restrict xmp to qtmux, but use it too
+	  on mp4mux and gppmux
+
+2010-03-05 13:33:37 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* tests/check/pipelines/tagschecking.c:
+	  check: tagschecking: tests for tags serialization in muxers
+	  Adds a check unit test that aims to test tags serialization
+	  and deserialization consistency (in muxers). It provides a
+	  basic function that allows one to easily specify tags, a
+	  muxer and a demuxer and a test will be done to check if
+	  the tags have been consistently muxed and demuxed
+
+2010-02-22 16:45:34 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/fourcc.h:
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: add xmp support
+	  Adds xmp metatags adding to qtmux.
+	  Fixes #609539
+
+2010-03-11 17:17:15 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/quicktime/gstqtmoovrecover.c:
+	  qtmux: fix GST_ELEMENT_ERROR usage
+	  We need to pass (NULL) rather than NULL for empty arguments.
+
+2010-03-10 10:23:23 -0600  Rob Clark <rob@ti.com>
+
+	* gst/quicktime/gstqtmoovrecover.c:
+	  qtmux: fix compile error
+	  gst/quicktime/gstqtmoovrecover.c:268: warning: format not a string literal and no format arguments
+	  https://bugzilla.gnome.org/show_bug.cgi?id=612454
+
+2010-02-22 19:38:15 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/gstqtmuxmap.c:
+	  qtmux: Rename 'avc-sample' to 'avc' in caps
+	  Fixes #606662
+
+2010-02-26 11:50:25 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Take lock around use of (non-threadsafe) tagsetter interface.
+
+2010-02-22 16:51:00 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	  qtmux: write all udta children atoms
+	  UDTA might have META and other children atoms
+	  together, write them all.
+
+2010-02-22 10:48:11 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmux.h:
+	  qtmux: Use internal sink pads list
+	  Due to GstCollectPads sink pads list being not reliably
+	  iteratable (when not inside the collected function) this
+	  patch adds a sink pads list to qtmux to be used when iterating
+	  sink pads on reset function.
+	  Fixes #609055
+
+2010-02-16 17:13:09 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	  qtmux: prevent leaking hdlr name
+
+2010-02-16 16:24:12 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmuxmap.c:
+	  qtmux: support for ALAC
+	  Fixes #580731.
+
+2010-02-16 14:19:04 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	  qtmux: refactor building stsd entry 'wave' extension
+
+2010-02-08 11:51:52 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/atomsrecovery.c:
+	  qtmux: atomsrecovery: Fix compilation problem
+	  Fixes a compilation error due to unused function result.
+
+2009-12-12 16:07:15 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/atomsrecovery.c:
+	* gst/quicktime/atomsrecovery.h:
+	* gst/quicktime/fourcc.h:
+	* gst/quicktime/gstqtmoovrecover.c:
+	* gst/quicktime/gstqtmoovrecover.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmux.h:
+	* gst/quicktime/gstqtmuxplugin.c:
+	  qtmux: Adds moov recovery feature
+	  Adds a new property to qtmux that sets a path to a file to write
+	  and update data about the moov atom (that is not writen till the
+	  end of the file). If the pipeline/app crashes during execution it
+	  might be possible to recover the movie using the qtmoovrecover element.
+	  qtmoovrecover is an element that is also a pipeline. It is not
+	  meant to be used with other elements (it has no pads). It is merely
+	  a tool/utilitary to recover unfinished qtmux files.
+	  Fixes #601576
+
+2010-01-27 19:06:53 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/quicktime/atoms.c:
+	  qtmux: for fixed-sample size streams (PCM audio, etc) don't allocate an enormous buffer that we then won't use at all.
+
+2010-01-27 15:37:37 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: handle muxing adpcm correctly.
+
+2010-01-22 13:36:04 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/quicktime/atoms.c:
+	  qtmux: Set the mdia hdlr name field to what quicktime uses. Fix writing it since it's not null-terminated. Improves compatibility with some hardware players.
+
+2010-01-22 13:30:07 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: endianness in gstreamer is an int, not boolean.
+
+2010-01-26 17:54:28 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	  qtmux: streamline moov data memory storage
+	  In particular, use arrays rather than (double) linked lists.
+
+2010-01-26 13:44:04 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: g_free is NULL safe
+
+2010-01-20 13:30:48 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/quicktime/descriptors.c:
+	* gst/quicktime/descriptors.h:
+	* gst/quicktime/properties.c:
+	  [cleanup] Various style and cleanups
+	  Various fixes for gtk-doc warnings and making functions without
+	  arguments take void as parameter.
+
+2010-01-14 08:09:03 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Actually use new caps info on renegotiation
+	  Following the previous qtmux commit, this patch tries
+	  to use the new info added to the caps to fill the 'trak'
+	  atom's fields and children atoms. This way qtmux will
+	  use the late added 'codec_data' when h264parse adds
+	  it in the following pipeline:
+	  videotestsrc num-buffers=200 ! x264enc byte-stream=true ! \
+	  h264parse output-format=0 ! qtmux ! \
+	  filesink location=test.mov
+
+2010-01-13 23:33:51 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Do caps renegotiation when it only adds fields
+	  Qtmux can accept caps renegotiation if the new caps is a
+	  superset of the old one, meaning upstream added new info to
+	  the caps. This patch still doesn't make qtmux update any
+	  atoms info from the new info, but at least it doesn't
+	  reject the new caps anymore.
+	  A pipeline that reproduces this use case is:
+	  videotestsrc num-buffers=200 ! x264enc byte-stream=true ! \
+	  h264parse output-format=0 ! qtmux ! \
+	  filesink location=test.mov
+
+2010-01-13 19:30:45 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: provide request pads under wider conditions
+	  Fixes #606859.
+
+2010-01-13 10:35:00 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/gstqtmuxmap.c:
+	  qtmux: Only accept avc-sample h264
+	  qtmux and mp4mux should only accept h264 in avc-sample
+	  format
+
+2010-01-11 13:13:41 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmuxmap.c:
+	  Rename aac's stream-format 'none' to 'raw'
+	  Renames aac's stream-format from previous commits from none to
+	  raw
+
+2010-01-11 10:34:32 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmuxmap.c:
+	  qtmux: Only accept stream-format='none' aac
+	  Only accept raw aac streams (stream-format=none) to avoid
+	  generating invalid files.
+	  Fixes #604925
+
+2009-12-28 11:34:35 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/quicktime/gstqtmux.h:
+	  qtmux: also add .h file changes to unbreak the build
+
+2009-12-27 23:51:50 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: use correct names from template for request pads
+	  The pads where names pad0, pad1, ...
+
+2009-12-27 23:32:58 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: move errors _new_pad to the end
+
+2009-12-21 13:58:30 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Accept non-paired uint tags
+	  Adds support for unpaired unsigned interger tags
+
+2009-12-21 12:05:37 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/fourcc.h:
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Adds new tags
+	  Maps more tags that are already posted by qtdemux
+	  Fixes #599759
+
+2009-12-10 22:20:45 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/fourcc.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmux.h:
+	* gst/quicktime/gstqtmuxmap.c:
+	  qtmux: support more of j2k
+	  Reads the new caps added to qtdemux by commit
+	  c917d65e6df0b5d585f905c7ad78a8a0a44b2cb0
+	  and adds its corresponding atoms.
+	  Also adds support for image/x-jpc as it is the same
+	  as image/x-jp2, except that the buffers need to be
+	  boxed inside a jp2c isom box before muxing. To solve
+	  this the QTPads now have a function that (if
+	  not NULL) is called when a buffer is collected. This
+	  function returns a replacement to the current collected
+	  buffer.
+	  Fixes #598916
+
+2009-12-10 16:53:19 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/fourcc.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmux.h:
+	  qtmux: Maps 'classification' tag for 3gpp files
+	  Adds the mapping of 'classification' tags to writing of
+	  'clsf' atoms for gppmux.
+	  Based on a patch by: Lasse Laukkanen <ext-lasse.2.laukkanen@nokia.com>
+
+2009-12-08 17:59:04 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: remove c++ comments and add some more comments.
+
+2009-12-08 17:55:56 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/fourcc.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmuxmap.c:
+	  qtmux: add ima adpcm support
+
+2009-11-25 21:41:27 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: replace _scale with _scale_round
+	  Use the rounding version for improved sync between streams.
+	  Small variations in the duration when muxing might lead to
+	  cumullative wrong timestamping when demuxing.
+	  Fixes #602936
+
+2009-11-24 16:16:56 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: use timestamps for muxing
+	  Try to use timestamps even when the stream has out of order
+	  timestamps, only fall back to durations when we detect an
+	  out of order buffer. Improves sync between streams.
+
+2009-11-19 18:28:52 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: fix missing debug argument
+	  Adds a missing debug argument
+
+2009-11-19 11:36:14 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: fix misinforming debug statement
+
+2009-11-19 11:14:57 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: ensure writable buffer metadata before setting caps
+
+2009-10-29 08:36:02 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/fourcc.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmuxmap.c:
+	  qtmux: support for SVQ3
+	  Adds support for muxing SVQ3 content. Usually this format
+	  has decoder info that must be passed in the 'seqh' field
+	  in the caps. It is also good to add the gama atom to make
+	  quicktime not crash.
+	  Fixes #587922
+
+2009-11-17 09:26:05 -0300  Thiago Sousa Santos <thiagoss@redmoon.(none)>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: do not leak a string
+	  Frees a string after use. Also does some code organization
+
+2009-11-16 14:57:53 -0300  Thiago Sousa Santos <thiagoss@redmoon.(none)>
+
+	* gst/quicktime/atoms.c:
+	  qtmux: do not add size to the pointer variable
+	  Do not wrongly add the result of the function to the
+	  pointer to the buffer size. Instead, check the result
+	  to see if the serialization was ok.
+	  Based on a patch by: "Carsten Kroll <car@ximidi.com>"
+	  Fixes #602106
+
+2009-11-06 10:34:39 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmux.h:
+	  qtmux: handle 'late' streams
+	  When muxing streams, some can start later than others. qtmux
+	  now handle this by adding an empty edts entry with the
+	  duration of the 'lateness' to the stream's trak.
+	  It tolerates a stream to be up to 0.1s late.
+	  Fixes #586848
+
+2009-11-05 21:35:56 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	  qtmux: adds the EDTS and ELTS atoms to atoms.c
+	  These atoms will be useful for signaling streams
+	  that start later in the file. As well for adding
+	  edit lists if needed sometime later.
+
+2009-11-06 00:46:12 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Adding some ifs for protection
+	  Adding somes ifs to protect against warning conditions
+	  that might happen when upstream element is not sane
+	  Fixes #600895
+
+2009-10-16 10:47:32 -0300  Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+
+	* gst/quicktime/ftypcc.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmux.h:
+	* gst/quicktime/gstqtmuxmap.c:
+	* gst/quicktime/gstqtmuxmap.h:
+	  gppmux: Add support for 3gr6
+	  Keep track of the chunk durations to be able to add 3gr6
+	  brand if it is a faststart file and the longest chunk is
+	  smaller than a sec. Implemented according to 3gpp
+	  TS 26.244 v6.4.0 (2005-09)
+	  Fixes #584361
+
+2009-10-15 21:11:16 -0300  Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Only push ftyp later (in faststart mode)
+	  In faststart mode, there is no need to send the ftyp
+	  right at the beginning of the stream. Waiting and sending it
+	  only later (when the moov atom is ready to be sent) provides
+	  us with more information about the stream and we can better
+	  select the compatible brands.
+
+2009-10-15 17:51:39 -0300  Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Improve error message
+	  Improve error message when we can't get or estimate the
+	  timestamp/duration of a buffer
+
+2009-09-29 15:47:13 +0200  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/quicktime/atoms.c:
+	  qtmux: fix flags_as_uint to flags[]
+
+2009-08-04 12:58:35 +0200  Jan Urbanski <wulczer@wulczer.org>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Don't require endianness field for 8 bit raw audio
+	  Fixes bug #590360.
+
+2009-06-25 08:38:21 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/quicktime/atoms.c:
+	  qtmux: Remove unused variable.
+
+2009-06-25 08:38:10 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Fix debug statement.
+
+2009-06-11 15:54:42 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmux.h:
+	  qtmux: only use (64-bit) extended (mdat) atom size if needed.  Fixes #585319.
+
+2009-06-10 14:46:14 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: set default movie timescale to microsecond units
+
+2009-06-10 13:24:20 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	  qtmux: compress/optimize stsc writing
+
+2009-06-10 12:42:44 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/fourcc.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmuxmap.c:
+	  qtmux: add 3GP style tagging (and refactor appropriately)
+
+2009-06-01 23:00:44 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/fourcc.h:
+	* gst/quicktime/gstqtmux.c:
+	  qtmux (and variants): handle pixel-aspect-ratio.  Fixes #584358.
+
+2009-06-01 22:42:08 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/ftypcc.h:
+	* gst/quicktime/gstqtmuxmap.c:
+	  gppmux: enhance ftyp brand heuristic.  Fixes #584360.
+
+2009-05-28 13:56:10 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/fourcc.h:
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: use different stsd atom type for H263 for ISO and QT variants
+	  Fixes #584114.
+
+2009-05-15 01:54:44 -0300  Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+
+	* gst/quicktime/atoms.c:
+	  [qtmux] Fixes segfault when adding a blob as first tag.
+	  Moves tags data initialization to the function that actually appends
+	  the tags to the list. Fixes #582702
+	  Also fixes some style caught by the pre-commit hook.
+
+2009-05-10 21:21:36 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmuxmap.c:
+	  gppmux: Add MPEG-4 part 2 to supported formats.  Fixes #581593.
+
+2009-05-07 17:53:42 +0100  Christian Schaller <christian.schaller@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  Add ranks to various muxers and encoders in -bad
+
+2009-04-30 14:43:36 -0300  Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+
+	* gst/quicktime/gstqtmuxmap.c:
+	  qtmux: changes caps of src pads to video/quicktime, variant=something
+	  Take a look at bug #580005 for further info.
+
+2009-04-24 18:53:36 -0300  Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+
+	* gst/quicktime/gstqtmuxmap.c:
+	  mp4mux: Changes src caps to application/x-iso-mp4
+	  Fixes #580005
+
+2009-03-25 21:24:44 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: fix reusing element
+	  State change to READY and then back to PAUSED should still provide
+	  the proper structures as are otherwise freshly available following
+	  a request_new_pad.
+	  Pointed out by Thiago Santos.
+
+2009-03-23 11:17:39 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: fix includes for lseek
+	  --
+
+2009-03-20 14:20:16 +0100  LRN <lrn1986 at gmail dot com>
+
+	* gst/quicktime/gstqtmux.c:
+	  win32: fix seeking in large files
+	  Use _lseeki64() on Windows to seek in large files.
+	  Fixes #576021.
+
+2009-03-02 10:57:35 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/quicktime/gstqtmux.c:
+	  qtmux: Be a bit more verbose in our debug message when failing to renegotiate
+
+2009-01-28 13:25:14 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/quicktime/atoms.c:
+	* gst/quicktime/atoms.h:
+	* gst/quicktime/gstqtmux.c:
+	* gst/quicktime/gstqtmuxmap.c:
+	  Additional media type support in qtmux (and friends).
+	  Support AMR and H263 for both qtmux and gppmux,
+	  and add extensions in sample table description.
+
+2009-01-09 21:59:48 +0000  David Schleef <ds@schleef.org>
+
+	  gst/quicktime/gstqtmuxmap.c: Add video/x-qt-part and video/x-m4-part to caps so schroenc/schroparse can use it.  Fixes #5...
+	  Original commit message from CVS:
+	  * gst/quicktime/gstqtmuxmap.c: Add video/x-qt-part and video/x-m4-part
+	  to caps so schroenc/schroparse can use it.  Fixes #566958
+
+2008-12-19 18:53:47 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/quicktime/gstqtmux.c: Do not tempt or suggest to violate gst_collect_pads API specification.
+	  Original commit message from CVS:
+	  * gst/quicktime/gstqtmux.c: (gst_qt_mux_change_state):
+	  Do not tempt or suggest to violate gst_collect_pads API specification.
+
+2008-12-19 18:33:47 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/quicktime/: Dual license qtmux LGPL/MIT.  Fixes #564232.
+	  Original commit message from CVS:
+	  * gst/quicktime/atoms.c:
+	  * gst/quicktime/atoms.h:
+	  * gst/quicktime/descriptors.c:
+	  * gst/quicktime/descriptors.h:
+	  * gst/quicktime/fourcc.h:
+	  * gst/quicktime/ftypcc.h:
+	  * gst/quicktime/gstqtmux.c:
+	  * gst/quicktime/gstqtmux.h:
+	  * gst/quicktime/gstqtmuxmap.c:
+	  * gst/quicktime/gstqtmuxmap.h:
+	  * gst/quicktime/properties.c:
+	  * gst/quicktime/properties.h:
+	  Dual license qtmux LGPL/MIT.  Fixes #564232.
+
+2008-12-16 16:26:52 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Totally remove the internal taglists and fully use tagsetter. Fixes various tag muxing issues.
+	  Original commit message from CVS:
+	  * ext/celt/gstceltenc.c:
+	  * ext/celt/gstceltenc.h:
+	  * ext/metadata/gstmetadatamux.c:
+	  * gst/quicktime/gstqtmux.c:
+	  * gst/quicktime/gstqtmux.h:
+	  Totally remove the internal taglists and fully use tagsetter. Fixes
+	  various tag muxing issues.
+
+2008-12-01 16:37:45 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/quicktime/atoms.c: Fix mj2 sample description metadata construction.
+	  Original commit message from CVS:
+	  * gst/quicktime/atoms.c: (build_jp2h_extension):
+	  Fix mj2 sample description metadata construction.
+
+2008-11-18 01:09:09 +0000  David Schleef <ds@schleef.org>
+
+	  gst/quicktime/gstqtmux.c: Quiet a debugging message that I recently added.
+	  Original commit message from CVS:
+	  * gst/quicktime/gstqtmux.c: Quiet a debugging message that I recently
+	  added.
+
+2008-11-15 02:56:31 +0000  David Schleef <ds@schleef.org>
+
+	  gst/quicktime/gstqtmux.*: Use dts from GST_BUFFER_OFFSET_END() for video/x-qt-part.
+	  Original commit message from CVS:
+	  * gst/quicktime/gstqtmux.c:
+	  * gst/quicktime/gstqtmux.h:
+	  Use dts from GST_BUFFER_OFFSET_END() for video/x-qt-part.
+
+2008-11-14 21:24:51 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/quicktime/: Revert previous commit.
+	  Original commit message from CVS:
+	  * gst/quicktime/atoms.c:
+	  * gst/quicktime/atoms.h:
+	  * gst/quicktime/descriptors.c:
+	  * gst/quicktime/descriptors.h:
+	  * gst/quicktime/fourcc.h:
+	  * gst/quicktime/ftypcc.h:
+	  * gst/quicktime/gstqtmux.c:
+	  * gst/quicktime/gstqtmux.h:
+	  * gst/quicktime/gstqtmuxmap.c:
+	  * gst/quicktime/gstqtmuxmap.h:
+	  * gst/quicktime/properties.c:
+	  * gst/quicktime/properties.h:
+	  Revert previous commit.
+
+2008-11-14 20:38:18 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/quicktime/: Dual license LGPL/MIT, as apparently supposed to.
+	  Original commit message from CVS:
+	  * gst/quicktime/atoms.c:
+	  * gst/quicktime/atoms.h:
+	  * gst/quicktime/descriptors.c:
+	  * gst/quicktime/descriptors.h:
+	  * gst/quicktime/fourcc.h:
+	  * gst/quicktime/ftypcc.h:
+	  * gst/quicktime/gstqtmux.c:
+	  * gst/quicktime/gstqtmux.h:
+	  * gst/quicktime/gstqtmuxmap.c:
+	  * gst/quicktime/gstqtmuxmap.h:
+	  * gst/quicktime/properties.c:
+	  * gst/quicktime/properties.h:
+	  Dual license LGPL/MIT, as apparently supposed to.
+
+2008-11-14 20:17:10 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/quicktime/: Cut detour in sample description extension construction.
+	  Original commit message from CVS:
+	  * gst/quicktime/atoms.c: (build_esds_extension),
+	  (build_mov_aac_extension), (build_jp2h_extension),
+	  (build_codec_data_extension):
+	  * gst/quicktime/atoms.h:
+	  * gst/quicktime/fourcc.h:
+	  * gst/quicktime/gstqtmux.c: (gst_qt_mux_audio_sink_set_caps),
+	  (gst_qt_mux_video_sink_set_caps):
+	  * gst/quicktime/gstqtmuxmap.c: (gst_qt_mux_map_format_to_header):
+	  Cut detour in sample description extension construction.
+	  Also actually implement ISO JPEG2000 mj2 format.
+
+2008-11-11 19:31:35 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  tests/check/: Add unit test for qtmux.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/qtmux.c: (setup_src_pad),
+	  (teardown_src_pad), (setup_qtmux), (cleanup_qtmux),
+	  (check_qtmux_pad), (GST_START_TEST), (qtmux_suite), (main):
+	  Add unit test for qtmux.
+
+2008-11-11 19:24:12 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/quicktime/gstqtmux.c: Add some more safety/sanity checks in tag manipulation.
+	  Original commit message from CVS:
+	  * gst/quicktime/gstqtmux.c: (gst_qt_mux_add_metadata_tags):
+	  Add some more safety/sanity checks in tag manipulation.
+
+2008-11-08 02:00:58 +0000  Thiago Sousa Santos <thiagossantos@gmail.com>
+
+	  Copy qtmux from revision 148 of the gst-qtmux repository.
+	  Original commit message from CVS:
+	  patch by: Thiago Sousa Santos <thiagossantos@gmail.com>
+	  * configure.ac:
+	  * gst/quicktime/Makefile.am:
+	  * gst/quicktime/atoms.c:
+	  * gst/quicktime/atoms.h:
+	  * gst/quicktime/descriptors.c:
+	  * gst/quicktime/descriptors.h:
+	  * gst/quicktime/fourcc.h:
+	  * gst/quicktime/ftypcc.h:
+	  * gst/quicktime/gstqtmux.c:
+	  * gst/quicktime/gstqtmux.h:
+	  * gst/quicktime/gstqtmuxmap.c:
+	  * gst/quicktime/gstqtmuxmap.h:
+	  * gst/quicktime/properties.c:
+	  * gst/quicktime/properties.h:
+	  Copy qtmux from revision 148 of the gst-qtmux repository.
+	  Fixes #550280.
+
+2011-04-12 18:25:34 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* Android.mk:
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* gst/quicktime/LEGAL:
+	* gst/quicktime/Makefile.am:
+	* gst/quicktime/gstrtpxqtdepay.c:
+	* gst/quicktime/gstrtpxqtdepay.h:
+	* gst/quicktime/qtatomparser.h:
+	* gst/quicktime/qtdemux.c:
+	* gst/quicktime/qtdemux.h:
+	* gst/quicktime/qtdemux.vcproj:
+	* gst/quicktime/qtdemux_dump.c:
+	* gst/quicktime/qtdemux_dump.h:
+	* gst/quicktime/qtdemux_fourcc.h:
+	* gst/quicktime/qtdemux_lang.c:
+	* gst/quicktime/qtdemux_lang.h:
+	* gst/quicktime/qtdemux_types.c:
+	* gst/quicktime/qtdemux_types.h:
+	* gst/quicktime/qtpalette.h:
+	* gst/quicktime/quicktime.c:
+	* po/POTFILES.in:
+	  qtdemux: rename directory to quicktime to match plugin name
+	  In preparation for qtmux moving to -good.
+
+2011-04-12 11:49:54 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: simplify framerate fraction calculation
+
+2011-01-24 15:45:28 -0600  Leonardo Sandoval <lsandoval@ti.com>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	  flvdemux: add width, height and framerate to caps when present on onMetaData
+	  Fixes #640483.
+
+2010-08-24 13:57:55 +0200  Pascal Buhler <pascal.buhler@tandberg.com>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Unknown SSRC is not fatal
+	  https://bugzilla.gnome.org/show_bug.cgi?id=646966
+
+2010-08-24 13:54:58 +0200  Pascal Buhler <pascal.buhler@tandberg.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Number of active sources should be updated whenever the status of the source changes to active
+	  Forward-ported by Olivier Crête
+	  https://bugzilla.gnome.org/show_bug.cgi?id=646965
+
+2010-06-23 11:29:58 +0200  Havard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpmanager: ignore a BYE if it is sent with our internal SSRC
+	  https://bugzilla.gnome.org/show_bug.cgi?id=646964
+
+2010-01-29 09:49:48 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Adds more h264 fields to its caps
+	  Adds alignment=au and stream-format=avc to h264 caps
+	  Fixes #606662
+
+2011-04-11 12:44:19 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* configure.ac:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: also handle deprecations for jack 1.9.7
+	  Jack 1.9.7 was released 20.Mar.2011, need to handle the deprecated api for this
+	  version too.
+
+2011-04-11 00:36:35 -0400  Thibault Saunier <thibault.saunier@collabora.co.uk>
+
+	* gst/dtmf/Makefile.am:
+	  android: make it ready for androgenizer
+	  Remove the android/ top dir
+	  Fixe the Makefile.am to be androgenized
+	  To build gstreamer for android we are now using androgenizer which generates the needed Android.mk files.
+	  Androgenizer can be found here: http://git.collabora.co.uk/?p=user/derek/androgenizer.git
+
+2011-04-10 18:56:52 -0400  Thibault Saunier <thibault.saunier@collabora.co.uk>
+
+	* Android.mk:
+	* android/NOTICE:
+	* android/apetag.mk:
+	* android/avi.mk:
+	* android/flv.mk:
+	* android/gst/rtpmanager/gstrtpbin-marshal.c:
+	* android/gst/rtpmanager/gstrtpbin-marshal.h:
+	* android/gst/udp/gstudp-enumtypes.c:
+	* android/gst/udp/gstudp-enumtypes.h:
+	* android/gst/udp/gstudp-marshal.c:
+	* android/gst/udp/gstudp-marshal.h:
+	* android/icydemux.mk:
+	* android/id3demux.mk:
+	* android/qtdemux.mk:
+	* android/rtp.mk:
+	* android/rtpmanager.mk:
+	* android/rtsp.mk:
+	* android/soup.mk:
+	* android/udp.mk:
+	* android/wavenc.mk:
+	* android/wavparse.mk:
+	* gst/alpha/Makefile.am:
+	* gst/apetag/Makefile.am:
+	* gst/audiofx/Makefile.am:
+	* gst/auparse/Makefile.am:
+	* gst/autodetect/Makefile.am:
+	* gst/avi/Makefile.am:
+	* gst/cutter/Makefile.am:
+	* gst/debugutils/Makefile.am:
+	* gst/deinterlace/Makefile.am:
+	* gst/effectv/Makefile.am:
+	* gst/equalizer/Makefile.am:
+	* gst/flv/Makefile.am:
+	* gst/flx/Makefile.am:
+	* gst/goom/Makefile.am:
+	* gst/goom2k1/Makefile.am:
+	* gst/icydemux/Makefile.am:
+	* gst/id3demux/Makefile.am:
+	* gst/imagefreeze/Makefile.am:
+	* gst/interleave/Makefile.am:
+	* gst/law/Makefile.am:
+	* gst/level/Makefile.am:
+	* gst/matroska/Makefile.am:
+	* gst/monoscope/Makefile.am:
+	* gst/multifile/Makefile.am:
+	* gst/multipart/Makefile.am:
+	* gst/qtdemux/Makefile.am:
+	* gst/replaygain/Makefile.am:
+	* gst/rtp/Makefile.am:
+	* gst/rtpmanager/Makefile.am:
+	* gst/rtsp/Makefile.am:
+	* gst/shapewipe/Makefile.am:
+	* gst/smpte/Makefile.am:
+	* gst/spectrum/Makefile.am:
+	* gst/udp/Makefile.am:
+	* gst/videobox/Makefile.am:
+	* gst/videocrop/Makefile.am:
+	* gst/videofilter/Makefile.am:
+	* gst/videomixer/Makefile.am:
+	* gst/wavenc/Makefile.am:
+	* gst/wavparse/Makefile.am:
+	* gst/y4m/Makefile.am:
+	  android: Make it ready for androgenizer
+	  Remove the android/ top dir
+	  Fixe the Makefile.am to be androgenized
+	  To build gstreamer for android we are now using androgenizer which generates the needed Android.mk files.
+	  Androgenizer can be found here: http://git.collabora.co.uk/?p=user/derek/androgenizer.git
+
+2011-04-05 21:14:43 +0200  Haakon Sporsheim <haakon.sporsheim@gmail.com>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  rtpgstpay: declare frag_offset to hold 32bits.
+	  As specified in documenation above and below.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=646954
+
+2011-04-09 12:41:48 +0200  Havard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: fix wrongly applied patch
+	  Obviously recv_rtp_sink does not have much to do with send_rtcp_src...
+	  See commit 046ff170.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=647263
+
+2011-04-08 15:59:58 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  audioparsers: update for set_frame_props -> set_frame_rate API change
+
+2011-04-08 00:03:21 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	  tests: hook up audioparser unit tests
+
+2011-04-07 18:30:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: relax sync match a bit when draining
+	  ... to at least allow initial caps change (but no further caps jitter).
+	  Fixes unit test again after previous change.
+
+2011-04-07 15:21:10 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* 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:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	  docs: update for changes in git
+
+2011-04-07 15:20:19 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/inspect/plugin-audioparsers.xml:
+	  docs: add audioparsers to docs
+
+2011-04-07 15:07:15 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstaacparse.h:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstamrparse.h:
+	* gst/audioparsers/plugin.c:
+	  aacparse, amrparse: gst_fooparse_xyz -> gst_foo_parse_xyz to match GstFooParse
+	  See moving-plugins checklist.
+
+2011-04-07 14:43:42 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* gst/audioparsers/Makefile.am:
+	* gst/audioparsers/plugin.c:
+	  audioparsers: hook up to build
+
+2011-04-07 13:26:41 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/Makefile.am:
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstaacparse.h:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstac3parse.h:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstamrparse.h:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstdcaparse.h:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstflacparse.h:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstmpegaudioparse.h:
+	  audioparsers: port to new GstBaseParse in core
+
+2011-04-04 20:55:39 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: require tighter sync match when draining
+
+2011-04-01 14:47:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstmpegaudioparse.h:
+	  mpegaudioparse: Parse encoder delay and encoder padding from the LAME header if present
+
+2011-03-09 23:06:14 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/audioparsers/plugin.c:
+	  dcaparse: Bump rank to primary+1
+	  Seems to work fine with a reasonably wide range of media, so bumping
+	  rank.
+
+2011-03-23 22:02:37 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstdcaparse.h:
+	  dcaparse: Expose frame size in caps
+	  This exports the size of the frame (number of bytes from one sync point
+	  to the next) as the "frame_size" field in caps.
+
+2011-03-09 23:03:10 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstdcaparse.h:
+	  dcaparse: Expose block size in caps
+	  This sets the "block_size" field on caps as the number of samples
+	  encoded in one frame.
+
+2011-03-16 15:53:13 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: add FIXME for making the base class use xing seek tables better
+
+2011-03-14 18:25:25 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstdcaparse.h:
+	  dcaparse: Add depth and endianness to the caps
+	  Some decoders can only handle specific endianness or a fixed
+	  depth and this allows better negotiation.
+	  Fixes bug #644208.
+
+2011-02-26 13:53:44 -0800  David Schleef <ds@schleef.org>
+
+	* gst/audioparsers/gstaacparse.c:
+	  Revert "aacparse: allow parsed frames on sink pad"
+	  This reverts commit e49b89d5c5a1244fa0dcb8bb4996e38fb9bff9e5.
+
+2011-02-23 17:25:03 -0800  David Schleef <ds@schleef.org>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: allow parsed frames on sink pad
+
+2010-10-13 16:12:02 -0700  David Schleef <ds@schleef.org>
+
+	* tests/check/elements/parser.c:
+	  tests: fix baseparse test
+
+2010-10-13 15:39:55 -0700  David Schleef <ds@schleef.org>
+
+	* gst/audioparsers/Makefile.am:
+	* gst/audioparsers/gstaacparse.h:
+	* gst/audioparsers/gstac3parse.h:
+	* gst/audioparsers/gstamrparse.h:
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	* gst/audioparsers/gstdcaparse.h:
+	* gst/audioparsers/gstflacparse.h:
+	* gst/audioparsers/gstmpegaudioparse.h:
+	  baseparse: Create baseparse library
+
+2011-02-07 14:46:57 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: tune QUERY_SEEKING response
+	  Even if we currently do not have a duration yet, assume seekable if
+	  it looks like we'll likely be able to determine it later on
+	  (which coincides with needed information to perform seeking).
+	  Fixes #641047.
+
+2011-02-08 23:39:24 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: Update min/max bitrate before first posting them
+	  This avoids posting an initial min-bitrate of G_UINTMAX and max-bitrate
+	  of 0.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=641857
+
+2011-02-08 23:50:13 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstmpegaudioparse.h:
+	  mpegaudioparse: Post CBR bitrate as nominal bitrate
+	  Even if VBR headers are missing, we can't guarantee that a stream is in
+	  fact a CBR stream, so it's safer to let baseparse calculate the average
+	  bitrate rather than assume a CBR stream. However, in order to make
+	  /some/ metadata available before the requisite number of frames have
+	  been parsed, this posts the bitrate from the non-VBR headers as the
+	  nominal bitrate.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=641858
+
+2010-09-06 14:10:11 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstamrparse.c:
+	  amrparse: a valid amr-wb frame should not have reserved frame type index
+	  See #639715.
+
+2011-01-27 16:52:34 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: improve handling of dependent substream frames
+	  In particular, timestamps of these should track main-stream timestamps.
+
+2011-01-21 14:53:39 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: tune default duration estimate update interval
+	  Rather than a fixed default frame count, estimate frame count to aim for
+	  an interval duration depending on fps if available, otherwise use old
+	  fixed default.
+
+2011-01-14 15:16:04 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: reverse playback; mind keyframes for fragment boundary
+
+2011-01-13 15:26:21 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstamrparse.c:
+	  amrparse: properly check for sufficient available data prior to access
+
+2011-01-12 14:40:37 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: ensure non-empty candidate frames
+
+2011-01-11 15:24:23 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: clarify some debug statements
+
+2011-01-11 15:24:02 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: properly track upstream timestamps
+	  ... rather than with a delay.
+
+2011-01-11 15:23:29 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: need proper frame duration to obtain sensible frame bitrate
+
+2011-01-11 15:22:51 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: proper initial values for index tracking variables
+
+2011-01-11 12:05:13 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: arrange for consistent event handling
+
+2011-01-10 16:59:59 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.h:
+	  baseparse: header style cleaning
+
+2011-01-10 17:07:38 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: provide some more initial frame metadata in parse_frame
+	  ... and document accordingly.
+
+2011-01-10 16:56:36 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	* gst/audioparsers/gstflacparse.c:
+	  baseparse: refactor passthrough into format flags
+	  Also add a format flag to signal baseparse that subclass/format can provide
+	  (parsed) timestamp rather than an estimated one.  In particular, such "strong"
+	  timestamp then allows to e.g. determine duration.
+
+2011-01-10 15:34:48 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  baseparse: introduce a baseparse frame to serve as context
+	  ... and adjust subclass parsers accordingly
+
+2011-01-07 16:39:51 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	  baseparse: restrict duration scanning to pull mode and avoid extra set_caps call
+
+2011-01-07 15:58:49 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	  baseparse: update some documentation
+	  Also add some more debug.
+
+2011-01-06 11:41:44 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: allow increasing min_size for current frame parsing only
+	  Also check that subclass actually either directs to skip bytes or
+	  increases expected frame size to avoid going nowhere in bogus
+	  indefinite looping.
+
+2011-01-14 15:26:37 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baesparse: fix refactor regression in loop based parsing
+
+2011-01-06 11:16:56 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: pass all available data to subclass rather than minimum
+	  Also reduce some adapter calls and add a few debug statements.
+
+2010-12-10 15:59:49 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: fix reverse playback handling
+
+2010-12-10 14:56:13 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: minor typo and debug statement cleanup
+
+2010-12-10 14:40:05 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	  baseparse: reduce locking
+	  ... which is either already mute and/or implicitly handled by STREAM_LOCK.
+
+2011-01-14 14:08:38 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: avoid loop in frame locating interpolation
+
+2011-01-19 18:26:30 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: mind gst_buffer_unref not liking NULL
+	  Fixes #639950.
+
+2011-01-14 16:30:11 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  audioparsers: baseparse: Be careful to not lose the event ref
+	  Don't unref the event if it hasn't been handled, because the caller
+	  assumes it is still valid and might reuse it.
+	  I ran into this problem when transcoding an AVI (with mp3 inside)
+	  to gpp.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=639555
+
+2011-01-13 17:10:13 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstdcaparse.c:
+	  dcaparse: fix sync word for 14-bit little endian coding
+	  Fix copy'n'paste bug that made us look for the raw little endian
+	  sync word twice instead of looking for the 14-bit LE sync word
+	  as well. Fixes parsing of such streams (see #636234 for sample file).
+
+2011-01-13 16:27:04 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  docs: minor baseparse docs/comment fixes
+	  Remove copy'n'paste leftovers.
+
+2011-01-06 12:49:43 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Fix unitialized variable on macosx
+
+2010-12-13 15:17:29 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: relax bsid checking
+	  ... to the widest possible spec interpretation.
+	  Fixes #637062.
+
+2010-12-03 18:11:56 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	  audioparsers: update some documentation
+
+2010-12-03 18:11:38 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: add to documentation
+
+2010-12-03 18:11:09 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstdcaparse.c:
+	  dcaparse: add to documentation
+
+2010-11-08 19:58:31 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: increase keyframe awareness
+	  ... which is not particular relevant for audio parsing, but more so
+	  in video cases.  In particular, auto-determine if dealing with video (caps).
+
+2010-12-01 15:28:53 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstac3parse.h:
+	  ac3parse: use proper EAC-3 caps
+
+2010-11-30 15:41:02 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: avoid unexpected stray metadata
+
+2010-11-30 15:40:28 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: use proper _NONE output value when applicable
+
+2010-11-25 18:56:42 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstbaseparse.c:
+	  audioparsers: Remove dead assignments
+
+2010-11-25 17:14:23 +0100  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  audioparse: fix possible division-by-zero
+	  https://bugzilla.gnome.org/show_bug.cgi?id=635786
+
+2010-11-17 16:23:42 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: use correct offset when adding index entry
+	  ... bearing in mind that BUFFER_OFFSET is media specific and may not
+	  reflect the basic offset after having been parsed.
+
+2010-11-17 14:30:09 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: enhancements for timestamp marked framed formats
+	  That is, as such formats allow subclass to extract position from frame,
+	  it is possible to extract duration (if not otherwise provided)
+	  from (near) last frame, and a seek can fairly accurately target the required
+	  position.
+	  Fixes #631389.
+
+2010-11-16 17:06:14 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: refactor frame scanning peformed by _loop
+
+2010-11-16 18:04:00 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: slightly optimize sending of pending newsegment events
+
+2010-11-16 17:04:35 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: minor fixes and enhancements
+	  Arrange for upstream as well as downstream flushing when seeking.
+	  Also determine upstream size as well as seekability.  Adjust some comments
+	  to reality and employ debug statement in proper order.
+
+2010-11-17 15:33:36 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: minor cleanups
+
+2010-11-17 15:24:37 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: fix regression in ADIF src caps setting
+
+2010-11-16 12:11:53 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstflacparse.h:
+	  flacparse: parse seektable
+	  Fixes #631389 (partially).
+
+2010-11-16 12:08:54 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: minor refactor and enable default baseparse segment clipping
+
+2010-11-09 19:38:25 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstmpegaudioparse.c:
+	  mpegaudioparse: fix silly leak in _reset
+
+2010-10-29 14:08:58 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: use only upstream duration if it provides one
+
+2010-10-25 14:15:50 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: reflow update_bitrate code
+	  ... which makes local variables represent real state better, and avoids
+	  triggering unneeded updates/actions.
+
+2010-10-25 14:13:51 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: add some debug statements
+
+2010-10-19 23:25:54 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstdcaparse.c:
+	  dcaparse: init variable to make osx build bot happy
+	  gstdcaparse.c: In function 'gst_dca_parse_check_valid_frame':
+	  gstdcaparse.c:246: warning: 'best_sync' may be used uninitialized in this function
+
+2010-10-19 00:15:20 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/Makefile.am:
+	* gst/audioparsers/gstdcaparse.c:
+	* gst/audioparsers/gstdcaparse.h:
+	* gst/audioparsers/plugin.c:
+	  audioparsers: add very basic dts/dca parser
+	  Still some issues, e.g. with seekable queries in totem, but also
+	  processing already-chunked input (created with matroskademux ! gdppay).
+
+2010-10-14 16:48:21 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: properly parse e-ac3 frame header
+	  Also add a few debug statements.
+
+2010-10-13 11:00:01 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: tweak setting buffer metadata; avoid timestamp jitter
+	  Fixes #631993.
+
+2010-10-12 18:07:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstaacparse.h:
+	  aacparse: streamline src caps setting
+	  In particular, also set src caps whenever changes in stream warrant doing so.
+
+2010-10-12 10:28:33 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/flacparse.c:
+	  flacparse: Adjust unit tests to new flacparse behaviour
+	  Garbage after frames is now included in the frames because flacparse
+	  has no easy way to detect the real end of a frame. Decoders are
+	  expected to everything after the frame because only decoding the
+	  bitstream will reveal the real end of the frame.
+	  Fixes bug #631814.
+
+2010-10-12 10:27:53 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Don't drop the last frame if it is followed by garbage
+	  See bug #631814.
+
+2010-10-11 17:49:46 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: perform bitrate handling and posting after newsegment sending
+
+2010-10-11 17:36:19 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: immediately post subclass provided bitrate
+
+2010-10-11 17:06:48 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: fix parsing with unknown framesizes
+	  Fixes #631814 (mostly).
+
+2010-10-07 23:37:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Simplify frame header parsing by using lookup tables
+	  Based on a patch by Felipe Contreras.
+	  See bug #631200.
+
+2010-10-07 23:28:08 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstflacparse.h:
+	  flacparse: Don't parse the complete FLAC frames but only look for valid frame headers
+	  Thanks to Felipe Contreras for the suggestion. This is partially
+	  based on his patches and makes flacparse more than 3.5 times faster.
+	  Looking for valid frame headers is unlikely to give false positives
+	  because every frame header is at least 9 bytes long, contains a
+	  14 bit sync code and a 8 bit checksum over the first 8 bytes.
+	  Fixes bug #631200.
+
+2010-10-06 18:32:51 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Really post tags only after the initial newsegment event
+	  The first newsegment event will be send by the first call to
+	  gst_base_parse_push_buffer() if necessary, posting the tags
+	  before that is not a good idea. Instead do it from the
+	  GstBaseParse::pre_push_buffer vfunc.
+
+2010-10-05 11:17:52 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  Revert "baseparse: add skip property"
+	  This reverts commit b5a3d60363d837a10f0533c141ec93d10b742312.
+	  Reverting this for now, since no one really seems to remember why this
+	  property exists or what it could possibly be good for. It seems to have
+	  been in the original mp3parse since the beginning of time and was back-
+	  ported from there.
+
+2010-10-04 10:41:52 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Fix uninitialized variable compiler warnings
+	  These warnings are wrong, the variables are only used if they were
+	  initialized by the bit reader.
+
+2010-09-14 02:48:58 +0300  Felipe Contreras <felipe.contreras@gmail.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: fix picture parsing
+	  Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
+
+2010-10-03 23:54:49 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Push tags before the header buffers are pushed
+
+2010-08-02 20:50:21 +0300  Felipe Contreras <felipe.contreras@gmail.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: trivial caps fix
+	  Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
+
+2010-10-03 23:50:29 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  audioparser: Let the format string agree with the parameters to fix compiler warning
+
+2010-10-03 15:41:20 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: Use unchecked versions of the bitreader get functions
+	  We didn't check the return values anyway...
+
+2010-09-22 15:44:43 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: Fix debug output
+	  We lose the reference to the buffer after gst_pad_push(), so the debug
+	  print should happen before.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=622276
+
+2010-10-01 12:34:55 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/flacparse.c:
+	* tests/check/elements/parser.c:
+	* tests/check/elements/parser.h:
+	  audioparsers: add flacparse unit test
+	  ... and tweak parser test helper in the process.
+
+2010-09-29 16:12:42 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: support reverse playback
+	  ... in pull mode or upstream driven.
+
+2010-09-27 12:16:43 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: remove done TODOs and update documentation
+
+2010-09-25 14:40:54 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: use determined seekability in answering SEEKING query
+
+2010-09-25 14:32:06 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: add skip property
+
+2010-09-25 13:59:39 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/ac3parse.c:
+	* tests/check/elements/mpegaudioparse.c:
+	  audioparsers: add ac3parse and mpegaudioparse unit test
+
+2010-09-25 13:59:18 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/Makefile.am:
+	* gst/audioparsers/gstmpegaudioparse.c:
+	* gst/audioparsers/gstmpegaudioparse.h:
+	* gst/audioparsers/plugin.c:
+	  mpegaudioparse: initial version
+	  ... adequately equivalent to mp3parse, so lets boldly set it
+	  to higher rank.
+
+2010-09-25 14:01:07 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: set minimum frame size at _start
+	  ... rather than one time at _init.
+
+2010-09-25 13:50:51 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/aacparse.c:
+	* tests/check/elements/amrparse.c:
+	* tests/check/elements/parser.c:
+	* tests/check/elements/parser.h:
+	  audioparsers: refactor existing unit tests using common helper
+
+2010-09-22 15:07:09 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	  baseparse: use _set_frame_props to configure frame lead_in and lead_out
+	  ... provided a corresponding decoder with sufficient leading and following
+	  frames to carry out full decoding for a particular segment.
+
+2010-09-22 14:13:17 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	* gst/audioparsers/gstflacparse.c:
+	  baseparse: use _set_duration to configure duration update interval
+	  ... as it logically belongs there as one or the other; either subclass
+	  can provide a duration, or an estimate must be made (reguarly updated).
+
+2010-09-22 13:55:20 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: localize use of provided fps information
+
+2010-09-22 12:13:12 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: seek table and accurate seek support
+
+2010-09-21 13:57:10 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: proper and more extended segment and seek handling
+	  That is, loop pause handling, segment seek support, newsegment for gaps, etc
+
+2010-09-21 10:57:04 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	  baseparse: add index support
+
+2010-09-21 09:59:56 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: refactor state reset
+
+2010-09-20 16:39:37 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: prevent indefinite resyncing
+
+2010-09-20 13:57:55 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: specific EOS handling if no output so far
+
+2010-09-20 13:31:57 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: adjust _set_frame_prop documentation and set default as claimed
+
+2010-09-20 13:30:54 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: fix bitrate copy-and-paste and update heuristic
+
+2010-09-17 18:33:29 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: post duration message if average bitrates is updated
+
+2010-09-17 18:24:22 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	  baseparse: remove is_seekable vmethod and use a set_seek instead
+	  Seekability, like duration, etc is unlikely to change (frequently), and
+	  the default assumption covers most cases, so let subclass set when needed.
+	  At the same time, allow subclass to indicate if it has seek-metadata (table)
+	  available, and possibly have it provide an average bitrate.
+
+2010-09-17 17:35:40 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: remove redundant default is_seekable
+
+2010-09-17 17:21:46 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	  baseparse: add another hook for subclass prior to pushing buffer
+	  ... and allow subclass to perform custom segment clipping, or to
+	  emit tags or messages at this time.
+
+2010-09-17 17:19:37 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: 0 converts to 0 by default
+
+2010-09-16 18:56:46 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	  basepase: refactor conversion using helper function and export default convert
+
+2010-09-16 18:35:47 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: streamline query handling
+
+2010-09-16 11:51:20 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	  baseparse: cleanup struct and remove unused member
+
+2010-08-16 11:04:37 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/plugin.c:
+	  audioparsers: increase ranks to enable auto-plugging
+	  Because we can, and should, have some shakedown testing before having
+	  these make it into -good later on ...
+
+2010-09-22 16:07:24 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: Allow chaining of subclass event handlers
+	  This allows the child class to chain its event handler with
+	  GstBaseParse, so that subclasses don't have to duplicate all the default
+	  event handling logic.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=622276
+
+2010-08-27 18:35:10 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: Don't use GST_FLOW_IS_FATAL()
+	  Also don't post an error message for UNEXPECTED and do it
+	  for NOT_LINKED.
+
+2010-09-06 14:12:00 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: non-TIME seek event is simply not handled
+
+2010-06-15 15:34:05 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: fix seek event ref handling
+
+2010-06-15 15:33:37 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: prevent arithmetic overflows in pull mode buffer cache handling
+
+2010-06-15 15:32:34 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: fix seek handling
+	  Allow a few more seek event type combinations, and really use the result
+	  of gst_segment_set_seek to perform the seek.  Also add some debug.
+
+2010-04-12 18:07:29 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* tests/check/elements/aacparse.c:
+	* tests/check/elements/amrparse.c:
+	  check: Don't re-declare 'GList *buffers' in the tests
+	  It's an external which lives in gstcheck.c. Redeclaring it makes some
+	  compilers/architectures think the 'buffers' in the individual tests are
+	  a different symbol... and therefore we end up comparing holodecks with
+	  oranges.
+
+2010-03-26 18:56:49 +0000  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: Don't emit bitrate tags too early
+	  We wait to parse a minimum number of frames (10, arbitrarily) before
+	  emiting bitrate tags so that our early estimates are not wildly
+	  inaccurate for streams that start with a silence. If the stream ends
+	  before that, we just emit the tags anyway.
+	  While it _would_ be nicer to be specify the threshold to start pushing
+	  the tags in terms of duration, this would introduce more complexity than
+	  this merits.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=614991
+
+2010-03-26 18:58:35 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstflacparse.h:
+	  flacparse: Optionally check the overall frame checksums too before accepting a frame as valid
+	  This is optional because it's a quite expensive operation and it's very
+	  unlikely that a non-frame is detected as frame after the header CRC check
+	  and checking all bits for valid values. The overall frame checksums are
+	  mainly useful to detect inconsistencies in the encoded payload.
+
+2010-03-26 18:42:28 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Check the CRC-8 of the headers before accepting a frame as valid
+	  This makes false-positives during seeking much less likely and detection of
+	  them much faster.
+
+2010-03-26 18:20:24 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: Set the last stop to the buffer starttime if the duration is invalid
+	  ...instead of not setting it at all.
+
+2010-03-26 18:19:00 +0100  Joshua M. Doe <josh@joshdoe.com>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: Send NEWSEGMENT event with correct start and position
+	  Instead of taking the last stop (which could be buffer endtime instead
+	  of starttime) always take the buffer starttime.
+	  Fixes bug #614016.
+
+2010-03-26 16:49:01 +0000  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Fix buffer refcount issue
+	  When called from the GST_FLAC_PARSE_STATE_HEADERS case,
+	  gst_flac_parse_hand_headers() does a gst_buffer_set_caps() on a buffer
+	  with refcount > 1. This change handles this case by making the buffer
+	  metadata_Writable.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=614037
+
+2010-03-25 17:09:17 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	  audioparsers: remove unused GstBaseParseClassPrivate structure
+
+2010-03-25 12:55:02 +0000  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Make bitrate estimation more accurate
+	  This implements the get_frame_overhead() vfunc so that baseparse can
+	  make more accurate bitrate estimates.
+
+2010-03-25 11:48:46 +0000  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Fix bitrate calculation
+	  This patch adds the get_frame_overhead() vfunc so that baseparse can
+	  accurately calculate the min/avg/max bitrates for aacparse.
+	  Note: The bitrate was being incorrectly calculated for ADTS streams
+	  (it's not in the header as the code suggests).
+
+2010-03-25 11:22:58 +0000  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	  audioparsers: Add bitrate calculation to baseparse
+	  This makes baseparse keep a running average of the stream bitrate, as
+	  well as the minimum and maximum bitrates. Subclasses can override a
+	  vfunc to make sure that per-frame overhead from the container is not
+	  accounted for in the bitrate calculation.
+	  We take care not to override the bitrate, minimum-bitrate, and
+	  maximum-bitrate tags if they have been posted upstream. We also
+	  rate-limit the emission of bitrate so that it is only triggered by a
+	  change of >10 kbps.
+
+2010-03-22 16:56:03 +0100  Benjamin Otte <otte@redhat.com>
+
+	* tests/check/elements/amrparse.c:
+	  Add -Wold-style-definition
+	  and fix the warnings
+
+2010-03-21 21:39:18 +0100  Benjamin Otte <otte@redhat.com>
+
+	* tests/check/elements/aacparse.c:
+	* tests/check/elements/amrparse.c:
+	  Add -Wmissing-declarations -Wmissing-prototypes to configure flags
+	  And fix all warnings
+
+2010-03-18 17:30:26 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstamrparse.c:
+	  gst_element_class_set_details => gst_element_class_set_details_simple
+
+2010-01-14 11:50:33 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  audioparsers: rename baseparse GType name to avoid possible conflicts
+
+2010-01-12 18:55:53 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: Initialize variables.
+	  Fixes build on $#@*( macosx
+
+2010-01-11 22:41:57 +0300  Ðóñëàí Èæáóëàòîâ <lrn1986@gmail.com>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstamrparse.c:
+	  win32: Include config.h before anything else. Fix mpegdemux LIBADD
+	  Because config.h defines __MSVCRT_VERSION__, which should be defined
+	  before inclusion of any system header.
+	  Also fixes mpegdemux Makefile.am LIBADD typo.
+	  Fixes #606665
+
+2010-01-11 13:20:26 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Also add stream-format to template caps
+	  Do not forget to add stream-format to template caps
+	  off aacparse
+
+2010-01-11 13:13:41 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* tests/check/elements/aacparse.c:
+	  Rename aac's stream-format 'none' to 'raw'
+	  Renames aac's stream-format from previous commits from none to
+	  raw
+
+2010-01-11 12:10:02 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* tests/check/elements/aacparse.c:
+	  aacparse: update tests to stream-format changes
+	  Updates aacparse unit tests to check for stream-format
+	  correctness as well.
+
+2010-01-11 10:51:18 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	  aacparse: Add stream-format to output caps
+	  Adds stream-format field to output caps
+
+2010-01-05 15:05:05 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstbaseparse.c:
+	  audioparsers: documentation fixes
+
+2010-01-05 15:04:38 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: add documentation
+
+2010-01-05 14:48:49 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstflacparse.h:
+	  flacparse: add documentation
+
+2009-12-21 18:29:43 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: perform additional frame checks when resyncing
+
+2010-01-05 16:35:52 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: fix (multiple channel) frame parsing
+
+2010-01-05 16:35:44 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: declare unparsed input and parsed output
+
+2009-12-21 18:19:23 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: fix scanning for next syncword
+
+2009-12-21 18:18:39 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: adjust seek handling and newsegment sending
+	  Perform sanity check on type of seek, and only perform one that is
+	  appropriately supported.  Adjust downstream newsegment event
+	  to first buffer timestamp that is sent downstream.
+
+2009-12-21 11:59:45 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: minor refactor cleanup
+	  Also add some debug logging.
+
+2009-12-18 21:05:11 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: locate next sync code more efficiently
+
+2009-12-18 21:04:12 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: baseparse takes care of handling leftover pieces
+
+2009-12-18 21:02:40 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: implement leftover draining in pull mode
+
+2009-12-17 12:45:36 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstflacparse.c:
+	  flacparse: set _OFFSET and _OFFSET_END on outgoing buffers
+
+2009-12-17 12:44:20 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/Makefile.am:
+	* gst/audioparsers/gstflacparse.c:
+	* gst/audioparsers/gstflacparse.h:
+	* gst/audioparsers/plugin.c:
+	  audioparsers: move 'flacparse' into it
+
+2009-12-16 18:38:33 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: provide default conversion using bps if no fps available
+	  Also store estimated duration as such, rather than pretending otherwise
+	  (e.g. set by subclass).
+
+2009-12-18 13:30:29 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: check for remaining data when draining in push mode
+
+2009-12-18 13:30:07 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  baseparse: fix pull mode cache size comparison
+
+2009-12-18 13:01:17 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: Fix unitialized variable.
+
+2009-12-17 14:46:01 +0000  Christian Schaller <christian.schaller@collabora.co.uk>
+
+	* gst/audioparsers/Makefile.am:
+	  Update spec file and fix ac3parser header listing in Makefile.am
+
+2009-12-11 10:25:16 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  audioparse: fix a format string as reported on irc.
+
+2009-11-23 16:34:50 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: ensure sufficient data available for parsing
+
+2009-10-29 15:19:04 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: extract and use some more details for Enhanced Ac-3 streams
+
+2009-10-29 15:18:37 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	  baseparse: custom bufferflag indicates not to count frame in stats
+
+2009-10-28 14:08:43 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: perform additional frame checks when resyncing
+
+2009-10-28 14:07:17 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: inform base parser of frame duration
+
+2009-10-27 16:16:50 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstac3parse.c:
+	  ac3parse: improve src caps settings
+
+2009-11-27 17:59:03 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/Makefile.am:
+	* gst/audioparsers/gstac3parse.c:
+	* gst/audioparsers/gstac3parse.h:
+	* gst/audioparsers/plugin.c:
+	  ac3parse: initial version
+	  MARGINAL rank for now; might take some time for some (useful)
+	  framed=true/false to appear here and there.
+
+2009-11-26 18:34:45 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstamrparse.h:
+	  amrparse: use (default) time handling of baseparser class
+
+2009-11-26 18:15:21 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/Makefile.am:
+	* gst/audioparsers/gstamrparse.c:
+	* gst/audioparsers/gstamrparse.h:
+	* gst/audioparsers/plugin.c:
+	  audioparsers: move 'amrparse' into it
+
+2009-11-27 17:27:32 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/audioparsers/gstbaseparse.c:
+	  audioparsers: reference GstBaseParse now lives here
+
+2009-11-28 18:13:31 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/Makefile.am:
+	* gst/audioparsers/Makefile.am:
+	* gst/audioparsers/gstaacparse.c:
+	* gst/audioparsers/gstaacparse.h:
+	* gst/audioparsers/gstbaseparse.c:
+	* gst/audioparsers/gstbaseparse.h:
+	* gst/audioparsers/plugin.c:
+	  audioparsers: rename 'aacparse' plugin to generic 'audioparsers' plugin
+
+2009-11-26 17:04:43 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/Makefile.am:
+	* gst/aacparse/gstaacparse.c:
+	* gst/aacparse/plugin.c:
+	  aacparse: separate plugin registration and rename plugin
+
+2009-11-26 17:04:36 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstaacparse.c:
+	  aacparse: ensure sufficient data available before accessing
+
+2009-11-05 14:31:40 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstaacparse.c:
+	* gst/aacparse/gstaacparse.h:
+	  aacparse: use (default) time handling of baseparser class
+
+2009-10-29 15:19:35 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstaacparse.c:
+	  aacparse: fixup comments to C-style
+
+2009-10-29 16:05:00 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: reset passthrough mode to default (disabled) on activation
+
+2009-10-29 15:16:59 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: ensure buffer metadata is writable
+
+2009-10-28 14:06:13 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstbaseparse.c:
+	* gst/aacparse/gstbaseparse.h:
+	  baseparse: fix/enhance DISCONT marking
+	  In particular, consider DISCONT == !sync, and allow subclass to query
+	  sync state, as it may want to perform additional checks depending
+	  on whether sync was achieved earlier on.
+	  Also arrange for subclass to query whether leftover data is being drained.
+
+2009-11-23 15:48:25 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstbaseparse.c:
+	* gst/aacparse/gstbaseparse.h:
+	  baseparse: add timestamp handling, and default conversion
+	  In particular, (optionally) provide baseparse with a notion of frames per second
+	  (and therefore also frame duration) and have it track frame and byte counts.
+	  This way, subclass can provide baseparse with fps and have it provide default
+	  buffer time metadata and conversions, though subclass can still install
+	  callbacks to handle such itself.
+
+2009-10-28 12:02:03 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: documentation fixes
+
+2009-10-28 12:00:08 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: use_fixed_caps for src pad
+	  After all, stream is as-is, and there is little molding to downstream's
+	  taste that can be done.  If subclass can and wants to do so, it can
+	  still override as such.
+
+2009-11-20 17:32:13 +0100  Julien Moutte <julien@fluendo.com>
+
+	* gst/aacparse/gstbaseparse.c:
+	  aacparse: Fix compilation warnings
+
+2009-10-11 11:22:11 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/aacparse/gstaacparse.c:
+	* gst/aacparse/gstbaseparse.c:
+	  aacparse: fix warnings in macosx snow leopard
+
+2009-09-25 17:02:53 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstaacparse.c:
+	* gst/aacparse/gstbaseparse.c:
+	* gst/aacparse/gstbaseparse.h:
+	  aacparse: forego (bogus) parsing of already parsed (raw) input
+
+2009-08-07 13:07:17 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: prevent infinite loop when draining
+
+2009-08-07 13:06:28 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: fix minor memory leak
+
+2009-07-14 14:08:04 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/aacparse/gstbaseparse.c:
+	* gst/aacparse/gstbaseparse.h:
+	  aacparse: Add function for the baseparse subclass to push buffers downstream
+	  Also handle the case gracefully where the subclass decides to drop
+	  the first buffers and has no caps set yet. It's still required to
+	  have valid caps set when the first buffer should be passed downstream.
+
+2009-07-14 14:07:44 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: Fix seek event leaking
+
+2009-06-18 12:13:28 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstaacparse.c:
+	  aacparse: ADIF: do not send bogus timestamps, leave to downstream (decoder)
+
+2009-06-01 15:53:27 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/aacparse/gstaacparse.c:
+	  aacparse: fix sample rate extraction from codec data
+	  In one case we extracted the sample rate index from the codec data
+	  and saved it as sample rate rather than getting the real sample
+	  rate from the table. Fix that, and also make sure we don't access
+	  non-existant table entries by adding a small helper function that
+	  guards against out-of-bounds access in case of invalid input data.
+
+2009-06-01 14:02:33 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/aacparse/gstaacparse.c:
+	  aacparse, amrparse: remove bogus gst_pad_fixate_caps() calls
+
+2009-06-01 13:56:18 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: propagate return value of GstBaseParse::set_sink_caps()
+	  gst_base_parse_sink_setcaps() presumably should fail if the subclass
+	  returns FALSE from its ::set_sink_caps() function.
+
+2009-06-01 13:47:01 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: don't try to GST_LOG an already-freed caps string
+	  The proper way to log caps is via GST_PTR_FORMAT anyway.
+
+2009-06-01 13:05:35 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/aacparse/gstaacparse.c:
+	* tests/check/elements/aacparse.c:
+	  aacparse: set channels and rate on output caps, and keep codec_data
+	  Create output caps from input caps, so we maintain any fields we
+	  might get on the input caps, such as codec_data or rate and channels.
+	  Set channels and rate on the output caps if we don't have input caps
+	  or they don't contain such fields. We do this partly because we can,
+	  but also because some muxers need this information. Tagreadbin will
+	  also be happy about this.
+
+2009-05-26 19:43:53 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: fix debug category
+
+2009-04-27 22:39:15 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: fix (regression in) newsegment handling
+	  (aacparse, amrparse, flacparse).  Fixes #580133.
+
+2009-04-07 04:53:02 +0300  René Stadler <mail@renestadler.de>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: Fix slightly broken buffer-in-segment check (aacparse, amrparse, flacparse)
+
+2009-04-05 03:50:19 +0300  René Stadler <mail@renestadler.de>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: Fix push mode seeking (aacparse, amrparse)
+	  Sending the flush-start event forward before taking the stream lock actually
+	  works, in contrast to deadlocking in downstream preroll_wait (hunk 1).
+	  After that we get the chain function being stuck in a busy loop. This is fixed
+	  by updating the minimum frame size inside the synchronization loop because the
+	  subclass asks for more data in this way (hunk 2).
+	  Finally, this leads to a very probable crash because the subclass can find a
+	  valid frame with a size greater than the currently available data in the
+	  adapter. This makes the subsequent gst_adapter_take_buffer call return NULL,
+	  which is not expected (hunk 3).
+
+2009-03-31 16:07:46 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: Delay newsegment as long as possible.
+	  If newsegment is sent (too) early, caps may not yet be fixed/set,
+	  and downstream may not have been linked.
+
+2009-03-19 01:17:25 +0200  René Stadler <mail@renestadler.de>
+
+	* gst/aacparse/gstaacparse.c:
+	  aacparse: Fix busyloop when seeking. Fixes #575388
+	  The problem is that after a discont, set_min_frame_size(1024) is called when
+	  detect_stream returns FALSE. However, detect_stream calls check_adts_frame
+	  which sets the frame size on its own to something larger than 1024. This is the
+	  same situation as in the beginning, so the base class ends up calling
+	  check_valid_frame in an endless loop.
+
+2009-03-19 00:32:40 +0200  René Stadler <mail@renestadler.de>
+
+	* gst/aacparse/gstaacparse.c:
+	  aacparse: Refactor check_valid_frame to expose broken code
+	  Just moving code around and removing an unhelpful/misleading comment.
+
+2009-02-27 11:24:37 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: revert last change and properly fix
+	  Baseparse internaly breaks the semantics of a _chain function by calling it with
+	  buffer==NULL. The reson I belived it was okay to remove it was that there is
+	  also an unchecked access to buffer later in _chain. Actually that code is wrong,
+	  as it most probably wants to set discont on the outgoing buffer.
+
+2009-02-26 11:02:06 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/aacparse/gstbaseparse.c:
+	  baseparse: remove checks for buffer==NULL
+	  Accordifn to docs for GstPadChainFunction buffer cannot be NULL. If we would
+	  leave the check, we would also need more such check below.
+
+2009-02-11 00:15:43 +0200  René Stadler <mail@renestadler.de>
+
+	* gst/aacparse/gstaacparse.c:
+	  aacparse: Fix license specified in plugin details.
+
+2009-01-30 18:18:10 +0000  Jan Schmidt <jan.schmidt@sun.com>
+
+	* gst/aacparse/gstbaseparse.c:
+	  Fix the return value of the default parse_frame function.
+	  Fix the return value of the default parse_frame function in both
+	  copies of GstBaseParse
+
+2009-01-23 16:00:10 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/aacparse/gstaacparse.c:
+	  Log aac details found in codec_data.
+
+2008-11-13 17:24:58 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/aacparse/gstaacparse.c: Don't autoplug aacparse until it works.
+	  Original commit message from CVS:
+	  * gst/aacparse/gstaacparse.c: (plugin_init):
+	  Don't autoplug aacparse until it works.
+
+2008-11-13 15:20:15 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/check/: Add unit tests for new parsers.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/aacparse.c:
+	  * tests/check/elements/amrparse.c:
+	  Add unit tests for new parsers.
+
+2008-11-13 14:21:39 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/: Fix baseparse type name.
+	  Original commit message from CVS:
+	  * gst/aacparse/gstbaseparse.c:
+	  * gst/amrparse/gstbaseparse.c:
+	  Fix baseparse type name.
+
+2008-11-13 12:59:34 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Add two new baseparse based parsers (aac and amr) from Bug #518857.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/aacparse/Makefile.am:
+	  * gst/aacparse/gstaacparse.c:
+	  * gst/aacparse/gstaacparse.h:
+	  * gst/aacparse/gstbaseparse.c:
+	  * gst/aacparse/gstbaseparse.h:
+	  * gst/amrparse/Makefile.am:
+	  * gst/amrparse/gstamrparse.c:
+	  * gst/amrparse/gstamrparse.h:
+	  * gst/amrparse/gstbaseparse.c:
+	  * gst/amrparse/gstbaseparse.h:
+	  Add two new baseparse based parsers (aac and amr) from Bug #518857.
+
+2011-03-20 01:08:38 +0100  Havard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: Make src_query MT-safe
+	  It is possible that the element might be going down while the event arrives
+
+2011-04-08 15:22:47 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Unref event if the parent element disappeared
+
+2011-04-08 15:22:19 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: Unref event if the parent element disappeared
+
+2011-03-21 16:04:34 +0100  Havard Graff <havard.graff@tandberg.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Make upstream events MT-safe
+
+2011-03-21 16:04:34 +0100  Havard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: Make upstream events MT-safe
+
+2011-04-08 15:20:51 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtp: Unref events if the parent element disappeared
+
+2011-01-06 18:24:36 +0100  Ole André Vadla Ravnås <oravnas@cisco.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpmanager: fix pad callbacks so they handle when parent goes away
+	  1) We need to lock and get a strong ref to the parent, if still there.
+	  2) If it has gone away, we need to handle that gracefully.
+	  This is necessary in order to safely modify a running pipeline. Has been
+	  observed when a streaming thread is doing a buffer_alloc() while an
+	  application thread sends an event on a pad further downstream, and from
+	  within a pad probe (holding STREAM_LOCK) carries out the pipeline plumbing
+	  while the streaming thread has its buffer_alloc() in progress.
+
+2010-11-26 15:20:04 +0100  Havard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: make iterate_internal_links MT-safe
+
+2011-04-08 14:35:04 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  Revert "Pulsesink: Allow chunks up to bufsize instead of segsize"
+	  This reverts commit 1e2c1467ae042a3c6bb1a6bc0c07aeff13ec5edb.
+	  The commit causes pulsesink to ignore the latency-time baseaudiosink property.
+
+2011-04-08 11:13:07 +0200  Alexey Fisher <bug-track@fisher-privat.net>
+
+	* gst/rtp/gstrtpspeexpay.c:
+	  rtpspeexpay: Do not transmitt samples with GAP flag
+	  If we get GAP samples, there is no need to transmitt it.
+	  In some situations, microphone is muted, we can drop net traffick
+	  usage to ~1 kbit/s. Without patch it will stay ~20 kbit/s
+
+2011-04-08 11:11:58 +0200  Alexey Fisher <bug-track@fisher-privat.net>
+
+	* ext/speex/gstspeexenc.c:
+	  speexenc: Use speex intern silence detection
+	  Speex has build in silence detection. If speex_encode_int returns 0,
+	  than there is silence and sample do not need to be transmitted.
+	  This work only if vbr=1 and dtx=1 optionas are enabled.
+	  So if we get 0, we add GAP flag to the sample.
+
+2011-04-07 19:04:33 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	  rtp: port some pay/depayloaders
+
+2011-04-05 19:15:11 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  udpsink: handle scather gather from buffers
+	  Iterate the memory blocks on the buffer and send them using sendmsg.
+
+2011-04-05 17:26:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtpdec.c:
+	  rtpdec: reset structure before use
+
+2011-04-05 17:20:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  gst/rtsp/gstrtspsrc.c
+
+2011-04-05 17:12:28 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: handle * control correctly
+	  Parse session control attributes when no media control attribute is
+	  present. Threat * control attributes as an empty string, just like the
+	  spec says.
+	  Fixes #646800
+
+2011-04-05 17:06:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtpdec.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	  rtsp/udp: port to 0.11
+
+2011-04-05 14:28:54 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Add support for A-Law and µ-Law
+	  Fixes bug #646567.
+
+2011-04-05 09:44:01 +0200  Jon Nordby <jononor@gmail.com>
+
+	* configure.ac:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: Fix build with jack 0.120.1
+	  9544622674c0d0a3147a9b51145159b02eec68e9 checked
+	  for 0.120.2 and later, but the deprecation was introduced in
+	  0.120.1
+
+2011-04-05 11:13:36 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavisubtitle.c:
+	  avi: more porting to 0.11
+
+2011-04-05 12:05:19 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/gstv4l2radio.h:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/gstv4l2xoverlay.c:
+	  docs: fix docuemntation warnings (and reindent)
+
+2011-04-04 19:17:43 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavimux.c:
+	  avi: port to 0.11 API
+
+2011-04-04 17:34:17 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/videomixer/blendorc-dist.c:
+	* gst/videomixer/blendorc-dist.h:
+	  videomixer: update orc dist files
+
+2011-04-04 15:57:10 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 1ccbe09 to c3cafe1
+
+2011-03-01 14:08:12 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Always call pa_stream_new_with_proplist()
+	  pa_stream_new_with_proplist() can take a NULL proplist, so we don't need
+	  to concern ourselves with whether it's NULL or not.
+
+2011-04-04 11:33:10 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: perform post-flush state tricks downstream to upstream
+	  ... so downstream is set when upstream resumes data flow.
+
+2011-04-04 11:27:29 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: distribute new base_time to manager children following flush seek
+	  ... by forcing a state changed to PLAYING, which should otherwise be a
+	  no-op as elements should already be in that state.
+	  In particular, jitterbuffer needs new base_time as soon as possible to perform
+	  proper timing (e.g. eos timeout handling) and can't wait for the new base_time
+	  that will be distributed when the whole pipeline returns to PLAYING.
+	  See bug #646397.
+
+2011-04-04 11:35:59 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  Revert "jitterbuffer: reset element base_time upon flush"
+	  This reverts commit f84b8a69cba9c538f5546869cb4ef454ad5efb9d.
+	  Fixes bug #646397.
+
+2011-04-04 10:31:44 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvmux.c:
+	  flv: Specify the only possible stream-format for h264 in the pad templates.
+
+2011-04-04 10:07:42 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Check for invalid (empty) classification info entity strings
+	  Otherwise the classification string can be empty and gst_tag_list_add() will
+	  complain or have a \0 in the first four bytes, which is wrong too.
+
+2011-04-04 10:01:26 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Year 0 is not a valid year for GDate and the proleptic gregorian calendar
+
+2011-04-01 13:18:55 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: Add support for writing METADATA_BLOCK_PICTURE blocks for GST_TAG_IMAGE and GST_TAG_PREVIEW_IMAGE
+
+2011-04-01 11:33:54 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer2.c:
+	  videomixer[2]: Use orc_memset() instead of memset()
+
+2011-01-19 18:06:45 -0700  Lane Brooks <dirjud@gmail.com>
+
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer.h:
+	  videomixer: Add transparent background option for alpha channel formats
+
+2011-01-19 12:07:17 -0700  Lane Brooks <dirjud@gmail.com>
+
+	* gst/videomixer/blend.c:
+	* gst/videomixer/blend.h:
+	* gst/videomixer/blendorc.orc:
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	  videomixer2: Add transparent background option for alpha channel formats
+	  This option allows the videomixer2 element to output a valid alpha
+	  channel when the inputs contain a valid alpha channel. This allows
+	  mixing to occur in multiple stages serially.
+	  The following pipeline shows an example of such a pipeline:
+	  gst-launch videotestsrc background-color=0x000000 pattern=ball ! video/x-raw-yuv,format=\(fourcc\)AYUV ! videomixer2 background=transparent name=mix1 ! videomixer2 name=mix2 ! ffmpegcolorspace ! autovideosink  videotestsrc ! video/x-raw-yuv,format=\(fourcc\)AYUV ! mix2.
+	  The first videotestsrc in this pipeline creates a moving ball on a
+	  transparent background. It is then passed to the first videomixer2.
+	  Previously, this videomixer2 would have forced the alpha channel to
+	  1.0 and given a background of checker, black, or white to the
+	  stream. With this patch, however, you can now specify the background
+	  as transparent, and the alpha channel of the input will be
+	  preserved. This allows for further mixing downstream, as is shown in
+	  the above pipeline where the a second videomixer2 is used to mix in a
+	  background of an smpte videotestsrc. So the result is a ball hovering
+	  over the smpte test source. This could, of course, have been
+	  accomplished with a single mixer element, but staged mixing is useful
+	  when it is not convenient to mix all video at once (e.g. a pipeline
+	  where a foreground and background bin exist and are mixed at the final
+	  output, but the foreground bin needs an internal mixer to create
+	  transitions between clips).
+	  Fixes bug #639994.
+
+2011-03-31 13:25:00 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: also uncork during EOS waiting (and after EOS is rendered)
+	  Pulsesink was recently changed to defer uncorking until there is data
+	  to write. This condition will however never occur when EOS in being
+	  rendered (since that marks the end of data). Changing to PAUSED state
+	  while EOS is being waited on results in a hang: pausing corks the
+	  stream, which will never be undone since there is no more data when
+	  going back to PLAYING. If pulsesink is the clock provider, deadlock
+	  ensues since time doesn't continue in corked state and the clock id
+	  for EOS wait never fires.
+	  Fixes #645961.
+
+2011-03-29 16:33:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/rtpbin.c:
+	  rtpbin: Don't try to request the same request pad twice
+
+2011-03-28 23:46:47 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacdec.h:
+	  flacdec: fix issues with large metadata blocks when streaming unframed flac
+	  Parse metadata blocks when handling unparsed flac in push mode. This
+	  works around a bunch of issues with the flac decoder when handling
+	  metadata blocks that are larger than the max. flac framesize, which
+	  coverart blocks often are. We need to have all the data for these
+	  blocks available when we pass data to libflac.
+	  http://gstreamer-devel.966125.n4.nabble.com/Flac-files-that-will-playback-but-not-stream-td3338198.html#a3395276
+	  https://bugzilla.gnome.org/show_bug.cgi?id=566769
+
+2011-03-28 21:05:31 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalphacolor.c:
+	* gst/apetag/gstapedemux.c:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideoflip.c:
+	  plugins: port to new memory API
+
+2011-03-28 20:50:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11-fdo
+
+2011-03-27 21:39:50 +0200  Jan Urbański <wulczer@wulczer.org>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	  flvdemux: Do not build an index if upstream is not seekable
+	  An index is not useful if upstream cannot handle seeks and building it
+	  for infinite files, for instance FLV streams, results in a memory leak.
+
+2011-03-27 01:19:58 +0300  Alexey Chernov <4ernov@gmail.com>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2radio.c:
+	* sys/v4l2/gstv4l2radio.h:
+	  v4l2: new v4l2radio element to control analog radio devices
+	  https://bugzilla.gnome.org/show_bug.cgi?id=640118
+
+2011-03-25 22:22:43 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 193b717 to 1ccbe09
+
+2011-03-25 14:56:06 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From b77e2bf to 193b717
+
+2011-03-25 12:53:43 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/cairo/Makefile.am:
+	  cairo: fix the name of the *-marshall.list file to unbreak make distcheck
+
+2011-03-25 09:31:03 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From d8814b6 to b77e2bf
+
+2011-03-25 09:06:16 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 6aaa286 to d8814b6
+
+2011-03-25 00:10:56 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	* gst/spectrum/gstspectrum.h:
+	  spectrum: refactor processing loop for block based operation
+	  Previously the chain function was working sample frame based. In each cycle it
+	  was checking if it is time to run a fft or if it is time to send a message.
+	  Now we changed the data transform functions to work on a block of data and
+	  calculate the max length until either {end-of-data, do-fft, do-msg}. This allows
+	  us also to avoid the duplicated code for the single and multi-channel case (as
+	  the transformers have the same signature now).
+
+2011-03-24 23:47:33 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* configure.ac:
+	  jack: unbreak the build for jack2 users
+	  Jack2 (versions 1.X.X) does only have that API in svn. Limmit the use of the new
+	  API for jack1 versions.
+
+2011-03-24 18:49:19 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 6aec6b9 to 6aaa286
+
+2011-03-24 14:14:09 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: fix the error accumulation and frames_todo handling
+	  Even though we wrap around the accumulated second, we still need to add the
+	  error in the same cycle. Increase the todo in the same conditional as afterwards
+	  the accumulated error will be below one second.
+
+2011-03-24 13:53:12 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: fix broken code resulting for a wrong splitup of changes
+
+2011-03-22 16:29:53 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	* gst/spectrum/gstspectrum.h:
+	  spectrum: simplify the have_interval calculation
+	  Move some of the conditions to the places where the dependent variables change.
+
+2011-03-22 16:26:45 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: use local var for input_data function
+	  Avoid dereferencing the input_data from the instance from within an inner loop.
+
+2011-03-23 16:34:16 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexdec.h:
+	  speexdec: Get and use streamheader from the caps if possible
+	  This allows playback of streams where the streamheader buffers
+	  were dropped from the stream for some reason.
+
+2011-03-22 19:36:31 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: use running time for synchronization
+	  Fixes #432612.
+
+2011-03-22 19:36:21 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: use running time for synchronization
+	  Fixes #432612.
+
+2011-03-22 19:35:58 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: use running time for synchronization
+	  See bug #432612.
+
+2011-03-22 12:53:22 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* configure.ac:
+	  configure.ac: redundant uses of AC_MSG_RESULT()
+	  cleaned the redundant uses of AC_MSG_RESULT() in configure.ac
+
+2011-03-18 19:34:57 +0100  Luis de Bethencourt <luis@debethencourt.com>
+
+	* autogen.sh:
+	  autogen: wingo signed comment
+
+2011-03-16 10:43:47 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* ext/jack/gstjackaudiosink.c:
+	  jackaudiosink: Fix typo from 9544622674c0d0a3147a9b51145159b02eec68e9
+
+2011-03-16 09:38:43 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	  matroska: Mark tag mapping tables as static const
+
+2011-03-16 09:37:58 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Use ARTIST instead of AUTHOR for GST_TAG_ARTIST
+
+2011-03-16 09:35:50 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	  matroskademux: Use ARTIST Matroska tag instead of AUTHOR for GST_TAG_ARTIST
+	  AUTHOR only existed in an old version of the spec and ARTIST is
+	  the new replacement for this. We are still reading both to still
+	  be compatible with old files.
+	  Fixes bug #644875.
+
+2011-03-15 20:19:48 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/videofilter.c:
+	  tests: enable more formats in videofilter unit test, check more resolutions
+
+2011-03-14 19:14:07 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: Fix buffer overflow bug for odd resolutions and Y422 colorspaces
+	  https://bugzilla.gnome.org/show_bug.cgi?id=644773
+
+2011-03-15 19:36:01 +0200  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	  speexdec: silence warning message when appropriate
+	  If we did not know how many frames to expect, then we get an unexpected
+	  end of stream when trying to decode more frames that are there, if there
+	  are leftover bits to pad to the next byte
+
+2011-03-14 19:14:07 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: Add support for YUY2, UVYV and YVYU colorspaces
+	  https://bugzilla.gnome.org/show_bug.cgi?id=644773
+
+2011-03-15 09:43:35 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/videofilter.c:
+	  tests: in videofilter unit test also check with 'odd' widths and heights
+	  And only use one test suite.
+
+2011-03-14 19:28:07 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	  speexdec: Always process the number of frames per packet as specified in the header
+	  Looking at the remaining bits in the bitstream after decoding a
+	  single frame can't be used as loop condition. The remaining
+	  bits might not give a complete frame and the speex decoder will
+	  then output nothing but access uninitialized memory, which leads
+	  to valgrind warnings.
+	  Fixes bug #644669.
+
+2011-03-14 15:46:50 +0100  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: return TRUE from sink pad event function for tag events, which are handled
+	  https://bugzilla.gnome.org/show_bug.cgi?id=644730
+
+2011-03-12 00:44:31 +0530  Philip Jägenstedt <philipj@opera.com>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Better fix for deadlock on failed connect
+	  This reverts the previous fix that would cause a double-unlock when the
+	  stream connect failed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=644510
+
+2011-03-11 23:06:31 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Fix deadlock if connecting to PA fails
+	  Commit dd4ec22e introduced a deadlock in the failure path while trying
+	  to connect to PulseAudio. This makes sure we drop the lock on the
+	  resource mutex to avoid this.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=644510
+
+2011-03-11 16:59:10 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/check/Makefile.am:
+	  tests: order state-test blacklist and add jack elements
+	  Jack audio src/sink elements recently got moved from bad and should be excluded
+	  from the test (like the other device specific source and sinks).
+	  Fixes #644288
+
+2011-03-11 13:47:26 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: Chain up to the parent class' ::send_event for non-seek events
+
+2011-03-11 13:46:05 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: Fix refcount issues with the seek event
+	  Fixes bug #642963.
+
+2011-03-11 09:54:02 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  docs: fix pulsesink gtk-doc markup
+
+2011-03-11 10:29:08 +0100  Philippe Normand <pnormand@igalia.com>
+
+	* configure.ac:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: fix build against jack 0.120.2
+	  jack_port_get_total_latency() has been deprecated in favor of
+	  jack_port_get_latency_range().
+	  https://bugzilla.gnome.org/show_bug.cgi?id=644477
+
+2011-03-10 14:29:25 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: more comments and tune and logging
+
+2011-03-10 14:15:42 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: avoid unneccesary extra fft runs
+	  Before it was possible that we run an extra fft when the time for sending a new
+	  message is due. Only do this if we have not run the fft for the interval at all.
+
+2011-03-10 14:12:01 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: only scale the vectors that we are processing
+	  Phase is not produced by default, so lets not scale it unconditionally to save a
+	  few cycles.
+
+2011-03-10 14:10:25 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	* gst/spectrum/gstspectrum.h:
+	  spectrum: put number of channels to instance variable
+	  When freeing data the format might have changed. Thus we need to remember for
+	  which format we allocated memory.
+
+2011-03-10 10:27:14 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: update doc review stamp
+
+2011-03-10 10:22:29 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	* gst/spectrum/gstspectrum.h:
+	  spectrum: use function pointers for data readers
+	  Don't check the format for each sample frame to read. We can make that decission
+	  in _setup already. This is still not ideal as we call the function per frame.
+	  Ideally we determine how many samples we can copy and have a loop in the input
+	  reader. As an alternative we might also consider to use the fft variants for the
+	  various formats and not convert to float for all cases - we would still need to
+	  mix or deinterleave though.
+
+2011-03-09 17:07:47 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: improve recovery from failed seek
+	  In case server-side fails to perform seek, i.e. PLAY at non-zero requested
+	  position, recovery so far would arrange for streaming to continue, albeit
+	  having lost position tracking in the process.  So, query position prior
+	  to seek and use upon failed seek.
+
+2011-03-09 16:51:00 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: handle position query
+
+2011-03-09 16:57:28 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	* gst/spectrum/gstspectrum.h:
+	  spectrum:  multi-channel support
+	  Add a boolean multi-channel property with a default of FALSE. When set to TRUE
+	  the element won't mix all input channels to mono, but instead run a FFT on each
+	  channel. In that case the result message would contain a 2 dimensional array
+	  of channel x data for magnitude and phase.
+	  API: GstSpectrum:multi-channel
+	  https://bugzilla.gnome.org/show_bug.cgi?id=593482
+
+2011-03-09 16:55:56 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: more xrefs in the docs
+
+2011-03-09 12:41:15 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: factor out the code that accumulated samples into the ring-buffer
+	  Use a separate function to read a sample frame into a ringbuffer slot. In the
+	  future we can use format-specific function pointer to avoid the reoccuring
+	  format checks.
+
+2011-03-09 12:38:52 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: pull format to temp var to improve readability of lines using it
+
+2011-03-09 12:20:11 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: code cleanup for copying data to ring-buffer
+	  Rename fp to is_float and restructure if-else part for handling the different formats.
+
+2011-03-09 11:40:48 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	* gst/spectrum/gstspectrum.h:
+	  spectrum: add a GstSpecrtumChannel context structure
+	  We now keep the fft data that is related to one channel in a separate structure
+	  to prepare for multichannel support. We also refactor the code to operate more
+	  often on the channel context.
+
+2011-03-09 11:18:19 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: call the instance var spectrum instead of filter
+
+2011-03-09 11:14:37 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: don't value we already took from the gvalue
+
+2011-03-08 17:26:17 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  configure.ac
+
+2011-03-08 17:02:30 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/debugutils/efence.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/ximage/ximageutil.c:
+	  meta: update for new API
+
+2011-03-08 16:28:27 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	  Merge ad-hoc release branch '0.10.28'
+
+=== release 0.10.28 ===
+
+2011-03-08 15:47:52 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.10.28
+	  Ad-hoc release to fix build issue with newer kernels.
+
+2011-03-03 00:16:47 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/v4l2_calls.h:
+	  v4l2: remove unnecessary linux/videodev.h include
+	  Causes compilation issues with newer kernel headers where the old
+	  v4l interface has been removed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=643716
+
+2011-03-08 10:14:20 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  tests/examples/cairo/Makefile.am
+
+2011-03-07 16:56:43 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: also estimate eos if very near eos
+
+2011-03-07 16:56:18 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: avoid trying to buffer more than is available.
+	  That is, in case of short (or near eos of) stream, deadlock (until timeout)
+	  would occur trying to buffer more than is yet forthcoming.
+
+2011-03-07 11:01:06 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: reset element base_time upon flush
+	  ... to arrange for properly scheduled timeout (following seek).
+
+2011-03-07 10:54:22 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/examples/cairo/cairo_overlay.c:
+	  cairooverlay: Add a bus handler to the example to handle EOS/ERROR/WARNING
+	  Also clean up the pipeline properly.
+
+2011-03-07 10:47:23 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/examples/Makefile.am:
+	  examples: Always dist the cairo example
+
+2011-03-07 10:46:12 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/examples/cairo/Makefile.am:
+	  cairooverlay: Use LDADD instead of LDFLAGS for libs and add $(GST_LIBS)
+
+2011-03-05 23:22:58 +0000  Jon Nordby <jononor@gmail.com>
+
+	* tests/examples/Makefile.am:
+	* tests/examples/cairo/Makefile.am:
+	* tests/examples/cairo/cairo_overlay.c:
+	  cairooverlay: Remove unnecessary gtk/gtk-x11 use in example.
+	  This removes code, and allows the example to be used on any platform.
+	  Fixes bug #643981.
+
+2011-03-04 18:37:38 -0800  David Schleef <ds@schleef.org>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Use #ifdefs for V4L2_PIX_FMT_PJPG
+	  It's only recently added to kernel headers.
+
+2011-02-23 16:50:43 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	* gst/wavparse/gstwavparse.h:
+	  wavparse: tune output max buffer size to material
+	  ... to avoid ending up with tons of short time buffers for e.g. high sample
+	  rate audio.
+
+2011-03-04 17:04:37 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/examples/cairo/Makefile.am:
+	  examples: don't use hardcodec 0.10
+
+2011-03-04 16:30:36 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-03-04 15:50:01 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: add a doc example for setting stream-properties
+
+2011-03-04 15:42:19 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: fix the xml in the docs
+
+2011-03-03 00:16:47 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/v4l2_calls.h:
+	  v4l2: remove unnecessary linux/videodev.h include
+	  Causes compilation issues with newer kernel headers where the old
+	  v4l interface has been removed.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=643716
+
+2011-03-02 23:21:15 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* tests/examples/Makefile.am:
+	* tests/examples/cairo/Makefile.am:
+	* tests/examples/cairo/cairo_overlay.c:
+	  cairooverlay: The example always requires gtk-x11
+	  Check for gtk-x11 and only build the example if it's available.
+
+2011-03-02 23:14:36 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/cairo/gstcairooverlay.c:
+	* ext/cairo/gstcairooverlay.h:
+	  cairooverlay: Some minor cleanup
+
+2011-03-02 23:09:21 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* 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:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	  docs: Update inspected plugin data
+
+2011-01-28 02:14:04 +0200  Jon Nordby <jononor@gmail.com>
+
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* ext/cairo/.gitignore:
+	* ext/cairo/Makefile.am:
+	* ext/cairo/gstcairo-marshal.list:
+	* ext/cairo/gstcairo.c:
+	* ext/cairo/gstcairooverlay.c:
+	* ext/cairo/gstcairooverlay.h:
+	* tests/examples/Makefile.am:
+	* tests/examples/cairo/.gitignore:
+	* tests/examples/cairo/Makefile.am:
+	* tests/examples/cairo/cairo_overlay.c:
+	  cairooverlay: Add generic Cairo overlay video element.
+	  Allows applications to connect to the "draw" signal of
+	  the element and do their custom drawing there.
+	  Includes an example application demonstrating usage.
+	  Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=595520
+
+2011-03-02 13:00:31 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/monoscope/monoscope.c:
+	  monoscope: don't leak the monoscope_state data
+	  The monoscope_close() implementation was empty.
+
+2011-03-02 12:59:35 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/monoscope/monoscope.c:
+	  monoscope: we have 64 colors, don't access colors[64]
+	  Fixes remaining invalid read.
+
+2011-03-02 10:25:29 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: arrange for non-fatal error when parsing non-vital parts
+
+2011-03-02 10:56:33 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/monoscope/convolve.c:
+	  monoscope: stack needs to be size+1 as we put a end-marker into it
+	  Valgrind is still complaining about one bad read, but this takes care of the
+	  crash mentioned in the comment and in bug #564122.
+
+2011-03-01 22:40:19 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/examples/rtp/server-v4l2-H263p-alsasrc-AMR.sh:
+	  example: fix the variable name for the ip-address
+	  Fix the name in the launch pipeline and use a value of "localhost" by default.
+
+2011-02-28 19:16:00 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	  configure.ac: cygwin/mingw; enable plugin linking to static lib
+	  Useful for DirectX plugin(s).
+	  Fixes #642507.
+
+2011-02-28 19:13:41 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* configure.ac:
+	  configure.ac: export plugin description more platform independent
+	  Fixes #642504.
+
+2011-02-28 18:32:54 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 1de7f6a to 6aec6b9
+
+2011-02-28 13:29:47 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2011-02-28 13:28:29 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: use NetAddress metadata
+
+2011-02-28 13:14:37 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstudp.c:
+	* gst/udp/gstudpsrc.c:
+	  udp: implement NetAddress with metadata
+
+2011-02-28 10:16:52 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: register metadata
+
+2011-02-27 19:43:13 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/debugutils/efence.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/ximage/gstximagesrc.c:
+	* sys/ximage/ximageutil.c:
+	* sys/ximage/ximageutil.h:
+	  meta: fix for new API
+
+2011-02-25 16:29:38 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/debugutils/efence.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/ximage/gstximagesrc.c:
+	* sys/ximage/ximageutil.c:
+	* sys/ximage/ximageutil.h:
+	  metadata: use metadata for private buffer data
+	  Use buffer metadata to store element private data.
+
+2011-02-24 13:51:32 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/ximage/gstximagesrc.c:
+	* sys/ximage/gstximagesrc.h:
+	* sys/ximage/ximageutil.c:
+	* sys/ximage/ximageutil.h:
+	  miniobject: port to 0.11
+	  Use buffer private data instead of subclassing.
+
+2011-02-24 13:50:48 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/examples/pulse/Makefile.am:
+	* tests/examples/v4l2/Makefile.am:
+	* tests/icles/Makefile.am:
+	  build: don't hardcode version number
+
+2011-02-24 13:03:44 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/taglib/gstid3v2mux.cc:
+	  id3: use boxed type instead of miniobject
+
+2011-02-24 13:00:48 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/debugutils/efence.c:
+	* gst/replaygain/Makefile.am:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstudp.c:
+	* gst/udp/gstudpsrc.c:
+	  miniobject: use buffer private field for extra data
+	  Use the owner private field to store extra buffer data instead of using
+	  subclassing.
+
+2011-02-24 12:23:44 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: add duration when extimating QoS time
+	  When we need to decide on the next QoS time, take into account the duration of
+	  the buffers.
+
+2011-02-28 11:58:05 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+	  Conflicts:
+	  configure.ac
+
+2011-02-23 17:41:22 +0100  Philip Jägenstedt <philipj@opera.com>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: release pa_shared_resource_mutex before pa_threaded_mainloop_wait
+	  Not doing so can result in a deadlock when two threads enter
+	  gst_pulseringbuffer_open_device at the same time, as
+	  pa_threaded_mainloop_wait releases the mainloop lock while waiting,
+	  allowing another thread to take it, resulting in a deadlock as two
+	  threads waits for the lock the other is holding.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=643087
+
+2011-02-23 17:18:19 +0100  Philip Jägenstedt <philipj@opera.com>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: s/ressource/resource/
+	  https://bugzilla.gnome.org/show_bug.cgi?id=643087
+
+2011-02-25 20:12:35 -0800  David Schleef <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: remove accidental debug message
+	  in previous commit
+
+2011-02-25 19:35:51 -0800  David Schleef <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Add support for 2Vuy and r210
+
+2011-02-24 14:08:25 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	* gst/deinterlace/gstdeinterlacemethod.h:
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/scalerbob.c:
+	* gst/deinterlace/tvtime/vfir.c:
+	* gst/deinterlace/tvtime/weave.c:
+	* gst/deinterlace/tvtime/weavebff.c:
+	* gst/deinterlace/tvtime/weavetff.c:
+	  deinterlace: Add support for NV21 colorspace
+
+2011-02-24 14:00:37 +0100  Carsten Kroll <car@ximidi.com>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	* gst/deinterlace/gstdeinterlacemethod.h:
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/scalerbob.c:
+	* gst/deinterlace/tvtime/vfir.c:
+	* gst/deinterlace/tvtime/weave.c:
+	* gst/deinterlace/tvtime/weavebff.c:
+	* gst/deinterlace/tvtime/weavetff.c:
+	  deinterlace: Add support for NV12 colorspace
+	  Fixes bug #642961.
+
+2011-02-24 13:56:04 +0100  Carsten Kroll <car@ximidi.com>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: First try if upstream handles TIME seeks before handling them here
+	  Fixes bug #642963.
+
+2010-11-08 14:25:59 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  deinterlace: Simplify setcaps
+	  The current code never uses upstream negotiation so the code can be
+	  significantly simplified.
+
+2011-01-24 12:48:18 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/tvtime/greedy.c:
+	  deinterlace: Port greedyl to GstDeinterlaceSimpleMethod
+	  The main goal of this change is to reuse the complex but now neatly
+	  written scanline pointer calculation code from the simple methods.
+
+2011-02-22 15:20:11 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/id3demux/gstid3demux.c:
+	  Revert "id3demux: ensure a taglist before adding the container tag"
+	  This reverts commit a86bab66893bb1a3323a756410573c117b8219ef. The issue is
+	  fixed with commit ff5e5a8f0daa1fdf89792d0726ea063bbd99db18 instead.
+
+2011-02-22 15:19:00 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/id3demux/id3tags.c:
+	  id3demux: return ID3TAGS_BROKEN_TAG for unsupported versions
+	  This prevents us for trying to work with a NULL taglist.
+
+2011-02-22 14:15:27 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix unitialized variable.
+
+2011-02-22 14:01:27 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: ensure sane parameters when parsing superindex
+
+2011-02-22 14:00:11 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: check for NULL audio stream format header when parsing stream
+
+2011-02-22 14:52:18 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/examples/rtp/server-v4l2-H263p-alsasrc-AMR.sh:
+	* tests/examples/rtp/server-v4l2-H264-alsasrc-PCMA.sh:
+	  rtp-examples: move capsfilter behind converters
+	  We need to have the capsfilter behin the converters to make the converters
+	  convert from the formats v4l2src can do to what we request with the
+	  capsfilter.
+
+2011-02-22 14:50:59 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/examples/rtp/client-H264-PCMA.sh:
+	* tests/examples/rtp/client-PCMA.sh:
+	* tests/examples/rtp/server-alsasrc-PCMA.sh:
+	* tests/examples/rtp/server-v4l2-H263p-alsasrc-AMR.sh:
+	* tests/examples/rtp/server-v4l2-H264-alsasrc-PCMA.sh:
+	  rtp-examples: fix ascii-art
+	  Some boxes where misaligned due to long "audiotetssrc" name. Trim trailing
+	  whitespace.
+
+2011-02-22 13:29:26 +0100  Blaise Gassend <blaise at willowgarage dot com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: handle NULL demux elements
+	  When using gstrtpbin with ignore-pt=true, the free_stream function tries to
+	  call gst_element_set_locked_state and gst_element_set_state on a stream->demux
+	  which is NULL.
+	  fixes #642412
+
+2011-01-24 12:18:39 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	  deinterlace: small clean-ups
+	  Improve debug output by printing the buffer pointer when
+	  popping a buffer and simplify code to use scanlines.bottom_field
+	  as appropriate.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=642691
+
+2011-01-24 12:18:39 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: fix assigned method_id when using fallback
+	  https://bugzilla.gnome.org/show_bug.cgi?id=642691
+
+2011-02-21 17:17:32 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: fix setting the SDES property
+	  Only the sdes veriable is protected with the object lock.
+	  Use the right object when setting the sdes property.
+
+2011-02-21 12:09:07 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* ext/cairo/gsttextoverlay.c:
+	* gst/avi/gstavimux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/interleave/interleave.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/videomixer/videomixer.c:
+	  Revert "Check that collectpads exists before removing pad"
+	  This reverts commit 8e6b876e76c94410db160afe5eb30f21452e419f.
+	  Depends on a core commit that was reverted
+
+2011-02-21 00:55:49 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/icydemux/gsticydemux.c:
+	  icydemux: fix tag list handling issues that might have caused crashes
+	  Fix slightly confused tag handling in some places: make it clear when
+	  we're taking ownership of a tag list and when not. For example,
+	  gst_icydemux_tag_found() was taking ownership when the source pad
+	  existed, but otherwise not (leak). Also, gst_event_parse_tag() does
+	  not return a newly-allocated taglist, but a tag list that belongs to
+	  the tag event, so don't give ownership of it away.
+	  While we're at it, some minor clean-ups: don't re-invent g_strndup()
+	  and simplify gst_icydemux_parse_and_send_tags() a bit, and don't
+	  leak the tag list in case no valid tags where found.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=641330
+
+2011-02-20 23:39:41 -0800  David Schleef <ds@schleef.org>
+
+	* ext/cairo/gsttextoverlay.c:
+	* gst/avi/gstavimux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/interleave/interleave.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/videomixer/videomixer.c:
+	  Check that collectpads exists before removing pad
+	  The core now calls release pad from finalize, at which point
+	  the collectpads might have already been freed.
+
+2011-02-19 15:48:22 -0800  David Schleef <ds@schleef.org>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: Handle 16-bit-per-channel images
+
+2011-02-18 10:12:47 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: stream->current_total is accumulated byte size and not time
+	  Use timestamp for the stream index as well.
+
+2011-02-15 19:33:45 -0800  David Schleef <ds@schleef.org>
+
+	* gst/udp/gstmultiudpsink.c:
+	  udpsink: warn when packet is too large
+
+2011-02-17 17:59:25 -0800  David Schleef <ds@schleef.org>
+
+	* gst/matroska/Makefile.am:
+	* gst/matroska/matroska-parse.c:
+	* gst/matroska/matroska-parse.h:
+	* gst/matroska/matroska.c:
+	  matroskaparse: New element
+	  Copied from demux.  Duplicates much code, also some dead code
+	  remaining.
+
+2011-02-17 17:57:55 -0800  David Schleef <ds@schleef.org>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Earlier debug category initialization
+
+2011-01-22 00:13:16 -0800  David Schleef <ds@schleef.org>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: don't set duration for live stream
+
+2011-01-06 15:44:24 -0800  David Schleef <ds@schleef.org>
+
+	* gst/debugutils/Makefile.am:
+	* gst/debugutils/negotiation.c:
+	  debugutils: remove bitrotten negotiation element
+	  Wasn't enabled, didn't work, and planned features have been
+	  superceded by capsfilter and capsdebug.
+
+2010-09-17 12:10:38 -0700  David Schleef <ds@schleef.org>
+
+	* gst/rtp/gstrtpvrawpay.c:
+	* gst/rtp/gstrtpvrawpay.h:
+	  rtpvrawpay: Implement interlacing
+
+2011-02-17 17:57:42 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: also add the frame-type for the stream index
+
+2011-02-17 17:56:29 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: get the index writer id when the pad has a parent
+	  Otherwise the index writer has a weired name, as the pad has no parent yet.
+
+2011-02-17 14:00:48 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/avi/gstavidemux.c:
+	* gst/flv/gstflvdemux.c:
+	  avidemux, flvdemux: formatting cleanup
+	  Trim trailing whitespaces and fix the formatting of double negation.
+
+2011-02-17 13:57:37 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/avi/gstavidemux.c:
+	* gst/flv/gstflvdemux.c:
+	  avidemux, flvdemux: mark delta-units in the index
+	  We need to use the 'delta' flag for delta units and not the 'none' flag.
+
+2011-02-17 11:58:42 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/icles/.gitignore:
+	  .gitignore: ignore moved equalizer test binary
+
+2011-02-17 12:46:14 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: mark delta-unit in the index
+	  We need to use the delta flag fro delta units and not none. Print more details
+	  to the debug log.
+
+2011-02-17 12:44:01 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: formatting cleanup
+	  Trim trailing whitespaces and fix the formatting of double negation.
+
+2011-02-16 17:09:20 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: rework _request_new_pad to handle explict req-pad-names
+	  Don't ignore explicit pad-names.
+
+2011-02-16 17:06:51 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/avi/gstavimux.c:
+	  avimux: rework _request_new_pad to handle explict req-pad-names
+	  Don't ignore explicit pad-names. Rearrange the code and the error handling a
+	  bit. Add a FIXME-0.11 for the bad pad-names.
+
+2011-02-16 15:28:53 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/icles/Makefile.am:
+	  icles: Add equalizer-test to the build system
+
+2011-02-16 15:23:50 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/icles/equalizer-test.c:
+	  [MOVED FROM BAD 5/5] equalizer-test: Initialize debug category after gst_init() to fix segfault
+
+2007-11-07 15:36:59 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 4/5] tests/icles/equalizer-test.c: Fix gain ranges for the latest equalizer changes.
+	  Original commit message from CVS:
+	  * tests/icles/equalizer-test.c: (do_slider_fiddling):
+	  Fix gain ranges for the latest equalizer changes.
+
+2007-05-21 14:01:16 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  [MOVED FROM BAD 3/5] ChangeLog: ChangeLog surgery. gst/equalizer/gstiirequalizer.c (ARG_BAND_WIDTH, _do_init, ARG_GAIN, _GstIirEqualizerBa...
+	  Original commit message from CVS:
+	  * ChangeLog:
+	  ChangeLog surgery.
+	  * gst/equalizer/gstiirequalizer.c (ARG_BAND_WIDTH, _do_init, ARG_GAIN,
+	  _GstIirEqualizerBand, object, _GstIirEqualizerBandClass,
+	  parent_class, gst_iir_equalizer_band_set_property,
+	  gst_iir_equalizer_band_class_init, gst_iir_equalizer_band_get_type,
+	  gst_iir_equalizer_child_proxy_get_child_by_index,
+	  gst_iir_equalizer_child_proxy_get_children_count,
+	  gst_iir_equalizer_child_proxy_interface_init, setup_filter,
+	  gst_iir_equalizer_compute_frequencies, plugin_init):
+	  * tests/icles/equalizer-test.c:
+	  Add fixme and comment for example.
+
+2007-03-14 16:33:03 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  [MOVED FROM BAD 2/5] tests/icles/equalizer-test.c: Port the example to new equalizer api.
+	  Original commit message from CVS:
+	  * tests/icles/equalizer-test.c: (equalizer_set_band_value),
+	  (equalizer_set_all_band_values),
+	  (equalizer_set_band_value_and_wait),
+	  (equalizer_set_all_band_values_and_wait), (do_slider_fiddling),
+	  (main):
+	  Port the example to new equalizer api.
+
+2007-02-03 23:35:26 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  [MOVED FROM BAD 1/5] Fix up to use the newly ported (actually working) GstAudioFilter.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/equalizer/Makefile.am:
+	  * gst/equalizer/gstiirequalizer.c: (gst_iir_equalizer_base_init),
+	  (gst_iir_equalizer_class_init), (gst_iir_equalizer_init),
+	  (setup_filter), (gst_iir_equalizer_compute_frequencies),
+	  (gst_iir_equalizer_set_property), (gst_iir_equalizer_get_property),
+	  (gst_iir_equalizer_transform_ip), (gst_iir_equalizer_setup),
+	  (plugin_init):
+	  * gst/equalizer/gstiirequalizer.h:
+	  Fix up to use the newly ported (actually working) GstAudioFilter.
+	  Bump core/base requirements to CVS for this.
+	  * tests/icles/.cvsignore:
+	  * tests/icles/Makefile.am:
+	  * tests/icles/equalizer-test.c: (check_bus),
+	  (equalizer_set_band_value), (equalizer_set_all_band_values),
+	  (equalizer_set_band_value_and_wait),
+	  (equalizer_set_all_band_values_and_wait), (do_slider_fiddling),
+	  (main):
+	  Add brain-dead interactive test for equalizer.
+
+2011-02-15 15:59:32 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Add PJPG mapping
+	  Adds mapping of progressive jpeg format
+
+2011-02-15 16:30:20 +0100  Andy Wingo <wingo@oblong.com>
+
+	  plug qtdemux refcount leaks
+	  * gst/qtdemux/qtdemux.c (gst_qtdemux_src_convert): Unref the qtdemux; we
+	  weren't doing so before.
+	  (gst_qtdemux_handle_src_event, gst_qtdemux_chain): Fix some error
+	  cases which would leak a ref to the qtdemux.
+
+2011-02-14 20:20:08 +0100  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Add URI query handler
+	  Fixes bug #642337.
+
+2011-02-14 17:49:54 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: avoid sorting NULL array of cluster positions
+
+2011-02-14 16:46:46 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	  theorapay: handle 0 sized packets
+	  Handle 0 sized packets (repeat frame) in the payloader and depayloader.
+	  Fixes #641827
+
+2011-02-14 15:21:29 +0200  Tuukka Pasanen <tuukka.pasanen@ilmi.fi>
+
+	* gst/debugutils/gsttaginject.c:
+	  taginject: resend tags when they are changed
+	  Allow setting new tags on the property while running and send them.
+	  Fixes #640249
+
+2011-02-14 12:53:27 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From f94d739 to 1de7f6a
+
+2011-02-07 23:32:53 +0100  Miguel Angel Cabrera Moya <madmac2501@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix minor leaks when handling server requests.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=640163
+
+2011-02-14 00:49:00 +0000  Heath Nielson <heathn@gmail.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: extract MusicBrainz tags
+	  Extract MusicBrainz tags added by MusicBrainz's Picard
+	  tagger application. These tags (esp. the album id) are
+	  helpful for rhythmbox et.al. to automatically downloads
+	  cover art.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=642205
+
+2011-02-14 00:38:45 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: refactor iTunes tag parsing a bit
+
+2011-02-10 23:52:51 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst-plugins-good.doap:
+	  doap: update mailing list location
+
+2011-02-10 18:11:46 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: propagate error during expose_streams
+	  ... as it may occur during initial parsing of fragmented file.
+
+2011-02-10 18:00:11 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: avoid skipping exposing a stream following a removed stream
+
+2011-02-10 11:56:33 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: store cluster positions provided by SeekHead
+	  ... and use those, if available, to locate a cluster rather than scanning.
+
+2011-02-09 16:22:47 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: properly resume cluster scanning
+	  ... rather than getting offset tracking messed up, and then likely
+	  failing a subsequent assert.
+
+2011-02-08 10:07:43 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/id3demux/gstid3demux.c:
+	  id3demux: ensure a taglist before adding the container tag
+	  In the case of id3v1 also don't return NULL on empty tags, but also create a new
+	  taglist and add the container tag for consistency.
+
+2011-02-07 17:08:47 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: strip trailing spaces
+
+2011-02-07 17:07:42 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtpsrc: set multiple properties in one go
+	  There is no need for separate g_object_set() calls here.
+
+2011-02-03 16:10:49 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* tests/check/elements/deinterlace.c:
+	  deinterlace: Handle image caps without asserting
+	  Images might have framerate=0/1 in the caps, which caused an
+	  assertion on deinterlace. I don't know of interlaced image formats
+	  but deinterlace might be hardcoded on some generic pipelines and
+	  it shouldn't assert.
+	  The fix was to set field_duration to 0 if the input has a framerate
+	  with a 0 numerator.
+	  This patch also adds checks for this situation on the unit tests.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=641400
+
+2011-02-04 12:33:09 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/udp/gstudpsrc.c:
+	  docs: fix parameter name in udpsrc docs
+	  It is "buffer-size" and not "buffer". Also trim trailing whitespace.
+
+2011-02-03 23:42:59 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: fix interlaced set_format configuration
+	  Commit 6c8268dbfd5c88fac28c882ef2e4598a6522e2d6 broke recording
+	  from interlaced v4l2 source (e.g. typical tv capture card) since
+	  V4L2_FIELD_SEQ_TB (with fields stored separately) does not map
+	  to currently defined interlaced format (fields stored interleaved).
+	  Besides this mismatch, hardware might quite likely not support or
+	  appreciate this field value, since querying supported formats mapped
+	  _INTERLACED field formats to interlaced=true caps (so the latter should
+	  not be mapped to field value that is not known to be supported).
+
+2011-02-02 18:27:52 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  source: fix type of ntpnstime
+
+2011-02-02 18:21:26 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpbin: Get and use the NTP time when receiving RTCP
+	  When we receive an RTCP packet, get the current NTP time in nanseconds so that
+	  we can correctly calculate the round-trip time.
+
+2011-02-01 19:40:58 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsound: arrange for definition of _swab on Cygwin
+	  gstdirectsoundsink.c: In function 'gst_directsound_sink_write':
+	  gstdirectsoundsink.c:557: error: implicit declaration of function '_swab'
+	  gstdirectsoundsink.c:557: error: nested extern declaration of '_swab'
+
+2010-10-06 21:17:28 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheoradepay.h:
+	  rtptheoradepay: Request new keyframe on lost packets
+	  Theora can only use the last frame (or the keyframe) as a reference, so in
+	  practice. If we receive a buffer that references an unknown codebook, request
+	  new headers. It probably means that headers were lost.
+
+2010-08-27 14:11:53 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin-marshal.list:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Add action signal to request early RTCP
+
+2010-08-27 16:11:06 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Add callback to get the current time
+
+2010-10-19 22:21:54 +0200  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Don't relay more than one PLI request per RTT
+	  Drop PLI requests if one was relay in the last RTT, the other side may
+	  just not have received the keyframe yet.
+
+2010-06-23 16:43:24 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Send GstForceKeyUnit event in response to received RTCP PLI
+
+2010-11-24 15:27:46 -0500  Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  gstrtpsession: Fallback for FIR to PLI if PLI isn't available
+
+2010-06-22 19:56:50 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Implement sending PLI packets in response to GstForceKeyUnit
+
+2010-06-22 13:33:32 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpsource: Retain RTCP Feedback packets for a specified amount of time
+
+2010-09-07 13:35:16 +0300  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Make rtcp buffer metadata writable after processing it
+	  Functions that process the rtcp buffer could decide to keep a ref
+	  on the buffer for further processing. So make the metadata writable
+	  only after they are done.
+
+2010-06-17 17:34:19 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin-marshal.list:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Emit signal on incoming RTCP FB packet
+
+2011-02-01 18:17:13 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: fix compilation
+
+2010-06-15 18:39:47 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Add method to request early RTCP packet
+	  Implement the early mode defined in RFC 4585. In this mode, RTCP feedback
+	  packets are sent early to notifier.
+
+2010-06-01 19:28:01 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpstats.c:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpsession: Add property for minimum interval between Regular RTCP messages
+	  This can be changed according to RFC 4585
+
+2010-06-14 18:40:33 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin-marshal.list:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: Emit signal when sending a compound RTCP packet
+	  This allows users to add extra RTCP packets to the compound
+	  RTCP packet.
+
+2010-06-19 19:11:06 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpptdemux.c:
+	  rtpptdemux: Tag upstream custom events with payload type
+
+2010-06-18 19:12:40 -0400  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Tag upstream custom events with SSRC
+
+2010-10-01 17:19:16 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Emit "on-ssrc-validated" when validating by RTCP
+	  Emit "on-ssrc-validated" if the SSRC is validated by receiving
+	  a RTCP SDES packet.
+
+2011-02-01 16:38:20 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpj2kpay.c:
+	  j2kpay: skip EPH packets
+	  Include EPH markers into the previous chunk of packets.
+
+2011-01-31 17:56:18 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmapay.h:
+	  rtppcmapay: Rename the class to have the right name
+	  It was name pmca instead of pcma and made debug logs hard to search.
+
+2011-01-31 05:58:36 +0100  David Henningsson <david.henningsson@canonical.com>
+
+	* ext/pulse/pulsesink.c:
+	  Pulsesink: Allow chunks up to bufsize instead of segsize
+	  By allowing larger chunks to be sent, PulseAudio will have a
+	  lower CPU usage. This is especially important on low-end machines,
+	  where PulseAudio can crash if packets are coming in at a higher
+	  rate than PulseAudio can process them.
+	  Signed-off-by: David Henningsson <david.henningsson@canonical.com>
+
+2011-01-31 13:44:45 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: simplify template caps
+	  We can merge all the YUV variants into one single structure.
+
+2011-01-27 15:35:06 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  win32: fix DEFAULT_AUDIOSINK, should be direct*sound*sink
+	  https://bugzilla.gnome.org/show_bug.cgi?id=640705
+
+2011-01-27 16:02:46 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: initialize local variable to please mingw32 compiler
+
+2011-01-26 22:21:31 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudpnetutils.h:
+	* gst/udp/gstudpsrc.c:
+	  udp: use socklen_t where appropriate rather than custom type
+	  In particular, fixes Cygwin build where socklen_t is defined as int
+	  in line with native win32 api definition.
+
+2011-01-27 12:16:46 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: mind rounding issues when converting from global time to mov time
+	  In particular, this avoids missing the intended keyframe when first converting
+	  from the frame's mov time to global segment time, and then back from global
+	  time to mov time when activating the segment.
+
+2011-01-26 08:48:43 +0000  Ognyan Tonchev <ognyan.tonchev@axis.com>
+
+	* gst/matroska/ebml-write.c:
+	* tests/check/elements/matroskamux.c:
+	  matroskamux: don't leak ebml writer caps when re-using matroskamux
+	  https://bugzilla.gnome.org/show_bug.cgi?id=640542
+
+2011-01-25 21:56:19 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: don't divide by 0
+
+2011-01-18 14:48:04 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: pull mode should always report seekable
+	  ... as it no longer requires an index, but can seek by scanning as well.
+
+2011-01-10 12:34:22 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	  qtdemux: support some more mpeg-4 fourcc variants
+
+2011-01-10 12:34:03 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: simplify retrieving stsd child entry atom
+
+2011-01-24 18:27:52 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Don't consider 0 fcc_handler as uncompressed.
+	  Just avoids a warning
+
+2011-01-20 12:14:08 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: take configured start time into account
+	  when creating the newsegment event, take the configured start time
+	  into account.
+
+2011-01-24 15:11:02 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix printf format warning on mingw32
+	  Make win32 build bot happy again, and nicefy output while we're at it.
+	  qtdemux.c: In function 'qtdemux_parse_trun':
+	  qtdemux.c:2162:3: error: format '%lu' expects type 'long unsigned int', but argument 9 has type 'guint32'
+
+2011-01-24 13:39:58 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/examples/rtp/client-H263p-AMR.sh:
+	* tests/examples/rtp/client-H263p-PCMA.sh:
+	* tests/examples/rtp/client-H264-PCMA.sh:
+	* tests/examples/rtp/client-PCMA.sh:
+	  examples: autoaudisink -> autoaudiosink in RTP examples
+
+2011-01-24 00:32:41 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/gst-plugins-good-plugins.prerequisites:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	  Back to development
+
+=== release 0.10.27 ===
+
+2011-01-21 12:54:16 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.10.27
+
+2011-01-20 14:10:55 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	  h264depay: don't leak codec data buffer in byte-stream=true mode
+	  https://bugzilla.gnome.org/show_bug.cgi?id=640063
+
+2011-01-20 13:41:33 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: don't leak url string
+	  https://bugzilla.gnome.org/show_bug.cgi?id=640064
+
+2011-01-20 11:45:47 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Gracefully handle mov files misusing the WAVE atoms
+	  Check that the WAVEHEADER node is present instead of blindly using it.
+	  If not present we won't be able to provide a more refined caps, but at
+	  least we won't crash.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=640028
+
+2011-01-20 00:07:33 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: fix accidental breakage of navigation interface support
+
+2011-01-18 12:58:29 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.10.26.4 pre-release
+
+2011-01-12 14:03:57 -0800  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	  deinterlace: rewrite how neighboring scan lines are calculated
+	  Old code was difficult to understand exactly how the neighboring
+	  scan lines are calculated, and it appeared that some were off by
+	  +2 or -2, depending on the field flag.  Fixes #639321.
+
+2011-01-18 09:33:06 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/avi/gstavisubtitle.c:
+	  avisubtitle: set caps on srcpad to fix issue with discoverer
+	  Set caps from the start so discoverer doesn't blow up on
+	  seeing no negotiated caps between elements on preroll,
+	  which might happen if no subtitle buffers have been
+	  pushed yet at the time. See file from bug #603308.
+
+2011-01-17 20:09:16 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Uncork stream while flushing the ringbuffer
+	  After starting the ringbuffer, we wait for enough data to arrive before
+	  uncorking the stream. This will cause the pipeline to stall if we get an
+	  EOS (or otherwise need to flush the stream) before sufficient data
+	  becomes available. This patch makes sure that the stream is uncorked
+	  while flushing to avoid this problem.
+	  Fixes issue with a webkit unit test testing reverse playback of
+	  an MP4 H.264/AAC file.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=639740
+
+2011-01-14 14:51:51 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: avoid creating caps from string when possible
+	  Fixes #639516.
+
+2011-01-14 14:48:49 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: set src pad caps when starting file
+	  Fixes #639516.
+
+2011-01-12 20:38:59 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: define V4L2_FIELD_INTERLACED_{TB,BT} if not available in header
+	  Older kernels don't have these, and there's no easy way to check for the
+	  existance of enums that doesn't involve a configure check, so just define
+	  these if the V4L2_CAP_VIDEO_OUTPUT_OVERLAY define is not there, which was
+	  added in the same commit as the TB/BT enum. Fixes compilation on CentOS 5.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=639339
+
+2011-01-11 23:18:59 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.10.26.3 pre-release
+
+2011-01-11 22:42:42 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* 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:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	  docs: update docs
+
+2011-01-11 23:39:12 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Make corking during pause synchronous
+	  This makes the call to pa_stream_cork() during ringbuffer pause()
+	  synchronous, which makes sure that the clock does not advance after we
+	  take a snapshot for start_time.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=639240
+
+2011-01-11 19:33:16 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/da.po:
+	* po/gl.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/sl.po:
+	* po/sv.po:
+	* po/tr.po:
+	  po: update translations
+
+2011-01-11 15:50:28 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From e572c87 to f94d739
+
+2011-01-10 16:36:19 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From ccbaa85 to e572c87
+
+2011-01-10 14:53:39 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 46445ad to ccbaa85
+
+2011-01-07 13:24:02 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.10.26.2 pre-release
+
+2011-01-07 13:06:38 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: update translations
+
+2011-01-07 02:32:20 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: fix compiler warnings caused by -DG_DISABLE_ASSERT
+
+2011-01-07 02:06:51 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/ebml-read.c:
+	  matroska: don't put essential function calls into g_assert()
+	  g_assert() will expand to NOOPs if -DG_DISABLE_ASSERT is passed.
+
+2011-01-07 01:35:45 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: don't put functional code like ioctl calls into g_return_if_fail()
+	  These macros will expand to NOOPs given the right defines. Also,
+	  g_return_if_fail() and friends are meant to be used to catch programming
+	  errors (like invalid input to functions), not runtime error handling.
+
+2011-01-07 01:11:02 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	  tests: never disable g_assert() and cast checks for the unit tests
+	  The unit tests are riddled with g_assert() and friends, make sure we
+	  don't disable assert and cast checks for the unit tests even if
+	  this has been specified for the rest of the code base, e.g. via
+	  --disable-glib-asserts.
+
+2011-01-06 12:29:21 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4adepay.c:
+	  rtp: Fix unitialized variables on macosx
+
+2011-01-06 12:28:58 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux_dump.c:
+	  qtdemux: Fix unitialized variables on macosx
+
+2011-01-05 17:49:16 -0800  David Schleef <ds@schleef.org>
+
+	* gst/debugutils/gstcapsdebug.c:
+	  capsdebug: Add capdebug debug category
+
+2010-12-11 12:42:10 -0800  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Change the default to linear
+	  The previous default, greedyh, takes 4 times as long as MPEG-2
+	  video decoding, and is unlikely fast enough on any current CPU
+	  to play 1080i video in real-time.  greedyl isn't much faster.
+	  linear was chosen over vfir, since the quality advantage of vfir
+	  is minimal compared to the occasional visual artifacts and slower
+	  processing.
+
+2011-01-05 18:32:58 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: don't confuse return values
+	  Return a return value of the right type.
+
+2011-01-05 16:24:13 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_dump.c:
+	  qtdemux: Fix unitialized variables on macosx
+
+2011-01-05 15:03:32 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  vrawdepay: fix length check
+	  Add some more debugging.
+	  Add the length check so we don't cause unneeded warnings.
+
+2011-01-05 12:04:03 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	  multiudpsink: add buffer-size property
+	  Add buffer-size property to configure the kernel send buffer.
+
+2011-01-03 20:16:22 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: remove unused variables when debug-logging disabled
+
+2011-01-03 20:06:35 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: remove unused variables when debug-logging disabled
+
+2011-01-03 18:05:15 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/libcaca/gstcacasink.c:
+	  cacasink: fix masks and strides
+	  Use the right endianness to read the masks.
+	  Use the right strides for the bitmap.
+	  Fixes #638569
+
+2011-01-03 01:18:06 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: undo presumably accidental enablement of the GstXOverlay interface
+	  Looks like this got enabled by accident when adding it to v4l2sink,
+	  so undo this for now. Not sure it makes much sense in a GStreamer
+	  context with current hardware.
+
+2011-01-03 15:40:11 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: increase udp buffer size
+	  Set a bigger UDP buffer size by default to reduce packet loss with
+	  high bitrate streams.
+
+2011-01-02 19:19:27 -0800  David Schleef <ds@schleef.org>
+
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesink.h:
+	  multifilesink: send stream headers in key-frame mode
+
+2011-01-02 19:43:02 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jack/Makefile.am:
+	* ext/jack/README:
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: fix up element details and some other minor clean-ups
+
+2011-01-02 19:23:51 +0000  Erich Schubert <erich@debian.org>
+
+	* gst/id3demux/id3v2frames.c:
+	  id3demux: fix parsing of ID3v2.4 genre frames with multiple genres
+	  We'd only extract the first genre (multiple times) instead of all
+	  genres.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=638535
+
+2011-01-02 17:40:41 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: template caps had lists with one value, just use value directly
+
+2011-01-02 17:07:19 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: make get_type functions thread-safe
+	  Because we can (shouldn't be needed with other workarounds still there).
+
+2011-01-02 15:27:19 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* 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:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	  docs: update plugin docs
+
+2011-01-02 15:25:41 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* .gitignore:
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/inspect/plugin-jack.xml:
+	* ext/Makefile.am:
+	* gst-plugins-good.spec.in:
+	* tests/examples/Makefile.am:
+	* tests/examples/jack/Makefile.am:
+	  jack: new jackaudiosrc and jackaudiosink elements, moved from gst-plugins-bad
+	  https://bugzilla.gnome.org/show_bug.cgi?id=621929
+
+2010-10-19 16:23:23 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  various (ext): add missing G_PARAM_STATIC_STRINGS flags
+	  Canonicalize property names as needed.
+
+2010-09-09 14:49:06 -0400  Tristan Matthews <le.businessman@gmail.com>
+
+	* ext/jack/Makefile.am:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: added translatable text for server not found error
+
+2010-09-06 17:17:54 -0400  Tristan Matthews <le.businessman@gmail.com>
+
+	* tests/examples/jack/Makefile.am:
+	* tests/examples/jack/jack_client.c:
+	  examples: add test to demonstrate jack_client_t usage
+
+2010-09-06 16:11:31 -0400  Tristan Matthews <le.businessman@gmail.com>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	* ext/jack/gstjackaudioclient.c:
+	* ext/jack/gstjackaudioclient.h:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosink.h:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jack/gstjackaudiosrc.h:
+	  jack: added client property
+
+2010-06-17 16:26:07 -0400  Tristan Matthews <tristan@sat.qc.ca>
+
+	* ext/jack/gstjackbin.c:
+	  jack: removed unused file gstjackbin.c
+	  This is a 0.8 leftover.
+
+2010-05-13 12:55:29 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jack/gstjackaudiosrc.c:
+	  jacksrc: make sure we always read nframes
+	  Error out when we are asked to read a different size that what was configured as
+	  the jack period size because that would mean something else is wrong.
+	  Fixes #618409
+
+2010-05-11 17:56:31 -0400  Tristan Matthews <tristan@sat.qc.ca>
+
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jack/gstjackaudiosrc.h:
+	  jack: improve process_cb
+
+2010-04-27 10:48:32 -0400  Tristan Matthews <tristan@tristan-laptop.(none)>
+
+	* ext/jack/Makefile.am:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jack/gstjackutil.c:
+	* ext/jack/gstjackutil.h:
+	  jack: implement multichannel support correctly for jackaudiosrc
+	  Fixes parts of bug #616541.
+
+2010-04-27 11:21:16 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	* ext/jack/gstjackringbuffer.h:
+	  jack: remove empty dispose and finalize methods
+
+2010-04-27 10:59:00 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: don't leak caps
+	  Add dispose methods to clear caps.
+
+2010-04-27 10:34:24 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: don't use GST_DEBUG_FUNCPTR for gobject vmethods
+
+2010-03-24 15:59:53 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: fix element name in section doc blob
+
+2010-03-22 16:56:03 +0100  Benjamin Otte <otte@redhat.com>
+
+	* ext/jack/gstjackaudiosrc.c:
+	  Add -Wold-style-definition
+	  and fix the warnings
+
+2010-03-21 21:39:18 +0100  Benjamin Otte <otte@redhat.com>
+
+	* ext/jack/gstjack.h:
+	  Add -Wmissing-declarations -Wmissing-prototypes to configure flags
+	  And fix all warnings
+
+2010-03-18 17:30:26 +0100  Benjamin Otte <otte@redhat.com>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  gst_element_class_set_details => gst_element_class_set_details_simple
+
+2009-10-12 09:06:37 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: ensure segtotal is at least 2
+	  Not only adjust buffer-time and avoid segtotal=0, but instead ensure segtotal is
+	  atleast 2. Do same change on jacksrc. We could also check the latency and buffer
+	  time configured by the client and adjust buffer-time so that we get to the same
+	  number of segments.
+
+2009-10-12 00:51:27 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jack/gstjackaudiosink.c:
+	  jack: don't crash in ringbuffer with SIGFPE on small buffer-times
+	  Jack overrides user-specified latency-time with the one it gets from jack
+	  itself. It also needs to adjust buffer-time somewhat to avoid segtotal being 0
+
+2009-05-11 16:12:54 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jack/gstjackaudioclient.c:
+	* ext/jack/gstjackaudiosink.c:
+	  jack: when stopping playback, do one more cycle to flush the port. Fixes #582167
+	  The gst_jack_audio_client_set_active() flags the port as deactivating and uses
+	  a GCond to wait until the jack_process_cb() has run once more and cleared the
+	  flag. This way the client zero's the buffer. This happens if one manyally go
+	  to PAUSED and then to READY, while leting the mainloop run inbetween.
+
+2009-03-16 11:21:02 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	* ext/jack/gstjackaudiosink.c:
+	* ext/jack/gstjackaudiosrc.c:
+	  jack: Add new connection mode
+	  Add a new connection mode to jacksrc and jacksink. In this new auto-force
+	  connection mode jack will create as many ports as requested/needed in the
+	  pipeline and will then connect as many physical ports as possible, possibly
+	  leaving some ports unconnected.
+	  Also get rid of some leftover g_print.
+	  Fixes #575284.
+
+2008-11-23 17:50:08 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/jack/: Query port latencies for sink/src delays.
+	  Original commit message from CVS:
+	  * ext/jack/gstjackaudiosink.c:
+	  * ext/jack/gstjackaudiosrc.c:
+	  Query port latencies for sink/src delays.
+	  * ext/jack/gstjackbin.c:
+	  No printf please.
+
+2008-11-04 12:42:30 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Don't install static libs for plugins. Fixes #550851 for -bad.
+	  Original commit message from CVS:
+	  * ext/alsaspdif/Makefile.am:
+	  * ext/amrwb/Makefile.am:
+	  * ext/apexsink/Makefile.am:
+	  * ext/arts/Makefile.am:
+	  * ext/artsd/Makefile.am:
+	  * ext/audiofile/Makefile.am:
+	  * ext/audioresample/Makefile.am:
+	  * ext/bz2/Makefile.am:
+	  * ext/cdaudio/Makefile.am:
+	  * ext/celt/Makefile.am:
+	  * ext/dc1394/Makefile.am:
+	  * ext/dirac/Makefile.am:
+	  * ext/directfb/Makefile.am:
+	  * ext/divx/Makefile.am:
+	  * ext/dts/Makefile.am:
+	  * ext/faac/Makefile.am:
+	  * ext/faad/Makefile.am:
+	  * ext/gsm/Makefile.am:
+	  * ext/hermes/Makefile.am:
+	  * ext/ivorbis/Makefile.am:
+	  * ext/jack/Makefile.am:
+	  * ext/jp2k/Makefile.am:
+	  * ext/ladspa/Makefile.am:
+	  * ext/lcs/Makefile.am:
+	  * ext/libfame/Makefile.am:
+	  * ext/libmms/Makefile.am:
+	  * ext/metadata/Makefile.am:
+	  * ext/mpeg2enc/Makefile.am:
+	  * ext/mplex/Makefile.am:
+	  * ext/musepack/Makefile.am:
+	  * ext/musicbrainz/Makefile.am:
+	  * ext/mythtv/Makefile.am:
+	  * ext/nas/Makefile.am:
+	  * ext/neon/Makefile.am:
+	  * ext/ofa/Makefile.am:
+	  * ext/polyp/Makefile.am:
+	  * ext/resindvd/Makefile.am:
+	  * ext/sdl/Makefile.am:
+	  * ext/shout/Makefile.am:
+	  * ext/snapshot/Makefile.am:
+	  * ext/sndfile/Makefile.am:
+	  * ext/soundtouch/Makefile.am:
+	  * ext/spc/Makefile.am:
+	  * ext/swfdec/Makefile.am:
+	  * ext/tarkin/Makefile.am:
+	  * ext/theora/Makefile.am:
+	  * ext/timidity/Makefile.am:
+	  * ext/twolame/Makefile.am:
+	  * ext/x264/Makefile.am:
+	  * ext/xine/Makefile.am:
+	  * ext/xvid/Makefile.am:
+	  * gst-libs/gst/app/Makefile.am:
+	  * gst-libs/gst/dshow/Makefile.am:
+	  * gst/aiffparse/Makefile.am:
+	  * gst/app/Makefile.am:
+	  * gst/audiobuffer/Makefile.am:
+	  * gst/bayer/Makefile.am:
+	  * gst/cdxaparse/Makefile.am:
+	  * gst/chart/Makefile.am:
+	  * gst/colorspace/Makefile.am:
+	  * gst/dccp/Makefile.am:
+	  * gst/deinterlace/Makefile.am:
+	  * gst/deinterlace2/Makefile.am:
+	  * gst/dvdspu/Makefile.am:
+	  * gst/festival/Makefile.am:
+	  * gst/filter/Makefile.am:
+	  * gst/flacparse/Makefile.am:
+	  * gst/flv/Makefile.am:
+	  * gst/games/Makefile.am:
+	  * gst/h264parse/Makefile.am:
+	  * gst/librfb/Makefile.am:
+	  * gst/mixmatrix/Makefile.am:
+	  * gst/modplug/Makefile.am:
+	  * gst/mpeg1sys/Makefile.am:
+	  * gst/mpeg4videoparse/Makefile.am:
+	  * gst/mpegdemux/Makefile.am:
+	  * gst/mpegtsmux/Makefile.am:
+	  * gst/mpegvideoparse/Makefile.am:
+	  * gst/mve/Makefile.am:
+	  * gst/nsf/Makefile.am:
+	  * gst/nuvdemux/Makefile.am:
+	  * gst/overlay/Makefile.am:
+	  * gst/passthrough/Makefile.am:
+	  * gst/pcapparse/Makefile.am:
+	  * gst/playondemand/Makefile.am:
+	  * gst/rawparse/Makefile.am:
+	  * gst/real/Makefile.am:
+	  * gst/rtjpeg/Makefile.am:
+	  * gst/rtpmanager/Makefile.am:
+	  * gst/scaletempo/Makefile.am:
+	  * gst/sdp/Makefile.am:
+	  * gst/selector/Makefile.am:
+	  * gst/smooth/Makefile.am:
+	  * gst/smoothwave/Makefile.am:
+	  * gst/speed/Makefile.am:
+	  * gst/speexresample/Makefile.am:
+	  * gst/stereo/Makefile.am:
+	  * gst/subenc/Makefile.am:
+	  * gst/tta/Makefile.am:
+	  * gst/vbidec/Makefile.am:
+	  * gst/videodrop/Makefile.am:
+	  * gst/videosignal/Makefile.am:
+	  * gst/virtualdub/Makefile.am:
+	  * gst/vmnc/Makefile.am:
+	  * gst/y4m/Makefile.am:
+	  * sys/acmenc/Makefile.am:
+	  * sys/cdrom/Makefile.am:
+	  * sys/dshowdecwrapper/Makefile.am:
+	  * sys/dshowsrcwrapper/Makefile.am:
+	  * sys/dvb/Makefile.am:
+	  * sys/dxr3/Makefile.am:
+	  * sys/fbdev/Makefile.am:
+	  * sys/oss4/Makefile.am:
+	  * sys/qcam/Makefile.am:
+	  * sys/qtwrapper/Makefile.am:
+	  * sys/vcd/Makefile.am:
+	  * sys/wininet/Makefile.am:
+	  * win32/common/config.h:
+	  Don't install static libs for plugins. Fixes #550851 for -bad.
+
+2008-09-17 13:59:21 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Fix compiler warnings on OS/X
+	  Original commit message from CVS:
+	  * ext/jack/gstjackaudiosink.c: (jack_process_cb):
+	  * gst/rtpmanager/rtpjitterbuffer.c: (calculate_skew):
+	  Fix compiler warnings on OS/X
+
+2008-08-07 13:15:21 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/jack/gstjackaudiosrc.c: Try committing this once again. Now properly renamed.
+	  Original commit message from CVS:
+	  * ext/jack/gstjackaudiosrc.c:
+	  Try committing this once again. Now properly renamed.
+
+2008-08-07 09:09:44 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/: docs/plugins/inspect/plugin-jack.xml
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-bad-plugins.args:
+	  * docs/plugins/gst-plugins-bad-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-bad-plugins.interfaces:
+	  * docs/plugins/gst-plugins-bad-plugins.prerequisites:
+	  * docs/plugins/inspect/plugin-jack.xml
+	  Add new element to docs.
+	  * ext/jack/gstjack.h
+	  Add missing file.
+	  * ext/jack/gstjackaudiosrc.c:
+	  * ext/jack/gstjackaudiosrc.h:
+	  Rename jackaudiosrc to jack_audio_src.
+
+2008-08-07 08:47:40 +0000  Tristan Matthews <tristan@sat.qc.ca>
+
+	  ext/jack/: Add a jackaudiosrc. Refactor sink slightly for better code reuse.
+	  Original commit message from CVS:
+	  patch by: Tristan Matthews <tristan@sat.qc.ca>
+	  * ext/jack/Makefile.am:
+	  * ext/jack/gstjack.c:
+	  * ext/jack/gstjackaudioclient.c:
+	  * ext/jack/gstjackaudiosink.c:
+	  * ext/jack/gstjackaudiosink.h:
+	  * ext/jack/gstjackaudiosrc.c:
+	  * ext/jack/gstjackaudiosrc.h:
+	  * ext/jack/gstjackringbuffer.h:
+	  Add a jackaudiosrc. Refactor sink slightly for better code reuse.
+	  Fixes #545197.
+
+2008-06-13 11:59:23 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/: docs/plugins/inspect/plugin-mythtv.xml
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-bad-plugins.args:
+	  * docs/plugins/gst-plugins-bad-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-bad-plugins.interfaces:
+	  * docs/plugins/gst-plugins-bad-plugins.prerequisites:
+	  * docs/plugins/gst-plugins-bad-plugins.signals:
+	  * docs/plugins/inspect/plugin-alsaspdif.xml:
+	  * docs/plugins/inspect/plugin-amrwb.xml:
+	  * docs/plugins/inspect/plugin-app.xml:
+	  * docs/plugins/inspect/plugin-bayer.xml:
+	  * docs/plugins/inspect/plugin-bz2.xml:
+	  * docs/plugins/inspect/plugin-cdaudio.xml:
+	  * docs/plugins/inspect/plugin-cdxaparse.xml:
+	  * docs/plugins/inspect/plugin-dtsdec.xml:
+	  * docs/plugins/inspect/plugin-dvb.xml:
+	  * docs/plugins/inspect/plugin-dvdspu.xml:
+	  * docs/plugins/inspect/plugin-faac.xml:
+	  * docs/plugins/inspect/plugin-faad.xml:
+	  * docs/plugins/inspect/plugin-fbdevsink.xml:
+	  * docs/plugins/inspect/plugin-festival.xml:
+	  * docs/plugins/inspect/plugin-filter.xml:
+	  * docs/plugins/inspect/plugin-flvdemux.xml:
+	  * docs/plugins/inspect/plugin-freeze.xml:
+	  * docs/plugins/inspect/plugin-gsm.xml:
+	  * docs/plugins/inspect/plugin-gstinterlace.xml:
+	  * docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	  * docs/plugins/inspect/plugin-h264parse.xml:
+	  * docs/plugins/inspect/plugin-interleave.xml:
+	  * docs/plugins/inspect/plugin-jack.xml:
+	  * docs/plugins/inspect/plugin-ladspa.xml:
+	  * docs/plugins/inspect/plugin-metadata.xml:
+	  * docs/plugins/inspect/plugin-mms.xml:
+	  * docs/plugins/inspect/plugin-modplug.xml:
+	  * docs/plugins/inspect/plugin-mpeg2enc.xml:
+	  * docs/plugins/inspect/plugin-mpeg4videoparse.xml:
+	  * docs/plugins/inspect/plugin-mpegtsparse.xml:
+	  * docs/plugins/inspect/plugin-mpegvideoparse.xml:
+	  * docs/plugins/inspect/plugin-musepack.xml:
+	  * docs/plugins/inspect/plugin-musicbrainz.xml:
+	  * docs/plugins/inspect/plugin-mve.xml:
+	  * docs/plugins/inspect/plugin-mythtv.xml
+	  * docs/plugins/inspect/plugin-nas.xml:
+	  * docs/plugins/inspect/plugin-neon.xml:
+	  * docs/plugins/inspect/plugin-nsfdec.xml:
+	  * docs/plugins/inspect/plugin-nuvdemux.xml:
+	  * docs/plugins/inspect/plugin-oss4.xml
+	  * docs/plugins/inspect/plugin-rawparse.xml:
+	  * docs/plugins/inspect/plugin-real.xml:
+	  * docs/plugins/inspect/plugin-replaygain.xml:
+	  * docs/plugins/inspect/plugin-rfbsrc.xml:
+	  * docs/plugins/inspect/plugin-sdl.xml:
+	  * docs/plugins/inspect/plugin-sdp.xml:
+	  * docs/plugins/inspect/plugin-selector.xml:
+	  * docs/plugins/inspect/plugin-sndfile.xml:
+	  * docs/plugins/inspect/plugin-soundtouch.xml:
+	  * docs/plugins/inspect/plugin-spcdec.xml:
+	  * docs/plugins/inspect/plugin-speed.xml:
+	  * docs/plugins/inspect/plugin-speexresample.xml:
+	  * docs/plugins/inspect/plugin-stereo.xml:
+	  * docs/plugins/inspect/plugin-subenc.xml
+	  * docs/plugins/inspect/plugin-timidity.xml:
+	  * docs/plugins/inspect/plugin-tta.xml:
+	  * docs/plugins/inspect/plugin-vcdsrc.xml:
+	  * docs/plugins/inspect/plugin-videosignal.xml:
+	  * docs/plugins/inspect/plugin-vmnc.xml:
+	  * docs/plugins/inspect/plugin-wildmidi.xml:
+	  * docs/plugins/inspect/plugin-x264.xml:
+	  * docs/plugins/inspect/plugin-xvid.xml:
+	  * docs/plugins/inspect/plugin-y4menc.xml:
+	  * ext/amrwb/gstamrwbdec.c:
+	  * ext/amrwb/gstamrwbenc.c:
+	  * ext/amrwb/gstamrwbparse.c:
+	  * ext/dc1394/gstdc1394.c:
+	  * ext/directfb/dfbvideosink.c:
+	  * ext/ivorbis/vorbisdec.c:
+	  * ext/jack/gstjackaudiosink.c:
+	  * ext/mpeg2enc/gstmpeg2enc.cc:
+	  * ext/mplex/gstmplex.cc:
+	  * ext/musicbrainz/gsttrm.c:
+	  * ext/mythtv/gstmythtvsrc.c:
+	  * ext/theora/theoradec.c:
+	  * ext/timidity/gsttimidity.c:
+	  * ext/timidity/gstwildmidi.c:
+	  * gst-libs/gst/app/gstappsink.c:
+	  * gst/deinterlace/gstdeinterlace.c:
+	  * gst/dvdspu/gstdvdspu.c:
+	  * gst/festival/gstfestival.c:
+	  * gst/freeze/gstfreeze.c:
+	  * gst/interleave/deinterleave.c:
+	  * gst/interleave/interleave.c:
+	  * gst/modplug/gstmodplug.cc:
+	  * gst/nuvdemux/gstnuvdemux.c:
+	  Add missing elements to docs. Fix doc-markup: use convinience syntax
+	  for examples (produces valid docbook), add several refsec2 when we
+	  have several titles. Fix some types.
+
+2008-06-12 14:49:18 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Do not use short_description in section docs for elements. We extract them from element details and there will be war...
+	  Original commit message from CVS:
+	  * ext/dc1394/gstdc1394.c:
+	  * ext/ivorbis/vorbisdec.c:
+	  * ext/jack/gstjackaudiosink.c:
+	  * ext/metadata/gstmetadatademux.c:
+	  * ext/mythtv/gstmythtvsrc.c:
+	  * ext/theora/theoradec.c:
+	  * gst-libs/gst/app/gstappsink.c:
+	  * gst/bayer/gstbayer2rgb.c:
+	  * gst/deinterlace/gstdeinterlace.c:
+	  * gst/rawparse/gstaudioparse.c:
+	  * gst/rawparse/gstvideoparse.c:
+	  * gst/rtpmanager/gstrtpbin.c:
+	  * gst/rtpmanager/gstrtpclient.c:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  * gst/rtpmanager/gstrtpptdemux.c:
+	  * gst/rtpmanager/gstrtpsession.c:
+	  * gst/rtpmanager/gstrtpssrcdemux.c:
+	  * gst/selector/gstinputselector.c:
+	  * gst/selector/gstoutputselector.c:
+	  * gst/videosignal/gstvideoanalyse.c:
+	  * gst/videosignal/gstvideodetect.c:
+	  * gst/videosignal/gstvideomark.c:
+	  * sys/oss4/oss4-mixer.c:
+	  * sys/oss4/oss4-sink.c:
+	  * sys/oss4/oss4-source.c:
+	  Do not use short_description in section docs for elements. We extract
+	  them from element details and there will be warnings if they differ.
+	  Also fixing up the ChangeLog order.
+
+2008-05-26 17:52:21 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/jack/gstjackaudiosink.c: Include the element name in the port name to avoid duplicate port names.
+	  Original commit message from CVS:
+	  * ext/jack/gstjackaudiosink.c:
+	  (gst_jack_audio_sink_allocate_channels):
+	  Include the element name in the port name to avoid duplicate port names.
+
+2008-04-06 20:18:16 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/jack/gstjackaudiosink.c: Work around missing bits of thread-safety on older GLibs some more to avoid assertions w...
+	  Original commit message from CVS:
+	  * ext/jack/gstjackaudiosink.c: (gst_jack_audio_sink_class_init):
+	  Work around missing bits of thread-safety on older GLibs some
+	  more to avoid assertions when starting up multiple playbin
+	  objects concurrently (see #512382).
+
+2008-03-13 14:25:20 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Use GST_LICENSE, GST_PACKAGE_NAME and GST_PACKAGE_ORIGIN instead of hardcoding values where possible. Fixes bug #522212.
+	  Original commit message from CVS:
+	  * ext/alsaspdif/alsaspdifsink.c:
+	  * ext/gsm/gstgsm.c:
+	  * ext/jack/gstjack.c:
+	  * ext/libmms/gstmms.c:
+	  * ext/neon/gstneonhttpsrc.c:
+	  * ext/shout/gstshout.c:
+	  * ext/timidity/gsttimidity.c:
+	  * ext/timidity/gstwildmidi.c:
+	  * gst/nuvdemux/gstnuvdemux.c:
+	  * gst/tta/gsttta.c:
+	  Use GST_LICENSE, GST_PACKAGE_NAME and GST_PACKAGE_ORIGIN instead
+	  of hardcoding values where possible. Fixes bug #522212.
+
+2007-07-18 07:42:47 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/jack/gstjackaudiosink.c: Add stdlib include here too.
+	  Original commit message from CVS:
+	  * ext/jack/gstjackaudiosink.c: (gst_jack_ring_buffer_open_device),
+	  (gst_jack_ring_buffer_acquire):
+	  Add stdlib include here too.
+
+2007-04-04 07:36:28 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/jack/gstjackaudiosink.c: Try t better name clients. properly handle return codes when re- establishing links.
+	  Original commit message from CVS:
+	  * ext/jack/gstjackaudiosink.c: (gst_jack_ring_buffer_open_device),
+	  (gst_jack_ring_buffer_acquire):
+	  Try t better name clients. properly handle return codes when re-
+	  establishing links.
+
+2007-03-18 17:57:48 +0000  Paul Davis <paul@linuxaudiosystems.com>
+
+	  ext/jack/gstjackaudioclient.c: Don't need to take the connection lock, it will not be used and could cause deadlocks.
+	  Original commit message from CVS:
+	  Based on patch by: Paul Davis <paul at linuxaudiosystems dot com>
+	  * ext/jack/gstjackaudioclient.c: (gst_jack_audio_unref_connection):
+	  Don't need to take the connection lock, it will not be used and could
+	  cause deadlocks.
+
+2007-03-08 15:24:52 +0000  Paul Davis <paul@linuxaudiosystems.com>
+
+	  ext/jack/: Make an object to manage client connections to the jack server which we will use in the future to run sele...
+	  Original commit message from CVS:
+	  Includes patch by: Paul Davis <paul at linuxaudiosystems dot com>
+	  * ext/jack/Makefile.am:
+	  * ext/jack/gstjackaudioclient.c: (gst_jack_audio_client_init),
+	  (jack_process_cb), (jack_sample_rate_cb), (jack_buffer_size_cb),
+	  (jack_shutdown_cb), (connection_find),
+	  (gst_jack_audio_make_connection), (gst_jack_audio_get_connection),
+	  (gst_jack_audio_unref_connection),
+	  (gst_jack_audio_connection_add_client),
+	  (gst_jack_audio_connection_remove_client),
+	  (gst_jack_audio_client_new), (gst_jack_audio_client_free),
+	  (gst_jack_audio_client_get_client),
+	  (gst_jack_audio_client_set_active):
+	  * ext/jack/gstjackaudioclient.h:
+	  Make an object to manage client connections to the jack server which we
+	  will use in the future to run selected jack elements with the same jack
+	  connection.
+	  Make some stuff a bit more threadsafe.
+	  Activate the jack client ASAP.
+	  * ext/jack/gstjackaudiosink.c:
+	  (gst_jack_audio_sink_allocate_channels),
+	  (gst_jack_audio_sink_free_channels), (jack_process_cb),
+	  (gst_jack_ring_buffer_open_device),
+	  (gst_jack_ring_buffer_close_device),
+	  (gst_jack_ring_buffer_acquire), (gst_jack_ring_buffer_release),
+	  (gst_jack_audio_sink_class_init), (gst_jack_audio_sink_init),
+	  (gst_jack_audio_sink_getcaps):
+	  * ext/jack/gstjackaudiosink.h:
+	  Use new client object to manage connections.
+	  Don't remove and recreate all ports, try to reuse them.
+
+2007-01-12 10:25:40 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/jack/gstjackaudiosink.*: Improve docs.
+	  Original commit message from CVS:
+	  * ext/jack/gstjackaudiosink.c: (jack_sample_rate_cb),
+	  (jack_buffer_size_cb), (jack_shutdown_cb),
+	  (gst_jack_ring_buffer_acquire):
+	  * ext/jack/gstjackaudiosink.h:
+	  Improve docs.
+
+2006-12-06 16:57:17 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/jack/.cvsignore: Ignore old files as requested by the build slave.
+	  Original commit message from CVS:
+	  * ext/jack/.cvsignore:
+	  Ignore old files as requested by the build slave.
+
+2006-11-30 11:59:04 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/Makefile.am: Fix build.
+	  Original commit message from CVS:
+	  * ext/Makefile.am:
+	  Fix build.
+	  * ext/jack/gstjackaudiosink.c: (jack_process_cb),
+	  (jack_sample_rate_cb), (jack_buffer_size_cb), (jack_shutdown_cb),
+	  (gst_jack_ring_buffer_acquire):
+	  Small cleanups.
+
+2006-11-30 11:49:36 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  Added fully functional jackaudiosink.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * ext/Makefile.am:
+	  * ext/jack/Makefile.am:
+	  * ext/jack/gstjack.c: (plugin_init):
+	  * ext/jack/gstjack.h:
+	  * ext/jack/gstjackaudiosink.c: (gst_jack_ring_buffer_get_type),
+	  (gst_jack_ring_buffer_class_init), (jack_process_cb),
+	  (jack_sample_rate_cb), (jack_buffer_size_cb), (jack_shutdown_cb),
+	  (gst_jack_ring_buffer_init), (gst_jack_ring_buffer_dispose),
+	  (gst_jack_ring_buffer_finalize),
+	  (gst_jack_ring_buffer_open_device),
+	  (gst_jack_ring_buffer_close_device),
+	  (gst_jack_ring_buffer_acquire), (gst_jack_ring_buffer_release),
+	  (gst_jack_ring_buffer_start), (gst_jack_ring_buffer_pause),
+	  (gst_jack_ring_buffer_stop), (gst_jack_ring_buffer_delay),
+	  (gst_jack_connect_get_type), (gst_jack_audio_sink_base_init),
+	  (gst_jack_audio_sink_class_init), (gst_jack_audio_sink_init),
+	  (gst_jack_audio_sink_set_property),
+	  (gst_jack_audio_sink_get_property), (gst_jack_audio_sink_getcaps),
+	  (gst_jack_audio_sink_create_ringbuffer):
+	  * ext/jack/gstjackaudiosink.h:
+	  Added fully functional jackaudiosink.
+
+2006-04-08 21:48:01 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Fix #337365 (g_type_class_ref <-> g_type_class_peek_parent)
+	  Original commit message from CVS:
+	  * ext/amrwb/gstamrwbdec.c: (gst_amrwbdec_class_init):
+	  * ext/amrwb/gstamrwbenc.c: (gst_amrwbenc_class_init):
+	  * ext/amrwb/gstamrwbparse.c: (gst_amrwbparse_class_init):
+	  * ext/arts/gst_arts.c: (gst_arts_class_init):
+	  * ext/artsd/gstartsdsink.c: (gst_artsdsink_class_init):
+	  * ext/audiofile/gstafsink.c: (gst_afsink_class_init):
+	  * ext/audiofile/gstafsrc.c: (gst_afsrc_class_init):
+	  * ext/audioresample/gstaudioresample.c:
+	  * ext/cdaudio/gstcdaudio.c: (gst_cdaudio_class_init):
+	  * ext/directfb/dfbvideosink.c: (gst_dfbvideosink_class_init):
+	  * ext/divx/gstdivxdec.c: (gst_divxdec_class_init):
+	  * ext/hermes/gsthermescolorspace.c:
+	  (gst_hermes_colorspace_class_init):
+	  * ext/ivorbis/vorbisfile.c: (gst_ivorbisfile_class_init):
+	  * ext/jack/gstjack.c: (gst_jack_class_init):
+	  * ext/jack/gstjackbin.c: (gst_jack_bin_class_init):
+	  * ext/lcs/gstcolorspace.c: (gst_colorspace_class_init):
+	  * ext/libfame/gstlibfame.c: (gst_fameenc_class_init):
+	  * ext/musicbrainz/gsttrm.c: (gst_musicbrainz_class_init):
+	  * ext/nas/nassink.c: (gst_nassink_class_init):
+	  * ext/shout/gstshout.c: (gst_icecastsend_class_init):
+	  * ext/snapshot/gstsnapshot.c: (gst_snapshot_class_init):
+	  * ext/sndfile/gstsf.c: (gst_sf_class_init):
+	  * ext/swfdec/gstswfdec.c: (gst_swfdecbuffer_class_init),
+	  (gst_swfdec_class_init):
+	  * ext/tarkin/gsttarkindec.c: (gst_tarkindec_class_init):
+	  * ext/tarkin/gsttarkinenc.c: (gst_tarkinenc_class_init):
+	  * gst/cdxaparse/gstcdxastrip.c: (gst_cdxastrip_class_init):
+	  * gst/chart/gstchart.c: (gst_chart_class_init):
+	  * gst/colorspace/gstcolorspace.c: (gst_colorspace_class_init):
+	  * gst/deinterlace/gstdeinterlace.c: (gst_deinterlace_class_init):
+	  * gst/festival/gstfestival.c: (gst_festival_class_init):
+	  * gst/filter/gstbpwsinc.c: (gst_bpwsinc_class_init):
+	  * gst/filter/gstiir.c: (gst_iir_class_init):
+	  * gst/filter/gstlpwsinc.c: (gst_lpwsinc_class_init):
+	  * gst/librfb/gstrfbsrc.c: (gst_rfbsrc_class_init):
+	  * gst/mixmatrix/mixmatrix.c: (gst_mixmatrix_class_init):
+	  * gst/mpeg1sys/gstmpeg1systemencode.c:
+	  (gst_system_encode_class_init):
+	  * gst/mpeg1videoparse/gstmp1videoparse.c:
+	  (gst_mp1videoparse_class_init):
+	  * gst/mpeg2sub/gstmpeg2subt.c: (gst_mpeg2subt_class_init):
+	  * gst/mpegaudioparse/gstmpegaudioparse.c:
+	  (gst_mp3parse_class_init):
+	  * gst/overlay/gstoverlay.c: (gst_overlay_class_init):
+	  * gst/passthrough/gstpassthrough.c: (passthrough_class_init):
+	  * gst/playondemand/gstplayondemand.c: (play_on_demand_class_init):
+	  * gst/rtjpeg/gstrtjpegdec.c: (gst_rtjpegdec_class_init):
+	  * gst/rtjpeg/gstrtjpegenc.c: (gst_rtjpegenc_class_init):
+	  * gst/smooth/gstsmooth.c: (gst_smooth_class_init):
+	  * gst/smoothwave/gstsmoothwave.c: (gst_smoothwave_class_init):
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_class_init):
+	  * gst/stereo/gststereo.c: (gst_stereo_class_init):
+	  * gst/switch/gstswitch.c: (gst_switch_class_init):
+	  * gst/tta/gstttadec.c: (gst_tta_dec_class_init):
+	  * gst/tta/gstttaparse.c: (gst_tta_parse_class_init):
+	  * gst/vbidec/gstvbidec.c: (gst_vbidec_class_init):
+	  * gst/videocrop/gstvideocrop.c: (gst_video_crop_class_init):
+	  * gst/virtualdub/gstxsharpen.c: (gst_xsharpen_class_init):
+	  * gst/y4m/gsty4mencode.c: (gst_y4mencode_class_init):
+	  * sys/cdrom/gstcdplayer.c: (cdplayer_class_init):
+	  * sys/directsound/gstdirectsoundsink.c:
+	  (gst_directsoundsink_class_init):
+	  * sys/dxr3/dxr3audiosink.c: (dxr3audiosink_class_init):
+	  * sys/dxr3/dxr3spusink.c: (dxr3spusink_class_init):
+	  * sys/dxr3/dxr3videosink.c: (dxr3videosink_class_init):
+	  * sys/qcam/gstqcamsrc.c: (gst_qcamsrc_class_init):
+	  * sys/v4l2/gstv4l2colorbalance.c:
+	  (gst_v4l2_color_balance_channel_class_init):
+	  * sys/v4l2/gstv4l2tuner.c: (gst_v4l2_tuner_channel_class_init),
+	  (gst_v4l2_tuner_norm_class_init):
+	  * sys/ximagesrc/ximagesrc.c: (gst_ximagesrc_class_init):
+	  Fix #337365 (g_type_class_ref <-> g_type_class_peek_parent)
+
+2006-04-01 10:09:11 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/jack/gstjack.c:
+	  rework build; add translations for v4l2
+	  Original commit message from CVS:
+	  rework build; add translations for v4l2
+
+2005-10-12 14:29:55 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  renamed GST_FLAGS macros to GST_OBJECT_FLAGS moved bitshift from macro to enum definition
+	  Original commit message from CVS:
+	  * examples/indexing/indexmpeg.c: (main):
+	  * ext/artsd/gstartsdsink.c: (gst_artsdsink_open_audio),
+	  (gst_artsdsink_close_audio), (gst_artsdsink_change_state):
+	  * ext/artsd/gstartsdsink.h:
+	  * ext/audiofile/gstafparse.c: (gst_afparse_open_file),
+	  (gst_afparse_close_file):
+	  * ext/audiofile/gstafparse.h:
+	  * ext/audiofile/gstafsink.c: (gst_afsink_open_file),
+	  (gst_afsink_close_file), (gst_afsink_chain),
+	  (gst_afsink_change_state):
+	  * ext/audiofile/gstafsink.h:
+	  * ext/audiofile/gstafsrc.c: (gst_afsrc_open_file),
+	  (gst_afsrc_close_file), (gst_afsrc_change_state):
+	  * ext/audiofile/gstafsrc.h:
+	  * ext/cdaudio/gstcdaudio.c: (gst_cdaudio_init):
+	  * ext/directfb/directfbvideosink.c: (gst_directfbvideosink_init):
+	  * ext/dts/gstdtsdec.c: (gst_dtsdec_init):
+	  * ext/jack/gstjack.h:
+	  * ext/jack/gstjackbin.c: (gst_jack_bin_init),
+	  (gst_jack_bin_change_state):
+	  * ext/musepack/gstmusepackdec.c: (gst_musepackdec_init):
+	  * ext/musicbrainz/gsttrm.c: (gst_musicbrainz_init):
+	  * ext/nas/nassink.c: (gst_nassink_open_audio),
+	  (gst_nassink_close_audio), (gst_nassink_change_state):
+	  * ext/nas/nassink.h:
+	  * ext/polyp/polypsink.c: (gst_polypsink_init):
+	  * ext/sdl/sdlvideosink.c: (gst_sdlvideosink_change_state):
+	  * ext/sdl/sdlvideosink.h:
+	  * ext/smoothwave/gstsmoothwave.c: (gst_smoothwave_init):
+	  * ext/sndfile/gstsf.c: (gst_sf_set_property),
+	  (gst_sf_change_state), (gst_sf_release_request_pad),
+	  (gst_sf_open_file), (gst_sf_close_file), (gst_sf_loop):
+	  * ext/sndfile/gstsf.h:
+	  * ext/swfdec/gstswfdec.c: (gst_swfdec_init):
+	  * ext/tarkin/gsttarkindec.c: (gst_tarkindec_init):
+	  * gst/apetag/apedemux.c: (gst_ape_demux_init):
+	  * gst/cdxaparse/gstcdxaparse.c: (gst_cdxaparse_init):
+	  * gst/cdxaparse/gstcdxastrip.c: (gst_cdxastrip_init):
+	  * gst/festival/gstfestival.c: (gst_festival_change_state):
+	  * gst/festival/gstfestival.h:
+	  * gst/mpeg2sub/gstmpeg2subt.c: (gst_mpeg2subt_init):
+	  * gst/multifilesink/gstmultifilesink.c: (gst_multifilesink_init),
+	  (gst_multifilesink_set_location), (gst_multifilesink_open_file),
+	  (gst_multifilesink_close_file), (gst_multifilesink_next_file),
+	  (gst_multifilesink_pad_query), (gst_multifilesink_handle_event),
+	  (gst_multifilesink_chain), (gst_multifilesink_change_state):
+	  * gst/multifilesink/gstmultifilesink.h:
+	  * gst/videodrop/gstvideodrop.c: (gst_videodrop_init):
+	  * sys/cdrom/gstcdplayer.c: (cdplayer_init):
+	  * sys/dxr3/dxr3audiosink.c: (dxr3audiosink_init),
+	  (dxr3audiosink_open), (dxr3audiosink_close),
+	  (dxr3audiosink_chain_pcm), (dxr3audiosink_chain_ac3),
+	  (dxr3audiosink_change_state):
+	  * sys/dxr3/dxr3audiosink.h:
+	  * sys/dxr3/dxr3spusink.c: (dxr3spusink_init), (dxr3spusink_open),
+	  (dxr3spusink_close), (dxr3spusink_chain),
+	  (dxr3spusink_change_state):
+	  * sys/dxr3/dxr3spusink.h:
+	  * sys/dxr3/dxr3videosink.c: (dxr3videosink_init),
+	  (dxr3videosink_open), (dxr3videosink_close),
+	  (dxr3videosink_write_data), (dxr3videosink_change_state):
+	  * sys/dxr3/dxr3videosink.h:
+	  * sys/glsink/glimagesink.c: (gst_glimagesink_init):
+	  * sys/qcam/gstqcamsrc.c: (gst_qcamsrc_change_state),
+	  (gst_qcamsrc_open), (gst_qcamsrc_close):
+	  * sys/qcam/gstqcamsrc.h:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_init):
+	  * sys/vcd/vcdsrc.c: (gst_vcdsrc_set_property), (gst_vcdsrc_get),
+	  (gst_vcdsrc_open_file), (gst_vcdsrc_close_file),
+	  (gst_vcdsrc_change_state), (gst_vcdsrc_recalculate):
+	  * sys/vcd/vcdsrc.h:
+	  renamed GST_FLAGS macros to GST_OBJECT_FLAGS
+	  moved bitshift from macro to enum definition
+
+2005-09-05 17:20:29 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjackbin.c:
+	  Fix up all the state change functions.
+	  Original commit message from CVS:
+	  Fix up all the state change functions.
+
+2004-08-03 14:28:12 +0000  Benjamin Otte <otte@gnome.org>
+
+	  fixes for G_DISABLE_ASSERT and friends
+	  Original commit message from CVS:
+	  * examples/dynparams/filter.c: (ui_control_create):
+	  * examples/gstplay/player.c: (print_tag):
+	  * ext/alsa/gstalsa.c: (gst_alsa_request_new_pad):
+	  * ext/gdk_pixbuf/gstgdkanimation.c:
+	  (gst_gdk_animation_iter_may_advance):
+	  * ext/jack/gstjack.c: (gst_jack_request_new_pad):
+	  * ext/mad/gstid3tag.c: (gst_mad_id3_to_tag_list),
+	  (tag_list_to_id3_tag_foreach), (gst_id3_tag_handle_event):
+	  * ext/vorbis/oggvorbisenc.c: (gst_oggvorbisenc_get_tag_value):
+	  * ext/vorbis/vorbisenc.c: (gst_vorbisenc_get_tag_value):
+	  * ext/xine/xineaudiodec.c: (gst_xine_audio_dec_chain):
+	  * gst-libs/gst/media-info/media-info-test.c: (print_tag):
+	  * gst/sine/demo-dparams.c: (main):
+	  * gst/tags/gstvorbistag.c: (gst_tag_to_vorbis_comments):
+	  * testsuite/alsa/formats.c: (create_pipeline):
+	  * testsuite/alsa/sinesrc.c: (sinesrc_force_caps), (sinesrc_get):
+	  fixes for G_DISABLE_ASSERT and friends
+	  * gst/typefind/gsttypefindfunctions.c: (aac_type_find),
+	  (mp3_type_frame_length_from_header), (mp3_type_find),
+	  (plugin_init):
+	  require mp3 typefinding to have at least MIN_HEADERS valid headers
+	  add typefinding for AAC adts files
+
+2004-05-21 23:28:57 +0000  Stéphane Loeuillet <gstreamer@leroutier.net>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	  second batch : remove ',' at end of enums as they could confuse older gcc, foreign compilers (forte) and gtk-doc (in ...
+	  Original commit message from CVS:
+	  second batch :
+	  remove ',' at end of enums as they could confuse older gcc, foreign compilers (forte) and gtk-doc
+	  (in gst-plugins/ext/ this time)
+
+2004-03-15 19:32:27 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjackbin.c:
+	  don't mix tabs and spaces
+	  Original commit message from CVS:
+	  don't mix tabs and spaces
+
+2004-03-15 16:32:54 +0000  Johan Dahlin <johan@gnome.org>
+
+	  *.h: Revert indenting
+	  Original commit message from CVS:
+	  * *.h: Revert indenting
+
+2004-03-14 22:34:33 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	* ext/jack/gstjackbin.c:
+	  gst-indent
+	  Original commit message from CVS:
+	  gst-indent
+
+2004-01-12 03:40:18 +0000  David Schleef <ds@schleef.org>
+
+	* ext/jack/gstjack.c:
+	  Remove all usage of gst_pad_get_caps(), and replace it with gst_pad_get_allowed_caps() or gst_pad_get_negotiated_cap().
+	  Original commit message from CVS:
+	  Remove all usage of gst_pad_get_caps(), and replace it with
+	  gst_pad_get_allowed_caps() or gst_pad_get_negotiated_cap().
+
+2003-12-22 01:47:09 +0000  David Schleef <ds@schleef.org>
+
+	* ext/jack/gstjack.c:
+	  Merge CAPS branch
+	  Original commit message from CVS:
+	  Merge CAPS branch
+
+2003-12-13 16:59:51 +0000  Benjamin Otte <otte@gnome.org>
+
+	* ext/jack/gstjackbin.c:
+	  removed GST_*_CAST. Disabling of type checking is done in glib.
+	  Original commit message from CVS:
+	  removed GST_*_CAST. Disabling of type checking is done in glib.
+
+2003-12-04 10:37:38 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	  remove copyright field from plugins
+	  Original commit message from CVS:
+	  remove copyright field from plugins
+
+2003-11-07 12:47:02 +0000  Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+
+	* ext/jack/gstjackbin.c:
+	  Remove all config.h includes from header files, add it to each source file and remove duplicate config.h includes fro...
+	  Original commit message from CVS:
+	  Remove all config.h includes from header files, add it to each source file and remove duplicate config.h includes from several source files
+
+2003-11-01 23:43:13 +0000  Iain Holmes <iain@prettypeople.org>
+
+	* ext/jack/gstjack.c:
+	  Jack fixed too
+	  Original commit message from CVS:
+	  Jack fixed too
+
+2003-10-29 03:15:55 +0000  David Schleef <ds@schleef.org>
+
+	* ext/jack/gstjack.h:
+	  change gst/bytestream.h to gst/bytestream/bytestream.h
+	  Original commit message from CVS:
+	  change gst/bytestream.h to gst/bytestream/bytestream.h
+
+2003-10-28 20:52:41 +0000  Benjamin Otte <otte@gnome.org>
+
+	* ext/jack/gstjack.h:
+	  merge TYPEFIND branch. Major changes:
+	  Original commit message from CVS:
+	  merge TYPEFIND branch. Major changes:
+	  - totally reworked type(find) system
+	  - all typefind functions are in gst/typefind now
+	  - more typefind functions then before
+	  - some plugins might fail to compile now because I don't have them installed and they
+	  a) require bytestream or
+	  b) haven't had their typefind fixed.
+	  Please fix those plugins and put the typefind functions into gst/typefind if they don't have dependencies
+
+2003-10-08 16:08:19 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	  /GstBuffer/GstData/ in the API where you can pass events. Fix the plugins to deal with that. Fixes #113488.
+	  Original commit message from CVS:
+	  /GstBuffer/GstData/ in the API where you can pass events. Fix the plugins to deal with that. Fixes #113488.
+
+2003-10-01 13:14:50 +0000  Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+
+	* ext/jack/gstjack.h:
+	  New typefind system: bytestream is now part of the core all plugins have been modified to use this new typefind syste...
+	  Original commit message from CVS:
+	  New typefind system:
+	  * bytestream is now part of the core
+	  * all plugins have been modified to use this new typefind system
+	  * asf typefinding added
+	  * mpeg video stream typefiding removed because it's broken
+	  * duplicate typefind entries removed
+	  * extra id3 typefinding added, because we've seen 4 types of files
+	  (riff/wav, flac, vorbis, mp3) with id3 headers and each of these needs
+	  to work. Instead, I've added an id3 element and let it redo typefiding
+	  after the id3 header. this needs a hack because spider only typefinds
+	  once. We can remove this hack once spider supports multiple typefinds.
+	  * with all this, mp3 typefinding is semi-rewritten
+	  * id3 typefinding in flac/vorbis is removed, it's no longer needed
+	  * fixed spider and gst-typefind to use this, too.
+	  * Other general cleanups
+
+2003-09-30 12:56:27 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	* ext/jack/gstjackbin.c:
+	  conform to the buffer-frames props entry -- much nicer now...
+	  Original commit message from CVS:
+	  conform to the buffer-frames props entry -- much nicer now...
+
+2003-08-10 00:01:58 +0000  David Schleef <ds@schleef.org>
+
+	* ext/jack/Makefile.am:
+	  Remove redundant plugindir definition
+	  Original commit message from CVS:
+	  Remove redundant plugindir definition
+
+2003-07-19 23:25:25 +0000  Leif Johnson <leif@ambient.2y.net>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	  + changes for new float caps without slope/intercept + some category changes for plugins
+	  Original commit message from CVS:
+	  + changes for new float caps without slope/intercept
+	  + some category changes for plugins
+
+2003-07-06 20:49:52 +0000  Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+
+	* ext/jack/gstjack.c:
+	  New mimetypes gone into effect today - this commit changes all old mimetypes over to the new mimetypes spec as descri...
+	  Original commit message from CVS:
+	  New mimetypes gone into effect today - this commit changes all old mimetypes over to the new mimetypes spec as described in the previous commit's document. Note: some plugins will break, some pipelines will break, expect HEAD to be broken or at least not 100% working for a few days, but don't forget to report bugs
+
+2003-07-01 02:27:06 +0000  David Schleef <ds@schleef.org>
+
+	* ext/jack/gstjack.c:
+	  fix type punning
+	  Original commit message from CVS:
+	  fix type punning
+
+2003-06-29 19:46:13 +0000  Benjamin Otte <otte@gnome.org>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjackbin.c:
+	  compatibility fix for new GST_DEBUG stuff.
+	  Original commit message from CVS:
+	  compatibility fix for new GST_DEBUG stuff.
+	  Includes fixes for missing includes for config.h and unistd.h
+	  I only ensured for plugins I can build that they work, so if some of them are still broken, you gotta fix them yourselves unfortunately.
+
+2003-06-13 21:21:17 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	* ext/jack/gstjack.c:
+	  Removed ugly caps fixed flag hack, will be done automatically in core soon
+	  Original commit message from CVS:
+	  Removed ugly caps fixed flag hack, will be done automatically in
+	  core soon
+
+2003-03-04 15:34:20 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	* ext/jack/gstjackbin.c:
+	  update for the latest jack cvs and non-cothreaded gst scheduler
+	  Original commit message from CVS:
+	  update for the latest jack cvs and non-cothreaded gst scheduler
+
+2003-02-05 20:38:41 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ext/jack/gstjack.c:
+	  Changed caps->fixed to use FLAG_SET
+	  Original commit message from CVS:
+	  Changed caps->fixed to use FLAG_SET
+
+2003-01-10 13:38:32 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/jack/gstjack.c:
+	  PadConnect -> PadLink
+	  Original commit message from CVS:
+	  PadConnect -> PadLink
+
+2003-01-10 10:22:25 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/jack/gstjack.c:
+	  another batch of connect->link fixes please let me know about issues and please refrain of making them yourself, so t...
+	  Original commit message from CVS:
+	  another batch of connect->link fixes
+	  please let me know about issues
+	  and please refrain of making them yourself, so that I don't spend double
+	  the time resolving conflicts
+
+2002-12-08 14:50:10 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/jack/Makefile.am:
+	  parallel install fixes
+	  Original commit message from CVS:
+	  parallel install fixes
+
+2002-09-29 18:12:18 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjackbin.c:
+	  licenses again
+	  Original commit message from CVS:
+	  licenses again
+
+2002-09-18 19:02:52 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* ext/jack/gstjack.c:
+	  plugins part of license field patch
+	  Original commit message from CVS:
+	  plugins part of license field patch
+
+2002-09-10 09:31:40 +0000  Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+
+	* ext/jack/gstjack.c:
+	  This updates all plugins to the new API for gst_pad_try_set_caps
+	  Original commit message from CVS:
+	  This updates all plugins to the new API for gst_pad_try_set_caps
+
+2002-09-09 23:27:38 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/jack/gstjack.c:
+	  removing warnings as approved by wim
+	  Original commit message from CVS:
+	  removing warnings as approved by wim
+
+2002-08-23 04:04:11 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjackbin.c:
+	  fix jack input port connection
+	  Original commit message from CVS:
+	  fix jack input port connection
+
+2002-07-09 17:39:17 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	  compile fixen, and prepare to move MAINTAINER_MODE to as-version.m4
+	  Original commit message from CVS:
+	  compile fixen, and prepare to move MAINTAINER_MODE to as-version.m4
+
+2002-07-02 23:35:07 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjackbin.c:
+	  make jack work in all its full duplex glory
+	  Original commit message from CVS:
+	  make jack work in all its full duplex glory
+
+2002-06-12 03:32:02 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjackbin.c:
+	  working jack elements (fixed a problem in upstream jack) random other fixen...
+	  Original commit message from CVS:
+	  * working jack elements (fixed a problem in upstream jack)
+	  * random other fixen...
+
+2002-05-15 19:08:49 +0000  Steve Baker <steve@stevebaker.org>
+
+	* ext/jack/gstjack.c:
+	  use new bytestream api
+	  Original commit message from CVS:
+	  use new bytestream api
+
+2002-05-13 18:08:33 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	* ext/jack/gstjackbin.c:
+	  update to new jack api
+	  Original commit message from CVS:
+	  update to new jack api
+
+2002-05-05 19:39:17 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	  add some includes
+	  Original commit message from CVS:
+	  add some includes
+
+2002-05-05 01:08:05 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	* ext/jack/gstjackbin.c:
+	  better initialization. it doesn't work over here, though.
+	  Original commit message from CVS:
+	  better initialization. it doesn't work over here, though.
+
+2002-05-04 21:38:56 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjackbin.c:
+	  a commit so that jack will build without errors on Uraeus's system ;)
+	  Original commit message from CVS:
+	  a commit so that jack will build without errors on Uraeus's system ;)
+
+2002-05-04 20:53:35 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	  set caps once we know the sample rate of the system
+	  Original commit message from CVS:
+	  set caps once we know the sample rate of the system
+
+2002-05-04 18:57:44 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	* ext/jack/gstjackbin.c:
+	  some jack fixes, alsa touchups, and add rtp by default to the build if there are any problems building rtp, we're mov...
+	  Original commit message from CVS:
+	  some jack fixes, alsa touchups, and add rtp by default to the build
+	  if there are any problems building rtp, we're moving it back to experimental ;)
+
+2002-04-20 21:42:51 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	  a hack to work around intltool's brokenness a current check for mpeg2dec details->klass reorganizations an element br...
+	  Original commit message from CVS:
+	  * a hack to work around intltool's brokenness
+	  * a current check for mpeg2dec
+	  * details->klass reorganizations
+	  * an element browser that uses details->klass
+	  * separated cdxa parse out from the avi directory
+
+2002-04-16 17:14:05 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/Makefile.am:
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	* ext/jack/gstjackbin.c:
+	  Finally we're on to a proper jack setup, with a specialized bin and elements that can only go in a jack bin. I had to...
+	  Original commit message from CVS:
+	  Finally we're on to a proper jack setup, with a specialized bin and elements
+	  that can only go in a jack bin. I had to fix the parser first to do this, but
+	  to run it, the syntax is like so:
+	  gst-launch jackbin.( filesrc ! mad ! jacksink )
+	  But of course it's not fully functional yet. Sigh.
+
+2002-04-11 20:42:26 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	  GstPadTemplate <-> gst_pad_template <-> GST_PAD_TEMPLATE same with *factory and typefind.
+	  Original commit message from CVS:
+	  GstPadTemplate <-> gst_pad_template <-> GST_PAD_TEMPLATE
+	  same with *factory and typefind.
+	  also, some -Werror fixes.
+
+2002-03-30 21:07:51 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	  alphabetization fixen a jack caps fix
+	  Original commit message from CVS:
+	  * alphabetization fixen
+	  * a jack caps fix
+
+2002-03-30 19:31:13 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	  add notify back to filesrc, it's needed for MVC applications remove notify printouts from gst-launch cleanup in gst-p...
+	  Original commit message from CVS:
+	  * add notify back to filesrc, it's needed for MVC applications
+	  * remove notify printouts from gst-launch
+	  * cleanup in gst-plugins configure.ac
+	  * some jack updates
+	  * remove SELF_ITERATING flag in favor of SEF_SCHEDULABLE (not a clear name,
+	  but it's what we have for the moment)
+	  * improve parsing of request pad names, no more sscanf
+	  * fixes to the fastscheduler Makefile.am
+
+2002-03-20 21:45:04 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/gstjack.c:
+	  s/Gnome-Streamer/GStreamer/
+	  Original commit message from CVS:
+	  s/Gnome-Streamer/GStreamer/
+
+2002-03-19 04:10:06 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/Makefile.am:
+	* ext/jack/gstjack.c:
+	  removal of //-style comments don't link plugins to core libs -- the versioning is done internally to the plugins with...
+	  Original commit message from CVS:
+	  * removal of //-style comments
+	  * don't link plugins to core libs -- the versioning is done internally to the plugins with the plugin_info struct,
+	  and symbol resolution is lazy, so we can always know if a plugin can be loaded by the plugin_info data. in theory.
+
+2002-03-19 01:39:43 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/Makefile.am:
+	  s/@GST_PLUGIN_LDFLAGS@/$(GST_PLUGIN_LDFLAGS)/ @-substitued variables variables are defined as make variables automagi...
+	  Original commit message from CVS:
+	  s/@GST_PLUGIN_LDFLAGS@/$(GST_PLUGIN_LDFLAGS)/
+	  @-substitued variables variables are defined as make variables automagically,
+	  and this gives the user the freedom to say make GST_PLUGIN_LDFLAGS=-myflag
+
+2002-03-18 04:41:35 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ext/jack/Makefile.am:
+	* ext/jack/README:
+	* ext/jack/gstjack.c:
+	* ext/jack/gstjack.h:
+	  s/gst_element_install_std_props/gst_element_class_install_std_props/ -- it just makes more sense that way added jack ...
+	  Original commit message from CVS:
+	  * s/gst_element_install_std_props/gst_element_class_install_std_props/ -- it just makes more sense that way
+	  * added jack element, doesn't quite work right yet but i didn't want to lose the work -- it does build, register,
+	  and attempt to run though
+	  * imposed some restrictions on the naming of request pads to better allow for reverse parsing
+	  * added '%s' to reverse parsing
+	  * added new bin flag to indicate that it is self-iterating, and some lame code in gst-launch to test it out
+	  * fixen on launch-gui
+	  * added pkg-config stuff for the editor's libs
+
+2011-01-02 11:37:14 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: mark v4l2sink as experimental and build only if --enable-experimental is passed
+	  It's not really of 'good' quality yet, but there's a lot of
+	  code shared with v4l2src, so not so easy to move it elswhere.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=612244
+
+2011-01-02 01:24:21 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* 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:
+	  Revert "v4l2: add norm property"
+	  This reverts commit 9e1d419d07337e6db2cc3936472be205ce927e54.
+	  Reverting this since it adds unreviewed and bad API to v4l2src
+	  (property of type enum, with seemingly random and unsorted values).
+
+2011-01-01 23:26:33 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tools/.gitignore:
+	* tools/Makefile.am:
+	* tools/README.filterstamp:
+	* tools/filterstamp.sh:
+	* tools/gst-launch-ext-m.m:
+	* tools/gst-launch-ext.1.in:
+	* tools/gst-visualise-m.m:
+	* tools/gst-visualise.1.in:
+	  tools: remove unused left-over directory
+	  These are all in -base/tools.
+
+2010-12-31 13:57:05 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4adepay.h:
+	  mp4adepay: improve timestamps on outgoing packets
+	  Improve parsing of the samplerate.
+	  Parse the framelen so that we can calculate timestamps.
+	  When interpollate the incomming timestamp on outgoing buffers when there are
+	  multiple subframes.
+	  fixes #625825
+
+2010-12-31 00:12:53 -0800  David Schleef <ds@schleef.org>
+
+	* gst/dtmf/tone_detect.c:
+	  dtmf: Fix build failure caused by previous commit
+
+2010-12-30 18:20:47 -0800  David Schleef <ds@schleef.org>
+
+	* gst/dtmf/gstdtmfdetect.c:
+	* gst/dtmf/tone_detect.c:
+	* gst/dtmf/tone_detect.h:
+	  dtmf: build fixes for MSVC
+	  Use gint16 and G_PI.
+
+2010-12-30 18:19:47 -0800  David Schleef <ds@schleef.org>
+
+	* gst/dtmf/tone_detect.c:
+	  dtmf: reindent
+
+2010-12-31 02:16:54 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/cairo/gsttimeoverlay.c:
+	* gst/videofilter/gstvideobalance.c:
+	  cairo, videofilter: use gst/math-compat.h header for rint
+
+2010-12-30 14:30:27 -0800  David Schleef <ds@schleef.org>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: Check for HAVE_RINT instead
+	  Also change M_PI to G_PI for giggles.
+
+2010-12-30 14:21:37 -0800  David Schleef <ds@schleef.org>
+
+	* ext/cairo/gstcairorender.c:
+	  cairo: Don't use #ifdefs inside macros
+
+2010-12-30 14:20:52 -0800  David Schleef <ds@schleef.org>
+
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/audiofx/audiowsincband.c:
+	* gst/audiofx/audiowsinclimit.c:
+	* gst/effectv/gstop.c:
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/goom/convolve_fx.c:
+	* gst/goom/ifs.c:
+	* gst/goom/lines.c:
+	* gst/goom/tentacle3d.c:
+	* tests/examples/audiofx/firfilter-example.c:
+	* tests/examples/audiofx/iirfilter-example.c:
+	  Change M_PI to G_PI
+
+2010-12-30 12:07:52 -0800  David Schleef <ds@schleef.org>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: use G_OS_WIN32 for windows check
+
+2010-12-30 16:24:16 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4adepay.c:
+	  mp4adepay: fix timestamps on buffers
+
+2010-12-30 16:22:48 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmpvpay.c:
+	  mpvpay: fix flushing and discont
+	  Fix flushing and disconts.
+	  Clean up in state changes.
+
+2010-12-29 23:38:18 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: increase allowed max. block size for push mode from 10M to 15M
+	  It was an arbitrary limit from the start, meant as a basic sanity check,
+	  so may just as well increase it a little. Would be good to provide
+	  progress reporting while completing the block in any case..
+	  https://bugzilla.gnome.org/show_bug.cgi?id=637060
+
+2010-12-29 23:09:04 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: assume matroska if no doctype is specified
+	  https://bugzilla.gnome.org/show_bug.cgi?id=638019
+
+2010-12-04 13:43:11 -0600  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/v4l2/v4l2src_calls.h:
+	  v4l2: add interlaced support
+
+2010-10-02 14:45:14 -0500  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2sink.h:
+	* sys/v4l2/gstv4l2xoverlay.c:
+	* sys/v4l2/gstv4l2xoverlay.h:
+	  v4l2sink: add navigation support
+
+2010-04-04 06:43:41 -0500  Rob Clark <rob@ti.com>
+
+	* 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:
+	  v4l2: add norm property
+	  Based on a patch by Guennadi Liakhovetski.
+
+2010-07-13 10:03:51 -0500  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2_calls.h:
+	  v4l2: cleanup get/set input/output
+	  output devices should use get/set output, and in either case we should
+	  not print a warning message if the ioctl fails but the device does not
+	  claim to support the tuner interface
+
+2010-06-10 11:15:46 -0500  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2xoverlay.c:
+	* sys/v4l2/gstv4l2xoverlay.h:
+	  v4l2xoverlay: add support to create window
+	  If xoverlay is available, v4l2sink should create a window for the overlay to
+	  display in.
+	  The window automatically tries to make itself as large as possible.
+	  This works well on a small screen, but perhaps should first attempt to use
+	  the size of the video that is played (no scaling).
+
+2010-04-04 06:41:28 -0500  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: special handling for cases gst_buffer_make_metadata_writable()
+	  Special case check for sub-buffers:  In certain cases, places like
+	  GstBaseTransform, which might check that the buffer is writable before copying
+	  metadata, timestamp, and such, will find that the buffer has more than one
+	  reference to it.  In these cases, they will create a sub-buffer with an offset=0
+	  and length equal to the original buffer size.
+	  This could happen in two scenarios: (1) a tee in the pipeline, and (2) because
+	  the refcnt is incremented in gst_mini_object_free() before the finalize function
+	  is called, and decremented after it returns..  but returning this buffer to the
+	  buffer pool in the finalize function, could wake up a thread blocked in
+	  _buffer_alloc() which could run and get a buffer w/ refcnt==2 before the thread
+	  originally unref'ing the buffer returns from finalize function and decrements
+	  the refcnt back to 1!
+	  This is related to issue #545501
+
+2010-04-04 06:39:52 -0500  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: fix race condition
+	  The size of the buffer would be zero'd out in gst_v4l2_buffer_finalize()
+	  after the buffer is qbuf'd or pushed onto the queue of available buffers..
+	  leaving a race condition where the thread waiting for the buffer could awake
+	  and set back a valid size before the finalizing thread zeros out the length.
+	  This would result that the newly allocated buffer has length of zero.
+
+2010-04-04 06:39:08 -0500  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2sink.h:
+	  v4l2sink: add properties to control crop
+
+2010-04-04 06:37:16 -0500  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2xoverlay.c:
+	  v4l2: re-enable x-overlay support
+
+2010-12-25 11:52:36 -0600  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: fix for PAUSED->READY->PAUSED state transitions
+	  When v4l2sink goes to PAUSED->READY it only stops streaming, so the state
+	  should be set to STATE_PENDING_STREAMON in case the element transitions
+	  back to PLAYING.
+
+2010-04-04 06:28:51 -0500  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2sink.h:
+	  v4l2sink: add "min-queued-bufs" property
+
+2010-04-04 06:26:50 -0500  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2sink: Add support for blocking dequeue.
+	  We'd prefer to throttle the decoder if we run out of buffers, to keep a bound
+	  on memory usage.  Also, for OMAP4 it is a requirement of the decoder to not
+	  alternate between memory alloced by the display driver and malloc'd userspace
+	  memory.
+
+2010-04-04 06:24:41 -0500  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: clear flags before reusing buffer from buffer pool
+	  note: this really only affects v4l2sink since gst_v4l2_buffer_pool_get() is
+	  only called once per buffer in the v4l2src case (in
+	  gst_v4l2src_buffer_pool_activate())
+
+2010-04-04 06:23:31 -0500  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: don't render preroll buffers
+	  Most v4l2 drivers will get upset when you queue the same buffer twice in a
+	  row without first dequeueing it.
+	  Rendering of pre-roll buffers can be re-introduced later, but will require
+	  tracking the state of the buffer, and avoiding to re-QBUF if the buffer has
+	  already been passed to the driver.
+
+2010-04-04 06:22:43 -0500  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: Improve behavior for shared buffers.
+	  When the decoder is using pad_alloc(), v4l2sink would behave badly if
+	  the number of buffers ('queue-size' property) was not high enough to
+	  account for all the buffers needed by the decoder, and other elements
+	  (such as queues) between the decoder and v4l2sink.  This patch
+	  slightly increases the default number of buffers, and changes v4l2sink
+	  to drop frames rather than return an error in case the number of
+	  buffers is not high enough.
+
+2010-11-15 15:58:28 +0100  Andy Wingo <wingo@oblong.com>
+
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulsesrc.h:
+	  add "client" property
+	  * ext/pulse/pulsesrc.c (gst_pulsesrc_class_init, gst_pulsesrc_init)
+	  (gst_pulsesrc_set_property, gst_pulsesrc_get_property)
+	  (gst_pulsesrc_open): Add a "client" property, as in pulsesink.
+	  Fixes #634914
+
+2010-12-29 15:54:46 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: serialise/deserialise floats without changing locale
+	  Use g_ascii_dtostr() and g_ascii_strtod() to serialise/deserialise
+	  floating point numbers, instead of ugly hacks that switch locale
+	  before and after calling libc functions (which is not a good idea
+	  in a multi-threaded application).
+
+2010-12-29 14:40:05 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	  rtpjpegdepay: fix framerate parsing for locales that use a comma as floating point
+	  atof() converts strings according to the current locale, but the
+	  framerate string will likely always use a dot as floating point
+	  separator, so use g_ascii_strtod() instead (but also canonicalise
+	  the string before, so we can handle both formats as input).
+
+2010-12-27 13:11:59 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: use the right variable
+	  Use the right variable for specifying that we sent a receiver report.
+
+2010-12-23 16:42:29 -0600  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: fix typo
+
+2010-12-23 16:03:00 -0600  Rob Clark <rob@ti.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: add stream-format and alignment properties for h264
+
+2010-12-22 11:41:59 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstpay.c:
+	  gstpay: fix klass, add RTP as a use case
+
+2010-12-12 15:10:47 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpgstdepay.c:
+	  gstdepay: cleanup the cache
+
+2010-12-12 05:10:01 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpgstdepay.c:
+	* gst/rtp/gstrtpgstdepay.h:
+	* gst/rtp/gstrtpgstpay.c:
+	* gst/rtp/gstrtpgstpay.h:
+	  gstpay/depay: add generic gstreamer payloader
+	  Add the beginnings of a generic GStreamer buffers payloader.
+
+2010-12-23 17:06:58 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4gpay.c:
+	  mp4gpay: reset state on flush-stop
+
+2010-12-23 16:26:07 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4gdepay.c:
+	  mp4gdepay: flush state on flush-stop
+
+2010-12-23 16:25:15 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: on-npt-stop is a manager signal
+
+2010-12-23 15:24:29 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: improve RTP session handling
+	  Store the RTP session in the stream so that we can more efficiently
+	  perform actions on the stream based on RTP signals.
+
+2010-12-23 13:55:31 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: include last send RB block
+	  Only report RB values for non-internal sources.
+	  Report not only the RB blocks we last received from but also the last RB
+	  block we sent to a source.
+
+2010-12-23 13:52:57 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpsession: remember last sent RB values.
+
+2010-12-23 13:00:49 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: include all stats and document
+	  Include all possible stats of a source in the stats structure because we might
+	  be interested in what happened in the past.
+	  Document the stats property and the fields.
+
+2010-12-23 12:59:59 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/examples/rtp/client-PCMA.c:
+	  examples: add example RTP stats
+	  Add some more RTP examples for how to retrieve RTP stats in a receiver.
+
+2010-12-23 12:58:05 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: also emit RTCP activity on SR
+	  Also emit RTCP activity signals when we receive an SR packet without RB blocks,
+	  such as from a sender that is not receiving anything.
+
+2010-12-23 11:10:55 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  docs: add some more gstrtpbin docs
+
+2010-12-22 21:27:11 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximagesrc: remote is a boolean (and not uint) property
+
+2010-12-22 19:58:21 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Don't use gst_pad_alloc_buffer()
+	  Using this in a demuxer will cause deadlocks if there's
+	  a pad with a pending pad-block downstream, no matter if
+	  there is a queue between the pad or not. Queues pass
+	  bufferalloc downstream from the same thread and only
+	  act as a thread boundary for events and buffers.
+
+2010-12-22 14:14:08 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: fix subtitle pad template, we only handle kate for now
+
+2010-12-16 11:44:44 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  docs: update rtspsrc docs, rtpbin is not in -bad any more
+
+2010-12-22 11:42:31 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: unlock before emitting signals
+
+2010-12-21 22:34:49 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpac3pay.c:
+	* gst/rtp/gstrtpac3pay.h:
+	  rtpac3pay: add AC3 payloader
+
+2010-12-21 22:17:19 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpac3depay.c:
+	  ac3depay: fix debug category description
+
+2010-12-21 22:16:42 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmpapay.c:
+	  mpapay: add debug category
+
+2010-12-20 14:49:02 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/jpegenc.c:
+	  jpegenc: Adds another test case
+	  Adds a test for jpegenc to check that is possible to negotiate and
+	  push buffers with different resolution one after another.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=637686
+
+2010-12-21 13:37:40 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: sink pad's getcaps shouldn't use the src pad getcaps
+	  Instead of using get_allowed_caps on the srcpad, the sinkpad getcaps
+	  should use the getcaps of the srcpad's peer. This way the srcpad
+	  can keep using fixed_caps and sinkpad getcaps exposes all caps
+	  that can be negotiated
+	  https://bugzilla.gnome.org/show_bug.cgi?id=637686
+
+2010-12-21 16:58:47 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpdepay.c:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpg722depay.c:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtpg723depay.c:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmparobustdepay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtppcmupay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpsirenpay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	  rtp: add RTP hint to the klass
+
+2010-12-21 16:49:28 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpdepay.c:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpg722depay.c:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtpg723depay.c:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmparobustdepay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtppcmupay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpsirenpay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	  rtp: fix rank of payloaders and depayloaders
+	  Set the payloaders and depayloaders to a reasonable rank.
+
+2010-12-21 15:24:18 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  vrawdepay: reset depayloader state
+	  Reset the depayloader state on flush-stop.
+
+2010-12-21 15:07:14 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmp4vpay.h:
+	  mp4pay: use vmethod for intercepting events
+
+2010-12-21 13:55:40 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtptheorapay.c:
+	  theorapay: clear packet on flush-stop
+
+2010-12-21 13:49:41 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	  vorbispay: clear packet on flush-stop
+
+2010-12-21 12:31:44 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4gdepay.c:
+	  mp4gdepay: reset depayloader state
+
+2010-12-21 12:29:58 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  h264pay: flush adapter on flush-stop
+
+2010-12-20 18:49:49 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmpapay.c:
+	  mpapay: flush last packets on EOS
+
+2010-12-20 17:47:05 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 169462a to 46445ad
+
+2010-12-20 16:51:47 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmpapay.c:
+	  mpapay: reset payloader on state change
+
+2010-12-20 16:05:36 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmpapay.c:
+	  mpapay: reset payloader on flush
+	  Reset the payloader on a flush event.
+	  Handle DISCONT better.
+
+2010-12-20 15:54:45 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  jitterbuffer: get better buffering level
+	  When the jitterbuffer contains -1 timestamps, make sure we still calculate the
+	  buffer fill level by skipping the -1 buffers.
+	  Try to be more resilient to weird input timestamps.
+
+2010-12-20 11:10:22 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: provide a clock.
+	  since we are using the clock for sync, we need to also provide a clock for good
+	  measure. The reason is that even if downstream elements provide a clock, we
+	  don't want to have that clock selected because it might not be running yet.
+
+2010-12-20 10:49:56 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: copy buffering stats
+	  when we create an aggregate buffering message, copy the buffering stats form the
+	  last message. At least we get correct buffering mode then.
+
+2010-12-19 11:02:41 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/pipelines/wavenc.c:
+	  wavenc: Fix memory leaks in the unit test
+
+2010-12-19 10:58:16 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstradioac.h:
+	  radioactv: Prevent use of uninitialized values
+	  Fixes bug #618652.
+
+2010-12-19 10:22:29 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/debugutils/gstcapsdebug.c:
+	  capsdebug: Don't leak pad templates created from static pad templates
+
+2010-11-29 12:36:06 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/ximage/gstximagesrc.c:
+	* sys/ximage/gstximagesrc.h:
+	  ximagesrc: change from XGetImage to XGetSubImage dependant on a property
+	  ximagesrc: change from XGetImage to XGetSubImage dependant on a property
+	  to avoid unnecessary performance hits by default.
+
+2010-11-28 16:04:35 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximagesrc: use XGetSubImage instead of XGetImage, works with remote X
+	  ximagesrc: use XGetSubImage instead of XGetImage, works with remote X
+	  (on my setup anyway...)
+
+2010-11-27 17:15:32 +0000  Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximagesrc: fix various width/height calculations being off by one,
+	  ximagesrc: fix various width/height calculations being off by one,
+	  and make it so a single pixel width/height can be captured (except
+	  the top left one, as 0,0,0,0 is reserved for full screen as per
+	  the property comments).
+
+2010-12-17 19:19:35 -0600  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  fix compile errors on macosx
+	  with i686-apple-darwin10-gcc-4.2.1:
+	  gstv4l2object.c: In function 'gst_v4l2_object_get_nearest_size':
+	  gstv4l2object.c:1988: warning: format '%u' expects type 'unsigned int', but argument 12 has type 'gint *'
+	  gstv4l2object.c:1988: warning: format '%u' expects type 'unsigned int', but argument 13 has type 'gint *'
+
+2010-12-17 15:38:15 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: determine output h264 layout using caps negotiation
+	  ... thereby (partially) deprecating properties currently controlling whether
+	  or not byte-stream output or NAL/AU alignment (though properties still determine
+	  fallback if nothing specified in caps).
+	  Fixes #606662.
+
+2010-12-16 18:55:43 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpj2kpay.c:
+	  j2kpay: handle EOC correctly
+	  Don't include the next 2 bytes when we are at the end of the data and there are
+	  no more bytes left.
+
+2010-12-16 15:15:49 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: flush remaining buffered samples on EOS
+	  ... which can make a difference between all or nothing when dealing
+	  with short streams and relatively large ringbuffer segment.
+
+2010-12-16 10:04:19 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Change classification to Filter/Effect/Video/Deinterlace
+
+2010-12-15 18:21:34 +0100  Edward Hervey <edward.hervey@collabora.co.uk>
+
+	* gst/rtp/gstrtpj2kpay.c:
+	  rtpj2kpay: Initialize all fields
+	  Makes sad compliers happy
+
+2010-12-15 16:22:54 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpj2kpay.c:
+	  j2kpay: cleanup header construction
+	  Use a simpler way of constructing the header that doesn't depend on
+	  the endianness.
+
+2010-12-15 13:30:50 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: depend on -base from git for new rtp base depayloader features
+	  This is ok in this case, since the plan is to release core/base again
+	  along with good/ugly/bad in the next cycle.
+
+2010-12-15 14:55:58 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 20742ae to 169462a
+
+2010-12-15 13:12:09 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kdepay.h:
+	  j2kdepay: add support for buffer lists
+
+2010-12-14 18:12:43 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: fix average RTCP packet size some more.
+	  Fix stupid error in averaging macro.
+	  Include udp headers in packet length estimation.
+
+2010-12-14 17:15:23 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpstats.c:
+	  rtpbin: correctly calculate RTCP packet size
+
+2010-12-14 15:27:52 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpj2kpay.c:
+	  j2kpay: stop scanning when we reached the end
+	  Stop scanning for markers when we reached the end of the data.
+
+2010-12-13 16:23:24 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 011bcc8 to 20742ae
+
+2010-12-13 12:56:12 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: avoid leaking sink events
+	  Avoid leaking the newsegment event when it has the wrong format.
+
+2010-12-12 14:53:17 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4vpay.c:
+	  mp4vpay: we can also accept xvid caps
+
+2010-12-12 01:39:06 +1100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Avoid infinite loop draining frames
+	  When the pipeline is flushed just as we're draining history,
+	  don't loop infinitely, just discard the history and abort.
+
+2010-12-11 17:39:20 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: add "max-errors" property to ignore decoding errors
+	  Add property to ignore decoding errors. Default is to ignore a few
+	  decoding errors if the input is packetized, but error out immediately
+	  if the input is not packetized.
+	  Ignoring errors for packetized input most likely doesn't work
+	  properly yet, so don't do that for now.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=623063
+
+2010-05-28 15:27:14 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: free/malloc instead of realloc, avoids memcpy
+
+2010-12-11 17:49:03 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Check if there's actually a seek table before parsing it
+
+2010-12-11 17:46:17 +0100  Kishore Arepalli <kishore.arepalli@gmail.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Implement CONVERT and FORMATS query
+	  Fixes bug #636784.
+
+2010-07-01 00:22:07 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: put unrecognised RIFF format IDs into the unknown caps
+	  Extra info can't hurt. Field names aren't necessarily consistent with
+	  what's used elsewhere though (e.g. avidemux), but then neither are the
+	  caps.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=623178
+
+2010-10-29 22:50:14 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* ext/pulse/pulsemixerctrl.c:
+	* ext/pulse/pulsemixerctrl.h:
+	  pulsemixer: Implement MIXER_FLAG_AUTO_NOTIFICATIONS
+	  Add the mixer flag and send notifications when either the volume or muted
+	  status changes.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=618389
+
+2010-02-08 21:41:29 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: mark DISCONT when resuming PLAY
+	  In particular, when streaming interleaved, this arranges for setting a new
+	  timestamp on outgoing buffer so downstream can appropriate reset
+	  to a change in (rtp)time.
+
+2010-12-02 16:08:34 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: degrade gracefully upon failing seek and tweak QUERY_SEEKING response
+
+2010-10-25 11:51:06 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: add and use auto buffering mode
+	  ... which selects BUFFER for a non-live stream, and otherwise SLAVE.
+	  Fixes #633088.
+
+2010-12-06 12:16:12 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kdepay.h:
+	  j2kdepay: make the depayloader more resilient
+	  Use 3 adapters, one to accumulate paketization units, another on to accumulate
+	  tiles and a last one to accumulate the final frame.
+	  Don't just blindly flush the adapter on DISCONT but only discard the current
+	  packetization unit.
+	  When we dropped jpeg2000 packets between SOP markers, adjust the SOT header with
+	  the new lenght.
+
+2010-12-09 13:49:04 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix flow return aggregation
+
+2010-12-08 11:35:33 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix handling near end-of-file corner cases
+	  Also, relax some error handling to not bail out completely when something
+	  feels amiss, but consider this EOF and continue with was obtained so far.
+
+2010-12-07 17:19:00 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fragmented support; fix offset handling and relax error raising
+	  In particular, accept unknown stream in track fragment, and only error out
+	  if that raises problems later on with respect to offset tracking.
+	  Fixes #620283.
+
+2010-12-07 13:11:48 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/Makefile.am:
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: use aac codec-data to adjust samplerate if needed
+	  Based on patch by Fabien Lebaillif-Delamare <fabien@arq-media.com>
+	  Fixes #636621.
+
+2010-12-07 11:43:13 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: don't uncork in _start
+	  Don't uncork in the _start method just yet but wait until we have written some
+	  samples to pulseaudio. This avoid underruns on pulseaudio and less crackling
+	  noises when starting.
+
+2010-12-07 11:47:41 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' into 0.11
+
+2010-12-07 11:43:13 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: don't uncork in _start
+	  Don't uncork in the _start method just yet but wait until we have written some
+	  samples to pulseaudio. This avoid underruns on pulseaudio and less crackling
+	  noises when starting.
+
+2010-12-07 11:42:15 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: use _object_ref_sink() when we can
+
+2010-12-07 11:40:58 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: don't abuse the class lock
+	  Use a new static lock to protect the probed device list instead of the object
+	  class lock.
+
+2010-12-06 19:59:49 +0100  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix compiler warnings on OSX.
+
+2010-12-06 18:17:24 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: add debug to notify when skipping to jpeg header
+
+2010-12-06 18:16:19 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: discard incomplete image
+	  ... as determined when finding SOI next image before an EOI.
+	  Based on patch by David Hoyt <david.hoyt@llnl.gov>
+	  Fixes #635734.
+
+2010-12-06 17:45:38 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: avoid infinite loop when resyncing
+	  Fixes #635734 (partly).
+
+2010-12-06 17:28:32 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  Merge branch 'master' of ssh://git.freedesktop.org/git/gstreamer/gst-plugins-good into 0.11
+
+2010-12-06 17:27:51 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* android/apetag.mk:
+	* android/avi.mk:
+	* android/flv.mk:
+	* android/icydemux.mk:
+	* android/id3demux.mk:
+	* android/qtdemux.mk:
+	* android/rtp.mk:
+	* android/rtpmanager.mk:
+	* android/rtsp.mk:
+	* android/soup.mk:
+	* android/udp.mk:
+	* android/wavenc.mk:
+	* android/wavparse.mk:
+	* configure.ac:
+	  more 0.10 -> 0.11 changes
+
+2010-12-06 15:21:53 +0100  David Hoyt <dhoyt@llnl.gov>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: pass along eos if received before buffer arrives
+	  Fixes #636172.
+
+2010-10-20 11:05:49 +0200  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/ebml-write.h:
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: try to write timestamps in all the outgoing buffers
+	  Fixes #632654.
+
+2010-12-06 12:21:00 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	  configure: start 0.11 branch
+
+2010-12-06 12:17:21 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/debugutils/progressreport.c:
+	* gst/debugutils/progressreport.h:
+	  progressreport: optionally determine progress using buffer metadata
+	  Based on patch by Leo Singer <lsinger at caltech.edu>
+	  Fixes #629418.
+
+2010-12-05 14:39:19 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* tests/check/elements/interleave.c:
+	  check: Fixup the shutting down order
+	  First bring down everything to NULL before attempting to unlink
+	  or unref anything.
+	  Avoids the tests just hanging there for ever waiting to acquire a
+	  lock that doesn't exist anymore.
+
+2010-11-04 19:31:45 +0100  Janne Grunau <janne.grunau@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2src: set top field first for interlaced buffers if v4l2 exports it
+	  https://bugzilla.gnome.org/show_bug.cgi?id=634393
+
+2010-11-04 18:36:09 +0100  Janne Grunau <janne.grunau@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2src: check field information and set interlaced caps accordingly
+	  Reject the format if the field type is not supported.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=634391
+
+2010-12-03 17:42:14 +0100  Benjamin Gaignard <benjamin.gaignard@stericsson.com>
+
+	* Android.mk:
+	* android/NOTICE:
+	* android/apetag.mk:
+	* android/avi.mk:
+	* android/flv.mk:
+	* android/gst/rtpmanager/gstrtpbin-marshal.c:
+	* android/gst/rtpmanager/gstrtpbin-marshal.h:
+	* android/gst/udp/gstudp-enumtypes.c:
+	* android/gst/udp/gstudp-enumtypes.h:
+	* android/gst/udp/gstudp-marshal.c:
+	* android/gst/udp/gstudp-marshal.h:
+	* android/icydemux.mk:
+	* android/id3demux.mk:
+	* android/qtdemux.mk:
+	* android/rtp.mk:
+	* android/rtpmanager.mk:
+	* android/rtsp.mk:
+	* android/soup.mk:
+	* android/udp.mk:
+	* android/wavenc.mk:
+	* android/wavparse.mk:
+	  Add build system for Android
+
+2010-03-26 13:51:58 +0100  Guillaume Emont <gemont@igalia.com>
+
+	* gst/debugutils/gstnavseek.c:
+	  navseek: add basic support to change playback rate
+	  The following keys will now be interpreted by navseek:
+	  'f' means fast forward: the stream gets played at rate 2.0
+	  'r' means rewind: the stream gets played at rate -2.0
+	  'n' means normal: the stream gets played at rate 1.0
+	  Fixes #631516.
+
+2010-12-01 13:12:04 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: add support for e(a)c-3 audio
+
+2010-11-19 12:44:35 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: avoid sending EOS event twice
+
+2010-11-19 12:44:18 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: remove dead code trying to update stream duration
+	  On the one hand, it insufficiently checks whether it only updates a dummy
+	  segment.  On the other hand, only doing this at the time the last sampled is
+	  prepared (and sent downstream) is too little too late.
+
+2010-11-09 10:58:57 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fragmented support; handle ismv sample flags
+
+2010-11-08 11:41:21 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fragmented support; handle ismv stbl atoms
+	  ... or lack of some thereof, such as mandatory stsz.  Shuffle some code
+	  in _stbl_init to detect this early enough.
+
+2010-11-08 11:39:37 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fragmented support; compensate for ismv offset handling
+	  ... or lack thereof, which according to specs would put media data in
+	  unlikely position.
+
+2010-11-04 14:07:56 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux.h:
+	  qtdemux: fragmented support for push mode
+
+2010-11-04 10:17:37 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux.h:
+	  qtdemux: fragmented support; proper and incremental moof parsing
+	  That is, parse each moof in one pass (considering all contained streams'
+	  metadata), and do so incrementally as needed for playback rather than
+	  an initial complete scan of all moof (though all moov sample metadata
+	  is fully parsed at startup).
+
+2010-11-04 10:06:30 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: refactor stream freeing
+
+2010-11-04 10:05:15 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: delegate linear search for sample to binary search when possible
+	  Also arrange for parsing a sample prior to taking a reference to it,
+	  which requires less memory layout assumptions for correctness.
+
+2010-11-01 15:52:29 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fragmented support; handle moov samples and proper stream duration
+
+2010-11-01 13:40:05 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fragmented support; consider mvex and handle flags and offset fields
+
+2010-10-28 16:49:41 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fragmented support; forego check for short streams
+	  ... as some bogus files may indicate streams of 0 duration in moov,
+	  while indicating the complete movie duration in mvhd (the latter should
+	  be in mehd).
+
+2010-10-28 16:46:48 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_types.h:
+	  qtdemux: fragmented support; code cleanups and optimizations in atom parsing
+	  Avoid extra allocation in _parse_trun, add more checks for parsing errors,
+	  add or adjust some debug statement, fix comments, sprinkle some branch
+	  prediction.
+
+2010-09-13 23:19:44 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: parse_moof should return TRUE on success
+
+2010-09-10 22:41:03 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix iteration bug
+	  Avoid infinite loop when iterating traf
+
+2010-09-10 21:32:26 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Refactor trun parsing
+	  The allocation of the samples can be placed out of the loop.
+	  Makes the code clearer.
+	  Also avoid relying on traf information as it is placed on the
+	  end of the file and might not be acessible on push mode.
+
+2010-09-10 00:29:26 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Remove parsing of unused atom
+	  sdtp atom is parsed but not used, so we don't have to
+	  parse it.
+
+2010-11-09 11:45:00 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: tweak wam support
+	  ... with some comment and portability macros.
+
+2009-09-23 18:47:42 +0200  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	* gst/qtdemux/qtdemux_types.c:
+	  qtdemux: support wma & vc-1
+	  https://bugzilla.gnome.org/show_bug.cgi?id=596321
+
+2010-03-11 09:56:04 +0100  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux.h:
+	  qtdemux: parse fmp4 samples information
+	  The fragmented mp4 format stores the tracks and samples information in the
+	  'moof' boxes, which are appended before each fragment (fragment->'moof'+'mdat').
+	  The 'mfra' box stores the offset of each 'moof' box and their presentation
+	  time. The location of this box can be retrieved from the 'mfro' box, which is
+	  located at the end of the file.
+	  The 'mfra' box is parsed to get the offset of each 'moof' box and their
+	  presentation time.
+	  Each 'moof' box can contain information for one or more tracks inside
+	  'tfhd' boxes. For each track in a 'moof', we have a 'trun' box, which
+	  contains information of each sample (offset and duration) used to build
+	  the samples table.
+	  Based on patch by Marc-André Lureau <mlureau@flumotion.com>
+	  https://bugzilla.gnome.org/show_bug.cgi?id=596321
+
+2010-03-11 15:34:49 +0100  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/qtdemux/qtatomparser.h:
+	* gst/qtdemux/qtdemux_dump.c:
+	* gst/qtdemux/qtdemux_dump.h:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	* gst/qtdemux/qtdemux_types.c:
+	* gst/qtdemux/qtdemux_types.h:
+	  qtdemux: add fragmented mp4 fourccs
+	  Adds fourcc's for tfra, tfhd, trun, sdtp, trex, mehd and
+	  their dumps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=596321
+
+2010-03-11 10:24:56 +0100  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: parse the track id from the track header
+	  Signed-off-by: Andoni Morales Alastruey <amorales@flumotion.com>
+	  https://bugzilla.gnome.org/show_bug.cgi?id=596321
+
+2010-03-11 14:10:12 +0100  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: allow pulling atoms with unknown size
+	  Signed-off-by: Andoni Morales Alastruey <amorales@flumotion.com>
+	  https://bugzilla.gnome.org/show_bug.cgi?id=596321
+
+2010-07-14 20:13:55 +0200  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/qtdemux/qtdemux_dump.c:
+	  qtdemux: make qtdemux_dump_mvhd parse version 1 correctly
+	  Versions 0 and 1 of mvhd have different sizes of its values
+	  (32bits/64bits). This patch makes it dump them correctly.
+	  Also use the right node in the parameter and not the root node.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=596321
+
+2010-11-19 12:45:00 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskademux: minor cleanups in setting streamheader on caps
+
+2010-11-02 17:04:04 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: normalize empty Cues to no Cues
+	  ... to trigger indexless seeking.
+
+2010-10-26 11:15:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: add workaround for buggy list size
+	  Fixes truncated extra-data in hdrl/strl/strf due to buggy containing
+	  list size not accounting for padding in contained chunks.
+
+2010-12-02 16:11:01 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: do not hold custom PAD_LOCK when pushing downstream
+
+2010-12-02 16:10:14 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: reset session manager base time when flushing
+	  ... as rtpbin uses running time to handle rtpjitterbuffer's buffer mode pauses.
+
+2010-12-01 16:51:33 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: include range request for all streams with non-aggregate control
+
+2010-10-07 14:50:53 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix debug statement
+
+2010-12-03 15:38:00 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Parse more variants of numerical IDIT tag
+
+2010-05-07 17:30:30 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/libpng/gstpngenc.c:
+	  pngenc: Use proper framerate range in caps
+
+2010-12-03 15:04:26 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* tests/check/pipelines/wavenc.c:
+	  tests: Fix previously unbuildable/untested wavenc test
+
+2010-10-24 15:21:08 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Refactor tag pushing logic
+	  The logic of when to push was wrong also (resulting in some tags never
+	  being pushed).
+
+2010-10-24 15:20:27 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/flv/Makefile.am:
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Use pbutils for codec descriptions
+
+2010-04-13 11:29:30 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* tests/check/elements/udpsink.c:
+	  check: Use fail_unless_equals_int instead of fail_if
+	  Makes the error message more interesting
+
+2010-11-30 19:22:11 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Also extract IDIT tags present too early
+	  https://bugzilla.gnome.org/show_bug.cgi?id=636143
+
+2010-11-30 19:21:23 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Also emit DateTime tag
+	  https://bugzilla.gnome.org/show_bug.cgi?id=636143
+
+2010-12-03 00:22:48 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: detect DTS advertised as PCM correctly in some more cases
+	  The DTS typefinder may return a lower probability for frames that start
+	  at non-zero offsets and where there's no second frame sync in the first
+	  buffer. It's fairly unlikely that we'll acidentally identify PCM data
+	  as DTS, so we don't do additional checks for now.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=636234
+
+2010-11-08 17:11:42 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/check/Makefile.am:
+	  tests: makefile cleanup
+	  Fix indentation. Use $(GST_MAJORMINOR) instead of hardcoded 0.10.
+
+2010-11-08 17:02:56 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/check/Makefile.am:
+	* tests/check/pipelines/.gitignore:
+	* tests/check/pipelines/wavenc.c:
+	  tests: add a test for wav muxing
+
+2010-11-08 16:57:17 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/check/elements/interleave.c:
+	* tests/check/pipelines/wavpack.c:
+	  tests: remove newlines between variable decls (old gst-indent failure)
+
+2010-11-08 14:47:04 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: use png_error() as recommended by libpng docs to signal an error
+	  Without that the element loops endlessly on broekn pngs. Fixes #634314
+
+2010-11-16 17:48:16 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Parse and use creation time tag from mvhd
+	  Expose creation time from mvhd as a datetime tag
+	  Fixes #634928
+
+2010-10-27 19:15:20 +0200  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* gst/icydemux/gsticydemux.c:
+	  icydemux: Add 'StreamUrl' metadata as GST_TAG_HOMEPAGE tag
+
+2010-10-23 19:34:00 -0400  Tom Janiszewski <Tom.Janiszewski@alcatel-lucent.com>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Fix for nellymoser codecid setting
+	  Fixes bug #632897.
+
+2010-10-21 16:15:08 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Add support for E-AC3
+
+2010-10-21 16:14:44 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Add support for DTS
+
+2010-10-31 18:08:17 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Don't send seeks behind the end of file to the server
+	  Also improve debug output, re-initialize the content size and let the
+	  seek handler error out on invalid seek segments.
+	  Fixes bug #632977.
+
+2010-12-02 17:53:42 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpj2kpay.c:
+	  j2kpay: use SOP markers to split bitstream
+	  When parsing the bitstream, look for SOP markers because we are allowed to split
+	  packets on those marker boundaries.
+	  Rework the parsing code a little so that we can pack multiple Packetization
+	  units in one RTP packet.
+
+2010-11-18 12:49:47 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpj2kpay.h:
+	  rtpj2kpay: use buffer lists
+	  Use buffer lists for doing zerocopy payloading.
+	  Add property to disable buffer lists.
+
+2010-11-16 16:54:25 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  h264pay: small cleanups
+	  Allocate adapter only once.
+	  Make some guint8 * const.
+
+2010-11-16 15:39:24 +0100  Tambet Ingo <tambet at gmail.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtph264pay.h:
+	  rtph264pay: implement full bytestream scan mode.
+	  Implement the full bytestream scan mode.
+	  Fixes #634910
+
+2010-11-15 10:52:31 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/examples/rtp/client-H263p-AMR.sh:
+	* tests/examples/rtp/client-H263p-PCMA.sh:
+	* tests/examples/rtp/client-H263p.sh:
+	* tests/examples/rtp/client-H264-PCMA.sh:
+	* tests/examples/rtp/client-H264.sh:
+	* tests/examples/rtp/client-PCMA.sh:
+	* tests/examples/rtp/server-v4l2-H264-alsasrc-PCMA.sh:
+	  examples: improve RTP examples
+	  Make the examples use autovideosink and ffmpegcolorspace for better
+	  compàtibility.
+	  Make some more variables for the sink and the decoders.
+	  Set zerolatency tuning on x264enc for better realtime results.
+
+2010-11-10 11:04:48 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: select multicast transports in a smarter way
+	  When we see a multicast address in the SDP connection, only try to negotiate a
+	  multicast transport with the server.
+	  Fixes #634093
+
+2010-12-02 18:14:16 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  Bump GLib requirement to implicit requirement
+	  ie. >= 2.20 while we depend on core/base 0.10.31
+
+2010-12-02 18:13:57 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	  Back to development
+
+=== release 0.10.26 ===
+
+2010-12-01 21:15:09 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.10.26
+
+2010-11-30 15:28:50 -0800  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: analyse RFF fields in correct order
+	  Code was repeating the second field, not the first.
+	  Fixes: #636179.
+
+2010-11-29 15:32:40 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: handle stale digest authentication session data
+	  In particular, handle Unauthorized server response when trying to convey
+	  keep-alive.
+	  Fixes #635532.
+
+2010-11-26 15:00:29 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: fix segfault on empty payload
+	  https://bugzilla.gnome.org/show_bug.cgi?id=635843
+
+2010-11-25 19:06:27 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  dtmf: Remove dead assignments
+
+2010-11-18 00:45:29 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.10.25.5 pre-release
+
+2010-11-18 00:44:45 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/bg.po:
+	* po/fi.po:
+	* po/hu.po:
+	* po/sk.po:
+	* po/tr.po:
+	  po: update translations
+
+2010-11-14 00:18:16 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: fix reference leak
+
+2010-11-12 23:59:06 +1100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Flush QoS and history before applying segment
+	  When handling newsegment, flush out the buffer history in the
+	  existing segment, not the new one. Fixes playback in some DVD
+	  cases.
+	  Partially fixes #633294
+
+2010-11-12 12:20:16 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: improve event logging
+
+2010-11-05 17:00:15 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  deinterlace: Implement field history flushing
+	  In a number of cases it is necessary to flush the field history by
+	  performing 'degraded' deinterlacing - that is, using the user-chosen
+	  method for as many fields as possible, then using vfir for as long as
+	  there are >= 2 fields remaining in the history, then using linear for
+	  the last field.
+	  This should avoid losing fields being kept for history for example at
+	  EOS.
+	  This may address part of #633294
+
+2010-11-05 15:44:35 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Refactor chain function
+	  This is needed to be able to output a frame from outside the chain
+	  function, i.e. in the following commit that adds flushing of the field
+	  history.
+
+2010-11-05 17:17:56 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: we still require Gtk+ >= 2.14.0 when compiling against 2.0
+	  The check for the minor version was dropped in the previous commit.
+
+2010-11-05 16:24:42 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: add --with-gtk option and default to Gtk+ 2.0 while the 3.0 API is still in flux
+	  https://bugzilla.gnome.org/show_bug.cgi?id=634014
+
+2010-11-04 16:42:07 +1000  Jonathan Matthew <jonathan@d14n.org>
+
+	* gst/icydemux/gsticydemux.c:
+	  icydemux: fix use-after-free of taglist
+	  Broken by commit 4c2f5333 (bug #630205).
+	  https://bugzilla.gnome.org/show_bug.cgi?id=633970
+
+2010-11-01 17:29:01 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.10.25.4 pre-release
+
+2010-11-01 17:28:36 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/es.po:
+	* po/fr.po:
+	* po/it.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/pl.po:
+	* po/sl.po:
+	* po/sv.po:
+	  po: update translations
+
+2010-11-01 16:04:20 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: fix --disable-external
+
+2010-11-01 14:56:28 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264depay.h:
+	  rtph264depay: only set delta unit on all-non-key units
+	  Only set the delta flag when all of the units in the packet are delta units.
+	  Based on patch from Olivier Crête <olivier.crete@collabora.co.uk>
+	  Fixes #632945
+
+2010-10-26 15:44:37 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/goom/gstgoom.c:
+	  goom: Return not-negotiated when bps is unknown
+	  If caps weren't negotiated, goom should return not-negotiated
+	  from its chain functions instead of using bps unitialized, which
+	  leads to a division by 0
+	  https://bugzilla.gnome.org/show_bug.cgi?id=633212
+
+2010-10-27 13:16:54 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 7bbd708 to 011bcc8
+
+2010-10-26 16:54:11 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: Forward src pad events upstream.
+	  Fix passing navigation and other events upstream by actually sending them.
+	  Fixes: #633205
+
+2010-10-24 18:50:30 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix deadlock in error code path
+	  GST_ELEMENT_ERROR must not be called with the object lock held,
+	  since it will call gst_object_get_parent() internally, which
+	  takes the object lock as well.
+
+2010-10-20 10:21:48 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Remove useless clearing of send_xiph_headers for Dirac
+	  This looks like a mistake when copy-pasting the Theora code.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=632682
+
+2010-10-20 13:28:28 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: don't crash if vorbis/theora codec data is missing
+	  Error out properly in this case instead of crashing.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=632682
+
+2010-10-22 18:11:46 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.10.25.3 pre-release
+
+2010-10-19 16:45:51 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix duration reporting
+	  Init segment prior to storing duration info in it.
+	  Fixes #632548.
+
+2010-10-19 14:21:53 +0100  Bastien Nocera <hadess@hadess.net>
+
+	* gconf/Makefile.am:
+	  gconf: Don't install schemas when GConf is disabled
+	  https://bugzilla.gnome.org/show_bug.cgi?id=632553
+
+2010-10-19 13:43:14 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  various (gst): add missing G_PARAM_STATIC_STRINGS flags
+	  Canonicalize property names as needed.
+
+2010-10-19 13:44:25 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  dtmfsrc: remove DEBUG_FUNCPTR from gobject vmethods
+
+2010-10-16 15:43:53 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  win32: set GST_PACKAGE_RELEASE_DATETIME also in win32 config.h
+
+2010-10-16 01:33:52 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.10.25.2 pre-release
+
+2010-10-16 01:26:01 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/el.po:
+	* po/vi.po:
+	  po: update translations
+
+2010-10-15 13:22:03 -0700  David Schleef <ds@schleef.org>
+
+	* tests/check/Makefile.am:
+	  tests: Don't dist generated orc files
+
+2010-10-15 14:02:19 -0700  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/tvtime-dist.c:
+	* gst/deinterlace/tvtime-dist.h:
+	* gst/videobox/gstvideoboxorc-dist.c:
+	* gst/videobox/gstvideoboxorc-dist.h:
+	* gst/videomixer/blendorc-dist.c:
+	* gst/videomixer/blendorc-dist.h:
+	  Update generated orc code
+
+2010-10-15 18:00:10 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: bump Orc requirement to 0.4.11
+
+2010-10-14 17:41:30 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Use the right constant to define the "use-pipeline-clock" property
+	  The wrong #define was being used, now use the correct one.
+
+2010-10-14 12:31:48 -0700  David Schleef <ds@schleef.org>
+
+	* common:
+	  Automatic update of common submodule
+	  From 5a668bf to 7bbd708
+
+2010-10-14 17:26:14 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/qtdemux/qtdemux.c:
+	  ac3: demuxers provide framed output
+
+2010-10-14 00:11:27 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/ebml-write.h:
+	  matroskamux: reduce newsegment event spam and set discont flag where needed
+	  Only send newsegment events with new positions downstream when actually
+	  needed, instead of sending multiple newsegment events with new seek
+	  positions in a row. Also set the discont flag on buffers after a
+	  discontinuity.
+
+2010-10-13 23:46:02 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/ebml-write.h:
+	  matroskamux: set correct buffer offsets after seeks
+	  Re-use the existing 'pos' field maintained by ebml writer to set
+	  buffer offsets. This also makes sure that we set the right offsets
+	  on buffers after a seek (e.g. when writing an index at the end).
+
+2010-10-14 00:22:03 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: don't forward tag events downstream
+	  Don't forward stream-specific tag events downstream (esp. not
+	  before any newsegment event).x
+
+2010-10-13 17:15:25 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	  qtdemux: handle another mp4v variation
+	  ... including the glbl atom containing codec-data.
+
+2010-10-13 17:21:23 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audioinvert.c:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/audiofx/audiopanorama.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	* gst/avi/gstavimux.c:
+	* gst/cutter/gstcutter.c:
+	* gst/debugutils/breakmydata.c:
+	* gst/debugutils/efence.c:
+	* gst/debugutils/gstnavseek.c:
+	* gst/debugutils/negotiation.c:
+	* gst/debugutils/progressreport.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/id3demux/gstid3demux.c:
+	* gst/level/gstlevel.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/median/gstmedian.c:
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartmux.c:
+	* gst/replaygain/gstrganalysis.c:
+	* gst/replaygain/gstrglimiter.c:
+	* gst/replaygain/gstrgvolume.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtsp/gstrtpdec.c:
+	* gst/smpte/gstsmpte.c:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videofilter/gstvideotemplate.c:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	  various (gst): add a missing G_PARAM_STATIC_STRINGS flags
+
+2010-10-13 17:13:04 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/oss/gstossmixerelement.c:
+	* sys/oss/gstosssink.c:
+	* sys/oss/gstosssrc.c:
+	* sys/oss4/oss4-mixer.c:
+	* sys/oss4/oss4-sink.c:
+	* sys/oss4/oss4-source.c:
+	* sys/osxvideo/osxvideosink.m:
+	* sys/sunaudio/gstsunaudiosink.c:
+	* sys/sunaudio/gstsunaudiosrc.c:
+	* sys/ximage/gstximagesrc.c:
+	  various (sys): add a missing G_PARAM_STATIC_STRINGS flags
+
+2010-10-13 16:25:15 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/aalib/gstaasink.c:
+	* ext/annodex/gstcmmldec.c:
+	* ext/annodex/gstcmmlenc.c:
+	* ext/annodex/gstcmmltag.c:
+	* ext/cairo/gsttextoverlay.c:
+	* ext/dv/gstdvdec.c:
+	* ext/esd/esdmon.c:
+	* ext/esd/esdsink.c:
+	* ext/flac/gstflacenc.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	* ext/gdk_pixbuf/pixbufscale.c:
+	* ext/hal/gsthalaudiosink.c:
+	* ext/hal/gsthalaudiosrc.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstsmokeenc.c:
+	* ext/libcaca/gstcacasink.c:
+	* ext/libpng/gstpngenc.c:
+	* ext/mikmod/gstmikmod.c:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	* ext/shout2/gstshout2.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	* ext/wavpack/gstwavpackenc.c:
+	  various (ext): add a missing G_PARAM_STATIC_STRINGS flags
+
+2010-10-13 16:34:09 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/aalib/gstaasink.c:
+	* ext/esd/esdmon.c:
+	* gst/median/gstmedian.c:
+	  various: wrap property registration and add a single fixme for long desc.
+
+2010-10-13 11:46:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	  h264depay: always mark the codec_data as keyframe
+	  We need to mark the codec_data as a keyframe or else downstream decoders might
+	  decide to skip it, waiting for a keyframe.
+	  Fixes #631996
+
+2010-10-13 07:16:47 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/ebml-write.c:
+	  matroskamux: make buffer offsets a byte count rather than a buffer count
+
+2010-10-07 21:12:48 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/aalib/gstaasink.c:
+	* ext/dv/gstdvdec.c:
+	* ext/esd/esdmon.c:
+	* ext/flac/gstflacenc.c:
+	* ext/mikmod/gstmikmod.c:
+	* ext/raw1394/gstdv1394src.c:
+	* gst/debugutils/efence.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	  ext, gst: canonicalise property names where this wasn't the case
+	  ie. "foo_bar" -> "foo-bar"
+
+2010-10-12 15:02:42 +0200  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/rtp/gstrtpmpvpay.c:
+	  rtpmpvpay: fix timestamping of rtp buffers
+	  Incomming buffer is only pushed on the adapter at the end of the
+	  handle_buffer function. But duration/timestamp of this buffer is already
+	  taken into account for the current data in the adapter. This leads to
+	  wrong rtp timestamps and extra latency.
+
+2010-10-12 11:37:40 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/examples/equalizer/demo.c:
+	* tests/examples/spectrum/demo-audiotest.c:
+	* tests/examples/spectrum/demo-osssrc.c:
+	  examples: Fix build with GTK+ 3.0
+
+2010-10-11 15:12:00 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: mark as a source
+	  Mark the rtspsrc element as a source.
+	  Requires 0.10.31.1 now
+
+2010-10-11 14:24:13 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosrc.c:
+	  autodetect: Set GST_ELEMENT_IS_SOURCE flag on sources
+
+2010-10-11 14:21:07 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/gconf/gstswitchsrc.c:
+	  switchsrc: Set the GST_ELEMENT_IS_SOURCE flag
+
+2010-10-11 14:17:33 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Require core 0.10.30.1
+
+2010-10-10 14:43:58 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/ebml-write.h:
+	  matroskamux: set offsets on outgoing buffers
+
+2010-10-09 14:14:27 +0200  IOhannes m zmölnig <zmoelnig@iem.at>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: Only get/set overlay params if needed
+	  it's perfectly ok for a video output device to not have overlay capabilities.
+	  this patch removes the need to get/set the overlay parameters if the user
+	  does not explicitely request one of the overlay properties
+
+2010-09-30 15:28:23 +0200  IOhannes m zmölnig <zmoelnig@iem.at>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: Protect against NULL-pointer access
+	  gst_v4l2sink_change_state() would free the pool without checking whether there
+	  was a valid pool...
+
+2010-10-08 12:43:51 -0700  David Schleef <ds@schleef.org>
+
+	* common:
+	  Automatic update of common submodule
+	  From c4a8adc to 5a668bf
+
+2010-10-08 12:53:33 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 5e3c9bf to c4a8adc
+
+2010-10-06 11:29:55 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Fix required fields logic
+	  Both history_count and fields_required count from 1. As per the while loop
+	  condition that follows this code, to perform the deinterlacing method, we need
+	  history_count >= fields_required fields in the history. Therefore if we have
+	  history_count < fields_required (not fields_required + 1), we need more fields.
+
+2010-09-20 19:43:45 +0200  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  flvmux: resend onMetada tag when tags changes in streamable mode
+
+2010-10-05 19:40:50 +0100  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: AAC codec_data can be > 2 bytes long
+	  This fixes the assumption that DecoderSpecificInfo must be 2 bytes long
+	  for AAC files. The specification allows HE-AAC to be explicitly
+	  signalled in a backward compatible way. This is done by means of an
+	  additional information after the regular AAC header. It is expected that
+	  decoders that can play AAC but not HE-AAC will parse the header normally
+	  and ignore extended bits, much as they do for the HE-AAC specific payload
+	  in the actual stream.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=612313
+
+2010-10-05 16:01:19 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: only unref buffer when no longer needed for cluster scanning
+	  Fixes #629047.
+
+2010-10-05 16:00:45 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: avoid infinite cluster scanning
+
+2010-10-05 12:20:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	  goom: take duration into account when doing QoS
+	  Take the duration of the frames into account so that we don't drop frames that
+	  are only partially past the QoS deadline.
+
+2010-10-05 10:40:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/goom/gstgoom.c:
+	* gst/goom/gstgoom.h:
+	* gst/goom2k1/gstgoom.c:
+	* gst/goom2k1/gstgoom.h:
+	  goom: use adapter for timestamping
+	  Use the adapter timestamp code to get more accurate timestamps.
+	  Fix latency calculation, we add our own latency in the worst case.
+
+2010-10-04 22:31:32 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* configure.ac:
+	* ext/raw1394/Makefile.am:
+	* ext/raw1394/gst1394.c:
+	  raw1394: Don't compile hdv1394src if libiec61883 isn't available
+	  Fixes #629896
+
+2010-09-20 19:44:09 +0200  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* gst/icydemux/gsticydemux.c:
+	  icydemux: forward tag events
+	  https://bugzilla.gnome.org/show_bug.cgi?id=630205
+
+2010-10-04 19:00:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/goom2k1/gstgoom.c:
+	  goom2k1: report our latency correctly
+	  Fixes #631303
+
+2010-10-04 18:56:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/goom2k1/gstgoom.c:
+	  goom2k1: add defines for default width/height/fps
+	  Add some defines for the default width/height/fps instead of using different
+	  values in different places.
+
+2010-10-04 18:52:14 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/goom/gstgoom.c:
+	  goom: add latency compensation code.
+	  Implement a latency query and report how much latency we will add to the
+	  stream.
+	  Alse make some defaults for the default width/height/framerate
+	  Fixes #631303
+
+2010-10-04 17:56:57 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/examples/rtp/server-alsasrc-PCMA.py:
+	  test: add python version of the audio sender
+	  Add a python version of the audio sender pipeline.
+	  Ported by Sp4rc on IRC.
+
+2010-10-04 17:52:22 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/examples/rtp/client-PCMA.py:
+	  tests: Add python RTP client example
+	  Add a python version of the PCMA client app.
+	  Ported by Sp4rc on IRC.
+
+2010-10-04 09:39:59 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4gpay.c:
+	  rtp: Fix unitialized compiler warnings on OS X build bot
+	  These warnings are wrong though, the variables are only used in
+	  the cases where they *are* initialized by the bit reader.
+
+2010-10-03 23:49:08 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtp/gstrtpg722pay.c:
+	  rtpg722pay: Fix uninitialized variable compiler warning
+	  The clock rate is always 8000 Hz according to the RFC and
+	  the sampling rate must always be 16000 Hz.
+
+2010-10-01 13:59:10 +0400  Vladimir Eremeev <eremeev@atlantis.ru>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: improve article reference in comment block
+	  https://bugzilla.gnome.org/show_bug.cgi?id=631082
+
+2010-04-30 21:00:31 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/quicktime.c:
+	  qtdemux: Use pbutils for H.264 profile/level extraction
+	  The functions used to extract this data have been moved to gstpbutils to
+	  facilitate reuse.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=617318
+
+2010-04-30 21:00:31 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/matroska/Makefile.am:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska.c:
+	  matroskademux: Use pbutils for H.264 profile/level extraction
+	  The functions used to extract this data have been moved to gstpbutils to
+	  facilitate reuse.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=617318
+
+2010-04-22 19:39:47 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Export MPEG-4 video profile and level in stream caps
+	  This uses gstpbutils to extract the profile and level from the video
+	  object sequence and adds this to stream caps. This can be used as
+	  metadata and for fine-grained decoder selection.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=616521
+
+2010-09-30 12:44:52 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix aac channel override based on codec data for 7.1 case
+
+2010-04-30 14:06:27 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/qtdemux/Makefile.am:
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Export AAC profile and level in caps
+	  This exports the AAC profile and level in caps for use as metadata and
+	  (eventually) for more fine-grained selection of decoders at
+	  caps-negotiation time. (Doesn't work for HE-AAC yet though.)
+	  https://bugzilla.gnome.org/show_bug.cgi?id=612313
+
+2010-09-30 18:34:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpg722depay.c:
+	* gst/rtp/gstrtpg722depay.h:
+	* gst/rtp/gstrtpg722pay.c:
+	* gst/rtp/gstrtpg722pay.h:
+	  rtp: add G722 pay and depayloader
+
+2010-09-30 12:08:49 +0200  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: update link to documentation
+
+2010-09-30 11:34:56 +0200  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* tests/examples/rtp/client-H264.sh:
+	  examples: fix indentation on rtp client example
+
+2010-09-30 11:33:24 +0200  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* tests/examples/rtp/client-H264-PCMA.sh:
+	* tests/examples/rtp/client-H264.sh:
+	  examples: fix typo in port of rtp examples
+
+2010-09-29 13:20:22 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: miniscule code clean-up
+	  GST_CLOCK_TIME_NONE is not something that should be used in connection with
+	  GST_FORMAT_BYTES.
+
+2010-09-29 10:34:36 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: reverse playback; prevent overlap of subsequent fragments
+
+2010-09-28 16:21:48 +0300  René Stadler <rene.stadler@nokia.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix missing null-terminator in protocols array
+	  Fixes random crash regression from commit ae84ae.
+
+2010-09-24 16:26:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: don't add /UDP in the transport, it's the default
+	  don't add the default UDP lower-transport, some servers don't seem to like it.
+	  Fixes #630500
+
+2010-06-25 17:08:03 +0200  Pascal Buhler <pascal.buhler@tandberg.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpmanager: packet lost should not be a warning. It happens all the time...
+
+2010-09-24 15:33:40 +0200  Pascal Buhler <pascal.buhler@tandberg.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpbin: Make cleaning up sources in rtp_session_on_timeout MT safe
+	  Using _foreach_remove on the hashtable, while releasing the lock protecting
+	  that table inside the callback is not a good idea. The hashtable might
+	  then change (a source removed or added) while signals like on_timeout
+	  are being sent.
+	  This solution makes a copy of the table, performs the _foreach without
+	  actually removing any sources, but marks them for removal on a second
+	  iteration with the real list, but this time not letting go of the lock.
+	  Fixes #630452
+
+2010-09-24 15:19:15 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/id3demux/id3tags.c:
+	  id3demux: Sanitize id3 frame names
+	  This is similar to what is done in qtdemux. Avoids providing invalid
+	  structure/tags names
+
+2010-09-24 14:59:45 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/apetag/gstapedemux.c:
+	  apedemux: Skip empty tags
+	  Avoid creating bogus string tags. Also added logging of the string
+	  values of the tag name and value.
+
+2010-09-24 08:56:36 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  soup: init debug category before using it
+
+2010-04-12 09:49:14 +0200  Pascal Buhler <pascal.buhler@tandberg.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Handle rysnc of iterator when looking for free pad name
+	  If a new pad was added while iterating then a pad could be
+	  returned that was already in use.
+	  Fixes #630451
+
+2010-09-24 14:09:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: fix compilation
+
+2010-04-07 15:31:52 +0200  Trond Andersen <trond.andersen@tandberg.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Unlock before adding pad in new_payload_found
+	  Holding internal locks while potentially calling out is a source
+	  of deadlocks, and in this case the application might subscribe to the
+	  pad-added signal.
+	  Fixes #630449
+
+2009-08-31 18:37:40 +0200  Havard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: relax third-party collision detection
+	  If the source has been inactive for some time, we assume that it has
+	  simply changed its transport source address. Hence, there is no true
+	  third-party collision - only a simulated one.
+	  Fixes #630447
+
+2010-09-24 13:50:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: whitespace fixes
+
+2010-09-24 13:48:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: simplify the rate estimation some more
+
+2009-08-31 18:34:08 +0200  Havard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpstats.c:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpmanager: provide additional statistics
+
+2010-09-24 00:01:05 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: set plugin release datetime
+
+2010-09-23 21:21:29 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/equalizer/gstiirequalizer10bands.h:
+	* gst/equalizer/gstiirequalizer3bands.h:
+	* gst/equalizer/gstiirequalizernbands.h:
+	  equalizer: fix class definitions
+	  Class structures must be based on the parent class struct, not on
+	  the parent instance struct.
+
+2010-09-15 20:36:33 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer2: pre-register pad class properly with g_type_class_ref
+	  Fix code to match the comment. Also, there's no need to register the
+	  background enum type again, this is already done via install_property.
+
+2010-09-23 21:57:18 +0200  David Hoyt <dhoyt@llnl.gov>
+
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	  speex: Fix crashes with MSVC
+	  Using the symbols for the different Speex modes results
+	  in crashes when using MSVC. Use the library functions to
+	  get the modes instead.
+	  Fixes bug #630378.
+
+2010-08-24 13:25:02 +0200  Havard Graff <havard.graff@tandberg.com>
+
+	* gst/level/gstlevel.c:
+	  level: avoid division by zero on silence
+	  Fixes bug #630458.
+
+2010-09-23 16:46:31 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: parse and use cts
+	  For H264, there is an extra header containing the CTS, which is a timestamp
+	  offset that should be applied to the PTS. Parse this value and use it to adjust
+	  the pts.
+	  Fixes #630088
+
+2010-09-23 16:45:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: improve pts debugging
+
+2010-09-22 19:01:40 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* tests/examples/Makefile.am:
+	* tests/examples/pulse/.gitignore:
+	* tests/examples/pulse/Makefile.am:
+	* tests/examples/pulse/pulse.c:
+	  pulse: add test app for pulse device probe
+
+2010-09-22 18:50:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	  pulse: fix device_description in READY
+	  Make the is_dead check more clear and add an option to check for the status of
+	  the stream in addition to the context.
+	  We don't need a stream to get the device_description string.
+	  Fixes #630317
+
+2010-09-22 12:56:00 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Don't post tags if there are none
+	  And make all code go through _post_global_tags.
+
+2010-09-22 12:37:33 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264depay.h:
+	  rtph264depay: refactor and simplify AU merging
+	  Move the processing of the NALU to a separate method.
+	  Simplify the merging of NALU into AU and use common code when possible.
+
+2010-09-21 23:23:07 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/examples/shapewipe/shapewipe-example.c:
+	  shapewipe: add optional border parameter and slowdown animation
+	  Allow to play with the border property (sharp/soft edges).
+
+2010-09-21 19:14:40 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  shapewipe: Force format to AYUV in the example pipeline for the same reason
+
+2010-09-21 19:13:07 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/examples/shapewipe/shapewipe-example.c:
+	  shapewipe: Force the input to AYUV to prevent negotiation failures in videomixer
+	  The second videotestsrc chain might produce YUY2 because everything is
+	  accepted downstream before the first shapewipe chain gets negotiated.
+
+2010-09-21 19:12:45 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  shapewipe: Improve debugging and immediately return empty caps from the getcaps functions
+
+2010-09-21 18:33:55 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From aa0d1d0 to 5e3c9bf
+
+2010-09-21 12:49:31 +0200  Philippe Normand <pnormand@igalia.com>
+
+	* sys/v4l2/gstv4l2xoverlay.c:
+	* sys/v4l2/gstv4l2xoverlay.h:
+	  v4l2: use the xoverlay APIs
+
+2010-09-21 12:48:34 +0200  Philippe Normand <pnormand@igalia.com>
+
+	* configure.ac:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: use the new xoverlay APIs
+	  Also bumped -base requirements.
+
+2010-09-21 12:31:59 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Use -DGST_DISABLE_DEPRECATED again for GIT versions
+
+2010-09-21 11:52:22 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Fix debug statement
+
+2010-09-20 23:17:35 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Parse uuid atoms in push mode
+	  Parses uuid atoms in push mode when they are found, they might
+	  contain xmp tags.
+	  Also does a minor refactoring to put the global tags posting
+	  into a single function instead of repeating it in 3 different
+	  places.
+	  Fixes #629839
+
+2010-09-16 08:04:02 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Delay tags posting a little
+	  Delay tags posting until we've parsed all the headers so
+	  that the native and xmp tags get merged before posting
+	  https://bugzilla.gnome.org/show_bug.cgi?id=629839
+
+2010-09-15 22:13:43 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	  qtdemux: Parse xmp packet in uuid atom
+	  xmp packet is placed into a top-level uuid atom for
+	  isom/mp4 variants.
+	  This patch makes qtdemux parse all top-level atoms
+	  in pull-mode before starting to push data, making
+	  it able to find those tags.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=629839
+
+2010-09-17 11:07:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpstats.c:
+	  rtpstats: printf format fixes
+
+2010-09-17 11:07:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	  rtppay: some printf format fixes
+
+2010-09-15 18:21:11 +0200  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix logic when pushing EOS.
+	  Don't check for return values when pushing EOS. Still post an error if EOS is
+	  reached and no streams have been found.
+
+2010-09-15 17:02:57 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2src.c:
+	  docs: add gtk-doc chunks with Since: markers for new v4l2src properties
+
+2010-09-15 18:43:50 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/examples/v4l2/camctrl.c:
+	  camctrl: add license header to demo
+
+2010-09-14 17:41:28 +0200  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: don't send EOS twice on the same pad.
+
+2010-09-14 10:07:58 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	  pulsesink: move the shared mainloop from class to static var
+	  Just have one static var for the shared mainloop instead of one class variable
+	  and copies in the instance.
+
+2010-09-13 17:31:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: cleanups for DRI markers
+	  Protect against invalid DRI markers.
+	  do some cleanups
+
+2010-09-10 11:35:53 -0400  American Dynamics <GStreamer-Bugs@tycosp.com>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  gstrtpjpegpay: Added Define Restart Interval (DRI) Marker
+	  Added ability to detect and respond to a JPEG-defined DRI marker
+
+2010-06-19 19:20:18 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  gstrtpsession: Split getting the caps into its own function
+
+2010-09-13 16:03:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: small cleanup.
+
+2010-09-13 16:24:26 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	  pulsesink: rework context sharing
+	  We also need to share the main-loop threads as this owns the context. Thus have
+	  a class wide main-loop thread. From this we create a context per client-name.
+	  Instead of always looking up the context, we keep this with the instance. The
+	  reverse mapping is only needed in pulse singal handlers. This saves a lot of
+	  locking. Also one signal handler becomes simpler as ther eis only one mainloop
+	  to notify.
+	  Now valgind happy - no leaks, no bad reads/writes.
+	  This reverts major parts of commit 69a397c32f4baf07a7b2937c610f9e8f383e9ae9.
+	  Fixes #628996
+
+2010-09-13 15:44:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpstats.c:
+	  rtpsession: Small cleanups
+	  Make the property description prettier.
+	  Actually multiple the bandwidth with the fraction.
+
+2010-06-01 21:35:40 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpstats.c:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpsession: Calculate RTCP bandwidth as a fraction of the RTP bandwidth
+	  Calculate the RTCP bandwidth to be a fraction of the RTP bandwidth if it is
+	  specified as a value between 0 and 1.
+
+2010-09-13 15:29:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  session: improve bandwidth recalculation
+	  Also recalculate bandwidth when one of the source bandwidths changed.
+	  Use the newly calculated bandwidth.
+
+2010-06-01 21:17:26 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Add the option to auto-discover the RTP bandwidth
+
+2010-09-13 14:38:11 +0200  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: set use-pipeline-clock on correct GObject
+
+2010-06-02 17:51:12 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Initialise the average scaled by 16
+
+2010-09-13 12:41:11 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: add running_time argument docs
+
+2010-06-23 16:13:01 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpstats.h:
+	  rtpstats: Rectify description of current_time in RTPArrivalStats
+	  It is the current time, it is unrelated to when the packet was actually received.
+
+2010-09-13 12:31:40 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: compute the average correctly scaled
+
+2010-06-01 20:31:18 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Count sent RTCP packets after they have been finished
+	  If they are counted before calling gst_rtcp_buffer_end(), then the
+	  size is way too big.
+
+2010-06-01 19:51:34 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  gstrtpsession: Don't unref  pads in finalize
+	  The gstrtpsession object is not holding any reference to them directly
+
+2010-09-12 00:09:09 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/POTFILES.in:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/gl.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ro.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: update translations for new souphttpsrc messages
+
+2010-09-12 00:08:05 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  soup: hook up i18n bits for plugin
+	  Call bindtextdomain() etc.
+
+2010-09-12 00:04:42 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  soup: fix error messages
+	  Error messages should be translated. URIs and filenames should not
+	  be part of the error message string that's shown to the user.
+	  soup_message->reason_phrase is not translated and not suitable as
+	  error message for users (see libsoup documentation). Also fix up
+	  error codes a bit, as far as possible with the existing codes.
+
+2010-09-10 09:43:24 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: don't post an error message if buffer alloc fails with NOT_LINKED flow
+	  This is not fatal, let upstream handle it.
+
+2010-09-10 18:06:48 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: don't clear sdp when set as uri
+	  when we set the SDP with an uri, don't clear it when we go to READY.
+
+2010-09-10 18:01:18 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: use sdp uri parse method
+	  Use the sdp parse method that does proper uri escaping.
+
+2010-09-10 16:59:10 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/examples/v4l2/.gitignore:
+	* tests/examples/v4l2/Makefile.am:
+	* tests/examples/v4l2/camctrl.c:
+	  example: add v4l2 example, demonstrating the use of gst controller
+
+2010-09-10 16:55:25 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2src: don't skip calculating the duration
+
+2010-06-22 15:48:04 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	  v4l2src: add controlable colorbalance parameters
+	  Expose colorbalance controls as object properties (like we do on xvimagesink).
+	  Make them controlable.
+
+2010-09-10 13:25:39 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmparobustdepay.c:
+	  rtpmparobustdepay: fix some mis-implementation
+	  Also add some debug.
+
+2010-09-10 13:24:02 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmparobustdepay.c:
+	  rtpmparobustdepay: properly insert dummy buffers
+
+2010-09-10 11:55:26 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: add rtsp-sdp protocol support
+	  Allow setting an SDP with the rtsp-sdp:// url.
+	  Based on patch from Marco Ballesio.
+	  See #628214
+
+2010-09-10 11:35:58 +0200  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	  alphacolor: make passthrough work.
+
+2010-09-09 21:43:40 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtp/gstrtpmp4adepay.c:
+	  mp4adepay: small logging cleanup and addition to debug config parsing
+
+2010-09-09 21:42:46 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/aalib/gstaasink.c:
+	  aasink: fix context initialisation and freeing to not leak
+
+2010-09-09 21:40:51 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/check/Makefile.am:
+	* tests/check/generic/states.c:
+	  tests: allow running state tests for all elements
+	  Now one can use GST_NO_STATE_IGNORE_ELEMENTS=1 make generic/states.check
+	  to try elements that would normaly be skipped.
+
+2010-09-09 18:47:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtp-payloading.c:
+	  tests: fix rtpjpegpay test
+	  Make the data we send to the jpeg payloader be a valid jpeg file because the
+	  payloader now expects this.
+
+2010-09-09 18:47:11 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: improve debugging
+
+2010-09-09 16:31:56 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmparobustdepay.c:
+	  rtpmparobustdepay: use valid bitrate for dummy frame
+
+2010-09-08 17:07:53 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* ext/taglib/gstid3v2mux.cc:
+	  id3v2mux: Adds mapping for album artist
+	  Maps GST_TAG_ALBUM_ARTIST to TPE2 in id3v2mux
+
+2010-09-08 18:35:08 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Require orc 0.4.8
+	  The deinterlace plugin apparently fails to compile with older versions.
+
+2010-09-08 17:50:11 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: QoS handling logic only applies to forward playback
+	  Fixes #628894.
+
+2010-09-08 17:43:47 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: remove unused code
+
+2010-09-08 14:36:48 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: fixup last commit
+	  We need to prevent the eventual leak better.
+
+2010-09-08 14:16:58 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: code cleanups
+	  Use g_slist_prepend as we don't care about the order. Check for list == NULL
+	  instead of iterating the list to see if it is empty. Move ctx allocation down
+	  to prevent leak in case of failure.
+
+2010-09-08 07:13:42 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: Fix uninitialized variable compiler warning
+	  Fixes bug #629018.
+
+2010-09-07 19:02:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: simplify clock provide code
+	  Don't leak the pulsesink element by having the clock keep a ref to the sink.
+	  Create the clock only once in the constructor and use the baseaudiosink clock
+	  cleanup code.
+
+2010-09-07 17:49:05 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: move the context table init to _get_type phase
+	  This seems to fix the invalid reads on context shutdown better, altough
+	  I can't really explain.
+
+2010-09-07 17:06:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: use older g_array_free
+	  g_array_unref() is only since 2.22
+
+2010-09-07 16:49:16 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: avoid invalid adapter flush on QoS
+	  First store the available data in the adapter in the rem_img_len instance field
+	  before trying to flush the adapter with that value on QoS.
+
+2010-09-07 16:40:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: do some more sanitity checks
+	  Protect some more against invalid input.
+
+2010-09-07 15:20:12 +0200  American Dynamics <GStreamer-Bugs at tycosp.com>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  jpegpay: handle corrupted jpeg better
+	  Protect against corrupted jpeg input.
+
+2010-09-07 13:55:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  rvawdepay: cleanup unused fields
+
+2010-09-07 13:51:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  vrawdepay: handle invalid payload better
+	  Make sure we don't read more data than available in the input buffer.
+	  Clip the input data into the output buffer.
+
+2010-08-16 15:35:51 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulsesrc.h:
+	* ext/pulse/pulseutil.c:
+	* ext/pulse/pulseutil.h:
+	  pulse: allow setting stream properties
+	  Add a "properties" property to the elements to allow setting extra stream
+	  properties.
+	  Fixes #537544
+
+2010-09-07 12:08:10 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf3.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	  docs: remove introspection info for gdkpixbuf3 plugin and update version for others
+	  The versions got accidentally reverted to a pre-release version, fix that.
+
+2010-09-07 11:42:10 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From c2e10bf to aa0d1d0
+
+2010-09-07 09:20:03 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/annodex/gstcmmldec.c:
+	  cmmldec: fix flow return handling
+	  Fix buggy GST_FLOW_IS_FATAL substitution, and 'make check':
+	  -  if (!GST_FLOW_IS_FATAL (dec->flow_return) && !dec->sent_root) {
+	  +  if (dec->flow_return != GST_FLOW_OK && !dec->sent_root) {
+
+2010-09-07 00:27:07 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: don't free the context multiple times
+	  Apparently the close function of the ring-buffer can be called multiple times.
+
+2010-08-12 12:33:06 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtp/gstrtpmp4adepay.c:
+	  rtpmp4adepay: grab the sampling arte and put into caps
+	  This is needed to be able to mux the received audio into mp4 (in the case of
+	  aac). Fixes #625825.
+
+2010-09-06 14:40:02 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	  rtp: mark constant tables as const
+
+2010-08-18 14:40:48 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpamrpay.h:
+	  rtpamrpay: properly support perfect-rtptime
+
+2010-08-18 11:42:33 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpamrpay.c:
+	  rtpamrpay: proper duration for multiple frame payload
+
+2010-08-18 11:42:07 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	  rtpamr(de)pay: support AMR-WB SID frame
+
+2010-08-18 11:39:06 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpg729pay.h:
+	  rtpg729pay: properly support perfect-rtptime
+
+2010-08-16 16:08:04 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: improve framerate determining
+	  Collect a limited number of starting sample durations and use the median of
+	  those to determine caps framerate.
+
+2010-08-17 12:08:10 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: attempt more resync upon (cluster) parse error
+	  That is, if parse error occurs in state requiring to move to next cluster,
+	  and doing so to the expected next position of cluster fails, then scan for a
+	  next cluster from present position and resume from there.
+	  Fixes #620790.
+
+2010-08-16 16:05:41 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: not so fatal error handling
+	  If some bits out of place in block(group) parsing, forego and move to next.
+	  Also skip large blocks in pull mode, but need to give up in push mode.
+	  Fixes #626463.
+	  Improves #620790.
+
+2010-07-26 15:51:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: additional parse recovery
+	  In particular, upon parse failure in one cluster, we may forego remaining
+	  content and try resuming from next cluster onwards.
+	  Fixes #620790.
+
+2010-08-26 02:54:55 -0400  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  dtmfsrc: Make the dtmfsrc accept events sent with gst_element_send_event
+	  The doc says to use gst_element_send_event on the pipeline, but if
+	  we are to call it on the element itself, it's a noop. This should make it
+	  handle the event properly before delegating it to basesrc.
+
+2010-09-06 12:22:11 +0200  American Dynamics <GStreamer-Bugs at tycosp.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Add property to configure udpsrc buffer size
+	  Add a new udp-buffer-size property to configure the buffer-size on the udpsrc
+	  elements.
+	  Fixes #628058
+
+2010-08-27 17:58:47 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: add ntp-sync property
+	  Add an ntp-sync property that will sync the received streams to the server
+	  NTP time. This requires synchronized NTP times between the sender and receivers,
+	  like with ntpd.
+	  Based on patch from Thijs Vermeir.
+	  Fixes #627796
+
+2010-08-27 12:14:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: rename a variable to avoid confusion
+
+2010-08-27 11:07:34 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: rename some variables for less confusion
+
+2010-08-27 10:41:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: move comment where it belongs
+
+2010-08-26 16:00:38 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  session: minor cleanups
+	  Make clock snapshots more accurate by only sampling the same clock once.
+
+2010-08-26 10:58:26 +0200  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpbin: add use-pipeline-clock property
+	  With this property RTCP SR NTP times can be based
+	  on the system clock (maybe synced with ntpd) or the
+	  current pipeline clock.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=627796
+
+2010-08-25 09:58:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspext.c:
+	  rtspext: stop configuration on first failure
+	  Stop the configuration of a stream as soon as some of the extensions return
+	  FALSE.
+	  Fixes #581294
+
+2010-08-20 15:35:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	  multifdsink: use refcount to count host/port duplicates
+	  Instead of adding multiple client structures for the same host/port pair, use a
+	  refcount.
+	  Add a send-duplicates feature that allows you to disable sending multiple copies
+	  of the same packet to the same host when it was added multiple times. The
+	  send-duplicates property is by default set to TRUE for backwards compatibility
+	  although it is very likely that this is not desired behaviour.
+
+2010-08-19 17:06:26 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: implement custom event handler
+	  Extend the _push_event() function so that it can also send events to the udp
+	  sources when asked.
+	  Implement a custum send_event function that correctly dispatches the downstream
+	  events in TCP mode. This fixes sending EOS to rtspsrc and have it push the EOS
+	  downstream.
+
+2010-08-19 11:37:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: use _get_caps_reffed() when we can
+	  Use _get_caps_reffed()
+	  Add some more debug when opening the server connection.
+
+2010-08-16 11:29:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegdepay.h:
+	  jpegdepay: handle DISCONT and reset state
+	  Put a DISCONT event on the next output buffer when the input buffer had a
+	  DISCONT.
+	  Make sure we clear our adapter and reset our state before going to PAUSED.
+	  Free the qtables.
+	  Fixes #626869
+
+2010-08-16 11:27:53 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpg729pay.h:
+	  g729pay: extend from right parent
+
+2010-09-06 09:57:10 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: add since docs for new property.
+
+2010-08-30 16:45:48 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: use GST_BOILERPLATE macro
+
+2010-08-16 17:23:58 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/videomixer/videomixer.c:
+	  videmixer: add a example showing how to use the child properties
+	  Show how to position and set the alpho of the videos on gst-launch.
+
+2010-08-16 15:19:38 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: move the property-setter to the getter.
+
+2010-08-11 15:48:18 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum only aggregate magnitude/phase if user asks for it
+
+2010-08-11 15:45:56 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: improve performance with local vars
+	  Use 'input' instead of 'spectrum->input' which was intende already (variable
+	  exists, but not used everywhere). Also use a local version of
+	  'spectrum->input_pos'.
+
+2010-08-11 15:44:03 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: code cleanup
+	  More comments and logging. Extract one complex condition to a variable. Reorder
+	  some code for readability.
+
+2010-08-11 15:40:09 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: improve property setter
+	  consistently only update if the property actualy changed the value. Do it
+	  without reading the gvalue twice. No need to reset the spectrum analyzer for
+	  threshold changes.
+
+2010-08-11 15:38:24 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: add helper to only flush ringbuffer data without resetting the fft
+	  Reduces some duplicated code as well.
+
+2010-08-11 12:45:53 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/spectrum/gstspectrum.c:
+	* gst/spectrum/gstspectrum.h:
+	  spectrum: more comments
+
+2010-09-05 22:22:42 -0700  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Document methods with bad quality
+
+2010-09-05 22:19:56 -0700  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	  deinterlace: initialize all deinterlace class members
+	  This fixes UYVY deinterlacing.
+
+2010-09-05 18:58:13 -0700  David Schleef <ds@schleef.org>
+
+	* common:
+	  Automatic update of common submodule
+	  From d3d9acf to c2e10bf
+
+2010-09-05 18:45:21 -0700  David Schleef <ds@schleef.org>
+
+	* gst/videomixer/blend.c:
+	  videomixer: orc_init() doesn't need to be called
+	  There's no need to call orc_init() unless you're using the Orc
+	  API directly.  All code created by orcc is guaranteed to work
+	  without calling orc_init().
+
+2010-09-05 18:40:48 -0700  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/tvtime-dist.c:
+	* gst/deinterlace/tvtime.orc:
+	* gst/deinterlace/tvtime/greedy.c:
+	  deinterlace: Fix greedyl Orc implementation
+	  To agree with the previous C/asm code.
+
+2010-09-05 22:31:34 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/videomixer/videomixer2.c:
+	  videomixer2: Fail when caps are incompatible
+	  Do not forget to return false when caps are incompatible.
+
+2010-09-05 20:56:52 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/videomixer/blend.c:
+	  videomixer: Only init orc if it is available
+	  Put some ifdef around orc_init to prevent build errors
+
+2010-09-05 12:17:08 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From ec60217 to d3d9acf
+
+2010-09-04 12:46:31 -0700  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/tvtime-dist.c:
+	* gst/deinterlace/tvtime-dist.h:
+	  deinterlace: Update disted Orc files
+
+2009-06-29 11:43:07 -0700  David Schleef <ds@schleef.org>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	  v4l2src: add decimate property
+
+2010-06-04 12:09:23 -0700  David Schleef <ds@schleef.org>
+
+	* ext/dv/Makefile.am:
+	* ext/dv/gstdvdemux.c:
+	* ext/dv/gstsmptetimecode.h:
+	  dvdemux: Parse SMPTE time codes
+
+2010-08-23 02:50:36 -0700  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	  deinterlace: remove assembly code in favor of orc
+
+2010-06-08 14:54:49 -0700  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/tvtime.orc:
+	* gst/deinterlace/tvtime/greedy.c:
+	  deinterlace: implement greedy in Orc
+
+2010-09-04 11:43:21 -0700  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/tvtime-dist.c:
+	* gst/deinterlace/tvtime-dist.h:
+	* gst/videobox/gstvideoboxorc-dist.c:
+	* gst/videobox/gstvideoboxorc-dist.h:
+	* gst/videomixer/blendorc-dist.c:
+	* gst/videomixer/blendorc-dist.h:
+	  update disted Orc files
+
+2010-09-02 14:34:50 +0200  Thibault Saunier <tsaunier@gnome.org>
+
+	* gst/alpha/gstalphacolor.c:
+	  alphacolor: Fix classification
+	  This is no effect but a converter. Fixes bug #628608.
+
+2010-09-02 11:19:06 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* 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:
+	* docs/plugins/gst-plugins-good-plugins.types:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf3.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	* gst/videomixer/videomixer2pad.h:
+	  videomixer2: Add documentation and add to the docs
+
+2010-07-26 16:07:15 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/gstcollectpads2.c:
+	* gst/videomixer/gstcollectpads2.h:
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer2.c:
+	* gst/videomixer/videomixer2.h:
+	  videomixer2: Add videomixer2 element
+	  This is based on collectpads2 and is synchronizing
+	  all streams based on the running time.
+	  New features compared to old videomixer:
+	  * Synchronizing frames on the running time
+	  * Improved and simplified negotiation
+	  * Full QoS support
+	  * Variable framerate support
+	  Fixes bug #626048, #624905.
+
+2010-09-01 11:11:34 +0200  Pavel Kostyuchenko <shprotx@gmail.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Relax parsing of date tags
+	  Before we required a complete date in matroskademux but in
+	  id3demux for example only the year or year and month was possible too.
+	  Fixes bug #628454.
+
+2010-08-30 19:03:52 +0100  Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: Use GstBaseSrc::block-size as fallback size
+
+2010-08-30 18:36:54 +0100  Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: Fix using mpegts via the mmap interface
+	  MPEG doesn't have a static size per frame, so don't pretend it has one
+	  and fail when capturing because it doesn't match. Instead mark the size
+	  as unknown and let the read frame grabbing method use a reasonable fallback
+	  value (assuming that's only for actual streaming formats)
+	  Fixes bug #628349.
+
+2010-08-27 18:15:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackparse.c:
+	  wavpackparse: Don't use GST_FLOW_IS_FATAL()
+
+2010-08-27 18:13:21 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: Don't use GST_FLOW_IS_FATAL()
+	  And don't post an error message if downstream returns UNEXPECTED.
+
+2010-08-27 18:09:11 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: Don't use GST_FLOW_IS_FATAL()
+
+2010-08-27 18:05:50 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Don't use GST_FLOW_IS_FATAL()
+	  And don't post an error message if buffer allocation failed because
+	  of UNEXPECTED, which only means that downstream wants us to EOS now.
+
+2010-08-27 18:02:57 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacenc.c:
+	  flacenc/dec: Don't use GST_FLOW_IS_FATAL()
+	  And properly handle UNEXPECTED and WRONG_STATE.
+
+2010-08-27 17:52:18 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/annodex/gstcmmldec.c:
+	* ext/annodex/gstcmmlenc.c:
+	  cmmldec/enc: Don't use GST_FLOW_IS_FATAL()
+	  And as a result, don't ignore WRONG_STATE and NOT_LINKED.
+	  Both mean that it's a good idea to pass them upstream instead
+	  of pretending that everything is good.
+
+2010-08-27 17:47:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Don't use GST_FLOW_IS_FATAL()
+
+2010-08-27 17:45:53 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Don't use GST_FLOW_IS_FATAL() and GST_FLOW_IS_SUCCESS()
+
+2010-08-27 17:39:32 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Don't use GST_FLOW_IS_FATAL()
+
+2010-08-27 17:37:33 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Don't use GST_FLOW_IS_FATAL()
+
+2010-08-27 17:35:47 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/debugutils/rndbuffersize.c:
+	  rndbuffersize: Don't use GST_FLOW_IS_FATAL()
+
+2010-08-27 17:35:38 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Don't use GST_FLOW_IS_FATAL()
+
+2010-08-27 17:32:09 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Don't use GST_FLOW_IS_FATAL()
+	  And document why wrong-state doesn't need an error message.
+
+2010-08-26 13:44:49 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Fail gracefully if no threaded PA mainloop can be created
+	  Fixes bug #628020.
+
+2010-08-24 15:11:20 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blendorc-dist.c:
+	* gst/videomixer/blendorc-dist.h:
+	  videomixer: Update disted ORC files
+
+2010-08-23 15:44:50 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/blend.c:
+	* gst/videomixer/blend_mmx.h:
+	* gst/videomixer/blendorc.orc:
+	* gst/videomixer/videomixer.c:
+	  videomixer: Optimize ARGB blending and implement BGRA blending with orc
+	  This now means, that we have absolutely no handwritten assembly anymore
+	  in videomixer and it's also faster now when using SSE.
+
+2010-08-22 01:58:05 -0700  David Schleef <ds@schleef.org>
+
+	* gst/videomixer/blend.c:
+	* gst/videomixer/blendorc.orc:
+	  videomixer: Add orc implementation for blending
+	  videomixer: Add orc implementation for blending
+
+2010-08-22 01:54:16 -0700  David Schleef <ds@schleef.org>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: Fix example pipelines
+	  videomixer: Fix example pipelines
+
+2010-08-20 11:41:55 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/imagefreeze.c:
+	  imagefreeze: Add test for checking if imagefreeze correctly returns UNEXPECTED after the first buffer
+
+2010-08-20 11:38:09 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/imagefreeze.c:
+	  imagefreeze: Add test for bufferalloc passthrough
+
+2010-08-20 10:35:15 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/imagefreeze.c:
+	  imagefreeze: Fix race conditions in the unit test
+	  If setting the pipeline to PLAYING before issuing the seek, buffers
+	  are already arriving at the sink before the seek is handled and
+	  will have the wrong timestamps and everything.
+	  Fixes bug #625547.
+
+2010-08-20 10:34:17 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/imagefreeze/gstimagefreeze.h:
+	  imagefreeze: Fix another subtle race condition related to starting the srcpad task
+	  Due to a seek the srcpad task could be started in rare circumstances although
+	  it shouldn't be started anymore because no upstream buffer is available.
+
+2010-08-20 10:24:33 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/imagefreeze/gstimagefreeze.h:
+	  imagefreeze: Protect the flushing-seek variable by the srcpad's stream lock
+	  This fixes a subtle race condition, that caused bufferalloc to fail
+	  with wrong-state due to a seek but caused it to be not retried as
+	  it should.
+
+2010-08-20 09:14:59 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Always generate a perfectly timestamped stream
+	  Before there could be rounding errors when calculating the duration,
+	  resulting in timestamp + duration being smaller than the next buffer's
+	  timestamp.
+
+2010-08-19 18:38:39 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Only include the server name in the context name if it's not NULL
+
+2010-08-18 16:37:41 +0200  Philippe Normand <pnormand@igalia.com>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	  pulsesink: Add "client" property to set the PA client name
+	  Allows the application to modify the client name used to connect when
+	  connecting to the PulseAudio daemon. Note however that updating the
+	  property after the element reached the READY state will have no
+	  effect until the next NULL->READY transition.
+	  Fixes bug #627174.
+
+2010-08-19 17:59:09 +0200  David Hoyt <dhoyt@llnl.gov>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Improve error messages
+	  Before they contained the URL before the actual failure. The other
+	  way around makes more sense and we do the same in other elements
+	  like filesrc.
+	  Fixes bug #627289.
+
+2010-08-19 12:46:50 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Free the clock on state change failures too
+
+2010-08-17 16:26:41 +0200  Philippe Normand <pnormand@igalia.com>
+
+	* configure.ac:
+	* ext/pulse/pulseutil.c:
+	* win32/common/config.h:
+	  pulseutil: include pid value in gst_pulse_client_name() fallback return value
+	  Fixes bug #627162
+
+2010-08-19 12:32:59 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Free the GstPulseContext after usage
+
+2010-08-16 09:12:04 +0200  Philippe Normand <pnormand@igalia.com>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: share the PA context between all clients with the same name
+	  Avoid to create a new PA context for each new client by using a hash
+	  table containing the list of ring-buffers and the shared PA context
+	  for each client. Doing this will improve application memory usage in
+	  the cases where multiple pipelines involving multiple pulsesink
+	  elements are used.
+	  Fixes bug #624338.
+
+2010-08-17 13:41:49 +0200  Philippe Normand <phil@base-art.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: clear the PA mainloop if baseaudiosink failed to open the ring_buffer
+	  If the application requests a state-change and pulsesink fails to open
+	  the ring_buffer device the mainloop attribute of the sink should be
+	  cleaned up to avoid future state-change (NULL->READY) failures.
+
+2010-08-19 12:23:16 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Post an error message if EOS happens before valid input is found
+	  Fixes bug #627341.
+
+2010-08-12 11:49:47 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: Send close newsegment event from the streaming thread
+
+2010-08-11 11:36:31 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/imagefreeze/gstimagefreeze.h:
+	  imagefreeze: Retry bufferalloc if it was aborted with WRONG_STATE because of a flushing seek
+
+2010-08-11 08:46:14 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Return GST_FLOW_UNEXPECTED when getting a second buffer
+	  This prevents upstream from pushing many useless buffers and makes
+	  it go into EOS state.
+
+2010-08-10 20:11:26 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Passthrough buffer allocations
+
+2010-09-04 13:10:30 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	  Back to development
+	  Temporarily disable -DGST_DISABLE_DEPRECATED for git builds until
+	  the code is updated for the GST_FLOW_IS_* macro deprecations.
+
+=== release 0.10.25 ===
+
+2010-09-02 23:44:19 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* gst-plugins-good.doap:
+	* gst/deinterlace/tvtime-dist.c:
+	* gst/deinterlace/tvtime-dist.h:
+	* gst/videobox/gstvideoboxorc-dist.c:
+	* gst/videobox/gstvideoboxorc-dist.h:
+	* gst/videomixer/blendorc-dist.c:
+	* gst/videomixer/blendorc-dist.h:
+	* win32/common/config.h:
+	  Release 0.10.25
+
+2010-09-02 23:12:48 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	  docs: update docs for release
+
+2010-09-02 23:07:36 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/LINGUAS:
+	* po/es.po:
+	* po/gl.po:
+	* po/lt.po:
+	* po/nl.po:
+	* po/ro.po:
+	* po/sv.po:
+	  po: update translations
+
+2010-08-25 19:01:50 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  0.10.24.5 pre-release
+
+2010-08-22 21:15:07 -0700  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: use separate buffer metadata for fields
+	  Call gst_buffer_make_metadata_writable() on buffers that are
+	  duplicated into fields.  Fixes #627689.
+
+2010-08-21 21:41:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* gst/deinterlace/tvtime-dist.c:
+	* gst/deinterlace/tvtime-dist.h:
+	* gst/videobox/gstvideoboxorc-dist.c:
+	* gst/videobox/gstvideoboxorc-dist.h:
+	* gst/videomixer/blendorc-dist.c:
+	* gst/videomixer/blendorc-dist.h:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sl.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  0.10.24.4 pre-release
+
+2010-08-19 18:30:05 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Prevent crash when reading image with problems
+	  Check if we have data on the adapter and fail if not.
+	  Fixes #627413
+
+2010-08-13 17:24:01 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 3e8db1d to ec60217
+
+2010-08-11 22:20:25 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Send close segments when seeking only for non-flushing seeks and if we already sent a newsegment event
+	  Fixes bug #626619.
+
+2010-08-11 16:50:42 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	* win32/common/gstrtpbin-marshal.c:
+	* win32/common/gstudp-enumtypes.c:
+	* win32/common/gstudp-enumtypes.h:
+	* win32/common/gstudp-marshal.c:
+	  0.10.24.3 pre-release
+
+2010-08-11 11:17:18 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: prevent reading past avc1 atom when parsing
+	  ... when one of the subatoms has a large/invalid size.
+	  Fixes #626609.
+
+2010-08-10 23:37:23 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* 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/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	  0.10.24.2 pre-release
+
+2010-08-10 10:57:45 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From bd2054b to 3e8db1d
+
+2010-08-09 00:36:36 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulse: fix printf format in some debugging messages
+
+2010-08-08 23:31:42 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* pkgconfig/gstreamer-plugins-good-uninstalled.pc.in:
+	  pkgconfig: set pluginsdir to top-level builddir without the pkgconfig/.. bits
+	  Removes clutter in plugin dir paths. This is only used to find the -good
+	  plugins for unit tests of ugly/bad/ffmpeg/etc. in an uninstalled setup.
+
+2010-08-06 20:04:59 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2src: also log pixel formats in sorted order
+
+2010-08-06 18:07:46 +0100  Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: sort formats in the right order so that non-emulated formats are prefered
+	  The format list should be sorted from high ranks to low ranks. In the GSList
+	  sorting function this means the compare needs to return a positive value if
+	  format a has a lower rank than format b.
+	  Among other things this fixes v4l2src to prefer non-emulated formats
+	  to emulated formats when built against libv4l.
+
+2010-08-06 19:24:06 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: Fix pipeline in the documentation
+	  Make sure that we have the same color format on all streams, i.e. AYUV
+	  Fixes bug #625452.
+
+2010-08-05 13:56:44 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From a519571 to bd2054b
+
+2010-06-14 19:58:11 +1000  Jonathan Matthew <jonathan@d14n.org>
+
+	* ext/taglib/gstid3v2mux.cc:
+	* tests/check/elements/id3v2mux.c:
+	  id3v2mux: write beats-per-minute tag using TBPM frame
+	  https://bugzilla.gnome.org/show_bug.cgi?id=621520
+
+2010-07-25 11:47:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend.c:
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer.h:
+	  videomixer: Move debug categories into the source files and add debug category for the blend functions
+
+2010-08-04 19:25:31 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Check if the compiler supports ISO C89 or C99 and which parameters are required
+	  This first checks what is required for ISO C99 support and sets the relevant
+	  compiler parameters and if no C99 compiler is found, it checks for a
+	  C89 compiler. This enables us to check for and use C89/C99 functions
+	  that gcc hides from us without the correct compiler parameters.
+
+2010-07-15 10:10:31 +0200  Philippe Normand <pnormand@igalia.com>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: use G_TYPE_DEFINE to define ring buffer type
+	  The existing get_type() implementation is racy, and the
+	  g_type_class_ref() workaround didn't actually work because
+	  it was in the wrong function. Since class creation in GObject
+	  is thread-safe these days (since 2.16), the class_ref workaround
+	  is no longer needed and it is sufficient to ensure the _get_type()
+	  function is thread-safe, which G_TYPE_DEFINE does.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=624338
+
+2010-08-04 15:20:42 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Post CLOCK-LOST/CLOCK-PROVIDE when going to/from READY
+	  Otherwise the clocks are redistributed every time the pipeline
+	  goes to PAUSED, which is quite expensive.
+
+2010-07-12 12:35:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4gpay.h:
+	  rtpmp4gpay: implement perfect timestamps
+	  Use bitreader for parsing the config string
+	  Reset state variables when going to READY
+	  Parse frame length and use it to keep track of the rtptimestamps
+
+2010-07-09 14:07:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph263pdepay.c:
+	  rtph263pdepay: allow more clock-rates as input
+	  Although the spec says that the clock-rate should always be 90000, some rtsp
+	  servers send different clock-rates so we must accept then in order to handle
+	  those streams too.
+
+2010-07-06 19:02:14 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpL16depay.c:
+	  L16depay: default to 1 channel
+	  When we can't find any channel or encoding-params on the caps for dynamic
+	  payload types, set the default number of channels to 1, as the spec says we
+	  should.
+	  See #623209
+
+2010-07-06 18:22:24 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: don't reuse udp sockets
+	  Don't reuse sockets but make the udpsrc element fail the state change when the
+	  socket is already in use. If we don't prevent reuse, we might end up using the same
+	  port for different streams in some cases.
+	  Fixes #622017
+
+2010-07-06 18:11:21 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	* gst/udp/gstudpsrc.h:
+	  udpsrc: add property to enable port reuse
+
+2010-07-05 10:23:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpL16depay.c:
+	  L16depay: use encoding-params for the channels
+	  When parsing the number of channels, use the encoding-params property from the
+	  RTP caps because that is where we can find the channels according to the spec.
+	  Fall back to the channels property in the caps when needed.
+	  Fixes #623209
+
+2010-06-29 10:46:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: improve error and warning message
+	  Improve error and warning message.
+	  Fixes #622577
+
+2010-08-02 23:15:56 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/examples/spectrum/demo-audiotest.c:
+	* tests/examples/spectrum/demo-osssrc.c:
+	  examples: no need to set the color for each frq-band
+
+2010-08-02 12:56:29 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpg729pay.h:
+	  rtpg729pay: avoid basertppayload perfect-rtptime mode
+	  G729 packets may only occur intermittently (e.g. cn packets), and as such
+	  do not allow for perfect-rtptime calculating rtp times based on frame or byte
+	  count.  In particular, do not use rtp audio base payloader as base class, but
+	  rather base payloader directly.
+
+2010-08-02 12:48:02 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: fix element leak
+
+2010-08-02 12:46:41 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4vdepay.c:
+	  rtpmp4vdepay: fix buffer leak
+
+2010-08-02 12:46:20 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/rtp-payloading.c:
+	  tests: rtp payloading: fix pad leak
+
+2010-07-29 17:18:11 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: push mode; use proper movi offset for movi based index
+	  Fixes #623357.
+
+2010-07-29 10:00:15 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux.h:
+	  qtdemux: Correctly parse mvhd atoms
+	  Parse mvhd data according to its version to avoid failing
+	  on valid files.
+
+2010-07-28 12:21:41 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix the max/avg in btrt atom reading
+	  According to ISO media base format, the max bitrate is the
+	  first one, and the avg comes next.
+
+2010-07-27 15:58:02 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: proper handling of streaming upstream without duration
+	  Fixes #625371.
+
+2010-07-26 18:33:09 +0200  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: initialize some variables to fix compiler warnings on OSX build bot
+
+2010-07-26 18:15:25 +0200  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: correctly check what version of gst-plugins-base we're compiling against
+	  We need to check the gst-plugins-base version, not the core version
+	  (even if both should be the same in any sane setup).
+
+2010-07-26 17:45:42 +0200  Arnaud Vrac <rawoul at gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: add port-range property to rtspsrc
+	  To support setups with firewall/ipsec, it is useful for an rtsp client to be
+	  able to set the range of ports that can be used for rtp/rtcp reception.
+	  Allows this by adding a "port-range" property to the rtspsrc element.
+	  Fixes #625153
+
+2010-07-26 13:38:31 +0200  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: set the pixel-aspect-ratio field also for par=1/1
+	  https://bugzilla.gnome.org/show_bug.cgi?id=625302
+
+2010-07-26 15:31:16 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix memory leak in server request reply
+	  The RTSP server rtspsrc is communicating with, sends a GET_PARAMETER request
+	  periodically as a ping.  The code in gst_rtspsrc_handle_request forms an OK
+	  response and sends, but doesn't call gst_rtsp_message_unset to free the memory
+	  after sending the response.  This results in a constant slow memory leak.
+	  Fixes #624770
+
+2010-07-24 22:39:54 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/debugutils/cpureport.c:
+	  cpureport: remove bogus docs
+
+2010-07-24 22:37:11 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/debugutils/Makefile.am:
+	* gst/debugutils/cpureport.c:
+	* gst/debugutils/cpureport.h:
+	* gst/debugutils/gstdebug.c:
+	  debugutils: new element cpureport
+	  cpureport posts bus messages after every buffer received of cpu used, system
+	  clock time, buffer time
+
+2010-07-24 10:29:01 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/examples/equalizer/demo.c:
+	* tests/examples/spectrum/demo-audiotest.c:
+	* tests/examples/spectrum/demo-osssrc.c:
+	  examples: Destroy the cairo context after usage
+
+2010-07-24 10:21:05 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/gdk_pixbuf/Makefile.am:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	* ext/gdk_pixbuf/pixbufscale.c:
+	  Revert "gdkpixbuf: Add a gdkpixbuf3 plugin that uses gdkpixbuf3"
+	  This reverts commit b6788153161b4e07fbf3d42a2d8921ea049305d0.
+	  There's no gdk-pixbuf3 anymore. gdk-pixbuf was separated from GTK+
+	  and will stay at version 2.0 for GTK+ 3.0.
+
+2010-07-24 10:19:37 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/examples/equalizer/demo.c:
+	* tests/examples/spectrum/demo-audiotest.c:
+	* tests/examples/spectrum/demo-osssrc.c:
+	  examples: Use cairo instead of to-be-deprecated GDK API
+	  Fixes bug #625002.
+
+2010-07-22 16:24:43 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: fix event leak
+
+2010-07-22 12:05:26 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: pull mode non-cue seeking
+	  That is, in files that have no index (Cue), perform seek by scanning for
+	  nearest cluster with timecode before requested position.  Scanning is done
+	  as a combination of interpolation and sequential scan.
+	  Fixes #617368.
+
+2010-07-16 12:46:50 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: streamable files need no _finish
+	  Fixes #624455.
+
+2010-07-22 11:46:35 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: push mode; handle 0-size data chunks
+	  Fixes #618535.
+
+2010-07-21 08:11:23 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: Only reset QoS information and send a NEWSEGMENT event downstream for NEWSEGMENT events on the master pad
+
+2010-07-14 20:31:44 -0700  David Schleef <ds@schleef.org>
+
+	* gst/debugutils/Makefile.am:
+	* gst/debugutils/gstcapsdebug.c:
+	* gst/debugutils/gstcapsdebug.h:
+	* gst/debugutils/gstdebug.c:
+	  capsdebug: Add new element
+
+2010-07-20 16:11:25 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: demote WARNING message to LOG level
+	  It's not a warning.
+
+2010-07-19 14:47:32 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Fix regression on markers parsing
+	  Fixes a regression introduced when fixing bug #583047 in
+	  commit a391bf52cc3c580c7a0a2316ca52eb66da3b85c1
+	  Skip the data when libjpeg asks it to be skipped on
+	  one of its callbacks.
+
+2010-07-16 18:04:44 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: add missing argument in debug message
+
+2010-07-16 17:53:55 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsemixerctrl.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	  pulsesink: Only use gst_audio_clock_new() when compiling against newer base
+
+2010-07-09 17:33:55 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/raw1394/gstdv1394src.c:
+	  dv1394src: Post clock-provide and clock-lost messages when going from/to PLAYING
+	  In PAUSED and below the clock is not working.
+
+2010-07-04 16:57:55 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/gconf/gstswitchsink.c:
+	* ext/gconf/gstswitchsink.h:
+	* ext/gconf/gstswitchsrc.c:
+	* ext/gconf/gstswitchsrc.h:
+	  gconf: Fix ref handling of new child elements and minor cleanup
+
+2010-07-04 09:45:52 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/gconf/gstgconfvideosrc.c:
+	  gconfvideosrc: Use correct GConf key
+
+2010-07-03 14:16:42 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/gconf/gstgconfaudiosrc.c:
+	* ext/gconf/gstgconfaudiosrc.h:
+	  gconf: Port gconfaudiosrc to GstSwitchSrc
+
+2010-07-03 14:12:12 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/gconf/gstgconfvideosrc.c:
+	* ext/gconf/gstgconfvideosrc.h:
+	  gconf: Port gconfvideosrc to GstSwitchSrc
+
+2010-07-03 14:11:55 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/gconf/Makefile.am:
+	* ext/gconf/gstswitchsrc.c:
+	* ext/gconf/gstswitchsrc.h:
+	  gconf: Add GstSwitchSrc base class
+
+2010-07-03 13:56:33 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/gconf/gstswitchsink.c:
+	  gconf: Create the ghostpad of the switchsink from the template
+
+2010-07-07 10:10:52 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Post clock-provide/clock-lost when going to/from PAUSED
+	  Also use gst_audio_clock_new_full() to prevent crashes when the
+	  clock is used after the element was destroyed.
+
+2010-07-15 11:49:03 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: remove bogus UNLOCK
+
+2010-07-13 12:34:44 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: also calculate PAR using track width and height for QT files
+	  (... as opposed to only for ISO style files).
+	  Fixes #624173.
+
+2010-07-12 17:29:12 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: handle bogus files storing ADTS AAC data
+
+2010-07-09 16:57:33 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: do not error out on a block with unknown tracknumber
+
+2010-07-08 18:57:21 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: do not align reverse playback reference stream twice
+	  Timestamp rounding issues could lead to going backwards 2 keyframe periods
+	  (rather than only 1).  While this is not necessarily a problem, it might
+	  potentially place additional (buffering) load on downstream and could be
+	  avoided (because We Can).
+	  Fixes #623629.
+
+2010-07-08 16:07:16 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: convert some more mov format timestamp to gst time
+
+2010-07-07 14:16:59 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: additional verification heuristics for VBR audio stream
+	  Check for and override some header field(s) for reasonable values, according
+	  to later expected use in calculations.
+
+2010-07-14 15:21:21 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: Fix wrong lock order that could lead to a deadlock. Fixes #624331.
+
+2010-07-16 11:31:08 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	  Back to development
+
+=== release 0.10.24 ===
+
+2010-07-15 01:49:04 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.10.24
+
+2010-07-15 01:35:06 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/cs.po:
+	* po/lv.po:
+	  po: update translations
+
+2010-07-07 00:42:46 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	  0.10.23.4 pre-release
+
+2010-07-07 00:31:17 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/LINGUAS:
+	* po/da.po:
+	* po/el.po:
+	* po/es.po:
+	* po/fr.po:
+	* po/id.po:
+	* po/pt_BR.po:
+	* po/sl.po:
+	* po/tr.po:
+	* po/zh_CN.po:
+	  po: update translations
+
+2010-06-23 11:47:43 +0200  Michael Grzeschik <m.grzeschik@pengutronix.de>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: destroy buffer pool when changing state to NULL
+	  In the case we change the State from READY_TO_NULL the buffers in the pool
+	  still hold an open dup file descriptor to the device, therefore the device
+	  release function will not be called and the device will probably answer with
+	  -EBUSY when we reopen it in the next NULL_TO_READY transition.
+	  Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
+	  See bug #622500 and #612244.
+
+2010-07-06 13:21:19 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix order of bitrates in 'btrt' atom
+	  There seems to be a bug in libmp4v2 that generates a MPEG4BitRateBox as
+	  (bufferSizeDB, avgBitrate, maxBitrate) instead of (bufferSizeDB,
+	  maxBitrate, avgBitrate), according to the spec. I used the mp4file
+	  output while writing this code, so the order is wrong. This patches
+	  fixes that.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=623654
+
+2010-07-05 12:05:57 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fix skipping extra 0xff markers
+	  Fixes #623585.
+
+2010-06-29 23:18:23 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: fix memory leak
+	  Don't leak result of gst_adapter_take(). There are most likely
+	  smarter things we can do, but let's keep things simple for the
+	  release.
+	  Fixes #623172.
+
+2010-07-02 12:31:31 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: strip out bogus tags from XMP atom
+	  https://bugzilla.gnome.org/show_bug.cgi?id=623366
+
+2010-07-02 14:25:22 +0200  Andrzej K. Haczewski <ahaczewski@gmail.com>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Write duration at the correct position
+
+2010-06-30 11:12:08 +0200  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/rtpmanager/gstrtpptdemux.c:
+	  rtpptdemux: fix memleak on custom downstream events
+	  by not sending custom downstream event twice and fix memleak when
+	  not handling the event
+	  https://bugzilla.gnome.org/show_bug.cgi?id=623196
+
+2010-06-29 20:18:51 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	  0.10.23.3 pre-release
+
+2010-06-29 20:14:53 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: fix unportable printf format specifiers in commented out code
+	  To avoid false positives when grepping for unportable specifiers.
+
+2010-06-29 19:12:36 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: fix --disable-external
+
+2010-06-28 15:44:06 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* autogen.sh:
+	* configure.ac:
+	  Bump automake requirement to 1.10 and autoconf to 2.60
+	  For maintainability reasons and $(builddir).
+	  See #622944.
+
+2010-06-28 09:07:58 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/goom/plugin_info.c:
+	  goom: don't allocate 260kB struct on the stack
+	  PluginInfo is quite a sizeable struct, let's not allocate it on the
+	  stack, especially not if we're copying it over into another dynamically
+	  allocated copy anyway.
+	  Fixes #570761.
+
+2010-06-27 10:31:17 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Require GTK+ >= 2.14 for the examples
+
+2010-06-26 20:12:25 +0200  Guido Günther <agx@sigxcpu.org>
+
+	* tests/examples/equalizer/demo.c:
+	* tests/examples/spectrum/demo-audiotest.c:
+	* tests/examples/spectrum/demo-osssrc.c:
+	  examples: Make demos -DSEAL safe to fix build with GTK+ 3.0
+
+2010-06-26 21:39:34 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/jpeg/Makefile.am:
+	  jpeg: Explicitely link with libgstbase
+
+2010-06-26 18:42:29 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.10.23.2 pre-release
+
+2010-06-26 18:41:49 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/deinterlace/tvtime-dist.c:
+	* gst/deinterlace/tvtime-dist.h:
+	* gst/videobox/gstvideoboxorc-dist.c:
+	* gst/videobox/gstvideoboxorc-dist.h:
+	* gst/videomixer/blendorc-dist.c:
+	  gst: update orc files
+
+2010-06-26 18:41:39 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: update translations
+
+2010-06-25 19:40:06 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Fix leaking of the streamheader buffers
+	  gst_value_set_buffer() increases the refcount and doesn't
+	  take ownership of the buffer.
+
+2010-06-24 16:32:23 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/ebml-read.c:
+	* gst/videobox/gstvideobox.c:
+	* gst/videofilter/gstvideoflip.c:
+	  matroska, videobox, videofilter: fix compiler warnings when debugging is disabled in gstreamer
+	  Fixes unused variable warnings when GStreamer's debugging system has been disabled.
+
+2010-06-24 15:17:11 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	  tests: add plugin loading whitelist to test environment
+	  Only want to load core/base/good plugins here.
+	  Fixes #619717.
+
+2010-06-24 15:09:16 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 73ff93a to a519571
+
+2010-06-24 13:02:04 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	  gdkpixbufdec: bump rank to SECONDARY
+	  Bump gdkpixbufdec's rank to SECONDARY to give it an edge over misc.
+	  image decoders in gst-ffmpeg that also have a MARGINAL rank.
+	  Fixes #620162.
+
+2010-06-23 12:15:13 +0200  Michael Grzeschik <m.grzeschik@pengutronix.de>
+
+	* gst/avi/gstavidemux.c:
+	  reset the have_index flag at transition PAUSED_TO_READY
+	  If we restart the Stream in the case of doing a transition from
+	  PAUSED_TO_READY and back with READY_TO_PAUSED aso. the duration of the video
+	  will get calculated even if we have a avi header with that information.
+	  Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
+
+2010-06-23 20:29:14 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Fix negotiation for I420/YV12
+	  We don't support conversion into *all* YUV
+	  formats for them, only into I420/YV12/AYUV.
+	  Fixes bug #622501.
+
+2010-06-22 15:22:44 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: proper closing segment construction
+	  Fixes #618982.
+
+2010-06-22 15:46:51 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2: precalculate duration
+	  Have frame duration in the instance struct and calculate it after changing the caps.
+
+2010-06-21 12:17:39 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/gstv4l2sink.c:
+	  v4l2sink: use glib defines in property declarations for readability
+
+2010-06-21 12:15:14 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: use G_PARAM_STATIC_STRINGS to save a few bytes and strdups
+
+2010-06-18 20:02:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix locking after moving things around
+
+2010-06-18 14:13:58 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* ext/taglib/gstapev2mux.cc:
+	  taglib: Use newly added gst_tag_list_peek_string_index
+	  Replace calls to gst_tag_list_get_string_index with
+	  gst_tag_list_peek_string_index to avoid a string copy
+
+2010-06-18 16:56:19 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: make some errors as warnings
+	  Avoid spamming the testsuite with these error debug lines.
+
+2010-06-18 16:49:08 +0200  Keith Nicholson <keith.nicholson at ultra-ccs.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: fix multicast support on windows builds
+	  On windows builds, sets source address for bind to INADDR_ANY, while
+	  maintaining the original multicast group address for subsequent join.
+	  Fixes #595978
+
+2010-06-18 16:16:28 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpnetutils.c:
+	  udp: make url parsing compatible with VLC syntax
+	  Skip everything before the @ sign in the url location. VLC uses that as the
+	  remote address to connect to (but we ignore it for now). This makes our udp urls
+	  compatible with the ones used by VLC.
+	  Fixes #597695
+
+2010-06-18 15:08:21 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: factor out the connections
+	  Keep a global connection for aggregate control but also keep stream connections
+	  for non-aggregate control.
+	  Add some helper methods to connect/close/flush the connections.
+
+2010-06-17 13:06:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: add non-aggregate control
+	  Add non-aggregate control.
+	  Separate retrieving thr SDP from parsing and setting up the streaming from the
+	  SDP.
+
+2010-06-17 22:10:03 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* common:
+	  common: update common back to what it was
+
+2010-06-17 17:24:22 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* common:
+	* gst/flv/gstflvmux.c:
+	  flvmux: add documentation for streamable property
+
+2010-06-17 16:43:44 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	  docs: update introspected plugin docs for gstdoc-scangobj and other changes
+	  Update common for latest gstdoc-scangobj, and inspect xml files for
+	  escaping and pad template order changes.
+
+2010-06-17 16:41:56 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/.gitignore:
+	  tests: ignore sub-directory with orc tests
+
+2010-06-17 10:44:33 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Fix an uninitialized variable compiler warning
+
+2010-06-16 21:02:13 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/ebml-read.c:
+	  ebml-read: Zero-sized ints/uints/floats have a value of 0 according to the EBML spec
+
+2010-06-16 20:02:58 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Fix possible NULL pointer dereference and assertion that could be caused by invalid files
+
+2010-06-16 19:50:34 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Clean up/fix some minor error handling bugs
+
+2010-06-16 19:30:25 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximagesrc: Fix NULL pointer dereference when allocation of the ximage fails
+
+2010-06-16 19:28:04 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflactag.c:
+	  flactag: Fix possible NULL pointer dereference
+
+2010-06-16 19:24:54 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audioiirfilter.c:
+	  audioiirfilter: Fix possible NULL pointer dereference
+
+2010-06-16 19:20:02 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstwarp.c:
+	  warptv: Don't use floats as loop counters
+
+2010-06-16 11:21:35 -0400  Havoc Pennington <hp@pobox.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2src: do not try to change device format if it's already correct
+	  This allows set_caps to succeed if caps change in a way that
+	  would not modify the format we're getting from the hardware.
+	  Otherwise if not in NULL state, setting caps would fail
+	  with EBUSY.
+	  With this change, in some cases it's OK to go PLAYING->READY->PLAYING
+	  rather than PLAYING->NULL->PLAYING to avoid a time-consuming close
+	  and reopen of the device.
+	  Fixes #621723
+
+2010-06-16 11:09:17 -0400  Havoc Pennington <hp@pobox.com>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: in negotiate, check for error return from set_caps
+	  Fixes #621723  (partially)
+	  set_caps can fail if the video device is running, in that case
+	  setting its format leads to EBUSY.
+	  If set_caps fails then we will not have set up the buffer pool
+	  (it will be NULL) which leads to a crash when we try to pull
+	  buffers. If we fail the negotiate on set_caps failure, then we
+	  won't go to playing state and won't crash.
+	  This is a small improvement. Of course, a nicer fix would
+	  be to make set_caps work in the case where the format is
+	  unchanged. If the format has changed, failing is
+	  probably correct because we need to close the device
+	  (go to NULL state) in order to set caps.
+
+2010-06-16 15:40:34 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: improve audio vbr detection
+	  Subsequent entry time calculations use blockalign value to determine
+	  number of frames per chunk, and blockalign == 1 is then most unlikely to result
+	  in reasonable values (which also aligns with "spec").
+
+2010-06-16 15:52:57 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: tweak DELTA_UNIT labeling
+	  Consider SPS, PPS and IDR as keyframe, all others as DELTA_UNIT.
+	  See #620154.
+
+2010-06-15 20:06:17 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackdec.c:
+	  wavpackdec: Initialize uninitialized variable and don't unref it if it's NULL
+
+2010-06-15 20:04:35 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Assign variables before printing them
+
+2010-06-15 20:00:28 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Initialize uninitialized variable
+
+2010-06-15 19:47:16 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Initialize variable
+
+2010-06-15 19:45:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: Fix NEWSEGMENT parsing logic and don't use uninitialized variables
+
+2010-06-15 17:20:20 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/matroska/ebml-read.c:
+	  matroska: Fix unitialized variable
+
+2010-06-15 16:49:49 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From 9339ccc to 35617c2
+
+2010-06-15 16:54:04 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 5adb1ca to 9339ccc
+
+2010-06-15 16:35:18 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 57c89b7 to 5adb1ca
+
+2010-06-15 14:08:26 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* .gitignore:
+	  .gitignore: ignore generated tvtime.h file
+
+2010-06-15 15:36:33 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From c804988 to 57c89b7
+
+2010-05-17 13:54:03 +0200  Marc-André Lureau <mlureau@flumotion.com>
+
+	* ext/raw1394/gst1394clock.c:
+	* ext/raw1394/gst1394clock.h:
+	  raw1394: remove useless last_time
+	  It seems to me this code is useless: removing it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=618871
+
+2010-06-14 19:21:22 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: respect aggregate control attributes
+	  when the SDP specifies an aggregate control url, use that for playback
+	  control.
+	  Fixes #619531
+
+2010-06-14 15:36:00 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/goom/gstgoom.c:
+	  goom: Call orc_init() before trying to get target flags
+
+2010-06-14 15:35:08 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Call orc_init() before trying to get target flags
+
+2010-06-14 14:26:22 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/matroska-mux.c:
+	* tests/check/elements/matroskamux.c:
+	  matroskamux: revert change that set a reserved flag on the Block.
+	  So matroska's Block structure has no keyframe flag, only the SimpleBlock has it.
+	  To detect keyframes in Blocks, it is just the BlockGroup container that needs
+	  to have a ReferenceBlock attached if it is a delta frame in video.
+
+2010-05-31 12:45:01 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: use libjpeg scatter-gather operation to avoid data copying
+	  Fixes #583047 (more).
+
+2010-05-27 15:45:23 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: optimize buffer handling when parsing
+	  Use an adapter to collect incoming data, and use adapter API to scan and peek.
+	  Fixes #583047.
+
+2010-06-14 13:48:28 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/oss4/oss4-mixer.c:
+	  oss4: Use g_ascii_strcasecmp() instead of the deprecated g_strcasecmp()
+
+2010-06-14 13:27:30 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Use GLIB_EXTRA_CFLAGS
+
+2010-06-14 13:03:57 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 7a0fdf5 to c804988
+
+2010-06-14 11:46:32 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: also consider AU and SEI NALUs as DELTA_UNIT
+	  Fixes #620154.
+
+2010-06-14 11:32:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 6da3bab to 7a0fdf5
+
+2010-06-12 21:26:16 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtp/gstrtpmparobustdepay.c:
+	  build: include stdio.h for sscanf
+
+2010-06-12 14:12:50 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	  tests: Add clean rule for the orc tests
+
+2010-06-12 14:12:04 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	  tests: Add autogenerated orc tests
+
+2010-06-12 08:27:42 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 733fca9 to 6da3bab
+
+2010-06-11 16:23:29 -0700  David Schleef <ds@schleef.org>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: Fix element description
+
+2010-06-11 21:13:59 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtpmparobustdepay.c:
+	  rtpmparobustdepay: don't try to unref NULL buffers
+	  Fixes generic/states unit test.
+
+2010-06-11 20:50:23 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: use typefind functions to check if PCM data contains dts stream
+	  Use new dts audio typefinder from -base to check if the PCM data
+	  contains a dts stream. This way we recognise more varieties more
+	  reliably and also detect the dts stream if there isn't a frame
+	  sync right at the start of the data.
+	  Fixes #413942.
+
+2010-06-11 20:47:22 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: set buffer offsets before using the buffer for the first time
+	  gst_type_find_helper_for_buffer() will need the correct offset
+	  set on the buffer (ie. 0) and not the byte offset we started
+	  pulling the data from.
+
+2010-06-10 16:14:43 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpmparobustdepay.c:
+	* gst/rtp/gstrtpmparobustdepay.h:
+	  rtp: add mpa-robust depayloader
+	  Fixes #589997.
+
+2010-06-11 10:57:41 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: fix avi header bytewriting
+	  ... by using proper offsets for tag list writing.
+	  Also use _reset rather than _free and consistently use bytewriter position.
+	  See #619293.
+
+2010-06-10 22:58:41 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* .gitignore:
+	  Update .gitignore
+	  Add the generated orc source files
+
+2010-06-10 22:55:17 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/matroskamux.c:
+	  matroskamux: Fix unit test for changed key-frame behaviour
+	  All audio frames are marked as keyframe now instead of marking
+	  them all as delta unit...
+
+2010-06-10 22:45:13 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/blend.c:
+	* gst/videomixer/blend_mmx.h:
+	* gst/videomixer/blendorc-dist.c:
+	* gst/videomixer/blendorc-dist.h:
+	* gst/videomixer/blendorc.orc:
+	  videomixer: Port most blending related functions to orc
+	  Only remaining MMX implementation is the ARGB/BGRA/AYUV blending
+	  for which we first need the orc compositing opcodes.
+
+2010-06-10 20:17:07 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_mmx.h:
+	  videomixer: Replace some tabs by spaces
+
+2010-06-10 11:04:38 +0100  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* ext/raw1394/gst1394clock.c:
+	  dv1394: Fix the internal clock even more
+	  The cycleCount register is 13 bits long and the cycleOffset one
+	  is 12 bits long. To read the cycleCount register we need to shift
+	  12 bits and not 13. Fixes #615461
+
+2010-06-09 18:37:29 -0700  David Schleef <ds@schleef.org>
+
+	* configure.ac:
+	  configure: use m4 macro to check for Orc
+
+2010-06-09 22:40:23 +0200  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: some non-delta buffers were not marked as keyframes
+
+2010-06-09 22:00:16 +0200  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: change 2 second limit per cluster
+	  Start cluster at every keyframe or when we would overflow the previous
+	  cluster's relative timestamp field. This would avoid as much as possible
+	  starting clusters at non-keyframes.
+
+2010-06-09 12:40:09 -0700  David Schleef <ds@schleef.org>
+
+	* common:
+	  Automatic update of common submodule
+	  From fad145b to 733fca9
+
+2010-06-09 12:34:01 -0700  David Schleef <ds@schleef.org>
+
+	* common:
+	  Automatic update of common submodule
+	  From 47683c1 to fad145b
+
+2010-06-09 20:53:06 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Don't request more shared memory than needed
+
+2010-06-09 20:45:04 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/gconf/gstswitchsink.c:
+	  switchsink: Set the GST_ELEMENT_IS_SINK flag on the sink
+
+2010-06-09 20:43:50 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/gconf/gstgconfvideosink.c:
+	* ext/gconf/gstgconfvideosink.h:
+	  gconfvideosink: Use GstSwitchSink as base class
+
+2010-06-09 20:30:31 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/gconf/gstgconfaudiosink.c:
+	  gconfaudiosink: Use G_PARAM_STATIC_STRINGS
+
+2010-06-09 20:29:02 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/gconf/gstgconfaudiosink.c:
+	* ext/gconf/gstgconfaudiosink.h:
+	  gconfaudiosink: Rename instance variable to be more descriptive
+
+2010-06-09 20:22:30 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautovideosink.c:
+	  auto{audio,video}sink: Don't lose the GST_ELEMENT_IS_SINK flag after removing the child
+
+2010-06-09 20:07:09 +0200  Julien Moutte <julien@fluendo.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: Plug some memleak and support 22050Hz mono sound.
+	  Segment size needs to be a multiple of the sample size in bytes.
+
+2010-06-09 16:22:27 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Flush shm buffer immediately if it's full
+
+2010-06-09 16:21:55 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Fix writing of buffers larger than segsize
+	  Fixes bug #620540.
+
+2010-06-09 15:42:37 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Fix playback if PA doesn't give us a large enough shared memory buffer
+
+2010-06-09 15:42:19 +0200  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: change indexed property to streamable
+	  The property streamable has reverse semantics to indexed.
+
+2010-06-09 09:13:09 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  flvmux: Rename unreleased property 'indexed' to 'streamable'
+	  Rename 'indexed' to 'streamable' for a better name while it
+	  hasn't been released
+
+2010-06-08 15:23:51 -0700  David Schleef <ds@schleef.org>
+
+	* REQUIREMENTS:
+	* configure.ac:
+	  configure: remove liboil check
+
+2010-06-08 14:44:19 -0700  David Schleef <ds@schleef.org>
+
+	* gst/level/gstlevel.c:
+	  level: remove unused liboil include
+
+2010-06-04 18:22:42 -0700  David Schleef <ds@schleef.org>
+
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/blend.c:
+	  videomixer: liboil to orc conversion
+
+2010-06-04 18:21:21 -0700  David Schleef <ds@schleef.org>
+
+	* gst/videobox/Makefile.am:
+	* gst/videobox/gstvideobox.c:
+	* gst/videobox/gstvideoboxorc-dist.c:
+	* gst/videobox/gstvideoboxorc-dist.h:
+	* gst/videobox/gstvideoboxorc.orc:
+	  videobox: liboil to orc conversion
+
+2010-06-04 18:16:25 -0700  David Schleef <ds@schleef.org>
+
+	* gst/goom/Makefile.am:
+	* gst/goom/README:
+	* gst/goom/gstgoom.c:
+	* gst/goom/plugin_info.c:
+	  goom: liboil to orc conversion
+
+2010-06-08 16:04:23 -0700  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/Makefile.am:
+	* gst/deinterlace/tvtime-dist.c:
+	* gst/deinterlace/tvtime-dist.h:
+	* gst/deinterlace/tvtime.orc:
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/vfir.c:
+	  deinterlace: orcify some deinterlacing methods
+
+2010-06-08 16:03:36 -0700  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/Makefile.am:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	* gst/deinterlace/gstdeinterlacemethod.h:
+	* gst/deinterlace/tvtime/greedy.c:
+	* gst/deinterlace/tvtime/greedyh.c:
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/scalerbob.c:
+	* gst/deinterlace/tvtime/tomsmocomp.c:
+	* gst/deinterlace/tvtime/vfir.c:
+	* gst/deinterlace/tvtime/weave.c:
+	* gst/deinterlace/tvtime/weavebff.c:
+	* gst/deinterlace/tvtime/weavetff.c:
+	  deinterlace: convert from liboil to orc
+
+2010-06-08 15:23:28 -0700  David Schleef <ds@schleef.org>
+
+	* REQUIREMENTS:
+	* configure.ac:
+	  configure: Add orc check
+
+2010-06-08 14:09:00 +0200  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  flvmux: Add indexed property to replace disabled is-live.
+	  Add indexed property to be the negation of what the disabled is-live property
+	  was. Fixes bug #613066.
+
+2010-06-08 09:22:30 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  raw1394: Require libraw1394 >= 2.0.0 for raw1394_read_cycle_timer
+	  Fixes bug #620929.
+
+2010-06-08 07:35:00 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/annodex/gstcmmlenc.c:
+	  cmmlenc: Remove hack to let oggmux start a new page for every CMML buffer
+	  oggmux does this for CMML by its own now
+
+2010-06-07 18:32:16 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Don't handle non-TIME seeks
+	  Don't send them upstream because for upstream a BYTES seek
+	  might make sense but is completely wrong because upstream
+	  can't seek to a byte position of the audio or video stream.
+	  Also don't build the index in push mode for non-TIME seeks,
+	  things will go wrong here otherwise.
+
+2010-06-07 11:15:26 -0400  Olivier Crête <tester@tester.ca>
+
+	* gst/dtmf/gstdtmfdetect.c:
+	* gst/dtmf/gstdtmfdetect.h:
+	  dtmfdetect: Only works with rate=8000, fix in caps
+
+2010-06-02 19:16:20 +0100  Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  Cope with short startcodes in the h264 bytestream
+
+2010-06-06 17:25:16 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulse: log message printf format fixes
+
+2010-06-06 18:00:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	* ext/pulse/pulsemixer.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* ext/speex/gstspeexenc.c:
+	* ext/taglib/gsttaglibmux.c:
+	* ext/wavpack/gstwavpackdec.c:
+	* ext/wavpack/gstwavpackenc.c:
+	* ext/wavpack/gstwavpackparse.c:
+	  ext: Don't use GST_DEBUG_FUNCPTR for GObject vfuncs
+
+2010-06-06 17:57:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/oss/gstossdmabuffer.c:
+	* sys/oss/gstosssink.c:
+	* sys/oss/gstosssrc.c:
+	* sys/oss4/oss4-sink.c:
+	* sys/oss4/oss4-source.c:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxaudio/gstosxringbuffer.c:
+	* sys/sunaudio/gstsunaudiosink.c:
+	* sys/sunaudio/gstsunaudiosrc.c:
+	* sys/waveform/gstwaveformsink.c:
+	  sys: Don't use GST_DEBUG_FUNCPTR for GObject vfuncs
+
+2010-06-06 17:52:40 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	* gst/debugutils/breakmydata.c:
+	* gst/debugutils/gsttaginject.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/debugutils/testplugin.c:
+	* gst/flv/gstflvdemux.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videomixer/videomixer.c:
+	  gst: Don't use GST_DEBUG_FUNCPTR for GObject vfuncs
+
+2010-06-06 15:12:16 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: refactor delta unit handling
+	  This allows us to skip delta units earlier and is a bit clearer in my
+	  opinion. It also makes only video buffers ever be delta units, not
+	  just for SimpleBlock as before.
+
+2010-06-06 15:17:00 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Clear adapter on discontinuities
+
+2010-06-06 14:03:53 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Ignore keyframe flag for non-video streams
+	  When the keyframe bit of SimpleBlock Flags wasn't set, the buffer was being
+	  marked with GST_BUFFER_FLAG_DELTA_UNIT, causing all buffers to be skipped
+	  after a seek. This may be a problem with the Sorenson Squish encoder, but
+	  arguably the keyframe bit should only be applied to video.
+	  Fixes bug #620358.
+
+2010-06-06 14:56:52 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: First try upstream when handling seek events/queries
+
+2010-06-04 14:54:59 -0400  Tristan Matthews <tristan@sat.qc.ca>
+
+	* gst/rtp/gstrtpceltpay.c:
+	  gstrtpceltpay: don't always fixate sink caps to 1 channel
+	  The getcaps function should not fixate the channels field until we
+	  get the encoding-params field from our srcpad's caps. Fixes #620591
+
+2010-06-04 13:57:28 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtsp: try all ranges from the sdp
+	  Try all ranges in the SDP before giving up.
+
+2010-06-04 13:56:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: make parse_range return result
+	  Make the parse_range function return if the parsing succeeded or failed.
+
+2010-06-04 11:44:09 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: if we're not linked downstream, we can do any format
+	  Stupid me, assuming _get_allowed_caps() would actually return the
+	  pad templates if there was no peer.
+
+2010-05-31 16:26:19 +0100  Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+
+	* gst/rtp/gstrtptheorapay.c:
+	  Keep announcing the delivery-method in the capabilities
+	  Even though we don't use delivery-method in our payloader, older versions of
+	  the theora payloader in gstreamer required it. As such we need to keep this
+	  around in the caps for backwards-compatibility.
+	  This reverts part of 49463a37cbaa952e1401291f0a2623de6cab3880
+	  Fixes #618940
+
+2010-06-03 17:52:11 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	* sys/oss4/oss4-mixer.c:
+	  oss4: add some comments for translators to clarify meaning of "Low"
+	  "Low" etc. are quality settings here (e.g. for the internal resampler).
+	  Some day when we use GLib's i18n functions we might want to use
+	  NC_() and g_dpgettext2() here instead of the comments.
+	  Fixes #555967.
+
+2010-06-03 19:23:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gdepay.h:
+	  mp4gdepay: calculate the frame duration correctly
+	  When we calculate the frame duration, we need to use the amount of
+	  frames in the _previous_ packet, not the current packet. The frame duration is
+	  needed to correctly de-interleave interleaved streams. This fixes the case where
+	  there are a variable number of frames in a packet.
+	  Fixes #620494
+
+2010-06-03 18:58:42 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: Don't return caps in get_caps() that will be rejected
+	  This commit basically puts _get_caps() in sync with accept_caps().
+	  If we don't have a master pad OR the master pad caps aren't negotiated
+	  then we just return the downstream allowed caps.
+	  If we have a master pad with negotiated caps, we return those caps
+	  with a free range of width/height/framerate
+
+2010-06-03 13:45:32 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  Revert "pulsesink: Add comments to remove the provide-clock message posting once we depend on base 0.10.30"
+	  This reverts commit 8f3708f38aa3839a6a625ca7d1c166101c9fbb7f.
+	  The baseaudiosink commit was reverted
+
+2010-06-03 10:27:25 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Add comments to remove the provide-clock message posting once we depend on base 0.10.30
+	  baseaudiosink does all this for us now.
+
+2010-05-07 18:42:06 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  dtmf: Remove rtpdtmfmux stream-lock code
+
+2010-06-02 16:36:11 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: delayed seek handling also deserves TRUE event response
+
+2010-06-02 15:30:47 +0200  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: fix compiler warning
+	  unused variable ‘estimated’
+
+2010-06-02 15:04:00 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* common:
+	  common: revert the change i did in my previous commit
+
+2010-06-02 13:39:10 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* common:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: stop buffering and emit EOS at the end of a stream
+	  When using RTP_JITTER_BUFFER_MODE_BUFFER, make sure that the ringbuffer doesn't
+	  get stuck buffering forever when there isn't enough data left to fill the
+	  buffer.
+
+2010-06-01 21:52:59 +0200  Benjamin Otte <otte@redhat.com>
+
+	* gst/debugutils/testplugin.c:
+	  debugutils: Don't consume preroll buffer twice
+
+2010-06-01 21:32:11 +0200  Benjamin Otte <otte@redhat.com>
+
+	* ext/pulse/pulseutil.c:
+	  pulse: Style fix: use g_strdup() instead of printf()ing a simple string
+
+2010-05-27 16:07:31 +0200  Benjamin Otte <otte@redhat.com>
+
+	* gst/debugutils/tests.c:
+	  debugutils: Replace md5 implementation with glib's
+	  https://bugzilla.gnome.org/show_bug.cgi?id=619824
+
+2010-05-22 11:55:37 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: clean up code for avi header using a bytewriter
+	  https://bugzilla.gnome.org/show_bug.cgi?id=619293
+
+2010-06-01 18:54:41 -0500  Pierre-Louis Bossart <pierre-louis.bossart@intel.com>
+
+	* configure.ac:
+	* ext/pulse/pulsesink.c:
+	  pulsesink: optimize communication with PulseAudio using pa_stream_begin_write
+
+2010-06-02 10:52:56 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Post provide-clock message on the bus if the clock appears/disappears
+	  Fixes bug #620277.
+
+2010-06-01 23:49:17 -0700  David Schleef <ds@schleef.org>
+
+	* common:
+	  Automatic update of common submodule
+	  From 17f89e5 to 47683c1
+
+2010-06-01 22:54:49 -0700  David Schleef <ds@schleef.org>
+
+	* common:
+	  Automatic update of common submodule
+	  From cdff0fb to 17f89e5
+
+2010-06-01 20:45:29 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: filter caps returned from downstream with our pad template.
+
+2010-06-01 16:56:32 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Remove more unneeded warnings
+
+2010-06-01 16:54:03 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/ebml-write.c:
+	  matroskamux: remove unneeded warning
+
+2010-06-01 16:49:14 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/ebml-write.c:
+	  matroskamux: remove unneeded debug statement
+
+2010-06-01 16:24:53 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: change is-live property to indexed
+
+2010-05-23 13:56:16 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	  matroska: use the uint64 scaling functions
+	  In demuxer and muxer use the gst_util_uint64 scaling functions rather than
+	  standard integer division. Add warnings (to be changed to debug) for debugging
+	  the timestamp and duration.
+
+2010-05-21 14:35:34 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/ebml-write.h:
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: set delta unit on all buffers except cluster start ones
+
+2010-05-21 13:38:11 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/ebml-write.h:
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: store caps and set on buffers rather than using pad caps
+
+2010-05-21 13:25:24 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: make sure pads caps are set before any buffers pushed.
+
+2010-05-21 13:14:04 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/ebml-write.h:
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: add streamheaders
+
+2010-05-21 12:23:08 +0100  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: no need to set cache twice
+
+2010-05-21 01:59:53 +0200  Xavier Queralt <xqueralt@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	  Do not create a SeekHeader, Cues, .. when doing live
+
+2010-05-20 23:39:59 +0200  Xavier Queralt <xqueralt@gmail.com>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  Add is-live property
+
+2010-06-01 13:22:26 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fix variable init
+
+2010-05-28 16:37:32 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	* gst/matroska/matroska-ids.h:
+	  matroskademux: improve reverse playback
+	  Slightly modify approach to also handle cases where cue entries do not reliably
+	  lead to initial keyframes.
+	  Fixes #619817.
+
+2010-05-24 16:02:58 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlacemethod.h:
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/scalerbob.c:
+	* gst/deinterlace/tvtime/tomsmocomp.c:
+	* gst/deinterlace/tvtime/vfir.c:
+	* gst/deinterlace/tvtime/weave.c:
+	* gst/deinterlace/tvtime/weavebff.c:
+	* gst/deinterlace/tvtime/weavetff.c:
+	  deinterlace: avoid gtk-doc confusing comments
+
+2010-05-21 11:21:58 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/matroskamux.c:
+	  matroskamux: adjust unit test to modified behaviour
+
+2010-05-20 14:33:41 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/ebml-write.h:
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: use write caching also when writing buffer data
+	  Specifically, this reduces pushing several small buffers for each
+	  data buffer and also avoids a seek for each buffer altogether
+	  (though a seek is still needed for each cluster).
+	  Fixes #619273.
+
+2010-05-20 14:23:07 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/ebml-write.h:
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: fix ebml write caching with bytewriter implementation
+	  Also cache a bit more during header writing.
+	  Fixes #619273.
+
+2010-05-20 14:08:42 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/ebml-write.c:
+	  matroskamux: use consistent debug category name for ebmlwrite
+
+2010-05-18 14:44:15 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/ebml-read.c:
+	* gst/matroska/ebml-read.h:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: use bytereader based GstEbmlRead as a helper
+	  ... rather than basing on it by inheritance.
+	  Also use more common code for push and pull mode.
+	  Fixes #619198.
+	  Fixes #611117.
+
+2010-06-01 15:47:32 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: _get_pad_template result needs no unref
+
+2010-05-18 19:42:58 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* ext/libpng/gstpngenc.c:
+	  pngenc: Support 8 bit grayscale
+	  Adds support to 8 bit grayscale input
+
+2010-05-18 14:46:54 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Adds 8bit grayscale support
+	  Adds decoding support for jpeg images in 8 bit grayscale format.
+
+2010-05-18 01:57:14 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: Accept grayscale as input
+	  Adds video/x-raw-grayscale (8 bit) support to jpegenc
+
+2010-05-31 13:30:05 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: Implement sinkpad GetCapsFunction.
+	  This allows returning only the formats, width, height, framerate
+	  and pixel-aspect-ratio that downstream can support.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=620148
+
+2010-05-31 07:49:21 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Don't compare running times with stream times when doing QoS
+
+2010-05-27 21:06:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  deinterlace: Don't reconfigure the caps when changing properties
+	  Fixes bug #619848.
+
+2010-05-26 13:13:44 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalpha.h:
+	  alpha: Add property to allow passthrough mode
+	  This passthrough mode is used if the alpha method is "set"
+	  and the alpha value is 1.0.
+	  Fixes bug #617512.
+
+2010-05-25 15:16:06 +1000  Alexander Kojevnikov <alexander@kojevnikov.com>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: support 24-bit width
+	  Fixes #619045
+
+2010-05-24 21:50:58 +1000  Alexander Kojevnikov <alexander@kojevnikov.com>
+
+	* gst/spectrum/gstspectrum.c:
+	  spectrum: support arbitrary bit depth
+	  Partially fixes #619045
+
+2010-05-25 05:36:46 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: fix deadlock introduced by video keyframe QoS
+
+2010-05-23 09:32:08 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.c:
+	* gst/matroska/matroska-ids.h:
+	  matroskademux: skip buffers before a late keyframe (QoS)
+	  Before, vp8dec had no option but to decode all frames even if some/all
+	  of them would be late. With this change, performance when keyframes are
+	  frequent is helped a great deal. On my Thinkpad X60s, decoding a 20 s
+	  1080p sunflower encode with keyframes every 10 frames went from taking
+	  42 s with 5 frames shown to 21 s with 15 frames shown (still slow
+	  enough to count by hand). When keyframes are more sparse, you will
+	  still be able to catch up eventually, but the results won't be as
+	  noticable.
+
+2010-05-14 17:57:59 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer.h:
+	* gst/videomixer/videomixerpad.h:
+	  videomixer: Don't mix input with different pixel aspect ratios
+	  Fixes bug #618530.
+
+2010-05-17 19:54:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/tvtime/greedyh.asm:
+	* gst/deinterlace/tvtime/greedyh.c:
+	  deinterlace: Add MMX/3DNow implementations of greedyh for UYVY
+
+2010-05-17 19:16:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/tvtime/greedyh.c:
+	  deinterlace: Fix UYVY implementation of greedyh to be actually used
+
+2010-05-11 11:43:07 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/gdk_pixbuf/Makefile.am:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	* ext/gdk_pixbuf/pixbufscale.c:
+	  gdkpixbuf: Add a gdkpixbuf3 plugin that uses gdkpixbuf3
+
+2010-06-01 10:06:10 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* Makefile.am:
+	* common:
+	* win32/common/gstrtpbin-marshal.c:
+	* win32/common/gstrtpbin-marshal.h:
+	* win32/common/gstudp-enumtypes.c:
+	* win32/common/gstudp-marshal.c:
+	* win32/common/gstudp-marshal.h:
+	  win32: add more generated marshal and enumtype files to win32-update
+
+2010-06-01 09:27:00 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska.c:
+	  Revert "matroska: add temporary webm typefinder"
+	  This reverts commit d148ec0ad2053abb0c38fc681a8953292985388f.
+	  We depend on -base git now, which has a webm typefinder in the usual
+	  place.
+
+2010-06-01 09:26:11 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/matroska/matroska-mux.c:
+	  Revert "avimux, flvmux, matroskamux: don't crash if tags arrive on multiple input pads at the same time"
+	  This reverts commit 6a9983cd20c48b96396229b3f94d0254a05ddf48.
+	  Rely on locking done in GstTagSetter in core git.
+
+2010-06-01 09:23:18 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: require core/base git
+	  For WebM typefinding and GstTagsetter fixes.
+
+2010-06-01 09:17:52 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	  Back to development
+
+=== release 0.10.23 ===
+
+2010-05-30 14:03:53 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.10.23
+
+2010-05-30 14:02:04 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2010-05-29 10:23:48 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Fix position query
+
+2010-05-28 15:14:07 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/webm-mux.c:
+	  docs: remove unnecessary videorate element from webmmux example pipeline
+
+2010-05-28 10:43:36 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: Keep variables in sane state after _reset
+	  When reseting, keep 'row' variables at a sane state after
+	  freeing to avoid it being freed again on _resync realloc
+	  when the element is reused.
+	  Fixes #619943
+
+2010-05-27 18:08:17 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Fix floating point to integer conversion for the alpha values
+	  Fixes bug #619835.
+
+2010-05-26 08:54:33 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.10.22.3 pre-release
+
+2010-05-26 00:33:59 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: update translations
+
+2010-05-25 15:34:11 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: handle truncated input data at EOS in pull mode
+	  Fixes #617733.
+
+2010-05-26 11:55:13 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 357b0db to fd7ca04
+
+2010-05-25 21:14:05 +0200  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Round timestamp up when scaling to mov format
+	  Fix timestamp rounding to allow the correct index to be located.
+	  The issue was that scaling from GStreamer time format to mov time format was
+	  rounding down causing the timestamp of the newsegment event received after a
+	  flushing keyframe seek to find the sample index before the one it should
+	  causing further backward seeking to the keyframe prior until no rounding error
+	  occurred.
+	  Rounding up when scaling to mov format has the desired effect, and it is
+	  not clear whether just the _round () variant would be sufficient.
+	  Fixes bug #619105
+
+2010-05-24 17:26:42 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	* gst/flv/gstflvmux.c:
+	* gst/matroska/matroska-mux.c:
+	  avimux, flvmux, matroskamux: don't crash if tags arrive on multiple input pads at the same time
+	  This is a temporary fix for the release only.
+	  Fixes #619533.
+
+2010-05-25 17:05:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	  rtptheora: remove delivery-method from caps
+	  We can accept all delivery methods so don't advertise anything on the caps or
+	  parse anything, we will handle whatever we receive.
+	  Fixes #618940
+
+2010-05-25 15:40:01 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska.c:
+	  matroska: add temporary webm typefinder
+	  Add webm typefinder just for the release, so webm works for
+	  people whose distros don't patch gst-plugins-base as well.
+	  We'll remove this again after the release.
+
+2010-05-23 11:17:27 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/webm-mux.c:
+	  docs: add some pipeline examples to webmmux docs
+
+2010-05-21 12:27:07 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	  docs: add webmmux to docs
+
+2010-05-21 13:01:30 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska.c:
+	* gst/matroska/webm-mux.c:
+	  matroska: fix up plugin and element descriptions a bit
+
+2010-05-21 12:47:03 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/Makefile.am:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	* gst/matroska/matroska.c:
+	* gst/matroska/webm-mux.c:
+	* gst/matroska/webm-mux.h:
+	  matroska: move webmmux into own source files
+	  Makes things easier for gtk-doc.
+
+2010-05-21 12:26:05 +0500  Christian Schaller <christian.schaller@collabora.co.uk>
+
+	* gst-plugins-good.spec.in:
+	  Update spec file with latest changes
+
+2010-05-20 20:01:58 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.c:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.c:
+	  matroska: Remove the doctype enum, it's not needed anymore
+
+2010-05-20 19:57:14 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  webmmux: Add new webmmux element that only supports muxing of WebM
+	  ...and remove the doctype property from matroskamux again.
+
+2010-05-20 17:31:59 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/matroskamux.c:
+	  matroskamux: unit test checks version 1 files
+
+2010-05-18 15:27:06 -0400  Tristan Matthews <tristan@sat.qc.ca>
+
+	* ext/speex/gstspeexenc.c:
+	  speex: fix latency query
+	  Speex should report 30 ms latency for narrowband mode, 34 otherwise.
+	  Fixes #619018
+
+2010-05-18 21:04:32 +0800  Philip <philipj@opera.com>
+
+	* gst/matroska/ebml-read.c:
+	  ebmlread: rm floatcast.h include (not used)
+
+2010-05-17 05:36:00 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: bump default doctype version to 2
+	  In this day and age this should be safe. There's otherwise a risk people
+	  will be creating unneccessarily big WebM files as they can't use
+	  SimpleBlock in v1.
+
+2010-05-17 05:27:44 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	  matroska: handle matroska and webm doctype versions equally
+	  The original plan was to let WebM v1 be the same as Matroska v2 (with
+	  extra constraints), but for simplicity it was decided to handle the
+	  versions equally, such that e.g. SimpleBlock is only allowed in WebM v2.
+
+2010-05-13 12:10:54 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Verify lace size in _parse_blockgroup_or_simpleblock
+	  Failure to do this for corrupt input can cause a subbuffer bigger
+	  than the actual buffer to be created, quickly leading to segfault.
+	  Test case:
+	  bug_s222005751_r0.001____memcpy.webm
+
+2010-05-13 10:23:10 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* gst/matroska/matroska-demux.c:
+	  ebml: crude hack to avoid crashing on unexpected metadata
+	  The comment says this cannot happen, but it did and I don't know
+	  why. This is not the correct fix, needs investigation. Test case:
+	  bug_s555010094_r0.0005:0.008____IA__g_assertion_message_expr.webm
+
+2010-05-13 09:18:56 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* gst/matroska/ebml-read.c:
+	  ebml: don't modify out str if returning an error in _read_ascii
+	  This is a regression from ASCII validation changes. Test case:
+	  bug_s66876390_r0.001____malloc_printerr.webm
+
+2010-05-12 13:16:28 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* gst/matroska/ebml-read.c:
+	  ebml: Validate 7-bit ASCII in gst_ebml_read_ascii
+	  This was triggering an UTF-8 assertion in gst_caps_set_simple for
+	  corrupt files with garbage as codec id. Test case:
+	  gstreamer_error_trying_to_set_invalid_utf8_as_codec_id.webm
+	  Old gst_ebml_read_ascii renamed to gst_ebml_read_string, also used by
+	  gst_ebml_read_utf8. Unlike for UTF-8, failure to validate is an error,
+	  as gst_ebml_read_ascii is used for reading doctype and codec id and we
+	  might just as well give up early in those cases.
+
+2010-05-12 14:30:18 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Ignore unexpected CodecState
+	  Because GstMatroskaTrackContext *stream is set up in the first
+	  SimpleBlock or Block, a rogue CodecState otherwise causes a segfault on
+	  derefencing the NULL pointer. Test case:
+	  bug_s5506167_r0.001____gst_matroska_demux_parse_blockgroup_or_simpleblock.webm
+
+2010-05-10 06:00:49 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Add video/webm sink caps
+
+2010-05-09 19:46:51 +0200  Philip Jägenstedt <philip@foolip.org>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Use SimpleBlock for WebM when possible
+
+2010-05-09 19:28:59 +0200  Philip Jägenstedt <philip@foolip.org>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Support "webm" DocType
+
+2010-05-09 12:35:10 +0200  Philip Jägenstedt <philip@foolip.org>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: rename matroska_version to doctype_version
+
+2010-05-09 12:09:57 +0200  Philip Jägenstedt <philip@foolip.org>
+
+	* gst/matroska/matroska-ids.c:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: Support "webm" DocType
+
+2010-05-12 18:38:48 -0700  David Schleef <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Add VP8
+
+2010-04-27 15:26:13 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Add support for On2 VP8
+	  ...matroskademux automatically supports it through libgstriff.
+
+2010-04-27 15:25:32 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: Add support for On2 VP8
+	  ...avidemux automatically supports it through libgstriff.
+
+2010-05-17 17:17:01 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	  pulse: Don't lock the mainloop in NULL
+
+2010-05-15 21:15:52 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Use = instead of == in shell scripts for equality checks
+
+2010-05-14 18:33:32 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.10.22.2 pre-release
+
+2010-05-14 18:24:14 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 4d67bd6 to 357b0db
+
+2010-05-14 18:16:45 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/souphttpsrc.c:
+	  tests: fix leak in souphttpsrc unit test
+	  Unref server objects when done. Fixes check-valgrind.
+
+2010-05-14 17:30:40 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: fix two leaks
+	  Don't leak othercaps or jpegenc ref.
+
+2010-05-13 13:01:26 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: fix docs
+	  Documentation error spotted by tony <caicai0119 at gmail.com>
+	  Fixes #618419
+
+2010-05-11 13:18:42 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	  rtptheoradepay: make delivery-method parameter optional
+	  It probably will not be in the final RFC as it is not in RFC 5215 for Vorbis.
+	  If there is a configuration specified, assume it is in-line and if nothing is
+	  specified, assume it is in-band.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=618386
+
+2010-05-13 12:16:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: increase acceptable output sizes
+	  We can perfectly decode 1x1 images so lower the min width and height to 1.
+	  Fixes #618392
+
+2010-05-13 11:30:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpceltpay.c:
+	  celtpay: fix queue duration calculations
+	  Don't blindly add the durations of incomming buffers to the total queued
+	  duration because it might be invalid. Mark the total queued duration invalid
+	  when we receive an invalid incomming timestamp because that's when we lose track
+	  of the total queued duration.
+	  Fixes #618324
+
+2010-05-10 11:14:39 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: extract SPS and PPS from property provided parameter set
+	  ... so it can also be regularly inserted into the stream if so configured.
+	  Fixes #617164.
+
+2010-05-11 22:28:08 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: allow switching views at runtime.
+
+2010-05-11 20:26:37 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	  rtp: dist missing header file to fix make distcheck
+
+2010-05-11 19:05:08 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/oss4/oss4-sink.c:
+	  oss4: minor cleanup
+	  Remove fixed FIXME, change finalise to finalize for consistency.
+
+2010-05-11 19:01:51 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/inspect/plugin-oss4.xml:
+	  docs: add oss4 elements to docs
+
+2010-05-11 16:09:10 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/ky.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: move oss4 strings from -bad to -good
+
+2010-05-11 16:08:21 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* gst-plugins-good.spec.in:
+	* po/POTFILES.in:
+	* sys/Makefile.am:
+	* tests/icles/.gitignore:
+	* tests/icles/Makefile.am:
+	  Move oss4 plugin from -bad to -good
+	  Hook up build infrastructure, docs and tests.
+	  Fixes #614305.
+
+2010-04-29 13:18:58 +0100  Brian Cameron <brian.cameron@oracle.com>
+
+	* sys/oss4/oss4-sink.c:
+	* sys/oss4/oss4-sink.h:
+	  oss4sink: implement GstStreamVolume interface and add mute and volume properties
+	  OSS4 supports per-stream volume control, so expose this using the right
+	  API, so that playbin2 and applications like totem can make use of it
+	  (instead of using a volume element for volume control).
+	  Fixes #614305.
+
+2010-04-08 10:45:33 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/oss4/oss4-audio.c:
+	  oss4: 8-bit PCM audio caps don't need an endianness field
+
+2010-04-08 10:40:02 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/oss4/oss4-audio.c:
+	  oss4: don't iterate the formats table twice for each entry
+	  When iterating the formats table, we can just pass the whole
+	  entry to our helper function, which avoids iterating the table
+	  again to find the entry structure from the passed format id.
+
+2010-03-30 11:43:04 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/oss4/oss4-audio.c:
+	  oss4: also accept formats not natively supported
+	  Also accept formats that are not natively supported by the
+	  hardware, OSS4 can convert them internally. List the native
+	  formats first in the caps though, to express our preference
+	  for the native formats. We need this in order to support the
+	  case properly where the audio hardware supports only e.g.
+	  little endian PCM, but the host is big endian, since many
+	  audio elements only support native endianness and make the
+	  reasonable assumption that any audiosink will be able to
+	  handle audio in native endianness.
+	  Based on patch by Jerry Tan <jerry.tan@sun.com>
+	  Fixes #614317.
+
+2010-03-30 01:14:58 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/oss4/oss4-mixer.c:
+	  oss4: add comment for translators
+	  Not that that will make these strings much better. Also remove i18n
+	  marker where it doesn't make sense.
+
+2010-03-22 16:13:12 +0100  Benjamin Otte <otte@redhat.com>
+
+	* sys/oss4/oss4-mixer.c:
+	  oss4: Refactor code to make it look more modern
+	  A side effect is that it passes -Wformat-nonliteral and doesn't read
+	  invalid memory in some cases, like when the mixer track contains
+	  a % sign or there is a number but not a known mixer name.
+
+2010-03-22 14:09:24 +0100  Benjamin Otte <otte@redhat.com>
+
+	* sys/oss4/oss4-mixer.c:
+	  oss4: Avoid g_quark_to_string (g_quark_from_string ()) madness
+	  We to the strdup inside gst_oss4_mixer_control_get_translated_name()
+	  instead of in the only caller.
+
+2010-03-21 21:39:18 +0100  Benjamin Otte <otte@redhat.com>
+
+	* sys/oss4/oss4-mixer.c:
+	  Add -Wmissing-declarations -Wmissing-prototypes to configure flags
+	  And fix all warnings
+
+2010-01-20 13:29:52 +0100  Benjamin Otte <otte@redhat.com>
+
+	* sys/oss4/oss4-mixer.c:
+	  Fix compiler warning about unused return value
+
+2009-08-21 01:17:18 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/icles/test-oss4.c:
+	  tests: fix test-oss4 to treat an empty device name the same as a NULL name
+
+2009-07-16 13:55:14 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* sys/oss4/oss4-mixer.c:
+	  oss4: Attempt to fix a compiler warning
+	  Don't store a const gchar * in a non-const gchar * local var.
+	  Also, make the translation string function static since it's only
+	  used in the one file.
+
+2009-06-10 19:21:21 +0100  Garrett D'Amore <garrett.damore@sun.com>
+
+	* sys/oss4/oss4-audio.c:
+	* sys/oss4/oss4-mixer-slider.c:
+	* sys/oss4/oss4-mixer-switch.c:
+	* sys/oss4/oss4-mixer.c:
+	  oss4: Enhancements to the mixer and audio output
+	  Code cleanups, general improvements, support for the
+	  new mixer flags in latest gst-plugins-base.
+	  Fixes: #584252
+	  Patch By: Brian Cameron <brian.cameron@sun.com>
+	  Patch By: Garrett D'Amore <garrett.damore@sun.com>
+
+2009-06-19 16:21:28 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/oss4/oss4-mixer.c:
+	  Make build without warnings with debugging disabled
+
+2008-11-04 12:42:30 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Don't install static libs for plugins. Fixes #550851 for -bad.
+	  Original commit message from CVS:
+	  * ext/alsaspdif/Makefile.am:
+	  * ext/amrwb/Makefile.am:
+	  * ext/apexsink/Makefile.am:
+	  * ext/arts/Makefile.am:
+	  * ext/artsd/Makefile.am:
+	  * ext/audiofile/Makefile.am:
+	  * ext/audioresample/Makefile.am:
+	  * ext/bz2/Makefile.am:
+	  * ext/cdaudio/Makefile.am:
+	  * ext/celt/Makefile.am:
+	  * ext/dc1394/Makefile.am:
+	  * ext/dirac/Makefile.am:
+	  * ext/directfb/Makefile.am:
+	  * ext/divx/Makefile.am:
+	  * ext/dts/Makefile.am:
+	  * ext/faac/Makefile.am:
+	  * ext/faad/Makefile.am:
+	  * ext/gsm/Makefile.am:
+	  * ext/hermes/Makefile.am:
+	  * ext/ivorbis/Makefile.am:
+	  * ext/jack/Makefile.am:
+	  * ext/jp2k/Makefile.am:
+	  * ext/ladspa/Makefile.am:
+	  * ext/lcs/Makefile.am:
+	  * ext/libfame/Makefile.am:
+	  * ext/libmms/Makefile.am:
+	  * ext/metadata/Makefile.am:
+	  * ext/mpeg2enc/Makefile.am:
+	  * ext/mplex/Makefile.am:
+	  * ext/musepack/Makefile.am:
+	  * ext/musicbrainz/Makefile.am:
+	  * ext/mythtv/Makefile.am:
+	  * ext/nas/Makefile.am:
+	  * ext/neon/Makefile.am:
+	  * ext/ofa/Makefile.am:
+	  * ext/polyp/Makefile.am:
+	  * ext/resindvd/Makefile.am:
+	  * ext/sdl/Makefile.am:
+	  * ext/shout/Makefile.am:
+	  * ext/snapshot/Makefile.am:
+	  * ext/sndfile/Makefile.am:
+	  * ext/soundtouch/Makefile.am:
+	  * ext/spc/Makefile.am:
+	  * ext/swfdec/Makefile.am:
+	  * ext/tarkin/Makefile.am:
+	  * ext/theora/Makefile.am:
+	  * ext/timidity/Makefile.am:
+	  * ext/twolame/Makefile.am:
+	  * ext/x264/Makefile.am:
+	  * ext/xine/Makefile.am:
+	  * ext/xvid/Makefile.am:
+	  * gst-libs/gst/app/Makefile.am:
+	  * gst-libs/gst/dshow/Makefile.am:
+	  * gst/aiffparse/Makefile.am:
+	  * gst/app/Makefile.am:
+	  * gst/audiobuffer/Makefile.am:
+	  * gst/bayer/Makefile.am:
+	  * gst/cdxaparse/Makefile.am:
+	  * gst/chart/Makefile.am:
+	  * gst/colorspace/Makefile.am:
+	  * gst/dccp/Makefile.am:
+	  * gst/deinterlace/Makefile.am:
+	  * gst/deinterlace2/Makefile.am:
+	  * gst/dvdspu/Makefile.am:
+	  * gst/festival/Makefile.am:
+	  * gst/filter/Makefile.am:
+	  * gst/flacparse/Makefile.am:
+	  * gst/flv/Makefile.am:
+	  * gst/games/Makefile.am:
+	  * gst/h264parse/Makefile.am:
+	  * gst/librfb/Makefile.am:
+	  * gst/mixmatrix/Makefile.am:
+	  * gst/modplug/Makefile.am:
+	  * gst/mpeg1sys/Makefile.am:
+	  * gst/mpeg4videoparse/Makefile.am:
+	  * gst/mpegdemux/Makefile.am:
+	  * gst/mpegtsmux/Makefile.am:
+	  * gst/mpegvideoparse/Makefile.am:
+	  * gst/mve/Makefile.am:
+	  * gst/nsf/Makefile.am:
+	  * gst/nuvdemux/Makefile.am:
+	  * gst/overlay/Makefile.am:
+	  * gst/passthrough/Makefile.am:
+	  * gst/pcapparse/Makefile.am:
+	  * gst/playondemand/Makefile.am:
+	  * gst/rawparse/Makefile.am:
+	  * gst/real/Makefile.am:
+	  * gst/rtjpeg/Makefile.am:
+	  * gst/rtpmanager/Makefile.am:
+	  * gst/scaletempo/Makefile.am:
+	  * gst/sdp/Makefile.am:
+	  * gst/selector/Makefile.am:
+	  * gst/smooth/Makefile.am:
+	  * gst/smoothwave/Makefile.am:
+	  * gst/speed/Makefile.am:
+	  * gst/speexresample/Makefile.am:
+	  * gst/stereo/Makefile.am:
+	  * gst/subenc/Makefile.am:
+	  * gst/tta/Makefile.am:
+	  * gst/vbidec/Makefile.am:
+	  * gst/videodrop/Makefile.am:
+	  * gst/videosignal/Makefile.am:
+	  * gst/virtualdub/Makefile.am:
+	  * gst/vmnc/Makefile.am:
+	  * gst/y4m/Makefile.am:
+	  * sys/acmenc/Makefile.am:
+	  * sys/cdrom/Makefile.am:
+	  * sys/dshowdecwrapper/Makefile.am:
+	  * sys/dshowsrcwrapper/Makefile.am:
+	  * sys/dvb/Makefile.am:
+	  * sys/dxr3/Makefile.am:
+	  * sys/fbdev/Makefile.am:
+	  * sys/oss4/Makefile.am:
+	  * sys/qcam/Makefile.am:
+	  * sys/qtwrapper/Makefile.am:
+	  * sys/vcd/Makefile.am:
+	  * sys/wininet/Makefile.am:
+	  * win32/common/config.h:
+	  Don't install static libs for plugins. Fixes #550851 for -bad.
+
+2008-10-12 21:52:27 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  sys/oss4/: Add some spaces in translateable strings.
+	  Original commit message from CVS:
+	  * sys/oss4/oss4-mixer.c:
+	  * sys/oss4/oss4-sink.c:
+	  * sys/oss4/oss4-source.c:
+	  Add some spaces in translateable strings.
+	  Fixes: #555969 #555968 #555965
+
+2008-08-07 16:20:30 +0000  Frederic Crozat <fcrozat@mandriva.org>
+
+	  Make sure gettext returns translations in UTF-8 encoding rather than in the current locale encoding (#546822).
+	  Original commit message from CVS:
+	  Patch by: Frederic Crozat <fcrozat@mandriva.org>
+	  * ext/sndfile/gstsf.c: (plugin_init):
+	  * sys/dvb/gstdvbsrc.c: (gst_dvbsrc_plugin_init):
+	  * sys/oss4/oss4-audio.c: (plugin_init):
+	  Make sure gettext returns translations in UTF-8 encoding rather
+	  than in the current locale encoding (#546822).
+
+2008-06-16 07:30:34 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Final round of doc updates.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  * gst/speed/gstspeed.c:
+	  * gst/speexresample/gstspeexresample.c:
+	  * gst/videosignal/gstvideoanalyse.c:
+	  * gst/videosignal/gstvideodetect.c:
+	  * gst/videosignal/gstvideomark.c:
+	  * sys/dvb/gstdvbsrc.c:
+	  * sys/oss4/oss4-mixer.c:
+	  * sys/oss4/oss4-sink.c:
+	  * sys/oss4/oss4-source.c:
+	  * sys/wininet/gstwininetsrc.c:
+	  Final round of doc updates.
+
+2008-06-12 14:49:18 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Do not use short_description in section docs for elements. We extract them from element details and there will be war...
+	  Original commit message from CVS:
+	  * ext/dc1394/gstdc1394.c:
+	  * ext/ivorbis/vorbisdec.c:
+	  * ext/jack/gstjackaudiosink.c:
+	  * ext/metadata/gstmetadatademux.c:
+	  * ext/mythtv/gstmythtvsrc.c:
+	  * ext/theora/theoradec.c:
+	  * gst-libs/gst/app/gstappsink.c:
+	  * gst/bayer/gstbayer2rgb.c:
+	  * gst/deinterlace/gstdeinterlace.c:
+	  * gst/rawparse/gstaudioparse.c:
+	  * gst/rawparse/gstvideoparse.c:
+	  * gst/rtpmanager/gstrtpbin.c:
+	  * gst/rtpmanager/gstrtpclient.c:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  * gst/rtpmanager/gstrtpptdemux.c:
+	  * gst/rtpmanager/gstrtpsession.c:
+	  * gst/rtpmanager/gstrtpssrcdemux.c:
+	  * gst/selector/gstinputselector.c:
+	  * gst/selector/gstoutputselector.c:
+	  * gst/videosignal/gstvideoanalyse.c:
+	  * gst/videosignal/gstvideodetect.c:
+	  * gst/videosignal/gstvideomark.c:
+	  * sys/oss4/oss4-mixer.c:
+	  * sys/oss4/oss4-sink.c:
+	  * sys/oss4/oss4-source.c:
+	  Do not use short_description in section docs for elements. We extract
+	  them from element details and there will be warnings if they differ.
+	  Also fixing up the ChangeLog order.
+
+2008-06-12 13:06:37 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/icles/test-oss4.c: Include stdlib.h.
+	  Original commit message from CVS:
+	  * tests/icles/test-oss4.c:
+	  Include stdlib.h.
+
+2008-05-22 16:33:25 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/icles/: Small oss4 test that probes for available devices and retrieves their caps and mixer tracks and all tha...
+	  Original commit message from CVS:
+	  * tests/icles/.cvsignore:
+	  * tests/icles/Makefile.am:
+	  * tests/icles/test-oss4.c: (opt_show_mixer_messages), (WAIT_TIME),
+	  (show_mixer_messages), (probe_mixer_tracks), (probe_pad),
+	  (probe_details), (probe_element), (main):
+	  Small oss4 test that probes for available devices and retrieves
+	  their caps and mixer tracks and all that. Also allows testing of
+	  mixer change messages on the bus.
+
+2008-05-22 15:14:26 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/oss4/: Make device-name probing in NULL state work better (e.g. for the gnome-control-center sound capplet).
+	  Original commit message from CVS:
+	  * sys/oss4/oss4-mixer.c: (gst_oss4_mixer_open):
+	  * sys/oss4/oss4-property-probe.c:
+	  (gst_oss4_property_probe_find_device_name),
+	  (gst_oss4_property_probe_find_device_name_nofd):
+	  * sys/oss4/oss4-property-probe.h:
+	  * sys/oss4/oss4-sink.c: (gst_oss4_sink_get_property):
+	  * sys/oss4/oss4-source.c: (gst_oss4_source_get_property):
+	  Make device-name probing in NULL state work better (e.g. for the
+	  gnome-control-center sound capplet).
+
+2008-05-08 19:16:17 +0000  Clive Wright <clive_wright@ntlworld.com>
+
+	  sys/oss4/oss4-mixer-slider.c: Apparently mono sliders have the mono value repeated in the upper bits, so mask those o...
+	  Original commit message from CVS:
+	  Based on patch by: Clive Wright <clive_wright ntlworld com>
+	  * sys/oss4/oss4-mixer-slider.c: (gst_oss4_mixer_slider_unpack_volume):
+	  Apparently mono sliders have the mono value repeated in the upper bits,
+	  so mask those out when reading them. Probably makes the mixer applet
+	  work properly in some more cases.
+
+2008-04-11 08:13:22 +0000  Julien Moutte <julien@moutte.net>
+
+	  sys/oss4/: Fix arguments format in debug statements.
+	  Original commit message from CVS:
+	  2008-04-11  Julien Moutte  <julien@fluendo.com>
+	  * sys/oss4/oss4-mixer-enum.c:
+	  (gst_oss4_mixer_enum_get_values_locked):
+	  * sys/oss4/oss4-source.c: (gst_oss4_source_delay): Fix arguments
+	  format in debug statements.
+
+2008-04-02 20:18:58 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Add initial support for OSSv4. Mixer still needs a bit more love, but even magic has its limits.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * sys/Makefile.am:
+	  * sys/oss4/Makefile.am:
+	  * sys/oss4/oss4-audio.c:
+	  * sys/oss4/oss4-audio.h:
+	  * sys/oss4/oss4-mixer-enum.c:
+	  * sys/oss4/oss4-mixer-enum.h:
+	  * sys/oss4/oss4-mixer-slider.c:
+	  * sys/oss4/oss4-mixer-slider.h:
+	  * sys/oss4/oss4-mixer-switch.c:
+	  * sys/oss4/oss4-mixer-switch.h:
+	  * sys/oss4/oss4-mixer.c:
+	  * sys/oss4/oss4-mixer.h:
+	  * sys/oss4/oss4-property-probe.c:
+	  * sys/oss4/oss4-property-probe.h:
+	  * sys/oss4/oss4-sink.c:
+	  * sys/oss4/oss4-sink.h:
+	  * sys/oss4/oss4-soundcard.h:
+	  * sys/oss4/oss4-source.c:
+	  * sys/oss4/oss4-source.h:
+	  Add initial support for OSSv4. Mixer still needs a bit more love,
+	  but even magic has its limits.
+
+2010-05-11 10:52:58 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* sys/osxvideo/cocoawindow.h:
+	* sys/osxvideo/cocoawindow.m:
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: implement the xoverlay interface. Fixes #618349.
+
+2010-05-11 18:42:32 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix push based seeking
+	  ... where it comes down to transforming incoming BYTE segment
+	  to a corresponding TIME segment.
+	  Also fixes #609405.
+
+2010-05-11 14:23:47 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-imagefreeze.xml:
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	  Move imagefreeze plugin from -bad to -good
+	  Hook up build infrastructure, docs and unit test for new plugin.
+	  Fixes #613786.
+
+2010-05-05 12:23:56 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Set fixed caps on the correct pad
+	  This makes the sink getcaps function actually used instead of using
+	  the fixed caps function for it.
+
+2010-03-21 21:39:18 +0100  Benjamin Otte <otte@redhat.com>
+
+	* tests/check/elements/imagefreeze.c:
+	  Add -Wmissing-declarations -Wmissing-prototypes to configure flags
+	  And fix all warnings
+
+2010-03-15 11:54:02 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Only start the task after a seek if a buffer was received already
+
+2010-02-28 16:08:14 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/imagefreeze.c:
+	  imagefreeze: Add some unit tests
+
+2010-02-28 16:04:31 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Set undefined framerate in sink getcaps function
+
+2010-02-28 15:02:02 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/imagefreeze/gstimagefreeze.c:
+	  imagefreeze: Implement reverse playback and set buffer offsets
+
+2010-02-27 17:33:05 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/imagefreeze/Makefile.am:
+	* gst/imagefreeze/gstimagefreeze.c:
+	* gst/imagefreeze/gstimagefreeze.h:
+	  imagefreeze: Add still frame stream generator element
+
+2010-05-11 13:07:19 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* gst/debugutils/Makefile.am:
+	* gst/debugutils/gstdebug.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	  Move capsfilter element from -bad to -good
+	  Hook up moved files to the build infrastructure and docs.
+	  Fixes #617739.
+
+2010-05-06 13:12:32 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/debugutils/gstcapssetter.c:
+	* gst/debugutils/gstcapssetter.h:
+	  capssetter: Some minor cleanup
+
+2010-03-22 16:56:03 +0100  Benjamin Otte <otte@redhat.com>
+
+	* tests/check/elements/capssetter.c:
+	  Add -Wold-style-definition
+	  and fix the warnings
+
+2010-03-18 17:30:26 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/debugutils/gstcapssetter.c:
+	  gst_element_class_set_details => gst_element_class_set_details_simple
+
+2009-10-08 19:51:31 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/capssetter.c:
+	  capssetter: add unit test
+
+2009-06-25 16:41:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/debugutils/gstcapssetter.c:
+	* gst/debugutils/gstcapssetter.h:
+	  capssetter: import element into -bad
+
+2010-05-11 12:06:10 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: check that pads have been negotiated
+	  Also set fcc_handler field in audio stream header.
+	  Fixes #618351.
+
+2010-05-10 18:33:03 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix partial parsing of ctts table
+	  Fixes #616516.
+
+2010-05-10 18:32:15 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: cleanup a comment and add some debug and conditional compilation
+
+2010-05-11 10:01:52 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Check for GTK+ 3.0 and if it's not available for GTK+ 2.0
+
+2010-05-10 22:11:10 +0200  Jan Urbański <wulczer@wulczer.org>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: only store the last buffer timestamp if it's valid
+	  Fixes bug #618305
+
+2010-01-08 22:13:59 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: Re-send SPS/PPS when requested
+	  https://bugzilla.gnome.org/show_bug.cgi?id=606689
+
+2010-05-07 17:09:16 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: fix typo in debug message
+
+2010-05-07 15:42:23 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtptheorapay.h:
+	  rtptheorapay: add config-interval parameter to re-insert config in stream
+	  Add a new config-interval property to instruct the payloader to insert
+	  configuration headers at periodic intervals in the stream
+	  (when a keyframe is countered).
+
+2010-05-07 15:31:03 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	  rtptheoradepay: fix in-band configuration parsing
+	  Also make configuration header parsing a bit more relaxed with respect
+	  to length field interpretation.
+
+2010-05-07 15:30:30 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpvorbisdepay.c:
+	  rtpvorbisdepay: fix in-line configuration parsing
+	  Also make configuration header parsing a bit more relaxed with respect
+	  to length field interpretation.
+
+2010-05-04 16:57:35 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtptheorapay.c:
+	  rtptheorapay: do not discard downstream flow return
+
+2010-05-04 16:57:11 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtptheorapay.c:
+	  rtptheorapay: refactor buffer payloading
+
+2010-05-07 20:41:04 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	* gst/deinterlace/gstdeinterlacemethod.h:
+	* gst/deinterlace/tvtime/greedy.c:
+	* gst/deinterlace/tvtime/greedyh.c:
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/scalerbob.c:
+	* gst/deinterlace/tvtime/vfir.c:
+	* gst/deinterlace/tvtime/weave.c:
+	* gst/deinterlace/tvtime/weavebff.c:
+	* gst/deinterlace/tvtime/weavetff.c:
+	  deinterlace: Add support for UYVY
+
+2010-05-07 19:06:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: fix return value
+
+2010-05-07 19:02:21 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: don't leak the session
+
+2010-05-07 18:59:42 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtsp: configure bandwidth properties in the session
+
+2010-05-07 18:58:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: add properties to configure the bandwidth
+	  Add properties to proxy the bandwidth configuration to the session object.
+
+2010-05-07 18:57:13 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	  rtpsession: add properties to configure bandwidths
+	  Add properties to configure the sender and receiver bandwidths.
+	  Configure the bandwidths before calculating the RTCP timeout when we need to.
+
+2010-05-07 18:56:30 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpstats.c:
+	  rtpstats: add some debug info
+
+2010-05-07 18:55:34 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: small cleanups
+
+2010-05-07 16:55:13 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpstats.c:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpstats: make bandwidths more configurable
+	  Add a method to configure the various bandwidths in the session.
+
+2010-05-07 13:32:30 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: handle NONE RTCP intervals
+	  Prepare for handling RTCP reporting intervals of GST_CLOCK_TIME_NONE, which
+	  means don't send RTCP at all.
+
+2010-05-07 12:51:05 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: fall back to SDP ports instead of server_port
+	  In multicast, fall back to the ports in the SDP instead of the server_port
+	  attribute as this is more in line with the RFC.
+
+2010-05-07 12:24:51 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: refactor collecting the transport info
+	  Make a method to collect the ports and destination address.
+
+2010-05-07 11:28:36 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: handle servers that send broken Transports
+	  Handle servers that send their port pairs with the wrong name.
+	  Fixes #617537
+
+2010-05-06 16:52:26 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: use the SDP connection info in multicast
+	  Parse the connection info from the SDP.
+	  When we need to configure the multicast destination, fall back to the SDP
+	  connection info when the transport did not specify a destination and ttl.
+	  Fixes #617537
+
+2010-05-06 15:42:38 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/monoscope/gstmonoscope.c:
+	  goom,monoscope: truncate own caps, instead of copying and using the first only
+	  We got the caps from an intersect, it is our own, hence we can truncate it.
+
+2010-05-06 15:40:33 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: reflow to truncate caps just once
+	  We get writable cpas from the intersection (unless it failed). As we truncate
+	  those anyway, we don't need to manyaly copy the first structure.
+
+2010-05-06 15:39:31 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	  gdkpixbuf: don't leak template caps
+
+2010-05-06 15:38:35 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	  auto{audio,video}{src,sink}: use can_intersect to avoid a caps copy
+
+2010-04-27 13:36:35 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: tell what we can do
+	  Any-caps are bad. If apps scan the registry, they'd like to know what we can
+	  output.
+
+2010-04-27 13:43:29 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: also lift the arbitrary restrictions for width and height
+	  This was already done for jpegdec.
+
+2010-05-06 14:03:11 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: Allocate/free PA mainloop during state changes
+	  ...also destroy the stream and context during state changes.
+
+2010-05-06 13:57:01 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Allocate and free the custom clock in NULL<->READY
+
+2010-05-06 13:51:59 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Create and free the PA mainloop in NULL->READY/READY->NULL
+	  This fixes a race condition, when stopping the mainloop during finalization
+	  is done from a mainloop callback.
+	  Fixes bugs #614765 and #590662.
+
+2010-05-05 19:35:48 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: Make selection of a sinkpad number threadsafe
+
+2010-05-05 17:39:32 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	* gst/deinterlace/gstdeinterlacemethod.h:
+	* gst/deinterlace/tvtime/greedy.c:
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/scalerbob.c:
+	* gst/deinterlace/tvtime/vfir.c:
+	* gst/deinterlace/tvtime/weave.c:
+	* gst/deinterlace/tvtime/weavebff.c:
+	* gst/deinterlace/tvtime/weavetff.c:
+	  deinterlace: Add support for all common RGB formats
+
+2010-05-05 16:06:51 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	* gst/deinterlace/gstdeinterlacemethod.h:
+	* gst/deinterlace/tvtime/greedy.c:
+	* gst/deinterlace/tvtime/greedyh.asm:
+	* gst/deinterlace/tvtime/greedyh.c:
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/scalerbob.c:
+	* gst/deinterlace/tvtime/vfir.c:
+	* gst/deinterlace/tvtime/weave.c:
+	* gst/deinterlace/tvtime/weavebff.c:
+	* gst/deinterlace/tvtime/weavetff.c:
+	  deinterlace: Add support for AYUV
+
+2010-05-04 16:34:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: make setup url in a smarter way
+	  Make sure we always separate the base and control url parts with a / when
+	  creating the setup url.
+
+2010-05-04 16:04:39 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: handle SEEKING queries.
+
+2010-05-04 11:13:45 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmp4vpay.h:
+	  rtpmp4vpay: add config-interval parameter to re-insert config in stream
+	  Add a new config-interval property to instruct the payloader to insert
+	  config (VOSH, VOS, etc) at periodic intervals in the stream
+	  (when a GOP or VOP-I is encountered).
+	  Based on patch by <marc.leeman at gmail.com>
+	  Fixes #607452.
+
+2010-05-03 13:26:32 +0200  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: move some initialization code from change_state to _init.
+	  Set ->active to TRUE in _init so it can be set to FALSE after creating the
+	  jitterbuffer and it won't be mistakenly reset to TRUE in the change_state
+	  function.
+	  This is needed to start the jitterbuffer as inactive when rtpbin is buffering.
+
+2010-05-03 11:56:58 +0200  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: fix a bug handling BUFFERING messages.
+	  If a session exists but has no streams, set the min buffering percent to 0
+	  since it means that we haven't received anything for that session yet.
+
+2010-05-03 11:51:37 +0200  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: when a stream is created, pause the jitterbuffer if rtpbin is buffering.
+
+2010-05-03 11:23:59 +0200  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: fix a bug calculating stream offsets.
+
+2010-05-01 14:20:59 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: Write previous cluster's size
+	  This is useful for backwards playback, which should be implemented
+	  in matroskademux at some point.
+
+2010-05-01 14:15:49 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Set interlaced flag in the caps if the flag is set in the Matroska file
+
+2010-05-01 14:12:28 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Write interlaced flag if the input video content is interlaced
+	  Unfortunately Matroska has no way to specify TFF and friends...
+
+2010-05-01 11:25:26 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	  rtp: fix printf format of some debug messages
+
+2010-05-01 11:06:53 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska: init variable to avoid compiler warning on OSX
+	  Fixes (bogus) "'offset' may be used uninitialized in this function"
+	  warning on build bot (also spotted by philn).
+
+2010-04-30 17:19:44 -0700  David Schleef <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: UYVY is 4:2:2, not 4:2:0
+
+2010-04-30 22:22:25 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulseutil.c:
+	  pulse: Don't compare values of two different enum types
+
+2010-04-30 22:13:30 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Make automatic detection of interlacing the default
+	  Previously "force deinterlacing" was the default, which is a not very
+	  sensible default for the normal use case where deinterlace should act
+	  in passthrough mode unless interlaced content is present.
+
+2010-04-29 16:26:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: optimise buffer scanning
+	  Specifically, when needing more data, do not rescan from start next time
+	  around, but resume from last position.
+	  See also #583047.
+
+2010-04-29 15:38:49 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: disregard superfluous lines when indirect decoding
+
+2010-04-27 15:44:39 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: add support for RGB and grayscale color space
+	  Also refactor src caps negotiation and setting.
+
+2010-04-27 12:19:22 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/Makefile.am:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstjpegenc.h:
+	  jpegenc: support more colour spaces and some cleanups
+
+2010-04-30 12:47:01 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: more generic sink getcaps
+
+2010-04-30 12:42:42 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: more sanity checks on input
+	  Specifically, verify input components / colour space is as code
+	  subsequently expects, thereby avoiding crashes or otherwise bogus output.
+	  Presently, that means 3 components YCbCr colour space, and somewhat
+	  limited sampling factors.
+	  Fixes #600553.
+
+2010-04-22 12:28:22 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	  rtptheoradepay: also accept in-band configuration
+	  Fixes #574416 (theora).
+
+2010-04-22 12:27:35 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpvorbisdepay.c:
+	  rtpvorbisdepay: also accept in-line configuration
+	  Fixes #574416 (vorbis).
+
+2010-04-07 17:21:55 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	  rtptheoradepay: Ignore packets without a known codebook
+	  Don't produce an error if a packet is received without a valid codebook,
+	  it's possible that the codebook will just be coming later.
+	  See #574416.
+
+2010-04-20 12:17:26 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* tests/check/elements/y4menc.c:
+	  y4menc: adjust unit test to element behaviour
+
+2010-02-23 22:16:39 -0500  Benjamin M. Schwartz <bens@alum.mit.edu>
+
+	* gst/y4m/gsty4mencode.c:
+	* gst/y4m/gsty4mencode.h:
+	  y4menc: add 4:2:2, 4:1:1, and 4:4:4 output support
+	  Fixes #610902.
+
+2010-04-15 12:21:56 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264depay.h:
+	  rtph264depay: DELTA_UNIT marking of output buffers
+	  ... which evidently makes (most) sense if output buffers are
+	  actually frames.
+	  Partially based on a patch by
+	  Miguel Angel Cabrera <mad_aluche at hotmail.com>
+	  Fixes #609658.
+
+2010-04-16 17:21:50 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263depay.h:
+	  rtph263depay: extra keyframe info from PTYPE header
+	  ... as opposed to taking it from h263 payload header, which need not
+	  be so reliable.
+	  Fixes #610172.
+
+2010-04-16 17:08:47 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph263depay.c:
+	  rtph263depay: also use Picture Start Code to detect packet loss
+	  This ensures a whole frame is dropped if a (start) packet is lost,
+	  rather than relying only on the DISCONT flag.
+
+2010-04-16 17:06:11 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph263depay.c:
+	  rtph263depay: detect frame start using Picture Start Code
+	  So we stop dropping fragments as soon as there is a picture start (code).
+	  In particular, this prevents dropping the first frame following
+	  initial DISCONT.
+
+2010-04-16 16:34:06 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph263depay.c:
+	  rtph263depay: handle a few FIXMEs
+
+2010-04-16 16:27:25 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph263depay.c:
+	  rtph263depay: slightly refactor payload dropping
+
+2010-04-16 11:53:17 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pay.h:
+	  rtph263pay: use found GOBs to apply Mode A payloading
+	  ... rather than falling back to sending the whole frame in one packet
+	  if number of GOB startcodes < maximum.
+	  One might take this further and still perform Mode B/C payloading,
+	  but at least this should cater for decent fragments in typical cases.
+	  Fixes #599585.
+
+2010-04-14 11:53:46 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: implement push mode seeking
+
+2010-04-29 20:08:43 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videofilter.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* gst/smpte/gstsmptealpha.c:
+	  docs: update for videofilter plugin merge and add gtk-doc blurb for new property
+
+2010-04-26 18:12:46 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Improve segment handling a bit
+
+2010-04-26 18:05:00 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Order caps by amount of contained information
+
+2010-04-26 17:25:38 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Properly set interlaced field in getcaps
+
+2010-04-24 16:28:12 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/scalerbob.c:
+	* gst/deinterlace/tvtime/weave.c:
+	* gst/deinterlace/tvtime/weavebff.c:
+	* gst/deinterlace/tvtime/weavetff.c:
+	  deinterlace: Add planar YUV support to all other simple methods
+
+2010-04-24 16:10:06 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/tvtime/greedyh.asm:
+	* gst/deinterlace/tvtime/greedyh.c:
+	  deinterlace: Add planar YUV support to greedyh method
+
+2010-04-24 15:42:07 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/tvtime/greedy.c:
+	  deinterlace: Add support for planar YUV formats in greedyl method
+
+2010-04-24 13:58:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	* gst/deinterlace/gstdeinterlacemethod.h:
+	* gst/deinterlace/tvtime/vfir.c:
+	  deinterlace: Add support for Y444, Y42B, I420, YV12 and Y41B
+	  The vfir method supports them and will be used until something else
+	  supports it.
+
+2010-04-24 09:16:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	  deinterlace: Define deinterlace method base classes as abstract types
+
+2010-04-23 17:40:10 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/Makefile.am:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	* gst/deinterlace/gstdeinterlacemethod.c:
+	* gst/deinterlace/gstdeinterlacemethod.h:
+	* gst/deinterlace/tvtime/greedy.c:
+	* gst/deinterlace/tvtime/greedyh.c:
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/scalerbob.c:
+	* gst/deinterlace/tvtime/tomsmocomp.c:
+	* gst/deinterlace/tvtime/vfir.c:
+	* gst/deinterlace/tvtime/weave.c:
+	* gst/deinterlace/tvtime/weavebff.c:
+	* gst/deinterlace/tvtime/weavetff.c:
+	  deinterlace: Move deinterlacing methods to their own file
+
+2010-04-23 17:25:12 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  deinterlace: Simplify passthrough mode detection
+
+2010-04-23 14:35:44 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/deinterlace.c:
+	  deinterlace: Fix unit test that checks caps handling
+	  deinterlace now always adds the interlaced field to the output caps,
+	  if it wasn't present in the input caps the output caps will still
+	  contain interlaced=false.
+
+2010-04-21 17:00:05 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/Makefile.am:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	* gst/deinterlace/tvtime/greedy.c:
+	* gst/deinterlace/tvtime/greedyh.asm:
+	* gst/deinterlace/tvtime/greedyh.c:
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/scalerbob.c:
+	* gst/deinterlace/tvtime/tomsmocomp.c:
+	* gst/deinterlace/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	* gst/deinterlace/tvtime/vfir.c:
+	* gst/deinterlace/tvtime/weave.c:
+	* gst/deinterlace/tvtime/weavebff.c:
+	* gst/deinterlace/tvtime/weavetff.c:
+	  deinterlace: Refactor deinterlacing as preparation for supporting more color formats
+
+2010-04-22 19:05:37 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Add support for Y444, Y42B and Y41B
+
+2010-04-22 15:54:21 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Add support for YVYU and reorder template caps
+
+2010-04-18 21:11:21 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Translate navigation events to make sense again upstream
+
+2010-04-18 20:58:14 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Properly handle ranges/lists of width or height when transforming caps
+	  Code partly taken from the videocrop element.
+
+2010-04-22 15:45:15 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Fix planar YUV->RGB processing
+
+2010-04-22 15:42:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Correctly clamp after YUV->RGB conversion
+
+2010-04-22 15:20:24 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Add support for YUY2, YVYU and UYVY
+
+2010-04-18 15:02:42 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Sync properties to the controller in before_transform
+
+2010-04-16 17:00:02 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Add support for YUY2 and UYUV
+
+2010-04-21 17:41:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Refactor processing and add support for other planar YUV formats
+	  This reduces the generated code size by a factor of 2.5.
+
+2010-04-21 17:15:33 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Add support for YV12 input
+
+2010-04-22 13:56:58 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend.c:
+	* gst/videomixer/blend.h:
+	* gst/videomixer/videomixer.c:
+	  videomixer: Add support for YUY2, YVYU, UYVY
+
+2010-04-20 12:18:18 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend.c:
+	* gst/videomixer/blend.h:
+	* gst/videomixer/videomixer.c:
+	  videomixer: Add support for Y444, Y42B, Y41B and YV12
+
+2010-04-21 17:07:10 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideoflip.c:
+	  videofilter: Order color formats by their contained amount of information
+
+2010-04-20 18:22:16 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: Drop Y41B/Y42B support
+	  Rotating 90°/270° with subsampled YUV where horizontal
+	  and vertical subsampling are different doesn't really work.
+
+2010-04-19 14:37:54 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: Also flip the pixel-aspect-ratio if width/height are exchanged
+
+2010-04-18 23:08:14 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/videofilter.c:
+	  videofilter: Extend the unit test to test different color formats
+
+2010-04-18 22:55:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/videofilter.c:
+	  videofilter: Add some more tests
+	  These check different property combinations
+
+2010-04-18 22:54:23 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: Change the default method to identity
+
+2010-04-18 22:50:20 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideobalance.h:
+	  videobalance: Reduce number of allocations per instance
+
+2010-04-18 22:45:58 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideoflip.c:
+	  videofilter: Update last-reviewed comments
+
+2010-04-18 22:40:55 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: Add support for all RGB formats
+
+2010-04-18 22:28:17 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: Add support for YUY2, UYVY, AYUV and YVYU
+
+2010-04-18 22:23:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: Add debug category
+
+2010-04-18 22:19:55 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: Make property access threadsafe
+
+2010-04-18 22:18:24 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: Add support for Y41B, Y42B and Y444
+
+2010-04-18 22:17:02 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideobalance.h:
+	  videobalance: Use libgstvideo for format specific things
+
+2010-04-18 22:09:06 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: Make properties controllable
+
+2010-04-18 22:06:44 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: Emit "value-changed" signal of color balance interface when values change
+
+2010-04-18 21:58:13 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideobalance.h:
+	  videobalance: Some random cleanup
+
+2010-04-18 21:37:23 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideobalance.c:
+	  videobalance: Stop using liboil
+	  The used liboil function is deprecated and has no optimized
+	  implementation anyway.
+
+2010-04-18 21:14:11 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: Make property access threadsafe
+
+2010-04-18 15:00:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstgamma.c:
+	  gamma: Sync properties to the controller in before_transform
+
+2010-04-18 14:46:09 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: Add support for all RGB formats and AYUV
+
+2010-04-18 14:31:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: Add support for Y41B, Y42B and Y444
+
+2010-04-18 14:29:30 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videofilter/gstvideoflip.h:
+	  videoflip: Make processing more general and use libgstvideo for all format specific things
+
+2010-04-18 13:12:40 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideoflip.c:
+	  videoflip: Make method property controllable and improve debug output
+
+2010-04-18 13:03:48 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videofilter/gstvideoflip.h:
+	  videoflip: Some random cleanup
+
+2010-04-18 10:17:52 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* Makefile.am:
+	* gst/videofilter/Makefile.am:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videofilter/plugin.c:
+	  videofilter: Move all elements into a single plugin
+	  Having all these small elements in a separate plugin
+	  is not very memory effective...
+
+2010-04-18 10:07:24 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstgamma.h:
+	  gamma: Improve docs a bit
+
+2010-04-18 09:59:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstgamma.c:
+	  gamma: Add support for all RGB formats
+
+2010-04-18 09:46:15 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstgamma.c:
+	  gamma: Add support for many packed YUV formats
+	  That is YUY2, UYVY, AYUV and YVYU.
+
+2010-04-18 09:38:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstgamma.c:
+	  gamma: Add support for all other planar YUV formats
+	  That is Y41B, Y42B, Y444, NV12 and NV21.
+
+2010-04-18 09:33:49 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/Makefile.am:
+	* gst/videofilter/gstgamma.c:
+	  gamma: Stop using liboil
+	  The used liboil function is deprecated, only has a reference implementation
+	  and is more complex than what's needed here.
+
+2010-04-17 18:13:46 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstgamma.h:
+	  gamma: Use libgstvideo for format specific values and make gamma processing more generic
+	  Allows us to easily add support for new color formats later.
+
+2010-04-17 18:01:06 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/Makefile.am:
+	* gst/videofilter/gstgamma.c:
+	  gamma: Make gamma property controllable
+	  ...and properly use liboil.
+
+2010-04-17 17:55:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videofilter/gstgamma.c:
+	  gamma: Some random cleanup
+
+2010-04-19 14:45:33 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/smpte/gstsmptealpha.c:
+	  smptealpha: Sync properties to the controller in before_transform
+
+2010-04-17 17:47:05 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/smpte/gstsmptealpha.c:
+	  smptealpha: Add support for YV12 (converted to AYUV)
+
+2010-04-17 17:43:51 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/smpte/gstsmptealpha.c:
+	  smptealpha: Add support for all 4 ARGB formats
+	  ...without format conversion.
+
+2010-04-16 17:27:02 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/smpte/gstsmptealpha.c:
+	* gst/smpte/gstsmptealpha.h:
+	  smptealpha: Make color format support more generic
+	  This allows easier addition of new formats later.
+
+2010-04-16 17:18:15 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/smpte/gstsmptealpha.c:
+	* gst/smpte/gstsmptealpha.h:
+	  smptealpha: Some random cleanup
+
+2010-04-15 22:28:58 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/smpte/gstmask.c:
+	* gst/smpte/gstmask.h:
+	* gst/smpte/gstsmpte.c:
+	* gst/smpte/gstsmpte.h:
+	* gst/smpte/gstsmptealpha.c:
+	* gst/smpte/gstsmptealpha.h:
+	  smpte: Add property for inverting the transition mask
+	  This converts a left-to-right transition to right-to-left or
+	  clock-wise to counter-clock-wise.
+
+2010-04-15 22:27:57 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/smpte/gstsmptealpha.c:
+	  smptealpha: Correctly detect property changes and update properties
+
+2010-04-16 19:35:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpqcelpdepay.c:
+	* gst/rtp/gstrtpqcelpdepay.h:
+	  qcelpdepay: add first version of a QCELP depayloader
+
+2010-04-29 15:18:07 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	  Back to development.
+
+=== release 0.10.22 ===
+
+2010-04-28 02:58:02 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/gst-plugins-good-plugins.prerequisites:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.10.22
+
+2010-04-28 02:57:21 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2010-04-25 23:36:29 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.10.21.3 pre-release
+
+2010-04-25 21:19:33 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: hide is-live property for release
+	  At the very least it needs a better/less wrong name.
+	  See #613066.
+
+2010-04-25 15:12:20 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: don't crash if jpeg image contains more than three components
+	  Our code currently only handles a maximum of 3 components, so error
+	  out for now if the image has more components than that.
+	  Fixes #604106.
+
+2010-04-20 17:21:29 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst-plugins-good.doap:
+	  doap: update repository info from cvs->git and maintainers
+
+2010-04-23 14:40:20 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From fc85867 to 4d67bd6
+
+2010-04-22 13:30:55 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend.c:
+	  videomixer: Fix byte order for MMX ARGB/AYUV color filling
+	  Fixes bug #616409.
+
+2010-04-21 17:53:49 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend.c:
+	  videomixer: Fix AYUV checker/color filling
+
+2010-04-19 16:43:28 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_mmx.h:
+	  videomixer: Add i387 floating point registers to the clobbered registers list
+	  They are the same as the mm0-mm7 MMX registers and will be overwritten
+	  by the assembly code if gcc doesn't know about the MMX registers.
+	  Note: They're all added to the list of clobbered registers in all cases
+	  and not only when __MMX__ is not defined just to make sure that no other
+	  bugs happen with this code just because some compiler version gets things
+	  wrong.
+	  Fixes bug #614466.
+
+2010-04-19 14:09:34 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Use libgstvideo to get the order of RGB
+
+2010-04-17 10:06:41 +0100  Brian Cameron <brian.cameron@oracle.com>
+
+	* gst/goom/xmmx.c:
+	  goom: add edx to clobber list in inline assembly code
+	  mull modifies %edx, so should be mentioned in clobber list.
+	  Fixes crash on Solaris (#615998).
+
+2010-04-15 13:39:41 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/icles/Makefile.am:
+	  tests: don't use GST_PLUGIN_LDFLAGS when building test binaries
+
+2010-04-16 15:27:12 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Fix I420->I420 copying
+	  Fixes bug #615143.
+
+2010-04-13 18:15:50 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Fix AYUV->I420 copying
+
+2010-04-16 12:14:26 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: profile-level-id is an optional parameter
+	  So, if needed, extract the corresponding info from
+	  sprop-parameter-sets.
+	  Based on patch provided by <dxssx at gmail.com>
+	  Fixes #612657.
+
+2010-04-15 07:13:46 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Drop -Wcast-align
+	  Commit message copied from core's commit from Benjamin Otte:
+	  246f5dba96a5b50bb74621af67b30942cca72af5
+	  Apparently gcc warns that GstMiniObject is not castable to
+	  GstEvent/Message/Buffer due to them containing 64bit variables, even
+	  though ARM hackers claim that those only need 4byte alignment. And as
+	  long as gcc behaves that way, this warning is not very useful.
+	  So we'll remove the warning until this problem is fixed.
+	  Fixes #615698
+
+2010-04-14 23:46:06 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflactag.c:
+	  flactag: fix adapter assertion when used directly after flacenc
+	  Unlike filesrc, flacenc outputs the flac blocks neatly aligned one in
+	  each buffer. This means that when we switch from metadata mode to
+	  audio data passthrough mode, there's no data left in the adapter to
+	  push out at this point, so check if there's data in the adapter
+	  before requesting buffers from it (also needed in case we get input
+	  buffers of 0 size).
+	  Fixes #615793.
+
+2010-04-14 23:18:27 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.10.21.2 pre-release
+
+2010-04-14 20:31:30 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: update
+
+2010-04-14 20:06:09 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/examples/equalizer/Makefile.am:
+	* tests/examples/shapewipe/Makefile.am:
+	* tests/examples/spectrum/Makefile.am:
+	* tests/examples/v4l2/Makefile.am:
+	* tests/icles/Makefile.am:
+	  tests: use LDADD for libs to link to instead of LDFLAGS
+	  Use foo_LDADD instead of foo_LDFLAGS to specify the libraries to link to.
+	  This should make sure arguments are passed to the linker in the right
+	  order, and makes LDFLAGS usable again.
+	  Based on patch by Brian Cameron <brian.cameron@oracle.com>
+	  Fixes #615697.
+
+2010-04-14 18:13:56 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: transform_caps : We can only convert AYUV to xRGB
+	  We were previously stating that we could convert AYUV/I420/YV12 to xRGB.
+
+2010-04-13 00:14:46 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: also remove -Waggregate-return from warning flags
+	  It causes problems with Objective-C code like in osxvideosink.
+	  Fixes #613663.
+
+2010-04-12 18:22:39 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* tests/check/Makefile.am:
+	  check: Ignore osx audio/video src/sinks in state change tests
+	  And make the line readable for those mere mortals that don't own a 30" screen
+
+2010-04-12 18:03:20 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* tests/check/elements/cmmldec.c:
+	* tests/check/elements/cmmlenc.c:
+	* tests/check/elements/level.c:
+	* tests/check/elements/matroskamux.c:
+	* tests/check/elements/rganalysis.c:
+	* tests/check/elements/rglimiter.c:
+	* tests/check/elements/rgvolume.c:
+	* tests/check/elements/spectrum.c:
+	* tests/check/elements/videofilter.c:
+	  check: Don't re-declare 'GList *buffers' in the tests
+	  It's an external which lives in gstcheck.c. Redeclaring it makes some
+	  compilers/architectures think the 'buffers' in the individual tests are
+	  a different symbol... and therefore we end up comparing holodecks with
+	  oranges.
+
+2010-04-12 14:50:46 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/qtdemux/qtdemux.c:
+	  matroskademux, qtdemux: minor code cleanup in avc_level_idc_to_string()
+	  Do the same with slightly fewer LOC.
+
+2010-04-12 12:40:11 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* configure.ac:
+	  configure: Remove -Wundef flag
+	  Fixes #615161
+
+2010-04-12 11:43:49 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Fix I420->AYUV copying
+
+2010-04-12 11:25:59 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Correctly clamp frame/background alphas to [0,255] before writing them
+
+2010-04-12 11:16:56 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* tests/check/elements/.gitignore:
+	  check: Ignore jpegenc test
+
+2010-04-11 13:14:30 -0700  David Schleef <ds@schleef.org>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  deinterlace: Only check interlaced flag in sink caps
+	  Fixes #615460.
+
+2010-04-09 11:21:47 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From ba33d1f to fc85867
+
+2010-04-08 18:05:46 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	  docs: do proper escaping for "%"
+
+2010-04-08 17:50:49 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtsp/gstrtspgoogle.c:
+	* gst/rtsp/gstrtspgoogle.h:
+	  rtsp: remove obsolete google extension
+	  This was not build for a while and can be removed.
+
+2010-04-08 17:42:52 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  docs: move two symbols to private section
+
+2010-04-08 17:36:30 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  docs: add flxdec docs
+
+2010-04-08 17:17:06 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	  docs: enable the 2 of 65 rtp elements in the docs
+
+2010-04-08 11:54:19 +0200  Benjamin Otte <otte@redhat.com>
+
+	* ext/shout2/gstshout2.c:
+	  shout2: Don't wait if we're late
+	  In fact, due to signedness issues, a negative delay would be changed to
+	  an almost infinite wait causing shout2send to "lock up".
+	  Reported by Christopher Montgomery.
+
+2010-04-08 16:56:37 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/udp/gstmultiudpsink.c:
+	  docs: upd -> udp and voila it shows up in the docs
+
+2010-04-08 16:51:27 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/alpha/gstalpha.h:
+	  docs: fix doc blob syntax
+
+2010-04-08 16:51:05 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  docs: add (sparse) docs for auparse element
+
+2010-04-08 14:40:43 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  docs: add videobox symbols
+
+2010-04-08 14:40:19 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/Makefile.am:
+	  docs: remove dynudpsink until someone documents it
+
+2010-04-08 14:34:59 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: make debug category static
+
+2010-04-08 14:29:19 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	  flxdemux: rename GstFLVDemux for GstFlvDemux
+
+2010-04-08 14:23:19 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* gst/flv/Makefile.am:
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	* gst/flv/gstflvparse.c:
+	* gst/flv/gstflvparse.h:
+	  flvdemux: merge flvparse into the demuxer and make function static
+	  No need to hide certain function in the docs. Allows to do more cleanups.
+
+2010-04-08 13:13:34 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalpha.h:
+	  alpha: Add documentation
+
+2010-04-08 14:00:08 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  docs: v4l2buffer pool is now a separate object, remove them from v4l2src docs
+
+2010-04-08 13:58:11 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  docs: remove non existing flags and add two internal methods
+	  If someone cares flvparse could be merged into flvdemux.
+
+2010-04-08 13:57:09 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtpmanager/gstrtpsession.h:
+	  rtpsession: remove prototype for non existing function
+	  There is no function by that name anywhere.
+
+2010-04-08 12:56:50 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* 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:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	  docs: Update inspected plugin information
+
+2010-04-08 12:56:30 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	  alphacolor: Improve docs a bit
+
+2010-04-08 13:47:42 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  docs: add effecttv defines and reorder list
+
+2010-04-08 13:41:47 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  docs: remove three entries that are not exported from the headers anymore
+
+2010-04-08 13:40:36 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: move macro to c source
+	  One less semi public symbol without namespace prefix in the headers.
+
+2010-04-08 13:40:09 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/speex/gstspeexenc.h:
+	  speexenc: remove unused defines
+
+2010-04-08 13:23:38 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/matroska/matroska-mux.c:
+	  matroska-mux: fix last commit
+	  Use a local define for WAVEFORMAT_EX based on the size of the struct + 2 bytes
+	  for the extension size.
+
+2010-04-08 13:16:53 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/speex/gstspeexdec.h:
+	  speex: remove unused define
+
+2010-04-08 13:03:43 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/wavenc/Makefile.am:
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavenc/riff.h:
+	  wavenc: remove internal copy of riff.h and use riff-library instead.
+	  We don't use any function yet, just the structures and defines.
+
+2010-04-08 12:56:09 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: use riff lib more
+	  Remove BITMAPINFOHEADER and use the one from riff-lib. Also remove the
+	  WAVEFORMATEX_SIZE define and use a sizeof together with the respective struct.
+	  Besides better code reuse this lessens the ununsed symbols in the docs.
+
+2010-04-08 12:14:07 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  docs: trim sections file more
+	  Rename some defines and move some itesm to *.c files. Add more items to internal
+	  subsection.
+
+2010-04-08 11:19:43 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  docsw: trim the section file
+
+2010-04-08 10:26:25 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  docs: add v4l2sink to docs
+
+2010-04-08 10:15:08 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/audiofx/audioamplify.c:
+	* gst/multifile/gstmultifilesink.c:
+	  docs: fix xml
+	  The title tag belongs into the refsect2.
+
+2010-04-07 17:43:56 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Add support for YV12, including conversion support for I420/AYUV
+
+2010-04-07 17:27:12 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Add support for grayscale input/output
+	  This doesn't do any conversion and is the next step to
+	  replacing videocrop by supporting all remaining formats
+	  in passthrough mode.
+
+2010-04-07 16:24:38 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	* gst/videobox/gstvideobox.h:
+	  videobox: Add support for filling the background with red, yellow and white
+
+2010-04-07 16:11:11 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Add support for direct RGB<->AYUV conversion
+
+2010-04-07 16:11:01 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Fix RGB24 filling
+
+2010-04-07 16:06:54 +0300  Marco Ballesio <marco.ballesio@nokia.com>
+
+	* gst/rtp/gstrtph264depay.c:
+	  h264depay: handle properly STAPs
+	  in rtph264depay.c, lines 577-576, NALU-type 24 (Single-Time Aggregation
+	  Packet) is handled in fall-through as NALU-type 26 (unhandled).
+	  This leads high quality h264 streams such as:
+	  rtsp://stream.yle.mobi/yle/areena/MEDIA_E0342657_p3.mp4
+	  to fail with "NAL unit type 24 not supported yet" (but it's actually
+	  supported), and thus to close any stream which contains STAPs.
+	  The proposed one-liner patch fixes the issue.
+	  Fixes #615051.
+
+2010-04-07 13:47:02 +0200  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst-libs/gst/gst-i18n-plugin.h:
+	* gst/avi/gstavi.c:
+	  build: fix compiler warnings
+	  fix warnings for all plugins that use: setlocale (LC_ALL...
+
+2010-04-07 13:31:13 +0200  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/avi/gstavi.c:
+	  avi: fix compiler warning
+
+2010-03-31 17:54:21 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: restrict resyncing to subtitle tracks
+	  This should prevent skipping audio or video in not so well interleaved
+	  cases.
+	  Fixes #614460.
+
+2010-04-06 13:21:51 +0530  Arun Raghavan <ford_prefect@gentoo.org>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	  qtdemux: Post avg./max. bitrate tags for H.264
+	  This reads the average and maximum bitrates from the 'btrt' atom if
+	  available, and pushes these as tags,
+	  https://bugzilla.gnome.org/show_bug.cgi?id=614927
+
+2010-04-03 23:39:20 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: fix racy shutdown
+	  Keep a ref of pulsesink for deferred mainloop invocation. Fixes #614765
+
+2010-04-05 15:48:17 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/jpegenc.c:
+	  tests: jpegenc: Adds some getcaps test
+	  Adds tests for the jpegenc getcaps function, to avoid
+	  having it returning non-subset caps
+
+2010-04-05 14:51:58 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: Fix getcaps function
+	  When creating the caps allowed to upstream using downstream
+	  restrictions, use gst_pad_get_allowed_caps as that has the
+	  usable formats and puts into it the width, height and framerate
+	  fields. This avoids getting errors about getcaps returning
+	  non subset caps of its pad template.
+	  This error showed up on the metadata plugin unit test in -bad.
+
+2010-04-05 17:31:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Fix conversion from 3 byte RGB to ARGB
+
+2010-04-05 17:08:15 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Add support for 3 byte RGB formats and refactor RGB code a bit
+
+2010-04-05 15:51:13 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	* gst/videobox/gstvideobox.h:
+	  videobox: Add support for all 32 bit RGB formats
+	  ...including conversion between them.
+
+2010-04-05 15:26:03 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: add property to control the buffering method
+	  Add a property to control how the jitterbuffer performs timestamping and
+	  buffering.
+
+2010-04-04 19:02:41 -0300  André Dieb Martins <andre.dieb@gmail.com>
+
+	* gst/alpha/gstalphacolor.c:
+	  alphacolor: Removing unused variable
+	  Fixes bug #614843.
+
+2010-04-04 20:31:38 -0300  André Dieb Martins <andre.dieb@gmail.com>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: should not return caps ANY based on downstream
+	  When downstream has a sink pad with ANY caps, jpegenc should
+	  treat it the same as NULL and return its template caps.
+	  Fixes #614842
+
+2010-04-04 22:28:33 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/oss/gstosshelper.c:
+	  oss: add fixme comment
+
+2010-04-04 22:26:59 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gconf/Makefile.am:
+	  build: use $(builddir) for installing generated files
+
+2010-04-04 22:07:33 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* configure.ac:
+	  Revert "configure: fix out of source dir builds"
+	  This reverts commit ca0bd3a8cea31f9ea0df798a83d3007e696958ba.
+
+2010-04-04 21:36:35 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* configure.ac:
+	  configure: fix out of source dir builds
+	  Remove non-existing gst-libs from include and library-paths'.
+	  Fixes #614354 even more.
+
+2010-04-01 10:19:00 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	  qtdemux: Read replaygain peak/gain tags
+	  Make qtdemux read tags replaygain tags that are within '----' atoms.
+	  Fixes #614471
+
+2010-04-01 18:48:43 +0530  Arun Raghavan <ford_prefect@gentoo.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/qtdemux/qtdemux.c:
+	  matroska: Export h.264 profile and level in caps
+	  This replicates the code in qtdemux to export the h.264 profile and
+	  level in the stream caps.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=614651
+
+2010-04-02 18:50:45 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix off-by-one introduced in last commit
+
+2010-04-01 18:38:38 +0530  Arun Raghavan <ford_prefect@gentoo.org>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Minor refactor of the code
+	  This will make it easier to clump together common code when copying to
+	  mastroskademux.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=614651
+
+2010-04-01 18:17:09 +0530  Arun Raghavan <ford_prefect@gentoo.org>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Export h.264 level in caps
+	  This exports the h.264 level in the stream caps (as a string) which can
+	  be used to match a decoder, or as metadata.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=614651
+
+2010-04-01 16:58:32 +0530  Arun Raghavan <ford_prefect@gentoo.org>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Export h.264 profile in caps
+	  This adds the h.264 profile for a given stream into caps. This can
+	  (eventually) be used to select an appropriate decoder and as metadata
+	  for certain applications.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=614651
+
+2010-03-31 14:43:14 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: remove obsolete reverse playback code path
+
+2010-03-31 14:40:50 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	* gst/flv/gstflvparse.c:
+	  flvdemux: support (pull mode) negative seek rate
+
+2010-03-29 15:27:37 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: also check for segment stop for non-segment-seek
+
+2010-03-30 16:50:10 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: push correctly sized flac header buffers
+	  Fixes #614353.
+
+2010-03-30 07:34:07 -0500  Rob Clark <rob@ti.com>
+
+	* configure.ac:
+	  build: fix compiler warning when srcdir != builddir
+	  Fixes '../../gst-libs: No such file or directory' warning/error when
+	  the build directory is not the same as the source directory.
+	  Fixes #614354.
+
+2010-03-30 01:50:32 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/id3demux/id3v2frames.c:
+	  id3demux: fix parsing of unsynced frames with data length indicator
+	  Fixes bug #614158.
+
+2010-03-29 11:00:04 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	* ext/Makefile.am:
+	* gst/Makefile.am:
+	* sys/Makefile.am:
+	* tests/examples/Makefile.am:
+	  build: build plugins and examples in parallel where possible
+
+2010-03-18 18:49:24 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: fix redundant function redeclaration compiler warnings
+	  Re-apply this again as well, as it was undone by the previous commit..
+
+2010-03-18 14:31:35 +0100  Benjamin Otte <otte@redhat.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  gst_element_class_set_details => gst_element_class_set_details_simple
+	  Apply this again, as it was overwritten by the previous commit. Merging
+	  is hard, apparently.
+
+2010-03-26 23:20:10 +0100  Julien Moutte <julien@fluendo.com>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/directsound/gstdirectsoundsink.h:
+	  directsoundsink: Implement SPDIF support for AC3.
+	  Detect if the sound card supports SPDIF passthru of AC3 and add
+	  necessary code to support that like alsasink.
+
+2010-03-26 17:06:57 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* Makefile.am:
+	  build: add cruft alert for common/shave*
+
+2010-03-26 16:50:22 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/Makefile.am:
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_lang.c:
+	* gst/qtdemux/qtdemux_lang.h:
+	  qtdemux: extract stream language in more cases
+	  The 16-bit language code can be either a packed ISO-639-2T code
+	  or a 'Macintosh language code'. Handle the latter type of language
+	  codes as well, and map to the matching ISO code. Lastly, fix
+	  language code posting for language #0, which is valid and stands
+	  for 'English'.
+	  Fixes #614001.
+
+2010-03-26 14:55:53 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: Improve debugging and add some FIXMEs
+
+2010-03-26 14:42:06 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: Sample rate markers 0x01, 0x02 and 0x03 are valid
+	  They are for 88.2kHz, 176.4kHz and 192kHz.
+
+2010-03-26 14:16:39 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: Take samplerate, width and number of channels from the STREAMINFO
+	  ...and update it from the frame headers if it should change for some reason.
+	  This allows playback of files with odd sample rates.
+
+2010-03-26 13:45:46 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Fix AYUV->I420 frame copying
+
+2010-03-26 13:34:17 +0100  Raimo Järvi <raimo.jarvi@gmail.com>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: Set correct getcaps/setcaps functions on srcpads and simplify them
+	  This fixes downstream negotiation, upstream negotiation isn't really
+	  supported by jpegenc yet.
+	  Fixes bug #613789.
+
+2010-03-26 10:31:22 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	* gst/videobox/gstvideobox.h:
+	  videobox: Always fill the complete frame if borders should be added
+	  This makes sure that we don't get any gaps between rectangles because
+	  of chroma subsampling for example.
+
+2010-03-18 22:12:40 +0000  Damien Lespiau <damien.lespiau@intel.com>
+
+	* autogen.sh:
+	  autogen.sh: Don't call configure with --enable-plugin-docs
+	  configure gives a nice warning:
+	  configure: WARNING: unrecognized options: --enable-plugin-docs
+	  and indeed, I could not find anything in the configure.ac or the m4
+	  macros that would allow enabling that option. Remove it then.
+
+2010-03-22 16:58:26 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	* gst/videobox/gstvideobox.h:
+	  videobox: Refactor boxing to reduce code duplication
+
+2010-03-22 13:13:59 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Simplify caps transformation
+
+2010-03-21 20:14:19 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Add const qualifier to the source frame data
+
+2010-03-23 17:47:48 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: only seek when in proper state
+	  ... and data structures can be thread-safely accessed.
+	  See #601617.
+
+2010-03-23 17:34:50 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	* gst/matroska/matroska-ids.h:
+	  matroskademux: support (pull mode) negative seek rate
+
+2010-03-18 15:29:00 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: track clip duration in segment
+
+2010-03-18 13:39:05 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: prefer index of video track to perform seeking
+
+2010-03-25 22:58:47 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/dtmf/gstdtmfdetect.c:
+	  dtmfdetect: if we tell that we handle gap flags, then do so
+
+2010-03-25 22:55:32 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/dtmf/gstdtmfdetect.c:
+	  dtmfdetect: use glib types
+
+2010-03-25 22:54:49 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/dtmf/gstdtmfdetect.c:
+	  dtmfdetect: fix classification
+
+2010-03-25 22:53:20 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/dtmf/gstdtmfdetect.c:
+	  dtmfdetect: reformat message docs
+	  Use a list like in other element docs as an untweaked docbook table look ugly.
+
+2010-03-24 16:19:53 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix typo in header validation check
+
+2010-03-24 18:53:20 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From 55cd514 to c1d07dd
+
+2010-03-23 19:46:43 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/icydemux/gsticydemux.c:
+	* gst/icydemux/gsticydemux.h:
+	  icydemux: Handle upstream Content-Type.
+	  Allows us to handle ShoutCast TV (NSV) streams.
+	  If the upstream caps have the 'content-type' field set to video/nsv, then
+	  we shortcut the typefinding and set video/x-nsv directly.
+
+2010-03-23 19:30:50 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Set the Content-Type HTTP header on the caps.
+	  First step to fixing ShoutCast (NSV) streaming.
+
+2010-03-23 02:38:43 -0400  Tristan Matthews <tristan@sat.qc.ca>
+
+	* sys/osxaudio/gstosxaudioelement.c:
+	* sys/osxvideo/Makefile.am:
+	  osx: fix compiler warnings
+	  Added void parameter to avoid old-style definition warning.
+	  Added -Wno-aggregate-return flag to avoid erroneous aggregate return warning.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=613663
+
+2010-03-23 00:15:15 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/videocrop.c:
+	  tests: use loop test for long-running videocrop check
+	  This should avoid timeouts on slow machines.
+	  Fixes #597739.
+
+2010-03-22 17:26:37 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/flac/gstflac.c:
+	* ext/pulse/plugin.c:
+	* ext/wavpack/gstwavpack.c:
+	* gst-libs/gst/gettext.h:
+	* gst/multifile/gstmultifilesink.h:
+	  i18n: build fixes: #if -> #ifdef for ENABLE_NLS
+
+2010-03-22 17:25:09 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst-libs/gst/gst-i18n-plugin.h:
+	  i18n: fix the build
+	  Don't inlcude locale.h which we include in gettext.h if needed. Guard the
+	  inlcude like we do in the simillar headers in core.
+
+2010-03-22 13:16:33 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  Add -Wwrite-strings
+	  and fix its warnings
+
+2010-03-22 12:02:16 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  Add -Wredundant-decls flag
+	  and fix warnings from it
+
+2010-03-21 21:39:18 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/dtmf/gstrtpdtmfdepay.h:
+	  Add -Wmissing-declarations -Wmissing-prototypes to configure flags
+	  And fix all warnings
+
+2010-03-21 17:46:06 +0100  Benjamin Otte <otte@redhat.com>
+
+	* configure.ac:
+	  -Wold-style-definition is not valid for C++
+
+2010-03-21 17:36:28 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/multifile/gstmultifile.c:
+	  multifile: Include headers instead fo defining functions
+
+2010-03-21 17:24:14 +0100  Benjamin Otte <otte@redhat.com>
+
+	* configure.ac:
+	  Add a large set of warning flags.
+	  None of them trigger warnings anymore, so nothing needed to be fixed.
+
+2010-03-21 17:23:43 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/goom/config_param.c:
+	* gst/goom/convolve_fx.c:
+	* gst/goom/filters.c:
+	* gst/goom/flying_stars_fx.c:
+	* gst/goom/goom_config_param.h:
+	* gst/goom/goom_core.c:
+	* gst/goom/goom_filters.h:
+	* gst/goom/goom_fx.h:
+	* gst/goom/ifs.c:
+	* gst/goom/ifs.h:
+	* gst/goom/plugin_info.c:
+	* gst/goom/tentacle3d.c:
+	* gst/goom/tentacle3d.h:
+	  Make goom not use aggregate returns
+
+2010-03-21 15:17:46 +0100  Benjamin Otte <otte@redhat.com>
+
+	* configure.ac:
+	* ext/annodex/gstcmmlutils.c:
+	* ext/wavpack/gstwavpackparse.c:
+	* gst/effectv/gstwarp.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/udp/gstmultiudpsink.c:
+	* tests/check/elements/cmmldec.c:
+	* tests/check/elements/cmmlenc.c:
+	* tests/check/elements/deinterlace.c:
+	* tests/check/elements/rglimiter.c:
+	* tests/check/elements/rtp-payloading.c:
+	* tests/check/elements/udpsink.c:
+	* tests/check/elements/videofilter.c:
+	* tests/check/elements/wavpackdec.c:
+	* tests/check/generic/states.c:
+	* tests/icles/v4l2src-test.c:
+	  Add -Wold-style-definition flag
+	  And fix the warnings
+
+2010-03-20 00:54:14 +0100  Benjamin Otte <otte@redhat.com>
+
+	* configure.ac:
+	* ext/hal/hal.c:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/wavpack/gstwavpackcommon.c:
+	* gst/avi/gstavimux.c:
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/flv/gstflvparse.c:
+	* gst/goom/config_param.c:
+	* gst/goom/goom_config_param.h:
+	* gst/id3demux/id3tags.c:
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/ebml-write.h:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/qtdemux/qtdemux.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	* gst/videofilter/gstvideobalance.c:
+	* sys/oss/gstossmixertrack.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2src.c:
+	* tests/check/elements/avimux.c:
+	* tests/check/elements/level.c:
+	* tests/check/elements/rtpbin_buffer_list.c:
+	* tests/check/pipelines/simple-launch-lines.c:
+	  Add -Wwrite-strings to the configure flags
+	  ... and fix all warnings
+
+2010-03-21 11:14:12 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  shapewipe: Add support for the remaining ARGB formats
+	  And handle AYUV like ARGB, we need no YUV specific handling.
+
+2010-03-20 21:30:58 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Add support for RGB and xRGB input
+
+2010-03-20 21:13:23 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Add support for ARGB input
+
+2010-03-20 20:46:19 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Add support for generating ARGB output
+
+2010-03-20 10:47:42 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend.c:
+	* gst/videomixer/blend.h:
+	* gst/videomixer/blend_mmx.h:
+	* gst/videomixer/videomixer.c:
+	  videomixer: Add support for ABGR and RGBA
+	  Now all 4 ARGB variants are supported by videomixer.
+
+2010-03-20 10:24:56 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Move chroma keying parameters into stack variables to prevent multiple pointer dereferences per pixel
+
+2010-03-20 10:20:53 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Move color conversion matrixes into stack variables to speed up processing
+
+2010-03-20 10:18:04 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Use correct matrixes to convert chroma keying color to YUV
+
+2010-03-19 18:51:59 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Add support for different color matrixes
+
+2010-03-19 18:21:19 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Rename and move functions as further preparation for supporting more color formats
+
+2010-03-19 18:18:08 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalpha.h:
+	  alpha: Remove some unneeded calculations and instance struct fields
+	  And document the instance struct fields a bit better
+
+2010-03-19 18:11:12 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalpha.h:
+	  alpha: Some preparations for supporting more color formats
+
+2010-03-19 17:09:06 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  h264pay: fix config-interval property
+	  Use the same units for comparing the elapsed time against the interval.
+	  Fixes #613013
+
+2010-03-19 16:44:00 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	* gst/alpha/gstalphacolor.h:
+	  alphacolor: Implement color-matrix support and use integer arithmetic only
+	  Alphacolor now uses the correct matrixes for SDTV and HDTV and can
+	  convert between them.
+
+2010-03-19 15:03:43 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* gst/rtsp/gstrtspsrc.c:
+	  rtsp: use GType from -base and bump required version
+	  Use the transport flags GType from -base and bump the required version of -base
+	  because of this.
+
+2010-03-19 00:05:19 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/apetag/Makefile.am:
+	  apetag: minor Makefile.am surgery
+	  -I$(top_srcdir)/gst-libs/ is already in $(GST_CFLAGS)
+
+2010-03-18 17:30:26 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/dtmf/gstdtmfdetect.c:
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  gst_element_class_set_details => gst_element_class_set_details_simple
+
+2010-03-04 22:12:35 +0100  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* ext/raw1394/gst1394clock.c:
+	  dv1394src: Fix internal clock
+	  Fixes #593910.
+
+2010-03-18 21:14:17 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/dv/Makefile.am:
+	* ext/esd/Makefile.am:
+	* ext/libcaca/Makefile.am:
+	* ext/pulse/Makefile.am:
+	* ext/shout2/Makefile.am:
+	* ext/speex/Makefile.am:
+	* ext/wavpack/Makefile.am:
+	* gst/auparse/Makefile.am:
+	* gst/avi/Makefile.am:
+	* gst/flx/Makefile.am:
+	* gst/icydemux/Makefile.am:
+	* gst/interleave/Makefile.am:
+	* gst/matroska/Makefile.am:
+	* gst/qtdemux/Makefile.am:
+	* gst/replaygain/Makefile.am:
+	* gst/rtp/Makefile.am:
+	* gst/udp/Makefile.am:
+	* gst/videomixer/Makefile.am:
+	* gst/wavparse/Makefile.am:
+	* sys/directsound/Makefile.am:
+	* sys/oss/Makefile.am:
+	* sys/waveform/Makefile.am:
+	* tests/examples/v4l2/Makefile.am:
+	  build: Makefile.am cleanups
+	  Mostly add $(GST_BASE_CFLAGS) where it was missing, but also fix up
+	  order of flags and libs if needed (see docs/random/moving-plugins).
+
+2010-03-18 18:49:24 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/directsound/gstdirectsoundsink.c:
+	  directsoundsink: fix redundant function redeclaration compiler warnings
+
+2010-03-18 19:00:09 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalpha.h:
+	  alpha: Remove remaining floating point arithmetic when processing a pixel
+
+2010-03-18 18:55:34 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Refactor chroma keying into a single function
+	  This reduces code duplication once we add support for more color formats.
+
+2010-03-18 14:31:35 +0100  Benjamin Otte <otte@redhat.com>
+
+	* ext/aalib/gstaasink.c:
+	* ext/annodex/gstcmmldec.c:
+	* ext/annodex/gstcmmlenc.c:
+	* ext/cairo/gsttextoverlay.c:
+	* ext/cairo/gsttimeoverlay.c:
+	* ext/dv/gstdvdec.c:
+	* ext/dv/gstdvdemux.c:
+	* ext/esd/esdmon.c:
+	* ext/esd/esdsink.c:
+	* ext/gconf/gstgconfaudiosink.c:
+	* ext/gconf/gstgconfaudiosrc.c:
+	* ext/gconf/gstgconfvideosink.c:
+	* ext/gconf/gstgconfvideosrc.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/gdk_pixbuf/pixbufscale.c:
+	* ext/hal/gsthalaudiosink.c:
+	* ext/hal/gsthalaudiosrc.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstsmokedec.c:
+	* ext/jpeg/gstsmokeenc.c:
+	* ext/libcaca/gstcacasink.c:
+	* ext/libmng/gstmng.h:
+	* ext/libmng/gstmngdec.c:
+	* ext/libmng/gstmngenc.c:
+	* ext/libpng/gstpng.h:
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngenc.c:
+	* ext/mikmod/gstmikmod.c:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	* ext/shout2/gstshout2.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	* gst/apetag/gstapedemux.c:
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audioinvert.c:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/audiofx/audiopanorama.c:
+	* gst/auparse/gstauparse.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavimux.c:
+	* gst/cutter/gstcutter.c:
+	* gst/debugutils/breakmydata.c:
+	* gst/debugutils/efence.c:
+	* gst/debugutils/gstnavigationtest.c:
+	* gst/debugutils/gstnavseek.c:
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/debugutils/negotiation.c:
+	* gst/debugutils/progressreport.c:
+	* gst/debugutils/testplugin.c:
+	* gst/flx/gstflxdec.c:
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/id3demux/gstid3demux.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/level/gstlevel.c:
+	* gst/median/gstmedian.c:
+	* gst/monoscope/gstmonoscope.c:
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartmux.c:
+	* gst/qtdemux/gstrtpxqtdepay.c:
+	* gst/qtdemux/qtdemux.c:
+	* gst/replaygain/gstrganalysis.c:
+	* gst/replaygain/gstrglimiter.c:
+	* gst/replaygain/gstrgvolume.c:
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpdepay.c:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpg723depay.c:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtppcmupay.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpsirenpay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtsp/gstrtpdec.c:
+	* gst/rtsp/gstrtspgoogle.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/smpte/gstsmpte.c:
+	* gst/smpte/gstsmptealpha.c:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videofilter/gstvideotemplate.c:
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavparse/gstwavparse.c:
+	* gst/y4m/gsty4mencode.c:
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/oss/gstossmixerelement.c:
+	* sys/oss/gstosssink.c:
+	* sys/oss/gstosssrc.c:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxvideo/osxvideosink.m:
+	* sys/sunaudio/gstsunaudiomixer.c:
+	* sys/sunaudio/gstsunaudiosink.c:
+	* sys/sunaudio/gstsunaudiosrc.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/waveform/gstwaveformsink.c:
+	* sys/ximage/gstximagesrc.c:
+	  gst_element_class_set_details => gst_element_class_set_details_simple
+
+2010-03-18 14:02:30 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/oldcore/Makefile.am:
+	* gst/oldcore/gstaggregator.c:
+	* gst/oldcore/gstaggregator.h:
+	* gst/oldcore/gstelements.c:
+	* gst/oldcore/gstfdsink.c:
+	* gst/oldcore/gstfdsink.h:
+	* gst/oldcore/gstmd5sink.c:
+	* gst/oldcore/gstmd5sink.h:
+	* gst/oldcore/gstmultifilesrc.c:
+	* gst/oldcore/gstmultifilesrc.h:
+	* gst/oldcore/gstpipefilter.c:
+	* gst/oldcore/gstpipefilter.h:
+	* gst/oldcore/gstshaper.c:
+	* gst/oldcore/gstshaper.h:
+	* gst/oldcore/gststatistics.c:
+	* gst/oldcore/gststatistics.h:
+	  Remove oldcore directory
+	  The elements have been unused for ages and all important ones have been
+	  replaced or copied elsewhere.
+
+2010-03-18 13:45:08 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/avi/gstavidecoder.c:
+	  avi: Remove old file
+	  Seems to be leftover from the 0.4 days or so.
+
+2010-03-18 12:44:53 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulseutil.c:
+	  pulse: use #ifdef rather than #if conditionals
+
+2010-03-18 12:20:17 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: do not call _push_ts with unneeded (and wrong) time parameter
+	  Fixes #613206.
+
+2010-03-18 11:33:59 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix typo in header validation check
+
+2010-03-18 01:51:19 +0100  Jan Urbański <wulczer@wulczer.org>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: put more information in the metadata
+	  Additional tags are: audiocodecid, videocodecid framerate and (in the
+	  non-live case) filesize.
+	  While at it, fix index rewriting to update duration and filesize
+	  values even if the index is empty.
+	  Fixes #613094.
+
+2010-03-17 21:33:28 +0100  Benjamin Otte <otte@redhat.com>
+
+	* configure.ac:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/speex/gstspeexenc.h:
+	* gst/goom/goom_config.h:
+	* gst/goom/mathtools.h:
+	* tests/check/elements/level.c:
+	  Add -Wundef to configure flags
+	  and fix the resulting warnings
+
+2010-03-17 20:02:16 +0100  Benjamin Otte <otte@redhat.com>
+
+	* configure.ac:
+	  -Wmissing-prototypes is not valid for C++
+
+2010-03-17 19:35:10 +0100  Benjamin Otte <otte@redhat.com>
+
+	* configure.ac:
+	* ext/flac/gstflacdec.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/gdk_pixbuf/pixbufscale.c:
+	* ext/jpeg/gstjpeg.h:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/wavpack/gstwavpackdec.c:
+	* gst/deinterlace/tvtime/greedyh.c:
+	* gst/deinterlace/tvtime/tomsmocomp.c:
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/replaygain/gstrganalysis.c:
+	* gst/replaygain/gstrglimiter.c:
+	* gst/replaygain/gstrgvolume.c:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/videomixer/videomixer.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  Add -Wredundant-decls warning flag
+	  Also fix compile issues
+
+2010-03-17 18:49:11 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/monoscope/gstmonoscope.h:
+	  Fix warnings in experimental plugins, too
+
+2010-03-17 18:23:00 +0100  Benjamin Otte <otte@redhat.com>
+
+	* configure.ac:
+	* ext/annodex/gstannodex.c:
+	* ext/annodex/gstcmmldec.h:
+	* ext/annodex/gstcmmlenc.h:
+	* ext/annodex/gstcmmlparser.c:
+	* ext/annodex/gstcmmlutils.c:
+	* ext/dv/gstdvdec.c:
+	* ext/flac/gstflacenc.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/gdk_pixbuf/pixbufscale.h:
+	* ext/jpeg/Makefile.am:
+	* ext/jpeg/gstjpeg.c:
+	* ext/jpeg/gstjpeg.h:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/wavpack/gstwavpackstreamreader.c:
+	* ext/wavpack/gstwavpackstreamreader.h:
+	* gst/debugutils/breakmydata.c:
+	* gst/debugutils/gstnavseek.c:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/debugutils/testplugin.c:
+	* gst/deinterlace/tvtime/greedyh.asm:
+	* gst/deinterlace/tvtime/greedyh.c:
+	* gst/deinterlace/tvtime/mmx.h:
+	* gst/deinterlace/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	* gst/goom/goom_fx.h:
+	* gst/goom2k1/filters.c:
+	* gst/goom2k1/filters.h:
+	* gst/law/mulaw-conversion.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/multipart/multipart.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartdemux.h:
+	* gst/multipart/multipartmux.c:
+	* gst/multipart/multipartmux.h:
+	* gst/qtdemux/gstrtpxqtdepay.c:
+	* gst/rtp/fnv1hash.c:
+	* gst/rtp/fnv1hash.h:
+	* gst/rtp/gstasteriskh263.h:
+	* gst/rtp/gstrtpL16depay.h:
+	* gst/rtp/gstrtpL16pay.h:
+	* gst/rtp/gstrtpac3depay.h:
+	* gst/rtp/gstrtpamrdepay.h:
+	* gst/rtp/gstrtpamrpay.h:
+	* gst/rtp/gstrtpbvdepay.h:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpbvpay.h:
+	* gst/rtp/gstrtpceltdepay.h:
+	* gst/rtp/gstrtpceltpay.h:
+	* gst/rtp/gstrtpdvdepay.h:
+	* gst/rtp/gstrtpdvpay.h:
+	* gst/rtp/gstrtpg723depay.h:
+	* gst/rtp/gstrtpg723pay.h:
+	* gst/rtp/gstrtpg726depay.h:
+	* gst/rtp/gstrtpg726pay.h:
+	* gst/rtp/gstrtpg729depay.h:
+	* gst/rtp/gstrtpg729pay.h:
+	* gst/rtp/gstrtpgsmdepay.h:
+	* gst/rtp/gstrtpgsmpay.h:
+	* gst/rtp/gstrtph263depay.h:
+	* gst/rtp/gstrtph263pay.h:
+	* gst/rtp/gstrtph263pdepay.h:
+	* gst/rtp/gstrtph263ppay.h:
+	* gst/rtp/gstrtph264depay.h:
+	* gst/rtp/gstrtph264pay.h:
+	* gst/rtp/gstrtpilbcdepay.h:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpilbcpay.h:
+	* gst/rtp/gstrtpj2kdepay.h:
+	* gst/rtp/gstrtpj2kpay.h:
+	* gst/rtp/gstrtpjpegdepay.h:
+	* gst/rtp/gstrtpjpegpay.h:
+	* gst/rtp/gstrtpmp1sdepay.h:
+	* gst/rtp/gstrtpmp2tdepay.h:
+	* gst/rtp/gstrtpmp2tpay.h:
+	* gst/rtp/gstrtpmp4adepay.h:
+	* gst/rtp/gstrtpmp4apay.h:
+	* gst/rtp/gstrtpmp4gdepay.h:
+	* gst/rtp/gstrtpmp4gpay.h:
+	* gst/rtp/gstrtpmp4vdepay.h:
+	* gst/rtp/gstrtpmp4vpay.h:
+	* gst/rtp/gstrtpmpadepay.h:
+	* gst/rtp/gstrtpmpapay.h:
+	* gst/rtp/gstrtpmpvdepay.h:
+	* gst/rtp/gstrtpmpvpay.h:
+	* gst/rtp/gstrtppcmadepay.h:
+	* gst/rtp/gstrtppcmapay.h:
+	* gst/rtp/gstrtppcmudepay.h:
+	* gst/rtp/gstrtppcmupay.h:
+	* gst/rtp/gstrtpqdmdepay.h:
+	* gst/rtp/gstrtpsirendepay.h:
+	* gst/rtp/gstrtpsirenpay.c:
+	* gst/rtp/gstrtpsirenpay.h:
+	* gst/rtp/gstrtpspeexdepay.h:
+	* gst/rtp/gstrtpspeexpay.h:
+	* gst/rtp/gstrtpsv3vdepay.h:
+	* gst/rtp/gstrtptheoradepay.h:
+	* gst/rtp/gstrtptheorapay.h:
+	* gst/rtp/gstrtpvorbisdepay.h:
+	* gst/rtp/gstrtpvorbispay.h:
+	* gst/rtp/gstrtpvrawdepay.h:
+	* gst/rtp/gstrtpvrawpay.h:
+	* gst/rtsp/gstrtpdec.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/smpte/gstmask.c:
+	* gst/smpte/gstmask.h:
+	* gst/videobox/gstvideobox.h:
+	* gst/videocrop/gstvideocrop.h:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer.h:
+	* gst/wavenc/gstwavenc.h:
+	* sys/v4l2/gstv4l2colorbalance.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2tuner.h:
+	* sys/v4l2/gstv4l2vidorient.h:
+	* sys/ximage/ximageutil.c:
+	* tests/check/elements/aspectratiocrop.c:
+	* tests/check/elements/audioamplify.c:
+	* tests/check/elements/audiochebband.c:
+	* tests/check/elements/audiocheblimit.c:
+	* tests/check/elements/audiodynamic.c:
+	* tests/check/elements/audioecho.c:
+	* tests/check/elements/audioinvert.c:
+	* tests/check/elements/audiopanorama.c:
+	* tests/check/elements/audiowsincband.c:
+	* tests/check/elements/audiowsinclimit.c:
+	* tests/check/elements/avimux.c:
+	* tests/check/elements/avisubtitle.c:
+	* tests/check/elements/cmmldec.c:
+	* tests/check/elements/equalizer.c:
+	* tests/check/elements/level.c:
+	* tests/check/elements/matroskamux.c:
+	* tests/check/elements/multifile.c:
+	* tests/check/elements/rganalysis.c:
+	* tests/check/elements/rglimiter.c:
+	* tests/check/elements/rgvolume.c:
+	* tests/check/elements/shapewipe.c:
+	* tests/check/elements/souphttpsrc.c:
+	* tests/check/elements/spectrum.c:
+	* tests/check/elements/videofilter.c:
+	* tests/check/elements/wavpackdec.c:
+	* tests/check/elements/wavpackenc.c:
+	* tests/check/elements/wavpackparse.c:
+	* tests/check/elements/y4menc.c:
+	* tests/check/generic/states.c:
+	* tests/check/pipelines/simple-launch-lines.c:
+	* tests/check/pipelines/wavpack.c:
+	* tests/examples/equalizer/demo.c:
+	* tests/examples/level/level-example.c:
+	* tests/examples/spectrum/spectrum-example.c:
+	* tests/icles/v4l2src-test.c:
+	  Add -Wmissing-declarations -Wmissing-prototypes warning flags
+	  And fix all the warnings.
+
+2010-03-17 16:23:24 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4gdepay.c:
+	  mp4gdepay: improve constantDuration guessing
+	  When no constantDuration has been given in the caps, try to derive one from the
+	  timestamp difference between packets. Also keep doing this for each packet
+	  because some broken streams might simply provide wrong timestamps.
+
+2010-03-16 23:43:39 +0100  Jan Urbański <wulczer@wulczer.org>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Put width and height in the metadata
+	  Some players use that info to scale their display.
+	  See #613094.
+
+2010-03-16 23:32:45 +0100  Jan Urbański <wulczer@wulczer.org>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: don't put timestamps larger than G_MAXINT32 in the FLV tags
+	  For non-live input respond by pushing EOS, for live wrap the
+	  timestamps every G_MAXINT32 miliseconds.
+	  Fixes #613003.
+
+2010-03-16 23:40:12 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  soup: also use g_value_set_static_string() here for static strings
+
+2010-03-16 21:23:11 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	  alphacolor: Fix RGBA<->AYUV conversion
+
+2010-03-16 21:16:26 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalpha.h:
+	  alpha: Remove redundant instance field
+
+2010-03-16 21:10:08 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: Protect property values from changes during frame processing
+
+2010-03-15 23:29:55 +0300  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* ext/libpng/gstpngdec.c:
+	  pngenc: Use png_get_io_ptr() instead of accessing io_ptr directly
+	  Fixes #612700 (for the last time!)
+
+2010-03-15 23:29:06 +0300  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* configure.ac:
+	  png: Check for libpng >= 1.2 instead of libpng12
+
+2010-03-16 01:29:36 +0100  Jan Urbański <wulczer@wulczer.org>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  flvmux: Always put a duration tag in the metadata
+	  Some Flash players (for instance JW Player) always expect a duration
+	  tag, otherwise they don't start playback.
+	  If duration can be queried from the sink pads or is provided as a tag,
+	  use it. Otherwise try to determine it from the last seen timestamp of
+	  the sink pads after EOS and rewrite it in the header before writing
+	  the index.
+
+2010-03-16 00:35:46 +0100  Jan Urbański <wulczer@wulczer.org>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  flvmux: Remove the send_codec_data field from GstFlvPad
+	  That field is not used anymore after the changes in
+	  9fdecbc1c11f4e5af6578bba32a9b32771029d33.
+
+2010-03-16 13:53:26 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: get family of external sockets too
+	  Get the family of externally configured sockets so that we can configure it
+	  correctly.
+
+2010-03-15 20:37:51 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	  alphacolor: Add support for the remaining ARGB formats
+
+2010-03-15 19:16:18 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	  alphacolor: Simplify ARGB<->AYUV conversions by code generation macros
+
+2010-03-15 19:07:28 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* gst/alpha/Makefile.am:
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalpha.h:
+	  alpha: Minor cleanups and move declarations into a separate header file
+
+2010-03-15 18:58:51 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/Makefile.am:
+	* gst/alpha/gstalpha.c:
+	  alpha: Use GstVideoFilter as base class for automatic QoS support
+
+2010-03-15 18:50:11 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	* gst/alpha/gstalphacolor.h:
+	  alphacolor: Add support for inplace conversions from AYUV to ARGB
+
+2010-03-15 18:14:19 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	* gst/alpha/gstalphacolor.h:
+	  alphacolor: Use libgstvideo for caps parsing
+
+2010-03-15 18:09:55 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/Makefile.am:
+	* gst/alpha/gstalphacolor.c:
+	* gst/alpha/gstalphacolor.h:
+	  alphacolor: Use GstVideoFilter as base class for automatic QoS support
+
+2010-03-15 18:07:29 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/alpha/gstalphacolor.c:
+	  alphacolor: Some minor cleanup
+
+2010-03-15 14:16:58 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexdec.h:
+	  speexdec: Use speex_stereo_state_init() instead of the deprecated initialization macro
+	  Fixes bug #612777.
+
+2010-03-15 01:09:49 +0100  Jan Urbański <wulczer@wulczer.org>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Correctly mark buffers as delta units
+	  Mark video interframes, video codec data buffers and audio buffers (if
+	  it's not an audio-only stream) as delta units.
+
+2010-03-14 19:32:20 +0100  Jan Urbański <wulczer@wulczer.org>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Support streamheaders
+	  Put the FLV header, the metadata tag and (if present) codec
+	  information in the streamheader to allow the muxer to be used for
+	  streaming.
+
+2010-03-14 01:38:21 +0100  Jan Urbański <wulczer@wulczer.org>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Preallocate index space and fill it after finishing output
+	  Make the index appear at the beginning of the file, which is what most
+	  players are expecting.
+	  Fixes #601236.
+
+2010-03-15 13:47:13 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Minor coding style fixes and cleanup
+
+2010-03-14 01:34:02 +0100  Jan Urbański <wulczer@wulczer.org>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  flvmux: Add a is-live property
+	  If it is set, the muxer will not write the index. Defaults to false.
+
+2010-03-14 01:25:42 +0100  Jan Urbański <wulczer@wulczer.org>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Only put valid seek points in the index
+	  For files containing video only video keyframes are valid points to
+	  which a player can seek. For audio-only files any tag start is a valid
+	  seek point.
+	  See #601236.
+
+2010-03-14 01:09:37 +0100  Jan Urbański <wulczer@wulczer.org>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Fix index building to make entries point to tag's start offset
+	  Previous coding was wrongly incrementing the total byte count before
+	  adding an index entry.
+
+2010-03-15 13:40:38 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/cairo/gsttextoverlay.c:
+	  cairotextoverlay: Don't render text outside the frame boundaries
+	  Fixes bug #611986.
+
+2010-03-15 11:38:23 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: don't forget to send keepalive messages
+	  When we operate in TCP mode, still send keepalive messages when we
+	  need to.
+	  Fixes #612696
+
+2010-03-13 23:19:35 +0300  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* ext/libpng/gstpngenc.c:
+	  pngenc: Call png_jmpbuf() instead of accessing png_struct_ptr directly
+	  Fixes #612700 (again)
+
+2010-03-12 16:44:30 +0300  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* ext/libpng/gstpngenc.c:
+	  pngenc: Call png_error() instead of using longjmp() directly.
+	  Fixes #612700
+
+2010-03-12 13:57:28 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From e272f71 to 55cd514
+
+2010-03-05 11:06:47 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	  qtdemux: add XMP parsing support
+	  Use xmp helpers to parse XMP metadata in udta atom.
+	  Fixes #609539
+
+2010-03-11 12:32:56 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/udp/gstmultiudpsink.h:
+	* gst/udp/gstudpnetutils.c:
+	* gst/udp/gstudpnetutils.h:
+	  udp: fix compilation errors on non-windows.
+
+2010-03-10 22:23:43 +0100  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	* gst/udp/gstudpnetutils.c:
+	* gst/udp/gstudpnetutils.h:
+	  multiudpsink: avoid getting the socket family using getsockname()
+
+2010-03-11 17:28:47 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix print statements for pointer differences.
+	  This fixes it for both 32 and 64 bit
+
+2010-03-11 17:28:35 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix unitialized variables
+
+2010-03-11 17:03:47 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Fix printf formatting for macosx
+
+2010-03-11 17:03:05 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Fix unitialized variables
+
+2010-03-11 17:02:44 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Fix unitialized variable.
+
+2010-02-19 13:39:04 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/flv/gstflvparse.c:
+	  flvparse: Make script tag parsing more flexible.
+	  * The nb_elements for arrays is just an indication, we can therefore ignore
+	  it and carry on parsing metadata items until we reach the end marker.
+	  * If type == 3, then the script tag contains a list of object followed
+	  by the end marker.
+	  Refactor code slightly to handle both cases
+	  https://bugzilla.gnome.org/show_bug.cgi?id=610447
+
+2010-03-11 15:51:40 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/deinterleave.c:
+	* tests/check/elements/interleave.c:
+	  tests: fix metadata not writable warnings in interleave and deinterleave tests
+
+2010-03-11 15:38:19 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/apev2mux.c:
+	* tests/check/elements/id3v2mux.c:
+	  tests: fix metadata not writable warnings with apev2mux and id3v2mux tests
+
+2010-03-11 15:24:20 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: fix metadata writable warnings
+	  Set metadata on buffer first, when the refcount is still 1, and only
+	  ref again afterwards.
+
+2010-03-11 15:02:48 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: ignore stream with invalid header time metadata
+
+2010-03-08 14:57:17 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Set stream-format=raw on AAC caps
+	  Set stream-format=raw for AAC caps, as that is the
+	  expected AAC format to be in this container family.
+	  Fixes #566250
+
+2010-03-11 12:56:11 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: check for NULL before doing strcmp
+	  Check the connection and address type for NULL before doing strcmp and
+	  crashing.
+	  Fixes #612553
+
+2010-03-11 11:20:59 +0100  Benjamin Otte <otte@redhat.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From df8a7c8 to e272f71
+
+2010-03-11 11:09:55 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/udp/gstudpnetutils.c:
+	  build: include stdlib.h for atoi()
+
+2010-03-11 10:33:00 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/audiofx/audiopanorama.c:
+	  audiopanorama: move invariant check out of the inner loop
+	  Improves performance for simple method.
+
+2010-03-10 22:15:04 +0100  Benjamin Otte <otte@redhat.com>
+
+	* configure.ac:
+	  Update CXXFLAGS, too, just like CFLAGS
+
+2010-03-10 21:01:20 +0100  Benjamin Otte <otte@redhat.com>
+
+	* configure.ac:
+	* gst/rtpmanager/Makefile.am:
+	* tests/check/Makefile.am:
+	  Update for recent changes to common submodule
+	  This just replaces every "$ERROR_CFLAGS" usage with a usage of
+	  "$WARNING_CFLAGS $ERROR_CFLAGS" to get the same functionality as
+	  previously.
+	  Actually using that separation will happen later.
+
+2010-03-10 21:52:09 +0100  Benjamin Otte <otte@redhat.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From 9720a7d to df8a7c8
+
+2010-03-10 20:43:57 +0100  Benjamin Otte <otte@redhat.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From 0b6e072 to 9720a7d
+
+2010-03-10 10:51:28 -0800  Andoni Morales Alastruey <amorales@flumotion.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: Reset windows error code after getting corresponding error message.
+
+2010-03-09 17:32:27 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavimux.h:
+	  avimux: put the codec_data blob into the actual data for MPEG4 video, to match other implementations in the wild.
+
+2010-03-10 16:09:56 +0100  Benjamin Otte <otte@redhat.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From 7cc5eb4 to 0b6e072
+
+2010-02-23 21:06:55 -0300  Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximagesrc: send new_segment with GST_FORMAT_TIME format
+	  Instead of using BaseSrc default format GST_FORMAT_BYTES, send it in
+	  GST_FORMAT_TIME.
+	  Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
+	  Fixes #611659
+
+2010-03-10 11:46:06 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: push mode; also report seekable without an element index
+	  ... since recent code also seeks around to obtain required data
+	  from avi index.
+
+2010-03-09 18:06:52 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: add some check and standardized seek event handling in push mode
+
+2010-03-09 18:05:29 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix offset handling in push mode seeking
+	  Push mode seeking uses same index data as pull mode, and stores
+	  offset to data in chunk, whereas push mode operates in chunks,
+	  and as such needs offset consistently corresponding to chunk headers.
+	  Also fix determining best matching stream for incoming newsegment event,
+	  as well as setting some stream state accordingly.
+
+2010-02-26 21:29:49 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	  flvdemux: conduct index scan in task thread
+	  ... rather than in seeking thread, which might then occupy mainloop
+	  for some time with possible unresponsive side-effects.
+
+2010-02-26 21:27:33 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvparse.c:
+	  flvdemux: avoid indefinite index growth
+	  That is, check for and do not add an index entry that has already
+	  been added.
+
+2010-02-18 14:57:39 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvparse.c:
+	  flvdemux: also collect index info on-the-fly in pull mode
+
+2010-02-18 12:42:31 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	* gst/flv/gstflvparse.c:
+	* gst/flv/gstflvparse.h:
+	  flvdemux: incrementally build index in pull mode
+	  Scan for needed part upon a seek as opposed to doing a complete scan
+	  at startup, which may take some time depending on file and/or platform.
+	  Also accept index metadata in pull mode and peek for some metadata
+	  at the end of the file when deemed appropriate.
+
+2010-02-18 12:26:46 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: some more variable cleanup
+
+2010-03-09 18:25:23 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvparse.c:
+	  flvdemux: refactor adding index entry
+
+2010-02-17 11:36:13 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/flv/gstflvparse.c:
+	  flvdemux: fix setting DELTA_UNIT flag on outgoing buffers
+	  ... which should not depend on having index available or not.
+	  Also refactor resulting collapsed code.
+
+2010-02-11 19:43:47 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: avoid erroneous codec-data overriding of stsd information
+
+2010-02-01 22:37:30 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	  speexdec: adapt to new oggdemux
+	  Remove all granulepos hacks and simply use upstream timestamps.
+
+2010-02-01 22:36:02 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexdec.h:
+	  speexdec: refactor granulepos hacks
+
+2010-03-10 11:19:46 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: parse connection information
+	  Parse the connection information from the SDP and use it to figure out if we are
+	  dealing with ipv4 or ipv6 connections.
+
+2010-03-09 17:53:32 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: require a destination for multicast
+	  When setting up the multicast sockets, we need a destination address to listen
+	  on or else we error.
+
+2010-03-09 17:52:35 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: handle ipv6 listening ports when needed
+	  Add some code to make udpsrc listen on an ipv6 address when needed. The
+	  detection of IPV6 is not yet implemented.
+
+2010-03-09 17:15:16 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsink.h:
+	* gst/udp/gstudpsrc.c:
+	* gst/udp/gstudpsrc.h:
+	  udp: use uri parsing code
+	  Use the uri parsing helper functions to manage the host and port pairs. This
+	  adds support for IPV6.
+
+2010-03-09 17:13:31 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpnetutils.c:
+	* gst/udp/gstudpnetutils.h:
+	  udpnetutils: add helper functions for udp uri handling
+	  Add some helpers to parse udp uris. Make sure IPV6 is supported too.
+
+2010-03-05 16:08:45 +0100  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpsession: Make it possible to favor new sources in case of SSRC conflict
+	  Add a "favor-new" property that tells the session to favor new sources when
+	  there is a SSRC conflict. This is useful for SIP calls and other such cases
+	  where a remote loop is extremely unlikely.
+	  Fixes #607615
+
+2010-03-05 15:46:48 +0100  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpsession: Move SSRC conflicts lists into RTPSource
+	  We will also need to track SSRC conflicts in remote sources.
+	  See #607615
+
+2010-02-26 17:13:49 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: send keep alive when paused
+	  When we are paused, send keep alive messages to the server so that our session
+	  doesn't time out when we go back to playing later.
+
+2010-03-10 01:10:07 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 7aa65b5 to 7cc5eb4
+
+2010-02-23 19:48:10 -0800  David Schleef <ds@schleef.org>
+
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesink.h:
+	  multifilesink: Add key-frame option to next-file
+	  This allows segmenting of MPEG-TS files at key frames, which is
+	  exactly what is needed for Apple's HTTP streaming.
+
+2010-03-09 21:32:47 +0000  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 44ecce7 to 7aa65b5
+
+2010-03-08 20:17:58 +0000  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Fix autocropping for odd width/height differences
+
+2010-03-08 20:02:19 +0000  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/Makefile.am:
+	* gst/videobox/gstvideobox.c:
+	* gst/videobox/gstvideobox.h:
+	  videobox: Use libgstvideo for format specific stuff
+
+2010-03-08 19:28:47 +0000  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbaseiirfilter.c:
+	* gst/audiofx/audioinvert.c:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/audiofx/audiopanorama.c:
+	  audiofx: Sync properties to the stream time
+
+2010-03-08 19:20:59 +0000  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/Makefile.am:
+	* gst/videobox/gstvideobox.c:
+	  videobox: Make properties controllable
+
+2010-03-08 19:09:01 +0000  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Some cleanup
+
+2010-02-28 15:47:50 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstop.c:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstripple.c:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gststreak.c:
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstwarp.c:
+	  effectv: Use controller where possible, optimize a bit and make properties threadsafe
+
+2010-02-26 16:35:17 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* pkgconfig/Makefile.am:
+	  build: Make some more rules silent if requested
+
+2010-02-26 15:41:52 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  configure: Use automake 1.11 silent rules instead of shave if available
+	  This makes sure that we use something that is still maintained and
+	  also brings back libtool 1.5 support.
+
+2010-03-08 22:57:34 +0100  Benjamin Otte <otte@redhat.com>
+
+	* ext/libpng/gstpngenc.c:
+	  png: fractions don't allow doubles
+
+2010-03-01 12:03:56 +0100  Benjamin Otte <otte@redhat.com>
+
+	* gst/flx/gstflxdec.c:
+	  flx: fix description
+	  It's video, not audio
+
+2010-03-09 17:45:27 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* win32/common/config.h:
+	  Back to development
+
+=== release 0.10.21 ===
+
+2010-03-09 00:28:16 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.10.21
+
+2010-03-09 00:24:45 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2010-03-09 00:09:34 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/y4m/gsty4mencode.c:
+	* gst/y4m/gsty4mencode.h:
+	  Revert "Add 4:2:2, 4:1:1, and 4:4:4 output support"
+	  This reverts commit 637c26f61a2bd8d7b01f8b6d081d94da65f74557.
+
+=== release 0.10.20 ===
+
+2010-03-08 23:42:51 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.10.20
+
+2010-03-08 23:42:06 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2010-03-08 16:47:04 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: don't send second newsegment event in framed mode, fixes long playback delay
+	  Don't send another newsegment event if the upstream muxer/parser has already
+	  sent one (otherwise the sink will wait for $duration before starting playback).
+	  Fixes long delay until playback starts with flac-in-ogg files.
+	  Fixes #610959.
+
+2010-03-05 13:49:31 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: configure multicast correctly
+	  Take the transport destination for multicast.
+	  Disable loop and autojoin for multicast on the udpsinks.
+
+2010-03-05 13:47:33 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multicast: always configure loop and ttl
+	  Also configure TTL and loop parameters when we add a client after initializing
+	  the sender.
+
+2010-03-08 12:13:32 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph263depay.c:
+	  Revert "rtph263depay: baseclass handles timestamps for us"
+	  This reverts commit 564581e1b88ecd5ec5da82c3cafb0e7a2d58b302.
+	  If we don't call push_ts, there will be no timestamp at all on the outgoing
+	  buffer.
+	  Fixes #612154
+
+2010-02-23 22:16:39 -0500  Benjamin M. Schwartz <bens@alum.mit.edu>
+
+	* gst/y4m/gsty4mencode.c:
+	* gst/y4m/gsty4mencode.h:
+	  Add 4:2:2, 4:1:1, and 4:4:4 output support
+
+2010-03-02 13:21:24 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: use payload size to estimate bitrate
+	  Use the length of the payload for estimating the receiver bitrate so that it
+	  matches the calculations done on the sender side. Together with the number of
+	  packets one can scale the bitrate with the header overhead of the lower
+	  transport.
+
+2010-03-02 12:39:20 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpsource: refactor bitrate estimation
+	  Don't reuse the same variable we need for stats for the bitrate estimation
+	  because we're updating it.
+	  Refactor the bitrate estimation code so that both sender and receivers use the
+	  same code path.
+
+2010-03-01 16:40:27 -0500  Tristan Matthews <tristan@sat.qc.ca>
+
+	* gst/rtpmanager/rtpsource.c:
+	  added bitrate estimation to receiver-side stats, fixes #611213
+
+2010-03-01 16:01:24 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph263pay.c:
+	  h263pay: fix typo in debug
+
+=== release 0.10.19 ===
+
+2010-03-06 00:43:03 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.10.19
+
+2010-03-06 00:42:09 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2010-03-03 20:29:30 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.18.4 pre-release
+
+2010-03-02 18:29:41 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Make sure we don't send invalid newsegments
+	  Fixes #611501
+
+2010-03-02 14:09:14 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	  matroskademux: Mark streams as being EOS at the right time.
+	  This allows us to stop streaming only when all streams have gone past the
+	  segment.stop and not before.
+	  Fixes #611501
+
+2010-02-26 18:10:32 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Advance sparse streams only as much as required to keep the gap smaller than 500ms
+	  Changing it to the newest timestamp that was ever pushed will
+	  increase the segment start in 500ms jumps, which could be just
+	  after the next sparse stream buffer. E.g.
+	  Video at 1.0s, sparse stream at 0.5s would jump the
+	  sparse stream to 1.0s. Now a new sparse stream buffer could
+	  appear that has a timestamp of 0.9s and this would be
+	  dropped for no good reason because of bad luck.
+
+2010-02-24 01:36:07 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* po/es.po:
+	* win32/common/config.h:
+	  0.10.18.3 pre-release
+
+2010-02-24 02:05:49 +0100  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer.h:
+	  Make sure FLUSH_STOP is sent so not to leave downstream flushing.
+
+2010-02-23 17:25:54 +0100  Volker Grabsch <bugzilla.gnome.org@v.notjusthosting.com>
+
+	* configure.ac:
+	  configure: Use $PKG_CONFIG instead of pkg-config to fix cross compilation
+	  Fixes bug #610839.
+
+2010-02-23 17:24:03 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Reset skew detection after instantiating the jitterbuffer
+	  ...not only when going to READY. This sets high_level and friends to
+	  a more useful value.
+
+2010-02-23 17:19:14 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpjitterbuffer: Return 100 if high-level is 0 instead of dividing by zero
+
+2010-02-22 12:24:14 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4gdepay.c:
+	  rtpmp4gdepay: avoid division by 0
+	  Avoid a division by 0 when no constantDuration was specified and when out two
+	  timestamps are equal.
+	  Fixes #610265
+
+2010-02-22 18:20:46 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpdvdepay.h:
+	  dvdepay: don't output frames until we have a header
+	  Wait for the complete first 6 header DIF packets before outputting a frame.
+	  Decoders need this info to correctly decode the data.
+	  Fixes #610556
+
+2010-02-22 20:55:29 +0100  David Hoyt <dhoyt@llnl.gov>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Fix invalid memory access by first checking and then reading
+	  Fixes bug #610483.
+
+2010-02-18 09:05:50 +0100  Philippe Normand <phil@base-art.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: gst_pulsesink_get_mute: set result earlier.
+	  In the cases where no buffer was process yet or the index is not
+	  available, get_pulsesink_get_mute() would unconditionally return
+	  FALSE.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=610337
+
+2010-02-19 12:35:29 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* pkgconfig/gstreamer-plugins-good-uninstalled.pc.in:
+	  pkgconfig: fix gstreamer-plugins-good uninstalled .pc file
+	  Fix gst-plugins-base reference/requirement. This caused spurious
+	  problems with uninstalled -ugly/-bad not finding -good plugins in
+	  their unit tests (when distchecking).
+
+2010-02-19 01:03:31 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* po/lv.po:
+	* win32/common/config.h:
+	  0.10.18.2 pre-release
+
+2010-02-19 00:54:13 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/.gitignore:
+	* tests/examples/shapewipe/.gitignore:
+	  Make git ignore shapewipe examples and tests
+
+2010-02-19 00:46:40 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/flv/gstflvparse.c:
+	  flvdemux: minor micro-optimisation
+	  We know these values don't change during the loop, but the compiler
+	  doesn't and has to re-check them for every iteration.
+
+2010-02-19 00:39:50 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/flv/gstflvparse.c:
+	  flvdemux: remove static keyword from variables that shouldn't be static
+	  Multiple flvparse/flvdemux instances should be able to operate without
+	  trampling over each other by accidentally re-using the same (static)
+	  variables. (Spotted by Mark Nauwelaerts)
+
+2010-02-16 02:07:07 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  docs: add Since: markers for new jitterbuffer properties
+
+2010-02-18 18:20:24 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix off-by-one logic error in frame rate cap regression commit
+
+2010-02-17 16:27:33 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Use the correct duration when comparing segments
+	  Do not confuse QtDemuxSegments with GstSegments when
+	  comparing the total file duration with the segment duration
+	  Fixes #610296
+
+2010-02-17 18:06:29 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: add durations modulo 1<<32
+	  For calculating the durations of each sample, we are supposed to add each
+	  duration modulo 1<<32 so make the elapsed time counter a uint32.
+	  Fixes #610280
+
+2010-02-16 21:05:24 +0100  Anders Skargren <anders.skargren at axis.com>
+
+	* gst/multipart/multipartdemux.c:
+	  multipartdemux: improve header mime-type parsing
+	  Make the handing of the mime type within the "boundary" a bit less naive.
+	  The standard for MIME allows parameters to follow the "type" / "subtype"
+	  clause separated from the mime type by ';'.
+	  Modifies the multipartdemuxer's header parsing so it doesnt assume
+	  the whole line after "content-type:" is the mime type and thus makes it a bit
+	  more resilient to finding absurd mime types in the case where parameters are
+	  added.
+	  Fixes #604711
+
+2010-02-16 19:53:09 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: avoid stopping NULL tasks
+	  Check the task for NULL, it could be paused and set to NULL before.
+
+2010-02-16 16:22:28 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix ALAC codec-data handling
+	  ALAC codec-data apparently comes in (at least) two flavours (mov, mp4),
+	  so use atom based parsing to retrieve required data, rather than
+	  aiming for a specific offset.
+	  See also #580731.
+
+2010-02-16 15:50:23 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix debug message
+
+2010-02-11 19:39:04 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_types.h:
+	  qtdemux: handle signed values in 3GPP location tag
+
+2010-02-08 21:35:53 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix typo in debug message
+
+2010-02-16 15:00:13 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: reset some more stream state after seek
+	  In particular, fixes non-flushing seek.
+
+2010-02-16 14:44:11 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix frame rate cap regression
+	  Look for a non-zero min_duration during initialisation to avoid
+	  incorrect frame rate caps.
+
+2010-02-16 10:13:17 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	  v4l2: log more details in buffer pool finalize
+	  Helps to align with the loggin from libv4l.
+
+2010-02-16 10:11:40 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: init datastructures after pre-conditions checks
+
+2010-02-16 10:10:45 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: add a fixme for handling other YUV variants
+
+2010-02-16 01:40:19 +0000  Brian Cameron <brian.cameron@sun.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska: fix GST_ELEMENT_ERROR usage
+	  Fixes #610053.
+
+2010-02-16 00:50:15 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: fix up GST_CXXFLAGS properly
+	  We don't want C specific flags in GST_CXXFLAGS, so base it on the
+	  GST_CFLAGS that only contains the pkg-config CFLAGS but none of
+	  the GST_OPTION_CFLAGS. Also, we only need the local includes once.
+	  Fix typo as well (GST_FLAGS -> GST_CFLAGS).
+
+2010-02-15 23:13:46 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* configure.ac:
+	  configure: base GST_CXXFLAGS on --cflags from pkg-config
+	  pkg-config sets GST_CFLAGS and GST_LIBS. We need to use CFLAGS as a starting
+	  point for for both C and CXX settings.
+
+2010-01-20 18:52:51 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpbin: remove use of ntp_ns_base
+
+2010-01-20 18:22:20 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpstats.h:
+	  rtpbin: remove more ntpnstime and cleanups
+	  Remove some code where we pass ntpnstime around, we can do most things with the
+	  running_time just fine.
+	  Rename a variable in the ArrivalStats struct so that it's clear that this is the
+	  current system time.
+
+2010-01-20 18:19:34 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: use running_time for jitter
+	  Use the running_time to calculate the jitter instead of the ntp time. Part of
+	  the plan to get rid of ntpnsbase.
+
+2010-01-20 17:04:03 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpbin: change how NTP time is calculated in RTCP
+	  Don't calculate the NTP time based on the running_time of the pipeline but from
+	  the systemclock. This allows us to generate more accurate NTP timestamps in case
+	  the systemclock is synchronized with NTP or similar.
+
+2010-02-15 12:12:36 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: printf format string fix
+	  The compiler wants a cast here even though the type is already
+	  typedefed as 64-bit integer (presumably because glib has typedefed
+	  guint64 to unsigned long here).
+
+2010-02-15 10:33:02 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska: fix printf format string
+
+2010-02-15 00:50:10 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/raw1394/gst1394clock.h:
+	* gst/matroska/ebml-write.h:
+	* gst/rtpmanager/gstrtpjitterbuffer.h:
+	  raw1394, matroska, rtpmanager: remove padding from structures
+	  None of these element and class structures are in public headers,
+	  so don't need padding.
+
+2010-02-15 00:47:11 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: update for new translator comment
+
+2010-02-15 00:45:51 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: add comment for translators for 'x by y' message
+	  Fixes #609724.
+
+2010-02-15 01:28:44 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/cairo/gstcairorender.c:
+	  cairorender: Fix leaking of pad templates
+
+2010-02-15 00:50:27 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/shapewipe.c:
+	  shapewipe: Fix unit test for latest changes
+	  Now the alpha is multiplied with the already existing alpha
+	  value instead of simply ignoring it and the luma/chroma values
+	  are kept, even if the output is 100% transparent.
+
+2010-02-15 00:47:08 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/shapewipe.c:
+	  shapewipe: Improve unit test output on errors
+
+2010-02-14 23:17:20 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 96dc793 to 44ecce7
+
+2010-02-13 23:28:06 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: bump -base requirement to git
+	  For GST_RIFF_TAG_JUNQ.
+
+2010-02-12 16:11:30 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2.c:
+	  v4l2sink: change rank to NONE so it is never autoplugged
+
+2010-02-13 18:18:42 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/flv/gstflvparse.c:
+	  flvdemux: Audio tags without any content are valid.
+	  We silently ignore them instead of erroring out.
+
+2010-02-13 18:07:50 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/flv/gstflvparse.c:
+	  flvdemux: Fix GST_CLOCK_DIFF usage.
+	  It was previously checking for DIFF(a, b > 6 * GST_SECOND) instead of
+	  the proper DIFF(a,b) > 6 * GST_SECOND
+
+2010-02-13 16:27:07 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Don't forget to reset the indexed variable when cleaning up
+
+2010-02-13 11:01:53 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/flv/gstflvparse.c:
+	  flvdemux: Speedup GstIndex usage
+	  Used the _add_associationv variant of GstIndex since we know how many
+	  associations we're adding. Trims up to 50% from index generation time.
+	  Note : It would be great if the index could be generated on the fly or
+	  on request as opposed to being fully created at startup.
+
+2010-02-12 19:32:27 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  jitterbuffer: don't resync to invalid timestamps
+	  If we detect backward timestamps on the server, don't try to resync when we
+	  don't have an input timestamp (such as when using RTSP over TCP) instead, do
+	  nothing but assume the timestamp was ok, it will correct itself when time goes
+	  forwards.
+
+2010-02-12 17:21:43 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: fix typo
+
+2010-02-12 16:47:29 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: start out active and not buffering
+	  There is no need to set the latency in the jittebuffer in _init, we will set
+	  that later when going to PAUSED.
+	  Set the jitterbuffer active and not buffering when starting.
+
+2010-01-27 17:57:55 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  rtpbin: more buffering work
+	  When deactivating jitterbuffers when the buffering starts, keep the current
+	  percent of the jitterbuffer and also set the jitterbuffer in the buffering state
+	  so that we know when it's filled again.
+	  Add property to get the buffering percentage of the jitterbuffer.
+
+2009-10-14 16:29:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: adjust latency in buffer mode
+	  When we are in buffer mode, adjust the buffering low/high thresholds based on
+	  the total configured latency. If we don't and there is a huge queue or element
+	  with a big latency downstream we might drain the complete queue immediately and
+	  start buffering again.
+
+2009-10-12 11:54:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: add ts-offset to timestamp
+	  Add the ts-offset to the buffer timestamp to get the final output timestamp of
+	  the buffer.
+
+2009-10-08 19:23:53 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin-marshal.list:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.h:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpbin: do more accurate buffer offsets
+	  Return the next timestamp in the jitterbuffer.
+	  Use the min-timestamp of the jitterbuffers to calculate an offset so that the
+	  next timestamp is pushed with a timestamp equal to running_time.
+	  Start producing timestamps from 0 in the buffering case too.
+
+2009-10-08 18:42:11 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: only start buffering when < 100%
+	  Only start buffering when the percentage message is < 100 %.
+
+2009-10-06 13:34:34 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: keep track of elapsed pause time
+	  Keep track of the time we spend pausing the jitterbuffers when they were
+	  buffering and distribute this elapsed time to the jitterbuffers.
+	  Also keep the latency in nanosecond precision.
+
+2009-10-06 13:33:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.h:
+	  jitterbuffer: keep track of offset
+	  Keep track of an outgoing offset that we add to each outgoing buffer to
+	  compensate for PAUSE when buffering.
+	  Adjust the offset when activating.
+
+2009-10-06 13:30:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  jitterbuffer: report level using high watermark
+
+2009-10-05 21:31:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtsp/gstrtspsrc.c:
+	  rtpbin: pass running_time to jitterbuffer pause
+	  Pass the current running time to the jitterbuffer when pausing or resuming so
+	  that it calculate the right offsets.
+	  Small cleanups and comments.
+	  Set the default rtspsrc latency to 2 seconds.
+
+2009-10-05 20:09:30 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  rtpbin: add some comments
+
+2009-10-05 19:45:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin-marshal.list:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.h:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  rtpbin: more buffering updates
+	  Add signal to pause the jitterbuffer. This will be emitted from gstrtpbin when
+	  one of the jitterbuffers is buffering.
+	  Make rtpbin collect the buffering messages and post a new buffering message with
+	  the min value.
+	  Remove the stats callback from jitterbuffer but pass a percent integer to
+	  functions that affect the buffering state of the jitterbuffer. This allows us
+	  then to post buffering messages from outside of the jitterbuffer lock.
+
+2009-10-05 13:32:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  rtpbin: propagate buffer-mode property
+	  Propagate buffer-mode property to the jitterbuffers.
+	  Intercept BUFFERING messages in rtpbin
+
+2009-10-01 17:14:09 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  jitterbuffer: do more buffering implementation
+	  Add callback for buffering stats.
+	  Configure the latency in the jitterbuffer instead of passing it with _insert.
+	  Calculate buffering levels when pushing and popping
+	  Post buffering messages.
+
+2009-10-01 12:46:21 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  jitterbuffer: flesh out buffering mode some more
+	  Add a buffering state to the jitterbuffer and wait until buffering ends before
+	  pushing out packets.
+
+2009-10-01 12:09:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  jitterbuffer: hook up the mode property
+	  Expose a mode property on the jitterbuffer.
+	  Fix the case where timestamps are -1 in the check for outgoing timestamps.
+
+2009-10-01 11:20:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  jitterbuffer: add buffering mode options
+	  Add getters and setters for different buffering modes that the jitterbuffer will
+	  support. Default to the current slave mode.
+
+2010-02-12 15:54:37 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2.c:
+	  v4lsink: lower rank to MARGINAL
+
+2010-02-12 16:06:45 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	* gst/flv/gstflvparse.c:
+	  flvdemux: Obtain the index from the end of an flv file in push mode
+	  Allows for better support of seeking in flv files when in push mode
+
+2010-01-21 11:55:15 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: Drop video frames up to the desired keyframe after a seek
+	  The audio packets in AVI are generally muxed ~0.5s before the
+	  corresponding video packet. This changes causes downstream to only
+	  receive packets with roughly corresponding timestamps.
+
+2010-01-19 18:35:49 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: more DISCONT handling
+	  Add some debug in the DISCONT handling code.
+	  When we receive a DISCONT in push mode, mark all streams as DISCONT.
+
+2010-01-19 10:51:08 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Fix _handle_seek_push () and new segement behaviour
+
+2010-01-18 17:13:06 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: cleanups
+	  Make sure we reset the demuxer correctly wrt parsing the index.
+	  Don't leak pending seek events.
+	  Rename some methods to reflect what they do and to avoid confusion with similar
+	  method names.
+	  Try to make the seeking threadsafe by protecting the setup code with a lock.
+	  Make sure we post errors when a seek fails.
+
+2010-01-18 11:45:38 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: rename some variables
+	  seek_event -> seg_event
+	  event_seek -> seek_event
+
+2010-01-15 18:00:46 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: take fallback duration from avih
+	  When we have not parsed any indexes yet, we don't know the length of the streams
+	  and we must take the length given in the avih as a fallback.
+	  Avoid some typechecking.
+
+2009-12-04 15:13:12 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: Push mode seeking support
+
+2010-02-01 16:04:41 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: cleanup properties
+	  Use more default constants.
+	  Use static strings param flag.
+	  Init properties explicitly instead of letting gobject do this.
+
+2010-02-12 15:34:38 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/speex/gstspeexdec.c:
+	  speex: add missing include
+
+2010-02-05 13:28:53 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/debugutils/gsttaginject.c:
+	  taginject: fix multi-value tag example
+	  We need to use {} to specify a list.
+
+2010-02-01 14:43:04 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/avi/gstavidemux.c:
+	* gst/wavparse/gstwavparse.c:
+	  avi,wav: also handle JUNQ chunk in addition to JUNK
+
+2010-02-04 15:59:25 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	  rtppay: don't ignore result from set_outcaps
+	  set_outcaps can fail and we need to propagate the result upstream.
+
+2010-02-04 15:36:24 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/flv/gstflvparse.c:
+	  flvparse: fix confusing debug messages
+
+2010-01-27 13:28:13 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: add some more debug info
+
+2010-01-27 13:26:46 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: avoid segfault when shutting down
+	  when we are shutting down, we might still receive state updates from pulseaudio
+	  but since we are unparented we should not do anything with the NULL parent
+	  anymore.
+
+2010-01-26 18:33:27 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer.h:
+	  videomixer: fix timestamp problems
+	  When the pad with the highest framerate goes EOS, instead of not timestamping
+	  output buffers, intepollate timestamps and durations from the last seen ones.
+	  Fixes #608026
+
+2010-02-12 11:32:40 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* 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:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	  docs: Update documentation
+
+2010-02-12 11:18:26 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/inspect/plugin-shapewipe.xml:
+	* tests/check/Makefile.am:
+	* tests/examples/Makefile.am:
+	  Moved 'shapewipe' from -bad to -good
+	  Fixes bug #584536.
+
+2010-02-10 10:52:53 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 29/29] shapewipe: Preserve the input color values in all cases
+
+2010-02-10 10:50:49 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 28/29] shapewipe: Scale mask alpha values by the source alpha values
+
+2010-02-10 10:42:32 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 27/29] shapewipe: Fix ARGB processing
+
+2010-02-10 10:34:24 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/examples/shapewipe/shapewipe-example.c:
+	  [MOVED FROM BAD 26/29] shapewipe: Print some more details on error/warning messages
+
+2010-02-08 08:26:33 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 25/29] shapewipe: Improve/add debug output
+
+2010-02-08 08:20:44 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 24/29] shapewipe: Always hold the mask mutex before signalling the GCond
+
+2010-02-08 08:19:48 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 23/29] shapewipe: Move chain function error cases at the end of the function and add useful debug output
+
+2010-02-08 08:12:11 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/shapewipe/gstshapewipe.h:
+	  [MOVED FROM BAD 22/29] shapewipe: Fix race condition during shutdown that can lead to a deadlock
+
+2010-02-08 08:11:33 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 21/29] shapewipe: Drop mask buffer on FLUSH events
+
+2010-02-08 08:09:55 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/shapewipe/gstshapewipe.h:
+	  [MOVED FROM BAD 20/29] shapewipe: Update copyright year
+
+2010-02-08 08:08:44 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 19/29] shapewipe: Don't reset properties when going PAUSED->READY
+	  Also use defines for the default values of the properties.
+
+2010-01-16 16:52:11 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 18/29] shapewipe: Replace floating point arithmetic in the inner processing loops by integer arithmetic
+
+2009-12-10 10:40:10 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 17/29] shapewipe: Don't do pointer dereferences in the processing loop
+	  Lowers the time taken there in my testcase from 6.91% to 6.20%
+	  as measured by callgrind.
+
+2009-07-08 17:59:29 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 16/29] shapewipe: Add BGRA support for video in/output
+
+2009-07-02 11:24:48 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/shapewipe/gstshapewipe.h:
+	  [MOVED FROM BAD 15/29] shapewipe: Add support for ARGB video input/output
+
+2009-06-23 18:23:13 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 14/29] shapewipe: Correctly handle 0/1 fps
+
+2009-06-09 19:14:41 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/shapewipe/gstshapewipe.h:
+	  [MOVED FROM BAD 13/29] shapewipe: Implement basic QoS
+	  This change is based on Tim's QoS implementation
+	  for jpegdec.
+
+2009-06-09 18:45:19 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 12/29] shapewipe: Proxy queries on the video pads to the correct peers
+
+2009-06-09 18:37:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 11/29] shapewipe: Proxy bufferalloc on the video sinkpad
+
+2009-06-09 18:25:13 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 10/29] shapewipe: Try to work inplace if possible
+	  This saves one new, large allocation per frame for the
+	  most cases.
+
+2009-06-04 08:56:14 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/shapewipe.c:
+	  [MOVED FROM BAD 09/29] shapewipe: Increase timeout of the unit test
+
+2009-06-01 21:24:27 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 08/29] shapewipe: Fix some issues that were exposed by the new unit test
+
+2009-06-01 21:24:12 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/shapewipe.c:
+	  [MOVED FROM BAD 07/29] shapewipe: Add unit test for shapewipe
+
+2009-05-31 21:33:01 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 06/29] shapewipe: Add documentation and integrate into the build system
+
+2009-05-29 21:07:26 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	  [MOVED FROM BAD 05/29] shapewipe: Adjust border to still have everything transparent at 1.0 and the other way around
+
+2009-05-29 16:55:25 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	* tests/examples/shapewipe/shapewipe-example.c:
+	  [MOVED FROM BAD 04/29] shapewipe: Divide the border value by two, otherwise we use a twice a wide border
+
+2009-05-29 16:51:50 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/shapewipe/gstshapewipe.h:
+	* tests/examples/shapewipe/shapewipe-example.c:
+	  [MOVED FROM BAD 03/29] shapewipe: Add border property to allow smooth borders
+	  ...and use a border of 0.01 in the example application.
+
+2009-05-29 16:00:16 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/examples/shapewipe/Makefile.am:
+	  [MOVED FROM BAD 02/29] shapewipe: Fix Makefile of the example application
+
+2009-05-29 15:32:24 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/shapewipe/Makefile.am:
+	* gst/shapewipe/gstshapewipe.c:
+	* gst/shapewipe/gstshapewipe.h:
+	* tests/examples/shapewipe/Makefile.am:
+	* tests/examples/shapewipe/shapewipe-example.c:
+	  [MOVED FROM BAD 01/29] shapewipe: Add a simple shapewipe transition filter & example application
+
+2010-02-06 18:19:27 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: Only flush the FLAC decoder if it wasn't created right before
+	  If the FLAC decoder is flushed, its state will be set to frame-sync mode,
+	  which will sync to the next *audio* frame and makes it ignore all headers.
+	  This prevented tags and everything else to show up when using flacdec
+	  in push mode.
+	  Fixes bug #608843.
+
+2010-02-11 01:12:15 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* MAINTAINERS:
+	  Update MAINTAINERS
+
+2010-02-12 00:03:09 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: back to development
+	  Slushy freeze remains in effect.
+
+=== release 0.10.18 ===
+
+2010-02-10 23:18:22 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.10.18
+
+2010-02-10 23:17:21 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2010-02-10 20:36:56 +0000  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: temporary safety check to avoid crashes with a certain file
+	  Add temporary check to avoid crashes with a certain file when seeking
+	  until the real cause of this is figured out. See #609405.
+
+2010-02-05 18:05:39 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux.h:
+	  qtdemux: skip unknown atoms when looking for moov
+	  Fixes bug #609107
+
+2010-02-05 02:13:33 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.10.17.3 pre-release
+
+2010-02-04 19:10:36 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/bg.po:
+	* po/hu.po:
+	  po: update translations
+
+2010-02-04 14:46:56 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux.h:
+	  qtdemux: Set the segment start time to the requested seek time for non-keyframe seeks
+
+2010-02-04 12:00:03 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix time returned for index at a byte offset
+	  The logic for searching forwards/backwards was swapped
+
+2010-02-01 19:22:24 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	  speexdec: initialize stereo decoding state
+
+2010-01-28 18:58:08 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: improve stream synchronization
+	  In particular, do not make it send newsegment updates that
+	  sort-of contradict the indented playback segment (e.g. start time).
+
+2010-01-28 18:53:18 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: fix bridging (time) gaps in streams
+	  As a side effect, avoid sending newsegment updates with start times
+	  that go back and forth, which leads to bogus downstream running_time.
+	  Also fixes seeking in bug #606744.
+
+2010-01-28 18:49:57 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: fix stream synchronization
+	  .. by initializing streams starting at 0, as that is basically
+	  where we 'seek to' at the start and assume streams to start elsewhere.
+	  Also enables newsegment update events for subtitle streams.
+
+2010-02-02 13:41:03 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpeg: don't directly access message, some message have args
+	  This caused bogus messages, such as reported in bug #607471.
+
+2010-02-02 00:02:34 +0000  David Hoyt <dhoyt@llnl.gov>
+
+	* ext/libpng/gstpngdec.c:
+	  png: fix compilation with libpng 1.4
+	  png_set_gray_1_2_4_to_8() has been deprecated for a while and was
+	  finally removed in libpng 1.4.x. Use png_set_expand_gray_1_2_4_to_8()
+	  instead.
+	  Fixes #608629.
+
+2010-02-01 16:46:36 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: free transports on errors
+	  See #608564
+
+2010-02-01 09:18:53 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2: fix unportable printf format
+
+2010-01-30 15:18:48 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 15d47a6 to 96dc793
+
+2010-01-27 17:53:07 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: index timestamps should be in seconds, not milliseconds
+
+2010-01-27 15:24:52 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	  speexdec: free some more when resetting
+	  Fixes #608255.
+
+2010-01-27 15:24:24 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpspeexpay.c:
+	  rtpspeexpay: fix occasional buffer leak
+	  Fixes #608255.
+
+2010-01-27 15:22:46 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/speex/gstspeexenc.c:
+	  speexenc: prevent invalid arithmetic if not setup yet
+	  Fixes #608255.
+
+2010-01-27 16:34:21 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_mmx.h:
+	  videomixer: Fix assembly register constraints
+	  Fixes bug #608209.
+
+2010-01-27 01:56:03 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.10.17.2 pre-release
+
+2010-01-27 01:52:59 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/LINGUAS:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/el.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: update translations
+
+2010-01-27 01:49:49 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/.gitignore:
+	  checks: ignore deinterlace check binary
+
+2010-01-27 01:18:51 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: purge all mention of CVS
+
+2010-01-26 11:18:28 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: ignore streams that finished
+	  When we receive an UNEXPECTED from a stream, move to the next stream and only go
+	  EOS when all streams are EOS. When selecting a stream to push, ignore streams
+	  that went EOS.
+	  Fixes #607949
+
+2010-01-25 17:23:43 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2src: don't deref NULL
+	  Error out when the pool gets shutdown.
+
+2010-01-25 17:21:13 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpegenc.c:
+	* sys/v4l2/v4l2src_calls.c:
+	* tests/check/Makefile.am:
+	  Revert "v4l2src: don't deref NULL"
+	  This reverts commit 3d9d34bd60faeb940b36d992a47168fc895036ba.
+
+2010-01-25 14:16:22 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpegenc.c:
+	* sys/v4l2/v4l2src_calls.c:
+	* tests/check/Makefile.am:
+	  v4l2src: don't deref NULL
+	  Error out when the pool gets shutdown.
+
+2010-01-23 15:32:48 -0800  Michael Smith <msmith@xiph.org>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: when creating an overflow buffer, copy timestamps.
+
+2010-01-23 14:47:55 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: dmb1 is a valid fourcc for Motion-JPEG
+
+2010-01-23 14:20:02 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdeux: IV32 is also used for Indeo 3 video streams
+
+2010-01-22 16:48:01 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/icles/ximagesrc-test.c:
+	  build: no unused variables when disabling asserts
+
+2010-01-21 23:17:40 -0300  Roland Krikava <rkrikava@gmail.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Avoid negative overflow on keyframe search
+	  Do not overflow negatively when searching a previous
+	  "keyframe" on audio streams. Could cause infinite loops
+	  on backwards playback
+	  Fixes #607718
+
+2010-01-21 17:22:38 -0800  Peter van Hardenberg <pvh@songbirdnest.com>
+
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstjpegenc.h:
+	  jpegenc: enlarge buffer if libjpeg tells us it's out of space. Fixes buffer overflow on some high-quality, low-resolution jpeg encodes.
+
+2010-01-21 19:24:22 +0100  Alessandro Decina <alessandro.d@gmail.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix compiler warnings under OS X.
+
+2010-01-21 17:57:36 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: don't parse NULL indexes
+	  for some streams we might fail to fetch the index offsets. Don't try to parse
+	  NULL indexes in those cases.
+
+2010-01-18 21:15:51 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtpg729pay.c:
+	  rtpg729pay: ptime should is in nanoseconds
+	  https://bugzilla.gnome.org/show_bug.cgi?id=607403
+
+2010-01-20 15:11:15 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavenc/gstwavenc.h:
+	  wavenc: Post warning if file isnt finished properly
+	  When the pipeline is shut down and the file isn't
+	  finished properly, wavenc should post a warning.
+	  Fixes #607440
+
+2009-05-27 13:51:44 +0200  Arnout Vandecappelle <arnout@mind.be>
+
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroskamux: make index size configurable.
+	  Added the 'min-index-interval' property to matroskamux,
+	  which determines how much time (nanoseconds) is left
+	  between keyframes stored in the index.
+	  Fixes #583985.
+
+2010-01-20 16:28:31 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: scale spspps_interval to milliseconds
+	  The spspps_interval is kept in seconds. Convert it to milliseconds before
+	  comparing it to another value in milliseconds.
+
+2010-01-20 15:18:47 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: always keep media segments within total duration
+	  ... as opposed to only doing so following a seek.
+
+2010-01-20 15:44:40 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: rename spspps-interval property
+	  Rename the spspps-interval property to config-interval because it is nicer.
+
+2010-01-19 18:37:31 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: skip RIFF and index in push mode
+	  When we are in push mode, we can encounter RIFF and idx tags in the data chunk
+	  when we are dealing with ODML files. In these cases, simply skip the chunks and
+	  continue streaming instead of going EOS.
+
+2010-01-20 11:27:23 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: more DISCONT handling
+	  Add some debug in the DISCONT handling code.
+	  When we receive a DISCONT in push mode, mark all streams as DISCONT.
+
+2010-01-20 11:26:34 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: reset on flush events
+	  When we receive a flush event on the sinkpad, reset the EOS state and the
+	  flowreturn of all streams. Also mark the streams with a DISCONT.
+
+2010-01-20 11:22:04 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: rename some variable
+	  Rename the seek_event variable to seg_event because it really contains the
+	  newsegment event that needs to be pushed.
+
+2010-01-20 00:54:03 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 14cec89 to 15d47a6
+
+2010-01-18 14:49:26 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtph264pay.h:
+	  rtph264pay: Don't set profile-level-id in out caps
+	  The profile-level-id represents restrictions on what can be sent, it does not
+	  describe the stream. So it should be reflected in the sink caps of the
+	  payloader, not the src caps.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=607353
+
+2010-01-18 14:41:10 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: Don't ignore the return value from set_outcaps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=607353
+
+2010-01-18 17:43:41 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/tvtime/greedyhmacros.h:
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/tomsmocomp.c:
+	* gst/deinterlace/tvtime/weave.c:
+	* gst/deinterlace/tvtime/weavebff.c:
+	* gst/deinterlace/tvtime/weavetff.c:
+	  deinterlace: Fix license and copyright headers
+
+2010-01-18 14:57:42 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2: move G_END_DECLS to the end
+
+2010-01-18 14:55:38 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	  v4l2: fix bufferpool file names in header comment
+
+2010-01-15 18:15:14 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: avoid some typecasting
+
+2010-01-15 18:13:24 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: avoid some type checks
+
+2010-01-15 18:09:15 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: fallback to avih duration
+	  when we have not yet parsed the indexes (in push mode, for example) use
+	  the duration as given in the avih header instead of -1.
+
+2010-01-15 13:32:32 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: g_free is NULL safe
+
+2010-01-15 13:27:40 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: use DEMUX errors, instead of DECODE
+	  qtdemux should use DEMUX errors, and not DECODE
+	  Conflicts:
+	  gst/qtdemux/qtdemux.c
+
+2010-01-14 19:16:19 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Minor refactor
+	  Replace repeated code with a function call
+
+2010-01-14 17:11:13 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	  qtdemux: Handle another kind of redirect trak
+	  Some traks might contain a redirect rtsp uri inside
+	  hndl atom (which is a dref atom entry). This commit makes qtdemux
+	  post a message when it finds one of these traks and there are
+	  no other traks.
+	  Fixes #597497
+
+2010-01-14 16:13:08 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux.h:
+	  qtdemux: Post error when reaching EOS without pads
+	  Post an error when EOS is reached and there are no src pads
+
+2010-01-14 14:13:50 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Do not post empty redirect messages
+	  Some misinterpreted data could result in posting redirect messages
+	  with empty redirect strings. It is better not to post them.
+	  An example is the file on bug #597497
+
+2010-01-14 18:19:25 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: polish last buffer end time usage
+	  That is, reset it upon seek, and note that (rarely) last pushed buffer
+	  time might precede segment start.
+
+2010-01-13 16:48:46 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/videomixer/blend_mmx.h:
+	  videomixer: use 'q' constraint instead of 'r'
+	  This avoids the "bad register name `%dil'" compilation errors on 32bit where
+	  because of 'r' gcc puts the value in a general purpose register and then tries
+	  to access the lower part as %dil/%sil which is not existing on 32bit. 'q' requests
+	  a-d registers
+
+2010-01-13 16:44:58 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/avi/gstavidemux.c:
+	  avi: add missing include for sscanf
+
+2010-01-13 09:36:03 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/equalizer/gstiirequalizer10bands.c:
+	  equalizer: Fix property description for the 3rd band of the 10band equalizer
+	  The frequency is actually 237 Hz, not 227 Hz.
+	  Fixes bug #606692.
+
+2010-01-13 09:22:20 +0100  Kipp Cannon <kcannon@ligo.caltech.edu>
+
+	* gst/audiofx/audioamplify.c:
+	  audioamplify: Allow negative amplifications
+	  Fixes bug #606807.
+
+2010-01-13 09:17:05 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/taglib/gstapev2mux.cc:
+	  apev2mux: Don't call constructors directly, this leads to compiler errors with gcc 4.5
+
+2010-01-12 17:39:05 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: use G_GSIZE_FORMAT for platform independent gsize qualifier
+	  Fixes build on macosx
+
+2010-01-11 19:02:34 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: refactor eos sending when pausing loop
+	  Also, prevent hanging if no pads yet on which to send eos by
+	  posting a message instead.
+
+2010-01-11 17:50:35 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: standardize seek handling
+	  ... which implies fixing some corner cases.
+
+2010-01-11 15:14:06 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: use more generic xiphN_streamheader_to_codecdata helper
+
+2010-01-11 17:50:04 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: reflow audio and video setcaps and improve logging
+	  Also ensure width and height are available as they are mandatory
+	  in matroska specs.
+
+2010-01-11 11:42:43 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix offset for type 2 mp4a sound sample descriptions.
+	  Allows us to correctly find the esds (and thus the codec data) for such
+	  mp4a files.
+
+2010-01-11 15:45:49 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	  rtpmp4g(de)pay: Only handle raw aac
+	  rtpmp4g(de)pay should only handle raw AAC streams
+
+2010-01-11 18:59:43 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer.h:
+	  videomixer: Implement basic QoS
+	  This drops frames if they're too late anyway before blending and all
+	  that starts but QoS events are not forwarded upstream. In the future
+	  the QoS events should be transformed somehow and forwarded upstream.
+
+2010-01-11 14:48:26 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	  rtpmp4a(de)pay: Only accept raw aac
+	  rtpmp4a(de)pay should only handle raw aac to conform to the RFC
+
+2010-01-11 18:35:47 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend.c:
+	* gst/videomixer/blend_mmx.h:
+	  videomixer: Add MMX implementations for I420 and all non-alpha RGB formats
+
+2010-01-04 10:24:45 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/blend.c:
+	* gst/videomixer/blend.h:
+	* gst/videomixer/blend_ayuv.c:
+	* gst/videomixer/blend_bgra.c:
+	* gst/videomixer/blend_i420.c:
+	* gst/videomixer/blend_mmx.h:
+	* gst/videomixer/blend_rgb.c:
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer.h:
+	  videomixer: Refactor processing functions
+	  This allows easier plugging of optimized processing functions
+	  in the future, like for SSE or AltiVec.
+
+2010-01-11 13:26:32 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	* gst/matroska/matroska-mux.c:
+	  avimux: matroskamux: rename aac's stream-format to raw
+	  AAC's none stream-format has been renamed to raw, rename
+	  on avimux and matroskamux as well
+
+2010-01-11 12:07:29 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Only accept raw aac
+	  makes matroskamux reject aac streams that are not
+	  in raw format (stream-format=none)
+	  Fixes #598350
+
+2010-01-11 12:08:55 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: Only accept raw aac
+	  makes avimux reject aac streams that are not
+	  in raw format (stream-format=none)
+	  Fixes #598350
+
+2010-01-11 10:38:10 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Oops. The gpointer cast is needed because of the const qualifiers on the data elements
+
+2010-01-11 10:17:54 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Debug -> info level for a message for benchmarking index parsing
+	  The extra message output at higher levels affects the accuracy of the
+	  benchmark.
+
+2010-01-11 10:05:10 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Don't check for NULL pointers or cast to gpointer as this is not needed
+
+2010-01-08 13:55:05 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Refactor stbl sub-atom freeing. Free when index has been completely parsed.
+
+2010-01-08 14:32:06 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Avoid whitespace commits due to inconsistent GNU indent behaviour
+
+2010-01-11 00:10:34 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: remove newline at end of debug statement
+
+2010-01-08 19:26:21 +0100  Havard Graff <havard.graff@tandberg.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: Compiler warning fixes for Windows
+	  Just simple missing casts
+	  Fixes bug #606438.
+
+2010-01-08 18:04:14 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: fix seekpoints property copy-and-paste documentation
+
+2010-01-06 17:06:53 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflacenc.h:
+	  flacenc: optionally add a seek table
+	  API: GstFlacEnc:seekpoints
+	  Fixes #351595.
+
+2010-01-08 11:33:02 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Use more glib and be safer
+	  Be safer on sscanf by limiting string format sizes.
+	  Remove useless parameter and use g_strndup.
+
+2010-01-08 10:44:44 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Simplifying code
+	  Greatly simplify the IDIT chunk handling by using sscanf
+	  instead of 'manually' parsing. Also replaces strncasecmp and
+	  is_alpha/is_digit with glib versions.
+
+2010-01-08 10:18:30 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: it's feb for february
+	  Fix typo in last commit.
+
+2010-01-08 09:17:22 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Parse and post IDIT dates
+	  Parses and post date tags contained in IDIT chunks.
+	  Fixes #503582
+
+2010-01-07 17:25:05 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiofirfilter.c:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbasefirfilter.h:
+	  audiofxbasefirfilter: Add property for not draining the history on kernel changes
+	  Currently this only works if the kernel size doesn't change, in the future
+	  it will be possible to change the kernel size too without draining
+	  the complete history and without loosing anything.
+	  Partially based on a patch by
+	  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+2010-01-07 16:58:55 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: remove weird memcmp code
+	  Use plain memcmp for comparing memory instead of the custom buggy one.
+	  Fixes #606198
+
+2010-01-07 15:38:36 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/level/gstlevel.c:
+	  level: fix typo in 'message' property description
+
+2010-01-06 14:06:14 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: really use upstream timestamp if there is one
+	  See/fixes #603471.
+
+2010-01-06 13:45:59 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpg729pay.c:
+	  rtpg728pay: remove unused adapter peek
+
+2010-01-05 19:00:35 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* tests/check/elements/deinterlace.c:
+	  deinterlace: Improve passthrough tests
+	  Improve passthrough tests by forcing more specific
+	  interlaced/deinterlaced caps to be tested
+
+2010-01-05 18:22:49 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* tests/check/elements/deinterlace.c:
+	  deinterlace: Adds some docs to the new tests
+	  Adds some docs explaining the utility functions of the check
+	  tests of deinterlace
+
+2010-01-05 18:14:08 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* tests/check/elements/deinterlace.c:
+	  deinterlace: Adds tests for passthrough
+	  Adds tests for checking if the element really does
+	  passthrough in disabled mode and in auto (if the input is
+	  not interlaced)
+
+2010-01-05 07:50:51 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/deinterlace.c:
+	  deinterlace: Adds tests for caps acceptance
+	  Adds check unit tests for deinterlace for validating
+	  caps accepting and the expected caps output on the
+	  other pad
+
+2010-01-04 13:43:00 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/deinterlace.c:
+	  deinterlace: Adds basic check test
+	  Adds a basic check test for deinterlace element
+
+2010-01-04 15:44:28 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/qtdemux/Makefile.am:
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Add support for wave-style audio in qt.
+	  Uses gstriff to parse the wave headers appropriately. Tested with MS-ADPCM
+	  content.
+
+2009-12-31 17:09:03 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* tests/check/elements/rtp-payloading.c:
+	  tests: Add G.729 RTP payloader/depayloader test
+	  https://bugzilla.gnome.org/show_bug.cgi?id=606050
+
+2009-12-31 16:52:30 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtpg729pay.c:
+	  rtpg729pay: Simplify adapter usage
+	  https://bugzilla.gnome.org/show_bug.cgi?id=606050
+
+2009-12-31 16:27:30 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtpg729pay.c:
+	  rtpg729pay: Support ptime from caps
+	  https://bugzilla.gnome.org/show_bug.cgi?id=606050
+
+2009-12-02 19:35:21 +0530  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/README:
+	  rtp: Add maxptime to the README
+	  https://bugzilla.gnome.org/show_bug.cgi?id=606050
+
+2010-01-05 19:03:06 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpg723depay.c:
+	* gst/rtp/gstrtpg723depay.h:
+	  rtpg723depay: add G723 depayloader
+
+2010-01-05 19:02:39 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpg729depay.h:
+	  rtpg729depay: remove unused variable
+
+2010-01-05 18:33:25 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg723pay.h:
+	  rtpg723pay: rewrite payloader
+	  Handle all 3 packet sizes according to RFC 3551.
+	  Totally untested, we don't have a G723 encoder.
+	  Fixes #605882
+
+2010-01-05 11:47:20 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix chunk counter
+
+2010-01-04 19:44:53 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: more work at reducing loop overhead
+	  Try to avoid derefs when parsing the index. Save the state into the structures
+	  when we exit the loop instead of for each iteration.
+
+2010-01-04 16:33:30 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: cleanups and make duration more accurate
+	  Make the QtDemuxSample struct smaller by keeping the duration and the pts_offset
+	  as their 32 bit values.
+	  Make some macros to calculate PTS, DTS and duration of a sample.
+	  Deref the sample index less often by keeping a ref to the sample we're dealing
+	  with.
+
+2010-01-04 13:41:18 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: simplify logic to calculate duration
+	  Since we no longer store the timestamp and duration in nanoseconds, we can now
+	  simply store the duration as-is.
+
+2010-01-01 16:42:57 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Store timestamps in mov format in the index
+	  This allows faster building of the index upon seeks so that scaling of
+	  timestamps only occurs when actually needed.
+
+2009-12-18 13:54:46 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: make seeking in push mode work
+	  Move sample position checks into qtdemux_parse_samples where we can protect it
+	  with a lock.
+	  Refactor and make an qtdemux_ensure_index function.
+	  Rename qtdemux_do_push_seek to qtdemux_seek_offset in order to avoid confusion
+	  with gst_qtdemux_do_push_seek.
+
+2009-12-18 12:44:27 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: move error code out of normal flow
+
+2009-11-24 16:27:26 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux.h:
+	  qtdemux: Add push mode seek support for seeking to obtain the moov atom
+
+2010-01-05 12:22:09 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix on-npt-stop signal warnings for RDT
+	  The RDT manager does not implement this signal so we need to check for it before
+	  trying to connect to it.
+
+2010-01-05 09:47:00 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: fix memory leak in new uri handler code
+	  Don't leak a string everytime get_uri() is called and a device
+	  has been set. There's a limited number of devices, so just
+	  intern the string instead of doing more elaborate housekeeping
+	  and storing it in the instance struct or so.
+
+2010-01-01 14:10:49 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/avi/gstavimux.c:
+	  avimux: fix typo in warning message
+
+2010-01-04 09:28:36 -0300  Robert Weidlich <gnomebugzilla@robert.weidlich.cc>
+
+	* ext/shout2/gstshout2.c:
+	* ext/shout2/gstshout2.h:
+	  shout2send: Add 'public' property
+	  Adds a property to set 'public' flag on libshout, making
+	  the stream listed on the server's stream directory.
+	  Fixes #605269
+
+2009-12-30 14:14:55 +0530  Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Add tags for average and maximum bitrate
+	  Fixes #599300.
+
+2009-12-26 16:59:14 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	  audiofxbasefirfilter: do not try to alloc really large buffers
+	  When nsamples_out is larger than nsamples_in, using unsigned
+	  ints lead to a overflow and the resulting value is wrong and
+	  way too large for allocating a buffer. Use signed integers
+	  and returning immediatelly when that happens.
+
+2009-12-25 12:38:35 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videomixer/blend_ayuv.c:
+	  videomixer: optimize blend code some more
+	  Use more efficient formula that uses less multiplies.
+	  Reduce the amount of scalar code, use MMX to calculate the desired
+	  alpha value.
+	  Unroll and handle 2 pixels in one iteration for improved pairing.
+
+2009-12-24 22:59:09 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videomixer/blend_ayuv.c:
+	* gst/videomixer/blend_bgra.c:
+	* gst/videomixer/blend_i420.c:
+	* gst/videomixer/blend_rgb.c:
+	  videomixer: scale and clamp
+	  Scale and clamp to the max alpha values.
+
+2009-12-24 22:50:31 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/alpha/gstalpha.c:
+	  alpha: scale and clamp alpha to its full extend
+	  Convert the alpha value to 0->255 when setting and to 0->256 when using as
+	  a scaling factor. This makes sure we can reach the full opacity value of 0xff in
+	  all cases.
+
+2009-12-24 22:23:01 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix some comments, remove property check
+	  Fix some comments, clarify some FIXMEs
+	  Remove the on-ntp-stop signal check now that the jitterbuffer is in
+	  -good and we know that it supports this signal.
+
+2009-12-24 20:27:57 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: some trivial cleanups
+
+2009-12-24 17:04:28 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Parse all rtpinfo entries
+	  Do not forget to parse all rtp-info entries, instead of
+	  parsing the first one only.
+	  Fixes #605222
+
+2009-12-22 12:44:50 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: perf tag should map to GST_TAG_ARTIST
+
+2009-12-24 17:03:02 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/interleave/interleave.c:
+	  interleave: fix weird indentation
+
+2009-12-24 17:01:54 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph263ppay.c:
+	  rtph263ppay: use faster _adapter_copy() whem possible
+
+2009-12-24 17:01:15 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/examples/audiofx/firfilter-example.c:
+	  tests: use right type when passing vararg value
+
+2009-12-23 17:50:34 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacdec.h:
+	  flacdec: use a single decoder field for both push and pull mode
+
+2009-12-23 17:03:32 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: fix possible hanging in pull mode seeking
+	  A seek in multi-sink pipeline typically leads to several seek events in a row,
+	  which could lead to sending several newsegments in a row without intermediate
+	  flushing.  These would then accumulate, distort rendering times and as such
+	  lead to 'hanging'.
+
+2009-12-23 19:39:05 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtph264pay: fix uninitialized variable
+
+2009-12-23 13:09:54 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpdepay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtppcmupay.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpsirenpay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	  rtp: use boilerplate
+
+2009-12-23 00:38:05 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpL16pay.h:
+	  rtpL16pay: convert to baseaudiopayload
+	  Use GstRTPBaseAudioPayload as the base class. This saves a lot of code and fixes
+	  a bunch of problems that were already solved in the base class.
+	  Fixes #853367
+
+2009-12-23 00:30:49 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtppcmapay.c:
+	  rtppcmapay: the boilerplate macro sets parent_class
+
+2009-12-22 22:27:21 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpbin: avoid some structure copies
+	  Don't make copied in the getter and setter for SDES in the RTPSource. This
+	  avoids a couple of copies of the SDES structure when generating RTCP
+	  packets.
+
+2009-08-31 18:42:25 +0200  Pascal Buhler <pascal.buhler@tandberg.com>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpmanager: improve SDES handling
+	  Store SDES internally as a struct to support multiple PRIV values.
+	  Include all values set in SDES struct when sending RTCP SDES.
+
+2009-12-22 14:41:35 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph263depay.c:
+	  rtph263depay: add some fixmes
+
+2009-12-22 14:35:13 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph263depay.c:
+	  rtph263depay: baseclass handles timestamps for us
+
+2009-12-22 14:27:40 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph263depay.c:
+	  rtph263depay: reset start variable properly
+
+2009-05-29 15:49:27 +0300  Marco Ballesio <marco.ballesio@nokia.com>
+
+	* gst/rtp/gstrtph263depay.c:
+	* gst/rtp/gstrtph263depay.h:
+	  Drop the whole frame if a packet is lost.
+	  Fixes #582575
+
+2009-12-21 20:39:53 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtph264pay.h:
+	  rtph264pay: add option to insert PPS/SPS in streams
+	  Add a new spspps-interval property to instruct the payloader to insert
+	  SPS and PPS at periodic intervals in the stream.
+	  Rework the SPS/PPS handling so that bytestream and AVC sample code both use the
+	  same code paths to handle sprop-parameter-sets. This also allows to have the AVC
+	  code to insert SPS/PPS like the bytestream code.
+	  Fixes #604913
+
+2009-12-21 19:12:22 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 47cb23a to 14cec89
+
+2009-12-21 12:01:53 -0300  Jonathan Conder <j@skurvy.no-ip.org>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	* gst/qtdemux/qtdemux_types.c:
+	  qtdemux: Adds new tags
+	  Adds some new tags mapping to qtdemux.
+	  Fixes #599759
+
+2009-12-21 15:05:09 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: add property to remove pads automatically
+	  Add a property called autoremove to automatically remove the pads of sources
+	  that timed out.
+	  Fixes #554839
+
+2009-12-21 14:55:16 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  ssrcdemux: fix comparison
+	  A NULL means no pad was found.
+
+2009-11-08 11:49:14 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: Add GstURIHandler interface. Fixes #601143
+	  This allows using v4l2://[<device>]
+
+2009-12-20 17:24:47 -0800  Michael Smith <msmith@xiph.org>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: pass length parameter to g_convert
+
+2009-12-18 12:44:50 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska: Fix unitialized variable.
+	  Yes, it's stupid, but macosx compilers are even more stupid.
+
+2009-12-17 16:01:25 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_ayuv.c:
+	  videomixer: Fix assembly compilation on x86
+	  Fixes bug #604814.
+
+2009-12-17 17:37:03 +0100  Branko Čibej <brane at xbc.nu>
+
+	* gst/replaygain/rganalysis.c:
+	  rganalysis: fix timestamp rounding
+	  Use scaling function to round and avoid overflows.
+	  Fixes #604352
+
+2009-12-17 17:27:42 +0100  Tiago Katcipis <tiago.katcipis@digitro.com.br>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpg723pay.c:
+	* gst/rtp/gstrtpg723pay.h:
+	  rtp: add G723 payloader
+	  Fixes #597823
+
+2009-12-17 16:22:56 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_types.c:
+	  qtdemux: Fix ALAC codec_data parsing
+	  Fixes #604611
+
+2009-12-16 17:28:30 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Remove cpp style coments
+	  Removes // comments and replace them with /* */ comments
+
+2009-12-16 12:48:02 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: also consider BlockNumber indicated in index when seeking
+
+2009-12-16 12:43:27 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/ebml-read.c:
+	* gst/matroska/ebml-read.h:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: support push based mode
+	  Fixes #598610.
+
+2009-12-16 12:44:36 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/ebml-read.c:
+	  matroskademux: fix ebml read cache usage
+
+2009-12-16 10:50:32 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_ayuv.c:
+	  videomixer: Use movzbl instead of movzxb for moving one byte to a l register
+	  For some reason latest gcc/binutils accept movzxb here while
+	  movzbl would be correct and is the only thing accepted by older
+	  gcc/binutils.
+	  Fixes bug #604679.
+
+2009-12-16 06:59:01 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_ayuv.c:
+	  videomixer: src/dest are input and output of the AYUV blending MMX assembler
+
+2009-12-15 18:18:54 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiowsincband.c:
+	  audiowsincband: Use the same upper length limit as audiowsinclimit
+
+2009-12-12 17:00:50 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiowsincband.c:
+	* gst/audiofx/audiowsinclimit.c:
+	  audiowsinc{limit,band}: Allow much larger filter lengths now
+
+2009-12-11 12:27:32 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	  audiofxbasefirfilter: Fix frequency response calculation
+
+2009-12-08 14:57:02 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	  audiofxbasefirfilter: Remove dead assignments
+
+2009-12-06 16:58:51 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	  audiofxbasefirfilter: Add special processing functions for Mono/Stereo
+	  This provides another 7% speedup for the time domain convolution and 1.5%
+	  speedup for the FFT convolution on Mono input.
+	  This optimization assumes that the compiler simplifies calculations
+	  and conditions on constant numbers and unrolls loops with a constant
+	  number of repeats.
+
+2009-12-04 09:25:49 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbasefirfilter.h:
+	  audiofxbasefirfilter: Add a "low-latency" mode
+	  This will always use time-domain convolution, which lowers the latency.
+	  With FFT convolution it's always a multiple of the kernel length,
+	  with time domain convolution it's only the pre-latency of the filter kernel.
+
+2009-12-04 09:00:22 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	  audiofxbasefirfilter: Remove obsolete TODO comments
+
+2009-12-03 20:12:01 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	  audiofxbasefirfilter: Use samples everywhere instead of samples*channels sometimes
+
+2009-12-03 17:27:13 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/Makefile.am:
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbasefirfilter.h:
+	  audiofxbasefirfilter: FFT convolution implementation
+	  This provides a great speedup, especially the relationship between kernel
+	  length and processing size is now logarithmic instead of linear. Below a
+	  kernel size of 32 it's a bit slower, afterwards it's much faster:
+	  17     0.788000 -> 0.950000
+	  33     1.208000 -> 1.146000
+	  65     2.166000 -> 1.146000
+	  ...
+	  4097 107.444000 -> 1.508000
+	  For sizes smaller 32 the normal time-domain convolution is chosen,
+	  for larger sizes the FFT convolution is automatically used.
+	  Fixes bug #594381.
+
+2009-11-27 20:33:14 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbasefirfilter.h:
+	  audiofxbasefirfilter: Make most code parts independent of the processing functions and used convolution algorithm
+	  Only remaining part is the residue pushing, which will be fixed later.
+
+2009-11-26 15:17:27 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	  audiofxbasefirfilter: Optimize time-domain convolution
+	  Remove some redundant calculations, move comparisions out of
+	  inner loops, etc.
+	  This makes the convolution about 3 (!) times faster but
+	  processing time is of course still proportional to the
+	  filter size.
+
+2009-11-26 10:45:37 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	  audiofxbasefirfilter: Use _CAST macros in some places and do some calculations only once
+
+2009-11-25 18:12:05 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbasefirfilter.h:
+	  audiofxbasefirfilter: Rewrite timestamp tracking
+	  It's much simpler now and doesn't introduce accumulating rounding
+	  errors.
+
+2009-11-25 17:39:53 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbasefirfilter.h:
+	  audiofxbasefirfilter: Rename some variables and change comments
+
+2009-11-24 20:06:25 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	* gst/audiofx/audiofxbasefirfilter.h:
+	  audiofxbasefirfilter: Add const qualifier to the source data array
+
+2009-12-14 20:08:06 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/blend_ayuv.c:
+	* gst/videomixer/videomixer.c:
+	  videomixer: Add MMX implementations of the AYUV blending and color filling functions
+	  This provides a 20% speedup for blending and 100% for color filling.
+	  The blending can probably be optimized even more.
+
+2009-12-13 13:19:43 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/id3demux/id3v2frames.c:
+	  id3demux: prefer two letter ISO 639-1 code for extended comment
+
+2009-12-13 13:10:12 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix up language code extraction some more
+	  Quicktime uses ISO 639-2 for language codes, but GST_TAG_LANGUAGE
+	  is supposed to hold a ISO 639-1 code, so convert as needed using
+	  the new API from -base.
+	  See #602126.
+
+2009-12-13 12:45:22 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	  matroska: fix language code writing and extraction
+	  Matroska uses three-letter ISO 639-2B codes, but GST_TAG_LANGUAGE is
+	  supposed to contain two-letter ISO 639-1 codes, so use new language
+	  code mapping functions in -base to convert between those two as
+	  needed.
+	  Fixes #505823.
+
+2009-12-07 20:54:07 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: minor debug message changes
+	  Fix up a few debug messages so that it's clearer what they mean.
+
+2009-12-12 17:44:04 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  Revert "qtdemux: Correctly parse classification tags"
+	  This reverts commit cd883aa60c1133196a6ae052884d15c295c37dde.
+	  Previous code was correct, 4 is due to table and language code,
+	  not only language code
+
+2009-12-12 16:28:36 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Correctly parse classification tags
+	  In clsf atoms, the language code is 2 bytes long, not 4.
+
+2009-12-12 16:55:13 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: Dequeue current buffer on FLUSH_STOP and don't unref NULL buffers
+	  ... NULL buffers shouldn't really happen anymore when popping the
+	  buffer from GstCollectPads but better check for this and print a warning.
+
+2009-12-11 13:11:12 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_i420.c:
+	  videomixer: Fix stupid mistake in last commit
+
+2009-12-11 12:35:59 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_i420.c:
+	  videomixer: Don't do floating point math in the inner processing loop for I420 blending
+
+2009-12-10 18:43:44 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: handle NULL and empty transport strings
+	  When an RTSP extension returns NULL or an empty transport string, just ignore it
+	  and try to get the next possible transport. Fixes playback of RealMedia streams.
+
+2009-12-10 18:42:51 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: install event function on internal RTCP pad
+	  Install a custom event function on the internal RTCP pad so that we can reply
+	  TRUE to a latency event.
+
+2009-12-10 10:48:49 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_ayuv.c:
+	* gst/videomixer/blend_bgra.c:
+	* gst/videomixer/blend_rgb.c:
+	  videomixer: Remove wrong comments, copied from the I420 blend function
+
+2009-12-09 21:15:07 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: The queued duration is a signed integer
+	  ...and it will really be negative sometimes.
+
+2009-12-09 21:03:57 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: Only pop buffers from collectpads after they're fully consumed
+	  This decreases latency and memory usage because new buffers are only
+	  accepted by collectpads if there's no queued buffer.
+
+2009-12-09 20:42:44 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: Clean up position/duration handling
+	  Also use the last end time for closing the segment, not the
+	  start time of the last buffer.
+
+2009-12-09 16:50:02 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Close the segment on EOS if the real duration is known
+
+2009-12-09 16:46:18 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Update duration if current buffer is already after the old duration
+
+2009-12-09 16:43:41 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Drop buffers that are after segment stop
+	  ...and if this happened for all streams go EOS.
+
+2009-12-09 16:41:04 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Fix position tracking and sending of filler segments
+
+2009-12-09 16:15:09 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: Use gst_util_uint64_scale_int() for fps to seconds per frame calculations
+
+2009-12-08 17:34:15 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Keep the segment stop position for update newsegment events
+
+2009-12-04 14:42:49 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/ladspa/Makefile.am:
+	* ext/ladspa/gstladspa.c:
+	* ext/ladspa/gstladspa.h:
+	* ext/ladspa/gstsignalprocessor.c:
+	* ext/ladspa/gstsignalprocessor.h:
+	* ext/ladspa/load.c:
+	* ext/ladspa/search.c:
+	* ext/ladspa/utils.h:
+	  ladspa: Remove the sources from gst-plugins-good
+	  It's disabled anyway and the latest version of it is in
+	  gst-plugins-bad. Fixes bug #603779.
+
+2009-12-04 13:50:59 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: init current_entry in push mode
+	  Set the current_entry to 0 (instead of -1) in push mode so that we correctly
+	  calculate the current frame number and timestamp.
+	  Add some more debug info and fic the duration debug.
+
+2009-12-04 11:14:03 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix major memory leak when playing back rtsp video streams
+	  Don't forget to unref QoS, navigation and latency events when
+	  dropping them.
+
+2009-12-03 08:58:08 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: only send pending tags with newsegment events
+	  Send pending tags only from the streaming thread, just after we've sent
+	  the newsegment event, not with e.g. flush-start. This not only does the
+	  right thing, but also makes sure we're not trampling over variables set
+	  up in the streaming thread from the seeking thread in case someone tries
+	  to issue a seek just as the demuxer is parsing the headers.
+	  Fixes #601617. Spotted by Ognyan Tonchev.
+
+2009-12-03 17:49:55 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix debug message printf args
+	  Fixes debug message printf format to make it build in mac's gcc
+
+2009-12-02 13:33:20 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* ext/shout2/gstshout2.c:
+	  shout2: Convert delay correctly
+	  Use GST_MSECOND to convert delay in msecs to nanosecs
+	  Fixes #603547
+
+2009-12-01 19:24:02 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: reset segment info after flush
+	  Reset the segment info after a flush. We use the segment for handling QoS and if
+	  we don't reset the segment, QoS is basically disabled after a flushing seek.
+
+2009-12-01 15:07:06 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 87bf428 to 47cb23a
+
+2009-12-01 14:15:46 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From da4c75c to 87bf428
+
+2009-11-30 15:59:50 +0100  Aurelien Grimaud <gstelzz at yahoo dot fr>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: avoid buffer ref/unref pairs for CSRCs
+	  We ref the buffer before pushing it downstream in order to get the CSRCs of it
+	  after pushing. This causes performance problems when downstream elements want to
+	  change the metadata because the buffer needs to be subbuffered.
+	  Instead, read and store the CSRCs of the buffer in an array before pushing it
+	  and process the array after pushing the buffer. This allows us to remove the
+	  ref/unref pair.
+	  Fixes #603376
+
+2009-11-28 19:23:26 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/shout2/gstshout2.c:
+	* ext/shout2/gstshout2.h:
+	  shout2: use gstpoll for timeouts
+	  Use our own GstPoll based timeout instead of the shout sleep so that we can
+	  interrupt when doing a state change and shutting down.
+	  Fixes #602887
+
+2009-11-28 12:25:06 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  check: fix jitterbuffer check
+	  Make sure we set a base_time on the element.
+	  Fix the timeout to at least twice the jitterbuffer latency.
+	  Enable previously failing tests.
+	  Remove impossible checks.
+
+2009-11-27 18:55:20 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From 53a2485 to da4c75c
+
+2009-11-26 16:14:30 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264depay.h:
+	  rtph264depay: optionally merge NALUs into Access Units
+	  ... which may be expected/desired by some downstream decoders
+	  (and spec-wise highly recommended for at least non-bytestream mode).
+
+2009-11-26 17:29:03 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix timestamp datatype
+
+2009-11-25 10:38:23 -0600  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: avoid using wrong clock-rate
+	  Check for a valid clock-rate before attempting to estimate the npt
+	  stop time.
+
+2009-11-25 10:37:30 -0600  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: fix typo in comments
+
+2009-11-25 16:05:10 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  rtpjitterbuffertest: add one more test and file a bug now
+	  CHange the backwards test to always send first buffer first to have a define
+	  basetime. Add another test that sends buffers backwards to assert that only
+	  first sent buffer is keep and used as basetime. Disabled those tests still,
+	  as its not passing/failing consitently and file a bug for jitterbuffer.
+
+2009-11-25 10:17:34 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  jitterbuffertest: improve the test
+	  the tests are a bit more solid now but still not produce reliable results.
+	  Wonder if they are still flawky or if its a bug in jitterbuffer.
+
+2009-11-24 11:13:06 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: return error message on windows too.
+
+2009-11-24 10:58:49 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: first phase of fixing up error reporting for windows.
+
+2009-10-30 03:13:54 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: also set the suggested buf size for audio
+	  We were only setting the suggested buf size for video,
+	  we can set it for audio as well.
+	  This and 195e14529d80ef318ce3a778c1995efb11f266cd
+	  fix an issue that prevented seeking on large avi files
+	  on WMP (non-recent versions).
+
+2009-11-04 16:10:23 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavimux.h:
+	  avimux: fix indx duration for PCM audio
+	  GstBuffers for PCM audio usually contains more than
+	  1 sample, we need to get the total number of samples to set
+	  the indx duration.
+
+2009-11-04 16:04:10 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: Audio buffers should be picked earlier
+	  Adds a 0.5s advantage for audio buffers to being
+	  picked earlier for muxing.
+
+2009-11-24 16:40:19 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix push mode by making sure stbl information is available in next_entry_size ()
+
+2009-11-24 16:35:20 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix order of arguments in log message
+
+2009-11-24 15:51:21 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: fix spelling in comment
+
+2009-11-23 17:58:17 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* common:
+	  build system: Fix wrongly committed change to common/
+
+2009-11-10 10:26:07 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Ease debugging by removing a goto for an error message
+
+2009-11-14 15:52:09 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* common:
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Parse per sample rather than all at once but build complete index when seeking
+
+2009-11-04 17:31:15 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Save atom data for later use so it doesn't get freed after initial parsing
+
+2009-11-06 11:00:04 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Parse from the previously parsed sample up to sample n
+
+2009-11-04 17:04:22 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Make qtdemux_parse_samples () parse up to n samples
+
+2009-10-28 17:49:02 +0000  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Separate off stbl sub-atom initialisation
+
+2009-10-26 22:42:36 +0000  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Move variables into context in preparation for refactorisation
+
+2009-10-26 20:36:08 +0000  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix bug where stps is never parsed due to logic error
+
+2009-11-04 17:31:15 +0100  Robert Swain <robert.swain@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Port ctts from Gnode * to GstByteReader
+
+2009-10-23 13:06:44 +0100  Robert Swain <robert.swain@gmail.com>
+
+	* gst/qtdemux/qtatomparser.h:
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_dump.c:
+	* gst/qtdemux/qtdemux_dump.h:
+	* gst/qtdemux/qtdemux_types.h:
+	  qtdemux: Switch from QtAtomParser to GstByteReader
+
+2009-11-23 12:53:50 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix typo and grammar
+
+2009-11-22 19:30:58 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/dtmf/Makefile.am:
+	  Clean up LDFLAGS, LIBS, CFLAGS
+	  Fix order, fix variables that don't exist, like GST_LIBS_LIBS,
+	  use $(LIBM) instead of -lm, and move _LIBS from LDFLAGS to LIBADD.
+	  Spotted by Havard Graff.
+
+2009-11-20 10:31:47 -0500  Olivier Crête <tester@tester.ca>
+
+	* gst/dtmf/tone_detect.h:
+	  dtmf: Use _stdint.h from configure
+	  https://bugzilla.gnome.org/show_bug.cgi?id=602465
+
+2009-11-20 10:30:00 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: fix typo in mode enum description
+
+2009-11-20 11:25:49 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  docs: more links and better short description
+	  Fix spelling of GstRtpSsrcDemux to get it linked. Add more links. Change
+	  the short description to be more meaningful.
+
+2009-11-20 09:58:26 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/wavpackparse.c:
+	  wavpackparse: Fix unit test for recent position reporting changes
+
+2009-11-19 20:33:07 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/tone_detect.c:
+	* gst/dtmf/tone_detect.h:
+	  dtmf: Update dtmfdetect to make it MSVC friendly
+	  https://bugzilla.gnome.org/show_bug.cgi?id=602465
+
+2009-11-19 16:09:38 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackparse.c:
+	  wavpackparse: After pushing a frame, update last_stop to the end of the frame
+	  This improves position reporting, especially because of the fact that
+	  WavPack frames are usually 0.5-1.0 seconds long.
+
+2009-11-19 16:08:33 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackparse.c:
+	  wavpackparse: Allow pulling the last WavPack frame of a file
+	  Because of a >= instead of a >, that last frame of a WavPack file
+	  would never be parsed in pull mode.
+
+2009-11-19 10:30:43 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 0702fe1 to 53a2485
+
+2009-10-29 08:29:38 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	  qtdemux: Add more fields to SVQ3 caps
+	  qtdemux only added the whole stsd atom as 'codec_data'
+	  in its output caps for SVQ3. This patch makes it add
+	  the SEQH (inside a SMI atom) and a gamma field (taken
+	  from the gama atom) if available.
+	  Fixes #587922
+
+2009-11-18 17:55:42 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: Raise rank of muxer to PRIMARY
+
+2009-11-18 17:54:16 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/y4m/gsty4mencode.c:
+	  y4m: Raise rank of encoder to PRIMARY
+
+2009-11-18 17:54:02 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/law/alaw.c:
+	* gst/law/mulaw.c:
+	  law: Raise rank of encoders to PRIMARY
+
+2009-11-12 19:11:18 +0000  Bastien Nocera <hadess@hadess.net>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  Add user-id and user-pw properties
+	  So that one doesn't need to modify the URL to have access
+	  to authenticated RTSP streams.
+	  fixes #601728
+
+2009-11-18 12:22:10 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: use acquired flag when checking valid state
+	  Use the acquired field of the ringbuffer in get_time to know when we are in an
+	  invalid state. We don't clear the rate flag when releasing the ringbuffer so
+	  this values is not usable.
+	  Avoids some error messages being posted because the pulseaudio connection is
+	  down.
+
+2009-11-18 10:17:02 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: bump core requirement to 0.10.25.1 as well
+	  Make implicit requirement explicit.
+
+2009-11-18 12:53:44 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix bogus memory chunk size check
+
+2009-11-18 12:01:52 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: implement some more callbacks
+	  Implement some more callbacks for debugging purposes.
+
+2009-11-11 15:50:19 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: release lock before emiting signals
+	  Release the jbuf lock before emiting the request-pt-map signal to avoid
+	  deadlocks. We also need to catch the shutdown case when locking again.
+	  Fixes #593354
+
+2009-11-11 11:59:16 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpbvdepay.c:
+	* gst/rtp/gstrtpbvdepay.h:
+	  rtp: add BroadcomVoice depayloader
+
+2009-11-11 11:38:36 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpbvpay.c:
+	  rtpbvpay: add rfc reference
+
+2009-11-11 11:37:07 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpbvpay.c:
+	* gst/rtp/gstrtpbvpay.h:
+	  rtp: add BroadcomVoice payloader
+
+2009-11-09 12:17:34 +0100  Jan Urbański <wulczer@wulczer.org>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: properly finish the ECMA array
+	  The ECMA array with the file index was missing a mandatory end marker.
+	  Fixes bug #601242.
+
+2009-11-18 02:15:15 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  Use new still-frame API from gst-plugins-base
+
+2009-11-18 02:14:46 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* configure.ac:
+	  Bump gst-plugins-base requirement to 0.10.25.1
+
+2009-11-17 17:59:13 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: identify IMA adpcm in qt properly.
+
+2009-11-18 01:27:37 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  Back to development -> 0.10.17.1
+
+2009-11-17 01:53:08 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst-plugins-good.doap:
+	  Add release 0.10.17 to the doap file
+
+=== release 0.10.17 ===
+
+2009-11-17 01:25:30 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	  Release 0.10.17
+
+2009-11-17 00:18:22 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2009-11-13 02:07:25 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* configure.ac:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	* win32/common/config.h:
+	  0.10.16.3 pre-release
+
+2009-11-10 11:52:24 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Make sure to initialize variables before using them
+
+2009-11-09 20:06:03 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* ChangeLog:
+	* configure.ac:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	* win32/common/config.h:
+	  0.10.16.2 pre-release
+
+2009-11-09 15:20:00 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: free temporary buffer when changing state to NULL
+	  Free temporary allocations in the state change function and not
+	  only when the object is finalised.
+
+2009-11-09 11:40:25 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: only allocate as much temporary memory as needed for indirect decoding
+	  When we can't decode directly into the output buffer, make our temp buffers
+	  only as big as needed instead of allocating for the worst case scenario (well,
+	  we still alloc more than strictly needed for some cases, but significantly
+	  less than before).
+
+2009-11-05 23:46:58 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: printf format fix
+
+2009-11-05 23:44:27 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/raw1394/gst1394clock.c:
+	* ext/raw1394/gsthdv1394src.c:
+	  raw1394: printf format fixes
+
+2009-11-05 23:40:15 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/equalizer/gstiirequalizer.c:
+	  equalizer: printf format fix
+
+2009-11-04 22:19:58 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/Makefile.am:
+	* gst/dtmf/gstdtmf.c:
+	* gst/dtmf/gstdtmfdetect.c:
+	* gst/dtmf/gstdtmfdetect.h:
+	* gst/dtmf/tone_detect.c:
+	* gst/dtmf/tone_detect.h:
+	  dtmfdetect: Add DTMF tone detector
+	  It looks at raw audio data and emits messages when DTMF is detected.
+	  The dtmf detector is the same Goertzel implementation used in FreeSwitch
+	  and Asterisk. It is in the public domain.
+
+2009-11-05 12:13:44 -0300  Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: do not write empty INFO list
+	  avoid writing an empty INFO list chunk, both because
+	  it is useless and because vlc refuses to play the
+	  resulting file.
+
+2009-11-05 10:54:12 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/equalizer/gstiirequalizer.c:
+	  equalizer: Notify about band property changes caused by changing number of bands
+
+2009-11-05 10:45:59 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/equalizer/gstiirequalizer.h:
+	* gst/equalizer/gstiirequalizernbands.c:
+	  equalizer: Make changes to band properties and the number of bands threadsafe
+
+2009-11-05 10:30:46 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/equalizer/gstiirequalizer.c:
+	  equalizer: Fix stupid off by two bug
+
+2009-11-05 08:18:05 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/equalizer/gstiirequalizer.c:
+	  equalizer: Add band property to select the band filter type
+	  This allows per band configuration of a peak, low shelf or
+	  high shelf filter, which can be very useful if the band frequencies
+	  and widths are manually configured.
+
+2009-11-05 08:17:53 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/equalizer/gstiirequalizer.c:
+	  equalizer: Fix code style
+
+2009-11-05 08:03:13 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/equalizer/gstiirequalizer10bands.c:
+	* gst/equalizer/gstiirequalizer3bands.c:
+	* gst/equalizer/gstiirequalizernbands.c:
+	  equalizer: Some cleanup
+
+2009-11-04 22:21:35 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  dtmfsrc: Reject empty caps
+
+2009-11-04 22:21:22 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  dtmfsrc: Use log level for repeated debug messages
+
+2009-11-04 20:05:17 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  dtmfsrc: Allow for any samplerate
+
+2009-10-07 09:31:19 -0400  Gabriel Millaire <gabriel.millaire@collabora.co.uk>
+
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltpay.c:
+	  celtpay/depay : change GST_DEBUG_OBJECT to GST_LOG_OBJECT in pay_handle_buffer and depay_process
+
+2009-10-02 17:04:43 -0400  Gabriel Millaire <gabriel.millaire@collabora.co.uk>
+
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltdepay.h:
+	* gst/rtp/gstrtpceltpay.c:
+	  celtpay/depay: Negotiate parameters through caps
+	  celtdepay : added default framesize(480) channels(1) and clockrate(32000)
+	  depay_setcaps : now gets channels and framesize from string with default value
+	  depay_process : now adds timestamp to outbuf
+	  Added frame_size to GstRtpCeltDepay
+	  Changed some GST_DEBUG to GST_DEBUG_OBJECT or GST_LOG_OBJECT
+	  celtpay : getcaps : gets channel and framesize and sets caps
+	  Added frame-size to static caps for audio/x-celt
+
+2009-11-04 15:58:34 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/deinterlace/Makefile.am:
+	  deinterlace: Pull in CFLAGS and LIBS flags from -base before core before system.
+
+2009-10-15 16:33:24 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* po/Makevars:
+	  po: Don't create backup .po files
+	  As well as preventing creation of useless backup files, it works
+	  around a bug in gettext 0.17 on OS/X
+
+2009-11-04 16:47:42 +0100  Edward Hervey <bilboed@ihatesteve.local>
+
+	* gst/qtdemux/qtdemux_dump.c:
+	  qtdemux: init variables to make compiler on osx build bot happy
+
+2009-11-03 16:04:37 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux_dump.c:
+	  qtdemux: init variables to make compiler on osx build bot happy
+
+2009-11-03 17:35:15 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: don't allocate big arrays on the stack
+	  Add the arrays to the instance data and allocate on first use.
+
+2009-11-01 15:57:44 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: remove pointless call to gst_element_no_more_pads()
+
+2009-11-01 00:29:57 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/level/gstlevel.c:
+	  level: fix decay to be smooth
+	  The length not having any fractional part as it was promoted to gdouble after
+	  dividing two guint64.
+
+2009-11-01 00:29:24 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/level/gstlevel.c:
+	* gst/level/gstlevel.h:
+	  level: calculate the message-intervall when it changes
+
+2009-11-01 00:14:08 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/level/gstlevel.c:
+	  level: clocktime is a guint64, use right macro to init fields
+
+2009-11-01 00:10:01 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/level/gstlevel.c:
+	  level: use more g-style types
+
+2009-10-30 09:27:59 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Only set the volume on stream connection if pulse >= 0.9.20 is available
+	  In older versions the volume set during stream connection had
+	  no defined sematic and usually it was a relative volume. What
+	  was needed for our use case is an absolute volume though, otherwise
+	  the volume will be always decreased on stream connection if it's
+	  less than 100%.
+	  Since pulse 0.9.20 that volume is always an absolute volume if
+	  flat volumes are used and relative otherwise, which is the same
+	  as for pa_context_set_sink_input_volume().
+	  Relevant pulse changesets:
+	  http://git.0pointer.de/?p=pulseaudio.git;a=commit;h=f27a50691c8fe45bac7dd6b21fac91a359def3a1
+	  http://git.0pointer.de/?p=pulseaudio.git;a=commit;h=2501687579e359d5032a4d165b2ffc8f5b1b8ba6
+
+2009-10-27 18:07:18 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: use segment_full when we can
+	  Use segment_full so that we can pass the applied rate to the segment values. We
+	  will change the applied rate when we implement skip mode.
+
+2009-10-18 00:16:06 +0100  Robert Swain <robert.swain@gmail.com>
+
+	* gst/wavenc/gstwavenc.c:
+	  wavenc: Fix buffer offset by moving length incrementation
+
+2009-10-23 18:31:14 -0700  Michael Smith <msmith@songbirdnest.com>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: Create the video NSView in READY->PAUSED rather than NULL->READY
+
+2009-10-23 18:28:22 -0700  Michael Smith <msmith@songbirdnest.com>
+
+	* sys/osxvideo/Makefile.am:
+	  osxvideo: explicitly link to GST_LIBS
+
+2009-10-23 18:09:43 -0700  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/avi/Makefile.am:
+	* gst/matroska/Makefile.am:
+	* gst/wavparse/Makefile.am:
+	  Add dependencies of gstriff to things that link to gstriff, needed on Win32.
+
+2009-10-23 17:25:17 -0700  Michael Smith <msmith@songbirdnest.com>
+
+	* tests/examples/rtp/client-PCMA.c:
+	* tests/examples/rtp/server-alsasrc-PCMA.c:
+	  rtp examples: remove executable bits from C files.
+
+2009-10-23 11:21:44 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: disable all jitterbuffer tests for now
+	  Since even the one enabled seems to fail.
+
+2009-10-22 13:39:58 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/check/elements/rtpjitterbuffer.c:
+	  tests: also include the new test for prev commit
+
+2009-10-22 13:19:07 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	  tests: add a jitterbuffer test
+	  Tests pushing a few buffers in various order and asserting the order sent by the
+	  jitterbuffer. Contains two disabled tests that need more work.
+
+2009-10-22 12:30:14 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Dirac "muxing" units end on EOS too
+	  A Dirac muxing unit are all non-picture, non-end-of-sequence
+	  packets up to and including the first picture or eos packet.
+	  See http://www.diracvideo.org/wiki/index.php/ContainerFormatMappingGuidelines
+
+2009-10-22 02:09:08 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix compilation with debugging disabled
+	  total_idx is always evaluated.
+
+2009-10-19 21:59:46 +0300  Priit Laes <plaes@plaes.org>
+
+	* ext/libcaca/gstcacasink.h:
+	  cacasink: minor cleanups for header.
+	  Use G_BEGIN_DECLS macros, remove unused variables and fix typo.
+	  See #599018.
+
+2009-10-19 21:59:23 +0300  Priit Laes <plaes@plaes.org>
+
+	* ext/libcaca/gstcacasink.c:
+	  cacasink: exit properly when invalid driver has been selected.
+	  See #599018.
+
+2009-10-20 18:23:28 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Stop scanning at the last entry... and not the one before :)
+	  This ensures we actually push out everything
+
+2009-10-20 17:20:55 +0200  Andy Wingo <wingo@oblong.net>
+
+	  qtdemux: unpack more information into image/x-j2c caps
+	  * gst/qtdemux/qtdemux_fourcc.h: Add new fourccs for use by the mj2
+	  unpacker.
+	  * gst/qtdemux/qtdemux.c (qtdemux_parse_trak): Unpack JPEG2000 component
+	  mapping and channel definitions from the jp2h header. Will add
+	  component-map and channel-definitions elements to the caps if the
+	  component maps or channel definitions are nonstandard, where standard
+	  order means RGB, 444 packed YUV, or greyscale, with no alpha channel.
+	  Fixes #598915.
+
+2009-10-20 17:33:41 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/check/elements/deinterleave.c:
+	  tests: include stdio.h for sscanf
+
+2009-10-19 15:21:57 +0100  Bastien Nocera <hadess@hadess.net>
+
+	* ext/pulse/pulsesink.c:
+	  Fix the StreamVolume interface not being advertised
+	  gst_pulsesink_interface_supported() was missing a check for it.
+	  https://bugzilla.gnome.org/show_bug.cgi?id=598933
+
+2009-10-16 21:14:14 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/level/gstlevel.c:
+	  level: code cleanup
+	  Use gdouble instead of double. Calculate falloff_time once instead of twice.
+
+2009-10-18 15:52:02 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: MEMDUMP the junk blobs
+	  It will only actually pull the junk blobs from upstream if the memdump
+	  level is activated
+
+2009-10-18 15:51:34 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Some avi files have INFO lists in the headers.
+
+2009-10-18 16:02:01 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Don't seek on empty streams
+
+2009-10-18 15:50:39 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Ensure _calculate_durations_from_index only uses valid streams
+
+2009-10-18 15:49:29 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Only call convert function if we have strf.auds
+
+2009-10-18 15:48:06 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: Use first indexed stream for seeking.
+	  In the future, main_stream can be adjusted to contain the optimal stream
+	  as mentionned in the FIXME line 3440
+
+2009-10-18 15:46:48 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: Only expose streams that actually have something in it.
+	  This guarantees that in pull-mode, all streams have a valid index to
+	  work with.
+
+2009-10-18 15:40:37 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Properly mark presence of index.
+	  Instead of blindly saying we have an index, only do so if we have a
+	  non-empty index.
+
+2009-10-17 02:18:53 +0200  Lennart Poettering <lennart@poettering.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulse: never apply volume more than once
+	  Generally decisions on the volume of the stream should be done inside of
+	  PA, not inside of Gst. Only PA knows how volumes translate between
+	  devices and s on.
+	  This patch makes sure that all volumes set via the volume property are
+	  only applied *once* to the underlying stream. After applying them the
+	  client side will not store them anymore. This should make sure that
+	  really only user-triggered volume changes are forwarded to server, but
+	  the client never tries to save/restore the volume internally.
+	  Fixes bug #595231.
+
+2009-10-17 08:55:16 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/plugin.c:
+	  pulsesink: Initialize gettext for the translated strings in plugin_init()
+
+2009-10-17 00:10:30 +0200  Lennart Poettering <lennart@poettering.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulse: use 'performer' as a fallback for 'artist' tag
+
+2009-10-17 00:09:36 +0200  Lennart Poettering <lennart@poettering.net>
+
+	* ext/pulse/pulsesink.c:
+	* po/POTFILES.in:
+	  pulse: when constructing a stream title from tag data make sure it is translatable
+
+2009-10-17 00:06:15 +0200  Lennart Poettering <lennart@poettering.net>
+
+	* ext/pulse/pulsemixerctrl.c:
+	  pulse: loop while connecting to server
+	  pthread does not guarantee that there are no spurious condition variable
+	  wakeups, neither does pa_threaded_mainloop_xxx() which is a wrapper
+	  around it. So we need to loop around the _wait() function to make sure
+	  we get the right wakeup.
+	  Also, unify the order of the wait loops across the file.
+
+2009-10-17 00:05:10 +0200  Lennart Poettering <lennart@poettering.net>
+
+	* ext/pulse/pulsemixerctrl.c:
+	* ext/pulse/pulseprobe.c:
+	  pulse: mainloop creation can fail too, so handle that
+
+2009-10-17 00:03:06 +0200  Lennart Poettering <lennart@poettering.net>
+
+	* ext/pulse/pulsemixerctrl.c:
+	  pulse: adjust CHECK_DEAD_GOTO macro to glib style
+
+2009-10-16 17:28:42 +0200  Lennart Poettering <lennart@poettering.net>
+
+	* ext/pulse/pulsemixerctrl.c:
+	* ext/pulse/pulsemixerctrl.h:
+	* ext/pulse/pulseprobe.c:
+	* ext/pulse/pulseprobe.h:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	* ext/pulse/pulsesrc.h:
+	  pulse: make a few things smaller by making them bitfields
+
+2009-10-16 17:26:41 +0200  Lennart Poettering <lennart@poettering.net>
+
+	* configure.ac:
+	  pulse: bump minimum libpulse version to 0.9.10
+	  Older versions than 0.9.10 are really really old and buggy. Drop
+	  compatibility with them. Nobody should run anything that old.
+	  Also see: https://bugzilla.gnome.org/show_bug.cgi?id=595029
+
+2009-10-16 18:18:31 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/debugutils/gstdebug.c:
+	  debugutils: register pushfilesrc element
+
+2009-10-16 17:28:09 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavimux.h:
+	  avimux: support (some) VBR audio muxing
+	  AVI format can handle VBR audio provided audio chunks are of fixed duration
+	  (cfr fixed duration video frames).  Apply this approach to (always) parsed
+	  raw AAC and (if parsed) to MPEG-1/2 audio.
+	  See #368681.
+
+2009-10-16 13:41:45 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fix branch hints
+	  Remove inappropriate branching hints and add some new ones.
+
+2009-10-16 12:33:04 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fix regression in indirect decode path
+	  Revert variable name back to what it was before the G_LIKELY was
+	  added (in commit 69c24fb9). The code works better that way.
+
+2009-10-16 02:47:38 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fix regression with certain formats
+	  Fix regression introduced by previous commit (#598517).
+
+2009-10-15 19:49:55 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: don't use decompress structure members we shouldn't be using
+
+2009-10-14 17:53:52 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: remove some unused members from jpegdec instance structure
+
+2009-10-16 11:53:38 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtpmanager/Makefile.am:
+	* gst/udp/Makefile.am:
+	  build: use gst-glib-gen.mak to fix the glib build rules.
+	  The build rules in glib-gen.mak were using pattern rules in a non save way.
+
+2009-10-16 10:15:35 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 85d1530 to 0702fe1
+
+2009-10-15 21:04:02 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: adjust flow return aggregation to updated loop_data
+	  In particular, each stream is now treated separately, and one stream's
+	  EOS should not lead to overall EOS.
+
+2009-10-15 11:52:35 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: check some more atom sizes prior to parsing
+
+2009-10-15 13:19:13 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtsp: handle events in TCP mode
+	  We need to handle events in TCP mode so that we can reply to the LATENCY event
+	  with TRUE.
+
+2009-10-15 11:24:45 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: add missing argument in debug message
+
+2009-10-14 18:58:06 +0200  Marvin Schmidt <marv@exherbo.org>
+
+	* tests/check/elements/flvmux.c:
+	  flvmux: Use loop test to prevent timeout on slow machines
+	  Partially fixes bug #597739.
+
+2009-10-14 16:15:48 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: forward events into the rtpbin
+	  Only catch the SEEK event on the srcpad and let other events enter the rtpbin.
+
+2009-10-14 11:33:24 -0300  Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Fix late tags finding
+	  Use the correct taglist variable when notifying of late tags.
+
+2009-10-14 13:09:03 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: use GstIndex for (limited) seeking in push mode
+	  ... but disable this for now.  Although it basically works fine,
+	  user experience might be shaky (depending on taste), since there
+	  is no keyframe info in push mode.
+
+2009-10-14 13:08:47 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: add GstIndex support
+
+2009-10-14 11:55:33 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: also determine duration in push mode
+
+2009-10-14 11:54:44 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux.h:
+	  qtdemux: add GstIndex support
+
+2009-10-14 07:38:26 -0300  Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: Set duration on buffers
+	  Use framerate to estimate duration of buffers.
+	  Fixes #590362
+
+2009-10-14 12:28:55 +0200  Håvard Graff <havard.graff at tandberg.com>
+
+	* gst/rtpmanager/gstrtpptdemux.c:
+	  rtpptdemux: only forward the lost-event to the last seen pt-number
+	  forward all events on all pads except for the PacketLost event, which we want to
+	  forward to the last seen pt pad.
+	  Fixes #598377
+
+2009-10-06 22:28:50 +0300  René Stadler <mail@renestadler.de>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: set desired minreq value to segsize/latency-time
+	  If we let the daemon decide freely by passing -1, we end up always getting 20ms.
+	  We want to set this value because in some cases we want to select a higher
+	  latency-time in order to save power.
+	  Fixes #597601
+
+2009-10-14 10:41:21 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From a3e3ce4 to 85d1530
+
+2009-10-13 18:33:34 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* tests/check/pipelines/flacdec.c:
+	  tests/pipeline/flac: Fix build on macosx 10.5
+
+2009-10-13 18:19:32 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: demote some warnings to debug
+
+2009-10-13 17:47:40 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/avi-ids.h:
+	  avi: add new avi flag we might want to use
+
+2009-10-13 17:46:22 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: calculate suggested buffer size
+	  Calculate the suggested buffer size based on the largest chunk in the file.
+	  See #597847
+
+2009-10-13 17:45:14 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	  avimux: add jpeg2000 to allowed caps
+
+2009-10-13 17:41:13 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: add debug for the superindex offsets
+
+2009-10-13 16:02:37 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix uninitialized variable warning
+	  Fix another bogus may-be-used-uninitialized warning in qtdemux
+
+2009-10-13 13:08:33 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavimux.c:
+	* gst/avi/gstavimux.h:
+	  avi: lower max file size
+	  Make a constant of the max file size and lower the value to what ffmpeg does,
+	  hopefully improving compatibility with windows media player.
+	  See #597847
+
+2009-10-13 01:02:15 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fix bogus warning about discont flag on first buffer
+	  The very first buffer should always have the DISCONT flag set, no
+	  need to warn about that. Only warn if we get a DISCONT buffer in
+	  non-packetised mode and we already have some data.
+
+2009-10-13 00:41:57 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fix crash for unusual vertical chroma subsampling factors
+	  Fixes #597351.
+
+2009-10-13 00:12:42 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix uninitialized variable warnings
+	  The gcc on the OS/X buildbot complains about these variables not being
+	  initialized, even though they can't possibly actually be used
+	  uninitialized.
+
+2009-10-11 11:35:23 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  dtmf: fix warnings in macosx snow leopard
+
+2009-10-10 00:37:08 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fixes warning building in snow leopard
+
+2009-10-09 17:12:46 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: also consider Quicktime text subtitles
+
+2009-10-09 17:02:57 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: provide language tag for stream
+
+2009-10-09 16:30:57 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: refactor common parts in track parsing
+
+2009-10-09 16:21:03 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux.h:
+	  qtdemux: refactor buffer processing and sending
+	  ... so it can be used in both pull and push based mode.
+
+2009-10-08 13:39:25 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: extract palette data for dvd subpicture streams
+	  ... and send it downstream using custom dvd event
+
+2009-10-07 14:03:17 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux.h:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	  qtdemux: support 3GPP timed text subtitles
+	  In particular, also make subtitle support less subp(icture)-centric.
+
+2009-10-07 16:15:55 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: NULL is not a valid taglist
+
+2009-09-23 17:20:25 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	  qtdemux: recognize some more encypted track cases
+
+2009-10-09 15:59:25 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/id3demux/id3tags.c:
+	  id3: fixes warnings building on macosx
+	  Another round on the formating of that debug line.
+
+2009-10-09 14:44:02 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/id3demux/id3tags.c:
+	  id3: cast pointer math results to glong
+
+2009-10-09 14:37:32 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/flac/gstflacdec.c:
+	  flac: apparently on some platforms a FLAC__uint64!=guint64
+
+2009-10-09 14:21:09 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	  buikd: explicitely cast, to tell some compilers that this is not long int
+
+2009-10-09 13:38:17 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/flac/gstflacdec.c:
+	* gst/id3demux/id3tags.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	  build: don't cast, but use the right format specified instead
+	  This correct some of the previous macos fixes.
+
+2009-10-09 12:40:47 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* ext/dv/gstdvdemux.c:
+	  dv: fix warnings on macosx
+
+2009-10-09 12:25:19 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacenc.c:
+	  flac: fix warnings on macosx
+
+2009-10-09 12:19:35 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* ext/annodex/gstcmmldec.c:
+	* ext/annodex/gstcmmlenc.c:
+	  annodex: fix warnings in macosx
+
+2009-10-09 12:14:22 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* sys/osxvideo/cocoawindow.m:
+	  osxvideo: fix a warning doing a cast
+
+2009-10-09 12:11:12 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* sys/osxaudio/gstosxringbuffer.c:
+	  osxaudio: fix warnings on macosx
+
+2009-10-09 12:01:10 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/rtp/gstrtpvrawpay.c:
+	  rtpvrawpay: fix warning on macosx
+
+2009-10-09 11:57:59 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: fix warning on macosx
+
+2009-10-09 11:54:03 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix warnings building on macosx
+
+2009-10-09 11:42:36 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/id3demux/id3tags.c:
+	  id3demux: fix printf warnings on macosx
+
+2009-10-09 11:30:00 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix warning in macosx making the format portable
+
+2009-10-09 10:51:29 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/audiofx/audiofxbasefirfilter.c:
+	  audiofx: use G_GUINT64_FORMAT to fix warnings on OSX
+
+2009-10-09 10:11:38 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* sys/osxaudio/gstosxringbuffer.c:
+	  osxaudio: Fixes build on macosx snow leopard.
+
+2009-10-09 11:34:16 +0200  Pau Garcia i Quiles <pgquiles@elpauer.org>
+
+	* sys/v4l2/gstv4l2object.h:
+	  v4l2: Include sys/ioctl.h for the V4L ioctl requests
+	  Old videodevice2.h kernel headers used ioctl stuff without
+	  including ioctl.h, making compilation fail on older systems.
+	  Note: Including ioctl.h here is only a workaround for old kernel
+	  headers, should be removed once everybody has new enough headers.
+	  Fixes bug #597867.
+
+2009-10-09 00:14:07 +0100  Jan Schmidt <jan.schmidt@sun.com>
+
+	* configure.ac:
+	* tests/check/elements/level.c:
+	  check: Make the level unit test succeed on Solaris 10
+	  Add a configure check for functional isinf() and fpclass(), and
+	  use fpclass() where possible when isinf() is not available.
+
+2009-05-16 13:52:50 +0300  René Stadler <rene.stadler@nokia.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: fix strstr() usage on possibly unterminated string
+
+2009-10-08 16:16:14 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/level.c:
+	  check: Link against LIBM and include math.h for isinf()
+
+2009-10-07 21:51:38 +0100  Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+
+	* sys/oss/gstossaudio.c:
+	  oss: Downgrade the rank of osssrc to SECONDARY
+	  which is the same rank as osssink has.
+	  Fixes bug #597730.
+
+2009-10-08 10:59:53 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 19fa4f3 to a3e3ce4
+
+2009-10-08 10:20:09 +0100  Jan Schmidt <jan.schmidt@sun.com>
+
+	* gst/avi/gstavidemux.c:
+	* gst/wavparse/gstwavparse.c:
+	  avi/wav: Fix some compiler warnings about incompatible pointers.
+
+2009-10-05 17:36:55 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/multifile/gstmultifile.c:
+	  multifile: Fix plugin description
+
+2009-10-07 14:03:20 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/annodex/gstcmmlutils.c:
+	* ext/jpeg/gstjpegdec.h:
+	* ext/jpeg/gstjpegenc.h:
+	* gst/apetag/gstapedemux.c:
+	* gst/debugutils/tests.c:
+	* gst/id3demux/id3v2frames.c:
+	* gst/qtdemux/qtdemux.c:
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtsp/gstrtpdec.c:
+	* tests/examples/spectrum/demo-audiotest.c:
+	* tests/examples/spectrum/demo-osssrc.c:
+	* tests/examples/spectrum/spectrum-example.c:
+	  build: fprintf, sprintf, sscanf need stdio.h
+
+2009-10-07 00:33:49 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/equalizer/gstiirequalizer.c:
+	  equalizer: use shelfing filters for first and last band
+	  Refactor the filter setup. Add two new filters with shelf characteristics for
+	  first and last band. Change gain calculation as recommended in the quoted
+	  document (no qrt needed). Rename variables to match the formulas in the
+	  document.
+
+2009-10-02 23:51:29 +0300  René Stadler <mail@renestadler.de>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: guard fragment size with a lower limit based on latency-time
+	  In case that the pulse daemon runs the source device at a relatively low fixed
+	  fragment size compared to the requested latency-time, configure the ring buffer
+	  segsize to the largest integer multiple of the fragment size that is still
+	  smaller than or equal to the requested latency-time.
+	  Fixes bug #597463.
+
+2009-10-06 17:40:47 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: comment/logging cleanups and more branch guides
+
+2009-10-05 22:43:11 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/equalizer/gstiirequalizer.c:
+	  equalizer: fix filter history usage. Fixes #597397
+	  The process functions where overwriting the history for each channel. Also pull
+	  some static things out of the inner loop.
+
+2009-10-05 16:07:24 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: use locking around the sessions
+
+2009-10-05 11:46:08 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: make sure compatible brands buffer exists before dereferencing it
+
+2009-10-04 21:59:24 +0200  Robert Swain <robert.swain@gmail.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix printf warnings on OSX
+	  Cast variables passed to printf to avoid warnings about incorrect
+	  formats (most likely caused by sizeof returning a size_t).
+	  Fixes #597348.
+
+2009-10-02 00:23:34 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: remove internal genre table
+	  No need to maintain our own genre table in qtdemux. The genres are
+	  identical to the ID3 genres, so we can just use libgsttag's
+	  gst_tag_id3_genre_get() to look them up.
+
+2009-10-03 17:18:28 +0200  Robert Swain <robert.swain@gmail.com>
+
+	* gst/avi/gstavidemux.c:
+	  Fix printf formats to avoid warnings in avidemux. Fixes #597214
+	  https://bugzilla.gnome.org/show_bug.cgi?id=597214
+
+2009-10-03 09:52:57 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Change one GST_WARNING to a GST_DEBUG
+
+2009-10-02 14:37:54 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	* gst/flv/gstflvparse.c:
+	  flvdemux: If there's no audio stream after 6 seconds of video signal no-more-pads
+	  ...and the other way around. Also ignore any audio/video streams that appear
+	  after no-more-pads.
+	  Fixes bug #597091.
+
+2009-10-02 14:37:40 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	* gst/flv/gstflvparse.c:
+	  flvdemux: Make sure to only signal no-more-pads a single time
+
+2009-10-02 22:55:45 +0300  René Stadler <mail@renestadler.de>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	  pulse: rename pa_buffer_attr variables
+	  Makes it much easier to see what is going on and is a lot less error prone.
+
+2009-10-02 18:25:16 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	  rtp: add missing include to fix the build
+
+2009-10-02 13:15:59 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	  videofilter: add G_OBJECT_WARN_INVALID_PROPERTY_ID to property setter
+
+2009-10-02 13:10:44 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/level/gstlevel.c:
+	  level: don't give wrong number of fields in the message docs
+
+2009-10-01 12:52:40 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: cache latency in nanoseconds
+	  Cache the latency in nanoseconds units to avoid having to convert the
+	  milliseconds value to nanoseconds all the time.
+
+2009-10-01 12:12:09 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  jitterbuffer: handle -1 input timestamps
+	  Don't try to check a -1 timestamp against the max delay.
+
+2009-10-01 10:54:55 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/avi/gstavidemux.c:
+	  avi: don't misues perf-category and remove unused ext category
+	  The performance category is meant to be used to audit codepaths that lead to bad
+	  performance (e.g. copies, conversion that can be avoided).
+	  Remove the event category which is not used.
+
+2009-09-16 14:23:24 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	  rtpg729pay/depay: Demote per-buffer debug messages to log level
+
+2009-09-16 14:16:27 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtpg729pay.c:
+	  rtpg729pay: Don't leak incoming buffers after subbuffering them
+
+2009-09-16 13:57:05 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpg729pay.c:
+	  rtpg729pay/depay: Add debug categories
+
+2009-09-16 13:55:19 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtpg729pay.c:
+	  rtpg729pay: Remove long unneeded define replacement
+
+2009-09-30 18:06:07 +0100  Christian F.K. Schaller <christian.schaller@collabora.co.uk>
+
+	* ext/dv/Makefile.am:
+	  Update makefile with missing header file
+
+2009-09-30 18:45:17 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/examples/rtp/client-H263p-AMR.sh:
+	* tests/examples/rtp/client-H263p-PCMA.sh:
+	* tests/examples/rtp/client-H264-PCMA.sh:
+	* tests/examples/rtp/client-PCMA.sh:
+	* tests/examples/rtp/server-alsasrc-PCMA.sh:
+	* tests/examples/rtp/server-v4l2-H263p-alsasrc-AMR.sh:
+	* tests/examples/rtp/server-v4l2-H264-alsasrc-PCMA.sh:
+	  rtp: Use autoaudio{sink,src} instead of alsa in the examples
+
+2009-09-29 17:51:04 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: don't leak output buffers on decoding errors
+	  The setjmp handles libjpeg error. Free the outputbffer if we don't need it.
+
+2009-09-29 00:01:59 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fix 'unused variable' compiler warning when compiling with GST_DISABLE_GST_DEBUG
+
+2009-09-23 14:25:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avi: small cleanups
+
+2009-09-23 13:57:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avi: fix timestamping in some audio streams
+	  For vbr audio streams we need to use the number of blocks to calculate the
+	  timestamps.
+	  When the allocation of additional index memory fails, don't throw away what
+	  we had before.
+	  Various cleanups.
+
+2009-09-23 12:56:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avi: add support for ODML indexes again
+
+2009-09-22 22:12:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avi: implement index scanning
+	  Implement scanning of the file when we can parse the index.
+	  Some refactoring of common code.
+	  Cleanups and comments.
+	  Remove some reimplemented code.
+	  Remove index massage code and put a FIXME where we should do something
+	  equivalent later.
+
+2009-09-22 18:18:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avi: fix reverse playback
+
+2009-09-22 17:42:48 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avi: fix prev keyframe search and cleanups
+
+2009-09-22 14:51:30 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avi: remove code that got converted
+
+2009-09-22 14:44:42 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avi: more cleanups
+	  Remove some duplicate counters.
+	  Be smarter when updateing the current the timestamp and offset in the stream
+	  because we can reuse previously calculated values when simply go forward one
+	  step.
+	  Correctly set metadata on outgoing buffers.
+
+2009-09-22 12:35:30 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: small cleanups
+
+2009-09-22 01:28:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avi: fix read offset and cleanups
+
+2009-09-21 18:04:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avi: rewrite index playback
+	  disable code, start on reimplementing loop based operation.
+	  Rewrite the index handling so that all streams use their own index for decoding
+	  media.
+
+2009-09-21 15:35:55 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: add new index parsing code
+	  Add a new function and datastructure to parse and hold the index entries on a
+	  per stream base. Also avoid doing too much work trying to figure out the
+	  timestamps and durations as we can trivially do that later.
+	  Less information in the entries makes them 2 times smaller and not doing too
+	  much work makes this code about 12 times faster than the regular case.
+	  Hook in the new function alongside the existing function for comparison until
+	  the rest of the code is updated to handle the new index datastructure.
+
+2009-09-28 16:29:45 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpeg: handle more libjpeg return values, add some more branch hints
+	  Also remove unused size variable in _chain().
+
+2009-09-25 19:21:32 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: some optional QT specified stsd MPEG-4 atoms also apply to H264
+	  Fixes #596319.
+
+2009-09-25 16:40:31 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: only send tag events downstream after newsegment
+
+2009-09-25 14:14:03 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: if transport protocol unsupported, try another one
+	  Also change error message to more accurately reflect cases in which
+	  it can occur.
+
+2009-09-25 11:54:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: add durations modulo 1<<32
+	  For calculating the durations of each sample, we are supposed to add each
+	  duration modulo 1<<32 so make the elapsed time counter a uint32.
+	  Fixes #595942
+
+2009-09-24 20:38:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: small cleanup
+
+2009-09-24 19:33:39 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtatomparser.h:
+	  qtdemux: don't use core API that doesn't exist yet
+	  There's no gst_byte_reader_has_remaining() yet. Fixes build.
+
+2009-09-24 13:20:50 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtatomparser.h:
+	  qtdemux: map some atomparser functions to their new bytereader equivalents
+	  Now that GstByteReader has unchecked and inlined variants as well, map
+	  atomparser functions to their respective bytereader equivalents.
+
+2009-08-25 12:11:28 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtatomparser.h:
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_dump.c:
+	  qtdemux: add qt_atom_parser_has_chunks() and fix indentation
+
+2009-08-20 18:21:59 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: bail out instead of trying to alloc silly index sizes
+	  If it looks like we would be allocating a silly size for our sample
+	  index, just bail out instead of trying to allocate it. Helps with
+	  broken or fuzzed files where we might end up trying to malloc a
+	  couple of hundred MBs otherwise.
+
+2009-08-20 16:47:25 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: error out correctly if we don't even have enough bytes for an atom header
+
+2009-08-20 15:39:00 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: init fourcc to 0 as well to avoid invalid reads when printf'ing error message
+
+2009-08-20 01:39:17 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtatomparser.h:
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_dump.c:
+	  qtdemux: add qt_atom_parse_has_remaining() to avoid overflows with _get_remaining()
+
+2009-08-20 01:21:04 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: use GstByteReader when parsing tkhd atom
+
+2009-08-19 19:13:38 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: use unsigned ints for node length and do more sanity checking of the atom length
+
+2009-08-19 01:36:33 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtatomparser.h:
+	* gst/qtdemux/qtdemux_dump.c:
+	* gst/qtdemux/qtdemux_dump.h:
+	* gst/qtdemux/qtdemux_types.h:
+	  qtdemux: use GstByteReader for atom dumping and fix a few bugs
+
+2009-08-21 14:21:08 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: move stco, stts, stss and stps atom parsing over to GstByteReader
+	  Make sure we don't read beyond the atom boundary. Note that the code
+	  behaves slightly differently in the corner case where there is not
+	  enough atom data for the specified number of samples (n_samples_time)
+	  in the atom, but still enough data to fill the pre-allocated index of
+	  n_samples entries: before we would just stop parsing the stts data
+	  and continue, whereas now we will likely error out. This should not
+	  be a problem in practice though. We could maintain the old behaviour
+	  by doing reads with a size check inside the loop if needed.
+
+2009-06-30 19:51:15 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: use bytereader to parse stsz and stsc atoms
+	  Use GstByteReader to parse stsz and stsc chunks, and check size of
+	  available data before parsing it, instead of blindly assuming there
+	  will be enough data. Fixes crashes with some fuzzed/broken files.
+
+2009-08-15 20:38:40 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtatomparser.h:
+	  qtdemux: add qt_atom_parser_get_offset() and optimise _peek_sub()
+
+2009-07-01 13:49:57 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/Makefile.am:
+	* gst/qtdemux/qtatomparser.h:
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: add QtAtomParser, an inlined GstByteReader variant
+
+2009-09-23 17:19:34 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	  matroskademux: use proper order for no-more-pads and newsegment and tag sending
+
+2009-09-23 09:50:37 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: sprinkle a few branch prediction macros
+
+2009-09-22 15:03:20 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	* gst/avi/gstavidemux.c:
+	* gst/flv/gstflvparse.c:
+	* gst/id3demux/id3v2frames.c:
+	  Fix compile warnings with gcc 4.0.1.
+
+2009-09-22 11:48:50 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: Don't get stuck in an infinite loop with Dirac
+	  At the end, Dirac streams have an EOS packet with 0 length.
+	  Don't ever sit in an infinite loop when processing one. Allows
+	  muxing Dirac into mkv to complete successfully.
+
+2009-09-22 11:03:46 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* .gitignore:
+	  Update .gitignore
+
+2009-09-22 11:02:02 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/videomixer/Makefile.am:
+	  videomixer: fix up Makefile some more
+	  Remove CFLAGS from LIBADD and make order of the various CFLAGS and
+	  LIBS at least consistent with each other.
+
+2009-09-22 08:02:48 +0200  Brian Cameron <brian.cameron@sun.com>
+
+	* gst/videomixer/Makefile.am:
+	  videomixer: Add $(GST_PLUGINS_BASE_LIBS) to LDFLAGS for linking libgstvideo
+	  Fixes bug #595897.
+
+2009-09-21 18:09:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avi: fix timestamps in push mode
+
+2009-09-18 17:26:42 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: add a G_UNLIKELY and put perf-cat log to code path that copies
+
+2009-09-21 12:32:51 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avi: add some performance measurements
+	  Measure the performance of various index and header parsing steps to the
+	  PERFORMANCE debug category.
+
+2009-09-18 11:53:12 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	  speexdec: allow for unknown varying number of frames per buffer
+	  In particular, this caters for RTP payloads with multiple frames
+	  per packet.
+
+2009-09-18 11:45:06 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/speex/gstspeexdec.c:
+	  speexdec: use correct sample size in conversions
+
+2009-09-18 11:43:46 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/speex/gstspeexenc.c:
+	  speexenc: fix buffer time and duration for multiple frames per packet
+
+2009-09-18 14:22:02 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: some logging cleanup to help understanding the index parsing overhead
+
+2009-09-16 13:28:27 -0700  David Schleef <ds@schleef.org>
+
+	* sys/osxaudio/Makefile.am:
+	  osxaudio: link against GST_BASE_LIBS
+
+2009-09-15 17:24:24 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtpg729pay.c:
+	  rtpg729pay: Fix adapter leak
+	  The adapter would be leaked if it was empty and the data could be pushed out directly.
+
+2009-09-15 10:04:30 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: Don't dereference NULL pointers
+	  pa_stream_get_timing_info() can return NULL.
+	  Fixes bug #595220.
+
+2009-09-15 10:01:54 +0200  David Henningsson <gnome.web@epost.diwic.se>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Don't dereference NULL pointers
+	  pa_stream_get_timing_info() can return NULL.
+	  Fixes bug #595220.
+
+2009-09-14 16:05:30 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: handle stream events
+	  Handle stream events and request a PAUSE/PLAY state change from the application
+	  when we receive a CORK/UNCORK event.
+
+2009-09-13 12:30:34 -0700  David Schleef <ds@schleef.org>
+
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesink.h:
+	  multifilesink: Add next-file property
+	  Add a property to allow control over what event causes a file
+	  to finish being written and a new file start.  The default is
+	  the same as before -- each buffer causes a new file to be
+	  written.  Added is a case where buffers are written to the
+	  same file until a discontinuity in the stream.
+
+2009-09-13 15:55:02 -0700  David Schleef <ds@schleef.org>
+
+	* ext/dv/gstdvdemux.c:
+	* ext/dv/gstdvdemux.h:
+	  dvdemux: Use values from decoder structure directly
+	  Don't store the same values in the GstDvDemux.  This
+	  fixes a bug where dvdemux would detect a stream as PAL
+	  instead of NTSC, and silently parse it wrong.
+
+2009-09-13 12:20:23 -0700  David Schleef <ds@schleef.org>
+
+	* ext/dv/Makefile.am:
+	* ext/dv/gstsmptetimecode.c:
+	* ext/dv/gstsmptetimecode.h:
+	* ext/dv/smpte_test.c:
+	  dvdemux: Add code to parse SMPTE time codes
+	  Code to convert time codes to/from timestamps and frame numbers.
+
+2009-09-13 12:01:27 -0700  David Schleef <ds@schleef.org>
+
+	* ext/dv/gstdvdemux.c:
+	* ext/dv/gstdvdemux.h:
+	  dvdemux: Fix detection of new media
+	  There are 5 or 6 AAUX source control packs in a frame, and any
+	  of them could have REC_ST cleared, indicating a recording start
+	  point.  libdv only checks the first.
+
+2009-09-12 19:25:36 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: Set DISCONT flag on buffers when REC_ST flag is set.
+	  Also add a few branch prediction macros
+
+2009-09-12 00:13:04 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* tests/check/elements/souphttpsrc.c:
+	* tests/check/elements/y4menc.c:
+	  check: Fix a couple of tests.
+	  The souphttpsrc test wasn't compiling. The soup-misc.h header is needed for
+	  soup_ssl_supported.
+	  Fix the y4menc test to use a 'progressive' header for the test data now that
+	  the element outputs correct interlacing info.
+
+2009-09-11 13:32:39 -0700  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: treat a zero-sized data chunk as extending to the end of the file.
+	  This fixes playback of some files that don't have a valid data chunk length,
+	  apparently some program creates these.
+
+2009-09-11 22:24:47 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	  v4l2src: add a function pointer for get_frame function and optimize a bit
+	  Use a function-pointer for mmap/read, as this can't change during capture. Also
+	  sprinkle a few G_LIKELY/UNLIKELY to improve the error-less code path.
+
+2009-09-11 22:15:01 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2: log buffer copies on queue underrun in perf category
+	  v4l2src has a slow path where it does buffer-copies when it runs out of queued
+	  buffers. Log this to performance category to help monitoring it.
+
+2009-09-11 15:14:15 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Implement GstStreamVolume interface
+
+2009-09-11 16:09:40 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	  pulsesink: Implement mute property
+
+2009-09-11 13:33:31 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	  gdkpixbufsink: fix docs refering to send-messages
+
+2009-09-11 13:28:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/spectrum/gstspectrum.c:
+	* gst/spectrum/gstspectrum.h:
+	  spectrum: add post-messages property
+	  Add a post-messages property and deprecate the less descriptive message
+	  property.
+
+2009-09-11 13:20:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	* ext/gdk_pixbuf/gstgdkpixbufsink.h:
+	  pixbufsink: add post-messages property
+	  Add post-messages and deprecate send-messages as the former is more
+	  descriptive of what actually happens.
+
+2009-09-11 13:12:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesink.h:
+	  multifilesink: rename silent to post-messages
+	  Use the post-messages property name instead of silent as it is more
+	  descriptive.
+
+2009-09-11 12:16:18 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesink.h:
+	  multifilesink: post messages for each buffer
+	  Add a silent property that can be set to FALSE to post messages on the bus for
+	  each written file.
+	  Do some more cleanups.
+	  Add some docs.
+	  Fixes #594663
+
+2009-09-09 18:13:29 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: Allocate Boundry structs on the stack instead of the heap to avoid leaks
+	  Fixes bug #594691.
+
+2009-09-10 10:28:48 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpptdemux.c:
+	  docs: fix gtk-doc warnings
+
+2009-09-10 10:26:23 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2sink.h:
+	  docs: fix gtk-doc warnings
+
+2009-09-09 17:51:19 -0700  David Schleef <ds@schleef.org>
+
+	* ext/raw1394/Makefile.am:
+	* ext/raw1394/gst1394clock.c:
+	* ext/raw1394/gst1394clock.h:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gstdv1394src.h:
+	  dv1394src: Add a clock based on isochronous cycle counter
+	  Partial fix for #169383.
+
+2009-09-09 16:02:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Fix AYUV->I420 conversion
+	  For this fix the averaging of the chroma values. It should't be (a/2 + b)/2
+	  but just (a + b)/2.
+	  Fixes bug #594599.
+
+2009-09-09 16:25:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* ext/pulse/pulsesink.c:
+	  pulsesink: remove ringbuffer reset compensation
+	  Remove the code to deal with a ringbuffer reset as this code is now in the base
+	  class.
+	  Bump the -base requirement as we need the new baseaudiosink code to function
+	  properly.
+
+2009-09-09 16:24:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.h:
+	  pulsesink: whitespace fixes
+
+2009-09-09 10:27:55 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2colorbalance.h:
+	  whitespace fixes
+
+2009-09-08 19:34:09 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsemixer.c:
+	* ext/pulse/pulsemixerctrl.c:
+	* ext/pulse/pulseprobe.c:
+	  pulse: small cleanups
+	  Add some debug info
+	  Fix the state changes
+
+2009-09-08 18:29:35 +0200  Marc-André Lureau <mlureau@flumotion.com>
+
+	* gst/multipart/multipartmux.c:
+	  multipartmux: mark data buffer as delta-unit
+	  So that multifdsink always start sending header buffer first
+	  Fixes #594520
+
+2009-09-08 17:37:15 +0200  Marc Leeman <marc.leeman@gmail.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: add ignore-pt parameter
+	  Add a parameter 'ignore-pt' that disables creating a gstrtpptdemux module and
+	  ghosts the pads of gstrtpjitterbuffer instead of the ones of gstrtpptdemux.
+	  Fixes #594490
+
+2009-09-04 13:51:37 +0200  Marvin Schmidt <marvin_schmidt@gmx.net>
+
+	* tests/check/elements/souphttpsrc.c:
+	  checks: only run HTTPS test if libsoup has SSL support
+
+2009-09-08 13:59:56 +0200  Håvard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: propagate payload-type-change signal from demuxer
+	  fixes #594254
+
+2009-08-31 18:46:25 +0200  Havard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  jitterbuffer: change severity of clock-rate change debug
+	  Make log GST_DEBUG under normal circumstances, GST_WARNING otherwise.
+	  Fixes #594253
+
+2009-09-08 13:39:31 +0200  Håvard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: avoid throwing reordered buffers with same timestamps
+	  When we receive a reordered packet with the same timestamp as the previous one
+	  (which can happen for fragmented packets) don't consider the packet as lost but
+	  instead wait for the reordered packet to arrive.
+	  Switch the warning-level, so that a reordering does not get a warning, only
+	  an actual produced lost-packet.
+	  Fixes #594251
+
+2009-08-31 21:16:54 +0200  Havard Graff <havard.graff@tandberg.com>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	  rtpjpegdepay: add missing math.h include
+	  Fixes #594247
+
+2009-09-08 13:30:29 +0200  Arnout Vandecappelle <arnout@mind.be>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix memory leak
+	  In gst_rtspsrc_parse_digest_challenge(), rtspsrc does a g_strndup of the auth
+	  header items and then passes them to gst_rtsp_connection_set_auth_param()
+	  without freeing.
+	  Fixes #594133
+
+2009-09-08 13:18:29 +0200  Stig Sandnes <stig.sandnes@tandberg.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: make free_session() remove stream references
+	  When receiving a sync-packet, all sessions with the same cname will be compared
+	  and synced together. In this process, there could still be references to a
+	  session that has been shut down in the meanwhile.
+	  This patch makes sure that these references are removed when shutting down a
+	  session, so that the syncing can be done safely.
+	  Fixes #594283
+
+2009-08-31 18:46:51 +0200  Havard Graff <havard.graff@tandberg.com>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: use locked state on internal bins
+	  Set the locked state on internal elements to make sure that they don't change
+	  back to another state when shutting down.
+	  Fixes #594248
+
+2009-09-07 18:28:51 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2src: add support for mpeg formats
+
+2009-09-05 20:51:14 -0700  Zaheer Merali <zaheerabbas@merali.org>
+
+	* gst/y4m/gsty4mencode.c:
+	* gst/y4m/gsty4mencode.h:
+	  y4menc: Add interlaced support
+	  Fixes #591713
+	  Signed-off-by: David Schleef <ds@schleef.org>
+
+2009-08-24 13:42:42 -0700  David Schleef <ds@schleef.org>
+
+	* ext/gconf/gstgconfaudiosink.c:
+	* ext/gconf/gstgconfaudiosrc.c:
+	* ext/gconf/gstgconfvideosink.c:
+	* ext/gconf/gstgconfvideosrc.c:
+	* gst/apetag/gstapedemux.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/autodetect/gstautovideosrc.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavimux.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* sys/v4l2/gstv4l2src.c:
+	  Remove Ronald Bultje from Authors field
+	  Replaced with "GStreamer maintainers
+	  <gstreamer-devel@lists.sourceforge.net>" or just removed,
+	  depending on the number of other authors.
+
+2009-09-05 10:21:31 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 00a859e to 19fa4f3
+
+2009-09-04 13:42:43 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: prevent a spurious debug warning
+
+2009-09-04 09:32:42 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Define V4L2_FMT_FLAG_EMULATED if it's not defined yet
+	  libv4l2 already uses this flag, even on Linux kernel versions
+	  before 2.6.32.
+
+2009-09-04 07:10:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Correctly handle NULL GstIndex
+
+2009-09-03 20:40:17 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Fix stupid typo in last commit
+
+2009-09-03 20:38:50 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2: Put emulated formats behind native formats
+	  Fixes bug #593764.
+
+2009-09-03 19:37:10 +0200  Laurent Glayal <spglegle at yahoo.fr>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: fix memleak
+	  Don't leak the input buffer when the received and expected seqnum are different when
+	  in probation.
+	  fixes #594039
+
+2009-09-02 15:21:02 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  rtpjitterbuffer: Lock clock_rate variable
+	  The priv->clock_rate variable could become -1 between when its checked to not
+	  be -1 and when its used, causing an assertion. Fixed by taking the mutex
+	  earlier in the chain() function.
+	  Fixes #593955
+
+2009-09-03 19:12:39 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: whitespace fixes
+
+2009-09-03 19:09:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmpapay.c:
+	  rtpmpapay: whitespace fixes
+
+2009-09-03 19:08:53 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: whitespace fixes
+
+2009-09-03 17:33:28 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: Avoid unnecessary processing until we have a full picture.
+	  This is for non-packetized mode, when we know the upstream size in bytes.
+
+2009-09-03 14:40:20 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: fully use tagsetter to manage the tags. Fixes #563221
+	  There is no need to manage a separate taglist.
+
+2009-09-03 14:13:43 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/speex/gstspeexenc.c:
+	  speexenc: small taglist handling cleanup
+	  Don't eventualy leak the list and instead assert (like in other elements).
+
+2009-09-02 23:12:41 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: also guard reseting subscribe callback with ifdefs
+	  It is conditionaly set, so do the same when unsetting.
+
+2009-09-01 15:06:46 +0200  Peter Kjellerstedt <pkj@axis.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpmanager: Fixed a copy & paste error
+
+2009-09-01 13:21:23 +0200  Peter Kjellerstedt <pkj@axis.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpmanager: Removed unused variable priv
+	  The variable priv was initialized in a lot of functions but then never
+	  used for anything.
+
+2009-09-01 13:03:57 +0200  Peter Kjellerstedt <pkj@axis.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpmanager: A little clean up
+	  Make the code flow of gst_rtp_session_send_rtcp() and
+	  gst_rtp_session_sync_rtcp() identical.
+
+2009-09-01 12:47:51 +0200  Peter Kjellerstedt <pkj@axis.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpmanager: Make sure that used caps are not freed already (take 2)
+	  This reintroduces the fix for bug #593391. It also applies it in
+	  gst_rtp_session_sync_rtcp() which has very similar code to
+	  gst_rtp_session_send_rtcp().
+
+2009-09-01 12:41:36 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	* gst/rtpmanager/rtpjitterbuffer.h:
+	  jitterbuffer: make sure time does not go backwards
+	  When we construct a timestamp that would result in a timestamp that is earlier
+	  than when the packet was received, reset the skew calculation as this is
+	  probably a sign that the sender restarted or paused.
+	  Fixes #593354
+
+2009-09-01 11:32:41 +0200  Peter Kjellerstedt <pkj@axis.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpmanager: Set caps in gst_rtp_session_send_rtcp() correctly again
+	  The test for when to set an RTCP caps on the output pad in
+	  gst_rtp_session_send_rtcp() accidentally got inverted in the last commit.
+
+2009-09-01 10:26:46 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Add support for QCELP audio
+	  Fixes bug #593757.
+
+2009-08-31 18:10:11 +0200  Peter Kjellerstedt <pkj@axis.com>
+
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstop.c:
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gstvertigo.c:
+	  effectv: Fix compilation with gcc 3
+	  Recent changes in gst-plugins-good/gst/effectv prevents it from being compiled
+	  with gcc 3. The problem is that the new code uses preprocessor conditionals
+	  within a macro call which does not work with older versions of gcc.
+	  Fixes bug #593688.
+
+2009-08-31 16:20:59 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  docs: small clean-ups in -sections.txt
+	  Remove duplicate entry for warptv; there is no taglibmux element.
+
+2009-08-27 15:46:52 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4gdepay.c:
+	  rtpmp4gdepay: consider (optional) auxiliary data when parsing
+
+2009-08-27 15:46:15 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4gdepay.c:
+	* gst/rtp/gstrtpmp4gdepay.h:
+	  rtpmp4gdepay: handle broken AU-Index in non-interleaved streams
+	  In case of non-interleaved (= sequentially payloaded) streams,
+	  the AU-Index serves little purpose (that is not already covered by
+	  RTP fields).  (Broken) Payloaders might consider this field then
+	  to be disregarded and have non spec compliant values, e.g. each
+	  RTP packet having AU-Index 2 (rather than 0).  As such, ensure/force
+	  simple sequential sending of non-interleaved streams.
+
+2009-08-18 17:17:28 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: also extract ftyp info in push mode
+
+2009-08-13 16:11:59 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux.h:
+	  qtdemux: consider 3gpp style tag parsing in some more cases
+	  3GPP specs define a number of tags along with precise layout. While these
+	  are normally expected to be found in a container whose major brand is a
+	  3GPP brand, this may also happen when a 3GPP brand is only mentioned as a
+	  compatible brand.  Apply some checks, heuristic and fallbacks to extract
+	  such tags as well.
+
+2009-08-11 13:56:43 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: reflow exit, and fix some leaks
+
+2009-08-11 13:54:56 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: push mode; add pad if needed so downstream gets EOS
+
+2009-08-10 16:19:03 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	* gst/wavparse/gstwavparse.h:
+	  wavparse: push mode; fix/improve chunk handling
+	  Handle large, invalid or otherwise unusual chunk sizes.
+	  Verify some chunk sizes to be at least the size they are
+	  expected to be and round up some sizes to even number for
+	  e.g. offset administration, which must also be properly
+	  tracked in push mode.
+
+2009-08-08 21:54:00 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavidemux.h:
+	  avidemux: push mode; cater for unusual chunk sizes
+
+2009-08-31 16:34:14 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: use proper locking for pads and caps
+	  Use the sesion lock and shotdown variable to protect and ref the pads we are
+	  going to push on.
+	  fixes #561825
+
+2009-08-31 16:33:26 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: whitespace fixes
+
+2009-08-31 13:38:08 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: clean up adapter properly
+	  Reflow code so we don't try to clear or re-use an already-freed adapter.
+
+2009-08-31 13:07:53 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflactag.c:
+	* gst/wavparse/gstwavparse.c:
+	  flactag, wavparse: GstAdapter is not a GstObject
+
+2009-08-31 12:28:52 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	  docs: update plugin docs to git version
+
+2009-08-31 11:32:39 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Fix tests warning from setting a NULL index
+	  Setting a null index in the tests was causing warnings by unreffing
+	  NULL pointers. This is a bug exposed by a recent change in core, it
+	  seems.
+
+2009-08-31 13:02:16 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  jitterbuffer: add slope estimation code and debug
+	  Add some code to measure the sender speed vs the receiver speed. This can be
+	  used to detect bursts.
+
+2009-08-31 12:57:32 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  jitterbuffer: reset skew when timestamps change
+	  Refactor the jitterbuffer resync code.
+	  Reset the skew correction when we detect a big timestamp discont.
+	  See #593354
+
+2009-08-31 12:47:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  jitterbuffer: make sure time never goes invalid
+	  Since the skew can be negative, we might end up with invalid timestamps. Check
+	  for negative results and clamp to 0.
+	  See #593354
+
+2009-08-31 12:16:01 +0200  Jarkko Palviainen <jarkko.palviainen at sesca.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstmultiudpsink.h:
+	* gst/udp/gstudpnetutils.c:
+	  udpsink: Add ttl multicast property
+	  Add a new ttl-mc property to control the TTL on multicast addresses.
+	  Fixes #588245
+
+2009-08-31 12:13:07 +0200  Jarkko Palviainen <jarkko.palviainen at sesca.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudpnetutils.c:
+	* gst/udp/gstudpnetutils.h:
+	  udp: split out TTL and loop options
+	  Split setting the TTL and loop parameters in 2 methods as they are not related.
+	  Fix setting the TTL correctly for multicast streams.
+	  See #588245
+
+2009-08-27 12:36:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	  rtp: whitespace fixes
+
+2009-08-14 13:45:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	  videobox: Correctly add to the docs
+
+2009-08-14 13:40:21 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/Makefile.am:
+	* gst/videobox/gstvideobox.c:
+	* gst/videobox/gstvideobox.h:
+	  videobox: Split declarations into a header file and add autocrop stuff to the docs
+
+2009-08-14 13:26:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Reconfigure basetransform if something changes again
+	  For this invent a new lock and don't abuse the basetransform lock,
+	  otherwise we'll end up in deadlocks.
+
+2009-08-14 13:15:57 +0200  Stephen Jungels <stephen@jungels.net>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: Add support for autocropping according to the caps
+	  Fixes bug #582238.
+
+2009-08-30 21:57:57 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: Make sure that used caps are not freed already
+	  Fixes bug #593391.
+
+2009-08-26 17:02:45 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtpmanager/rtpstats.c:
+	  rtp: Use new gst_iterator_new_single() for the internal linked pads iteration
+
+2009-08-19 16:57:05 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: Use iterate internal links instead of deprecated get internal links
+
+2009-08-19 16:48:25 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: Use iterate internal links instead of deprecated get internal links
+
+2009-08-19 16:37:11 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: Use iterate internal links instead of deprecated get internal links
+
+2009-08-30 23:27:09 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	  Update common
+
+2009-08-30 23:26:48 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  Back to hacking -> 0.10.16.1
+
+=== release 0.10.16 ===
+
+2009-08-29 12:05:40 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Release 0.10.16
+
+2009-08-26 00:58:45 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  0.10.15.5 pre-release
+
+2009-08-25 16:53:29 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: don't use relative seeks
+	  Don't use relative seeks, it's too hard to track where we are after a flush
+	  etc.
+	  fixes #593015
+
+2009-08-24 17:50:29 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* po/LINGUAS:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/lv.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  0.10.15.4 pre-release
+
+2009-08-24 16:22:47 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: don't discard the result of _set_caps()
+	  Use the result of gst_pad_set_caps() instead of assuming success.
+	  See #590678
+
+2009-08-21 11:44:43 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	  qtdemux: add support for agsm
+	  Fixes #592530
+
+2009-08-18 17:16:11 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix qt style string tag extraction
+	  QT style tags are tested on starting with (C) symbol using >>,
+	  and (unsigned) int (may) have different >> behaviour.
+	  Fixes #592232.
+
+2009-08-17 15:48:20 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/smokecodec.c:
+	  smokeenc: don't crash when compiled against libjpeg7
+	  Set parameters so that we don't crash with libjpeg7. Based on
+	  Stefan Kost's fix for jpegenc. Fixes #591951.
+
+2009-08-14 20:18:04 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  0.10.15.3 pre-release
+
+2009-08-14 13:45:08 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/rtpbin.c:
+	  checks: add test for leak to rtpbin unit test
+	  See #591476.
+
+2009-08-11 14:47:12 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Fix reference leak
+	  Fixes #591476.
+
+2009-08-14 13:34:53 +0100  Zaheer Merali <zaheerabbas@merali.org>
+
+	* ext/dv/gstdvdec.c:
+	  dvdec: set bottom field first on PAL interlaced content, not top field first
+	  DV interlaced content is always bottom field first. Fixes #591712.
+
+2009-08-14 12:44:06 +0100  Hans de Goede <jwrdegoede@fedoraproject.org>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: fix 'hang' with some cameras caused by bad timestamping if no framerate is available
+	  For cameras/drivers that don't support e.g. VIDIOC_G_PARM we'd end up without
+	  a framerate and would try to divide by 0, causing run-time warnings and all
+	  frames to be timestamped with 0, which makes sinks that sync against the clock
+	  drop them, causing 'hangs' (observed with the pwc driver and a Logitech QuickCam
+	  Pro 4000). So if we do not know the framerate, simply don't adjust the
+	  timestamps. Fixes #591451.
+
+2009-08-14 10:11:25 +0200  Filippo Argiolas <filippo.argiolas@gmail.com>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2src: clear format list in READY->NULL
+	  Clear format list and probed caps when going to NULL so if a new device
+	  is set we'll probe the formats again instead of using previously
+	  detected ones. Fixes bug #591747.
+
+2009-08-11 16:42:51 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  dtmfsrc: Empty event queue on finalize
+
+2009-08-11 16:39:42 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  dtmf: Use GSlice for internal event structures
+
+2009-08-11 16:23:20 -0400  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  rtpdtmfsrc: Cleanup events on finalize
+	  Problem found by Laurent Glayal
+	  Fixes bug #591440
+
+2009-08-11 16:23:20 -0400  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  rtpdtmfsrc: Cleanup events on finalize
+	  Problem found by Laurent Glayal
+	  Fixes bug #591440
+
+2009-08-11 17:30:41 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* po/LINGUAS:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/de.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/tr.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  0.10.15.2 pre-release
+
+2009-08-11 15:25:39 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* MAINTAINERS:
+	  Add myself to MAINTAINERS file and update Wim's e-mail.
+
+2009-08-11 03:08:01 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/Makefile.am:
+	  v4l2: fix make distcheck by disting some more headers
+
+2009-08-11 02:42:16 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* 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:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	  docs: update
+
+2009-08-11 02:31:44 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	* gst-plugins-good.spec.in:
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/pipelines/.gitignore:
+	  Move rtpmanager from -bad to -good.
+	  Hook up build infrastructure (autotools, docs, unit test).
+
+2009-08-06 19:26:21 +0200  ric <csxnju at sogou.com>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: avoid buffer leak on bad seqnum
+	  Fixes #590797
+
+2009-07-28 18:18:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: allow for NULL caps on buffers
+	  Add the NULL caps check where it matters and also cover another case of
+	  potential NULL caps.
+	  Fixes #590030
+
+2009-07-28 11:59:56 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: Incoming buffers do not always have caps
+
+2009-07-27 15:46:23 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: avoid doing lip-sync in BYE
+	  When we get a BYE packet, don't do lip-sync with the SR inside because some
+	  senders have trouble constructing valid SR packets after BYE.
+
+2009-07-27 13:17:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpbin: don't do lip-sync after a BYE
+	  After a BYE packet from a source, stop forwarding the SR packets for lip-sync
+	  to rtpbin. Some senders don't update their SR packets correctly after sending a
+	  BYE and then we break lip-sync. We prefer to let the jitterbuffers drain with
+	  the current lip-sync instead.
+
+2009-07-27 12:43:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpbin: only reconsider once for BYE
+	  When iterating the sources of a BYE packet, don't signal a reconsideration for
+	  each of them but signal after we handled all sources.
+
+2009-07-21 15:33:41 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: Free conflicting addresses on finalize
+
+2009-07-01 12:55:03 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpbin: use new method for netaddress to string
+
+2009-06-29 18:48:33 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* tests/check/elements/rtpbin.c:
+	  rtpbin: do better cleanup of the src ghostpads
+	  Connect to the pad-removed signal of the ptdemux elements so that we remove the
+	  ghostpads for them. Fixes cleanup when going to NULL as well as when releasing
+	  the sinkpads.
+	  Fixes #561752
+
+2009-05-28 19:08:40 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: add a comment
+
+2009-06-29 16:37:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpbin: add SDES property
+	  Remove all individual SDES properties and use one sdes property that takes a
+	  GstStructure instead. This will allow us to add more custom stuff to the SDES
+	  messages later.
+
+2009-06-29 16:21:05 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	  rtpbin: add SDES property that takes GstStructure
+	  Remove all individual SDES properties and use one sdes property that takes a
+	  GstStructure instead. This will allow us to add more custom stuff to the SDES
+	  messages later.
+
+2009-06-02 17:46:08 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/Makefile.am:
+	* gst/rtpmanager/gstrtpclient.c:
+	* gst/rtpmanager/gstrtpclient.h:
+	* gst/rtpmanager/gstrtpmanager.c:
+	  rtpbin: removed old gstrtpclient
+
+2009-06-19 19:09:19 +0200  Branko Subasic <branko.subasic at axis.com>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	* gst/rtpmanager/rtpsession.c:
+	* gst/rtpmanager/rtpsession.h:
+	* gst/rtpmanager/rtpsource.c:
+	* gst/rtpmanager/rtpsource.h:
+	* tests/check/elements/rtpbin_buffer_list.c:
+	  rtpbin: add support for buffer-list
+	  Add support for sending buffer-lists.
+	  Add unit test for testing that the buffer-list passed through rtpbin.
+	  fixes #585839
+
+2009-06-19 16:21:28 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  Make build without warnings with debugging disabled
+
+2009-05-28 17:37:44 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Transform the right session sdes message
+	  Fixes #584165
+
+2009-05-28 17:33:10 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  Add ssrc to application/x-rtp-source-sdes structure
+
+2009-05-27 11:03:14 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsouce: the network address is in network order
+	  Bring the network address in netowkr byte order to the host order.
+
+2009-05-26 15:40:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: byteswap the port from GstNetAddress
+	  Since the port in GstNetAddress is in network order we might need to byteswap it
+	  before adding it to the source statistics.
+
+2009-05-25 13:46:29 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: remove ptdemux ghostpads
+
+2009-05-25 13:33:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpbin.c:
+	  tests: add receive rtpbin unit test
+
+2009-05-22 16:41:19 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: add to new signal to remove SSRC pads
+
+2009-05-22 16:35:20 +0200  Ali Sabil <ali.sabil at gmail.com>
+
+	* gst/rtpmanager/gstrtpbin-marshal.list:
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	* gst/rtpmanager/gstrtpssrcdemux.h:
+	  ssrcdemux: emit signal when pads are removed
+	  Add action signal to clear an SSRC in the ssrc demuxer.
+	  Add signal to notify of removed ssrc.
+	  See #554839
+
+2009-05-22 15:45:19 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: use our ghostpads instead of its target
+	  Since we keep a reference to our ghostpads, we can use them to track sessions.
+	  This avoid us having to mess with the target of the ghostpad.
+
+2009-05-22 15:37:29 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpbin.c:
+	  tests: more rtpbin checks
+
+2009-05-22 15:36:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: don't warn when getting request pads twice
+	  Allow getting the request pads multiple times, just return the previously
+	  created pads.
+
+2009-05-22 13:47:30 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsource: add RTP and RTCP source address
+	  Add the RTP and RTCP sender addresses in the stats structure.
+
+2009-05-22 13:45:15 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: reuse source code for SDES
+	  Reuse the RTPSource object property instead of duplicating code.
+
+2009-05-22 13:44:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpbin.c:
+	  tests: add more rtpbin tests
+
+2009-05-22 12:23:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/rtpbin.c:
+	  tests: add rtpbin unit test
+	  Add the beginnings of an rtpbin unit test
+	  Add some more stuff to .gitignore
+
+2009-05-22 12:20:13 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: set target state on new elements
+	  Set the state on newly added elements to the state of the parent.
+	  Add some debug info and do some cleanups
+
+2009-05-22 11:59:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: unref requests pads after releasing
+
+2009-05-22 01:43:50 +0200  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Implement releasing the streams
+	  See #561752
+
+2009-05-22 01:16:11 +0200  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Keep jb signals handler
+	  Keep the signal handlers so they can be disconnected at release time
+	  See #561752
+
+2009-05-22 01:12:57 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: use the right lock for the sessions
+	  Use the right lock when iterating the sessions.
+
+2009-05-22 01:03:55 +0200  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Free session if request pads are released
+	  Free the session when all the request pads are released.
+	  Don't mess with the session list in free_session as it is called from a foreach
+	  on that list.
+	  Set the state of the upstream element to NULL first.
+	  See #561752
+
+2009-05-22 00:51:53 +0200  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Implement relasing of the rtp recv pad
+
+2009-05-22 00:44:51 +0200  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Implement releasing of rtp send pads
+
+2009-05-22 00:34:36 +0200  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Implement release of the recv rtcp pad
+	  See #561752
+
+2009-05-22 00:16:19 +0200  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	  rtpbin: Implement releasing of rtcp src pad
+	  See #561752
+
+2009-05-05 16:48:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpssrcdemux.c:
+	  rtpssrcdemux: drop unexpected RTCP packets
+	  We usually only get SR packets in our chain function but if an invalid packet
+	  contains the SR packet after the RR packet, we must not fail but simply ignore
+	  the malformed packet.
+	  Fixes #581375
+
+2009-04-27 11:09:08 +0200  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsource.c:
+	  rtpsouce: make WARNING into LOG
+	  Since neither rtpmanager nor any of the payloaders properly implement
+	  pad allocation, there is no way for the rtpmanager to inform downstream elements
+	  of the new SSRC if there is an SSRC collision. So the warning is emitted all the
+	  time and it is confusing.
+	  Fixes #580144
+
+2009-04-27 11:06:01 +0200  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/rtpsession.c:
+	  rtpsession: notify when SSRC changes
+	  Emit a g_object_notify when the SSRc changes because of a collision.
+	  Fixes #580144
+
+2009-04-17 16:16:29 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpsession: join the RTCP thread
+	  Avoid a case where a joinable thread would be left unjoined, which leaked the
+	  thread structure.
+	  Fixes #577318.
+
+2009-04-15 18:14:48 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: prevent overflow in EOS estimation
+	  Use a guint64 instead of a guint to hold a 64bit value to prevent completely
+	  bogues EOS estimation values due to overflows.
+
+2009-04-15 17:44:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	  rtpbin: we should not provide a clock
+	  There is no need to provide a clock.
+
+2009-04-15 17:28:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: more estimated EOS fixes
+	  Do more accurate EOS estimate and guard against backward timestamps.
+
+2009-04-15 17:25:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  jitterbuffer: release lock before pushing EOS
+	  Make sure we release the jitterbuffer lock before we start pushing out data
+	  because else we might deadlock.
+
+2009-03-27 17:44:57 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpbin.c:
+	* gst/rtpmanager/gstrtpbin.h:
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	* gst/rtpmanager/gstrtpjitterbuffer.h:
+	  rtpbin: add on_npt_stop signal
+	  Add the on_npt_stop signal to rtpbin and rtpjitterbuffer to notify the
+	  application that the NPT stop position has been reached.
+
+2009-03-13 15:59:37 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  rtpbin: don't return FALSE on seek events
+	  Silently ignore the seek event instead of returning FALSE.
+
+2009-02-26 13:10:29 +0100  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpsession.c:
+	  gstrtpbin: Don't forward revc events to sender
+	  Don't send events from the receiver to the sender side.
+	  Fixes #572900.
+
+2009-02-25 11:45:05 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/rtpmanager/rtpjitterbuffer.c:
+	  docs: various doc fixes
+	  No short-desc as we have them in the element details.
+	  Also keep things (Makefile.am and sections.txt) sorted.
+	  Reword ambigous returns. No text after since please.
+
+2009-01-23 12:13:00 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/rtpstats.c:
+	  Send BYE packets immediatly for small sessions
+	  When the number of participants is less than 50, the RFC allows for sending the
+	  BYE packet immediatly instead of using the regular BYE timeout.
+	  Fixes #567828.
+
+2009-01-22 13:33:14 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtpmanager/gstrtpjitterbuffer.c:
+	  Unlock the jitterbuffer before pushing out the packet-lost events. Move some code before we do the unlock to make the jitterbuffer state consistent while we are unlocked.
+
+2009-01-02 17:40:06 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtpmanager/: When an SSRC is found on the caps of the sender RTP, use this as the internal SSRC. Fixes #565910.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtpmanager/gstrtpsession.c:
+	  (gst_rtp_session_setcaps_send_rtp), (create_send_rtp_sink):
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_set_internal_ssrc):
+	  When an SSRC is found on the caps of the sender RTP, use this as the
+	  internal SSRC. Fixes #565910.
+
+2009-01-02 16:50:53 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Rename a method to better reflect what it really does.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c:
+	  (gst_rtp_session_event_send_rtp_sink),
+	  (gst_rtp_session_getcaps_send_rtp):
+	  * gst/rtpmanager/rtpsession.c: (check_collision),
+	  (rtp_session_schedule_bye_locked), (rtp_session_schedule_bye):
+	  * gst/rtpmanager/rtpsession.h:
+	  Rename a method to better reflect what it really does.
+
+2008-12-29 15:49:37 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpsession.c: Use method to get the internal SSRC.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c:
+	  (gst_rtp_session_getcaps_send_rtp):
+	  Use method to get the internal SSRC.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_class_init),
+	  (rtp_session_set_property), (rtp_session_get_property):
+	  Add property to congiure the internal SSRC of the session.
+	  Fixes #565910.
+
+2008-12-29 15:21:58 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/rtpsession.c: Only change the SSRC of the session and reset the internal source when the SSRC actually...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_set_internal_ssrc):
+	  Only change the SSRC of the session and reset the internal source when
+	  the SSRC actually changed. See #565910.
+
+2008-12-29 14:21:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/rtpsource.*: When no payload was specified on the caps but there was a clock-rate, assume the clock-ra...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_init),
+	  (rtp_source_update_caps), (get_clock_rate):
+	  * gst/rtpmanager/rtpsource.h:
+	  When no payload was specified on the caps but there was a clock-rate,
+	  assume the clock-rate corresponds to the first payload type found in the
+	  RTP packets. Fixes #565509.
+
+2008-12-23 11:39:59 +0000  Arnout Vandecappelle <arnout@mind.be>
+
+	  gst/rtpmanager/rtpjitterbuffer.*: Keep track of the last outgoing timestamp and of the last sender-side time.  Timest...
+	  Original commit message from CVS:
+	  Patch by: Arnout Vandecappelle <arnout at mind dot be>
+	  * gst/rtpmanager/rtpjitterbuffer.c: (rtp_jitter_buffer_reset_skew),
+	  (calculate_skew):
+	  * gst/rtpmanager/rtpjitterbuffer.h:
+	  Keep track of the last outgoing timestamp and of the last sender-side
+	  time.  Timestamps can only go forward if they do at the sender
+	  side, can only go back if they do at the sender side, and remain the
+	  same if they remain the same at the sender side. Fixes #565319.
+
+2008-11-26 12:40:18 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/rtpsession.c: Make obtain_source return an aditional ref so that we don't lose our ref to it when a se...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/rtpsession.c: (obtain_source),
+	  (rtp_session_create_source), (rtp_session_process_rtp),
+	  (rtp_session_process_sr), (rtp_session_process_rr),
+	  (rtp_session_process_sdes), (rtp_session_process_bye):
+	  Make obtain_source return an aditional ref so that we don't lose our ref
+	  to it when a session cleanup occurs when we are emiting a signal.
+	  Emit the on_new_ssrc signal for the CSRC, not the SSRC.
+	  Fixes #562319.
+
+2008-11-26 12:02:21 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Reset the sync parameters when clearing the payload type map too.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_reset_sync),
+	  (gst_rtp_bin_clear_pt_map):
+	  Reset the sync parameters when clearing the payload type map too.
+	  Fixes #562312.
+
+2008-11-26 11:44:37 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.*: Remove a lot of per stream state that is not needed and pass new info in the method call.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (get_client),
+	  (gst_rtp_bin_reset_sync), (gst_rtp_bin_associate),
+	  (gst_rtp_bin_handle_sync), (create_stream),
+	  (gst_rtp_bin_class_init), (new_ssrc_pad_found):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  Remove a lot of per stream state that is not needed and pass new info in
+	  the method call.
+	  Add signal to reset sync parameters.
+	  Avoid parsing the caps to get a clock_base, we get this from the sync
+	  signal now.
+
+2008-11-25 15:12:06 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpsession.c: Fix event leak.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c:
+	  (gst_rtp_session_event_send_rtcp_src):
+	  Fix event leak.
+
+2008-11-22 15:31:36 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/rtpsession.c: Add property to configure the RTCP MTU.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_class_init),
+	  (rtp_session_init), (rtp_session_set_property),
+	  (rtp_session_get_property):
+	  Add property to configure the RTCP MTU.
+
+2008-11-22 15:24:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/rtpsession.c: Add G_PARAM_STATIC_STRINGS.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_class_init),
+	  (copy_source), (rtp_session_create_sources),
+	  (rtp_session_get_property):
+	  Add G_PARAM_STATIC_STRINGS.
+	  Add property to return a GValueArray of all known RTPSources in the
+	  session.
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_class_init),
+	  (rtp_source_create_sdes), (rtp_source_set_property),
+	  (rtp_source_get_property):
+	  Remove properties to set the various SDES items, an application is never
+	  supposed to change the RTPSource data.
+	  Change the SDES getter properties to one SDES property that returns all
+	  SDES items in a GstStructure.
+
+2008-11-22 13:17:24 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Also unref the target pad for unknown pads.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_release_pad):
+	  Also unref the target pad for unknown pads.
+
+2008-11-21 16:17:22 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtpmanager/gstrtpbin.c: Release the right pads on rtpbin. Fixes #561752.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_release_pad):
+	  Release the right pads on rtpbin. Fixes #561752.
+
+2008-11-20 18:41:34 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpsession.c: Pass the running time to the session when processing RTP packets.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c: (get_current_times),
+	  (rtcp_thread), (gst_rtp_session_chain_recv_rtp):
+	  Pass the running time to the session when processing RTP packets.
+	  Improve the time function to provide more info.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_class_init),
+	  (rtp_session_init), (update_arrival_stats),
+	  (rtp_session_process_rtp), (rtp_session_process_sdes),
+	  (rtp_session_process_rtcp), (session_start_rtcp),
+	  (rtp_session_on_timeout):
+	  * gst/rtpmanager/rtpsession.h:
+	  Mark the internal source with a flag.
+	  Use running_time instead of the more useless timestamp.
+	  Validate a source when a valid SDES has been received.
+	  Pass the current system time when processing SR packets.
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_class_init),
+	  (rtp_source_init), (rtp_source_create_stats),
+	  (rtp_source_get_property), (rtp_source_send_rtp),
+	  (rtp_source_process_rb), (rtp_source_get_new_rb),
+	  (rtp_source_get_last_rb):
+	  * gst/rtpmanager/rtpsource.h:
+	  Add property to get source stats.
+	  Mark params as STATIC_STRINGS.
+	  Calculate the bitrate at the sender SSRC.
+	  Avoid negative values in the round trip time calculations.
+	  * gst/rtpmanager/rtpstats.h:
+	  Update some docs and change some variable name to more closely reflect
+	  what it contains.
+
+2008-11-20 08:19:15 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Initialize return value to fix compiler warning about uninitialized variable.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_chain_rtcp):
+	  Initialize return value to fix compiler warning about uninitialized
+	  variable.
+
+2008-11-19 16:48:38 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Mark signal arg as static scope.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_class_init):
+	  Mark signal arg as static scope.
+
+2008-11-19 09:06:29 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Remove internal sync pad, use signals instead to get lip-sync notifications.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_associate),
+	  (gst_rtp_bin_handle_sync), (create_stream), (free_stream),
+	  (new_ssrc_pad_found):
+	  Remove internal sync pad, use signals instead to get lip-sync
+	  notifications.
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_base_init),
+	  (gst_rtp_jitter_buffer_class_init),
+	  (gst_rtp_jitter_buffer_internal_links), (create_rtcp_sink),
+	  (remove_rtcp_sink), (gst_rtp_jitter_buffer_request_new_pad),
+	  (gst_rtp_jitter_buffer_release_pad),
+	  (gst_rtp_jitter_buffer_sink_rtcp_event),
+	  (gst_rtp_jitter_buffer_chain_rtcp),
+	  (gst_rtp_jitter_buffer_get_property):
+	  * gst/rtpmanager/gstrtpjitterbuffer.h:
+	  Make it possible to send SR packets to the jitterbuffer.
+	  Check if the SR timestamps are valid by comparing them to the RTP
+	  timestamps.
+	  Signal the SR packet and the timing information to listeners.
+	  * gst/rtpmanager/gstrtpssrcdemux.c: (create_demux_pad_for_ssrc),
+	  (gst_rtp_ssrc_demux_rtcp_chain), (gst_rtp_ssrc_demux_src_query):
+	  Remove some unused code.
+	  * gst/rtpmanager/rtpjitterbuffer.c: (rtp_jitter_buffer_reset_skew),
+	  (calculate_skew), (rtp_jitter_buffer_get_sync):
+	  * gst/rtpmanager/rtpjitterbuffer.h:
+	  Keep track of the last seen RTP timestamp so that we can filter out
+	  invalid SR packets.
+
+2008-11-17 19:47:32 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/rtpmanager/rtpsource.c: Fix GST_DEBUG call to only have as many arguments as required by the format string. Fixes...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/rtpsource.c: (get_clock_rate):
+	  Fix GST_DEBUG call to only have as many arguments as required
+	  by the format string. Fixes a compiler warning.
+
+2008-11-17 15:17:52 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Do not try to keep track of the clock-rate ourselves but simply get the value from the ji...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_associate),
+	  (gst_rtp_bin_sync_chain), (create_stream), (new_ssrc_pad_found):
+	  Do not try to keep track of the clock-rate ourselves but simply get the
+	  value from the jitterbuffer.
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_jitter_buffer_sink_parse_caps), (gst_rtp_jitter_buffer_chain),
+	  (gst_rtp_jitter_buffer_get_sync):
+	  * gst/rtpmanager/gstrtpjitterbuffer.h:
+	  Add some debug info.
+	  Pass the clock-rate to the jitterbuffer.
+	  Also pass the clock-rate along with the rtp timestamp when getting the
+	  sync parameters.
+	  * gst/rtpmanager/gstrtpptdemux.c: (gst_rtp_pt_demux_chain):
+	  Fix some debug.
+	  * gst/rtpmanager/rtpjitterbuffer.c: (rtp_jitter_buffer_reset_skew),
+	  (calculate_skew), (rtp_jitter_buffer_get_sync):
+	  * gst/rtpmanager/rtpjitterbuffer.h:
+	  Keep track of clock-rate changes and return the clock-rate together with
+	  the rtp timestamps used for sync.
+	  Don't try to construct timestamps when we have no base_time.
+	  * gst/rtpmanager/rtpsource.c: (get_clock_rate):
+	  Request a new clock-rate when the payload type changes.
+	  Reset the jitter calculation when the clock-rate changes.
+
+2008-11-13 15:48:54 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Small cleanups and some more debug info.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_jitter_buffer_sink_parse_caps),
+	  (gst_rtp_jitter_buffer_flush_stop), (gst_rtp_jitter_buffer_chain):
+	  * gst/rtpmanager/rtpjitterbuffer.c: (rtp_jitter_buffer_reset_skew),
+	  (calculate_skew):
+	  Small cleanups and some more debug info.
+
+2008-11-10 15:26:40 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Also configure the next expected output seqnum when we get a seqnum-base on the ...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_jitter_buffer_sink_parse_caps), (gst_rtp_jitter_buffer_chain):
+	  Also configure the next expected output seqnum when we get a seqnum-base
+	  on the caps.
+
+2008-11-04 12:42:30 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Don't install static libs for plugins. Fixes #550851 for -bad.
+	  Original commit message from CVS:
+	  * ext/alsaspdif/Makefile.am:
+	  * ext/amrwb/Makefile.am:
+	  * ext/apexsink/Makefile.am:
+	  * ext/arts/Makefile.am:
+	  * ext/artsd/Makefile.am:
+	  * ext/audiofile/Makefile.am:
+	  * ext/audioresample/Makefile.am:
+	  * ext/bz2/Makefile.am:
+	  * ext/cdaudio/Makefile.am:
+	  * ext/celt/Makefile.am:
+	  * ext/dc1394/Makefile.am:
+	  * ext/dirac/Makefile.am:
+	  * ext/directfb/Makefile.am:
+	  * ext/divx/Makefile.am:
+	  * ext/dts/Makefile.am:
+	  * ext/faac/Makefile.am:
+	  * ext/faad/Makefile.am:
+	  * ext/gsm/Makefile.am:
+	  * ext/hermes/Makefile.am:
+	  * ext/ivorbis/Makefile.am:
+	  * ext/jack/Makefile.am:
+	  * ext/jp2k/Makefile.am:
+	  * ext/ladspa/Makefile.am:
+	  * ext/lcs/Makefile.am:
+	  * ext/libfame/Makefile.am:
+	  * ext/libmms/Makefile.am:
+	  * ext/metadata/Makefile.am:
+	  * ext/mpeg2enc/Makefile.am:
+	  * ext/mplex/Makefile.am:
+	  * ext/musepack/Makefile.am:
+	  * ext/musicbrainz/Makefile.am:
+	  * ext/mythtv/Makefile.am:
+	  * ext/nas/Makefile.am:
+	  * ext/neon/Makefile.am:
+	  * ext/ofa/Makefile.am:
+	  * ext/polyp/Makefile.am:
+	  * ext/resindvd/Makefile.am:
+	  * ext/sdl/Makefile.am:
+	  * ext/shout/Makefile.am:
+	  * ext/snapshot/Makefile.am:
+	  * ext/sndfile/Makefile.am:
+	  * ext/soundtouch/Makefile.am:
+	  * ext/spc/Makefile.am:
+	  * ext/swfdec/Makefile.am:
+	  * ext/tarkin/Makefile.am:
+	  * ext/theora/Makefile.am:
+	  * ext/timidity/Makefile.am:
+	  * ext/twolame/Makefile.am:
+	  * ext/x264/Makefile.am:
+	  * ext/xine/Makefile.am:
+	  * ext/xvid/Makefile.am:
+	  * gst-libs/gst/app/Makefile.am:
+	  * gst-libs/gst/dshow/Makefile.am:
+	  * gst/aiffparse/Makefile.am:
+	  * gst/app/Makefile.am:
+	  * gst/audiobuffer/Makefile.am:
+	  * gst/bayer/Makefile.am:
+	  * gst/cdxaparse/Makefile.am:
+	  * gst/chart/Makefile.am:
+	  * gst/colorspace/Makefile.am:
+	  * gst/dccp/Makefile.am:
+	  * gst/deinterlace/Makefile.am:
+	  * gst/deinterlace2/Makefile.am:
+	  * gst/dvdspu/Makefile.am:
+	  * gst/festival/Makefile.am:
+	  * gst/filter/Makefile.am:
+	  * gst/flacparse/Makefile.am:
+	  * gst/flv/Makefile.am:
+	  * gst/games/Makefile.am:
+	  * gst/h264parse/Makefile.am:
+	  * gst/librfb/Makefile.am:
+	  * gst/mixmatrix/Makefile.am:
+	  * gst/modplug/Makefile.am:
+	  * gst/mpeg1sys/Makefile.am:
+	  * gst/mpeg4videoparse/Makefile.am:
+	  * gst/mpegdemux/Makefile.am:
+	  * gst/mpegtsmux/Makefile.am:
+	  * gst/mpegvideoparse/Makefile.am:
+	  * gst/mve/Makefile.am:
+	  * gst/nsf/Makefile.am:
+	  * gst/nuvdemux/Makefile.am:
+	  * gst/overlay/Makefile.am:
+	  * gst/passthrough/Makefile.am:
+	  * gst/pcapparse/Makefile.am:
+	  * gst/playondemand/Makefile.am:
+	  * gst/rawparse/Makefile.am:
+	  * gst/real/Makefile.am:
+	  * gst/rtjpeg/Makefile.am:
+	  * gst/rtpmanager/Makefile.am:
+	  * gst/scaletempo/Makefile.am:
+	  * gst/sdp/Makefile.am:
+	  * gst/selector/Makefile.am:
+	  * gst/smooth/Makefile.am:
+	  * gst/smoothwave/Makefile.am:
+	  * gst/speed/Makefile.am:
+	  * gst/speexresample/Makefile.am:
+	  * gst/stereo/Makefile.am:
+	  * gst/subenc/Makefile.am:
+	  * gst/tta/Makefile.am:
+	  * gst/vbidec/Makefile.am:
+	  * gst/videodrop/Makefile.am:
+	  * gst/videosignal/Makefile.am:
+	  * gst/virtualdub/Makefile.am:
+	  * gst/vmnc/Makefile.am:
+	  * gst/y4m/Makefile.am:
+	  * sys/acmenc/Makefile.am:
+	  * sys/cdrom/Makefile.am:
+	  * sys/dshowdecwrapper/Makefile.am:
+	  * sys/dshowsrcwrapper/Makefile.am:
+	  * sys/dvb/Makefile.am:
+	  * sys/dxr3/Makefile.am:
+	  * sys/fbdev/Makefile.am:
+	  * sys/oss4/Makefile.am:
+	  * sys/qcam/Makefile.am:
+	  * sys/qtwrapper/Makefile.am:
+	  * sys/vcd/Makefile.am:
+	  * sys/wininet/Makefile.am:
+	  * win32/common/config.h:
+	  Don't install static libs for plugins. Fixes #550851 for -bad.
+
+2008-10-16 13:05:37 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Fix problem with using the output seqnum counter to check for input seqnum disco...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_jitter_buffer_sink_parse_caps),
+	  (gst_rtp_jitter_buffer_flush_start),
+	  (gst_rtp_jitter_buffer_flush_stop), (gst_rtp_jitter_buffer_chain),
+	  (gst_rtp_jitter_buffer_loop):
+	  Fix problem with using the output seqnum counter to check for input
+	  seqnum discontinuities.
+	  Improve gap detection and recovery, reset and flush the jitterbuffer on
+	  seqnum restart. Fixes #556520.
+	  * gst/rtpmanager/rtpjitterbuffer.c: (rtp_jitter_buffer_insert):
+	  Fix wrong G_LIKELY.
+
+2008-10-16 09:51:28 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpsession.c: Install event handler on the rtcp_src pad, make LATENCY event return
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c:
+	  (gst_rtp_session_event_send_rtcp_src), (create_send_rtcp_src):
+	  Install event handler on the rtcp_src pad, make LATENCY event return
+	  TRUE.
+
+2008-10-07 18:54:41 +0000  Håvard Graff <havard.graff@tandberg.com>
+
+	  gst/rtpmanager/gstrtpbin-marshal.list: Add marshaller for new action signal.
+	  Original commit message from CVS:
+	  Patch by: Håvard Graff <havard dot graff at tandberg dot com>
+	  * gst/rtpmanager/gstrtpbin-marshal.list:
+	  Add marshaller for new action signal.
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_get_internal_session),
+	  (gst_rtp_bin_class_init):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  Add action signal to retrieve the internal RTPSession object.
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_class_init),
+	  (gst_rtp_session_get_property), (gst_rtp_session_release_pad):
+	  Add property to access the internal RTPSession object.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_class_init),
+	  (check_collision):
+	  * gst/rtpmanager/rtpsession.h:
+	  Add action signal to retrieve an RTPSource object by SSRC.
+	  See #555396.
+
+2008-10-07 11:33:10 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Release pads of the session manager.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (find_session_by_pad),
+	  (free_session), (gst_rtp_bin_dispose), (remove_recv_rtp),
+	  (remove_recv_rtcp), (remove_send_rtp), (remove_rtcp),
+	  (gst_rtp_bin_release_pad):
+	  Release pads of the session manager.
+	  Start implementing releasing pads of gstrtpbin.
+	  * gst/rtpmanager/gstrtpsession.c: (remove_recv_rtp_sink),
+	  (remove_recv_rtcp_sink), (remove_send_rtp_sink),
+	  (remove_send_rtcp_src), (gst_rtp_session_release_pad):
+	  Implement releasing pads in gstrtpsession.
+
+2008-10-07 10:02:20 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Only update the seqnum-base when it was not already configured for the streams.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_jitter_buffer_sink_parse_caps):
+	  Only update the seqnum-base when it was not already configured for the
+	  streams.
+
+2008-09-30 15:08:52 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/rtpsession.c: Ref the rtpsource object before we release the session lock when we emit the signals.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/rtpsession.c: (on_new_ssrc), (on_ssrc_collision),
+	  (on_ssrc_validated), (on_ssrc_active), (on_ssrc_sdes),
+	  (on_bye_ssrc), (on_bye_timeout), (on_timeout), (on_sender_timeout):
+	  Ref the rtpsource object before we release the session lock when we emit
+	  the signals.
+
+2008-09-23 18:13:31 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Fix some docs.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/rtpjitterbuffer.c: (rtp_jitter_buffer_insert),
+	  (rtp_jitter_buffer_get_sync):
+	  * gst/rtpmanager/rtpsession.c: (on_sender_timeout),
+	  (session_cleanup):
+	  * gst/rtpmanager/rtpsource.c:
+	  Fix some docs.
+
+2008-09-17 13:59:21 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Fix compiler warnings on OS/X
+	  Original commit message from CVS:
+	  * ext/jack/gstjackaudiosink.c: (jack_process_cb):
+	  * gst/rtpmanager/rtpjitterbuffer.c: (calculate_skew):
+	  Fix compiler warnings on OS/X
+
+2008-09-13 01:37:50 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Do not try to adjust the offset of streams for which we have not yet seen an SR packet. A...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (create_session),
+	  (gst_rtp_bin_associate), (gst_rtp_bin_sync_chain):
+	  Do not try to adjust the offset of streams for which we have not yet
+	  seen an SR packet. Avoids large ts-offsets in some cases.
+
+2008-09-05 13:52:34 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.*: Add signal to notify listeners when a sender becomes a receiver.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (on_sender_timeout),
+	  (create_session), (gst_rtp_bin_associate),
+	  (gst_rtp_bin_sync_chain), (gst_rtp_bin_class_init),
+	  (gst_rtp_bin_request_new_pad):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  Add signal to notify listeners when a sender becomes a receiver.
+	  Tweak lip-sync code, don't store our own copy of the ts-offset of the
+	  jitterbuffer, don't adjust sync if the change is less than 4msec.
+	  Get the RTP timestamp <-> GStreamer timestamp relation directly from
+	  the jitterbuffer instead of our inaccurate version from the source.
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_chain), (gst_rtp_jitter_buffer_loop),
+	  (gst_rtp_jitter_buffer_get_sync):
+	  * gst/rtpmanager/gstrtpjitterbuffer.h:
+	  Add G_LIKELY macros, use global defines for max packet reorder and
+	  dropouts.
+	  Reset the jitterbuffer clock skew detection when packets seqnums are
+	  changed unexpectedly.
+	  * gst/rtpmanager/gstrtpsession.c: (on_sender_timeout),
+	  (gst_rtp_session_class_init), (gst_rtp_session_init):
+	  * gst/rtpmanager/gstrtpsession.h:
+	  Add sender timeout signal.
+	  * gst/rtpmanager/rtpjitterbuffer.c: (rtp_jitter_buffer_reset_skew),
+	  (calculate_skew), (rtp_jitter_buffer_insert),
+	  (rtp_jitter_buffer_get_sync):
+	  * gst/rtpmanager/rtpjitterbuffer.h:
+	  Add some G_LIKELY macros.
+	  Keep track of the extended RTP timestamp so that we can report the RTP
+	  timestamp <-> GStreamer timestamp relation for lip-sync.
+	  Remove server timestamp gap detection code, the server can sometimes
+	  make a huge gap in timestamps (talk spurts,...) see #549774.
+	  Detect timetamp weirdness instead by observing the sender/receiver
+	  timestamp relation and resync if it changes more than 1 second.
+	  Add method to report about the current rtp <-> gst timestamp relation
+	  which is needed for lip-sync.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_class_init),
+	  (on_sender_timeout), (check_collision), (rtp_session_process_sr),
+	  (session_cleanup):
+	  * gst/rtpmanager/rtpsession.h:
+	  Add sender timeout signal.
+	  Remove inaccurate rtp <-> gst timestamp relation code, the
+	  jitterbuffer can now do an accurate reporting about this.
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_init),
+	  (rtp_source_update_caps), (calculate_jitter),
+	  (rtp_source_process_rtp):
+	  * gst/rtpmanager/rtpsource.h:
+	  Remove inaccurate rtp <-> gst timestamp relation code.
+	  * gst/rtpmanager/rtpstats.h:
+	  Define global max-reorder and max-dropout constants for use in various
+	  subsystems.
+
+2008-08-28 15:21:45 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpsession.c: Send EOS when the session object instructs us to.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_send_rtcp),
+	  (gst_rtp_session_event_send_rtp_sink):
+	  Send EOS when the session object instructs us to.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_on_timeout):
+	  * gst/rtpmanager/rtpsession.h:
+	  Make it possible for the session manager to instruct us to send EOS. We
+	  currently will EOS when the session is a sender and when the sender part
+	  goes EOS. This is not entirely correct behaviour because the session
+	  could still participate as a receiver.
+	  Fixes #549409.
+
+2008-08-13 14:31:02 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Reset rtp timestamp interpollation when we detect a gap when the clock_base changed.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_associate),
+	  (gst_rtp_bin_sync_chain), (new_ssrc_pad_found):
+	  Reset rtp timestamp interpollation when we detect a gap when the
+	  clock_base changed.
+	  Don't try to adjust the ts-offset when it's too big (> 3seconds)
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_set_ssrc):
+	  * gst/rtpmanager/gstrtpsession.h:
+	  Add method to set session SSRC.
+	  * gst/rtpmanager/rtpsession.c: (check_collision),
+	  (rtp_session_set_internal_ssrc), (rtp_session_get_internal_ssrc),
+	  (rtp_session_on_timeout):
+	  * gst/rtpmanager/rtpsession.h:
+	  Added debugging for the collision checks.
+	  Add method to change the internal SSRC of the session.
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_process_rtp):
+	  Reset the clock base when we detect large jumps in the seqnums.
+
+2008-08-11 07:20:15 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/rtpmanager/gstrtpbin.c: Print the pad-name in debug log.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c:
+	  Print the pad-name in debug log.
+	  * sys/dshowsrcwrapper/gstdshowaudiosrc.c:
+	  * sys/dshowsrcwrapper/gstdshowvideosrc.c:
+	  Use "-" instead of "_" in property names. Can we call them just
+	  "device" like everywhere else?
+
+2008-08-05 09:42:53 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Make the buffer metadata writable before inserting it in the jitterbuffer becaus...
+	  Original commit message from CVS:
+	  Based on patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_chain), (gst_rtp_jitter_buffer_loop):
+	  Make the buffer metadata writable before inserting it in the
+	  jitterbuffer because the jitterbuffer will modify the timestamps.
+	  * gst/rtpmanager/rtpjitterbuffer.c:
+	  Update method comment about requiring writable metadata on buffers.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_process_sr),
+	  (rtp_session_process_rtcp):
+	  Make the RTCP buffer metadata writable because we want to modify the
+	  metadata.
+	  Fixes #546312.
+
+2008-08-05 09:00:50 +0000  Håvard Graff <havard.graff@tandberg.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Fix debug by logging the right seqnum.
+	  Original commit message from CVS:
+	  Patch by: Håvard Graff <havard dot graff at tandberg dot com>
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_chain):
+	  Fix debug by logging the right seqnum.
+
+2008-08-05 08:58:27 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtpmanager/gstrtpbin.c: Release lock before emitting the request-pt-map signal.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtpmanager/gstrtpbin.c: (get_pt_map):
+	  Release lock before emitting the request-pt-map signal.
+	  Fixes #543480.
+
+2008-07-03 14:44:51 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtpmanager/: Corrected a typo (interpollate -> interpolate).
+	  Original commit message from CVS:
+	  * ChangeLog:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c: (gst_rtp_jitter_buffer_loop):
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_get_new_sr):
+	  Corrected a typo (interpollate -> interpolate).
+
+2008-07-03 14:31:10 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtpmanager/: Changed some GST_DEBUG() to GST_LOG() to reduce the spam when a pipeline is running normally.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_process_rtp),
+	  (gst_rtp_session_send_rtp), (gst_rtp_session_send_rtcp),
+	  (gst_rtp_session_sync_rtcp), (gst_rtp_session_chain_recv_rtp),
+	  (gst_rtp_session_chain_recv_rtcp), (gst_rtp_session_chain_send_rtp):
+	  * gst/rtpmanager/rtpsession.c: (source_push_rtp),
+	  (rtp_session_send_rtp):
+	  * gst/rtpmanager/rtpsource.c: (push_packet), (calculate_jitter),
+	  (rtp_source_process_rtp), (rtp_source_send_rtp):
+	  Changed some GST_DEBUG() to GST_LOG() to reduce the spam when a
+	  pipeline is running normally.
+
+2008-07-03 13:47:19 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtpmanager/: Do not mix the use of g_get_current_time() with gst_clock_get_time().
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_init),
+	  (gst_rtp_session_finalize), (rtcp_thread),
+	  (gst_rtp_session_chain_recv_rtp), (gst_rtp_session_chain_recv_rtcp),
+	  (gst_rtp_session_event_send_rtp_sink),
+	  (gst_rtp_session_chain_send_rtp):
+	  * gst/rtpmanager/rtpsession.c: (check_collision),
+	  (update_arrival_stats), (rtp_session_process_rtp),
+	  (rtp_session_process_rtcp), (rtp_session_send_rtp),
+	  (rtp_session_send_bye_locked), (rtp_session_send_bye),
+	  (rtp_session_next_timeout), (session_report_blocks), (session_cleanup),
+	  (is_rtcp_time), (rtp_session_on_timeout):
+	  * gst/rtpmanager/rtpsession.h:
+	  Do not mix the use of g_get_current_time() with gst_clock_get_time().
+
+2008-06-16 07:30:34 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Final round of doc updates.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  * gst/speed/gstspeed.c:
+	  * gst/speexresample/gstspeexresample.c:
+	  * gst/videosignal/gstvideoanalyse.c:
+	  * gst/videosignal/gstvideodetect.c:
+	  * gst/videosignal/gstvideomark.c:
+	  * sys/dvb/gstdvbsrc.c:
+	  * sys/oss4/oss4-mixer.c:
+	  * sys/oss4/oss4-sink.c:
+	  * sys/oss4/oss4-source.c:
+	  * sys/wininet/gstwininetsrc.c:
+	  Final round of doc updates.
+
+2008-06-16 07:03:58 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/: More doc updates. More xrefs.
+	  Original commit message from CVS:
+	  * gst/deinterlace/gstdeinterlace.c:
+	  * gst/rtpmanager/gstrtpbin.c:
+	  * gst/rtpmanager/gstrtpclient.c:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  * gst/rtpmanager/gstrtpptdemux.c:
+	  * gst/rtpmanager/gstrtpsession.c:
+	  * gst/rtpmanager/gstrtpssrcdemux.c:
+	  * gst/sdp/gstsdpdemux.c:
+	  More doc updates. More xrefs.
+
+2008-06-12 14:49:18 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Do not use short_description in section docs for elements. We extract them from element details and there will be war...
+	  Original commit message from CVS:
+	  * ext/dc1394/gstdc1394.c:
+	  * ext/ivorbis/vorbisdec.c:
+	  * ext/jack/gstjackaudiosink.c:
+	  * ext/metadata/gstmetadatademux.c:
+	  * ext/mythtv/gstmythtvsrc.c:
+	  * ext/theora/theoradec.c:
+	  * gst-libs/gst/app/gstappsink.c:
+	  * gst/bayer/gstbayer2rgb.c:
+	  * gst/deinterlace/gstdeinterlace.c:
+	  * gst/rawparse/gstaudioparse.c:
+	  * gst/rawparse/gstvideoparse.c:
+	  * gst/rtpmanager/gstrtpbin.c:
+	  * gst/rtpmanager/gstrtpclient.c:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  * gst/rtpmanager/gstrtpptdemux.c:
+	  * gst/rtpmanager/gstrtpsession.c:
+	  * gst/rtpmanager/gstrtpssrcdemux.c:
+	  * gst/selector/gstinputselector.c:
+	  * gst/selector/gstoutputselector.c:
+	  * gst/videosignal/gstvideoanalyse.c:
+	  * gst/videosignal/gstvideodetect.c:
+	  * gst/videosignal/gstvideomark.c:
+	  * sys/oss4/oss4-mixer.c:
+	  * sys/oss4/oss4-sink.c:
+	  * sys/oss4/oss4-source.c:
+	  Do not use short_description in section docs for elements. We extract
+	  them from element details and there will be warnings if they differ.
+	  Also fixing up the ChangeLog order.
+
+2008-06-06 13:01:05 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Fix deadlock when shutting down, use a new lock instead to properly shutdown.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_init),
+	  (gst_rtp_bin_finalize), (gst_rtp_bin_change_state):
+	  Fix deadlock when shutting down, use a new lock instead to properly
+	  shutdown.
+
+2008-05-27 16:48:10 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Break out of callbacks when we are shutting down.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c:
+	  (gst_rtp_bin_propagate_property_to_jitterbuffer),
+	  (gst_rtp_bin_change_state), (new_payload_found),
+	  (new_ssrc_pad_found):
+	  Break out of callbacks when we are shutting down.
+	  Make sure no state changes can happen when we reconfigure.
+
+2008-05-26 10:09:29 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: When checking the seqnum, reset the jitterbuffer if the gap is too big, we need ...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_chain), (gst_rtp_jitter_buffer_loop):
+	  When checking the seqnum, reset the jitterbuffer if the gap is too big,
+	  we need to do this so that we can better handle a restarted source.
+	  Fix some comments.
+	  * gst/rtpmanager/rtpjitterbuffer.c: (calculate_skew),
+	  (rtp_jitter_buffer_insert):
+	  Tweak the skew resync diff.
+	  Use our working seqnum compare function in -base.
+	  Rework the jitterbuffer insert code to make it clearer and more
+	  performant by only retrieving the seqnum of the input buffer once and by
+	  adding some G_LIKELY compiler hints.
+	  Improve debugging for duplicate packets.
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_process_rtp):
+	  Fix a comment, we don't do skew correction here..
+
+2008-05-26 10:00:24 +0000  Håvard Graff <havard.graff@tandberg.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Propagate the do-lost and latency properties to the jitterbuffers when they are changed o...
+	  Original commit message from CVS:
+	  Patch by: Håvard Graff <havard dot graff at tandberg dot com>
+	  * gst/rtpmanager/gstrtpbin.c:
+	  (gst_rtp_bin_propagate_property_to_jitterbuffer),
+	  (gst_rtp_bin_set_property):
+	  Propagate the do-lost and latency properties to the jitterbuffers when
+	  they are changed on rtpbin.
+
+2008-05-26 09:57:40 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  Don't use _gst_pad().
+	  Original commit message from CVS:
+	  * examples/switch/switcher.c: (switch_timer):
+	  * gst/replaygain/gstrgvolume.c: (gst_rg_volume_init):
+	  * gst/rtpmanager/gstrtpclient.c: (create_stream):
+	  * gst/sdp/gstsdpdemux.c: (gst_sdp_demux_stream_configure_udp),
+	  (gst_sdp_demux_stream_configure_udp_sink):
+	  * tests/check/elements/deinterleave.c: (GST_START_TEST),
+	  (pad_added_setup_data_check_float32_8ch_cb):
+	  * tests/check/elements/rganalysis.c: (send_eos_event),
+	  (send_tag_event):
+	  Don't use _gst_pad().
+
+2008-05-16 19:56:30 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  docs/Makefile.am: Don't attempt to build plugin docs when they're disabled.
+	  Original commit message from CVS:
+	  * docs/Makefile.am:
+	  Don't attempt to build plugin docs when they're disabled.
+	  * gst/bayer/Makefile.am:
+	  Add libgstvideo to the link.
+	  * gst/rtpmanager/Makefile.am:
+	  Fix link order, and move LIBS things to _LIBS
+
+2008-05-14 21:02:19 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Simply drop bad RTP packets with a warning instead of just posting an error and ...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_chain):
+	  Simply drop bad RTP packets with a warning instead of just posting an
+	  error and stopping. This is a perfectly recoverable event and we don't
+	  force people to use an rtpbin to filter out bad packets first.
+
+2008-05-13 09:06:51 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Actually add the do-lost property to the object.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_class_init):
+	  Actually add the do-lost property to the object.
+
+2008-05-12 18:43:41 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Avoid waiting for a negative (huge) duration when the last packet has a lower ti...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_loop):
+	  Avoid waiting for a negative (huge) duration when the last packet has a
+	  lower timestamp than the current packet.
+
+2008-05-12 14:28:09 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtpmanager/gstrtpsession.c: Make sure to unref the rtpsession returned by gst_pad_get_parent() to prevent a memor...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_query_send_rtcp_src):
+	  Make sure to unref the rtpsession returned by gst_pad_get_parent() to
+	  prevent a memory leak.
+
+2008-05-12 14:12:08 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Initialise with GST_CLOCK_TIME_NONE to avoid compiler warning.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_loop):
+	  Initialise with GST_CLOCK_TIME_NONE to avoid compiler warning.
+
+2008-05-09 07:41:58 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtpmanager/rtpsource.c: Make sure to unref the caps used by RTPSource to prevent a memory leak.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_finalize):
+	  Make sure to unref the caps used by RTPSource to prevent a memory leak.
+
+2008-05-08 09:43:33 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtpmanager/rtpsession.c: Unlock the session lock when calling one of our callbacks.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtpmanager/rtpsession.c: (source_clock_rate),
+	  (rtp_session_process_bye), (rtp_session_send_bye_locked):
+	  Unlock the session lock when calling one of our callbacks.
+	  Fixes #532011.
+
+2008-05-08 06:23:39 +0000  Sjoerd Simons <sjoerd@luon.net>
+
+	  gst/rtpmanager/gstrtpsession.c: Send RTP BYE command on EOS. Fixes bug #531955.
+	  Original commit message from CVS:
+	  Patch by: Sjoerd Simons <sjoerd at luon dot net>
+	  * gst/rtpmanager/gstrtpsession.c:
+	  (gst_rtp_session_event_send_rtp_sink):
+	  Send RTP BYE command on EOS. Fixes bug #531955.
+
+2008-04-25 11:32:09 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.*: Expose new jitterbuffer property in rtpbin too.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (create_stream), (gst_rtp_bin_init),
+	  (gst_rtp_bin_set_property), (gst_rtp_bin_get_property):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  Expose new jitterbuffer property in rtpbin too.
+
+2008-04-25 11:22:13 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Disable sending out rtp packet lost events by default and make a property to ena...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_class_init), (gst_rtp_jitter_buffer_init),
+	  (gst_rtp_jitter_buffer_loop), (gst_rtp_jitter_buffer_set_property),
+	  (gst_rtp_jitter_buffer_get_property):
+	  Disable sending out rtp packet lost events by default and make a
+	  property to enabe it. We will likely enable it by default when the base
+	  depayloaders have a default handler for them so that we don't send these
+	  events all through the pipeline for now.
+
+2008-04-25 09:35:43 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Remove private version of a function that is in -base now.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_init), (gst_rtp_jitter_buffer_flush_stop),
+	  (gst_rtp_jitter_buffer_src_event), (gst_rtp_jitter_buffer_chain),
+	  (gst_rtp_jitter_buffer_loop):
+	  Remove private version of a function that is in -base now.
+	  Add src event handler.
+	  Rework the jitterbuffer pushing loop so that it can quickly react to
+	  lost packets and instruct the depayloader of them. This can then be used
+	  to implement error concealment data.
+
+2008-04-25 08:21:06 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpsession.c: Set up some internal links functions for the RTCP and sync pads because the defaults ...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c:
+	  (gst_rtp_session_query_send_rtcp_src), (create_recv_rtcp_sink),
+	  (create_send_rtcp_src):
+	  Set up some internal links functions for the RTCP and sync pads because
+	  the defaults are really not correct.
+	  Implement a query handler for the RTCP src pad, mostly to correctly
+	  report about the latency.
+
+2008-04-25 08:15:58 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Also keep track of the first buffer timestamp together with the first
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_associate),
+	  (gst_rtp_bin_sync_chain):
+	  * gst/rtpmanager/rtpsession.c: (update_arrival_stats),
+	  (rtp_session_process_sr), (rtp_session_on_timeout):
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_init),
+	  (calculate_jitter):
+	  * gst/rtpmanager/rtpsource.h:
+	  * gst/rtpmanager/rtpstats.h:
+	  Also keep track of the first buffer timestamp together with the first
+	  RTP timestamp as they both are needed to construct the timing of
+	  outgoing packets in the jitterbuffer and are therefore also needed to
+	  manage lip-sync. This fixes lip-sync if the first RTP packets arrive
+	  with a wildly different gap.
+
+2008-04-21 08:26:37 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtpmanager/gstrtpbin.c: Ref caps when inserting into the cache.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtpmanager/gstrtpbin.c: (create_session), (get_pt_map),
+	  (new_ssrc_pad_found):
+	  Ref caps when inserting into the cache.
+	  Don't leak pads.
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_get_clock_rate),
+	  (gst_rtp_jitter_buffer_query):
+	  Avoid a caps leak.
+	  Don't leak refcount in query.
+	  * gst/rtpmanager/gstrtpptdemux.c: (gst_rtp_pt_demux_get_caps),
+	  (gst_rtp_pt_demux_chain):
+	  Avoid caps leaks.
+	  * gst/rtpmanager/gstrtpsession.c: (source_get_sdes_structure),
+	  (gst_rtp_session_init), (return_true),
+	  (gst_rtp_session_clear_pt_map), (gst_rtp_session_cache_caps),
+	  (gst_rtp_session_clock_rate):
+	  Ref caps when inserting into the cache.
+	  Fix some more caps leaks. Fixes #528245.
+
+2008-04-17 07:31:44 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Unset GValues after g_signal_emitv so that we avoid a refcount leak.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (get_pt_map), (free_client),
+	  (gst_rtp_bin_associate), (gst_rtp_bin_get_free_pad_name):
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_get_clock_rate):
+	  * gst/rtpmanager/gstrtpptdemux.c: (gst_rtp_pt_demux_get_caps):
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_clock_rate):
+	  Unset GValues after g_signal_emitv so that we avoid a refcount leak.
+	  Don't leak a padname.
+	  Don't leak client streams list.
+	  Lock rtpbin when associating streams. Fixes #528245.
+
+2008-04-09 22:27:50 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtpmanager/: Avoid leaking pads in the RTP manager.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (free_session):
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_finalize):
+	  Avoid leaking pads in the RTP manager.
+
+2008-03-11 12:40:58 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtpmanager/rtpsession.*: Implement collision and loop detection in rtpmanager.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtpmanager/rtpsession.c: (find_add_conflicting_addresses),
+	  (check_collision), (obtain_source), (rtp_session_create_new_ssrc),
+	  (rtp_session_create_source), (rtp_session_process_rtp),
+	  (rtp_session_process_sr), (rtp_session_process_rr),
+	  (rtp_session_process_sdes), (rtp_session_process_bye),
+	  (rtp_session_send_bye_locked), (rtp_session_send_bye),
+	  (rtp_session_on_timeout):
+	  * gst/rtpmanager/rtpsession.h:
+	  Implement collision and loop detection in rtpmanager.
+	  Fixes #520626.
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_reset),
+	  (rtp_source_init):
+	  * gst/rtpmanager/rtpsource.h:
+	  Add method to reset stats.
+
+2008-03-11 11:36:03 +0000  Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+
+	  gst/rtpmanager/gstrtpsession.c: Avoid a deadlock when joining the RTCP thread in PAUSED because it might be blocked d...
+	  Original commit message from CVS:
+	  Based on patch by: Ole André Vadla Ravnås  <ole.andre.ravnas@tandberg.com>
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_init),
+	  (rtcp_thread), (start_rtcp_thread), (stop_rtcp_thread),
+	  (join_rtcp_thread), (gst_rtp_session_change_state):
+	  Avoid a deadlock when joining the RTCP thread in PAUSED because it might
+	  be blocked downstream. Also avoid spawning multiple rtcp threads.
+	  Fixes #520894.
+
+2008-03-11 10:43:32 +0000  Stefan Kost <ensonic@users.sf.net>
+
+	  gst/rtpmanager/rtpjitterbuffer.c: Don't try to reset the clock skew when we have no timestamps.
+	  Original commit message from CVS:
+	  Patch by: Stefan Kost <ensonic@users.sf.net>
+	  * gst/rtpmanager/rtpjitterbuffer.c: (calculate_skew):
+	  Don't try to reset the clock skew when we have no timestamps.
+	  Fixes #519005.
+
+2008-02-20 09:33:25 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtpmanager/gstrtpbin.c: Fix small memory leak, leaking caps. Fixes #bug 517571.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtpmanager/gstrtpbin.c: (new_ssrc_pad_found):
+	  Fix small memory leak, leaking caps. Fixes #bug 517571.
+
+2008-02-14 16:25:51 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtpmanager/gstrtpbin.c: Ignore streams that did not receive an SR packet when doing synchronisation. Fixes #516160.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester@tester.ca>
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_associate):
+	  Ignore streams that did not receive an SR packet when doing
+	  synchronisation. Fixes #516160.
+
+2008-01-29 18:57:27 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Try to get the new clock-rate from the buffer caps when we receive a new payload...
+	  Original commit message from CVS:
+	  Patch by: Thijs Vermeir  <thijsvermeir at gmail dot com>
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_chain):
+	  Try to get the new clock-rate from the buffer caps when we receive a new
+	  payload type instead of always firing the signal. Fixes #512774.
+
+2008-01-25 16:58:00 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtpmanager/gstrtpbin.c: Also handle lip-sync when the clock-rate is not provided with caps but with a signal.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester@tester.ca>
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_associate),
+	  (create_stream), (payload_type_change), (new_ssrc_pad_found):
+	  Also handle lip-sync when the clock-rate is not provided with caps but
+	  with a signal.
+
+2008-01-25 16:00:52 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtpmanager/: Remove the fixed clock-rate from the jitterbuffer and extend it so that a clock-rate can be provided...
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester@tester.ca>
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_jitter_buffer_sink_parse_caps), (gst_rtp_jitter_buffer_chain):
+	  * gst/rtpmanager/rtpjitterbuffer.c: (calculate_skew),
+	  (rtp_jitter_buffer_insert):
+	  * gst/rtpmanager/rtpjitterbuffer.h:
+	  Remove the fixed clock-rate from the jitterbuffer and extend it so that
+	  a clock-rate can be provided with each buffer instead. Fixes #511686.
+
+2008-01-25 15:49:55 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Remove old unused variable.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester@tester.ca>
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_init), (gst_rtp_jitter_buffer_change_state),
+	  (gst_rtp_jitter_buffer_chain), (gst_rtp_jitter_buffer_loop):
+	  Remove old unused variable.
+	  Track pt on input buffers and get the clock-rate when it changes.
+	  Ignore packets with unknown clock-rate. See #511686.
+
+2008-01-25 01:44:27 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtpmanager/rtpsource.c: Fix unref of buffer using the wrong function.  Fixes #511920
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester@tester.ca>
+	  * gst/rtpmanager/rtpsource.c: Fix unref of buffer using the
+	  wrong function.  Fixes #511920
+
+2008-01-11 17:02:30 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpsession.c: If we find the caps in the cache, use it to parse the clock-rate instead of returning...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_clock_rate):
+	  If we find the caps in the cache, use it to parse the clock-rate instead
+	  of returning an error. Fixes a TODO as found by Youness Alaoui.
+
+2008-01-11 16:45:57 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	  gst/rtpmanager/: Make it possible to use different user_data for each of the callbacks.
+	  Original commit message from CVS:
+	  Patch by: Youness Alaoui <youness dot alaoui at collabora dot co dot uk>
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_clock_rate):
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_set_callbacks),
+	  (rtp_session_set_process_rtp_callback),
+	  (rtp_session_set_send_rtp_callback),
+	  (rtp_session_set_send_rtcp_callback),
+	  (rtp_session_set_sync_rtcp_callback),
+	  (rtp_session_set_clock_rate_callback),
+	  (rtp_session_set_reconsider_callback), (source_push_rtp),
+	  (source_clock_rate), (rtp_session_process_bye),
+	  (rtp_session_process_rtcp), (rtp_session_send_bye),
+	  (rtp_session_on_timeout):
+	  * gst/rtpmanager/rtpsession.h:
+	  Make it possible to use different user_data for each of the callbacks.
+	  Fixes #508587.
+
+2008-01-10 20:57:17 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Fix documentation for latest patch
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c:
+	  Fix documentation for latest patch
+
+2008-01-10 14:34:30 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Allow request_new_pad with name NULL (bug #508515)
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c:
+	  Allow request_new_pad with name NULL (bug #508515)
+
+2008-01-09 14:39:44 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpsession.c: Don't set fixed caps, we can basically do everything the upsteam peer pad can renegot...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c: (create_send_rtp_sink):
+	  Don't set fixed caps, we can basically do everything the upsteam peer
+	  pad can renegotiate to. Fixes #507940.
+
+2008-01-04 18:47:57 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Don't unref the popped buffer when we don't have ownership.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_loop):
+	  Don't unref the popped buffer when we don't have ownership.
+	  Fixes #507020.
+
+2007-12-31 13:12:06 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpssrcdemux.c: Don't clean up pads when going to PAUSED.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpssrcdemux.c:
+	  (gst_rtp_ssrc_demux_change_state):
+	  Don't clean up pads when going to PAUSED.
+
+2007-12-12 16:59:03 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Clean up the dynamic pads when going to READY.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpptdemux.c: (gst_rtp_pt_demux_finalize),
+	  (gst_rtp_pt_demux_setup), (gst_rtp_pt_demux_release),
+	  (gst_rtp_pt_demux_change_state):
+	  * gst/rtpmanager/gstrtpssrcdemux.c: (gst_rtp_ssrc_demux_reset),
+	  (gst_rtp_ssrc_demux_dispose), (gst_rtp_ssrc_demux_src_query),
+	  (gst_rtp_ssrc_demux_change_state):
+	  Clean up the dynamic pads when going to READY.
+
+2007-12-12 12:11:53 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Fix some leaks.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_finalize),
+	  (gst_rtp_bin_set_sdes_string), (gst_rtp_bin_get_sdes_string),
+	  (gst_rtp_bin_handle_message):
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_finalize),
+	  (rtp_session_send_bye):
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_finalize):
+	  Fix some leaks.
+
+2007-12-10 18:36:04 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Post a message when the SDES infor changes for a source.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_class_init),
+	  (gst_rtp_bin_handle_message):
+	  * gst/rtpmanager/gstrtpsession.c: (source_get_sdes_structure),
+	  (on_ssrc_sdes):
+	  Post a message when the SDES infor changes for a source.
+	  * gst/rtpmanager/rtpsession.c:
+	  * gst/rtpmanager/rtpsource.c:
+	  Update some comments.
+
+2007-12-10 15:34:19 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Add signal to notify of an SDES change.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (on_ssrc_sdes), (create_session),
+	  (gst_rtp_bin_class_init):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  * gst/rtpmanager/gstrtpclient.c:
+	  * gst/rtpmanager/gstrtpclient.h:
+	  * gst/rtpmanager/gstrtpjitterbuffer.h:
+	  * gst/rtpmanager/gstrtpmanager.c:
+	  * gst/rtpmanager/gstrtpptdemux.c:
+	  * gst/rtpmanager/gstrtpptdemux.h:
+	  * gst/rtpmanager/gstrtpsession.c: (on_ssrc_sdes),
+	  (gst_rtp_session_class_init), (gst_rtp_session_init):
+	  * gst/rtpmanager/gstrtpsession.h:
+	  * gst/rtpmanager/gstrtpssrcdemux.c:
+	  * gst/rtpmanager/gstrtpssrcdemux.h:
+	  * gst/rtpmanager/rtpjitterbuffer.c:
+	  * gst/rtpmanager/rtpjitterbuffer.h:
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_class_init),
+	  (on_ssrc_sdes), (rtp_session_process_sdes):
+	  * gst/rtpmanager/rtpsession.h:
+	  * gst/rtpmanager/rtpsource.c:
+	  * gst/rtpmanager/rtpsource.h:
+	  * gst/rtpmanager/rtpstats.c:
+	  * gst/rtpmanager/rtpstats.h:
+	  Add signal to notify of an SDES change.
+	  Fix object type in the signal callbacks.
+
+2007-12-10 14:03:32 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.*: Expose SDES items as properties and configure the session managers with them.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (create_session),
+	  (gst_rtp_bin_class_init), (gst_rtp_bin_init), (sdes_type_to_name),
+	  (gst_rtp_bin_set_sdes_string), (gst_rtp_bin_get_sdes_string),
+	  (gst_rtp_bin_set_property), (gst_rtp_bin_get_property):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  Expose SDES items as properties and configure the session managers with
+	  them.
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_class_init),
+	  (rtp_source_set_property):
+	  Fix SSRC property.
+
+2007-12-10 11:08:11 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Update comment.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (create_session):
+	  * gst/rtpmanager/rtpjitterbuffer.c:
+	  Update comment.
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_class_init),
+	  (gst_rtp_session_set_property), (gst_rtp_session_get_property):
+	  Define some GObject properties to set SDES and other configuration.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_class_init),
+	  (rtp_session_init), (rtp_session_finalize),
+	  (rtp_session_set_property), (rtp_session_get_property),
+	  (on_ssrc_sdes), (rtp_session_set_bandwidth),
+	  (rtp_session_get_bandwidth), (rtp_session_set_rtcp_fraction),
+	  (rtp_session_get_rtcp_fraction), (rtp_session_set_sdes_string),
+	  (rtp_session_get_sdes_string), (obtain_source),
+	  (rtp_session_get_internal_source), (rtp_session_process_sdes),
+	  (rtp_session_send_rtp), (rtp_session_next_timeout), (session_sdes),
+	  (is_rtcp_time):
+	  * gst/rtpmanager/rtpsession.h:
+	  Add signal when new SDES infor has been found for a source.
+	  Create properties for SDES and other info.
+	  Simplify the SDES API.
+	  Add method for getting the internal source object of the session.
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_class_init),
+	  (rtp_source_finalize), (rtp_source_set_property),
+	  (rtp_source_get_property), (rtp_source_set_callbacks),
+	  (rtp_source_get_ssrc), (rtp_source_set_as_csrc),
+	  (rtp_source_is_as_csrc), (rtp_source_is_active),
+	  (rtp_source_is_validated), (rtp_source_is_sender),
+	  (rtp_source_received_bye), (rtp_source_get_bye_reason),
+	  (rtp_source_set_sdes), (rtp_source_set_sdes_string),
+	  (rtp_source_get_sdes), (rtp_source_get_sdes_string),
+	  (rtp_source_get_new_sr), (rtp_source_get_new_rb):
+	  * gst/rtpmanager/rtpsource.h:
+	  Add GObject properties for various things.
+	  Don't leak the bye reason.
+
+2007-11-22 09:08:27 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: jitterbuffer can buffer an unlimited amount of time and thus has no max_latency ...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_query):
+	  jitterbuffer can buffer an unlimited amount of time and thus has no
+	  max_latency requirements.
+
+2007-11-02 21:45:38 +0000  Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+
+	  gst/rtpmanager/gstrtpsession.c: Fix bad function signatures (#492798).
+	  Original commit message from CVS:
+	  Patch by: Ole André Vadla Ravnås  <ole.andre.ravnas@tandberg.com>
+	  * gst/rtpmanager/gstrtpsession.c:
+	  Fix bad function signatures (#492798).
+
+2007-10-09 10:01:39 +0000  Laurent Glayal <spglegle@yahoo.fr>
+
+	  gst/rtpmanager/gstrtpbin.c: Fix memleak. Fixes #484990.
+	  Original commit message from CVS:
+	  Patch by: Laurent Glayal <spglegle at yahoo dot fr>
+	  * gst/rtpmanager/gstrtpbin.c: (create_stream),
+	  (gst_rtp_bin_class_init):
+	  Fix memleak. Fixes #484990.
+
+2007-10-08 17:46:45 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/: Fix compiler warnings shown by Forte.
+	  Original commit message from CVS:
+	  * gst/librfb/rfbbuffer.c: (rfb_buffer_new_and_alloc):
+	  * gst/librfb/rfbbuffer.h:
+	  * gst/librfb/rfbdecoder.c: (rfb_socket_get_buffer):
+	  * gst/mpegvideoparse/mpegvideoparse.c: (gst_mpegvideoparse_chain):
+	  * gst/nsf/nes6502.c: (nes6502_execute):
+	  * gst/real/gstrealaudiodec.c: (gst_real_audio_dec_setcaps):
+	  * gst/real/gstrealvideodec.c: (open_library):
+	  * gst/real/gstrealvideodec.h:
+	  * gst/rtpmanager/gstrtpsession.c: (create_recv_rtp_sink),
+	  (create_recv_rtcp_sink), (create_send_rtp_sink):
+	  Fix compiler warnings shown by Forte.
+
+2007-10-08 10:39:35 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Fix caps refcounting for payload maps.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (get_pt_map),
+	  (gst_rtp_bin_clear_pt_map), (gst_rtp_bin_class_init):
+	  Fix caps refcounting for payload maps.
+	  When clearing payload maps, also clear sessions and streams payload
+	  maps.
+	  * gst/rtpmanager/gstrtpptdemux.c: (gst_rtp_pt_demux_get_caps),
+	  (gst_rtp_pt_demux_clear_pt_map), (gst_rtp_pt_demux_chain),
+	  (find_pad_for_pt):
+	  Implement clearing the payload map.
+	  * gst/rtpmanager/gstrtpsession.c:
+	  (gst_rtp_session_event_send_rtp_sink):
+	  Forward flush events instead of leaking them.
+	  * gst/rtpmanager/gstrtpssrcdemux.c:
+	  (gst_rtp_ssrc_demux_rtcp_sink_event):
+	  Correctly refcount events before pushing them.
+
+2007-10-05 17:26:14 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/rtpsession.c: When reconsidering RTCP timeouts, set the next timeout against the last report time inst...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_next_timeout),
+	  When reconsidering RTCP timeouts, set the next timeout against the last
+	  report time instead of the current clock time so that we don't end up
+	  reconsidering forever.
+
+2007-10-05 12:07:37 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Only peek at the tail element instead of popping it off, which allows us to grea...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_chain), (gst_rtp_jitter_buffer_loop):
+	  Only peek at the tail element instead of popping it off, which allows
+	  us to greatly simplify things when the tail element changes.
+	  * gst/rtpmanager/gstrtpsession.c:
+	  (gst_rtp_session_event_recv_rtp_sink):
+	  * gst/rtpmanager/gstrtpssrcdemux.c:
+	  (gst_rtp_ssrc_demux_sink_event):
+	  Forward FLUSH events instead of leaking them.
+	  * gst/rtpmanager/rtpjitterbuffer.c: (rtp_jitter_buffer_reset_skew),
+	  (calculate_skew), (rtp_jitter_buffer_insert):
+	  * gst/rtpmanager/rtpjitterbuffer.h:
+	  Remove the tail-changed callback in favour of a simple boolean when we
+	  insert a buffer in the queue.
+	  Add method to peek the tail of the buffer.
+
+2007-10-02 10:27:45 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Remove some old unused variables.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_flush_start),
+	  (gst_rtp_jitter_buffer_flush_stop),
+	  (gst_rtp_jitter_buffer_change_state), (apply_offset),
+	  (gst_rtp_jitter_buffer_loop):
+	  Remove some old unused variables.
+	  Don't add the latency to the skew corrected timestamp, latency is only
+	  used to sync against the clock.
+	  Improve debugging.
+	  * gst/rtpmanager/rtpjitterbuffer.c: (rtp_jitter_buffer_init),
+	  (rtp_jitter_buffer_reset_skew), (calculate_skew):
+	  * gst/rtpmanager/rtpjitterbuffer.h:
+	  Handle case where server timestamp goes backwards or wildly jumps by
+	  temporarily pausing the skew correction.
+	  Improve debugging.
+
+2007-09-28 14:51:58 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Fix crasher in dispose.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (free_client):
+	  Fix crasher in dispose.
+	  * gst/rtpmanager/rtpjitterbuffer.c: (calculate_skew):
+	  Handle cases where input buffers have no timestamps so that no clock
+	  skew can be calculated, in this case interpollate timestamps based on
+	  rtp timestamp and assume a 0 clock skew.
+
+2007-09-28 11:17:35 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Remove jitter correction code, it's now in the lower level object.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c: (apply_latency),
+	  (gst_rtp_jitter_buffer_loop), (gst_rtp_jitter_buffer_query):
+	  Remove jitter correction code, it's now in the lower level object.
+	  Use new -core method for doing a peer query.
+	  * gst/rtpmanager/rtpjitterbuffer.c: (rtp_jitter_buffer_init),
+	  (calculate_skew), (rtp_jitter_buffer_insert):
+	  * gst/rtpmanager/rtpjitterbuffer.h:
+	  Move jitter correction to the lowlevel jitterbuffer.
+	  Increase the max window size.
+	  When filling the window, already start estimating the skew using a
+	  parabolic weighting factor so that we have a much better startup
+	  behaviour that gets more accurate with the more samples we have.
+	  Increase the default weighting factor for the steady state to get
+	  smoother timestamps.
+
+2007-09-26 20:08:28 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Fix cleanup crasher.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_dispose),
+	  (gst_rtp_bin_finalize):
+	  Fix cleanup crasher.
+	  * gst/rtpmanager/rtpjitterbuffer.c: (rtp_jitter_buffer_init),
+	  (calculate_skew):
+	  * gst/rtpmanager/rtpjitterbuffer.h:
+	  Dynamically adjust the skew calculation window so that we calculate it
+	  over a period of around 2 seconds.
+
+2007-09-20 14:34:57 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Add notification of active SSRCs to various RTP elements. Fixes #478566.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (on_ssrc_active), (create_session),
+	  (gst_rtp_bin_class_init):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  * gst/rtpmanager/gstrtpsession.c: (on_ssrc_active),
+	  (gst_rtp_session_class_init), (gst_rtp_session_init),
+	  (gst_rtp_session_event_send_rtp_sink):
+	  * gst/rtpmanager/gstrtpsession.h:
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_class_init),
+	  (on_ssrc_active), (rtp_session_process_rb):
+	  * gst/rtpmanager/rtpsession.h:
+	  Add notification of active SSRCs to various RTP elements. Fixes #478566.
+
+2007-09-17 02:01:41 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Link to the right pads regardless of which one was created first in the ssrc demuxer.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (new_ssrc_pad_found):
+	  Link to the right pads regardless of which one was created first in the
+	  ssrc demuxer.
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_chain), (gst_rtp_jitter_buffer_loop):
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_process_rtp),
+	  (gst_rtp_session_chain_recv_rtp), (gst_rtp_session_chain_send_rtp):
+	  * gst/rtpmanager/rtpsource.c: (calculate_jitter):
+	  Improve debugging.
+	  * gst/rtpmanager/gstrtpssrcdemux.c: (create_demux_pad_for_ssrc),
+	  (gst_rtp_ssrc_demux_init), (gst_rtp_ssrc_demux_finalize),
+	  (gst_rtp_ssrc_demux_sink_event),
+	  (gst_rtp_ssrc_demux_rtcp_sink_event), (gst_rtp_ssrc_demux_chain),
+	  (gst_rtp_ssrc_demux_rtcp_chain),
+	  (gst_rtp_ssrc_demux_internal_links):
+	  * gst/rtpmanager/gstrtpssrcdemux.h:
+	  Fix race in creating the RTP and RTCP pads when a new SSRC is detected.
+
+2007-09-16 19:40:31 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Use lock to protect variable.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_set_property),
+	  (gst_rtp_bin_get_property):
+	  Use lock to protect variable.
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_class_init),
+	  (gst_jitter_buffer_sink_parse_caps), (gst_rtp_jitter_buffer_chain),
+	  (convert_rtptime_to_gsttime), (gst_rtp_jitter_buffer_loop):
+	  Reconstruct GST timestamp from RTP timestamps based on measured clock
+	  skew and sync offset.
+	  * gst/rtpmanager/rtpjitterbuffer.c: (rtp_jitter_buffer_init),
+	  (rtp_jitter_buffer_set_tail_changed),
+	  (rtp_jitter_buffer_set_clock_rate),
+	  (rtp_jitter_buffer_get_clock_rate), (calculate_skew),
+	  (rtp_jitter_buffer_insert), (rtp_jitter_buffer_peek):
+	  * gst/rtpmanager/rtpjitterbuffer.h:
+	  Measure clock skew.
+	  Add callback to be notfied when a new packet was inserted at the tail.
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_init),
+	  (calculate_jitter), (rtp_source_send_rtp):
+	  * gst/rtpmanager/rtpsource.h:
+	  Remove clock skew detection, it's move to the jitterbuffer now.
+
+2007-09-15 18:48:03 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Also set NTP base time on new sessions.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (create_session):
+	  Also set NTP base time on new sessions.
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_loop), (gst_rtp_jitter_buffer_query),
+	  (gst_rtp_jitter_buffer_set_property),
+	  (gst_rtp_jitter_buffer_get_property):
+	  Use the right lock to protect our variables.
+	  Fix some comment.
+	  * gst/rtpmanager/gstrtpsession.c:
+	  (gst_rtp_session_getcaps_send_rtp),
+	  (gst_rtp_session_chain_send_rtp), (create_send_rtp_sink):
+	  Implement getcaps on the sender sinkpad so that payloaders can negotiate
+	  the right SSRC.
+
+2007-09-12 21:23:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Various leak fixes.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (create_session), (free_session),
+	  (get_client), (free_client), (gst_rtp_bin_associate),
+	  (free_stream), (gst_rtp_bin_class_init), (gst_rtp_bin_dispose),
+	  (gst_rtp_bin_finalize):
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_class_init),
+	  (gst_rtp_jitter_buffer_finalize):
+	  * gst/rtpmanager/gstrtpptdemux.c: (gst_rtp_pt_demux_release):
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_finalize),
+	  (gst_rtp_session_set_property), (gst_rtp_session_chain_recv_rtp),
+	  (gst_rtp_session_chain_send_rtp):
+	  * gst/rtpmanager/gstrtpssrcdemux.c:
+	  (gst_rtp_ssrc_demux_class_init), (gst_rtp_ssrc_demux_dispose):
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_finalize):
+	  * gst/rtpmanager/rtpsession.h:
+	  Various leak fixes.
+
+2007-09-12 18:04:32 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Calculate and configure the NTP base time so that we can generate better
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (calc_ntp_ns_base),
+	  (gst_rtp_bin_change_state), (new_payload_found), (create_send_rtp):
+	  Calculate and configure the NTP base time so that we can generate better
+	  NTP times in SR packets.
+	  Set caps on new ghostpad.
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_loop):
+	  Clean debug statement.
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_class_init),
+	  (gst_rtp_session_init), (gst_rtp_session_set_property),
+	  (gst_rtp_session_get_property), (get_current_ntp_ns_time),
+	  (rtcp_thread), (gst_rtp_session_event_recv_rtp_sink),
+	  (gst_rtp_session_internal_links), (gst_rtp_session_chain_recv_rtp),
+	  (gst_rtp_session_event_send_rtp_sink),
+	  (gst_rtp_session_chain_send_rtp), (create_recv_rtp_sink),
+	  (create_send_rtp_sink):
+	  * gst/rtpmanager/gstrtpsession.h:
+	  Add ntp-ns-base property to convert running_time to NTP time.
+	  Handle NEWSEGMENT events on send and recv RTP pads so that we can
+	  calculate the running time and thus NTP time of the packets.
+	  Simplify getting the current NTP time using the pipeline clock.
+	  Implement internal links functions.
+	  Use the buffer timestamp to calculate the NTP time instead of the clock.
+	  * gst/rtpmanager/gstrtpssrcdemux.c: (create_demux_pad_for_ssrc),
+	  (gst_rtp_ssrc_demux_init), (gst_rtp_ssrc_demux_sink_event),
+	  (gst_rtp_ssrc_demux_chain), (gst_rtp_ssrc_demux_rtcp_chain),
+	  (gst_rtp_ssrc_demux_internal_links),
+	  (gst_rtp_ssrc_demux_src_query):
+	  * gst/rtpmanager/gstrtpssrcdemux.h:
+	  Implement internal links function.
+	  Calculate the diff between different streams, this might be used later
+	  to get the inter stream latency.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_send_rtp):
+	  Simple cleanup.
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_init),
+	  (calculate_jitter), (rtp_source_send_rtp), (rtp_source_get_new_sr):
+	  Make the clock skew window a little bigger.
+	  Apply the clock skew to all buffers, not just one with a new timestamp.
+	  Calculate and debug sender clock drift.
+	  Use extended last timestamp to interpollate for SR reports.
+
+2007-09-04 15:23:34 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/rtpmanager/gstrtpsession.c: Make compiler happy: fix compilation with -Wall -Werror (#473562).
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c:
+	  Make compiler happy: fix compilation with -Wall -Werror
+	  (#473562).
+
+2007-09-03 21:19:34 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Updated example pipelines in docs.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin-marshal.list:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_get_client),
+	  (gst_rtp_bin_associate), (gst_rtp_bin_sync_chain), (create_stream),
+	  (gst_rtp_bin_init), (caps_changed), (new_ssrc_pad_found),
+	  (create_recv_rtp), (create_recv_rtcp), (create_send_rtp):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  Updated example pipelines in docs.
+	  Handle sync_rtcp buffers from the SSRC demuxer to perform lip-sync.
+	  Set the default latency correctly.
+	  Add some more points where we can get caps.
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_class_init),
+	  (gst_jitter_buffer_sink_parse_caps), (gst_rtp_jitter_buffer_loop),
+	  (gst_rtp_jitter_buffer_query),
+	  (gst_rtp_jitter_buffer_set_property),
+	  (gst_rtp_jitter_buffer_get_property):
+	  Add ts-offset property to control timestamping.
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_class_init),
+	  (gst_rtp_session_init), (gst_rtp_session_set_property),
+	  (gst_rtp_session_get_property), (get_current_ntp_ns_time),
+	  (rtcp_thread), (stop_rtcp_thread), (gst_rtp_session_change_state),
+	  (gst_rtp_session_send_rtcp), (gst_rtp_session_sync_rtcp),
+	  (gst_rtp_session_cache_caps), (gst_rtp_session_clock_rate),
+	  (gst_rtp_session_sink_setcaps), (gst_rtp_session_chain_recv_rtp),
+	  (gst_rtp_session_event_send_rtp_sink),
+	  (gst_rtp_session_chain_send_rtp), (create_recv_rtp_sink),
+	  (create_recv_rtcp_sink), (create_send_rtp_sink),
+	  (create_send_rtcp_src):
+	  Various cleanups.
+	  Feed rtpsession manager with NTP time based on pipeline clock when
+	  handling RTP packets and RTCP timeouts.
+	  Perform all RTCP with the system clock.
+	  Set caps on RTCP outgoing buffers.
+	  * gst/rtpmanager/gstrtpssrcdemux.c: (find_demux_pad_for_ssrc),
+	  (create_demux_pad_for_ssrc), (gst_rtp_ssrc_demux_base_init),
+	  (gst_rtp_ssrc_demux_init), (gst_rtp_ssrc_demux_sink_event),
+	  (gst_rtp_ssrc_demux_rtcp_sink_event), (gst_rtp_ssrc_demux_chain),
+	  (gst_rtp_ssrc_demux_rtcp_chain):
+	  * gst/rtpmanager/gstrtpssrcdemux.h:
+	  Also demux RTCP messages.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_set_callbacks),
+	  (update_arrival_stats), (rtp_session_process_rtp),
+	  (rtp_session_process_rb), (rtp_session_process_sr),
+	  (rtp_session_process_rr), (rtp_session_process_rtcp),
+	  (rtp_session_send_rtp), (rtp_session_send_bye),
+	  (session_start_rtcp), (session_report_blocks), (session_cleanup),
+	  (rtp_session_on_timeout):
+	  * gst/rtpmanager/rtpsession.h:
+	  Remove the get_time callback, the GStreamer part will feed us with
+	  enough timing information.
+	  Split sync timing and RTCP timing information.
+	  Factor out common RB handling for SR and RR.
+	  Send out SR RTCP packets for lip-sync.
+	  Move SR and RR packet info generation to the source.
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_init),
+	  (rtp_source_update_caps), (get_clock_rate), (calculate_jitter),
+	  (rtp_source_process_rtp), (rtp_source_send_rtp),
+	  (rtp_source_process_sr), (rtp_source_process_rb),
+	  (rtp_source_get_new_sr), (rtp_source_get_new_rb),
+	  (rtp_source_get_last_sr):
+	  * gst/rtpmanager/rtpsource.h:
+	  * gst/rtpmanager/rtpstats.h:
+	  Use caps on incomming buffers to get timing information when they are
+	  there.
+	  Calculate clock scew of the receiver compared to the sender and adjust
+	  the rtp timestamps.
+	  Calculate the round trip in sources.
+	  Do SR and RR calculations in the source.
+
+2007-08-31 15:26:14 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Use extended timestamp to release buffers from the jitterbuffer so that we can h...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_flush_stop),
+	  (gst_rtp_jitter_buffer_change_state), (gst_rtp_jitter_buffer_loop):
+	  Use extended timestamp to release buffers from the jitterbuffer so that
+	  we can handle the rtp wraparound correctly.
+
+2007-08-29 16:56:27 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Improve Comments.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_loop):
+	  Improve Comments.
+	  * gst/rtpmanager/gstrtpsession.c: (stop_rtcp_thread),
+	  (gst_rtp_session_change_state), (gst_rtp_session_parse_caps),
+	  (gst_rtp_session_clock_rate), (gst_rtp_session_sink_setcaps),
+	  (gst_rtp_session_event_send_rtp_sink), (create_recv_rtp_sink),
+	  (create_send_rtp_sink):
+	  Also parse the sink caps for clock-rate instead of only relying on the
+	  result of the signal.
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_send_rtp):
+	  Make sure we fetch the clock rate for payloads we are sending out so
+	  that we can use it for SR reports.
+
+2007-08-29 01:22:43 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpsession.*: Distribute synchronisation parameters to the session manager so that it can generate ...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c: (stop_rtcp_thread),
+	  (gst_rtp_session_change_state),
+	  (gst_rtp_session_event_send_rtp_sink):
+	  * gst/rtpmanager/gstrtpsession.h:
+	  Distribute synchronisation parameters to the session manager so that it
+	  can generate correct SR packets for lip-sync.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_set_base_time),
+	  (rtp_session_set_timestamp_sync), (session_start_rtcp):
+	  * gst/rtpmanager/rtpsession.h:
+	  Add methods for setting sync parameters.
+	  Set correct RTP time in SR packets using the sync params.
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_send_rtp):
+	  * gst/rtpmanager/rtpsource.h:
+	  Record last RTP <-> GST timestamp so that we can use them to convert NTP
+	  to RTP timestamps in SR packets.
+
+2007-08-28 20:30:16 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Add some more advanced example pipelines.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_clear_pt_map):
+	  Add some more advanced example pipelines.
+	  * gst/rtpmanager/gstrtpsession.c: (rtcp_thread),
+	  (stop_rtcp_thread), (gst_rtp_session_send_rtcp):
+	  Add some debug and FIXME.
+	  Release LOCK when performing session cleanup.
+	  * gst/rtpmanager/rtpsession.c: (session_report_blocks):
+	  Add some debug.
+	  * gst/rtpmanager/rtpsource.c: (calculate_jitter),
+	  (rtp_source_send_rtp):
+	  Make sure we always send RTP packets with the session SSRC.
+
+2007-08-27 21:17:21 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: When synchronizing buffers, take peer latency into account.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_change_state), (gst_rtp_jitter_buffer_loop),
+	  (gst_rtp_jitter_buffer_query):
+	  When synchronizing buffers, take peer latency into account.
+	  Don't try to add our latency to invalid peer max latency values.
+
+2007-08-23 21:39:58 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Rename all GstRTPFoo structs to GstRtpFoo so that GST_BOILERPLATE registers a GType that's different than the GstRTPF...
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-bad-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-bad-plugins.interfaces:
+	  * docs/plugins/gst-plugins-bad-plugins.signals:
+	  * gst/rtpmanager/gstrtpbin.c:
+	  * gst/rtpmanager/gstrtpbin.h:
+	  * gst/rtpmanager/gstrtpclient.c:
+	  * gst/rtpmanager/gstrtpclient.h:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  * gst/rtpmanager/gstrtpjitterbuffer.h:
+	  * gst/rtpmanager/gstrtpptdemux.c:
+	  * gst/rtpmanager/gstrtpptdemux.h:
+	  * gst/rtpmanager/gstrtpsession.c:
+	  * gst/rtpmanager/gstrtpsession.h:
+	  * gst/rtpmanager/gstrtpssrcdemux.c:
+	  * gst/rtpmanager/gstrtpssrcdemux.h:
+	  Rename all GstRTPFoo structs to GstRtpFoo so that GST_BOILERPLATE
+	  registers a GType that's different than the GstRTPFoo types that
+	  farsight registers (luckily GType names are case sensitive). Should
+	  finally fix #430664.
+
+2007-08-21 17:18:29 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: When drop-on-latency is set but we have no latency configured, just push the buf...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_chain),
+	  (gst_rtp_jitter_buffer_set_property):
+	  When drop-on-latency is set but we have no latency configured, just push
+	  the buffer as fast as possible.
+	  Fix typo in comment.
+
+2007-08-21 16:04:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/rtpjitterbuffer.*: Fix undefined overflow prone ts_diff handling.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/rtpjitterbuffer.c:
+	  (rtp_jitter_buffer_get_ts_diff):
+	  * gst/rtpmanager/rtpjitterbuffer.h:
+	  Fix undefined overflow prone ts_diff handling.
+
+2007-08-16 11:40:16 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Fix EOS handling.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_sink_event), (gst_rtp_jitter_buffer_chain),
+	  (gst_rtp_jitter_buffer_loop):
+	  Fix EOS handling.
+	  Convert some DEBUG into WARNINGs.
+	  Pause task when flushing.
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_class_init),
+	  (rtcp_thread), (gst_rtp_session_event_recv_rtcp_sink):
+	  Use system clock for RTCP session management timeouts.
+	  * gst/rtpmanager/rtpsession.c: (on_new_ssrc), (on_ssrc_collision),
+	  (on_ssrc_validated), (on_bye_ssrc), (on_bye_timeout), (on_timeout):
+	  Release the session lock when emiting signals.
+
+2007-08-13 06:16:40 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/rtpmanager/rtpjitterbuffer.c: Include stdlib.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/rtpjitterbuffer.c:
+	  Include stdlib.
+
+2007-08-10 17:16:53 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Remove complicated async queue and replace with more simple jitterbuffer code while also fixing some...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/Makefile.am:
+	  * gst/rtpmanager/async_jitter_queue.c:
+	  * gst/rtpmanager/async_jitter_queue.h:
+	  * gst/rtpmanager/rtpjitterbuffer.c: (rtp_jitter_buffer_class_init),
+	  (rtp_jitter_buffer_init), (rtp_jitter_buffer_finalize),
+	  (rtp_jitter_buffer_new), (compare_seqnum),
+	  (rtp_jitter_buffer_insert), (rtp_jitter_buffer_pop),
+	  (rtp_jitter_buffer_flush), (rtp_jitter_buffer_num_packets),
+	  (rtp_jitter_buffer_get_ts_diff):
+	  * gst/rtpmanager/rtpjitterbuffer.h:
+	  Remove complicated async queue and replace with more simple jitterbuffer
+	  code while also fixing some bugs.
+	  * gst/rtpmanager/gstrtpbin-marshal.list:
+	  * gst/rtpmanager/gstrtpbin.c: (on_new_ssrc), (on_ssrc_collision),
+	  (on_ssrc_validated), (on_bye_ssrc), (on_bye_timeout), (on_timeout),
+	  (create_session), (gst_rtp_bin_class_init), (create_recv_rtp),
+	  (create_send_rtp):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_init), (gst_rtp_jitter_buffer_dispose),
+	  (gst_jitter_buffer_sink_parse_caps),
+	  (gst_rtp_jitter_buffer_flush_start),
+	  (gst_rtp_jitter_buffer_flush_stop),
+	  (gst_rtp_jitter_buffer_change_state),
+	  (gst_rtp_jitter_buffer_sink_event), (gst_rtp_jitter_buffer_chain),
+	  (gst_rtp_jitter_buffer_loop), (gst_rtp_jitter_buffer_set_property):
+	  * gst/rtpmanager/gstrtpsession.c: (on_new_ssrc),
+	  (on_ssrc_collision), (on_ssrc_validated), (on_bye_ssrc),
+	  (on_bye_timeout), (on_timeout), (gst_rtp_session_class_init),
+	  (gst_rtp_session_init):
+	  * gst/rtpmanager/gstrtpsession.h:
+	  * gst/rtpmanager/rtpsession.c: (on_bye_ssrc), (session_cleanup):
+	  Use new jitterbuffer code.
+	  Expose some new signals in preparation for handling EOS.
+
+2007-07-18 07:35:32 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Add stdlib include (free, atoi, exit).
+	  Original commit message from CVS:
+	  * examples/app/appsrc_ex.c:
+	  * examples/switch/switcher.c:
+	  * ext/neon/gstneonhttpsrc.c:
+	  * ext/timidity/gstwildmidi.c:
+	  * ext/x264/gstx264enc.c:
+	  * gst/mve/mveaudioenc.c: (mve_compress_audio):
+	  * gst/rtpmanager/gstrtpclient.c:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  * gst/spectrum/demo-audiotest.c:
+	  * gst/spectrum/demo-osssrc.c:
+	  * sys/dvb/gstdvbsrc.c:
+	  Add stdlib include (free, atoi, exit).
+
+2007-06-22 20:23:18 +0000  Jens Granseuer <jensgr@gmx.net>
+
+	  gst/: Build fixes for gcc-2.9x (no mid-block variable declarations etc.).
+	  Original commit message from CVS:
+	  Patch by: Jens Granseuer  <jensgr at gmx net>
+	  * gst/equalizer/gstiirequalizer.c:
+	  * gst/equalizer/gstiirequalizer10bands.c:
+	  * gst/equalizer/gstiirequalizer3bands.c:
+	  * gst/equalizer/gstiirequalizernbands.c:
+	  * gst/rtpmanager/async_jitter_queue.c:
+	  (async_jitter_queue_push_sorted):
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_chain):
+	  * gst/switch/gstswitch.c: (gst_switch_chain):
+	  Build fixes for gcc-2.9x (no mid-block variable declarations etc.).
+	  Fixes #450185.
+
+2007-05-28 16:37:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  Rename elements to avoid conflict with farsight elements with the same name. Fixes #430664.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * gst/rtpmanager/gstrtpbin.c: (create_session), (create_stream),
+	  (gst_rtp_bin_class_init), (create_recv_rtp), (create_recv_rtcp),
+	  (create_send_rtp), (create_rtcp), (gst_rtp_bin_request_new_pad):
+	  * gst/rtpmanager/gstrtpclient.c: (create_stream),
+	  (gst_rtp_client_request_new_pad):
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_clear_pt_map), (gst_rtp_jitter_buffer_loop):
+	  * gst/rtpmanager/gstrtpmanager.c: (plugin_init):
+	  * gst/rtpmanager/gstrtpptdemux.c:
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_class_init),
+	  (gst_rtp_session_request_new_pad):
+	  * gst/rtpmanager/gstrtpssrcdemux.c:
+	  Rename elements to avoid conflict with farsight elements with the same
+	  name. Fixes #430664.
+
+2007-05-23 13:08:52 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  Document stuff.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_class_init):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  * gst/rtpmanager/gstrtpclient.c:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_class_init),
+	  (gst_rtp_jitter_buffer_clear_pt_map), (gst_rtp_jitter_buffer_loop):
+	  * gst/rtpmanager/gstrtpjitterbuffer.h:
+	  * gst/rtpmanager/gstrtpptdemux.c: (gst_rtp_pt_demux_class_init),
+	  (gst_rtp_pt_demux_clear_pt_map):
+	  * gst/rtpmanager/gstrtpptdemux.h:
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_class_init),
+	  (rtcp_thread), (gst_rtp_session_clear_pt_map):
+	  * gst/rtpmanager/gstrtpsession.h:
+	  * gst/rtpmanager/gstrtpssrcdemux.c:
+	  (gst_rtp_ssrc_demux_class_init):
+	  Document stuff.
+	  Add clear-pt-map action signal where needed.
+
+2007-05-15 13:29:53 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpptdemux.c: We always use fixed caps.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpptdemux.c: (gst_rtp_pt_demux_chain):
+	  We always use fixed caps.
+
+2007-05-15 03:45:45 +0000  David Schleef <ds@schleef.org>
+
+	  gst/rtpmanager/gstrtpbin.c: g_hash_table_remove_all() only exists in 2.12.  Work around.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c:
+	  g_hash_table_remove_all() only exists in 2.12.  Work around.
+
+2007-05-14 15:28:36 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/async_jitter_queue.c: Fix leak when flushing.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/async_jitter_queue.c:
+	  (async_jitter_queue_set_flushing_unlocked):
+	  Fix leak when flushing.
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_clear_pt_map),
+	  (gst_rtp_bin_class_init):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  Add clear-pt-map signal.
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_flush_stop),
+	  (gst_rtp_jitter_buffer_sink_event), (gst_rtp_jitter_buffer_loop):
+	  Init clock-rate to -1 to mark unknow clock rate.
+	  Fix flushing.
+
+2007-05-10 14:02:07 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/qtdemux/qtdemux.c (gst_qtdemux_move_stream, gst_qtdemux_loop_state_header, gst_qtdemux_activate_segment, gst_qtde...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c (gst_qtdemux_move_stream,
+	  gst_qtdemux_loop_state_header, gst_qtdemux_activate_segment,
+	  gst_qtdemux_prepare_current_sample, gst_qtdemux_combine_flows,
+	  gst_qtdemux_loop_state_movie, gst_qtdemux_loop,
+	  qtdemux_parse_segments, qtdemux_parse_trak):
+	  * gst/rtpmanager/rtpsession.c (rtp_session_get_bandwidth,
+	  rtp_session_get_rtcp_bandwidth, rtp_session_get_cname,
+	  rtp_session_get_name, rtp_session_get_email, rtp_session_get_phone,
+	  rtp_session_get_location, rtp_session_get_tool,
+	  rtp_session_process_bye, session_report_blocks):
+	  * gst/rtpmanager/rtpsource.c (rtp_source_process_rtp,
+	  rtp_source_send_rtp, rtp_source_process_sr, rtp_source_process_rb):
+	  More format arg fixing (spotted by Ali Sabil <ali.sabil@gmail.com>).
+	  * gst/switch/Makefile.am:
+	  Add require libraries(spotted by Ali Sabil <ali.sabil@gmail.com>).
+
+2007-05-10 12:38:49 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	* gst/rtpmanager/async_jitter_queue.c:
+	  gst/rtpmanager/async_jitter_queue.c (tail_buffer_duration, async_jitter_queue_ref, async_jitter_queue_ref_unlocked, a...
+	  Original commit message from CVS:
+	  * gst/rtpmanager/async_jitter_queue.c (tail_buffer_duration,
+	  async_jitter_queue_ref, async_jitter_queue_ref_unlocked,
+	  async_jitter_queue_set_low_threshold,
+	  async_jitter_queue_length_ts_units_unlocked,
+	  async_jitter_queue_unref_and_unlock, async_jitter_queue_unref,
+	  async_jitter_queue_lock, async_jitter_queue_push,
+	  async_jitter_queue_push_unlocked, async_jitter_queue_push_sorted,
+	  async_jitter_queue_pop_intern_unlocked, async_jitter_queue_pop,
+	  async_jitter_queue_pop_unlocked, async_jitter_queue_length_unlocked,
+	  async_jitter_queue_set_flushing_unlocked,
+	  async_jitter_queue_unset_flushing_unlocked):
+	  Format arg fix (spotted by Ali Sabil <ali.sabil@gmail.com>)
+
+2007-05-09 11:24:22 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Pass queries upstream.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_query):
+	  Pass queries upstream.
+
+2007-05-04 12:32:27 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Add some debug info.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_query):
+	  Add some debug info.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_init),
+	  (rtp_session_send_rtp):
+	  Store real user name in the session.
+
+2007-04-30 13:41:30 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/async_jitter_queue.c: Fix the case where the buffer underruns and does not block.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/async_jitter_queue.c: (signal_waiting_threads),
+	  (async_jitter_queue_pop_intern_unlocked):
+	  Fix the case where the buffer underruns and does not block.
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_base_init),
+	  (create_recv_rtcp), (create_send_rtp), (create_rtcp),
+	  (gst_rtp_bin_request_new_pad):
+	  Rename RTCP send pad, like in the session manager.
+	  Allow getting an RTCP pad for receiving even if we don't receive RTP.
+	  fix handling of send_rtp_src pad.
+	  * gst/rtpmanager/gstrtpptdemux.c: (gst_rtp_pt_demux_chain):
+	  When no pt map could be found, fall back to the sinkpad caps.
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_process_rtp),
+	  (gst_rtp_session_send_rtp), (create_recv_rtp_sink),
+	  (create_recv_rtcp_sink), (create_send_rtp_sink),
+	  (create_send_rtcp_src):
+	  Fix pad names.
+	  * gst/rtpmanager/rtpsession.c: (source_push_rtp),
+	  (rtp_session_create_source), (rtp_session_process_sr),
+	  (rtp_session_send_rtp), (session_start_rtcp):
+	  * gst/rtpmanager/rtpsession.h:
+	  Unlock session when performing a callback.
+	  Add callbacks for the internal session object.
+	  Fix sending of RTP packets.
+	  first attempt at adding NTP times in the SR packets.
+	  Small debug and doc improvements.
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_send_rtp):
+	  Update stats for SR reports.
+
+2007-04-29 14:46:27 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpsession.c: Remove debug.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_send_rtcp):
+	  Remove debug.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_process_sr),
+	  (rtp_session_process_sdes), (calculate_rtcp_interval),
+	  (rtp_session_next_timeout), (session_report_blocks):
+	  * gst/rtpmanager/rtpstats.c: (rtp_stats_calculate_rtcp_interval):
+	  Improve debugging
+	  Fix interval for BYE/RTCP packets.
+
+2007-04-27 15:09:12 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpsession.c: Move reconsideration code to the rtpsession object.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c: (rtcp_thread),
+	  (gst_rtp_session_send_rtcp), (gst_rtp_session_reconsider):
+	  Move reconsideration code to the rtpsession object.
+	  Simplify timout handling and add reconsideration.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_class_init),
+	  (rtp_session_init), (rtp_session_finalize), (on_bye_ssrc),
+	  (on_bye_timeout), (on_timeout), (rtp_session_set_callbacks),
+	  (obtain_source), (rtp_session_create_source),
+	  (update_arrival_stats), (rtp_session_process_rtp),
+	  (rtp_session_process_sr), (rtp_session_process_rr),
+	  (rtp_session_process_bye), (rtp_session_process_rtcp),
+	  (calculate_rtcp_interval), (rtp_session_send_bye),
+	  (rtp_session_next_timeout), (session_start_rtcp),
+	  (session_report_blocks), (session_cleanup), (session_sdes),
+	  (session_bye), (is_rtcp_time), (rtp_session_on_timeout):
+	  * gst/rtpmanager/rtpsession.h:
+	  Handle timeout of inactive sources and senders.
+	  Implement BYE scheduling.
+	  * gst/rtpmanager/rtpsource.c: (calculate_jitter),
+	  (rtp_source_process_sr), (rtp_source_get_last_sr),
+	  (rtp_source_get_last_rb):
+	  * gst/rtpmanager/rtpsource.h:
+	  Add members to check for timeouts.
+	  * gst/rtpmanager/rtpstats.c: (rtp_stats_init_defaults),
+	  (rtp_stats_calculate_rtcp_interval), (rtp_stats_add_rtcp_jitter),
+	  (rtp_stats_calculate_bye_interval):
+	  * gst/rtpmanager/rtpstats.h:
+	  Use RFC algorithm for calculating the reporting interval.
+
+2007-04-25 16:38:03 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpsession.c: Implement forward and reverse reconsideration.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpsession.c: (rtcp_thread):
+	  Implement forward and reverse reconsideration.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_get_num_sources),
+	  (rtp_session_get_num_active_sources), (rtp_session_process_sr),
+	  (session_report_blocks):
+	  * gst/rtpmanager/rtpsession.h:
+	  Small cleanups.
+
+2007-04-25 15:48:46 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.*: Make default jitterbuffer latency configurable.
+	  Original commit message from CVS:
+	  reviewed by: <delete if not using a buddy>
+	  * gst/rtpmanager/gstrtpbin.c: (create_stream),
+	  (gst_rtp_bin_class_init), (gst_rtp_bin_set_property),
+	  (gst_rtp_bin_get_property):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  Make default jitterbuffer latency configurable.
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_class_init),
+	  (gst_jitter_buffer_sink_parse_caps), (gst_rtp_jitter_buffer_loop),
+	  (gst_rtp_jitter_buffer_set_property),
+	  (gst_rtp_jitter_buffer_get_property):
+	  Debuging cleanups.
+
+2007-04-25 13:19:36 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Report NO_PREROLL when going to PAUSED.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_change_state):
+	  Report NO_PREROLL when going to PAUSED.
+	  * gst/rtpmanager/gstrtpsession.c: (rtcp_thread):
+	  Don't send RTCP right before we are shutting down.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_process_rtp),
+	  (rtp_session_process_sr), (session_report_blocks),
+	  (rtp_session_perform_reporting):
+	  Improve report blocks.
+	  * gst/rtpmanager/rtpsource.c: (calculate_jitter), (init_seq),
+	  (rtp_source_process_rtp), (rtp_source_process_sr),
+	  (rtp_source_process_rb), (rtp_source_get_last_sr),
+	  (rtp_source_get_last_rb):
+	  * gst/rtpmanager/rtpsource.h:
+	  * gst/rtpmanager/rtpstats.h:
+	  Cleanups, add methods to access stats.
+
+2007-04-25 08:30:48 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: fix for pad name change
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (create_rtcp):
+	  fix for pad name change
+	  * gst/rtpmanager/gstrtpsession.c: (rtcp_thread),
+	  (gst_rtp_session_send_rtcp), (gst_rtp_session_clock_rate):
+	  Fix for renamed methods.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_init),
+	  (rtp_session_finalize), (rtp_session_set_cname),
+	  (rtp_session_get_cname), (rtp_session_set_name),
+	  (rtp_session_get_name), (rtp_session_set_email),
+	  (rtp_session_get_email), (rtp_session_set_phone),
+	  (rtp_session_get_phone), (rtp_session_set_location),
+	  (rtp_session_get_location), (rtp_session_set_tool),
+	  (rtp_session_get_tool), (rtp_session_set_note),
+	  (rtp_session_get_note), (source_push_rtp), (obtain_source),
+	  (rtp_session_add_source), (rtp_session_get_source_by_ssrc),
+	  (rtp_session_create_source), (rtp_session_process_rtp),
+	  (rtp_session_process_sr), (rtp_session_process_sdes),
+	  (rtp_session_process_rtcp), (rtp_session_send_rtp),
+	  (rtp_session_get_reporting_interval), (session_report_blocks),
+	  (session_sdes), (rtp_session_perform_reporting):
+	  * gst/rtpmanager/rtpsession.h:
+	  Prepare for implementing SSRC sampling.
+	  Create SSRC for the session.
+	  Add methods to set the SDES entries.
+	  fix accounting of senders/receivers.
+	  Implement SR/RR/SDES RTCP reporting.
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_init), (init_seq),
+	  (rtp_source_process_rtp), (rtp_source_process_sr):
+	  * gst/rtpmanager/rtpsource.h:
+	  Implement extended sequence number.
+	  * gst/rtpmanager/rtpstats.c: (rtp_stats_calculate_rtcp_interval):
+	  * gst/rtpmanager/rtpstats.h:
+	  Rename some fields.
+
+2007-04-21 19:21:49 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/rtpmanager/rtpsession.c: Don't use GLib-2.10 API, we only require GLib 2.8 at the moment.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_finalize):
+	  Don't use GLib-2.10 API, we only require GLib 2.8 at the moment.
+
+2007-04-18 18:58:53 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  configure.ac: Disable rtpmanager for now because it depends on CVS -base.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Disable rtpmanager for now because it depends on CVS -base.
+	  * gst/rtpmanager/Makefile.am:
+	  Added new files for session manager.
+	  * gst/rtpmanager/gstrtpjitterbuffer.h:
+	  * gst/rtpmanager/gstrtpbin.c: (create_session), (get_pt_map),
+	  (create_stream), (pt_map_requested), (new_ssrc_pad_found):
+	  Some cleanups.
+	  the session manager can now also request a pt-map.
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_base_init),
+	  (gst_rtp_session_class_init), (gst_rtp_session_init),
+	  (gst_rtp_session_finalize), (rtcp_thread), (start_rtcp_thread),
+	  (stop_rtcp_thread), (gst_rtp_session_change_state),
+	  (gst_rtp_session_process_rtp), (gst_rtp_session_send_rtp),
+	  (gst_rtp_session_send_rtcp), (gst_rtp_session_clock_rate),
+	  (gst_rtp_session_get_time), (gst_rtp_session_event_recv_rtp_sink),
+	  (gst_rtp_session_chain_recv_rtp),
+	  (gst_rtp_session_event_recv_rtcp_sink),
+	  (gst_rtp_session_chain_recv_rtcp),
+	  (gst_rtp_session_event_send_rtp_sink),
+	  (gst_rtp_session_chain_send_rtp), (create_send_rtcp_src),
+	  (gst_rtp_session_request_new_pad):
+	  * gst/rtpmanager/gstrtpsession.h:
+	  We can ask for pt-map now too when the session manager needs it.
+	  Hook up to the new session manager, implement the needed callbacks for
+	  pushing data, getting clock time and requesting clock-rates.
+	  Rename rtcp_src to send_rtcp_src to make it clear that this RTCP is to
+	  be send to clients.
+	  Add code to start and stop the thread that will schedule RTCP through
+	  the session manager.
+	  * gst/rtpmanager/rtpsession.c: (rtp_session_class_init),
+	  (rtp_session_init), (rtp_session_finalize),
+	  (rtp_session_set_property), (rtp_session_get_property),
+	  (on_new_ssrc), (on_ssrc_collision), (on_ssrc_validated),
+	  (on_bye_ssrc), (rtp_session_new), (rtp_session_set_callbacks),
+	  (rtp_session_set_bandwidth), (rtp_session_get_bandwidth),
+	  (rtp_session_set_rtcp_bandwidth), (rtp_session_get_rtcp_bandwidth),
+	  (source_push_rtp), (source_clock_rate), (check_collision),
+	  (obtain_source), (rtp_session_add_source),
+	  (rtp_session_get_num_sources),
+	  (rtp_session_get_num_active_sources),
+	  (rtp_session_get_source_by_ssrc),
+	  (rtp_session_get_source_by_cname), (rtp_session_create_source),
+	  (update_arrival_stats), (rtp_session_process_rtp),
+	  (rtp_session_process_sr), (rtp_session_process_rr),
+	  (rtp_session_process_sdes), (rtp_session_process_bye),
+	  (rtp_session_process_app), (rtp_session_process_rtcp),
+	  (rtp_session_send_rtp), (rtp_session_get_rtcp_interval),
+	  (rtp_session_produce_rtcp):
+	  * gst/rtpmanager/rtpsession.h:
+	  The advanced beginnings of the main session manager that handles the
+	  participant database of RTPSources, SSRC probation, SSRC collisions,
+	  parse RTCP to update source stats. etc..
+	  * gst/rtpmanager/rtpsource.c: (rtp_source_class_init),
+	  (rtp_source_init), (rtp_source_finalize), (rtp_source_new),
+	  (rtp_source_set_callbacks), (rtp_source_set_as_csrc),
+	  (rtp_source_set_rtp_from), (rtp_source_set_rtcp_from),
+	  (push_packet), (get_clock_rate), (calculate_jitter),
+	  (rtp_source_process_rtp), (rtp_source_process_bye),
+	  (rtp_source_send_rtp), (rtp_source_process_sr),
+	  (rtp_source_process_rb):
+	  * gst/rtpmanager/rtpsource.h:
+	  Object that encapsulates an SSRC and its state in the database.
+	  Calculates the jitter and transit times of data packets.
+	  * gst/rtpmanager/rtpstats.c: (rtp_stats_init_defaults),
+	  (rtp_stats_calculate_rtcp_interval), (rtp_stats_add_rtcp_jitter):
+	  * gst/rtpmanager/rtpstats.h:
+	  Various stats regarding the session and sources.
+	  Used to calculate the RTCP interval.
+
+2007-04-13 09:20:55 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Protect lists and structures with locks.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (create_session), (get_pt_map),
+	  (gst_rtp_bin_init), (gst_rtp_bin_finalize), (new_ssrc_pad_found),
+	  (create_recv_rtp), (gst_rtp_bin_request_new_pad):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  * gst/rtpmanager/gstrtpclient.c:
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_class_init),
+	  (gst_rtp_session_init), (gst_rtp_session_finalize),
+	  (gst_rtp_session_event_recv_rtp_sink),
+	  (gst_rtp_session_event_recv_rtcp_sink),
+	  (gst_rtp_session_chain_recv_rtcp),
+	  (gst_rtp_session_request_new_pad):
+	  Protect lists and structures with locks.
+	  Return FLOW_OK from RTCP messages for now.
+
+2007-04-12 08:18:32 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Emit pt map requests and cache results.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (create_session), (get_pt_map),
+	  (create_stream), (gst_rtp_bin_class_init), (pt_map_requested):
+	  Emit pt map requests and cache results.
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_class_init),
+	  (gst_jitter_buffer_sink_parse_caps),
+	  (gst_jitter_buffer_sink_setcaps),
+	  (gst_rtp_jitter_buffer_get_clock_rate),
+	  (gst_rtp_jitter_buffer_chain), (gst_rtp_jitter_buffer_loop):
+	  * gst/rtpmanager/gstrtpjitterbuffer.h:
+	  * gst/rtpmanager/gstrtpptdemux.c: (gst_rtp_pt_demux_chain):
+	  Emit request-pt-map signals.
+
+2007-04-11 13:49:54 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin-marshal.list: Some more custom marshallers.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin-marshal.list:
+	  Some more custom marshallers.
+	  * gst/rtpmanager/gstrtpbin.c: (create_session), (get_pt_map),
+	  (clock_rate_request), (create_stream), (gst_rtp_bin_class_init),
+	  (pt_map_requested), (new_ssrc_pad_found), (create_recv_rtp):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  Prepare for caching pt maps.
+	  Connect to signals to collect pt maps.
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_class_init),
+	  (gst_jitter_buffer_sink_setcaps), (gst_rtp_jitter_buffer_loop):
+	  * gst/rtpmanager/gstrtpjitterbuffer.h:
+	  Add request_clock_rate signal.
+	  Use scale insteat of scale_int because the later does not deal with
+	  negative numbers.
+	  * gst/rtpmanager/gstrtpptdemux.c: (gst_rtp_pt_demux_class_init),
+	  (gst_rtp_pt_demux_chain):
+	  * gst/rtpmanager/gstrtpptdemux.h:
+	  Implement request-pt-map signal.
+
+2007-04-10 09:14:07 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Added custom marshallers for signals.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/.cvsignore:
+	  * gst/rtpmanager/Makefile.am:
+	  * gst/rtpmanager/gstrtpbin-marshal.list:
+	  Added custom marshallers for signals.
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_class_init):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  Prepare for emiting pt map signals.
+	  * gst/rtpmanager/gstrtpptdemux.c: (gst_rtp_pt_demux_class_init):
+	  * gst/rtpmanager/gstrtpssrcdemux.c:
+	  (gst_rtp_ssrc_demux_class_init):
+	  Fix signals.
+
+2007-04-06 12:28:29 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.*: Provide a clock.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_class_init),
+	  (gst_rtp_bin_init), (gst_rtp_bin_provide_clock):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  Provide a clock.
+
+2007-04-06 12:07:30 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.c: Fix pad template name parsing.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (create_rtcp):
+	  Fix pad template name parsing.
+
+2007-04-05 16:10:24 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpjitterbuffer.c: Add some debug and comments.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_jitter_buffer_sink_setcaps), (gst_rtp_jitter_buffer_chain),
+	  (gst_rtp_jitter_buffer_loop):
+	  Add some debug and comments.
+	  Fix double unref() in error cases.
+
+2007-04-05 13:54:23 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/gstrtpbin.*: Add debugging category.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (find_session_by_id),
+	  (create_session), (find_stream_by_ssrc), (create_stream),
+	  (gst_rtp_bin_class_init), (new_payload_found),
+	  (new_ssrc_pad_found), (create_recv_rtp), (create_recv_rtcp),
+	  (create_send_rtp), (create_rtcp):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  Add debugging category.
+	  Added RTPStream to manage stream per SSRC, each with its own
+	  jitterbuffer and ptdemux.
+	  Added SSRCDemux.
+	  Connect to various SSRC and PT signals and create ghostpads, link stuff.
+	  * gst/rtpmanager/gstrtpmanager.c: (plugin_init):
+	  Added rtpbin to elements.
+	  * gst/rtpmanager/gstrtpptdemux.c: (gst_rtp_pt_demux_chain):
+	  Fix caps and forward GstFlowReturn
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_class_init),
+	  (gst_rtp_session_event_recv_rtp_sink),
+	  (gst_rtp_session_chain_recv_rtp),
+	  (gst_rtp_session_event_recv_rtcp_sink),
+	  (gst_rtp_session_chain_recv_rtcp),
+	  (gst_rtp_session_event_send_rtp_sink),
+	  (gst_rtp_session_chain_send_rtp), (create_recv_rtp_sink),
+	  (create_recv_rtcp_sink), (create_send_rtp_sink), (create_rtcp_src),
+	  (gst_rtp_session_request_new_pad):
+	  Add debug category.
+	  Add event handling
+	  * gst/rtpmanager/gstrtpssrcdemux.c: (find_rtp_pad_for_ssrc),
+	  (create_rtp_pad_for_ssrc), (gst_rtp_ssrc_demux_class_init),
+	  (gst_rtp_ssrc_demux_init), (gst_rtp_ssrc_demux_chain),
+	  (gst_rtp_ssrc_demux_change_state):
+	  * gst/rtpmanager/gstrtpssrcdemux.h:
+	  Add debug category.
+	  Add new-pt-pad signal.
+
+2007-04-04 10:23:15 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Added simple SSRC demuxer.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/Makefile.am:
+	  * gst/rtpmanager/gstrtpmanager.c: (plugin_init):
+	  * gst/rtpmanager/gstrtpssrcdemux.c: (find_pad_for_ssrc),
+	  (create_pad_for_ssrc), (gst_rtp_ssrc_demux_base_init),
+	  (gst_rtp_ssrc_demux_class_init), (gst_rtp_ssrc_demux_init),
+	  (gst_rtp_ssrc_demux_finalize), (gst_rtp_ssrc_demux_sink_event),
+	  (gst_rtp_ssrc_demux_chain), (gst_rtp_ssrc_demux_src_event),
+	  (gst_rtp_ssrc_demux_change_state):
+	  * gst/rtpmanager/gstrtpssrcdemux.h:
+	  Added simple SSRC demuxer.
+
+2007-04-03 11:35:39 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/: Some more ghostpad magic.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/gstrtpbin.c: (find_session_by_id),
+	  (create_session), (gst_rtp_bin_base_init), (create_recv_rtp),
+	  (create_recv_rtcp), (create_send_rtp), (create_rtcp),
+	  (gst_rtp_bin_request_new_pad):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  * gst/rtpmanager/gstrtpclient.c:
+	  Some more ghostpad magic.
+
+2007-04-03 09:51:13 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtpmanager/Makefile.am: Add .h file so it can be disted properly.
+	  Original commit message from CVS:
+	  * gst/rtpmanager/Makefile.am:
+	  Add .h file so it can be disted properly.
+
+2007-04-03 09:13:17 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  Add RTP session management elements. Still in progress.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/rtpmanager/Makefile.am:
+	  * gst/rtpmanager/async_jitter_queue.c: (async_jitter_queue_new),
+	  (signal_waiting_threads), (async_jitter_queue_ref),
+	  (async_jitter_queue_ref_unlocked),
+	  (async_jitter_queue_set_low_threshold),
+	  (async_jitter_queue_set_high_threshold),
+	  (async_jitter_queue_set_max_queue_length),
+	  (async_jitter_queue_get_g_queue), (calculate_ts_diff),
+	  (async_jitter_queue_length_ts_units_unlocked),
+	  (async_jitter_queue_unref_and_unlock), (async_jitter_queue_unref),
+	  (async_jitter_queue_lock), (async_jitter_queue_unlock),
+	  (async_jitter_queue_push), (async_jitter_queue_push_unlocked),
+	  (async_jitter_queue_push_sorted),
+	  (async_jitter_queue_push_sorted_unlocked),
+	  (async_jitter_queue_insert_after_unlocked),
+	  (async_jitter_queue_pop_intern_unlocked), (async_jitter_queue_pop),
+	  (async_jitter_queue_pop_unlocked), (async_jitter_queue_length),
+	  (async_jitter_queue_length_unlocked),
+	  (async_jitter_queue_set_flushing_unlocked),
+	  (async_jitter_queue_unset_flushing_unlocked),
+	  (async_jitter_queue_set_blocking_unlocked):
+	  * gst/rtpmanager/async_jitter_queue.h:
+	  * gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_base_init),
+	  (gst_rtp_bin_class_init), (gst_rtp_bin_init),
+	  (gst_rtp_bin_finalize), (gst_rtp_bin_set_property),
+	  (gst_rtp_bin_get_property), (gst_rtp_bin_change_state),
+	  (gst_rtp_bin_request_new_pad), (gst_rtp_bin_release_pad):
+	  * gst/rtpmanager/gstrtpbin.h:
+	  * gst/rtpmanager/gstrtpclient.c: (new_pad), (create_stream),
+	  (free_stream), (find_stream_by_ssrc), (gst_rtp_client_base_init),
+	  (gst_rtp_client_class_init), (gst_rtp_client_init),
+	  (gst_rtp_client_finalize), (gst_rtp_client_set_property),
+	  (gst_rtp_client_get_property), (gst_rtp_client_change_state),
+	  (gst_rtp_client_request_new_pad), (gst_rtp_client_release_pad):
+	  * gst/rtpmanager/gstrtpclient.h:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_base_init),
+	  (gst_rtp_jitter_buffer_class_init), (gst_rtp_jitter_buffer_init),
+	  (gst_rtp_jitter_buffer_dispose), (gst_rtp_jitter_buffer_getcaps),
+	  (gst_jitter_buffer_sink_setcaps), (free_func),
+	  (gst_rtp_jitter_buffer_flush_start),
+	  (gst_rtp_jitter_buffer_flush_stop),
+	  (gst_rtp_jitter_buffer_src_activate_push),
+	  (gst_rtp_jitter_buffer_change_state), (priv_compare_rtp_seq_lt),
+	  (compare_rtp_buffers_seq_num), (gst_rtp_jitter_buffer_sink_event),
+	  (gst_rtp_jitter_buffer_chain), (gst_rtp_jitter_buffer_loop),
+	  (gst_rtp_jitter_buffer_query),
+	  (gst_rtp_jitter_buffer_set_property),
+	  (gst_rtp_jitter_buffer_get_property):
+	  * gst/rtpmanager/gstrtpjitterbuffer.h:
+	  * gst/rtpmanager/gstrtpmanager.c: (plugin_init):
+	  * gst/rtpmanager/gstrtpptdemux.c: (gst_rtp_pt_demux_base_init),
+	  (gst_rtp_pt_demux_class_init), (gst_rtp_pt_demux_init),
+	  (gst_rtp_pt_demux_finalize), (gst_rtp_pt_demux_chain),
+	  (gst_rtp_pt_demux_getcaps), (find_pad_for_pt),
+	  (gst_rtp_pt_demux_setup), (gst_rtp_pt_demux_release),
+	  (gst_rtp_pt_demux_change_state):
+	  * gst/rtpmanager/gstrtpptdemux.h:
+	  * gst/rtpmanager/gstrtpsession.c: (gst_rtp_session_base_init),
+	  (gst_rtp_session_class_init), (gst_rtp_session_init),
+	  (gst_rtp_session_finalize), (gst_rtp_session_set_property),
+	  (gst_rtp_session_get_property), (gst_rtp_session_change_state),
+	  (gst_rtp_session_chain_recv_rtp),
+	  (gst_rtp_session_chain_recv_rtcp),
+	  (gst_rtp_session_chain_send_rtp), (create_recv_rtp_sink),
+	  (create_recv_rtcp_sink), (create_send_rtp_sink), (create_rtcp_src),
+	  (gst_rtp_session_request_new_pad), (gst_rtp_session_release_pad):
+	  * gst/rtpmanager/gstrtpsession.h:
+	  Add RTP session management elements. Still in progress.
+
+2009-08-10 13:30:23 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: push mode; cater for chunk padding
+
+2009-08-04 19:45:43 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: only use stream's pad after having checked it exists
+
+2009-08-04 13:38:09 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: sprinkle some more GST_DEBUG_FUNCPTR
+
+2009-08-04 13:36:36 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: post error message if no pads to push EOS event on
+
+2009-08-04 11:39:59 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix typo in warning message
+
+2009-08-04 11:39:39 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix some buffer ref handling
+
+2009-08-04 11:37:16 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: do not exceed maximum number of supported streams
+
+2009-08-04 11:35:18 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: prevent double unref; gst_avi_demux_parse_avih already unrefs
+
+2009-08-04 11:32:27 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: verify size of INFO LIST to satisfy subsequent expectations
+
+2009-07-29 15:25:38 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: check video stream framerate against avi header frame duration
+	  The former might be bogus in silly cases, and the latter seems to
+	  carry more weight.
+
+2009-08-04 12:16:13 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: streamline stream duration calculation
+
+2009-07-03 14:04:13 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/raw1394/gstdv1394src.c:
+	  dv1394src: Fix element for live usage... which has been broken for 2 years :(
+	  This is a live source, therefore:
+	  * Use GST_FORMAT_TIME as the default format
+	  * set_timestamp to True
+	  * properly implement query latency.
+	  This allows expected live usage like : playbin2 uri=dv://
+
+2009-08-09 09:43:41 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/raw1394/gstdv1394src.c:
+	  raw1394: Remove unneeded variable
+
+2009-08-09 09:43:29 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska: remove dead assignments
+
+2009-08-09 09:43:00 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	  rtp: Remove dead assignments and resulting unneeded variables.
+
+2009-08-10 09:53:28 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* ext/wavpack/Makefile.am:
+	* ext/wavpack/gstwavpackenc.c:
+	* ext/wavpack/gstwavpackenc.h:
+	* ext/wavpack/md5.c:
+	* ext/wavpack/md5.h:
+	  wavpack: Use GLib GChecksum instead of our own MD5 implementation
+	  This requires GLib 2.16 but that version is already required by core anyway.
+
+2009-08-08 00:47:48 -0300  Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/matroska/matroska-mux.h:
+	  matroska: Adds support to muxing/demuxing WMA
+	  Adds support for muxing wma audio family and fixes
+	  demuxing of wma family in matroskademux. matroskademux
+	  was broken because it missed codec_data.
+
+2009-08-06 20:15:17 -0300  Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+
+	* gst/matroska/matroska-mux.c:
+	  matroskamux: adds support for wmv family
+	  Adds support to WMV1, WMV2, WMV3 and other family formats that
+	  are signaled by the 'format' field in the caps (i.e. WVC1).
+	  Partially fixes #576378
+
+2009-08-09 14:19:42 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2src: if max == min width/height put an int in the probed caps, not an int range
+	  Fixes #560033.
+
+2009-08-09 13:58:07 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/osxaudio/gstosxaudiosrc.c:
+	  osxaudiosrc: if max_channels == min_channels, use an int instead of an int range in the caps
+
+2009-08-09 12:52:17 +0200  LoneStar <lone@auvtech.com>
+
+	* gst/id3demux/id3v2frames.c:
+	  id3demux: Try GST_*_TAG_ENCODING and locale encoding if tags are not UTF8
+	  Fixes bug #499242.
+
+2009-08-09 01:29:50 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: bump core/base requirements to latest release
+	  To avoid confusion.
+
+2009-08-09 01:27:01 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/flvmux.c:
+	  check: fix flvmux unit test on big endian machines
+	  flvmux only accepts raw audio in little endian, but audiotestsrc
+	  produces audio in the native endianness, which makes linking
+	  between audiotestsrc and flvmux fail on big endian machines. Add
+	  an audioconvert element in between the two to fix this.
+
+2009-02-15 18:49:44 +0000  Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.c:
+	  matroska: add kate subtitle support to matroska muxer and demuxer
+	  See #525743.
+
+2009-08-07 16:51:45 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/id3demux/id3v2.3.0.html:
+	  id3demux: add ID3 v2.3 spec as well
+
+2009-08-07 16:42:39 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/id3demux/id3v2frames.c:
+	  id3demux: sizes in ID3 v2.3 are unlikely to be sync-safe integers
+	  In ID3 v2.3 compressed frames will have a 4-byte data length indicator
+	  after the frame header to indicate the size of the decompressed data.
+	  This integer is unlikely to be a sync-safe integer for v2.3 tags,
+	  only in v2.4 it's sync-safe.
+
+2009-08-07 16:36:55 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/id3demux/id3tags.c:
+	  id3demux: fix typo in debug message
+
+2009-08-07 16:02:23 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/id3demux/id3tags.c:
+	* gst/id3demux/id3tags.h:
+	* gst/id3demux/id3v2frames.c:
+	* tests/check/elements/id3demux.c:
+	* tests/files/Makefile.am:
+	* tests/files/id3-588148-unsynced-v24.tag:
+	  id3demux: fix parsing of unsync'ed ID3 v2.4 tags and frames
+	  Reversing the unsynchronisation seems to work slightly differently
+	  for ID3 v2.3 tags and v2.4 tags: v2.3 tags don't have syncsafe frame
+	  sizes in the frame header, so the unsynchronisation is applied to
+	  the whole frame data including all the frame headers. v2.4 frames
+	  have sync-safe sizes, however, so the unsynchronisation only needs
+	  to be applied to the actual frame data, and it seems that's what's
+	  being done as well. So we need to undo the unsynchronisation on a
+	  per-frame basis for v2.4 tags for things to work properly.
+	  Fixes extraction of coverart/images from APIC frames in ID3 v2.4
+	  tags (#588148).
+	  Add unit test for this as well.
+
+2009-08-06 21:24:14 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Use SOUP_METHOD_GET instead of "GET" string
+	  Fixes bug #590970.
+
+2009-08-06 13:00:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: set the default slave method to skew
+	  Set the default slave method to the much better skew algorithm. This is the
+	  default in the new base class but we override this here as well for the
+	  upcomming release.
+
+2009-08-06 10:20:34 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: fix compilation with --disable-gst-debug
+
+2009-08-03 18:59:32 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtph264pay.h:
+	  rtph264pay: use array instead of queue
+
+2009-08-03 18:55:19 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtph264pay.h:
+	  rtph264pay: push NALs only after SPS/PPS
+	  parse complete (bytestream) buffer for SPS/PPS before pushing NALs.
+	  Fixes #564501.
+
+2009-08-04 14:44:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/v4l2/v4l2_calls.h:
+	  v4l2: Directly use GST_PTR_FORMAT for printing caps with the LOG_CAPS macro
+
+2009-08-04 11:17:17 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpqdmdepay.c:
+	  rtpqdm2depay: Fix debug statement.
+
+2009-08-04 09:32:07 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/v4l2_calls.h:
+	  v4l2: Remove some OMAP specific hacks
+	  They require special build flags and are not useful in general.
+
+2009-08-04 09:22:29 +0200  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2sink: change where buffers get dequeued
+	  It seems to cause strange occasional high latencies (almost 200ms) when dequeuing buffers from _buffer_alloc().  It is simpler and seems to work much better to dqbuf from the same thread that is queuing the next buffer.
+
+2009-08-04 09:14:20 +0200  Rob Clark <rob@ti.com>
+
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2bufferpool.c:
+	* sys/v4l2/gstv4l2bufferpool.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2sink.c:
+	* sys/v4l2/gstv4l2sink.h:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2_calls.h:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/v4l2/v4l2src_calls.h:
+	  v4l2: Add v4l2sink element
+	  This also does the following changes:
+	  (1) pull the bufferpool code out into gstv4l2bufferpool.c, and make a
+	  bit more generic so it can be used both for v4l2src and v4l2sink
+	  (2) move some of the device probing/configuration/caps stuff into
+	  gstv4l2object.c so it does not have to be duplicated between
+	  v4l2src and v4l2sink
+	  Fixes bug #590280.
+
+2009-08-04 07:07:45 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	  flvmux: Enable unit test now that it passes
+
+2009-08-03 21:21:39 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpsv3vdepay.c:
+	  rtpqdm2depay,rtpsv3vdepay: Add debugging category.
+
+2009-08-03 21:22:48 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpqdmdepay.h:
+	  rtpqdm2depay: Handle gaps in incoming packets.
+	  Whenever we see a gap, we flush the temporary packets (but not the adapter). If we
+	  had some data temporarily stored it will be outputted (the sound will sound a bit
+	  garbled... but that's how it sounds on MacOSX :)
+
+2009-08-03 19:01:07 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpqdmdepay.c:
+	  rtpqdmdepay: Fix CRC calculation and remove commented code.
+
+2009-08-02 13:42:12 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpqdmdepay.c:
+	* gst/rtp/gstrtpqdmdepay.h:
+	  rtp: New QDM2 rtp depayloader.
+	  Reverse-engineered by comparing:
+	  * A rtp hinted file provided by DarwinStreamingServer
+	  * The output procued by DSS for that same file
+	  Also used various streaming sources available on the internet to fine-tune
+	  the code.
+	  The header/codec_data extraction methods are from FFMpeg (LGPL).
+
+2009-08-03 21:24:44 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpsv3vdepay.c:
+	  rtpsv3vdepay: Properly fill codec_data and cleanup code a bite more.
+
+2009-08-03 19:02:17 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpsv3vdepay.c:
+	* gst/rtp/gstrtpsv3vdepay.h:
+	  rtpsv3vdepay: Only output buffers once we're configured.
+
+2009-08-03 19:02:00 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpsv3vdepay.c:
+	  rtpsv3vdepay: Add more encoding-name variants
+
+2009-08-03 20:08:33 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/flvmux.c:
+	  flvmux: Fix unit test to correctly handle request pads
+	  Request pads are removed by the element instance in PAUSED->READY
+	  so we need to re-request pads for every run and link them again.
+	  Last fix for bug #590447.
+
+2009-08-03 20:08:00 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Fix writing of the index for < 128 buffers
+	  Partially fixes bug #590447.
+
+2009-08-03 20:07:00 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Fix resetting of the element
+	  Reset the have_video/have_audio flags and make sure to
+	  properly release the request pads.
+	  Partially fixes bug #590447.
+
+2009-08-03 18:13:46 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: don't add non-utf8 chars to structures
+
+2009-08-03 18:02:31 +0200  Luc Deschenaux <luc.deschenaux at freesurf.ch>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegdepay.h:
+	  jpegdepay: use attributes for extra properties
+	  Use some of the SDP attributes when they are present to specify the output
+	  dimension and framerate. This allows us to receive jpeg frames larger than
+	  2040 width/height.
+	  Fixes #564437
+
+2009-08-03 18:01:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/README:
+	  RTP docs: update with attributes in caps
+
+2009-08-03 17:21:44 +0200  Luc Deschenaux <luc.deschenaux at freesurf.ch>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: put all SDP attributes on caps
+	  Put the SDP attributes on the caps too so that they can be used by
+	  depayloaders.
+	  See #564437
+
+2009-08-03 13:32:12 +0200  Jonathan Tellier <jonathan.tellier at gmail.com>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: initialize the probe with the server
+	  When creating a new probe, pass the server instead of the device string.
+	  fixes #590401
+
+2009-08-02 11:44:03 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/udp/gstmultiudpsink.c:
+	  multiudpsink: don't do things with side-effects inside g_return_val_if_fail()
+	  Someone might compile this code with -DG_DISABLE_ASSERT some day.
+
+2009-08-01 21:39:30 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: don't do logic within g_assert() statements
+	  Otherwise that code will just be expanded to nothing when compiled
+	  -DG_DISABLE_ASSERT (PS: why is mainloop_start() called in the init
+	  function and not when changing state to READY?)
+
+2009-08-01 17:07:42 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: send newsegment event when operating push-based and unframed
+	  For some reason flac doesn't call our metadata callback when we operate
+	  in push mode with unframed input, but that's where we set up the
+	  newsegment event (since that's where we'd get the duration from the
+	  stream info header), so we didn't send a newsegment event at all in this
+	  case. Hack around this by storing a generic newsegment event for now
+	  which will be used if we don't replace it with a better one that
+	  includes the duration.
+
+2009-08-01 16:48:36 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: small cleanups
+	  Remove some callback indirections which are no longer needed because
+	  there's only one decoder object type now. Also remove unused variable.
+
+2009-08-01 15:22:49 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: use gst_adapter_copy() to avoid unnecessary buffer merges
+	  gst_adapter_peek() will merge buffers as needed, which we can avoid
+	  here since we're doing a memcpy anyway and then flush the copied
+	  data from the adapter right away.
+
+2009-08-01 00:00:41 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: repair some broken indenting
+
+2009-08-01 12:19:41 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/flvmux.c:
+	  checks: add basic unit test for flvmux, but disable it for now
+	  Basic unit test for flvmux. Fails miserably, hence disabled for now.
+
+2009-07-31 23:28:12 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/flvdemux.c:
+	* tests/files/Makefile.am:
+	* tests/files/pcm16sine.flv:
+	  check: add basic unit test for flvdemux
+	  In particular, test re-use of flvdemux in both pull and push mode
+	  (see #583030).
+
+2009-07-31 20:25:17 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: fix invalid write caused by using sizeof("string") as length
+	  sizeof("foo") includes the string's NUL-terminator in the size returned,
+	  but we're writing strings here with an explicit size at the beginning
+	  and no NUL-terminator. In most cases using sizeof("foo") as length in
+	  memcpy is not harmful, but it is where the string goes right at the
+	  end of our buffer to write, since we don't allocate space for that
+	  NUL terminator.
+
+2009-07-27 18:44:45 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  soup: Use "GET" instead of SOUP_METHOD_GET. Fixes build with libsoup-2.7.*
+	  This is due to a quality API change in libsoup 2.7. SOUP_METHOD_* are now
+	  integers and not strings... they could have changed the names.
+
+2009-07-30 17:57:53 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	  jpeg: use longer macro names to not clash with some stupid windows defines
+	  libjpeg headers pull some windows system inlcudes (on windows) that contain a
+	  define for DEFAULT_QUALITY.
+
+2009-07-29 14:31:48 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Fix last commit and improve readability
+
+2009-07-24 19:04:31 +0400  Руслан Ижбулатов <lrn1986@gmail.com>
+
+	* gst/avi/gstavidemux.c:
+	  Fixed the fix for TIME->DEFAULT conversion.
+	  Fixes bug #578052 again.
+
+2009-07-29 13:38:03 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpsv3vdepay.c:
+	  rtpsv3depay: Fix width/height calculation, bring up to marginal rank.
+	  Based on documentation found on http://wiki.multimedia.cx/
+
+2009-07-29 12:13:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	  pulse: conditionally compile newer stuff
+	  configured_sink/source_usec in the timing_info is only since 0.9.11 so
+	  conditionally compile this information.
+	  fixes #590038
+
+2009-07-28 18:29:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulsesrc.h:
+	  pulsesrc: cleanups
+	  Keep track of the paused state of the source and leave the read function when
+	  paused.
+	  don't wait for a latency update when the delay is not yet known but simply
+	  return 0 instead of blocking.
+	  Keep track of the corked state of the stream.
+	  Fix the state changes.
+
+2009-07-28 16:11:18 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulsesrc: set maxlength always to -1
+
+2009-07-28 15:53:57 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulsesrc.h:
+	  pulsesrc; cleanups, report real latency
+	  Add some more debug info
+	  Avoid some type casts
+	  Report the real latency to the application.
+
+2009-07-28 16:11:36 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: when scanning for 0xff marker ends, ensure desired result
+	  Otherwise, any non 0xff byte at end of data would be mistaken for
+	  a tag byte, and in case of a frame_len 0 tag subsequently lead to an
+	  infinite loop.
+
+2009-07-28 00:30:43 -0300  Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+
+	* gst/avi/gstavimux.c:
+	  avimux: adds support to wma
+
+2009-07-28 00:07:15 -0300  Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+
+	* gst/avi/gstavimux.c:
+	  avimux: adds support to wmv
+
+2009-07-27 21:34:22 -0300  Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Downgrade warning message to debug
+
+2009-07-27 11:51:39 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: avoid using ivalid stream indexes
+	  when we get an invalid stream index from pulse because we were just starting,
+	  avoid using it for getting and setting the volume.
+	  Fixes #589365
+
+2009-07-24 19:38:07 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstripple.c:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gststreak.c:
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstwarp.c:
+	  effectv: Don't allow caps changes for some effectv filters
+	  These filters use information from previous frames to
+	  generate the current frame and a caps change will make
+	  the effect start from the beginning again.
+
+2009-07-24 19:37:09 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstwarp.c:
+	* gst/effectv/gstwarp.h:
+	  warptv: Make the sine table global instead of having it in every instance
+
+2009-07-24 10:47:44 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpeg: make encoder work with libjpeg v7
+	  We have to specify do_fancy_downsampling = FALSE in the encoder with did not exist before.
+
+2009-07-24 00:42:33 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From fedaaee to 94f95e3
+
+2009-07-23 12:06:27 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: Implement SEEKING query
+	  Fixes bug #589423.
+
+2009-07-22 11:16:06 +0100  Colin Guthrie <cguthrie@mandriva.org>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Fix a couple error messages that mentioned incorrect function names.
+	  Fixes #589459.
+
+2009-07-23 11:50:16 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvparse.c:
+	  flvdemux: Implement SEEKING query
+	  Also add some more query types to the answer of the query type function.
+	  Fixes bug #589424.
+
+2009-07-21 19:46:55 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacdec.h:
+	  flacdec: fix intermittent FLAC__STREAM_DECODER_ABORTED errors when seeking
+	  When seeking in a local flac file (ie. operating pull-based), the decoder
+	  would often just error out after the loop function sees a DECODER_ABORTED
+	  status. This, however, is the read callback's way of telling our loop
+	  function that pull_range failed and streaming should stop, in this case
+	  because of the flush-start event that the seek handler pushed upstream
+	  from the seeking thread. Handle this slightly better by storing the last
+	  flow return from pull_range, so the loop function can evaluate it properly
+	  when it encounters a DECODER_ABORTED and take the right action.
+	  Fixes #578612.
+
+2009-07-21 10:07:00 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/interleave/interleave.c:
+	  interleave: fix indenting and upgrade two debugs to warnings.
+	  Fix newlines in variable decls. Change two debugs to become warnings as they
+	  indicate that things will not work.
+
+2009-07-21 10:04:36 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpeg.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstjpegenc.h:
+	  jpeg: code cleanups for encoder
+	  Remove some disabled code in encoder. Try #if 0'ed code and add comments about
+	  why it is disabled. Move idct-method enum to jpeg.c and use in both encoder and
+	  decoder. Add idct-method property to encoder.
+
+2009-07-21 07:50:46 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Answer SEEKING queries in the original format
+
+2009-07-21 01:12:44 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/udp/gstudpnetutils.c:
+	  udputils: initialize struct content with 0.
+	  Fixes some random crashes.
+
+2009-07-20 19:09:19 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: set some values to their defaults
+	  Set the minreq and maxlength buffer attributes to -1 to let puleseaudio select a
+	  sensible value.
+
+2009-07-20 19:04:09 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: don't wait for posted message
+	  We can't wait for the ENTER/LEAVE messages to be be posted because the base
+	  class sometimes calls the start method with the object lock, which would block
+	  the message posting.
+	  Instead, just assume that the message will be posted soon and continue. We'll
+	  have to fix this in the base class.
+
+2009-07-20 18:11:33 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: use relative seeks
+	  Use relative seeks because I was told that absolute seeks don't work.
+
+2009-07-20 16:52:19 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Implement SEEKING query
+
+2009-07-20 08:07:13 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/cairo/gstcairorender.c:
+	  cairorender: Add support for ARGB/BGRA input
+	  Note that videotestsrc outputs 100% transparent video
+	  which will result in white output from cairorender.
+
+2009-07-17 13:22:57 +0100  Elaine Xiong <Elaine.Xiong@Sun.COM>
+
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2: Fix v4l2src on OpenSolaris
+	  The v4l2 driver for USB webcams on OpenSolaris does not support select()
+	  calls. Detect when select() fails, and skip polling the device afterward,
+	  which restores the pre 0.10.14 behaviour on OpenSolaris.
+	  Signed-off-by: Jan Schmidt <thaytan@noraisin.net>
+
+2009-07-17 11:22:06 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* tests/check/elements/.gitignore:
+	* tests/examples/v4l2/.gitignore:
+	  gitignore: Ignore some new binaries
+
+2009-07-17 13:49:21 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* ext/cairo/gstcairorender.c:
+	  cairorender: Add to the documentation
+
+2009-07-17 13:42:49 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/cairo/gstcairorender.c:
+	  cairorender: Return not-negotiated if we have no caps
+
+2009-07-17 13:41:19 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/cairo/gstcairorender.c:
+	* ext/cairo/gstcairorender.h:
+	  cairorender: Fix caps and colorspace handling
+
+2009-07-17 13:30:02 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/cairo/gstcairorender.c:
+	  cairorender: Use correct mimetypes for PDF and SVG
+
+2009-07-17 13:24:28 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/cairo/gstcairorender.c:
+	  cairorender: Remove pull mode, it only adds complexity but not advantages
+
+2009-07-16 21:55:31 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/cairo/gstcairorender.c:
+	  cairorender: Fix caps negotiation and cairo surface creation
+
+2009-07-16 21:42:21 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/cairo/gstcairorender.c:
+	  cairorender: Correctly set srccaps
+
+2009-07-16 21:31:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/cairo/gstcairorender.c:
+	* ext/cairo/gstcairorender.h:
+	  cairorender: Move instance/class struct definitions to the header
+
+2009-07-16 21:30:00 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/cairo/gstcairorender.c:
+	* ext/cairo/gstcairorender.h:
+	  cairorender: Add Lutz' copyright to the file header
+
+2009-07-16 21:27:45 +0200  Lutz Mueller <lutz@topfrose.de>
+
+	* ext/cairo/Makefile.am:
+	* ext/cairo/gstcairo.c:
+	* ext/cairo/gstcairorender.c:
+	* ext/cairo/gstcairorender.h:
+	  cairo: Add cairo-based PDF/PS/SVG encoder element
+	  Fixes bug #331420.
+
+2009-07-16 20:44:40 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflacenc.h:
+	  flacenc: Optionally write a PADDING block
+	  The size of the PADDING block is specified by a new
+	  "padding" property.
+	  Fixes bug #588483.
+
+2009-07-16 19:35:44 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Only assume seekability if the server provides Content-Length
+	  Previously seekability way always assumed until the first seek actually
+	  failed. Now we assume that all servers are not seekable unless they provide
+	  a Content-Length header. If a seek fails after that we continue to
+	  assume no seekability. Fixes bug #585576.
+
+2009-07-16 15:14:43 +0200  Arnout Vandecappelle <arnout@mind.be>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: don't try to authenticate if no username/password is set.
+
+2009-07-16 17:10:21 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstwarp.c:
+	  effectv: Chain up finalize to the parent class in warptv
+	  Fixes a memory leak.
+
+2009-07-16 12:55:49 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/pipelines/effectv.c:
+	  effectv: Add unit test for all effectv elements
+
+2009-07-16 12:17:32 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	  effectv: Add new effectv elements to the docs
+
+2009-07-15 14:37:19 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/Makefile.am:
+	* gst/effectv/gsteffectv.c:
+	* gst/effectv/gstripple.c:
+	* gst/effectv/gstripple.h:
+	  effectv: Add rippletv element
+	  This produces a water ripple effect on the video input,
+	  based on motion or a rain drop algorithm.
+	  Kindly relicensed to LGPL2+ by Kentaro Fukuchi <fukuchi@megaui.net>.
+	  Fixes bug #588695.
+
+2009-07-12 15:42:35 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/Makefile.am:
+	* gst/effectv/gsteffectv.c:
+	* gst/effectv/gststreak.c:
+	* gst/effectv/gststreak.h:
+	  effectv: Add streaktv effect filter element
+	  This combines the StreakTV and BaltanTV filters from the
+	  effectv project.
+	  Kindly relicensed to LGPL2+ by Kentaro Fukuchi <fukuchi@megaui.net>.
+	  Fixes bug #588368.
+
+2009-07-12 12:31:15 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstop.c:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gstvertigo.c:
+	  effectv: Fix processing on big endian architectures
+
+2009-07-12 11:52:04 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/Makefile.am:
+	* gst/effectv/gsteffectv.c:
+	* gst/effectv/gstradioac.c:
+	* gst/effectv/gstradioac.h:
+	  effectv: Add radioactv effect filter
+	  This filter adds a radiation-like motion blur effect
+	  to the video stream.
+	  Kindly relicensed to LGPL2+ by Kentaro Fukuchi <fukuchi@megaui.net>.
+	  Fixes bug #588359.
+
+2009-07-12 11:26:57 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstop.c:
+	* gst/effectv/gstop.h:
+	  effectv: Make the optv threshold property an uint
+
+2009-07-12 10:39:02 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/Makefile.am:
+	* gst/effectv/gsteffectv.c:
+	* gst/effectv/gstop.c:
+	* gst/effectv/gstop.h:
+	  effect: Add optv effect filter from the effectv project
+	  This filter binarizes input frames and combines them with various
+	  optical pattern.
+	  Kindly relicensed to LGPL2+ by Kentaro Fukuchi <fukuchi@megaui.net>.
+	  Fixes bug #588349.
+
+2009-07-03 05:11:26 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Emit stream-status leave message
+	  Fixes #587695
+
+2009-07-03 05:06:45 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	  pulsesink: Emit stream-status enter message
+	  Emit stream-status messages for the pulse thread.
+	  Don't use our own GCond for signaling but simply use the pulse mainloop
+	  mechanisms for synchronisation.
+	  See #587695
+
+2009-07-14 18:15:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: debug the latency update values
+
+2009-07-14 16:12:55 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulseutil.c:
+	  pulsesink: add 24bit sample formats
+	  Add check for pulseaudio 0.9.15 and enable 24bits samples in that case.
+
+2009-07-13 12:23:37 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 5845b63 to fedaaee
+
+2009-07-13 17:53:25 +0200  Marc Leeman <marc.leeman at gmail.com>
+
+	* gst/rtp/gstrtpmpvpay.c:
+	  mpvpay: Rework the timestamping
+	  Rework the timestamping in the mpv payloader so that the timestamps are more
+	  accurate.
+	  Fixes #587680
+
+2009-07-03 08:47:12 +0200  Filippo Argiolas <filippo.argiolas@gmail.com>
+
+	* configure.ac:
+	* tests/examples/Makefile.am:
+	* tests/examples/v4l2/Makefile.am:
+	* tests/examples/v4l2/probe.c:
+	  v4l2src: add a simple test case for device probing
+
+2009-07-03 08:38:43 +0200  Filippo Argiolas <filippo.argiolas@gmail.com>
+
+	* configure.ac:
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2object.c:
+	  v4l2src: optional support for device probing with gudev
+	  Enumerate v4l2 devices using gudev if available.
+	  Fixes bug #583640.
+
+2009-07-10 19:54:25 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: Random cleanup
+
+2009-07-10 19:54:13 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: Send queries to the master pad by default instead of all pads
+
+2009-07-10 19:34:41 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/blend_rgb.c:
+	* gst/videomixer/videomixer.c:
+	  videomixer: Add RGB, BGR, xRGB, RGBx, xBGR, BGRx support
+
+2009-07-10 17:43:07 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: Clean up debugging a bit
+
+2009-07-10 17:25:48 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: Remove some redundant checks and error out immediately if not negotiated
+	  Also stop leaking the output buffer in some error cases.
+
+2009-07-10 17:23:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_ayuv.c:
+	* gst/videomixer/blend_bgra.c:
+	* gst/videomixer/blend_i420.c:
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer.h:
+	  videomixer: Remove the calculate_frame_size() function and use libgstvideo instead
+
+2009-06-30 15:13:44 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: Remove unused link/unlink pad methods
+
+2009-06-30 12:43:04 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/videomixer/blend_i420.c:
+	  videomixer: I420 mode: Add fast path for 0.0 and 1.0 alpha
+	  If the source alpha is 0.0, we take nothing.
+	  If the source alpha is 1.0, we overwrite everything.
+
+2009-06-30 12:40:02 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/videomixer/blend_i420.c:
+	  videomixer: I420 blending : Fix main algorithm.
+	  When blending a source layer with an alpha of 'a' on top of another
+	  destination layer we take the sum of:
+	  * 'a' percent of the source layer
+	  * (100 - 'a') percent of the destination layer (the remainder)
+
+2009-06-30 12:39:19 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/videomixer/blend_i420.c:
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer.h:
+	* gst/videomixer/videomixerpad.h:
+	  videomixer: Make debugging category global to all the code.
+
+2009-06-29 19:23:41 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: improve readability of debugging statements.
+
+2009-07-08 13:38:53 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: do not leak timeout message
+
+2009-07-09 07:14:23 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avi: Don't forward NEWSEGMENT events from upstream
+	  New ones are generated later and simply forwarding them can
+	  result in NEWSEGMENT events of different format going downstream.
+	  Fixes bug #587983.
+
+2009-07-08 18:19:45 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_ayuv.c:
+	* gst/videomixer/blend_i420.c:
+	  videomixer: Make checker pattern lookup table constant
+
+2009-07-08 18:17:48 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/blend_bgra.c:
+	* gst/videomixer/videomixer.c:
+	  videomixer: Add support for ARGB
+	  And clean up the caps parsing.
+
+2009-07-08 15:17:41 +0200  Benjamin Gaignard <benjamin@gaignard.net>
+
+	* gst/udp/gstudpnetutils.c:
+	  udp: Initialize pointer to NULL
+	  Otherwise we're calling free() with some random
+	  memory address in error cases.
+	  Fixes bug #587982.
+
+2009-07-07 16:35:24 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: sprinkle some more const
+
+2009-07-07 15:57:55 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: perform some more (careful) data buffering
+	  Once buffering has started (with an mdat atom), continue buffering
+	  until moov atom is reached, which handles cases with multiple
+	  mdat atoms.  Also keep adapter/offset better in sync with upstream
+	  and fix some debug statements.  Fixes #587426.
+
+2009-07-06 10:40:31 +0200  Philip Jägenstedt <philipj@opera.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Replace deprecated GST_DISABLE_DEBUG with correct macro. Fixes #587826
+
+2009-07-01 13:07:48 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: error out instead of dividing by 0
+	  Error out if timescale is 0.
+
+2009-07-01 09:32:42 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  Revert "qtdemux: Make sure we don't blacklist streams by wrongly comparing their"
+	  This reverts commit 5503a59a5779b67451d8a271000181790ee76bc7.
+	  Reverting this since it causes regressions with a lot of sample files
+	  I have, all of which worked fine with the last -good release (#586891).
+
+2009-06-30 15:54:47 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: comment out unused structure
+
+2009-06-30 13:12:09 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: more size checks, and use g_try_new0() instead of g_new0()
+	  Whenever we alloc something based on a user-supplied size, we should
+	  really use g_try_new(), otherwise we can easily be made to abort by
+	  passing a ridiculously large number to us for allocing. Fixes
+	  problems with some fuzzed files.
+
+2009-06-29 18:58:33 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: guard against bogus atom sizes and short reads
+	  Check the possibly 64-bit atom size more carefully before casting it
+	  to an int and passing it to gst_pad_pull_range(), otherwise we might
+	  end up pulling 0 bytes, getting an empty buffer as requested and
+	  dereferencing not available data whilst thinking we actually asked
+	  for and got 0x1000000000000 bytes. Similar fix for push mode operation
+	  where neededbytes ends up being 0 bytes, which makes us assert. Fixes
+	  crash with broken or fuzzed file (NB #122378).
+
+2009-06-29 16:52:41 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: use 0x prefix when logging numbers in hex
+
+2009-07-01 08:40:40 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: Don't send empty string tags
+
+2009-06-30 21:35:37 +0400  LRN <lrn1986 at gmail.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	  Don't use sendmsg()-dependent code on Windows
+	  Fixes #585842
+
+2009-06-30 15:59:20 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/alaw.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/law/mulaw.c:
+	  law: fix caps and negotiation
+	  Fix the caps to include the depth (instead of width twice) in the caps of
+	  audio/x-raw-int.
+	  Fix negotiation to not only copy the rate/channels of the first structure.
+
+2009-06-30 14:48:09 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: include "1.0=100%" in volume and change upper limit
+	  Upper volume limmit was 1000. That appear unneceasrily high. It would also cause
+	  sever distortion if accidentialy used. Now its 10 (~ +15db) which is also in
+	  sync with volume and playbin2.
+
+2009-06-29 15:39:43 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesrc.c:
+	  pulse: some more trivial cleanups
+
+2009-06-29 15:38:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsemixer.c:
+	  pulse: trivial cleanups
+
+2009-06-29 15:20:31 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: clear ringbuffer when asked to
+	  Since we map the ringbuffer to the pulseaudio internal ringbuffer, flush the
+	  pulseaudio buffer when we are asked to clear the ringbuffer.
+	  This avoids some leftover audio after a seek.
+
+2009-06-26 15:00:14 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* autogen.sh:
+	  autogen.sh: Actually do the 'echo -n' -> printf change.
+
+2009-06-26 14:40:14 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* autogen.sh:
+	  autogen.sh: Use printf instead of 'echo -n'. Check for automake-1.1[01]
+	  Check for more automake command variants. Use printf instead of 'echo -n'
+	  for portability
+
+2009-06-26 13:42:09 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From f810030 to 5845b63
+
+2009-06-26 13:19:04 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: don't process track_num/track_count tags with a 0 value
+	  Number/count values of 0 mean they're not set. Don't put those in the
+	  taglist.
+
+2009-06-25 18:51:12 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/waveform/gstwaveformsink.c:
+	  waveformsink: use 'guint8' instead of 'byte' to fix compilation with MSVC8
+	  We need a cast here for pointer arithmetic to work correctly, but some
+	  MSVC versions don't seem to like 'byte', so use guint8 here. Hopefully
+	  fixes #585361.
+
+2009-06-25 19:39:37 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2src: set structs to zero before using them in ioctls
+	  This fixes valgrind warnings.
+
+2009-06-25 13:23:40 +0200  Julien Moutte <julien@fluendo.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Make sure we don't blacklist streams by wrongly comparing their duration with entire clip duration.
+
+2009-06-25 13:18:14 +0200  Krzysztof Błaszkowski <kb at sysmikro.com.pl>
+
+	* gst/rtsp/gstrtpdec.c:
+	  rtpdec: fix some buffer leaks
+
+2009-06-25 08:11:09 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/flv/gstflvparse.c:
+	  flvparse: Add missing break in switch/case.
+
+2009-06-25 08:10:38 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/flv/gstflvdemux.c:
+	  flvdemux: Remove unused variable, hint branch likeliness, add comments.
+
+2009-06-25 08:09:57 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Removed unused variable
+
+2009-06-25 07:41:07 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Remove dead assignments and unused variables.
+	  Also add branch likeliness macros.
+
+2009-06-25 07:40:26 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Fix uninitialized variables. Fixes build on macosx
+
+2009-06-24 17:43:25 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: free memory in finalize
+	  finalize is called only once. no need to clear pointers there. dispose is for
+	  unreffing.
+
+2009-06-24 15:14:14 +0100  Jan Schmidt <jan.schmidt@sun.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From 6ab11d1 to f810030
+
+2009-06-08 14:46:48 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: short-circuit gst_avi_demux_src_convert() when parsing the index
+	  Don't call gst_avi_demux_src_convert() for each single index entry. Not
+	  only do we already have the pointer to the stream context, we also know
+	  the formats we want to convert from and to already, so we may just as
+	  well use optimised conversion routines that bypass some of the checks
+	  and lookups made in gst_avi_demux_src_convert().
+
+2009-06-17 16:39:36 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Another round of G_*LIKELY micro-optimisations.
+
+2009-06-17 16:20:25 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Take last sample duration for dummy segment calculation.
+	  This fixes the cases where files without EDL wouldn't output their
+	  last buffer.
+
+2009-06-24 12:36:31 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Sprinkle branch likeliness macros over the code.
+
+2009-06-23 16:54:32 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	  raw1394: sprinkle branch likeliness macros accross the code.
+
+2009-06-14 10:36:17 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: Add GST_MEMDUMP statements for unknown atoms.
+	  This is to help developers track down and implement unhandled atoms faster.
+
+2009-06-23 17:51:32 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Remove the interlaced field from the output caps if deinterlacing is enabled
+
+2009-06-23 17:48:47 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/tvtime/greedyh.c:
+	  deinterlace: Copy the correct line from correct place in the history
+
+2009-06-23 16:35:36 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: use same protocols after redirect
+	  After a redirect we want to use the same protocols that we were using for the
+	  current url.
+
+2009-06-23 15:35:37 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: don't leak cover art
+
+2009-06-23 14:10:10 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/udp/gstudpnetutils.c:
+	  udp: fix compiler warning about EAI_ADDRFAMILY getting redefined in some cases
+	  Include the header from where we include all the system headers with the
+	  socket stuff before we try to define EAI_ADDRFAMILY ourselves, otherwise
+	  we define it ourselves and then get a compiler warning if a system header
+	  defines it as well without guarding against it being defined already.
+
+2009-06-23 14:39:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/matroska/matroska-ids.h:
+	  matroska: and the new headers too
+
+2009-06-23 14:32:43 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroske: fix compiler error
+	  change gpointer to guint8 * for codec_state and codec_priv as some
+	  functions operate on those types and it avoids breaking strict-aliasing
+	  rules.
+
+2009-06-23 12:42:33 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: avoid leaking buffers
+	  Don't leak buffers when resyncing to a keyframe.
+	  Avoid leaking buffers when exiting the loop on error conditions.
+	  Add some more debug info.
+	  Fixes #585911
+
+2009-06-22 15:56:58 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/gstv4l2src.c:
+	  v4l2: open/close the device in READY
+	  This allows to query the device in READY. Before one need to switch it to PAUSED
+	  and that also starts streaming.
+
+2009-06-20 15:41:44 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_dump.c:
+	  qtdemux: use GST_MEMDUMP
+
+2009-06-19 00:16:41 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/apetag/Makefile.am:
+	* gst/apetag/gstapedemux.c:
+	  apedemux: add container-format tag
+	  Use pbutils here because the string is translated.
+
+2009-06-19 00:15:51 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/id3demux/Makefile.am:
+	* gst/id3demux/gstid3demux.c:
+	  id3demux: add container-format tag
+	  Using pbutils here because the string is translated.
+
+2009-06-18 23:51:52 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: post container-format tag
+	  Also merge the two almost identical _add_*_pad() functions into one.
+
+2009-06-18 23:43:49 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/dv/gstdvdemux.c:
+	  dvdemux: don't screw up first audio buffer
+	  Query the audio format, esp. dvdemux->num_channels, before we use that
+	  variable to allocate the initial buffer. That way we don't accidentally
+	  push a zero-sized buffer as first audio buffer.
+
+2009-06-18 23:38:30 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/multipart/multipartdemux.c:
+	  multipartdemux: post container-format tag
+
+2009-06-18 23:37:11 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska-demux: post container-format tags
+
+2009-06-18 23:36:28 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: post container-format tag
+
+2009-06-18 23:35:29 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: post container-format tags
+
+2009-06-21 17:13:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audioamplify.c:
+	  audioamplify: Fix integer overflows on 32 bit architectures
+
+2009-06-21 09:50:54 +0200  Kipp Cannon <kcannon@ligo.caltech.edu>
+
+	* gst/audiofx/audioamplify.c:
+	  audioamplify: Don't declare a loop index static
+	  The previous patch to add support for additional sample formats possibly
+	  introduced a reentrancy bug:  a variable used for a loop index was declared
+	  static.  This patch fixes that, and also adds a "/* *INDENT-ON* */" annotation
+	  following the macro block.  (I don't know what the annotation is for, but the
+	  adder, where I copied this from, has it).
+
+2009-06-19 22:37:27 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audioamplify.c:
+	  audioamplify: Fix off-by-one in wrap-positive mode
+
+2009-06-19 22:20:45 +0200  Kipp Cannon <kcannon@ligo.caltech.edu>
+
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audioamplify.h:
+	  audioamplify: Add noclip method and support for more formats
+	  Fixes bug #585828 and #585831.
+
+2009-06-19 21:46:41 +0200  Koop Mast <kwm@freebsd.org>
+
+	* gst/udp/gstudpnetutils.h:
+	  udp: Fix build on FreeBSD
+	  Fixes bug #586397.
+
+2009-06-19 18:12:27 +0200  Ognyan Tonchev <ognyan.tonchev at axis.com>
+
+	* tests/check/elements/rtp-payloading.c:
+	  tests: add unit tests for buffer-list payloaders
+	  See #585559
+
+2009-06-19 18:00:35 +0200  Ognyan Tonchev <ognyan.tonchev at axis.com>
+
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmp4vpay.h:
+	  rtpmp4vpay: add support for buffer-list
+	  See #585559
+
+2009-06-19 17:57:12 +0200  Ognyan Tonchev <ognyan.tonchev at axis.com>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpjpegpay.h:
+	  rtpjpegpay: add support for buffer-lists
+	  See #585559
+
+2009-06-19 17:53:32 +0200  Ognyan Tonchev <ognyan.tonchev at axis.com>
+
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtph264pay.h:
+	  rtph264pay: add support for buffer-lists
+	  See #585559
+
+2009-06-18 11:54:22 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpnetutils.c:
+	  udputils: don't free invalid memory
+	  As spotted by benjiG in IRC.
+	  don't free invalid memory when getaddrinfo failed.
+
+2009-06-17 17:48:31 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulseink: don't leak device_description
+	  don't leak the device_description.
+	  some cleanups.
+
+2009-06-19 14:44:40 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: update .po files for sunaudiomixer string changes
+
+2009-06-18 16:58:26 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: streaming; adjust sizes to cater for padding in chunks
+
+2009-06-17 11:54:53 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: streaming mode; handle data chunks grouped in rec lists.
+	  Fixes #567983.
+
+2009-06-10 12:36:50 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: map some tags to COMPOSER rather than ARTIST
+
+2009-06-10 12:34:43 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix some 3GP tag extraction (keywords, genre, location)
+
+2009-06-09 15:36:50 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	  qtdemux: extract pixel-aspect-ratio information
+
+2009-06-17 07:14:09 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Fix leaking of the Matroska TITLE element
+
+2009-06-16 20:38:42 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* 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:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstaging.h:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstdice.h:
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstedge.h:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstquark.h:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstrev.h:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gstshagadelic.h:
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstvertigo.h:
+	* gst/effectv/gstwarp.c:
+	* gst/effectv/gstwarp.h:
+	  effectv: Add basic documentation for the effectv elements
+
+2009-06-16 20:16:13 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gsteffectv.h:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstshagadelic.c:
+	  effectv: Define the fast PRNG function at a central place
+
+2009-06-16 20:13:35 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/Makefile.am:
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstaging.h:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstdice.h:
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstedge.h:
+	* gst/effectv/gsteffectv.c:
+	* gst/effectv/gsteffectv.h:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstquark.h:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstrev.h:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gstshagadelic.h:
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstvertigo.h:
+	* gst/effectv/gstwarp.c:
+	* gst/effectv/gstwarp.h:
+	  effectv: Move type definitions into separate headers
+	  This is needed for the docs later.
+
+2009-06-16 19:41:02 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstwarp.c:
+	  effectv: Remove get_unit_size implementations
+	  The default on from GstVideoFilter handles this already.
+
+2009-06-16 14:54:34 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: bump core/base requirements to git
+	  Need git core for basesink bufferlist additions; -base requirement
+	  bumped gratuitously.
+
+2009-06-16 15:25:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/elements/udpsink.c:
+	  tests: add some debug, send newsegment
+
+2009-06-16 15:06:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: add debug line for the socket
+
+2009-06-16 15:06:25 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/check/pipelines/flacdec.c:
+	  tests: turn g_print into debug
+
+2009-06-16 15:04:15 +0200  Ognyan Tonchev <ognyan@axis.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/udpsink.c:
+	  multiudpsink: add support for buffer lists
+	  Add support for BufferList and add a unit test.
+	  Fixes #585842
+
+2009-06-16 00:02:42 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: reset session state when stopping
+	  Increases the chances that the element is actually reusable.
+
+2009-06-15 23:49:48 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: log response and request headers and fix some broken indenting
+
+2009-06-15 22:40:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4gdepay.c:
+	  mp4gdepay: guess constantDuration better
+	  Do a better job at guessing the constantDuration parameter when it is not
+	  present in the caps.
+	  Fixes #585205
+
+2009-06-15 21:09:47 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstwarp.c:
+	  warptv: Clean up warptv element and fix some minor bugs and leaks
+
+2009-06-15 20:53:23 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstvertigo.c:
+	  vertigotv: Clean up vertigotv element and fix some minor bugs and leaks
+
+2009-06-15 20:38:01 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstdice.c:
+	  dicetv: Use guint8 instead of char (which can be signed or unsigned)
+
+2009-06-15 20:36:39 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstshagadelic.c:
+	  shagadelictv: Use guint8/gint8 instead of char (which can be signed or unsigned)
+
+2009-06-15 20:31:30 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstshagadelic.c:
+	  shagadelictv: Clean up element and free all memory in finalize
+
+2009-06-15 20:21:58 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstrev.c:
+	  revtv: Clean up revtv element
+
+2009-06-15 20:07:42 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstquark.c:
+	  quarktv: Simplify some code
+
+2009-06-15 20:07:10 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstquark.c:
+	  quarktv: Use the input data if a NULL buffer is chosen instead of the value 0
+
+2009-06-15 20:00:43 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstquark.c:
+	  quarktv: Fix setting the planes property of quarktv
+	  Setting it to a value<16 would cause crashes before because
+	  current_plane was set to the old number of planes-1. Also
+	  fix calculations for non-2^n planes values.
+
+2009-06-15 17:50:41 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstquark.c:
+	  quarktv: Clean up the quarktv element
+
+2009-06-15 17:39:20 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gsteffectv.c:
+	  effectv: Make elements list constant
+
+2009-06-15 17:37:53 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstedge.c:
+	  edgetv: Clean up edgetv element and fix memory leak
+
+2009-06-15 17:21:58 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstdice.c:
+	  dicetv: Clean up dicetv element and fix some smaller issues
+	  This fixes a memory leak (the dice map) and a crash when
+	  setting the square-bits property before caps are set.
+
+2009-06-15 17:20:21 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/Makefile.am:
+	* gst/effectv/gstaging.c:
+	  agingtv: Actually use GstController for syncing the properties to timestamps
+
+2009-06-15 17:03:38 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstaging.c:
+	  agingtv: Export some more agingtv properties via GObject properties
+
+2009-06-15 15:06:56 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstaging.c:
+	  agingtv: General cleanup and updating of copyright
+	  Also make the scratch-lines property exported via a GObject
+	  property and initialize/reset the internal state correctly.
+
+2009-06-15 15:05:58 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/effectv/gstaging.c:
+	  agingtv: Store and update state inside the instance struct
+	  This makes the coloraging effect and pits effect visible.
+
+2009-06-15 15:51:32 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: ref custom ring buffer class and type in class_init
+	  Hack around thread-safety issues in GObject and our racy _get_type()
+	  functions (we could easily fix the _get_type() functions, but we still
+	  need to hack around the GObject class races until we require a newer
+	  GLib version, I think).
+
+2009-06-14 19:19:19 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/dv/demo-play.c:
+	* tests/old/examples/Makefile.am:
+	* tests/old/examples/level/Makefile.am:
+	* tests/old/examples/level/README:
+	* tests/old/examples/level/demo.c:
+	* tests/old/examples/level/plot.c:
+	* tests/old/examples/switch/.gitignore:
+	* tests/old/examples/switch/Makefile.am:
+	* tests/old/examples/switch/switcher.c:
+	  Remove a few old example apps from the 0.8 days
+	  Some have been replaced by newer ones, others are demoing elements that
+	  don't exist any longer (not in -good anyway), and others have not been
+	  touched in many years and it seem pointless to keep them around.
+	  Removing these files makes sure we don't have any code in our repository
+	  that uses Gtk+ symbols which are to be removed for GNOME3, and as such
+	  will make some script that greps for this kind of stuff give us a clean
+	  bill of code health. Fixes #585757.
+
+2009-06-13 21:02:45 -0400  Olivier Crête <tester@tester.ca>
+
+	* common:
+	* gst/rtp/gstrtpsirenpay.c:
+	  rtpsirenpay: Remove deprecated symbol
+	  Patch by: Luis Menina
+
+2009-06-13 10:43:55 +0200  Marvin Schmidt <marvin_schmidt@gmx.net>
+
+	* tests/check/Makefile.am:
+	  tests: Don't run the flacdec test if the plugin isn't built. Fixes #585630
+
+2009-06-12 16:06:28 +0200  Patrick Radizi <patrick.radizi at axis.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Add RTP blocksize functionality
+	  Add property to make the client suggest a blocksize to the server.
+	  Fixes #585549
+
+2009-06-11 22:30:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/README:
+	  rtp: update README, fix some typos, mention gstrtpbin
+
+2009-06-11 19:10:53 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: handle border cases in resampler
+
+2009-06-11 13:32:22 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* common:
+	* docs/Makefile.am:
+	* docs/plugins/Makefile.am:
+	* docs/upload.mak:
+	  docs: Bump common. Use upload-doc.mak instead of upload.mak
+	  Remove the local copy of upload.mak in favour of using the shared
+	  upload-doc.make in common/
+
+2009-06-11 11:39:25 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/goom/goom_config_param.h:
+	* gst/videomixer/videomixer.c:
+	  docs: Quieten a couple more docs warnings
+
+2009-06-11 11:27:26 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/matroska/lzo.c:
+	  docs: Remove gtk-doc comment marker
+	  These comment blocks aren't gtk-doc comments and cause annoying noise in
+	  the docs build.
+
+2009-06-11 10:05:32 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  deinterlace: Implement upstream negotation
+
+2009-06-10 21:47:40 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Improve debugging and clean up some code
+
+2009-06-10 14:55:18 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Clip buffers to the current segment if possible
+
+2009-06-10 14:45:06 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  deinterlace: Clean up includes and clean up order of instance struct fields
+
+2009-06-10 16:09:56 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtph263pay.h:
+	  rtph263pay: Default to doing A, B and C modes, not only A
+
+2009-06-10 09:56:11 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Fix QoS calculations
+	  The diff is a signed integer, not an unsigned one of course.
+	  In modes other than GST_DEINTERLACE_ALL every frame has twice the
+	  duration of the field duration.
+
+2009-06-09 14:13:31 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/gstrtpsirenpay.c:
+	  rtpsirenpay: Put the bitrate in the RTP caps
+	  The MS code seems to require the bitrate to interoperate and
+	  draft-ietf-avt-rtp-g7221-00 also has it.
+
+2009-06-09 19:55:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  deinterlace: Implement basic QoS
+	  This change is based on Tim's QoS implementation
+	  for jpegdec.
+
+2009-06-09 19:29:51 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: Directly proxy events/queries to the peer pads
+	  This removes some overhead introduced by the default handlers
+	  that need to iterate over the other pads.
+
+2009-06-09 10:38:52 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: debug_memdump() unknown tags. Refactor junk parsing code.
+	  This makes life slightly easier when debugging avi files.
+
+2009-06-08 08:21:43 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/Makefile.am:
+	  rtp: Don't forget to dist the headers for the CELT (de)payloaders.
+
+2009-06-07 20:54:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  Revert "Revert "qtdemux: fill timestamp table completely""
+	  This reverts commit 9f022c8a8503c2ce0fa617fdb50e41706dd412f5.
+	  Sorry, I was thinking about the wrong module.
+
+2009-06-07 20:49:50 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  Revert "qtdemux: fill timestamp table completely"
+	  This reverts commit 790b050fc5302cae89cddcd23b258093967d05a9.
+	  I forgot we were frozen.
+
+2009-06-07 20:46:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fill timestamp table completely
+	  When there are less timestamps that there are samples, fill up the sample table
+	  with the last know timestamp. This situation can happen when the last sample
+	  does not decode and doesn't need a timestamp. We however calculate the total
+	  track length using the last sample timestamp so we need to have something
+	  sensible in there.
+	  Fixes #585056
+
+2009-06-07 13:37:04 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: handle LIST INFO of 0 size
+	  Handle LIST INFO chunks of 0 size instead of causing errors.
+	  Fixes #584981
+
+2009-06-07 13:24:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  Revert "wavparse: Remove dead assignments, move variable to where it's needed."
+	  Reverts commit 44256a78f8dd79a91f3bb2ab7c3aa623c097bb8a and use the result in
+	  error reporting so that we can see what's going on.
+
+2009-06-05 18:55:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpceltdepay.c:
+	* gst/rtp/gstrtpceltdepay.h:
+	  celtdepay: add CELT depayloader
+
+2009-06-05 15:30:51 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpceltpay.c:
+	* gst/rtp/gstrtpceltpay.h:
+	  rtpceltpay: add CELT RTP payloader
+
+2009-06-05 16:54:48 +0100  Jan Schmidt <jan.schmidt@sun.com>
+
+	* sys/sunaudio/gstsunaudiomixerctrl.c:
+	* sys/sunaudio/gstsunaudiomixeroptions.c:
+	* sys/sunaudio/gstsunaudiomixertrack.c:
+	  sunaudio: Fix switch setting on some devices. Add debug. Fix a FIXME.
+	  Fix the setting of toggle switches on some broken audio drivers which
+	  report that no audio ports are settable by ignoring the mod_port field
+	  there.
+	  Add some debug statements.
+	  Fix a FIXME now that Good relies on a new enough gst-plugins-base.
+
+2009-06-04 12:27:19 +0100  Jan Schmidt <jan.schmidt@sun.com>
+
+	* sys/sunaudio/Makefile.am:
+	* sys/sunaudio/gstsunaudiomixerctrl.c:
+	* sys/sunaudio/gstsunaudiomixerctrl.h:
+	* sys/sunaudio/gstsunaudiomixeroptions.c:
+	* sys/sunaudio/gstsunaudiomixeroptions.h:
+	* sys/sunaudio/gstsunaudiomixertrack.c:
+	* sys/sunaudio/gstsunaudiomixertrack.h:
+	  sunaudio: Support new flags for options and actions
+	  Use new audio mixer flags added in Base 0.10.23 to expose flags and options
+	  on the SunAudio devices.
+	  Fixes: #583593
+	  Patch By: Brian Cameron <brian.cameron@sun.com>
+	  Patch By: Garrett D'Amore <garrett.damore@sun.com>
+
+2009-05-15 11:50:38 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	  deinterlace: First try to handle DVD still frames correctly
+	  This helps a bit with bug #582740 but still doesn't make it work.
+
+2009-06-04 17:37:03 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: only notify if all checks passed
+	  Replace goto done: with return, as those are checks when we don't want to flag a
+	  pending notify.
+
+2009-06-04 15:19:05 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: set the right state on rtpbin
+	  We need to set the state of gstrtpbin to the same state as our source elements.
+	  This fixes fallback to TCP again.
+
+2009-06-03 18:23:53 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: check pointer before accessing
+	  Move existing check a few lines up, so that we check before accessing fields.
+
+2009-06-03 18:21:12 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: rename gst_pulse_sink_get_time to gst_pulsesink_get_time
+	  Rename internal method for consistency.
+
+2009-06-03 18:19:22 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: use values from pa_stream_get_buffer_attr()
+	  We were putting the requested values back into ringbuffer spec, instead of
+	  using the queried values.
+
+2009-06-02 19:32:21 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawpay.c:
+	  vrawpay: trim output buffers
+	  Remove the leftover unused bytes in the output buffer.
+	  Fixes #584613
+
+2009-06-02 19:30:30 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  vrawdepay: fix parsing of sampling field
+	  commit a12d9a80f225be97b3674b1a0506ac66544dbf49 broke the parsing of the
+	  sampling.
+
+2009-05-27 17:06:34 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: Avoid possible overflow in calculations
+	  A malformed (or simply huge) PNG file can lead to integer overflow in
+	  calculating the size of the output buffer, leading to crashes or buffer
+	  overflows later. Fixes SA35205 security advisory.
+
+2009-06-02 00:48:00 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: some more logging - dump header packets
+	  Also, the final fixing up of the headers is expected and not something
+	  we should warn about.
+
+2009-06-02 00:37:15 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: never ever pass values >36bits to _set_total_samples_estimate()
+	  Let's be paranoid and make sure we never pass a number that takes up
+	  more than 36 bits to _set_total_samples_estimate(), since libFLAC
+	  expects all the other bits to be zero, and if this is not the case
+	  neighbouring fields in the global stream info header may get messed
+	  up inadvertently, so that flac -d refuses to decode the stream.
+	  See #584455.
+
+2009-06-01 22:33:02 +0200  Thomas Vander Stichele <thomas (at) apestaart (dot) org>
+
+	* ext/flac/gstflacenc.c:
+	  Address bad FLAC sample length encoding of #5844455
+	  Commit df707c666433a78d3878af6f055698d5756226c4
+	  introduced an obvious bug in the sample length calculation,
+	  using the wrong macro for conversion.
+
+2009-06-01 11:58:21 -0700  Brian Cameron <brian.cameron@sun.com>
+
+	* gst/deinterlace/tvtime/mmx.h:
+	  deinterlace: Fix spurious colons in asm code
+	  Fixes #584174.
+	  Signed-off-by: David Schleef <ds@schleef.org>
+
+2009-06-01 00:40:55 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: skip JUNK chunks in data section in streaming mode
+	  Skip JUNK tags in streaming mode as well instead of EOSing
+	  prematurely. Fixes #564100.
+
+2009-05-28 14:01:17 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_bgra.c:
+	* gst/videomixer/blend_i420.c:
+	* gst/videomixer/videomixer.c:
+	  videomixer: Don't use // comments
+
+2009-05-28 13:56:15 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_bgra.c:
+	  videomixer: Fix background blitting when a color mode is selected with BGRA
+
+2009-05-28 13:54:14 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_ayuv.c:
+	* gst/videomixer/blend_bgra.c:
+	* gst/videomixer/blend_i420.c:
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer.h:
+	  videomixer: Some cleanup and fix the calculation of the frame size in bytes
+
+2009-05-28 13:35:52 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_i420.c:
+	  videomixer: Fix I420 blending to actually do something
+	  For this we a) implement the checkers filling and b)
+	  actually blend the src/dest by using the src alpha value
+	  from the pad.
+
+2009-05-28 13:14:13 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/blend_bgra.c:
+	  videomixer: Fix ARGB blending to actually work
+
+2009-05-28 13:04:51 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/blend_bgra.c:
+	  videomixer: Blend BGRA ourselves instead of using Cairo
+
+2009-05-28 12:55:16 +0200  Alex Ugarte <alexugarte@gmail.com>
+
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/blend_ayuv.c:
+	* gst/videomixer/blend_bgra.c:
+	* gst/videomixer/blend_i420.c:
+	* gst/videomixer/videomixer.c:
+	* gst/videomixer/videomixer.h:
+	  videomixer: Add support for blending BGRA and AYUV
+	  Fixes bug #577017.
+
+2009-05-28 12:39:46 +0200  Ghislain 'Aus' Lacroix <aus@songbirdnest.com>
+
+	* gst/equalizer/gstiirequalizer.c:
+	  equalizer: Use floating point arithmetic internally for the int16 mode
+	  By using int32 arithmetic we will introduce distortions as the
+	  IIR filter is very sensitive to rounding errors. Fixes bug #580214.
+
+2009-05-28 10:55:16 +0100  Christian Schaller <christian.schaller@collabora.co.uk>
+
+	* gst-plugins-good.spec.in:
+	  Update spec file with latest plugins
+
+2009-05-26 17:19:08 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 888e0a2 to c572721
+
+2009-05-26 16:20:35 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	  v4l2: cleanup and commenting
+	  Remove newlines inserted by gst-indent once. Remove unused var from instance
+	  struct. Add comments. Add another #define for default property value.
+
+2009-05-06 12:43:35 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/check/Makefile.am:
+	  makefile: idea about makeing more sources/sinks testable again
+
+2009-05-25 16:33:35 +0200  John Keeping <john.keeping at lineone.net>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: match g_malloc() with g_free()
+	  Matching g_malloc() with a g_free() is important when a custom allocator is
+	  installed.
+	  Fixes #583803
+
+2009-05-12 18:39:28 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmp4vpay.h:
+	  rtpmp4vpay: don't look for headers in some cases
+	  In some streams (starting with 00000100) don't look for the headers but push
+	  data as it is.
+	  Fixes #582153
+
+2009-05-13 11:50:22 +0200  Patrick Radizi <patrick.radizi at axis.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix memory leak of messages
+	  Free messages correctly.
+	  Fixes #577318
+
+2009-05-24 19:32:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: make fakesrc silent
+	  Make the fakesrc that is responsible for sending dummy packets silent.
+
+2009-05-24 16:33:42 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: don't send teardown before setup
+	  Don't send a TEARDOWN request when we did not manage to successfully setup a
+	  stream.
+
+2009-05-14 14:46:14 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-demux.h:
+	* gst/matroska/matroska-ids.h:
+	  matroskademux: Populate a GstIndex that is set on matroskademux
+
+2009-05-14 10:35:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  flvmux: Get the max duration from upstream if there's no duration tag
+
+2009-05-14 10:29:49 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  flvmux: Write an index table to the end of the file
+
+2009-05-22 01:12:35 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* autogen.sh:
+	* configure.ac:
+	  autotools: move the -Wno-portability from autogen.sh to configure.ac
+	  If we're lucky it'll get used on automatic rebuilds as well that way.
+
+2009-05-22 01:10:12 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* common:
+	* configure.ac:
+	* m4/gst-fionread.m4:
+	  m4: fix 'suspicious cache id' warnings
+	  and update common to pull in a similar fix. Also check in configure
+	  whether the compiler supports do while macros (GLib wants this
+	  defined and it is needed to avoid warnings with some c++ compilers
+	  apparently).
+
+2009-05-22 01:39:33 +0300  Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
+
+	* configure.ac:
+	  souphttpsrc: Bump-up libsoup-2.24 dep to >= 2.26
+	  The helper function soup_message_headers_get_content_type that we now use
+	  was added in 2.26.
+
+2009-05-20 17:57:59 +0300  Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Set caps for audio/L16 content-type
+	  When "Content-Type" header is "audio/L16", we need to set the caps on the
+	  outgoing buffers so that downstream elements can have means to detect the
+	  stream type and handle it appropriately. Tested with HTTP stream provided
+	  by pulse-audio's http module (git master).
+
+2009-05-20 15:06:25 +0300  Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: Rename icy_caps to src_caps
+
+2009-05-21 23:39:13 +0200  Philippe Normand <philippe at fluendo.com>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: bump max size to 65535x65535
+	  Remove artificial jpeg image limits.
+	  Fixes #583048.
+
+2009-05-21 21:36:02 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* win32/common/config.h:
+	  win32: Update the win32 config.h
+
+2009-05-19 15:12:09 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	  matroskademux: Recognise PGS subpicture streams - the bluray format.
+	  Recognise and apply appropriate caps to PGS (Presentation Graphic Stream)
+	  subpicture streams.
+
+2009-05-15 10:42:19 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Convert an erroneous assertion
+	  Occasionally, we get a change callback for an old stream, triggering
+	  the assertion unnecessarily. Just ignore such callbacks.
+
+2009-05-20 16:14:40 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulse: Print a warning on under/overflows
+
+2009-05-20 18:45:45 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	  qtdemux: parse in24 boxes to get endianness
+	  in24 samples are normally big-endian but an enda box can change this to
+	  little-endian. Recurse into the in24 box and find the enda box so that we get
+	  the endianness right.
+	  Fixes #582515
+
+2009-05-20 14:14:31 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/multipart/multipartdemux.c:
+	  multipartdemux: add proper padtemplate
+
+2009-05-20 14:02:43 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/multipart/multipartdemux.c:
+	  multipartdemux: add more mime types
+	  Add mime-type for Panasonic g726 and add more required caps properties for other
+	  G726 mime-types.
+	  Make mime-types case insensitive.
+	  See #582169
+
+2009-05-20 13:47:52 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartdemux.h:
+	  multipartdemux: add flow aggregation
+
+2009-05-20 13:29:02 +0200  Arnout Vandecappelle <arnout@mind.be>
+
+	* gst/multipart/multipartdemux.c:
+	  multipartdemux: allow content to be empty.
+	  gst_adapter_take_buffer doesn't allow buffer to be empty.
+	  Simply skip any part where the content is empty.  Don't
+	  create a pad for it either.
+	  See #582169
+
+2009-05-18 22:19:39 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpchannels.h:
+	  rtp: fix channel positions for mono
+
+2009-05-21 21:02:11 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* configure.ac:
+	  Back to hacking -> 0.10.15.1
+
+=== release 0.10.15 ===
+
+2009-05-20 22:34:18 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.10.15
+
+2009-05-20 22:03:21 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2009-05-16 02:59:14 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* ChangeLog:
+	* configure.ac:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	* win32/common/config.h:
+	  0.10.14.3 pre-release
+
+2009-05-16 02:37:06 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* tests/check/pipelines/flacdec.c:
+	  check: Don't change directory in the test
+	  Changing directory invalidates the paths the registry has picked
+	  up for our plugins, because the test environment specifies relative
+	  paths. Fixing that is a separate problem, in the meantime, build a
+	  path to the test files instead of changing directory. Fixes the
+	  distcheck.
+
+2009-05-16 01:53:46 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* win32/MANIFEST:
+	  win32: Remove directdraw project files from the win32 manifest
+
+2009-05-16 01:21:34 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* tests/check/elements/rganalysis.c:
+	  check: Remove assertion that breaks check again git master
+	  Remove the assertion that the sender of the tags message is the
+	  element until we decide whether that's going to be true or not.
+
+2009-05-16 01:11:33 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/inspect/plugin-directdraw.xml:
+	* sys/Makefile.am:
+	* sys/directdraw/Makefile.am:
+	* sys/directdraw/gstdirectdrawplugin.c:
+	* sys/directdraw/gstdirectdrawsink.c:
+	* sys/directdraw/gstdirectdrawsink.h:
+	* win32/vs6/libgstdirectdraw.dsp:
+	* win32/vs7/libgstdirectdraw.vcproj:
+	* win32/vs8/libgstdirectdraw.vcproj:
+	  Moved 'directdraw' from -good to -bad
+
+2009-05-16 00:18:34 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* tests/check/pipelines/.gitignore:
+	  ignores: Ignore the flacdec check binary
+
+2009-05-16 00:17:57 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* docs/plugins/inspect/plugin-avi.xml:
+	  docs: Update inspection details for the avi plugin
+
+2009-05-16 00:00:07 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/inspect/plugin-y4menc.xml:
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/y4menc.c:
+	  Moved 'y4menc' from -bad to -good
+
+2009-05-13 17:55:46 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] y4menc: change my email
+	  change my email to something more current
+	  See #580783
+
+2009-05-13 17:54:47 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] y4menc: don't strip timestamps
+	  Fixes #582483
+
+2008-11-04 12:42:30 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  [MOVED FROM BAD] Don't install static libs for plugins. Fixes #550851 for -bad.
+	  Original commit message from CVS:
+	  * ext/alsaspdif/Makefile.am:
+	  * ext/amrwb/Makefile.am:
+	  * ext/apexsink/Makefile.am:
+	  * ext/arts/Makefile.am:
+	  * ext/artsd/Makefile.am:
+	  * ext/audiofile/Makefile.am:
+	  * ext/audioresample/Makefile.am:
+	  * ext/bz2/Makefile.am:
+	  * ext/cdaudio/Makefile.am:
+	  * ext/celt/Makefile.am:
+	  * ext/dc1394/Makefile.am:
+	  * ext/dirac/Makefile.am:
+	  * ext/directfb/Makefile.am:
+	  * ext/divx/Makefile.am:
+	  * ext/dts/Makefile.am:
+	  * ext/faac/Makefile.am:
+	  * ext/faad/Makefile.am:
+	  * ext/gsm/Makefile.am:
+	  * ext/hermes/Makefile.am:
+	  * ext/ivorbis/Makefile.am:
+	  * ext/jack/Makefile.am:
+	  * ext/jp2k/Makefile.am:
+	  * ext/ladspa/Makefile.am:
+	  * ext/lcs/Makefile.am:
+	  * ext/libfame/Makefile.am:
+	  * ext/libmms/Makefile.am:
+	  * ext/metadata/Makefile.am:
+	  * ext/mpeg2enc/Makefile.am:
+	  * ext/mplex/Makefile.am:
+	  * ext/musepack/Makefile.am:
+	  * ext/musicbrainz/Makefile.am:
+	  * ext/mythtv/Makefile.am:
+	  * ext/nas/Makefile.am:
+	  * ext/neon/Makefile.am:
+	  * ext/ofa/Makefile.am:
+	  * ext/polyp/Makefile.am:
+	  * ext/resindvd/Makefile.am:
+	  * ext/sdl/Makefile.am:
+	  * ext/shout/Makefile.am:
+	  * ext/snapshot/Makefile.am:
+	  * ext/sndfile/Makefile.am:
+	  * ext/soundtouch/Makefile.am:
+	  * ext/spc/Makefile.am:
+	  * ext/swfdec/Makefile.am:
+	  * ext/tarkin/Makefile.am:
+	  * ext/theora/Makefile.am:
+	  * ext/timidity/Makefile.am:
+	  * ext/twolame/Makefile.am:
+	  * ext/x264/Makefile.am:
+	  * ext/xine/Makefile.am:
+	  * ext/xvid/Makefile.am:
+	  * gst-libs/gst/app/Makefile.am:
+	  * gst-libs/gst/dshow/Makefile.am:
+	  * gst/aiffparse/Makefile.am:
+	  * gst/app/Makefile.am:
+	  * gst/audiobuffer/Makefile.am:
+	  * gst/bayer/Makefile.am:
+	  * gst/cdxaparse/Makefile.am:
+	  * gst/chart/Makefile.am:
+	  * gst/colorspace/Makefile.am:
+	  * gst/dccp/Makefile.am:
+	  * gst/deinterlace/Makefile.am:
+	  * gst/deinterlace2/Makefile.am:
+	  * gst/dvdspu/Makefile.am:
+	  * gst/festival/Makefile.am:
+	  * gst/filter/Makefile.am:
+	  * gst/flacparse/Makefile.am:
+	  * gst/flv/Makefile.am:
+	  * gst/games/Makefile.am:
+	  * gst/h264parse/Makefile.am:
+	  * gst/librfb/Makefile.am:
+	  * gst/mixmatrix/Makefile.am:
+	  * gst/modplug/Makefile.am:
+	  * gst/mpeg1sys/Makefile.am:
+	  * gst/mpeg4videoparse/Makefile.am:
+	  * gst/mpegdemux/Makefile.am:
+	  * gst/mpegtsmux/Makefile.am:
+	  * gst/mpegvideoparse/Makefile.am:
+	  * gst/mve/Makefile.am:
+	  * gst/nsf/Makefile.am:
+	  * gst/nuvdemux/Makefile.am:
+	  * gst/overlay/Makefile.am:
+	  * gst/passthrough/Makefile.am:
+	  * gst/pcapparse/Makefile.am:
+	  * gst/playondemand/Makefile.am:
+	  * gst/rawparse/Makefile.am:
+	  * gst/real/Makefile.am:
+	  * gst/rtjpeg/Makefile.am:
+	  * gst/rtpmanager/Makefile.am:
+	  * gst/scaletempo/Makefile.am:
+	  * gst/sdp/Makefile.am:
+	  * gst/selector/Makefile.am:
+	  * gst/smooth/Makefile.am:
+	  * gst/smoothwave/Makefile.am:
+	  * gst/speed/Makefile.am:
+	  * gst/speexresample/Makefile.am:
+	  * gst/stereo/Makefile.am:
+	  * gst/subenc/Makefile.am:
+	  * gst/tta/Makefile.am:
+	  * gst/vbidec/Makefile.am:
+	  * gst/videodrop/Makefile.am:
+	  * gst/videosignal/Makefile.am:
+	  * gst/virtualdub/Makefile.am:
+	  * gst/vmnc/Makefile.am:
+	  * gst/y4m/Makefile.am:
+	  * sys/acmenc/Makefile.am:
+	  * sys/cdrom/Makefile.am:
+	  * sys/dshowdecwrapper/Makefile.am:
+	  * sys/dshowsrcwrapper/Makefile.am:
+	  * sys/dvb/Makefile.am:
+	  * sys/dxr3/Makefile.am:
+	  * sys/fbdev/Makefile.am:
+	  * sys/oss4/Makefile.am:
+	  * sys/qcam/Makefile.am:
+	  * sys/qtwrapper/Makefile.am:
+	  * sys/vcd/Makefile.am:
+	  * sys/wininet/Makefile.am:
+	  * win32/common/config.h:
+	  Don't install static libs for plugins. Fixes #550851 for -bad.
+
+2008-06-26 15:52:40 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  [MOVED FROM BAD] Add documentation for YUV4MPEG2 encoder element.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * gst/y4m/gsty4mencode.c:
+	  Add documentation for YUV4MPEG2 encoder element.
+
+2007-04-24 15:49:18 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  [MOVED FROM BAD] Plug some leaks; try to make build bot happy again.
+	  Original commit message from CVS:
+	  * gst/y4m/gsty4mencode.c: (gst_y4m_encode_init),
+	  (gst_y4m_encode_setcaps):
+	  * tests/check/elements/y4menc.c: (GST_START_TEST):
+	  Plug some leaks; try to make build bot happy again.
+
+2006-11-13 18:55:57 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  [MOVED FROM BAD] configure.ac: Enable cdaudio and y4m.
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts <manauw at skynet be>
+	  * configure.ac:
+	  Enable cdaudio and y4m.
+	  * gst/y4m/Makefile.am:
+	  * gst/y4m/gsty4mencode.c: (gst_y4m_encode_base_init),
+	  (gst_y4m_encode_class_init), (gst_y4m_encode_init),
+	  (gst_y4m_encode_reset), (gst_y4m_encode_setcaps),
+	  (gst_y4m_encode_get_stream_header),
+	  (gst_y4m_encode_get_frame_header), (gst_y4m_encode_chain),
+	  (gst_y4m_encode_set_property), (gst_y4m_encode_get_property),
+	  (gst_y4m_encode_change_state), (plugin_init):
+	  * gst/y4m/gsty4mencode.h:
+	  Port of y4mencode to 0.10.
+
+2006-04-25 21:56:38 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  [MOVED FROM BAD] Define GstElementDetails as const and also static (when defined as global)
+	  Original commit message from CVS:
+	  * ext/amrwb/gstamrwbdec.c:
+	  * ext/amrwb/gstamrwbenc.c:
+	  * ext/amrwb/gstamrwbparse.c:
+	  * ext/arts/gst_arts.c:
+	  * ext/artsd/gstartsdsink.c:
+	  * ext/audiofile/gstafparse.c:
+	  * ext/audiofile/gstafsink.c:
+	  * ext/audiofile/gstafsrc.c:
+	  * ext/audioresample/gstaudioresample.c:
+	  * ext/bz2/gstbz2dec.c:
+	  * ext/bz2/gstbz2enc.c:
+	  * ext/cdaudio/gstcdaudio.c:
+	  * ext/directfb/dfbvideosink.c:
+	  * ext/divx/gstdivxdec.c:
+	  * ext/divx/gstdivxenc.c:
+	  * ext/dts/gstdtsdec.c: (gst_dtsdec_base_init):
+	  * ext/faac/gstfaac.c: (gst_faac_base_init):
+	  * ext/faad/gstfaad.c:
+	  * ext/gsm/gstgsmdec.c:
+	  * ext/gsm/gstgsmenc.c:
+	  * ext/hermes/gsthermescolorspace.c:
+	  * ext/ivorbis/vorbisfile.c:
+	  * ext/lcs/gstcolorspace.c:
+	  * ext/libfame/gstlibfame.c:
+	  * ext/libmms/gstmms.c: (gst_mms_base_init):
+	  * ext/musepack/gstmusepackdec.c: (gst_musepackdec_base_init):
+	  * ext/musicbrainz/gsttrm.c: (gst_musicbrainz_base_init):
+	  * ext/nas/nassink.c: (gst_nassink_base_init):
+	  * ext/neon/gstneonhttpsrc.c:
+	  * ext/sdl/sdlaudiosink.c:
+	  * ext/sdl/sdlvideosink.c:
+	  * ext/shout/gstshout.c:
+	  * ext/snapshot/gstsnapshot.c:
+	  * ext/sndfile/gstsf.c:
+	  * ext/swfdec/gstswfdec.c:
+	  * ext/tarkin/gsttarkindec.c:
+	  * ext/tarkin/gsttarkinenc.c:
+	  * ext/theora/theoradec.c:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_base_init):
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_base_init):
+	  * ext/xvid/gstxviddec.c:
+	  * ext/xvid/gstxvidenc.c:
+	  * gst/cdxaparse/gstcdxaparse.c: (gst_cdxa_parse_base_init):
+	  * gst/cdxaparse/gstcdxastrip.c: (gst_cdxastrip_base_init):
+	  * gst/chart/gstchart.c:
+	  * gst/colorspace/gstcolorspace.c:
+	  * gst/deinterlace/gstdeinterlace.c:
+	  * gst/equalizer/gstiirequalizer.c: (gst_iir_equalizer_base_init):
+	  * gst/festival/gstfestival.c:
+	  * gst/filter/gstbpwsinc.c:
+	  * gst/filter/gstiir.c:
+	  * gst/filter/gstlpwsinc.c:
+	  * gst/freeze/gstfreeze.c:
+	  * gst/games/gstpuzzle.c: (gst_puzzle_base_init):
+	  * gst/librfb/gstrfbsrc.c:
+	  * gst/mixmatrix/mixmatrix.c:
+	  * gst/mpeg1sys/gstmpeg1systemencode.c:
+	  * gst/mpeg1videoparse/gstmp1videoparse.c:
+	  * gst/mpeg2sub/gstmpeg2subt.c:
+	  * gst/mpegaudioparse/gstmpegaudioparse.c:
+	  * gst/multifilesink/gstmultifilesink.c:
+	  * gst/overlay/gstoverlay.c:
+	  * gst/passthrough/gstpassthrough.c:
+	  * gst/playondemand/gstplayondemand.c:
+	  * gst/qtdemux/qtdemux.c:
+	  * gst/rtjpeg/gstrtjpegdec.c:
+	  * gst/rtjpeg/gstrtjpegenc.c:
+	  * gst/smooth/gstsmooth.c:
+	  * gst/smoothwave/gstsmoothwave.c:
+	  * gst/spectrum/gstspectrum.c:
+	  * gst/speed/gstspeed.c:
+	  * gst/stereo/gststereo.c:
+	  * gst/switch/gstswitch.c:
+	  * gst/tta/gstttadec.c: (gst_tta_dec_base_init):
+	  * gst/tta/gstttaparse.c: (gst_tta_parse_base_init):
+	  * gst/vbidec/gstvbidec.c:
+	  * gst/videocrop/gstvideocrop.c:
+	  * gst/videodrop/gstvideodrop.c:
+	  * gst/virtualdub/gstxsharpen.c:
+	  * gst/xingheader/gstxingmux.c: (gst_xing_mux_base_init):
+	  * gst/y4m/gsty4mencode.c:
+	  * sys/cdrom/gstcdplayer.c:
+	  * sys/directdraw/gstdirectdrawsink.c:
+	  * sys/directsound/gstdirectsoundsink.c:
+	  * sys/glsink/glimagesink.c:
+	  * sys/qcam/gstqcamsrc.c:
+	  * sys/v4l2/gstv4l2src.c:
+	  * sys/vcd/vcdsrc.c: (gst_vcdsrc_base_init):
+	  * sys/ximagesrc/ximagesrc.c:
+	  Define GstElementDetails as const and also static (when defined as
+	  global)
+
+2006-04-08 21:48:01 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  [MOVED FROM BAD] Fix #337365 (g_type_class_ref <-> g_type_class_peek_parent)
+	  Original commit message from CVS:
+	  * ext/amrwb/gstamrwbdec.c: (gst_amrwbdec_class_init):
+	  * ext/amrwb/gstamrwbenc.c: (gst_amrwbenc_class_init):
+	  * ext/amrwb/gstamrwbparse.c: (gst_amrwbparse_class_init):
+	  * ext/arts/gst_arts.c: (gst_arts_class_init):
+	  * ext/artsd/gstartsdsink.c: (gst_artsdsink_class_init):
+	  * ext/audiofile/gstafsink.c: (gst_afsink_class_init):
+	  * ext/audiofile/gstafsrc.c: (gst_afsrc_class_init):
+	  * ext/audioresample/gstaudioresample.c:
+	  * ext/cdaudio/gstcdaudio.c: (gst_cdaudio_class_init):
+	  * ext/directfb/dfbvideosink.c: (gst_dfbvideosink_class_init):
+	  * ext/divx/gstdivxdec.c: (gst_divxdec_class_init):
+	  * ext/hermes/gsthermescolorspace.c:
+	  (gst_hermes_colorspace_class_init):
+	  * ext/ivorbis/vorbisfile.c: (gst_ivorbisfile_class_init):
+	  * ext/jack/gstjack.c: (gst_jack_class_init):
+	  * ext/jack/gstjackbin.c: (gst_jack_bin_class_init):
+	  * ext/lcs/gstcolorspace.c: (gst_colorspace_class_init):
+	  * ext/libfame/gstlibfame.c: (gst_fameenc_class_init):
+	  * ext/musicbrainz/gsttrm.c: (gst_musicbrainz_class_init):
+	  * ext/nas/nassink.c: (gst_nassink_class_init):
+	  * ext/shout/gstshout.c: (gst_icecastsend_class_init):
+	  * ext/snapshot/gstsnapshot.c: (gst_snapshot_class_init):
+	  * ext/sndfile/gstsf.c: (gst_sf_class_init):
+	  * ext/swfdec/gstswfdec.c: (gst_swfdecbuffer_class_init),
+	  (gst_swfdec_class_init):
+	  * ext/tarkin/gsttarkindec.c: (gst_tarkindec_class_init):
+	  * ext/tarkin/gsttarkinenc.c: (gst_tarkinenc_class_init):
+	  * gst/cdxaparse/gstcdxastrip.c: (gst_cdxastrip_class_init):
+	  * gst/chart/gstchart.c: (gst_chart_class_init):
+	  * gst/colorspace/gstcolorspace.c: (gst_colorspace_class_init):
+	  * gst/deinterlace/gstdeinterlace.c: (gst_deinterlace_class_init):
+	  * gst/festival/gstfestival.c: (gst_festival_class_init):
+	  * gst/filter/gstbpwsinc.c: (gst_bpwsinc_class_init):
+	  * gst/filter/gstiir.c: (gst_iir_class_init):
+	  * gst/filter/gstlpwsinc.c: (gst_lpwsinc_class_init):
+	  * gst/librfb/gstrfbsrc.c: (gst_rfbsrc_class_init):
+	  * gst/mixmatrix/mixmatrix.c: (gst_mixmatrix_class_init):
+	  * gst/mpeg1sys/gstmpeg1systemencode.c:
+	  (gst_system_encode_class_init):
+	  * gst/mpeg1videoparse/gstmp1videoparse.c:
+	  (gst_mp1videoparse_class_init):
+	  * gst/mpeg2sub/gstmpeg2subt.c: (gst_mpeg2subt_class_init):
+	  * gst/mpegaudioparse/gstmpegaudioparse.c:
+	  (gst_mp3parse_class_init):
+	  * gst/overlay/gstoverlay.c: (gst_overlay_class_init):
+	  * gst/passthrough/gstpassthrough.c: (passthrough_class_init):
+	  * gst/playondemand/gstplayondemand.c: (play_on_demand_class_init):
+	  * gst/rtjpeg/gstrtjpegdec.c: (gst_rtjpegdec_class_init):
+	  * gst/rtjpeg/gstrtjpegenc.c: (gst_rtjpegenc_class_init):
+	  * gst/smooth/gstsmooth.c: (gst_smooth_class_init):
+	  * gst/smoothwave/gstsmoothwave.c: (gst_smoothwave_class_init):
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_class_init):
+	  * gst/stereo/gststereo.c: (gst_stereo_class_init):
+	  * gst/switch/gstswitch.c: (gst_switch_class_init):
+	  * gst/tta/gstttadec.c: (gst_tta_dec_class_init):
+	  * gst/tta/gstttaparse.c: (gst_tta_parse_class_init):
+	  * gst/vbidec/gstvbidec.c: (gst_vbidec_class_init):
+	  * gst/videocrop/gstvideocrop.c: (gst_video_crop_class_init):
+	  * gst/virtualdub/gstxsharpen.c: (gst_xsharpen_class_init):
+	  * gst/y4m/gsty4mencode.c: (gst_y4mencode_class_init):
+	  * sys/cdrom/gstcdplayer.c: (cdplayer_class_init):
+	  * sys/directsound/gstdirectsoundsink.c:
+	  (gst_directsoundsink_class_init):
+	  * sys/dxr3/dxr3audiosink.c: (dxr3audiosink_class_init):
+	  * sys/dxr3/dxr3spusink.c: (dxr3spusink_class_init):
+	  * sys/dxr3/dxr3videosink.c: (dxr3videosink_class_init):
+	  * sys/qcam/gstqcamsrc.c: (gst_qcamsrc_class_init):
+	  * sys/v4l2/gstv4l2colorbalance.c:
+	  (gst_v4l2_color_balance_channel_class_init):
+	  * sys/v4l2/gstv4l2tuner.c: (gst_v4l2_tuner_channel_class_init),
+	  (gst_v4l2_tuner_norm_class_init):
+	  * sys/ximagesrc/ximagesrc.c: (gst_ximagesrc_class_init):
+	  Fix #337365 (g_type_class_ref <-> g_type_class_peek_parent)
+
+2006-04-08 19:04:01 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  [MOVED FROM BAD] gst/: Fix more broken GObject macros
+	  Original commit message from CVS:
+	  * gst/colorspace/gstcolorspace.h:
+	  * gst/deinterlace/gstdeinterlace.h:
+	  * gst/passthrough/gstpassthrough.h:
+	  * gst/y4m/gsty4mencode.h:
+	  Fix more broken GObject macros
+
+2006-04-06 11:35:26 +0000  j@bootlab.org <j@bootlab.org>
+
+	  [MOVED FROM BAD] Unify the long descriptions in the plugin details (#337263).
+	  Original commit message from CVS:
+	  Patch by: j^  <j at bootlab dot org>
+	  * ext/amrwb/gstamrwbdec.c:
+	  * ext/amrwb/gstamrwbenc.c:
+	  * ext/amrwb/gstamrwbparse.c:
+	  * ext/arts/gst_arts.c:
+	  * ext/artsd/gstartsdsink.c:
+	  * ext/audiofile/gstafparse.c:
+	  * ext/audiofile/gstafsink.c:
+	  * ext/audiofile/gstafsrc.c:
+	  * ext/cdaudio/gstcdaudio.c:
+	  * ext/directfb/dfbvideosink.c:
+	  * ext/divx/gstdivxdec.c:
+	  * ext/divx/gstdivxenc.c:
+	  * ext/dts/gstdtsdec.c: (gst_dtsdec_base_init):
+	  * ext/faac/gstfaac.c: (gst_faac_base_init):
+	  * ext/faad/gstfaad.c:
+	  * ext/gsm/gstgsmdec.c:
+	  * ext/gsm/gstgsmenc.c:
+	  * ext/hermes/gsthermescolorspace.c:
+	  * ext/ivorbis/vorbisfile.c:
+	  * ext/lcs/gstcolorspace.c:
+	  * ext/libfame/gstlibfame.c:
+	  * ext/libmms/gstmms.c: (gst_mms_base_init):
+	  * ext/musicbrainz/gsttrm.c: (gst_musicbrainz_base_init):
+	  * ext/nas/nassink.c: (gst_nassink_base_init):
+	  * ext/neon/gstneonhttpsrc.c:
+	  * ext/polyp/polypsink.c: (gst_polypsink_base_init):
+	  * ext/sdl/sdlaudiosink.c:
+	  * ext/sdl/sdlvideosink.c:
+	  * ext/shout/gstshout.c:
+	  * ext/snapshot/gstsnapshot.c:
+	  * ext/sndfile/gstsf.c:
+	  * ext/tarkin/gsttarkindec.c:
+	  * ext/tarkin/gsttarkinenc.c:
+	  * ext/theora/theoradec.c:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_base_init):
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_base_init):
+	  * ext/xvid/gstxviddec.c:
+	  * ext/xvid/gstxvidenc.c:
+	  * gst/cdxaparse/gstcdxaparse.c: (gst_cdxa_parse_base_init):
+	  * gst/cdxaparse/gstcdxastrip.c: (gst_cdxastrip_base_init):
+	  * gst/chart/gstchart.c:
+	  * gst/equalizer/gstiirequalizer.c: (gst_iir_equalizer_base_init):
+	  * gst/festival/gstfestival.c:
+	  * gst/filter/gstiir.c:
+	  * gst/filter/gstlpwsinc.c:
+	  * gst/freeze/gstfreeze.c:
+	  * gst/games/gstpuzzle.c: (gst_puzzle_base_init):
+	  * gst/mixmatrix/mixmatrix.c:
+	  * gst/mpeg1sys/gstmpeg1systemencode.c:
+	  * gst/mpeg1videoparse/gstmp1videoparse.c:
+	  * gst/mpeg2sub/gstmpeg2subt.c:
+	  * gst/mpegaudioparse/gstmpegaudioparse.c:
+	  * gst/multifilesink/gstmultifilesink.c:
+	  * gst/overlay/gstoverlay.c:
+	  * gst/passthrough/gstpassthrough.c:
+	  * gst/playondemand/gstplayondemand.c:
+	  * gst/qtdemux/qtdemux.c:
+	  * gst/rtjpeg/gstrtjpegdec.c:
+	  * gst/rtjpeg/gstrtjpegenc.c:
+	  * gst/smooth/gstsmooth.c:
+	  * gst/tta/gstttadec.c: (gst_tta_dec_base_init):
+	  * gst/tta/gstttaparse.c: (gst_tta_parse_base_init):
+	  * gst/videocrop/gstvideocrop.c:
+	  * gst/videodrop/gstvideodrop.c:
+	  * gst/virtualdub/gstxsharpen.c:
+	  * gst/xingheader/gstxingmux.c: (gst_xing_mux_base_init):
+	  * gst/y4m/gsty4mencode.c:
+	  Unify the long descriptions in the plugin details (#337263).
+
+2006-04-01 10:09:11 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] rework build; add translations for v4l2
+	  Original commit message from CVS:
+	  rework build; add translations for v4l2
+
+2005-09-05 17:20:29 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] Fix up all the state change functions.
+	  Original commit message from CVS:
+	  Fix up all the state change functions.
+
+2005-07-05 10:51:49 +0000  Andy Wingo <wingo@pobox.com>
+
+	  [MOVED FROM BAD] Way, way, way too many files: Remove crack comment from the 2000 era.
+	  Original commit message from CVS:
+	  2005-07-05  Andy Wingo  <wingo@pobox.com>
+	  * Way, way, way too many files:
+	  Remove crack comment from the 2000 era.
+
+2005-01-14 18:36:42 +0000  Stéphane Loeuillet <gstreamer@leroutier.net>
+
+	  [MOVED FROM BAD] I'm a bad boy. using /1001. to force C to do float division and not integer division (as it did in my last commit)
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdec.c:
+	  * gst/subparse/gstsubparse.c: (parse_mdvdsub):
+	  * gst/y4m/gsty4mencode.c: (gst_y4mencode_sinkconnect):
+	  I'm a bad boy. using /1001. to force C to do float division
+	  and not integer division (as it did in my last commit)
+	  Thanks to David I. Lehn for pointing this mistake.
+
+2005-01-14 12:27:22 +0000  Stéphane Loeuillet <gstreamer@leroutier.net>
+
+	  [MOVED FROM BAD] replace framerate aproximations by their real value (24000/1001, 30000/1001, 60000/1001)
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdec.c:
+	  * ext/libfame/gstlibfame.c:
+	  * gst/subparse/gstsubparse.c: (parse_mdvdsub):
+	  * gst/y4m/gsty4mencode.c: (gst_y4mencode_sinkconnect):
+	  replace framerate aproximations by their real value
+	  (24000/1001, 30000/1001, 60000/1001)
+	  Finish fixing bug #164049
+
+2004-07-27 21:41:30 +0000  Steve Lhomme <steve.lhomme@free.fr>
+
+	* gst/y4m/y4menc.vcproj:
+	  [MOVED FROM BAD] more working plugins
+	  Original commit message from CVS:
+	  more working plugins
+
+2004-07-27 09:57:33 +0000  Steve Lhomme <steve.lhomme@free.fr>
+
+	* gst/y4m/y4menc.vcproj:
+	  [MOVED FROM BAD] rename GStreamer-0.8.lib to libgstreamer.lib
+	  Original commit message from CVS:
+	  rename GStreamer-0.8.lib to libgstreamer.lib
+
+2004-07-27 09:48:51 +0000  Steve Lhomme <steve.lhomme@free.fr>
+
+	* gst/y4m/y4menc.vcproj:
+	  [MOVED FROM BAD] avoid problems with math.h, fix release dependancy
+	  Original commit message from CVS:
+	  avoid problems with math.h, fix release dependancy
+
+2004-07-26 13:20:11 +0000  Steve Lhomme <steve.lhomme@free.fr>
+
+	* gst/y4m/y4menc.vcproj:
+	  [MOVED FROM BAD] more plugins supported under windows
+	  Original commit message from CVS:
+	  more plugins supported under windows
+
+2004-04-01 11:48:27 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] a52dec:   Use a debug category, Output timestamps correctly
+	  Original commit message from CVS:
+	  a52dec:   Use a debug category, Output timestamps correctly
+	  Emit tag info, Handle events, tell liba52dec about cpu
+	  capabilities so it can use MMX etc.
+	  dvdec:    Fix a crasher accessing invalid memory
+	  dvdnavsrc:Some support for byte-format seeking.
+	  Small fixes for still frames and menu button overlays
+	  mpeg2dec: Use a debug category. Adjust the report level of several items to
+	  LOG. Call mpeg2_custom_fbuf to mark our buffers as 'custom buffers'
+	  so it doesn't lose the GstBuffer pointer
+	  navseek:  Add the navseek debug element for seeking back and forth in a
+	  video stream using arrow keys.
+	  mpeg2subt:Pretty much a complete rewrite. Now a loopbased element. May still
+	  require work to properly synchronise subtitle buffers.
+	  mpegdemux:
+	  dvddemux: Don't attempt to create subbuffers of size 0
+	  Reduce a couple of error outputs to warnings.
+	  y4mencode:Output the y4m frame header correctly
+
+2004-03-15 19:32:27 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] don't mix tabs and spaces
+	  Original commit message from CVS:
+	  don't mix tabs and spaces
+
+2004-03-15 16:32:54 +0000  Johan Dahlin <johan@gnome.org>
+
+	  [MOVED FROM BAD] *.h: Revert indenting
+	  Original commit message from CVS:
+	  * *.h: Revert indenting
+
+2004-03-14 22:34:33 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/y4m/gsty4mencode.c:
+	* gst/y4m/gsty4mencode.h:
+	  [MOVED FROM BAD] gst-indent
+	  Original commit message from CVS:
+	  gst-indent
+
+2004-01-12 02:01:52 +0000  Benjamin Otte <otte@gnome.org>
+
+	  [MOVED FROM BAD] gst-libs/gst/video/video.h: Fix caps template names to be understandable.
+	  Original commit message from CVS:
+	  2004-01-12  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+	  * gst-libs/gst/video/video.h:
+	  Fix caps template names to be understandable.
+	  Prefix everything with GST_VIDEO.
+	  * ext/aalib/gstaasink.c:
+	  * ext/divx/gstdivxdec.c:
+	  * ext/divx/gstdivxenc.c:
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c:
+	  * ext/hermes/gstcolorspace.c: (gst_colorspace_base_init):
+	  * ext/jpeg/gstjpegdec.c: (raw_caps_factory):
+	  * ext/jpeg/gstjpegenc.c: (raw_caps_factory):
+	  * ext/libcaca/gstcacasink.c:
+	  * ext/libpng/gstpngenc.c: (raw_caps_factory):
+	  * ext/snapshot/gstsnapshot.c:
+	  * ext/swfdec/gstswfdec.c:
+	  * ext/xvid/gstxviddec.c:
+	  * ext/xvid/gstxvidenc.c:
+	  * gst/chart/gstchart.c:
+	  * gst/deinterlace/gstdeinterlace.c:
+	  * gst/effectv/gsteffectv.c:
+	  * gst/flx/gstflxdec.c: (gst_flxdec_loop):
+	  * gst/goom/gstgoom.c:
+	  * gst/median/gstmedian.c:
+	  * gst/monoscope/gstmonoscope.c: (gst_monoscope_init),
+	  (gst_monoscope_srcconnect), (gst_monoscope_chain):
+	  * gst/overlay/gstoverlay.c:
+	  * gst/smooth/gstsmooth.c:
+	  * gst/smpte/gstsmpte.c:
+	  * gst/synaesthesia/gstsynaesthesia.c:
+	  * gst/videocrop/gstvideocrop.c:
+	  * gst/videodrop/gstvideodrop.c:
+	  * gst/y4m/gsty4mencode.c:
+	  * sys/qcam/gstqcamsrc.c:
+	  * sys/v4l/gstv4lsrc.c: (gst_v4lsrc_palette_to_caps):
+	  Make them work with new video.h file.
+	  * sys/ximage/ximagesink.c: (gst_ximagesink_chain),
+	  (gst_ximagesink_buffer_free), (gst_ximagesink_buffer_alloc):
+	  * sys/xvimage/xvimagesink.c: (gst_xvimagesink_chain),
+	  (gst_xvimagesink_buffer_free), (gst_xvimagesink_buffer_alloc):
+	  Make it work with new buffer allocation system.
+
+2003-12-22 01:47:09 +0000  David Schleef <ds@schleef.org>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] Merge CAPS branch
+	  Original commit message from CVS:
+	  Merge CAPS branch
+
+2003-12-04 10:37:38 +0000  Andy Wingo <wingo@pobox.com>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] remove copyright field from plugins
+	  Original commit message from CVS:
+	  remove copyright field from plugins
+
+2003-11-16 22:02:23 +0000  Leif Johnson <leif@ambient.2y.net>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] + checking in plugin category changes
+	  Original commit message from CVS:
+	  + checking in plugin category changes
+
+2003-11-07 12:47:02 +0000  Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+
+	* gst/y4m/gsty4mencode.h:
+	  [MOVED FROM BAD] Remove all config.h includes from header files, add it to each source file and remove duplicate config.h includes fro...
+	  Original commit message from CVS:
+	  Remove all config.h includes from header files, add it to each source file and remove duplicate config.h includes from several source files
+
+2003-11-02 19:17:27 +0000  Benjamin Otte <otte@gnome.org>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] fix to new plugin system
+	  Original commit message from CVS:
+	  fix to new plugin system
+
+2003-10-08 16:08:19 +0000  Andy Wingo <wingo@pobox.com>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] /GstBuffer/GstData/ in the API where you can pass events. Fix the plugins to deal with that. Fixes #113488.
+	  Original commit message from CVS:
+	  /GstBuffer/GstData/ in the API where you can pass events. Fix the plugins to deal with that. Fixes #113488.
+
+2003-08-10 00:01:58 +0000  David Schleef <ds@schleef.org>
+
+	* gst/y4m/Makefile.am:
+	  [MOVED FROM BAD] Remove redundant plugindir definition
+	  Original commit message from CVS:
+	  Remove redundant plugindir definition
+
+2003-07-06 20:49:52 +0000  Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+
+	* gst/y4m/gsty4mencode.c:
+	* gst/y4m/gsty4mencode.h:
+	  [MOVED FROM BAD] New mimetypes gone into effect today - this commit changes all old mimetypes over to the new mimetypes spec as descri...
+	  Original commit message from CVS:
+	  New mimetypes gone into effect today - this commit changes all old mimetypes over to the new mimetypes spec as described in the previous commit's document. Note: some plugins will break, some pipelines will break, expect HEAD to be broken or at least not 100% working for a few days, but don't forget to report bugs
+
+2003-06-29 19:46:13 +0000  Benjamin Otte <otte@gnome.org>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] compatibility fix for new GST_DEBUG stuff.
+	  Original commit message from CVS:
+	  compatibility fix for new GST_DEBUG stuff.
+	  Includes fixes for missing includes for config.h and unistd.h
+	  I only ensured for plugins I can build that they work, so if some of them are still broken, you gotta fix them yourselves unfortunately.
+
+2003-01-10 13:38:32 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] PadConnect -> PadLink
+	  Original commit message from CVS:
+	  PadConnect -> PadLink
+
+2003-01-10 10:22:25 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] another batch of connect->link fixes please let me know about issues and please refrain of making them yourself, so t...
+	  Original commit message from CVS:
+	  another batch of connect->link fixes
+	  please let me know about issues
+	  and please refrain of making them yourself, so that I don't spend double
+	  the time resolving conflicts
+
+2002-12-08 14:50:10 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/y4m/Makefile.am:
+	  [MOVED FROM BAD] parallel install fixes
+	  Original commit message from CVS:
+	  parallel install fixes
+
+2002-09-18 19:02:52 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] plugins part of license field patch
+	  Original commit message from CVS:
+	  plugins part of license field patch
+
+2002-06-17 10:29:30 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/y4m/Makefile.am:
+	  [MOVED FROM BAD] cosmetic change
+	  Original commit message from CVS:
+	  cosmetic change
+
+2002-05-03 09:59:10 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] various name fixes and sundry
+	  Original commit message from CVS:
+	  various name fixes and sundry
+
+2002-04-20 21:42:51 +0000  Andy Wingo <wingo@pobox.com>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] a hack to work around intltool's brokenness a current check for mpeg2dec details->klass reorganizations an element br...
+	  Original commit message from CVS:
+	  * a hack to work around intltool's brokenness
+	  * a current check for mpeg2dec
+	  * details->klass reorganizations
+	  * an element browser that uses details->klass
+	  * separated cdxa parse out from the avi directory
+
+2002-04-11 20:42:26 +0000  Andy Wingo <wingo@pobox.com>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] GstPadTemplate <-> gst_pad_template <-> GST_PAD_TEMPLATE same with *factory and typefind.
+	  Original commit message from CVS:
+	  GstPadTemplate <-> gst_pad_template <-> GST_PAD_TEMPLATE
+	  same with *factory and typefind.
+	  also, some -Werror fixes.
+
+2002-03-30 17:06:26 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] Changed to the new props API
+	  Original commit message from CVS:
+	  Changed to the new props API
+	  Other small tuff.
+
+2002-03-20 21:45:04 +0000  Andy Wingo <wingo@pobox.com>
+
+	* gst/y4m/gsty4mencode.c:
+	* gst/y4m/gsty4mencode.h:
+	  [MOVED FROM BAD] s/Gnome-Streamer/GStreamer/
+	  Original commit message from CVS:
+	  s/Gnome-Streamer/GStreamer/
+
+2002-03-19 04:10:06 +0000  Andy Wingo <wingo@pobox.com>
+
+	* gst/y4m/Makefile.am:
+	* gst/y4m/gsty4mencode.c:
+	* gst/y4m/gsty4mencode.h:
+	  [MOVED FROM BAD] removal of //-style comments don't link plugins to core libs -- the versioning is done internally to the plugins with...
+	  Original commit message from CVS:
+	  * removal of //-style comments
+	  * don't link plugins to core libs -- the versioning is done internally to the plugins with the plugin_info struct,
+	  and symbol resolution is lazy, so we can always know if a plugin can be loaded by the plugin_info data. in theory.
+
+2002-03-19 01:39:43 +0000  Andy Wingo <wingo@pobox.com>
+
+	* gst/y4m/Makefile.am:
+	  [MOVED FROM BAD] s/@GST_PLUGIN_LDFLAGS@/$(GST_PLUGIN_LDFLAGS)/ @-substitued variables variables are defined as make variables automagi...
+	  Original commit message from CVS:
+	  s/@GST_PLUGIN_LDFLAGS@/$(GST_PLUGIN_LDFLAGS)/
+	  @-substitued variables variables are defined as make variables automagically,
+	  and this gives the user the freedom to say make GST_PLUGIN_LDFLAGS=-myflag
+
+2002-01-18 11:37:19 +0000  Wrobell <wrobell@ite.pl>
+
+	* gst/y4m/Makefile.am:
+	  [MOVED FROM BAD] - plugins are built without versioning info
+	  Original commit message from CVS:
+	  - plugins are built without versioning info
+
+2002-01-13 22:27:25 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] Bring the plugins in sync with the new core capsnego system.
+	  Original commit message from CVS:
+	  Bring the plugins in sync with the new core capsnego system.
+	  Added some features, enhancements...
+
+2002-01-12 03:34:27 +0000  David I. Lehn <dlehn@users.sourceforge.net>
+
+	* gst/y4m/Makefile.am:
+	  [MOVED FROM BAD] s/filter/plugin/ link plugins to GST_LIBS rearrange rules to a common format
+	  Original commit message from CVS:
+	  * s/filter/plugin/
+	  * link plugins to GST_LIBS
+	  * rearrange rules to a common format
+
+2001-12-23 20:21:20 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/y4m/Makefile.am:
+	* gst/y4m/gsty4mencode.c:
+	  [MOVED FROM BAD] more fixes
+	  Original commit message from CVS:
+	  more fixes
+
+2001-12-23 13:17:36 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/y4m/Makefile.am:
+	* gst/y4m/gsty4mencode.c:
+	* gst/y4m/gsty4mencode.h:
+	  [MOVED FROM BAD] BBB asked me to rename lav to y4m can someone who knows the plugin do this in the source as well ?
+	  Original commit message from CVS:
+	  BBB asked me to rename lav to y4m
+	  can someone who knows the plugin do this in the source as well ?
+
+2009-05-15 18:17:35 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* po/Makevars:
+	  po: add Makevars magic so we don't get line numbers in *.po files
+	  This avoids the number one reason for local modifications in *.po
+	  files and and makes things less annoying when working with git (or
+	  any other VCS for that matter).
+
+2009-05-15 17:11:27 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	* tests/check/elements/id3demux.c:
+	* tests/check/elements/souphttpsrc.c:
+	* tests/check/pipelines/flacdec.c:
+	* tests/files/Makefile.am:
+	* tests/files/audiotestsrc.flac:
+	* tests/files/test-cert.pem:
+	* tests/files/test-key.pem:
+	  checks: move files required by unit tests into tests/files and make sure they're disted
+	  Move unit test data into the directory where it belongs and make in particular
+	  the flacdec unit test cd into the directory with the test files instead of making
+	  assumptions about the current working directory in that unit test. As a side effect
+	  of movng those files, there's only one EXTRA_DIST in tests/check/Makefile.am now,
+	  which is likely to work better than having two. Hopefully fixes #582753.
+
+2009-05-14 21:43:14 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace/gstdeinterlace.c:
+	  deinterlace: If the upstream max latency is unbound return unbound max latency
+	  Fixes bug #582661.
+
+2009-05-15 08:44:39 +0200  James Andrewartha <trs80@ucc.gu.uwa.edu.au>
+
+	* gst/flv/gstflvmux.c:
+	* sys/sunaudio/gstsunaudiomixerctrl.c:
+	* sys/sunaudio/gstsunaudiomixertrack.c:
+	* sys/sunaudio/gstsunaudiosrc.c:
+	* sys/v4l2/v4l2_calls.c:
+	  Fix compiler warnings
+	  Fixes bug #582715.
+
+2009-05-13 22:46:44 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* configure.ac:
+	  Recovered debugutils line accidentally removed in deinterlace2 move.
+
+2009-05-13 10:46:40 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/inspect/plugin-deinterlace.xml:
+	* gst/deinterlace/Makefile.am:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/deinterlace/gstdeinterlace.h:
+	* gst/deinterlace/tvtime/greedy.c:
+	* gst/deinterlace/tvtime/greedyh.asm:
+	* gst/deinterlace/tvtime/greedyh.c:
+	* gst/deinterlace/tvtime/greedyhmacros.h:
+	* gst/deinterlace/tvtime/linear.c:
+	* gst/deinterlace/tvtime/linearblend.c:
+	* gst/deinterlace/tvtime/mmx.h:
+	* gst/deinterlace/tvtime/plugins.h:
+	* gst/deinterlace/tvtime/scalerbob.c:
+	* gst/deinterlace/tvtime/sse.h:
+	* gst/deinterlace/tvtime/tomsmocomp.c:
+	* gst/deinterlace/tvtime/tomsmocomp/SearchLoop0A.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/SearchLoopBottom.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/SearchLoopEdgeA.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/SearchLoopEdgeA8.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddA.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddA2.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddA6.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddAH.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddAH2.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/SearchLoopTop.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/SearchLoopVA.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/SearchLoopVAH.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/StrangeBob.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/TomsMoCompAll2.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/WierdBob.inc:
+	* gst/deinterlace/tvtime/tomsmocomp/tomsmocompmacros.h:
+	* gst/deinterlace/tvtime/vfir.c:
+	* gst/deinterlace/tvtime/weave.c:
+	* gst/deinterlace/tvtime/weavebff.c:
+	* gst/deinterlace/tvtime/weavetff.c:
+	* gst/deinterlace/tvtime/x86-64_macros.inc:
+	  Moved 'deinterlace2' from -bad to -good
+	  And rename it to deinterlace.
+
+2009-05-08 15:39:24 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace2/gstdeinterlace2.c:
+	* gst/deinterlace2/gstdeinterlace2.h:
+	  [MOVED FROM BAD 56/56] deinterlace2: Add a disabled mode for passthrough operation
+	  Also allow to change the mode in PAUSED and PLAYING by updating
+	  the caps if necessary.
+
+2009-04-22 19:43:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace2/gstdeinterlace2.c:
+	* gst/deinterlace2/gstdeinterlace2.h:
+	  [MOVED FROM BAD 55/56] deinterlace2: Add documentation and integrate into the build system
+
+2009-04-19 17:18:35 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace2/gstdeinterlace2.c:
+	  [MOVED FROM BAD 54/56] deinterlace2: Make it possible to select interlacing autodetection or to enfore deinterlacing
+	  For this add a "mode" property that defaults to "interlaced" for now as
+	  most decoders/demuxers don't properly set the "interlaced" field on the
+	  caps yet.
+	  If this property is set to "auto" the element will work in passthrough
+	  mode unless the caps contain the "interlaced" field.
+
+2009-04-17 15:39:59 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace2/gstdeinterlace2.c:
+	  [MOVED FROM BAD 53/56] deinterlace2: Use GST_(DEBUG|WARNING|ERROR)_OBJECT instead of the non-OBJECT ones
+
+2009-04-17 15:39:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace2/gstdeinterlace2.c:
+	  [MOVED FROM BAD 52/56] deinterlace2: Reset history if DISCONT is set on the incoming buffer
+
+2009-04-17 15:39:10 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace2/gstdeinterlace2.c:
+	  [MOVED FROM BAD 51/56] deinterlace2: Fix timestamps for buffers with RFF flag set
+
+2009-04-16 17:41:37 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace2/gstdeinterlace2.c:
+	* gst/deinterlace2/gstdeinterlace2.h:
+	* gst/deinterlace2/tvtime/greedy.c:
+	* gst/deinterlace2/tvtime/greedyh.c:
+	* gst/deinterlace2/tvtime/scalerbob.c:
+	* gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	* gst/deinterlace2/tvtime/weave.c:
+	* gst/deinterlace2/tvtime/weavebff.c:
+	* gst/deinterlace2/tvtime/weavetff.c:
+	  [MOVED FROM BAD 50/56] deinterlace2: Rename line_length to row_stride and remove output_stride
+
+2009-04-16 15:52:39 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace2/gstdeinterlace2.c:
+	  [MOVED FROM BAD 49/56] deinterlace2: Implement support for RFF and ONEFIELD buffer flags
+
+2009-04-15 15:46:44 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace2/gstdeinterlace2.c:
+	* gst/deinterlace2/gstdeinterlace2.h:
+	* gst/deinterlace2/tvtime/greedy.c:
+	* gst/deinterlace2/tvtime/greedyh.c:
+	* gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	  [MOVED FROM BAD 48/56] deinterlace2: Move output buffer from the instance struct to a function parameter
+
+2009-04-15 15:33:17 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace2/gstdeinterlace2.c:
+	* gst/deinterlace2/gstdeinterlace2.h:
+	  [MOVED FROM BAD 47/56] deinterlace2: Add initial support for automatic detection of the field order
+
+2009-04-15 14:47:49 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/deinterlace2/gstdeinterlace2.c:
+	  [MOVED FROM BAD 46/56] deinterlace2: Add support for YVYU colorspace
+	  This is the same as YUY2 with just Cr and Cb swapped. As
+	  we don't make a difference between them when deinterlacing
+	  this works.
+
+2008-11-06 14:05:55 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  [MOVED FROM BAD 45/56] gst/deinterlace2/gstdeinterlace2.c: Bring properties into this century.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/gstdeinterlace2.c:
+	  (gst_deinterlace2_class_init), (gst_deinterlace2_init),
+	  (gst_deinterlace2_set_property), (gst_deinterlace2_get_property):
+	  Bring properties into this century.
+
+2008-11-04 12:42:30 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  [MOVED FROM BAD 44/56] Don't install static libs for plugins. Fixes #550851 for -bad.
+	  Original commit message from CVS:
+	  * ext/alsaspdif/Makefile.am:
+	  * ext/amrwb/Makefile.am:
+	  * ext/apexsink/Makefile.am:
+	  * ext/arts/Makefile.am:
+	  * ext/artsd/Makefile.am:
+	  * ext/audiofile/Makefile.am:
+	  * ext/audioresample/Makefile.am:
+	  * ext/bz2/Makefile.am:
+	  * ext/cdaudio/Makefile.am:
+	  * ext/celt/Makefile.am:
+	  * ext/dc1394/Makefile.am:
+	  * ext/dirac/Makefile.am:
+	  * ext/directfb/Makefile.am:
+	  * ext/divx/Makefile.am:
+	  * ext/dts/Makefile.am:
+	  * ext/faac/Makefile.am:
+	  * ext/faad/Makefile.am:
+	  * ext/gsm/Makefile.am:
+	  * ext/hermes/Makefile.am:
+	  * ext/ivorbis/Makefile.am:
+	  * ext/jack/Makefile.am:
+	  * ext/jp2k/Makefile.am:
+	  * ext/ladspa/Makefile.am:
+	  * ext/lcs/Makefile.am:
+	  * ext/libfame/Makefile.am:
+	  * ext/libmms/Makefile.am:
+	  * ext/metadata/Makefile.am:
+	  * ext/mpeg2enc/Makefile.am:
+	  * ext/mplex/Makefile.am:
+	  * ext/musepack/Makefile.am:
+	  * ext/musicbrainz/Makefile.am:
+	  * ext/mythtv/Makefile.am:
+	  * ext/nas/Makefile.am:
+	  * ext/neon/Makefile.am:
+	  * ext/ofa/Makefile.am:
+	  * ext/polyp/Makefile.am:
+	  * ext/resindvd/Makefile.am:
+	  * ext/sdl/Makefile.am:
+	  * ext/shout/Makefile.am:
+	  * ext/snapshot/Makefile.am:
+	  * ext/sndfile/Makefile.am:
+	  * ext/soundtouch/Makefile.am:
+	  * ext/spc/Makefile.am:
+	  * ext/swfdec/Makefile.am:
+	  * ext/tarkin/Makefile.am:
+	  * ext/theora/Makefile.am:
+	  * ext/timidity/Makefile.am:
+	  * ext/twolame/Makefile.am:
+	  * ext/x264/Makefile.am:
+	  * ext/xine/Makefile.am:
+	  * ext/xvid/Makefile.am:
+	  * gst-libs/gst/app/Makefile.am:
+	  * gst-libs/gst/dshow/Makefile.am:
+	  * gst/aiffparse/Makefile.am:
+	  * gst/app/Makefile.am:
+	  * gst/audiobuffer/Makefile.am:
+	  * gst/bayer/Makefile.am:
+	  * gst/cdxaparse/Makefile.am:
+	  * gst/chart/Makefile.am:
+	  * gst/colorspace/Makefile.am:
+	  * gst/dccp/Makefile.am:
+	  * gst/deinterlace/Makefile.am:
+	  * gst/deinterlace2/Makefile.am:
+	  * gst/dvdspu/Makefile.am:
+	  * gst/festival/Makefile.am:
+	  * gst/filter/Makefile.am:
+	  * gst/flacparse/Makefile.am:
+	  * gst/flv/Makefile.am:
+	  * gst/games/Makefile.am:
+	  * gst/h264parse/Makefile.am:
+	  * gst/librfb/Makefile.am:
+	  * gst/mixmatrix/Makefile.am:
+	  * gst/modplug/Makefile.am:
+	  * gst/mpeg1sys/Makefile.am:
+	  * gst/mpeg4videoparse/Makefile.am:
+	  * gst/mpegdemux/Makefile.am:
+	  * gst/mpegtsmux/Makefile.am:
+	  * gst/mpegvideoparse/Makefile.am:
+	  * gst/mve/Makefile.am:
+	  * gst/nsf/Makefile.am:
+	  * gst/nuvdemux/Makefile.am:
+	  * gst/overlay/Makefile.am:
+	  * gst/passthrough/Makefile.am:
+	  * gst/pcapparse/Makefile.am:
+	  * gst/playondemand/Makefile.am:
+	  * gst/rawparse/Makefile.am:
+	  * gst/real/Makefile.am:
+	  * gst/rtjpeg/Makefile.am:
+	  * gst/rtpmanager/Makefile.am:
+	  * gst/scaletempo/Makefile.am:
+	  * gst/sdp/Makefile.am:
+	  * gst/selector/Makefile.am:
+	  * gst/smooth/Makefile.am:
+	  * gst/smoothwave/Makefile.am:
+	  * gst/speed/Makefile.am:
+	  * gst/speexresample/Makefile.am:
+	  * gst/stereo/Makefile.am:
+	  * gst/subenc/Makefile.am:
+	  * gst/tta/Makefile.am:
+	  * gst/vbidec/Makefile.am:
+	  * gst/videodrop/Makefile.am:
+	  * gst/videosignal/Makefile.am:
+	  * gst/virtualdub/Makefile.am:
+	  * gst/vmnc/Makefile.am:
+	  * gst/y4m/Makefile.am:
+	  * sys/acmenc/Makefile.am:
+	  * sys/cdrom/Makefile.am:
+	  * sys/dshowdecwrapper/Makefile.am:
+	  * sys/dshowsrcwrapper/Makefile.am:
+	  * sys/dvb/Makefile.am:
+	  * sys/dxr3/Makefile.am:
+	  * sys/fbdev/Makefile.am:
+	  * sys/oss4/Makefile.am:
+	  * sys/qcam/Makefile.am:
+	  * sys/qtwrapper/Makefile.am:
+	  * sys/vcd/Makefile.am:
+	  * sys/wininet/Makefile.am:
+	  * win32/common/config.h:
+	  Don't install static libs for plugins. Fixes #550851 for -bad.
+
+2008-10-09 19:38:52 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 43/56] gst/deinterlace2/tvtime/tomsmocomp.c: Fix unused variable compiler warning when not building
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/tomsmocomp.c:
+	  (gst_deinterlace_method_tomsmocomp_class_init):
+	  Fix unused variable compiler warning when not building
+	  X86 assembly.
+
+2008-08-28 17:16:51 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  [MOVED FROM BAD 42/56] gst/dccp/: Fix compilation on Solaris by including filio.h as needed.
+	  Original commit message from CVS:
+	  * gst/dccp/gstdccp.c:
+	  * gst/dccp/gstdccpclientsrc.c:
+	  Fix compilation on Solaris by including filio.h as needed.
+	  * gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll2.inc:
+	  Fix compilation with Forte - apparently it hates concatenating a
+	  macro argument that starts with an underscore??
+
+2008-08-26 12:33:16 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 41/56] gst/deinterlace2/tvtime/tomsmocomp/: Unroll the loop to handle two bytes at once. This should give a small speedup an...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopBottom.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopTop.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/StrangeBob.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/WierdBob.inc:
+	  Unroll the loop to handle two bytes at once. This should give
+	  a small speedup and makes it possible to handle chroma and luma
+	  different which is needed later.
+
+2008-08-25 14:37:45 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 40/56] gst/deinterlace2/: First part of the C implementation of the tomsmocomp deinterlacing algorithm. This only supports s...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/gstdeinterlace2.c:
+	  (gst_deinterlace_method_class_init):
+	  * gst/deinterlace2/gstdeinterlace2.h:
+	  * gst/deinterlace2/tvtime/tomsmocomp.c:
+	  (gst_deinterlace_method_tomsmocomp_class_init):
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopBottom.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopTop.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/StrangeBob.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll2.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/WierdBob.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/tomsmocompmacros.h:
+	  First part of the C implementation of the tomsmocomp deinterlacing
+	  algorithm. This only supports search-effort=0 currently, is painfully
+	  slow and needs some cleanup later when all search-effort settings
+	  are implemented in C.
+
+2008-08-02 18:48:17 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 39/56] gst/deinterlace2/: Use oil_memcpy() instead of memcpy() as it's faster for the sizes that are usually used here.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/gstdeinterlace2.c:
+	  (gst_deinterlace_simple_method_interpolate_scanline),
+	  (gst_deinterlace_simple_method_copy_scanline),
+	  (gst_deinterlace_simple_method_deinterlace_frame):
+	  * gst/deinterlace2/tvtime/greedy.c: (deinterlace_frame_di_greedy):
+	  * gst/deinterlace2/tvtime/greedyh.c:
+	  (deinterlace_frame_di_greedyh):
+	  * gst/deinterlace2/tvtime/scalerbob.c:
+	  (deinterlace_scanline_scaler_bob):
+	  * gst/deinterlace2/tvtime/tomsmocomp.c: (Fieldcopy):
+	  * gst/deinterlace2/tvtime/weave.c: (deinterlace_scanline_weave),
+	  (copy_scanline):
+	  * gst/deinterlace2/tvtime/weavebff.c: (deinterlace_scanline_weave),
+	  (copy_scanline):
+	  * gst/deinterlace2/tvtime/weavetff.c: (deinterlace_scanline_weave),
+	  (copy_scanline):
+	  Use oil_memcpy() instead of memcpy() as it's faster for the sizes that
+	  are usually used here.
+
+2008-08-02 18:36:11 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 38/56] gst/deinterlace2/: Add the remaining tvtime deinterlacing methods and fix the deinterlace_frame() implementation of G...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/Makefile.am:
+	  * gst/deinterlace2/gstdeinterlace2.c:
+	  (gst_deinterlace_simple_method_deinterlace_frame),
+	  (gst_deinterlace2_methods_get_type), (gst_deinterlace2_set_method):
+	  * gst/deinterlace2/gstdeinterlace2.h:
+	  * gst/deinterlace2/tvtime/linear.c:
+	  (deinterlace_scanline_linear_c), (deinterlace_scanline_linear_mmx),
+	  (deinterlace_scanline_linear_mmxext),
+	  (gst_deinterlace_method_linear_class_init),
+	  (gst_deinterlace_method_linear_init):
+	  * gst/deinterlace2/tvtime/linearblend.c:
+	  (deinterlace_scanline_linear_blend_c),
+	  (deinterlace_scanline_linear_blend2_c),
+	  (deinterlace_scanline_linear_blend_mmx),
+	  (deinterlace_scanline_linear_blend2_mmx),
+	  (gst_deinterlace_method_linear_blend_class_init),
+	  (gst_deinterlace_method_linear_blend_init):
+	  * gst/deinterlace2/tvtime/plugins.h:
+	  * gst/deinterlace2/tvtime/scalerbob.c:
+	  (deinterlace_scanline_scaler_bob),
+	  (gst_deinterlace_method_scaler_bob_class_init),
+	  (gst_deinterlace_method_scaler_bob_init):
+	  * gst/deinterlace2/tvtime/weave.c: (deinterlace_scanline_weave),
+	  (copy_scanline), (gst_deinterlace_method_weave_class_init),
+	  (gst_deinterlace_method_weave_init):
+	  * gst/deinterlace2/tvtime/weavebff.c: (deinterlace_scanline_weave),
+	  (copy_scanline), (gst_deinterlace_method_weave_bff_class_init),
+	  (gst_deinterlace_method_weave_bff_init):
+	  * gst/deinterlace2/tvtime/weavetff.c: (deinterlace_scanline_weave),
+	  (copy_scanline), (gst_deinterlace_method_weave_tff_class_init),
+	  (gst_deinterlace_method_weave_tff_init):
+	  Add the remaining tvtime deinterlacing methods and fix the
+	  deinterlace_frame() implementation of GstDeinterlaceSimpleMethod.
+
+2008-08-02 18:30:56 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 37/56] gst/deinterlace2/tvtime/vfir.c: Implement the VFIR deinterlacing method as simple method.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/vfir.c: (deinterlace_line_c),
+	  (deinterlace_line_mmx), (gst_deinterlace_method_vfir_class_init):
+	  Implement the VFIR deinterlacing method as simple method.
+
+2008-08-02 18:18:54 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 36/56] gst/deinterlace2/gstdeinterlace2.*: Add a GstDeinterlaceSimpleMethod subclass of GstDeinterlaceMethod that can be use...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/gstdeinterlace2.c:
+	  (gst_deinterlace_simple_method_interpolate_scanline),
+	  (gst_deinterlace_simple_method_copy_scanline),
+	  (gst_deinterlace_simple_method_deinterlace_frame),
+	  (gst_deinterlace_simple_method_class_init),
+	  (gst_deinterlace_simple_method_init):
+	  * gst/deinterlace2/gstdeinterlace2.h:
+	  Add a GstDeinterlaceSimpleMethod subclass of GstDeinterlaceMethod that
+	  can be used by simple deinterlacing methods. They only have to provide
+	  a function for interpolating a scanline or copying a scanline.
+
+2008-08-02 18:15:49 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 35/56] gst/deinterlace2/gstdeinterlace2.c: Respect the latency of the deinterlacing algorithm for the timestamps of every bu...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/gstdeinterlace2.c: (gst_deinterlace2_chain):
+	  Respect the latency of the deinterlacing algorithm for the timestamps
+	  of every buffer.
+
+2008-08-02 18:13:20 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 34/56] gst/deinterlace2/tvtime/: Add the MMX registers to the clobbered registers only if __MMX__ is defined.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/greedyh.asm:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopBottom.inc:
+	  Add the MMX registers to the clobbered registers only if __MMX__ is
+	  defined.
+
+2008-08-02 18:09:56 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 33/56] gst/deinterlace2/: Enable tomsmocomp again as the C port will be ready for the next release.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/Makefile.am:
+	  * gst/deinterlace2/gstdeinterlace2.c:
+	  (gst_deinterlace2_methods_get_type), (gst_deinterlace2_set_method),
+	  (gst_deinterlace2_class_init):
+	  Enable tomsmocomp again as the C port will be ready for the next
+	  release.
+
+2008-08-02 18:02:44 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 32/56] gst/deinterlace2/gstdeinterlace2.c: Don't use proxy_getcaps() but implement our own getcaps() function that doubles/h...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/gstdeinterlace2.c: (gst_deinterlace2_init),
+	  (gst_greatest_common_divisor), (gst_fraction_double),
+	  (gst_deinterlace2_getcaps), (gst_deinterlace2_setcaps):
+	  Don't use proxy_getcaps() but implement our own getcaps() function
+	  that doubles/halfs the framerate if all fields should be sent out.
+
+2008-07-18 08:34:06 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 31/56] Disable the tomsmocomp algorithm for this release as it's buggy and has no C implementation yet.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/deinterlace2/Makefile.am:
+	  * gst/deinterlace2/gstdeinterlace2.c:
+	  (gst_deinterlace2_methods_get_type), (gst_deinterlace2_set_method),
+	  (gst_deinterlace2_class_init), (gst_deinterlace2_init):
+	  * gst/deinterlace2/gstdeinterlace2.h:
+	  * gst/deinterlace2/tvtime/greedy.c:
+	  (gst_deinterlace_method_greedy_l_class_init):
+	  * gst/deinterlace2/tvtime/greedyh.c:
+	  (gst_deinterlace_method_greedy_h_class_init):
+	  * gst/deinterlace2/tvtime/vfir.c:
+	  (gst_deinterlace_method_vfir_class_init):
+	  Disable the tomsmocomp algorithm for this release as it's buggy
+	  and has no C implementation yet.
+	  Build the deinterlace2 plugin on all architectures but still mark it
+	  as experimental.
+	  Build the x86 inline assembly only if GCC inline assembly is supported
+	  and only on x86 or amd64. Fixes bug #543286.
+
+2008-07-14 14:13:54 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  [MOVED FROM BAD 30/56] gst/deinterlace2/tvtime/: Fix build on x86_64
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/greedy.c:
+	  (gst_deinterlace_method_greedy_l_class_init):
+	  * gst/deinterlace2/tvtime/greedyh.c:
+	  (gst_deinterlace_method_greedy_h_class_init):
+	  * gst/deinterlace2/tvtime/vfir.c:
+	  (gst_deinterlace_method_vfir_class_init):
+	  Fix build on x86_64
+
+2008-07-13 10:56:45 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 29/56] gst/deinterlace2/tvtime/greedyh.asm: Always use the C implementation if width is not a multiple of 4. The assembly op...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/greedyh.asm:
+	  Always use the C implementation if width is not a multiple of 4. The
+	  assembly optimized version only handle this and calling the C
+	  implementation for the remaining part doesn't work because it needs
+	  previous calculations.
+
+2008-07-13 10:52:03 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 28/56] gst/deinterlace2/tvtime/: Some cleanup, use 3DNOW instead of TDNOW in macros.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/greedyh.asm:
+	  * gst/deinterlace2/tvtime/greedyh.c:
+	  * gst/deinterlace2/tvtime/greedyhmacros.h:
+	  Some cleanup, use 3DNOW instead of TDNOW in macros.
+	  * gst/deinterlace2/tvtime/tomsmocomp.c:
+	  (gst_deinterlace_method_tomsmocomp_class_init):
+	  * gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/tomsmocompmacros.h:
+	  The SSE method in fact only needs MMXEXT, declare it as such.
+
+2008-07-08 13:31:37 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 27/56] Don't use declarations after statements in the remaining code.
+	  Original commit message from CVS:
+	  * ext/spc/gstspc.c: (spc_setup):
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopTop.inc:
+	  Don't use declarations after statements in the remaining code.
+
+2008-07-06 20:43:58 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 26/56] gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll2.inc: Mark internal processing functions as static inline for quite ...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll2.inc:
+	  Mark internal processing functions as static inline for quite some
+	  speedup as they're used only once and need to get many local variables
+	  passed as parameter.
+
+2008-07-05 19:20:30 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 25/56] gst/deinterlace2/gstdeinterlace2.*: Call the current instance "self" instead of "object".
+	  Original commit message from CVS:
+	  * gst/deinterlace2/gstdeinterlace2.c:
+	  (gst_deinterlace_method_deinterlace_frame),
+	  (gst_deinterlace2_set_method), (gst_deinterlace2_init),
+	  (gst_deinterlace2_reset_history), (gst_deinterlace2_reset),
+	  (gst_deinterlace2_set_property), (gst_deinterlace2_get_property),
+	  (gst_deinterlace2_pop_history), (gst_deinterlace2_head_history),
+	  (gst_deinterlace2_push_history), (gst_deinterlace2_chain),
+	  (gst_deinterlace2_setcaps), (gst_deinterlace2_sink_event),
+	  (gst_deinterlace2_change_state), (gst_deinterlace2_src_event),
+	  (gst_deinterlace2_src_query):
+	  * gst/deinterlace2/gstdeinterlace2.h:
+	  Call the current instance "self" instead of "object".
+
+2008-07-05 19:11:56 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 24/56] gst/deinterlace2/gstdeinterlace2.*: Include latency of the method in the returned latency.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/gstdeinterlace2.c:
+	  (gst_deinterlace_method_get_latency),
+	  (gst_deinterlace2_set_method), (gst_deinterlace2_class_init),
+	  (gst_deinterlace2_push_history), (gst_deinterlace2_chain),
+	  (gst_deinterlace2_setcaps), (gst_deinterlace2_src_query):
+	  * gst/deinterlace2/gstdeinterlace2.h:
+	  Include latency of the method in the returned latency.
+	  Fix outputting of all fields, i.e. doubling of the framerate.
+
+2008-07-05 16:47:32 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 23/56] gst/deinterlace2/: Use a GstObject subtype for the deinterlacing methods and export the different settings for each d...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/Makefile.am:
+	  * gst/deinterlace2/gstdeinterlace2.c:
+	  (gst_deinterlace_method_class_init), (gst_deinterlace_method_init),
+	  (gst_deinterlace_method_deinterlace_frame),
+	  (gst_deinterlace_method_get_fields_required),
+	  (gst_deinterlace2_methods_get_type), (_do_init),
+	  (gst_deinterlace2_set_method), (gst_deinterlace2_class_init),
+	  (gst_deinterlace2_child_proxy_get_child_by_index),
+	  (gst_deinterlace2_child_proxy_get_children_count),
+	  (gst_deinterlace2_child_proxy_interface_init),
+	  (gst_deinterlace2_init), (gst_deinterlace2_finalize),
+	  (gst_deinterlace2_chain), (gst_deinterlace2_src_query):
+	  * gst/deinterlace2/gstdeinterlace2.h:
+	  * gst/deinterlace2/tvtime/greedy.c:
+	  (deinterlace_greedy_packed422_scanline_c),
+	  (deinterlace_greedy_packed422_scanline_mmx),
+	  (deinterlace_greedy_packed422_scanline_mmxext),
+	  (deinterlace_frame_di_greedy),
+	  (gst_deinterlace_method_greedy_l_set_property),
+	  (gst_deinterlace_method_greedy_l_get_property),
+	  (gst_deinterlace_method_greedy_l_class_init),
+	  (gst_deinterlace_method_greedy_l_init):
+	  * gst/deinterlace2/tvtime/greedyh.asm:
+	  * gst/deinterlace2/tvtime/greedyh.c: (greedyDScaler_C),
+	  (deinterlace_frame_di_greedyh),
+	  (gst_deinterlace_method_greedy_h_set_property),
+	  (gst_deinterlace_method_greedy_h_get_property),
+	  (gst_deinterlace_method_greedy_h_class_init),
+	  (gst_deinterlace_method_greedy_h_init):
+	  * gst/deinterlace2/tvtime/greedyh.h:
+	  * gst/deinterlace2/tvtime/plugins.h:
+	  * gst/deinterlace2/tvtime/tomsmocomp.c:
+	  (gst_deinterlace_method_tomsmocomp_set_property),
+	  (gst_deinterlace_method_tomsmocomp_get_property),
+	  (gst_deinterlace_method_tomsmocomp_class_init),
+	  (gst_deinterlace_method_tomsmocomp_init):
+	  * gst/deinterlace2/tvtime/tomsmocomp.h:
+	  * gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	  * gst/deinterlace2/tvtime/vfir.c: (deinterlace_frame_vfir),
+	  (gst_deinterlace_method_vfir_class_init),
+	  (gst_deinterlace_method_vfir_init):
+	  Use a GstObject subtype for the deinterlacing methods and export
+	  the different settings for each deinterlacing method via GObject
+	  properties.
+	  Implement GstChildProxy interface to allow access to the used
+	  deinterlacing method and to allow adjusting the different settings.
+	  Move global variables of the tomsmocomp deinterlacing method into
+	  function local variables to make it possible to use this deinterlacing
+	  method from different instances.
+
+2008-07-05 12:22:37 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 22/56] gst/deinterlace2/tvtime/greedyh.asm: Support widths that are not a multiply of 4 when using the assembly optimized gr...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/greedyh.asm:
+	  Support widths that are not a multiply of 4 when using the assembly
+	  optimized greedyh implementations.
+
+2008-07-04 18:54:15 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 21/56] gst/deinterlace2/tvtime/greedyh.c: Only build the assembly optimized implementations on x86.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/greedyh.c:
+	  (deinterlace_frame_di_greedyh):
+	  Only build the assembly optimized implementations on x86.
+
+2008-06-30 07:51:07 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 20/56] gst/deinterlace2/: Remove useless file and mark everything possible as static.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/Makefile.am:
+	  * gst/deinterlace2/tvtime/tomsmocomp.c: (tomsmocomp_init),
+	  (tomsmocomp_filter_mmx), (tomsmocomp_filter_3dnow),
+	  (tomsmocomp_filter_sse), (deinterlace_frame_di_tomsmocomp):
+	  * gst/deinterlace2/tvtime/tomsmocomp.h:
+	  Remove useless file and mark everything possible as static.
+	  * gst/deinterlace2/tvtime/greedy.c:
+	  * gst/deinterlace2/tvtime/greedyh.c:
+	  Use "_stdint.h" instead of <stdint.h>.
+
+2008-06-29 10:56:47 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 19/56] gst/deinterlace2/: Get rid of speedy.[ch] as we don't use most of it's code anyway and it doesn't seem to be relicens...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/Makefile.am:
+	  * gst/deinterlace2/gstdeinterlace2.c: (gst_deinterlace2_init):
+	  * gst/deinterlace2/tvtime/greedy.c: (deinterlace_frame_di_greedy):
+	  * gst/deinterlace2/tvtime/greedyh.c:
+	  (deinterlace_frame_di_greedyh):
+	  * gst/deinterlace2/tvtime/speedtools.h:
+	  * gst/deinterlace2/tvtime/speedy.c:
+	  * gst/deinterlace2/tvtime/speedy.h:
+	  * gst/deinterlace2/tvtime/tomsmocomp.c: (Fieldcopy):
+	  * gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	  * gst/deinterlace2/tvtime/vfir.c: (deinterlace_frame_vfir):
+	  Get rid of speedy.[ch] as we don't use most of it's code anyway
+	  and it doesn't seem to be relicensed to LGPL. Use memcpy() instead
+	  of the speedy memcpy everywhere instead.
+	  * gst/deinterlace2/gstdeinterlace2.h:
+	  Remove many unused declarations.
+
+2008-06-28 18:13:08 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 18/56] gst/deinterlace2/gstdeinterlace2.c: Divide latency be 2 to convert from fields to frames.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/gstdeinterlace2.c: (gst_deinterlace2_src_query):
+	  Divide latency be 2 to convert from fields to frames.
+
+2008-06-28 18:10:52 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 17/56] gst/deinterlace2/tvtime/greedy.c: Don't use scanlines function from gstdeinterlace2 as it's not appropiate for this m...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/greedy.c:
+	  (deinterlace_greedy_packed422_scanline_c),
+	  (deinterlace_greedy_packed422_scanline_mmx),
+	  (deinterlace_greedy_packed422_scanline_mmxext),
+	  (deinterlace_frame_di_greedy):
+	  Don't use scanlines function from gstdeinterlace2 as it's
+	  not appropiate for this method. Instead implement deinterlace_frame
+	  function by taking the one from greedyh.
+	  * gst/deinterlace2/tvtime/greedyh.c: (greedyDScaler_C):
+	  Small fix for the C implementation.
+	  * gst/deinterlace2/tvtime/vfir.c: (deinterlace_frame_vfir):
+	  Don't use the scanlines function from gstdeinterlace2 as it's only
+	  used for this method and will be removed. Instead implement
+	  deinterlace_frame function and make it a bit more efficient.
+	  * gst/deinterlace2/gstdeinterlace2.c:
+	  (gst_deinterlace2_class_init), (gst_deinterlace2_set_method),
+	  (gst_deinterlace2_push_history), (gst_deinterlace2_chain),
+	  (gst_deinterlace2_setcaps), (gst_deinterlace2_sink_event),
+	  (gst_deinterlace2_change_state), (gst_deinterlace2_src_event),
+	  (gst_deinterlace2_src_query):
+	  Fix coding style and remove scanlines function as it's unused now.
+
+2008-06-28 17:25:56 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 16/56] gst/deinterlace2/tvtime/: Add a C implementation for the greedyh deinterlacing method, clean up the code a bit and ma...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/greedyh.asm:
+	  * gst/deinterlace2/tvtime/greedyh.c: (greedyDScaler_C),
+	  (deinterlace_frame_di_greedyh), (dscaler_greedyh_get_method):
+	  * gst/deinterlace2/tvtime/greedyhmacros.h:
+	  Add a C implementation for the greedyh deinterlacing method, clean
+	  up the code a bit and mark the SSE version as MMXEXT as it doesn't
+	  require any SSE instructions.
+
+2008-06-27 13:22:34 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 15/56] gst/deinterlace2/gstdeinterlace2.c: If we're outputting all fields the framerate has to be doubled.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/gstdeinterlace2.c:
+	  (gst_deinterlace2_set_property), (gst_deinterlace2_chain),
+	  (gst_deinterlace2_setcaps):
+	  If we're outputting all fields the framerate has to be doubled.
+	  Set duration on the outgoing buffers.
+
+2008-06-25 16:05:08 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  [MOVED FROM BAD 14/56] gst/deinterlace2/tvtime/tomsmocomp/tomsmocompmacros.h: Remove unneeded macros that break build on macosx.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/tomsmocomp/tomsmocompmacros.h:
+	  Remove unneeded macros that break build on macosx.
+
+2008-06-24 12:08:47 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 13/56] gst/deinterlace2/tvtime/greedy.c: Optimize MMX/MMXEXT implementations a bit by requiring two less memory accesses and...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/greedy.c:
+	  (deinterlace_greedy_packed422_scanline_mmx),
+	  (deinterlace_greedy_packed422_scanline_mmxext):
+	  Optimize MMX/MMXEXT implementations a bit by requiring two less
+	  memory accesses and fix the workaround for the missing right shift
+	  on bytes to unset the highest bit of every byte.
+
+2008-06-24 10:15:41 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 12/56] gst/deinterlace2/tvtime/greedy.c: Remove sfence instruction as it's not needed and actually is an SSE instruction.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/greedy.c:
+	  (deinterlace_greedy_packed422_scanline_mmxext):
+	  Remove sfence instruction as it's not needed and actually is an SSE
+	  instruction.
+
+2008-06-24 10:12:08 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 11/56] gst/deinterlace2/tvtime/greedy.c: Add plain MMX implementation for the greedyl method.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/greedy.c:
+	  (deinterlace_greedy_packed422_scanline_mmx),
+	  (deinterlace_greedy_packed422_scanline):
+	  Add plain MMX implementation for the greedyl method.
+
+2008-06-24 09:40:03 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 10/56] gst/deinterlace2/Makefile.am: Move the assembly includes to noinst_HEADERS where they belong.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/Makefile.am:
+	  Move the assembly includes to noinst_HEADERS where they belong.
+	  * gst/deinterlace2/tvtime/vfir.c: (deinterlace_line_c),
+	  (deinterlace_line_mmx):
+	  Fix C and MMX implementations a bit more.
+
+2008-06-24 09:10:46 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 09/56] gst/deinterlace2/tvtime/greedy.c: Fix the C implementation to produce correct results and optimize the
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/greedy.c:
+	  (deinterlace_greedy_packed422_scanline_c),
+	  (deinterlace_greedy_packed422_scanline_mmxext),
+	  (deinterlace_greedy_packed422_scanline):
+	  Fix the C implementation to produce correct results and optimize the
+	  MMXEXT implementation.
+	  Handle odd widths and don't read over array boundaries in the MMXEXT
+	  implementation.
+	  * gst/deinterlace2/tvtime/vfir.c: (deinterlace_line_c),
+	  (deinterlace_line_mmx), (deinterlace_scanline_vfir):
+	  Fix a small rounding bug in the MMX implementation, the MMX
+	  implementation doesn't actually need MMXEXT instructions so don't mark
+	  it as such.
+	  Handle odd widths in both implementations.
+
+2008-06-21 09:05:00 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 08/56] gst/deinterlace2/tvtime/greedy.c: Implement a C version of the greedy low motion algorithm and mark the assembly opti...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/greedy.c:
+	  (deinterlace_greedy_packed422_scanline_sse),
+	  (deinterlace_greedy_packed422_scanline_c),
+	  (deinterlace_greedy_packed422_scanline):
+	  Implement a C version of the greedy low motion algorithm and mark the
+	  assembly optimized version as SSE as it uses SSE instructions
+	  additional to MMX instructions.
+
+2008-06-20 14:48:40 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 07/56] gst/deinterlace2/tvtime/vfir.c: Make it possible to use the vfir method on X86 CPUs without MMXEXT too but use the MM...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/vfir.c: (deinterlace_line_mmxext),
+	  (deinterlace_line_c), (deinterlace_scanline_vfir):
+	  Make it possible to use the vfir method on X86 CPUs without MMXEXT too
+	  but use the MMXEXT optimized code whenever possible.
+
+2008-06-20 14:35:25 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 06/56] gst/deinterlace2/gstdeinterlace2.*: Reset element state on PAUSED->READY properly, don't leak any buffers when finali...
+	  Original commit message from CVS:
+	  * gst/deinterlace2/gstdeinterlace2.c:
+	  (gst_deinterlace2_class_init), (gst_deinterlace2_init),
+	  (gst_deinterlace2_reset_history), (gst_deinterlace2_reset),
+	  (gst_deinterlace2_finalize), (gst_deinterlace2_chain),
+	  (gst_deinterlace2_sink_event), (gst_deinterlace2_change_state),
+	  (gst_deinterlace2_src_query):
+	  * gst/deinterlace2/gstdeinterlace2.h:
+	  Reset element state on PAUSED->READY properly, don't leak any buffers
+	  when finalizing, allocate buffers with gst_pad_alloc_buffer() and
+	  properly return flow returns from gst_pad_push() instead of ignoring them.
+
+2008-06-20 13:45:08 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 05/56] gst/deinterlace2/tvtime/tomsmocomp/tomsmocompmacros.h: Add missing header.
+	  Original commit message from CVS:
+	  * gst/deinterlace2/tvtime/tomsmocomp/tomsmocompmacros.h:
+	  Add missing header.
+
+2008-06-20 13:24:29 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 04/56] Fix compilation on generic x86/amd64 and include deinterlace2 in the build system. Because of several bugs it's still...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/deinterlace2/Makefile.am:
+	  * gst/deinterlace2/tvtime/greedyh.asm:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopBottom.inc:
+	  Fix compilation on generic x86/amd64 and include deinterlace2 in the
+	  build system. Because of several bugs it's still enabled only
+	  by --enable-experimental.
+
+2008-06-18 06:31:13 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  [MOVED FROM BAD 03/56] Fix gtk-doc warnings. Also don't misuse api-doc comments for normal comments.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * examples/app/appsrc-ra.c:
+	  * examples/app/appsrc-seekable.c:
+	  * examples/app/appsrc-stream.c:
+	  * examples/app/appsrc-stream2.c:
+	  * ext/directfb/dfbvideosink.h:
+	  * ext/metadata/gstbasemetadata.c:
+	  * ext/metadata/gstbasemetadata.h:
+	  * ext/metadata/metadata.c:
+	  * ext/metadata/metadataexif.c:
+	  * ext/theora/theoradec.h:
+	  * gst/deinterlace2/gstdeinterlace2.h:
+	  * gst/deinterlace2/tvtime/speedy.c:
+	  * gst/deinterlace2/tvtime/speedy.h:
+	  * gst/deinterlace2/tvtime/vfir.c:
+	  Fix gtk-doc warnings. Also don't misuse api-doc comments for normal
+	  comments.
+
+2008-06-11 11:12:49 +0000  Martin Eikermann <meiker@upb.de>
+
+	  [MOVED FROM BAD 02/56] gst/deinterlace2/: Add a deinterlacer plugin based on the tvtime/DScaler deinterlacer, which was relicensed to LGPL f...
+	  Original commit message from CVS:
+	  Based on a patch by: Martin Eikermann <meiker at upb dot de>
+	  * gst/deinterlace2/Makefile.am:
+	  * gst/deinterlace2/gstdeinterlace2.c:
+	  (gst_deinterlace2_method_get_type),
+	  (gst_deinterlace2_fields_get_type),
+	  (gst_deinterlace2_field_layout_get_type),
+	  (gst_deinterlace2_base_init), (gst_deinterlace2_class_init),
+	  (gst_deinterlace2_init), (gst_deinterlace2_set_method),
+	  (gst_deinterlace2_set_property), (gst_deinterlace2_get_property),
+	  (gst_deinterlace2_finalize), (gst_deinterlace2_pop_history),
+	  (gst_deinterlace2_head_history), (gst_deinterlace2_push_history),
+	  (gst_deinterlace2_deinterlace_scanlines), (gst_deinterlace2_chain),
+	  (gst_deinterlace2_setcaps), (gst_deinterlace2_sink_event),
+	  (gst_deinterlace2_change_state), (gst_deinterlace2_src_event),
+	  (gst_deinterlace2_src_query), (gst_deinterlace2_src_query_types),
+	  (plugin_init):
+	  * gst/deinterlace2/gstdeinterlace2.h:
+	  * gst/deinterlace2/tvtime/greedy.c: (copy_scanline),
+	  (deinterlace_greedy_packed422_scanline_mmxext),
+	  (dscaler_greedyl_get_method):
+	  * gst/deinterlace2/tvtime/greedyh.asm:
+	  * gst/deinterlace2/tvtime/greedyh.c:
+	  (deinterlace_frame_di_greedyh), (dscaler_greedyh_get_method),
+	  (greedyh_init), (greedyh_filter_mmx), (greedyh_filter_3dnow),
+	  (greedyh_filter_sse):
+	  * gst/deinterlace2/tvtime/greedyh.h:
+	  * gst/deinterlace2/tvtime/greedyhmacros.h:
+	  * gst/deinterlace2/tvtime/mmx.h:
+	  * gst/deinterlace2/tvtime/plugins.h:
+	  * gst/deinterlace2/tvtime/speedtools.h:
+	  * gst/deinterlace2/tvtime/speedy.c: (multiply_alpha), (clip255),
+	  (comb_factor_packed422_scanline_mmx),
+	  (diff_factor_packed422_scanline_c),
+	  (diff_factor_packed422_scanline_mmx),
+	  (diff_packed422_block8x8_mmx), (diff_packed422_block8x8_c),
+	  (packed444_to_packed422_scanline_c),
+	  (packed422_to_packed444_scanline_c),
+	  (packed422_to_packed444_rec601_scanline_c),
+	  (vfilter_chroma_121_packed422_scanline_mmx),
+	  (vfilter_chroma_121_packed422_scanline_c),
+	  (vfilter_chroma_332_packed422_scanline_mmx),
+	  (vfilter_chroma_332_packed422_scanline_c),
+	  (kill_chroma_packed422_inplace_scanline_mmx),
+	  (kill_chroma_packed422_inplace_scanline_c),
+	  (invert_colour_packed422_inplace_scanline_mmx),
+	  (invert_colour_packed422_inplace_scanline_c),
+	  (mirror_packed422_inplace_scanline_c),
+	  (interpolate_packed422_scanline_c),
+	  (convert_uyvy_to_yuyv_scanline_mmx),
+	  (convert_uyvy_to_yuyv_scanline_c),
+	  (interpolate_packed422_scanline_mmx),
+	  (interpolate_packed422_scanline_mmxext),
+	  (blit_colour_packed422_scanline_c),
+	  (blit_colour_packed422_scanline_mmx),
+	  (blit_colour_packed422_scanline_mmxext),
+	  (blit_colour_packed4444_scanline_c),
+	  (blit_colour_packed4444_scanline_mmx),
+	  (blit_colour_packed4444_scanline_mmxext), (small_memcpy),
+	  (speedy_memcpy_c), (speedy_memcpy_mmx), (speedy_memcpy_mmxext),
+	  (blit_packed422_scanline_c), (blit_packed422_scanline_mmx),
+	  (blit_packed422_scanline_mmxext),
+	  (composite_colour4444_alpha_to_packed422_scanline_c),
+	  (composite_colour4444_alpha_to_packed422_scanline_mmxext),
+	  (composite_packed4444_alpha_to_packed422_scanline_c),
+	  (composite_packed4444_alpha_to_packed422_scanline_mmxext),
+	  (composite_packed4444_to_packed422_scanline_c),
+	  (composite_packed4444_to_packed422_scanline_mmxext),
+	  (composite_alphamask_to_packed4444_scanline_c),
+	  (composite_alphamask_to_packed4444_scanline_mmxext),
+	  (composite_alphamask_alpha_to_packed4444_scanline_c),
+	  (premultiply_packed4444_scanline_c),
+	  (premultiply_packed4444_scanline_mmxext),
+	  (blend_packed422_scanline_c), (blend_packed422_scanline_mmxext),
+	  (quarter_blit_vertical_packed422_scanline_mmxext),
+	  (quarter_blit_vertical_packed422_scanline_c),
+	  (subpix_blit_vertical_packed422_scanline_c),
+	  (a8_subpix_blit_scanline_c), (myround), (init_RGB_to_YCbCr_tables),
+	  (init_YCbCr_to_RGB_tables), (rgb24_to_packed444_rec601_scanline_c),
+	  (rgba32_to_packed4444_rec601_scanline_c),
+	  (packed444_to_rgb24_rec601_scanline_c),
+	  (packed444_to_nonpremultiplied_packed4444_scanline_c),
+	  (aspect_adjust_packed4444_scanline_c), (setup_speedy_calls),
+	  (speedy_get_accel):
+	  * gst/deinterlace2/tvtime/speedy.h:
+	  * gst/deinterlace2/tvtime/sse.h:
+	  * gst/deinterlace2/tvtime/tomsmocomp.c: (Fieldcopy),
+	  (deinterlace_frame_di_tomsmocomp), (dscaler_tomsmocomp_get_method),
+	  (tomsmocomp_init), (tomsmocomp_filter_mmx),
+	  (tomsmocomp_filter_3dnow), (tomsmocomp_filter_sse):
+	  * gst/deinterlace2/tvtime/tomsmocomp.h:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoop0A.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopBottom.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA8.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA2.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA6.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH2.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopTop.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVA.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVAH.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/StrangeBob.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll2.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/WierdBob.inc:
+	  * gst/deinterlace2/tvtime/vfir.c: (deinterlace_line),
+	  (deinterlace_scanline_vfir), (copy_scanline),
+	  (dscaler_vfir_get_method):
+	  * gst/deinterlace2/tvtime/x86-64_macros.inc:
+	  Add a deinterlacer plugin based on the tvtime/DScaler deinterlacer,
+	  which was relicensed to LGPL for GStreamer and in theory provides
+	  better and faster results than the simple deinterlace element.
+	  Fixes bug #163578.
+	  Ported to GStreamer 0.10 but still not enabled or included in the
+	  build system by default because of bad artefacts caused by a bug
+	  somewhere and as it can be only build on x86/amd64 ATM and requires
+	  special CFLAGS. Will be fixed soon.
+
+2008-06-11 11:12:14 +0000  Martin Eikermann <meiker@upb.de>
+
+	  [MOVED FROM BAD 01/56] gst/deinterlace2/: Add a deinterlacer plugin based on the tvtime/DScaler deinterlacer, which was relicensed to LGPL f...
+	  Original commit message from CVS:
+	  Based on a patch by: Martin Eikermann <meiker at upb dot de>
+	  * gst/deinterlace2/Makefile.am:
+	  * gst/deinterlace2/gstdeinterlace2.c:
+	  (gst_deinterlace2_method_get_type),
+	  (gst_deinterlace2_fields_get_type),
+	  (gst_deinterlace2_field_layout_get_type),
+	  (gst_deinterlace2_base_init), (gst_deinterlace2_class_init),
+	  (gst_deinterlace2_init), (gst_deinterlace2_set_method),
+	  (gst_deinterlace2_set_property), (gst_deinterlace2_get_property),
+	  (gst_deinterlace2_finalize), (gst_deinterlace2_pop_history),
+	  (gst_deinterlace2_head_history), (gst_deinterlace2_push_history),
+	  (gst_deinterlace2_deinterlace_scanlines), (gst_deinterlace2_chain),
+	  (gst_deinterlace2_setcaps), (gst_deinterlace2_sink_event),
+	  (gst_deinterlace2_change_state), (gst_deinterlace2_src_event),
+	  (gst_deinterlace2_src_query), (gst_deinterlace2_src_query_types),
+	  (plugin_init):
+	  * gst/deinterlace2/gstdeinterlace2.h:
+	  * gst/deinterlace2/tvtime/greedy.c: (copy_scanline),
+	  (deinterlace_greedy_packed422_scanline_mmxext),
+	  (dscaler_greedyl_get_method):
+	  * gst/deinterlace2/tvtime/greedyh.asm:
+	  * gst/deinterlace2/tvtime/greedyh.c:
+	  (deinterlace_frame_di_greedyh), (dscaler_greedyh_get_method),
+	  (greedyh_init), (greedyh_filter_mmx), (greedyh_filter_3dnow),
+	  (greedyh_filter_sse):
+	  * gst/deinterlace2/tvtime/greedyh.h:
+	  * gst/deinterlace2/tvtime/greedyhmacros.h:
+	  * gst/deinterlace2/tvtime/mmx.h:
+	  * gst/deinterlace2/tvtime/plugins.h:
+	  * gst/deinterlace2/tvtime/speedtools.h:
+	  * gst/deinterlace2/tvtime/speedy.c: (multiply_alpha), (clip255),
+	  (comb_factor_packed422_scanline_mmx),
+	  (diff_factor_packed422_scanline_c),
+	  (diff_factor_packed422_scanline_mmx),
+	  (diff_packed422_block8x8_mmx), (diff_packed422_block8x8_c),
+	  (packed444_to_packed422_scanline_c),
+	  (packed422_to_packed444_scanline_c),
+	  (packed422_to_packed444_rec601_scanline_c),
+	  (vfilter_chroma_121_packed422_scanline_mmx),
+	  (vfilter_chroma_121_packed422_scanline_c),
+	  (vfilter_chroma_332_packed422_scanline_mmx),
+	  (vfilter_chroma_332_packed422_scanline_c),
+	  (kill_chroma_packed422_inplace_scanline_mmx),
+	  (kill_chroma_packed422_inplace_scanline_c),
+	  (invert_colour_packed422_inplace_scanline_mmx),
+	  (invert_colour_packed422_inplace_scanline_c),
+	  (mirror_packed422_inplace_scanline_c),
+	  (interpolate_packed422_scanline_c),
+	  (convert_uyvy_to_yuyv_scanline_mmx),
+	  (convert_uyvy_to_yuyv_scanline_c),
+	  (interpolate_packed422_scanline_mmx),
+	  (interpolate_packed422_scanline_mmxext),
+	  (blit_colour_packed422_scanline_c),
+	  (blit_colour_packed422_scanline_mmx),
+	  (blit_colour_packed422_scanline_mmxext),
+	  (blit_colour_packed4444_scanline_c),
+	  (blit_colour_packed4444_scanline_mmx),
+	  (blit_colour_packed4444_scanline_mmxext), (small_memcpy),
+	  (speedy_memcpy_c), (speedy_memcpy_mmx), (speedy_memcpy_mmxext),
+	  (blit_packed422_scanline_c), (blit_packed422_scanline_mmx),
+	  (blit_packed422_scanline_mmxext),
+	  (composite_colour4444_alpha_to_packed422_scanline_c),
+	  (composite_colour4444_alpha_to_packed422_scanline_mmxext),
+	  (composite_packed4444_alpha_to_packed422_scanline_c),
+	  (composite_packed4444_alpha_to_packed422_scanline_mmxext),
+	  (composite_packed4444_to_packed422_scanline_c),
+	  (composite_packed4444_to_packed422_scanline_mmxext),
+	  (composite_alphamask_to_packed4444_scanline_c),
+	  (composite_alphamask_to_packed4444_scanline_mmxext),
+	  (composite_alphamask_alpha_to_packed4444_scanline_c),
+	  (premultiply_packed4444_scanline_c),
+	  (premultiply_packed4444_scanline_mmxext),
+	  (blend_packed422_scanline_c), (blend_packed422_scanline_mmxext),
+	  (quarter_blit_vertical_packed422_scanline_mmxext),
+	  (quarter_blit_vertical_packed422_scanline_c),
+	  (subpix_blit_vertical_packed422_scanline_c),
+	  (a8_subpix_blit_scanline_c), (myround), (init_RGB_to_YCbCr_tables),
+	  (init_YCbCr_to_RGB_tables), (rgb24_to_packed444_rec601_scanline_c),
+	  (rgba32_to_packed4444_rec601_scanline_c),
+	  (packed444_to_rgb24_rec601_scanline_c),
+	  (packed444_to_nonpremultiplied_packed4444_scanline_c),
+	  (aspect_adjust_packed4444_scanline_c), (setup_speedy_calls),
+	  (speedy_get_accel):
+	  * gst/deinterlace2/tvtime/speedy.h:
+	  * gst/deinterlace2/tvtime/sse.h:
+	  * gst/deinterlace2/tvtime/tomsmocomp.c: (Fieldcopy),
+	  (deinterlace_frame_di_tomsmocomp), (dscaler_tomsmocomp_get_method),
+	  (tomsmocomp_init), (tomsmocomp_filter_mmx),
+	  (tomsmocomp_filter_3dnow), (tomsmocomp_filter_sse):
+	  * gst/deinterlace2/tvtime/tomsmocomp.h:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoop0A.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopBottom.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA8.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA2.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA6.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH2.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopTop.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVA.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVAH.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/StrangeBob.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll2.inc:
+	  * gst/deinterlace2/tvtime/tomsmocomp/WierdBob.inc:
+	  * gst/deinterlace2/tvtime/vfir.c: (deinterlace_line),
+	  (deinterlace_scanline_vfir), (copy_scanline),
+	  (dscaler_vfir_get_method):
+	  * gst/deinterlace2/tvtime/x86-64_macros.inc:
+	  Add a deinterlacer plugin based on the tvtime/DScaler deinterlacer,
+	  which was relicensed to LGPL for GStreamer and in theory provides
+	  better and faster results than the simple deinterlace element.
+	  Fixes bug #163578.
+	  Ported to GStreamer 0.10 but still not enabled or included in the
+	  build system by default because of bad artefacts caused by a bug
+	  somewhere and as it can be only build on x86/amd64 ATM and requires
+	  special CFLAGS. Will be fixed soon.
+
+2009-05-13 10:30:35 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  flv: Actually add the flv plugin to configure.ac
+
+2009-05-13 09:24:26 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/pipelines/flacdec.c:
+	  checks: fix flacdec unit tests on big-endian machines and under valgrind
+	  Flacdec outputs 16-bit samples, so let's check if the value of the first
+	  sample is what we expect rather than just the first byte, which may be
+	  different from what we expect depending on the host's endianness. Fixes
+	  the flacdec unit tests on PPC. Also fix a bunch of leaks in the unit
+	  tests to make valgrind happy. Fixes #582420.
+
+2009-05-13 09:18:07 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: fix buffer leak
+	  gst_buffer_replace() will take its own ref, so we still have
+	  to unref the buffer if we don't need it any longer.
+
+2009-05-12 21:20:04 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Fix pointer arithmetic
+	  This fixes a seeking regression, bug #134522.
+
+2009-05-12 21:36:31 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flv.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	  Moved 'flv' from -bad to -good
+
+2009-05-07 17:53:42 +0100  Christian Schaller <christian.schaller@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	  [MOVED FROM BAD 57/57] Add ranks to various muxers and encoders in -bad
+
+2009-04-29 18:52:20 +0100  Tristan Matthews <le.businessman@gmail.com>
+
+	* gst/flv/gstflvmux.c:
+	  [MOVED FROM BAD 56/57] flvmux: init variable to NULL to fix compiler warning
+	  Fixes #580786.
+
+2009-04-29 13:56:07 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvparse.c:
+	  [MOVED FROM BAD 55/57] flv: Set/require the framed/parsed fields of the audio/mpeg caps to TRUE
+
+2009-04-29 13:16:25 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	  [MOVED FROM BAD 54/57] flv: Always write at least the minimal tags and write the PAR as tags
+
+2009-04-29 13:03:46 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  [MOVED FROM BAD 53/57] flv: Add support for muxing some tags
+
+2009-04-29 13:03:27 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvparse.c:
+	  [MOVED FROM BAD 52/57] flv: Add support for title tag
+
+2009-04-29 09:40:41 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvparse.c:
+	  [MOVED FROM BAD 51/57] flv: Fix parsing of tags and add new mappings
+	  We shouldn't register a new GstTag for every unknown tag
+	  we find as this might lead to conflicts and also those
+	  tags are essentially unknown.
+	  Add mappings for some known tags and also convert string
+	  dates to GDate, as found in many FLV files.
+
+2009-04-22 19:52:05 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/flv/gstflvdemux.c:
+	* gst/flv/gstflvdemux.h:
+	* gst/flv/gstflvmux.c:
+	* gst/flv/gstflvmux.h:
+	  [MOVED FROM BAD 50/57] flv: Add documentation to flvmux and flvdemux
+	  Partially fixes bug #573737.
+
+2009-01-22 13:39:34 +0100  Jan Urbanski <j.urbanski@students.mimuw.edu.pl>
+
+	* gst/flv/gstflvparse.c:
+	  [MOVED FROM BAD 49/57] Add support for ECMA arrays in script tags. Fixes bug #567965.
+	  Add support for ECMA arrays in script tags. This fixes
+	  seeking on some files that have the seek table stored
+	  inside an ECMA array instead of the normal array.
+
+2008-12-03 11:43:00 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 48/57] gst/flv/gstflvparse.c: Check if strings are valid UTF8 before using them.
+	  Original commit message from CVS:
+	  * gst/flv/gstflvparse.c: (FLV_GET_STRING):
+	  Check if strings are valid UTF8 before using them.
+
+2008-11-24 11:17:19 +0000  Julien Moutte <julien@moutte.net>
+
+	  [MOVED FROM BAD 47/57] gst/flv/gstflvdemux.c: Fix non key unit seeking by always going to the previous keyframe. Mark the discont flag when ...
+	  Original commit message from CVS:
+	  2008-11-24  Julien Moutte  <julien@fluendo.com>
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_find_offset),
+	  (gst_flv_demux_handle_seek_push),
+	  (gst_flv_demux_handle_seek_pull):
+	  Fix non key unit seeking by always going to the previous
+	  keyframe. Mark
+	  the discont flag when we've moved in the file.
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_audio_negotiate): MP3
+	  streams
+	  are parsed already, makes autoplugged pipelines shorter.
+
+2008-11-04 12:42:30 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  [MOVED FROM BAD 46/57] Don't install static libs for plugins. Fixes #550851 for -bad.
+	  Original commit message from CVS:
+	  * ext/alsaspdif/Makefile.am:
+	  * ext/amrwb/Makefile.am:
+	  * ext/apexsink/Makefile.am:
+	  * ext/arts/Makefile.am:
+	  * ext/artsd/Makefile.am:
+	  * ext/audiofile/Makefile.am:
+	  * ext/audioresample/Makefile.am:
+	  * ext/bz2/Makefile.am:
+	  * ext/cdaudio/Makefile.am:
+	  * ext/celt/Makefile.am:
+	  * ext/dc1394/Makefile.am:
+	  * ext/dirac/Makefile.am:
+	  * ext/directfb/Makefile.am:
+	  * ext/divx/Makefile.am:
+	  * ext/dts/Makefile.am:
+	  * ext/faac/Makefile.am:
+	  * ext/faad/Makefile.am:
+	  * ext/gsm/Makefile.am:
+	  * ext/hermes/Makefile.am:
+	  * ext/ivorbis/Makefile.am:
+	  * ext/jack/Makefile.am:
+	  * ext/jp2k/Makefile.am:
+	  * ext/ladspa/Makefile.am:
+	  * ext/lcs/Makefile.am:
+	  * ext/libfame/Makefile.am:
+	  * ext/libmms/Makefile.am:
+	  * ext/metadata/Makefile.am:
+	  * ext/mpeg2enc/Makefile.am:
+	  * ext/mplex/Makefile.am:
+	  * ext/musepack/Makefile.am:
+	  * ext/musicbrainz/Makefile.am:
+	  * ext/mythtv/Makefile.am:
+	  * ext/nas/Makefile.am:
+	  * ext/neon/Makefile.am:
+	  * ext/ofa/Makefile.am:
+	  * ext/polyp/Makefile.am:
+	  * ext/resindvd/Makefile.am:
+	  * ext/sdl/Makefile.am:
+	  * ext/shout/Makefile.am:
+	  * ext/snapshot/Makefile.am:
+	  * ext/sndfile/Makefile.am:
+	  * ext/soundtouch/Makefile.am:
+	  * ext/spc/Makefile.am:
+	  * ext/swfdec/Makefile.am:
+	  * ext/tarkin/Makefile.am:
+	  * ext/theora/Makefile.am:
+	  * ext/timidity/Makefile.am:
+	  * ext/twolame/Makefile.am:
+	  * ext/x264/Makefile.am:
+	  * ext/xine/Makefile.am:
+	  * ext/xvid/Makefile.am:
+	  * gst-libs/gst/app/Makefile.am:
+	  * gst-libs/gst/dshow/Makefile.am:
+	  * gst/aiffparse/Makefile.am:
+	  * gst/app/Makefile.am:
+	  * gst/audiobuffer/Makefile.am:
+	  * gst/bayer/Makefile.am:
+	  * gst/cdxaparse/Makefile.am:
+	  * gst/chart/Makefile.am:
+	  * gst/colorspace/Makefile.am:
+	  * gst/dccp/Makefile.am:
+	  * gst/deinterlace/Makefile.am:
+	  * gst/deinterlace2/Makefile.am:
+	  * gst/dvdspu/Makefile.am:
+	  * gst/festival/Makefile.am:
+	  * gst/filter/Makefile.am:
+	  * gst/flacparse/Makefile.am:
+	  * gst/flv/Makefile.am:
+	  * gst/games/Makefile.am:
+	  * gst/h264parse/Makefile.am:
+	  * gst/librfb/Makefile.am:
+	  * gst/mixmatrix/Makefile.am:
+	  * gst/modplug/Makefile.am:
+	  * gst/mpeg1sys/Makefile.am:
+	  * gst/mpeg4videoparse/Makefile.am:
+	  * gst/mpegdemux/Makefile.am:
+	  * gst/mpegtsmux/Makefile.am:
+	  * gst/mpegvideoparse/Makefile.am:
+	  * gst/mve/Makefile.am:
+	  * gst/nsf/Makefile.am:
+	  * gst/nuvdemux/Makefile.am:
+	  * gst/overlay/Makefile.am:
+	  * gst/passthrough/Makefile.am:
+	  * gst/pcapparse/Makefile.am:
+	  * gst/playondemand/Makefile.am:
+	  * gst/rawparse/Makefile.am:
+	  * gst/real/Makefile.am:
+	  * gst/rtjpeg/Makefile.am:
+	  * gst/rtpmanager/Makefile.am:
+	  * gst/scaletempo/Makefile.am:
+	  * gst/sdp/Makefile.am:
+	  * gst/selector/Makefile.am:
+	  * gst/smooth/Makefile.am:
+	  * gst/smoothwave/Makefile.am:
+	  * gst/speed/Makefile.am:
+	  * gst/speexresample/Makefile.am:
+	  * gst/stereo/Makefile.am:
+	  * gst/subenc/Makefile.am:
+	  * gst/tta/Makefile.am:
+	  * gst/vbidec/Makefile.am:
+	  * gst/videodrop/Makefile.am:
+	  * gst/videosignal/Makefile.am:
+	  * gst/virtualdub/Makefile.am:
+	  * gst/vmnc/Makefile.am:
+	  * gst/y4m/Makefile.am:
+	  * sys/acmenc/Makefile.am:
+	  * sys/cdrom/Makefile.am:
+	  * sys/dshowdecwrapper/Makefile.am:
+	  * sys/dshowsrcwrapper/Makefile.am:
+	  * sys/dvb/Makefile.am:
+	  * sys/dxr3/Makefile.am:
+	  * sys/fbdev/Makefile.am:
+	  * sys/oss4/Makefile.am:
+	  * sys/qcam/Makefile.am:
+	  * sys/qtwrapper/Makefile.am:
+	  * sys/vcd/Makefile.am:
+	  * sys/wininet/Makefile.am:
+	  * win32/common/config.h:
+	  Don't install static libs for plugins. Fixes #550851 for -bad.
+
+2008-10-28 18:44:44 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 45/57] gst/flv/gstflvdemux.c: Implement position query in time format.
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_query):
+	  Implement position query in time format.
+
+2008-10-28 18:41:19 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 44/57] gst/flv/: Put the GstSegment directly into the instance struct instead of allocating and free'ing it again.
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_cleanup),
+	  (gst_flv_demux_loop), (gst_flv_demux_handle_seek_push),
+	  (gst_flv_demux_handle_seek_pull), (gst_flv_demux_sink_event),
+	  (gst_flv_demux_dispose), (gst_flv_demux_init):
+	  * gst/flv/gstflvdemux.h:
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_tag_audio),
+	  (gst_flv_parse_tag_video), (gst_flv_parse_tag_timestamp):
+	  Put the GstSegment directly into the instance struct instead of
+	  allocating and free'ing it again.
+	  Push tags already if only one pad was added, no need to wait for
+	  the second one.
+	  When generating our index set has_video and has_audio if we find
+	  video or audio in case the FLV header has incorrect data.
+
+2008-10-27 09:45:04 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 43/57] gst/flv/: Don't memcpy() all data we want to push downstream, instead just create subbuffers and push them downstream.
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_chain),
+	  (gst_flv_demux_pull_tag), (gst_flv_demux_pull_header),
+	  (gst_flv_demux_create_index):
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_tag_script),
+	  (gst_flv_parse_tag_audio), (gst_flv_parse_tag_video),
+	  (gst_flv_parse_tag_timestamp), (gst_flv_parse_tag_type),
+	  (gst_flv_parse_header):
+	  * gst/flv/gstflvparse.h:
+	  Don't memcpy() all data we want to push downstream, instead just
+	  create subbuffers and push them downstream.
+	  Fix some minor memory leaks.
+
+2008-10-27 09:41:18 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 42/57] gst/flv/Makefile.am: Fix (non-critical) syntax error and add all required CFLAGS and LIBS.
+	  Original commit message from CVS:
+	  * gst/flv/Makefile.am:
+	  Fix (non-critical) syntax error and add all required CFLAGS and LIBS.
+	  * gst/flv/gstflvparse.c: (FLV_GET_STRING),
+	  (gst_flv_parse_metadata_item), (gst_flv_parse_tag_script),
+	  (gst_flv_parse_tag_audio), (gst_flv_parse_tag_video),
+	  (gst_flv_parse_tag_timestamp), (gst_flv_parse_tag_type):
+	  Rewrite the script tag parsing to make sure we don't try to read
+	  more data than we have. Also use GST_READ_UINT24_BE directly and
+	  fix some minor memory leaks.
+	  This should make all crashes on fuzzed FLV files disappear.
+
+2008-10-27 09:37:21 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 41/57] gst/flv/gstflvparse.c: Properly check everywhere that we have enough data to parse and don't read outside the allocat...
+	  Original commit message from CVS:
+	  * gst/flv/gstflvparse.c: (FLV_GET_STRING),
+	  (gst_flv_parse_tag_audio), (gst_flv_parse_tag_video),
+	  (gst_flv_parse_tag_type), (gst_flv_parse_header):
+	  Properly check everywhere that we have enough data to parse and
+	  don't read outside the allocated memory region.
+
+2008-10-27 09:35:34 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 40/57] gst/flv/gstflvparse.c: If the caps change during playback and negotiation fails error out instead of trying to continue.
+	  Original commit message from CVS:
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_tag_audio),
+	  (gst_flv_parse_tag_video):
+	  If the caps change during playback and negotiation fails error out
+	  instead of trying to continue.
+
+2008-10-27 09:33:40 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 39/57] gst/flv/: Add support for Speex audio and allow buffers without valid timestamp in the muxer.
+	  Original commit message from CVS:
+	  * gst/flv/gstflvmux.c: (gst_flv_mux_audio_pad_setcaps),
+	  (gst_flv_mux_request_new_pad), (gst_flv_mux_write_buffer),
+	  (gst_flv_mux_collected):
+	  * gst/flv/gstflvmux.h:
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_audio_negotiate):
+	  Add support for Speex audio and allow buffers without valid
+	  timestamp in the muxer.
+
+2008-10-27 09:32:03 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 38/57] gst/flv/gstflvdemux.c: Don't post an error message on the bus if sending EOS downstream didn't work. Fixes bug #550454.
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_loop),
+	  (gst_flv_demux_find_offset), (gst_flv_demux_handle_seek_push),
+	  (gst_flv_demux_handle_seek_pull):
+	  Don't post an error message on the bus if sending EOS downstream
+	  didn't work. Fixes bug #550454.
+	  Fix seek event handling to look at the flags of the seek event
+	  instead of assuming some random flags, don't send segment-start
+	  messages when operating in push mode and push seek events upstream
+	  if we couldn't handle them.
+
+2008-10-27 09:27:18 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 37/57] gst/flv/gstflvdemux.c: Error out early if pulling a tag failed.
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_pull_tag):
+	  Error out early if pulling a tag failed.
+
+2008-10-27 09:25:11 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 36/57] gst/flv/: In pull mode we create our own index before doing anything else and don't use the index provided by some fi...
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_create_index),
+	  (gst_flv_demux_loop):
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_tag_script),
+	  (gst_flv_parse_tag_audio), (gst_flv_parse_tag_video),
+	  (gst_flv_parse_tag_timestamp):
+	  * gst/flv/gstflvparse.h:
+	  In pull mode we create our own index before doing anything else
+	  and don't use the index provided by some files (which are more than
+	  often incorrect and cause failed seeks).
+	  For push mode we still use the index provided by the file and extend it
+	  while doing the playback.
+
+2008-10-27 09:20:01 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 35/57] gst/flv/gstflvdemux.c: Instead of using gst_pad_event_default() use a small gst_pad_push_event() wrapper that only do...
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_push_src_event),
+	  (gst_flv_demux_loop), (gst_flv_demux_handle_seek_pull),
+	  (gst_flv_demux_sink_event):
+	  Instead of using gst_pad_event_default() use a small
+	  gst_pad_push_event() wrapper that only does what we want and is much
+	  more simple.
+
+2008-10-27 09:14:45 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 34/57] gst/flv/gstflvdemux.*: If our index was created by the element and not provided from the outside we should destroy it...
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_change_state),
+	  (gst_flv_demux_set_index), (gst_flv_demux_init):
+	  * gst/flv/gstflvdemux.h:
+	  If our index was created by the element and not provided from the
+	  outside we should destroy it when starting a new stream to get
+	  all old entries removed.
+
+2008-10-27 09:12:33 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 33/57] gst/flv/gstflvdemux.c: Improve debugging a bit when pulling a buffer from upstream fails.
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_pull_range):
+	  Improve debugging a bit when pulling a buffer from upstream fails.
+
+2008-10-27 09:10:54 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 32/57] gst/flv/: Close the currently playing segment from the streaming thread instead of the thread where the seek event is...
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_cleanup),
+	  (gst_flv_demux_handle_seek_pull), (gst_flv_demux_dispose):
+	  * gst/flv/gstflvdemux.h:
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_tag_audio),
+	  (gst_flv_parse_tag_video):
+	  Close the currently playing segment from the streaming thread
+	  instead of the thread where the seek event is handled.
+
+2008-10-16 15:21:15 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 31/57] gst/flv/gstflvmux.c: Don't set video_codec to the value that actually should go into audio codec, otherwise we create...
+	  Original commit message from CVS:
+	  * gst/flv/gstflvmux.c: (gst_flv_mux_audio_pad_setcaps),
+	  (gst_flv_mux_write_buffer):
+	  Don't set video_codec to the value that actually should go
+	  into audio codec, otherwise we create invalid files.
+	  Fixes bug #556564.
+
+2008-10-12 17:08:10 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 30/57] gst/flv/gstflvdemux.c: Fix regression of handling flow returns in pull mode.
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_pull_tag),
+	  (gst_flv_demux_pull_header):
+	  Fix regression of handling flow returns in pull mode.
+	  Fixes bug #556003.
+
+2008-10-10 16:33:36 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 29/57] gst/flv/gstflvparse.c: Use gst_pad_alloc_buffer_and_set_caps() to make sure we get a buffer with caps that we can wor...
+	  Original commit message from CVS:
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_tag_audio),
+	  (gst_flv_parse_tag_video):
+	  Use gst_pad_alloc_buffer_and_set_caps() to make sure we get
+	  a buffer with caps that we can work with (i.e. the pad's caps).
+	  Add non-keyframe video frames to the index too but without the
+	  keyframe flag.
+	  Add audio frames to the index only if we have no video stream.
+
+2008-10-10 16:15:09 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 28/57] gst/flv/gstflvparse.c: Create pads from the pad templates, use fixed caps on them and only activate them after the ca...
+	  Original commit message from CVS:
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_tag_audio),
+	  (gst_flv_parse_tag_video):
+	  Create pads from the pad templates, use fixed caps on them
+	  and only activate them after the caps are set.
+
+2008-10-09 16:20:26 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 27/57] gst/flv/: Get an approximate duration of the file by looking at the timestamp of the last tag in pull mode. If we get...
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_loop):
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_tag_timestamp):
+	  * gst/flv/gstflvparse.h:
+	  Get an approximate duration of the file by looking at the timestamp
+	  of the last tag in pull mode. If we get (maybe better) duration from
+	  metadata later we'll use that instead.
+
+2008-10-09 15:43:02 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 26/57] gst/flv/gstflvdemux.c: Refactor _pull_range() logic with checks into a seperate function to make things a bit more re...
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_pull_range),
+	  (gst_flv_demux_pull_tag), (gst_flv_demux_pull_header):
+	  Refactor _pull_range() logic with checks into a seperate function
+	  to make things a bit more readable.
+
+2008-10-09 15:26:56 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 25/57] gst/flv/gstflvdemux.c: Use gst_element_class_set_details_simple().
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_chain),
+	  (gst_flv_demux_base_init):
+	  Use gst_element_class_set_details_simple().
+	  If we get GST_FLOW_NOT_LINKED in the parse loop but at least
+	  one of the pads is linked continue the loop.
+
+2008-10-09 10:00:51 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 24/57] gst/flv/gstflvparse.c: Correct caps for video codec id 5: It's On2 VP6 with alpha channel which needs a different dec...
+	  Original commit message from CVS:
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_audio_negotiate),
+	  (gst_flv_parse_tag_audio), (gst_flv_parse_video_negotiate):
+	  Correct caps for video codec id 5: It's On2 VP6 with alpha channel
+	  which needs a different decoder and has different caps.
+	  Add support for audio codec id 14, which is MP3 with 8kHz sampling
+	  rate.
+	  Fix endianness and signedness for raw audio codec ids.
+	  Add support for alaw and mulaw audio.
+
+2008-10-09 09:48:46 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 23/57] gst/flv/gstflvdemux.c: Go out of the parse loop as soon as we get an error instead of parsing until the GstAdapter is...
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_chain):
+	  Go out of the parse loop as soon as we get an error instead
+	  of parsing until the GstAdapter is empty.
+	  Add some explanations about the header and tag size.
+	  Don't print synchronizing message if everything is fine.
+
+2008-10-09 09:26:58 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  [MOVED FROM BAD 22/57] gst/flv/: Add first version of a FLV muxer. The only missing feature is writing of stream metadata.
+	  Original commit message from CVS:
+	  * gst/flv/Makefile.am:
+	  * gst/flv/gstflvdemux.c: (plugin_init):
+	  * gst/flv/gstflvmux.c: (gst_flv_mux_base_init),
+	  (gst_flv_mux_class_init), (gst_flv_mux_init),
+	  (gst_flv_mux_finalize), (gst_flv_mux_reset),
+	  (gst_flv_mux_handle_src_event), (gst_flv_mux_handle_sink_event),
+	  (gst_flv_mux_video_pad_setcaps), (gst_flv_mux_audio_pad_setcaps),
+	  (gst_flv_mux_request_new_pad), (gst_flv_mux_release_pad),
+	  (gst_flv_mux_write_header), (gst_flv_mux_write_buffer),
+	  (gst_flv_mux_collected), (gst_flv_mux_change_state):
+	  * gst/flv/gstflvmux.h:
+	  Add first version of a FLV muxer. The only missing feature is writing
+	  of stream metadata.
+
+2008-06-13 22:46:43 +0000  Julien Moutte <julien@moutte.net>
+
+	  [MOVED FROM BAD 21/57] gst/flv/: Introduce demuxing support for AAC and
+	  Original commit message from CVS:
+	  2008-06-14  Julien Moutte  <julien@fluendo.com>
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_cleanup),
+	  (gst_flv_demux_dispose):
+	  * gst/flv/gstflvdemux.h:
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_audio_negotiate),
+	  (gst_flv_parse_tag_audio), (gst_flv_parse_video_negotiate),
+	  (gst_flv_parse_tag_video): Introduce demuxing support for AAC
+	  and
+	  H.264/AVC inside FLV.
+	  * sys/dshowdecwrapper/gstdshowaudiodec.c:
+	  (gst_dshowaudiodec_init),
+	  (gst_dshowaudiodec_chain), (gst_dshowaudiodec_push_buffer),
+	  (gst_dshowaudiodec_sink_event), (gst_dshowaudiodec_setup_graph):
+	  * sys/dshowdecwrapper/gstdshowaudiodec.h:
+	  * sys/dshowdecwrapper/gstdshowvideodec.c:
+	  (gst_dshowvideodec_init),
+	  (gst_dshowvideodec_sink_event), (gst_dshowvideodec_chain),
+	  (gst_dshowvideodec_push_buffer),
+	  (gst_dshowvideodec_src_getcaps):
+	  * sys/dshowdecwrapper/gstdshowvideodec.h: Lot of random fixes
+	  to improve stability (ref counting, safety checks...)
+
+2008-04-25 08:07:36 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  [MOVED FROM BAD 20/57] gst/flv/gstflvdemux.c: Forward unknown queries upstream instead of returning FALSE on them.
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_query):
+	  Forward unknown queries upstream instead of returning FALSE on them.
+
+2008-04-11 23:19:21 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  [MOVED FROM BAD 19/57] gst/flv/gstflvparse.c: Handle NULL returns from FLV_GET_STRING() more gracefully. Fixes crash caused by a strlen on a...
+	  Original commit message from CVS:
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_metadata_item),
+	  (gst_flv_parse_tag_script):
+	  Handle NULL returns from FLV_GET_STRING() more gracefully. Fixes
+	  crash caused by a strlen on a NULL string (#527622).
+
+2007-12-11 11:54:43 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  [MOVED FROM BAD 18/57] gst/flv/gstflvparse.c: Don't strdup (and thus leak) codec name strings when passing them to gst_tag_list_add().
+	  Original commit message from CVS:
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_tag_audio),
+	  (gst_flv_parse_tag_video):
+	  Don't strdup (and thus leak) codec name strings when passing
+	  them to gst_tag_list_add().
+
+2007-12-09 19:37:53 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  [MOVED FROM BAD 17/57] gst/flv/gstflvparse.c: Fix list of supported and known codecs.
+	  Original commit message from CVS:
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_tag_audio),
+	  (gst_flv_parse_tag_video):
+	  Fix list of supported and known codecs.
+	  Emit tag with the codec name so it gets properly reported in totem and
+	  other applications.
+
+2007-11-25 10:45:09 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  [MOVED FROM BAD 16/57] gst/flv/gstflvparse.c: Output segment with proper 'stop' value, makes flvdemux 100% compatible with gnonlin.
+	  Original commit message from CVS:
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_tag_audio),
+	  (gst_flv_parse_tag_video):
+	  Output segment with proper 'stop' value, makes flvdemux 100% compatible
+	  with gnonlin.
+
+2007-11-12 19:22:24 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  [MOVED FROM BAD 15/57] gst/flv/gstflvparse.c: Add mapping for Nellymoser ASAO audio codec.
+	  Original commit message from CVS:
+	  * gst/flv/gstflvparse.c:
+	  Add mapping for Nellymoser ASAO audio codec.
+	  (gst_flv_parse_tag_audio), (gst_flv_parse_tag_video): Make sure we
+	  actually have data to read at the end of the tag. This avoids trying
+	  to allocate negative buffers.
+
+2007-10-22 15:45:49 +0000  Julien Moutte <julien@moutte.net>
+
+	  [MOVED FROM BAD 14/57] gst/flv/gstflvparse.c: Don't emit no-more-pads for single pad scenarios as the header is definitely not reliable. We ...
+	  Original commit message from CVS:
+	  2007-10-22  Julien MOUTTE  <julien@moutte.net>
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_tag_audio),
+	  (gst_flv_parse_tag_video), (gst_flv_parse_tag_type): Don't
+	  emit no-more-pads for single pad scenarios as the header
+	  is definitely not reliable. We emit them for 2 pads scenarios
+	  though to speed up media discovery.
+
+2007-09-27 10:06:23 +0000  Julien Moutte <julien@moutte.net>
+
+	  [MOVED FROM BAD 13/57] gst/flv/gstflvparse.c: I got it wrong again, audio rate was not detected correctly in all cases.
+	  Original commit message from CVS:
+	  2007-09-27  Julien MOUTTE  <julien@moutte.net>
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_tag_audio),
+	  (gst_flv_parse_tag_video): I got it wrong again, audio rate
+	  was not detected correctly in all cases.
+
+2007-09-26 16:30:50 +0000  Julien Moutte <julien@moutte.net>
+
+	  [MOVED FROM BAD 12/57] gst/flv/gstflvparse.c: codec_data is needed for every tag not just the first one. (Fix a stupid bug i introduced with...
+	  Original commit message from CVS:
+	  2007-09-26  Julien MOUTTE  <julien@moutte.net>
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_tag_audio),
+	  (gst_flv_parse_tag_video): codec_data is needed for every tag
+	  not just the first one. (Fix a stupid bug i introduced without
+	  testing)
+
+2007-09-26 11:17:08 +0000  Julien Moutte <julien@moutte.net>
+
+	  [MOVED FROM BAD 11/57] gst/flv/gstflvparse.c: Fix bit masks operations to be sure we detect the codec_tags and sample rates correctly.
+	  Original commit message from CVS:
+	  2007-09-26  Julien MOUTTE  <julien@moutte.net>
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_tag_audio),
+	  (gst_flv_parse_tag_video): Fix bit masks operations to be
+	  sure we detect the codec_tags and sample rates correctly.
+	  Fix raw audio caps generation.
+
+2007-09-12 08:38:22 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  [MOVED FROM BAD 10/57] gst/: Printf format fixes (#476128).
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt  <pkj at axis com>
+	  * gst-libs/gst/app/gstappsink.c:
+	  * gst/flv/gstflvdemux.c:
+	  * gst/flv/gstflvparse.c:
+	  * gst/interleave/deinterleave.c:
+	  * gst/switch/gstswitch.c:
+	  Printf format fixes (#476128).
+
+2007-08-27 14:56:05 +0000  Julien Moutte <julien@moutte.net>
+
+	  [MOVED FROM BAD 09/57] gst/flv/gstflvdemux.c: Make sure we initialize the seek result.
+	  Original commit message from CVS:
+	  2007-08-27  Julien MOUTTE  <julien@moutte.net>
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_handle_seek_pull):
+	  Make sure we initialize the seek result.
+
+2007-08-24 17:03:15 +0000  Julien Moutte <julien@moutte.net>
+
+	  [MOVED FROM BAD 08/57] gst/flv/gstflvdemux.c: Remove some useless ifdef.
+	  Original commit message from CVS:
+	  2007-08-24  Julien MOUTTE  <julien@moutte.net>
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_flush),
+	  (gst_flv_demux_chain), (gst_flv_demux_pull_tag),
+	  (gst_flv_demux_find_offset), (gst_flv_demux_handle_seek_push),
+	  (gst_flv_demux_handle_seek_pull), (gst_flv_demux_sink_event),
+	  (gst_flv_demux_src_event): Remove some useless ifdef.
+
+2007-08-24 15:31:26 +0000  Julien Moutte <julien@moutte.net>
+
+	  [MOVED FROM BAD 07/57] gst/flv/gstflvdemux.c: Implement seeking in push mode.
+	  Original commit message from CVS:
+	  2007-08-24  Julien MOUTTE  <julien@moutte.net>
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_flush),
+	  (gst_flv_demux_cleanup), (gst_flv_demux_chain),
+	  (gst_flv_demux_pull_tag), (gst_flv_demux_find_offset),
+	  (gst_flv_demux_handle_seek_push),
+	  (gst_flv_demux_handle_seek_pull),
+	  (gst_flv_demux_sink_event), (gst_flv_demux_src_event): Implement
+	  seeking in push mode.
+	  * gst/flv/gstflvdemux.h:
+
+2007-08-22 14:50:51 +0000  Julien Moutte <julien@moutte.net>
+
+	  [MOVED FROM BAD 06/57] gst/flv/: Handle pixel aspect ratio through metadata tags like ASF does. Fluendo muxer supports this and
+	  Original commit message from CVS:
+	  2007-08-22  Julien MOUTTE  <julien@moutte.net>
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_cleanup),
+	  (gst_flv_demux_pull_tag):
+	  * gst/flv/gstflvdemux.h:
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_metadata_item),
+	  (gst_flv_parse_tag_script), (gst_flv_parse_tag_audio),
+	  (gst_flv_parse_tag_video): Handle pixel aspect ratio through
+	  metadata tags like ASF does. Fluendo muxer supports this and
+	  Flash players can support it as well this way.
+
+2007-08-22 14:03:42 +0000  Julien Moutte <julien@moutte.net>
+
+	  [MOVED FROM BAD 05/57] gst/flv/: Make sure we don't try filling up the index if no times object was parsed. Fix the way we decide to push ta...
+	  Original commit message from CVS:
+	  2007-08-22  Julien MOUTTE  <julien@moutte.net>
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_pull_tag):
+	  * gst/flv/gstflvparse.c: (gst_flv_parse_metadata_item),
+	  (gst_flv_parse_tag_script), (gst_flv_parse_tag_audio),
+	  (gst_flv_parse_tag_video): Make sure we don't try filling up the
+	  index if no times object was parsed. Fix the way we decide to
+	  push
+	  tags and emit no-more-pads. Fix some printf typing in debugging.
+
+2007-08-14 14:56:20 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  [MOVED FROM BAD 04/57] gst/flv/gstflvdemux.c: Fix locking and refcounting on the index.
+	  Original commit message from CVS:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_set_index),
+	  (gst_flv_demux_get_index):
+	  Fix locking and refcounting on the index.
+
+2007-08-14 14:22:09 +0000  Julien Moutte <julien@moutte.net>
+
+	  [MOVED FROM BAD 03/57] gst/flv/gstflvdemux.c: First method for seeking in pull mode using the index built step by step or coming from metadata.
+	  Original commit message from CVS:
+	  2007-08-14  Julien MOUTTE  <julien@moutte.net>
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_cleanup),
+	  (gst_flv_demux_adapter_flush), (gst_flv_demux_chain),
+	  (gst_flv_demux_pull_tag), (gst_flv_demux_do_seek),
+	  (gst_flv_demux_handle_seek), (gst_flv_demux_sink_event),
+	  (gst_flv_demux_src_event), (gst_flv_demux_query),
+	  (gst_flv_demux_change_state), (gst_flv_demux_set_index),
+	  (gst_flv_demux_get_index), (gst_flv_demux_dispose),
+	  (gst_flv_demux_class_init): First method for seeking in pull
+	  mode using the index built step by step or coming from metadata.
+	  * gst/flv/gstflvdemux.h:
+	  * gst/flv/gstflvparse.c: (FLV_GET_STRING),
+	  (gst_flv_parse_metadata_item), (gst_flv_parse_tag_script),
+	  (gst_flv_parse_tag_audio), (gst_flv_parse_tag_video): Parse
+	  more metadata types and keyframes index.
+
+2007-07-25 13:29:04 +0000  Julien Moutte <julien@moutte.net>
+
+	  [MOVED FROM BAD 02/57] gst/flv/: Handle not linked pads, try to make it reusable, more safety checks.
+	  Original commit message from CVS:
+	  2007-07-25  Julien MOUTTE  <julien@moutte.net>
+	  (gst_flv_demux_chain), (gst_flv_demux_pull_tag),
+	  (gst_flv_demux_change_state), (gst_flv_demux_dispose),
+	  (gst_flv_demux_init):
+	  * gst/flv/gstflvdemux.h:
+	  * gst/flv/gstflvparse.c: (FLV_GET_STRING),
+	  (gst_flv_parse_metadata_item), (gst_flv_parse_tag_script),
+	  (gst_flv_parse_tag_audio), (gst_flv_parse_tag_video),
+	  (gst_flv_parse_header):
+	  * gst/flv/gstflvparse.h: Handle not linked pads, try to make it
+	  reusable, more safety checks.
+
+2007-07-19 15:05:30 +0000  Julien Moutte <julien@moutte.net>
+
+	  [MOVED FROM BAD 01/57] Adds a first draft of an FLV demuxer.
+	  Original commit message from CVS:
+	  2007-07-19  Julien MOUTTE  <julien@moutte.net>
+	  * configure.ac:
+	  * gst/flv/Makefile.am:
+	  * gst/flv/gstflvdemux.c: (gst_flv_demux_flush),
+	  (gst_flv_demux_cleanup), (gst_flv_demux_chain),
+	  (gst_flv_demux_pull_tag), (gst_flv_demux_pull_header),
+	  (gst_flv_demux_seek_to_prev_keyframe), (gst_flv_demux_loop),
+	  (gst_flv_demux_sink_activate),
+	  (gst_flv_demux_sink_activate_push),
+	  (gst_flv_demux_sink_activate_pull), (gst_flv_demux_sink_event),
+	  (gst_flv_demux_change_state), (gst_flv_demux_dispose),
+	  (gst_flv_demux_base_init), (gst_flv_demux_class_init),
+	  (gst_flv_demux_init), (plugin_init):
+	  * gst/flv/gstflvdemux.h:
+	  * gst/flv/gstflvparse.c: (FLV_GET_BEUI24), (FLV_GET_STRING),
+	  (gst_flv_demux_query_types), (gst_flv_demux_query),
+	  (gst_flv_parse_metadata_item), (gst_flv_parse_tag_script),
+	  (gst_flv_parse_tag_audio), (gst_flv_parse_tag_video),
+	  (gst_flv_parse_tag_type), (gst_flv_parse_header):
+	  * gst/flv/gstflvparse.h: Adds a first draft of an FLV demuxer.
+	  It does not do seeking yet, it supports pull and push mode so
+	  YES
+	  you can use it to play youtube videos directly from an HTTP uri.
+	  Not so much testing done yet but it parses metadata, reply to
+	  duration queries, etc...
+
+2009-05-12 13:00:46 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	  rtp: Link to -lm
+	  Fixes bug #582281.
+
+2009-05-12 11:16:48 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/rganalysis.c:
+	  rganalysis: Remove invalid unit test
+	  The test creates buffers with non-silence, sets the GAP
+	  flag on it and expects rganalysis to ignore the content and assume silence.
+	  That's not the way how GAP buffers should be used, if the GAP flag is set
+	  elements *can* assume that they only contain silence but they're not *required*
+	  to assume that. The GAP flag must only be set on silence buffers.
+	  Fixes bug #582252.
+
+2009-05-12 00:48:49 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* ChangeLog:
+	* configure.ac:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	* win32/common/config.h:
+	  0.10.14.2 pre-release
+
+2009-05-11 23:13:20 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* tests/files/Makefile.am:
+	  checks: dist id3-577468-unsynced-tag.tag test file
+
+2009-05-11 21:02:27 +0200  Tristan Matthews <le.businessman at gmail.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: initialize variable to 0
+	  Fixes #582218.
+
+2009-05-11 18:21:13 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Only search for the index entry once
+
+2009-05-11 18:18:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Use the first index entry if it's after the seek position
+
+2009-05-11 18:15:22 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Use the first entry for a given stream if the first entry is after the seek position
+
+2009-05-11 16:50:48 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Use binary search for finding the requested index entry when seeking
+
+2009-05-11 15:36:46 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	  matroskademux: Improve/optimize seeking
+	  First of all a keyframe seek should be done to the
+	  keyframe right before the requested position and not
+	  to the keyframe that is nearest to the requested position.
+	  Use per track index arrays and use our new binary search function
+	  from core to speed up the search.
+
+2009-05-11 15:36:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  Require released versions of core/base
+
+2009-05-11 10:15:00 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	  gdkpixbuf: Use the libs and cflags of gdk pixbuf instead of gtk
+	  This fixes the build if gdk-pixbuf is found but gtk isn't
+
+2009-05-11 09:58:48 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* configure.ac:
+	  Always define the conditional HAVE_GTK to fix configure in some cases
+
+2009-05-10 11:17:23 +0200  Marc-Andre Lureau <marcandre.lureau@gmail.com>
+
+	* autogen.sh:
+	  Run libtoolize before aclocal
+	  This unbreaks the build in some cases. Fixes bug #582021
+
+2009-05-09 10:50:45 -0700  David Schleef <ds@schleef.org>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska: fix printf format to agree with argument
+
+2009-05-08 19:42:10 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	  raw1394: include stdlib.h for strtol()
+	  Fixes compiler warning when compiling with xml stuff in core disabled.
+
+2009-05-08 16:40:57 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: Actually output the pending buffer.. and not a blank one.
+	  It was previously sending the bogus buffer which was returned from
+	  the bufferalloc (required for reverse negotiation apparently) instead
+	  of the pending buffer.
+
+2009-05-08 12:00:57 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  souphttpsrc: Allow non-string fields in the extra-headers property
+
+2009-05-08 11:35:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpj2kdepay.c:
+	* gst/rtp/gstrtpj2kdepay.h:
+	  rtj2kdepay: add basic JPEG 2000 depayloader
+
+2009-05-08 11:31:02 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpj2kpay.c:
+	  rtpj2kpay: set marker bit correctly
+
+2009-05-08 11:29:04 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: Add support for extra-headers appended to the HTTP request
+	  This allows to set the Referer header among other things by
+	  adding a "extra-headers" property that takes a GstStructure
+	  with field=string pairs.
+	  Fixes bug #581806.
+
+2009-05-08 10:38:42 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpj2kpay.c:
+	* gst/rtp/gstrtpj2kpay.h:
+	  rtpj2kpay: add a simple JPEG 2000 payloader
+
+2009-05-08 10:31:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: we only need to swap bits on LE
+
+2009-05-07 18:10:08 +0100  Christian Schaller <christian.schaller@collabora.co.uk>
+
+	* ext/flac/gstflac.c:
+	* ext/jpeg/gstjpeg.c:
+	* ext/libpng/gstpng.c:
+	* ext/speex/gstspeex.c:
+	* gst/avi/gstavi.c:
+	* gst/matroska/matroska-mux.c:
+	  Add RANKS for various encoders and muxers
+
+2009-05-07 17:09:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: add some debugging
+
+2009-05-07 15:58:43 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: parse xiph headers length correctly
+	  See #580980
+
+2009-05-07 16:25:41 +0200  Gabriel Bouvigne <bouvigne@mp3-tech.org>
+
+	* gst/replaygain/gstrganalysis.c:
+	* gst/replaygain/gstrganalysis.h:
+	* gst/replaygain/rganalysis.c:
+	* gst/replaygain/rganalysis.h:
+	  rganalysis: Add ability to post level messages
+	  Fixes bug #581568.
+
+2009-05-06 23:56:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: refuse some unsupported jpeg formats
+
+2009-05-06 18:06:49 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtptheorapay.c:
+	  rtptheorapay: fix description
+
+2009-05-06 16:09:13 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: rewrite quant table handling
+	  Rewrite the quant table parsing to also handle multiple tables in one JPEG HDQ
+	  segment.
+	  Handle more jpeg types by keeping track of the tables used per component and
+	  putting the used ones in the quant headers.
+
+2009-04-18 17:23:51 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* tests/check/elements/id3v2mux.c:
+	  id3v2mux: Make the test failure slightly more informative
+
+2009-04-20 18:33:09 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* ext/flac/gstflacdec.c:
+	  flac: Make buffers created during seek act like normal buffers.
+	  Store the offset and caps when allocating a buffer during seeking, and then
+	  allocate a new buffer with buffer_alloc before we push it out. This ensures
+	  that in all respects the first buffer decoded during seeking behaves like
+	  all other buffers, including allowing downstream re-negotiation.
+
+2009-04-18 18:00:54 +0200  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: don't use pad_alloc when decoding while seeking. Fixes #579422
+
+2009-05-06 13:22:51 +0200  Arnout Vandecappelle <arnout@mind.be>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: refactored gst_jpeg_dec_parse_image_data
+	  Fixes #579808
+
+2009-05-06 13:11:53 +0200  Arnout Vandecappelle <arnout@mind.be>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: support additional 0xff before end marker.
+	  JPEG markers may be preceded by additional 0xff.  jpegdec should
+	  skip over these, even before the end marker.
+	  See #579808
+
+2009-05-06 12:54:22 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	  rtpjpegpay: handle input with 1 quant table
+	  Also handle input with just one quant table, simply duplicate the quant table.
+	  Handle invalid SOF correctly and some small cleanups.
+	  Fixes #578257
+
+2009-04-29 15:58:10 +0300  Marco Ballesio <marco.ballesio@nokia.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix byte order swapping in 3GPP classification entity tag
+	  Fixes #580746.
+
+2009-05-05 17:07:13 +0200  Arnout Vandecappelle <arnout@mind.be>
+
+	* gst/multipart/multipartdemux.c:
+	  multipartdemux: avoid reading from inavlid memory
+	  Read the timestamp of the incomming buffer before we push it in the adapter and
+	  flush it out again as the buffer might be unreffed then and we read from invalid
+	  memory.
+	  Fixes #581444.
+
+2009-05-05 17:03:29 +0200  Arnout Vandecappelle <arnout@mind.be>
+
+	* gst/multipart/multipartdemux.c:
+	  multipartdemux: don't leak dynamic pads
+	  Free the dynamic pads data in finalize.
+	  Fixes #581432
+
+2009-05-05 16:32:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtp/gstrtpjpegpay.h:
+	  rtpjpegpay: correctly set the type header
+	  Don't require width/height on the caps. Use the SOF header to find width/height
+	  and fall back to the caps if there is no SOF. Also use the SOF info to find the
+	  subsampling and quantization tables used. This allows us to set the right type
+	  value in the JPEG rtp header.
+	  Deprecate the quality property, it's unused now and it was used wrongly before.
+	  Always send full quant tables for now until we have some code to detect default
+	  ones.
+	  Fixes #580880
+
+2009-05-05 16:28:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpjpegdepay.h:
+	  rtpjpegdepay: use width/height from payload
+	  Use the width and the height from the payload headers and set them on the
+	  output caps for added awesomeness.
+	  Fix quant parsing, we need to check the type in the lower 6 bits.
+	  Add first bits of caching quantization tables.
+
+2009-05-05 16:24:16 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: set colorspace before _set_defaults()
+	  The libjpeg api says that we need to set the colorspace before we call
+	  _set_defaults(). Indeed, if we don't do that we end up with some very freaky
+	  non-standard quant table and huffman table indexes.
+
+2009-05-05 13:19:19 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/Makefile.am:
+	  tests: don't build examples if --disable-examples was passed to configure
+
+2009-05-05 12:33:57 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure: clean up mess around gtk+ checking
+	  And don't check for gtk+ when it's not needed (ie. if examples are disabled)
+
+2009-05-05 12:27:21 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* ext/gdk_pixbuf/Makefile.am:
+	* ext/gdk_pixbuf/pixbufscale.h:
+	  configure: make gdk-pixbuf plugin depend only on gdk-pixbuf, not gtk+
+
+2009-05-04 18:55:12 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Fix find_stream_by_* functions
+	  Fix various version of find_stream_by_* by not trying to convert an int to a
+	  pointer and vice versa, for portability reasons.
+	  Fixes #581333
+
+2009-05-04 18:32:05 +0200  Chris Winter <elwintro at gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix dummy nat packet logic
+	  Fix a typo in the dummy NAT packet sending code.
+	  Fixes #581329
+
+2009-04-30 10:24:27 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: avoid errors after server eof
+	  Server eof (e.g. connection closed) is announced as connection closed,
+	  so better record state and act accordingly to prevent (read/write)
+	  errors during subsequent teardown/cleanup sequences.  #Fixes 580851.(c).
+
+2009-04-30 10:19:27 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: also set base_time on src after flush
+	  timestamps following flush/seek should be consistent between
+	  UDP and TCP interleaved case.  Fixes #580851.(b).
+
+2009-04-30 10:17:23 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: sanity checks on range info
+	  A max range that overflows should not be trusted,
+	  nor should a max range that equals the min range.
+	  Fixes #580851.(a).
+
+2009-05-04 16:16:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: use SKIP flag to use SCALE headers
+	  We can use the SKIP seek flag to instruct the server to send data faster then
+	  normal but with the same bandwidth.
+	  Fixes #537609
+
+2009-05-04 14:19:22 +0200  Alessandro Decina <alessandro.d@gmail.com>
+
+	* ext/speex/gstspeexdec.c:
+	  speexdec: make speex_dec_convert work with same-format values when no data has been decoded.
+
+2009-05-04 12:43:42 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flac: Implement preset interface
+
+2009-05-04 12:41:56 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/speex/gstspeexenc.c:
+	  speex: Implement preset interface
+
+2009-05-04 12:40:12 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/wavpack/gstwavpackenc.c:
+	  wavpack: Implement preset interface
+
+2009-05-04 12:35:19 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: use binary search for index
+	  Use the new binary search method for finding the right index entry faster.
+
+2009-05-04 11:26:56 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videobox/gstvideobox.c:
+	  videobox: draw the complete U and V planes
+	  Round up the scaled U and V width and height so that we always draw the correct
+	  amount of pixels to fill the complete image.
+	  Fixes #569611
+
+2009-05-01 19:35:11 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: add some more micro optimisations
+
+2009-04-30 18:41:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_dump.c:
+	* gst/qtdemux/qtdemux_types.c:
+	  qtdemux: micro optimize qtdemux a little
+	  Sprinkle some G_LIKELY around.
+	  Avoid traversing and dumping the tree when debugging is not activated.
+
+2009-04-30 14:22:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux.h:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	  qtdemux: add support for subtitle pictures
+	  Add support for subtitle pictures.
+	  Fixes #568278.
+
+2009-04-30 10:32:39 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: make sure we always signal waiters
+	  Always signal the waiters in the async callbacks. Especially for the volume
+	  callbacks since this might cause deadlocks.
+
+2009-04-29 18:09:07 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: release state lock before stopping task
+	  We need to release the state lock before trying to wait for the task to end
+	  because the task might also take the lock.
+	  Fixes #577671
+
+2009-04-29 12:19:27 +0200  Hans de Goede <jwrdegoede at fedoraproject.org>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: handle ac-3 audio
+	  fix demuxing of m4v streams with ac-3 audio
+	  Fixes #580554
+
+2009-04-29 11:12:36 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/flac/gstflacenc.c:
+	  flacenc: Use the tag merge mode that was set on the interface for merging tag events
+
+2009-04-25 09:43:38 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: fix getaddrinfo error reporting
+	  getaddrinfo errors should be reported with gai_strerror instead of errno as
+	  spotted by MikeS.
+
+2009-04-27 10:08:39 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpg726pay.c:
+	  g726pay: fix compilation
+
+2009-04-27 10:02:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpg726pay.h:
+	  g726pay: add RFC compliant packetizing
+	  Shuffle the input bits according to RFC 3551 for G726 payloads.
+	  Add option to force the previous behaviour.
+	  Fixes #567140
+
+2009-04-27 09:59:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpg726depay.c:
+	  g726depay: add debug category
+	  Add a debugging category, add some comments and remove _peek_parent().
+
+2009-04-26 15:59:50 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  id3v2mux: we need taglib 1.5 for ID3v2::RelativeVolumeFrame::setIdentification
+	  Bump taglib requirement.
+
+2009-04-24 02:11:28 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/elements/id3demux.c:
+	* tests/files/id3-577468-unsynced-tag.tag:
+	  id3demux: add unit test file for unsynced id3 tags
+
+2009-04-24 01:51:35 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/id3demux/id3tags.c:
+	  id3demux: parse unsynchronised tags properly
+	  We didn't handle unsynchronization at all up to now, which might have
+	  caused frames to not be extracted - esp. frames after an APIC picture
+	  frame. Fixes #577468.
+
+2009-04-24 01:01:53 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/id3demux/id3tags.c:
+	  id3demux: pass the right size value for size of all frames to the parser
+	  Frame data size is tag size adjusted for size of the tag header and
+	  footer, not tag size including header and footer.
+
+2009-04-22 15:24:55 +0200  Patrick Radizi <patrick.radizi at axis.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix some more pad leaks
+	  Fix some pad leaks.
+	  See #577318.
+
+2009-04-21 22:12:45 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From b3941ea to 6ab11d1
+
+2009-04-21 14:02:01 -0700  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: override caps based on data from ESDS atoms in mpeg4.
+	  If the codec is actually something else (e.g. mjpeg) change the caps to
+	  match when parsing the ESDS atom.
+	  Also, for AAC, override rate and channels with correct values read from
+	  ESDS, since the rate/channels values elsewhere are often wrong.
+
+2009-04-20 19:32:00 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	  jpegdec: fix warning for still images by not trying to divide by 0
+	  Don't pass a 0 divisor to gst_util_uint64_scale(), or it will complain
+	  in the single image case where fps=0/1 (are we supposed to differentiate
+	  between no fps=still image and fps=0/1=variable rate here btw?)
+
+2009-04-20 17:25:34 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/udp/gstudpnetutils.c:
+	  udp: Fix a simple typo in the previous commit
+	  Use #ifdef instead of #if, to fix the build
+
+2009-04-20 15:48:21 +0200  Andy Wingo <wingo@wingomac.bcn.oblong.net>
+
+	  fix format string in pngdec
+	  * ext/libpng/gstpngdec.c: Fix size_t vs unsigned int format in error message.
+
+2009-04-20 15:46:03 +0200  Andy Wingo <wingo@wingomac.bcn.oblong.net>
+
+	  only use struct ip_mreqn if it is detected
+	  * configure.ac: Make an explicit check for struct ip_mreqn.
+	  * gst/udp/gstudpnetutils.c: Use HAVE_IP_MREQN instead of the ad-hoc checks.
+
+2009-04-20 13:45:32 +0200  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  Fix push mode buffering sanity check to actually fit the description.
+
+2009-04-18 19:11:06 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: And let's not forget to remove the unused variable.
+
+2009-04-18 18:50:32 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtph263pay.c:
+	  rtph263pay: Remove dead assignments, the variables are never read after.
+
+2009-04-18 18:49:49 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpmp4vpay.c:
+	  rtpmp4vpay: Remove dead assignment. The value is never read after.
+
+2009-04-18 18:48:55 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Remove dead assignment.
+	  t is being overwritten after, before it's used.
+
+2009-04-18 18:48:06 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpamrdepay.c:
+	  rtpamrdepay: Remove unneeded variable, the value is only read once.
+
+2009-04-18 18:47:05 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpamrpay.c:
+	  rtpamrpay: Remove unneeded variable, the value is only read once.
+
+2009-04-18 18:46:12 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/goom/filters.c:
+	  goom/filters: Remove dead assignment. Value overwritten just after.
+
+2009-04-18 18:45:32 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	  rtpvorbispay: Remove dead assignment. Value never read after.
+
+2009-04-18 18:45:07 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtptheorapay.c:
+	  rtptheorapay: Remove dead assignment. Value never read after.
+
+2009-04-18 18:43:31 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	  rtptheoradepay: Remove unused variable, it's never being read.
+
+2009-04-18 18:42:45 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Remove dead assignment. 'res' isn't read after.
+
+2009-04-18 18:41:58 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Remove unused variable. 'res' is never read.
+
+2009-04-18 18:40:48 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: Remove dead variable. 'stream' is never read after.
+
+2009-04-18 18:39:48 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/videobox/gstvideobox.c:
+	  videbox: Remove dead assignments.
+	  These variables are never read after this point.
+
+2009-04-18 18:38:29 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/goom/convolve_fx.c:
+	  goom: ff and iff are only used in a '#ifdef DRAW_MOTIF' block.
+
+2009-04-18 18:34:11 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Remove dead assignment.
+	  res isn't read after this.
+
+2009-04-18 18:32:03 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Remove dead assignments, move variable to where it's needed.
+	  The header_read_error label will return GST_FLOW_ERROR
+
+2009-04-18 18:21:22 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  rtpvrawdepay: Remove dead assignment.
+	  The value of 'str' will never be used in these cases.
+
+2009-04-18 18:19:12 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Remove useless variable.
+	  iret was never read outside of that loop, and is always being exited if
+	  iret was != GST_FLOW_OK anyway.
+
+2009-04-18 18:17:35 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Move 'res' to where it's actually being used.
+	  res was never used outside of that block except for a dead assignment.
+
+2009-04-18 18:16:33 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	  audiofx: Remove unused variable.
+	  rz is never used in these methods.
+
+2009-04-18 18:15:39 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* sys/osxaudio/gstosxringbuffer.c:
+	  osxringbuffer: Run gst-indent.
+
+2009-04-18 18:14:49 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* sys/ximage/gstximagesrc.c:
+	  ximage: Remove dead assignments.
+	  Those variables are not read after that point.
+
+2009-04-18 18:11:00 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/dv/gstdvdemux.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/gdk_pixbuf/pixbufscale.c:
+	* ext/libcaca/gstcacasink.c:
+	* ext/libpng/gstpngdec.c:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	* ext/speex/gstspeexenc.c:
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalphacolor.c:
+	* gst/apetag/gstapedemux.c:
+	* gst/auparse/gstauparse.c:
+	* gst/effectv/gstquark.c:
+	* gst/flx/gstflxdec.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/interleave/interleave.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/qtdemux/gstrtpxqtdepay.c:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtpsirenpay.c:
+	* gst/rtp/gstrtpvorbisdepay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/rtsp/gstrtpdec.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/smpte/gstsmptealpha.c:
+	* gst/smpte/paint.c:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/videobox/gstvideobox.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videomixer/videomixer.c:
+	* gst/wavparse/gstwavparse.c:
+	* sys/ximage/gstximagesrc.c:
+	  Remove trivial unused variables detected by CLang static analyzer.
+
+2009-04-18 17:52:00 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/gconf/gstswitchsink.c:
+	* gst/qtdemux/gstrtpxqtdepay.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpac3depay.c:
+	* gst/rtp/gstrtpdepay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtpjpegdepay.c:
+	* gst/rtp/gstrtpmp1sdepay.c:
+	* gst/rtp/gstrtpmp2tdepay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpvdepay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtpvrawpay.c:
+	  Remove blank {set|get}_property/change_state/finalize methods.
+
+2009-04-18 17:42:55 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/cairo/gsttimeoverlay.c:
+	* ext/esd/esdsink.c:
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngenc.c:
+	* ext/pulse/pulsesink.c:
+	* gst/alpha/gstalphacolor.c:
+	* gst/cutter/gstcutter.c:
+	* gst/debugutils/efence.c:
+	* gst/debugutils/gstnavigationtest.c:
+	* gst/debugutils/gsttaginject.c:
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstwarp.c:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpdvdepay.c:
+	* gst/rtp/gstrtpdvpay.c:
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726pay.c:
+	* gst/rtp/gstrtpg729depay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpmp2tpay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmpvpay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtppcmupay.c:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpsirenpay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	* gst/rtp/gstrtpvrawdepay.c:
+	* gst/smpte/gstsmptealpha.c:
+	* gst/udp/gstudpsink.c:
+	* gst/videofilter/gstvideobalance.c:
+	* sys/oss/gstosssink.c:
+	* sys/oss/gstosssrc.c:
+	  Remove unused variables in _class_init
+	  Detected by LLVM's CLang static analyzer
+
+2009-04-18 13:54:08 +0100  Jan Schmidt <thaytan@noraisin.net>
+
+	* tests/check/elements/souphttpsrc.c:
+	  check: Check whether threads are already initialised before g_thread_init()
+
+2009-04-18 14:32:40 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: mark discont on the streams as was said the debug line
+	  After a seek mark all streams with discont as it was said in the debug line.
+	  Fixes that buffers after a seek are generated without a valid timestamp.
+
+2009-04-18 08:45:18 +0200  Josep Torra <n770galaxy@gmail.com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: map GST_RTSP_EEOF to EOS on server requests
+	  Permit properly handle the EOS condition when server report it in a request.
+
+2009-04-18 08:39:57 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtptheoradepay.c:
+	  rtptheoradepay: Fix build on macosx.
+	  Use G_GSIZE_FORMAT instead of u.
+
+2009-04-16 22:50:59 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: fix sample offset calculation again
+
+2009-04-15 19:32:18 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* sys/sunaudio/gstsunaudiomixerctrl.c:
+	  sunaudio: fix broken indentation of variable declarations
+
+2009-04-15 19:28:53 +0100  James Andrewartha <trs80@ucc.gu.uwa.edu.au>
+
+	* sys/sunaudio/gstsunaudiomixerctrl.c:
+	* sys/sunaudio/gstsunaudiosink.c:
+	  sunaudio: remove some unused variables and goto labels
+	  Fixes #579070.
+
+2009-04-15 19:24:49 +0200  James Andrewartha <trs80 at ucc.gu.uwa.edu.au>
+
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pay.h:
+	  rtph263pay: fix compilation on big-endian
+	  Some semicolons were missing from the big-endian structs in gstrtph263pay.h.
+	  A GST_DEBUG call was missing a format specifier.
+	  Fixes #579069
+
+2009-04-15 20:10:04 +0300  Marco Ballesio <marco.ballesio@nokia.com>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux.h:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	* gst/qtdemux/qtdemux_types.c:
+	* gst/qtdemux/quicktime.c:
+	  qtdemux: implement 3GPP (TS 26.244 V8.0.0) Asset metadata handling, Fixes #132193
+	  Implements 3gpp iso metadata tags which are different from mov udta atoms.
+
+2009-04-15 15:51:24 +0200  Peter Kjellerstedt <pkj@axis.com>
+
+	* gst/debugutils/efence.h:
+	  debugutils: Use G_BEGIN_DECLS/G_END_DECLS.
+	  Use G_BEGIN_DECLS/G_END_DECLS to avoid gst-indent messing up the
+	  indentation due to extern "C" { }.
+
+2009-04-15 16:03:27 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* gst/debugutils/Makefile.am:
+	* gst/debugutils/breakmydata.c:
+	* gst/debugutils/debug.vcproj:
+	* gst/debugutils/efence.c:
+	* gst/debugutils/efence.h:
+	* gst/debugutils/efence.vcproj:
+	* gst/debugutils/gstdebug.c:
+	* gst/debugutils/gstnavigationtest.c:
+	* gst/debugutils/gstnavigationtest.h:
+	* gst/debugutils/gstnavseek.c:
+	* gst/debugutils/gstnavseek.h:
+	* gst/debugutils/gstpushfilesrc.c:
+	* gst/debugutils/gstpushfilesrc.h:
+	* gst/debugutils/gsttaginject.c:
+	* gst/debugutils/gsttaginject.h:
+	* gst/debugutils/navigationtest.vcproj:
+	* gst/debugutils/negotiation.c:
+	* gst/debugutils/progressreport.c:
+	* gst/debugutils/progressreport.h:
+	* gst/debugutils/rndbuffersize.c:
+	* gst/debugutils/testplugin.c:
+	* gst/debugutils/tests.c:
+	* gst/debugutils/tests.h:
+	  debug: rename debug to debugutils to avoid clash with --disable-debug. Fixes #562168
+
+2009-04-15 15:43:04 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/debug/efence.c:
+	* gst/debug/efence.h:
+	* gst/debug/gstnavigationtest.h:
+	* gst/debug/gstnavseek.h:
+	* gst/debug/gstpushfilesrc.h:
+	* gst/debug/gsttaginject.h:
+	* gst/debug/progressreport.h:
+	* gst/debug/tests.h:
+	  debug: indent before renaming
+
+2009-04-15 14:07:57 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpg726depay.c:
+	  g726depay: add property for aal2 force
+
+2009-04-15 13:56:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpg726depay.c:
+	* gst/rtp/gstrtpg726depay.h:
+	  g726depay: implement RFC3551 packing
+	  We implemented the AAL2 packing, add the encoding-name for those to the caps and
+	  a property to force AAL2 decoding (always TRUE for now).
+	  Implement RFC3551 unpacking for regular G726.
+	  See #567140.
+
+2009-04-15 00:22:43 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph263pay.h:
+	  rtph263pay: fix build
+
+2009-04-14 18:52:48 +0200  Youness Alaoui <youness.alaoui at collabora.co.uk>
+
+	* gst/rtp/gstrtph263pay.c:
+	  h263pay: various fixes
+	  Re-enable mode A support and a property to control it.
+	  Fix memory leak of GstRtpH263PayBoundry objects.
+	  Fix marker.
+	  Fixes #509311
+
+2009-04-14 18:44:51 +0200  Janin Kolenc <janin.kolenc at marand.si>
+
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pay.h:
+	  h263pay: Fix the payloader
+	  Fix the H263 payloader to be more RFC 2190 compliant.
+	  See #509311
+
+2009-04-14 17:27:05 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: don't push EOS in streaming mode
+	  In streaming mode, avidemux is not supposed to send an EOS event downstream but
+	  it is supposed to return UNEXPECTED from the chain function instead so that
+	  upstream can do the right EOS handling.
+
+2009-04-13 14:03:03 +0200  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.c:
+	  Add initial support for muxing/demuxing Speex audio
+	  Note: This is not in the Matroska spec yet
+	  Fixes bug #578310.
+
+2009-04-10 21:31:06 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: handle NULL timing info
+	  Don't crash when the timing info is not yet available.
+
+2009-04-10 21:42:13 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	  pulse: make it work on 0.9.12
+	  First we ignore request to fill the ringbuffer which are less then a segment.
+	  The small request where causing stutter.
+	  Then we disable flushing the stream when running against pa 0.9.12 as this
+	  triggers an assertiong in the sound server and terminates it. It does not happen
+	  with 0.9.10 and 0.9.14.
+
+2009-04-10 14:18:48 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: handle server disconnect in get_time
+	  When the server is disconnected or when we are shut down, make our clock return
+	  an invalid time instead of erroring out.
+
+2009-04-10 12:01:27 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: bps is signed int to avoid overflow
+	  Keep bps as gint instead of guint because we will be doing signed math with it
+	  later on and we don't want weird results.
+
+2009-04-10 00:26:44 +0200  LRN <lrn1986 at gmail.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: add convert query, fix duration query
+	  Fix the duration query so that it also works with formats other than
+	  TIME, such as DEFAULT to get the number of frames.
+	  Add a convert function.
+	  Fixes #578052.
+
+2009-04-09 23:43:58 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: check for a stream
+	  Don't try to change the stream volume (and other things) when we don't have a
+	  stream yet. Just store the values for later.
+
+2009-04-09 18:07:38 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: fix compilation for newer pulseaudio
+
+2009-04-09 17:18:54 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: uncork fixes and use prebuf = 0
+	  We can use prebuf = 0 to instruct pulse to not pause the stream on underflows.
+	  This way we can remove the underflow callback. We however have to manually
+	  uncork the stream now when we have no available space in the buffer or when we
+	  are writing too far away from the current read_index.
+
+2009-04-09 14:38:17 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: handle write errors
+
+2009-04-09 14:16:35 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: write silence on underflow
+	  Start filling up the buffer with empty samples when an underflow happens. We
+	  need to do this to keep pulseaudio reporting the right time for us.
+
+2009-04-09 13:14:14 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: handle pull-based scheduling
+	  Use the default basesink methods for implementing pull based scheduling, it
+	  works fine for us.
+
+2009-04-09 12:13:44 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: add beginnings of pull-based scheduling
+
+2009-04-08 18:17:10 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: keep track of clock reset
+	  when we switch streams, the clock will reset to 0. Make sure that the provided
+	  clock doesn't get stuck when this happens by keeping an initial offset. We also
+	  need to make sure that we subtract this offset in samples when writing to the
+	  ringbuffer.
+
+2009-04-08 13:52:41 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	  pulsesink: rewrite pulsesink
+	  Derive from BaseAudioSink and implement our custom ringbuffer that maps to the
+	  internal pulseaudio ringbuffer.
+
+2009-04-08 13:52:00 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulseutil.c:
+	  pulse: remove some stray debug lines
+
+2009-04-09 11:30:59 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: use slightly more adaptive formula for QoS
+	  Should work at least a tad better if the decoder can't keep up, and
+	  should also spread dropped frames a bit more evenly over time.
+
+2009-04-07 22:35:31 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: don't leak pad-template
+	  gst_element_class_add_pad_template() does not take ownership.
+
+2009-04-04 21:18:55 +0300  Felipe Contreras <felipe.contreras@gmail.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From d0ea89e to b3941ea
+
+2009-04-01 01:15:31 +0200  Thomas Vander Stichele <thomas (at) apestaart (dot) org>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacdec.h:
+	  add pending_samples so that we only update segment's last stop after really sending the samples
+
+2009-03-15 21:31:49 +0100  Thomas Vander Stichele <thomas (at) apestaart (dot) org>
+
+	* tests/check/pipelines/flacdec.c:
+	  add debug and an assert
+
+2009-03-15 21:30:32 +0100  Thomas Vander Stichele <thomas (at) apestaart (dot) org>
+
+	* ext/flac/gstflacdec.c:
+	  add debugging
+
+2009-03-03 10:14:02 +0100  Thomas Vander Stichele <thomas (at) apestaart (dot) org>
+
+	* tests/check/Makefile.am:
+	* tests/check/audiotestsrc.flac:
+	* tests/check/pipelines/flacdec.c:
+	  add a test to check that we get all decoded bytes from a 10-buffer audiotestsrc flac, in the case of:  - a full decode  - a decode of a seek for the full file  - a decode of a seek for a small part, smaller than the first buffer
+	  The test fails because flacdec drops the first outgoing buffer on a seek
+
+2009-03-03 10:06:52 +0100  Thomas Vander Stichele <thomas (at) apestaart (dot) org>
+
+	* ext/flac/gstflacdec.c:
+	  clipping should also work if it's done on the first buffer starting at 0
+
+2009-04-04 14:54:01 +0200  Edward Hervey <bilboed@bilboed.com>
+
+	* common:
+	  Automatic update of common submodule
+	  From f8b3d91 to d0ea89e
+
+2009-04-03 09:57:15 +0100  Zaheer Merali <zaheerabbas@merali.org>
+
+	* gst/qtdemux/LEGAL:
+	  Fix grammar.
+
+2009-04-02 22:41:01 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: allow http:// on the proxy setting
+	  Allow and ignore http:// at the start of the proxy setting, like
+	  souphttpsrc.
+	  Fixes #573173
+
+2009-04-02 21:08:48 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: don't leak the udpsrc pad
+	  Fix memory leak in rtspsrc because we didn't unref the udpsrc pad.
+	  See #577318
+
+2009-04-01 17:31:18 -0700  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/rtp/gstrtptheorapay.c:
+	  rtptheorapay: fix length encoding in packed headers.
+	  As for vorbis payloader; this by inspection had the same bug.
+
+2009-04-01 17:23:33 -0700  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/rtp/gstrtpvorbispay.c:
+	  rtpvorbispay: in packed headers, properly flag multibyte lengths.
+	  In the sequence of header lengths, for headers >127 bytes, we use
+	  multiple bytes to encode the length. Bytes other than the last must have
+	  the top (flag) bit set.
+
+2009-04-02 00:20:02 +0100  Jonathan Matthew <jonathan@d14n.org>
+
+	* ext/taglib/gstid3v2mux.cc:
+	* tests/check/elements/id3v2mux.c:
+	  id3v2mux: write RVA2 frames containing peak/gain volume data
+
+2009-04-02 00:05:14 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: demote some log message from DEBUG to LOG
+	  And log decoder object.
+
+2009-04-01 21:15:02 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: implement basic QoS
+	  Don't decode frames that are going to be too late anyway.
+
+2009-04-01 12:26:12 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: don't emit ugly warnings with older rtpjitterbuffer versions
+	  The on-npt-stop signals was added only recently to rtpjitterbuffer in
+	  -bad, so check if the signal exists before g_signal_connect()ing to
+	  it, to avoid warnings.
+
+2009-03-31 19:08:37 +0200  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: add proxy support
+
+2009-03-31 17:16:04 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/matroska/matroska-mux.c:
+	  matroska: don't leak serialized values when writing tags
+
+2009-03-31 17:06:50 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska: don't alter passed data and especialy don't leak.
+	  If we need different size, Make a copy, work with that and free it.
+
+2009-03-31 16:42:15 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/goom/plugin_info.c:
+	  goom: the structure is not fully initialized, but the copied.
+	  Set to fully to 0 to avoid creep of uninitialized values.
+
+2009-03-31 16:25:58 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/matroska/matroska-mux.c:
+	  matroska: init endianess as such and signedness as boolean.
+
+2009-03-31 16:22:42 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: don't use ininitialized var in debug log statement
+	  Also make the log statement useful by printing the human readable format name.
+
+2009-03-31 12:01:21 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: don't leak atom data in case of a wrong fourcc
+
+2009-03-31 11:57:36 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/matroska/matroska-demux.c:
+	  matroska: don't leak read data in demuxer
+
+2009-03-31 11:50:41 +0300  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	  udp: don't use protocol in debug message after freeing
+
+2009-03-30 14:10:15 +0100  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4adepay.c:
+	  rtpmp4adepay: output should be framed already
+
+2009-03-27 21:17:05 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacdec.h:
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflacenc.h:
+	  flac: require a 'newer' flac and remove support for the legacy flac API
+
+2009-03-27 17:48:13 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: link to the on_npt_stop signal to EOS
+	  Connect to the on_npt_stop signal of the session manager to schedule the EOS
+	  actions.
+
+2009-03-26 14:39:06 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: some stream synchronization to aid seeking in unbalanced clips
+	  Some clips (trailers) may have (length-wise) unbalanced streams,
+	  which stalls the pipeline if seeking into that region.
+	  Additional stream synchronization can handle this, as well as
+	  sparse (subtitle) streams (at some later time ?)
+
+2009-03-26 10:31:18 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: additional safety and sanity checks (push based mode)
+
+2009-03-26 10:18:31 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: some more indent fixes
+
+2009-03-24 16:00:58 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/videomixer/videomixer.c:
+	  videomixer: fix gst-indent screwup
+
+2009-03-25 17:54:35 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtsp/gstrtsp.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* po/POTFILES.in:
+	  rtspsrc: better error message when the RTSP extension for Real streams is missing
+	  Try to post a decent error message when it looks like we're failing
+	  because the Real RTSP extension plugin is missing. Also add i18n
+	  bits for rtspsrc so our error messages get translated.
+
+2009-03-25 15:42:15 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/avi/gstavi.c:
+	* gst/qtdemux/quicktime.c:
+	  i18n: make sure gettext gives us UTF-8 at all times
+
+2009-03-25 01:28:38 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4adepay.c:
+	* gst/rtp/gstrtpmp4apay.c:
+	  rtpmp4apay,rtpmp4depay: fix buffer leaks in AAC payloader and depayloader
+
+2009-03-25 01:22:17 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4apay.c:
+	  rtpmp4apay: warn if input is unframed
+
+2009-03-22 21:20:57 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegdec.h:
+	  jpegdec: put GstSegment inside the element struct instead of allocating it separately
+
+2009-03-25 10:08:41 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2src: move duplicated timestamping and buffer metadata code to _create()
+	  This will include the latency changes also in the mmap case.
+
+2009-03-25 10:06:48 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2src: remove win32 ifdefs introduced by commit cff3f46760eac74c9bbd7a36aca44fedf327424b
+	  V4l2src is under sys and does not exists/run under windows anyway.
+
+2009-03-24 15:44:42 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: handle FLUSH_STOP event
+	  Clean up some state (most notably pad flow returns) to resume
+	  proper streaming following flushing seek.
+
+2009-03-24 12:42:13 +0100  Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: don't post an error if EOS can't be pushed downstream.
+	  This aligns avidemux with other demuxers and fixes a bug using avidemux
+	  with a recent gnonlin.
+
+2009-03-23 11:22:08 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: clean up the state change function
+	  Make the state change function a bit more readable and only pause after the
+	  parent had a change to pause first.
+
+2009-03-09 23:43:55 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/dtmf/Makefile.am:
+	  Makefile.am: no static libs for plugins
+
+2009-03-20 17:22:32 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: support seeking in push based mode
+
+2009-03-20 17:11:39 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: align push based behaviour more with pull based
+	  Cater for DELTA_UNIT flag on buffers, keep track of current
+	  position, remove and warn about edit lists if any (as those
+	  as are de facto discarded anyway), add some debug statements
+	  and indent fixes.
+
+2009-03-20 17:03:03 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: fix mem leaks and prevent excessive buffering in push based mode
+
+2009-03-20 13:27:59 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	  pulsesink: Track the corked/uncorked state ourselves
+	  Use an instance variable to track whether the stream is corked or not,
+	  instead of using PA API that was only introduced in 0.9.11
+
+2009-03-19 18:39:04 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulse: Make sure the stream is uncorked in the write function
+	  If the caps changes, the sink is reset without transitioning through
+	  a PAUSED->PLAYING state change, resulting in a corked stream. This avoids
+	  the problem by checking that the stream is uncorked when writing samples
+	  to it.
+
+2009-03-20 01:02:26 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/speex/gstspeexenc.c:
+	  speexenc: fix direction of latency query and other upstream queries
+	  Don't send queries back to the element they just came from by sending
+	  them to the peer of the wrong pad.
+
+2009-03-19 11:10:40 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* .gitignore:
+	* tests/check/elements/.gitignore:
+	  .gitignore: ignore more
+
+2009-03-18 16:55:27 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4adepay.c:
+	  rtpmp4adepay: don't append an extra 0 byte to the codec data
+	  The audioMuxVersion structure is packed in such a way that the codec
+	  data does not start byte-aligned, which means there's an extra bit of
+	  padding at the end. We don't want that bit in the codec data, since
+	  some decoders seem get confused when they're fed with an extra codec
+	  data byte (also it's just not right of course).
+
+2009-03-19 13:25:57 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	  rtph264depay: fix base64 decoding
+	  We can't pass -1 to _decode_step, that functions returns 0 right away instead of
+	  decoding up to the string end.
+
+2009-03-19 13:24:02 +0100  David Adam <zanchey at ucc.gu.uwa.edu.au>
+
+	* gst/udp/gstudpnetutils.c:
+	  udp: Fix build if on Solaris
+	  This patch checks for Solaris and uses ip_mreq instead of ip_mreqn if on this
+	  platform.
+	  Fixes #575937.
+
+2009-03-18 14:50:17 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/rtp/gstrtph264depay.c:
+	* gst/rtp/gstrtph264pay.c:
+	* gst/rtp/gstrtptheoradepay.c:
+	* gst/rtp/gstrtptheorapay.c:
+	* gst/rtp/gstrtpvorbispay.c:
+	  rtp: Use GLib functions for encoding/decoding base64
+
+2009-03-16 19:17:24 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: add some debug for the timestamps
+	  When timestamping in TCP mode, log the first timestamp we put on the buffers.
+
+2009-03-15 23:26:56 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2src: log details if we have them, needed for #575391
+
+2009-03-13 18:32:47 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: convert _ in properties to -
+	  --
+
+2009-03-13 18:28:59 +0100  Edgar E. Iglesias <edgar.iglesias@gmail.com>
+
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudpnetutils.c:
+	* gst/udp/gstudpnetutils.h:
+	* gst/udp/gstudpsrc.c:
+	* gst/udp/gstudpsrc.h:
+	  udpsrc: Add network interface selection
+	  Add network interface selection when joining multicast groups.
+	  Useful when using the udpsrc on multihomed hosts.
+	  Fixes #575234.
+	  API: GstUDPSrc::multicast-iface
+
+2009-03-13 15:43:52 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* sys/v4l2/v4l2_calls.c:
+	  v4l2src: Prepend to lists and reverse them at the end.
+	  Gratuitous micro-optimisation - prepend to lists and reverse them, rather
+	  than appending to them each time.
+
+2009-03-13 15:40:50 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* ext/pulse/pulsesink.c:
+	  pulsesink: Wait until there is enough room to write an entire segment
+	  When trying to write out a segment, wait until there is enough free space
+	  for the entire segment. This helps to reduce ripple in the clock reporting,
+	  where the app might query the playback position while only half a segment
+	  has been written (and is therefore reported by _delay(), even though
+	  the ring buffer has not yet been advanced)
+
+2009-03-12 20:38:42 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: don't send PAUSE when not connected
+	  don't send a PAUSE request when we are no longer connected.
+
+2009-03-12 16:10:25 +0100  Laszlo Pandy <laszlok2@gmail.com>
+
+	* ext/flac/gstflacdec.c:
+	  Don't call FLAC__ methods before it's initialized. Fixes #516031
+	  In the event handler, gst_flac_dec_sink_event(), two functions are called on
+	  the FLAC stream without checking if it has been initialized:
+	  FLAC__stream_decoder_flush()
+	  FLAC__stream_decoder_process_until_end_of_stream()
+	  Both these FLAC__*() functions modify the internal state of the FLAC stream.
+	  Later, when the buffers start flowing, gst_flac_dec_chain() tries to initialize
+	  the stream. the FLAC__stream_decoder_init_stream() call will fail because the
+	  previous calls to FLAC__*() changed the stream state so it is no longer in the
+	  initialized state.
+
+2009-03-11 17:59:00 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix timeout check
+	  ---
+
+2009-03-11 12:48:03 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* win32/MANIFEST:
+	  win32: update MANIFEST, fixing 'make dist'
+	  config.h.in no longer exists.
+
+2009-03-10 21:14:43 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/multipart/Makefile.am:
+	  makefile: fix typo in no-static plugins rule
+
+2009-03-10 11:01:16 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/libpng/gstpngdec.c:
+	  pngdec: various cleanups.
+	  Make some code more readable.
+	  Fix a leak when pull range returns a shot buffer.
+	  Push EOS after posting the error.
+
+2009-03-10 10:16:27 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/rtp/gstrtpvorbisdepay.c:
+	  gstrtpvorbisdepay: Fix build on macosx
+
+2009-03-01 17:37:56 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* .gitignore:
+	  .gitignore: Ignore m4 directory
+
+2009-03-09 23:12:33 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 7032163 to f8b3d91
+
+2009-03-09 18:07:20 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvorbisdepay.c:
+	  vorbisdepay: fix some leaks
+	  And leak the codebooks.
+	  Use glib base64 decoders.
+	  Use subbuffers to avoid a memcpy of the headers.
+
+2009-03-09 17:14:12 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacdec.h:
+	  flacdec: don't lose the first buffer after a seek
+	  The flacdec API calls the write callback when performing a seek. We cannot yet
+	  push out a buffer at that time so we must keep it and push it out later.
+	  Flush out the upstream part of the pipeline when doing a seek.
+	  Fixes #574275.
+
+2009-03-09 15:20:05 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/qtdemux/qtdemux.c:
+	  qtdemux: sanitize tag names
+	  Sanitize the tag names before turning them into a structure name. We can only
+	  add alphanumeric values as the structure name.
+
+2009-03-08 12:04:22 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From ffa738d to 7032163
+
+2009-03-08 11:19:56 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 3f13e4e to ffa738d
+
+2009-03-07 11:45:35 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 3c7456b to 3f13e4e
+
+2009-03-07 10:45:40 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* common:
+	  Automatic update of common submodule
+	  From 57c83f2 to 3c7456b
+
+2009-03-06 21:56:26 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2src: fix pads, so that they are subset of template caps
+	  Do not add w=0 | h=0. When we can't get a framerate add fraction range.
+
+2009-03-05 14:08:14 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: fix range parsing
+	  Fix parsing of the range headers.
+
+2009-02-10 17:20:57 +0000  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpsirendepay.c:
+	* gst/rtp/gstrtpsirendepay.h:
+	* gst/rtp/gstrtpsirenpay.c:
+	* gst/rtp/gstrtpsirenpay.h:
+	  Move siren rtp pay/depay from gst-plugins-farsight
+
+2009-03-04 16:25:34 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix memory leak in close
+	  Close the connection even when we fail to send the teardown message.
+	  Use the connection url (which is a copy of the src url).
+
+2009-03-04 16:15:05 +0100  Peter Kjellerstedt <pkj@axis.com>
+
+	* tests/check/Makefile.am:
+	  check: gst-plugins-good.supp needs to be distributed.
+
+2009-03-04 12:29:50 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: fix do-rtcp property description
+	  ---
+
+2009-03-03 12:20:27 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/soup/gstsouphttpsrc.h:
+	  souphttpsrc: Expose the SoupSession 'timeout' property.
+
+2009-03-02 15:07:24 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* .gitignore:
+	  .gitignore: Ignore the m4/ directory
+
+2009-03-02 17:18:55 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpmp4vpay.c:
+	  rtpmp4vpay: Add support for more formats
+	  Hack around short header mpeg4 video files and put the short header as the
+	  config string.
+	  Fixes #572551.
+
+2009-03-02 16:08:23 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: add support for http tunneling
+	  Add support for http tunneling and a new rtsph:// uri for it.
+	  See #573173.
+
+2009-03-02 09:43:30 +0100  Thomas Vander Stichele <thomas (at) apestaart (dot) org>
+
+	  Merge branch 'master' of ssh://thomasvs@git.freedesktop.org/git/gstreamer/gst-plugins-good
+
+2009-03-02 08:41:15 +0100  Thomas Vander Stichele <thomas (at) apestaart (dot) org>
+
+	* ext/flac/gstflacdec.c:
+	  Add/clarify/fix some logging.
+
+2009-03-01 12:47:37 -0800  David Schleef <ds@hutch-2.local>
+
+	* sys/osxvideo/Makefile.am:
+	  Remove hardcoded definition of OBJC
+
+2009-03-01 19:55:26 +0100  Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  Wait for a frame to become available before capturing it
+	  Use GstPoll to wait for the fd of the video device to become readable before
+	  trying to capture a frame. This speeds up stopping v4l2src a lot as it no
+	  longer has to wait for the next frame, especially when capturing with low
+	  framerates or when the video device just never generates a frame (which seems a
+	  common issue for uvcvideo devices)
+	  Fixes bug #563574.
+
+2009-02-14 17:56:05 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/law/alaw-decode.c:
+	* gst/law/mulaw-decode.c:
+	  alawdec, mulawdec: demote some debug messages from ERROR to WARNING or DEBUG
+	  Non-ok flow returns may happen for a variety of perfectly legitimate and expected reasons
+	  (temporarily not linked, seeking, pipeline shutdown), so we really shouldn't spew ERROR
+	  debug messages to stderr in those cases. Fixes #570781. (Seems like someone already took
+	  care of some of these.)
+
+2009-02-28 15:26:00 +0200  René Stadler <mail@renestadler.de>
+
+	* gst/replaygain/gstrgvolume.c:
+	  rgvolume: Improve log message for peak values >1.0 by clamping explicitly.
+
+2009-02-27 23:25:32 -0800  David Schleef <ds@schleef.org>
+
+	* ext/dv/gstdvdec.c:
+	  Fix the field dominance
+	  PAL is TFF, NTSC is BFF.  Some day I will learn to keep this
+	  straight.
+
+2009-02-27 20:40:31 +0100  LRN <lrn1986@gmail.com>
+
+	* sys/directdraw/gstdirectdrawsink.c:
+	  directdrawsink: Fix type mismatches
+	  Fixes bug #573343.
+
+2009-02-27 20:28:27 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	  Merge branch 'master' of ssh://git.freedesktop.org/git/gstreamer/gst-plugins-good
+
+2009-02-27 20:24:53 +0100  LRN <lrn1986@gmail.com>
+
+	* gst/udp/gstudpnetutils.c:
+	  udp: Don't set errno to EAFNOSUPPORT unconditionally
+	  Fixes bug #573342.
+
+2009-02-27 11:17:50 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* gst/replaygain/gstrgvolume.c:
+	  rgvolume: ignore out-of-range peak values
+	  If the peak value is > 1 (and thus nonsensical) ignore it. Prevents
+	  rgvolume reducing volume to effectively silent on files with bogus peak
+	  values.
+
+2009-02-27 13:29:41 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/wavparse/gstwavparse.c:
+	  wavparse: Fix SEEK event handling in push mode, and SEEKABLY query handling
+	  Standard pull mode loop based SEEK handling fails in push mode,
+	  so convert the SEEK event appropriately and dispatch to upstream.
+	  Also cater for NEWSEGMENT event handling, and properly inform
+	  downstream and application of SEEKABLE capabilities, depending
+	  on scheduling mode and upstream.
+
+2009-02-27 11:04:08 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Remove gst_util_dump_mem() calls.
+
+2009-02-26 19:07:35 +0100  Julien Moutte <julien@fluendo.com>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: fix SEEK event handling in push mode
+	  When in push mode we should not try to handle the SEEK event as there's
+	  no code to handle it properly. Propagate upstream.
+
+2009-02-26 19:05:06 +0100  Patrick Radizi <patrick dot radizi at axis dot com>
+
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: add the .h file change too
+	  Add the .h file change for the new property.
+
+2009-02-26 19:03:52 +0100  Patrick Radizi <patrick dot radizi at axis dot com>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: add property to disable RTCP
+	  Some old servers don't like us doing RTCP and thus we need a property to disable
+	  it. See #573173.
+
+2009-02-26 13:19:31 +0100  Jan Smout <jan dot smout at gmail dot com>
+
+	* gst/udp/gstudpnetutils.c:
+	  udp: fix gst_udp_set_loop_ttl() again
+	  Fix the gst_udp_set_loop_ttl() function that was commented out in a
+	  previous commit. See #573115.
+
+2009-02-26 13:06:17 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawdepay.c:
+	  rtpvrawdepay: fail on interlaced video
+	  Fail on interlaced video until we support it.
+
+2009-02-26 13:00:58 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtp/gstrtpvrawpay.c:
+	  rtpvrawpay: fail on interlaced video
+	  Detect and fail when trying to payload interlaced video.
+
+2009-02-25 20:47:15 -0800  David Schleef <ds@schleef.org>
+
+	* Makefile.am:
+	* configure.ac:
+	* win32/common/config.h.in:
+	  Change how win32/common/config.h is updated
+	  Generate win32/common/config.h-new directly from config.h.in,
+	  using shell variables in configure and some hard-coded information.
+	  Change top-level makefile so that 'make win32-update' copies the
+	  generated file to win32/common/config.h, which we keep in source
+	  control.  It's kept in source control so that the git tree is
+	  buildable from VS.
+	  This change is similar to the one recently applied to GStreamer
+	  and gst-plugins-good.  The previous config.h file in -good was in
+	  pretty bad shape, so unlike core and base, I didn't attempt to
+	  leave it strictly the same, but fixed it as necessary.  Needs
+	  testing I cannot do myself.
+
+2009-02-25 19:58:29 -0800  David Schleef <ds@schleef.org>
+
+	* ext/dv/gstdvdec.c:
+	* ext/dv/gstdvdec.h:
+	  dvdec: Add interlacing info to caps and buffers
+
+2009-02-25 14:57:33 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* common:
+	* configure.ac:
+	  build: Update shave init statement for changes in common. Bump common.
+
+2009-02-25 14:01:26 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: fix compilation
+	  Fix compilation on systems MSG_ERRQUEUE and IP_RECVERR.
+
+2009-02-19 20:14:10 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	  jpegenc: error out instead of crashing if no caps have been set
+	  Don't crash if we receive a buffer without caps. Fixes #572413.
+
+2009-02-25 11:35:31 +0100  Peter Kjellerstedt <pkj@axis.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Make sure the sockaddr length used for recvfrom() is big enough.
+	  Previously the sockaddr length used for recvfrom() was calculated as
+	  sizeof (struct sockaddr). However, this is too little to hold an IPv6
+	  address, so the full size of the gst_sockaddr union should be used
+	  instead.
+
+2009-02-25 11:32:28 +0100  Peter Kjellerstedt <pkj@axis.com>
+
+	* gst/udp/gstudpsrc.c:
+	  udpsrc: Unify the use of union gst_sockaddr.
+
+2009-02-25 11:32:07 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 9cf8c9b to a6ce5c6
+
+2009-02-25 12:05:22 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: avoid crashing on subtitles
+	  Avoid a crash in avi with subtitles by only dereferencing the video description
+	  when we actually are dealing with video in the _invert function.
+
+2009-02-25 11:45:05 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  docs: various doc fixes
+	  No short-desc as we have them in the element details.
+	  Also keep things (Makefile.am and sections.txt) sorted.
+	  Reword ambigous returns. No text after since please.
+
+2009-02-24 17:58:32 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/udp/gstudpsrc.c:
+	  udp: Fix strict-aliasing warnings from gcc 4.4.0
+	  Fix strict aliasing warnings by defining a union on the different
+	  sockaddr structs that we need.
+
+2009-02-24 17:35:46 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* gst/rtp/gstrtph264pay.c:
+	  rtp: Fix compiler warning in h264 payloader
+	  Fix an undefined behaviour warning from gcc 4.4.0
+	  Patch By: Tim-Philipp Müller <tim.muller@collabora.co.uk>
+	  Fixes: #570995
+	  Signed-Off-By: Jan Schmidt <jan.schmidt@sun.com>
+
+2009-02-22 17:23:09 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	  Use shave for the build output
+
+2009-02-24 14:55:28 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/gconf/Makefile.am:
+	* ext/gconf/gstgconf.c:
+	* ext/gconf/gstgconf.h:
+	* ext/gconf/gstgconfelements.h:
+	  gconf: Rename gconf.[ch] to gstgconf.[ch] to prevent name conflicts
+
+2009-02-24 14:41:26 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	  qtdemux: Also use "(c)inf" to fill the comment tag
+
+2009-01-26 11:06:13 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  rtspsrc: perform UDP SETUP according to MS RTSP spec
+	  MS RTSP spec states that the UDP port pair used in subsequent SETUP
+	  requests for various streams must be identical (since there will actually
+	  be only 1 stream of muxed asf packets).  Following traditional specs and
+	  using different port pairs in the SETUPs for separate streams will result
+	  in all but the first one failing and only one stream being streamed.
+	  So, in appropriate circumstances, retry UDP SETUP using previously used
+	  port pair.  Fixes #552650.
+
+2009-02-23 20:49:37 +0100  Aurelien Grimaud <gstelzz at yahoo dot fr>
+
+	* gst/udp/gstudpsrc.c:
+	  Read ICMP error messages instead of looping
+	  When we are dealing with connected sockets shared between a udpsrc and a udpsink
+	  we might receive ICMP connection refused error messages in udpsrc that will
+	  cause it to go into a bursty loop because the poll returns right away without a
+	  message to read.
+	  Instead of looping, read the error message from the error queue in udpsrc.
+	  Fixes #567857.
+
+2009-02-23 19:53:58 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  Conditionally compile code for YVYU
+	  Only compile the code for the YVYU format when the format is actually defined.
+	  Spotted by tmatth on IRC.
+
+2009-02-17 11:01:47 -0800  Levente Farkas <lfarkas@lfarkas.org>
+
+	* sys/v4l2/v4l2src_calls.c:
+	  v4l2src: Make sort_by_frame_size conditionally compiled
+	  sort_by_frame_size is declared static and only used inside
+	  an ifdef, so use the same ifdef to define the function.  Fixes #572185
+	  Signed-off-by: David Schleef <ds@schleef.org>
+
+2009-02-23 17:05:43 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* sys/v4l2/gstv4l2src.c:
+	  Add YVYU format to caps
+	  Add YVYU format to the caps. We don't have anything to handle these caps yet,
+	  though.
+
+2009-02-23 15:48:41 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstjpegenc.h:
+	  Some cleanups
+	  Remove some unused variables.
+	  Avoid a useless _resync call.
+	  Correctly use a gboolean.
+
+2009-02-23 15:43:51 +0100  Wai-Ming Ho <waiming at ailuropoda dot net>
+
+	* gst/rtp/gstrtph264pay.c:
+	  Always add PPS to the sprop-parameters-set
+	  Rework the parsing code that under certain circumstances dropped the PPS from
+	  the sprop-parameters-set.
+	  Fixes #572854.
+
+2009-02-23 12:14:23 +0100  Arnout Vandecappelle <arnout at mind dot be>
+
+	* gst/matroska/matroska-mux.c:
+	  Don't do crazy things with 0/1 framerates
+	  We use 0/1 framerates to mark variable framerates and matroskamux should not try
+	  to calculate a frame duration for it.
+	  Fixes #571294.
+
+2009-02-23 11:45:50 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* configure.ac:
+	  Require newer gst-p-b for the RTSP extensions.
+	  --
+
+2009-02-23 11:42:53 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  Call new receive_request method
+	  Call the receive_request extension methods so that extensions can handle the
+	  server request if they want.
+
+2009-02-23 11:13:30 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspext.c:
+	* gst/rtsp/gstrtspext.h:
+	  Add method for hadling server requests
+	  Add method to handle server requests on the list of RTSP extensions.
+
+2009-02-13 14:39:29 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/law/alaw-decode.c:
+	* gst/law/mulaw-decode.c:
+	  Don't use GST_ERROR for non-error cases.
+	  Turn a GST_ERROR line into a GST_DEBUG line so that we don't spam the log with
+	  errors. Fixes #570781.
+
+2009-02-22 19:30:32 +0100  Sjoerd Simons <sjoerd@luon.net>
+
+	* ext/gconf/gstgconfvideosink.c:
+	* ext/gconf/gstgconfvideosink.h:
+	* ext/gconf/gstgconfvideosrc.c:
+	* ext/gconf/gstgconfvideosrc.h:
+	  gconfvideo(src|sink): Disconnect GConf notifications
+	  Fixes bug #571321.
+
+2009-02-22 19:25:39 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/matroska/matroska-demux.c:
+	  matroskademux: Unref the buffer and not the memory address of the buffer
+
+2009-02-22 18:47:35 +0100  Olivier Crete <tester@tester.ca>
+
+	* gst/law/alaw-decode.c:
+	* gst/law/mulaw-decode.c:
+	  alaw/mulaw: Implement _getcaps function for alaw/mulaw decoders
+	  Fixes bug #572358.
+
+2009-02-22 18:46:03 +0100  Olivier Crete <tester@tester.ca>
+
+	* gst/law/alaw-encode.c:
+	* gst/law/mulaw-encode.c:
+	  alaw/mulaw: Don't require both, rate and channel, to be set in _getcaps
+	  Fixes bug #572358.
+
+2009-02-22 18:32:02 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/avi/gstavidemux.c:
+	  avidemux: Fix alignment issues by using GST_READ_*
+	  Reading integers from random memory addresses will result
+	  in SIGBUS on some architectures if the memory address
+	  is not correctly aligned. This can happen at two
+	  places in avidemux so we should use GST_READ_UINT32_LE
+	  and friends here. Fixes bug #572256.
+
+2009-02-22 18:08:59 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/pulse/pulsemixerctrl.c:
+	  pulsemixer: Don't use g_atomic_int_(get|set) for accessing the mixer track flags
+	  g_atomic_int_(get|set) only work on ints and the flags are
+	  an enum (which on most architectures is stored as an int).
+	  Also the way the flags were accessed atomically would still
+	  leave a possible race condition and we don't do it in any
+	  other mixer track implementation, let alone at any other
+	  place where an integer could be changed from different
+	  threads. Removing the g_atomic_int_(get|set) will only
+	  introduce a new race condition on architectures where
+	  integers could be half-written while reading them
+	  which shouldn't be the case for any modern architecture
+	  and if we really care about this we need to use
+	  g_atomic_int_(get|set) at many other places too.
+	  Apart from that g_atomic_int_(set|get) will result in
+	  aliasing warnings if their argument is explicitely
+	  casted to an int *. Fixes bug #571153.
+
+2009-02-22 15:52:06 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* common:
+	  Automatic update of common submodule
+	  From 5d7c9cc to 9cf8c9b
+
+2009-02-22 12:41:53 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* ext/raw1394/gsthdv1394src.c:
+	  hdv1394src: Don't use void * pointer arithmetic
+
+2009-02-21 11:13:43 -0800  David Schleef <ds@schleef.org>
+
+	* common:
+	  Automatic update of common submodule
+	  From 80c627d to 5d7c9cc
+
+2009-02-21 18:42:46 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* configure.ac:
+	  Back to development -> 0.10.14.1
+
+2009-02-20 18:16:02 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  Document rtpdtmfdepay a bit
+
+2009-02-20 17:41:37 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmf.c:
+	  Moved dtmf elements from gst-plugins-farsight to -bad
+
+2009-02-20 17:40:57 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	* gst/dtmf/gstrtpdtmfdepay.h:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  Fix up documentation blobs SGML
+
+2009-02-20 17:37:43 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmf.c:
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	* gst/dtmf/gstrtpdtmfcommon.h:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfdepay.h:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  Re-indent to Gst style
+
+2009-02-18 13:30:44 -0500  Laurent Glayal <spglegle@yahoo.fr>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Missing format directive
+
+2008-12-04 21:21:44 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfdepay.h:
+	  [MOVED FROM GST-P-FARSIGHT] Allow setting a maximum duration to a RTP DTMF event
+
+2008-12-04 21:11:17 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  [MOVED FROM GST-P-FARSIGHT] Improve the minimum quanta to make it impossible for the duration to fall down to 0
+
+2008-12-01 18:31:48 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfdepay.h:
+	  [MOVED FROM GST-P-FARSIGHT] Allow setting a minimum size of a sound quanta in the dtmf depayloader
+
+2008-12-11 17:54:18 -0500  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/.git-darcs-dir:
+	  [MOVED FROM GST-P-FARSIGHT] Remove .git-darcs-dir files
+
+2008-12-01 17:37:10 -0500  Håvard Graff <havard.graff@tandberg.com>
+
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  [MOVED FROM GST-P-FARSIGHT] Do wierd casting of the volume to make MSVC happy
+
+2008-10-15 16:21:50 -0400  Olivier Crête <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Clarify the documentation of the "event-type" field when specifying dtmf events
+
+2008-07-22 21:39:38 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Remove g_debugs
+	  20080722213938-3e2dc-44a82d017fe66f3112301c410aa0b543de6156ad.gz
+
+2008-06-13 23:57:23 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Take rate from the peers caps if possible
+	  20080613235723-3e2dc-15690ee42708c539e1be12e20e076a5613faea96.gz
+
+2008-06-13 23:41:44 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] Put the sample rate in dtmfsrc into a variable
+	  20080613234144-3e2dc-e60070943bec829b703b8821c7aa4351a02deebe.gz
+
+2008-06-13 23:30:06 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Take the clock-rate from the caps in rtpdtmfsrc
+	  20080613233006-3e2dc-a7d4e918643f4f8c1bb2cc2678558c654025920e.gz
+
+2008-04-28 22:22:37 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/Makefile.am:
+	  [MOVED FROM GST-P-FARSIGHT] Link modules with libm where required
+	  20080428222237-3e2dc-b1e9120c1e9ca1a510bfd7c27e2d45f0d4a12504.gz
+
+2008-04-12 23:44:18 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  [MOVED FROM GST-P-FARSIGHT] Fix byte ordering issues with dtmfsrc and rtpdtmfdepay.. use of G_STRINGIFY to avoid error on MSVC
+	  20080412234418-4f0f6-4828d1613dfcd564afd236dfc8fb57a299092f83.gz
+
+2008-03-20 19:14:38 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfdepay.h:
+	  [MOVED FROM GST-P-FARSIGHT] Fix copyrights again, per smcv's advice..
+	  20080320191438-4f0f6-671c9db5d996a4601df017ceab4af6d16469c966.gz
+
+2008-03-19 21:17:31 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Make it clear that dtmfsrc also takes named events as input
+	  20080319211731-3e2dc-26c729f6dc8db27e71cf6b22646a81530dbf862f.gz
+
+2008-03-20 18:48:41 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  [MOVED FROM GST-P-FARSIGHT] debug message made into errors because that's what they are...
+	  20080320184841-4f0f6-8a2d283297b02713dade0ae4acaa5f6e0f67eace.gz
+
+2008-03-20 18:39:37 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	  [MOVED FROM GST-P-FARSIGHT] Clean unused stuff...
+	  20080320183937-4f0f6-bcb841cdc07f9e9677512f4b50b4b659a58c6783.gz
+
+2008-03-20 18:39:12 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfdepay.h:
+	  [MOVED FROM GST-P-FARSIGHT] Fix copyrights
+	  20080320183912-4f0f6-689365d5a406632e3d088fac74e4fb6f8a4eb0ea.gz
+
+2008-03-20 01:13:01 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/Makefile.am:
+	* gst/dtmf/gstdtmf.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] Adding support for rtpdtmfdepay
+	  20080320011301-4f0f6-d36a5d24be20336e36c4796d75476c9b5ee1a7e1.gz
+
+2008-03-19 19:32:51 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] encoding name has to be upper-case
+	  20080319193251-3e2dc-1581b33be9b486e35ec4948009677ccd5ffdc098.gz
+
+2008-03-20 00:51:47 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfcommon.h:
+	* gst/dtmf/gstrtpdtmfdepay.c:
+	* gst/dtmf/gstrtpdtmfdepay.h:
+	  [MOVED FROM GST-P-FARSIGHT] Adding necessary files for rtpdtmfdepay
+	  20080320005147-4f0f6-550fe22f70152f3aab3dcd7a6b02cbf81e89232d.gz
+
+2008-03-20 00:50:41 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Fix typos
+	  20080320005041-4f0f6-9d22fa5d155e35b605ea85b1fd9e7197a882a1f0.gz
+
+2008-02-16 13:41:40 +0000  Sjoerd Simons <sjoerd@luon.net>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] dtmfsrc: Correctly set the endianess in the caps to the machines endianess
+	  20080216134140-93b9a-40a3a9d7ac1679c5e0dfd24a6b91e4aba6cc6496.gz
+
+2007-09-17 17:52:33 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Search&Replace oops
+	  20070917175233-3e2dc-57f579c4b890993f49fa8e9e6470a3eb79d2b922.gz
+
+2007-09-17 17:51:33 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] events dont yet belong in the caps
+	  20070917175133-3e2dc-fd1d83b7826b898110fc571ae7c3440f1887434d.gz
+
+2007-09-17 16:08:20 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Add patch to make it work with maemo dsp sources that payload incorrectly
+	  20070917160820-3e2dc-06b1b1d1b0918b30dabea5a0714cb732b3b8d8dd.gz
+
+2007-09-17 04:26:49 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Oops, set to no preroll when playing->paused too
+	  20070917042649-3e2dc-94adb6aa0617e815a6e233232dabb4bbc48dc82c.gz
+
+2007-09-17 00:36:54 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] Complete port to basesrc
+	  20070917003654-3e2dc-db0f84dabd9dd1ac929a0461865b8aaa8ef91a77.gz
+
+2007-09-17 00:24:12 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] Add caps negotiation function
+	  20070917002412-3e2dc-ca266816e9629746e9083c5bb8b7f73b94a9b2b0.gz
+
+2007-09-17 00:16:59 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Properly free non-start events
+	  20070917001659-3e2dc-a571777e3ecfb90989f87412f554aa10a31cc2ca.gz
+
+2007-09-17 00:15:52 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Make interval and packet_redundancy into uint
+	  20070917001552-3e2dc-60032e547b3669b87317c981d985c156aab91b40.gz
+
+2007-09-16 19:44:08 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] Make the rtp dtmf src use basesrc
+	  20070916194408-3e2dc-734000130dce2434a014acf843d641ff0e60aa5a.gz
+
+2007-09-16 19:41:01 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Make dtmf src code nicer
+	  20070916194101-3e2dc-a8be8c509c65400d1d3962da02e67d15d2054316.gz
+
+2007-09-14 04:20:42 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] Implement stopping in a nice thread safe way
+	  20070914042042-3e2dc-1fe257ff4b72aca4b0eb5f285a14650b8df268c3.gz
+
+2007-09-14 04:18:34 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Remove get_times (Wim says its only good for really fake sources)
+	  20070914041834-3e2dc-fff4d5da2a145f19e7b610a1027d2c4d4bc5eae0.gz
+
+2007-09-13 21:21:45 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] using the unlock method of basesrc
+	  20070913212145-4f0f6-0e438a681bf1651c0cc0d8fa3269aed3f1668b6b.gz
+
+2007-09-13 21:12:26 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] more debug
+	  20070913211226-4f0f6-bc32b5828fc8e0323c8a6eee779a38145aacd593.gz
+
+2007-09-13 20:46:14 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] added debugs
+	  20070913204614-4f0f6-68c2a69ae7a1efca6e13c116dbad7f9b686f0242.gz
+
+2007-09-13 19:20:53 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Make sure to unlock the thread when going to ready and to flush the queue when moving to paused or playing
+	  20070913192053-4f0f6-76c3925380d1a30988286170535a65dea64a5583.gz
+
+2007-09-13 17:55:20 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] Changed dtmfsrc into a subclass of GstBaseSrc
+	  20070913175520-4f0f6-16ca4bf93690072f3e836d1c8a5b52cf7a421916.gz
+
+2007-09-04 22:57:53 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] Add another fix for a possible race condition
+	  20070904225753-4f0f6-5ba8c4260c002bb27eb98e9faba3c15799357b57.gz
+
+2007-09-04 21:52:24 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Add comment to explain push back
+	  20070904215224-3e2dc-d92ac1f403dcf571546a7c53f18809f840eea51d.gz
+
+2007-09-04 20:55:09 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Properly do the locking to avoid race conditions with clock unscheduling
+	  20070904205509-3e2dc-da19900b51af6aedb6547f4f392bef4d1061dec2.gz
+
+2007-09-01 00:03:24 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] oups, I did it again...
+	  20070901000324-4f0f6-3d8b46691ee520537b06c511a5e732f5b812b844.gz
+
+2007-08-31 23:54:28 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] oups, sorry.. DTMF, not RTP_DTMF for this file...
+	  20070831235428-4f0f6-00b606bfb4892e4f217c440b611cc794ab0de55a.gz
+
+2007-08-31 23:44:13 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] Fixes the deadlock when pausing the dtmfsrc and rtpdtmfsrc. Had to push something on the async queue to release the blocking async_queue_pop(). Thanks to Olivier for the solution.
+	  20070831234413-4f0f6-793cf35fc43636e7275258cc7063fc068f5efa0a.gz
+
+2007-08-28 22:15:34 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] ClockID when waiting for buffer is now unscheduled when stopping the task. Various fixes to avoid bugs (thanks to -Wall -Werror). Fixes to allow the merge of the branch.
+	  20070828221534-4f0f6-b0d6a4fe48c4e2a16b9ff69cb310087c970ce48e.gz
+
+2007-08-28 17:15:46 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Cleaned up the code a bit, no use of GST_* and return value verification from gst_*
+	  20070828171546-4f0f6-bdeb4b1b7f99f9464aabe5c43bd4a4d2025262b6.gz
+
+2007-08-27 19:56:10 +0000  Olivier Crete <olivier.crete@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Fix overly long lines and tabs
+	  20070827195610-3e2dc-396a3fa01e16f184e4109c71fe2deb6e516bdf0d.gz
+
+2007-08-27 19:26:18 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] untabbified dtmfsrc
+	  20070827192618-4f0f6-77d68070464f1b5f9a46cb6eec2d922340143c04.gz
+
+2007-08-27 17:24:24 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Fix RTP timestamps by sending a new_segment event to the payloader
+	  20070827172424-4f0f6-d20907e3d436d50bfe74eb4fc3d2d6d7b6b6dbc5.gz
+
+2007-08-27 17:23:39 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Better handling of packets, we send the same duration for all packets to avoid huge packets when min duration defines are modified.
+	  20070827172339-4f0f6-cc93304437ea376fff6458c74c46c19f6920d329.gz
+
+2007-08-27 17:23:22 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] Changing minimum values to work better on some gateways
+	  20070827172322-4f0f6-5bf2bffa59a8244538dced795fa7d7649452ca91.gz
+
+2007-08-22 20:16:53 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] The DTMF tone generator now respects the volume argument passed in the event
+	  20070822201653-4f0f6-8b7ff874006e11f5a74d0fd91e5a9a43cd082ada.gz
+
+2007-08-22 18:01:33 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] don't know why I did that...
+	  20070822180133-4f0f6-6a7382f6c7d3630f91da384e1904763c7ea6fa1a.gz
+
+2007-08-22 17:55:33 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] Ported the event queue work from dtmfsrc to rtpdtmfsrc
+	  Added a queue based system for the rtpdtmfsrc. Now it waits for start/stop messages on the queue, and makes sure that the minimum duty cycle (120ms) is respected between each
+	  tone, including inter-digit silence.
+	  20070822175533-4f0f6-f27414c406f1f7b00c9a9084a988cf3a7930fe5c.gz
+
+2007-08-22 17:54:44 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	  [MOVED FROM GST-P-FARSIGHT] ouch, printing with arguments but without %s.. that made it segfault a few times...
+	  20070822175444-4f0f6-445ea6ce7a9668d04cf999af772a504ec74fb67a.gz
+
+2007-08-22 17:51:26 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] Moved the timestamp from the event to dtmfsrc structure since we have only one event at a time, so let's keep it stored in the dtmfsrc struct
+	  20070822175126-4f0f6-53bcda2bd8ae8c56d29e62e69ac19a30e08ad350.gz
+
+2007-08-20 20:38:26 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] Added a queue based system for the dtmfsrc. Now it waits for start/stop messages on the queue, and makes sure that the minimum duty cycle (120ms) is respected between each tone, including inter-digit silence.
+	  20070820203826-4f0f6-750a22b612a5e495e767666934465c34fe32074b.gz
+
+2007-08-20 18:48:52 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/Makefile.am:
+	* gst/dtmf/gstdtmf.c:
+	* gst/dtmf/gstdtmfsrc.c:
+	* gst/dtmf/gstdtmfsrc.h:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] Added dtmfsrc, a DTMF Tone Generator, and made it part of the 'dtmf' plugin.
+	  20070820184852-4f0f6-a0d85e67708290aebafa89ab79d3cedd5815b620.gz
+
+2007-08-20 18:48:00 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	* gst/dtmf/.git-darcs-dir:
+	* gst/dtmf/Makefile.am:
+	* gst/dtmf/gstrtpdtmfsrc.c:
+	* gst/dtmf/gstrtpdtmfsrc.h:
+	  [MOVED FROM GST-P-FARSIGHT] Moved rtpdtmf to dtmf directory
+	  20070820184800-4f0f6-fa33ea974510161de8c9951c39087af3613b65a4.gz
+
+2009-02-21 12:47:00 +0100  Thomas Vander Stichele <thomas (at) apestaart (dot) org>
+
+	* ext/flac/gstflacdec.c:
+	  respect DEFAULT segment by clipping the last buffer to be sent
+
+=== release 0.10.14 ===
+
+2009-02-19 20:09:07 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.10.14
+
+2009-02-19 20:07:41 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+
+2009-02-19 13:16:39 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst/audiofx/audioecho.c:
+	* gst/autodetect/gstautoaudiosrc.c:
+	* gst/autodetect/gstautovideosrc.c:
+	  Update Since: tags in autodetect srcs and audioecho
+
+2009-02-19 11:12:58 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* ChangeLog:
+	  Update ChangeLog for 0.10.13.3
+
+2009-02-19 11:09:03 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  0.10.13.3 pre-release
+
+2009-02-10 11:25:49 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/pulse/pulsemixerctrl.c:
+	  pulsemixer: Fix compiler warnings.
+	  Cast (enum *) to (int *), not necessarily technically right,
+	  but plugs #571153.
+
+2009-02-13 18:03:14 +0100  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	  pulsesink: Issue property change notification in streaming thread, rather than PA thread.
+	  pa_threaded_mainloop_lock() (a.o.) and by extension get_property should
+	  not be done from a PA thread, but the latter may occur as a result of a
+	  property change notification.  Fixes #571204 (though current situation
+	  not ideal, e.g. post message rather than signal).
+
+2009-02-10 11:27:51 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/videocrop/gstaspectratiocrop.c:
+	  aspectratiocrop: Don't forget to call parent finalize implementation.
+	  This fixes a memory leak (leaking the contained elements of the bin).
+
+2009-02-10 08:43:59 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: Fix build. Fixes #571038
+
+2009-02-09 12:18:36 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* common:
+	  Bump revision to use for common submodule.
+
+2009-02-07 16:00:49 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* ChangeLog:
+	  ChangeLog: Update ChangeLog for 0.10.13.2
+
+2009-02-07 15:58:55 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/mt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  po: Update translations for 0.10.13.2
+
+2009-02-07 15:46:07 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  Release 0.10.13.2
+
+2009-02-07 15:40:53 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* po/LINGUAS:
+	* po/mt.po:
+	  po: Add Maltese translation
+
+2009-02-06 16:16:05 -0800  David Schleef <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_dump.c:
+	* gst/qtdemux/qtdemux_dump.h:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	* gst/qtdemux/qtdemux_types.c:
+	  qtdemux: Add handling for stps atoms
+	  stps atoms contain "partial sync" information, which means that it's
+	  a sync point where pts != dts.  This is needed to properly handle
+	  MPEG2, H.264, Dirac, etc., in quicktime.
+
+2009-02-05 15:51:42 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* ext/flac/gstflacdec.c:
+	  flacdec: if we aborted reading, don't do into an infinite loop.
+	  If our read callback ran out of data, so had to abort reading, we return
+	  GST_FLOW_ERROR instead of going into an infinite loop.
+
+2009-02-05 10:19:37 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  osxvideosink: remove non-embedded mode and fix memory management.
+	  Remove non-embedded mode. Embed mode becomes default and only mode.
+	  embed property is retained for binary compatibility.
+	  Added autorelease pools around all objc functions that might be called
+	  from a non-main thread.
+
+2009-02-05 20:02:01 +0100  Thomas Vander Stichele <thomas (at) apestaart (dot) org>
+
+	* ext/flac/gstflacdec.c:
+	  debug on the object
+
+2009-02-04 16:40:13 -0800  Michael Smith <msmith@songbirdnest.com>
+
+	* sys/osxaudio/gstosxringbuffer.c:
+	  osxaudio fixes: multichannel and changing caps.
+	  Ensure we create the ringbuffer segment size as a multiple of the
+	  bytes per sample (fixes 6-channel output).
+	  Reset the segoffset when acquiring the ringbuffer, so we don't retain
+	  a bogus offset when caps change.
+
+2009-02-04 11:38:30 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	  rtspsrc: Keep track of connected state
+	  Keep track of the state of the connection and don't try to send TEARDOWN when
+	  the server has closed the connection.
+
+2009-02-04 09:20:28 +0100  Robin Stocker <robin@nibor.org>
+
+	* gst/matroska/matroska-demux.c:
+	  Read Matroska Title element for the TITLE tag
+	  Not all Matroska files have a Tags element which contains
+	  information about the title among other things. Most video
+	  Matroska files only contain the Title element so we
+	  should parse this too. Fixes bug #570435.
+
+2009-02-03 22:34:38 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* configure.ac:
+	  configure.ac: bump core/base requirements to released versions
+
+2009-02-03 17:10:30 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/check/elements/audioecho.c:
+	  Fix audioecho unit test on 32 bit systems
+	  Cast the new value for the "delay" property to GstClockTime.
+	  Integers without type are passed to vararg functions with
+	  an integer type that can hold a pointer.
+
+2009-02-03 14:09:26 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/equalizer/gstiirequalizer.c:
+	  equalizer: Don't reset frequency bands from user settings. Fixes #570343.
+	  Move reallocating the history buffer out of _compute_frequencies() and call the
+	  right function as needed. Add some logging and tweak the formatting of existing
+	  logging. Simplify setting need_new_coefficients when changing properties.
+
+2009-02-03 11:52:15 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audioecho.c:
+	  Use guint64 instead of guint for storing guint64
+
+2009-02-02 18:37:35 +0100  Jonathan Matthew <notverysmart@gmail.com>
+
+	* ext/soup/gstsouphttpsrc.c:
+	  Use correct flag for the GNOME proxy configuration
+	  Fixes bug #552140.
+
+2009-02-02 13:08:14 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* tests/icles/v4l2src-test.c:
+	  Fix compiler warnings
+	  fix compiler warnings due to unused return values of scanf.
+
+2009-01-31 11:08:30 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* tests/icles/v4l2src-test.c:
+	  Fix format string compiler warning
+
+2009-01-30 22:24:14 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  Add releaseinfo with online url.
+
+2009-01-30 18:04:11 +0000  Jan Schmidt <jan.schmidt@sun.com>
+
+	* tests/check/Makefile.am:
+	* tests/icles/Makefile.am:
+	  Fix up some compile flags
+
+2009-01-30 17:35:49 +0000  Jan Schmidt <jan.schmidt@sun.com>
+
+	* gst/videocrop/gstvideocrop.c:
+	  Don't use Glib 2.16 function g_strcmp0.
+
+2009-01-30 17:34:45 +0000  Jan Schmidt <jan.schmidt@sun.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  Don't do void pointer arithmetic
+
+2009-01-30 17:26:19 +0000  Jan Schmidt <jan.schmidt@sun.com>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	  Fix Forte compiler warnings.
+	  Don't do void pointer arithmetic. Don't have an unreachable statement.
+
+2009-01-30 17:29:45 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* common:
+	  Bump common
+
+2009-01-26 10:33:55 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/avi/gstavidemux.c:
+	  Remove useless processing for non-raw formats
+
+2009-01-30 15:34:31 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux_fourcc.h:
+	* gst/qtdemux/qtdemux_types.c:
+	  Add support for the 'Requirement' and 'Encoder' tags
+
+2009-01-30 15:33:19 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  Modify private-tag name formatter so that it doesn't go mad at fourcc starting with '(c)'.
+
+2009-01-30 14:40:51 +0100  Brijesh Singh <brijesh.ksingh@gmail.com>
+
+	* sys/v4l2/gstv4l2tuner.c:
+	  Fix comparison of the tuner norms
+	  The V4L2 tuner norms that a device supports could
+	  be a subset of some norm (e.g. NTSC instead of NTSC_M).
+	  The comparison should be done by & instead of ==.
+	  See http://www.linuxtv.org/downloads/video4linux/API/V4L2_API/spec-single/v4l2.html#STANDARD
+	  Fixes bug #569820.
+
+2009-01-30 08:53:06 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* autogen.sh:
+	* common:
+	  Use a symbolic link for the pre-commit client-side hook
+
+2009-01-29 14:08:56 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/videocrop/gstaspectratiocrop.c:
+	  Only unref the peer when there is one.
+
+2009-01-29 11:07:59 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/avi/gstavimux.c:
+	* gst/interleave/deinterleave.c:
+	* gst/interleave/interleave.c:
+	* sys/directdraw/gstdirectdrawsink.c:
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/osxvideo/osxvideosink.m:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/waveform/gstwaveformsink.c:
+	  Remove version numbers from a few gst-launch examples.
+	  The majority of the examples doe not use -0.10 and this will also help us to maintain the docs.
+
+2009-01-29 10:10:08 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* sys/directdraw/gstdirectdrawsink.c:
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/oss/gstossmixerelement.c:
+	* sys/oss/gstosssink.c:
+	* sys/oss/gstosssrc.c:
+	* sys/osxaudio/gstosxaudio.c:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxvideo/osxvideosink.m:
+	* sys/sunaudio/gstsunaudiomixer.c:
+	* sys/sunaudio/gstsunaudiosink.c:
+	* sys/sunaudio/gstsunaudiosrc.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/waveform/gstwaveformsink.c:
+	* sys/ximage/gstximagesrc.c:
+	  Update and add documentation for platform specific plugins (sys).
+	  Link to properties. Correct titles for examples. Fix examples.
+
+2009-01-29 09:45:25 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* gst/multipart/multipartmux.c:
+	  Add ' to framerate argument and remove the word 'simple' as all our pipelines are apparently simple.
+
+2009-01-29 09:42:56 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	  Add examples for the jpeg elements.
+
+2009-01-28 21:40:11 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* ext/pulse/pulsesink.c:
+	  Fix compile error in the last commit
+
+2009-01-28 20:34:40 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* configure.ac:
+	* ext/pulse/pulseprobe.c:
+	* ext/pulse/pulseprobe.h:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesink.h:
+	* ext/pulse/pulsesrc.c:
+	* ext/pulse/pulsesrc.h:
+	* ext/pulse/pulseutil.c:
+	* ext/pulse/pulseutil.h:
+	  Rewrite the pulse plugin, conditionally enabling new behaviour with newer pulseaudio.
+	  Fixes: #567794
+	  * Hook pulsesink's volume property up with the stream volume -- not the
+	  sink volume in PA.
+	  * Read the device description directly from the sink instead of going
+	  via the mixer.
+	  * Properly implement _reset() methods for both sink and source to avoid
+	  deadlocks when shutting down a pipeline.
+	  * Replace all simple pa_threaded_mainloop_wait() by proper loops to
+	  guarantee that we wait for the right event in case multiple events are
+	  fired.  While this is not strictly necessary in many cases it
+	  certainly is more correct and makes me sleep better at night.
+	  * Replace CHECK_DEAD_GOTO macros with proper functions
+	  * Extend the number of supported channels to 32 since that is the actual
+	  limit in PA.
+	  * Get rid of _dispose() methods since we don't need them.
+	  * Increase the volume property upper limit of the sink to 1000.
+	  * Reset function pointers after we disconnect a stream/context. Better
+	  fix for bug 556986.
+	  * Reset the state of the element properly if open/prepare fails
+	  * Cork the PA stream when the pipeline is paused. This allows the PA
+	  * daemon to
+	  close audio device on pause and thus save a bit of power.
+	  * Set PA stream properties based on GST tags such as GST_TAG_TITLE,
+	  GST_TAG_ARTIST, and so on.
+	  Signed-off-by: Lennart Poettering <lennart@poettering.net>
+
+2009-01-28 17:46:06 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* ext/aalib/gstaasink.c:
+	* ext/annodex/gstcmmldec.c:
+	* ext/annodex/gstcmmlenc.c:
+	* ext/cairo/gsttextoverlay.c:
+	* ext/cairo/gsttimeoverlay.c:
+	* ext/dv/gstdvdec.c:
+	* ext/dv/gstdvdemux.c:
+	* ext/esd/esdmon.c:
+	* ext/esd/esdsink.c:
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacenc.c:
+	* ext/gconf/gstgconfaudiosink.c:
+	* ext/gconf/gstgconfaudiosrc.c:
+	* ext/gconf/gstgconfvideosink.c:
+	* ext/gconf/gstgconfvideosrc.c:
+	* ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	* ext/hal/gsthalaudiosink.c:
+	* ext/hal/gsthalaudiosrc.c:
+	* ext/hal/hal.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstsmokedec.c:
+	* ext/jpeg/gstsmokeenc.c:
+	* ext/libcaca/gstcacasink.c:
+	* ext/libcaca/gstcacasink.h:
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngenc.c:
+	* ext/pulse/pulsemixer.c:
+	* ext/pulse/pulsesink.c:
+	* ext/pulse/pulsesrc.c:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gsthdv1394src.c:
+	* ext/soup/gstsouphttpsrc.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	* ext/taglib/gstapev2mux.cc:
+	* ext/taglib/gstid3v2mux.cc:
+	* ext/wavpack/gstwavpackdec.c:
+	* ext/wavpack/gstwavpackenc.c:
+	* ext/wavpack/gstwavpackparse.c:
+	* gst/matroska/matroska-mux.h:
+	* gst/udp/gstudpsrc.c:
+	  Update and add documentation for plugins with deps (ext).
+	  Link to properties. Correct titles for examples. Document a few trivial cases. Keep lists in section file and docs/plugins/Makefile.am alphabetically ordered. Fix warnings that gtk-doc points out.
+
+2009-01-28 15:57:20 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audioecho.h:
+	  Limit the delay by a new max-delay property
+	  Introduce a new max-delay property that can only
+	  be set before going to PLAYING or PAUSED. This
+	  is used to limit the maximum delay and is set
+	  to the current delay by default.
+	  Using this will make sure that we have enough data
+	  in our internal ringbuffer for the echo. With dynamic
+	  reallocation of the ringbuffer as used before silence
+	  could've been used as the echo directly after setting
+	  a new delay.
+
+2009-01-28 11:58:42 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* win32/common/config.h:
+	  Revert previous bogus commit
+
+2009-01-28 12:29:42 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/gst-plugins-good-plugins.interfaces:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* gst/alpha/gstalphacolor.c:
+	* gst/apetag/gstapedemux.c:
+	* gst/audiofx/audioamplify.c:
+	* gst/audiofx/audiochebband.c:
+	* gst/audiofx/audiocheblimit.c:
+	* gst/audiofx/audiodynamic.c:
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audiofirfilter.c:
+	* gst/audiofx/audioiirfilter.c:
+	* gst/audiofx/audioinvert.c:
+	* gst/audiofx/audiokaraoke.c:
+	* gst/audiofx/audiopanorama.c:
+	* gst/audiofx/audiowsincband.c:
+	* gst/audiofx/audiowsinclimit.c:
+	* gst/auparse/gstauparse.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavimux.c:
+	* gst/cutter/gstcutter.c:
+	* gst/debug/gstpushfilesrc.c:
+	* gst/debug/gsttaginject.c:
+	* gst/debug/progressreport.c:
+	* gst/equalizer/gstiirequalizer10bands.c:
+	* gst/equalizer/gstiirequalizer3bands.c:
+	* gst/equalizer/gstiirequalizernbands.c:
+	* gst/flx/gstflxdec.c:
+	* gst/goom/gstgoom.c:
+	* gst/goom2k1/gstgoom.c:
+	* gst/icydemux/gsticydemux.c:
+	* gst/id3demux/gstid3demux.c:
+	* gst/law/alaw-decode.c:
+	* gst/law/alaw-encode.c:
+	* gst/law/mulaw-decode.c:
+	* gst/law/mulaw-encode.c:
+	* gst/law/mulaw.c:
+	* gst/level/gstlevel.c:
+	* gst/monoscope/gstmonoscope.c:
+	* gst/multifile/gstmultifilesink.c:
+	* gst/multifile/gstmultifilesrc.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartmux.c:
+	* gst/qtdemux/qtdemux.c:
+	* gst/rtp/gstrtpjpegpay.c:
+	* gst/rtsp/gstrtpdec.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/smpte/gstsmpte.c:
+	* gst/smpte/gstsmptealpha.c:
+	* gst/spectrum/gstspectrum.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsrc.c:
+	* gst/videobox/gstvideobox.c:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videomixer/videomixer.c:
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavparse/gstwavparse.c:
+	* win32/common/config.h:
+	  Update and add documentation for plugins with no deps (gst).
+	  Link to properties. Correct titles for examples. Document a few trivial cases. Keep lists in section file and docs/plugins/Makefile.am alphabetically ordered.
+
+2009-01-27 23:09:05 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* tests/examples/spectrum/demo-audiotest.c:
+	* tests/examples/spectrum/demo-osssrc.c:
+	  Fix example apps by drawing in the main-loop.
+
+2009-01-27 20:33:02 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* tests/check/Makefile.am:
+	  tests: fix build of aspectratio crop unit test in uninstalled environment.
+
+2009-01-27 20:30:02 +0000  Tim-Philipp Müller <tim.muller@collabora.co.uk>
+
+	* .gitignore:
+	  Make git ignore backup files
+
+2009-01-26 16:14:47 +0100  Peter Kjellerstedt <pkj@axis.com>
+
+	* gst/multipart/multipartdemux.c:
+	  Plug a memory leak in a debug message.
+
+2009-01-22 15:59:40 +0100  Peter Kjellerstedt <pkj@axis.com>
+
+	* gst/udp/gstudpnetutils.c:
+	  Correct return value from gst_udp_get_addr() when no known family is found.
+
+2009-01-26 09:51:36 +0100  Jonathan Matthew <jonathan@d14n.org>
+
+	* configure.ac:
+	* ext/soup/gstsouphttpsrc.c:
+	  Use libsoup-gnome for proxy configuration if available
+	  If libsoup-gnome is found use this as it will give us
+	  the GNOME proxy configuration. Otherwise use normal
+	  libsoup.
+	  The GNOME proxy configuration will only be used if
+	  the proxy properties are not set on souphttpsrc
+	  and if the http_proxy environment variable is not
+	  set.
+	  Fixes bug #552140.
+
+2009-01-25 19:26:46 -0800  David Schleef <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c:
+	  Add a few more video fourcc's
+
+2009-01-24 14:48:00 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/videocrop/gstaspectratiocrop.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/aspectratiocrop.c:
+	  Add unit test for aspectratiocrop Fixes bug #527951
+	  Add unit test for aspectratiocrop and refactor this element. Added
+	  finalize function to cleanup leaking mutex.
+
+2009-01-25 14:34:09 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* tests/check/elements/.gitignore:
+	  Ignore check binaries
+
+2009-01-24 18:28:06 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audioecho.c:
+	  Save some allocations if the echo delay is increased often
+	  Save some allocations if the echo delay is increased often
+	  during playback by always allocating enough memory to hold
+	  data up to the next complete second, i.e. in the worst case
+	  allocate memory for one additional second.
+
+2009-01-24 14:25:08 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	  Update plugin version in documentation
+
+2009-01-23 21:47:40 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/videocrop/gstvideocrop.c:
+	  Fix link in documentation of videocrop element
+
+2009-01-23 21:46:13 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* 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:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* gst/videocrop/gstaspectratiocrop.c:
+	  Add documentation for aspectratiocrop
+
+2009-01-24 13:21:39 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* win32/common/config.h:
+	  Update win32/common/config.h for the new development cycle
+
+2009-01-24 11:53:40 +0100  Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
+	* gst/audiofx/audioecho.c:
+	  Add note that audioecho's reverb sounds metallic
+	  Add a note to the docs that audioecho's reverb will
+	  sound metallic. This happens because for a real
+	  reverb filter additional filtering is necessary.
+	  Also note which values should be used for the delay
+	  property to get an echo effect.
+
+2009-01-23 23:38:10 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* .gitignore:
+	* docs/plugins/.gitignore:
+	* po/.gitignore:
+	* tests/examples/audiofx/.gitignore:
+	  More entries for the gitignores
+
+2009-01-23 20:36:27 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* tests/check/elements/videocrop.c:
+	  skip video/x-raw-gray in videocrop unit test
+	  A recent commit added video/x-raw-gray support to videocrop. However
+	  this lets the videocrop unit test fail. Because videotestsrc can't
+	  generate this format.
+
+2009-01-23 15:39:46 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/videocrop/Makefile.am:
+	* gst/videocrop/gstaspectratiocrop.c:
+	* gst/videocrop/gstaspectratiocrop.h:
+	* gst/videocrop/gstvideocrop.c:
+	  Add aspectratiocrop element. Fixes bug #527951
+	  Add new aspectratiocrop element that crops the video
+	  to a specified aspect ratio using videocrop.
+
+2009-01-23 10:49:28 +0100  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	* gst/videocrop/gstvideocrop.c:
+	  Fix navigation event forwarding while cropping. Fixes bug #567992.
+	  Fix the navigation event forwarding while cropping by adjusting
+	  the mouse position by the amount of cropped pixels.
+
+2009-01-23 10:04:39 +0100  Brian Cameron <brian.cameron@sun.com>
+
+	* configure.ac:
+	  Fix linking on Solaris. Fixes bug #568809.
+	  Check for the socket library which is needed
+	  for socket() on Solaris.
+
+2009-01-22 22:41:43 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* configure.ac:
+	  Bump version number again -> 0.10.13.1
+
+2009-01-22 22:41:01 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* gst-plugins-good.doap:
+	  Add releases 0.10.12 and 0.10.13 to the doap file
+
+2009-01-22 18:08:50 +0200  Stefan Kost <ensonic@users.sf.net>
+
+	* common:
+	  Update common snapshot.
+
+2009-01-22 14:25:07 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* configure.ac:
+	* win32/common/config.h:
+	  Back to devel -> 0.10.12.1
+
+2009-01-22 01:29:40 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* configure.ac:
+	  Release 0.10.12
+
+2009-01-21 17:22:39 -0800  David Schleef <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c:
+	  Fix for security advisory TKADV2009-0xx
+	  Fix potential buffer overflows while reading quicktime headers.
+	  Security issue noticed by Tobias Klein.
+
+2009-01-21 12:56:55 +0000  Jan Schmidt <thaytan@noraisin.net>
+
+	* ext/flac/gstflacdec.c:
+	  Fix typo and small flaw in flac decoder
+
+2009-01-22 13:49:35 +0100  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* common:
+	  Fix pre-commit hook
+
+2009-01-22 10:40:34 +0100  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* gst/audiofx/Makefile.am:
+	* gst/audiofx/audioecho.c:
+	* gst/audiofx/audioecho.h:
+	* gst/audiofx/audiofx.c:
+	* tests/check/Makefile.am:
+	* tests/check/elements/audioecho.c:
+	  Rename audioreverb to audioecho. Fixes bug #568395.
+	  The element can add an echo and a simple reverb effect to
+	  an audio stream but for a real reverb filter it would need
+	  some additional filtering to prevent a metallic-sounding
+	  result.
+
+2009-01-22 12:21:29 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* gst/rtsp/gstrtspsrc.c:
+	  Free leftover udp ports (if any) when a setup request fails.
+
+2009-01-22 06:05:26 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* autogen.sh:
+	* common:
+	  Install and use pre-commit indentation hook from common
+
+2009-01-21 13:25:06 +0100  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	* ext/flac/gstflacdec.c:
+	  Whitespace fixes and some improved debug lines.
+
+2009-01-21 04:31:58 +0100  Edward Hervey <bilboed@bilboed.com>
+
+	* autogen.sh:
+	  autogen.sh : Use git submodule
+
+2009-01-20 15:33:05 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/v4l2/gstv4l2src.c: Fix error code (the message string also needs love, but not today).
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_get_read):
+	  Fix error code (the message string also needs love, but not today).
+
+2009-01-19 11:44:36 +0000  Luotao Fu <l.fu@pengutronix.de>
+
+	  gst/videocrop/gstvideocrop.c: Add 8bit grayscale support to videocrop plugin. Fixes #567952.
+	  Original commit message from CVS:
+	  Patch by: Luotao Fu <l dot fu at pengutronix dot de>
+	  * gst/videocrop/gstvideocrop.c:
+	  (gst_video_crop_get_image_details_from_caps):
+	  Add 8bit grayscale support to videocrop plugin. Fixes #567952.
+
+2009-01-19 11:22:06 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/audioreverb.c: Set the default value in the instance init function.
+	  Original commit message from CVS:
+	  * gst/audiofx/audioreverb.c: (gst_audio_reverb_init):
+	  Set the default value in the instance init function.
+
+2009-01-19 11:19:08 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Add an echo/reverb filter to the audiofx plugin, with configurable echo delay, intensity and feedback. Fixes bug #567...
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  * docs/plugins/inspect/plugin-spectrum.xml:
+	  * gst/audiofx/Makefile.am:
+	  * gst/audiofx/audiofx.c: (plugin_init):
+	  * gst/audiofx/audioreverb.c: (gst_audio_reverb_base_init),
+	  (gst_audio_reverb_class_init), (gst_audio_reverb_init),
+	  (gst_audio_reverb_finalize), (gst_audio_reverb_set_property),
+	  (gst_audio_reverb_get_property), (gst_audio_reverb_setup),
+	  (gst_audio_reverb_stop), (gst_audio_reverb_transform_ip):
+	  * gst/audiofx/audioreverb.h:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/audioreverb.c: (setup_reverb),
+	  (cleanup_reverb), (GST_START_TEST), (audioreverb_suite):
+	  Add an echo/reverb filter to the audiofx plugin, with configurable
+	  echo delay, intensity and feedback. Fixes bug #567874.
+
+2009-01-19 10:13:53 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/spectrum/gstspectrum.*: Implement a simple compensation algorithm for rounding errors.
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_reset_state),
+	  (gst_spectrum_transform_ip):
+	  * gst/spectrum/gstspectrum.h:
+	  Implement a simple compensation algorithm for rounding errors.
+	  This makes sure that a spectrum message is posted on the bus
+	  every interval nanoseconds. Fixes bug #567955.
+
+2009-01-15 21:16:45 +0000  Michael Smith <msmith@xiph.org>
+
+	  sys/osxaudio/Makefile.am: Link against CoreServices (needed for osx 10.4) and fix up the linker flags. Fixes #567853.
+	  Original commit message from CVS:
+	  * sys/osxaudio/Makefile.am:
+	  Link against CoreServices (needed for osx 10.4) and fix up the linker
+	  flags. Fixes #567853.
+
+2009-01-15 14:53:18 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Catch invalid and commonly wrong playback rates in the elst atoms.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_segments):
+	  Catch invalid and commonly wrong playback rates in the elst atoms.
+	  Fixes #567800.
+
+2009-01-15 11:40:23 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/spectrum/gstspectrum.c: Don't call gst_fft_f32_free() with NULL to prevent a crash. Fixes bug #567642.
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_reset_state):
+	  Don't call gst_fft_f32_free() with NULL to prevent a
+	  crash. Fixes bug #567642.
+
+2009-01-14 15:44:18 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/spectrum/gstspectrum.*: Use correct types for frame/fft counters and some minor cleanup.
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_transform_ip):
+	  * gst/spectrum/gstspectrum.h:
+	  Use correct types for frame/fft counters and some minor
+	  cleanup.
+
+2009-01-14 15:37:07 +0000  Lennart Poettering <lennart@poettering.net>
+
+	  ext/pulse/pulseprobe.c: Fix refcount loop, resulting in a thread leak. Fixes bug #567746.
+	  Original commit message from CVS:
+	  Patch by: Lennart Poettering <lennart at poettering dot net>
+	  * ext/pulse/pulseprobe.c: (gst_pulseprobe_new),
+	  (gst_pulseprobe_free):
+	  Fix refcount loop, resulting in a thread leak. Fixes bug #567746.
+
+2009-01-14 10:46:54 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/spectrum/: Post a spectrum message on the bus for every interval, even if the interval is small than the length o...
+	  Original commit message from CVS:
+	  * gst/spectrum/Makefile.am:
+	  * gst/spectrum/README:
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_base_init),
+	  (gst_spectrum_class_init), (gst_spectrum_init),
+	  (gst_spectrum_reset_state), (gst_spectrum_finalize),
+	  (gst_spectrum_set_property), (gst_spectrum_start),
+	  (gst_spectrum_stop), (gst_spectrum_setup),
+	  (gst_spectrum_transform_ip):
+	  * gst/spectrum/gstspectrum.h:
+	  Post a spectrum message on the bus for every interval, even
+	  if the interval is small than the length of the FFT.
+	  Fixes bug #567642.
+	  Major cleanup of the spectrum element.
+
+2009-01-13 19:23:57 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Add audioiirfilter and audiofirfilter elements which allow generic IIR/FIR filters to be implemented by providing the...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/audiofx/Makefile.am:
+	  * gst/audiofx/audiofirfilter.c: (gst_audio_fir_filter_base_init),
+	  (gst_audio_fir_filter_class_init),
+	  (gst_audio_fir_filter_update_kernel), (gst_audio_fir_filter_init),
+	  (gst_audio_fir_filter_setup), (gst_audio_fir_filter_finalize),
+	  (gst_audio_fir_filter_set_property),
+	  (gst_audio_fir_filter_get_property):
+	  * gst/audiofx/audiofirfilter.h:
+	  * gst/audiofx/audiofx.c: (plugin_init):
+	  * gst/audiofx/audioiirfilter.c: (gst_audio_iir_filter_base_init),
+	  (gst_audio_iir_filter_class_init),
+	  (gst_audio_iir_filter_update_coefficients),
+	  (gst_audio_iir_filter_init), (gst_audio_iir_filter_setup),
+	  (gst_audio_iir_filter_finalize),
+	  (gst_audio_iir_filter_set_property),
+	  (gst_audio_iir_filter_get_property):
+	  * gst/audiofx/audioiirfilter.h:
+	  Add audioiirfilter and audiofirfilter elements which allow
+	  generic IIR/FIR filters to be implemented by providing the
+	  filter coefficients. Fixes bug #567577.
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-good-plugins.signals:
+	  * docs/plugins/inspect/plugin-alaw.xml:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  * docs/plugins/inspect/plugin-avi.xml:
+	  * docs/plugins/inspect/plugin-flac.xml:
+	  * docs/plugins/inspect/plugin-mulaw.xml:
+	  * docs/plugins/inspect/plugin-video4linux2.xml:
+	  * docs/plugins/inspect/plugin-wavparse.xml:
+	  Add documentation for the audioiirfilter and audiofirfilter
+	  elements.
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/audiofirfilter.c: (on_message),
+	  (on_rate_changed), (on_handoff), (GST_START_TEST),
+	  (audiofirfilter_suite):
+	  * tests/check/elements/audioiirfilter.c: (on_message),
+	  (on_rate_changed), (on_handoff), (GST_START_TEST),
+	  (audioiirfilter_suite):
+	  * tests/examples/Makefile.am:
+	  * tests/examples/audiofx/Makefile.am:
+	  * tests/examples/audiofx/firfilter-example.c: (on_message),
+	  (on_rate_changed), (main):
+	  * tests/examples/audiofx/iirfilter-example.c: (on_message),
+	  (on_rate_changed), (main):
+	  Add unit tests and example applications for the two filter
+	  elements.
+
+2009-01-13 19:09:19 +0000  Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+
+	  gst/qtdemux/qtdemux.c: Fix format string for guint64.
+	  Original commit message from CVS:
+	  Patch by: Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+	  * gst/qtdemux/qtdemux.c:
+	  Fix format string for guint64.
+
+2009-01-13 19:04:09 +0000  Michael Smith <msmith@xiph.org>
+
+	  sys/osxaudio/Makefile.am: osxaudio plugin now requires AudioUnit framework, so link against that.
+	  Original commit message from CVS:
+	  * sys/osxaudio/Makefile.am:
+	  osxaudio plugin now requires AudioUnit framework, so link against that.
+	  Clean up tabs v spaces while I'm there.
+
+2009-01-13 17:49:07 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  tests/examples/rtp/server-alsasrc-PCMA.c: Add some example code for printing the RTP manager stats.
+	  Original commit message from CVS:
+	  * tests/examples/rtp/server-alsasrc-PCMA.c: (print_source_stats),
+	  (print_stats), (main):
+	  Add some example code for printing the RTP manager stats.
+
+2009-01-13 08:24:25 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/: Use a custom mutex for protecting the instance fields instead of the GstObject lock. Using the latter c...
+	  Original commit message from CVS:
+	  * gst/audiofx/audiochebband.c: (gst_audio_cheb_band_class_init),
+	  (gst_audio_cheb_band_init), (gst_audio_cheb_band_finalize),
+	  (gst_audio_cheb_band_set_property):
+	  * gst/audiofx/audiochebband.h:
+	  * gst/audiofx/audiocheblimit.c: (gst_audio_cheb_limit_class_init),
+	  (gst_audio_cheb_limit_init), (gst_audio_cheb_limit_finalize),
+	  (gst_audio_cheb_limit_set_property):
+	  * gst/audiofx/audiocheblimit.h:
+	  * gst/audiofx/audiowsincband.c: (gst_audio_wsincband_class_init),
+	  (gst_audio_wsincband_init), (gst_audio_wsincband_finalize),
+	  (gst_audio_wsincband_set_property):
+	  * gst/audiofx/audiowsincband.h:
+	  * gst/audiofx/audiowsinclimit.c: (gst_audio_wsinclimit_class_init),
+	  (gst_audio_wsinclimit_init), (gst_audio_wsinclimit_finalize),
+	  (gst_audio_wsinclimit_set_property):
+	  * gst/audiofx/audiowsinclimit.h:
+	  Use a custom mutex for protecting the instance fields instead of
+	  the GstObject lock. Using the latter can lead to deadlocks, especially
+	  with the FIR filters when updating the latency.
+
+2009-01-11 19:03:38 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/: Implement a base class for generic audio FIR filters.
+	  Original commit message from CVS:
+	  * gst/audiofx/Makefile.am:
+	  * gst/audiofx/audiofxbasefirfilter.c:
+	  (gst_audio_fx_base_fir_filter_dispose),
+	  (gst_audio_fx_base_fir_filter_base_init),
+	  (gst_audio_fx_base_fir_filter_class_init),
+	  (gst_audio_fx_base_fir_filter_init),
+	  (gst_audio_fx_base_fir_filter_push_residue),
+	  (gst_audio_fx_base_fir_filter_setup),
+	  (gst_audio_fx_base_fir_filter_transform),
+	  (gst_audio_fx_base_fir_filter_start),
+	  (gst_audio_fx_base_fir_filter_stop),
+	  (gst_audio_fx_base_fir_filter_query),
+	  (gst_audio_fx_base_fir_filter_query_type),
+	  (gst_audio_fx_base_fir_filter_event),
+	  (gst_audio_fx_base_fir_filter_set_kernel):
+	  * gst/audiofx/audiofxbasefirfilter.h:
+	  * gst/audiofx/audiofxbaseiirfilter.c:
+	  Implement a base class for generic audio FIR filters.
+	  * gst/audiofx/audiowsincband.c:
+	  (gst_gst_audio_wsincband_mode_get_type),
+	  (gst_gst_audio_wsincband_window_get_type),
+	  (gst_audio_wsincband_base_init), (gst_audio_wsincband_class_init),
+	  (gst_audio_wsincband_init), (gst_audio_wsincband_build_kernel),
+	  (gst_audio_wsincband_setup), (gst_audio_wsincband_set_property),
+	  (gst_audio_wsincband_get_property):
+	  * gst/audiofx/audiowsincband.h:
+	  * gst/audiofx/audiowsinclimit.c:
+	  (gst_audio_wsinclimit_mode_get_type),
+	  (gst_audio_wsinclimit_window_get_type),
+	  (gst_audio_wsinclimit_base_init),
+	  (gst_audio_wsinclimit_class_init), (gst_audio_wsinclimit_init),
+	  (gst_audio_wsinclimit_build_kernel), (gst_audio_wsinclimit_setup),
+	  (gst_audio_wsinclimit_set_property),
+	  (gst_audio_wsinclimit_get_property):
+	  * gst/audiofx/audiowsinclimit.h:
+	  * tests/check/elements/audiowsincband.c: (GST_START_TEST):
+	  * tests/check/elements/audiowsinclimit.c: (GST_START_TEST):
+	  Use this new base class for audiowsincband and audiowsinclimit.
+	  Also cleanup both elements.
+
+2009-01-08 18:17:13 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/qtdemux/qtdemux.c: In push mode, error out if we get EOS before we've created any srcpads.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c:
+	  In push mode, error out if we get EOS before we've created any srcpads.
+	  Handle (in pull mode) some files that have a truncated moov atom where
+	  the final sub-atom is a 'free' atom and the contents of that are not
+	  present in the file.
+
+2009-01-08 15:56:46 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/matroska/: Some cleanups, refactoring and minor enhancements in caps handling.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_video_caps):
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_video_pad_setcaps):
+	  Some cleanups, refactoring and minor enhancements in caps handling.
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_class_init),
+	  (gst_matroska_mux_init), (gst_matroska_pad_reset),
+	  (gst_matroska_pad_free), (gst_matroska_mux_reset),
+	  (gst_matroska_mux_video_pad_setcaps),
+	  (gst_matroska_mux_request_new_pad):
+	  * tests/check/elements/matroskamux.c: (teardown_src_pad):
+	  Only remove, release or reset what is appropriate upon state change.
+
+2009-01-07 20:38:50 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/pulse/pulsesink.*: Use a mutex to protect the current stream pointer, and ignore callbacks for stream objects tha...
+	  Original commit message from CVS:
+	  * ext/pulse/pulsesink.c:
+	  * ext/pulse/pulsesink.h:
+	  Use a mutex to protect the current stream pointer, and ignore
+	  callbacks for stream objects that have been destroyed already.
+	  Fixes problems with unprepare/prepare cycles caused by the input
+	  caps changing, without reintroducing bug #556986.
+
+2009-01-07 16:09:47 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  sys/v4l2/gstv4l2src.c: Remove () from translateable string, so that it makes more sense.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c:
+	  Remove () from translateable string, so that it makes more sense.
+
+2009-01-07 09:43:13 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/avi/gstavimux.c: Minor fix/cleanup in header field calculation.
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c: (gst_avi_mux_audsink_set_caps):
+	  Minor fix/cleanup in header field calculation.
+
+2009-01-06 17:48:10 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/matroska/matroska-mux.*: Remove internal taglist and fully use tagsetter interface.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_reset),
+	  (gst_matroska_mux_handle_sink_event), (gst_matroska_mux_finish):
+	  * gst/matroska/matroska-mux.h:
+	  Remove internal taglist and fully use tagsetter interface.
+
+2009-01-06 14:50:29 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/avi/gstavimux.*: Ensure header size invariance during subsequent rewrite by using tags snapshot.
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c: (gst_avi_mux_reset),
+	  (gst_avi_mux_riff_get_avi_header):
+	  * gst/avi/gstavimux.h:
+	  Ensure header size invariance during subsequent rewrite by using
+	  tags snapshot.
+
+2009-01-05 17:31:13 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/pulse/pulsesink.c: Don't wait for the pulse mainloop when destroying the stream.
+	  Original commit message from CVS:
+	  * ext/pulse/pulsesink.c: (gst_pulsesink_destroy_stream):
+	  Don't wait for the pulse mainloop when destroying the stream.
+	  Fixes a deadlock when the pulsedaemon goes away while pulsesink
+	  is PLAYING. Fixes bug #556986.
+
+2009-01-05 12:30:40 +0000  Sascha Hauer <s.hauer@pengutronix.de>
+
+	  sys/v4l2/gstv4l2src.c: Add support for grayscale v4l2 devices. Fixes bug #566616.
+	  Original commit message from CVS:
+	  Patch by: Sascha Hauer <s dot hauer at pengutronix dot de>
+	  Luotao Fu <l dot fu at pengutronix dot de>
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_v4l2fourcc_to_structure),
+	  (gst_v4l2_get_caps_info):
+	  Add support for grayscale v4l2 devices. Fixes bug #566616.
+
+2009-01-05 11:42:09 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/qtdemux/: Streamline tag handling and pass unparsed tags as binary blob in private tag.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_tag_add_str),
+	  (qtdemux_tag_add_tmpo), (qtdemux_tag_add_covr),
+	  (qtdemux_tag_add_date), (qtdemux_tag_add_gnre),
+	  (qtdemux_tag_add_blob), (qtdemux_parse_udta):
+	  * gst/qtdemux/qtdemux.h:
+	  * gst/qtdemux/quicktime.c: (plugin_init):
+	  Streamline tag handling and pass unparsed tags as binary blob
+	  in private tag.
+
+2009-01-05 10:13:29 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/: Implement a base class for IIR filters.
+	  Original commit message from CVS:
+	  * gst/audiofx/Makefile.am:
+	  * gst/audiofx/audiofxbaseiirfilter.c:
+	  (gst_audio_fx_base_iir_filter_base_init),
+	  (gst_audio_fx_base_iir_filter_dispose),
+	  (gst_audio_fx_base_iir_filter_class_init),
+	  (gst_audio_fx_base_iir_filter_init),
+	  (gst_audio_fx_base_iir_filter_calculate_gain),
+	  (gst_audio_fx_base_iir_filter_set_coefficients),
+	  (gst_audio_fx_base_iir_filter_setup), (process),
+	  (gst_audio_fx_base_iir_filter_transform_ip),
+	  (gst_audio_fx_base_iir_filter_stop):
+	  * gst/audiofx/audiofxbaseiirfilter.h:
+	  Implement a base class for IIR filters.
+	  * gst/audiofx/audiochebband.c: (gst_audio_cheb_band_base_init),
+	  (gst_audio_cheb_band_class_init), (gst_audio_cheb_band_init),
+	  (generate_coefficients), (gst_audio_cheb_band_set_property),
+	  (gst_audio_cheb_band_setup):
+	  * gst/audiofx/audiochebband.h:
+	  * gst/audiofx/audiocheblimit.c: (gst_audio_cheb_limit_base_init),
+	  (gst_audio_cheb_limit_class_init), (gst_audio_cheb_limit_init),
+	  (generate_coefficients), (gst_audio_cheb_limit_set_property),
+	  (gst_audio_cheb_limit_setup):
+	  * gst/audiofx/audiocheblimit.h:
+	  Use the IIR filter base class for the chebyshev filters.
+
+2009-01-02 20:39:34 +0000  Justin Karnegas <justin@affinix.com>
+
+	  sys/osxaudio/: Rewrite osxaudio to work more flexibly and more reliably, using a different abstraction layer of corea...
+	  Original commit message from CVS:
+	  Patch by: Justin Karnegas <justin@affinix.com> and
+	  Michael Smith <msmith@songbirdnest.com>
+	  * sys/osxaudio/gstosxaudio.c:
+	  * sys/osxaudio/gstosxaudioelement.c:
+	  * sys/osxaudio/gstosxaudioelement.h:
+	  * sys/osxaudio/gstosxaudiosink.c:
+	  * sys/osxaudio/gstosxaudiosink.h:
+	  * sys/osxaudio/gstosxaudiosrc.c:
+	  * sys/osxaudio/gstosxaudiosrc.h:
+	  * sys/osxaudio/gstosxringbuffer.c:
+	  * sys/osxaudio/gstosxringbuffer.h:
+	  Rewrite osxaudio to work more flexibly and more reliably, using a
+	  different abstraction layer of coreaudio that is the recommended way of
+	  doing low-level audio I/O on OSX.
+	  Fixes byg #564948.
+
+2009-01-02 16:31:13 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  tests/examples/rtp/server-decodebin-H263p-AMR.sh: Add example RTP transcoding pipeline from any file decodedable with...
+	  Original commit message from CVS:
+	  * tests/examples/rtp/server-decodebin-H263p-AMR.sh:
+	  Add example RTP transcoding pipeline from any file decodedable with
+	  uridecodebin.
+
+2009-01-02 15:20:48 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  tests/examples/rtp/: Add two C examples of using gstrtpbin as a sender and a receiver.
+	  Original commit message from CVS:
+	  * tests/examples/rtp/.cvsignore:
+	  * tests/examples/rtp/Makefile.am:
+	  * tests/examples/rtp/client-PCMA.c: (pad_added_cb), (main):
+	  * tests/examples/rtp/server-alsasrc-PCMA.c: (main):
+	  Add two C examples of using gstrtpbin as a sender and a receiver.
+
+2008-12-31 11:20:55 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ChangeLog: Remove conflict marker from ChangeLog
+	  Original commit message from CVS:
+	  * ChangeLog:
+	  Remove conflict marker from ChangeLog
+
+2008-12-28 09:50:31 +0000  j^ <j@oil21.org>
+
+	  gst/qtdemux/qtdemux.c: Add codec mapping for xvid, fmp4 and ac3 tracks.
+	  Original commit message from CVS:
+	  Patch by: j^ <j at oil21.org>
+	  * gst/qtdemux/qtdemux.c: (qtdemux_video_caps),
+	  (qtdemux_audio_caps):
+	  Add codec mapping for xvid, fmp4 and ac3 tracks.
+	  Fixes #565850
+
+2008-12-23 12:10:41 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/jpeg/gstsmokeenc.*: Implement getcaps function.
+	  Original commit message from CVS:
+	  * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_init),
+	  (gst_smokeenc_getcaps), (gst_smokeenc_setcaps),
+	  (gst_smokeenc_chain), (gst_smokeenc_change_state):
+	  * ext/jpeg/gstsmokeenc.h:
+	  Implement getcaps function.
+	  Set caps on the pad and on all outgoing buffers.
+	  Fixes #565441.
+
+2008-12-19 09:36:45 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/pulse/pulsemixerctrl.c: And remove temporary comment pointing to the bug ticket.
+	  Original commit message from CVS:
+	  * ext/pulse/pulsemixerctrl.c:
+	  And remove temporary comment pointing to the bug ticket.
+	  * gst/avi/gstavimux.c:
+	  Move reoccuring logging to LOG and log instance too.
+
+2008-12-17 17:28:39 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/pulse/pulsemixerctrl.c: Don't leak the pa_operation.
+	  Original commit message from CVS:
+	  * ext/pulse/pulsemixerctrl.c:
+	  Don't leak the pa_operation.
+
+2008-12-16 16:19:26 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  configure.ac: Require core cvs.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Require core cvs.
+
+2008-12-16 16:07:48 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavimux.c: Rename api from _flush to _reset_tags.
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c:
+	  Rename api from _flush to _reset_tags.
+
+2008-12-16 14:22:51 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavimux.c: Use new tagsetter api to flush tags.
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c:
+	  Use new tagsetter api to flush tags.
+
+2008-12-16 13:14:39 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/deinterleave.c: Increase timeout to 3 minutes to prevent timeouts.
+	  Original commit message from CVS:
+	  * tests/check/elements/deinterleave.c: (deinterleave_suite):
+	  Increase timeout to 3 minutes to prevent timeouts.
+
+2008-12-16 12:52:24 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/interleave.c: Increase timeout to 3 minutes to prevent timeouts.
+	  Original commit message from CVS:
+	  * tests/check/elements/interleave.c: (interleave_suite):
+	  Increase timeout to 3 minutes to prevent timeouts.
+
+2008-12-16 11:57:01 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavimux.*: Totally remove the internal taglists and fully use tagsetter.
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c:
+	  * gst/avi/gstavimux.h:
+	  Totally remove the internal taglists and fully use tagsetter.
+
+2008-12-15 15:59:53 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavimux.c: Instead of filtering wrongly just use the mergemode. Applications is use KEEP_ALL if they want t...
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c:
+	  Instead of filtering wrongly just use the mergemode. Applications is
+	  use KEEP_ALL if they want to supress tag-events. Fixes #563221 for
+	  avi for real (I hope). Everyone chime in, before I fix the others.
+
+2008-12-15 12:45:35 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/pulse/pulsemixerctrl.c: Add note about memleak.
+	  Original commit message from CVS:
+	  * ext/pulse/pulsemixerctrl.c:
+	  Add note about memleak.
+
+2008-12-13 16:23:09 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  m4/Makefile.am: A couple more .m4 that aren't shipped anymore with gettext 0.17.
+	  Original commit message from CVS:
+	  * m4/Makefile.am:
+	  A couple more .m4 that aren't shipped anymore with gettext 0.17.
+
+2008-12-13 15:34:01 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  Switch to using GstStaticPadTemplate.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_base_init),
+	  (gst_flac_dec_init):
+	  * gst/law/alaw-decode.c: (gst_alaw_dec_base_init),
+	  (gst_alaw_dec_init):
+	  * gst/law/alaw-encode.c: (gst_alaw_enc_base_init),
+	  (gst_alaw_enc_init):
+	  * gst/law/alaw.c: (plugin_init):
+	  * gst/law/mulaw-decode.c: (gst_mulawdec_base_init),
+	  (gst_mulawdec_init):
+	  * gst/law/mulaw-encode.c: (gst_mulawenc_base_init),
+	  (gst_mulawenc_init):
+	  * gst/law/mulaw.c: (plugin_init):
+	  Switch to using GstStaticPadTemplate.
+	  * gst/udp/gstudpnetutils.c: (gst_udp_get_addr):
+	  Don't forget to free the addrinfo structure.
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_reset),
+	  (gst_wavparse_sink_activate):
+	  Don't forget to unref the GstAdapter.
+
+2008-12-13 12:58:24 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  m4/Makefile.am: inttypes.m4 hasn't been available since gettext-0.15, and since we now require gettext >= 0.17 ... we...
+	  Original commit message from CVS:
+	  * m4/Makefile.am:
+	  inttypes.m4 hasn't been available since gettext-0.15, and since we now
+	  require gettext >= 0.17 ... we can remove it from the list of files to
+	  dist.
+
+2008-12-10 15:03:23 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  smaller spec file updates
+	  Original commit message from CVS:
+	  smaller spec file updates
+
+2008-12-09 17:55:22 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.c: More logging.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  More logging.
+	  * gst/avi/gstavimux.c:
+	  Handle more metadata fields. Better estimate of metadata size. Don't
+	  merge received tags, if application has specified tags using
+	  GST_TAG_MERGE_REPLACE_ALL. Fixes #563221 for avi.
+
+2008-12-09 14:30:03 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/Makefile.am: Also ignore pulsemixer for the states unit test.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Also ignore pulsemixer for the states unit test.
+
+2008-12-09 14:19:16 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpjpegdepay.c: Add an EOI marker at the end of the jpeg frame when it's missing.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpjpegdepay.c: (gst_rtp_jpeg_depay_process):
+	  Add an EOI marker at the end of the jpeg frame when it's missing.
+	  Fixes #563056.
+
+2008-12-09 10:47:14 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/videocrop.c: Update the unit test for the new color values for BT.601 red.
+	  Original commit message from CVS:
+	  * tests/check/elements/videocrop.c: (check_1x1_buffer):
+	  Update the unit test for the new color values for BT.601 red.
+	  Fixes bug #563510.
+
+2008-12-09 10:28:11 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/dv/gstdvdemux.c: Restore previous behaviour of not passing QoS and navigation events upstream, which presumably w...
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_handle_src_event):
+	  Restore previous behaviour of not passing QoS and navigation
+	  events upstream, which presumably wasn't meant to be changed.
+
+2008-12-09 09:39:53 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/dv/gstdvdemux.c: Add srcpads only when needed and remove them again when going back to READY. This prevents stall...
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_add_video_pad),
+	  (gst_dvdemux_add_audio_pad), (gst_dvdemux_remove_pads),
+	  (gst_dvdemux_demux_audio), (gst_dvdemux_demux_video),
+	  (gst_dvdemux_chain), (gst_dvdemux_loop),
+	  (gst_dvdemux_change_state):
+	  Add srcpads only when needed and remove them again when going
+	  back to READY. This prevents stalled pipelines if there's no
+	  audio inside the DV stream, which happens for many MXF files.
+
+2008-12-09 09:09:25 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/souphttpsrc.c: The ports in libsoup are unsigned integers and not signed integers.
+	  Original commit message from CVS:
+	  * tests/check/elements/souphttpsrc.c: (GST_START_TEST),
+	  (run_server):
+	  The ports in libsoup are unsigned integers and not signed
+	  integers.
+
+2008-12-08 18:31:00 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/dv/gstdvdemux.c: Forward all events upstream unless it's something we really don't handle. This fixes latency con...
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_handle_src_event):
+	  Forward all events upstream unless it's something we really
+	  don't handle. This fixes latency configuration of pipelines.
+
+2008-12-08 18:24:21 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/dv/: Really call dv_init() exactly one time, not one time for the demuxer and one time for the decoder.
+	  Original commit message from CVS:
+	  * ext/dv/gstdv.c: (plugin_init):
+	  * ext/dv/gstdvdec.c: (gst_dvdec_class_init):
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_class_init):
+	  Really call dv_init() exactly one time, not one time for
+	  the demuxer and one time for the decoder.
+
+2008-12-08 12:37:45 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmp4apay.c: Copy incomming timestamp to outgoing packets.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4apay.c: (gst_rtp_mp4a_pay_handle_buffer):
+	  Copy incomming timestamp to outgoing packets.
+
+2008-12-08 12:36:21 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmp4vpay.c: Don't try to push packets before we could find a valid config startcode. Fixes #563509.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4vpay.c: (gst_rtp_mp4v_pay_flush),
+	  (gst_rtp_mp4v_pay_event):
+	  Don't try to push packets before we could find a valid config
+	  startcode. Fixes #563509.
+
+2008-12-07 19:22:48 +0000  Brian Cameron <brian.cameron@sun.com>
+
+	  sys/sunaudio/gstsunaudiomixerctrl.c: Set the mixer fd before calling ioctl() on it. Fixes bug #563414.
+	  Original commit message from CVS:
+	  Patch by: Brian Cameron <brian.cameron at sun dot com>
+	  * sys/sunaudio/gstsunaudiomixerctrl.c:
+	  (gst_sunaudiomixer_ctrl_open):
+	  Set the mixer fd before calling ioctl() on it. Fixes bug #563414.
+
+2008-12-07 19:01:35 +0000  Alexandre Rostovtsev <tetromino@gmail.com>
+
+	  configure.ac: Make usage of libv4l optional by a configure parameter.
+	  Original commit message from CVS:
+	  Patch by: Alexandre Rostovtsev <tetromino at gmail dot com>
+	  * configure.ac:
+	  Make usage of libv4l optional by a configure parameter.
+	  Fixes bug #563504.
+
+2008-12-05 09:24:18 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Add documentation for matroskamux and matroskademux and update the inspection xml files.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-good-plugins.interfaces:
+	  * docs/plugins/inspect/plugin-1394.xml:
+	  * docs/plugins/inspect/plugin-aasink.xml:
+	  * docs/plugins/inspect/plugin-alaw.xml:
+	  * docs/plugins/inspect/plugin-alpha.xml:
+	  * docs/plugins/inspect/plugin-alphacolor.xml:
+	  * docs/plugins/inspect/plugin-annodex.xml:
+	  * docs/plugins/inspect/plugin-apetag.xml:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  * docs/plugins/inspect/plugin-auparse.xml:
+	  * docs/plugins/inspect/plugin-autodetect.xml:
+	  * docs/plugins/inspect/plugin-avi.xml:
+	  * docs/plugins/inspect/plugin-cacasink.xml:
+	  * docs/plugins/inspect/plugin-cairo.xml:
+	  * docs/plugins/inspect/plugin-cutter.xml:
+	  * docs/plugins/inspect/plugin-debug.xml:
+	  * docs/plugins/inspect/plugin-dv.xml:
+	  * docs/plugins/inspect/plugin-efence.xml:
+	  * docs/plugins/inspect/plugin-effectv.xml:
+	  * docs/plugins/inspect/plugin-equalizer.xml:
+	  * docs/plugins/inspect/plugin-esdsink.xml:
+	  * docs/plugins/inspect/plugin-flac.xml:
+	  * docs/plugins/inspect/plugin-flxdec.xml:
+	  * docs/plugins/inspect/plugin-gamma.xml:
+	  * docs/plugins/inspect/plugin-gconfelements.xml:
+	  * docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	  * docs/plugins/inspect/plugin-goom.xml:
+	  * docs/plugins/inspect/plugin-goom2k1.xml:
+	  * docs/plugins/inspect/plugin-halelements.xml:
+	  * docs/plugins/inspect/plugin-icydemux.xml:
+	  * docs/plugins/inspect/plugin-id3demux.xml:
+	  * docs/plugins/inspect/plugin-interleave.xml:
+	  * docs/plugins/inspect/plugin-jpeg.xml:
+	  * docs/plugins/inspect/plugin-level.xml:
+	  * docs/plugins/inspect/plugin-matroska.xml:
+	  * docs/plugins/inspect/plugin-monoscope.xml:
+	  * docs/plugins/inspect/plugin-mulaw.xml:
+	  * docs/plugins/inspect/plugin-multifile.xml:
+	  * docs/plugins/inspect/plugin-multipart.xml:
+	  * docs/plugins/inspect/plugin-navigationtest.xml:
+	  * docs/plugins/inspect/plugin-ossaudio.xml:
+	  * docs/plugins/inspect/plugin-png.xml:
+	  * docs/plugins/inspect/plugin-pulseaudio.xml:
+	  * docs/plugins/inspect/plugin-quicktime.xml:
+	  * docs/plugins/inspect/plugin-replaygain.xml:
+	  * docs/plugins/inspect/plugin-rtp.xml:
+	  * docs/plugins/inspect/plugin-rtsp.xml:
+	  * docs/plugins/inspect/plugin-shout2send.xml:
+	  * docs/plugins/inspect/plugin-smpte.xml:
+	  * docs/plugins/inspect/plugin-soup.xml:
+	  * docs/plugins/inspect/plugin-spectrum.xml:
+	  * docs/plugins/inspect/plugin-speex.xml:
+	  * docs/plugins/inspect/plugin-taglib.xml:
+	  * docs/plugins/inspect/plugin-udp.xml:
+	  * docs/plugins/inspect/plugin-video4linux2.xml:
+	  * docs/plugins/inspect/plugin-videobalance.xml:
+	  * docs/plugins/inspect/plugin-videobox.xml:
+	  * docs/plugins/inspect/plugin-videocrop.xml:
+	  * docs/plugins/inspect/plugin-videoflip.xml:
+	  * docs/plugins/inspect/plugin-videomixer.xml:
+	  * docs/plugins/inspect/plugin-wavenc.xml:
+	  * docs/plugins/inspect/plugin-wavpack.xml:
+	  * docs/plugins/inspect/plugin-wavparse.xml:
+	  * docs/plugins/inspect/plugin-ximagesrc.xml:
+	  * gst/matroska/matroska-demux.c:
+	  * gst/matroska/matroska-demux.h:
+	  * gst/matroska/matroska-mux.c:
+	  * gst/matroska/matroska-mux.h:
+	  Add documentation for matroskamux and matroskademux and
+	  update the inspection xml files.
+
+2008-12-04 20:10:58 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  configure.ac: Apparently AC_CONFIG_MACRO_DIR breaks when using more than one macro directory, reverting last change.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Apparently AC_CONFIG_MACRO_DIR breaks when using more
+	  than one macro directory, reverting last change.
+
+2008-12-04 19:47:21 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  configure.ac: Set AC_CONFIG_MACRO_DIR to common/m4 to point autoconf to our M4 macros.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Set AC_CONFIG_MACRO_DIR to common/m4 to point autoconf to
+	  our M4 macros.
+
+2008-11-30 16:24:45 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/udp/gstmultiudpsink.c: Provide the parameters that are required for the format string to fix a compiler warning.
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_render):
+	  Provide the parameters that are required for the format string
+	  to fix a compiler warning.
+
+2008-11-29 20:05:41 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/autodetect/gstautoaudiosrc.c: Fix classification.
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautoaudiosrc.c:
+	  Fix classification.
+
+2008-11-29 13:31:55 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Require gettext 0.17 because older versions don't mix with libtool 2.2. At build time an older gettext version will s...
+	  Original commit message from CVS:
+	  Patch by: Cygwin Ports maintainer
+	  <yselkowitz at users dot sourceforge dot net>
+	  * autogen.sh:
+	  * configure.ac:
+	  Require gettext 0.17 because older versions don't mix with libtool
+	  2.2. At build time an older gettext version will still work.
+	  Fixes bug #556091.
+
+2008-11-28 15:10:50 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/udp/gstmultiudpsink.c: Make gst_multiudpsink_render() ignore errors from sendto() instead of breaking streaming. ...
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt <pkj at axis com>
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_render):
+	  Make gst_multiudpsink_render() ignore errors from sendto() instead of
+	  breaking streaming. Emit a warning instead. Fixes #562572.
+
+2008-11-27 16:43:24 +0000  Ron McOuat <rmcouat@smartt.com>
+
+	  Add support for basic and digest authentication in souphttpsrc.
+	  Original commit message from CVS:
+	  Patch by: Ron McOuat <rmcouat at smartt dot com>
+	  * ext/soup/gstsouphttpsrc.c: (gst_soup_http_src_class_init),
+	  (gst_soup_http_src_init), (gst_soup_http_src_dispose),
+	  (gst_soup_http_src_set_property), (gst_soup_http_src_get_property),
+	  (gst_soup_http_src_authenticate_cb), (gst_soup_http_src_start):
+	  * ext/soup/gstsouphttpsrc.h:
+	  * tests/check/elements/souphttpsrc.c: (basic_auth_cb),
+	  (digest_auth_cb), (run_test), (GST_START_TEST),
+	  (souphttpsrc_suite), (run_server):
+	  Add support for basic and digest authentication in souphttpsrc.
+	  Fixes bug #561775.
+
+2008-11-27 12:13:39 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/wavenc/: Add support for a-law and mu-law encoded wav files. Fixes bug #562434.
+	  Original commit message from CVS:
+	  Patch by: Pepijn Van Eeckhoudt
+	  <pepijn dot vaneeckhoudt at luciad dot com>
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_create_header_buf),
+	  (gst_wavenc_sink_setcaps), (gst_wavenc_change_state):
+	  * gst/wavenc/gstwavenc.h:
+	  * gst/wavenc/riff.h:
+	  Add support for a-law and mu-law encoded wav files. Fixes bug #562434.
+
+2008-11-27 11:22:56 +0000  이문형 <iwings@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Prevent further read/write actions taken to the connect-failed socket by erroring out quickly....
+	  Original commit message from CVS:
+	  Patch by: 이문형 <iwings at gmail dot com>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_loop_udp):
+	  Prevent further read/write actions taken to the connect-failed socket by
+	  erroring out quickly. See #562258.
+
+2008-11-26 21:19:47 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/examples/level/level-example.c: Set fakesink to sync. Otherwise people might question the message interval. Nev...
+	  Original commit message from CVS:
+	  * tests/examples/level/level-example.c:
+	  Set fakesink to sync. Otherwise people might question the message
+	  interval. Nevertheless the timestamp in the message is what matters.
+
+2008-11-25 18:13:25 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  tests/icles/.cvsignore: cvsignore newly generated file.
+	  Original commit message from CVS:
+	  * tests/icles/.cvsignore:
+	  cvsignore newly generated file.
+
+2008-11-25 18:03:02 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Fix the descriptions and fix some email addresses.
+	  Original commit message from CVS:
+	  * gst/rtp/gstasteriskh263.c:
+	  * gst/rtp/gstasteriskh263.h:
+	  * gst/rtp/gstrtpL16depay.c: (gst_rtp_L16_depay_setcaps):
+	  * gst/rtp/gstrtpL16depay.h:
+	  * gst/rtp/gstrtpL16pay.c:
+	  * gst/rtp/gstrtpL16pay.h:
+	  * gst/rtp/gstrtpac3depay.c: (gst_rtp_ac3_depay_setcaps):
+	  * gst/rtp/gstrtpac3depay.h:
+	  * gst/rtp/gstrtpamrdepay.c:
+	  * gst/rtp/gstrtpamrdepay.h:
+	  * gst/rtp/gstrtpamrpay.c:
+	  * gst/rtp/gstrtpamrpay.h:
+	  * gst/rtp/gstrtpdepay.c:
+	  * gst/rtp/gstrtpdepay.h:
+	  * gst/rtp/gstrtpdvdepay.c: (gst_rtp_dv_depay_setcaps):
+	  * gst/rtp/gstrtpg726depay.c:
+	  * gst/rtp/gstrtpg726pay.c:
+	  * gst/rtp/gstrtpg729depay.c:
+	  * gst/rtp/gstrtpg729pay.c:
+	  * gst/rtp/gstrtpgsmdepay.c:
+	  * gst/rtp/gstrtpgsmpay.c: (gst_rtp_gsm_pay_setcaps):
+	  * gst/rtp/gstrtph263depay.c: (gst_rtp_h263_depay_setcaps):
+	  * gst/rtp/gstrtph263depay.h:
+	  * gst/rtp/gstrtph263pay.c:
+	  * gst/rtp/gstrtph263pay.h:
+	  * gst/rtp/gstrtph263pdepay.c: (gst_rtp_h263p_depay_setcaps):
+	  * gst/rtp/gstrtph263pdepay.h:
+	  * gst/rtp/gstrtph263ppay.c:
+	  * gst/rtp/gstrtph263ppay.h:
+	  * gst/rtp/gstrtph264depay.c:
+	  * gst/rtp/gstrtph264depay.h:
+	  * gst/rtp/gstrtph264pay.c:
+	  * gst/rtp/gstrtph264pay.h:
+	  * gst/rtp/gstrtpilbcdepay.c:
+	  * gst/rtp/gstrtpilbcpay.c:
+	  * gst/rtp/gstrtpjpegdepay.h:
+	  * gst/rtp/gstrtpmp1sdepay.c: (gst_rtp_mp1s_depay_setcaps):
+	  * gst/rtp/gstrtpmp1sdepay.h:
+	  * gst/rtp/gstrtpmp2tdepay.c: (gst_rtp_mp2t_depay_setcaps):
+	  * gst/rtp/gstrtpmp2tdepay.h:
+	  * gst/rtp/gstrtpmp2tpay.c:
+	  * gst/rtp/gstrtpmp2tpay.h:
+	  * gst/rtp/gstrtpmp4adepay.c: (gst_rtp_mp4a_depay_setcaps):
+	  * gst/rtp/gstrtpmp4apay.c:
+	  * gst/rtp/gstrtpmp4apay.h:
+	  * gst/rtp/gstrtpmp4gdepay.c: (gst_rtp_mp4g_depay_setcaps):
+	  * gst/rtp/gstrtpmp4gdepay.h:
+	  * gst/rtp/gstrtpmp4gpay.c:
+	  * gst/rtp/gstrtpmp4gpay.h:
+	  * gst/rtp/gstrtpmp4vdepay.c: (gst_rtp_mp4v_depay_setcaps):
+	  * gst/rtp/gstrtpmp4vdepay.h:
+	  * gst/rtp/gstrtpmp4vpay.c: (gst_rtp_mp4v_pay_event):
+	  * gst/rtp/gstrtpmp4vpay.h:
+	  * gst/rtp/gstrtpmpadepay.c:
+	  * gst/rtp/gstrtpmpadepay.h:
+	  * gst/rtp/gstrtpmpapay.c:
+	  * gst/rtp/gstrtpmpapay.h:
+	  * gst/rtp/gstrtpmpvdepay.c:
+	  * gst/rtp/gstrtpmpvdepay.h:
+	  * gst/rtp/gstrtppcmadepay.c: (gst_rtp_pcma_depay_process):
+	  * gst/rtp/gstrtppcmapay.c:
+	  * gst/rtp/gstrtppcmudepay.c:
+	  * gst/rtp/gstrtppcmupay.c:
+	  * gst/rtp/gstrtpspeexdepay.c:
+	  * gst/rtp/gstrtpspeexpay.c:
+	  * gst/rtp/gstrtpsv3vdepay.c:
+	  * gst/rtp/gstrtpsv3vdepay.h:
+	  * gst/rtp/gstrtptheoradepay.c:
+	  * gst/rtp/gstrtptheoradepay.h:
+	  * gst/rtp/gstrtptheorapay.c:
+	  * gst/rtp/gstrtptheorapay.h:
+	  * gst/rtp/gstrtpvorbisdepay.c:
+	  * gst/rtp/gstrtpvorbisdepay.h:
+	  * gst/rtp/gstrtpvorbispay.c: (gst_rtp_vorbis_pay_finish_headers):
+	  * gst/rtp/gstrtpvorbispay.h:
+	  * gst/rtp/gstrtpvrawdepay.c: (gst_rtp_vraw_depay_setcaps):
+	  * gst/rtp/gstrtpvrawpay.c:
+	  Fix the descriptions and fix some email addresses.
+
+2008-11-25 17:47:24 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/qtdemux/qtdemux.c: Add MPG1 and MPG2 fourcc to supported qtdemux video codecs as I found some video clips using t...
+	  Original commit message from CVS:
+	  2008-11-25  Julien Moutte  <julien@fluendo.com>
+	  * gst/qtdemux/qtdemux.c: (qtdemux_video_caps): Add MPG1 and MPG2
+	  fourcc
+	  to supported qtdemux video codecs as I found some video clips
+	  using
+	  those.
+
+2008-11-25 16:26:16 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/autodetect/: Post an error when we can't set the internal ghostpad target.
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautoaudiosink.c: (gst_auto_audio_sink_detect):
+	  * gst/autodetect/gstautoaudiosrc.c: (gst_auto_audio_src_detect):
+	  * gst/autodetect/gstautovideosink.c: (gst_auto_video_sink_reset),
+	  (gst_auto_video_sink_detect):
+	  * gst/autodetect/gstautovideosrc.c: (gst_auto_video_src_detect):
+	  Post an error when we can't set the internal ghostpad target.
+
+2008-11-25 16:06:22 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/videocrop/gstvideocrop.*: Fix renegotiation when changing properties using the new basetransform features. Fixes ...
+	  Original commit message from CVS:
+	  * gst/videocrop/gstvideocrop.c: (gst_video_crop_init),
+	  (gst_video_crop_transform), (gst_video_crop_transform_caps),
+	  (gst_video_crop_set_caps), (gst_video_crop_set_property):
+	  * gst/videocrop/gstvideocrop.h:
+	  Fix renegotiation when changing properties using the new basetransform
+	  features. Fixes #561502.
+	  * tests/icles/Makefile.am:
+	  * tests/icles/videocrop2-test.c: (make_pipeline), (main):
+	  Add crazy interactive test unit for dynamically changing properties.
+
+2008-11-24 12:20:29 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Add some more debugging.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (new_session_pad),
+	  (gst_rtspsrc_parse_range):
+	  Add some more debugging.
+	  Use the reanges received from the server unconditionally.
+	  Fixes #561625.
+
+2008-11-23 15:08:45 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/pulse/pulsesink.c: Change #if 0 to something more expresive and add pointer to related bug ticket.
+	  Original commit message from CVS:
+	  * ext/pulse/pulsesink.c:
+	  Change #if 0 to something more expresive and add pointer to related
+	  bug ticket.
+
+2008-11-23 11:17:01 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ChangeLog:
+	  ChangeLog surgery
+	  Original commit message from CVS:
+	  ChangeLog surgery
+
+2008-11-23 11:14:42 +0000  Tal Shalif <tshalif@nargila.org>
+
+	  gst/qtdemux/qtdemux.c: Use G_{BIG,LITTLE}_ENDIAN instead of the non-GLib variants as the latter don't exist on some s...
+	  Original commit message from CVS:
+	  Patch by: Tal Shalif <tshalif at nargila dot org>
+	  * gst/qtdemux/qtdemux.c: (qtdemux_audio_caps):
+	  Use G_{BIG,LITTLE}_ENDIAN instead of the non-GLib variants as
+	  the latter don't exist on some systems (mingw). Fixes bug #561992.
+
+2008-11-21 13:43:29 +0000  Zeeshan Ali <zeeshanak@gnome.org>
+
+	  ext/soup/gstsouphttpsrc.c: Add transferMode.dnla.org header to HTTP requests as this is required by the DLNA specs an...
+	  Original commit message from CVS:
+	  Patch by: Zeeshan Ali <zeeshanak at gnome dot org>
+	  * ext/soup/gstsouphttpsrc.c: (gst_soup_http_src_build_message):
+	  Add transferMode.dnla.org header to HTTP requests as this is
+	  required by the DLNA specs and doesn't hurt in other situations.
+	  Fixes bug #561802.
+
+2008-11-20 23:59:07 +0000  Michael Smith <msmith@xiph.org>
+
+	  sys/osxvideo/osxvideosink.*: Handle video window resizing more correctly, avoiding crashes when embedding the window ...
+	  Original commit message from CVS:
+	  * sys/osxvideo/osxvideosink.h:
+	  * sys/osxvideo/osxvideosink.m:
+	  Handle video window resizing more correctly, avoiding crashes when
+	  embedding the window and resizing it.
+
+2008-11-20 22:56:58 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/udp/: Fix multiudpsink on OSX by passing the specific length of the socket, refactor that into a function shared ...
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c:
+	  * gst/udp/gstudpnetutils.c:
+	  * gst/udp/gstudpnetutils.h:
+	  * gst/udp/gstudpsrc.c:
+	  Fix multiudpsink on OSX by passing the specific length of the socket,
+	  refactor that into a function shared with the same thing in udpsrc.
+
+2008-11-20 20:07:26 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/wavparse/gstwavparse.c: Fix the scaling code.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (uint64_ceiling_scale_int),
+	  (uint64_ceiling_scale), (gst_wavparse_calculate_duration),
+	  (gst_wavparse_stream_headers):
+	  Fix the scaling code.
+	  Fix parsing of the INFO chunks, we were reading the wrong number of
+	  bytes.  Fixes #561580.
+
+2008-11-20 14:30:40 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/matroska/matroska-mux.c: Fix NULL pointer dereference of an unset codec_id in the recently added Dirac paths
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c:
+	  Fix NULL pointer dereference of an unset codec_id in the recently
+	  added Dirac paths
+
+2008-11-20 13:58:43 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  tests/check/Makefile.am: Just keep disabling elements that hang the states test until it works.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Just keep disabling elements that hang the states test until it
+	  works.
+
+2008-11-20 13:46:47 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/libpng/gstpngenc.c: Don't flush downstream after every buffer - that's not what this libpng callback is for at all!
+	  Original commit message from CVS:
+	  * ext/libpng/gstpngenc.c:
+	  Don't flush downstream after every buffer - that's not what
+	  this libpng callback is for at all!
+
+2008-11-17 14:04:20 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/v4l2/v4l2src_calls.c: Turns out we don't always get the frame sizes in a predefined order from lowest to highest ...
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c:
+	  (gst_v4l2src_probe_caps_for_format_and_size), (sort_by_frame_size),
+	  (gst_v4l2src_probe_caps_for_format):
+	  Turns out we don't always get the frame sizes in a predefined
+	  order from lowest to highest resolution, so let's just sort the
+	  list by frame size once we've queried the possible resolutions
+	  rather than assume any particular order. Fixes probed caps for
+	  the camera in my HP2133 mini notebook and makes v4l2src default
+	  to a decent size.
+
+2008-11-16 14:41:32 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/matroska/: Make mkvdemux aware of E-AC3.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_audio_caps):
+	  * gst/matroska/matroska-ids.h:
+	  Make mkvdemux aware of E-AC3.
+
+2008-11-14 18:41:29 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Add a jpeg depayloader.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpjpegdepay.c: (gst_rtp_jpeg_depay_base_init),
+	  (gst_rtp_jpeg_depay_class_init), (gst_rtp_jpeg_depay_init),
+	  (gst_rtp_jpeg_depay_finalize), (MakeTables), (MakeQuantHeader),
+	  (MakeHuffmanHeader), (MakeDRIHeader), (MakeHeaders),
+	  (gst_rtp_jpeg_depay_setcaps), (gst_rtp_jpeg_depay_process),
+	  (gst_rtp_jpeg_depay_change_state),
+	  (gst_rtp_jpeg_depay_plugin_init):
+	  * gst/rtp/gstrtpjpegdepay.h:
+	  Add a jpeg depayloader.
+	  * gst/rtp/gstrtpjpegpay.c:
+	  Set the default properties on the payloader to better defaults.
+
+2008-11-14 15:42:32 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/v4l2/gstv4l2.c: Give it a primary rank for autovideosrc.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2.c:
+	  Give it a primary rank for autovideosrc.
+
+2008-11-14 11:41:55 +0000  Bjorn Ostby <bjornos@axis.com>
+
+	  gst/rtp/: Add JPEG payloader. Fixes #560756.
+	  Original commit message from CVS:
+	  Patch by: Bjorn Ostby <bjornos at axis dot com>
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpjpegpay.c: (gst_rtp_jpeg_pay_base_init),
+	  (gst_rtp_jpeg_pay_class_init), (gst_rtp_jpeg_pay_init),
+	  (gst_rtp_jpeg_pay_setcaps), (gst_rtp_jpeg_pay_header_size),
+	  (gst_rtp_jpeg_pay_read_quant_table),
+	  (gst_rtp_jpeg_pay_scan_marker), (gst_rtp_jpeg_pay_handle_buffer),
+	  (gst_rtp_jpeg_pay_set_property), (gst_rtp_jpeg_pay_get_property),
+	  (gst_rtp_jpeg_pay_plugin_init):
+	  * gst/rtp/gstrtpjpegpay.h:
+	  Add JPEG payloader. Fixes #560756.
+
+2008-11-13 17:45:59 +0000  Fabricio Godoy <skarllot@gmail.com>
+
+	  sys/: Fix some spelling mistakes. Fixes #556802.
+	  Original commit message from CVS:
+	  Patch by: Fabricio Godoy <skarllot at gmail dot com>
+	  * sys/oss/gstosssink.c: (gst_oss_sink_open):
+	  * sys/oss/gstosssrc.c: (gst_oss_src_open):
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_get_mmap):
+	  * sys/v4l2/v4l2_calls.c: (gst_v4l2_fill_lists):
+	  Fix some spelling mistakes. Fixes #556802.
+
+2008-11-13 16:24:59 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/equalizer/: Add presets for equalizer. Fixes #522183.
+	  Original commit message from CVS:
+	  * gst/equalizer/GstIirEqualizer10Bands.prs:
+	  * gst/equalizer/GstIirEqualizer3Bands.prs:
+	  * gst/equalizer/Makefile.am:
+	  * gst/equalizer/gstiirequalizer10bands.c:
+	  * gst/equalizer/gstiirequalizer3bands.c:
+	  Add presets for equalizer. Fixes #522183.
+
+2008-11-13 16:17:38 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/: Remove google extension again, it's not needed anymore because we never send multiple transports anymore.
+	  Original commit message from CVS:
+	  * gst/rtsp/Makefile.am:
+	  * gst/rtsp/gstrtsp.c: (plugin_init):
+	  * gst/rtsp/gstrtspgoogle.c:
+	  * gst/rtsp/gstrtspgoogle.h:
+	  Remove google extension again, it's not needed anymore because we never
+	  send multiple transports anymore.
+
+2008-11-13 16:11:16 +0000  Eric Zhang <chao.zhang@access-company.com>
+
+	  gst/rtsp/gstrtspsrc.*: Add property to configure NAT traversal method.
+	  Original commit message from CVS:
+	  Based on patch by: Eric Zhang <chao.zhang at access-company dot com>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtsp_nat_method_get_type),
+	  (gst_rtspsrc_class_init), (gst_rtspsrc_set_property),
+	  (gst_rtspsrc_get_property), (gst_rtspsrc_create_stream),
+	  (gst_rtspsrc_stream_free),
+	  (gst_rtspsrc_stream_configure_udp_sinks),
+	  (gst_rtspsrc_stream_configure_transport),
+	  (gst_rtspsrc_send_dummy_packets),
+	  (gst_rtspsrc_create_transports_string),
+	  (gst_rtspsrc_handle_message), (gst_rtspsrc_change_state):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Add property to configure NAT traversal method.
+	  Ignore EOS from the internal sinks.
+	  Implement sending dummy packets as a (simple) method to open up
+	  some firewalls.
+	  Send PLAY request to the server after we started the udp sources.
+	  Fixes #559545.
+
+2008-11-13 14:04:40 +0000  Yotam <sh.yotam@gmail.com>
+
+	  gst/rtp/gstrtpmp4vpay.c: Flush the remaining frames on EOS. Fixes #560641.
+	  Original commit message from CVS:
+	  Patch by: Yotam <sh dot yotam at gmail dot com>
+	  * gst/rtp/gstrtpmp4vpay.c: (gst_rtp_mp4v_pay_event):
+	  Flush the remaining frames on EOS. Fixes #560641.
+
+2008-11-12 16:37:06 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/rtp/gstrtpg729pay.c: Fix compiler warning about printf formatting.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpg729pay.c: (gst_rtp_g729_pay_handle_buffer):
+	  Fix compiler warning about printf formatting.
+
+2008-11-12 11:55:14 +0000  Andy Wingo <wingo@pobox.com>
+
+	  gst/qtdemux/qtdemux.*: Queue up new segment events instead of sending them from the seeking thread.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.h (struct _GstQTDemux):
+	  * gst/qtdemux/qtdemux.c (gst_qtdemux_do_seek): Queue up new
+	  segment events instead of sending them from the seeking thread.
+	  Fixes #559288.
+	  (gst_qtdemux_push_pending_newsegment): New helper, sends out
+	  queued newsegment events.
+	  (gst_qtdemux_loop_state_movie): Voilà, call it here. Only need to
+	  call it here, as we only seek when looping, and only push in the
+	  movie state.
+
+2008-11-11 19:52:05 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/qtdemux/: Add cover and alternative copyright tag, and enhance some existing ones by marking them as container at...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_tag_add_tmpo),
+	  (qtdemux_tag_add_covr), (qtdemux_parse_udta):
+	  * gst/qtdemux/qtdemux_fourcc.h:
+	  * gst/qtdemux/qtdemux_types.c:
+	  Add cover and alternative copyright tag, and enhance some existing
+	  ones by marking them as container atoms.
+
+2008-11-11 17:33:00 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpg729pay.c: Don't ignore the return value of setcaps.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpg729pay.c: (gst_rtp_g729_pay_set_caps):
+	  Don't ignore the return value of setcaps.
+
+2008-11-11 17:29:03 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtp/gstrtpg729pay.*: Replace G729 payloader with an improved version. Fixes #532409.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtp/gstrtpg729pay.c: (gst_rtp_g729_pay_base_init),
+	  (gst_rtp_g729_pay_class_init), (gst_rtp_g729_pay_init),
+	  (gst_rtp_g729_pay_set_caps), (gst_rtp_g729_pay_handle_buffer):
+	  * gst/rtp/gstrtpg729pay.h:
+	  Replace G729 payloader with an improved version. Fixes #532409.
+
+2008-11-11 16:00:48 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Only send one transport at a time for improved compatibility with some broken servers. See #53...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_create_transports_string),
+	  (gst_rtspsrc_change_state):
+	  Only send one transport at a time for improved compatibility with some
+	  broken servers. See #537832.
+
+2008-11-11 15:16:31 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Only pause/play in the seek handler when the source was playing.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_do_seek),
+	  (gst_rtspsrc_perform_seek):
+	  Only pause/play in the seek handler when the source was playing.
+	  Fixes #529379.
+
+2008-11-11 12:18:23 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-mux.c: Fix muxing of Dirac streams if the input already has the format we need, i.e. is the out...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_handle_dirac_packet):
+	  Fix muxing of Dirac streams if the input already has the format
+	  we need, i.e. is the output of matroskademux.
+
+2008-11-11 10:06:01 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavimux.c: Don't segfault on string typed tags being NULL. Fixes #560155.
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c:
+	  Don't segfault on string typed tags being NULL. Fixes #560155.
+
+2008-11-10 16:44:45 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/matroska/matroska-mux.c: Fix mapping AAC profile to Matroska codec id.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c: (aac_codec_data_to_codec_id),
+	  (gst_matroska_mux_audio_pad_setcaps):
+	  Fix mapping AAC profile to Matroska codec id.
+
+2008-11-10 16:36:09 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/qtdemux/qtdemux.c: Refactor some raw audio caps building, and handle >16-bit cases.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_trak),
+	  (qtdemux_video_caps), (qtdemux_audio_caps):
+	  Refactor some raw audio caps building, and handle >16-bit cases.
+	  Fix/replace building caps from a string description.
+
+2008-11-10 13:59:27 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  gst/: Make author name consistent with others.
+	  Original commit message from CVS:
+	  * gst/audiofx/audiowsincband.c:
+	  * gst/audiofx/audiowsinclimit.c:
+	  * gst/cutter/gstcutter.c:
+	  Make author name consistent with others.
+
+2008-11-10 12:13:21 +0000  Eric Zhang <chao.zhang@access-company.com>
+
+	  gst/rtsp/gstrtspsrc.c: Pause the RTSP stream before doing a new play request.
+	  Original commit message from CVS:
+	  Based on patch by: Eric Zhang <chao.zhang at access-company dot com>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_perform_seek),
+	  (gst_rtspsrc_stream_configure_udp_sink):
+	  Pause the RTSP stream before doing a new play request.
+	  Make sure that adding the udpsinks does not cause the rtspsrc to become
+	  a sink. Fixes #559547.
+
+2008-11-05 14:42:35 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/: Implement Dirac muxing into Matroska comforming to the spec, i.e. put all Dirac packages up to a pictu...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-ids.h:
+	  * gst/matroska/matroska-mux.c: (gst_matroska_pad_free),
+	  (gst_matroska_mux_handle_dirac_packet),
+	  (gst_matroska_mux_write_data):
+	  Implement Dirac muxing into Matroska comforming to the spec, i.e.
+	  put all Dirac packages up to a picture into a Matroska block.
+	  TODO: Implement writing of the ReferenceBlock Matroska elements,
+	  currently the Dirac muxing is only 100% correct if Matroska version 2
+	  is selected for muxing.
+
+2008-11-04 12:32:48 +0000  Bastien Nocera <hadess@hadess.net>
+
+	  Optionally use libv4l to access v4l2 devices. Fixes bug #545033.
+	  Original commit message from CVS:
+	  Patch by: Bastien Nocera <hadess at hadess dot net>,
+	  Hans de Goede <jwrdegoede at fedoraproject dot org>
+	  * configure.ac:
+	  * sys/v4l2/Makefile.am:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_get_read):
+	  * sys/v4l2/v4l2_calls.c: (gst_v4l2_get_capabilities),
+	  (gst_v4l2_fill_lists), (gst_v4l2_open), (gst_v4l2_close),
+	  (gst_v4l2_get_norm), (gst_v4l2_set_norm), (gst_v4l2_get_frequency),
+	  (gst_v4l2_set_frequency), (gst_v4l2_signal_strength),
+	  (gst_v4l2_get_attribute), (gst_v4l2_set_attribute),
+	  (gst_v4l2_get_input), (gst_v4l2_set_input):
+	  * sys/v4l2/v4l2_calls.h:
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2_buffer_finalize),
+	  (gst_v4l2_buffer_new), (gst_v4l2_buffer_pool_finalize),
+	  (gst_v4l2_buffer_pool_new), (gst_v4l2_buffer_pool_activate),
+	  (gst_v4l2src_fill_format_list),
+	  (gst_v4l2src_probe_caps_for_format_and_size),
+	  (gst_v4l2src_probe_caps_for_format), (gst_v4l2src_grab_frame),
+	  (gst_v4l2src_set_capture), (gst_v4l2src_capture_init),
+	  (gst_v4l2src_capture_start), (gst_v4l2src_capture_stop),
+	  (gst_v4l2src_get_nearest_size):
+	  Optionally use libv4l to access v4l2 devices. Fixes bug #545033.
+
+2008-11-04 12:28:34 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Don't install static libs for plugins. Fixes #550851 for -good.
+	  Original commit message from CVS:
+	  * ext/aalib/Makefile.am:
+	  * ext/annodex/Makefile.am:
+	  * ext/cairo/Makefile.am:
+	  * ext/dv/Makefile.am:
+	  * ext/esd/Makefile.am:
+	  * ext/flac/Makefile.am:
+	  * ext/gconf/Makefile.am:
+	  * ext/gdk_pixbuf/Makefile.am:
+	  * ext/hal/Makefile.am:
+	  * ext/jpeg/Makefile.am:
+	  * ext/ladspa/Makefile.am:
+	  * ext/libcaca/Makefile.am:
+	  * ext/libmng/Makefile.am:
+	  * ext/libpng/Makefile.am:
+	  * ext/mikmod/Makefile.am:
+	  * ext/pulse/Makefile.am:
+	  * ext/raw1394/Makefile.am:
+	  * ext/shout2/Makefile.am:
+	  * ext/soup/Makefile.am:
+	  * ext/speex/Makefile.am:
+	  * ext/taglib/Makefile.am:
+	  * ext/wavpack/Makefile.am:
+	  * gst/alpha/Makefile.am:
+	  * gst/apetag/Makefile.am:
+	  * gst/audiofx/Makefile.am:
+	  * gst/auparse/Makefile.am:
+	  * gst/autodetect/Makefile.am:
+	  * gst/avi/Makefile.am:
+	  * gst/cutter/Makefile.am:
+	  * gst/debug/Makefile.am:
+	  * gst/effectv/Makefile.am:
+	  * gst/equalizer/Makefile.am:
+	  * gst/flx/Makefile.am:
+	  * gst/goom/Makefile.am:
+	  * gst/goom2k1/Makefile.am:
+	  * gst/icydemux/Makefile.am:
+	  * gst/id3demux/Makefile.am:
+	  * gst/interleave/Makefile.am:
+	  * gst/law/Makefile.am:
+	  * gst/level/Makefile.am:
+	  * gst/matroska/Makefile.am:
+	  * gst/median/Makefile.am:
+	  * gst/monoscope/Makefile.am:
+	  * gst/multifile/Makefile.am:
+	  * gst/multipart/Makefile.am:
+	  * gst/oldcore/Makefile.am:
+	  * gst/qtdemux/Makefile.am:
+	  * gst/replaygain/Makefile.am:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtsp/Makefile.am:
+	  * gst/smpte/Makefile.am:
+	  * gst/spectrum/Makefile.am:
+	  * gst/udp/Makefile.am:
+	  * gst/videobox/Makefile.am:
+	  * gst/videocrop/Makefile.am:
+	  * gst/videofilter/Makefile.am:
+	  * gst/videomixer/Makefile.am:
+	  * gst/wavenc/Makefile.am:
+	  * gst/wavparse/Makefile.am:
+	  * sys/directdraw/Makefile.am:
+	  * sys/directsound/Makefile.am:
+	  * sys/oss/Makefile.am:
+	  * sys/osxaudio/Makefile.am:
+	  * sys/osxvideo/Makefile.am:
+	  * sys/sunaudio/Makefile.am:
+	  * sys/v4l2/Makefile.am:
+	  * sys/waveform/Makefile.am:
+	  * sys/ximage/Makefile.am:
+	  Don't install static libs for plugins. Fixes #550851 for -good.
+
+2008-10-31 18:17:50 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/flac/Makefile.am: Include $(FLAC_CFLAGS) in CFLAGS to make sure to find the FLAC headers.
+	  Original commit message from CVS:
+	  * ext/flac/Makefile.am:
+	  Include $(FLAC_CFLAGS) in CFLAGS to make sure to find the FLAC headers.
+	  This fixes compilation if FLAC is installed in an uncommon location
+	  that is not already handled by other CFLAGS. Fixes bug #558711.
+
+2008-10-31 10:08:50 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/v4l2/v4l2src_calls.c: Guard more uncommon formats with ifdefs so that we can compile on older versions.
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_format_get_rank):
+	  Guard more uncommon formats with ifdefs so that we can compile on older
+	  versions.
+
+2008-10-31 10:00:18 +0000  Nick Haddad <nick@haddads.net>
+
+	  gst/avi/gstavidemux.c: Invert other uncompressed RGB formats. Fixes #558554.
+	  Original commit message from CVS:
+	  Patch by: Nick Haddad <nick at haddads dot net>
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_is_uncompressed),
+	  (gst_avi_demux_invert), (gst_avi_demux_process_next_entry),
+	  (gst_avi_demux_stream_data):
+	  Invert other uncompressed RGB formats. Fixes #558554.
+
+2008-10-30 15:08:49 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/wavenc/gstwavenc.*: Add support for float/double as input and remove the (nowadays) useless parsing of the depth ...
+	  Original commit message from CVS:
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_create_header_buf),
+	  (gst_wavenc_sink_setcaps), (gst_wavenc_change_state):
+	  * gst/wavenc/gstwavenc.h:
+	  Add support for float/double as input and remove the (nowadays)
+	  useless parsing of the depth as we require width==depth.
+
+2008-10-30 10:31:35 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Narrow down the caps of the mpeg audio pay/depayloaders to only accept mpeg version 1. Fixes #558427.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmpadepay.c: (gst_rtp_mpa_depay_setcaps):
+	  * gst/rtp/gstrtpmpapay.c:
+	  Narrow down the caps of the mpeg audio pay/depayloaders to only accept
+	  mpeg version 1. Fixes #558427.
+
+2008-10-29 18:28:25 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpL16pay.c: Only put an integral amount of samples in the RTP packet.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpL16pay.c: (gst_rtp_L16_pay_flush),
+	  (gst_rtp_L16_pay_getcaps):
+	  Only put an integral amount of samples in the RTP packet.
+	  Fixes #556641.
+
+2008-10-28 17:42:02 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpchannels.*: Add method to get possible channel positions.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpchannels.c: (gst_rtp_channels_get_by_index):
+	  * gst/rtp/gstrtpchannels.h:
+	  Add method to get possible channel positions.
+
+2008-10-28 17:39:48 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/Makefile.am: Also commit updated makefile
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  Also commit updated makefile
+
+2008-10-28 14:56:08 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/wavenc/gstwavenc.c: Don't allow width=32,depth=24 as input. WAV requires that the width is the next integer multi...
+	  Original commit message from CVS:
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_chain):
+	  Don't allow width=32,depth=24 as input. WAV requires that the width
+	  is the next integer multiply of 8 from the depth.
+
+2008-10-28 10:01:49 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Add mappings for multichannel support. Does not completely just work because the getcaps function does not ...
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpL16depay.c: (gst_rtp_L16_depay_setcaps):
+	  * gst/rtp/gstrtpL16pay.c: (gst_rtp_L16_pay_setcaps),
+	  (gst_rtp_L16_pay_getcaps):
+	  * gst/rtp/gstrtpchannels.c: (check_channels),
+	  (gst_rtp_channels_get_by_pos), (gst_rtp_channels_get_by_order),
+	  (gst_rtp_channels_create_default):
+	  * gst/rtp/gstrtpchannels.h:
+	  Add mappings for multichannel support. Does not completely just work
+	  because the getcaps function does not yet return the allowed channel
+	  mappings. See #556641.
+
+2008-10-28 06:50:57 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/goom/: Add license headers in all source files. Remove filter.c from
+	  Original commit message from CVS:
+	  * gst/goom/Makefile.am:
+	  * gst/goom/README:
+	  * gst/goom/config_param.c:
+	  * gst/goom/convolve_fx.c:
+	  * gst/goom/drawmethods.c:
+	  * gst/goom/drawmethods.h:
+	  * gst/goom/filters.c:
+	  * gst/goom/filters_mmx.s:
+	  * gst/goom/flying_stars_fx.c:
+	  * gst/goom/goom.h:
+	  * gst/goom/goom_config.h:
+	  * gst/goom/goom_config_param.h:
+	  * gst/goom/goom_core.c:
+	  * gst/goom/goom_filters.h:
+	  * gst/goom/goom_fx.h:
+	  * gst/goom/goom_graphic.h:
+	  * gst/goom/goom_plugin_info.h:
+	  * gst/goom/goom_tools.c:
+	  * gst/goom/goom_tools.h:
+	  * gst/goom/goom_typedefs.h:
+	  * gst/goom/goom_visual_fx.h:
+	  * gst/goom/graphic.c:
+	  * gst/goom/ifs.c:
+	  * gst/goom/ifs.h:
+	  * gst/goom/lines.c:
+	  * gst/goom/lines.h:
+	  * gst/goom/mathtools.c:
+	  * gst/goom/mathtools.h:
+	  * gst/goom/mmx.c:
+	  * gst/goom/motif_goom1.h:
+	  * gst/goom/motif_goom2.h:
+	  * gst/goom/plugin_info.c:
+	  * gst/goom/ppc_drawings.h:
+	  * gst/goom/ppc_zoom_ultimate.h:
+	  * gst/goom/sound_tester.c:
+	  * gst/goom/sound_tester.h:
+	  * gst/goom/surf3d.c:
+	  * gst/goom/surf3d.h:
+	  * gst/goom/tentacle3d.c:
+	  * gst/goom/tentacle3d.h:
+	  * gst/goom/v3d.c:
+	  * gst/goom/v3d.h:
+	  * gst/goom/xmmx.c:
+	  Add license headers in all source files. Remove filter.c from
+	  EXTRA_DIST, as its in SOURCES already. Mention the files in the REDME
+	  which are not used right now. Fixes #557709.
+
+2008-10-27 11:28:30 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtp/gstrtpL16pay.c: Implement getcaps in rtpL16pay. Fixes #556484.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtp/gstrtpL16pay.c: (gst_rtp_L16_pay_class_init),
+	  (gst_rtp_L16_pay_setcaps), (gst_rtp_L16_pay_getcaps):
+	  Implement getcaps in rtpL16pay. Fixes #556484.
+
+2008-10-27 11:03:53 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpL16depay.c: Check if clock-rate and channels are valid.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpL16depay.c: (gst_rtp_L16_depay_setcaps),
+	  (gst_rtp_L16_depay_process):
+	  Check if clock-rate and channels are valid.
+	  Don't ignore the return value of setcaps.
+	  No need to validate the buffer, the base class does that for us.
+	  Use the marker bit to set the DISCONT flag on outgoing buffers.
+	  * gst/rtp/gstrtpL16pay.c: (gst_rtp_L16_pay_setcaps):
+	  Don't ignore the return value of set_outcaps.
+	  * gst/rtp/gstrtpac3depay.c: (gst_rtp_ac3_depay_setcaps),
+	  (gst_rtp_ac3_depay_process):
+	  Don't ignore the return value of set_caps.
+	  No need to validate the buffer, the base class does that for us.
+	  * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_setcaps),
+	  (gst_rtp_amr_depay_process):
+	  * gst/rtp/gstrtpamrdepay.h:
+	  Don't ignore the return value of setcaps.
+	  No need to validate the buffer, the base class does that for us.
+	  No need to set output caps on the buffers, the base class does that for
+	  us.
+	  The subclass will make sure we are negotiated.
+	  * gst/rtp/gstrtpdvdepay.c: (gst_rtp_dv_depay_setcaps),
+	  (gst_rtp_dv_depay_process), (gst_rtp_dv_depay_reset):
+	  * gst/rtp/gstrtpdvdepay.h:
+	  Clean up caps negotiation.
+	  The subclass will make sure we are negotiated.
+	  * gst/rtp/gstrtpg726depay.c: (gst_rtp_g726_depay_setcaps),
+	  (gst_rtp_g726_depay_process):
+	  Clean up caps negotiation.
+	  Use the marker bit to set the DISCONT flag on outgoing buffers.
+	  * gst/rtp/gstrtpg729depay.c: (gst_rtp_g729_depay_init),
+	  (gst_rtp_g729_depay_setcaps), (gst_rtp_g729_depay_process):
+	  * gst/rtp/gstrtpg729depay.h:
+	  The subclass will make sure we are negotiated.
+	  Use the marker bit to set the DISCONT flag on outgoing buffers.
+	  * gst/rtp/gstrtpgsmdepay.c: (gst_rtp_gsm_depay_setcaps),
+	  (gst_rtp_gsm_depay_process):
+	  Clean up caps negotiation.
+	  Use the marker bit to set the DISCONT flag on outgoing buffers.
+	  * gst/rtp/gstrtpgsmpay.c: (gst_rtp_gsm_pay_setcaps):
+	  Clean up caps negotiation.
+	  Don't ignore the return value of set_outcaps.
+	  * gst/rtp/gstrtph263depay.c: (gst_rtp_h263_depay_setcaps),
+	  (gst_rtp_h263_depay_process):
+	  Clean up caps negotiation.
+	  No need to validate the buffer, the base class does that for us.
+	  * gst/rtp/gstrtph263pay.c: (gst_rtp_h263_pay_setcaps),
+	  (gst_rtp_h263_pay_flush), (gst_rtp_h263_pay_handle_buffer):
+	  * gst/rtp/gstrtph263pay.h:
+	  Don't ignore the return value of set_outcaps.
+	  Do some more timestamps.
+	  * gst/rtp/gstrtph263pdepay.c: (gst_rtp_h263p_depay_setcaps),
+	  (gst_rtp_h263p_depay_process):
+	  Clean up caps negotiation.
+	  Don't ignore the return value of setcaps.
+	  No need to validate the buffer, the base class does that for us.
+	  * gst/rtp/gstrtph263ppay.c: (gst_rtp_h263p_pay_class_init),
+	  (gst_rtp_h263p_pay_setcaps), (gst_rtp_h263p_pay_flush),
+	  (gst_rtp_h263p_pay_handle_buffer):
+	  * gst/rtp/gstrtph263ppay.h:
+	  Don't ignore the return value of set_outcaps.
+	  Do some more timestamps.
+	  * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_setcaps),
+	  (gst_rtp_h264_depay_process):
+	  Clean up caps negotiation.
+	  Don't ignore the return value of setcaps.
+	  Fix possible caps leak.
+	  No need to validate the buffer, the base class does that for us.
+	  * gst/rtp/gstrtph264pay.c: (gst_rtp_h264_pay_setcaps):
+	  Add some more debug info.
+	  * gst/rtp/gstrtpilbcdepay.c: (gst_rtp_ilbc_depay_setcaps),
+	  (gst_rtp_ilbc_depay_process):
+	  Clean up caps negotiation.
+	  Use the marker bit to set the DISCONT flag on outgoing buffers.
+	  * gst/rtp/gstrtpilbcpay.c: (gst_rtpilbcpay_sink_setcaps):
+	  Clean up caps negotiation.
+	  * gst/rtp/gstrtpmp1sdepay.c: (gst_rtp_mp1s_depay_setcaps),
+	  (gst_rtp_mp1s_depay_process):
+	  Clean up caps negotiation.
+	  Don't ignore the return value of setcaps.
+	  No need to validate the buffer, the base class does that for us.
+	  No need to set caps on buffers, subclass does that for us.
+	  * gst/rtp/gstrtpmp2tdepay.c: (gst_rtp_mp2t_depay_setcaps),
+	  (gst_rtp_mp2t_depay_process):
+	  Clean up caps negotiation.
+	  Don't ignore the return value of setcaps.
+	  No need to validate the buffer, the base class does that for us.
+	  No need to set caps on buffers, subclass does that for us.
+	  * gst/rtp/gstrtpmp4adepay.c: (gst_rtp_mp4a_depay_setcaps),
+	  (gst_rtp_mp4a_depay_process):
+	  Clean up caps negotiation.
+	  Don't ignore the return value of setcaps.
+	  No need to validate the buffer, the base class does that for us.
+	  * gst/rtp/gstrtpmp4apay.c: (gst_rtp_mp4a_pay_new_caps),
+	  (gst_rtp_mp4a_pay_setcaps):
+	  Don't ignore the return value of set_outcaps.
+	  * gst/rtp/gstrtpmp4gdepay.c: (gst_rtp_mp4g_depay_setcaps),
+	  (gst_rtp_mp4g_depay_process):
+	  Clean up caps negotiation.
+	  Don't ignore the return value of setcaps.
+	  No need to validate the buffer, the base class does that for us.
+	  No need to set caps on buffers, subclass does that for us.
+	  * gst/rtp/gstrtpmp4gpay.c: (gst_rtp_mp4g_pay_finalize),
+	  (gst_rtp_mp4g_pay_new_caps), (gst_rtp_mp4g_pay_setcaps):
+	  Don't ignore the return value of set_outcaps.
+	  * gst/rtp/gstrtpmp4vdepay.c: (gst_rtp_mp4v_depay_setcaps),
+	  (gst_rtp_mp4v_depay_process):
+	  Clean up caps negotiation.
+	  Don't ignore the return value of setcaps.
+	  No need to validate the buffer, the base class does that for us.
+	  No need to set caps on buffers, subclass does that for us.
+	  * gst/rtp/gstrtpmp4vpay.c: (gst_rtp_mp4v_pay_new_caps),
+	  (gst_rtp_mp4v_pay_setcaps):
+	  Don't ignore the return value of set_outcaps.
+	  * gst/rtp/gstrtpmpadepay.c: (gst_rtp_mpa_depay_setcaps),
+	  (gst_rtp_mpa_depay_process):
+	  Clean up caps negotiation.
+	  Don't ignore the return value of setcaps.
+	  No need to validate the buffer, the base class does that for us.
+	  Use the marker bit to set the DISCONT flag on outgoing buffers.
+	  * gst/rtp/gstrtpmpapay.c: (gst_rtp_mpa_pay_setcaps):
+	  Don't ignore the return value of set_outcaps.
+	  * gst/rtp/gstrtpmpvdepay.c: (gst_rtp_mpv_depay_setcaps),
+	  (gst_rtp_mpv_depay_process):
+	  Clean up caps negotiation.
+	  Actually set output caps.
+	  No need to validate the buffer, the base class does that for us.
+	  * gst/rtp/gstrtpmpvpay.c: (gst_rtp_mpv_pay_setcaps):
+	  Don't ignore the return value of set_outcaps.
+	  * gst/rtp/gstrtppcmadepay.c: (gst_rtp_pcma_depay_setcaps),
+	  (gst_rtp_pcma_depay_process):
+	  Clean up caps negotiation.
+	  Set output buffer duration because we can.
+	  Use the marker bit to set the DISCONT flag on outgoing buffers.
+	  * gst/rtp/gstrtppcmapay.c: (gst_rtp_pcma_pay_setcaps):
+	  Don't ignore the return value of set_outcaps.
+	  * gst/rtp/gstrtppcmudepay.c: (gst_rtp_pcmu_depay_setcaps),
+	  (gst_rtp_pcmu_depay_process):
+	  Clean up caps negotiation.
+	  Use the marker bit to set the DISCONT flag on outgoing buffers.
+	  * gst/rtp/gstrtppcmupay.c: (gst_rtp_pcmu_pay_setcaps):
+	  Don't ignore the return value of set_outcaps.
+	  * gst/rtp/gstrtpspeexdepay.c: (gst_rtp_speex_depay_init),
+	  (gst_rtp_speex_depay_setcaps), (gst_rtp_speex_depay_process):
+	  Clean up caps negotiation.
+	  Set output caps on the pad and header buffers.
+	  Set duration on output buffers because we can.
+	  * gst/rtp/gstrtpspeexpay.c: (gst_rtp_speex_pay_parse_ident):
+	  Don't ignore the return value of set_outcaps.
+	  * gst/rtp/gstrtpsv3vdepay.c: (gst_rtp_sv3v_depay_setcaps),
+	  (gst_rtp_sv3v_depay_process):
+	  Clean up caps negotiation.
+	  No need to validate the buffer, the base class does that for us.
+	  No need to set caps out output buffers, subclass does that.
+	  * gst/rtp/gstrtptheoradepay.c: (gst_rtp_theora_depay_setcaps),
+	  (gst_rtp_theora_depay_process):
+	  Don't ignore the return value of setcaps.
+	  No need to validate the buffer, the base class does that for us.
+	  * gst/rtp/gstrtptheorapay.c: (gst_rtp_theora_pay_class_init),
+	  (gst_rtp_theora_pay_flush_packet), (encode_base64),
+	  (gst_rtp_theora_pay_finish_headers), (gst_rtp_theora_pay_parse_id),
+	  (gst_rtp_theora_pay_handle_buffer):
+	  Don't ignore the return value of set_outcaps.
+	  * gst/rtp/gstrtpvorbisdepay.c: (gst_rtp_vorbis_depay_setcaps),
+	  (gst_rtp_vorbis_depay_process):
+	  Don't ignore the return value of setcaps.
+	  No need to validate the buffer, the base class does that for us.
+	  * gst/rtp/gstrtpvorbispay.c: (gst_rtp_vorbis_pay_finish_headers):
+	  Don't ignore the return value of set_outcaps.
+	  * gst/rtp/gstrtpvrawdepay.c: (gst_rtp_vraw_depay_setcaps):
+	  Clean up caps negotiation, don't ignore setcaps return.
+	  * gst/rtp/gstrtpvrawpay.c: (gst_rtp_vraw_pay_setcaps):
+	  Don't ignore the return value of set_outcaps.
+
+2008-10-27 10:35:07 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/matroska/matroska-demux.c: Forward unknown events upstream.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_handle_src_event):
+	  Forward unknown events upstream.
+
+2008-10-27 10:33:20 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  tests/check/elements/icydemux.c: Add some refcount check
+	  Original commit message from CVS:
+	  * tests/check/elements/icydemux.c: (icydemux_found_pad):
+	  Add some refcount check
+	  * tests/check/elements/rtp-payloading.c: (rtp_pipeline_run):
+	  Don't ignore the result of write(), fixes a  compiler warning for me.
+	  * tests/icles/videobox-test.c: (main):
+	  Make the output a little more pretty.
+
+2008-10-27 09:26:19 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/esd/esdmon.c: Add doc blob.
+	  Original commit message from CVS:
+	  * ext/esd/esdmon.c:
+	  Add doc blob.
+
+2008-10-27 09:21:44 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/: Add the docs of the new elements.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-good-plugins.interfaces:
+	  * docs/plugins/inspect/plugin-autodetect.xml:
+	  Add the docs of the new elements.
+
+2008-10-27 09:04:37 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/autodetect/: Fix "Since" tags in the documentation.
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautoaudiosrc.c:
+	  (gst_auto_audio_src_class_init):
+	  * gst/autodetect/gstautovideosrc.c:
+	  (gst_auto_video_src_class_init):
+	  Fix "Since" tags in the documentation.
+
+2008-10-27 09:00:29 +0000  Sjoerd Simons <sjoerd@luon.net>
+
+	  ext/soup/gstsouphttpsrc.c: Add support for souphttpsrc to act as a live source. This makes it possible to get timesta...
+	  Original commit message from CVS:
+	  Patch by: Sjoerd Simons <sjoerd at luon dot net>
+	  * ext/soup/gstsouphttpsrc.c: (gst_soup_http_src_class_init),
+	  (gst_soup_http_src_set_property), (gst_soup_http_src_get_property):
+	  Add support for souphttpsrc to act as a live source. This makes it
+	  possible to get timestamped buffers in combination with the
+	  "do-timestamp" property. Fixes bug #556019.
+
+2008-10-27 08:54:30 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/autodetect/: Implement src plugins. Little code/string cleanup in the sinks.
+	  Original commit message from CVS:
+	  * gst/autodetect/Makefile.am:
+	  * gst/autodetect/gstautoaudiosink.c:
+	  * gst/autodetect/gstautoaudiosrc.c:
+	  * gst/autodetect/gstautoaudiosrc.h:
+	  * gst/autodetect/gstautodetect.c:
+	  * gst/autodetect/gstautovideosink.c:
+	  * gst/autodetect/gstautovideosrc.c:
+	  * gst/autodetect/gstautovideosrc.h:
+	  Implement src plugins. Little code/string cleanup in the sinks.
+	  Fixes #523813.
+
+2008-10-27 08:45:11 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/matroska/matroska-mux.c: Fix a memory leak when pads are requested but the pipeline never goes into PLAYING.
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt <pkj at axis com>
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_reset),
+	  (gst_matroska_mux_request_new_pad), (gst_matroska_mux_release_pad):
+	  Fix a memory leak when pads are requested but the pipeline never
+	  goes into PLAYING.
+	  Correctly remove request pads, no matter if they have collected
+	  data or not.
+	  Fixes bug #557710.
+
+2008-10-27 08:40:02 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/udp/gstudpnetutils.h: Define the correct WINVER so getaddinfo() can be used when using mingw32. Fixes bug #557294.
+	  Original commit message from CVS:
+	  Patch by: <lrn1986 at gmail dot com>
+	  * gst/udp/gstudpnetutils.h:
+	  Define the correct WINVER so getaddinfo() can be used when using
+	  mingw32. Fixes bug #557294.
+
+2008-10-27 08:36:43 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/udp/: Fix "argument type mismatch" compiler warnings on Windows.
+	  Original commit message from CVS:
+	  Patch by: <lrn1986 at gmail dot com>
+	  * gst/udp/gstdynudpsink.c: (gst_dynudpsink_render):
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_render):
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_create):
+	  Fix "argument type mismatch" compiler warnings on Windows.
+	  Fixes bug #557293.
+
+2008-10-27 08:30:51 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/equalizer/gstiirequalizer.c: Don't calculate the filter coefficients for every single buffer but only when it's n...
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer.c: (update_coefficients):
+	  Don't calculate the filter coefficients for every single buffer
+	  but only when it's needed. Fixes bug #557260.
+
+2008-10-26 20:05:43 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Back to development -> 0.10.11.1
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Back to development -> 0.10.11.1
+
+2008-10-26 20:04:21 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst-plugins-good.doap: Fix version number of 0.10.11 release in doap file
+	  Original commit message from CVS:
+	  * gst-plugins-good.doap:
+	  Fix version number of 0.10.11 release in doap file
+
+=== release 0.10.11 ===
+
+2008-10-24 22:41:18 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.10.11
+	  Original commit message from CVS:
+	  Release 0.10.11
+
+2008-10-24 22:20:47 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/id.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+	  Original commit message from CVS:
+	  Update .po files
+
+2008-10-24 16:30:53 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Commit 0.10.10.4 pre-release
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Commit 0.10.10.4 pre-release
+
+2008-10-21 12:42:45 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/avi/gstavimux.c: Fix VPRP chunk setup in avimux.
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c:
+	  Fix VPRP chunk setup in avimux.
+	  Fixes: #556010
+	  Patch By: Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+2008-10-21 12:38:35 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  gst/videobox/gstvideobox.c: support dynamically changing properties in videobox
+	  Original commit message from CVS:
+	  * gst/videobox/gstvideobox.c:
+	  support dynamically changing properties in videobox
+	  Fixed: #557085
+	  Patch By: Wim Taymans <wim.taymans@collabora.co.uk>
+
+2008-10-16 17:10:42 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: 0.10.10.3 pre-release
+	  Original commit message from CVS:
+	  * configure.ac:
+	  0.10.10.3 pre-release
+
+2008-10-16 15:30:22 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  tests/check/Makefile.am: Don't run the states test on pulsesrc and pulsesink
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Don't run the states test on pulsesrc and pulsesink
+
+2008-10-16 11:52:44 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Commit 0.10.10.2 pre-release bump that actually went out on 2008-10-11
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Commit 0.10.10.2 pre-release bump that actually went
+	  out on 2008-10-11
+
+2008-10-15 15:42:29 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/avi/gstavidemux.c: Skip entries for streams that don't have a output pad yet, thereby avoiding calling pad functi...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_stream_scan):
+	  Skip entries for streams that don't have a output pad yet, thereby
+	  avoiding calling pad functions with a NULL pad.
+	  Fixes #556424
+
+2008-10-15 09:39:27 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Remove previous wrong commit
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: Remove previous wrong commit
+	  * tests/check/elements/icydemux.c: (icydemux_found_pad):
+	  Remove problematic and useless refcount check.
+	  Fixes #556381
+
+2008-10-15 09:27:27 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Remove problematic and useless refcount check.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_node):
+	  Remove problematic and useless refcount check.
+	  Fixes #556381
+
+2008-10-10 12:28:34 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/flac/: Cast some size_t arguments to guint to avoid compiler warnings on 64-bit systems.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c (gst_flac_dec_read_stream):
+	  * ext/flac/gstflacenc.c (gst_flac_enc_write_callback):
+	  Cast some size_t arguments to guint to avoid compiler
+	  warnings on 64-bit systems.
+
+2008-10-09 14:27:12 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Return TRUE instead of FALSE from the event handler when we swallowed the event.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_handle_src_event):
+	  Return TRUE instead of FALSE from the event handler when we swallowed the
+	  event.
+
+2008-10-08 15:59:56 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  remove old CDIO plugin now in ugly
+	  Original commit message from CVS:
+	  remove old CDIO plugin now in ugly
+
+2008-10-08 14:47:14 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: Reset header state. Fixes #555321.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_reset),
+	  (gst_avi_demux_parse_subindex), (gst_avi_demux_parse_index):
+	  Reset header state. Fixes #555321.
+
+2008-10-08 13:31:44 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.*: For timestamping audio packets we need to take into account the amount of blocks in one entry ...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_subindex),
+	  (gst_avi_demux_parse_stream), (gst_avi_demux_parse_index):
+	  * gst/avi/gstavidemux.h:
+	  For timestamping audio packets we need to take into account the
+	  amount of blocks in one entry using the blockalign. Fixes some sync
+	  issues with zero-padded audio blocks in the beginning of avi files.
+
+2008-10-08 10:42:26 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/multifile/gstmultifilesrc.c: Implement DEFAULT and BUFFER position queries. See #555260.
+	  Original commit message from CVS:
+	  * gst/multifile/gstmultifilesrc.c: (gst_multi_file_src_class_init),
+	  (gst_multi_file_src_query):
+	  Implement DEFAULT and BUFFER position queries. See #555260.
+
+2008-10-08 09:29:00 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  sys/ximage/gstximagesrc.c: Fix build for systems that don't have XDamage.
+	  Original commit message from CVS:
+	  * sys/ximage/gstximagesrc.c: (gst_ximage_src_stop):
+	  Fix build for systems that don't have XDamage.
+
+2008-10-07 09:58:13 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  tests/examples/rtp/: Add some more H263p server and client examples.
+	  Original commit message from CVS:
+	  * tests/examples/rtp/client-H263p.sdp:
+	  * tests/examples/rtp/client-H263p.sh:
+	  * tests/examples/rtp/server-VTS-H263p.sh:
+	  Add some more H263p server and client examples.
+
+2008-10-03 17:03:07 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Depend on released versions of core and base.
+	  Original commit message from CVS:
+	  * configure.ac::
+	  Depend on released versions of core and base.
+
+2008-10-03 16:13:32 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/pulse/: Return -1 instead of 0 in error cases. Fixes #554771.
+	  Original commit message from CVS:
+	  * ext/pulse/pulsesink.c: (gst_pulsesink_write):
+	  * ext/pulse/pulsesrc.c: (gst_pulsesrc_read):
+	  Return -1 instead of 0 in error cases. Fixes #554771.
+
+2008-10-03 15:54:07 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/ximage/gstximagesrc.c: Stop leaking the cursor image.
+	  Original commit message from CVS:
+	  * sys/ximage/gstximagesrc.c: (gst_ximage_src_start),
+	  (gst_ximage_src_stop), (gst_ximage_src_ximage_get):
+	  Stop leaking the cursor image.
+	  Unref the last_ximage and the cached cursor image on shutdown.
+	  Fixes #551570.
+
+2008-10-03 11:32:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/v4l2/gstv4l2object.h: Getting the Class from an instance is not just a matter of casting it to the class struct b...
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2object.h:
+	  Getting the Class from an instance is not just a matter of casting it to
+	  the class struct but it involves calling G_OBJECT_GET_CLASS on the
+	  instance. Fixes #549784.
+
+2008-10-01 21:22:26 +0000  Michael Smith <msmith@xiph.org>
+
+	  configure.ac: Fix libs for linking directsound.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Fix libs for linking directsound.
+	  * sys/directsound/gstdirectsoundsink.c:
+	  Fix buffer sizing to prevent racing the ringbuffer at startup.
+	  Add volume property.
+
+2008-09-27 00:43:07 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/pulse/pulsesink.c: Fix problems with pulsesink randomly erroring with code 'OK' after a format change on the stre...
+	  Original commit message from CVS:
+	  * ext/pulse/pulsesink.c:
+	  Fix problems with pulsesink randomly erroring with code 'OK' after a
+	  format change on the stream by waiting when disconnecting the stream.
+
+2008-09-26 14:44:49 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpamrdepay.c: Mark DISCONT on output buffers when the marker bit signals a new talk spurt.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_class_init),
+	  (gst_rtp_amr_depay_process):
+	  Mark DISCONT on output buffers when the marker bit signals a new talk
+	  spurt.
+	  * gst/rtp/gstrtpamrpay.c: (gst_rtp_amr_pay_handle_buffer):
+	  Set the marker bit for buffers with a DISCONT flag to signal a talk
+	  spurt.
+
+2008-09-26 13:55:48 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Added MP4A-LATM payloader to match the depayloader.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpmp4apay.c: (gst_rtp_mp4a_pay_get_type),
+	  (gst_rtp_mp4a_pay_base_init), (gst_rtp_mp4a_pay_class_init),
+	  (gst_rtp_mp4a_pay_init), (gst_rtp_mp4a_pay_finalize),
+	  (gst_rtp_mp4a_pay_parse_audio_config), (gst_rtp_mp4a_pay_new_caps),
+	  (gst_rtp_mp4a_pay_setcaps), (gst_rtp_mp4a_pay_handle_buffer),
+	  (gst_rtp_mp4a_pay_change_state), (gst_rtp_mp4a_pay_plugin_init):
+	  * gst/rtp/gstrtpmp4apay.h:
+	  Added MP4A-LATM payloader to match the depayloader.
+
+2008-09-25 15:11:16 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/videomixer/videomixer.c: Handle segments a little better. Fixes #537361.
+	  Original commit message from CVS:
+	  * gst/videomixer/videomixer.c: (gst_videomixer_fill_queues),
+	  (gst_videomixer_sink_event):
+	  Handle segments a little better. Fixes #537361.
+
+2008-09-25 12:07:46 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Don't assume the server supports PAUSE by default. Fixes #551048.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_parse_methods):
+	  Don't assume the server supports PAUSE by default. Fixes #551048.
+
+2008-09-25 11:30:35 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstudpsrc.c: Switch on the socket family to get the addrlen size right.
+	  Original commit message from CVS:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init),
+	  (gst_udpsrc_set_uri), (gst_udpsrc_start):
+	  Switch on the socket family to get the addrlen size right.
+
+2008-09-25 10:34:39 +0000  Daniel Franke <df@dfranke.us>
+
+	  gst/udp/gstudpsrc.c: OS X's bind() implementation is picky about its addrlen parameter and fails with EINVAL if it is...
+	  Original commit message from CVS:
+	  Patch by: Daniel Franke <df at dfranke dot us>
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_create), (gst_udpsrc_start):
+	  OS X's bind() implementation is picky about its addrlen parameter and
+	  fails with EINVAL if it is larger than expected for the socket's address
+	  family. Set the length to the expected length instead. Fixes #553191.
+
+2008-09-23 18:08:56 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Handle the case where we cannot do desribe or when the describe result does not contain a vali...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_open):
+	  Handle the case where we cannot do desribe or when the describe result
+	  does not contain a valid SDP message.
+
+2008-09-23 17:31:22 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstmultiudpsink.c: Fix setting the qos.
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_set_property):
+	  Fix setting the qos.
+
+2008-09-17 14:50:42 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Some 'broken' files out there have atom lengths of zero... which basically results in qtdemux ...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_state_header),
+	  (gst_qtdemux_chain):
+	  Some 'broken' files out there have atom lengths of zero...
+	  which basically results in qtdemux consuming that atom again and again
+	  until the *end of night* !
+	  Detect that and emits an adequate element error message.
+
+2008-09-17 13:49:04 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/: Fix build flags order.
+	  Original commit message from CVS:
+	  * gst/interleave/Makefile.am:
+	  * gst/matroska/Makefile.am:
+	  Fix build flags order.
+	  * tests/check/elements/audioamplify.c: (GST_START_TEST):
+	  * tests/check/elements/audiodynamic.c: (GST_START_TEST):
+	  * tests/check/elements/audioinvert.c: (GST_START_TEST):
+	  * tests/check/elements/audiopanorama.c: (GST_START_TEST):
+	  Format fixes.
+	  * tests/check/elements/multifile.c:
+	  Pull in unistd.h
+
+2008-09-15 21:10:23 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmp4gdepay.*: Handle interleaved streams by reordering AU in a queue.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4gdepay.c: (gst_rtp_mp4g_depay_init),
+	  (gst_rtp_mp4g_depay_finalize), (gst_rtp_mp4g_depay_setcaps),
+	  (gst_rtp_mp4g_depay_clear_queue), (gst_rtp_mp4g_depay_flush_queue),
+	  (gst_rtp_mp4g_depay_queue), (gst_rtp_mp4g_depay_process),
+	  (gst_rtp_mp4g_depay_change_state):
+	  * gst/rtp/gstrtpmp4gdepay.h:
+	  Handle interleaved streams by reordering AU in a queue.
+
+2008-09-15 16:04:26 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmp4gdepay.c: Change some of the ranges in the caps, mostly for the amount of bits we can use.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4gdepay.c: (gst_bs_parse_init),
+	  (gst_bs_parse_read), (gst_rtp_mp4g_depay_process):
+	  Change some of the ranges in the caps, mostly for the amount of bits we
+	  can use.
+	  Added a little bitstream parse and use it to parse the AU header fields.
+	  Check for malformed and wrongly sized packets better.
+	  Implement more header field parsing.
+	  Handle the size of fragmented packets correctly.
+
+2008-09-14 11:32:15 +0000  Jonathan Matthew <notverysmart@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Add mapping for 'tiff' => image/tiff
+	  Original commit message from CVS:
+	  Patch by: Jonathan Matthew <notverysmart@gmail.com>
+	  * gst/qtdemux/qtdemux.c: (qtdemux_video_caps):
+	  Add mapping for 'tiff' => image/tiff
+	  Fixes #552213
+
+2008-09-11 11:26:06 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/raw1394/: Pretend to care about the result of write() which works around compiler warnings.
+	  Original commit message from CVS:
+	  * ext/raw1394/gstdv1394src.c: (SEND_COMMAND):
+	  * ext/raw1394/gsthdv1394src.c: (SEND_COMMAND):
+	  Pretend to care about the result of write() which works around
+	  compiler warnings.
+
+2008-09-04 09:25:59 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacenc.c: Make sure the desired default values are actually set, not only registered as defaults (actual...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacenc.c: (gst_flac_enc_class_init):
+	  Make sure the desired default values are actually set, not only
+	  registered as defaults (actual problem is that the stereo-specific
+	  values are only updated if channels==2, which is not the case yet
+	  when the object is created, so the default values for the
+	  mid-side-stereo and loose-mid-side-stereo settings are never
+	  set in _update_quality()). Makes flacenc create smaller files by
+	  default (for stereo input), and fixes #550791.
+
+2008-09-03 12:39:35 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/qtdemux/: Add support for video/mj2 mime-type and its additional atoms/boxes.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_change_state),
+	  (gst_qtdemux_loop_state_header), (qtdemux_parse_node),
+	  (qtdemux_parse_trak), (qtdemux_video_caps):
+	  * gst/qtdemux/qtdemux.h:
+	  * gst/qtdemux/qtdemux_fourcc.h:
+	  * gst/qtdemux/qtdemux_types.c:
+	  Add support for video/mj2 mime-type and its additional atoms/boxes.
+	  Fixes #550646.
+
+2008-09-03 11:10:25 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/debug/gsttaginject.c: Add warning when tags parameter is unparsable and give example for quoting in the docs.
+	  Original commit message from CVS:
+	  * gst/debug/gsttaginject.c:
+	  Add warning when tags parameter is unparsable and give example for
+	  quoting in the docs.
+
+2008-09-02 15:27:49 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Add mapping for IMA Loki SDL MJPEG ADPCM codec.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_audio_caps):
+	  Add mapping for IMA Loki SDL MJPEG ADPCM codec.
+	  Add some alternative byteswapped mappings that seem to pop up sometimes.
+	  Fixes #550288.
+
+2008-09-02 09:40:38 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  po/: Add 'ca' to LINGUAS; add some more files with translations and some files which should be ignored by translation...
+	  Original commit message from CVS:
+	  * po/LINGUAS:
+	  * po/POTFILES.in:
+	  * po/POTFILES.skip:
+	  Add 'ca' to LINGUAS; add some more files with translations and some
+	  files which should be ignored by translation tools.
+
+2008-09-02 08:51:04 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/speex/: Use integer encoding and decoding functions instead of converting the integer input to float in the eleme...
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexdec.c: (speex_dec_chain_parse_data):
+	  * ext/speex/gstspeexdec.h:
+	  * ext/speex/gstspeexenc.c: (gst_speex_enc_encode):
+	  * ext/speex/gstspeexenc.h:
+	  Use integer encoding and decoding functions instead of converting
+	  the integer input to float in the element. The libspeex integer
+	  functions are doing this for us already or, if libspeex was compiled
+	  in integer mode, they're doing everything using integer arithmetics.
+	  Also saves some copying around.
+
+2008-09-01 13:29:29 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Fix --disable-external
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Fix --disable-external
+
+2008-08-31 17:09:18 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackenc.*: Handle non-zero start timestamps and stream discontinuities correctly. This only has an ...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_reset),
+	  (gst_wavpack_enc_push_block), (gst_wavpack_enc_chain):
+	  * ext/wavpack/gstwavpackenc.h:
+	  Handle non-zero start timestamps and stream discontinuities
+	  correctly. This only has an effect if we're muxing into
+	  a container format as the raw WavPack stream must contain
+	  continous sample numbers.
+
+2008-08-31 15:02:09 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/speex/gstspeexenc.c: Correct the timestamp and granulepos calculation by one Speex frame.
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexenc.c: (gst_speex_enc_encode):
+	  Correct the timestamp and granulepos calculation by one Speex
+	  frame.
+
+2008-08-31 14:39:57 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/speex/gstspeexdec.c: Correctly take the granulepos from upstream if possible and correctly handle the granulepos ...
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexdec.c: (speex_dec_chain_parse_data):
+	  Correctly take the granulepos from upstream if possible and
+	  correctly handle the granulepos in various calculations: the
+	  granulepos is the sample number of the _last_ sample in a frame, not
+	  the first.
+	  * ext/speex/gstspeexenc.c: (gst_speex_enc_sinkevent),
+	  (gst_speex_enc_encode), (gst_speex_enc_chain),
+	  (gst_speex_enc_change_state):
+	  * ext/speex/gstspeexenc.h:
+	  Handle non-zero start timestamps in the encoder and detect/handle
+	  stream discontinuities. Fixes bug #547075.
+
+2008-08-31 08:32:45 +0000  Craig Keogh <cskeogh@adam.com.au>
+
+	  ext/annodex/gstcmmlparser.c: Fix compiler warnings caused by passing a string as format string instead of "%s" and th...
+	  Original commit message from CVS:
+	  Patch by: Craig Keogh <cskeogh at adam dot com dot au>
+	  * ext/annodex/gstcmmlparser.c: (gst_cmml_parser_parse_chunk):
+	  Fix compiler warnings caused by passing a string as format string
+	  instead of "%s" and then the string. This is only exposed by -Wformat=2
+	  as used by default on Ubuntu. Fixes bug #550015.
+
+2008-08-30 14:15:03 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Make stuff compile with GST_DISABLE_GST_DEBUG.
+	  Original commit message from CVS:
+	  * ext/raw1394/gsthdv1394src.c: (gst_hdv1394src_create):
+	  * gst/alpha/gstalpha.c: (gst_alpha_get_unit_size):
+	  * gst/audiofx/audiocheblimit.c: (generate_coefficients):
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_src_convert):
+	  * gst/matroska/ebml-read.c: (gst_ebml_read_element_id),
+	  (gst_ebml_read_element_length):
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_check_subtitle_buffer):
+	  Make stuff compile with GST_DISABLE_GST_DEBUG.
+
+2008-08-29 00:28:55 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/law/: Ref caps before passing to gst_pad_template_new(), since that takes ownership.
+	  Original commit message from CVS:
+	  * gst/law/alaw.c:
+	  * gst/law/mulaw.c:
+	  Ref caps before passing to gst_pad_template_new(), since that takes
+	  ownership.
+
+2008-08-28 10:09:16 +0000  Mersad Jelacic <mersad@axis.com>
+
+	  gst/multipart/: Convert audio/x-adpcm to and from the audio/G726-X in the muxer and demuxer. Fixes #549551.
+	  Original commit message from CVS:
+	  Patch by: Mersad Jelacic <mersad at axis dot com>
+	  * gst/multipart/multipartdemux.c:
+	  * gst/multipart/multipartmux.c: (gst_multipart_mux_get_mime):
+	  Convert audio/x-adpcm to and from the audio/G726-X in the muxer and
+	  demuxer. Fixes #549551.
+
+2008-08-27 16:12:39 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  sys/osxaudio/: Fix the build on macosx.
+	  Original commit message from CVS:
+	  * sys/osxaudio/gstosxaudiosink.c:
+	  (gst_osx_audio_sink_select_device):
+	  * sys/osxaudio/gstosxaudiosrc.c:
+	  (gst_osx_audio_src_create_ringbuffer),
+	  (gst_osx_audio_src_select_device):
+	  * sys/osxaudio/gstosxringbuffer.c: (gst_osx_ring_buffer_acquire):
+	  Fix the build on macosx.
+
+2008-08-27 15:42:11 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/icydemux/gsticydemux.c: Small docs fix: in the example pipeline, we need to pass iradio-mode=true to the source, ...
+	  Original commit message from CVS:
+	  * gst/icydemux/gsticydemux.c:
+	  Small docs fix: in the example pipeline, we need to pass
+	  iradio-mode=true to the source, so the server actually sends
+	  an ICY stream.
+
+2008-08-27 00:08:20 +0000  Michael Smith <msmith@xiph.org>
+
+	  sys/osxaudio/gstosxaudio.c: Oops. Revert more completely.
+	  Original commit message from CVS:
+	  * sys/osxaudio/gstosxaudio.c:
+	  Oops. Revert more completely.
+
+2008-08-26 23:57:05 +0000  Michael Smith <msmith@xiph.org>
+
+	  sys/osxaudio/gstosxaudio.c: Revert accidental element rename from testing.
+	  Original commit message from CVS:
+	  * sys/osxaudio/gstosxaudio.c:
+	  Revert accidental element rename from testing.
+
+2008-08-26 23:53:40 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst-plugins-good.doap: Pull in 0.10.10 doap entry from release branch
+	  Original commit message from CVS:
+	  * gst-plugins-good.doap:
+	  Pull in 0.10.10 doap entry from release branch
+
+2008-08-26 23:05:57 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Update version number to reflect 0.10.10 release from branch.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Update version number to reflect 0.10.10 release from
+	  branch.
+
+2008-08-26 21:13:08 +0000  Michael Smith <msmith@xiph.org>
+
+	  sys/osxaudio/: Rewrite caps setting and ring buffer initialisation.
+	  Original commit message from CVS:
+	  * sys/osxaudio/Makefile.am:
+	  * sys/osxaudio/gstosxaudio.c:
+	  * sys/osxaudio/gstosxaudiosink.c:
+	  * sys/osxaudio/gstosxaudiosink.h:
+	  * sys/osxaudio/gstosxaudiosrc.c:
+	  * sys/osxaudio/gstosxaudiosrc.h:
+	  * sys/osxaudio/gstosxringbuffer.c:
+	  * sys/osxaudio/gstosxringbuffer.h:
+	  Rewrite caps setting and ring buffer initialisation.
+	  Previously we never told CoreAudio what format we were going to send it,
+	  so it only worked due to luck, and not at all on some hardware.
+	  Now we explicitly advertise what formats the hardware supports, and then
+	  configure the selected one correctly.
+
+2008-08-26 12:27:11 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/v4l2/: Fix memory leaks. Small code cleanups : No need for empty _init(). No need to memset instance structures. ...
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2object.c:
+	  * sys/v4l2/gstv4l2src.c:
+	  * sys/v4l2/gstv4l2src.h:
+	  * sys/v4l2/v4l2_calls.c:
+	  * sys/v4l2/v4l2src_calls.c:
+	  Fix memory leaks. Small code cleanups : No need for empty _init(). No
+	  need to memset instance structures. Some more FIXME's.
+
+2008-08-26 08:11:26 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/icles/.cvsignore: Ignore more.
+	  Original commit message from CVS:
+	  * tests/icles/.cvsignore:
+	  Ignore more.
+
+2008-08-26 08:00:57 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/: Ignore files.
+	  Original commit message from CVS:
+	  * gst/goom/.cvsignore:
+	  * gst/goom2k1/.cvsignore:
+	  Ignore files.
+
+2008-08-26 07:51:42 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/cairo/gsttextoverlay.c: Fix compiler warning.
+	  Original commit message from CVS:
+	  * ext/cairo/gsttextoverlay.c:
+	  Fix compiler warning.
+
+2008-08-26 05:42:15 +0000  David Schleef <ds@schleef.org>
+
+	  ext/cairo/gsttextoverlay.c: Fix obvious memleak.
+	  Original commit message from CVS:
+	  * ext/cairo/gsttextoverlay.c: Fix obvious memleak.
+
+2008-08-25 14:15:43 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/matroska/: Add Real[Audio|Video] support to Matroska containers.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_send_event),
+	  (gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps):
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_video_pad_setcaps),
+	  (gst_matroska_mux_audio_pad_setcaps), (gst_matroska_mux_finish):
+	  Add Real[Audio|Video] support to Matroska containers.
+	  It works fine for:
+	  * decoding real audio/video streams contained in mkv
+	  * 'transmuxing' real (.rm) files into .mkv files
+	  It will not work though for encoding real[audio/video] streams that
+	  don't contain the 'mdpr_data' extra data on the caps.
+	  The reason why this will not work is because I never intended to
+	  duplicate virtually all the 'mdpr' block creation into mkvmux.
+	  Fixes #536067
+
+2008-08-25 09:48:06 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/law/: The encoder can't really renegotiate at the time they perform a pad-alloc so make the srcpads use fixed caps.
+	  Original commit message from CVS:
+	  * gst/law/alaw-encode.c: (gst_alaw_enc_init), (gst_alaw_enc_chain):
+	  * gst/law/mulaw-conversion.c:
+	  * gst/law/mulaw-encode.c: (gst_mulawenc_init),
+	  (gst_mulawenc_chain):
+	  The encoder can't really renegotiate at the time they perform a
+	  pad-alloc so make the srcpads use fixed caps.
+	  Check the buffer size after a pad-alloc because the returned size might
+	  not be right when the downstream element does not know the size of the
+	  new buffer (capsfilter). Fixes #549073.
+
+2008-08-23 15:43:49 +0000  Filippo Argiolas <filippo.argiolas@gmail.com>
+
+	  sys/v4l2/gstv4l2tuner.c: v4l2src doesn't have a property named "norm" so don't try to notify about changes to that pr...
+	  Original commit message from CVS:
+	  Patch by: Filippo Argiolas <filippo dot argiolas at gmail dot com>
+	  * sys/v4l2/gstv4l2tuner.c: (gst_v4l2_tuner_set_norm_and_notify):
+	  v4l2src doesn't have a property named "norm" so don't try to notify
+	  about changes to that property. The "norm" property and related
+	  code are commented out currently. Fixes bug #549090.
+
+2008-08-23 15:33:49 +0000  Mike Ruprecht <cmaiku@gmail.com>
+
+	  sys/v4l2/gstv4l2object.c: Reprobe devices again instead of taking a cached list as new devices could've been plugged ...
+	  Original commit message from CVS:
+	  Patch by: Mike Ruprecht <cmaiku at gmail dot com>
+	  * sys/v4l2/gstv4l2object.c: (gst_v4l2_class_probe_devices):
+	  Reprobe devices again instead of taking a cached list as new
+	  devices could've been plugged in. Fixes bug #549062.
+
+2008-08-22 16:04:02 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/autodetect/Makefile.am: Don't link the autodetect plugin with GConf as it doesn't use GConf. Fixes bug #545463.
+	  Original commit message from CVS:
+	  * gst/autodetect/Makefile.am:
+	  Don't link the autodetect plugin with GConf as it doesn't
+	  use GConf. Fixes bug #545463.
+
+2008-08-22 12:24:23 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/ebml-read.c: Change some GST_ELEMENT_ERRORs to GST_ERROR_OBJECT to make it possible to ignore errors and...
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-read.c: (gst_ebml_read_element_id),
+	  (gst_ebml_read_element_length), (gst_ebml_read_uint),
+	  (gst_ebml_read_sint), (gst_ebml_read_float),
+	  (gst_ebml_read_header):
+	  Change some GST_ELEMENT_ERRORs to GST_ERROR_OBJECT to make it
+	  possible to ignore errors and not post any ERROR messages on
+	  the bus.
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_parse_contents):
+	  Ignore any errors and not just EOS when parsing the contents of
+	  a SeekHead. Errors here are usually caused by truncated files
+	  and playback of the file works fine. Fixes playback of the
+	  audio_only_chapter_seekbroken.mka file from the MPlayer samples
+	  archive.
+
+2008-08-22 11:29:26 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  gst/multipart/: Conform to RFC2046. audio/basic is mulaw 8000Hz mono.
+	  Original commit message from CVS:
+	  * gst/multipart/multipartdemux.c:
+	  * gst/multipart/multipartmux.c:
+	  Conform to RFC2046. audio/basic is mulaw 8000Hz mono.
+
+2008-08-21 21:56:19 +0000  Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+
+	* ChangeLog:
+	* sys/directdraw/gstdirectdrawsink.c:
+	  sys/directdraw/gstdirectdrawsink.c (gst_directdraw_sink_buffer_alloc, gst_directdraw_sink_bufferpool_clear):
+	  Original commit message from CVS:
+	  * sys/directdraw/gstdirectdrawsink.c (gst_directdraw_sink_buffer_alloc,
+	  gst_directdraw_sink_bufferpool_clear):
+	  Fix two more buffer ref leaks.
+
+2008-08-21 15:28:09 +0000  Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+
+	  sys/directdraw/gstdirectdrawsink.c: Fix buffer ref leak.
+	  Original commit message from CVS:
+	  Patch by: Ole André Vadla Ravnås  <ole.andre.ravnas at tandberg com>
+	  * sys/directdraw/gstdirectdrawsink.c:
+	  (gst_directdraw_sink_show_frame):
+	  Fix buffer ref leak.
+
+2008-08-21 13:27:12 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/wavenc/gstwavenc.c: Revert the last commit. wavenc still supports width!=depth for 32 bit width. Thanks Tim.
+	  Original commit message from CVS:
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_chain):
+	  Revert the last commit. wavenc still supports width!=depth for 32 bit
+	  width. Thanks Tim.
+
+2008-08-21 13:22:06 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.c: If the duration of a block is unknown only use the timestamp for the first lace and us...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock):
+	  If the duration of a block is unknown only use the timestamp for the
+	  first lace and use GST_CLOCK_TIME_NONE as duration for the following
+	  laces. Otherwise every lace has the same timestamp which leads to
+	  various problems. Really fixes bug #548831.
+
+2008-08-21 12:56:01 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/wavenc/gstwavenc.c: If we're not allowing width!=depth in wavenc we should also disable the code that was added t...
+	  Original commit message from CVS:
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_chain):
+	  If we're not allowing width!=depth in wavenc we should also disable
+	  the code that was added to support width!=depth.
+
+2008-08-21 12:52:47 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.c: Don't calculate the default duration of a frame from the audio sampling rate. This onl...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream):
+	  Don't calculate the default duration of a frame from the audio sampling
+	  rate. This only works for raw audio if every frame contains a single
+	  sample and results in broken buffer durations for other formats
+	  if no specified default duration is given or the blocks have no
+	  duration. Fixes bug #548831.
+
+2008-08-21 12:34:33 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.c: Allow zero sized blocks instead of returning GST_FLOW_OK. Such blocks are used for tex...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock):
+	  Allow zero sized blocks instead of returning GST_FLOW_OK. Such blocks
+	  are used for text/plain subtitles as a gap-filler in some files.
+
+2008-08-21 12:12:00 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/v4l2/gstv4l2src.c: Add S910 and PWC formats with a low priority.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_v4l2fourcc_to_structure),
+	  (gst_v4l2_get_caps_info):
+	  Add S910 and PWC formats with a low priority.
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_format_get_rank),
+	  (gst_v4l2src_probe_caps_for_format):
+	  Add more debugging.
+
+2008-08-20 21:54:35 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacenc.c: Fix compilation against older libflac versions.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacenc.c:
+	  Fix compilation against older libflac versions.
+
+2008-08-20 17:46:48 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/pulse/: Use GST_BOILERPLATE everywhere and fix coding style at some places.
+	  Original commit message from CVS:
+	  * ext/pulse/pulsemixer.c: (gst_pulsemixer_class_init),
+	  (gst_pulsemixer_set_property), (gst_pulsemixer_get_property):
+	  * ext/pulse/pulsemixerctrl.c: (gst_pulsemixer_ctrl_subscribe_cb),
+	  (gst_pulsemixer_ctrl_open), (gst_pulsemixer_ctrl_timeout_event),
+	  (gst_pulsemixer_ctrl_set_volume):
+	  * ext/pulse/pulsemixertrack.c: (gst_pulsemixer_track_new):
+	  * ext/pulse/pulseprobe.c: (gst_pulseprobe_open):
+	  * ext/pulse/pulsesink.c: (gst_pulsesink_class_init),
+	  (gst_pulsesink_init), (gst_pulsesink_open),
+	  (gst_pulsesink_prepare), (gst_pulsesink_write),
+	  (gst_pulsesink_delay), (gst_pulsesink_reset):
+	  * ext/pulse/pulsesrc.c: (gst_pulsesrc_class_init),
+	  (gst_pulsesrc_init):
+	  Use GST_BOILERPLATE everywhere and fix coding style at some places.
+	  Fix a locking issue in pulsesink's prepare function.
+	  * ext/pulse/pulseutil.c: (gst_pulse_channel_map_to_gst):
+	  Check if the created channel layout is valid for GStreamer.
+
+2008-08-20 17:42:21 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspgoogle.c: Things that can happen when your brain is in google mode trying to deal with their google r...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspgoogle.c:
+	  Things that can happen when your brain is in google mode trying to
+	  deal with their google rtsp server extensions and trying to type your
+	  google mail account.
+
+2008-08-20 17:30:19 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/: Add google RTSP extension, it can only handle udp and responds with unsupported if we do anything else. Fi...
+	  Original commit message from CVS:
+	  * gst/rtsp/Makefile.am:
+	  * gst/rtsp/gstrtsp.c: (plugin_init):
+	  * gst/rtsp/gstrtspgoogle.c: (gst_rtsp_google_before_send),
+	  (gst_rtsp_google_after_send), (gst_rtsp_google_get_transports),
+	  (_do_init), (gst_rtsp_google_base_init),
+	  (gst_rtsp_google_class_init), (gst_rtsp_google_init),
+	  (gst_rtsp_google_finalize), (gst_rtsp_google_change_state),
+	  (gst_rtsp_google_extension_init):
+	  * gst/rtsp/gstrtspgoogle.h:
+	  Add google RTSP extension, it can only handle udp and responds with
+	  unsupported if we do anything else. Fixes #546465.
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_connection_send),
+	  (gst_rtspsrc_connection_receive), (gst_rtspsrc_loop_send_cmd),
+	  (gst_rtspsrc_create_transports_string),
+	  (gst_rtspsrc_setup_streams), (gst_rtspsrc_open),
+	  (gst_rtspsrc_close), (gst_rtspsrc_pause):
+	  Make transport setup code a bit better using GString.
+	  Add some more debug.
+	  Check for closed connections before doing anything on them.
+
+2008-08-20 17:17:55 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/pulse/: If downstream provides no channel layout and >2 channels should be used use the default layout that pulse...
+	  Original commit message from CVS:
+	  * ext/pulse/pulsesrc.c: (gst_pulsesrc_class_init),
+	  (gst_pulsesrc_create_stream), (gst_pulsesrc_negotiate),
+	  (gst_pulsesrc_prepare):
+	  * ext/pulse/pulseutil.c: (gst_pulse_gst_to_channel_map),
+	  (gst_pulse_channel_map_to_gst):
+	  * ext/pulse/pulseutil.h:
+	  If downstream provides no channel layout and >2 channels should be
+	  used use the default layout that pulseaudio chooses and also
+	  add this layout to the caps. Fixes bug #547258.
+
+2008-08-20 11:51:38 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/udp/: Avoid leaking internally allocated file descriptors when setting custom file descriptors. Fixes #543101.
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt <pkj at axis com>
+	  * gst/udp/gstdynudpsink.c: (gst_dynudpsink_init),
+	  (gst_dynudpsink_finalize), (gst_dynudpsink_set_property),
+	  (gst_dynudpsink_init_send), (gst_dynudpsink_close):
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_init),
+	  (gst_multiudpsink_finalize), (gst_multiudpsink_set_property):
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_finalize),
+	  (gst_udpsrc_set_property):
+	  Avoid leaking internally allocated file descriptors when setting
+	  custom file descriptors. Fixes #543101.
+
+2008-08-20 11:48:46 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Don't try to configure RTCP back to the server when the server did not give us a valid port nu...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_stream_configure_udp_sink):
+	  Don't try to configure RTCP back to the server when the server did not
+	  give us a valid port number.
+
+2008-08-20 10:59:52 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/videobox/gstvideobox.c: Use new basetransform method to renegotiate. Fixes #544956.
+	  Original commit message from CVS:
+	  * gst/videobox/gstvideobox.c: (gst_video_box_set_property):
+	  Use new basetransform method to renegotiate. Fixes #544956.
+	  * tests/icles/Makefile.am:
+	  * tests/icles/videobox-test.c: (make_pipeline), (main):
+	  Add videobox renegotiation example.
+
+2008-08-19 21:03:22 +0000  David Schleef <ds@schleef.org>
+
+	  gst/wavenc/gstwavenc.c: Remove depth ranges and replace with sane values.  Fixes #548530.
+	  Original commit message from CVS:
+	  * gst/wavenc/gstwavenc.c: Remove depth ranges and replace
+	  with sane values.  Fixes #548530.
+
+2008-08-18 15:05:32 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/pulse/: The bytes_per_sample and silence_sample fields of the GstRingBufferSpec are already filled with the corre...
+	  Original commit message from CVS:
+	  * ext/pulse/pulsesink.c: (gst_pulsesink_prepare):
+	  * ext/pulse/pulsesrc.c: (gst_pulsesrc_prepare):
+	  The bytes_per_sample and silence_sample fields of the GstRingBufferSpec
+	  are already filled with the correct values by
+	  gst_ring_buffer_parse_caps() so there's no need to set them again
+	  with wrong values.
+
+2008-08-16 14:54:56 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/avi/gstavidemux.c: Some AVI 2.0 (ODML) files don't respect the 'specifications' completely and instead of using t...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_read_subindexes_pull),
+	  (gst_avi_demux_read_subindexes_push):
+	  Some AVI 2.0 (ODML) files don't respect the 'specifications' completely
+	  and instead of using the 'ix##' nomenclature, use '##ix'.
+	  They're still valid though, this fixes the duration and indexes for
+	  virtually all the ODML files I have.
+
+2008-08-15 17:26:18 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtp/: Update the vorbis RTP pay/depay to RFC 5215.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtp/gstrtpvorbisdepay.c: (gst_rtp_vorbis_depay_setcaps),
+	  (gst_rtp_vorbis_depay_process):
+	  * gst/rtp/gstrtpvorbispay.c: (gst_rtp_vorbis_pay_finish_headers):
+	  Update the vorbis RTP pay/depay to RFC 5215.
+	  Fixes #547842.
+
+2008-08-14 22:07:02 +0000  David Schleef <ds@schleef.org>
+
+	  gst/qtdemux/qtdemux.c: Add 'hdv6' as a HDV format for 1080i/60 with 3:2 pulldown, i.e., 24p.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: Add 'hdv6' as a HDV format for 1080i/60
+	  with 3:2 pulldown, i.e., 24p.
+
+2008-08-14 12:47:09 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  tests/check/elements/level.c: Fix compilation some more.
+	  Original commit message from CVS:
+	  * tests/check/elements/level.c: (GST_START_TEST):
+	  Fix compilation some more.
+
+2008-08-14 11:44:59 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Require -base CVS for wavparse acid chunk parsing.
+	  Original commit message from CVS:
+	  * configure.ac::
+	  Require -base CVS for wavparse acid chunk parsing.
+
+2008-08-13 13:57:01 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/pulse/pulsesink.*: Add "device-name" property to pulsesink too and currently commented out and not working suppor...
+	  Original commit message from CVS:
+	  * ext/pulse/pulsesink.c: (gst_pulsesink_class_init),
+	  (gst_pulsesink_init), (gst_pulsesink_finalize),
+	  (gst_pulsesink_set_volume), (gst_pulsesink_get_volume),
+	  (gst_pulsesink_set_property), (gst_pulsesink_get_property),
+	  (gst_pulsesink_prepare), (gst_pulsesink_change_state):
+	  * ext/pulse/pulsesink.h:
+	  Add "device-name" property to pulsesink too and currently commented
+	  out and not working support for a "volume" property.
+
+2008-08-13 13:17:15 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  configure.ac: Remove more cdio stuff (moved to ugly)
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Remove more cdio stuff (moved to ugly)
+
+2008-08-13 12:37:26 +0000  Laszlo Pandy <laszlok2@gmail.com>
+
+	  ext/pulse/pulsesrc.c: Add "device-name" property, which provides a human readable string for the audio device, to mak...
+	  Original commit message from CVS:
+	  Patch by: Laszlo Pandy <laszlok2 at gmail dot com>
+	  * ext/pulse/pulsesrc.c: (gst_pulsesrc_class_init),
+	  (gst_pulsesrc_get_property):
+	  Add "device-name" property, which provides a human readable string
+	  for the audio device, to make it more consisten with other audio
+	  sources. Fixes bug #547519.
+
+2008-08-13 12:34:13 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/pulse/: Improve debugging a bit by including the parent object in pulsemixerctrl and pulseprobe objects and using...
+	  Original commit message from CVS:
+	  * ext/pulse/pulsemixer.c: (gst_pulsemixer_change_state):
+	  * ext/pulse/pulsemixerctrl.c: (gst_pulsemixer_ctrl_subscribe_cb),
+	  (gst_pulsemixer_ctrl_open), (gst_pulsemixer_ctrl_new),
+	  (gst_pulsemixer_ctrl_free), (gst_pulsemixer_ctrl_timeout_event):
+	  * ext/pulse/pulsemixerctrl.h:
+	  * ext/pulse/pulseprobe.c: (gst_pulseprobe_open),
+	  (gst_pulseprobe_enumerate), (gst_pulseprobe_new),
+	  (gst_pulseprobe_free), (gst_pulseprobe_needs_probe),
+	  (gst_pulseprobe_probe_property), (gst_pulseprobe_get_values):
+	  * ext/pulse/pulseprobe.h:
+	  * ext/pulse/pulsesink.c: (gst_pulsesink_init):
+	  * ext/pulse/pulsesrc.c: (gst_pulsesrc_init), (gst_pulsesrc_delay),
+	  (gst_pulsesrc_change_state):
+	  Improve debugging a bit by including the parent object in pulsemixerctrl
+	  and pulseprobe objects and using GST_WARNING_OBJECT instead of
+	  GST_WARNING.
+	  Use the parent GObject subclass instead of a random struct as GObject
+	  parameter for G_OBJECT_WARN_INVALID_PROPERTY_ID. This fixes a crash
+	  when probing for another property than "device".
+
+2008-08-13 12:21:22 +0000  Laszlo Pandy <laszlok2@gmail.com>
+
+	  ext/pulse/pulsemixer.c: Fix property probing after the device property is set by calling set_server when the server p...
+	  Original commit message from CVS:
+	  Patch by: Laszlo Pandy <laszlok2 at gmail dot com>
+	  * ext/pulse/pulsemixer.c: (gst_pulsemixer_set_property):
+	  Fix property probing after the device property is set by calling
+	  set_server when the server property changes. Fixes bug #547518.
+
+2008-08-13 12:11:34 +0000  Laszlo Pandy <laszlok2@gmail.com>
+
+	  ext/pulse/pulsemixer.c: Fix property probing after the device property is set by calling set_server when the server p...
+	  Original commit message from CVS:
+	  Patch by: Laszlo Pandy <laszlok2 at gmail dot com>
+	  * ext/pulse/pulsemixer.c: (gst_pulsemixer_set_property):
+	  Fix property probing after the device property is set by calling
+	  set_server when the server property changes. Fixes bug #547518.
+
+2008-08-13 12:01:01 +0000  Laszlo Pandy <laszlok2@gmail.com>
+
+	  ext/pulse/: Implement GstPropertyProbe interface on pulsesink for detecting sink devices and on pulsesrc for detectin...
+	  Original commit message from CVS:
+	  Patch by: Laszlo Pandy <laszlok2 at gmail dot com>
+	  * ext/pulse/pulsesink.c: (gst_pulsesink_interface_supported),
+	  (gst_pulsesink_implements_interface_init),
+	  (gst_pulsesink_init_interfaces), (gst_pulsesink_init),
+	  (gst_pulsesink_finalize), (gst_pulsesink_set_property),
+	  (gst_pulsesink_get_type):
+	  * ext/pulse/pulsesink.h:
+	  * ext/pulse/pulsesrc.c: (gst_pulsesrc_interface_supported),
+	  (gst_pulsesrc_init_interfaces), (gst_pulsesrc_init),
+	  (gst_pulsesrc_finalize), (gst_pulsesrc_set_property):
+	  * ext/pulse/pulsesrc.h:
+	  Implement GstPropertyProbe interface on pulsesink for detecting
+	  sink devices and on pulsesrc for detecting source devices.
+	  Fixes bugs #547227 and #547217.
+
+2008-08-13 09:17:20 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/gstspectrum.c: Don't terminate on fabs(in)>1.0. Init doubles as doubles.
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c:
+	  Don't terminate on fabs(in)>1.0. Init doubles as doubles.
+
+2008-08-13 08:33:57 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  sys/v4l2/gstv4l2src.c: Properly set the maximum latency value, in the same way it is done in v4lsrc.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_query):
+	  Properly set the maximum latency value, in the same way it is done in
+	  v4lsrc.
+	  * sys/v4l2/v4l2src_calls.c:
+	  Simplify fraction equality check, no need to use GValues for this.
+
+2008-08-12 12:04:24 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  sys/v4l2/gstv4l2src.c: Add warning messages stating exactly why the latency query failed.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_query):
+	  Add warning messages stating exactly why the latency query failed.
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_set_capture):
+	  In some cases, the negotiated framerate might be the default one which
+	  is already set internally. But we still need to mark it down in fps_n
+	  and fps_d so that the latency query can happen properly.
+
+2008-08-12 11:28:47 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  docs/plugins/inspect/plugin-1394.xml: Whoops, forgot one doc file for people who can't/don't build the raw1394 plugin.
+	  Original commit message from CVS:
+	  * docs/plugins/inspect/plugin-1394.xml:
+	  Whoops, forgot one doc file for people who can't/don't build the
+	  raw1394 plugin.
+
+2008-08-12 09:22:29 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Pull changes from 0.10.9.2 pre-release branch moving the libcdio
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/inspect/plugin-cdio.xml:
+	  * ext/Makefile.am:
+	  * ext/cdio/Makefile.am:
+	  * ext/cdio/gstcdio.c:
+	  * ext/cdio/gstcdio.h:
+	  * ext/cdio/gstcdiocddasrc.c:
+	  * ext/cdio/gstcdiocddasrc.h:
+	  Pull changes from 0.10.9.2 pre-release branch moving the libcdio
+	  CDDA source to -ugly.
+	  * po/LINGUAS:
+	  * po/POTFILES.in:
+	  * po/id.po:
+	  Pull in new translation from 0.10.9.2 release branch.
+
+2008-08-11 15:05:13 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  docs/plugins/: Integrate documentation for new hdv1394src element.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-good-plugins.interfaces:
+	  Integrate documentation for new hdv1394src element.
+
+2008-08-11 14:36:13 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/raw1394/: mpeg2-ts (HDV) variant of firewire capture element.
+	  Original commit message from CVS:
+	  * ext/raw1394/Makefile.am:
+	  * ext/raw1394/gst1394.c: (plugin_init):
+	  * ext/raw1394/gsthdv1394src.c: (_do_init),
+	  (gst_hdv1394src_base_init), (gst_hdv1394src_class_init),
+	  (gst_hdv1394src_init), (gst_hdv1394src_dispose),
+	  (gst_hdv1394src_set_property), (gst_hdv1394src_get_property),
+	  (gst_hdv1394src_from_raw1394handle),
+	  (gst_hdv1394src_iec61883_receive), (gst_hdv1394src_bus_reset),
+	  (gst_hdv1394src_create), (gst_hdv1394src_discover_avc_node),
+	  (gst_hdv1394src_start), (gst_hdv1394src_stop),
+	  (gst_hdv1394src_unlock), (gst_hdv1394src_update_device_name),
+	  (gst_hdv1394src_uri_get_type), (gst_hdv1394src_uri_get_protocols),
+	  (gst_hdv1394src_uri_get_uri), (gst_hdv1394src_uri_set_uri),
+	  (gst_hdv1394src_uri_handler_init):
+	  * ext/raw1394/gsthdv1394src.h:
+	  mpeg2-ts (HDV) variant of firewire capture element.
+	  Fixes #350830
+
+2008-08-11 10:53:06 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/level/gstlevel.c: Fix compilation (also known as the classic 'fix code that someone committed without compiling i...
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c: (gst_level_message_new):
+	  Fix compilation (also known as the classic 'fix code that someone
+	  committed without compiling it first').
+
+2008-08-10 19:40:27 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/check/elements/level.c: Add a test for level in stereo mode.
+	  Original commit message from CVS:
+	  * tests/check/elements/level.c:
+	  Add a test for level in stereo mode.
+
+2008-08-10 19:35:05 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/examples/spectrum/: Demo how to draw analyzer results synced to the clock.
+	  Original commit message from CVS:
+	  * tests/examples/spectrum/demo-audiotest.c:
+	  * tests/examples/spectrum/demo-osssrc.c:
+	  Demo how to draw analyzer results synced to the clock.
+
+2008-08-10 15:52:42 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/level/gstlevel.c: Little renaming (l -> level).
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c:
+	  Little renaming (l -> level).
+	  * gst/spectrum/gstspectrum.c:
+	  * gst/spectrum/gstspectrum.h:
+	  Also send full timestamp/duration details here.
+
+2008-08-10 11:32:03 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/level/gstlevel.*: Send same timestamp/duration details as videoanalysis. This gives applications better chance to...
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c:
+	  * gst/level/gstlevel.h:
+	  Send same timestamp/duration details as videoanalysis. This gives
+	  applications better chance to sync analysis results with playback.
+
+2008-08-09 14:02:27 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-mux.c: We need to drop one additional buffer for FLAC as the fLaC marker and STREAMINFO block a...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_handle_sink_event),
+	  (flac_streamheader_to_codecdata):
+	  We need to drop one additional buffer for FLAC as the fLaC
+	  marker and STREAMINFO block are merged into one buffer in the caps.
+	  Also don't pretend to support NEWSEGMENT events, otherwise we
+	  will most probably write some invalid data.
+
+2008-08-09 13:48:22 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-mux.c: Add support for muxing FLAC into Matroska containers.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c: (flac_streamheader_to_codecdata),
+	  (gst_matroska_mux_audio_pad_setcaps):
+	  Add support for muxing FLAC into Matroska containers.
+	  Fixes bug #311586.
+
+2008-08-09 08:58:26 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/flac/gstflacenc.c: Actually provide the variables required for the format string.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacenc.c: (gst_flac_enc_check_discont):
+	  Actually provide the variables required for the format string.
+
+2008-08-08 16:20:26 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.*: Close the current segment if we're doing a non-flushing seek and send the close-segmen...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_reset),
+	  (gst_matroska_demux_element_send_event),
+	  (gst_matroska_demux_handle_seek_event), (gst_matroska_demux_loop):
+	  * gst/matroska/matroska-demux.h:
+	  Close the current segment if we're doing a non-flushing seek and send
+	  the close-segment and the new segment of the seek from the streaming
+	  thread.
+
+2008-08-08 15:20:24 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/flac/gstflacenc.*: Handle non-zero start timestamps correctly, mark header packets as
+	  Original commit message from CVS:
+	  * ext/flac/gstflacenc.c: (gst_flac_enc_write_callback),
+	  (gst_flac_enc_check_discont), (gst_flac_enc_chain),
+	  (gst_flac_enc_change_state):
+	  * ext/flac/gstflacenc.h:
+	  Handle non-zero start timestamps correctly, mark header packets as
+	  IN_CAPS and print a warning and suggest using audiorate if stream
+	  discontinuities are detected. When FLAC supports flushing the encoder
+	  somehow this should be done for discontinuities instead.
+	  Remove some unused variables from the instance struct.
+
+2008-08-07 17:14:39 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  add pulseaudio to plugins list in spec file
+	  Original commit message from CVS:
+	  add pulseaudio to plugins list in spec file
+
+2008-08-07 16:13:41 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/flac/gstflacenc.c: If seeking failed return the appropiate return value to FLAC.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacenc.c: (gst_flac_enc_seek_callback):
+	  If seeking failed return the appropiate return value to FLAC.
+	  Otherwise it thinks seeking was successfull and tries to rewrite
+	  parts of the headers which then get appended to the output.
+
+2008-08-07 16:11:00 +0000  Frederic Crozat <fcrozat@mandriva.org>
+
+	  Make sure gettext returns translations in UTF-8 encoding rather than in the current locale encoding (#546822).
+	  Original commit message from CVS:
+	  Patch by: Frederic Crozat <fcrozat@mandriva.org>
+	  * ext/esd/gstesd.c: (plugin_init):
+	  * ext/flac/gstflac.c: (plugin_init):
+	  * ext/shout2/gstshout2.c: (plugin_init):
+	  * ext/wavpack/gstwavpack.c: (plugin_init):
+	  * sys/oss/gstossaudio.c: (plugin_init):
+	  * sys/v4l2/gstv4l2.c: (plugin_init):
+	  Make sure gettext returns translations in UTF-8 encoding rather
+	  than in the current locale encoding (#546822).
+
+2008-08-07 14:40:13 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/flac/gstflacdec.c: Add FIXME for 0.11 to simply output everything with width=32 as given by FLAC and let audiocon...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c:
+	  Add FIXME for 0.11 to simply output everything with width=32 as given
+	  by FLAC and let audioconvert handle the conversions instead of doing
+	  them in flacdec.
+
+2008-08-07 10:22:32 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  sys/v4l2/v4l2src_calls.c: When outputting a pad template range for the size, include a framerate range too, to avoid ...
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_probe_caps_for_format):
+	  When outputting a pad template range for the size, include a framerate
+	  range too, to avoid 'not a real subset of template caps' errors.
+
+2008-08-06 15:34:55 +0000  Jonathan Matthew <notverysmart@gmail.com>
+
+	  ext/flac/: Port flactag to 0.10, add documentation for it and clean it up a bit.
+	  Original commit message from CVS:
+	  Based on a patch by: Jonathan Matthew <notverysmart at gmail dot com>
+	  * ext/flac/Makefile.am:
+	  * ext/flac/gstflac.c: (plugin_init):
+	  * ext/flac/gstflactag.c: (gst_flac_tag_setup_interfaces),
+	  (gst_flac_tag_base_init), (gst_flac_tag_class_init),
+	  (gst_flac_tag_dispose), (gst_flac_tag_init),
+	  (gst_flac_tag_sink_setcaps), (gst_flac_tag_chain),
+	  (gst_flac_tag_change_state):
+	  * ext/flac/gstflactag.h:
+	  Port flactag to 0.10, add documentation for it and clean it up a bit.
+	  Fixes bug #413841.
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-good-plugins.interfaces:
+	  * docs/plugins/gst-plugins-good-plugins.prerequisites:
+	  * docs/plugins/inspect/plugin-flac.xml:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_base_init):
+	  * ext/flac/gstflacdec.h:
+	  * ext/flac/gstflacenc.c: (gst_flac_enc_base_init):
+	  * ext/flac/gstflacenc.h:
+	  Add flactag and flacenc to the documentation and mark
+	  the private parts of the flacdec instance structure as private.
+	  Also use gst_element_class_set_details_simple() in flacdec and
+	  flacenc.
+
+2008-08-06 13:12:07 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/qtdemux/qtdemux.c: Use audio/x-qdm for caps. Collect some info - mplayer has a decoder for it but ffmpeg does not.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c:
+	  Use audio/x-qdm for caps. Collect some info - mplayer has a decoder
+	  for it but ffmpeg does not.
+
+2008-08-05 15:05:44 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/wavparse/gstwavparse.c: Handle the list chunk and use gst_riff_parse_info() to parse the info sub-chunk.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c:
+	  Handle the list chunk and use gst_riff_parse_info() to parse the info
+	  sub-chunk.
+
+2008-08-05 14:22:12 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/wavparse/gstwavparse.c: Handle the acid chunk and send tempo as part of tags. Other fields are interesting too, b...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c:
+	  Handle the acid chunk and send tempo as part of tags. Other fields are
+	  interesting too, but need more tag-definitions. Fixes #545433.
+
+2008-08-05 14:16:32 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/wavparse/gstwavparse.c: Refactor wavparse. Call _reset() from dispose() and move old code from dispose into reset...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c:
+	  Refactor wavparse. Call _reset() from dispose() and move old code from
+	  dispose into reset. This way we don't leak taglists when we abort
+	  parsing. Fix some comments. Move code for skipping a chunk into extra
+	  function. Replace chunk sizes with a const to ease readability.
+
+2008-08-05 13:57:57 +0000  Aurelien Grimaud <gstelzz@yahoo.fr>
+
+	  gst/rtsp/gstrtspsrc.c: Improve udp port setup. Fixes #545710.
+	  Original commit message from CVS:
+	  Patch by: Aurelien Grimaud <gstelzz at yahoo dot fr>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_alloc_udp_ports):
+	  Improve udp port setup. Fixes #545710.
+
+2008-08-05 13:54:18 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Add MP1S depayloader.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpmp1sdepay.c: (gst_rtp_mp1s_depay_base_init),
+	  (gst_rtp_mp1s_depay_class_init), (gst_rtp_mp1s_depay_init),
+	  (gst_rtp_mp1s_depay_setcaps), (gst_rtp_mp1s_depay_process),
+	  (gst_rtp_mp1s_depay_set_property),
+	  (gst_rtp_mp1s_depay_get_property),
+	  (gst_rtp_mp1s_depay_change_state),
+	  (gst_rtp_mp1s_depay_plugin_init):
+	  * gst/rtp/gstrtpmp1sdepay.h:
+	  Add MP1S depayloader.
+	  * gst/rtsp/URLS:
+	  Some more sample rtsp streams.
+
+2008-08-05 08:43:45 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/URLS: Add another URL.
+	  Original commit message from CVS:
+	  * gst/rtsp/URLS:
+	  Add another URL.
+	  * tests/check/elements/id3v2mux.c: (test_taglib_id3mux_with_tags):
+	  * tests/check/elements/rglimiter.c: (GST_START_TEST):
+	  Add some more debug info.
+
+2008-08-04 09:16:40 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/avi/gstavimux.c: Provide cbSize field for audio extra_data size, and take care to pad extra_data.
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c: (gst_avi_mux_riff_get_avi_header):
+	  Provide cbSize field for audio extra_data size, and take care to
+	  pad extra_data.
+
+2008-08-04 07:23:07 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/qtdemux/qtdemux.c: Return the result of gst_pad_{start,stop}_task instead of hard-coded
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c:
+	  Return the result of gst_pad_{start,stop}_task instead of hard-coded
+	  TRUE.
+
+2008-08-04 07:17:38 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/qtdemux/: Add keyword tag support. Fixes #520694 for qtdemux.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c:
+	  * gst/qtdemux/qtdemux_fourcc.h:
+	  Add keyword tag support. Fixes #520694 for qtdemux.
+
+2008-08-04 07:05:33 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/qtdemux/qtdemux.c: Add support for tmpo tag (BPM).
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c:
+	  Add support for tmpo tag (BPM).
+
+2008-08-03 12:23:49 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/flac/gstflacenc.c: Set an estimate for the total number of samples that will be encoded if possible to help decod...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacenc.c: (gst_flac_enc_query_peer_total_samples),
+	  (gst_flac_enc_sink_setcaps), (gst_flac_enc_write_callback):
+	  Set an estimate for the total number of samples that will be encoded
+	  if possible to help decoders if the streaminfo can't be rewritten
+	  later (like when muxing into Ogg containers).
+	  Add a warning if we get header packets after data packets as those
+	  will get lost when muxing into Ogg, i.e. rewriting the headers doesn't
+	  work.
+
+2008-08-03 11:38:22 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/flac/gstflacdec.c: Support decoding of all depths between 4 and 32 bits and read the depth from the streaminfo he...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_metadata_callback),
+	  (gst_flac_dec_write):
+	  Support decoding of all depths between 4 and 32 bits and read the
+	  depth from the streaminfo header if needed. Also support all sampling
+	  rates between 1 and 655350 Hz.
+	  * ext/flac/gstflacenc.c:
+	  (gst_flac_enc_caps_append_structure_with_widths),
+	  (gst_flac_enc_sink_getcaps), (gst_flac_enc_sink_setcaps),
+	  (gst_flac_enc_chain):
+	  * ext/flac/gstflacenc.h:
+	  Support encoding in all bit depths supported by the streamable
+	  subformat (i.e. 8, 12, 16, 20 and 24 bits) and all sampling rates
+	  between 1 Hz and 655350 Hz.
+
+2008-08-03 09:23:14 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/flac/gstflacenc.c: Support encoding of up to 8 channels.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacenc.c: (gst_flac_enc_init),
+	  (gst_flac_enc_sink_getcaps):
+	  Support encoding of up to 8 channels.
+
+2008-08-02 21:39:01 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  ext/soup/gstsouphttpsrc.*: Fix seeking race condition in #540300
+	  Original commit message from CVS:
+	  * ext/soup/gstsouphttpsrc.c:
+	  * ext/soup/gstsouphttpsrc.h:
+	  Fix seeking race condition in #540300
+	  Patch By: Wouter Cloetens  <wouter at mind be>
+
+2008-08-02 18:35:21 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.c: When receiving a SEEK event on a specific pad first search for a seek table entry for ...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroskademux_do_index_seek),
+	  (gst_matroska_demux_element_send_event),
+	  (gst_matroska_demux_handle_seek_event),
+	  (gst_matroska_demux_handle_src_event):
+	  When receiving a SEEK event on a specific pad first search for a seek
+	  table entry for the stream of the pad and then fall back to an entry
+	  for a different stream.
+
+2008-08-02 18:20:44 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Build depend on core CVS for the attachment tag.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/matroska/matroska-ids.c: (gst_matroska_register_tags):
+	  * gst/matroska/matroska-ids.h:
+	  Build depend on core CVS for the attachment tag.
+
+2008-08-02 18:18:05 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Decode the codec private data and following ContentEncoding if necessary.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/matroska/Makefile.am:
+	  * gst/matroska/lzo.c: (get_byte), (get_len), (copy),
+	  (copy_backptr), (lzo1x_decode), (main):
+	  * gst/matroska/lzo.h:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_read_track_encoding),
+	  (gst_matroska_decompress_data), (gst_matroska_decode_data),
+	  (gst_matroska_decode_buffer),
+	  (gst_matroska_decode_content_encodings),
+	  (gst_matroska_demux_read_track_encodings),
+	  (gst_matroska_demux_add_stream),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock):
+	  * gst/matroska/matroska-ids.h:
+	  Decode the codec private data and following ContentEncoding if
+	  necessary.
+	  Support bzip2, lzo and header stripped compression. For lzo use the
+	  ffmpeg lzo implementation as liblzo is GPL licensed.
+	  Fix zlib decompression.
+
+2008-08-02 18:11:32 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-mux.c: Fix muxing of MP3/MP2 with different MPEG versions by calculating the duration of a fram...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_audio_pad_setcaps):
+	  Fix muxing of MP3/MP2 with different MPEG versions by calculating the
+	  duration of a frame with the new mpegaudioversion caps field.
+
+2008-08-02 18:06:20 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.*: Allow an infinite number of stream inside Matroska containers and use a GPtrArray for ...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_finalize),
+	  (gst_matroska_demux_class_init), (gst_matroska_demux_init),
+	  (gst_matroska_demux_combine_flows), (gst_matroska_demux_reset),
+	  (gst_matroska_demux_stream_from_num),
+	  (gst_matroska_demux_tracknumber_unique),
+	  (gst_matroska_demux_add_stream), (gst_matroska_demux_send_event),
+	  (gst_matroska_demux_handle_seek_event),
+	  (gst_matroska_demux_sync_streams),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+	  (gst_matroska_demux_loop):
+	  * gst/matroska/matroska-demux.h:
+	  Allow an infinite number of stream inside Matroska containers and use
+	  a GPtrArray for storing them instead of allowing "only" 127 streams.
+
+2008-08-02 18:01:36 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/: Fix indention everywhere. A broken indent version has added newlines after every single declaration so...
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-read.c: (gst_ebml_read_class_init),
+	  (gst_ebml_read_change_state), (gst_ebml_read_element_level_up),
+	  (gst_ebml_read_peek_bytes), (gst_ebml_read_element_id),
+	  (gst_ebml_read_element_length), (gst_ebml_peek_id),
+	  (gst_ebml_read_get_length), (gst_ebml_read_skip),
+	  (gst_ebml_read_buffer), (gst_ebml_read_bytes),
+	  (gst_ebml_read_uint), (gst_ebml_read_sint), (_ext2dbl),
+	  (gst_ebml_read_float), (gst_ebml_read_ascii), (gst_ebml_read_date),
+	  (gst_ebml_read_master), (gst_ebml_read_binary),
+	  (gst_ebml_read_header):
+	  * gst/matroska/ebml-write.c: (gst_ebml_write_element_id),
+	  (gst_ebml_write_element_size), (gst_ebml_write_uint),
+	  (gst_ebml_write_sint), (gst_ebml_write_ascii),
+	  (gst_ebml_write_master_start), (gst_ebml_write_master_finish),
+	  (gst_ebml_replace_uint):
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_reset),
+	  (gst_matroska_demux_read_track_encoding),
+	  (gst_matroska_demux_read_track_encodings),
+	  (gst_matroska_demux_add_stream), (gst_matroskademux_do_index_seek),
+	  (gst_matroska_demux_send_event),
+	  (gst_matroska_demux_element_send_event),
+	  (gst_matroska_demux_handle_seek_event),
+	  (gst_matroska_demux_handle_src_event),
+	  (gst_matroska_demux_init_stream),
+	  (gst_matroska_demux_parse_tracks),
+	  (gst_matroska_demux_parse_index_cuetrack),
+	  (gst_matroska_demux_parse_index_pointentry),
+	  (gst_matroska_demux_parse_index), (gst_matroska_demux_parse_info),
+	  (gst_matroska_demux_parse_metadata_id_simple_tag),
+	  (gst_matroska_demux_parse_metadata_id_tag),
+	  (gst_matroska_demux_parse_metadata),
+	  (gst_matroska_demux_parse_attached_file),
+	  (gst_matroska_demux_parse_attachments),
+	  (gst_matroska_demux_parse_chapters), (gst_matroska_ebmlnum_uint),
+	  (gst_matroska_ebmlnum_sint), (gst_matroska_demux_push_hdr_buf),
+	  (gst_matroska_demux_push_flac_codec_priv_data),
+	  (gst_matroska_demux_push_xiph_codec_priv_data),
+	  (gst_matroska_demux_push_dvd_clut_change_event),
+	  (gst_matroska_demux_add_mpeg_seq_header),
+	  (gst_matroska_demux_add_wvpk_header),
+	  (gst_matroska_demux_check_subtitle_buffer),
+	  (gst_matroska_decode_buffer),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+	  (gst_matroska_demux_parse_cluster),
+	  (gst_matroska_demux_parse_contents_seekentry),
+	  (gst_matroska_demux_parse_contents),
+	  (gst_matroska_demux_loop_stream_parse_id),
+	  (gst_matroska_demux_loop_stream), (gst_matroska_demux_loop),
+	  (gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps),
+	  (gst_matroska_demux_subtitle_caps),
+	  (gst_matroska_demux_change_state):
+	  * gst/matroska/matroska-ids.c:
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_class_init),
+	  (gst_matroska_mux_reset), (gst_matroska_mux_handle_sink_event),
+	  (gst_matroska_mux_video_pad_setcaps),
+	  (xiph3_streamheader_to_codecdata),
+	  (vorbis_streamheader_to_codecdata),
+	  (theora_streamheader_to_codecdata),
+	  (gst_matroska_mux_audio_pad_setcaps),
+	  (gst_matroska_mux_request_new_pad), (gst_matroska_mux_release_pad),
+	  (gst_matroska_mux_track_header), (gst_matroska_mux_start),
+	  (gst_matroska_mux_write_simple_tag), (gst_matroska_mux_finish),
+	  (gst_matroska_mux_best_pad), (gst_matroska_mux_write_data),
+	  (gst_matroska_mux_collected), (gst_matroska_mux_change_state):
+	  Fix indention everywhere. A broken indent version has added newlines
+	  after every single declaration some time ago.
+
+2008-08-02 17:59:05 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.c: If no Tracks are found error out instead of trying it again until the end of time.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_loop_stream_parse_id):
+	  If no Tracks are found error out instead of trying it again until the
+	  end of time.
+
+2008-08-02 17:57:31 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.c: Fix demuxing of raw integer audio. The samples are unsigned only for 8 bit and signed ...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_audio_caps):
+	  Fix demuxing of raw integer audio. The samples are unsigned only for 8
+	  bit and signed otherwise, not the other way around.
+
+2008-08-02 17:54:04 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-mux.c: Add more raw YUV formats to the list of supported formats.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c:
+	  Add more raw YUV formats to the list of supported formats.
+
+2008-08-02 17:52:16 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-mux.c: Add support for muxing raw float audio now that the spec defines the endianness and add ...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_audio_pad_setcaps):
+	  Add support for muxing raw float audio now that the spec defines the
+	  endianness and add support for muxing raw integer audio with 24 and
+	  32 bits.
+	  Allow muxing of more than 8 audio channels.
+
+2008-08-02 17:47:32 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-mux.c: Add locking to the global array of used track UIDs to prevent random crashes if more tha...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_create_uid),
+	  (gst_matroska_mux_reset), (gst_matroska_mux_start):
+	  Add locking to the global array of used track UIDs to prevent random
+	  crashes if more than a single matrosmux instance is used.
+	  Use 64 bit values for the track UIDs.
+	  Use the global GRandom of GLib instead of creating our own one
+	  for the few random numbers we need every single time.
+
+2008-08-02 17:18:47 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/flac/gstflacdec.c: Always post the audio-codec tag, not only if other tags are present.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_setup_seekable_decoder),
+	  (gst_flac_dec_setup_stream_decoder),
+	  (gst_flac_dec_update_metadata):
+	  Always post the audio-codec tag, not only if other tags are present.
+
+2008-08-01 23:26:50 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Back to development -> 0.10.9.1
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Back to development -> 0.10.9.1
+
+2008-08-01 15:58:47 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  add missing gstreamer plugins to spec file
+	  Original commit message from CVS:
+	  add missing gstreamer plugins to spec file
+
+=== release 0.10.9 ===
+
+2008-07-31 22:10:17 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cdio.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-goom2k1.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-interleave.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-pulseaudio.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-replaygain.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* gst-plugins-good.doap:
+	* win32/common/config.h:
+	  Release 0.10.9
+	  Original commit message from CVS:
+	  Release 0.10.9
+
+2008-07-31 21:50:44 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/lt.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/pt_BR.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+	  Original commit message from CVS:
+	  Update .po files
+
+2008-07-31 21:26:48 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/soup/gstsouphttpsrc.c: Don't throw an error when soup completes a msg with status 'cancelled', as that indicates ...
+	  Original commit message from CVS:
+	  * ext/soup/gstsouphttpsrc.c:
+	  Don't throw an error when soup completes a msg with status
+	  'cancelled', as that indicates we cancelled a request while
+	  shutting down or seeking, and it's not an error.
+	  Fixes: #540300 again.
+
+2008-07-28 20:17:46 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: 0.10.8.4 pre-release
+	  Original commit message from CVS:
+	  * configure.ac:
+	  0.10.8.4 pre-release
+
+2008-07-25 14:50:03 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Fix segment-stop regression.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_activate_segment):
+	  Fix segment-stop regression.
+	  Add documentation regarding segments in quicktime files by Wim Taymans.
+	  Fixes #544509
+
+2008-07-24 23:55:58 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: 0.10.8.3 pre-release
+	  Original commit message from CVS:
+	  * configure.ac:
+	  0.10.8.3 pre-release
+	  * po/LINGUAS:
+	  * po/pt_BR.po:
+	  Add pt_BR translation
+
+2008-07-23 22:01:20 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/goom/: Fix build with MSVC: include glib.h to define inline appropriately, use header guards where needed.
+	  Original commit message from CVS:
+	  * gst/goom/convolve_fx.c:
+	  * gst/goom/filters.c:
+	  * gst/goom/goom_config.h:
+	  * gst/goom/goom_core.c:
+	  * gst/goom/goom_tools.h:
+	  Fix build with MSVC: include glib.h to define inline appropriately,
+	  use header guards where needed.
+	  * gst/udp/gstudpnetutils.c:
+	  * gst/udp/gstudpsrc.c:
+	  Fix build with MSVC: use WSA* constants/functions where appropriate, use
+	  g_snprintf rather than snprintf.
+	  Fixes #544433.
+
+2008-07-22 06:32:03 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/debug/gsttaginject.*: Sent tags in _transform_ip() instead of _start(). Fixes #543404 partially.
+	  Original commit message from CVS:
+	  * gst/debug/gsttaginject.c:
+	  * gst/debug/gsttaginject.h:
+	  Sent tags in _transform_ip() instead of _start(). Fixes #543404
+	  partially.
+
+2008-07-19 14:12:39 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: 0.10.8.2 pre-release
+	  Original commit message from CVS:
+	  * configure.ac:
+	  0.10.8.2 pre-release
+
+2008-07-19 13:50:53 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/Makefile.am: Finish hooking up pulseaudio plugin to the build.
+	  Original commit message from CVS:
+	  * ext/Makefile.am:
+	  Finish hooking up pulseaudio plugin to the build.
+	  * ext/pulse/pulsemixerctrl.c:
+	  Fix compilation error.
+
+2008-07-19 13:23:29 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  po/: Add new lithunian translation, and add french to the LINGUAS file.
+	  Original commit message from CVS:
+	  * po/LINGUAS:
+	  * po/lt.po:
+	  Add new lithunian translation, and add french to the LINGUAS
+	  file.
+
+2008-07-19 13:08:42 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  ext/soup/gstsouphttpsrc.c: Fix Soup HTTP source seeking.
+	  Original commit message from CVS:
+	  * ext/soup/gstsouphttpsrc.c:
+	  Fix Soup HTTP source seeking.
+	  Patch By: Wouter Cloetens  <wouter at mind be>
+	  Fixes: #540300
+	  * tests/check/elements/.cvsignore:
+	  Ignore new check programs.
+
+2008-07-19 01:01:13 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Move replaygain and interleave plugins from -bad.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * 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:
+	  * docs/plugins/inspect/plugin-interleave.xml:
+	  * docs/plugins/inspect/plugin-replaygain.xml:
+	  * tests/check/Makefile.am:
+	  Move replaygain and interleave plugins from -bad.
+	  Fixes: #543406
+	  Fixes: #536228
+
+2008-07-18 20:03:07 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/qtdemux/qtdemux.c: Revert ISO base media spec based pixel-aspect-ratio calculation.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_add_stream),
+	  (qtdemux_parse_trak):
+	  Revert ISO base media spec based pixel-aspect-ratio calculation.
+	  Fixes #543300.
+
+2008-07-17 16:42:53 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  sys/osxvideo/osxvideosink.m: Fix minor build issues on macosx.
+	  Original commit message from CVS:
+	  * sys/osxvideo/osxvideosink.m:
+	  Fix minor build issues on macosx.
+	  Fixes #543054
+
+2008-07-17 14:40:51 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Only use -Wno-attributes (which is there to work around a bug in the taglib 1.5 headers) if the c++ compiler actually...
+	  Original commit message from CVS:
+	  * configure.ac::
+	  * ext/taglib/Makefile.am::
+	  Only use -Wno-attributes (which is there to work around a
+	  bug in the taglib 1.5 headers) if the c++ compiler actually
+	  supports it (#543255).
+
+2008-07-17 13:54:38 +0000  Benoit Fouet <benoit.fouet@purplelabs.com>
+
+	  sys/v4l2/gstv4l2src.c: Avoid compiler warning by initialising variable to NULL (#543259).
+	  Original commit message from CVS:
+	  Patch by: Benoit Fouet <benoit.fouet purplelabs com>
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_negotiate):
+	  Avoid compiler warning by initialising variable to NULL (#543259).
+
+2008-07-14 17:17:47 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/debug/gsttaginject.c: Don't pass NULL taglists to gst_tag_list_is_empty().
+	  Original commit message from CVS:
+	  * gst/debug/gsttaginject.c: (gst_tag_inject_start):
+	  Don't pass NULL taglists to gst_tag_list_is_empty().
+
+2008-07-14 17:15:42 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/: Don't use declarations after statements.
+	  Original commit message from CVS:
+	  * tests/check/elements/cmmldec.c: (GST_START_TEST):
+	  * tests/check/elements/rtp-payloading.c: (rtp_pipeline_create),
+	  (rtp_pipeline_run):
+	  * tests/check/elements/souphttpsrc.c: (souphttpsrc_suite):
+	  Don't use declarations after statements.
+
+2008-07-14 16:28:25 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  ext/jpeg/gstjpegdec.c: Align documentation with reality.
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c:
+	  Align documentation with reality.
+
+2008-07-14 13:11:14 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/udp/gstudpnetutils.c: EAI_ADDRFAMILY was obsoleted in BSD at some point. Define it to the old value (1) if it's n...
+	  Original commit message from CVS:
+	  * gst/udp/gstudpnetutils.c:
+	  EAI_ADDRFAMILY was obsoleted in BSD at some point. Define it to the
+	  old value (1) if it's not defined which should not cause any problems
+	  as we're using it internal only anyway.
+
+2008-07-14 13:02:48 +0000  Alessandro Decina <alessandro@nnva.org>
+
+	  gst/avi/gstavidemux.c: Fix build of avidemux on big endian architectures.
+	  Original commit message from CVS:
+	  Patch by: Alessandro Decina <alessandro at nnva dot org>
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_riff_parse_vprp):
+	  Fix build of avidemux on big endian architectures.
+
+2008-07-10 20:47:56 +0000  Thiago Sousa Santos <thiagoss@lcc.ufcg.edu.br>
+
+	  gst/qtdemux/qtdemux.c: Correctly distinguish 8bit vs 16bit raw audio.  Fixes #542410.
+	  Original commit message from CVS:
+	  Patch by: Thiago Sousa Santos <thiagoss at lcc dot ufcg dot edu dot br>
+	  * gst/qtdemux/qtdemux.c: (qtdemux_audio_caps):
+	  Correctly distinguish 8bit vs 16bit raw audio.  Fixes #542410.
+
+2008-07-08 21:05:18 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/qtdemux/qtdemux.c: Set pixel-aspect-ratio in caps using display width and height provided in track.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_add_stream),
+	  (qtdemux_parse_trak):
+	  Set pixel-aspect-ratio in caps using display width and height
+	  provided in track.
+
+2008-07-08 13:59:51 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  configure.ac: Don't include ERROR_CFLAGS in GST_CXXFLAGS as it might include flags that are invalid for C++. Fixes bu...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Don't include ERROR_CFLAGS in GST_CXXFLAGS as it might include
+	  flags that are invalid for C++. Fixes bug #516509.
+
+2008-07-08 12:51:34 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Don't use declarations after statements and variable length arrays.
+	  Original commit message from CVS:
+	  * ext/raw1394/gstdv1394src.c: (gst_dv1394src_uri_set_uri):
+	  * ext/speex/gstspeexenc.c: (gst_speex_enc_sink_getcaps):
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_set_wp_config):
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_fixate):
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_probe_caps_for_format):
+	  * tests/examples/equalizer/demo.c: (message_handler):
+	  * tests/examples/spectrum/demo-audiotest.c: (message_handler):
+	  * tests/examples/spectrum/demo-osssrc.c: (message_handler):
+	  Don't use declarations after statements and variable length arrays.
+
+2008-07-07 21:28:58 +0000  Daniel Drake <dsd@gentoo.org>
+
+	  sys/v4l2/v4l2src_calls.c: Try progressive video if interlaced fails. Fixes bug #541956 and the usage of v4l2src on OLPC.
+	  Original commit message from CVS:
+	  Patch by: Daniel Drake <dsd at gentoo dot org>
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_set_capture),
+	  (gst_v4l2src_get_nearest_size):
+	  Try progressive video if interlaced fails. Fixes bug #541956
+	  and the usage of v4l2src on OLPC.
+
+2008-07-07 15:34:12 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/rtp/gstrtpspeexdepay.*: Revert last change: Only the jitterbuffer is able to convert RTP to
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpspeexdepay.c: (gst_rtp_speex_depay_init),
+	  (gst_rtp_speex_depay_process):
+	  * gst/rtp/gstrtpspeexdepay.h:
+	  Revert last change: Only the jitterbuffer is able to convert RTP to
+	  Gstreamer timestamps and normal (de)payloaders should simply copy it.
+	  Reopens bug #541787.
+
+2008-07-07 10:30:51 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/rtp/gstrtpvrawdepay.c: Include stdlib.h for atoi().
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpvrawdepay.c:
+	  Include stdlib.h for atoi().
+	  * gst/rtsp/gstrtspsrc.c:
+	  Use floating point math for latencies < 0 sec in log output.
+
+2008-07-07 10:16:07 +0000  Tomasz Grobelny <tomasz@grobelny.oswiecenia.net>
+
+	  gst/rtp/gstrtpspeexdepay.*: Take timestamp from the RTP packet as a first step to fix problems with transmission over...
+	  Original commit message from CVS:
+	  Patch by: Tomasz Grobelny <tomasz at grobelny dot oswiecenia dot net>
+	  * gst/rtp/gstrtpspeexdepay.c: (gst_rtp_speex_depay_init),
+	  (gst_rtp_speex_depay_process):
+	  * gst/rtp/gstrtpspeexdepay.h:
+	  Take timestamp from the RTP packet as a first step to fix problems
+	  with transmission over RTP when the network is not reliable.
+	  Fixes bug #541787.
+
+2008-07-05 19:01:28 +0000  Tero Saarni <tero.saarni@gmail.com>
+
+	  gst/udp/gstudpsrc.c: Fix parsing of udp:// URIs containing IPv6 addresses.
+	  Original commit message from CVS:
+	  Patch by: Tero Saarni <tero dot saarni at gmail dot com>
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_set_uri):
+	  Fix parsing of udp:// URIs containing IPv6 addresses.
+	  Fixes bug #541650.
+
+2008-07-04 20:43:07 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  ext/gdk_pixbuf/gstgdkpixbuf.c: Do not leak incoming buffers.
+	  Original commit message from CVS:
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_chain):
+	  Do not leak incoming buffers.
+
+2008-07-03 19:27:53 +0000  Damien Lespiau <damien.lespiau@gmail.com>
+
+	  configure.ac: Fix build of the RTP plugin with mingw32 by linking to ws2_32 for htons() and htonl(). Fixes bug #541412.
+	  Original commit message from CVS:
+	  Patch by: Damien Lespiau <damien dot lespiau at gmail dot com>
+	  * configure.ac:
+	  Fix build of the RTP plugin with mingw32 by linking to ws2_32
+	  for htons() and htonl(). Fixes bug #541412.
+
+2008-07-02 09:51:16 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.c: Handle position and duration query in DEFAULT format if the pad's track has a default ...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_class_init),
+	  (gst_matroska_demux_add_stream), (gst_matroska_demux_query),
+	  (gst_matroska_demux_element_query),
+	  (gst_matroska_demux_handle_src_query),
+	  (gst_matroska_demux_handle_seek_event):
+	  Handle position and duration query in DEFAULT format if the
+	  pad's track has a default frame duration set.
+	  Fix seeking now that the segment's duration doesn't contain the
+	  (possibly wrong or inaccurate) duration of the Matroska file.
+
+2008-07-02 09:04:50 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/ebml-read.c: Use NAN constant instead of 0.0/0.0 if possible. NAN is defined in math.h except on MSVC wh...
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-read.c: (_ext2dbl):
+	  Use NAN constant instead of 0.0/0.0 if possible. NAN is defined
+	  in math.h except on MSVC where it is defined in xmath.h.
+	  Fixes compilation with MSVC.
+
+2008-07-02 08:57:04 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.*: Don't set the segment duration to the duration from the Matroska header as this value ...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_reset),
+	  (gst_matroska_demux_handle_src_query),
+	  (gst_matroska_demux_parse_info),
+	  (gst_matroska_demux_loop_stream_parse_id):
+	  * gst/matroska/matroska-demux.h:
+	  Don't set the segment duration to the duration from the Matroska
+	  header as this value could be wrong and is just informational.
+
+2008-07-02 08:47:00 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.c: If no Tracks element is found until the first Cluster is found search it and error out...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_loop_stream_parse_id):
+	  If no Tracks element is found until the first Cluster is found
+	  search it and error out if none is found in the complete file.
+
+2008-07-02 08:14:35 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.c: Resync non-subtitle tracks too if a too large gap compared to other tracks is detected.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_sync_streams):
+	  Resync non-subtitle tracks too if a too large gap compared to other
+	  tracks is detected.
+
+2008-07-01 13:28:02 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Add raw video pay and depayloaders, see RFC4175.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpvrawdepay.c: (gst_rtp_vraw_depay_base_init),
+	  (gst_rtp_vraw_depay_class_init), (gst_rtp_vraw_depay_init),
+	  (gst_rtp_vraw_depay_setcaps), (gst_rtp_vraw_depay_process),
+	  (gst_rtp_vraw_depay_change_state),
+	  (gst_rtp_vraw_depay_plugin_init):
+	  * gst/rtp/gstrtpvrawdepay.h:
+	  * gst/rtp/gstrtpvrawpay.c: (gst_rtp_vraw_pay_get_type),
+	  (gst_rtp_vraw_pay_base_init), (gst_rtp_vraw_pay_class_init),
+	  (gst_rtp_vraw_pay_init), (gst_rtp_vraw_pay_finalize),
+	  (gst_rtp_vraw_pay_setcaps), (gst_rtp_vraw_pay_handle_buffer),
+	  (gst_rtp_vraw_pay_plugin_init):
+	  * gst/rtp/gstrtpvrawpay.h:
+	  Add raw video pay and depayloaders, see RFC4175.
+
+2008-06-30 22:53:39 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/libpng/gstpngdec.c: Don't return GST_FLOW_ERROR when buffer_alloc fails - return whatever it returned.
+	  Original commit message from CVS:
+	  * ext/libpng/gstpngdec.c:
+	  Don't return GST_FLOW_ERROR when buffer_alloc fails - return
+	  whatever it returned.
+
+2008-06-29 19:52:51 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/avi/avi-ids.h: Add vprp chunk related structures.
+	  Original commit message from CVS:
+	  * gst/avi/avi-ids.h:
+	  Add vprp chunk related structures.
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_riff_parse_vprp),
+	  (gst_avi_demux_parse_stream):
+	  Parse optional vprp chunk and add calculated pixel-aspect-ratio
+	  to caps.  Fixes #539482.
+	  * gst/avi/gstavimux.h:
+	  * gst/avi/gstavimux.c: (gst_avi_mux_pad_reset),
+	  (gst_avi_mux_vidsink_set_caps), (gst_avi_mux_riff_get_avi_header):
+	  Add a vprp chunk if non-trival pixel-aspect-ratio provided in caps.
+
+2008-06-28 19:31:46 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  tests/check/elements/avimux.c: Adjust avimux unit test according to increased streamheader size.
+	  Original commit message from CVS:
+	  * tests/check/elements/avimux.c: (check_avimux_pad):
+	  Adjust avimux unit test according to increased streamheader size.
+
+2008-06-27 18:11:01 +0000  David Schleef <ds@schleef.org>
+
+	  gst/qtdemux/qtdemux.c: Add Dirac stream type
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: Add Dirac stream type
+
+2008-06-27 15:25:00 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/avi/gstavimux.*: Add 8 bytes to current streamheader to make for a complete one and to make more players happy.  ...
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c: (gst_avi_mux_riff_get_avi_header):
+	  * gst/avi/gstavimux.h:
+	  Add 8 bytes to current streamheader to make for a complete one
+	  and to make more players happy.  Fixes #519460.
+
+2008-06-26 16:36:47 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/v4l2/v4l2_calls.c: Don't include unused gstv4l2xoverlay.h. Fixes build in case where X11 headers are not installed.
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2_calls.c::
+	  Don't include unused gstv4l2xoverlay.h. Fixes build
+	  in case where X11 headers are not installed.
+
+2008-06-26 10:07:46 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/dv/gstdv.c: Fix compilation.
+	  Original commit message from CVS:
+	  * ext/dv/gstdv.c: (plugin_init):
+	  Fix compilation.
+
+2008-06-26 09:37:23 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/dv/gstdv.c: Marking rank of dvdec as GST_RANK_MARGINAL since it's the slowest
+	  Original commit message from CVS:
+	  * ext/dv/gstdv.c: (plugin_init):
+	  Marking rank of dvdec as GST_RANK_MARGINAL since it's the slowest
+	  DV decoder available.
+	  Fixes #532393
+
+2008-06-25 08:12:18 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/udp/gstudpsrc.c: Call getsockname() after the call to bind() to get updated values for the port, etc. This fixes ...
+	  Original commit message from CVS:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_start):
+	  Call getsockname() after the call to bind() to get updated values
+	  for the port, etc. This fixes the usage of udpsrc on anonymous
+	  binding and it's usage by rtspsrc. Fixes bugs #539372, #539548.
+	  Thanks to Aurelien Grimaud for pointing out the obvious fix.
+
+2008-06-25 07:57:26 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/pipelines/wavpack.c: Remove workaround for a bug in identity that is fixed in 0.10.20.
+	  Original commit message from CVS:
+	  * tests/check/pipelines/wavpack.c: (bus_handler):
+	  Remove workaround for a bug in identity that is fixed in 0.10.20.
+
+2008-06-25 06:36:58 +0000  Jason Donenfeld <BugZilla@zx2c4.com>
+
+	  ext/soup/gstsouphttpsrc.c: Fix HTTP auth support with user/password passed via the URI.
+	  Original commit message from CVS:
+	  Patch by: Jason Donenfeld <BugZilla at zx2c4 dot com>
+	  * ext/soup/gstsouphttpsrc.c: (gst_soup_http_src_got_headers_cb):
+	  Fix HTTP auth support with user/password passed via the URI.
+	  Fixes bug #540067.
+
+2008-06-24 15:42:33 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Depend on released versions of core and -base.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Depend on released versions of core and -base.
+
+2008-06-23 16:13:40 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/matroska/matroska-demux.c: Fix buggy format strings in macros. (makes it build on OS X again...)
+	  Original commit message from CVS:
+	  2008-06-23  Julien Moutte  <julien@fluendo.com>
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_read_track_encoding),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock): Fix buggy
+	  format strings in macros. (makes it build on OS X again...)
+
+2008-06-20 16:24:11 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  gst/: Added debug.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtptheorapay.c:
+	  * gst/udp/gstmultiudpsink.c:
+	  Added debug.
+
+2008-06-20 15:21:59 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* ChangeLog:
+	* common:
+	* configure.ac:
+	  switch v4l2src from experimental to normal build. Fixes #536831
+	  Original commit message from CVS:
+	  switch v4l2src from experimental to normal build. Fixes #536831
+
+2008-06-19 11:24:54 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpg726pay.c: Remove unused variable so that we can compile again.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpg726pay.c: (gst_rtp_g726_pay_setcaps):
+	  Remove unused variable so that we can compile again.
+
+2008-06-19 11:06:29 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtp/gstrtpg726pay.c: No need to check for audio/G723 and audio/32KADPCM here as they are no longer supported.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpg726pay.c: (gst_rtp_g726_pay_setcaps):
+	  No need to check for audio/G723 and audio/32KADPCM here as they are
+	  no longer supported.
+
+2008-06-19 10:58:57 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackparse.c: Use G_GINT64_CONSTANT, this fixes the duration query on files without known length.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_reset),
+	  (gst_wavpack_parse_src_query), (gst_wavpack_parse_create_src_pad):
+	  Use G_GINT64_CONSTANT, this fixes the duration query on files without
+	  known length.
+
+2008-06-19 10:48:57 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/: Fix demuxing of WavPack files. Muxing is still broken.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_add_wvpk_header),
+	  (gst_matroska_demux_audio_caps):
+	  * gst/matroska/matroska-ids.h:
+	  Fix demuxing of WavPack files. Muxing is still broken.
+
+2008-06-19 09:12:55 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/: Add a "vfunc" to the track context for postprocessing frames and convert the wavpack and subtitle post...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_track_free),
+	  (gst_matroska_demux_add_mpeg_seq_header),
+	  (gst_matroska_demux_add_wvpk_header),
+	  (gst_matroska_demux_check_subtitle_buffer),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+	  (gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps),
+	  (gst_matroska_demux_subtitle_caps):
+	  * gst/matroska/matroska-ids.h:
+	  Add a "vfunc" to the track context for postprocessing frames and
+	  convert the wavpack and subtitle postprocessing to this vfunc.
+	  Copy buffer flags in those functions to the new buffers too.
+	  Parse CodecState elements of Blocks.
+	  Add a postprocessing function for MPEG video that adds the sequence
+	  header from the codec private data or codec state to the frames if
+	  it's not already there.
+
+2008-06-19 08:22:16 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.c: If a gap of more than 1/2 second is found in one stream send a
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock):
+	  If a gap of more than 1/2 second is found in one stream send a
+	  NEWSEGMENT event to not stall the pipeline if the gap is too large.
+	  This also fixes Matroska files where the first buffer doesn't start
+	  at timestamp 0. Fixes bug #429322.
+	  The duration of a block is the default duration multiplied with the
+	  number of laces. Every lace is one frame and the default duration
+	  is the duration of one frame. This fixes playback of files that use
+	  lacing for some tracks.
+
+2008-06-18 20:09:28 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.c: Update FIXME/TODOs and only ignore EOS at the central, important place instead of seve...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_parse_contents_seekentry):
+	  Update FIXME/TODOs and only ignore EOS at the central, important place
+	  instead of several places.
+
+2008-06-18 16:55:05 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpg726pay.c: Fix caps, See #538891.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpg726pay.c:
+	  Fix caps, See #538891.
+
+2008-06-18 10:28:20 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.c: Improve debug output everywhere and fix the EOS logic.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_reset),
+	  (gst_matroska_demux_stream_from_num),
+	  (gst_matroska_demux_encoding_cmp),
+	  (gst_matroska_demux_encoding_order_unique),
+	  (gst_matroska_demux_read_track_encoding),
+	  (gst_matroska_demux_read_track_encodings),
+	  (gst_matroska_demux_tracknumber_unique),
+	  (gst_matroska_demux_add_stream), (gst_matroska_demux_init_stream),
+	  (gst_matroska_demux_parse_tracks),
+	  (gst_matroska_demux_parse_index_cuetrack),
+	  (gst_matroska_demux_parse_index_pointentry),
+	  (gst_matroska_demux_parse_index), (gst_matroska_demux_parse_info),
+	  (gst_matroska_demux_parse_metadata_id_simple_tag),
+	  (gst_matroska_demux_parse_metadata_id_tag),
+	  (gst_matroska_demux_parse_metadata),
+	  (gst_matroska_demux_parse_attached_file),
+	  (gst_matroska_demux_parse_attachments),
+	  (gst_matroska_demux_parse_chapters),
+	  (gst_matroska_demux_sync_streams), (gst_matroska_decode_buffer),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+	  (gst_matroska_demux_parse_cluster),
+	  (gst_matroska_demux_parse_contents_seekentry),
+	  (gst_matroska_demux_parse_contents),
+	  (gst_matroska_demux_loop_stream_parse_id),
+	  (gst_matroska_demux_loop):
+	  Improve debug output everywhere and fix the EOS logic.
+	  Check the values of the ContentEncoding elements more strictly and
+	  don't use tracks for which it's invalid.
+	  Check that the track number is unique for this stream.
+	  Check that seek positions are below G_MAXINT64 as our seeks are
+	  int64-based and overflows will fail badly.
+	  After seeks also don't push SimpleBlocks until the first one
+	  containing a keyframe is found. Before this was done only for normal
+	  Blocks.
+	  Update some FIXME/TODOs.
+	  * gst/matroska/ebml-read.c: (gst_ebml_read_peek_bytes),
+	  (gst_ebml_read_utf8), (gst_ebml_read_header):
+	  Improve debug output.
+	  * gst/matroska/matroska-ids.c:
+	  (gst_matroska_track_init_video_context):
+	  * gst/matroska/matroska-ids.h:
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_video_pad_setcaps):
+	  Remove eye mode and don't parse it anymore. We can't use that
+	  information in GStreamer yet so it's useless.
+
+2008-06-18 10:12:57 +0000  mersad <mersad@axis.com>
+
+	  gst/rtp/: Added G726 pay/depayloaders. Fixes #538891.
+	  Original commit message from CVS:
+	  Patch by: mersad <mersad at axis dot com>
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpg726depay.c: (gst_rtp_g726_depay_base_init),
+	  (gst_rtp_g726_depay_class_init), (gst_rtp_g726_depay_init),
+	  (gst_rtp_g726_depay_setcaps), (gst_rtp_g726_depay_process),
+	  (gst_rtp_g726_depay_plugin_init):
+	  * gst/rtp/gstrtpg726depay.h:
+	  * gst/rtp/gstrtpg726pay.c: (gst_rtp_g726_pay_base_init),
+	  (gst_rtp_g726_pay_class_init), (gst_rtp_g726_pay_init),
+	  (gst_rtp_g726_pay_setcaps), (gst_rtp_g726_pay_plugin_init):
+	  * gst/rtp/gstrtpg726pay.h:
+	  Added G726 pay/depayloaders. Fixes #538891.
+
+2008-06-17 10:14:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/URLS: Some more urls.
+	  Original commit message from CVS:
+	  * gst/rtsp/URLS:
+	  Some more urls.
+	  * gst/smpte/barboxwipes.c:
+	  Add a comment
+	  * tests/examples/rtp/server-v4l2-H264-alsasrc-PCMA.sh:
+	  Fix typo, add audioresample to the pipeline.
+
+2008-06-17 10:05:55 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/libmng/: Somewhat port mngenc and mngdec to 0.10. Does not work yet and has many bits ifdeffed out still.
+	  Original commit message from CVS:
+	  * ext/libmng/Makefile.am:
+	  * ext/libmng/gstmng.c: (plugin_init):
+	  * ext/libmng/gstmngdec.c: (gst_mng_dec_base_init),
+	  (gst_mng_dec_class_init), (gst_mng_dec_sink_setcaps),
+	  (gst_mng_dec_init), (gst_mng_dec_src_getcaps), (gst_mng_dec_loop),
+	  (gst_mng_dec_get_property), (gst_mng_dec_set_property),
+	  (mngdec_error), (mngdec_openstream), (mngdec_closestream),
+	  (gst_mng_dec_sink_event), (mngdec_readdata), (mngdec_settimer),
+	  (mngdec_processheader), (mngdec_getcanvasline), (mngdec_refresh),
+	  (gst_mng_dec_change_state):
+	  * ext/libmng/gstmngdec.h:
+	  * ext/libmng/gstmngenc.c: (gst_mng_enc_base_init),
+	  (gst_mng_enc_class_init), (gst_mng_enc_sink_setcaps),
+	  (gst_mng_enc_init), (gst_mng_enc_chain),
+	  (gst_mng_enc_get_property), (gst_mng_enc_set_property):
+	  * ext/libmng/gstmngenc.h:
+	  Somewhat port mngenc and mngdec to 0.10. Does not work yet and has many
+	  bits ifdeffed out still.
+
+2008-06-16 11:34:54 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.c: When comparing index elements with the same time compare their block number.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_index_compare):
+	  When comparing index elements with the same time compare their
+	  block number.
+
+2008-06-16 11:31:06 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-demux.c: (gst_matroska_demux_parse_attached_file)
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_parse_attached_file)
+	  Init variable to NULL to avoid compiler warning.
+
+2008-06-16 10:59:39 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/: Parse Attachments and post them as GST_TAG_IMAGE if we detect it as image and otherwise as GST_TAG_ATT...
+	  Original commit message from CVS:
+	  * gst/matroska/Makefile.am:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_reset),
+	  (gst_matroska_demux_parse_attached_file),
+	  (gst_matroska_demux_parse_attachments),
+	  (gst_matroska_demux_parse_contents_seekentry),
+	  (gst_matroska_demux_loop_stream_parse_id):
+	  * gst/matroska/matroska-demux.h:
+	  * gst/matroska/matroska-ids.c: (gst_matroska_register_tags):
+	  * gst/matroska/matroska-ids.h:
+	  * gst/matroska/matroska.c: (plugin_init):
+	  Parse Attachments and post them as GST_TAG_IMAGE if we detect
+	  it as image and otherwise as GST_TAG_ATTACHMENT. Include filename
+	  and description of the attachments in the caps. Fixes bug #537622.
+
+2008-06-16 10:09:03 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/speex/gstspeexenc.c: Add mode property.
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexenc.c: (gst_speex_enc_mode_get_type),
+	  (gst_speex_enc_class_init), (gst_speex_enc_sink_getcaps),
+	  (gst_speex_enc_get_latency), (gst_speex_enc_get_query_types),
+	  (gst_speex_enc_src_query), (gst_speex_enc_init),
+	  (gst_speex_enc_setup), (gst_speex_enc_push_buffer),
+	  (gst_speex_enc_chain), (gst_speex_enc_get_property),
+	  (gst_speex_enc_set_property):
+	  Add mode property.
+	  Some cleanups, add more debug info.
+	  Add latency query.
+
+2008-06-16 09:54:27 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/ebml-read.c: Return GST_FLOW_UNEXPECTED instead of GST_FLOW_ERROR on short reads.
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-read.c: (gst_ebml_read_peek_bytes):
+	  Return GST_FLOW_UNEXPECTED instead of GST_FLOW_ERROR on short reads.
+	  If we get less bytes than requested we can't do anything except doing
+	  our EOS logic.
+
+2008-06-15 19:09:54 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/: Use a GArray for storing the Cue (i.e. seek) information, store the CueTrackPositions for every track,...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_reset),
+	  (gst_matroskademux_do_index_seek),
+	  (gst_matroska_demux_parse_index_cuetrack),
+	  (gst_matroska_demux_parse_index_pointentry),
+	  (gst_matroska_index_compare), (gst_matroska_demux_parse_index),
+	  (gst_matroska_demux_parse_metadata):
+	  * gst/matroska/matroska-demux.h:
+	  * gst/matroska/matroska-ids.h:
+	  Use a GArray for storing the Cue (i.e. seek) information, store
+	  the CueTrackPositions for every track, store the block number
+	  and optimize searching in the array by sorting it after the last
+	  element was added.
+	  Fix a small memory leak when trying to parse a tags element that was
+	  already parsed.
+
+2008-06-15 15:29:29 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-mux.*: Don't write another SeekHead which indexes all Clusters to the end of the file. This isn...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_reset),
+	  (gst_matroska_mux_start), (gst_matroska_mux_finish),
+	  (gst_matroska_mux_write_data):
+	  * gst/matroska/matroska-mux.h:
+	  Don't write another SeekHead which indexes all Clusters to the end of
+	  the file. This isn't useful for anything and just increases filesize.
+
+2008-06-15 15:01:30 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/ebml-read.c: Prevent unaligned memory access when reading floats.
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-read.c: (_ext2dbl), (gst_ebml_read_float):
+	  Prevent unaligned memory access when reading floats.
+
+2008-06-15 14:08:41 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/: Make sure that every Tags element is only parsed once and it's containing tags are only posted once.
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-read.c:
+	  * gst/matroska/ebml-read.h:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_reset),
+	  (gst_matroska_demux_parse_metadata):
+	  * gst/matroska/matroska-demux.h:
+	  Make sure that every Tags element is only parsed once and it's
+	  containing tags are only posted once.
+
+2008-06-15 09:43:25 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/: Handle EBML elements like Void or CRC32 in the EbmlRead base class already. They're not useful in the ...
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-read.c: (gst_ebml_peek_id),
+	  (gst_ebml_read_header):
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream),
+	  (gst_matroska_demux_parse_tracks),
+	  (gst_matroska_demux_parse_index_cuetrack),
+	  (gst_matroska_demux_parse_index_pointentry),
+	  (gst_matroska_demux_parse_index), (gst_matroska_demux_parse_info),
+	  (gst_matroska_demux_parse_metadata_id_simple_tag),
+	  (gst_matroska_demux_parse_metadata_id_tag),
+	  (gst_matroska_demux_parse_metadata),
+	  (gst_matroska_demux_parse_attachments),
+	  (gst_matroska_demux_parse_chapters),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+	  (gst_matroska_demux_parse_cluster),
+	  (gst_matroska_demux_parse_contents_seekentry),
+	  (gst_matroska_demux_parse_contents),
+	  (gst_matroska_demux_loop_stream_parse_id):
+	  Handle EBML elements like Void or CRC32 in the EbmlRead base class
+	  already. They're not useful in the matroska parser and only cause
+	  additional code.
+
+2008-06-14 15:51:25 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/: Reverse the level list as we usually are only interested in the first element or want to add a new fir...
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-read.c: (gst_ebml_level_free),
+	  (gst_ebml_finalize), (gst_ebml_read_change_state),
+	  (gst_ebml_read_element_level_up), (gst_ebml_read_master):
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_parse_contents_seekentry):
+	  Reverse the level list as we usually are only interested in the
+	  first element or want to add a new first element. Having the
+	  first element stored at the end and calling g_list_last() and
+	  g_list_append() is more expensive.
+	  Also use GSlice for allocating the GstEbmlLevel structs.
+
+2008-06-13 21:13:46 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/debug/gsttaginject.c: Don't unref NULL taglist in finalize. Don't use c++ style comments.
+	  Original commit message from CVS:
+	  * gst/debug/gsttaginject.c: (gst_tag_inject_finalize),
+	  (gst_tag_inject_class_init), (gst_tag_inject_init):
+	  Don't unref NULL taglist in finalize. Don't use c++ style
+	  comments.
+
+2008-06-13 19:14:41 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/: Use gst_value_serialize() and gst_value_deserialize() for transforming tags from some GType to a strin...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_parse_metadata_id_simple_tag):
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_write_simple_tag),
+	  (gst_matroska_mux_write_data):
+	  Use gst_value_serialize() and gst_value_deserialize() for transforming
+	  tags from some GType to a string and the other way around. The default
+	  transformations in GLib don't include transformations from string to
+	  number types.
+
+2008-06-13 19:07:03 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-demux.*: Only parse Tracks, SeekHead and SegmentInfo elements once but allow
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_reset),
+	  (gst_matroska_demux_parse_tracks),
+	  (gst_matroska_demux_parse_index), (gst_matroska_demux_parse_info),
+	  (gst_matroska_demux_parse_attachments),
+	  (gst_matroska_demux_parse_chapters),
+	  (gst_matroska_demux_parse_contents_seekentry),
+	  (gst_matroska_demux_loop_stream_parse_id):
+	  * gst/matroska/matroska-demux.h:
+	  Only parse Tracks, SeekHead and SegmentInfo elements once but allow
+	  Tags multiple times. The first ones can appear more than once but must
+	  contain the same content as the first for backup purposes so we ignore
+	  all but the first one. Tags can appear multiple times with different
+	  content.
+	  Jump to all elements except Clusters that are available from a
+	  SeekHead to make it more likely to have all required informations
+	  before getting to the first Clusters.
+	  Add dummy functions for parsing Attachments and Chapters.
+
+2008-06-13 14:33:52 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/replaygain/: More doc updates.
+	  Original commit message from CVS:
+	  * gst/replaygain/gstrganalysis.c:
+	  * gst/replaygain/gstrglimiter.c:
+	  * gst/replaygain/gstrgvolume.c:
+	  More doc updates.
+
+2008-06-13 11:59:23 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/: docs/plugins/inspect/plugin-mythtv.xml
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-bad-plugins.args:
+	  * docs/plugins/gst-plugins-bad-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-bad-plugins.interfaces:
+	  * docs/plugins/gst-plugins-bad-plugins.prerequisites:
+	  * docs/plugins/gst-plugins-bad-plugins.signals:
+	  * docs/plugins/inspect/plugin-alsaspdif.xml:
+	  * docs/plugins/inspect/plugin-amrwb.xml:
+	  * docs/plugins/inspect/plugin-app.xml:
+	  * docs/plugins/inspect/plugin-bayer.xml:
+	  * docs/plugins/inspect/plugin-bz2.xml:
+	  * docs/plugins/inspect/plugin-cdaudio.xml:
+	  * docs/plugins/inspect/plugin-cdxaparse.xml:
+	  * docs/plugins/inspect/plugin-dtsdec.xml:
+	  * docs/plugins/inspect/plugin-dvb.xml:
+	  * docs/plugins/inspect/plugin-dvdspu.xml:
+	  * docs/plugins/inspect/plugin-faac.xml:
+	  * docs/plugins/inspect/plugin-faad.xml:
+	  * docs/plugins/inspect/plugin-fbdevsink.xml:
+	  * docs/plugins/inspect/plugin-festival.xml:
+	  * docs/plugins/inspect/plugin-filter.xml:
+	  * docs/plugins/inspect/plugin-flvdemux.xml:
+	  * docs/plugins/inspect/plugin-freeze.xml:
+	  * docs/plugins/inspect/plugin-gsm.xml:
+	  * docs/plugins/inspect/plugin-gstinterlace.xml:
+	  * docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	  * docs/plugins/inspect/plugin-h264parse.xml:
+	  * docs/plugins/inspect/plugin-interleave.xml:
+	  * docs/plugins/inspect/plugin-jack.xml:
+	  * docs/plugins/inspect/plugin-ladspa.xml:
+	  * docs/plugins/inspect/plugin-metadata.xml:
+	  * docs/plugins/inspect/plugin-mms.xml:
+	  * docs/plugins/inspect/plugin-modplug.xml:
+	  * docs/plugins/inspect/plugin-mpeg2enc.xml:
+	  * docs/plugins/inspect/plugin-mpeg4videoparse.xml:
+	  * docs/plugins/inspect/plugin-mpegtsparse.xml:
+	  * docs/plugins/inspect/plugin-mpegvideoparse.xml:
+	  * docs/plugins/inspect/plugin-musepack.xml:
+	  * docs/plugins/inspect/plugin-musicbrainz.xml:
+	  * docs/plugins/inspect/plugin-mve.xml:
+	  * docs/plugins/inspect/plugin-mythtv.xml
+	  * docs/plugins/inspect/plugin-nas.xml:
+	  * docs/plugins/inspect/plugin-neon.xml:
+	  * docs/plugins/inspect/plugin-nsfdec.xml:
+	  * docs/plugins/inspect/plugin-nuvdemux.xml:
+	  * docs/plugins/inspect/plugin-oss4.xml
+	  * docs/plugins/inspect/plugin-rawparse.xml:
+	  * docs/plugins/inspect/plugin-real.xml:
+	  * docs/plugins/inspect/plugin-replaygain.xml:
+	  * docs/plugins/inspect/plugin-rfbsrc.xml:
+	  * docs/plugins/inspect/plugin-sdl.xml:
+	  * docs/plugins/inspect/plugin-sdp.xml:
+	  * docs/plugins/inspect/plugin-selector.xml:
+	  * docs/plugins/inspect/plugin-sndfile.xml:
+	  * docs/plugins/inspect/plugin-soundtouch.xml:
+	  * docs/plugins/inspect/plugin-spcdec.xml:
+	  * docs/plugins/inspect/plugin-speed.xml:
+	  * docs/plugins/inspect/plugin-speexresample.xml:
+	  * docs/plugins/inspect/plugin-stereo.xml:
+	  * docs/plugins/inspect/plugin-subenc.xml
+	  * docs/plugins/inspect/plugin-timidity.xml:
+	  * docs/plugins/inspect/plugin-tta.xml:
+	  * docs/plugins/inspect/plugin-vcdsrc.xml:
+	  * docs/plugins/inspect/plugin-videosignal.xml:
+	  * docs/plugins/inspect/plugin-vmnc.xml:
+	  * docs/plugins/inspect/plugin-wildmidi.xml:
+	  * docs/plugins/inspect/plugin-x264.xml:
+	  * docs/plugins/inspect/plugin-xvid.xml:
+	  * docs/plugins/inspect/plugin-y4menc.xml:
+	  * ext/amrwb/gstamrwbdec.c:
+	  * ext/amrwb/gstamrwbenc.c:
+	  * ext/amrwb/gstamrwbparse.c:
+	  * ext/dc1394/gstdc1394.c:
+	  * ext/directfb/dfbvideosink.c:
+	  * ext/ivorbis/vorbisdec.c:
+	  * ext/jack/gstjackaudiosink.c:
+	  * ext/mpeg2enc/gstmpeg2enc.cc:
+	  * ext/mplex/gstmplex.cc:
+	  * ext/musicbrainz/gsttrm.c:
+	  * ext/mythtv/gstmythtvsrc.c:
+	  * ext/theora/theoradec.c:
+	  * ext/timidity/gsttimidity.c:
+	  * ext/timidity/gstwildmidi.c:
+	  * gst-libs/gst/app/gstappsink.c:
+	  * gst/deinterlace/gstdeinterlace.c:
+	  * gst/dvdspu/gstdvdspu.c:
+	  * gst/festival/gstfestival.c:
+	  * gst/freeze/gstfreeze.c:
+	  * gst/interleave/deinterleave.c:
+	  * gst/interleave/interleave.c:
+	  * gst/modplug/gstmodplug.cc:
+	  * gst/nuvdemux/gstnuvdemux.c:
+	  Add missing elements to docs. Fix doc-markup: use convinience syntax
+	  for examples (produces valid docbook), add several refsec2 when we
+	  have several titles. Fix some types.
+
+2008-06-13 11:54:05 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstudpsrc.*: Add property to control automatic join/leave of multicast groups.
+	  Original commit message from CVS:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init), (gst_udpsrc_init),
+	  (gst_udpsrc_create), (gst_udpsrc_set_property),
+	  (gst_udpsrc_get_property), (gst_udpsrc_start), (gst_udpsrc_stop):
+	  * gst/udp/gstudpsrc.h:
+	  Add property to control automatic join/leave of multicast groups.
+	  Add G_LIKELY.
+	  Remove setting caps on buffers explicitly, basesrc does that for us now.
+	  Improve debug info.
+	  Convert some non-fatal error into warnings.
+	  Use g_ntohs for better portability.
+	  Leave multicast groups when stopping.
+	  When using external sockets, use getsockname() on them to fill up the
+	  addr structure before calling methods that use the structure.
+	  Should all fix #536903.
+	  API: GstUDPSrc::auto-multicast property
+
+2008-06-13 11:47:28 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstudpnetutils.c: Use g_ntohl for better portability.
+	  Original commit message from CVS:
+	  * gst/udp/gstudpnetutils.c: (gst_udp_is_multicast):
+	  Use g_ntohl for better portability.
+
+2008-06-13 11:45:54 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstmultiudpsink.c: Fix a typo and do some small cleanups.
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_init_send),
+	  (gst_multiudpsink_remove):
+	  Fix a typo and do some small cleanups.
+
+2008-06-13 09:39:41 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtp/gstrtptheoradepay.c: Make the delivery-method mandatory on the caps and only accept inline for now.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtp/gstrtptheoradepay.c: (gst_rtp_theora_depay_setcaps):
+	  Make the delivery-method mandatory on the caps and only accept inline
+	  for now.
+	  Reverse strcmp checks for delivery-method.
+	  * gst/rtp/gstrtpvorbisdepay.c: (gst_rtp_vorbis_depay_setcaps):
+	  Make delivery method optional when parsing caps and note this in the
+	  caps.
+	  Reverse strcmp checks for delivery-method.
+	  * gst/rtp/gstrtpvorbispay.c:
+	  Update a comment to note that the delivery-method is optional,
+	  Fixes #537675.
+
+2008-06-12 17:30:06 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Set udpsrc for receiving data from multicast groups to PAUSED instead of leaving them in READY...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_stream_configure_mcast):
+	  Set udpsrc for receiving data from multicast groups to PAUSED instead of
+	  leaving them in READY. Fixes #537832.
+
+2008-06-12 12:14:38 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavimux.c: Simplify code. gst_tag_list_merge() does the NULL checks. Add a FIXME for a random constant in t...
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c:
+	  Simplify code. gst_tag_list_merge() does the NULL checks. Add a FIXME
+	  for a random constant in tagmuxing code.
+
+2008-06-11 14:28:44 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/debug/gsttaginject.*: Now actually adding the new element.
+	  Original commit message from CVS:
+	  * gst/debug/gsttaginject.c:
+	  * gst/debug/gsttaginject.h:
+	  Now actually adding the new element.
+
+2008-06-11 14:11:16 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Remove dummy plugin_init. Remove some undefined entries from doc- section file. Add taginject element and rebuild doc...
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * 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:
+	  * docs/plugins/inspect/plugin-aasink.xml:
+	  * docs/plugins/inspect/plugin-alaw.xml:
+	  * docs/plugins/inspect/plugin-alpha.xml:
+	  * docs/plugins/inspect/plugin-alphacolor.xml:
+	  * docs/plugins/inspect/plugin-annodex.xml:
+	  * docs/plugins/inspect/plugin-apetag.xml:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  * docs/plugins/inspect/plugin-auparse.xml:
+	  * docs/plugins/inspect/plugin-autodetect.xml:
+	  * docs/plugins/inspect/plugin-avi.xml:
+	  * docs/plugins/inspect/plugin-cacasink.xml:
+	  * docs/plugins/inspect/plugin-cairo.xml:
+	  * docs/plugins/inspect/plugin-cdio.xml:
+	  * docs/plugins/inspect/plugin-cutter.xml:
+	  * docs/plugins/inspect/plugin-debug.xml:
+	  * docs/plugins/inspect/plugin-dv.xml:
+	  * docs/plugins/inspect/plugin-efence.xml:
+	  * docs/plugins/inspect/plugin-effectv.xml:
+	  * docs/plugins/inspect/plugin-equalizer.xml:
+	  * docs/plugins/inspect/plugin-esdsink.xml:
+	  * docs/plugins/inspect/plugin-flac.xml:
+	  * docs/plugins/inspect/plugin-flxdec.xml:
+	  * docs/plugins/inspect/plugin-gamma.xml:
+	  * docs/plugins/inspect/plugin-gconfelements.xml:
+	  * docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	  * docs/plugins/inspect/plugin-goom.xml:
+	  * docs/plugins/inspect/plugin-goom2k1.xml:
+	  * docs/plugins/inspect/plugin-halelements.xml:
+	  * docs/plugins/inspect/plugin-icydemux.xml:
+	  * docs/plugins/inspect/plugin-id3demux.xml:
+	  * docs/plugins/inspect/plugin-jpeg.xml:
+	  * docs/plugins/inspect/plugin-level.xml:
+	  * docs/plugins/inspect/plugin-matroska.xml:
+	  * docs/plugins/inspect/plugin-monoscope.xml:
+	  * docs/plugins/inspect/plugin-mulaw.xml:
+	  * docs/plugins/inspect/plugin-multifile.xml:
+	  * docs/plugins/inspect/plugin-multipart.xml:
+	  * docs/plugins/inspect/plugin-navigationtest.xml:
+	  * docs/plugins/inspect/plugin-ossaudio.xml:
+	  * docs/plugins/inspect/plugin-png.xml:
+	  * docs/plugins/inspect/plugin-quicktime.xml:
+	  * docs/plugins/inspect/plugin-rtp.xml:
+	  * docs/plugins/inspect/plugin-rtsp.xml:
+	  * docs/plugins/inspect/plugin-smpte.xml:
+	  * docs/plugins/inspect/plugin-soup.xml:
+	  * docs/plugins/inspect/plugin-spectrum.xml:
+	  * docs/plugins/inspect/plugin-speex.xml:
+	  * docs/plugins/inspect/plugin-taglib.xml:
+	  * docs/plugins/inspect/plugin-udp.xml:
+	  * docs/plugins/inspect/plugin-video4linux2.xml:
+	  * docs/plugins/inspect/plugin-videobalance.xml:
+	  * docs/plugins/inspect/plugin-videobox.xml:
+	  * docs/plugins/inspect/plugin-videocrop.xml:
+	  * docs/plugins/inspect/plugin-videoflip.xml:
+	  * docs/plugins/inspect/plugin-videomixer.xml:
+	  * docs/plugins/inspect/plugin-wavenc.xml:
+	  * docs/plugins/inspect/plugin-wavpack.xml:
+	  * docs/plugins/inspect/plugin-wavparse.xml:
+	  * docs/plugins/inspect/plugin-ximagesrc.xml:
+	  * gst/debug/Makefile.am:
+	  * gst/debug/breakmydata.c:
+	  * gst/debug/efence.c:
+	  * gst/debug/gstdebug.c:
+	  * gst/debug/gstnavseek.c:
+	  * gst/debug/gstpushfilesrc.c:
+	  * gst/debug/gstpushfilesrc.h:
+	  * gst/debug/negotiation.c:
+	  * gst/debug/progressreport.c:
+	  * gst/debug/progressreport.h:
+	  * gst/debug/rndbuffersize.c:
+	  * gst/debug/testplugin.c:
+	  Remove dummy plugin_init. Remove some undefined entries from doc-
+	  section file. Add taginject element and rebuild docs for it.
+
+2008-06-11 11:27:46 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/matroska-mux.c: Update the counter for the number of streams when pads are added or removed. This will m...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_request_new_pad),
+	  (gst_matroska_mux_release_pad), (gst_matroska_mux_write_data):
+	  Update the counter for the number of streams when pads are added or
+	  removed. This will make sure that a seek table is generated for
+	  files with just one audio stream.
+
+2008-06-11 11:18:23 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/: Add some more tags, improve debugging a bit and make sure that
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_parse_metadata_id_simple_tag):
+	  * gst/matroska/matroska-ids.h:
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_write_simple_tag):
+	  Add some more tags, improve debugging a bit and make sure that
+	  GValue transformation has succeeded before using the result
+	  as a tag.
+
+2008-06-11 08:56:16 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtp/gstrtptheorapay.c: The Theora RTP payloader only supports the "inline" delievery method so let's declare this...
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtp/gstrtptheorapay.c:
+	  The Theora RTP payloader only supports the "inline" delievery method
+	  so let's declare this on the caps of the static pad template.
+	  Fixes bug #537675.
+
+2008-06-10 17:20:45 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/videomixer/videomixer.c: Remove bogus check.
+	  Original commit message from CVS:
+	  * gst/videomixer/videomixer.c: (gst_videomixer_fill_queues),
+	  (gst_videomixer_blend_buffers), (gst_videomixer_update_queues):
+	  Remove bogus check.
+
+2008-06-10 16:25:24 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/videomixer/videomixer.c: Use stream_time to synchronize the object properties.
+	  Original commit message from CVS:
+	  * gst/videomixer/videomixer.c: (gst_videomixer_fill_queues),
+	  (gst_videomixer_blend_buffers):
+	  Use stream_time to synchronize the object properties.
+	  Use running_time of the master pad to timestamp outgoing buffers.
+	  Fix the initial segment event to extend an unknown amount of time.
+	  Fixes #537361.
+
+2008-06-10 11:05:30 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: Try to ignore unparsable/unknown streams and give a warning instead of erroring out. Fixes #53...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_parse_index), (gst_avi_demux_massage_index),
+	  (gst_avi_demux_calculate_durations_from_index),
+	  (gst_avi_demux_stream_header_push),
+	  (gst_avi_demux_stream_header_pull):
+	  Try to ignore unparsable/unknown streams and give a warning instead of
+	  erroring out. Fixes #537377.
+
+2008-06-10 10:44:53 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/ebml-write.c: Use GDOUBLE_TO_BE() instead of (probably slower) custom code.
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-write.c: (gst_ebml_write_float):
+	  Use GDOUBLE_TO_BE() instead of (probably slower) custom code.
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_base_init),
+	  (gst_matroska_demux_class_init), (gst_matroska_demux_init),
+	  (gst_matroska_track_free), (gst_matroska_demux_encoding_cmp),
+	  (gst_matroska_demux_read_track_encodings),
+	  (gst_matroska_demux_add_stream),
+	  (gst_matroska_demux_handle_src_query),
+	  (gst_matroska_demux_init_stream),
+	  (gst_matroska_demux_parse_index_cuetrack),
+	  (gst_matroska_demux_parse_index_pointentry),
+	  (gst_matroska_demux_parse_info),
+	  (gst_matroska_demux_parse_metadata_id_simple_tag),
+	  (gst_matroska_demux_parse_metadata),
+	  (gst_matroska_demux_add_wvpk_header), (gst_matroska_decode_buffer),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+	  (gst_matroska_demux_parse_cluster),
+	  (gst_matroska_demux_parse_contents_seekentry),
+	  (gst_matroska_demux_loop_stream_parse_id),
+	  (gst_matroska_demux_loop), (gst_matroska_demux_video_caps),
+	  (gst_matroska_demux_audio_caps),
+	  (gst_matroska_demux_subtitle_caps):
+	  * gst/matroska/matroska-demux.h:
+	  * gst/matroska/matroska-ids.c:
+	  (gst_matroska_track_init_subtitle_context):
+	  * gst/matroska/matroska-ids.h:
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_base_init),
+	  (gst_matroska_mux_class_init), (gst_matroska_mux_init),
+	  (gst_matroska_mux_create_uid), (gst_matroska_mux_reset),
+	  (gst_matroska_mux_video_pad_setcaps),
+	  (gst_matroska_mux_audio_pad_setcaps),
+	  (gst_matroska_mux_subtitle_pad_setcaps),
+	  (gst_matroska_mux_request_new_pad),
+	  (gst_matroska_mux_track_header), (gst_matroska_mux_start),
+	  (gst_matroska_mux_write_simple_tag), (gst_matroska_mux_finish),
+	  (gst_matroska_mux_write_data), (gst_matroska_mux_collected),
+	  (gst_matroska_mux_set_property):
+	  Add many FIXMEs/TODOs all over the matroska muxer and demuxer
+	  elements, do some checks for valid values in the demuxer, handle
+	  tracktimecodescale in the demuxer, set correct default values for all
+	  settings in the demuxer, review and add all missing matroska
+	  IDs and some more raw YUV formats, and some trivial cleanup.
+
+2008-06-10 08:59:17 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/pulse/: Some smaller cleanup. Use G_PARAM_STATIC_STRINGS, gst_element_class_set_details_simple() and fix coding s...
+	  Original commit message from CVS:
+	  * ext/pulse/pulsemixer.c: (gst_pulsemixer_base_init),
+	  (gst_pulsemixer_class_init):
+	  * ext/pulse/pulsesink.c: (gst_pulsesink_base_init),
+	  (gst_pulsesink_class_init), (gst_pulsesink_prepare):
+	  * ext/pulse/pulsesrc.c: (gst_pulsesrc_interface_supported),
+	  (gst_pulsesrc_base_init), (gst_pulsesrc_class_init),
+	  (gst_pulsesrc_prepare):
+	  Some smaller cleanup. Use G_PARAM_STATIC_STRINGS,
+	  gst_element_class_set_details_simple() and fix coding style a bit
+	  more.
+
+2008-06-10 08:22:17 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Add documentation to the pulseaudio plugin and run make update in docs/plugins.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * 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:
+	  * docs/plugins/inspect/plugin-aasink.xml:
+	  * docs/plugins/inspect/plugin-alaw.xml:
+	  * docs/plugins/inspect/plugin-alpha.xml:
+	  * docs/plugins/inspect/plugin-alphacolor.xml:
+	  * docs/plugins/inspect/plugin-annodex.xml:
+	  * docs/plugins/inspect/plugin-apetag.xml:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  * docs/plugins/inspect/plugin-auparse.xml:
+	  * docs/plugins/inspect/plugin-autodetect.xml:
+	  * docs/plugins/inspect/plugin-avi.xml:
+	  * docs/plugins/inspect/plugin-cacasink.xml:
+	  * docs/plugins/inspect/plugin-cairo.xml:
+	  * docs/plugins/inspect/plugin-cdio.xml:
+	  * docs/plugins/inspect/plugin-cutter.xml:
+	  * docs/plugins/inspect/plugin-debug.xml:
+	  * docs/plugins/inspect/plugin-dv.xml:
+	  * docs/plugins/inspect/plugin-efence.xml:
+	  * docs/plugins/inspect/plugin-effectv.xml:
+	  * docs/plugins/inspect/plugin-equalizer.xml:
+	  * docs/plugins/inspect/plugin-esdsink.xml:
+	  * docs/plugins/inspect/plugin-flac.xml:
+	  * docs/plugins/inspect/plugin-flxdec.xml:
+	  * docs/plugins/inspect/plugin-gamma.xml:
+	  * docs/plugins/inspect/plugin-gconfelements.xml:
+	  * docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	  * docs/plugins/inspect/plugin-goom.xml:
+	  * docs/plugins/inspect/plugin-goom2k1.xml:
+	  * docs/plugins/inspect/plugin-halelements.xml:
+	  * docs/plugins/inspect/plugin-icydemux.xml:
+	  * docs/plugins/inspect/plugin-id3demux.xml:
+	  * docs/plugins/inspect/plugin-jpeg.xml:
+	  * docs/plugins/inspect/plugin-level.xml:
+	  * docs/plugins/inspect/plugin-matroska.xml:
+	  * docs/plugins/inspect/plugin-monoscope.xml:
+	  * docs/plugins/inspect/plugin-mulaw.xml:
+	  * docs/plugins/inspect/plugin-multifile.xml:
+	  * docs/plugins/inspect/plugin-multipart.xml:
+	  * docs/plugins/inspect/plugin-navigationtest.xml:
+	  * docs/plugins/inspect/plugin-ossaudio.xml:
+	  * docs/plugins/inspect/plugin-png.xml:
+	  * docs/plugins/inspect/plugin-pulseaudio.xml:
+	  * docs/plugins/inspect/plugin-quicktime.xml:
+	  * docs/plugins/inspect/plugin-rtp.xml:
+	  * docs/plugins/inspect/plugin-rtsp.xml:
+	  * docs/plugins/inspect/plugin-smpte.xml:
+	  * docs/plugins/inspect/plugin-soup.xml:
+	  * docs/plugins/inspect/plugin-spectrum.xml:
+	  * docs/plugins/inspect/plugin-speex.xml:
+	  * docs/plugins/inspect/plugin-taglib.xml:
+	  * docs/plugins/inspect/plugin-udp.xml:
+	  * docs/plugins/inspect/plugin-video4linux2.xml:
+	  * docs/plugins/inspect/plugin-videobalance.xml:
+	  * docs/plugins/inspect/plugin-videobox.xml:
+	  * docs/plugins/inspect/plugin-videocrop.xml:
+	  * docs/plugins/inspect/plugin-videoflip.xml:
+	  * docs/plugins/inspect/plugin-videomixer.xml:
+	  * docs/plugins/inspect/plugin-wavenc.xml:
+	  * docs/plugins/inspect/plugin-wavpack.xml:
+	  * docs/plugins/inspect/plugin-wavparse.xml:
+	  * docs/plugins/inspect/plugin-ximagesrc.xml:
+	  * ext/pulse/plugin.c:
+	  * ext/pulse/pulsemixer.c:
+	  * ext/pulse/pulsesink.c:
+	  * ext/pulse/pulsesrc.c:
+	  Add documentation to the pulseaudio plugin and run make update
+	  in docs/plugins.
+
+2008-06-10 06:52:44 +0000  Brian Cameron <brian.cameron@sun.com>
+
+	  sys/sunaudio/gstsunaudiomixerctrl.c: Improvements for the SunAudio mixer by handling mute as no gain for tracks that ...
+	  Original commit message from CVS:
+	  Patch by: Brian Cameron <brian.cameron at sun dot com>
+	  * sys/sunaudio/gstsunaudiomixerctrl.c:
+	  (gst_sunaudiomixer_ctrl_get_volume),
+	  (gst_sunaudiomixer_ctrl_set_volume):
+	  Improvements for the SunAudio mixer by handling mute as no gain
+	  for tracks that have a gain property but no mute property.
+	  Fixes bug #536067.
+
+2008-06-10 06:45:33 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Add pulseaudio GStreamer element from gst-pulse. Development will continue here instead of pulseaudio SVN. Fixes bug ...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * ext/pulse/Makefile.am:
+	  * ext/pulse/plugin.c: (plugin_init):
+	  * ext/pulse/pulsemixer.c: (gst_pulsemixer_interface_supported),
+	  (gst_pulsemixer_implements_interface_init),
+	  (gst_pulsemixer_init_interfaces), (gst_pulsemixer_base_init),
+	  (gst_pulsemixer_class_init), (gst_pulsemixer_init),
+	  (gst_pulsemixer_finalize), (gst_pulsemixer_set_property),
+	  (gst_pulsemixer_get_property), (gst_pulsemixer_change_state):
+	  * ext/pulse/pulsemixer.h:
+	  * ext/pulse/pulsemixerctrl.c:
+	  (gst_pulsemixer_ctrl_context_state_cb),
+	  (gst_pulsemixer_ctrl_sink_info_cb),
+	  (gst_pulsemixer_ctrl_source_info_cb),
+	  (gst_pulsemixer_ctrl_subscribe_cb),
+	  (gst_pulsemixer_ctrl_success_cb), (gst_pulsemixer_ctrl_open),
+	  (gst_pulsemixer_ctrl_close), (gst_pulsemixer_ctrl_new),
+	  (gst_pulsemixer_ctrl_free), (gst_pulsemixer_ctrl_list_tracks),
+	  (gst_pulsemixer_ctrl_timeout_event), (restart_time_event),
+	  (gst_pulsemixer_ctrl_set_volume), (gst_pulsemixer_ctrl_get_volume),
+	  (gst_pulsemixer_ctrl_set_record), (gst_pulsemixer_ctrl_set_mute):
+	  * ext/pulse/pulsemixerctrl.h:
+	  * ext/pulse/pulsemixertrack.c: (gst_pulsemixer_track_class_init),
+	  (gst_pulsemixer_track_init), (gst_pulsemixer_track_new):
+	  * ext/pulse/pulsemixertrack.h:
+	  * ext/pulse/pulseprobe.c: (gst_pulseprobe_context_state_cb),
+	  (gst_pulseprobe_sink_info_cb), (gst_pulseprobe_source_info_cb),
+	  (gst_pulseprobe_invalidate), (gst_pulseprobe_open),
+	  (gst_pulseprobe_enumerate), (gst_pulseprobe_close),
+	  (gst_pulseprobe_new), (gst_pulseprobe_free),
+	  (gst_pulseprobe_get_properties), (gst_pulseprobe_needs_probe),
+	  (gst_pulseprobe_probe_property), (gst_pulseprobe_get_values),
+	  (gst_pulseprobe_set_server):
+	  * ext/pulse/pulseprobe.h:
+	  * ext/pulse/pulsesink.c: (gst_pulsesink_base_init),
+	  (gst_pulsesink_class_init), (gst_pulsesink_init),
+	  (gst_pulsesink_destroy_stream), (gst_pulsesink_destroy_context),
+	  (gst_pulsesink_finalize), (gst_pulsesink_dispose),
+	  (gst_pulsesink_set_property), (gst_pulsesink_get_property),
+	  (gst_pulsesink_context_state_cb), (gst_pulsesink_stream_state_cb),
+	  (gst_pulsesink_stream_request_cb),
+	  (gst_pulsesink_stream_latency_update_cb), (gst_pulsesink_open),
+	  (gst_pulsesink_close), (gst_pulsesink_prepare),
+	  (gst_pulsesink_unprepare), (gst_pulsesink_write),
+	  (gst_pulsesink_delay), (gst_pulsesink_success_cb),
+	  (gst_pulsesink_reset), (gst_pulsesink_change_title),
+	  (gst_pulsesink_event), (gst_pulsesink_get_type):
+	  * ext/pulse/pulsesink.h:
+	  * ext/pulse/pulsesrc.c: (gst_pulsesrc_interface_supported),
+	  (gst_pulsesrc_implements_interface_init),
+	  (gst_pulsesrc_init_interfaces), (gst_pulsesrc_base_init),
+	  (gst_pulsesrc_class_init), (gst_pulsesrc_init),
+	  (gst_pulsesrc_destroy_stream), (gst_pulsesrc_destroy_context),
+	  (gst_pulsesrc_finalize), (gst_pulsesrc_dispose),
+	  (gst_pulsesrc_set_property), (gst_pulsesrc_get_property),
+	  (gst_pulsesrc_context_state_cb), (gst_pulsesrc_stream_state_cb),
+	  (gst_pulsesrc_stream_request_cb), (gst_pulsesrc_open),
+	  (gst_pulsesrc_close), (gst_pulsesrc_prepare),
+	  (gst_pulsesrc_unprepare), (gst_pulsesrc_read),
+	  (gst_pulsesrc_delay), (gst_pulsesrc_change_state),
+	  (gst_pulsesrc_get_type):
+	  * ext/pulse/pulsesrc.h:
+	  * ext/pulse/pulseutil.c: (gst_pulse_fill_sample_spec),
+	  (gst_pulse_client_name), (gst_pulse_gst_to_channel_map):
+	  * ext/pulse/pulseutil.h:
+	  Add pulseaudio GStreamer element from gst-pulse. Development will
+	  continue here instead of pulseaudio SVN. Fixes bug #400679.
+	  Only changes over gst-pulse SVN are added copyright to the top of
+	  files and coding style changes.
+
+2008-06-09 20:02:05 +0000  Benjamin Kampmann <benjamin@fluendo.com>
+
+	  ext/cdio/: Also extract album title and album genre from CD-TEXT if available (#537021).
+	  Original commit message from CVS:
+	  Patch by: Benjamin Kampmann  <benjamin at fluendo dot com>
+	  * ext/cdio/gstcdio.c: (gst_cdio_get_cdtext),
+	  (gst_cdio_add_cdtext_album_tags):
+	  * ext/cdio/gstcdio.h:
+	  * ext/cdio/gstcdiocddasrc.c: (gst_cdio_cdda_src_open):
+	  Also extract album title and album genre from CD-TEXT if
+	  available (#537021).
+
+2008-06-09 08:52:04 +0000  Sjoerd Simons <sjoerd@luon.net>
+
+	  sys/v4l2/gstv4l2src.c: Improve negotiation a bit more by picking the smallest possible resolution that is larger than...
+	  Original commit message from CVS:
+	  Patch by: Sjoerd Simons <sjoerd at luon dot net>
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_negotiate):
+	  Improve negotiation a bit more by picking the smallest possible
+	  resolution that is larger than the resolution specified in the
+	  first caps entry of the peer caps. Fixes bug #536994.
+
+2008-06-09 08:42:49 +0000  Bastien Nocera <hadess@hadess.net>
+
+	  sys/v4l2/: Fix compilation with newer GIT kernels that deprecated
+	  Original commit message from CVS:
+	  Patch by: Bastien Nocera <hadess at hadess dot net>
+	  * sys/v4l2/gstv4l2vidorient.c:
+	  * sys/v4l2/v4l2_calls.c: (gst_v4l2_fill_lists):
+	  Fix compilation with newer GIT kernels that deprecated
+	  V4L2_CID_HCENTER and V4L2_CID_VCENTER. Fixes bug #536317.
+
+2008-06-07 18:48:54 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Require libcdio >= 0.76.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * ext/cdio/gstcdio.c:
+	  * ext/cdio/gstcdio.h:
+	  * ext/cdio/gstcdiocddasrc.c: (gst_cdio_cdda_src_open):
+	  Require libcdio >= 0.76.
+
+2008-06-05 11:07:17 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/interleave/: Properly implement duration and position queries in bytes format. We have to take the upstream reply...
+	  Original commit message from CVS:
+	  * gst/interleave/deinterleave.c: (gst_deinterleave_add_new_pads),
+	  (gst_deinterleave_src_query):
+	  * gst/interleave/interleave.c: (gst_interleave_src_query_duration),
+	  (gst_interleave_src_query):
+	  Properly implement duration and position queries in bytes format. We
+	  have to take the upstream reply and divide/multiply it by the number
+	  of channels to get the correct result.
+
+2008-06-05 09:45:00 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  gst/avi/gstavidemux.c: Catch UNEXPECTED when downstream has reached end of segment in reverse mode.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  Catch UNEXPECTED when downstream has reached end of
+	  segment in reverse mode.
+
+2008-06-04 18:08:35 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  gst/avi/gstavidemux.c: Fix typo in comment
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  Fix typo in comment
+
+2008-06-04 18:03:24 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  gst/avi/gstavidemux.c: Because we don't know the frame order we need to push till the next keyframe
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  Because we don't know the frame order we need to push till
+	  the next keyframe
+
+2008-06-04 17:39:31 +0000  Sjoerd Simons <sjoerd@luon.net>
+
+	  sys/v4l2/gstv4l2src.c: Provide a custom negotiation function to make sure to pick the highest possible framerate and ...
+	  Original commit message from CVS:
+	  Patch by: Sjoerd Simons <sjoerd at luon dot net>
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init),
+	  (gst_v4l2src_fixate), (gst_v4l2src_negotiate):
+	  Provide a custom negotiation function to make sure to pick the highest
+	  possible framerate and resolution. Fixes bug #536646.
+
+2008-06-04 16:49:26 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  gst/avi/gstavidemux.c: Set EOS when going out of the segment in reverse playback
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  Set EOS when going out of the segment in reverse playback
+
+2008-06-04 15:19:46 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/Makefile.am: Add -Wno-attributes to CXXFLAGS to suppress warning caused by taglib headers (with gcc 4.3.1).
+	  Original commit message from CVS:
+	  * ext/taglib/Makefile.am::
+	  Add -Wno-attributes to CXXFLAGS to suppress warning caused by
+	  taglib headers (with gcc 4.3.1).
+
+2008-06-04 11:59:18 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtsp/gstrtspsrc.c: Use the new gst_rtsp_connection_get_ip() to access the IP address of a GstRTSPConnection since...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_stream_configure_udp_sink):
+	  Use the new gst_rtsp_connection_get_ip() to access the IP address
+	  of a GstRTSPConnection since it is a private member.
+
+2008-06-04 10:42:46 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Use new utility functions in libgsttag to process coverart (#512333).
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_extract_picture_buffer):
+	  * gst/id3demux/id3v2frames.c: (parse_picture_frame):
+	  Use new utility functions in libgsttag to process coverart (#512333).
+
+2008-06-04 08:54:09 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/flac/gstflacdec.c: We actually support left/side, right/side and mid/side files. The conversion to normal, interl...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_write):
+	  We actually support left/side, right/side and mid/side files. The
+	  conversion to normal, interleaved stereo is done by libflac.
+
+2008-06-04 07:36:07 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/ebml-write.c: Unref the write cache in finalize if it was set and add add "FIXME" to a comment that need...
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-write.c: (gst_ebml_write_finalize),
+	  (gst_ebml_write_set_cache):
+	  Unref the write cache in finalize if it was set and add add "FIXME"
+	  to a comment that needs it.
+
+2008-06-04 06:48:46 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/interleave/interleave.*: Use an always increasing integer for the number in the name of the requested sink pads t...
+	  Original commit message from CVS:
+	  * gst/interleave/interleave.c: (gst_interleave_pad_get_type),
+	  (gst_interleave_pad_get_property), (gst_interleave_pad_class_init),
+	  (gst_interleave_request_new_pad), (gst_interleave_release_pad):
+	  * gst/interleave/interleave.h:
+	  Use an always increasing integer for the number in the name of the
+	  requested sink pads to guarantuee a unique name. Add a "channel"
+	  property to GstInterleavePad to make it possible for applications
+	  to retrieve the channel number in the output for every pad.
+	  Use g_type_register_static_simple() instead of
+	  g_type_register_static() to save some relocations.
+
+2008-06-03 14:35:59 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/interleave/interleave.c: Stop GstCollectPads before calling the parent's state change function when going from PA...
+	  Original commit message from CVS:
+	  * gst/interleave/interleave.c: (gst_interleave_pad_get_type),
+	  (gst_interleave_change_state):
+	  Stop GstCollectPads before calling the parent's state change function
+	  when going from PAUSED to READY as we otherwise deadlock.
+	  Fixes bug #536258.
+
+2008-06-03 09:03:19 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/interleave/interleave.c: Use new gst_audio_check_channel_positions() function and register the GstInterleavePad t...
+	  Original commit message from CVS:
+	  * gst/interleave/interleave.c:
+	  (gst_interleave_check_channel_positions),
+	  (gst_interleave_set_channel_positions),
+	  (gst_interleave_class_init):
+	  Use new gst_audio_check_channel_positions() function and register
+	  the GstInterleavePad type from a threadsafe context.
+
+2008-06-02 16:10:00 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  gst/avi/gstavidemux.*: Implement reverse playback. Fixes #535300.
+	  Original commit message from CVS:
+	  Patch by: Thijs Vermeir <thijsvermeir at gmail dot com>
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_index_next),
+	  (gst_avi_demux_index_prev), (gst_avi_demux_index_entry_for_time),
+	  (gst_avi_demux_do_seek), (gst_avi_demux_handle_seek),
+	  (gst_avi_demux_process_next_entry):
+	  * gst/avi/gstavidemux.h:
+	  Implement reverse playback. Fixes #535300.
+	  Small cleanups.
+
+2008-06-02 12:42:14 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/interleave/interleave.*: Allow setting channel positions via a property and allow using the channel positions on ...
+	  Original commit message from CVS:
+	  * gst/interleave/interleave.c: (gst_interleave_pad_get_type),
+	  (gst_interleave_finalize), (gst_audio_check_channel_positions),
+	  (gst_interleave_set_channel_positions),
+	  (gst_interleave_class_init), (gst_interleave_init),
+	  (gst_interleave_set_property), (gst_interleave_get_property),
+	  (gst_interleave_request_new_pad), (gst_interleave_release_pad),
+	  (gst_interleave_sink_setcaps), (gst_interleave_src_query_duration),
+	  (gst_interleave_src_query_latency), (gst_interleave_collected):
+	  * gst/interleave/interleave.h:
+	  Allow setting channel positions via a property and allow using the
+	  channel positions on the input as the channel positions of the output.
+	  Fix some broken logic and memory leaks.
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/interleave.c: (src_handoff_float32),
+	  (sink_handoff_float32), (GST_START_TEST), (interleave_suite):
+	  Add unit tests for checking correct handling of channel positions.
+
+2008-06-02 12:22:56 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/videomixer/videomixer.c: When using gst_element_iterate_pads() one has to unref every pad after usage.
+	  Original commit message from CVS:
+	  * gst/videomixer/videomixer.c: (gst_videomixer_query_duration),
+	  (gst_videomixer_query_latency):
+	  When using gst_element_iterate_pads() one has to unref every pad
+	  after usage.
+
+2008-05-31 16:53:23 +0000  Bastien Nocera <hadess@hadess.net>
+
+	  gst/qtdemux/: Improve meta-data handling, add 'comment', 'description' and 'copyright' tag handling.
+	  Original commit message from CVS:
+	  Patch by: Bastien Nocera <hadess at hadess dot net>
+	  * gst/qtdemux/qtdemux.c: (qtdemux_tag_add_str),
+	  (qtdemux_parse_udta):
+	  * gst/qtdemux/qtdemux_fourcc.h:
+	  Improve meta-data handling, add 'comment', 'description' and
+	  'copyright' tag handling.
+	  Fixes #535935
+
+2008-05-31 15:30:41 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/qtdemux/qtdemux.c: Make sure we we don't clip the segment's stop using the main segment duration as that could cr...
+	  Original commit message from CVS:
+	  2008-05-31  Julien Moutte  <julien@fluendo.com>
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_find_keyframe),
+	  (gst_qtdemux_find_segment), (gst_qtdemux_perform_seek),
+	  (gst_qtdemux_seek_to_previous_keyframe),
+	  (gst_qtdemux_activate_segment), (gst_qtdemux_loop): Make sure we
+	  we don't clip the segment's stop using the main segment duration
+	  as
+	  that could crop quite some video frames. Make reverse playback
+	  support
+	  more robust and support edit lists. Support seeking to the last
+	  frame,
+	  and fix reverse looping playback. Add some debugging.
+	  * win32/common/config.h: Updated.
+
+2008-05-31 08:37:00 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/equalizer/gstiirequalizer.c: Don't clip float/double samples, correctly unset passthrough mode and use better rou...
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer.c:
+	  (gst_iir_equalizer_transform_ip):
+	  Don't clip float/double samples, correctly unset passthrough mode
+	  and use better rounding for integer samples.
+
+2008-05-30 11:03:57 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/equalizer/gstiirequalizer.*: Update the filter coefficients only when needed in the transform_ip function and cor...
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer.c:
+	  (gst_iir_equalizer_band_set_property), (gst_iir_equalizer_init),
+	  (setup_filter), (set_passthrough), (update_coefficients),
+	  (gst_iir_equalizer_compute_frequencies),
+	  (gst_iir_equalizer_transform_ip):
+	  * gst/equalizer/gstiirequalizer.h:
+	  Update the filter coefficients only when needed in the transform_ip
+	  function and correctly set the element into passthrough mode if the
+	  gain of all bands is 0.
+
+2008-05-29 11:30:16 +0000  Sebastian Keller <sebastian-keller@gmx.de>
+
+	  gst/alpha/gstalpha.c: Try to skip pixels or areas that are too dark or too bright for us to do meaningfull color dete...
+	  Original commit message from CVS:
+	  Based on patch by: Sebastian Keller <sebastian-keller at gmx dot de>
+	  * gst/alpha/gstalpha.c: (gst_alpha_class_init), (gst_alpha_init),
+	  (gst_alpha_set_property), (gst_alpha_get_property),
+	  (gst_alpha_chroma_key_ayuv), (gst_alpha_chromakey_row_i420):
+	  Try to skip pixels or areas that are too dark or too bright for us to do
+	  meaningfull color detection.
+	  Added properties to control the sensitivity to light and darkness.
+	  Added some small cleanups. Fixes #512345.
+
+2008-05-28 20:01:32 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Ignore some more generated things
+	  Original commit message from CVS:
+	  * docs/plugins/.cvsignore:
+	  * tests/check/elements/.cvsignore:
+	  Ignore some more generated things
+	  * tests/check/Makefile.am:
+	  Ignore OSS elements in the state changes test too.
+
+2008-05-28 16:22:36 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  docs/plugins/: Add SMPTE effect elements to docs.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  Add SMPTE effect elements to docs.
+
+2008-05-28 14:31:05 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Document whats first shown on the fdo plugin docs page :)
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * ext/raw1394/gstdv1394src.c:
+	  Document whats first shown on the fdo plugin docs page :)
+
+2008-05-28 14:07:21 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Rename audiovoice to audiokaraoke and add it to the docs.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  * gst/audiofx/Makefile.am:
+	  * gst/audiofx/audiofx.c:
+	  * gst/audiofx/audiokaraoke.c:
+	  * gst/audiofx/audiokaraoke.h:
+	  * gst/audiofx/audiovoice.c:
+	  * gst/audiofx/audiovoice.h:
+	  Rename audiovoice to audiokaraoke and add it to the docs.
+
+2008-05-28 13:28:20 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Document aasink and cacasink.
+	  Original commit message from CVS:
+	  * REQUIREMENTS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * 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:
+	  * docs/plugins/inspect/plugin-aasink.xml:
+	  * docs/plugins/inspect/plugin-alaw.xml:
+	  * docs/plugins/inspect/plugin-alpha.xml:
+	  * docs/plugins/inspect/plugin-alphacolor.xml:
+	  * docs/plugins/inspect/plugin-annodex.xml:
+	  * docs/plugins/inspect/plugin-apetag.xml:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  * docs/plugins/inspect/plugin-auparse.xml:
+	  * docs/plugins/inspect/plugin-autodetect.xml:
+	  * docs/plugins/inspect/plugin-avi.xml:
+	  * docs/plugins/inspect/plugin-cacasink.xml:
+	  * docs/plugins/inspect/plugin-cairo.xml:
+	  * docs/plugins/inspect/plugin-cdio.xml:
+	  * docs/plugins/inspect/plugin-cutter.xml:
+	  * docs/plugins/inspect/plugin-debug.xml:
+	  * docs/plugins/inspect/plugin-dv.xml:
+	  * docs/plugins/inspect/plugin-efence.xml:
+	  * docs/plugins/inspect/plugin-effectv.xml:
+	  * docs/plugins/inspect/plugin-equalizer.xml:
+	  * docs/plugins/inspect/plugin-esdsink.xml:
+	  * docs/plugins/inspect/plugin-flac.xml:
+	  * docs/plugins/inspect/plugin-flxdec.xml:
+	  * docs/plugins/inspect/plugin-gamma.xml:
+	  * docs/plugins/inspect/plugin-gconfelements.xml:
+	  * docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	  * docs/plugins/inspect/plugin-goom.xml:
+	  * docs/plugins/inspect/plugin-goom2k1.xml:
+	  * docs/plugins/inspect/plugin-halelements.xml:
+	  * docs/plugins/inspect/plugin-icydemux.xml:
+	  * docs/plugins/inspect/plugin-id3demux.xml:
+	  * docs/plugins/inspect/plugin-jpeg.xml:
+	  * docs/plugins/inspect/plugin-level.xml:
+	  * docs/plugins/inspect/plugin-matroska.xml:
+	  * docs/plugins/inspect/plugin-monoscope.xml:
+	  * docs/plugins/inspect/plugin-mulaw.xml:
+	  * docs/plugins/inspect/plugin-multifile.xml:
+	  * docs/plugins/inspect/plugin-multipart.xml:
+	  * docs/plugins/inspect/plugin-navigationtest.xml:
+	  * docs/plugins/inspect/plugin-ossaudio.xml:
+	  * docs/plugins/inspect/plugin-png.xml:
+	  * docs/plugins/inspect/plugin-quicktime.xml:
+	  * docs/plugins/inspect/plugin-rtp.xml:
+	  * docs/plugins/inspect/plugin-rtsp.xml:
+	  * docs/plugins/inspect/plugin-smpte.xml:
+	  * docs/plugins/inspect/plugin-soup.xml:
+	  * docs/plugins/inspect/plugin-spectrum.xml:
+	  * docs/plugins/inspect/plugin-speex.xml:
+	  * docs/plugins/inspect/plugin-taglib.xml:
+	  * docs/plugins/inspect/plugin-udp.xml:
+	  * docs/plugins/inspect/plugin-video4linux2.xml:
+	  * docs/plugins/inspect/plugin-videobalance.xml:
+	  * docs/plugins/inspect/plugin-videobox.xml:
+	  * docs/plugins/inspect/plugin-videocrop.xml:
+	  * docs/plugins/inspect/plugin-videoflip.xml:
+	  * docs/plugins/inspect/plugin-videomixer.xml:
+	  * docs/plugins/inspect/plugin-wavenc.xml:
+	  * docs/plugins/inspect/plugin-wavpack.xml:
+	  * docs/plugins/inspect/plugin-wavparse.xml:
+	  * docs/plugins/inspect/plugin-ximagesrc.xml:
+	  * ext/aalib/gstaasink.c:
+	  * ext/libcaca/gstcacasink.c:
+	  Document aasink and cacasink.
+
+2008-05-28 08:36:44 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/videomixer/videomixer.*: duration and latency queries.
+	  Original commit message from CVS:
+	  * gst/videomixer/videomixer.c: (gst_videomixer_reset),
+	  (gst_videomixer_init), (gst_videomixer_query_duration),
+	  (gst_videomixer_query_latency), (gst_videomixer_query),
+	  (gst_videomixer_blend_buffers):
+	  * gst/videomixer/videomixer.h:
+	  Implement position (in time), duration and latency queries.
+
+2008-05-28 08:14:16 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/interleave/interleave.c: Implement latency query.
+	  Original commit message from CVS:
+	  * gst/interleave/interleave.c: (gst_interleave_src_query_duration),
+	  (gst_interleave_src_query_latency), (gst_interleave_src_query):
+	  Implement latency query.
+
+2008-05-27 17:55:30 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/videomixer/videomixer.*: Implement proper seek/newsegment handling.
+	  Original commit message from CVS:
+	  * gst/videomixer/videomixer.c: (gst_videomixer_reset),
+	  (gst_videomixer_init), (gst_videomixer_request_new_pad),
+	  (gst_videomixer_fill_queues), (forward_event_func),
+	  (forward_event), (gst_videomixer_src_event),
+	  (gst_videomixer_sink_event):
+	  * gst/videomixer/videomixer.h:
+	  Implement proper seek/newsegment handling.
+	  Based on adder's implementation.
+	  Fixes #535121
+
+2008-05-26 16:25:15 +0000  j^ <j@oil21.org>
+
+	  gst/qtdemux/qtdemux.c: Add caps for DVCPRO50 and DVCPRO HD PAL/NTSC. See #526481.
+	  Original commit message from CVS:
+	  Patch by: j^ <j at oil21 dot org>
+	  * gst/qtdemux/qtdemux.c: (qtdemux_video_caps):
+	  Add caps for DVCPRO50 and DVCPRO HD PAL/NTSC. See #526481.
+
+2008-05-26 15:51:41 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/audiofx/: Add simple voice removal element. Yay karaoke.
+	  Original commit message from CVS:
+	  * gst/audiofx/Makefile.am:
+	  * gst/audiofx/audiofx.c: (plugin_init):
+	  * gst/audiofx/audiovoice.c: (gst_audio_voice_base_init),
+	  (gst_audio_voice_class_init), (gst_audio_voice_init),
+	  (update_filter), (gst_audio_voice_set_property),
+	  (gst_audio_voice_get_property), (gst_audio_voice_setup),
+	  (gst_audio_voice_transform_int), (gst_audio_voice_transform_float),
+	  (gst_audio_voice_transform_ip):
+	  * gst/audiofx/audiovoice.h:
+	  Add simple voice removal element. Yay karaoke.
+
+2008-05-26 15:39:26 +0000  William M. Brack <wbrack@mmm.com.hk>
+
+	  sys/v4l2/v4l2src_calls.c: Fix potential caps leak.
+	  Original commit message from CVS:
+	  Patch by: William M. Brack <wbrack at mmm dot com dot hk>
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_probe_caps_for_format):
+	  Fix potential caps leak.
+	  If we can't get the framerate with an ioctl, try to get it with the
+	  current norm. Fixes #520092.
+
+2008-05-26 15:14:55 +0000  William M. Brack <wbrack@mmm.com.hk>
+
+	  sys/v4l2/v4l2src_calls.c: If we fail to get the frame intervals, simply don't touch the framerates on the template ca...
+	  Original commit message from CVS:
+	  Patch by: William M. Brack <wbrack at mmm dot com dot hk>
+	  * sys/v4l2/v4l2src_calls.c:
+	  (gst_v4l2src_probe_caps_for_format_and_size):
+	  If we fail to get the frame intervals, simply don't touch the framerates
+	  on the template caps instead of discarding the format. See #520092.
+
+2008-05-26 14:52:51 +0000  William M. Brack <wbrack@mmm.com.hk>
+
+	  sys/v4l2/gstv4l2src.c: Add NV12, NV21 and bayer support. See #520092.
+	  Original commit message from CVS:
+	  Patch by: William M. Brack <wbrack at mmm dot com dot hk>
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_v4l2fourcc_to_structure),
+	  (gst_v4l2_get_caps_info):
+	  Add NV12, NV21 and bayer support. See #520092.
+
+2008-05-26 13:51:38 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Unbreak segment activation again. Fixes #531672.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_find_segment),
+	  (gst_qtdemux_activate_segment):
+	  Unbreak segment activation again. Fixes #531672.
+
+2008-05-26 10:28:47 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/interleave/deinterleave.c: Add another example launch line.
+	  Original commit message from CVS:
+	  * gst/interleave/deinterleave.c:
+	  Add another example launch line.
+	  * gst/interleave/interleave.c: (interleave_24),
+	  (gst_interleave_finalize), (gst_interleave_base_init),
+	  (gst_interleave_class_init), (gst_interleave_init),
+	  (gst_interleave_request_new_pad), (gst_interleave_release_pad),
+	  (gst_interleave_change_state), (__remove_channels),
+	  (__set_channels), (gst_interleave_sink_getcaps),
+	  (gst_interleave_set_process_function),
+	  (gst_interleave_sink_setcaps), (gst_interleave_sink_event),
+	  (gst_interleave_src_query_duration), (gst_interleave_src_query),
+	  (forward_event_func), (forward_event), (gst_interleave_src_event),
+	  (gst_interleave_collected):
+	  * gst/interleave/interleave.h:
+	  Major rewrite of interleave using GstCollectpads. This new version
+	  also supports almost all raw audio formats and has better caps
+	  negotiation. Fixes bug #506594.
+	  Also update docs and add some more examples.
+	  * tests/check/elements/interleave.c: (interleave_chain_func),
+	  (GST_START_TEST), (src_handoff_float32), (sink_handoff_float32),
+	  (interleave_suite):
+	  Add some more extensive unit tests for interleave.
+
+2008-05-26 09:57:40 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  Don't use _gst_pad().
+	  Original commit message from CVS:
+	  * examples/switch/switcher.c: (switch_timer):
+	  * gst/replaygain/gstrgvolume.c: (gst_rg_volume_init):
+	  * gst/rtpmanager/gstrtpclient.c: (create_stream):
+	  * gst/sdp/gstsdpdemux.c: (gst_sdp_demux_stream_configure_udp),
+	  (gst_sdp_demux_stream_configure_udp_sink):
+	  * tests/check/elements/deinterleave.c: (GST_START_TEST),
+	  (pad_added_setup_data_check_float32_8ch_cb):
+	  * tests/check/elements/rganalysis.c: (send_eos_event),
+	  (send_tag_event):
+	  Don't use _gst_pad().
+
+2008-05-25 16:09:39 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/flac/: Set the channel layout when decoding FLAC files with more than 2 channels as defined by the FLAC spec. Fix...
+	  Original commit message from CVS:
+	  * ext/flac/Makefile.am:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_write):
+	  Set the channel layout when decoding FLAC files with more than 2
+	  channels as defined by the FLAC spec. Fixes bug #534570.
+	  Also don't try to decode left/side, right/side and mid/side files
+	  as we don't support this at all.
+
+2008-05-24 12:55:39 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: We need -base CVS (rtsp).
+	  Original commit message from CVS:
+	  * configure.ac:
+	  We need -base CVS (rtsp).
+
+2008-05-22 19:47:53 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  docs/plugins/: Add interleave/deinterleave to the docs and while at that run make update in docs/plugins.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-bad-plugins.args:
+	  * docs/plugins/gst-plugins-bad-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-bad-plugins.interfaces:
+	  * docs/plugins/gst-plugins-bad-plugins.prerequisites:
+	  * docs/plugins/gst-plugins-bad-plugins.signals:
+	  * docs/plugins/inspect/plugin-alsaspdif.xml:
+	  * docs/plugins/inspect/plugin-amrwb.xml:
+	  * docs/plugins/inspect/plugin-app.xml:
+	  * docs/plugins/inspect/plugin-bayer.xml:
+	  * docs/plugins/inspect/plugin-bz2.xml:
+	  * docs/plugins/inspect/plugin-cdaudio.xml:
+	  * docs/plugins/inspect/plugin-cdxaparse.xml:
+	  * docs/plugins/inspect/plugin-dfbvideosink.xml:
+	  * docs/plugins/inspect/plugin-dtsdec.xml:
+	  * docs/plugins/inspect/plugin-dvb.xml:
+	  * docs/plugins/inspect/plugin-dvdspu.xml:
+	  * docs/plugins/inspect/plugin-faac.xml:
+	  * docs/plugins/inspect/plugin-faad.xml:
+	  * docs/plugins/inspect/plugin-fbdevsink.xml:
+	  * docs/plugins/inspect/plugin-festival.xml:
+	  * docs/plugins/inspect/plugin-filter.xml:
+	  * docs/plugins/inspect/plugin-flvdemux.xml:
+	  * docs/plugins/inspect/plugin-freeze.xml:
+	  * docs/plugins/inspect/plugin-gsm.xml:
+	  * docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	  * docs/plugins/inspect/plugin-h264parse.xml:
+	  * docs/plugins/inspect/plugin-interleave.xml:
+	  * docs/plugins/inspect/plugin-jack.xml:
+	  * docs/plugins/inspect/plugin-ladspa.xml:
+	  * docs/plugins/inspect/plugin-metadata.xml:
+	  * docs/plugins/inspect/plugin-mms.xml:
+	  * docs/plugins/inspect/plugin-modplug.xml:
+	  * docs/plugins/inspect/plugin-mpeg2enc.xml:
+	  * docs/plugins/inspect/plugin-mpeg4videoparse.xml:
+	  * docs/plugins/inspect/plugin-mpegtsparse.xml:
+	  * docs/plugins/inspect/plugin-mpegvideoparse.xml:
+	  * docs/plugins/inspect/plugin-musepack.xml:
+	  * docs/plugins/inspect/plugin-musicbrainz.xml:
+	  * docs/plugins/inspect/plugin-mve.xml:
+	  * docs/plugins/inspect/plugin-nas.xml:
+	  * docs/plugins/inspect/plugin-neon.xml:
+	  * docs/plugins/inspect/plugin-nsfdec.xml:
+	  * docs/plugins/inspect/plugin-nuvdemux.xml:
+	  * docs/plugins/inspect/plugin-rawparse.xml:
+	  * docs/plugins/inspect/plugin-real.xml:
+	  * docs/plugins/inspect/plugin-replaygain.xml:
+	  * docs/plugins/inspect/plugin-rfbsrc.xml:
+	  * docs/plugins/inspect/plugin-sdl.xml:
+	  * docs/plugins/inspect/plugin-sdp.xml:
+	  * docs/plugins/inspect/plugin-selector.xml:
+	  * docs/plugins/inspect/plugin-sndfile.xml:
+	  * docs/plugins/inspect/plugin-soundtouch.xml:
+	  * docs/plugins/inspect/plugin-spcdec.xml:
+	  * docs/plugins/inspect/plugin-speed.xml:
+	  * docs/plugins/inspect/plugin-speexresample.xml:
+	  * docs/plugins/inspect/plugin-stereo.xml:
+	  * docs/plugins/inspect/plugin-tta.xml:
+	  * docs/plugins/inspect/plugin-vcdsrc.xml:
+	  * docs/plugins/inspect/plugin-videosignal.xml:
+	  * docs/plugins/inspect/plugin-vmnc.xml:
+	  * docs/plugins/inspect/plugin-wildmidi.xml:
+	  * docs/plugins/inspect/plugin-x264.xml:
+	  * docs/plugins/inspect/plugin-xvid.xml:
+	  * docs/plugins/inspect/plugin-y4menc.xml:
+	  Add interleave/deinterleave to the docs and while at that
+	  run make update in docs/plugins.
+	  * gst/interleave/deinterleave.c:
+	  Add a parapraph about using a queue and audioconvert after the source
+	  pads to the docs.
+
+2008-05-22 18:55:09 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/interleave/deinterleave.*: Don't set a getcaps() function on the src pads as it's not required and the default ge...
+	  Original commit message from CVS:
+	  * gst/interleave/deinterleave.c: (gst_deinterleave_base_init),
+	  (gst_deinterleave_class_init), (gst_deinterleave_init),
+	  (gst_deinterleave_add_new_pads), (gst_deinterleave_sink_getcaps):
+	  * gst/interleave/deinterleave.h:
+	  Don't set a getcaps() function on the src pads as it's not required
+	  and the default getcaps() function returns the correct results for
+	  our src pads.
+	  Complete documentation and add myself to the authors of the element.
+
+2008-05-22 14:49:08 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/udp/Makefile.am: Add -D_GNU_SOURCE to CFLAGS so we get things like EAI_ADDRFAMILY when including netdb.h when bui...
+	  Original commit message from CVS:
+	  * gst/udp/Makefile.am:
+	  Add -D_GNU_SOURCE to CFLAGS so we get things like EAI_ADDRFAMILY
+	  when including netdb.h when building against glibc >= 2.8.
+
+2008-05-22 11:19:03 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/smpte/gstsmptealpha.c: Fix debug statement arguments.
+	  Original commit message from CVS:
+	  2008-05-22  Julien Moutte  <julien@fluendo.com>
+	  * gst/smpte/gstsmptealpha.c: (gst_smpte_alpha_setcaps): Fix
+	  debug statement arguments.
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_setup_qos_dscp):
+	  * gst/udp/gstudpnetutils.c: (gst_udp_join_group),
+	  (gst_udp_leave_group): Fix IP and IPV6 options to make it work
+	  on more platforms.
+
+2008-05-21 17:51:09 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  tests/check/elements/: Don't use gst_element_get_pad(), it's a bad, bad method.
+	  Original commit message from CVS:
+	  * tests/check/elements/avimux.c: (setup_src_pad),
+	  (teardown_src_pad):
+	  * tests/check/elements/icydemux.c: (icydemux_found_pad),
+	  (GST_START_TEST):
+	  * tests/check/elements/matroskamux.c: (setup_src_pad),
+	  (teardown_src_pad), (setup_sink_pad), (teardown_sink_pad):
+	  * tests/check/elements/videocrop.c: (video_crop_get_test_caps),
+	  (GST_START_TEST):
+	  * tests/check/elements/wavpackparse.c: (wavpackparse_found_pad),
+	  (setup_wavpackparse), (cleanup_wavpackparse):
+	  Don't use gst_element_get_pad(), it's a bad, bad method.
+
+2008-05-21 17:39:38 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  Don't use gst_element_get_pad(), it's a bad method.
+	  Original commit message from CVS:
+	  * ext/gconf/gstgconfaudiosrc.c: (gst_gconf_audio_src_reset),
+	  (do_toggle_element):
+	  * ext/gconf/gstgconfvideosink.c: (gst_gconf_video_sink_reset),
+	  (do_toggle_element):
+	  * ext/gconf/gstgconfvideosrc.c: (gst_gconf_video_src_reset),
+	  (do_toggle_element):
+	  * ext/gconf/gstswitchsink.c: (gst_switch_commit_new_kid):
+	  * ext/hal/gsthalaudiosink.c: (gst_hal_audio_sink_reset),
+	  (do_toggle_element):
+	  * ext/hal/gsthalaudiosrc.c: (gst_hal_audio_src_reset),
+	  (do_toggle_element):
+	  * gst/autodetect/gstautoaudiosink.c: (gst_auto_audio_sink_reset),
+	  (gst_auto_audio_sink_detect):
+	  * gst/autodetect/gstautovideosink.c: (gst_auto_video_sink_reset),
+	  (gst_auto_video_sink_detect):
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init),
+	  (gst_rtspsrc_stream_free), (gst_rtspsrc_stream_configure_udp),
+	  (gst_rtspsrc_stream_configure_udp_sink), (gst_rtspsrc_skip_lws),
+	  (gst_rtspsrc_unskip_lws), (gst_rtspsrc_skip_commas),
+	  (gst_rtspsrc_skip_item), (gst_rtsp_decode_quoted_string),
+	  (gst_rtspsrc_parse_digest_challenge), (gst_rtspsrc_parse_auth_hdr):
+	  * tests/icles/videocrop-test.c: (test_with_caps),
+	  (video_crop_get_test_caps):
+	  Don't use gst_element_get_pad(), it's a bad method.
+
+2008-05-21 17:35:50 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/: Joining a multicast group and setting the loop/ttl properties are totally unrelated tasks are must be separ...
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_init_send),
+	  (gst_multiudpsink_add_internal):
+	  * gst/udp/gstudpnetutils.c: (gst_udp_set_loop_ttl),
+	  (gst_udp_join_group):
+	  * gst/udp/gstudpnetutils.h:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_start):
+	  Joining a multicast group and setting the loop/ttl properties are
+	  totally unrelated tasks are must be separated.
+
+2008-05-21 14:09:41 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavimux.c: Also support alaw/mulaw.
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c:
+	  Also support alaw/mulaw.
+
+2008-05-21 13:47:43 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstmultiudpsink.*: Add a fixme for the auto-multicast property.
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_class_init),
+	  (gst_multiudpsink_setup_qos_dscp), (gst_multiudpsink_add_internal):
+	  * gst/udp/gstmultiudpsink.h:
+	  Add a fixme for the auto-multicast property.
+	  Fix some confusing debug messages.
+	  Disable setting a qos value by default.
+
+2008-05-21 11:38:17 +0000  Gustaf Räntilä <g.rantila@gmail.com>
+
+	  gst/udp/gstmultiudpsink.c: Ignore EPERM errors from sendto. Fixes #533619.
+	  Original commit message from CVS:
+	  Patch by: Gustaf Räntilä <g dot rantila at gmail dot com>
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_render):
+	  Ignore EPERM errors from sendto. Fixes #533619.
+
+2008-05-21 10:51:52 +0000  Henrik Eriksson <henriken@axis.com>
+
+	  gst/udp/gstmultiudpsink.*: Add qos-dscp property to manage the Quality of service.
+	  Original commit message from CVS:
+	  Patch by: Henrik Eriksson <henriken at axis dot com>
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_class_init),
+	  (gst_multiudpsink_init), (gst_multiudpsink_setup_qos_dscp),
+	  (gst_multiudpsink_set_property), (gst_multiudpsink_get_property),
+	  (gst_multiudpsink_init_send), (gst_multiudpsink_add_internal):
+	  * gst/udp/gstmultiudpsink.h:
+	  Add qos-dscp property to manage the Quality of service.
+
+2008-05-21 10:09:23 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtptheoradepay.c: Improve debugging of the ident.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtptheoradepay.c: (gst_rtp_theora_depay_process):
+	  Improve debugging of the ident.
+
+2008-05-21 09:56:02 +0000  Bruno Santos <brunof@ua.pt>
+
+	  gst/udp/gstudpnetutils.*: Provide a bunch of helper methods to deal with IPv4 and IPv6 transparently.
+	  Original commit message from CVS:
+	  Patch by: Bruno Santos <brunof at ua dot pt>
+	  * gst/udp/gstudpnetutils.c: (gst_udp_get_addr),
+	  (gst_udp_join_group), (gst_udp_leave_group),
+	  (gst_udp_is_multicast):
+	  * gst/udp/gstudpnetutils.h:
+	  Provide a bunch of helper methods to deal with IPv4 and IPv6
+	  transparently.
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_class_init),
+	  (gst_multiudpsink_init), (gst_multiudpsink_set_property),
+	  (gst_multiudpsink_get_property), (join_multicast),
+	  (gst_multiudpsink_init_send), (gst_multiudpsink_add_internal),
+	  (gst_multiudpsink_remove):
+	  * gst/udp/gstmultiudpsink.h:
+	  Add multicast TTL and loopback properties.
+	  Use the helper methods to implement ip4 and ip6.
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_create), (gst_udpsrc_start):
+	  * gst/udp/gstudpsrc.h:
+	  Use the helper methods to implement ip4 and ip6.
+	  Fixes #515962.
+
+2008-05-21 09:38:48 +0000  Patrick Radizi <patrick.radizi@axis.com>
+
+	  gst/multipart/multipartdemux.*: Don't blindly copy the mime-type as the caps name because they not always map directl...
+	  Original commit message from CVS:
+	  Patch by: Patrick Radizi <patrick dot radizi at axis dot com>
+	  * gst/multipart/multipartdemux.c: (gst_multipart_demux_class_init),
+	  (gst_multipart_demux_get_gstname),
+	  (gst_multipart_find_pad_by_mime), (gst_multipart_demux_chain):
+	  * gst/multipart/multipartdemux.h:
+	  Don't blindly copy the mime-type as the caps name because they not
+	  always map directly. Instead use a hashtable with common mappings.
+	  Fixes #533287.
+
+2008-05-20 17:27:35 +0000  Michael Meeks <mmeeks@ximian.org>
+
+	  ext/esd/esdsink.c: When we post an error, we must return -1 to let the parent know that we cannot write the segment e...
+	  Original commit message from CVS:
+	  * ext/esd/esdsink.c: (gst_esdsink_write):
+	  When we post an error, we must return -1 to let the parent know that we
+	  cannot write the segment else it will loop and continue to call us again
+	  forever. Patch by Michael Meeks.
+
+2008-05-20 14:24:21 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/videomixer/videomixer.c: Add missing incudes.
+	  Original commit message from CVS:
+	  * gst/videomixer/videomixer.c:
+	  Add missing incudes.
+
+2008-05-20 13:57:44 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtp/gstrtph264pay.*: Correct a typo (sinle -> single).
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph264pay.c: (gst_h264_scan_mode_get_type),
+	  (gst_rtp_h264_pay_handle_buffer):
+	  * gst/rtp/gstrtph264pay.h:
+	  Correct a typo (sinle -> single).
+
+2008-05-20 11:33:05 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtph264depay.*: Add experimental support for outputting quicktime-like AVC output in addition to the exist...
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_class_init),
+	  (gst_rtp_h264_depay_init), (gst_rtp_h264_depay_set_property),
+	  (gst_rtp_h264_depay_get_property), (gst_rtp_h264_depay_setcaps),
+	  (gst_rtp_h264_depay_process):
+	  * gst/rtp/gstrtph264depay.h:
+	  Add experimental support for outputting quicktime-like AVC output in
+	  addition to the existing bytestream output.
+	  * gst/rtp/gstrtph264pay.c: (gst_h264_scan_mode_get_type),
+	  (gst_rtp_h264_pay_class_init), (gst_rtp_h264_pay_init),
+	  (gst_rtp_h264_pay_setcaps), (gst_rtp_h264_pay_payload_nal),
+	  (gst_rtp_h264_pay_handle_buffer), (gst_rtp_h264_pay_set_property),
+	  (gst_rtp_h264_pay_get_property):
+	  * gst/rtp/gstrtph264pay.h:
+	  Make the parsing mode configurable, for some inputs we don't need to
+	  scan every byte for start codes.
+	  Only set the marker bit on ACCESS units.
+
+2008-05-20 10:47:10 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/equalizer/gstiirequalizer.c: Use a bigger type in integer mode for the intermediate results to prevent overflows....
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer.c:
+	  Use a bigger type in integer mode for the intermediate results to
+	  prevent overflows. This fixes the crippled sound when using the
+	  equalizer in integer mode. Fixes bug #510865.
+
+2008-05-20 10:42:33 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/videomixer/videomixer.*: Instead of a random number for the request pad id's, use a counter.
+	  Original commit message from CVS:
+	  * gst/videomixer/videomixer.c:
+	  * gst/videomixer/videomixer.h:
+	  Instead of a random number for the request pad id's,
+	  use a counter.
+	  Register the videomixerpad class from the element's class_init
+	  where it's safer, and allows the docs generator to scan it.
+
+2008-05-20 09:29:28 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/smpte/: Add new plugin that adds the SMPTE transition in the alpha channel of
+	  Original commit message from CVS:
+	  * gst/smpte/Makefile.am:
+	  * gst/smpte/gstsmpte.c: (gst_smpte_plugin_init):
+	  * gst/smpte/gstsmpte.h:
+	  * gst/smpte/gstsmptealpha.c:
+	  (gst_smpte_alpha_transition_type_get_type),
+	  (gst_smpte_alpha_get_type), (gst_smpte_alpha_base_init),
+	  (gst_smpte_alpha_class_init), (gst_smpte_alpha_update_mask),
+	  (gst_smpte_alpha_setcaps), (gst_smpte_alpha_get_unit_size),
+	  (gst_smpte_alpha_init), (gst_smpte_alpha_finalize),
+	  (gst_smpte_alpha_do_ayuv), (gst_smpte_alpha_do_i420),
+	  (gst_smpte_alpha_transform), (gst_smpte_alpha_set_property),
+	  (gst_smpte_alpha_get_property), (gst_smpte_alpha_plugin_init):
+	  * gst/smpte/gstsmptealpha.h:
+	  * gst/smpte/plugin.c: (plugin_init):
+	  Add new plugin that adds the SMPTE transition in the alpha channel of
+	  I420 and AYUV frames so that they can be blended with videomixer later
+	  on. Uses all niceties such as using base transform for efficient alloc
+	  and negotiation. It currently requires GstController to control the
+	  position in the transition effect.
+
+2008-05-19 21:05:03 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Try using thaytans new mechanism to get extra classes into plugin docs. Aparently works for the Eq. For VideoMixer th...
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * 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.types:
+	  * gst/videomixer/videomixer.c:
+	  Try using thaytans new mechanism to get extra classes into plugin
+	  docs. Aparently works for the Eq. For VideoMixer the GObject stuff is
+	  missing still.
+
+2008-05-19 12:32:06 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/deinterleave.c: Set keep-positions property to TRUE for the 8 channel test to ensure that the or...
+	  Original commit message from CVS:
+	  * tests/check/elements/deinterleave.c: (GST_START_TEST):
+	  Set keep-positions property to TRUE for the 8 channel test to ensure
+	  that the original channel position is set on the output.
+
+2008-05-19 07:46:05 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/interleave/deinterleave.*: Add a property to select whether channel positions should be kept on the mono output b...
+	  Original commit message from CVS:
+	  * gst/interleave/deinterleave.c: (gst_deinterleave_class_init),
+	  (gst_deinterleave_init), (gst_deinterleave_add_new_pads),
+	  (gst_deinterleave_set_pads_caps), (gst_deinterleave_set_property),
+	  (gst_deinterleave_get_property):
+	  * gst/interleave/deinterleave.h:
+	  Add a property to select whether channel positions should be kept on
+	  the mono output buffers or should be dropped.
+
+2008-05-18 19:27:59 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/avi/gstavimux.c: Set proper rate in avi stream header for PCM audio, and also do some more sanity checks on caps ...
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c: (gst_avi_mux_audsink_set_caps):
+	  Set proper rate in avi stream header for PCM audio, and also do some
+	  more sanity checks on caps in this case.  Fixes #511489.
+
+2008-05-17 19:39:53 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/interleave/deinterleave.*: Queue events until src pads were added and they can be sent. Otherwise downstream will...
+	  Original commit message from CVS:
+	  * gst/interleave/deinterleave.c: (gst_deinterleave_finalize),
+	  (gst_deinterleave_init), (gst_deinterleave_sink_event),
+	  (gst_deinterleave_process), (gst_deinterleave_sink_activate_push):
+	  * gst/interleave/deinterleave.h:
+	  Queue events until src pads were added and they can be sent. Otherwise
+	  downstream will never get the first newsegment event.
+
+2008-05-17 14:05:03 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/interleave/deinterleave.c: Always set the channel positions when gst_audio_get_channel_positions() returns someth...
+	  Original commit message from CVS:
+	  * gst/interleave/deinterleave.c: (gst_deinterleave_sink_setcaps),
+	  (gst_deinterleave_getcaps):
+	  Always set the channel positions when gst_audio_get_channel_positions()
+	  returns something, even if they're not set in the caps. This makes
+	  sure that the output channels can be interleaved again correctly
+	  in the mono/stereo cases too.
+	  Don't ask for the peercaps of the current pad in getcaps() as this
+	  might call getcaps() again and deadlock.
+
+2008-05-17 10:38:18 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  sys/v4l2/gstv4l2src.c: Don't include the gstv4l2xoverlay.h header as the XOverlay support isn't implemented at all ye...
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c:
+	  Don't include the gstv4l2xoverlay.h header as the XOverlay support
+	  isn't implemented at all yet and this requires X headers to be
+	  installed. Fixes bug #533264.
+
+2008-05-16 21:56:24 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/interleave/: Add support for all raw audio formats and provide better negotiation if the caps are changing.
+	  Original commit message from CVS:
+	  * gst/interleave/Makefile.am:
+	  * gst/interleave/deinterleave.c: (deinterleave_24),
+	  (gst_deinterleave_finalize), (gst_deinterleave_base_init),
+	  (gst_deinterleave_class_init), (gst_deinterleave_init),
+	  (gst_deinterleave_add_new_pads), (gst_deinterleave_set_pads_caps),
+	  (gst_deinterleave_set_process_function),
+	  (gst_deinterleave_sink_setcaps), (__remove_channels),
+	  (__set_channels), (gst_deinterleave_getcaps),
+	  (gst_deinterleave_process), (gst_deinterleave_chain),
+	  (gst_deinterleave_sink_activate_push):
+	  * gst/interleave/deinterleave.h:
+	  Add support for all raw audio formats and provide better negotiation
+	  if the caps are changing.
+	  Don't allow changes of the channel positions and set the position of
+	  the corresponding channel on the src pad caps.
+	  General cleanup and smaller bugfixes.
+	  * tests/check/elements/deinterleave.c: (float_buffer_check_probe):
+	  Check the channel positions on the output buffer caps.
+
+2008-05-16 17:50:20 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Fix some compiler warnings.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackstreamreader.c:
+	  * tests/examples/spectrum/demo-audiotest.c:
+	  * tests/examples/spectrum/demo-osssrc.c:
+	  Fix some compiler warnings.
+
+2008-05-14 18:28:46 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtph264depay.c: Small comment added.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_process):
+	  Small comment added.
+	  * gst/rtp/gstrtph264pay.c: (gst_rtp_h264_pay_class_init),
+	  (gst_rtp_h264_pay_decode_nal), (gst_rtp_h264_pay_parse_sps_pps),
+	  (gst_rtp_h264_pay_payload_nal), (gst_rtp_h264_pay_handle_buffer):
+	  Debug string cleanups (remove trailing \n)
+	  Refactor and clean up the payloader a bit and make sure that we only
+	  put one NAL unit in an RTP packet even if the input buffer contains
+	  multiple NAL units.
+	  Add suport for AVC format input.
+
+2008-05-14 17:58:50 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtp/gstrtph264pay.*: Make it possible to specify profile-level-id and sprop-parameter-sets using properties in ca...
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph264pay.c: (gst_rtp_h264_pay_class_init),
+	  (gst_rtp_h264_pay_finalize), (gst_rtp_h264_pay_handle_buffer),
+	  (gst_rtp_h264_pay_set_property), (gst_rtp_h264_pay_get_property):
+	  * gst/rtp/gstrtph264pay.h:
+	  Make it possible to specify profile-level-id and sprop-parameter-sets
+	  using properties in case they are not available in-stream.
+
+2008-05-14 14:19:47 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/check/Makefile.am: Add deinterleave unit test to VALGRIND_TO_FIX, since it causes weird invalid free errors in ...
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Add deinterleave unit test to VALGRIND_TO_FIX, since it causes
+	  weird invalid free errors in valgrind/libc after _exit for some
+	  reason.
+	  * tests/check/elements/deinterleave.c: (pads_created),
+	  (set_channel_positions), (src_handoff_float32_8ch),
+	  (float_buffer_check_probe),
+	  (pad_added_setup_data_check_float32_8ch_cb),
+	  (make_fake_src_8chans_float32), (GST_START_TEST),
+	  (deinterleave_suite):
+	  Add some more deinterleave unit test bits I had locally.
+
+2008-05-14 12:52:15 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/: Remove ladspa fro plugin-docs, its in gst-plugins-bad.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/inspect/plugin-ladspa.xml:
+	  Remove ladspa fro plugin-docs, its in gst-plugins-bad.
+
+2008-05-14 07:32:44 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/interleave/: Split definitions into separate header files for better documentation generation.
+	  Original commit message from CVS:
+	  * gst/interleave/Makefile.am:
+	  * gst/interleave/deinterleave.h:
+	  * gst/interleave/interleave.h:
+	  * gst/interleave/plugin.h:
+	  Split definitions into separate header files for better documentation
+	  generation.
+	  * gst/interleave/deinterleave.c: (gst_deinterleave_base_init),
+	  (gst_deinterleave_class_init), (gst_deinterleave_sink_setcaps),
+	  (gst_deinterleave_process):
+	  Don't use alloca, allow caps changes as long as the number of channels
+	  does not change, don't use g_warning, return NOT_NEGOTIATED as early
+	  as possible and some other cleanup.
+	  * gst/interleave/interleave.c: (gst_interleave_base_init),
+	  (gst_interleave_class_init):
+	  Do some random cleanup.
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/deinterleave.c: (GST_START_TEST),
+	  (deinterleave_chain_func), (deinterleave_pad_added),
+	  (deinterleave_suite):
+	  Add unit tests for the deinterleave element.
+
+2008-05-13 20:25:20 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/avi/gstavimux.c: Send an initial BYTE segment to inform downstream of later seeking, and to forego sync attempts.
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c: (gst_avi_mux_start_file):
+	  Send an initial BYTE segment to inform downstream of later seeking,
+	  and to forego sync attempts.
+
+2008-05-13 08:59:41 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpg729depay.c: Fix wrong caps string.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpg729depay.c: (gst_rtp_g729_depay_setcaps):
+	  Fix wrong caps string.
+
+2008-05-13 08:35:55 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtp/: Added G729 pay and depayloaders. Fixes #532409.
+	  Original commit message from CVS:
+	  Based on patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpg729depay.c: (gst_rtp_g729_depay_base_init),
+	  (gst_rtp_g729_depay_class_init), (gst_rtp_g729_depay_init),
+	  (gst_rtp_g729_depay_setcaps), (gst_rtp_g729_depay_process),
+	  (gst_rtp_g729_depay_plugin_init):
+	  * gst/rtp/gstrtpg729depay.h:
+	  * gst/rtp/gstrtpg729pay.c: (gst_rtpg729pay_base_init),
+	  (gst_rtpg729pay_class_init), (gst_rtpg729pay_init),
+	  (gst_rtpg729pay_setcaps), (gst_rtp_g729_pay_plugin_init):
+	  * gst/rtp/gstrtpg729pay.h:
+	  Added G729 pay and depayloaders. Fixes #532409.
+
+2008-05-13 08:21:26 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/speex/gstspeexdec.c: Fix the calculation of the duration of the concealment packets.
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexdec.c: (speex_dec_sink_event):
+	  Fix the calculation of the duration of the concealment packets.
+
+2008-05-12 18:27:24 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtp/: Add DV pay and depayloaders. Fixes #532423.
+	  Original commit message from CVS:
+	  Based on patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpdvdepay.c: (gst_rtp_dv_depay_base_init),
+	  (gst_rtp_dv_depay_class_init), (gst_rtp_dv_depay_init),
+	  (parse_encode), (gst_rtp_dv_depay_setcaps),
+	  (calculate_difblock_location), (gst_rtp_dv_depay_process),
+	  (gst_rtp_dv_depay_reset), (gst_rtp_dv_depay_change_state),
+	  (gst_rtp_dv_depay_plugin_init):
+	  * gst/rtp/gstrtpdvdepay.h:
+	  * gst/rtp/gstrtpdvpay.c: (gst_dv_pay_mode_get_type),
+	  (gst_rtp_dv_pay_base_init), (gst_rtp_dv_pay_class_init),
+	  (gst_rtp_dv_pay_init), (gst_dv_pay_set_property),
+	  (gst_dv_pay_get_property), (gst_rtp_dv_pay_setcaps),
+	  (gst_dv_pay_negotiate), (include_dif),
+	  (gst_rtp_dv_pay_handle_buffer), (gst_rtp_dv_pay_plugin_init):
+	  * gst/rtp/gstrtpdvpay.h:
+	  Add DV pay and depayloaders. Fixes #532423.
+
+2008-05-12 16:35:39 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/matroska/matroska-demux.c: Convert subtitle palette info in VobSub private data from VobSub's (buggy) RGB to YUV.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_push_dvd_clut_change_event):
+	  Convert subtitle palette info in VobSub private data from VobSub's
+	  (buggy) RGB to YUV.
+
+2008-05-12 15:26:01 +0000  Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+
+	  gst/avi/gstavimux.c: Do not leave fourcc stream header field empty upon reset.
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c: (gst_avi_mux_pad_reset):
+	  Do not leave fourcc stream header field empty upon reset.
+	  Fixes #519301.
+
+2008-05-11 14:43:26 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Add goom2k1 into the docs.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/inspect/plugin-goom.xml:
+	  * docs/plugins/inspect/plugin-goom2k1.xml:
+	  * gst/goom/gstgoom.c:
+	  * gst/goom2k1/gstgoom.c:
+	  Add goom2k1 into the docs.
+
+2008-05-08 16:58:02 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  gst/rtsp/gstrtspsrc.c: Support Digest authentication. Fixes #532065.
+	  Original commit message from CVS:
+	  Based on patch by: Wouter Cloetens  <wouter at mind be>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init),
+	  (gst_rtspsrc_skip_lws), (gst_rtspsrc_unskip_lws),
+	  (gst_rtspsrc_skip_commas), (gst_rtspsrc_skip_item),
+	  (gst_rtsp_decode_quoted_string),
+	  (gst_rtspsrc_parse_digest_challenge), (gst_rtspsrc_parse_auth_hdr),
+	  (gst_rtspsrc_setup_auth):
+	  Support Digest authentication. Fixes #532065.
+
+2008-05-08 10:20:52 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/level/gstlevel.c: Also support 32bit (e.g. whe having it after 'mad'). Add more notes about whats needed for libo...
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c:
+	  Also support 32bit (e.g. whe having it after 'mad'). Add more notes
+	  about whats needed for liboil acceleration. Simplify docs a bit.
+
+2008-05-08 08:15:34 +0000  Sjoerd Simons <sjoerd@luon.net>
+
+	  gst/matroska/matroska-mux.c: Update the track duration if the old one was invalid.
+	  Original commit message from CVS:
+	  Patch by: Sjoerd Simons <sjoerd at luon dot net>
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_collected):
+	  Update the track duration if the old one was invalid.
+	  Fixes bug #532117.
+
+2008-05-07 16:36:04 +0000  Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+
+	  gst/rtp/gstrtph264pay.c (gst_rtp_h264_pay_parse_sps_pps): Use GST_STR_NULL when trying to print sps and pps strings t...
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph264pay.c (gst_rtp_h264_pay_parse_sps_pps):
+	  Use GST_STR_NULL when trying to print sps and pps strings that could
+	  be NULL, as this might crash on some platforms.
+
+2008-05-07 15:33:52 +0000  Haakon Sporsheim <haakon.sporsheim@tandberg.com>
+
+	  sys/directdraw/gstdirectdrawsink.c (gst_directdraw_sink_setup_ddraw): Do IDirectDrawClipper_SetHWnd() if the window I...
+	  Original commit message from CVS:
+	  patch by: Haakon Sporsheim <haakon.sporsheim at tandberg com>
+	  * sys/directdraw/gstdirectdrawsink.c (gst_directdraw_sink_setup_ddraw):
+	  Do IDirectDrawClipper_SetHWnd() if the window ID has already been
+	  set after creating the clipper.
+
+2008-05-07 15:28:06 +0000  Haakon Sporsheim <haakon.sporsheim@tandberg.com>
+
+	  sys/directdraw/gstdirectdrawsink.c (gst_directdraw_sink_show_frame): Added checking of surface lost case after an uns...
+	  Original commit message from CVS:
+	  patch by: Haakon Sporsheim <haakon.sporsheim at tandberg com>
+	  * sys/directdraw/gstdirectdrawsink.c (gst_directdraw_sink_show_frame):
+	  Added checking of surface lost case after an unsuccessful
+	  IDirectDrawSurface7_Lock() call.
+	  If surface is lost, return GST_FLOW_OK.
+
+2008-05-07 15:19:47 +0000  Haakon Sporsheim <haakon.sporsheim@tandberg.com>
+
+	* ChangeLog:
+	* sys/directdraw/gstdirectdrawsink.c:
+	  sys/directdraw/gstdirectdrawsink.c (gst_directdraw_sink_show_frame,
+	  Original commit message from CVS:
+	  patch by: Haakon Sporsheim <haakon.sporsheim at tandberg com>
+	  * sys/directdraw/gstdirectdrawsink.c (gst_directdraw_sink_show_frame,
+	  WndProc, gst_directdraw_sink_window_thread):
+	  Improved Windows message loop and fixed window destruction issue.
+	  When the window which DirectDraw is rendering to is destroyed, the
+	  render/show_frame function will return GST_FLOW_ERROR.
+	  Partially fixes #520885.
+
+2008-05-07 15:09:10 +0000  Haakon Sporsheim <haakon.sporsheim@tandberg.com>
+
+	  sys/directdraw/gstdirectdrawsink.c (gst_directdraw_sink_set_caps): Fixed mid stream resolution change bug, the offscr...
+	  Original commit message from CVS:
+	  patch by: Haakon Sporsheim <haakon.sporsheim at tandberg com>
+	  * sys/directdraw/gstdirectdrawsink.c (gst_directdraw_sink_set_caps):
+	  Fixed mid stream resolution change bug, the offscreen surface is now
+	  released when set_caps is called.
+	  Partially fixes #520885.
+
+2008-05-07 14:56:22 +0000  Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+
+	* ChangeLog:
+	* sys/directdraw/gstdirectdrawsink.c:
+	  sys/directdraw/gstdirectdrawsink.c
+	  Original commit message from CVS:
+	  * sys/directdraw/gstdirectdrawsink.c
+	  (gst_directdraw_sink_buffer_alloc):
+	  Make it so that gst_directdraw_sink_buffer_alloc uses the right
+	  width/height.
+	  Especially when looking through the pool of buffers, make sure that
+	  the width/height of caps is used instead of the already negotiated
+	  dimensions.
+	  For example if a buffer with different caps is requested, i.e.
+	  higher resolution, the caller would get a buffer with the old
+	  dimensions and thus corrupt the heap.
+
+2008-05-07 14:43:39 +0000  Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+
+	* sys/directdraw/gstdirectdrawsink.c:
+	  sys/directdraw/gstdirectdrawsink.c
+	  Original commit message from CVS:
+	  * sys/directdraw/gstdirectdrawsink.c
+	  (gst_directdraw_sink_buffer_alloc):
+	  Clear the flags on recycled buffers from buffer_alloc.
+	  Partially fixes #520885.
+	  The right fix this time.
+
+2008-05-07 14:39:45 +0000  Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+
+	* sys/directdraw/gstdirectdrawsink.c:
+	  sys/directdraw/gstdirectdrawsink.c
+	  Original commit message from CVS:
+	  * sys/directdraw/gstdirectdrawsink.c
+	  (gst_directdraw_sink_buffer_alloc):
+	  Reverting previous commit, it had it all mixed up, was for a different
+	  patch (major automation screw-up). Sorry!
+
+2008-05-07 13:48:28 +0000  Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+
+	* ChangeLog:
+	* sys/directdraw/gstdirectdrawsink.c:
+	  sys/directdraw/gstdirectdrawsink.c
+	  Original commit message from CVS:
+	  * sys/directdraw/gstdirectdrawsink.c
+	  (gst_directdraw_sink_buffer_alloc):
+	  Clear the flags on recycled buffers from buffer_alloc.
+	  Partially fixes #520885.
+
+2008-05-07 11:22:51 +0000  Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+
+	  gst/rtp/gstrtpilbcpay.c: Added missing stdlib.h include for strtol(), and made include ordering and style consistent ...
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpilbcpay.c:
+	  Added missing stdlib.h include for strtol(), and made include ordering and
+	  style consistent with the corresponding depayloader.
+
+2008-05-07 09:52:34 +0000  Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+
+	  gst/rtp/gstrtpilbcpay.c: Added missing stdlib.h include for strtol(), and made include ordering and style consistent ...
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpilbcpay.c:
+	  Added missing stdlib.h include for strtol(), and made include ordering and
+	  style consistent with the corresponding depayloader.
+
+2008-05-07 08:03:51 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Error out if we don't have the required core/base versions.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Error out if we don't have the required core/base versions.
+
+2008-05-06 09:33:46 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  sys/osxvideo/cocoawindow.m: Fix compiler warnings on PPC64. Fixes bug #499318.
+	  Original commit message from CVS:
+	  Patch by: Thijs Vermeir <thijsvermeir at gmail dot com>
+	  * sys/osxvideo/cocoawindow.m:
+	  Fix compiler warnings on PPC64. Fixes bug #499318.
+
+2008-05-05 11:19:13 +0000  Sjoerd Simons <sjoerd@luon.net>
+
+	  gst/rtsp/gstrtspsrc.c: Don't leak file descriptors on error. Fixes #531532.
+	  Original commit message from CVS:
+	  Patch by: Sjoerd Simons <sjoerd at luon dot net>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init), (gst_rtspsrc_open):
+	  Don't leak file descriptors on error. Fixes #531532.
+
+2008-05-03 09:18:22 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/gconf/: When we can't create a fakesink/fakesrc complain instead of unreffing
+	  Original commit message from CVS:
+	  * ext/gconf/gstgconfaudiosrc.c: (gst_gconf_audio_src_reset),
+	  (gst_gconf_audio_src_change_state):
+	  * ext/gconf/gstgconfvideosink.c: (gst_gconf_video_sink_reset),
+	  (gst_gconf_video_sink_change_state):
+	  * ext/gconf/gstgconfvideosrc.c: (gst_gconf_video_src_reset),
+	  (gst_gconf_video_src_change_state):
+	  * ext/gconf/gstswitchsink.c: (gst_switch_sink_reset),
+	  (gst_switch_commit_new_kid), (gst_switch_sink_change_state):
+	  When we can't create a fakesink/fakesrc complain instead of unreffing
+	  NULL pointers and crashing later. See bug #530535.
+
+2008-05-02 12:44:18 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtph263pdepay.c: Add some more debug info and guard against small payloads.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph263pdepay.c: (gst_rtp_h263p_depay_process):
+	  Add some more debug info and guard against small payloads.
+	  * gst/rtp/gstrtppcmudepay.c: (gst_rtp_pcmu_depay_process):
+	  Set duration on outgoing buffers because we can.
+
+2008-05-02 12:39:03 +0000  Olivier Crete <tester@tester.ca>
+
+	  ext/speex/gstspeexenc.c: Add negotiation for the speex channels and rate. Fixes #465146.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * ext/speex/gstspeexenc.c: (gst_speex_enc_sink_getcaps),
+	  (gst_speex_enc_init), (gst_speex_enc_chain):
+	  Add negotiation for the speex channels and rate. Fixes #465146.
+
+2008-05-02 12:34:22 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtp/gstrtpspeexpay.c: Add negotiation for the speec channels and rate. See #465146.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtp/gstrtpspeexpay.c: (gst_rtp_speex_pay_class_init),
+	  (gst_rtp_speex_pay_getcaps):
+	  Add negotiation for the speec channels and rate. See #465146.
+
+2008-05-02 12:24:55 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtp/gstrtpilbcpay.c: Add negotiation for the ILBC mode. See #465146.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtp/gstrtpilbcpay.c: (gst_rtpilbcpay_class_init),
+	  (gst_rtpilbcpay_sink_setcaps), (gst_rtpilbcpay_sink_getcaps):
+	  Add negotiation for the ILBC mode. See #465146.
+
+2008-05-02 11:32:31 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/soup/gstsouphttpsrc.c: Include stdlib to fix the build. Use g_free instead of free, libsoup uses glib.
+	  Original commit message from CVS:
+	  * ext/soup/gstsouphttpsrc.c:
+	  Include stdlib to fix the build. Use g_free instead of free, libsoup
+	  uses glib.
+
+2008-05-02 09:09:58 +0000  j^ <j@bootlab.org>
+
+	  gst/qtdemux/qtdemux.c: Add more mpeg2 variants. Fixes #530886.
+	  Original commit message from CVS:
+	  Patch by: j^ <j@bootlab.org>
+	  * gst/qtdemux/qtdemux.c: (qtdemux_video_caps):
+	  Add more mpeg2 variants. Fixes #530886.
+
+2008-05-01 10:52:11 +0000  Youness Alaoui <youness.alaoui@collabora.co.uk>
+
+	  gst/udp/gstudpsrc.c: Don't error out if we get an ICMP destination-unreachable message when trying to read packets on...
+	  Original commit message from CVS:
+	  Patch by: Youness Alaoui <youness.alaoui at collabora co uk>
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_create):
+	  Don't error out if we get an ICMP destination-unreachable
+	  message when trying to read packets on win32 (#529454).
+
+2008-04-30 12:18:41 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Use new error code for encrypted streams (which requires core CVS).
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_trak):
+	  Use new error code for encrypted streams (which requires core CVS).
+
+2008-04-30 12:10:02 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Fix swapped pad template names, spotted by Thiago Sousa Santos.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_videosrc_template),
+	  (gst_qtdemux_audiosrc_template):
+	  Fix swapped pad template names, spotted by Thiago Sousa Santos.
+
+2008-04-30 09:48:11 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/speex/gstspeexdec.c: Produce concealment data when time progresses in a segment update.
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexdec.c: (speex_dec_sink_event),
+	  (speex_dec_chain_parse_data):
+	  Produce concealment data when time progresses in a segment update.
+
+2008-04-29 14:11:45 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/speex/gstspeexdec.c: Try to preserve input timestamps when we can.
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexdec.c: (speex_dec_chain_parse_data),
+	  (speex_dec_chain):
+	  Try to preserve input timestamps when we can.
+	  Do beginnings of error concealment.
+
+2008-04-28 22:38:11 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/debug/gstnavigationtest.c: MSVC doesn't provide rint(), define an adequate replacement locally as elsewhere.
+	  Original commit message from CVS:
+	  * gst/debug/gstnavigationtest.c:
+	  MSVC doesn't provide rint(), define an adequate replacement locally as
+	  elsewhere.
+
+2008-04-28 11:16:32 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/debug/rndbuffersize.c: Fix printf format to pacify Mac OSX's gcc.
+	  Original commit message from CVS:
+	  2008-04-28  Julien Moutte  <julien@fluendo.com>
+	  * gst/debug/rndbuffersize.c: (gst_rnd_buffer_size_loop): Fix printf
+	  format to pacify Mac OSX's gcc.
+
+2008-04-25 19:34:31 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/debug/rndbuffersize.c: Bring rndbuffersize element into a state that doesn't require us to move it to -bad immedi...
+	  Original commit message from CVS:
+	  * gst/debug/rndbuffersize.c: (DEFAULT_SEED), (DEFAULT_MIN),
+	  (DEFAULT_MAX), (src_template), (sink_template),
+	  (gst_rnd_buffer_size_base_init), (gst_rnd_buffer_size_class_init),
+	  (gst_rnd_buffer_size_init), (gst_rnd_buffer_size_activate),
+	  (gst_rnd_buffer_size_loop), (gst_rnd_buffer_size_plugin_init):
+	  Bring rndbuffersize element into a state that doesn't require us
+	  to move it to -bad immediately. For one, fix up default min/max
+	  values so that the element actuall works using the default values.
+	  Also, don't ignore flow return values and do some kind of minimal
+	  eos logic. Allow min=max to pull fixed-sized buffers. Bunch of
+	  other gratuitious clean-ups.
+
+2008-04-25 19:24:00 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  docs/plugins/: Add docs for gdkpixbufsink; update docs to CVS version.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * 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:
+	  * docs/plugins/inspect/plugin-1394.xml:
+	  * docs/plugins/inspect/plugin-aasink.xml:
+	  * docs/plugins/inspect/plugin-alaw.xml:
+	  * docs/plugins/inspect/plugin-alpha.xml:
+	  * docs/plugins/inspect/plugin-alphacolor.xml:
+	  * docs/plugins/inspect/plugin-annodex.xml:
+	  * docs/plugins/inspect/plugin-apetag.xml:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  * docs/plugins/inspect/plugin-auparse.xml:
+	  * docs/plugins/inspect/plugin-autodetect.xml:
+	  * docs/plugins/inspect/plugin-avi.xml:
+	  * docs/plugins/inspect/plugin-cacasink.xml:
+	  * docs/plugins/inspect/plugin-cairo.xml:
+	  * docs/plugins/inspect/plugin-cdio.xml:
+	  * docs/plugins/inspect/plugin-cutter.xml:
+	  * docs/plugins/inspect/plugin-debug.xml:
+	  * docs/plugins/inspect/plugin-dv.xml:
+	  * docs/plugins/inspect/plugin-efence.xml:
+	  * docs/plugins/inspect/plugin-effectv.xml:
+	  * docs/plugins/inspect/plugin-equalizer.xml:
+	  * docs/plugins/inspect/plugin-esdsink.xml:
+	  * docs/plugins/inspect/plugin-flac.xml:
+	  * docs/plugins/inspect/plugin-flxdec.xml:
+	  * docs/plugins/inspect/plugin-gamma.xml:
+	  * docs/plugins/inspect/plugin-gconfelements.xml:
+	  * docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	  * docs/plugins/inspect/plugin-goom.xml:
+	  * docs/plugins/inspect/plugin-halelements.xml:
+	  * docs/plugins/inspect/plugin-icydemux.xml:
+	  * docs/plugins/inspect/plugin-id3demux.xml:
+	  * docs/plugins/inspect/plugin-jpeg.xml:
+	  * docs/plugins/inspect/plugin-level.xml:
+	  * docs/plugins/inspect/plugin-matroska.xml:
+	  * docs/plugins/inspect/plugin-monoscope.xml:
+	  * docs/plugins/inspect/plugin-mulaw.xml:
+	  * docs/plugins/inspect/plugin-multifile.xml:
+	  * docs/plugins/inspect/plugin-multipart.xml:
+	  * docs/plugins/inspect/plugin-navigationtest.xml:
+	  * docs/plugins/inspect/plugin-ossaudio.xml:
+	  * docs/plugins/inspect/plugin-png.xml:
+	  * docs/plugins/inspect/plugin-quicktime.xml:
+	  * docs/plugins/inspect/plugin-rtp.xml:
+	  * docs/plugins/inspect/plugin-rtsp.xml:
+	  * docs/plugins/inspect/plugin-shout2send.xml:
+	  * docs/plugins/inspect/plugin-smpte.xml:
+	  * docs/plugins/inspect/plugin-spectrum.xml:
+	  * docs/plugins/inspect/plugin-speex.xml:
+	  * docs/plugins/inspect/plugin-taglib.xml:
+	  * docs/plugins/inspect/plugin-udp.xml:
+	  * docs/plugins/inspect/plugin-video4linux2.xml:
+	  * docs/plugins/inspect/plugin-videobalance.xml:
+	  * docs/plugins/inspect/plugin-videobox.xml:
+	  * docs/plugins/inspect/plugin-videocrop.xml:
+	  * docs/plugins/inspect/plugin-videoflip.xml:
+	  * docs/plugins/inspect/plugin-videomixer.xml:
+	  * docs/plugins/inspect/plugin-wavenc.xml:
+	  * docs/plugins/inspect/plugin-wavpack.xml:
+	  * docs/plugins/inspect/plugin-wavparse.xml:
+	  * docs/plugins/inspect/plugin-ximagesrc.xml:
+	  Add docs for gdkpixbufsink; update docs to CVS version.
+
+2008-04-25 18:45:33 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  tests/examples/rtp/server-v4l2-H264-alsasrc-PCMA.sh: Remove test sync-offset by default.
+	  Original commit message from CVS:
+	  * tests/examples/rtp/server-v4l2-H264-alsasrc-PCMA.sh:
+	  Remove test sync-offset by default.
+
+2008-04-25 13:31:48 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/: Use GLib versions of htonl, htons, ntohl and ntohs in order to avoid problems on win32 (#529707).
+	  Original commit message from CVS:
+	  * gst/rtp/gstasteriskh263.c: (gst_asteriskh263_chain):
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_add_internal):
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_start):
+	  Use GLib versions of htonl, htons, ntohl and ntohs in order
+	  to avoid problems on win32 (#529707).
+
+2008-04-25 12:52:44 +0000  Jesús Corrius <jesus@softcatala.org>
+
+	  gst/goom/: Fix build with mingw32: use rand() instead of random() and replace bzero() with memset(). Fixes #529692.
+	  Original commit message from CVS:
+	  Patch by: Jesús Corrius <jesus at softcatala org>
+	  * gst/goom/filters.c: (zoomVector):
+	  * gst/goom/goom_core.c: (init_buffers):
+	  Fix build with mingw32: use rand() instead of random() and
+	  replace bzero() with memset(). Fixes #529692.
+
+2008-04-25 07:56:12 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: Fix typo in comments.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_combine_flows):
+	  Fix typo in comments.
+	  * tests/examples/rtp/client-H263p-PCMA.sdp:
+	  * tests/examples/rtp/client-H263p-PCMA.sh:
+	  * tests/examples/rtp/client-H264-PCMA.sdp:
+	  * tests/examples/rtp/client-H264-PCMA.sh:
+	  * tests/examples/rtp/client-H264.sdp:
+	  * tests/examples/rtp/client-H264.sh:
+	  * tests/examples/rtp/client-PCMA.sdp:
+	  * tests/examples/rtp/client-PCMA.sh:
+	  * tests/examples/rtp/server-alsasrc-PCMA.sh:
+	  * tests/examples/rtp/server-v4l2-H263p-alsasrc-AMR.sh:
+	  * tests/examples/rtp/server-v4l2-H264-alsasrc-PCMA.sh:
+	  Add some more docs and fix examples.
+
+2008-04-24 22:04:57 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/multifile.c: Include stdlib.h and unistd.h for mkdtemp. Some platforms have it declared in the f...
+	  Original commit message from CVS:
+	  * tests/check/elements/multifile.c:
+	  Include stdlib.h and unistd.h for mkdtemp. Some platforms have it
+	  declared in the former, some have it declared in the latter.
+
+2008-04-24 22:01:52 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Stop using deprecated GLib functions.
+	  Original commit message from CVS:
+	  * ext/cairo/gsttextoverlay.c: (gst_text_overlay_set_property):
+	  * gst/debug/tests.c: (md5_get_value):
+	  * gst/rtp/gstrtph263pdepay.c: (gst_rtp_h263p_depay_setcaps):
+	  * gst/rtp/gstrtpilbcpay.c: (gst_rtpilbcpay_setcaps):
+	  * gst/rtp/gstrtptheoradepay.c: (gst_rtp_theora_depay_setcaps):
+	  * gst/rtp/gstrtpvorbisdepay.c: (gst_rtp_vorbis_depay_setcaps):
+	  Stop using deprecated GLib functions.
+
+2008-04-24 21:17:42 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Back to development -> 0.10.8.1
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Back to development -> 0.10.8.1
+	  === release 0.10.8 ===
+
+=== release 0.10.8 ===
+
+2008-04-23 23:40:48 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* NEWS:
+	* RELEASE:
+	  Release 0.10.8 a little harder (edited the release notes)
+	  Original commit message from CVS:
+	  Release 0.10.8 a little harder (edited the release notes)
+
+2008-04-23 23:26:24 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cdio.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-soup.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* gst-plugins-good.doap:
+	* po/LINGUAS:
+	* win32/common/config.h:
+	  Release 0.10.8
+	  Original commit message from CVS:
+	  Release 0.10.8
+
+2008-04-23 23:18:44 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* common:
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/fr.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/ru.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+	  Original commit message from CVS:
+	  Update .po files
+
+2008-04-22 00:29:00 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: 0.10.7.4 pre-release
+	  Original commit message from CVS:
+	  * configure.ac:
+	  0.10.7.4 pre-release
+
+2008-04-22 00:18:52 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/goom/: Free a bunch of stuff, and initialise things to fix leaks and valgrind warnings in the testsuite.
+	  Original commit message from CVS:
+	  * gst/goom/config_param.c: (goom_plugin_parameters_free):
+	  * gst/goom/convolve_fx.c: (convolve_init), (convolve_free):
+	  * gst/goom/filters.c: (zoomFilterVisualFXWrapper_free):
+	  * gst/goom/flying_stars_fx.c: (fs_free):
+	  * gst/goom/goom_config_param.h:
+	  * gst/goom/goom_core.c: (goom_init), (goom_close):
+	  * gst/goom/goom_plugin_info.h:
+	  * gst/goom/gstgoom.c: (gst_goom_finalize):
+	  * gst/goom/lines.c: (goom_lines_free):
+	  * gst/goom/plugin_info.c: (plugin_info_init), (plugin_info_free):
+	  * gst/goom/surf3d.c: (grid3d_free):
+	  * gst/goom/surf3d.h:
+	  * gst/goom/tentacle3d.c: (tentacle_free):
+	  Free a bunch of stuff, and initialise things to fix leaks
+	  and valgrind warnings in the testsuite.
+	  Fixes: #529268
+
+2008-04-21 21:54:11 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/rganalysis.c: Don't leak a tag list. Fixes bug #529285.
+	  Original commit message from CVS:
+	  * tests/check/elements/rganalysis.c: (GST_START_TEST):
+	  Don't leak a tag list. Fixes bug #529285.
+
+2008-04-21 08:21:14 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Ref caps as the return value for the request_pt_map signal.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init), (request_pt_map),
+	  (gst_rtspsrc_configure_caps):
+	  Ref caps as the return value for the request_pt_map signal.
+	  Remove some caps weirdness when configuring a stream. See #528245.
+
+2008-04-18 18:47:43 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/icles/gdkpixbufsink-test.c: Add cast to placate gcc 4.1.2.
+	  Original commit message from CVS:
+	  * tests/icles/gdkpixbufsink-test.c:
+	  Add cast to placate gcc 4.1.2.
+
+2008-04-17 23:00:29 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: 0.10.7.3 pre-release
+	  Original commit message from CVS:
+	  * configure.ac:
+	  0.10.7.3 pre-release
+
+2008-04-17 22:32:16 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  tests/check/Makefile.am: Disable some more elements in the state test.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Disable some more elements in the state test.
+	  Add a define so the soup test can find the test files
+	  it needs at runtime.
+	  * tests/check/elements/souphttpsrc.c: (run_server):
+	  Add a define so the soup test can find the test files
+	  it needs at runtime.
+
+2008-04-17 18:08:53 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/goom/convolve_fx.c: Don't ever draw the GOOM logo.
+	  Original commit message from CVS:
+	  * gst/goom/convolve_fx.c: (convolve_apply):
+	  Don't ever draw the GOOM logo.
+	  Fixes: #528615
+
+2008-04-17 10:24:32 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/: gst_atomic_int_set ==> g_atomic_int_set
+	  Original commit message from CVS:
+	  * ext/cdio/gstcdiocddasrc.c:
+	  * ext/dv/gstdvdemux.c:
+	  gst_atomic_int_set ==> g_atomic_int_set
+
+2008-04-16 10:31:17 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Strip out the config/script parsing stuff, we don't need it.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/goom/Makefile.am:
+	  * gst/goom/convolve_fx.c:
+	  * gst/goom/default_scripts.h:
+	  * gst/goom/goom.h:
+	  * gst/goom/goom_core.c: (choose_a_goom_line):
+	  * gst/goom/goom_plugin_info.h:
+	  * gst/goom/goomsl.c:
+	  * gst/goom/goomsl.h:
+	  * gst/goom/goomsl_hash.c:
+	  * gst/goom/goomsl_hash.h:
+	  * gst/goom/goomsl_heap.c:
+	  * gst/goom/goomsl_heap.h:
+	  * gst/goom/goomsl_private.h:
+	  * gst/goom/plugin_info.c:
+	  Strip out the config/script parsing stuff, we don't need it.
+	  Fixes #527999.
+
+2008-04-15 16:58:36 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/goom/plugin_info.c: Disable altivec optimisations for 32-bit PPC as well to make things build properly on all PPC...
+	  Original commit message from CVS:
+	  * gst/goom/plugin_info.c: (setOptimizedMethods):
+	  Disable altivec optimisations for 32-bit PPC as well to make
+	  things build properly on all PPC systems. Fixes #528143
+
+2008-04-14 20:01:44 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst-plugins-good.spec.in: Update for souphttpsrc plugin which has moved to -good.
+	  Original commit message from CVS:
+	  * gst-plugins-good.spec.in:
+	  Update for souphttpsrc plugin which has moved to -good.
+
+2008-04-14 13:38:32 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  gst/matroska/matroska-demux.c: Fix open-ended seeks in matroskademux
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_handle_seek_event):
+	  Fix open-ended seeks in matroskademux
+	  Patch by: Mark Nauwelaerts <manauw skynet be>
+	  Fixes: #526557
+
+2008-04-13 23:13:32 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  tests/check/Makefile.am: Add soup test certificates to the dist.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Add soup test certificates to the dist.
+
+2008-04-13 17:43:52 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/Makefile.am: Remove LADSPA reference I missed.
+	  Original commit message from CVS:
+	  * ext/Makefile.am:
+	  Remove LADSPA reference I missed.
+
+2008-04-13 13:06:39 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/soup/gstsouphttpsrc.c: Give souphttpsrc GST_RANK_PRIMARY to make it the default HTTP source over gnome-vfs and ev...
+	  Original commit message from CVS:
+	  * ext/soup/gstsouphttpsrc.c: (plugin_init):
+	  Give souphttpsrc GST_RANK_PRIMARY to make it the default HTTP source
+	  over gnome-vfs and everything else. Fixes bug #527848.
+
+2008-04-12 23:47:23 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Remove LADSPA plugin. Fixes: #515978
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * ext/Makefile.am:
+	  Remove LADSPA plugin. Fixes: #515978
+
+2008-04-12 23:30:54 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Move soup plugin from -bad (Fixes: #523124)
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/inspect/plugin-soup.xml:
+	  * ext/Makefile.am:
+	  * tests/check/Makefile.am:
+	  Move soup plugin from -bad (Fixes: #523124)
+
+2008-04-11 11:08:35 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	  Fix the Changelog - actually speex <= 1.1.12 are vulnerable.
+	  Original commit message from CVS:
+	  Fix the Changelog - actually speex <= 1.1.12 are vulnerable.
+
+2008-04-11 10:32:20 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/speex/gstspeexdec.c: Fix bounds checking of mode in Speex header, which may produce negative numbers in speex < 1...
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexdec.c: (speex_dec_chain_parse_header):
+	  Fix bounds checking of mode in Speex header, which may
+	  produce negative numbers in speex < 1.1.12
+
+2008-04-10 07:11:51 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/souphttpsrc.c: Increase the timeout for the internet tests to 250 seconds and check for NULL cap...
+	  Original commit message from CVS:
+	  * tests/check/elements/souphttpsrc.c: (got_buffer),
+	  (souphttpsrc_suite):
+	  Increase the timeout for the internet tests to 250 seconds
+	  and check for NULL caps instead of just crashing.
+	  The real fix would be to implement an shoutcast server for the unit test
+	  instead of relying on a working internet connection.
+	  Fixes bug #521749.
+
+2008-04-09 16:11:40 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/goom/: Remove a bunch of font/text related code that we don't need.
+	  Original commit message from CVS:
+	  * gst/goom/Makefile.am:
+	  * gst/goom/gfontlib.c:
+	  * gst/goom/gfontlib.h:
+	  * gst/goom/gfontrle.c:
+	  * gst/goom/gfontrle.h:
+	  * gst/goom/goom.h:
+	  * gst/goom/goom_core.c: (goom_update):
+	  * gst/goom/goom_plugin_info.h:
+	  * gst/goom/gstgoom.c: (gst_goom_chain):
+	  * gst/goom/plugin_info.c:
+	  Remove a bunch of font/text related code that we don't need.
+
+2008-04-09 14:02:37 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/goom/: Change license of these files to LGPL, as permitted by the author, Guillaume Borios. See #515073.
+	  Original commit message from CVS:
+	  * gst/goom/ppc_drawings.s:
+	  * gst/goom/ppc_zoom_ultimate.s:
+	  Change license of these files to LGPL, as permitted by the
+	  author, Guillaume Borios. See #515073.
+
+2008-04-09 13:31:22 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/goom/: As hinted in Bug #518213, revert one change and fix warnings properly.
+	  Original commit message from CVS:
+	  * gst/goom/convolve_fx.c:
+	  * gst/goom/motif_goom1.h:
+	  * gst/goom/motif_goom2.h:
+	  As hinted in Bug #518213, revert one change and fix warnings properly.
+	  This fixes both #518213 and #520073 for me.
+
+2008-04-09 12:02:55 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/matroska/: Fix the Forte build by making function declaration signatures match the implementations.
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-read.c: (gst_ebml_read_seek):
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_handle_seek_event),
+	  (gst_matroska_demux_parse_contents_seekentry),
+	  (gst_matroska_demux_loop):
+	  Fix the Forte build by making function declaration signatures
+	  match the implementations.
+
+2008-04-08 19:49:34 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/oss/: More logging when probing (see #518474), some comments in _reset().
+	  Original commit message from CVS:
+	  * sys/oss/gstosshelper.c: (gst_oss_helper_rate_check_rate):
+	  * sys/oss/gstosssink.c: (gst_oss_sink_reset):
+	  * sys/oss/gstosssrc.c: (gst_oss_src_reset):
+	  More logging when probing (see #518474), some comments in _reset().
+
+2008-04-07 17:18:48 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/rtp/gstrtph264pay.c: Fix build because of a bad argument number.
+	  Original commit message from CVS:
+	  2008-04-07  Julien Moutte  <julien@fluendo.com>
+	  * gst/rtp/gstrtph264pay.c: (gst_rtp_h264_pay_setcaps): Fix build
+	  because of a bad argument number.
+
+2008-04-06 18:28:09 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/icles/: Interactive test app for gdkpixbufsink.
+	  Original commit message from CVS:
+	  * tests/icles/.cvsignore:
+	  * tests/icles/Makefile.am:
+	  * tests/icles/gdkpixbufsink-test.c:
+	  Interactive test app for gdkpixbufsink.
+
+2008-04-06 09:01:42 +0000  Sjoerd Simons <sjoerd@luon.net>
+
+	  ext/soup/gstsouphttpsrc.c: Only ignore actual redirects not all responses when in state
+	  Original commit message from CVS:
+	  Patch by: Sjoerd Simons <sjoerd at luon dot net>
+	  * ext/soup/gstsouphttpsrc.c: (gst_soup_http_src_response_cb):
+	  Only ignore actual redirects not all responses when in state
+	  GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING. Fixes bug #526337.
+
+2008-04-06 08:57:59 +0000  Damien Lespiau <damien.lespiau@gmail.com>
+
+	  configure.ac: Actually build dlls when cross-compiling with mingw32.
+	  Original commit message from CVS:
+	  Patch by: Damien Lespiau <damien dot lespiau at gmail dot com>
+	  * configure.ac:
+	  Actually build dlls when cross-compiling with mingw32.
+	  Fixes bug #526247.
+
+2008-04-05 12:00:46 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/hal/hal.c: Don't munge device string to 'default:x' for capture devices.
+	  Original commit message from CVS:
+	  * ext/hal/hal.c: (gst_hal_get_alsa_element):
+	  Don't munge device string to 'default:x' for capture devices.
+	  Fixes #525833.
+
+2008-04-04 19:00:19 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackparse.c: Always use GSlice as we actually depend on GLib 2.12 already.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackparse.c:
+	  (gst_wavpack_parse_index_entry_free):
+	  Always use GSlice as we actually depend on GLib 2.12 already.
+
+2008-04-04 11:26:40 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Require core/base 0.10.18 for ARGB caps parsing fixes in libgstvideo.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Require core/base 0.10.18 for ARGB caps parsing fixes in libgstvideo.
+	  Also bump the GLib requirement to the current de-facto requirement
+	  (ie. 2.12).
+
+2008-04-04 10:32:21 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtph264pay.*: Parse codec_data for future AVC compatibility.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph264pay.c: (encode_base64),
+	  (gst_rtp_h264_pay_setcaps), (gst_rtp_h264_pay_handle_buffer):
+	  * gst/rtp/gstrtph264pay.h:
+	  Parse codec_data for future AVC compatibility.
+	  Fail when we encounter AVC data for now.
+
+2008-04-04 09:50:10 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/spectrum/gstspectrum.c: Rename property enums and default defines for the properties to match the property names ...
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_class_init),
+	  (gst_spectrum_init), (gst_spectrum_set_property),
+	  (gst_spectrum_get_property), (gst_spectrum_message_new):
+	  Rename property enums and default defines for the properties to match
+	  the property names and rephrase property descriptions to make them a
+	  bit clearer (hopefully). See #518188.
+
+2008-04-03 22:59:44 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/check/: Add unit test for gdkpixbufsink element.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/gdkpixbufsink.c:
+	  Add unit test for gdkpixbufsink element.
+
+2008-04-03 22:50:48 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/gdk_pixbuf/: Add gdkpixbufsink element for easy snapshotting (#525946).
+	  Original commit message from CVS:
+	  * ext/gdk_pixbuf/Makefile.am:
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c: (plugin_init):
+	  * ext/gdk_pixbuf/gstgdkpixbufsink.c:
+	  (gst_gdk_pixbuf_sink_base_init),
+	  (gst_gdk_pixbuf_sink_class_init), (gst_gdk_pixbuf_sink_init),
+	  (gst_gdk_pixbuf_sink_start), (gst_gdk_pixbuf_sink_stop),
+	  (gst_gdk_pixbuf_sink_set_caps),
+	  (gst_gdk_pixbuf_sink_pixbuf_destroy_notify),
+	  (gst_gdk_pixbuf_sink_get_pixbuf_from_buffer),
+	  (gst_gdk_pixbuf_sink_handle_buffer), (gst_gdk_pixbuf_sink_preroll),
+	  (gst_gdk_pixbuf_sink_render), (gst_gdk_pixbuf_sink_set_property),
+	  (gst_gdk_pixbuf_sink_get_property):
+	  * ext/gdk_pixbuf/gstgdkpixbufsink.h:
+	  Add gdkpixbufsink element for easy snapshotting (#525946).
+
+2008-04-03 20:25:34 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/pipelines/wavpack.c: Bump timeout from 3 to 60 seconds.
+	  Original commit message from CVS:
+	  * tests/check/pipelines/wavpack.c: (wavpack_suite):
+	  Bump timeout from 3 to 60 seconds.
+
+2008-04-03 20:21:15 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/pipelines/.cvignore: Remove useless file.
+	  Original commit message from CVS:
+	  * tests/check/pipelines/.cvignore:
+	  Remove useless file.
+	  * tests/check/pipelines/.cvsignore:
+	  Add new test to .cvsignore.
+
+2008-04-03 20:05:31 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/: Add unit test that encodes and decodes some data, checks that it is still the same and that all timesta...
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  * tests/check/pipelines/wavpack.c: (bus_handler),
+	  (identity_handoff), (fakesink_handoff), (GST_START_TEST),
+	  (wavpack_suite), (main):
+	  Add unit test that encodes and decodes some data, checks that it
+	  is still the same and that all timestamps/offsets are perfect.
+
+2008-04-03 18:28:28 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/: Use GSlice for allocating index entries and use gst_element_class_set_details_simple().
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_base_init):
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_base_init):
+	  * ext/wavpack/gstwavpackparse.c:
+	  (gst_wavpack_parse_index_entry_new),
+	  (gst_wavpack_parse_index_entry_free),
+	  (gst_wavpack_parse_base_init),
+	  (gst_wavpack_parse_index_append_entry), (gst_wavpack_parse_reset):
+	  Use GSlice for allocating index entries and use
+	  gst_element_class_set_details_simple().
+
+2008-04-02 22:37:29 +0000  Brian Cameron <brian.cameron@sun.com>
+
+	  sys/sunaudio/: Fix up copyrights (#525860).
+	  Original commit message from CVS:
+	  Patch by: Brian Cameron <brian.cameron at sun dot com>
+	  * sys/sunaudio/gstsunaudio.c:
+	  * sys/sunaudio/gstsunaudiomixer.c:
+	  * sys/sunaudio/gstsunaudiomixer.h:
+	  * sys/sunaudio/gstsunaudiomixerctrl.c:
+	  * sys/sunaudio/gstsunaudiomixerctrl.h:
+	  * sys/sunaudio/gstsunaudiomixertrack.c:
+	  * sys/sunaudio/gstsunaudiomixertrack.h:
+	  * sys/sunaudio/gstsunaudiosink.c:
+	  * sys/sunaudio/gstsunaudiosink.h:
+	  * sys/sunaudio/gstsunaudiosrc.c:
+	  * sys/sunaudio/gstsunaudiosrc.h:
+	  Fix up copyrights (#525860).
+
+2008-04-02 16:10:33 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  add new goom plugin to spec file
+	  Original commit message from CVS:
+	  add new goom plugin to spec file
+
+2008-04-02 15:42:27 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/goom/goomsl.c: Check return value of fread() to avoid compiler warnings.
+	  Original commit message from CVS:
+	  * gst/goom/goomsl.c: (gsl_read_file):
+	  Check return value of fread() to avoid compiler warnings.
+
+2008-04-01 11:00:43 +0000  mersad <mersad@axis.com>
+
+	  gst/law/: Make negotiation a bit modern.
+	  Original commit message from CVS:
+	  Based on patch by: mersad <mersad at axis dot com>
+	  * gst/law/alaw-decode.c: (gst_alaw_dec_sink_setcaps),
+	  (gst_alaw_dec_chain), (gst_alaw_dec_change_state):
+	  * gst/law/alaw-decode.h:
+	  * gst/law/alaw-encode.c: (gst_alaw_enc_chain):
+	  * gst/law/mulaw-decode.c: (mulawdec_sink_setcaps),
+	  (gst_mulawdec_chain), (gst_mulawdec_change_state):
+	  * gst/law/mulaw-decode.h:
+	  * gst/law/mulaw-encode.c: (gst_mulawenc_chain):
+	  Make negotiation a bit modern.
+	  Use pad_alloc. Fixes #525359.
+
+2008-03-31 22:06:14 +0000  David Schleef <ds@schleef.org>
+
+	  gst/goom/xmmx.c: Fix constraints on asm code so that it compiles consistently.  Fixes #522278.
+	  Original commit message from CVS:
+	  * gst/goom/xmmx.c: Fix constraints on asm code so that it
+	  compiles consistently.  Fixes #522278.
+
+2008-03-27 09:36:58 +0000  Brian Cameron <brian.cameron@sun.com>
+
+	  sys/sunaudio/: Fix up the mixer tracks to use a volume range of 0-255, which is what the sun audio API uses. This sim...
+	  Original commit message from CVS:
+	  Patch by: Brian Cameron <brian.cameron at sun dot com>
+	  * sys/sunaudio/gstsunaudiomixerctrl.c:
+	  (gst_sunaudiomixer_ctrl_get_volume),
+	  (gst_sunaudiomixer_ctrl_set_volume):
+	  * sys/sunaudio/gstsunaudiomixertrack.c: (gst_sunaudiomixer_track_new):
+	  Fix up the mixer tracks to use a volume range of 0-255, which is what
+	  the sun audio API uses. This simplifies the code and avoids rounding
+	  errors. Fixes #524593.
+
+2008-03-26 15:10:08 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	  Add device-fd property to make it possible to apps to call ioctl's.
+	  Original commit message from CVS:
+	  Add device-fd property to make it possible to apps to call ioctl's.
+
+2008-03-25 16:44:20 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Unbreak streaming mode again.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (next_entry_size):
+	  Unbreak streaming mode again.
+
+2008-03-25 12:39:22 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/v4l2/v4l2src_calls.c: Remove superfluous DEBUG macro.
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_set_capture):
+	  Remove superfluous DEBUG macro.
+
+2008-03-25 12:33:09 +0000  William M. Brack <wbrack@mmm.com.hk>
+
+	  sys/v4l2/v4l2src_calls.c: Check whether the device supports setting the framerate before trying to set it and then po...
+	  Original commit message from CVS:
+	  Based on patch by: William M. Brack <wbrack at mmm com hk>
+	  * sys/v4l2/v4l2src_calls.c: (fractions_are_equal),
+	  (gst_v4l2src_set_capture):
+	  Check whether the device supports setting the framerate before
+	  trying to set it and then posting a warning or error if it doesn't
+	  work (#516649, #520092). Also compare fractions more correctly.
+
+2008-03-24 12:32:59 +0000  Rene Stadler <mail@renestadler.de>
+
+	  Make rganalysis and rglimiter elements GAP-flag aware.
+	  Original commit message from CVS:
+	  * gst/replaygain/gstrganalysis.c (gst_rg_analysis_init),
+	  (gst_rg_analysis_transform_ip):
+	  * gst/replaygain/gstrglimiter.c (gst_rg_limiter_init),
+	  (gst_rg_limiter_transform_ip):
+	  Make rganalysis and rglimiter elements GAP-flag aware.
+	  * tests/check/elements/rganalysis.c: (test_gap_buffers),
+	  (rganalysis_suite):
+	  * tests/check/elements/rglimiter.c (test_gap), (rglimiter_suite):
+	  Add tests to verify gap-awareness.
+
+2008-03-23 13:31:15 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/goom/Makefile.am: Remove ppc assembler optimisations from the build until they actually build (they also seem to ...
+	  Original commit message from CVS:
+	  * gst/goom/Makefile.am:
+	  Remove ppc assembler optimisations from the build until they
+	  actually build (they also seem to have GPL headers).
+
+2008-03-23 12:48:44 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  m4/Makefile.am: Better not dist files that don't exist any longer (lrint*m4).
+	  Original commit message from CVS:
+	  * m4/Makefile.am:
+	  Better not dist files that don't exist any longer (lrint*m4).
+
+2008-03-22 19:26:04 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/soup/gstsouphttpsrc.c: Don't autoplug souphttpsrc for dav/davs. This is better handled by
+	  Original commit message from CVS:
+	  * ext/soup/gstsouphttpsrc.c: (gst_soup_http_src_got_headers_cb),
+	  (gst_soup_http_src_chunk_allocator),
+	  (gst_soup_http_src_got_chunk_cb),
+	  (gst_soup_http_src_uri_get_protocols):
+	  Don't autoplug souphttpsrc for dav/davs. This is better handled by
+	  GIO and GnomeVFS as they provide authentication.
+	  Don't leak the icy caps if we already set them and get a new
+	  icy-metaint header.
+	  Try harder to set the icy caps on the output buffer to have correct
+	  caps for the first buffer already.
+	  * tests/check/elements/souphttpsrc.c: (got_buffer),
+	  (GST_START_TEST):
+	  Check that we get a buffer with application/x-icy caps if iradio-mode
+	  is enabled and we have an icecast URL.
+
+2008-03-22 18:18:46 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/soup/gstsouphttpsrc.c: Actually set the icy caps on our src pad if we have icecast data.
+	  Original commit message from CVS:
+	  * ext/soup/gstsouphttpsrc.c: (gst_soup_http_src_chunk_allocator):
+	  Actually set the icy caps on our src pad if we have icecast data.
+	  Fixes bug #523854.
+
+2008-03-21 13:36:27 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Remove lrint/lrintf checks. We don't use it anywhere.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * m4/lrint.m4:
+	  * m4/lrintf.m4:
+	  Remove lrint/lrintf checks. We don't use it anywhere.
+
+2008-03-19 19:56:59 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/freeze/: Add example to source code documentation blob and remove the 3 line
+	  Original commit message from CVS:
+	  * gst/freeze/FAQ:
+	  * gst/freeze/Makefile.am:
+	  * gst/freeze/gstfreeze.c:
+	  Add example to source code documentation blob and remove the 3 line
+	  FAQ.
+	  * gst/interleave/interleave.c:
+	  Add a source code documentation blob.
+
+2008-03-18 15:03:06 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ChangeLog:
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  sys/osxvideo/osxvideosink.m (gst_osx_video_sink_osxwindow_destroy)
+	  Original commit message from CVS:
+	  2008-03-18  Andy Wingo  <wingo@pobox.com>
+	  * sys/osxvideo/osxvideosink.m
+	  (gst_osx_video_sink_osxwindow_destroy)
+	  (gst_osx_video_sink_osxwindow_new): Actually set a lock on the
+	  task, whoopdee.
+	  (cocoa_event_loop): Pacify the taymans by upping the usleepage to
+	  2 ms.
+
+2008-03-18 11:50:08 +0000  Andy Wingo <wingo@pobox.com>
+
+	  sys/osxvideo/osxvideosink.m (gst_osx_video_sink_osxwindow_destroy)
+	  Original commit message from CVS:
+	  2008-03-18  Andy Wingo  <wingo@pobox.com>
+	  * sys/osxvideo/osxvideosink.m (gst_osx_video_sink_osxwindow_destroy)
+	  (gst_osx_video_sink_osxwindow_new, cocoa_event_loop):
+	  * sys/osxvideo/osxvideosink.h (struct _GstOSXVideoSink): If we
+	  need to run an event loop, do so in a task instead of assuming
+	  that there will be a GMainLoop. Fixes #523134.
+
+2008-03-17 19:50:58 +0000  William M. Brack <wbrack@mmm.com.hk>
+
+	  sys/v4l2/v4l2src_calls.c: Make sure the probed frame sizes are reversed in the resulting caps also when using V4L2_FR...
+	  Original commit message from CVS:
+	  Patch by: William M. Brack <wbrack at mmm com hk>
+	  * sys/v4l2/v4l2src_calls.c:
+	  (gst_v4l2src_probe_caps_for_format_and_size),
+	  (gst_v4l2src_probe_caps_for_format):
+	  Make sure the probed frame sizes are reversed in the resulting
+	  caps also when using V4L2_FRMSIZE_STEPWISE (so they end up
+	  highest resolution first); also remove unused variable.
+	  (Partly fixes #520092)
+
+2008-03-17 15:56:01 +0000  Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+
+	  gst/rtsp/gstrtspsrc.c: Call WSAStartup() and WSACleanup before using the Winsock API.
+	  Original commit message from CVS:
+	  Patch by: Ole André Vadla Ravnås  <ole.andre.ravnas@tandberg.com>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init),
+	  (gst_rtspsrc_finalize):
+	  Call WSAStartup() and WSACleanup before using the Winsock API.
+	  See #520808.
+
+2008-03-16 15:01:07 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.c: Erm, the buffer-size is just guint, no need for the special format specifier.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  Erm, the buffer-size is just guint, no need for the special format
+	  specifier.
+
+2008-03-16 14:34:45 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/goom/: Small fixes to build more on PPC: ifdef out code that uses unknown define; add newline at end of header fi...
+	  Original commit message from CVS:
+	  * gst/goom/plugin_info.c:
+	  * gst/goom/ppc_zoom_ultimate.h:
+	  Small fixes to build more on PPC: ifdef out code that uses unknown
+	  define; add newline at end of header file to avoid compiler warning.
+	  Assembler code still doesn't build though.
+
+2008-03-16 14:04:16 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.c: Fix up my last commit. Use G_GUINT32_FORMAT for the guint32 debug log.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  Fix up my last commit. Use G_GUINT32_FORMAT for the guint32 debug log.
+	  Also downgrade a GST_WARNING to GST_DEBUG and add a comment.
+
+2008-03-15 22:10:38 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.c: Chunksize is uint32. Fix format specifier.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  Chunksize is uint32. Fix format specifier.
+
+2008-03-14 15:53:01 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* ChangeLog:
+	* gst/rtsp/COPYING.MIT:
+	  fix license file, remove extra line copied over by mistake
+	  Original commit message from CVS:
+	  fix license file, remove extra line copied over by mistake
+
+2008-03-13 14:30:45 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/audiofx.c: Use GST_LICENSE, GST_PACKAGE_NAME and GST_PACKAGE_ORIGIN instead of hardcoding values.
+	  Original commit message from CVS:
+	  * gst/audiofx/audiofx.c:
+	  Use GST_LICENSE, GST_PACKAGE_NAME and GST_PACKAGE_ORIGIN instead
+	  of hardcoding values.
+
+2008-03-13 09:45:09 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  ext/soup/gstsouphttpsrc.*: Try to resume on server disconnect. Fixes bug #522134.
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * ext/soup/gstsouphttpsrc.c: (gst_soup_http_src_init),
+	  (gst_soup_http_src_finished_cb), (gst_soup_http_src_response_cb),
+	  (gst_soup_http_src_build_message), (gst_soup_http_src_create):
+	  * ext/soup/gstsouphttpsrc.h:
+	  Try to resume on server disconnect. Fixes bug #522134.
+
+2008-03-11 23:12:04 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  sys/oss/gstosssrc.*: Cache probed caps, so _get_caps() during recording doesn't cause ioctl calls which may disrupt t...
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts <manauw skynet be>
+	  * sys/oss/gstosssrc.c: (gst_oss_src_init), (gst_oss_src_getcaps),
+	  (gst_oss_src_close):
+	  * sys/oss/gstosssrc.h:
+	  Cache probed caps, so _get_caps() during recording doesn't cause
+	  ioctl calls which may disrupt the recording (fixes #521875).
+
+2008-03-11 16:23:04 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Make sure we always send a DISCONT after a seek by setting the sample index to an undefined va...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_perform_seek),
+	  (gst_qtdemux_activate_segment),
+	  (gst_qtdemux_prepare_current_sample),
+	  (gst_qtdemux_loop_state_movie), (qtdemux_parse_trak):
+	  Make sure we always send a DISCONT after a seek by setting the sample
+	  index to an undefined value after a seek.
+
+2008-03-11 15:18:43 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavisubtitle.h: Fix up IS_FOO macros, which makes gtk-doc much happier.
+	  Original commit message from CVS:
+	  * gst/avi/gstavisubtitle.h: (GST_IS_AVI_SUBTITLE),
+	  (GST_IS_AVI_SUBTITLE_CLASS):
+	  Fix up IS_FOO macros, which makes gtk-doc much happier.
+
+2008-03-08 19:29:20 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/icles/Makefile.am: Move the -lgstfoo where it belongs.
+	  Original commit message from CVS:
+	  * tests/icles/Makefile.am:
+	  Move the -lgstfoo where it belongs.
+
+2008-03-08 19:14:22 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* ChangeLog:
+	  ChangeLog surgery
+	  Original commit message from CVS:
+	  ChangeLog surgery
+
+2008-03-08 04:40:32 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/matroska/ebml-ids.h: Add ID for EBML CRC32 elements.
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-ids.h:
+	  Add ID for EBML CRC32 elements.
+	  * gst/matroska/Makefile.am:
+	  * gst/matroska/ebml-read.c: (gst_ebml_finalize),
+	  (gst_ebml_read_class_init), (gst_ebml_read_peek_bytes),
+	  (gst_ebml_read_get_length), (_ext2dbl), (gst_ebml_read_float),
+	  (gst_ebml_read_header):
+	  Support reading 80bit floats, add finalize method to clean up
+	  in any case, support reading length/id elements with any length
+	  as long as it's smaller than our supported maximum, don't leak
+	  buffers if reading as much data as we wanted failed and some
+	  smaller cleanup.
+
+2008-03-08 04:21:34 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtp/gstrtph263pdepay.c: Check that a buffer is large enough before reading from it.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtp/gstrtph263pdepay.c: (gst_rtp_h263p_depay_process):
+	  Check that a buffer is large enough before reading from it.
+	  Fixes bug #521102.
+
+2008-03-07 15:54:09 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstudpsrc.c: Fix compilation after removing the GstPollMode from the constructor.
+	  Original commit message from CVS:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_start):
+	  Fix compilation after removing the GstPollMode from the
+	  constructor.
+
+2008-03-07 13:08:42 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Check for sinh(), cosh() and asinh() and define our own implementations if they're not available. Fixes bug #520880.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/audiofx/Makefile.am:
+	  * gst/audiofx/audiochebband.c:
+	  * gst/audiofx/audiocheblimit.c:
+	  * gst/audiofx/math_compat.h:
+	  Check for sinh(), cosh() and asinh() and define our own
+	  implementations if they're not available. Fixes bug #520880.
+
+2008-03-07 12:40:18 +0000  Olivier Crete <tester@tester.ca>
+
+	  ext/speex/gstspeexenc.c: Unref the buffers only once when handling not-negotiated errors.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * ext/speex/gstspeexenc.c: (gst_speex_enc_chain):
+	  Unref the buffers only once when handling not-negotiated errors.
+	  Fixes bug #520764.
+
+2008-03-07 10:01:40 +0000  Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+
+	  gst/udp/gstudpsrc.c: Properly balance WSA_Cleanup with WSA_Startup.
+	  Original commit message from CVS:
+	  Patch by: Ole André Vadla Ravnås  <ole.andre.ravnas@tandberg.com>
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_finalize), (gst_udpsrc_start),
+	  (gst_udpsrc_stop):
+	  Properly balance WSA_Cleanup with WSA_Startup.
+	  Also make the poll controllable on windows. Fixes #520888.
+
+2008-03-06 19:47:48 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/matroska/: Handle return values from pull_range in a more granular way to properly shut down on seeks.
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-read.c: (gst_ebml_read_peek_bytes),
+	  (gst_ebml_read_pull_bytes), (gst_ebml_read_element_id),
+	  (gst_ebml_read_element_length), (gst_ebml_peek_id),
+	  (gst_ebml_read_skip), (gst_ebml_read_buffer),
+	  (gst_ebml_read_bytes), (gst_ebml_read_uint), (gst_ebml_read_sint),
+	  (gst_ebml_read_float), (gst_ebml_read_ascii), (gst_ebml_read_utf8),
+	  (gst_ebml_read_date), (gst_ebml_read_master),
+	  (gst_ebml_read_binary), (gst_ebml_read_header):
+	  * gst/matroska/ebml-read.h:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_combine_flows), (gst_matroska_demux_reset),
+	  (gst_matroska_demux_read_track_encodings),
+	  (gst_matroska_demux_add_stream),
+	  (gst_matroska_demux_handle_src_query),
+	  (gst_matroska_demux_handle_seek_event),
+	  (gst_matroska_demux_init_stream),
+	  (gst_matroska_demux_parse_tracks),
+	  (gst_matroska_demux_parse_index_cuetrack),
+	  (gst_matroska_demux_parse_index_pointentry),
+	  (gst_matroska_demux_parse_index), (gst_matroska_demux_parse_info),
+	  (gst_matroska_demux_parse_metadata_id_simple_tag),
+	  (gst_matroska_demux_parse_metadata_id_tag),
+	  (gst_matroska_demux_parse_metadata),
+	  (gst_matroska_demux_sync_streams),
+	  (gst_matroska_demux_push_hdr_buf),
+	  (gst_matroska_demux_push_flac_codec_priv_data),
+	  (gst_matroska_demux_push_xiph_codec_priv_data),
+	  (gst_matroska_demux_add_wvpk_header),
+	  (gst_matroska_demux_check_subtitle_buffer),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+	  (gst_matroska_demux_parse_cluster),
+	  (gst_matroska_demux_parse_contents_seekentry),
+	  (gst_matroska_demux_parse_contents),
+	  (gst_matroska_demux_loop_stream_parse_id),
+	  (gst_matroska_demux_loop_stream), (gst_matroska_demux_loop):
+	  * gst/matroska/matroska-demux.h:
+	  * gst/matroska/matroska-ids.h:
+	  Handle return values from pull_range in a more granular way to properly
+	  shut down on seeks.
+	  Combine return values from push.
+	  Implement proper error handling.
+	  Prepare for handling seeking correctly.
+
+2008-03-03 22:01:56 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/matroska/ebml-read.c: Use GINT64 formatting constants from GLIB.
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-read.c:
+	  Use GINT64 formatting constants from GLIB.
+	  * gst/matroska/matroska-demux.c:
+	  Add some guards to avoid a possible division by 0 and crashing
+	  with NULL events on some systems.
+	  Use gst_gdouble_to_guint64 somewhere instead of an implicit
+	  conversion.
+	  * gst/matroska/matroska-mux.c:
+	  Check for invalid timestamps in a bunch of places to avoid
+	  writing bogus durations into the output file.
+	  Fix some double<->gint64 conversions that weren't using
+	  gst_guint64_to_gdouble
+
+2008-03-03 13:03:43 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  configure.ac: Move the checks for bison, flex and as to the program section and the check for gcc inline asm to the c...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Move the checks for bison, flex and as to the program section and the
+	  check for gcc inline asm to the compiler characteristics section.
+
+2008-03-03 12:10:55 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  configure.ac: Use AG_GST_CHECK_PLUGIN and AG_GST_DISABLE_PLUGIN to simplify which plug-ins are included/excluded. (#4...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Use AG_GST_CHECK_PLUGIN and AG_GST_DISABLE_PLUGIN to simplify which
+	  plug-ins are included/excluded. (#498222)
+
+2008-02-29 12:35:24 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/videomixer/videomixer.c: Don't call gst_object_sync_values() unless we have a valid timestamp.
+	  Original commit message from CVS:
+	  * gst/videomixer/videomixer.c: (gst_videomixer_blend_buffers):
+	  Don't call gst_object_sync_values() unless we have a valid timestamp.
+
+2008-02-29 06:18:55 +0000  David Schleef <ds@schleef.org>
+
+	  gst/matroska/: Fix Dirac mapping.  I had previously added a VfW-type mapping, but it looks like Dirac will get a nati...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  * gst/matroska/matroska-ids.h:
+	  * gst/matroska/matroska-mux.c:
+	  Fix Dirac mapping.  I had previously added a VfW-type
+	  mapping, but it looks like Dirac will get a native Matroska
+	  mapping, and this is the most likely method.
+
+2008-02-28 23:56:30 +0000  David Schleef <ds@schleef.org>
+
+	  gst/avi/gstavimux.c: Add Dirac encoding
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c: Add Dirac encoding
+
+2008-02-28 11:51:24 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/udp/gstudpsrc.*: Port to GstPoll. See #505417.
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt <pkj at axis com>
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_init), (gst_udpsrc_create),
+	  (gst_udpsrc_get_property), (gst_udpsrc_start), (gst_udpsrc_unlock),
+	  (gst_udpsrc_unlock_stop), (gst_udpsrc_stop):
+	  * gst/udp/gstudpsrc.h:
+	  Port to GstPoll. See #505417.
+
+2008-02-28 08:37:44 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/law/mulaw-decode.c: Return GST_FLOW_NOT_NEGOTIATED when the caps are not set yet on the srcpad. We need rate and ...
+	  Original commit message from CVS:
+	  * gst/law/mulaw-decode.c: (gst_mulawdec_chain):
+	  Return GST_FLOW_NOT_NEGOTIATED when the caps are not set
+	  yet on the srcpad. We need rate and channels before we
+	  can do any processing. Fixes bug #519088.
+
+2008-02-26 10:09:38 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Detect and indicate if GCC inline assembly syntax is available.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Detect and indicate if GCC inline assembly syntax is
+	  available.
+	  * gst/goom/Makefile.am:
+	  * gst/goom/convolve_fx.c:
+	  * gst/goom/flying_stars_fx.c:
+	  * gst/goom/goom_config.h:
+	  * gst/goom/goom_core.c:
+	  * gst/goom/goomsl.c:
+	  * gst/goom/ifs.c:
+	  * gst/goom/mmx.c:
+	  * gst/goom/plugin_info.c:
+	  * gst/goom/xmmx.c:
+	  Fix various GCC-isms, and only build the inline assembly
+	  with compilers that support GCC inline assembly.
+	  Fix a couple of other warnings shown with Forte.
+
+2008-02-26 05:36:17 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  Add support for specifying a list of cookies to be passed in the HTTP request. Fixes bug #518722.
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * ext/soup/gstsouphttpsrc.c: (gst_soup_http_src_class_init),
+	  (gst_soup_http_src_init), (gst_soup_http_src_dispose),
+	  (gst_soup_http_src_set_property), (gst_soup_http_src_get_property),
+	  (gst_soup_http_src_create):
+	  * ext/soup/gstsouphttpsrc.h:
+	  * tests/check/elements/souphttpsrc.c: (run_test), (GST_START_TEST),
+	  (souphttpsrc_suite):
+	  Add support for specifying a list of cookies to be passed in
+	  the HTTP request. Fixes bug #518722.
+
+2008-02-25 12:03:46 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/goom/xmmx.c: Use 'emms' instead of 'femms' to not crash on cpus that do not implement this 3dnow specific instruc...
+	  Original commit message from CVS:
+	  * gst/goom/xmmx.c:
+	  Use 'emms' instead of 'femms' to not crash on cpus that do not
+	  implement this 3dnow specific instruction.
+
+2008-02-25 10:32:35 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/goom/plugin_info.c: Use extended MMX for draw_line() too if available, not only normal MMX.
+	  Original commit message from CVS:
+	  * gst/goom/plugin_info.c: (setOptimizedMethods):
+	  Use extended MMX for draw_line() too if available, not only
+	  normal MMX.
+
+2008-02-25 06:50:31 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/jpeg/gstjpeg.c: Remove (commented out) smoke typefinder. This is in base now.
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpeg.c: (plugin_init):
+	  Remove (commented out) smoke typefinder. This is in base now.
+
+2008-02-23 15:02:15 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/goom2k1/: Rename the installed library, and don't register the same
+	  Original commit message from CVS:
+	  * gst/goom2k1/Makefile.am:
+	  * gst/goom2k1/gstgoom.c:
+	  Rename the installed library, and don't register the same
+	  GType name as the new goom.
+
+2008-02-23 12:23:38 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Check for and define ERROR_CXXFLAGS and use them when building
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * ext/taglib/Makefile.am:
+	  Check for and define ERROR_CXXFLAGS and use them when building
+	  C++ code (#516509).
+
+2008-02-23 12:10:16 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/goom/: Call oil_init(), otherwise oil_get_cpu_flags() won't return anything useful. Export goom debug category so...
+	  Original commit message from CVS:
+	  * gst/goom/gstgoom.c: (goom_debug), (plugin_init):
+	  * gst/goom/plugin_info.c: (goom_debug), (GST_CAT_DEFAULT),
+	  (setOptimizedMethods):
+	  Call oil_init(), otherwise oil_get_cpu_flags() won't return
+	  anything useful. Export goom debug category so we can get
+	  rid of the VERBOSE define and the printfs.
+
+2008-02-23 11:53:27 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/goom/: Compile fixes for x86-64.
+	  Original commit message from CVS:
+	  * gst/goom/goomsl_heap.c: (align_it):
+	  * gst/goom/plugin_info.c: (setOptimizedMethods):
+	  Compile fixes for x86-64.
+
+2008-02-23 03:10:55 +0000  Bastien Nocera <hadess@hadess.net>
+
+	  gst/goom/Makefile.am: Don't compile lex or yacc outputs with warnings, but add other CFLAGS
+	  Original commit message from CVS:
+	  * gst/goom/Makefile.am: Don't compile lex or yacc outputs
+	  with warnings, but add other CFLAGS
+	  * gst/goom/goomsl.c (gsl_instr_set_namespace),
+	  (gsl_instr_add_param), (iflow_execute), (gsl_enternamespace),
+	  (calculate_labels), (gsl_read_file):
+	  * gst/goom/goomsl_lex.l:
+	  * gst/goom/goomsl_yacc.y:
+	  * gst/goom/plugin_info.c: Remove a few live printf, and
+	  fprintf, replace exit() calls with g_assert_not_reached()
+	  if it not optimal for a library
+
+2008-02-23 02:38:03 +0000  Bastien Nocera <hadess@hadess.net>
+
+	  gst/goom/Makefile.am: Remove the warnings being disabled, fix linkage on x86, spotted by Sebastian Dröge
+	  Original commit message from CVS:
+	  * gst/goom/Makefile.am: Remove the warnings being disabled,
+	  fix linkage on x86, spotted by Sebastian Dröge
+	  <slomo@circular-chaos.org>
+	  * gst/goom/convolve_fx.c (convolve_init),
+	  (create_output_with_brightness), (convolve_apply):
+	  * gst/goom/filters.c (zoomFilterVisualFXWrapper_create):
+	  * gst/goom/goomsl.c:
+	  * gst/goom/ifs.c (ifs_update), (ifs_visualfx_create):
+	  * gst/goom/plugin_info.c:
+	  * gst/goom/tentacle3d.c (tentacle_fx_create):
+	  Fix warnings, and disable the motifs in the convolve_fx
+	  plugin (they were causing warnings, and they were just
+	  "Goom" in funny letterring)
+
+2008-02-23 01:51:37 +0000  Bastien Nocera <hadess@hadess.net>
+
+	  configure.ac: Add checks for Flex/Yacc/Bison and other furry animals, for the new goom 2k4 based plugin
+	  Original commit message from CVS:
+	  2008-02-23  Bastien Nocera  <hadess@hadess.net>
+	  * configure.ac: Add checks for Flex/Yacc/Bison and other
+	  furry animals, for the new goom 2k4 based plugin
+	  * gst/goom/*: Update to use goom 2k4, uses liboil to detect
+	  CPU optimisations (not working yet), move the old plugin to...
+	  * gst/goom2k1/*: ... here, in case somebody is sick enough
+	  Fixes #515073
+
+2008-02-22 09:56:03 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Post the server response code in an error message instead of a generic 'error' message. Fixes ...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_setup_streams):
+	  Post the server response code in an error message instead of a generic
+	  'error' message. Fixes #517237.
+
+2008-02-22 07:20:03 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  Implement zero-copy and make the buffer size configurable.
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * configure.ac:
+	  * ext/soup/gstsouphttpsrc.c: (gst_soup_http_src_cancel_message),
+	  (gst_soup_http_src_finished_cb), (gst_soup_http_src_chunk_free),
+	  (gst_soup_http_src_chunk_allocator),
+	  (gst_soup_http_src_got_chunk_cb), (gst_soup_http_src_create),
+	  (gst_soup_http_src_start), (gst_soup_http_src_set_proxy):
+	  * ext/soup/gstsouphttpsrc.h:
+	  Implement zero-copy and make the buffer size configurable.
+	  Prefix proxy URIs with "http://" if they don't start with it
+	  already and catch errors earlier, fixes hanging in some situations.
+	  Fixes bug #514948.
+
+2008-02-22 06:22:39 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/Makefile.am: Ignore gconfaudiosrc for the states unit test too. It will fallback to alsasrc if the gconf ...
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Ignore gconfaudiosrc for the states unit test too. It will fallback
+	  to alsasrc if the gconf settings can't be read and not everybody has
+	  alsa.
+
+2008-02-22 06:06:06 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackparse.*: Always report the duration if we know it in push mode and don't return 0 just to make ...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_src_query),
+	  (gst_wavpack_parse_create_src_pad):
+	  * ext/wavpack/gstwavpackparse.h:
+	  Always report the duration if we know it in push mode and don't
+	  return 0 just to make totem believe we can't seek in push mode.
+	  Newer totem version use the SEEKING query which properly reports
+	  if we can seek or not.
+
+2008-02-22 05:39:01 +0000  Jens Granseuer <jensgr@gmx.net>
+
+	  tests/examples/equalizer/demo.c: C89 fix, moving variable declarations to the beginning of the block. Fixes bug #517933.
+	  Original commit message from CVS:
+	  Patch by: Jens Granseuer <jensgr at gmx dot net>
+	  * tests/examples/equalizer/demo.c: (main):
+	  C89 fix, moving variable declarations to the beginning of
+	  the block. Fixes bug #517933.
+
+2008-02-21 23:47:37 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Back to development...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Back to development...
+
+=== release 0.10.7 ===
+
+2008-02-21 00:09:07 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* 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:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cdio.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-equalizer.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gamma.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-monoscope.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multifile.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-spectrum.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-video4linux2.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* gst-plugins-good.doap:
+	* po/LINGUAS:
+	* win32/common/config.h:
+	  Release 0.10.7 - Red Door Black
+	  Original commit message from CVS:
+	  Release 0.10.7 - Red Door Black
+
+2008-02-20 22:51:08 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/bg.po:
+	* po/ca.po:
+	* po/cs.po:
+	* po/da.po:
+	* po/en_GB.po:
+	* po/es.po:
+	* po/eu.po:
+	* po/fi.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/pl.po:
+	* po/sk.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	* po/zh_CN.po:
+	* po/zh_HK.po:
+	* po/zh_TW.po:
+	  Update .po files
+	  Original commit message from CVS:
+	  Update .po files
+
+2008-02-19 10:47:20 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/alpha/Makefile.am: Link alpha plugin with libgstbase. Fixes bug #517386.
+	  Original commit message from CVS:
+	  * gst/alpha/Makefile.am:
+	  Link alpha plugin with libgstbase. Fixes bug #517386.
+
+2008-02-18 11:13:35 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Init values to -1 instead of the default 0 value.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_create_stream):
+	  Init values to -1 instead of the default 0 value.
+	  Fixes #516524.
+
+2008-02-14 14:50:30 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/examples/spectrum/spectrum-example.c: Add missing include to fix compilation when libxml usage is disabled.
+	  Original commit message from CVS:
+	  * tests/examples/spectrum/spectrum-example.c:
+	  Add missing include to fix compilation when libxml usage is disabled.
+	  Fixes: #516371
+
+2008-02-12 23:38:19 +0000  Wim Taymans <wim.taymans@collabora.co.uk>
+
+	  fixes: #514889
+	  Original commit message from CVS:
+	  patch by:  Wim Taymans  <wim.taymans@collabora.co.uk>
+	  fixes: #514889
+	  * gst/rtp/gstrtph264pay.c:
+	  * gst/rtp/gstrtpmp4gdepay.c:
+	  * gst/rtp/gstrtpmp4gpay.c:
+	  * gst/rtp/gstrtpmp4gpay.h:
+	  * gst/rtp/gstrtptheorapay.c:
+	  * gst/rtp/gstrtpvorbispay.c:
+	  Fix various leaks shown up in valgrind
+	  - free sprops and buffer in error cases in H264 payloader
+	  - fix leak in mp4g depayloader when construction the caps
+	  - don't leak config string in the mp4g payloader
+	  - don't leak buffers and headers in theora and vorbis payloaders
+	  * tests/check/elements/rtp-payloading.c:
+	  Fix the RTP data test
+	  - Actually send valid amr data to the payloader instead of 20
+	  zero-bytes
+	  - The mp4g payloader expects codec_data on the caps
+
+2008-02-12 21:36:40 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  win32/MANIFEST: Add libgstpng.dsp to MANIFEST.
+	  Original commit message from CVS:
+	  * win32/MANIFEST:
+	  Add libgstpng.dsp to MANIFEST.
+	  * win32/vs6/libgstaudiofx.dsp:
+	  Add new source files to VS project file.
+
+2008-02-12 13:34:52 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  sys/ximage/gstximagesrc.c: Initialise variables when opening the X display rather than in _start(), as the display ca...
+	  Original commit message from CVS:
+	  * sys/ximage/gstximagesrc.c:
+	  Initialise variables when opening the X display rather
+	  than in _start(), as the display can be opened before that.
+	  Fixes: #515985
+
+2008-02-12 12:22:48 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  sys/directdraw/gstdirectdrawsink.c: Properly chain up finalize functions. Fixes bug #515980.
+	  Original commit message from CVS:
+	  * sys/directdraw/gstdirectdrawsink.c:
+	  (gst_ddrawsurface_class_init), (gst_ddrawsurface_finalize),
+	  (gst_directdraw_sink_finalize):
+	  Properly chain up finalize functions. Fixes bug #515980.
+
+2008-02-12 11:38:54 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  sys/v4l2/v4l2src_calls.c: Chain up the finalize functions. Fixes bug #515984.
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2_buffer_finalize),
+	  (gst_v4l2_buffer_class_init), (gst_v4l2_buffer_pool_finalize),
+	  (gst_v4l2_buffer_pool_class_init):
+	  Chain up the finalize functions. Fixes bug #515984.
+
+2008-02-12 11:14:36 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  sys/ximage/ximageutil.c: Chain up in the finalize function for our custom buffer sub-class.
+	  Original commit message from CVS:
+	  * sys/ximage/ximageutil.c:
+	  Chain up in the finalize function for our custom
+	  buffer sub-class.
+	  Patch by: Sebastian Dröge  <slomo@circular-chaos.org>
+	  Fixes: #515706
+
+2008-02-12 11:12:43 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/debug/efence.c: Properly chain up finalize method. Fixes bug #515979.
+	  Original commit message from CVS:
+	  * gst/debug/efence.c: (gst_fenced_buffer_finalize),
+	  (gst_fenced_buffer_class_init):
+	  Properly chain up finalize method. Fixes bug #515979.
+
+2008-02-12 11:09:08 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  sys/ximage/gstximagesrc.c: Free allocated Damage memory before closing our connection to the
+	  Original commit message from CVS:
+	  * sys/ximage/gstximagesrc.c:
+	  Free allocated Damage memory before closing our connection to the
+	  X server. Fixes: #515706
+
+2008-02-12 05:21:46 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/souphttpsrc.c: Include glib/gprintf.h for g_vasprintf(). Fixes bug #515564.
+	  Original commit message from CVS:
+	  * tests/check/elements/souphttpsrc.c:
+	  Include glib/gprintf.h for g_vasprintf(). Fixes bug #515564.
+
+2008-02-12 05:14:16 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Add a few libjpeg suppressions and initialize a variable to make smokeenc valgrind clean. Fixes bug #515701.
+	  Original commit message from CVS:
+	  * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_chain):
+	  * tests/check/Makefile.am:
+	  * tests/check/gst-plugins-good.supp:
+	  Add a few libjpeg suppressions and initialize a variable to
+	  make smokeenc valgrind clean. Fixes bug #515701.
+
+2008-02-11 21:24:30 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/avi/gstavidemux.c: Revert patch which sends timestamps only on keyframes, as it breaks playback with current gst-...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  Revert patch which sends timestamps only on keyframes, as it
+	  breaks playback with current gst-ffmpeg.
+	  Fixes: #515562
+
+2008-02-11 14:01:52 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Close some memory leaks spotted by the unit test. Fixes bug #515697.
+	  Original commit message from CVS:
+	  * gst/multifile/gstmultifilesrc.c: (gst_multi_file_src_create):
+	  * tests/check/elements/multifile.c: (GST_START_TEST):
+	  Close some memory leaks spotted by the unit test. Fixes bug #515697.
+
+2008-02-11 13:48:03 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/gconf/gconf.c: Use and unset the GError when pipeline creation fails instead of simply leaking it. Fixes bug #515...
+	  Original commit message from CVS:
+	  * ext/gconf/gconf.c: (gst_gconf_render_bin_with_default):
+	  Use and unset the GError when pipeline creation fails instead of
+	  simply leaking it. Fixes bug #515704.
+
+2008-02-10 10:46:13 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/: Fix long description of audiofx elements. Fixes bug #515457.
+	  Original commit message from CVS:
+	  * gst/audiofx/audioamplify.c:
+	  * gst/audiofx/audiochebband.c:
+	  * gst/audiofx/audiocheblimit.c:
+	  * gst/audiofx/audiodynamic.c:
+	  * gst/audiofx/audioinvert.c:
+	  * gst/audiofx/audiopanorama.c:
+	  * gst/audiofx/audiowsincband.c:
+	  * gst/audiofx/audiowsinclimit.c:
+	  Fix long description of audiofx elements. Fixes bug #515457.
+
+2008-02-09 01:45:32 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Add a simple example application for the spectrum element, include it in the docs, and fix some documentation ambigui...
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * gst/spectrum/gstspectrum.c:
+	  * tests/examples/spectrum/.cvsignore:
+	  * tests/examples/spectrum/Makefile.am:
+	  * tests/examples/spectrum/spectrum-example.c:
+	  Add a simple example application for the spectrum element, include it
+	  in the docs, and fix some documentation ambiguities.
+	  Fixes: #348085
+
+2008-02-09 00:15:25 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/: Fix includes order
+	  Original commit message from CVS:
+	  * gst/equalizer/Makefile.am:
+	  * gst/spectrum/Makefile.am:
+	  Fix includes order
+	  * tests/check/Makefile.am:
+	  Exclude v4l2src from the states test - it takes too long to start.
+	  * tests/check/elements/spectrum.c:
+	  Make the test run properly with CK_FORK=no
+
+2008-02-08 15:32:36 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  add 3 new plugins to spec file
+	  Original commit message from CVS:
+	  add 3 new plugins to spec file
+
+2008-02-08 15:27:51 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* ChangeLog:
+	* gst/audiofx/Makefile.am:
+	  add missing header files for disting
+	  Original commit message from CVS:
+	  add missing header files for disting
+
+2008-02-08 15:20:31 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/matroska/matroska-demux.c: Flag keyframe and delta units correctly when dealign with a
+	  Original commit message from CVS:
+	  2008-02-08  Julien Moutte  <julien@fluendo.com>
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock): Flag
+	  keyframe and delta units correctly when dealign with a
+	  BlockGroup.
+	  Fixes: #514397
+
+2008-02-08 10:19:33 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  tests/check/elements/.cvsignore: Spell the new tests correctly in .cvsignore
+	  Original commit message from CVS:
+	  * tests/check/elements/.cvsignore:
+	  Spell the new tests correctly in .cvsignore
+
+2008-02-08 10:09:33 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/multifile/gstmultifilesrc.c: Need to use gsize here for the size, fixes compiler warning.
+	  Original commit message from CVS:
+	  * gst/multifile/gstmultifilesrc.c: (gst_multi_file_src_create):
+	  Need to use gsize here for the size, fixes compiler warning.
+	  * tests/examples/equalizer/.cvsignore:
+	  * tests/examples/equalizer/Makefile.am:
+	  * tests/examples/spectrum/.cvsignore:
+	  * tests/examples/spectrum/Makefile.am:
+	  Add missing files to fix the build.
+
+2008-02-08 04:25:32 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Move multifile plugin from -bad.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * docs/plugins/inspect/plugin-multifile.xml:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  Move multifile plugin from -bad.
+	  Fixes: #490283
+
+2008-02-08 03:44:12 +0000  David Schleef <ds@schleef.org>
+
+	  gst/multifile/: Use g_file_[sg]et_contents() instead of using stdio functions.
+	  Original commit message from CVS:
+	  * gst/multifile/gstmultifilesink.c:
+	  * gst/multifile/gstmultifilesrc.c:
+	  Use g_file_[sg]et_contents() instead of using stdio functions.
+	  Should be less error prone.
+	  * tests/check/elements/multifile.c:
+	  Create a temporary directory using standard functions instead of
+	  creating a directory in the current dir.
+
+2008-02-08 03:28:57 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Move spectrum plugin from -bad.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * docs/plugins/inspect/plugin-spectrum.xml:
+	  * gst/spectrum/Makefile.am:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/examples/Makefile.am:
+	  Move spectrum plugin from -bad.
+	  Move examples into tests/examples/spectrum.
+
+2008-02-08 02:56:12 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	  Mention bug 415627 fixed with previous commit
+	  Original commit message from CVS:
+	  Mention bug 415627 fixed with previous commit
+
+2008-02-08 02:49:20 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Move the equalizer plugin across from -bad
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-good-plugins.interfaces:
+	  * docs/plugins/inspect/plugin-equalizer.xml:
+	  * gst/equalizer/Makefile.am:
+	  * tests/check/Makefile.am:
+	  * tests/examples/Makefile.am:
+	  Move the equalizer plugin across from -bad
+	  * tests/check/elements/.cvsignore:
+	  Add equalizer, audiosincwband and audiosincwlimit
+	  * tests/check/elements/equalizer.c:
+	  Fix compiler warnings
+
+2008-02-08 02:48:54 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  docs/plugins/gst-plugins-bad-plugins.*: Remove equalizer plugin docs
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-bad-plugins.args:
+	  * docs/plugins/gst-plugins-bad-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-bad-plugins.interfaces:
+	  Remove equalizer plugin docs
+	  * tests/check/Makefile.am:
+	  Add GST_OPTION_CFLAGS, to get -Werror -Wall into the tests as for
+	  other modules.
+	  * tests/check/elements/multifile.c:
+	  * tests/check/elements/rganalysis.c:
+	  * tests/check/elements/rglimiter.c:
+	  Fix compiler warnings from -Wall -Werror
+
+2008-02-08 01:07:02 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Only build with DISABLE_DEPRECATED during the CVS cycle. Pre-releases are treated like releases and bui...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Only build with DISABLE_DEPRECATED during the CVS cycle. Pre-releases
+	  are treated like releases and build without it.
+
+2008-02-07 21:57:54 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Move the lpwsinc and bpwsinc elements from gst-plugins-bad into the audiofx plugin, and rename to audiowsinclimit and...
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  * gst/audiofx/Makefile.am:
+	  * gst/audiofx/audiofx.c:
+	  * gst/audiofx/audiowsincband.c:
+	  * gst/audiofx/audiowsincband.h:
+	  * gst/audiofx/audiowsinclimit.c:
+	  * gst/audiofx/audiowsinclimit.h:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/audiowsincband.c:
+	  * tests/check/elements/audiowsinclimit.c:
+	  Move the lpwsinc and bpwsinc elements from gst-plugins-bad into
+	  the audiofx plugin, and rename to audiowsinclimit and audiowsincband
+	  respectively.
+	  Fixes: #467666
+
+2008-02-07 21:17:36 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Return GST_FLOW_NOT_NEGOTIATED if we get a buffer without caps, and add a somewhat useful debug message. Plus test.
+	  Original commit message from CVS:
+	  * gst/icydemux/gsticydemux.c: (gst_icydemux_chain):
+	  * tests/check/elements/icydemux.c:
+	  Return GST_FLOW_NOT_NEGOTIATED if we get a buffer without
+	  caps, and add a somewhat useful debug message. Plus test.
+
+2008-02-07 19:13:56 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  gst/rtsp/gstrtspsrc.c: Include unistd.h only if HAVE_UNISTD_H is defined
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c:
+	  Include unistd.h only if HAVE_UNISTD_H is defined
+	  * win32/common/config.h.in:
+	  * win32/common/config.h:
+	  Define socklen_t as it seems it's not defined in default
+	  Visual Studio headers.
+	  * win32/vs6/libgstalpha.dsp:
+	  * win32/vs6/libgstapetag.dsp:
+	  * win32/vs6/libgstavi.dsp:
+	  * win32/vs6/libgstrtp.dsp:
+	  * win32/vs6/libgstrtsp.dsp:
+	  * win32/vs6/libgstvideomixer.dsp:
+	  Update project file dependencies and add new source files
+
+2008-02-07 16:38:55 +0000  Bjarne Rosengren <bjarne@axis.com>
+
+	  gst/matroska/ebml-write.c: Don't leak buffers when we don't push them downstream.
+	  Original commit message from CVS:
+	  Patch by: Bjarne Rosengren <bjarne at axis dot com>
+	  * gst/matroska/ebml-write.c: (gst_ebml_write_element_push):
+	  Don't leak buffers when we don't push them downstream.
+	  Fixes bug #514965.
+
+2008-02-07 13:48:20 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/multifile/gstmultifilesink.c: Add a fixme comment.
+	  Original commit message from CVS:
+	  * gst/multifile/gstmultifilesink.c:
+	  Add a fixme comment.
+	  * gst/selector/gstoutputselector.c:
+	  Fix same leak as in input-selector.
+	  * tests/icles/output-selector-test.c:
+	  Improve the test.
+
+2008-02-07 13:41:11 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/gstspectrum.c: Improve the docs.
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c:
+	  Improve the docs.
+
+2008-02-07 10:17:14 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Bump requirements to (good) released versions to avoid confusion and make implicit core requirement exp...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Bump requirements to (good) released versions to avoid
+	  confusion and make implicit core requirement explicit.
+
+2008-02-07 10:04:01 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/gstlpwsinc.c: Fix typo in the long description of the element.
+	  Original commit message from CVS:
+	  * gst/filter/gstlpwsinc.c:
+	  Fix typo in the long description of the element.
+
+2008-02-06 23:44:43 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Rename audiochebyshevfreqband -> audiochebband and audiochebyshevfreqlimit -> audiocheblimit and do the requisite CVS...
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  * gst/audiofx/Makefile.am:
+	  * gst/audiofx/audiochebband.c:
+	  * gst/audiofx/audiochebband.h:
+	  * gst/audiofx/audiocheblimit.c:
+	  * gst/audiofx/audiocheblimit.h:
+	  * gst/audiofx/audiochebyshevfreqband.c:
+	  * gst/audiofx/audiochebyshevfreqband.h:
+	  * gst/audiofx/audiochebyshevfreqlimit.c:
+	  * gst/audiofx/audiochebyshevfreqlimit.h:
+	  * gst/audiofx/audiofx.c:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/audiochebband.c:
+	  * tests/check/elements/audiocheblimit.c:
+	  * tests/check/elements/audiochebyshevfreqband.c:
+	  * tests/check/elements/audiochebyshevfreqlimit.c:
+	  Rename audiochebyshevfreqband -> audiochebband and
+	  audiochebyshevfreqlimit -> audiocheblimit and do the requisite CVS
+	  surgery.
+	  Closes: #491811
+
+2008-02-06 11:07:47 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  ext/soup/gstsouphttpsrc.c: Fix memory leak and improve debugging a bit.
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * ext/soup/gstsouphttpsrc.c: (gst_soup_http_src_got_chunk_cb),
+	  (gst_soup_http_src_create):
+	  Fix memory leak and improve debugging a bit.
+
+2008-02-05 17:59:24 +0000  orjan <orjanf@axis.com>
+
+	  gst/multipart/multipartmux.c: Fix caps memory leak. Fixes #514573.
+	  Original commit message from CVS:
+	  Patch by: orjan <orjanf at axis dot com>
+	  * gst/multipart/multipartmux.c: (gst_multipart_mux_collected):
+	  Fix caps memory leak. Fixes #514573.
+
+2008-02-04 12:07:14 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/avi/gstavidemux.c: If there's no entries in the subindex, don't try to do anything stupid, just return.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_subindex):
+	  If there's no entries in the subindex, don't try to do anything stupid,
+	  just return.
+
+2008-02-02 19:47:50 +0000  John Millikin <jmillikin@gmail.com>
+
+	  ext/flac/gstflacdec.c: Fix extraction of picture blocks with newer libflac versions again:
+	  Original commit message from CVS:
+	  Patch by: John Millikin <jmillikin at gmail dot com>
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_scan_for_last_block),
+	  (gst_flac_extract_picture_buffer), (gst_flac_dec_metadata_callback):
+	  Fix extraction of picture blocks with newer libflac versions again:
+	  FLAC__METADATA_TYPE_PICTURE is an enum, not a define (#513628).
+
+2008-02-02 18:06:19 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/check/Makefile.am: Add rtp-payloading test to VALGRIND_TO_FIX.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Add rtp-payloading test to VALGRIND_TO_FIX.
+	  * tests/check/elements/rtp-payloading.c:
+	  Add semicolons after GST_TEST_END so gst-indent gets the
+	  formatting right; make test less verbose in general, but
+	  more verbose in the error case (which should probably
+	  make the test fail anyway).
+
+2008-02-01 18:29:21 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  Add documentation for avisubtitle and change class to
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * gst/avi/gstavisubtitle.c:
+	  Add documentation for avisubtitle and change class to
+	  Codec/Parser/Subtitle
+
+2008-01-31 16:12:28 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  sys/v4l2/v4l2_calls.c: Treat ENOTTY (driver does not implement ioctl) the same as
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2_calls.c: (gst_v4l2_fill_lists):
+	  Treat ENOTTY (driver does not implement ioctl) the same as
+	  EINVAL since it implies there are no available standards.
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_probe_caps_for_format),
+	  (gst_v4l2src_get_nearest_size):
+	  Replace gst_v4l2src_get_size_limits with 2 calls to new function
+	  gst_v4l2src_get_nearest_size, and get it to use VIDIOC_S_FMT to
+	  probe if the driver does not support VIDIOC_TRY_FMT for whatever
+	  reason, and if we aren't yet actively capturing.
+	  * sys/v4l2/v4l2src_calls.h:
+	  Remove replaced function declaration.
+
+2008-01-31 16:03:48 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Bump plugins-base requirement to 0.10.16 for the gst_video_format_*
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Bump plugins-base requirement to 0.10.16 for the gst_video_format_*
+	  API.
+
+2008-01-31 09:50:31 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/soup/gstsouphttpsrc.c: Add changes to gstsouphttpsrc.c that were missing from last commit.
+	  Original commit message from CVS:
+	  * ext/soup/gstsouphttpsrc.c: (_do_init),
+	  (gst_soup_http_src_base_init), (gst_soup_http_src_class_init),
+	  (gst_soup_http_src_init), (gst_soup_http_src_dispose),
+	  (gst_soup_http_src_set_property), (gst_soup_http_src_get_property),
+	  (gst_soup_http_src_unicodify), (gst_soup_http_src_cancel_message),
+	  (gst_soup_http_src_queue_message),
+	  (gst_soup_http_src_add_range_header),
+	  (gst_soup_http_src_session_unpause_message),
+	  (gst_soup_http_src_session_pause_message),
+	  (gst_soup_http_src_session_close),
+	  (gst_soup_http_src_got_headers_cb),
+	  (gst_soup_http_src_got_body_cb), (gst_soup_http_src_finished_cb),
+	  (gst_soup_http_src_got_chunk_cb), (gst_soup_http_src_response_cb),
+	  (gst_soup_http_src_parse_status), (gst_soup_http_src_create),
+	  (gst_soup_http_src_start), (gst_soup_http_src_stop),
+	  (gst_soup_http_src_unlock), (gst_soup_http_src_unlock_stop),
+	  (gst_soup_http_src_get_size), (gst_soup_http_src_is_seekable),
+	  (gst_soup_http_src_do_seek), (gst_soup_http_src_set_location),
+	  (gst_soup_http_src_set_proxy), (gst_soup_http_src_uri_get_type),
+	  (gst_soup_http_src_uri_get_protocols),
+	  (gst_soup_http_src_uri_get_uri), (gst_soup_http_src_uri_set_uri),
+	  (gst_soup_http_src_uri_handler_init), (plugin_init):
+	  Add changes to gstsouphttpsrc.c that were missing from last commit.
+
+2008-01-31 08:57:16 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  Make coding style more consistent, including class renaming.
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-bad-plugins.args:
+	  * docs/plugins/gst-plugins-bad-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-bad-plugins.interfaces:
+	  * docs/plugins/inspect/plugin-soup.xml:
+	  (gst_soup_http_src_base_init), (gst_soup_http_src_class_init),
+	  (gst_soup_http_src_init), (gst_soup_http_src_dispose),
+	  (gst_soup_http_src_set_property), (gst_soup_http_src_get_property),
+	  (gst_soup_http_src_unicodify), (gst_soup_http_src_cancel_message),
+	  (gst_soup_http_src_queue_message),
+	  (gst_soup_http_src_add_range_header),
+	  (gst_soup_http_src_session_unpause_message),
+	  (gst_soup_http_src_session_pause_message),
+	  (gst_soup_http_src_session_close),
+	  (gst_soup_http_src_got_headers_cb),
+	  (gst_soup_http_src_got_body_cb), (gst_soup_http_src_finished_cb),
+	  (gst_soup_http_src_got_chunk_cb), (gst_soup_http_src_response_cb),
+	  (gst_soup_http_src_parse_status), (gst_soup_http_src_create),
+	  (gst_soup_http_src_start), (gst_soup_http_src_stop),
+	  (gst_soup_http_src_unlock), (gst_soup_http_src_unlock_stop),
+	  (gst_soup_http_src_get_size), (gst_soup_http_src_is_seekable),
+	  (gst_soup_http_src_do_seek), (gst_soup_http_src_set_location),
+	  (gst_soup_http_src_set_proxy), (gst_soup_http_src_uri_get_type),
+	  (gst_soup_http_src_uri_get_protocols),
+	  (gst_soup_http_src_uri_get_uri), (gst_soup_http_src_uri_set_uri),
+	  (gst_soup_http_src_uri_handler_init), (plugin_init):
+	  * ext/soup/gstsouphttpsrc.h:
+	  Make coding style more consistent, including class renaming.
+
+2008-01-31 00:03:26 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Fix typo.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Fix typo.
+
+2008-01-31 00:00:23 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/alpha/: Re-write the 'alpha' plugin to be BaseTransform based, simplifying some stuff, and making buffer-alloc an...
+	  Original commit message from CVS:
+	  * gst/alpha/Makefile.am:
+	  * gst/alpha/gstalpha.c:
+	  Re-write the 'alpha' plugin to be BaseTransform based, simplifying
+	  some stuff, and making buffer-alloc and resizing work automatically.
+	  No longer crashes on odd frame widths and heights, although there
+	  seems to be a disagreement with ffmpegcolorspace about what size
+	  an AYUV frame with odd height should be.
+
+2008-01-30 15:40:36 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  ext/soup/gstsouphttpsrc.c: Update documentation a bit.
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * ext/soup/gstsouphttpsrc.c:
+	  Update documentation a bit.
+	  * docs/plugins/gst-plugins-bad-plugins.args:
+	  * docs/plugins/gst-plugins-bad-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-bad-plugins.interfaces:
+	  * docs/plugins/gst-plugins-bad-plugins.prerequisites:
+	  * docs/plugins/inspect/plugin-alsaspdif.xml:
+	  * docs/plugins/inspect/plugin-dvb.xml:
+	  * docs/plugins/inspect/plugin-filter.xml:
+	  * docs/plugins/inspect/plugin-glimagesink.xml:
+	  * docs/plugins/inspect/plugin-mpegvideoparse.xml:
+	  * docs/plugins/inspect/plugin-quicktime.xml:
+	  * docs/plugins/inspect/plugin-rawparse.xml:
+	  * docs/plugins/inspect/plugin-replaygain.xml:
+	  * docs/plugins/inspect/plugin-sdl.xml:
+	  * docs/plugins/inspect/plugin-soundtouch.xml:
+	  * docs/plugins/inspect/plugin-soup.xml:
+	  * docs/plugins/inspect/plugin-spcdec.xml:
+	  * docs/plugins/inspect/plugin-spectrum.xml:
+	  * docs/plugins/inspect/plugin-speed.xml:
+	  * docs/plugins/inspect/plugin-speexresample.xml:
+	  * docs/plugins/inspect/plugin-switch.xml:
+	  * docs/plugins/inspect/plugin-videocrop.xml:
+	  Regenerate everything for the documentation changes we had.
+
+2008-01-30 13:29:15 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  ext/soup/gstsouphttpsrc.c: Let the proxy property default to the content of the $http_proxy environment variable.
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * ext/soup/gstsouphttpsrc.c: (gst_souphttp_src_init):
+	  Let the proxy property default to the content of the $http_proxy
+	  environment variable.
+
+2008-01-30 13:08:45 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  tests/check/: Add missing files for the unit test.
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * tests/check/test-cert.pem:
+	  * tests/check/test-key.pem:
+	  Add missing files for the unit test.
+
+2008-01-30 13:06:01 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  docs/plugins/: Add souphttpsrc to the docs.
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  Add souphttpsrc to the docs.
+	  * configure.ac:
+	  * ext/soup/gstsouphttpsrc.c: (gst_souphttp_src_class_init),
+	  (gst_souphttp_src_init), (gst_souphttp_src_dispose),
+	  (gst_souphttp_src_set_property), (gst_souphttp_src_get_property),
+	  (gst_souphttp_src_cancel_message),
+	  (gst_souphttp_src_queue_message),
+	  (gst_souphttp_src_add_range_header),
+	  (gst_souphttp_src_session_unpause_message),
+	  (gst_souphttp_src_session_pause_message),
+	  (gst_souphttp_src_session_close),
+	  (gst_souphttp_src_got_headers_cb), (gst_souphttp_src_got_body_cb),
+	  (gst_souphttp_src_finished_cb), (gst_souphttp_src_got_chunk_cb),
+	  (gst_souphttp_src_response_cb), (gst_souphttp_src_parse_status),
+	  (gst_souphttp_src_create), (gst_souphttp_src_start),
+	  (gst_souphttp_src_stop), (gst_souphttp_src_unlock),
+	  (gst_souphttp_src_unlock_stop), (gst_souphttp_src_get_size),
+	  (gst_souphttp_src_is_seekable), (gst_souphttp_src_do_seek),
+	  (gst_souphttp_src_set_location), (gst_souphttp_src_set_proxy),
+	  (plugin_init):
+	  * ext/soup/gstsouphttpsrc.h:
+	  Add support for libsoup2.4 and require it. Also implement redirection
+	  and manual proxy specification. Fixes bug #510708.
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/souphttpsrc.c:
+	  Add unit test for souphttpsrc.
+
+2008-01-29 18:43:32 +0000  Alessandro Decina <alessandro@nnva.org>
+
+	  ext/libpng/gstpngenc.*: Preallocate the output buffer so that g_memdup() and gst_buffer_merge() aren't needed anymore...
+	  Original commit message from CVS:
+	  Patch by: Alessandro Decina <alessandro at nnva dot org>
+	  * ext/libpng/gstpngenc.c: (user_write_data), (gst_pngenc_chain):
+	  * ext/libpng/gstpngenc.h:
+	  Preallocate the output buffer so that g_memdup() and
+	  gst_buffer_merge() aren't needed anymore. This greatly improves
+	  performances and fixes #512544.
+
+2008-01-29 18:24:28 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: GStreamer timestamps are PTS values while AVI only knows about DTS timestamps. Make sure we on...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_process_next_entry),
+	  (gst_avi_demux_stream_data):
+	  GStreamer timestamps are PTS values while AVI only knows about DTS
+	  timestamps. Make sure we only copy the DTS as the buffer timestamp when
+	  we are dealing with a key frame.
+
+2008-01-29 15:45:48 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/check/: Add add testsuite for the rtp-payloader that tries simulating dataflow. Needs more test data.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/rtp-payloading.c:
+	  Add add testsuite for the rtp-payloader that tries simulating
+	  dataflow. Needs more test data.
+
+2008-01-29 15:27:02 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/check/elements/alphacolor.c: Remove two unused variables.
+	  Original commit message from CVS:
+	  * tests/check/elements/alphacolor.c:
+	  Remove two unused variables.
+
+2008-01-28 12:17:02 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/rtsp/gstrtspsrc.c: Use g_ascii_strtoll() instead of atoll, which is only available in C99.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_parse_rtpinfo):
+	  Use g_ascii_strtoll() instead of atoll, which is only
+	  available in C99.
+
+2008-01-26 16:19:26 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/: Don't implement get_unit_size() ourselves, the GstAudioFilter base class already does this for us.
+	  Original commit message from CVS:
+	  * gst/filter/gstbpwsinc.c: (gst_bpwsinc_class_init):
+	  * gst/filter/gstlpwsinc.c: (gst_lpwsinc_class_init):
+	  Don't implement get_unit_size() ourselves, the GstAudioFilter base
+	  class already does this for us.
+
+2008-01-25 10:53:17 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  gst/rtp/: Add MPEG2 video payloader
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c:
+	  * gst/rtp/gstrtpmpvpay.c:
+	  * gst/rtp/gstrtpmpvpay.h:
+	  Add MPEG2 video payloader
+
+2008-01-23 17:05:32 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/level/gstlevel.c: Use #include <math.h> instead of #include "math.h".
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c:
+	  Use #include <math.h> instead of #include "math.h".
+
+2008-01-21 19:41:45 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  tests/check/Makefile.am: Fix up some CFLAGS sets.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Fix up some CFLAGS sets.
+	  Don't include gconfvideosrc in the states test.
+	  * tests/check/elements/autodetect.c: (GST_START_TEST):
+	  Add some error strings to fail_unless arguments to fix some weird
+	  compiler errors on Solaris.
+
+2008-01-21 19:35:58 +0000  Brian Cameron <brian.cameron@sun.com>
+
+	  configure.ac: Detect video4linux headers on Solaris too.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Detect video4linux headers on Solaris too.
+	  * sys/v4l2/gstv4l2colorbalance.h:
+	  * sys/v4l2/gstv4l2object.h:
+	  * sys/v4l2/v4l2_calls.c:
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2_buffer_finalize),
+	  (gst_v4l2_buffer_new):
+	  Make v4l2 build on Solaris.
+	  Patch by: Brian Cameron  <brian.cameron at sun dot com>
+	  Fixes: #510505
+
+2008-01-21 11:46:19 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/gst-plugins-good-plugins-docs.sgml: Update list from (still local) scanning script.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  Update list from (still local) scanning script.
+
+2008-01-21 09:57:07 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/: Add symbols from -unused.txt to the right place.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  Add symbols from -unused.txt to the right place.
+	  * gst/dvdspu/gstdvdspu.c:
+	  * gst/dvdspu/gstdvdspu.h:
+	  Coherent namespace usage.
+	  * gst/spectrum/gstspectrum.c:
+	  Fix broken XML fragment in doc snippet even more.
+
+2008-01-21 07:54:02 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/Makefile.am: Update include list.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  Update include list.
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  Update xml includes.
+	  * docs/plugins/inspect/plugin-alsaspdif.xml:
+	  * docs/plugins/inspect/plugin-amrwb.xml:
+	  * docs/plugins/inspect/plugin-bayer.xml:
+	  * docs/plugins/inspect/plugin-bz2.xml:
+	  * docs/plugins/inspect/plugin-cdxaparse.xml:
+	  * docs/plugins/inspect/plugin-dtsdec.xml:
+	  * docs/plugins/inspect/plugin-dvbsrc.xml:
+	  * docs/plugins/inspect/plugin-dvdspu.xml:
+	  * docs/plugins/inspect/plugin-equalizer.xml:
+	  * docs/plugins/inspect/plugin-faac.xml:
+	  * docs/plugins/inspect/plugin-faad.xml:
+	  * docs/plugins/inspect/plugin-fbdevsink.xml:
+	  * docs/plugins/inspect/plugin-festival.xml:
+	  * docs/plugins/inspect/plugin-filter.xml:
+	  * docs/plugins/inspect/plugin-flvdemux.xml:
+	  * docs/plugins/inspect/plugin-freeze.xml:
+	  * docs/plugins/inspect/plugin-gsm.xml:
+	  * docs/plugins/inspect/plugin-gstinterlace.xml:
+	  * docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	  * docs/plugins/inspect/plugin-h264parse.xml:
+	  * docs/plugins/inspect/plugin-interleave.xml:
+	  * docs/plugins/inspect/plugin-ladspa.xml:
+	  * docs/plugins/inspect/plugin-metadata.xml:
+	  * docs/plugins/inspect/plugin-modplug.xml:
+	  * docs/plugins/inspect/plugin-mpeg4videoparse.xml:
+	  * docs/plugins/inspect/plugin-mpegtsparse.xml:
+	  * docs/plugins/inspect/plugin-mpegvideoparse.xml:
+	  * docs/plugins/inspect/plugin-musicbrainz.xml:
+	  * docs/plugins/inspect/plugin-mve.xml:
+	  * docs/plugins/inspect/plugin-nsfdec.xml:
+	  * docs/plugins/inspect/plugin-nuvdemux.xml:
+	  * docs/plugins/inspect/plugin-qtdemux.xml:
+	  * docs/plugins/inspect/plugin-quicktime.xml:
+	  * docs/plugins/inspect/plugin-real.xml:
+	  * docs/plugins/inspect/plugin-replaygain.xml:
+	  * docs/plugins/inspect/plugin-sdl.xml:
+	  * docs/plugins/inspect/plugin-sdp.xml:
+	  * docs/plugins/inspect/plugin-spectrum.xml:
+	  * docs/plugins/inspect/plugin-speed.xml:
+	  * docs/plugins/inspect/plugin-speexresample.xml:
+	  * docs/plugins/inspect/plugin-stereo.xml:
+	  * docs/plugins/inspect/plugin-switch.xml:
+	  * docs/plugins/inspect/plugin-timidity.xml:
+	  * docs/plugins/inspect/plugin-tta.xml:
+	  * docs/plugins/inspect/plugin-videocrop.xml:
+	  * docs/plugins/inspect/plugin-videoparse.xml:
+	  * docs/plugins/inspect/plugin-videosignal.xml:
+	  * docs/plugins/inspect/plugin-vmnc.xml:
+	  * docs/plugins/inspect/plugin-wildmidi.xml:
+	  * docs/plugins/inspect/plugin-x264.xml:
+	  * docs/plugins/inspect/plugin-xingheader.xml:
+	  * docs/plugins/inspect/plugin-xvid.xml:
+	  * docs/plugins/inspect/plugin-y4menc.xml:
+	  Regenerate files.
+	  * gst/spectrum/gstspectrum.c:
+	  Fix broken XML fragment in doc snippet.
+	  * tests/check/elements/.cvsignore:
+	  Add test binary to ignores.
+
+2008-01-20 05:07:52 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  ext/soup/gstsouphttpsrc.c: Report the size of the stream as the total size instead of the remaining Content-Length, w...
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * ext/soup/gstsouphttpsrc.c: (soup_got_headers):
+	  Report the size of the stream as the total size instead of
+	  the remaining Content-Length, which is wrong after a seek.
+
+2008-01-19 14:59:08 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	* ChangeLog:
+	  Add bug number to the latest entry
+	  Original commit message from CVS:
+	  Add bug number to the latest entry
+
+2008-01-19 14:53:58 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/wavparse/gstwavparse.c: Set variable to NULL after freeing it to prevent double frees or make failures by another...
+	  Original commit message from CVS:
+	  Based on a patch by:
+	  Victor STINNER <victor dot stinner at haypocalc dot com>
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_stream_headers):
+	  Set variable to NULL after freeing it to prevent double frees
+	  or make failures by another use of it afterwards more obvious
+	  and fix use of it after the freeing.
+
+2008-01-19 14:34:50 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  ext/soup/gstsouphttpsrc.c: Correctly set duration on the GstBaseSrc segment when we know it to fix failing the durati...
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * ext/soup/gstsouphttpsrc.c: (soup_got_headers):
+	  Correctly set duration on the GstBaseSrc segment when we know it
+	  to fix failing the duration query.
+
+2008-01-18 13:40:38 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  gst/udp/gstmultiudpsink.c: use GST_WARNING for logging
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c:
+	  use GST_WARNING for logging
+
+2008-01-18 10:05:53 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/multifile/gstmultifilesrc.c: Fix memory leak spotted by the unit test.
+	  Original commit message from CVS:
+	  * gst/multifile/gstmultifilesrc.c: (gst_multi_file_src_create):
+	  Fix memory leak spotted by the unit test.
+
+2008-01-18 10:04:25 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  gst/udp/gstmultiudpsink.c: Don't try to leave a multicast group with an invalid socket
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c:
+	  Don't try to leave a multicast group with an invalid socket
+
+2008-01-18 08:49:59 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/: Add some minimal tests for the equalizer plugin.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/equalizer.c: (setup_equalizer),
+	  (cleanup_equalizer), (GST_START_TEST), (equalizer_suite), (main):
+	  Add some minimal tests for the equalizer plugin.
+
+2008-01-18 07:03:23 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/equalizer/gstiirequalizer.c: Unparent all bands from the equalizer when finalizing to stop leaking	them.
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer.c: (gst_iir_equalizer_finalize):
+	  Unparent all bands from the equalizer when finalizing to stop
+	  leaking	them.
+
+2008-01-18 05:32:26 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/soup/gstsouphttpsrc.c: Add support for WebDAV.
+	  Original commit message from CVS:
+	  * ext/soup/gstsouphttpsrc.c: (gst_souphttp_src_uri_get_protocols):
+	  Add support for WebDAV.
+
+2008-01-18 05:24:39 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  ext/soup/gstsouphttpsrc.*: Add support for seeking to souphttpsrc. Fixes bug #502335.
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * ext/soup/gstsouphttpsrc.c: (gst_souphttp_src_class_init),
+	  (gst_souphttp_src_init), (gst_souphttp_src_create),
+	  (gst_souphttp_src_is_seekable), (gst_souphttp_src_do_seek),
+	  (soup_add_range_header), (soup_got_headers), (soup_got_chunk):
+	  * ext/soup/gstsouphttpsrc.h:
+	  Add support for seeking to souphttpsrc. Fixes bug #502335.
+
+2008-01-17 21:23:32 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacdec.c: where the picture metadata defines and structs don't exist yet.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c:
+	  Fix compilation against flac 1.1.2 (as on debian stable), where
+	  the picture metadata defines and structs don't exist yet.
+	  Fixes #509301.
+
+2008-01-17 11:13:16 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/udp/gstmultiudpsink.*: Add property to automatically join a multicast group or not. This can be useful when shari...
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_class_init),
+	  (gst_multiudpsink_init), (gst_multiudpsink_set_property),
+	  (gst_multiudpsink_get_property), (gst_multiudpsink_init_send),
+	  (gst_multiudpsink_add_internal), (gst_multiudpsink_remove):
+	  * gst/udp/gstmultiudpsink.h:
+	  Add property to automatically join a multicast group or not. This can be
+	  useful when sharing a socket between multiple elements.
+	  Fixes #509531.
+
+2008-01-16 21:53:41 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/videomixer/Makefile.am: Add controller flags.
+	  Original commit message from CVS:
+	  * gst/videomixer/Makefile.am:
+	  Add controller flags.
+
+2008-01-16 20:17:08 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/videomixer/videomixer.c: Also commit the missing gst_object_sync_values().
+	  Original commit message from CVS:
+	  * gst/videomixer/videomixer.c:
+	  Also commit the missing gst_object_sync_values().
+
+2008-01-16 08:11:46 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/Makefile.am: Remove duplicate entry.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  Remove duplicate entry.
+
+2008-01-15 16:52:10 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/: Add 3 more plugins to docs.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/inspect/plugin-gamma.xml:
+	  * docs/plugins/inspect/plugin-monoscope.xml:
+	  * docs/plugins/inspect/plugin-video4linux2.xml:
+	  Add 3 more plugins to docs.
+
+2008-01-15 16:04:44 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Revert previous change caused by a file that got stuck on an old revision.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * sys/osxvideo/osxvideosink.h:
+	  Revert previous change caused by a file that got stuck on an old
+	  revision.
+
+2008-01-15 15:40:58 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Re-add multipartdemux to the docs. Last round of section cleanup.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * gst/multipart/Makefile.am:
+	  * gst/multipart/multipartdemux.c:
+	  * gst/multipart/multipartdemux.h:
+	  * gst/multipart/multipartmux.c:
+	  * gst/multipart/multipartmux.h:
+	  Re-add multipartdemux to the docs. Last round of section cleanup.
+
+2008-01-15 15:22:41 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Managed to resolve most unused declarations. Filed a bug for one left.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * sys/osxaudio/gstosxaudiosink.h:
+	  * sys/osxvideo/osxvideosink.h:
+	  Managed to resolve most unused declarations. Filed a bug for one left.
+
+2008-01-15 08:03:49 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/gst-plugins-good-plugins-sections.txt: Cleanup section file.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  Cleanup section file.
+
+2008-01-15 07:42:51 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/: Update plugin docs.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/gst-plugins-good-plugins.signals:
+	  * docs/plugins/inspect/plugin-alaw.xml:
+	  * docs/plugins/inspect/plugin-alpha.xml:
+	  * docs/plugins/inspect/plugin-alphacolor.xml:
+	  * docs/plugins/inspect/plugin-annodex.xml:
+	  * docs/plugins/inspect/plugin-apetag.xml:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  * docs/plugins/inspect/plugin-auparse.xml:
+	  * docs/plugins/inspect/plugin-autodetect.xml:
+	  * docs/plugins/inspect/plugin-avi.xml:
+	  * docs/plugins/inspect/plugin-cairo.xml:
+	  * docs/plugins/inspect/plugin-cdio.xml:
+	  * docs/plugins/inspect/plugin-cutter.xml:
+	  * docs/plugins/inspect/plugin-debug.xml:
+	  * docs/plugins/inspect/plugin-dv.xml:
+	  * docs/plugins/inspect/plugin-efence.xml:
+	  * docs/plugins/inspect/plugin-effectv.xml:
+	  * docs/plugins/inspect/plugin-flac.xml:
+	  * docs/plugins/inspect/plugin-flxdec.xml:
+	  * docs/plugins/inspect/plugin-gconfelements.xml:
+	  * docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	  * docs/plugins/inspect/plugin-goom.xml:
+	  * docs/plugins/inspect/plugin-halelements.xml:
+	  * docs/plugins/inspect/plugin-icydemux.xml:
+	  * docs/plugins/inspect/plugin-id3demux.xml:
+	  * docs/plugins/inspect/plugin-jpeg.xml:
+	  * docs/plugins/inspect/plugin-ladspa.xml:
+	  * docs/plugins/inspect/plugin-level.xml:
+	  * docs/plugins/inspect/plugin-matroska.xml:
+	  * docs/plugins/inspect/plugin-mulaw.xml:
+	  * docs/plugins/inspect/plugin-multipart.xml:
+	  * docs/plugins/inspect/plugin-navigationtest.xml:
+	  * docs/plugins/inspect/plugin-png.xml:
+	  * docs/plugins/inspect/plugin-quicktime.xml:
+	  * docs/plugins/inspect/plugin-rtp.xml:
+	  * docs/plugins/inspect/plugin-rtsp.xml:
+	  * docs/plugins/inspect/plugin-shout2send.xml:
+	  * docs/plugins/inspect/plugin-smpte.xml:
+	  * docs/plugins/inspect/plugin-speex.xml:
+	  * docs/plugins/inspect/plugin-taglib.xml:
+	  * docs/plugins/inspect/plugin-udp.xml:
+	  * docs/plugins/inspect/plugin-videobalance.xml:
+	  * docs/plugins/inspect/plugin-videobox.xml:
+	  * docs/plugins/inspect/plugin-videocrop.xml:
+	  * docs/plugins/inspect/plugin-videoflip.xml:
+	  * docs/plugins/inspect/plugin-videomixer.xml:
+	  * docs/plugins/inspect/plugin-wavenc.xml:
+	  * docs/plugins/inspect/plugin-wavpack.xml:
+	  * docs/plugins/inspect/plugin-wavparse.xml:
+	  Update plugin docs.
+	  * gst/videomixer/Makefile.am:
+	  * gst/videomixer/videomixer.c:
+	  * gst/videomixer/videomixer.h:
+	  * gst/videomixer/videomixerpad.h:
+	  Split out header to fix warnings from the doc-build.
+
+2008-01-14 12:35:23 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  As found by: Tommi Myöhänen <ext-tommi.myohanen nokia com>
+	  Original commit message from CVS:
+	  As found by: Tommi Myöhänen <ext-tommi.myohanen nokia com>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_parse_rtpinfo):
+	  Use atoll to parse the rtptime with enough precision. Fixes #509329.
+
+2008-01-14 12:11:43 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/: Initialise variables to work around (false) 'foo might be used uninitialized in this function' warnings by gcc-...
+	  Original commit message from CVS:
+	  * gst/avi/gstavisubtitle.c: (gst_avi_subtitle_extract_file):
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send):
+	  Initialise variables to work around (false) 'foo might be used
+	  uninitialized in this function' warnings by gcc-3.3.3 (#509298).
+
+2008-01-12 02:32:35 +0000  David Schleef <ds@schleef.org>
+
+	  Ignore more files for the buildbot.
+	  Original commit message from CVS:
+	  * docs/plugins/.cvsignore:
+	  * tests/check/pipelines/.cvsignore:
+	  Ignore more files for the buildbot.
+
+2008-01-11 21:08:59 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Generate the image-type values correctly. Leave them out of the caps when outputting a "preview image" tag, since it ...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_extract_picture_buffer):
+	  * gst/id3demux/id3v2frames.c: (parse_picture_frame):
+	  Generate the image-type values correctly. Leave them out of the caps
+	  when outputting a "preview image" tag, since it only makes sense
+	  to have one of those - the type is irrelevant.
+	  * sys/sunaudio/gstsunaudiomixerctrl.c:
+	  (gst_sunaudiomixer_ctrl_open):
+	  If we can, mark the mixer multiple open when we use it, in case
+	  (for some reason) the process wants to open it again elsewhere.
+
+2008-01-11 19:16:53 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/check/elements/: It's "endianness", not "endianess". Fixes unit tests.
+	  Original commit message from CVS:
+	  * tests/check/elements/rganalysis.c: (test_buffer_const_float_mono),
+	  (test_buffer_const_float_stereo), (test_buffer_const_int16_mono),
+	  (test_buffer_const_int16_stereo), (test_buffer_square_float_mono),
+	  (test_buffer_square_float_stereo), (test_buffer_square_int16_mono),
+	  (test_buffer_square_int16_stereo):
+	  * tests/check/elements/rglimiter.c: (create_test_buffer):
+	  * tests/check/elements/rgvolume.c: (test_buffer_new):
+	  It's "endianness", not "endianess". Fixes unit tests.
+
+2008-01-11 18:56:06 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	* tests/check/pipelines/.cvignore:
+	  ignore some more
+	  Original commit message from CVS:
+	  ignore some more
+
+2008-01-11 18:54:31 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	* tests/check/elements/.gitignore:
+	  ignore some more
+	  Original commit message from CVS:
+	  ignore some more
+
+2008-01-11 17:21:30 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtp/: Fix the clock rate to 90000 as required by the RFC.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtp/gstrtptheoradepay.c: (gst_rtp_theora_depay_setcaps):
+	  * gst/rtp/gstrtptheorapay.c:
+	  Fix the clock rate to 90000 as required by the RFC.
+	  Fixes #508644.
+
+2008-01-11 17:12:37 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/check/elements/icydemux.c: Don't use deprecated GST_PLUGIN_DEFINE_STATIC.
+	  Original commit message from CVS:
+	  * tests/check/elements/icydemux.c: (GST_START_TEST), (icydemux_suite):
+	  Don't use deprecated GST_PLUGIN_DEFINE_STATIC.
+
+2008-01-10 12:25:44 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  autogen.sh: Add -Wno-portability to the automake parameters to stop warnings about GNU make extensions being used. We...
+	  Original commit message from CVS:
+	  * autogen.sh:
+	  Add -Wno-portability to the automake parameters to stop warnings
+	  about GNU make extensions being used. We require GNU make in almost
+	  every Makefile anyway.
+	  * configure.ac:
+	  Use AM_PROG_CC_C_O as a compiler that accepts both -c and -o
+	  at the same time is required for per target flags.
+
+2008-01-09 15:28:29 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/videomixer/videomixer.c: Fix error from my last commit.
+	  Original commit message from CVS:
+	  * gst/videomixer/videomixer.c: (gst_videomixer_init):
+	  Fix error from my last commit.
+
+2008-01-09 15:20:19 +0000  Tommi Myöhänen <ext-tommi.myohanen@nokia.com>
+
+	  gst/id3demux/id3v2frames.c: Make sure the ISO 639-X language code in ID3v2 COMM frames so we don't end up with non-UT...
+	  Original commit message from CVS:
+	  Based on patch by: Tommi Myöhänen <ext-tommi.myohanen nokia com>
+	  * gst/id3demux/id3v2frames.c: (parse_comment_frame):
+	  Make sure the ISO 639-X language code in ID3v2 COMM frames
+	  is actually valid UTF-8 (or rather: ASCII), so we don't end
+	  up with non-UTF8 strings in tags if there's garbage in the
+	  language field. Also make sure the language code is always
+	  lower case. Fixes: #508291.
+
+2008-01-09 13:55:28 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ChangeLog: Fix ChangeLog typo.
+	  Original commit message from CVS:
+	  * ChangeLog:
+	  Fix ChangeLog typo.
+
+2008-01-09 13:50:09 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Makefile.am: Include lcov.mak to allow builging coverage reports. Guard check-torture target like in the other packages.
+	  Original commit message from CVS:
+	  * Makefile.am:
+	  Include lcov.mak to allow builging coverage reports. Guard
+	  check-torture target like in the other packages.
+
+2008-01-09 12:33:58 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/videomixer/videomixer.c: Implement GstChildProxy interface.
+	  Original commit message from CVS:
+	  reviewed by: Edward Hervey  <edward.hervey@collabora.co.uk>
+	  * gst/videomixer/videomixer.c:
+	  (gst_videomixer_set_master_geometry), (_do_init),
+	  (gst_videomixer_child_proxy_get_child_by_index),
+	  (gst_videomixer_child_proxy_get_children_count),
+	  (gst_videomixer_child_proxy_init), (gst_videomixer_reset),
+	  (gst_videomixer_init), (gst_videomixer_request_new_pad),
+	  (gst_videomixer_release_pad), (gst_videomixer_fill_queues):
+	  Implement GstChildProxy interface.
+	  Send newsegment at the right moment
+	  Fixes #488879
+
+2008-01-09 12:01:14 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/alpha/: Make the various properties of 'alpha' controllable. This allows doing niceties like fade-in/fade-out.
+	  Original commit message from CVS:
+	  * gst/alpha/Makefile.am:
+	  * gst/alpha/gstalpha.c: (gst_alpha_class_init), (gst_alpha_init),
+	  (gst_alpha_sink_event), (gst_alpha_chain),
+	  (gst_alpha_change_state), (plugin_init):
+	  Make the various properties of 'alpha' controllable. This allows doing
+	  niceties like fade-in/fade-out.
+
+2008-01-09 11:11:01 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/rtp/: Remove copy/paste unused code (property setters and getter) found by the coverage suite (yay, saves ~20k on...
+	  Original commit message from CVS:
+	  * gst/rtp/gstasteriskh263.c:
+	  * gst/rtp/gstrtpL16depay.c:
+	  * gst/rtp/gstrtpac3depay.c:
+	  * gst/rtp/gstrtpamrpay.c:
+	  * gst/rtp/gstrtpdepay.c:
+	  * gst/rtp/gstrtpgsmdepay.c:
+	  * gst/rtp/gstrtph263depay.c:
+	  * gst/rtp/gstrtph263pdepay.c:
+	  * gst/rtp/gstrtph263ppay.c:
+	  * gst/rtp/gstrtph264depay.c:
+	  * gst/rtp/gstrtph264pay.c:
+	  * gst/rtp/gstrtpmp2tdepay.c:
+	  * gst/rtp/gstrtpmp4adepay.c:
+	  * gst/rtp/gstrtpmp4gdepay.c:
+	  * gst/rtp/gstrtpmp4gpay.c:
+	  * gst/rtp/gstrtpmp4vdepay.c:
+	  * gst/rtp/gstrtpmpadepay.c:
+	  * gst/rtp/gstrtpmpvdepay.c:
+	  * gst/rtp/gstrtpsv3vdepay.c:
+	  * gst/rtp/gstrtptheoradepay.c:
+	  * gst/rtp/gstrtptheorapay.c:
+	  * gst/rtp/gstrtpvorbisdepay.c:
+	  * gst/rtp/gstrtpvorbispay.c:
+	  Remove copy/paste unused code (property setters and getter) found by
+	  the coverage suite (yay, saves ~20k on disk).
+
+2008-01-08 20:03:30 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-mux.c: Also fix up pad templates to indicate that image/jpeg doesn't absolutely require the fra...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c: (COMMON_VIDEO_CAPS_NO_FRAMERATE),
+	  (videosink_templ):
+	  Also fix up pad templates to indicate that image/jpeg doesn't
+	  absolutely require the framerate property to be set (#504081).
+
+2008-01-08 19:57:23 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  gst/matroska/matroska-mux.*: Keep track of first and last timestamps for each incoming stream, so we can calculate th...
+	  Original commit message from CVS:
+	  Based on patch by: Wouter Cloetens  <wouter at mind be>
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_video_pad_setcaps),
+	  (gst_matroska_mux_request_new_pad), (gst_matroska_mux_release_pad),
+	  (gst_matroska_mux_finish), (gst_matroska_mux_collected):
+	  * gst/matroska/matroska-mux.h:
+	  Keep track of first and last timestamps for each incoming stream,
+	  so we can calculate the total duration for live sources and other
+	  input where we can't query the duration from the start or where
+	  there's no constant framerate from which we can deduce the
+	  duration; also use calculated/observed duration if it is bigger
+	  than the previously queried duration. Furthermore, use
+	  gst_pad_query_peer_duration() and take into account that it may
+	  return TRUE but still a duration of CLOCK_TIME_NONE, which easily
+	  screws up comparisons when using unsigned integers. Fixes #504081.
+
+2008-01-08 14:58:18 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Make elements GST_BUFFER_FLAG_GAP aware and call gst_base_transform_set_gap_aware for this.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/audiofx/audioamplify.c:
+	  (gst_audio_amplify_clipping_method_get_type),
+	  (gst_audio_amplify_init), (gst_audio_amplify_transform_ip):
+	  * gst/audiofx/audiodynamic.c: (gst_audio_dynamic_init),
+	  (gst_audio_dynamic_transform_ip):
+	  * gst/audiofx/audioinvert.c: (gst_audio_invert_init),
+	  (gst_audio_invert_transform_ip):
+	  * gst/audiofx/audiopanorama.c: (gst_audio_panorama_init),
+	  (gst_audio_panorama_transform):
+	  * gst/level/gstlevel.c: (gst_level_init):
+	  Make elements GST_BUFFER_FLAG_GAP aware and call
+	  gst_base_transform_set_gap_aware for this.
+	  Bump core requirement to CVS.
+	  * gst/audiofx/audiochebyshevfreqband.c:
+	  (gst_audio_chebyshev_freq_band_transform_ip):
+	  * gst/audiofx/audiochebyshevfreqlimit.c:
+	  (gst_audio_chebyshev_freq_limit_transform_ip):
+	  Also sync GObject properties to the controller if operating
+	  in passthrough mode.
+
+2008-01-07 16:41:00 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/directdraw/gstdirectdrawsink.c: FALSE is not a gpointer.
+	  Original commit message from CVS:
+	  * sys/directdraw/gstdirectdrawsink.c:
+	  (gst_directdraw_sink_window_thread):
+	  FALSE is not a gpointer.
+
+2008-01-05 21:20:08 +0000  Julien Moutte <julien@moutte.net>
+
+	  sys/directdraw/gstdirectdrawsink.c: Make sure we create our internal window only when we need it. That will give a ch...
+	  Original commit message from CVS:
+	  2008-01-05  Julien Moutte  <julien@fluendo.com>
+	  * sys/directdraw/gstdirectdrawsink.c:
+	  (gst_directdraw_sink_set_window_id),
+	  (gst_directdraw_sink_set_caps),
+	  (gst_directdraw_sink_change_state),
+	  (gst_directdraw_sink_buffer_alloc),
+	  (gst_directdraw_sink_draw_borders),
+	  (gst_directdraw_sink_show_frame),
+	  (gst_directdraw_sink_setup_ddraw),
+	  (gst_directdraw_sink_window_thread),
+	  (gst_directdraw_sink_get_ddrawcaps),
+	  (gst_directdraw_sink_surface_create): Make sure we create our
+	  internal window only when we need it. That will give a chance to
+	  the application to get the prepare-xwindow-id bus message. Draw
+	  black borders when keeping aspect ratio. Handle the case where
+	  our
+	  rendering window disappears (closed or errors) like other sinks
+	  do. Various 80 columns fixes, improve state change order. That
+	  element could need some more love.
+
+2008-01-04 18:30:21 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/taglib/: Remove useless typedefs without new type name. Fixes a warning with gcc 4.3.
+	  Original commit message from CVS:
+	  * ext/taglib/gstapev2mux.h:
+	  * ext/taglib/gstid3v2mux.h:
+	  Remove useless typedefs without new type name. Fixes a warning with
+	  gcc 4.3.
+
+2008-01-03 12:26:03 +0000  John Millikin <jmillikin@gmail.com>
+
+	  ext/flac/gstflacdec.c: Emit metadata messages when a PICTURE block is encountered.
+	  Original commit message from CVS:
+	  Patch by: John Millikin <jmillikin at gmail dot com>
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_setup_seekable_decoder),
+	  (gst_flac_dec_setup_stream_decoder),
+	  (gst_flac_normalize_picture_mime_type),
+	  (gst_flac_extract_picture_buffer),
+	  (gst_flac_dec_metadata_callback):
+	  Emit metadata messages when a PICTURE block is encountered.
+	  Fixes #506715.
+
+2008-01-02 13:54:10 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  gst/avi/gstavi.c: increase rank because no known issues anymore ...
+	  Original commit message from CVS:
+	  * gst/avi/gstavi.c:
+	  increase rank because no known issues anymore ...
+	  * gst/avi/gstavisubtitle.c:
+	  send subtitle name to the srcpad
+
+2007-12-31 13:27:32 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Implement redirect for the DESCRIBE reply. Fixes #506025.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send), (gst_rtspsrc_open):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Implement redirect for the DESCRIBE reply. Fixes #506025.
+
+2007-12-29 16:48:33 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/flac/gstflacdec.c: Fix 'xyz may be used uninitialized' compiler warnings caused by broken g_assert_not_reached() ...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_write):
+	  Fix 'xyz may be used uninitialized' compiler warnings caused
+	  by broken g_assert_not_reached() macro in GLib-2.15.x and don't
+	  abort() in any case but properly report the error.
+
+2007-12-28 11:44:28 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/soup/: Use gst_tag_freeform_string_to_utf8() and post radio station info as tags on the bus.
+	  Original commit message from CVS:
+	  * ext/soup/Makefile.am:
+	  * ext/soup/gstsouphttpsrc.c: (gst_souphttp_src_get_property),
+	  (gst_souphttp_src_unicodify), (soup_got_headers):
+	  Use gst_tag_freeform_string_to_utf8() and post radio station
+	  info as tags on the bus.
+
+2007-12-26 16:03:57 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Fix 'xyz may be used uninitialized' compiler warnings caused by broken g_assert_not_reached() macro in GLib-2.15.x (i...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_loop):
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_chain):
+	  * sys/ximage/gstximagesrc.c: (composite_pixel):
+	  Fix 'xyz may be used uninitialized' compiler warnings caused
+	  by broken g_assert_not_reached() macro in GLib-2.15.x (it's
+	  not really nice to abort in any case). Fixes #505745.
+
+2007-12-20 17:07:22 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/: Ignore more.
+	  Original commit message from CVS:
+	  * gst/equalizer/.cvsignore:
+	  * gst/switch/.cvsignore:
+	  Ignore more.
+
+2007-12-18 23:17:14 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/check/elements/avisubtitle.c: Small unit test fix (has no practical impact at the moment, since we're only feed...
+	  Original commit message from CVS:
+	  * tests/check/elements/avisubtitle.c: (check_correct_buffer):
+	  Small unit test fix (has no practical impact at the moment,
+	  since we're only feeding utf8 and hence just create a sub-
+	  buffer for the output).
+
+2007-12-18 21:13:05 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  Add seeking support for avi subtitle
+	  Original commit message from CVS:
+	  * gst/avi/gstavisubtitle.c:
+	  * tests/check/elements/avisubtitle.c:
+	  Add seeking support for avi subtitle
+
+2007-12-18 17:40:34 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/flac/gstflacdec.*: Remove some unused vars.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_reset_decoders),
+	  (gst_flac_dec_update_metadata), (gst_flac_dec_metadata_callback),
+	  (gst_flac_dec_write):
+	  * ext/flac/gstflacdec.h:
+	  Remove some unused vars.
+	  Do more cleanup of leftover events and tags.
+	  Output tags after the segment event. Fixes #504018.
+
+2007-12-18 14:31:36 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavisubtitle.c: Detect other UTF byte order markers and convert to UTF-8 as appropriate.
+	  Original commit message from CVS:
+	  * gst/avi/gstavisubtitle.c: (IS_BOM_UTF8), (IS_BOM_UTF16_BE),
+	  (IS_BOM_UTF16_LE), (IS_BOM_UTF32_BE), (IS_BOM_UTF32_LE),
+	  (gst_avi_subtitle_extract_file), (gst_avi_subtitle_parse_gab2_chunk):
+	  Detect other UTF byte order markers and convert to UTF-8 as
+	  appropriate.
+
+2007-12-18 13:30:15 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavisubtitle.*: Refactor a bit; fix name extraction; don't assume all the data in the chunk is actually sub...
+	  Original commit message from CVS:
+	  * gst/avi/gstavisubtitle.c: (src_template),
+	  (gst_avi_subtitle_extract_utf8_file),
+	  (gst_avi_subtitle_parse_gab2_chunk), (gst_avi_subtitle_chain),
+	  (gst_avi_subtitle_base_init), (gst_avi_subtitle_class_init),
+	  (gst_avi_subtitle_init), (gst_avi_subtitle_change_state):
+	  * gst/avi/gstavisubtitle.h:
+	  Refactor a bit; fix name extraction; don't assume all the data
+	  in the chunk is actually subtitle data, there may be padding at
+	  the end; fix GST_ELEMENT_ERROR usage; store extracted subtitle
+	  file so it's there to send again after a seek (for future use).
+
+2007-12-18 09:13:12 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  Add avi subtitle element for bug #442034. Need seeking support and more support for character conversion.
+	  Original commit message from CVS:
+	  * gst/avi/Makefile.am:
+	  * gst/avi/gstavi.c:
+	  * gst/avi/gstavisubtitle.c:
+	  * gst/avi/gstavisubtitle.h:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/avisubtitle.c:
+	  * win32/common/config.h:
+	  Add avi subtitle element for bug #442034. Need seeking support
+	  and more support for character conversion.
+
+2007-12-18 09:07:17 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Makefile.am: Include common/win32.mak for CRLF check of win32 project files (see #393626).
+	  Original commit message from CVS:
+	  * Makefile.am:
+	  Include common/win32.mak for CRLF check of win32 project
+	  files (see #393626).
+	  * win32/vs6/libgstpng.dsp:
+	  Fix line endings and do cvs admin -kb.
+
+2007-12-17 21:12:28 +0000  David Schleef <ds@schleef.org>
+
+	  gst/multifile/gstmultifilesrc.*: When subsequent files are read, if the file doesn't exist, send an EOS instead of ca...
+	  Original commit message from CVS:
+	  * gst/multifile/gstmultifilesrc.c:
+	  * gst/multifile/gstmultifilesrc.h:
+	  When subsequent files are read, if the file doesn't exist, send
+	  an EOS instead of causing an error.
+
+2007-12-16 23:43:46 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/jpeg/gstjpegdec.c: Actually drop the buffers which are outside the currently configured segment instead of just e...
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_chain):
+	  Actually drop the buffers which are outside the currently configured
+	  segment instead of just emitting a WARNING.
+
+2007-12-14 18:49:34 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/flac/gstflacdec.*: Send segments from the streaming thread. Fixes #502187.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_metadata_callback),
+	  (gst_flac_dec_write):
+	  * ext/flac/gstflacdec.h:
+	  Send segments from the streaming thread. Fixes #502187.
+	  Fix segment seeking and a bunch of other seeking cases.
+
+2007-12-14 10:17:10 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/id3v2frames.c: Parse WOAF frames and put the result into GST_TAG_CONTACT, which is where it would end up...
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (parse_url_link_frame):
+	  Parse WOAF frames and put the result into GST_TAG_CONTACT,
+	  which is where it would end up if the same information was
+	  put in a vorbis comment (don't think it's worth adding a
+	  new URI tag for this). Fixes #488112.
+
+2007-12-11 22:29:18 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: We need core/base 0.10.15 or later.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  We need core/base 0.10.15 or later.
+
+2007-12-11 16:47:12 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  gst/avi/gstavimux.c: Fix regression in stream numbering. Fixes #502655.
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts <manauw skynet be>
+	  * gst/avi/gstavimux.c: (gst_avi_mux_start_file):
+	  Fix regression in stream numbering. Fixes #502655.
+
+2007-12-11 16:39:39 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  ext/soup/gstsouphttpsrc.*: Do not try to unpause I/O in the "queued" state.
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * ext/soup/gstsouphttpsrc.c: (_do_init),
+	  (gst_souphttp_src_class_init), (gst_souphttp_src_init),
+	  (gst_souphttp_src_dispose), (gst_souphttp_src_set_property),
+	  (gst_souphttp_src_get_property), (unicodify),
+	  (gst_souphttp_src_unicodify), (gst_souphttp_src_create),
+	  (gst_souphttp_src_start), (gst_souphttp_src_stop),
+	  (gst_souphttp_src_unlock), (gst_souphttp_src_unlock_stop),
+	  (gst_souphttp_src_get_size), (gst_souphttp_src_is_seekable),
+	  (soup_got_headers), (soup_got_body), (soup_finished),
+	  (soup_got_chunk), (soup_response), (soup_parse_status),
+	  (gst_souphttp_src_uri_get_type),
+	  (gst_souphttp_src_uri_get_protocols),
+	  (gst_souphttp_src_uri_get_uri), (gst_souphttp_src_uri_set_uri),
+	  (gst_souphttp_src_uri_handler_init):
+	  * ext/soup/gstsouphttpsrc.h:
+	  Do not try to unpause I/O in the "queued" state.
+	  Reorganise a bunch of things and cleanups.
+	  Uses G_GUINT64_FORMAT instead of hard-coding %llu.
+	  See #502335.
+
+2007-12-11 16:31:49 +0000  Wai-Ming Ho <webregbox@yahoo.co.uk>
+
+	  gst/rtp/gstrtph264pay.*: Use higher performance start-code searching.
+	  Original commit message from CVS:
+	  Patch by: Wai-Ming Ho <webregbox at yahoo dot co dot uk>
+	  * gst/rtp/gstrtph264pay.c: (gst_rtp_h264_pay_init),
+	  (gst_rtp_h264_pay_finalize), (gst_rtp_h264_pay_setcaps),
+	  (next_start_code), (is_nal_equal), (gst_rtp_h264_pay_decode_nal),
+	  (encode_base64), (gst_rtp_h264_pay_parse_sps_pps),
+	  (gst_rtp_h264_pay_handle_buffer):
+	  * gst/rtp/gstrtph264pay.h:
+	  Use higher performance start-code searching.
+	  Parse NALs and store SPS, PPS and profile in the caps so that they can
+	  be used in the SDP. Fixes #502814.
+
+2007-12-11 11:50:54 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/v4l2/: Init some structs to zero before we pass them to ioctl, which avoids valgrind warnings.  Also fix a small ...
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2_calls.c: (gst_v4l2_fill_lists):
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list):
+	  Init some structs to zero before we pass them to ioctl, which
+	  avoids valgrind warnings.  Also fix a small memory leak.
+
+2007-12-11 11:05:57 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  gst/multipart/multipartdemux.c: Copy timestamp from input to output. Not very perfect yet but better than nothing. Fi...
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * gst/multipart/multipartdemux.c: (gst_multipart_demux_chain):
+	  Copy timestamp from input to output. Not very perfect yet but better
+	  than nothing. Fixes #503023.
+
+2007-12-09 16:49:09 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackdec.c: Also print a useful error message with the old Wavpack API if possible.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_chain):
+	  Also print a useful error message with the old Wavpack API
+	  if possible.
+
+2007-12-09 16:34:08 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/wavpack/gstwavpackdec.c: More build fixes for old libwavpack versions: include config.h so that WAVPACK_OLD_API i...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c:
+	  More build fixes for old libwavpack versions: include config.h so
+	  that WAVPACK_OLD_API is actually defined as detected; only use
+	  WavpackGetErrorMessage if it is available. This fixes the build
+	  on debian stable for me.
+
+2007-12-09 16:21:02 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/: Workaround the non-existance of WavpackGetChannelMask in Wavpack versions below 4.40.0.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_chain):
+	  * ext/wavpack/gstwavpackparse.c:
+	  (gst_wavpack_parse_create_src_pad):
+	  Workaround the non-existance of WavpackGetChannelMask in Wavpack
+	  versions below 4.40.0.
+
+2007-12-09 05:13:58 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  configure.ac: And now do it right for real...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  And now do it right for real...
+
+2007-12-09 05:09:57 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  configure.ac: Correctly reset $LIBS to not contain -lm.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Correctly reset $LIBS to not contain -lm.
+
+2007-12-09 05:02:17 +0000  Kwang Yul Seo <kwangyul.seo@gmail.com>
+
+	  Fix compilation with MSVC by using gst_util_guint64_to_gdouble() and checking for rint() and implementing it ourself ...
+	  Original commit message from CVS:
+	  Based on a patch by: Kwang Yul Seo <kwangyul dot seo at gmail dot com>
+	  * configure.ac:
+	  * ext/cairo/gsttimeoverlay.c:
+	  (gst_cairo_time_overlay_print_smpte_time):
+	  Fix compilation with MSVC by using gst_util_guint64_to_gdouble()
+	  and checking for rint() and implementing it ourself if it doesn't
+	  exist.
+
+2007-12-09 04:29:08 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  configure.ac: Don't define GST_DISABLE_DEPRECATED for releases. Fixes #498181.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Don't define GST_DISABLE_DEPRECATED for releases. Fixes #498181.
+
+2007-12-08 16:47:33 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  sys/oss/gstosshelper.c: Verify that the format returned after the ioctl is the one we requested. It is valid for the ...
+	  Original commit message from CVS:
+	  * sys/oss/gstosshelper.c:
+	  Verify that the format returned after the ioctl is the one
+	  we requested. It is valid for the ioctl to succeed while
+	  substituting an alternate 'supported' sample format.
+
+2007-12-07 20:07:49 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/oss/: Post decent (and translated) error message when we can't open the audio device for some reason.
+	  Original commit message from CVS:
+	  * sys/oss/gstossaudio.c: (plugin_init):
+	  * sys/oss/gstosssink.c: (gst_oss_sink_open):
+	  * sys/oss/gstosssrc.c: (gst_oss_src_open):
+	  Post decent (and translated) error message when we can't
+	  open the audio device for some reason.
+
+2007-12-07 19:29:39 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  sys/oss/: Allow the AUDIODEV environment variable to redirect us to a different default OSS device, like sunaudiosink...
+	  Original commit message from CVS:
+	  * sys/oss/gstosssink.c:
+	  * sys/oss/gstosssrc.c:
+	  Allow the AUDIODEV environment variable to redirect us
+	  to a different default OSS device, like sunaudiosink does
+	  on Solaris (makes audio play automatically on SunRays).
+
+2007-12-06 12:45:50 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/equalizer/gstiirequalizer.c: Fix compilation.
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer.c:
+	  (gst_iir_equalizer_transform_ip):
+	  Fix compilation.
+
+2007-12-06 12:42:11 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/equalizer/gstiirequalizer.c: Don't process buffers in passthrough mode.
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer.c:
+	  (gst_iir_equalizer_transform_ip):
+	  Don't process buffers in passthrough mode.
+
+2007-12-06 12:37:43 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/: The transform() methods are not called in passthrough mode so there's no need for checking if the elemen...
+	  Original commit message from CVS:
+	  * gst/filter/gstbpwsinc.c: (bpwsinc_transform):
+	  * gst/filter/gstlpwsinc.c: (lpwsinc_transform):
+	  The transform() methods are not called in passthrough mode so
+	  there's no need for checking if the element is in passthrough mode.
+
+2007-12-06 12:29:26 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/: Sync the GObject properties with the controller even in passthrough mode to get consistent property values.
+	  Original commit message from CVS:
+	  * gst/filter/gstbpwsinc.c: (bpwsinc_transform):
+	  * gst/filter/gstlpwsinc.c: (lpwsinc_transform):
+	  Sync the GObject properties with the controller even in passthrough
+	  mode to get consistent property values.
+
+2007-12-06 12:11:29 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/: The transform_ip() methods should do nothing if in passthrough mode.
+	  Original commit message from CVS:
+	  * gst/audiofx/audioamplify.c: (gst_audio_amplify_transform_ip):
+	  * gst/audiofx/audiochebyshevfreqband.c:
+	  (gst_audio_chebyshev_freq_band_transform_ip):
+	  * gst/audiofx/audiochebyshevfreqlimit.c:
+	  (gst_audio_chebyshev_freq_limit_transform_ip):
+	  * gst/audiofx/audiodynamic.c: (gst_audio_dynamic_transform_ip):
+	  * gst/audiofx/audioinvert.c: (gst_audio_invert_transform_ip):
+	  The transform_ip() methods should do nothing if in passthrough mode.
+	  It might get non-writable buffers in that case but the buffer might
+	  as well be writable.
+	  * gst/audiofx/audiopanorama.c: (gst_audio_panorama_transform):
+	  The transform() methods won't be called in passthrough mode and
+	  otherwise the buffer is always writable so don't check here.
+
+2007-12-06 11:46:22 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/wavparse/gstwavparse.c: Fix seeking in .wav files again (#501775).  Some people seem to think they don't need to ...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_srcpad_event):
+	  Fix seeking in .wav files again (#501775).  Some people seem to think
+	  they don't need to test their changes when they're just 'reflowing'
+	  some code.
+
+2007-12-05 16:04:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/autodetect/gstautovideosink.*: Fix docs.
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautovideosink.c:
+	  (gst_auto_video_sink_class_init), (gst_auto_video_sink_dispose),
+	  (gst_auto_video_sink_init),
+	  (gst_auto_video_sink_create_element_with_pretty_name),
+	  (gst_auto_video_sink_find_best),
+	  (gst_auto_video_sink_set_property),
+	  (gst_auto_video_sink_get_property):
+	  * gst/autodetect/gstautovideosink.h:
+	  Fix docs.
+	  Use same error reporting code as autoaudiosink.
+	  Add property to filter sinks based on caps. Only select raw video sinks
+	  by default for backwards compat.
+	  API: GstAutoVideoSink::filter-caps
+
+2007-12-05 16:02:15 +0000  Tommi Myöhänen <ext-tommi.myohanen@nokia.com>
+
+	  gst/autodetect/gstautoaudiosink.*: Add property to filter sinks based on caps. Only select raw audio sinks by default...
+	  Original commit message from CVS:
+	  Patch by: Tommi Myöhänen  <ext-tommi dot myohanen at nokia dot com>
+	  * gst/autodetect/gstautoaudiosink.c:
+	  (gst_auto_audio_sink_class_init), (gst_auto_audio_sink_dispose),
+	  (gst_auto_audio_sink_init), (gst_auto_audio_sink_find_best),
+	  (gst_auto_audio_sink_set_property),
+	  (gst_auto_audio_sink_get_property):
+	  * gst/autodetect/gstautoaudiosink.h:
+	  Add property to filter sinks based on caps. Only select raw audio sinks
+	  by default for backwards compat.  Fixes #417420.
+	  API: GstAutoAudioSink::filter-caps
+
+2007-11-29 11:40:15 +0000  Arek Korbik <arkadini@gmail.com>
+
+	  gst/videobox/gstvideobox.c: Initialise liboil in plugin_init()
+	  Original commit message from CVS:
+	  Patch by: Arek Korbik <arkadini@gmail.com>
+	  * gst/videobox/gstvideobox.c: (plugin_init):
+	  Initialise liboil in plugin_init()
+
+2007-11-29 10:49:18 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  configure.ac: Bump libsoup requirement as libsoup does not support async client operation prior to version 2.2.104 an...
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * configure.ac:
+	  Bump libsoup requirement as libsoup does not support async client
+	  operation prior to version 2.2.104 and it has some leaks.
+	  * ext/soup/gstsouphttpsrc.c: (gst_souphttp_src_class_init),
+	  (gst_souphttp_src_init), (gst_souphttp_src_dispose),
+	  (gst_souphttp_src_set_property), (gst_souphttp_src_create),
+	  (gst_souphttp_src_start), (gst_souphttp_src_stop),
+	  (gst_souphttp_src_unlock), (gst_souphttp_src_unlock_stop),
+	  (gst_souphttp_src_get_size), (soup_got_headers), (soup_got_body),
+	  (soup_finished), (soup_got_chunk), (soup_response),
+	  (soup_session_close):
+	  * ext/soup/gstsouphttpsrc.h:
+	  Implement unlock().
+	  Picks up the size from the Content-Length header and emit a duration
+	  message.
+	  Don't leak the GMainContext object.
+	  Fixes #500099.
+
+2007-11-29 10:34:18 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/libpng/gstpngdec.c: Post error before sending EOS. Fixes #499178.
+	  Original commit message from CVS:
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_task):
+	  Post error before sending EOS. Fixes #499178.
+
+2007-11-28 21:54:50 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  win32/vs6/: Add a project file for libgstpng
+	  Original commit message from CVS:
+	  * win32/vs6/gst_plugins_good.dsw:
+	  * win32/vs6/libgstpng.dsp:
+	  Add a project file for libgstpng
+
+2007-11-28 17:48:45 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/rtp/gstrtph263depay.c: Code beautification.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph263depay.c: (gst_rtp_h263_depay_class_init),
+	  (gst_rtp_h263_depay_process):
+	  Code beautification.
+	  Added debug statements.
+	  Don't bit-shift everything, just do operations on last/first byte
+	  instead.
+
+2007-11-27 11:11:08 +0000  Jayarama S. Santana <sundarsantana@gmail.com>
+
+	  gst/rtp/gstrtpmp4adepay.c: Fix wrong comparison in overrun check. Fixes #499239 some more.
+	  Original commit message from CVS:
+	  Patch by: Jayarama S. Santana <sundarsantana at gmail dot com>
+	  * gst/rtp/gstrtpmp4adepay.c: (gst_rtp_mp4a_depay_process):
+	  Fix wrong comparison in overrun check. Fixes #499239 some more.
+
+2007-11-27 00:01:41 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/rtp/gstrtph263depay.*: Fix h263 depayloader so that ANY h263 decoder can handle the outgoing stream.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph263depay.c: (gst_rtp_h263_depay_init),
+	  (gst_rtp_h263_depay_process):
+	  * gst/rtp/gstrtph263depay.h:
+	  Fix h263 depayloader so that ANY h263 decoder can handle the outgoing
+	  stream.
+
+2007-11-26 19:17:10 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmp4adepay.*: Fix depayloading when multiple frames are inside one RTP packet.
+	  Original commit message from CVS:
+	  Based on Path by: Jayarama S. Santana <sundarsantana at gmail dot com>
+	  * gst/rtp/gstrtpmp4adepay.c: (gst_rtp_mp4a_depay_setcaps),
+	  (gst_rtp_mp4a_depay_process):
+	  * gst/rtp/gstrtpmp4adepay.h:
+	  Fix depayloading when multiple frames are inside one RTP packet.
+	  Fixes #499239.
+
+2007-11-26 12:26:20 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/level/gstlevel.c: Add GAP-flag support.
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c:
+	  Add GAP-flag support.
+
+2007-11-26 12:01:11 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/rtp/gstrtph263depay.c: Read the I flag for Mode A h263 rtp stream and set the
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph263depay.c: (gst_rtp_h263_depay_process):
+	  Read the I flag for Mode A h263 rtp stream and set the
+	  GST_BUFFER_FLAG_DELTA_UNIT accordingly.
+	  Fixes #499383
+
+2007-11-26 10:08:20 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/gstspectrum.c: Use dispose and finalize. Dispose can be called multiple times.
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c:
+	  Use dispose and finalize. Dispose can be called multiple times.
+
+2007-11-26 10:04:49 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/level/gstlevel.c: Remove some dead code and do cleanups.
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c:
+	  Remove some dead code and do cleanups.
+
+2007-11-26 09:13:48 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/check/pipelines/simple-launch-lines.c: Improve the tests by allowing to set a target state.
+	  Original commit message from CVS:
+	  * tests/check/pipelines/simple-launch-lines.c:
+	  Improve the tests by allowing to set a target state.
+
+2007-11-26 09:04:17 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/wavpackenc.c: Don't check the caps of the output buffer if they're equal some other caps. The ca...
+	  Original commit message from CVS:
+	  * tests/check/elements/wavpackenc.c: (GST_START_TEST):
+	  Don't check the caps of the output buffer if they're equal some
+	  other caps. The caps can change in a backward compatible way
+	  and did at this point.
+
+2007-11-24 14:55:04 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/qtdemux/qtdemux.c: Implement reverse playback support.
+	  Original commit message from CVS:
+	  2007-11-24  Julien MOUTTE  <julien@moutte.net>
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_find_segment),
+	  (gst_qtdemux_move_stream), (gst_qtdemux_do_seek),
+	  (gst_qtdemux_seek_to_previous_keyframe),
+	  (gst_qtdemux_activate_segment), (gst_qtdemux_advance_sample),
+	  (gst_qtdemux_loop_state_movie), (gst_qtdemux_loop): Implement
+	  reverse playback support.
+
+2007-11-21 09:56:54 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/: Post a GST_MESSAGE_LATENCY if the latency changes.
+	  Original commit message from CVS:
+	  * gst/filter/gstbpwsinc.c: (bpwsinc_set_property):
+	  * gst/filter/gstlpwsinc.c: (lpwsinc_set_property):
+	  Post a GST_MESSAGE_LATENCY if the latency changes.
+
+2007-11-21 08:21:10 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/equalizer/: Remove preset iface again. We'll re-add this after its been released in -good.
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer10bands.c:
+	  * gst/equalizer/gstiirequalizer3bands.c:
+	  Remove preset iface again. We'll re-add this after its been released
+	  in -good.
+
+2007-11-20 13:14:40 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackcommon.c: Also set the channel layout on the Wavpack caps if we're having a mono layout. Of cou...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackcommon.c: (gst_wavpack_set_channel_layout):
+	  Also set the channel layout on the Wavpack caps if we're having
+	  a mono layout. Of course only do it for "audio/x-wavpack".
+
+2007-11-20 13:08:45 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/: Add support for encoding, parsing and decoding multichannel files with up to 8 channels. This also impr...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackcommon.c:
+	  (gst_wavpack_get_default_channel_mask),
+	  (gst_wavpack_set_channel_layout),
+	  (gst_wavpack_get_default_channel_positions),
+	  (gst_wavpack_get_channel_mask_from_positions),
+	  (gst_wavpack_set_channel_mapping):
+	  * ext/wavpack/gstwavpackcommon.h:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_reset),
+	  (gst_wavpack_dec_sink_set_caps), (gst_wavpack_dec_chain):
+	  * ext/wavpack/gstwavpackdec.h:
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_reset),
+	  (gst_wavpack_enc_init), (gst_wavpack_enc_sink_set_caps),
+	  (gst_wavpack_enc_set_wp_config), (gst_wavpack_enc_push_block),
+	  (gst_wavpack_enc_fix_channel_order), (gst_wavpack_enc_chain),
+	  (gst_wavpack_enc_rewrite_first_block),
+	  (gst_wavpack_enc_sink_event):
+	  * ext/wavpack/gstwavpackenc.h:
+	  * ext/wavpack/gstwavpackparse.c:
+	  (gst_wavpack_parse_index_append_entry), (gst_wavpack_parse_reset),
+	  (gst_wavpack_parse_scan_to_find_sample),
+	  (gst_wavpack_parse_sink_event), (gst_wavpack_parse_create_src_pad),
+	  (gst_wavpack_parse_push_buffer), (gst_wavpack_parse_loop):
+	  * ext/wavpack/gstwavpackparse.h:
+	  Add support for encoding, parsing and decoding multichannel
+	  files with up to 8 channels. This also improves the robustness
+	  of parsing quite a bit.
+	  * ext/wavpack/gstwavpackstreamreader.c:
+	  (gst_wavpack_stream_reader_read_bytes),
+	  (gst_wavpack_stream_reader_get_pos),
+	  (gst_wavpack_stream_reader_set_pos_abs),
+	  (gst_wavpack_stream_reader_set_pos_rel),
+	  (gst_wavpack_stream_reader_push_back_byte),
+	  (gst_wavpack_stream_reader_get_length),
+	  (gst_wavpack_stream_reader_can_seek),
+	  (gst_wavpack_stream_reader_write_bytes):
+	  Improve debugging.
+
+2007-11-20 12:20:38 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/libpng/gstpngdec.*: Don't release the png-memory from within the callback.
+	  Original commit message from CVS:
+	  * ext/libpng/gstpngdec.c:
+	  * ext/libpng/gstpngdec.h:
+	  Don't release the png-memory from within the callback.
+
+2007-11-20 12:11:13 +0000  René Stadler <mail@renestadler.de>
+
+	  ext/libpng/gstpngenc.c: Don't leak buffer data memory. Fixes #498395.
+	  Original commit message from CVS:
+	  Patch by: René Stadler <mail at renestadler dot de>
+	  * ext/libpng/gstpngenc.c:
+	  Don't leak buffer data memory. Fixes #498395.
+
+2007-11-20 11:46:28 +0000  René Stadler <mail@renestadler.de>
+
+	  tests/check/pipelines/simple-launch-lines.c: Tests for #498395.
+	  Original commit message from CVS:
+	  Patch by: René Stadler <mail at renestadler dot de>
+	  * tests/check/pipelines/simple-launch-lines.c:
+	  Tests for #498395.
+
+2007-11-20 11:41:13 +0000  Julien Moutte <julien@moutte.net>
+
+	  Fix build on Mac OS X 10.5
+	  Original commit message from CVS:
+	  2007-11-20  Julien MOUTTE  <julien@moutte.net>
+	  * ext/taglib/gsttaglibmux.c: (gst_tag_lib_mux_render_tag),
+	  (gst_tag_lib_mux_adjust_event_offsets):
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_theora_extension):
+	  * sys/osxaudio/Makefile.am:
+	  * sys/osxvideo/cocoawindow.h:
+	  * sys/osxvideo/cocoawindow.m: Fix build on Mac OS X 10.5
+
+2007-11-19 20:30:19 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/equalizer/: Activate preset iface and upload two presets here.
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer10bands.c:
+	  * gst/equalizer/gstiirequalizer3bands.c:
+	  Activate preset iface and upload two presets here.
+
+2007-11-16 05:52:55 +0000  David Schleef <ds@schleef.org>
+
+	  ext/cairo/gsttextoverlay.c: Change strcasecmp() to g_strcasecmp().  Fixes #497292.
+	  Original commit message from CVS:
+	  * ext/cairo/gsttextoverlay.c:
+	  Change strcasecmp() to g_strcasecmp().  Fixes #497292.
+
+2007-11-15 18:19:19 +0000  Jordi Jaen Pallares <jordijp@gmail.com>
+
+	  gst/rtp/gstrtpmp2tpay.*: Fill the MTU with as many packets as possible. Fixes #491323.
+	  Original commit message from CVS:
+	  Patch by: Jordi Jaen Pallares <jordijp at gmail dot com>
+	  * gst/rtp/gstrtpmp2tpay.c: (gst_rtp_mp2t_pay_class_init),
+	  (gst_rtp_mp2t_pay_init), (gst_rtp_mp2t_pay_finalize),
+	  (gst_rtp_mp2t_pay_flush), (gst_rtp_mp2t_pay_handle_buffer):
+	  * gst/rtp/gstrtpmp2tpay.h:
+	  Fill the MTU with as many packets as possible. Fixes #491323.
+
+2007-11-15 17:47:43 +0000  Tommi Myöhänen <ext-tommi.myohanen@nokia.com>
+
+	  gst/rtsp/gstrtspsrc.c: Fix some more leaks. Fixes #497007.
+	  Original commit message from CVS:
+	  Patch by: Tommi Myöhänen  <ext-tommi dot myohanen at nokia dot com>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_setup_streams):
+	  Fix some more leaks. Fixes #497007.
+
+2007-11-15 17:35:18 +0000  Tommi Myöhänen <ext-tommi.myohanen@nokia.com>
+
+	  gst/rtsp/gstrtspsrc.c: Fix 3 pad leaks. Fixes #496983.
+	  Original commit message from CVS:
+	  Patch by: Tommi Myöhänen  <ext-tommi dot myohanen at nokia dot com>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_stream_free),
+	  (gst_rtspsrc_stream_configure_tcp):
+	  Fix 3 pad leaks. Fixes #496983.
+
+2007-11-15 17:26:25 +0000  Wouter Cloetens <wouter@mind.be>
+
+	  Added HTTP source based on libsoup. Fixes #497020.
+	  Original commit message from CVS:
+	  Patch by: Wouter Cloetens <wouter at mind dot be>
+	  * configure.ac:
+	  * ext/Makefile.am:
+	  * ext/soup/Makefile.am:
+	  * ext/soup/gstsouphttpsrc.c: (_do_init),
+	  (gst_souphttp_src_base_init), (gst_souphttp_src_class_init),
+	  (gst_souphttp_src_init), (gst_souphttp_src_dispose),
+	  (gst_souphttp_src_set_property), (gst_souphttp_src_get_property),
+	  (gst_souphttp_src_create), (gst_souphttp_src_start),
+	  (gst_souphttp_src_stop), (gst_souphttp_src_unlock),
+	  (gst_souphttp_src_set_location), (soup_got_chunk), (soup_response),
+	  (soup_session_close), (plugin_init):
+	  * ext/soup/gstsouphttpsrc.h:
+	  Added HTTP source based on libsoup. Fixes #497020.
+
+2007-11-15 17:01:32 +0000  Tommi Myöhänen <ext-tommi.myohanen@nokia.com>
+
+	  gst/rtp/gstrtph264depay.c: Fix small leak. Fixes #497017.
+	  Original commit message from CVS:
+	  Patch by: Tommi Myöhänen  <ext-tommi dot myohanen at nokia dot com>
+	  * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_setcaps):
+	  Fix small leak. Fixes #497017.
+
+2007-11-15 16:31:32 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/: Add suppport for theora in quicktime according to XiphQT.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_change_state),
+	  (gst_qtdemux_prepare_current_sample),
+	  (gst_qtdemux_loop_state_movie), (qtdemux_parse_theora_extension),
+	  (qtdemux_parse_node), (qtdemux_parse_trak), (qtdemux_video_caps):
+	  * gst/qtdemux/qtdemux_fourcc.h:
+	  * gst/qtdemux/qtdemux_types.c:
+	  Add suppport for theora in quicktime according to XiphQT.
+
+2007-11-15 12:22:10 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/v4l2src_calls.c:
+	  Always copy buffers by default (handle safer with bugged drivers) and added a property to make it possible to use mma...
+	  Original commit message from CVS:
+	  Always copy buffers by default (handle safer with bugged drivers) and added a property to make it possible to use mmap effectively (no copy if possible) when application wants to. Fixes: #480557.
+
+2007-11-14 21:39:47 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/: We don't want the same string multiple times in a tag list for the same tag ever, for any tag, not jus...
+	  Original commit message from CVS:
+	  * gst/id3demux/id3tags.c:
+	  * gst/id3demux/id3tags.h:
+	  * gst/id3demux/id3v2frames.c: (id3v2_tag_to_taglist):
+	  We don't want the same string multiple times in a tag list for the
+	  same tag ever, for any tag, not just for GST_TAG_GENRE, so make sure
+	  this doesn't happen and remove special-case code for GST_TAG_GENRE.
+
+2007-11-14 21:04:12 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/gstid3v2mux.cc: Write GST_TAG_MUSICBRAINZ_DISCID and GST_TAG_CDDA_CDDB_DISCID into ID3v2 TXXX frames (fixe...
+	  Original commit message from CVS:
+	  * ext/taglib/gstid3v2mux.cc: (add_musicbrainz_tag), (add_funcs):
+	  Write GST_TAG_MUSICBRAINZ_DISCID and GST_TAG_CDDA_CDDB_DISCID
+	  into ID3v2 TXXX frames (fixes #347848).
+
+2007-11-14 20:34:24 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/rtsp/gstrtspsrc.c: Don't leak sdp message contents (fixes #496773).
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_open):
+	  Don't leak sdp message contents (fixes #496773).
+	  * gst/udp/gstudpsink.c: (gst_udpsink_finalize):
+	  Don't leak URI string.
+
+2007-11-14 19:10:37 +0000  Julien Puydt <julien.puydt@laposte.net>
+
+	  ext/raw1394/: Implement GstPropertyProbe interface and add "device-name" property, so applications can use this to pr...
+	  Original commit message from CVS:
+	  Patch by: Julien Puydt <julien dot puydt at laposte net>
+	  * ext/raw1394/Makefile.am:
+	  * ext/raw1394/gst1394probe.c: (gst_1394_get_guid_array),
+	  (gst_1394_property_probe_get_properties),
+	  (gst_1394_property_probe_probe_property),
+	  (gst_1394_property_probe_needs_probe),
+	  (gst_1394_property_probe_get_values),
+	  (gst_1394_property_probe_interface_init),
+	  (gst_1394_type_add_property_probe_interface):
+	  * ext/raw1394/gst1394probe.h: (GST_1394_PROBE_H):
+	  * ext/raw1394/gstdv1394src.c: (_do_init), (gst_dv1394src_class_init),
+	  (gst_dv1394src_init), (gst_dv1394src_dispose),
+	  (gst_dv1394src_set_property), (gst_dv1394src_get_property),
+	  (gst_dv1394src_discover_avc_node), (gst_dv1394src_query),
+	  (gst_dv1394src_update_device_name):
+	  * ext/raw1394/gstdv1394src.h:
+	  Implement GstPropertyProbe interface and add "device-name" property,
+	  so applications can use this to probe for available devices in the
+	  same way they can already with v4lsrc and v4l2src (however horrible
+	  this property probe interface may be). Fixes #358841.
+
+2007-11-14 17:03:18 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/spectrum.c: Fix spectrum unit test for the latest spectrum changes.
+	  Original commit message from CVS:
+	  * tests/check/elements/spectrum.c: (GST_START_TEST):
+	  Fix spectrum unit test for the latest spectrum changes.
+
+2007-11-14 15:29:05 +0000  Tommi Myöhänen <ext-tommi.myohanen@nokia.com>
+
+	  gst/rtsp/gstrtspsrc.c: Don't leak event, don't leak range (fixes #496752).
+	  Original commit message from CVS:
+	  Patch by: Tommi Myöhänen  <ext-tommi dot myohanen at nokia dot com>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_handle_src_event),
+	  (gst_rtspsrc_parse_range):
+	  Don't leak event, don't leak range (fixes #496752).
+
+2007-11-14 10:22:41 +0000  Arek Korbik <arkadini@gmail.com>
+
+	  gst/alpha/gstalphacolor.c: Detect RGBA/BGRA correctly on little endian systems.
+	  Original commit message from CVS:
+	  Patch by: Arek Korbik <arkadini@gmail.com>
+	  * gst/alpha/gstalphacolor.c: (gst_alpha_color_set_caps):
+	  Detect RGBA/BGRA correctly on little endian systems.
+
+2007-11-13 17:19:13 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/v4l2/v4l2src_calls.c: but the corresponding ioctl() call fails even though the driver claims to support this form...
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_probe_caps_for_format):
+	  If VIDIOC_ENUM_FRAMESIZES is defined (= recent kernel), but the
+	  corresponding ioctl() call fails even though the driver claims to
+	  support this format, just fall back to the pre-2.6.19 kernel
+	  routine that creates caps with suitable height and width ranges
+	  (see #448278).
+
+2007-11-13 17:01:07 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  gst/matroska/: Extract palette data for dvd subpicture streams and send it downstream as custom gstreamer dvd event (...
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts <manauw skynet be>
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_push_dvd_clut_change_event),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+	  (gst_matroska_demux_subtitle_caps):
+	  * gst/matroska/matroska-ids.h:
+	  Extract palette data for dvd subpicture streams and send it
+	  downstream as custom gstreamer dvd event (fixes #453417).
+
+2007-11-13 14:51:30 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/cairo/gsttextoverlay.c: Implement minimal parsing of the passed pango font description string, so passing a font ...
+	  Original commit message from CVS:
+	  * ext/cairo/gsttextoverlay.c: (gst_text_overlay_font_init):
+	  Implement minimal parsing of the passed pango font description
+	  string, so passing a font size works the same as with the
+	  pango textoverlay plugin; fixes #455086.
+	  (Maybe we could just use pangocairo here at some point).
+
+2007-11-13 06:55:28 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/: Return the result in _activate_pull(). Don't ref element there.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  * gst/wavparse/gstwavparse.c:
+	  Return the result in _activate_pull(). Don't ref element there.
+
+2007-11-13 06:23:51 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/wavparse/gstwavparse.c: Ref the element when we should, but not when we its not needed. Reflow the event_handling...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_stream_headers),
+	  (gst_wavparse_pad_convert), (gst_wavparse_pad_query),
+	  (gst_wavparse_srcpad_event):
+	  Ref the element when we should, but not when we its not needed. Reflow
+	  the event_handling to not leak the event.
+
+2007-11-12 21:07:31 +0000  René Stadler <mail@renestadler.de>
+
+	  gst/replaygain/rganalysis.c: Avoid slowdown from denormals when processing near-silence input data.
+	  Original commit message from CVS:
+	  Patch by: René Stadler <mail at renestadler dot de>
+	  * gst/replaygain/rganalysis.c: (yule_filter):
+	  Avoid slowdown from denormals when processing near-silence input data.
+	  Spotted by Gabriel Bouvigne. Fixes #494499.
+
+2007-11-12 17:59:40 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Properly free QTDemuxSamples array.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_change_state),
+	  (qtdemux_parse_samples):
+	  Properly free QTDemuxSamples array.
+	  Protect table write with a sensible check, some files apparently DO contain
+	  stts values starting with 0 :(
+
+2007-11-12 17:21:59 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/: Drop EOS in _handle_src_event(). Fix the refcount in qtdemux that previous commit messed up.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  * gst/qtdemux/qtdemux.c:
+	  Drop EOS in _handle_src_event(). Fix the refcount in qtdemux that
+	  previous commit messed up.
+
+2007-11-12 17:06:32 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/: Sync _handle_src_event() with oggdemux. In avidemux also ref the element when we should, but not when we its no...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  * gst/qtdemux/qtdemux.c:
+	  Sync _handle_src_event() with oggdemux. In avidemux also ref the
+	  element when we should, but not when we its not needed.
+
+2007-11-11 21:12:10 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/: Change the meaning of the magnitude values given in the
+	  Original commit message from CVS:
+	  * gst/equalizer/demo.c: (draw_spectrum):
+	  * gst/spectrum/demo-audiotest.c: (draw_spectrum):
+	  * gst/spectrum/demo-osssrc.c: (draw_spectrum):
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_class_init):
+	  Change the meaning of the magnitude values given in the
+	  GstMessages by spectrum to decibel instead of
+	  decibel+threshold.
+
+2007-11-11 13:55:27 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/equalizer/: And continue to update docs. Also include some sample code for the n-band equalizer in the docs.
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer10bands.c:
+	  * gst/equalizer/gstiirequalizer3bands.c:
+	  * gst/equalizer/gstiirequalizernbands.c:
+	  And continue to update docs. Also include some sample code
+	  for the n-band equalizer in the docs.
+
+2007-11-11 12:54:31 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/equalizer/: Update docs and property ranges to the real values.
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer10bands.c:
+	  (gst_iir_equalizer_10bands_class_init):
+	  * gst/equalizer/gstiirequalizer3bands.c:
+	  (gst_iir_equalizer_3bands_class_init):
+	  * gst/equalizer/gstiirequalizernbands.c:
+	  Update docs and property ranges to the real values.
+
+2007-11-09 17:27:00 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/spectrum/gstspectrum.c: Now do the scaling right for real. Also initialize a previously uninitialized variable.
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c:
+	  Now do the scaling right for real. Also initialize a previously
+	  uninitialized variable.
+
+2007-11-08 15:56:46 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/equalizer/demo.c: Make default volume a bit less. Improve layout by giving more space to the slider with big-numb...
+	  Original commit message from CVS:
+	  * gst/equalizer/demo.c:
+	  Make default volume a bit less. Improve layout by giving more space to
+	  the slider with big-numbers and enable fill.
+
+2007-11-08 15:00:40 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/wavparse/gstwavparse.c: Return FALSE if we can't handle a query instead of changing the format. Ignore fact when ...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c:
+	  Return FALSE if we can't handle a query instead of changing the
+	  format. Ignore fact when dealing with mpeg audio.
+
+2007-11-06 12:23:35 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/spectrum/demo-audiotest.c: Use autoaudiosink instead of alsasink and use a sine wave.
+	  Original commit message from CVS:
+	  * gst/spectrum/demo-audiotest.c: (main):
+	  Use autoaudiosink instead of alsasink and use a sine wave.
+	  * gst/spectrum/gstspectrum.c:
+	  Fix the magnitude calculation.
+
+2007-11-03 19:50:11 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/equalizer/: Allow setting 0 as bandwidth and handle this correctly.
+	  Original commit message from CVS:
+	  * gst/equalizer/demo.c: (main):
+	  * gst/equalizer/gstiirequalizer.c:
+	  (gst_iir_equalizer_band_class_init), (setup_filter):
+	  Allow setting 0 as bandwidth and handle this correctly.
+	  Also handle a bandwidth of rate/2 properly.
+	  * gst/equalizer/gstiirequalizernbands.c:
+	  (gst_iir_equalizer_nbands_class_init):
+	  Make it possible to generate a N-band equalizer with 1 bands. The
+	  previous limit of 2 was caused by a nowadays replaced calculation
+	  doing a division by zero if number of bands was 1.
+
+2007-11-02 21:16:09 +0000  Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+
+	  Fix includes for MSVC and GLib-2.14.0 (#492388).
+	  Original commit message from CVS:
+	  Patch by: Ole André Vadla Ravnås  <ole.andre.ravnas@tandberg.com>
+	  * configure.ac:
+	  * gst/udp/gstdynudpsink.c:
+	  * gst/udp/gstdynudpsink.h:
+	  * gst/udp/gstmultiudpsink.c:
+	  * gst/udp/gstmultiudpsink.h:
+	  * gst/udp/gstudpsink.c:
+	  * gst/udp/gstudpsink.h:
+	  Fix includes for MSVC and GLib-2.14.0 (#492388).
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_start):
+	  No more pipe define since GLib-2.14.0, need to use _pipe() directly.
+
+2007-11-02 17:23:43 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/law/mulaw-decode.*: Calculate outgoing buffer duration if incoming buffer didn't have a valid duration.
+	  Original commit message from CVS:
+	  * gst/law/mulaw-decode.c: (mulawdec_sink_setcaps),
+	  (gst_mulawdec_chain):
+	  * gst/law/mulaw-decode.h:
+	  Calculate outgoing buffer duration if incoming buffer didn't have a
+	  valid duration.
+
+2007-10-30 21:37:49 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/equalizer/: Add small demo application based on the spectrum demo applications that gets white noise as input, pu...
+	  Original commit message from CVS:
+	  * gst/equalizer/Makefile.am:
+	  * gst/equalizer/demo.c: (on_window_destroy), (on_configure_event),
+	  (on_gain_changed), (on_bandwidth_changed), (on_freq_changed),
+	  (draw_spectrum), (message_handler), (main):
+	  Add small demo application based on the spectrum demo applications
+	  that gets white noise as input, pushes it through an equalizer and
+	  paints the spectrum. For every equalizer band it's possible to set
+	  gain, bandwidth and frequency.
+	  * gst/equalizer/gstiirequalizer.c: (setup_filter):
+	  Add some guarding against too large or too small frequencies and
+	  bandwidths. Also improve debugging a bit.
+
+2007-10-30 21:18:45 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/equalizer/gstiirequalizer.c: Replace filters with a bit better filters for which we can actually find documentati...
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer.c:
+	  (gst_iir_equalizer_band_set_property),
+	  (gst_iir_equalizer_band_get_property),
+	  (gst_iir_equalizer_band_class_init), (arg_to_scale),
+	  (setup_filter), (gst_iir_equalizer_compute_frequencies):
+	  Replace filters with a bit better filters for which we can actually
+	  find documentation, which don't change anything on zero gain, etc.
+	  Make the frequency property of the bands writable, rename the
+	  band-width property to bandwidth and change the	meaning to the
+	  frequency difference between bandedges, change the meaning of the
+	  gain property to dB instead of a weird scale between -1	and 1 that
+	  has no real meaning.
+
+2007-10-30 12:29:46 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Smarter combine_flow code that also deals with downstream elements returning UNEXPECTED when t...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_activate_segment),
+	  (gst_qtdemux_combine_flows), (gst_qtdemux_loop_state_movie):
+	  Smarter combine_flow code that also deals with downstream elements
+	  returning UNEXPECTED when they receive data out of the segment
+	  boundaries. Fixes #491305.
+
+2007-10-27 16:04:48 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/interleave/interleave.c: Let's not call every request pad we create "sink%d", that'll create problems if there's ...
+	  Original commit message from CVS:
+	  * gst/interleave/interleave.c: (gst_interleave_request_new_pad):
+	  Let's not call every request pad we create "sink%d", that'll
+	  create problems if there's to be more than one pad. Fixes #490682.
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/interleave.c:
+	  Add unit test for the above.
+
+2007-10-26 15:03:06 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/v4l2/v4l2src_calls.c: Fix 'unused variable' compiler warning when compiling against older kernel headers.
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c:
+	  Fix 'unused variable' compiler warning when compiling against
+	  older kernel headers.
+
+2007-10-26 12:10:43 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  update spec file
+	  Original commit message from CVS:
+	  update spec file
+
+2007-10-25 23:42:52 +0000  David Schleef <ds@schleef.org>
+
+	  Improve documentation, write some tests for multifilesrc/sink for upcoming ->good review.
+	  Original commit message from CVS:
+	  * gst/multifile/Makefile.am:
+	  * gst/multifile/gstmultifilesink.c:
+	  * gst/multifile/gstmultifilesrc.c:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/multifile.c:
+	  Improve documentation, write some tests for multifilesrc/sink
+	  for upcoming ->good review.
+
+2007-10-25 15:00:15 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/gstid3v2mux.cc (add_funcs): Map new SORTNAME tags to ID3v2 TSOP, TSOA and TSOT frames (#414539).
+	  Original commit message from CVS:
+	  * ext/taglib/gstid3v2mux.cc (add_funcs):
+	  Map new SORTNAME tags to ID3v2 TSOP, TSOA and TSOT frames (#414539).
+
+2007-10-24 07:01:47 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/check/pipelines/simple-launch-lines.c: Improve the tests a little more.
+	  Original commit message from CVS:
+	  * tests/check/pipelines/simple-launch-lines.c:
+	  Improve the tests a little more.
+
+2007-10-23 08:38:50 +0000  Yun Zheng Hu <yunzheng.hu@gmail.com>
+
+	  sys/osxaudio/gstosxaudiosrc.c: Use default input device instead of default output device and only memcpy actual avail...
+	  Original commit message from CVS:
+	  patch by: Yun Zheng Hu
+	  * sys/osxaudio/gstosxaudiosrc.c:
+	  Use default input device instead of default output device and
+	  only memcpy actual available bytes.
+
+2007-10-22 19:14:08 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	  sys/v4l2/v4l2src_calls.c: Fixes "v4l2src ! queue ! xvimagesink". The queue ask for buffer too early. It is temporary ...
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_grab_frame):
+	  Fixes "v4l2src ! queue ! xvimagesink". The queue ask for buffer too
+	  early. It is temporary until we find something better.
+
+2007-10-22 16:44:48 +0000  Tommi Myöhänen <ext-tommi.myohanen@nokia.com>
+
+	  gst/rtsp/gstrtspsrc.c: Fix race when pausing a RTSP stream in interleaved.
+	  Original commit message from CVS:
+	  Patch by: Tommi Myöhänen  <ext-tommi dot myohanen at nokia dot com>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_loop_interleaved):
+	  Fix race when pausing a RTSP stream in interleaved.
+	  Fixes #475784.
+
+2007-10-22 09:53:16 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtp/gstrtpmp4vpay.c: Use correct unref function for buffers. #488844.
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt <pkj at axis com>
+	  * gst/rtp/gstrtpmp4vpay.c: (gst_rtp_mp4v_pay_finalize):
+	  Use correct unref function for buffers. #488844.
+
+2007-10-19 19:33:16 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Add some debug and sync tests with the fix.
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c:
+	  * tests/check/elements/avimux.c:
+	  Add some debug and sync tests with the fix.
+
+2007-10-18 17:04:14 +0000  Laurent Glayal <spglegle@yahoo.fr>
+
+	  gst/udp/gstudpsrc.c: When the socket is used by the app for other purposes, don't generate an error if there is activ...
+	  Original commit message from CVS:
+	  Based on patch by: Laurent Glayal  <spglegle yahoo fr>
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_create):
+	  When the socket is used by the app for other purposes, don't generate an
+	  error if there is activaty on the socket that is not data related.
+	  Fixes #487488.
+
+2007-10-18 14:55:38 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/v4l2/v4l2src_calls.c: Add some more debug info. Generate an error when we run out of buffers for some reason. See...
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2_buffer_finalize),
+	  (gst_v4l2src_grab_frame):
+	  Add some more debug info. Generate an error when we run out of buffers
+	  for some reason. See #480557.
+
+2007-10-18 08:27:56 +0000  Anders Skargren <anders.skargren@axis.com>
+
+	  gst/rtp/gstrtph264pay.c: Set marker bit correctly.
+	  Original commit message from CVS:
+	  Patch by: Anders Skargren <anders dot skargren at axis dot com>
+	  * gst/rtp/gstrtph264pay.c: (gst_rtp_h264_pay_handle_buffer):
+	  Set marker bit correctly.
+
+2007-10-18 06:20:21 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/equalizer/gstiirequalizer.c: Add a missing break.
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer.c:
+	  (gst_iir_equalizer_band_set_property):
+	  Add a missing break.
+
+2007-10-18 06:14:42 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/equalizer/gstiirequalizer.*: Move bandwidth property to the separate bands and add float64 support.
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer.c:
+	  (gst_iir_equalizer_band_set_property),
+	  (gst_iir_equalizer_band_get_property),
+	  (gst_iir_equalizer_band_class_init), (gst_iir_equalizer_band_init),
+	  (gst_iir_equalizer_band_get_type), (gst_iir_equalizer_class_init),
+	  (setup_filter), (gst_iir_equalizer_setup):
+	  * gst/equalizer/gstiirequalizer.h:
+	  Move bandwidth property to the separate bands and add float64 support.
+
+2007-10-17 15:08:02 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Use allowed name for the GstStructure.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_open):
+	  Use allowed name for the GstStructure.
+
+2007-10-17 11:47:23 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Use new gst_bus_pop_filtered().
+	  Original commit message from CVS:
+	  * ext/gconf/gstswitchsink.c:
+	  * gst/autodetect/gstautoaudiosink.c:
+	  Use new gst_bus_pop_filtered().
+
+2007-10-13 12:03:44 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/v4l2/: When probing the formats and sizes a camera supports, make sure the best ones (highest resolution, prefere...
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c:
+	  * sys/v4l2/v4l2src_calls.c:
+	  When probing the formats and sizes a camera supports, make
+	  sure the best ones (highest resolution, prefered format)
+	  end up at the beginning of the probed caps and the less
+	  desirable ones at the end.  This is important because the
+	  order within the caps matters for things like fixation and
+	  negotiation, ie. what format is chosen in the end.
+	  With recent kernels, the current probing code will end up
+	  querying the supported sizes from lowest resolution to
+	  highest resolution, adding them to the probed caps in that
+	  order, resulting to v4l2src fixating to the lowest possible
+	  resolution if downstream does not express a size preference.
+	  Also make up a somewhat random ranking of prefered output
+	  formats for the same reason. Fixes #485828.
+
+2007-10-11 17:55:29 +0000  Jason Kivlighn <jkivlighn@gmail.com>
+
+	  gst/id3demux/id3v2frames.c: Extract license/copyright URIs from ID3v2 WCOP frames (Fixes #447000).
+	  Original commit message from CVS:
+	  Based on patch by: Jason Kivlighn  <jkivlighn gmail com>
+	  * gst/id3demux/id3v2frames.c:
+	  Extract license/copyright URIs from ID3v2 WCOP frames
+	  (Fixes #447000).
+	  * tests/check/elements/id3demux.c:
+	  * tests/files/Makefile.am:
+	  * tests/files/id3-447000-wcop.tag:
+	  Add simple unit test.
+
+2007-10-11 16:41:44 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/gstid3v2mux.cc: Add support for license/copyright URI tags (ID3v2 WCOP frame).
+	  Original commit message from CVS:
+	  * ext/taglib/gstid3v2mux.cc:
+	  Add support for license/copyright URI tags (ID3v2 WCOP frame).
+	  Prerequisite for #447000.
+
+2007-10-08 17:44:42 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/rtsp/gstrtspsrc.c: Fix compiler warning by using GST_CLOCK_TIME_NONE to initialise a GstClockTime.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_flush):
+	  Fix compiler warning by using GST_CLOCK_TIME_NONE to initialise
+	  a GstClockTime.
+
+2007-10-08 11:58:51 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: More seeking fixes, mostly passing around the new playback segment in order to configure it pr...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_flush),
+	  (gst_rtspsrc_do_seek), (gst_rtspsrc_perform_seek),
+	  (gst_rtspsrc_configure_caps), (gst_rtspsrc_loop_udp),
+	  (gst_rtspsrc_parse_range), (gst_rtspsrc_open), (gst_rtspsrc_play),
+	  (gst_rtspsrc_change_state):
+	  More seeking fixes, mostly passing around the new playback segment in
+	  order to configure it properly.
+	  Also reset base_time of udp sources when setting them back to PLAYING as
+	  a temporary hack until core supports seek in live sources properly.
+
+2007-10-08 10:34:03 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmp4adepay.c: Fix caps as to not confuse autopluggers.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4adepay.c:
+	  Fix caps as to not confuse autopluggers.
+
+2007-10-06 16:13:14 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/: Port ID3 tag demuxer over to the new GstTagDemux in -base (now would be a good time to test re-importi...
+	  Original commit message from CVS:
+	  * gst/id3demux/gstid3demux.c:
+	  * gst/id3demux/gstid3demux.h:
+	  * gst/id3demux/id3tags.c:
+	  * gst/id3demux/id3tags.h:
+	  * gst/id3demux/id3v2frames.c:
+	  Port ID3 tag demuxer over to the new GstTagDemux in -base
+	  (now would be a good time to test re-importing your music
+	  collection).
+
+2007-10-06 15:13:09 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/apetag/: Port APE tag demuxer over to the new GstTagDemux in -base.
+	  Original commit message from CVS:
+	  * gst/apetag/Makefile.am:
+	  * gst/apetag/gstapedemux.c:
+	  * gst/apetag/gstapedemux.h:
+	  * gst/apetag/gsttagdemux.c:
+	  * gst/apetag/gsttagdemux.h:
+	  Port APE tag demuxer over to the new GstTagDemux in -base.
+
+2007-10-05 13:18:19 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Improve flushing behaviour.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_flush),
+	  (gst_rtspsrc_perform_seek), (gst_rtspsrc_handle_src_event),
+	  (gst_rtspsrc_handle_internal_src_query),
+	  (gst_rtspsrc_handle_src_query), (new_session_pad),
+	  (gst_rtspsrc_stream_configure_tcp),
+	  (gst_rtspsrc_stream_configure_transport),
+	  (gst_rtspsrc_loop_send_cmd):
+	  Improve flushing behaviour.
+	  Set state of the udp sources to PAUSE/PLAYING correctly.
+	  Handle events and queries for UDP and TCP transport now.
+
+2007-10-04 07:29:48 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/rtp/: Add log category.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpgsmdepay.c:
+	  * gst/rtp/gstrtpgsmpay.c:
+	  Add log category.
+
+2007-10-04 07:24:02 +0000  Timo Hotti <Timo.Hotti@sysopendigia.com>
+
+	  tests/check/: Add unit tests for payloaders/depayloaders.
+	  Original commit message from CVS:
+	  Patch by: Timo Hotti <Timo.Hotti@sysopendigia.com>
+	  * tests/check/Makefile.am:
+	  * tests/check/pipelines/simple-launch-lines.c:
+	  Add unit tests for payloaders/depayloaders.
+
+2007-10-02 10:49:03 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavimux.*: Also save codec data for audio streams. Fixes #482495.
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c:
+	  * gst/avi/gstavimux.h:
+	  Also save codec data for audio streams. Fixes #482495.
+
+2007-10-02 10:23:04 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavimux.c: Fix "Index entry has invalid stream nr 1".
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c:
+	  Fix "Index entry has invalid stream nr 1".
+	  Add support for muxing aac - work in progress (see #482495).
+
+2007-10-01 16:34:56 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Parse bandwidth modifiers, they are not yet configured in the session manager because we don't...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_get_bandwidth),
+	  (gst_rtspsrc_collect_bandwidth), (gst_rtspsrc_create_stream),
+	  (gst_rtspsrc_media_to_caps), (gst_rtspsrc_loop_interleaved):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Parse bandwidth modifiers, they are not yet configured in the session
+	  manager because we don't have an API for that yet.
+
+2007-10-01 13:57:28 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Use shiny new function in -base to get the default clock-rate.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_parse_rtpmap),
+	  (gst_rtspsrc_media_to_caps), (gst_rtspsrc_loop_interleaved):
+	  Use shiny new function in -base to get the default clock-rate.
+	  Update some docs.
+
+2007-09-29 12:50:36 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  win32/MANIFEST: Add files to win32 manifest.
+	  Original commit message from CVS:
+	  * win32/MANIFEST:
+	  Add files to win32 manifest.
+	  * win32/vs6/libgstaudiofx.dsp:
+	  * win32/vs6/libgstqtdemux.dsp:
+	  * win32/vs6/libgstrtp.dsp:
+	  * win32/vs6/libgstrtsp.dsp:
+	  Update project files.
+
+2007-09-28 14:56:19 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: In TCP mode, only timestamp the first buffer. TCP is not real time and it does not make sense ...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_loop_interleaved),
+	  (gst_rtspsrc_play):
+	  * gst/rtsp/gstrtspsrc.h:
+	  In TCP mode, only timestamp the first buffer. TCP is not real time and
+	  it does not make sense to try to skew compensate, also some servers send
+	  the first batch of data in a burst.
+
+2007-09-27 15:00:30 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-demux.c: Fix setting the discont flag on the first buffer pushed downstream for formats with pr...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  Fix setting the discont flag on the first buffer
+	  pushed downstream for formats with private codec
+	  data that needs to be deserialised into buffers
+	  (such as vorbis and FLAC when in a matroska container).
+
+2007-09-27 11:10:12 +0000  Antoine Tremblay <hexa00@gmail.com>
+
+	  gst/rtp/gstrtpmp4vpay.*: Free the config string. Fixes #480707.
+	  Original commit message from CVS:
+	  Patch by: Antoine Tremblay <hexa00 at gmail dot com>
+	  * gst/rtp/gstrtpmp4vpay.c: (gst_rtp_mp4v_pay_init),
+	  (gst_rtp_mp4v_pay_finalize), (gst_rtp_mp4v_pay_flush),
+	  (gst_rtp_mp4v_pay_handle_buffer):
+	  * gst/rtp/gstrtpmp4vpay.h:
+	  Free the config string. Fixes #480707.
+	  Clean up the timestamp code a little.
+
+2007-09-26 20:12:52 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Set timestamps on RTP buffers in interleaved mode.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_create_stream),
+	  (gst_rtspsrc_handle_src_query), (gst_rtspsrc_loop_interleaved),
+	  (gst_rtspsrc_loop_udp), (gst_rtspsrc_close):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Set timestamps on RTP buffers in interleaved mode.
+	  Mark first buffers with a DISCONT.
+	  Remove flush hack now that sync for live sources has been figured out.
+
+2007-09-26 14:28:20 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstudpsrc.c: Update documentation.
+	  Original commit message from CVS:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_create):
+	  Update documentation.
+
+2007-09-26 14:26:39 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/gstrtpxqtdepay.*: Fail if we don't know the quicktime format.
+	  Original commit message from CVS:
+	  * gst/qtdemux/gstrtpxqtdepay.c: (gst_rtp_xqt_depay_process),
+	  (gst_rtp_xqt_depay_change_state):
+	  * gst/qtdemux/gstrtpxqtdepay.h:
+	  Fail if we don't know the quicktime format.
+
+2007-09-26 13:19:17 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacenc.*: Save the flow return from the last gst_pad_push() and make sure we pass the right flow return ...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacenc.c:
+	  * ext/flac/gstflacenc.h:
+	  Save the flow return from the last gst_pad_push() and
+	  make sure we pass the right flow return value upstream
+	  in the case of failure; minor clean-ups.
+
+2007-09-25 19:09:33 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Add support for the new GST_TAG_COMPOSER (#459809).
+	  Original commit message from CVS:
+	  * ext/taglib/gstapev2mux.cc:
+	  * ext/taglib/gstid3v2mux.cc:
+	  * gst/apetag/gstapedemux.c:
+	  Add support for the new GST_TAG_COMPOSER (#459809).
+
+2007-09-25 17:18:34 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/law/: Compulsive clean-ups: use boilerplate macros, add debug categories, fix up things to conform to symbol nome...
+	  Original commit message from CVS:
+	  * gst/law/alaw-decode.c:
+	  * gst/law/alaw-decode.h:
+	  * gst/law/alaw-encode.c:
+	  * gst/law/alaw-encode.h:
+	  * gst/law/alaw.c:
+	  * gst/law/mulaw-conversion.h:
+	  Compulsive clean-ups: use boilerplate macros, add debug
+	  categories, fix up things to conform to symbol nomenklatura,
+	  etc.
+
+2007-09-25 16:05:29 +0000  Laurent Glayal <spglegle@yahoo.fr>
+
+	  gst/law/: Use static tables for A-Law decoding and encoding; this makes
+	  Original commit message from CVS:
+	  Based on patch by: Laurent Glayal  <spglegle yahoo fr>
+	  * gst/law/alaw-decode.c:
+	  * gst/law/alaw-encode.c:
+	  Use static tables for A-Law decoding and encoding; this makes
+	  A-Law decoding and encoding less CPU-intensive, but increases
+	  the binary size a bit. Leaving old code around for now,
+	  selectable by a define in the code. Fixes #435435.
+
+2007-09-25 08:51:36 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  configure.ac: Use AG_GST_ARG_WITH_PLUGINS, AG_GST_ARG_ENABLE_EXTERNAL and
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Use AG_GST_ARG_WITH_PLUGINS, AG_GST_ARG_ENABLE_EXTERNAL and
+	  AG_GST_ARG_ENABLE_EXPERIMENTAL instead of duplicating those macros
+	  in configure.ac.
+
+2007-09-25 05:03:58 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/qtdemux/qtdemux.c: Add fourccs for MPEG2 HDV streams. Fixes #479960.
+	  Original commit message from CVS:
+	  Patch by: <j at bootlab dot org>
+	  * gst/qtdemux/qtdemux.c: (qtdemux_video_caps):
+	  Add fourccs for MPEG2 HDV streams. Fixes #479960.
+
+2007-09-24 10:53:36 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Massive leak fixing, plus code cleanups.
+	  Original commit message from CVS:
+	  * ext/audioresample/gstaudioresample.c:
+	  * ext/x264/gstx264enc.c:
+	  * gst/dvdspu/gstdvdspu.c:
+	  * gst/dvdspu/gstdvdspu.h:
+	  * gst/festival/gstfestival.c:
+	  * gst/h264parse/gsth264parse.c:
+	  * gst/mpegtsparse/mpegtspacketizer.c:
+	  * gst/mpegtsparse/mpegtsparse.c:
+	  * gst/multifile/gstmultifilesink.c:
+	  * gst/multifile/gstmultifilesrc.c:
+	  * gst/nuvdemux/gstnuvdemux.c:
+	  * sys/dshowsrcwrapper/gstdshowaudiosrc.c:
+	  * sys/dshowsrcwrapper/gstdshowvideosrc.c:
+	  * sys/vcd/vcdsrc.c:
+	  Massive leak fixing, plus code cleanups.
+
+2007-09-23 18:57:14 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/oss/gstosshelper.c: Use GST_WARNING instead of a g_critical. This situation is not caused by the application.
+	  Original commit message from CVS:
+	  * sys/oss/gstosshelper.c:
+	  Use GST_WARNING instead of a g_critical. This situation is not caused
+	  by the application.
+
+2007-09-22 18:15:12 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  po/: Updated translations.
+	  Original commit message from CVS:
+	  * po/LINGUAS:
+	  * po/nl.po:
+	  Updated translations.
+
+2007-09-22 18:13:58 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  po/eu.po: Added Basque translation.
+	  Original commit message from CVS:
+	  translated by: Mikel Olasagasti <hey_neken@mundurat.net>
+	  * po/eu.po:
+	  Added Basque translation.
+
+2007-09-22 18:13:10 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  po/: Added Chinese (traditional and Hong Kong) translation.
+	  Original commit message from CVS:
+	  translated by: Abel Cheung <abelcheung@gmail.com>
+	  * po/zh_HK.po:
+	  * po/zh_TW.po:
+	  Added Chinese (traditional and Hong Kong) translation.
+
+2007-09-22 18:10:42 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  po/pl.po: Added Polish translation.
+	  Original commit message from CVS:
+	  translated by: Jakub Bogusz <qboosh@pld-linux.org>
+	  * po/pl.po:
+	  Added Polish translation.
+
+2007-09-22 18:09:59 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  po/fi.po: Added Finnish translation.
+	  Original commit message from CVS:
+	  translated by: Ilkka Tuohela <hile@iki.fi>
+	  * po/fi.po:
+	  Added Finnish translation.
+
+2007-09-22 18:09:09 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  po/es.po: Added Spanish translation.
+	  Original commit message from CVS:
+	  translated by: Jorge González González <aloriel@gmail.com>
+	  * po/es.po:
+	  Added Spanish translation.
+
+2007-09-22 18:08:13 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  po/da.po: Added Danish translation.
+	  Original commit message from CVS:
+	  translated by: Mogens Jaeger <mogens@jaeger.tf>
+	  * po/da.po:
+	  Added Danish translation.
+
+2007-09-22 18:06:55 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  po/zh_CN.po: Added Chinese (simplified) translation.
+	  Original commit message from CVS:
+	  translated by: Funda Wang <fundawang@linux.net.cn>
+	  * po/zh_CN.po:
+	  Added Chinese (simplified) translation.
+
+2007-09-22 18:05:37 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  po/bg.po: Added Bulgarian translation.
+	  Original commit message from CVS:
+	  translated by: Alexander Shopov <ash@contact.bg>
+	  * po/bg.po:
+	  Added Bulgarian translation.
+
+2007-09-22 08:12:57 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* common:
+	* sys/directdraw/gstdirectdrawsink.c:
+	* sys/directdraw/gstdirectdrawsink.h:
+	  fix header and comments
+	  Original commit message from CVS:
+	  fix header and comments
+
+2007-09-21 11:34:34 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpamrdepay.c: Set outgoing packet duration because we can. Fixes #478244 some more.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_process):
+	  Set outgoing packet duration because we can. Fixes #478244 some more.
+
+2007-09-20 13:35:34 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/cairo/gsttextoverlay.c: Add info about static leak.
+	  Original commit message from CVS:
+	  * ext/cairo/gsttextoverlay.c:
+	  Add info about static leak.
+	  * tests/check/Makefile.am:
+	  * tests/check/generic/states.c:
+	  Improved state change unit test.
+
+2007-09-19 18:19:49 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Ignore registries in any format.
+	  Original commit message from CVS:
+	  * docs/plugins/.cvsignore:
+	  * tests/check/.cvsignore:
+	  Ignore registries in any format.
+
+2007-09-19 16:24:09 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpL16pay.c: Removed some unused code.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpL16pay.c: (gst_rtp_L16_pay_handle_buffer):
+	  Removed some unused code.
+	  * gst/rtp/gstrtpamrpay.c: (gst_rtp_amr_pay_handle_buffer):
+	  * gst/rtp/gstrtpgsmpay.c: (gst_rtp_gsm_pay_handle_buffer):
+	  * gst/rtp/gstrtpmp2tpay.c: (gst_rtp_mp2t_pay_handle_buffer):
+	  * gst/rtp/gstrtpspeexpay.c: (gst_rtp_speex_pay_handle_buffer):
+	  * gst/rtp/gstrtptheorapay.c: (gst_rtp_theora_pay_init_packet),
+	  (gst_rtp_theora_pay_flush_packet):
+	  * gst/rtp/gstrtpvorbispay.c: (gst_rtp_vorbis_pay_flush_packet):
+	  Try to preserve the incomming buffer duration on the outgoing
+	  packets. Fixes #478244.
+
+2007-09-19 10:22:40 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/: Work around compiler warnings with g++-4.2 when assigning a string constant to a gchar * (partially fixe...
+	  Original commit message from CVS:
+	  * ext/taglib/gstapev2mux.cc:
+	  * ext/taglib/gstid3v2mux.cc:
+	  Work around compiler warnings with g++-4.2 when assigning a
+	  string constant to a gchar * (partially fixes #478092).
+
+2007-09-18 16:44:46 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: We require core CVS now for gst_base_src_set_do_timestamp().
+	  Original commit message from CVS:
+	  * configure.ac:
+	  We require core CVS now for gst_base_src_set_do_timestamp().
+
+2007-09-18 13:55:06 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/: Handling window resize.
+	  Original commit message from CVS:
+	  * gst/spectrum/demo-audiotest.c:
+	  * gst/spectrum/demo-osssrc.c:
+	  Handling window resize.
+
+2007-09-18 11:45:06 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ChangeLog: Add missing newline.
+	  Original commit message from CVS:
+	  * ChangeLog:
+	  Add missing newline.
+	  * gst/librfb/rfbdecoder.c:
+	  Fix the build (missing stdlib.h).
+	  * gst/spectrum/gstspectrum.c:
+	  * gst/spectrum/gstspectrum.h:
+	  Use basetransform segment so that it is correctly managed on flushes
+	  and start/stop. Report message timestamp as stream time, which is what
+	  an application can understand. (Yes these are adapted from wim recent
+	  level element changes)
+
+2007-09-17 17:35:13 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/: Fix compiler warnings shown with Forte.
+	  Original commit message from CVS:
+	  * gst/audiofx/audiodynamic.c: (gst_audio_dynamic_class_init):
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_create_stream),
+	  (new_session_pad), (request_pt_map), (gst_rtspsrc_do_stream_eos),
+	  (gst_rtspsrc_loop_interleaved), (gst_rtspsrc_parse_rtpinfo),
+	  (gst_rtspsrc_handle_message):
+	  Fix compiler warnings shown with Forte.
+
+2007-09-17 02:05:14 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Give meaningfull error when all streams failed to configure for some reason.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_setup_streams),
+	  (gst_rtspsrc_dup_printf):
+	  Give meaningfull error when all streams failed to configure for some
+	  reason.
+
+2007-09-16 19:13:58 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/README: Update README with the design for synchronisation rules of RTP on sender and receiver.
+	  Original commit message from CVS:
+	  * gst/rtp/README:
+	  Update README with the design for synchronisation rules of RTP on
+	  sender and receiver.
+
+2007-09-14 09:40:49 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/wavparse/gstwavparse.c: Don't push EOS from the chain function, the element driving the pipeline is responsible f...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_loop),
+	  (gst_wavparse_chain):
+	  Don't push EOS from the chain function, the element
+	  driving the pipeline is responsible for this. The bug
+	  this was meant to fix seems to be queue not forwarding
+	  EOS in all cases (see #476514).
+
+2007-09-13 17:31:16 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/level/gstlevel.*: Use basetransform segment so that it is correctly managed on flushes and start/stop.
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c: (gst_level_class_init), (gst_level_start),
+	  (gst_level_transform_ip):
+	  * gst/level/gstlevel.h:
+	  Use basetransform segment so that it is correctly managed on flushes and
+	  start/stop.
+	  Report message timestamp as stream time, which is what an application
+	  can understand.
+
+2007-09-13 15:04:15 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Update my mail address.
+	  Original commit message from CVS:
+	  * ext/taglib/gstapev2mux.cc:
+	  * ext/taglib/gstapev2mux.h:
+	  * ext/taglib/gsttaglibmux.c:
+	  * tests/check/elements/apev2mux.c:
+	  Update my mail address.
+
+2007-09-13 12:37:56 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/wavparse/gstwavparse.c: Add EOS logic for the push-based mode too. Fixes #476514.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_perform_eos),
+	  (gst_wavparse_loop), (gst_wavparse_chain):
+	  Add EOS logic for the push-based mode too. Fixes #476514.
+
+2007-09-12 22:01:59 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/law/: Fix law encoder timestamps.
+	  Original commit message from CVS:
+	  * gst/law/alaw-encode.c: (gst_alawenc_init), (gst_alawenc_chain):
+	  * gst/law/alaw-encode.h:
+	  * gst/law/mulaw-encode.c: (gst_mulawenc_init),
+	  (gst_mulawenc_chain):
+	  * gst/law/mulaw-encode.h:
+	  Fix law encoder timestamps.
+
+2007-09-12 09:13:39 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/gconf/gstgconfaudiosink.c: Fix warning when building without debug.
+	  Original commit message from CVS:
+	  * ext/gconf/gstgconfaudiosink.c:
+	  Fix warning when building without debug.
+	  * sys/oss/gstossmixertrack.c:
+	  Use const like in alsamixertrack.c (fixes warnings).
+
+2007-09-12 08:38:21 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/: Printf format fixes (#476128).
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt  <pkj at axis com>
+	  * gst-libs/gst/app/gstappsink.c:
+	  * gst/flv/gstflvdemux.c:
+	  * gst/flv/gstflvparse.c:
+	  * gst/interleave/deinterleave.c:
+	  * gst/switch/gstswitch.c:
+	  Printf format fixes (#476128).
+
+2007-09-11 15:37:55 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/v4l2/v4l2src_calls.c: Fix framerate detection code some more.
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c:
+	  (gst_v4l2src_probe_caps_for_format_and_size):
+	  Fix framerate detection code some more.
+	  Handle the case where there is a weird step in the stepwise framerates.
+	  Don't overwrite the min interval with the framerate, use a temp variable
+	  instead.
+	  Use max in the Continuous framerate intervals instead of step, which is
+	  1 according to the docs. Fixes #475424.
+
+2007-09-10 19:53:28 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstudpsrc.c: Make udpsrc timestamp outgoing buffers based on when they were received.
+	  Original commit message from CVS:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_init), (gst_udpsrc_create):
+	  Make udpsrc timestamp outgoing buffers based on when they were received.
+	  Also make it output a segment in time.
+
+2007-09-10 06:49:32 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.c: Plug a little leak. Little code cleanups.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  Plug a little leak. Little code cleanups.
+
+2007-09-09 18:08:36 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Use AC_TRY_COMPILE instead of AC_TRY_RUN to check for old flac versions, 's good for cross-compilation ...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Use AC_TRY_COMPILE instead of AC_TRY_RUN to check for old
+	  flac versions, 's good for cross-compilation karma.
+
+2007-09-07 18:04:41 +0000  Haakon Sporsheim <haakon.sporsheim@tandberg.com>
+
+	  gst/rtp/gstrtph263pay.c: Fix up header structure so that compilers don't add padding between the structure fields, si...
+	  Original commit message from CVS:
+	  Patch by: Haakon Sporsheim  <haakon.sporsheim at tandberg com>
+	  * gst/rtp/gstrtph263pay.c:
+	  Fix up header structure so that compilers don't add padding
+	  between the structure fields, since that would lead to us
+	  sending RTP packets with broken headers (as is currently the
+	  case when compiling with MSVC). Also see similar fixes in
+	  libgstrtp in gst-plugins-base. (#474616; #471194)
+
+2007-09-07 16:04:14 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/v4l2/v4l2src_calls.c: Don't overwrite our GValue with 0 but instead use the previously computed value. Fixes #471...
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c:
+	  (gst_v4l2src_probe_caps_for_format_and_size):
+	  Don't overwrite our GValue with 0 but instead use the previously
+	  computed value. Fixes #471823 some more.
+
+2007-09-07 15:54:38 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/spectrum/gstspectrum.c: Use the correct parameter order for the memset calls.
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_start),
+	  (gst_spectrum_transform_ip):
+	  Use the correct parameter order for the memset calls.
+	  Thanks to Christian Schaller for noticing.
+
+2007-09-06 12:00:36 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  docs/plugins/gst-plugins-good-plugins.hierarchy: No tabs in this file please, or gtk-doc will end up documenting rath...
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  No tabs in this file please, or gtk-doc will end up documenting
+	  rather absurd class hierarchies.
+
+2007-09-06 10:48:56 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/gconf/gstswitchsink.c: If the new kid element fails to change state for some reason forward the error message it ...
+	  Original commit message from CVS:
+	  * ext/gconf/gstswitchsink.c:
+	  If the new kid element fails to change state for some reason
+	  (e.g. esdsink not being able to connect to the sound server),
+	  forward the error message it posted on the bus instead of just
+	  posting a generic 'Internal state change error: please file a
+	  bug' error message. Fixes #471364.
+
+2007-09-06 07:21:22 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Port GstSpectrum to GstAudioFilter and libgstfft, add support for int32, float and double, use floats for the message...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/spectrum/Makefile.am:
+	  * gst/spectrum/demo-audiotest.c: (draw_spectrum),
+	  (message_handler), (main):
+	  * gst/spectrum/demo-osssrc.c: (draw_spectrum), (message_handler):
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_base_init),
+	  (gst_spectrum_class_init), (gst_spectrum_init),
+	  (gst_spectrum_dispose), (gst_spectrum_set_property),
+	  (gst_spectrum_get_property), (gst_spectrum_start),
+	  (gst_spectrum_setup), (gst_spectrum_message_new),
+	  (gst_spectrum_transform_ip):
+	  * gst/spectrum/gstspectrum.h:
+	  Port GstSpectrum to GstAudioFilter and libgstfft, add support
+	  for int32, float and double, use floats for the message contents,
+	  average all FFTs done in one interval for better results, use
+	  a better windowing function, allow posting the phase in the message
+	  and actually do an FFT with the requested number of bands instead
+	  of interpolating.
+	  * tests/check/elements/spectrum.c: (GST_START_TEST),
+	  (spectrum_suite):
+	  Improve the units tests by checking for a 11025Hz sine wave
+	  and add unit tests for all 4 supported sample types.
+
+2007-09-05 16:23:21 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/: Don't assume tags are encoded as UTF-8 (#473670).
+	  Original commit message from CVS:
+	  * gst/qtdemux/Makefile.am:
+	  * gst/qtdemux/qtdemux.c:
+	  Don't assume tags are encoded as UTF-8 (#473670).
+
+2007-09-05 14:43:16 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/v4l2/: Implement LATENCY queries in the crudest way possible so I don't have to use sync=false any longer when te...
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c:
+	  * sys/v4l2/gstv4l2src.h:
+	  * sys/v4l2/v4l2src_calls.c:
+	  Implement LATENCY queries in the crudest way possible so I don't
+	  have to use sync=false any longer when testing with videosinks.
+
+2007-09-05 09:25:23 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Fix build.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Fix build.
+
+2007-09-05 00:12:46 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/v4l2/v4l2src_calls.c: Add some more debugging in the framerate function.
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c:
+	  (gst_v4l2src_probe_caps_for_format_and_size):
+	  Add some more debugging in the framerate function.
+	  Iterate stepwise framerate up to and _including_ the max and if nothing
+	  was added to the list, add a dummy 0/1 to 100/1 framerate so that we
+	  don't end up with an empty list.
+
+2007-09-04 22:42:21 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstmultiudpsink.c: Add property do configure destination address/port pairs
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_class_init),
+	  (gst_multiudpsink_set_clients_string),
+	  (gst_multiudpsink_get_clients_string),
+	  (gst_multiudpsink_set_property), (gst_multiudpsink_get_property),
+	  (gst_multiudpsink_init_send), (gst_multiudpsink_add_internal),
+	  (gst_multiudpsink_add), (gst_multiudpsink_clear_internal),
+	  (gst_multiudpsink_clear):
+	  Add property do configure destination address/port pairs
+	  API:GstMultiUDPSink::clients
+
+2007-09-04 18:30:22 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  tests/examples/: Added some RTP example scripts for sending and receiving RTP streams.
+	  Original commit message from CVS:
+	  * tests/examples/Makefile.am:
+	  * tests/examples/rtp/Makefile.am:
+	  * tests/examples/rtp/client-H263p-AMR.sh:
+	  * tests/examples/rtp/client-H263p-PCMA.sdp:
+	  * tests/examples/rtp/client-H263p-PCMA.sh:
+	  * tests/examples/rtp/client-H264-PCMA.sdp:
+	  * tests/examples/rtp/client-H264-PCMA.sh:
+	  * tests/examples/rtp/client-PCMA.sh:
+	  * tests/examples/rtp/server-VTS-H263p-ATS-PCMA.sh:
+	  * tests/examples/rtp/server-alsasrc-PCMA.sh:
+	  * tests/examples/rtp/server-v4l2-H263p-alsasrc-AMR.sh:
+	  * tests/examples/rtp/server-v4l2-H264-alsasrc-PCMA.sh:
+	  Added some RTP example scripts for sending and receiving RTP streams.
+
+2007-09-04 16:40:05 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/v4l2/gstv4l2src.c: Restructure the setcaps function so that we can also compute the expected GStreamer output siz...
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2_get_caps_info),
+	  (gst_v4l2src_set_caps), (gst_v4l2src_get_mmap):
+	  Restructure the setcaps function so that we can also compute the
+	  expected GStreamer output size of the video frames.
+	  Set frame_byte_size correctly so that read-based devices have a chance
+	  of working correctly.
+	  When grabbing a frame, discard frames that are not of the expected size.
+	  Some cameras don't output the right framesize for the first buffer.
+	  Try only a couple of times to get a valid frame, else error out.
+	  * sys/v4l2/v4l2_calls.c: (gst_v4l2_get_capabilities),
+	  (gst_v4l2_fill_lists), (gst_v4l2_get_input):
+	  Add some more debug info when scanning the device.
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2_buffer_new),
+	  (gst_v4l2_buffer_pool_new), (gst_v4l2_buffer_pool_activate),
+	  (gst_v4l2src_fill_format_list), (gst_v4l2src_grab_frame),
+	  (gst_v4l2src_set_capture), (gst_v4l2src_capture_init):
+	  Add some more debug info when dequeing a frame.
+
+2007-09-04 14:37:22 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/wavparse/gstwavparse.c: More code cleanups. Add some more comment and improve debugs logs.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c:
+	  More code cleanups. Add some more comment and improve debugs logs.
+
+2007-09-04 07:58:36 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/wavparse/gstwavparse.*: Implement seek-query. Refactor duration calculations. Appropriate use of uint64_scale_int...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c:
+	  * gst/wavparse/gstwavparse.h:
+	  Implement seek-query. Refactor duration calculations. Appropriate use
+	  of uint64_scale_int and uint64_scale. Move repeadedly calculated stuff
+	  out of loops.
+
+2007-09-03 07:44:34 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.c: Implement seek-query.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  Implement seek-query.
+
+2007-08-29 21:43:08 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Use new basesink async property to make sparse RTCP packet not wait for preroll.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_stream_configure_udp_sink),
+	  (gst_rtspsrc_dup_printf):
+	  Use new basesink async property to make sparse RTCP packet not wait for
+	  preroll.
+
+2007-08-27 14:44:19 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/audiofx/Makefile.am: Dist the right file.
+	  Original commit message from CVS:
+	  * gst/audiofx/Makefile.am:
+	  Dist the right file.
+
+2007-08-23 16:27:36 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Make sure we generate and parse floating point values in the POSIX locale instead of the curre...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_dup_printf),
+	  (gst_rtspsrc_get_float), (gst_rtspsrc_play):
+	  Make sure we generate and parse floating point values in the POSIX
+	  locale instead of the current locale.
+
+2007-08-22 15:01:29 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Fix method detection again.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_do_seek),
+	  (gst_rtspsrc_parse_methods), (gst_rtspsrc_open),
+	  (gst_rtspsrc_play):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Fix method detection again.
+	  Keep track of when we must send a Range header.
+	  Use segment values for Range, Speed and Scale headers.
+	  Parse Speed and Scale headers to update the segment values.
+
+2007-08-22 08:22:50 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  sys/v4l2/v4l2src_calls.c: Handle optional v4l2 ioctls gracefully.
+	  Original commit message from CVS:
+	  patch by: Mark Nauwelaerts <manauw@skynet.be>
+	  * sys/v4l2/v4l2src_calls.c:
+	  Handle optional v4l2 ioctls gracefully.
+
+2007-08-20 16:52:03 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Added an H263 depayloader. Fixes #369392.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtph263depay.c: (gst_rtp_h263_depay_base_init),
+	  (gst_rtp_h263_depay_class_init), (gst_rtp_h263_depay_init),
+	  (gst_rtp_h263_depay_finalize), (gst_rtp_h263_depay_setcaps),
+	  (gst_rtp_h263_depay_process), (gst_rtp_h263_depay_set_property),
+	  (gst_rtp_h263_depay_get_property),
+	  (gst_rtp_h263_depay_change_state),
+	  (gst_rtp_h263_depay_plugin_init):
+	  * gst/rtp/gstrtph263depay.h:
+	  Added an H263 depayloader. Fixes #369392.
+	  * gst/rtp/gstrtph263pdepay.c: (gst_rtp_h263p_depay_setcaps),
+	  (gst_rtp_h263p_depay_process):
+	  * gst/rtp/gstrtph263ppay.c: (gst_fragmentation_mode_get_type),
+	  (gst_rtp_h263p_pay_class_init), (gst_rtp_h263p_pay_flush):
+	  Make the H263+ pay/depayloader support H263-1998 and H263-2000
+	  payloads.
+	  Also alow plain H263 on the h263p payloaders. Fixes #465040.
+
+2007-08-19 19:16:33 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/: Add small comparision with the chebyshev filters in the docs.
+	  Original commit message from CVS:
+	  * gst/filter/gstbpwsinc.c:
+	  * gst/filter/gstlpwsinc.c:
+	  Add small comparision with the chebyshev filters in the docs.
+
+2007-08-19 19:11:04 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/: Add small comparision with the windowed sinc filters in the docs.
+	  Original commit message from CVS:
+	  * gst/audiofx/audiochebyshevfreqband.c:
+	  * gst/audiofx/audiochebyshevfreqlimit.c:
+	  Add small comparision with the windowed sinc filters in the docs.
+
+2007-08-19 19:01:45 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/: Also test everything in 32 bit float mode.
+	  Original commit message from CVS:
+	  * tests/check/elements/bpwsinc.c: (GST_START_TEST),
+	  (bpwsinc_suite):
+	  * tests/check/elements/lpwsinc.c: (GST_START_TEST),
+	  (lpwsinc_suite):
+	  Also test everything in 32 bit float mode.
+
+2007-08-19 18:47:19 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/: Also test 32 bit float mode and the type 2 variants of the filters.
+	  Original commit message from CVS:
+	  * tests/check/elements/audiochebyshevfreqband.c: (GST_START_TEST),
+	  (audiochebyshevfreqband_suite):
+	  * tests/check/elements/audiochebyshevfreqlimit.c: (GST_START_TEST),
+	  (audiochebyshevfreqlimit_suite):
+	  Also test 32 bit float mode and the type 2 variants of the filters.
+
+2007-08-18 19:44:55 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Refactor the udp and interleaved loop function a bit.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_loop_interleaved),
+	  (gst_rtspsrc_loop_udp), (gst_rtspsrc_loop_send_cmd),
+	  (gst_rtspsrc_loop):
+	  Refactor the udp and interleaved loop function a bit.
+
+2007-08-17 17:08:11 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Protect connection activity with a new lock, avoids deadlocks when going to PAUSED. Fixes #455...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init),
+	  (gst_rtspsrc_finalize), (gst_rtspsrc_connection_send),
+	  (gst_rtspsrc_connection_receive), (gst_rtspsrc_sink_chain),
+	  (gst_rtspsrc_handle_request), (gst_rtspsrc_send_keep_alive),
+	  (gst_rtspsrc_loop_interleaved), (gst_rtspsrc_loop_udp),
+	  (gst_rtspsrc_try_send), (gst_rtspsrc_pause):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Protect connection activity with a new lock, avoids deadlocks when going
+	  to PAUSED. Fixes #455808.
+
+2007-08-17 15:30:39 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/debug/rndbuffersize.c: Fix debug statement.
+	  Original commit message from CVS:
+	  * gst/debug/rndbuffersize.c: (gst_rnd_buffer_size_loop):
+	  Fix debug statement.
+
+2007-08-17 15:28:40 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Fix stray %u in debug line as spotted by Saur on IRC.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_do_stream_eos):
+	  Fix stray %u in debug line as spotted by Saur on IRC.
+
+2007-08-17 15:05:17 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Use generator macros for the process functions for the different sample types, add lower upper boundaries for the GOb...
+	  Original commit message from CVS:
+	  * gst/filter/gstbpwsinc.c: (gst_bpwsinc_class_init),
+	  (bpwsinc_set_property), (bpwsinc_get_property):
+	  * gst/filter/gstbpwsinc.h:
+	  * gst/filter/gstlpwsinc.c: (gst_lpwsinc_class_init),
+	  (gst_lpwsinc_init), (lpwsinc_build_kernel), (lpwsinc_set_property),
+	  (lpwsinc_get_property):
+	  * gst/filter/gstlpwsinc.h:
+	  * tests/check/elements/lpwsinc.c: (GST_START_TEST):
+	  Use generator macros for the process functions for the different
+	  sample types, add lower upper boundaries for the GObject properties
+	  so automatically generated UIs can use sliders and change frequency
+	  properties to floats to save a bit of memory, even ints would in
+	  theory be enough. Also rename frequency to cutoff for consistency
+	  reasons.
+	  * docs/plugins/gst-plugins-bad-plugins.args:
+	  * docs/plugins/gst-plugins-bad-plugins.signals:
+	  * docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	  Regenerated for the above changes.
+
+2007-08-17 14:43:33 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/: Use generator macros for the process functions for the different sample types, add lower upper boundari...
+	  Original commit message from CVS:
+	  * gst/audiofx/audiochebyshevfreqband.c:
+	  (gst_audio_chebyshev_freq_band_class_init):
+	  * gst/audiofx/audiochebyshevfreqlimit.c:
+	  (gst_audio_chebyshev_freq_limit_class_init):
+	  Use generator macros for the process functions for the different
+	  sample types, add lower upper boundaries for the GObject properties
+	  so automatically generated UIs can use sliders and add a note about
+	  the number of poles as a too high number of poles combined with
+	  very low or very high frequencies will produce only noise.
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  Regenerated for the property changes.
+
+2007-08-17 14:15:19 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Improve timeout handling.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_set_property),
+	  (gst_rtspsrc_flush), (gst_rtspsrc_sink_chain),
+	  (gst_rtspsrc_stream_configure_udp_sink),
+	  (gst_rtspsrc_send_keep_alive), (gst_rtspsrc_loop_interleaved),
+	  (gst_rtspsrc_loop_udp), (gst_rtspsrc_loop_send_cmd),
+	  (gst_rtspsrc_try_send), (gst_rtspsrc_send),
+	  (gst_rtspsrc_parse_methods), (gst_rtspsrc_parse_range),
+	  (gst_rtspsrc_open), (gst_rtspsrc_close), (gst_rtspsrc_pause),
+	  (gst_rtspsrc_handle_message), (gst_rtspsrc_change_state):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Improve timeout handling.
+	  Use the same socket for sending and receiving RTCP packets so that some
+	  servers can track clients better.
+	  Improve connection closed handling. Try to reconnect.
+	  Don't overwrite our content base with NULL.
+	  Improve debugging.
+	  Improve range parsing and handling.
+	  Remove flushing hack now that core does the right thing.
+
+2007-08-17 13:59:15 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstmultiudpsink.*: Add support for getting and setting the socket to use.
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_class_init),
+	  (gst_multiudpsink_init), (gst_multiudpsink_set_property),
+	  (gst_multiudpsink_get_property), (gst_multiudpsink_init_send),
+	  (gst_multiudpsink_close), (gst_multiudpsink_add):
+	  * gst/udp/gstmultiudpsink.h:
+	  Add support for getting and setting the socket to use.
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init), (gst_udpsrc_init),
+	  (gst_udpsrc_create), (gst_udpsrc_get_property):
+	  Add support for getting the currently used socket.
+
+2007-08-16 19:22:48 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/gstbpwsinc.*: Implement latency query and only forward those samples downstream that actually contain the ...
+	  Original commit message from CVS:
+	  * gst/filter/gstbpwsinc.c: (gst_bpwsinc_class_init),
+	  (gst_bpwsinc_init), (process_32), (process_64),
+	  (bpwsinc_build_kernel), (bpwsinc_push_residue),
+	  (bpwsinc_transform), (bpwsinc_start), (bpwsinc_query),
+	  (bpwsinc_query_type), (bpwsinc_event), (bpwsinc_set_property):
+	  * gst/filter/gstbpwsinc.h:
+	  Implement latency query and only forward those samples downstream
+	  that actually contain the data we want, i.e. drop kernel_length/2
+	  in the beginning and append kernel_length/2 (created by convolving
+	  the filter kernel with zeroes) to the end.
+	  * tests/check/elements/bpwsinc.c: (GST_START_TEST):
+	  Adjust the unit test for this slightly changed behaviour.
+	  * gst/filter/gstlpwsinc.c: (lpwsinc_build_kernel):
+	  Reset residue length only when actually creating a residue.
+
+2007-08-16 17:02:07 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/: Add Chebyshev lowpass/highpass and bandpass/bandreject elements.
+	  Original commit message from CVS:
+	  reviewed by: Stefan Kost  <ensonic@users.sf.net>
+	  * gst/audiofx/Makefile.am:
+	  * gst/audiofx/audiochebyshevfreqband.c:
+	  (gst_audio_chebyshev_freq_band_mode_get_type),
+	  (gst_audio_chebyshev_freq_band_base_init),
+	  (gst_audio_chebyshev_freq_band_dispose),
+	  (gst_audio_chebyshev_freq_band_class_init),
+	  (gst_audio_chebyshev_freq_band_init),
+	  (generate_biquad_coefficients), (calculate_gain),
+	  (generate_coefficients),
+	  (gst_audio_chebyshev_freq_band_set_property),
+	  (gst_audio_chebyshev_freq_band_get_property),
+	  (gst_audio_chebyshev_freq_band_setup), (process), (process_64),
+	  (process_32), (gst_audio_chebyshev_freq_band_transform_ip),
+	  (gst_audio_chebyshev_freq_band_start):
+	  * gst/audiofx/audiochebyshevfreqband.h:
+	  * gst/audiofx/audiochebyshevfreqlimit.c:
+	  (gst_audio_chebyshev_freq_limit_mode_get_type),
+	  (gst_audio_chebyshev_freq_limit_base_init),
+	  (gst_audio_chebyshev_freq_limit_dispose),
+	  (gst_audio_chebyshev_freq_limit_class_init),
+	  (gst_audio_chebyshev_freq_limit_init),
+	  (generate_biquad_coefficients), (calculate_gain),
+	  (generate_coefficients),
+	  (gst_audio_chebyshev_freq_limit_set_property),
+	  (gst_audio_chebyshev_freq_limit_get_property),
+	  (gst_audio_chebyshev_freq_limit_setup), (process), (process_64),
+	  (process_32), (gst_audio_chebyshev_freq_limit_transform_ip),
+	  (gst_audio_chebyshev_freq_limit_start):
+	  * gst/audiofx/audiochebyshevfreqlimit.h:
+	  * gst/audiofx/audiofx.c: (plugin_init):
+	  Add Chebyshev lowpass/highpass and bandpass/bandreject elements.
+	  Fixes #464800.
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/audiochebyshevfreqband.c:
+	  (setup_audiochebyshevfreqband), (cleanup_audiochebyshevfreqband),
+	  (GST_START_TEST), (audiochebyshevfreqband_suite), (main):
+	  * tests/check/elements/audiochebyshevfreqlimit.c:
+	  (setup_audiochebyshevfreqlimit), (cleanup_audiochebyshevfreqlimit),
+	  (GST_START_TEST), (audiochebyshevfreqlimit_suite), (main):
+	  Add unit tests for the chebyshev filters.
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/inspect/plugin-1394.xml:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  * docs/plugins/inspect/plugin-dv.xml:
+	  * docs/plugins/inspect/plugin-flac.xml:
+	  * docs/plugins/inspect/plugin-jpeg.xml:
+	  * docs/plugins/inspect/plugin-png.xml:
+	  * docs/plugins/inspect/plugin-rtp.xml:
+	  * docs/plugins/inspect/plugin-shout2send.xml:
+	  * docs/plugins/inspect/plugin-wavpack.xml:
+	  And add docs for the chebyshev filters. While doing
+	  that also run make update in docs/plugins.
+
+2007-08-16 12:15:06 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Make ro memory to share.
+	  Original commit message from CVS:
+	  * ext/annodex/gstcmmltag.c:
+	  * gst/rtp/gstrtpvorbispay.c:
+	  Make ro memory to share.
+
+2007-08-16 11:49:01 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstudpsrc.c: Improve UDP performance by avoiding a select() when we have data available immediatly.
+	  Original commit message from CVS:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_create):
+	  Improve UDP performance by avoiding a select() when we have data
+	  available immediatly.
+
+2007-08-16 11:47:19 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtpdec.*: Add (dummy) SSRC management signals.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtpdec.c: (gst_rtp_dec_marshal_VOID__UINT_UINT),
+	  (gst_rtp_dec_class_init):
+	  * gst/rtsp/gstrtpdec.h:
+	  Add (dummy) SSRC management signals.
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_class_init),
+	  (gst_rtspsrc_set_property), (gst_rtspsrc_get_property),
+	  (find_stream), (gst_rtspsrc_create_stream), (new_session_pad),
+	  (request_pt_map), (gst_rtspsrc_do_stream_eos), (on_bye_ssrc),
+	  (on_timeout), (gst_rtspsrc_stream_configure_manager),
+	  (gst_rtspsrc_stream_push_event), (gst_rtspsrc_push_event),
+	  (gst_rtspsrc_loop_interleaved), (gst_rtspsrc_parse_rtpinfo),
+	  (gst_rtspsrc_handle_message), (gst_rtspsrc_change_state):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Add connection-speed property.
+	  Add find_stream helper functions.
+	  Handle stream EOS based on BYE messages or SSRC timeout.
+	  Returns SUCCESS from the state change function as we hide our async
+	  elements from the parent.
+
+2007-08-16 09:48:27 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/gstlpwsinc.*: Implement latency query and only forward those samples downstream that actually contain the ...
+	  Original commit message from CVS:
+	  * gst/filter/gstlpwsinc.c: (gst_lpwsinc_class_init),
+	  (gst_lpwsinc_init), (process_32), (process_64),
+	  (lpwsinc_build_kernel), (lpwsinc_push_residue),
+	  (lpwsinc_transform), (lpwsinc_start), (lpwsinc_query),
+	  (lpwsinc_query_type), (lpwsinc_event), (lpwsinc_set_property):
+	  * gst/filter/gstlpwsinc.h:
+	  Implement latency query and only forward those samples downstream
+	  that actually contain the data we want, i.e. drop kernel_length/2
+	  in the beginning and append kernel_length/2 (created by convolving
+	  the filter kernel with zeroes) to the end.
+	  * tests/check/elements/lpwsinc.c: (GST_START_TEST):
+	  Adjust the unit test for this slightly changed behaviour.
+
+2007-08-16 07:40:48 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/debug/rndbuffersize.c: Fix da leak.
+	  Original commit message from CVS:
+	  * gst/debug/rndbuffersize.c:
+	  Fix da leak.
+
+2007-08-14 13:50:43 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/debug/: Add new test element and clean-up the others a little.
+	  Original commit message from CVS:
+	  * gst/debug/Makefile.am:
+	  * gst/debug/breakmydata.c:
+	  * gst/debug/gstdebug.c:
+	  * gst/debug/negotiation.c:
+	  * gst/debug/progressreport.c:
+	  * gst/debug/rndbuffersize.c:
+	  * gst/debug/testplugin.c:
+	  Add new test element and clean-up the others a little.
+
+2007-08-13 13:50:39 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Add docs for lpwsinc and bpwsinc and integrate them into the build system. While doing that also update all other doc...
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-bad-plugins.args:
+	  * docs/plugins/gst-plugins-bad-plugins.signals:
+	  * docs/plugins/inspect/plugin-bz2.xml:
+	  * docs/plugins/inspect/plugin-cdxaparse.xml:
+	  * docs/plugins/inspect/plugin-dtsdec.xml:
+	  * docs/plugins/inspect/plugin-faac.xml:
+	  * docs/plugins/inspect/plugin-faad.xml:
+	  * docs/plugins/inspect/plugin-filter.xml:
+	  * docs/plugins/inspect/plugin-freeze.xml:
+	  * docs/plugins/inspect/plugin-gsm.xml:
+	  * docs/plugins/inspect/plugin-gstrtpmanager.xml:
+	  * docs/plugins/inspect/plugin-h264parse.xml:
+	  * docs/plugins/inspect/plugin-modplug.xml:
+	  * docs/plugins/inspect/plugin-mpeg2enc.xml:
+	  * docs/plugins/inspect/plugin-musepack.xml:
+	  * docs/plugins/inspect/plugin-musicbrainz.xml:
+	  * docs/plugins/inspect/plugin-nsfdec.xml:
+	  * docs/plugins/inspect/plugin-replaygain.xml:
+	  * docs/plugins/inspect/plugin-soundtouch.xml:
+	  * docs/plugins/inspect/plugin-spcdec.xml:
+	  * docs/plugins/inspect/plugin-spectrum.xml:
+	  * docs/plugins/inspect/plugin-speed.xml:
+	  * docs/plugins/inspect/plugin-tta.xml:
+	  * docs/plugins/inspect/plugin-videosignal.xml:
+	  * docs/plugins/inspect/plugin-xingheader.xml:
+	  * docs/plugins/inspect/plugin-xvid.xml:
+	  * gst/filter/gstbpwsinc.c:
+	  * gst/filter/gstbpwsinc.h:
+	  * gst/filter/gstlpwsinc.c:
+	  * gst/filter/gstlpwsinc.h:
+	  Add docs for lpwsinc and bpwsinc and integrate them
+	  into the build system. While doing that also update
+	  all other docs via make update in docs/plugins.
+
+2007-08-12 20:55:01 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/bpwsinc.c: Make one test constraint a bit stricter.
+	  Original commit message from CVS:
+	  * tests/check/elements/bpwsinc.c: (GST_START_TEST):
+	  Make one test constraint a bit stricter.
+
+2007-08-12 20:53:11 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/: Add unit tests for bpwsinc, testing fundamental functionality again.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/bpwsinc.c: (setup_bpwsinc),
+	  (cleanup_bpwsinc), (GST_START_TEST), (bpwsinc_suite), (main):
+	  Add unit tests for bpwsinc, testing fundamental functionality again.
+
+2007-08-12 20:19:37 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/: Add unit tests for lpwsinc, testing fundamental functionality.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/lpwsinc.c: (setup_lpwsinc),
+	  (cleanup_lpwsinc), (GST_START_TEST), (lpwsinc_suite), (main):
+	  Add unit tests for lpwsinc, testing fundamental functionality.
+
+2007-08-12 15:41:57 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/: Improve debugging a bit.
+	  Original commit message from CVS:
+	  * gst/filter/gstbpwsinc.c: (bpwsinc_build_kernel):
+	  * gst/filter/gstlpwsinc.c: (lpwsinc_build_kernel):
+	  Improve debugging a bit.
+
+2007-08-12 14:35:41 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Fix parsing of mp4a version 0 atoms. Fixes #465774.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_node):
+	  Fix parsing of mp4a version 0 atoms. Fixes #465774.
+
+2007-08-12 12:46:20 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/: Reset the residue in BaseTransform::start to get a clean residue on stream changes.
+	  Original commit message from CVS:
+	  * gst/filter/gstbpwsinc.c: (gst_bpwsinc_class_init),
+	  (bpwsinc_start):
+	  * gst/filter/gstlpwsinc.c: (gst_lpwsinc_class_init),
+	  (lpwsinc_start):
+	  Reset the residue in BaseTransform::start to get a clean residue
+	  on stream changes.
+
+2007-08-11 15:58:30 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/: Fix processing with buffer sizes that are larger than the filter kernel size.
+	  Original commit message from CVS:
+	  * gst/filter/gstbpwsinc.c: (process_32), (process_64):
+	  * gst/filter/gstlpwsinc.c: (process_32), (process_64):
+	  Fix processing with buffer sizes that are larger than the filter
+	  kernel size.
+
+2007-08-10 17:08:01 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/rtp/gstrtpilbcdepay.c: Include stdlib.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpilbcdepay.c:
+	  Include stdlib.
+
+2007-08-10 16:10:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmpvdepay.c: Set the mpegversion in the caps so that autoplugging does not get confused.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmpvdepay.c:
+	  Set the mpegversion in the caps so that autoplugging does not get
+	  confused.
+
+2007-08-10 05:51:40 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/gstbpwsinc.c: Fix a segfault with more than one channel and don't rebuild the kernel & residue with every ...
+	  Original commit message from CVS:
+	  * gst/filter/gstbpwsinc.c: (bpwsinc_build_kernel):
+	  Fix a segfault with more than one channel and don't rebuild
+	  the kernel & residue with every buffer.
+
+2007-08-10 05:35:25 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/gstbpwsinc.*: Add support for a bandreject mode and allow specifying the window function that should be used.
+	  Original commit message from CVS:
+	  * gst/filter/gstbpwsinc.c: (gst_bpwsinc_mode_get_type),
+	  (gst_bpwsinc_window_get_type), (gst_bpwsinc_class_init),
+	  (gst_bpwsinc_init), (bpwsinc_build_kernel), (bpwsinc_set_property),
+	  (bpwsinc_get_property):
+	  * gst/filter/gstbpwsinc.h:
+	  Add support for a bandreject mode and allow specifying the window
+	  function that should be used.
+	  * gst/filter/gstlpwsinc.c:
+	  And another small formatting fix.
+
+2007-08-10 05:20:06 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/gstbpwsinc.*: Apply the same changes to the bandpass filter:
+	  Original commit message from CVS:
+	  * gst/filter/gstbpwsinc.c: (gst_bpwsinc_class_init),
+	  (gst_bpwsinc_init), (process_32), (process_64),
+	  (bpwsinc_build_kernel), (bpwsinc_setup), (bpwsinc_get_unit_size),
+	  (bpwsinc_transform), (bpwsinc_set_property),
+	  (bpwsinc_get_property):
+	  * gst/filter/gstbpwsinc.h:
+	  Apply the same changes to the bandpass filter:
+	  - Support double input
+	  - Fix processing for input with >1 channels
+	  - Specify frequency in Hz
+	  - Specify actual filter kernel length
+	  - Use transform instead of transform_ip as we're working
+	  out of place anyway
+	  - Factor out filter kernel generation and update the filter
+	  kernel when the properties are set
+	  Fix bandpass filter kernel generation to actually generate
+	  a bandpass filter by creating a highpass instead of a second
+	  lowpass.
+	  * gst/filter/gstlpwsinc.c: (gst_lpwsinc_class_init):
+	  Small formatting fix.
+
+2007-08-10 04:44:43 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/gstlpwsinc.*: Specify the actual filter length instead of a weird 2N+1. Setting the property will round to...
+	  Original commit message from CVS:
+	  * gst/filter/gstlpwsinc.c: (gst_lpwsinc_class_init),
+	  (gst_lpwsinc_init), (process_32), (process_64),
+	  (lpwsinc_build_kernel), (lpwsinc_set_property),
+	  (lpwsinc_get_property):
+	  * gst/filter/gstlpwsinc.h:
+	  Specify the actual filter length instead of a weird
+	  2N+1. Setting the property will round to the next odd number.
+	  Also remove now obsolete FIXMEs.
+
+2007-08-10 04:32:47 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/gstlpwsinc.*: Allow choosing between hamming and blackman window. The blackman window provides a better st...
+	  Original commit message from CVS:
+	  * gst/filter/gstlpwsinc.c: (gst_lpwsinc_window_get_type),
+	  (gst_lpwsinc_class_init), (gst_lpwsinc_init),
+	  (lpwsinc_build_kernel), (lpwsinc_set_property),
+	  (lpwsinc_get_property):
+	  * gst/filter/gstlpwsinc.h:
+	  Allow choosing between hamming and blackman window. The blackman
+	  window provides a better stopband attenuation but a bit slower
+	  rolloff.
+
+2007-08-10 04:21:39 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/gstlpwsinc.*: Add a highpass mode.
+	  Original commit message from CVS:
+	  * gst/filter/gstlpwsinc.c: (gst_lpwsinc_mode_get_type),
+	  (gst_lpwsinc_class_init), (process_32), (process_64),
+	  (lpwsinc_build_kernel), (lpwsinc_set_property),
+	  (lpwsinc_get_property):
+	  * gst/filter/gstlpwsinc.h:
+	  Add a highpass mode.
+
+2007-08-10 04:06:53 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/gstlpwsinc.c: Fix processing if the input has more than one channel.
+	  Original commit message from CVS:
+	  * gst/filter/gstlpwsinc.c: (process_32), (process_64),
+	  (lpwsinc_build_kernel):
+	  Fix processing if the input has more than one channel.
+
+2007-08-09 19:23:33 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/gstbpwsinc.c: "this" is a C++ keyword, use "self" instead.
+	  Original commit message from CVS:
+	  * gst/filter/gstbpwsinc.c: (gst_bpwsinc_dispose),
+	  (gst_bpwsinc_init), (bpwsinc_setup), (bpwsinc_transform_ip),
+	  (bpwsinc_set_property), (bpwsinc_get_property):
+	  "this" is a C++ keyword, use "self" instead.
+	  Add TODOs and FIXMEs and remove two wrong FIXMEs.
+	  * gst/filter/gstlpwsinc.c:
+	  Add FIXMEs and a new TODO.
+
+2007-08-09 18:08:05 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/gstlpwsinc.*: Add double support, replace "this" with "self" as the former is a C++ keyword.
+	  Original commit message from CVS:
+	  * gst/filter/gstlpwsinc.c: (gst_lpwsinc_dispose),
+	  (gst_lpwsinc_class_init), (gst_lpwsinc_init), (process_32),
+	  (process_64), (lpwsinc_build_kernel), (lpwsinc_setup),
+	  (lpwsinc_get_unit_size), (lpwsinc_transform),
+	  (lpwsinc_set_property), (lpwsinc_get_property):
+	  * gst/filter/gstlpwsinc.h:
+	  Add double support, replace "this" with "self" as the former
+	  is a C++ keyword.
+	  Implement the frequency property in Hz instead of fraction
+	  of sampling frequency.
+	  Remove some unecessary FIXMEs and add some TODOs, add some
+	  required locking and refactor the kernel generation into a
+	  separate function that is also called when the properties
+	  change now.
+	  And use BaseTransform::transform instead of transform_ip
+	  as the convolution is done out of place anyway. Should
+	  be done in place later.
+
+2007-08-09 10:54:05 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  po/: Updated translations.
+	  Original commit message from CVS:
+	  * po/hu.po:
+	  * po/uk.po:
+	  * po/vi.po:
+	  Updated translations.
+
+2007-08-08 20:47:33 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/filter/: Use GstAudioFilter as base class and don't leak the memory of the filter kernel and residue.
+	  Original commit message from CVS:
+	  * gst/filter/Makefile.am:
+	  * gst/filter/gstbpwsinc.c: (gst_bpwsinc_dispose),
+	  (gst_bpwsinc_base_init), (gst_bpwsinc_class_init),
+	  (gst_bpwsinc_init), (bpwsinc_setup):
+	  * gst/filter/gstbpwsinc.h:
+	  * gst/filter/gstlpwsinc.c: (gst_lpwsinc_dispose),
+	  (gst_lpwsinc_base_init), (gst_lpwsinc_class_init),
+	  (gst_lpwsinc_init), (lpwsinc_setup):
+	  * gst/filter/gstlpwsinc.h:
+	  Use GstAudioFilter as base class and don't leak the memory
+	  of the filter kernel and residue.
+
+2007-08-08 17:47:05 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/videobox/gstvideobox.c: Render right border in the correct location.
+	  Original commit message from CVS:
+	  * gst/videobox/gstvideobox.c: (gst_video_box_ayuv_i420):
+	  Render right border in the correct location.
+
+2007-08-08 10:54:50 +0000  Olivier Crete <tester@tester.ca>
+
+	  gst/rtp/: Make mode property a string. Fixes #464475.
+	  Original commit message from CVS:
+	  Patch by: Olivier Crete <tester at tester dot ca>
+	  * gst/rtp/gstrtpilbcdepay.c: (gst_rtp_ilbc_depay_setcaps):
+	  * gst/rtp/gstrtpilbcpay.c: (gst_rtpilbcpay_setcaps):
+	  Make mode property a string. Fixes #464475.
+
+2007-08-05 14:58:20 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/flac/gstflacenc.c: Widen caps to match decoder a bit and add more FIXMEs.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacenc.c:
+	  Widen caps to match decoder a bit and add more FIXMEs.
+
+2007-08-05 14:53:36 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  gst/avi/gstavimux.c: Fix ODML index tag numbering. Fixes #463624.
+	  Original commit message from CVS:
+	  patch by: Mark Nauwelaerts <manauw@skynet.be>
+	  * gst/avi/gstavimux.c:
+	  Fix ODML index tag numbering. Fixes #463624.
+
+2007-08-03 16:08:56 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Fix default clock-rate for realmedia.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (get_default_rate_for_pt),
+	  (gst_rtspsrc_parse_rtpmap), (gst_rtspsrc_media_to_caps),
+	  (gst_rtspsrc_stream_configure_tcp),
+	  (gst_rtspsrc_stream_configure_udp_sink):
+	  Fix default clock-rate for realmedia.
+	  Fix parsing of transport.
+	  Don't try to link NULL pads.
+
+2007-07-30 17:17:04 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  po/POTFILES.skip: Add POTFILES.skip with list of source files that aren't disted at the moment but contain translatab...
+	  Original commit message from CVS:
+	  * po/POTFILES.skip:
+	  Add POTFILES.skip with list of source files that aren't disted at the
+	  moment but contain translatable strings. Should hopefully pacify
+	  broken tools and make it clearer that these files are left out
+	  intentionally (#461600).
+
+2007-07-30 12:41:58 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: If the buffer was entirely clipped ... don't try sending it :)
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_state_movie):
+	  If the buffer was entirely clipped ... don't try sending it :)
+
+2007-07-27 16:56:45 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: If we don't hav a session manager, set the caps on outgoing buffers ourselves.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_activate_streams),
+	  (gst_rtspsrc_loop_interleaved), (gst_rtspsrc_parse_methods),
+	  (gst_rtspsrc_create_transports_string),
+	  (gst_rtspsrc_prepare_transports):
+	  If we don't hav a session manager, set the caps on outgoing buffers
+	  ourselves.
+	  Force PAUSE/PLAY methods for now until the extensions can overwrite.
+	  Append final bit of the transport string even when it does not contain a
+	  placeholder.
+
+2007-07-27 11:21:20 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/: Clean up the interface list.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspext.c: (gst_rtsp_ext_list_free),
+	  (gst_rtsp_ext_list_connect):
+	  * gst/rtsp/gstrtspext.h:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init),
+	  (gst_rtspsrc_finalize), (gst_rtspsrc_send_cb):
+	  Clean up the interface list.
+	  Allow connecting to interface signals for the extensions.
+	  Remove old extension code.
+	  Free list on cleanup.
+	  Allow extensions to send additional RTSP messages.
+
+2007-07-27 10:38:34 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/gconf/gconf.c: Handle a NULL gconf key gracefully by rendering the default element.
+	  Original commit message from CVS:
+	  * ext/gconf/gconf.c: (gst_gconf_render_bin_with_default):
+	  Handle a NULL gconf key gracefully by rendering the default element.
+
+2007-07-27 10:11:18 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspext.h: Fix include path for extension interface.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspext.h:
+	  Fix include path for extension interface.
+
+2007-07-26 19:45:30 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/audioamplify.h: Also remove a now unecessary variable here.
+	  Original commit message from CVS:
+	  * gst/audiofx/audioamplify.h:
+	  Also remove a now unecessary variable here.
+
+2007-07-26 19:41:07 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/: Don't save format information ourselves, this is already saved in
+	  Original commit message from CVS:
+	  * gst/audiofx/audioamplify.c: (gst_audio_amplify_init),
+	  (gst_audio_amplify_setup), (gst_audio_amplify_transform_ip):
+	  * gst/audiofx/audiodynamic.c:
+	  (gst_audio_dynamic_set_process_function), (gst_audio_dynamic_init),
+	  (gst_audio_dynamic_setup), (gst_audio_dynamic_transform_ip):
+	  * gst/audiofx/audiodynamic.h:
+	  * gst/audiofx/audioinvert.c: (gst_audio_invert_init),
+	  (gst_audio_invert_setup), (gst_audio_invert_transform_ip):
+	  * gst/audiofx/audioinvert.h:
+	  Don't save format information ourselves, this is already saved in
+	  GstAudioFilter.
+
+2007-07-26 15:48:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/: Use rank to filter out extensions.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspext.c: (gst_rtsp_ext_list_filter),
+	  (gst_rtsp_ext_list_stream_select):
+	  * gst/rtsp/gstrtspext.h:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_setup_streams):
+	  Use rank to filter out extensions.
+	  Add url to stream_select interface call.
+
+2007-07-25 18:50:08 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/: Use shiny new RTSP and SDP library.
+	  Original commit message from CVS:
+	  * gst/rtsp/Makefile.am:
+	  * gst/rtsp/base64.c:
+	  * gst/rtsp/base64.h:
+	  * gst/rtsp/gstrtspext.c: (gst_rtsp_ext_list_filter),
+	  (gst_rtsp_ext_list_init), (gst_rtsp_ext_list_get),
+	  (gst_rtsp_ext_list_detect_server), (gst_rtsp_ext_list_before_send),
+	  (gst_rtsp_ext_list_after_send), (gst_rtsp_ext_list_parse_sdp),
+	  (gst_rtsp_ext_list_setup_media),
+	  (gst_rtsp_ext_list_configure_stream),
+	  (gst_rtsp_ext_list_get_transports),
+	  (gst_rtsp_ext_list_stream_select):
+	  * gst/rtsp/gstrtspext.h:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtsp_lower_trans_get_type),
+	  (gst_rtspsrc_class_init), (gst_rtspsrc_init),
+	  (gst_rtspsrc_finalize), (gst_rtspsrc_create_stream),
+	  (gst_rtspsrc_parse_rtpmap), (gst_rtspsrc_media_to_caps),
+	  (gst_rtspsrc_flush), (gst_rtspsrc_do_seek),
+	  (gst_rtspsrc_sink_chain), (gst_rtspsrc_stream_configure_manager),
+	  (gst_rtspsrc_stream_configure_tcp),
+	  (gst_rtspsrc_stream_configure_mcast),
+	  (gst_rtspsrc_stream_configure_udp),
+	  (gst_rtspsrc_stream_configure_udp_sink),
+	  (gst_rtspsrc_stream_configure_transport),
+	  (gst_rtspsrc_handle_request), (gst_rtspsrc_send_keep_alive),
+	  (gst_rtspsrc_loop_interleaved), (gst_rtspsrc_loop_udp),
+	  (gst_rtspsrc_loop_send_cmd), (gst_rtsp_auth_method_to_string),
+	  (gst_rtspsrc_parse_auth_hdr), (gst_rtspsrc_setup_auth),
+	  (gst_rtspsrc_try_send), (gst_rtspsrc_send),
+	  (gst_rtspsrc_parse_methods),
+	  (gst_rtspsrc_create_transports_string),
+	  (gst_rtspsrc_prepare_transports), (gst_rtspsrc_setup_streams),
+	  (gst_rtspsrc_parse_range), (gst_rtspsrc_open), (gst_rtspsrc_close),
+	  (gst_rtspsrc_play), (gst_rtspsrc_pause),
+	  (gst_rtspsrc_change_state), (gst_rtspsrc_uri_set_uri):
+	  * gst/rtsp/gstrtspsrc.h:
+	  * gst/rtsp/rtsp.h:
+	  * gst/rtsp/rtspconnection.c:
+	  * gst/rtsp/rtspconnection.h:
+	  * gst/rtsp/rtspdefs.c:
+	  * gst/rtsp/rtspdefs.h:
+	  * gst/rtsp/rtspext.h:
+	  * gst/rtsp/rtspextwms.c:
+	  * gst/rtsp/rtspextwms.h:
+	  * gst/rtsp/rtspmessage.c:
+	  * gst/rtsp/rtspmessage.h:
+	  * gst/rtsp/rtsprange.c:
+	  * gst/rtsp/rtsprange.h:
+	  * gst/rtsp/rtsptransport.c:
+	  * gst/rtsp/rtsptransport.h:
+	  * gst/rtsp/rtspurl.c:
+	  * gst/rtsp/rtspurl.h:
+	  * gst/rtsp/sdp.h:
+	  * gst/rtsp/sdpmessage.c:
+	  * gst/rtsp/sdpmessage.h:
+	  * gst/rtsp/test.c:
+	  Use shiny new RTSP and SDP library.
+	  Implement RTSP extensions using the new interface.
+	  Remove a lot of old code.
+
+2007-07-24 14:31:56 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Add codec mapping for '2vuy' (Raw YUV produced by FCP) and 'divx'.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_video_caps):
+	  Add codec mapping for '2vuy' (Raw YUV produced by FCP) and 'divx'.
+
+2007-07-24 05:07:59 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackdec.c: Don't unref the outgoing buffer twice when dropping it because it's outside of the segment.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_chain):
+	  Don't unref the outgoing buffer twice when dropping it because it's
+	  outside of the segment.
+
+2007-07-24 04:57:20 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Use the new buffer clipping function from gstaudio here and require gst-plugins-base CVS.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_reset),
+	  (gst_wavpack_dec_chain), (gst_wavpack_dec_sink_event):
+	  Use the new buffer clipping function from gstaudio here and
+	  require gst-plugins-base CVS.
+	  * tests/check/elements/wavpackdec.c: (GST_START_TEST):
+	  For framed Wavpack buffers we require a valid timestamp.
+
+2007-07-23 18:03:54 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Clip raw audio and video when we can, keep track of current output segment.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_activate_segment),
+	  (gst_qtdemux_clip_buffer), (gst_qtdemux_loop_state_movie),
+	  (qtdemux_parse_trak), (qtdemux_video_caps), (qtdemux_audio_caps):
+	  Clip raw audio and video when we can, keep track of current output
+	  segment.
+	  Don't leak buffers and events when there is no output pad.
+	  Improve debugging here and there.
+
+2007-07-23 09:02:07 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  configure.ac: Sync liboil check with plugins-base.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Sync liboil check with plugins-base.
+
+2007-07-20 11:37:37 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/equalizer/: Better algorith for the center frequencies. Subtract band filters from input for negative gains. Rewo...
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer.c:
+	  (gst_iir_equalizer_band_set_property),
+	  (gst_iir_equalizer_child_proxy_get_child_by_index),
+	  (gst_iir_equalizer_child_proxy_get_children_count),
+	  (gst_iir_equalizer_child_proxy_interface_init),
+	  (gst_iir_equalizer_class_init), (arg_to_scale), (setup_filter),
+	  (gst_iir_equalizer_compute_frequencies):
+	  * gst/equalizer/gstiirequalizer10bands.c:
+	  (gst_iir_equalizer_10bands_class_init):
+	  * gst/equalizer/gstiirequalizer3bands.c:
+	  (gst_iir_equalizer_3bands_class_init):
+	  * gst/equalizer/gstiirequalizernbands.c:
+	  Better algorith for the center frequencies. Subtract band filters from
+	  input for negative gains. Rework the gain mapping.
+
+2007-07-20 07:41:58 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/annodex/Makefile.am: Fix CFLAGS/LIBS.
+	  Original commit message from CVS:
+	  * ext/annodex/Makefile.am:
+	  Fix CFLAGS/LIBS.
+	  * ext/cdio/gstcdiocddasrc.c:
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_task):
+	  Include stdlib
+	  * ext/cairo/Makefile.am:
+	  * gst/videofilter/Makefile.am:
+	  * tests/examples/level/Makefile.am:
+	  Use $(LIBM) instead of -lm
+
+2007-07-18 11:55:13 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/v4l2/gstv4l2src.c: Add another example pipeline.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c:
+	  Add another example pipeline.
+
+2007-07-18 11:42:33 +0000  Alexander Eichner <alexeichi@yahoo.de>
+
+	  sys/v4l2/gstv4l2src.c: Use define here.
+	  Original commit message from CVS:
+	  Patch by: Alexander Eichner <alexeichi@yahoo.de>
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_init):
+	  Use define here.
+	  * sys/v4l2/gstv4l2tuner.c:
+	  (gst_v4l2_tuner_set_frequency_and_notify):
+	  Don't touch the property - its still disabled.
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_probe_caps_for_format),
+	  (gst_v4l2src_grab_frame), (gst_v4l2src_get_size_limits):
+	  * sys/v4l2/v4l2src_calls.h:
+	  Improve fallback format negotionation. Fixes #451388
+
+2007-07-18 10:33:39 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/check/elements/videocrop.c: Fix the test.
+	  Original commit message from CVS:
+	  * tests/check/elements/videocrop.c: (GST_START_TEST):
+	  Fix the test.
+
+2007-07-18 09:21:23 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  More docs. More logs in pngdec.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/inspect/plugin-jpeg.xml:
+	  * docs/plugins/inspect/plugin-png.xml:
+	  * ext/jpeg/gstjpegdec.c:
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_task),
+	  (gst_pngdec_sink_setcaps):
+	  More docs. More logs in pngdec.
+
+2007-07-18 07:51:11 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/multifile/gstmultifilesrc.c: Add example to the docs. Fix buffer-offset-end and add some debug.
+	  Original commit message from CVS:
+	  * gst/multifile/gstmultifilesrc.c: (gst_multi_file_src_create):
+	  Add example to the docs. Fix buffer-offset-end and add some debug.
+
+2007-07-18 07:35:32 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Add stdlib include (free, atoi, exit).
+	  Original commit message from CVS:
+	  * examples/app/appsrc_ex.c:
+	  * examples/switch/switcher.c:
+	  * ext/neon/gstneonhttpsrc.c:
+	  * ext/timidity/gstwildmidi.c:
+	  * ext/x264/gstx264enc.c:
+	  * gst/mve/mveaudioenc.c: (mve_compress_audio):
+	  * gst/rtpmanager/gstrtpclient.c:
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  * gst/spectrum/demo-audiotest.c:
+	  * gst/spectrum/demo-osssrc.c:
+	  * sys/dvb/gstdvbsrc.c:
+	  Add stdlib include (free, atoi, exit).
+
+2007-07-17 11:35:29 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/v4l2/gstv4l2src.c: Initialize num_buffers with minimum value.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_init):
+	  Initialize num_buffers with minimum value.
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list),
+	  (gst_v4l2src_probe_caps_for_format), (gst_v4l2src_grab_frame):
+	  Handle frame-size query failure gracefully.
+
+2007-07-16 12:11:36 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Fix parsing of esds atoms inside mp4a atoms so that we can set correct codec_info for AAC audi...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_node):
+	  Fix parsing of esds atoms inside mp4a atoms so that we can set correct
+	  codec_info for AAC audio. Fixes #457097 along with a whole other bunch
+	  of qt/aac files.
+
+2007-07-16 09:16:03 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackdec.c: Fix buffer clipping to correctly clip to the segment stop.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c:
+	  (gst_wavpack_dec_clip_outgoing_buffer):
+	  Fix buffer clipping to correctly clip to the segment stop.
+
+2007-07-13 16:31:27 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Remove bogus check for libcheck, since we check for gstreamer-check and it pulls in the required info from there, and...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * tests/Makefile.am:
+	  Remove bogus check for libcheck, since we check for
+	  gstreamer-check and it pulls in the required info from there,
+	  and we weren't actually _using_ the information for libcheck
+	  ourselves anyway.
+
+2007-07-12 11:21:01 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  configure.ac: Use pkg-config to locate check.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Use pkg-config to locate check.
+
+2007-07-11 23:43:25 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/: Fix build against core CVS.
+	  Original commit message from CVS:
+	  * gst/interleave/deinterleave.c: (gst_deinterleave_process):
+	  * gst/vmnc/vmncdec.c: (vmnc_make_buffer):
+	  Fix build against core CVS.
+
+2007-07-11 22:31:06 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Fix build against core CVS.
+	  Original commit message from CVS:
+	  * ext/cairo/gsttimeoverlay.c: (gst_cairo_time_overlay_transform):
+	  * ext/jpeg/gstjpegenc.c: (gst_jpegenc_chain):
+	  * ext/libpng/gstpngenc.c: (gst_pngenc_chain):
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_chain):
+	  * gst/debug/gstnavigationtest.c: (gst_navigationtest_transform):
+	  * gst/effectv/gstaging.c: (gst_agingtv_transform):
+	  * gst/effectv/gstdice.c: (gst_dicetv_transform):
+	  * gst/effectv/gstedge.c: (gst_edgetv_transform):
+	  * gst/effectv/gstquark.c: (gst_quarktv_transform):
+	  * gst/effectv/gstrev.c: (gst_revtv_transform):
+	  * gst/effectv/gstshagadelic.c: (gst_shagadelictv_transform):
+	  * gst/effectv/gstvertigo.c: (gst_vertigotv_transform):
+	  * gst/effectv/gstwarp.c: (gst_warptv_transform):
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_add_wvpk_header),
+	  (gst_matroska_demux_check_subtitle_buffer),
+	  (gst_matroska_decode_buffer):
+	  * gst/videofilter/gstvideoflip.c: (gst_video_flip_transform):
+	  Fix build against core CVS.
+
+2007-07-10 10:16:38 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/id3demux/gstid3demux.c: Don't return GST_FLOW_ERROR when pushing an event returns FALSE. We don't have enough gra...
+	  Original commit message from CVS:
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_chain):
+	  Don't return GST_FLOW_ERROR when pushing an event returns FALSE. We
+	  don't have enough granularity to convert that boolean into a
+	  GstFlowReturn.
+
+2007-07-06 15:00:47 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/law/: Fix capsnego bogosity in *law decoders.
+	  Original commit message from CVS:
+	  * gst/law/alaw-decode.c: (alawdec_sink_setcaps),
+	  (gst_alawdec_class_init), (gst_alawdec_init), (gst_alawdec_chain),
+	  (gst_alawdec_change_state):
+	  * gst/law/alaw-decode.h:
+	  * gst/law/mulaw-decode.c: (mulawdec_sink_setcaps),
+	  (gst_mulawdec_class_init), (gst_mulawdec_init),
+	  (gst_mulawdec_chain), (gst_mulawdec_change_state):
+	  * gst/law/mulaw-decode.h:
+	  Fix capsnego bogosity in *law decoders.
+
+2007-07-06 14:35:59 +0000  Michael Smith <msmith@xiph.org>
+
+	  ext/jpeg/gstsmokeenc.*: Remove stupidity in get/set caps functions.
+	  Original commit message from CVS:
+	  * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_init),
+	  (gst_smokeenc_setcaps), (gst_smokeenc_chain),
+	  (gst_smokeenc_change_state):
+	  * ext/jpeg/gstsmokeenc.h:
+	  Remove stupidity in get/set caps functions.
+	  Fix some refcounting problems.
+
+2007-07-06 11:42:53 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/libpng/gstpngdec.c: Remove endianness-flipping hack that seems to have been required only because of a bug in ffm...
+	  Original commit message from CVS:
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_caps_create_and_set):
+	  Remove endianness-flipping hack that seems to have been required
+	  only because of a bug in ffmpegcolorspace.
+	  Partially Fixes: #451908
+
+2007-07-05 08:44:11 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/Makefile.am: Simplify --extra-dir as gtkdoc scans recursively.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  Simplify --extra-dir as gtkdoc scans recursively.
+
+2007-07-03 09:59:46 +0000  Tommi Myöhänen <ext-tommi.myohanen@nokia.com>
+
+	  gst/rtp/gstrtpilbcpay.c: Set the encoding-name in the rtp caps to all uppercase, as required by the caps spec.
+	  Original commit message from CVS:
+	  Patch by: Tommi Myöhänen  <ext-tommi dot myohanen at nokia dot com>
+	  * gst/rtp/gstrtpilbcpay.c: (gst_rtpilbcpay_setcaps):
+	  Set the encoding-name in the rtp caps to all uppercase, as required by
+	  the caps spec.
+	  Some small cleanups in the error paths. Fixes #453037.
+
+2007-07-03 08:01:18 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/multifile/: Add .h files to be able to add it to the docs.
+	  Original commit message from CVS:
+	  * gst/multifile/Makefile.am:
+	  * gst/multifile/gstmultifile.c:
+	  * gst/multifile/gstmultifilesink.c:
+	  * gst/multifile/gstmultifilesink.h:
+	  * gst/multifile/gstmultifilesrc.c:
+	  * gst/multifile/gstmultifilesrc.h:
+	  Add .h files to be able to add it to the docs.
+
+2007-07-03 07:16:26 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/replaygain/gstrgvolume.h: Fix GObject macros.
+	  Original commit message from CVS:
+	  * gst/replaygain/gstrgvolume.h:
+	  Fix GObject macros.
+
+2007-06-28 19:00:43 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackparse.*: Use a GSList for the GArray that is used like a list anyway.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackparse.c:
+	  (gst_wavpack_parse_index_get_last_entry),
+	  (gst_wavpack_parse_index_get_entry_from_sample),
+	  (gst_wavpack_parse_index_append_entry), (gst_wavpack_parse_reset),
+	  (gst_wavpack_parse_scan_to_find_sample):
+	  * ext/wavpack/gstwavpackparse.h:
+	  Use a GSList for the GArray that is used like a list anyway.
+
+2007-06-28 13:25:05 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/gdk_pixbuf/gstgdkpixbuf.c: Add state change function where we set 0/1 as default framerate in case our setcaps fu...
+	  Original commit message from CVS:
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_sink_setcaps),
+	  (gst_gdk_pixbuf_class_init), (gst_gdk_pixbuf_flush),
+	  (gst_gdk_pixbuf_sink_event), (gst_gdk_pixbuf_change_state):
+	  Add state change function where we set 0/1 as default framerate in
+	  case our setcaps function isn't called, like it might not in a
+	  filesrc ! gdkpixbufdec scenario. Fixes assertion triggered by
+	  gdkpixbufdec trying to create caps with a 0/0 framerate.
+	  Also post an error message on the bus if gst_pad_push() fails when
+	  called from our sink event handler (+1 for flow returns for event
+	  functions in 0.11) instead of failing silently.
+
+2007-06-27 11:36:24 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Cast stack args to the proper types. Fixes #451249.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_configure_caps):
+	  Cast stack args to the proper types. Fixes #451249.
+
+2007-06-27 11:04:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: For container formats we only need to activate one of the streams so that we correctly signal ...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_create_stream),
+	  (new_session_pad), (gst_rtspsrc_setup_streams):
+	  * gst/rtsp/gstrtspsrc.h:
+	  For container formats we only need to activate one of the streams so
+	  that we correctly signal no-more-pads. Fixes #451015.
+
+2007-06-25 12:46:08 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/: Update docs with caps info.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/inspect/plugin-aasink.xml:
+	  * docs/plugins/inspect/plugin-alaw.xml:
+	  * docs/plugins/inspect/plugin-alpha.xml:
+	  * docs/plugins/inspect/plugin-alphacolor.xml:
+	  * docs/plugins/inspect/plugin-annodex.xml:
+	  * docs/plugins/inspect/plugin-apetag.xml:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  * docs/plugins/inspect/plugin-auparse.xml:
+	  * docs/plugins/inspect/plugin-autodetect.xml:
+	  * docs/plugins/inspect/plugin-avi.xml:
+	  * docs/plugins/inspect/plugin-cacasink.xml:
+	  * docs/plugins/inspect/plugin-cairo.xml:
+	  * docs/plugins/inspect/plugin-cdio.xml:
+	  * docs/plugins/inspect/plugin-cutter.xml:
+	  * docs/plugins/inspect/plugin-debug.xml:
+	  * docs/plugins/inspect/plugin-efence.xml:
+	  * docs/plugins/inspect/plugin-effectv.xml:
+	  * docs/plugins/inspect/plugin-esdsink.xml:
+	  * docs/plugins/inspect/plugin-flac.xml:
+	  * docs/plugins/inspect/plugin-flxdec.xml:
+	  * docs/plugins/inspect/plugin-gconfelements.xml:
+	  * docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	  * docs/plugins/inspect/plugin-goom.xml:
+	  * docs/plugins/inspect/plugin-halelements.xml:
+	  * docs/plugins/inspect/plugin-icydemux.xml:
+	  * docs/plugins/inspect/plugin-id3demux.xml:
+	  * docs/plugins/inspect/plugin-jpeg.xml:
+	  * docs/plugins/inspect/plugin-ladspa.xml:
+	  * docs/plugins/inspect/plugin-level.xml:
+	  * docs/plugins/inspect/plugin-matroska.xml:
+	  * docs/plugins/inspect/plugin-mulaw.xml:
+	  * docs/plugins/inspect/plugin-multipart.xml:
+	  * docs/plugins/inspect/plugin-navigationtest.xml:
+	  * docs/plugins/inspect/plugin-ossaudio.xml:
+	  * docs/plugins/inspect/plugin-png.xml:
+	  * docs/plugins/inspect/plugin-quicktime.xml:
+	  * docs/plugins/inspect/plugin-rtp.xml:
+	  * docs/plugins/inspect/plugin-rtsp.xml:
+	  * docs/plugins/inspect/plugin-smpte.xml:
+	  * docs/plugins/inspect/plugin-speex.xml:
+	  * docs/plugins/inspect/plugin-taglib.xml:
+	  * docs/plugins/inspect/plugin-udp.xml:
+	  * docs/plugins/inspect/plugin-videobalance.xml:
+	  * docs/plugins/inspect/plugin-videobox.xml:
+	  * docs/plugins/inspect/plugin-videocrop.xml:
+	  * docs/plugins/inspect/plugin-videoflip.xml:
+	  * docs/plugins/inspect/plugin-videomixer.xml:
+	  * docs/plugins/inspect/plugin-wavenc.xml:
+	  * docs/plugins/inspect/plugin-wavparse.xml:
+	  * docs/plugins/inspect/plugin-ximagesrc.xml:
+	  Update docs with caps info.
+
+2007-06-25 12:13:09 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  po/POTFILES.in: Add more files with translatable strings (#450878).
+	  Original commit message from CVS:
+	  * po/POTFILES.in:
+	  Add more files with translatable strings (#450878).
+
+2007-06-22 20:23:18 +0000  Jens Granseuer <jensgr@gmx.net>
+
+	  gst/: Build fixes for gcc-2.9x (no mid-block variable declarations etc.).
+	  Original commit message from CVS:
+	  Patch by: Jens Granseuer  <jensgr at gmx net>
+	  * gst/equalizer/gstiirequalizer.c:
+	  * gst/equalizer/gstiirequalizer10bands.c:
+	  * gst/equalizer/gstiirequalizer3bands.c:
+	  * gst/equalizer/gstiirequalizernbands.c:
+	  * gst/rtpmanager/async_jitter_queue.c:
+	  (async_jitter_queue_push_sorted):
+	  * gst/rtpmanager/gstrtpjitterbuffer.c:
+	  (gst_rtp_jitter_buffer_chain):
+	  * gst/switch/gstswitch.c: (gst_switch_chain):
+	  Build fixes for gcc-2.9x (no mid-block variable declarations etc.).
+	  Fixes #450185.
+
+2007-06-22 14:26:36 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  MAINTAINERS: Updating all the maintainers files
+	  Original commit message from CVS:
+	  * MAINTAINERS:
+	  Updating all the maintainers files
+
+2007-06-22 10:12:15 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  Fix memory leaks.
+	  Original commit message from CVS:
+	  * ext/flac/gstflactag.c: (gst_flac_tag_init):
+	  * gst/interleave/deinterleave.c: (deinterleave_init),
+	  (deinterleave_sink_link):
+	  * gst/interleave/interleave.c: (interleave_init):
+	  * gst/median/gstmedian.c: (gst_median_init):
+	  * gst/oldcore/gstmultifilesrc.c: (gst_multifilesrc_init):
+	  Fix memory leaks.
+	  * tests/check/elements/id3demux.c: (pad_added_cb):
+	  Remove unused variable.
+
+2007-06-21 10:48:10 +0000  Damien Carbery <damien.carbery@sun.com>
+
+	  ext/gconf/gconf.h: Make the prototype of gst_gconf_get_key_for_sink_profile match the implementation.
+	  Original commit message from CVS:
+	  * ext/gconf/gconf.h:
+	  Make the prototype of gst_gconf_get_key_for_sink_profile
+	  match the implementation.
+	  Patch by: Damien Carbery <damien dot carbery at sun dot com>
+	  Fixes: #449747
+
+2007-06-20 12:56:12 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/rtp/gstrtpdepay.c: Fix description - rtpdepay is not a payloader.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpdepay.c:
+	  Fix description - rtpdepay is not a payloader.
+
+2007-06-20 10:15:00 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/equalizer/gstiirequalizer.c: Document parameter mapping.
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer.c:
+	  Document parameter mapping.
+
+2007-06-20 08:56:17 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/gstspectrum.c: Fix leaking buffers.
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_event),
+	  (gst_spectrum_transform_ip):
+	  Fix leaking buffers.
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/spectrum.c: (setup_spectrum),
+	  (cleanup_spectrum), (GST_START_TEST), (spectrum_suite), (main):
+	  Add simple test for spectrum element.
+
+2007-06-20 08:26:21 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/qtdemux/: Add MJPG to the variants of motion jpeg.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_samples),
+	  (qtdemux_video_caps):
+	  * gst/qtdemux/qtdemux_fourcc.h:
+	  Add MJPG to the variants of motion jpeg.
+
+2007-06-19 16:40:40 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/check/: Add GST_OPTION_CFLAGS to CFLAGS when building unit tests, so the error flags are included and it errors...
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/audiopanorama.c: (GST_START_TEST):
+	  * tests/check/elements/videocrop.c: (GST_START_TEST):
+	  * tests/check/elements/videofilter.c:
+	  * tests/check/elements/wavpackdec.c: (GST_START_TEST):
+	  * tests/check/elements/wavpackparse.c: (GST_START_TEST):
+	  Add GST_OPTION_CFLAGS to CFLAGS when building unit tests, so the
+	  error flags are included and it errors out on compiler warnings
+	  for CVS builds; remove unused variables in various unit tests.
+
+2007-06-19 14:48:03 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/rtspconnection.c: Use threadsafe inet_ntop to convert an ip number to a string.
+	  Original commit message from CVS:
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_connect),
+	  (rtsp_connection_close), (rtsp_connection_free):
+	  Use threadsafe inet_ntop to convert an ip number to a string.
+	  Fixes #447961.
+	  Don't leak fd (and ip) when freeing a connection without first closing
+	  it.
+
+2007-06-19 14:11:49 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst/qtdemux/LEGAL:
+	  add 'LEGAL' file describing why this is in -good and under what circumstances it might need to move.
+	  Original commit message from CVS:
+	  add 'LEGAL' file describing why this is in -good and under what
+	  circumstances it might need to move.
+
+2007-06-19 10:41:49 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Back to CVS
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Back to CVS
+	  * gst-plugins-good.doap:
+	  Add 0.10.6 to the doap file.
+
+=== release 0.10.6 ===
+
+2007-06-19 10:24:55 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-audiofx.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cdio.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-quicktime.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videocrop.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavpack.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* win32/common/config.h:
+	  Release 0.10.6
+	  Original commit message from CVS:
+	  Release 0.10.6
+
+2007-06-18 17:53:20 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/ja.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	  Update .po files
+	  Original commit message from CVS:
+	  Update .po files
+
+2007-06-17 12:35:03 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/rtsp/rtspconnection.c: Revert previous commit again, since we are frozen (sorry).
+	  Original commit message from CVS:
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_connect),
+	  (rtsp_connection_free):
+	  Revert previous commit again, since we are frozen (sorry).
+
+2007-06-17 12:24:58 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtsp/rtspconnection.c: inet_ntoa() uses a static buffer internally, so we need to copy the returned string if we ...
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt <pkj at axis com>
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_connect),
+	  (rtsp_connection_free):
+	  inet_ntoa() uses a static buffer internally, so we need to copy the
+	  returned string if we want to store it for later (#447961).
+
+2007-06-15 09:13:55 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  win32/vs6/: Mark *.dsp & *.dsw as binary files and convert to DOS line endings, as they don't load into VS6 correctly...
+	  Original commit message from CVS:
+	  * win32/vs6/autogen.dsp:
+	  * win32/vs6/gst_plugins_good.dsw:
+	  * win32/vs6/libgstalaw.dsp:
+	  * win32/vs6/libgstalpha.dsp:
+	  * win32/vs6/libgstalphacolor.dsp:
+	  * win32/vs6/libgstapetag.dsp:
+	  * win32/vs6/libgstaudiofx.dsp:
+	  * win32/vs6/libgstauparse.dsp:
+	  * win32/vs6/libgstautodetect.dsp:
+	  * win32/vs6/libgstavi.dsp:
+	  * win32/vs6/libgstcutter.dsp:
+	  * win32/vs6/libgstdirectdraw.dsp:
+	  * win32/vs6/libgstdirectsound.dsp:
+	  * win32/vs6/libgsteffectv.dsp:
+	  * win32/vs6/libgstflx.dsp:
+	  * win32/vs6/libgstgoom.dsp:
+	  * win32/vs6/libgsticydemux.dsp:
+	  * win32/vs6/libgstid3demux.dsp:
+	  * win32/vs6/libgstinterleave.dsp:
+	  * win32/vs6/libgstjpeg.dsp:
+	  * win32/vs6/libgstlevel.dsp:
+	  * win32/vs6/libgstmatroska.dsp:
+	  * win32/vs6/libgstmedian.dsp:
+	  * win32/vs6/libgstmonoscope.dsp:
+	  * win32/vs6/libgstmulaw.dsp:
+	  * win32/vs6/libgstmultipart.dsp:
+	  * win32/vs6/libgstqtdemux.dsp:
+	  * win32/vs6/libgstrtp.dsp:
+	  * win32/vs6/libgstrtsp.dsp:
+	  * win32/vs6/libgstsmpte.dsp:
+	  * win32/vs6/libgstspeex.dsp:
+	  * win32/vs6/libgstudp.dsp:
+	  * win32/vs6/libgstvideobalance.dsp:
+	  * win32/vs6/libgstvideobox.dsp:
+	  * win32/vs6/libgstvideocrop.dsp:
+	  * win32/vs6/libgstvideoflip.dsp:
+	  * win32/vs6/libgstvideomixer.dsp:
+	  * win32/vs6/libgstwaveform.dsp:
+	  * win32/vs6/libgstwavenc.dsp:
+	  * win32/vs6/libgstwavparse.dsp:
+	  Mark *.dsp & *.dsw as binary files and convert to DOS line
+	  endings, as they don't load into VS6 correctly otherwise.
+
+2007-06-15 08:32:52 +0000  Vincent Torri <vtorri@univ-evry.fr>
+
+	  gst/rtsp/rtspconnection.c: Fix the MingW build.
+	  Original commit message from CVS:
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_create),
+	  (rtsp_connection_connect):
+	  Fix the MingW build.
+	  Patch By: Vincent Torri <vtorri at univ-evry dot fr>
+	  Fixes: #446981
+
+2007-06-14 14:03:41 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  tests/: Hush the buildbots up
+	  Original commit message from CVS:
+	  * tests/check/elements/.cvsignore:
+	  * tests/icles/.cvsignore:
+	  Hush the buildbots up
+
+2007-06-14 12:14:24 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Make sure to dist everything needed for win32 builds.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * sys/Makefile.am:
+	  * sys/directdraw/Makefile.am:
+	  * sys/directsound/Makefile.am:
+	  * sys/waveform/Makefile.am:
+	  Make sure to dist everything needed for win32 builds.
+
+2007-06-14 10:23:20 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: For AMR-NB streams, export the AMRSpecificBox as codec_data on the caps.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_trak):
+	  For AMR-NB streams, export the AMRSpecificBox as codec_data on the
+	  caps.
+	  Fixes #447458
+
+2007-06-13 17:11:24 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtph264depay.c: Make sure we allocate enough memory for the codec_data.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_setcaps):
+	  Make sure we allocate enough memory for the codec_data.
+	  Fixes #447210.
+
+2007-06-12 21:05:22 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  win32/MANIFEST: Add videocrop project file to the win32 manifest.
+	  Original commit message from CVS:
+	  * win32/MANIFEST:
+	  Add videocrop project file to the win32 manifest.
+	  * win32/vs6/gst_plugins_good.dsw:
+	  Add qtdemux,videocrop and waveform projects to the workspace.
+	  * win32/vs6/libgstqtdemux.dsp:
+	  Add zlib to the link list of qtdemux.
+	  * win32/vs6/libgstvideocrop.dsp:
+	  Add a project file for videocrop.
+
+2007-06-12 20:22:26 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  po/POTFILES.in: Add qtdemux for translation
+	  Original commit message from CVS:
+	  * po/POTFILES.in:
+	  Add qtdemux for translation
+
+2007-06-12 20:15:29 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Move videocrop and osxvideo from -bad.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/inspect/plugin-videocrop.xml:
+	  * gst-plugins-good.spec.in:
+	  * sys/Makefile.am:
+	  * tests/check/Makefile.am:
+	  * tests/icles/Makefile.am:
+	  * tests/icles/videocrop-test.c:
+	  Move videocrop and osxvideo from -bad.
+
+2007-06-12 19:35:08 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Move qtdemux from -bad.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/inspect/plugin-qtdemux.xml:
+	  * docs/plugins/inspect/plugin-quicktime.xml:
+	  * win32/MANIFEST:
+	  Move qtdemux from -bad.
+	  * gst-plugins-good.spec.in:
+	  Update spec file to reflect moving of qtdemux and wavpack
+
+2007-06-12 19:01:41 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	* win32/MANIFEST:
+	  Fix typo in the changelog and commit the manifest too
+	  Original commit message from CVS:
+	  Fix typo in the changelog and commit the manifest too
+
+2007-06-12 18:52:33 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  win32/MANIFEST
+	  Original commit message from CVS:
+	  * win32/MANIFEST
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/inspect/plugin-directdraw.xml:
+	  * docs/plugins/inspect/plugin-directsound.xml:
+	  * docs/plugins/inspect/plugin-waveform.xml:
+	  Move the waveform plugin from -bad too. Update the inspect xml
+	  files to mention Plugins Good instead of Plugins Bad.
+
+2007-06-12 13:33:56 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ChangeLog:
+	* sys/v4l2/v4l2src_calls.c:
+	  Return a copy of the pool buffer if all mmap buffers have been dequeued.
+	  Original commit message from CVS:
+	  (gst_v4l2src_grab_frame): Return a copy of the pool buffer if all
+	  mmap buffers have been dequeued.
+
+2007-06-12 11:23:01 +0000  Andy Wingo <wingo@pobox.com>
+
+	  sys/v4l2/v4l2src_calls.c (gst_v4l2_buffer_finalize) (gst_v4l2_buffer_class_init, gst_v4l2_buffer_get_type)
+	  Original commit message from CVS:
+	  2007-06-12  Andy Wingo  <wingo@pobox.com>
+	  * sys/v4l2/v4l2src_calls.c (gst_v4l2_buffer_finalize)
+	  (gst_v4l2_buffer_class_init, gst_v4l2_buffer_get_type)
+	  (gst_v4l2_buffer_new): Behave more like ximagesink's buffers, with
+	  finalization and resuscitation. No longer public.
+	  (gst_v4l2_buffer_pool_finalize, gst_v4l2_buffer_pool_init)
+	  (gst_v4l2_buffer_pool_class_init, gst_v4l2_buffer_pool_get_type)
+	  (gst_v4l2_buffer_pool_new, gst_v4l2_buffer_pool_activate)
+	  (gst_v4l2_buffer_pool_destroy): Make the pool follow common
+	  miniobject semantics, and be threadsafe.
+	  (gst_v4l2src_queue_frame): Remove this function, as we just call
+	  the ioctls directly in the two places where we queue buffers.
+	  (gst_v4l2src_grab_frame): Return a flowreturn and fill the buffer
+	  directly.
+	  (gst_v4l2src_capture_init): Use the new buffer_pool_new function
+	  to allocate the pool, which also preallocates the GstBuffers.
+	  (gst_v4l2src_capture_start): Call buffer_pool_activate instead of
+	  queueing the frames directly.
+	  * sys/v4l2/gstv4l2src.h (struct _GstV4l2BufferPool): Make this a
+	  real MiniObject instead of rolling our own refcounting and
+	  finalizing. Give it a lock.
+	  (struct _GstV4l2Buffer): Remove one intermediary object, having
+	  the buffers hold the struct v4l2_buffer directly.
+	  * sys/v4l2/gstv4l2src.c (gst_v4l2src_set_caps): Pass the caps to
+	  capture_init so that it can set them on the buffers that it will
+	  create.
+	  (gst_v4l2src_get_read): For better or for worse, include the
+	  timestamping and offsetting code here; really we should be using
+	  bufferalloc though.
+	  (gst_v4l2src_get_mmap): Just make grab_frame return one of our
+	  preallocated, mmap'd buffers.
+
+2007-06-11 11:41:56 +0000  daniel fischer <dan@f3c.com>
+
+	  sys/ximage/gstximagesrc.c: Actually use the display_name property so that we can dump any available X display. Fixes ...
+	  Original commit message from CVS:
+	  Patch by: daniel fischer <dan at f3c dot com>
+	  * sys/ximage/gstximagesrc.c: (gst_ximage_src_start),
+	  (gst_ximage_src_get_caps):
+	  Actually use the display_name property so that we can dump any
+	  available X display. Fixes #445905.
+
+2007-06-11 10:21:13 +0000  Tommi Myöhänen <ext-tommi.myohanen@nokia.com>
+
+	  gst/rtp/: Add missing rate fields to caps. Fixes #441118.
+	  Original commit message from CVS:
+	  Patch by: Tommi Myöhänen  <ext-tommi dot myohanen at nokia dot com>
+	  * gst/rtp/gstrtppcmadepay.c: (gst_rtp_pcma_depay_setcaps):
+	  * gst/rtp/gstrtppcmudepay.c: (gst_rtp_pcmu_depay_setcaps):
+	  Add missing rate fields to caps. Fixes #441118.
+
+2007-06-10 21:14:11 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  win32/: Add DirectSound and DirectDraw sinks project files to workspace and solution files.
+	  Original commit message from CVS:
+	  * win32/vs6/gst_plugins_good.dsw:
+	  * win32/vs8/gst-plugins-good.sln:
+	  Add DirectSound and DirectDraw sinks project files to
+	  workspace and solution files.
+
+2007-06-10 10:53:26 +0000  Josh Coalson <xflac@yahoo.com>
+
+	  Add support for flac >= 1.1.3 which changed the API. Fixes bug #385887.
+	  Original commit message from CVS:
+	  Patch by: Josh Coalson <xflac at yahoo dot com>,
+	  updated by Alexis Ballier <aballier at gentoo dot org>:
+	  * configure.ac:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_reset_decoders),
+	  (gst_flac_dec_setup_seekable_decoder),
+	  (gst_flac_dec_setup_stream_decoder), (gst_flac_dec_seek),
+	  (gst_flac_dec_tell), (gst_flac_dec_length), (gst_flac_dec_eof),
+	  (gst_flac_dec_read_seekable), (gst_flac_dec_read_stream):
+	  * ext/flac/gstflacdec.h:
+	  * ext/flac/gstflacenc.c: (gst_flac_enc_init),
+	  (gst_flac_enc_finalize), (gst_flac_enc_set_metadata),
+	  (gst_flac_enc_sink_setcaps), (gst_flac_enc_update_quality),
+	  (gst_flac_enc_seek_callback), (gst_flac_enc_write_callback),
+	  (gst_flac_enc_tell_callback), (gst_flac_enc_sink_event),
+	  (gst_flac_enc_chain), (gst_flac_enc_set_property),
+	  (gst_flac_enc_get_property), (gst_flac_enc_change_state):
+	  * ext/flac/gstflacenc.h:
+	  Add support for flac >= 1.1.3 which changed the API. Fixes bug #385887.
+
+2007-06-09 15:41:52 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackenc.c: Remove workaround for bug #421543. This is fixed in core 0.10.13 and not necessary anymo...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_sink_set_caps):
+	  Remove workaround for bug #421543. This is fixed in core 0.10.13 and
+	  not necessary anymore as we need at least that core version.
+
+2007-06-09 15:33:32 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/: Improve discont handling by checking if the next Wavpack block has the expected, following block index.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_reset),
+	  (gst_wavpack_dec_chain):
+	  * ext/wavpack/gstwavpackdec.h:
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_reset),
+	  (gst_wavpack_parse_push_buffer):
+	  * ext/wavpack/gstwavpackparse.h:
+	  Improve discont handling by checking if the next Wavpack block has
+	  the expected, following block index.
+
+2007-06-08 20:23:07 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* tests/check/elements/.gitignore:
+	  moap ignore
+	  Original commit message from CVS:
+	  moap ignore
+
+2007-06-08 20:20:56 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  gst/rtp/gstrtpmp4vpay.c (gst_rtp_mp4vpay_details): Fix element description.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4vpay.c (gst_rtp_mp4vpay_details):
+	  Fix element description.
+
+2007-06-08 20:19:55 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  move wavpack plugin.  See #352605.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-good-plugins.signals:
+	  * docs/plugins/inspect/plugin-autodetect.xml:
+	  * docs/plugins/inspect/plugin-gconfelements.xml:
+	  * docs/plugins/inspect/plugin-ladspa.xml:
+	  * docs/plugins/inspect/plugin-rtp.xml:
+	  * docs/plugins/inspect/plugin-wavpack.xml:
+	  * ext/Makefile.am:
+	  * tests/check/Makefile.am:
+	  move wavpack plugin.  See #352605.
+
+2007-06-08 19:45:43 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/plugins/Makefile.am:
+	  the alphabet tripping up people since 10929BC
+	  Original commit message from CVS:
+	  the alphabet
+	  tripping up people since 10929BC
+
+2007-06-08 17:37:02 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Add DirectDraw & DirectSound plugins to the build and docs.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * sys/Makefile.am:
+	  * win32/MANIFEST:
+	  Add DirectDraw & DirectSound plugins to the build and docs.
+
+2007-06-08 16:31:15 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Rename the keep-aspect-ratio property to force-aspect-ratio to make it consistent with xvimagesink and ximagesink.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-bad-plugins.args:
+	  * sys/directdraw/gstdirectdrawsink.c:
+	  (gst_directdraw_sink_class_init):
+	  Rename the keep-aspect-ratio property to force-aspect-ratio to make
+	  it consistent with xvimagesink and ximagesink.
+
+2007-06-08 10:43:26 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/: When operating in pull mode, error out correct on not-linked.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_loop):
+	  * ext/libpng/gstpngdec.c: (user_read_data), (gst_pngdec_task):
+	  When operating in pull mode, error out correct on not-linked.
+
+2007-06-08 08:12:43 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/icles/videocrop-test.c: Default to xvimagesink instead of autovideosink while autovideosink/ghostpads/whatever ...
+	  Original commit message from CVS:
+	  * tests/icles/videocrop-test.c: (main):
+	  Default to xvimagesink instead of autovideosink while
+	  autovideosink/ghostpads/whatever don't handle the way we use it in
+	  the way we expect it to.
+
+2007-06-06 10:19:17 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ChangeLog:
+	* sys/v4l2/v4l2src_calls.c:
+	  sys/v4l2/v4l2src_calls.c (gst_v4l2src_probe_caps_for_format)
+	  Original commit message from CVS:
+	  2007-06-06  Andy Wingo  <wingo@pobox.com>
+	  * sys/v4l2/v4l2src_calls.c (gst_v4l2src_probe_caps_for_format)
+	  (gst_v4l2src_probe_caps_for_format_and_size): Only probe for
+	  format and size if the ioctls are defined; should fix compilation
+	  on Linux < 2.16.19.
+
+2007-06-06 08:53:12 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/videobox/gstvideobox.c: Printf fixes in debug statements; use LOG level for debug statements that are printed for...
+	  Original commit message from CVS:
+	  * gst/videobox/gstvideobox.c: (gst_video_box_ayuv_i420):
+	  Printf fixes in debug statements; use LOG level for debug statements
+	  that are printed for each and every frame; convert c++ comments to
+	  C-style comments; not much point using g_try_malloc() if we then not
+	  even check the return value.
+
+2007-06-05 16:32:19 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Bump requirements to released versions (core and base 0.10.13).
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Bump requirements to released versions (core and base 0.10.13).
+	  * gst/icydemux/gsticydemux.c: (gst_icydemux_unicodify):
+	  Use gst_tag_utf8_from_freeform_string() from libgsttag instead of
+	  own implementation.
+
+2007-06-05 14:17:25 +0000  Andy Wingo <wingo@pobox.com>
+
+	  sys/v4l2/gstv4l2src.c (gst_v4l2src_start, gst_v4l2src_stop): Add some useless comments.
+	  Original commit message from CVS:
+	  2007-06-05  Andy Wingo  <wingo@pobox.com>
+	  * sys/v4l2/gstv4l2src.c (gst_v4l2src_start, gst_v4l2src_stop): Add
+	  some useless comments.
+	  * sys/v4l2/v4l2src_calls.c (gst_v4l2src_capture_init): Don't queue
+	  frames before calling STREAMON, that might leave them in a state
+	  where they can't be dequeued if we go back to NULL without calling
+	  STREAMON, according to the docs.
+	  (gst_v4l2src_capture_start): Enqueue buffers here instead, right
+	  before we call STREAMON.
+	  (gst_v4l2src_capture_deinit): Remove crack to work around dequeue
+	  failures. (For me this code hung.) The pool refcounting is still
+	  crack; added a note to that effect.
+
+2007-06-05 09:11:41 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/multipart/multipartmux.c: Add support for mapping gst structure names to the MIME type equivalent.
+	  Original commit message from CVS:
+	  * gst/multipart/multipartmux.c: (gst_multipart_mux_class_init),
+	  (gst_multipart_mux_get_mime), (gst_multipart_mux_collected):
+	  Add support for mapping gst structure names to the MIME type equivalent.
+	  Implemented for audio/x-mulaw->audio/basic. Fixes #442874.
+
+2007-06-03 11:21:44 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/wavenc/gstwavenc.*: Properly write wav files with width!=depth by having the depth most significant bytes set and...
+	  Original commit message from CVS:
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_create_header_buf),
+	  (gst_wavenc_sink_setcaps), (gst_wavenc_format_samples),
+	  (gst_wavenc_chain), (gst_wavenc_change_state):
+	  * gst/wavenc/gstwavenc.h:
+	  Properly write wav files with width!=depth by having the depth most
+	  significant bytes set and all others zero. Fixes #442535.
+
+2007-06-01 13:52:17 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/rtspconnection.c: Add include to make buildbot happy.
+	  Original commit message from CVS:
+	  * gst/rtsp/rtspconnection.c:
+	  Add include to make buildbot happy.
+
+2007-06-01 13:07:11 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtsp/: Improves version checking, allowing an RTSP server to reply with "505
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt  <pkj at axis com>
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_create),
+	  (rtsp_connection_connect), (add_date_header),
+	  (rtsp_connection_send), (parse_response_status),
+	  (parse_request_line), (parse_line), (rtsp_connection_receive):
+	  * gst/rtsp/rtspdefs.c: (rtsp_version_as_text):
+	  * gst/rtsp/rtspdefs.h:
+	  * gst/rtsp/rtspmessage.c: (key_value_foreach),
+	  (rtsp_message_init_request), (rtsp_message_init_response),
+	  (rtsp_message_remove_header), (rtsp_message_append_headers),
+	  (rtsp_message_dump):
+	  * gst/rtsp/rtspmessage.h:
+	  Improves version checking, allowing an RTSP server to reply with "505
+	  RTSP Version not supported.
+	  Adds a Date header to all messages.
+	  Replies with RTSP_EPARSE rather than RTSP_EINVALID in cases where we
+	  want to be able to send a response even if something in the request was
+	  invalid. EINVAL is only used when passing wrong arguments to functions.
+	  Do not handle an invalid method in parse_request_line(). Defer this to
+	  the caller so it can respond with "405 Method Not Allowed".
+	  Improves parsing of the timeout parameter to the Session header,
+	  allowing whitespace after the semicolon.
+	  Avoids a compiler warning due to variables shadowing a function argument.
+
+2007-06-01 11:16:17 +0000  Daniel Charles <dcharles@ti.com>
+
+	  gst/rtp/: Add support for AMR-WB.
+	  Original commit message from CVS:
+	  Based on Patch by: Daniel Charles <dcharles at ti dot com>
+	  * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_setcaps),
+	  (gst_rtp_amr_depay_process):
+	  * gst/rtp/gstrtpamrdepay.h:
+	  * gst/rtp/gstrtpamrpay.c: (gst_rtp_amr_pay_base_init),
+	  (gst_rtp_amr_pay_class_init), (gst_rtp_amr_pay_init),
+	  (gst_rtp_amr_pay_setcaps), (gst_rtp_amr_pay_handle_buffer):
+	  * gst/rtp/gstrtpamrpay.h:
+	  Add support for AMR-WB.
+	  Small cleanups such as using BOILERPLATE.
+
+2007-05-31 15:57:07 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/rtspextwms.c: Fix compile warning when debug is disabled as spotted bu Saur on IRC.
+	  Original commit message from CVS:
+	  * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_configure_stream):
+	  Fix compile warning when debug is disabled as spotted bu Saur on IRC.
+
+2007-05-30 14:57:44 +0000  Andy Wingo <wingo@pobox.com>
+
+	  sys/v4l2/gstv4l2object.*: Revert some unintended changes.
+	  Original commit message from CVS:
+	  2007-05-30  Andy Wingo  <wingo@pobox.com>
+	  * sys/v4l2/gstv4l2object.h:
+	  * sys/v4l2/gstv4l2object.c (gst_v4l2_object_new): Revert some
+	  unintended changes.
+
+2007-05-30 14:40:53 +0000  Andy Wingo <wingo@pobox.com>
+
+	  sys/v4l2/v4l2src_calls.*: Store the format list in the order that the driver gives it to us.
+	  Original commit message from CVS:
+	  2007-05-30  Andy Wingo  <wingo@pobox.com>
+	  * sys/v4l2/v4l2src_calls.h:
+	  * sys/v4l2/v4l2src_calls.c (gst_v4l2src_fill_format_list): Store
+	  the format list in the order that the driver gives it to us.
+	  (gst_v4l2src_probe_caps_for_format_and_size)
+	  (gst_v4l2src_probe_caps_for_format): New functions, fill GstCaps
+	  based on the capabilities of the device.
+	  (gst_v4l2src_grab_frame): Update for object variable renaming.
+	  (gst_v4l2src_set_capture): Update to be strict in its parameters,
+	  as in the set_caps below.
+	  (gst_v4l2src_capture_init): Update for object variable renaming,
+	  and reflow.
+	  (gst_v4l2src_capture_start, gst_v4l2src_capture_stop)
+	  (gst_v4l2src_capture_deinit): Update for object variable renaming.
+	  (gst_v4l2src_update_fps, gst_v4l2src_set_fps)
+	  (gst_v4l2src_get_fps): Remove; these functions don't have much
+	  meaning outside of an atomic set_caps method.
+	  (gst_v4l2src_buffer_new): Don't set buffer duration, it is not
+	  known.
+	  * sys/v4l2/gstv4l2tuner.c (gst_v4l2_tuner_set_channel): Remove
+	  call to update_fps; not sure about this change.
+	  (gst_v4l2_tuner_set_norm): Work around the fact that for the
+	  moment we don't have an update_fps_func.
+	  * sys/v4l2/gstv4l2src.h (struct _GstV4l2Src): Don't put v4l2
+	  structures in the object, just store what we need. Do store the
+	  probed caps of the device. Don't store the current frame rate.
+	  * sys/v4l2/gstv4l2src.c (gst_v4l2src_init): Remove the
+	  update_fps_function, for now. Update for new object variable
+	  naming.
+	  (gst_v4l2src_set_property, gst_v4l2src_get_property): Update for
+	  new object variable naming.
+	  (gst_v4l2src_v4l2fourcc_to_structure): Rename from ..._to_caps.
+	  (gst_v4l2_structure_to_v4l2fourcc): Rename from ...caps_to_....
+	  (gst_v4l2src_get_caps): Rework to probe the device for supported
+	  frame sizes and frame rates.
+	  (gst_v4l2src_set_caps): Rework to be strict in the given
+	  parameters: if someone asks us to have a certain size and rate,
+	  that is what we configure.
+	  (gst_v4l2src_get_read): Update for object variable naming. Don't
+	  leak buffers on short reads.
+	  (gst_v4l2src_get_mmap): Update for object variable naming, and add
+	  comments.
+	  (gst_v4l2src_create): Update for object variable naming.
+
+2007-05-30 14:38:59 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavidemux.*: Parse subtitle text streams instead of erroring out (#442034). Still needs a parser for the su...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_base_init),
+	  (gst_avi_demux_reset), (gst_avi_demux_parse_stream):
+	  * gst/avi/gstavidemux.h:
+	  Parse subtitle text streams instead of erroring out (#442034). Still
+	  needs a parser for the subtitles to actually show up.
+
+2007-05-30 12:46:32 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavidemux.c: Make _push_event() return TRUE if the event could be pushed on at least one pad and not only i...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_push_event),
+	  (gst_avi_demux_loop):
+	  Make _push_event() return TRUE if the event could be pushed on at
+	  least one pad and not only if it could be pushed on all pads,
+	  otherwise we'll end up posting an error message on EOS if one or
+	  more source pads are not connected.
+
+2007-05-28 16:39:09 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/rtsptransport.c: Use renamed RTP bin.
+	  Original commit message from CVS:
+	  * gst/rtsp/rtsptransport.c:
+	  Use renamed RTP bin.
+
+2007-05-28 15:01:33 +0000  Dejan Sakelšak <sakdean@gmail.com>
+
+	  gst/videobox/gstvideobox.c: Add AYUV->AYUV and AYUV->I420 formats.
+	  Original commit message from CVS:
+	  Based on patch by: Dejan Sakelšak <sakdean at gmail dot com>
+	  * gst/videobox/gstvideobox.c: (gst_video_box_class_init),
+	  (gst_video_box_set_property), (gst_video_box_transform_caps),
+	  (video_box_recalc_transform), (gst_video_box_set_caps),
+	  (gst_video_box_get_unit_size), (gst_video_box_apply_alpha),
+	  (gst_video_box_ayuv_ayuv), (gst_video_box_clear), (UVfloor),
+	  (UVceil), (gst_video_box_ayuv_i420), (gst_video_box_i420_ayuv),
+	  (gst_video_box_i420_i420), (gst_video_box_transform),
+	  (plugin_init):
+	  Add AYUV->AYUV and AYUV->I420 formats.
+	  Fix negotiation and I420->AYUV conversion.
+	  Fixes #429329.
+
+2007-05-26 15:25:18 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/speex/gstspeexdec.c: Use different variables for nested for loops so that the outer loop functions properly and s...
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexdec.c: (speex_dec_chain_parse_data):
+	  Use different variables for nested for loops so that the outer loop
+	  functions properly and speex files with multiple frames per buffer work
+	  properly.
+	  Fixes #441408.
+
+2007-05-25 20:51:36 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/gstid3demux.c: Don't leak newsegment events.
+	  Original commit message from CVS:
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_sink_event):
+	  Don't leak newsegment events.
+
+2007-05-25 20:33:10 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/wavparse/Makefile.am: Add '-lm' to LIBS for ceil(), don't assume one of our dependencies drags it in.
+	  Original commit message from CVS:
+	  * gst/wavparse/Makefile.am:
+	  Add '-lm' to LIBS for ceil(), don't assume one of our dependencies
+	  drags it in.
+
+2007-05-25 16:02:51 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacenc.*: Collect headers, add "streamheader" field to output caps and set
+	  Original commit message from CVS:
+	  * ext/flac/gstflacenc.c: (gst_flac_enc_init),
+	  (notgst_value_array_append_buffer),
+	  (gst_flac_enc_process_stream_headers),
+	  (gst_flac_enc_write_callback), (gst_flac_enc_chain),
+	  (gst_flac_enc_change_state):
+	  * ext/flac/gstflacenc.h:
+	  Collect headers, add "streamheader" field to output caps and set
+	  BUFFER_IN_CAPS flag on pushed header buffers. That way oggmux
+	  produces output according to the official FLAC-to-Ogg mapping
+	  instead of completely broken files. Fixes #426044.
+
+2007-05-25 10:44:12 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/: Handle and adjust new-segment events so that downstream really sees a stream with the tag pieces stripped off t...
+	  Original commit message from CVS:
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_reset),
+	  (gst_id3demux_send_new_segment), (gst_id3demux_chain),
+	  (gst_id3demux_sink_event):
+	  * gst/id3demux/gstid3demux.h:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_reset),
+	  (gst_tag_demux_chain), (gst_tag_demux_sink_event),
+	  (gst_tag_demux_send_new_segment):
+	  Handle and adjust new-segment events so that downstream really
+	  sees a stream with the tag pieces stripped off the front and back.
+	  Fixes strangeness in seeking when mp3 decoders use the new-segment
+	  byte position to estimate their current playback position timestamp
+	  and then the arriving buffers don't match up.
+
+2007-05-25 10:23:49 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/autodetect/gstautoaudiosink.c: Don't unnecessarily perform a READY->NULL->READY transition on the detected audio ...
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautoaudiosink.c: (gst_auto_audio_sink_detect):
+	  Don't unnecessarily perform a READY->NULL->READY transition on the
+	  detected audio sink when starting up. Fixes: #440127
+
+2007-05-24 17:00:21 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacenc.c: Don't crash in chain function if setcaps hasn't been called.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacenc.c: (gst_flac_enc_sink_setcaps),
+	  (gst_flac_enc_chain):
+	  Don't crash in chain function if setcaps hasn't been called.
+
+2007-05-24 08:35:23 +0000  Vincent Torri <vtorri@univ-evry.fr>
+
+	  sys/directdraw/gstdirectdrawsink.*: Fix more warnings when compiling with MingW (#439914).
+	  Original commit message from CVS:
+	  Patch by: Vincent Torri  <vtorri at univ-evry fr>
+	  * sys/directdraw/gstdirectdrawsink.c:
+	  (gst_directdraw_sink_buffer_alloc),
+	  (gst_directdraw_sink_show_frame),
+	  (gst_directdraw_sink_check_primary_surface),
+	  (gst_directdraw_sink_check_offscreen_surface),
+	  (EnumModesCallback2), (gst_directdraw_sink_get_ddrawcaps),
+	  (gst_directdraw_sink_surface_create):
+	  * sys/directdraw/gstdirectdrawsink.h:
+	  Fix more warnings when compiling with MingW (#439914).
+
+2007-05-24 08:14:00 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Init value to avoid infinte loops.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_parse_methods):
+	  Init value to avoid infinte loops.
+
+2007-05-24 08:10:42 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtsp/: Fix for new API.
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt  <pkj at axis com>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_setup_auth),
+	  (gst_rtspsrc_try_send), (gst_rtspsrc_parse_methods),
+	  (gst_rtspsrc_setup_streams), (gst_rtspsrc_open),
+	  (gst_rtspsrc_play):
+	  (rtsp_connection_send), (rtsp_connection_receive):
+	  * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_after_send):
+	  Fix for new API.
+	  * gst/rtsp/rtspconnection.c: (add_auth_header),
+	  Only add authorisation and session headers when sending messages.
+	  * gst/rtsp/rtspmessage.c: (key_value_foreach), (rtsp_message_init),
+	  (rtsp_message_init_request), (rtsp_message_init_response),
+	  (rtsp_message_unset), (rtsp_message_add_header),
+	  (rtsp_message_remove_header), (rtsp_message_get_header),
+	  (rtsp_message_append_headers), (dump_key_value),
+	  (rtsp_message_dump):
+	  * gst/rtsp/rtspmessage.h:
+	  Add support for multiple headers of the same type by storing the parsed
+	  headers in a GArray instaed of a hashtable.
+
+2007-05-23 22:44:12 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  docs/plugins/gst-plugins-bad-plugins.args: Remove directsoundsink property doc as this sink use the mixer interface now.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-bad-plugins.args:
+	  Remove directsoundsink property doc as this sink use the mixer
+	  interface now.
+	  * docs/plugins/gst-plugins-bad-plugins.interfaces:
+	  Add interfaces implemented by Windows sinks.
+	  * sys/directsound/gstdirectsoundsink.c:
+	  * sys/directsound/gstdirectsoundsink.h:
+	  Remove directsoundsink property  and implement the mixer interface.
+	  * win32/vs6/gst_plugins_bad.dsw:
+	  * win32/vs6/libgstdirectsound.dsp:
+	  Update project files.
+	  * gst-libs/gst/dshow/gstdshow.cpp:
+	  * gst-libs/gst/dshow/gstdshow.h:
+	  * gst-libs/gst/dshow/gstdshowfakesink.cpp:
+	  * gst-libs/gst/dshow/gstdshowfakesink.h:
+	  * gst-libs/gst/dshow/gstdshowfakesrc.cpp:
+	  * gst-libs/gst/dshow/gstdshowfakesrc.h:
+	  * gst-libs/gst/dshow/gstdshowinterface.cpp:
+	  * gst-libs/gst/dshow/gstdshowinterface.h:
+	  * win32/common/libgstdshow.def:
+	  * win32/vs6/libgstdshow.dsp:
+	  Add a new gst library which allow to create internal Direct Show
+	  graph (pipelines) to wrap Windows sources, decoders or encoders.
+	  It includes a DirectShow fake source and sink and utility functions.
+	  * sys/dshowsrcwrapper/gstdshowaudiosrc.c:
+	  * sys/dshowsrcwrapper/gstdshowaudiosrc.h:
+	  * sys/dshowsrcwrapper/gstdshowsrcwrapper.c:
+	  * sys/dshowsrcwrapper/gstdshowsrcwrapper.h:
+	  * sys/dshowsrcwrapper/gstdshowvideosrc.c:
+	  * sys/dshowsrcwrapper/gstdshowvideosrc.h:
+	  * win32/vs6/libdshowsrcwrapper.dsp:
+	  Add a new plugin to wrap DirectShow sources on Windows.
+	  It gets data from any webcam, dv cam, micro. We could add
+	  tv tunner card later.
+
+2007-05-22 11:14:13 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  configure.ac: Depend on gstreamer-0.10.12.1. gst/equalizer/gstiirequalizer.c (ARG_BAND_WIDTH, _do_init, ARG_GAIN, _Gs...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Depend on gstreamer-0.10.12.1.
+	  * gst/equalizer/gstiirequalizer.c (ARG_BAND_WIDTH, _do_init, ARG_GAIN,
+	  _GstIirEqualizerBand, object, _GstIirEqualizerBandClass,
+	  parent_class, gst_iir_equalizer_band_set_property,
+	  gst_iir_equalizer_band_class_init, gst_iir_equalizer_band_get_type,
+	  gst_iir_equalizer_child_proxy_get_child_by_index,
+	  gst_iir_equalizer_child_proxy_get_children_count,
+	  gst_iir_equalizer_child_proxy_interface_init, setup_filter,
+	  gst_iir_equalizer_compute_frequencies,
+	  gst_iir_equalizer_set_property, gst_iir_equalizer_get_property,
+	  plugin_init):
+	  * gst/equalizer/gstiirequalizer.h (audiofilter):
+	  * gst/equalizer/gstiirequalizernbands.c (ARG_NUM_BANDS,
+	  gst_iir_equalizer_nbands_base_init, gst_iir_equalizer_nbands_init,
+	  gst_iir_equalizer_nbands_set_property):
+	  Use new locking macros.
+	  * gst/filter/gstbpwsinc.c (bpwsinc_set_caps):
+	  Add fixme.
+	  * gst/spectrum/gstspectrum.c (SPECTRUM_WINDOW_BASE,
+	  SPECTRUM_WINDOW_LEN, gst_spectrum_init, gst_spectrum_set_property,
+	  gst_spectrum_event, gst_spectrum_transform_ip):
+	  Use new locking macros. Turn two fixed values into #defines.
+
+2007-05-22 11:03:30 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  docs/plugins/Makefile.am: Also look for .m (objectivec) files.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  Also look for .m (objectivec) files.
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-bad-plugins.args:
+	  * sys/osxvideo/osxvideosink.m:
+	  Add documentation for element and properties.
+
+2007-05-21 14:01:16 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ChangeLog: ChangeLog surgery. gst/equalizer/gstiirequalizer.c (ARG_BAND_WIDTH, _do_init, ARG_GAIN, _GstIirEqualizerBa...
+	  Original commit message from CVS:
+	  * ChangeLog:
+	  ChangeLog surgery.
+	  * gst/equalizer/gstiirequalizer.c (ARG_BAND_WIDTH, _do_init, ARG_GAIN,
+	  _GstIirEqualizerBand, object, _GstIirEqualizerBandClass,
+	  parent_class, gst_iir_equalizer_band_set_property,
+	  gst_iir_equalizer_band_class_init, gst_iir_equalizer_band_get_type,
+	  gst_iir_equalizer_child_proxy_get_child_by_index,
+	  gst_iir_equalizer_child_proxy_get_children_count,
+	  gst_iir_equalizer_child_proxy_interface_init, setup_filter,
+	  gst_iir_equalizer_compute_frequencies, plugin_init):
+	  * tests/icles/equalizer-test.c:
+	  Add fixme and comment for example.
+
+2007-05-21 12:43:37 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	* gst/spectrum/gstspectrum.c:
+	  gst/spectrum/gstspectrum.c (gst_spectrum_set_property, gst_spectrum_event, gst_spectrum_transform_ip):
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c (gst_spectrum_set_property,
+	  gst_spectrum_event, gst_spectrum_transform_ip):
+	  Use lock to protect from concurrent access.
+
+2007-05-21 11:37:16 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackenc.c: Specify and use properties as unsigned int that are an unsigned int.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_class_init),
+	  (gst_wavpack_enc_set_property), (gst_wavpack_enc_get_property):
+	  Specify and use properties as unsigned int that are an unsigned int.
+
+2007-05-21 11:17:21 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackenc.*: Fixup docs, make the bitrate property an int as it should be and allow to set the differ...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_class_init),
+	  (gst_wavpack_enc_init), (gst_wavpack_enc_set_wp_config),
+	  (gst_wavpack_enc_set_property), (gst_wavpack_enc_get_property):
+	  * ext/wavpack/gstwavpackenc.h:
+	  Fixup docs, make the bitrate property an int as it should be and
+	  allow to set the different extra processing modes instead of only
+	  allowing none and the default one.
+
+2007-05-21 10:07:05 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstudpsrc.c: Since we depend on 0.10.13 -core, override the unlock_stop vmethod for safer shutdown.
+	  Original commit message from CVS:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init),
+	  (gst_udpsrc_create), (gst_udpsrc_unlock), (gst_udpsrc_unlock_stop):
+	  Since we depend on 0.10.13 -core, override the unlock_stop vmethod for
+	  safer shutdown.
+
+2007-05-21 10:03:42 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtpdec.*: Added signal for backwards compat.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtpdec.c: (gst_rtp_dec_class_init):
+	  * gst/rtsp/gstrtpdec.h:
+	  Added signal for backwards compat.
+
+2007-05-21 09:32:26 +0000  René Stadler <mail@renestadler.de>
+
+	  Use audioconvert for converting from non-native endianness floats in auparse instead of doing it ourself. Fixes #424527.
+	  Original commit message from CVS:
+	  Patch by: René Stadler <mail at renestadler dot de>
+	  * configure.ac:
+	  * gst/auparse/gstauparse.c: (gst_au_parse_reset),
+	  (gst_au_parse_parse_header), (gst_au_parse_chain):
+	  * gst/auparse/gstauparse.h:
+	  Use audioconvert for converting from non-native endianness floats
+	  in auparse instead of doing it ourself. Fixes #424527.
+	  This needs the audioconvert from plugins-base CVS.
+
+2007-05-21 09:29:30 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtph263ppay.c: Fix enum registration.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph263ppay.c: (gst_fragmentation_mode_get_type),
+	  (gst_rtp_h263p_pay_flush):
+	  Fix enum registration.
+
+2007-05-21 08:57:18 +0000  Antoine Tremblay <hexa00@gmail.com>
+
+	  gst/rtp/gstrtph263ppay.*: Add new fragmentation mode base on GOB headers. Fixes #438940.
+	  Original commit message from CVS:
+	  Patch by: Antoine Tremblay <hexa00 at gmail dot com>
+	  * gst/rtp/gstrtph263ppay.c: (gst_fragmentation_mode_get_type),
+	  (gst_rtp_h263p_pay_class_init), (gst_rtp_h263p_pay_init),
+	  (gst_rtp_h263p_pay_set_property), (gst_rtp_h263p_pay_get_property),
+	  (gst_rtp_h263p_pay_flush):
+	  * gst/rtp/gstrtph263ppay.h:
+	  Add new fragmentation mode base on GOB headers. Fixes #438940.
+
+2007-05-20 21:31:58 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackenc.c: Add missing audioconverts in the example pipelines of wavpackenc. As the wavpack stuff n...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackenc.c:
+	  Add missing audioconverts in the example pipelines of wavpackenc. As
+	  the wavpack stuff now needs input with 32 bit width (and random depth)
+	  this is needed now. The example pipelines for the parser and decoder
+	  are still fine.
+
+2007-05-20 14:59:46 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/directdraw/gstdirectdrawsink.c: Bunch of small fixes: remove static function that doesn't exist; declare another ...
+	  Original commit message from CVS:
+	  * sys/directdraw/gstdirectdrawsink.c: (gst_ddrawsurface_finalize),
+	  (gst_directdraw_sink_buffer_alloc),
+	  (gst_directdraw_sink_get_ddrawcaps),
+	  (gst_directdraw_sink_surface_create):
+	  Bunch of small fixes: remove static function that doesn't exist;
+	  declare another one that does; printf format fix; use right macro
+	  when specifying debug category; remove a bunch of unused variables;
+	  #if 0 out an unused chunk of code (partially fixes #439914).
+
+2007-05-20 14:14:49 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/: Printf format fixes (#439910, #439911).
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_prepare_current_sample):
+	  * gst/switch/gstswitch.c: (gst_switch_chain):
+	  Printf format fixes (#439910, #439911).
+
+2007-05-20 14:05:42 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/rtsp/gstrtspsrc.c: Printf format fix.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_loop_udp):
+	  Printf format fix.
+
+2007-05-19 10:01:45 +0000  René Stadler <mail@renestadler.de>
+
+	  Add replaygain playback elements (#412710).
+	  Original commit message from CVS:
+	  Patch by: René Stadler <mail at renestadler de>
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * docs/plugins/inspect/plugin-replaygain.xml:
+	  * gst/replaygain/Makefile.am:
+	  * gst/replaygain/gstrganalysis.c: (gst_rg_analysis_class_init),
+	  (gst_rg_analysis_start), (gst_rg_analysis_set_caps),
+	  (gst_rg_analysis_transform_ip), (gst_rg_analysis_event),
+	  (gst_rg_analysis_stop), (gst_rg_analysis_handle_tags),
+	  (gst_rg_analysis_handle_eos), (gst_rg_analysis_track_result),
+	  (gst_rg_analysis_album_result):
+	  * gst/replaygain/gstrganalysis.h:
+	  * gst/replaygain/gstrglimiter.c: (gst_rg_limiter_base_init),
+	  (gst_rg_limiter_class_init), (gst_rg_limiter_init),
+	  (gst_rg_limiter_set_property), (gst_rg_limiter_get_property),
+	  (gst_rg_limiter_transform_ip):
+	  * gst/replaygain/gstrglimiter.h:
+	  * gst/replaygain/gstrgvolume.c: (gst_rg_volume_base_init),
+	  (gst_rg_volume_class_init), (gst_rg_volume_init),
+	  (gst_rg_volume_set_property), (gst_rg_volume_get_property),
+	  (gst_rg_volume_dispose), (gst_rg_volume_change_state),
+	  (gst_rg_volume_sink_event), (gst_rg_volume_tag_event),
+	  (gst_rg_volume_reset), (gst_rg_volume_update_gain),
+	  (gst_rg_volume_determine_gain):
+	  * gst/replaygain/gstrgvolume.h:
+	  * gst/replaygain/replaygain.c: (plugin_init):
+	  * gst/replaygain/replaygain.h:
+	  * gst/replaygain/rganalysis.h:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/rganalysis.c: (send_eos_event),
+	  (GST_START_TEST):
+	  * tests/check/elements/rglimiter.c: (setup_rglimiter),
+	  (cleanup_rglimiter), (set_playing_state), (create_test_buffer),
+	  (verify_test_buffer), (GST_START_TEST), (rglimiter_suite), (main):
+	  * tests/check/elements/rgvolume.c: (event_func), (setup_rgvolume),
+	  (cleanup_rgvolume), (set_playing_state), (set_null_state),
+	  (send_eos_event), (send_tag_event), (test_buffer_new),
+	  (fail_unless_target_gain), (fail_unless_result_gain),
+	  (fail_unless_gain), (GST_START_TEST), (rgvolume_suite), (main):
+	  Add replaygain playback elements (#412710).
+
+2007-05-18 13:27:39 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Don't crash when an unsupported transport error was returned by the server, just try to config...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_setup_streams):
+	  Don't crash when an unsupported transport error was returned by the
+	  server, just try to configure the next stream. Fixes #439255.
+
+2007-05-18 11:39:12 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Add TCP timeout property and use it for all TCP connection.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_class_init),
+	  (gst_rtspsrc_set_property), (gst_rtspsrc_get_property),
+	  (gst_rtspsrc_stream_configure_udp), (gst_rtspsrc_loop_interleaved),
+	  (gst_rtspsrc_loop_udp), (gst_rtspsrc_try_send), (gst_rtspsrc_send),
+	  (gst_rtspsrc_setup_streams), (gst_rtspsrc_open):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Add TCP timeout property and use it for all TCP connection.
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_connect),
+	  (rtsp_connection_write), (rtsp_connection_next_timeout),
+	  (rtsp_connection_reset_timeout):
+	  Make connect and writes cancelable and make them use the timeout.
+
+2007-05-18 10:36:12 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Refactor timeout handling.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send_keep_alive),
+	  (gst_rtspsrc_loop_interleaved), (gst_rtspsrc_loop_udp),
+	  (gst_rtspsrc_try_send), (gst_rtspsrc_send),
+	  (gst_rtspsrc_setup_streams):
+	  Refactor timeout handling.
+	  Also send keep-alive when dealing with TCP transport.
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_create),
+	  (rtsp_connection_free), (rtsp_connection_next_timeout),
+	  (rtsp_connection_reset_timeout):
+	  * gst/rtsp/rtspconnection.h:
+	  Use a timer to handle the session timeouts, add some methods to deal
+	  with timeouts.
+
+2007-05-17 14:56:39 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Ignore streams that fail the setup command, we will retry with a different transport later on.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send),
+	  (gst_rtspsrc_setup_streams):
+	  Ignore streams that fail the setup command, we will retry with a
+	  different transport later on.
+	  * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_parse_sdp),
+	  (rtsp_ext_wms_configure_stream):
+	  Fix encoding name case.
+
+2007-05-17 10:59:00 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  sys/osxvideo/osxvideosink.*: Remove the event-loop-in-separate-thread modifications, because MacOSX is $#@(*%$# ! For...
+	  Original commit message from CVS:
+	  * sys/osxvideo/osxvideosink.h:
+	  * sys/osxvideo/osxvideosink.m:
+	  Remove the event-loop-in-separate-thread modifications, because MacOSX
+	  is $#@(*%$# ! For those wondering, the event handling needs to be done
+	  in the main thread after all..
+
+2007-05-17 09:41:48 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  sys/osxvideo/osxvideosink.*: Fix a stupid #if vs #ifdef bug. Should use the proper colorspace now.
+	  Original commit message from CVS:
+	  * sys/osxvideo/osxvideosink.h:
+	  * sys/osxvideo/osxvideosink.m:
+	  Fix a stupid #if vs #ifdef bug. Should use the proper colorspace now.
+	  Use a separate thread/task for the cocoa event_loop, else it wouldn't
+	  stop.
+
+2007-05-16 16:50:23 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/libpng/gstpngdec.c: Fix build on macosx.
+	  Original commit message from CVS:
+	  * ext/libpng/gstpngdec.c: (user_endrow_callback), (user_read_data):
+	  Fix build on macosx.
+
+2007-05-16 16:30:03 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/raw1394/gstdv1394src.c: Replace direct comparison of a string with the string literal "" with a comparison of the...
+	  Original commit message from CVS:
+	  * ext/raw1394/gstdv1394src.c: (gst_dv1394src_uri_set_uri):
+	  Replace direct comparison of a string with the string literal "" with
+	  a comparison of the first character with '\0'. Fixes #438926.
+
+2007-05-15 17:22:58 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Add DIRECTDRAW_CFLAGS and DIRECTSOUND_CFLAGS to Makefile.am; save and restore the various flags in the directdraw/dir...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * sys/directdraw/Makefile.am:
+	  * sys/directsound/Makefile.am:
+	  Add DIRECTDRAW_CFLAGS and DIRECTSOUND_CFLAGS to Makefile.am; save
+	  and restore the various flags in the directdraw/directsound
+	  detection section. Apparently improves cross-compiling for win32
+	  with mingw32 under some circumstances (#437539).
+
+2007-05-15 11:18:33 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/debug/breakmydata.c (gst_break_my_data_init): One more try. This should be the proper fix now.
+	  Original commit message from CVS:
+	  * gst/debug/breakmydata.c (gst_break_my_data_init):
+	  One more try. This should be the proper fix now.
+
+2007-05-15 06:41:58 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/debug/breakmydata.c: Ooops, no // comments please.
+	  Original commit message from CVS:
+	  * gst/debug/breakmydata.c:
+	  Ooops, no // comments please.
+
+2007-05-15 06:34:48 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/debug/breakmydata.c: Fix gst_buffer_is_writable() assertion.
+	  Original commit message from CVS:
+	  * gst/debug/breakmydata.c: (gst_break_my_data_class_init),
+	  (gst_break_my_data_init):
+	  Fix gst_buffer_is_writable() assertion.
+
+2007-05-15 02:56:23 +0000  David Schleef <ds@schleef.org>
+
+	  sys/v4l2/gstv4l2src.c: Add support for Bayer images as video/x-raw-bayer.  Fixes #314160.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c: Add support for Bayer images as
+	  video/x-raw-bayer.  Fixes #314160.
+
+2007-05-14 17:10:12 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Update theora pay/depayloader in a similar to vorbis.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtptheoradepay.c: (decode_base64),
+	  (gst_rtp_theora_depay_parse_configuration):
+	  * gst/rtp/gstrtptheorapay.c: (encode_base64),
+	  (gst_rtp_theora_pay_finish_headers),
+	  (gst_rtp_theora_pay_handle_buffer):
+	  Update theora pay/depayloader in a similar to vorbis.
+	  * gst/rtp/gstrtpvorbisdepay.c:
+	  (gst_rtp_vorbis_depay_parse_configuration):
+	  Update docs.
+
+2007-05-14 16:19:58 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: When we try to execute a method that is not supported by the server, don't error out but remov...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send):
+	  When we try to execute a method that is not supported by the server,
+	  don't error out but remove the method from the accepted methods so that
+	  we never try to perform this method again.
+
+2007-05-14 14:47:26 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpvorbisdepay.c: Remove annoying _dump_mem.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpvorbisdepay.c: (gst_rtp_vorbis_depay_process):
+	  Remove annoying _dump_mem.
+
+2007-05-14 11:11:42 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Parse range correctly.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_parse_range):
+	  Parse range correctly.
+	  * gst/rtsp/rtspurl.c: (rtsp_url_get_request_uri):
+	  The baseurl now always has a '/' at the start.
+
+2007-05-14 09:01:05 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Factor out caps configuration and configure more stuff such as the time ranges and speed/scale...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_configure_caps),
+	  (gst_rtspsrc_parse_range), (gst_rtspsrc_open),
+	  (gst_rtspsrc_parse_rtpinfo), (gst_rtspsrc_play):
+	  Factor out caps configuration and configure more stuff such as the time
+	  ranges and speed/scale values.
+	  * gst/rtsp/rtsptransport.c:
+	  Add Copyright after non-trival fixes.
+
+2007-05-13 19:57:45 +0000  David Schleef <ds@schleef.org>
+
+	  gst/replaygain/rganalysis.c: Fix wrong ifdef for visual C++.  Fixes: #437403.
+	  Original commit message from CVS:
+	  * gst/replaygain/rganalysis.c:
+	  Fix wrong ifdef for visual C++.  Fixes: #437403.
+	  By Ali Sabil <ali.sabil@gmail.com>.
+
+2007-05-13 15:47:13 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  gst/level/gstlevel.c: Use guint8 * instead of gpointer then vs6 can build in_data += (filter->width / 8).
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c: (gst_level_transform_ip):
+	  Use guint8 * instead of gpointer then vs6 can build
+	  in_data += (filter->width / 8).
+
+2007-05-12 16:37:50 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtsp/: Make channel guint8 where possible.
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt  <pkj at axis com>
+	  * gst/rtsp/gstrtspsrc.h:
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_receive):
+	  * gst/rtsp/rtspmessage.c: (rtsp_message_init_data),
+	  (rtsp_message_get_header):
+	  * gst/rtsp/rtspmessage.h:
+	  Make channel guint8 where possible.
+	  Make rtsp_message_init_data() take the channel as a guint8.
+	  * gst/rtsp/rtspdefs.c:
+	  Fixed a typo: Timout -> Timeout
+	  * gst/rtsp/rtspdefs.h:
+	  Make RTSP_CHECK() behave as a statement.
+	  * gst/rtsp/sdpmessage.c:
+	  Avoid a compiler warning in INIT_ARRAY().
+	  Fixes #437692.
+
+2007-05-12 16:27:51 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtsp/rtspurl.*: Add support for query parameters to RTSP URLs.
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt  <pkj at axis com>
+	  * gst/rtsp/rtspurl.c: (rtsp_url_parse), (rtsp_url_free),
+	  (rtsp_url_get_request_uri):
+	  * gst/rtsp/rtspurl.h:
+	  Add support for query parameters to RTSP URLs.
+
+2007-05-12 16:26:06 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtsp/rtsptransport.*: Add validation to rtsp_transport_parse().
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt  <pkj at axis com>
+	  * gst/rtsp/rtsptransport.c: (rtsp_transport_init), (parse_mode),
+	  (parse_range), (range_as_text), (rtsp_transport_mode_as_text),
+	  (rtsp_transport_profile_as_text), (rtsp_transport_ltrans_as_text),
+	  (rtsp_transport_parse), (rtsp_transport_as_text):
+	  * gst/rtsp/rtsptransport.h:
+	  Add validation to rtsp_transport_parse().
+	  Add rtsp_transport_as_text() to generate an RTSP header from an
+	  RTSPTransport.
+	  Change ssrc to guint (was a string) since that is what it is, even
+	  though it is sent as a hex string.
+	  Correctly identify PLAY|RECORD mode parameters (the syntax in the RFC is
+	  incorrect, which can be seen when looking at the examples in the RFC).
+	  Fixes #437670.
+
+2007-05-11 16:11:04 +0000  Eric Anholt <anholt@freebsd.org>
+
+	* ChangeLog:
+	* sys/ximage/gstximagesrc.c:
+	  sys/ximage/gstximagesrc.c (gst_ximage_src_open_display, gst_ximage_src_ximage_get):
+	  Original commit message from CVS:
+	  Patch by: Eric Anholt
+	  * sys/ximage/gstximagesrc.c (gst_ximage_src_open_display,
+	  gst_ximage_src_ximage_get):
+	  Use union of all damage between frames to make it faster.
+	  Fixes bug #342463.
+	  Also fix crasher when cursor is at bottom right of window.
+
+2007-05-11 16:01:45 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/wavparse/gstwavparse.c: Skip LIST chunks before the fmt chunk (fixes #437499). Also fix streaming mode regression...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_stream_headers):
+	  Skip LIST chunks before the fmt chunk (fixes #437499). Also fix
+	  streaming mode regression for file from #343837 with 'bext' chunk
+	  before the 'fmt' chunk.
+
+2007-05-11 15:09:39 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/: Preliminary seek support.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_flush),
+	  (gst_rtspsrc_do_seek), (gst_rtspsrc_perform_seek),
+	  (gst_rtspsrc_handle_src_event),
+	  (gst_rtspsrc_stream_configure_manager),
+	  (gst_rtspsrc_stream_configure_tcp), (gst_rtspsrc_loop_interleaved),
+	  (gst_rtspsrc_send_keep_alive), (gst_rtspsrc_open),
+	  (gst_rtspsrc_parse_rtpinfo), (gst_rtspsrc_play):
+	  * gst/rtsp/gstrtspsrc.h:
+	  * gst/rtsp/rtspdefs.h:
+	  Preliminary seek support.
+	  Activate internal pads so that we can receive events on them.
+	  Don't try to parse a range string when it's NULL.
+
+2007-05-11 15:04:38 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/README: Update README with new RTP variables that will be used for synchronisation.
+	  Original commit message from CVS:
+	  * gst/rtp/README:
+	  Update README with new RTP variables that will be used for
+	  synchronisation.
+	  * gst/rtp/gstrtpvorbisdepay.c: (decode_base64),
+	  (gst_rtp_vorbis_depay_parse_configuration),
+	  (gst_rtp_vorbis_depay_process):
+	  * gst/rtp/gstrtpvorbispay.c: (encode_base64),
+	  (gst_rtp_vorbis_pay_finish_headers),
+	  (gst_rtp_vorbis_pay_handle_buffer):
+	  Update vorbis pay and depayloader to draft-04.
+
+2007-05-11 11:24:13 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/rtsptransport.c: UDP MCAST is actually the default for RTP/AVP.
+	  Original commit message from CVS:
+	  * gst/rtsp/rtsptransport.c:
+	  UDP MCAST is actually the default for RTP/AVP.
+
+2007-05-11 10:31:27 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  sys/ximage/gstximagesrc.c (gst_ximage_src_start, gst_ximage_src_ximage_get):
+	  Original commit message from CVS:
+	  * sys/ximage/gstximagesrc.c (gst_ximage_src_start,
+	  gst_ximage_src_ximage_get):
+	  * sys/ximage/gstximagesrc.h (last_ximage):
+	  When using Damage actually keep the last frame, and not assume
+	  that the buffer we get already has the last frame on it.
+	  Copy the cursor over if we specify a non-zero start x and
+	  start y.
+
+2007-05-11 09:12:55 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/rtsptransport.c: Make UDP the default transport when not specified.
+	  Original commit message from CVS:
+	  * gst/rtsp/rtsptransport.c:
+	  Make UDP the default transport when not specified.
+
+2007-05-10 14:02:07 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/qtdemux/qtdemux.c (gst_qtdemux_move_stream, gst_qtdemux_loop_state_header, gst_qtdemux_activate_segment, gst_qtde...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c (gst_qtdemux_move_stream,
+	  gst_qtdemux_loop_state_header, gst_qtdemux_activate_segment,
+	  gst_qtdemux_prepare_current_sample, gst_qtdemux_combine_flows,
+	  gst_qtdemux_loop_state_movie, gst_qtdemux_loop,
+	  qtdemux_parse_segments, qtdemux_parse_trak):
+	  * gst/rtpmanager/rtpsession.c (rtp_session_get_bandwidth,
+	  rtp_session_get_rtcp_bandwidth, rtp_session_get_cname,
+	  rtp_session_get_name, rtp_session_get_email, rtp_session_get_phone,
+	  rtp_session_get_location, rtp_session_get_tool,
+	  rtp_session_process_bye, session_report_blocks):
+	  * gst/rtpmanager/rtpsource.c (rtp_source_process_rtp,
+	  rtp_source_send_rtp, rtp_source_process_sr, rtp_source_process_rb):
+	  More format arg fixing (spotted by Ali Sabil <ali.sabil@gmail.com>).
+	  * gst/switch/Makefile.am:
+	  Add require libraries(spotted by Ali Sabil <ali.sabil@gmail.com>).
+
+2007-05-10 01:21:19 +0000  David Schleef <ds@schleef.org>
+
+	  gst/level/gstlevel.c: Revert last change.
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c:
+	  Revert last change.
+
+2007-05-09 21:30:53 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  gst/level/gstlevel.c: Use guint8 * instead of gpointer then vs6 know the size of data pointed when moving the pointer.
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c: (gst_level_calculate_##TYPE),
+	  (gst_level_transform_ip):
+	  Use guint8 * instead of gpointer then vs6 know the size of data
+	  pointed when moving the pointer.
+	  * gst/rtp/gstrtph264pay.c: (gst_rtp_h264_pay_handle_buffer):
+	  Move instructions after variables declaration.
+	  * win32/vs6/autogen.dsp:
+	  * win32/vs6/libgstrtp.dsp:
+	  * win32/vs6/libgstrtsp.dsp:
+	  Update vs6 project files.
+
+2007-05-09 11:23:39 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/: Add code to parse time ranges.
+	  Original commit message from CVS:
+	  * gst/rtsp/Makefile.am:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_handle_src_query),
+	  (gst_rtspsrc_send_keep_alive), (gst_rtspsrc_open):
+	  * gst/rtsp/rtsprange.c: (parse_npt_time), (parse_npt_range),
+	  (parse_clock_range), (parse_smpte_range), (rtsp_range_parse),
+	  (rtsp_range_free):
+	  * gst/rtsp/rtsprange.h:
+	  Add code to parse time ranges.
+	  Report DURATION on the stream when possible.
+
+2007-05-08 15:49:01 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/videomixer/videomixer.c: Fix strides calculation for AYUV (it's just width*4) (#436910).
+	  Original commit message from CVS:
+	  * gst/videomixer/videomixer.c: (gst_videomixer_blend_ayuv_ayuv),
+	  (gst_videomixer_fill_checker), (gst_videomixer_fill_color),
+	  (gst_videomixer_collected):
+	  Fix strides calculation for AYUV (it's just width*4) (#436910).
+
+2007-05-06 21:32:40 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/: Sync the GObject properties before each processing step to properly work with the controller.
+	  Original commit message from CVS:
+	  * gst/audiofx/audioamplify.c: (gst_audio_amplify_transform_ip):
+	  * gst/audiofx/audiodynamic.c: (gst_audio_dynamic_transform_ip):
+	  * gst/audiofx/audioinvert.c: (gst_audio_invert_transform_ip):
+	  Sync the GObject properties before each processing step to properly
+	  work with the controller.
+
+2007-05-04 15:17:14 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Let more error state trickle down so that we can catch more error cases.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send_keep_alive),
+	  (gst_rtspsrc_loop_udp), (gst_rtspsrc_try_send), (gst_rtspsrc_send),
+	  (gst_rtspsrc_setup_streams), (gst_rtspsrc_open),
+	  (gst_rtspsrc_close), (gst_rtspsrc_play), (gst_rtspsrc_pause),
+	  (gst_rtspsrc_change_state):
+	  Let more error state trickle down so that we can catch more error
+	  cases.
+	  Handle keep-alive a little smarter by selecting a method the server
+	  actually supports.
+	  Fix a race in UDP streaming shutdown.
+
+2007-05-04 13:04:31 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Ignore errors when trying to use the keep-alive messages.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send_keep_alive):
+	  Ignore errors when trying to use the keep-alive messages.
+
+2007-05-04 12:31:32 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Send RTCP messages back to the server over the TCP connection.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_handle_src_event),
+	  (gst_rtspsrc_handle_src_query), (gst_rtspsrc_sink_chain),
+	  (gst_rtspsrc_stream_configure_manager),
+	  (gst_rtspsrc_stream_free_udp), (gst_rtspsrc_stream_configure_tcp),
+	  (gst_rtspsrc_stream_configure_mcast),
+	  (gst_rtspsrc_stream_configure_udp),
+	  (gst_rtspsrc_stream_configure_udp_sink),
+	  (gst_rtspsrc_stream_configure_transport):
+	  Send RTCP messages back to the server over the TCP connection.
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_write),
+	  (rtsp_connection_send), (rtsp_connection_read), (read_body),
+	  (rtsp_connection_receive):
+	  * gst/rtsp/rtspconnection.h:
+	  Factor out and expose lowlevel _write and _read methods.
+	  Implement sending data messages to the server.
+
+2007-05-03 15:55:06 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/multipart/multipartmux.c: Fix timestamps on outgoing buffers.
+	  Original commit message from CVS:
+	  * gst/multipart/multipartmux.c: (gst_multipart_mux_queue_pads),
+	  (gst_multipart_mux_collected):
+	  Fix timestamps on outgoing buffers.
+
+2007-05-03 14:39:09 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/multipart/multipartmux.c: Emit NEWSEGMENT events before pushing the first buffer.
+	  Original commit message from CVS:
+	  * gst/multipart/multipartmux.c:
+	  (gst_multipart_mux_request_new_pad), (gst_multipart_mux_collected),
+	  (gst_multipart_mux_change_state):
+	  Emit NEWSEGMENT events before pushing the first buffer.
+
+2007-05-03 13:48:54 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Refactor transport configuration code.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_finalize),
+	  (gst_rtspsrc_alloc_udp_ports), (gst_rtspsrc_handle_src_event),
+	  (gst_rtspsrc_handle_src_query),
+	  (gst_rtspsrc_stream_configure_manager),
+	  (gst_rtspsrc_stream_free_udp), (gst_rtspsrc_stream_configure_tcp),
+	  (gst_rtspsrc_stream_configure_mcast),
+	  (gst_rtspsrc_stream_configure_udp),
+	  (gst_rtspsrc_stream_configure_udp_sink),
+	  (gst_rtspsrc_stream_configure_transport), (gst_rtspsrc_push_event),
+	  (gst_rtspsrc_loop_udp), (gst_rtspsrc_open),
+	  (gst_rtspsrc_parse_rtpinfo), (gst_rtspsrc_play),
+	  (gst_rtspsrc_pause):
+	  Refactor transport configuration code.
+	  Create internal pads for TCP transport so that we can implement events
+	  and queries.
+	  Handle events and queries.
+	  Parse range from the SDP.
+	  Fix race in pause handler where the connection could still be flushing.
+
+2007-05-02 19:32:58 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Fix race when multiple udp sources post timeouts, just act on the first received timeout.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init),
+	  (gst_rtspsrc_finalize), (new_session_pad), (request_pt_map),
+	  (gst_rtspsrc_loop_send_cmd), (gst_rtspsrc_try_send),
+	  (gst_rtspsrc_send), (gst_rtspsrc_async_open), (gst_rtspsrc_close),
+	  (gst_rtspsrc_play), (gst_rtspsrc_handle_message),
+	  (gst_rtspsrc_change_state):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Fix race when multiple udp sources post timeouts, just act on the first
+	  received timeout.
+	  Protect stream list with a recursive lock to fix some races.
+	  Flush connection when we need to do a reconnect or stop.
+	  Make state lock recursive.
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_connect),
+	  (rtsp_connection_close):
+	  Some small cleanups.
+
+2007-05-02 18:31:16 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpack.c: Call bindtextdomain() to get localized strings.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpack.c: (plugin_init):
+	  Call bindtextdomain() to get localized strings.
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_chain):
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_reset),
+	  (gst_wavpack_parse_handle_seek_event),
+	  (gst_wavpack_parse_push_buffer), (gst_wavpack_parse_chain):
+	  * ext/wavpack/gstwavpackparse.h:
+	  Handle DISCONT buffers by correctly setting the DISCONT flag
+	  on outgoing buffers when necessary.
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_handle_seek_event)
+	  Send newsegment from the streaming thread.
+
+2007-05-02 18:25:09 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/wavparse/gstwavparse.c: Only set DISCONT when there actually is a discont or when we just started.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_perform_seek),
+	  (gst_wavparse_stream_headers), (gst_wavparse_stream_data):
+	  Only set DISCONT when there actually is a discont or when we just
+	  started.
+
+2007-05-02 18:01:52 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/flac/gstflac.c: Call bindtextdomain() to get localized strings.
+	  Original commit message from CVS:
+	  * ext/flac/gstflac.c: (plugin_init):
+	  Call bindtextdomain() to get localized strings.
+
+2007-05-02 17:19:36 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/wavparse/gstwavparse.*: Be a bit more clever when dealing with VBR files with FACT tags, we don't want to timesta...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_perform_seek),
+	  (gst_wavparse_stream_headers), (gst_wavparse_add_src_pad),
+	  (gst_wavparse_stream_data):
+	  * gst/wavparse/gstwavparse.h:
+	  Be a bit more clever when dealing with VBR files with FACT tags, we
+	  don't want to timestamp buffers in that case but the estimated BPS can
+	  be used for seeking.
+	  Only send close segment in the streaming thread.
+
+2007-05-02 17:08:09 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/flac/gstflacdec.c: Correctly post an error on the bus if something went wrong in the loop function. This fixes a ...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_loop):
+	  Correctly post an error on the bus if something went wrong in the loop
+	  function. This fixes a few cases where the task was paused and nothing
+	  happened anymore.
+
+2007-05-02 16:58:06 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackparse.c: Remove old workaround that was needed when seeking after the last sample. With the fix...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackparse.c:
+	  (gst_wavpack_parse_handle_seek_event):
+	  Remove old workaround that was needed when seeking after the last
+	  sample. With the fixed error handling this works now as expected
+	  without pushing the last sample although it wasn't requested.
+
+2007-05-02 16:45:43 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackparse.c: Handle segment seeks in the seek event handler, correctly work with stop position == -...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackparse.c:
+	  (gst_wavpack_parse_handle_seek_event):
+	  Handle segment seeks in the seek event handler, correctly work with
+	  stop position == -1 and instead of stopping the task on seek just
+	  pause it.
+
+2007-05-02 16:19:58 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackparse.c: Add handling for segment seeks.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_loop):
+	  Add handling for segment seeks.
+
+2007-05-02 15:13:04 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackparse.c: Correctly handle errors, especially in the loop function. Before it was easy to get th...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_pull_buffer),
+	  (gst_wavpack_parse_create_src_pad),
+	  (gst_wavpack_parse_resync_loop), (gst_wavpack_parse_loop),
+	  (gst_wavpack_parse_chain):
+	  Correctly handle errors, especially in the loop function. Before it
+	  was easy to get the task paused but no error being posted on the bus.
+
+2007-05-02 14:27:28 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/test.c: Fix compilation of deprecated test just because I'm too lazy to delete it.
+	  Original commit message from CVS:
+	  * gst/rtsp/test.c: (main):
+	  Fix compilation of deprecated test just because I'm too lazy to delete
+	  it.
+
+2007-05-02 13:32:57 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Fix sending RTCP to the right place.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init),
+	  (gst_rtspsrc_finalize), (gst_rtspsrc_stream_configure_transport),
+	  (gst_rtspsrc_handle_request), (gst_rtspsrc_loop_interleaved),
+	  (gst_rtspsrc_send_keep_alive), (gst_rtspsrc_loop_udp),
+	  (gst_rtspsrc_loop_send_cmd), (gst_rtspsrc_try_send),
+	  (gst_rtspsrc_open), (gst_rtspsrc_handle_message):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Fix sending RTCP to the right place.
+	  Fix bug in reffing the wrong UDP element.
+	  Use new pad names for the session manager.
+	  Implement handling server requests in interleaved and UDP modes.
+	  Handle session keep-alive in UDP modes.
+	  Remove GCond for handling UDP timeouts.
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_connect),
+	  (rtsp_connection_send), (rtsp_connection_read), (read_body),
+	  (rtsp_connection_receive), (rtsp_connection_close):
+	  * gst/rtsp/rtspconnection.h:
+	  Store connection IP address for later.
+	  Add timeout args to all operations that might block forever.
+	  Parse session timeout.
+	  Only close sockets when not already closed.
+	  * gst/rtsp/rtspdefs.c:
+	  * gst/rtsp/rtspdefs.h:
+	  Add timeout return value and error string.
+	  * gst/rtsp/rtspmessage.c: (rtsp_message_init_response):
+	  Add small comment.
+
+2007-05-01 16:13:58 +0000  Sjoerd Simons <sjoerd@luon.net>
+
+	  gst/rtp/gstrtpmp4vpay.*: Handle NEWSEGMENT and FLUSH events. Fixes #434824.
+	  Original commit message from CVS:
+	  Patch by: Sjoerd Simons <sjoerd at luon dot net>
+	  * gst/rtp/gstrtpmp4vpay.c: (gst_rtp_mp4v_pay_init),
+	  (gst_rtp_mp4v_pay_empty), (gst_rtp_mp4v_pay_event):
+	  * gst/rtp/gstrtpmp4vpay.h:
+	  Handle NEWSEGMENT and FLUSH events. Fixes #434824.
+
+2007-04-30 11:15:58 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  docs/plugins/gst-plugins-good-plugins-docs.sgml: Remove v4l2src from docs, since it breaks the docs build, and the pl...
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  Remove v4l2src from docs, since it breaks the docs build, and the
+	  plugin is only built if --enable-experimental is used anyway.
+	  * docs/plugins/Makefile.am:
+	  Spaces => tab.
+
+2007-04-29 14:43:37 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstmultiudpsink.c: Add code to drop membership of a multicast group.
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c: (leave_multicast),
+	  (gst_multiudpsink_add), (gst_multiudpsink_remove):
+	  Add code to drop membership of a multicast group.
+	  * gst/udp/gstudpsink.c: (gst_udpsink_update_uri),
+	  (gst_udpsink_set_uri):
+	  Implement URI handler.
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_stream_configure_transport),
+	  (gst_rtspsrc_parse_rtpinfo):
+	  Use URI handler to make udpsink instace.
+	  Improve code to configure port and destination.
+
+2007-04-29 13:56:18 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* sys/directdraw/gstdirectdrawsink.c:
+	* sys/osxvideo/osxvideosink.m:
+	  80 char police
+	  Original commit message from CVS:
+	  80 char police
+
+2007-04-29 13:53:16 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  autogen.sh: Require automake 1.7
+	  Original commit message from CVS:
+	  * autogen.sh:
+	  Require automake 1.7
+	  * ext/alsaspdif/Makefile.am:
+	  * ext/divx/Makefile.am:
+	  * ext/ivorbis/Makefile.am:
+	  * ext/musicbrainz/Makefile.am:
+	  * ext/neon/Makefile.am:
+	  * ext/sdl/Makefile.am:
+	  * ext/swfdec/Makefile.am:
+	  * ext/theora/Makefile.am:
+	  * ext/wavpack/Makefile.am:
+	  * ext/xvid/Makefile.am:
+	  * gst/modplug/Makefile.am:
+	  Fix up Makefile.am accordingly.
+
+2007-04-29 13:49:02 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  docs/plugins/inspect/: Add jack and update.
+	  Original commit message from CVS:
+	  * docs/plugins/inspect/plugin-alsaspdif.xml:
+	  * docs/plugins/inspect/plugin-bz2.xml:
+	  * docs/plugins/inspect/plugin-cdxaparse.xml:
+	  * docs/plugins/inspect/plugin-dfbvideosink.xml:
+	  * docs/plugins/inspect/plugin-faac.xml:
+	  * docs/plugins/inspect/plugin-faad.xml:
+	  * docs/plugins/inspect/plugin-filter.xml:
+	  * docs/plugins/inspect/plugin-freeze.xml:
+	  * docs/plugins/inspect/plugin-glimagesink.xml:
+	  * docs/plugins/inspect/plugin-gsm.xml:
+	  * docs/plugins/inspect/plugin-h264parse.xml:
+	  * docs/plugins/inspect/plugin-jack.xml:
+	  * docs/plugins/inspect/plugin-mms.xml:
+	  * docs/plugins/inspect/plugin-modplug.xml:
+	  * docs/plugins/inspect/plugin-musepack.xml:
+	  * docs/plugins/inspect/plugin-musicbrainz.xml:
+	  * docs/plugins/inspect/plugin-neon.xml:
+	  * docs/plugins/inspect/plugin-nsfdec.xml:
+	  * docs/plugins/inspect/plugin-replaygain.xml:
+	  * docs/plugins/inspect/plugin-sdl.xml:
+	  * docs/plugins/inspect/plugin-soundtouch.xml:
+	  * docs/plugins/inspect/plugin-spectrum.xml:
+	  * docs/plugins/inspect/plugin-speed.xml:
+	  * docs/plugins/inspect/plugin-tta.xml:
+	  * docs/plugins/inspect/plugin-videocrop.xml:
+	  * docs/plugins/inspect/plugin-wavpack.xml:
+	  * docs/plugins/inspect/plugin-xingheader.xml:
+	  * docs/plugins/inspect/plugin-xvid.xml:
+	  Add jack and update.
+
+2007-04-29 12:19:21 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstmultiudpsink.c: Fix multicast detection.
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_add):
+	  Fix multicast detection.
+	  Don't try to join a multicast group if the address is not multicast.
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_update_uri):
+	  Small debug improvement.
+
+2007-04-27 16:44:17 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Ignore ASYNC state messages from the udpsink, it's irrelevant for the parent.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_stream_configure_transport),
+	  (gst_rtspsrc_parse_rtpinfo), (gst_rtspsrc_play),
+	  (gst_rtspsrc_handle_message):
+	  Ignore ASYNC state messages from the udpsink, it's irrelevant for the
+	  parent.
+
+2007-04-27 15:30:39 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpilbcdepay.h: Fix mode property when specified as an arg.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpilbcdepay.h:
+	  Fix mode property when specified as an arg.
+
+2007-04-26 15:08:20 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  docs/plugins/: Add documentation for osxaudio plugin.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * docs/plugins/inspect/plugin-osxaudio.xml:
+	  Add documentation for osxaudio plugin.
+
+2007-04-26 14:31:32 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  docs/plugins/: Add documentation for osxvideo
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-bad-plugins.hierarchy:
+	  * docs/plugins/inspect/plugin-osxvideo.xml:
+	  Add documentation for osxvideo
+
+2007-04-26 10:08:27 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Protect state changes with a lock.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init),
+	  (gst_rtspsrc_finalize), (gst_rtspsrc_stream_configure_transport),
+	  (gst_rtspsrc_open), (gst_rtspsrc_close),
+	  (gst_rtspsrc_parse_rtpinfo), (gst_rtspsrc_play),
+	  (gst_rtspsrc_pause):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Protect state changes with a lock.
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_create),
+	  (parse_line):
+	  * gst/rtsp/rtspconnection.h:
+	  Remove some unused stuff.
+
+2007-04-26 08:48:30 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstudpsrc.c: Handle the case where there are exactly 0 bytes to read and the ioctl did not report an error. F...
+	  Original commit message from CVS:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_create):
+	  Handle the case where there are exactly 0 bytes to read and the ioctl
+	  did not report an error. Fixes #433530.
+
+2007-04-26 08:39:49 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/wavparse/gstwavparse.*: Apply DISCONT to buffers.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_perform_seek),
+	  (gst_wavparse_stream_headers), (gst_wavparse_stream_data):
+	  * gst/wavparse/gstwavparse.h:
+	  Apply DISCONT to buffers.
+	  Only apply timestamp to the first sample after a DISCONT, too many VBR
+	  files cause random jitter in the timestamps. Fixes #433119.
+
+2007-04-25 15:55:32 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtpdec.*: Add dummy latency property to be backwards compat with rtpbin.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtpdec.c: (gst_rtp_dec_class_init),
+	  (gst_rtp_dec_init), (gst_rtp_dec_set_property),
+	  (gst_rtp_dec_get_property):
+	  * gst/rtsp/gstrtpdec.h:
+	  Add dummy latency property to be backwards compat with rtpbin.
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_class_init),
+	  (gst_rtspsrc_set_property), (gst_rtspsrc_get_property),
+	  (gst_rtspsrc_stream_configure_transport),
+	  (gst_rtspsrc_parse_rtpinfo):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Add latency property and configure in the session manager.
+	  Don't set invalid clock-base and seqnum-base on caps, some servers
+	  sometimes don't send them.
+
+2007-04-25 15:31:53 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/alpha/gstalphacolor.c: Double-check that RGB input caps are really RGBA caps (apparently the core doesn't always ...
+	  Original commit message from CVS:
+	  * gst/alpha/gstalphacolor.c: (gst_alpha_color_base_init),
+	  (gst_alpha_color_transform_caps), (gst_alpha_color_set_caps):
+	  Double-check that RGB input caps are really RGBA caps (apparently
+	  the core doesn't always catch it if those caps aren't a subset of
+	  our template caps, also see #421543). Fixes #429319 in a way.
+	  Also, don't leak the pad template in the transform_caps function.
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/alphacolor.c: (setup_alphacolor),
+	  (cleanup_alphacolor), (create_caps_rgb24), (create_caps_rgba32),
+	  (create_buffer_rgb24_3x4), (create_buffer_rgba32_3x4),
+	  (GST_START_TEST), (alphacolor_suite):
+	  Add some basic unit tests for alphacolor.
+
+2007-04-25 15:08:22 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/libpng/gstpngdec.c: If we get a fatal flow return in the loop function, first post the error message and only the...
+	  Original commit message from CVS:
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_task):
+	  If we get a fatal flow return in the loop function, first post the
+	  error message and only then send the EOS event downstream, otherwise
+	  applications might get an eos message before the error message and
+	  think everything was ok (related to #429319).
+
+2007-04-25 10:07:12 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/rtspconnection.c: Read the channel byte as an unsigned byte.
+	  Original commit message from CVS:
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_receive):
+	  Read the channel byte as an unsigned byte.
+
+2007-04-25 09:47:48 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Make sure we configure the clock_rate in the baseclass in the setcaps function. Fixes #431282.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpL16depay.c: (gst_rtp_L16_depay_set_property):
+	  * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_init),
+	  (gst_rtp_amr_depay_setcaps), (gst_rtp_amr_depay_process):
+	  * gst/rtp/gstrtpgsmdepay.c: (gst_rtp_gsm_depay_init),
+	  (gst_rtp_gsm_depay_setcaps):
+	  * gst/rtp/gstrtph263pdepay.c: (gst_rtp_h263p_depay_setcaps):
+	  * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_setcaps):
+	  * gst/rtp/gstrtpilbcdepay.c: (gst_rtp_ilbc_depay_class_init),
+	  (gst_rtp_ilbc_depay_init), (gst_rtp_ilbc_depay_setcaps),
+	  (gst_rtp_ilbc_depay_process), (gst_ilbc_depay_set_property),
+	  (gst_ilbc_depay_get_property):
+	  * gst/rtp/gstrtpmp2tdepay.c: (gst_rtp_mp2t_depay_setcaps):
+	  * gst/rtp/gstrtpmp4adepay.c:
+	  * gst/rtp/gstrtppcmadepay.c: (gst_rtp_pcma_depay_init),
+	  (gst_rtp_pcma_depay_setcaps):
+	  * gst/rtp/gstrtppcmudepay.c: (gst_rtp_pcmu_depay_init),
+	  (gst_rtp_pcmu_depay_setcaps):
+	  Make sure we configure the clock_rate in the baseclass in the setcaps
+	  function. Fixes #431282.
+
+2007-04-25 08:36:46 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Parse server address from SDP.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_finalize),
+	  (gst_rtspsrc_stream_free), (request_pt_map),
+	  (gst_rtspsrc_stream_configure_transport), (gst_rtspsrc_open):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Parse server address from SDP.
+	  Hook up a udpsink to send RTCP back to the server.
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * gst/rtsp/rtsptransport.h:
+	  Add some docs.
+
+2007-04-25 06:52:09 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/wavparse/gstwavparse.c: Make header field check conditional. Fixes #433135
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_stream_headers):
+	  Make header field check conditional. Fixes #433135
+
+2007-04-24 09:12:42 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Add minimal docs blurb to alphacolor; split out headers into separate header file for gtk-doc.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/inspect/plugin-alphacolor.xml:
+	  * gst/alpha/Makefile.am:
+	  * gst/alpha/gstalphacolor.c:
+	  * gst/alpha/gstalphacolor.h:
+	  Add minimal docs blurb to alphacolor; split out headers into
+	  separate header file for gtk-doc.
+
+2007-04-20 17:25:50 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/debug/progressreport.c: Don't try to post NULL message (in case we can't query upstream position or duration).
+	  Original commit message from CVS:
+	  * gst/debug/progressreport.c: (gst_progress_report_report):
+	  Don't try to post NULL message (in case we can't query upstream
+	  position or duration).
+
+2007-04-18 12:36:37 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/cutter/gstcutter.*: Fix some of the most obvious bugs in cutter. Now doesn't leak everything if input is silent.
+	  Original commit message from CVS:
+	  * gst/cutter/gstcutter.c: (gst_cutter_init), (gst_cutter_chain),
+	  (gst_cutter_get_caps):
+	  * gst/cutter/gstcutter.h:
+	  Fix some of the most obvious bugs in cutter. Now doesn't leak
+	  everything if input is silent.
+
+2007-04-18 09:48:25 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/wavenc/gstwavenc.*: everything else results in a invalid block align and invalid files.
+	  Original commit message from CVS:
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_create_header_buf),
+	  (gst_wavenc_sink_setcaps), (gst_wavenc_change_state):
+	  * gst/wavenc/gstwavenc.h:
+	  Wav apparently only supports width==GST_ROUND_UP(depth), everything
+	  else results in a invalid block align and invalid files.
+
+2007-04-17 16:39:02 +0000  Snaik <snaik32@gmail.com>
+
+	  gst/smpte/barboxwipes.c: Add missing break statement for BOX_HORIZONTAL case.
+	  Original commit message from CVS:
+	  Patch by: Snaik <snaik32 gmail com>
+	  * gst/smpte/barboxwipes.c: (gst_wipe_boxes_draw):
+	  Add missing break statement for BOX_HORIZONTAL case.
+
+2007-04-17 10:14:43 +0000  Vincent Torri <vtorri@univ-evry.fr>
+
+	  gst/wavparse/gstwavparse.c: Use correct format strings for integer types.
+	  Original commit message from CVS:
+	  Patch by: Vincent Torri <vtorri at univ-evry dot fr>
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_stream_headers):
+	  Use correct format strings for integer types.
+
+2007-04-17 02:51:02 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/wavparse/gstwavparse.c: Use gst_riff_create_audio_template_caps () instead of the local caps.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_base_init),
+	  (gst_wavparse_create_sourcepad):
+	  Use gst_riff_create_audio_template_caps () instead of the local caps.
+	  This makes updates of the local caps unecessary whenever libgstriff
+	  gets support for new formats.
+
+2007-04-16 21:29:40 +0000  Brian Cameron <brian.cameron@sun.com>
+
+	  sys/sunaudio/: Fix and/or update copyright attributions (#430228).
+	  Original commit message from CVS:
+	  Patch by: Brian Cameron  <brian.cameron at sun dot com>
+	  * sys/sunaudio/gstsunaudio.c:
+	  * sys/sunaudio/gstsunaudiomixer.c:
+	  * sys/sunaudio/gstsunaudiomixer.h:
+	  * sys/sunaudio/gstsunaudiomixerctrl.c:
+	  * sys/sunaudio/gstsunaudiomixerctrl.h:
+	  * sys/sunaudio/gstsunaudiomixertrack.h:
+	  * sys/sunaudio/gstsunaudiosink.c:
+	  * sys/sunaudio/gstsunaudiosink.h:
+	  * sys/sunaudio/gstsunaudiosrc.c:
+	  * sys/sunaudio/gstsunaudiosrc.h:
+	  Fix and/or update copyright attributions (#430228).
+
+2007-04-14 17:18:14 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  docs/plugins/inspect/: Add xml doc files for Windows sinks
+	  Original commit message from CVS:
+	  * docs/plugins/inspect/plugin-directdraw.xml:
+	  * docs/plugins/inspect/plugin-directsound.xml:
+	  * docs/plugins/inspect/plugin-waveform.xml:
+	  Add xml doc files for Windows sinks
+	  * win32/vs6/libgstqtdemux.dsp:
+	  * win32/vs6/libgstmpegvideoparse.dsp:
+	  * win32/vs6/gst_plugins_bad.dsw:
+	  Update projects files.
+
+2007-04-13 09:32:21 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  docs/plugins/gst-plugins-good-plugins-sections.txt: Fix docs.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  Fix docs.
+	  * gst/rtsp/URLS:
+	  Add some more example urls.
+	  * gst/rtsp/gstrtpdec.c: (gst_rtp_dec_marshal_BOXED__UINT_UINT),
+	  (gst_rtp_dec_chain_rtp):
+	  Better debugging.
+	  * gst/rtsp/gstrtspsrc.c: (request_pt_map),
+	  (gst_rtspsrc_activate_streams), (gst_rtspsrc_loop_interleaved),
+	  (gst_rtspsrc_parse_rtpinfo):
+	  Remove unused code.
+
+2007-04-13 08:19:35 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/wavparse/gstwavparse.c: Relax the audio/mpeg caps again and add FIXME: comment.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (uint64_ceiling_scale_int),
+	  (gst_wavparse_perform_seek), (gst_wavparse_stream_headers),
+	  (gst_wavparse_stream_data):
+	  Relax the audio/mpeg caps again and add FIXME: comment.
+
+2007-04-13 06:20:28 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/wavparse/gstwavparse.*: More sanity check for the header fields. Fix type for 'rate' header field.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (uint64_ceiling_scale_int),
+	  (gst_wavparse_perform_seek), (gst_wavparse_stream_headers),
+	  (gst_wavparse_stream_data):
+	  * gst/wavparse/gstwavparse.h:
+	  More sanity check for the header fields. Fix type for 'rate' header
+	  field.
+
+2007-04-12 16:06:31 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/icydemux/gsticydemux.c: If the metadata strings we get in the stream are not UTF-8, try to interpret them accordi...
+	  Original commit message from CVS:
+	  * gst/icydemux/gsticydemux.c: (notgst_tag_freeform_string_to_utf8),
+	  (gst_icydemux_unicodify):
+	  If the metadata strings we get in the stream are not UTF-8, try to
+	  interpret them according to the character encodings specified in the
+	  GST_ICY_TAG_ENCODING and GST_TAG_ENCODING environment variables, and
+	  only fall back to locale/ISO-8859-1 if those aren't set or don't
+	  work. Should fix #428901.
+
+2007-04-12 14:20:56 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtph264depay.c: Use the proper sync word for SPS and PPS.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph264depay.c:
+	  Use the proper sync word for SPS and PPS.
+
+2007-04-12 11:41:11 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  gst/rtp/Makefile.am: gst/rtp/fnv1hash.c (MASK_24, FNV1_HASH_32_INIT, FNV1_HASH_32_PRIME, fnv1_hash_32_new, fnv1_hash_...
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/fnv1hash.c (MASK_24, FNV1_HASH_32_INIT, FNV1_HASH_32_PRIME,
+	  fnv1_hash_32_new, fnv1_hash_32_update, fnv1_hash_32_to_24):
+	  * gst/rtp/fnv1hash.h (__GST_FNV1_HASH_H__):
+	  Add a simple hashing implementation that we can use to generate
+	  a 24-bit ident value based on the codebooks for vorbis and theora.
+	  * gst/rtp/gstrtptheorapay.c (gst_rtp_theora_pay_finish_headers,
+	  gst_rtp_theora_pay_handle_buffer):
+	  * gst/rtp/gstrtpvorbisdepay.c
+	  (gst_rtp_vorbis_depay_parse_configuration,
+	  gst_rtp_vorbis_depay_switch_codebook, gst_rtp_vorbis_depay_process):
+	  * gst/rtp/gstrtpvorbispay.c (gst_rtp_vorbis_pay_reset_packet,
+	  gst_rtp_vorbis_pay_init_packet, gst_rtp_vorbis_pay_flush_packet,
+	  gst_rtp_vorbis_pay_finish_headers, gst_rtp_vorbis_pay_handle_buffer):
+	  Use the hashing function, ensuring that the same codebooks result
+	  in the same ident and thus the same SDP description.
+	  Various log fixes/changes.
+
+2007-04-12 11:37:50 +0000  jerry tan <jerry.tan@sun.com>
+
+	  sys/sunaudio/gstsunaudiosrc.c: it is the application's responsibility to make sure it open the device once.
+	  Original commit message from CVS:
+	  Patch by: jerry tan <jerry dot tan at sun dot com>
+	  * sys/sunaudio/gstsunaudiosrc.c: (gst_sunaudiosrc_open):
+	  remove the call of  ioctl (fd, AUDIO_MIXER_MULTIPLE_OPEN), it is the
+	  application's responsibility to make sure it open the device once.
+	  Remove a careless error if AUDIODEV is set. Fixes #392620.
+
+2007-04-12 10:52:02 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Make timescale 32 bits again so we don't screw up the pts_offset calculations.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c:
+	  Make timescale 32 bits again so we don't screw up the pts_offset
+	  calculations.
+
+2007-04-12 08:21:28 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtpdec.*: Make backward compat with rtpbin by adding the request-pt-map signals.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtpdec.c: (gst_rtp_dec_marshal_BOXED__UINT_UINT),
+	  (gst_rtp_dec_class_init), (gst_rtp_dec_chain_rtp):
+	  * gst/rtsp/gstrtpdec.h:
+	  Make backward compat with rtpbin by adding the request-pt-map signals.
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_create_stream),
+	  (new_session_pad), (request_pt_map),
+	  (gst_rtspsrc_stream_configure_transport),
+	  (gst_rtspsrc_stream_configure_caps),
+	  (gst_rtspsrc_activate_streams):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Implement request-pt-map signals instead of setting caps on the buffers
+	  for the session manager.
+
+2007-04-11 10:25:25 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstudp.c: Register GstNetBuffer in plugin_init so that the type can be used from multiple threads without races.
+	  Original commit message from CVS:
+	  * gst/udp/gstudp.c: (plugin_init):
+	  Register GstNetBuffer in plugin_init so that the type can be used from
+	  multiple threads without races.
+
+2007-04-11 10:19:06 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  update to spec file
+	  Original commit message from CVS:
+	  update to spec file
+
+2007-04-11 09:53:38 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/: Handle version 1 mdhd atoms to get extended precision durations.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_get_duration),
+	  (qtdemux_parse_samples), (qtdemux_parse_segments),
+	  (qtdemux_parse_trak), (qtdemux_parse_tree):
+	  * gst/qtdemux/qtdemux_dump.c: (qtdemux_dump_mdhd):
+	  Handle version 1 mdhd atoms to get extended precision durations.
+	  Fixes #426972.
+
+2007-04-10 17:06:05 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpamrdepay.c: Fix depayloader clock_rate and some cleanups.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_setcaps),
+	  (gst_rtp_amr_depay_process):
+	  Fix depayloader clock_rate and some cleanups.
+	  * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_finalize),
+	  (gst_rtp_h264_depay_setcaps), (gst_rtp_h264_depay_process):
+	  * gst/rtp/gstrtph264depay.h:
+	  Don't push codec_data in the adapter because it might get flushed when
+	  we get a discont.
+	  * gst/rtp/gstrtpmp4gdepay.c: (gst_rtp_mp4g_depay_process):
+	  Handle multiple AU per packet.
+	  * gst/rtp/gstrtpsv3vdepay.c: (gst_rtp_sv3v_depay_process),
+	  (gst_rtp_sv3v_depay_plugin_init):
+	  Disable rank, this one does not work.
+	  Remove timestamping, base class does that.
+
+2007-04-10 12:01:33 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/auparse/gstauparse.c: limit caps to the formats we announce in the template
+	  Original commit message from CVS:
+	  * gst/auparse/gstauparse.c: (gst_au_parse_parse_header):
+	  limit caps to the formats we announce in the template
+	  * gst/wavparse/gstwavparse.c: (uint64_ceiling_scale_int),
+	  (gst_wavparse_perform_seek), (gst_wavparse_stream_headers),
+	  (gst_wavparse_add_src_pad), (gst_wavparse_stream_data):
+	  fix some crashers/asserts when dealing with broken files
+
+2007-04-10 10:01:14 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/: Fix some compiler warnings. Fixes #428182.
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt  <pkj at axis com>
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_massage_index):
+	  * gst/rtp/gstrtpL16depay.c:
+	  * gst/rtp/gstrtpmp4gdepay.c: (gst_rtp_mp4g_depay_process):
+	  * gst/rtp/gstrtpspeexdepay.c: (gst_rtp_speex_depay_get_mode),
+	  (gst_rtp_speex_depay_setcaps):
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_media_to_caps),
+	  (gst_rtspsrc_stream_configure_transport), (gst_rtspsrc_loop_udp):
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_init_send):
+	  Fix some compiler warnings. Fixes #428182.
+
+2007-04-06 12:54:16 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/: Morph RTPDec into something compatible with RTPBin as a fallback.
+	  Original commit message from CVS:
+	  * gst/rtsp/Makefile.am:
+	  * gst/rtsp/gstrtpdec.c: (find_session_by_id), (create_session),
+	  (free_session), (gst_rtp_dec_base_init), (gst_rtp_dec_class_init),
+	  (gst_rtp_dec_init), (gst_rtp_dec_finalize),
+	  (gst_rtp_dec_query_src), (gst_rtp_dec_chain_rtp),
+	  (gst_rtp_dec_chain_rtcp), (gst_rtp_dec_set_property),
+	  (gst_rtp_dec_get_property), (gst_rtp_dec_provide_clock),
+	  (gst_rtp_dec_change_state), (create_recv_rtp), (create_recv_rtcp),
+	  (create_rtcp), (gst_rtp_dec_request_new_pad),
+	  (gst_rtp_dec_release_pad):
+	  * gst/rtsp/gstrtpdec.h:
+	  * gst/rtsp/gstrtsp.c: (plugin_init):
+	  Morph RTPDec into something compatible with RTPBin as a fallback.
+	  Various other style fixes.
+	  * gst/rtsp/gstrtspsrc.c: (find_stream_by_id),
+	  (find_stream_by_udpsrc), (gst_rtspsrc_stream_free),
+	  (gst_rtspsrc_cleanup), (gst_rtspsrc_media_to_caps),
+	  (new_session_pad), (gst_rtspsrc_stream_configure_transport),
+	  (gst_rtspsrc_activate_streams), (gst_rtspsrc_loop_interleaved),
+	  (gst_rtspsrc_loop_udp), (gst_rtspsrc_setup_auth),
+	  (gst_rtspsrc_handle_message), (gst_rtspsrc_change_state):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Implement RTPBin session manager handling.
+	  Don't try to add empty properties to caps.
+	  Implement fallback session manager, handling.
+	  Don't combine errors from RTCP streams, just ignore them.
+	  * gst/rtsp/rtsptransport.c: (rtsp_transport_get_manager):
+	  * gst/rtsp/rtsptransport.h:
+	  Implement fallback session manager.
+	  Make RTPBin the default one when available.
+
+2007-04-05 15:05:24 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/gstrtpxqtdepay.*: Try to recover from packet loss a little better.
+	  Original commit message from CVS:
+	  * gst/qtdemux/gstrtpxqtdepay.c: (gst_rtp_xqt_depay_process),
+	  (gst_rtp_xqt_depay_change_state):
+	  * gst/qtdemux/gstrtpxqtdepay.h:
+	  Try to recover from packet loss a little better.
+
+2007-04-05 13:56:44 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmp4adepay.c: This element is ready to be autoplugged.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4adepay.c: (gst_rtp_mp4a_depay_class_init),
+	  (gst_rtp_mp4a_depay_setcaps), (gst_rtp_mp4a_depay_plugin_init):
+	  This element is ready to be autoplugged.
+
+2007-04-05 11:26:25 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/avi/gstavidemux.c: Don't leave the offsets defined by upstream element on the compressed data buffer we are pushi...
+	  Original commit message from CVS:
+	  2007-04-05  Julien MOUTTE  <julien@moutte.net>
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_process_next_entry):
+	  Don't leave the offsets defined by upstream element on the
+	  compressed data buffer we are pushing downstream. Make them
+	  GST_BUFFER_OFFSET_NONE.
+
+2007-04-04 12:39:41 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/: Don't abort on out-of-memory. Use stream-nr as unsigned integer only.
+	  Original commit message from CVS:
+	  * gst/avi/README:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query),
+	  (gst_avi_demux_parse_stream), (gst_avi_demux_parse_index),
+	  (gst_avi_demux_stream_index), (gst_avi_demux_sync),
+	  (gst_avi_demux_stream_scan), (gst_avi_demux_massage_index),
+	  (gst_avi_demux_calculate_durations_from_index),
+	  (gst_avi_demux_stream_header_push),
+	  (gst_avi_demux_stream_header_pull), (gst_avi_demux_combine_flows),
+	  (gst_avi_demux_process_next_entry), (gst_avi_demux_stream_data):
+	  Don't abort on out-of-memory. Use stream-nr as unsigned integer only.
+
+2007-04-03 09:55:45 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/smpte/barboxwipes.c:
+	  Original commit message from CVS:
+	  * gst/smpte/barboxwipes.c:
+	  Fix error as spotted by Snaik <snaik32 at gmail dot com>
+
+2007-03-30 17:19:34 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/wavparse/gstwavparse.c: Support audio/x-raw-float in wav files. This only works with plugins-base CVS, using an o...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c:
+	  Support audio/x-raw-float in wav files. This only works with
+	  plugins-base CVS, using an older version doesn't have any
+	  disadvantages though.
+
+2007-03-30 15:59:27 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Revert last change as we don't want plugins-good to depend on plugins-base CVS now.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/auparse/gstauparse.c: (gst_au_parse_reset),
+	  (gst_au_parse_parse_header), (gst_au_parse_chain):
+	  * gst/auparse/gstauparse.h:
+	  Revert last change as we don't want plugins-good to depend on
+	  plugins-base CVS now.
+
+2007-03-30 04:50:11 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/: Don't play audioconvert. As wavpack wants/outputs all samples with width==32 and depth=[1,32] accept th...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_reset),
+	  (gst_wavpack_dec_init), (gst_wavpack_dec_sink_set_caps),
+	  (gst_wavpack_dec_clip_outgoing_buffer),
+	  (gst_wavpack_dec_post_tags), (gst_wavpack_dec_chain):
+	  * ext/wavpack/gstwavpackdec.h:
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_reset),
+	  (gst_wavpack_enc_sink_set_caps), (gst_wavpack_enc_set_wp_config),
+	  (gst_wavpack_enc_chain):
+	  * ext/wavpack/gstwavpackenc.h:
+	  * ext/wavpack/gstwavpackparse.c:
+	  Don't play audioconvert. As wavpack wants/outputs all samples with
+	  width==32 and depth=[1,32] accept this and let audioconvert convert
+	  to accepted formats instead of doing it in the element for n*8 depths.
+	  This also adds support for non-n*8 depths and prevents some useless
+	  memory allocations. Fixes #421598
+	  Also add a workaround for bug #421542 in wavpackenc for now...
+	  * tests/check/elements/wavpackdec.c: (GST_START_TEST):
+	  * tests/check/elements/wavpackenc.c: (GST_START_TEST):
+	  * tests/check/elements/wavpackparse.c: (GST_START_TEST):
+	  Consider the change above in the unit tests and test if the correct
+	  caps are accepted and set. Also check for GST_BUFFER_OFFSET_END in
+	  the wavpackparse unit test.
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_init),
+	  (gst_wavpack_dec_sink_set_caps):
+	  Set caps on the src pad as soon as possible.
+	  * ext/wavpack/gstwavpackdec.h:
+	  * ext/wavpack/gstwavpackcommon.h:
+	  * ext/wavpack/gstwavpackenc.h:
+	  * ext/wavpack/gstwavpackparse.h:
+	  Fix indention. gst-indent is now called by cicl.
+
+2007-03-29 18:51:33 +0000  René Stadler <mail@renestadler.de>
+
+	  configure.ac: Require gst-plugins-base CVS for audioconvert with non-native float support and width/depth fix in libg...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Require gst-plugins-base CVS for audioconvert with non-native
+	  float support and width/depth fix in libgstriff.
+	  Patch by: René Stadler <mail at renestadler dot de>
+	  * gst/auparse/gstauparse.c: (gst_au_parse_reset),
+	  (gst_au_parse_parse_header), (gst_au_parse_chain):
+	  * gst/auparse/gstauparse.h:
+	  Don't swap the floats ourself if they're not in native endianness.
+	  Instead let audioconvert handle this. Fixes #339838.
+
+2007-03-29 14:40:35 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Flush adapter on disconts.
+	  Original commit message from CVS:
+	  * gst/rtp/gstasteriskh263.h:
+	  * gst/rtp/gstrtph263pdepay.c: (gst_rtp_h263p_depay_process),
+	  (gst_rtp_h263p_depay_change_state):
+	  * gst/rtp/gstrtph263pdepay.h:
+	  * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_class_init),
+	  (gst_rtp_h264_depay_setcaps), (gst_rtp_h264_depay_process),
+	  (gst_rtp_h264_depay_change_state):
+	  * gst/rtp/gstrtph264depay.h:
+	  * gst/rtp/gstrtpmp4adepay.c: (gst_rtp_mp4a_depay_class_init),
+	  (gst_rtp_mp4a_depay_setcaps), (gst_rtp_mp4a_depay_process):
+	  * gst/rtp/gstrtpmp4gdepay.c: (gst_rtp_mp4g_depay_process):
+	  Flush adapter on disconts.
+
+2007-03-29 14:03:21 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Use more efficient adapter and rtpbuffer methods when possible.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpL16depay.c: (gst_rtp_L16_depay_process):
+	  * gst/rtp/gstrtpgsmdepay.c: (gst_rtp_gsm_depay_process):
+	  * gst/rtp/gstrtpilbcdepay.c: (gst_rtp_ilbc_depay_process):
+	  * gst/rtp/gstrtpmp2tdepay.c: (gst_rtp_mp2t_depay_process):
+	  * gst/rtp/gstrtpmp4gdepay.c: (gst_rtp_mp4g_depay_process):
+	  * gst/rtp/gstrtpmp4gpay.c: (gst_rtp_mp4g_pay_flush):
+	  * gst/rtp/gstrtpmp4vdepay.c: (gst_rtp_mp4v_depay_setcaps),
+	  (gst_rtp_mp4v_depay_process):
+	  * gst/rtp/gstrtpmp4vpay.c: (gst_rtp_mp4v_pay_flush):
+	  * gst/rtp/gstrtpmpadepay.c: (gst_rtp_mpa_depay_process):
+	  * gst/rtp/gstrtpmpapay.c: (gst_rtp_mpa_pay_flush):
+	  * gst/rtp/gstrtpmpvdepay.c: (gst_rtp_mpv_depay_process):
+	  * gst/rtp/gstrtppcmadepay.c: (gst_rtp_pcma_depay_process):
+	  * gst/rtp/gstrtppcmudepay.c: (gst_rtp_pcmu_depay_process):
+	  * gst/rtp/gstrtpsv3vdepay.c: (gst_rtp_sv3v_depay_process):
+	  Use more efficient adapter and rtpbuffer methods when possible.
+
+2007-03-29 12:14:22 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/wavenc/gstwavenc.c: Correctly handle width!=depth input.
+	  Original commit message from CVS:
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_create_header_buf),
+	  (gst_wavenc_sink_setcaps):
+	  Correctly handle width!=depth input.
+	  * gst/wavparse/gstwavparse.c:
+	  Already export in the caps that width==8 uses unsigned samples and
+	  everything else uses signed samples.
+
+2007-03-29 09:59:23 +0000  Laurent Glayal <spglegle@yahoo.fr>
+
+	  gst/udp/: Rework the socket allocation a bit based on the sockfd argument so that it becomes usable.
+	  Original commit message from CVS:
+	  Patch by: Laurent Glayal <spglegle at yahoo dot fr>
+	  * gst/udp/gstdynudpsink.c: (gst_dynudpsink_class_init),
+	  (gst_dynudpsink_init), (gst_dynudpsink_set_property),
+	  (gst_dynudpsink_get_property), (gst_dynudpsink_init_send),
+	  (gst_dynudpsink_close):
+	  * gst/udp/gstdynudpsink.h:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init), (gst_udpsrc_init),
+	  (gst_udpsrc_create), (gst_udpsrc_set_property),
+	  (gst_udpsrc_get_property), (gst_udpsrc_start), (gst_udpsrc_stop):
+	  * gst/udp/gstudpsrc.h:
+	  Rework the socket allocation a bit based on the sockfd argument so that
+	  it becomes usable.
+	  Add a closefd property to instruct the udp elements to close the custom
+	  file descriptors when going to READY. Fixes #423304.
+	  API:GstUDPSrc::closefd property
+	  API:GstDynUDPSink::closefd property
+
+2007-03-29 08:08:49 +0000  Laurent Glayal <spglegle@yahoo.fr>
+
+	  gst/rtp/: Added H264 payloader. Fixes #423782.
+	  Original commit message from CVS:
+	  Patch by: Laurent Glayal <spglegle at yahoo dot fr>
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtph264pay.c: (gst_rtp_h264_pay_base_init),
+	  (gst_rtp_h264_pay_class_init), (gst_rtp_h264_pay_init),
+	  (gst_rtp_h264_pay_finalize), (gst_rtp_h264_pay_setcaps),
+	  (gst_rtp_h264_pay_handle_buffer), (gst_rtp_h264_pay_set_property),
+	  (gst_rtp_h264_pay_get_property), (gst_rtp_h264_pay_change_state),
+	  (gst_rtp_h264_pay_plugin_init):
+	  * gst/rtp/gstrtph264pay.h:
+	  Added H264 payloader. Fixes #423782.
+	  * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_class_init),
+	  (gst_rtp_h264_depay_setcaps), (gst_rtp_h264_depay_process):
+	  Small fixes.
+
+2007-03-28 22:27:36 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/wavparse/gstwavparse.c: Actually support depths from 1 to 32, not only 8 to 32.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c:
+	  Actually support depths from 1 to 32, not only 8 to 32.
+
+2007-03-28 22:23:43 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/wavparse/gstwavparse.c: Add support for wav files containing audio/x-raw-int with random depths between 1 and 32 ...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c:
+	  Add support for wav files containing audio/x-raw-int with random
+	  depths between 1 and 32 bits.
+
+2007-03-28 18:40:12 +0000  Stefan Kost <ensonic@users.sf.net>
+
+	  gst/rtp/: Added MP4A-LATM depayloader. Fixes #417792.
+	  Original commit message from CVS:
+	  Based on patch by: Stefan Kost  <ensonic@users.sf.net>
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpmp4adepay.c: (gst_rtp_mp4a_depay_base_init),
+	  (gst_rtp_mp4a_depay_class_init), (gst_rtp_mp4a_depay_init),
+	  (gst_rtp_mp4a_depay_finalize), (gst_rtp_mp4a_depay_setcaps),
+	  (gst_rtp_mp4a_depay_process), (gst_rtp_mp4a_depay_set_property),
+	  (gst_rtp_mp4a_depay_get_property),
+	  (gst_rtp_mp4a_depay_change_state),
+	  (gst_rtp_mp4a_depay_plugin_init):
+	  * gst/rtp/gstrtpmp4adepay.h:
+	  Added MP4A-LATM depayloader. Fixes #417792.
+	  * gst/rtp/gstrtpmp4vdepay.c: (gst_rtp_mp4v_depay_setcaps),
+	  (gst_rtp_mp4v_depay_process):
+	  Fixup depayloader, setting codec_data, using more efficient adaptor and
+	  rtpbuffer handling.
+	  * gst/rtsp/URLS:
+	  Add url to test above.
+
+2007-03-28 15:17:27 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/: Process 'ctts' atoms, which are present in AVC ISO files (.mov files with h264 video).
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_prepare_current_sample),
+	  (gst_qtdemux_chain), (qtdemux_parse_samples):
+	  * gst/qtdemux/qtdemux_dump.c: (qtdemux_dump_ctts):
+	  * gst/qtdemux/qtdemux_dump.h:
+	  * gst/qtdemux/qtdemux_fourcc.h:
+	  * gst/qtdemux/qtdemux_types.c:
+	  Process 'ctts' atoms, which are present in AVC ISO files (.mov files
+	  with h264 video).
+	  Use the offset present in 'ctts' to calculate the PTS for each packet
+	  and set the PTS on outgoing buffers.
+	  Fixes #423283
+
+2007-03-25 15:34:42 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Handle default clock-rates for static payload types, rearrange stuff so that the rtpmap field ...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (find_stream_by_setup),
+	  (gst_rtspsrc_create_stream), (gst_rtspsrc_stream_free),
+	  (get_default_rate_for_pt), (gst_rtspsrc_parse_rtpmap),
+	  (gst_rtspsrc_media_to_caps),
+	  (gst_rtspsrc_stream_configure_transport),
+	  (gst_rtspsrc_stream_configure_caps),
+	  (gst_rtspsrc_activate_streams), (gst_rtspsrc_parse_rtpinfo):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Handle default clock-rates for static payload types, rearrange stuff so
+	  that the rtpmap field in the sdp can override the defaults.
+	  Parse RTP-Info field to get the seqnum and timebase fields that should
+	  go in the caps.
+	  Delay configuring caps after we got the RTP-Info from the PLAY reply from
+	  the server.
+
+2007-03-24 19:46:59 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/interleave/deinterleave.c: Remove 'channel-positions' field when munging input caps into 1-channel output caps (I...
+	  Original commit message from CVS:
+	  * gst/interleave/deinterleave.c: (gst_deinterleave_sink_setcaps):
+	  Remove 'channel-positions' field when munging input caps into
+	  1-channel output caps (I guess technically we should set the
+	  position for each channel on the output caps if it's non-NONE,
+	  but I'll save that as a task for another day).
+
+2007-03-22 22:14:29 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/interleave/deinterleave.c: Don't leak input buffer in chain function; maintain our own list of source pads - ther...
+	  Original commit message from CVS:
+	  * gst/interleave/deinterleave.c: (gst_deinterleave_add_new_pads),
+	  (gst_deinterleave_remove_pads), (gst_deinterleave_process),
+	  (gst_deinterleave_chain):
+	  Don't leak input buffer in chain function; maintain our own list of
+	  source pads - there are no guarantees about the order of the list
+	  in the GstElement struct, and we want a very specific order; lastly,
+	  some more debugging.
+
+2007-03-22 16:25:56 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackparse.c: Revert last commit, preventing infinite plugging loops with ranks is no clean solution...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_plugin_init):
+	  Revert last commit, preventing infinite plugging loops with ranks
+	  is no clean solution and in general there's no reason why one wants
+	  to parse framed wavpack data again.
+
+2007-03-22 15:52:51 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackenc.c: Send the new segment event in time format instead of bytes. This allows "wavpackenc ! wa...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_push_block):
+	  Send the new segment event in time format instead of bytes. This
+	  allows "wavpackenc ! wavpackdec ! someaudiosink" pipelines.
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_plugin_init):
+	  Accept framed and non-framed input, wavpackparse doesn't care. To
+	  prevent "wavpackparse ! wavpackparse ! ..." pipelines lower the
+	  rank of wavpackparse by one. This allows "wavpackenc ! wavpackparse !
+	  ..." pipelines.
+
+2007-03-22 11:08:03 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackdec.c: Revert to use gst_pad_alloc_buffer() here. We can and should use it.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_chain):
+	  Revert to use gst_pad_alloc_buffer() here. We can and should use it.
+	  Thanks to Jan and Mike for noticing my mistake.
+
+2007-03-22 09:44:17 +0000  Christophe Dehais <christophe.dehais@gmail.com>
+
+	  ext/gconf/gconf.c: Accept complex pipeline descriptions as an audio profile instead of just a single element. Fixes #...
+	  Original commit message from CVS:
+	  Patch by: Christophe Dehais <christophe dot dehais at gmail dot com>
+	  * ext/gconf/gconf.c: (gst_gconf_render_bin_with_default):
+	  Accept complex pipeline descriptions as an audio profile instead of just
+	  a single element. Fixes #420658.
+
+2007-03-22 00:17:41 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackenc.*: Put the write helpers into the GstWavpackEnc struct directly and not as a pointer to sav...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_class_init),
+	  (gst_wavpack_enc_init), (gst_wavpack_enc_chain),
+	  (gst_wavpack_enc_rewrite_first_block):
+	  * ext/wavpack/gstwavpackenc.h:
+	  Put the write helpers into the GstWavpackEnc struct directly and not
+	  as a pointer to save two small, but useless mallocs. This also makes
+	  it possible to drop the finalize method.
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_push_buffer):
+	  For consistency reasons also set GST_BUFFER_OFFSET_END on the outgoing
+	  buffers the same way wavpackenc does it.
+
+2007-03-21 23:50:09 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackdec.c: Don't use gst_pad_alloc_buffer() as we might clip the buffer later and
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_chain):
+	  Don't use gst_pad_alloc_buffer() as we might clip the buffer later and
+	  BaseTransform-based elements will likely break because of wrong
+	  unit-size. Also plug a possible memleak that happens when decoding
+	  fails for some reason.
+
+2007-03-21 11:49:32 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/apetag/gsttagdemux.c: Rename registered type in preparation of GstTagDemux moving to
+	  Original commit message from CVS:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_get_type):
+	  Rename registered type in preparation of GstTagDemux moving to
+	  -base at some point in the future.
+
+2007-03-19 10:29:19 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/wavparse/gstwavparse.c: Streaming mode fixes: don't unref buffer we don't own any longer; remove bogus adapter fl...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_stream_headers):
+	  Streaming mode fixes: don't unref buffer we don't own any longer;
+	  remove bogus adapter flush. Fixes #419338.
+
+2007-03-18 04:21:28 +0000  David Schleef <ds@schleef.org>
+
+	  REQUIREMENTS: Change the format to key/value, add a bunch of information, remove a bunch of requirements that are for...
+	  Original commit message from CVS:
+	  * REQUIREMENTS: Change the format to key/value, add a bunch of
+	  information, remove a bunch of requirements that are for
+	  other GStreamer packages.
+
+2007-03-18 02:00:54 +0000  David Schleef <ds@schleef.org>
+
+	  REQUIREMENTS: Fix a few things.  This file really needs a good once-over.
+	  Original commit message from CVS:
+	  * REQUIREMENTS: Fix a few things.  This file really needs a
+	  good once-over.
+
+2007-03-16 18:38:18 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  sys/osxvideo/osxvideosink.m: Fix previous commit, we want to pass the NSView in the message.
+	  Original commit message from CVS:
+	  * sys/osxvideo/osxvideosink.m:
+	  Fix previous commit, we want to pass the NSView in the message.
+
+2007-03-16 16:27:20 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  sys/osxvideo/osxvideosink.m: Emit 'have-ns-view' message when working in embedded mode. The message will contain a po...
+	  Original commit message from CVS:
+	  * sys/osxvideo/osxvideosink.m:
+	  Emit 'have-ns-view' message when working in embedded mode. The message
+	  will contain a pointer to the newly created NSView.
+
+2007-03-16 09:57:40 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/equalizer/gstiirequalizer10bands.c: A 10 band EQ should be initialized to 1 bands and not to 3.
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer10bands.c:
+	  (gst_iir_equalizer_10bands_init):
+	  A 10 band EQ should be initialized to 1 bands and not to 3.
+
+2007-03-15 12:05:01 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  sys/Makefile.am: Don't forget to distribute the sys/osxaudio/ directory.
+	  Original commit message from CVS:
+	  * sys/Makefile.am:
+	  Don't forget to distribute the sys/osxaudio/ directory.
+
+2007-03-15 11:39:53 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  Activate osxaudio in gst-plugins-good with proper build setup.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * sys/Makefile.am:
+	  * sys/osxaudio/Makefile.am:
+	  * sys/osxaudio/gstosxaudio.c:
+	  * sys/osxaudio/gstosxaudiosink.c:
+	  (gst_osx_audio_sink_osxelement_do_init), (gst_osx_audio_sink_init),
+	  (gst_osx_audio_sink_getcaps),
+	  (gst_osx_audio_sink_create_ringbuffer), (plugin_init):
+	  * sys/osxaudio/gstosxaudiosrc.c:
+	  (gst_osx_audio_src_osxelement_do_init), (gst_osx_audio_src_init),
+	  (gst_osx_audio_src_create_ringbuffer):
+	  * sys/osxaudio/gstosxringbuffer.c: (gst_osx_ring_buffer_get_type),
+	  (gst_osx_ring_buffer_class_init), (gst_osx_ring_buffer_init),
+	  (gst_osx_ring_buffer_acquire), (gst_osx_ring_buffer_start),
+	  (gst_osx_ring_buffer_pause), (gst_osx_ring_buffer_stop):
+	  * sys/osxaudio/gstosxringbuffer.h:
+	  Activate osxaudio in gst-plugins-good with proper build setup.
+	  Add inlined documentation.
+	  Fix debug statements
+	  Fix ringbuffer when pausing.
+	  Fixes #323471
+
+2007-03-14 22:21:26 +0000  Philippe Kalaf <philippe.kalaf@collabora.co.uk>
+
+	  gst/rtp/: Ported mulaw and alaw payloaders to use new base class
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtppcmapay.c:
+	  * gst/rtp/gstrtppcmapay.h:
+	  * gst/rtp/gstrtppcmupay.c:
+	  * gst/rtp/gstrtppcmupay.h:
+	  Ported mulaw and alaw payloaders to use new base class
+
+2007-03-14 16:30:19 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  sys/osxvideo/: Fix leaks when running a NSApp.
+	  Original commit message from CVS:
+	  * sys/osxvideo/cocoawindow.h:
+	  * sys/osxvideo/cocoawindow.m:
+	  * sys/osxvideo/osxvideosink.h:
+	  * sys/osxvideo/osxvideosink.m:
+	  Fix leaks when running a NSApp.
+	  Accept any kind of resolutions.
+	  Works in fullscreen. Can maximize.
+	  Only thing left before being able to move this to -good is documentation
+	  and embedded window support.
+
+2007-03-14 15:25:10 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  po/: Update translations.
+	  Original commit message from CVS:
+	  * po/af.po:
+	  * po/az.po:
+	  * po/cs.po:
+	  * po/en_GB.po:
+	  * po/it.po:
+	  * po/nl.po:
+	  * po/or.po:
+	  * po/sq.po:
+	  * po/sr.po:
+	  * po/sv.po:
+	  * po/uk.po:
+	  * po/vi.po:
+	  Update translations.
+
+2007-03-14 14:49:45 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Fix string replace error (AG_AG_GST_* => AG_GST_*).
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Fix string replace error (AG_AG_GST_* => AG_GST_*).
+
+2007-03-14 14:48:08 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/equalizer/: Add 3 and 10 band version and add missing gst_object_sync_values.
+	  Original commit message from CVS:
+	  * gst/equalizer/Makefile.am:
+	  * gst/equalizer/gstiirequalizer.c: (_do_init),
+	  (gst_iir_equalizer_band_set_property),
+	  (gst_iir_equalizer_band_class_init),
+	  (gst_iir_equalizer_band_get_type),
+	  (gst_iir_equalizer_child_proxy_get_child_by_index),
+	  (gst_iir_equalizer_child_proxy_get_children_count),
+	  (gst_iir_equalizer_child_proxy_interface_init), (setup_filter),
+	  (gst_iir_equalizer_compute_frequencies),
+	  (gst_iir_equalizer_transform_ip), (plugin_init):
+	  * gst/equalizer/gstiirequalizer10bands.c:
+	  (gst_iir_equalizer_10bands_base_init),
+	  (gst_iir_equalizer_10bands_class_init),
+	  (gst_iir_equalizer_10bands_init),
+	  (gst_iir_equalizer_10bands_set_property),
+	  (gst_iir_equalizer_10bands_get_property):
+	  * gst/equalizer/gstiirequalizer10bands.h:
+	  * gst/equalizer/gstiirequalizer3bands.c:
+	  (gst_iir_equalizer_3bands_base_init),
+	  (gst_iir_equalizer_3bands_class_init),
+	  (gst_iir_equalizer_3bands_init),
+	  (gst_iir_equalizer_3bands_set_property),
+	  (gst_iir_equalizer_3bands_get_property):
+	  * gst/equalizer/gstiirequalizer3bands.h:
+	  * gst/equalizer/gstiirequalizernbands.c:
+	  (gst_iir_equalizer_nbands_base_init),
+	  (gst_iir_equalizer_nbands_init):
+	  Add 3 and 10 band version and add missing gst_object_sync_values.
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_event),
+	  (gst_spectrum_transform_ip):
+	  Add some comments about float support.
+
+2007-03-12 17:56:54 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/apetag/gsttagdemux.c: Fix handling of -1 values for start and stop values when seeking, and SEEK_CUR+SEEK_END her...
+	  Original commit message from CVS:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_srcpad_event):
+	  Fix handling of -1 values for start and stop values when seeking,
+	  and SEEK_CUR+SEEK_END here as well.
+
+2007-03-12 17:24:23 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/id3demux/gstid3demux.c: Fix handling of -1 values for start and stop values when seeking, and SEEK_CUR+SEEK_END.
+	  Original commit message from CVS:
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_srcpad_event):
+	  Fix handling of -1 values for start and stop values when seeking,
+	  and SEEK_CUR+SEEK_END.
+
+2007-03-12 15:49:02 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	  I'm too lazy to comment this
+	  Original commit message from CVS:
+	  Add Patch by: line for wim, since he's away
+
+2007-03-12 13:28:29 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/id3v2frames.c: Fix parsing of ID3 v2.2.0 PIC frames. Only in version >= 2.3.0 is the image format a vari...
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (parse_picture_frame):
+	  Fix parsing of ID3 v2.2.0 PIC frames. Only in version >= 2.3.0 is
+	  the image format a variable-length NUL-terminated string; in
+	  versions before that the image format is a fixed-length string of
+	  3 characters (see #348644 for a sample tag).
+	  Also make supplied mime type lower-case and fix up 'jpg' to 'jpeg'.
+
+2007-03-11 22:23:04 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  sys/directdraw/gstdirectdrawsink.*: Handle display mode changes during playback.
+	  Original commit message from CVS:
+	  * sys/directdraw/gstdirectdrawsink.c:
+	  * sys/directdraw/gstdirectdrawsink.h:
+	  Handle display mode changes during playback.
+
+2007-03-10 16:07:31 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  win32/MANIFEST: Add new project files to MANIFEST.
+	  Original commit message from CVS:
+	  * win32/MANIFEST:
+	  Add new project files to MANIFEST.
+	  * win32/vs6/libgstaudiofx.dsp:
+	  * win32/vs6/libgstrtp.dsp:
+	  * win32/vs6/libgstrtsp.dsp:
+	  Update project files.
+
+2007-03-10 12:30:48 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Printf format fixes; also add some missing quotes in translated strings. Fixes #416728 and #416727.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_subindex),
+	  (gst_avi_demux_parse_index):
+	  * sys/v4l2/v4l2_calls.c: (gst_v4l2_fill_lists):
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_grab_frame):
+	  Printf format fixes; also add some missing quotes in translated
+	  strings. Fixes #416728 and #416727.
+
+2007-03-09 20:12:08 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/autodetect/gstautoaudiosink.c: Tim and I can't think of any reason the child audio sink needs to be set back to N...
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautoaudiosink.c: (gst_auto_audio_sink_find_best):
+	  Tim and I can't think of any reason the child audio sink needs to
+	  be set back to NULL after successfully determining that it can
+	  reach READY - it gets immediately set back to READY by the caller
+	  anyway, causing an unnecessary close/open of any audio devices
+	  involved.
+
+2007-03-09 19:51:27 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  po/: Add ja.po file from #377306.
+	  Original commit message from CVS:
+	  * po/LINGUAS:
+	  * po/ja.po:
+	  Add ja.po file from #377306.
+
+2007-03-09 19:44:30 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/sunaudio/: Actually translate sunaudio mixer track labels instead of just marking the strings as translatable (#3...
+	  Original commit message from CVS:
+	  * sys/sunaudio/gstsunaudio.c: (plugin_init):
+	  * sys/sunaudio/gstsunaudiomixertrack.c:
+	  (gst_sunaudiomixer_track_new):
+	  Actually translate sunaudio mixer track labels instead of just
+	  marking the strings as translatable (#377306); clean up weird
+	  label string mapping code that serves no apparent purpose. Also
+	  set the 'untranslated-label' property when creating mixer tracks
+	  if the GstMixerTrack base class supports this.
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/sunaudio.c: (GST_START_TEST),
+	  (sunaudio_suite):
+	  Very minimalistic unit test for sunaudiomixer element (compiles, but not
+	  actually tested on a system where sunaudiomixer is available).
+
+2007-03-09 18:49:37 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  tests/check/Makefile.am: Re-enable the states test and see if it works on the buildbots.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Re-enable the states test and see if it works on the buildbots.
+
+2007-03-09 17:32:32 +0000  Wim Taymans <wim@fluendo.com>
+
+	  ext/dv/gstdvdec.*: Infer pixel-aspect-ratio from the video frame format if it isn't provided by the container, as hap...
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdec.c: (gst_dvdec_init), (gst_dvdec_sink_setcaps),
+	  (gst_dvdec_src_negotiate), (gst_dvdec_chain),
+	  (gst_dvdec_change_state):
+	  * ext/dv/gstdvdec.h:
+	  Infer pixel-aspect-ratio from the video frame format if it isn't
+	  provided by the container, as happens when playing DV from AVI
+	  or Quicktime containers.
+	  Patch by: Wim Taymans <wim@fluendo.com>
+	  Fixes #380944
+
+2007-03-09 17:05:17 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: When activated, remove the udpsrc timeout, we have dataflow and timeouts will later be handled...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_activate_streams):
+	  When activated, remove the udpsrc timeout, we have dataflow and timeouts
+	  will later be handled by the jitterbuffer.
+
+2007-03-09 16:53:39 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/taglib/gstid3v2mux.cc: Add write support for GST_TAG_MUSICBRAINZ_SORTNAME (TSOP) tag.
+	  Original commit message from CVS:
+	  * ext/taglib/gstid3v2mux.cc:
+	  Add write support for GST_TAG_MUSICBRAINZ_SORTNAME (TSOP) tag.
+	  Fixes #414496.
+
+2007-03-09 15:04:45 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: Fix stream position reporting after a seek. Fixes #416445.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_push_event), (gst_avi_demux_do_seek),
+	  (gst_avi_demux_process_next_entry), (gst_avi_demux_stream_data),
+	  (gst_avi_demux_chain):
+	  Fix stream position reporting after a seek. Fixes #416445.
+
+2007-03-09 08:58:26 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/equalizer/: Refactor plugin into a base class and a first subclass (nband eq). The nband eq uses GstChildProxy an...
+	  Original commit message from CVS:
+	  * gst/equalizer/Makefile.am:
+	  * gst/equalizer/gstiirequalizer.c: (_do_init),
+	  (gst_iir_equalizer_band_set_property),
+	  (gst_iir_equalizer_band_get_property),
+	  (gst_iir_equalizer_band_class_init),
+	  (gst_iir_equalizer_band_get_type),
+	  (gst_iir_equalizer_child_proxy_get_child_by_index),
+	  (gst_iir_equalizer_child_proxy_get_children_count),
+	  (gst_iir_equalizer_child_proxy_interface_init),
+	  (gst_iir_equalizer_base_init), (gst_iir_equalizer_class_init),
+	  (gst_iir_equalizer_finalize), (setup_filter),
+	  (gst_iir_equalizer_compute_frequencies),
+	  (gst_iir_equalizer_set_property), (gst_iir_equalizer_get_property),
+	  (gst_iir_equalizer_setup), (plugin_init):
+	  * gst/equalizer/gstiirequalizer.h:
+	  * gst/equalizer/gstiirequalizernbands.c:
+	  (gst_iir_equalizer_nbands_base_init),
+	  (gst_iir_equalizer_nbands_class_init),
+	  (gst_iir_equalizer_nbands_init),
+	  (gst_iir_equalizer_nbands_set_property),
+	  (gst_iir_equalizer_nbands_get_property):
+	  * gst/equalizer/gstiirequalizernbands.h:
+	  Refactor plugin into a base class and a first subclass (nband eq). The
+	  nband eq uses GstChildProxy and is controlable. More subclasses will
+	  follow.
+
+2007-03-08 16:01:42 +0000  René Stadler <mail@renestadler.de>
+
+	  gst/avi/gstavidemux.c: Make avidemux accept optional header chunks in any order.
+	  Original commit message from CVS:
+	  Patch by: René Stadler <mail at renestadler dot de>
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_push_event), (gst_avi_demux_process_next_entry),
+	  (gst_avi_demux_stream_data), (gst_avi_demux_chain):
+	  Make avidemux accept optional header chunks in any order.
+	  Fixes #415446.
+
+2007-03-08 12:23:57 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  tests/check/Makefile.am: Disable the states check until the remaining Valgrind errors are fixed or suppressed.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Disable the states check until the remaining Valgrind errors
+	  are fixed or suppressed.
+
+2007-03-08 10:24:43 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/elements/.cvsignore: Add audiodynamic check to .cvsignore
+	  Original commit message from CVS:
+	  * tests/check/elements/.cvsignore:
+	  Add audiodynamic check to .cvsignore
+
+2007-03-08 10:02:12 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/: Add new audiodynamic element which can act as a compressor or expander. Supported are hard-knee and sof...
+	  Original commit message from CVS:
+	  reviewed by: Stefan Kost  <ensonic@users.sf.net>
+	  * gst/audiofx/Makefile.am:
+	  * gst/audiofx/audiodynamic.c:
+	  (gst_audio_dynamic_characteristics_get_type),
+	  (gst_audio_dynamic_mode_get_type),
+	  (gst_audio_dynamic_set_process_function),
+	  (gst_audio_dynamic_base_init), (gst_audio_dynamic_class_init),
+	  (gst_audio_dynamic_init), (gst_audio_dynamic_set_property),
+	  (gst_audio_dynamic_get_property), (gst_audio_dynamic_setup),
+	  (gst_audio_dynamic_transform_hard_knee_compressor_int),
+	  (gst_audio_dynamic_transform_hard_knee_compressor_float),
+	  (gst_audio_dynamic_transform_soft_knee_compressor_int),
+	  (gst_audio_dynamic_transform_soft_knee_compressor_float),
+	  (gst_audio_dynamic_transform_hard_knee_expander_int),
+	  (gst_audio_dynamic_transform_hard_knee_expander_float),
+	  (gst_audio_dynamic_transform_soft_knee_expander_int),
+	  (gst_audio_dynamic_transform_soft_knee_expander_float),
+	  (gst_audio_dynamic_transform_ip):
+	  * gst/audiofx/audiodynamic.h:
+	  * gst/audiofx/audiofx.c: (plugin_init):
+	  Add new audiodynamic element which can act as a compressor or
+	  expander. Supported are hard-knee and soft-knee operation modes with
+	  user-specified ratio and threshold.
+	  Attack and release parameters are not yet implemented but will follow.
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  Integrate audiodynamic into the docs.
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/audiodynamic.c: (setup_dynamic),
+	  (cleanup_dynamic), (GST_START_TEST), (dynamic_suite), (main):
+	  Add unit test for audiodynamic.
+
+2007-03-07 19:48:03 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/raw1394/gstdv1394src.c: Free handles that we allocated when exiting via the error paths.
+	  Original commit message from CVS:
+	  * ext/raw1394/gstdv1394src.c: (gst_dv1394src_start):
+	  Free handles that we allocated when exiting via the error paths.
+
+2007-03-07 12:07:07 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/: Use a general wavpack debug category for common code.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpack.c: (plugin_init):
+	  * ext/wavpack/gstwavpackcommon.c:
+	  Use a general wavpack debug category for common code.
+	  * ext/wavpack/gstwavpackstreamreader.c:
+	  (gst_wavpack_stream_reader_set_pos_abs),
+	  (gst_wavpack_stream_reader_set_pos_rel),
+	  (gst_wavpack_stream_reader_write_bytes):
+	  Use the general wavpack debug category here too and add debug
+	  output to the functions that should not be called at all by
+	  the wavpack library.
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_plugin_init):
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_plugin_init):
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_plugin_init):
+	  Change debugging category names to conform to the conventions.
+
+2007-03-07 11:37:23 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.*: Share qtdemux debug category across all files, otherwise all debugging in files other than qtd...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c:
+	  * gst/qtdemux/qtdemux.h:
+	  Share qtdemux debug category across all files, otherwise all debugging
+	  in files other than qtdemux.c would end up in the default category.
+
+2007-03-07 11:24:05 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/level/gstlevel.*: Resolve message timestamps against the playback segment.
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c: (gst_level_class_init),
+	  (gst_level_set_caps), (gst_level_start), (gst_level_event),
+	  (gst_level_transform_ip):
+	  * gst/level/gstlevel.h:
+	  Resolve message timestamps against the playback segment.
+
+2007-03-07 11:23:20 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/gstspectrum.*: One FIXME less, by resolving message timestamps against the playback segment.
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_start),
+	  (gst_spectrum_event), (gst_spectrum_transform_ip):
+	  * gst/spectrum/gstspectrum.h:
+	  One FIXME less, by resolving message timestamps against the playback
+	  segment.
+
+2007-03-06 23:21:41 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* ChangeLog:
+	  Fix ChangeLog message
+	  Original commit message from CVS:
+	  Fix ChangeLog message
+
+2007-03-06 23:19:30 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/gstid3demux.c: Don't leak caps: make gst_id3demux_add_srcpad() not take ownership of the caps passed to ...
+	  Original commit message from CVS:
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_add_srcpad),
+	  (gst_id3demux_sink_activate):
+	  Don't leak caps: make gst_id3demux_add_srcpad() not take ownership of the
+	  caps passed to it (previouslly one code path assumes it takes ownership
+	  while another one assumes it doesn't).
+	  * configure.ac:
+	  * tests/files/Makefile.am:
+	  * tests/files/id3-407349-1.tag:
+	  * tests/files/id3-407349-2.tag:
+	  Add directory where data for unit tests can be stored.
+	  * tests/Makefile.am:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/id3demux.c: (pad_added_cb), (error_cb),
+	  (read_tags_from_file), (run_check_for_file),
+	  (check_date_1977_06_23), (GST_START_TEST), (id3demux_suite):
+	  Add unit test for id3demux, and in particular for bug #407349. Only
+	  testing pull-mode for now; push mode doesn't work yet because the test
+	  files are smaller than ID3_TYPE_FIND_MIN_SIZE.
+
+2007-03-06 22:14:59 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/check/Makefile.am: Add missing backslash at end of line.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Add missing backslash at end of line.
+
+2007-03-06 18:36:09 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	* common:
+	  Trigger rebuild.
+	  Original commit message from CVS:
+	  Trigger rebuild.
+
+2007-03-06 18:16:49 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/: Do not convert obsolete TDA/TDAT frames to TDRC frames, otherwise the four-digit number will be interp...
+	  Original commit message from CVS:
+	  * gst/id3demux/id3tags.c: (id3demux_id3v2_frames_to_tag_list):
+	  * gst/id3demux/id3tags.h:
+	  * gst/id3demux/id3v2frames.c: (id3demux_id3v2_parse_frame),
+	  (parse_obsolete_tdat_frame):
+	  Do not convert obsolete TDA/TDAT frames to TDRC frames, otherwise
+	  the four-digit number will be interpreted as a year, whereas it is
+	  month and day in DDMM format. Instead, parse TDAT frames and fix up
+	  the date in the GST_TAG_DATE tag later if we also extracted a year.
+	  Fixes #407349.
+
+2007-03-06 14:53:04 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/gconf/gstswitchsink.c: Fix up the dispose logic so it doesn't leak, and fix setting of the child state so that we...
+	  Original commit message from CVS:
+	  * ext/gconf/gstswitchsink.c: (gst_switch_sink_dispose),
+	  (gst_switch_commit_new_kid):
+	  Fix up the dispose logic so it doesn't leak, and fix setting of
+	  the child state so that we don't set a child to our current state
+	  just as we are changing it to something else.
+
+2007-03-06 13:57:55 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/spectrum/gstspectrum.c: Fix and cleanup default property values.
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_class_init),
+	  (gst_spectrum_init), (gst_spectrum_set_property),
+	  (gst_spectrum_transform_ip):
+	  Fix and cleanup default property values.
+	  Add FIXMEs for stuff that looks rather wrong.
+
+2007-03-06 13:21:23 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/goom/gstgoom.*: Document, fix and improve goom adapter behaviour.
+	  Original commit message from CVS:
+	  * gst/goom/gstgoom.c: (gst_goom_src_setcaps), (get_buffer),
+	  (gst_goom_chain):
+	  * gst/goom/gstgoom.h:
+	  Document, fix and improve goom adapter behaviour.
+	  Fixes #407006.
+
+2007-03-05 18:43:29 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/esd/esdsink.c: Unref static pad template after using it.
+	  Original commit message from CVS:
+	  * ext/esd/esdsink.c: (gst_esdsink_open):
+	  Unref static pad template after using it.
+
+2007-03-05 17:17:04 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/gconf/gstswitchsink.c: Fix up the reference counting of the child elements.
+	  Original commit message from CVS:
+	  * ext/gconf/gstswitchsink.c: (gst_switch_sink_dispose),
+	  (gst_switch_commit_new_kid):
+	  Fix up the reference counting of the child elements.
+
+2007-03-05 17:08:32 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Fix encoding-name case.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4gpay.c: (gst_rtp_mp4g_pay_setcaps):
+	  * gst/rtp/gstrtptheorapay.c: (gst_rtp_theora_pay_finish_headers):
+	  * gst/rtp/gstrtpvorbispay.c: (gst_rtp_vorbis_pay_finish_headers):
+	  Fix encoding-name case.
+
+2007-03-05 16:39:29 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Fix speex (de)payloader. Fixes #358040.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpspeexdepay.c: (gst_rtp_speex_depay_class_init),
+	  (gst_rtp_speex_depay_get_mode), (gst_rtp_speex_depay_setcaps),
+	  (gst_rtp_speex_depay_process):
+	  * gst/rtp/gstrtpspeexpay.c: (gst_rtp_speex_pay_base_init),
+	  (gst_rtp_speex_pay_class_init), (gst_rtp_speex_pay_setcaps),
+	  (gst_rtp_speex_pay_parse_ident), (gst_rtp_speex_pay_handle_buffer),
+	  (gst_rtp_speex_pay_change_state):
+	  * gst/rtp/gstrtpspeexpay.h:
+	  Fix speex (de)payloader. Fixes #358040.
+
+2007-03-05 15:42:58 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/gconf/gstswitchsink.c: Install fakesink in NULL by fixing some broken logic. This obviates the need to manually s...
+	  Original commit message from CVS:
+	  * ext/gconf/gstswitchsink.c: (gst_switch_sink_reset),
+	  (gst_switch_commit_new_kid), (gst_switch_sink_set_child):
+	  Install fakesink in NULL by fixing some broken logic. This obviates
+	  the need to manually set _IS_SINK.
+	  Add some comments and remove a little cruft while I'm at it.
+
+2007-03-05 14:46:43 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/gconf/gstswitchsink.c: Mark us as a sink when we have no fakesink in NULL. Fixes #414887.
+	  Original commit message from CVS:
+	  * ext/gconf/gstswitchsink.c: (gst_switch_sink_reset):
+	  Mark us as a sink when we have no fakesink in NULL. Fixes #414887.
+
+2007-03-05 08:30:52 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/: Remove two obsolete and confusing comments.
+	  Original commit message from CVS:
+	  * gst/spectrum/demo-audiotest.c: (message_handler):
+	  * gst/spectrum/demo-osssrc.c: (message_handler):
+	  Remove two obsolete and confusing comments.
+
+2007-03-04 18:52:12 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  po/POTFILES.in: Update.
+	  Original commit message from CVS:
+	  * po/POTFILES.in:
+	  Update.
+
+2007-03-04 17:33:34 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  tests/check/Makefile.am: Gah! Also disable gconfvideosink from the tests, otherwise it will instantiate autovideosink...
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Gah! Also disable gconfvideosink from the tests, otherwise
+	  it will instantiate autovideosink, and dfbvideosink and
+	  leak on the buildbots.
+
+2007-03-04 17:13:19 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/cdio/gstcdiocddasrc.c: Make sure we always destroy our libcdio handle.
+	  Original commit message from CVS:
+	  * ext/cdio/gstcdiocddasrc.c: (gst_cdio_cdda_src_open),
+	  (gst_cdio_cdda_src_finalize):
+	  Make sure we always destroy our libcdio handle.
+
+2007-03-04 17:05:58 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  tests/check/Makefile.am: Disable autovideosink so the buildbots don't barf over memory leaked in the directfb sink.
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Disable autovideosink so the buildbots don't barf over memory
+	  leaked in the directfb sink.
+
+2007-03-04 15:28:30 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  sys/ximage/gstximagesrc.c: Chain up in dispose
+	  Original commit message from CVS:
+	  * sys/ximage/gstximagesrc.c: (gst_ximage_src_dispose):
+	  Chain up in dispose
+
+2007-03-04 15:07:15 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/multipart/multipartdemux.c: Use gst_pad_new_from_static_template instead of static_pad_template_get+pad_new.
+	  Original commit message from CVS:
+	  * gst/multipart/multipartdemux.c: (gst_multipart_demux_init),
+	  (gst_multipart_find_pad_by_mime):
+	  Use gst_pad_new_from_static_template instead of
+	  static_pad_template_get+pad_new.
+
+2007-03-04 14:56:53 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  sys/ximage/gstximagesrc.c: Catch the case where no clock has been set.
+	  Original commit message from CVS:
+	  * sys/ximage/gstximagesrc.c: (gst_ximage_src_create):
+	  Catch the case where no clock has been set.
+
+2007-03-04 13:52:03 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Fix a bunch of leaks shown by the newly-added states test.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacenc.c: (gst_flac_enc_finalize):
+	  * ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_class_init),
+	  (gst_gconf_audio_sink_dispose), (gst_gconf_audio_sink_finalize):
+	  * ext/gconf/gstgconfaudiosrc.c: (gst_gconf_audio_src_base_init),
+	  (gst_gconf_audio_src_class_init), (gst_gconf_audio_src_dispose),
+	  (gst_gconf_audio_src_finalize), (do_toggle_element):
+	  * ext/gconf/gstgconfvideosink.c: (gst_gconf_video_sink_base_init),
+	  (gst_gconf_video_sink_class_init), (gst_gconf_video_sink_finalize),
+	  (do_toggle_element):
+	  * ext/gconf/gstgconfvideosrc.c: (gst_gconf_video_src_base_init),
+	  (gst_gconf_video_src_class_init), (gst_gconf_video_src_dispose),
+	  (gst_gconf_video_src_finalize), (do_toggle_element):
+	  * ext/gconf/gstswitchsink.c: (gst_switch_sink_class_init),
+	  (gst_switch_sink_reset), (gst_switch_sink_set_child):
+	  * ext/hal/gsthalaudiosink.c: (gst_hal_audio_sink_base_init):
+	  * ext/hal/gsthalaudiosrc.c: (gst_hal_audio_src_base_init):
+	  * ext/shout2/gstshout2.c: (gst_shout2send_class_init),
+	  (gst_shout2send_init), (gst_shout2send_finalize):
+	  * gst/debug/testplugin.c: (gst_test_class_init),
+	  (gst_test_finalize):
+	  * gst/flx/gstflxdec.c: (gst_flxdec_class_init),
+	  (gst_flxdec_dispose):
+	  * gst/multipart/multipartmux.c: (gst_multipart_mux_finalize):
+	  * gst/rtp/gstrtpmp4gpay.c: (gst_rtp_mp4g_pay_finalize):
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init),
+	  (gst_rtspsrc_finalize):
+	  * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_free_context):
+	  * gst/rtsp/rtspextwms.h:
+	  * gst/smpte/gstsmpte.c: (gst_smpte_class_init),
+	  (gst_smpte_finalize):
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_finalize):
+	  * gst/udp/gstudpsink.c: (gst_udpsink_class_init),
+	  (gst_udpsink_finalize):
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_dispose),
+	  (gst_wavparse_sink_activate):
+	  * sys/oss/gstosssink.c: (gst_oss_sink_finalise):
+	  * sys/oss/gstosssrc.c: (gst_oss_src_class_init),
+	  (gst_oss_src_finalize):
+	  * sys/v4l2/gstv4l2object.c: (gst_v4l2_object_destroy):
+	  * sys/v4l2/gstv4l2object.h:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init),
+	  (gst_v4l2src_finalize):
+	  * sys/ximage/gstximagesrc.c: (gst_ximage_src_ximage_get):
+	  Fix a bunch of leaks shown by the newly-added states test.
+
+2007-03-04 13:41:00 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/dv/gstdvdec.c: Use gst_pad_new_from_static_template instead of static_pad_template_get+pad_new.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdec.c: (gst_dvdec_init):
+	  Use gst_pad_new_from_static_template instead of
+	  static_pad_template_get+pad_new.
+
+2007-03-03 13:06:21 +0000  Loïc Minier <lool+gnome@via.ecp.fr>
+
+	  Don't mix tabs and spaces (#414168).
+	  Original commit message from CVS:
+	  Patch by: Loïc Minier <lool+gnome at via ecp fr>
+	  * ext/libcaca/Makefile.am:
+	  * gst/debug/Makefile.am:
+	  Don't mix tabs and spaces (#414168).
+
+2007-03-02 21:35:11 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/check/generic/.cvsignore: Ignore files to please buildbot.
+	  Original commit message from CVS:
+	  * tests/check/generic/.cvsignore:
+	  Ignore files to please buildbot.
+
+2007-03-02 21:01:19 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/wavparse/gstwavparse.c: Unbreak my previous commit (swapped nominator & denominator). Tim, thanks for spotting.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_stream_headers),
+	  (gst_wavparse_stream_data):
+	  Unbreak my previous commit (swapped nominator & denominator). Tim,
+	  thanks for spotting.
+
+2007-03-02 16:08:17 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/cdio/gstcdiocddasrc.c: Small code cleanups.
+	  Original commit message from CVS:
+	  * ext/cdio/gstcdiocddasrc.c: (gst_cdio_cdda_src_probe_devices),
+	  (gst_cdio_cdda_src_read_sector), (gst_cdio_cdda_src_open),
+	  (gst_cdio_cdda_src_finalize):
+	  Small code cleanups.
+	  Don't use pad_alloc as the base class cannot deal with the error codes.
+
+2007-03-02 13:40:06 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstudpsrc.c: Fix doc.
+	  Original commit message from CVS:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init),
+	  (gst_udpsrc_create):
+	  Fix doc.
+
+2007-03-02 13:29:25 +0000  René Stadler <mail@renestadler.de>
+
+	  gst/wavparse/gstwavparse.c: Handle rounding better to not drop last sample frame. Fixes #356692
+	  Original commit message from CVS:
+	  Patch by: René Stadler <mail@renestadler.de>
+	  * gst/wavparse/gstwavparse.c: (uint64_ceiling_scale_int),
+	  (gst_wavparse_perform_seek), (gst_wavparse_stream_headers),
+	  (gst_wavparse_stream_data):
+	  Handle rounding better to not drop last sample frame. Fixes #356692
+
+2007-03-02 13:19:57 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  tests/check/Makefile.am: Disable cacasink from the states check too - it also calls exit(1) on us when it can't find ...
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Disable cacasink from the states check too - it also calls exit(1)
+	  on us when it can't find a terminal to talk to.
+
+2007-03-02 12:56:13 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  gst/udp/gstudpsrc.*: Add support to strip proprietary headers. Fixes #350296.
+	  Original commit message from CVS:
+	  Patch by: Thijs Vermeir <thijsvermeir at gmail dot com>
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init), (gst_udpsrc_init),
+	  (gst_udpsrc_create), (gst_udpsrc_set_property),
+	  (gst_udpsrc_get_property):
+	  * gst/udp/gstudpsrc.h:
+	  Add support to strip proprietary headers. Fixes #350296.
+
+2007-03-02 12:52:56 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmp2tdepay.c: Fix compilation.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp2tdepay.c: (gst_rtp_mp2t_depay_process):
+	  Fix compilation.
+
+2007-03-02 12:16:16 +0000  Thijs Vermeir <thijsvermeir@gmail.com>
+
+	  gst/rtp/gstrtpmp2tdepay.*: Add support to strip off proprietary headers. Fixes #350278.
+	  Original commit message from CVS:
+	  Patch by: Thijs Vermeir <thijsvermeir at gmail dot com>
+	  * gst/rtp/gstrtpmp2tdepay.c: (gst_rtp_mp2t_depay_class_init),
+	  (gst_rtp_mp2t_depay_init), (gst_rtp_mp2t_depay_process),
+	  (gst_rtp_mp2t_depay_set_property),
+	  (gst_rtp_mp2t_depay_get_property):
+	  * gst/rtp/gstrtpmp2tdepay.h:
+	  Add support to strip off proprietary headers. Fixes #350278.
+
+2007-03-02 11:22:35 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/hal/hal.c: Fix compilation.
+	  Original commit message from CVS:
+	  * ext/hal/hal.c:
+	  Fix compilation.
+
+2007-03-02 10:54:49 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/sunaudio/gstsunaudiosrc.*: Remove device-name from GstSunAudioSrc. Fixes #412597.
+	  Original commit message from CVS:
+	  * sys/sunaudio/gstsunaudiosrc.c: (gst_sunaudiosrc_class_init),
+	  (gst_sunaudiosrc_init), (gst_sunaudiosrc_get_property),
+	  (gst_sunaudiosrc_open):
+	  * sys/sunaudio/gstsunaudiosrc.h:
+	  Remove device-name from GstSunAudioSrc. Fixes #412597.
+
+2007-03-01 21:50:36 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/hal/: Having NULL as UDI previously selected the default sink/src. Change this back but mention it in the debug o...
+	  Original commit message from CVS:
+	  * ext/hal/gsthalaudiosink.c: (do_toggle_element):
+	  * ext/hal/gsthalaudiosrc.c: (do_toggle_element):
+	  Having NULL as UDI previously selected the default sink/src. Change
+	  this back but mention it in the debug output.
+	  * ext/hal/hal.c: (gst_hal_get_alsa_element),
+	  (gst_hal_get_oss_element), (gst_hal_get_string),
+	  (gst_hal_render_bin_from_udi), (gst_hal_get_audio_sink),
+	  (gst_hal_get_audio_src):
+	  * ext/hal/hal.h:
+	  Refactor a bit, check all error conditions, greatly improve debugging
+	  and fix some possible memory leaks. Also implement OSS support
+	  and allow specifying an UDI that points to a real device. For this the
+	  child device which supports ALSA (preferred) or OSS is used.
+	  As a side effect this makes it impossible now to get a alsasink in
+	  halaudiosrc and a alsasrc in halaudiosink.
+
+2007-03-01 18:47:28 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Errors from the udp sources are not fatal unless all of them are in error.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (find_stream_by_channel),
+	  (find_stream_by_udpsrc), (gst_rtspsrc_handle_message):
+	  Errors from the udp sources are not fatal unless all of them are in
+	  error.
+
+2007-03-01 18:14:42 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  tests/check/Makefile.am: Disable aasink in the states test. I suspect this is the element that is calling exit(1) whe...
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Disable aasink in the states test. I suspect this is the element that
+	  is calling exit(1) when it can't proceed.
+
+2007-03-01 17:26:30 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  tests/check/Makefile.am: Draw plugins in from the build tree sys/ dir, rather than picking up the already installed v...
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Draw plugins in from the build tree sys/ dir, rather than picking
+	  up the already installed versions.
+
+2007-03-01 10:44:36 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  sys/ximage/gstximagesrc.c: Error out correctly when getting xcontext fails.
+	  Original commit message from CVS:
+	  2007-03-01  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * sys/ximage/gstximagesrc.c: (gst_ximage_src_open_display):
+	  Error out correctly when getting xcontext fails.
+
+2007-03-01 09:29:34 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtpdec.c: Make state change to PAUSED NO_PREROLL because that's what it will be in the future and rtspsrc...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtpdec.c: (gst_rtpdec_change_state):
+	  Make state change to PAUSED NO_PREROLL because that's what it will be in
+	  the future and rtspsrc relies on it.
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_stream_configure_transport),
+	  (gst_rtspsrc_change_state):
+	  Don't error out when we don't get an error from the state change
+	  function.
+
+2007-03-01 01:48:59 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/hal/: Check if the device UDI is set before trying to query HAL about it and give a useful error message if it wa...
+	  Original commit message from CVS:
+	  * ext/hal/gsthalaudiosink.c: (do_toggle_element):
+	  * ext/hal/gsthalaudiosrc.c: (do_toggle_element):
+	  Check if the device UDI is set before trying to query HAL
+	  about it and give a useful error message if it wasn't set.
+	  * ext/hal/hal.c: (gst_hal_get_string):
+	  Don't query HAL for NULL UDIs. Passing NULL as UDI to HAL
+	  gives an assertion failure in D-Bus when running with
+	  DBUS_FATAL_WARNINGS=1.
+
+2007-02-28 19:29:42 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* win32/common/config.h:
+	  update config to trunk
+	  Original commit message from CVS:
+	  update config to trunk
+
+2007-02-28 19:29:25 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  configure.ac: Convert to new AG_GST style.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Convert to new AG_GST style.
+
+2007-02-28 12:59:43 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  tests/check/: add test for states
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  * tests/check/generic/states.c: (GST_START_TEST), (states_suite):
+	  add test for states
+
+2007-02-28 10:58:10 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  tests/check/elements/.cvsignore: Add new videofilter check to .cvsignore.
+	  Original commit message from CVS:
+	  * tests/check/elements/.cvsignore:
+	  Add new videofilter check to .cvsignore.
+
+2007-02-28 10:54:55 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: Fix combined flow return. Fixes #412608.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_combine_flows),
+	  (gst_avi_demux_process_next_entry), (gst_avi_demux_stream_data),
+	  (gst_avi_demux_loop), (gst_avi_demux_chain):
+	  Fix combined flow return. Fixes #412608.
+
+2007-02-28 10:41:14 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/videofilter/Makefile.am: Dist header..
+	  Original commit message from CVS:
+	  * gst/videofilter/Makefile.am:
+	  Dist header..
+
+2007-02-28 10:29:08 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/videofilter/gstgamma.h: Add header too.
+	  Original commit message from CVS:
+	  * gst/videofilter/gstgamma.h:
+	  Add header too.
+
+2007-02-28 10:17:15 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  gst/videofilter/: Port gamma filter to 0.10. Fixes #412704.
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts <manauw at skynet be>
+	  * gst/videofilter/Makefile.am:
+	  * gst/videofilter/gstgamma.c: (gst_gamma_base_init),
+	  (gst_gamma_class_init), (gst_gamma_init), (gst_gamma_set_property),
+	  (gst_gamma_get_property), (gst_gamma_calculate_tables),
+	  (oil_tablelookup_u8), (gst_gamma_set_caps),
+	  (gst_gamma_planar411_ip), (gst_gamma_transform_ip), (plugin_init):
+	  Port gamma filter to 0.10. Fixes #412704.
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/videofilter.c: (setup_filter),
+	  (cleanup_filter), (check_filter), (GST_START_TEST),
+	  (videobalance_suite), (videoflip_suite), (gamma_suite), (main):
+	  Add unit tests for videofilters.
+
+2007-02-28 10:06:27 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/URLS: Add another interesting test url.
+	  Original commit message from CVS:
+	  * gst/rtsp/URLS:
+	  Add another interesting test url.
+	  * gst/rtsp/rtspmessage.c: (rtsp_message_get_header):
+	  Don't allow getting header fields from data packets.
+
+2007-02-27 23:43:08 +0000  Michael Smith <msmith@xiph.org>
+
+	  ext/shout2/gstshout2.*: Add a property for username.
+	  Original commit message from CVS:
+	  * ext/shout2/gstshout2.c: (gst_shout2send_class_init),
+	  (gst_shout2send_init), (gst_shout2send_start),
+	  (gst_shout2send_set_property), (gst_shout2send_get_property):
+	  * ext/shout2/gstshout2.h:
+	  Add a property for username.
+
+2007-02-27 12:02:03 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* sys/directdraw/gstdirectdrawplugin.c:
+	* sys/directdraw/gstdirectdrawsink.c:
+	* sys/directdraw/gstdirectdrawsink.h:
+	* sys/directsound/gstdirectsoundplugin.c:
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/directsound/gstdirectsoundsink.h:
+	* sys/osxvideo/cocoawindow.h:
+	* sys/osxvideo/cocoawindow.m:
+	* sys/osxvideo/osxvideosink.h:
+	* sys/osxvideo/osxvideosink.m:
+	  update copyright statements
+	  Original commit message from CVS:
+	  update copyright statements
+
+2007-02-27 11:59:21 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* ChangeLog:
+	* sys/osxaudio/gstosxaudio.c:
+	* sys/osxaudio/gstosxaudioelement.c:
+	* sys/osxaudio/gstosxaudioelement.h:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosink.h:
+	  update copyright statement
+	  Original commit message from CVS:
+	  update copyright statement
+
+2007-02-27 11:30:19 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  sys/osxvideo/: Disable the cocoa event loop since it's a huge memory leak. Should only matter if the sink isn't used ...
+	  Original commit message from CVS:
+	  * sys/osxvideo/cocoawindow.h:
+	  * sys/osxvideo/cocoawindow.m:
+	  * sys/osxvideo/osxvideosink.h:
+	  * sys/osxvideo/osxvideosink.m:
+	  Disable the cocoa event loop since it's a huge memory leak. Should only
+	  matter if the sink isn't used within an NSApp (which has already got
+	  a coca event loop).
+	  Remove all unused code.
+
+2007-02-26 12:07:14 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/rtsp/Makefile.am: Fix make check too.
+	  Original commit message from CVS:
+	  * gst/rtsp/Makefile.am:
+	  Fix make check too.
+
+2007-02-26 10:00:28 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/rtsp/base64.*: Commit missing files for base64 encoding.
+	  Original commit message from CVS:
+	  * gst/rtsp/base64.c: (util_base64_encode):
+	  * gst/rtsp/base64.h:
+	  Commit missing files for base64 encoding.
+
+2007-02-24 22:57:49 +0000  Loïc Minier <lool+gnome@via.ecp.fr>
+
+	  Fix build with LDFLAGS='-Wl,-z,defs' (#410997)
+	  Original commit message from CVS:
+	  Patch by: Loïc Minier <lool+gnome at via ecp fr>
+	  * configure.ac:
+	  * ext/annodex/Makefile.am:
+	  * ext/jpeg/Makefile.am:
+	  * ext/speex/Makefile.am:
+	  * gst/alpha/Makefile.am:
+	  * gst/cutter/Makefile.am:
+	  * gst/debug/Makefile.am:
+	  * gst/effectv/Makefile.am:
+	  * gst/goom/Makefile.am:
+	  * gst/level/Makefile.am:
+	  * gst/smpte/Makefile.am:
+	  * gst/videofilter/Makefile.am:
+	  Fix build with LDFLAGS='-Wl,-z,defs' (#410997)
+
+2007-02-24 22:52:47 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Fix build with LDFLAGS='-Wl,-z,defs'.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * ext/gsm/Makefile.am:
+	  * ext/ladspa/Makefile.am:
+	  * ext/wavpack/Makefile.am:
+	  * gst/equalizer/Makefile.am:
+	  * gst/filter/Makefile.am:
+	  * gst/mve/Makefile.am:
+	  * gst/nsf/Makefile.am:
+	  * gst/replaygain/Makefile.am:
+	  * gst/speed/Makefile.am:
+	  Fix build with LDFLAGS='-Wl,-z,defs'.
+
+2007-02-23 19:12:52 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/rtsp/: g_base64_encode is a GLib 2.12 function. Use an equivalent taken from icecast to replace it. Relicensed fr...
+	  Original commit message from CVS:
+	  * gst/rtsp/Makefile.am:
+	  * gst/rtsp/rtspconnection.c: (append_auth_header),
+	  (rtsp_connection_send), (rtsp_connection_set_auth):
+	  g_base64_encode is a GLib 2.12 function. Use an equivalent taken
+	  from icecast to replace it. Relicensed from GPL courtesy of Mike
+	  Smith.
+
+2007-02-23 18:12:27 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/rtsp/: Implement simple Basic Authentication support so that urls like rtsp://user:pass@hostname/rtspstream work ...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_finalize),
+	  (gst_rtspsrc_create_stream), (rtsp_auth_method_to_string),
+	  (gst_rtspsrc_parse_auth_hdr), (gst_rtspsrc_setup_auth),
+	  (gst_rtspsrc_send), (gst_rtspsrc_try_send), (gst_rtspsrc_open),
+	  (gst_rtspsrc_close), (gst_rtspsrc_play), (gst_rtspsrc_pause),
+	  (gst_rtspsrc_uri_set_uri):
+	  * gst/rtsp/gstrtspsrc.h:
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_create),
+	  (append_auth_header), (rtsp_connection_send),
+	  (rtsp_connection_free), (rtsp_connection_set_auth):
+	  * gst/rtsp/rtspconnection.h:
+	  * gst/rtsp/rtspdefs.h:
+	  * gst/rtsp/rtspurl.c: (rtsp_url_get_request_uri):
+	  * gst/rtsp/rtspurl.h:
+	  Implement simple Basic Authentication support so that urls like
+	  rtsp://user:pass@hostname/rtspstream work on hosts that require
+	  authentication.
+
+2007-02-22 17:53:26 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2tuner.c:
+	* sys/v4l2/v4l2_calls.c:
+	  Fix segfault when oppening a radio device.
+	  Original commit message from CVS:
+	  Fix segfault when oppening a radio device.
+
+2007-02-22 14:35:28 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Fix level for multi-channel case.
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c: (gst_level_set_caps),
+	  (gst_level_transform_ip):
+	  * sys/v4l2/README:
+	  * tests/check/elements/level.c: (GST_START_TEST):
+	  Fix level for multi-channel case.
+
+2007-02-21 10:18:12 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/level/gstlevel.*: Use function pointer for process function and add process functions for float audio.
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c: (gst_level_init), (gst_level_set_caps),
+	  (gst_level_transform_ip):
+	  * gst/level/gstlevel.h:
+	  Use function pointer for process function and add process functions
+	  for float audio.
+
+2007-02-20 21:34:00 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  sys/directsound/gstdirectsoundsink.*: Remove include of unused headers.
+	  Original commit message from CVS:
+	  * sys/directsound/gstdirectsoundsink.c:
+	  * sys/directsound/gstdirectsoundsink.h:
+	  Remove include of unused headers.
+	  * sys/waveform/gstwaveformplugin.c:
+	  * sys/waveform/gstwaveformsink.c:
+	  * sys/waveform/gstwaveformsink.h:
+	  * win32/vs6/libgstwaveform.dsp:
+	  Add a new waveform plugin which includes an audio sink
+	  element using the WaveForm win32 API.
+	  * win32/MANIFEST:
+	  Add the new project file form waveform plugin.
+
+2007-02-19 12:22:43 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/v4l2/v4l2src_calls.c: Readd GST_ELEMENT_ERROR if we can't reenque buffers after EIO, fixes #407369
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list),
+	  (gst_v4l2src_grab_frame), (gst_v4l2src_set_capture),
+	  (gst_v4l2src_capture_init):
+	  Readd GST_ELEMENT_ERROR if we can't reenque buffers after EIO,
+	  fixes #407369
+
+2007-02-18 18:00:51 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  sys/directdraw/: Prepare the plugin to move to good:
+	  Original commit message from CVS:
+	  * sys/directdraw/gstdirectdrawplugin.c:
+	  * sys/directdraw/gstdirectdrawsink.c:
+	  * sys/directdraw/gstdirectdrawsink.h:
+	  Prepare the plugin to move to good:
+	  Remove unused/untested code (rendering to an extern surface,
+	  yuv format rendering).Use GST_(DEBUG/*)_OBJECT macros
+	  Rename all functions from gst_directdrawsink to gst_directdraw_sink.
+	  Add gtk doc section
+	  Fix a bug in gst_directdraw_sink_show_frame, memcpy line by line
+	  respecting destination surface stride.
+	  * sys/directsound/gstdirectsoundplugin.c:
+	  * sys/directsound/gstdirectsoundsink.c:
+	  * sys/directsound/gstdirectsoundsink.h:
+	  Prepare the plugin to move to good:
+	  Rename all functions from gst_directsoundsink to gst_directsound_sink.
+	  Add gtk doc section
+	  * win32/common/config.h.in:
+	  * win32/MANIFEST:
+	  Add config.h.in
+
+2007-02-18 13:24:26 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Added simple mpeg transport stream payloader.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpmp2tpay.c: (gst_rtp_mp2t_pay_base_init),
+	  (gst_rtp_mp2t_pay_class_init), (gst_rtp_mp2t_pay_init),
+	  (gst_rtp_mp2t_pay_setcaps), (gst_rtp_mp2t_pay_handle_buffer),
+	  (gst_rtp_mp2t_pay_plugin_init):
+	  * gst/rtp/gstrtpmp2tpay.h:
+	  Added simple mpeg transport stream payloader.
+
+2007-02-16 12:32:01 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/URLS: Add example H264 rtsp url.
+	  Original commit message from CVS:
+	  * gst/rtsp/URLS:
+	  Add example H264 rtsp url.
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_media_to_caps),
+	  (gst_rtspsrc_handle_message), (gst_rtspsrc_change_state):
+	  Don't convert values to lowercase or we might mess up base64 encoded
+	  properties.
+
+2007-02-16 12:30:22 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/README: Fix case of string params.
+	  Original commit message from CVS:
+	  * gst/rtp/README:
+	  Fix case of string params.
+	  * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_class_init),
+	  (gst_rtp_h264_depay_setcaps), (gst_rtp_h264_depay_process):
+	  Fix depayloader, support more packet types.
+	  Add sync codes to make sure the packetizer can do its job.
+	  * gst/rtp/gstrtpmp4gdepay.c:
+	  * gst/rtp/gstrtpmp4gpay.c:
+	  * gst/rtp/gstrtpmpvdepay.c: (gst_rtp_mpv_depay_process):
+	  Fix caps case again.
+
+2007-02-15 12:26:28 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtph264depay.c: Set right caps on output buffers.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_process):
+	  Set right caps on output buffers.
+
+2007-02-14 17:04:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/sdpmessage.c: Clear stack allocated SDPMedia struct before calling _init() on it.
+	  Original commit message from CVS:
+	  * gst/rtsp/sdpmessage.c: (sdp_parse_line):
+	  As spotted by: Peter Kjellerstedt  <pkj at axis com>:
+	  Clear stack allocated SDPMedia struct before calling _init() on it.
+	  Clarify this in the docs as well.
+
+2007-02-14 17:01:25 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/gconf/gstgconfaudiosink.c: Don't reset the profile when going switching states, as it makes the element non-reusa...
+	  Original commit message from CVS:
+	  * ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_reset),
+	  (do_change_child):
+	  Don't reset the profile when going switching states, as it makes
+	  the element non-reusable.
+
+2007-02-14 15:24:50 +0000  jp.liu <jp_liu@astrocom.cn>
+
+	  gst/rtsp/sdpmessage.*: Fix memory management of SDP messages. Fixes #407793.
+	  Original commit message from CVS:
+	  * gst/rtsp/sdpmessage.c: (sdp_origin_init), (sdp_connection_init),
+	  (sdp_bandwidth_init), (sdp_time_init), (sdp_zone_init),
+	  (sdp_key_init), (sdp_attribute_init), (sdp_message_init),
+	  (sdp_message_uninit), (sdp_message_free), (sdp_media_init),
+	  (sdp_media_uninit), (sdp_media_free), (sdp_message_add_media),
+	  (sdp_parse_line):
+	  * gst/rtsp/sdpmessage.h:
+	  Based on patch by: jp.liu <jp_liu at astrocom dot cn>
+	  Fix memory management of SDP messages. Fixes #407793.
+
+2007-02-14 12:07:01 +0000  zhangfei gao <gaozhangfei@yahoo.com.cn>
+
+	  gst/avi/gstavimux.c: Allow muxing video/x-h264 (was already in the caps). Fixes #407780.
+	  Original commit message from CVS:
+	  Patch by: zhangfei gao <gaozhangfei@yahoo.com.cn>
+	  * gst/avi/gstavimux.c: (gst_avi_mux_vidsink_set_caps):
+	  Allow muxing video/x-h264 (was already in the caps). Fixes #407780.
+
+2007-02-14 10:09:12 +0000  jp.liu <jp_liu@astrocom.cn>
+
+	  gst/rtsp/rtspurl.c: Fix parsing of password field in url. Fixes #407797.
+	  Original commit message from CVS:
+	  Patch by: jp.liu <jp_liu at astrocom dot cn>
+	  * gst/rtsp/rtspurl.c: (rtsp_url_parse):
+	  Fix parsing of password field in url. Fixes #407797.
+
+2007-02-14 09:55:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/wavparse/gstwavparse.*: Update docs.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_class_init),
+	  (gst_wavparse_reset), (gst_wavparse_init),
+	  (gst_wavparse_destroy_sourcepad), (gst_wavparse_fmt),
+	  (gst_wavparse_parse_file_header), (gst_wavparse_stream_init),
+	  (gst_wavparse_perform_seek), (gst_wavparse_peek_chunk_info),
+	  (gst_wavparse_stream_headers), (gst_wavparse_parse_stream_init),
+	  (gst_wavparse_add_src_pad), (gst_wavparse_stream_data),
+	  (gst_wavparse_loop), (gst_wavparse_chain),
+	  (gst_wavparse_pad_convert), (gst_wavparse_pad_query),
+	  (gst_wavparse_srcpad_event), (gst_wavparse_change_state),
+	  (plugin_init):
+	  * gst/wavparse/gstwavparse.h:
+	  Update docs.
+	  Use boilerplate.
+	  Various code cleanups.
+	  When the bitrate is not known (bps == 0 or compressed formats) let
+	  downstream element guestimate the duration and position and don't
+	  generate timestamps or durations. Fixes #405213.
+	  Fix EOS and ERROR conditions in chain mode, we just need to forward the
+	  error flowreturn upstream.
+
+2007-02-13 16:01:29 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Re-factor the gconfaudiosink into a "GstSwitchSink" base class and a child that implements the GConf key monitoring. ...
+	  Original commit message from CVS:
+	  * ext/gconf/Makefile.am:
+	  * ext/gconf/gconf.c: (gst_gconf_get_string),
+	  (gst_gconf_get_key_for_sink_profile), (gst_gconf_set_string),
+	  (gst_gconf_render_bin_with_default):
+	  * ext/gconf/gconf.h:
+	  * ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_base_init),
+	  (gst_gconf_audio_sink_reset), (gst_gconf_audio_sink_init),
+	  (gst_gconf_audio_sink_dispose), (do_change_child),
+	  (gst_gconf_switch_profile), (gst_gconf_audio_sink_set_property),
+	  (cb_change_child), (gst_gconf_audio_sink_change_state):
+	  * ext/gconf/gstgconfaudiosink.h:
+	  * ext/gconf/gstswitchsink.c: (gst_switch_sink_base_init),
+	  (gst_switch_sink_class_init), (gst_switch_sink_reset),
+	  (gst_switch_sink_init), (gst_switch_sink_dispose),
+	  (gst_switch_commit_new_kid), (gst_switch_sink_set_child),
+	  (gst_switch_sink_set_property), (gst_switch_sink_handle_event),
+	  (gst_switch_sink_get_property), (gst_switch_sink_change_state):
+	  * ext/gconf/gstswitchsink.h:
+	  * gst/autodetect/gstautoaudiosink.c:
+	  (gst_auto_audio_sink_class_init), (gst_auto_audio_sink_dispose),
+	  (gst_auto_audio_sink_clear_kid), (gst_auto_audio_sink_reset),
+	  (gst_auto_audio_sink_detect):
+	  * gst/autodetect/gstautovideosink.c:
+	  (gst_auto_video_sink_class_init), (gst_auto_video_sink_dispose),
+	  (gst_auto_video_sink_clear_kid), (gst_auto_video_sink_reset),
+	  (gst_auto_video_sink_detect):
+	  Re-factor the gconfaudiosink into a "GstSwitchSink" base class
+	  and a child that implements the GConf key monitoring. The end goal of
+	  this is an audio sink that can be changed on the fly, but at the
+	  moment it still only changes on the next READY transition.
+
+2007-02-13 11:57:18 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.c: Put debug stuff into #ifndef GST_DISABLE_DEBUG #endif
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query),
+	  (gst_avi_demux_parse_index), (gst_avi_demux_stream_index),
+	  (gst_avi_demux_sync), (gst_avi_demux_massage_index),
+	  (gst_avi_demux_calculate_durations_from_index),
+	  (gst_avi_demux_push_event), (gst_avi_demux_stream_header_pull),
+	  (gst_avi_demux_process_next_entry), (gst_avi_demux_stream_data),
+	  (gst_avi_demux_loop):
+	  Put debug stuff into #ifndef GST_DISABLE_DEBUG #endif
+
+2007-02-13 09:46:26 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Add crossreferences to glib/gobject/gstream docs.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * docs/plugins/Makefile.am:
+	  Add crossreferences to glib/gobject/gstream docs.
+
+2007-02-12 23:35:16 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/monoscope/: Fix copy'n'paste-o in docs chunk. Also add some missing CFLAGS (but no LIBS, since we only use define...
+	  Original commit message from CVS:
+	  * gst/monoscope/Makefile.am:
+	  * gst/monoscope/gstmonoscope.c:
+	  Fix copy'n'paste-o in docs chunk. Also add some missing CFLAGS
+	  (but no LIBS, since we only use defines from the headers).
+
+2007-02-12 23:27:31 +0000  Jonathan Matthew <jonathan@kaolin.wh9.net>
+
+	  gst/wavparse/gstwavparse.c: Fix massive memory leak when operating in streaming mode due to
+	  Original commit message from CVS:
+	  Based on patch by: Jonathan Matthew  <jonathan at kaolin wh9 net>
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_parse_stream_init),
+	  (gst_wavparse_stream_data):
+	  Fix massive memory leak when operating in streaming mode due to
+	  GST_BUFFER_MALLOCDATA() not being set on newly-created buffers.
+	  Fixes #407057.
+
+2007-02-12 15:29:44 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.*: Save some memory (8%) by repacking the index entry structure (more to come). Add more FIXMEs t...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_class_init),
+	  (gst_avi_demux_reset), (gst_avi_demux_index_entry_for_time),
+	  (gst_avi_demux_handle_src_query), (gst_avi_demux_parse_superindex),
+	  (gst_avi_demux_parse_subindex), (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_parse_index), (gst_avi_demux_stream_index),
+	  (gst_avi_demux_sync), (gst_avi_demux_next_data_buffer),
+	  (gst_avi_demux_stream_scan), (gst_avi_demux_massage_index),
+	  (gst_avi_demux_calculate_durations_from_index),
+	  (gst_avi_demux_push_event), (gst_avi_demux_stream_header_pull),
+	  (gst_avi_demux_do_seek), (gst_avi_demux_process_next_entry),
+	  (gst_avi_demux_stream_data), (gst_avi_demux_loop):
+	  * gst/avi/gstavidemux.h:
+	  Save some memory (8%) by repacking the index entry structure (more to
+	  come). Add more FIXMEs to questionable parts.
+
+2007-02-12 12:57:22 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/v4l2/: More FIXME comments and messaging changes.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_v4l2fourcc_to_caps),
+	  (gst_v4l2src_get_caps):
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list),
+	  (gst_v4l2src_grab_frame), (gst_v4l2src_set_capture),
+	  (gst_v4l2src_capture_init):
+	  More FIXME comments and messaging changes.
+
+2007-02-12 12:43:00 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/goom/gstgoom.*: Improved docs and use GST_DEBUG_FUNCPTR.
+	  Original commit message from CVS:
+	  * gst/goom/gstgoom.c: (gst_goom_class_init), (gst_goom_init),
+	  (gst_goom_change_state):
+	  * gst/goom/gstgoom.h:
+	  Improved docs and use GST_DEBUG_FUNCPTR.
+	  * gst/level/gstlevel.c: (gst_level_class_init):
+	  Use GST_DEBUG_FUNCPTR.
+	  * gst/monoscope/gstmonoscope.c: (gst_monoscope_init),
+	  (gst_monoscope_chain), (gst_monoscope_change_state):
+	  Improved docs source cleanups.
+
+2007-02-12 10:29:57 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/debug/: Add code for a pushfilesrc element that implements a pushfile:// URI handler, to make debugging push-mode...
+	  Original commit message from CVS:
+	  * gst/debug/Makefile.am:
+	  * gst/debug/gstdebug.c: (plugin_init):
+	  * gst/debug/gstpushfilesrc.c:
+	  * gst/debug/gstpushfilesrc.h:
+	  Add code for a pushfilesrc element that implements a pushfile:// URI
+	  handler, to make debugging push-mode operation of demuxer/decoders
+	  that support both easier in connection with seek/playbin/etc.
+	  The element isn't registered at the moment.
+
+2007-02-11 15:26:49 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  Makefile.am: Add win32 MANIFEST
+	  Original commit message from CVS:
+	  * Makefile.am:
+	  Add win32 MANIFEST
+	  * sys/directdraw/gstdirectdrawsink.c:
+	  * sys/directdraw/gstdirectdrawsink.h:
+	  Clear unused code and add comments.
+	  Remove yuv from template caps, it only supports RGB
+	  actually.
+	  Implement XOverlay interface and remove window and fullscreen
+	  properties.
+	  Add debug logs.
+	  Test for blit capabilities to return only the current colorspace if
+	  the hardware can't blit for one colorspace to another.
+	  * sys/directsound/gstdirectsoundsink.c:
+	  Add some debugs.
+	  * win32/MANIFEST:
+	  Add VS7 project files and solution.
+	  * win32/vs6/gst_plugins_bad.dsw:
+	  * win32/vs6/libgstdirectdraw.dsp:
+	  * win32/vs6/libgstdirectsound.dsp:
+	  * win32/vs6/libgstqtdemux.dsp:
+	  Update project files.
+
+2007-02-11 12:57:47 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  gst/avi/gstavimux.c: Comment a #if 0 in caps template definition as VS6 seems to do not support it.
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c:
+	  Comment a #if 0 in caps template definition as VS6 seems to
+	  do not support it.
+	  * gst/rtsp/gstrtspsrc.c:(gst_rtspsrc_loop_udp):
+	  Use gst_guint64_to_gdouble for conversion.
+	  * gst/rtsp/rtspconnection.c:(rtsp_connection_send):
+	  Move variables declaration before the first instruction.
+	  * gst/rtsp/rtspdefs.c:(rtsp_strresult):
+	  Don't use hstrerror for error log on G_OS_WIN32 build as it's not supported.
+	  And don't include netdb.h for G_OS_WIN32
+	  * gst/rtsp/sdpmessage.c:(sdp_parse_line):
+	  This initialization SDPMedia nmedia = {.media = NULL }; is not supported
+	  by VS6 then use an other way to initialize SDPMedia structure.
+	  * gst/udp/gstdynudpsink.h:
+	  * gst/udp/gstdynudpnetutils.h:
+	  Do not include <sys/time.h> for G_OS_WIN32
+	  * gst/udp/gstudpsrc.c:
+	  Define socklen_t as int for G_OS_WIN32
+	  * win/common/config.h.in:
+	  Undef HAVE_NETINET_IN_H
+	  * win32/vs6/gst_plugins_good.dsw:
+	  * win32/vs6/libgstrtp.dsp:
+	  * win32/vs6/libgstrtsp.dsp:
+	  * win32/vs6/libgstautogen.dsp:
+	  * win32/vs6/libgstaudiofx.dsp:
+	  * win32/vs6/libgstudp.dsp:
+	  Add and update project files.
+	  * win32/common/gstudp-enumtypes.c:
+	  * win32/common/gstudp-enumtypes.h:
+	  Add a copy of udp enumtypes to win32/common as in core
+	  and base.
+
+2007-02-11 10:53:21 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  configure.ac: Activate monoscope when building with --enable-experimental. Fix
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Activate monoscope when building with --enable-experimental. Fix
+	  --enable-external configure switch description.
+	  * sys/sunaudio/gstsunaudiomixer.c: (gst_sunaudiomixer_base_init):
+	  * sys/sunaudio/gstsunaudiosrc.c: (gst_sunaudiosrc_dispose):
+	  Help gst-indent.
+
+2007-02-09 09:24:58 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavimux.c: Explicitly cast result of pointer arithmetic to integer in order to avoid compiler warnings on s...
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c: (gst_avi_mux_riff_get_avi_header):
+	  Explicitly cast result of pointer arithmetic to integer in order to
+	  avoid compiler warnings on some 64-bit systems. Should fix #406018.
+
+2007-02-08 11:09:15 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/debug/progressreport.c: Some more docs.
+	  Original commit message from CVS:
+	  * gst/debug/progressreport.c:
+	  Some more docs.
+
+2007-02-07 21:09:45 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  docs/plugins/inspect/plugin-rtp.xml: Update for new elements.
+	  Original commit message from CVS:
+	  * docs/plugins/inspect/plugin-rtp.xml:
+	  Update for new elements.
+	  * gst/debug/progressreport.h:
+	  Commit newly-created header file as well.
+
+2007-02-07 20:39:16 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Make progressreport element post messages with the current progress on the bus. Also add some basic docs for it.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * gst/debug/Makefile.am:
+	  * gst/debug/progressreport.c: (gst_progress_report_post_progress),
+	  (gst_progress_report_do_query), (gst_progress_report_report):
+	  Make progressreport element post messages with the current progress
+	  on the bus. Also add some basic docs for it.
+
+2007-02-07 13:08:34 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/hal/hal.*: Some small cleanups; deal with errors when parsing the HAL ALSA capabilities a bit better.
+	  Original commit message from CVS:
+	  * ext/hal/hal.c: (gst_hal_get_string):
+	  * ext/hal/hal.h:
+	  Some small cleanups; deal with errors when parsing the HAL ALSA
+	  capabilities a bit better.
+
+2007-02-06 16:29:30 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/smpte/gstsmpte.c: Let's try this again and use the right cast this time.
+	  Original commit message from CVS:
+	  * gst/smpte/gstsmpte.c: (gst_smpte_transition_type_get_type):
+	  Let's try this again and use the right cast this time.
+
+2007-02-06 16:24:57 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/smpte/gstsmpte.c: Add cast to avoid compiler warnings with older GLib versions where the nick/name members in GEn...
+	  Original commit message from CVS:
+	  * gst/smpte/gstsmpte.c: (gst_smpte_transition_type_get_type):
+	  Add cast to avoid compiler warnings with older GLib versions
+	  where the nick/name members in GEnumValue are not declared as
+	  constant strings.
+
+2007-02-06 15:56:14 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/gconf/: In gconfaudiosink, get the right key as the old key in do_toggle (ie. one dependent on the profile select...
+	  Original commit message from CVS:
+	  * ext/gconf/gconf.c: (gst_gconf_get_key_for_sink_profile),
+	  (gst_gconf_render_bin_from_key),
+	  (gst_gconf_get_default_audio_sink):
+	  * ext/gconf/gconf.h:
+	  * ext/gconf/gstgconfaudiosink.c: (get_gconf_key_for_profile),
+	  (do_toggle_element), (gst_gconf_audio_sink_set_property),
+	  (gst_gconf_audio_sink_get_property):
+	  In gconfaudiosink, get the right key as the old key in do_toggle
+	  (ie. one dependent on the profile selected). Log some more stuff so
+	  we can see what's actually going on.
+
+2007-02-06 11:16:49 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/: Some small cleanups and port both elements to the new GstAudioFilter base class to save a few lines of ...
+	  Original commit message from CVS:
+	  * gst/audiofx/audioamplify.c: (gst_audio_amplify_base_init),
+	  (gst_audio_amplify_class_init), (gst_audio_amplify_init),
+	  (gst_audio_amplify_set_process_function),
+	  (gst_audio_amplify_setup):
+	  * gst/audiofx/audioamplify.h:
+	  * gst/audiofx/audioinvert.c: (gst_audio_invert_base_init),
+	  (gst_audio_invert_class_init), (gst_audio_invert_setup):
+	  * gst/audiofx/audioinvert.h:
+	  Some small cleanups and port both elements to the new GstAudioFilter
+	  base class to save a few lines of common code.
+	  * gst/audiofx/Makefile.am:
+	  Link against libgstaudio for the above changes
+
+2007-02-03 23:35:26 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Fix up to use the newly ported (actually working) GstAudioFilter.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/equalizer/Makefile.am:
+	  * gst/equalizer/gstiirequalizer.c: (gst_iir_equalizer_base_init),
+	  (gst_iir_equalizer_class_init), (gst_iir_equalizer_init),
+	  (setup_filter), (gst_iir_equalizer_compute_frequencies),
+	  (gst_iir_equalizer_set_property), (gst_iir_equalizer_get_property),
+	  (gst_iir_equalizer_transform_ip), (gst_iir_equalizer_setup),
+	  (plugin_init):
+	  * gst/equalizer/gstiirequalizer.h:
+	  Fix up to use the newly ported (actually working) GstAudioFilter.
+	  Bump core/base requirements to CVS for this.
+	  * tests/icles/.cvsignore:
+	  * tests/icles/Makefile.am:
+	  * tests/icles/equalizer-test.c: (check_bus),
+	  (equalizer_set_band_value), (equalizer_set_all_band_values),
+	  (equalizer_set_band_value_and_wait),
+	  (equalizer_set_all_band_values_and_wait), (do_slider_fiddling),
+	  (main):
+	  Add brain-dead interactive test for equalizer.
+
+2007-02-02 18:36:28 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/equalizer/gstiirequalizer.c: Rename "values" property to "band-values" and change type into a
+	  Original commit message from CVS:
+	  * gst/equalizer/gstiirequalizer.c: (gst_iir_equalizer_class_init),
+	  (gst_iir_equalizer_set_property), (gst_iir_equalizer_get_property),
+	  (gst_iir_equalizer_filter_inplace):
+	  Rename "values" property to "band-values" and change type into a
+	  GValueArray, so it's more easily bindable and the range of the
+	  values passed in is defined and checked etc.; also do some
+	  locking.
+
+2007-02-02 17:39:21 +0000  James Doc Livingston <doclivingston@gmail.com>
+
+	  Port equalizer plugin to 0.10 (#403572).
+	  Original commit message from CVS:
+	  Patch by: James "Doc" Livingston  <doclivingston at gmail com>
+	  * configure.ac:
+	  * gst/equalizer/Makefile.am:
+	  * gst/equalizer/gstiirequalizer.c: (gst_iir_equalizer_get_type),
+	  (gst_iir_equalizer_base_init), (gst_iir_equalizer_class_init),
+	  (gst_iir_equalizer_compute_frequencies),
+	  (gst_iir_equalizer_set_property),
+	  (gst_iir_equalizer_filter_inplace), (gst_iir_equalizer_setup),
+	  (plugin_init):
+	  Port equalizer plugin to 0.10 (#403572).
+
+2007-01-31 08:32:59 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackparse.c: Fix a off by one that leads to the duration reported as one sample less than it is
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_src_query),
+	  (gst_wavpack_parse_handle_seek_event),
+	  (gst_wavpack_parse_create_src_pad):
+	  Fix a off by one that leads to the duration reported as one
+	  sample less than it is
+
+2007-01-30 17:19:33 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  configure.ac: Check for an Objective C compiler
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Check for an Objective C compiler
+	  * sys/Makefile.am:
+	  * sys/osxvideo/Makefile.am:
+	  * sys/osxvideo/cocoawindow.h:
+	  * sys/osxvideo/cocoawindow.m:
+	  * sys/osxvideo/osxvideosink.h:
+	  * sys/osxvideo/osxvideosink.m:
+	  Port of osxvideo plugin to 0.10. Do NOT consider 100% stable !
+	  Fixes #402470
+
+2007-01-29 10:59:48 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  tests/check/elements/.cvsignore: Some more ignores.
+	  Original commit message from CVS:
+	  * tests/check/elements/.cvsignore:
+	  Some more ignores.
+
+2007-01-28 18:28:33 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/videocrop/gstvideocrop.c: Fix cropping for packed 4:2:2 formats YUYV/YUY2 and UYVY.
+	  Original commit message from CVS:
+	  * gst/videocrop/gstvideocrop.c:
+	  (gst_video_crop_get_image_details_from_caps),
+	  (gst_video_crop_transform_packed_complex):
+	  Fix cropping for packed 4:2:2 formats YUYV/YUY2 and UYVY.
+	  * tests/icles/videocrop-test.c: (check_bus_for_errors),
+	  (test_with_caps), (main):
+	  Block streaming thread before changing filter caps while the
+	  pipeline is running so that we don't get random not-negotiated
+	  errors just because GStreamer can't handle that yet.
+
+2007-01-27 16:08:15 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/icles/videocrop-test.c: Catch errors while the test is running.
+	  Original commit message from CVS:
+	  * tests/icles/videocrop-test.c: (test_with_caps):
+	  Catch errors while the test is running.
+
+2007-01-26 12:21:41 +0000  charles <charlesg3@gmail.com>
+
+	  ext/shout2/gstshout2.*: Properly handle tags in shout2send. Fixes #399825.
+	  Original commit message from CVS:
+	  Patch by: charles <charlesg3 at gmail dot com>
+	  * ext/shout2/gstshout2.c: (gst_shout2send_init),
+	  (set_shout_metadata), (gst_shout2send_event):
+	  * ext/shout2/gstshout2.h:
+	  Properly handle tags in shout2send. Fixes #399825.
+
+2007-01-25 23:27:59 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackparse.c: Fix the SEEKING query. We can seek if we are in pull mode, not the other way around. A...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_src_query):
+	  Fix the SEEKING query. We can seek if we are in pull mode, not the
+	  other way around. Also set the correct format in the seeking query and
+	  handle the case where the headers are not read yet and we can't say
+	  anything about our seeking capabilities.
+
+2007-01-25 21:55:49 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/: Fix spelling in 2 places: It's called Wavpack, not WavePack.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_base_init):
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_base_init):
+	  Fix spelling in 2 places: It's called Wavpack, not WavePack.
+
+2007-01-25 14:40:15 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Convert SDP fields to upper/lowercase following the rules in the SDP to caps document.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_media_to_caps),
+	  (gst_rtspsrc_activate_streams):
+	  Convert SDP fields to upper/lowercase following the rules in the SDP to
+	  caps document.
+
+2007-01-25 14:22:53 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Fix case of encoding-name and key/value pairs to match the document.
+	  Original commit message from CVS:
+	  * gst/rtp/README:
+	  * gst/rtp/gstrtpilbcdepay.c:
+	  * gst/rtp/gstrtpilbcpay.c:
+	  * gst/rtp/gstrtpmp4gdepay.c:
+	  * gst/rtp/gstrtpmp4gpay.c:
+	  * gst/rtp/gstrtpspeexdepay.c:
+	  * gst/rtp/gstrtpspeexpay.c:
+	  * gst/rtp/gstrtpsv3vdepay.c:
+	  * gst/rtp/gstrtptheoradepay.c:
+	  * gst/rtp/gstrtptheorapay.c:
+	  * gst/rtp/gstrtpvorbisdepay.c:
+	  * gst/rtp/gstrtpvorbispay.c:
+	  Fix case of encoding-name and key/value pairs to match the document.
+	  This is to make interoperation with SDP case-insensitive as required by
+	  the relevant RFCs.
+
+2007-01-25 12:05:11 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/: Use proper print statements.
+	  Original commit message from CVS:
+	  * gst/multifile/gstmultifilesink.c:
+	  (gst_multi_file_sink_class_init):
+	  * gst/multifile/gstmultifilesrc.c: (gst_multi_file_src_class_init):
+	  * gst/mve/gstmvedemux.c: (gst_mve_video_create_buffer),
+	  (gst_mve_video_palette), (gst_mve_video_code_map),
+	  (gst_mve_audio_init), (gst_mve_audio_data), (gst_mve_timer_create),
+	  (gst_mve_demux_chain):
+	  * gst/mve/gstmvemux.c: (gst_mve_mux_push_chunk):
+	  * gst/mve/mveaudioenc.c: (mve_compress_audio):
+	  * gst/mve/mvevideodec16.c: (ipvideo_copy_block):
+	  * gst/mve/mvevideodec8.c: (ipvideo_copy_block):
+	  * gst/mve/mvevideoenc16.c: (mve_encode_frame16):
+	  * gst/mve/mvevideoenc8.c: (mve_encode_frame8):
+	  Use proper print statements.
+	  Fixes build on mac os x.
+	  <wingo> oo look at me my name is edward i'm hacking on macos wooo
+
+2007-01-25 11:02:01 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  configure.ac: Bump required -core/-base to CVS
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Bump required -core/-base to CVS
+
+2007-01-25 10:54:19 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpL16pay.*: Fill up to MTU using adapter.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpL16pay.c: (gst_rtp_L16_pay_setcaps),
+	  (gst_rtp_L16_pay_flush), (gst_rtp_L16_pay_handle_buffer):
+	  * gst/rtp/gstrtpL16pay.h:
+	  Fill up to MTU using adapter.
+	  Timestamp rtp packets.
+
+2007-01-25 10:36:35 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  Use G_GSIZE_FORMAT in print statements for portability.
+	  Original commit message from CVS:
+	  * gst/multipart/multipartmux.c: (gst_multipart_mux_collected):
+	  * sys/ximage/ximageutil.c: (ximageutil_check_xshm_calls):
+	  Use G_GSIZE_FORMAT in print statements for portability.
+	  Fixes build on macosx.
+
+2007-01-24 18:20:14 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Port and enable raw audio payloader/depayloader. Needs a bit more work on the payloader side.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpL16depay.c: (gst_rtp_L16_depay_base_init),
+	  (gst_rtp_L16_depay_class_init), (gst_rtp_L16_depay_init),
+	  (gst_rtp_L16_depay_parse_int), (gst_rtp_L16_depay_setcaps),
+	  (gst_rtp_L16_depay_process), (gst_rtp_L16_depay_set_property),
+	  (gst_rtp_L16_depay_get_property), (gst_rtp_L16_depay_change_state),
+	  (gst_rtp_L16_depay_plugin_init):
+	  * gst/rtp/gstrtpL16depay.h:
+	  * gst/rtp/gstrtpL16pay.c: (gst_rtp_L16_pay_get_type),
+	  (gst_rtp_L16_pay_base_init), (gst_rtp_L16_pay_class_init),
+	  (gst_rtp_L16_pay_init), (gst_rtp_L16_pay_finalize),
+	  (gst_rtp_L16_pay_setcaps), (gst_rtp_L16_pay_handle_buffer),
+	  (gst_rtp_L16_pay_plugin_init):
+	  * gst/rtp/gstrtpL16pay.h:
+	  Port and enable raw audio payloader/depayloader. Needs a bit more work
+	  on the payloader side.
+
+2007-01-24 16:25:55 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Only unblock the udp pads when we linked and activated them all.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (pad_blocked),
+	  (gst_rtspsrc_stream_configure_transport),
+	  (gst_rtspsrc_activate_streams), (gst_rtspsrc_loop_udp):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Only unblock the udp pads when we linked and activated them all.
+	  Fixes #395688.
+
+2007-01-24 15:18:34 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Added simple AC3 depayloader (RFC 4184).
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpac3depay.c: (gst_rtp_ac3_depay_base_init),
+	  (gst_rtp_ac3_depay_class_init), (gst_rtp_ac3_depay_init),
+	  (gst_rtp_ac3_depay_setcaps), (gst_rtp_ac3_depay_process),
+	  (gst_rtp_ac3_depay_set_property), (gst_rtp_ac3_depay_get_property),
+	  (gst_rtp_ac3_depay_change_state), (gst_rtp_ac3_depay_plugin_init):
+	  * gst/rtp/gstrtpac3depay.h:
+	  Added simple AC3 depayloader (RFC 4184).
+	  * gst/rtp/gstrtpmp2tdepay.c: (gst_rtp_mp2t_depay_setcaps):
+	  Fix a leak.
+
+2007-01-24 12:41:03 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/: Add new element "audioamplify". This allows scaling of raw audio samples, similar to the "volume" eleme...
+	  Original commit message from CVS:
+	  reviewed by: Stefan Kost  <ensonic@users.sf.net>
+	  * gst/audiofx/Makefile.am:
+	  * gst/audiofx/audioamplify.c:
+	  (gst_audio_amplify_clipping_method_get_type),
+	  (gst_audio_amplify_base_init), (gst_audio_amplify_class_init),
+	  (gst_audio_amplify_init), (gst_audio_amplify_set_process_function),
+	  (gst_audio_amplify_set_property), (gst_audio_amplify_get_property),
+	  (gst_audio_amplify_set_caps),
+	  (gst_audio_amplify_transform_int_clip),
+	  (gst_audio_amplify_transform_int_wrap_negative),
+	  (gst_audio_amplify_transform_int_wrap_positive),
+	  (gst_audio_amplify_transform_float_clip),
+	  (gst_audio_amplify_transform_float_wrap_negative),
+	  (gst_audio_amplify_transform_float_wrap_positive),
+	  (gst_audio_amplify_transform_ip):
+	  * gst/audiofx/audioamplify.h:
+	  * gst/audiofx/audiofx.c: (plugin_init):
+	  Add new element "audioamplify". This allows scaling of raw audio
+	  samples, similar to the "volume" element, but provides different modes
+	  for clipping and allows unlimited amplification. It's mainly targeted
+	  for creative sound design and not as a replacement of the "volume"
+	  element. Fixes #397162
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  Add docs for audioamplify and integrate them into the build system
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/audioamplify.c: (setup_amplify),
+	  (cleanup_amplify), (GST_START_TEST), (amplify_suite), (main):
+	  Add fairly extensive unit test suite for audioamplify
+
+2007-01-24 12:26:41 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Unblock pads after adding the pads to the element so that autopluggers get a change to link so...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (pad_unblocked), (pad_blocked):
+	  Unblock pads after adding the pads to the element so that autopluggers
+	  get a change to link something. Possibly fixes #395688.
+
+2007-01-24 12:22:51 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Fix caps with payload numbers.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpamrdepay.c:
+	  * gst/rtp/gstrtpgsmdepay.c:
+	  * gst/rtp/gstrtph263pdepay.c:
+	  * gst/rtp/gstrtph263ppay.c:
+	  * gst/rtp/gstrtph264depay.c:
+	  * gst/rtp/gstrtpilbcdepay.c:
+	  * gst/rtp/gstrtpmp2tdepay.c:
+	  * gst/rtp/gstrtpmp4gdepay.c:
+	  * gst/rtp/gstrtpmp4gpay.c:
+	  * gst/rtp/gstrtpmp4vdepay.c: (gst_rtp_mp4v_depay_class_init):
+	  * gst/rtp/gstrtpmp4vpay.c:
+	  * gst/rtp/gstrtpmpadepay.c: (gst_rtp_mpa_depay_class_init),
+	  (gst_rtp_mpa_depay_init), (gst_rtp_mpa_depay_setcaps),
+	  (gst_rtp_mpa_depay_process):
+	  * gst/rtp/gstrtpmpvdepay.c: (gst_rtp_mpv_depay_class_init),
+	  (gst_rtp_mpv_depay_init), (gst_rtp_mpv_depay_process):
+	  * gst/rtp/gstrtppcmadepay.c:
+	  * gst/rtp/gstrtppcmudepay.c:
+	  * gst/rtp/gstrtpspeexdepay.c:
+	  * gst/rtp/gstrtpspeexpay.c:
+	  * gst/rtp/gstrtpsv3vdepay.c:
+	  * gst/rtp/gstrtptheoradepay.c:
+	  * gst/rtp/gstrtptheorapay.c:
+	  * gst/rtp/gstrtpvorbisdepay.c:
+	  * gst/rtp/gstrtpvorbispay.c:
+	  Fix caps with payload numbers.
+	  Add some fixed payload numbers to caps when possible.
+
+2007-01-24 11:29:00 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/gstrtpxqtdepay.c: Fix caps on the depayloader.
+	  Original commit message from CVS:
+	  * gst/qtdemux/gstrtpxqtdepay.c:
+	  Fix caps on the depayloader.
+
+2007-01-23 18:16:09 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/: Add new audiofx element "audioinvert". This element swaps the upper and lower half of samples and can b...
+	  Original commit message from CVS:
+	  reviewed by: Stefan Kost  <ensonic@users.sf.net>
+	  * gst/audiofx/Makefile.am:
+	  * gst/audiofx/audiofx.c: (plugin_init):
+	  * gst/audiofx/audioinvert.c: (gst_audio_invert_base_init),
+	  (gst_audio_invert_class_init), (gst_audio_invert_init),
+	  (gst_audio_invert_set_property), (gst_audio_invert_get_property),
+	  (gst_audio_invert_set_caps), (gst_audio_invert_transform_int),
+	  (gst_audio_invert_transform_float),
+	  (gst_audio_invert_transform_ip):
+	  * gst/audiofx/audioinvert.h:
+	  Add new audiofx element "audioinvert". This element swaps the upper
+	  and lower half of samples and can be used for example for a
+	  wide-stereo effect. Fixes #396057
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  Add docs for the audioinvert element and add them to the build system.
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/audioinvert.c: (setup_invert),
+	  (cleanup_invert), (GST_START_TEST), (invert_suite), (main):
+	  Add unit test suite for the audioinvert element.
+
+2007-01-23 17:36:32 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmp4gdepay.c: Parse config params as string and int.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4gdepay.c: (gst_rtp_mp4g_depay_parse_int),
+	  (gst_rtp_mp4g_depay_setcaps), (gst_rtp_mp4g_depay_process):
+	  Parse config params as string and int.
+	  Parse and use AU header length
+
+2007-01-23 17:27:39 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/smpte/: constify some static structs.
+	  Original commit message from CVS:
+	  * gst/smpte/barboxwipes.c: (gst_wipe_boxes_draw),
+	  (gst_wipe_triangles_clock_draw), (gst_wipe_triangles_draw):
+	  * gst/smpte/gstmask.c: (_gst_mask_register):
+	  * gst/smpte/gstmask.h:
+	  * gst/smpte/gstsmpte.c: (gst_smpte_update_mask):
+	  * gst/smpte/paint.c: (gst_smpte_paint_hbox), (draw_bresenham_line),
+	  (gst_smpte_paint_triangle_clock):
+	  constify some static structs.
+	  Don't update the mask if nothing changed to the params.
+	  Make sure we never draw outside of the picture. Fixes #398325.
+
+2007-01-22 13:06:43 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavidemux.c: Error out properly when pull_range fails while we're reading the headers, instead of just paus...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_stream_header_pull):
+	  Error out properly when pull_range fails while we're reading the
+	  headers, instead of just pausing the task silently. Fixes #399338.
+
+2007-01-19 13:06:07 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/smpte/gstsmpte.c: Some more sanity checks to make sure the input formats match and the input pads are actually ne...
+	  Original commit message from CVS:
+	  * gst/smpte/gstsmpte.c: (gst_smpte_collected):
+	  Some more sanity checks to make sure the input formats match and the
+	  input pads are actually negotiated, in case someone tries to feed
+	  buffers from fakesrc or filesrc. Fixes #398299.
+	  Also const-ify an array, just because we can.
+
+2007-01-19 10:35:13 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/smpte/gstsmpte.c: Ignore previous commit, that was only valid for widths and heights that are multiples of 4.
+	  Original commit message from CVS:
+	  * gst/smpte/gstsmpte.c: (fill_i420), (gst_smpte_collected):
+	  Ignore previous commit, that was only valid for widths and heights
+	  that are multiples of 4.
+	  Copy over size/stride macros from jpegdec. This allows the element
+	  to work with any width,height...
+	  ... but puts in evidence that the actual transformations only work
+	  with width/height that are multiples of 4.
+
+2007-01-19 09:48:47 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/smpte/gstsmpte.c: Allocate buffers of the right size.
+	  Original commit message from CVS:
+	  * gst/smpte/gstsmpte.c: (gst_smpte_collected):
+	  Allocate buffers of the right size.
+	  The proper size of a I420 buffer in bytes is:
+	  width * height * 3
+	  ------------------
+	  2
+
+2007-01-18 18:37:39 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/smpte/gstsmpte.c: Proxy getcaps on sink pads too, so that we either end up with the same dimensions on all pads o...
+	  Original commit message from CVS:
+	  * gst/smpte/gstsmpte.c: (gst_smpte_init):
+	  Proxy getcaps on sink pads too, so that we either end up with the
+	  same dimensions on all pads or error out if that's not possible
+	  (seems to work even!). Fixes #398086, I think.
+
+2007-01-18 11:29:17 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  docs/plugins/: Remove ladspa from docs; add hierarchy info for GstAudioPanorama; fix integer properties with -1 as mi...
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  Remove ladspa from docs; add hierarchy info for GstAudioPanorama;
+	  fix integer properties with -1 as minimum value.
+	  * docs/plugins/inspect/plugin-1394.xml:
+	  * docs/plugins/inspect/plugin-aasink.xml:
+	  * docs/plugins/inspect/plugin-alaw.xml:
+	  * docs/plugins/inspect/plugin-alpha.xml:
+	  * docs/plugins/inspect/plugin-alphacolor.xml:
+	  * docs/plugins/inspect/plugin-annodex.xml:
+	  * docs/plugins/inspect/plugin-apetag.xml:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  * docs/plugins/inspect/plugin-auparse.xml:
+	  * docs/plugins/inspect/plugin-autodetect.xml:
+	  * docs/plugins/inspect/plugin-avi.xml:
+	  * docs/plugins/inspect/plugin-cacasink.xml:
+	  * docs/plugins/inspect/plugin-cairo.xml:
+	  * docs/plugins/inspect/plugin-cdio.xml:
+	  * docs/plugins/inspect/plugin-cutter.xml:
+	  * docs/plugins/inspect/plugin-debug.xml:
+	  * docs/plugins/inspect/plugin-dv.xml:
+	  * docs/plugins/inspect/plugin-efence.xml:
+	  * docs/plugins/inspect/plugin-effectv.xml:
+	  * docs/plugins/inspect/plugin-esdsink.xml:
+	  * docs/plugins/inspect/plugin-flac.xml:
+	  * docs/plugins/inspect/plugin-flxdec.xml:
+	  * docs/plugins/inspect/plugin-gconfelements.xml:
+	  * docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	  * docs/plugins/inspect/plugin-goom.xml:
+	  * docs/plugins/inspect/plugin-halelements.xml:
+	  * docs/plugins/inspect/plugin-icydemux.xml:
+	  * docs/plugins/inspect/plugin-id3demux.xml:
+	  * docs/plugins/inspect/plugin-jpeg.xml:
+	  * docs/plugins/inspect/plugin-level.xml:
+	  * docs/plugins/inspect/plugin-matroska.xml:
+	  * docs/plugins/inspect/plugin-mulaw.xml:
+	  * docs/plugins/inspect/plugin-multipart.xml:
+	  * docs/plugins/inspect/plugin-navigationtest.xml:
+	  * docs/plugins/inspect/plugin-ossaudio.xml:
+	  * docs/plugins/inspect/plugin-png.xml:
+	  * docs/plugins/inspect/plugin-rtp.xml:
+	  * docs/plugins/inspect/plugin-rtsp.xml:
+	  * docs/plugins/inspect/plugin-shout2send.xml:
+	  * docs/plugins/inspect/plugin-smpte.xml:
+	  * docs/plugins/inspect/plugin-speex.xml:
+	  * docs/plugins/inspect/plugin-taglib.xml:
+	  * docs/plugins/inspect/plugin-udp.xml:
+	  * docs/plugins/inspect/plugin-videobalance.xml:
+	  * docs/plugins/inspect/plugin-videobox.xml:
+	  * docs/plugins/inspect/plugin-videoflip.xml:
+	  * docs/plugins/inspect/plugin-videomixer.xml:
+	  * docs/plugins/inspect/plugin-wavenc.xml:
+	  * docs/plugins/inspect/plugin-wavparse.xml:
+	  * docs/plugins/inspect/plugin-ximagesrc.xml:
+	  Update to CVS.
+
+2007-01-18 11:23:36 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/audiofx/audiopanorama.c: Fix doc section name (Fixes #397946)
+	  Original commit message from CVS:
+	  * gst/audiofx/audiopanorama.c:
+	  Fix doc section name (Fixes #397946)
+
+2007-01-18 10:33:50 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* ChangeLog:
+	  Remove bogus ChangeLog entry
+	  Original commit message from CVS:
+	  Remove bogus ChangeLog entry
+
+2007-01-17 14:30:50 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/v4l2/: Fix EIO handing when capturing. Add new property to specify the number of buffers to enque (and remove the...
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2object.c:
+	  (gst_v4l2_object_install_properties_helper),
+	  (gst_v4l2_object_set_property_helper),
+	  (gst_v4l2_object_get_property_helper), (gst_v4l2_set_defaults):
+	  * sys/v4l2/gstv4l2object.h:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init),
+	  (gst_v4l2src_init), (gst_v4l2src_set_property),
+	  (gst_v4l2src_get_property), (gst_v4l2src_set_caps):
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list),
+	  (gst_v4l2src_grab_frame), (gst_v4l2src_set_capture),
+	  (gst_v4l2src_capture_init), (gst_v4l2src_capture_start),
+	  (gst_v4l2src_capture_deinit):
+	  Fix EIO handing when capturing. Add new property to specify the number of
+	  buffers to enque (and remove the borked num-buffers usage).
+
+2007-01-16 08:29:11 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/audiopanorama.c: Use a function array for process methods, add more docs and define the startindex of enums.
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge <slomo circular-chaos org>
+	  * gst/audiofx/audiopanorama.c: (gst_audio_panorama_class_init),
+	  (gst_audio_panorama_set_process_function):
+	  Use a function array for process methods, add more docs and define the
+	  startindex of enums.
+
+2007-01-14 17:55:33 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  Add support for more than one audio stream; write better AVIX header; refactor code a bit; don't announce vorbis caps...
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts <manauw at skynet be>
+	  * gst/avi/gstavimux.c: (gst_avi_mux_finalize),
+	  (gst_avi_mux_pad_reset), (gst_avi_mux_reset), (gst_avi_mux_init),
+	  (gst_avi_mux_vidsink_set_caps), (gst_avi_mux_audsink_set_caps),
+	  (gst_avi_mux_request_new_pad), (gst_avi_mux_release_pad),
+	  (gst_avi_mux_riff_get_avi_header),
+	  (gst_avi_mux_riff_get_avix_header), (gst_avi_mux_riff_get_header),
+	  (gst_avi_mux_write_avix_index), (gst_avi_mux_add_index),
+	  (gst_avi_mux_bigfile), (gst_avi_mux_start_file),
+	  (gst_avi_mux_stop_file), (gst_avi_mux_handle_event),
+	  (gst_avi_mux_do_buffer), (gst_avi_mux_do_one_buffer),
+	  (gst_avi_mux_change_state):
+	  * gst/avi/gstavimux.h:
+	  * tests/check/elements/avimux.c: (teardown_src_pad):
+	  Add support for more than one audio stream; write better AVIX
+	  header; refactor code a bit; don't announce vorbis caps on our audio
+	  sink pads since we don't support it anyway. Closes #379298.
+
+2007-01-13 19:12:32 +0000  Andy Wingo <wingo@pobox.com>
+
+	  gst/interleave/deinterleave.c (gst_deinterleave_add_new_pads): Use fixed caps on src pads.
+	  Original commit message from CVS:
+	  2007-01-13  Andy Wingo  <wingo@pobox.com>
+	  * gst/interleave/deinterleave.c (gst_deinterleave_add_new_pads):
+	  Use fixed caps on src pads.
+	  (gst_deinterleave_remove_pads): Remove src pads, not sink pads. I
+	  seem to have reverse midas disease!
+	  (gst_deinterleave_process): Proxy timestamps, offsets, durations,
+	  and set caps on outgoing buffers. Fixes #395597, I think.
+
+2007-01-13 18:01:41 +0000  Andy Wingo <wingo@pobox.com>
+
+	  gst/interleave/interleave.c (gst_interleave_init): Init the activation mode properly.
+	  Original commit message from CVS:
+	  2007-01-13  Andy Wingo  <wingo@pobox.com>
+	  * gst/interleave/interleave.c (gst_interleave_init): Init the
+	  activation mode properly.
+	  (gst_interleave_src_setcaps, gst_interleave_src_getcaps)
+	  (gst_interleave_init): Set a setcaps and getcaps function on the
+	  src pad, so that we can implement pull-mode negotiation.
+	  (gst_interleave_sink_setcaps): Renamed from
+	  gst_interleave_setcaps, as it only does the sink logic now.
+	  Implement both for pull-mode and push-mode.
+	  (gst_interleave_process): Set caps on our outgoing buffer.
+	  (gst_interleave_src_activate_pull): Fix some more bogus casts.
+	  What is up with this.
+
+2007-01-13 15:52:18 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  gst/audiofx/audiopanorama.*: Add 'method' property and provide a simple (non-psychoacustic) processing method (#394859).
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge <slomo circular-chaos org>
+	  * gst/audiofx/audiopanorama.c:
+	  (gst_audio_panorama_method_get_type),
+	  (gst_audio_panorama_class_init), (gst_audio_panorama_init),
+	  (gst_audio_panorama_set_process_function),
+	  (gst_audio_panorama_set_property),
+	  (gst_audio_panorama_get_property), (gst_audio_panorama_set_caps),
+	  (gst_audio_panorama_transform_m2s_int_simple),
+	  (gst_audio_panorama_transform_s2s_int_simple),
+	  (gst_audio_panorama_transform_m2s_float_simple),
+	  (gst_audio_panorama_transform_s2s_float_simple):
+	  * gst/audiofx/audiopanorama.h:
+	  Add 'method' property and provide a simple (non-psychoacustic)
+	  processing method (#394859).
+	  * tests/check/elements/audiopanorama.c: (GST_START_TEST),
+	  (panorama_suite):
+	  Tests for new method.
+
+2007-01-12 18:28:13 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  comment out LADSPA plugin for now
+	  Original commit message from CVS:
+	  comment out LADSPA plugin for now
+
+2007-01-12 17:16:51 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/: Add X-QT depayloader that will eventually share code with the demuxer.
+	  Original commit message from CVS:
+	  * gst/qtdemux/Makefile.am:
+	  * gst/qtdemux/gstrtpxqtdepay.c: (gst_rtp_xqt_depay_base_init),
+	  (gst_rtp_xqt_depay_class_init), (gst_rtp_xqt_depay_init),
+	  (gst_rtp_xqt_depay_finalize), (gst_rtp_quicktime_parse_sd),
+	  (gst_rtp_xqt_depay_setcaps), (gst_rtp_xqt_depay_process),
+	  (gst_rtp_xqt_depay_set_property), (gst_rtp_xqt_depay_get_property),
+	  (gst_rtp_xqt_depay_change_state), (gst_rtp_xqt_depay_plugin_init):
+	  * gst/qtdemux/gstrtpxqtdepay.h:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_base_init),
+	  (gst_qtdemux_loop_state_header), (gst_qtdemux_loop),
+	  (qtdemux_parse_moov), (qtdemux_parse_container),
+	  (qtdemux_parse_node), (gst_qtdemux_add_stream),
+	  (qtdemux_parse_trak), (qtdemux_audio_caps):
+	  * gst/qtdemux/qtdemux.h:
+	  * gst/qtdemux/quicktime.c: (plugin_init):
+	  Add X-QT depayloader that will eventually share code with the demuxer.
+	  Make new plugin entry point with quicktime releated stuff.
+
+2007-01-12 12:10:19 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/Makefile.am: Dist all new files.
+	  Original commit message from CVS:
+	  * gst/qtdemux/Makefile.am:
+	  Dist all new files.
+
+2007-01-12 10:27:25 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  docs/plugins/: Activate docs for jack, sdl and qtdemux.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-bad-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-bad-plugins.signals:
+	  * docs/plugins/inspect/plugin-qtdemux.xml:
+	  Activate docs for jack, sdl and qtdemux.
+
+2007-01-12 10:22:16 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/: Cleanup and refactor to make the code more readable.
+	  Original commit message from CVS:
+	  * gst/qtdemux/Makefile.am:
+	  * gst/qtdemux/qtdemux.c: (extract_initial_length_and_fourcc),
+	  (gst_qtdemux_loop_state_header), (gst_qtdemux_combine_flows),
+	  (gst_qtdemux_loop_state_movie), (gst_qtdemux_loop),
+	  (gst_qtdemux_chain), (qtdemux_sink_activate_pull),
+	  (qtdemux_inflate), (qtdemux_parse_moov), (qtdemux_parse_container),
+	  (qtdemux_parse_node), (qtdemux_tree_get_child_by_type),
+	  (qtdemux_tree_get_sibling_by_type), (gst_qtdemux_add_stream),
+	  (qtdemux_parse_samples), (qtdemux_parse_segments),
+	  (qtdemux_parse_trak), (qtdemux_tag_add_str), (qtdemux_tag_add_num),
+	  (qtdemux_tag_add_date), (qtdemux_tag_add_gnre),
+	  (qtdemux_parse_udta), (qtdemux_redirects_sort_func),
+	  (qtdemux_process_redirects), (qtdemux_parse_redirects),
+	  (qtdemux_parse_tree), (gst_qtdemux_handle_esds),
+	  (qtdemux_video_caps), (qtdemux_audio_caps):
+	  * gst/qtdemux/qtdemux.h:
+	  * gst/qtdemux/qtdemux_dump.c: (qtdemux_dump_mvhd),
+	  (qtdemux_dump_tkhd), (qtdemux_dump_elst), (qtdemux_dump_mdhd),
+	  (qtdemux_dump_hdlr), (qtdemux_dump_vmhd), (qtdemux_dump_dref),
+	  (qtdemux_dump_stsd), (qtdemux_dump_stts), (qtdemux_dump_stss),
+	  (qtdemux_dump_stsc), (qtdemux_dump_stsz), (qtdemux_dump_stco),
+	  (qtdemux_dump_co64), (qtdemux_dump_dcom), (qtdemux_dump_cmvd),
+	  (qtdemux_dump_unknown), (qtdemux_node_dump_foreach),
+	  (qtdemux_node_dump):
+	  * gst/qtdemux/qtdemux_dump.h:
+	  * gst/qtdemux/qtdemux_fourcc.h:
+	  * gst/qtdemux/qtdemux_types.c: (qtdemux_type_get):
+	  * gst/qtdemux/qtdemux_types.h:
+	  * gst/qtdemux/qtpalette.h:
+	  Cleanup and refactor to make the code more readable.
+	  Move debugging/tables into separate files.
+	  Add 2/4/16 color palletee support.
+	  Fix raw 15 bit RGB handling.
+	  Use more FOURCC constants.
+	  Add some docs.
+
+2007-01-11 19:51:04 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackenc.c: Minor clean-up: use enum values instead of hardcoded constants (#395536).
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge  <slomo@circular-chaos.org>
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_mode_get_type),
+	  (gst_wavpack_enc_correction_mode_get_type),
+	  (gst_wavpack_enc_joint_stereo_mode_get_type):
+	  Minor clean-up: use enum values instead of hardcoded constants (#395536).
+
+2007-01-11 16:59:40 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/: Set correct caps on outgoing pulled buffers, or things blow up after recent core changes.
+	  Original commit message from CVS:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_read_range):
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_read_range):
+	  Set correct caps on outgoing pulled buffers, or things blow up
+	  after recent core changes.
+
+2007-01-11 11:05:04 +0000  Jonas Holmberg <jonas.holmberg@axis.com>
+
+	  gst/multipart/multipartmux.c: Return FLOW errors ASAP. Fixes #394977.
+	  Original commit message from CVS:
+	  Based on patch by: Jonas Holmberg <jonas dot holmberg at axis dot com>
+	  * gst/multipart/multipartmux.c: (gst_multipart_mux_init),
+	  (gst_multipart_mux_request_new_pad),
+	  (gst_multipart_mux_queue_pads), (gst_multipart_mux_collected),
+	  (gst_multipart_mux_change_state):
+	  Return FLOW errors ASAP. Fixes #394977.
+	  Misc cleanups.
+
+2007-01-11 09:30:59 +0000  Lutz Mueller <lutz@topfrose.de>
+
+	  gst/rtsp/gstrtspsrc.c: Check for stream pad before activating.
+	  Original commit message from CVS:
+	  Patch by: Lutz Mueller <lutz at topfrose dot de>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_activate_streams):
+	  Check for stream pad before activating.
+
+2007-01-10 15:19:48 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/rtsp/: Allow url to be NULL to be able to use it for server connections.
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt  <pkj at axis com>
+	  * gst/rtsp/COPYING.MIT:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_create_stream),
+	  (gst_rtspsrc_stream_free), (gst_rtspsrc_cleanup),
+	  (gst_rtspsrc_alloc_udp_ports), (pad_unblocked), (pad_blocked),
+	  (gst_rtspsrc_stream_configure_transport),
+	  (gst_rtspsrc_activate_streams), (gst_rtspsrc_loop_interleaved),
+	  (gst_rtspsrc_loop_udp), (gst_rtspsrc_send),
+	  (gst_rtspsrc_parse_methods),
+	  (gst_rtspsrc_create_transports_string),
+	  (gst_rtspsrc_prepare_transports), (gst_rtspsrc_setup_streams),
+	  (gst_rtspsrc_open), (gst_rtspsrc_close):
+	  * gst/rtsp/gstrtspsrc.h:
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_create),
+	  (rtsp_connection_connect), (rtsp_connection_send), (read_line),
+	  (parse_request_line), (parse_line), (rtsp_connection_read),
+	  (rtsp_connection_close):
+	  * gst/rtsp/rtspdefs.c: (rtsp_init_status), (rtsp_strresult),
+	  (rtsp_method_as_text), (rtsp_header_as_text),
+	  (rtsp_status_as_text), (rtsp_find_header_field),
+	  (rtsp_find_method):
+	  * gst/rtsp/rtspdefs.h:
+	  * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_after_send),
+	  (rtsp_ext_wms_configure_stream):
+	  * gst/rtsp/rtspmessage.c: (rtsp_message_new), (rtsp_message_init),
+	  (rtsp_message_new_request), (rtsp_message_init_request),
+	  (rtsp_message_new_response), (rtsp_message_init_response),
+	  (rtsp_message_init_data), (rtsp_message_unset),
+	  (rtsp_message_free), (rtsp_message_add_header),
+	  (rtsp_message_get_header), (rtsp_message_set_body),
+	  (rtsp_message_get_body), (dump_mem), (rtsp_message_dump):
+	  * gst/rtsp/rtspmessage.h:
+	  * gst/rtsp/sdpmessage.c: (sdp_message_get_attribute_val_n),
+	  (sdp_media_get_attribute_val_n), (read_string), (read_string_del),
+	  (sdp_parse_line), (sdp_message_parse_buffer), (print_media),
+	  (sdp_message_dump):
+	  Allow url to be NULL to be able to use it for server connections.
+	  Can now send responses as well as requests.
+	  No longer hangs in an endless loop if EOF is received.
+	  Can now convert a status code to a text string.
+	  Return RTSP_HDR_INVALID for unknown headers.
+	  Return RTSP_INVALID for unknown methods.
+	  Copy CSeq and Session headers from the request.
+	  Only free memory corresponding to the currently set message type.
+	  Added const to function arguments as appropriate.
+	  Avoid a compiler warning when initializing nmedia.
+	  Use guint rather than gint to avoid compiler warnings.
+	  Fix crasher in wms extension.
+	  Factor out stream setup from open_connection.
+	  Delay activation of streams when actual data is received from the
+	  server, this prepares us to do proper protocol switching.
+	  Added new license.
+	  Fixes #380895.
+
+2007-01-10 09:47:43 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Some small docs fixes (#394851).
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge <slomo ubuntu com>
+	  * docs/plugins/Makefile.am:
+	  * gst/audiofx/audiopanorama.c:
+	  Some small docs fixes (#394851).
+
+2007-01-09 12:25:26 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: Fix docs.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  Fix docs.
+
+2007-01-09 12:23:48 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Added RFC 2250 MPEG Video Depayloader.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpmpvdepay.c: (gst_rtp_mpv_depay_base_init),
+	  (gst_rtp_mpv_depay_class_init), (gst_rtp_mpv_depay_init),
+	  (gst_rtp_mpv_depay_setcaps), (gst_rtp_mpv_depay_process),
+	  (gst_rtp_mpv_depay_set_property), (gst_rtp_mpv_depay_get_property),
+	  (gst_rtp_mpv_depay_change_state), (gst_rtp_mpv_depay_plugin_init):
+	  * gst/rtp/gstrtpmpvdepay.h:
+	  Added RFC 2250 MPEG Video Depayloader.
+	  * gst/rtp/gstrtpL16depay.h:
+	  * gst/rtp/gstrtph263pdepay.c: (gst_rtp_h263p_depay_setcaps),
+	  (gst_rtp_h263p_depay_process):
+	  Fix Header file. Small cleanups.
+	  * gst/rtp/gstrtpmp4gdepay.c: (gst_rtp_mp4g_depay_class_init),
+	  (gst_rtp_mp4g_depay_init), (gst_rtp_mp4g_depay_finalize),
+	  (gst_rtp_mp4g_depay_process), (gst_rtp_mp4g_depay_change_state):
+	  * gst/rtp/gstrtpmp4vdepay.c: (gst_rtp_mp4v_depay_class_init),
+	  (gst_rtp_mp4v_depay_init), (gst_rtp_mp4v_depay_finalize),
+	  (gst_rtp_mp4v_depay_setcaps), (gst_rtp_mp4v_depay_process),
+	  (gst_rtp_mp4v_depay_change_state):
+	  Remove usused code. Remove Adapter from state Change. Added debug.
+	  * gst/rtp/gstrtpmpadepay.c: (gst_rtp_mpa_depay_base_init),
+	  (gst_rtp_mpa_depay_class_init), (gst_rtp_mpa_depay_init),
+	  (gst_rtp_mpa_depay_setcaps), (gst_rtp_mpa_depay_process):
+	  * gst/rtp/gstrtpmpadepay.h:
+	  Subclass base depayloader.
+	  Added debug.
+	  Support static payload type assignment as well.
+	  * gst/rtp/gstrtpmpapay.c:
+	  Fix caps.
+
+2007-01-08 12:45:10 +0000  Vincent Torri <vtorri@univ-evry.fr>
+
+	  ext/jpeg/: These libjpeg callbacks should return a 'boolean' (unsigned char apparently) and not a 'gboolean' (which m...
+	  Original commit message from CVS:
+	  Patch by: Vincent Torri  <vtorri at univ-evry fr>
+	  * ext/jpeg/gstjpegdec.c:
+	  * ext/jpeg/gstjpegenc.c:
+	  * ext/jpeg/smokecodec.c:
+	  These libjpeg callbacks should return a 'boolean' (unsigned char
+	  apparently) and not a 'gboolean' (which maps to gint). Fixes
+	  warnings when compiling with MingW (#393427).
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_read):
+	  Use ioctlsocket on win32.
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_create):
+	  Some printf format fixes for win32.
+
+2007-01-07 22:03:54 +0000  Andy Wingo <wingo@pobox.com>
+
+	  New elements interleave and deinterleave, implement channel interleaving and deinterleaving.
+	  Original commit message from CVS:
+	  2007-01-07  Andy Wingo  <wingo@pobox.com>
+	  * configure.ac:
+	  * gst/interleave/Makefile.am:
+	  * gst/interleave/plugin.h:
+	  * gst/interleave/plugin.c:
+	  * gst/interleave/interleave.c:
+	  * gst/interleave/deinterleave.c: New elements interleave and
+	  deinterleave, implement channel interleaving and deinterleaving.
+	  The interleaver can operate in pull or push mode but the
+	  deinterleaver is more like a demuxer and can only operate in push
+	  mode.
+
+2007-01-07 10:44:12 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  gst/cutter/gstcutter.c: Use gst_guint64_to_gdouble for conversion.
+	  Original commit message from CVS:
+	  * gst/cutter/gstcutter.c: (gst_cutter_chain):
+	  Use gst_guint64_to_gdouble for conversion.
+	  * win32/vs6/libgstmatroska.dsp:
+	  Add zlib to the link.
+	  * win32/vs6/libgstvideobox.dsp:
+	  Update liboil library name (project is linked to liboil-0.3-0.lib now).
+
+2007-01-05 18:32:03 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Check for zlib and if available pass it explicitly to the linker when linking qtdemux. If not available (or --disable...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/qtdemux/Makefile.am:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_moov):
+	  Check for zlib and if available pass it explicitly to the linker
+	  when linking qtdemux. If not available (or --disable-external has
+	  been specified!), disable the bits in qtdemux that use it. Fixes
+	  build on MingW (#392856).
+
+2007-01-05 17:23:04 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/Makefile.am: If zlib is available and used, we must link it explicitly for things to work on MingW (fixe...
+	  Original commit message from CVS:
+	  * gst/matroska/Makefile.am:
+	  If zlib is available and used, we must link it explicitly for
+	  things to work on MingW (fixes #392855).
+
+2007-01-05 16:07:12 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/icles/videocrop-test.c: Call g_thread_init() right at the beginning. Remove superfluous gst_init() - we've alre...
+	  Original commit message from CVS:
+	  * tests/icles/videocrop-test.c: (main):
+	  Call g_thread_init() right at the beginning. Remove superfluous
+	  gst_init() - we've already been inited via the GOption stuff.
+
+2007-01-04 11:02:29 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/esd/esdsink.c: Don't return bogus values when esd_get_delay() fails for some reason (#392189).
+	  Original commit message from CVS:
+	  * ext/esd/esdsink.c: (gst_esdsink_delay):
+	  Don't return bogus values when esd_get_delay() fails for some
+	  reason (#392189).
+
+2007-01-04 09:44:57 +0000  Vincent Torri <vtorri@univ-evry.fr>
+
+	  Add directsoundsink to build and dist it, so it gets built when compiling with MingW on win32 and the required header...
+	  Original commit message from CVS:
+	  Patch by: Vincent Torri  <vtorri at univ-evry fr>
+	  * configure.ac:
+	  * sys/Makefile.am:
+	  * sys/directsound/Makefile.am:
+	  * sys/directsound/gstdirectsoundsink.c:
+	  (gst_directsoundsink_reset):
+	  Add directsoundsink to build and dist it, so it gets built when
+	  compiling with MingW on win32 and the required headers and libraries
+	  are available (fixes: #392638). Also simplify DirectDraw check a bit.
+	  * tests/check/elements/.cvsignore:
+	  Fix CVS ignore for neonhttpsrc test binary.
+
+2007-01-03 19:54:33 +0000  Vincent Torri <vtorri@univ-evry.fr>
+
+	  Add directdrawsink to build and dist it, so it gets built when compiling with MingW on win32 and the required headers...
+	  Original commit message from CVS:
+	  Patch by: Vincent Torri  <vtorri at univ-evry fr>
+	  * configure.ac:
+	  * sys/Makefile.am:
+	  * sys/directdraw/Makefile.am:
+	  Add directdrawsink to build and dist it, so it gets built when
+	  compiling with MingW on win32 and the required headers and libraries
+	  are available (fixes: #392313).
+	  * sys/directdraw/gstdirectdrawsink.c:
+	  (gst_directdrawsink_center_rect), (gst_directdrawsink_show_frame),
+	  (gst_directdrawsink_setup_ddraw),
+	  (gst_directdrawsink_surface_create):
+	  Comment out some unused things and fix some printf format issues in
+	  order to avoid warnings when buildling with MingW (#392313).
+
+2007-01-03 16:41:10 +0000  Jens Granseuer <jensgr@gmx.net>
+
+	  Fix build with gcc-2.x (declare variables at the beginning of a block etc.). Fixes #391971.
+	  Original commit message from CVS:
+	  Patch by: Jens Granseuer  <jensgr at gmx net>
+	  * ext/xvid/gstxvidenc.c: (gst_xvidenc_encode),
+	  (gst_xvidenc_get_property):
+	  * gst/filter/gstbpwsinc.c: (bpwsinc_transform_ip):
+	  * gst/filter/gstfilter.c: (plugin_init):
+	  * gst/filter/gstiir.c: (iir_transform_ip):
+	  * gst/filter/gstlpwsinc.c: (lpwsinc_transform_ip):
+	  * gst/modplug/gstmodplug.cc:
+	  * gst/nuvdemux/gstnuvdemux.c: (gst_nuv_demux_header_load),
+	  (gst_nuv_demux_stream_extend_header):
+	  Fix build with gcc-2.x (declare variables at the beginning of a
+	  block etc.). Fixes #391971.
+
+2006-12-30 12:44:01 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/check/elements/videocrop.c: When we can't create an element needed for the test, print a message detailing whic...
+	  Original commit message from CVS:
+	  * tests/check/elements/videocrop.c: (GST_START_TEST),
+	  (videocrop_test_cropping_init_context):
+	  When we can't create an element needed for the test, print a message
+	  detailing which element it actually is that's missing (#390673).
+
+2006-12-24 11:36:31 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/ximage/gstximagesrc.c: Fix presumably copy'n'pasto for 16bpp depth.
+	  Original commit message from CVS:
+	  * sys/ximage/gstximagesrc.c: (composite_pixel):
+	  Fix presumably copy'n'pasto for 16bpp depth.
+
+2006-12-24 11:24:59 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-mux.c: The "signed" field in audio caps is of boolean type, trying to use gst_structure_get_int...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_audio_pad_setcaps):
+	  The "signed" field in audio caps is of boolean type, trying to use
+	  gst_structure_get_int() to extract it will fail. Fixing this makes
+	  matroskamux accept raw audio input (#387121) (use at your own risk
+	  though, due to the matroska spec being not entirely useful in this
+	  respect).
+	  Also fix up raw audio structures in template caps so that they
+	  represent what our setcaps function will actually accept, so that
+	  converters know what to convert to.
+	  Finally, don't fail if there isn't an "endianness" field in 8-bit
+	  PCM caps.
+
+2006-12-22 10:15:24 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/check/elements/: reapply consistent pad (de)activation
+	  Original commit message from CVS:
+	  * tests/check/elements/mpeg2enc.c: (setup_mpeg2enc),
+	  (cleanup_mpeg2enc):
+	  * tests/check/elements/rganalysis.c: (cleanup_rganalysis):
+	  * tests/check/elements/wavpackdec.c: (setup_wavpackdec),
+	  (cleanup_wavpackdec):
+	  * tests/check/elements/wavpackenc.c: (setup_wavpackenc),
+	  (cleanup_wavpackenc):
+	  * tests/check/elements/y4menc.c: (setup_y4menc), (cleanup_y4menc):
+	  reapply consistent pad (de)activation
+
+2006-12-22 10:15:23 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/check/elements/: reapply consistent pad (de)activation
+	  Original commit message from CVS:
+	  * tests/check/elements/audiopanorama.c: (cleanup_panorama):
+	  * tests/check/elements/avimux.c: (setup_avimux), (cleanup_avimux):
+	  * tests/check/elements/cmmldec.c: (setup_cmmldec),
+	  (teardown_cmmldec):
+	  * tests/check/elements/cmmlenc.c: (setup_cmmlenc),
+	  (teardown_cmmlenc):
+	  * tests/check/elements/level.c: (setup_level), (cleanup_level):
+	  reapply consistent pad (de)activation
+
+2006-12-21 17:03:39 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Back to CVS
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Back to CVS
+	  * gst-plugins-good.doap:
+	  Add 0.10.5 doap entry
+
+=== release 0.10.4 ===
+
+2006-12-21 15:45:02 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: releasing 0.10.4, "Black Bugs"
+	  Original commit message from CVS:
+	  === release 0.10.4 ===
+	  2006-12-21  Jan Schmidt <thaytan@mad.scientist.com>
+	  * configure.ac:
+	  releasing 0.10.4, "Black Bugs"
+
+=== release 0.10.5 ===
+
+2006-12-21 15:40:55 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: releasing 0.10.5, "The Path of Thorns"
+	  Original commit message from CVS:
+	  === release 0.10.5 ===
+	  2006-12-21  Jan Schmidt <thaytan@mad.scientist.com>
+	  * configure.ac:
+	  releasing 0.10.5, "The Path of Thorns"
+
+2006-12-21 14:03:42 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/check/elements/mpeg2enc.c: (setup_mpeg2enc)
+	  Original commit message from CVS:
+	  * tests/check/elements/mpeg2enc.c: (setup_mpeg2enc)
+	  (cleanup_mpeg2enc):
+	  * tests/check/elements/rganalysis.c: (cleanup_rganalysis):
+	  * tests/check/elements/wavpackdec.c: (setup_wavpackdec),
+	  (cleanup_wavpackdec):
+	  * tests/check/elements/wavpackenc.c: (setup_wavpackenc),
+	  (cleanup_wavpackenc):
+	  * tests/check/elements/y4menc.c: (setup_y4menc), (cleanup_y4menc):
+	  revert my freeze breakage
+
+2006-12-21 12:48:32 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/check/elements/: revert my freeze breakage
+	  Original commit message from CVS:
+	  * tests/check/elements/audiopanorama.c: (cleanup_panorama):
+	  * tests/check/elements/avimux.c: (setup_avimux), (cleanup_avimux):
+	  * tests/check/elements/cmmldec.c: (setup_cmmldec),
+	  (teardown_cmmldec):
+	  * tests/check/elements/cmmlenc.c: (setup_cmmlenc),
+	  (teardown_cmmlenc):
+	  * tests/check/elements/level.c: (setup_level), (cleanup_level):
+	  revert my freeze breakage
+
+2006-12-21 08:20:10 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/check/elements/: consistent pad (de)activation
+	  Original commit message from CVS:
+	  * tests/check/elements/mpeg2enc.c: (setup_mpeg2enc),
+	  (cleanup_mpeg2enc):
+	  * tests/check/elements/rganalysis.c: (cleanup_rganalysis):
+	  * tests/check/elements/wavpackdec.c: (setup_wavpackdec),
+	  (cleanup_wavpackdec):
+	  * tests/check/elements/wavpackenc.c: (setup_wavpackenc),
+	  (cleanup_wavpackenc):
+	  * tests/check/elements/y4menc.c: (setup_y4menc), (cleanup_y4menc):
+	  consistent pad (de)activation
+
+2006-12-21 08:15:23 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/check/elements/: consistent pad (de)activation
+	  Original commit message from CVS:
+	  * tests/check/elements/audiopanorama.c: (cleanup_panorama):
+	  * tests/check/elements/avimux.c: (setup_avimux), (cleanup_avimux):
+	  * tests/check/elements/cmmldec.c: (setup_cmmldec),
+	  (teardown_cmmldec):
+	  * tests/check/elements/cmmlenc.c: (setup_cmmlenc),
+	  (teardown_cmmlenc):
+	  * tests/check/elements/level.c: (setup_level), (cleanup_level):
+	  consistent pad (de)activation
+
+2006-12-18 17:11:49 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Don't post BUFFERING messages in streaming mode if the stream headers are behind the movie dat...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_post_progress),
+	  (gst_qtdemux_chain):
+	  Don't post BUFFERING messages in streaming mode if the stream
+	  headers are behind the movie data; instead, post "progress" element
+	  messages as a temporary solution. Apps might get confused and do
+	  silly things to the pipeline state if they see buffering messages
+	  from different sources and don't realize they come from different
+	  sources (#387160).
+
+2006-12-18 16:46:17 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Disable LADPSA, as it has moved to the -bad module for the duration.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * ext/Makefile.am:
+	  Disable LADPSA, as it has moved to the -bad module for the duration.
+
+2006-12-18 15:51:54 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/ladspa/gstsignalprocessor.c: Reset flow_state back to _OK after a flush stop so that we exit our error state afte...
+	  Original commit message from CVS:
+	  * ext/ladspa/gstsignalprocessor.c: (gst_signal_processor_setcaps),
+	  (gst_signal_processor_event):
+	  Reset flow_state back to _OK after a flush stop so that we exit our
+	  error state after the flush. Fixes #374213
+
+2006-12-18 15:49:08 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ChangeLog surgery on one of Stefan's commits from August:
+	  Original commit message from CVS:
+	  ChangeLog surgery on one of Stefan's commits from August:
+	  * ext/Makefile.am:
+	  Quietly (accidentally) enable LADSPA for building by default,
+	  despite the fact that it doesn't meet the plugin checklist.
+	  -- Added by Jan Schmidt 18 Dec 2006
+
+2006-12-18 13:40:34 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/qtdemux/qtdemux.c: Don't output g_warning for an unsupported format, just send a
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_chain),
+	  (gst_qtdemux_add_stream):
+	  Don't output g_warning for an unsupported format, just send a
+	  GST_ELEMENT_WARNING and don't add the pad.
+	  Fix the case where it doesn't check for a NULL pad in streaming mode.
+	  Fixes #387137
+
+2006-12-18 12:27:32 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Fix crash dereferencing NULL pointer if there's no stco atom.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_trak):
+	  Fix crash dereferencing NULL pointer if there's no stco atom.
+	  Fixes #387122.
+
+2006-12-18 10:02:56 +0000  Sebastian Dröge <slomo@ubuntu.com>
+
+	  ext/wavpack/gstwavpackenc.h: Use local copy of md5.h, as it disappeared in recent wavpack installs.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackenc.h:
+	  Use local copy of md5.h, as it disappeared in recent wavpack
+	  installs.
+	  Patch by: Sebastian Dröge <slomo at ubuntu dot com>
+	  Fixes: #387076
+
+2006-12-17 19:42:05 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	  Update .po files
+	  Original commit message from CVS:
+	  Update .po files
+
+2006-12-17 06:11:39 +0000  David Schleef <ds@schleef.org>
+
+	  sys/osxvideo/osxvideosink.*: Decent effort at porting to 0.10.  Needs cleanup on OS/X.
+	  Original commit message from CVS:
+	  * sys/osxvideo/osxvideosink.h:
+	  * sys/osxvideo/osxvideosink.m:
+	  Decent effort at porting to 0.10.  Needs cleanup on OS/X.
+
+2006-12-17 05:07:07 +0000  Vijay Santhanam <vijay@santhanam.gmail.com>
+
+	  sys/osxvideo/: Preliminary patch for porting osxvideosink
+	  Original commit message from CVS:
+	  Patch by: Vijay Santhanam <vijay santhanam gmail com>
+	  * sys/osxvideo/Makefile.am:
+	  * sys/osxvideo/osxvideosink.h:
+	  * sys/osxvideo/osxvideosink.m:
+	  Preliminary patch for porting osxvideosink
+
+2006-12-16 16:21:26 +0000  Sjoerd Simons <sjoerd@luon.net>
+
+	  gst/videomixer/videomixer.c: Introduce some locking around the videomixer state so that it does not crash when adding...
+	  Original commit message from CVS:
+	  Patch by: Sjoerd Simons <sjoerd at luon dot net>
+	  * gst/videomixer/videomixer.c: (gst_videomixer_pad_set_property),
+	  (gst_videomixer_set_master_geometry),
+	  (gst_videomixer_pad_sink_setcaps), (gst_videomixer_collect_free),
+	  (gst_videomixer_reset), (gst_videomixer_init),
+	  (gst_videomixer_finalize), (gst_videomixer_request_new_pad),
+	  (gst_videomixer_release_pad), (gst_videomixer_collected),
+	  (gst_videomixer_change_state):
+	  Introduce some locking around the videomixer state so that it does not
+	  crash when adding/removing pads. Fixes #383043.
+
+2006-12-16 15:25:23 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: We don't support seeking in streaming mode, so don't even try.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_get_src_query_types),
+	  (gst_qtdemux_handle_src_query), (gst_qtdemux_handle_src_event):
+	  We don't support seeking in streaming mode, so don't even try.
+	  Implement seeking query so apps can query seekability properly
+	  (see #365414). Fix duration query.
+
+2006-12-16 11:42:56 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Make sure libcaca can actually be used instead of just checking for /usr/bin/caca-config, so we don't w...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Make sure libcaca can actually be used instead of just checking for
+	  /usr/bin/caca-config, so we don't wrongly try to build cacasink when
+	  cross-compiling (fixes #384587).
+
+2006-12-15 10:54:28 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  adding doap file
+	  Original commit message from CVS:
+	  * Makefile.am:
+	  * gst-plugins-good.doap:
+	  * gst-plugins-good.spec.in:
+	  adding doap file
+
+2006-12-14 16:20:15 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: libflac-1.1.3 changed API again, but we can't build against it yet, so make sure our check doesn't use ...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  libflac-1.1.3 changed API again, but we can't build against it yet,
+	  so make sure our check doesn't use libflac-1.1.3 and add a comment
+	  to this effect.
+
+2006-12-14 14:25:17 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/effectv/gstquark.c: Add some NULL pointer checks (possibly related to #385623).
+	  Original commit message from CVS:
+	  * gst/effectv/gstquark.c: (gst_quarktv_transform),
+	  (gst_quarktv_planetable_clear):
+	  Add some NULL pointer checks (possibly related to #385623).
+
+2006-12-13 17:12:22 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Add AMR-WB to the list of supported formats.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_get_duration),
+	  (gst_qtdemux_handle_src_query), (qtdemux_parse_trak),
+	  (qtdemux_audio_caps):
+	  Add AMR-WB to the list of supported formats.
+
+2006-12-12 18:45:58 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/: In streaming mode, if the first buffer we get doesn't have an offset, fix it up to be 0, otherwise trimming won...
+	  Original commit message from CVS:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_chain_parse_tag),
+	  (gst_tag_demux_chain):
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_chain):
+	  In streaming mode, if the first buffer we get doesn't have an
+	  offset, fix it up to be 0, otherwise trimming won't work later on
+	  and we'll be typefinding application/x-id3, which may result in
+	  decodebin plugging an endless number of id3demux elements as a
+	  consequence. Fixes #385031.
+
+2006-12-11 21:21:16 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  sys/sunaudio/gstsunaudiosink.c: Ignore the buffer_time the sound device reports. Turns out it is sometimes completely...
+	  Original commit message from CVS:
+	  * sys/sunaudio/gstsunaudiosink.c: (gst_sunaudiosink_prepare):
+	  Ignore the buffer_time the sound device reports. Turns out it is
+	  sometimes completely bogus and we're better off without it.
+
+2006-12-11 17:33:26 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Fix non-working redirects from inetfilm.com (handle 'alis' reference data type as well). Fixes...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_tree):
+	  Fix non-working redirects from inetfilm.com (handle 'alis' reference
+	  data type as well). Fixes #378613.
+
+2006-12-11 13:59:33 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/: Try harder to extract the framerate for video tracks correctly and save it directly instead of convert...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream),
+	  (gst_matroska_demux_video_caps):
+	  * gst/matroska/matroska-ids.c:
+	  (gst_matroska_track_init_video_context):
+	  * gst/matroska/matroska-ids.h:
+	  Try harder to extract the framerate for video tracks correctly and
+	  save it directly instead of converting it back and forth a few
+	  times. Mostly makes a difference for very small framerates (<1).
+	  Fixes #380199.
+
+2006-12-11 11:41:18 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/gconf/gstgconfaudiosrc.*: Remove gconf notify hook when the gconfaudiosrc element is destroyed, otherwise the cal...
+	  Original commit message from CVS:
+	  * ext/gconf/gstgconfaudiosrc.c: (gst_gconf_audio_src_init),
+	  (gst_gconf_audio_src_dispose), (do_toggle_element):
+	  * ext/gconf/gstgconfaudiosrc.h:
+	  Remove gconf notify hook when the gconfaudiosrc element is
+	  destroyed, otherwise the callback may be called on an
+	  already-destroyed instance and bad things happen. Should fix
+	  #378184.
+	  Also ignore gconf key changes when the source is already running.
+
+2006-12-09 19:27:28 +0000  Sebastian Dröge <mail@slomosnail.de>
+
+	  gst/apetag/gstapedemux.c: We need to be able to read and parse any possible floating point string format ("1,234" or ...
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge  <mail at slomosnail de>
+	  * gst/apetag/gstapedemux.c: (ape_demux_parse_tags):
+	  We need to be able to read and parse any possible floating point string
+	  format ("1,234" or "1.234") irrespective of the current locale. g_strod()
+	  will parse the former only in certain locales though, so we really need
+	  to canonicalise the separator to '.' and then use g_ascii_strtod() to
+	  make sure we can parse either version at all times.
+	  Fixes #382982 for real.
+
+2006-12-09 16:17:33 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  sys/sunaudio/: Use the sunaudio debug category.
+	  Original commit message from CVS:
+	  * sys/sunaudio/gstsunaudiomixerctrl.c:
+	  * sys/sunaudio/gstsunaudiosrc.c:
+	  Use the sunaudio debug category.
+	  * sys/sunaudio/gstsunaudiosink.c: (gst_sunaudiosink_finalize),
+	  (gst_sunaudiosink_class_init), (gst_sunaudiosink_init),
+	  (gst_sunaudiosink_set_property), (gst_sunaudiosink_get_property),
+	  (gst_sunaudiosink_open), (gst_sunaudiosink_close),
+	  (gst_sunaudiosink_prepare), (gst_sunaudio_sink_do_delay),
+	  (gst_sunaudiosink_write), (gst_sunaudiosink_delay),
+	  (gst_sunaudiosink_reset):
+	  * sys/sunaudio/gstsunaudiosink.h:
+	  Uses the sunaudio debug category for all debug output
+	  Implements the _delay() callback to synchronise video playback better
+	  Change the segtotal and segsize values back to the parent class
+	  defaults (taken from buffer_time and latency_times of 200ms and 10ms
+	  respectively)
+	  Measure the samples written to the device vs. played.
+	  Keep track of segments in the device by writing empty eof frames, and
+	  sleep using a GCond when we get too far ahead and risk overrunning the
+	  sink's ringbuffer.
+	  Fixes: #360673
+
+2006-12-08 21:12:47 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	  Correct the attribution of the previous commit. The patch in question was written by Brian Cameron.
+	  Original commit message from CVS:
+	  Correct the attribution of the previous commit. The patch in
+	  question was written by Brian Cameron.
+
+2006-12-08 17:06:43 +0000  René Stadler <mail@renestadler.de>
+
+	  gst/qtdemux/qtdemux.c: Fix caps for 24 bit raw PCM audio (2).
+	  Original commit message from CVS:
+	  Patch by: René Stadler  <mail at renestadler de>
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_get_duration),
+	  (gst_qtdemux_handle_src_query), (qtdemux_parse_trak),
+	  (qtdemux_audio_caps):
+	  Fix caps for 24 bit raw PCM audio (2).
+	  Fixes #383471.
+
+2006-12-08 16:38:18 +0000  Sebastian Dröge <mail@slomosnail.de>
+
+	  gst/audiofx/audiopanorama.*: Fix audiopanorame with float samples. Fixes #383726.
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge  <mail at slomosnail de >
+	  * gst/audiofx/audiopanorama.c: (gst_audio_panorama_init),
+	  (gst_audio_panorama_set_caps), (gst_audio_panorama_transform):
+	  * gst/audiofx/audiopanorama.h:
+	  Fix audiopanorame with float samples. Fixes #383726.
+
+2006-12-08 15:12:01 +0000  Padraig O'Briain <padraig.obriain@sun.com>
+
+	  sys/sunaudio/: Implement reset functions to unblock the src/sink more quickly on state change requests.
+	  Original commit message from CVS:
+	  * sys/sunaudio/gstsunaudiosink.c: (gst_sunaudiosink_reset):
+	  * sys/sunaudio/gstsunaudiosrc.c: (gst_sunaudiosrc_open),
+	  (gst_sunaudiosrc_reset):
+	  Implement reset functions to unblock the src/sink more quickly on
+	  state change requests.
+	  Patch by: Padraig O'Briain <padraig dot obriain at sun dot com>
+
+2006-12-08 14:42:42 +0000  Jerry Tan <jerry.tan@sun.com>
+
+	  sys/sunaudio/gstsunaudiomixer.c: Construct the correct mixer device name when the AUDIODEV env var is set.
+	  Original commit message from CVS:
+	  * sys/sunaudio/gstsunaudiomixer.c:
+	  (gst_sunaudiomixer_change_state):
+	  Construct the correct mixer device name when the AUDIODEV env var
+	  is set.
+	  Patch by: Jerry Tan <jerry.tan at sun dot com>
+	  Fixes: #383596
+
+2006-12-08 14:32:51 +0000  Jerry Tan <jerry.tan@sun.com>
+
+	  sys/sunaudio/gstsunaudiosrc.c: Apply patch to open the mixer control and set the MULTIPLE_OPEN ioctl. On solaris, the...
+	  Original commit message from CVS:
+	  * sys/sunaudio/gstsunaudiosrc.c: (gst_sunaudiosrc_open):
+	  Apply patch to open the mixer control and set the MULTIPLE_OPEN
+	  ioctl. On solaris, the mixer device doesn't need opening non-blocking
+	  - it can be opened by multiple processes by default, but needs the ioctl 	for multiple opens within 1 process.
+	  Patch by: Jerry Tan <jerry.tan at sun dot com>
+	  Fixes: #349015
+
+2006-12-07 17:30:03 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/smpte/: Port to 0.10 some more.
+	  Original commit message from CVS:
+	  * gst/smpte/gstmask.h:
+	  * gst/smpte/gstsmpte.c: (gst_smpte_class_init),
+	  (gst_smpte_setcaps), (gst_smpte_init), (gst_smpte_reset),
+	  (gst_smpte_collected), (gst_smpte_set_property),
+	  (gst_smpte_get_property), (gst_smpte_change_state), (plugin_init):
+	  * gst/smpte/gstsmpte.h:
+	  Port to 0.10 some more.
+	  Added duration property to specify the duration of the transition.
+	  Make framerate a fraction.
+	  Deprecate fps property, we only use negotiated fps.
+	  Added docs.
+	  Fix collectpad usage.
+	  Reset state in READY.
+	  Send NEWSEGMENT event.
+	  Fix racy updates of object properties.
+	  Added debug category.
+	  Fixes #383323.
+
+2006-12-07 11:35:41 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Handle more H263 variants.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_get_duration),
+	  (gst_qtdemux_handle_src_query), (qtdemux_parse_trak),
+	  (qtdemux_video_caps):
+	  Handle more H263 variants.
+
+2006-12-06 15:06:04 +0000  Sjoerd Simons <sjoerd@luon.net>
+
+	  gst/videomixer/videomixer.c: Don't reset xpos and ypos in the setcaps function because causes unexpected behaviour.
+	  Original commit message from CVS:
+	  Patch by: Sjoerd Simons <sjoerd at luon dot net>
+	  * gst/videomixer/videomixer.c:
+	  (gst_videomixer_set_master_geometry),
+	  (gst_videomixer_pad_sink_setcaps), (gst_videomixer_collect_free):
+	  Don't reset xpos and ypos in the setcaps function because causes
+	  unexpected behaviour.
+	  Fixes #382179.
+
+2006-12-06 14:45:30 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/multipart/multipartmux.c: Keep track of the buffer timestamp in the collectdata member instead of modifying the b...
+	  Original commit message from CVS:
+	  * gst/multipart/multipartmux.c: (gst_multipart_mux_compare_pads),
+	  (gst_multipart_mux_queue_pads), (gst_multipart_mux_collected):
+	  Keep track of the buffer timestamp in the collectdata member instead
+	  of modifying the buffer without making the metadata writable first.
+	  Fixes #382277.
+
+2006-12-06 14:33:54 +0000  Rob Taylor <robtaylor@floopily.org>
+
+	  gst/udp/gstudpsrc.c: If using multicast in udpsrc, bind to the multicast address rather than
+	  Original commit message from CVS:
+	  Patch by: Rob Taylor <robtaylor at floopily dot org>
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_start):
+	  If using multicast in udpsrc, bind to the multicast address rather than
+	  IN_ADDR_ANY.
+	  This allows the simultanous use of multiple udpsrcs listening on
+	  different multicat addresses. Without this all udpsrcs will receive all
+	  packets from all subscribed multicast addresses.
+	  Fixes #383001.
+
+2006-12-06 13:35:52 +0000  Jonathan Matthew <jonathan@0kaolin.wh9.net>
+
+	  ext/taglib/gstid3v2mux.cc: Don't attempt to write a NULL frame into the ID3 tag set when the createFrame method retur...
+	  Original commit message from CVS:
+	  * ext/taglib/gstid3v2mux.cc:
+	  Don't attempt to write a NULL frame into the ID3 tag set when the
+	  createFrame method returned NULL.
+	  Fixes: #381857
+	  Patch by: Jonathan Matthew <jonathan at 0kaolin wh9 net >
+
+2006-12-06 13:16:59 +0000  Sebastian Dröge <mail@slomosnail.de>
+
+	  gst/apetag/gstapedemux.c: Use g_strtod() instead of sscanf to parse doubles, so that it will try parsing in the C loc...
+	  Original commit message from CVS:
+	  * gst/apetag/gstapedemux.c: (ape_demux_parse_tags):
+	  Use g_strtod() instead of sscanf to parse doubles, so that it will
+	  try parsing in the C locale if the current locale fails.
+	  Fixes: #382982
+	  Patch by: Sebastian Dröge  <mail at slomosnail de >
+
+2006-12-01 10:31:46 +0000  Sergey Scobich <sergey.scobich@gmail.com>
+
+	  win32/MANIFEST: Fix compilation on win32 under VS8
+	  Original commit message from CVS:
+	  * win32/MANIFEST:
+	  Fix compilation on win32 under VS8
+	  Patch by: Sergey Scobich <sergey dot scobich at gmail dot com>
+	  Partially fixes #381175
+
+2006-11-30 16:48:51 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavimux.c: accept all mpegversions,fixes #380825 spotted by: Jerome Alet
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c:
+	  accept all mpegversions,fixes #380825
+	  spotted by: Jerome Alet
+
+2006-11-30 16:46:13 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/v4l2/v4l2src_calls.c: cleanup the error message a bit more
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list),
+	  (gst_v4l2src_queue_frame), (gst_v4l2src_grab_frame),
+	  (gst_v4l2src_get_capture), (gst_v4l2src_set_capture),
+	  (gst_v4l2src_capture_init), (gst_v4l2src_buffer_finalize):
+	  cleanup the error message a bit more
+
+2006-11-30 15:08:08 +0000  René Stadler <mail@renestadler.de>
+
+	  gst/replaygain/gstrganalysis.c: Call the base class handler.  Fixes #380610.
+	  Original commit message from CVS:
+	  Patch by: René Stadler  <mail at renestadler de>
+	  * gst/replaygain/gstrganalysis.c: (gst_rg_analysis_event):
+	  Call the base class handler.  Fixes #380610.
+
+2006-11-28 12:30:10 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/libcaca/gstcacasink.c: Fix width and height properties.
+	  Original commit message from CVS:
+	  * ext/libcaca/gstcacasink.c: (gst_cacasink_class_init):
+	  Fix width and height properties.
+	  * ext/libcaca/gstcacasink.h:
+	  Fix compilation on newer libcaca that require us to include a new
+	  header. Fixes #379918.
+
+2006-11-28 11:52:27 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/: Add method so that extensions can choose to disable the setup of a stream.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_open):
+	  * gst/rtsp/gstrtspsrc.h:
+	  * gst/rtsp/rtspext.h:
+	  * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_configure_stream),
+	  (rtsp_ext_wms_get_context):
+	  Add method so that extensions can choose to disable the setup of
+	  a stream.
+	  Make the WMS extension skip setup of x-wms-rtx streams. Fixes #377792.
+
+2006-11-27 17:16:26 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Remove some asserts and replace them with a proper error message. Fixes #379261.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_get_duration),
+	  (gst_qtdemux_handle_src_query), (qtdemux_parse_trak):
+	  Remove some asserts and replace them with a proper error
+	  message. Fixes #379261.
+
+2006-11-27 16:30:49 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	* ChangeLog:
+	  mention bug fix
+	  Original commit message from CVS:
+	  mention bug fix
+
+2006-11-27 16:29:07 +0000  Jonas Holmberg <jonas.holmberg@axis.com>
+
+	  gst/multipart/multipartmux.c: Push header in a separate buffer instead of memcpy:ing all data
+	  Original commit message from CVS:
+	  Patch by: Jonas Holmberg <jonas dot holmberg at axis dot com>
+	  * gst/multipart/multipartmux.c: (gst_multipart_mux_collected):
+	  Push header in a separate buffer instead of memcpy:ing all data
+	  Change LF => CRLF in headers
+	  Move trailing LF to header
+
+2006-11-27 16:26:50 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmpadepay.c: Small buffer overflow fix and improve debugging.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmpadepay.c: (gst_rtp_mpa_depay_chain):
+	  Small buffer overflow fix and improve debugging.
+
+2006-11-24 08:58:53 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/esd/: remove obsolete _factory_init protos
+	  Original commit message from CVS:
+	  * ext/esd/esdmon.h:
+	  * ext/esd/esdsink.h:
+	  remove obsolete _factory_init protos
+
+2006-11-24 07:46:54 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.c: remove dead code, tweak debugs statements, add comments, use _uint64_scale instead _uint64_sca...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_index_entry_for_time),
+	  (gst_avi_demux_src_convert), (gst_avi_demux_handle_src_query),
+	  (gst_avi_demux_peek_chunk), (gst_avi_demux_parse_subindex),
+	  (gst_avi_demux_read_subindexes_push),
+	  (gst_avi_demux_read_subindexes_pull), (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_parse_index), (gst_avi_demux_stream_index),
+	  (gst_avi_demux_sync), (gst_avi_demux_next_data_buffer),
+	  (gst_avi_demux_massage_index),
+	  (gst_avi_demux_calculate_durations_from_index),
+	  (gst_avi_demux_stream_header_pull), (gst_avi_demux_do_seek),
+	  (gst_avi_demux_handle_seek), (gst_avi_demux_process_next_entry),
+	  (gst_avi_demux_stream_data), (gst_avi_demux_loop):
+	  remove dead code, tweak debugs statements, add comments, use
+	  _uint64_scale instead _uint64_scale_int when using guint64 values,
+	  small optimizations, reflow some error handling
+
+2006-11-22 17:39:13 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  po/.cvsignore: We never put .pot files in cvs. Let's ignore them all.
+	  Original commit message from CVS:
+	  * po/.cvsignore:
+	  We never put .pot files in cvs. Let's ignore them all.
+
+2006-11-21 12:57:50 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  enalbe LADSPA plugin in spec file
+	  Original commit message from CVS:
+	  enalbe LADSPA plugin in spec file
+
+2006-11-19 18:46:03 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  po/POTFILES.in: ... but better exclude files that aren't disted.
+	  Original commit message from CVS:
+	  * po/POTFILES.in:
+	  ... but better exclude files that aren't disted.
+
+2006-11-19 16:32:49 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  po/POTFILES.in: Add v4l2 source files to list of files with translations, so the strings are actually extracted (howe...
+	  Original commit message from CVS:
+	  * po/POTFILES.in:
+	  Add v4l2 source files to list of files with translations, so the
+	  strings are actually extracted (however bad they still may be).
+
+2006-11-19 16:30:19 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/videobox/gstvideobox.c: Minor clean-ups: const-ify static array, remove trailing comma from use GST_DEBUG_FUNCPTR.
+	  Original commit message from CVS:
+	  * gst/videobox/gstvideobox.c: (gst_video_box_class_init):
+	  Minor clean-ups: const-ify static array, remove trailing comma from
+	  last enum (gcc-2.9x trips over that), use GST_DEBUG_FUNCPTR.
+
+2006-11-19 13:41:53 +0000  René Stadler <mail@renestadler.de>
+
+	  gst/id3demux/id3v2frames.c: Make sure that g_free always gets called on the same pointer that was returned by g_mallo...
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (id3demux_id3v2_parse_frame):
+	  Make sure that g_free always gets called on the same pointer that was
+	  returned by g_malloc.  Fixes #376594.
+	  Do not leak memory if decompressed size is wrong.
+	  Remove unneeded check of return value of g_malloc.
+	  Patch by: René Stadler <mail@renestadler.de>
+
+2006-11-18 18:14:34 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/v4l2/v4l2src_calls.c: Add missing curly brackets.
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_capture_deinit):
+	  Add missing curly brackets.
+
+2006-11-17 14:54:01 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* sys/v4l2/v4l2src_calls.c:
+	  Fix capture_deinit.
+	  Original commit message from CVS:
+	  Fix capture_deinit.
+
+2006-11-16 15:36:48 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-mux.c: Use GST_DEBUG_FUNCPTR; activate request pad before returning it.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_class_init),
+	  (gst_matroska_mux_request_new_pad):
+	  Use GST_DEBUG_FUNCPTR; activate request pad before returning it.
+	  * tests/check/elements/matroskamux.c: (setup_src_pad),
+	  (setup_sink_pad), (GST_START_TEST):
+	  Activate pads before using them.
+
+2006-11-16 15:04:55 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavidemux.c: Initialise variable to get rid of bogus compiler warning.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_stream_scan):
+	  Initialise variable to get rid of bogus compiler warning.
+
+2006-11-16 07:26:17 +0000  Ville Syrjala <ville.syrjala@movial.fi>
+
+	  gst/rtp/: Specify H.263 variant and version in the caps (fixes #361637)
+	  Original commit message from CVS:
+	  Patch by: Ville Syrjala <ville.syrjala@movial.fi>
+	  * gst/rtp/gstrtph263pay.c:
+	  * gst/rtp/gstrtph263pdepay.c:
+	  * gst/rtp/gstrtph263ppay.c:
+	  Specify H.263 variant and version in the caps (fixes #361637)
+
+2006-11-15 17:44:01 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/rtspconnection.c: Don't set a data pointer to NULL and a size > 0 when we deal with empty packets.
+	  Original commit message from CVS:
+	  * gst/rtsp/rtspconnection.c: (read_body):
+	  Don't set a data pointer to NULL and a size > 0 when we deal
+	  with empty packets.
+	  * gst/rtsp/rtspmessage.c: (rtsp_message_new_response),
+	  (rtsp_message_init_response), (rtsp_message_init_data),
+	  (rtsp_message_unset), (rtsp_message_free),
+	  (rtsp_message_take_body):
+	  Check that we can't create invalid empty packets.
+
+2006-11-15 12:35:46 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/: Some small clean-ups: use enums instead of hard-coded numbers, const-ify element details, re-factor som...
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge  <slomo@circular-chaos.org>
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_reset),
+	  (gst_wavpack_dec_init), (gst_wavpack_dec_change_state):
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_base_init),
+	  (gst_wavpack_enc_class_init), (gst_wavpack_enc_reset),
+	  (gst_wavpack_enc_init), (gst_wavpack_enc_set_wp_config),
+	  (gst_wavpack_enc_change_state):
+	  * ext/wavpack/gstwavpackparse.c:
+	  Some small clean-ups: use enums instead of hard-coded numbers,
+	  const-ify element details, re-factor some code into _reset()
+	  functions (#352605).
+
+2006-11-15 12:08:20 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  gst/matroska/matroska-mux.*: Add basic tag writing support; implement releasing pads (#374658).
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts  <manauw at skynet be>
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_add_interfaces),
+	  (gst_matroska_mux_class_init), (gst_matroska_pad_free),
+	  (gst_matroska_mux_reset), (gst_matroska_mux_handle_sink_event),
+	  (gst_matroska_mux_request_new_pad), (gst_matroska_mux_release_pad),
+	  (gst_matroska_mux_track_header), (gst_matroska_mux_start),
+	  (gst_matroska_mux_write_simple_tag), (gst_matroska_mux_finish):
+	  * gst/matroska/matroska-mux.h:
+	  Add basic tag writing support; implement releasing pads (#374658).
+
+2006-11-15 11:19:13 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-demux.c: Handle opaque/unspecified A_AAC audio codec ID (fixes #374737).
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream),
+	  (gst_matroska_demux_audio_caps):
+	  Handle opaque/unspecified A_AAC audio codec ID (fixes #374737).
+
+2006-11-15 00:12:19 +0000  David Schleef <ds@schleef.org>
+
+	  gst/matroska/matroska-mux.c: Add Dirac fourcc.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c: Add Dirac fourcc.
+
+2006-11-14 20:07:22 +0000  Sergey Scobich <sergey.scobich@gmail.com>
+
+	  win32/vs8/: Make end-of-line returns unixy, so that when the files are checked out on win32 the line returns will be ...
+	  Original commit message from CVS:
+	  Patch by: Sergey Scobich  <sergey.scobich at gmail com>
+	  * win32/vs8/gst-plugins-good.sln:
+	  * win32/vs8/libgst1394.vcproj:
+	  * win32/vs8/libgstaasink.vcproj:
+	  * win32/vs8/libgstalaw.vcproj:
+	  * win32/vs8/libgstalpha.vcproj:
+	  * win32/vs8/libgstalphacolor.vcproj:
+	  * win32/vs8/libgstannodex.vcproj:
+	  * win32/vs8/libgstapetag.vcproj:
+	  * win32/vs8/libgstaudiofx.vcproj:
+	  * win32/vs8/libgstauparse.vcproj:
+	  * win32/vs8/libgstautodetect.vcproj:
+	  * win32/vs8/libgstavi.vcproj:
+	  * win32/vs8/libgstcacasink.vcproj:
+	  * win32/vs8/libgstcdio.vcproj:
+	  * win32/vs8/libgstcutter.vcproj:
+	  * win32/vs8/libgstdv.vcproj:
+	  * win32/vs8/libgsteffectv.vcproj:
+	  * win32/vs8/libgstflac.vcproj:
+	  * win32/vs8/libgstflxdec.vcproj:
+	  * win32/vs8/libgstgoom.vcproj:
+	  * win32/vs8/libgsticydemux.vcproj:
+	  * win32/vs8/libgstid3demux.vcproj:
+	  * win32/vs8/libgstjpeg.vcproj:
+	  * win32/vs8/libgstladspa.vcproj:
+	  * win32/vs8/libgstlevel.vcproj:
+	  * win32/vs8/libgstmatroska.vcproj:
+	  * win32/vs8/libgstmikmod.vcproj:
+	  * win32/vs8/libgstmng.vcproj:
+	  * win32/vs8/libgstmonoscope.vcproj:
+	  * win32/vs8/libgstmulaw.vcproj:
+	  * win32/vs8/libgstmultipart.vcproj:
+	  * win32/vs8/libgstpng.vcproj:
+	  * win32/vs8/libgstrtp.vcproj:
+	  * win32/vs8/libgstrtsp.vcproj:
+	  * win32/vs8/libgstshout2.vcproj:
+	  * win32/vs8/libgstsmpte.vcproj:
+	  * win32/vs8/libgstspeex.vcproj:
+	  * win32/vs8/libgsttaglib.vcproj:
+	  * win32/vs8/libgstudp.vcproj:
+	  * win32/vs8/libgstvideobalance.vcproj:
+	  * win32/vs8/libgstvideobox.vcproj:
+	  * win32/vs8/libgstvideoflip.vcproj:
+	  * win32/vs8/libgstvideomixer.vcproj:
+	  * win32/vs8/libgstwavenc.vcproj:
+	  * win32/vs8/libgstwavparse.vcproj:
+	  Make end-of-line returns unixy, so that when the files are checked
+	  out on win32 the line returns will be 0d 0a and not 0d 0d 0a.
+	  Hopefully fixes #366492.
+
+2006-11-14 15:55:32 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: Disable init_frames delay timestamp adjustment, it does not seem to be needed at all. Fixes #3...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_massage_index):
+	  Disable init_frames delay timestamp adjustment, it does not
+	  seem to be needed at all. Fixes #369621.
+
+2006-11-14 11:43:40 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Don't parse extra sample params for raw pcm. Fixes #374914.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_get_duration),
+	  (gst_qtdemux_handle_src_query), (qtdemux_parse_trak):
+	  Don't parse extra sample params for raw pcm. Fixes #374914.
+
+2006-11-13 18:31:18 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  gst/videomixer/videomixer.c: Fix memleak by unref'ing collectpads instance (when finalizing)
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts  <manauw at skynet be>
+	  * gst/videomixer/videomixer.c:
+	  (gst_videomixer_set_master_geometry),
+	  (gst_videomixer_pad_sink_setcaps), (gst_videomixer_class_init),
+	  (gst_videomixer_collect_free), (gst_videomixer_reset),
+	  (gst_videomixer_init), (gst_videomixer_finalize),
+	  (gst_videomixer_request_new_pad), (gst_videomixer_release_pad),
+	  (gst_videomixer_collected), (gst_videomixer_change_state):
+	  Fix memleak by unref'ing collectpads instance (when finalizing)
+	  Implement releasing a request pad. Fixes #374479.
+
+2006-11-10 20:08:42 +0000  Sergey Scobich <sergey.scobich@gmail.com>
+
+	  win32/vs8/: Add VS8 project files (note that many of the plugins in ext are disabled by default). Fixes #366492.
+	  Original commit message from CVS:
+	  Patch by: Sergey Scobich  <sergey.scobich at gmail com>
+	  * win32/vs8/gst-plugins-good.sln:
+	  * win32/vs8/libgst1394.vcproj:
+	  * win32/vs8/libgstaasink.vcproj:
+	  * win32/vs8/libgstalaw.vcproj:
+	  * win32/vs8/libgstalpha.vcproj:
+	  * win32/vs8/libgstalphacolor.vcproj:
+	  * win32/vs8/libgstannodex.vcproj:
+	  * win32/vs8/libgstapetag.vcproj:
+	  * win32/vs8/libgstaudiofx.vcproj:
+	  * win32/vs8/libgstauparse.vcproj:
+	  * win32/vs8/libgstautodetect.vcproj:
+	  * win32/vs8/libgstavi.vcproj:
+	  * win32/vs8/libgstcacasink.vcproj:
+	  * win32/vs8/libgstcdio.vcproj:
+	  * win32/vs8/libgstcutter.vcproj:
+	  * win32/vs8/libgstdv.vcproj:
+	  * win32/vs8/libgsteffectv.vcproj:
+	  * win32/vs8/libgstflac.vcproj:
+	  * win32/vs8/libgstflxdec.vcproj:
+	  * win32/vs8/libgstgoom.vcproj:
+	  * win32/vs8/libgsticydemux.vcproj:
+	  * win32/vs8/libgstid3demux.vcproj:
+	  * win32/vs8/libgstjpeg.vcproj:
+	  * win32/vs8/libgstladspa.vcproj:
+	  * win32/vs8/libgstlevel.vcproj:
+	  * win32/vs8/libgstmatroska.vcproj:
+	  * win32/vs8/libgstmikmod.vcproj:
+	  * win32/vs8/libgstmng.vcproj:
+	  * win32/vs8/libgstmonoscope.vcproj:
+	  * win32/vs8/libgstmulaw.vcproj:
+	  * win32/vs8/libgstmultipart.vcproj:
+	  * win32/vs8/libgstpng.vcproj:
+	  * win32/vs8/libgstrtp.vcproj:
+	  * win32/vs8/libgstrtsp.vcproj:
+	  * win32/vs8/libgstshout2.vcproj:
+	  * win32/vs8/libgstsmpte.vcproj:
+	  * win32/vs8/libgstspeex.vcproj:
+	  * win32/vs8/libgsttaglib.vcproj:
+	  * win32/vs8/libgstudp.vcproj:
+	  * win32/vs8/libgstvideobalance.vcproj:
+	  * win32/vs8/libgstvideobox.vcproj:
+	  * win32/vs8/libgstvideoflip.vcproj:
+	  * win32/vs8/libgstvideomixer.vcproj:
+	  * win32/vs8/libgstwavenc.vcproj:
+	  * win32/vs8/libgstwavparse.vcproj:
+	  Add VS8 project files (note that many of the plugins in ext are
+	  disabled by default). Fixes #366492.
+
+2006-11-10 19:18:33 +0000  David Schleef <ds@schleef.org>
+
+	  gst/multifile/Makefile.am: Let's not depend on a file that doesn't exist.
+	  Original commit message from CVS:
+	  * gst/multifile/Makefile.am:
+	  Let's not depend on a file that doesn't exist.
+
+2006-11-10 18:51:10 +0000  David Schleef <ds@schleef.org>
+
+	  Revive multifile[src|sink].
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/multifile/Makefile.am:
+	  * gst/multifile/gstmultifile.c:
+	  * gst/multifile/gstmultifilesink.c:
+	  * gst/multifile/gstmultifilesrc.c:
+	  * gst/multifile/multifile.vproj:
+	  Revive multifile[src|sink].
+
+2006-11-10 08:09:05 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/v4l2/v4l2src_calls.c: we do not translate debug messages
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_grab_frame):
+	  we do not translate debug messages
+
+2006-11-08 12:04:03 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/flx/gstflxdec.c: fix categorisation, make short desc more explicit, remove unused code
+	  Original commit message from CVS:
+	  * gst/flx/gstflxdec.c: (gst_flxdec_class_init):
+	  fix categorisation, make short desc more explicit, remove unused code
+	  Fixes #372021
+
+2006-11-08 01:30:39 +0000  Christian Schaller <uraeus@gnome.org>
+
+	  gst/rtp/: Fix element descriptions.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpL16depay.c:
+	  * gst/rtp/gstrtpamrdepay.c:
+	  * gst/rtp/gstrtpamrpay.c:
+	  * gst/rtp/gstrtpgsmdepay.c:
+	  * gst/rtp/gstrtph263pay.c:
+	  * gst/rtp/gstrtph263pdepay.c:
+	  * gst/rtp/gstrtph263ppay.c:
+	  * gst/rtp/gstrtph264depay.c:
+	  * gst/rtp/gstrtpmp2tdepay.c:
+	  * gst/rtp/gstrtpmp4gdepay.c:
+	  * gst/rtp/gstrtpmp4gpay.c:
+	  * gst/rtp/gstrtpmp4vdepay.c:
+	  * gst/rtp/gstrtpmp4vpay.c:
+	  * gst/rtp/gstrtpmpadepay.c:
+	  * gst/rtp/gstrtpmpapay.c:
+	  * gst/rtp/gstrtppcmadepay.c:
+	  * gst/rtp/gstrtppcmapay.c:
+	  * gst/rtp/gstrtppcmudepay.c:
+	  * gst/rtp/gstrtppcmupay.c:
+	  * gst/rtp/gstrtpspeexdepay.c:
+	  * gst/rtp/gstrtpspeexpay.c:
+	  * gst/rtp/gstrtpsv3vdepay.c:
+	  Fix element descriptions.
+
+2006-11-08 01:29:51 +0000  Christian Schaller <uraeus@gnome.org>
+
+	  gst/rtp/: Fix description.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpvorbisdepay.c:
+	  * gst/rtp/gstrtpvorbispay.c: (gst_rtp_vorbis_pay_handle_buffer):
+	  Fix description.
+	  Small cleanup in the payloader.
+
+2006-11-08 01:28:00 +0000  Christian Schaller <uraeus@gnome.org>
+
+	  gst/rtp/: Add theora pay/depayloaders.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtptheoradepay.c: (gst_rtp_theora_depay_base_init),
+	  (gst_rtp_theora_depay_class_init), (gst_rtp_theora_depay_init),
+	  (gst_rtp_theora_depay_finalize),
+	  (gst_rtp_theora_depay_parse_configuration),
+	  (gst_rtp_theora_depay_setcaps),
+	  (gst_rtp_theora_depay_switch_codebook),
+	  (gst_rtp_theora_depay_process),
+	  (gst_rtp_theora_depay_set_property),
+	  (gst_rtp_theora_depay_get_property),
+	  (gst_rtp_theora_depay_change_state),
+	  (gst_rtp_theora_depay_plugin_init):
+	  * gst/rtp/gstrtptheoradepay.h:
+	  * gst/rtp/gstrtptheorapay.c: (gst_rtp_theora_pay_base_init),
+	  (gst_rtp_theora_pay_class_init), (gst_rtp_theora_pay_init),
+	  (gst_rtp_theora_pay_setcaps), (gst_rtp_theora_pay_reset_packet),
+	  (gst_rtp_theora_pay_init_packet),
+	  (gst_rtp_theora_pay_flush_packet),
+	  (gst_rtp_theora_pay_finish_headers), (gst_rtp_theora_pay_parse_id),
+	  (gst_rtp_theora_pay_handle_buffer),
+	  (gst_rtp_theora_pay_plugin_init):
+	  * gst/rtp/gstrtptheorapay.h:
+	  Add theora pay/depayloaders.
+
+2006-11-07 01:43:06 +0000  Christian Schaller <uraeus@gnome.org>
+
+	  gst/rtp/Makefile.am: We depend on gsttag to generate the vorbis comments.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  We depend on gsttag to generate the vorbis comments.
+	  * gst/rtp/gstrtpvorbisdepay.c:
+	  (gst_rtp_vorbis_depay_parse_configuration),
+	  (gst_rtp_vorbis_depay_setcaps),
+	  (gst_rtp_vorbis_depay_switch_codebook),
+	  (gst_rtp_vorbis_depay_process):
+	  * gst/rtp/gstrtpvorbisdepay.h:
+	  Parse configuration string in the depayloader.
+	  Implement selecting and switching to a new codebook.
+	  Receiving vorbis over RTP now works.
+	  * gst/rtp/gstrtpvorbispay.c: (gst_rtp_vorbis_pay_reset_packet),
+	  (gst_rtp_vorbis_pay_init_packet),
+	  (gst_rtp_vorbis_pay_finish_headers),
+	  (gst_rtp_vorbis_pay_handle_buffer):
+	  * gst/rtp/gstrtpvorbispay.h:
+	  Set timestamps on outgoing buffers and RTP packets.
+	  Fix configuration string, prepend number of Packet headers.
+	  Fix encoding of ident string.
+	  Add delivery-method to caps.
+	  Streaming vorbis over RTP now works.
+
+2006-11-06 20:52:10 +0000  Christian Schaller <uraeus@gnome.org>
+
+	  gst/rtp/gstrtpvorbispay.*: Generate a valid configuration string in the caps based on the vorbis headers.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpvorbispay.c: (gst_rtp_vorbis_pay_setcaps),
+	  (gst_rtp_vorbis_pay_finish_headers), (gst_rtp_vorbis_pay_parse_id),
+	  (gst_rtp_vorbis_pay_handle_buffer):
+	  * gst/rtp/gstrtpvorbispay.h:
+	  Generate a valid configuration string in the caps based on the
+	  vorbis headers.
+
+2006-11-02 20:13:26 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Fix enum nicks; only emit no-more-pads once; add support for very fast encoding mode in upcoming 4.40.0 release (#369...
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge <slomo at circular-chaos.org>
+	  * configure.ac:
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_mode_get_type),
+	  (gst_wavpack_enc_correction_mode_get_type),
+	  (gst_wavpack_enc_joint_stereo_mode_get_type),
+	  (gst_wavpack_enc_init), (gst_wavpack_enc_set_wp_config):
+	  Fix enum nicks; only emit no-more-pads once; add support for very
+	  fast encoding mode in upcoming 4.40.0 release (#369539).
+
+2006-11-02 14:43:11 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/cdio/: Move CD-TEXT utility function into common file so it can also be used by a future cdioparanoiasrc.
+	  Original commit message from CVS:
+	  * ext/cdio/gstcdio.c: (gst_cdio_get_cdtext):
+	  * ext/cdio/gstcdio.h:
+	  * ext/cdio/gstcdiocddasrc.c: (gst_cdio_cdda_src_open):
+	  Move CD-TEXT utility function into common file so it can also be
+	  used by a future cdioparanoiasrc.
+
+2006-11-01 19:48:26 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  Improved comments in ELEMENT_ERROR/WARNING and added "#if 0" to xoverlay code that is still not implemented.
+	  Original commit message from CVS:
+	  Improved comments in ELEMENT_ERROR/WARNING and added "#if 0" to xoverlay code that is still not implemented.
+
+2006-11-01 13:59:49 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/id3v2frames.c: We require a -base more recent than 0.10.9, so it's safe to use
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (parse_picture_frame):
+	  We require a -base more recent than 0.10.9, so it's safe to use
+	  GST_TYPE_TAG_IMAGE_TYPE unconditionally now.
+	  * ext/dv/gstdvdec.c: (gst_dvdec_sink_event):
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_sink_event):
+	  Use _newsegment_full() now that we depend on a recent enough core.
+	  * gst/wavparse/gstwavparse.c:
+	  Remove cruft that we don't need any longer now that we depend on
+	  a recent enough -base.
+
+2006-11-01 10:19:18 +0000  Sergey Scobich <sergey.scobich@gmail.com>
+
+	  sys/: Wait until the window is created before using it; guard unistd.h includes with HAVE_UNISTD_H. (#366523)
+	  Original commit message from CVS:
+	  Patch by: Sergey Scobich  <sergey dot scobich at gmail com>
+	  * sys/directdraw/gstdirectdrawsink.c:
+	  (gst_directdrawsink_window_thread),
+	  (gst_directdrawsink_create_default_window):
+	  * sys/directdraw/gstdirectdrawsink.h:
+	  * sys/directsound/gstdirectsoundsink.c:
+	  Wait until the window is created before using it; guard unistd.h
+	  includes with HAVE_UNISTD_H. (#366523)
+	  * win32/vs8/libgstdirectdraw.vcproj:
+	  * win32/vs8/libgstdirectsound.vcproj:
+	  Update project files.
+
+2006-10-31 10:52:31 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Fix and activate ILBC pay and depayloaders. Fixes #368162.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpilbcpay.c: (gst_rtpilbcpay_init),
+	  (gst_rtpilbcpay_setcaps):
+	  Fix and activate ILBC pay and depayloaders. Fixes #368162.
+
+2006-10-31 10:31:18 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Handle unbounded length streams a bit better. Fixes #367696.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_get_duration),
+	  (gst_qtdemux_handle_src_query), (qtdemux_parse_tree),
+	  (qtdemux_parse_trak):
+	  Handle unbounded length streams a bit better. Fixes #367696.
+
+2006-10-31 09:44:39 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/speex/gstspeexdec.c: Some small cleanups, use _scale.
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexdec.c: (speex_dec_convert),
+	  (speex_dec_sink_event), (speex_dec_chain_parse_header):
+	  Some small cleanups, use _scale.
+
+2006-10-31 09:29:36 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: Use higher precision scale function.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query):
+	  Use higher precision scale function.
+
+2006-10-30 16:18:18 +0000  Michal Benes <michal.benes@itonis.tv>
+
+	  gst/matroska/matroska-demux.c: Fix several issues with encoded/compressed/encrypted/signed tracks; also, remove super...
+	  Original commit message from CVS:
+	  Patch by: Michal Benes  <michal dot benes at itonis tv>
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_encoding_cmp),
+	  (gst_matroska_demux_read_track_encodings),
+	  (gst_matroska_decode_buffer):
+	  Fix several issues with encoded/compressed/encrypted/signed tracks;
+	  also, remove superfluous newline characters from some debug
+	  statements. (#366155)
+
+2006-10-30 09:24:53 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/jpeg/: Various cleanups, capsnego and leak fixes.
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegenc.c: (gst_jpegenc_getcaps):
+	  * ext/jpeg/gstsmokedec.c: (gst_smokedec_class_init),
+	  (gst_smokedec_init), (gst_smokedec_finalize), (gst_smokedec_chain),
+	  (gst_smokedec_change_state):
+	  * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_class_init),
+	  (gst_smokeenc_init), (gst_smokeenc_finalize),
+	  (gst_smokeenc_getcaps), (gst_smokeenc_setcaps),
+	  (gst_smokeenc_resync), (gst_smokeenc_chain),
+	  (gst_smokeenc_set_property), (gst_smokeenc_get_property),
+	  (gst_smokeenc_change_state):
+	  Various cleanups, capsnego and leak fixes.
+
+2006-10-30 08:17:08 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  gst/videomixer/videomixer.c: Fix videomixer so that it can handle any combination of framerates.
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts  <manauw at skynet be>
+	  * gst/videomixer/videomixer.c: (gst_videomixer_update_queues):
+	  Fix videomixer so that it can handle any combination of framerates.
+	  Fixes #367221.
+
+2006-10-28 16:37:20 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: Fix position query for audio. also fixes timestamps in streaming mode and bug #364958.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query),
+	  (gst_avi_demux_parse_file_header),
+	  (gst_avi_demux_stream_init_push), (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_stream_header_push), (gst_avi_demux_stream_data),
+	  (gst_avi_demux_chain):
+	  Fix position query for audio. also fixes timestamps in streaming
+	  mode and bug #364958.
+	  Small cleanups.
+
+2006-10-27 17:10:42 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/libpng/gstpngenc.*: Fix strides. Fixes #364856.
+	  Original commit message from CVS:
+	  * ext/libpng/gstpngenc.c: (gst_pngenc_setcaps), (gst_pngenc_chain):
+	  * ext/libpng/gstpngenc.h:
+	  Fix strides. Fixes #364856.
+	  Cleanup capsnego.
+	  Set caps on outgoing buffers.
+
+2006-10-18 17:06:21 +0000  Ville Syrjala <ville.syrjala@movial.fi>
+
+	  gst/rtp/: Add static payload numbers in addition to the dynamic ones.
+	  Original commit message from CVS:
+	  Patch by: Ville Syrjala <ville dot syrjala at movial dot fi>
+	  * gst/rtp/gstrtpgsmpay.c:
+	  * gst/rtp/gstrtph263pay.c:
+	  * gst/rtp/gstrtpmpapay.c:
+	  * gst/rtp/gstrtppcmapay.c: (gst_rtp_pcma_pay_flush),
+	  (gst_rtp_pcma_pay_handle_buffer):
+	  * gst/rtp/gstrtppcmupay.c: (gst_rtp_pcmu_pay_flush):
+	  Add static payload numbers in addition to the dynamic ones.
+	  Fixes #361639.
+
+2006-10-18 16:18:55 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/: Reuse already existing enum for lower transport.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtsp_lower_trans_get_type),
+	  (gst_rtspsrc_class_init), (gst_rtspsrc_loop_interleaved),
+	  (gst_rtspsrc_loop_udp), (gst_rtspsrc_open),
+	  (gst_rtspsrc_uri_get_protocols), (gst_rtspsrc_uri_set_uri):
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_create):
+	  * gst/rtsp/rtspdefs.h:
+	  * gst/rtsp/rtspurl.c: (rtsp_url_parse):
+	  * gst/rtsp/rtspurl.h:
+	  Reuse already existing enum for lower transport.
+	  Add rtspt and rtspu protocols.
+	  Send redirect to rtspt when udp times out.
+
+2006-10-18 14:00:44 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/wavparse/gstwavparse.c: Fix seeking some more, mostly for speed changes.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_perform_seek),
+	  (gst_wavparse_stream_data):
+	  Fix seeking some more, mostly for speed changes.
+
+2006-10-18 11:28:05 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* ChangeLog:
+	  ChangeLog surgery: fix Fredrik's e-mail address
+	  Original commit message from CVS:
+	  ChangeLog surgery: fix Fredrik's e-mail address
+
+2006-10-18 11:04:09 +0000  Fredrik Persson <frepe@broadband.net>
+
+	  sys/v4l2/gstv4l2tuner.*: Fix _set_channel(): remove useless g_object_notify() for "channel" property that doesn't exi...
+	  Original commit message from CVS:
+	  Patch by: Fredrik Persson  <frepe at broadband net>
+	  * sys/v4l2/gstv4l2tuner.c:
+	  * sys/v4l2/gstv4l2tuner.h:
+	  Fix _set_channel(): remove useless g_object_notify() for "channel"
+	  property that doesn't exist any longer and therefore now also
+	  useless redirect (#338818).
+
+2006-10-17 15:16:47 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Activate pads before adding them to running element.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_set_wp_config):
+	  * ext/wavpack/gstwavpackparse.c:
+	  (gst_wavpack_parse_create_src_pad):
+	  * gst/nuvdemux/gstnuvdemux.c: (gst_nuv_demux_create_pads):
+	  * tests/check/elements/wavpackparse.c: (wavpackparse_found_pad):
+	  Activate pads before adding them to running element.
+
+2006-10-17 14:57:17 +0000  Josep Torra Valles <josep@fluendo.com>
+
+	  gst/qtdemux/qtdemux.c: Make compile with Forte compiler, mostly don't do pointer arithmetic with void pointers (#3626...
+	  Original commit message from CVS:
+	  Patch by: Josep Torra Valles  <josep at fluendo com>
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_handle_sink_event),
+	  (next_entry_size), (qtdemux_inflate), (qtdemux_parse_moov),
+	  (qtdemux_parse_tree), (qtdemux_parse_trak), (qtdemux_tag_add_str),
+	  (qtdemux_tag_add_num), (qtdemux_tag_add_date),
+	  (qtdemux_tag_add_gnre):
+	  Make compile with Forte compiler, mostly don't do pointer arithmetic
+	  with void pointers (#362626).
+
+2006-10-17 14:37:49 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/oss/gstosssink.c: Some drivers do not support unsetting the non-blocking flag once the device is opened. In those...
+	  Original commit message from CVS:
+	  * sys/oss/gstosssink.c: (gst_oss_sink_prepare):
+	  Some drivers do not support unsetting the non-blocking flag once the
+	  device is opened. In those cases, close/open the device in
+	  non-blocking mode. Fixes #362673.
+
+2006-10-17 13:44:14 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/v4l2/: dear stefan, framespersecond is not frameperiod, reverting but adding comment
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2_calls.c: (gst_v4l2_fill_lists):
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_set_fps),
+	  (gst_v4l2src_get_fps):
+	  dear stefan, framespersecond is not frameperiod, reverting but adding
+	  comment
+
+2006-10-17 11:28:50 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/v4l2/: Numerator is numerator and denominator is denominator. Say that aloud 5 times and retry after next beer.
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2_calls.c: (gst_v4l2_fill_lists):
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_set_fps),
+	  (gst_v4l2src_get_fps):
+	  Numerator is numerator and denominator is denominator. Say that aloud
+	  5 times and retry after next beer.
+
+2006-10-17 10:59:55 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.*: Avoid void pointer usage, better use guint8 * instead.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_moov), (qtdemux_parse),
+	  (qtdemux_node_dump_foreach), (qtdemux_dump_mvhd),
+	  (qtdemux_dump_tkhd), (qtdemux_dump_elst), (qtdemux_dump_mdhd),
+	  (qtdemux_dump_hdlr), (qtdemux_dump_vmhd), (qtdemux_dump_dref),
+	  (qtdemux_dump_stsd), (qtdemux_dump_stts), (qtdemux_dump_stss),
+	  (qtdemux_dump_stsc), (qtdemux_dump_stsz), (qtdemux_dump_stco),
+	  (qtdemux_dump_co64), (qtdemux_dump_dcom), (qtdemux_dump_cmvd),
+	  (qtdemux_dump_unknown), (qtdemux_tree_get_child_by_type),
+	  (qtdemux_tree_get_sibling_by_type):
+	  * gst/qtdemux/qtdemux.h:
+	  Avoid void pointer usage, better use guint8 * instead.
+
+2006-10-16 18:22:47 +0000  Josep Torra Valles <josep@fluendo.com>
+
+	  Fix a bunch of problems discovered by the Forte compiler, mostly type mixups and pointer arithmetics with void pointe...
+	  Original commit message from CVS:
+	  Patch by: Josep Torra Valles  <josep at fluendo com>
+	  * ext/cairo/gsttimeoverlay.c: (gst_cairo_time_overlay_transform):
+	  * ext/esd/esdsink.c: (gst_esdsink_write):
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_length),
+	  (gst_flac_dec_read_seekable), (gst_flac_dec_chain),
+	  (gst_flac_dec_send_newsegment):
+	  * ext/flac/gstflacenc.c: (gst_flac_enc_seek_callback),
+	  (gst_flac_enc_tell_callback):
+	  * ext/jpeg/smokecodec.c: (find_best_size), (smokecodec_encode),
+	  (smokecodec_parse_header), (smokecodec_decode):
+	  * gst/avi/gstavimux.c: (gst_avi_mux_write_avix_index):
+	  * gst/debug/efence.c: (gst_fenced_buffer_alloc):
+	  * gst/goom/Makefile.am:
+	  * gst/goom/gstgoom.c:
+	  * gst/icydemux/gsticydemux.c: (gst_icydemux_typefind_or_forward):
+	  * gst/rtsp/gstrtspsrc.c:
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_read):
+	  * gst/udp/gstudpsink.c:
+	  * gst/udp/gstudpsrc.c:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_change_state):
+	  * sys/sunaudio/gstsunaudiomixertrack.h:
+	  Fix a bunch of problems discovered by the Forte compiler, mostly type
+	  mixups and pointer arithmetics with void pointers. Fixes #362603.
+
+2006-10-12 19:02:51 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/speex/: Miscellaneous clean-ups, among other things: speexenc => enc to enhance code readability; change speexenc...
+	  Original commit message from CVS:
+	  * ext/speex/gstspeex.c: (plugin_init):
+	  * ext/speex/gstspeexenc.c: (gst_speex_enc_get_formats),
+	  (gst_speex_enc_setup_interfaces), (gst_speex_enc_base_init),
+	  (gst_speex_enc_class_init), (gst_speex_enc_finalize),
+	  (gst_speex_enc_sink_setcaps), (gst_speex_enc_convert_src),
+	  (gst_speex_enc_convert_sink), (gst_speex_enc_get_query_types),
+	  (gst_speex_enc_src_query), (gst_speex_enc_sink_query),
+	  (gst_speex_enc_init), (gst_speex_enc_create_metadata_buffer),
+	  (gst_speex_enc_set_last_msg), (gst_speex_enc_setup),
+	  (gst_speex_enc_buffer_from_data), (gst_speex_enc_push_buffer),
+	  (gst_speex_enc_set_header_on_caps), (gst_speex_enc_sinkevent),
+	  (gst_speex_enc_chain), (gst_speex_enc_get_property),
+	  (gst_speex_enc_set_property), (gst_speex_enc_change_state):
+	  * ext/speex/gstspeexenc.h:
+	  Miscellaneous clean-ups, among other things: speexenc => enc to
+	  enhance code readability; change speexenc => speex_enc; in chain
+	  function unref input buffer in case of error; take reference in
+	  event function; use boilerplate macro; use gst_pad_query_peer_*
+	  convenience functions.
+
+2006-10-12 18:35:10 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/speex/gstspeexenc.c: Fix some mem leaks.
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexenc.c: (gst_speexenc_finalize),
+	  (gst_speexenc_set_last_msg), (gst_speexenc_setup),
+	  (gst_speexenc_set_header_on_caps):
+	  Fix some mem leaks.
+
+2006-10-11 16:21:53 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/URLS: Added some other URL.
+	  Original commit message from CVS:
+	  * gst/rtsp/URLS:
+	  Added some other URL.
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_loop_udp),
+	  (gst_rtspsrc_handle_request), (gst_rtspsrc_send),
+	  (gst_rtspsrc_open), (gst_rtspsrc_play),
+	  (gst_rtspsrc_handle_message), (gst_rtspsrc_change_state):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Work on fallback to TCP connection when the UDP socket times out.
+	  Handler server requests, just reply with OK for now.
+	  * gst/rtsp/rtspdefs.c: (rtsp_strresult):
+	  * gst/rtsp/rtspdefs.h:
+	  Added some more Real extension headers.
+	  * gst/rtsp/rtspurl.c: (rtsp_url_parse):
+	  Fix parsing of urls with a ':' that is not part of the hostname:port
+	  part of the url.
+
+2006-10-11 13:49:26 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Add some fourcc for DV format.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_video_caps):
+	  Add some fourcc for DV format.
+
+2006-10-11 13:24:42 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/: Activate pad before adding it to the already-running element.
+	  Original commit message from CVS:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_add_srcpad):
+	  * gst/icydemux/gsticydemux.c: (gst_icydemux_add_srcpad):
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_add_srcpad):
+	  Activate pad before adding it to the already-running element.
+	  * tests/check/elements/icydemux.c: (icydemux_found_pad):
+	  Activate newly-created pad too.
+
+2006-10-11 08:34:14 +0000  Sebastien Cote <sebas642@yahoo.ca>
+
+	  gst/udp/gstudpsrc.c: Fix some leaks in caps and uris. Fixes #361252.
+	  Original commit message from CVS:
+	  Patch by: Sebastien Cote <sebas642 at yahoo dot ca>
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init),
+	  (gst_udpsrc_finalize), (gst_udpsrc_create), (gst_udpsrc_set_uri),
+	  (gst_udpsrc_start):
+	  Fix some leaks in caps and uris. Fixes #361252.
+
+2006-10-10 18:54:05 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Printf format fixes.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (extract_initial_length_and_fourcc),
+	  (gst_qtdemux_loop_state_header):
+	  Printf format fixes.
+	  * sys/dvb/gstdvbsrc.c:
+	  Use "_stdint.h".
+
+2006-10-10 09:57:19 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Reorganise some stuff.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_init),
+	  (gst_qtdemux_push_event), (gst_qtdemux_do_seek),
+	  (gst_qtdemux_change_state), (extract_initial_length_and_fourcc),
+	  (gst_qtdemux_loop_state_header), (gst_qtdemux_activate_segment),
+	  (gst_qtdemux_loop_state_movie), (gst_qtdemux_loop),
+	  (gst_qtdemux_post_buffering), (gst_qtdemux_chain),
+	  (gst_qtdemux_add_stream), (qtdemux_process_redirects),
+	  (qtdemux_parse_tree), (qtdemux_parse_trak):
+	  Reorganise some stuff.
+	  Parse RTSP redirection URLS.
+
+2006-10-10 08:29:07 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/wavparse/Makefile.am: Fix copy'n'paste-o (spotted by Mark Nauwelaerts, #341489).
+	  Original commit message from CVS:
+	  * gst/wavparse/Makefile.am:
+	  Fix copy'n'paste-o (spotted by Mark Nauwelaerts, #341489).
+
+2006-10-09 07:01:19 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  sys/v4l2/gstv4l2xoverlay.*: Fix build as per the patch in #338818 comment 36.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2xoverlay.c:
+	  * sys/v4l2/gstv4l2xoverlay.h:
+	  Fix build as per the patch in #338818 comment 36.
+
+2006-10-08 20:05:13 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	  inspect updates
+	  Original commit message from CVS:
+	  inspect updates
+
+2006-10-07 21:15:40 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/rtsp/gstrtspsrc.c: Activate pads before adding them to the source.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_stream_configure_transport):
+	  Activate pads before adding them to the source.
+
+2006-10-07 11:37:59 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  docs/plugins/: Add/update docs stuff.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-bad-plugins.args:
+	  * docs/plugins/gst-plugins-bad-plugins.hierarchy:
+	  * docs/plugins/gst-plugins-bad-plugins.interfaces:
+	  * docs/plugins/gst-plugins-bad-plugins.prerequisites:
+	  * docs/plugins/inspect/plugin-dtsdec.xml:
+	  * docs/plugins/inspect/plugin-mms.xml:
+	  * docs/plugins/inspect/plugin-mpeg2enc.xml:
+	  * docs/plugins/inspect/plugin-neon.xml:
+	  * docs/plugins/inspect/plugin-replaygain.xml:
+	  * docs/plugins/inspect/plugin-soundtouch.xml:
+	  * docs/plugins/inspect/plugin-spcdec.xml:
+	  * docs/plugins/inspect/plugin-swfdec.xml:
+	  * docs/plugins/inspect/plugin-videocrop.xml:
+	  * docs/plugins/inspect/plugin-wavpack.xml:
+	  Add/update docs stuff.
+
+2006-10-06 17:00:14 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  Activate pads before adding.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_add_pads), (gst_dvdemux_chain):
+	  * gst/auparse/gstauparse.c: (gst_au_parse_add_srcpad):
+	  Activate pads before adding.
+
+2006-10-06 16:03:23 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/multipart/multipartdemux.c: Activate pads before adding.
+	  Original commit message from CVS:
+	  * gst/multipart/multipartdemux.c: (gst_multipart_demux_init),
+	  (gst_multipart_find_pad_by_mime):
+	  Activate pads before adding.
+	  * gst/rtp/gstrtpmp4vdepay.c: (gst_rtp_mp4v_depay_class_init):
+	  BOILERPLATE sets parent_class for us.
+
+2006-10-06 15:56:01 +0000  René Stadler <mail@renestadler.de>
+
+	  Add ReplayGain analysis element (#357069).
+	  Original commit message from CVS:
+	  Patch by: René Stadler  <mail at renestadler de>
+	  * configure.ac:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * gst/replaygain/Makefile.am:
+	  * gst/replaygain/gstrganalysis.c: (gst_rg_analysis_base_init),
+	  (gst_rg_analysis_class_init), (gst_rg_analysis_init),
+	  (gst_rg_analysis_set_property), (gst_rg_analysis_get_property),
+	  (gst_rg_analysis_start), (gst_rg_analysis_set_caps),
+	  (gst_rg_analysis_transform_ip), (gst_rg_analysis_event),
+	  (gst_rg_analysis_stop), (gst_rg_analysis_handle_tags),
+	  (gst_rg_analysis_handle_eos), (gst_rg_analysis_track_result),
+	  (gst_rg_analysis_album_result), (plugin_init):
+	  * gst/replaygain/gstrganalysis.h:
+	  * gst/replaygain/rganalysis.c: (yule_filter), (butter_filter),
+	  (apply_filters), (reset_filters), (accumulator_add),
+	  (accumulator_clear), (accumulator_result), (rg_analysis_new),
+	  (rg_analysis_set_sample_rate), (rg_analysis_destroy),
+	  (rg_analysis_analyze_mono_float),
+	  (rg_analysis_analyze_stereo_float),
+	  (rg_analysis_analyze_mono_int16),
+	  (rg_analysis_analyze_stereo_int16), (rg_analysis_analyze),
+	  (rg_analysis_track_result), (rg_analysis_album_result),
+	  (rg_analysis_reset_album), (rg_analysis_reset):
+	  * gst/replaygain/rganalysis.h:
+	  Add ReplayGain analysis element (#357069).
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/rganalysis.c: (get_expected_gain),
+	  (setup_rganalysis), (cleanup_rganalysis), (set_playing_state),
+	  (send_eos_event), (send_tag_event), (poll_eos), (poll_tags),
+	  (fail_unless_track_gain), (fail_unless_track_peak),
+	  (fail_unless_album_gain), (fail_unless_album_peak),
+	  (fail_if_track_tags), (fail_if_album_tags),
+	  (fail_unless_num_tracks), (test_buffer_const_float_mono),
+	  (test_buffer_const_float_stereo), (test_buffer_const_int16_mono),
+	  (test_buffer_const_int16_stereo), (test_buffer_square_float_mono),
+	  (test_buffer_square_float_stereo), (test_buffer_square_int16_mono),
+	  (test_buffer_square_int16_stereo), (push_buffer), (GST_START_TEST),
+	  (rganalysis_suite), (main):
+	  Unit tests for the new replaygain element.
+
+2006-10-06 15:49:39 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/faad/gstfaad.c: Some cleanups.
+	  Original commit message from CVS:
+	  * ext/faad/gstfaad.c: (gst_faad_setcaps), (gst_faad_chain),
+	  (gst_faad_close_decoder):
+	  Some cleanups.
+	  Added some more debugging.
+	  Don't ever ignore unlinked, we're not a demuxer.
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_add_stream):
+	  Activate pad before adding it to the element.
+
+2006-10-06 12:55:53 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Rework how the transport string is constructed, try to share channels and udp ports.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtsp_proto_get_type),
+	  (gst_rtspsrc_class_init), (gst_rtspsrc_init),
+	  (gst_rtspsrc_create_stream), (gst_rtspsrc_media_to_caps),
+	  (gst_rtspsrc_alloc_udp_ports),
+	  (gst_rtspsrc_stream_configure_transport), (find_stream_by_channel),
+	  (gst_rtspsrc_push_event), (gst_rtspsrc_loop_interleaved),
+	  (gst_rtspsrc_create_transports_string),
+	  (gst_rtspsrc_configure_transports), (gst_rtspsrc_open),
+	  (gst_rtspsrc_handle_message), (gst_rtspsrc_change_state):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Rework how the transport string is constructed, try to share channels
+	  and udp ports.
+	  Make most of the stuff less dependant on RTP as we are also going to use
+	  it for RDT.
+	  Add support for transport specific session managers.
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_flush):
+	  Implement _flush().
+	  * gst/rtsp/rtspdefs.c: (rtsp_strresult):
+	  * gst/rtsp/rtspdefs.h:
+	  Add generic error return code.
+	  * gst/rtsp/rtspext.h:
+	  Add support for pluggable tranport strings.
+	  * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_before_send),
+	  (rtsp_ext_wms_after_send), (rtsp_ext_wms_parse_sdp),
+	  (rtsp_ext_wms_get_context):
+	  Detect WMServer and activate the extension.
+	  * gst/rtsp/rtsptransport.c: (rtsp_transport_get_mime),
+	  (rtsp_transport_get_manager), (rtsp_transport_parse):
+	  * gst/rtsp/rtsptransport.h:
+	  Added methods to get mime/manager for certain transports.
+
+2006-10-06 11:31:11 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/spectrum/gstspectrum.c: Fix mem leak, avoid unnecessary memcpy.
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_transform_ip):
+	  Fix mem leak, avoid unnecessary memcpy.
+
+2006-10-06 02:29:35 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/gstspectrum.c: Removed cruft code that was just commented out. Removed some obsolete debug logs statements.
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_init),
+	  (gst_spectrum_transform_ip):
+	  Removed cruft code that was just commented out. Removed some obsolete
+	  debug logs statements.
+
+2006-10-05 18:14:46 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Another batch of printf format fixes.
+	  Original commit message from CVS:
+	  * ext/dts/gstdtsdec.c: (gst_dtsdec_chain):
+	  * ext/musicbrainz/gsttrm.c: (gst_trm_setcaps):
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_sink_set_caps):
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_chain), (qtdemux_parse),
+	  (qtdemux_parse_trak):
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_transform_ip):
+	  Another batch of printf format fixes.
+
+2006-10-05 16:37:33 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Printf format fixes.
+	  Original commit message from CVS:
+	  * ext/cairo/gsttimeoverlay.c:
+	  (gst_cairo_time_overlay_update_font_height):
+	  * ext/gdk_pixbuf/pixbufscale.c: (gst_pixbufscale_transform_caps):
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_parse_image_data):
+	  * ext/jpeg/gstjpegenc.c: (gst_jpegenc_chain):
+	  * ext/jpeg/gstsmokedec.c: (gst_smokedec_chain):
+	  * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_chain):
+	  * ext/libpng/gstpngdec.c: (user_endrow_callback):
+	  * gst/auparse/gstauparse.c: (gst_au_parse_parse_header):
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_superindex),
+	  (gst_avi_demux_parse_subindex), (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_stream_data):
+	  * gst/cutter/gstcutter.c: (gst_cutter_chain):
+	  * gst/debug/efence.c: (gst_efence_buffer_alloc),
+	  (gst_fenced_buffer_copy):
+	  * gst/id3demux/id3v2frames.c: (id3demux_id3v2_parse_frame):
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream):
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_start):
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send),
+	  (gst_rtspsrc_handle_message):
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_stream_headers):
+	  * sys/ximage/ximageutil.c: (ximageutil_xcontext_get):
+	  Printf format fixes.
+
+2006-10-04 22:37:07 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/videocrop/gstvideocrop.*: Handle packed YUV formats (UYVY, YUY2, YUYV) separately; also, fix passthrough mode; la...
+	  Original commit message from CVS:
+	  * gst/videocrop/gstvideocrop.c: (gst_video_crop_class_init),
+	  (gst_video_crop_init),
+	  (gst_video_crop_get_image_details_from_caps),
+	  (gst_video_crop_transform_packed_complex),
+	  (gst_video_crop_transform_packed_simple),
+	  (gst_video_crop_transform), (gst_video_crop_transform_caps),
+	  (gst_video_crop_set_caps),
+	  (gst_videocrop_clear_negotiated_caps_locked),
+	  (gst_video_crop_set_property):
+	  * gst/videocrop/gstvideocrop.h:
+	  Handle packed YUV formats (UYVY, YUY2, YUYV) separately; also, fix
+	  passthrough mode; lastly, clear negotiated basetransform caps when
+	  the cropping changes in order to force renegotiation.
+
+2006-10-04 20:05:07 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/icles/: Visual test for videocrop, shows that packed yuv doesn't work right yet. --with-ffmpegcolorspace option...
+	  Original commit message from CVS:
+	  * tests/icles/.cvsignore:
+	  * tests/icles/Makefile.am:
+	  * tests/icles/videocrop-test.c: (quit_mainloop), (tick_cb),
+	  (test_with_caps), (video_crop_get_test_caps), (main):
+	  Visual test for videocrop, shows that packed yuv doesn't work right
+	  yet. --with-ffmpegcolorspace option doesn't work yet for unknown
+	  reasons (another basetransform issue?)
+
+2006-10-04 17:53:12 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/Makefile.am: Dist new .h file too.
+	  Original commit message from CVS:
+	  * gst/rtsp/Makefile.am:
+	  Dist new .h file too.
+
+2006-10-04 17:24:40 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/: Factor out extension in separate module.
+	  Original commit message from CVS:
+	  * gst/rtsp/Makefile.am:
+	  * gst/rtsp/gstrtpdec.c: (gst_rtpdec_getcaps),
+	  (gst_rtpdec_chain_rtp), (gst_rtpdec_chain_rtcp):
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init),
+	  (gst_rtspsrc_finalize), (gst_rtspsrc_create_stream),
+	  (gst_rtspsrc_parse_rtpmap),
+	  (gst_rtspsrc_stream_configure_transport), (gst_rtspsrc_send),
+	  (gst_rtspsrc_parse_methods), (gst_rtspsrc_open),
+	  (gst_rtspsrc_play), (gst_rtspsrc_handle_message):
+	  * gst/rtsp/gstrtspsrc.h:
+	  * gst/rtsp/rtspdefs.c: (rtsp_strresult):
+	  * gst/rtsp/rtspdefs.h:
+	  * gst/rtsp/rtspext.h:
+	  * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_parse_sdp),
+	  (rtsp_ext_wms_get_context):
+	  * gst/rtsp/rtspextwms.h:
+	  * gst/rtsp/rtsptransport.c: (rtsp_transport_init), (parse_mode),
+	  (rtsp_transport_parse):
+	  * gst/rtsp/rtsptransport.h:
+	  Factor out extension in separate module.
+	  Fix getcaps to filter against the padtemplate.
+	  Use Content-Base if the server gives one.
+	  Rework the transport parsing a bit for future extensions.
+	  Added some Real Header field definitions.
+
+2006-10-04 10:29:11 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  docs/plugins/: added v4l2 stubs
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  added v4l2 stubs
+	  * gst-plugins-good.spec.in:
+	  add v4l2
+
+2006-10-04 10:24:49 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/apetag/gstapedemux.c: Extract disc/album/medium number and count and try harder to extract track number/count.
+	  Original commit message from CVS:
+	  * gst/apetag/gstapedemux.c: (ape_demux_parse_tags):
+	  Extract disc/album/medium number and count and try harder
+	  to extract track number/count.
+
+2006-10-03 18:36:29 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* tests/icles/.gitignore:
+	  moap ignore
+	  Original commit message from CVS:
+	  moap ignore
+
+2006-10-03 18:35:34 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* tests/icles/Makefile.am:
+	  add icle for v4l2
+	  Original commit message from CVS:
+	  add icle for v4l2
+
+2006-10-03 18:15:58 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  add build stuff for v4l2, needs --enable-experimental until the last bits are resolved
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * sys/Makefile.am:
+	  add build stuff for v4l2, needs --enable-experimental until
+	  the last bits are resolved
+
+2006-10-03 13:47:10 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* sys/v4l2/gstv4l2object.c:
+	  comment out the notifies for removed properties
+	  Original commit message from CVS:
+	  comment out the notifies for removed properties
+
+2006-10-03 13:30:48 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  sys/v4l2/gstv4l2object.c: comment out the properties that are already part of the tuner interface.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2object.c:
+	  (gst_v4l2_object_install_properties_helper):
+	  comment out the properties that are already part of the tuner
+	  interface.
+
+2006-10-03 13:18:59 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  sys/v4l2/gstv4l2src.c: Improve docs.
+	  Original commit message from CVS:
+	  2006-10-03  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * sys/v4l2/gstv4l2src.c:
+	  Improve docs.
+
+2006-10-02 16:14:06 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  stop removing gdkpixbuf plugin from package
+	  Original commit message from CVS:
+	  stop removing gdkpixbuf plugin from package
+
+2006-09-29 15:39:41 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/check/Makefile.am: Disable autodetect test temporarily, so that the build bots update -bad and the ranks of unr...
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Disable autodetect test temporarily, so that the build bots
+	  update -bad and the ranks of unreliable video sinks in there.
+	  * tests/check/elements/autodetect.c: (GST_START_TEST):
+	  Skip test if no usable videosink is found.
+
+2006-09-29 15:37:29 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/URLS: Add some more URLs.
+	  Original commit message from CVS:
+	  * gst/rtsp/URLS:
+	  Add some more URLs.
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_class_init),
+	  (gst_rtspsrc_init), (gst_rtspsrc_finalize),
+	  (gst_rtspsrc_set_property), (gst_rtspsrc_get_property),
+	  (gst_rtspsrc_stream_setup_rtp), (gst_rtspsrc_loop_interleaved),
+	  (gst_rtspsrc_loop_udp), (gst_rtspsrc_loop_send_cmd),
+	  (gst_rtspsrc_loop), (gst_rtspsrc_send),
+	  (gst_rtspsrc_parse_methods), (gst_rtspsrc_open),
+	  (gst_rtspsrc_close), (gst_rtspsrc_play), (gst_rtspsrc_pause),
+	  (gst_rtspsrc_handle_message), (gst_rtspsrc_change_state):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Add timeout property to control UDP timeouts.
+	  Fix error messages.
+	  Also start a loop function when operating in UDP mode so that we can
+	  do some more stuff async.
+	  Handle element messages from udpsrc to detect timeouts. If a timeout
+	  happens we currently generate an error.
+	  API: rtspsrc::timeout property.
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init),
+	  (gst_udpsrc_create):
+	  Really implement the timeout in microseconds and not milliseconds.
+
+2006-09-29 11:09:40 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstudpsrc.*: Added property to post a message on timeout.
+	  Original commit message from CVS:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init), (gst_udpsrc_init),
+	  (gst_udpsrc_create), (gst_udpsrc_set_property),
+	  (gst_udpsrc_get_property), (gst_udpsrc_unlock), (gst_udpsrc_stop):
+	  * gst/udp/gstudpsrc.h:
+	  Added property to post a message on timeout.
+	  Updated docs.
+	  When restarting the select, initialize the fdsets again.
+	  Init control sockets so we don't accidentally close a random socket.
+	  API: GstUDPSrc::timeout property
+
+2006-09-29 08:15:05 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Fix flag registration.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtsp_proto_get_type):
+	  Fix flag registration.
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_read):
+	  Reading 0 also means 'no more commands'
+
+2006-09-29 08:09:24 +0000  Antoine Tremblay <hexa00@gmail.com>
+
+	  gst/udp/gstudpsrc.c: Fix possible infinite loop when shutting down, a read can also return 0 to indicate no more mess...
+	  Original commit message from CVS:
+	  Patch by: Antoine Tremblay <hexa00 at gmail dot com>
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_create):
+	  Fix possible infinite loop when shutting down, a read can also return
+	  0 to indicate no more messages are available. Fixes #358156.
+
+2006-09-28 17:08:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/v4l2/: Framerate can be 0/1 too.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_get_all_caps),
+	  (gst_v4l2src_get_caps):
+	  * sys/v4l2/v4l2_calls.c: (gst_v4l2_fill_lists):
+	  Framerate can be 0/1 too.
+	  Init framerate to 0/1 before querying it so that we can detect
+	  devices that don't know about a framerate.
+	  Add some more debugging info.
+
+2006-09-28 14:31:41 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Add support for 'yv12' fourcc.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_video_caps):
+	  Add support for 'yv12' fourcc.
+
+2006-09-27 17:47:57 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* tests/icles/v4l2src-test.c:
+	  Removed set-undef-fps.
+	  Original commit message from CVS:
+	  Removed set-undef-fps.
+
+2006-09-27 17:04:22 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/v4l2/: Renamed some properties to match the tuner interface naming.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2object.c:
+	  (gst_v4l2_object_install_properties_helper), (gst_v4l2_object_new),
+	  (gst_v4l2_object_set_property_helper),
+	  (gst_v4l2_object_get_property_helper), (gst_v4l2_set_defaults):
+	  * sys/v4l2/gstv4l2object.h:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init),
+	  (gst_v4l2src_create):
+	  * sys/v4l2/gstv4l2tuner.c: (gst_v4l2_tuner_contains_channel),
+	  (gst_v4l2_tuner_list_channels),
+	  (gst_v4l2_tuner_set_channel_and_notify),
+	  (gst_v4l2_tuner_get_channel), (gst_v4l2_tuner_contains_norm),
+	  (gst_v4l2_tuner_list_norms), (gst_v4l2_tuner_set_norm_and_notify),
+	  (gst_v4l2_tuner_get_norm):
+	  * sys/v4l2/v4l2_calls.c: (gst_v4l2_get_capabilities),
+	  (gst_v4l2_fill_lists), (gst_v4l2_empty_lists):
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_get_fps):
+	  Renamed some properties to match the tuner interface naming.
+
+2006-09-27 16:14:18 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  Small cleanups.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2object.c: (gst_v4l2_object_set_property_helper),
+	  (gst_v4l2_set_defaults):
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_get_read),
+	  (gst_v4l2src_create):
+	  * sys/v4l2/gstv4l2xoverlay.c: (gst_v4l2_xoverlay_open):
+	  * sys/v4l2/v4l2_calls.c: (gst_v4l2_get_capabilities),
+	  (gst_v4l2_fill_lists), (gst_v4l2_open), (gst_v4l2_set_norm),
+	  (gst_v4l2_get_frequency), (gst_v4l2_set_frequency),
+	  (gst_v4l2_signal_strength), (gst_v4l2_get_attribute),
+	  (gst_v4l2_set_attribute), (gst_v4l2_get_input),
+	  (gst_v4l2_set_input):
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list),
+	  (gst_v4l2src_grab_frame), (gst_v4l2src_get_capture),
+	  (gst_v4l2src_set_capture), (gst_v4l2src_capture_init),
+	  (gst_v4l2src_capture_start), (gst_v4l2src_capture_stop),
+	  (gst_v4l2src_buffer_new):
+	  * tests/icles/v4l2src-test.c: (my_bus_callback), (main):
+	  Small cleanups.
+	  Fix error messages.
+	  Use locks when getting timestamps.
+	  Fix leaks in test.
+	  Add licensing header to tests.
+
+2006-09-27 15:14:07 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/gstv4l2tuner.c:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2src_calls.c:
+	* tests/icles/v4l2src-test.c:
+	  Some cleanups and comments.
+	  Original commit message from CVS:
+	  Some cleanups and comments.
+
+2006-09-27 13:41:35 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  add audiofx plugin
+	  Original commit message from CVS:
+	  add audiofx plugin
+
+2006-09-26 14:17:54 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  docs/plugins/: Add v4l2 plugin to the docs.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  Add v4l2 plugin to the docs.
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_get_read),
+	  (gst_v4l2src_get_mmap), (gst_v4l2src_create):
+	  * sys/v4l2/gstv4l2src.h:
+	  * sys/v4l2/gstv4l2vidorient.c:
+	  Fix docs.
+	  Remove some more externs.
+
+2006-09-26 13:18:06 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/v4l2/Makefile.am: Fix makefile, list libs in stack order.
+	  Original commit message from CVS:
+	  * sys/v4l2/Makefile.am:
+	  Fix makefile, list libs in stack order.
+	  * sys/v4l2/gstv4l2colorbalance.c:
+	  * sys/v4l2/gstv4l2colorbalance.h:
+	  * sys/v4l2/gstv4l2object.c: (gst_v4l2_device_get_type),
+	  (gst_v4l2_object_install_properties_helper):
+	  * sys/v4l2/gstv4l2object.h:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_get_read),
+	  (gst_v4l2src_get_mmap), (gst_v4l2src_create):
+	  * sys/v4l2/gstv4l2src.h:
+	  * sys/v4l2/gstv4l2tuner.h:
+	  * sys/v4l2/gstv4l2vidorient.h:
+	  * sys/v4l2/gstv4l2xoverlay.h:
+	  * sys/v4l2/v4l2_calls.h:
+	  * sys/v4l2/v4l2src_calls.h:
+	  Fix coding style:
+	  - Remove extern from functions.
+	  - Fix header indentation.
+	  Fix Flags, add defaults for properties.
+	  Remove unused enums.
+	  Fix TOO_LAZY in error messages.
+
+2006-09-26 11:06:17 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/v4l2/: Fix pass at code cleanups, move errors cases out of the normal flow for additional code clarity.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2object.c: (gst_v4l2_class_probe_devices),
+	  (gst_v4l2_probe_needs_probe),
+	  (gst_v4l2_object_install_properties_helper), (gst_v4l2_object_new),
+	  (gst_v4l2_object_destroy), (gst_v4l2_object_set_property_helper),
+	  (gst_v4l2_object_get_property_helper), (gst_v4l2_set_defaults),
+	  (gst_v4l2_object_start), (gst_v4l2_object_stop):
+	  * sys/v4l2/gstv4l2object.h:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init),
+	  (gst_v4l2src_init), (gst_v4l2src_dispose),
+	  (gst_v4l2src_set_property), (gst_v4l2src_get_property),
+	  (gst_v4l2src_fixate), (gst_v4l2src_get_caps),
+	  (gst_v4l2src_set_caps), (gst_v4l2src_get_read),
+	  (gst_v4l2src_get_mmap), (gst_v4l2src_create):
+	  * sys/v4l2/v4l2_calls.c: (gst_v4l2_get_capabilities),
+	  (gst_v4l2_open), (gst_v4l2_close), (gst_v4l2_get_norm),
+	  (gst_v4l2_set_norm), (gst_v4l2_get_frequency),
+	  (gst_v4l2_set_frequency), (gst_v4l2_signal_strength),
+	  (gst_v4l2_get_attribute), (gst_v4l2_set_attribute),
+	  (gst_v4l2_get_input), (gst_v4l2_set_input):
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list),
+	  (gst_v4l2src_queue_frame), (gst_v4l2src_grab_frame),
+	  (gst_v4l2src_get_capture), (gst_v4l2src_set_capture),
+	  (gst_v4l2src_capture_init), (gst_v4l2src_capture_start),
+	  (gst_v4l2src_capture_stop), (gst_v4l2src_capture_deinit),
+	  (gst_v4l2src_get_size_limits), (gst_v4l2src_set_fps),
+	  (gst_v4l2src_get_fps), (gst_v4l2src_buffer_finalize),
+	  (gst_v4l2src_buffer_new):
+	  Fix pass at code cleanups, move errors cases out of the normal
+	  flow for additional code clarity.
+
+2006-09-25 13:55:44 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/autodetect/: Small cleanups. don't try to set "sync" property when it is not available.
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautoaudiosink.c:
+	  (gst_auto_audio_sink_base_init), (gst_auto_audio_sink_class_init),
+	  (gst_auto_audio_sink_find_best):
+	  * gst/autodetect/gstautovideosink.c: (gst_auto_video_sink_detect):
+	  Small cleanups.
+	  don't try to set "sync" property when it is not available.
+
+2006-09-25 11:47:42 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  gst/: Include stdlib.h in some more places, makes things compile with uClibc and -Werror (#357592).
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt  <pkj at axis com>
+	  * gst/alpha/gstalpha.c:
+	  * gst/rtp/gstrtpamrdepay.c:
+	  * gst/rtsp/gstrtspsrc.c:
+	  * gst/udp/gstudpsrc.c:
+	  * gst/videomixer/videomixer.c:
+	  Include stdlib.h in some more places, makes things compile
+	  with uClibc and -Werror (#357592).
+
+2006-09-25 09:15:10 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/jpeg/gstjpegdec.c: our code should handle that fine. Some of the buttons on the apple trailer site are apparently...
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c:
+	  Set minimum height to 8 (from 16), our code should handle
+	  that fine. Some of the buttons on the apple trailer site
+	  are apparently only 15 pixels high (see #357470).
+
+2006-09-23 15:31:56 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/: Improve error reporting.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_loop), (gst_rtspsrc_send),
+	  (gst_rtspsrc_open):
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_create),
+	  (rtsp_connection_connect), (rtsp_connection_read), (read_body),
+	  (rtsp_connection_receive):
+	  * gst/rtsp/rtspdefs.c: (rtsp_strresult):
+	  * gst/rtsp/rtspdefs.h:
+	  Improve error reporting.
+
+2006-09-23 15:30:40 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Fix klass typos.
+	  Original commit message from CVS:
+	  * gst/rtp/gstasteriskh263.c: (gst_asteriskh263_plugin_init):
+	  * gst/rtp/gstrtpL16depay.c: (gst_rtp_L16depay_plugin_init):
+	  * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_plugin_init):
+	  * gst/rtp/gstrtpdepay.c:
+	  * gst/rtp/gstrtpgsmdepay.c: (gst_rtp_gsm_depay_plugin_init):
+	  * gst/rtp/gstrtph263pdepay.c: (gst_rtp_h263p_depay_plugin_init):
+	  * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_plugin_init):
+	  * gst/rtp/gstrtpilbcdepay.c: (gst_rtp_ilbc_depay_plugin_init):
+	  * gst/rtp/gstrtpmp2tdepay.c: (gst_rtp_mp2t_depay_setcaps),
+	  (gst_rtp_mp2t_depay_plugin_init):
+	  * gst/rtp/gstrtpmp4gdepay.c: (gst_rtp_mp4g_depay_plugin_init):
+	  * gst/rtp/gstrtpmp4vdepay.c: (gst_rtp_mp4v_depay_plugin_init):
+	  * gst/rtp/gstrtpmpadepay.c: (gst_rtp_mpa_depay_plugin_init):
+	  * gst/rtp/gstrtppcmadepay.c: (gst_rtp_pcma_depay_plugin_init):
+	  * gst/rtp/gstrtppcmudepay.c: (gst_rtp_pcmu_depay_plugin_init):
+	  * gst/rtp/gstrtpspeexdepay.c: (gst_rtp_speex_depay_plugin_init):
+	  * gst/rtp/gstrtpsv3vdepay.c: (gst_rtp_sv3v_depay_plugin_init):
+	  * gst/rtp/gstrtpvorbisdepay.c: (gst_rtp_vorbis_depay_plugin_init):
+	  Fix klass typos.
+	  Mark RANK_MARGINAL, decodebin can handle the depayloaders fine.
+
+2006-09-22 17:53:48 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Need  -base CVS for gst_base_rtp_depayload_push_ts().
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Need  -base CVS for gst_base_rtp_depayload_push_ts().
+
+2006-09-22 17:22:34 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: Don't check for a tag that is never there and check if we read the correct tag. Fixes seeking ...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_stream_index):
+	  Don't check for a tag that is never there and check if we read the
+	  correct tag. Fixes seeking again.
+	  We must post an error when all pads are unlinked.
+
+2006-09-22 15:15:13 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: More fixage, set endoder-params correctly in the payloader.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpvorbisdepay.c: (gst_rtp_vorbis_depay_process):
+	  * gst/rtp/gstrtpvorbispay.c: (gst_rtp_vorbis_pay_setcaps),
+	  (gst_rtp_vorbis_pay_reset_packet),
+	  (gst_rtp_vorbis_pay_init_packet),
+	  (gst_rtp_vorbis_pay_flush_packet), (gst_rtp_vorbis_pay_parse_id),
+	  (gst_rtp_vorbis_pay_handle_buffer):
+	  More fixage, set endoder-params correctly in the payloader.
+
+2006-09-22 12:12:10 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/autodetect/: Make static pad templates static to appease valgrind's leak detector.
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautoaudiosink.c:
+	  (gst_auto_audio_sink_base_init):
+	  * gst/autodetect/gstautovideosink.c:
+	  (gst_auto_video_sink_base_init):
+	  Make static pad templates static to appease valgrind's leak
+	  detector.
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/autodetect.c: (GST_START_TEST),
+	  (autodetect_suite):
+	  Add simple test for the ghostpad lockup on shutdown fixed in core
+	  CVS (audio bit disabled because it would need dozens of alsa
+	  suppressions and I'm too lazy to add those now).
+
+2006-09-22 12:08:14 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Small cleanups.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpL16depay.c: (gst_rtp_L16depay_change_state):
+	  * gst/rtp/gstrtpmp4gdepay.c: (gst_rtp_mp4g_depay_class_init):
+	  Small cleanups.
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpvorbisdepay.c: (gst_rtp_vorbis_depay_base_init),
+	  (gst_rtp_vorbis_depay_class_init), (gst_rtp_vorbis_depay_init),
+	  (gst_rtp_vorbis_depay_finalize), (gst_rtp_vorbis_depay_setcaps),
+	  (gst_rtp_vorbis_depay_process),
+	  (gst_rtp_vorbis_depay_set_property),
+	  (gst_rtp_vorbis_depay_get_property),
+	  (gst_rtp_vorbis_depay_change_state),
+	  (gst_rtp_vorbis_depay_plugin_init):
+	  * gst/rtp/gstrtpvorbisdepay.h:
+	  * gst/rtp/gstrtpvorbispay.c: (gst_rtp_vorbis_pay_base_init),
+	  (gst_rtp_vorbis_pay_class_init), (gst_rtp_vorbis_pay_init),
+	  (gst_rtp_vorbis_pay_setcaps), (gst_rtp_vorbis_pay_init_packet),
+	  (gst_rtp_vorbis_pay_flush_packet),
+	  (gst_rtp_vorbis_pay_append_buffer),
+	  (gst_rtp_vorbis_pay_handle_buffer),
+	  (gst_rtp_vorbis_pay_plugin_init):
+	  * gst/rtp/gstrtpvorbispay.h:
+	  Add experimental vorbis pay and depayloaders.
+
+2006-09-21 13:33:16 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmp4gpay.c: Fix profile-level-id parsing and setup.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4gpay.c: (gst_rtp_mp4g_pay_parse_audio_config):
+	  Fix profile-level-id parsing and setup.
+
+2006-09-21 09:50:41 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/: Update README, simple cleanup.
+	  Original commit message from CVS:
+	  * gst/udp/README:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_set_property):
+	  Update README, simple cleanup.
+
+2006-09-21 09:35:13 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/README: Update README with some examples.
+	  Original commit message from CVS:
+	  * gst/rtp/README:
+	  Update README with some examples.
+	  * gst/rtp/gstrtpmp4gpay.c: (gst_rtp_mp4g_pay_init),
+	  (gst_rtp_mp4g_pay_finalize), (gst_rtp_mp4g_pay_parse_audio_config),
+	  (gst_rtp_mp4g_pay_parse_video_config), (gst_rtp_mp4g_pay_new_caps),
+	  (gst_rtp_mp4g_pay_setcaps):
+	  * gst/rtp/gstrtpmp4gpay.h:
+	  Make optional RTP parameters of type STRING, as required by the
+	  application/x-rtp caps specification.
+
+2006-09-20 19:37:45 +0000  Philippe Kalaf <philippe.kalaf@collabora.co.uk>
+
+	  gst/rtp/: Correctly calculate size of each H263+ RTP buffer taking into account MTU and
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph263pdepay.c:
+	  * gst/rtp/gstrtph263ppay.c:
+	  Correctly calculate size of each H263+ RTP buffer taking into account MTU and
+	  RTP header.
+
+2006-09-20 16:41:48 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/Makefile.am: And makefile too.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  And makefile too.
+
+2006-09-20 16:09:03 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Added preliminary ASF depayloader.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpasfdepay.c: (gst_rtp_asf_depay_base_init),
+	  (gst_rtp_asf_depay_class_init), (gst_rtp_asf_depay_init),
+	  (decode_base64), (gst_rtp_asf_depay_setcaps),
+	  (gst_rtp_asf_depay_process), (gst_rtp_asf_depay_set_property),
+	  (gst_rtp_asf_depay_get_property), (gst_rtp_asf_depay_change_state),
+	  (gst_rtp_asf_depay_plugin_init):
+	  * gst/rtp/gstrtpasfdepay.h:
+	  Added preliminary ASF depayloader.
+	  * gst/rtp/gstrtph264depay.c: (decode_base64):
+	  Fix base64 decoding.
+
+2006-09-20 16:06:27 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/URLS: Added some test URLS.
+	  Original commit message from CVS:
+	  * gst/rtsp/URLS:
+	  Added some test URLS.
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_create_stream),
+	  (gst_rtspsrc_loop), (gst_rtspsrc_open):
+	  * gst/rtsp/gstrtspsrc.h:
+	  When creating streams, give access to the complete SDP.
+	  Fix some leaks.
+	  Collect and merge global stream properties in stream caps.
+	  Preliminary support for WMServer.
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_create),
+	  (rtsp_connection_connect), (rtsp_connection_read), (read_body),
+	  (rtsp_connection_receive):
+	  * gst/rtsp/rtspconnection.h:
+	  Make connection interruptable.
+	  Refactor to make it reconnectable.
+	  Don't fail on short reads when reading data packets.
+	  * gst/rtsp/rtspurl.c: (rtsp_url_parse), (rtsp_url_set_port),
+	  (rtsp_url_get_port):
+	  * gst/rtsp/rtspurl.h:
+	  Add methods for getting/setting the port.
+	  * gst/rtsp/sdpmessage.c: (sdp_message_get_attribute_val_n),
+	  (sdp_message_get_attribute_val), (sdp_media_get_attribute),
+	  (sdp_media_get_attribute_val_n), (sdp_media_get_attribute_val),
+	  (sdp_media_get_format), (sdp_parse_line),
+	  (sdp_message_parse_buffer):
+	  Fix headers.
+	  Add methods for getting multiple attributes with the same name.
+	  Increase buffer size when parsing.
+	  Fix parsing of a=foo fields.
+	  * gst/rtsp/test.c: (main):
+	  Update to new connection API.
+	  * gst/rtsp/rtspmessage.c: (rtsp_message_new_response),
+	  (rtsp_message_init_response), (rtsp_message_init_data),
+	  (rtsp_message_unset), (rtsp_message_free), (rtsp_message_dump):
+	  * gst/rtsp/rtspmessage.h:
+	  * gst/rtsp/rtsptransport.c: (rtsp_transport_free):
+	  * gst/rtsp/rtsptransport.h:
+	  * gst/rtsp/sdp.h:
+	  * gst/rtsp/sdpmessage.h:
+	  * gst/rtsp/gstrtsp.c:
+	  * gst/rtsp/gstrtsp.h:
+	  * gst/rtsp/gstrtpdec.c:
+	  * gst/rtsp/gstrtpdec.h:
+	  * gst/rtsp/rtsp.h:
+	  * gst/rtsp/rtspdefs.c:
+	  * gst/rtsp/rtspdefs.h:
+	  Dual licensed under MIT and LGPL now.
+
+2006-09-19 17:25:15 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Reorganize stream parsing and creation.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (find_stream_by_pt),
+	  (gst_rtspsrc_create_stream), (gst_rtspsrc_free_stream),
+	  (gst_rtspsrc_media_to_caps), (gst_rtspsrc_stream_setup_rtp),
+	  (gst_rtspsrc_stream_configure_transport), (find_stream_by_channel),
+	  (gst_rtspsrc_push_event), (gst_rtspsrc_loop), (gst_rtspsrc_send),
+	  (gst_rtspsrc_parse_methods), (gst_rtspsrc_open),
+	  (gst_rtspsrc_parse_rtpinfo), (gst_rtspsrc_play):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Reorganize stream parsing and creation.
+	  Detect container formats in interleaved mode.
+	  Keep more state about the streams.
+	  Assume a server also supports PLAY if it does not say.
+	  Add unicast and interleaved properties to TCP transport requests to make
+	  some servers happy (WMServer).
+	  * gst/rtsp/sdpmessage.h:
+	  Add some defines for the standard Bandwidth types.
+
+2006-09-19 16:24:10 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* tests/icles/v4l2src-test.c:
+	  Just a small fix to the app options.
+	  Original commit message from CVS:
+	  Just a small fix to the app options.
+
+2006-09-19 13:08:35 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2vidorient.c:
+	* sys/v4l2/gstv4l2vidorient.h:
+	* tests/icles/v4l2src-test.c:
+	  Add Video Orientation interface support to v4l2src.
+	  Original commit message from CVS:
+	  Add Video Orientation interface support to v4l2src.
+
+2006-09-19 10:53:56 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/test.c: Fix build.
+	  Original commit message from CVS:
+	  * gst/rtsp/test.c: (main):
+	  Fix build.
+
+2006-09-19 10:14:52 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/wavparse/gstwavparse.c: Add ms-gsm to the src template.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c:
+	  Add ms-gsm to the src template.
+
+2006-09-18 17:37:46 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Small cleanups, added documentation.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_media_to_caps),
+	  (gst_rtspsrc_send), (gst_rtspsrc_parse_methods),
+	  (gst_rtspsrc_open), (gst_rtspsrc_close), (gst_rtspsrc_play),
+	  (gst_rtspsrc_pause), (gst_rtspsrc_change_state),
+	  (gst_rtspsrc_uri_get_uri), (gst_rtspsrc_uri_set_uri):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Small cleanups, added documentation.
+	  Try to clean up the requests and responses.
+	  Refactor parsing the supported methods.
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_open),
+	  (rtsp_connection_create), (rtsp_connection_send),
+	  (parse_response_status), (parse_request_line),
+	  (rtsp_connection_receive), (rtsp_connection_close),
+	  (rtsp_connection_free):
+	  * gst/rtsp/rtsptransport.c: (rtsp_transport_new),
+	  (rtsp_transport_init), (rtsp_transport_parse),
+	  (rtsp_transport_free):
+	  * gst/rtsp/rtspurl.c: (rtsp_url_parse):
+	  * gst/rtsp/sdpmessage.c: (sdp_message_new), (sdp_message_init),
+	  (sdp_message_clean), (sdp_message_free), (sdp_media_new),
+	  (sdp_media_init), (sdp_message_parse_buffer), (sdp_message_dump):
+	  Use g_return_val some more.
+	  * gst/rtsp/rtspdefs.h:
+	  Add more enum values to track initial states.
+	  * gst/rtsp/rtspmessage.c: (rtsp_message_new_request),
+	  (rtsp_message_init_request), (rtsp_message_new_response),
+	  (rtsp_message_init_response), (rtsp_message_init_data),
+	  (rtsp_message_unset), (rtsp_message_free),
+	  (rtsp_message_add_header), (rtsp_message_remove_header),
+	  (rtsp_message_get_header), (rtsp_message_set_body),
+	  (rtsp_message_take_body), (rtsp_message_get_body),
+	  (rtsp_message_steal_body), (rtsp_message_dump):
+	  * gst/rtsp/rtspmessage.h:
+	  Reorder arguments, object goes as the first one.
+	  Use g_return_val some more.
+
+2006-09-18 15:36:14 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/v4l2src_calls.c:
+	  Fix GST_BUFFER_DURATION.
+	  Original commit message from CVS:
+	  Fix GST_BUFFER_DURATION.
+
+2006-09-18 14:00:41 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.*: Export sometimes source pad with correct caps on the template, create the ghostpad from the te...
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_base_init),
+	  (gst_rtspsrc_stream_configure_transport), (gst_rtspsrc_push_event),
+	  (gst_rtspsrc_loop), (gst_rtspsrc_uri_set_uri):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Export sometimes source pad with correct caps on the template, create
+	  the ghostpad from the template.
+	  Remove RTCP template as we never expose RTCP.
+	  Protect against invalid body size.
+	  Avoid memcpy when creating the output buffer.
+	  Properly post an error and send EOS when the loop function is shut down.
+
+2006-09-18 11:29:12 +0000  Lutz Mueller <lutz@topfrose.de>
+
+	  gst/rtsp/gstrtspsrc.*: Make sure we can never set an invalid location.
+	  Original commit message from CVS:
+	  Based on patch by: Lutz Mueller <lutz at topfrose dot de>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_class_init),
+	  (gst_rtspsrc_init), (gst_rtspsrc_set_property), (gst_rtspsrc_open),
+	  (gst_rtspsrc_uri_get_uri), (gst_rtspsrc_uri_set_uri):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Make sure we can never set an invalid location.
+	  * gst/rtsp/rtspmessage.c: (rtsp_message_steal_body):
+	  * gst/rtsp/rtspmessage.h:
+	  Added _steal_body method for future use.
+	  * gst/rtsp/rtspurl.c: (rtsp_url_parse), (rtsp_url_free):
+	  Make freeing of NULL url return immediatly.
+
+2006-09-18 10:42:52 +0000  Lutz Mueller <lutz@topfrose.de>
+
+	  gst/rtsp/gstrtspsrc.*: Use boilerplate.
+	  Original commit message from CVS:
+	  Based on patch by: Lutz Mueller <lutz at topfrose dot de>
+	  * gst/rtsp/gstrtspsrc.c: (_do_init), (gst_rtspsrc_class_init),
+	  (gst_rtspsrc_init), (gst_rtspsrc_stream_setup_rtp),
+	  (gst_rtspsrc_stream_configure_transport), (gst_rtspsrc_play),
+	  (gst_rtspsrc_change_state):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Use boilerplate.
+	  Make rtspsrc subclass GstBin to make state changes easier.
+	  Add Range header field on the PLAY request.
+
+2006-09-18 08:59:17 +0000  Thijs Vermeir <thijs.vermeir@barco.com>
+
+	  gst/rtsp/: Small cleanups. when multicast is selected as the transport, create UDP sources and connect to the multica...
+	  Original commit message from CVS:
+	  Based on patch by: Thijs Vermeir <thijs dot vermeir at barco dot com>
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_set_state),
+	  (gst_rtspsrc_media_to_caps), (gst_rtspsrc_stream_setup_rtp),
+	  (gst_rtspsrc_stream_configure_transport), (gst_rtspsrc_open),
+	  (gst_rtspsrc_close), (gst_rtspsrc_play), (gst_rtspsrc_pause):
+	  * gst/rtsp/rtspconnection.c: (inet_aton):
+	  Small cleanups.
+	  when multicast is selected as the transport, create UDP sources and
+	  connect to the multicast group.
+	  Move parsing and setting of caps to a common place.
+	  Fixes #349894.
+
+2006-09-16 22:14:35 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  More G_OBJECT macro fixing.
+	  Original commit message from CVS:
+	  * ext/hermes/gsthermescolorspace.c:
+	  * ext/ivorbis/vorbisfile.c:
+	  * ext/lcs/gstcolorspace.c:
+	  * ext/wavpack/gstwavpackenc.h:
+	  * ext/xine/xineaudiodec.c:
+	  * ext/xine/xineaudiosink.c:
+	  * ext/xine/xineinput.c:
+	  * gst/chart/gstchart.c:
+	  * gst/equalizer/gstiirequalizer.c:
+	  * gst/games/gstpuzzle.c:
+	  * gst/librfb/gstrfbsrc.c:
+	  * gst/mixmatrix/mixmatrix.c:
+	  * gst/nsf/gstnsf.h:
+	  * gst/vbidec/gstvbidec.c:
+	  * gst/virtualdub/gstxsharpen.c:
+	  More G_OBJECT macro fixing.
+
+2006-09-16 21:57:29 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  More G_OBJECT macro fixing.
+	  Original commit message from CVS:
+	  * ext/flac/gstflactag.c:
+	  * gst/alpha/gstalpha.c:
+	  * gst/debug/breakmydata.c:
+	  * gst/debug/negotiation.c:
+	  * gst/debug/testplugin.c:
+	  * gst/effectv/gstaging.c:
+	  * gst/effectv/gstdice.c:
+	  * gst/effectv/gstedge.c:
+	  * gst/effectv/gstquark.c:
+	  * gst/effectv/gstrev.c:
+	  * gst/effectv/gstshagadelic.c:
+	  * gst/effectv/gstvertigo.c:
+	  * gst/effectv/gstwarp.c:
+	  * gst/multipart/multipartdemux.c:
+	  * gst/multipart/multipartmux.c:
+	  * gst/videobox/gstvideobox.c:
+	  * gst/videofilter/gstgamma.c:
+	  * gst/videofilter/gstvideotemplate.c:
+	  * gst/videomixer/videomixer.c:
+	  * sys/sunaudio/gstsunaudiosrc.h:
+	  More G_OBJECT macro fixing.
+
+2006-09-16 14:30:59 +0000  Yves Lefebvre <ivanohe@abacom.com>
+
+	  gst/avi/gstavimux.c: Correctly set the dwLength in strh.
+	  Original commit message from CVS:
+	  Patch by: Yves Lefebvre <ivanohe at abacom dot com>
+	  * gst/avi/gstavimux.c: (gst_avi_mux_stop_file):
+	  Correctly set the dwLength in strh.
+	  With this patch, the file duration is now displayed correctly in window
+	  media player and the AVI plays completely. Fixes #356147
+
+2006-09-15 19:11:00 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/gstv4l2xoverlay.c:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2src_calls.c:
+	* tests/icles/v4l2src-test.c:
+	  The test application and the plgind error messages has been improved.
+	  Original commit message from CVS:
+	  The test application and the plgind error messages has been improved.
+
+2006-09-15 17:10:22 +0000  Darren Kenny <darren.kenny@sun.com>
+
+	  sys/sunaudio/gstsunaudiomixerctrl.c: Set the output track as the MASTER so that the gnome-settings-daemon keybindings...
+	  Original commit message from CVS:
+	  Patch by: Darren Kenny <darren dot kenny at sun dot com>
+	  * sys/sunaudio/gstsunaudiomixerctrl.c:
+	  (gst_sunaudiomixer_ctrl_build_list):
+	  Set the output track as the MASTER so that the gnome-settings-daemon
+	  keybindings for changing the volume using the keyboard works.
+	  Fixes #356142.
+
+2006-09-15 16:01:48 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/multipart/multipartdemux.c: Fix documentation, it is not possible to control the framerate of jpegdec using filte...
+	  Original commit message from CVS:
+	  * gst/multipart/multipartdemux.c: (gst_multipart_demux_chain):
+	  Fix documentation, it is not possible to control the framerate of jpegdec
+	  using filtered caps yet. Fixes #355210.
+	  Return the downstream GstFlowReturn instead of GST_FLOW_OK so that we
+	  stop when there is an error.
+
+2006-09-14 11:05:35 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/: Don't interpret a first buffer with an offset of NONE as 'from the middle of the stream', but only a first buff...
+	  Original commit message from CVS:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_chain_parse_tag):
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_chain):
+	  Don't interpret a first buffer with an offset of NONE as
+	  'from the middle of the stream', but only a first buffer
+	  that has a valid buffer offset that's non-zero (see #345449).
+
+2006-09-14 10:38:42 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/icydemux/gsticydemux.*: When we merge/collect multiple incoming buffers for typefinding purposes, keep an initial...
+	  Original commit message from CVS:
+	  * gst/icydemux/gsticydemux.c: (gst_icydemux_reset),
+	  (gst_icydemux_typefind_or_forward):
+	  * gst/icydemux/gsticydemux.h:
+	  When we merge/collect multiple incoming buffers for typefinding
+	  purposes, keep an initial 0 offset on the first outgoing buffer
+	  as well (otherwise id3demux won't work right). Fixes #345449.
+	  Also Make buffer metadata writable before setting buffer caps.
+	  * tests/check/elements/icydemux.c: (typefind_succeed),
+	  (cleanup_icydemux), (push_data), (GST_START_TEST),
+	  (icydemux_suite):
+	  Small test case for the above.
+
+2006-09-13 13:26:15 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.c: More code reuse and better logging in _peek_chunk(). Reintroduce check for chunk sizes before ...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_peek_chunk),
+	  (gst_avi_demux_stream_index), (gst_avi_demux_sync),
+	  (gst_avi_demux_stream_header_push),
+	  (gst_avi_demux_process_next_entry), (gst_avi_demux_stream_data),
+	  (gst_avi_demux_loop):
+	  More code reuse and better logging in _peek_chunk(). Reintroduce check
+	  for chunk sizes before reading them (avoid oom). Better handling for
+	  invalid chunksizes when streaming.
+
+2006-09-12 20:18:55 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/gstspectrum.c: Implements stop() to clear the adapter and event() to clear the adapter on FLUSH_STOP and...
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_class_init),
+	  (gst_spectrum_start), (gst_spectrum_stop), (gst_spectrum_event):
+	  Implements stop() to clear the adapter and event() to clear the
+	  adapter on FLUSH_STOP and EOS.
+
+2006-09-11 20:38:41 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/level/gstlevel.*: Fix type mixup in level->interval (gdouble<->guint64). Spotted by
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c: (gst_level_set_property):
+	  * gst/level/gstlevel.h:
+	  Fix type mixup in level->interval (gdouble<->guint64). Spotted by
+	  René Stadler
+
+2006-09-11 18:23:59 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/gstspectrum.*: Fix type mixup in spectrum->interval (gdouble<->guint64). Spotted by
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_init),
+	  (gst_spectrum_set_property):
+	  * gst/spectrum/gstspectrum.h:
+	  Fix type mixup in spectrum->interval (gdouble<->guint64). Spotted by
+	  René Stadler
+
+2006-09-11 18:02:39 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/demo-osssrc.c: Use more defines
+	  Original commit message from CVS:
+	  * gst/spectrum/demo-osssrc.c: (draw_spectrum), (main):
+	  Use more defines
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_init),
+	  (gst_spectrum_dispose), (gst_spectrum_set_caps),
+	  (gst_spectrum_transform_ip):
+	  * gst/spectrum/gstspectrum.h:
+	  Apply some of the spectrum cleanup changes suggested in #348085.
+
+2006-09-08 16:47:46 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Bump requirements of -base (videocrop test case needs this).
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Bump requirements of -base (videocrop test case needs this).
+	  * gst/videocrop/gstvideocrop.c:
+	  Document sloppy handling of subsampled chroma planes if
+	  left/top cropping is an odd number.
+	  * tests/check/elements/videocrop.c: (handoff_cb),
+	  (videocrop_test_cropping_init_context),
+	  (videocrop_test_cropping_deinit_context),
+	  (videocrop_test_cropping), (check_1x1_buffer), (GST_START_TEST),
+	  (videocrop_suite), (main):
+	  Add another unit test that crops the input to 1x1 (and checks
+	  that that pixel has the expected values in a number of formats).
+
+2006-09-08 11:04:24 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/videocrop/: Some quick tests indicate that it doesn't make a great deal of sense to use liboil here, at least not...
+	  Original commit message from CVS:
+	  * gst/videocrop/Makefile.am:
+	  * gst/videocrop/gstvideocrop.c: (gst_video_crop_class_init),
+	  (gst_video_crop_transform_packed),
+	  (gst_video_crop_transform_planar):
+	  Some quick tests indicate that it doesn't make a great deal
+	  of sense to use liboil here, at least not for the memcpy()s
+	  we do, so remove liboil usage until there is clear evidence
+	  it actually makes a positive difference somewhere.
+
+2006-09-06 09:05:33 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.c: Revert one change to fix streaming avi (adapter size != data size).
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_read_subindexes_pull),
+	  (gst_avi_demux_sync), (gst_avi_demux_stream_header_push),
+	  (gst_avi_demux_stream_data):
+	  Revert one change to fix streaming avi (adapter size != data size).
+
+2006-09-04 16:21:17 +0000  Frédéric Riss <frederic.riss@gmail.com>
+
+	  gst/matroska/: Add support for VOBSUB subtitle tracks and zlib-compressed tracks. Make sure we start on a keyframe af...
+	  Original commit message from CVS:
+	  Patch by: Frédéric Riss  <frederic.riss at gmail dot com>
+	  * gst/matroska/matroska-demux.c: (gst_matroska_track_free),
+	  (gst_matroska_demux_reset),
+	  (gst_matroska_demux_read_track_encodings),
+	  (gst_matroska_demux_add_stream), (gst_matroska_decode_buffer),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+	  (gst_matroska_demux_subtitle_caps):
+	  * gst/matroska/matroska-ids.h:
+	  Add support for VOBSUB subtitle tracks and zlib-compressed
+	  tracks. Make sure we start on a keyframe after a seek. (#343348)
+
+2006-09-04 15:06:25 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/: not perfect yet though, needs some tweaking in flacdec; also, seeking could be better.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_push_hdr_buf),
+	  (gst_matroska_demux_push_flac_codec_priv_data),
+	  (gst_matroska_demux_push_xiph_codec_priv_data),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+	  (gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps):
+	  * gst/matroska/matroska-ids.h:
+	  Add basic FLAC support (#311586), not perfect yet though, needs some
+	  tweaking in flacdec; also, seeking could be better.
+	  Do better bounds checking when deserialising vorbis stream headers
+	  to make sure we don't read beyond the end of the buffer on bad input.
+
+2006-09-04 09:34:25 +0000  Alessandro Decina <alessandro@nnva.org>
+
+	  ext/annodex/gstcmmldec.c: Seeking back in a file containing a CMML stream errors out if the seek goes back up to the ...
+	  Original commit message from CVS:
+	  Patch by: Alessandro Decina <alessandro at nnva dot org>
+	  * ext/annodex/gstcmmldec.c: (gst_cmml_dec_chain):
+	  Seeking back in a file containing a CMML stream errors out if the seek
+	  goes back up to the CMML headers. This is because after the seek the xml
+	  processing instruction <?xml ...?> is submitted to the xml parser again,
+	  which results in an error. The attached patch fixes the problem.
+	  Fixes #353908.
+	  * ext/annodex/gstcmmlenc.h:
+	  Fix authors name.
+
+2006-09-03 10:46:17 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/check/elements/videocrop.c: More tests: check passthrough mode and caps transform in both directions with fixed...
+	  Original commit message from CVS:
+	  * tests/check/elements/videocrop.c: (handoff_cb),
+	  (buffer_probe_cb), (test_caps_transform), (test_passthrough),
+	  (notgst_value_list_get_nth_int), (videocrop_suite):
+	  More tests: check passthrough mode and caps transform in
+	  both directions with fixed values, ranges and lists.
+
+2006-09-02 18:49:01 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  docs/plugins/: Add videocrop to docs.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-bad-plugins.hierarchy:
+	  Add videocrop to docs.
+	  * gst/videocrop/Makefile.am:
+	  * gst/videocrop/gstvideocrop.c:
+	  * gst/videocrop/gstvideocrop.h:
+	  Move boilerplate stuff and structures into a header file.
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/videocrop.c: (video_crop_get_test_caps),
+	  (test_unit_sizes), (videocrop_test_cropping_init_context),
+	  (videocrop_test_cropping_deinit_context),
+	  (videocrop_test_cropping), (test_cropping), (videocrop_suite):
+	  Add unit tests for videocrop.
+
+2006-09-02 15:30:45 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Port/rewrite videocrop from scratch for GStreamer-0.10, and make it support all formats videoscale supports (#345653).
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/videocrop/Makefile.am:
+	  * gst/videocrop/gstvideocrop.c: (gst_video_crop_base_init),
+	  (gst_video_crop_class_init), (gst_video_crop_init),
+	  (gst_video_crop_get_image_details_from_caps),
+	  (gst_video_crop_get_unit_size), (gst_video_crop_transform_packed),
+	  (gst_video_crop_transform_planar), (gst_video_crop_transform),
+	  (gst_video_crop_transform_dimension),
+	  (gst_video_crop_transform_dimension_value),
+	  (gst_video_crop_transform_caps), (gst_video_crop_set_caps),
+	  (gst_video_crop_set_property), (gst_video_crop_get_property),
+	  (plugin_init):
+	  Port/rewrite videocrop from scratch for GStreamer-0.10, and make
+	  it support all formats videoscale supports (#345653).
+
+2006-09-02 14:45:04 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/v4l2/: Whitespace cleanups, dashify property-names.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2.c:
+	  * sys/v4l2/gstv4l2colorbalance.c:
+	  * sys/v4l2/gstv4l2object.c:
+	  (gst_v4l2_object_install_properties_helper):
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init):
+	  * sys/v4l2/gstv4l2src.h:
+	  Whitespace cleanups, dashify property-names.
+
+2006-09-02 14:28:55 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/v4l2/: Cleanup error messages and unify header comments
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2.c:
+	  * sys/v4l2/gstv4l2colorbalance.c:
+	  * sys/v4l2/gstv4l2colorbalance.h:
+	  * sys/v4l2/gstv4l2object.c:
+	  * sys/v4l2/gstv4l2object.h:
+	  * sys/v4l2/gstv4l2src.c:
+	  * sys/v4l2/gstv4l2src.h:
+	  * sys/v4l2/gstv4l2tuner.c:
+	  * sys/v4l2/gstv4l2tuner.h:
+	  * sys/v4l2/gstv4l2xoverlay.c: (gst_v4l2_xoverlay_open):
+	  * sys/v4l2/gstv4l2xoverlay.h:
+	  * sys/v4l2/v4l2_calls.c: (gst_v4l2_get_capabilities),
+	  (gst_v4l2_open):
+	  * sys/v4l2/v4l2_calls.h:
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_queue_frame),
+	  (gst_v4l2src_capture_init):
+	  * sys/v4l2/v4l2src_calls.h:
+	  Cleanup error messages and unify header comments
+
+2006-08-30 18:01:52 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2src.c:
+	  Another small fix to set_caps function.
+	  Original commit message from CVS:
+	  Another small fix to set_caps function.
+
+2006-08-30 13:30:13 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2src.c:
+	  Send new_segment in GST_FORMAT_TIME instead of in GST_FORMAT_BYTES.
+	  Original commit message from CVS:
+	  Send new_segment in GST_FORMAT_TIME instead of in GST_FORMAT_BYTES.
+
+2006-08-30 11:36:06 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2src.c:
+	  A small fix to set_caps function.
+	  Original commit message from CVS:
+	  A small fix to set_caps function.
+
+2006-08-30 11:27:40 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Reset each streams last_flow to GST_FLOW_OK.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c:
+	  (gst_qtdemux_do_seek):
+	  Reset each streams last_flow to GST_FLOW_OK.
+	  (gst_qtdemux_activate_segment):
+	  Removing mystic modifications for good.
+
+2006-08-30 11:07:37 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/qtdemux/qtdemux.c: put back 'segment start<=stop' change that was mystically reverted by the last commit
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_activate_segment),
+	  (qtdemux_parse_tree):
+	  put back 'segment start<=stop' change that was mystically reverted by
+	  the last commit
+
+2006-08-30 10:43:53 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/qtdemux/qtdemux.c: Fix the build for disabled debug
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_activate_segment),
+	  (qtdemux_parse_tree):
+	  Fix the build for disabled debug
+
+2006-08-29 20:59:47 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/v4l2/v4l2src_calls.h:
+	  Fixed framerate negotiation.
+	  Original commit message from CVS:
+	  Fixed framerate negotiation.
+
+2006-08-28 17:47:29 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Make sure segment start<=stop in weird quicktime files.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_activate_segment),
+	  (gst_qtdemux_add_stream), (qtdemux_parse_trak),
+	  (qtdemux_video_caps):
+	  Make sure segment start<=stop in weird quicktime files.
+
+2006-08-28 16:59:13 +0000  Andy Wingo <wingo@pobox.com>
+
+	  ext/raw1394/gstdv1394src.c (gst_dv1394src_from_raw1394handle): New helper function to lessen the ifdefs.
+	  Original commit message from CVS:
+	  2006-08-28  Andy Wingo  <wingo@pobox.com>
+	  * ext/raw1394/gstdv1394src.c (gst_dv1394src_from_raw1394handle):
+	  New helper function to lessen the ifdefs.
+	  (GST_INFO_OBJECT):
+	  (gst_dv1394src_iso_receive): Use it.
+	  (gst_dv1394src_create): Also use the control sockets in iec61883
+	  mode.
+	  (gst_dv1394src_start, gst_dv1394src_stop): Always use a separate
+	  handle for AVC operations; fixes #348233.
+
+2006-08-28 14:59:05 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/v4l2/v4l2_calls.c: add comments and more debug logging
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2_calls.c: (gst_v4l2_fill_lists):
+	  add comments and more debug logging
+
+2006-08-27 17:14:06 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Rename again (audiofxgood -> audiofx).
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/inspect/plugin-audiofx.xml:
+	  * docs/plugins/inspect/plugin-audiofxgood.xml:
+	  * gst/audiofx/Makefile.am:
+	  * gst/audiofx/audiofx.c:
+	  * gst/audiofxgood/.cvsignore:
+	  * gst/audiofxgood/Makefile.am:
+	  * gst/audiofxgood/audiofx.c:
+	  * gst/audiofxgood/audiopanorama.c:
+	  * gst/audiofxgood/audiopanorama.h:
+	  Rename again (audiofxgood -> audiofx).
+
+2006-08-27 13:12:52 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.c: Initialze variables.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_next_data_buffer),
+	  (gst_avi_demux_stream_scan):
+	  Initialze variables.
+
+2006-08-25 16:21:37 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.*: More attempts to turn this into readable code.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_class_init),
+	  (gst_avi_demux_init), (gst_avi_demux_finalize),
+	  (gst_avi_demux_reset), (gst_avi_demux_index_last),
+	  (gst_avi_demux_index_next), (gst_avi_demux_index_entry_for_time),
+	  (gst_avi_demux_parse_subindex), (gst_avi_demux_parse_index),
+	  (gst_avi_demux_stream_index), (gst_avi_demux_peek_tag),
+	  (gst_avi_demux_next_data_buffer), (gst_avi_demux_stream_scan),
+	  (gst_avi_demux_massage_index),
+	  (gst_avi_demux_calculate_durations_from_index),
+	  (gst_avi_demux_stream_header_pull), (gst_avi_demux_do_seek),
+	  (gst_avi_demux_process_next_entry), (gst_avi_demux_loop),
+	  (gst_avi_demux_chain), (gst_avi_demux_sink_activate),
+	  (gst_avi_demux_change_state):
+	  * gst/avi/gstavidemux.h:
+	  More attempts to turn this into readable code.
+	  Don't leak adapters.
+	  Calculate duration according to index more efficiently.
+	  Don't try to act like we drive the pipeline in chain mode.
+
+2006-08-25 09:53:18 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/annodex/gstcmmlutils.c: Fix build.
+	  Original commit message from CVS:
+	  * ext/annodex/gstcmmlutils.c: (gst_cmml_clock_time_from_npt):
+	  Fix build.
+
+2006-08-25 09:42:43 +0000  Alessandro Decina <alessandro@nnva.org>
+
+	  ext/annodex/gstannodex.c: Do some extra sanity checks.
+	  Original commit message from CVS:
+	  Patch by: Alessandro Decina <alessandro at nnva dot org>
+	  * ext/annodex/gstannodex.c: (gst_annodex_granule_to_time):
+	  Do some extra sanity checks.
+	  Fixes #350340.
+	  * ext/annodex/gstcmmlenc.c: (gst_cmml_enc_change_state),
+	  (gst_cmml_enc_parse_tag_head), (gst_cmml_enc_parse_tag_clip),
+	  (gst_cmml_enc_push_clip), (gst_cmml_enc_push):
+	  Check if clip->start_time is valid before adding the clip to the
+	  track list.
+	  Reset enc->preamble going from PAUSED to READY.
+	  Don't use GST_FLOW_UNEXPECTED for wrong usage of the element, it is
+	  only used for EOS.
+	  Only post an error message if we were the one that created the fatal
+	  GstFlowReturn value.
+	  * ext/annodex/gstcmmlutils.c: (gst_cmml_clock_time_from_npt),
+	  (gst_cmml_clock_time_to_granule), (gst_cmml_track_list_has_clip):
+	  Parse the seconds field of the npt-sec time format using %llu rather than
+	  %d and check that the value scaled by GST_SECOND doesn't overflow.
+	  Use guint64(s) to represent the keyindex and keyoffset fields of a granulepos.
+	  Lookup a clip's track with clip->track rather than clip->id which
+	  makes no sense.
+	  Identify a clip by its track and start time and not its xml id.
+	  do some more input checking and make sure we don't do undefined shifts.
+	  * tests/check/elements/cmmldec.c: (setup_cmmldec),
+	  (teardown_cmmldec), (check_output_buffer_is_equal), (push_data),
+	  (cmml_tag_message_pop), (check_headers), (push_clip_full),
+	  (push_clip), (push_empty_clip), (check_output_clip),
+	  (GST_START_TEST), (cmmldec_suite):
+	  * tests/check/elements/cmmlenc.c: (setup_cmmlenc),
+	  (teardown_cmmlenc), (check_output_buffer_is_equal), (push_data),
+	  (check_headers), (push_clip), (check_clip_times), (check_clip),
+	  (check_empty_clip), (GST_START_TEST), (cmmlenc_suite):
+	  Added some more checks.
+
+2006-08-24 19:00:22 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Make also the pan-property float (saves scaling and yields better resolution)
+	  Original commit message from CVS:
+	  * gst/audiofxgood/audiopanorama.c: (gst_audio_panorama_class_init),
+	  (gst_audio_panorama_set_property),
+	  (gst_audio_panorama_get_property),
+	  (gst_audio_panorama_transform_m2s_int),
+	  (gst_audio_panorama_transform_s2s_int),
+	  (gst_audio_panorama_transform_m2s_float),
+	  (gst_audio_panorama_transform_s2s_float):
+	  * gst/audiofxgood/audiopanorama.h:
+	  * tests/check/elements/audiopanorama.c: (GST_START_TEST):
+	  Make also the pan-property float (saves scaling and yields better
+	  resolution)
+
+2006-08-24 18:23:14 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/audiofxgood/audiopanorama.c: ChangeLog surgery to add cymax's real name
+	  Original commit message from CVS:
+	  * gst/audiofxgood/audiopanorama.c: (gst_audio_panorama_set_caps),
+	  (gst_audio_panorama_transform_m2s_float),
+	  (gst_audio_panorama_transform_s2s_float):
+	  ChangeLog surgery to add cymax's real name
+
+2006-08-24 18:17:20 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/audiofxgood/audiopanorama.*: Added float support (thanks cymax)
+	  Original commit message from CVS:
+	  * gst/audiofxgood/audiopanorama.c: (gst_audio_panorama_set_caps),
+	  (gst_audio_panorama_transform_m2s_int),
+	  (gst_audio_panorama_transform_s2s_int),
+	  (gst_audio_panorama_transform_m2s_float),
+	  (gst_audio_panorama_transform_s2s_float),
+	  (gst_audio_panorama_transform):
+	  * gst/audiofxgood/audiopanorama.h:
+	  Added float support (thanks cymax)
+
+2006-08-24 14:16:55 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/audiofxgood/audiopanorama.c: Fix docs & debug category. Add Fixme for volume pan levels.
+	  Original commit message from CVS:
+	  * gst/audiofxgood/audiopanorama.c:
+	  (gst_audio_panorama_transform_m2s):
+	  Fix docs & debug category. Add Fixme for volume pan levels.
+
+2006-08-24 13:51:15 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.c: unbreak AVI index handling, some more debug, remove an obsolete adapter_flush that caused stre...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_read_subindexes_pull),
+	  (gst_avi_demux_sync), (gst_avi_demux_stream_header_push),
+	  (gst_avi_demux_stream_header_pull),
+	  (gst_avi_demux_process_next_entry), (gst_avi_demux_stream_data),
+	  (gst_avi_demux_chain):
+	  unbreak AVI index handling, some more debug, remove an obsolete
+	  adapter_flush that caused streaming to wander off in the wild
+
+2006-08-24 11:21:06 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.*: Some more cleanups.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query),
+	  (gst_avi_demux_parse_superindex), (gst_avi_demux_parse_subindex),
+	  (gst_avi_demux_parse_stream), (gst_avi_demux_parse_odml),
+	  (gst_avi_demux_parse_index), (gst_avi_demux_stream_index),
+	  (gst_avi_demux_calculate_durations_from_index),
+	  (gst_avi_demux_stream_header_push),
+	  (gst_avi_demux_stream_header_pull):
+	  * gst/avi/gstavidemux.h:
+	  Some more cleanups.
+	  Fix totalFrames parsing in ODML.
+	  Disable use of index for length calculation in case of ODML as this is
+	  broken now.
+
+2006-08-24 10:03:03 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacdec.c: Use libgsttag helper function here too.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_update_metadata):
+	  Use libgsttag helper function here too.
+
+2006-08-24 09:24:11 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackdec.c: Post audio codec and average bitrate tags on bus (#344472).
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge <slomo at circular-chaos.org>
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_post_tags),
+	  (gst_wavpack_dec_chain):
+	  Post audio codec and average bitrate tags on bus (#344472).
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_base_init),
+	  (gst_wavpack_parse_src_query):
+	  Forward queries in other formats (BYTE format in particular)
+	  upstream; add Sebastian to authors.
+
+2006-08-24 00:40:07 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/v4l2/v4l2src_calls.h:
+	  Fix set_caps to set width and height to the values the driver is really working with.
+	  Original commit message from CVS:
+	  Fix set_caps to set width and height to the values the driver is really working with.
+
+2006-08-23 15:33:47 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.*: Initial streaming support for avidemux (fixes #336465)
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_class_init),
+	  (gst_avi_demux_init), (gst_avi_demux_dispose),
+	  (gst_avi_demux_reset), (gst_avi_demux_index_next),
+	  (gst_avi_demux_index_entry_for_time), (gst_avi_demux_src_convert),
+	  (gst_avi_demux_handle_src_query), (gst_avi_demux_handle_src_event),
+	  (gst_avi_demux_peek_chunk_info), (gst_avi_demux_peek_chunk),
+	  (gst_avi_demux_stream_init_push), (gst_avi_demux_stream_init_pull),
+	  (gst_avi_demux_parse_subindex),
+	  (gst_avi_demux_read_subindexes_push),
+	  (gst_avi_demux_read_subindexes_pull), (gst_avi_demux_parse_stream),
+	  (sort), (gst_avi_demux_parse_index), (gst_avi_demux_stream_index),
+	  (gst_avi_demux_sync), (gst_avi_demux_peek_tag),
+	  (gst_avi_demux_massage_index), (gst_avi_demux_stream_header_push),
+	  (gst_avi_demux_stream_header_pull),
+	  (gst_avi_demux_process_next_entry), (gst_avi_demux_stream_data),
+	  (push_tag_lists), (gst_avi_demux_loop), (gst_avi_demux_chain),
+	  (gst_avi_demux_sink_activate), (gst_avi_demux_activate_push),
+	  (gst_avi_demux_change_state):
+	  * gst/avi/gstavidemux.h:
+	  Initial streaming support for avidemux (fixes #336465)
+
+2006-08-23 10:30:31 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/wavpack/gstwavpackenc.c: Fix mem leak, send newsegment event on correction pad as well (#352476).
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_push_block):
+	  Fix mem leak, send newsegment event on correction pad
+	  as well (#352476).
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_base_init):
+	  Restore original author (on Sebastian's request).
+	  * tests/check/Makefile.am:
+	  * tests/check/gst-plugins-bad.supp:
+	  Add (so far empty) suppression file for -bad. Remove
+	  wavpackenc test from VALGRIND_TO_FIX now that the leak
+	  is fixed.
+
+2006-08-23 09:22:07 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  tests/check/: Add unit tests for wavpack elements (#352476).
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge <slomo at circular-chaos.org>
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/.cvsignore:
+	  * tests/check/elements/wavpackdec.c: (setup_wavpackdec),
+	  (cleanup_wavpackdec), (GST_START_TEST), (wavpackdec_suite), (main):
+	  * tests/check/elements/wavpackenc.c: (setup_wavpackenc),
+	  (cleanup_wavpackenc), (GST_START_TEST), (wavpackenc_suite), (main):
+	  * tests/check/elements/wavpackparse.c: (wavpackparse_found_pad),
+	  (setup_wavpackparse), (cleanup_wavpackparse), (GST_START_TEST),
+	  (wavpackparse_suite), (main):
+	  Add unit tests for wavpack elements (#352476).
+
+2006-08-23 08:52:50 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  Add docs for wavpack elements (#352476).
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge <slomo at circular-chaos.org>
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-bad-plugins.hierarchy:
+	  * docs/plugins/inspect/plugin-wavpack.xml:
+	  * ext/wavpack/gstwavpackdec.c:
+	  * ext/wavpack/gstwavpackdec.h:
+	  * ext/wavpack/gstwavpackenc.c:
+	  * ext/wavpack/gstwavpackenc.h:
+	  * ext/wavpack/gstwavpackparse.c:
+	  * ext/wavpack/gstwavpackparse.h:
+	  Add docs for wavpack elements (#352476).
+
+2006-08-22 20:39:26 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  Fixed query size to work with drivers that uses intermediate step like "width * height" to find closest size.
+	  Original commit message from CVS:
+	  Fixed query size to work with drivers that uses intermediate step like "width * height" to find closest size.
+
+2006-08-22 17:20:41 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  docs/plugins/gst-plugins-good-plugins-docs.sgml: There is no taglibmux element ...
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  There is no taglibmux element ...
+	  * gst/rtsp/gstrtspsrc.c:
+	  Use '%' rather than '&perc;' in gtk-doc blurb, docs build
+	  was complaining about unknown entity here.
+
+2006-08-22 17:02:39 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.*: Mark DISCONT.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_do_seek), (gst_avi_demux_handle_seek),
+	  (gst_avi_demux_process_next_entry):
+	  * gst/avi/gstavidemux.h:
+	  Mark DISCONT.
+	  Remove old unused fields and reorder the struct a bit.
+
+2006-08-22 16:45:37 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  Small documentation updates.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_media_to_caps),
+	  (gst_rtspsrc_send), (gst_rtspsrc_close), (gst_rtspsrc_play),
+	  (gst_rtspsrc_pause):
+	  * gst/rtsp/gstrtspsrc.h:
+	  * sys/oss/gstosssink.c: (gst_oss_sink_open),
+	  (gst_oss_sink_prepare), (gst_oss_sink_unprepare):
+	  Small documentation updates.
+
+2006-08-22 16:42:22 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.*: Precalc most of the duration query for each stream.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_reset),
+	  (gst_avi_demux_index_entry_for_time),
+	  (gst_avi_demux_handle_src_query), (gst_avi_demux_handle_src_event),
+	  (gst_avi_demux_stream_init), (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_stream_index), (gst_avi_demux_peek_tag),
+	  (gst_avi_demux_next_data_buffer),
+	  (gst_avi_demux_calculate_durations_from_index),
+	  (gst_avi_demux_stream_header), (gst_avi_demux_do_seek),
+	  (gst_avi_demux_handle_seek), (gst_avi_demux_aggregated_flow),
+	  (gst_avi_demux_process_next_entry), (gst_avi_demux_loop),
+	  (gst_avi_demux_sink_activate_pull), (gst_avi_demux_change_state):
+	  * gst/avi/gstavidemux.h:
+	  Precalc most of the duration query for each stream.
+	  Make seeking more correct.
+	  Use GstSegment to track position and duration.
+	  Code cleanups and leak fixes.
+	  Calculate correct total duration based on index length.
+
+2006-08-22 13:53:34 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/id3demux/id3v2frames.c: If strings in text fields are marked ISO8859-1, but contain valid UTF-8 already, then han...
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (parse_text_identification_frame),
+	  (parse_insert_string_field):
+	  If strings in text fields are marked ISO8859-1, but contain
+	  valid UTF-8 already, then handle them as UTF-8 and ignore
+	  the encoding. (#351794)
+
+2006-08-22 12:28:24 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacdec.*: Make flac-in-ogg work (#352100).
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_scan_got_frame),
+	  (gst_flac_dec_write), (gst_flac_dec_loop),
+	  (gst_flac_dec_sink_event), (gst_flac_dec_chain),
+	  (gst_flac_dec_src_query):
+	  * ext/flac/gstflacdec.h:
+	  Make flac-in-ogg work (#352100).
+
+2006-08-22 12:10:32 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/monoscope/gstmonoscope.c: Don't unref buffers of which we've already given away ownership to the adapter.
+	  Original commit message from CVS:
+	  * gst/monoscope/gstmonoscope.c: (gst_monoscope_chain):
+	  Don't unref buffers of which we've already given away
+	  ownership to the adapter.
+
+2006-08-22 10:32:34 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/speex/gstspeexdec.c: Make metadata extraction actually work.
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexdec.c: (speex_dec_chain_parse_comments):
+	  Make metadata extraction actually work.
+	  * ext/speex/gstspeexenc.c: (gst_speexenc_base_init),
+	  (gst_speexenc_init), (gst_speexenc_create_metadata_buffer),
+	  (gst_speexenc_chain):
+	  Fix metadata writing: replace old code which wrote completely
+	  broken tags with libgsttag-based code. Plus miscellaneous
+	  code cleanups (use static pad templates etc.) and a bunch
+	  of leak fixes.
+
+2006-08-21 19:34:03 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/audiopanorama/: die! die! die! you should never have been there
+	  Original commit message from CVS:
+	  * gst/audiopanorama/.cvsignore:
+	  * gst/audiopanorama/Makefile.am:
+	  * gst/audiopanorama/audiofx.c:
+	  * gst/audiopanorama/audiopanorama.c:
+	  * gst/audiopanorama/audiopanorama.h:
+	  die! die! die! you should never have been there
+
+2006-08-21 16:24:28 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Some more constification.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_add_stream), (qtdemux_parse),
+	  (qtdemux_node_dump_foreach), (qtdemux_parse_trak),
+	  (qtdemux_video_caps), (qtdemux_audio_caps):
+	  Some more constification.
+	  Fix some paletted data formats again.
+	  Fix ulaw/alaw in qt.
+	  Set correct caps for raw RGB.
+	  Add support for yuv2, which is like Yuv2.
+	  Add support for raw audio with the NONE fourcc, which is like raw.
+
+2006-08-21 13:59:52 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/wavpack/: More clean-ups: use shorter variable names to make code easier to read; prefix structures we define wit...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_init),
+	  (gst_wavpack_enc_finalize), (gst_wavpack_enc_sink_set_caps),
+	  (gst_wavpack_enc_set_wp_config), (gst_wavpack_enc_format_samples),
+	  (gst_wavpack_enc_push_block), (gst_wavpack_enc_chain),
+	  (gst_wavpack_enc_rewrite_first_block),
+	  (gst_wavpack_enc_sink_event), (gst_wavpack_enc_change_state),
+	  (gst_wavpack_enc_set_property), (gst_wavpack_enc_get_property):
+	  * ext/wavpack/gstwavpackenc.h:
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_reset),
+	  (gst_wavpack_parse_src_query), (gst_wavpack_parse_src_event),
+	  (gst_wavpack_parse_init), (gst_wavpack_parse_get_upstream_length),
+	  (gst_wavpack_parse_loop):
+	  More clean-ups: use shorter variable names to make code easier to
+	  read; prefix structures we define with 'Gst' to make it clearer
+	  where they come from.
+
+2006-08-21 13:26:37 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/wavpack/gstwavpackenc.c: Fix caps set on buffers and template caps (output is framed) and make them match (#35166...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_init),
+	  (gst_wavpack_enc_set_wp_config), (gst_wavpack_enc_push_block),
+	  (gst_wavpack_enc_chain), (gst_wavpack_enc_rewrite_first_block),
+	  (gst_wavpack_enc_sink_event):
+	  Fix caps set on buffers and template caps (output is framed)
+	  and make them match (#351663); use GST_WARNING_OBJECT instead of
+	  GST_ELEMENT_WARNING; simplify push_block(); do some small
+	  clean-ups here and there; fix memleak (#351663).
+
+2006-08-21 13:12:47 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  tests/check/elements/audiopanorama.c: Fix invalid memory access in audiopanorama test suite.
+	  Original commit message from CVS:
+	  * tests/check/elements/audiopanorama.c: (GST_START_TEST):
+	  Fix invalid memory access in audiopanorama test suite.
+
+2006-08-21 11:34:41 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  tests/check/elements/.cvsignore: ignore built file
+	  Original commit message from CVS:
+	  * tests/check/elements/.cvsignore:
+	  ignore built file
+
+2006-08-21 10:46:21 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/Makefile.am: Fix the build again.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  Fix the build again.
+
+2006-08-21 09:21:27 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/audiofxgood/: resubmit with the desired name *again*
+	  Original commit message from CVS:
+	  * gst/audiofxgood/.cvsignore:
+	  * gst/audiofxgood/Makefile.am:
+	  * gst/audiofxgood/audiofx.c: (plugin_init):
+	  * gst/audiofxgood/audiopanorama.c: (gst_audio_panorama_base_init),
+	  (gst_audio_panorama_class_init), (gst_audio_panorama_init),
+	  (gst_audio_panorama_set_property),
+	  (gst_audio_panorama_get_property),
+	  (gst_audio_panorama_get_unit_size),
+	  (gst_audio_panorama_transform_caps), (gst_audio_panorama_set_caps),
+	  (gst_audio_panorama_transform_m2s),
+	  (gst_audio_panorama_transform_s2s), (gst_audio_panorama_transform):
+	  * gst/audiofxgood/audiopanorama.h:
+	  resubmit with the desired name *again*
+
+2006-08-20 13:09:51 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  use g_assert in _get_unit_size
+	  Original commit message from CVS:
+	  * ext/gdk_pixbuf/pixbufscale.c: (gst_pixbufscale_get_unit_size):
+	  * gst/videobox/gstvideobox.c: (gst_video_box_get_unit_size):
+	  use g_assert in _get_unit_size
+
+2006-08-20 13:06:44 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/: cleanup -unused.txt to make it useful, add previously missing docs
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/inspect/plugin-audiofxgood.xml:
+	  cleanup -unused.txt to make it useful, add previously missing docs
+	  * ext/Makefile.am:
+	  * ext/esd/esdmon.c:
+	  * ext/esd/esdsink.c:
+	  * ext/esd/gstesd.c: (plugin_init):
+	  reflow to get rid of two external symbols
+	  * gst/audiofxgood/audiofx.c: (plugin_init):
+	  re-add
+
+2006-08-20 12:09:16 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/audiofxgood/audiofx.c
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/audiofxgood/.cvsignore:
+	  * gst/audiofxgood/Makefile.am:
+	  * gst/audiofxgood/audiofx.c
+	  * gst/audiofxgood/audiopanorama.c: (gst_audio_panorama_base_init),
+	  (gst_audio_panorama_class_init), (gst_audio_panorama_init),
+	  (gst_audio_panorama_set_property),
+	  (gst_audio_panorama_get_property),
+	  (gst_audio_panorama_get_unit_size),
+	  (gst_audio_panorama_transform_caps), (gst_audio_panorama_set_caps),
+	  (gst_audio_panorama_transform_m2s),
+	  (gst_audio_panorama_transform_s2s), (gst_audio_panorama_transform):
+	  * gst/audiofxgood/audiopanorama.h:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/audiopanorama.c: (setup_panorama_m),
+	  (setup_panorama_s), (cleanup_panorama), (GST_START_TEST),
+	  (panorama_suite), (main):
+	  Add audiofxgood plugin with audiopanorama element
+
+2006-08-18 21:39:00 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackparse.c: Fix resyncing in push mode not stopping re-syncing at embedded zeroes; skip garbage be...
+	  Original commit message from CVS:
+	  Based on patch by: Sebastian Dröge <slomo at circular-chaos.org>
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_sink_event),
+	  (gst_wavpack_parse_get_upstream_length),
+	  (gst_wavpack_parse_find_marker), (gst_wavpack_parse_resync_loop),
+	  (gst_wavpack_parse_loop), (gst_wavpack_parse_resync_adapter):
+	  Fix resyncing in push mode not stopping re-syncing at embedded
+	  zeroes; skip garbage between frames in pull mode as well if
+	  necessary; use gst_pad_query_peer_duration(); push EOS and
+	  NEWSEGMENT event in right direction (#351659).
+
+2006-08-18 17:00:53 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  docs/plugins/Makefile.am: More Oss docs fixage.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  More Oss docs fixage.
+
+2006-08-18 16:52:21 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Added experimental SVQ3 depayloader.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpsv3vdepay.c: (gst_rtp_sv3v_depay_base_init),
+	  (gst_rtp_sv3v_depay_class_init), (gst_rtp_sv3v_depay_init),
+	  (gst_rtp_sv3v_depay_finalize), (gst_rtp_sv3v_depay_setcaps),
+	  (gst_rtp_sv3v_depay_process), (gst_rtp_sv3v_depay_set_property),
+	  (gst_rtp_sv3v_depay_get_property),
+	  (gst_rtp_sv3v_depay_change_state),
+	  (gst_rtp_sv3v_depay_plugin_init):
+	  * gst/rtp/gstrtpsv3vdepay.h:
+	  Added experimental SVQ3 depayloader.
+
+2006-08-18 13:25:06 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/dv/gstdvdemux.*: When handling seek requests, don't send the newsegment event from the calling thread. Instead sa...
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_handle_pull_seek),
+	  (gst_dvdemux_loop), (gst_dvdemux_change_state):
+	  * ext/dv/gstdvdemux.h:
+	  When handling seek requests, don't send the newsegment event from the
+	  calling thread. Instead save it so it can be sent from the streaming
+	  thread.
+
+2006-08-17 15:51:50 +0000  Sjoerd Simons <sjoerd@luon.net>
+
+	  gst/multipart/multipartdemux.c: Accept leading whitespace before the boundary
+	  Original commit message from CVS:
+	  Patch by: Sjoerd Simons <sjoerd at luon dot net>
+	  * gst/multipart/multipartdemux.c: (multipart_parse_header):
+	  Accept leading whitespace before the boundary
+	  This patch makes the demuxer allow some whitespace before the actual
+	  boundary. This makes the demuxer work with the ``old'' gstreamer
+	  multipartmuxer again (which placed an extra \n before the start
+	  of the stream) Fixes #349068.
+
+2006-08-17 15:47:28 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtph264depay.c: Error out on non-implemented stuff.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_process):
+	  Error out on non-implemented stuff.
+
+2006-08-16 16:50:00 +0000  Andy Wingo <wingo@pobox.com>
+
+	  ext/ladspa/gstsignalprocessor.c: Make ladspa elements reusable. Fixes #350006.
+	  Original commit message from CVS:
+	  Patch by: Andy Wingo <wingo at pobox dot com>
+	  * ext/ladspa/gstsignalprocessor.c: (gst_signal_processor_setup),
+	  (gst_signal_processor_start), (gst_signal_processor_stop),
+	  (gst_signal_processor_cleanup), (gst_signal_processor_setcaps),
+	  (gst_signal_processor_pen_buffer), (gst_signal_processor_flush),
+	  (gst_signal_processor_do_pulls), (gst_signal_processor_do_pushes),
+	  (gst_signal_processor_change_state):
+	  Make ladspa elements reusable. Fixes #350006.
+
+2006-08-16 15:33:12 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/ladspa/gstladspa.c: Convert ' ' into '_'. Try to keep as many characters in the padtemplate names as possible.
+	  Original commit message from CVS:
+	  * ext/ladspa/gstladspa.c: (gst_ladspa_base_init):
+	  Convert ' ' into '_'. Try to keep as many characters in the padtemplate
+	  names as possible.
+
+2006-08-16 14:47:50 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/ladspa/gstsignalprocessor.c: A push() gives away our refcount so we should not use the buffer on the pen anymore.
+	  Original commit message from CVS:
+	  * ext/ladspa/gstsignalprocessor.c: (gst_signal_processor_flush),
+	  (gst_signal_processor_do_pushes):
+	  A push() gives away our refcount so we should not use the buffer on the
+	  pen anymore.
+
+2006-08-16 13:48:00 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/oss/gstossmixerelement.c: Don't leak device string.
+	  Original commit message from CVS:
+	  * sys/oss/gstossmixerelement.c: (gst_oss_mixer_element_class_init),
+	  (gst_oss_mixer_element_finalize):
+	  Don't leak device string.
+
+2006-08-16 13:01:32 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Require CVS of GStreamer core and -base (for
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Require CVS of GStreamer core and -base (for
+	  GST_TAG_EXTENDED_COMMENT and gst_tag_parse_extended_comment()).
+	  * ext/taglib/gstid3v2mux.cc:
+	  Write extended comment tags properly (#348762).
+	  * gst/id3demux/id3v2frames.c: (id3demux_id3v2_parse_frame),
+	  (parse_comment_frame):
+	  Extract COMM frames into extended comments, which makes it
+	  easier to properly retain the description bit of the tag
+	  and maintain this information when re-tagging (#348762).
+
+2006-08-16 12:02:48 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/check/Makefile.am: Don't try to run annodex unit tests if the annodex plugin has not been built (Fixes #351116).
+	  Original commit message from CVS:
+	  * tests/check/Makefile.am:
+	  Don't try to run annodex unit tests if the annodex
+	  plugin has not been built (Fixes #351116).
+
+2006-08-16 10:53:32 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/autodetect/gstautoaudiosink.c: When we can't find a usable audiosink, don't error out, but use a fake sink instea...
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautoaudiosink.c:
+	  (gst_auto_audio_sink_find_best):
+	  When we can't find a usable audiosink, don't error out,
+	  but use a fake sink instead and post a warning message
+	  on the bus (#341278).
+
+2006-08-16 10:40:04 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/: In push mode, re-sync to next wavpack header if sync is lost (#351557). Also use hyphens instead of und...
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge <slomo at circular-chaos.org>
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_class_init):
+	  * ext/wavpack/gstwavpackparse.c:
+	  (gst_wavpack_parse_resync_adapter), (gst_wavpack_parse_chain):
+	  In push mode, re-sync to next wavpack header if sync is lost
+	  (#351557). Also use hyphens instead of underscores in
+	  GObject property names.
+
+2006-08-16 10:22:32 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/oss/: Document OSS elements; add gtk-doc blurb with 'Since 0.10.5' for ossmixer's new device property.
+	  Original commit message from CVS:
+	  * sys/oss/gstossmixerelement.c: (gst_oss_mixer_element_class_init):
+	  * sys/oss/gstosssink.c:
+	  * sys/oss/gstosssrc.c:
+	  Document OSS elements; add gtk-doc blurb with 'Since 0.10.5' for
+	  ossmixer's new device property.
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  Add docs for OSS elements.
+	  * docs/plugins/inspect/plugin-aasink.xml:
+	  * docs/plugins/inspect/plugin-alaw.xml:
+	  * docs/plugins/inspect/plugin-alpha.xml:
+	  * docs/plugins/inspect/plugin-alphacolor.xml:
+	  * docs/plugins/inspect/plugin-annodex.xml:
+	  * docs/plugins/inspect/plugin-apetag.xml:
+	  * docs/plugins/inspect/plugin-auparse.xml:
+	  * docs/plugins/inspect/plugin-autodetect.xml:
+	  * docs/plugins/inspect/plugin-avi.xml:
+	  * docs/plugins/inspect/plugin-cacasink.xml:
+	  * docs/plugins/inspect/plugin-cairo.xml:
+	  * docs/plugins/inspect/plugin-cdio.xml:
+	  * docs/plugins/inspect/plugin-cutter.xml:
+	  * docs/plugins/inspect/plugin-debug.xml:
+	  * docs/plugins/inspect/plugin-dv.xml:
+	  * docs/plugins/inspect/plugin-efence.xml:
+	  * docs/plugins/inspect/plugin-effectv.xml:
+	  * docs/plugins/inspect/plugin-esdsink.xml:
+	  * docs/plugins/inspect/plugin-flac.xml:
+	  * docs/plugins/inspect/plugin-flxdec.xml:
+	  * docs/plugins/inspect/plugin-gconfelements.xml:
+	  * docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	  * docs/plugins/inspect/plugin-goom.xml:
+	  * docs/plugins/inspect/plugin-halelements.xml:
+	  * docs/plugins/inspect/plugin-icydemux.xml:
+	  * docs/plugins/inspect/plugin-id3demux.xml:
+	  * docs/plugins/inspect/plugin-jpeg.xml:
+	  * docs/plugins/inspect/plugin-level.xml:
+	  * docs/plugins/inspect/plugin-matroska.xml:
+	  * docs/plugins/inspect/plugin-mulaw.xml:
+	  * docs/plugins/inspect/plugin-multipart.xml:
+	  * docs/plugins/inspect/plugin-navigationtest.xml:
+	  * docs/plugins/inspect/plugin-ossaudio.xml:
+	  * docs/plugins/inspect/plugin-png.xml:
+	  * docs/plugins/inspect/plugin-rtp.xml:
+	  * docs/plugins/inspect/plugin-rtsp.xml:
+	  * docs/plugins/inspect/plugin-shout2send.xml:
+	  * docs/plugins/inspect/plugin-smpte.xml:
+	  * docs/plugins/inspect/plugin-speex.xml:
+	  * docs/plugins/inspect/plugin-taglib.xml:
+	  * docs/plugins/inspect/plugin-udp.xml:
+	  * docs/plugins/inspect/plugin-videobalance.xml:
+	  * docs/plugins/inspect/plugin-videobox.xml:
+	  * docs/plugins/inspect/plugin-videoflip.xml:
+	  * docs/plugins/inspect/plugin-videomixer.xml:
+	  * docs/plugins/inspect/plugin-wavenc.xml:
+	  * docs/plugins/inspect/plugin-wavparse.xml:
+	  * docs/plugins/inspect/plugin-ximagesrc.xml:
+	  Update to CVS version.
+
+2006-08-16 10:05:00 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Caps extra properties must be defined as strings for depayloaders because they are generated from an SDP.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpamrdepay.c:
+	  * gst/rtp/gstrtpmp4gdepay.c:
+	  Caps extra properties must be defined as strings for
+	  depayloaders because they are generated from an SDP.
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_base_init),
+	  (gst_rtp_h264_depay_class_init), (gst_rtp_h264_depay_init),
+	  (gst_rtp_h264_depay_finalize), (decode_base64),
+	  (gst_rtp_h264_depay_setcaps), (gst_rtp_h264_depay_process),
+	  (gst_rtp_h264_depay_set_property),
+	  (gst_rtp_h264_depay_get_property),
+	  (gst_rtp_h264_depay_change_state),
+	  (gst_rtp_h264_depay_plugin_init):
+	  * gst/rtp/gstrtph264depay.h:
+	  Added basic, not completely functional RFC 3984 H264 depayloader.
+
+2006-08-16 09:48:26 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtpdec.c: Add pads after setting them up.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtpdec.c: (gst_rtpdec_init), (gst_rtpdec_getcaps):
+	  Add pads after setting them up.
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_class_init),
+	  (gst_rtspsrc_init), (gst_rtspsrc_finalize),
+	  (gst_rtspsrc_free_stream), (gst_rtspsrc_media_to_caps),
+	  (gst_rtspsrc_stream_setup_rtp),
+	  (gst_rtspsrc_stream_configure_transport),
+	  (gst_rtspsrc_combine_flows), (gst_rtspsrc_loop),
+	  (gst_rtspsrc_open), (gst_rtspsrc_close), (gst_rtspsrc_play),
+	  (gst_rtspsrc_pause):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Fix interleaved mode.
+	  - Protect streaming with lock.
+	  - Combine flows
+	  - set caps on outgoing buffers.
+	  - strip trailing \0 from data packets.
+	  - Configure RTP/RTCP in stream.
+	  Use DEBUG_OBJECT more.
+
+2006-08-16 09:29:20 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstmultiudpsink.c: Turn a g_print into a DEBUG line.
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_add):
+	  Turn a g_print into a DEBUG line.
+
+2006-08-16 09:25:17 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/oss/: Small cleanups. Better error reporting.
+	  Original commit message from CVS:
+	  * sys/oss/gstossmixer.c: (gst_ossmixer_open), (gst_ossmixer_new):
+	  * sys/oss/gstossmixerelement.c: (gst_oss_mixer_element_class_init),
+	  (gst_oss_mixer_element_init), (gst_oss_mixer_element_set_property),
+	  (gst_oss_mixer_element_get_property),
+	  (gst_oss_mixer_element_change_state):
+	  * sys/oss/gstossmixerelement.h:
+	  Small cleanups. Better error reporting.
+	  Add device property for the mixer instead of the hardcoded
+	  /dev/mixer. Fixes #350785.
+	  API: GstOssMixerElement::device property
+
+2006-08-15 22:44:27 +0000  Jens Granseuer <jensgr@gmx.net>
+
+	  gconf/Makefile.am: Make --disable-schemas work right (they still need to be copied to the installation directory, jus...
+	  Original commit message from CVS:
+	  Patch by: Jens Granseuer <jensgr at gmx net>
+	  * gconf/Makefile.am:
+	  Make --disable-schemas work right (they still need
+	  to be copied to the installation directory, just not
+	  applied). Fixes #351347 (also #344100).
+
+2006-08-15 20:29:45 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackparse.*: Make wavpackparse also work in push-mode (not seekable yet though); some small clean-u...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_class_init),
+	  (gst_wavpack_parse_reset), (gst_wavpack_parse_get_src_query_types),
+	  (gst_wavpack_parse_src_query),
+	  (gst_wavpack_parse_handle_seek_event),
+	  (gst_wavpack_parse_sink_event), (gst_wavpack_parse_init),
+	  (gst_wavpack_parse_create_src_pad),
+	  (gst_wavpack_parse_push_buffer), (gst_wavpack_parse_loop),
+	  (gst_wavpack_parse_chain), (gst_wavpack_parse_sink_activate),
+	  (gst_wavpack_parse_sink_activate_pull):
+	  * ext/wavpack/gstwavpackparse.h:
+	  Patch by: Sebastian Dröge <slomo at circular-chaos.org>
+	  Make wavpackparse also work in push-mode (not seekable yet though);
+	  some small clean-ups along the way; add support for SEEKING query
+	  and query types function. (#351495).
+
+2006-08-14 11:37:10 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* configure.ac:
+	* win32/common/config.h:
+	  back to HEAD
+	  Original commit message from CVS:
+	  back to HEAD
+
+2006-08-14 11:14:43 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cdio.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* win32/common/config.h:
+	  releasing 0.10.4
+	  Original commit message from CVS:
+	  releasing 0.10.4
+
+2006-08-14 10:06:55 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Extract all references/redirections if there is more than one and sort them; also extract mini...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_redirects_sort_func),
+	  (qtdemux_process_redirects), (qtdemux_parse_tree):
+	  Extract all references/redirections if there is more
+	  than one and sort them; also extract minimum required
+	  bitrate information if available. (#350399)
+
+2006-08-10 14:10:28 +0000  Edward Hervey <edward@fluendo.com>
+
+	  Send the newsegment event in the streaming thread.
+	  Original commit message from CVS:
+	  Patch by: Edward Hervey <edward@fluendo.com>
+	  * configure.ac:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_perform_seek),
+	  (gst_wavparse_stream_data):
+	  Send the newsegment event in the streaming thread.
+	  Fixes #347529
+
+2006-08-10 14:02:45 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* win32/common/config.h:
+	  bumped for prerel
+	  Original commit message from CVS:
+	  bumped for prerel
+
+2006-08-10 13:10:38 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	  update translations
+	  Original commit message from CVS:
+	  update translations
+
+2006-08-08 14:55:53 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Fix silly typo.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_tree):
+	  Fix silly typo.
+
+2006-08-08 14:46:00 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* ChangeLog:
+	  ChangeLog surgery: mention bug number
+	  Original commit message from CVS:
+	  ChangeLog surgery: mention bug number
+
+2006-08-08 14:40:47 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/jpeg/: Refuse sink caps in the encoder if width or height is not a multiple of 16, the encoder does not support t...
+	  Original commit message from CVS:
+	  * ext/jpeg/gstsmokedec.c: (gst_smokedec_chain):
+	  * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_setcaps),
+	  (gst_smokeenc_resync), (gst_smokeenc_chain):
+	  Refuse sink caps in the encoder if width or height is not a
+	  multiple of 16, the encoder does not support that yet; along the
+	  same lines, check the return value of the encoder setup function;
+	  also remove some debug log clutter.
+
+2006-08-04 11:38:54 +0000  Andy Wingo <wingo@pobox.com>
+
+	  ext/ladspa/gstsignalprocessor.h: Add infrastructure for storing whether a processor can work in place or not, and for...
+	  Original commit message from CVS:
+	  2006-08-04  Andy Wingo  <wingo@pobox.com>
+	  * ext/ladspa/gstsignalprocessor.h: Add infrastructure for storing
+	  whether a processor can work in place or not, and for keeping
+	  track of its state. Change the FlowReturn instance variable from
+	  "state" to "flow_state", all callers changed.
+	  * ext/ladspa/gstsignalprocessor.c (gst_signal_processor_setup)
+	  (gst_signal_processor_start, gst_signal_processor_stop)
+	  (gst_signal_processor_cleanup): New functions to manage the
+	  processor's state.
+	  (gst_signal_processor_setcaps): start() as well as setup() here.
+	  (gst_signal_processor_prepare): Respect CAN_PROCESS_IN_PLACE.
+	  (gst_signal_processor_change_state): Stop and cleanup the
+	  processor as we go to NULL.
+	  * ext/ladspa/gstladspa.c (gst_ladspa_base_init): Reuse buffers if
+	  INPLACE_BROKEN is not set.
+	  * ext/ladspa/gstsignalprocessor.c (gst_signal_processor_prepare):
+	  Do the alloc_buffer in bytes, not frames.
+
+2006-08-04 10:21:26 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  sys/ximage/ximageutil.c: Fix rgb masks when recording in < 24bpp.
+	  Original commit message from CVS:
+	  2006-08-04  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * sys/ximage/ximageutil.c: (ximageutil_xcontext_get):
+	  Fix rgb masks when recording in < 24bpp.
+
+2006-08-04 09:20:26 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ChangeLog:
+	* ext/ladspa/gstsignalprocessor.c:
+	  BPB
+	  Original commit message from CVS:
+	  (gst_signal_processor_src_activate_pull): BPB
+
+2006-08-04 09:05:53 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ChangeLog:
+	* ext/ladspa/gstsignalprocessor.c:
+	  ext/ladspa/gstsignalprocessor.c (gst_signal_processor_setcaps) (gst_signal_processor_prepare) (gst_signal_processor_u...
+	  Original commit message from CVS:
+	  2006-08-04  Andy Wingo  <wingo@pobox.com>
+	  * ext/ladspa/gstsignalprocessor.c (gst_signal_processor_setcaps)
+	  (gst_signal_processor_prepare)
+	  (gst_signal_processor_update_inputs)
+	  (gst_signal_processor_process, gst_signal_processor_pen_buffer)
+	  (gst_signal_processor_flush)
+	  (gst_signal_processor_sink_activate_push)
+	  (gst_signal_processor_src_activate_pull)
+	  (gst_signal_processor_change_state): Remove the last of the code
+	  that assumes that we process whole buffers at a time. Fix some
+	  debugging. Seems to work now in some cases.
+
+2006-07-31 22:27:22 +0000  Andy Wingo <wingo@pobox.com>
+
+	  ext/ladspa/gstsignalprocessor.c (gst_signal_processor_process): Fix nframes-choosing.
+	  Original commit message from CVS:
+	  2006-08-01  Andy Wingo  <wingo@pobox.com>
+	  * ext/ladspa/gstsignalprocessor.c (gst_signal_processor_process):
+	  Fix nframes-choosing.
+	  (gst_signal_processor_init): Init pending_in and pending_out.
+
+2006-07-31 22:03:09 +0000  Andy Wingo <wingo@pobox.com>
+
+	  ext/ladspa/gstsignalprocessor.c (gst_signal_processor_init): No more default sample rate, although we never check tha...
+	  Original commit message from CVS:
+	  2006-08-01  Andy Wingo  <wingo@pobox.com>
+	  * ext/ladspa/gstsignalprocessor.c (gst_signal_processor_init): No
+	  more default sample rate, although we never check that the sample
+	  rate actually gets set. Something for the future.
+	  (gst_signal_processor_setcaps): Some refcount fixes, flow fixes.
+	  (gst_signal_processor_event): Refcount fixen.
+	  (gst_signal_processor_process): Pull the number of frames to
+	  process from the sizes of the buffers in the input pens.
+	  (gst_signal_processor_pen_buffer): Remove an incorrect FIXME :)
+	  (gst_signal_processor_do_pulls): Add an nframes argument, and use
+	  it instead of buffer_frames.
+	  (gst_signal_processor_getrange): Refcount fixen, pass nframes on
+	  to do_pulls.
+	  (gst_signal_processor_chain)
+	  (gst_signal_processor_sink_activate_push)
+	  (gst_signal_processor_src_activate_pull):  Refcount fixen.
+	  * ext/ladspa/gstsignalprocessor.h: No more buffer_frames, yay.
+
+2006-07-31 19:44:18 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/ladspa/gstsignalprocessor.c: don't query buffer-frames from caps, add lots of debug-log, try fix for assert (#349...
+	  Original commit message from CVS:
+	  * ext/ladspa/gstsignalprocessor.c: (gst_signal_processor_setcaps),
+	  (gst_signal_processor_process):
+	  don't query buffer-frames from caps, add lots of debug-log,
+	  try fix for assert (#349189)
+
+2006-07-31 15:58:43 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstudpsrc.c: Fix docs.
+	  Original commit message from CVS:
+	  * gst/udp/gstudpsrc.c:
+	  Fix docs.
+
+2006-07-29 16:32:26 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/ladspa/gstsignalprocessor.c: Add debugs logs here and there, add more error handling, add some
+	  Original commit message from CVS:
+	  * ext/ladspa/gstsignalprocessor.c:
+	  (gst_signal_processor_add_pad_from_template),
+	  (gst_signal_processor_init), (gst_signal_processor_setcaps),
+	  (gst_signal_processor_process), (gst_signal_processor_pen_buffer),
+	  (gst_signal_processor_do_pulls), (gst_signal_processor_getrange),
+	  (gst_signal_processor_sink_activate_push),
+	  (gst_signal_processor_src_activate_pull),
+	  (gst_signal_processor_change_state):
+	  Add debugs logs here and there, add more error handling, add some
+	  FIXME comments, filed #349189
+
+2006-07-29 11:22:47 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  ext/jpeg/gstsmokeenc.c: Set caps on buffer correctly.  Fixes bug #349155.
+	  Original commit message from CVS:
+	  2006-07-29  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_getcaps),
+	  (gst_smokeenc_setcaps), (gst_smokeenc_chain):
+	  Set caps on buffer correctly.  Fixes bug #349155.
+
+2006-07-28 16:17:17 +0000  Sjoerd Simons <sjoerd@luon.net>
+
+	  gst/multipart/multipartdemux.c: Uses GstAdapter instead of own buffering.
+	  Original commit message from CVS:
+	  Patch by: Sjoerd Simons <sjoerd at luon dot net>
+	  * gst/multipart/multipartdemux.c: (gst_multipart_demux_base_init),
+	  (gst_multipart_demux_class_init), (gst_multipart_demux_init),
+	  (gst_multipart_demux_finalize), (get_line_end),
+	  (multipart_parse_header), (multipart_find_boundary),
+	  (gst_multipart_demux_chain), (gst_multipart_demux_change_state),
+	  (gst_multipart_set_property), (gst_multipart_get_property):
+	  Uses GstAdapter instead of own buffering.
+	  Actually parses the mime-type correctly (In tests the mime-type was
+	  always "" with the old version).
+	  Uses the Content-length header if available to speed up things.
+	  Reliably autoscans the boundary name by default.
+	  Fixes #349068.
+	  * gst/multipart/multipartmux.c: (gst_multipart_mux_collected):
+	  Don't start the stream with a \n.
+
+2006-07-28 08:32:47 +0000  Brian Cameron <brian.cameron@sun.com>
+
+	  sys/sunaudio/gstsunaudiosrc.c: Open source with O_NONBLOCK (#349015).
+	  Original commit message from CVS:
+	  Patch by: Brian Cameron <brian dot cameron at sun com>
+	  * sys/sunaudio/gstsunaudiosrc.c: (gst_sunaudiosrc_open):
+	  Open source with O_NONBLOCK (#349015).
+
+2006-07-28 08:21:27 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.*: Whitespace fixes and more debug
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_stream_index),
+	  (gst_avi_demux_massage_index):
+	  * gst/avi/gstavidemux.h:
+	  Whitespace fixes and more debug
+
+2006-07-27 11:21:53 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/autodetect/gstautoaudiosink.c: Get rid of old and unused magic sound-server properties stuff.
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautoaudiosink.c:
+	  (gst_auto_audio_sink_create_element_with_pretty_name),
+	  (gst_auto_audio_sink_find_best),
+	  (gst_auto_audio_sink_change_state):
+	  Get rid of old and unused magic sound-server properties stuff.
+	  Add suffix to child sink's name that makes it easy to see from
+	  the name alone which type it actually is (alsa, oss, esd, etc.).
+
+2006-07-27 10:05:27 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstudpsrc.*: Rename "buffer" to "buffer-size" to make clear it is a size we set and not some sort of feature ...
+	  Original commit message from CVS:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init), (gst_udpsrc_init),
+	  (gst_udpsrc_set_property), (gst_udpsrc_get_property),
+	  (gst_udpsrc_start):
+	  * gst/udp/gstudpsrc.h:
+	  Rename "buffer" to "buffer-size" to make clear it is a size we set and
+	  not some sort of feature we enable.
+
+2006-07-27 10:01:49 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/udp/gstudpsrc.c: Use CLOSE_SOCKET() here instead of close() to maintain win32 workiness.
+	  Original commit message from CVS:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_start):
+	  Use CLOSE_SOCKET() here instead of close() to maintain
+	  win32 workiness.
+
+2006-07-27 09:04:51 +0000  Thijs Vermeir <thijs.vermeir@barco.com>
+
+	  gst/udp/gstudpsrc.*: Added "buffer" property to control the kernel receive buffer size.
+	  Original commit message from CVS:
+	  Patch by: Thijs Vermeir <thijs dot vermeir at barco dot com>
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init), (gst_udpsrc_init),
+	  (gst_udpsrc_create), (gst_udpsrc_set_property),
+	  (gst_udpsrc_get_property), (gst_udpsrc_start):
+	  * gst/udp/gstudpsrc.h:
+	  Added "buffer" property to control the kernel receive buffer size.
+	  Update documentation.
+	  Small cleanups. Fixes #348752.
+	  API: buffer property
+
+2006-07-26 16:36:59 +0000  Kai Vehmanen <kv2004@eca.cx>
+
+	  gst/rtp/: Fix timestamp calculation on outgoing RTP packets.
+	  Original commit message from CVS:
+	  Patch by: Kai Vehmanen <kv2004 at eca dot cx>
+	  * gst/rtp/gstrtppcmapay.c: (gst_rtp_pcma_pay_flush),
+	  (gst_rtp_pcma_pay_handle_buffer):
+	  * gst/rtp/gstrtppcmupay.c: (gst_rtp_pcmu_pay_flush),
+	  (gst_rtp_pcmu_pay_handle_buffer):
+	  Fix timestamp calculation on outgoing RTP packets.
+	  Fixes #348675.
+
+2006-07-26 10:07:29 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/gstid3v2mux.cc: is still sub-optimal though, since we don't retain or extract the comment descriptions pro...
+	  Original commit message from CVS:
+	  * ext/taglib/gstid3v2mux.cc:
+	  Fix writing of comment frames (should be COMM not TCOM),
+	  is still sub-optimal though, since we don't retain or
+	  extract the comment descriptions properly (#334375,
+	  also see #334375).
+
+2006-07-26 09:02:56 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/wavparse/gstwavparse.c: #define 'fact' RIFF chunk if we are not compiling against
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c:
+	  #define 'fact' RIFF chunk if we are not compiling against
+	  -base CVS (we don't want to depend on -base CVS for this
+	  one define only, and also not for release order reasons).
+
+2006-07-26 08:17:45 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/gstid3v2mux.cc: Handle multiple tags of the same type properly. Re-inject unparsed ID3v2 frames that we ge...
+	  Original commit message from CVS:
+	  * ext/taglib/gstid3v2mux.cc:
+	  Handle multiple tags of the same type properly. Re-inject
+	  unparsed ID3v2 frames that we get as binary blobs from
+	  id3demux into the tag again so we don't lose information
+	  when retagging (#334375).
+
+2006-07-25 17:54:25 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/ximage/gstximagesrc.c: Document newly-added properties properly, so that there is a 'Since: 0.10.4' in the plugin...
+	  Original commit message from CVS:
+	  * sys/ximage/gstximagesrc.c: (gst_ximage_src_class_init):
+	  Document newly-added properties properly, so that there is a
+	  'Since: 0.10.4' in the plugin docs. Convert some property
+	  names into canonical GObject style (GObject will do that
+	  internally anyway).
+
+2006-07-25 16:47:04 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/id3tags.c: Extract frames for ID3v2 versions prior to ID3v2.3.0 properly as well, and add the version to...
+	  Original commit message from CVS:
+	  * gst/id3demux/id3tags.c:
+	  (id3demux_add_id3v2_frame_blob_to_taglist):
+	  Extract frames for ID3v2 versions prior to ID3v2.3.0 properly as
+	  well, and add the version to the blob's buffer caps, since that
+	  information will be needed for deserialisation later on (#348644).
+
+2006-07-25 13:14:05 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavidemux.c: Moved win32 variant of GST_DEBUG_CATEGORY_EXTERN to gstinfo.h. Fixed indentation and spacing.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_read_subindexes),
+	  (gst_avi_demux_parse_stream):
+	  Moved win32 variant of GST_DEBUG_CATEGORY_EXTERN to gstinfo.h. Fixed
+	  indentation and spacing.
+
+2006-07-24 21:43:06 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  sys/directsound/gstdirectsoundsink.*: Add an attenuation property that will directly attenuate the directsound buffer.
+	  Original commit message from CVS:
+	  * sys/directsound/gstdirectsoundsink.h:
+	  * sys/directsound/gstdirectsoundsink.c:
+	  Add an attenuation property that will directly attenuate the
+	  directsound buffer.
+	  Change the size of the directsound secondary buffer to a half second.
+	  Add more debug logs.
+	  Add a lock to protect dsound buffer write access.
+	  Fix a bad implementation of reset.
+	  * sys/directsound/gstdirectdrawsink.c:
+	  * sys/directsound/gstdirectdrawsink.h:
+	  Add a keep_aspect_ratio property.
+	  Do not use overlay if not supported.
+	  Add more debug logs.
+	  Remove overwrite of WM_ERASEBKGND message handling. It was not
+	  redrawing border when keep_aspect_ratio was enabled.
+	  * win32/common/config.h:
+	  update version waiting an auto-generated config.h
+
+2006-07-24 15:25:49 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  docs/plugins/: Update files to CVS/Prerelease version, add esdsink docs.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/inspect/plugin-1394.xml:
+	  * docs/plugins/inspect/plugin-aasink.xml:
+	  * docs/plugins/inspect/plugin-alaw.xml:
+	  * docs/plugins/inspect/plugin-alpha.xml:
+	  * docs/plugins/inspect/plugin-alphacolor.xml:
+	  * docs/plugins/inspect/plugin-annodex.xml:
+	  * docs/plugins/inspect/plugin-apetag.xml:
+	  * docs/plugins/inspect/plugin-auparse.xml:
+	  * docs/plugins/inspect/plugin-autodetect.xml:
+	  * docs/plugins/inspect/plugin-avi.xml:
+	  * docs/plugins/inspect/plugin-cacasink.xml:
+	  * docs/plugins/inspect/plugin-cairo.xml:
+	  * docs/plugins/inspect/plugin-cdio.xml:
+	  * docs/plugins/inspect/plugin-cutter.xml:
+	  * docs/plugins/inspect/plugin-debug.xml:
+	  * docs/plugins/inspect/plugin-dv.xml:
+	  * docs/plugins/inspect/plugin-efence.xml:
+	  * docs/plugins/inspect/plugin-effectv.xml:
+	  * docs/plugins/inspect/plugin-esdsink.xml:
+	  * docs/plugins/inspect/plugin-flac.xml:
+	  * docs/plugins/inspect/plugin-flxdec.xml:
+	  * docs/plugins/inspect/plugin-gconfelements.xml:
+	  * docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	  * docs/plugins/inspect/plugin-goom.xml:
+	  * docs/plugins/inspect/plugin-halelements.xml:
+	  * docs/plugins/inspect/plugin-icydemux.xml:
+	  * docs/plugins/inspect/plugin-id3demux.xml:
+	  * docs/plugins/inspect/plugin-jpeg.xml:
+	  * docs/plugins/inspect/plugin-level.xml:
+	  * docs/plugins/inspect/plugin-matroska.xml:
+	  * docs/plugins/inspect/plugin-mulaw.xml:
+	  * docs/plugins/inspect/plugin-multipart.xml:
+	  * docs/plugins/inspect/plugin-navigationtest.xml:
+	  * docs/plugins/inspect/plugin-ossaudio.xml:
+	  * docs/plugins/inspect/plugin-png.xml:
+	  * docs/plugins/inspect/plugin-rtp.xml:
+	  * docs/plugins/inspect/plugin-rtsp.xml:
+	  * docs/plugins/inspect/plugin-shout2send.xml:
+	  * docs/plugins/inspect/plugin-smpte.xml:
+	  * docs/plugins/inspect/plugin-speex.xml:
+	  * docs/plugins/inspect/plugin-udp.xml:
+	  * docs/plugins/inspect/plugin-videobalance.xml:
+	  * docs/plugins/inspect/plugin-videobox.xml:
+	  * docs/plugins/inspect/plugin-videoflip.xml:
+	  * docs/plugins/inspect/plugin-videomixer.xml:
+	  * docs/plugins/inspect/plugin-wavenc.xml:
+	  * docs/plugins/inspect/plugin-wavparse.xml:
+	  * docs/plugins/inspect/plugin-ximagesrc.xml:
+	  Update files to CVS/Prerelease version, add esdsink docs.
+	  * ext/esd/esdsink.c:
+	  Add gtk-doc blurb.
+	  * gst/rtp/gstrtpmp4vpay.c:
+	  Fix typo in element description.
+
+2006-07-24 14:54:04 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* ChangeLog:
+	  ChangeLog surgery: fix Stefan's e-mail address
+	  Original commit message from CVS:
+	  ChangeLog surgery: fix Stefan's e-mail address
+
+2006-07-24 14:49:19 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/esd/esdsink.c: Prevent libesd from auto-spawning a sound daemon if it is not already running. Now that we don't d...
+	  Original commit message from CVS:
+	  * ext/esd/esdsink.c: (gst_esdsink_open),
+	  (gst_esdsink_factory_init):
+	  Prevent libesd from auto-spawning a sound daemon if it
+	  is not already running. Now that we don't do evil stuff
+	  like that any longer we can give esdsink a rank so that
+	  autoaudiosink will try it as well if all other audio
+	  sinks fail (#343051).
+
+2006-07-24 14:42:11 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/esd/Makefile.am: Oops, need to remove README from EXTRA_DIST as well.
+	  Original commit message from CVS:
+	  * ext/esd/Makefile.am:
+	  Oops, need to remove README from EXTRA_DIST as well.
+
+2006-07-24 14:37:36 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/esd/README: Remove, it contains nothing useful anyway.
+	  Original commit message from CVS:
+	  * ext/esd/README:
+	  Remove, it contains nothing useful anyway.
+	  * ext/esd/esdsink.c: (gst_esdsink_init), (gst_esdsink_prepare),
+	  (gst_esdsink_delay):
+	  Some small clean-ups; use GST_BOILERPLATE etc.
+
+2006-07-24 14:16:06 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/law/: Fix negotiation to deal with ANY/EMPTY caps instead of leaking.
+	  Original commit message from CVS:
+	  * gst/law/alaw-decode.c: (alawdec_getcaps):
+	  * gst/law/alaw-encode.c: (alawenc_getcaps), (gst_alawenc_chain):
+	  * gst/law/mulaw-decode.c: (mulawdec_getcaps):
+	  * gst/law/mulaw-encode.c: (mulawenc_getcaps):
+	  Fix negotiation to deal with ANY/EMPTY caps instead of leaking.
+
+2006-07-24 13:40:56 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/wavparse/gstwavparse.*: Use information from 'fact' chunk for length calculation of compressed samples. Calculate...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_reset),
+	  (gst_wavparse_other), (gst_wavparse_perform_seek),
+	  (gst_wavparse_get_upstream_size), (gst_wavparse_stream_headers),
+	  (gst_wavparse_add_src_pad), (gst_wavparse_stream_data),
+	  (gst_wavparse_pad_query):
+	  * gst/wavparse/gstwavparse.h:
+	  Use information from 'fact' chunk for length calculation of compressed
+	  samples. Calculate bps if bogus value is found in wav header (embeded
+	  mp2/mp3).
+
+2006-07-24 11:48:03 +0000  Joni Valtanen <joni.valtanen@movial.fi>
+
+	  Port udp plugin to win32 (#345288).
+	  Original commit message from CVS:
+	  Based on patch by: Joni Valtanen  <joni dot valtanen at movial fi>
+	  * configure.ac:
+	  * gst/udp/Makefile.am:
+	  * gst/udp/gstdynudpsink.c: (gst_dynudpsink_init),
+	  (gst_dynudpsink_finalize), (gst_dynudpsink_close):
+	  * gst/udp/gstdynudpsink.h:
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_init),
+	  (gst_multiudpsink_finalize), (gst_multiudpsink_close):
+	  * gst/udp/gstmultiudpsink.h:
+	  * gst/udp/gstudp.c: (plugin_init):
+	  * gst/udp/gstudpsink.h:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_init), (gst_udpsrc_create),
+	  (gst_udpsrc_start), (gst_udpsrc_stop):
+	  * gst/udp/gstudpsrc.h:
+	  * gst/udp/gstudpnetutils.c: (gst_udp_net_utils_win32_inet_aton),
+	  (gst_udp_net_utils_win32_wsa_startup):
+	  * gst/udp/gstudpnetutils.h:
+	  Port udp plugin to win32 (#345288).
+
+2006-07-24 11:00:34 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/rtspconnection.c: Remove unwanted DEBUG line.
+	  Original commit message from CVS:
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_send):
+	  Remove unwanted DEBUG line.
+
+2006-07-23 11:33:54 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/: On second thought, it might be wiser and more efficient not to do tag registration from a streaming th...
+	  Original commit message from CVS:
+	  * gst/id3demux/gstid3demux.c: (plugin_init):
+	  * gst/id3demux/id3tags.c:
+	  (id3demux_add_id3v2_frame_blob_to_taglist):
+	  * gst/id3demux/id3tags.h:
+	  On second thought, it might be wiser and more efficient
+	  not to do tag registration from a streaming thread.
+
+2006-07-23 10:56:27 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/id3tags.c: Put ID3v2 frames we can't parse as binary blobs into private tags, so that they are not lost ...
+	  Original commit message from CVS:
+	  * gst/id3demux/id3tags.c:
+	  (id3demux_add_id3v2_frame_blob_to_taglist),
+	  (id3demux_id3v2_frames_to_tag_list):
+	  Put ID3v2 frames we can't parse as binary blobs into private
+	  tags, so that they are not lost when retagging, at least once
+	  id3v2mux has been taught to re-inject those frames again.
+	  See bug #334375.
+
+2006-07-21 10:57:00 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: Fix some leaks.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_process_next_entry):
+	  Fix some leaks.
+	  * gst/id3demux/id3tags.c: (id3demux_id3v2_frames_to_tag_list):
+	  Don't use \n in debug lines.
+
+2006-07-20 18:48:32 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  docs/plugins/: Add annodex and icydemux, cleanup the sections a bit
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  Add annodex and icydemux, cleanup the sections a bit
+
+2006-07-19 14:36:00 +0000  Martin Szulecki <compiz@sukimashita.com>
+
+	  sys/v4l2/gstv4l2object.c: If "device-name" is requested and the device is not open, try to temporarily open it to obt...
+	  Original commit message from CVS:
+	  Patch by: Martin Szulecki
+	  * sys/v4l2/gstv4l2object.c: (gst_v4l2_object_get_property_helper):
+	  If "device-name" is requested and the device is not
+	  open, try to temporarily open it to obtain this
+	  information (#342494).
+
+2006-07-19 11:52:53 +0000  Alex Lancaster <alexl@users.sourceforge.net>
+
+	  ext/taglib/gstid3v2mux.cc: Write GST_TAG_ENCODER and GST_TAG_ENCODER_VERSION as
+	  Original commit message from CVS:
+	  Patch by: Alex Lancaster <alexl at users sourceforge net>
+	  * ext/taglib/gstid3v2mux.cc:
+	  Write GST_TAG_ENCODER and GST_TAG_ENCODER_VERSION as
+	  ID3v2 TSSE frames (#347898).
+
+2006-07-19 07:40:52 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* ChangeLog:
+	  ChangeLog surgery: mention fixed bug
+	  Original commit message from CVS:
+	  ChangeLog surgery: mention fixed bug
+
+2006-07-18 19:59:01 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/avi/gstavimux.c: Respect mpegversion for "video/mpeg" and give message in case of unhandled versions.
+	  Original commit message from CVS:
+	  * gst/avi/gstavimux.c: (gst_avi_mux_vidsink_set_caps):
+	  Respect mpegversion for "video/mpeg" and give message in case of
+	  unhandled versions.
+
+2006-07-18 18:05:15 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/wavpack/gstwavpackdec.c: Fix caps after previous change to byte order endianness.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_chain):
+	  Fix caps after previous change to byte order endianness.
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_reset),
+	  (gst_wavpack_parse_sink_event), (gst_wavpack_parse_init),
+	  (gst_wavpack_parse_loop):
+	  * ext/wavpack/gstwavpackparse.h:
+	  Queue incoming events if there's no source pad yet and
+	  send them downstream later when the pad is there.
+
+2006-07-18 16:47:25 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/wavpack/gstwavpackdec.*: Output audio in native byte order (which is also how we get samples from wavpack); outpu...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_init),
+	  (gst_wavpack_dec_format_samples),
+	  (gst_wavpack_dec_clip_outgoing_buffer), (gst_wavpack_dec_chain),
+	  (gst_wavpack_dec_change_state):
+	  * ext/wavpack/gstwavpackdec.h:
+	  Output audio in native byte order (which is also how we get
+	  samples from wavpack); output samples with 21-24 bit depth
+	  with 32 bit width (makes things easier for us).
+
+2006-07-18 15:53:35 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/wavpack/gstwavpackdec.*: More clean-ups: remove most of the disfunctional correction pad stuff for now, if it eve...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_base_init),
+	  (gst_wavpack_dec_class_init), (gst_wavpack_dec_init),
+	  (gst_wavpack_dec_finalize), (gst_wavpack_dec_format_samples),
+	  (gst_wavpack_dec_clip_outgoing_buffer), (gst_wavpack_dec_chain),
+	  (gst_wavpack_dec_sink_event), (gst_wavpack_dec_change_state):
+	  * ext/wavpack/gstwavpackdec.h:
+	  More clean-ups: remove most of the disfunctional correction
+	  pad stuff for now, if it ever gets implemented a lot of stuff
+	  will have to be rewritten anyway; redo chain function, move
+	  errors to end, error out instead of g_assert()ing. Also rename
+	  overly long variable 'wavpackdec' to just 'dec'; miscellaneous
+	  other small stuff.
+
+2006-07-18 14:08:06 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  configure.ac: Check for wavpack version and define WAVPACK_OLD_API if necessary.
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge <slomo at circular-chaos.org>
+	  * configure.ac:
+	  Check for wavpack version and define WAVPACK_OLD_API if
+	  necessary.
+	  * ext/wavpack/Makefile.am:
+	  * ext/wavpack/gstwavpackcommon.c: (gst_wavpack_read_header),
+	  (gst_wavpack_read_metadata):
+	  * ext/wavpack/gstwavpackcommon.h:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_base_init),
+	  (gst_wavpack_dec_class_init), (gst_wavpack_dec_init),
+	  (gst_wavpack_dec_finalize), (gst_wavpack_dec_format_samples),
+	  (gst_wavpack_dec_clip_outgoing_buffer), (gst_wavpack_dec_chain),
+	  (gst_wavpack_dec_sink_event), (gst_wavpack_dec_change_state),
+	  (gst_wavpack_dec_request_new_pad), (gst_wavpack_dec_plugin_init):
+	  * ext/wavpack/gstwavpackdec.h:
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_class_init),
+	  (gst_wavpack_enc_init), (gst_wavpack_enc_finalize),
+	  (gst_wavpack_enc_set_wp_config):
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_base_init),
+	  (gst_wavpack_parse_finalize), (gst_wavpack_parse_class_init),
+	  (gst_wavpack_parse_index_get_entry_from_sample),
+	  (gst_wavpack_parse_scan_to_find_sample),
+	  (gst_wavpack_parse_handle_seek_event),
+	  (gst_wavpack_parse_create_src_pad):
+	  * ext/wavpack/gstwavpackstreamreader.c:
+	  * ext/wavpack/gstwavpackstreamreader.h:
+	  Port to new/official wavpack API, don't use API that was exported
+	  in wavpack header files and in the lib but meant to be private, at
+	  least not for recent wavpack versions; misc. 'cleanups' (#347443).
+
+2006-07-17 10:25:57 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Store duration in uint64 too instead of clipping.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_perform_seek),
+	  (gst_qtdemux_prepare_current_sample),
+	  (gst_qtdemux_loop_state_movie):
+	  Store duration in uint64 too instead of clipping.
+	  When we do a keyframe seek and the requested time is at the
+	  keyframe, don't seek back to the beginning of the keyframe.
+	  Fixes #347439.
+
+2006-07-17 10:22:54 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/libpng/gstpngdec.*: Use statically allocated segment instead of leaking.
+	  Original commit message from CVS:
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_init), (buffer_clip),
+	  (gst_pngdec_caps_create_and_set), (gst_pngdec_task),
+	  (gst_pngdec_chain), (gst_pngdec_sink_event),
+	  (gst_pngdec_libpng_init), (gst_pngdec_change_state),
+	  (gst_pngdec_sink_activate_push):
+	  * ext/libpng/gstpngdec.h:
+	  Use statically allocated segment instead of leaking.
+	  Various cleanups.
+	  Fix flush and seek handling.
+
+2006-07-16 14:31:48 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Added simple generic mpeg4 depayloader.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpmp4gdepay.c: (gst_rtp_mp4g_depay_base_init),
+	  (gst_rtp_mp4g_depay_class_init), (gst_rtp_mp4g_depay_init),
+	  (gst_rtp_mp4g_depay_setcaps), (gst_rtp_mp4g_depay_process),
+	  (gst_rtp_mp4g_depay_set_property),
+	  (gst_rtp_mp4g_depay_get_property),
+	  (gst_rtp_mp4g_depay_change_state),
+	  (gst_rtp_mp4g_depay_plugin_init):
+	  * gst/rtp/gstrtpmp4gdepay.h:
+	  * gst/rtp/gstrtpmp4gpay.c: (gst_rtp_mp4g_pay_class_init),
+	  (gst_rtp_mp4g_pay_parse_audio_config), (gst_rtp_mp4g_pay_setcaps),
+	  (gst_rtp_mp4g_pay_flush):
+	  Added simple generic mpeg4 depayloader.
+	  Fix generic mpeg4 payloader.
+
+2006-07-15 15:25:05 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/rtsp/gstrtspsrc.c: Don't try doing state changes on a NULL pointer.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_set_state):
+	  Don't try doing state changes on a NULL pointer.
+
+2006-07-15 11:50:25 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/: Do not use deprecated gtk functions.
+	  Original commit message from CVS:
+	  * gst/spectrum/demo-audiotest.c: (main):
+	  * gst/spectrum/demo-osssrc.c: (main):
+	  Do not use deprecated gtk functions.
+
+2006-07-14 13:33:54 +0000  Sebastien Cote <sebas642@yahoo.ca>
+
+	  gst/rtp/gstrtpamrdepay.*: rtpamrdec isn't a subclass of GstBaseRtpDepayload.
+	  Original commit message from CVS:
+	  Patch by: Sebastien Cote <sebas642 at yahoo dot ca>
+	  * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_base_init),
+	  (gst_rtp_amr_depay_class_init), (gst_rtp_amr_depay_init),
+	  (gst_rtp_amr_depay_setcaps), (gst_rtp_amr_depay_process):
+	  * gst/rtp/gstrtpamrdepay.h:
+	  rtpamrdec isn't a subclass of GstBaseRtpDepayload.
+	  Fixes #321191
+
+2006-07-14 12:01:05 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  sys/ximage/gstximagesrc.c: Fix segfault when moving mouse pointer to the bottom right corner.
+	  Original commit message from CVS:
+	  2006-07-14  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * sys/ximage/gstximagesrc.c: (gst_ximage_src_ximage_get),
+	  (gst_ximage_src_get_caps), (gst_ximage_src_class_init):
+	  Fix segfault when moving mouse pointer to the bottom right corner.
+
+2006-07-13 15:22:20 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* common:
+	* docs/plugins/inspect/plugin-qtdemux.xml:
+	  remove sdlvideosink plugin and update the rest
+	  Original commit message from CVS:
+	  remove sdlvideosink plugin and update the rest
+
+2006-07-12 09:34:15 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Added mpeg2 TS depayloader. Closing #347234.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpmp2tdepay.c: (gst_rtp_mp2t_depay_base_init),
+	  (gst_rtp_mp2t_depay_class_init), (gst_rtp_mp2t_depay_init),
+	  (gst_rtp_mp2t_depay_setcaps), (gst_rtp_mp2t_depay_process),
+	  (gst_rtp_mp2t_depay_set_property),
+	  (gst_rtp_mp2t_depay_get_property),
+	  (gst_rtp_mp2t_depay_change_state),
+	  (gst_rtp_mp2t_depay_plugin_init):
+	  * gst/rtp/gstrtpmp2tdepay.h:
+	  Added mpeg2 TS depayloader. Closing #347234.
+
+2006-07-12 09:28:46 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/spectrum/gstspectrum.c: Fix typo in property nick.
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_class_init):
+	  Fix typo in property nick.
+
+2006-07-11 22:46:47 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/cdio/gstcdiocddasrc.c: Remove g_assert that shouldn't be there.
+	  Original commit message from CVS:
+	  * ext/cdio/gstcdiocddasrc.c: (gst_cdio_cdda_src_close):
+	  Remove g_assert that shouldn't be there.
+
+2006-07-10 20:11:34 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/avi/gstavidemux.*: Don't push tag events found by gst_riff_parse_info() before outputting
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_reset),
+	  (gst_avi_demux_stream_header), (push_tag_lists):
+	  * gst/avi/gstavidemux.h:
+	  Don't push tag events found by gst_riff_parse_info() before outputting
+	  GST_EVENT_NEWSEGMENT.
+
+2006-07-10 16:41:57 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/: replaced closesocket and close in code with one CLOSE_SOCKET.
+	  Original commit message from CVS:
+	  * gst/rtsp/Makefile.am:
+	  * gst/rtsp/rtspconnection.c: (rtsp_connection_send),
+	  (rtsp_connection_close):
+	  * gst/rtsp/rtspdefs.h:
+	  replaced closesocket and close in code with one CLOSE_SOCKET.
+	  Some more cleanups. Fixes #345301.
+
+2006-07-10 15:26:39 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/autodetect/gstautoaudiosink.c: Fix example pipeline in docs.
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautoaudiosink.c:
+	  Fix example pipeline in docs.
+
+2006-07-10 14:49:46 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/filter/: Don't forget new files.
+	  Original commit message from CVS:
+	  * gst/filter/gstbpwsinc.h:
+	  * gst/filter/gstiir.h:
+	  * gst/filter/gstlpwsinc.h:
+	  Don't forget new files.
+
+2006-07-10 14:42:15 +0000  Mathis Hofer <mathis.hofer@dreamlab.net>
+
+	  Ported the gstfilter plugin to GStreamer 0.10.
+	  Original commit message from CVS:
+	  Patch by: Mathis Hofer <mathis dot hofer at dreamlab dot net>
+	  * configure.ac:
+	  * gst/filter/Makefile.am:
+	  * gst/filter/gstbpwsinc.c: (gst_bpwsinc_dispose),
+	  (gst_bpwsinc_base_init), (gst_bpwsinc_class_init),
+	  (gst_bpwsinc_init), (bpwsinc_set_caps), (bpwsinc_transform_ip),
+	  (bpwsinc_set_property), (bpwsinc_get_property):
+	  * gst/filter/gstfilter.c: (plugin_init):
+	  * gst/filter/gstfilter.h:
+	  * gst/filter/gstiir.c: (gst_iir_dispose), (gst_iir_base_init),
+	  (gst_iir_class_init), (gst_iir_init), (iir_set_caps),
+	  (iir_transform_ip), (iir_set_property), (iir_get_property):
+	  * gst/filter/gstlpwsinc.c: (gst_lpwsinc_dispose),
+	  (gst_lpwsinc_base_init), (gst_lpwsinc_class_init),
+	  (gst_lpwsinc_init), (lpwsinc_set_caps), (lpwsinc_transform_ip),
+	  (lpwsinc_set_property), (lpwsinc_get_property):
+	  Ported the gstfilter plugin to GStreamer 0.10.
+
+2006-07-10 10:21:57 +0000  Rob Taylor <robtaylor@floopily.org>
+
+	  gst/udp/gstmultiudpsink.c: If a destination is added before the stream is set to PAUSED, the multicast group is not j...
+	  Original commit message from CVS:
+	  Patch by: Rob Taylor <robtaylor at floopily dot org>
+	  * gst/udp/gstmultiudpsink.c: (join_multicast),
+	  (gst_multiudpsink_init_send), (gst_multiudpsink_add):
+	  If a destination is added before the stream is set to PAUSED, the
+	  multicast group is not joined as the socket is not created yet.
+	  Also TTL and LOOP should also be set. Fixes #346921.
+
+2006-07-10 09:57:26 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Extract comment information!!
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_udta):
+	  Extract comment information!!
+
+2006-07-10 09:46:25 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Extract year/date information (fixes #347079).
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_udta),
+	  (qtdemux_tag_add_date):
+	  Extract year/date information (fixes #347079).
+
+2006-07-08 22:41:25 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  sys/ximage/gstximagesrc.*: Fix use-damage property to actually work :)
+	  Original commit message from CVS:
+	  2006-07-09  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * sys/ximage/gstximagesrc.c: (gst_ximage_src_ximage_get),
+	  (gst_ximage_src_set_property), (gst_ximage_src_get_property),
+	  (gst_ximage_src_get_caps), (gst_ximage_src_class_init),
+	  (gst_ximage_src_init):
+	  * sys/ximage/gstximagesrc.h:
+	  Fix use-damage property to actually work :)
+	  Add startx, starty, endx, endy properties so screencasts other than full
+	  screen ones can work.
+
+2006-07-08 19:03:54 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  sys/ximage/gstximagesrc.*: Add use_damage property to offer ability to choose whether to use
+	  Original commit message from CVS:
+	  2006-07-08  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * sys/ximage/gstximagesrc.c: (gst_ximage_src_ximage_get),
+	  (gst_ximage_src_set_property), (gst_ximage_src_get_property),
+	  (gst_ximage_src_class_init), (gst_ximage_src_init):
+	  * sys/ximage/gstximagesrc.h:
+	  Add use_damage property to offer ability to choose whether to use
+	  XDamage or not.
+
+2006-07-07 15:04:29 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/goom/filters.c: Avoid goom coredumping by clearing memory.
+	  Original commit message from CVS:
+	  * gst/goom/filters.c: (zoomFilterSetResolution):
+	  Avoid goom coredumping by clearing memory.
+	  Fixes 345679.
+
+2006-07-07 14:30:26 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Don't crash on twos/sowt/raw audio. #345830.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_trak):
+	  Don't crash on twos/sowt/raw audio. #345830.
+
+2006-07-05 20:21:02 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  win32/vs6/libgstid3demux.dsp: Add a link to libgsttag-0.10.lib.
+	  Original commit message from CVS:
+	  * win32/vs6/libgstid3demux.dsp:
+	  Add a link to libgsttag-0.10.lib.
+
+2006-07-05 14:52:13 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/: Don't return FLOW_UNEXPECTED when a buffer is before the start of the stream (which might happen with large ID3...
+	  Original commit message from CVS:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_trim_buffer),
+	  (gst_tag_demux_read_range):
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_trim_buffer),
+	  (gst_id3demux_read_range):
+	  Don't return FLOW_UNEXPECTED when a buffer is before
+	  the start of the stream (which might happen with
+	  large ID3v2 tags if the tag reading was done pullrange
+	  based and we then switched to push mode later on).
+	  Fixes regression introduced by commit from June 29th.
+
+2006-07-05 10:14:16 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/gstid3v2mux.cc: Make UTF-8 the default encoding when writing string tags (before, our UTF-8 strings would ...
+	  Original commit message from CVS:
+	  * ext/taglib/gstid3v2mux.cc:
+	  Make UTF-8 the default encoding when writing string
+	  tags (before, our UTF-8 strings would automatically
+	  be converted to ISO-8859-1 by taglib and written as
+	  ISO-8859-1 fields if that was possible).
+	  * tests/check/elements/id3v2mux.c: (utf8_string_in_buf),
+	  (test_taglib_id3mux_check_tag_buffer), (identity_cb),
+	  (test_taglib_id3mux_with_tags):
+	  Add test case that makes sure our UTF-8 strings have
+	  actually been written into the tag as UTF-8.
+
+2006-07-04 16:00:26 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Let's try that again.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Let's try that again.
+
+2006-07-04 15:40:47 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Disable monoscope plugin for now until it fulfills all the requirements.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Disable monoscope plugin for now until it fulfills
+	  all the requirements.
+
+2006-07-03 20:35:45 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Port monoscope visualisation to 0.10.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/monoscope/Makefile.am:
+	  * gst/monoscope/gstmonoscope.c: (gst_monoscope_base_init),
+	  (gst_monoscope_class_init), (gst_monoscope_init),
+	  (gst_monoscope_finalize), (gst_monoscope_reset),
+	  (gst_monoscope_sink_setcaps), (gst_monoscope_src_setcaps),
+	  (gst_monoscope_src_negotiate), (get_buffer), (gst_monoscope_chain),
+	  (gst_monoscope_sink_event), (gst_monoscope_src_event),
+	  (gst_monoscope_change_state), (plugin_init):
+	  * gst/monoscope/gstmonoscope.h:
+	  Port monoscope visualisation to 0.10.
+
+2006-07-03 20:02:56 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Fix silly crasher in state change function; add
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_change_state),
+	  (gst_qtdemux_loop_state_header), (qtdemux_video_caps):
+	  Fix silly crasher in state change function; add
+	  IV41 fourcc (see bug #171111); don't output confusing
+	  debug message when skipping atoms.
+
+2006-07-03 16:43:10 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/: Return FLOW_UNEXPECTED when at the end of the file, not
+	  Original commit message from CVS:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_chain):
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_chain):
+	  Return FLOW_UNEXPECTED when at the end of the file, not
+	  FLOW_ERROR. Fixes 'internal stream error' errors that
+	  would sometimes occur in totem when scrubbing to the
+	  end of an ID3v1 tagged mp3 file.
+
+2006-07-03 15:31:22 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/libpng/gstpngdec.*: Implement buffer clipping/dropping using GstSegment.
+	  Original commit message from CVS:
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_init), (user_info_callback),
+	  (buffer_clip), (user_end_callback), (gst_pngdec_chain),
+	  (gst_pngdec_sink_event), (gst_pngdec_change_state):
+	  * ext/libpng/gstpngdec.h:
+	  Implement buffer clipping/dropping using GstSegment.
+	  This provides accurate seeking.
+
+2006-07-03 15:28:48 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/avi/gstavidemux.*: Proper aggregation of each stream's GstFlowReturn in order to figure out whether the task shou...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_reset),
+	  (gst_avi_demux_read_subindexes), (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_handle_seek), (gst_avi_demux_aggregated_flow),
+	  (gst_avi_demux_process_next_entry), (push_tag_lists),
+	  (gst_avi_demux_stream_data), (gst_avi_demux_loop):
+	  * gst/avi/gstavidemux.h:
+	  Proper aggregation of each stream's GstFlowReturn in order to figure out
+	  whether the task should stop or not.
+	  Don't send inline events before pushing out a NEW_SEGMENT, more
+	  specifically for GST_TAG_EVENT.
+	  Change a GST_ERROR to a GST_WARNING for a non-fatal situation in reading
+	  sub-indexes.
+
+2006-06-30 07:11:24 +0000  Brian Cameron <brian.cameron@sun.com>
+
+	  sys/sunaudio/gstsunaudiomixerctrl.c: Move "Monitor" slider to input tab so it works more like sdtaudiocontrol, which ...
+	  Original commit message from CVS:
+	  Patch by: Brian Cameron  <brian dot cameron at sun dot com>
+	  * sys/sunaudio/gstsunaudiomixerctrl.c:
+	  (gst_sunaudiomixer_ctrl_build_list):
+	  Move "Monitor" slider to input tab so it works more like
+	  sdtaudiocontrol, which is what people on Solaris are used
+	  to using for their mixer program (#346259).
+
+2006-06-29 14:50:18 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  tests/check/elements/level.c: fix a leak, clean up at the end
+	  Original commit message from CVS:
+	  * tests/check/elements/level.c: (GST_START_TEST):
+	  fix a leak, clean up at the end
+
+2006-06-29 11:41:55 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/: Send tag event after newsegment event.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream),
+	  (gst_matroska_demux_send_event),
+	  (gst_matroska_demux_loop_stream_parse_id):
+	  * gst/matroska/matroska-ids.h:
+	  Send tag event after newsegment event.
+
+2006-06-29 11:11:50 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/gstid3demux.c: Make sure we don't return GST_FLOW_OK with a NULL buffer in certain cases where a read be...
+	  Original commit message from CVS:
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_trim_buffer),
+	  (gst_id3demux_read_range):
+	  Make sure we don't return GST_FLOW_OK with a NULL buffer in
+	  certain cases where a read beyond the end of the file is
+	  requested. Fixes #345930.
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_trim_buffer),
+	  (gst_tag_demux_read_range):
+	  Fix same issue here as well.
+
+2006-06-29 11:05:14 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  sys/ximage/gstximagesrc.c: Fix hypothetical crash.
+	  Original commit message from CVS:
+	  2006-06-29  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * sys/ximage/gstximagesrc.c: (gst_ximage_src_ximage_get):
+	  Fix hypothetical crash.
+
+2006-06-28 08:36:30 +0000  Brian Cameron <brian.cameron@sun.com>
+
+	  sys/sunaudio/gstsunaudiosink.c: Do not modify the ports value. If the user has turned off the built-in speakers, then...
+	  Original commit message from CVS:
+	  Patch by: Brian Cameron  <brian dot cameron at sun dot com>
+	  * sys/sunaudio/gstsunaudiosink.c: (gst_sunaudiosink_prepare):
+	  Do not modify the ports value. If the user has turned off the
+	  built-in speakers, then we should not reset it in the prepare
+	  function, since this causes the built-in speakers to turn
+	  back on anytime the user changes a track in totem, rhythmbox,
+	  etc. (#346066).
+
+2006-06-23 09:35:45 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/goom/gstgoom.c: Fix double caps unref when negotiation fails.
+	  Original commit message from CVS:
+	  * gst/goom/gstgoom.c: (gst_goom_src_negotiate):
+	  Fix double caps unref when negotiation fails.
+
+2006-06-22 19:31:04 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Use GST_DEBUG_CATEGORY_STATIC where possible (#342503) plus two minor macro fixes.
+	  Original commit message from CVS:
+	  * ext/annodex/gstcmmldec.c:
+	  * ext/annodex/gstcmmlenc.c:
+	  * ext/annodex/gstcmmlparser.c:
+	  * ext/dv/gstdvdec.c:
+	  * ext/dv/gstdvdemux.c:
+	  * ext/gdk_pixbuf/pixbufscale.c:
+	  * ext/jpeg/gstjpegenc.c:
+	  * ext/jpeg/gstsmokedec.c:
+	  * ext/jpeg/gstsmokeenc.c:
+	  * ext/libpng/gstpngdec.c:
+	  * ext/libpng/gstpngenc.c:
+	  * ext/speex/gstspeexenc.c:
+	  * gst/alpha/gstalphacolor.c:
+	  * gst/cutter/gstcutter.c:
+	  * gst/debug/gstnavigationtest.c:
+	  * gst/icydemux/gsticydemux.c:
+	  * gst/level/gstlevel.c:
+	  * gst/multipart/multipart.c:
+	  * gst/rtp/gstrtpamrpay.c:
+	  * gst/rtp/gstrtpdepay.c:
+	  * gst/rtp/gstrtpilbcpay.c:
+	  * gst/rtp/gstrtpmp4gpay.c:
+	  * gst/rtp/gstrtpmp4vpay.c:
+	  * gst/rtsp/gstrtpdec.c:
+	  * gst/rtsp/gstrtspsrc.c:
+	  * gst/udp/gstdynudpsink.c:
+	  * gst/udp/gstmultiudpsink.c:
+	  * gst/udp/gstudpsrc.c:
+	  * gst/videobox/gstvideobox.c:
+	  * gst/videofilter/gstvideoflip.c:
+	  Use GST_DEBUG_CATEGORY_STATIC where possible (#342503)
+	  plus two minor macro fixes.
+
+2006-06-22 16:27:03 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/: Try to fix up broken matroska files containing subtitle streams with non-UTF8 character encodings (cou...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_check_subtitle_buffer),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+	  (gst_matroska_demux_subtitle_caps):
+	  * gst/matroska/matroska-ids.c:
+	  (gst_matroska_track_init_subtitle_context):
+	  * gst/matroska/matroska-ids.h:
+	  Try to fix up broken matroska files containing subtitle
+	  streams with non-UTF8 character encodings (courtesy of
+	  mkvmerge) using either the encoding specified in the
+	  GST_SUBTITLE_ENCODING environment variable or the
+	  current locale's character set if it is non-UTF8.
+	  Fixes #337076.
+
+2006-06-22 12:17:13 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/id3v2frames.c: Set image type from APIC frame as "image-type" field of GST_TAG_IMAGE buffer caps (#344605).
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (parse_picture_frame):
+	  Set image type from APIC frame as "image-type" field
+	  of GST_TAG_IMAGE buffer caps (#344605).
+
+2006-06-20 19:40:29 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/: Support chain-based operation, should make flac-over-DAAP work (#340492).
+	  Original commit message from CVS:
+	  * ext/flac/Makefile.am:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_init),
+	  (gst_flac_dec_reset_decoders),
+	  (gst_flac_dec_setup_seekable_decoder),
+	  (gst_flac_dec_setup_stream_decoder), (gst_flac_dec_finalize),
+	  (gst_flac_dec_metadata_callback),
+	  (gst_flac_dec_metadata_callback_seekable),
+	  (gst_flac_dec_metadata_callback_stream),
+	  (gst_flac_dec_error_callback),
+	  (gst_flac_dec_error_callback_seekable),
+	  (gst_flac_dec_error_callback_stream), (gst_flac_dec_read_seekable),
+	  (gst_flac_dec_read_stream), (gst_flac_dec_write),
+	  (gst_flac_dec_write_seekable), (gst_flac_dec_write_stream),
+	  (gst_flac_dec_loop), (gst_flac_dec_sink_event),
+	  (gst_flac_dec_chain), (gst_flac_dec_convert_sink),
+	  (gst_flac_dec_get_sink_query_types), (gst_flac_dec_sink_query),
+	  (gst_flac_dec_get_src_query_types), (gst_flac_dec_src_query),
+	  (gst_flac_dec_handle_seek_event), (gst_flac_dec_sink_activate),
+	  (gst_flac_dec_sink_activate_push),
+	  (gst_flac_dec_sink_activate_pull), (gst_flac_dec_change_state):
+	  * ext/flac/gstflacdec.h:
+	  Support chain-based operation, should make flac-over-DAAP
+	  work (#340492).
+
+2006-06-20 15:35:05 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  docs/plugins/gst-plugins-good-plugins-sections.txt: Doc updates, merge some unused symbols.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  Doc updates, merge some unused symbols.
+
+2006-06-20 14:57:09 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  Added documentation for the rtsp plugin. Fixes #345393.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * gst/rtsp/gstrtpdec.c: (gst_rtpdec_class_init):
+	  * gst/rtsp/gstrtspsrc.c:
+	  * gst/rtsp/gstrtspsrc.h:
+	  Added documentation for the rtsp plugin. Fixes #345393.
+
+2006-06-20 12:10:29 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/rtspconnection.c: Use better G_OS_* macros. Fixes #345301 some more.
+	  Original commit message from CVS:
+	  * gst/rtsp/rtspconnection.c: (inet_aton), (rtsp_connection_send),
+	  (rtsp_connection_close), (rtsp_connection_free):
+	  Use better G_OS_* macros. Fixes #345301 some more.
+
+2006-06-20 10:35:48 +0000  Brian Cameron <brian.cameron@sun.com>
+
+	  sys/sunaudio/: Add a SunAudio source plugin.
+	  Original commit message from CVS:
+	  Patch by: Brian Cameron <brian dot cameron at sun dot com>
+	  * sys/sunaudio/Makefile.am:
+	  * sys/sunaudio/gstsunaudio.c: (plugin_init):
+	  * sys/sunaudio/gstsunaudiomixerctrl.c:
+	  (gst_sunaudiomixer_ctrl_build_list), (gst_sunaudiomixer_ctrl_new),
+	  (gst_sunaudiomixer_ctrl_list_tracks),
+	  (gst_sunaudiomixer_ctrl_get_volume),
+	  (gst_sunaudiomixer_ctrl_set_volume),
+	  (gst_sunaudiomixer_ctrl_set_mute),
+	  (gst_sunaudiomixer_ctrl_set_record):
+	  * sys/sunaudio/gstsunaudiomixerctrl.h:
+	  * sys/sunaudio/gstsunaudiomixertrack.c:
+	  (gst_sunaudiomixer_track_init), (gst_sunaudiomixer_track_new):
+	  * sys/sunaudio/gstsunaudiomixertrack.h:
+	  * sys/sunaudio/gstsunaudiosrc.c: (gst_sunaudiosrc_dispose),
+	  (gst_sunaudiosrc_base_init), (gst_sunaudiosrc_class_init),
+	  (gst_sunaudiosrc_init), (gst_sunaudiosrc_set_property),
+	  (gst_sunaudiosrc_get_property), (gst_sunaudiosrc_getcaps),
+	  (gst_sunaudiosrc_open), (gst_sunaudiosrc_close),
+	  (gst_sunaudiosrc_prepare), (gst_sunaudiosrc_unprepare),
+	  (gst_sunaudiosrc_read), (gst_sunaudiosrc_delay),
+	  (gst_sunaudiosrc_reset):
+	  * sys/sunaudio/gstsunaudiosrc.h:
+	  Add a SunAudio source plugin.
+	  Support stereo and right/left channel gain in the mixer plugin.
+	  Support the RECORD flag so that you can switch between line-input and
+	  microphone in gnome-volume-control.
+	  Code cleanups like using an enumerator for track number instead of an
+	  integer. Fixes #344923.
+
+2006-06-20 10:31:41 +0000  Joni Valtanen <joni.valtanen@movial.fi>
+
+	  gst/rtsp/rtspconnection.c: Make RTSP plugin compile on windows. Fixes #345301.
+	  Original commit message from CVS:
+	  Patch by: Joni Valtanen <joni dot valtanen at movial dot fi>
+	  * gst/rtsp/rtspconnection.c: (inet_aton), (rtsp_connection_send),
+	  (rtsp_connection_close):
+	  Make RTSP plugin compile on windows. Fixes #345301.
+	  Some changes to original patch to catch errors better.
+	  use ifdef WIN32 instead of ifndef.
+
+2006-06-19 10:00:18 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  configure.ac: If we have libraw1394 >= 1.2.1, then we need libiec61883.
+	  Original commit message from CVS:
+	  2006-06-19  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * configure.ac:
+	  If we have libraw1394 >= 1.2.1, then we need libiec61883.
+
+2006-06-18 14:00:19 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/jpeg/gstjpegdec.c: After a failed buffer alloc, we need to abort the jpeg decoding (it started when parsing heade...
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_chain):
+	  After a failed buffer alloc, we need to abort the jpeg decoding (it
+	  started when parsing headers to figure out how many bytes we need
+	  to request downstream).
+
+2006-06-18 12:37:12 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  gst/wavparse/gstwavparse.c: Make sure we don't read beyond the end of the file (#345232).
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts  <manauw at skynet be>
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_perform_seek):
+	  Make sure we don't read beyond the end of the file (#345232).
+
+2006-06-17 14:35:37 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Fix --disable-external (can't set conditionals conditionally, #343602).
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Fix --disable-external (can't set conditionals conditionally,
+	  #343602).
+
+2006-06-16 12:35:08 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  gst/spectrum/Makefile.am: Fix build.
+	  Original commit message from CVS:
+	  2006-06-16  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * gst/spectrum/Makefile.am:
+	  Fix build.
+
+2006-06-16 10:56:24 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Use GST_PLUGIN_DOCS, --enable-plugin-docs etc.
+	  Original commit message from CVS:
+	  * autogen.sh:
+	  * configure.ac:
+	  * docs/Makefile.am:
+	  Use GST_PLUGIN_DOCS, --enable-plugin-docs etc.
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/inspect/plugin-taglib.xml:
+	  Add/fix apev2mux docs.
+
+2006-06-16 09:49:07 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/: port to use message to get results, cleanly exit when closing the window
+	  Original commit message from CVS:
+	  * gst/spectrum/demo-audiotest.c: (on_window_destroy),
+	  (draw_spectrum), (message_handler), (main):
+	  * gst/spectrum/demo-osssrc.c: (on_window_destroy), (draw_spectrum),
+	  (message_handler), (main):
+	  port to use message to get results, cleanly exit when closing the window
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_class_init),
+	  (gst_spectrum_init), (gst_spectrum_dispose),
+	  (gst_spectrum_set_property), (gst_spectrum_get_property),
+	  (gst_spectrum_set_caps), (gst_spectrum_start),
+	  (gst_spectrum_message_new), (gst_spectrum_transform_ip):
+	  * gst/spectrum/gstspectrum.h:
+	  port to derive from basetransform and send results via messages
+	  (like level element)
+
+2006-06-15 15:58:09 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Combine return values from src pad pushes.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_perform_seek),
+	  (gst_qtdemux_combine_flows), (gst_qtdemux_loop_state_movie),
+	  (gst_qtdemux_loop), (gst_qtdemux_chain), (qtdemux_parse_trak):
+	  Combine return values from src pad pushes.
+
+2006-06-15 08:50:09 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Don't crash on files with 0 samples, EOS immediatly instead.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_state_header),
+	  (gst_qtdemux_prepare_current_sample), (gst_qtdemux_advance_sample),
+	  (gst_qtdemux_add_stream):
+	  Don't crash on files with 0 samples, EOS immediatly instead.
+	  Fixes #344944.
+
+2006-06-14 15:59:56 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/dv/gstdvdec.c: Reset segment info on flush.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdec.c: (gst_dvdec_class_init), (gst_dvdec_init),
+	  (gst_dvdec_finalize), (gst_dvdec_sink_event),
+	  (gst_dvdec_change_state):
+	  Reset segment info on flush.
+	  Alloc segment in _init, free in _finalize.
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_handle_pull_seek):
+	  Don't send segments twice.
+
+2006-06-14 15:07:22 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/dv/gstdvdemux.c: Respect segment.stop. Fixes #342592.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_demux_frame):
+	  Respect segment.stop. Fixes #342592.
+
+2006-06-14 11:28:41 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-demux.c: No language specified means the implied language is English according to the matroska ...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream):
+	  No language specified means the implied language is English
+	  according to the matroska spec (partially fixes #344708);
+	  add some more debug output.
+
+2006-06-14 09:32:27 +0000  Sebastian Dröge <slomo@circular-chaos.org>
+
+	  ext/wavpack/gstwavpackenc.*: Use bitrate property solely for bitrates and add new bits-per-sample property for the ot...
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge  <slomo at circular-chaos org>
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_base_init),
+	  (gst_wavpack_enc_class_init), (gst_wavpack_enc_set_wp_config),
+	  (gst_wavpack_enc_chain), (gst_wavpack_enc_sink_event),
+	  (gst_wavpack_enc_set_property), (gst_wavpack_enc_get_property):
+	  * ext/wavpack/gstwavpackenc.h:
+	  Use bitrate property solely for bitrates and add new
+	  bits-per-sample property for the other stuff. Set duration
+	  to 'unknown' in initial header and resend header with proper
+	  duration on EOS; update Sebastian's e-mail address.
+
+2006-06-14 08:06:43 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/wavparse/gstwavparse.c: When operating chain-based, don't make any assumptions about the chunking of the incoming...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_peek_chunk_info),
+	  (gst_wavparse_peek_chunk), (gst_wavparse_stream_headers),
+	  (gst_wavparse_chain):
+	  When operating chain-based, don't make any assumptions about the
+	  chunking of the incoming data and make streaming work on days other
+	  than the second Thursday after a full moon. Also fix up debug
+	  messages here and there and make use of the most excellent new
+	  gst_pad_query_peer_duration() utility function.
+	  Skip any 'bext' chunks in front of the 'fmt ' chunk. Fixes #343837.
+	  * gst/wavparse/gstwavparse.h:
+	  Remove trailing comma after last enum value, some compilers don't
+	  like that.
+
+2006-06-13 17:05:25 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/wavparse/gstwavparse.c: Handle premature EOS gracefully.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_stream_data):
+	  Handle premature EOS gracefully.
+
+2006-06-13 09:54:26 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavidemux.c: Prevent out of bounds array access when scrubbing towards the end of the file between the last...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_handle_seek):
+	  Prevent out of bounds array access when scrubbing towards
+	  the end of the file between the last index entry and the
+	  end. Fixes occasional 'start <= stop' newsegment event
+	  assertions when scrubbing in MJPEG files.
+
+2006-06-12 11:13:39 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/check/elements/.cvsignore: And another one.
+	  Original commit message from CVS:
+	  * tests/check/elements/.cvsignore:
+	  And another one.
+
+2006-06-12 11:04:59 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/spectrum/.cvsignore: Ignore more.
+	  Original commit message from CVS:
+	  * gst/spectrum/.cvsignore:
+	  Ignore more.
+
+2006-06-12 10:53:26 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/libmms/gstmms.c: Set caps on outgoing buffers.
+	  Original commit message from CVS:
+	  * ext/libmms/gstmms.c: (gst_mms_create):
+	  Set caps on outgoing buffers.
+	  * sys/directdraw/gstdirectdrawsink.c: (gst_directdrawsink_init):
+	  Comment out unused global instance variable.
+
+2006-06-11 19:31:10 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/id3v2frames.c: Extract images from ID3v2 tags (APIC frames). Fixes #339704.
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (id3demux_id3v2_parse_frame),
+	  (scan_encoded_string), (parse_picture_frame):
+	  Extract images from ID3v2 tags (APIC frames). Fixes #339704.
+	  * configure.ac:
+	  Require core >= 0.10.8 (for GST_TAG_IMAGE and
+	  GST_TAG_PPEVIEW_IMAGE used in the patch above).
+
+2006-06-11 18:56:24 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/raw1394/.gitignore:
+	* ext/taglib/.gitignore:
+	* tests/check/elements/.gitignore:
+	* tests/examples/level/.gitignore:
+	  moap ignore
+	  Original commit message from CVS:
+	  moap ignore
+
+2006-06-11 18:52:19 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  ext/raw1394/gstdv1394src.c: gratuitous comment changes
+	  Original commit message from CVS:
+	  * ext/raw1394/gstdv1394src.c: (gst_dv1394src_discover_avc_node):
+	  gratuitous comment changes
+	  * tests/check/elements/level.c: (GST_START_TEST):
+	  fix level test leaks
+
+2006-06-11 18:44:54 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* .gitignore:
+	  ignore more
+	  Original commit message from CVS:
+	  ignore more
+
+2006-06-11 18:20:39 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/: Use gst_pad_query_peer_duration() utility function here.
+	  Original commit message from CVS:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_get_upstream_size):
+	  * gst/id3demux/gstid3demux.c: (id3demux_get_upstream_size):
+	  Use gst_pad_query_peer_duration() utility function here.
+
+2006-06-11 13:57:19 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  autogen.sh: require am17
+	  Original commit message from CVS:
+	  * autogen.sh:
+	  require am17
+	  * configure.ac:
+	  * ext/annodex/Makefile.am:
+	  * ext/cdio/Makefile.am:
+	  * ext/dv/Makefile.am:
+	  * ext/esd/Makefile.am:
+	  * ext/flac/Makefile.am:
+	  * ext/gdk_pixbuf/Makefile.am:
+	  * ext/ladspa/Makefile.am:
+	  * ext/libcaca/Makefile.am:
+	  * ext/speex/Makefile.am:
+	  * ext/taglib/Makefile.am:
+	  * sys/oss/Makefile.am:
+	  * sys/sunaudio/Makefile.am:
+	  * sys/ximage/Makefile.am:
+	  clean up build further
+
+2006-06-11 13:55:34 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* common:
+	* win32/common/config.h:
+	  update
+	  Original commit message from CVS:
+	  update
+
+2006-06-10 15:33:18 +0000  Sebastian Dröge <mail@slomosnail.de>
+
+	  ext/wavpack/: Add wavpack encoder element (#343131).
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge  <mail at slomosnail de>
+	  * ext/wavpack/Makefile.am:
+	  * ext/wavpack/gstwavpack.c: (plugin_init):
+	  * ext/wavpack/gstwavpackcommon.h:
+	  * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_mode_get_type),
+	  (gst_wavpack_enc_correction_mode_get_type),
+	  (gst_wavpack_enc_joint_stereo_mode_get_type),
+	  (gst_wavpack_enc_base_init), (gst_wavpack_enc_class_init),
+	  (gst_wavpack_enc_init), (gst_wavpack_enc_dispose),
+	  (gst_wavpack_enc_sink_set_caps), (gst_wavpack_enc_set_wp_config),
+	  (gst_wavpack_enc_format_samples), (gst_wavpack_enc_push_block),
+	  (gst_wavpack_enc_chain), (gst_wavpack_enc_rewrite_first_block),
+	  (gst_wavpack_enc_sink_event), (gst_wavpack_enc_change_state),
+	  (gst_wavpack_enc_set_property), (gst_wavpack_enc_get_property),
+	  (gst_wavpack_enc_plugin_init):
+	  * ext/wavpack/gstwavpackenc.h:
+	  * ext/wavpack/md5.c:
+	  * ext/wavpack/md5.h:
+	  Add wavpack encoder element (#343131).
+
+2006-06-09 20:36:00 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gconf/Makefile.am: Honour --disable-schemas-install configure option. Fixes #344100.
+	  Original commit message from CVS:
+	  * gconf/Makefile.am:
+	  Honour --disable-schemas-install configure option. Fixes #344100.
+
+2006-06-09 18:33:01 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/examples/level/Makefile.am: Add -lm to LIBS for pow() function, don't assume one of our dependencies (such as l...
+	  Original commit message from CVS:
+	  * tests/examples/level/Makefile.am:
+	  Add -lm to LIBS for pow() function, don't assume one of our
+	  dependencies (such as libxml-2.0) drags it in automatically
+	  (#343603).
+
+2006-06-09 18:17:23 +0000  Peter Kjellerstedt <pkj@axis.com>
+
+	  configure.ac: We should use $SED and not $(SED) in configure.ac (#343678).
+	  Original commit message from CVS:
+	  Patch by: Peter Kjellerstedt  <pkj at axis dot com>
+	  * configure.ac:
+	  We should use $SED and not $(SED) in configure.ac (#343678).
+
+2006-06-09 17:38:19 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Check for X before using X_CFLAGS in the check for opengl (#343866).
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Check for X before using X_CFLAGS in the check for opengl (#343866).
+	  * ext/musepack/Makefile.am:
+	  * ext/wavpack/Makefile.am:
+	  * gst/speed/Makefile.am:
+	  Add missing GST_LIBS, fixes build on cygwin (#343866).
+
+2006-06-09 17:29:08 +0000  Brian Cameron <brian.cameron@sun.com>
+
+	  sys/sunaudio/: Attached find a patch that fixes a number of bugs with the SunAudio mixer plugin and fixes #344101: 1....
+	  Original commit message from CVS:
+	  Patch by: Brian Cameron <brian dot cameron at sun dot com>
+	  * sys/sunaudio/gstsunaudiomixerctrl.c:
+	  (gst_sunaudiomixer_ctrl_open), (gst_sunaudiomixer_ctrl_build_list),
+	  (gst_sunaudiomixer_ctrl_new), (gst_sunaudiomixer_ctrl_set_volume),
+	  (gst_sunaudiomixer_ctrl_set_mute):
+	  * sys/sunaudio/gstsunaudiosink.c: (gst_sunaudiosink_class_init),
+	  (gst_sunaudiosink_init), (gst_sunaudiosink_prepare),
+	  (gst_sunaudiosink_write):
+	  Attached find a patch that fixes a number of bugs with the SunAudio mixer
+	  plugin and fixes #344101:
+	  1. The gst_sunaudiomixer_ctrl_build_list kept appending the same 3 tracks onto
+	  the tracklist causing gnome-volume-control's preferences dialog to be messed
+	  up and would core dump if you checked/unchecked any item.
+	  2. We weren't previously setting the MUTE flag properly.  Fixing this makes
+	  gnome-volume-control work better.
+	  3. Now we properly define the input track to be GST_MIXER_TRACK_INPUT and
+	  the monitor to be GST_MIXER_TRACK_OUTPUT, so that makes gnome-volume-control
+	  look better.
+	  Also some minor cleanup in gstsunaudiosink.c.
+
+2006-06-09 17:12:52 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/jpeg/gstjpegdec.*: API: Added IDCT method property
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c: (gst_idct_method_get_type),
+	  (gst_jpeg_dec_class_init), (gst_jpeg_dec_init),
+	  (gst_jpeg_dec_decode_indirect), (gst_jpeg_dec_decode_direct),
+	  (gst_jpeg_dec_chain), (gst_jpeg_dec_sink_event),
+	  (gst_jpeg_dec_set_property), (gst_jpeg_dec_get_property):
+	  * ext/jpeg/gstjpegdec.h:
+	  API: Added IDCT method property
+	  Small cleanups.
+	  Avoid dynamic allocation of trivial fixed structure.
+	  Allocate enough space for temp 4:4:4 YUV buffers. Fixes #343661.
+
+2006-06-07 09:25:16 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  configure.ac: We now require libraw1394 >= 1.1.0 and that version onwards all have .pc files.
+	  Original commit message from CVS:
+	  2006-06-07  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * configure.ac:
+	  We now require libraw1394 >= 1.1.0 and that version onwards all
+	  have .pc files.
+
+2006-06-02 15:02:54 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/law/alaw-decode.c: Trying to get items from an ANY or EMPTY caps is ... stupid.
+	  Original commit message from CVS:
+	  * gst/law/alaw-decode.c: (alawdec_getcaps):
+	  Trying to get items from an ANY or EMPTY caps is ... stupid.
+
+2006-06-02 11:33:18 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/dv/gstdvdec.*: Added GstSegment handling, now implements dropping/clipping.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdec.c: (gst_dvdec_init), (gst_dvdec_sink_event),
+	  (gst_dvdec_chain), (gst_dvdec_change_state):
+	  * ext/dv/gstdvdec.h:
+	  Added GstSegment handling, now implements dropping/clipping.
+
+2006-06-01 22:00:26 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Fix more gobject macros: obj<->klass, GstXXX<->GstXXXClass
+	  Original commit message from CVS:
+	  * ext/alsaspdif/alsaspdifsink.h:
+	  * ext/amrwb/gstamrwbdec.h:
+	  * ext/amrwb/gstamrwbenc.h:
+	  * ext/amrwb/gstamrwbparse.h:
+	  * ext/arts/gst_arts.h:
+	  * ext/artsd/gstartsdsink.h:
+	  * ext/audiofile/gstafparse.h:
+	  * ext/audiofile/gstafsink.h:
+	  * ext/audiofile/gstafsrc.h:
+	  * ext/audioresample/gstaudioresample.h:
+	  * ext/bz2/gstbz2dec.h:
+	  * ext/bz2/gstbz2enc.h:
+	  * ext/dirac/gstdiracdec.h:
+	  * ext/directfb/dfbvideosink.h:
+	  * ext/divx/gstdivxdec.h:
+	  * ext/divx/gstdivxenc.h:
+	  * ext/dts/gstdtsdec.h:
+	  * ext/faac/gstfaac.h:
+	  * ext/gsm/gstgsmdec.h:
+	  * ext/gsm/gstgsmenc.h:
+	  * ext/ivorbis/vorbisenc.h:
+	  * ext/libfame/gstlibfame.h:
+	  * ext/nas/nassink.h:
+	  * ext/neon/gstneonhttpsrc.h:
+	  * ext/polyp/polypsink.h:
+	  * ext/sdl/sdlaudiosink.h:
+	  * ext/sdl/sdlvideosink.h:
+	  * ext/shout/gstshout.h:
+	  * ext/snapshot/gstsnapshot.h:
+	  * ext/sndfile/gstsf.h:
+	  * ext/swfdec/gstswfdec.h:
+	  * ext/tarkin/gsttarkindec.h:
+	  * ext/tarkin/gsttarkinenc.h:
+	  * ext/theora/theoradec.h:
+	  * ext/wavpack/gstwavpackdec.h:
+	  * ext/wavpack/gstwavpackparse.h:
+	  * ext/xine/gstxine.h:
+	  * ext/xvid/gstxviddec.h:
+	  * ext/xvid/gstxvidenc.h:
+	  * gst/cdxaparse/gstcdxaparse.h:
+	  * gst/cdxaparse/gstcdxastrip.h:
+	  * gst/colorspace/gstcolorspace.h:
+	  * gst/festival/gstfestival.h:
+	  * gst/freeze/gstfreeze.h:
+	  * gst/gdp/gstgdpdepay.h:
+	  * gst/gdp/gstgdppay.h:
+	  * gst/modplug/gstmodplug.h:
+	  * gst/mpeg1sys/gstmpeg1systemencode.h:
+	  * gst/mpeg1videoparse/gstmp1videoparse.h:
+	  * gst/mpeg2sub/gstmpeg2subt.h:
+	  * gst/mpegaudioparse/gstmpegaudioparse.h:
+	  * gst/multifilesink/gstmultifilesink.h:
+	  * gst/overlay/gstoverlay.h:
+	  * gst/playondemand/gstplayondemand.h:
+	  * gst/qtdemux/qtdemux.h:
+	  * gst/rtjpeg/gstrtjpegdec.h:
+	  * gst/rtjpeg/gstrtjpegenc.h:
+	  * gst/smooth/gstsmooth.h:
+	  * gst/smoothwave/gstsmoothwave.h:
+	  * gst/spectrum/gstspectrum.h:
+	  * gst/speed/gstspeed.h:
+	  * gst/stereo/gststereo.h:
+	  * gst/switch/gstswitch.h:
+	  * gst/tta/gstttadec.h:
+	  * gst/tta/gstttaparse.h:
+	  * gst/videodrop/gstvideodrop.h:
+	  * gst/xingheader/gstxingmux.h:
+	  * sys/directdraw/gstdirectdrawsink.h:
+	  * sys/directsound/gstdirectsoundsink.h:
+	  * sys/dxr3/dxr3audiosink.h:
+	  * sys/dxr3/dxr3spusink.h:
+	  * sys/dxr3/dxr3videosink.h:
+	  * sys/qcam/gstqcamsrc.h:
+	  * sys/vcd/vcdsrc.h:
+	  Fix more gobject macros: obj<->klass, GstXXX<->GstXXXClass
+
+2006-06-01 21:07:26 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Fix more gobject macros: obj<->klass, GstXXX<->GstXXXClass
+	  Original commit message from CVS:
+	  * ext/aalib/gstaasink.h:
+	  * ext/annodex/gstcmmldec.h:
+	  * ext/cairo/gsttimeoverlay.h:
+	  * ext/dv/gstdvdec.h:
+	  * ext/dv/gstdvdemux.h:
+	  * ext/esd/esdmon.h:
+	  * ext/esd/esdsink.h:
+	  * ext/flac/gstflacenc.h:
+	  * ext/gconf/gstgconfaudiosink.h:
+	  * ext/gconf/gstgconfaudiosrc.h:
+	  * ext/gconf/gstgconfvideosink.h:
+	  * ext/gconf/gstgconfvideosrc.h:
+	  * ext/gdk_pixbuf/gstgdkanimation.h:
+	  * ext/gdk_pixbuf/pixbufscale.h:
+	  * ext/hal/gsthalaudiosink.h:
+	  * ext/hal/gsthalaudiosrc.h:
+	  * ext/jpeg/gstjpegenc.h:
+	  * ext/jpeg/gstsmokedec.h:
+	  * ext/jpeg/gstsmokeenc.h:
+	  * ext/libcaca/gstcacasink.h:
+	  * ext/libmng/gstmngdec.h:
+	  * ext/libmng/gstmngenc.h:
+	  * ext/libpng/gstpngdec.h:
+	  * ext/libpng/gstpngenc.h:
+	  * ext/raw1394/gstdv1394src.h:
+	  * ext/speex/gstspeexenc.h:
+	  * gst/autodetect/gstautoaudiosink.h:
+	  * gst/autodetect/gstautovideosink.h:
+	  * gst/avi/gstavidemux.h:
+	  * gst/cutter/gstcutter.h:
+	  * gst/debug/efence.h:
+	  * gst/debug/gstnavigationtest.h:
+	  * gst/debug/gstnavseek.h:
+	  * gst/flx/gstflxdec.h:
+	  * gst/goom/gstgoom.h:
+	  * gst/icydemux/gsticydemux.h:
+	  * gst/id3demux/gstid3demux.h:
+	  * gst/law/alaw-decode.h:
+	  * gst/law/alaw-encode.h:
+	  * gst/law/mulaw-decode.h:
+	  * gst/law/mulaw-encode.h:
+	  * gst/matroska/matroska-mux.h:
+	  * gst/median/gstmedian.h:
+	  * gst/oldcore/gstaggregator.h:
+	  * gst/oldcore/gstfdsink.h:
+	  * gst/oldcore/gstmd5sink.h:
+	  * gst/oldcore/gstmultifilesrc.h:
+	  * gst/oldcore/gstpipefilter.h:
+	  * gst/oldcore/gstshaper.h:
+	  * gst/oldcore/gststatistics.h:
+	  * gst/rtp/gstasteriskh263.h:
+	  * gst/rtp/gstrtpL16depay.h:
+	  * gst/rtp/gstrtpL16pay.h:
+	  * gst/rtp/gstrtpamrdepay.h:
+	  * gst/rtp/gstrtpamrpay.h:
+	  * gst/rtp/gstrtpdepay.h:
+	  * gst/rtp/gstrtpgsmdepay.h:
+	  * gst/rtp/gstrtpgsmpay.h:
+	  * gst/rtp/gstrtph263pay.h:
+	  * gst/rtp/gstrtph263pdepay.h:
+	  * gst/rtp/gstrtph263ppay.h:
+	  * gst/rtp/gstrtpmp4gpay.h:
+	  * gst/rtp/gstrtpmp4vdepay.h:
+	  * gst/rtp/gstrtpmp4vpay.h:
+	  * gst/rtp/gstrtpmpadepay.h:
+	  * gst/rtp/gstrtpmpapay.h:
+	  * gst/rtp/gstrtppcmadepay.h:
+	  * gst/rtp/gstrtppcmapay.h:
+	  * gst/rtp/gstrtppcmudepay.h:
+	  * gst/rtp/gstrtppcmupay.h:
+	  * gst/rtp/gstrtpspeexdepay.h:
+	  * gst/rtp/gstrtpspeexpay.h:
+	  * gst/rtsp/gstrtpdec.h:
+	  * gst/rtsp/gstrtspsrc.h:
+	  * gst/smpte/gstsmpte.h:
+	  * gst/udp/gstdynudpsink.h:
+	  * gst/udp/gstmultiudpsink.h:
+	  * gst/udp/gstudpsink.h:
+	  * gst/udp/gstudpsrc.h:
+	  * gst/videofilter/gstvideobalance.h:
+	  * gst/videofilter/gstvideoflip.h:
+	  * sys/oss/gstossdmabuffer.h:
+	  * sys/oss/gstossmixerelement.h:
+	  * sys/oss/gstosssink.h:
+	  * sys/oss/gstosssrc.h:
+	  * sys/osxvideo/osxvideosink.h:
+	  * sys/sunaudio/gstsunaudiomixer.h:
+	  * sys/sunaudio/gstsunaudiosink.h:
+	  * sys/ximage/gstximagesrc.h:
+	  Fix more gobject macros: obj<->klass, GstXXX<->GstXXXClass
+
+2006-05-31 16:23:54 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/goom/gstgoom.*: Handle QoS.
+	  Original commit message from CVS:
+	  * gst/goom/gstgoom.c: (gst_goom_class_init), (gst_goom_init),
+	  (gst_goom_finalize), (gst_goom_reset), (gst_goom_sink_setcaps),
+	  (gst_goom_src_setcaps), (gst_goom_src_event),
+	  (gst_goom_sink_event), (get_buffer), (gst_goom_chain),
+	  (gst_goom_change_state):
+	  * gst/goom/gstgoom.h:
+	  Handle QoS.
+	  Handle flushing, discont and events.
+	  Fix timestamps and various other cleanups.
+
+2006-05-31 15:37:16 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  ext/raw1394/gstdv1394src.c: Fix bus reset when using libiec61883
+	  Original commit message from CVS:
+	  2006-05-31  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * ext/raw1394/gstdv1394src.c: (gst_dv1394src_bus_reset):
+	  Fix bus reset when using libiec61883
+
+2006-05-31 10:31:23 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  configure.ac: Detect libiec61883 and set necessary CFLAGS and LIBS for dv1394.
+	  Original commit message from CVS:
+	  2006-05-31  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * configure.ac:
+	  Detect libiec61883 and set necessary CFLAGS and LIBS for dv1394.
+	  * ext/raw1394/Makefile.am:
+	  Add CFLAGS.
+	  * ext/raw1394/gstdv1394src.c: (gst_dv1394src_iec61883_receive),
+	  New method, to receive using libiec61883.
+	  (gst_dv1394src_iso_receive),
+	  #ifdef'd out if libiec61883 is present.
+	  (gst_dv1394src_bus_reset),
+	  Get userdata correctly if using libiec61883.
+	  (gst_dv1394src_create),
+	  When using libiec61883, only poll one fd and no need to read.
+	  (gst_dv1394src_discover_avc_node),
+	  Replace g_warnings.
+	  (gst_dv1394src_start),
+	  Create new handle when we know which dv port.  More reliable
+	  than setting port on an existing handle.  Initialise libiec61883.
+	  (gst_dv1394src_stop):
+	  If using libiec61883, then cleanup its handle properly.
+	  * ext/raw1394/gstdv1394src.h:
+	  Add libiec61883 handle.
+
+2006-05-30 21:07:38 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  gst/avi/gstavidemux.c: add an explicit dll imported declaration for GST_CAT_EVENT+WIN32
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c:
+	  add an explicit dll imported declaration for GST_CAT_EVENT+WIN32
+	  * win32/MANIFEST:
+	  sort file listing
+	  * win32/vs6/libgstavi.dsp:
+	  add gstavimux.c to the project
+	  * win32/vs6/libgstid3demux.dsp:
+	  add link to zlib library
+	  * win32/vs6/libgstmatroska.dsp:
+	  add matroska-ids.c to the project
+
+2006-05-30 14:35:18 +0000  Sebastian Dröge <mail@slomosnail.de>
+
+	  Add apev2mux element (#343122).
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge  <mail at slomosnail de >
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * ext/taglib/Makefile.am:
+	  * ext/taglib/gstapev2mux.cc:
+	  * ext/taglib/gstapev2mux.h:
+	  * ext/taglib/gstid3v2mux.cc:
+	  * ext/taglib/gsttaglibmux.c: (plugin_init):
+	  * ext/taglib/gsttaglibmux.h:
+	  Add apev2mux element (#343122).
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/apev2mux.c:
+	  (test_taglib_apev2mux_create_tags),
+	  (test_taglib_apev2mux_check_tags), (fill_mp3_buffer), (got_buffer),
+	  (demux_pad_added), (test_taglib_apev2mux_check_output_buffer),
+	  (test_taglib_apev2mux_with_tags), (GST_START_TEST),
+	  (apev2mux_suite), (main):
+	  Add unit test for apev2mux element.
+
+2006-05-28 17:33:13 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/: GST_PTR_FORMAT should be used to print caps in debug statements.
+	  Original commit message from CVS:
+	  * gst/alpha/gstalphacolor.c: (gst_alpha_color_transform_caps):
+	  * gst/debug/negotiation.c: (gst_negotiation_update_caps):
+	  * gst/rtp/gstrtpilbcdepay.c: (gst_rtp_ilbc_depay_setcaps):
+	  GST_PTR_FORMAT should be used to print caps in debug statements.
+
+2006-05-28 14:38:11 +0000  Sebastian Dröge <slomo@ubuntu.com>
+
+	  gst/apetag/gstapedemux.c: Some clean-ups and additions: map APE 'file' tag to
+	  Original commit message from CVS:
+	  Patch by: Sebastian Dröge  <slomo at ubuntu dot com>
+	  * gst/apetag/gstapedemux.c: (ape_demux_get_gst_tag_from_tag),
+	  (ape_demux_parse_tags):
+	  Some clean-ups and additions: map APE 'file' tag to
+	  GST_TAG_LOCATION (#343123); add support for extracting
+	  the track count and clean up parsing a bit (#343127).
+
+2006-05-28 13:49:12 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/jpeg/gstjpegdec.c: Initialize segment to GST_FORMAT_UNDEFINED in READY->PAUSED.
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_change_state):
+	  Initialize segment to GST_FORMAT_UNDEFINED in READY->PAUSED.
+
+2006-05-28 13:30:13 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/jpeg/gstjpegdec.*: Clip outgoing buffers according to currently configured segment.
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_finalize),
+	  (gst_jpeg_dec_init), (gst_jpeg_dec_chain),
+	  (gst_jpeg_dec_sink_event), (gst_jpeg_dec_change_state):
+	  * ext/jpeg/gstjpegdec.h:
+	  Clip outgoing buffers according to currently configured segment.
+
+2006-05-28 10:39:00 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/gstid3v2mux.cc: Handle  writing of track-count or album-volume-count without track-number or albume-volume...
+	  Original commit message from CVS:
+	  * ext/taglib/gstid3v2mux.cc:
+	  Handle  writing of track-count or album-volume-count without
+	  track-number or albume-volume-number (in this case the number
+	  will just be set to 0).
+	  * tests/check/elements/id3v2mux.c: (test_taglib_id3mux_check_tags):
+	  It would be nice if we actually checked the values received for
+	  track/album-volume number/count in  _check_tags(), rather than
+	  setting them again ...
+
+2006-05-28 10:05:47 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/id3v2frames.c: A track/volume number or count of 0 does not make sense, just ignore it along with negati...
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (id3v2_tag_to_taglist):
+	  A track/volume number or count of 0 does not make sense,
+	  just ignore it along with negative numbers (a tag might
+	  only contain a track count without a track number).
+
+2006-05-27 13:11:37 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/jpeg/gstjpegdec.c: Abort decompression when receiving FLUSH_STOP. This should avoid issues when interrupting deco...
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_init),
+	  (gst_jpeg_dec_sink_event):
+	  Abort decompression when receiving FLUSH_STOP. This should avoid
+	  issues when interrupting decoding with flushes.
+
+2006-05-27 12:10:50 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflac.c: Don't #include file we don't dist any longer.
+	  Original commit message from CVS:
+	  * ext/flac/gstflac.c:
+	  Don't #include file we don't dist any longer.
+
+2006-05-27 11:27:59 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  README: Replace current README (containing the release notes from some 0.9.x version) with a proper README taken from...
+	  Original commit message from CVS:
+	  * README:
+	  Replace current README (containing the release notes from
+	  some 0.9.x version) with a proper README taken from the core.
+
+2006-05-26 22:35:00 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/: added another example
+	  Original commit message from CVS:
+	  * gst/spectrum/Makefile.am:
+	  * gst/spectrum/demo-audiotest.c: (on_frequency_changed),
+	  (spectrum_chain), (main):
+	  * gst/spectrum/demo-osssrc.c:
+	  added another example
+	  * sys/v4l2/gstv4l2src.c:
+	  fix typo
+
+2006-05-26 13:16:54 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Clip the outputed NEWSEGMENT stop time to the configured segment stop time.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_activate_segment):
+	  Clip the outputed NEWSEGMENT stop time to the configured segment stop
+	  time.
+
+2006-05-26 11:48:44 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Don't clear the running variable in the seek code.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_do_seek):
+	  Don't clear the running variable in the seek code.
+
+2006-05-24 16:03:40 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/dv/gstdvdemux.c: Implement EOS correctly by either posting
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_loop):
+	  Implement EOS correctly by either posting
+	  SEGMENT_DONE or pushing an EOS message depending
+	  on the seek type. Fixes #342592
+
+2006-05-24 11:56:43 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Detect QCELP in mp4a descriptors.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_handle_esds):
+	  Detect QCELP in mp4a descriptors.
+
+2006-05-24 10:00:50 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/law/: Some cleanups in the chain functions.
+	  Original commit message from CVS:
+	  * gst/law/alaw-decode.c: (gst_alawdec_chain):
+	  * gst/law/alaw-decode.h:
+	  * gst/law/alaw-encode.c: (gst_alawenc_chain):
+	  * gst/law/alaw-encode.h:
+	  * gst/law/mulaw-decode.c: (gst_mulawdec_chain):
+	  * gst/law/mulaw-decode.h:
+	  * gst/law/mulaw-encode.c: (gst_mulawenc_chain):
+	  * gst/law/mulaw-encode.h:
+	  Some cleanups in the chain functions.
+	  Remove some GStreamer 0.0.2 bits.
+
+2006-05-23 20:15:04 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  gst/matroska/matroska-mux.c: gst_collect_pads_stop() needs to be called before chaining up to the parent class (#3427...
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts  <manauw at skynet be>
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_change_state):
+	  gst_collect_pads_stop() needs to be called before chaining up
+	  to the parent class (#342734).
+
+2006-05-23 16:45:22 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/: Remove backwards compatibility cruft for dealing with FLAC API changes in the 1.0.x series - we require 1....
+	  Original commit message from CVS:
+	  * ext/flac/Makefile.am:
+	  * ext/flac/flac_compat.h:
+	  * ext/flac/gstflac.c:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_init):
+	  * ext/flac/gstflacenc.c:
+	  Remove backwards compatibility cruft for dealing with FLAC API
+	  changes in the 1.0.x series - we require 1.1.1 or newer these days.
+
+2006-05-23 13:44:11 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/: Add support for muxing/demuxing theora video (#342448; too bad none of the usual linux players can act...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream),
+	  (gst_matroska_demux_push_xiph_codec_priv_data),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+	  (gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps):
+	  * gst/matroska/matroska-ids.h:
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_base_init),
+	  (gst_matroska_mux_video_pad_setcaps),
+	  (xiph3_streamheader_to_codecdata),
+	  (vorbis_streamheader_to_codecdata),
+	  (theora_streamheader_to_codecdata),
+	  (gst_matroska_mux_audio_pad_setcaps),
+	  (gst_matroska_mux_write_data):
+	  Add support for muxing/demuxing theora video (#342448; too bad
+	  none of the usual linux players can actually play this). Playback
+	  in GStreamer will require additional changes to theoradec in -base.
+	  Refactor streamheaders <=> CodecPrivateData code a bit; some small
+	  cleanups.
+
+2006-05-22 18:00:52 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: po/POTFILES.in:
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_trak), (plugin_init):
+	  po/POTFILES.in:
+	  Throw an error when the file is encrypted. Move plugin_init stuff
+	  to the end of the file, add stuff for i18n, make debug category
+	  static.
+
+2006-05-22 15:23:05 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/jpeg/gstjpegdec.c: Fix crashes when the horizontal subsampling is 1.
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c: (hresamplecpy1),
+	  (gst_jpeg_dec_decode_indirect), (gst_jpeg_dec_chain):
+	  Fix crashes when the horizontal subsampling is 1.
+	  Fixes #342097.
+
+2006-05-22 14:56:29 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/rtp/gstasteriskh263.h:
+	* gst/rtp/gstrtpL16depay.h:
+	* gst/rtp/gstrtpL16pay.h:
+	* gst/rtp/gstrtpamrdepay.h:
+	* gst/rtp/gstrtpamrpay.h:
+	* gst/rtp/gstrtpgsmdepay.h:
+	* gst/rtp/gstrtpgsmpay.h:
+	* gst/rtp/gstrtph263pay.h:
+	* gst/rtp/gstrtph263pdepay.h:
+	* gst/rtp/gstrtph263ppay.h:
+	* gst/rtp/gstrtpmp4gpay.h:
+	* gst/rtp/gstrtpmp4vdepay.h:
+	* gst/rtp/gstrtpmp4vpay.h:
+	* gst/rtp/gstrtpmpadepay.h:
+	* gst/rtp/gstrtpmpapay.h:
+	  cover up the dirty truth
+	  Original commit message from CVS:
+	  cover up the dirty truth
+
+2006-05-22 13:53:18 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  gst/avi/gstavimux.*: - add odml (large file) index support
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts  <manauw at skynet be>
+	  * gst/avi/gstavimux.c: (gst_avi_mux_finalize), (gst_avi_mux_init),
+	  (gst_avi_mux_vidsink_set_caps), (gst_avi_mux_audsink_set_caps),
+	  (gst_avi_mux_write_tag), (gst_avi_mux_riff_get_avi_header),
+	  (gst_avi_mux_riff_get_avix_header), (gst_avi_mux_write_avix_index),
+	  (gst_avi_mux_add_index), (gst_avi_mux_bigfile),
+	  (gst_avi_mux_start_file), (gst_avi_mux_stop_file),
+	  (gst_avi_mux_handle_event), (gst_avi_mux_do_audio_buffer),
+	  (gst_avi_mux_do_video_buffer), (gst_avi_mux_do_one_buffer),
+	  (gst_avi_mux_change_state):
+	  * gst/avi/gstavimux.h:
+	  Some enhancements for avimux (#342526):
+	  - add odml (large file) index support
+	  - store codec init data (e.g. huffyuv)
+	  - miscellaneous other fixes/cleanups
+
+2006-05-22 13:51:30 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtpilbcdepay.c:
+	* gst/rtp/gstrtpilbcpay.c:
+	* gst/rtp/gstrtpmp4gpay.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtppcmadepay.c:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmudepay.c:
+	* gst/rtp/gstrtppcmupay.c:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	  fix descriptions and license blocks cut and paste anyone ?
+	  Original commit message from CVS:
+	  fix descriptions and license blocks
+	  cut and paste anyone ?
+
+2006-05-21 16:41:44 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/gstspectrum.c: Use boilerplate macro, fix strings to match plugin-moval-requirements
+	  Original commit message from CVS:
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_class_init),
+	  (gst_spectrum_init), (gst_spectrum_set_sink_caps),
+	  (gst_spectrum_get_sink_caps), (gst_spectrum_chain):
+	  Use boilerplate macro, fix strings to match plugin-moval-requirements
+
+2006-05-21 16:23:23 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/spectrum/Makefile.am: Link to base libraries
+	  Original commit message from CVS:
+	  * gst/spectrum/Makefile.am:
+	  Link to base libraries
+	  * gst/spectrum/demo-osssrc.c: (main):
+	  use new threshhold property
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_class_init),
+	  (gst_spectrum_init), (gst_spectrum_dispose),
+	  (gst_spectrum_set_property), (gst_spectrum_set_sink_caps),
+	  (gst_spectrum_get_sink_caps), (gst_spectrum_chain),
+	  (gst_spectrum_change_state):
+	  * gst/spectrum/gstspectrum.h:
+	  Use gst_adapter, support multiple-channels, add threshold property for
+	  result, add docs, fix resulting spectrum range (was including mirrored
+	  results)
+
+2006-05-20 22:42:15 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Initial port of the spectrum element
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/spectrum/demo-osssrc.c: (spectrum_chain), (main):
+	  * gst/spectrum/fix_fft.c: (gst_spectrum_fix_dot):
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_get_type),
+	  (gst_spectrum_base_init), (gst_spectrum_class_init),
+	  (gst_spectrum_init), (gst_spectrum_dispose),
+	  (gst_spectrum_set_property), (gst_spectrum_chain):
+	  * gst/spectrum/gstspectrum.h:
+	  Initial port of the spectrum element
+
+2006-05-19 18:58:05 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2xoverlay.c:
+	  I forget to add sys/v4l2/gstv4l2xoverlay.c in las commit
+	  Original commit message from CVS:
+	  I forget to add sys/v4l2/gstv4l2xoverlay.c in las commit
+
+2006-05-19 18:31:25 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2src.c:
+	  Some clean-ups requested by wingo in bug #338818.
+	  Original commit message from CVS:
+	  Some clean-ups requested by wingo in bug #338818.
+
+2006-05-19 14:05:53 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/id3demux/id3v2frames.c: Don't output any tag when we encounter a negative track number - the tag type is uint, so...
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (id3v2_tag_to_taglist):
+	  Don't output any tag when we encounter a negative track number - the
+	  tag type is uint, so we end up outputting huge positive numbers
+	  instead. (Fixes: #342029)
+
+2006-05-18 23:04:59 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  configure.ac: update for new GSTPB_PLUGINS_DIR
+	  Original commit message from CVS:
+	  * configure.ac:
+	  update for new GSTPB_PLUGINS_DIR
+
+2006-05-18 19:34:47 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  configure.ac: Check for X11
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Check for X11
+	  * sys/v4l2/gstv4l2object.c: (gst_v4l2_class_probe_devices):
+	  * sys/v4l2/gstv4l2object.h:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_iface_supported):
+	  * sys/v4l2/gstv4l2src.h:
+	  * sys/v4l2/gstv4l2xoverlay.c: (gst_v4l2_xoverlay_open):
+	  * sys/v4l2/gstv4l2xoverlay.h:
+	  Code cleanups, fix debug macros
+
+2006-05-18 14:45:33 +0000  Philippe Kalaf <philippe.kalaf@collabora.co.uk>
+
+	  rtp/gst/gstrtph263pay.c: Properly set static caps for H263 at 34.
+	  Original commit message from CVS:
+	  2006-05-18  Philippe Kalaf  <philippe.kalaf at collabora.co.uk>
+	  * rtp/gst/gstrtph263pay.c:
+	  Properly set static caps for H263 at 34.
+
+2006-05-18 12:46:08 +0000  James Doc Livingston <doclivingston@gmail.com>
+
+	  ext/taglib/gsttaglibmux.c: Merge event tags and tag setter tags correctly (#339918). Also, don't leak taglist in case...
+	  Original commit message from CVS:
+	  Patch by: James "Doc" Livingston  <doclivingston gmail com>
+	  * ext/taglib/gsttaglibmux.c: (gst_tag_lib_mux_render_tag):
+	  Merge event tags and tag setter tags correctly (#339918). Also,
+	  don't leak taglist in case of an error.
+
+2006-05-17 18:09:06 +0000  Philippe Kalaf <philippe.kalaf@collabora.co.uk>
+
+	* common:
+	* gst/rtp/gstrtph263pay.c:
+	  Fixed caps for H263 (not the same as H263+)
+	  Original commit message from CVS:
+	  Fixed caps for H263 (not the same as H263+)
+
+2006-05-17 12:36:26 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/law/mulaw-decode.c: We can only do caps intersection if the othercaps are non-empty and not
+	  Original commit message from CVS:
+	  * gst/law/mulaw-decode.c: (mulawdec_getcaps):
+	  We can only do caps intersection if the othercaps are non-empty and not
+	  ANY. Else we return the pad template (base_caps).
+
+2006-05-17 11:20:44 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/jpeg/gstjpegdec.c: Fix crash when outputting debugging information for certain pictures (always good to use the r...
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_chain):
+	  Fix crash when outputting debugging information for certain
+	  pictures (always good to use the right struct member for
+	  the number of records in an array).
+
+2006-05-17 08:10:31 +0000  Jindrich Makovicka <jindrich.makivicka@itonis.tv>
+
+	  gst/matroska/ebml-read.c: Don't create unnecessary sub-buffers all the time. Dramatically improves performance with m...
+	  Original commit message from CVS:
+	  Patch by: Jindrich Makovicka  <jindrich.makivicka at itonis tv>
+	  * gst/matroska/ebml-read.c: (gst_ebml_read_peek_bytes),
+	  (gst_ebml_read_pull_bytes), (gst_ebml_read_element_id),
+	  (gst_ebml_read_element_length), (gst_ebml_read_buffer),
+	  (gst_ebml_read_bytes), (gst_ebml_read_uint), (gst_ebml_read_sint),
+	  (gst_ebml_read_float), (gst_ebml_read_ascii),
+	  (gst_ebml_read_binary):
+	  Don't create unnecessary sub-buffers all the time. Dramatically
+	  improves performance with multiple concurrently running
+	  matroskademux instances (#341818) (and avoids doing
+	  unnecessarily inefficient things in the general case).
+
+2006-05-16 17:20:04 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/libpng/gstpngenc.c: In snapshot mode, we always return GST_FLOW_UNEXPECTED whatever the return value of gst_pad_p...
+	  Original commit message from CVS:
+	  * ext/libpng/gstpngenc.c: (gst_pngenc_chain):
+	  In snapshot mode, we always return GST_FLOW_UNEXPECTED whatever the
+	  return value of gst_pad_push_event().
+
+2006-05-16 14:07:29 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/autodetect/: Make the name of the child element be based on the name of the parent, so that debug output is more ...
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautoaudiosink.c:
+	  (gst_auto_audio_sink_find_best):
+	  * gst/autodetect/gstautovideosink.c:
+	  (gst_auto_video_sink_find_best):
+	  Make the name of the child element be based on the name of the
+	  parent, so that debug output is more useful.
+	  * gst/id3demux/id3v2frames.c: (find_utf16_bom),
+	  (parse_insert_string_field), (parse_split_strings):
+	  Rework string parsing to always walk over BOM markers in UTF16
+	  strings, using the endianness indicated by the innermost one,
+	  then trying the opposite endianness if that fails to convert
+	  to valid UTF-8. Fixes #341774
+
+2006-05-16 13:31:02 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  ext/libpng/Makefile.am: Add LIBPNG_CFLAGS.
+	  Original commit message from CVS:
+	  2006-05-16  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  Patch from: Matthieu <matthieu at fluendo dot com>
+	  * ext/libpng/Makefile.am:
+	  Add LIBPNG_CFLAGS.
+
+2006-05-15 11:20:21 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  update with latest changes
+	  Original commit message from CVS:
+	  update with latest changes
+
+2006-05-15 09:00:42 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/gstid3v2mux.cc: Add support for writing images (APIC frames) into ID3v2 tags (picture type always set to '...
+	  Original commit message from CVS:
+	  * ext/taglib/gstid3v2mux.cc:
+	  Add support for writing images (APIC frames) into ID3v2
+	  tags (picture type always set to 'other' for now though).
+
+2006-05-14 12:50:07 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/wavparse/gstwavparse.c: Update docs; wavparse implements push and pull modes.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c:
+	  Update docs; wavparse implements push and pull modes.
+
+2006-05-12 18:10:36 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: Ooops, bitten by the copy-and-paste design paradigm, fixes seek again.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_index_next),
+	  (gst_avi_demux_parse_index), (gst_avi_demux_massage_index),
+	  (gst_avi_demux_handle_seek), (gst_avi_demux_loop):
+	  Ooops, bitten by the copy-and-paste design paradigm, fixes
+	  seek again.
+
+2006-05-12 18:04:22 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.*: Some cleanups, prepare to use GstSegment.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_reset),
+	  (gst_avi_demux_index_next), (gst_avi_demux_handle_src_query),
+	  (gst_avi_demux_handle_src_event), (gst_avi_demux_parse_subindex),
+	  (gst_avi_demux_parse_stream), (gst_avi_demux_parse_index),
+	  (gst_avi_demux_stream_index), (gst_avi_demux_stream_scan),
+	  (gst_avi_demux_massage_index),
+	  (gst_avi_demux_calculate_durations_from_index),
+	  (gst_avi_demux_push_event), (gst_avi_demux_stream_header),
+	  (gst_avi_demux_handle_seek), (gst_avi_demux_process_next_entry),
+	  (gst_avi_demux_loop):
+	  * gst/avi/gstavidemux.h:
+	  Some cleanups, prepare to use GstSegment.
+	  Fix error in entry walking code.
+	  Fix VBR detection.
+	  Smarter timestamp calculation code.
+	  Uniform error/eos handling.
+
+2006-05-12 17:44:15 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/wavparse/gstwavparse.c: Fix use of uninitialised values if we're NOT seeking in ready.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_fmt),
+	  (gst_wavparse_perform_seek), (gst_wavparse_stream_headers):
+	  Fix use of uninitialised values if we're NOT seeking in ready.
+	  Fix typos.
+
+2006-05-12 08:23:18 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/wavparse/Makefile.am: Add CFLAGS and LIBS for libgstbase, fixes build on
+	  Original commit message from CVS:
+	  * gst/wavparse/Makefile.am:
+	  Add CFLAGS and LIBS for libgstbase, fixes build on
+	  Cygwin (#341489).
+
+2006-05-12 08:21:37 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/id3v2frames.c: Some more debug info. No need to check whether the string returned by g_convert() is real...
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (parse_insert_string_field):
+	  Some more debug info. No need to check whether the string
+	  returned by g_convert() is really UTF-8 - either it is or
+	  we get NULL returned.
+
+2006-05-11 17:59:59 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2colorbalance.c:
+	* sys/v4l2/gstv4l2colorbalance.h:
+	* sys/v4l2/gstv4l2element.c:
+	* sys/v4l2/gstv4l2element.h:
+	* sys/v4l2/gstv4l2object.c:
+	* sys/v4l2/gstv4l2object.h:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/gstv4l2tuner.c:
+	* sys/v4l2/gstv4l2tuner.h:
+	* sys/v4l2/gstv4l2xoverlay.c:
+	* sys/v4l2/gstv4l2xoverlay.h:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2_calls.h:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/v4l2/v4l2src_calls.h:
+	  Changes proposed by Wingo in bug #338818.
+	  Original commit message from CVS:
+	  Changes proposed by Wingo in bug #338818.
+
+2006-05-11 09:09:49 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Figure out the real audio type in mp4a boxes by parsing the optional descriptors in the option...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse), (qtdemux_parse_trak),
+	  (gst_qtdemux_handle_esds):
+	  Figure out the real audio type in mp4a boxes by parsing the
+	  optional descriptors in the optional esds box. Promote the
+	  default AAC to mp3 when indicated. Fixes #330632.
+
+2006-05-10 17:44:50 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Parse version 2 sample descriptions.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse), (qtdemux_dump_unknown),
+	  (qtdemux_parse_trak), (gst_qtdemux_handle_esds):
+	  Parse version 2 sample descriptions.
+	  Don't #define gst_util_dump_mem(), use something more
+	  specific instead to avoid confusion.
+
+2006-05-10 13:51:01 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/id3demux/id3v2frames.c: Fix parsing of numeric genre strings some more, by ensuring that we only try and parse st...
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (id3v2_genre_fields_to_taglist):
+	  Fix parsing of numeric genre strings some more, by ensuring that
+	  we only try and parse strings that a) Start with '(' and b) Consist
+	  only of digits.
+	  Also, when finding an escaping '((' sequence, bust it back to '(' by
+	  swallowing the first parenthesis
+
+2006-05-10 11:17:31 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/esd/esdsink.*: Move the esd_get_server_info() into gst_esdsink_open() and fail with a decent error message on err...
+	  Original commit message from CVS:
+	  * ext/esd/esdsink.c: (gst_esdsink_finalize), (gst_esdsink_getcaps),
+	  (gst_esdsink_open), (gst_esdsink_close):
+	  * ext/esd/esdsink.h:
+	  Move the esd_get_server_info() into gst_esdsink_open() and fail
+	  with a decent error message on errors.
+
+2006-05-10 10:29:54 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Const-ify GEnumValue arrays.
+	  Original commit message from CVS:
+	  * ext/esd/esdmon.c: (gst_esdmon_depths_get_type),
+	  (gst_esdmon_channels_get_type):
+	  * ext/gconf/gstgconfaudiosink.c: (gst_gconf_profile_get_type):
+	  * ext/gdk_pixbuf/pixbufscale.c: (gst_pixbufscale_method_get_type):
+	  * ext/libcaca/gstcacasink.c: (gst_cacasink_dither_get_type):
+	  * ext/shout2/gstshout2.c: (gst_shout2send_protocol_get_type):
+	  * gst/alpha/gstalpha.c: (gst_alpha_method_get_type):
+	  * gst/rtp/gstrtpilbcdepay.c: (gst_ilbc_mode_get_type):
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtsp_proto_get_type):
+	  * gst/videobox/gstvideobox.c: (gst_video_box_fill_get_type):
+	  * gst/videofilter/gstvideoflip.c: (gst_video_flip_method_get_type):
+	  * gst/videomixer/videomixer.c:
+	  (gst_video_mixer_background_get_type):
+	  Const-ify GEnumValue arrays.
+
+2006-05-09 14:08:15 +0000  Mark Nauwelaerts <manauw@skynet.bet>
+
+	  gst/avi/gstavimux.c: Work around gst_buffer_make_metadata_writable() bug that results in avimux marking all frames in...
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts  <manauw at skynet bet>
+	  * gst/avi/gstavimux.c: (gst_avi_mux_do_audio_buffer),
+	  (gst_avi_mux_do_video_buffer):
+	  Work around gst_buffer_make_metadata_writable() bug that
+	  results in avimux marking all frames in the index as
+	  keyframes (#340859).
+
+2006-05-08 19:21:18 +0000  Martin Rubli <martin_rubli@logitech.com>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  Fix fourcc name printed out. Patch from Martin Rubli.
+	  Original commit message from CVS:
+	  Fix fourcc name printed out. Patch from Martin Rubli.
+
+2006-05-08 15:20:10 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Don't cause side effects in a debugging function.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_handle_src_query),
+	  (qtdemux_dump_mvhd):
+	  Don't cause side effects in a debugging function.
+	  Also report duration in push mode since we can.
+
+2006-05-08 14:35:20 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/rtspurl.c: Make parsing of urls suck slightly less.
+	  Original commit message from CVS:
+	  * gst/rtsp/rtspurl.c: (rtsp_url_parse):
+	  Make parsing of urls suck slightly less.
+
+2006-05-08 11:53:03 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  autogen.sh: libtoolize on Darwin/MacOSX is called glibtoolize.
+	  Original commit message from CVS:
+	  * autogen.sh: (CONFIGURE_DEF_OPT):
+	  libtoolize on Darwin/MacOSX is called glibtoolize.
+
+2006-05-08 10:59:05 +0000  Jens Granseuer <jensgr@gmx.net>
+
+	  C89 compliance fixes. Fixes #340980
+	  Original commit message from CVS:
+	  Patch by: Jens Granseuer <jensgr at gmx dot net>
+	  * ext/gdk_pixbuf/pixbufscale.c: (gst_pixbufscale_init):
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_dispose):
+	  C89 compliance fixes. Fixes #340980
+
+2006-05-06 09:01:34 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacdec.*: Handle segment seeks that include the end of the file as stop point properly: when the decoder...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_loop):
+	  * ext/flac/gstflacdec.h:
+	  Handle segment seeks that include the end of the file as stop point
+	  properly: when the decoder hits EOS we want to send a SEGMENT_DONE
+	  message instead of an EOS event in case we're in segment seek
+	  mode (fixes #340699).
+
+2006-05-06 00:14:09 +0000  Maciej Katafiasz <mathrick@mathrick.org>
+
+	* ChangeLog:
+	* ext/cairo/gsttextoverlay.c:
+	* ext/flac/gstflacdec.c:
+	* ext/gdk_pixbuf/pixbufscale.c:
+	* ext/wavpack/gstwavpackdec.c:
+	* gst/apetag/gstapedemux.c:
+	* gst/debug/breakmydata.c:
+	* gst/debug/testplugin.c:
+	* gst/matroska/ebml-write.c:
+	* gst/multipart/multipartdemux.c:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	  Add semicolons after GST_BOILERPLATE[_FULL] so that indent doesn't mess up following lines.
+	  Original commit message from CVS:
+	  Add semicolons after GST_BOILERPLATE[_FULL] so that indent doesn't mess up following lines.
+
+2006-05-05 20:12:59 +0000  Martin Rubli <martin_rubli@logitech.com>
+
+	* sys/v4l2/gstv4l2element.c:
+	* sys/v4l2/gstv4l2element.h:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/gstv4l2tuner.c:
+	* sys/v4l2/gstv4l2tuner.h:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2_calls.h:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/v4l2/v4l2src_calls.h:
+	* tests/icles/v4l2src-test.c:
+	  Some changes proposed by wingo in bug #338818 (but not everything yet). Patch from Martin Rubli to fix framerate dete...
+	  Original commit message from CVS:
+	  Some changes proposed by wingo in bug #338818 (but not everything yet). Patch from Martin Rubli to fix framerate detection.
+
+2006-05-04 17:27:27 +0000  Michal Benes <michal.benes@xeris.cz>
+
+	  gst/matroska/matroska-demux.c: Don't leak caps when freeing the stream context (#340623).
+	  Original commit message from CVS:
+	  Patch by: Michal Benes  <michal dot benes at xeris dot cz>
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_reset):
+	  Don't leak caps when freeing the stream context (#340623).
+
+2006-05-04 15:40:18 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Back to CVS
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Back to CVS
+
+=== release 0.10.3 ===
+
+2006-05-04 15:36:02 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cdio.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* win32/common/config.h:
+	  Really release 0.10.3
+	  Original commit message from CVS:
+	  Really release 0.10.3
+
+2006-05-04 15:28:53 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* docs/plugins/inspect/plugin-qtdemux.xml:
+	  Really release 0.10.3 this time
+	  Original commit message from CVS:
+	  Really release 0.10.3 this time
+
+2006-05-04 15:05:00 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cdio.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-ladspa.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-qtdemux.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	* win32/common/config.h:
+	  Release 0.10.3
+	  Original commit message from CVS:
+	  Release 0.10.3
+
+2006-05-03 18:44:38 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	  Update .po files
+	  Original commit message from CVS:
+	  Update .po files
+
+2006-05-03 18:41:47 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-mux.c: Don't strcmp() NULL strings.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_stream_is_vorbis_header),
+	  (gst_matroska_mux_write_data):
+	  Don't strcmp() NULL strings.
+	  Only start new clusters on video keyframes, not on any
+	  random audio buffer that doesn't have the DELTA_UNIT
+	  flag set (fixes 'make check' again).
+
+2006-05-03 14:51:50 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  gst/matroska/matroska-mux.c: Don't misinterpret GST_CLOCK_TIME_NONE as very high timestamp value and then dead-lock w...
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts  <manauw at skynet be>
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_best_pad),
+	  (gst_matroska_mux_stream_is_vorbis_header),
+	  (gst_matroska_mux_write_data):
+	  Don't misinterpret GST_CLOCK_TIME_NONE as very high timestamp
+	  value and then dead-lock when muxing vorbis audio streams
+	  (the three vorbis header buffers carry no timestamp, and it
+	  would try to mux these after all video buffers). Fixes #340346.
+	  Improve clustering: start a new cluster also whenever we get
+	  a keyframe.
+
+2006-05-03 14:30:21 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/qtdemux/qtdemux.c: Clean up one piece of logic slightly and remove a dead code block.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_trak):
+	  Clean up one piece of logic slightly and remove a
+	  dead code block.
+
+2006-05-03 14:28:57 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  add win32 stuff
+	  Original commit message from CVS:
+	  * Makefile.am:
+	  * configure.ac:
+	  * win32/common/config.h.in:
+	  add win32 stuff
+
+2006-05-03 14:26:51 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  add win32 stuff
+	  Original commit message from CVS:
+	  * Makefile.am:
+	  * configure.ac:
+	  * win32/common/config.h.in:
+	  add win32 stuff
+
+2006-05-02 22:34:52 +0000  Michael Smith <msmith@xiph.org>
+
+	  ext/cairo/gsttimeoverlay.c: Fix timeoverlay for non-multiple-of-4 widths. This fourcc crap
+	  Original commit message from CVS:
+	  * ext/cairo/gsttimeoverlay.c: (gst_cairo_time_overlay_transform):
+	  Fix timeoverlay for non-multiple-of-4 widths. This fourcc crap
+	  SUCKS.
+
+2006-05-02 21:52:48 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2src.c:
+	  Fix get_caps func to work when no framerate is available and the caps isn't simple.
+	  Original commit message from CVS:
+	  Fix get_caps func to work when no framerate is available and the caps isn't simple.
+
+2006-05-02 18:50:23 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/: don't leak caps-string
+	  Original commit message from CVS:
+	  * gst/alpha/gstalphacolor.c: (gst_alpha_color_transform_caps):
+	  * gst/debug/negotiation.c: (gst_negotiation_update_caps):
+	  * gst/rtp/gstrtpilbcdepay.c: (gst_rtp_ilbc_depay_setcaps):
+	  don't leak caps-string
+
+2006-05-02 15:46:02 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/gstid3demux.c: Let core insert default error message for TYPE_NOT_FOUND errors, it's just as good as our...
+	  Original commit message from CVS:
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_chain),
+	  (gst_id3demux_sink_activate):
+	  Let core insert default error message for TYPE_NOT_FOUND
+	  errors, it's just as good as our own and has the added
+	  bonus of being translated.
+
+2006-05-02 15:40:15 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/: Post an error message when we get an EOS event and were not able to find out the type of stream.
+	  Original commit message from CVS:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_init),
+	  (gst_tag_demux_sink_event):
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_init),
+	  (gst_id3demux_sink_event):
+	  Post an error message when we get an EOS event and were not
+	  able to find out the type of stream.
+	  * tests/check/elements/id3v2mux.c: (fill_mp3_buffer), (got_buffer),
+	  (test_taglib_id3mux_with_tags):
+	  Decrease num-buffers to 16 per iteration again, otherwise the
+	  many memcpy()s and reallocations in the test will hammer slow
+	  CPUs completely and make the test timeout.
+
+2006-05-02 13:24:38 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  configure.ac: figure out where plugins-base plugins are
+	  Original commit message from CVS:
+	  * configure.ac:
+	  figure out where plugins-base plugins are
+	  * tests/check/Makefile.am:
+	  use plugins-base plugins, so we have typefind functions
+	  * tests/check/elements/id3v2mux.c: (test_taglib_id3mux_with_tags):
+	  increase num-buffers, this makes sure the test errors out instead
+	  of timing out when no typefind functions are present
+
+2006-05-02 13:01:50 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/wavparse/gstwavparse.c:
+	  fix docs for wavparse
+	  Original commit message from CVS:
+	  fix docs for wavparse
+
+2006-05-01 21:37:51 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2colorbalance.c:
+	* sys/v4l2/gstv4l2xoverlay.c:
+	* sys/v4l2/v4l2_calls.c:
+	* tests/icles/v4l2src-test.c:
+	  Few improvements to move to good.
+	  Original commit message from CVS:
+	  Few improvements to move to good.
+
+2006-05-01 11:46:33 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  docs/plugins/Makefile.am: also check .cc files for gtk-doc markup
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  also check .cc files for gtk-doc markup
+	  * configure.ac:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/id3v2mux.c: (id3v2mux_suite), (main):
+	  * ext/Makefile.am:
+	  * ext/taglib/Makefile.am:
+	  * ext/taglib/gstid3v2mux.h:
+	  * ext/taglib/gsttaglibmux.c:
+	  * ext/taglib/gsttaglibmux.h:
+	  move taglib-based id3v2muxer to -good.  Fixes #336110.
+
+2006-05-01 11:45:15 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/plugins/inspect/plugin-icydemux.xml:
+	  add icydemux inspection
+	  Original commit message from CVS:
+	  add icydemux inspection
+
+2006-05-01 11:43:31 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* po/POTFILES.in:
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	  add ximagesrc for translation
+	  Original commit message from CVS:
+	  add ximagesrc for translation
+
+2006-04-30 16:16:59 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/taglib/gstid3v2mux.cc:
+	* ext/taglib/gsttaglibmux.c:
+	  small cleanups
+	  Original commit message from CVS:
+	  small cleanups
+
+2006-04-30 15:32:13 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/taglib/gstid3v2mux.cc:
+	  fix docs
+	  Original commit message from CVS:
+	  fix docs
+
+2006-04-30 14:55:15 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/plugins/inspect/plugin-qtdemux.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	  update to latest version
+	  Original commit message from CVS:
+	  update to latest version
+
+2006-04-29 18:46:36 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/gsttaglib.cc: Post an error message on the bus in the (extremely unlikely) case of an error.
+	  Original commit message from CVS:
+	  * ext/taglib/gsttaglib.cc:
+	  Post an error message on the bus in the (extremely unlikely)
+	  case of an error.
+
+2006-04-29 18:18:24 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/: Split the actual ID3v2 tag rendering code into its own subclass.
+	  Original commit message from CVS:
+	  * ext/taglib/Makefile.am:
+	  * ext/taglib/gstid3v2mux.cc:
+	  * ext/taglib/gstid3v2mux.h:
+	  * ext/taglib/gsttaglib.cc:
+	  * ext/taglib/gsttaglib.h:
+	  Split the actual ID3v2 tag rendering code into
+	  its own subclass.
+
+2006-04-29 16:14:20 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/wavparse/gstwavparse.c: ... and fix multichannel/WAVFORMATEX support again.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_stream_headers):
+	  ... and fix multichannel/WAVFORMATEX support again.
+
+2006-04-28 23:09:17 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/wavparse/gstwavparse.*: Add push (streaming) mode to wavparse (fixes #337625)
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_base_init),
+	  (gst_wavparse_class_init), (gst_wavparse_dispose),
+	  (gst_wavparse_reset), (gst_wavparse_init),
+	  (gst_wavparse_create_sourcepad), (gst_wavparse_parse_adtl),
+	  (gst_wavparse_parse_cues), (gst_wavparse_parse_file_header),
+	  (gst_wavparse_stream_init), (gst_wavparse_perform_seek),
+	  (gst_wavparse_peek_chunk_info), (gst_wavparse_peek_chunk),
+	  (gst_wavparse_stream_headers), (gst_wavparse_parse_stream_init),
+	  (gst_wavparse_send_event), (gst_wavparse_add_src_pad),
+	  (gst_wavparse_stream_data), (gst_wavparse_loop),
+	  (gst_wavparse_chain), (gst_wavparse_srcpad_event),
+	  (gst_wavparse_sink_activate), (gst_wavparse_sink_activate_pull),
+	  (gst_wavparse_change_state), (plugin_init):
+	  * gst/wavparse/gstwavparse.h:
+	  Add push (streaming) mode to wavparse (fixes #337625)
+
+2006-04-28 21:43:07 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* tests/check/elements/id3v2mux.c:
+	  element renamed
+	  Original commit message from CVS:
+	  element renamed
+
+2006-04-28 19:22:46 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/plugins/inspect/plugin-ximagesrc.xml:
+	  add plugin docs for ximagesrc
+	  Original commit message from CVS:
+	  add plugin docs for ximagesrc
+
+2006-04-28 19:15:08 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  add ximagesrc icles test
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * tests/Makefile.am:
+	  add ximagesrc icles test
+
+2006-04-28 18:57:09 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  Move ximagesrc plug-in to good after review.  Fixes #336756.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * ext/annodex/gstcmmlenc.c: (gst_cmml_enc_class_init),
+	  (gst_cmml_enc_push_clip):
+	  * sys/Makefile.am:
+	  * sys/ximage/Makefile.am:
+	  * sys/ximage/gstximagesrc.c:
+	  Move ximagesrc plug-in to good after review.  Fixes #336756.
+
+2006-04-28 16:51:33 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* sys/ximage/gstximagesrc.c:
+	* sys/ximage/gstximagesrc.h:
+	  borgify naming
+	  Original commit message from CVS:
+	  borgify naming
+
+2006-04-28 16:46:52 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* sys/ximage/gstximagesrc.c:
+	  doc tweaks
+	  Original commit message from CVS:
+	  doc tweaks
+
+2006-04-28 16:15:20 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* sys/ximage/Makefile.am:
+	* sys/ximage/gstximagesrc.c:
+	  clean up Makefile.am
+	  Original commit message from CVS:
+	  clean up Makefile.am
+
+2006-04-28 15:33:09 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/taglib/gsttaglibmux.c:
+	* ext/taglib/gsttaglibmux.h:
+	  pedantic cleanups
+	  Original commit message from CVS:
+	  pedantic cleanups
+
+2006-04-28 14:57:57 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/icydemux/gsticydemux.*: Fix event handling: cache events when typefinding and forward later.
+	  Original commit message from CVS:
+	  * gst/icydemux/gsticydemux.c: (gst_icydemux_reset),         (gst_icydemux_init), (gst_icydemux_sink_setcaps),
+	  (gst_icydemux_add_srcpad), (gst_icydemux_parse_and_send_tags),
+	  (gst_icydemux_handle_event), (gst_icydemux_send_cached_events),
+	  (gst_icydemux_typefind_or_forward), (gst_icydemux_add_meta),
+	  (gst_icydemux_chain), (gst_icydemux_send_tag_event):
+	  * gst/icydemux/gsticydemux.h:
+	  Fix event handling: cache events when typefinding and forward later.
+
+2006-04-28 14:55:20 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  sys/osxaudio/gstosxaudiosink.c: Register osxaudiosrc to the plugin.
+	  Original commit message from CVS:
+	  2006-04-28  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * sys/osxaudio/gstosxaudiosink.c:
+	  (plugin_init):
+	  Register osxaudiosrc to the plugin.
+	  * sys/osxaudio/gstosxaudiosrc.c:
+	  (gst_osx_audio_src_osxelement_do_init),
+	  (gst_osx_audio_src_base_init), (gst_osx_audio_src_class_init),
+	  (gst_osx_audio_src_init), (gst_osx_audio_src_set_property),
+	  (gst_osx_audio_src_get_property),
+	  (gst_osx_audio_src_create_ringbuffer), (gst_osx_audio_src_io_proc),
+	  (gst_osx_audio_src_osxelement_init):
+	  * sys/osxaudio/gstosxaudiosrc.h:
+	  Port of osxaudiosrc to 0.10.
+	  * sys/osxaudio/Makefile.am:
+	  Add osxaudiosrc
+
+2006-04-28 12:00:39 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* ChangeLog:
+	  commit Changelog for previous commit
+	  Original commit message from CVS:
+	  commit Changelog for previous commit
+
+2006-04-28 11:57:39 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* sys/osxaudio/gstosxringbuffer.c:
+	* sys/osxaudio/gstosxringbuffer.h:
+	  Forgot to commit, quick commit be4 apple dies
+	  Original commit message from CVS:
+	  Forgot to commit, quick commit be4 apple dies
+
+2006-04-28 11:37:22 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/id3v2frames.c: Recognise and skip any byte order marker (BOM) in
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (has_utf16_bom),
+	  (parse_split_strings):
+	  Recognise and skip any byte order marker (BOM) in
+	  UTF-16 strings.
+
+2006-04-27 16:05:54 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Add docs for both avidemux and avimux.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * docs/plugins/inspect/plugin-avi.xml:
+	  * gst/avi/gstavidemux.c:
+	  * gst/avi/gstavimux.c:
+	  Add docs for both avidemux and avimux.
+
+2006-04-27 14:51:06 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  gst/avi/: Port AVI muxer to GStreamer-0.10 (#332031).
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts  <manauw at skynet dot be>
+	  * gst/avi/Makefile.am:
+	  * gst/avi/gstavi.c: (plugin_init):
+	  * gst/avi/gstavimux.c: (gst_avi_mux_get_type),
+	  (gst_avi_mux_base_init), (gst_avi_mux_finalize),
+	  (gst_avi_mux_class_init), (gst_avi_mux_init),
+	  (gst_avi_mux_vidsink_set_caps), (gst_avi_mux_audsink_set_caps),
+	  (gst_avi_mux_pad_link), (gst_avi_mux_pad_unlink),
+	  (gst_avi_mux_request_new_pad), (gst_avi_mux_release_pad),
+	  (gst_avi_mux_write_tag), (gst_avi_mux_riff_get_avi_header),
+	  (gst_avi_mux_riff_get_avix_header),
+	  (gst_avi_mux_riff_get_video_header),
+	  (gst_avi_mux_riff_get_audio_header), (gst_avi_mux_add_index),
+	  (gst_avi_mux_write_index), (gst_avi_mux_bigfile),
+	  (gst_avi_mux_start_file), (gst_avi_mux_stop_file),
+	  (gst_avi_mux_restart_file), (gst_avi_mux_handle_event),
+	  (gst_avi_mux_fill_queue), (gst_avi_mux_send_pad_data),
+	  (gst_avi_mux_strip_buffer), (gst_avi_mux_do_audio_buffer),
+	  (gst_avi_mux_do_video_buffer), (gst_avi_mux_do_one_buffer),
+	  (gst_avi_mux_loop), (gst_avi_mux_collect_pads),
+	  (gst_avi_mux_get_property), (gst_avi_mux_set_property),
+	  (gst_avi_mux_change_state):
+	  * gst/avi/gstavimux.h:
+	  Port AVI muxer to GStreamer-0.10 (#332031).
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/avimux.c:
+	  * tests/check/elements/.cvsignore:
+	  Add unit test for AVI muxer.
+
+2006-04-26 21:29:45 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/wavparse/gstwavparse.*: reverted patch #337625 for the price of 1 hour sleep
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_base_init),
+	  (gst_wavparse_class_init), (gst_wavparse_reset),
+	  (gst_wavparse_init), (gst_wavparse_create_sourcepad),
+	  (gst_wavparse_parse_file_header), (gst_wavparse_stream_init),
+	  (gst_wavparse_perform_seek), (gst_wavparse_stream_headers),
+	  (gst_wavparse_send_event), (gst_wavparse_add_src_pad),
+	  (gst_wavparse_stream_data), (gst_wavparse_loop),
+	  (gst_wavparse_srcpad_event), (gst_wavparse_sink_activate),
+	  (gst_wavparse_sink_activate_pull), (gst_wavparse_change_state),
+	  (plugin_init):
+	  * gst/wavparse/gstwavparse.h:
+	  reverted patch #337625 for the price of 1 hour sleep
+
+2006-04-26 20:11:18 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/wavparse/gstwavparse.*: correct partial implementation of push mode (from my last commit)
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_base_init),
+	  (gst_wavparse_class_init), (gst_wavparse_reset),
+	  (gst_wavparse_init), (gst_wavparse_create_sourcepad),
+	  (gst_wavparse_parse_adtl), (gst_wavparse_parse_cues),
+	  (gst_wavparse_parse_file_header), (gst_wavparse_stream_init),
+	  (gst_wavparse_perform_seek), (gst_wavparse_stream_headers),
+	  (gst_wavparse_stream_data), (gst_wavparse_loop),
+	  (gst_wavparse_chain), (plugin_init):
+	  * gst/wavparse/gstwavparse.h:
+	  correct partial implementation of push mode
+	  (from my last commit)
+
+2006-04-26 17:37:10 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/esd/esdsink.c: Fix compile problem by defining ESD_MAX_WRITE_SIZE if it is not in esd.h
+	  Original commit message from CVS:
+	  * ext/esd/esdsink.c:
+	  Fix compile problem by defining ESD_MAX_WRITE_SIZE if
+	  it is not in esd.h
+
+2006-04-26 17:08:24 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/auparse/gstauparse.*: Rewrite auparse to suck a little bit less: make source pad dynamic, so decodebin/playbin wo...
+	  Original commit message from CVS:
+	  * gst/auparse/gstauparse.c: (gst_au_parse_base_init),
+	  (gst_au_parse_class_init), (gst_au_parse_init),
+	  (gst_au_parse_reset), (gst_au_parse_add_srcpad),
+	  (gst_au_parse_remove_srcpad), (gst_au_parse_parse_header),
+	  (gst_au_parse_chain), (gst_au_parse_src_convert),
+	  (gst_au_parse_src_query), (gst_au_parse_handle_seek),
+	  (gst_au_parse_sink_event), (gst_au_parse_src_event),
+	  (gst_au_parse_change_state):
+	  * gst/auparse/gstauparse.h:
+	  Rewrite auparse to suck a little bit less: make source pad
+	  dynamic, so decodebin/playbin work with non-raw formats
+	  like alaw/mulaw; add query function for duration/position
+	  queries; check whether we have enough data before attempting
+	  to parse the header (instead of crashing when that is not the
+	  case); work around audioconvert sucking by swapping endianness
+	  to the native endianness ourselves for float formats; send
+	  initial newsegment event. Fixes #161712.
+
+2006-04-26 16:29:38 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  sys/osxaudio/: Port of osxaudiosink to 0.10
+	  Original commit message from CVS:
+	  2006-04-26  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * sys/osxaudio/Makefile.am:
+	  * sys/osxaudio/gstosxaudioelement.c:
+	  (gst_osx_audio_element_get_type),
+	  (gst_osx_audio_element_class_init):
+	  * sys/osxaudio/gstosxaudioelement.h:
+	  * sys/osxaudio/gstosxaudiosink.c:
+	  (gst_osx_audio_sink_osxelement_do_init),
+	  (gst_osx_audio_sink_base_init), (gst_osx_audio_sink_class_init),
+	  (gst_osx_audio_sink_init), (gst_osx_audio_sink_set_property),
+	  (gst_osx_audio_sink_get_property), (gst_osx_audio_sink_getcaps),
+	  (gst_osx_audio_sink_create_ringbuffer),
+	  (gst_osx_audio_sink_io_proc), (gst_osx_audio_sink_osxelement_init),
+	  (plugin_init):
+	  * sys/osxaudio/gstosxaudiosink.h:
+	  Port of osxaudiosink to 0.10
+
+2006-04-26 08:55:27 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/esd/esdsink.c: Always write ESD_BUF_SIZE bytes and use ESD_MAX_WRITE_SIZE as the size of the ringbuffer. This sho...
+	  Original commit message from CVS:
+	  * ext/esd/esdsink.c: (gst_esdsink_prepare), (gst_esdsink_delay):
+	  Always write ESD_BUF_SIZE bytes and use ESD_MAX_WRITE_SIZE as
+	  the size of the ringbuffer. This should fix hangs with older
+	  esd sound servers.
+
+2006-04-25 21:56:38 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Define GstElementDetails as const and also static (when defined as global)
+	  Original commit message from CVS:
+	  * ext/amrwb/gstamrwbdec.c:
+	  * ext/amrwb/gstamrwbenc.c:
+	  * ext/amrwb/gstamrwbparse.c:
+	  * ext/arts/gst_arts.c:
+	  * ext/artsd/gstartsdsink.c:
+	  * ext/audiofile/gstafparse.c:
+	  * ext/audiofile/gstafsink.c:
+	  * ext/audiofile/gstafsrc.c:
+	  * ext/audioresample/gstaudioresample.c:
+	  * ext/bz2/gstbz2dec.c:
+	  * ext/bz2/gstbz2enc.c:
+	  * ext/cdaudio/gstcdaudio.c:
+	  * ext/directfb/dfbvideosink.c:
+	  * ext/divx/gstdivxdec.c:
+	  * ext/divx/gstdivxenc.c:
+	  * ext/dts/gstdtsdec.c: (gst_dtsdec_base_init):
+	  * ext/faac/gstfaac.c: (gst_faac_base_init):
+	  * ext/faad/gstfaad.c:
+	  * ext/gsm/gstgsmdec.c:
+	  * ext/gsm/gstgsmenc.c:
+	  * ext/hermes/gsthermescolorspace.c:
+	  * ext/ivorbis/vorbisfile.c:
+	  * ext/lcs/gstcolorspace.c:
+	  * ext/libfame/gstlibfame.c:
+	  * ext/libmms/gstmms.c: (gst_mms_base_init):
+	  * ext/musepack/gstmusepackdec.c: (gst_musepackdec_base_init):
+	  * ext/musicbrainz/gsttrm.c: (gst_musicbrainz_base_init):
+	  * ext/nas/nassink.c: (gst_nassink_base_init):
+	  * ext/neon/gstneonhttpsrc.c:
+	  * ext/sdl/sdlaudiosink.c:
+	  * ext/sdl/sdlvideosink.c:
+	  * ext/shout/gstshout.c:
+	  * ext/snapshot/gstsnapshot.c:
+	  * ext/sndfile/gstsf.c:
+	  * ext/swfdec/gstswfdec.c:
+	  * ext/tarkin/gsttarkindec.c:
+	  * ext/tarkin/gsttarkinenc.c:
+	  * ext/theora/theoradec.c:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_base_init):
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_base_init):
+	  * ext/xvid/gstxviddec.c:
+	  * ext/xvid/gstxvidenc.c:
+	  * gst/cdxaparse/gstcdxaparse.c: (gst_cdxa_parse_base_init):
+	  * gst/cdxaparse/gstcdxastrip.c: (gst_cdxastrip_base_init):
+	  * gst/chart/gstchart.c:
+	  * gst/colorspace/gstcolorspace.c:
+	  * gst/deinterlace/gstdeinterlace.c:
+	  * gst/equalizer/gstiirequalizer.c: (gst_iir_equalizer_base_init):
+	  * gst/festival/gstfestival.c:
+	  * gst/filter/gstbpwsinc.c:
+	  * gst/filter/gstiir.c:
+	  * gst/filter/gstlpwsinc.c:
+	  * gst/freeze/gstfreeze.c:
+	  * gst/games/gstpuzzle.c: (gst_puzzle_base_init):
+	  * gst/librfb/gstrfbsrc.c:
+	  * gst/mixmatrix/mixmatrix.c:
+	  * gst/mpeg1sys/gstmpeg1systemencode.c:
+	  * gst/mpeg1videoparse/gstmp1videoparse.c:
+	  * gst/mpeg2sub/gstmpeg2subt.c:
+	  * gst/mpegaudioparse/gstmpegaudioparse.c:
+	  * gst/multifilesink/gstmultifilesink.c:
+	  * gst/overlay/gstoverlay.c:
+	  * gst/passthrough/gstpassthrough.c:
+	  * gst/playondemand/gstplayondemand.c:
+	  * gst/qtdemux/qtdemux.c:
+	  * gst/rtjpeg/gstrtjpegdec.c:
+	  * gst/rtjpeg/gstrtjpegenc.c:
+	  * gst/smooth/gstsmooth.c:
+	  * gst/smoothwave/gstsmoothwave.c:
+	  * gst/spectrum/gstspectrum.c:
+	  * gst/speed/gstspeed.c:
+	  * gst/stereo/gststereo.c:
+	  * gst/switch/gstswitch.c:
+	  * gst/tta/gstttadec.c: (gst_tta_dec_base_init):
+	  * gst/tta/gstttaparse.c: (gst_tta_parse_base_init):
+	  * gst/vbidec/gstvbidec.c:
+	  * gst/videocrop/gstvideocrop.c:
+	  * gst/videodrop/gstvideodrop.c:
+	  * gst/virtualdub/gstxsharpen.c:
+	  * gst/xingheader/gstxingmux.c: (gst_xing_mux_base_init):
+	  * gst/y4m/gsty4mencode.c:
+	  * sys/cdrom/gstcdplayer.c:
+	  * sys/directdraw/gstdirectdrawsink.c:
+	  * sys/directsound/gstdirectsoundsink.c:
+	  * sys/glsink/glimagesink.c:
+	  * sys/qcam/gstqcamsrc.c:
+	  * sys/v4l2/gstv4l2src.c:
+	  * sys/vcd/vcdsrc.c: (gst_vcdsrc_base_init):
+	  * sys/ximagesrc/ximagesrc.c:
+	  Define GstElementDetails as const and also static (when defined as
+	  global)
+
+2006-04-25 21:39:46 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Define GstElementDetails as const and also static (when defined as global)
+	  Original commit message from CVS:
+	  * ext/aalib/gstaasink.c:
+	  * ext/annodex/gstcmmldec.c:
+	  * ext/annodex/gstcmmlenc.c:
+	  * ext/cairo/gsttextoverlay.c:
+	  * ext/cairo/gsttimeoverlay.c:
+	  * ext/cdio/gstcdiocddasrc.c:
+	  * ext/dv/gstdvdec.c:
+	  * ext/dv/gstdvdemux.c:
+	  * ext/esd/esdmon.c:
+	  * ext/esd/esdsink.c:
+	  * ext/flac/gstflacenc.c:
+	  * ext/flac/gstflactag.c:
+	  * ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_base_init):
+	  * ext/gconf/gstgconfaudiosrc.c: (gst_gconf_audio_src_base_init):
+	  * ext/gconf/gstgconfvideosink.c: (gst_gconf_video_sink_base_init):
+	  * ext/gconf/gstgconfvideosrc.c: (gst_gconf_video_src_base_init):
+	  * ext/gdk_pixbuf/pixbufscale.c:
+	  * ext/hal/gsthalaudiosink.c: (gst_hal_audio_sink_base_init):
+	  * ext/hal/gsthalaudiosrc.c: (gst_hal_audio_src_base_init):
+	  * ext/jpeg/gstjpegdec.c:
+	  * ext/jpeg/gstjpegenc.c:
+	  * ext/jpeg/gstsmokedec.c:
+	  * ext/jpeg/gstsmokeenc.c:
+	  * ext/libcaca/gstcacasink.c:
+	  * ext/libmng/gstmngdec.c:
+	  * ext/libmng/gstmngenc.c:
+	  * ext/libpng/gstpngdec.c:
+	  * ext/libpng/gstpngenc.c:
+	  * ext/mikmod/gstmikmod.c:
+	  * ext/raw1394/gstdv1394src.c:
+	  * ext/shout2/gstshout2.c: (gst_shout2send_init):
+	  * ext/shout2/gstshout2.h:
+	  * ext/speex/gstspeexdec.c:
+	  * ext/speex/gstspeexenc.c:
+	  * gst/alpha/gstalpha.c:
+	  * gst/alpha/gstalphacolor.c:
+	  * gst/apetag/gstapedemux.c:
+	  * gst/auparse/gstauparse.c:
+	  * gst/autodetect/gstautoaudiosink.c:
+	  (gst_auto_audio_sink_base_init):
+	  * gst/autodetect/gstautovideosink.c:
+	  (gst_auto_video_sink_base_init):
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_base_init):
+	  * gst/avi/gstavimux.c: (gst_avimux_base_init):
+	  * gst/cutter/gstcutter.c:
+	  * gst/debug/breakmydata.c:
+	  * gst/debug/efence.c:
+	  * gst/debug/gstnavigationtest.c:
+	  * gst/debug/gstnavseek.c:
+	  * gst/debug/negotiation.c:
+	  * gst/debug/progressreport.c:
+	  * gst/debug/testplugin.c:
+	  * gst/effectv/gstaging.c:
+	  * gst/effectv/gstdice.c:
+	  * gst/effectv/gstedge.c:
+	  * gst/effectv/gstquark.c:
+	  * gst/effectv/gstrev.c:
+	  * gst/effectv/gstshagadelic.c:
+	  * gst/effectv/gstvertigo.c:
+	  * gst/effectv/gstwarp.c:
+	  * gst/flx/gstflxdec.c:
+	  * gst/goom/gstgoom.c:
+	  * gst/icydemux/gsticydemux.c:
+	  * gst/id3demux/gstid3demux.c:
+	  * gst/interleave/deinterleave.c:
+	  * gst/interleave/interleave.c:
+	  * gst/law/alaw-decode.c: (gst_alawdec_base_init):
+	  * gst/law/alaw-encode.c: (gst_alawenc_base_init):
+	  * gst/law/mulaw-decode.c: (gst_mulawdec_base_init):
+	  * gst/law/mulaw-encode.c: (gst_mulawenc_base_init):
+	  * gst/level/gstlevel.c:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_base_init):
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_base_init):
+	  * gst/median/gstmedian.c:
+	  * gst/monoscope/gstmonoscope.c:
+	  * gst/multipart/multipartdemux.c:
+	  * gst/multipart/multipartmux.c:
+	  * gst/oldcore/gstaggregator.c:
+	  * gst/oldcore/gstfdsink.c:
+	  * gst/oldcore/gstmd5sink.c:
+	  * gst/oldcore/gstmultifilesrc.c:
+	  * gst/oldcore/gstpipefilter.c:
+	  * gst/oldcore/gstshaper.c:
+	  * gst/oldcore/gststatistics.c:
+	  * gst/rtp/gstasteriskh263.c:
+	  * gst/rtp/gstrtpL16depay.c:
+	  * gst/rtp/gstrtpL16pay.c:
+	  * gst/rtp/gstrtpamrdepay.c:
+	  * gst/rtp/gstrtpamrpay.c:
+	  * gst/rtp/gstrtpdepay.c:
+	  * gst/rtp/gstrtpgsmpay.c:
+	  * gst/rtp/gstrtph263pay.c:
+	  * gst/rtp/gstrtph263pdepay.c:
+	  * gst/rtp/gstrtph263ppay.c:
+	  * gst/rtp/gstrtpilbcdepay.c:
+	  * gst/rtp/gstrtpmp4gpay.c:
+	  * gst/rtp/gstrtpmp4vdepay.c:
+	  * gst/rtp/gstrtpmp4vpay.c:
+	  * gst/rtp/gstrtpmpadepay.c:
+	  * gst/rtp/gstrtpmpapay.c:
+	  * gst/rtp/gstrtppcmadepay.c:
+	  * gst/rtp/gstrtppcmapay.c:
+	  * gst/rtp/gstrtppcmudepay.c:
+	  * gst/rtp/gstrtppcmupay.c:
+	  * gst/rtp/gstrtpspeexdepay.c:
+	  * gst/rtp/gstrtpspeexpay.c:
+	  * gst/rtsp/gstrtpdec.c:
+	  * gst/rtsp/gstrtspsrc.c:
+	  * gst/smpte/gstsmpte.c:
+	  * gst/udp/gstdynudpsink.c:
+	  * gst/udp/gstmultiudpsink.c:
+	  * gst/udp/gstudpsink.c:
+	  * gst/udp/gstudpsrc.c:
+	  * gst/videobox/gstvideobox.c:
+	  * gst/videofilter/gstgamma.c: (gst_gamma_base_init):
+	  * gst/videofilter/gstvideobalance.c:
+	  * gst/videofilter/gstvideoflip.c:
+	  * gst/videofilter/gstvideotemplate.c:
+	  (gst_videotemplate_base_init):
+	  * gst/videomixer/videomixer.c:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_base_init),
+	  (gst_wavparse_class_init), (gst_wavparse_dispose),
+	  (gst_wavparse_reset), (gst_wavparse_init),
+	  (gst_wavparse_perform_seek), (gst_wavparse_peek_chunk_info),
+	  (gst_wavparse_peek_chunk), (gst_wavparse_stream_headers),
+	  (gst_wavparse_parse_stream_init), (gst_wavparse_send_event),
+	  (gst_wavparse_add_src_pad), (gst_wavparse_stream_data),
+	  (gst_wavparse_chain), (gst_wavparse_srcpad_event),
+	  (gst_wavparse_sink_activate), (gst_wavparse_sink_activate_pull),
+	  (gst_wavparse_change_state):
+	  * gst/wavparse/gstwavparse.h:
+	  * sys/oss/gstossmixerelement.c:
+	  * sys/oss/gstosssink.c:
+	  * sys/oss/gstosssrc.c:
+	  * sys/osxaudio/gstosxaudioelement.c:
+	  * sys/osxaudio/gstosxaudiosink.c:
+	  * sys/osxaudio/gstosxaudiosrc.c:
+	  * sys/sunaudio/gstsunaudiomixer.c:
+	  * sys/sunaudio/gstsunaudiosink.c:
+	  Define GstElementDetails as const and also static (when defined as
+	  global)
+
+2006-04-25 17:57:23 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/jpeg/gstjpegdec.c: Source pad has fixed caps. If we don't set this, bad things happen when the window is resized.
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_chain):
+	  Source pad has fixed caps. If we don't set this, bad
+	  things happen when the window is resized.
+
+2006-04-25 16:38:50 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/: Handle case where the TrackType ebml chunk does not come before the
+	  Original commit message from CVS:
+	  * gst/matroska/Makefile.am:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream),
+	  (gst_matroska_demux_handle_src_event):
+	  * gst/matroska/matroska-ids.c:
+	  (gst_matroska_track_init_video_context),
+	  (gst_matroska_track_init_audio_context),
+	  (gst_matroska_track_init_subtitle_context),
+	  (gst_matroska_track_init_complex_context):
+	  * gst/matroska/matroska-ids.h:
+	  Handle case where the TrackType ebml chunk does not come before the
+	  TrackInfoAudio or TrackInfoVideo ebml chunk (#339446). Ignore QoS
+	  events.
+
+2006-04-25 16:09:55 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: It's codec_data, not codec_info.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4gpay.c: (gst_rtp_mp4g_pay_setcaps):
+	  * gst/rtp/gstrtpmp4vpay.c: (gst_rtp_mp4v_pay_setcaps):
+	  It's codec_data, not codec_info.
+
+2006-04-25 11:45:00 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  gst/matroska/matroska-demux.c: Handle codec_data for VfW compatibility codec IDs (#339451)
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts  <manauw at skynet dot be>
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_video_caps):
+	  Handle codec_data for VfW compatibility codec IDs (#339451)
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_video_pad_setcaps):
+	  Same here, handle codec_data and add additional caps we can handle
+	  now to the pad template (huffyuv, dv and h263 video) (#339451)
+
+2006-04-25 11:09:24 +0000  Josef Zlomek <josef.zlomek@itonis.tv>
+
+	  gst/matroska/matroska-mux.c: Fix timestamping of B-frames, use signed integers, do some rounding (#339678).
+	  Original commit message from CVS:
+	  Patch by: Josef Zlomek  <josef dot zlomek at itonis dot tv>
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_create_buffer_header),
+	  (gst_matroska_mux_write_data):
+	  Fix timestamping of B-frames, use signed integers, do
+	  some rounding (#339678).
+
+2006-04-24 18:30:55 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* ext/annodex/gstcmmlparser.c:
+	  just make it compile with --disable-gst-debug.
+	  Original commit message from CVS:
+	  just make it compile with --disable-gst-debug.
+
+2006-04-23 15:55:30 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  gst/matroska/matroska-demux.c: Fix a bad conversion using gst_guint64_to_gdouble. fabs ((gdouble) demux->index[entry]...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroskademux_do_index_seek):
+	  Fix a bad conversion using gst_guint64_to_gdouble.
+	  fabs ((gdouble) demux->index[entry].time - (gdouble) seek_pos) can not be
+	  replaced by fabs (gst_guint64_to_gdouble (demux->index[entry].time - seek_pos)) as the
+	  difference could be negative. fabs (gst_guint64_to_gdouble (demux->index[entry].time) -
+	  gst_guint64_to_gdouble (seek_pos)) is the good solution. Thanks to Tim who has seen my
+	  mistake.
+
+2006-04-22 15:32:48 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  gst/matroska/matroska-demux.c: Use gst_guint64_to_gdouble for conversions
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroskademux_do_index_seek):
+	  Use gst_guint64_to_gdouble for conversions
+	  * win32/vs6/gst_plugins_good.dsw:
+	  * win32/vs6/libgsticydemux.dsp:
+	  Add a project file for icydemux
+
+2006-04-21 18:07:10 +0000  Fabrizio Gennari <fabrizio.ge@tiscali.it>
+
+	  gst/avi/gstavidemux.c: When splitting audio chunks, the block alignment is not taken in consideration, so the smaller...
+	  Original commit message from CVS:
+	  Patch by: Fabrizio Gennari <fabrizio dot ge at tiscali dot it>
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_parse_index), (gst_avi_demux_massage_index):
+	  When splitting audio chunks, the block alignment is not taken in
+	  consideration, so the smaller chunks could be of size which is
+	  not a multiple of the block alignment. Fixes #336904
+
+2006-04-21 17:59:03 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/raw1394/gstdv1394src.c: Use scale functions
+	  Original commit message from CVS:
+	  * ext/raw1394/gstdv1394src.c: (gst_dv1394src_convert):
+	  Use scale functions
+
+2006-04-21 17:27:40 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/dv/gstdv.c: Fix build.
+	  Original commit message from CVS:
+	  * ext/dv/gstdv.c: (plugin_init):
+	  Fix build.
+
+2006-04-21 17:15:29 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/debug/progressreport.c: Add 'format' property to force querying to a particular format.
+	  Original commit message from CVS:
+	  * gst/debug/progressreport.c: (gst_progress_report_finalize),
+	  (gst_progress_report_class_init), (gst_progress_report_init),
+	  (gst_progress_report_do_query), (gst_progress_report_report),
+	  (gst_progress_report_set_property),
+	  (gst_progress_report_get_property):
+	  Add 'format' property to force querying to a particular format.
+
+2006-04-21 15:50:28 +0000  Andy Wingo <wingo@pobox.com>
+
+	  ext/dv/gstdv.c (plugin_init): libdv is a marginal decoder, at best, on big endian systems. Drop its rank in that case...
+	  Original commit message from CVS:
+	  2006-04-21  Andy Wingo  <wingo@pobox.com>
+	  * ext/dv/gstdv.c (plugin_init): libdv is a marginal decoder, at
+	  best, on big endian systems. Drop its rank in that case. OTOH on
+	  x86 it's quite fine. See changes from today in gst-ffmpeg as well.
+
+2006-04-21 09:27:11 +0000  Michael Smith <msmith@xiph.org>
+
+	  Add icydemux, and tests.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/icydemux/Makefile.am:
+	  * gst/icydemux/gsticydemux.c: (gst_icydemux_get_type),
+	  (gst_icydemux_base_init), (gst_icydemux_class_init),
+	  (gst_icydemux_reset), (gst_icydemux_init),
+	  (gst_icydemux_sink_setcaps), (gst_icydemux_dispose),
+	  (gst_icydemux_add_srcpad), (gst_icydemux_remove_srcpad),
+	  (unicodify), (gst_icydemux_unicodify),
+	  (gst_icydemux_parse_and_send_tags),
+	  (gst_icydemux_typefind_or_forward), (gst_icydemux_add_meta),
+	  (gst_icydemux_chain), (gst_icydemux_change_state),
+	  (gst_icydemux_send_tag_event), (plugin_init):
+	  * gst/icydemux/gsticydemux.h:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/icydemux.c: (typefind_succeed),
+	  (plugin_init), (icydemux_found_pad), (create_icydemux),
+	  (cleanup_icydemux), (push_data), (GST_START_TEST),
+	  (icydemux_suite), (main):
+	  Add icydemux, and tests.
+
+2006-04-20 17:48:29 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacdec.c: Post SEGMENT_DONE message in TIME format.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_loop):
+	  Post SEGMENT_DONE message in TIME format.
+
+2006-04-20 17:29:56 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2src.c:
+	  Added a couple of ifdefs to make it compile with other kernels.
+	  Original commit message from CVS:
+	  Added a couple of ifdefs to make it compile with other kernels.
+
+2006-04-20 16:33:55 +0000  Fabrizio Gennari <fabrizio.ge@tiscali.it>
+
+	  gst/avi/gstavidemux.c: Fix index creation when we have to scan the file to create an index. There may be other types ...
+	  Original commit message from CVS:
+	  Patch by: Fabrizio Gennari  <fabrizio dot ge at tiscali dot it>
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_peek_tag),
+	  (gst_avi_demux_next_data_buffer), (gst_avi_demux_stream_scan):
+	  Fix index creation when we have to scan the file to create
+	  an index. There may be other types of RIFF 'LIST' chunks than
+	  'movi' and we need to skip them properly as well or we'll end up
+	  reading garbage (#336889). Some other cosmetic changes.
+
+2006-04-20 14:21:42 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacdec.c: Add support for segment seeks (fixes #338290). Also demote some recurring debug message from D...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_loop),
+	  (gst_flac_dec_handle_seek_event):
+	  Add support for segment seeks (fixes #338290). Also demote
+	  some recurring debug message from DEBUG to LOG level.
+
+2006-04-20 13:23:40 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/: Set DISCONT flag on first buffer after a discontinuity.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream),
+	  (gst_matroskademux_do_index_seek),
+	  (gst_matroska_demux_handle_seek_event),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock):
+	  * gst/matroska/matroska-ids.h:
+	  Set DISCONT flag on first buffer after a discontinuity.
+	  Fix newsegment events sent when seeking and honour KEY_UNIT
+	  seek flag. Create pad with bogus caps if we don't recognise
+	  the stream codec id.
+	  * gst/matroska/matroska-demux.h:
+	  Fix GObject macros.
+
+2006-04-20 11:00:16 +0000  Mark Nauwelaerts <manauw@skynet.be>
+
+	  gst/matroska/matroska-demux.c: Handle end of segment properly when set; don't dead-lock when posting start of segment...
+	  Original commit message from CVS:
+	  Patch by: Mark Nauwelaerts  <manauw at skynet dot be>
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_handle_seek_event), (gst_matroska_demux_loop):
+	  Handle end of segment properly when set; don't dead-lock when
+	  posting start of segment message when doing a segment seek.
+	  Fixes #338810.
+
+2006-04-20 09:48:05 +0000  j^ <j@bootlab.org>
+
+	  gst/qtdemux/qtdemux.c: Never treat video streams as an audio stream.
+	  Original commit message from CVS:
+	  Patch by: j^ <j at bootlab dot org>
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_trak),
+	  (qtdemux_video_caps):
+	  Never treat video streams as an audio stream.
+	  Add qtdrw mime type.
+	  Fixes #339041
+
+2006-04-20 09:11:22 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-demux.c: Make mpeg2 aac audio work: create artificial private codec data chunk which faad2 seem...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_audio_caps),
+	  (gst_matroska_demux_plugin_init):
+	  Make mpeg2 aac audio work: create artificial private codec data
+	  chunk which faad2 seems to require, just as we do for mpeg4 aac.
+	  Also call gst_riff_init(). Partially fixes #338767.
+
+2006-04-19 15:16:33 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/wavenc/gstwavenc.*: Set caps on first outgoing buffer, so that it doesn't error out immediately with a non-negoti...
+	  Original commit message from CVS:
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_base_init),
+	  (gst_wavenc_class_init), (gst_wavenc_init),
+	  (gst_wavenc_create_header_buf), (gst_wavenc_push_header),
+	  (gst_wavenc_sink_setcaps), (get_id_from_name), (gst_wavenc_event),
+	  (gst_wavenc_chain), (gst_wavenc_change_state):
+	  * gst/wavenc/gstwavenc.h:
+	  Set caps on first outgoing buffer, so that it doesn't error out
+	  immediately with a non-negotiated error (#338716). Rewrite and
+	  clean up a bit; fix setcaps function to parse things properly;
+	  fix sink caps (8bit audio is unsigned and doesn't have depth);
+	  use boilerplate macros; remove unused properties stuff.
+
+2006-04-19 09:27:00 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: For VBR audio, don't try to calculate the samples_per_frame.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_trak):
+	  For VBR audio, don't try to calculate the samples_per_frame.
+	  Fixes #338935.
+
+2006-04-18 18:14:34 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/gdk_pixbuf/gstgdkpixbuf.c: Leave JPEG decoding to our jpegdec plugin. gdkpixbufdec cannot handle MJPEG streams an...
+	  Original commit message from CVS:
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c:
+	  Leave JPEG decoding to our jpegdec plugin. gdkpixbufdec cannot
+	  handle MJPEG streams and might be autoplugged for those if the
+	  user doesn't have jpegdec installed (resulting in a cryptic error
+	  message about huffman tables). Better to disable JPEG decoding here
+	  and let the user figure out that she needs to install jpegdec.
+
+2006-04-18 18:04:48 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/gdk_pixbuf/gstgdkpixbuf.*: Make work with packetised/framed input (e.g. png-in-quicktime). Use
+	  Original commit message from CVS:
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_sink_setcaps),
+	  (gst_gdk_pixbuf_class_init), (gst_gdk_pixbuf_init),
+	  (gst_gdk_pixbuf_flush), (gst_gdk_pixbuf_chain):
+	  * ext/gdk_pixbuf/gstgdkpixbuf.h:
+	  Make work with packetised/framed input (e.g. png-in-quicktime). Use
+	  GST_ELEMENT_ERROR when we return GST_FLOW_ERROR. Add some
+	  GST_DEBUG_FUNCPTR here and there. Use GST_LOG for recurring
+	  debug messages. Fix boilerplate macros.
+
+2006-04-18 17:29:42 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/gdk_pixbuf/gstgdkpixbuf.c: No need to special-case for Gdk-2.0 any longer, we require
+	  Original commit message from CVS:
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_get_capslist),
+	  (gst_gdk_pixbuf_set_property), (gst_gdk_pixbuf_get_property):
+	  No need to special-case for Gdk-2.0 any longer, we require
+	  Gdk 2.2 or newer; minor clean-ups.
+
+2006-04-18 17:17:55 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Rewrite a bit: use GstBaseSink::start and stop instead of a state change function; use GST_ELEMENT_ERROR for error re...
+	  Original commit message from CVS:
+	  * ext/shout2/gstshout2.c: (gst_shout2send_base_init),
+	  (gst_shout2send_class_init), (gst_shout2send_init),
+	  (set_shout_metadata), (gst_shout2send_set_metadata),
+	  (gst_shout2send_event), (gst_shout2send_start),
+	  (gst_shout2send_connect), (gst_shout2send_stop),
+	  (gst_shout2send_render), (gst_shout2send_set_property),
+	  (gst_shout2send_get_property), (gst_shout2send_setcaps),
+	  (plugin_init):
+	  * ext/shout2/gstshout2.h:
+	  * po/POTFILES.in:
+	  Rewrite a bit: use GstBaseSink::start and stop instead of a state
+	  change function; use GST_ELEMENT_ERROR for error reporting, not
+	  g_error() or GST_ERROR(); don't unref caps in setcaps function,
+	  will cause crashes or assertion failures; remove (unused) "sync"
+	  property, basesink already has such a property; misc. other
+	  minor fixes and cleanups.
+
+2006-04-18 14:15:33 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Add translatable error message for when we cannot connect to the sound server, as "Cannot open resource for writing" ...
+	  Original commit message from CVS:
+	  * ext/esd/esdsink.c: (gst_esdsink_open), (gst_esdsink_prepare):
+	  * ext/esd/gstesd.c: (plugin_init):
+	  * po/POTFILES.in:
+	  Add translatable error message for when we cannot
+	  connect to the sound server, as "Cannot open resource
+	  for writing" isn't really an acceptable message to show
+	  to the user in this case.
+
+2006-04-18 13:32:29 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/oss/gst-i18n-plugin.h: Remove bogus file that doesn't belong here.
+	  Original commit message from CVS:
+	  * sys/oss/gst-i18n-plugin.h:
+	  Remove bogus file that doesn't belong here.
+
+2006-04-17 19:57:10 +0000  Philippe Valembois <lephilousophe@users.sf.net>
+
+	  ext/shout2/gstshout2.*: Handle tags being received before the connection to the server is established properly (see #...
+	  Original commit message from CVS:
+	  Patch by: Philippe Valembois
+	  * ext/shout2/gstshout2.c: (gst_shout2send_init),
+	  (gst_shout2send_set_metadata), (gst_shout2send_event),
+	  (gst_shout2send_render), (gst_shout2send_change_state):
+	  * ext/shout2/gstshout2.h:
+	  Handle tags being received before the connection to
+	  the server is established properly (see #338636).
+
+2006-04-17 19:43:32 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2src.c:
+	  Just added a gtk-doc comment.
+	  Original commit message from CVS:
+	  Just added a gtk-doc comment.
+
+2006-04-17 19:12:36 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/shout2/gstshout2.c: Don't crash in case the connection to the server fails: don't set pointer to NULL by assignin...
+	  Original commit message from CVS:
+	  * ext/shout2/gstshout2.c: (gst_shout2send_render):
+	  Don't crash in case the connection to the server fails:
+	  don't set pointer to NULL by assigning FALSE; error out
+	  properly by using GST_ELEMENT_ERROR and returning
+	  GST_FLOW_ERROR (fixes #338636). Lastly, free connection
+	  before resetting the pointer.
+
+2006-04-17 10:01:51 +0000  Alex Lancaster <alexlan@fedoraproject.org>
+
+	  gst/id3demux/id3tags.c: (Fixes #338713)
+	  Original commit message from CVS:
+	  * gst/id3demux/id3tags.c:
+	  Recognise TCO (Genre) tags in ID3v2.2. Patch by Alex Lancaster
+	  (Fixes #338713)
+
+2006-04-13 21:45:57 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/v4l2src_calls.c:
+	  Fixed some memory leaks.
+	  Original commit message from CVS:
+	  Fixed some memory leaks.
+
+2006-04-13 09:15:31 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstasteriskh263.h:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpL16depay.h:
+	* gst/rtp/gstrtpL16pay.h:
+	* gst/rtp/gstrtpamrdepay.h:
+	* gst/rtp/gstrtpamrpay.h:
+	* gst/rtp/gstrtpdepay.h:
+	* gst/rtp/gstrtpgsmdepay.h:
+	* gst/rtp/gstrtpgsmpay.h:
+	* gst/rtp/gstrtph263pay.h:
+	* gst/rtp/gstrtph263pdepay.h:
+	* gst/rtp/gstrtph263ppay.h:
+	* gst/rtp/gstrtpmp4gpay.h:
+	* gst/rtp/gstrtpmp4vdepay.h:
+	* gst/rtp/gstrtpmp4vpay.h:
+	* gst/rtp/gstrtpmpadepay.h:
+	* gst/rtp/gstrtpmpapay.h:
+	* gst/rtp/gstrtppcmadepay.h:
+	* gst/rtp/gstrtppcmapay.c:
+	* gst/rtp/gstrtppcmapay.h:
+	* gst/rtp/gstrtppcmudepay.h:
+	* gst/rtp/gstrtppcmupay.c:
+	* gst/rtp/gstrtppcmupay.h:
+	* gst/rtp/gstrtpspeexdepay.h:
+	* gst/rtp/gstrtpspeexpay.h:
+	  reverting rtp patches to fix freeze break on -base as explained on the list
+	  Original commit message from CVS:
+	  reverting rtp patches to fix freeze break on -base as explained on the list
+
+2006-04-13 09:01:17 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/rtp/: Fix GObject macros.
+	  Original commit message from CVS:
+	  * gst/rtp/gstasteriskh263.h:
+	  * gst/rtp/gstrtpL16depay.h:
+	  * gst/rtp/gstrtpL16pay.h:
+	  * gst/rtp/gstrtpamrdepay.h:
+	  * gst/rtp/gstrtpamrpay.h:
+	  * gst/rtp/gstrtpdepay.h:
+	  * gst/rtp/gstrtpgsmdepay.h:
+	  * gst/rtp/gstrtpgsmpay.h:
+	  * gst/rtp/gstrtph263pay.h:
+	  * gst/rtp/gstrtph263pdepay.h:
+	  * gst/rtp/gstrtph263ppay.h:
+	  * gst/rtp/gstrtpilbcdepay.h:
+	  * gst/rtp/gstrtpilbcpay.h:
+	  * gst/rtp/gstrtpmp4gpay.h:
+	  * gst/rtp/gstrtpmp4vdepay.h:
+	  * gst/rtp/gstrtpmp4vpay.h:
+	  * gst/rtp/gstrtpmpadepay.h:
+	  * gst/rtp/gstrtpmpapay.h:
+	  * gst/rtp/gstrtppcmadepay.h:
+	  * gst/rtp/gstrtppcmapay.h:
+	  * gst/rtp/gstrtppcmudepay.h:
+	  * gst/rtp/gstrtppcmupay.h:
+	  * gst/rtp/gstrtpspeexdepay.h:
+	  * gst/rtp/gstrtpspeexpay.h:
+	  Fix GObject macros.
+
+2006-04-13 03:42:51 +0000  Philippe Kalaf <philippe.kalaf@collabora.co.uk>
+
+	  gst/rtp/: Ported mulaw and alaw payloaders to use new base class
+	  Original commit message from CVS:
+	  2006-04-12 Philippe Kalaf <philippe.kalaf@collabora.co.uk>
+	  * gst/rtp/gstrtppcmapay.c:
+	  * gst/rtp/gstrtppcmapay.h:
+	  * gst/rtp/gstrtppcmupay.c:
+	  * gst/rtp/gstrtppcmupay.h:
+	  Ported mulaw and alaw payloaders to use new base class
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c:
+	  * gst/rtp/gstrtpilbcpay.c:
+	  * gst/rtp/gstrtpilbcpay.h:
+	  * gst/rtp/gstrtpilbcdepay.c:
+	  * gst/rtp/gstrtpilbcdepay.h:
+	  Added new iLBC payloader/depayloader. Payloader uses new audio payload base
+	  class.
+
+2006-04-12 21:57:02 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/gstv4l2src.c:
+	  Fix to work in read mode.
+	  Original commit message from CVS:
+	  Fix to work in read mode.
+
+2006-04-12 09:42:10 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/gdk_pixbuf/gstgdkpixbuf.c: Some cleanups.
+	  Original commit message from CVS:
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_sink_setcaps),
+	  (gst_gdk_pixbuf_get_capslist), (gst_gdk_pixbuf_sink_getcaps),
+	  (gst_gdk_pixbuf_class_init), (gst_gdk_pixbuf_init),
+	  (gst_gdk_pixbuf_flush), (gst_gdk_pixbuf_sink_event),
+	  (gst_gdk_pixbuf_chain):
+	  Some cleanups.
+	  Added RGBA as a possible output format.
+	  Correctly free the supported mimetypes.
+	  deprecate silent arg, it's not used.
+	  Return result from _alloc_buffer to peer.
+
+2006-04-11 18:03:36 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/rtp/gstrtpmp4vdepay.c: Don't leak memory allocated by gst_buffer_new_and_alloc() by overwriting GST_BUFFER_MALLOC...
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4vdepay.c: (gst_rtp_mp4v_depay_process):
+	  Don't leak memory allocated by gst_buffer_new_and_alloc() by
+	  overwriting GST_BUFFER_MALLOCDATA.
+
+2006-04-11 15:27:31 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  fix version number macro
+	  Original commit message from CVS:
+	  fix version number macro
+
+2006-04-11 09:35:45 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/libpng/gstpngdec.*: Handle more than one frame if the content is framed, like with png-in-quicktime (#331917).
+	  Original commit message from CVS:
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_init),
+	  (user_endrow_callback), (user_end_callback),
+	  (gst_pngdec_caps_create_and_set), (gst_pngdec_chain),
+	  (gst_pngdec_sink_setcaps), (gst_pngdec_sink_event),
+	  (gst_pngdec_libpng_clear), (gst_pngdec_change_state):
+	  * ext/libpng/gstpngdec.h:
+	  Handle more than one frame if the content is framed,
+	  like with png-in-quicktime (#331917).
+
+2006-04-10 19:55:31 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  sys/oss/: - the user-visible error strings were in the wrong category
+	  Original commit message from CVS:
+	  * sys/oss/Makefile.am:
+	  * sys/oss/common.h:
+	  * sys/oss/gstosssink.c: (gst_oss_sink_init), (gst_oss_sink_open),
+	  (gst_oss_sink_prepare), (gst_oss_sink_unprepare):
+	  * sys/oss/gstosssrc.c: (gst_oss_src_prepare),
+	  (gst_oss_src_unprepare):
+	  - the user-visible error strings were in the wrong category
+	  - and the messages were not marked for translation
+	  - which is actually a good thing, because they were exactly
+	  the kind of message you would never want anyone to see
+	  - the macros were using variables that didn't exist in the macro
+	  arguments
+	  - and they were obviously copied from each other and then modified
+	  - so a common header makes sense
+
+2006-04-10 17:16:09 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Fix parsing of newer stsd chunks again.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_trak):
+	  Fix parsing of newer stsd chunks again.
+
+2006-04-10 16:09:03 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/ebml-read.c: Don't try to modify read-only data.
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-read.c: (gst_ebml_read_sint):
+	  Don't try to modify read-only data.
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock):
+	  Fix comment (won't crash any longer now).
+
+2006-04-10 15:48:55 +0000  Michael Smith <msmith@xiph.org>
+
+	  ext/annodex/gstcmmlenc.c: Use copies of header buffers for caps to avoid circular refcounting problems (as in theorad...
+	  Original commit message from CVS:
+	  * ext/annodex/gstcmmlenc.c: (gst_cmml_enc_set_header_on_caps):
+	  Use copies of header buffers for caps to avoid circular refcounting
+	  problems (as in theoradec, vorbisdec).
+	  * tests/check/elements/cmmldec.c: (GST_START_TEST):
+	  Fix a typo in test that meant it was testing the wrong thing.
+	  * tests/check/elements/cmmlenc.c: (check_headers):
+	  Fix refcount checks now that we use buffer-copies for caps.
+
+2006-04-10 15:43:54 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-demux.c: Use static pad templates with ANY caps for audio and video source pads and get rid of ...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_base_init),
+	  (gst_matroska_demux_handle_seek_event),
+	  (gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps),
+	  (gst_matroska_demux_subtitle_caps),
+	  (gst_matroska_demux_plugin_init):
+	  Use static pad templates with ANY caps for audio and video
+	  source pads and get rid of a lot of unnecessary (and partially
+	  broken) code for the template caps. Clean up caps finding
+	  functions. Fixes playback of audio files/streams that do not
+	  contain the sample rate and/or number of channels in the audio
+	  context (happens a lot with vorbis/mp3 .mka files it seems).
+	  Fixes #337183.
+	  Also add myself to copyright holders.
+
+2006-04-10 15:29:21 +0000  Michael Smith <msmith@xiph.org>
+
+	  ext/annodex/gstcmmlutils.c: Use g_list_delete_link () instead of g_list_remove_link () so that we free the link as we...
+	  Original commit message from CVS:
+	  * ext/annodex/gstcmmlutils.c: (gst_cmml_track_list_del_clip):
+	  Use g_list_delete_link () instead of g_list_remove_link () so that
+	  we free the link as well as the contained data.
+
+2006-04-10 14:20:41 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Fix framerate calculation.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_add_stream),
+	  (qtdemux_parse_trak):
+	  Fix framerate calculation.
+
+2006-04-10 10:10:55 +0000  Ryan Lortie (desrt) <desrt@destr.ca>
+
+	  gst/avi/gstavidemux.c: Fix some crashers with empty chunks. (Fixes #337749)
+	  Original commit message from CVS:
+	  Patch by: Ryan Lortie (desrt) <desrt at destr dot ca>
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_superindex),
+	  (gst_avi_demux_parse_stream), (gst_avi_demux_parse_index),
+	  (gst_avi_demux_stream_header):
+	  Fix some crashers with empty chunks. (Fixes #337749)
+
+2006-04-10 08:31:40 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: force mono 8000 Hz on AMR samples.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_trak):
+	  force mono 8000 Hz on AMR samples.
+
+2006-04-09 18:30:51 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  ext/neon/gstneonhttpsrc.c: remove atoll by using g_ascii_strtoull (atoll is not supported on WIN32)
+	  Original commit message from CVS:
+	  * ext/neon/gstneonhttpsrc.c: (gst_neonhttp_src_start):
+	  remove atoll by using g_ascii_strtoull (atoll is not supported on WIN32)
+	  * sys/directdraw/gstdirectdrawsink.c:
+	  * sys/directsound/gstdirectsoundsink.c:
+	  done some cleans in sources
+	  * win32/vs6:
+	  add project files for neon, qtdemux
+
+2006-04-09 17:31:37 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  gst/level/gstlevel.c: use G_GINT64_CONSTANT for INT64 constants
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c: (gst_level_set_caps),(gst_level_transform_ip):
+	  use G_GINT64_CONSTANT for INT64 constants
+	  * gst/videofilter/gstvideobalance.c:
+	  define rint for WIN32 #define rint(x) (floor((x)+0.5))
+	  * win32/vs6/libgstavi.dsp:
+	  add missing libraries for the link and remove avimux.c from
+	  the project as it isn't ported to 0.10 yet
+
+2006-04-09 14:00:32 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/ebml-read.c: Even better would be if we actually did the right thing here (also, G_GUINT64_CONSTANT only...
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-read.c: (gst_ebml_read_sint):
+	  Even better would be if we actually did the right thing
+	  here (also, G_GUINT64_CONSTANT only exists since GLib-2.10).
+
+2006-04-09 13:52:03 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/ebml-read.c: Can't just replace 1LL with 1L here just because MSVC doesn't support it, as it might lead ...
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-read.c: (gst_ebml_read_sint):
+	  Can't just replace 1LL with 1L here just because MSVC doesn't
+	  support it, as it might lead to incorrect results when doing the
+	  bitshifting here. Using GLib's G_GUINT64_CONSTANT() macro to
+	  force a 64-bit constant in a way that all compilers are happy with.
+
+2006-04-08 21:48:01 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Fix #337365 (g_type_class_ref <-> g_type_class_peek_parent)
+	  Original commit message from CVS:
+	  * ext/amrwb/gstamrwbdec.c: (gst_amrwbdec_class_init):
+	  * ext/amrwb/gstamrwbenc.c: (gst_amrwbenc_class_init):
+	  * ext/amrwb/gstamrwbparse.c: (gst_amrwbparse_class_init):
+	  * ext/arts/gst_arts.c: (gst_arts_class_init):
+	  * ext/artsd/gstartsdsink.c: (gst_artsdsink_class_init):
+	  * ext/audiofile/gstafsink.c: (gst_afsink_class_init):
+	  * ext/audiofile/gstafsrc.c: (gst_afsrc_class_init):
+	  * ext/audioresample/gstaudioresample.c:
+	  * ext/cdaudio/gstcdaudio.c: (gst_cdaudio_class_init):
+	  * ext/directfb/dfbvideosink.c: (gst_dfbvideosink_class_init):
+	  * ext/divx/gstdivxdec.c: (gst_divxdec_class_init):
+	  * ext/hermes/gsthermescolorspace.c:
+	  (gst_hermes_colorspace_class_init):
+	  * ext/ivorbis/vorbisfile.c: (gst_ivorbisfile_class_init):
+	  * ext/jack/gstjack.c: (gst_jack_class_init):
+	  * ext/jack/gstjackbin.c: (gst_jack_bin_class_init):
+	  * ext/lcs/gstcolorspace.c: (gst_colorspace_class_init):
+	  * ext/libfame/gstlibfame.c: (gst_fameenc_class_init):
+	  * ext/musicbrainz/gsttrm.c: (gst_musicbrainz_class_init):
+	  * ext/nas/nassink.c: (gst_nassink_class_init):
+	  * ext/shout/gstshout.c: (gst_icecastsend_class_init):
+	  * ext/snapshot/gstsnapshot.c: (gst_snapshot_class_init):
+	  * ext/sndfile/gstsf.c: (gst_sf_class_init):
+	  * ext/swfdec/gstswfdec.c: (gst_swfdecbuffer_class_init),
+	  (gst_swfdec_class_init):
+	  * ext/tarkin/gsttarkindec.c: (gst_tarkindec_class_init):
+	  * ext/tarkin/gsttarkinenc.c: (gst_tarkinenc_class_init):
+	  * gst/cdxaparse/gstcdxastrip.c: (gst_cdxastrip_class_init):
+	  * gst/chart/gstchart.c: (gst_chart_class_init):
+	  * gst/colorspace/gstcolorspace.c: (gst_colorspace_class_init):
+	  * gst/deinterlace/gstdeinterlace.c: (gst_deinterlace_class_init):
+	  * gst/festival/gstfestival.c: (gst_festival_class_init):
+	  * gst/filter/gstbpwsinc.c: (gst_bpwsinc_class_init):
+	  * gst/filter/gstiir.c: (gst_iir_class_init):
+	  * gst/filter/gstlpwsinc.c: (gst_lpwsinc_class_init):
+	  * gst/librfb/gstrfbsrc.c: (gst_rfbsrc_class_init):
+	  * gst/mixmatrix/mixmatrix.c: (gst_mixmatrix_class_init):
+	  * gst/mpeg1sys/gstmpeg1systemencode.c:
+	  (gst_system_encode_class_init):
+	  * gst/mpeg1videoparse/gstmp1videoparse.c:
+	  (gst_mp1videoparse_class_init):
+	  * gst/mpeg2sub/gstmpeg2subt.c: (gst_mpeg2subt_class_init):
+	  * gst/mpegaudioparse/gstmpegaudioparse.c:
+	  (gst_mp3parse_class_init):
+	  * gst/overlay/gstoverlay.c: (gst_overlay_class_init):
+	  * gst/passthrough/gstpassthrough.c: (passthrough_class_init):
+	  * gst/playondemand/gstplayondemand.c: (play_on_demand_class_init):
+	  * gst/rtjpeg/gstrtjpegdec.c: (gst_rtjpegdec_class_init):
+	  * gst/rtjpeg/gstrtjpegenc.c: (gst_rtjpegenc_class_init):
+	  * gst/smooth/gstsmooth.c: (gst_smooth_class_init):
+	  * gst/smoothwave/gstsmoothwave.c: (gst_smoothwave_class_init):
+	  * gst/spectrum/gstspectrum.c: (gst_spectrum_class_init):
+	  * gst/stereo/gststereo.c: (gst_stereo_class_init):
+	  * gst/switch/gstswitch.c: (gst_switch_class_init):
+	  * gst/tta/gstttadec.c: (gst_tta_dec_class_init):
+	  * gst/tta/gstttaparse.c: (gst_tta_parse_class_init):
+	  * gst/vbidec/gstvbidec.c: (gst_vbidec_class_init):
+	  * gst/videocrop/gstvideocrop.c: (gst_video_crop_class_init):
+	  * gst/virtualdub/gstxsharpen.c: (gst_xsharpen_class_init):
+	  * gst/y4m/gsty4mencode.c: (gst_y4mencode_class_init):
+	  * sys/cdrom/gstcdplayer.c: (cdplayer_class_init):
+	  * sys/directsound/gstdirectsoundsink.c:
+	  (gst_directsoundsink_class_init):
+	  * sys/dxr3/dxr3audiosink.c: (dxr3audiosink_class_init):
+	  * sys/dxr3/dxr3spusink.c: (dxr3spusink_class_init):
+	  * sys/dxr3/dxr3videosink.c: (dxr3videosink_class_init):
+	  * sys/qcam/gstqcamsrc.c: (gst_qcamsrc_class_init):
+	  * sys/v4l2/gstv4l2colorbalance.c:
+	  (gst_v4l2_color_balance_channel_class_init):
+	  * sys/v4l2/gstv4l2tuner.c: (gst_v4l2_tuner_channel_class_init),
+	  (gst_v4l2_tuner_norm_class_init):
+	  * sys/ximagesrc/ximagesrc.c: (gst_ximagesrc_class_init):
+	  Fix #337365 (g_type_class_ref <-> g_type_class_peek_parent)
+
+2006-04-08 21:21:45 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Fix #337365 (g_type_class_ref <-> g_type_class_peek_parent)
+	  Original commit message from CVS:
+	  * ext/aalib/gstaasink.c: (gst_aasink_class_init):
+	  * ext/esd/esdsink.c: (gst_esdsink_class_init):
+	  * ext/flac/gstflactag.c: (gst_flac_tag_class_init):
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_class_init):
+	  * ext/jpeg/gstjpegenc.c: (gst_jpegenc_class_init):
+	  * ext/jpeg/gstsmokedec.c: (gst_smokedec_class_init):
+	  * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_class_init):
+	  * ext/libcaca/gstcacasink.c: (gst_cacasink_class_init):
+	  * ext/libmng/gstmngdec.c: (gst_mngdec_class_init):
+	  * ext/libmng/gstmngenc.c: (gst_mngenc_class_init):
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_class_init):
+	  * ext/libpng/gstpngenc.c: (gst_pngenc_class_init):
+	  * ext/mikmod/gstmikmod.c: (gst_mikmod_class_init):
+	  * ext/shout2/gstshout2.c: (gst_shout2send_class_init):
+	  * ext/speex/gstspeexenc.c: (gst_speexenc_class_init):
+	  * gst/alpha/gstalpha.c: (gst_alpha_class_init):
+	  * gst/avi/gstavimux.c: (gst_avimux_class_init):
+	  * gst/debug/efence.c: (gst_efence_class_init):
+	  * gst/debug/negotiation.c: (gst_negotiation_class_init):
+	  * gst/flx/gstflxdec.c: (gst_flxdec_class_init):
+	  * gst/goom/gstgoom.c: (gst_goom_class_init):
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_class_init):
+	  * gst/interleave/deinterleave.c: (deinterleave_class_init):
+	  * gst/interleave/interleave.c: (interleave_class_init):
+	  * gst/law/alaw-decode.c: (gst_alawdec_class_init):
+	  * gst/law/alaw-encode.c: (gst_alawenc_class_init):
+	  * gst/law/mulaw-encode.c: (gst_mulawenc_class_init):
+	  * gst/median/gstmedian.c: (gst_median_class_init):
+	  * gst/monoscope/gstmonoscope.c: (gst_monoscope_class_init):
+	  * gst/multipart/multipartmux.c: (gst_multipart_mux_class_init):
+	  * gst/rtp/gstasteriskh263.c: (gst_asteriskh263_class_init):
+	  * gst/rtp/gstrtpL16depay.c: (gst_rtp_L16depay_class_init):
+	  * gst/rtp/gstrtpL16pay.c: (gst_rtpL16pay_class_init):
+	  * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_class_init):
+	  * gst/rtp/gstrtpamrpay.c: (gst_rtp_amr_pay_class_init):
+	  * gst/rtp/gstrtpdepay.c: (gst_rtp_depay_class_init):
+	  * gst/rtp/gstrtpgsmdepay.c: (gst_rtp_gsm_depay_class_init):
+	  * gst/rtp/gstrtpgsmpay.c: (gst_rtp_gsm_pay_class_init):
+	  * gst/rtp/gstrtph263pay.c: (gst_rtp_h263_pay_class_init):
+	  * gst/rtp/gstrtph263pdepay.c: (gst_rtp_h263p_depay_class_init):
+	  * gst/rtp/gstrtph263ppay.c: (gst_rtp_h263p_pay_class_init):
+	  * gst/rtp/gstrtpmp4gpay.c: (gst_rtp_mp4g_pay_class_init):
+	  * gst/rtp/gstrtpmp4vdepay.c: (gst_rtp_mp4v_depay_class_init):
+	  * gst/rtp/gstrtpmp4vpay.c: (gst_rtp_mp4v_pay_class_init):
+	  * gst/rtp/gstrtpmpadepay.c: (gst_rtp_mpa_depay_class_init):
+	  * gst/rtp/gstrtpmpapay.c: (gst_rtp_mpa_pay_class_init):
+	  * gst/rtp/gstrtppcmadepay.c: (gst_rtp_pcma_depay_class_init):
+	  * gst/rtp/gstrtppcmapay.c: (gst_rtp_pcma_pay_class_init):
+	  * gst/rtp/gstrtppcmudepay.c: (gst_rtp_pcmu_depay_class_init):
+	  * gst/rtp/gstrtppcmupay.c: (gst_rtp_pcmu_pay_class_init):
+	  * gst/rtp/gstrtpspeexdepay.c: (gst_rtp_speex_depay_class_init):
+	  * gst/rtp/gstrtpspeexpay.c: (gst_rtp_speex_pay_class_init):
+	  * gst/rtsp/gstrtpdec.c: (gst_rtpdec_class_init):
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_class_init):
+	  * gst/smpte/gstsmpte.c: (gst_smpte_class_init):
+	  * gst/udp/gstdynudpsink.c: (gst_dynudpsink_class_init):
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_class_init):
+	  * gst/udp/gstudpsink.c: (gst_udpsink_class_init):
+	  * gst/videomixer/videomixer.c: (gst_videomixer_class_init):
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_class_init):
+	  * sys/oss/gstossdmabuffer.c: (gst_ossdmabuffer_class_init):
+	  * sys/oss/gstosssink.c: (gst_oss_sink_class_init):
+	  * sys/osxaudio/gstosxaudioelement.c:
+	  (gst_osxaudioelement_class_init):
+	  * sys/osxaudio/gstosxaudiosink.c: (gst_osxaudiosink_class_init):
+	  * sys/osxaudio/gstosxaudiosrc.c: (gst_osxaudiosrc_class_init):
+	  * sys/sunaudio/gstsunaudiosink.c: (gst_sunaudiosink_class_init):
+	  Fix #337365 (g_type_class_ref <-> g_type_class_peek_parent)
+
+2006-04-08 19:06:25 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Fix more broken GObject macros
+	  Original commit message from CVS:
+	  * ext/mikmod/gstmikmod.h:
+	  * gst/level/gstlevel.h:
+	  Fix more broken GObject macros
+
+2006-04-08 18:41:07 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Fix broken GObject macros
+	  Original commit message from CVS:
+	  * ext/xine/gstxine.h:
+	  * gst-libs/gst/play/play.h:
+	  * sys/v4l2/gstv4l2element.h:
+	  * sys/ximagesrc/ximageutil.h:
+	  Fix broken GObject macros
+
+2006-04-08 18:25:55 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  Fix broken GObject macros
+	  Original commit message from CVS:
+	  * ext/annodex/gstcmmldec.h:
+	  * ext/annodex/gstcmmlenc.h:
+	  * ext/annodex/gstcmmltag.h:
+	  * ext/cairo/gsttextoverlay.h:
+	  * ext/ladspa/gstsignalprocessor.h:
+	  * gst/matroska/ebml-read.h:
+	  * gst/matroska/ebml-write.h:
+	  * sys/osxaudio/gstosxaudioelement.h:
+	  Fix broken GObject macros
+
+2006-04-08 18:23:04 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Don't make rounding errors in timestamp/duration calculations.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_prepare_current_sample),
+	  (gst_qtdemux_chain), (gst_qtdemux_add_stream), (qtdemux_dump_stsz),
+	  (qtdemux_dump_stco), (qtdemux_parse_trak):
+	  Don't make rounding errors in timestamp/duration calculations.
+	  Fix timestamps for AMR and IMA4.  Fixes (#337436).
+	  Create a dummy segment even when there is no edit list.
+
+2006-04-08 13:09:50 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacdec.c: Don't try to seek beyond the end of the file (would occasionally display error dialogs in tote...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_handle_seek_event):
+	  Don't try to seek beyond the end of the file (would
+	  occasionally display error dialogs in totem when seeking
+	  to the end) (#335869). Will still throw an error though
+	  if the file is truncated and the total_samples value in
+	  the stream header is wrong.
+
+2006-04-07 18:15:08 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacdec.*: If the stream header doesn't contain the total number of samples, search for the last flac fra...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_calculate_crc8),
+	  (gst_flac_dec_scan_got_frame), (gst_flac_dec_scan_for_last_block),
+	  (gst_flac_dec_metadata_callback):
+	  * ext/flac/gstflacdec.h:
+	  If the stream header doesn't contain the total number of samples,
+	  search for the last flac frame at the end of the file and calculate
+	  the total duration from that frame's offset (fixes #337609).
+
+2006-04-07 15:53:43 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  Typo fix, s/XFree86/X11 and added doc blurb saying that it fixates to 25fps
+	  Original commit message from CVS:
+	  2006-04-07  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * ext/amrwb/amrwb-code/Makefile.am:
+	  * sys/ximagesrc/ximagesrc.c: (gst_ximagesrc_recalc),
+	  (gst_ximagesrc_create), (gst_ximagesrc_set_property):
+	  Typo fix, s/XFree86/X11 and added doc blurb saying that it fixates to
+	  25fps
+
+2006-04-07 15:47:27 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  tests/icles/ximagesrc-test.c: Actually assert that pipeline goes to playing
+	  Original commit message from CVS:
+	  2006-04-07  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * tests/icles/ximagesrc-test.c: (main):
+	  Actually assert that pipeline goes to playing
+
+2006-04-07 15:27:40 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  sys/ximagesrc/ximagesrc.c: Fix typo, C++ style comments and other small cleanups
+	  Original commit message from CVS:
+	  2006-04-07  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * sys/ximagesrc/ximagesrc.c: (gst_ximagesrc_recalc),
+	  (composite_pixel), (gst_ximagesrc_ximage_get),
+	  (gst_ximagesrc_create), (gst_ximagesrc_set_property):
+	  Fix typo, C++ style comments and other small cleanups
+
+2006-04-07 10:48:19 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/avi/gstavidemux.c: Don't unref the GstPadTemplate returned by gst_element_class_get_pad_template().
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_stream):
+	  Don't unref the GstPadTemplate returned by
+	  gst_element_class_get_pad_template().
+
+2006-04-06 19:16:02 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Added full edit list support.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_init),
+	  (gst_qtdemux_handle_src_query), (gst_qtdemux_find_index),
+	  (gst_qtdemux_find_keyframe), (gst_qtdemux_find_segment),
+	  (gst_qtdemux_move_stream), (gst_qtdemux_perform_seek),
+	  (gst_qtdemux_do_seek), (gst_qtdemux_change_state),
+	  (gst_qtdemux_activate_segment),
+	  (gst_qtdemux_prepare_current_sample), (gst_qtdemux_advance_sample),
+	  (gst_qtdemux_loop_state_movie), (gst_qtdemux_loop),
+	  (qtdemux_parse_trak):
+	  Added full edit list support.
+	  Avoid overflows in prologue image detection code.
+	  Avoid roundoff errors in timestamp calculations.
+
+2006-04-06 11:35:26 +0000  j^ <j@bootlab.org>
+
+	  Unify the long descriptions in the plugin details (#337263).
+	  Original commit message from CVS:
+	  Patch by: j^  <j at bootlab dot org>
+	  * ext/amrwb/gstamrwbdec.c:
+	  * ext/amrwb/gstamrwbenc.c:
+	  * ext/amrwb/gstamrwbparse.c:
+	  * ext/arts/gst_arts.c:
+	  * ext/artsd/gstartsdsink.c:
+	  * ext/audiofile/gstafparse.c:
+	  * ext/audiofile/gstafsink.c:
+	  * ext/audiofile/gstafsrc.c:
+	  * ext/cdaudio/gstcdaudio.c:
+	  * ext/directfb/dfbvideosink.c:
+	  * ext/divx/gstdivxdec.c:
+	  * ext/divx/gstdivxenc.c:
+	  * ext/dts/gstdtsdec.c: (gst_dtsdec_base_init):
+	  * ext/faac/gstfaac.c: (gst_faac_base_init):
+	  * ext/faad/gstfaad.c:
+	  * ext/gsm/gstgsmdec.c:
+	  * ext/gsm/gstgsmenc.c:
+	  * ext/hermes/gsthermescolorspace.c:
+	  * ext/ivorbis/vorbisfile.c:
+	  * ext/lcs/gstcolorspace.c:
+	  * ext/libfame/gstlibfame.c:
+	  * ext/libmms/gstmms.c: (gst_mms_base_init):
+	  * ext/musicbrainz/gsttrm.c: (gst_musicbrainz_base_init):
+	  * ext/nas/nassink.c: (gst_nassink_base_init):
+	  * ext/neon/gstneonhttpsrc.c:
+	  * ext/polyp/polypsink.c: (gst_polypsink_base_init):
+	  * ext/sdl/sdlaudiosink.c:
+	  * ext/sdl/sdlvideosink.c:
+	  * ext/shout/gstshout.c:
+	  * ext/snapshot/gstsnapshot.c:
+	  * ext/sndfile/gstsf.c:
+	  * ext/tarkin/gsttarkindec.c:
+	  * ext/tarkin/gsttarkinenc.c:
+	  * ext/theora/theoradec.c:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_base_init):
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_base_init):
+	  * ext/xvid/gstxviddec.c:
+	  * ext/xvid/gstxvidenc.c:
+	  * gst/cdxaparse/gstcdxaparse.c: (gst_cdxa_parse_base_init):
+	  * gst/cdxaparse/gstcdxastrip.c: (gst_cdxastrip_base_init):
+	  * gst/chart/gstchart.c:
+	  * gst/equalizer/gstiirequalizer.c: (gst_iir_equalizer_base_init):
+	  * gst/festival/gstfestival.c:
+	  * gst/filter/gstiir.c:
+	  * gst/filter/gstlpwsinc.c:
+	  * gst/freeze/gstfreeze.c:
+	  * gst/games/gstpuzzle.c: (gst_puzzle_base_init):
+	  * gst/mixmatrix/mixmatrix.c:
+	  * gst/mpeg1sys/gstmpeg1systemencode.c:
+	  * gst/mpeg1videoparse/gstmp1videoparse.c:
+	  * gst/mpeg2sub/gstmpeg2subt.c:
+	  * gst/mpegaudioparse/gstmpegaudioparse.c:
+	  * gst/multifilesink/gstmultifilesink.c:
+	  * gst/overlay/gstoverlay.c:
+	  * gst/passthrough/gstpassthrough.c:
+	  * gst/playondemand/gstplayondemand.c:
+	  * gst/qtdemux/qtdemux.c:
+	  * gst/rtjpeg/gstrtjpegdec.c:
+	  * gst/rtjpeg/gstrtjpegenc.c:
+	  * gst/smooth/gstsmooth.c:
+	  * gst/tta/gstttadec.c: (gst_tta_dec_base_init):
+	  * gst/tta/gstttaparse.c: (gst_tta_parse_base_init):
+	  * gst/videocrop/gstvideocrop.c:
+	  * gst/videodrop/gstvideodrop.c:
+	  * gst/virtualdub/gstxsharpen.c:
+	  * gst/xingheader/gstxingmux.c: (gst_xing_mux_base_init):
+	  * gst/y4m/gsty4mencode.c:
+	  Unify the long descriptions in the plugin details (#337263).
+
+2006-04-06 09:14:30 +0000  Brian Cameron <brian.cameron@sun.com>
+
+	  sys/sunaudio/gstsunaudiosink.*: Use spec->segsize and spec->segtotal in the prepare function to initialise the ring b...
+	  Original commit message from CVS:
+	  Patch by: Brian Cameron  <brian dot cameron at sun dot com>
+	  * sys/sunaudio/gstsunaudiosink.c: (gst_sunaudiosink_init),
+	  (gst_sunaudiosink_prepare), (gst_sunaudiosink_write):
+	  * sys/sunaudio/gstsunaudiosink.h:
+	  Use spec->segsize and spec->segtotal in the prepare function
+	  to initialise the ring buffer instead of using the buffer-time
+	  property (#337421).
+
+2006-04-06 08:52:51 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Bump core requirements to CVS for gst_pad_query_peer_duration() which is used by speexdec.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Bump core requirements to CVS for gst_pad_query_peer_duration()
+	  which is used by speexdec.
+
+2006-04-05 18:27:22 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/speex/: Fix seeking and duration queries (#337033); clean up and refactor a bit.
+	  Original commit message from CVS:
+	  * ext/speex/gstspeex.c: (plugin_init):
+	  * ext/speex/gstspeexdec.c: (gst_speex_dec_class_init),
+	  (gst_speex_dec_reset), (gst_speex_dec_init), (speex_dec_convert),
+	  (speex_get_sink_query_types), (speex_dec_sink_query),
+	  (speex_get_src_query_types), (speex_dec_src_query),
+	  (speex_dec_src_event), (speex_dec_sink_event),
+	  (speex_dec_chain_parse_header), (speex_dec_chain_parse_comments),
+	  (speex_dec_chain_parse_data), (speex_dec_chain),
+	  (gst_speex_dec_get_property), (gst_speex_dec_set_property),
+	  (speex_dec_change_state):
+	  * ext/speex/gstspeexdec.h:
+	  Fix seeking and duration queries (#337033); clean up and
+	  refactor a bit.
+
+2006-04-05 12:41:14 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  ext/raw1394/gstdv1394src.c: distinguish between device not found and could not open for reading
+	  Original commit message from CVS:
+	  * ext/raw1394/gstdv1394src.c:
+	  distinguish between device not found and could not open for
+	  reading
+
+2006-04-05 08:36:55 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: Use duration as segment stop position if none is explicitly configured.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_perform_seek),
+	  (gst_qtdemux_do_seek), (gst_qtdemux_loop_state_movie),
+	  (gst_qtdemux_loop):
+	  Use duration as segment stop position if none is
+	  explicitly configured.
+	  Also perform EOS when we run past the segment stop.
+
+2006-04-04 11:20:58 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: More cleanups, added comments.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_go_back),
+	  (gst_qtdemux_perform_seek), (gst_qtdemux_do_seek),
+	  (gst_qtdemux_loop_state_movie), (gst_qtdemux_loop),
+	  (gst_qtdemux_chain), (qtdemux_parse_tree), (qtdemux_parse_trak):
+	  More cleanups, added comments.
+	  Mark discontinuities on outgoing buffers.
+	  Post better errors when something goes wrong.
+	  Handle EOS and segment end properly.
+
+2006-04-04 08:31:10 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.*: Handle stss boxes so we can mark and find keyframes.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_init),
+	  (gst_qtdemux_push_event), (gst_qtdemux_go_back),
+	  (gst_qtdemux_perform_seek), (gst_qtdemux_do_seek),
+	  (gst_qtdemux_handle_src_event), (plugin_init),
+	  (gst_qtdemux_change_state), (gst_qtdemux_loop_state_movie),
+	  (gst_qtdemux_loop), (gst_qtdemux_chain),
+	  (qtdemux_sink_activate_pull), (gst_qtdemux_add_stream),
+	  (qtdemux_parse), (qtdemux_parse_tree), (qtdemux_parse_trak),
+	  (qtdemux_parse_udta), (qtdemux_tag_add_str), (qtdemux_tag_add_num),
+	  (qtdemux_tag_add_gnre), (gst_qtdemux_handle_esds):
+	  * gst/qtdemux/qtdemux.h:
+	  Handle stss boxes so we can mark and find keyframes.
+	  Implement correct accurate and keyframe seeking.
+	  Use _DEBUG_OBJECT when possible.
+
+2006-04-03 13:29:20 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* tests/check/elements/.gitignore:
+	  ignore more
+	  Original commit message from CVS:
+	  ignore more
+
+2006-04-03 13:28:55 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* pkgconfig/Makefile.am:
+	  fix dist
+	  Original commit message from CVS:
+	  fix dist
+
+2006-04-03 09:02:29 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  add a .pc file so other modules can use good plugins in tests
+	  Original commit message from CVS:
+	  * Makefile.am:
+	  * configure.ac:
+	  * pkgconfig/.cvsignore:
+	  * pkgconfig/Makefile.am:
+	  * pkgconfig/gstreamer-plugins-good-uninstalled.pc.in:
+	  add a .pc file so other modules can use good plugins in tests
+
+2006-04-01 16:50:49 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* common:
+	* docs/plugins/inspect/plugin-qtdemux.xml:
+	* docs/plugins/inspect/plugin-taglib.xml:
+	* ext/taglib/gsttaglibmux.c:
+	* tests/check/elements/id3v2mux.c:
+	  add taglib checks and docs
+	  Original commit message from CVS:
+	  add taglib checks and docs
+
+2006-04-01 15:30:51 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/upload.mak:
+	  disable use of AS_LIBTOOL_TAGS, it doesn't work correctly
+	  Original commit message from CVS:
+	  disable use of AS_LIBTOOL_TAGS, it doesn't work correctly
+
+2006-04-01 14:03:03 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* common:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-annodex.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cdio.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-gdkpixbuf.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-halelements.xml:
+	* docs/plugins/inspect/plugin-id3demux.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-ladspa.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-videobalance.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	  adding inspect files
+	  Original commit message from CVS:
+	  adding inspect files
+
+2006-04-01 10:15:33 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* tests/icles/ximagesrc-test.c:
+	  5 second timeout
+	  Original commit message from CVS:
+	  5 second timeout
+
+2006-04-01 10:14:26 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* tests/icles/.gitignore:
+	* tests/icles/Makefile.am:
+	* tests/icles/ximagesrc-test.c:
+	  rename test
+	  Original commit message from CVS:
+	  rename test
+
+2006-04-01 10:09:11 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/qtdemux/qtdemux.c:
+	* gst/spectrum/gstspectrum.c:
+	* gst/videocrop/gstvideocrop.c:
+	* sys/directdraw/gstdirectdrawplugin.c:
+	* sys/directsound/gstdirectsoundplugin.c:
+	* sys/v4l2/gstv4l2.c:
+	* sys/ximage/gstximagesrc.c:
+	  rework build; add translations for v4l2
+	  Original commit message from CVS:
+	  rework build; add translations for v4l2
+
+2006-04-01 09:56:45 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  configure.ac: clean up, use AS_VERSION and AS_NANO
+	  Original commit message from CVS:
+	  * configure.ac:
+	  clean up, use AS_VERSION and AS_NANO
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_start):
+	  use PACKAGE_VERSION define
+	  * po/af.po:
+	  * po/az.po:
+	  * po/cs.po:
+	  * po/en_GB.po:
+	  * po/hu.po:
+	  * po/it.po:
+	  * po/nb.po:
+	  * po/nl.po:
+	  * po/or.po:
+	  * po/sq.po:
+	  * po/sr.po:
+	  * po/sv.po:
+	  * po/uk.po:
+	  * po/vi.po:
+	  updated
+
+2006-03-31 17:52:36 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  Add tests and fix PAR caps issue to ximagesrc
+	  Original commit message from CVS:
+	  2006-03-31  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * Makefile.am:
+	  * configure.ac:
+	  * sys/ximagesrc/ximagesrc.c:
+	  (gst_ximagesrc_ximage_get),
+	  (gst_ximagesrc_get_caps), (gst_ximagesrc_class_init):
+	  * sys/ximagesrc/ximageutil.c:
+	  * tests/Makefile.am:
+	  * tests/icles/Makefile.am:
+	  * tests/icles/ximagesrc-test.c: (terminate_playback), (main):
+	  Add tests and fix PAR caps issue to ximagesrc
+
+2006-03-31 16:32:47 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  sys/ximagesrc/ximagesrc.c: Add docs to ximagesrc
+	  Original commit message from CVS:
+	  2006-03-31  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * sys/ximagesrc/ximagesrc.c:
+	  Add docs to ximagesrc
+
+2006-03-31 15:21:35 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  sys/ximagesrc/: Fix ximagesrc so a) the cursor doesnt trail and b) there are no yellow rectangles with the cursor
+	  Original commit message from CVS:
+	  2006-03-31  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * sys/ximagesrc/ximagesrc.c: (composite_pixel),
+	  (gst_ximagesrc_ximage_get), (gst_ximagesrc_set_property),
+	  (gst_ximagesrc_get_caps), (gst_ximagesrc_class_init):
+	  * sys/ximagesrc/ximagesrc.h:
+	  * sys/ximagesrc/ximageutil.c: (ximageutil_xcontext_get):
+	  * sys/ximagesrc/ximageutil.h:
+	  Fix ximagesrc so a) the cursor doesnt trail and b) there are no
+	  yellow rectangles with the cursor
+
+2006-03-30 23:46:42 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	* win32/vs6/gst_plugins_good.dsw:
+	* win32/vs6/libgstalaw.dsp:
+	* win32/vs6/libgstalpha.dsp:
+	* win32/vs6/libgstalphacolor.dsp:
+	* win32/vs6/libgstapetag.dsp:
+	* win32/vs6/libgstauparse.dsp:
+	* win32/vs6/libgstautodetect.dsp:
+	* win32/vs6/libgstavi.dsp:
+	* win32/vs6/libgstcutter.dsp:
+	* win32/vs6/libgsteffectv.dsp:
+	* win32/vs6/libgstflx.dsp:
+	* win32/vs6/libgstgoom.dsp:
+	* win32/vs6/libgstid3demux.dsp:
+	* win32/vs6/libgstinterleave.dsp:
+	* win32/vs6/libgstjpeg.dsp:
+	* win32/vs6/libgstlevel.dsp:
+	* win32/vs6/libgstmatroska.dsp:
+	* win32/vs6/libgstmedian.dsp:
+	* win32/vs6/libgstmonoscope.dsp:
+	* win32/vs6/libgstmulaw.dsp:
+	* win32/vs6/libgstmultipart.dsp:
+	* win32/vs6/libgstrtp.dsp:
+	* win32/vs6/libgstrtsp.dsp:
+	* win32/vs6/libgstsmpte.dsp:
+	* win32/vs6/libgstspeex.dsp:
+	* win32/vs6/libgstvideobalance.dsp:
+	* win32/vs6/libgstvideobox.dsp:
+	* win32/vs6/libgstvideoflip.dsp:
+	* win32/vs6/libgstvideomixer.dsp:
+	* win32/vs6/libgstwavenc.dsp:
+	* win32/vs6/libgstwavparse.dsp:
+	  I'm too lazy to comment this
+	  Original commit message from CVS:
+	  *** empty log message ***
+
+2006-03-30 23:37:16 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  ext\jpeg\smokecodec.c: use of GST_DEBUG instead of DEBUG(a...) for WIN32
+	  Original commit message from CVS:
+	  * ext\jpeg\smokecodec.c:
+	  use of GST_DEBUG instead of DEBUG(a...) for WIN32
+	  * ext\speex\gstspeexenc.c: (gst_speexenc_set_header_on_caps):
+	  move first instruction after all variables declarations
+	  * gst\alpha\gstalpha.c:
+	  * gst\effectv\gstshagadelic.c:
+	  * gst\smpte\paint.c:
+	  * gst\videofilter\gstvideobalance.c:
+	  define M_PI if it's not defined (it's not defined on WIN32)
+	  * gst\cutter\gstcutter.c: (gst_cutter_chain):
+	  * gst\id3demux\id3v2frames.c: (parse_relative_volume_adjustment_two):
+	  * gst\level\gstlevel.c: (gst_level_set_property), (gst_level_transform_ip):
+	  * gst\matroska\matroska-demux.c: (gst_matroska_demux_parse_info),
+	  (gst_matroska_demux_video_caps):
+	  * gst\matroska\matroska-mux.c: (gst_matroska_mux_start), (gst_matroska_mux_finish):
+	  * gst\wavparse\gstwavparse.c: (gst_wavparse_stream_data):
+	  use gst_guint64_to_gdouble for conversions
+	  * gst\goom\filters.c: (setPixelRGB_):
+	  fix a debug which was using undefined variable
+	  * gst\level\gstlevel.c: (gst_level_set_caps), (gst_level_transform_ip):
+	  * gst\matroska\ebml-read.c: (gst_ebml_read_sint):
+	  replace LL suffix with L suffix (LL isn't supported by MSVC6.0)
+	  * win32/vs6:
+	  add vs6 projects files for most of plugins-good
+
+2006-03-30 15:37:05 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  better/unified long descriptions
+	  Original commit message from CVS:
+	  * ext/aalib/gstaasink.c:
+	  * ext/annodex/gstcmmldec.c:
+	  * ext/annodex/gstcmmlenc.c:
+	  * ext/cairo/gsttextoverlay.c:
+	  * ext/cairo/gsttimeoverlay.c:
+	  * ext/cdio/gstcdiocddasrc.c:
+	  * ext/dv/gstdvdec.c:
+	  * ext/esd/esdmon.c:
+	  * ext/esd/esdsink.c:
+	  * ext/flac/gstflacdec.c:
+	  * ext/flac/gstflacenc.c:
+	  * ext/flac/gstflactag.c:
+	  * ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_base_init):
+	  * ext/gconf/gstgconfaudiosrc.c: (gst_gconf_audio_src_base_init):
+	  * ext/gconf/gstgconfvideosink.c: (gst_gconf_video_sink_base_init):
+	  * ext/gconf/gstgconfvideosrc.c: (gst_gconf_video_src_base_init):
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c:
+	  * ext/gdk_pixbuf/pixbufscale.c:
+	  * ext/hal/gsthalaudiosink.c: (gst_hal_audio_sink_base_init):
+	  * ext/hal/gsthalaudiosrc.c: (gst_hal_audio_src_base_init):
+	  * ext/jpeg/gstjpegdec.c:
+	  * ext/jpeg/gstjpegenc.c:
+	  * ext/jpeg/gstsmokedec.c:
+	  * ext/jpeg/gstsmokeenc.c:
+	  * ext/libcaca/gstcacasink.c:
+	  * ext/libmng/gstmngdec.c:
+	  * ext/libmng/gstmngenc.c:
+	  * ext/libpng/gstpngdec.c:
+	  * ext/libpng/gstpngenc.c:
+	  * ext/mikmod/gstmikmod.c:
+	  * ext/raw1394/gstdv1394src.c:
+	  * ext/shout2/gstshout2.c:
+	  * ext/speex/gstspeexdec.c:
+	  * ext/speex/gstspeexenc.c:
+	  * gst/alpha/gstalpha.c:
+	  * gst/alpha/gstalphacolor.c:
+	  * gst/auparse/gstauparse.c:
+	  * gst/autodetect/gstautoaudiosink.c:
+	  (gst_auto_audio_sink_base_init):
+	  * gst/autodetect/gstautovideosink.c:
+	  (gst_auto_video_sink_base_init):
+	  * gst/avi/gstavimux.c: (gst_avimux_base_init):
+	  * gst/cutter/gstcutter.c:
+	  * gst/debug/breakmydata.c:
+	  * gst/debug/efence.c:
+	  * gst/debug/gstnavigationtest.c:
+	  * gst/debug/negotiation.c:
+	  * gst/debug/progressreport.c:
+	  * gst/debug/testplugin.c:
+	  * gst/effectv/gstaging.c:
+	  * gst/effectv/gstdice.c:
+	  * gst/effectv/gstedge.c:
+	  * gst/effectv/gstquark.c:
+	  * gst/effectv/gstrev.c:
+	  * gst/effectv/gstvertigo.c:
+	  * gst/effectv/gstwarp.c:
+	  * gst/flx/gstflxdec.c:
+	  * gst/goom/gstgoom.c:
+	  * gst/interleave/deinterleave.c:
+	  * gst/interleave/interleave.c:
+	  * gst/law/alaw-decode.c: (gst_alawdec_base_init):
+	  * gst/law/alaw-encode.c: (gst_alawenc_base_init):
+	  * gst/law/mulaw-decode.c: (gst_mulawdec_base_init):
+	  * gst/law/mulaw-encode.c: (gst_mulawenc_base_init):
+	  * gst/level/gstlevel.c:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_base_init):
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_base_init):
+	  * gst/median/gstmedian.c:
+	  * gst/monoscope/gstmonoscope.c:
+	  * gst/multipart/multipartdemux.c:
+	  * gst/multipart/multipartmux.c:
+	  * gst/oldcore/gstmd5sink.c:
+	  * gst/oldcore/gstmultifilesrc.c:
+	  * gst/oldcore/gstpipefilter.c:
+	  * gst/oldcore/gstshaper.c:
+	  * gst/oldcore/gststatistics.c:
+	  * gst/rtp/gstasteriskh263.c:
+	  * gst/rtp/gstrtpL16depay.c:
+	  * gst/rtp/gstrtpL16pay.c:
+	  * gst/rtp/gstrtpamrdepay.c:
+	  * gst/rtp/gstrtpamrpay.c:
+	  * gst/rtp/gstrtpdepay.c:
+	  * gst/rtp/gstrtpgsmpay.c:
+	  * gst/rtp/gstrtph263pay.c:
+	  * gst/rtp/gstrtph263pdepay.c:
+	  * gst/rtp/gstrtph263ppay.c:
+	  * gst/rtp/gstrtpmp4gpay.c:
+	  * gst/rtp/gstrtpmp4vdepay.c:
+	  * gst/rtp/gstrtpmp4vpay.c:
+	  * gst/rtp/gstrtpmpadepay.c:
+	  * gst/rtp/gstrtpmpapay.c:
+	  * gst/rtp/gstrtppcmadepay.c:
+	  * gst/rtp/gstrtppcmapay.c:
+	  * gst/rtp/gstrtppcmudepay.c:
+	  * gst/rtp/gstrtppcmupay.c:
+	  * gst/rtp/gstrtpspeexdepay.c:
+	  * gst/rtp/gstrtpspeexpay.c:
+	  * gst/rtsp/gstrtpdec.c:
+	  * gst/smpte/gstsmpte.c:
+	  * gst/videobox/gstvideobox.c:
+	  * gst/videofilter/gstgamma.c: (gst_gamma_base_init):
+	  * gst/videofilter/gstvideobalance.c:
+	  * gst/videofilter/gstvideoflip.c:
+	  * gst/videofilter/gstvideotemplate.c:
+	  (gst_videotemplate_base_init):
+	  * gst/videomixer/videomixer.c:
+	  * gst/wavenc/gstwavenc.c:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_base_init):
+	  better/unified long descriptions
+	  Fixed #336602
+	  Some cleanups to auparse, don't send multiple newsegments.
+
+2006-03-29 16:06:50 +0000  Michael Dominic K <mdk@mdk.org.pl>
+
+	  ext/dv/gstdvdemux.*: Seek in READY patch. Only works for pull based mode.
+	  Original commit message from CVS:
+	  From a patch by: Michael Dominic K. <mdk at mdk dot org dot pl>
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_class_init),
+	  (gst_dvdemux_reset), (gst_dvdemux_src_convert),
+	  (gst_dvdemux_send_event), (gst_dvdemux_flush), (gst_dvdemux_loop),
+	  (gst_dvdemux_sink_activate_pull), (gst_dvdemux_change_state):
+	  * ext/dv/gstdvdemux.h:
+	  Seek in READY patch. Only works for pull based mode.
+	  Fixes #323880
+
+2006-03-27 17:06:45 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/v4l2src_calls.c:
+	  Small fix, now pwc driver can tell about its buffers.
+	  Original commit message from CVS:
+	  Small fix, now pwc driver can tell about its buffers.
+
+2006-03-27 14:09:18 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/gdk_pixbuf/gstgdkpixbuf.c: Fix two crashers: don't unref the same caps twice, and set pixbuf loader to NULL after...
+	  Original commit message from CVS:
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_flush),
+	  (gst_gdk_pixbuf_event):
+	  Fix two crashers: don't unref the same caps twice, and
+	  set pixbuf loader to NULL after freeing it.
+
+2006-03-27 14:00:02 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/speex/gstspeexenc.*: Don't leak adapter.
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexenc.c: (gst_speexenc_class_init),
+	  (gst_speexenc_finalize), (gst_speexenc_sink_setcaps),
+	  (gst_speexenc_chain):
+	  * ext/speex/gstspeexenc.h:
+	  Don't leak adapter.
+	  A push *always* takes ownership of the buffer, even on
+	  errors.
+	  Small cleanups.
+
+2006-03-26 19:56:37 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/gsttaglib.*: Fix newsegment event handling a bit. We need to cache the first newsegment event, because we ...
+	  Original commit message from CVS:
+	  * ext/taglib/gsttaglib.cc:
+	  * ext/taglib/gsttaglib.h:
+	  Fix newsegment event handling a bit. We need to
+	  cache the first newsegment event, because we can't
+	  adjust offsets yet when we get it, as we don't
+	  know the size of the tag yet for sure at that point.
+	  Also do some minor cleaning up here and there and add
+	  some debug statements.
+
+2006-03-26 12:24:56 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/gstid3demux.c: Create source pad without leaking.
+	  Original commit message from CVS:
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_add_srcpad):
+	  Create source pad without leaking.
+
+2006-03-25 21:57:24 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/gsttaglib.cc: We do not want to proxy the caps on the sink pad; our source pad should have application/x-i...
+	  Original commit message from CVS:
+	  * ext/taglib/gsttaglib.cc:
+	  We do not want to proxy the caps on the sink pad; our
+	  source pad should have application/x-id3 caps; also,
+	  don't use already-freed strings in debug messages;
+	  finally, adjust buffer offsets on buffers sent out.
+
+2006-03-25 13:02:55 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/v4l2/gstv4l2src.c: Older kernels don't seem to have this particular v4l2 format, so comment out until this gets f...
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c:
+	  Older kernels don't seem to have this particular v4l2 format,
+	  so comment out until this gets fixed properly (and make
+	  buildbots happy).
+
+2006-03-25 05:31:28 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* common:
+	* sys/v4l2/gstv4l2colorbalance.c:
+	* sys/v4l2/gstv4l2colorbalance.h:
+	* sys/v4l2/gstv4l2element.c:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/gstv4l2tuner.c:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/v4l2/v4l2src_calls.h:
+	  Just make few things more robust and also some identation.
+	  Original commit message from CVS:
+	  Just make few things more robust and also some identation.
+
+2006-03-24 19:41:03 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/flac/: Spifify a bit.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_handle_seek_event):
+	  * ext/flac/gstflacdec.h:
+	  * ext/flac/gstflacenc.h:
+	  Spifify a bit.
+	  Fix deadly lock order error in seeking code, STREAM_LOCK
+	  cannot be taken within LOCK and the streaming variables are
+	  protected with the STREAM_LOCK anyway.
+
+2006-03-24 18:56:16 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: this patch combines the global init_frames with the stream init_frames. Rationale being that t...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_index),
+	  (gst_avi_demux_stream_index), (gst_avi_demux_stream_scan),
+	  (gst_avi_demux_massage_index), (gst_avi_demux_handle_seek):
+	  this patch combines the global init_frames with the stream
+	  init_frames. Rationale being that the global delay should
+	  be subtracted from any stream delay.
+	  Fixes #335858.
+
+2006-03-24 17:11:56 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/: use DEBUG_FUNCPTR for collectpads
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_init):
+	  * gst/multipart/multipartmux.c: (gst_multipart_mux_init):
+	  * gst/smpte/gstsmpte.c: (gst_smpte_init):
+	  * gst/videomixer/videomixer.c: (gst_videomixer_init):
+	  use DEBUG_FUNCPTR for collectpads
+
+2006-03-24 09:54:00 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/jpeg/gstjpegenc.c: Don't crash when encoding images where the number of rows isn't a multiple of 2*DCTSIZE. Add s...
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegenc.c: (gst_jpegenc_init), (gst_jpegenc_chain):
+	  Don't crash when encoding images where the number of rows isn't
+	  a multiple of 2*DCTSIZE. Add some GST_DEBUG_FUNCPTR.
+
+2006-03-23 21:28:06 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  More state change function fixes.
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexdec.c: (speex_dec_change_state):
+	  * gst/interleave/deinterleave.c: (deinterleave_change_state):
+	  * gst/interleave/interleave.c: (interleave_change_state):
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_change_state):
+	  More state change function fixes.
+
+2006-03-23 20:12:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/esd/esdsink.*: Fix esd choppy playback by configuring audiosink correctly. Fixes #325191
+	  Original commit message from CVS:
+	  * ext/esd/esdsink.c: (gst_esdsink_class_init),
+	  (gst_esdsink_getcaps), (gst_esdsink_open), (gst_esdsink_close),
+	  (gst_esdsink_prepare), (gst_esdsink_unprepare),
+	  (gst_esdsink_delay), (gst_esdsink_reset):
+	  * ext/esd/esdsink.h:
+	  Fix esd choppy playback by configuring audiosink
+	  correctly. Fixes #325191
+
+2006-03-23 19:57:34 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/libpng/gstpngdec.c: Make state change function thread-safe.
+	  Original commit message from CVS:
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_change_state):
+	  Make state change function thread-safe.
+
+2006-03-23 16:50:32 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/wavparse/gstwavparse.c: Don't try to read beyond the end of the file just because the header claims a bigger size...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_get_upstream_size),
+	  (gst_wavparse_stream_headers), (gst_wavparse_stream_data):
+	  Don't try to read beyond the end of the file just because
+	  the header claims a bigger size (like with truncated files).
+
+2006-03-23 15:36:27 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/wavparse/gstwavparse.*: Delay source pad creation until we have the first chunk of media data, so the we can exam...
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_perform_seek),
+	  (gst_wavparse_stream_headers), (gst_wavparse_add_src_pad),
+	  (gst_wavparse_stream_data), (gst_wavparse_loop):
+	  * gst/wavparse/gstwavparse.h:
+	  Delay source pad creation until we have the first chunk of
+	  media data, so the we can examine the data and adjust the
+	  caps accordingly if required. This makes playback of .wav
+	  files with DTS-declared-as-PCM content work (#313266).
+
+2006-03-22 19:50:56 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  add videobalance plugn
+	  Original commit message from CVS:
+	  add videobalance plugn
+
+2006-03-22 13:02:11 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	  mention fixed bug number in the changelog
+	  Original commit message from CVS:
+	  mention fixed bug number in the changelog
+
+2006-03-22 13:00:34 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/: Don't attempt typefinding on too-short buffers that have been completely trimmed away.
+	  Original commit message from CVS:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_chain):
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_chain):
+	  Don't attempt typefinding on too-short buffers that have been
+	  completely trimmed away.
+	  * gst/id3demux/id3tags.c: (id3demux_read_id3v2_tag):
+	  Improve the debug output
+
+2006-03-21 18:12:59 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/esd/esdsink.c: Some cleanups.
+	  Original commit message from CVS:
+	  * ext/esd/esdsink.c: (gst_esdsink_class_init), (gst_esdsink_init),
+	  (gst_esdsink_finalize), (gst_esdsink_getcaps), (gst_esdsink_open),
+	  (gst_esdsink_close), (gst_esdsink_prepare), (gst_esdsink_write),
+	  (gst_esdsink_set_property), (gst_esdsink_get_property):
+	  Some cleanups.
+	  Reset fd to -1 when we close them.
+
+2006-03-21 16:19:37 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: the OPTIONS request result is optional so don't fail on it.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_open):
+	  the OPTIONS request result is optional so don't
+	  fail on it.
+
+2006-03-21 14:53:36 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/: gcc 4.1 unreferenced pointer fixes.
+	  Original commit message from CVS:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_reset):
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_reset):
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_create_sourcepad),
+	  (gst_wavparse_stream_headers), (gst_wavparse_send_event),
+	  (gst_wavparse_change_state):
+	  gcc 4.1 unreferenced pointer fixes.
+
+2006-03-21 13:07:31 +0000  Tommi Myöhänen <ext-tommi.myohanen@nokia.com>
+
+	  gst/wavparse/gstwavparse.c: Fix block alignment calculation. Alignment should be done before adding the byte offset w...
+	  Original commit message from CVS:
+	  Patch by: Tommi Myöhänen  <ext-tommi dot myohanen at nokia dot com>
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_perform_seek):
+	  Fix block alignment calculation. Alignment should be done before
+	  adding the byte offset where the data starts (#335231).
+
+2006-03-20 18:34:21 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/matroska/ebml-write.c: Ensure that we set correct caps on buffers that are transferred direct from the input.
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-write.c: (gst_ebml_write_element_push):
+	  Ensure that we set correct caps on buffers that are transferred
+	  direct from the input.
+
+2006-03-20 17:38:48 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/goom/: Free filter data when cleaning up. (Fixes: #334995)
+	  Original commit message from CVS:
+	  * gst/goom/filters.c: (zoomFilterDestroy):
+	  * gst/goom/goom_core.c: (goom_close):
+	  Free filter data when cleaning up. (Fixes: #334995)
+
+2006-03-20 08:59:29 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/gsttaglib.h: Fix left-over gst_my_filter_get_type.
+	  Original commit message from CVS:
+	  * ext/taglib/gsttaglib.h:
+	  Fix left-over gst_my_filter_get_type.
+
+2006-03-17 16:34:36 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* sys/ximage/gstximagesrc.c:
+	  Have a show mouse pointer property and use it if we can
+	  Original commit message from CVS:
+	  Have a show mouse pointer property and use it if we can
+
+2006-03-17 15:33:08 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Don't compile udp and rtsp plugins on win32 (mingw) or other systems that don't have <sys/socket.h> for...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Don't compile udp and rtsp plugins on win32 (mingw) or other
+	  systems that don't have <sys/socket.h> for some reason (#316203).
+
+2006-03-16 17:28:07 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	* ChangeLog:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/raw1394/gstdv1394src.h:
+	  Change bus reset handler so it reports useful information such as whether the device being used connected or disconne...
+	  Original commit message from CVS:
+	  Change bus reset handler so it reports useful information such as
+	  whether the device being used connected or disconnected
+
+2006-03-16 16:06:22 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/id3v2frames.c: We only care about gain and peak data for the master volume.
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c:
+	  (parse_relative_volume_adjustment_two):
+	  We only care about gain and peak data for the master volume.
+
+2006-03-16 13:22:28 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/id3v2frames.c: Read replay gain tags (#323721).
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (id3demux_id3v2_parse_frame),
+	  (parse_id_string), (parse_unique_file_identifier),
+	  (parse_relative_volume_adjustment_two), (id3v2_tag_to_taglist):
+	  Read replay gain tags (#323721).
+
+2006-03-15 23:19:30 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Bump requirements to gst-plugins-base CVS because of buggy gst_tag_from_id3_user_tag() in 0.10.5.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Bump requirements to gst-plugins-base CVS because
+	  of buggy gst_tag_from_id3_user_tag() in 0.10.5.
+
+2006-03-15 22:30:24 +0000  Philippe Kalaf <philippe.kalaf@collabora.co.uk>
+
+	* ChangeLog:
+	* gst/rtp/gstrtppcmadepay.c:
+	  Fixed one of the caps in the code from mulaw to alaw.
+	  Original commit message from CVS:
+	  Fixed one of the caps in the code from mulaw to alaw.
+
+2006-03-15 16:21:38 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/apetag/gsttagdemux.c: Ensure that we set caps on the buffers we pass.
+	  Original commit message from CVS:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_chain):
+	  Ensure that we set caps on the buffers we pass.
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_chain),
+	  (gst_id3demux_sink_activate):
+	  Ensure that we set caps on the buffers we pass.
+	  Use STREAM, TYPE_NOT_FOUND as the error class when
+	  typefinding fails.
+
+2006-03-15 16:17:12 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  Fix memleak with gst_static_pad_template_get().
+	  Original commit message from CVS:
+	  * ext/cairo/gsttextoverlay.c: (gst_text_overlay_init):
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_init), (gst_dvdemux_add_pads):
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_init):
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_init),
+	  (gst_jpeg_dec_setcaps):
+	  * ext/jpeg/gstjpegenc.c: (gst_jpegenc_init):
+	  * ext/jpeg/gstsmokedec.c: (gst_smokedec_init):
+	  * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_init):
+	  * ext/libmng/gstmngdec.c: (gst_mngdec_init),
+	  (gst_mngdec_src_getcaps):
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_init),
+	  (gst_pngdec_caps_create_and_set):
+	  * ext/libpng/gstpngenc.c: (gst_pngenc_init):
+	  * ext/mikmod/gstmikmod.c: (gst_mikmod_init):
+	  * ext/speex/gstspeexdec.c: (gst_speex_dec_init):
+	  * gst/alpha/gstalpha.c: (gst_alpha_init):
+	  * gst/auparse/gstauparse.c: (gst_au_parse_init):
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_init),
+	  (gst_avi_demux_handle_src_event), (gst_avi_demux_parse_stream):
+	  * gst/cutter/gstcutter.c: (gst_cutter_init):
+	  * gst/debug/efence.c: (gst_efence_init), (gst_efence_getrange),
+	  (gst_efence_checkgetrange):
+	  * gst/debug/negotiation.c: (gst_negotiation_init):
+	  * gst/flx/gstflxdec.c: (gst_flxdec_init):
+	  * gst/goom/gstgoom.c: (gst_goom_init):
+	  * gst/rtp/gstasteriskh263.c: (gst_asteriskh263_init):
+	  * gst/rtp/gstrtpL16depay.c: (gst_rtp_L16depay_init):
+	  * gst/rtp/gstrtpL16pay.c: (gst_rtpL16pay_init):
+	  * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_init):
+	  * gst/rtp/gstrtpdepay.c: (gst_rtp_depay_init):
+	  * gst/rtp/gstrtpmpadepay.c: (gst_rtp_mpa_depay_init):
+	  * gst/rtsp/gstrtpdec.c: (gst_rtpdec_init):
+	  * gst/smpte/gstsmpte.c: (gst_smpte_init):
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_init),
+	  (gst_wavparse_create_sourcepad):
+	  Fix memleak with gst_static_pad_template_get().
+	  This uses gst_pad_new_from_static_template() instead.
+	  Fixes #333512
+
+2006-03-15 15:08:20 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Let's not forget to chain up to the parent dispose.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_dispose):
+	  Let's not forget to chain up to the parent dispose.
+
+2006-03-15 14:39:25 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Series of memleak fixes:
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_class_init),
+	  (gst_qtdemux_init), (gst_qtdemux_dispose),
+	  (gst_qtdemux_add_stream), (qtdemux_parse_trak):
+	  Series of memleak fixes:
+	  - Unref the GstAdapter in finalize.
+	  - Use gst_pad_new_from_static_template(), shorter and safer.
+	  - Free unused QtDemuxStream when not used.
+
+2006-03-14 17:56:02 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Bump -base requirement to 0.10.5 for gst_tag_from_id3_user_tag(), used by id3demux.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Bump -base requirement to 0.10.5 for gst_tag_from_id3_user_tag(),
+	  used by id3demux.
+	  * gst/id3demux/gstid3demux.c: (plugin_init):
+	  * gst/id3demux/id3v2frames.c: (id3demux_id3v2_parse_frame),
+	  (parse_user_text_identification_frame),
+	  (parse_unique_file_identifier):
+	  Add support for UFID and TXXX frames and extract musicbrainz tags.
+
+2006-03-14 17:24:03 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  sys/v4l2/gstv4l2src.c: Initialization of the debugging category should be as early as possible, moving it from _class...
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_base_init),
+	  (gst_v4l2src_class_init):
+	  Initialization of the debugging category should be as early as possible,
+	  moving it from _class_init() to beginning of _base_init().
+
+2006-03-14 15:28:00 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavidemux.c: Catch short reads, like they might happen with truncated files (see #305279); remove unnecessa...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_process_next_entry):
+	  Catch short reads, like they might happen with truncated
+	  files (see #305279); remove unnecessary indentation.
+
+2006-03-14 14:18:16 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavidemux.c: Fix DIB image inversion for pictures with a depth != 8 (#305279).
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_invert):
+	  Fix DIB image inversion for pictures with a
+	  depth != 8 (#305279).
+
+2006-03-14 09:23:09 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/jpeg/gstjpegdec.*: Fix durations on outgoing buffers after seeking in MJPEG files (#334083); some minor clean-ups.
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_class_init),
+	  (gst_jpeg_dec_chain), (gst_jpeg_dec_change_state):
+	  * ext/jpeg/gstjpegdec.h:
+	  Fix durations on outgoing buffers after seeking
+	  in MJPEG files (#334083); some minor clean-ups.
+
+2006-03-13 18:28:18 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/wavparse/gstwavparse.c: Implement seek in READY (re-fixes #327658)
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_reset),
+	  (gst_wavparse_change_state):
+	  Implement seek in READY (re-fixes #327658)
+
+2006-03-13 17:22:19 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/gsttaglib.cc: Add gtk-doc blurb (unused for the time being); match registered plugin name to the filename ...
+	  Original commit message from CVS:
+	  * ext/taglib/gsttaglib.cc:
+	  Add gtk-doc blurb (unused for the time being); match registered
+	  plugin name to the filename of the plugin (taglibmux => taglib)
+
+2006-03-13 15:49:08 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  close #333784 unref the result of gst_pad_get_parent() by: Christophe Fergeau.
+	  Original commit message from CVS:
+	  * ext/cairo/gsttextoverlay.c: (gst_text_overlay_setcaps):
+	  * ext/esd/esdmon.c: (gst_esdmon_get):
+	  * ext/flac/gstflactag.c: (gst_flac_tag_chain):
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_sink_setcaps),
+	  (gst_gdk_pixbuf_sink_getcaps):
+	  * ext/jpeg/gstjpegenc.c: (gst_jpegenc_getcaps),
+	  (gst_jpegenc_setcaps):
+	  * ext/jpeg/gstsmokedec.c: (gst_smokedec_chain):
+	  * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_getcaps),
+	  (gst_smokeenc_setcaps):
+	  * ext/libmng/gstmngdec.c: (gst_mngdec_sinklink),
+	  (gst_mngdec_src_getcaps):
+	  * ext/libmng/gstmngenc.c: (gst_mngenc_sinklink),
+	  (gst_mngenc_chain):
+	  * ext/libpng/gstpngenc.c: (gst_pngenc_setcaps):
+	  * ext/mikmod/gstmikmod.c: (gst_mikmod_srclink):
+	  * ext/speex/gstspeexdec.c: (speex_dec_convert),
+	  (speex_dec_src_event), (speex_dec_chain):
+	  * gst/avi/gstavimux.c: (gst_avimux_vidsinkconnect),
+	  (gst_avimux_audsinkconnect), (gst_avimux_handle_event):
+	  * gst/debug/negotiation.c: (gst_negotiation_getcaps),
+	  (gst_negotiation_pad_link), (gst_negotiation_chain):
+	  * gst/flx/gstflxdec.c: (gst_flxdec_src_query_handler),
+	  (gst_flxdec_chain):
+	  * gst/interleave/deinterleave.c: (deinterleave_sink_link),
+	  (deinterleave_chain):
+	  * gst/law/mulaw-encode.c: (mulawenc_setcaps):
+	  * gst/median/gstmedian.c: (gst_median_link):
+	  * gst/monoscope/gstmonoscope.c: (gst_monoscope_srcconnect),
+	  (gst_monoscope_chain):
+	  * gst/rtp/gstrtpL16pay.c: (gst_rtpL16pay_sinkconnect):
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_sink_setcaps):
+	  * sys/osxaudio/gstosxaudiosink.c: (gst_osxaudiosink_chain):
+	  * sys/osxaudio/gstosxaudiosrc.c: (gst_osxaudiosrc_get):
+	  close #333784 unref the result of gst_pad_get_parent()
+	  by: Christophe Fergeau.
+
+2006-03-13 10:05:09 +0000  Julien Moutte <julien@moutte.net>
+
+	  Fix build of v4l2 (sigh)
+	  Original commit message from CVS:
+	  2006-03-13  Julien MOUTTE  <julien@moutte.net>
+	  * docs/plugins/gst-plugins-bad-plugins-decl-list.txt:
+	  * sys/v4l2/Makefile.am: Fix build of v4l2 (sigh)
+
+2006-03-12 15:33:00 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  sys/v4l2/v4l2src_calls.c: g_atomic_int_set is only available in glib-0.10, use gst_atomic_int_et instead.
+	  Original commit message from CVS:
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_capture_init),
+	  (gst_v4l2src_buffer_pool_free):
+	  g_atomic_int_set is only available in glib-0.10, use gst_atomic_int_et
+	  instead.
+
+2006-03-12 15:25:51 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  sys/v4l2/gstv4l2element.h: Remove tim's addition of "_stdint.h" since it doesn't make the PPC buildbot happy.
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2element.h:
+	  Remove tim's addition of "_stdint.h" since it doesn't make the PPC
+	  buildbot happy.
+	  I will just use the same comment Ronald used when he added these lines:
+	  Yet Another Hack (tm) for kernel header borkedness.
+
+2006-03-12 15:02:02 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/taglib/: Add support for writing MusicBrainz IDs.
+	  Original commit message from CVS:
+	  * ext/taglib/Makefile.am:
+	  * ext/taglib/gsttaglib.cc:
+	  * ext/taglib/gsttaglib.h:
+	  Add support for writing MusicBrainz IDs.
+
+2006-03-12 14:43:57 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/v4l2/gstv4l2element.h: Include "_stdint.h" in an attempt to make the
+	  Original commit message from CVS:
+	  * sys/v4l2/gstv4l2element.h:
+	  Include "_stdint.h" in an attempt to make the
+	  PPC-buildbot happy.
+
+2006-03-11 22:50:03 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2.c:
+	* sys/v4l2/gstv4l2colorbalance.h:
+	* sys/v4l2/gstv4l2element.c:
+	* sys/v4l2/gstv4l2element.h:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/gstv4l2tuner.c:
+	* sys/v4l2/gstv4l2tuner.h:
+	* sys/v4l2/gstv4l2xoverlay.c:
+	* sys/v4l2/gstv4l2xoverlay.h:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2_calls.h:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/v4l2/v4l2src_calls.h:
+	  V4L2 ported to 0.10.
+	  Original commit message from CVS:
+	  V4L2 ported to 0.10.
+
+2006-03-11 10:58:08 +0000  Alex Lancaster <alexlan@fedoraproject.org>
+
+	  ext/taglib/gsttaglib.cc: and add support for TCOP (copyright)
+	  Original commit message from CVS:
+	  2006-03-11  Christophe Fergeau  <teuf@gnome.org>
+	  Patch by: Alex Lancaster
+	  * ext/taglib/gsttaglib.cc: fix writing of TPOS tags (album number),
+	  and add support for TCOP (copyright)
+
+2006-03-09 20:02:44 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Fix build with gcc-4.1 (#327355).
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_send_event):
+	  Fix build with gcc-4.1 (#327355).
+
+2006-03-09 17:44:17 +0000  Christophe Fergeau <teuf@gnome.org>
+
+	  new id3v2 muxer based on TagLib
+	  Original commit message from CVS:
+	  2006-03-09  Christophe Fergeau  <teuf@gnome.org>
+	  reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+	  * configure.ac:
+	  * ext/Makefile.am:
+	  * ext/taglib/Makefile.am:
+	  * ext/taglib/gsttaglib.cc:
+	  * ext/taglib/gsttaglib.h: new id3v2 muxer based on TagLib
+
+2006-03-09 11:47:32 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/dv/gstdvdemux.c: Handle events in push mode better, can now do non-flushing seeks in push mode as well.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_handle_sink_event),
+	  (gst_dvdemux_convert_segment), (gst_dvdemux_demux_frame):
+	  Handle events in push mode better, can now do non-flushing
+	  seeks in push mode as well.
+
+2006-03-08 12:16:14 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Extract disc number and count from files that use 'disk' instead of 'disc' as node identifier ...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_udta):
+	  Extract disc number and count from files that use
+	  'disk' instead of 'disc' as node identifier for that
+	  (fixes #332066).
+
+2006-03-07 17:31:03 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstdynudpsink.c: Applied patch from Kai Vehmanen, fixes #333624.
+	  Original commit message from CVS:
+	  * gst/udp/gstdynudpsink.c: (gst_dynudpsink_class_init):
+	  Applied patch from Kai Vehmanen, fixes #333624.
+
+2006-03-06 22:22:45 +0000  Julien Moutte <julien@moutte.net>
+
+	  ext/libpng/gstpngdec.c: Implement paletted and grayscale png files handling. (#150363).
+	  Original commit message from CVS:
+	  2006-03-06  Julien MOUTTE  <julien@moutte.net>
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_caps_create_and_set):
+	  Implement paletted and grayscale png files handling.
+	  (#150363).
+
+2006-03-06 00:10:29 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  ext/speex/gstspeexenc.c: fix a tag list assert follow gst-plugins-base/ext/ogg/README; set OFFSET and OFFSET_END.  Mu...
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexenc.c: (gst_speexenc_set_header_on_caps),
+	  (gst_speexenc_chain):
+	  fix a tag list assert
+	  follow gst-plugins-base/ext/ogg/README; set OFFSET
+	  and OFFSET_END.  Muxes correctly with gst-plugins-base
+	  > 0.9.3
+
+2006-03-05 13:03:40 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Add support for '3IVD' fourcc (#333403).
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_video_caps):
+	  Add support for '3IVD' fourcc (#333403).
+
+2006-03-04 20:11:35 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/: Use new typefind helper functions here as well, and do typefinding in pull-mode if upstream supports t...
+	  Original commit message from CVS:
+	  * gst/id3demux/Makefile.am:
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_add_srcpad),
+	  (gst_id3demux_chain), (gst_id3demux_sink_activate):
+	  Use new typefind helper functions here as well, and
+	  do typefinding in pull-mode if upstream supports that.
+
+2006-03-04 18:57:37 +0000  Benjamin Pineau <ben.pineau@gmail.com>
+
+	  sys/sunaudio/: Remove unused variables, breaks build from CVS
+	  Original commit message from CVS:
+	  * sys/sunaudio/gstsunaudiomixerctrl.c:
+	  (gst_sunaudiomixer_ctrl_get_volume),
+	  (gst_sunaudiomixer_ctrl_set_volume):
+	  * sys/sunaudio/gstsunaudiomixertrack.c:
+	  (gst_sunaudiomixer_track_new):
+	  Remove unused variables, breaks build from CVS
+	  with -Werror (#333392, patch by: Benjamin Pineau)
+
+2006-03-03 23:45:23 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	  sys/: sinks are now using GST_RANK_PRIMARY to be used with autodectection
+	  Original commit message from CVS:
+	  * sys/directdraw:
+	  * sys/directsound:
+	  sinks are now using GST_RANK_PRIMARY to be used with autodectection
+	  * win32/vs6:
+	  project files updated to fix some bugs
+	  * win32/vs7:
+	  * win32/vs8:
+	  vs7 and vs8 project files added
+
+2006-03-03 18:36:53 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  docs/plugins/: Added wavparse docs.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  Added wavparse docs.
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_class_init),
+	  (gst_wavparse_reset), (gst_wavparse_init),
+	  (gst_wavparse_create_sourcepad), (gst_wavparse_parse_file_header),
+	  (gst_wavparse_stream_init), (gst_wavparse_perform_seek),
+	  (gst_wavparse_stream_headers), (gst_wavparse_send_event),
+	  (gst_wavparse_stream_data), (gst_wavparse_loop),
+	  (gst_wavparse_srcpad_event), (gst_wavparse_sink_activate_pull),
+	  (gst_wavparse_change_state):
+	  * gst/wavparse/gstwavparse.h:
+	  Implement seek in READY (fixes #327658)
+	  Added docs and did some cleanups.
+
+2006-03-03 17:51:16 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavidemux.*: If we have an index, use a duration based on the index instead of blindly trusting the informa...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query),
+	  (gst_avi_demux_handle_src_event), (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_calculate_durations_from_index),
+	  (gst_avi_demux_stream_header):
+	  * gst/avi/gstavidemux.h:
+	  If we have an index, use a duration based on the index instead
+	  of blindly trusting the information in the stream headers
+	  (fixes #331817).
+
+2006-03-03 15:50:40 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  docs/plugins/: Added smoke and jpeg to the docs.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  Added smoke and jpeg to the docs.
+	  * ext/jpeg/Makefile.am:
+	  * ext/jpeg/gstjpeg.c: (plugin_init):
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_chain):
+	  * ext/jpeg/gstjpegenc.h:
+	  * ext/jpeg/gstsmokedec.c: (gst_smokedec_init),
+	  (gst_smokedec_chain):
+	  * ext/jpeg/gstsmokedec.h:
+	  * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_chain):
+	  * ext/jpeg/gstsmokeenc.h:
+	  * ext/jpeg/smokecodec.h:
+	  Port smokedec (fixes #331905).
+	  Added some docs.
+	  Some cleanups.
+
+2006-03-03 14:39:55 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  docs/plugins/: Added videobalance and videoflip to the docs.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  Added videobalance and videoflip to the docs.
+	  * gst/videofilter/Makefile.am:
+	  * gst/videofilter/gstvideobalance.c:
+	  (gst_video_balance_update_tables_planar411),
+	  (gst_video_balance_is_passthrough),
+	  (gst_video_balance_update_properties), (oil_tablelookup_u8),
+	  (gst_video_balance_planar411_ip), (gst_video_balance_set_caps),
+	  (gst_video_balance_transform_ip), (gst_video_balance_base_init),
+	  (gst_video_balance_finalize), (gst_video_balance_class_init),
+	  (gst_video_balance_init), (gst_video_balance_interface_supported),
+	  (gst_video_balance_interface_init),
+	  (gst_video_balance_colorbalance_list_channels),
+	  (gst_video_balance_colorbalance_set_value),
+	  (gst_video_balance_colorbalance_get_value),
+	  (gst_video_balance_colorbalance_init),
+	  (gst_video_balance_set_property), (gst_video_balance_get_property),
+	  (gst_video_balance_get_type), (plugin_init):
+	  * gst/videofilter/gstvideobalance.h:
+	  Ported to 0.10. (Fixes #326160)
+	  Added docs.
+	  * gst/videofilter/gstvideoflip.c:
+	  * gst/videofilter/gstvideoflip.h:
+	  Added docs.
+
+2006-03-03 11:07:41 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Use GST_WARNING instead of GST_ERROR for all the too short/long atoms when parsing.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse), (qtdemux_parse_trak):
+	  Use GST_WARNING instead of GST_ERROR for all the too short/long atoms
+	  when parsing.
+	  Also let's be a bit less vulgar in our warning messages :)
+
+2006-03-02 15:14:22 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Bump requirements to current core and -base CVS (core for new typefind helper API, and -base for the
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Bump requirements to current core and -base CVS
+	  (core for new typefind helper API, and -base for the
+	  WAVFORMATEX support that was added to libgstriff and
+	  is needed by wavparse).
+	  * gst/apetag/Makefile.am:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_chain),
+	  (gst_tag_demux_sink_activate):
+	  Use new typefind helpers for typefinding instead of our
+	  home-grown stuff; also, do typefinding in pull-mode if
+	  upstream supports that.
+
+2006-02-28 11:59:49 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Can't divide through zero (suppress warning in case of stream with one single still picture) (...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_trak):
+	  Can't divide through zero (suppress warning in case of
+	  stream with one single still picture) (see #327083)
+
+2006-02-28 10:40:01 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* ChangeLog:
+	  remove conflict indicator
+	  Original commit message from CVS:
+	  remove conflict indicator
+
+2006-02-28 10:39:08 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* ChangeLog:
+	  add missing entry
+	  Original commit message from CVS:
+	  add missing entry
+
+2006-02-28 10:29:16 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/wavparse/gstwavparse.c: Use DEBUG_OBJECT more.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_perform_seek),
+	  (gst_wavparse_stream_headers), (gst_wavparse_stream_data),
+	  (gst_wavparse_pad_convert), (gst_wavparse_srcpad_event),
+	  (gst_wavparse_sink_activate), (gst_wavparse_sink_activate_pull):
+	  Use DEBUG_OBJECT more.
+
+2006-02-28 10:22:11 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  docs/plugins/: Added dvdec and dvdemux to docs.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  Added dvdec and dvdemux to docs.
+	  * ext/dv/gstdvdec.c: (gst_dvdec_base_init), (gst_dvdec_chain):
+	  Added docs.
+	  Check frame sizes so we don't crash when don't have enough
+	  data.
+	  Send nice error messages on error.
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_base_init),
+	  (gst_dvdemux_class_init), (gst_dvdemux_init),
+	  (gst_dvdemux_finalize), (gst_dvdemux_reset),
+	  (gst_dvdemux_src_convert), (gst_dvdemux_sink_convert),
+	  (gst_dvdemux_src_query), (gst_dvdemux_sink_query),
+	  (gst_dvdemux_push_event), (gst_dvdemux_handle_sink_event),
+	  (gst_dvdemux_convert_src_pair), (gst_dvdemux_convert_sink_pair),
+	  (gst_dvdemux_convert_src_to_sink), (gst_dvdemux_handle_push_seek),
+	  (gst_dvdemux_do_seek), (gst_dvdemux_handle_pull_seek),
+	  (gst_dvdemux_handle_src_event), (gst_dvdemux_demux_audio),
+	  (gst_dvdemux_demux_video), (gst_dvdemux_demux_frame),
+	  (gst_dvdemux_flush), (gst_dvdemux_chain), (gst_dvdemux_loop),
+	  (gst_dvdemux_sink_activate_push), (gst_dvdemux_sink_activate_pull),
+	  (gst_dvdemux_sink_activate), (gst_dvdemux_change_state):
+	  * ext/dv/gstdvdemux.h:
+	  Added docs.
+	  Implement pull mode.
+	  Fix memleaks.
+	  Reduce memcpy for the video demuxing.
+
+2006-02-28 09:21:27 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/annodex/: Add a little extra debug. Make the decoder not return NOT_LINKED, as we want to continue decoding all C...
+	  Original commit message from CVS:
+	  * ext/annodex/gstcmmldec.c: (gst_cmml_dec_sink_event),
+	  (gst_cmml_dec_new_buffer), (gst_cmml_dec_parse_preamble),
+	  (gst_cmml_dec_parse_head), (gst_cmml_dec_push_clip):
+	  * ext/annodex/gstcmmlparser.c: (gst_cmml_parser_parse_chunk):
+	  Add a little extra debug. Make the decoder not return NOT_LINKED,
+	  as we want to continue decoding all CMML and emitting tags.
+
+2006-02-27 14:37:29 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  add annodex plugin
+	  Original commit message from CVS:
+	  add annodex plugin
+
+2006-02-27 14:00:18 +0000  Michael Smith <msmith@xiph.org>
+
+	  ext/annodex/gstskeltag.*: Deleted; these files aren't used any more either.
+	  Original commit message from CVS:
+	  * ext/annodex/gstskeltag.c:
+	  * ext/annodex/gstskeltag.h:
+	  Deleted; these files aren't used any more either.
+
+2006-02-25 20:37:29 +0000  Julien Moutte <julien@moutte.net>
+
+	  ext/Makefile.am: Fix dist-check.
+	  Original commit message from CVS:
+	  2006-02-25  Julien MOUTTE  <julien@moutte.net>
+	  * ext/Makefile.am: Fix dist-check.
+
+2006-02-25 19:36:24 +0000  Julien Moutte <julien@moutte.net>
+
+	  ext/annodex/gstcmmlenc.c: Fix another memleak.
+	  Original commit message from CVS:
+	  2006-02-25  Julien MOUTTE  <julien@moutte.net>
+	  * ext/annodex/gstcmmlenc.c: (gst_cmml_enc_push_clip): Fix another
+	  memleak.
+
+2006-02-25 19:07:41 +0000  Julien Moutte <julien@moutte.net>
+
+	  Fix a memleak in gst_cmml_track_list_add_clip.
+	  Original commit message from CVS:
+	  2006-02-25  Alessandro Decina <alessandro@nnva.org>
+	  * ext/annodex/Makefile.am:
+	  * ext/annodex/gstannodex.c:
+	  * ext/annodex/gstcmmldec.c:
+	  * ext/annodex/gstcmmlenc.c:
+	  * ext/annodex/gstcmmlparser.c:
+	  * ext/annodex/gstcmmlparser.h:
+	  * ext/annodex/gstcmmlutils.c:
+	  * tests/check/elements/cmmldec.c:
+	  * tests/check/elements/cmmlenc.c:
+	  Fix a memleak in gst_cmml_track_list_add_clip.
+	  Handle overflows in clip's start and end times.
+	  Add the "encoded" parameter to cmmldec and cmmlenc caps.
+	  Do not parse junk at the end of a CMML preamble buffer.
+	  Register a libxml error handler to not print stuff on stderr.
+	  Check for bad clip start and end times in the testsuites.
+
+2006-02-25 11:37:10 +0000  Julien Moutte <julien@moutte.net>
+
+	  ext/annodex/: Fix possible memleaks.
+	  Original commit message from CVS:
+	  2006-02-25  Julien MOUTTE  <julien@moutte.net>
+	  * ext/annodex/gstcmmldec.c: (gst_cmml_dec_class_init),
+	  (gst_cmml_dec_finalize), (gst_cmml_dec_change_state):
+	  * ext/annodex/gstcmmlenc.c: (gst_cmml_enc_class_init),
+	  (gst_cmml_enc_finalize), (gst_cmml_enc_change_state):
+	  * ext/annodex/gstcmmlutils.c: (gst_cmml_track_list_destroy): Fix
+	  possible memleaks.
+
+2006-02-24 23:52:28 +0000  Julien Moutte <julien@moutte.net>
+
+	  tests/check/: Fix tests so that they use the plugins-base tags.
+	  Original commit message from CVS:
+	  2006-02-25  Julien MOUTTE  <julien@moutte.net>
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/cmmldec.c:
+	  * tests/check/elements/cmmlenc.c: Fix tests so that they use
+	  the plugins-base tags.
+
+2006-02-24 23:36:58 +0000  Julien Moutte <julien@moutte.net>
+
+	  ext/Makefile.am: Re-enable module.
+	  Original commit message from CVS:
+	  2006-02-25  Julien MOUTTE  <julien@moutte.net>
+	  * ext/Makefile.am: Re-enable module.
+
+2006-02-24 23:32:14 +0000  Julien Moutte <julien@moutte.net>
+
+	  tests/check/Makefile.am: Forgot to remove that test.
+	  Original commit message from CVS:
+	  2006-02-25  Julien MOUTTE  <julien@moutte.net>
+	  * tests/check/Makefile.am: Forgot to remove that test.
+
+2006-02-24 23:31:08 +0000  Julien Moutte <julien@moutte.net>
+
+	  Try to fix Annodex plugin.
+	  Original commit message from CVS:
+	  2006-02-25  Julien MOUTTE  <julien@moutte.net>
+	  * ext/annodex/Makefile.am:
+	  * ext/annodex/gstannodex.c: (plugin_init):
+	  * ext/annodex/gstcmmldec.c:
+	  * ext/annodex/gstskeldec.c:
+	  * ext/annodex/gstskeldec.h:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/skeldec.c: Try to fix Annodex plugin.
+
+2006-02-24 23:06:27 +0000  Julien Moutte <julien@moutte.net>
+
+	  tests/check/Makefile.am: Disable those checks as well.
+	  Original commit message from CVS:
+	  2006-02-25  Julien MOUTTE  <julien@moutte.net>
+	  * tests/check/Makefile.am: Disable those checks as well.
+
+2006-02-24 22:49:29 +0000  Julien Moutte <julien@moutte.net>
+
+	  ext/Makefile.am: Disable annodex for now until we figure out how to make it build.
+	  Original commit message from CVS:
+	  2006-02-24  Julien MOUTTE  <julien@moutte.net>
+	  * ext/Makefile.am: Disable annodex for now until we figure out
+	  how to make it build.
+	  * ext/gdk_pixbuf/Makefile.am: Note for Thomas :
+	  Add a rule to your checklist : "please try to at least build
+	  what you are going to commit into -good, or if you are too lazy
+	  to do that, please check that the buildbots are not crying because
+	  of your commit."
+
+2006-02-24 19:51:29 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/gdk_pixbuf/Makefile.am:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.h:
+	* ext/gdk_pixbuf/pixbufscale.c:
+	* ext/gdk_pixbuf/pixbufscale.h:
+	  I'm too lazy to comment this
+	  Original commit message from CVS:
+	  Gdkpixbuf ported from 0.8 to 0.10 by Renato Filho <renato.filho@indt.org.br>. gst_loader and gdkpixbufanimation still need port.
+
+2006-02-24 19:49:32 +0000  Fabrizio Gennari <fabrizio.ge@tiscali.it>
+
+	  gst/qtdemux/qtdemux.c: Add support for palettised Apple SMC videos (#327075, based on
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_add_stream),
+	  (qtdemux_parse_trak), (qtdemux_video_caps):
+	  Add support for palettised Apple SMC videos (#327075, based on
+	  patch by: Fabrizio Gennari <fabrizio dot ge at tiscali dot it>).
+
+2006-02-24 19:07:10 +0000  Michael Smith <msmith@xiph.org>
+
+	  Add Annodex elements from Alessendro Decina: skeleton and CMML.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * ext/Makefile.am:
+	  * ext/annodex/Makefile.am:
+	  * ext/annodex/gstannodex.c:
+	  * ext/annodex/gstannodex.h:
+	  * ext/annodex/gstcmmldec.c:
+	  * ext/annodex/gstcmmldec.h:
+	  * ext/annodex/gstcmmlenc.c:
+	  * ext/annodex/gstcmmlenc.h:
+	  * ext/annodex/gstcmmlparser.c:
+	  * ext/annodex/gstcmmlparser.h:
+	  * ext/annodex/gstcmmltag.c:
+	  * ext/annodex/gstcmmltag.h:
+	  * ext/annodex/gstcmmlutils.c:
+	  * ext/annodex/gstcmmlutils.h:
+	  * ext/annodex/gstskeldec.c:
+	  * ext/annodex/gstskeldec.h:
+	  * ext/annodex/gstskeltag.c:
+	  * ext/annodex/gstskeltag.h:
+	  * tests/check/Makefile.am:
+	  * tests/check/elements/cmmldec.c:
+	  * tests/check/elements/cmmlenc.c:
+	  * tests/check/elements/skeldec.c:
+	  Add Annodex elements from Alessendro Decina: skeleton and CMML.
+	  Includes tests & docs, oh my! Passes Thomas's -good checklist
+	  entirely. Wow.
+
+2006-02-24 17:09:56 +0000  Michael Smith <msmith@xiph.org>
+
+	  autogen.sh: Check for automake 1.9 as well.
+	  Original commit message from CVS:
+	  * autogen.sh:
+	  Check for automake 1.9 as well.
+
+2006-02-24 14:49:48 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacenc.c: Change min. sample rate to 8kHz to match flacdec's.
+	  Original commit message from CVS:
+	  * ext/flac/gstflacenc.c:
+	  Change min. sample rate to 8kHz to match flacdec's.
+
+2006-02-23 20:08:58 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/cdio/Makefile.am: Add GST_BASE_CFLAGS and GST_BASE_LIBS (seems to be required for Cygwin, see #317048)
+	  Original commit message from CVS:
+	  * ext/cdio/Makefile.am:
+	  Add GST_BASE_CFLAGS and GST_BASE_LIBS (seems to be
+	  required for Cygwin, see #317048)
+	  * gst/rtp/gstasteriskh263.c:
+	  Cygwin has includes for both the unix network socket API
+	  and the windows API, but only one can be included, so fix
+	  includes to only use one or the other, prefering the unxi
+	  one (#317048).
+
+2006-02-23 12:21:25 +0000  Philippe Kalaf <philippe.kalaf@collabora.co.uk>
+
+	  rtp/gst/: Separated the G711 payloaders/depayloaders into separate elements for mulaw/alaw. Also removed the old g711...
+	  Original commit message from CVS:
+	  2006-02-23  Philippe Kalaf  <philippe.kalaf at collabora.co.uk>
+	  * rtp/gst/gstrtppcmadepay.c:
+	  * rtp/gst/gstrtppcmadepay.h:
+	  * rtp/gst/gstgstrtppcmapay.c:
+	  * rtp/gst/gstgstrtppcmapay.h:
+	  * rtp/gst/gstrtppcmudepay.c:
+	  * rtp/gst/gstrtppcmudepay.h:
+	  * rtp/gst/gstrtppcmupay.c:
+	  * rtp/gst/gstrtppcmupay.h:
+	  * rtp/gst/Makefile.am:
+	  * rtp/gst/gstrtp.c:
+	  * rtp/gst/README:
+	  Separated the G711 payloaders/depayloaders into separate elements for
+	  mulaw/alaw. Also removed the old g711 payloaders/depayloaders.
+
+2006-02-22 20:22:25 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/dv/: Ueber spiffify some more, added debug category.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdec.c: (gst_dvdec_base_init), (gst_dvdec_init),
+	  (gst_dvdec_change_state):
+	  * ext/dv/gstdvdec.h:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_base_init), (gst_dvdemux_init),
+	  (gst_dvdemux_src_convert), (gst_dvdemux_sink_convert),
+	  (gst_dvdemux_src_query), (gst_dvdemux_sink_query),
+	  (gst_dvdemux_handle_sink_event), (gst_dvdemux_demux_frame),
+	  (gst_dvdemux_flush), (gst_dvdemux_chain),
+	  (gst_dvdemux_change_state):
+	  * ext/dv/gstdvdemux.h:
+	  Ueber spiffify some more, added debug category.
+	  Use _scale.
+	  Use segments, respect playback rate from newsegment.
+	  Fix refcount issue.
+
+2006-02-22 09:33:25 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Add 'dvsd' and 'dv25' to list of possible fourcc values for DV Video.
+	  Original commit message from CVS:
+	  Reviewed by : Edward Hervey <edward@fluendo.com>
+	  * gst/qtdemux/qtdemux.c: (qtdemux_video_caps):
+	  Add 'dvsd' and 'dv25' to list of possible fourcc values for DV Video.
+	  Add image/png for fourcc 'png '
+
+2006-02-20 21:19:59 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Port ximagesrc to 0.10 (Closes #304795)
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * sys/Makefile.am:
+	  * sys/ximagesrc/Makefile.am:
+	  * sys/ximagesrc/ximagesrc.c: (gst_ximagesrc_return_buf),
+	  (gst_ximagesrc_open_display), (gst_ximagesrc_start),
+	  (gst_ximagesrc_stop), (gst_ximagesrc_unlock),
+	  (gst_ximagesrc_recalc), (composite_pixel),
+	  (gst_ximagesrc_ximage_get), (gst_ximagesrc_create),
+	  (gst_ximagesrc_set_property), (gst_ximagesrc_get_property),
+	  (gst_ximagesrc_clear_bufpool), (gst_ximagesrc_base_init),
+	  (gst_ximagesrc_dispose), (gst_ximagesrc_finalize),
+	  (gst_ximagesrc_get_caps), (gst_ximagesrc_set_caps),
+	  (gst_ximagesrc_fixate), (gst_ximagesrc_class_init),
+	  (gst_ximagesrc_init), (plugin_init):
+	  * sys/ximagesrc/ximagesrc.h:
+	  * sys/ximagesrc/ximageutil.c: (ximageutil_handle_xerror),
+	  (ximageutil_check_xshm_calls), (ximageutil_xcontext_get),
+	  (ximageutil_xcontext_clear),
+	  (ximageutil_calculate_pixel_aspect_ratio),
+	  (gst_ximagesrc_buffer_finalize), (gst_ximage_buffer_free),
+	  (gst_ximagesrc_buffer_init), (gst_ximagesrc_buffer_class_init),
+	  (gst_ximagesrc_buffer_get_type), (gst_ximageutil_ximage_new),
+	  (gst_ximageutil_ximage_destroy):
+	  * sys/ximagesrc/ximageutil.h:
+	  Port ximagesrc to 0.10 (Closes #304795)
+
+=== release 0.10.1 ===
+
+2006-02-20 19:12:10 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: releasing 0.10.1, "Slimy - yet satisfying"
+	  Original commit message from CVS:
+	  2006-02-20  Jan Schmidt <thaytan@mad.scientist.com>
+	  * configure.ac:
+	  releasing 0.10.1, "Slimy - yet satisfying"
+
+2006-02-20 13:08:50 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/ladspa/gstsignalprocessor.c: Fix compilation of LADPSA. It doesn't seem to work, and isn't enabled for the build,...
+	  Original commit message from CVS:
+	  * ext/ladspa/gstsignalprocessor.c: (gst_signal_processor_event),
+	  (gst_signal_processor_process):
+	  Fix compilation of LADPSA. It doesn't seem to work, and isn't
+	  enabled for the build, but it helps me win the feature-count
+	  competitions ooh yeah.
+
+2006-02-19 16:02:25 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: Use scaling code for added precission and more correct stop position in case scale==0.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_src_convert),
+	  (gst_avi_demux_handle_src_query), (gst_avi_demux_handle_src_event),
+	  (gst_avi_demux_parse_file_header), (gst_avi_demux_stream_init),
+	  (gst_avi_demux_parse_avih), (gst_avi_demux_parse_superindex),
+	  (gst_avi_demux_parse_subindex), (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_stream_header), (gst_avi_demux_change_state):
+	  Use scaling code for added precission and more correct stop
+	  position in case scale==0.
+
+2006-02-19 12:09:19 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/flx/gstflxdec.*: Implement DURATION query.
+	  Original commit message from CVS:
+	  * gst/flx/gstflxdec.c: (gst_flxdec_src_query_handler),
+	  (gst_flxdec_chain):
+	  * gst/flx/gstflxdec.h:
+	  Implement DURATION query.
+
+2006-02-19 11:57:58 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/flx/: Set MALLOCDATA for the temp buffers so we don't leak.
+	  Original commit message from CVS:
+	  * gst/flx/flx_color.h:
+	  * gst/flx/flx_fmt.h:
+	  * gst/flx/gstflxdec.c: (gst_flxdec_init),
+	  (gst_flxdec_src_query_handler), (flx_decode_color),
+	  (gst_flxdec_chain):
+	  * gst/flx/gstflxdec.h:
+	  Set MALLOCDATA for the temp buffers so we don't leak.
+	  Some debug cleanups.
+	  Consume all data in the adapter before leaving the chain
+	  function. Fixes #330678.
+
+2006-02-18 20:48:09 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/id3demux/: Handle 0 data size in otherwise valid frames.
+	  Original commit message from CVS:
+	  * gst/id3demux/id3tags.c: (id3demux_id3v2_frames_to_tag_list):
+	  * gst/id3demux/id3v2frames.c: (id3v2_genre_fields_to_taglist):
+	  Handle 0 data size in otherwise valid frames.
+	  Handle numeric strings in 2.4.0 even when not in parentheses
+
+2006-02-18 17:20:48 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/: Recognise SSA/ASS and USF subtitle formats and set proper caps when they are found.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_subtitle_caps),
+	  (gst_matroska_demux_plugin_init):
+	  * gst/matroska/matroska-ids.h:
+	  Recognise SSA/ASS and USF subtitle formats and
+	  set proper caps when they are found.
+
+2006-02-17 18:25:42 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Don't GST_LOG timestamps from nonexistent index entries (#331582).
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_state_movie):
+	  Don't GST_LOG timestamps from nonexistent index
+	  entries (#331582).
+
+2006-02-17 17:54:05 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/jpeg/gstjpegdec.c: Fix invalid memory access for some odd-sized images (see image contained in quicktime stream i...
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_decode_direct),
+	  (gst_jpeg_dec_chain):
+	  Fix invalid memory access for some odd-sized images
+	  (see image contained in quicktime stream in #327083);
+	  use g_malloc() instead of g_alloca().
+
+2006-02-17 16:28:29 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Check that the size of the returned buffer is of the correct size because the parser assumes t...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_state_header):
+	  Check that the size of the returned buffer is of the correct size
+	  because the parser assumes that.
+	  Fixes #331543.
+
+2006-02-17 15:37:38 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpamrdepay.c: Patch from Sebastien Cote, fixes #319884
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_chain):
+	  Patch from Sebastien Cote, fixes #319884
+
+2006-02-17 11:19:34 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/cdio/gstcdio.c: Init debug category (#331253).
+	  Original commit message from CVS:
+	  * ext/cdio/gstcdio.c: (plugin_init):
+	  Init debug category (#331253).
+
+2006-02-17 10:53:38 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* ext/gconf/gconf.c:
+	* ext/gconf/gconf.h:
+	* ext/gconf/gstgconfaudiosink.c:
+	* ext/gconf/gstgconfaudiosink.h:
+	* gconf/gstreamer.schemas.in:
+	* gst-plugins-good.spec.in:
+	  add Jurg's patch for multidevice support
+	  Original commit message from CVS:
+	  add Jurg's patch for multidevice support
+
+2006-02-16 20:30:13 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/wavparse/gstwavparse.c: Pass extra_data to gst_riff_create_audio_caps(), so that
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_stream_headers):
+	  Pass extra_data to gst_riff_create_audio_caps(), so that
+	  WAVEFORMATEX stuff works. Post audio codec name and post
+	  it as taglist on the bus. Allow up to 8 channesl for raw
+	  PCM in the source pad template caps.
+
+2006-02-16 16:53:52 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/multipart/multipartdemux.c: Applied #318663. Gives quite a few false positives in autoscan mode, but it's better ...
+	  Original commit message from CVS:
+	  * gst/multipart/multipartdemux.c: (gst_multipart_demux_base_init),
+	  (gst_multipart_demux_class_init), (gst_multipart_demux_init),
+	  (gst_multipart_demux_finalize), (gst_multipart_find_pad_by_mime),
+	  (gst_multipart_demux_chain), (gst_multipart_demux_change_state),
+	  (gst_multipart_set_property), (gst_multipart_get_property):
+	  Applied #318663. Gives quite a few false positives in
+	  autoscan mode, but it's better than nothing. Not closing yet.
+
+2006-02-16 14:13:48 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  Update documentation.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/inspect/plugin-udp.xml:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init), (gst_udpsrc_init),
+	  (gst_udpsrc_start):
+	  Update documentation.
+	  Fix args.
+
+2006-02-16 14:02:57 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Don't stop the task if the pad isn't linked.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_handle_src_event),
+	  (gst_qtdemux_loop), (qtdemux_sink_activate_pull):
+	  Don't stop the task if the pad isn't linked.
+
+2006-02-16 10:58:18 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/id3demux/id3tags.c: ID3 2.3.0 used synch-safe integers for the tag size, but not for the frame size. (Fixes #331368)
+	  Original commit message from CVS:
+	  * gst/id3demux/id3tags.c: (id3demux_id3v2_frames_to_tag_list):
+	  ID3 2.3.0 used synch-safe integers for the tag size, but not for the
+	  frame size. (Fixes #331368)
+
+2006-02-16 10:42:25 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/README: Updated README.
+	  Original commit message from CVS:
+	  * gst/rtsp/README:
+	  Updated README.
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_get_type),
+	  (gst_rtspsrc_class_init), (gst_rtspsrc_set_property),
+	  (gst_rtspsrc_get_property), (gst_rtspsrc_stream_setup_rtp):
+	  * gst/rtsp/gstrtspsrc.h:
+	  Make sure the RTP port is an even port an try to allocate
+	  another if not.
+	  Added retry property to control max retries for port allocation.
+	  Make sure RTCP port is RTP port+1.
+	  Cleanup when port allocation fails.
+	  Fixes #319183.
+
+2006-02-16 09:17:58 +0000  Wouter Paesen <wouter@kangaroot.net>
+
+	  gst/alpha/gstalpha.c: Don't ignore return value of the parent class's state
+	  Original commit message from CVS:
+	  * gst/alpha/gstalpha.c: (gst_alpha_change_state):
+	  Don't ignore return value of the parent class's state
+	  change function (#331385, patch by: Wouter Paesen).
+
+2006-02-15 12:17:28 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  Add HAL sound device wrapper plugins. Closes #329106
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * ext/Makefile.am:
+	  * ext/hal/Makefile.am:
+	  * ext/hal/gsthalaudiosink.c: (gst_hal_audio_sink_base_init),
+	  (gst_hal_audio_sink_class_init), (gst_hal_audio_sink_reset),
+	  (gst_hal_audio_sink_init), (gst_hal_audio_sink_dispose),
+	  (do_toggle_element), (gst_hal_audio_sink_set_property),
+	  (gst_hal_audio_sink_get_property),
+	  (gst_hal_audio_sink_change_state):
+	  * ext/hal/gsthalaudiosink.h:
+	  * ext/hal/gsthalaudiosrc.c: (gst_hal_audio_src_base_init),
+	  (gst_hal_audio_src_class_init), (gst_hal_audio_src_reset),
+	  (gst_hal_audio_src_init), (gst_hal_audio_src_dispose),
+	  (do_toggle_element), (gst_hal_audio_src_set_property),
+	  (gst_hal_audio_src_get_property), (gst_hal_audio_src_change_state):
+	  * ext/hal/gsthalaudiosrc.h:
+	  * ext/hal/gsthalelements.c: (plugin_init):
+	  * ext/hal/gsthalelements.h:
+	  * ext/hal/hal.c: (gst_hal_get_string),
+	  (gst_hal_render_bin_from_udi), (gst_hal_get_audio_sink),
+	  (gst_hal_get_audio_src):
+	  * ext/hal/hal.h:
+	  Add HAL sound device wrapper plugins. Closes #329106
+
+2006-02-15 12:13:47 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: It appears 100% equals 1/1 and not 100/1 ...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_chain):
+	  It appears 100% equals 1/1 and not 100/1 ...
+
+2006-02-15 10:15:47 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: Add comment in a fultile attempt to stop the copy-and-paste paradigm leading to duplication of...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_event):
+	  Add comment in a fultile attempt to stop the copy-and-paste
+	  paradigm leading to duplication of bad code.
+	  * gst/rtsp/rtsptransport.c: (rtsp_transport_parse):
+	  Mime parameters have to be checked case insensitive
+
+2006-02-15 09:45:27 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: When buffering MDAT data, show the user something is happening by posting 'buffering' messages...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_post_buffering),
+	  (gst_qtdemux_chain):
+	  When buffering MDAT data, show the user something is
+	  happening by posting 'buffering' messages on the bus.
+
+2006-02-14 23:23:08 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-demux.c: Advance stream time for lagging subtitle streams by sending newsegment events with the...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_sync_streams):
+	  Advance stream time for lagging subtitle streams by sending
+	  newsegment events with the update flag set.
+
+2006-02-14 18:50:13 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.*: Make push-based work if mdat atom is before moov atom.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_init),
+	  (gst_qtdemux_handle_src_query), (gst_qtdemux_change_state),
+	  (next_entry_size), (gst_qtdemux_chain):
+	  * gst/qtdemux/qtdemux.h:
+	  Make push-based work if mdat atom is before moov atom.
+	  Don't answer duration query. This should be transformed into replying
+	  FALSE to seek events.
+
+2006-02-14 16:58:30 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/avi/gstavidemux.c: There can be bogus data before the hdrl LIST tag in the RIFF header.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_stream_header):
+	  There can be bogus data before the hdrl LIST tag in the RIFF header.
+	  It's hard to say if it's not respecting the AVI specifications or not,
+	  but since Google Video is producing AVIs like that and the other player
+	  don't seem to complain, I guess we should do the same.
+
+2006-02-14 11:24:53 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Handle the case where data atoms are before moov atoms in push-based mode.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (next_entry_size), (gst_qtdemux_chain):
+	  Handle the case where data atoms are before moov atoms in push-based mode.
+	  Errors out gracefully.
+
+2006-02-13 22:04:42 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/: QtDemux can now work push-based.
+	  Original commit message from CVS:
+	  * gst/qtdemux/Makefile.am:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_init),
+	  (gst_qtdemux_handle_sink_event), (gst_qtdemux_change_state),
+	  (extract_initial_length_and_fourcc),
+	  (gst_qtdemux_loop_state_header), (gst_qtdemux_loop_state_movie),
+	  (gst_qtdemux_loop_header), (next_entry_size), (gst_qtdemux_chain),
+	  (qtdemux_sink_activate), (qtdemux_sink_activate_pull),
+	  (qtdemux_sink_activate_push), (qtdemux_parse_trak):
+	  * gst/qtdemux/qtdemux.h:
+	  QtDemux can now work push-based.
+	  It still needs some love for seeking.
+
+2006-02-13 12:00:51 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/id3demux/id3v2frames.c: Add more validation to ensure that a char encoding conversion produced a valid UTF-8 string.
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (parse_insert_string_field),
+	  (parse_split_strings):
+	  Add more validation to ensure that a char encoding conversion
+	  produced a valid UTF-8 string.
+
+2006-02-13 10:43:15 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/avi/gstavidemux.c: Properly handle end of segment. Closes #330885.
+	  Original commit message from CVS:
+	  Reviewed by: Edward Hervey  <edward@fluendo.com>
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_process_next_entry):
+	  Properly handle end of segment. Closes #330885.
+
+2006-02-13 10:36:23 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmp4gpay.h: For got to commit this one.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4gpay.h:
+	  For got to commit this one.
+
+2006-02-12 18:59:36 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmp4gpay.*: Make more things work.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4gpay.c: (gst_rtp_mp4g_pay_class_init),
+	  (gst_rtp_mp4g_pay_init), (gst_rtp_mp4g_pay_parse_audio_config),
+	  (gst_rtp_mp4g_pay_parse_video_config), (gst_rtp_mp4g_pay_new_caps),
+	  (gst_rtp_mp4g_pay_setcaps), (gst_rtp_mp4g_pay_flush):
+	  * gst/rtp/gstrtpmp4gpay.h:
+	  Make more things work.
+	  Handle ACC config strings.
+
+2006-02-12 13:10:20 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  gst/rtp/gstrtpamrpay.c: set timestamps if no incoming timestamps set
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpamrpay.c: (gst_rtp_amr_pay_handle_buffer):
+	  set timestamps if no incoming timestamps set
+
+2006-02-11 13:54:26 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/apetag/gsttagdemux.c: ... and fix the very same leaks in GstTagDemux.
+	  Original commit message from CVS:
+	  * gst/apetag/gsttagdemux.c: (gst_tag_demux_get_upstream_size),
+	  (gst_tag_demux_do_typefind):
+	  ... and fix the very same leaks in GstTagDemux.
+
+2006-02-11 13:35:13 +0000  Jon Trowbridge <trow@ximian.com>
+
+	  gst/id3demux/gstid3demux.c:
+	  Original commit message from CVS:
+	  * gst/id3demux/gstid3demux.c: (id3demux_get_upstream_size),
+	  (gst_id3demux_do_typefind):
+	  Fix a couple of mem leaks. (Patch by Jonathan Matthew
+	  <jonathan at kaolin dot wh9 dot net>)
+
+2006-02-10 17:37:39 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmp4vpay.c: First set options, then set caps or else the baseclass will not know about the options, duh.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4vpay.c: (gst_rtp_mp4v_pay_setcaps):
+	  First set options, then set caps or else the baseclass
+	  will not know about the options, duh.
+
+2006-02-10 17:16:55 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmp4vpay.c: Don't waste time looking for a config string if we have codec_info on the incomming caps.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4vpay.c: (gst_rtp_mp4v_pay_class_init),
+	  (gst_rtp_mp4v_pay_setcaps):
+	  Don't waste time looking for a config string if we have codec_info
+	  on the incomming caps.
+
+2006-02-10 16:40:58 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/README: Say something about case-sensitivity of caps vs mime-attributes.
+	  Original commit message from CVS:
+	  * gst/rtp/README:
+	  Say something about case-sensitivity of caps vs mime-attributes.
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpamrpay.c: (gst_rtp_amr_pay_class_init),
+	  (gst_rtp_amr_pay_handle_buffer):
+	  * gst/rtp/gstrtpmp4gpay.c: (gst_rtp_mp4g_pay_get_type),
+	  (gst_rtp_mp4g_pay_base_init), (gst_rtp_mp4g_pay_class_init),
+	  (gst_rtp_mp4g_pay_init), (gst_rtp_mp4g_pay_finalize),
+	  (gst_rtp_mp4g_pay_new_caps), (gst_rtp_mp4g_pay_setcaps),
+	  (gst_rtp_mp4g_pay_flush), (gst_rtp_mp4g_pay_handle_buffer),
+	  (gst_rtp_mp4g_pay_set_property), (gst_rtp_mp4g_pay_get_property),
+	  (gst_rtp_mp4g_pay_plugin_init):
+	  * gst/rtp/gstrtpmp4gpay.h:
+	  Added beginnings of mpeg4-generic payloader (RFC 3640)
+
+2006-02-09 14:20:14 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/: Resurected rtpdec to make rtspsrc happy again.
+	  Original commit message from CVS:
+	  * gst/rtsp/Makefile.am:
+	  * gst/rtsp/gstrtpdec.c: (gst_rtpdec_get_type),
+	  (gst_rtpdec_class_init), (gst_rtpdec_init), (gst_rtpdec_getcaps),
+	  (gst_rtpdec_chain_rtp), (gst_rtpdec_chain_rtcp),
+	  (gst_rtpdec_set_property), (gst_rtpdec_get_property),
+	  (gst_rtpdec_change_state):
+	  * gst/rtsp/gstrtpdec.h:
+	  * gst/rtsp/gstrtsp.c: (plugin_init):
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_stream_configure_transport):
+	  * gst/rtsp/rtspconnection.c: (read_body),
+	  (rtsp_connection_receive):
+	  * gst/rtsp/rtspmessage.c: (rtsp_message_dump):
+	  Resurected rtpdec to make rtspsrc happy again.
+	  Skip attributes from the session id.
+	  Don't crash when dumping a message with an empty body.
+
+2006-02-09 14:14:07 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpamrdepay.c: Added more meaningfull warnings when something goes wrong.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_chain):
+	  Added more meaningfull warnings when something goes wrong.
+	  Clear F bit on outgoing AMR packets.
+	  * gst/rtp/gstrtpamrpay.c: (gst_rtp_amr_pay_class_init),
+	  (gst_rtp_amr_pay_handle_buffer):
+	  Added debugging category
+	  Support payloading of multiple AMR frames.
+	  * gst/rtp/gstrtpmp4vpay.c: (gst_rtp_mp4v_pay_depay_data):
+	  Added some debugging.
+
+2006-02-09 11:25:42 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Back to CVS
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Back to CVS
+
+=== release 0.10.2 ===
+
+2006-02-09 11:22:38 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-apetag.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cdio.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	  Releasing 0.10.2
+	  Original commit message from CVS:
+	  Releasing 0.10.2
+
+2006-02-08 17:35:05 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	  Update .po files
+	  Original commit message from CVS:
+	  Update .po files
+
+2006-02-08 17:18:20 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	  Oops, jumping the gun with the ChangeLog entry
+	  Original commit message from CVS:
+	  Oops, jumping the gun with the ChangeLog entry
+
+2006-02-08 17:16:46 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Bump core and plugins-base requirement to 0.10.2.2 for API additions (and 1 migration of gst_bin_find_u...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Bump core and plugins-base requirement to 0.10.2.2
+	  for API additions (and 1 migration of gst_bin_find_unconnected_pad)
+
+2006-02-08 17:12:40 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/: Register musicbrainz tags.
+	  Original commit message from CVS:
+	  * ext/flac/gstflac.c: (plugin_init):
+	  * ext/speex/gstspeex.c: (plugin_init):
+	  Register musicbrainz tags.
+
+2006-02-07 18:31:31 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/qtdemux/qtdemux.c:
+	  remove unused var
+	  Original commit message from CVS:
+	  remove unused var
+
+2006-02-07 18:01:17 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  gst/qtdemux/qtdemux.c: use the correct variable to check if we can calculate the last chunk.  Looks like an obvious b...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header),
+	  (qtdemux_parse_trak):
+	  use the correct variable to check if we can calculate
+	  the last chunk.  Looks like an obvious bug, and makes
+	  the dump of offsets comparable to other tools
+
+2006-02-07 17:54:42 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  gst/qtdemux/qtdemux.c: clean up some debugging, using _OBJECT, moving recurring messages to LOG level
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header),
+	  (qtdemux_parse_trak):
+	  clean up some debugging, using _OBJECT, moving recurring
+	  messages to LOG level
+
+2006-02-07 16:23:33 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/gconf/gconf.h: Remove declaration of function that no longer exists.
+	  Original commit message from CVS:
+	  * ext/gconf/gconf.h:
+	  Remove declaration of function that no longer exists.
+
+2006-02-07 13:39:08 +0000  Zaheer Abbas Merali <zaheerabbas@merali.org>
+
+	  ext/shout2/gstshout2.c: Make shout2 work for non ogg streams
+	  Original commit message from CVS:
+	  2006-02-07  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+	  * ext/shout2/gstshout2.c: (gst_shout2send_render),
+	  (gst_shout2send_setcaps), (gst_shout2send_change_state):
+	  Make shout2 work for non ogg streams
+
+2006-02-06 17:26:43 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/udp/gstmultiudpsink.*: Updated docs.
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_class_init),
+	  (gst_multiudpsink_render), (gst_multiudpsink_get_property),
+	  (gst_multiudpsink_init_send), (gst_multiudpsink_add),
+	  (gst_multiudpsink_remove), (gst_multiudpsink_clear),
+	  (gst_multiudpsink_get_stats), (gst_multiudpsink_change_state):
+	  * gst/udp/gstmultiudpsink.h:
+	  Updated docs.
+	  Added properties bytes-served, bytes_to_serve.
+	  Post proper error messages,
+	  Emit client added signal too.
+
+2006-02-06 15:41:25 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.*: Some QT demux loving.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_handle_src_query),
+	  (gst_qtdemux_handle_src_event), (gst_qtdemux_loop_header),
+	  (qtdemux_inflate), (qtdemux_parse), (qtdemux_parse_trak),
+	  (qtdemux_parse_udta), (qtdemux_tag_add_str), (qtdemux_tag_add_num),
+	  (qtdemux_tag_add_gnre), (gst_qtdemux_handle_esds),
+	  (qtdemux_video_caps), (qtdemux_audio_caps):
+	  * gst/qtdemux/qtdemux.h:
+	  Some QT demux loving.
+	  Handle seeking in a less broken way.
+	  Fix AMR caps to match the AMR decoder.
+	  Set first timestamp on AMR samples to 0 for now.
+	  Remove some \n in DEBUG strings.
+	  Use _scale_int for maximum precision.
+
+2006-02-06 15:31:16 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* common:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* gst/udp/gstmultiudpsink.c:
+	  adding docs for multiudpsink
+	  Original commit message from CVS:
+	  adding docs for multiudpsink
+
+2006-02-06 15:28:56 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  gst/level/gstlevel.c: peak below decay is not necessarily an error, so don't ERROR log
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c: (gst_level_transform_ip):
+	  peak below decay is not necessarily an error, so don't ERROR log
+
+2006-02-06 15:27:06 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	  cvs versions
+	  Original commit message from CVS:
+	  cvs versions
+
+2006-02-06 14:25:34 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/ebml-write.*: Make sure we send a newsegment event in BYTES format before sending buffers (#328531).
+	  Original commit message from CVS:
+	  * gst/matroska/ebml-write.c: (gst_ebml_write_reset),
+	  (gst_ebml_write_flush_cache), (gst_ebml_write_element_push),
+	  (gst_ebml_write_seek):
+	  * gst/matroska/ebml-write.h:
+	  Make sure we send a newsegment event in BYTES format
+	  before sending buffers (#328531).
+
+2006-02-06 12:18:45 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Pass unhandled queries upstream instead of just dropping them (#326446). Update query type arrays here and there.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_src_query),
+	  (gst_dvdemux_sink_query):
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_src_query):
+	  * ext/speex/gstspeexdec.c: (speex_get_query_types),
+	  (speex_dec_src_query):
+	  * ext/speex/gstspeexenc.c: (gst_speexenc_src_query),
+	  (gst_speexenc_sink_query):
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query):
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_get_src_query_types),
+	  (gst_matroska_demux_handle_src_query):
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_get_query_types),
+	  (gst_wavparse_pad_query):
+	  Pass unhandled queries upstream instead of just dropping
+	  them (#326446). Update query type arrays here and there.
+
+2006-02-06 11:57:52 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  tests/check/elements/matroskamux.c: Collectpads in core got changed and now also holds a reference to any pad that is...
+	  Original commit message from CVS:
+	  * tests/check/elements/matroskamux.c: (setup_src_pad):
+	  Collectpads in core got changed and now also holds a
+	  reference to any pad that is part of it. Fix refcount
+	  checks in test case accordingly.
+
+2006-02-06 11:41:43 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/apetag/gstapedemux.h: Fix include, for now GstTagDemux is in the apetag dir.
+	  Original commit message from CVS:
+	  * gst/apetag/gstapedemux.h:
+	  Fix include, for now GstTagDemux is in the apetag dir.
+
+2006-02-06 11:34:23 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  docs/plugins/: Add cdio plugin to docs.
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/inspect/plugin-cdio.xml:
+	  Add cdio plugin to docs.
+	  * ext/cdio/gstcdiocddasrc.c:
+	  Add gtk-doc blurb.
+	  * ext/cdio/gstcdio.c:
+	  The plugin is called 'cdio' not 'cddio'.
+
+2006-02-06 10:56:07 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Add APE tag demuxer (#325649).
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * docs/plugins/inspect/plugin-apetag.xml:
+	  * gst/apetag/Makefile.am:
+	  * gst/apetag/gstapedemux.c:
+	  * gst/apetag/gstapedemux.h:
+	  * gst/apetag/gsttagdemux.c:
+	  * gst/apetag/gsttagdemux.h:
+	  Add APE tag demuxer (#325649).
+
+2006-02-05 22:22:56 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/gconf/: Ignore changing the GConf key to "". Ignore GConf key updates that don't actually change the string.
+	  Original commit message from CVS:
+	  * ext/gconf/gconf.c: (gst_gconf_get_default_audio_sink),
+	  (gst_gconf_get_default_video_sink),
+	  (gst_gconf_get_default_audio_src),
+	  (gst_gconf_get_default_video_src):
+	  * ext/gconf/gconf.h:
+	  * ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_reset),
+	  (gst_gconf_audio_sink_init), (gst_gconf_audio_sink_dispose),
+	  (do_toggle_element):
+	  * ext/gconf/gstgconfaudiosink.h:
+	  * ext/gconf/gstgconfaudiosrc.c: (gst_gconf_audio_src_reset),
+	  (gst_gconf_audio_src_init), (gst_gconf_audio_src_dispose),
+	  (do_toggle_element):
+	  * ext/gconf/gstgconfaudiosrc.h:
+	  * ext/gconf/gstgconfvideosink.c: (gst_gconf_video_sink_reset),
+	  (gst_gconf_video_sink_init), (gst_gconf_video_sink_dispose),
+	  (do_toggle_element):
+	  * ext/gconf/gstgconfvideosink.h:
+	  * ext/gconf/gstgconfvideosrc.c: (gst_gconf_video_src_reset),
+	  (gst_gconf_video_src_init), (gst_gconf_video_src_dispose),
+	  (do_toggle_element):
+	  * ext/gconf/gstgconfvideosrc.h:
+	  Ignore changing the GConf key to "". Ignore GConf key updates
+	  that don't actually change the string.
+	  For now, ignore the GConf key when the state is > READY, as
+	  it breaks streaming. Sometime it will be nice to bring the
+	  new sink online even mid-stream, by sending NEWSEGMENT info
+	  and possibly prerolling.
+	  (Fixes #326736)
+
+2006-02-05 20:43:49 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/goom/: Make goom reentrant by moving all important static variables into instance structures.
+	  Original commit message from CVS:
+	  * gst/goom/filters.c: (zoomFilterNew), (calculatePXandPY),
+	  (setPixelRGB), (setPixelRGB_), (getPixelRGB), (getPixelRGB_),
+	  (zoomFilterSetResolution), (zoomFilterDestroy),
+	  (zoomFilterFastRGB), (pointFilter):
+	  * gst/goom/filters.h:
+	  * gst/goom/goom_core.c: (goom_init), (goom_set_resolution),
+	  (goom_update), (goom_close):
+	  * gst/goom/goom_core.h:
+	  * gst/goom/goom_tools.h:
+	  * gst/goom/graphic.c:
+	  * gst/goom/gstgoom.c: (gst_goom_class_init), (gst_goom_init),
+	  (gst_goom_dispose), (gst_goom_src_setcaps), (gst_goom_chain):
+	  * gst/goom/gstgoom.h:
+	  * gst/goom/lines.c: (goom_lines):
+	  * gst/goom/lines.h:
+	  Make goom reentrant by moving all important static variables
+	  into instance structures.
+	  (Fixes #329181)
+
+2006-02-04 15:41:43 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavidemux.*: Third attempt, use gst_pad_is_linked() this time.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_all_source_pads_unlinked),
+	  (gst_avi_demux_process_next_entry):
+	  * gst/avi/gstavidemux.h:
+	  Third attempt, use gst_pad_is_linked() this time.
+
+2006-02-04 13:30:12 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/id3demux/id3v2frames.c: Adjust for data length indicators when parsing (Fixes #329810)
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (id3demux_id3v2_parse_frame),
+	  (parse_split_strings):
+	  Adjust for data length indicators when parsing (Fixes #329810)
+	  Fix stupid bug parsing UTF-8 tag text.
+	  Output tag strings with multiple fields as multiple tags, so the
+	  app gets all the data.
+
+2006-02-03 20:05:20 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* ext/flac/gstflacenc.c:
+	  Fixed a bug add in last commit, where no event is send. Thanks Tim to show me.
+	  Original commit message from CVS:
+	  Fixed a bug add in last commit, where no event is send. Thanks Tim to show me.
+
+2006-02-03 18:07:35 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* ext/flac/gstflacenc.c:
+	* gst/matroska/ebml-read.c:
+	  Just make it compile with --disable-gst-debug.
+	  Original commit message from CVS:
+	  Just make it compile with --disable-gst-debug.
+
+2006-02-03 16:55:42 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  update spec file
+	  Original commit message from CVS:
+	  update spec file
+
+2006-02-03 13:06:24 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/id3demux/id3v2frames.c: Never output a tag with a null contents string.
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (parse_text_identification_frame),
+	  (id3v2_tag_to_taglist), (id3v2_genre_string_to_taglist),
+	  (id3v2_genre_fields_to_taglist):
+	  Never output a tag with a null contents string.
+
+2006-02-02 21:00:16 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavidemux.c: Only pause if all pads are unlinked AND we've tried to send data on all of them at least once.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_all_source_pads_unlinked):
+	  Only pause if all pads are unlinked AND we've tried to send data
+	  on all of them at least once.
+
+2006-02-02 12:29:24 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavidemux.c: Make loop function/task pause itself when all source pads are unlinked.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_all_source_pads_unlinked),
+	  (gst_avi_demux_process_next_entry), (gst_avi_demux_loop):
+	  Make loop function/task pause itself when all source pads are
+	  unlinked.
+
+2006-02-02 10:47:15 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Use new functions from core to render a bin from a string. Fixes build. Up requirements to core CVS.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * ext/gconf/gconf.c: (gst_gconf_render_bin_from_key):
+	  Use new functions from core to render a bin from a
+	  string. Fixes build. Up requirements to core CVS.
+
+2006-02-01 11:01:04 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/auparse/gstauparse.c: Don't push buffers into the adapter that we are going to push downstream again without fram...
+	  Original commit message from CVS:
+	  * gst/auparse/gstauparse.c: (gst_au_parse_chain):
+	  Don't push buffers into the adapter that we are going to
+	  push downstream again without framing anyway. Also, the
+	  adaptor takes ownership of buffers put into it (fixes
+	  auparse pushing invalid buffers for .au files with
+	  ADPCM contents). Finally, set caps on all outgoing buffers.
+
+2006-01-30 23:13:05 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/id3demux/: Someone should kick my butt. Remove ID3v1 tags from the end of the file.
+	  Original commit message from CVS:
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_chain),
+	  (gst_id3demux_read_id3v1), (gst_id3demux_sink_activate),
+	  (gst_id3demux_send_tag_event):
+	  * gst/id3demux/id3tags.c: (id3demux_read_id3v1_tag):
+	  Someone should kick my butt. Remove ID3v1 tags from the end of the
+	  file.
+	  Improve error messages. Send the TAG message as soon as we complete
+	  typefinding, instead of waiting until we send the first buffer.
+	  Downstream tag event is still sent before the first buffer.
+
+2006-01-29 20:07:49 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/wavpack/gstwavpackdec.c: Add debug category, use boilerplate macros, fix handling of widths of 32 bits.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_setcaps),
+	  (gst_wavpack_dec_base_init), (gst_wavpack_dec_dispose),
+	  (gst_wavpack_dec_class_init), (gst_wavpack_dec_sink_event),
+	  (gst_wavpack_dec_init), (gst_wavpack_dec_format_samples),
+	  (gst_wavpack_dec_chain), (gst_wavpack_dec_plugin_init):
+	  Add debug category, use boilerplate macros, fix handling
+	  of widths of 32 bits.
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_base_init),
+	  (gst_wavpack_parse_dispose), (gst_wavpack_parse_class_init),
+	  (gst_wavpack_parse_index_get_last_entry),
+	  (gst_wavpack_parse_index_get_entry_from_sample),
+	  (gst_wavpack_parse_index_append_entry), (gst_wavpack_parse_reset),
+	  (gst_wavpack_parse_src_query),
+	  (gst_wavpack_parse_scan_to_find_sample),
+	  (gst_wavpack_parse_send_newsegment),
+	  (gst_wavpack_parse_handle_seek_event),
+	  (gst_wavpack_parse_src_event), (gst_wavpack_parse_init),
+	  (gst_wavpack_parse_get_upstream_length),
+	  (gst_wavpack_parse_pull_buffer),
+	  (gst_wavpack_parse_create_src_pad), (gst_wavpack_parse_loop),
+	  (gst_wavpack_parse_change_state),
+	  (gst_wavepack_parse_sink_activate),
+	  (gst_wavepack_parse_sink_activate_pull),
+	  (gst_wavpack_parse_plugin_init):
+	  * ext/wavpack/gstwavpackparse.h:
+	  Rewrite a bit, mostly to fix flow logic and to make seeking work.
+	  Fix buffer/event refcounting. Add some debug statements. Add
+	  width of 32 to source pad template caps. Use boilerplate macros.
+
+2006-01-27 12:17:56 +0000  Andy Wingo <wingo@pobox.com>
+
+	  ext/dv/: Call dv_set_error_log (dv_decoder_t *, NULL); after dv_decoder_new to not have warings flooding stderr. this...
+	  Original commit message from CVS:
+	  2006-01-27  Jan Gerber  <j@bootlab.org>
+	  Reviewed by: Andy Wingo <wingo@pobox.com>
+	  * ext/dv/gstdvdec.c (gst_dvdec_change_state):
+	  * ext/dv/gstdvdemux.c (gst_dvdemux_change_state):
+	  Call dv_set_error_log (dv_decoder_t *, NULL); after dv_decoder_new
+	  to not have warings flooding stderr. this is the suggested way
+	  also used in dvgrab and kino. (#328336)
+
+2006-01-27 01:43:07 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  sys/oss/gstosssink.c: Free the device name string when finalised.
+	  Original commit message from CVS:
+	  * sys/oss/gstosssink.c: (gst_oss_sink_class_init),
+	  (gst_oss_sink_init), (gst_oss_sink_finalise):
+	  Free the device name string when finalised.
+
+2006-01-26 16:23:42 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Fix wrong memcpy source pointer.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_trak):
+	  Fix wrong memcpy source pointer.
+
+2006-01-25 22:05:28 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/id3demux/gstid3demux.c: Don't put function calls in g_return_if_fail() statements, or they'll be replaced with NO...
+	  Original commit message from CVS:
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_remove_srcpad):
+	  Don't put function calls in g_return_if_fail() statements,
+	  or they'll be replaced with NOOPs if someone compiles with
+	  G_DISABLE_CHECKS defined.
+
+2006-01-25 20:33:05 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	  changelog surgery
+	  Original commit message from CVS:
+	  changelog surgery
+
+2006-01-25 18:23:05 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/id3demux/id3v2frames.c: Never trust ANY information encoded in a media file, especially when it's giving you size...
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (id3demux_id3v2_parse_frame):
+	  Never trust ANY information encoded in a media file, especially
+	  when it's giving you sizes. (Fixes #328452)
+
+2006-01-24 18:03:46 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* gst/rtp/gstrtpg711pay.c:
+	  I'm too lazy to comment this
+	  Original commit message from CVS:
+	  Patch written by Kai Vehmanen <kai.vehmanen@nokia.com> applied. See bug #325148.
+
+2006-01-24 11:58:53 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: More coherent framerate setting on caps.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header),
+	  (gst_qtdemux_add_stream), (qtdemux_parse_trak):
+	  More coherent framerate setting on caps.
+	  If sample_size is available, use that for the samples' duration in
+	  the index. This enables single frame streams to work (and I imagine
+	  fixes some other cases).
+	  Tested on testsuite, no regression.
+
+2006-01-23 18:39:31 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/matroska/: Added recognition of Real Audio and Video streams in matroska demuxer.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_video_caps),
+	  (gst_matroska_demux_audio_caps), (gst_matroska_demux_plugin_init):
+	  * gst/matroska/matroska-ids.h:
+	  Added recognition of Real Audio and Video streams in matroska demuxer.
+
+2006-01-23 15:10:55 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Added codec recognition for: _ VP31 : video/x-vp3 _ AVDJ : image/jpeg _ dvcp, dvc  : video/x-d...
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_trak),
+	  (qtdemux_video_caps), (qtdemux_audio_caps):
+	  Added codec recognition for:
+	  _ VP31 : video/x-vp3
+	  _ AVDJ : image/jpeg
+	  _ dvcp, dvc  : video/x-dv, systemstream=(boolean)false
+	  _ 0x6d730017 : audio/x-adpcm, layout=(string)quicktime
+
+2006-01-23 14:32:47 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/id3demux/id3v2frames.c: Remove errant break statement, and fix compilation with older GCC.
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (id3v2_tag_to_taglist):
+	  Remove errant break statement, and fix compilation with
+	  older GCC.
+
+2006-01-23 12:04:12 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	  Mention that my last commit fixes #328241
+	  Original commit message from CVS:
+	  Mention that my last commit fixes #328241
+
+2006-01-23 11:06:34 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/sunaudio/: Export functions that are needed in other parts of the code, makes the mixer actually work; adjust mag...
+	  Original commit message from CVS:
+	  Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+	  * sys/sunaudio/gstsunaudiomixerctrl.c:
+	  * sys/sunaudio/gstsunaudiosink.c: (gst_sunaudiosink_init):
+	  Export functions that are needed in other parts of the code,
+	  makes the mixer actually work; adjust magic minimum buffer-time
+	  value from 3ms to 5ms to work around stuttering during mp3
+	  playback (#327765).
+
+2006-01-23 10:44:03 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-mux.c: Fix possible deadlock in matroska muxer (#327825).
+	  Original commit message from CVS:
+	  Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_best_pad),
+	  (gst_matroska_mux_write_data), (gst_matroska_mux_collected):
+	  Fix possible deadlock in matroska muxer (#327825).
+
+2006-01-23 09:59:03 +0000  Jens Granseuer <jensgr@gmx.net>
+
+	  C89 fixes: declare variables at the beginning of a block and
+	  Original commit message from CVS:
+	  * ext/libpng/gstpngenc.c: (gst_pngenc_chain):
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_invert):
+	  * gst/rtp/gstrtpmp4vdepay.c: (gst_rtp_mp4v_depay_setcaps):
+	  * gst/rtsp/sdpmessage.h:
+	  * gst/udp/gstdynudpsink.c: (gst_dynudpsink_render):
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_get_stats):
+	  C89 fixes: declare variables at the beginning of a block and
+	  make gcc-2.9x happy (#328264; patch by: Jens Granseuer
+	  <jensgr at gmx dot net>).
+
+2006-01-23 09:22:17 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/id3demux/: Rewrite parsing of text tags to handle multiple NULL terminated strings. Parse numeric genre strings a...
+	  Original commit message from CVS:
+	  * gst/id3demux/id3tags.c: (id3demux_read_id3v2_tag):
+	  * gst/id3demux/id3tags.h:
+	  * gst/id3demux/id3v2frames.c: (id3demux_id3v2_parse_frame),
+	  (parse_comment_frame), (parse_text_identification_frame),
+	  (id3v2_tag_to_taglist), (id3v2_are_digits),
+	  (id3v2_genre_string_to_taglist), (id3v2_genre_fields_to_taglist),
+	  (parse_split_strings), (free_tag_strings):
+	  Rewrite parsing of text tags to handle multiple NULL terminated
+	  strings. Parse numeric genre strings and ID3v2 type
+	  "(3)(6)Alternative" style genre strings.
+	  Parse dates that are only YYYY or YYYY-mm format.
+
+2006-01-21 11:43:53 +0000  Fabrizio <fabrizio.ge@tiscali.it>
+
+	  gst/qtdemux/qtdemux.c: 'twos' and 'sowt' fourcc can be 16bit or 8bit audio.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_trak),
+	  (qtdemux_audio_caps):
+	  'twos' and 'sowt' fourcc can be 16bit or 8bit audio.
+	  Fix 8bit case (#327133, based on patch by: Fabrizio
+	  Gennari <fabrizio dot ge at tiscali dot it>).
+	  Also, "G_LITTLE_ENDIAN" and "G_BIG_ENDIAN" are not
+	  valid literals for endianness in caps strings,
+	  only "LITTLE_ENDIAN" and "BIG_ENDIAN" are valid.
+
+2006-01-20 15:06:28 +0000  Christoph Burghardt <hawkes@web.de>
+
+	  gst/videobox/gstvideobox.c: Don't forget to initialize liboil, otherwise our oil functions
+	  Original commit message from CVS:
+	  * gst/videobox/gstvideobox.c: (gst_video_box_class_init):
+	  Don't forget to initialize liboil, otherwise our oil functions
+	  will crash (fixes #327871; patch by: Christoph Burghardt
+	  <hawkes at web dot de>).
+
+2006-01-19 21:46:32 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	* ChangeLog:
+	  ChangeLog surgery (last entry may have been slightly misleading)
+	  Original commit message from CVS:
+	  ChangeLog surgery (last entry may have been slightly misleading)
+
+2006-01-19 21:00:50 +0000  Brian Cameron <brian.cameron@sun.com>
+
+	  configure.ac: just like in the core and gst-plugins-base. Fixes build on Solaris (fixes
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Use plain AS_LIBTOOL_TAGS instead of AS_LIBTOOL_TAGS([CXX]), just
+	  like in the core and gst-plugins-base. Fixes build on Solaris (fixes
+	  #326683; patch by: Brian Cameron <brian dot cameron at sun dot com>)
+
+2006-01-19 00:10:51 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/cdio/: Fix build for libcdio versions >= 76; give slightly lower rank than cdparanoia.
+	  Original commit message from CVS:
+	  * ext/cdio/gstcdio.c: (gst_cdio_add_cdtext_field), (plugin_init):
+	  * ext/cdio/gstcdio.h:
+	  * ext/cdio/gstcdiocddasrc.c: (gst_cdio_cdda_src_get_cdtext):
+	  Fix build for libcdio versions >= 76; give slightly lower rank
+	  than cdparanoia.
+
+2006-01-18 19:30:36 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Port libcdio cdda source, formerly known as cddasrc, now known as cdiocddasrc (fixes #323327). Should also read CD-TE...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * ext/Makefile.am:
+	  * ext/cdio/Makefile.am:
+	  * ext/cdio/gstcdio.c:
+	  * ext/cdio/gstcdio.h:
+	  * ext/cdio/gstcdiocddasrc.c:
+	  * ext/cdio/gstcdiocddasrc.h:
+	  Port libcdio cdda source, formerly known as cddasrc, now known as
+	  cdiocddasrc (fixes #323327). Should also read CD-TEXT if available,
+	  but that's not tested (fixes #317658).
+
+2006-01-18 19:08:08 +0000  Tommi Myöhänen <ext-tommi.myohanen@nokia.com>
+
+	  gst/wavparse/gstwavparse.c: Fix conversion from TIME to BYTES format (fixes #326864;
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_pad_convert):
+	  Fix conversion from TIME to BYTES format (fixes #326864;
+	  patch by: Tommi Myöhänen <ext-tommi dot myohanen at nokia dot com>)
+
+2006-01-18 18:54:02 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* gst/qtdemux/qtdemux.c:
+	  Ronald's patch applied. see bug #326318.
+	  Original commit message from CVS:
+	  Ronald's patch applied. see bug #326318.
+
+2006-01-17 16:45:43 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.*: Fix seeking for quicktime files. Could still use some more love and sophistication.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_init),
+	  (gst_qtdemux_send_event), (gst_qtdemux_handle_src_event),
+	  (gst_qtdemux_change_state), (gst_qtdemux_loop_header):
+	  * gst/qtdemux/qtdemux.h:
+	  Fix seeking for quicktime files. Could still use some more
+	  love and sophistication.
+
+2006-01-16 10:23:47 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  update with love
+	  Original commit message from CVS:
+	  update with love
+
+2006-01-15 20:21:48 +0000  Sergey Scobich <sergey.scobich@gmail.com>
+
+	  gst/id3demux/id3v2frames.c: Fix compilation of id3demux when zlib is not present.
+	  Original commit message from CVS:
+	  * gst/id3demux/id3v2frames.c: (id3demux_id3v2_parse_frame):
+	  Fix compilation of id3demux when zlib is not present.
+	  (Fixes #326602; patch by: Sergey Scobich)
+
+2006-01-15 14:12:12 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/esd/Makefile.am: otherwise build will fail for folks with libesd in a non-standard prefix (#327009).
+	  Original commit message from CVS:
+	  * ext/esd/Makefile.am:
+	  Add $(ESD_CFLAGS), otherwise build will fail for folks
+	  with libesd in a non-standard prefix (#327009).
+
+2006-01-13 19:29:27 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* configure.ac:
+	  back to head
+	  Original commit message from CVS:
+	  back to head
+
+2006-01-13 19:25:40 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* docs/upload.mak:
+	  releasing 0.10.1
+	  Original commit message from CVS:
+	  releasing 0.10.1
+
+2006-01-13 18:37:13 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/jpeg/gstsmokeenc.c: fix memleak.  Fixes #326618
+	  Original commit message from CVS:
+	  patch by: Wim Taymans
+	  * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_chain):
+	  fix memleak.  Fixes #326618
+
+2006-01-13 18:35:00 +0000  Mike Smith <msmith@xiph.org>
+
+	  gst/level/gstlevel.c: Fix memleak.  Fixes #326612
+	  Original commit message from CVS:
+	  2006-01-13  Thomas Vander Stichele  <thomas at apestaart dot org>
+	  patch by: Mike Smith
+	  * gst/level/gstlevel.c: (gst_level_message_new),
+	  (gst_level_message_append_channel):
+	  Fix memleak.  Fixes #326612
+
+2006-01-11 11:39:10 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  configure.ac: prereleasing
+	  Original commit message from CVS:
+	  * configure.ac:
+	  prereleasing
+	  * po/af.po:
+	  * po/az.po:
+	  * po/cs.po:
+	  * po/en_GB.po:
+	  * po/hu.po:
+	  * po/it.po:
+	  * po/nb.po:
+	  * po/nl.po:
+	  * po/or.po:
+	  * po/sq.po:
+	  * po/sr.po:
+	  * po/sv.po:
+	  * po/uk.po:
+	  * po/vi.po:
+	  update translations
+
+2006-01-11 11:04:03 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Add support for Indeo3 video in Quicktime files.
+	  Original commit message from CVS:
+	  reviewed by: Edward Hervey  <edward@fluendo.com>
+	  * gst/qtdemux/qtdemux.c: (qtdemux_video_caps):
+	  Add support for Indeo3 video in Quicktime files.
+	  Closes #326524
+
+2006-01-10 12:38:59 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/level/gstlevel.c: Don't leak filter arrays.
+	  Original commit message from CVS:
+	  * gst/level/gstlevel.c: (gst_level_class_init),
+	  (gst_level_dispose):
+	  Don't leak filter arrays.
+
+2006-01-09 17:04:52 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* ChangeLog:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/upload.mak:
+	* gst-plugins-good.spec.in:
+	* sys/Makefile.am:
+	* sys/sunaudio/Makefile.am:
+	* sys/sunaudio/gstsunaudio.c:
+	* sys/sunaudio/gstsunaudiomixer.c:
+	* sys/sunaudio/gstsunaudiomixer.h:
+	* sys/sunaudio/gstsunaudiomixerctrl.c:
+	* sys/sunaudio/gstsunaudiomixerctrl.h:
+	* sys/sunaudio/gstsunaudiomixertrack.c:
+	* sys/sunaudio/gstsunaudiomixertrack.h:
+	* sys/sunaudio/gstsunaudiosink.c:
+	* sys/sunaudio/gstsunaudiosink.h:
+	  add Sun Audio plugin. Verified that nothing breaks and that make check works.
+	  Original commit message from CVS:
+	  add Sun Audio plugin. Verified that nothing breaks and that make check works.
+	  Don't think the docs gets properly built yet, but I don't understand exactly how to enable that.
+
+2006-01-07 20:01:09 +0000  Philippe Kalaf <philippe.kalaf@collabora.co.uk>
+
+	  gst-plugins-good/gst/udp/: Allow udpsrc and dynudpsink to take a sockfd as a parameter. For udpsrc, overrides the por...
+	  Original commit message from CVS:
+	  2005-01-07  Philippe Khalaf  <philippe.kalaf@collabora.co.uk>
+	  * gst-plugins-good/gst/udp/gstdynudpsink.c:
+	  * gst-plugins-good/gst/udp/gstudpsrc.c:
+	  Allow udpsrc and dynudpsink to take a sockfd as a parameter. For udpsrc,
+	  overrides the port or multicast parameters. Fixes bugs #323021.
+
+2006-01-06 16:28:30 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/gconf/: Add new gconfaudiosrc and gconfvideosrc elements (needed for gnome-sound-recorder).
+	  Original commit message from CVS:
+	  * ext/gconf/Makefile.am:
+	  * ext/gconf/gstgconfaudiosrc.c: (gst_gconf_audio_src_base_init),
+	  (gst_gconf_audio_src_class_init), (gst_gconf_audio_src_reset),
+	  (gst_gconf_audio_src_init), (gst_gconf_audio_src_dispose),
+	  (do_toggle_element), (cb_toggle_element),
+	  (gst_gconf_audio_src_change_state):
+	  * ext/gconf/gstgconfaudiosrc.h:
+	  * ext/gconf/gstgconfelements.c: (plugin_init):
+	  * ext/gconf/gstgconfvideosrc.c: (gst_gconf_video_src_base_init),
+	  (gst_gconf_video_src_class_init), (gst_gconf_video_src_reset),
+	  (gst_gconf_video_src_init), (gst_gconf_video_src_dispose),
+	  (do_toggle_element), (cb_toggle_element),
+	  (gst_gconf_video_src_change_state):
+	  * ext/gconf/gstgconfvideosrc.h:
+	  Add new gconfaudiosrc and gconfvideosrc elements
+	  (needed for gnome-sound-recorder).
+
+2006-01-06 11:46:53 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/id3demux/gstid3demux.c: Add gst_element_no_more_pads() for proper decodebin behaviour.
+	  Original commit message from CVS:
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_add_srcpad):
+	  Add gst_element_no_more_pads() for proper decodebin behaviour.
+	  * gst/id3demux/id3v2frames.c: (parse_comment_frame),
+	  (parse_text_identification_frame), (parse_split_strings):
+	  Failure to decode some tags is not a GST_ERROR() but a
+	  GST_WARNING()
+	  When iterating over a chunk of text, check that we haven't gone too
+	  far.
+
+2006-01-05 23:17:44 +0000  Sébastien Moutte <sebastien@moutte.net>
+
+	* sys/directdraw/gstdirectdrawplugin.c:
+	* sys/directdraw/gstdirectdrawsink.c:
+	* sys/directdraw/gstdirectdrawsink.h:
+	* sys/directsound/gstdirectsoundplugin.c:
+	* sys/directsound/gstdirectsoundsink.c:
+	* sys/directsound/gstdirectsoundsink.h:
+	* win32/vs6/libgstdirectdraw.dsp:
+	* win32/vs6/libgstdirectsound.dsp:
+	  added sys/directdraw added sys/directsound added win32/vs6/gst_plugins_bad.dsw added win32/vs6/libgstdirectsound.dsp ...
+	  Original commit message from CVS:
+	  2006-01-05  Sebastien Moutte  <sebastien@moutte.net>
+	  * added sys/directdraw
+	  * added sys/directsound
+	  * added win32/vs6/gst_plugins_bad.dsw
+	  * added win32/vs6/libgstdirectsound.dsp
+	  * added win32/vs6/libgstdirectdraw.dsp
+	  * added win32/common/config.h
+
+2006-01-05 17:03:45 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/videobox/gstvideobox.c: call oil_init() when using liboil
+	  Original commit message from CVS:
+	  * gst/videobox/gstvideobox.c: (gst_video_box_class_init),
+	  (plugin_init):
+	  call oil_init() when using liboil
+
+2006-01-04 17:28:49 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/jpeg/: Fix leaks.
+	  Original commit message from CVS:
+	  * ext/jpeg/gstsmokedec.c: (gst_smokedec_chain):
+	  * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_chain):
+	  Fix leaks.
+
+2006-01-02 19:38:32 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacdec.c: Don't g_assert() where we should just return FALSE; remove unnecessary g_assert(); initialize ...
+	  Original commit message from CVS:
+	  Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_write),
+	  (gst_flac_dec_convert_src), (gst_flac_dec_src_query),
+	  (gst_flac_dec_change_state):
+	  Don't g_assert() where we should just return FALSE; remove
+	  unnecessary g_assert(); initialize some fields properly in
+	  state change function (fixes #325504). Also, use
+	  GST_DEBUG_OBJECT in two more places.
+
+2005-12-30 15:51:05 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  configure.ac: also remove smoothwave's Makefile.am
+	  Original commit message from CVS:
+	  * configure.ac:
+	  also remove smoothwave's Makefile.am
+	  * docs/plugins/Makefile.am:
+	  fix plugin docs
+
+2005-12-30 15:39:17 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/smoothwave/.gitignore:
+	* gst/smoothwave/Makefile.am:
+	* gst/smoothwave/README:
+	* gst/smoothwave/demo-osssrc.c:
+	* gst/smoothwave/gstsmoothwave.c:
+	* gst/smoothwave/gstsmoothwave.h:
+	  remove old plugin that went bad
+	  Original commit message from CVS:
+	  remove old plugin that went bad
+
+2005-12-30 15:34:18 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  tests/examples/Makefile.am: added missing Makefile.am
+	  Original commit message from CVS:
+	  * tests/examples/Makefile.am:
+	  added missing Makefile.am
+
+2005-12-30 15:28:44 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  moved level-example to tests/examples/level-example
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/level/Makefile.am:
+	  * gst/level/level-example.c:
+	  * tests/Makefile.am:
+	  * tests/examples/level/Makefile.am:
+	  * tests/examples/level/level-example.c: (message_handler), (main):
+	  moved level-example to tests/examples/level-example
+	  * tests/old/examples/level/demo.c: (main):
+	  * tests/old/examples/level/plot.c: (main):
+	  some initial fixes
+
+2005-12-29 16:36:19 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/udp/gstmultiudpsink.*: Track packets sent per client in addition to bytes sent; provide this info through get-sta...
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_render),
+	  (gst_multiudpsink_remove), (gst_multiudpsink_get_stats):
+	  * gst/udp/gstmultiudpsink.h:
+	  Track packets sent per client in addition to bytes sent; provide
+	  this info through get-stats signal
+
+2005-12-29 11:26:12 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/auparse/gstauparse.c: Can't use gst_object_unref() on a GstAdapter (#325191).
+	  Original commit message from CVS:
+	  * gst/auparse/gstauparse.c: (gst_au_parse_dispose):
+	  Can't use gst_object_unref() on a GstAdapter (#325191).
+
+2005-12-28 18:55:32 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/id3demux/id3tags.c: If a broken tag has 0 bytes payload, at least still skip the 10 byte header
+	  Original commit message from CVS:
+	  * gst/id3demux/id3tags.c: (id3demux_read_id3v2_tag):
+	  If a broken tag has 0 bytes payload, at least still skip
+	  the 10 byte header
+
+2005-12-22 15:00:41 +0000  Philippe Kalaf <philippe.kalaf@collabora.co.uk>
+
+	  gst-plugins-good/gst/rtp/: Making these depayloaders (H263+ and mpeg4 video) inherit from
+	  Original commit message from CVS:
+	  2005-12-22  Philippe Khalaf  <burger@speedy.org>
+	  * gst-plugins-good/gst/rtp/gstrtph263pdepay.h:
+	  * gst-plugins-good/gst/rtp/gstrtph263pdepay.c:
+	  * gst-plugins-good/gst/rtp/gstrtpmp4vdepay.h:
+	  * gst-plugins-good/gst/rtp/gstrtpmp4vdepay.c:
+	  Making these depayloaders (H263+ and mpeg4 video) inherit from
+	  RtpBaseDepayloaderClass. Fixes bugs #323922 and #323908.
+
+2005-12-21 17:15:09 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  docs/plugins/gst-plugins-good-plugins.*: Regenerate the plugin hiearchy.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  Regenerate the plugin hiearchy.
+
+2005-12-21 15:24:59 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Add documentation for id3demux.
+	  Original commit message from CVS:
+	  2005-12-21  Jan Schmidt  <thaytan@mad.scientist.com>
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  * gst/id3demux/gstid3demux.c: (gst_id3demux_get_type),
+	  (gst_id3demux_base_init), (gst_id3demux_class_init),
+	  (gst_id3demux_chain):
+	  * gst/id3demux/gstid3demux.h:
+	  Add documentation for id3demux.
+	  Don't fail if the first buffer is not at offset 0, just
+	  attempt to typefind and do pass through
+	  Rename the gst_type function from gst_gst_id3demux..
+
+2005-12-20 12:44:25 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/udp/gstmultiudpsink.*: Collect statistics; return them from get_stats.
+	  Original commit message from CVS:
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_render),
+	  (gst_multiudpsink_add), (gst_multiudpsink_remove),
+	  (gst_multiudpsink_get_stats):
+	  * gst/udp/gstmultiudpsink.h:
+	  Collect statistics; return them from get_stats.
+
+2005-12-19 15:43:30 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/avi/gstavidemux.c: Stupid signedness issue...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_stream_scan):
+	  Stupid signedness issue...
+
+2005-12-19 15:19:44 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/swfdec/gstswfdec.c: Add debugging category and return GstFlowReturn in the right places
+	  Original commit message from CVS:
+	  * ext/swfdec/gstswfdec.c: (gst_swfdec_class_init),
+	  (gst_swfdec_chain), (gst_swfdec_render):
+	  Add debugging category and return GstFlowReturn in the right places
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_link):
+	  Get something from the peer pad once we've checked if there is a peer pad.
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_change_state),
+	  (qtdemux_tree_get_child_by_type), (qtdemux_parse_trak),
+	  (qtdemux_video_caps):
+	  Couple of fixes
+
+2005-12-19 15:06:27 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/avi/gstavidemux.c: Construct index for indexless files.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_reset),
+	  (gst_avi_demux_handle_src_event), (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_parse_odml), (gst_avi_demux_peek_tag),
+	  (gst_avi_demux_next_data_buffer), (gst_avi_demux_stream_scan),
+	  (gst_avi_demux_stream_header), (gst_avi_demux_loop):
+	  Construct index for indexless files.
+	  Make sure pad/buffers are correctly reset to NULL once we don't need
+	  them anymore, else we get lovely segfaults/assertions.
+	  * gst/wavparse/gstwavparse.c:
+	  Yes, you can have 96KHz audio and wma in wav :(
+
+2005-12-18 15:14:44 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  configure.ac: Check for optional dependency on zlib for id3demux
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Check for optional dependency on zlib for id3demux
+	  * gst/id3demux/Makefile.am:
+	  * gst/id3demux/gstid3demux.c: (gst_gst_id3demux_get_type),
+	  (gst_id3demux_base_init), (gst_id3demux_class_init),
+	  (gst_id3demux_reset), (gst_id3demux_init), (gst_id3demux_dispose),
+	  (gst_id3demux_add_srcpad), (gst_id3demux_remove_srcpad),
+	  (gst_id3demux_trim_buffer), (gst_id3demux_chain),
+	  (gst_id3demux_set_property), (gst_id3demux_get_property),
+	  (id3demux_get_upstream_size), (gst_id3demux_srcpad_event),
+	  (gst_id3demux_read_id3v1), (gst_id3demux_read_id3v2),
+	  (gst_id3demux_sink_activate), (gst_id3demux_src_activate_pull),
+	  (gst_id3demux_src_checkgetrange), (gst_id3demux_read_range),
+	  (gst_id3demux_src_getrange), (gst_id3demux_change_state),
+	  (gst_id3demux_pad_query), (gst_id3demux_get_query_types),
+	  (simple_find_peek), (simple_find_suggest),
+	  (gst_id3demux_do_typefind), (gst_id3demux_send_tag_event),
+	  (plugin_init):
+	  * gst/id3demux/gstid3demux.h:
+	  * gst/id3demux/id3tags.c: (read_synch_uint),
+	  (id3demux_read_id3v1_tag), (id3demux_read_id3v2_tag),
+	  (id3demux_id3v2_frame_hdr_size), (convert_fid_to_v240),
+	  (id3demux_id3v2_frames_to_tag_list):
+	  * gst/id3demux/id3tags.h:
+	  * gst/id3demux/id3v2.4.0-frames.txt:
+	  * gst/id3demux/id3v2.4.0-structure.txt:
+	  * gst/id3demux/id3v2frames.c: (id3demux_id3v2_parse_frame),
+	  (parse_comment_frame), (parse_text_identification_frame),
+	  (id3v2_tag_to_taglist), (parse_split_strings):
+	  All new LGPL id3 demuxer. Can use zlib for compressed frames,
+	  otherwise it discards them. Works on my test files.
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_loop):
+	  Don't send EOS to a non-existing srcpad
+	  The debug category can be static
+
+2005-12-17 17:48:38 +0000  Julien Moutte <julien@moutte.net>
+
+	  docs/plugins/: Updates.
+	  Original commit message from CVS:
+	  2005-12-17  Julien MOUTTE  <julien@moutte.net>
+	  * docs/plugins/gst-plugins-bad-plugins-decl.txt:
+	  * docs/plugins/gst-plugins-bad-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-bad-plugins-undocumented.txt:
+	  * docs/plugins/gst-plugins-bad-plugins.args:
+	  * docs/plugins/gst-plugins-bad-plugins.interfaces:
+	  * docs/plugins/gst-plugins-bad-plugins.signals:
+	  * docs/plugins/inspect/plugin-dfbvideosink.xml:
+	  * docs/plugins/inspect/plugin-qtdemux.xml:
+	  * docs/plugins/inspect/plugin-sdlvideosink.xml:
+	  * docs/plugins/inspect/plugin-speed.xml:
+	  * docs/plugins/inspect/plugin-tta.xml: Updates.
+	  * ext/directfb/dfbvideosink.c:
+	  (gst_dfbvideosink_surface_create),
+	  (gst_dfbvideosink_event_thread), (gst_dfbvideosink_enum_vmodes),
+	  (gst_dfbvideosink_enum_devices), (gst_dfbvideosink_setup),
+	  (gst_dfbvideosink_cleanup),
+	  (gst_dfbvideosink_can_blit_from_format),
+	  (gst_dfbvideosink_get_best_vmode), (gst_dfbvideosink_getcaps),
+	  (gst_dfbvideosink_setcaps), (gst_dfbvideosink_show_frame),
+	  (gst_dfbvideosink_buffer_alloc), (gst_dfbsurface_finalize),
+	  (gst_dfbvideosink_interface_supported),
+	  (gst_dfbvideosink_navigation_send_event),
+	  (gst_dfbvideosink_update_colorbalance),
+	  (gst_dfbvideosink_colorbalance_list_channels),
+	  (gst_dfbvideosink_colorbalance_set_value),
+	  (gst_dfbvideosink_colorbalance_get_value),
+	  (gst_dfbvideosink_colorbalance_init),
+	  (gst_dfbvideosink_set_property),
+	  (gst_dfbvideosink_get_property),
+	  (gst_dfbvideosink_init), (gst_dfbvideosink_class_init):
+	  * ext/directfb/dfbvideosink.h: Implement vertical sync and
+	  color balance interface.
+
+2005-12-16 21:57:51 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  change some char* into char[]
+	  Original commit message from CVS:
+	  * ext/esd/esdmon.c: (gst_esdmon_open_audio):
+	  * ext/esd/esdsink.c: (gst_esdsink_prepare):
+	  * gst/multipart/multipartdemux.c:
+	  change some char* into char[]
+
+2005-12-16 19:32:53 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/wavparse/gstwavparse.*: Use GstSegment to implement more seeking features.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_reset),
+	  (gst_wavparse_other), (gst_wavparse_perform_seek),
+	  (gst_wavparse_stream_headers), (gst_wavparse_stream_data),
+	  (gst_wavparse_loop), (gst_wavparse_pad_convert),
+	  (gst_wavparse_srcpad_event), (gst_wavparse_sink_activate_pull):
+	  * gst/wavparse/gstwavparse.h:
+	  Use GstSegment to implement more seeking features.
+
+2005-12-16 12:25:38 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/wavpack/gstwavpackdec.c: Oops, remove trailing comma from caps string.
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c:
+	  Oops, remove trailing comma from caps string.
+
+2005-12-16 10:12:49 +0000  Benjamin Pineau <ben.pineau@gmail.com>
+
+	  gst/rtsp/rtspconnection.c: Add <netinet/in.h> include and move <arpa/inet.h> include to make things work on OpenBSD a...
+	  Original commit message from CVS:
+	  * gst/rtsp/rtspconnection.c:
+	  Add <netinet/in.h> include and move <arpa/inet.h> include
+	  to make things work on OpenBSD as well (fixes #323717;
+	  patch by: Benjamin Pineau)
+
+2005-12-16 09:59:21 +0000  gcocatre@gmail.com <gcocatre@gmail.com>
+
+	  ext/wavpack/: Wavpack supports samplerates from 6-192kHz, fix pad template remove buffer-frames from caps, they are g...
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_link):
+	  * ext/wavpack/gstwavpackparse.c:
+	  Wavpack supports samplerates from 6-192kHz, fix pad template
+	  caps (fixes #322973; patch by: gcocatre@gmail.com). Also
+	  remove buffer-frames from caps, they are gone in 0.10.
+
+2005-12-14 20:05:45 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	  Set clock rate to be fixed in 8000. It fixes bug #324012.
+	  Original commit message from CVS:
+	  Set clock rate to be fixed in 8000. It fixes bug #324012.
+
+2005-12-14 18:07:16 +0000  Philippe Kalaf <philippe.kalaf@collabora.co.uk>
+
+	  gst-plugins-good/gst/rtp/: Fixed payload range in payloder caps. Removed payload range completly from depayloaders as...
+	  Original commit message from CVS:
+	  2005-12-14  Philippe Khalaf  <burger@speedy.org>
+	  * gst-plugins-good/gst/rtp/gstasteriskh263.c:
+	  * gst-plugins-good/gst/rtp/gstrtpamrdepay.c:
+	  * gst-plugins-good/gst/rtp/gstrtpamrpay.c:
+	  * gst-plugins-good/gst/rtp/gstrtpg711depay.c:
+	  * gst-plugins-good/gst/rtp/gstrtpg711depay.c:
+	  * gst-plugins-good/gst/rtp/gstrtpgsmdepay.c:
+	  * gst-plugins-good/gst/rtp/gstrtph263pay.c:
+	  * gst-plugins-good/gst/rtp/gstrtph263pdepay.c:
+	  * gst-plugins-good/gst/rtp/gstrtph263ppay.c:
+	  * gst-plugins-good/gst/rtp/gstrtpmp4vdepay.c:
+	  * gst-plugins-good/gst/rtp/gstrtpmp4vpay.c:
+	  * gst-plugins-good/gst/rtp/gstrtpmpadepay.c:
+	  * gst-plugins-good/gst/rtp/gstrtpmpapay.c:
+	  * gst-plugins-good/gst/rtp/README:
+	  Fixed payload range in payloder caps. Removed payload range completly from
+	  depayloaders as they don't require payload type in their caps. In effect,
+	  there isn't any specific payload type for any given codec, only suggestions.
+	  Fixes bug #324011.
+
+2005-12-13 21:58:42 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/videomixer/videomixer.c: Code cleanup and re-enabling queued time validity check for correct EOS handling.
+	  Original commit message from CVS:
+	  2005-12-13  Julien MOUTTE  <julien@moutte.net>
+	  * gst/videomixer/videomixer.c: (gst_videomixer_init),
+	  (gst_videomixer_fill_queues), (gst_videomixer_blend_buffers),
+	  (gst_videomixer_collected): Code cleanup and re-enabling
+	  queued time validity check for correct EOS handling.
+
+2005-12-13 17:18:32 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/oss/gstossmixerelement.c: Add 'device-name' property and fix state change function.
+	  Original commit message from CVS:
+	  * sys/oss/gstossmixerelement.c: (gst_oss_mixer_element_class_init),
+	  (gst_oss_mixer_element_get_property),
+	  (gst_oss_mixer_element_change_state):
+	  Add 'device-name' property and fix state change function.
+
+2005-12-13 10:45:04 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/flx/gstflxdec.c: If the speed of the file is null in the header, set the frame_time to the default setting of GST...
+	  Original commit message from CVS:
+	  * gst/flx/gstflxdec.c: (gst_flxdec_chain):
+	  If the speed of the file is null in the header, set the frame_time to the default
+	  setting of GST_SECOND / 70. Which is the default frame_delay for .fli files as
+	  stated in this document : http://www.compuphase.com/flic.htm
+	  Would be nice to have the time conversion done properly too
+	  (duration = flxh->frames * flxdec->frame_time)
+
+2005-12-12 22:29:34 +0000  Julien Moutte <julien@moutte.net>
+
+	  Adding documentation for videomixer on my way with a funny sample pipeline.
+	  Original commit message from CVS:
+	  2005-12-12  Julien MOUTTE  <julien@moutte.net>
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * gst/videomixer/videomixer.c:
+	  (gst_videomixer_pad_sink_setcaps),
+	  (gst_videomixer_getcaps), (gst_videomixer_fill_queues),
+	  (gst_videomixer_update_queues), (gst_videomixer_collected):
+	  Adding
+	  documentation for videomixer on my way with a funny sample
+	  pipeline.
+
+2005-12-12 21:43:00 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/videomixer/videomixer.c: Fix caps negotiation. (#323896)
+	  Original commit message from CVS:
+	  2005-12-12  Julien MOUTTE  <julien@moutte.net>
+	  * gst/videomixer/videomixer.c:
+	  (gst_videomixer_pad_sink_setcaps),
+	  (gst_videomixer_getcaps), (gst_videomixer_fill_queues),
+	  (gst_videomixer_update_queues), (gst_videomixer_collected):
+	  Fix caps negotiation. (#323896)
+
+2005-12-12 18:14:58 +0000  Arwed v. Merkatz <v.merkatz@gmx.net>
+
+	* ChangeLog:
+	* gst/matroska/matroska-demux.c:
+	  Set correct timestamps on audio laces, fixes playback of mp3 from matroska.
+	  Original commit message from CVS:
+	  Set correct timestamps on audio laces, fixes playback of mp3 from matroska.
+
+2005-12-12 10:40:42 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/: GstObjects must be unref'ed with gst_object_unref() instead of g_object_unref(), otherwise things break for GLi...
+	  Original commit message from CVS:
+	  * ext/ivorbis/vorbisfile.c: (gst_ivorbisfile_loop):
+	  * ext/libmms/gstmms.c: (gst_mms_src_query), (gst_mms_create):
+	  * ext/musepack/gstmusepackdec.c: (gst_musepackdec_src_query),
+	  (gst_musepackdec_loop):
+	  * ext/swfdec/gstswfdec.c: (gst_swfdec_video_link),
+	  (gst_swfdec_src_query):
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_src_query):
+	  GstObjects must be unref'ed with gst_object_unref() instead of
+	  g_object_unref(), otherwise things break for GLib-2.6 users.
+
+2005-12-12 10:30:20 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/auparse/gstauparse.*: Use gst_object_unref() for GstObjects instead of g_object_unref() and fix a mem leak in a d...
+	  Original commit message from CVS:
+	  * gst/auparse/gstauparse.c: (gst_au_parse_base_init),
+	  (gst_au_parse_class_init), (gst_au_parse_init),
+	  (gst_au_parse_dispose), (gst_au_parse_chain),
+	  (gst_au_parse_change_state), (plugin_init):
+	  * gst/auparse/gstauparse.h:
+	  Use gst_object_unref() for GstObjects instead of
+	  g_object_unref() and fix a mem leak in a debug
+	  statement; while we're at it, also borgify, use
+	  boilerplate macros and clean up a little bit.
+
+2005-12-11 20:27:06 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/debug/efence.c: Added pull mode.
+	  Original commit message from CVS:
+	  * gst/debug/efence.c: (gst_efence_init), (gst_efence_getrange),
+	  (gst_efence_checkgetrange), (gst_efence_activate_src_pull):
+	  Added pull mode.
+
+2005-12-11 19:25:41 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/: Use audiotestsrc instead of sinesrc (#323798).
+	  Original commit message from CVS:
+	  * gst/goom/gstgoom.c:
+	  * gst/level/level-example.c: (main):
+	  * gst/smoothwave/demo-osssrc.c: (main):
+	  Use audiotestsrc instead of sinesrc (#323798).
+
+2005-12-11 17:50:50 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  sys/oss/gstosssink.c: more debug-func-ptr usage
+	  Original commit message from CVS:
+	  * sys/oss/gstosssink.c: (gst_oss_sink_class_init):
+	  more debug-func-ptr usage
+
+2005-12-11 16:43:42 +0000  Zeeshan Ali <zeenix@gmail.com>
+
+	* ChangeLog:
+	* gst/flx/flx_color.c:
+	* gst/flx/flx_color.h:
+	* gst/flx/flx_fmt.h:
+	* gst/flx/gstflxdec.c:
+	* gst/flx/gstflxdec.h:
+	  Now flxdec works on big-endian machines as well.
+	  Original commit message from CVS:
+	  Now flxdec works on big-endian machines as well.
+
+2005-12-11 16:14:22 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/debug/efence.c: Make sure GST_BUFFER_DATA is set on fenced copied buffers; fix
+	  Original commit message from CVS:
+	  * gst/debug/efence.c: (gst_efence_init), (gst_efence_chain),
+	  (gst_fenced_buffer_copy):
+	  Make sure GST_BUFFER_DATA is set on fenced copied buffers; fix
+	  GST_DEBUG crasher where GST_TIME_FORMAT was not used in
+	  conjunction with GST_TIME_ARGS. Also, don't leak pad templates
+	  and use GST_DEBUG_FUNCPTR for pad functions.
+
+2005-12-10 20:26:33 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacdec.*: Rewrite flacdec a bit, so that even seeking might work now. Most importantly, don't act upon a...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (gst_flac_dec_base_init),
+	  (gst_flac_dec_class_init), (gst_flac_dec_init),
+	  (gst_flac_dec_metadata_callback), (gst_flac_dec_error_callback),
+	  (gst_flac_dec_eof), (gst_flac_dec_write), (gst_flac_dec_loop),
+	  (gst_flac_dec_convert_src), (gst_flac_dec_get_src_query_types),
+	  (gst_flac_dec_src_query), (gst_flac_dec_send_newsegment),
+	  (gst_flac_dec_handle_seek_event), (gst_flac_dec_src_event),
+	  (gst_flac_dec_change_state):
+	  * ext/flac/gstflacdec.h:
+	  Rewrite flacdec a bit, so that even seeking might work now. Most
+	  importantly, don't act upon any flow return values we get, just tell
+	  the decoder everything's dandy and act on the flow return values
+	  later on in the loop function. We don't want to mess up the internal
+	  decoder state for non-fatal things like flushing pads etc. Other
+	  than that, use GstSegment (segment seeks don't work yet though, but
+	  should be easy to add), use boilerplate macros, drop the superfluous
+	  'flacdec:' from debug messages, use gst_util_uint64_scale_int, and
+	  lots of other things.
+
+2005-12-10 14:57:48 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Update comment in OSS includes check.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Update comment in OSS includes check.
+	  * sys/oss/gstossdmabuffer.c:
+	  * sys/oss/gstosshelper.c:
+	  * sys/oss/gstossmixer.c:
+	  * sys/oss/gstossmixertrack.c:
+	  * sys/oss/gstosssink.c:
+	  * sys/oss/gstosssrc.c:
+	  * sys/oss/oss_probe.c:
+	  Don't assume the OSS soundcard.h include is always in
+	  the sys/ directory. Instead, use the existing defines
+	  from config.h to include the right file. Fixes
+	  compilation on OpenBSD 3.8 (#323718).
+
+2005-12-09 19:51:03 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.hierarchy:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* ext/flac/gstflac.c:
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacdec.h:
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflacenc.h:
+	  borgify and fix up documentation
+	  Original commit message from CVS:
+	  borgify and fix up documentation
+
+2005-12-09 15:30:21 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  ext/faad/gstfaad.c: Assume that an unknown channel mapping with 2 channels is stereo and play it that way instead of ...
+	  Original commit message from CVS:
+	  * ext/faad/gstfaad.c: (gst_faad_chanpos_to_gst),
+	  (gst_faad_update_caps):
+	  Assume that an unknown channel mapping with 2 channels
+	  is stereo and play it that way instead of erroring.
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header),
+	  (gst_qtdemux_add_stream), (qtdemux_parse_trak):
+	  Handle e.g. jpeg streams with 0 duration frames as having 0 framerate.
+	  Debug fixes. Some 64 bit variable fixes
+
+2005-12-09 11:12:48 +0000  Michael Smith <msmith@xiph.org>
+
+	  ext/flac/gstflacdec.c: Accept a wider range of flac files, more closely matching flac sp
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (raw_caps_factory), (gst_flacdec_write):
+	  Accept a wider range of flac files, more closely matching flac sp
+
+2005-12-08 16:27:12 +0000  Julien Moutte <julien@moutte.net>
+
+	  docs/plugins/Makefile.am: Add multipart elements.
+	  Original commit message from CVS:
+	  2005-12-08  Julien MOUTTE  <julien@moutte.net>
+	  * docs/plugins/Makefile.am: Add multipart elements.
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt: Fix flac.
+	  * docs/plugins/gst-plugins-good-plugins.hierarchy:
+	  * gst/multipart/multipartdemux.c:
+	  * gst/multipart/multipartmux.c: Add docs.
+
+2005-12-07 11:46:15 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/qtdemux/qtdemux.c: Memleak fixes.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header),
+	  (gst_qtdemux_add_stream):
+	  Memleak fixes.
+	  Send out EOS for valid reasons (couldn't pull_range() from upstream
+	  for example).
+
+2005-12-07 11:40:46 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/avi/gstavidemux.c: Memleak and crasher fixes.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_event),
+	  (gst_avi_demux_parse_stream), (gst_avi_demux_stream_header),
+	  (gst_avi_demux_invert):
+	  Memleak and crasher fixes.
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_base_init),
+	  (gst_wavparse_create_sourcepad), (gst_wavparse_stream_headers):
+	  Memleak fixes
+
+2005-12-06 19:55:58 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/qtdemux/qtdemux.c:
+	* gst/qtdemux/qtdemux.h:
+	* sys/v4l2/gstv4l2colorbalance.h:
+	* sys/v4l2/gstv4l2element.h:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/gstv4l2tuner.h:
+	* sys/v4l2/gstv4l2xoverlay.h:
+	* sys/v4l2/v4l2_calls.c:
+	* sys/v4l2/v4l2_calls.h:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/v4l2/v4l2src_calls.h:
+	  expand tabs
+	  Original commit message from CVS:
+	  expand tabs
+
+2005-12-06 19:44:58 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* ext/aalib/gstaasink.h:
+	* ext/cairo/gsttextoverlay.h:
+	* ext/dv/gstdvdec.h:
+	* ext/dv/gstdvdemux.c:
+	* ext/dv/gstdvdemux.h:
+	* ext/esd/esdsink.h:
+	* ext/flac/flac_compat.h:
+	* ext/flac/gstflacdec.h:
+	* ext/flac/gstflacenc.h:
+	* ext/gconf/gconf.h:
+	* ext/gconf/gstgconfaudiosink.h:
+	* ext/gconf/gstgconfvideosink.h:
+	* ext/gdk_pixbuf/gstgdkanimation.h:
+	* ext/jpeg/gstjpegdec.h:
+	* ext/jpeg/smokecodec.h:
+	* ext/jpeg/smokeformat.h:
+	* ext/ladspa/gstsignalprocessor.h:
+	* ext/ladspa/search.c:
+	* ext/ladspa/utils.h:
+	* ext/libmng/gstmngdec.h:
+	* ext/libmng/gstmngenc.c:
+	* ext/libmng/gstmngenc.h:
+	* ext/libpng/gstpngenc.c:
+	* ext/libpng/gstpngenc.h:
+	* ext/shout2/gstshout2.h:
+	* ext/speex/gstspeexdec.h:
+	* ext/speex/gstspeexenc.c:
+	* ext/speex/gstspeexenc.h:
+	* gst/auparse/gstauparse.c:
+	* gst/autodetect/gstautoaudiosink.h:
+	* gst/autodetect/gstautovideosink.h:
+	* gst/avi/gstavidemux.h:
+	* gst/cutter/gstcutter.h:
+	* gst/debug/tests.c:
+	* gst/debug/tests.h:
+	* gst/effectv/gstwarp.c:
+	* gst/flx/flx_fmt.h:
+	* gst/flx/gstflxdec.h:
+	* gst/goom/filters.c:
+	* gst/goom/filters.h:
+	* gst/goom/goom_tools.h:
+	* gst/law/alaw-encode.c:
+	* gst/level/gstlevel.c:
+	* gst/level/gstlevel.h:
+	* gst/matroska/ebml-write.h:
+	* gst/matroska/matroska-demux.h:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.h:
+	* gst/monoscope/convolve.c:
+	* gst/monoscope/convolve.h:
+	* gst/multipart/multipartmux.c:
+	* gst/oldcore/gstaggregator.c:
+	* gst/oldcore/gstaggregator.h:
+	* gst/oldcore/gstmd5sink.c:
+	* gst/oldcore/gstmd5sink.h:
+	* gst/oldcore/gstmultifilesrc.c:
+	* gst/oldcore/gstmultifilesrc.h:
+	* gst/oldcore/gstpipefilter.h:
+	* gst/oldcore/gstshaper.h:
+	* gst/rtp/gstrtpL16depay.h:
+	* gst/rtp/gstrtpL16pay.h:
+	* gst/rtp/gstrtpdepay.h:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmp4vpay.h:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/rtsp/gstrtspsrc.h:
+	* gst/rtsp/rtspconnection.h:
+	* gst/rtsp/rtspdefs.h:
+	* gst/rtsp/rtspmessage.h:
+	* gst/rtsp/rtsptransport.h:
+	* gst/rtsp/rtspurl.c:
+	* gst/rtsp/rtspurl.h:
+	* gst/rtsp/sdpmessage.c:
+	* gst/rtsp/sdpmessage.h:
+	* gst/smpte/barboxwipes.c:
+	* gst/smpte/gstmask.h:
+	* gst/smpte/gstsmpte.h:
+	* gst/smpte/paint.c:
+	* gst/smpte/paint.h:
+	* gst/udp/gstdynudpsink.h:
+	* gst/udp/gstmultiudpsink.h:
+	* gst/udp/gstudpsink.c:
+	* gst/udp/gstudpsink.h:
+	* gst/udp/gstudpsrc.c:
+	* gst/videomixer/videomixer.c:
+	* gst/wavenc/riff.h:
+	* gst/wavparse/gstwavparse.h:
+	* sys/oss/gstossdmabuffer.h:
+	* sys/oss/gstossmixer.h:
+	* sys/oss/gstossmixerelement.h:
+	* sys/oss/gstossmixertrack.h:
+	* sys/oss/gstosssink.c:
+	* sys/oss/gstosssink.h:
+	* sys/oss/gstosssrc.c:
+	* sys/oss/gstosssrc.h:
+	* sys/osxaudio/gstosxaudioelement.h:
+	* sys/osxaudio/gstosxaudiosink.h:
+	* sys/osxaudio/gstosxaudiosrc.h:
+	  expand tabs
+	  Original commit message from CVS:
+	  expand tabs
+
+2005-12-05 18:12:07 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* configure.ac:
+	  back to HEAD
+	  Original commit message from CVS:
+	  back to HEAD
+
+=== release 0.10.0 ===
+
+2005-12-05 18:03:23 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	  releasing 0.10.0
+	  Original commit message from CVS:
+	  releasing 0.10.0
+
+2005-12-05 18:01:48 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/plugins/inspect/plugin-qtdemux.xml:
+	  releasing 0.10.0
+	  Original commit message from CVS:
+	  releasing 0.10.0
+
+2005-12-05 16:21:08 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	  Update .po files
+	  Original commit message from CVS:
+	  Update .po files
+
+2005-12-05 15:08:46 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* Makefile.am:
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/it.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	  update translations
+	  Original commit message from CVS:
+	  update translations
+
+2005-12-05 13:04:22 +0000  Andy Wingo <wingo@pobox.com>
+
+	  Update for alloc_buffer changes.
+	  Original commit message from CVS:
+	  2005-12-05  Andy Wingo  <wingo@pobox.com>
+	  * ext/faac/gstfaac.c: (gst_faac_sink_event), (gst_faac_chain):
+	  * ext/faad/gstfaad.c: (gst_faad_chain):
+	  * ext/hermes/gsthermescolorspace.c: (gst_hermes_colorspace_chain):
+	  * ext/lcs/gstcolorspace.c: (gst_colorspace_chain):
+	  * ext/xine/xineinput.c: (gst_xine_input_get):
+	  * gst/colorspace/gstcolorspace.c: (gst_colorspace_chain):
+	  * gst/speed/gstspeed.c: (speed_chain):
+	  * gst/videocrop/gstvideocrop.c: (gst_video_crop_chain): Update for
+	  alloc_buffer changes.
+
+2005-12-05 13:03:00 +0000  Andy Wingo <wingo@pobox.com>
+
+	  Update for alloc_buffer changes.
+	  Original commit message from CVS:
+	  2005-12-05  Andy Wingo  <wingo@pobox.com>
+	  * ext/dv/gstdvdec.c: (gst_dvdec_chain):
+	  * ext/flac/gstflacdec.c: (gst_flacdec_write):
+	  * ext/flac/gstflacenc.c: (gst_flacenc_write_callback):
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_chain):
+	  * ext/gdk_pixbuf/pixbufscale.c: (gst_pixbufscale_chain):
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_chain):
+	  * ext/jpeg/gstjpegenc.c: (gst_jpegenc_chain):
+	  * ext/ladspa/gstsignalprocessor.c: (gst_signal_processor_process):
+	  * ext/libpng/gstpngdec.c: (user_info_callback), (gst_pngdec_task):
+	  * ext/speex/gstspeexdec.c: (speex_dec_chain):
+	  * ext/speex/gstspeexenc.c: (gst_speexenc_chain):
+	  * gst/auparse/gstauparse.c: (gst_auparse_chain):
+	  * gst/flx/gstflxdec.c: (gst_flxdec_chain):
+	  * gst/goom/gstgoom.c: (gst_goom_chain):
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_push_vorbis_codec_priv_data),
+	  (gst_matroska_demux_add_wvpk_header):
+	  * gst/multipart/multipartdemux.c: (gst_multipart_demux_chain):
+	  * gst/multipart/multipartmux.c: (gst_multipart_mux_collected):
+	  * gst/videomixer/videomixer.c: (gst_videomixer_collected):
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_chain): Update for
+	  alloc_buffer changes.
+
+2005-12-05 12:23:22 +0000  Michael Smith <msmith@xiph.org>
+
+	  docs/plugins/gst-plugins-good-plugins.args: Remove args for plugins that aren't in -good.
+	  Original commit message from CVS:
+	  * docs/plugins/gst-plugins-good-plugins.args:
+	  Remove args for plugins that aren't in -good.
+
+2005-12-04 22:26:07 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  remove pango plugin as its gone into base
+	  Original commit message from CVS:
+	  remove pango plugin as its gone into base
+
+2005-12-03 18:51:48 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpg711pay.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtpspeexpay.c:
+	  fix element descriptions
+	  Original commit message from CVS:
+	  fix element descriptions
+
+2005-12-03 18:50:12 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/plugins/inspect/plugin-fdsrc.xml:
+	  remove fdsrc docs
+	  Original commit message from CVS:
+	  remove fdsrc docs
+
+2005-12-01 19:18:08 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* configure.ac:
+	  back to HEAD
+	  Original commit message from CVS:
+	  back to HEAD
+
+=== release 0.9.7 ===
+
+2005-12-01 19:14:26 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cutter.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	  releasing 0.9.7
+	  Original commit message from CVS:
+	  releasing 0.9.7
+
+2005-12-01 19:13:20 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/plugins/inspect/plugin-qtdemux.xml:
+	  releasing 0.9.7
+	  Original commit message from CVS:
+	  releasing 0.9.7
+
+2005-12-01 17:53:29 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* common:
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	  Update .po files
+	  Original commit message from CVS:
+	  Update .po files
+
+2005-12-01 15:34:13 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* docs/plugins/.gitignore:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/inspect/plugin-multipart.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	  add multipart plugin to docs
+	  Original commit message from CVS:
+	  add multipart plugin to docs
+
+2005-12-01 15:22:25 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/pango/Makefile.am:
+	* ext/pango/gstclockoverlay.c:
+	* ext/pango/gstclockoverlay.h:
+	* ext/pango/gsttextoverlay.c:
+	* ext/pango/gsttextoverlay.h:
+	* ext/pango/gsttextrender.c:
+	* ext/pango/gsttextrender.h:
+	* ext/pango/gsttimeoverlay.c:
+	* ext/pango/gsttimeoverlay.h:
+	  move pango to base
+	  Original commit message from CVS:
+	  move pango to base
+
+2005-12-01 14:39:30 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  gst/rtp/: parsers are depayers
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtpL16depay.c:
+	  * gst/rtp/gstrtpL16depay.h:
+	  * gst/rtp/gstrtpL16parse.c:
+	  * gst/rtp/gstrtpL16parse.h:
+	  * gst/rtp/gstrtpgsmdepay.c:
+	  * gst/rtp/gstrtpgsmdepay.h:
+	  * gst/rtp/gstrtpgsmparse.c:
+	  * gst/rtp/gstrtpgsmparse.h:
+	  parsers are depayers
+
+2005-12-01 14:30:01 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* common:
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16depay.h:
+	* gst/rtp/gstrtpL16enc.c:
+	* gst/rtp/gstrtpL16enc.h:
+	* gst/rtp/gstrtpL16parse.c:
+	* gst/rtp/gstrtpL16parse.h:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpL16pay.h:
+	* gst/rtp/gstrtpamrdec.c:
+	* gst/rtp/gstrtpamrdec.h:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrdepay.h:
+	* gst/rtp/gstrtpamrenc.c:
+	* gst/rtp/gstrtpamrenc.h:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpamrpay.h:
+	* gst/rtp/gstrtpdec.c:
+	* gst/rtp/gstrtpdec.h:
+	* gst/rtp/gstrtpdepay.c:
+	* gst/rtp/gstrtpdepay.h:
+	* gst/rtp/gstrtpg711dec.c:
+	* gst/rtp/gstrtpg711dec.h:
+	* gst/rtp/gstrtpg711depay.c:
+	* gst/rtp/gstrtpg711depay.h:
+	* gst/rtp/gstrtpg711enc.c:
+	* gst/rtp/gstrtpg711enc.h:
+	* gst/rtp/gstrtpg711pay.c:
+	* gst/rtp/gstrtpg711pay.h:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmdepay.h:
+	* gst/rtp/gstrtpgsmenc.c:
+	* gst/rtp/gstrtpgsmenc.h:
+	* gst/rtp/gstrtpgsmparse.c:
+	* gst/rtp/gstrtpgsmparse.h:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtpgsmpay.h:
+	* gst/rtp/gstrtph263enc.c:
+	* gst/rtp/gstrtph263enc.h:
+	* gst/rtp/gstrtph263pay.c:
+	* gst/rtp/gstrtph263pay.h:
+	* gst/rtp/gstrtph263pdec.c:
+	* gst/rtp/gstrtph263pdec.h:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263pdepay.h:
+	* gst/rtp/gstrtph263penc.c:
+	* gst/rtp/gstrtph263penc.h:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph263ppay.h:
+	* gst/rtp/gstrtpmp4vdec.c:
+	* gst/rtp/gstrtpmp4vdec.h:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmp4vdepay.h:
+	* gst/rtp/gstrtpmp4venc.c:
+	* gst/rtp/gstrtpmp4venc.h:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmp4vpay.h:
+	* gst/rtp/gstrtpmpadec.c:
+	* gst/rtp/gstrtpmpadec.h:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpadepay.h:
+	* gst/rtp/gstrtpmpaenc.c:
+	* gst/rtp/gstrtpmpaenc.h:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmpapay.h:
+	* gst/rtp/gstrtpspeexdec.c:
+	* gst/rtp/gstrtpspeexdec.h:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexdepay.h:
+	* gst/rtp/gstrtpspeexenc.c:
+	* gst/rtp/gstrtpspeexenc.h:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpspeexpay.h:
+	  Do burger's rename for rtp payloaders and depayloaders
+	  Original commit message from CVS:
+	  Do burger's rename for rtp payloaders and depayloaders
+
+2005-11-30 19:02:35 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/dv/: Fix seeking in dvdemux again, add some more debug info.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdec.c: (gst_dvdec_chain):
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_demux_frame):
+	  * ext/dv/gstdvdemux.h:
+	  Fix seeking in dvdemux again, add some more debug info.
+
+2005-11-30 18:48:56 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* configure.ac:
+	  fix tests
+	  Original commit message from CVS:
+	  fix tests
+
+2005-11-30 18:40:19 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* Makefile.am:
+	  add tests subdir
+	  Original commit message from CVS:
+	  add tests subdir
+
+2005-11-30 18:36:02 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* tests/check/Makefile.am:
+	  add Makefile.am
+	  Original commit message from CVS:
+	  add Makefile.am
+
+2005-11-30 18:28:53 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  move
+	  Original commit message from CVS:
+	  * PORTED_09:
+	  * docs/random/PORTED_09:
+	  move
+	  * tests/Makefile.am:
+	  add
+	  * win32/gst.sln:
+	  remove
+
+2005-11-30 18:24:08 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* Makefile.am:
+	* check/.gitignore:
+	* check/Makefile.am:
+	* check/elements/.gitignore:
+	* check/elements/level.c:
+	* check/elements/matroskamux.c:
+	* configure.ac:
+	* examples/Makefile.am:
+	* examples/capsfilter/Makefile.am:
+	* examples/capsfilter/capsfilter1.c:
+	* examples/gob/Makefile.am:
+	* examples/gob/gst-identity2.gob:
+	* examples/gstplay/.gitignore:
+	* examples/gstplay/Makefile.am:
+	* examples/gstplay/player.c:
+	* examples/indexing/.gitignore:
+	* examples/indexing/Makefile.am:
+	* examples/indexing/indexmpeg.c:
+	* examples/level/Makefile.am:
+	* examples/level/README:
+	* examples/level/demo.c:
+	* examples/level/plot.c:
+	* examples/stats/Makefile.am:
+	* examples/stats/mp2ogg.c:
+	* examples/switch/.gitignore:
+	* examples/switch/Makefile.am:
+	* examples/switch/switcher.c:
+	  move under tests
+	  Original commit message from CVS:
+	  move under tests
+
+2005-11-30 16:57:57 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* common:
+	* gst-plugins-good.spec.in:
+	  update for latest changes
+	  Original commit message from CVS:
+	  update for latest changes
+
+2005-11-30 14:53:29 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/pango/gsttextrender.*: Add missing files.
+	  Original commit message from CVS:
+	  * ext/pango/gsttextrender.c: (gst_text_render_base_init),
+	  (gst_text_render_class_init), (resize_bitmap),
+	  (gst_text_render_render_text), (gst_text_render_setcaps),
+	  (gst_text_render_fixate_caps), (gst_text_renderer_bitmap_to_ayuv),
+	  (gst_text_render_chain), (gst_text_render_finalize),
+	  (gst_text_render_init), (gst_text_render_set_property):
+	  * ext/pango/gsttextrender.h:
+	  Add missing files.
+
+2005-11-30 13:20:57 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Port pango-based textoverlay, timeoverlay and textrender to 0.9 and add background shading and text wrapping modes. M...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * ext/Makefile.am:
+	  * ext/pango/Makefile.am:
+	  * ext/pango/gstclockoverlay.c: (gst_clock_overlay_base_init),
+	  (gst_clock_overlay_render_time), (gst_clock_overlay_get_text),
+	  (gst_clock_overlay_class_init), (gst_clock_overlay_init):
+	  * ext/pango/gstclockoverlay.h:
+	  * ext/pango/gsttextoverlay.c: (gst_text_overlay_base_init),
+	  (gst_text_overlay_get_text), (gst_text_overlay_class_init),
+	  (gst_text_overlay_finalize), (gst_text_overlay_init),
+	  (gst_text_overlay_update_wrap_mode), (gst_text_overlay_setcaps),
+	  (gst_text_overlay_text_pad_linked),
+	  (gst_text_overlay_text_pad_unlinked),
+	  (gst_text_overlay_set_property), (gst_text_overlay_getcaps),
+	  (gst_text_overlay_shade_y), (gst_text_overlay_blit_yuv420),
+	  (gst_text_overlay_resize_bitmap), (gst_text_overlay_render_text),
+	  (gst_text_overlay_push_frame), (gst_text_overlay_pop_video),
+	  (gst_text_overlay_pop_text), (gst_text_overlay_collected),
+	  (gst_text_overlay_change_state), (plugin_init):
+	  * ext/pango/gsttextoverlay.h:
+	  * ext/pango/gsttimeoverlay.c: (gst_time_overlay_base_init),
+	  (gst_time_overlay_render_time), (gst_time_overlay_get_text),
+	  (gst_time_overlay_class_init), (gst_time_overlay_init):
+	  * ext/pango/gsttimeoverlay.h:
+	  Port pango-based textoverlay, timeoverlay and textrender to 0.9
+	  and add background shading and text wrapping modes. Make
+	  timoverlay derive from textoverlay. Also add new clockoverlay
+	  element.
+
+2005-11-30 11:10:01 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/udp/Makefile.am: Moved to netbuffer.
+	  Original commit message from CVS:
+	  2005-11-30  Julien MOUTTE  <julien@moutte.net>
+	  * gst/udp/Makefile.am: Moved to netbuffer.
+
+2005-11-30 10:18:42 +0000  Julien Moutte <julien@moutte.net>
+
+	  Ported multipart mux/demux to 0.9.
+	  Original commit message from CVS:
+	  2005-11-30  Julien MOUTTE  <julien@moutte.net>
+	  * configure.ac:
+	  * PORTED_O9:
+	  * gst/multipart/Makefile.am:
+	  * gst/multipart/multipartdemux.c:
+	  (gst_multipart_demux_base_init),
+	  (gst_multipart_demux_class_init), (gst_multipart_demux_init),
+	  (gst_multipart_find_pad_by_mime), (gst_multipart_demux_chain),
+	  (gst_multipart_demux_change_state),
+	  (gst_multipart_demux_plugin_init):
+	  * gst/multipart/multipartmux.c: (gst_multipart_mux_class_init),
+	  (gst_multipart_mux_init), (gst_multipart_mux_finalize),
+	  (gst_multipart_mux_sinkconnect),
+	  (gst_multipart_mux_request_new_pad),
+	  (gst_multipart_mux_handle_src_event),
+	  (gst_multipart_mux_queue_pads), (gst_multipart_mux_collected),
+	  (gst_multipart_mux_change_state): Ported multipart mux/demux to
+	  0.9.
+
+2005-11-30 08:26:47 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  gst/: update for symbols change
+	  Original commit message from CVS:
+	  * gst/debug/gstnavigationtest.c: (gst_navigationtest_get_type):
+	  * gst/debug/gstnavigationtest.h:
+	  * gst/effectv/gstaging.c: (gst_agingtv_get_type):
+	  * gst/effectv/gstdice.c: (gst_dicetv_get_type):
+	  * gst/effectv/gstedge.c: (gst_edgetv_get_type):
+	  * gst/effectv/gstquark.c: (gst_quarktv_get_type):
+	  * gst/effectv/gstrev.c: (gst_revtv_get_type):
+	  * gst/effectv/gstshagadelic.c: (gst_shagadelictv_get_type):
+	  * gst/effectv/gstvertigo.c: (gst_vertigotv_get_type):
+	  * gst/effectv/gstwarp.c: (gst_warptv_get_type):
+	  * gst/videofilter/gstvideoflip.c: (gst_video_flip_set_property),
+	  (gst_video_flip_get_type):
+	  * gst/videofilter/gstvideoflip.h:
+	  update for symbols change
+
+2005-11-29 17:46:04 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  gst/udp/: the old gstnet lib was renamed gstnetbuffer (#322257)
+	  Original commit message from CVS:
+	  * gst/udp/gstdynudpsink.c:
+	  * gst/udp/gstudpsrc.c:
+	  the old gstnet lib was renamed gstnetbuffer (#322257)
+
+2005-11-29 15:42:01 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/cairo/gsttextoverlay.c: Actually render the text from the text pad.
+	  Original commit message from CVS:
+	  * ext/cairo/gsttextoverlay.c: (gst_text_overlay_render_text),
+	  (gst_text_overlay_collected):
+	  Actually render the text from the text pad.
+
+2005-11-29 14:49:00 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/debug/: Update for GstBaseTransform event virtual method
+	  Original commit message from CVS:
+	  * gst/debug/gstnavseek.c: (gst_navseek_event):
+	  * gst/debug/progressreport.c: (gst_progress_report_event):
+	  Update for GstBaseTransform event virtual method
+
+2005-11-29 10:55:09 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  ext/cairo/Makefile.am: no need to link to videofilter
+	  Original commit message from CVS:
+	  2005-11-29  Thomas Vander Stichele  <thomas at apestaart dot org>
+	  * ext/cairo/Makefile.am:
+	  no need to link to videofilter
+
+2005-11-29 10:46:00 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* gst/debug/Makefile.am:
+	* gst/debug/gstnavigationtest.h:
+	* gst/effectv/Makefile.am:
+	* gst/effectv/gstaging.c:
+	* gst/effectv/gstdice.c:
+	* gst/effectv/gstedge.c:
+	* gst/effectv/gstquark.c:
+	* gst/effectv/gstrev.c:
+	* gst/effectv/gstshagadelic.c:
+	* gst/effectv/gstvertigo.c:
+	* gst/effectv/gstwarp.c:
+	* gst/videofilter/Makefile.am:
+	* gst/videofilter/gstvideofilter.c:
+	* gst/videofilter/gstvideofilter.h:
+	* gst/videofilter/gstvideoflip.h:
+	  remove the videofilter library and link to the one in base
+	  Original commit message from CVS:
+	  remove the videofilter library and link to the one in base
+
+2005-11-29 01:30:40 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* common:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videofilter/gstvideoflip.h:
+	  borgify
+	  Original commit message from CVS:
+	  borgify
+
+2005-11-28 17:31:44 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/avi/gstavidemux.c: Useless check now we're setting the current entry correctly.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_process_next_entry):
+	  Useless check now we're setting the current entry correctly.
+
+2005-11-28 16:54:03 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/jpeg/gstjpegenc.c: Don't leak input buffer in chain function (fixes #322667); make state change function thread-s...
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegenc.c: (gst_jpegenc_resync), (gst_jpegenc_chain),
+	  (gst_jpegenc_set_property), (gst_jpegenc_get_property),
+	  (gst_jpegenc_change_state):
+	  Don't leak input buffer in chain function (fixes #322667); make
+	  state change function thread-safe; don't repeat the current function
+	  name in GST_DEBUG statements; use GST_ROUND_UP_* macros; use
+	  gst_pad_alloc_buffer(); misc. minor cleanups.
+
+2005-11-28 15:43:29 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/faad/gstfaad.c: Handle gracefully the consequence of "Maximum number of scalefactor bands exceeded", which result...
+	  Original commit message from CVS:
+	  * ext/faad/gstfaad.c: (gst_faad_srcgetcaps):
+	  Handle gracefully the consequence of "Maximum number of scalefactor
+	  bands exceeded", which results in 0 channels with samplerates of 0.
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_change_state):
+	  Do upward transitions, then call parent state_change, then do
+	  downward transitions.
+
+2005-11-28 15:13:22 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/matroska/matroska-mux.c: Look for pixel-aspect-ratio in caps, not pixel_width and pixel_height (Fixes: #322645)
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_video_pad_setcaps):
+	  Look for pixel-aspect-ratio in caps, not pixel_width and
+	  pixel_height (Fixes: #322645)
+
+2005-11-28 12:59:05 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/matroska/matroska-mux.c: From Michal Benes: frame duration should be GST_SECOND / framerate, not
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_video_pad_setcaps):
+	  From Michal Benes:
+	  frame duration should be GST_SECOND / framerate, not
+	  GST_SECOND * framerate. (Fixes: #322643)
+
+2005-11-27 17:02:53 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  configure.ac: fix up GST_PLUGIN_LDFLAGS
+	  Original commit message from CVS:
+	  * configure.ac:
+	  fix up GST_PLUGIN_LDFLAGS
+	  * gst/rtsp/rtspconnection.c:
+	  fix includes (see #317043)
+	  * gst/videofilter/Makefile.am:
+	  stop installing this library
+
+2005-11-27 15:30:25 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* configure.ac:
+	  no need for an AS_LIBTOOL call
+	  Original commit message from CVS:
+	  no need for an AS_LIBTOOL call
+
+2005-11-27 14:33:31 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* Makefile.am:
+	* common:
+	* gst-plugins-good.spec.in:
+	  add ACLOCAL_AMFLAGS; remove old stuff from spec changelog
+	  Original commit message from CVS:
+	  add ACLOCAL_AMFLAGS; remove old stuff from spec changelog
+
+2005-11-26 12:54:47 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/dv/gstdvdec.c: Handle the case where the incoming Video dv stream doesn't have a pixel aspect ratio set.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdec.c: (gst_dvdec_sink_setcaps):
+	  Handle the case where the incoming Video dv stream doesn't have
+	  a pixel aspect ratio set.
+
+2005-11-25 22:14:47 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* ext/flac/gstflacdec.c:
+	  document flacdec
+	  Original commit message from CVS:
+	  document flacdec
+
+2005-11-25 21:36:18 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* ext/cairo/gstcairo.c:
+	* ext/cairo/gsttextoverlay.c:
+	* ext/cairo/gsttextoverlay.h:
+	* ext/cairo/gsttimeoverlay.c:
+	* ext/cairo/gsttimeoverlay.h:
+	  do some name borgifying document
+	  Original commit message from CVS:
+	  do some name borgifying
+	  document
+
+2005-11-25 21:02:16 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  documenting auto*sink using strstr for the video sink lookup, class field is not ordered update other plugins
+	  Original commit message from CVS:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * gst/autodetect/gstautoaudiosink.c:
+	  (gst_auto_audio_sink_base_init):
+	  * gst/autodetect/gstautovideosink.c:
+	  (gst_auto_video_sink_base_init),
+	  (gst_auto_video_sink_factory_filter):
+	  documenting auto*sink
+	  using strstr for the video sink lookup, class field is not ordered
+	  update other plugins
+
+2005-11-25 19:58:19 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ext/wavpack/Makefile.am:
+	* ext/wavpack/gstwavpackdec.c:
+	* ext/wavpack/gstwavpackdec.h:
+	* ext/wavpack/gstwavpackparse.c:
+	* ext/wavpack/gstwavpackparse.h:
+	  Wavpack ported to 0.9. No support for correction file yet.
+	  Original commit message from CVS:
+	  Wavpack ported to 0.9. No support for correction file yet.
+
+2005-11-25 18:15:51 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  ext/wavpack/: put back wavpack - still needs porting
+	  Original commit message from CVS:
+	  * ext/wavpack/gstwavpackcommon.h:
+	  * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_link),
+	  (gst_wavpack_dec_wvclink), (gst_wavpack_dec_get_type),
+	  (gst_wavpack_dec_base_init), (gst_wavpack_dec_dispose),
+	  (gst_wavpack_dec_class_init), (gst_wavpack_dec_src_query),
+	  (gst_wavpack_dec_init), (gst_wavpack_dec_setup_context),
+	  (gst_wavpack_dec_format_samples), (gst_wavpack_dec_loop),
+	  (gst_wavpack_dec_plugin_init):
+	  * ext/wavpack/gstwavpackdec.h:
+	  * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_get_type),
+	  (gst_wavpack_parse_base_init), (gst_wavpack_parse_dispose),
+	  (gst_wavpack_parse_class_init), (gst_wavpack_parse_src_query),
+	  (gst_wavpack_parse_src_event), (find_header), (find_sample),
+	  (gst_wavpack_parse_seek), (gst_wavpack_parse_init),
+	  (gst_wavpack_parse_handle_event), (gst_wavpack_parse_loop),
+	  (gst_wavpack_parse_change_state), (gst_wavpack_parse_plugin_init):
+	  * ext/wavpack/gstwavpackparse.h:
+	  put back wavpack - still needs porting
+
+2005-11-25 18:03:24 +0000  Sebastien Cote <sebas642@yahoo.ca>
+
+	  gst/udp/gstudpsrc.c: Patch from Sebastien Cote to close control sockets in udpsrc.
+	  Original commit message from CVS:
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_stop):
+	  Patch from Sebastien Cote to close control sockets in udpsrc.
+
+2005-11-24 15:07:06 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/effectv/gstquark.c: Flush the planes list on reverse caps negotiation. This was crashing because of differently s...
+	  Original commit message from CVS:
+	  2005-11-24  Julien MOUTTE  <julien@moutte.net>
+	  * gst/effectv/gstquark.c: (gst_quarktv_set_caps),
+	  (gst_quarktv_get_unit_size), (gst_quarktv_transform),
+	  (gst_quarktv_planetable_clear), (gst_quarktv_change_state),
+	  (gst_quarktv_base_init), (gst_quarktv_class_init),
+	  (gst_quarktv_init): Flush the planes list on reverse caps
+	  negotiation. This was crashing because of differently sized
+	  buffers.
+
+2005-11-24 12:50:28 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/: Handle strides correctly, fix identity flipping, convert navigation event correctly again.
+	  Original commit message from CVS:
+	  2005-11-24  Julien MOUTTE  <julien@moutte.net>
+	  * gst/debug/gstnavigationtest.c: (draw_box_planar411):
+	  * gst/videofilter/gstvideoflip.c:
+	  (gst_videoflip_method_get_type),
+	  (gst_videoflip_set_caps), (gst_videoflip_transform_caps),
+	  (gst_videoflip_get_unit_size), (gst_videoflip_flip),
+	  (gst_videoflip_transform), (gst_videoflip_handle_src_event),
+	  (gst_videoflip_set_property), (gst_videoflip_base_init),
+	  (gst_videoflip_class_init), (gst_videoflip_init): Handle strides
+	  correctly, fix identity flipping, convert navigation event
+	  correctly again.
+
+2005-11-24 11:16:53 +0000  Michael Smith <msmith@xiph.org>
+
+	* README:
+	  Fix #320288: wrong readme in plugins-good
+	  Original commit message from CVS:
+	  Fix #320288: wrong readme in plugins-good
+
+2005-11-24 11:06:29 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* Makefile.am:
+	  fix torture target
+	  Original commit message from CVS:
+	  fix torture target
+
+2005-11-23 21:25:56 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* Makefile.am:
+	  add a torture target
+	  Original commit message from CVS:
+	  add a torture target
+
+2005-11-23 20:05:26 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* configure.ac:
+	  back to HEAD
+	  Original commit message from CVS:
+	  back to HEAD
+
+=== release 0.9.6 ===
+
+2005-11-23 19:57:49 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/plugins/inspect/plugin-qtdemux.xml:
+	  releasing 0.9.6
+	  Original commit message from CVS:
+	  releasing 0.9.6
+
+2005-11-23 19:56:31 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	  releasing 0.9.6
+	  Original commit message from CVS:
+	  releasing 0.9.6
+
+2005-11-23 19:14:07 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/plugins/inspect/plugin-cutter.xml:
+	  adding cutter
+	  Original commit message from CVS:
+	  adding cutter
+
+2005-11-23 19:05:29 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	  Update .po files
+	  Original commit message from CVS:
+	  Update .po files
+
+2005-11-23 16:49:16 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/debug/gstnavigationtest.c: Oops, initialise the framerate GValue
+	  Original commit message from CVS:
+	  * gst/debug/gstnavigationtest.c: (gst_navigationtest_init):
+	  Oops, initialise the framerate GValue
+
+2005-11-23 15:50:51 +0000  Julien Moutte <julien@moutte.net>
+
+	  VideoFilter inherits from
+	  Original commit message from CVS:
+	  2005-11-23  Julien MOUTTE  <julien@moutte.net>
+	  * ext/cairo/gsttimeoverlay.c:
+	  (gst_timeoverlay_update_font_height),
+	  (gst_timeoverlay_set_caps), (gst_timeoverlay_get_unit_size),
+	  (gst_timeoverlay_transform), (gst_timeoverlay_base_init),
+	  (gst_timeoverlay_class_init), (gst_timeoverlay_init),
+	  (gst_timeoverlay_get_type):
+	  * ext/cairo/gsttimeoverlay.h:
+	  * gst/debug/Makefile.am:
+	  * gst/debug/gstnavigationtest.c:
+	  (gst_navigationtest_handle_src_event),
+	  (gst_navigationtest_get_unit_size),
+	  (gst_navigationtest_set_caps),
+	  (gst_navigationtest_transform),
+	  (gst_navigationtest_change_state),
+	  (gst_navigationtest_base_init), (gst_navigationtest_class_init),
+	  (gst_navigationtest_init), (gst_navigationtest_get_type),
+	  (plugin_init):
+	  * gst/debug/gstnavigationtest.h:
+	  * gst/effectv/Makefile.am:
+	  * gst/effectv/gstaging.c: (gst_agingtv_set_caps),
+	  (gst_agingtv_get_unit_size), (gst_agingtv_transform),
+	  (gst_agingtv_base_init), (gst_agingtv_class_init),
+	  (gst_agingtv_init), (gst_agingtv_get_type):
+	  * gst/effectv/gstdice.c: (gst_dicetv_set_caps),
+	  (gst_dicetv_get_unit_size), (gst_dicetv_transform),
+	  (gst_dicetv_base_init), (gst_dicetv_class_init),
+	  (gst_dicetv_init),
+	  (gst_dicetv_get_type):
+	  * gst/effectv/gstedge.c: (gst_edgetv_set_caps),
+	  (gst_edgetv_get_unit_size), (gst_edgetv_transform),
+	  (gst_edgetv_base_init), (gst_edgetv_class_init),
+	  (gst_edgetv_init),
+	  (gst_edgetv_get_type):
+	  * gst/effectv/gsteffectv.c:
+	  * gst/effectv/gsteffectv.h:
+	  * gst/effectv/gstquark.c: (gst_quarktv_set_caps),
+	  (gst_quarktv_get_unit_size), (fastrand),
+	  (gst_quarktv_transform),
+	  (gst_quarktv_change_state), (gst_quarktv_base_init),
+	  (gst_quarktv_class_init), (gst_quarktv_init),
+	  (gst_quarktv_get_type):
+	  * gst/effectv/gstrev.c: (gst_revtv_set_caps),
+	  (gst_revtv_get_unit_size), (gst_revtv_transform),
+	  (gst_revtv_base_init), (gst_revtv_class_init), (gst_revtv_init),
+	  (gst_revtv_get_type):
+	  * gst/effectv/gstshagadelic.c: (gst_shagadelictv_set_caps),
+	  (gst_shagadelictv_get_unit_size), (gst_shagadelictv_transform),
+	  (gst_shagadelictv_base_init), (gst_shagadelictv_class_init),
+	  (gst_shagadelictv_init), (gst_shagadelictv_get_type):
+	  * gst/effectv/gstvertigo.c: (gst_vertigotv_set_caps),
+	  (gst_vertigotv_get_unit_size), (gst_vertigotv_transform),
+	  (gst_vertigotv_base_init), (gst_vertigotv_class_init),
+	  (gst_vertigotv_init), (gst_vertigotv_get_type):
+	  * gst/effectv/gstwarp.c: (gst_warptv_set_caps),
+	  (gst_warptv_get_unit_size), (gst_warptv_transform),
+	  (gst_warptv_base_init), (gst_warptv_class_init),
+	  (gst_warptv_init),
+	  (gst_warptv_get_type):
+	  * gst/videofilter/Makefile.am:
+	  * gst/videofilter/gstvideobalance.c:
+	  * gst/videofilter/gstvideobalance.h:
+	  * gst/videofilter/gstvideofilter.c: (gst_videofilter_get_type),
+	  (gst_videofilter_class_init), (gst_videofilter_init):
+	  * gst/videofilter/gstvideofilter.h:
+	  * gst/videofilter/gstvideoflip.c: (gst_videoflip_set_caps),
+	  (gst_videoflip_transform_caps), (gst_videoflip_get_unit_size),
+	  (gst_videoflip_flip), (gst_videoflip_transform),
+	  (gst_videoflip_handle_src_event), (gst_videoflip_set_property),
+	  (gst_videoflip_base_init), (gst_videoflip_class_init),
+	  (gst_videoflip_init), (plugin_init), (gst_videoflip_get_type):
+	  * gst/videofilter/gstvideoflip.h: VideoFilter inherits from
+	  BaseTransform, it's just a place holder for now and every video
+	  effect plugin has been ported to use BaseTransform features
+	  directly. QuarkTV was fixed too (was broken), navigationtest
+	  works
+	  and best for the end, videoflip converts navigation events
+	  depending
+	  on flip method ! Fixes #320953
+
+2005-11-23 14:22:18 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Fixes for API changes
+	  Original commit message from CVS:
+	  * ext/aalib/gstaasink.c: (gst_aasink_fixate):
+	  * ext/cairo/gsttextoverlay.c: (gst_text_overlay_collected):
+	  * gst/goom/gstgoom.c: (gst_goom_init), (gst_goom_src_setcaps),
+	  (gst_goom_src_negotiate), (gst_goom_chain):
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_video_pad_setcaps):
+	  * sys/osxvideo/osxvideosink.m:
+	  Fixes for API changes
+
+2005-11-23 12:19:06 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  add cutter to spec in
+	  Original commit message from CVS:
+	  add cutter to spec in
+
+2005-11-23 11:57:51 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  gst/qtdemux/qtdemux.c: Convert to fractional framerates
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header),
+	  (gst_qtdemux_add_stream), (qtdemux_dump_mvhd),
+	  (qtdemux_parse_trak):
+	  Convert to fractional framerates
+
+2005-11-22 23:58:14 +0000  Michael Smith <msmith@xiph.org>
+
+	  ext/jpeg/: JPEG fractiony goodness.
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_setcaps),
+	  (gst_jpeg_dec_chain), (gst_jpeg_dec_change_state):
+	  * ext/jpeg/gstjpegdec.h:
+	  * ext/jpeg/gstjpegenc.c: (gst_jpegenc_setcaps):
+	  * ext/jpeg/gstjpegenc.h:
+	  * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_setcaps),
+	  (gst_smokeenc_resync):
+	  * ext/jpeg/gstsmokeenc.h:
+	  JPEG fractiony goodness.
+
+2005-11-22 22:35:57 +0000  Michael Smith <msmith@xiph.org>
+
+	* ChangeLog:
+	* gst/goom/filters.c:
+	* gst/goom/graphic.h:
+	  Fix for #321430: unresolved symbols due to incorrect linkage on inline functions in goom.
+	  Original commit message from CVS:
+	  Fix for #321430: unresolved symbols due to incorrect linkage on inline functions
+	  in goom.
+	  Does not, however, fix the general crackheadedness of goom (global variables,
+	  oh my!); this should be moved to -bad.
+
+2005-11-22 22:21:37 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  More fractional framerate conversions
+	  Original commit message from CVS:
+	  * ext/cairo/gsttextoverlay.c: (gst_text_overlay_init),
+	  (gst_text_overlay_setcaps), (gst_text_overlay_collected):
+	  * ext/cairo/gsttextoverlay.h:
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_sink_link):
+	  * ext/gdk_pixbuf/gstgdkpixbuf.h:
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_init),
+	  (gst_pngdec_caps_create_and_set):
+	  * ext/libpng/gstpngdec.h:
+	  * ext/libpng/gstpngenc.c: (gst_pngenc_setcaps):
+	  * gst/alpha/gstalphacolor.c: (gst_alpha_color_set_caps):
+	  * gst/avi/gstavimux.c: (gst_avimux_init),
+	  (gst_avimux_vidsinkconnect):
+	  * gst/flx/gstflxdec.c: (gst_flxdec_chain):
+	  * gst/goom/gstgoom.c: (gst_goom_init), (gst_goom_src_setcaps),
+	  (gst_goom_src_negotiate), (gst_goom_chain):
+	  * gst/goom/gstgoom.h:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_video_caps):
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_video_pad_setcaps):
+	  * sys/osxvideo/osxvideosink.h:
+	  * sys/osxvideo/osxvideosink.m:
+	  More fractional framerate conversions
+
+2005-11-22 20:07:47 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Convert to fractional framerates.
+	  Original commit message from CVS:
+	  * ext/aalib/gstaasink.c: (gst_aasink_fixate):
+	  * gst/debug/gstnavigationtest.c:
+	  (gst_navigationtest_handle_src_event):
+	  * gst/videofilter/gstvideofilter.c:
+	  (gst_videofilter_format_get_structure), (gst_videofilter_setcaps),
+	  (gst_videofilter_init):
+	  * gst/videofilter/gstvideofilter.h:
+	  Convert to fractional framerates.
+
+2005-11-22 18:11:58 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* ext/aalib/gstaasink.c:
+	* ext/dv/gstdvdec.c:
+	* ext/esd/esdmon.c:
+	* ext/flac/gstflacenc.c:
+	* ext/gdk_pixbuf/pixbufscale.c:
+	* ext/libcaca/gstcacasink.c:
+	* ext/shout2/gstshout2.c:
+	* gst/alpha/gstalpha.c:
+	* gst/oldcore/gstaggregator.c:
+	* gst/oldcore/gstshaper.c:
+	* gst/smpte/barboxwipes.c:
+	* gst/smpte/gstsmpte.c:
+	* gst/videobox/gstvideobox.c:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videomixer/videomixer.c:
+	  fix up more enums
+	  Original commit message from CVS:
+	  fix up more enums
+
+2005-11-22 17:39:11 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/videomixer/videomixer.c: Fractional framerates, videomixer.
+	  Original commit message from CVS:
+	  * gst/videomixer/videomixer.c: (gst_videomixer_pad_sink_setcaps),
+	  (gst_videomixer_getcaps), (gst_videomixer_fill_queues),
+	  (gst_videomixer_update_queues):
+	  Fractional framerates, videomixer.
+
+2005-11-22 17:09:36 +0000  Michael Smith <msmith@xiph.org>
+
+	  ext/dv/: Fractional framerates for DV.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdec.c: (gst_dvdec_init), (gst_dvdec_sink_setcaps):
+	  * ext/dv/gstdvdec.h:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_init),
+	  (gst_dvdemux_src_convert), (gst_dvdemux_sink_convert),
+	  (gst_dvdemux_demux_video), (gst_dvdemux_demux_frame),
+	  (gst_dvdemux_flush):
+	  * ext/dv/gstdvdemux.h:
+	  Fractional framerates for DV.
+
+2005-11-22 14:44:26 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/autodetect/: Use gst_plugin_feature_list_free() to free feature list and in the case of autovideosink free the li...
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautoaudiosink.c:
+	  (gst_auto_audio_sink_find_best), (gst_auto_audio_sink_detect):
+	  * gst/autodetect/gstautovideosink.c:
+	  (gst_auto_video_sink_find_best), (gst_auto_video_sink_detect):
+	  Use gst_plugin_feature_list_free() to free feature list and
+	  in the case of autovideosink free the list at all. Also
+	  miscellaneous cosmetic fixes.
+
+2005-11-22 13:13:21 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  gst/cutter/gstcutter.c: copy calculation code from level; remove use of some audio functions
+	  Original commit message from CVS:
+	  * gst/cutter/gstcutter.c: (gst_cutter_chain),
+	  (gst_cutter_set_property), (gst_cutter_get_caps):
+	  copy calculation code from level; remove use of some audio
+	  functions
+
+2005-11-22 13:11:25 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/level/gstlevel.c:
+	  various cosmetic fixes
+	  Original commit message from CVS:
+	  various cosmetic fixes
+
+2005-11-22 12:48:10 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/level/gstlevel.c:
+	  various cosmetic fixes
+	  Original commit message from CVS:
+	  various cosmetic fixes
+
+2005-11-22 12:41:35 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/level/gstlevel.c:
+	  various cosmetic fixes
+	  Original commit message from CVS:
+	  various cosmetic fixes
+
+2005-11-22 12:38:33 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ChangeLog:
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflactag.c:
+	* ext/shout2/gstshout2.c:
+	* ext/speex/gstspeexenc.c:
+	* gst/avi/gstavimux.c:
+	  Update for gst_tag_setter API changes.
+	  Original commit message from CVS:
+	  2005-11-22  Andy Wingo  <wingo@pobox.com>
+	  * Update for gst_tag_setter API changes.
+
+2005-11-22 11:57:51 +0000  Andy Wingo <wingo@pobox.com>
+
+	* gst/qtdemux/qtdemux.c:
+	  ext/faad/gstfaad.c (gst_faad_event) ext/ivorbis/vorbisfile.c (gst_ivorbisfile_loop) gst/qtdemux/qtdemux.c (gst_qtdemu...
+	  Original commit message from CVS:
+	  2005-11-22  Andy Wingo  <wingo@pobox.com>
+	  * ext/faad/gstfaad.c (gst_faad_event)
+	  * ext/ivorbis/vorbisfile.c (gst_ivorbisfile_loop)
+	  * gst/qtdemux/qtdemux.c (gst_qtdemux_loop_header)
+	  * gst/speed/gstspeed.c (speed_sink_event)
+	  * gst/tta/gstttaparse.c (gst_tta_parse_src_event)
+	  (gst_tta_parse_parse_header): Run update-funcnames.
+
+2005-11-22 11:53:34 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ChangeLog:
+	* ext/dv/gstdvdemux.c:
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacenc.c:
+	* ext/gconf/gstgconfaudiosink.c:
+	* ext/gconf/gstgconfvideosink.c:
+	* ext/libpng/gstpngdec.c:
+	* ext/speex/gstspeexdec.c:
+	* gst/auparse/gstauparse.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/avi/gstavidemux.c:
+	* gst/goom/gstgoom.c:
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavparse/gstwavparse.c:
+	  ext/dv/gstdvdemux.c (gst_dvdemux_handle_sink_event) (gst_dvdemux_demux_frame) ext/flac/gstflacdec.c (gst_flacdec_writ...
+	  Original commit message from CVS:
+	  2005-11-22  Andy Wingo  <wingo@pobox.com>
+	  * ext/dv/gstdvdemux.c (gst_dvdemux_handle_sink_event)
+	  (gst_dvdemux_demux_frame)
+	  * ext/flac/gstflacdec.c (gst_flacdec_write)
+	  * ext/flac/gstflacenc.c (gst_flacenc_seek_callback)
+	  (gst_flacenc_sink_event)
+	  * ext/gconf/gstgconfaudiosink.c (gst_gconf_audio_sink_init)
+	  * ext/gconf/gstgconfvideosink.c (gst_gconf_video_sink_init)
+	  * ext/libpng/gstpngdec.c (gst_pngdec_caps_create_and_set)
+	  * ext/speex/gstspeexdec.c (speex_dec_event, speex_dec_chain)
+	  * gst/auparse/gstauparse.c (gst_auparse_chain)
+	  * gst/autodetect/gstautoaudiosink.c (gst_auto_audio_sink_init)
+	  * gst/autodetect/gstautovideosink.c (gst_auto_video_sink_init)
+	  * gst/avi/gstavidemux.c (gst_avi_demux_stream_header)
+	  (gst_avi_demux_handle_seek)
+	  * gst/goom/gstgoom.c (gst_goom_event)
+	  * gst/matroska/ebml-write.c (gst_ebml_write_seek)
+	  * gst/matroska/matroska-demux.c
+	  (gst_matroska_demux_handle_seek_event)
+	  (gst_matroska_demux_loop_stream_parse_id)
+	  * gst/wavenc/gstwavenc.c (gst_wavenc_stop_file)
+	  * gst/wavparse/gstwavparse.c (gst_wavparse_handle_seek)
+	  (gst_wavparse_stream_headers): Run update-funcnames.
+
+2005-11-22 11:49:30 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  URIHandler interface and element properties are now properly synchronized for DV1394src and UDPSrc
+	  Original commit message from CVS:
+	  * ext/raw1394/gstdv1394src.c: (gst_dv1394src_class_init),
+	  (gst_dv1394src_init), (gst_dv1394src_dispose),
+	  (gst_dv1394src_set_property), (gst_dv1394src_discover_avc_node),
+	  (gst_dv1394src_uri_set_uri):
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init),
+	  (gst_udpsrc_update_uri), (gst_udpsrc_set_uri),
+	  (gst_udpsrc_set_property), (gst_udpsrc_uri_get_uri):
+	  URIHandler interface and element properties are now properly
+	  synchronized for DV1394src and UDPSrc
+
+2005-11-22 11:36:04 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/: libgsttagedit has been renamed to libgsttag.
+	  Original commit message from CVS:
+	  * ext/flac/Makefile.am:
+	  * ext/speex/Makefile.am:
+	  libgsttagedit has been renamed to libgsttag.
+
+2005-11-21 20:11:59 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/rtspconnection.c: Apply patch from Sebastien Cote to fix #319184.
+	  Original commit message from CVS:
+	  * gst/rtsp/rtspconnection.c: (read_body):
+	  Apply patch from Sebastien Cote to fix #319184.
+
+2005-11-21 19:50:25 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  port cutter
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/cutter/Makefile.am:
+	  * gst/cutter/gstcutter.c: (gst_cutter_class_init),
+	  (gst_cutter_init), (gst_cutter_message_new), (gst_cutter_chain),
+	  (gst_cutter_set_property), (gst_cutter_get_property),
+	  (plugin_init), (gst_cutter_get_caps):
+	  port cutter
+	  * gst/level/gstlevel.c:
+	  fix up plugin details
+
+2005-11-21 18:09:02 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Update for stream lock API changes: don't take stream log in sink event handlers any longer and change GST_STREAM_LOC...
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_handle_sink_event):
+	  * ext/flac/gstflacdec.c: (gst_flacdec_loop),
+	  (gst_flacdec_src_event):
+	  * ext/flac/gstflacenc.c: (gst_flacenc_sink_event):
+	  * ext/ladspa/gstsignalprocessor.c: (gst_signal_processor_event),
+	  (gst_signal_processor_getrange), (gst_signal_processor_chain):
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_handle_seek):
+	  * gst/flx/gstflxdec.c: (gst_flxdec_src_event_handler),
+	  (gst_flxdec_sink_event_handler):
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_handle_seek_event):
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_handle_seek):
+	  Update for stream lock API changes: don't take stream log
+	  in sink event handlers any longer and change GST_STREAM_LOCK
+	  to GST_PAD_STREAM_LOCK. Don't leak references in flxdec event
+	  functions.
+
+2005-11-21 17:52:15 +0000  Michael Smith <msmith@xiph.org>
+
+	* gst/auparse/Makefile.am:
+	* gst/auparse/gstauparse.h:
+	  Forgot to commit header file changes, Makefile.am changes. Oops.
+	  Original commit message from CVS:
+	  Forgot to commit header file changes, Makefile.am changes. Oops.
+
+2005-11-21 17:49:21 +0000  Michael Smith <msmith@xiph.org>
+
+	* ChangeLog:
+	* gst/auparse/gstauparse.c:
+	  gst_object_unref, not g_object_unref
+	  Original commit message from CVS:
+	  gst_object_unref, not g_object_unref
+
+2005-11-21 17:37:41 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  Fix for stream lock updates.
+	  Original commit message from CVS:
+	  * ext/faac/gstfaac.c: (gst_faac_sink_event):
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_handle_src_event):
+	  * gst/tta/gstttaparse.c: (gst_tta_parse_src_event):
+	  Fix for stream lock updates.
+
+2005-11-21 17:23:46 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/wavparse/gstwavparse.c: Use GST_DEBUG_FUNCPTR; add debug message in pad activate function.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_init),
+	  (gst_wavparse_create_sourcepad), (gst_wavparse_sink_activate):
+	  Use GST_DEBUG_FUNCPTR; add debug message in pad activate function.
+
+2005-11-21 17:18:01 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/auparse/: Partially fix #161712. playbin still doesn't work on these files, (on the bug report, Andy says we aren...
+	  Original commit message from CVS:
+	  * gst/auparse/Makefile.am:
+	  * gst/auparse/gstauparse.c: (gst_auparse_class_init),
+	  (gst_auparse_init), (gst_auparse_dispose), (gst_auparse_chain),
+	  (gst_auparse_change_state):
+	  * gst/auparse/gstauparse.h:
+	  Partially fix #161712. playbin still doesn't work on these files,
+	  (on the bug report, Andy says we aren't typefinding it for some
+	  reason?) but at least auparse isn't totally busted like it was before.
+
+2005-11-21 16:45:46 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: j@bootlab.org, #321903).
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (qtdemux_video_caps):
+	  Add DX50, DIVX and DIV3 fourccs (patch by
+	  j@bootlab.org, #321903).
+
+2005-11-21 16:36:05 +0000  Andy Wingo <wingo@pobox.com>
+
+	  *.*: Ran scripts/update-macros. Oh yes.
+	  Original commit message from CVS:
+	  2005-11-21  Andy Wingo  <wingo@pobox.com>
+	  * *.h:
+	  * *.c: Ran scripts/update-macros. Oh yes.
+
+2005-11-21 15:06:35 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-demux.c: Filler events are gone for now, comment out section generating them.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_sync_streams):
+	  Filler events are gone for now, comment out section generating
+	  them.
+
+2005-11-21 14:39:04 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Update for GST_FOURCC_FORMAT API change.
+	  Original commit message from CVS:
+	  * ext/directfb/dfbvideosink.c:
+	  (gst_dfbvideosink_get_format_from_caps):
+	  * ext/sdl/sdlvideosink.c: (gst_sdlvideosink_create):
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header),
+	  (qtdemux_parse), (qtdemux_type_get), (qtdemux_node_dump_foreach),
+	  (qtdemux_dump_hdlr), (qtdemux_dump_dref), (qtdemux_dump_stsd),
+	  (qtdemux_dump_dcom), (qtdemux_parse_trak), (qtdemux_video_caps),
+	  (qtdemux_audio_caps):
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_v4l2fourcc_to_caps):
+	  * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list),
+	  (gst_v4l2src_capture_init), (gst_v4l2src_get_size_limits):
+	  Update for GST_FOURCC_FORMAT API change.
+
+2005-11-21 14:33:11 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Rename gst_caps_structure_fixate_* to gst_structure_fixate_* (#322027)
+	  Original commit message from CVS:
+	  * ext/audioresample/gstaudioresample.c:
+	  * ext/polyp/polypsink.c: (gst_polypsink_sink_fixate):
+	  * gst/librfb/gstrfbsrc.c: (gst_rfbsrc_fixate):
+	  * gst/modplug/gstmodplug.cc:
+	  * sys/glsink/glimagesink.c: (gst_glimagesink_fixate):
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_fixate):
+	  Rename gst_caps_structure_fixate_* to gst_structure_fixate_*
+	  (#322027)
+
+2005-11-21 14:31:05 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Rename gst_caps_structure_fixate_* to gst_structure_fixate_* (#322027)
+	  Original commit message from CVS:
+	  * ext/aalib/gstaasink.c: (gst_aasink_fixate):
+	  * ext/mikmod/gstmikmod.c: (gst_mikmod_srcfixate):
+	  * gst/goom/gstgoom.c: (gst_goom_src_negotiate):
+	  * sys/osxvideo/osxvideosink.m:
+	  Rename gst_caps_structure_fixate_* to gst_structure_fixate_*
+	  (#322027)
+
+2005-11-21 13:38:24 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Fixes for GST_FOURCC_FORMAT API change.
+	  Original commit message from CVS:
+	  * ext/aalib/gstaasink.c: (gst_aasink_setcaps):
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_file_header),
+	  (gst_avi_demux_read_subindexes), (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_parse_odml), (gst_avi_demux_stream_index),
+	  (gst_avi_demux_sync), (gst_avi_demux_stream_header),
+	  (gst_avi_demux_stream_data):
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_video_caps):
+	  * gst/wavenc/gstwavenc.c: (write_metadata):
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_parse_adtl),
+	  (gst_wavparse_parse_file_header), (gst_wavparse_stream_headers):
+	  Fixes for GST_FOURCC_FORMAT API change.
+
+2005-11-21 12:13:48 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Fix for collect pads API change. Also fix textoverlay state change function.
+	  Original commit message from CVS:
+	  * ext/cairo/gsttextoverlay.c: (gst_text_overlay_finalize),
+	  (gst_text_overlay_init), (gst_text_overlay_text_pad_linked),
+	  (gst_text_overlay_text_pad_unlinked), (gst_text_overlay_pop_video),
+	  (gst_text_overlay_pop_text), (gst_text_overlay_collected),
+	  (gst_text_overlay_change_state):
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_init),
+	  (gst_matroska_mux_reset), (gst_matroska_mux_request_new_pad),
+	  (gst_matroska_mux_best_pad), (gst_matroska_mux_change_state):
+	  * gst/smpte/gstsmpte.c: (gst_smpte_init), (gst_smpte_collected):
+	  * gst/videomixer/videomixer.c: (gst_videomixer_init),
+	  (gst_videomixer_request_new_pad), (gst_videomixer_fill_queues),
+	  (gst_videomixer_change_state):
+	  Fix for collect pads API change. Also fix textoverlay state
+	  change function.
+
+2005-11-20 17:04:55 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/matroska/matroska-mux.c: Replace
+	  Original commit message from CVS:
+	  2005-11-20  Julien MOUTTE  <julien@moutte.net>
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_start): Replace
+	  GST_PAD_IS_USABLE by something approaching it.
+
+2005-11-20 16:43:32 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/matroska/matroska-mux.c: Fix for
+	  Original commit message from CVS:
+	  2005-11-20  Julien MOUTTE  <julien@moutte.net>
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_start): Fix for
+	  API changes.
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_chain): Fix for API
+	  changes,
+	  but also fix the code that was not checking return values from
+	  pad_push neither using pad_alloc_buffer.
+
+2005-11-18 18:19:21 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/libpng/gstpngenc.c: Added debug category
+	  Original commit message from CVS:
+	  * ext/libpng/gstpngenc.c: (gst_pngenc_class_init),
+	  (gst_pngenc_chain):
+	  Added debug category
+	  Return GST_FLOW_UNEXPECTED when sending an EOS, so the whole pipeline
+	  goes to EOS.
+
+2005-11-17 18:23:23 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpg711dec.c:
+	* gst/rtp/gstrtpg711depay.c:
+	* gst/rtp/gstrtpg711enc.c:
+	* gst/rtp/gstrtpg711enc.h:
+	* gst/rtp/gstrtpg711pay.c:
+	* gst/rtp/gstrtpg711pay.h:
+	* gst/rtp/gstrtpspeexdec.c:
+	* gst/rtp/gstrtpspeexdec.h:
+	* gst/rtp/gstrtpspeexdepay.c:
+	* gst/rtp/gstrtpspeexdepay.h:
+	* gst/rtp/gstrtpspeexenc.c:
+	* gst/rtp/gstrtpspeexenc.h:
+	* gst/rtp/gstrtpspeexpay.c:
+	* gst/rtp/gstrtpspeexpay.h:
+	  Created Speex payloader and depayloader; Optimize G711 payloader to use adapter and send packets until MTU size.
+	  Original commit message from CVS:
+	  Created Speex payloader and depayloader; Optimize G711 payloader to use adapter and send packets until MTU size.
+
+2005-11-16 19:08:54 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  check/elements/matroskamux.c: Fix leak in check.
+	  Original commit message from CVS:
+	  * check/elements/matroskamux.c: (setup_src_pad), (setup_sink_pad):
+	  Fix leak in check.
+
+2005-11-16 17:00:32 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/flx/gstflxdec.c: Fix state change.
+	  Original commit message from CVS:
+	  * gst/flx/gstflxdec.c: (gst_flxdec_change_state):
+	  Fix state change.
+
+2005-11-16 11:02:24 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ChangeLog:
+	* gst/udp/gstudpsrc.c:
+	  Move comment.
+	  Original commit message from CVS:
+	  (gst_udpsrc_create): Move comment.
+
+2005-11-16 10:43:44 +0000  Andy Wingo <wingo@pobox.com>
+
+	  gst/udp/gstudpsrc.c: Clean up with the boilerplate macro.
+	  Original commit message from CVS:
+	  2005-11-16  Andy Wingo  <wingo@pobox.com>
+	  * gst/udp/gstudpsrc.c: Clean up with the boilerplate macro.
+
+2005-11-15 19:41:21 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-demux.c: When seeking, seek to closest index entry at or before the requested seek position, no...
+	  Original commit message from CVS:
+	  Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+	  * gst/matroska/matroska-demux.c: (gst_matroskademux_do_index_seek):
+	  When seeking, seek to closest index entry at or before the requested
+	  seek position, not just the closest one (#321001).
+
+2005-11-15 12:16:00 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavidemux.c: Invert DIB images again (see #132341).
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (swap_line), (gst_avi_demux_invert),
+	  (gst_avi_demux_process_next_entry), (gst_avi_demux_stream_data):
+	  Invert DIB images again (see #132341).
+
+2005-11-14 02:13:35 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* common:
+	* configure.ac:
+	* ext/aalib/gstaasink.c:
+	* ext/cairo/gstcairo.c:
+	* ext/dv/gstdv.c:
+	* ext/esd/gstesd.c:
+	* ext/flac/gstflac.c:
+	* ext/gconf/gstgconfelements.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/jpeg/gstjpeg.c:
+	* ext/ladspa/gstladspa.c:
+	* ext/libcaca/gstcacasink.c:
+	* ext/libmng/gstmng.c:
+	* ext/libpng/gstpng.c:
+	* ext/mikmod/gstmikmod.c:
+	* ext/pango/gsttextoverlay.c:
+	* ext/pango/gsttimeoverlay.c:
+	* ext/raw1394/gst1394.c:
+	* ext/speex/gstspeex.c:
+	* gst/alpha/Makefile.am:
+	* gst/alpha/gstalpha.c:
+	* gst/alpha/gstalphacolor.c:
+	* gst/auparse/gstauparse.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautodetect.c:
+	* gst/avi/gstavi.c:
+	* gst/cutter/gstcutter.c:
+	* gst/debug/efence.c:
+	* gst/debug/gstdebug.c:
+	* gst/debug/gstnavigationtest.c:
+	* gst/effectv/gsteffectv.c:
+	* gst/flx/gstflxdec.c:
+	* gst/goom/gstgoom.c:
+	* gst/law/alaw.c:
+	* gst/law/mulaw.c:
+	* gst/level/gstlevel.c:
+	* gst/matroska/matroska.c:
+	* gst/median/gstmedian.c:
+	* gst/monoscope/gstmonoscope.c:
+	* gst/multipart/multipart.c:
+	* gst/oldcore/gstelements.c:
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstasteriskh263.c:
+	* gst/rtp/gstrtp.c:
+	* gst/rtsp/gstrtsp.c:
+	* gst/smoothwave/gstsmoothwave.c:
+	* gst/smpte/gstsmpte.c:
+	* gst/udp/gstudp.c:
+	* gst/videobox/gstvideobox.c:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videofilter/gstvideotemplate.c:
+	* gst/videomixer/videomixer.c:
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavparse/gstwavparse.c:
+	* sys/oss/gstossaudio.c:
+	* sys/osxaudio/gstosxaudio.c:
+	  rework configure.ac; make asterisk rtp stuff compile on mingw
+	  Original commit message from CVS:
+	  rework configure.ac; make asterisk rtp stuff compile on mingw
+
+2005-11-12 13:31:56 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/jpeg/gstjpegdec.c: Only GST_DEBUG() information on the valid components.
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_chain):
+	  Only GST_DEBUG() information on the valid components.
+
+2005-11-11 19:34:50 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* configure.ac:
+	  back to head
+	  Original commit message from CVS:
+	  back to head
+
+=== release 0.9.5 ===
+
+2005-11-11 19:33:23 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	  releasing 0.9.5
+	  Original commit message from CVS:
+	  releasing 0.9.5
+
+2005-11-11 18:33:21 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	  Update .po files
+	  Original commit message from CVS:
+	  Update .po files
+
+2005-11-11 16:48:58 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/avi/gstavidemux.*: Yeah, implement proper seeking. Exact seeking and segment seeking.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_reset),
+	  (gst_avi_demux_src_convert), (gst_avi_demux_handle_src_event),
+	  (gst_avi_demux_stream_header), (gst_avi_demux_handle_seek),
+	  (gst_avi_demux_process_next_entry), (gst_avi_demux_stream_data),
+	  (gst_avi_demux_loop):
+	  * gst/avi/gstavidemux.h:
+	  Yeah, implement proper seeking. Exact seeking and segment seeking.
+	  Still need to do some checks for segment_stop.
+
+2005-11-11 15:17:44 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  fix Cairo entry
+	  Original commit message from CVS:
+	  fix Cairo entry
+
+2005-11-10 12:34:26 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Add support for custom genre tags.
+	  Original commit message from CVS:
+	  Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+	  * gst/qtdemux/qtdemux.c: (qtdemux_parse_udta):
+	  Add support for custom genre tags.
+
+2005-11-10 12:22:30 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-mux.c: Don't try to ready buffer duration from buffer that we don't own any  longer and that mi...
+	  Original commit message from CVS:
+	  Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_write_data):
+	  Don't try to ready buffer duration from buffer that we don't
+	  own any  longer and that might already have been unreffed.
+	  (#321136)
+
+2005-11-09 21:35:29 +0000  Zeeshan Ali <zeenix@gmail.com>
+
+	* ChangeLog:
+	* gst/flx/gstflxdec.c:
+	  Attempting to optimize the code for embedded systems.
+	  Original commit message from CVS:
+	  Attempting to optimize the code for embedded systems.
+
+2005-11-08 08:54:30 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/oss/gstosssink.c: Don't re-use already closed file descriptor. (#320920)
+	  Original commit message from CVS:
+	  Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+	  * sys/oss/gstosssink.c: (gst_oss_sink_close):
+	  Don't re-use already closed file descriptor. (#320920)
+
+2005-11-07 17:35:20 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/oss/gstosssink.*: Cache probed caps; fix debug output for SET_PARAM macros.
+	  Original commit message from CVS:
+	  * sys/oss/gstosssink.c: (gst_oss_sink_dispose),
+	  (gst_oss_sink_set_property), (gst_oss_sink_getcaps),
+	  (gst_oss_sink_prepare):
+	  * sys/oss/gstosssink.h:
+	  Cache probed caps; fix debug output for SET_PARAM macros.
+
+2005-11-07 15:09:54 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/cairo/: Port cairo textoverlay plugin to 0.9. Add 'shaded-background' property and redo position. Doesn't handle ...
+	  Original commit message from CVS:
+	  * ext/cairo/Makefile.am:
+	  * ext/cairo/gstcairo.c: (plugin_init):
+	  * ext/cairo/gsttextoverlay.c: (gst_text_overlay_base_init),
+	  (gst_text_overlay_class_init), (gst_text_overlay_finalize),
+	  (gst_text_overlay_init), (gst_text_overlay_font_init),
+	  (gst_text_overlay_set_property), (gst_text_overlay_render_text),
+	  (gst_text_overlay_getcaps), (gst_text_overlay_setcaps),
+	  (gst_text_overlay_text_pad_linked),
+	  (gst_text_overlay_text_pad_unlinked), (gst_text_overlay_shade_y),
+	  (gst_text_overlay_blit_1), (gst_text_overlay_blit_sub2x2),
+	  (gst_text_overlay_push_frame), (gst_text_overlay_pop_video),
+	  (gst_text_overlay_pop_text), (gst_text_overlay_collected),
+	  (gst_text_overlay_change_state):
+	  * ext/cairo/gsttextoverlay.h:
+	  Port cairo textoverlay plugin to 0.9. Add 'shaded-background'
+	  property and redo position. Doesn't handle upstream renegotiation
+	  yet though.
+
+2005-11-07 10:31:32 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavidemux.c: No need to take the STREAM_LOCK in the loop function. Improve some debug messages. Don't leak ...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_process_next_entry), (gst_avi_demux_stream_data),
+	  (gst_avi_demux_loop):
+	  No need to take the STREAM_LOCK in the loop function. Improve
+	  some debug messages. Don't leak pad names in debug messages.
+
+2005-11-07 10:27:00 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-demux.c: Don't error out when the source pad isn't linked.
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_push_vorbis_codec_priv_data),
+	  (gst_matroska_demux_add_wvpk_header):
+	  Don't error out when the source pad isn't linked.
+
+2005-11-02 19:42:38 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/gconf/: Fix state change functions here as well and set kid to NULL state before removing it.
+	  Original commit message from CVS:
+	  * ext/gconf/gstgconfaudiosink.c: (do_toggle_element),
+	  (gst_gconf_audio_sink_change_state):
+	  * ext/gconf/gstgconfvideosink.c: (do_toggle_element),
+	  (gst_gconf_video_sink_change_state):
+	  Fix state change functions here as well and set kid
+	  to NULL state before removing it.
+
+2005-11-02 16:48:55 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* check/elements/matroskamux.c:
+	* common:
+	* tests/check/elements/matroskamux.c:
+	  sigh, static pad templates aren't refcounted properly
+	  Original commit message from CVS:
+	  sigh, static pad templates aren't refcounted properly
+
+2005-11-01 16:14:25 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* check/elements/.gitignore:
+	* gst/level/.gitignore:
+	* tests/check/elements/.gitignore:
+	  ignore more
+	  Original commit message from CVS:
+	  ignore more
+
+2005-11-01 15:15:44 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  gst/wavenc/gstwavenc.c: Added proper event handlind, made downstream newsegment event use GST_FORMAT_BYTES (otherwise...
+	  Original commit message from CVS:
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_stop_file),
+	  (gst_wavenc_init), (gst_wavenc_event), (gst_wavenc_chain):
+	  Added proper event handlind,
+	  made downstream newsegment event use GST_FORMAT_BYTES (otherwise it's
+	  ignored),
+	  and don't set a duration of 0 for buffers otherwise they are discarded
+	  by GstBaseSink.
+	  GstWavEnc needs some serious loving, after going through the code I'm
+	  really wondering how this can stay in -good ...
+
+2005-11-01 15:11:16 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  Fix leaks and invalid memory access as reported by valgrind
+	  Original commit message from CVS:
+	  * check/elements/matroskamux.c: (setup_src_pad), (setup_sink_pad),
+	  (setup_matroskamux), (check_buffer_data), (GST_START_TEST):
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_finalize),
+	  (gst_matroska_mux_reset), (gst_matroska_mux_audio_pad_setcaps),
+	  (gst_matroska_mux_start), (gst_matroska_mux_write_data),
+	  (gst_matroska_mux_collected):
+	  Fix leaks and invalid memory access as reported by valgrind
+
+2005-11-01 14:41:01 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* check/elements/matroskamux.c:
+	* tests/check/elements/matroskamux.c:
+	  ... and add the missing file
+	  Original commit message from CVS:
+	  ... and add the missing file
+
+2005-11-01 14:36:02 +0000  Michal Benes <michal.benes@xeris.cz>
+
+	  add a unit test for matroskamux fix the bugs that the unit test exposed
+	  Original commit message from CVS:
+	  Patch by: Michal Benes <michal.benes@xeris.cz>
+	  * check/Makefile.am:
+	  * gst/matroska/ebml-write.c: (gst_ebml_write_seek):
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_handle_src_event),
+	  (gst_matroska_mux_audio_pad_setcaps), (gst_matroska_mux_start):
+	  add a unit test for matroskamux
+	  fix the bugs that the unit test exposed
+
+2005-11-01 14:34:22 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/rtp/Makefile.am:
+	  fix Makefile.am
+	  Original commit message from CVS:
+	  fix Makefile.am
+
+2005-11-01 12:39:16 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/autodetect/: Fix state change function and use GST_DEBUG_FUNCPTR in class_init.
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautoaudiosink.c:
+	  (gst_auto_audio_sink_class_init),
+	  (gst_auto_audio_sink_change_state):
+	  * gst/autodetect/gstautovideosink.c:
+	  (gst_auto_video_sink_class_init),
+	  (gst_auto_video_sink_change_state):
+	  Fix state change function and use GST_DEBUG_FUNCPTR in
+	  class_init.
+
+2005-11-01 12:35:39 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/: Set timestamps on outgoing ebml headers as well, so that the element after matroskamux can get the tim...
+	  Original commit message from CVS:
+	  Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+	  * gst/matroska/ebml-write.c: (gst_ebml_write_new),
+	  (gst_ebml_write_reset), (gst_ebml_write_element_new):
+	  * gst/matroska/ebml-write.h:
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_write_data):
+	  Set timestamps on outgoing ebml headers as well, so that the
+	  element after matroskamux can get the timestamp already when
+	  reading the first ebml element and doesn't have to wait for
+	  the actual data buffer for that (#320308).
+
+2005-10-31 22:08:52 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ChangeLog:
+	* gst/videomixer/videomixer.c:
+	  gst/videomixer/videomixer.c (gst_videomixer_pad_unlink)
+	  Original commit message from CVS:
+	  2005-10-31  Andy Wingo  <wingo@pobox.com>
+	  * gst/videomixer/videomixer.c (gst_videomixer_pad_unlink)
+	  (gst_videomixer_pad_link): Kill some memleaks.
+	  (gst_videomixer_pad_get_property): Style fix.
+	  (gst_videomixer_pad_set_property): Style fix.
+	  (gst_videomixer_pad_init): Style fix.
+	  (gst_videomixer_update_queues): Kill memleak.
+	  (gst_videomixer_loop): Kill memleak.
+	  (gst_videomixer_collected): Kill memleak.
+
+2005-10-31 19:08:27 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* gst/auparse/gstauparse.c:
+	  Just some cleanup.
+	  Original commit message from CVS:
+	  Just some cleanup.
+
+2005-10-31 14:41:31 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* ext/speex/gstspeexenc.c:
+	  Add checks to GST_FLOW_NOT_LINKED for values returned from gst_pad_push.
+	  Original commit message from CVS:
+	  Add checks to GST_FLOW_NOT_LINKED for values returned from gst_pad_push.
+
+2005-10-31 12:00:10 +0000  Zeeshan Ali <zeenix@gmail.com>
+
+	* ChangeLog:
+	* gst/rtp/gstrtpg711dec.c:
+	* gst/rtp/gstrtpg711depay.c:
+	  Payloader now sets some default caps on the srcpad if caps on the sinkpad are never set. This is important for the g7...
+	  Original commit message from CVS:
+	  Payloader now sets some default caps on the srcpad if caps on the sinkpad are never set. This is important for the g711 to work with burger's rtpbin element.
+
+2005-10-28 19:19:40 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* common:
+	* ext/speex/gstspeexenc.c:
+	  Add checks for return values from gst_pad_push and gst_pad_alloc_buffer.
+	  Original commit message from CVS:
+	  Add checks for return values from gst_pad_push and gst_pad_alloc_buffer.
+
+2005-10-28 15:32:48 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/: Add SimpleBlock support to matroska demuxer and muxer (part of
+	  Original commit message from CVS:
+	  Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_init_stream),
+	  (gst_matroska_demux_parse_info),
+	  (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+	  (gst_matroska_demux_parse_cluster):
+	  * gst/matroska/matroska-ids.h:
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_class_init),
+	  (gst_matroska_mux_init), (gst_matroska_mux_start),
+	  (gst_matroska_mux_create_buffer_header),
+	  (gst_matroska_mux_write_data), (gst_matroska_mux_set_property),
+	  (gst_matroska_mux_get_property):
+	  * gst/matroska/matroska-mux.h:
+	  Add SimpleBlock support to matroska demuxer and muxer (part of
+	  Matroska v2). (#319731)
+
+2005-10-28 13:24:40 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/jpeg/gstjpegdec.*: Cleanups. Don't create caps for every chain.
+	  Original commit message from CVS:
+	  * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_init), (gst_jpeg_dec_chain),
+	  (gst_jpeg_dec_change_state):
+	  * ext/jpeg/gstjpegdec.h:
+	  Cleanups. Don't create caps for every chain.
+
+2005-10-27 18:46:32 +0000  Flavio Oliveira <flavio.oliveira@indt.org.br>
+
+	* ChangeLog:
+	* gst/law/alaw-encode.c:
+	* gst/law/alaw-encode.h:
+	* gst/law/mulaw-encode.c:
+	* gst/law/mulaw-encode.h:
+	  Fix to set timestamp on buffer, it was tested with RTP G711 elements.
+	  Original commit message from CVS:
+	  Fix to set timestamp on buffer, it was tested with RTP G711 elements.
+
+2005-10-27 11:27:53 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.h: Remove got_redirect from class structure as well.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.h:
+	  Remove got_redirect from class structure as well.
+
+2005-10-27 11:25:19 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/qtdemux/qtdemux.c: Remove 'got-redirect' signal and post element message on the bus instead.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_class_init),
+	  (qtdemux_parse_tree):
+	  Remove 'got-redirect' signal and post element message
+	  on the bus instead.
+
+2005-10-27 11:00:40 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/oss/gstosssrc.c: Set correct format on oss instead of a silly value.
+	  Original commit message from CVS:
+	  * sys/oss/gstosssrc.c: (gst_oss_src_prepare):
+	  Set correct format on oss instead of a silly value.
+
+2005-10-27 09:52:08 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/videobox/gstvideobox.c: Use liboil for
+	  Original commit message from CVS:
+	  2005-10-27  Julien MOUTTE  <julien@moutte.net>
+	  * gst/videobox/gstvideobox.c: (gst_video_box_class_init),
+	  (gst_video_box_transform_caps), (gst_video_box_set_caps),
+	  (gst_video_box_get_unit_size), (gst_video_box_copy_plane_i420),
+	  (gst_video_box_i420), (gst_video_box_ayuv): Use liboil for
+	  I420 rendering as well, doesn't bring much for my platform.
+	  Might help on some other platforms.
+
+2005-10-26 21:47:36 +0000  Zeeshan Ali <zeenix@gmail.com>
+
+	* ChangeLog:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmenc.c:
+	* gst/rtp/gstrtpgsmparse.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	  Declaring the padtemplate correctly.
+	  Original commit message from CVS:
+	  Declaring the padtemplate correctly.
+
+2005-10-26 20:28:32 +0000  Zeeshan Ali <zeenix@gmail.com>
+
+	* ChangeLog:
+	* gst/rtp/gstrtpg711dec.c:
+	* gst/rtp/gstrtpg711depay.c:
+	* gst/rtp/gstrtpg711enc.c:
+	* gst/rtp/gstrtpg711pay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmenc.c:
+	* gst/rtp/gstrtpgsmparse.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	  Setting the proper copyright notice.
+	  Original commit message from CVS:
+	  Setting the proper copyright notice.
+
+2005-10-26 17:23:06 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/videobox/Makefile.am: Use liboil.
+	  Original commit message from CVS:
+	  2005-10-26  Julien MOUTTE  <julien@moutte.net>
+	  * gst/videobox/Makefile.am: Use liboil.
+	  * gst/videobox/gstvideobox.c: (gst_video_box_class_init),
+	  (gst_video_box_set_property), (gst_video_box_transform_caps),
+	  (gst_video_box_set_caps), (gst_video_box_get_unit_size),
+	  (gst_video_box_ayuv): Lot of optimization in AYUV rendering
+	  using liboil. Will dot the same to I420 border generation
+	  tomorrow.
+
+2005-10-26 16:36:01 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/rtp/Makefile.am:
+	  fix automake warnings
+	  Original commit message from CVS:
+	  fix automake warnings
+
+2005-10-26 14:50:59 +0000  Zeeshan Ali <zeenix@gmail.com>
+
+	* ChangeLog:
+	* gst/rtp/gstrtpg711dec.c:
+	* gst/rtp/gstrtpg711dec.h:
+	* gst/rtp/gstrtpg711depay.c:
+	* gst/rtp/gstrtpg711depay.h:
+	* gst/rtp/gstrtpg711enc.c:
+	* gst/rtp/gstrtpg711pay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmdepay.h:
+	* gst/rtp/gstrtpgsmenc.c:
+	* gst/rtp/gstrtpgsmparse.c:
+	* gst/rtp/gstrtpgsmparse.h:
+	* gst/rtp/gstrtpgsmpay.c:
+	  Hacked the G711 (de)payloader to try to make things right. rtpg711dec now inherits from the basertpdepayloader.
+	  Original commit message from CVS:
+	  Hacked the G711 (de)payloader to try to make things right. rtpg711dec now inherits from the basertpdepayloader.
+
+2005-10-26 14:23:45 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/videobox/gstvideobox.c: Removing this forgotten debug.
+	  Original commit message from CVS:
+	  2005-10-26  Julien MOUTTE  <julien@moutte.net>
+	  * gst/videobox/gstvideobox.c: (gst_video_box_class_init),
+	  (gst_video_box_transform_caps), (gst_video_box_get_unit_size),
+	  (gst_video_box_ayuv): Removing this forgotten debug.
+
+2005-10-26 14:08:49 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/videobox/gstvideobox.c: Fix the stride issue when boxing to AYUV.
+	  Original commit message from CVS:
+	  2005-10-26  Julien MOUTTE  <julien@moutte.net>
+	  * gst/videobox/gstvideobox.c: (gst_video_box_class_init),
+	  (gst_video_box_transform_caps), (gst_video_box_get_unit_size),
+	  (gst_video_box_ayuv): Fix the stride issue when boxing to AYUV.
+
+2005-10-26 11:12:34 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/oss/: Actually use the 'oss' debug category we register.
+	  Original commit message from CVS:
+	  * sys/oss/gstossaudio.c:
+	  * sys/oss/gstossdmabuffer.c:
+	  * sys/oss/gstosshelper.c:
+	  * sys/oss/gstossmixer.c:
+	  * sys/oss/gstossmixerelement.c:
+	  * sys/oss/gstossmixertrack.c:
+	  * sys/oss/gstosssink.c:
+	  * sys/oss/gstosssrc.c:
+	  Actually use the 'oss' debug category we register.
+
+2005-10-26 10:38:18 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/videomixer/videomixer.c: Use gst_pad_get_parent and drop the ref that was added through that call.
+	  Original commit message from CVS:
+	  2005-10-26  Julien MOUTTE  <julien@moutte.net>
+	  * gst/videomixer/videomixer.c:
+	  (gst_videomixer_pad_set_property),
+	  (gst_videomixer_pad_sink_setcaps), (gst_videomixer_getcaps):
+	  Use gst_pad_get_parent and drop the ref that was added through
+	  that call.
+
+2005-10-26 10:03:02 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* gst/rtp/gstrtpgsmenc.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	  fix compilation
+	  Original commit message from CVS:
+	  fix compilation
+
+2005-10-25 21:09:36 +0000  Flavio Oliveira <flavio.oliveira@indt.org.br>
+
+	* ChangeLog:
+	* gst/rtp/gstrtpg711dec.c:
+	* gst/rtp/gstrtpg711depay.c:
+	  Just removed a couple of lines of weird code used during development/test time.
+	  Original commit message from CVS:
+	  Just removed a couple of lines of weird code used during development/test time.
+
+2005-10-25 19:19:38 +0000  Flavio Oliveira <flavio.oliveira@indt.org.br>
+
+	* ChangeLog:
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpg711dec.c:
+	* gst/rtp/gstrtpg711dec.h:
+	* gst/rtp/gstrtpg711depay.c:
+	* gst/rtp/gstrtpg711depay.h:
+	* gst/rtp/gstrtpg711enc.c:
+	* gst/rtp/gstrtpg711enc.h:
+	* gst/rtp/gstrtpg711pay.c:
+	* gst/rtp/gstrtpg711pay.h:
+	  G711 payloader and depayloader created by Edgard Lima (it supports mulaw and alaw (dec)encoders)
+	  Original commit message from CVS:
+	  G711 payloader and depayloader created by Edgard Lima (it supports
+	  mulaw and alaw (dec)encoders)
+
+2005-10-25 17:55:19 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/videobox/gstvideobox.c: Doh ! I introduced wingo's bug again ! Sorry...
+	  Original commit message from CVS:
+	  2005-10-25  Julien MOUTTE  <julien@moutte.net>
+	  * gst/videobox/gstvideobox.c: (gst_video_box_class_init),
+	  (gst_video_box_transform_caps), (gst_video_box_get_unit_size):
+	  Doh ! I introduced wingo's bug again ! Sorry...
+
+2005-10-25 16:02:38 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* ChangeLog:
+	* gst/rtp/Makefile.am:
+	  add missing header files for disting
+	  Original commit message from CVS:
+	  add missing header files for disting
+
+2005-10-25 15:07:02 +0000  Zeeshan Ali <zeenix@gmail.com>
+
+	* ChangeLog:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmdepay.h:
+	* gst/rtp/gstrtpgsmenc.c:
+	* gst/rtp/gstrtpgsmenc.h:
+	* gst/rtp/gstrtpgsmparse.c:
+	* gst/rtp/gstrtpgsmparse.h:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtpgsmpay.h:
+	  Getting the GSM (de)payloader working and compatible with our plans for RTP.
+	  Original commit message from CVS:
+	  Getting the GSM (de)payloader working and compatible with our plans for RTP.
+
+2005-10-25 13:03:04 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst/rtp/gstrtp.c:
+	  fix mistaken claim on GPL, its LGPL
+	  Original commit message from CVS:
+	  fix mistaken claim on GPL, its LGPL
+
+2005-10-25 10:47:09 +0000  Julien Moutte <julien@moutte.net>
+
+	  ext/libpng/gstpngdec.c: Push a newsegment event, move some redundant code in a single place.
+	  Original commit message from CVS:
+	  2005-10-25  Julien MOUTTE  <julien@moutte.net>
+	  * ext/libpng/gstpngdec.c: (user_info_callback),
+	  (gst_pngdec_caps_create_and_set), (gst_pngdec_task): Push
+	  a newsegment event, move some redundant code in a single place.
+
+2005-10-25 10:23:26 +0000  Julien Moutte <julien@moutte.net>
+
+	  ext/libpng/gstpngdec.c: Temporary hack to get correct colors order when we have a png image with alpha channel.
+	  Original commit message from CVS:
+	  2005-10-25  Julien MOUTTE  <julien@moutte.net>
+	  * ext/libpng/gstpngdec.c: (user_info_callback),
+	  (gst_pngdec_caps_create_and_set), (gst_pngdec_task): Temporary
+	  hack to get correct colors order when we have a png image with
+	  alpha channel.
+
+2005-10-24 17:29:02 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/dv/gstdvdemux.c: Call gst_element_no_more_pads when there will be no more pads.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_add_pads):
+	  Call gst_element_no_more_pads when there will be no more pads.
+
+2005-10-24 16:39:38 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Added two new payloaders, an RFC 2190 payloader for h263 and a payload convertor for an asterisk server.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstasteriskh263.c: (gst_asteriskh263_get_type),
+	  (gst_asteriskh263_base_init), (gst_asteriskh263_class_init),
+	  (gst_asteriskh263_init), (gst_asteriskh263_finalize),
+	  (gst_asteriskh263_chain), (gst_asteriskh263_set_property),
+	  (gst_asteriskh263_get_property), (gst_asteriskh263_change_state),
+	  (gst_asteriskh263_plugin_init):
+	  * gst/rtp/gstasteriskh263.h:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtph263enc.c: (gst_rtph263enc_get_type),
+	  (gst_rtph263enc_base_init), (gst_rtph263enc_class_init),
+	  (gst_rtph263enc_init), (gst_rtph263enc_finalize),
+	  (gst_rtph263enc_setcaps), (gst_rtph263enc_gobfiner),
+	  (gst_rtph263enc_flush), (gst_rtph263enc_handle_buffer),
+	  (gst_rtph263enc_plugin_init):
+	  * gst/rtp/gstrtph263enc.h:
+	  Added two new payloaders, an RFC 2190 payloader for h263 and
+	  a payload convertor for an asterisk server.
+
+2005-10-24 15:57:17 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/oss/gstosssrc.c: Set bytes_per_sample correctly (is not always 4, but depends on width and number of channels).
+	  Original commit message from CVS:
+	  * sys/oss/gstosssrc.c: (gst_oss_src_prepare):
+	  Set bytes_per_sample correctly (is not always 4, but
+	  depends on width and number of channels).
+
+2005-10-24 15:50:06 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacenc.*: Fix seeking, so that flacenc can rewrite the header with the correct duration and amount of sa...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacenc.c: (gst_flacenc_base_init),
+	  (gst_flacenc_init), (gst_flacenc_sink_setcaps),
+	  (gst_flacenc_seek_callback), (gst_flacenc_write_callback),
+	  (gst_flacenc_sink_event), (gst_flacenc_chain),
+	  (gst_flacenc_set_property), (gst_flacenc_get_property),
+	  (gst_flacenc_change_state):
+	  * ext/flac/gstflacenc.h:
+	  Fix seeking, so that flacenc can rewrite the header with the
+	  correct duration and amount of samples and all that at EOS;
+	  also set timestamps and granulepos on outgoing buffers; add
+	  debug category; fix state change function.
+
+2005-10-24 13:46:09 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/videomixer/videomixer.c: Don't restrict video geometry from 16 to 4096.
+	  Original commit message from CVS:
+	  2005-10-24  Julien MOUTTE  <julien@moutte.net>
+	  * gst/videomixer/videomixer.c: Don't restrict video geometry
+	  from 16 to 4096.
+
+2005-10-24 13:22:14 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/videobox/gstvideobox.c: Fix caps negotiation correctly, add debugging category.
+	  Original commit message from CVS:
+	  2005-10-24  Julien MOUTTE  <julien@moutte.net>
+	  * gst/videobox/gstvideobox.c: (gst_video_box_class_init),
+	  (gst_video_box_transform_caps), (gst_video_box_get_unit_size):
+	  Fix caps negotiation correctly, add debugging category.
+
+2005-10-24 13:02:47 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* ChangeLog:
+	* configure.ac:
+	  port over plugin listing from base
+	  Original commit message from CVS:
+	  port over plugin listing from base
+
+2005-10-24 08:59:24 +0000  Julien Moutte <julien@moutte.net>
+
+	  ext/libpng/gstpngdec.c: Don't use fixed caps on a sink pad.
+	  Original commit message from CVS:
+	  2005-10-24  Julien MOUTTE  <julien@moutte.net>
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_init): Don't use fixed
+	  caps on
+	  a sink pad.
+
+2005-10-23 23:05:59 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* configure.ac:
+	* docs/upload.mak:
+	  back to HEAD
+	  Original commit message from CVS:
+	  back to HEAD
+
+=== release 0.9.4 ===
+
+2005-10-23 22:43:08 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* docs/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/gst-plugins-good-plugins.signals:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-alphacolor.xml:
+	* docs/plugins/inspect/plugin-auparse.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-cairo.xml:
+	* docs/plugins/inspect/plugin-debug.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-efence.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-flxdec.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-matroska.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-navigationtest.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-videomixer.xml:
+	* docs/plugins/inspect/plugin-wavenc.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	  releasing 0.9.4
+	  Original commit message from CVS:
+	  releasing 0.9.4
+
+2005-10-23 11:07:10 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/libpng/gstpngdec.c:
+	* gst/wavparse/gstwavparse.c:
+	* po/POTFILES.in:
+	  STOPPED->FAILED
+	  Original commit message from CVS:
+	  STOPPED->FAILED
+
+2005-10-21 17:00:58 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/speex/gstspeexenc.c: Add position and duration query, fix query type function.
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexenc.c: (gst_speexenc_get_query_types),
+	  (gst_speexenc_src_query):
+	  Add position and duration query, fix query type function.
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream),
+	  (gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps):
+	  Let's not set non-fixed caps on source pads.
+
+2005-10-21 16:15:57 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  Set correct stream_time in newsegment event. avi can also handle a duration query now.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_demux_frame):
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_get_src_query_types),
+	  (gst_avi_demux_handle_seek):
+	  Set correct stream_time in newsegment event.
+	  avi can also handle a duration query now.
+
+2005-10-21 10:06:40 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  update for latest additions
+	  Original commit message from CVS:
+	  update for latest additions
+
+2005-10-20 19:14:27 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-demux.c: Fix duration query; fix basetime in newsegment event after seek; fix duration in initi...
+	  Original commit message from CVS:
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_handle_src_query),
+	  (gst_matroska_demux_handle_seek_event),
+	  (gst_matroska_demux_loop_stream_parse_id):
+	  Fix duration query; fix basetime in newsegment event after
+	  seek; fix duration in initial newsegment event.
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_audio_pad_setcaps), (gst_matroska_mux_start):
+	  Extract number of channels and samplerate from vorbis headers;
+	  add some debug messages when querying the durations of the
+	  input streams.
+
+2005-10-20 11:50:53 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/wavparse/gstwavparse.c: Set stream time correctly in newsegment.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_handle_seek),
+	  (gst_wavparse_stream_headers), (gst_wavparse_stream_data),
+	  (gst_wavparse_pad_convert), (gst_wavparse_srcpad_event):
+	  Set stream time correctly in newsegment.
+
+2005-10-20 11:39:40 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/avi/gstavidemux.c: Correctly fill in the stream time.
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_handle_seek):
+	  Correctly fill in the stream time.
+
+2005-10-19 20:48:24 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* check/elements/level.c:
+	* gst/level/gstlevel.c:
+	* gst/level/level-example.c:
+	* tests/check/elements/level.c:
+	  use ELEMENT messages instead
+	  Original commit message from CVS:
+	  use ELEMENT messages instead
+
+2005-10-19 15:58:00 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/: API change fix.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_get_src_query_types),
+	  (gst_qtdemux_handle_src_query):
+	  * gst/speed/gstspeed.c: (speed_get_query_types), (speed_src_query):
+	  * gst/tta/gstttaparse.c: (gst_tta_parse_src_event),
+	  (gst_tta_parse_get_query_types), (gst_tta_parse_query):
+	  API change fix.
+
+2005-10-19 15:57:04 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  API change fix.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_get_src_query_types),
+	  (gst_dvdemux_src_query):
+	  * ext/flac/gstflacdec.c: (gst_flacdec_length),
+	  (gst_flacdec_src_query):
+	  * ext/raw1394/gstdv1394src.c: (gst_dv1394src_query):
+	  * ext/speex/gstspeexdec.c: (speex_dec_src_query):
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query):
+	  * gst/debug/gstnavseek.c: (gst_navseek_seek):
+	  * gst/debug/progressreport.c: (gst_progress_report_report):
+	  * gst/matroska/ebml-read.c: (gst_ebml_read_get_length):
+	  * gst/matroska/matroska-demux.c:
+	  (gst_matroska_demux_handle_src_query):
+	  * gst/matroska/matroska-mux.c: (gst_matroska_mux_start):
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_handle_seek),
+	  (gst_wavparse_stream_headers), (gst_wavparse_stream_data),
+	  (gst_wavparse_pad_convert), (gst_wavparse_pad_query),
+	  (gst_wavparse_srcpad_event):
+	  API change fix.
+
+2005-10-19 10:57:46 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/goom/: Make inline functions either 'static inline' or 'extern inline', otherwise the Forte compiler apparently w...
+	  Original commit message from CVS:
+	  * gst/goom/filters.c:
+	  * gst/goom/graphic.h:
+	  * gst/goom/lines.c:
+	  Make inline functions either 'static inline' or 'extern inline',
+	  otherwise the Forte compiler apparently won't inline them (#317300).
+
+2005-10-18 22:50:11 +0000  Julien Moutte <julien@moutte.net>
+
+	  ext/libpng/gstpngdec.c: forgot the buffer unref in pull.
+	  Original commit message from CVS:
+	  2005-10-19  Julien MOUTTE  <julien@moutte.net>
+	  * ext/libpng/gstpngdec.c: forgot the buffer unref in pull.
+
+2005-10-18 22:44:11 +0000  Julien Moutte <julien@moutte.net>
+
+	  ext/libpng/gstpngdec.*: Complete rewrite of pngdec. It's now very nice and handle push/pull based model. if you have ...
+	  Original commit message from CVS:
+	  2005-10-19  Julien MOUTTE  <julien@moutte.net>
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_class_init),
+	  (gst_pngdec_init), (user_error_fn), (user_warning_fn),
+	  (user_info_callback), (user_endrow_callback),
+	  (user_end_callback),
+	  (user_read_data), (gst_pngdec_caps_create_and_set),
+	  (gst_pngdec_task), (gst_pngdec_chain), (gst_pngdec_sink_event),
+	  (gst_pngdec_libpng_clear), (gst_pngdec_libpng_init),
+	  (gst_pngdec_change_state), (gst_pngdec_sink_activate_push),
+	  (gst_pngdec_sink_activate_pull), (gst_pngdec_sink_activate):
+	  * ext/libpng/gstpngdec.h: Complete rewrite of pngdec. It's now
+	  very nice and handle push/pull based model. if you have filesrc
+	  connected to it, it will do random access to load the png file.
+	  If you have a network source that can't do _getrange, it does
+	  progressive loading through the chain function.
+	  * gst/alpha/gstalphacolor.c: (gst_alpha_color_transform_caps),
+	  (transform_rgb), (transform_bgr): Fix caps negotiation correctly
+	  thanks to Master Wim Taymans ;-)
+
+2005-10-18 18:12:31 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/: Ported matroska demuxer to 0.9.
+	  Original commit message from CVS:
+	  * gst/matroska/Makefile.am:
+	  * gst/matroska/ebml-read.c:
+	  * gst/matroska/ebml-read.h:
+	  * gst/matroska/matroska-demux.c:
+	  * gst/matroska/matroska-demux.h:
+	  * gst/matroska/matroska.c: (plugin_init):
+	  Ported matroska demuxer to 0.9.
+
+2005-10-18 18:06:14 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/matroska/matroska-mux.c: Fix mpeg4 input handling (#318847); also, while we're at it, fix media type for Motion-J...
+	  Original commit message from CVS:
+	  Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+	  * gst/matroska/matroska-mux.c:
+	  (gst_matroska_mux_video_pad_setcaps),
+	  (gst_matroska_mux_audio_pad_setcaps):
+	  Fix mpeg4 input handling (#318847); also, while we're at it,
+	  fix media type for Motion-JPEG: should be image/jpeg.
+
+2005-10-18 13:21:18 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/wavparse/gstwavparse.c: Fix for segment-start/stop API change.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_handle_seek),
+	  (gst_wavparse_stream_headers), (gst_wavparse_stream_data),
+	  (gst_wavparse_pad_convert), (gst_wavparse_srcpad_event):
+	  Fix for segment-start/stop API change.
+
+2005-10-17 17:18:56 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/alpha/gstalphacolor.c: Handle caps negotiation in a better way.
+	  Original commit message from CVS:
+	  2005-10-17  Julien MOUTTE  <julien@moutte.net>
+	  * gst/alpha/gstalphacolor.c: (gst_alpha_color_transform_caps),
+	  (transform_rgb), (transform_bgr): Handle caps negotiation in a
+	  better
+	  way.
+
+2005-10-17 16:59:20 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/videobox/gstvideobox.c: Fix caps nego some more to get
+	  Original commit message from CVS:
+	  2005-10-17  Julien MOUTTE  <julien@moutte.net>
+	  * gst/videobox/gstvideobox.c: (gst_video_box_transform_caps),
+	  (gst_video_box_get_unit_size): Fix caps nego some more to get
+	  AYUV
+	  output declared in transform_caps.
+
+2005-10-17 15:23:24 +0000  Julien Moutte <julien@moutte.net>
+
+	  ext/libpng/gstpngdec.c: We use fixed caps.
+	  Original commit message from CVS:
+	  2005-10-17  Julien MOUTTE  <julien@moutte.net>
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_init): We use fixed caps.
+
+2005-10-17 15:14:29 +0000  Julien Moutte <julien@moutte.net>
+
+	  gst/videobox/gstvideobox.c: Fix wrong size calculations and implement get_unit_size correctly.
+	  Original commit message from CVS:
+	  2005-10-17  Julien MOUTTE  <julien@moutte.net>
+	  * gst/videobox/gstvideobox.c: (gst_video_box_transform_caps),
+	  (gst_video_box_get_unit_size): Fix wrong size calculations and
+	  implement get_unit_size correctly.
+
+2005-10-17 14:56:12 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Enable flx plugin.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Enable flx plugin.
+	  * gst/flx/gstflxdec.c: (flx_decode_chunks):
+	  Fix gcc4 signedness issue.
+
+2005-10-17 08:46:30 +0000  Julien Moutte <julien@moutte.net>
+
+	  configure.ac: Adding videomixer.
+	  Original commit message from CVS:
+	  2005-10-17  Julien MOUTTE  <julien@moutte.net>
+	  * configure.ac: Adding videomixer.
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_class_init),
+	  (user_read_data), (gst_pngdec_chain): More debugging.
+	  * gst/alpha/Makefile.am: Adding alphacolor
+	  * gst/alpha/gstalphacolor.c: (gst_alpha_color_base_init),
+	  (gst_alpha_color_class_init), (gst_alpha_color_init),
+	  (gst_alpha_color_transform_caps), (gst_alpha_color_set_caps),
+	  (transform_rgb), (transform_bgr),
+	  (gst_alpha_color_transform_ip),
+	  (plugin_init): Ported to 0.9 using in place base tranform.
+	  * gst/videomixer/Makefile.am:
+	  * gst/videomixer/videomixer.c: (gst_videomixer_pad_get_type),
+	  (gst_videomixer_pad_class_init),
+	  (gst_videomixer_pad_sink_setcaps),
+	  (gst_videomixer_pad_link), (gst_videomixer_pad_unlink),
+	  (gst_videomixer_pad_init), (gst_videomixer_class_init),
+	  (gst_videomixer_init), (gst_videomixer_getcaps),
+	  (gst_videomixer_request_new_pad), (gst_videomixer_fill_queues),
+	  (gst_videomixer_blend_buffers), (gst_videomixer_update_queues),
+	  (gst_videomixer_collected), (gst_videomixer_change_state):
+	  Ported
+	  to 0.9 using collectpads.
+
+2005-10-16 21:19:44 +0000  Zeeshan Ali <zeenix@gmail.com>
+
+	* ChangeLog:
+	* common:
+	* configure.ac:
+	* gst/flx/Makefile.am:
+	* gst/flx/gstflxdec.c:
+	* gst/flx/gstflxdec.h:
+	  flx plugin ported to 0.9
+	  Original commit message from CVS:
+	  flx plugin ported to 0.9
+
+2005-10-16 14:33:05 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* ext/shout2/gstshout2.c:
+	  use gst_version_string
+	  Original commit message from CVS:
+	  use gst_version_string
+
+2005-10-16 13:17:11 +0000  Andy Wingo <wingo@pobox.com>
+
+	  configure.ac: GLIB_CHECK.
+	  Original commit message from CVS:
+	  2005-10-16  Andy Wingo  <wingo@pobox.com>
+	  * configure.ac: GLIB_CHECK.
+
+2005-10-15 16:48:55 +0000  Julien Moutte <julien@moutte.net>
+
+	  ext/libpng/: Ported pngdec to 0.9
+	  Original commit message from CVS:
+	  2005-10-15  Julien MOUTTE  <julien@moutte.net>
+	  * ext/libpng/Makefile.am:
+	  * ext/libpng/gstpng.c: (plugin_init):
+	  * ext/libpng/gstpngdec.c: (gst_pngdec_class_init),
+	  (gst_pngdec_init), (user_read_data), (gst_pngdec_chain):
+	  * ext/libpng/gstpngdec.h: Ported pngdec to 0.9
+
+2005-10-14 12:43:30 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  Port matroska muxer to 0.9 (#318847).
+	  Original commit message from CVS:
+	  Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+	  * configure.ac:
+	  * gst/matroska/Makefile.am:
+	  * gst/matroska/ebml-ids.h:
+	  * gst/matroska/ebml-write.c:
+	  * gst/matroska/ebml-write.h:
+	  * gst/matroska/matroska-ids.h:
+	  * gst/matroska/matroska-mux.c:
+	  * gst/matroska/matroska-mux.h:
+	  * gst/matroska/matroska.c: (plugin_init):
+	  Port matroska muxer to 0.9 (#318847).
+
+2005-10-13 18:59:35 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/speex/gstspeexenc.c: Fix handling of GST_TAG_DATE, which is now of GST_TYPE_DATE; use GST_READ_UINT32_LE() and fr...
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexenc.c: (gst_speexenc_get_tag_value),
+	  (comment_init), (comment_add):
+	  Fix handling of GST_TAG_DATE, which is now of GST_TYPE_DATE;
+	  use GST_READ_UINT32_LE() and friends rather than the private
+	  implementation of those same macros.
+
+2005-10-13 16:01:35 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/cairo/Makefile.am:
+	  fix dist
+	  Original commit message from CVS:
+	  fix dist
+
+2005-10-13 15:28:01 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  examples/stats/mp2ogg.c: more typo fixes
+	  Original commit message from CVS:
+	  * examples/stats/mp2ogg.c:
+	  more typo fixes
+
+2005-10-12 14:29:55 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  renamed GST_FLAGS macros to GST_OBJECT_FLAGS moved bitshift from macro to enum definition
+	  Original commit message from CVS:
+	  * examples/indexing/indexmpeg.c: (main):
+	  * ext/artsd/gstartsdsink.c: (gst_artsdsink_open_audio),
+	  (gst_artsdsink_close_audio), (gst_artsdsink_change_state):
+	  * ext/artsd/gstartsdsink.h:
+	  * ext/audiofile/gstafparse.c: (gst_afparse_open_file),
+	  (gst_afparse_close_file):
+	  * ext/audiofile/gstafparse.h:
+	  * ext/audiofile/gstafsink.c: (gst_afsink_open_file),
+	  (gst_afsink_close_file), (gst_afsink_chain),
+	  (gst_afsink_change_state):
+	  * ext/audiofile/gstafsink.h:
+	  * ext/audiofile/gstafsrc.c: (gst_afsrc_open_file),
+	  (gst_afsrc_close_file), (gst_afsrc_change_state):
+	  * ext/audiofile/gstafsrc.h:
+	  * ext/cdaudio/gstcdaudio.c: (gst_cdaudio_init):
+	  * ext/directfb/directfbvideosink.c: (gst_directfbvideosink_init):
+	  * ext/dts/gstdtsdec.c: (gst_dtsdec_init):
+	  * ext/jack/gstjack.h:
+	  * ext/jack/gstjackbin.c: (gst_jack_bin_init),
+	  (gst_jack_bin_change_state):
+	  * ext/musepack/gstmusepackdec.c: (gst_musepackdec_init):
+	  * ext/musicbrainz/gsttrm.c: (gst_musicbrainz_init):
+	  * ext/nas/nassink.c: (gst_nassink_open_audio),
+	  (gst_nassink_close_audio), (gst_nassink_change_state):
+	  * ext/nas/nassink.h:
+	  * ext/polyp/polypsink.c: (gst_polypsink_init):
+	  * ext/sdl/sdlvideosink.c: (gst_sdlvideosink_change_state):
+	  * ext/sdl/sdlvideosink.h:
+	  * ext/smoothwave/gstsmoothwave.c: (gst_smoothwave_init):
+	  * ext/sndfile/gstsf.c: (gst_sf_set_property),
+	  (gst_sf_change_state), (gst_sf_release_request_pad),
+	  (gst_sf_open_file), (gst_sf_close_file), (gst_sf_loop):
+	  * ext/sndfile/gstsf.h:
+	  * ext/swfdec/gstswfdec.c: (gst_swfdec_init):
+	  * ext/tarkin/gsttarkindec.c: (gst_tarkindec_init):
+	  * gst/apetag/apedemux.c: (gst_ape_demux_init):
+	  * gst/cdxaparse/gstcdxaparse.c: (gst_cdxaparse_init):
+	  * gst/cdxaparse/gstcdxastrip.c: (gst_cdxastrip_init):
+	  * gst/festival/gstfestival.c: (gst_festival_change_state):
+	  * gst/festival/gstfestival.h:
+	  * gst/mpeg2sub/gstmpeg2subt.c: (gst_mpeg2subt_init):
+	  * gst/multifilesink/gstmultifilesink.c: (gst_multifilesink_init),
+	  (gst_multifilesink_set_location), (gst_multifilesink_open_file),
+	  (gst_multifilesink_close_file), (gst_multifilesink_next_file),
+	  (gst_multifilesink_pad_query), (gst_multifilesink_handle_event),
+	  (gst_multifilesink_chain), (gst_multifilesink_change_state):
+	  * gst/multifilesink/gstmultifilesink.h:
+	  * gst/videodrop/gstvideodrop.c: (gst_videodrop_init):
+	  * sys/cdrom/gstcdplayer.c: (cdplayer_init):
+	  * sys/dxr3/dxr3audiosink.c: (dxr3audiosink_init),
+	  (dxr3audiosink_open), (dxr3audiosink_close),
+	  (dxr3audiosink_chain_pcm), (dxr3audiosink_chain_ac3),
+	  (dxr3audiosink_change_state):
+	  * sys/dxr3/dxr3audiosink.h:
+	  * sys/dxr3/dxr3spusink.c: (dxr3spusink_init), (dxr3spusink_open),
+	  (dxr3spusink_close), (dxr3spusink_chain),
+	  (dxr3spusink_change_state):
+	  * sys/dxr3/dxr3spusink.h:
+	  * sys/dxr3/dxr3videosink.c: (dxr3videosink_init),
+	  (dxr3videosink_open), (dxr3videosink_close),
+	  (dxr3videosink_write_data), (dxr3videosink_change_state):
+	  * sys/dxr3/dxr3videosink.h:
+	  * sys/glsink/glimagesink.c: (gst_glimagesink_init):
+	  * sys/qcam/gstqcamsrc.c: (gst_qcamsrc_change_state),
+	  (gst_qcamsrc_open), (gst_qcamsrc_close):
+	  * sys/qcam/gstqcamsrc.h:
+	  * sys/v4l2/gstv4l2src.c: (gst_v4l2src_init):
+	  * sys/vcd/vcdsrc.c: (gst_vcdsrc_set_property), (gst_vcdsrc_get),
+	  (gst_vcdsrc_open_file), (gst_vcdsrc_close_file),
+	  (gst_vcdsrc_change_state), (gst_vcdsrc_recalculate):
+	  * sys/vcd/vcdsrc.h:
+	  renamed GST_FLAGS macros to GST_OBJECT_FLAGS
+	  moved bitshift from macro to enum definition
+
+2005-10-12 14:29:43 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  renamed GST_FLAGS macros to GST_OBJECT_FLAGS moved bitshift from macro to enum definition
+	  Original commit message from CVS:
+	  * examples/indexing/indexmpeg.c: (main):
+	  * ext/esd/esdmon.c: (gst_esdmon_open_audio),
+	  (gst_esdmon_close_audio), (gst_esdmon_change_state):
+	  * ext/esd/esdmon.h:
+	  * ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_init):
+	  * ext/pango/gsttextoverlay.c: (gst_textoverlay_init):
+	  * gst/autodetect/gstautoaudiosink.c: (gst_auto_audio_sink_init):
+	  * gst/autodetect/gstautovideosink.c: (gst_auto_video_sink_init):
+	  * gst/avi/gstavimux.c: (gst_avimux_init):
+	  * gst/matroska/matroska-demux.c: (gst_matroska_demux_init):
+	  * gst/multipart/multipartdemux.c: (gst_multipart_demux_init):
+	  * gst/multipart/multipartmux.c: (gst_multipart_mux_init):
+	  * gst/oldcore/gstmultifilesrc.c: (gst_multifilesrc_init),
+	  (gst_multifilesrc_get), (gst_multifilesrc_open_file),
+	  (gst_multifilesrc_close_file), (gst_multifilesrc_change_state):
+	  * gst/oldcore/gstmultifilesrc.h:
+	  * gst/oldcore/gstpipefilter.c: (gst_pipefilter_init),
+	  (gst_pipefilter_open_file), (gst_pipefilter_close_file),
+	  (gst_pipefilter_change_state):
+	  * gst/oldcore/gstpipefilter.h:
+	  * gst/smoothwave/gstsmoothwave.c: (gst_smoothwave_init):
+	  * gst/videomixer/videomixer.c: (gst_videomixer_init):
+	  * sys/osxaudio/gstosxaudiosink.c: (gst_osxaudiosink_init):
+	  * sys/osxaudio/gstosxaudiosink.h:
+	  * sys/osxaudio/gstosxaudiosrc.h:
+	  renamed GST_FLAGS macros to GST_OBJECT_FLAGS
+	  moved bitshift from macro to enum definition
+
+2005-10-12 03:14:57 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/Makefile.am:
+	  dist cairo
+	  Original commit message from CVS:
+	  dist cairo
+
+2005-10-12 03:12:57 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  ext/: update of cairo-based timeoverlay to 1.0 Cairo API doesn't work yet for resizing of output sink
+	  Original commit message from CVS:
+	  * ext/Makefile.am:
+	  * ext/cairo/Makefile.am:
+	  * ext/cairo/gstcairo.c: (plugin_init):
+	  * ext/cairo/gsttextoverlay.c: (gst_textoverlay_change_state):
+	  * ext/cairo/gsttimeoverlay.c: (gst_timeoverlay_update_font_height),
+	  (gst_timeoverlay_setup), (gst_timeoverlay_planar411):
+	  * ext/cairo/gsttimeoverlay.h:
+	  update of cairo-based timeoverlay to 1.0 Cairo API
+	  doesn't work yet for resizing of output sink
+
+2005-10-12 03:07:26 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* configure.ac:
+	  don't build checks if we don't have check
+	  Original commit message from CVS:
+	  don't build checks if we don't have check
+
+2005-10-12 03:03:27 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* Makefile.am:
+	* common:
+	  don't build checks if we don't have gstcheck
+	  Original commit message from CVS:
+	  don't build checks if we don't have gstcheck
+
+2005-10-11 17:38:29 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/speex/gstspeexdec.c: newsegment API fix.
+	  Original commit message from CVS:
+	  * ext/speex/gstspeexdec.c: (speex_dec_event), (speex_dec_chain):
+	  newsegment API fix.
+
+2005-10-11 16:34:36 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/: newsegment API update.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header):
+	  * gst/tta/gstttaparse.c: (gst_tta_parse_src_event),
+	  (gst_tta_parse_parse_header):
+	  newsegment API update.
+
+2005-10-11 16:33:08 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  newsegment API update.
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_handle_sink_event),
+	  (gst_dvdemux_demux_frame):
+	  * ext/flac/gstflacdec.c: (gst_flacdec_write):
+	  * gst/auparse/gstauparse.c: (gst_auparse_chain):
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_stream_header),
+	  (gst_avi_demux_handle_seek):
+	  * gst/goom/gstgoom.c: (gst_goom_event):
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_stop_file):
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_handle_seek),
+	  (gst_wavparse_stream_headers), (gst_wavparse_stream_data),
+	  (gst_wavparse_loop), (gst_wavparse_pad_convert),
+	  (gst_wavparse_srcpad_event):
+	  newsegment API update.
+
+2005-10-11 10:07:35 +0000  Andy Wingo <wingo@pobox.com>
+
+	  ext/speex/gstspeexenc.c: Signedness cleanups.
+	  Original commit message from CVS:
+	  2005-10-11  Andy Wingo  <wingo@pobox.com>
+	  * ext/speex/gstspeexenc.c: Signedness cleanups.
+
+2005-10-10 19:57:40 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* PORTED_09:
+	* ext/speex/Makefile.am:
+	* ext/speex/gstspeex.c:
+	* ext/speex/gstspeexenc.c:
+	  Speexenc ported to 0.9.
+	  Original commit message from CVS:
+	  Speexenc ported to 0.9.
+
+2005-10-10 14:16:21 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  sys/oss/: Cleanups, make device configurable in the sink, handle and report errors.
+	  Original commit message from CVS:
+	  * sys/oss/gstosssink.c: (gst_oss_sink_class_init),
+	  (gst_oss_sink_init), (gst_oss_sink_set_property),
+	  (gst_oss_sink_get_property), (gst_oss_sink_open),
+	  (gst_oss_sink_prepare), (gst_oss_sink_reset):
+	  * sys/oss/gstosssink.h:
+	  * sys/oss/gstosssrc.c: (gst_oss_src_class_init),
+	  (gst_oss_src_set_property), (gst_oss_src_init), (gst_oss_src_open),
+	  (gst_oss_src_prepare):
+	  Cleanups, make device configurable in the sink, handle and report
+	  errors.
+
+2005-10-10 12:31:07 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  ext/gconf/: Make sure element is NULL before removing from the bin.
+	  Original commit message from CVS:
+	  * ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_reset):
+	  * ext/gconf/gstgconfvideosink.c: (gst_gconf_video_sink_reset):
+	  Make sure element is NULL before removing from the bin.
+
+2005-10-07 16:28:24 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ChangeLog:
+	* ext/raw1394/gstdv1394src.c:
+	  Don't unref the message.
+	  Original commit message from CVS:
+	  (gst_dv1394src_bus_reset): Don't unref the message.
+
+2005-10-07 16:22:59 +0000  Andy Wingo <wingo@pobox.com>
+
+	* ChangeLog:
+	* ext/raw1394/gstdv1394src.c:
+	  Post a message when the cable is unplugged.
+	  Original commit message from CVS:
+	  (gst_dv1394src_bus_reset): Post a message when the cable is
+	  unplugged.
+	  (gst_dv1394src_create, gst_dv1394src_unlock): Remove some prints.
+
+2005-10-07 15:24:24 +0000  Andy Wingo <wingo@pobox.com>
+
+	  ext/raw1394/gstdv1394src.c: Make interruptible, so it won't block forever in a read().
+	  Original commit message from CVS:
+	  2005-10-07  Andy Wingo  <wingo@pobox.com>
+	  * ext/raw1394/gstdv1394src.c: Make interruptible, so it won't
+	  block forever in a read().
+
+2005-10-07 13:17:53 +0000  Andy Wingo <wingo@pobox.com>
+
+	  ext/raw1394/gstdv1394src.c: Clean up for style before doing some hacking. The only change should be that the state ch...
+	  Original commit message from CVS:
+	  2005-10-07  Andy Wingo  <wingo@pobox.com>
+	  * ext/raw1394/gstdv1394src.c: Clean up for style before doing some
+	  hacking. The only change should be that the state change stuff was
+	  put into basesrc's start() and stop() routines, which coalesces
+	  some steps.
+
+2005-10-07 11:30:41 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Add check for mmap
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Add check for mmap
+	  * gst/debug/Makefile.am:
+	  Only compile efence plugin on systems that have mmap.
+
+2005-10-05 16:36:57 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  add latest files
+	  Original commit message from CVS:
+	  add latest files
+
+2005-10-05 11:38:29 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/debug/: Port progressreport, navseek, navigationtest, testsink and breakmydata.
+	  Original commit message from CVS:
+	  * gst/debug/Makefile.am:
+	  * gst/debug/breakmydata.c:
+	  * gst/debug/gstdebug.c:
+	  * gst/debug/gstnavigationtest.c:
+	  * gst/debug/gstnavseek.c:
+	  * gst/debug/gstnavseek.h:
+	  * gst/debug/progressreport.c:
+	  * gst/debug/testplugin.c:
+	  Port progressreport, navseek, navigationtest, testsink and
+	  breakmydata.
+
+2005-10-05 11:15:23 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/dv/gstdvdemux.c: Fixes for better conversion
+	  Original commit message from CVS:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_src_convert),
+	  (gst_dvdemux_src_query):
+	  Fixes for better conversion
+
+2005-10-04 17:58:40 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/autodetect/: Set state of elements to NULL before removing from bins.
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautoaudiosink.c: (gst_auto_audio_sink_reset),
+	  (gst_auto_audio_sink_find_best), (gst_auto_audio_sink_detect):
+	  * gst/autodetect/gstautovideosink.c: (gst_auto_video_sink_reset),
+	  (gst_auto_video_sink_find_best), (gst_auto_video_sink_detect):
+	  Set state of elements to NULL before removing from bins.
+	  Set state of test element to NULL if we failed to move it to READY
+
+2005-10-04 17:44:43 +0000  Edward Hervey <bilboed@bilboed.com>
+
+	  ext/dv/: Added DEFAULT <==> BYTES, TIME conversions on srcpad,
+	  Original commit message from CVS:
+	  * ext/dv/Makefile.am:
+	  * ext/dv/gstdvdemux.c: (gst_dvdemux_src_query), (gst_dvdemux_src_conver):
+	  Added DEFAULT <==> BYTES, TIME conversions on srcpad,
+	  Corrected the query function for position so it doesn't forget what
+	  format was asked, and calls the conversion functions on the correct pad.
+
+2005-10-03 17:59:18 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* configure.ac:
+	  back to head
+	  Original commit message from CVS:
+	  back to head
+
+=== release 0.9.3 ===
+
+2005-10-03 17:48:57 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* NEWS:
+	* README:
+	* configure.ac:
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	  release time
+	  Original commit message from CVS:
+	  release time
+
+2005-10-02 23:08:35 +0000  Andy Wingo <wingo@pobox.com>
+
+	  ext/flac/gstflacdec.c (gst_flacdec_write): Deal with pad_alloc error returns.
+	  Original commit message from CVS:
+	  2005-10-03  Andy Wingo  <wingo@pobox.com>
+	  * ext/flac/gstflacdec.c (gst_flacdec_write): Deal with pad_alloc
+	  error returns.
+
+2005-10-02 15:33:14 +0000  Andy Wingo <wingo@pobox.com>
+
+	  configure.ac (GST_PLUGIN_LDFLAGS): Change to be like -base.
+	  Original commit message from CVS:
+	  2005-10-02  Andy Wingo  <wingo@pobox.com>
+	  * configure.ac (GST_PLUGIN_LDFLAGS): Change to be like -base.
+	  * ext/flac/gstflacenc.c: Ported to 0.9.
+	  * ext/flac/gstflacdec.c (gst_flacdec_loop): Handle errors better.
+	  * ext/flac/Makefile.am: Add the GST_PLUGINS_BASE cflags and libs,
+	  and link to gsttagedit. Enable flacenc.
+	  * ext/flac/gstflacdec.c: Re-enable tag reading.
+
+2005-09-30 16:36:49 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Various class and caps fixes from Andre Magalhaes (andrunko)
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpamrenc.c: (gst_rtpamrenc_setcaps):
+	  * gst/rtp/gstrtpgsmparse.c:
+	  * gst/rtp/gstrtph263penc.c:
+	  * gst/rtp/gstrtpmp4venc.c: (gst_rtpmp4venc_class_init),
+	  (gst_rtpmp4venc_parse_data), (gst_rtpmp4venc_handle_buffer),
+	  (gst_rtpmp4venc_set_property):
+	  * gst/rtp/gstrtpmpaenc.c: (gst_rtpmpaenc_handle_buffer):
+	  Various class and caps fixes from Andre Magalhaes (andrunko)
+
+2005-09-29 13:08:41 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/level/level-example.c: Update for new bus API.
+	  Original commit message from CVS:
+	  * gst/level/level-example.c: (main):
+	  Update for new bus API.
+
+2005-09-28 13:38:02 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/qtdemux/qtdemux.c: No need to take stream lock here.
+	  Original commit message from CVS:
+	  * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header):
+	  No need to take stream lock here.
+
+2005-09-28 09:45:00 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  configure.ac: Fix unexpanded autoconf macro GST_DOC, which has been renamed to GST_DOCBOOK_CHECK (see common/m4/gst-d...
+	  Original commit message from CVS:
+	  * configure.ac:
+	  Fix unexpanded autoconf macro GST_DOC, which has been renamed
+	  to GST_DOCBOOK_CHECK (see common/m4/gst-doc.m4) (#316202).
+
+2005-09-27 15:12:45 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  sys/oss/gstosssink.c: Fix playback of mono streams (bytes_per_sample should be set from the sample width and the numb...
+	  Original commit message from CVS:
+	  * sys/oss/gstosssink.c: (gst_oss_sink_prepare):
+	  Fix playback of mono streams (bytes_per_sample should be set
+	  from the sample width and the number of channels negotiated,
+	  and not just be set to 4) (#317338)
+
+2005-09-26 14:59:10 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  add auparse to plugins list
+	  Original commit message from CVS:
+	  add auparse to plugins list
+
+2005-09-26 14:42:09 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmpaenc.c: Set buffer duration correctly.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmpaenc.c: (gst_rtpmpaenc_flush),
+	  (gst_rtpmpaenc_handle_buffer):
+	  Set buffer duration correctly.
+
+2005-09-26 13:06:27 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  gst/avi/gstavidemux.c: Don't crash when encountering a stream with an unknown fourcc or codec id. Instead, create a p...
+	  Original commit message from CVS:
+	  * gst/avi/gstavidemux.c: (gst_avi_demux_base_init),
+	  (gst_avi_demux_class_init), (gst_avi_demux_parse_stream),
+	  (gst_avi_demux_change_state):
+	  Don't crash when encountering a stream with an unknown fourcc or
+	  codec id. Instead, create a pad of type video/x-avi-unknown or
+	  audio/x-avi-unknown, which as a side-effect also results in less
+	  confusing error messages in players ('no decoder' vs. 'no streams');
+	  minor fixes to state change function and class_init function.
+
+2005-09-24 13:34:46 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* check/Makefile.am:
+	* tests/check/Makefile.am:
+	  set up plugin paths properly
+	  Original commit message from CVS:
+	  set up plugin paths properly
+
+2005-09-24 13:10:52 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/autodetect/: These are sinks.
+	  Original commit message from CVS:
+	  * gst/autodetect/gstautoaudiosink.c: (gst_auto_audio_sink_init):
+	  * gst/autodetect/gstautovideosink.c: (gst_auto_video_sink_init):
+	  These are sinks.
+
+2005-09-24 12:10:02 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  check/elements/level.c: fix test for new GstClockTime use
+	  Original commit message from CVS:
+	  * check/elements/level.c: (GST_START_TEST):
+	  fix test for new GstClockTime use
+	  * gst/level/gstlevel.c: (gst_level_init), (gst_level_set_caps),
+	  (gst_level_transform_ip):
+	  * gst/level/gstlevel.h:
+	  fix up the decay peak, ensuring the decay peak is never lower
+	  than the peak for that interval
+
+2005-09-23 18:23:04 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* docs/plugins/gst-plugins-good-plugins.args:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* gst/level/gstlevel.c:
+	  updating docs
+	  Original commit message from CVS:
+	  updating docs
+
+2005-09-23 18:15:51 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* Makefile.am:
+	* check/elements/level.c:
+	* common:
+	* gst/level/Makefile.am:
+	* gst/level/gstlevel.c:
+	* gst/level/gstlevel.h:
+	* gst/level/level-example.c:
+	* tests/check/elements/level.c:
+	  convert to using GstClockTime for all time values, finally.
+	  Original commit message from CVS:
+	  convert to using GstClockTime for all time values, finally.
+
+2005-09-23 15:01:00 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/goom/Makefile.am:
+	  fix build of goom
+	  Original commit message from CVS:
+	  fix build of goom
+
+2005-09-23 14:20:01 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* common:
+	* gst/level/gstlevel.c:
+	  we handle more than two channels
+	  Original commit message from CVS:
+	  we handle more than two channels
+
+2005-09-23 04:23:00 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* configure.ac:
+	* ext/cairo/Makefile.am:
+	* ext/dv/Makefile.am:
+	* ext/esd/Makefile.am:
+	* ext/flac/Makefile.am:
+	* ext/gconf/Makefile.am:
+	* ext/gdk_pixbuf/Makefile.am:
+	* ext/jpeg/Makefile.am:
+	* ext/ladspa/Makefile.am:
+	* ext/libcaca/Makefile.am:
+	* ext/libmng/Makefile.am:
+	* ext/libpng/Makefile.am:
+	* ext/mikmod/Makefile.am:
+	* ext/pango/Makefile.am:
+	* ext/raw1394/Makefile.am:
+	* ext/shout2/Makefile.am:
+	* ext/speex/Makefile.am:
+	* gst/alpha/Makefile.am:
+	* gst/auparse/Makefile.am:
+	* gst/auparse/gstauparse.c:
+	* gst/autodetect/Makefile.am:
+	* gst/avi/Makefile.am:
+	* gst/cutter/Makefile.am:
+	* gst/debug/Makefile.am:
+	* gst/effectv/Makefile.am:
+	* gst/flx/Makefile.am:
+	* gst/goom/Makefile.am:
+	* gst/law/Makefile.am:
+	* gst/matroska/Makefile.am:
+	* gst/median/Makefile.am:
+	* gst/monoscope/Makefile.am:
+	* gst/multipart/Makefile.am:
+	* gst/oldcore/Makefile.am:
+	* gst/rtp/Makefile.am:
+	* gst/rtsp/Makefile.am:
+	* gst/smoothwave/Makefile.am:
+	* gst/smpte/Makefile.am:
+	* gst/videobox/Makefile.am:
+	* gst/videofilter/Makefile.am:
+	* gst/videomixer/Makefile.am:
+	* gst/wavenc/Makefile.am:
+	* gst/wavparse/Makefile.am:
+	* sys/oss/Makefile.am:
+	* sys/osxaudio/Makefile.am:
+	  fix build and use of GST_LIBS
+	  Original commit message from CVS:
+	  fix build and use of GST_LIBS
+
+2005-09-22 22:38:48 +0000  Edgard Lima <edgard.lima@indt.org.br>
+
+	* ChangeLog:
+	* PORTED_09:
+	* configure.ac:
+	* gst/auparse/gstauparse.c:
+	* gst/auparse/gstauparse.h:
+	  Auparse ported to 0.9. Tested with filesrc ! auparse ! osssink and alsasink
+	  Original commit message from CVS:
+	  Auparse ported to 0.9. Tested with filesrc ! auparse ! osssink and alsasink
+
+2005-09-22 14:13:36 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Use is_filled to both check MTU and max-ptime of base class.
+	  Original commit message from CVS:
+	  * gst/rtp/TODO:
+	  * gst/rtp/gstrtpdec.c: (gst_rtpdec_getcaps):
+	  * gst/rtp/gstrtpmp4venc.c: (gst_rtpmp4venc_class_init),
+	  (gst_rtpmp4venc_parse_data), (gst_rtpmp4venc_handle_buffer),
+	  (gst_rtpmp4venc_set_property):
+	  * gst/rtp/gstrtpmp4venc.h:
+	  * gst/rtp/gstrtpmpaenc.c: (gst_rtpmpaenc_handle_buffer):
+	  * gst/rtp/gstrtpmpaenc.h:
+	  Use is_filled to both check MTU and max-ptime of base class.
+
+2005-09-22 11:28:23 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpmp4venc.c: Don't fragment packets with multiple frames.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpmp4venc.c: (gst_rtpmp4venc_class_init),
+	  (gst_rtpmp4venc_parse_data), (gst_rtpmp4venc_handle_buffer),
+	  (gst_rtpmp4venc_set_property):
+	  Don't fragment packets with multiple frames.
+
+2005-09-22 10:39:11 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Remove g_print.
+	  Original commit message from CVS:
+	  * gst/rtp/TODO:
+	  * gst/rtp/gstrtpmp4vdec.c: (gst_rtpmp4vdec_setcaps):
+	  * gst/rtp/gstrtpmp4venc.c: (gst_rtpmp4venc_class_init),
+	  (gst_rtpmp4venc_init), (gst_rtpmp4venc_parse_data),
+	  (gst_rtpmp4venc_handle_buffer), (gst_rtpmp4venc_set_property),
+	  (gst_rtpmp4venc_get_property):
+	  * gst/rtp/gstrtpmp4venc.h:
+	  Remove g_print.
+	  Update TODO
+	  Make payload encoder a bit smarter and more correct with
+	  timestamps.
+	  Added option in payloader to include config string in-band.
+
+2005-09-21 19:41:45 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: Strip spaces for key/value pairs.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_parse_rtpmap),
+	  (gst_rtspsrc_media_to_caps), (gst_rtspsrc_stream_setup_rtp),
+	  (gst_rtspsrc_send):
+	  Strip spaces for key/value pairs.
+
+2005-09-21 17:53:26 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/gstrtspsrc.c: More SDP parsing and caps setting.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_parse_rtpmap),
+	  (gst_rtspsrc_media_to_caps), (gst_rtspsrc_stream_setup_rtp),
+	  (gst_rtspsrc_stream_configure_transport), (gst_rtspsrc_send),
+	  (gst_rtspsrc_change_state):
+	  More SDP parsing and caps setting.
+	  Do NO_PREROLL differently.
+	  add pads only after negotiated.
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init),
+	  (gst_udpsrc_getcaps):
+	  Implement the getcaps function.
+
+2005-09-21 17:50:29 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtpamrdec.c: Handle multiple AMr packets per payload. Handle CRC and parse ILL/ILP.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtpamrdec.c: (gst_rtpamrdec_sink_setcaps),
+	  (gst_rtpamrdec_chain):
+	  Handle multiple AMr packets per payload. Handle CRC and
+	  parse ILL/ILP.
+	  * gst/rtp/gstrtpamrenc.c: (gst_rtpamrenc_setcaps):
+	  Make caps params strings for easy SDP mapping.
+	  * gst/rtp/gstrtpdec.c: (gst_rtpdec_init), (gst_rtpdec_getcaps):
+	  Handle capsnego better.
+	  * gst/rtp/gstrtpmp4vdec.c: (gst_rtpmp4vdec_setcaps):
+	  * gst/rtp/gstrtpmp4venc.c: (gst_rtpmp4venc_new_caps):
+	  Generate and parse config string in the caps.
+
+2005-09-21 12:19:24 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/README: Update README
+	  Original commit message from CVS:
+	  * gst/rtp/README:
+	  Update README
+	  * gst/rtp/gstrtpamrdec.c: (gst_rtpamrdec_sink_setcaps):
+	  Make extra params as strings.
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_set_state),
+	  (gst_rtspsrc_parse_rtpmap), (gst_rtspsrc_media_to_caps),
+	  (gst_rtspsrc_stream_setup_rtp), (gst_rtspsrc_send):
+	  Make state change return NO_PREROLL as this is a live
+	  source.
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_set_property):
+	  Don't unref old caps when NULL.
+
+2005-09-20 17:35:11 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtsp/: Add URI handler.
+	  Original commit message from CVS:
+	  * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_get_type),
+	  (gst_rtspsrc_parse_rtpmap), (gst_rtspsrc_media_to_caps),
+	  (gst_rtspsrc_stream_setup_rtp), (gst_rtspsrc_send),
+	  (gst_rtspsrc_open), (gst_rtspsrc_uri_get_type),
+	  (gst_rtspsrc_uri_get_protocols), (gst_rtspsrc_uri_get_uri),
+	  (gst_rtspsrc_uri_set_uri), (gst_rtspsrc_uri_handler_init):
+	  * gst/rtsp/sdpmessage.c: (sdp_media_get_format):
+	  * gst/rtsp/sdpmessage.h:
+	  Add URI handler.
+	  Parse SDP and create caps.
+
+2005-09-20 17:19:43 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	  more spec file fixoring
+	  Original commit message from CVS:
+	  more spec file fixoring
+
+2005-09-20 17:04:33 +0000  Christian Schaller <uraeus@gnome.org>
+
+	* gst-plugins-good.spec.in:
+	* gst-plugins.spec.in:
+	  fix spec files
+	  Original commit message from CVS:
+	  fix spec files
+
+2005-09-20 10:51:51 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/rtp/README:
+	* gst/rtp/gstrtpamrdec.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrenc.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpgsmenc.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtph263pdec.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263penc.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtpmp4vdec.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmp4venc.c:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmpadec.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpaenc.c:
+	* gst/rtp/gstrtpmpapay.c:
+	  don't use underscores
+	  Original commit message from CVS:
+	  don't use underscores
+
+2005-09-20 07:30:31 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  gst/alpha/gstalpha.c: fix element description
+	  Original commit message from CVS:
+	  * gst/alpha/gstalpha.c:
+	  fix element description
+
+2005-09-19 17:57:06 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/plugins/gst-plugins-good-plugins.prerequisites:
+	  prereqs as well
+	  Original commit message from CVS:
+	  prereqs as well
+
+2005-09-19 17:53:42 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/plugins/.gitignore:
+	* 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.signals:
+	  commit result of scanobj step
+	  Original commit message from CVS:
+	  commit result of scanobj step
+
+2005-09-19 17:03:55 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/gstrtph263pdec.c: Don't check payload for now.
+	  Original commit message from CVS:
+	  * gst/rtp/gstrtph263pdec.c: (gst_rtph263pdec_chain):
+	  Don't check payload for now.
+
+2005-09-19 16:43:56 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* Makefile.am:
+	  add check-valgrind target
+	  Original commit message from CVS:
+	  add check-valgrind target
+
+2005-09-19 16:26:30 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/wavparse/gstwavparse.*: Fix wavparse some more.
+	  Original commit message from CVS:
+	  * gst/wavparse/gstwavparse.c: (gst_wavparse_reset),
+	  (gst_wavparse_init), (gst_wavparse_parse_file_header),
+	  (gst_wavparse_stream_init), (gst_wavparse_handle_seek),
+	  (gst_wavparse_stream_headers), (gst_wavparse_stream_data),
+	  (gst_wavparse_loop), (gst_wavparse_pad_convert),
+	  (gst_wavparse_pad_query), (gst_wavparse_srcpad_event),
+	  (gst_wavparse_change_state):
+	  * gst/wavparse/gstwavparse.h:
+	  Fix wavparse some more.
+
+2005-09-19 11:48:13 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  check/elements/level.c: Fix for bus API change.
+	  Original commit message from CVS:
+	  * check/elements/level.c: (GST_START_TEST):
+	  Fix for bus API change.
+
+2005-09-19 11:38:10 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/level/level-example.c: Fix for new bus API.
+	  Original commit message from CVS:
+	  * gst/level/level-example.c: (main):
+	  Fix for new bus API.
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_set_property):
+	  Set caps on pads.
+
+2005-09-19 11:06:05 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/debug/Makefile.am:
+	  disable flags for unbuilt plugins
+	  Original commit message from CVS:
+	  disable flags for unbuilt plugins
+
+2005-09-19 08:21:29 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* common:
+	* docs/plugins/scanobj-build.stamp:
+	  normal builds shouldn't scan gobjects
+	  Original commit message from CVS:
+	  normal builds shouldn't scan gobjects
+
+2005-09-16 00:38:50 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* check/Makefile.am:
+	* common:
+	* tests/check/Makefile.am:
+	  remove gst-register
+	  Original commit message from CVS:
+	  remove gst-register
+
+2005-09-15 13:57:56 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	* ChangeLog:
+	* common:
+	* gst/rtp/Makefile.am:
+	* gst/rtp/README:
+	* gst/rtp/gstrtp.c:
+	* gst/rtp/gstrtpamrdec.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrenc.c:
+	* gst/rtp/gstrtpamrenc.h:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpamrpay.h:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmdepay.h:
+	* gst/rtp/gstrtpgsmenc.c:
+	* gst/rtp/gstrtpgsmenc.h:
+	* gst/rtp/gstrtpgsmparse.c:
+	* gst/rtp/gstrtpgsmparse.h:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtpgsmpay.h:
+	* gst/rtp/gstrtph263pdec.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263penc.c:
+	* gst/rtp/gstrtph263penc.h:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtph263ppay.h:
+	* gst/rtp/gstrtpmp4vdec.c:
+	* gst/rtp/gstrtpmp4vdepay.c:
+	* gst/rtp/gstrtpmp4venc.c:
+	* gst/rtp/gstrtpmp4venc.h:
+	* gst/rtp/gstrtpmp4vpay.c:
+	* gst/rtp/gstrtpmp4vpay.h:
+	* gst/rtp/gstrtpmpadec.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpaenc.c:
+	* gst/rtp/gstrtpmpaenc.h:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtp/gstrtpmpapay.h:
+	  Updates to payloader/depayloaders, make payloaders use the base classes.
+	  Original commit message from CVS:
+	  Updates to payloader/depayloaders, make payloaders use
+	  the base classes.
+	  Updated README with suggested RTP caps and how to convert
+	  to/from SDP.
+	  Added config descriptor in mp4v payloader.
+
+2005-09-15 10:47:58 +0000  Andy Wingo <wingo@pobox.com>
+
+	  gst/autodetect/gstautoaudiosink.c (gst_auto_audio_sink_find_best): gst/autodetect/gstautovideosink.c
+	  Original commit message from CVS:
+	  2005-09-15  Andy Wingo  <wingo@pobox.com>
+	  * gst/autodetect/gstautoaudiosink.c (gst_auto_audio_sink_find_best):
+	  * gst/autodetect/gstautovideosink.c
+	  (gst_auto_video_sink_find_best): Update for new registry API.
+
+2005-09-14 20:51:47 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  common/: a simple py script to generate valid xml from a C example probably also need to strip an MIT license when we...
+	  Original commit message from CVS:
+	  * common/c-to-xml.py:
+	  * common/gtk-doc-plugins.mak:
+	  a simple py script to generate valid xml from a C example
+	  probably also need to strip an MIT license when we decide
+	  * docs/plugins/Makefile.am:
+	  * gst/level/Makefile.am:
+	  * gst/level/gstlevel.c: (gst_level_init):
+	  * gst/level/level-example.c: (message_handler), (main):
+	  add an example to level that will show up in the docs
+	  * gst/rtp/TODO:
+	  add a note for the future
+
+2005-09-14 11:44:11 +0000  Michael Smith <msmith@xiph.org>
+
+	  gst/wavenc/gstwavenc.c: Actually define the debug object being used in wavenc. Fixes #316205
+	  Original commit message from CVS:
+	  * gst/wavenc/gstwavenc.c: (gst_wavenc_class_init):
+	  Actually define the debug object being used in wavenc. Fixes #316205
+
+2005-09-14 11:23:44 +0000  Michael Smith <msmith@xiph.org>
+
+	* ChangeLog:
+	* gst/smpte/Makefile.am:
+	  Link smpte plugin against GST_BASE_LIBS, to get libgstbase; needed to build on win32 as this plugin uses collectpads ...
+	  Original commit message from CVS:
+	  Link smpte plugin against GST_BASE_LIBS, to get libgstbase; needed to
+	  build on win32 as this plugin uses collectpads (bug 316204)
+
+2005-09-12 16:37:05 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ChangeLog:
+	  Fix up bogus ChangeLog entry
+	  Original commit message from CVS:
+	  Fix up bogus ChangeLog entry
+
+2005-09-12 16:14:48 +0000  Andy Wingo <wingo@pobox.com>
+
+	  autogen.sh (package): Now type 'make' to build gst-plugins-good.
+	  Original commit message from CVS:
+	  2005-09-12  Andy Wingo  <wingo@pobox.com>
+	  * autogen.sh (package): Now type 'make' to build gst-plugins-good.
+
+2005-09-11 17:52:09 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* common:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-fdsrc.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	  add source module to docs; reinspect
+	  Original commit message from CVS:
+	  add source module to docs; reinspect
+
+2005-09-09 17:56:43 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Move fdsrc back into gstreamer core elements.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/fdsrc/Makefile.am:
+	  * gst/fdsrc/gstfdsrc.c:
+	  * gst/fdsrc/gstfdsrc.h:
+	  Move fdsrc back into gstreamer core elements.
+	  * gst/level/gstlevel.c: (gst_level_class_init),
+	  (gst_level_transform_ip):
+	  * gst/videobox/gstvideobox.c: (gst_video_box_set_property):
+	  Basetransform changes.
+
+2005-09-09 16:11:48 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* ext/jpeg/gstsmokeenc.c:
+	* ext/jpeg/smokecodec.c:
+	  fix compiler warnings
+	  Original commit message from CVS:
+	  fix compiler warnings
+
+2005-09-09 11:09:49 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  gst-plugins-good.spec.in: spec file fixes
+	  Original commit message from CVS:
+	  * gst-plugins-good.spec.in:
+	  spec file fixes
+	  * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_class_init),
+	  (gst_multiudpsink_render), (gst_multiudpsink_add),
+	  (gst_multiudpsink_clear):
+	  it actually helps to actually stream if we hook up the
+	  add signal to an actual implementation
+	  * gst/udp/gstudpsrc.c: (gst_udpsrc_start):
+	  some debugging
+
+2005-09-08 16:58:40 +0000  Flavio Oliveira <flavio.oliveira@indt.org.br>
+
+	* ext/jpeg/Makefile.am:
+	* ext/jpeg/gstjpeg.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/jpeg/gstsmokeenc.c:
+	  jpgenc ported to GSTreamer 0.9
+	  Original commit message from CVS:
+	  jpgenc ported to GSTreamer 0.9
+
+2005-09-08 16:26:17 +0000  Flavio Oliveira <flavio.oliveira@indt.org.br>
+
+	* ChangeLog:
+	  jpegenc ported to GStreamer 0.9
+	  Original commit message from CVS:
+	  jpegenc ported to GStreamer 0.9
+
+2005-09-07 13:49:37 +0000  Stefan Kost <ensonic@users.sourceforge.net>
+
+	  ext/: gsttaginterface.h -> gsttagsetter.h
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c:
+	  * ext/flac/gstflacenc.c:
+	  * ext/flac/gstflactag.c:
+	  * ext/speex/gstspeexenc.c:
+	  gsttaginterface.h -> gsttagsetter.h
+
+2005-09-06 23:30:03 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	  Port to 0.9 and re-enable efence plugin.
+	  Original commit message from CVS:
+	  * configure.ac:
+	  * gst/debug/Makefile.am:
+	  * gst/debug/efence.c: (gst_efence_class_init), (gst_efence_init),
+	  (gst_efence_chain), (gst_efence_buffer_alloc), (plugin_init),
+	  (gst_fenced_buffer_finalize), (gst_fenced_buffer_copy),
+	  (gst_fenced_buffer_alloc), (gst_fenced_buffer_class_init),
+	  (gst_fenced_buffer_init), (gst_fenced_buffer_get_type):
+	  Port to 0.9 and re-enable efence plugin.
+
+2005-09-06 21:31:25 +0000  Tim-Philipp Müller <tim@centricular.net>
+
+	  ext/flac/gstflacdec.*: Add support for flac files with 24/32 bits per sample; and misc. minor clean-ups. Seeking is s...
+	  Original commit message from CVS:
+	  * ext/flac/gstflacdec.c: (flac_caps_factory), (raw_caps_factory),
+	  (gst_flacdec_write), (gst_flacdec_convert_src):
+	  * ext/flac/gstflacdec.h:
+	  Add support for flac files with 24/32 bits per sample; and misc.
+	  minor clean-ups. Seeking is still partly broken (for me at least).
+
+2005-09-06 15:50:58 +0000  Wim Taymans <wim.taymans@gmail.com>
+
+	  gst/rtp/: Added mpeg4 video payload encoder/decoder.
+	  Original commit message from CVS:
+	  * gst/rtp/Makefile.am:
+	  * gst/rtp/gstrtp.c: (plugin_init):
+	  * gst/rtp/gstrtpmp4vdec.c: (gst_rtpmp4vdec_get_type),
+	  (gst_rtpmp4vdec_base_init), (gst_rtpmp4vdec_class_init),
+	  (gst_rtpmp4vdec_init), (gst_rtpmp4vdec_setcaps),
+	  (gst_rtpmp4vdec_chain), (gst_rtpmp4vdec_set_property),
+	  (gst_rtpmp4vdec_get_property), (gst_rtpmp4vdec_change_state),
+	  (gst_rtpmp4vdec_plugin_init):
+	  * gst/rtp/gstrtpmp4vdec.h:
+	  * gst/rtp/gstrtpmp4venc.c: (gst_rtpmp4venc_get_type),
+	  (gst_rtpmp4venc_base_init), (gst_rtpmp4venc_class_init),
+	  (gst_rtpmp4venc_init), (gst_rtpmp4venc_setcaps),
+	  (gst_rtpmp4venc_flush), (gst_rtpmp4venc_chain),
+	  (gst_rtpmp4venc_set_property), (gst_rtpmp4venc_get_property),
+	  (gst_rtpmp4venc_change_state), (gst_rtpmp4venc_plugin_init):
+	  * gst/rtp/gstrtpmp4venc.h:
+	  * gst/rtp/gstrtpmpadec.c: (gst_rtpmpadec_chain):
+	  * gst/rtp/gstrtpmpaenc.c: (gst_rtpmpaenc_flush):
+	  Added mpeg4 video payload encoder/decoder.
+	  Added some docs in mpa payloader.
+
+2005-09-06 14:06:47 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* configure.ac:
+	  back to HEAD
+	  Original commit message from CVS:
+	  back to HEAD
+
+=== release 0.9.1 ===
+
+2005-09-06 14:05:33 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* NEWS:
+	* README:
+	* RELEASE:
+	* autogen.sh:
+	* common:
+	* configure.ac:
+	  releasing 0.9.2
+	  Original commit message from CVS:
+	  releasing 0.9.2
+
+2005-09-05 17:20:28 +0000  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* gst/videocrop/gstvideocrop.c:
+	* sys/v4l2/gstv4l2element.c:
+	* sys/v4l2/gstv4l2src.c:
+	  Fix up all the state change functions.
+	  Original commit message from CVS:
+	  Fix up all the state change functions.
+
+2005-09-05 16:28:16 +0000  Andy Wingo <wingo@pobox.com>
+
+	  ext/dv/gstdvdemux.c (gst_dvdemux_chain): Move the pad adding here from the state change handler, so we fire signals w...
+	  Original commit message from CVS:
+	  2005-09-05  Andy Wingo  <wingo@pobox.com>
+	  * ext/dv/gstdvdemux.c (gst_dvdemux_chain): Move the pad adding
+	  here from the state change handler, so we fire signals without
+	  holding the state lock.
+
+2005-09-05 15:10:18 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/qtdemux/qtdemux.c:
+	  cleaning up bad
+	  Original commit message from CVS:
+	  cleaning up bad
+
+2005-09-05 13:18:42 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/.gitignore:
+	* docs/plugins/.gitignore:
+	  maintenance commits
+	  Original commit message from CVS:
+	  maintenance commits
+
+2005-09-04 15:09:33 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* configure.ac:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/inspect-build.stamp:
+	* docs/plugins/inspect.stamp:
+	* docs/plugins/inspect/plugin-1394.xml:
+	* docs/plugins/inspect/plugin-aasink.xml:
+	* docs/plugins/inspect/plugin-alaw.xml:
+	* docs/plugins/inspect/plugin-alpha.xml:
+	* docs/plugins/inspect/plugin-autodetect.xml:
+	* docs/plugins/inspect/plugin-avi.xml:
+	* docs/plugins/inspect/plugin-cacasink.xml:
+	* docs/plugins/inspect/plugin-dv.xml:
+	* docs/plugins/inspect/plugin-effectv.xml:
+	* docs/plugins/inspect/plugin-esdsink.xml:
+	* docs/plugins/inspect/plugin-fdsrc.xml:
+	* docs/plugins/inspect/plugin-flac.xml:
+	* docs/plugins/inspect/plugin-gconfelements.xml:
+	* docs/plugins/inspect/plugin-goom.xml:
+	* docs/plugins/inspect/plugin-jpeg.xml:
+	* docs/plugins/inspect/plugin-level.xml:
+	* docs/plugins/inspect/plugin-mulaw.xml:
+	* docs/plugins/inspect/plugin-ossaudio.xml:
+	* docs/plugins/inspect/plugin-png.xml:
+	* docs/plugins/inspect/plugin-rtp.xml:
+	* docs/plugins/inspect/plugin-rtsp.xml:
+	* docs/plugins/inspect/plugin-shout2send.xml:
+	* docs/plugins/inspect/plugin-smpte.xml:
+	* docs/plugins/inspect/plugin-speex.xml:
+	* docs/plugins/inspect/plugin-udp.xml:
+	* docs/plugins/inspect/plugin-videobox.xml:
+	* docs/plugins/inspect/plugin-videoflip.xml:
+	* docs/plugins/inspect/plugin-wavparse.xml:
+	  distcheck fixes
+	  Original commit message from CVS:
+	  distcheck fixes
+
+2005-09-04 11:50:47 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* Makefile.am:
+	* autogen.sh:
+	* common:
+	* docs/plugins/Makefile.am:
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	  fix distcheck
+	  Original commit message from CVS:
+	  fix distcheck
+
+2005-09-02 15:56:52 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst-plugins-good.spec.in:
+	  various spec fixes
+	  Original commit message from CVS:
+	  various spec fixes
+
+2005-09-02 15:44:50 +0000  Andy Wingo <wingo@pobox.com>
+
+	* check/elements/level.c:
+	* examples/gstplay/player.c:
+	* examples/stats/mp2ogg.c:
+	* ext/aalib/gstaasink.c:
+	* ext/cairo/gsttextoverlay.c:
+	* ext/dv/gstdvdec.c:
+	* ext/dv/gstdvdemux.c:
+	* ext/esd/esdmon.c:
+	* ext/flac/gstflacdec.c:
+	* ext/flac/gstflacenc.c:
+	* ext/flac/gstflactag.c:
+	* ext/gconf/gstgconfaudiosink.c:
+	* ext/gconf/gstgconfvideosink.c:
+	* ext/gdk_pixbuf/gstgdkanimation.c:
+	* ext/jpeg/gstjpegdec.c:
+	* ext/jpeg/gstjpegenc.c:
+	* ext/ladspa/gstsignalprocessor.c:
+	* ext/libcaca/gstcacasink.c:
+	* ext/libmng/gstmngdec.c:
+	* ext/mikmod/gstmikmod.c:
+	* ext/pango/gsttextoverlay.c:
+	* ext/raw1394/gstdv1394src.c:
+	* ext/shout2/gstshout2.c:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	* gst/alpha/gstalpha.c:
+	* gst/auparse/gstauparse.c:
+	* gst/autodetect/gstautoaudiosink.c:
+	* gst/autodetect/gstautovideosink.c:
+	* gst/avi/gstavidemux.c:
+	* gst/avi/gstavimux.c:
+	* gst/debug/breakmydata.c:
+	* gst/debug/gstnavigationtest.c:
+	* gst/effectv/gstquark.c:
+	* gst/fdsrc/gstfdsrc.c:
+	* gst/flx/gstflxdec.c:
+	* gst/goom/gstgoom.c:
+	* gst/matroska/ebml-read.c:
+	* gst/matroska/ebml-write.c:
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-mux.c:
+	* gst/multipart/multipartdemux.c:
+	* gst/multipart/multipartmux.c:
+	* gst/oldcore/gstmd5sink.c:
+	* gst/oldcore/gstmultifilesrc.c:
+	* gst/oldcore/gstpipefilter.c:
+	* gst/rtp/gstrtpL16depay.c:
+	* gst/rtp/gstrtpL16enc.c:
+	* gst/rtp/gstrtpL16parse.c:
+	* gst/rtp/gstrtpL16pay.c:
+	* gst/rtp/gstrtpamrdec.c:
+	* gst/rtp/gstrtpamrdepay.c:
+	* gst/rtp/gstrtpamrenc.c:
+	* gst/rtp/gstrtpamrpay.c:
+	* gst/rtp/gstrtpdec.c:
+	* gst/rtp/gstrtpdepay.c:
+	* gst/rtp/gstrtpgsmdepay.c:
+	* gst/rtp/gstrtpgsmenc.c:
+	* gst/rtp/gstrtpgsmparse.c:
+	* gst/rtp/gstrtpgsmpay.c:
+	* gst/rtp/gstrtph263pdec.c:
+	* gst/rtp/gstrtph263pdepay.c:
+	* gst/rtp/gstrtph263penc.c:
+	* gst/rtp/gstrtph263ppay.c:
+	* gst/rtp/gstrtpmpadec.c:
+	* gst/rtp/gstrtpmpadepay.c:
+	* gst/rtp/gstrtpmpaenc.c:
+	* gst/rtp/gstrtpmpapay.c:
+	* gst/rtsp/gstrtspsrc.c:
+	* gst/smoothwave/gstsmoothwave.c:
+	* gst/udp/gstdynudpsink.c:
+	* gst/udp/gstmultiudpsink.c:
+	* gst/videomixer/videomixer.c:
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavparse/gstwavparse.c:
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	* po/vi.po:
+	* sys/oss/gstossmixerelement.c:
+	* sys/osxaudio/gstosxaudioelement.c:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* tests/check/elements/level.c:
+	  All plugins updated for element state changes.
+	  Original commit message from CVS:
+	  2005-09-02  Andy Wingo  <wingo@pobox.com>
+	  * All plugins updated for element state changes.
+
+2005-09-01 21:24:57 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/aalib/Makefile.am:
+	  fix build after cleaning up my vomit
+	  Original commit message from CVS:
+	  fix build after cleaning up my vomit
+
+2005-09-01 21:23:09 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ext/aalib/Makefile.am:
+	  fix build after cleaning up my vomit
+	  Original commit message from CVS:
+	  fix build after cleaning up my vomit
+
+2005-09-01 21:20:45 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/smpte/Makefile.am:
+	  fix build after cleaning up my vomit
+	  Original commit message from CVS:
+	  fix build after cleaning up my vomit
+
+2005-09-01 21:15:30 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/smpte/Makefile.am:
+	  fix build after cleaning up my vomit
+	  Original commit message from CVS:
+	  fix build after cleaning up my vomit
+
+2005-09-01 20:23:22 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* Makefile.am:
+	* check/.gitignore:
+	* check/Makefile.am:
+	* check/elements/.gitignore:
+	* check/elements/level.c:
+	* common:
+	* configure.ac:
+	* gst/level/gstlevel.c:
+	* gst/level/gstlevel.h:
+	* tests/check/.gitignore:
+	* tests/check/Makefile.am:
+	* tests/check/elements/.gitignore:
+	* tests/check/elements/level.c:
+	  Andrewio Patrickoforus Wingonymus - 5 additional tests for your sins
+	  Original commit message from CVS:
+	  Andrewio Patrickoforus Wingonymus - 5 additional tests for your sins
+	  Add a regression test for level and fix a casting bug that made the additional
+	  channels turn out wrong
+
+2005-09-01 17:55:14 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  add docs to build
+	  Original commit message from CVS:
+	  * Makefile.am:
+	  * configure.ac:
+	  add docs to build
+	  * common/plugins.xsl:
+	  wrap Description into a refsect2
+	  * docs/Makefile.am:
+	  * docs/plugins/Makefile.am:
+	  * docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	  * docs/plugins/gst-plugins-good-plugins-sections.txt:
+	  * gst/goom/Makefile.am:
+	  * gst/goom/gstgoom.c: (gst_goom_get_type), (gst_goom_base_init),
+	  (gst_goom_class_init), (gst_goom_init), (gst_goom_dispose),
+	  (gst_goom_sink_setcaps), (gst_goom_src_setcaps),
+	  (gst_goom_src_negotiate), (gst_goom_event), (gst_goom_chain),
+	  (gst_goom_change_state):
+	  * gst/goom/gstgoom.h:
+	  GstGOOM -> GstGoom
+	  add an example launch line
+	  * gst/level/gstlevel.h:
+	  * gst/monoscope/gstmonoscope.c:
+	  cleanups
+
+2005-08-31 16:28:05 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* gst/dvdlpcmdec/.gitignore:
+	* gst/dvdlpcmdec/Makefile.am:
+	* gst/dvdlpcmdec/gstdvdlpcmdec.c:
+	* gst/dvdlpcmdec/gstdvdlpcmdec.h:
+	  remove dvdlpcmdec, it's dvd stuff
+	  Original commit message from CVS:
+	  remove dvdlpcmdec, it's dvd stuff
+
+2005-08-30 19:41:12 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* Makefile.am:
+	* gst-libs/gst/gettext.h:
+	* gst-libs/gst/gst-i18n-plugin.h:
+	  add some i18n headers
+	  Original commit message from CVS:
+	  add some i18n headers
+
+2005-08-30 19:24:37 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/plugins/.gitignore:
+	  ignore more
+	  Original commit message from CVS:
+	  ignore more
+
+2005-08-30 19:24:03 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/Makefile.am:
+	  Makefile.am
+	  Original commit message from CVS:
+	  Makefile.am
+
+2005-08-30 19:20:02 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* docs/upload.mak:
+	* docs/version.entities.in:
+	  commit new stuff
+	  Original commit message from CVS:
+	  commit new stuff
+
+2005-08-30 19:01:18 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* ChangeLog:
+	* common:
+	* configure.ac:
+	* docs/plugins/Makefile.am:
+	* docs/plugins/gst-plugins-good-plugins-docs.sgml:
+	* docs/plugins/gst-plugins-good-plugins-sections.txt:
+	* docs/plugins/gst-plugins-good-plugins.types:
+	  document elements and plugins.  Shazam !
+	  Original commit message from CVS:
+	  document elements and plugins.  Shazam !
+
+2005-08-30 17:37:00 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	* .gitignore:
+	* COPYING:
+	* RELEASE:
+	* gst-plugins-good.spec.in:
+	  add some files
+	  Original commit message from CVS:
+	  add some files
+
+2001-12-17 18:37:01 +0000  Thomas Vander Stichele <thomas@apestaart.org>
+
+	  building up speed
+	  Original commit message from CVS:
+	  building up speed
+
diff --git a/MAINTAINERS b/MAINTAINERS
new file mode 100644
index 0000000..72aac8e
--- /dev/null
+++ b/MAINTAINERS
@@ -0,0 +1,12 @@
+GStreamer is currently maintained by the consensus of a number
+of people, including, but not limited to:
+
+ Jan Schmidt <thaytan@noraisin.net>
+ Wim Taymans <wim.taymans@gmail.com>
+ David Schleef <ds@schleef.org>
+ Tim-Philipp Müller <tim centricular net>
+ Sebastian Dröge <slomo@coaxion.net>
+
+Maintainer-related issues should be addressed to:
+
+  gstreamer-devel@lists.freedesktop.org
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..12cb59a
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,82 @@
+DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc
+
+ALWAYS_SUBDIRS =		\
+	gst sys ext 		\
+	tests			\
+	docs			\
+	po			\
+	common			\
+	m4			\
+	pkgconfig
+
+SUBDIRS = $(ALWAYS_SUBDIRS)
+
+DIST_SUBDIRS = $(ALWAYS_SUBDIRS)
+
+EXTRA_DIST = \
+	depcomp \
+	AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \
+	ChangeLog gst-plugins-good.doap autogen.sh \
+	$(shell find "$(top_srcdir)" -type f -name meson.build ! -path "$(top_srcdir)/$(PACKAGE_TARNAME)-*" ) \
+	meson_options.txt
+
+DISTCLEANFILES = _stdint.h
+
+noinst_HEADERS = \
+	gst-libs/gst/gettext.h \
+	gst-libs/gst/gst-i18n-plugin.h \
+	gst-libs/gst/glib-compat-private.h
+
+ACLOCAL_AMFLAGS = -I m4 -I common/m4
+
+include $(top_srcdir)/common/release.mak
+include $(top_srcdir)/common/po.mak
+
+check-valgrind:
+	$(MAKE) -C tests/check check-valgrind
+
+if HAVE_GST_CHECK
+check-torture:
+	$(MAKE) -C tests/check torture
+build-checks:
+	$(MAKE) -C tests/check build-checks
+else
+check-torture:
+	true
+build-checks:
+	true
+endif
+
+include $(top_srcdir)/common/coverage/lcov.mak
+
+# cruft: plugins that have been merged or moved or renamed
+
+CRUFT_FILES = \
+	$(top_builddir)/gst-plugins-good.spec \
+	$(top_builddir)/win32/common/config.h-new \
+	$(top_builddir)/common/shave \
+	$(top_builddir)/common/shave-libtool \
+	$(top_builddir)/docs/plugins/xml/plugin-shout2send.xml \
+	$(top_builddir)/ext/pulse/.libs/libgstpulse.so \
+	$(top_builddir)/ext/soup/.libs/libgstsouphttpsrc.so \
+	$(top_builddir)/gst/median/.libs/*.{so,dll,DLL,dylib} \
+	$(top_builddir)/gst/qtdemux/.libs/*.{so,dll,DLL,dylib} \
+	$(top_builddir)/gst/quicktime/.libs/*.{so,dll,DLL,dylib} \
+	$(top_builddir)/gst/videofilter/.libs/*videoflip.{so,dll,DLL,dylib} \
+	$(top_builddir)/gst/videofilter/.libs/*videobalance.{so,dll,DLL,dylib} \
+	$(top_builddir)/gst/videofilter/.libs/*gamma.{so,dll,DLL,dylib} \
+	$(top_builddir)/sys/directsound/.libs/libgstdirectsoundsink.{dll,DLL} \
+	$(top_builddir)/sys/oss4/.libs/libgstoss4audio.so \
+	$(top_builddir)/sys/waveform/.libs/libgstwaveformsink.{dll,DLL}
+
+CRUFT_DIRS = \
+	$(top_srcdir)/docs/plugins/tmpl \
+	$(top_srcdir)/gst/median \
+	$(top_srcdir)/gst/qtdemux \
+	$(top_srcdir)/gst/quicktime \
+	$(top_srcdir)/ext/annodex \
+	$(top_srcdir)/tests/examples/pulse
+
+include $(top_srcdir)/common/cruft.mak
+
+all-local: check-cruft
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..74fb1ea
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,734 @@
+# GStreamer 1.12 Release Notes
+
+GStreamer 1.12.0 was originally released on 4th May 2017.
+
+The GStreamer team is proud to announce a new major feature release in the
+stable 1.x API series of your favourite cross-platform multimedia framework!
+
+As always, this release is again packed with new features, bug fixes and other
+improvements.
+
+See [https://gstreamer.freedesktop.org/releases/1.12/][latest] for the latest
+version of this document.
+
+*Last updated: Thursday 4 May 2017, 11:00 UTC [(log)][gitlog]*
+
+[latest]: https://gstreamer.freedesktop.org/releases/1.12/
+[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.12/release-notes-1.12.md
+
+## Introduction
+
+The GStreamer team is proud to announce a new major feature release in the
+stable 1.x API series of your favourite cross-platform multimedia framework!
+
+As always, this release is again packed with new features, bug fixes and other
+improvements.
+
+## Highlights
+
+- new `msdk` plugin for Intel's Media SDK for hardware-accelerated video
+  encoding and decoding on Intel graphics hardware on Windows or Linux.
+
+- `x264enc` can now use multiple x264 library versions compiled for different
+  bit depths at runtime, to transparently provide support for multiple bit
+  depths.
+
+- `videoscale` and `videoconvert` now support multi-threaded scaling and
+  conversion, which is particularly useful with higher resolution video.
+
+- `h264parse` will now automatically insert AU delimiters if needed when
+  outputting byte-stream format, which improves standard compliance and
+  is needed in particular for HLS playback on iOS/macOS.
+
+- `rtpbin` has acquired bundle support for incoming streams
+
+## Major new features and changes
+
+### Noteworthy new API
+
+- The video library gained support for a number of new video formats:
+
+  - `GBR_12LE`, `GBR_12BE`, `GBRA_12LE`, `GBRA_12BE` (planar 4:4:4 RGB/RGBA, 12 bits per channel)
+  - `GBRA_10LE`, `GBRA_10BE` (planar 4:4:4:4 RGBA, 10 bits per channel)
+  - `GBRA` (planar 4:4:4:4 ARGB, 8 bits per channel)
+  - `I420_12BE`, `I420_12LE` (planar 4:2:0 YUV, 12 bits per channel)
+  - `I422_12BE`,`I422_12LE` (planar 4:2:2 YUV, 12 bits per channel)
+  - `Y444_12BE`, `Y444_12LE` (planar 4:4:4 YUV, 12 bits per channel)
+  - `VYUY` (another packed 4:2:2 YUV format)
+
+- The high-level `GstPlayer` API was extended with functions for taking video
+  snapshots and enabling accurate seeking. It can optionally also use the
+  still-experimental `playbin3` element now.
+
+### New Elements
+
+- msdk: new plugin for Intel's Media SDK for hardware-accelerated video encoding
+  and decoding on Intel graphics hardware on Windows or Linux. This includes
+  an H.264 encoder/decoder (`msdkh264dec`, `msdkh264enc`),
+  an H.265 encoder/decoder (`msdkh265dec`, `msdkh265enc`),
+  an MJPEG encoder/encoder (`msdkmjpegdec`, `msdkmjpegenc`),
+  an MPEG-2 video encoder (`msdkmpeg2enc`) and a VP8 encoder (`msdkvp8enc`).
+
+- `iqa` is a new Image Quality Assessment plugin based on [DSSIM][dssim],
+  similar to the old (unported) videomeasure element.
+
+- The `faceoverlay` element, which allows you to overlay SVG graphics over
+  a detected face in a video stream, has been ported from 0.10.
+
+- our `ffmpeg` wrapper plugin now exposes/maps the ffmpeg Opus audio decoder
+  (`avdec_opus`) as well as the GoPro CineForm HD / CFHD decoder (`avdec_cfhd`),
+  and also a parser/writer for the IVF format (`avdemux_ivf` and `avmux_ivf`).
+
+- `audiobuffersplit` is a new element that splits raw audio buffers into
+  equal-sized buffers
+
+- `audiomixmatrix` is a new element that mixes N:M audio channels according to
+  a configured mix matrix.
+
+- The `timecodewait` element got renamed to `avwait` and can operate in
+  different modes now.
+
+- The `opencv` video processing plugin has gained a new `dewarp` element that
+  dewarps fisheye images.
+
+- `ttml` is a new plugin for parsing and rendering subtitles in Timed Text
+  Markup Language (TTML) format. For the time being these elements will not
+  be autoplugged during media playback however, unless the `GST_TTML_AUTOPLUG=1`
+  environment variable is set. Only the EBU-TT-D profile is supported at this
+  point.
+
+[dssim]: https://github.com/pornel/dssim
+
+### New element features and additions
+
+- `x264enc` can now use multiple x264 library versions compiled for different
+  bit depths at runtime, to transparently provide support for multiple bit
+  depths. A new configure parameter `--with-x264-libraries` has been added to
+  specify additional paths to look for additional x264 libraries to load.
+  Background is that the libx264 library is always compile for one specific
+  bit depth and the `x264enc` element would simply support the depth supported
+  by the underlying library. Now we can support multiple depths.
+
+- `x264enc` also picks up the interlacing mode automatically from the input
+  caps now and passed interlacing/TFF information correctly to the library.
+
+- `videoscale` and `videoconvert` now support multi-threaded scaling and
+  conversion, which is particularly useful with higher resolution video.
+  This has to be enabled explicitly via the `"n-threads"` property.
+
+- `videorate`'s new `"rate"` property lets you set a speed factor
+  on the output stream
+
+- `splitmuxsink`'s buffer collection and scheduling was rewritten to make
+  processing and splitting deterministic; before it was possible for a buffer
+  to end up in a different file chunk in different runs. `splitmuxsink` also
+  gained a new `"format-location-full"` signal that works just like the existing
+  `"format-location"` signal only that it is also passed the primary stream's
+  first buffer as argument, so that it is possible to construct the file name
+  based on metadata such as the buffer timestamp or any GstMeta attached to
+  the buffer. The new `"max-size-timecode"` property allows for timecode-based
+  splitting. `splitmuxsink` will now also automatically start a new file if the
+  input caps change in an incompatible way.
+
+- `fakesink` has a new `"drop-out-of-segment"` property to not drop
+  out-of-segment buffers, which is useful for debugging purposes.
+
+- `identity` gained a `"ts-offset"` property.
+
+- both `fakesink` and `identity` now also print what kind of metas are attached
+  to buffers when printing buffer details via the `"last-message"` property
+  used by `gst-launch-1.0 -v`.
+
+- multiqueue: made `"min-interleave-time"` a configurable property.
+
+- video nerds will be thrilled to know that `videotestsrc`'s snow is now
+  deterministic. `videotestsrc` also gained some new properties to make the
+  ball pattern based on system time, and invert colours each second
+  (`"animation-mode"`, `"motion"`, and `"flip"` properties).
+
+- `oggdemux` reverse playback should work again now. You're welcome.
+
+- `playbin3` and `urisourcebin` now have buffering enabled by default, and
+  buffering message aggregation was fixed.
+
+- `tcpclientsrc` now has a `"timeout"` property
+
+- `appsink` has gained support for buffer lists. For backwards compatibility
+  reasons users need to enable this explicitly with `gst_app_sink_set_buffer_list_support()`,
+  however. Once activated, a pulled `GstSample` can contain either a buffer
+  list or a single buffer.
+
+- `splitmuxsrc` reverse playback was fixed and handling of sparse streams, such
+  as subtitle tracks or metadata tracks, was improved.
+
+- `matroskamux` has acquired support for muxing G722 audio; it also marks all
+  buffers as keyframes now when streaming only audio, so that `tcpserversink`
+  will behave properly with audio-only streams.
+
+- `qtmux` gained support for ProRes 4444 XQ, HEVC/H.265 and CineForm (GoPro) formats,
+  and generally writes more video stream-related metadata into the track headers.
+  It is also allows configuration of the maximum interleave size in bytes and
+  time now. For fragmented mp4 we always write the `tfdt` atom now as required
+  by the DASH spec.
+
+- `qtdemux` supports FLAC, xvid, mp2, S16L and CineForm (GoPro) tracks now, and
+  generally tries harder to extract more video-related information from track
+  headers, such as colorimetry or interlacing details. It also received a
+  couple of fixes for the scenario where upstream operates in TIME format and
+  feeds chunks to qtdemux (e.g. DASH or MSE).
+
+- `audioecho` has two new properties to apply a delay only to certain channels
+  to create a surround effect, rather than an echo on all channels. This is
+  useful when upmixing from stereo, for example. The `"surround-delay"` property
+  enables this, and the `"surround-mask"` property controls which channels
+  are considered surround sound channels in this case.
+
+- `webrtcdsp` gained various new properties for gain control and also exposes
+  voice activity detection now, in which case it will post `"voice-activity"`
+  messages on the bus whenever the voice detection status changes.
+
+- The `decklink` capture elements for Blackmagic Decklink cards have seen a
+  number of improvements:
+
+  - `decklinkvideosrc` will post a warning message on "no signal" and an info
+    message when the signal lock has been (re)acquired. There is also a new
+    read-only `"signal"` property that can be used to query the signal lock
+    status. The `GAP` flag will be set on buffers that are captured without
+    a signal lock. The new `drop-no-signal-frames` will make `decklinkvideosrc`
+    drop all buffers that have been captured without an input signal. The
+    `"skip-first-time"` property will make the source drop the first few
+    buffers, which is handy since some devices will at first output buffers
+    with the wrong resolution before they manage to figure out the right input
+    format and decide on the actual output caps.
+
+  - `decklinkaudiosrc` supports more than just 2 audio channels now.
+
+  - The capture sources no longer use the "hardware" timestamps which turn
+    out to be useless and instead just use the pipeline clock directly.
+
+- `srtpdec` now also has a readonly `"stats"` property, just like `srtpenc`.
+
+- `rtpbin` gained RTP bundle support, as used by e.g. WebRTC. The first
+   rtpsession will have a `rtpssrcdemux` element inside splitting the streams
+   based on their SSRC and potentially dispatch to a different rtpsession.
+   Because retransmission SSRCs need to be merged with the corresponding media
+   stream the `::on-bundled-ssrc` signal is emitted on `rtpbin` so that the
+   application can find out to which session the SSRC belongs.
+
+- `rtprtxqueue` gained two new properties exposing retransmission
+  statistics (`"requests"` and `"fulfilled-requests"`)
+
+- `kmssink` will now use the preferred mode for the monitor and render to the
+  base plane if nothing else has set a mode yet. This can also be done forcibly
+  in any case via the new `"force-modesetting"` property. Furthermore, `kmssink`
+  now allows only the supported connector resolutions as input caps in order to
+  avoid scaling or positioning of the input stream, as `kmssink` can't know
+  whether scaling or positioning would be more appropriate for the use case at
+  hand.
+
+- `waylandsink` can now take DMAbuf buffers as input in the presence
+  of a compatible Wayland compositor. This enables zero-copy transfer
+  from a decoder or source that outputs DMAbuf.
+
+- `udpsrc` can be bound to more than one interface when joining a
+  multicast group, this is done by giving a comma separate list of
+  interfaces such as multicast-iface="eth0,eth1".
+
+### Plugin moves
+
+- `dataurisrc` moved from gst-plugins-bad to core
+
+- The `rawparse` plugin containing the `rawaudioparse` and `rawvideoparse`
+  elements moved from gst-plugins-bad to gst-plugins-base. These elements
+  supersede the old `videoparse` and `audioparse` elements. They work the
+  same, with just some minor API changes. The old legacy elements still
+  exist in gst-plugins-bad, but may be removed at some point in the future.
+
+- `timecodestamper` is an element that attaches time codes to video buffers
+  in form of `GstVideoTimeCodeMeta`s. It had a `"clock-source"` property
+  which has now been removed because it was fairly useless in practice. It
+  gained some new properties however: the `"first-timecode"` property can
+  be used to set the inital timecode; alternatively `"first-timecode-to-now"`
+  can be set, and then the current system time at the time the first buffer
+  arrives is used as base time for the time codes.
+
+
+### Plugin removals
+
+- The `mad` mp1/mp2/mp3 decoder plugin was removed from gst-plugins-ugly,
+  as libmad is GPL licensed, has been unmaintained for a very long time, and
+  there are better alternatives available. Use the `mpg123audiodec` element
+  from the `mpg123` plugin in gst-plugins-ugly instead, or `avdec_mp3` from
+  the `gst-libav` module which wraps the ffmpeg library. We expect that we
+  will be able to move mp3 decoding to gst-plugins-good in the next cycle
+  seeing that most patents around mp3 have expired recently or are about to
+  expire.
+
+- The `mimic` plugin was removed from gst-plugins-bad. It contained a decoder
+  and encoder for a video codec used by MSN messenger many many years ago (in
+  a galaxy far far away). The underlying library is unmaintained and no one
+  really needs to use this codec any more. Recorded videos can still be played
+  back with the MIMIC decoder in gst-libav.
+
+## Miscellaneous API additions
+
+- Request pad name templates passed to `gst_element_request_pad()` may now
+  contain multiple specifiers, such as e.g. `src_%u_%u`.
+
+- [`gst_buffer_iterate_meta_filtered()`][buffer-iterate-meta-filtered] is a
+  variant of `gst_buffer_iterate_meta()` that only returns metas of the
+  requested type and skips all other metas.
+
+- [`gst_pad_task_get_state()`][pad-task-get-state] gets the current state of
+  a task in a thread-safe way.
+
+- [`gst_uri_get_media_fragment_table()`][uri-get-fragment-table] provides the
+  media fragments of an URI as a table of key=value pairs.
+
+- [`gst_print()`][print], [`gst_println()`][println], [`gst_printerr()`][printerr],
+  and [`gst_printerrln()`][printerrln] can be used to print to stdout or stderr.
+  These functions are similar to `g_print()` and `g_printerr()` but they also
+  support all the additional format specifiers provided by the GStreamer
+  logging system, such as e.g. `GST_PTR_FORMAT`.
+
+- a `GstParamSpecArray` has been added, for elements who want to have array
+  type properties, such as the `audiomixmatrix` element for example. There are
+  also two new functions to set and get properties of this type from bindings:
+   - gst_util_set_object_array()
+   - gst_util_get_object_array()
+
+- various helper functions have been added to make it easier to set or get
+  GstStructure fields containing caps-style array or list fields from language
+  bindings (which usually support GValueArray but don't know about the GStreamer
+  specific fundamental types):
+   - [`gst_structure_get_array()`][get-array]
+   - [`gst_structure_set_array()`][set-array]
+   - [`gst_structure_get_list()`][get-list]
+   - [`gst_structure_set_list()`][set-list]
+
+- a new ['dynamic type' registry factory type][dynamic-type] was added to
+  register dynamically loadable GType types. This is useful for automatically
+  loading enum/flags types that are used in caps, such as for example the
+  `GstVideoMultiviewFlagsSet` type used in multiview video caps.
+
+- there is a new [`GstProxyControlBinding`][proxy-control-binding] for use
+  with GstController. This allows proxying the control interface from one
+  property on one GstObject to another property (of the same type) in another
+  GstObject. So e.g. in parent-child relationship, one may need to call
+  `gst_object_sync_values()` on the child and have a binding (set elsewhere)
+  on the parent update the value. This is used in `glvideomixer` and `glsinkbin`
+  for example, where `sync_values()` on the child pad or element will call
+  `sync_values()` on the exposed bin pad or element.
+
+  Note that this doesn't solve GObject property forwarding, that must
+  be taken care of by the implementation manually or using GBinding.
+
+- `gst_base_parse_drain()` has been made public for subclasses to use.
+
+- `gst_base_sink_set_drop_out_of_segment()' can be used by subclasses to
+  prevent GstBaseSink from dropping buffers that fall outside of the segment.
+
+- [`gst_calculate_linear_regression()`][calc-lin-regression] is a new utility
+  function to calculate a linear regression.
+
+- [`gst_debug_get_stack_trace`][get-stack-trace] is an easy way to retrieve a
+  stack trace, which can be useful in tracer plugins.
+
+- allocators: the dmabuf allocator is now sub-classable, and there is a new
+  `GST_CAPS_FEATURE_MEMORY_DMABUF` define.
+
+- video decoder subclasses can use the newly-added function
+  `gst_video_decoder_allocate_output_frame_with_params()` to
+  pass a `GstBufferPoolAcquireParams` to the buffer pool for
+  each buffer allocation.
+
+- the video time code API has gained a dedicated [`GstVideoTimeCodeInterval`][timecode-interval]
+  type plus related API, including functions to add intervals to timecodes.
+
+- There is a new `libgstbadallocators-1.0` library in gst-plugins-bad, which
+  may go away again in future releases once the `GstPhysMemoryAllocator`
+  interface API has been validated by more users and was moved to
+  `libgstallocators-1.0` from gst-plugins-base.
+
+[timecode-interval]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html#gst-video-time-code-interval-new
+[buffer-iterate-meta-filtered]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#gst-buffer-iterate-meta-filtered
+[pad-task-get-state]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-task-get-state
+[uri-get-fragment-table]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstUri.html#gst-uri-get-media-fragment-table
+[print]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-print
+[println]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-println
+[printerr]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-printerr
+[printerrln]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-printerrln
+[get-array]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-get-array
+[set-array]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-set-array
+[get-list]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-get-list
+[set-list]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-set-list
+[dynamic-type]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstDynamicTypeFactory.html
+[proxy-control-binding]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/gstreamer-libs-GstProxyControlBinding.html
+[calc-lin-regression]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstUtils.html#gst-calculate-linear-regression
+[get-stack-trace]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstUtils.html#gst-debug-get-stack-trace
+
+### GstPlayer
+
+New API has been added to:
+
+ - get the number of audio/video/subtitle streams:
+   - `gst_player_media_info_get_number_of_streams()`
+   - `gst_player_media_info_get_number_of_video_streams()`
+   - `gst_player_media_info_get_number_of_audio_streams()`
+   - `gst_player_media_info_get_number_of_subtitle_streams()`
+
+ - enable accurate seeking: `gst_player_config_set_seek_accurate()`
+   and `gst_player_config_get_seek_accurate()`
+
+ - get a snapshot image of the video in RGBx, BGRx, JPEG, PNG or
+   native format: [`gst_player_get_video_snapshot()`][snapshot]
+
+ - selecting use of a specific video sink element
+   ([`gst_player_video_overlay_video_renderer_new_with_sink()`][renderer-with-vsink])
+
+ - If the environment variable `GST_PLAYER_USE_PLAYBIN3` is set, GstPlayer will
+   use the still-experimental `playbin3` element and the `GstStreams` API for
+   playback.
+
+[snapshot]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstplayer.html#gst-player-get-video-snapshot
+[renderer-with-vsink]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstplayer-videooverlayvideorenderer.html#gst-player-video-overlay-video-renderer-new-with-sink
+
+## Miscellaneous changes
+
+- video caps for interlaced video may contain an optional `"field-order"` field
+  now in the case of `interlaced-mode=interleaved` to signal that the field
+  order is always the same throughout the stream. This is useful to signal to
+  muxers such as mp4mux. The new field is parsed from/to `GstVideoInfo` of course.
+
+- video decoder and video encoder base classes try harder to proxy
+  interlacing, colorimetry and chroma-site related fields in caps properly.
+
+- The buffer stored in the `PROTECTION` events is now left unchanged. This is a
+  change of behaviour since 1.8, especially for the mssdemux element which used to
+  decode the base64 parsed data wrapped in the protection events emitted by the
+  demuxer.
+
+- `PROTECTION` events can now be injected into the pipeline from the application;
+  source elements deriving from GstBaseSrc will forward those downstream now.
+
+- The DASH demuxer is now correctly parsing the MSPR-2.0 ContentProtection nodes
+  and emits Protection events accordingly. Applications relying on those events
+  might need to decode the base64 data stored in the event buffer before using it.
+
+- The registry can now also be disabled by setting the environment variable
+  `GST_REGISTRY_DISABLE=yes`, with similar effect as the `GST_DISABLE_REGISTRY`
+  compile time switch.
+
+- Seeking performance with gstreamer-vaapi based decoders was improved. It would
+  recreate the decoder and surfaces on every seek which can be quite slow.
+
+- more robust handling of input caps changes in videoaggregator-based elements
+  such as `compositor`.
+
+- Lots of adaptive streaming-related fixes across the board (DASH, MSS, HLS). Also:
+
+  - `mssdemux`, the Microsoft Smooth Streaming demuxer, has seen various
+    fixes for live streams, duration reporting and seeking.
+
+  - The DASH manifest parser now extracts MS PlayReady ContentProtection objects
+    from manifests and sends them downstream as `PROTECTION` events. It also
+    supports multiple Period elements in external xml now.
+
+- gst-libav was updated to ffmpeg 3.3 but should still work with any 3.x
+  version.
+
+- GstEncodingProfile has been generally enhanced so it can, for
+  example, be used to get possible profiles for a given file
+  extension. It is now possible to define profiles based on element
+  factory names or using a path to a `.gep` file containing a
+  serialized profile.
+
+- `audioconvert` can now do endianness conversion in-place. All other
+  conversions still require a copy, but e.g. sign conversion and a few others
+  could also be implemented in-place now.
+
+- The new, experimental `playbin3` and `urisourcebin` elements got many
+  bugfixes and improvements and should generally be closer to a full
+  replacement of the old elements.
+
+- `interleave` now supports > 64 channels.
+
+### OpenGL integration
+
+- As usual the GStreamer OpenGL integration library has seen numerous
+  fixes and performance improvements all over the place, and is hopefully
+  ready now to become API stable and be moved to gst-plugins-base during the
+  1.14 release cycle.
+
+- The GStreamer OpenGL integration layer has also gained support for the
+  Vivante EGL FB windowing system, which improves performance on platforms
+  such as Freescale iMX.6 for those who are stuck with the proprietary driver.
+  The `qmlglsink` element also supports this now if Qt is used with eglfs or
+  wayland backend, and it works in conjunction with [gstreamer-imx][gstreamer-imx]
+  of course.
+
+- various `qmlglsrc` improvements
+
+[gstreamer-imx]: https://github.com/Freescale/gstreamer-imx
+
+## Tracing framework and debugging improvements
+
+- New tracing hooks have been added to track GstMiniObject and GstObject
+  ref/unref operations.
+
+- The memory leaks tracer can optionally use this to retrieve stack traces if
+  enabled with e.g. `GST_TRACERS=leaks(filters="GstEvent,GstMessage",stack-traces-flags=full)`
+
+- The `GST_DEBUG_FILE` environment variable, which can be used to write the
+  debug log output to a file instead of printing it to stderr, can now contain
+  a name pattern, which is useful for automated testing and continuous
+  integration systems. The following format specifiers are supported:
+
+   - `%p`: will be replaced with the PID
+   - `%r`: will be replaced with a random number, which is useful for instance
+     when running two processes with the same PID but in different containers.
+
+## Tools
+
+- `gst-inspect-1.0` can now list elements by type with the new `--types`
+   command-line option, e.g. `gst-inspect-1.0 --types=Audio/Encoder` will
+   show a list of audio encoders.
+
+- `gst-launch-1.0` and `gst_parse_launch()` have gained a new operator (`:`)
+   that allows linking all pads between two elements. This is useful in cases
+   where the exact number of pads or type of pads is not known beforehand, such
+   as in the `uridecodebin : encodebin` scenario, for example. In this case,
+   multiple links will be created if the encodebin has multiple profiles
+   compatible with the output of uridecodebin.
+
+- `gst-device-monitor-1.0` now shows a `gst-launch-1.0` snippet for each
+  device that shows how to make use of it in a `gst-launch-1.0` pipeline string.
+
+## GStreamer RTSP server
+
+- The RTSP server now also supports Digest authentication in addition to Basic
+  authentication.
+
+- The `GstRTSPClient` class has gained a `pre-*-request` signal and virtual
+  method for each client request type, emitted in the beginning of each rtsp
+  request. These signals or virtual methods let the application validate the
+  requests, configure the media/stream in a certain way and also generate error
+  status codes in case of an error or a bad request.
+
+## GStreamer VAAPI
+
+- GstVaapiDisplay now inherits from GstObject, thus the VA display logging
+  messages are better and tracing the context sharing is more readable.
+
+- When uploading raw images into a VA surfaces now VADeriveImages are tried
+  fist, improving the upload performance, if it is possible.
+
+- The decoders and the post-processor now can push dmabuf-based buffers to
+  downstream under certain conditions. For example:
+
+  `GST_GL_PLATFORM=egl gst-play-1.0 video-sample.mkv --videosink=glimagesink`
+
+- Refactored the wrapping of VA surface into gstreamer memory, adding lock
+  when mapping and unmapping, and many other fixes.
+
+- Now `vaapidecodebin` loads `vaapipostproc` dynamically. It is possible to
+  avoid it usage with the environment variable `GST_VAAPI_DISABLE_VPP=1`.
+
+- Regarding encoders: they have primary rank again, since they can discover,
+  in run-time, the color formats they can use for upstream raw buffers and
+  caps renegotiation is now possible. Also the encoders push encoding info
+  downstream via tags.
+
+- About specific encoders: added constant bit-rate encoding mode for VP8 and
+  H265 encoder handles P010_10LE color format.
+
+- Regarding decoders, flush operation has been improved, now the internal VA
+  encoder is not recreated at each flush. Also there are several improvements
+  in the handling of H264 and H265 streams.
+
+- VAAPI plugins try to create their on GstGL context (when available) if they
+  cannot find it in the pipeline, to figure out what type of VA Display they
+  should create.
+
+- Regarding `vaapisink` for X11, if the backend reports that it is unable to
+  render correctly the current color format, an internal VA post-processor, is
+  instantiated (if available) and converts the color format.
+
+## GStreamer Editing Services and NLE
+
+- Enhanced auto transition behaviour
+
+- Fix some races in `nlecomposition`
+
+- Allow building with msvc
+
+- Added a UNIX manpage for `ges-launch`
+
+- API changes:
+  - Added ges_deinit (allowing the leak tracer to work properly)
+  - Added ges_layer_get_clips_in_interval
+  - Finally hide internal symbols that should never have been exposed
+
+## GStreamer validate
+
+- Port `gst-validate-launcher` to python 3
+
+- `gst-validate-launcher` now checks if blacklisted bugs have been fixed on
+  bugzilla and errors out if it is the case
+
+- Allow building with msvc
+
+- Add ability for the launcher to run GStreamer unit tests
+
+- Added a way to activate the leaks tracer on our tests and fix leaks
+
+- Make the http server multithreaded
+
+- New testsuite for running various test scenarios on the DASH-IF test vectors
+
+## Build and Dependencies
+
+- Meson build files are now disted in tarballs, for jhbuild and so distro
+  packagers can start using it. Note that the Meson-based build system is not
+  100% feature-equivalent with the autotools-based one yet.
+
+- Some plugin filenames have been changed to match the plugin names: for example
+  the file name of the `encoding` plugin in gst-plugins-base containing the
+  `encodebin` element was `libgstencodebin.so` and has been changed to
+  `libgstencodebin.so`. This affects only a handful of plugins across modules.
+
+  **Developers who install GStreamer from source and just do `make install`**
+  **after updating the source code, without doing `make uninstall` first, will**
+  **have to manually remove the old installed plugin files from the installation**
+  **prefix, or they will get 'Cannot register existing type' critical warnings.**
+
+- Most of the docbook-based documentation (FAQ, Application Development Manual,
+  Plugin Writer's Guide, design documents) has been converted to markdown and
+  moved into a new gst-docs module. The gtk-doc library API references and
+  the plugins documentation are still built as part of the source modules though.
+
+- GStreamer core now optionally uses libunwind and libdw to generate backtraces.
+  This is useful for tracer plugins used during debugging and development.
+
+- There is a new `libgstbadallocators-1.0` library in gst-plugins-bad (which
+  may go away again in future releases once the `GstPhysMemoryAllocator`
+  interface API has been validated by more users).
+
+- `gst-omx` and `gstreamer-vaapi` modules can now also be built using the
+  Meson build system.
+
+- The `qtkitvideosrc` element for macOS was removed. The API is deprecated
+  since 10.9 and it wasn't shipped in the binaries since a few releases.
+
+## Platform-specific improvements
+
+### Android
+
+- androidmedia: add support for VP9 video decoding/encoding and Opus audio
+  decoding (where supported)
+
+### OS/X and iOS
+
+- `avfvideosrc`, which represents an iPhone camera or, on a Mac, a screencapture
+  session, so far allowed you to select an input device by device index only.
+  New API adds the ability to select the position (front or back facing) and
+  device-type (wide angle, telephoto, etc.). Furthermore, you can now also
+  specify the orientation (portrait, landscape, etc.) of the videostream.
+
+### Windows
+
+- `dx9screencapsrc` can now optionally also capture the cursor.
+
+## Contributors
+
+Aleix Conchillo Flaque, Alejandro G. Castro, Aleksandr Slobodeniuk, Alexandru
+Băluț, Alex Ashley, Andre McCurdy, Andrew, Anton Eliasson, Antonio Ospite,
+Arnaud Vrac, Arun Raghavan, Aurélien Zanelli, Axel Menzel, Benjamin Otte,
+Branko Subasic, Brendan Shanks, Carl Karsten, Carlos Rafael Giani, ChangBok
+Chae, Chris Bass, Christian Schaller, christophecvr, Claudio Saavedra,
+Corentin Noël, Dag Gullberg, Daniel Garbanzo, Daniel Shahaf, David Evans,
+David Schleef, David Warman, Dominique Leuenberger, Dongil Park, Douglas
+Bagnall, Edgard Lima, Edward Hervey, Emeric Grange, Enrico Jorns, Enrique
+Ocaña González, Evan Nemerson, Fabian Orccon, Fabien Dessenne, Fabrice Bellet,
+Florent Thiéry, Florian Zwoch, Francisco Velazquez, Frédéric Dalleau, Garima
+Gaur, Gaurav Gupta, George Kiagiadakis, Georg Lippitsch, Göran Jönsson, Graham
+Leggett, Guillaume Desmottes, Gurkirpal Singh, Haihua Hu, Hanno Boeck, Havard
+Graff, Heekyoung Seo, hoonhee.lee, Hyunjun Ko, Imre Eörs, Iñaki García
+Etxebarria, Jagadish, Jagyum Koo, Jan Alexander Steffens (heftig), Jan
+Schmidt, Jean-Christophe Trotin, Jochen Henneberg, Jonas Holmberg, Joris
+Valette, Josep Torra, Juan Pablo Ugarte, Julien Isorce, Jürgen Sachs, Koop
+Mast, Kseniia Vasilchuk, Lars Wendler, leigh123linux@googlemail.com, Luis de
+Bethencourt, Lyon Wang, Marcin Kolny, Marinus Schraal, Mark Nauwelaerts,
+Mathieu Duponchelle, Matthew Waters, Matt Staples, Michael Dutka, Michael
+Olbrich, Michael Smith, Michael Tretter, Miguel París Díaz, namanyadav12, Neha
+Arora, Nick Kallen, Nicola Murino, Nicolas Dechesne, Nicolas Dufresne, Nicolas
+Huet, Nirbheek Chauhan, Ole André Vadla Ravnås, Olivier Crête, Patricia
+Muscalu, Peter Korsgaard, Peter Seiderer, Petr Kulhavy, Philippe Normand,
+Philippe Renon, Philipp Zabel, Rahul Bedarkar, Reynaldo H. Verdejo Pinochet,
+Ricardo Ribalda Delgado, Rico Tzschichholz, Руслан Ижбулатов, Samuel Maroy,
+Santiago Carot-Nemesio, Scott D Phillips, Sean DuBois, Sebastian Dröge, Sergey
+Borovkov, Seungha Yang, shakin chou, Song Bing, Søren Juul, Sreerenj
+Balachandran, Stefan Kost, Stefan Sauer, Stepan Salenikovich, Stian Selnes,
+Stuart Weaver, suhas2go, Thiago Santos, Thibault Saunier, Thomas Bluemel,
+Thomas Petazzoni, Tim-Philipp Müller, Ting-Wei Lan, Tobias Mueller, Todor
+Tomov, Tomasz Zajac, Ulf Olsson, Ursula Maplehurst, Víctor Manuel Jáquez Leal,
+Victor Toso, Vincent Penquerc'h, Vineeth TM, Vinod Kesti, Vitor Massaru Iha,
+Vivia Nikolaidou, WeiChungChang, William Manley, Wim Taymans, Wojciech
+Przybyl, Wonchul Lee, Xavier Claessens, Yasushi SHOJI
+
+... and many others who have contributed bug reports, translations, sent
+suggestions or helped testing.
+
+## Bugs fixed in 1.12
+
+More than [635 bugs][bugs-fixed-in-1.12] have been fixed during
+the development of 1.12.
+
+This list does not include issues that have been cherry-picked into the
+stable 1.10 branch and fixed there as well, all fixes that ended up in the
+1.10 branch are also included in 1.12.
+
+This list also does not include issues that have been fixed without a bug
+report in bugzilla, so the actual number of fixes is much higher.
+
+[bugs-fixed-in-1.12]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=213265&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.10.1&target_milestone=1.10.2&target_milestone=1.10.3&target_milestone=1.10.4&target_milestone=1.11.1&target_milestone=1.11.2&target_milestone=1.11.3&target_milestone=1.11.4&target_milestone=1.11.90&target_milestone=1.11.91&target_milestone=1.12.0
+
+## Stable 1.12 branch
+
+After the 1.12.0 release there will be several 1.12.x bug-fix releases which
+will contain bug fixes which have been deemed suitable for a stable branch,
+but no new features or intrusive changes will be added to a bug-fix release
+usually. The 1.12.x bug-fix releases will be made from the git 1.12 branch, which
+is a stable branch.
+
+### 1.12.0
+
+1.12.0 was released on 4th May 2017.
+
+## Known Issues
+
+- The `webrtcdsp` element is currently not shipped as part of the Windows
+  binary packages due to a [build system issue][bug-770264].
+
+[bug-770264]: https://bugzilla.gnome.org/show_bug.cgi?id=770264
+
+## Schedule for 1.14
+
+Our next major feature release will be 1.14, and 1.11 will be the unstable
+development version leading up to the stable 1.12 release. The development
+of 1.13/1.14 will happen in the git master branch.
+
+The plan for the 1.14 development cycle is yet to be confirmed, but it is
+expected that feature freeze will be around September 2017
+followed by several 1.13 pre-releases and the new 1.14 stable release
+in October.
+
+1.14 will be backwards-compatible to the stable 1.12, 1.10, 1.8, 1.6, 1.4,
+1.2 and 1.0 release series.
+
+- - -
+
+*These release notes have been prepared by Sebastian Dröge, Tim-Philipp Müller
+and Víctor Manuel Jáquez Leal.*
+
+*License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)*
diff --git a/README b/README
new file mode 100644
index 0000000..cf32843
--- /dev/null
+++ b/README
@@ -0,0 +1,255 @@
+GStreamer 1.13.x development series
+
+WHAT IT IS
+----------
+
+This is GStreamer, a framework for streaming media.
+
+WHERE TO START
+--------------
+
+We have a website at
+http://gstreamer.freedesktop.org/
+
+You should start by going through our FAQ at
+http://gstreamer.freedesktop.org/data/doc/gstreamer/head/faq/html/
+
+There is more documentation; go to
+http://gstreamer.freedesktop.org/documentation
+
+You can subscribe to our mailing lists; see the website for details.
+
+We track bugs in GNOME's bugzilla; see the website for details.
+
+You can join us on IRC - #gstreamer on irc.freenode.org
+
+GStreamer 1.0 series
+--------------------
+
+Starring
+
+  GSTREAMER
+
+The core around which all other modules revolve.  Base functionality and
+libraries, some essential elements, documentation, and testing.
+
+  BASE
+
+A well-groomed and well-maintained collection of GStreamer plug-ins and
+elements, spanning the range of possible types of elements one would want
+to write for GStreamer.  
+
+And introducing, for the first time ever, on the development screen ...
+
+  THE GOOD
+
+ --- "Such ingratitude.  After all the times I've saved your life."
+
+A collection of plug-ins you'd want to have right next to you on the
+battlefield.  Shooting sharp and making no mistakes, these plug-ins have it
+all: good looks, good code, and good licensing.  Documented and dressed up
+in tests.  If you're looking for a role model to base your own plug-in on,
+here it is.
+
+If you find a plot hole or a badly lip-synced line of code in them,
+let us know - it is a matter of honour for us to ensure Blondie doesn't look
+like he's been walking 100 miles through the desert without water.
+
+  THE UGLY
+
+  --- "When you have to shoot, shoot.  Don't talk."
+
+There are times when the world needs a color between black and white.
+Quality code to match the good's, but two-timing, backstabbing and ready to
+sell your freedom down the river.  These plug-ins might have a patent noose
+around their neck, or a lock-up license, or any other problem that makes you
+think twice about shipping them.
+
+We don't call them ugly because we like them less.  Does a mother love her
+son less because he's not as pretty as the other ones ? No  - she commends
+him on his great personality.  These plug-ins are the life of the party.
+And we'll still step in and set them straight if you report any unacceptable
+behaviour - because there are two kinds of people in the world, my friend:
+those with a rope around their neck and the people who do the cutting.
+
+  THE BAD
+
+  --- "That an accusation?"
+
+No perfectly groomed moustache or any amount of fine clothing is going to
+cover up the truth - these plug-ins are Bad with a capital B. 
+They look fine on the outside, and might even appear to get the job done, but
+at the end of the day they're a black sheep. Without a golden-haired angel
+to watch over them, they'll probably land in an unmarked grave at the final
+showdown.
+
+Don't bug us about their quality - exercise your Free Software rights,
+patch up the offender and send us the patch on the fastest steed you can
+steal from the Confederates. Because you see, in this world, there's two
+kinds of people, my friend: those with loaded guns and those who dig.
+You dig.
+
+The Lowdown
+-----------
+
+  --- "I've never seen so many plug-ins wasted so badly."
+
+GStreamer Plug-ins has grown so big that it's hard to separate the wheat from
+the chaff.  Also, distributors have brought up issues about the legal status
+of some of the plug-ins we ship.  To remedy this, we've divided the previous
+set of available plug-ins into four modules:
+
+- gst-plugins-base: a small and fixed set of plug-ins, covering a wide range
+  of possible types of elements; these are continuously kept up-to-date
+  with any core changes during the development series.
+
+  - We believe distributors can safely ship these plug-ins.
+  - People writing elements should base their code on these elements.
+  - These elements come with examples, documentation, and regression tests.
+
+- gst-plugins-good: a set of plug-ins that we consider to have good quality
+  code, correct functionality, our preferred license (LGPL for the plug-in
+  code, LGPL or LGPL-compatible for the supporting library).
+
+  - We believe distributors can safely ship these plug-ins.
+  - People writing elements should base their code on these elements.
+ 
+- gst-plugins-ugly: a set of plug-ins that have good quality and correct
+  functionality, but distributing them might pose problems.  The license
+  on either the plug-ins or the supporting libraries might not be how we'd
+  like. The code might be widely known to present patent problems.
+
+  - Distributors should check if they want/can ship these plug-ins.
+  - People writing elements should base their code on these elements.
+
+- gst-plugins-bad: a set of plug-ins that aren't up to par compared to the
+  rest.  They might be close to being good quality, but they're missing
+  something - be it a good code review, some documentation, a set of tests,
+  a real live maintainer, or some actual wide use.
+  If the blanks are filled in they might be upgraded to become part of
+  either gst-plugins-good or gst-plugins-ugly, depending on the other factors.
+
+  - If the plug-ins break, you can't complain - instead, you can fix the
+    problem and send us a patch, or bribe someone into fixing them for you.
+  - New contributors can start here for things to work on.
+
+PLATFORMS
+---------
+
+- Linux is of course fully supported
+- FreeBSD is reported to work; other BSDs should work too
+- Solaris is reported to work; a specific sunaudiosink plugin has been written
+- MacOSX works, binary 1.x packages can be built using the cerbero build tool
+- Windows works; binary 1.x packages can be built using the cerbero build tool
+  - MSys/MinGW builds
+  - Microsoft Visual Studio builds are not yet available or supported
+- Android works, binary 1.x packages can be built using the cerbero build tool
+- iOS works
+
+INSTALLING FROM PACKAGES
+------------------------
+
+You should always prefer installing from packages first.  GStreamer is
+well-maintained for a number of distributions, including Fedora, Debian,
+Ubuntu, Mandrake, Gentoo, ...
+
+Only in cases where you:
+- want to hack on GStreamer
+- want to verify that a bug has been fixed
+- do not have a sane distribution
+should you choose to build from source tarballs or git.
+
+Find more information about the various packages at
+http://gstreamer.freedesktop.org/download/
+
+COMPILING FROM SOURCE TARBALLS
+------------------------------
+
+- again, make sure that you really need to install from source !
+  If GStreamer is one of your first projects ever that you build from source,
+  consider taking on an easier project.
+
+- check output of ./configure --help to see if any options apply to you
+- run
+  ./configure
+  make
+
+  to build GStreamer.
+- if you want to install it (not required, but what you usually want to do), run
+  make install
+
+- try out a simple test:
+  gst-launch -v fakesrc num_buffers=5 ! fakesink
+  (If you didn't install GStreamer, prefix gst-launch with tools/)
+
+  If it outputs a bunch of messages from fakesrc and fakesink, everything is
+  ok.
+
+  If it did not work, keep in mind that you might need to adjust the
+  PATH and/or LD_LIBRARY_PATH environment variables to make the system
+  find GStreamer in the prefix where you installed (by default that is /usr/local).
+
+- After this, you're ready to install gst-plugins, which will provide the
+  functionality you're probably looking for by now, so go on and read
+  that README.
+
+COMPILING FROM GIT
+------------------
+
+When building from git sources, you will need to run autogen.sh to generate
+the build system files.
+
+You will need a set of additional tools typical for building from git,
+including:
+- autoconf
+- automake
+- libtool
+
+autogen.sh will check for recent enough versions and complain if you don't have
+them.  You can also specify specific versions of automake and autoconf with
+--with-automake and --with-autoconf
+
+Check autogen.sh options by running autogen.sh --help
+
+autogen.sh can pass on arguments to configure
+
+When you have done this once, you can use autoregen.sh to re-autogen with
+the last passed options as a handy shortcut.  Use it.
+
+After the autogen.sh stage, you can follow the directions listed in
+"COMPILING FROM SOURCE"
+
+You can also run your whole git stack uninstalled in your home directory,
+so that you can quickly test changes without affecting your system setup or
+interfering with GStreamer installed from packages.  Many GStreamer developers
+use an uninstalled setup for their work.
+
+There is a 'create-uninstalled-setup.sh' script in
+
+  http://cgit.freedesktop.org/gstreamer/gstreamer/tree/scripts/
+
+to easily create an uninstalled setup from scratch.
+
+
+PLUG-IN DEPENDENCIES AND LICENSES
+---------------------------------
+
+GStreamer is developed under the terms of the LGPL (see LICENSE file for
+details). Some of our plug-ins however rely on libraries which are available
+under other licenses. This means that if you are distributing an application
+which has a non-GPL compatible license (for instance a closed-source
+application) with GStreamer, you have to make sure not to distribute GPL-linked
+plug-ins.
+
+When using GPL-linked plug-ins, GStreamer is for all practical reasons
+under the GPL itself.
+
+HISTORY
+-------
+
+The fundamental design comes from the video pipeline at Oregon Graduate
+Institute, as well as some ideas from DirectMedia.  It's based on plug-ins that
+will provide the various codec and other functionality.  The interface
+hopefully is generic enough for various companies (ahem, Apple) to release
+binary codecs for Linux, until such time as they get a clue and release the
+source.
diff --git a/README.static-linking b/README.static-linking
new file mode 100644
index 0000000..6d8299b
--- /dev/null
+++ b/README.static-linking
@@ -0,0 +1,174 @@
+=================================
+ GStreamer Static Linking README
+=================================
+
+DRAFT, April 2013
+
+
+   I. INTRODUCTION
+
+It is possible to link GStreamer libraries, plugins and applications
+statically, both in case of free/libre/open-source software applications
+and proprietary applications. On some platforms static linking may even
+be required.
+
+However, distributing statically linked binaries using GStreamer usually
+requires additional effort to stay compliant with the GNU LGPL v2.1 license.
+
+The purpose of this document is to draw attention to this fact, and to
+summarise in layman's terms what we believe is required from anyone
+distributing statically linked GStreamer binaries. Most of this also
+applies to dynamically linked GStreamer binaries.
+
+
+   II. DISCLAIMER
+
+This document is not legal advice, nor is it comprehensive. It may use
+words in ways that do not match the definition or use in the license
+text. It may even be outright wrong. Read the license text for all the
+details, it is the only legally binding document in this respect.
+
+This document is primarily concerned with the implications for the
+distribution of binaries based on LGPL-licensed software as imposed by
+the LGPL license, but there may be other restrictions to the distribution
+of such binaries, such as terms and conditions of distribution channels
+(e.g. "app stores").
+
+
+   III. THE SPIRIT OF THE LGPL LICENSE
+
+The GNU LGPL v2.1 license allows use of such-licensed software by
+proprietary applications, but still aims to ensure that at least the
+LGPL-licensed software parts remain free under all circumstances. This
+means any changes to LGPL-licensed source code must be documented and
+be made available on request to those who received binaries of the
+software. It also means that it must be possible to make changes to the
+LGPL-licensed software parts and make the application use those, as far
+as that is possible. And that recipients of an application using
+LGPL-licensed software are made aware of their rights according to the
+LGPL license.
+
+In an environment where GStreamer libraries and plugins are used as
+dynamically-loaded shared objects (DLL/.so/.dyn files), this is usually
+not a big problem, because it is fairly easy to compile a modified version
+of the GStreamer libraries or LGPL plugins, and the application will/should
+just pick up and use the modified version automatically. All that is needed
+is for the original, LGPL-licensed source code and source code modifications
+to be made available, and for a way to build the libraries or plugins for
+the platform required (usually that will be using the build system scripts
+that come with GStreamer, and using the typical build environment on the
+system in question, but where that is not the case the needed build scripts
+and/or tools would need to be provided as well).
+
+
+   IV. THINGS YOU NEED TO DO
+
+  * You must tell users of your application that you are using LGPL-licensed
+    software, which LGPL-licensed software exactly, and you must provide them
+    with a copy of the license so they know their rights under the LGPL.
+
+  * You must provide (on request) all the source code and all the changes
+    or additions you have made to the LGPL-licensed software you are using.
+
+    For GStreamer code we would recommend that the changes be provided either
+    in form of a branch in a git repository, or as a set of "git format-patch"-
+    style patches against a GStreamer release or a snapshot of a GStreamer git
+    repository. The patches should ideally say what was changed and why it
+    was changed, and there should ideally be separate patches for independent
+    changes.
+
+  * You must provide a way for users of your application to make changes to
+    the LGPL-licensed parts of the code, and re-create a full application
+    binary with the changes (using the standard toolchain and tools of the
+    target platform; if you are using a custom toolchain or custom tools
+    you must provide these and document how to use them to create a new
+    application binary).
+
+    Note that this of course does not mean that the user is allowed to
+    re-distribute the changed application. Nor does it mean that you have
+    to provide your proprietary source code - it is sufficient to provide a
+    ready-made compiled object file that can be relinked into an application
+    binary with the re-compiled LGPL components.
+
+
+   V. THINGS TO LOOK OUT FOR
+
+While most GStreamer plugins and the libraries they depend on are licensed
+under the LGPL or even more permissive licenses, that is not the case for
+all plugins and libraries used, esp. those in the gst-plugins-ugly or
+some of those in the gst-plugins-bad set of plugins.
+
+When statically linking proprietary code, care must be taken not to
+statically link plugins or libraries that are licensed under less permissive
+terms than the LGPL, such as e.g. GPL-licensed libraries.
+
+
+   VI. SPECIAL CONSIDERATIONS FOR SPECIFIC USE-CASES
+
+
+   1. Proprietary GStreamer/GLib-based Application On iOS
+
+Let's assume an individual or a company wants to distribute a proprietary
+iOS application that is built on top of GStreamer and GLib through
+Apple's App Store. At the time of writing the Apple iPhone developer
+agreement didn’t allow the bundling of shared libraries, so distributing
+a proprietary iOS application with shared libraries is only possible using
+distribution mechanisms outside of the App Store and/or only to jailbroken
+devices, a prospect that may not appeal to our individual or company. So the
+only alternative then is to link everything statically, which means the
+obligations mentioned above come into play.
+
+
+   2. Example: Jabber on iOS
+
+Tandberg (now Cisco) created a Jabber application for iOS, based on GStreamer.
+On request they provided an LGPL compliance bundle in form of a zip file, with
+roughly the following contents:
+
+buildapp.sh
+readme.txt
+Jabber/Jabber-Info.plist
+Jabber/libip.a [236MB binary with proprietary code]
+Jabber/main.mm
+Jabber/xcconfig/Application.xcconfig
+Jabber/xcconfig/Debug.xcconfig
+Jabber/xcconfig/Release.xcconfig
+Jabber/xcconfig/Shared.xcconfig
+Jabber/Resources/*.lproj/Localizable.strings
+Jabber/Resources/{Images,Audio,Sounds,IB,Message Styles,Emoticons,Fonts}/*
+Jabber/Resources/*
+Jabber.xcodeproj/project.pbxproj
+Jabber.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+opensource/build/config.site
+opensource/build/m4/movi.m4
+opensource/build/scripts/clean-deps.sh
+opensource/build/scripts/fixup-makefile.sh
+opensource/build/scripts/MoviMaker.py
+opensource/build.sh
+opensource/env.sh
+opensource/Makefile
+opensource/external/glib/*
+opensource/external/gstreamer/{gstreamer,gst-plugins-*}/*
+opensource/external/openssl/*
+opensource/external/proxy-libintl/*
+opensource/toolchain/darwin-x86/bin/{misc autotoools,m4,glib-mkenums,glib-genmarshal,libtool,pkg-config,etc.}
+opensource/toolchain/darwin-x86/share/{aclocal,aclocal-1.11,autoconf,automake-1.11,libtool}/*
+opensource/toolchain/darwin-x86/share/Config.pm
+opensource/toolchain/darwin-x86/share/Config.pm.movi.in
+patches/glib/glib.patch
+patches/gst-plugins-bad/gst-plugins-bad.patch
+patches/gst-plugins-base/gst-plugins-base.patch
+patches/gst-plugins-good/gst-plugins-good.patch
+patches/gstreamer/gstreamer.patch
+patches/openssl/openssl.patch
+
+readme.txt starts with "This Readme file describes how to build the Cisco 
+Jabber for iPad application. You need to install Xcode, but the final package
+is built by running buildapp.sh." and describes how to build project,
+prerequisites, the procedure in detail, and a "How to Include Provisioning
+Profile Manually / Alternate Code Signing Instructions" section.
+
+
+   3. Random Links Which May Be Of Interest
+
+[0] http://multinc.com/2009/08/24/compatibility-between-the-iphone-app-store-and-the-lgpl/
diff --git a/RELEASE b/RELEASE
new file mode 100644
index 0000000..3311f7d
--- /dev/null
+++ b/RELEASE
@@ -0,0 +1,98 @@
+
+Release notes for GStreamer Good Plugins 1.12.0
+
+The GStreamer team is pleased to announce the first release in the stable 1.12
+release series. The 1.12 release series is adding new features on top of the
+1.0, 1.2, 1.4, 1.6, 1.8 and 1.10 series and is part of the API and ABI-stable
+1.x release series of the GStreamer multimedia framework.
+
+
+Full release notes can be found here
+
+
+Binaries for Android, iOS, Mac OS X and Windows will be provided in the next days.
+
+
+"Such ingratitude.  After all the times I've saved your life."
+
+
+A collection of plugins you'd want to have right next to you on the
+battlefield.  Shooting sharp and making no mistakes, these plugins have it
+all: good looks, good code, and good licensing.  Documented and dressed up
+in tests.  If you're looking for a role model to base your own plugin on,
+here it is.
+
+
+If you find a plot hole or a badly lip-synced line of code in them,
+let us know - it is a matter of honour for us to ensure Blondie doesn't look
+like he's been walking 100 miles through the desert without water.
+
+
+This module contains a set of plugins that we consider to have good quality
+  code, correct functionality, our preferred license (LGPL for the plugin
+  code, LGPL or LGPL-compatible for the supporting library).
+We believe distributors can safely ship these plugins.
+People writing elements should base their code on these elements.
+
+
+Other modules containing plugins are:
+
+
+gst-plugins-base
+contains a basic set of well-supported plugins
+gst-plugins-ugly
+contains a set of well-supported plugins, but might pose problems for
+    distributors
+gst-plugins-bad
+contains a set of less supported plugins that haven't passed the
+    rigorous quality testing we expect, or are still missing documentation
+    and/or unit tests
+gst-libav
+contains a set of codecs plugins based on libav (formerly gst-ffmpeg)
+
+
+
+  
+
+Bugs fixed in this release
+     
+      * 782042 : qtdemux: Fix crash on mss stream caused by invalid stsd entry access
+
+==== Download ====
+
+You can find source releases of gst-plugins-good in the download
+directory: https://gstreamer.freedesktop.org/src/gst-plugins-good/
+
+The git repository and details how to clone it can be found at
+http://cgit.freedesktop.org/gstreamer/gst-plugins-good/
+
+==== Homepage ====
+
+The project's website is https://gstreamer.freedesktop.org/
+
+==== Support and Bugs ====
+
+We use GNOME's bugzilla for bug reports and feature requests:
+http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer
+
+Please submit patches via bugzilla as well.
+
+For help and support, please subscribe to and send questions to the
+gstreamer-devel mailing list (see below for details).
+
+There is also a #gstreamer IRC channel on the Freenode IRC network.
+
+==== Developers ====
+
+GStreamer is stored in Git, hosted at git.freedesktop.org, and can be cloned
+from there (see link above).
+
+Interested developers of the core library, plugins, and applications should
+subscribe to the gstreamer-devel list.
+
+        
+Contributors to this release
+    
+      * Sebastian Dröge
+      * Seungha Yang

\ No newline at end of file
diff --git a/REQUIREMENTS b/REQUIREMENTS
new file mode 100644
index 0000000..140e824
--- /dev/null
+++ b/REQUIREMENTS
@@ -0,0 +1,182 @@
+GStreamer uses a *large* array of tools and libraries, most of which are
+optional. We have attempted to make sure that any code that depends on
+optional libraries doesn't get built unless you have those libraries. If
+you find this not to be the case, please, let us know by filing a bug
+report at http://bugzilla.gnome.org/.
+
+On Debian/Ubuntu, the easiest way to install most build requirements is:
+
+        sudo apt-get build-dep gst-plugins-good1.0
+
+Required tools:
+===============
+
+An extra set of tools is required if you wish to build GStreamer
+from git (using autogen.sh):
+
+autoconf  >= 2.68   https://www.gnu.org/software/autoconf/
+automake  >= 1.11   https://www.gnu.org/software/automake/
+gettext   >= 0.17   https://www.gnu.org/software/gettext/
+libtool   >= 2.2.6  https://www.gnu.org/software/libtool/
+pkgconfig >= 0.9.0  https://www.freedesktop.org/software/pkgconfig/
+
+Required libraries:
+===================
+
+Package:        GStreamer
+Version:        1.x (same 1.x version as this package)
+Recommended:    Latest 1.x
+URL:            http://gstreamer.freedesktop.org/
+DebianPackage:  libgstreamer1.0-dev
+Notes:          The required version is updated frequently, so the version
+                listed in this file is often out of date. If you are compiling
+                from git master, you will usually need GStreamer core and
+                gst-plugins-base from git master as well.
+
+Package:        GStreamer Base Plugins
+Version:        1.x (same 1.x version as this package)
+Recommended:    Latest 1.x
+URL:            http://gstreamer.freedesktop.org/
+DebianPackage:  libgstreamer-plugins-base1.0-dev
+Notes:          The required version is updated frequently, so the version
+                listed in this file is often out of date. If you are compiling
+                from git master, you will usually need GStreamer core and
+                gst-plugins-base from git master as well.
+
+
+Optional libraries:
+===================
+
+This file lists supporting libraries for which gst-plugins-good contains
+plugins, as well as their minimum required version. You can find the
+corresponding plugins in ext/(library)
+
+Package:        Orc
+Version:        >= 0.4.17
+Recommended:    Latest 0.4.x
+URL:            http://gstreamer.freedesktop.org/data/src/orc/
+DebianPackage:  liborc-0.4-dev
+Notes:		Used by many plugins for accelerating SIMD processing using
+                run-time generated assembly. Not a hard requirement, but
+                highly recommended. Packagers, please hard-depend on liborc.
+                The git repository is http://cgit.freedesktop.org/gstreamer/orc/
+                (all versions on entropywave.com are outdated)
+
+Package:        gdk-pixbuf Library
+Version:        >= 2.8.0
+Recommended:    Latest 2.x
+URL:            http://www.gtk.org/
+DebianPackage:  libgdk-pixbuf2.0-dev
+Plugins:        gdkpixbuf (gdkpixbufdec, gdkpixbufoverlay)
+Notes:          This library does not depend on Gtk+ or Gdk or any window system
+
+Package:        GTK+
+Version:        >= 3.0
+Recommended:    Latest 3.x
+URL:            http://www.gtk.org/
+DebianPackage:  libgtk-3-dev
+Plugins:        None
+Notes:	        Only needed by some of the examples, not by any plugins.
+
+Package:        Xlib
+Plugins:        ximagesrc
+DebianPackage:  libx11-dev libxv-dev libxt-dev
+
+Package:        AALib
+Plugins:        aasink
+URL:            http://aa-project.sourceforge.net/aalib/
+
+Package:        Cairo
+Version:        >= 1.10
+DebianPackage:  libcairo2-dev
+Plugins:        cairo (cairooverlay)
+URL:            http://cairographics.org/
+
+Package:        FLAC
+Version:        >= 1.1.4
+DebianPackage:  libflac-dev
+Plugins:        flac (flacenc, flacdec)
+URL:            http://flac.sourceforge.net/
+
+Package:        gudev
+Version:        >= 147
+DebianPackage:  libgudev-1.0-dev
+Plugins:        v4l2 (v4l2src)
+URL:            http://www.freedesktop.org/software/systemd/
+Notes:          This dependency is entirely optional, the video4linux plugin
+                will work just fine without it. gudev is only required for
+                the device probing and monitoring functionality to detect
+                video4linux devices appearing/disappearing at run-time.
+
+Package:        JPEG library
+Plugins:        jpeg (jpegenc, jpegdec, smokeenc, smokedec)
+DebianPackage:  libjpeg-dev
+URL:            http://www.libjpeg-turbo.org/
+                or http://www.ijg.org/ for the IJG version
+
+Package:        Libcaca
+Plugins:        cacasink
+DebianPackage:  libcaca-dev
+URL:            http://libcaca.zoy.org/
+
+Package:        Libdv
+Version:        >= 0.100
+DebianPackage:  libdv4-dev
+Plugins:        dv (dvdec)
+URL:            http://libdv.sourceforge.net/
+
+Package:	liblame
+Version:	>= 3.98
+DebianPackage:	libmp3lame-dev
+Plugins:	lame (lamemp3enc)
+URL:		http://www.mp3dev.org/mp3/
+
+Package:	libmpg123
+Version:        >= 1.3
+DebianPackage:  libpng12-dev
+Plugins:        mpg123 (mpg123audiodec)
+URL:		https://www.mpg123.de/api/
+
+Package:        Libpng
+Version:        >= 1.2
+DebianPackage:  libpng12-dev
+Plugins:        png (pngenc, pngdec)
+URL:            http://www.libpng.org/pub/png/libpng.html
+
+Package:        libraw1394
+Plugins:        dv1394
+URL:            http://www.linux1394.org/
+
+Package:        libshout
+Version:        >= 2.0
+DebianPackage:  libshout3-dev
+plugins:        shout2 (shout2send)
+URL:            http://www.icecast.org/
+
+Package:        speex
+Version:        >= 1.1.6
+Plugins:        speex (speexenc, speexdec)
+URL:            http://www.speex.org/
+
+Package:        taglib
+Version:        >= 1.5
+DebianPackage:  libtag1-dev
+Plugins:        taglib (id3v2mux)
+URL:            http://taglib.github.io/
+
+Package:	twolame
+Version:	>= 0.3.13
+DebianPackage:	libtwolame-dev
+Plugins:	twolame (twolamemp2enc)
+URL:		http://www.twolame.org
+
+Package:        zlib
+DebianPackage:  zlib1g-dev
+Plugins:        isomp4 (qtdemux), matroska (matroskademux)
+URL:            http://www.zlib.net/
+
+Optional (debian) packages:
+===========================
+
+gtk-doc-tools >= 1.12  -- needed to build documentation
+python-xml  -- needed to build plugin documentation
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..39af028
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,124 @@
+#!/bin/sh
+#
+# gst-plugins-good autogen.sh
+#
+# Run this to generate all the initial makefiles, etc.
+#
+# This file has been generated from common/autogen.sh.in via common/update-autogen
+
+
+test -n "$srcdir" || srcdir=`dirname "$0"`
+test -n "$srcdir" || srcdir=.
+
+olddir=`pwd`
+cd "$srcdir"
+
+package=gst-plugins-good
+srcfile=gst-plugins-good.doap
+
+# Make sure we have common
+if test ! -f common/gst-autogen.sh;
+then
+  echo "+ Setting up common submodule"
+  git submodule init
+fi
+git submodule update
+
+# source helper functions
+if test ! -f common/gst-autogen.sh;
+then
+  echo There is something wrong with your source tree.
+  echo You are missing common/gst-autogen.sh
+  exit 1
+fi
+. common/gst-autogen.sh
+
+# install pre-commit hook for doing clean commits
+if test ! \( -x .git/hooks/pre-commit -a -L .git/hooks/pre-commit \);
+then
+    rm -f .git/hooks/pre-commit
+    if ! ln -s ../../common/hooks/pre-commit.hook .git/hooks/pre-commit 2> /dev/null
+    then
+        echo "Failed to create commit hook symlink, copying instead ..."
+        cp common/hooks/pre-commit.hook .git/hooks/pre-commit
+    fi
+fi
+
+# GNU gettext automake support doesn't get along with git.
+# https://bugzilla.gnome.org/show_bug.cgi?id=661128
+if test -d po ; then
+  touch -t 200001010000 po/gst-plugins-good-1.0.pot
+fi
+
+CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-gtk-doc'
+
+if test "x$package" = "xgstreamer"; then
+  CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --enable-failing-tests --enable-poisoning"
+elif test "x$package" = "xgst-plugins-bad"; then
+  CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-player-tests"
+fi
+
+autogen_options $@
+
+printf "+ check for build tools"
+if test -z "$NOCHECK"; then
+  echo
+
+  printf "  checking for autoreconf ... "
+  echo
+  which "autoreconf" 2>/dev/null || {
+    echo "not found! Please install the autoconf package."
+    exit 1
+  }
+
+  printf "  checking for pkg-config ... "
+  echo
+  which "pkg-config" 2>/dev/null || {
+    echo "not found! Please install pkg-config."
+    exit 1
+  }
+else
+  echo ": skipped version checks"
+fi
+
+# if no arguments specified then this will be printed
+if test -z "$*" && test -z "$NOCONFIGURE"; then
+  echo "+ checking for autogen.sh options"
+  echo "  This autogen script will automatically run ./configure as:"
+  echo "  ./configure $CONFIGURE_DEF_OPT"
+  echo "  To pass any additional options, please specify them on the $0"
+  echo "  command line."
+fi
+
+toplevel_check $srcfile
+
+# autopoint
+if test -d po && grep ^AM_GNU_GETTEXT_VERSION configure.ac >/dev/null ; then
+  tool_run "autopoint" "--force"
+fi
+
+# aclocal
+if test -f acinclude.m4; then rm acinclude.m4; fi
+
+autoreconf --force --install || exit 1
+
+test -n "$NOCONFIGURE" && {
+  echo "+ skipping configure stage for package $package, as requested."
+  echo "+ autogen.sh done."
+  exit 0
+}
+
+cd "$olddir"
+
+echo "+ running configure ... "
+test ! -z "$CONFIGURE_DEF_OPT" && echo "  default flags:  $CONFIGURE_DEF_OPT"
+test ! -z "$CONFIGURE_EXT_OPT" && echo "  external flags: $CONFIGURE_EXT_OPT"
+echo
+
+echo "$srcdir/configure" $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT
+"$srcdir/configure" $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT || {
+        echo "  configure failed"
+        exit 1
+}
+
+echo "Now type 'make' to compile $package."
diff --git a/common b/common
new file mode 160000
index 0000000..3fa2c9e
--- /dev/null
+++ b/common
@@ -0,0 +1 @@
+Subproject commit 3fa2c9e372bceec30be91e67fb02b6cb05bed493
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..6b1ecf7
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,1128 @@
+AC_PREREQ([2.69])
+
+dnl please read gstreamer/docs/random/autotools before changing this file
+
+dnl initialize autoconf
+dnl releases only do -Wall, git and prerelease does -Werror too
+dnl use a three digit version number for releases, and four for git/pre
+AC_INIT([GStreamer Good Plug-ins],[1.13.0.1],[http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer],[gst-plugins-good])
+
+AG_GST_INIT
+
+dnl initialize automake
+AM_INIT_AUTOMAKE([-Wno-portability 1.14 no-dist-gzip dist-xz tar-ustar subdir-objects])
+
+dnl define PACKAGE_VERSION_* variables
+AS_VERSION
+
+dnl check if this is a release version
+AS_NANO(GST_GIT="no", GST_GIT="yes")
+
+dnl can autoconf find the source ?
+AC_CONFIG_SRCDIR([gst/law/alaw.c])
+
+dnl define the output header for config
+AC_CONFIG_HEADERS([config.h])
+
+dnl AM_MAINTAINER_MODE only provides the option to configure to enable it
+AM_MAINTAINER_MODE([enable])
+
+dnl sets host_* variables
+AC_CANONICAL_HOST
+
+dnl use pretty build output with automake >= 1.11
+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],
+  [AM_DEFAULT_VERBOSITY=1
+   AC_SUBST(AM_DEFAULT_VERBOSITY)])
+
+dnl our libraries and install dirs use GST_API_VERSION in the filename
+dnl to allow side-by-side installation of different API versions
+GST_API_VERSION=1.0
+AC_SUBST(GST_API_VERSION)
+AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION",
+  [GStreamer API Version])
+
+AG_GST_LIBTOOL_PREPARE
+AS_LIBTOOL(GST, 1300, 0, 1300)
+
+dnl *** required versions of GStreamer stuff ***
+GST_REQ=1.13.0.1
+GSTPB_REQ=1.13.0.1
+
+dnl *** autotools stuff ****
+
+dnl allow for different autotools
+AS_AUTOTOOLS_ALTERNATE
+
+dnl Add parameters for aclocal
+AC_SUBST(ACLOCAL_AMFLAGS, "-I m4 -I common/m4")
+
+dnl set up gettext
+dnl the version check needs to stay here because autopoint greps for it
+AM_GNU_GETTEXT_VERSION([0.17])
+AM_GNU_GETTEXT([external])
+AG_GST_GETTEXT([gst-plugins-good-$GST_API_VERSION])
+
+dnl *** check for arguments to configure ***
+
+AG_GST_ARG_DISABLE_FATAL_WARNINGS
+AG_GST_ARG_ENABLE_EXTRA_CHECKS
+
+AG_GST_ARG_DEBUG
+AG_GST_ARG_PROFILING
+AG_GST_ARG_VALGRIND
+AG_GST_ARG_GCOV
+
+AG_GST_ARG_EXAMPLES
+
+AG_GST_ARG_WITH_PKG_CONFIG_PATH
+AG_GST_ARG_WITH_PACKAGE_NAME
+AG_GST_ARG_WITH_PACKAGE_ORIGIN
+
+AG_GST_ARG_WITH_PLUGINS
+
+AG_GST_ARG_ENABLE_EXTERNAL
+
+AG_GST_ARG_ENABLE_EXPERIMENTAL
+
+AG_GST_PKG_CONFIG_PATH
+
+dnl *** checks for platform ***
+
+dnl * hardware/architecture *
+
+dnl common/m4/gst-arch.m4
+dnl check CPU type
+AG_GST_ARCH
+
+dnl Determine endianness
+AC_C_BIGENDIAN
+
+dnl *** checks for programs ***
+
+dnl find a compiler
+AC_PROG_CC
+AC_PROG_CC_STDC
+
+dnl determine c++ compiler
+AC_PROG_CXX
+dnl determine if c++ is available on this system
+AC_CHECK_PROG(HAVE_CXX, $CXX, yes, no)
+
+dnl determine c++ preprocessor
+dnl FIXME: do we need this ?
+AC_PROG_CXXCPP
+
+AC_PROG_OBJC
+
+dnl check if the compiler supports '-c' and '-o' options
+AM_PROG_CC_C_O
+
+dnl find an assembler
+AM_PROG_AS
+
+dnl check if the compiler supports do while(0) macros
+AG_GST_CHECK_DOWHILE_MACROS
+
+AC_PATH_PROG(VALGRIND_PATH, valgrind, no)
+AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno")
+
+dnl check for documentation tools
+GTK_DOC_CHECK([1.12])
+AG_GST_PLUGIN_DOCS([1.12])
+
+dnl *** checks for libraries ***
+
+dnl check for libm, for sin()
+LT_LIB_M
+AC_SUBST(LIBM)
+
+AC_CHECK_FUNCS(clock_gettime, [], [
+  AC_CHECK_LIB(rt, clock_gettime, [
+    AC_DEFINE(HAVE_CLOCK_GETTIME, 1)
+    LIBRT="-lrt"
+    AC_SUBST([LIBRT])
+  ])
+])
+
+dnl check for pthreads
+AX_PTHREAD
+
+dnl *** checks for header files ***
+
+dnl check if we have ANSI C header files
+AC_HEADER_STDC
+
+dnl used by ext/wavpack
+AX_CREATE_STDINT_H
+
+dnl used in gst/udp
+AC_CHECK_HEADERS([sys/time.h])
+
+dnl used in gst/udp
+AC_CHECK_HEADERS([sys/socket.h])
+
+dnl *** checks for types/defines ***
+
+dnl Check for FIONREAD ioctl declaration.  This check is needed
+dnl for the UDP plugin to build on Solaris
+GST_CHECK_FIONREAD
+
+dnl *** checks for structures ***
+
+dnl *** checks for compiler characteristics ***
+
+dnl check if we have GCC inline-asm
+AS_GCC_INLINE_ASSEMBLY([HAVE_GCC_ASM=yes], [HAVE_GCC_ASM=no])
+if test x$HAVE_GCC_ASM = xyes ; then
+  AC_DEFINE(HAVE_GCC_ASM, 1,
+    [Define if compiler supports gcc inline assembly])
+fi
+AM_CONDITIONAL(HAVE_GCC_ASM, test "x$HAVE_GCC_ASM" = "xyes")
+
+dnl *** checks for library functions ***
+
+LIBS_SAVE=$LIBS
+LIBS="$LIBS $LIBM"
+AC_CHECK_FUNCS(rint sinh cosh asinh fpclass)
+LIBS=$LIBS_SAVE
+
+dnl Check whether isinf() is defined by math.h
+AC_CACHE_CHECK([for isinf], ac_cv_have_isinf,
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <math.h>]], [[float f = 0.0; int i=isinf(f)]])],[ac_cv_have_isinf="yes"],[ac_cv_have_isinf="no"]))
+if test "$ac_cv_have_isinf" = "yes"
+then
+    AC_DEFINE(HAVE_ISINF, 1, [Define to 1 if you have the `isinf' function.])
+fi
+
+dnl Check for mmap (needed by electricfence plugin)
+AC_FUNC_MMAP
+AC_CHECK_SIZEOF([off_t])
+AM_CONDITIONAL(GST_HAVE_MMAP, test "x$ac_cv_func_mmap_fixed_mapped" = "xyes")
+
+dnl Check for mmap (needed by electricfence plugin)
+
+AC_CHECK_TYPE([struct ip_mreqn], [
+              AC_DEFINE(HAVE_IP_MREQN,, [Define if we have struct ip_mreqn])],,
+              [#include <netinet/in.h>])
+
+dnl *** checks for dependency libraries ***
+
+
+dnl GLib
+GLIB_REQ=2.40.0
+AG_GST_GLIB_CHECK([$GLIB_REQ])
+
+dnl Orc
+ORC_CHECK([0.4.17])
+
+dnl checks for gstreamer
+dnl uninstalled is selected preferentially -- see pkg-config(1)
+AG_GST_CHECK_GST($GST_API_VERSION, [$GST_REQ], yes)
+AG_GST_CHECK_GST_BASE($GST_API_VERSION, [$GST_REQ], yes)
+AG_GST_CHECK_GST_CONTROLLER($GST_API_VERSION, [$GST_REQ], yes)
+AG_GST_CHECK_GST_NET($GST_API_VERSION, [$GST_REQ], yes)
+AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no)
+AG_GST_CHECK_GST_PLUGINS_BASE($GST_API_VERSION, [$GSTPB_REQ], yes)
+
+GST_TOOLS_DIR=`$PKG_CONFIG --variable=toolsdir gstreamer-$GST_API_VERSION`
+if test -z $GST_TOOLS_DIR; then
+  AC_MSG_ERROR([no tools dir defined in GStreamer pkg-config file; core upgrade needed.])
+fi
+AC_SUBST(GST_TOOLS_DIR)
+
+AC_MSG_NOTICE(Using GStreamer Core Plugins in $GST_PLUGINS_DIR)
+AC_MSG_NOTICE(Using GStreamer Base Plugins in $GSTPB_PLUGINS_DIR)
+
+AM_CONDITIONAL(HAVE_GST_CHECK, test "x$HAVE_GST_CHECK" = "xyes")
+
+dnl Check for documentation xrefs
+GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`"
+GST_PREFIX="`$PKG_CONFIG --variable=prefix gstreamer-$GST_API_VERSION`"
+GSTPB_PREFIX="`$PKG_CONFIG --variable=prefix gstreamer-plugins-base-$GST_API_VERSION`"
+AC_SUBST(GLIB_PREFIX)
+AC_SUBST(GST_PREFIX)
+AC_SUBST(GSTPB_PREFIX)
+
+dnl GTK is optional and used in examples
+HAVE_GTK=no
+GTK_REQ=3.0.0
+if test "x$BUILD_EXAMPLES" = "xyes"; then
+  PKG_CHECK_MODULES(GTK, gtk+-3.0 >= $GTK_REQ, HAVE_GTK=yes, HAVE_GTK=no)
+  dnl some examples need gtk+-x11
+  PKG_CHECK_MODULES(GTK_X11, gtk+-x11-3.0 >= $GTK_REQ, HAVE_GTK_X11=yes, HAVE_GTK_X11=no)
+  AC_SUBST(GTK_LIBS)
+  AC_SUBST(GTK_CFLAGS)
+fi
+AM_CONDITIONAL(HAVE_GTK, test "x$HAVE_GTK" = "xyes")
+AM_CONDITIONAL(HAVE_GTK_X11, test "x$HAVE_GTK_X11" = "xyes")
+
+dnl Check for -Bsymbolic-functions linker flag used to avoid
+dnl intra-library PLT jumps, if available.
+AC_ARG_ENABLE(Bsymbolic,
+              [AS_HELP_STRING([--disable-Bsymbolic],[avoid linking with -Bsymbolic])],,
+              [SAVED_LDFLAGS="${LDFLAGS}" SAVED_LIBS="${LIBS}"
+               AC_MSG_CHECKING([for -Bsymbolic-functions linker flag])
+               LDFLAGS=-Wl,-Bsymbolic-functions
+               LIBS=
+               AC_TRY_LINK([], [return 0],
+                           AC_MSG_RESULT(yes)
+                           enable_Bsymbolic=yes,
+                           AC_MSG_RESULT(no)
+                           enable_Bsymbolic=no)
+               LDFLAGS="${SAVED_LDFLAGS}" LIBS="${SAVED_LIBS}"])
+
+dnl *** set variables based on configure arguments ***
+
+dnl set license and copyright notice
+GST_LICENSE="LGPL"
+AC_DEFINE_UNQUOTED(GST_LICENSE, "$GST_LICENSE", [GStreamer license])
+AC_SUBST(GST_LICENSE)
+
+dnl set location of plugin directory
+AG_GST_SET_PLUGINDIR
+
+dnl set release date/time
+AG_GST_SET_PACKAGE_RELEASE_DATETIME_WITH_NANO([$PACKAGE_VERSION_NANO],
+  ["${srcdir}/gst-plugins-good.doap"],
+  [$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR.$PACKAGE_VERSION_MICRO])
+
+# set by AG_GST_PARSE_SUBSYSTEM_DISABLES above
+dnl make sure it doesn't complain about unused variables if debugging is disabled
+NO_WARNINGS=""
+AG_GST_CHECK_GST_DEBUG_DISABLED([NO_WARNINGS="-Wno-unused"], [NO_WARNINGS=""])
+
+dnl define an ERROR_CFLAGS Makefile variable
+dnl -Wundef: too many broken headers
+AG_GST_SET_ERROR_CFLAGS($FATAL_WARNINGS, [
+      -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls
+      -Wwrite-strings -Wold-style-definition -Waggregate-return
+      -Winit-self -Wmissing-include-dirs -Waddress -Wno-multichar
+      -Wnested-externs $NO_WARNINGS])
+
+dnl define an ERROR_CXXFLAGS Makefile variable
+AG_GST_SET_ERROR_CXXFLAGS($FATAL_WARNINGS, [
+        -Wmissing-declarations -Wredundant-decls
+        -Wwrite-strings
+        -Winit-self -Wmissing-include-dirs -Waddress -Wno-multichar
+        $NO_WARNINGS])
+
+dnl define an ERROR_OBJCFLAGS Makefile variable
+AG_GST_SET_ERROR_OBJCFLAGS($FATAL_WARNINGS, [
+      -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls
+      -Wwrite-strings -Wold-style-definition
+      -Winit-self -Wmissing-include-dirs -Wno-multichar
+      -Wnested-externs $NO_WARNINGS])
+
+dnl define correct level for debugging messages
+AG_GST_SET_LEVEL_DEFAULT($GST_GIT)
+
+dnl used in examples
+AG_GST_DEFAULT_ELEMENTS
+
+dnl *** plug-ins to include ***
+
+dnl these are all the gst plug-ins, compilable without additional libs
+dnl videofilter is at the top because others depend on it
+AG_GST_CHECK_PLUGIN(alpha)
+AG_GST_CHECK_PLUGIN(apetag)
+AG_GST_CHECK_PLUGIN(audiofx)
+AG_GST_CHECK_PLUGIN(audioparsers)
+AG_GST_CHECK_PLUGIN(auparse)
+AG_GST_CHECK_PLUGIN(autodetect)
+AG_GST_CHECK_PLUGIN(avi)
+AG_GST_CHECK_PLUGIN(cutter)
+AG_GST_CHECK_PLUGIN(debugutils)
+AG_GST_CHECK_PLUGIN(deinterlace)
+AG_GST_CHECK_PLUGIN(dtmf)
+AG_GST_CHECK_PLUGIN(effectv)
+AG_GST_CHECK_PLUGIN(equalizer)
+AG_GST_CHECK_PLUGIN(flv)
+AG_GST_CHECK_PLUGIN(flx)
+AG_GST_CHECK_PLUGIN(goom)
+AG_GST_CHECK_PLUGIN(goom2k1)
+AG_GST_CHECK_PLUGIN(icydemux)
+AG_GST_CHECK_PLUGIN(id3demux)
+AG_GST_CHECK_PLUGIN(imagefreeze)
+AG_GST_CHECK_PLUGIN(interleave)
+AG_GST_CHECK_PLUGIN(isomp4)
+AG_GST_CHECK_PLUGIN(law)
+AG_GST_CHECK_PLUGIN(level)
+AG_GST_CHECK_PLUGIN(matroska)
+AG_GST_CHECK_PLUGIN(monoscope)
+AG_GST_CHECK_PLUGIN(multifile)
+AG_GST_CHECK_PLUGIN(multipart)
+AG_GST_CHECK_PLUGIN(replaygain)
+AG_GST_CHECK_PLUGIN(rtp)
+AG_GST_CHECK_PLUGIN(rtpmanager)
+AG_GST_CHECK_PLUGIN(rtsp)
+AG_GST_CHECK_PLUGIN(shapewipe)
+AG_GST_CHECK_PLUGIN(smpte)
+AG_GST_CHECK_PLUGIN(spectrum)
+AG_GST_CHECK_PLUGIN(udp)
+AG_GST_CHECK_PLUGIN(videobox)
+AG_GST_CHECK_PLUGIN(videocrop)
+AG_GST_CHECK_PLUGIN(videofilter)
+AG_GST_CHECK_PLUGIN(videomixer)
+AG_GST_CHECK_PLUGIN(wavenc)
+AG_GST_CHECK_PLUGIN(wavparse)
+AG_GST_CHECK_PLUGIN(y4m)
+
+dnl disable experimental plug-ins
+if test "x$BUILD_EXPERIMENTAL" != "xyes"; then
+  AG_GST_DISABLE_PLUGIN(monoscope)
+fi
+
+dnl *** sys plug-ins ***
+
+echo
+AC_MSG_NOTICE([Checking libraries for plugins in sys/])
+echo
+
+dnl DirectSound
+translit(dnm, m, l) AM_CONDITIONAL(USE_DIRECTSOUND, true)
+AG_GST_CHECK_FEATURE(DIRECTSOUND, [DirectSound plug-in], directsoundsink, [
+  HAVE_DIRECTSOUND="no"
+  save_CFLAGS="$CFLAGS"
+  save_LDFLAGS="$LDFLAGS"
+  save_LIBS="$LIBS"
+  CFLAGS="$CFLAGS $DIRECTSOUND_CFLAGS"
+  LDFLAGS="$LDFLAGS $DIRECTSOUND_LDFLAGS"
+  LIBS="$LIBS -ldsound -ldxerr9 -luser32 -lole32"
+  AC_MSG_CHECKING(for DirectSound LDFLAGS)
+  AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#include <windows.h>
+#include <dxerr9.h>
+#include <dsound.h>
+]], [[
+  DXGetErrorString9 (0);
+  DirectSoundCreate(NULL, NULL, NULL);
+  CLSIDFromString(NULL, NULL);
+]])
+],
+    [HAVE_DIRECTSOUND="yes"],
+    [HAVE_DIRECTSOUND="no"])
+  AC_MSG_RESULT($HAVE_DIRECTSOUND)
+  CFLAGS=$save_CFLAGS
+  LDFLAGS=$save_LDFLAGS
+  LIBS=$save_LIBS
+
+  if test "x$HAVE_DIRECTSOUND" = "xyes";  then
+    dnl this is much more than we want
+    DIRECTSOUND_LIBS="-ldsound -ldxerr9 -luser32 -lole32"
+    AC_SUBST(DIRECTSOUND_CFLAGS)
+    AC_SUBST(DIRECTSOUND_LDFLAGS)
+    AC_SUBST(DIRECTSOUND_LIBS)
+  fi
+  AC_SUBST(HAVE_DIRECTSOUND)
+])
+
+dnl *** Win32 WaveOut ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_WAVEFORM, true)
+AG_GST_CHECK_FEATURE(WAVEFORM, [Win32 WaveForm], waveformsink, [
+  AC_CHECK_HEADER(mmsystem.h, HAVE_WAVEFORM="yes", HAVE_WAVEFORM="no", [#include <windows.h>])
+])
+
+dnl *** OSS audio *** (Linux, *BSD)
+translit(dnm, m, l) AM_CONDITIONAL(USE_OSS, true)
+AG_GST_CHECK_FEATURE(OSS, [OSS audio], ossaudio, [
+ HAVE_OSS="yes"
+dnl Linux and newer BSD versions :
+ AC_CHECK_HEADER(sys/soundcard.h, [
+   AC_DEFINE(HAVE_OSS_INCLUDE_IN_SYS,, [Define if OSS includes are in /sys/])
+   ] , [
+dnl Some old BSD versions and also newer OpenBSD versions :
+   AC_CHECK_HEADER(soundcard.h, [
+     AC_DEFINE(HAVE_OSS_INCLUDE_IN_ROOT,, [Define if OSS includes are in /])
+     ], [
+  dnl Some old BSD versions :
+     AC_CHECK_HEADER(machine/soundcard.h, [
+       AC_DEFINE(HAVE_OSS_INCLUDE_IN_MACHINE,,
+         [Define if OSS includes are in /machine/])
+       ], [
+       HAVE_OSS="no"
+     ])
+   ])
+ ])
+])
+
+dnl *** oss4 ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_OSS4, true)
+AG_GST_CHECK_FEATURE(OSS4, [Open Sound System 4], oss4, [
+  AC_MSG_CHECKING([Checking if we can build the OSS4 elements])
+  AC_CHECK_HEADERS([fcntl.h sys/ioctl.h sys/stat.h sys/types.h],
+      [test -z "$OSS4_MISSING_HEADER" && HAVE_OSS4="yes"],
+      [OSS4_MISSING_HEADER="yes";HAVE_OSS4="no"])
+])
+
+dnl *** OSX Audio ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_OSX_AUDIO, true)
+HAVE_IOS="no"
+AG_GST_CHECK_FEATURE(OSX_AUDIO, [OSX audio], osxaudio, [
+  AC_CHECK_HEADER(CoreAudio/CoreAudio.h,
+    [HAVE_OSX_AUDIO="yes"],
+    [AC_CHECK_HEADER(CoreAudio/CoreAudioTypes.h,
+    [
+      HAVE_OSX_AUDIO="yes"
+      HAVE_IOS="yes"
+    ], [
+      HAVE_OSX_AUDIO="no"
+      HAVE_IOS="no"
+    ])]
+  )
+])
+if test "x$HAVE_IOS" = "xyes"; then
+  AC_DEFINE(HAVE_IOS, 1, [building for iOS platofrm])
+fi
+AM_CONDITIONAL(HAVE_IOS, test "x$HAVE_IOS" = "xyes")
+
+dnl *** OS X video ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_OSX_VIDEO, true)
+HAVE_OSX_VIDEO="no"
+AG_GST_CHECK_FEATURE(OSX_VIDEO, [OSX video], osxvideosink, [
+  AC_CHECK_HEADER(OpenGL/gl.h, HAVE_OSX_VIDEO="yes", HAVE_OSX_VIDEO="no")
+
+  dnl in case header OpenGL/gl.h is found on other platforms (or older, unsupported OS X)
+  dnl also require Snow Leopard or newer
+
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+        #include <AvailabilityMacros.h>
+        #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+        #error Too old OSX version
+        #endif
+      ]], [[return 0;]])],[HAVE_OSX_VIDEO="yes"],[HAVE_OSX_VIDEO="no"])
+])
+
+dnl *** Video 4 Linux 2 ***
+dnl renamed to GST_V4L2 because of some conflict with kernel headers
+translit(dnm, m, l) AM_CONDITIONAL(USE_GST_V4L2, true)
+HAVE_GST_V4L2=no
+AG_GST_CHECK_FEATURE(GST_V4L2, [Video 4 Linux 2], video4linux2, [
+  AC_MSG_CHECKING([Checking for video4linux2 header ...])
+  AC_CHECK_HEADER(linux/videodev2.h, [ HAVE_GST_V4L2=yes ],
+  [
+    AC_CHECK_HEADER(sys/videodev2.h, [ HAVE_GST_V4L2=yes ],
+    [
+      AC_CHECK_HEADER(sys/videoio.h, [ HAVE_GST_V4L2=yes ])
+    ])
+  ])
+  if test "x$HAVE_VIDEODEV" = "xno"; then
+     AC_MSG_WARN([video4linux2 was not found])
+  fi
+])
+
+# Optional gudev for device probing
+AC_ARG_WITH([gudev],
+  AS_HELP_STRING([--with-gudev],[device detection with gudev]),
+  [],
+  [with_gudev=check])
+if test x$HAVE_GST_V4L2 = xyes; then
+  if test x$with_gudev != xno; then
+    PKG_CHECK_MODULES(GUDEV, [ gudev-1.0 >= 147 ],
+      [ AC_DEFINE(HAVE_GUDEV, 1,
+          [Whether gudev is available for device detection])
+      ],
+      [true])
+  fi
+fi
+
+AC_SUBST(GUDEV_CFLAGS)
+AC_SUBST(GUDEV_LIBS)
+
+# Make libv4l2 non-automagic
+AC_ARG_WITH([libv4l2],
+  AS_HELP_STRING([--with-libv4l2],[support video buffer conversion using libv4l2]),
+  [],
+  [with_libv4l2=check])
+if test x$HAVE_GST_V4L2 = xyes; then
+  if test x$with_libv4l2 != xno; then
+      PKG_CHECK_MODULES(LIBV4L2, libv4l2,
+          [ have_libv4l2=yes
+            AC_DEFINE(HAVE_LIBV4L2, 1,
+	        [Whether libv4l2 is available for video buffer conversion])
+          ], [
+          have_libv4l2=no
+          ])
+  else
+    have_libv4l2=no
+  fi
+fi
+
+dnl Allow enabling v4l2 device probing
+AS_CASE([$host],
+    [*-*linux*],
+      [AS_CASE([$host_cpu],
+        [arm*], [
+          enable_v4l2_probe="yes"],
+        [aarch64*], [
+          enable_v4l2_probe="yes"])])
+AC_ARG_ENABLE(
+  v4l2-probe,
+  AC_HELP_STRING(
+    [--enable-v4l2-probe],
+    [enable V4L2 plugin to probe devices @<:@default=no@:>@]))
+if test "x$enable_v4l2_probe" = "xyes"; then
+  AC_DEFINE(GST_V4L2_ENABLE_PROBE, 1,
+    [Define if Video4Linux probe shall be run at plugin load])
+fi
+
+dnl Check for X11
+translit(dnm, m, l) AM_CONDITIONAL(USE_X, true)
+AG_GST_CHECK_FEATURE(X, [X libraries and plugins],
+                  [ximagesrc], [
+  PKG_CHECK_MODULES([X], [x11], [
+    HAVE_X="yes"
+    dnl check for Xfixes
+    PKG_CHECK_MODULES([XFIXES], [ xfixes ], [
+      AC_DEFINE(HAVE_XFIXES, 1, [Defined if Xfixes is available])
+    ], [ HAVE_XFIXES="no" ])
+
+    dnl check for Xdamage
+    PKG_CHECK_MODULES([XDAMAGE], [ xdamage ], [
+      AC_DEFINE(HAVE_XDAMAGE, 1, [Defined if Xdamage is available])
+    ], [ HAVE_XDAMAGE="no" ])
+
+    dnl check for X Shm
+    PKG_CHECK_MODULES([XEXT], [ xext ], [
+      AC_CHECK_LIB([Xext], [ XShmAttach ], [
+        AC_DEFINE(HAVE_XSHM, 1, [Defined if XShm is available])
+        XSHM_LIBS="$XEXT_LIBS"
+        XSHM_CFLAGS="$XEXT_CFLAGS"
+      ], [ HAVE_XEXT="no" ] , [ $X_LIBS ])
+    ])
+    AC_SUBST(XSHM_LIBS)
+    AC_SUBST(XSHM_CFLAGS)
+  ], [ HAVE_X="no" ])
+])
+
+dnl *** ext plug-ins ***
+dnl keep this list sorted alphabetically !
+
+if test "x$BUILD_EXTERNAL" = "xyes"; then
+
+echo
+AC_MSG_NOTICE([Checking libraries for plugins in ext/])
+echo
+
+dnl *** aalib ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_AALIB, true)
+AG_GST_CHECK_FEATURE(AALIB, [aalib ASCII Art library], aasink, [
+  AM_PATH_AALIB(, HAVE_AALIB=yes, HAVE_AALIB=no)
+])
+
+dnl *** cairo ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_CAIRO, true)
+AG_GST_CHECK_FEATURE(CAIRO, [Cairo graphics rendering and gobject bindings], cairo, [
+  AG_GST_PKG_CHECK_MODULES(CAIRO, cairo >= 1.10.0 cairo-gobject >= 1.10.0)
+])
+
+dnl *** FLAC ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_FLAC, true)
+AG_GST_CHECK_FEATURE(FLAC, [FLAC lossless audio], flac, [
+  AG_GST_PKG_CHECK_MODULES(FLAC, flac >= 1.1.4)
+])
+
+dnl *** GDK pixbuf ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_GDK_PIXBUF, true)
+AG_GST_CHECK_FEATURE(GDK_PIXBUF, [GDK pixbuf], gdkpixbuf, [
+  AG_GST_PKG_CHECK_MODULES(GDK_PIXBUF, gdk-pixbuf-2.0 >= 2.8.0)
+])
+
+dnl *** Jack ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_JACK, true)
+AG_GST_CHECK_FEATURE(JACK, Jack, jack, [
+  PKG_CHECK_MODULES(JACK, jack >= 0.99.10, HAVE_JACK="yes", HAVE_JACK="no")
+  AC_SUBST(JACK_CFLAGS)
+  AC_SUBST(JACK_LIBS)
+
+  AG_GST_PKG_CHECK_MODULES(JACK_0_120_1, jack >= 0.120.1 jack < 1.0)
+  if test x$HAVE_JACK_0_120_1 = xyes; then
+    AC_DEFINE(HAVE_JACK_0_120_1, 1, [defined if jack >= 0.120.1 is available])
+  fi
+  AG_GST_PKG_CHECK_MODULES(JACK_1_9_7, jack >= 1.9.7)
+  if test x$HAVE_JACK_1_9_7 = xyes; then
+    AC_DEFINE(HAVE_JACK_1_9_7, 1, [defined if jack >= 1.9.7 is available])
+  fi
+
+])
+
+dnl *** jpeg ***
+dnl FIXME: we could use header checks here as well IMO
+translit(dnm, m, l) AM_CONDITIONAL(USE_JPEG, true)
+AG_GST_CHECK_FEATURE(JPEG, [jpeg library], jpeg, [
+  AC_ARG_WITH(jpeg-mmx,
+    [  --with-jpeg-mmx, path to MMX'ified JPEG library])
+  OLD_LIBS="$LIBS"
+  if test x$with_jpeg_mmx != x; then
+    LIBS="$LIBS -L$with_jpeg_mmx"
+  fi
+  AC_CHECK_LIB(jpeg-mmx, jpeg_set_defaults, HAVE_JPEG="yes", HAVE_JPEG="no")
+  JPEG_LIBS="$LIBS -ljpeg-mmx"
+  LIBS="$OLD_LIBS"
+  if test x$HAVE_JPEG != xyes; then
+    AC_CHECK_LIB(jpeg, jpeg_set_defaults, HAVE_JPEG="yes", HAVE_JPEG="no")
+    JPEG_LIBS="-ljpeg"
+  fi
+  AC_SUBST(JPEG_LIBS)
+])
+
+dnl *** lame ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_LAME, true)
+AG_GST_CHECK_FEATURE(LAME, [lame mp3 encoder library], lame, [
+  AG_GST_CHECK_LIBHEADER(LAME, mp3lame, lame_init, $LIBM, lame/lame.h,
+  [
+    HAVE_LAME="yes"
+    LAME_LIBS="-lmp3lame $LIBM"
+    dnl is lame presets available
+    LAME_CFLAGS=""
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <lame/lame.h>]], [[ int preset = MEDIUM ]])],[LAME_CFLAGS="-DGSTLAME_PRESET"],[LAME_CFLAGS=""
+    ])
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <lame/lame.h>]], [[
+        void *ptr = &lame_set_VBR_quality
+      ]])],[LAME_CFLAGS="$LAME_CFLAGS -DHAVE_LAME_SET_VBR_QUALITY"],[LAME_CFLAGS="$LAME_CFLAGS"
+    ])
+  AC_SUBST(LAME_CFLAGS)
+  AC_SUBST(LAME_LIBS)
+  ])
+])
+
+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 *** libdv ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_LIBDV, true)
+AG_GST_CHECK_FEATURE(LIBDV, [libdv DV demuxer/decoder], dv, [
+  AG_GST_PKG_CHECK_MODULES(LIBDV, libdv >= 0.100)
+])
+
+dnl *** libpng ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_LIBPNG, true)
+AG_GST_CHECK_FEATURE(LIBPNG, [Portable Network Graphics library], png, [
+  AG_GST_PKG_CHECK_MODULES(LIBPNG, libpng >= 1.2)
+  if test $HAVE_LIBPNG = "yes"; then
+    PKG_CHECK_MODULES(LIBPNG_1_5, libpng >= 1.5.1, [
+        AC_DEFINE(HAVE_LIBPNG_1_5, 1, [Defined if libpng version is 1.5.1 or newer])
+      ], [true])
+  fi
+])
+
+dnl *** mpg123 ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_MPG123, true)
+AG_GST_CHECK_FEATURE(MPG123, [mpg123 audio decoder], mpg123, [
+  PKG_CHECK_MODULES(MPG123, libmpg123 >= 1.13, HAVE_MPG123="yes", HAVE_MPG123="no")
+  AC_SUBST(MPG123_CFLAGS)
+  AC_SUBST(MPG123_LIBS)
+])
+
+dnl *** pulseaudio ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_PULSE, true)
+AG_GST_CHECK_FEATURE(PULSE, [pulseaudio plug-in], pulseaudio, [
+
+  dnl used in ext/pulse/pulseutil.c
+  AC_CHECK_HEADERS([process.h])
+
+  AG_GST_PKG_CHECK_MODULES(PULSE, libpulse >= 2.0)
+])
+
+dnl *** dv1394 ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_DV1394, true)
+AG_GST_CHECK_FEATURE(DV1394, [raw1394 and avc1394 library], 1394, [
+  dnl first test for libraw1394 >= 2.0.0
+  AG_GST_PKG_CHECK_MODULES(RAW1394, libraw1394 >= 2.0.0)
+  AG_GST_PKG_CHECK_MODULES(LIBIEC61883, libiec61883 >= 1.0.0)
+  dnl now see how far we got
+  if test x$HAVE_RAW1394 = xyes && \
+     test x$HAVE_LIBIEC61883 = xyes; then
+       AG_GST_CHECK_LIBHEADER(AVC1394,
+        avc1394, avc1394_send_command, $RAW1394_LIBS,
+	libavc1394/avc1394.h, AVC1394_LIBS="-lavc1394")
+       AG_GST_CHECK_LIBHEADER(ROM1394,
+        rom1394, rom1394_free_directory, $RAW1394_LIBS,
+        libavc1394/rom1394.h, ROM1394_LIBS="-lrom1394")
+       if test x$HAVE_AVC1394 = xyes && \
+          test x$HAVE_AVC1394 = xyes && \
+	  test x$HAVE_ROM1394 = xyes; then
+	  HAVE_DV1394=yes
+          DV1394_LIBS="$RAW1394_LIBS $AVC1394_LIBS $ROM1394_LIBS $LIBIEC61883_LIBS"
+          DV1394_CFLAGS="$RAW1394_CFLAGS $LIBIEC61883_CFLAGS -DHAVE_LIBIEC61883"
+          AC_SUBST(DV1394_CFLAGS)
+          AC_SUBST(DV1394_LIBS)
+	fi
+  else
+       if test x$HAVE_RAW1394 = xno; then
+	  AG_GST_PKG_CHECK_MODULES(RAW1394, libraw1394 >= 1.1.0)
+	  AG_GST_CHECK_LIBHEADER(AVC1394,
+	   avc1394, avc1394_send_command, $RAW1394_LIBS,
+	   libavc1394/avc1394.h, AVC1394_LIBS="-lavc1394")
+	  AG_GST_CHECK_LIBHEADER(ROM1394,
+	   rom1394, rom1394_free_directory, $RAW1394_LIBS,
+	   libavc1394/rom1394.h, ROM1394_LIBS="-lrom1394")
+          if test x$HAVE_RAW1394 = xyes && \
+	     test x$HAVE_AVC1394 = xyes && \
+	     test x$HAVE_ROM1394 = xyes; then
+	     HAVE_DV1394=yes
+	     DV1394_LIBS="$RAW1394_LIBS $AVC1394_LIBS $ROM1394_LIBS"
+	     DV1394_CFLAGS="$RAW1394_CFLAGS"
+	     if test x$HAVE_LIBIEC61883 = xyes; then
+	       DV1394_CFLAGS="$RAW1394_CFLAGS $LIBIEC61883_CFLAGS -DHAVE_LIBIEC61883"
+	       DV1394_LIBS="$DV1394_LIBS $LIBIEC61883_LIBS"
+	     fi
+             AC_SUBST(DV1394_CFLAGS)
+             AC_SUBST(DV1394_LIBS)
+           fi
+	 fi
+  fi
+])
+AM_CONDITIONAL(USE_LIBIEC61883, [ test "x${HAVE_LIBIEC61883}" = xyes ] )
+
+dnl *** shout2 ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_SHOUT2, true)
+AG_GST_CHECK_FEATURE(SHOUT2, [Shoutcast/Icecast client library], shout2, [
+  AG_GST_PKG_CHECK_MODULES(SHOUT2, shout >= 2.0)
+])
+
+dnl *** soup ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_SOUP, true)
+AG_GST_CHECK_FEATURE(SOUP, [soup http client plugin (2.4)], souphttpsrc, [
+  PKG_CHECK_MODULES(SOUP, libsoup-2.4 >= 2.48, [HAVE_SOUP="yes"], [HAVE_SOUP="no"])
+  AC_SUBST(SOUP_CFLAGS)
+  AC_SUBST(SOUP_LIBS)
+])
+
+dnl *** speex ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_SPEEX, true)
+AG_GST_CHECK_FEATURE(SPEEX, [speex speech codec], speex, [
+  AG_GST_PKG_CHECK_MODULES(SPEEX, speex >= 1.1.6)
+])
+
+dnl *** taglib ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_TAGLIB, true)
+AG_GST_CHECK_FEATURE(TAGLIB, [taglib tagging library], taglib, [
+  AG_GST_PKG_CHECK_MODULES(TAGLIB, taglib >= 1.5)
+  if test "x$HAVE_CXX" != "xyes"; then
+    USE_TAGLIB=false
+    AC_MSG_NOTICE([Not building taglib plugin: no C++ compiler found])
+  else
+    dnl work around bug in taglib 1.5 headers, remove once there is a 1.6
+    AS_CXX_COMPILER_FLAG([-Wno-attributes], [
+        TAGLIB_CXXFLAGS="$TAGLIB_CFLAGS -Wno-attributes"
+      ], [
+        TAGLIB_CXXFLAGS="$TAGLIB_CFLAGS"
+    ])
+    AC_SUBST(TAGLIB_CXXFLAGS)
+  fi
+])
+
+dnl *** twolame ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_TWOLAME, true)
+AG_GST_CHECK_FEATURE(TWOLAME, [twolame], twolame, [
+  PKG_CHECK_MODULES(TWOLAME, twolame >= 0.3.10, [
+      HAVE_TWOLAME="yes"], [
+      HAVE_TWOLAME="no"
+  ])
+  AC_SUBST(TWOLAME_CFLAGS)
+  AC_SUBST(TWOLAME_LIBS)
+])
+
+
+dnl *** vpx ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_VPX, vpx)
+AG_GST_CHECK_FEATURE(VPX, [VPX decoder], vpx, [
+  PKG_CHECK_MODULES(VPX, vpx >= 1.1.0, [HAVE_VPX="yes"], [HAVE_VPX="no"])
+  HAVE_VP8=no
+  HAVE_VP9=no
+
+  if test $HAVE_VPX = "yes"; then
+    OLD_LIBS="$LIBS"
+    OLD_CFLAGS="$CFLAGS"
+    CFLAGS="$CFLAGS $VPX_CFLAGS"
+    LIBS="$LIBS $VPX_LIBS"
+    AC_CHECK_LIB(vpx, vpx_codec_vp8_cx_algo, [
+      HAVE_VP8=yes
+      AC_DEFINE(HAVE_VP8_ENCODER, 1, [Defined if the VP8 encoder is available])
+    ])
+    AC_CHECK_LIB(vpx, vpx_codec_vp8_dx_algo, [
+      HAVE_VP8=yes
+      AC_DEFINE(HAVE_VP8_DECODER, 1, [Defined if the VP8 decoder is available])
+    ])
+
+    PKG_CHECK_MODULES(VPX_130, vpx >= 1.3.0, [
+      AC_CHECK_LIB(vpx, vpx_codec_vp9_cx_algo, [
+        HAVE_VP9=yes
+        AC_DEFINE(HAVE_VP9_ENCODER, 1, [Defined if the VP9 encoder is available])
+      ])
+      AC_CHECK_LIB(vpx, vpx_codec_vp9_dx_algo, [
+        HAVE_VP9=yes
+        AC_DEFINE(HAVE_VP9_DECODER, 1, [Defined if the VP9 decoder is available])
+      ])
+    ], [true])
+
+    PKG_CHECK_MODULES(VPX_140, vpx >= 1.4.0, [
+      AC_DEFINE(HAVE_VPX_1_4, 1, [Defined if the VPX library version is 1.4 or bigger])
+    ], [true])
+
+    LIBS="$OLD_LIBS"
+    CFLAGS="$OLD_CFLAGS"
+  fi
+  AC_SUBST(VPX_LIBS)
+  AC_SUBST(VPX_CFLAGS)
+])
+
+dnl *** wavpack ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_WAVPACK, true)
+AG_GST_CHECK_FEATURE(WAVPACK, [wavpack plug-in], wavpack, [
+  AG_GST_PKG_CHECK_MODULES(WAVPACK, wavpack >= 4.60.0)
+])
+
+dnl *** qtdemux & matroska prefer to have zlib ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_ZLIB, true)
+AG_GST_CHECK_FEATURE(ZLIB, [zlib support for qtdemux/matroska],, [
+  AG_GST_CHECK_LIBHEADER(ZLIB,
+    z, uncompress,, zlib.h, [
+    HAVE_ZLIB="yes"
+    ZLIB_LIBS="-lz"
+    AC_SUBST(ZLIB_LIBS)
+  ])
+])
+
+dnl *** matroska prefers to have bz2 ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_BZ2, true)
+AG_GST_CHECK_FEATURE(BZ2, [bz2 library for matroska ],, [
+  save_LIBS=$LIBS
+  LIBS="$LIBS -lbz2"
+  AC_MSG_CHECKING([for BZ2_bzlibVersion in -lbz2])
+  AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <bzlib.h>]], [[const char *version = BZ2_bzlibVersion ();]])],[HAVE_BZ2=yes],[HAVE_BZ2=no])
+  AC_MSG_RESULT($HAVE_BZ2)
+  LIBS=$save_LIBS
+  if test "x$HAVE_BZ2" = "xyes"; then
+    BZ2_LIBS="-lbz2"
+  fi
+  AC_SUBST(BZ2_LIBS)
+])
+
+else
+
+dnl not building plugins with external dependencies,
+dnl but we still need to set the conditionals
+AM_CONDITIONAL(USE_AALIB, false)
+AM_CONDITIONAL(USE_BZ2, false)
+AM_CONDITIONAL(USE_CAIRO, false)
+AM_CONDITIONAL(USE_DIRECTSOUND, false)
+AM_CONDITIONAL(USE_DV1394, false)
+AM_CONDITIONAL(USE_FLAC, false)
+AM_CONDITIONAL(USE_GDK_PIXBUF, false)
+AM_CONDITIONAL(USE_JACK, false)
+AM_CONDITIONAL(USE_JPEG, false)
+AM_CONDITIONAL(USE_LAME, false)
+AM_CONDITIONAL(USE_LIBCACA, false)
+AM_CONDITIONAL(USE_LIBDV, false)
+AM_CONDITIONAL(USE_LIBIEC61883, false)
+AM_CONDITIONAL(USE_LIBPNG, false)
+AM_CONDITIONAL(USE_MPG123, false)
+AM_CONDITIONAL(USE_OSS, false)
+AM_CONDITIONAL(USE_OSS4, false)
+AM_CONDITIONAL(USE_OSX_AUDIO, false)
+AM_CONDITIONAL(USE_OSX_VIDEO, false)
+AM_CONDITIONAL(USE_PULSE, false)
+AM_CONDITIONAL(USE_SHOUT2, false)
+AM_CONDITIONAL(USE_SOUP, false)
+AM_CONDITIONAL(USE_SPEEX, false)
+AM_CONDITIONAL(USE_TAGLIB, false)
+AM_CONDITIONAL(USE_TWOLAME, false)
+AM_CONDITIONAL(USE_VPX, false)
+AM_CONDITIONAL(USE_WAVEFORM, false)
+AM_CONDITIONAL(USE_WAVPACK, false)
+AM_CONDITIONAL(USE_X, false)
+AM_CONDITIONAL(USE_ZLIB, false)
+
+fi dnl of EXT plugins
+
+dnl *** finalize CFLAGS, LDFLAGS, LIBS
+
+dnl Overview:
+dnl GST_OPTION_CFLAGS:  common flags for profiling, debugging, errors, ...
+dnl GST_*:              flags shared by all built objects
+dnl GST_ALL_LDFLAGS:    linker flags shared by all
+dnl GST_LIB_LDFLAGS:    not needed, we don't install libraries
+dnl GST_LT_LDFLAGS:     library versioning of our libraries
+dnl GST_PLUGIN_LDFLAGS: flags to be used for all plugins
+
+dnl GST_OPTION_CFLAGS
+if test "x$USE_DEBUG" = xyes; then
+   PROFILE_CFLAGS="-g"
+fi
+AC_SUBST(PROFILE_CFLAGS)
+
+if test "x$PACKAGE_VERSION_NANO" = "x1"; then
+  dnl Define _only_ for git (not pre-releases or releases)
+  DEPRECATED_CFLAGS="-DGST_DISABLE_DEPRECATED"
+else
+  DEPRECATED_CFLAGS=""
+fi
+AC_SUBST(DEPRECATED_CFLAGS)
+
+VISIBILITY_CFLAGS=""
+AS_COMPILER_FLAG([-fvisibility=hidden], [VISIBILITY_CFLAGS="-fvisibility=hidden"])
+AC_SUBST(VISIBILITY_CFLAGS)
+
+VISIBILITY_CXXFLAGS=""
+if test "x$HAVE_CXX" = "xyes"; then
+  AS_CXX_COMPILER_FLAG([-fvisibility=hidden], [VISIBILITY_CXXFLAGS="-fvisibility=hidden"])
+fi
+AC_SUBST(VISIBILITY_CXXFLAGS)
+
+dnl disable strict aliasing
+AS_COMPILER_FLAG([-fno-strict-aliasing], [EXTRA_CFLAGS="-fno-strict-aliasing"])
+AC_SUBST(EXTRA_CFLAGS)
+
+dnl every flag in GST_OPTION_CFLAGS, GST_OPTION_CXXFLAGS and GST_OPTION_OBJCFLAGS can be overridden
+dnl at make time with e.g. make ERROR_CFLAGS=""
+GST_OPTION_CFLAGS="\$(WARNING_CFLAGS) \$(ERROR_CFLAGS) \$(DEBUG_CFLAGS) \$(PROFILE_CFLAGS) \$(GCOV_CFLAGS) \$(OPT_CFLAGS) \$(DEPRECATED_CFLAGS)"
+GST_OPTION_CXXFLAGS="\$(WARNING_CXXFLAGS) \$(ERROR_CXXFLAGS) \$(DEBUG_CFLAGS) \$(PROFILE_CFLAGS) \$(GCOV_CFLAGS) \$(OPT_CFLAGS) \$(DEPRECATED_CFLAGS)"
+GST_OPTION_OBJCFLAGS="\$(WARNING_OBJCFLAGS) \$(ERROR_OBJCFLAGS) \$(DEBUG_CFLAGS) \$(PROFILE_CFLAGS) \$(GCOV_CFLAGS) \$(OPT_CFLAGS) \$(DEPRECATED_CFLAGS)"
+AC_SUBST(GST_OPTION_CFLAGS)
+AC_SUBST(GST_OPTION_CXXFLAGS)
+AC_SUBST(GST_OPTION_OBJCFLAGS)
+
+dnl our libraries need to be versioned correctly
+AC_SUBST(GST_LT_LDFLAGS)
+
+dnl FIXME: do we want to rename to GST_ALL_* ?
+dnl prefer internal headers to already installed ones
+dnl also add builddir include for enumtypes and marshal
+dnl add ERROR_CFLAGS, but overridable
+GST_CFLAGS="$GST_CFLAGS -DGST_USE_UNSTABLE_API"
+GST_CXXFLAGS="-I\$(top_srcdir)/gst-libs $GST_CFLAGS $EXTRA_CFLAGS $GLIB_EXTRA_CFLAGS \$(GST_OPTION_CXXFLAGS) \$(VISIBILITY_CXXFLAGS)"
+GST_OBJCFLAGS="-I\$(top_srcdir)/gst-libs $GST_CFLAGS $EXTRA_CFLAGS $GLIB_EXTRA_CFLAGS \$(GST_OPTION_OBJCFLAGS)"
+GST_CFLAGS="-I\$(top_srcdir)/gst-libs $GST_CFLAGS $EXTRA_CFLAGS $GLIB_EXTRA_CFLAGS \$(GST_OPTION_CFLAGS) \$(VISIBILITY_CFLAGS)"
+AC_SUBST(GST_CFLAGS)
+AC_SUBST(GST_CXXFLAGS)
+AC_SUBST(GST_OBJCFLAGS)
+AC_SUBST(GST_LIBS)
+
+dnl LDFLAGS really should only contain flags, not libs - they get added before
+dnl whatevertarget_LIBS and -L flags here affect the rest of the linking
+GST_ALL_LDFLAGS="-no-undefined"
+if test "x${enable_Bsymbolic}" = "xyes"; then
+  GST_ALL_LDFLAGS="$GST_ALL_LDFLAGS -Wl,-Bsymbolic-functions"
+fi
+AC_SUBST(GST_ALL_LDFLAGS)
+
+dnl this really should only contain flags, not libs - they get added before
+dnl whatevertarget_LIBS and -L flags here affect the rest of the linking
+GST_PLUGIN_LDFLAGS="-module -avoid-version $GST_ALL_LDFLAGS"
+AC_SUBST(GST_PLUGIN_LDFLAGS)
+
+dnl *** output files ***
+
+$MKDIR_P tests/check/orc
+
+dnl keep this alphabetic per directory, please
+AC_CONFIG_FILES(
+Makefile
+gst/Makefile
+gst/alpha/Makefile
+gst/apetag/Makefile
+gst/audiofx/Makefile
+gst/audioparsers/Makefile
+gst/auparse/Makefile
+gst/autodetect/Makefile
+gst/avi/Makefile
+gst/cutter/Makefile
+gst/deinterlace/Makefile
+gst/dtmf/Makefile
+gst/debugutils/Makefile
+gst/effectv/Makefile
+gst/equalizer/Makefile
+gst/flv/Makefile
+gst/goom/Makefile
+gst/goom2k1/Makefile
+gst/id3demux/Makefile
+gst/icydemux/Makefile
+gst/imagefreeze/Makefile
+gst/interleave/Makefile
+gst/isomp4/Makefile
+gst/law/Makefile
+gst/level/Makefile
+gst/matroska/Makefile
+gst/monoscope/Makefile
+gst/multifile/Makefile
+gst/multipart/Makefile
+gst/replaygain/Makefile
+gst/rtp/Makefile
+gst/rtpmanager/Makefile
+gst/rtsp/Makefile
+gst/shapewipe/Makefile
+gst/smpte/Makefile
+gst/spectrum/Makefile
+gst/udp/Makefile
+gst/videobox/Makefile
+gst/videocrop/Makefile
+gst/videofilter/Makefile
+gst/videomixer/Makefile
+gst/wavenc/Makefile
+gst/wavparse/Makefile
+gst/flx/Makefile
+gst/y4m/Makefile
+ext/Makefile
+ext/aalib/Makefile
+ext/cairo/Makefile
+ext/dv/Makefile
+ext/flac/Makefile
+ext/gdk_pixbuf/Makefile
+ext/jack/Makefile
+ext/jpeg/Makefile
+ext/lame/Makefile
+ext/libcaca/Makefile
+ext/libpng/Makefile
+ext/mpg123/Makefile
+ext/pulse/Makefile
+ext/raw1394/Makefile
+ext/shout2/Makefile
+ext/soup/Makefile
+ext/speex/Makefile
+ext/taglib/Makefile
+ext/twolame/Makefile
+ext/vpx/Makefile
+ext/wavpack/Makefile
+sys/Makefile
+sys/directsound/Makefile
+sys/oss/Makefile
+sys/oss4/Makefile
+sys/osxaudio/Makefile
+sys/osxvideo/Makefile
+sys/v4l2/Makefile
+sys/waveform/Makefile
+sys/ximage/Makefile
+po/Makefile.in
+tests/Makefile
+tests/check/Makefile
+tests/examples/Makefile
+tests/examples/audiofx/Makefile
+tests/examples/cairo/Makefile
+tests/examples/equalizer/Makefile
+tests/examples/jack/Makefile
+tests/examples/level/Makefile
+tests/examples/rtp/Makefile
+tests/examples/shapewipe/Makefile
+tests/examples/spectrum/Makefile
+tests/examples/v4l2/Makefile
+tests/files/Makefile
+tests/icles/Makefile
+common/Makefile
+common/m4/Makefile
+m4/Makefile
+docs/Makefile
+docs/plugins/Makefile
+docs/version.entities
+pkgconfig/Makefile
+pkgconfig/gstreamer-plugins-good-uninstalled.pc
+)
+AC_OUTPUT
+
+AG_GST_OUTPUT_PLUGINS
+ORC_OUTPUT
+
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 0000000..e5a7abe
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1 @@
+version.entities
diff --git a/docs/Makefile.am b/docs/Makefile.am
new file mode 100644
index 0000000..8ff41fe
--- /dev/null
+++ b/docs/Makefile.am
@@ -0,0 +1,19 @@
+if ENABLE_GTK_DOC
+if ENABLE_PLUGIN_DOCS
+PLUGIN_DOCS_DIRS = plugins
+else
+PLUGIN_DOCS_DIRS =
+endif
+else
+PLUGIN_DOCS_DIRS = plugins
+endif
+
+SUBDIRS = $(PLUGIN_DOCS_DIRS)
+DIST_SUBDIRS = plugins
+
+EXTRA_DIST = \
+        random/ChangeLog-0.8 \
+        version.entities.in
+
+upload:
+	@if test "x$(SUBDIRS)" != x; then for a in $(SUBDIRS); do cd $$a; make upload; cd ..; done; fi
diff --git a/docs/plugins/.gitignore b/docs/plugins/.gitignore
new file mode 100644
index 0000000..8072a70
--- /dev/null
+++ b/docs/plugins/.gitignore
@@ -0,0 +1,23 @@
+Makefile
+Makefile.in
+
+*-decl.txt
+*-decl-list.txt
+*-undeclared.txt
+*-undocumented.txt
+*-unused.txt
+*-overrides.txt
+
+gst-plugins-good-plugins.args.new
+gst-plugins-good-plugins.signals.new
+
+tmpl
+html
+sgml
+xml
+*.stamp
+*.bak
+
+gst-plugins-good-plugins-scan
+gst-plugins-good-plugins-scan.c
+inspect-registry.*
diff --git a/docs/plugins/Makefile.am b/docs/plugins/Makefile.am
new file mode 100644
index 0000000..942a0bd
--- /dev/null
+++ b/docs/plugins/Makefile.am
@@ -0,0 +1,245 @@
+GST_DOC_SCANOBJ = $(top_srcdir)/common/gstdoc-scangobj
+
+## Process this file with automake to produce Makefile.in
+
+# The name of the module, e.g. 'glib'.
+#DOC_MODULE=gst-plugins-libs-@GST_API_VERSION@
+MODULE=gst-plugins-good
+DOC_MODULE=$(MODULE)-plugins
+
+# for upload-doc.mak
+DOC=$(MODULE)-plugins
+FORMATS=html
+html: html-build.stamp
+include $(top_srcdir)/common/upload-doc.mak
+
+# The top-level SGML file. Change it if you want.
+DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
+
+# The directory containing the source code.
+# gtk-doc will search all .c & .h files beneath here for inline comments
+# documenting functions and macros.
+DOC_SOURCE_DIR = $(top_srcdir)/gst $(top_srcdir)/ext $(top_srcdir)/sys
+
+# Extra options to supply to gtkdoc-scan.
+SCAN_OPTIONS=
+
+# Extra options to supply to gtkdoc-mkdb.
+MKDB_OPTIONS=--sgml-mode --source-suffixes=c,h,cc
+
+# Extra options to supply to gtkdoc-fixref.
+FIXXREF_OPTIONS=--extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html \
+	--extra-dir=$(GST_PREFIX)/share/gtk-doc/html \
+	--extra-dir=$(GSTPB_PREFIX)/share/gtk-doc/html
+
+# Used for dependencies.
+HFILE_GLOB= \
+  $(top_srcdir)/gst/*/*.h $(top_srcdir)/ext/*/*.h $(top_srcdir)/sys/*/*.h
+CFILE_GLOB= \
+  $(top_srcdir)/gst/*/*.c $(top_srcdir)/ext/*/*.c $(top_srcdir)/sys/*/*.c \
+  $(top_srcdir)/ext/*/*.cc $(top_srcdir)/sys/*/*.m
+
+# Header files to ignore when scanning.
+IGNORE_HFILES = 
+IGNORE_CFILES =
+
+# we add all .h files of elements that have signals/args we want
+# sadly this also pulls in the private methods - maybe we should
+# move those around in the source ?
+# also, we should add some stuff here conditionally based on whether
+# or not the plugin will actually build
+# but I'm not sure about that - it might be this Just Works given that
+# the registry won't have the element
+
+EXTRA_HFILES = \
+	$(top_srcdir)/ext/aalib/gstaasink.h \
+	$(top_srcdir)/ext/cairo/gstcairooverlay.h \
+	$(top_srcdir)/ext/dv/gstdvdec.h \
+	$(top_srcdir)/ext/dv/gstdvdemux.h \
+	$(top_srcdir)/ext/flac/gstflacdec.h \
+	$(top_srcdir)/ext/flac/gstflacenc.h \
+	$(top_srcdir)/ext/flac/gstflactag.h \
+	$(top_srcdir)/ext/gdk_pixbuf/gstgdkpixbufsink.h \
+	$(top_srcdir)/ext/jack/gstjackaudiosrc.h \
+	$(top_srcdir)/ext/jack/gstjackaudiosink.h \
+	$(top_srcdir)/ext/jpeg/gstjpegdec.h \
+	$(top_srcdir)/ext/jpeg/gstjpegenc.h \
+	$(top_srcdir)/ext/lame/gstlamemp3enc.h \
+	$(top_srcdir)/ext/libcaca/gstcacasink.h \
+	$(top_srcdir)/ext/libpng/gstpngdec.h \
+	$(top_srcdir)/ext/libpng/gstpngenc.h \
+	$(top_srcdir)/ext/raw1394/gstdv1394src.h \
+	$(top_srcdir)/ext/raw1394/gsthdv1394src.h \
+	$(top_srcdir)/ext/shout2/gstshout2.h \
+	$(top_srcdir)/ext/soup/gstsouphttpsrc.h \
+	$(top_srcdir)/ext/taglib/gstapev2mux.h \
+	$(top_srcdir)/ext/taglib/gstid3v2mux.h \
+	$(top_srcdir)/ext/twolame/gsttwolamemp2enc.h \
+	$(top_srcdir)/ext/pulse/pulsesink.h \
+	$(top_srcdir)/ext/pulse/pulsesrc.h \
+	$(top_srcdir)/ext/speex/gstspeexenc.h \
+	$(top_srcdir)/ext/speex/gstspeexdec.h \
+	$(top_srcdir)/ext/vpx/gstvp8dec.h \
+	$(top_srcdir)/ext/vpx/gstvp8enc.h \
+	$(top_srcdir)/ext/wavpack/gstwavpackdec.h \
+	$(top_srcdir)/ext/wavpack/gstwavpackenc.h \
+	$(top_srcdir)/gst/alpha/gstalpha.h \
+	$(top_srcdir)/gst/alpha/gstalphacolor.h \
+	$(top_srcdir)/gst/apetag/gstapedemux.h \
+	$(top_srcdir)/gst/audiofx/audioamplify.h \
+	$(top_srcdir)/gst/audiofx/audioecho.h \
+	$(top_srcdir)/gst/audiofx/audiodynamic.h \
+	$(top_srcdir)/gst/audiofx/audioinvert.h \
+	$(top_srcdir)/gst/audiofx/audiokaraoke.h \
+	$(top_srcdir)/gst/audiofx/audiopanorama.h \
+	$(top_srcdir)/gst/audiofx/audiocheblimit.h \
+	$(top_srcdir)/gst/audiofx/audiochebband.h \
+	$(top_srcdir)/gst/audiofx/audioiirfilter.h \
+	$(top_srcdir)/gst/audiofx/audiowsincband.h \
+	$(top_srcdir)/gst/audiofx/audiowsinclimit.h \
+	$(top_srcdir)/gst/audiofx/audiofirfilter.h \
+	$(top_srcdir)/gst/audiofx/gstscaletempo.h \
+	$(top_srcdir)/gst/audioparsers/gstaacparse.h \
+	$(top_srcdir)/gst/audioparsers/gstac3parse.h \
+	$(top_srcdir)/gst/audioparsers/gstamrparse.h \
+	$(top_srcdir)/gst/audioparsers/gstflacparse.h \
+	$(top_srcdir)/gst/audioparsers/gstdcaparse.h \
+	$(top_srcdir)/gst/audioparsers/gstmpegaudioparse.h \
+	$(top_srcdir)/gst/auparse/gstauparse.h \
+	$(top_srcdir)/gst/autodetect/gstautoaudiosink.h \
+	$(top_srcdir)/gst/autodetect/gstautoaudiosrc.h \
+	$(top_srcdir)/gst/autodetect/gstautovideosink.h \
+	$(top_srcdir)/gst/autodetect/gstautovideosrc.h \
+	$(top_srcdir)/gst/avi/gstavidemux.h \
+	$(top_srcdir)/gst/avi/gstavimux.h \
+	$(top_srcdir)/gst/avi/gstavisubtitle.h \
+	$(top_srcdir)/gst/cutter/gstcutter.h \
+	$(top_srcdir)/gst/debugutils/gstcapssetter.h \
+	$(top_srcdir)/gst/debugutils/gsttaginject.h \
+	$(top_srcdir)/gst/debugutils/progressreport.h \
+	$(top_srcdir)/gst/deinterlace/gstdeinterlace.h \
+	$(top_srcdir)/gst/dtmf/gstdtmfsrc.h \
+	$(top_srcdir)/gst/dtmf/gstrtpdtmfsrc.h \
+	$(top_srcdir)/gst/dtmf/gstrtpdtmfdepay.h \
+	$(top_srcdir)/gst/effectv/gstaging.h \
+	$(top_srcdir)/gst/effectv/gstdice.h \
+	$(top_srcdir)/gst/effectv/gstedge.h \
+	$(top_srcdir)/gst/effectv/gstquark.h \
+	$(top_srcdir)/gst/effectv/gstrev.h \
+	$(top_srcdir)/gst/effectv/gstshagadelic.h \
+	$(top_srcdir)/gst/effectv/gstvertigo.h \
+	$(top_srcdir)/gst/effectv/gstwarp.h \
+	$(top_srcdir)/gst/effectv/gststreak.h \
+	$(top_srcdir)/gst/effectv/gstripple.h \
+	$(top_srcdir)/gst/effectv/gstop.h \
+	$(top_srcdir)/gst/effectv/gstradioac.h \
+	$(top_srcdir)/gst/equalizer/gstiirequalizer.h \
+	$(top_srcdir)/gst/equalizer/gstiirequalizer3bands.h \
+	$(top_srcdir)/gst/equalizer/gstiirequalizer10bands.h \
+	$(top_srcdir)/gst/equalizer/gstiirequalizernbands.h \
+	$(top_srcdir)/gst/flv/gstflvdemux.h \
+	$(top_srcdir)/gst/flv/gstflvmux.h \
+	$(top_srcdir)/gst/flx/gstflxdec.h \
+	$(top_srcdir)/gst/goom/gstgoom.h \
+	$(top_srcdir)/gst/goom2k1/gstgoom.h \
+	$(top_srcdir)/gst/law/alaw-decode.h \
+	$(top_srcdir)/gst/law/alaw-encode.h \
+	$(top_srcdir)/gst/law/mulaw-decode.h \
+	$(top_srcdir)/gst/law/mulaw-encode.h \
+	$(top_srcdir)/gst/icydemux/gsticydemux.h \
+	$(top_srcdir)/gst/id3demux/gstid3demux.h \
+	$(top_srcdir)/gst/imagefreeze/gstimagefreeze.h \
+	$(top_srcdir)/gst/interleave/deinterleave.h \
+	$(top_srcdir)/gst/interleave/interleave.h \
+	$(top_srcdir)/gst/level/gstlevel.h \
+	$(top_srcdir)/gst/matroska/matroska-demux.h \
+	$(top_srcdir)/gst/matroska/matroska-mux.h \
+	$(top_srcdir)/gst/matroska/webm-mux.h \
+	$(top_srcdir)/gst/monoscope/gstmonoscope.h \
+	$(top_srcdir)/gst/multifile/gstmultifilesink.h \
+	$(top_srcdir)/gst/multifile/gstmultifilesrc.h \
+	$(top_srcdir)/gst/multifile/gstsplitfilesrc.h \
+	$(top_srcdir)/gst/multifile/gstsplitmuxsrc.h \
+	$(top_srcdir)/gst/multifile/gstsplitmuxsink.h \
+	$(top_srcdir)/gst/multipart/multipartdemux.h \
+	$(top_srcdir)/gst/multipart/multipartmux.h \
+	$(top_srcdir)/gst/isomp4/qtdemux.h \
+	$(top_srcdir)/gst/isomp4/gstqtmux.h \
+	$(top_srcdir)/gst/isomp4/gstqtmux-doc.h \
+	$(top_srcdir)/gst/replaygain/gstrganalysis.h \
+	$(top_srcdir)/gst/replaygain/gstrglimiter.h \
+	$(top_srcdir)/gst/replaygain/gstrgvolume.h \
+	$(top_srcdir)/gst/rtp/gstrtpj2kpay.h \
+	$(top_srcdir)/gst/rtp/gstrtpjpegpay.h \
+	$(top_srcdir)/gst/rtpmanager/gstrtpbin.h \
+	$(top_srcdir)/gst/rtpmanager/gstrtpjitterbuffer.h \
+	$(top_srcdir)/gst/rtpmanager/gstrtpptdemux.h \
+	$(top_srcdir)/gst/rtpmanager/gstrtpsession.h \
+	$(top_srcdir)/gst/rtpmanager/gstrtpssrcdemux.h \
+	$(top_srcdir)/gst/rtpmanager/gstrtpmux.h \
+	$(top_srcdir)/gst/rtpmanager/gstrtpdtmfmux.h \
+	$(top_srcdir)/gst/rtpmanager/gstrtprtxsend.h \
+	$(top_srcdir)/gst/rtpmanager/gstrtprtxreceive.h \
+	$(top_srcdir)/gst/rtsp/gstrtpdec.h \
+	$(top_srcdir)/gst/rtsp/gstrtspsrc.h \
+	$(top_srcdir)/gst/shapewipe/gstshapewipe.h \
+	$(top_srcdir)/gst/smpte/gstsmpte.h \
+	$(top_srcdir)/gst/smpte/gstsmptealpha.h \
+	$(top_srcdir)/gst/spectrum/gstspectrum.h \
+	$(top_srcdir)/gst/udp/gstmultiudpsink.h \
+	$(top_srcdir)/gst/udp/gstudpsrc.h \
+	$(top_srcdir)/gst/udp/gstudpsink.h \
+	$(top_srcdir)/gst/videobox/gstvideobox.h \
+	$(top_srcdir)/gst/videocrop/gstvideocrop.h \
+	$(top_srcdir)/gst/videocrop/gstaspectratiocrop.h \
+	$(top_srcdir)/gst/videofilter/gstgamma.h \
+	$(top_srcdir)/gst/videofilter/gstvideobalance.h \
+	$(top_srcdir)/gst/videofilter/gstvideoflip.h \
+	$(top_srcdir)/gst/videomixer/videomixer2.h \
+	$(top_srcdir)/gst/videomixer/videomixer2pad.h \
+	$(top_srcdir)/gst/wavenc/gstwavenc.h \
+	$(top_srcdir)/gst/wavparse/gstwavparse.h \
+	$(top_srcdir)/gst/y4m/gsty4mencode.h \
+	$(top_srcdir)/sys/directsound/gstdirectsoundsink.h \
+	$(top_srcdir)/sys/oss4/oss4-sink.h \
+	$(top_srcdir)/sys/oss4/oss4-source.h \
+	$(top_srcdir)/sys/oss/gstosssink.h \
+	$(top_srcdir)/sys/oss/gstosssrc.h \
+	$(top_srcdir)/sys/osxaudio/gstosxaudiosrc.h \
+	$(top_srcdir)/sys/osxaudio/gstosxaudiosink.h \
+	$(top_srcdir)/sys/osxvideo/osxvideosink.h \
+	$(top_srcdir)/sys/v4l2/gstv4l2src.h \
+	$(top_srcdir)/sys/v4l2/gstv4l2sink.h \
+	$(top_srcdir)/sys/v4l2/gstv4l2transform.h \
+	$(top_srcdir)/sys/v4l2/gstv4l2videodec.h \
+	$(top_srcdir)/sys/v4l2/gstv4l2radio.h \
+	$(top_srcdir)/sys/waveform/gstwaveformsink.h \
+	$(top_srcdir)/sys/ximage/gstximagesrc.h
+
+# example code that needs to be converted to xml and placed in xml/
+EXAMPLE_CFILES = \
+	$(top_srcdir)/tests/examples/level/level-example.c \
+	$(top_srcdir)/tests/examples/spectrum/spectrum-example.c \
+	$(top_srcdir)/tests/examples/audiofx/firfilter-example.c \
+	$(top_srcdir)/tests/examples/audiofx/iirfilter-example.c
+
+# Images to copy into HTML directory.
+HTML_IMAGES =
+
+# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
+content_files =
+
+# Other files to distribute.
+extra_files =
+
+# CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib
+# contains GtkObjects/GObjects and you want to document signals and properties.
+GTKDOC_CFLAGS = $(GST_BASE_CFLAGS) -I$(top_builddir)
+GTKDOC_LIBS = $(GST_BASE_LIBS)
+
+# If you need to override some of the declarations, place them in this file
+# and uncomment this line.
+#DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt
+DOC_OVERRIDES =
+
+include $(top_srcdir)/common/gtk-doc-plugins.mak
diff --git a/docs/plugins/gst-plugins-good-plugins-docs.sgml b/docs/plugins/gst-plugins-good-plugins-docs.sgml
new file mode 100644
index 0000000..a4128fc
--- /dev/null
+++ b/docs/plugins/gst-plugins-good-plugins-docs.sgml
@@ -0,0 +1,374 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" 
+               "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<!ENTITY % local.common.attrib "xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'">
+<!ENTITY % version-entities SYSTEM "version.entities">
+%version-entities;
+]>
+
+<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
+  <bookinfo>
+    <title>GStreamer Good Plugins &GST_API_VERSION; Plugins Reference Manual</title>
+    <releaseinfo>
+      for GStreamer Good Plugins &GST_API_VERSION; (&GST_VERSION;)
+      The latest version of this documentation can be found on-line at
+      <ulink role="online-location" url="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good/html/">http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good/html/</ulink>.
+    </releaseinfo>
+  </bookinfo>
+
+  <chapter>
+    <title>gst-plugins-good Elements</title>
+    <xi:include href="xml/element-3gppmux.xml" />
+    <xi:include href="xml/element-aacparse.xml" />
+    <xi:include href="xml/element-aasink.xml" />
+    <xi:include href="xml/element-ac3parse.xml" />
+    <xi:include href="xml/element-agingtv.xml" />
+    <xi:include href="xml/element-alawdec.xml" />
+    <xi:include href="xml/element-alawenc.xml" />
+    <xi:include href="xml/element-alphacolor.xml" />
+    <xi:include href="xml/element-alpha.xml" />
+    <xi:include href="xml/element-amrparse.xml" />
+    <xi:include href="xml/element-apedemux.xml" />
+    <xi:include href="xml/element-apev2mux.xml" />
+    <xi:include href="xml/element-aspectratiocrop.xml" />
+    <xi:include href="xml/element-asteriskh263.xml" />
+    <xi:include href="xml/element-audioamplify.xml" />
+    <xi:include href="xml/element-audiochebband.xml" />
+    <xi:include href="xml/element-audiocheblimit.xml" />
+    <xi:include href="xml/element-audiodynamic.xml" />
+    <xi:include href="xml/element-audioecho.xml" />
+    <xi:include href="xml/element-audiofirfilter.xml" />
+    <xi:include href="xml/element-audioiirfilter.xml" />
+    <xi:include href="xml/element-audioinvert.xml" />
+    <xi:include href="xml/element-audiokaraoke.xml" />
+    <xi:include href="xml/element-audiopanorama.xml" />
+    <xi:include href="xml/element-audiowsincband.xml" />
+    <xi:include href="xml/element-audiowsinclimit.xml" />
+    <xi:include href="xml/element-auparse.xml" />
+    <xi:include href="xml/element-autoaudiosink.xml" />
+    <xi:include href="xml/element-autoaudiosrc.xml" />
+    <xi:include href="xml/element-autovideosink.xml" />
+    <xi:include href="xml/element-autovideosrc.xml" />
+    <xi:include href="xml/element-avidemux.xml" />
+    <xi:include href="xml/element-avimux.xml" />
+    <xi:include href="xml/element-avisubtitle.xml" />
+    <xi:include href="xml/element-breakmydata.xml" />
+    <xi:include href="xml/element-cacasink.xml" />
+    <xi:include href="xml/element-cairooverlay.xml" />
+    <xi:include href="xml/element-capssetter.xml" />
+    <xi:include href="xml/element-cpureport.xml" />
+    <xi:include href="xml/element-cutter.xml" />
+    <xi:include href="xml/element-dcaparse.xml" />
+    <xi:include href="xml/element-deinterlace.xml" />
+    <xi:include href="xml/element-deinterleave.xml" />
+    <xi:include href="xml/element-dicetv.xml" />
+    <xi:include href="xml/element-directsoundsink.xml" />
+    <xi:include href="xml/element-dtmfsrc.xml" />
+    <xi:include href="xml/element-dv1394src.xml" />
+    <xi:include href="xml/element-dvdec.xml" />
+    <xi:include href="xml/element-dvdemux.xml" />
+    <xi:include href="xml/element-dynudpsink.xml" />
+    <xi:include href="xml/element-edgetv.xml" />
+    <xi:include href="xml/element-equalizer-10bands.xml" />
+    <xi:include href="xml/element-equalizer-3bands.xml" />
+    <xi:include href="xml/element-equalizer-nbands.xml" />
+    <xi:include href="xml/element-firfilter-example.xml" />
+    <xi:include href="xml/element-flacdec.xml" />
+    <xi:include href="xml/element-flacenc.xml" />
+    <xi:include href="xml/element-flacparse.xml" />
+    <xi:include href="xml/element-flactag.xml" />
+    <xi:include href="xml/element-flvdemux.xml" />
+    <xi:include href="xml/element-flvmux.xml" />
+    <xi:include href="xml/element-flxdec.xml" />
+    <xi:include href="xml/element-gamma.xml" />
+    <xi:include href="xml/element-gdkpixbufdec.xml" />
+    <xi:include href="xml/element-gdkpixbufoverlay.xml" />
+    <xi:include href="xml/element-gdkpixbufsink.xml" />
+    <xi:include href="xml/element-goom2k1.xml" />
+    <xi:include href="xml/element-goom.xml" />
+    <xi:include href="xml/element-hdv1394src.xml" />
+    <xi:include href="xml/element-icydemux.xml" />
+    <xi:include href="xml/element-id3demux.xml" />
+    <xi:include href="xml/element-id3v2mux.xml" />
+    <xi:include href="xml/element-iirequalizer.xml" />
+    <xi:include href="xml/element-iirfilter-example.xml" />
+    <xi:include href="xml/element-imagefreeze.xml" />
+    <xi:include href="xml/element-interleave.xml" />
+    <xi:include href="xml/element-ismlmux.xml" />
+    <xi:include href="xml/element-jackaudiosink.xml" />
+    <xi:include href="xml/element-jackaudiosrc.xml" />
+    <xi:include href="xml/element-jpegdec.xml" />
+    <xi:include href="xml/element-jpegenc.xml" />
+    <xi:include href="xml/element-lamemp3enc.xml" />
+    <xi:include href="xml/element-level-example.xml" />
+    <xi:include href="xml/element-level.xml" />
+    <xi:include href="xml/element-matroskademux.xml" />
+    <xi:include href="xml/element-matroskamux.xml" />
+    <xi:include href="xml/element-matroskaparse.xml" />
+    <xi:include href="xml/element-mj2mux.xml" />
+    <xi:include href="xml/element-monoscope.xml" />
+    <xi:include href="xml/element-mp4mux.xml" />
+    <xi:include href="xml/element-mpegaudioparse.xml" />
+    <xi:include href="xml/element-mpg123audiodec.xml" />
+    <xi:include href="xml/element-mulawdec.xml" />
+    <xi:include href="xml/element-mulawenc.xml" />
+    <xi:include href="xml/element-multifilesink.xml" />
+    <xi:include href="xml/element-multifilesrc.xml" />
+    <xi:include href="xml/element-multipartdemux.xml" />
+    <xi:include href="xml/element-multipartmux.xml" />
+    <xi:include href="xml/element-multiudpsink.xml" />
+    <xi:include href="xml/element-navigationtest.xml" />
+    <xi:include href="xml/element-navseek.xml" />
+    <xi:include href="xml/element-optv.xml" />
+    <xi:include href="xml/element-oss4sink.xml" />
+    <xi:include href="xml/element-oss4src.xml" />
+    <xi:include href="xml/element-osssink.xml" />
+    <xi:include href="xml/element-osssrc.xml" />
+    <xi:include href="xml/element-osxaudiosink.xml" />
+    <xi:include href="xml/element-osxaudiosrc.xml" />
+    <xi:include href="xml/element-osxvideosink.xml" />
+    <xi:include href="xml/element-pngdec.xml" />
+    <xi:include href="xml/element-pngenc.xml" />
+    <xi:include href="xml/element-progressreport.xml" />
+    <xi:include href="xml/element-pulsesink.xml" />
+    <xi:include href="xml/element-pulsesrc.xml" />
+    <xi:include href="xml/element-pushfilesrc.xml" />
+    <xi:include href="xml/element-qtdemux.xml" />
+    <xi:include href="xml/element-qtmoovrecover.xml" />
+    <xi:include href="xml/element-qtmux.xml" />
+    <xi:include href="xml/element-quarktv.xml" />
+    <xi:include href="xml/element-radioactv.xml" />
+    <xi:include href="xml/element-revtv.xml" />
+    <xi:include href="xml/element-rganalysis.xml" />
+    <xi:include href="xml/element-rglimiter.xml" />
+    <xi:include href="xml/element-rgvolume.xml" />
+    <xi:include href="xml/element-rippletv.xml" />
+    <xi:include href="xml/element-rndbuffersize.xml" />
+    <xi:include href="xml/element-rtpac3depay.xml" />
+    <xi:include href="xml/element-rtpac3pay.xml" />
+    <xi:include href="xml/element-rtpamrdepay.xml" />
+    <xi:include href="xml/element-rtpamrpay.xml" />
+    <xi:include href="xml/element-rtpbin.xml" />
+    <xi:include href="xml/element-rtpbvdepay.xml" />
+    <xi:include href="xml/element-rtpbvpay.xml" />
+    <xi:include href="xml/element-rtpceltdepay.xml" />
+    <xi:include href="xml/element-rtpceltpay.xml" />
+    <xi:include href="xml/element-rtpdec.xml" />
+    <xi:include href="xml/element-rtpdtmfdepay.xml" />
+    <xi:include href="xml/element-rtpdtmfmux.xml" />
+    <xi:include href="xml/element-rtpdtmfsrc.xml" />
+    <xi:include href="xml/element-rtpdvdepay.xml" />
+    <xi:include href="xml/element-rtpdvpay.xml" />
+    <xi:include href="xml/element-rtpg722depay.xml" />
+    <xi:include href="xml/element-rtpg722pay.xml" />
+    <xi:include href="xml/element-rtpg723depay.xml" />
+    <xi:include href="xml/element-rtpg723pay.xml" />
+    <xi:include href="xml/element-rtpg726depay.xml" />
+    <xi:include href="xml/element-rtpg726pay.xml" />
+    <xi:include href="xml/element-rtpg729depay.xml" />
+    <xi:include href="xml/element-rtpg729pay.xml" />
+    <xi:include href="xml/element-rtpgsmdepay.xml" />
+    <xi:include href="xml/element-rtpgsmpay.xml" />
+    <xi:include href="xml/element-rtpgstdepay.xml" />
+    <xi:include href="xml/element-rtpgstpay.xml" />
+    <xi:include href="xml/element-rtph261depay.xml" />
+    <xi:include href="xml/element-rtph261pay.xml" />
+    <xi:include href="xml/element-rtph263depay.xml" />
+    <xi:include href="xml/element-rtph263pay.xml" />
+    <xi:include href="xml/element-rtph263pdepay.xml" />
+    <xi:include href="xml/element-rtph263ppay.xml" />
+    <xi:include href="xml/element-rtph264depay.xml" />
+    <xi:include href="xml/element-rtph264pay.xml" />
+    <xi:include href="xml/element-rtph265depay.xml" />
+    <xi:include href="xml/element-rtph265pay.xml" />
+    <xi:include href="xml/element-rtpilbcdepay.xml" />
+    <xi:include href="xml/element-rtpilbcpay.xml" />
+    <xi:include href="xml/element-rtpj2kdepay.xml" />
+    <xi:include href="xml/element-rtpj2kpay.xml" />
+    <xi:include href="xml/element-rtpjitterbuffer.xml" />
+    <xi:include href="xml/element-rtpjpegdepay.xml" />
+    <xi:include href="xml/element-rtpjpegpay.xml" />
+    <xi:include href="xml/element-rtpklvdepay.xml" />
+    <xi:include href="xml/element-rtpklvpay.xml" />
+    <xi:include href="xml/element-rtpL8depay.xml" />
+    <xi:include href="xml/element-rtpL8pay.xml" />
+    <xi:include href="xml/element-rtpL16depay.xml" />
+    <xi:include href="xml/element-rtpL16pay.xml" />
+    <xi:include href="xml/element-rtpL24depay.xml" />
+    <xi:include href="xml/element-rtpL24pay.xml" />
+    <xi:include href="xml/element-rtpmp1sdepay.xml" />
+    <xi:include href="xml/element-rtpmp2tdepay.xml" />
+    <xi:include href="xml/element-rtpmp2tpay.xml" />
+    <xi:include href="xml/element-rtpmp4adepay.xml" />
+    <xi:include href="xml/element-rtpmp4apay.xml" />
+    <xi:include href="xml/element-rtpmp4gdepay.xml" />
+    <xi:include href="xml/element-rtpmp4gpay.xml" />
+    <xi:include href="xml/element-rtpmp4vdepay.xml" />
+    <xi:include href="xml/element-rtpmp4vpay.xml" />
+    <xi:include href="xml/element-rtpmpadepay.xml" />
+    <xi:include href="xml/element-rtpmpapay.xml" />
+    <xi:include href="xml/element-rtpmparobustdepay.xml" />
+    <xi:include href="xml/element-rtpmpvdepay.xml" />
+    <xi:include href="xml/element-rtpmpvpay.xml" />
+    <xi:include href="xml/element-rtpmux.xml" />
+    <xi:include href="xml/element-rtpopusdepay.xml" />
+    <xi:include href="xml/element-rtpopuspay.xml" />
+    <xi:include href="xml/element-rtppcmadepay.xml" />
+    <xi:include href="xml/element-rtppcmapay.xml" />
+    <xi:include href="xml/element-rtppcmudepay.xml" />
+    <xi:include href="xml/element-rtppcmupay.xml" />
+    <xi:include href="xml/element-rtpptdemux.xml" />
+    <xi:include href="xml/element-rtpqcelpdepay.xml" />
+    <xi:include href="xml/element-rtpqdm2depay.xml" />
+    <xi:include href="xml/element-rtprtxqueue.xml" />
+    <xi:include href="xml/element-rtprtxreceive.xml" />
+    <xi:include href="xml/element-rtprtxsend.xml" />
+    <xi:include href="xml/element-rtpsbcdepay.xml" />
+    <xi:include href="xml/element-rtpsbcpay.xml" />
+    <xi:include href="xml/element-rtpsession.xml" />
+    <xi:include href="xml/element-rtpsirendepay.xml" />
+    <xi:include href="xml/element-rtpsirenpay.xml" />
+    <xi:include href="xml/element-rtpspeexdepay.xml" />
+    <xi:include href="xml/element-rtpspeexpay.xml" />
+    <xi:include href="xml/element-rtpssrcdemux.xml" />
+    <xi:include href="xml/element-rtpstreamdepay.xml" />
+    <xi:include href="xml/element-rtpstreampay.xml" />
+    <xi:include href="xml/element-rtpsv3vdepay.xml" />
+    <xi:include href="xml/element-rtptheoradepay.xml" />
+    <xi:include href="xml/element-rtptheorapay.xml" />
+    <xi:include href="xml/element-rtpvorbisdepay.xml" />
+    <xi:include href="xml/element-rtpvorbispay.xml" />
+    <xi:include href="xml/element-rtpvp8depay.xml" />
+    <xi:include href="xml/element-rtpvp8pay.xml" />
+    <xi:include href="xml/element-rtpvp9depay.xml" />
+    <xi:include href="xml/element-rtpvp9pay.xml" />
+    <xi:include href="xml/element-rtpvrawdepay.xml" />
+    <xi:include href="xml/element-rtpvrawpay.xml" />
+    <xi:include href="xml/element-rtpxqtdepay.xml" />
+    <xi:include href="xml/element-rtspsrc.xml" />
+    <xi:include href="xml/element-sbcparse.xml" />
+    <xi:include href="xml/element-scaletempo.xml" />
+    <xi:include href="xml/element-shagadelictv.xml" />
+    <xi:include href="xml/element-shapewipe.xml" />
+    <xi:include href="xml/element-shout2send.xml" />
+    <xi:include href="xml/element-smptealpha.xml" />
+    <xi:include href="xml/element-smpte.xml" />
+    <xi:include href="xml/element-souphttpclientsink.xml" />
+    <xi:include href="xml/element-souphttpsrc.xml" />
+    <xi:include href="xml/element-spectrum-example.xml" />
+    <xi:include href="xml/element-spectrum.xml" />
+    <xi:include href="xml/element-speexdec.xml" />
+    <xi:include href="xml/element-speexenc.xml" />
+    <xi:include href="xml/element-splitfilesrc.xml" />
+    <xi:include href="xml/element-splitmuxsink.xml" />
+    <xi:include href="xml/element-splitmuxsrc.xml" />
+    <xi:include href="xml/element-streaktv.xml" />
+    <xi:include href="xml/element-taginject.xml" />
+    <xi:include href="xml/element-testsink.xml" />
+    <xi:include href="xml/element-twolamemp2enc.xml" />
+    <xi:include href="xml/element-udpsink.xml" />
+    <xi:include href="xml/element-udpsrc.xml" />
+    <xi:include href="xml/element-v4l2radio.xml" />
+    <xi:include href="xml/element-v4l2sink.xml" />
+    <xi:include href="xml/element-v4l2src.xml" />
+    <xi:include href="xml/element-vertigotv.xml" />
+    <xi:include href="xml/element-videobalance.xml" />
+    <xi:include href="xml/element-videobox.xml" />
+    <xi:include href="xml/element-videocrop.xml" />
+    <xi:include href="xml/element-videoflip.xml" />
+    <xi:include href="xml/element-videomedian.xml" />
+    <xi:include href="xml/element-videomixer.xml" />
+    <xi:include href="xml/element-vp8dec.xml" />
+    <xi:include href="xml/element-vp8enc.xml" />
+    <xi:include href="xml/element-vp9dec.xml" />
+    <xi:include href="xml/element-vp9enc.xml" />
+    <xi:include href="xml/element-warptv.xml" />
+    <xi:include href="xml/element-waveformsink.xml" />
+    <xi:include href="xml/element-wavenc.xml" />
+    <xi:include href="xml/element-wavpackdec.xml" />
+    <xi:include href="xml/element-wavpackenc.xml" />
+    <xi:include href="xml/element-wavpackparse.xml" />
+    <xi:include href="xml/element-wavparse.xml" />
+    <xi:include href="xml/element-webmmux.xml" />
+    <xi:include href="xml/element-ximagesrc.xml" />
+    <xi:include href="xml/element-y4menc.xml" />
+  </chapter>
+
+  <chapter>
+    <title>gst-plugins-good Plugins</title>
+    <xi:include href="xml/plugin-1394.xml" />
+    <xi:include href="xml/plugin-aasink.xml" />
+    <xi:include href="xml/plugin-alaw.xml" />
+    <xi:include href="xml/plugin-alphacolor.xml" />
+    <xi:include href="xml/plugin-alpha.xml" />
+    <xi:include href="xml/plugin-apetag.xml" />
+    <xi:include href="xml/plugin-audiofx.xml" />
+    <xi:include href="xml/plugin-audioparsers.xml" />
+    <xi:include href="xml/plugin-auparse.xml" />
+    <xi:include href="xml/plugin-autodetect.xml" />
+    <xi:include href="xml/plugin-avi.xml" />
+    <xi:include href="xml/plugin-cacasink.xml" />
+    <xi:include href="xml/plugin-cairo.xml" />
+    <xi:include href="xml/plugin-cutter.xml" />
+    <xi:include href="xml/plugin-debug.xml" />
+    <xi:include href="xml/plugin-deinterlace.xml" />
+    <xi:include href="xml/plugin-directsound.xml" />
+    <xi:include href="xml/plugin-dtmf.xml" />
+    <xi:include href="xml/plugin-dv.xml" />
+    <xi:include href="xml/plugin-effectv.xml" />
+    <xi:include href="xml/plugin-equalizer.xml" />
+    <xi:include href="xml/plugin-flac.xml" />
+    <xi:include href="xml/plugin-flv.xml" />
+    <xi:include href="xml/plugin-flxdec.xml" />
+    <xi:include href="xml/plugin-gdkpixbuf.xml" />
+    <xi:include href="xml/plugin-goom2k1.xml" />
+    <xi:include href="xml/plugin-goom.xml" />
+    <xi:include href="xml/plugin-icydemux.xml" />
+    <xi:include href="xml/plugin-id3demux.xml" />
+    <xi:include href="xml/plugin-imagefreeze.xml" />
+    <xi:include href="xml/plugin-interleave.xml" />
+    <xi:include href="xml/plugin-isomp4.xml" />
+    <xi:include href="xml/plugin-jack.xml" />
+    <xi:include href="xml/plugin-jpeg.xml" />
+    <xi:include href="xml/plugin-lame.xml" />
+    <xi:include href="xml/plugin-level.xml" />
+    <xi:include href="xml/plugin-matroska.xml" />
+    <xi:include href="xml/plugin-monoscope.xml" />
+    <xi:include href="xml/plugin-mpg123.xml" />
+    <xi:include href="xml/plugin-mulaw.xml" />
+    <xi:include href="xml/plugin-multifile.xml" />
+    <xi:include href="xml/plugin-multipart.xml" />
+    <xi:include href="xml/plugin-navigationtest.xml" />
+    <xi:include href="xml/plugin-oss4.xml" />
+    <xi:include href="xml/plugin-ossaudio.xml" />
+    <xi:include href="xml/plugin-osxaudio.xml" />
+    <xi:include href="xml/plugin-osxvideo.xml" />
+    <xi:include href="xml/plugin-png.xml" />
+    <xi:include href="xml/plugin-pulseaudio.xml" />
+    <xi:include href="xml/plugin-replaygain.xml" />
+    <xi:include href="xml/plugin-rtpmanager.xml" />
+    <xi:include href="xml/plugin-rtp.xml" />
+    <xi:include href="xml/plugin-rtsp.xml" />
+    <xi:include href="xml/plugin-shapewipe.xml" />
+    <xi:include href="xml/plugin-shout2.xml" />
+    <xi:include href="xml/plugin-smpte.xml" />
+    <xi:include href="xml/plugin-soup.xml" />
+    <xi:include href="xml/plugin-spectrum.xml" />
+    <xi:include href="xml/plugin-speex.xml" />
+    <xi:include href="xml/plugin-taglib.xml" />
+    <xi:include href="xml/plugin-twolame.xml" />
+    <xi:include href="xml/plugin-udp.xml" />
+    <xi:include href="xml/plugin-video4linux2.xml" />
+    <xi:include href="xml/plugin-videobox.xml" />
+    <xi:include href="xml/plugin-videocrop.xml" />
+    <xi:include href="xml/plugin-videofilter.xml" />
+    <xi:include href="xml/plugin-videomixer.xml" />
+    <xi:include href="xml/plugin-vpx.xml" />
+    <xi:include href="xml/plugin-waveform.xml" />
+    <xi:include href="xml/plugin-wavenc.xml" />
+    <xi:include href="xml/plugin-wavpack.xml" />
+    <xi:include href="xml/plugin-wavparse.xml" />
+    <xi:include href="xml/plugin-ximagesrc.xml" />
+    <xi:include href="xml/plugin-y4menc.xml" />
+  </chapter>
+</book>
diff --git a/docs/plugins/gst-plugins-good-plugins-sections.txt b/docs/plugins/gst-plugins-good-plugins-sections.txt
new file mode 100644
index 0000000..b23db52
--- /dev/null
+++ b/docs/plugins/gst-plugins-good-plugins-sections.txt
@@ -0,0 +1,4350 @@
+<SECTION>
+<FILE>element-3gppmux</FILE>
+<TITLE>3gppmux</TITLE>
+Gst3GPPMux
+<SUBSECTION Standard>
+Gst3GPPMuxClass
+GST_3_GPP_MUX
+GST_3_GPP_MUX_CAST
+GST_IS_3_GPP_MUX
+GST_3_GPP_MUX_CLASS
+GST_IS_3_GPP_MUX_CLASS
+GST_TYPE_3_GPP_MUX
+<SUBSECTION Private>
+gst_3_gpp_mux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-aasink</FILE>
+<TITLE>aasink</TITLE>
+GstAASink
+GstAASinkDitherers
+GstAASinkDrivers
+<SUBSECTION Standard>
+GstAASinkClass
+GST_AA_SINK
+GST_AA_SINK_CAST
+GST_IS_AA_SINK
+GST_AA_SINK_CLASS
+GST_IS_AA_SINK_CLASS
+GST_TYPE_AA_SINK
+<SUBSECTION Private>
+gst_aa_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-alawdec</FILE>
+<TITLE>alawdec</TITLE>
+GstALawDec
+<SUBSECTION Standard>
+GstALawDecClass
+GST_A_LAW_DEC
+GST_A_LAW_DEC_CAST
+GST_IS_A_LAW_DEC
+GST_A_LAW_DEC_CLASS
+GST_IS_A_LAW_DEC_CLASS
+GST_TYPE_A_LAW_DEC
+<SUBSECTION Private>
+gst_a_law_dec_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-alawenc</FILE>
+<TITLE>alawenc</TITLE>
+GstALawEnc
+<SUBSECTION Standard>
+GstALawEncClass
+GST_A_LAW_ENC
+GST_A_LAW_ENC_CAST
+GST_IS_A_LAW_ENC
+GST_A_LAW_ENC_CLASS
+GST_IS_A_LAW_ENC_CLASS
+GST_TYPE_A_LAW_ENC
+<SUBSECTION Private>
+gst_a_law_enc_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-aacparse</FILE>
+<TITLE>aacparse</TITLE>
+GstAacParse
+<SUBSECTION Standard>
+GstAacParseClass
+GST_AAC_PARSE
+GST_AAC_PARSE_CAST
+GST_IS_AAC_PARSE
+GST_AAC_PARSE_CLASS
+GST_IS_AAC_PARSE_CLASS
+GST_TYPE_AAC_PARSE
+<SUBSECTION Private>
+gst_aac_parse_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-ac3parse</FILE>
+<TITLE>ac3parse</TITLE>
+GstAc3Parse
+<SUBSECTION Standard>
+GstAc3ParseClass
+GST_AC3_PARSE
+GST_AC3_PARSE_CAST
+GST_IS_AC3_PARSE
+GST_AC3_PARSE_CLASS
+GST_IS_AC3_PARSE_CLASS
+GST_TYPE_AC3_PARSE
+<SUBSECTION Private>
+gst_ac3_parse_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-agingtv</FILE>
+<TITLE>agingtv</TITLE>
+GstAgingTV
+<SUBSECTION Standard>
+GstAgingTVClass
+GST_AGING_TV
+GST_AGING_TV_CAST
+GST_IS_AGING_TV
+GST_AGING_TV_CLASS
+GST_IS_AGING_TV_CLASS
+GST_TYPE_AGING_TV
+<SUBSECTION Private>
+gst_aging_tv_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-alpha</FILE>
+<TITLE>alpha</TITLE>
+GstAlpha
+GstAlphaMethod
+<SUBSECTION Standard>
+GstAlphaClass
+GST_ALPHA
+GST_ALPHA_CAST
+GST_IS_ALPHA
+GST_ALPHA_CLASS
+GST_IS_ALPHA_CLASS
+GST_TYPE_ALPHA
+<SUBSECTION Private>
+gst_alpha_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-alphacolor</FILE>
+<TITLE>alphacolor</TITLE>
+GstAlphaColor
+<SUBSECTION Standard>
+GstAlphaColorClass
+GST_ALPHA_COLOR
+GST_ALPHA_COLOR_CAST
+GST_IS_ALPHA_COLOR
+GST_ALPHA_COLOR_CLASS
+GST_IS_ALPHA_COLOR_CLASS
+GST_TYPE_ALPHA_COLOR
+<SUBSECTION Private>
+gst_alpha_color_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-amrparse</FILE>
+<TITLE>amrparse</TITLE>
+GstAmrParse
+<SUBSECTION Standard>
+GstAmrParseClass
+GST_AMR_PARSE
+GST_AMR_PARSE_CAST
+GST_IS_AMR_PARSE
+GST_AMR_PARSE_CLASS
+GST_IS_AMR_PARSE_CLASS
+GST_TYPE_AMR_PARSE
+<SUBSECTION Private>
+gst_amr_parse_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-apedemux</FILE>
+<TITLE>apedemux</TITLE>
+GstApeDemux
+<SUBSECTION Standard>
+GstApeDemuxClass
+GST_APE_DEMUX
+GST_APE_DEMUX_CAST
+GST_IS_APE_DEMUX
+GST_APE_DEMUX_CLASS
+GST_IS_APE_DEMUX_CLASS
+GST_TYPE_APE_DEMUX
+<SUBSECTION Private>
+gst_ape_demux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-apev2mux</FILE>
+<TITLE>apev2mux</TITLE>
+GstApev2Mux
+<SUBSECTION Standard>
+GstApev2MuxClass
+GST_APEV2_MUX
+GST_APEV2_MUX_CAST
+GST_IS_APEV2_MUX
+GST_APEV2_MUX_CLASS
+GST_IS_APEV2_MUX_CLASS
+GST_TYPE_APEV2_MUX
+<SUBSECTION Private>
+gst_apev2_mux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-aspectratiocrop</FILE>
+<TITLE>aspectratiocrop</TITLE>
+GstAspectRatioCrop
+<SUBSECTION Standard>
+GstAspectRatioCropClass
+GST_ASPECT_RATIO_CROP
+GST_ASPECT_RATIO_CROP_CAST
+GST_IS_ASPECT_RATIO_CROP
+GST_ASPECT_RATIO_CROP_CLASS
+GST_IS_ASPECT_RATIO_CROP_CLASS
+GST_TYPE_ASPECT_RATIO_CROP
+<SUBSECTION Private>
+gst_aspect_ratio_crop_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-asteriskh263</FILE>
+<TITLE>asteriskh263</TITLE>
+GstAsteriskh263
+<SUBSECTION Standard>
+GstAsteriskh263Class
+GST_ASTERISKH263
+GST_ASTERISKH263_CAST
+GST_IS_ASTERISKH263
+GST_ASTERISKH263_CLASS
+GST_IS_ASTERISKH263_CLASS
+GST_TYPE_ASTERISKH263
+<SUBSECTION Private>
+gst_asteriskh263_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-auparse</FILE>
+<TITLE>auparse</TITLE>
+GstAuParse
+<SUBSECTION Standard>
+GstAuParseClass
+GST_AU_PARSE
+GST_AU_PARSE_CAST
+GST_IS_AU_PARSE
+GST_AU_PARSE_CLASS
+GST_IS_AU_PARSE_CLASS
+GST_TYPE_AU_PARSE
+<SUBSECTION Private>
+gst_au_parse_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-audioamplify</FILE>
+<TITLE>audioamplify</TITLE>
+GstAudioAmplify
+GstAudioAmplifyClippingMethod
+<SUBSECTION Standard>
+GstAudioAmplifyClass
+GST_AUDIO_AMPLIFY
+GST_AUDIO_AMPLIFY_CAST
+GST_IS_AUDIO_AMPLIFY
+GST_AUDIO_AMPLIFY_CLASS
+GST_IS_AUDIO_AMPLIFY_CLASS
+GST_TYPE_AUDIO_AMPLIFY
+<SUBSECTION Private>
+gst_audio_amplify_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-audiochebband</FILE>
+<TITLE>audiochebband</TITLE>
+GstAudioChebBand
+GstAudioChebBandMode
+<SUBSECTION Standard>
+GstAudioChebBandClass
+GST_AUDIO_CHEB_BAND
+GST_AUDIO_CHEB_BAND_CAST
+GST_IS_AUDIO_CHEB_BAND
+GST_AUDIO_CHEB_BAND_CLASS
+GST_IS_AUDIO_CHEB_BAND_CLASS
+GST_TYPE_AUDIO_CHEB_BAND
+<SUBSECTION Private>
+gst_audio_cheb_band_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-audiocheblimit</FILE>
+<TITLE>audiocheblimit</TITLE>
+GstAudioChebLimit
+GstAudioChebLimitMode
+<SUBSECTION Standard>
+GstAudioChebLimitClass
+GST_AUDIO_CHEB_LIMIT
+GST_AUDIO_CHEB_LIMIT_CAST
+GST_IS_AUDIO_CHEB_LIMIT
+GST_AUDIO_CHEB_LIMIT_CLASS
+GST_IS_AUDIO_CHEB_LIMIT_CLASS
+GST_TYPE_AUDIO_CHEB_LIMIT
+<SUBSECTION Private>
+gst_audio_cheb_limit_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-audiodynamic</FILE>
+<TITLE>audiodynamic</TITLE>
+GstAudioDynamic
+GstAudioDynamicCharacteristics
+GstAudioDynamicMode
+<SUBSECTION Standard>
+GstAudioDynamicClass
+GST_AUDIO_DYNAMIC
+GST_AUDIO_DYNAMIC_CAST
+GST_IS_AUDIO_DYNAMIC
+GST_AUDIO_DYNAMIC_CLASS
+GST_IS_AUDIO_DYNAMIC_CLASS
+GST_TYPE_AUDIO_DYNAMIC
+<SUBSECTION Private>
+gst_audio_dynamic_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-audioecho</FILE>
+<TITLE>audioecho</TITLE>
+GstAudioEcho
+<SUBSECTION Standard>
+GstAudioEchoClass
+GST_AUDIO_ECHO
+GST_AUDIO_ECHO_CAST
+GST_IS_AUDIO_ECHO
+GST_AUDIO_ECHO_CLASS
+GST_IS_AUDIO_ECHO_CLASS
+GST_TYPE_AUDIO_ECHO
+<SUBSECTION Private>
+gst_audio_echo_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-audiofirfilter</FILE>
+<TITLE>audiofirfilter</TITLE>
+GstAudioFIRFilter
+<SUBSECTION Standard>
+GstAudioFIRFilterClass
+GST_AUDIO_FIR_FILTER
+GST_AUDIO_FIR_FILTER_CAST
+GST_IS_AUDIO_FIR_FILTER
+GST_AUDIO_FIR_FILTER_CLASS
+GST_IS_AUDIO_FIR_FILTER_CLASS
+GST_TYPE_AUDIO_FIR_FILTER
+<SUBSECTION Private>
+gst_audio_fir_filter_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-audioiirfilter</FILE>
+<TITLE>audioiirfilter</TITLE>
+GstAudioIIRFilter
+<SUBSECTION Standard>
+GstAudioIIRFilterClass
+GST_AUDIO_IIR_FILTER
+GST_AUDIO_IIR_FILTER_CAST
+GST_IS_AUDIO_IIR_FILTER
+GST_AUDIO_IIR_FILTER_CLASS
+GST_IS_AUDIO_IIR_FILTER_CLASS
+GST_TYPE_AUDIO_IIR_FILTER
+<SUBSECTION Private>
+gst_audio_iir_filter_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-audioinvert</FILE>
+<TITLE>audioinvert</TITLE>
+GstAudioInvert
+<SUBSECTION Standard>
+GstAudioInvertClass
+GST_AUDIO_INVERT
+GST_AUDIO_INVERT_CAST
+GST_IS_AUDIO_INVERT
+GST_AUDIO_INVERT_CLASS
+GST_IS_AUDIO_INVERT_CLASS
+GST_TYPE_AUDIO_INVERT
+<SUBSECTION Private>
+gst_audio_invert_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-audiokaraoke</FILE>
+<TITLE>audiokaraoke</TITLE>
+GstAudioKaraoke
+<SUBSECTION Standard>
+GstAudioKaraokeClass
+GST_AUDIO_KARAOKE
+GST_AUDIO_KARAOKE_CAST
+GST_IS_AUDIO_KARAOKE
+GST_AUDIO_KARAOKE_CLASS
+GST_IS_AUDIO_KARAOKE_CLASS
+GST_TYPE_AUDIO_KARAOKE
+<SUBSECTION Private>
+gst_audio_karaoke_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-audiopanorama</FILE>
+<TITLE>audiopanorama</TITLE>
+GstAudioPanorama
+GstAudioPanoramaMethod
+<SUBSECTION Standard>
+GstAudioPanoramaClass
+GST_AUDIO_PANORAMA
+GST_AUDIO_PANORAMA_CAST
+GST_IS_AUDIO_PANORAMA
+GST_AUDIO_PANORAMA_CLASS
+GST_IS_AUDIO_PANORAMA_CLASS
+GST_TYPE_AUDIO_PANORAMA
+<SUBSECTION Private>
+gst_audio_panorama_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-audiowsincband</FILE>
+<TITLE>audiowsincband</TITLE>
+GstAudioWSincBand
+GstAudioWSincBandMode
+GstAudioWSincBandWindow
+<SUBSECTION Standard>
+GstAudioWSincBandClass
+GST_AUDIO_W_SINC_BAND
+GST_AUDIO_W_SINC_BAND_CAST
+GST_IS_AUDIO_W_SINC_BAND
+GST_AUDIO_W_SINC_BAND_CLASS
+GST_IS_AUDIO_W_SINC_BAND_CLASS
+GST_TYPE_AUDIO_W_SINC_BAND
+<SUBSECTION Private>
+gst_audio_w_sinc_band_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-audiowsinclimit</FILE>
+<TITLE>audiowsinclimit</TITLE>
+GstAudioWSincLimit
+GstAudioWSincLimitMode
+GstAudioWSincLimitWindow
+<SUBSECTION Standard>
+GstAudioWSincLimitClass
+GST_AUDIO_W_SINC_LIMIT
+GST_AUDIO_W_SINC_LIMIT_CAST
+GST_IS_AUDIO_W_SINC_LIMIT
+GST_AUDIO_W_SINC_LIMIT_CLASS
+GST_IS_AUDIO_W_SINC_LIMIT_CLASS
+GST_TYPE_AUDIO_W_SINC_LIMIT
+<SUBSECTION Private>
+gst_audio_w_sinc_limit_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-autoaudiosink</FILE>
+<TITLE>autoaudiosink</TITLE>
+GstAutoAudioSink
+<SUBSECTION Standard>
+GstAutoAudioSinkClass
+GST_AUTO_AUDIO_SINK
+GST_AUTO_AUDIO_SINK_CAST
+GST_IS_AUTO_AUDIO_SINK
+GST_AUTO_AUDIO_SINK_CLASS
+GST_IS_AUTO_AUDIO_SINK_CLASS
+GST_TYPE_AUTO_AUDIO_SINK
+<SUBSECTION Private>
+gst_auto_audio_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-autoaudiosrc</FILE>
+<TITLE>autoaudiosrc</TITLE>
+GstAutoAudioSrc
+<SUBSECTION Standard>
+GstAutoAudioSrcClass
+GST_AUTO_AUDIO_SRC
+GST_AUTO_AUDIO_SRC_CAST
+GST_IS_AUTO_AUDIO_SRC
+GST_AUTO_AUDIO_SRC_CLASS
+GST_IS_AUTO_AUDIO_SRC_CLASS
+GST_TYPE_AUTO_AUDIO_SRC
+<SUBSECTION Private>
+gst_auto_audio_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-autovideosink</FILE>
+<TITLE>autovideosink</TITLE>
+GstAutoVideoSink
+<SUBSECTION Standard>
+GstAutoVideoSinkClass
+GST_AUTO_VIDEO_SINK
+GST_AUTO_VIDEO_SINK_CAST
+GST_IS_AUTO_VIDEO_SINK
+GST_AUTO_VIDEO_SINK_CLASS
+GST_IS_AUTO_VIDEO_SINK_CLASS
+GST_TYPE_AUTO_VIDEO_SINK
+<SUBSECTION Private>
+gst_auto_video_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-autovideosrc</FILE>
+<TITLE>autovideosrc</TITLE>
+GstAutoVideoSrc
+<SUBSECTION Standard>
+GstAutoVideoSrcClass
+GST_AUTO_VIDEO_SRC
+GST_AUTO_VIDEO_SRC_CAST
+GST_IS_AUTO_VIDEO_SRC
+GST_AUTO_VIDEO_SRC_CLASS
+GST_IS_AUTO_VIDEO_SRC_CLASS
+GST_TYPE_AUTO_VIDEO_SRC
+<SUBSECTION Private>
+gst_auto_video_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-avidemux</FILE>
+<TITLE>avidemux</TITLE>
+GstAviDemux
+<SUBSECTION Standard>
+GstAviDemuxClass
+GST_AVI_DEMUX
+GST_AVI_DEMUX_CAST
+GST_IS_AVI_DEMUX
+GST_AVI_DEMUX_CLASS
+GST_IS_AVI_DEMUX_CLASS
+GST_TYPE_AVI_DEMUX
+<SUBSECTION Private>
+gst_avi_demux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-avimux</FILE>
+<TITLE>avimux</TITLE>
+GstAviMux
+<SUBSECTION Standard>
+GstAviMuxClass
+GST_AVI_MUX
+GST_AVI_MUX_CAST
+GST_IS_AVI_MUX
+GST_AVI_MUX_CLASS
+GST_IS_AVI_MUX_CLASS
+GST_TYPE_AVI_MUX
+<SUBSECTION Private>
+gst_avi_mux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-avisubtitle</FILE>
+<TITLE>avisubtitle</TITLE>
+GstAviSubtitle
+<SUBSECTION Standard>
+GstAviSubtitleClass
+GST_AVI_SUBTITLE
+GST_AVI_SUBTITLE_CAST
+GST_IS_AVI_SUBTITLE
+GST_AVI_SUBTITLE_CLASS
+GST_IS_AVI_SUBTITLE_CLASS
+GST_TYPE_AVI_SUBTITLE
+<SUBSECTION Private>
+gst_avi_subtitle_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-breakmydata</FILE>
+<TITLE>breakmydata</TITLE>
+GstBreakMyData
+<SUBSECTION Standard>
+GstBreakMyDataClass
+GST_BREAK_MY_DATA
+GST_BREAK_MY_DATA_CAST
+GST_IS_BREAK_MY_DATA
+GST_BREAK_MY_DATA_CLASS
+GST_IS_BREAK_MY_DATA_CLASS
+GST_TYPE_BREAK_MY_DATA
+<SUBSECTION Private>
+gst_break_my_data_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-cacasink</FILE>
+<TITLE>cacasink</TITLE>
+GstCACASink
+GstCACASinkDithering
+<SUBSECTION Standard>
+GstCACASinkClass
+GST_CACA_SINK
+GST_CACA_SINK_CAST
+GST_IS_CACA_SINK
+GST_CACA_SINK_CLASS
+GST_IS_CACA_SINK_CLASS
+GST_TYPE_CACA_SINK
+<SUBSECTION Private>
+gst_caca_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-cairooverlay</FILE>
+<TITLE>cairooverlay</TITLE>
+GstCairoOverlay
+<SUBSECTION Standard>
+GstCairoOverlayClass
+GST_CAIRO_OVERLAY
+GST_CAIRO_OVERLAY_CAST
+GST_IS_CAIRO_OVERLAY
+GST_CAIRO_OVERLAY_CLASS
+GST_IS_CAIRO_OVERLAY_CLASS
+GST_TYPE_CAIRO_OVERLAY
+<SUBSECTION Private>
+gst_cairo_overlay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-capssetter</FILE>
+<TITLE>capssetter</TITLE>
+GstCapsSetter
+<SUBSECTION Standard>
+GstCapsSetterClass
+GST_CAPS_SETTER
+GST_CAPS_SETTER_CAST
+GST_IS_CAPS_SETTER
+GST_CAPS_SETTER_CLASS
+GST_IS_CAPS_SETTER_CLASS
+GST_TYPE_CAPS_SETTER
+<SUBSECTION Private>
+gst_caps_setter_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-cpureport</FILE>
+<TITLE>cpureport</TITLE>
+GstCpuReport
+<SUBSECTION Standard>
+GstCpuReportClass
+GST_CPU_REPORT
+GST_CPU_REPORT_CAST
+GST_IS_CPU_REPORT
+GST_CPU_REPORT_CLASS
+GST_IS_CPU_REPORT_CLASS
+GST_TYPE_CPU_REPORT
+<SUBSECTION Private>
+gst_cpu_report_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-cutter</FILE>
+<TITLE>cutter</TITLE>
+GstCutter
+<SUBSECTION Standard>
+GstCutterClass
+GST_CUTTER
+GST_CUTTER_CAST
+GST_IS_CUTTER
+GST_CUTTER_CLASS
+GST_IS_CUTTER_CLASS
+GST_TYPE_CUTTER
+<SUBSECTION Private>
+gst_cutter_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-directsoundsink</FILE>
+<TITLE>directsoundsink</TITLE>
+GstDirectSoundSink
+<SUBSECTION Standard>
+GstDirectSoundSinkClass
+GST_DIRECTSOUND_SINK
+GST_DIRECTSOUND_SINK_CLASS
+GST_IS_DIRECTSOUND_SINK
+GST_IS_DIRECTSOUND_SINK_CLASS
+GST_TYPE_DIRECTSOUND_SINK
+gst_directsound_sink_get_type
+GST_DSOUND_LOCK
+GST_DSOUND_UNLOCK
+</SECTION>
+
+<SECTION>
+<FILE>element-dtmfsrc</FILE>
+<TITLE>dtmfsrc</TITLE>
+GstDTMFSrc
+<SUBSECTION Standard>
+GstDTMFSrcClass
+GST_DTMF_SRC
+GST_DTMF_SRC_CAST
+GST_IS_DTMF_SRC
+GST_DTMF_SRC_CLASS
+GST_IS_DTMF_SRC_CLASS
+GST_TYPE_DTMF_SRC
+<SUBSECTION Private>
+gst_dtmf_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-dv1394src</FILE>
+<TITLE>dv1394src</TITLE>
+GstDV1394Src
+<SUBSECTION Standard>
+GstDV1394SrcClass
+GST_D_V1394_SRC
+GST_D_V1394_SRC_CAST
+GST_IS_D_V1394_SRC
+GST_D_V1394_SRC_CLASS
+GST_IS_D_V1394_SRC_CLASS
+GST_TYPE_D_V1394_SRC
+<SUBSECTION Private>
+gst_d_v1394_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-dvdec</FILE>
+<TITLE>dvdec</TITLE>
+GstDVDec
+GstDVDecQualityEnum
+<SUBSECTION Standard>
+GstDVDecClass
+GST_DV_DEC
+GST_DV_DEC_CAST
+GST_IS_DV_DEC
+GST_DV_DEC_CLASS
+GST_IS_DV_DEC_CLASS
+GST_TYPE_DV_DEC
+<SUBSECTION Private>
+gst_dv_dec_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-dvdemux</FILE>
+<TITLE>dvdemux</TITLE>
+GstDVDemux
+<SUBSECTION Standard>
+GstDVDemuxClass
+GST_DV_DEMUX
+GST_DV_DEMUX_CAST
+GST_IS_DV_DEMUX
+GST_DV_DEMUX_CLASS
+GST_IS_DV_DEMUX_CLASS
+GST_TYPE_DV_DEMUX
+<SUBSECTION Private>
+gst_dv_demux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-dcaparse</FILE>
+<TITLE>dcaparse</TITLE>
+GstDcaParse
+<SUBSECTION Standard>
+GstDcaParseClass
+GST_DCA_PARSE
+GST_DCA_PARSE_CAST
+GST_IS_DCA_PARSE
+GST_DCA_PARSE_CLASS
+GST_IS_DCA_PARSE_CLASS
+GST_TYPE_DCA_PARSE
+<SUBSECTION Private>
+gst_dca_parse_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-deinterlace</FILE>
+<TITLE>deinterlace</TITLE>
+GstDeinterlace
+GstDeinterlaceFields
+GstDeinterlaceLocking
+GstDeinterlaceMethods
+GstDeinterlaceModes
+GstDeinterlaceFieldLayout
+<SUBSECTION Standard>
+GstDeinterlaceClass
+GST_DEINTERLACE
+GST_DEINTERLACE_CAST
+GST_IS_DEINTERLACE
+GST_DEINTERLACE_CLASS
+GST_IS_DEINTERLACE_CLASS
+GST_TYPE_DEINTERLACE
+<SUBSECTION Private>
+gst_deinterlace_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-deinterleave</FILE>
+<TITLE>deinterleave</TITLE>
+GstDeinterleave
+<SUBSECTION Standard>
+GstDeinterleaveClass
+GST_DEINTERLEAVE
+GST_DEINTERLEAVE_CAST
+GST_IS_DEINTERLEAVE
+GST_DEINTERLEAVE_CLASS
+GST_IS_DEINTERLEAVE_CLASS
+GST_TYPE_DEINTERLEAVE
+<SUBSECTION Private>
+gst_deinterleave_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-dicetv</FILE>
+<TITLE>dicetv</TITLE>
+GstDiceTV
+<SUBSECTION Standard>
+GstDiceTVClass
+GST_DICE_TV
+GST_DICE_TV_CAST
+GST_IS_DICE_TV
+GST_DICE_TV_CLASS
+GST_IS_DICE_TV_CLASS
+GST_TYPE_DICE_TV
+<SUBSECTION Private>
+gst_dice_tv_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-dynudpsink</FILE>
+<TITLE>dynudpsink</TITLE>
+GstDynUDPSink
+<SUBSECTION Standard>
+GstDynUDPSinkClass
+GST_DYN_UDP_SINK
+GST_DYN_UDP_SINK_CAST
+GST_IS_DYN_UDP_SINK
+GST_DYN_UDP_SINK_CLASS
+GST_IS_DYN_UDP_SINK_CLASS
+GST_TYPE_DYN_UDP_SINK
+<SUBSECTION Private>
+gst_dyn_udp_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-edgetv</FILE>
+<TITLE>edgetv</TITLE>
+GstEdgeTV
+<SUBSECTION Standard>
+GstEdgeTVClass
+GST_EDGE_TV
+GST_EDGE_TV_CAST
+GST_IS_EDGE_TV
+GST_EDGE_TV_CLASS
+GST_IS_EDGE_TV_CLASS
+GST_TYPE_EDGE_TV
+<SUBSECTION Private>
+gst_edge_tv_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-flacdec</FILE>
+<TITLE>flacdec</TITLE>
+GstFlacDec
+<SUBSECTION Standard>
+GstFlacDecClass
+GST_FLAC_DEC
+GST_FLAC_DEC_CAST
+GST_IS_FLAC_DEC
+GST_FLAC_DEC_CLASS
+GST_IS_FLAC_DEC_CLASS
+GST_TYPE_FLAC_DEC
+<SUBSECTION Private>
+gst_flac_dec_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-flacenc</FILE>
+<TITLE>flacenc</TITLE>
+GstFlacEnc
+GstFlacEncQuality
+<SUBSECTION Standard>
+GstFlacEncClass
+GST_FLAC_ENC
+GST_FLAC_ENC_CAST
+GST_IS_FLAC_ENC
+GST_FLAC_ENC_CLASS
+GST_IS_FLAC_ENC_CLASS
+GST_TYPE_FLAC_ENC
+<SUBSECTION Private>
+gst_flac_enc_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-flacparse</FILE>
+<TITLE>flacparse</TITLE>
+GstFlacParse
+<SUBSECTION Standard>
+GstFlacParseClass
+GST_FLAC_PARSE
+GST_FLAC_PARSE_CAST
+GST_IS_FLAC_PARSE
+GST_FLAC_PARSE_CLASS
+GST_IS_FLAC_PARSE_CLASS
+GST_TYPE_FLAC_PARSE
+<SUBSECTION Private>
+gst_flac_parse_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-flactag</FILE>
+<TITLE>flactag</TITLE>
+GstFlacTag
+<SUBSECTION Standard>
+GstFlacTagClass
+GST_FLAC_TAG
+GST_FLAC_TAG_CAST
+GST_IS_FLAC_TAG
+GST_FLAC_TAG_CLASS
+GST_IS_FLAC_TAG_CLASS
+GST_TYPE_FLAC_TAG
+<SUBSECTION Private>
+gst_flac_tag_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-flvdemux</FILE>
+<TITLE>flvdemux</TITLE>
+GstFlvDemux
+<SUBSECTION Standard>
+GstFlvDemuxClass
+GST_FLV_DEMUX
+GST_FLV_DEMUX_CAST
+GST_IS_FLV_DEMUX
+GST_FLV_DEMUX_CLASS
+GST_IS_FLV_DEMUX_CLASS
+GST_TYPE_FLV_DEMUX
+<SUBSECTION Private>
+gst_flv_demux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-flvmux</FILE>
+<TITLE>flvmux</TITLE>
+GstFlvMux
+<SUBSECTION Standard>
+GstFlvMuxClass
+GST_FLV_MUX
+GST_FLV_MUX_CAST
+GST_IS_FLV_MUX
+GST_FLV_MUX_CLASS
+GST_IS_FLV_MUX_CLASS
+GST_TYPE_FLV_MUX
+<SUBSECTION Private>
+gst_flv_mux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-flxdec</FILE>
+<TITLE>flxdec</TITLE>
+GstFlxDec
+<SUBSECTION Standard>
+GstFlxDecClass
+GST_FLX_DEC
+GST_FLX_DEC_CAST
+GST_IS_FLX_DEC
+GST_FLX_DEC_CLASS
+GST_IS_FLX_DEC_CLASS
+GST_TYPE_FLX_DEC
+<SUBSECTION Private>
+gst_flx_dec_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-gamma</FILE>
+<TITLE>gamma</TITLE>
+GstGamma
+<SUBSECTION Standard>
+GstGammaClass
+GST_GAMMA
+GST_GAMMA_CAST
+GST_IS_GAMMA
+GST_GAMMA_CLASS
+GST_IS_GAMMA_CLASS
+GST_TYPE_GAMMA
+<SUBSECTION Private>
+gst_gamma_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-gdkpixbufdec</FILE>
+<TITLE>gdkpixbufdec</TITLE>
+GstGdkPixbufDec
+<SUBSECTION Standard>
+GstGdkPixbufDecClass
+GST_GDK_PIXBUF_DEC
+GST_GDK_PIXBUF_DEC_CAST
+GST_IS_GDK_PIXBUF_DEC
+GST_GDK_PIXBUF_DEC_CLASS
+GST_IS_GDK_PIXBUF_DEC_CLASS
+GST_TYPE_GDK_PIXBUF_DEC
+<SUBSECTION Private>
+gst_gdk_pixbuf_dec_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-gdkpixbufoverlay</FILE>
+<TITLE>gdkpixbufoverlay</TITLE>
+GstGdkPixbufOverlay
+<SUBSECTION Standard>
+GstGdkPixbufOverlayClass
+GST_GDK_PIXBUF_OVERLAY
+GST_GDK_PIXBUF_OVERLAY_CAST
+GST_IS_GDK_PIXBUF_OVERLAY
+GST_GDK_PIXBUF_OVERLAY_CLASS
+GST_IS_GDK_PIXBUF_OVERLAY_CLASS
+GST_TYPE_GDK_PIXBUF_OVERLAY
+<SUBSECTION Private>
+gst_gdk_pixbuf_overlay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-gdkpixbufsink</FILE>
+<TITLE>gdkpixbufsink</TITLE>
+GstGdkPixbufSink
+<SUBSECTION Standard>
+GstGdkPixbufSinkClass
+GST_GDK_PIXBUF_SINK
+GST_GDK_PIXBUF_SINK_CAST
+GST_IS_GDK_PIXBUF_SINK
+GST_GDK_PIXBUF_SINK_CLASS
+GST_IS_GDK_PIXBUF_SINK_CLASS
+GST_TYPE_GDK_PIXBUF_SINK
+<SUBSECTION Private>
+gst_gdk_pixbuf_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-goom</FILE>
+<TITLE>goom</TITLE>
+GstGoom
+<SUBSECTION Standard>
+GstGoomClass
+GST_GOOM
+GST_GOOM_CAST
+GST_IS_GOOM
+GST_GOOM_CLASS
+GST_IS_GOOM_CLASS
+GST_TYPE_GOOM
+<SUBSECTION Private>
+gst_goom_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-goom2k1</FILE>
+<TITLE>goom2k1</TITLE>
+GstGoom2k1
+<SUBSECTION Standard>
+GstGoom2k1Class
+GST_GOOM2K1
+GST_GOOM2K1_CAST
+GST_IS_GOOM2K1
+GST_GOOM2K1_CLASS
+GST_IS_GOOM2K1_CLASS
+GST_TYPE_GOOM2K1
+<SUBSECTION Private>
+gst_goom2k1_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-hdv1394src</FILE>
+<TITLE>hdv1394src</TITLE>
+GstHDV1394Src
+<SUBSECTION Standard>
+GstHDV1394SrcClass
+GST_HD_V1394_SRC
+GST_HD_V1394_SRC_CAST
+GST_IS_HD_V1394_SRC
+GST_HD_V1394_SRC_CLASS
+GST_IS_HD_V1394_SRC_CLASS
+GST_TYPE_HD_V1394_SRC
+<SUBSECTION Private>
+gst_hd_v1394_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-icydemux</FILE>
+<TITLE>icydemux</TITLE>
+GstICYDemux
+<SUBSECTION Standard>
+GstICYDemuxClass
+GST_ICY_DEMUX
+GST_ICY_DEMUX_CAST
+GST_IS_ICY_DEMUX
+GST_ICY_DEMUX_CLASS
+GST_IS_ICY_DEMUX_CLASS
+GST_TYPE_ICY_DEMUX
+<SUBSECTION Private>
+gst_icy_demux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-id3demux</FILE>
+<TITLE>id3demux</TITLE>
+GstID3Demux
+<SUBSECTION Standard>
+GstID3DemuxClass
+GST_I_D3_DEMUX
+GST_I_D3_DEMUX_CAST
+GST_IS_I_D3_DEMUX
+GST_I_D3_DEMUX_CLASS
+GST_IS_I_D3_DEMUX_CLASS
+GST_TYPE_I_D3_DEMUX
+<SUBSECTION Private>
+gst_i_d3_demux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-ismlmux</FILE>
+<TITLE>ismlmux</TITLE>
+GstISMLMux
+<SUBSECTION Standard>
+GstISMLMuxClass
+GST_ISML_MUX
+GST_ISML_MUX_CAST
+GST_IS_ISML_MUX
+GST_ISML_MUX_CLASS
+GST_IS_ISML_MUX_CLASS
+GST_TYPE_ISML_MUX
+<SUBSECTION Private>
+gst_isml_mux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-id3v2mux</FILE>
+<TITLE>id3v2mux</TITLE>
+GstId3v2Mux
+<SUBSECTION Standard>
+GstId3v2MuxClass
+GST_ID3V2_MUX
+GST_ID3V2_MUX_CAST
+GST_IS_ID3V2_MUX
+GST_ID3V2_MUX_CLASS
+GST_IS_ID3V2_MUX_CLASS
+GST_TYPE_ID3V2_MUX
+<SUBSECTION Private>
+gst_id3v2_mux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-iirequalizer</FILE>
+<TITLE>iirequalizer</TITLE>
+GstIirEqualizer
+<SUBSECTION Standard>
+GstIirEqualizerClass
+GST_IIR_EQUALIZER
+GST_IIR_EQUALIZER_CAST
+GST_IS_IIR_EQUALIZER
+GST_IIR_EQUALIZER_CLASS
+GST_IS_IIR_EQUALIZER_CLASS
+GST_TYPE_IIR_EQUALIZER
+<SUBSECTION Private>
+gst_iir_equalizer_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-equalizer-10bands</FILE>
+<TITLE>equalizer-10bands</TITLE>
+GstIirEqualizer10Bands
+<SUBSECTION Standard>
+GstIirEqualizer10BandsClass
+GST_IIR_EQUALIZER10_BANDS
+GST_IIR_EQUALIZER10_BANDS_CAST
+GST_IS_IIR_EQUALIZER10_BANDS
+GST_IIR_EQUALIZER10_BANDS_CLASS
+GST_IS_IIR_EQUALIZER10_BANDS_CLASS
+GST_TYPE_IIR_EQUALIZER10_BANDS
+<SUBSECTION Private>
+gst_iir_equalizer10_bands_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-equalizer-3bands</FILE>
+<TITLE>equalizer-3bands</TITLE>
+GstIirEqualizer3Bands
+<SUBSECTION Standard>
+GstIirEqualizer3BandsClass
+GST_IIR_EQUALIZER3_BANDS
+GST_IIR_EQUALIZER3_BANDS_CAST
+GST_IS_IIR_EQUALIZER3_BANDS
+GST_IIR_EQUALIZER3_BANDS_CLASS
+GST_IS_IIR_EQUALIZER3_BANDS_CLASS
+GST_TYPE_IIR_EQUALIZER3_BANDS
+<SUBSECTION Private>
+gst_iir_equalizer3_bands_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-equalizer-nbands</FILE>
+<TITLE>equalizer-nbands</TITLE>
+GstIirEqualizerNBands
+<SUBSECTION Standard>
+GstIirEqualizerNBandsClass
+GST_IIR_EQUALIZER_N_BANDS
+GST_IIR_EQUALIZER_N_BANDS_CAST
+GST_IS_IIR_EQUALIZER_N_BANDS
+GST_IIR_EQUALIZER_N_BANDS_CLASS
+GST_IS_IIR_EQUALIZER_N_BANDS_CLASS
+GST_TYPE_IIR_EQUALIZER_N_BANDS
+<SUBSECTION Private>
+gst_iir_equalizer_n_bands_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-imagefreeze</FILE>
+<TITLE>imagefreeze</TITLE>
+GstImageFreeze
+<SUBSECTION Standard>
+GstImageFreezeClass
+GST_IMAGE_FREEZE
+GST_IMAGE_FREEZE_CAST
+GST_IS_IMAGE_FREEZE
+GST_IMAGE_FREEZE_CLASS
+GST_IS_IMAGE_FREEZE_CLASS
+GST_TYPE_IMAGE_FREEZE
+<SUBSECTION Private>
+gst_image_freeze_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-interleave</FILE>
+<TITLE>interleave</TITLE>
+GstInterleave
+<SUBSECTION Standard>
+GstInterleaveClass
+GST_INTERLEAVE
+GST_INTERLEAVE_CAST
+GST_IS_INTERLEAVE
+GST_INTERLEAVE_CLASS
+GST_IS_INTERLEAVE_CLASS
+GST_TYPE_INTERLEAVE
+<SUBSECTION Private>
+gst_interleave_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-jackaudiosink</FILE>
+<TITLE>jackaudiosink</TITLE>
+GstJackAudioSink
+<SUBSECTION Standard>
+GstJackAudioSinkClass
+GST_JACK_AUDIO_SINK
+GST_JACK_AUDIO_SINK_CAST
+GST_IS_JACK_AUDIO_SINK
+GST_JACK_AUDIO_SINK_CLASS
+GST_IS_JACK_AUDIO_SINK_CLASS
+GST_TYPE_JACK_AUDIO_SINK
+<SUBSECTION Private>
+gst_jack_audio_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-jackaudiosrc</FILE>
+<TITLE>jackaudiosrc</TITLE>
+GstJackAudioSrc
+<SUBSECTION Standard>
+GstJackAudioSrcClass
+GST_JACK_AUDIO_SRC
+GST_JACK_AUDIO_SRC_CAST
+GST_IS_JACK_AUDIO_SRC
+GST_JACK_AUDIO_SRC_CLASS
+GST_IS_JACK_AUDIO_SRC_CLASS
+GST_TYPE_JACK_AUDIO_SRC
+<SUBSECTION Private>
+gst_jack_audio_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-jpegdec</FILE>
+<TITLE>jpegdec</TITLE>
+GstJpegDec
+<SUBSECTION Standard>
+GstJpegDecClass
+GST_JPEG_DEC
+GST_JPEG_DEC_CAST
+GST_IS_JPEG_DEC
+GST_JPEG_DEC_CLASS
+GST_IS_JPEG_DEC_CLASS
+GST_TYPE_JPEG_DEC
+<SUBSECTION Private>
+gst_jpeg_dec_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-jpegenc</FILE>
+<TITLE>jpegenc</TITLE>
+GstJpegEnc
+<SUBSECTION Standard>
+GstJpegEncClass
+GST_JPEG_ENC
+GST_JPEG_ENC_CAST
+GST_IS_JPEG_ENC
+GST_JPEG_ENC_CLASS
+GST_IS_JPEG_ENC_CLASS
+GST_TYPE_JPEG_ENC
+<SUBSECTION Private>
+gst_jpeg_enc_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-lamemp3enc</FILE>
+<TITLE>lamemp3enc</TITLE>
+GstLameMP3Enc
+<SUBSECTION Standard>
+GstLameMP3EncClass
+GST_LAMEMP3ENC
+GST_LAMEMP3ENC_CLASS
+GST_IS_LAMEMP3ENC
+GST_IS_LAMEMP3ENC_CLASS
+GST_TYPE_LAMEMP3ENC
+gst_lamemp3enc_get_type
+gst_lamemp3enc_register
+</SECTION>
+
+<SECTION>
+<FILE>element-level</FILE>
+<TITLE>level</TITLE>
+GstLevel
+<SUBSECTION Standard>
+GstLevelClass
+GST_LEVEL
+GST_LEVEL_CAST
+GST_IS_LEVEL
+GST_LEVEL_CLASS
+GST_IS_LEVEL_CLASS
+GST_TYPE_LEVEL
+<SUBSECTION Private>
+gst_level_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-mj2mux</FILE>
+<TITLE>mj2mux</TITLE>
+GstMJ2Mux
+<SUBSECTION Standard>
+GstMJ2MuxClass
+GST_M_J2_MUX
+GST_M_J2_MUX_CAST
+GST_IS_M_J2_MUX
+GST_M_J2_MUX_CLASS
+GST_IS_M_J2_MUX_CLASS
+GST_TYPE_M_J2_MUX
+<SUBSECTION Private>
+gst_m_j2_mux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-mp4mux</FILE>
+<TITLE>mp4mux</TITLE>
+GstMP4Mux
+<SUBSECTION Standard>
+GstMP4MuxClass
+GST_M_P4_MUX
+GST_M_P4_MUX_CAST
+GST_IS_M_P4_MUX
+GST_M_P4_MUX_CLASS
+GST_IS_M_P4_MUX_CLASS
+GST_TYPE_M_P4_MUX
+<SUBSECTION Private>
+gst_m_p4_mux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-matroskademux</FILE>
+<TITLE>matroskademux</TITLE>
+GstMatroskaDemux
+<SUBSECTION Standard>
+GstMatroskaDemuxClass
+GST_MATROSKA_DEMUX
+GST_MATROSKA_DEMUX_CAST
+GST_IS_MATROSKA_DEMUX
+GST_MATROSKA_DEMUX_CLASS
+GST_IS_MATROSKA_DEMUX_CLASS
+GST_TYPE_MATROSKA_DEMUX
+<SUBSECTION Private>
+gst_matroska_demux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-matroskamux</FILE>
+<TITLE>matroskamux</TITLE>
+GstMatroskaMux
+<SUBSECTION Standard>
+GstMatroskaMuxClass
+GST_MATROSKA_MUX
+GST_MATROSKA_MUX_CAST
+GST_IS_MATROSKA_MUX
+GST_MATROSKA_MUX_CLASS
+GST_IS_MATROSKA_MUX_CLASS
+GST_TYPE_MATROSKA_MUX
+<SUBSECTION Private>
+gst_matroska_mux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-monoscope</FILE>
+<TITLE>monoscope</TITLE>
+GstMonoscope
+<SUBSECTION Standard>
+GstMonoscopeClass
+GST_MONOSCOPE
+GST_IS_MONOSCOPE
+GST_TYPE_MONOSCOPE
+GST_MONOSCOPE_CLASS
+GST_IS_MONOSCOPE_CLASS
+gst_monoscope_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-matroskaparse</FILE>
+<TITLE>matroskaparse</TITLE>
+GstMatroskaParse
+<SUBSECTION Standard>
+GstMatroskaParseClass
+GST_MATROSKA_PARSE
+GST_MATROSKA_PARSE_CAST
+GST_IS_MATROSKA_PARSE
+GST_MATROSKA_PARSE_CLASS
+GST_IS_MATROSKA_PARSE_CLASS
+GST_TYPE_MATROSKA_PARSE
+<SUBSECTION Private>
+gst_matroska_parse_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-mpegaudioparse</FILE>
+<TITLE>mpegaudioparse</TITLE>
+GstMpegAudioParse
+<SUBSECTION Standard>
+GstMpegAudioParseClass
+GST_MPEG_AUDIO_PARSE
+GST_MPEG_AUDIO_PARSE_CAST
+GST_IS_MPEG_AUDIO_PARSE
+GST_MPEG_AUDIO_PARSE_CLASS
+GST_IS_MPEG_AUDIO_PARSE_CLASS
+GST_TYPE_MPEG_AUDIO_PARSE
+<SUBSECTION Private>
+gst_mpeg_audio_parse_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-mpg123audiodec</FILE>
+<TITLE>mpg123audiodec</TITLE>
+GstMpg123AudioDec
+<SUBSECTION Standard>
+GstMpg123AudioDecClass
+GST_MPG123_AUDIO_DEC
+GST_MPG123_AUDIO_DEC_CLASS
+GST_IS_MPG123_AUDIO_DEC
+GST_IS_MPG123_AUDIO_DEC_CLASS
+GST_TYPE_MPG123_AUDIO_DEC
+gst_mpg123_audio_dec_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-mulawdec</FILE>
+<TITLE>mulawdec</TITLE>
+GstMuLawDec
+<SUBSECTION Standard>
+GstMuLawDecClass
+GST_MU_LAW_DEC
+GST_MU_LAW_DEC_CAST
+GST_IS_MU_LAW_DEC
+GST_MU_LAW_DEC_CLASS
+GST_IS_MU_LAW_DEC_CLASS
+GST_TYPE_MU_LAW_DEC
+<SUBSECTION Private>
+gst_mu_law_dec_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-mulawenc</FILE>
+<TITLE>mulawenc</TITLE>
+GstMuLawEnc
+<SUBSECTION Standard>
+GstMuLawEncClass
+GST_MU_LAW_ENC
+GST_MU_LAW_ENC_CAST
+GST_IS_MU_LAW_ENC
+GST_MU_LAW_ENC_CLASS
+GST_IS_MU_LAW_ENC_CLASS
+GST_TYPE_MU_LAW_ENC
+<SUBSECTION Private>
+gst_mu_law_enc_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-multifilesink</FILE>
+<TITLE>multifilesink</TITLE>
+GstMultiFileSink
+GstMultiFileSinkNext
+<SUBSECTION Standard>
+GstMultiFileSinkClass
+GST_MULTI_FILE_SINK
+GST_MULTI_FILE_SINK_CAST
+GST_IS_MULTI_FILE_SINK
+GST_MULTI_FILE_SINK_CLASS
+GST_IS_MULTI_FILE_SINK_CLASS
+GST_TYPE_MULTI_FILE_SINK
+<SUBSECTION Private>
+gst_multi_file_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-multifilesrc</FILE>
+<TITLE>multifilesrc</TITLE>
+GstMultiFileSrc
+<SUBSECTION Standard>
+GstMultiFileSrcClass
+GST_MULTI_FILE_SRC
+GST_MULTI_FILE_SRC_CAST
+GST_IS_MULTI_FILE_SRC
+GST_MULTI_FILE_SRC_CLASS
+GST_IS_MULTI_FILE_SRC_CLASS
+GST_TYPE_MULTI_FILE_SRC
+<SUBSECTION Private>
+gst_multi_file_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-multiudpsink</FILE>
+<TITLE>multiudpsink</TITLE>
+GstMultiUDPSink
+<SUBSECTION Standard>
+GstMultiUDPSinkClass
+GST_MULTI_UDP_SINK
+GST_MULTI_UDP_SINK_CAST
+GST_IS_MULTI_UDP_SINK
+GST_MULTI_UDP_SINK_CLASS
+GST_IS_MULTI_UDP_SINK_CLASS
+GST_TYPE_MULTI_UDP_SINK
+<SUBSECTION Private>
+gst_multi_udp_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-multipartdemux</FILE>
+<TITLE>multipartdemux</TITLE>
+GstMultipartDemux
+<SUBSECTION Standard>
+GstMultipartDemuxClass
+GST_MULTIPART_DEMUX
+GST_MULTIPART_DEMUX_CAST
+GST_IS_MULTIPART_DEMUX
+GST_MULTIPART_DEMUX_CLASS
+GST_IS_MULTIPART_DEMUX_CLASS
+GST_TYPE_MULTIPART_DEMUX
+<SUBSECTION Private>
+gst_multipart_demux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-multipartmux</FILE>
+<TITLE>multipartmux</TITLE>
+GstMultipartMux
+<SUBSECTION Standard>
+GstMultipartMuxClass
+GST_MULTIPART_MUX
+GST_MULTIPART_MUX_CAST
+GST_IS_MULTIPART_MUX
+GST_MULTIPART_MUX_CLASS
+GST_IS_MULTIPART_MUX_CLASS
+GST_TYPE_MULTIPART_MUX
+<SUBSECTION Private>
+gst_multipart_mux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-navseek</FILE>
+<TITLE>navseek</TITLE>
+GstNavSeek
+<SUBSECTION Standard>
+GstNavSeekClass
+GST_NAV_SEEK
+GST_NAV_SEEK_CAST
+GST_IS_NAV_SEEK
+GST_NAV_SEEK_CLASS
+GST_IS_NAV_SEEK_CLASS
+GST_TYPE_NAV_SEEK
+<SUBSECTION Private>
+gst_nav_seek_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-navigationtest</FILE>
+<TITLE>navigationtest</TITLE>
+GstNavigationtest
+<SUBSECTION Standard>
+GstNavigationtestClass
+GST_NAVIGATIONTEST
+GST_NAVIGATIONTEST_CAST
+GST_IS_NAVIGATIONTEST
+GST_NAVIGATIONTEST_CLASS
+GST_IS_NAVIGATIONTEST_CLASS
+GST_TYPE_NAVIGATIONTEST
+<SUBSECTION Private>
+gst_navigationtest_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-optv</FILE>
+<TITLE>optv</TITLE>
+GstOpTV
+GstOpTVMode
+<SUBSECTION Standard>
+GstOpTVClass
+GST_OP_TV
+GST_OP_TV_CAST
+GST_IS_OP_TV
+GST_OP_TV_CLASS
+GST_IS_OP_TV_CLASS
+GST_TYPE_OP_TV
+<SUBSECTION Private>
+gst_op_tv_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-oss4sink</FILE>
+<TITLE>oss4sink</TITLE>
+GstOss4Sink
+<SUBSECTION Standard>
+GstOss4SinkClass
+GST_OSS4_SINK
+GST_OSS4_SINK_CAST
+GST_IS_OSS4_SINK
+GST_OSS4_SINK_CLASS
+GST_IS_OSS4_SINK_CLASS
+GST_TYPE_OSS4_SINK
+<SUBSECTION Private>
+gst_oss4_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-oss4src</FILE>
+<TITLE>oss4src</TITLE>
+GstOss4Source
+<SUBSECTION Standard>
+GstOss4SourceClass
+GST_OSS4_SOURCE
+GST_OSS4_SOURCE_CAST
+GST_IS_OSS4_SOURCE
+GST_OSS4_SOURCE_CLASS
+GST_IS_OSS4_SOURCE_CLASS
+GST_TYPE_OSS4_SOURCE
+<SUBSECTION Private>
+gst_oss4_source_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-osssink</FILE>
+<TITLE>osssink</TITLE>
+GstOssSink
+<SUBSECTION Standard>
+GstOssSinkClass
+GST_OSS_SINK
+GST_OSS_SINK_CAST
+GST_IS_OSS_SINK
+GST_OSS_SINK_CLASS
+GST_IS_OSS_SINK_CLASS
+GST_TYPE_OSS_SINK
+<SUBSECTION Private>
+gst_oss_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-osssrc</FILE>
+<TITLE>osssrc</TITLE>
+GstOssSrc
+<SUBSECTION Standard>
+GstOssSrcClass
+GST_OSS_SRC
+GST_OSS_SRC_CAST
+GST_IS_OSS_SRC
+GST_OSS_SRC_CLASS
+GST_IS_OSS_SRC_CLASS
+GST_TYPE_OSS_SRC
+<SUBSECTION Private>
+gst_oss_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-osxaudiosink</FILE>
+<TITLE>osxaudiosink</TITLE>
+GstOsxAudioSink
+<SUBSECTION Standard>
+GstOsxAudioSinkClass
+GST_TYPE_OSX_AUDIO_SINK
+GST_OSX_AUDIO_SINK
+GST_OSX_AUDIO_SINK_CLASS
+gst_osx_audio_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-osxaudiosrc</FILE>
+<TITLE>osxaudiosrc</TITLE>
+GstOsxAudioSrc
+<SUBSECTION Standard>
+GstOsxAudioSrcClass
+GST_TYPE_OSX_AUDIO_SRC
+GST_OSX_AUDIO_SRC
+GST_OSX_AUDIO_SRC_CLASS
+gst_osx_audio_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-osxvideosink</FILE>
+<TITLE>osxvideosink</TITLE>
+GstOSXVideoSink
+<SUBSECTION Standard>
+GstOSXVideoSinkClass
+GstOSXWindow
+<SUBSECTION Private>
+GST_IS_OSX_VIDEO_SINK
+GST_IS_OSX_VIDEO_SINK_CLASS
+GST_OSX_VIDEO_SINK
+GST_OSX_VIDEO_SINK_CLASS
+GST_TYPE_OSX_VIDEO_SINK
+GST_TYPE_OSXVIDEOBUFFER
+gst_osx_video_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-pngdec</FILE>
+<TITLE>pngdec</TITLE>
+GstPngDec
+<SUBSECTION Standard>
+GstPngDecClass
+GST_PNG_DEC
+GST_PNG_DEC_CAST
+GST_IS_PNG_DEC
+GST_PNG_DEC_CLASS
+GST_IS_PNG_DEC_CLASS
+GST_TYPE_PNG_DEC
+<SUBSECTION Private>
+gst_png_dec_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-pngenc</FILE>
+<TITLE>pngenc</TITLE>
+GstPngEnc
+<SUBSECTION Standard>
+GstPngEncClass
+GST_PNG_ENC
+GST_PNG_ENC_CAST
+GST_IS_PNG_ENC
+GST_PNG_ENC_CLASS
+GST_IS_PNG_ENC_CLASS
+GST_TYPE_PNG_ENC
+<SUBSECTION Private>
+gst_png_enc_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-progressreport</FILE>
+<TITLE>progressreport</TITLE>
+GstProgressReport
+<SUBSECTION Standard>
+GstProgressReportClass
+GST_PROGRESS_REPORT
+GST_PROGRESS_REPORT_CAST
+GST_IS_PROGRESS_REPORT
+GST_PROGRESS_REPORT_CLASS
+GST_IS_PROGRESS_REPORT_CLASS
+GST_TYPE_PROGRESS_REPORT
+<SUBSECTION Private>
+gst_progress_report_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-pulsesink</FILE>
+<TITLE>pulsesink</TITLE>
+GstPulseSink
+<SUBSECTION Standard>
+GstPulseSinkClass
+GST_PULSE_SINK
+GST_PULSE_SINK_CAST
+GST_IS_PULSE_SINK
+GST_PULSE_SINK_CLASS
+GST_IS_PULSE_SINK_CLASS
+GST_TYPE_PULSE_SINK
+<SUBSECTION Private>
+gst_pulse_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-pulsesrc</FILE>
+<TITLE>pulsesrc</TITLE>
+GstPulseSrc
+<SUBSECTION Standard>
+GstPulseSrcClass
+GST_PULSE_SRC
+GST_PULSE_SRC_CAST
+GST_IS_PULSE_SRC
+GST_PULSE_SRC_CLASS
+GST_IS_PULSE_SRC_CLASS
+GST_TYPE_PULSE_SRC
+<SUBSECTION Private>
+gst_pulse_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-pushfilesrc</FILE>
+<TITLE>pushfilesrc</TITLE>
+GstPushFileSrc
+<SUBSECTION Standard>
+GstPushFileSrcClass
+GST_PUSH_FILE_SRC
+GST_PUSH_FILE_SRC_CAST
+GST_IS_PUSH_FILE_SRC
+GST_PUSH_FILE_SRC_CLASS
+GST_IS_PUSH_FILE_SRC_CLASS
+GST_TYPE_PUSH_FILE_SRC
+<SUBSECTION Private>
+gst_push_file_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-qtdemux</FILE>
+<TITLE>qtdemux</TITLE>
+GstQTDemux
+<SUBSECTION Standard>
+GstQTDemuxClass
+GST_QT_DEMUX
+GST_QT_DEMUX_CAST
+GST_IS_QT_DEMUX
+GST_QT_DEMUX_CLASS
+GST_IS_QT_DEMUX_CLASS
+GST_TYPE_QT_DEMUX
+<SUBSECTION Private>
+gst_qt_demux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-qtmoovrecover</FILE>
+<TITLE>qtmoovrecover</TITLE>
+GstQTMoovRecover
+<SUBSECTION Standard>
+GstQTMoovRecoverClass
+GST_QT_MOOV_RECOVER
+GST_QT_MOOV_RECOVER_CAST
+GST_IS_QT_MOOV_RECOVER
+GST_QT_MOOV_RECOVER_CLASS
+GST_IS_QT_MOOV_RECOVER_CLASS
+GST_TYPE_QT_MOOV_RECOVER
+<SUBSECTION Private>
+gst_qt_moov_recover_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-qtmux</FILE>
+<TITLE>qtmux</TITLE>
+GstQTMux
+GstQTMuxDtsMethods
+<SUBSECTION Standard>
+GstQTMuxClass
+GST_QT_MUX
+GST_QT_MUX_CAST
+GST_IS_QT_MUX
+GST_QT_MUX_CLASS
+GST_IS_QT_MUX_CLASS
+GST_TYPE_QT_MUX
+<SUBSECTION Private>
+gst_qt_mux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-quarktv</FILE>
+<TITLE>quarktv</TITLE>
+GstQuarkTV
+<SUBSECTION Standard>
+GstQuarkTVClass
+GST_QUARK_TV
+GST_QUARK_TV_CAST
+GST_IS_QUARK_TV
+GST_QUARK_TV_CLASS
+GST_IS_QUARK_TV_CLASS
+GST_TYPE_QUARK_TV
+<SUBSECTION Private>
+gst_quark_tv_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpbvdepay</FILE>
+<TITLE>rtpbvdepay</TITLE>
+GstRTPBVDepay
+<SUBSECTION Standard>
+GstRTPBVDepayClass
+GST_RTPBV_DEPAY
+GST_RTPBV_DEPAY_CAST
+GST_IS_RTPBV_DEPAY
+GST_RTPBV_DEPAY_CLASS
+GST_IS_RTPBV_DEPAY_CLASS
+GST_TYPE_RTPBV_DEPAY
+<SUBSECTION Private>
+gst_rtpbv_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpbvpay</FILE>
+<TITLE>rtpbvpay</TITLE>
+GstRTPBVPay
+<SUBSECTION Standard>
+GstRTPBVPayClass
+GST_RTPBV_PAY
+GST_RTPBV_PAY_CAST
+GST_IS_RTPBV_PAY
+GST_RTPBV_PAY_CLASS
+GST_IS_RTPBV_PAY_CLASS
+GST_TYPE_RTPBV_PAY
+<SUBSECTION Private>
+gst_rtpbv_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpdtmfmux</FILE>
+<TITLE>rtpdtmfmux</TITLE>
+GstRTPDTMFMux
+<SUBSECTION Standard>
+GstRTPDTMFMuxClass
+GST_RTPDTMF_MUX
+GST_RTPDTMF_MUX_CAST
+GST_IS_RTPDTMF_MUX
+GST_RTPDTMF_MUX_CLASS
+GST_IS_RTPDTMF_MUX_CLASS
+GST_TYPE_RTPDTMF_MUX
+<SUBSECTION Private>
+gst_rtpdtmf_mux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpdtmfsrc</FILE>
+<TITLE>rtpdtmfsrc</TITLE>
+GstRTPDTMFSrc
+<SUBSECTION Standard>
+GstRTPDTMFSrcClass
+GST_RTPDTMF_SRC
+GST_RTPDTMF_SRC_CAST
+GST_IS_RTPDTMF_SRC
+GST_RTPDTMF_SRC_CLASS
+GST_IS_RTPDTMF_SRC_CLASS
+GST_TYPE_RTPDTMF_SRC
+<SUBSECTION Private>
+gst_rtpdtmf_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpdvdepay</FILE>
+<TITLE>rtpdvdepay</TITLE>
+GstRTPDVDepay
+<SUBSECTION Standard>
+GstRTPDVDepayClass
+GST_RTPDV_DEPAY
+GST_RTPDV_DEPAY_CAST
+GST_IS_RTPDV_DEPAY
+GST_RTPDV_DEPAY_CLASS
+GST_IS_RTPDV_DEPAY_CLASS
+GST_TYPE_RTPDV_DEPAY
+<SUBSECTION Private>
+gst_rtpdv_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpdvpay</FILE>
+<TITLE>rtpdvpay</TITLE>
+GstRTPDVPay
+<SUBSECTION Standard>
+GstRTPDVPayClass
+GST_RTPDV_PAY
+GST_RTPDV_PAY_CAST
+GST_IS_RTPDV_PAY
+GST_RTPDV_PAY_CLASS
+GST_IS_RTPDV_PAY_CLASS
+GST_TYPE_RTPDV_PAY
+<SUBSECTION Private>
+gst_rtpdv_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpdec</FILE>
+<TITLE>rtpdec</TITLE>
+GstRTPDec
+<SUBSECTION Standard>
+GstRTPDecClass
+GST_RTP_DEC
+GST_RTP_DEC_CAST
+GST_IS_RTP_DEC
+GST_RTP_DEC_CLASS
+GST_IS_RTP_DEC_CLASS
+GST_TYPE_RTP_DEC
+<SUBSECTION Private>
+gst_rtp_dec_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpg723pay</FILE>
+<TITLE>rtpg723pay</TITLE>
+GstRTPG723Pay
+<SUBSECTION Standard>
+GstRTPG723PayClass
+GST_RTP_G723_PAY
+GST_RTP_G723_PAY_CAST
+GST_IS_RTP_G723_PAY
+GST_RTP_G723_PAY_CLASS
+GST_IS_RTP_G723_PAY_CLASS
+GST_TYPE_RTP_G723_PAY
+<SUBSECTION Private>
+gst_rtp_g723_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpg729pay</FILE>
+<TITLE>rtpg729pay</TITLE>
+GstRTPG729Pay
+<SUBSECTION Standard>
+GstRTPG729PayClass
+GST_RTP_G729_PAY
+GST_RTP_G729_PAY_CAST
+GST_IS_RTP_G729_PAY
+GST_RTP_G729_PAY_CLASS
+GST_IS_RTP_G729_PAY_CLASS
+GST_TYPE_RTP_G729_PAY
+<SUBSECTION Private>
+gst_rtp_g729_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpgsmdepay</FILE>
+<TITLE>rtpgsmdepay</TITLE>
+GstRTPGSMDepay
+<SUBSECTION Standard>
+GstRTPGSMDepayClass
+GST_RTPGSM_DEPAY
+GST_RTPGSM_DEPAY_CAST
+GST_IS_RTPGSM_DEPAY
+GST_RTPGSM_DEPAY_CLASS
+GST_IS_RTPGSM_DEPAY_CLASS
+GST_TYPE_RTPGSM_DEPAY
+<SUBSECTION Private>
+gst_rtpgsm_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpgsmpay</FILE>
+<TITLE>rtpgsmpay</TITLE>
+GstRTPGSMPay
+<SUBSECTION Standard>
+GstRTPGSMPayClass
+GST_RTPGSM_PAY
+GST_RTPGSM_PAY_CAST
+GST_IS_RTPGSM_PAY
+GST_RTPGSM_PAY_CLASS
+GST_IS_RTPGSM_PAY_CLASS
+GST_TYPE_RTPGSM_PAY
+<SUBSECTION Private>
+gst_rtpgsm_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpilbcpay</FILE>
+<TITLE>rtpilbcpay</TITLE>
+GstRTPILBCPay
+<SUBSECTION Standard>
+GstRTPILBCPayClass
+GST_RTPILBC_PAY
+GST_RTPILBC_PAY_CAST
+GST_IS_RTPILBC_PAY
+GST_RTPILBC_PAY_CLASS
+GST_IS_RTPILBC_PAY_CLASS
+GST_TYPE_RTPILBC_PAY
+<SUBSECTION Private>
+gst_rtpilbc_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpmp2tpay</FILE>
+<TITLE>rtpmp2tpay</TITLE>
+GstRTPMP2TPay
+<SUBSECTION Standard>
+GstRTPMP2TPayClass
+GST_RTPM_P2_T_PAY
+GST_RTPM_P2_T_PAY_CAST
+GST_IS_RTPM_P2_T_PAY
+GST_RTPM_P2_T_PAY_CLASS
+GST_IS_RTPM_P2_T_PAY_CLASS
+GST_TYPE_RTPM_P2_T_PAY
+<SUBSECTION Private>
+gst_rtpm_p2_t_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpmpvpay</FILE>
+<TITLE>rtpmpvpay</TITLE>
+GstRTPMPVPay
+<SUBSECTION Standard>
+GstRTPMPVPayClass
+GST_RTPMPV_PAY
+GST_RTPMPV_PAY_CAST
+GST_IS_RTPMPV_PAY
+GST_RTPMPV_PAY_CLASS
+GST_IS_RTPMPV_PAY_CLASS
+GST_TYPE_RTPMPV_PAY
+<SUBSECTION Private>
+gst_rtpmpv_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpmux</FILE>
+<TITLE>rtpmux</TITLE>
+GstRTPMux
+<SUBSECTION Standard>
+GstRTPMuxClass
+GST_RTP_MUX
+GST_RTP_MUX_CAST
+GST_IS_RTP_MUX
+GST_RTP_MUX_CLASS
+GST_IS_RTP_MUX_CLASS
+GST_TYPE_RTP_MUX
+<SUBSECTION Private>
+gst_rtp_mux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpopusdepay</FILE>
+<TITLE>rtpopusdepay</TITLE>
+GstRTPOpusDepay
+<SUBSECTION Standard>
+GstRTPOpusDepayClass
+GST_RTP_OPUS_DEPAY
+GST_RTP_OPUS_DEPAY_CAST
+GST_IS_RTP_OPUS_DEPAY
+GST_RTP_OPUS_DEPAY_CLASS
+GST_IS_RTP_OPUS_DEPAY_CLASS
+GST_TYPE_RTP_OPUS_DEPAY
+<SUBSECTION Private>
+gst_rtp_opus_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtprtxqueue</FILE>
+<TITLE>rtprtxqueue</TITLE>
+GstRTPRtxQueue
+<SUBSECTION Standard>
+GstRTPRtxQueueClass
+GST_RTP_RTX_QUEUE
+GST_RTP_RTX_QUEUE_CAST
+GST_IS_RTP_RTX_QUEUE
+GST_RTP_RTX_QUEUE_CLASS
+GST_IS_RTP_RTX_QUEUE_CLASS
+GST_TYPE_RTP_RTX_QUEUE
+<SUBSECTION Private>
+gst_rtp_rtx_queue_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpsirendepay</FILE>
+<TITLE>rtpsirendepay</TITLE>
+GstRTPSirenDepay
+<SUBSECTION Standard>
+GstRTPSirenDepayClass
+GST_RTP_SIREN_DEPAY
+GST_RTP_SIREN_DEPAY_CAST
+GST_IS_RTP_SIREN_DEPAY
+GST_RTP_SIREN_DEPAY_CLASS
+GST_IS_RTP_SIREN_DEPAY_CLASS
+GST_TYPE_RTP_SIREN_DEPAY
+<SUBSECTION Private>
+gst_rtp_siren_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpsirenpay</FILE>
+<TITLE>rtpsirenpay</TITLE>
+GstRTPSirenPay
+<SUBSECTION Standard>
+GstRTPSirenPayClass
+GST_RTP_SIREN_PAY
+GST_RTP_SIREN_PAY_CAST
+GST_IS_RTP_SIREN_PAY
+GST_RTP_SIREN_PAY_CLASS
+GST_IS_RTP_SIREN_PAY_CLASS
+GST_TYPE_RTP_SIREN_PAY
+<SUBSECTION Private>
+gst_rtp_siren_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpilbcdepay</FILE>
+<TITLE>rtpilbcdepay</TITLE>
+GstRTPiLBCDepay
+<SUBSECTION Standard>
+GstRTPiLBCDepayClass
+GST_RT_PI_LBC_DEPAY
+GST_RT_PI_LBC_DEPAY_CAST
+GST_IS_RT_PI_LBC_DEPAY
+GST_RT_PI_LBC_DEPAY_CLASS
+GST_IS_RT_PI_LBC_DEPAY_CLASS
+GST_TYPE_RT_PI_LBC_DEPAY
+<SUBSECTION Private>
+gst_rt_pi_lbc_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtspsrc</FILE>
+<TITLE>rtspsrc</TITLE>
+GstRTSPSrc
+GstRTSPSrcBufferMode
+GstRTSPSrcNtpTimeSource
+<SUBSECTION Standard>
+GstRTSPSrcClass
+GST_RTSP_SRC
+GST_RTSP_SRC_CAST
+GST_IS_RTSP_SRC
+GST_RTSP_SRC_CLASS
+GST_IS_RTSP_SRC_CLASS
+GST_TYPE_RTSP_SRC
+<SUBSECTION Private>
+gst_rtsp_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-radioactv</FILE>
+<TITLE>radioactv</TITLE>
+GstRadioacTV
+GstRadioacTVColor
+GstRadioacTVMode
+<SUBSECTION Standard>
+GstRadioacTVClass
+GST_RADIOAC_TV
+GST_RADIOAC_TV_CAST
+GST_IS_RADIOAC_TV
+GST_RADIOAC_TV_CLASS
+GST_IS_RADIOAC_TV_CLASS
+GST_TYPE_RADIOAC_TV
+<SUBSECTION Private>
+gst_radioac_tv_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-revtv</FILE>
+<TITLE>revtv</TITLE>
+GstRevTV
+<SUBSECTION Standard>
+GstRevTVClass
+GST_REV_TV
+GST_REV_TV_CAST
+GST_IS_REV_TV
+GST_REV_TV_CLASS
+GST_IS_REV_TV_CLASS
+GST_TYPE_REV_TV
+<SUBSECTION Private>
+gst_rev_tv_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rganalysis</FILE>
+<TITLE>rganalysis</TITLE>
+GstRgAnalysis
+<SUBSECTION Standard>
+GstRgAnalysisClass
+GST_RG_ANALYSIS
+GST_RG_ANALYSIS_CAST
+GST_IS_RG_ANALYSIS
+GST_RG_ANALYSIS_CLASS
+GST_IS_RG_ANALYSIS_CLASS
+GST_TYPE_RG_ANALYSIS
+<SUBSECTION Private>
+gst_rg_analysis_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rglimiter</FILE>
+<TITLE>rglimiter</TITLE>
+GstRgLimiter
+<SUBSECTION Standard>
+GstRgLimiterClass
+GST_RG_LIMITER
+GST_RG_LIMITER_CAST
+GST_IS_RG_LIMITER
+GST_RG_LIMITER_CLASS
+GST_IS_RG_LIMITER_CLASS
+GST_TYPE_RG_LIMITER
+<SUBSECTION Private>
+gst_rg_limiter_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rgvolume</FILE>
+<TITLE>rgvolume</TITLE>
+GstRgVolume
+<SUBSECTION Standard>
+GstRgVolumeClass
+GST_RG_VOLUME
+GST_RG_VOLUME_CAST
+GST_IS_RG_VOLUME
+GST_RG_VOLUME_CLASS
+GST_IS_RG_VOLUME_CLASS
+GST_TYPE_RG_VOLUME
+<SUBSECTION Private>
+gst_rg_volume_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rippletv</FILE>
+<TITLE>rippletv</TITLE>
+GstRippleTV
+GstRippleTVMode
+<SUBSECTION Standard>
+GstRippleTVClass
+GST_RIPPLE_TV
+GST_RIPPLE_TV_CAST
+GST_IS_RIPPLE_TV
+GST_RIPPLE_TV_CLASS
+GST_IS_RIPPLE_TV_CLASS
+GST_TYPE_RIPPLE_TV
+<SUBSECTION Private>
+gst_ripple_tv_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rndbuffersize</FILE>
+<TITLE>rndbuffersize</TITLE>
+GstRndBufferSize
+<SUBSECTION Standard>
+GstRndBufferSizeClass
+GST_RND_BUFFER_SIZE
+GST_RND_BUFFER_SIZE_CAST
+GST_IS_RND_BUFFER_SIZE
+GST_RND_BUFFER_SIZE_CLASS
+GST_IS_RND_BUFFER_SIZE_CLASS
+GST_TYPE_RND_BUFFER_SIZE
+<SUBSECTION Private>
+gst_rnd_buffer_size_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpac3depay</FILE>
+<TITLE>rtpac3depay</TITLE>
+GstRtpAC3Depay
+<SUBSECTION Standard>
+GstRtpAC3DepayClass
+GST_RTP_A_C3_DEPAY
+GST_RTP_A_C3_DEPAY_CAST
+GST_IS_RTP_A_C3_DEPAY
+GST_RTP_A_C3_DEPAY_CLASS
+GST_IS_RTP_A_C3_DEPAY_CLASS
+GST_TYPE_RTP_A_C3_DEPAY
+<SUBSECTION Private>
+gst_rtp_a_c3_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpac3pay</FILE>
+<TITLE>rtpac3pay</TITLE>
+GstRtpAC3Pay
+<SUBSECTION Standard>
+GstRtpAC3PayClass
+GST_RTP_A_C3_PAY
+GST_RTP_A_C3_PAY_CAST
+GST_IS_RTP_A_C3_PAY
+GST_RTP_A_C3_PAY_CLASS
+GST_IS_RTP_A_C3_PAY_CLASS
+GST_TYPE_RTP_A_C3_PAY
+<SUBSECTION Private>
+gst_rtp_a_c3_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpamrdepay</FILE>
+<TITLE>rtpamrdepay</TITLE>
+GstRtpAMRDepay
+<SUBSECTION Standard>
+GstRtpAMRDepayClass
+GST_RTP_AMR_DEPAY
+GST_RTP_AMR_DEPAY_CAST
+GST_IS_RTP_AMR_DEPAY
+GST_RTP_AMR_DEPAY_CLASS
+GST_IS_RTP_AMR_DEPAY_CLASS
+GST_TYPE_RTP_AMR_DEPAY
+<SUBSECTION Private>
+gst_rtp_amr_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpamrpay</FILE>
+<TITLE>rtpamrpay</TITLE>
+GstRtpAMRPay
+<SUBSECTION Standard>
+GstRtpAMRPayClass
+GST_RTP_AMR_PAY
+GST_RTP_AMR_PAY_CAST
+GST_IS_RTP_AMR_PAY
+GST_RTP_AMR_PAY_CLASS
+GST_IS_RTP_AMR_PAY_CLASS
+GST_TYPE_RTP_AMR_PAY
+<SUBSECTION Private>
+gst_rtp_amr_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpbin</FILE>
+<TITLE>rtpbin</TITLE>
+GstRtpBin
+<SUBSECTION Standard>
+GstRtpBinClass
+GST_RTP_BIN
+GST_RTP_BIN_CAST
+GST_IS_RTP_BIN
+GST_RTP_BIN_CLASS
+GST_IS_RTP_BIN_CLASS
+GST_TYPE_RTP_BIN
+<SUBSECTION Private>
+gst_rtp_bin_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpceltdepay</FILE>
+<TITLE>rtpceltdepay</TITLE>
+GstRtpCELTDepay
+<SUBSECTION Standard>
+GstRtpCELTDepayClass
+GST_RTP_CELT_DEPAY
+GST_RTP_CELT_DEPAY_CAST
+GST_IS_RTP_CELT_DEPAY
+GST_RTP_CELT_DEPAY_CLASS
+GST_IS_RTP_CELT_DEPAY_CLASS
+GST_TYPE_RTP_CELT_DEPAY
+<SUBSECTION Private>
+gst_rtp_celt_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpceltpay</FILE>
+<TITLE>rtpceltpay</TITLE>
+GstRtpCELTPay
+<SUBSECTION Standard>
+GstRtpCELTPayClass
+GST_RTP_CELT_PAY
+GST_RTP_CELT_PAY_CAST
+GST_IS_RTP_CELT_PAY
+GST_RTP_CELT_PAY_CLASS
+GST_IS_RTP_CELT_PAY_CLASS
+GST_TYPE_RTP_CELT_PAY
+<SUBSECTION Private>
+gst_rtp_celt_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpdtmfdepay</FILE>
+<TITLE>rtpdtmfdepay</TITLE>
+GstRtpDTMFDepay
+<SUBSECTION Standard>
+GstRtpDTMFDepayClass
+GST_RTP_DTMF_DEPAY
+GST_RTP_DTMF_DEPAY_CAST
+GST_IS_RTP_DTMF_DEPAY
+GST_RTP_DTMF_DEPAY_CLASS
+GST_IS_RTP_DTMF_DEPAY_CLASS
+GST_TYPE_RTP_DTMF_DEPAY
+<SUBSECTION Private>
+gst_rtp_dtmf_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpg722depay</FILE>
+<TITLE>rtpg722depay</TITLE>
+GstRtpG722Depay
+<SUBSECTION Standard>
+GstRtpG722DepayClass
+GST_RTP_G722_DEPAY
+GST_RTP_G722_DEPAY_CAST
+GST_IS_RTP_G722_DEPAY
+GST_RTP_G722_DEPAY_CLASS
+GST_IS_RTP_G722_DEPAY_CLASS
+GST_TYPE_RTP_G722_DEPAY
+<SUBSECTION Private>
+gst_rtp_g722_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpg722pay</FILE>
+<TITLE>rtpg722pay</TITLE>
+GstRtpG722Pay
+<SUBSECTION Standard>
+GstRtpG722PayClass
+GST_RTP_G722_PAY
+GST_RTP_G722_PAY_CAST
+GST_IS_RTP_G722_PAY
+GST_RTP_G722_PAY_CLASS
+GST_IS_RTP_G722_PAY_CLASS
+GST_TYPE_RTP_G722_PAY
+<SUBSECTION Private>
+gst_rtp_g722_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpg723depay</FILE>
+<TITLE>rtpg723depay</TITLE>
+GstRtpG723Depay
+<SUBSECTION Standard>
+GstRtpG723DepayClass
+GST_RTP_G723_DEPAY
+GST_RTP_G723_DEPAY_CAST
+GST_IS_RTP_G723_DEPAY
+GST_RTP_G723_DEPAY_CLASS
+GST_IS_RTP_G723_DEPAY_CLASS
+GST_TYPE_RTP_G723_DEPAY
+<SUBSECTION Private>
+gst_rtp_g723_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpg726depay</FILE>
+<TITLE>rtpg726depay</TITLE>
+GstRtpG726Depay
+<SUBSECTION Standard>
+GstRtpG726DepayClass
+GST_RTP_G726_DEPAY
+GST_RTP_G726_DEPAY_CAST
+GST_IS_RTP_G726_DEPAY
+GST_RTP_G726_DEPAY_CLASS
+GST_IS_RTP_G726_DEPAY_CLASS
+GST_TYPE_RTP_G726_DEPAY
+<SUBSECTION Private>
+gst_rtp_g726_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpg726pay</FILE>
+<TITLE>rtpg726pay</TITLE>
+GstRtpG726Pay
+<SUBSECTION Standard>
+GstRtpG726PayClass
+GST_RTP_G726_PAY
+GST_RTP_G726_PAY_CAST
+GST_IS_RTP_G726_PAY
+GST_RTP_G726_PAY_CLASS
+GST_IS_RTP_G726_PAY_CLASS
+GST_TYPE_RTP_G726_PAY
+<SUBSECTION Private>
+gst_rtp_g726_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpg729depay</FILE>
+<TITLE>rtpg729depay</TITLE>
+GstRtpG729Depay
+<SUBSECTION Standard>
+GstRtpG729DepayClass
+GST_RTP_G729_DEPAY
+GST_RTP_G729_DEPAY_CAST
+GST_IS_RTP_G729_DEPAY
+GST_RTP_G729_DEPAY_CLASS
+GST_IS_RTP_G729_DEPAY_CLASS
+GST_TYPE_RTP_G729_DEPAY
+<SUBSECTION Private>
+gst_rtp_g729_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpgstdepay</FILE>
+<TITLE>rtpgstdepay</TITLE>
+GstRtpGSTDepay
+<SUBSECTION Standard>
+GstRtpGSTDepayClass
+GST_RTP_GST_DEPAY
+GST_RTP_GST_DEPAY_CAST
+GST_IS_RTP_GST_DEPAY
+GST_RTP_GST_DEPAY_CLASS
+GST_IS_RTP_GST_DEPAY_CLASS
+GST_TYPE_RTP_GST_DEPAY
+<SUBSECTION Private>
+gst_rtp_gst_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpgstpay</FILE>
+<TITLE>rtpgstpay</TITLE>
+GstRtpGSTPay
+<SUBSECTION Standard>
+GstRtpGSTPayClass
+GST_RTP_GST_PAY
+GST_RTP_GST_PAY_CAST
+GST_IS_RTP_GST_PAY
+GST_RTP_GST_PAY_CLASS
+GST_IS_RTP_GST_PAY_CLASS
+GST_TYPE_RTP_GST_PAY
+<SUBSECTION Private>
+gst_rtp_gst_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtph261depay</FILE>
+<TITLE>rtph261depay</TITLE>
+GstRtpH261Depay
+<SUBSECTION Standard>
+GstRtpH261DepayClass
+GST_RTP_H261_DEPAY
+GST_RTP_H261_DEPAY_CAST
+GST_IS_RTP_H261_DEPAY
+GST_RTP_H261_DEPAY_CLASS
+GST_IS_RTP_H261_DEPAY_CLASS
+GST_TYPE_RTP_H261_DEPAY
+<SUBSECTION Private>
+gst_rtp_h261_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtph261pay</FILE>
+<TITLE>rtph261pay</TITLE>
+GstRtpH261Pay
+<SUBSECTION Standard>
+GstRtpH261PayClass
+GST_RTP_H261_PAY
+GST_RTP_H261_PAY_CAST
+GST_IS_RTP_H261_PAY
+GST_RTP_H261_PAY_CLASS
+GST_IS_RTP_H261_PAY_CLASS
+GST_TYPE_RTP_H261_PAY
+<SUBSECTION Private>
+gst_rtp_h261_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtph263depay</FILE>
+<TITLE>rtph263depay</TITLE>
+GstRtpH263Depay
+<SUBSECTION Standard>
+GstRtpH263DepayClass
+GST_RTP_H263_DEPAY
+GST_RTP_H263_DEPAY_CAST
+GST_IS_RTP_H263_DEPAY
+GST_RTP_H263_DEPAY_CLASS
+GST_IS_RTP_H263_DEPAY_CLASS
+GST_TYPE_RTP_H263_DEPAY
+<SUBSECTION Private>
+gst_rtp_h263_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtph263pdepay</FILE>
+<TITLE>rtph263pdepay</TITLE>
+GstRtpH263PDepay
+<SUBSECTION Standard>
+GstRtpH263PDepayClass
+GST_RTP_H263_P_DEPAY
+GST_RTP_H263_P_DEPAY_CAST
+GST_IS_RTP_H263_P_DEPAY
+GST_RTP_H263_P_DEPAY_CLASS
+GST_IS_RTP_H263_P_DEPAY_CLASS
+GST_TYPE_RTP_H263_P_DEPAY
+<SUBSECTION Private>
+gst_rtp_h263_p_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtph263ppay</FILE>
+<TITLE>rtph263ppay</TITLE>
+GstRtpH263PPay
+<SUBSECTION Standard>
+GstRtpH263PPayClass
+GST_RTP_H263_P_PAY
+GST_RTP_H263_P_PAY_CAST
+GST_IS_RTP_H263_P_PAY
+GST_RTP_H263_P_PAY_CLASS
+GST_IS_RTP_H263_P_PAY_CLASS
+GST_TYPE_RTP_H263_P_PAY
+<SUBSECTION Private>
+gst_rtp_h263_p_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtph263pay</FILE>
+<TITLE>rtph263pay</TITLE>
+GstRtpH263Pay
+<SUBSECTION Standard>
+GstRtpH263PayClass
+GST_RTP_H263_PAY
+GST_RTP_H263_PAY_CAST
+GST_IS_RTP_H263_PAY
+GST_RTP_H263_PAY_CLASS
+GST_IS_RTP_H263_PAY_CLASS
+GST_TYPE_RTP_H263_PAY
+<SUBSECTION Private>
+gst_rtp_h263_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtph264depay</FILE>
+<TITLE>rtph264depay</TITLE>
+GstRtpH264Depay
+<SUBSECTION Standard>
+GstRtpH264DepayClass
+GST_RTP_H264_DEPAY
+GST_RTP_H264_DEPAY_CAST
+GST_IS_RTP_H264_DEPAY
+GST_RTP_H264_DEPAY_CLASS
+GST_IS_RTP_H264_DEPAY_CLASS
+GST_TYPE_RTP_H264_DEPAY
+<SUBSECTION Private>
+gst_rtp_h264_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtph264pay</FILE>
+<TITLE>rtph264pay</TITLE>
+GstRtpH264Pay
+<SUBSECTION Standard>
+GstRtpH264PayClass
+GST_RTP_H264_PAY
+GST_RTP_H264_PAY_CAST
+GST_IS_RTP_H264_PAY
+GST_RTP_H264_PAY_CLASS
+GST_IS_RTP_H264_PAY_CLASS
+GST_TYPE_RTP_H264_PAY
+<SUBSECTION Private>
+gst_rtp_h264_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtph265depay</FILE>
+<TITLE>rtph265depay</TITLE>
+GstRtpH265Depay
+<SUBSECTION Standard>
+GstRtpH265DepayClass
+GST_RTP_H265_DEPAY
+GST_RTP_H265_DEPAY_CAST
+GST_IS_RTP_H265_DEPAY
+GST_RTP_H265_DEPAY_CLASS
+GST_IS_RTP_H265_DEPAY_CLASS
+GST_TYPE_RTP_H265_DEPAY
+<SUBSECTION Private>
+gst_rtp_h265_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtph265pay</FILE>
+<TITLE>rtph265pay</TITLE>
+GstRtpH265Pay
+<SUBSECTION Standard>
+GstRtpH265PayClass
+GST_RTP_H265_PAY
+GST_RTP_H265_PAY_CAST
+GST_IS_RTP_H265_PAY
+GST_RTP_H265_PAY_CLASS
+GST_IS_RTP_H265_PAY_CLASS
+GST_TYPE_RTP_H265_PAY
+<SUBSECTION Private>
+gst_rtp_h265_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpj2kdepay</FILE>
+<TITLE>rtpj2kdepay</TITLE>
+GstRtpJ2KDepay
+<SUBSECTION Standard>
+GstRtpJ2KDepayClass
+GST_RTP_J2_K_DEPAY
+GST_RTP_J2_K_DEPAY_CAST
+GST_IS_RTP_J2_K_DEPAY
+GST_RTP_J2_K_DEPAY_CLASS
+GST_IS_RTP_J2_K_DEPAY_CLASS
+GST_TYPE_RTP_J2_K_DEPAY
+<SUBSECTION Private>
+gst_rtp_j2_k_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpj2kpay</FILE>
+<TITLE>rtpj2kpay</TITLE>
+GstRtpJ2KPay
+<SUBSECTION Standard>
+GstRtpJ2KPayClass
+GST_RTP_J2_K_PAY
+GST_RTP_J2_K_PAY_CAST
+GST_IS_RTP_J2_K_PAY
+GST_RTP_J2_K_PAY_CLASS
+GST_IS_RTP_J2_K_PAY_CLASS
+GST_TYPE_RTP_J2_K_PAY
+<SUBSECTION Private>
+gst_rtp_j2_k_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpjpegdepay</FILE>
+<TITLE>rtpjpegdepay</TITLE>
+GstRtpJPEGDepay
+<SUBSECTION Standard>
+GstRtpJPEGDepayClass
+GST_RTP_JPEG_DEPAY
+GST_RTP_JPEG_DEPAY_CAST
+GST_IS_RTP_JPEG_DEPAY
+GST_RTP_JPEG_DEPAY_CLASS
+GST_IS_RTP_JPEG_DEPAY_CLASS
+GST_TYPE_RTP_JPEG_DEPAY
+<SUBSECTION Private>
+gst_rtp_jpeg_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpjpegpay</FILE>
+<TITLE>rtpjpegpay</TITLE>
+GstRtpJPEGPay
+<SUBSECTION Standard>
+GstRtpJPEGPayClass
+GST_RTP_JPEG_PAY
+GST_RTP_JPEG_PAY_CAST
+GST_IS_RTP_JPEG_PAY
+GST_RTP_JPEG_PAY_CLASS
+GST_IS_RTP_JPEG_PAY_CLASS
+GST_TYPE_RTP_JPEG_PAY
+<SUBSECTION Private>
+gst_rtp_jpeg_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpjitterbuffer</FILE>
+<TITLE>rtpjitterbuffer</TITLE>
+GstRtpJitterBuffer
+<SUBSECTION Standard>
+GstRtpJitterBufferClass
+GST_RTP_JITTER_BUFFER
+GST_RTP_JITTER_BUFFER_CAST
+GST_IS_RTP_JITTER_BUFFER
+GST_RTP_JITTER_BUFFER_CLASS
+GST_IS_RTP_JITTER_BUFFER_CLASS
+GST_TYPE_RTP_JITTER_BUFFER
+<SUBSECTION Private>
+gst_rtp_jitter_buffer_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpklvdepay</FILE>
+<TITLE>rtpklvdepay</TITLE>
+GstRtpKlvDepay
+<SUBSECTION Standard>
+GstRtpKlvDepayClass
+GST_RTP_KLV_DEPAY
+GST_RTP_KLV_DEPAY_CAST
+GST_IS_RTP_KLV_DEPAY
+GST_RTP_KLV_DEPAY_CLASS
+GST_IS_RTP_KLV_DEPAY_CLASS
+GST_TYPE_RTP_KLV_DEPAY
+<SUBSECTION Private>
+gst_rtp_klv_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpklvpay</FILE>
+<TITLE>rtpklvpay</TITLE>
+GstRtpKlvPay
+<SUBSECTION Standard>
+GstRtpKlvPayClass
+GST_RTP_KLV_PAY
+GST_RTP_KLV_PAY_CAST
+GST_IS_RTP_KLV_PAY
+GST_RTP_KLV_PAY_CLASS
+GST_IS_RTP_KLV_PAY_CLASS
+GST_TYPE_RTP_KLV_PAY
+<SUBSECTION Private>
+gst_rtp_klv_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpL8depay</FILE>
+<TITLE>rtpL8depay</TITLE>
+GstRtpL8Depay
+<SUBSECTION Standard>
+GstRtpL8DepayClass
+GST_RTP_L8_DEPAY
+GST_RTP_L8_DEPAY_CAST
+GST_IS_RTP_L8_DEPAY
+GST_RTP_L8_DEPAY_CLASS
+GST_IS_RTP_L8_DEPAY_CLASS
+GST_TYPE_RTP_L8_DEPAY
+<SUBSECTION Private>
+gst_rtp_l8_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpL8pay</FILE>
+<TITLE>rtpL8pay</TITLE>
+GstRtpL8Pay
+<SUBSECTION Standard>
+GstRtpL8PayClass
+GST_RTP_L8_PAY
+GST_RTP_L8_PAY_CAST
+GST_IS_RTP_L8_PAY
+GST_RTP_L8_PAY_CLASS
+GST_IS_RTP_L8_PAY_CLASS
+GST_TYPE_RTP_L8_PAY
+<SUBSECTION Private>
+gst_rtp_l8_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpL16depay</FILE>
+<TITLE>rtpL16depay</TITLE>
+GstRtpL16Depay
+<SUBSECTION Standard>
+GstRtpL16DepayClass
+GST_RTP_L16_DEPAY
+GST_RTP_L16_DEPAY_CAST
+GST_IS_RTP_L16_DEPAY
+GST_RTP_L16_DEPAY_CLASS
+GST_IS_RTP_L16_DEPAY_CLASS
+GST_TYPE_RTP_L16_DEPAY
+<SUBSECTION Private>
+gst_rtp_l16_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpL16pay</FILE>
+<TITLE>rtpL16pay</TITLE>
+GstRtpL16Pay
+<SUBSECTION Standard>
+GstRtpL16PayClass
+GST_RTP_L16_PAY
+GST_RTP_L16_PAY_CAST
+GST_IS_RTP_L16_PAY
+GST_RTP_L16_PAY_CLASS
+GST_IS_RTP_L16_PAY_CLASS
+GST_TYPE_RTP_L16_PAY
+<SUBSECTION Private>
+gst_rtp_l16_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpL24depay</FILE>
+<TITLE>rtpL24depay</TITLE>
+GstRtpL24Depay
+<SUBSECTION Standard>
+GstRtpL24DepayClass
+GST_RTP_L24_DEPAY
+GST_RTP_L24_DEPAY_CAST
+GST_IS_RTP_L24_DEPAY
+GST_RTP_L24_DEPAY_CLASS
+GST_IS_RTP_L24_DEPAY_CLASS
+GST_TYPE_RTP_L24_DEPAY
+<SUBSECTION Private>
+gst_rtp_l24_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpL24pay</FILE>
+<TITLE>rtpL24pay</TITLE>
+GstRtpL24Pay
+<SUBSECTION Standard>
+GstRtpL24PayClass
+GST_RTP_L24_PAY
+GST_RTP_L24_PAY_CAST
+GST_IS_RTP_L24_PAY
+GST_RTP_L24_PAY_CLASS
+GST_IS_RTP_L24_PAY_CLASS
+GST_TYPE_RTP_L24_PAY
+<SUBSECTION Private>
+gst_rtp_l24_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpmp1sdepay</FILE>
+<TITLE>rtpmp1sdepay</TITLE>
+GstRtpMP1SDepay
+<SUBSECTION Standard>
+GstRtpMP1SDepayClass
+GST_RTP_M_P1_S_DEPAY
+GST_RTP_M_P1_S_DEPAY_CAST
+GST_IS_RTP_M_P1_S_DEPAY
+GST_RTP_M_P1_S_DEPAY_CLASS
+GST_IS_RTP_M_P1_S_DEPAY_CLASS
+GST_TYPE_RTP_M_P1_S_DEPAY
+<SUBSECTION Private>
+gst_rtp_m_p1_s_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpmp2tdepay</FILE>
+<TITLE>rtpmp2tdepay</TITLE>
+GstRtpMP2TDepay
+<SUBSECTION Standard>
+GstRtpMP2TDepayClass
+GST_RTP_M_P2_T_DEPAY
+GST_RTP_M_P2_T_DEPAY_CAST
+GST_IS_RTP_M_P2_T_DEPAY
+GST_RTP_M_P2_T_DEPAY_CLASS
+GST_IS_RTP_M_P2_T_DEPAY_CLASS
+GST_TYPE_RTP_M_P2_T_DEPAY
+<SUBSECTION Private>
+gst_rtp_m_p2_t_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpmp4adepay</FILE>
+<TITLE>rtpmp4adepay</TITLE>
+GstRtpMP4ADepay
+<SUBSECTION Standard>
+GstRtpMP4ADepayClass
+GST_RTP_M_P4_A_DEPAY
+GST_RTP_M_P4_A_DEPAY_CAST
+GST_IS_RTP_M_P4_A_DEPAY
+GST_RTP_M_P4_A_DEPAY_CLASS
+GST_IS_RTP_M_P4_A_DEPAY_CLASS
+GST_TYPE_RTP_M_P4_A_DEPAY
+<SUBSECTION Private>
+gst_rtp_m_p4_a_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpmp4apay</FILE>
+<TITLE>rtpmp4apay</TITLE>
+GstRtpMP4APay
+<SUBSECTION Standard>
+GstRtpMP4APayClass
+GST_RTP_M_P4_A_PAY
+GST_RTP_M_P4_A_PAY_CAST
+GST_IS_RTP_M_P4_A_PAY
+GST_RTP_M_P4_A_PAY_CLASS
+GST_IS_RTP_M_P4_A_PAY_CLASS
+GST_TYPE_RTP_M_P4_A_PAY
+<SUBSECTION Private>
+gst_rtp_m_p4_a_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpmp4gdepay</FILE>
+<TITLE>rtpmp4gdepay</TITLE>
+GstRtpMP4GDepay
+<SUBSECTION Standard>
+GstRtpMP4GDepayClass
+GST_RTP_M_P4_G_DEPAY
+GST_RTP_M_P4_G_DEPAY_CAST
+GST_IS_RTP_M_P4_G_DEPAY
+GST_RTP_M_P4_G_DEPAY_CLASS
+GST_IS_RTP_M_P4_G_DEPAY_CLASS
+GST_TYPE_RTP_M_P4_G_DEPAY
+<SUBSECTION Private>
+gst_rtp_m_p4_g_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpmp4gpay</FILE>
+<TITLE>rtpmp4gpay</TITLE>
+GstRtpMP4GPay
+<SUBSECTION Standard>
+GstRtpMP4GPayClass
+GST_RTP_M_P4_G_PAY
+GST_RTP_M_P4_G_PAY_CAST
+GST_IS_RTP_M_P4_G_PAY
+GST_RTP_M_P4_G_PAY_CLASS
+GST_IS_RTP_M_P4_G_PAY_CLASS
+GST_TYPE_RTP_M_P4_G_PAY
+<SUBSECTION Private>
+gst_rtp_m_p4_g_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpmp4vdepay</FILE>
+<TITLE>rtpmp4vdepay</TITLE>
+GstRtpMP4VDepay
+<SUBSECTION Standard>
+GstRtpMP4VDepayClass
+GST_RTP_M_P4_V_DEPAY
+GST_RTP_M_P4_V_DEPAY_CAST
+GST_IS_RTP_M_P4_V_DEPAY
+GST_RTP_M_P4_V_DEPAY_CLASS
+GST_IS_RTP_M_P4_V_DEPAY_CLASS
+GST_TYPE_RTP_M_P4_V_DEPAY
+<SUBSECTION Private>
+gst_rtp_m_p4_v_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpmp4vpay</FILE>
+<TITLE>rtpmp4vpay</TITLE>
+GstRtpMP4VPay
+<SUBSECTION Standard>
+GstRtpMP4VPayClass
+GST_RTP_M_P4_V_PAY
+GST_RTP_M_P4_V_PAY_CAST
+GST_IS_RTP_M_P4_V_PAY
+GST_RTP_M_P4_V_PAY_CLASS
+GST_IS_RTP_M_P4_V_PAY_CLASS
+GST_TYPE_RTP_M_P4_V_PAY
+<SUBSECTION Private>
+gst_rtp_m_p4_v_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpmpadepay</FILE>
+<TITLE>rtpmpadepay</TITLE>
+GstRtpMPADepay
+<SUBSECTION Standard>
+GstRtpMPADepayClass
+GST_RTP_MPA_DEPAY
+GST_RTP_MPA_DEPAY_CAST
+GST_IS_RTP_MPA_DEPAY
+GST_RTP_MPA_DEPAY_CLASS
+GST_IS_RTP_MPA_DEPAY_CLASS
+GST_TYPE_RTP_MPA_DEPAY
+<SUBSECTION Private>
+gst_rtp_mpa_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpmpapay</FILE>
+<TITLE>rtpmpapay</TITLE>
+GstRtpMPAPay
+<SUBSECTION Standard>
+GstRtpMPAPayClass
+GST_RTP_MPA_PAY
+GST_RTP_MPA_PAY_CAST
+GST_IS_RTP_MPA_PAY
+GST_RTP_MPA_PAY_CLASS
+GST_IS_RTP_MPA_PAY_CLASS
+GST_TYPE_RTP_MPA_PAY
+<SUBSECTION Private>
+gst_rtp_mpa_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpmparobustdepay</FILE>
+<TITLE>rtpmparobustdepay</TITLE>
+GstRtpMPARobustDepay
+<SUBSECTION Standard>
+GstRtpMPARobustDepayClass
+GST_RTP_MPA_ROBUST_DEPAY
+GST_RTP_MPA_ROBUST_DEPAY_CAST
+GST_IS_RTP_MPA_ROBUST_DEPAY
+GST_RTP_MPA_ROBUST_DEPAY_CLASS
+GST_IS_RTP_MPA_ROBUST_DEPAY_CLASS
+GST_TYPE_RTP_MPA_ROBUST_DEPAY
+<SUBSECTION Private>
+gst_rtp_mpa_robust_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpmpvdepay</FILE>
+<TITLE>rtpmpvdepay</TITLE>
+GstRtpMPVDepay
+<SUBSECTION Standard>
+GstRtpMPVDepayClass
+GST_RTP_MPV_DEPAY
+GST_RTP_MPV_DEPAY_CAST
+GST_IS_RTP_MPV_DEPAY
+GST_RTP_MPV_DEPAY_CLASS
+GST_IS_RTP_MPV_DEPAY_CLASS
+GST_TYPE_RTP_MPV_DEPAY
+<SUBSECTION Private>
+gst_rtp_mpv_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpopuspay</FILE>
+<TITLE>rtpopuspay</TITLE>
+GstRtpOPUSPay
+<SUBSECTION Standard>
+GstRtpOPUSPayClass
+GST_RTP_OPUS_PAY
+GST_RTP_OPUS_PAY_CAST
+GST_IS_RTP_OPUS_PAY
+GST_RTP_OPUS_PAY_CLASS
+GST_IS_RTP_OPUS_PAY_CLASS
+GST_TYPE_RTP_OPUS_PAY
+<SUBSECTION Private>
+gst_rtp_opus_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtppcmadepay</FILE>
+<TITLE>rtppcmadepay</TITLE>
+GstRtpPcmaDepay
+<SUBSECTION Standard>
+GstRtpPcmaDepayClass
+GST_RTP_PCMA_DEPAY
+GST_RTP_PCMA_DEPAY_CAST
+GST_IS_RTP_PCMA_DEPAY
+GST_RTP_PCMA_DEPAY_CLASS
+GST_IS_RTP_PCMA_DEPAY_CLASS
+GST_TYPE_RTP_PCMA_DEPAY
+<SUBSECTION Private>
+gst_rtp_pcma_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtppcmapay</FILE>
+<TITLE>rtppcmapay</TITLE>
+GstRtpPcmaPay
+<SUBSECTION Standard>
+GstRtpPcmaPayClass
+GST_RTP_PCMA_PAY
+GST_RTP_PCMA_PAY_CAST
+GST_IS_RTP_PCMA_PAY
+GST_RTP_PCMA_PAY_CLASS
+GST_IS_RTP_PCMA_PAY_CLASS
+GST_TYPE_RTP_PCMA_PAY
+<SUBSECTION Private>
+gst_rtp_pcma_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtppcmudepay</FILE>
+<TITLE>rtppcmudepay</TITLE>
+GstRtpPcmuDepay
+<SUBSECTION Standard>
+GstRtpPcmuDepayClass
+GST_RTP_PCMU_DEPAY
+GST_RTP_PCMU_DEPAY_CAST
+GST_IS_RTP_PCMU_DEPAY
+GST_RTP_PCMU_DEPAY_CLASS
+GST_IS_RTP_PCMU_DEPAY_CLASS
+GST_TYPE_RTP_PCMU_DEPAY
+<SUBSECTION Private>
+gst_rtp_pcmu_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtppcmupay</FILE>
+<TITLE>rtppcmupay</TITLE>
+GstRtpPcmuPay
+<SUBSECTION Standard>
+GstRtpPcmuPayClass
+GST_RTP_PCMU_PAY
+GST_RTP_PCMU_PAY_CAST
+GST_IS_RTP_PCMU_PAY
+GST_RTP_PCMU_PAY_CLASS
+GST_IS_RTP_PCMU_PAY_CLASS
+GST_TYPE_RTP_PCMU_PAY
+<SUBSECTION Private>
+gst_rtp_pcmu_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpptdemux</FILE>
+<TITLE>rtpptdemux</TITLE>
+GstRtpPtDemux
+<SUBSECTION Standard>
+GstRtpPtDemuxClass
+GST_RTP_PT_DEMUX
+GST_RTP_PT_DEMUX_CAST
+GST_IS_RTP_PT_DEMUX
+GST_RTP_PT_DEMUX_CLASS
+GST_IS_RTP_PT_DEMUX_CLASS
+GST_TYPE_RTP_PT_DEMUX
+<SUBSECTION Private>
+gst_rtp_pt_demux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpqcelpdepay</FILE>
+<TITLE>rtpqcelpdepay</TITLE>
+GstRtpQCELPDepay
+<SUBSECTION Standard>
+GstRtpQCELPDepayClass
+GST_RTP_QCELP_DEPAY
+GST_RTP_QCELP_DEPAY_CAST
+GST_IS_RTP_QCELP_DEPAY
+GST_RTP_QCELP_DEPAY_CLASS
+GST_IS_RTP_QCELP_DEPAY_CLASS
+GST_TYPE_RTP_QCELP_DEPAY
+<SUBSECTION Private>
+gst_rtp_qcelp_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpqdm2depay</FILE>
+<TITLE>rtpqdm2depay</TITLE>
+GstRtpQDM2Depay
+<SUBSECTION Standard>
+GstRtpQDM2DepayClass
+GST_RTP_QD_M2_DEPAY
+GST_RTP_QD_M2_DEPAY_CAST
+GST_IS_RTP_QD_M2_DEPAY
+GST_RTP_QD_M2_DEPAY_CLASS
+GST_IS_RTP_QD_M2_DEPAY_CLASS
+GST_TYPE_RTP_QD_M2_DEPAY
+<SUBSECTION Private>
+gst_rtp_qd_m2_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtprtxreceive</FILE>
+<TITLE>rtprtxreceive</TITLE>
+GstRtpRtxReceive
+<SUBSECTION Standard>
+GstRtpRtxReceiveClass
+GST_RTP_RTX_RECEIVE
+GST_RTP_RTX_RECEIVE_CAST
+GST_IS_RTP_RTX_RECEIVE
+GST_RTP_RTX_RECEIVE_CLASS
+GST_IS_RTP_RTX_RECEIVE_CLASS
+GST_TYPE_RTP_RTX_RECEIVE
+<SUBSECTION Private>
+gst_rtp_rtx_receive_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtprtxsend</FILE>
+<TITLE>rtprtxsend</TITLE>
+GstRtpRtxSend
+<SUBSECTION Standard>
+GstRtpRtxSendClass
+GST_RTP_RTX_SEND
+GST_RTP_RTX_SEND_CAST
+GST_IS_RTP_RTX_SEND
+GST_RTP_RTX_SEND_CLASS
+GST_IS_RTP_RTX_SEND_CLASS
+GST_TYPE_RTP_RTX_SEND
+<SUBSECTION Private>
+gst_rtp_rtx_send_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpsbcpay</FILE>
+<TITLE>rtpsbcpay</TITLE>
+GstRtpSBCPay
+<SUBSECTION Standard>
+GstRtpSBCPayClass
+GST_RTP_SBC_PAY
+GST_RTP_SBC_PAY_CAST
+GST_IS_RTP_SBC_PAY
+GST_RTP_SBC_PAY_CLASS
+GST_IS_RTP_SBC_PAY_CLASS
+GST_TYPE_RTP_SBC_PAY
+<SUBSECTION Private>
+gst_rtp_sbc_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpspeexdepay</FILE>
+<TITLE>rtpspeexdepay</TITLE>
+GstRtpSPEEXDepay
+<SUBSECTION Standard>
+GstRtpSPEEXDepayClass
+GST_RTP_SPEEX_DEPAY
+GST_RTP_SPEEX_DEPAY_CAST
+GST_IS_RTP_SPEEX_DEPAY
+GST_RTP_SPEEX_DEPAY_CLASS
+GST_IS_RTP_SPEEX_DEPAY_CLASS
+GST_TYPE_RTP_SPEEX_DEPAY
+<SUBSECTION Private>
+gst_rtp_speex_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpspeexpay</FILE>
+<TITLE>rtpspeexpay</TITLE>
+GstRtpSPEEXPay
+<SUBSECTION Standard>
+GstRtpSPEEXPayClass
+GST_RTP_SPEEX_PAY
+GST_RTP_SPEEX_PAY_CAST
+GST_IS_RTP_SPEEX_PAY
+GST_RTP_SPEEX_PAY_CLASS
+GST_IS_RTP_SPEEX_PAY_CLASS
+GST_TYPE_RTP_SPEEX_PAY
+<SUBSECTION Private>
+gst_rtp_speex_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpsv3vdepay</FILE>
+<TITLE>rtpsv3vdepay</TITLE>
+GstRtpSV3VDepay
+<SUBSECTION Standard>
+GstRtpSV3VDepayClass
+GST_RTP_S_V3_V_DEPAY
+GST_RTP_S_V3_V_DEPAY_CAST
+GST_IS_RTP_S_V3_V_DEPAY
+GST_RTP_S_V3_V_DEPAY_CLASS
+GST_IS_RTP_S_V3_V_DEPAY_CLASS
+GST_TYPE_RTP_S_V3_V_DEPAY
+<SUBSECTION Private>
+gst_rtp_s_v3_v_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpsbcdepay</FILE>
+<TITLE>rtpsbcdepay</TITLE>
+GstRtpSbcDepay
+<SUBSECTION Standard>
+GstRtpSbcDepayClass
+GST_RTP_SBC_DEPAY
+GST_RTP_SBC_DEPAY_CAST
+GST_IS_RTP_SBC_DEPAY
+GST_RTP_SBC_DEPAY_CLASS
+GST_IS_RTP_SBC_DEPAY_CLASS
+GST_TYPE_RTP_SBC_DEPAY
+<SUBSECTION Private>
+gst_rtp_sbc_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpsession</FILE>
+<TITLE>rtpsession</TITLE>
+GstRtpSession
+<SUBSECTION Standard>
+GstRtpSessionClass
+GST_RTP_SESSION
+GST_RTP_SESSION_CAST
+GST_IS_RTP_SESSION
+GST_RTP_SESSION_CLASS
+GST_IS_RTP_SESSION_CLASS
+GST_TYPE_RTP_SESSION
+<SUBSECTION Private>
+gst_rtp_session_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpssrcdemux</FILE>
+<TITLE>rtpssrcdemux</TITLE>
+GstRtpSsrcDemux
+<SUBSECTION Standard>
+GstRtpSsrcDemuxClass
+GST_RTP_SSRC_DEMUX
+GST_RTP_SSRC_DEMUX_CAST
+GST_IS_RTP_SSRC_DEMUX
+GST_RTP_SSRC_DEMUX_CLASS
+GST_IS_RTP_SSRC_DEMUX_CLASS
+GST_TYPE_RTP_SSRC_DEMUX
+<SUBSECTION Private>
+gst_rtp_ssrc_demux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpstreamdepay</FILE>
+<TITLE>rtpstreamdepay</TITLE>
+GstRtpStreamDepay
+<SUBSECTION Standard>
+GstRtpStreamDepayClass
+GST_RTP_STREAM_DEPAY
+GST_RTP_STREAM_DEPAY_CAST
+GST_IS_RTP_STREAM_DEPAY
+GST_RTP_STREAM_DEPAY_CLASS
+GST_IS_RTP_STREAM_DEPAY_CLASS
+GST_TYPE_RTP_STREAM_DEPAY
+<SUBSECTION Private>
+gst_rtp_stream_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpstreampay</FILE>
+<TITLE>rtpstreampay</TITLE>
+GstRtpStreamPay
+<SUBSECTION Standard>
+GstRtpStreamPayClass
+GST_RTP_STREAM_PAY
+GST_RTP_STREAM_PAY_CAST
+GST_IS_RTP_STREAM_PAY
+GST_RTP_STREAM_PAY_CLASS
+GST_IS_RTP_STREAM_PAY_CLASS
+GST_TYPE_RTP_STREAM_PAY
+<SUBSECTION Private>
+gst_rtp_stream_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtptheoradepay</FILE>
+<TITLE>rtptheoradepay</TITLE>
+GstRtpTheoraDepay
+<SUBSECTION Standard>
+GstRtpTheoraDepayClass
+GST_RTP_THEORA_DEPAY
+GST_RTP_THEORA_DEPAY_CAST
+GST_IS_RTP_THEORA_DEPAY
+GST_RTP_THEORA_DEPAY_CLASS
+GST_IS_RTP_THEORA_DEPAY_CLASS
+GST_TYPE_RTP_THEORA_DEPAY
+<SUBSECTION Private>
+gst_rtp_theora_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtptheorapay</FILE>
+<TITLE>rtptheorapay</TITLE>
+GstRtpTheoraPay
+<SUBSECTION Standard>
+GstRtpTheoraPayClass
+GST_RTP_THEORA_PAY
+GST_RTP_THEORA_PAY_CAST
+GST_IS_RTP_THEORA_PAY
+GST_RTP_THEORA_PAY_CLASS
+GST_IS_RTP_THEORA_PAY_CLASS
+GST_TYPE_RTP_THEORA_PAY
+<SUBSECTION Private>
+gst_rtp_theora_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpvp8depay</FILE>
+<TITLE>rtpvp8depay</TITLE>
+GstRtpVP8Depay
+<SUBSECTION Standard>
+GstRtpVP8DepayClass
+GST_RTP_V_P8_DEPAY
+GST_RTP_V_P8_DEPAY_CAST
+GST_IS_RTP_V_P8_DEPAY
+GST_RTP_V_P8_DEPAY_CLASS
+GST_IS_RTP_V_P8_DEPAY_CLASS
+GST_TYPE_RTP_V_P8_DEPAY
+<SUBSECTION Private>
+gst_rtp_v_p8_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpvp8pay</FILE>
+<TITLE>rtpvp8pay</TITLE>
+GstRtpVP8Pay
+<SUBSECTION Standard>
+GstRtpVP8PayClass
+GST_RTP_V_P8_PAY
+GST_RTP_V_P8_PAY_CAST
+GST_IS_RTP_V_P8_PAY
+GST_RTP_V_P8_PAY_CLASS
+GST_IS_RTP_V_P8_PAY_CLASS
+GST_TYPE_RTP_V_P8_PAY
+<SUBSECTION Private>
+gst_rtp_v_p8_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpvp9depay</FILE>
+<TITLE>rtpvp9depay</TITLE>
+GstRtpVP9Depay
+<SUBSECTION Standard>
+GstRtpVP9DepayClass
+GST_RTP_V_P9_DEPAY
+GST_RTP_V_P9_DEPAY_CAST
+GST_IS_RTP_V_P9_DEPAY
+GST_RTP_V_P9_DEPAY_CLASS
+GST_IS_RTP_V_P9_DEPAY_CLASS
+GST_TYPE_RTP_V_P9_DEPAY
+<SUBSECTION Private>
+gst_rtp_v_p9_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpvp9pay</FILE>
+<TITLE>rtpvp9pay</TITLE>
+GstRtpVP9Pay
+<SUBSECTION Standard>
+GstRtpVP9PayClass
+GST_RTP_V_P9_PAY
+GST_RTP_V_P9_PAY_CAST
+GST_IS_RTP_V_P9_PAY
+GST_RTP_V_P9_PAY_CLASS
+GST_IS_RTP_V_P9_PAY_CLASS
+GST_TYPE_RTP_V_P9_PAY
+<SUBSECTION Private>
+gst_rtp_v_p9_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpvrawdepay</FILE>
+<TITLE>rtpvrawdepay</TITLE>
+GstRtpVRawDepay
+<SUBSECTION Standard>
+GstRtpVRawDepayClass
+GST_RTP_V_RAW_DEPAY
+GST_RTP_V_RAW_DEPAY_CAST
+GST_IS_RTP_V_RAW_DEPAY
+GST_RTP_V_RAW_DEPAY_CLASS
+GST_IS_RTP_V_RAW_DEPAY_CLASS
+GST_TYPE_RTP_V_RAW_DEPAY
+<SUBSECTION Private>
+gst_rtp_v_raw_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpvrawpay</FILE>
+<TITLE>rtpvrawpay</TITLE>
+GstRtpVRawPay
+<SUBSECTION Standard>
+GstRtpVRawPayClass
+GST_RTP_V_RAW_PAY
+GST_RTP_V_RAW_PAY_CAST
+GST_IS_RTP_V_RAW_PAY
+GST_RTP_V_RAW_PAY_CLASS
+GST_IS_RTP_V_RAW_PAY_CLASS
+GST_TYPE_RTP_V_RAW_PAY
+<SUBSECTION Private>
+gst_rtp_v_raw_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpvorbisdepay</FILE>
+<TITLE>rtpvorbisdepay</TITLE>
+GstRtpVorbisDepay
+<SUBSECTION Standard>
+GstRtpVorbisDepayClass
+GST_RTP_VORBIS_DEPAY
+GST_RTP_VORBIS_DEPAY_CAST
+GST_IS_RTP_VORBIS_DEPAY
+GST_RTP_VORBIS_DEPAY_CLASS
+GST_IS_RTP_VORBIS_DEPAY_CLASS
+GST_TYPE_RTP_VORBIS_DEPAY
+<SUBSECTION Private>
+gst_rtp_vorbis_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpvorbispay</FILE>
+<TITLE>rtpvorbispay</TITLE>
+GstRtpVorbisPay
+<SUBSECTION Standard>
+GstRtpVorbisPayClass
+GST_RTP_VORBIS_PAY
+GST_RTP_VORBIS_PAY_CAST
+GST_IS_RTP_VORBIS_PAY
+GST_RTP_VORBIS_PAY_CLASS
+GST_IS_RTP_VORBIS_PAY_CLASS
+GST_TYPE_RTP_VORBIS_PAY
+<SUBSECTION Private>
+gst_rtp_vorbis_pay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-rtpxqtdepay</FILE>
+<TITLE>rtpxqtdepay</TITLE>
+GstRtpXQTDepay
+<SUBSECTION Standard>
+GstRtpXQTDepayClass
+GST_RTP_XQT_DEPAY
+GST_RTP_XQT_DEPAY_CAST
+GST_IS_RTP_XQT_DEPAY
+GST_RTP_XQT_DEPAY_CLASS
+GST_IS_RTP_XQT_DEPAY_CLASS
+GST_TYPE_RTP_XQT_DEPAY
+<SUBSECTION Private>
+gst_rtp_xqt_depay_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-smpte</FILE>
+<TITLE>smpte</TITLE>
+GstSMPTE
+GstSMPTETransitionType
+<SUBSECTION Standard>
+GstSMPTEClass
+GST_SMPTE
+GST_SMPTE_CAST
+GST_IS_SMPTE
+GST_SMPTE_CLASS
+GST_IS_SMPTE_CLASS
+GST_TYPE_SMPTE
+<SUBSECTION Private>
+gst_smpte_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-smptealpha</FILE>
+<TITLE>smptealpha</TITLE>
+GstSMPTEAlpha
+GstSMPTEAlphaTransitionType
+<SUBSECTION Standard>
+GstSMPTEAlphaClass
+GST_SMPTE_ALPHA
+GST_SMPTE_ALPHA_CAST
+GST_IS_SMPTE_ALPHA
+GST_SMPTE_ALPHA_CLASS
+GST_IS_SMPTE_ALPHA_CLASS
+GST_TYPE_SMPTE_ALPHA
+<SUBSECTION Private>
+gst_smpte_alpha_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-sbcparse</FILE>
+<TITLE>sbcparse</TITLE>
+GstSbcParse
+<SUBSECTION Standard>
+GstSbcParseClass
+GST_SBC_PARSE
+GST_SBC_PARSE_CAST
+GST_IS_SBC_PARSE
+GST_SBC_PARSE_CLASS
+GST_IS_SBC_PARSE_CLASS
+GST_TYPE_SBC_PARSE
+<SUBSECTION Private>
+gst_sbc_parse_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-scaletempo</FILE>
+<TITLE>scaletempo</TITLE>
+GstScaletempo
+<SUBSECTION Standard>
+GstScaletempoClass
+GST_SCALETEMPO
+GST_SCALETEMPO_CAST
+GST_IS_SCALETEMPO
+GST_SCALETEMPO_CLASS
+GST_IS_SCALETEMPO_CLASS
+GST_TYPE_SCALETEMPO
+<SUBSECTION Private>
+gst_scaletempo_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-shagadelictv</FILE>
+<TITLE>shagadelictv</TITLE>
+GstShagadelicTV
+<SUBSECTION Standard>
+GstShagadelicTVClass
+GST_SHAGADELIC_TV
+GST_SHAGADELIC_TV_CAST
+GST_IS_SHAGADELIC_TV
+GST_SHAGADELIC_TV_CLASS
+GST_IS_SHAGADELIC_TV_CLASS
+GST_TYPE_SHAGADELIC_TV
+<SUBSECTION Private>
+gst_shagadelic_tv_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-shapewipe</FILE>
+<TITLE>shapewipe</TITLE>
+GstShapeWipe
+<SUBSECTION Standard>
+GstShapeWipeClass
+GST_SHAPE_WIPE
+GST_SHAPE_WIPE_CAST
+GST_IS_SHAPE_WIPE
+GST_SHAPE_WIPE_CLASS
+GST_IS_SHAPE_WIPE_CLASS
+GST_TYPE_SHAPE_WIPE
+<SUBSECTION Private>
+gst_shape_wipe_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-shout2send</FILE>
+<TITLE>shout2send</TITLE>
+GstShout2send
+<SUBSECTION Standard>
+GstShout2sendClass
+GST_SHOUT2SEND
+GST_SHOUT2SEND_CAST
+GST_IS_SHOUT2SEND
+GST_SHOUT2SEND_CLASS
+GST_IS_SHOUT2SEND_CLASS
+GST_TYPE_SHOUT2SEND
+<SUBSECTION Private>
+gst_shout2send_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-souphttpsrc</FILE>
+<TITLE>souphttpsrc</TITLE>
+GstSoupHTTPSrc
+<SUBSECTION Standard>
+GstSoupHTTPSrcClass
+GST_SOUP_HTTP_SRC
+GST_SOUP_HTTP_SRC_CAST
+GST_IS_SOUP_HTTP_SRC
+GST_SOUP_HTTP_SRC_CLASS
+GST_IS_SOUP_HTTP_SRC_CLASS
+GST_TYPE_SOUP_HTTP_SRC
+<SUBSECTION Private>
+gst_soup_http_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-souphttpclientsink</FILE>
+<TITLE>souphttpclientsink</TITLE>
+GstSoupHttpClientSink
+<SUBSECTION Standard>
+GstSoupHttpClientSinkClass
+GST_SOUP_HTTP_CLIENT_SINK
+GST_SOUP_HTTP_CLIENT_SINK_CAST
+GST_IS_SOUP_HTTP_CLIENT_SINK
+GST_SOUP_HTTP_CLIENT_SINK_CLASS
+GST_IS_SOUP_HTTP_CLIENT_SINK_CLASS
+GST_TYPE_SOUP_HTTP_CLIENT_SINK
+<SUBSECTION Private>
+gst_soup_http_client_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-spectrum</FILE>
+<TITLE>spectrum</TITLE>
+GstSpectrum
+<SUBSECTION Standard>
+GstSpectrumClass
+GST_SPECTRUM
+GST_SPECTRUM_CAST
+GST_IS_SPECTRUM
+GST_SPECTRUM_CLASS
+GST_IS_SPECTRUM_CLASS
+GST_TYPE_SPECTRUM
+<SUBSECTION Private>
+gst_spectrum_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-speexdec</FILE>
+<TITLE>speexdec</TITLE>
+GstSpeexDec
+<SUBSECTION Standard>
+GstSpeexDecClass
+GST_SPEEX_DEC
+GST_SPEEX_DEC_CAST
+GST_IS_SPEEX_DEC
+GST_SPEEX_DEC_CLASS
+GST_IS_SPEEX_DEC_CLASS
+GST_TYPE_SPEEX_DEC
+<SUBSECTION Private>
+gst_speex_dec_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-speexenc</FILE>
+<TITLE>speexenc</TITLE>
+GstSpeexEnc
+GstSpeexEncMode
+<SUBSECTION Standard>
+GstSpeexEncClass
+GST_SPEEX_ENC
+GST_SPEEX_ENC_CAST
+GST_IS_SPEEX_ENC
+GST_SPEEX_ENC_CLASS
+GST_IS_SPEEX_ENC_CLASS
+GST_TYPE_SPEEX_ENC
+<SUBSECTION Private>
+gst_speex_enc_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-splitfilesrc</FILE>
+<TITLE>splitfilesrc</TITLE>
+GstSplitFileSrc
+<SUBSECTION Standard>
+GstSplitFileSrcClass
+GST_SPLIT_FILE_SRC
+GST_SPLIT_FILE_SRC_CAST
+GST_IS_SPLIT_FILE_SRC
+GST_SPLIT_FILE_SRC_CLASS
+GST_IS_SPLIT_FILE_SRC_CLASS
+GST_TYPE_SPLIT_FILE_SRC
+<SUBSECTION Private>
+gst_split_file_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-splitmuxsink</FILE>
+<TITLE>splitmuxsink</TITLE>
+GstSplitMuxSink
+<SUBSECTION Standard>
+GstSplitMuxSinkClass
+GST_SPLIT_MUX_SINK
+GST_SPLIT_MUX_SINK_CAST
+GST_IS_SPLIT_MUX_SINK
+GST_SPLIT_MUX_SINK_CLASS
+GST_IS_SPLIT_MUX_SINK_CLASS
+GST_TYPE_SPLIT_MUX_SINK
+<SUBSECTION Private>
+gst_split_mux_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-splitmuxsrc</FILE>
+<TITLE>splitmuxsrc</TITLE>
+GstSplitMuxSrc
+<SUBSECTION Standard>
+GstSplitMuxSrcClass
+GST_SPLIT_MUX_SRC
+GST_SPLIT_MUX_SRC_CAST
+GST_IS_SPLIT_MUX_SRC
+GST_SPLIT_MUX_SRC_CLASS
+GST_IS_SPLIT_MUX_SRC_CLASS
+GST_TYPE_SPLIT_MUX_SRC
+<SUBSECTION Private>
+gst_split_mux_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-streaktv</FILE>
+<TITLE>streaktv</TITLE>
+GstStreakTV
+<SUBSECTION Standard>
+GstStreakTVClass
+GST_STREAK_TV
+GST_STREAK_TV_CAST
+GST_IS_STREAK_TV
+GST_STREAK_TV_CLASS
+GST_IS_STREAK_TV_CLASS
+GST_TYPE_STREAK_TV
+<SUBSECTION Private>
+gst_streak_tv_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-taginject</FILE>
+<TITLE>taginject</TITLE>
+GstTagInject
+<SUBSECTION Standard>
+GstTagInjectClass
+GST_TAG_INJECT
+GST_TAG_INJECT_CAST
+GST_IS_TAG_INJECT
+GST_TAG_INJECT_CLASS
+GST_IS_TAG_INJECT_CLASS
+GST_TYPE_TAG_INJECT
+<SUBSECTION Private>
+gst_tag_inject_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-testsink</FILE>
+<TITLE>testsink</TITLE>
+GstTest
+<SUBSECTION Standard>
+GstTestClass
+GST_TEST
+GST_TEST_CAST
+GST_IS_TEST
+GST_TEST_CLASS
+GST_IS_TEST_CLASS
+GST_TYPE_TEST
+<SUBSECTION Private>
+gst_test_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-twolamemp2enc</FILE>
+<TITLE>twolame</TITLE>
+GstTwoLame
+<SUBSECTION Standard>
+GstTwoLameClass
+GST_TWO_LAME
+GST_TWO_LAME_CLASS
+GST_IS_TWO_LAME
+GST_IS_TWO_LAME_CLASS
+GST_TYPE_TWO_LAME
+gst_two_lame_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-udpsink</FILE>
+<TITLE>udpsink</TITLE>
+GstUDPSink
+<SUBSECTION Standard>
+GstUDPSinkClass
+GST_UDP_SINK
+GST_UDP_SINK_CAST
+GST_IS_UDP_SINK
+GST_UDP_SINK_CLASS
+GST_IS_UDP_SINK_CLASS
+GST_TYPE_UDP_SINK
+<SUBSECTION Private>
+gst_udp_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-udpsrc</FILE>
+<TITLE>udpsrc</TITLE>
+GstUDPSrc
+<SUBSECTION Standard>
+GstUDPSrcClass
+GST_UDP_SRC
+GST_UDP_SRC_CAST
+GST_IS_UDP_SRC
+GST_UDP_SRC_CLASS
+GST_IS_UDP_SRC_CLASS
+GST_TYPE_UDP_SRC
+<SUBSECTION Private>
+gst_udp_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-v4l2radio</FILE>
+<TITLE>v4l2radio</TITLE>
+GstV4l2Radio
+<SUBSECTION Standard>
+GstV4l2RadioClass
+GST_V4L2_RADIO
+GST_V4L2_RADIO_CAST
+GST_IS_V4L2_RADIO
+GST_V4L2_RADIO_CLASS
+GST_IS_V4L2_RADIO_CLASS
+GST_TYPE_V4L2_RADIO
+<SUBSECTION Private>
+gst_v4l2_radio_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-v4l2sink</FILE>
+<TITLE>v4l2sink</TITLE>
+GstV4l2Sink
+<SUBSECTION Standard>
+GstV4l2SinkClass
+GST_V4L2_SINK
+GST_V4L2_SINK_CAST
+GST_IS_V4L2_SINK
+GST_V4L2_SINK_CLASS
+GST_IS_V4L2_SINK_CLASS
+GST_TYPE_V4L2_SINK
+<SUBSECTION Private>
+gst_v4l2_sink_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-v4l2src</FILE>
+<TITLE>v4l2src</TITLE>
+GstV4l2Src
+<SUBSECTION Standard>
+GstV4l2SrcClass
+GST_V4L2_SRC
+GST_V4L2_SRC_CAST
+GST_IS_V4L2_SRC
+GST_V4L2_SRC_CLASS
+GST_IS_V4L2_SRC_CLASS
+GST_TYPE_V4L2_SRC
+<SUBSECTION Private>
+gst_v4l2_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-vp8dec</FILE>
+<TITLE>vp8dec</TITLE>
+GstVP8Dec
+<SUBSECTION Standard>
+GstVP8DecClass
+GST_V_P8_DEC
+GST_V_P8_DEC_CAST
+GST_IS_V_P8_DEC
+GST_V_P8_DEC_CLASS
+GST_IS_V_P8_DEC_CLASS
+GST_TYPE_V_P8_DEC
+<SUBSECTION Private>
+gst_v_p8_dec_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-vp8enc</FILE>
+<TITLE>vp8enc</TITLE>
+GstVP8Enc
+<SUBSECTION Standard>
+GstVP8EncClass
+GST_V_P8_ENC
+GST_V_P8_ENC_CAST
+GST_IS_V_P8_ENC
+GST_V_P8_ENC_CLASS
+GST_IS_V_P8_ENC_CLASS
+GST_TYPE_V_P8_ENC
+<SUBSECTION Private>
+gst_v_p8_enc_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-vp9dec</FILE>
+<TITLE>vp9dec</TITLE>
+GstVP9Dec
+<SUBSECTION Standard>
+GstVP9DecClass
+GST_V_P9_DEC
+GST_V_P9_DEC_CAST
+GST_IS_V_P9_DEC
+GST_V_P9_DEC_CLASS
+GST_IS_V_P9_DEC_CLASS
+GST_TYPE_V_P9_DEC
+<SUBSECTION Private>
+gst_v_p9_dec_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-vp9enc</FILE>
+<TITLE>vp9enc</TITLE>
+GstVP9Enc
+<SUBSECTION Standard>
+GstVP9EncClass
+GST_V_P9_ENC
+GST_V_P9_ENC_CAST
+GST_IS_V_P9_ENC
+GST_V_P9_ENC_CLASS
+GST_IS_V_P9_ENC_CLASS
+GST_TYPE_V_P9_ENC
+<SUBSECTION Private>
+gst_v_p9_enc_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-vertigotv</FILE>
+<TITLE>vertigotv</TITLE>
+GstVertigoTV
+<SUBSECTION Standard>
+GstVertigoTVClass
+GST_VERTIGO_TV
+GST_VERTIGO_TV_CAST
+GST_IS_VERTIGO_TV
+GST_VERTIGO_TV_CLASS
+GST_IS_VERTIGO_TV_CLASS
+GST_TYPE_VERTIGO_TV
+<SUBSECTION Private>
+gst_vertigo_tv_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-videobalance</FILE>
+<TITLE>videobalance</TITLE>
+GstVideoBalance
+<SUBSECTION Standard>
+GstVideoBalanceClass
+GST_VIDEO_BALANCE
+GST_VIDEO_BALANCE_CAST
+GST_IS_VIDEO_BALANCE
+GST_VIDEO_BALANCE_CLASS
+GST_IS_VIDEO_BALANCE_CLASS
+GST_TYPE_VIDEO_BALANCE
+<SUBSECTION Private>
+gst_video_balance_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-videobox</FILE>
+<TITLE>videobox</TITLE>
+GstVideoBox
+GstVideoBoxFill
+<SUBSECTION Standard>
+GstVideoBoxClass
+GST_VIDEO_BOX
+GST_VIDEO_BOX_CAST
+GST_IS_VIDEO_BOX
+GST_VIDEO_BOX_CLASS
+GST_IS_VIDEO_BOX_CLASS
+GST_TYPE_VIDEO_BOX
+<SUBSECTION Private>
+gst_video_box_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-videocrop</FILE>
+<TITLE>videocrop</TITLE>
+GstVideoCrop
+<SUBSECTION Standard>
+GstVideoCropClass
+GST_VIDEO_CROP
+GST_VIDEO_CROP_CAST
+GST_IS_VIDEO_CROP
+GST_VIDEO_CROP_CLASS
+GST_IS_VIDEO_CROP_CLASS
+GST_TYPE_VIDEO_CROP
+<SUBSECTION Private>
+gst_video_crop_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-videoflip</FILE>
+<TITLE>videoflip</TITLE>
+GstVideoFlip
+GstVideoFlipMethod
+<SUBSECTION Standard>
+GstVideoFlipClass
+GST_VIDEO_FLIP
+GST_VIDEO_FLIP_CAST
+GST_IS_VIDEO_FLIP
+GST_VIDEO_FLIP_CLASS
+GST_IS_VIDEO_FLIP_CLASS
+GST_TYPE_VIDEO_FLIP
+<SUBSECTION Private>
+gst_video_flip_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-videomedian</FILE>
+<TITLE>videomedian</TITLE>
+GstVideoMedian
+GstVideoMedianSize
+<SUBSECTION Standard>
+GstVideoMedianClass
+GST_VIDEO_MEDIAN
+GST_VIDEO_MEDIAN_CAST
+GST_IS_VIDEO_MEDIAN
+GST_VIDEO_MEDIAN_CLASS
+GST_IS_VIDEO_MEDIAN_CLASS
+GST_TYPE_VIDEO_MEDIAN
+<SUBSECTION Private>
+gst_video_median_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-videomixer</FILE>
+<TITLE>videomixer</TITLE>
+GstVideoMixer2
+GstVideoMixer2Background
+<SUBSECTION Standard>
+GstVideoMixer2Class
+GST_VIDEO_MIXER2
+GST_VIDEO_MIXER2_CAST
+GST_IS_VIDEO_MIXER2
+GST_VIDEO_MIXER2_CLASS
+GST_IS_VIDEO_MIXER2_CLASS
+GST_TYPE_VIDEO_MIXER2
+<SUBSECTION Private>
+gst_video_mixer2_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-warptv</FILE>
+<TITLE>warptv</TITLE>
+GstWarpTV
+<SUBSECTION Standard>
+GstWarpTVClass
+GST_WARP_TV
+GST_WARP_TV_CAST
+GST_IS_WARP_TV
+GST_WARP_TV_CLASS
+GST_IS_WARP_TV_CLASS
+GST_TYPE_WARP_TV
+<SUBSECTION Private>
+gst_warp_tv_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-waveformsink</FILE>
+<TITLE>waveformsink</TITLE>
+GstWaveFormSink
+<SUBSECTION Standard>
+GstWaveFormSinkClass
+GST_IS_WAVEFORM_SINK
+GST_IS_WAVEFORM_SINK_CLASS
+GST_WAVEFORM_SINK
+GST_WAVEFORM_SINK_CLASS
+GST_TYPE_WAVEFORM_SINK
+gst_waveform_sink_get_type
+WAVE_FORMAT_96M08
+WAVE_FORMAT_96M16
+WAVE_FORMAT_96S08
+WAVE_FORMAT_96S16
+BUFFER_COUNT
+BUFFER_SIZE
+ERROR_LENGTH
+</SECTION>
+
+<SECTION>
+<FILE>element-wavenc</FILE>
+<TITLE>wavenc</TITLE>
+GstWavEnc
+<SUBSECTION Standard>
+GstWavEncClass
+GST_WAV_ENC
+GST_WAV_ENC_CAST
+GST_IS_WAV_ENC
+GST_WAV_ENC_CLASS
+GST_IS_WAV_ENC_CLASS
+GST_TYPE_WAV_ENC
+<SUBSECTION Private>
+gst_wav_enc_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-wavparse</FILE>
+<TITLE>wavparse</TITLE>
+GstWavParse
+<SUBSECTION Standard>
+GstWavParseClass
+GST_WAV_PARSE
+GST_WAV_PARSE_CAST
+GST_IS_WAV_PARSE
+GST_WAV_PARSE_CLASS
+GST_IS_WAV_PARSE_CLASS
+GST_TYPE_WAV_PARSE
+<SUBSECTION Private>
+gst_wav_parse_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-wavpackdec</FILE>
+<TITLE>wavpackdec</TITLE>
+GstWavpackDec
+<SUBSECTION Standard>
+GstWavpackDecClass
+GST_WAVPACK_DEC
+GST_WAVPACK_DEC_CAST
+GST_IS_WAVPACK_DEC
+GST_WAVPACK_DEC_CLASS
+GST_IS_WAVPACK_DEC_CLASS
+GST_TYPE_WAVPACK_DEC
+<SUBSECTION Private>
+gst_wavpack_dec_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-wavpackenc</FILE>
+<TITLE>wavpackenc</TITLE>
+GstWavpackEnc
+GstWavpackEncCorrectionMode
+GstWavpackEncJSMode
+GstWavpackEncMode
+<SUBSECTION Standard>
+GstWavpackEncClass
+GST_WAVPACK_ENC
+GST_WAVPACK_ENC_CAST
+GST_IS_WAVPACK_ENC
+GST_WAVPACK_ENC_CLASS
+GST_IS_WAVPACK_ENC_CLASS
+GST_TYPE_WAVPACK_ENC
+<SUBSECTION Private>
+gst_wavpack_enc_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-wavpackparse</FILE>
+<TITLE>wavpackparse</TITLE>
+GstWavpackParse
+<SUBSECTION Standard>
+GstWavpackParseClass
+GST_WAVPACK_PARSE
+GST_WAVPACK_PARSE_CAST
+GST_IS_WAVPACK_PARSE
+GST_WAVPACK_PARSE_CLASS
+GST_IS_WAVPACK_PARSE_CLASS
+GST_TYPE_WAVPACK_PARSE
+<SUBSECTION Private>
+gst_wavpack_parse_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-webmmux</FILE>
+<TITLE>webmmux</TITLE>
+GstWebMMux
+<SUBSECTION Standard>
+GstWebMMuxClass
+GST_WEB_M_MUX
+GST_WEB_M_MUX_CAST
+GST_IS_WEB_M_MUX
+GST_WEB_M_MUX_CLASS
+GST_IS_WEB_M_MUX_CLASS
+GST_TYPE_WEB_M_MUX
+<SUBSECTION Private>
+gst_web_m_mux_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-ximagesrc</FILE>
+<TITLE>ximagesrc</TITLE>
+GstXImageSrc
+<SUBSECTION Standard>
+GstXImageSrcClass
+GST_X_IMAGE_SRC
+GST_X_IMAGE_SRC_CAST
+GST_IS_X_IMAGE_SRC
+GST_X_IMAGE_SRC_CLASS
+GST_IS_X_IMAGE_SRC_CLASS
+GST_TYPE_X_IMAGE_SRC
+<SUBSECTION Private>
+gst_x_image_src_get_type
+</SECTION>
+
+<SECTION>
+<FILE>element-y4menc</FILE>
+<TITLE>y4menc</TITLE>
+GstY4mEncode
+<SUBSECTION Standard>
+GstY4mEncodeClass
+GST_Y4M_ENCODE
+GST_Y4M_ENCODE_CAST
+GST_IS_Y4M_ENCODE
+GST_Y4M_ENCODE_CLASS
+GST_IS_Y4M_ENCODE_CLASS
+GST_TYPE_Y4M_ENCODE
+<SUBSECTION Private>
+gst_y4m_encode_get_type
+</SECTION>
+
diff --git a/docs/plugins/gst-plugins-good-plugins.args b/docs/plugins/gst-plugins-good-plugins.args
new file mode 100644
index 0000000..e878300
--- /dev/null
+++ b/docs/plugins/gst-plugins-good-plugins.args
@@ -0,0 +1,24580 @@
+<ARG>
+<NAME>GstIirEqualizer10Bands::band0</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-24,12]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>29 Hz</NICK>
+<BLURB>gain for the frequency band 29 Hz, ranging from -24 dB to +12 dB.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstIirEqualizer10Bands::band1</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-24,12]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>59 Hz</NICK>
+<BLURB>gain for the frequency band 59 Hz, ranging from -24 dB to +12 dB.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstIirEqualizer10Bands::band2</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-24,12]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>119 Hz</NICK>
+<BLURB>gain for the frequency band 119 Hz, ranging from -24 dB to +12 dB.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstIirEqualizer10Bands::band3</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-24,12]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>237 Hz</NICK>
+<BLURB>gain for the frequency band 237 Hz, ranging from -24 dB to +12 dB.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstIirEqualizer10Bands::band4</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-24,12]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>474 Hz</NICK>
+<BLURB>gain for the frequency band 474 Hz, ranging from -24 dB to +12 dB.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstIirEqualizer10Bands::band5</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-24,12]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>947 Hz</NICK>
+<BLURB>gain for the frequency band 947 Hz, ranging from -24 dB to +12 dB.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstIirEqualizer10Bands::band6</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-24,12]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>1889 Hz</NICK>
+<BLURB>gain for the frequency band 1889 Hz, ranging from -24 dB to +12 dB.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstIirEqualizer10Bands::band7</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-24,12]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>3770 Hz</NICK>
+<BLURB>gain for the frequency band 3770 Hz, ranging from -24 dB to +12 dB.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstIirEqualizer10Bands::band8</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-24,12]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>7523 Hz</NICK>
+<BLURB>gain for the frequency band 7523 Hz, ranging from -24 dB to +12 dB.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstIirEqualizer10Bands::band9</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-24,12]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>15011 Hz</NICK>
+<BLURB>gain for the frequency band 15011 Hz, ranging from -24 dB to +12 dB.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstIirEqualizer3Bands::band0</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-24,12]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>110 Hz</NICK>
+<BLURB>gain for the frequency band 100 Hz, ranging from -24.0 to +12.0.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstIirEqualizer3Bands::band1</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-24,12]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>1100 Hz</NICK>
+<BLURB>gain for the frequency band 1100 Hz, ranging from -24.0 to +12.0.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstIirEqualizer3Bands::band2</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-24,12]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>11 kHz</NICK>
+<BLURB>gain for the frequency band 11 kHz, ranging from -24.0 to +12.0.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstIirEqualizerNBands::num-bands</NAME>
+<TYPE>guint</TYPE>
+<RANGE>[1,64]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>num-bands</NICK>
+<BLURB>number of different bands to use.</BLURB>
+<DEFAULT>10</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiFileSink::location</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>File Location</NICK>
+<BLURB>Location of the file to write.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiFileSink::index</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Index</NICK>
+<BLURB>Index to use with location property to create file names.  The index is incremented by one for each buffer written.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiFileSink::next-file</NAME>
+<TYPE>GstMultiFileSinkNext</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Next File</NICK>
+<BLURB>When to start a new file.</BLURB>
+<DEFAULT>New file for each buffer</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiFileSink::post-messages</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Post Messages</NICK>
+<BLURB>Post a message for each file with information of the buffer.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiFileSink::max-files</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max files</NICK>
+<BLURB>Maximum number of files to keep on disk. Once the maximum is reached,old files start to be deleted to make room for new ones.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiFileSink::max-file-size</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Maximum File Size</NICK>
+<BLURB>Maximum file size before starting a new file in max-size mode.</BLURB>
+<DEFAULT>2147483648</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiFileSink::aggregate-gops</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Aggregate GOPs</NICK>
+<BLURB>Whether to aggregate GOPs and process them as a whole without splitting.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiFileSink::max-file-duration</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Maximum File Duration</NICK>
+<BLURB>Maximum file duration before starting a new file in max-size mode.</BLURB>
+<DEFAULT>18446744073709551615</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiFileSrc::caps</NAME>
+<TYPE>GstCaps*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Caps</NICK>
+<BLURB>Caps describing the format of the data.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiFileSrc::index</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>File Index</NICK>
+<BLURB>Index to use with location property to create file names.  The index is incremented by one for each buffer read.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiFileSrc::location</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>File Location</NICK>
+<BLURB>Pattern to create file names of input files.  File names are created by calling sprintf() with the pattern and the current index.</BLURB>
+<DEFAULT>"%05d"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiFileSrc::loop</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Loop</NICK>
+<BLURB>Whether to repeat from the beginning when all files have been read.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiFileSrc::start-index</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Start Index</NICK>
+<BLURB>Start value of index.  The initial value of index can be set either by setting index or start-index.  When the end of the loop is reached, the index will be set to the value start-index.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiFileSrc::stop-index</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Stop Index</NICK>
+<BLURB>Stop value of index.  The special value -1 means no stop.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOssSrc::device</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Device</NICK>
+<BLURB>OSS device (usually /dev/dspN).</BLURB>
+<DEFAULT>"/dev/dsp"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOssSrc::device-name</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Device name</NICK>
+<BLURB>Human-readable name of the sound device.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpectrum::bands</NAME>
+<TYPE>guint</TYPE>
+<RANGE>[2,1073741824]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Bands</NICK>
+<BLURB>Number of frequency bands.</BLURB>
+<DEFAULT>128</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpectrum::interval</NAME>
+<TYPE>guint64</TYPE>
+<RANGE>>= 1</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interval</NICK>
+<BLURB>Interval of time between message posts (in nanoseconds).</BLURB>
+<DEFAULT>100000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpectrum::threshold</NAME>
+<TYPE>gint</TYPE>
+<RANGE><= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Threshold</NICK>
+<BLURB>dB threshold for result. All lower values will be set to this.</BLURB>
+<DEFAULT>-60</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpectrum::message-magnitude</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Magnitude</NICK>
+<BLURB>Whether to add a 'magnitude' field to the structure of any 'spectrum' element messages posted on the bus.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpectrum::message-phase</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Phase</NICK>
+<BLURB>Whether to add a 'phase' field to the structure of any 'spectrum' element messages posted on the bus.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpectrum::post-messages</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Post Messages</NICK>
+<BLURB>Whether to post a 'spectrum' element message on the bus for each passed interval.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpectrum::multi-channel</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Multichannel results</NICK>
+<BLURB>Send separate results for each channel.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoBox::alpha</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Alpha</NICK>
+<BLURB>Alpha value picture.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoBox::border-alpha</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Border Alpha</NICK>
+<BLURB>Alpha value of the border.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoBox::bottom</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Bottom</NICK>
+<BLURB>Pixels to box at bottom (<0 = add a border).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoBox::fill</NAME>
+<TYPE>GstVideoBoxFill</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Fill</NICK>
+<BLURB>How to fill the borders.</BLURB>
+<DEFAULT>Black</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoBox::left</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Left</NICK>
+<BLURB>Pixels to box at left (<0  = add a border).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoBox::right</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Right</NICK>
+<BLURB>Pixels to box at right (<0 = add a border).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoBox::top</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Top</NICK>
+<BLURB>Pixels to box at top (<0 = add a border).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoBox::autocrop</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Auto crop</NICK>
+<BLURB>Auto crop.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSink::host</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>host</NICK>
+<BLURB>The host/IP/Multicast group to send the packets to.</BLURB>
+<DEFAULT>"localhost"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSink::port</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,65535]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>port</NICK>
+<BLURB>The port to send the packets to.</BLURB>
+<DEFAULT>5004</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::caps</NAME>
+<TYPE>GstCaps*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Caps</NICK>
+<BLURB>The caps of the source pad.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::multicast-group</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Multicast Group</NICK>
+<BLURB>The Address of multicast group to join. (DEPRECATED: Use address property instead).</BLURB>
+<DEFAULT>"0.0.0.0"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::port</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,65535]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Port</NICK>
+<BLURB>The port to receive the packets from, 0=allocate.</BLURB>
+<DEFAULT>5004</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::uri</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>URI</NICK>
+<BLURB>URI in the form of udp://multicast_group:port.</BLURB>
+<DEFAULT>"udp://0.0.0.0:5004"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::buffer-size</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Buffer Size</NICK>
+<BLURB>Size of the kernel receive buffer in bytes, 0=default.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::timeout</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Timeout</NICK>
+<BLURB>Post a message after timeout nanoseconds (0 = disabled).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::skip-first-bytes</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Skip first bytes</NICK>
+<BLURB>number of bytes to skip for each udp packet.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::auto-multicast</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Auto Multicast</NICK>
+<BLURB>Automatically join/leave multicast groups.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::multicast-iface</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Multicast Interface</NICK>
+<BLURB>The network interface on which to join the multicast group.This allows multiple interfaces seperated by comma. ("eth0,eth1").</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::reuse</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Reuse</NICK>
+<BLURB>Enable reuse of the port.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::close-socket</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Close socket</NICK>
+<BLURB>Close socket if passed as property on state change.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::socket</NAME>
+<TYPE>GSocket*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Socket</NICK>
+<BLURB>Socket to use for UDP reception. (NULL == allocate).</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::used-socket</NAME>
+<TYPE>GSocket*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Socket Handle</NICK>
+<BLURB>Socket currently in use for UDP reception. (NULL = no socket).</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::address</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Address</NICK>
+<BLURB>Address to receive packets for. This is equivalent to the multicast-group property for now.</BLURB>
+<DEFAULT>"0.0.0.0"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::loop</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Multicast Loopback</NICK>
+<BLURB>Used for setting the multicast loop parameter. TRUE = enable, FALSE = disable.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstUDPSrc::retrieve-sender-address</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Retrieve Sender Address</NICK>
+<BLURB>Whether to retrieve the sender address and add it to buffers as meta. Disabling this might result in minor performance improvements in certain scenarios.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSMPTE::border</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Border</NICK>
+<BLURB>The border width of the transition.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSMPTE::depth</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,24]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Depth</NICK>
+<BLURB>Depth of the mask in bits.</BLURB>
+<DEFAULT>16</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSMPTE::type</NAME>
+<TYPE>GstSMPTETransitionType</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Type</NICK>
+<BLURB>The type of transition to use.</BLURB>
+<DEFAULT>A bar moves from left to right</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSMPTE::duration</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Duration</NICK>
+<BLURB>Duration of the transition effect in nanoseconds.</BLURB>
+<DEFAULT>1000000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSMPTE::invert</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Invert</NICK>
+<BLURB>Invert transition mask.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::debug</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Debug</NICK>
+<BLURB>Dump request and response messages to stdout(DEPRECATED: Printed all RTSP message to gstreamer log as 'log' level).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::location</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTSP Location</NICK>
+<BLURB>Location of the RTSP url to read.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::protocols</NAME>
+<TYPE>GstRTSPLowerTrans</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Protocols</NICK>
+<BLURB>Allowed lower transport protocols.</BLURB>
+<DEFAULT>GST_RTSP_LOWER_TRANS_UDP|GST_RTSP_LOWER_TRANS_UDP_MCAST|GST_RTSP_LOWER_TRANS_TCP</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::retry</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 65535</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Retry</NICK>
+<BLURB>Max number of retries when allocating RTP ports.</BLURB>
+<DEFAULT>20</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::timeout</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Timeout</NICK>
+<BLURB>Retry TCP transport after UDP timeout microseconds (0 = disabled).</BLURB>
+<DEFAULT>5000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::latency</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Buffer latency in ms</NICK>
+<BLURB>Amount of ms to buffer.</BLURB>
+<DEFAULT>2000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::tcp-timeout</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>TCP Timeout</NICK>
+<BLURB>Fail after timeout microseconds on TCP connections (0 = disabled).</BLURB>
+<DEFAULT>20000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::connection-speed</NAME>
+<TYPE>guint64</TYPE>
+<RANGE><= 18446744073709551</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Connection Speed</NICK>
+<BLURB>Network connection speed in kbps (0 = unknown).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::nat-method</NAME>
+<TYPE>GstRTSPNatMethod</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>NAT Method</NICK>
+<BLURB>Method to use for traversing firewalls and NAT.</BLURB>
+<DEFAULT>Send Dummy packets</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::do-rtcp</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Do RTCP</NICK>
+<BLURB>Send RTCP packets, disable for old incompatible server.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::proxy</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Proxy</NICK>
+<BLURB>Proxy settings for HTTP tunneling. Format: [http://][user:passwd@]host[:port].</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::rtp-blocksize</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 65536</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTP Blocksize</NICK>
+<BLURB>RTP package size to suggest to server (0 = disabled).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::user-id</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>user-id</NICK>
+<BLURB>RTSP location URI user id for authentication.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::user-pw</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>user-pw</NICK>
+<BLURB>RTSP location URI user password for authentication.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::buffer-mode</NAME>
+<TYPE>GstRTSPSrcBufferMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Buffer Mode</NICK>
+<BLURB>Control the buffering algorithm in use.</BLURB>
+<DEFAULT>Choose mode depending on stream live</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::port-range</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Port range</NICK>
+<BLURB>Client port range that can be used to receive RTP and RTCP data, eg. 3000-3005 (NULL = no restrictions).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::udp-buffer-size</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>UDP Buffer Size</NICK>
+<BLURB>Size of the kernel UDP receive buffer in bytes, 0=default.</BLURB>
+<DEFAULT>524288</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::short-header</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Short Header</NICK>
+<BLURB>Only send the basic RTSP headers for broken encoders.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::do-rtsp-keep-alive</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Do RTSP Keep Alive</NICK>
+<BLURB>Send RTSP keep alive packets, disable for old incompatible server.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::drop-on-latency</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Drop buffers when maximum latency is reached</NICK>
+<BLURB>Tells the jitterbuffer to never exceed the given latency in size.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::probation</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Number of probations</NICK>
+<BLURB>Consecutive packet sequence numbers to accept the source.</BLURB>
+<DEFAULT>2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::udp-reconnect</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Reconnect to the server</NICK>
+<BLURB>Reconnect to the server if RTSP connection is closed when doing UDP.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::proxy-id</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>proxy-id</NICK>
+<BLURB>HTTP proxy URI user id for authentication.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::proxy-pw</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>proxy-pw</NICK>
+<BLURB>HTTP proxy URI user password for authentication.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::multicast-iface</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Multicast Interface</NICK>
+<BLURB>The network interface on which to join the multicast group.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::ntp-sync</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Sync on NTP clock</NICK>
+<BLURB>Synchronize received streams to the NTP clock.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::use-pipeline-clock</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Use pipeline clock</NICK>
+<BLURB>Use the pipeline running-time to set the NTP time in the RTCP SR messages(DEPRECATED: Use ntp-time-source property).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::sdes</NAME>
+<TYPE>GstStructure*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>SDES</NICK>
+<BLURB>The SDES items of this session.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::tls-database</NAME>
+<TYPE>GTlsDatabase*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>TLS database</NICK>
+<BLURB>TLS database with anchor certificate authorities used to validate the server certificate.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::tls-validation-flags</NAME>
+<TYPE>GTlsCertificateFlags</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>TLS validation flags</NICK>
+<BLURB>TLS certificate validation flags used to validate the server certificate.</BLURB>
+<DEFAULT>G_TLS_CERTIFICATE_UNKNOWN_CA|G_TLS_CERTIFICATE_BAD_IDENTITY|G_TLS_CERTIFICATE_NOT_ACTIVATED|G_TLS_CERTIFICATE_EXPIRED|G_TLS_CERTIFICATE_REVOKED|G_TLS_CERTIFICATE_INSECURE|G_TLS_CERTIFICATE_GENERIC_ERROR</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::do-retransmission</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Retransmission</NICK>
+<BLURB>Ask the server to retransmit lost packets.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::tls-interaction</NAME>
+<TYPE>GTlsInteraction*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>TLS interaction</NICK>
+<BLURB>A GTlsInteraction object to promt the user for password or certificate.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::ntp-time-source</NAME>
+<TYPE>GstRTSPSrcNtpTimeSource</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>NTP Time Source</NICK>
+<BLURB>NTP time source for RTCP packets.</BLURB>
+<DEFAULT>NTP time based on realtime clock</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::user-agent</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>User Agent</NICK>
+<BLURB>The User-Agent string to send to the server.</BLURB>
+<DEFAULT>"GStreamer/1.13.0.1"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::max-rtcp-rtp-time-diff</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max RTCP RTP Time Diff</NICK>
+<BLURB>Maximum amount of time in ms that the RTP time in RTCP SRs is allowed to be ahead (-1 disabled).</BLURB>
+<DEFAULT>1000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::rfc7273-sync</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Sync on RFC7273 clock</NICK>
+<BLURB>Synchronize received streams to the RFC7273 clock (requires clock and offset to be provided).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::default-rtsp-version</NAME>
+<TYPE>GstRTSPVersion</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>The RTSP version to try first</NICK>
+<BLURB>The RTSP version that should be tried first when negotiating version.</BLURB>
+<DEFAULT>GST_RTSP_VERSION_1_0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::max-ts-offset</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max TS Offset</NICK>
+<BLURB>The maximum absolute value of the time offset in (nanoseconds). Note, if the ntp-sync parameter is set the default value is changed to 0 (no limit).</BLURB>
+<DEFAULT>3000000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTSPSrc::max-ts-offset-adjustment</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Timestamp Offset Adjustment</NICK>
+<BLURB>The maximum number of nanoseconds per frame that time stamp offsets may be adjusted (0 = no limit).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPDec::latency</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Buffer latency in ms</NICK>
+<BLURB>Amount of ms to buffer.</BLURB>
+<DEFAULT>200</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstLevel::interval</NAME>
+<TYPE>guint64</TYPE>
+<RANGE>>= 1</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interval</NICK>
+<BLURB>Interval of time between message posts (in nanoseconds).</BLURB>
+<DEFAULT>100000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstLevel::message</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>message</NICK>
+<BLURB>Post a 'level' message for each passed interval (deprecated, use the post-messages property instead).</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstLevel::peak-falloff</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Peak Falloff</NICK>
+<BLURB>Decay rate of decay peak after TTL (in dB/sec).</BLURB>
+<DEFAULT>10</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstLevel::peak-ttl</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Peak TTL</NICK>
+<BLURB>Time To Live of decay peak before it falls back (in nanoseconds).</BLURB>
+<DEFAULT>300000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstLevel::post-messages</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Post Messages</NICK>
+<BLURB>Whether to post a 'level' element message on the bus for each passed interval.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDiceTV::square-bits</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Square Bits</NICK>
+<BLURB>The size of the Squares.</BLURB>
+<DEFAULT>4</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVertigoTV::speed</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0.01,100]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Speed</NICK>
+<BLURB>Control the speed of movement.</BLURB>
+<DEFAULT>0.02</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVertigoTV::zoom-speed</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1.01,1.1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Zoom Speed</NICK>
+<BLURB>Control the rate of zooming.</BLURB>
+<DEFAULT>1.01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRevTV::delay</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,100]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay in frames between updates.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRevTV::gain</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,200]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Gain</NICK>
+<BLURB>Control gain.</BLURB>
+<DEFAULT>50</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRevTV::linespace</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,100]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Linespace</NICK>
+<BLURB>Control line spacing.</BLURB>
+<DEFAULT>6</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQuarkTV::planes</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,64]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Planes</NICK>
+<BLURB>Number of planes.</BLURB>
+<DEFAULT>16</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAlpha::alpha</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Alpha</NICK>
+<BLURB>The value for the alpha channel.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAlpha::angle</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,90]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Angle</NICK>
+<BLURB>Size of the colorcube to change.</BLURB>
+<DEFAULT>20</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAlpha::method</NAME>
+<TYPE>GstAlphaMethod</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Method</NICK>
+<BLURB>How the alpha channels should be created.</BLURB>
+<DEFAULT>Set/adjust alpha channel</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAlpha::noise-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,64]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Noise Level</NICK>
+<BLURB>Size of noise radius.</BLURB>
+<DEFAULT>2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAlpha::target-b</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 255</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Target Blue</NICK>
+<BLURB>The blue color value for custom RGB chroma keying.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAlpha::target-g</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 255</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Target Green</NICK>
+<BLURB>The green color value for custom RGB chroma keying.</BLURB>
+<DEFAULT>255</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAlpha::target-r</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 255</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Target Red</NICK>
+<BLURB>The red color value for custom RGB chroma keying.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAlpha::black-sensitivity</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 128</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Black Sensitivity</NICK>
+<BLURB>Sensitivity to dark colors.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAlpha::white-sensitivity</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 128</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>White Sensitivity</NICK>
+<BLURB>Sensitivity to bright colors.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAlpha::prefer-passthrough</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Prefer Passthrough</NICK>
+<BLURB>Don't do any processing for alpha=1.0 if possible.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstShout2send::description</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>description</NICK>
+<BLURB>description.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstShout2send::genre</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>genre</NICK>
+<BLURB>genre.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstShout2send::ip</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>ip</NICK>
+<BLURB>IP address or hostname.</BLURB>
+<DEFAULT>"127.0.0.1"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstShout2send::mount</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>mount</NICK>
+<BLURB>mount.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstShout2send::password</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>password</NICK>
+<BLURB>password.</BLURB>
+<DEFAULT>"hackme"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstShout2send::port</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,65535]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>port</NICK>
+<BLURB>port.</BLURB>
+<DEFAULT>8000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstShout2send::protocol</NAME>
+<TYPE>GstShout2SendProtocol</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>protocol</NICK>
+<BLURB>Connection Protocol to use.</BLURB>
+<DEFAULT>Http Protocol (icecast 2.x)</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstShout2send::streamname</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>streamname</NICK>
+<BLURB>name of the stream.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstShout2send::url</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>url</NICK>
+<BLURB>the stream's homepage URL.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstShout2send::username</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>username</NICK>
+<BLURB>username.</BLURB>
+<DEFAULT>"source"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstShout2send::public</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>public</NICK>
+<BLURB>If the stream should be listed on the server's stream directory.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstShout2send::timeout</NAME>
+<TYPE>guint</TYPE>
+<RANGE>>= 1</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>timeout</NICK>
+<BLURB>Max amount of time to wait for network activity, in milliseconds.</BLURB>
+<DEFAULT>10000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpeexDec::enh</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Enh</NICK>
+<BLURB>Enable perceptual enhancement.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPngEnc::compression-level</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 9</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>compression-level</NICK>
+<BLURB>PNG compression level.</BLURB>
+<DEFAULT>6</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPngEnc::snapshot</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Snapshot</NICK>
+<BLURB>Send EOS after encoding a frame, useful for snapshots.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstCACASink::anti-aliasing</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Anti Aliasing</NICK>
+<BLURB>Enables Anti-Aliasing.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstCACASink::dither</NAME>
+<TYPE>GstCACASinkDithering</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Dither Type</NICK>
+<BLURB>Set type of Dither.</BLURB>
+<DEFAULT>No dithering</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstCACASink::screen-height</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Screen Height</NICK>
+<BLURB>The height of the screen.</BLURB>
+<DEFAULT>25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstCACASink::screen-width</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Screen Width</NICK>
+<BLURB>The width of the screen.</BLURB>
+<DEFAULT>80</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJpegEnc::quality</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Quality</NICK>
+<BLURB>Quality of encoding.</BLURB>
+<DEFAULT>85</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJpegEnc::idct-method</NAME>
+<TYPE>GstIDCTMethod</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>IDCT Method</NICK>
+<BLURB>The IDCT algorithm to use.</BLURB>
+<DEFAULT>Faster, less accurate integer method</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDVDec::clamp-chroma</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Clamp chroma</NICK>
+<BLURB>Clamp chroma.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDVDec::clamp-luma</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Clamp luma</NICK>
+<BLURB>Clamp luma.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDVDec::drop-factor</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 1</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Drop Factor</NICK>
+<BLURB>Only decode Nth frame.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDVDec::quality</NAME>
+<TYPE>GstDVDecQualityEnum</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Quality</NICK>
+<BLURB>Decoding quality.</BLURB>
+<DEFAULT>Highest quality colour decoding</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAASink::brightness</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>brightness</NICK>
+<BLURB>brightness.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAASink::contrast</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>contrast</NICK>
+<BLURB>contrast.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAASink::dither</NAME>
+<TYPE>GstAASinkDitherers</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>dither</NICK>
+<BLURB>dither.</BLURB>
+<DEFAULT>no dithering</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAASink::driver</NAME>
+<TYPE>GstAASinkDrivers</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>driver</NICK>
+<BLURB>driver.</BLURB>
+<DEFAULT>X11 driver 1.1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAASink::frame-time</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>frame time</NICK>
+<BLURB>frame time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAASink::frames-displayed</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>frames displayed</NICK>
+<BLURB>frames displayed.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAASink::gamma</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>gamma</NICK>
+<BLURB>gamma.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAASink::height</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>height</NICK>
+<BLURB>height.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAASink::inversion</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>inversion</NICK>
+<BLURB>inversion.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAASink::randomval</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>randomval</NICK>
+<BLURB>randomval.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAASink::width</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>width</NICK>
+<BLURB>width.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpeexEnc::abr</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>ABR</NICK>
+<BLURB>Enable average bit-rate (0 = disabled).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpeexEnc::bitrate</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Encoding Bit-rate</NICK>
+<BLURB>Specify an encoding bit-rate (in bps). (0 = automatic).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpeexEnc::complexity</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Complexity</NICK>
+<BLURB>Set encoding complexity.</BLURB>
+<DEFAULT>3</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpeexEnc::dtx</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DTX</NICK>
+<BLURB>Enable discontinuous transmission.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpeexEnc::last-message</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>last-message</NICK>
+<BLURB>The last status message.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpeexEnc::nframes</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>NFrames</NICK>
+<BLURB>Number of frames per buffer.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpeexEnc::quality</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Quality</NICK>
+<BLURB>Encoding quality.</BLURB>
+<DEFAULT>8</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpeexEnc::vad</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>VAD</NICK>
+<BLURB>Enable voice activity detection.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpeexEnc::vbr</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>VBR</NICK>
+<BLURB>Enable variable bit-rate.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSpeexEnc::mode</NAME>
+<TYPE>GstSpeexEncMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>The encoding mode.</BLURB>
+<DEFAULT>Auto</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDV1394Src::channel</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,64]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Channel</NICK>
+<BLURB>Channel number for listening.</BLURB>
+<DEFAULT>63</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDV1394Src::consecutive</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 1</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>consecutive frames</NICK>
+<BLURB>send n consecutive frames after skipping.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDV1394Src::drop-incomplete</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>drop incomplete</NICK>
+<BLURB>drop incomplete frames.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDV1394Src::guid</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>GUID</NICK>
+<BLURB>select one of multiple DV devices by its GUID. use a hexadecimal like 0xhhhhhhhhhhhhhhhh. (0 = no guid).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDV1394Src::port</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[G_MAXULONG,16]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Port</NICK>
+<BLURB>Port number (-1 automatic).</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDV1394Src::skip</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>skip frames</NICK>
+<BLURB>skip n frames.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDV1394Src::use-avc</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Use AV/C</NICK>
+<BLURB>Use AV/C VTR control.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDV1394Src::device-name</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>device name</NICK>
+<BLURB>user-friendly name of the device.</BLURB>
+<DEFAULT>"Default"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacEnc::blocksize</NAME>
+<TYPE>guint</TYPE>
+<RANGE>[16,65535]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Blocksize</NICK>
+<BLURB>Blocksize in samples.</BLURB>
+<DEFAULT>4608</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacEnc::escape-coding</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Do Escape coding</NICK>
+<BLURB>search for escape codes in the entropy coding stage for slightly better compression.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacEnc::exhaustive-model-search</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Do exhaustive model search</NICK>
+<BLURB>do exhaustive search of LP coefficient quantization (expensive!).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacEnc::loose-mid-side-stereo</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Loose mid side stereo</NICK>
+<BLURB>Loose mid side stereo.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacEnc::max-lpc-order</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 32</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Max LPC order</NICK>
+<BLURB>Max LPC order; 0 => use only fixed predictors.</BLURB>
+<DEFAULT>8</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacEnc::max-residual-partition-order</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 16</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Max residual partition order</NICK>
+<BLURB>Max residual partition order (above 4 doesn't usually help much).</BLURB>
+<DEFAULT>3</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacEnc::mid-side-stereo</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Do mid side stereo</NICK>
+<BLURB>Do mid side stereo (only for stereo input).</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacEnc::min-residual-partition-order</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 16</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Min residual partition order</NICK>
+<BLURB>Min residual partition order (above 4 doesn't usually help much).</BLURB>
+<DEFAULT>3</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacEnc::qlp-coeff-prec-search</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Do QLP coefficients precision search</NICK>
+<BLURB>false = use qlp_coeff_precision, true = search around qlp_coeff_precision, take best.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacEnc::qlp-coeff-precision</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 32</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>QLP coefficients precision</NICK>
+<BLURB>Precision in bits of quantized linear-predictor coefficients; 0 = automatic.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacEnc::quality</NAME>
+<TYPE>GstFlacEncQuality</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Quality</NICK>
+<BLURB>Speed versus compression tradeoff.</BLURB>
+<DEFAULT>5 - Default</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacEnc::rice-parameter-search-dist</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 15</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>rice_parameter_search_dist</NICK>
+<BLURB>0 = try only calc'd parameter k; else try all [k-dist..k+dist] parameters, use best.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacEnc::streamable-subset</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Streamable subset</NICK>
+<BLURB>true to limit encoder to generating a Subset stream, else false.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacEnc::padding</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Padding</NICK>
+<BLURB>Write a PADDING block with this length in bytes.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacEnc::seekpoints</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= -2147483647</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Seekpoints</NICK>
+<BLURB>Add SEEKTABLE metadata (if > 0, number of entries, if < 0, interval in sec).</BLURB>
+<DEFAULT>-10</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOssSink::device</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Device</NICK>
+<BLURB>OSS device (usually /dev/dspN).</BLURB>
+<DEFAULT>"/dev/dsp"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMatroskaMux::writing-app</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Writing application.</NICK>
+<BLURB>The name the application that creates the matroska file.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMatroskaMux::version</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,2]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>DocType version</NICK>
+<BLURB>This parameter determines what Matroska features can be used.</BLURB>
+<DEFAULT>2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMatroskaMux::min-index-interval</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Minimum time between index entries</NICK>
+<BLURB>An index entry is created every so many nanoseconds.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMatroskaMux::streamable</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Determines whether output should be streamable</NICK>
+<BLURB>If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMatroskaMux::timecodescale</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>[1,1000000000]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Timecode Scale</NICK>
+<BLURB>TimecodeScale used to calculate the Raw Timecode of a Block.</BLURB>
+<DEFAULT>1000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMatroskaMux::max-cluster-duration</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Maximum cluster duration</NICK>
+<BLURB>A new cluster will be created if its duration exceeds this value. 0 means no maximum duration.</BLURB>
+<DEFAULT>65535000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMatroskaMux::min-cluster-duration</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Minimum cluster duration</NICK>
+<BLURB>Desidered cluster duration as nanoseconds. A new cluster will be created irrespective of this property if a force key unit event is received. 0 means create a new cluster for each video keyframe or for each audio buffer in audio only streams.</BLURB>
+<DEFAULT>500000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTest::allowed-timestamp-deviation</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>>= G_MAXULONG</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>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTest::buffer-count</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>buffer count</NICK>
+<BLURB>number of buffers in stream.</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTest::expected-buffer-count</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>expected buffer count</NICK>
+<BLURB>expected number of buffers in stream.</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTest::expected-length</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>expected length</NICK>
+<BLURB>expected length of stream.</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTest::expected-md5</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>expected md5</NICK>
+<BLURB>expected md5 of processing the whole data.</BLURB>
+<DEFAULT>"---"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTest::length</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>length</NICK>
+<BLURB>length of stream.</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTest::md5</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>md5</NICK>
+<BLURB>md5 of processing the whole data.</BLURB>
+<DEFAULT>"---"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTest::timestamp-deviation</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>>= G_MAXULONG</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>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstProgressReport::silent</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Do not print output to stdout</NICK>
+<BLURB>Do not print output to stdout.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstProgressReport::update-freq</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 1</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Update Frequency</NICK>
+<BLURB>Number of seconds between reports when data is flowing.</BLURB>
+<DEFAULT>5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstProgressReport::format</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>format</NICK>
+<BLURB>Format to use for the querying.</BLURB>
+<DEFAULT>"auto"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstProgressReport::do-query</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Use a query instead of buffer metadata to determine stream position</NICK>
+<BLURB>Use a query instead of buffer metadata to determine stream position.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstNavSeek::seek-offset</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Seek Offset</NICK>
+<BLURB>Time in seconds to seek by.</BLURB>
+<DEFAULT>5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstBreakMyData::probability</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>probability</NICK>
+<BLURB>probability for each byte in the buffer to be changed.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstBreakMyData::seed</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>seed</NICK>
+<BLURB>seed for randomness (initialized when going from READY to PAUSED).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstBreakMyData::set-to</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[G_MAXULONG,255]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>set-to</NICK>
+<BLURB>set changed bytes to this value (-1 means random value.</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstBreakMyData::skip</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>skip</NICK>
+<BLURB>amount of bytes skipped at the beginning of stream.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstCutter::leaky</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Leaky</NICK>
+<BLURB>do we leak buffers when below threshold ?.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstCutter::pre-length</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Pre-recording buffer length</NICK>
+<BLURB>Length of pre-recording buffer (in nanoseconds).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstCutter::run-length</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Run length</NICK>
+<BLURB>Length of drop below threshold before cut_stop (in nanoseconds).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstCutter::threshold</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Threshold</NICK>
+<BLURB>Volume threshold before trigger.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstCutter::threshold-dB</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Threshold (dB)</NICK>
+<BLURB>Volume threshold before trigger (in dB).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoFlip::method</NAME>
+<TYPE>GstVideoFlipMethod</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>method</NICK>
+<BLURB>method (deprecated, use video-direction instead).</BLURB>
+<DEFAULT>Identity (no rotation)</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpMP4VPay::config-interval</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 3600</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Config Send Interval</NICK>
+<BLURB>Send Config Insertion Interval in seconds (configuration headers will be multiplexed in the data stream when detected.) (0 = disabled).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultipartMux::boundary</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Boundary</NICK>
+<BLURB>Boundary string.</BLURB>
+<DEFAULT>"ThisRandomString"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstID3Demux::prefer-v1</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Prefer version 1 tag</NICK>
+<BLURB>Prefer tags from ID3v1 tag at end of file when both ID3v1 and ID3v2 tags are present.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDynUDPSink::close-socket</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Close socket</NICK>
+<BLURB>Close socket if passed as property on state change.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDynUDPSink::socket</NAME>
+<TYPE>GSocket*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Socket</NICK>
+<BLURB>Socket to use for UDP sending. (NULL == allocate).</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDynUDPSink::bind-address</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Bind Address</NICK>
+<BLURB>Address to bind the socket to.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDynUDPSink::bind-port</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,65535]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Bind Port</NICK>
+<BLURB>Port to bind the socket to.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDynUDPSink::socket-v6</NAME>
+<TYPE>GSocket*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Socket IPv6</NICK>
+<BLURB>Socket to use for UDPv6 sending. (NULL == allocate).</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::bytes-served</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Bytes served</NICK>
+<BLURB>Total number of bytes sent to all clients.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::bytes-to-serve</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Bytes to serve</NICK>
+<BLURB>Number of bytes received to serve to clients.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::clients</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Clients</NICK>
+<BLURB>A comma separated list of host:port pairs with destinations.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::auto-multicast</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Automatically join/leave multicast groups</NICK>
+<BLURB>Automatically join/leave the multicast groups, FALSE means user has to do it himself.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::loop</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Multicast Loopback</NICK>
+<BLURB>Used for setting the multicast loop parameter. TRUE = enable, FALSE = disable.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::qos-dscp</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[G_MAXULONG,63]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>QoS diff srv code point</NICK>
+<BLURB>Quality of Service, differentiated services code point (-1 default).</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::ttl</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,255]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Unicast TTL</NICK>
+<BLURB>Used for setting the unicast TTL parameter.</BLURB>
+<DEFAULT>64</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::ttl-mc</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,255]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Multicast TTL</NICK>
+<BLURB>Used for setting the multicast TTL parameter.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::send-duplicates</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Send Duplicates</NICK>
+<BLURB>When a distination/port pair is added multiple times, send packets multiple times as well.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::buffer-size</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Buffer Size</NICK>
+<BLURB>Size of the kernel send buffer in bytes, 0=default.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::close-socket</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Close socket</NICK>
+<BLURB>Close socket if passed as property on state change.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::socket</NAME>
+<TYPE>GSocket*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Socket Handle</NICK>
+<BLURB>Socket to use for UDP sending. (NULL == allocate).</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::used-socket</NAME>
+<TYPE>GSocket*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Used Socket Handle</NICK>
+<BLURB>Socket currently in use for UDP sending. (NULL == no socket).</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::force-ipv4</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Force IPv4</NICK>
+<BLURB>Forcing the use of an IPv4 socket (DEPRECATED, has no effect anymore).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::multicast-iface</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Multicast Interface</NICK>
+<BLURB>The network interface on which to join the multicast group.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::bind-address</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Bind Address</NICK>
+<BLURB>Address to bind the socket to.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::bind-port</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,65535]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Bind Port</NICK>
+<BLURB>Port to bind the socket to.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::socket-v6</NAME>
+<TYPE>GSocket*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Socket Handle IPv6</NICK>
+<BLURB>Socket to use for UDPv6 sending. (NULL == allocate).</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultiUDPSink::used-socket-v6</NAME>
+<TYPE>GSocket*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Used Socket Handle IPv6</NICK>
+<BLURB>Socket currently in use for UDPv6 sending. (NULL == no socket).</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstXImageSrc::display-name</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Display</NICK>
+<BLURB>X Display Name.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstXImageSrc::show-pointer</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Show Mouse Pointer</NICK>
+<BLURB>Show mouse pointer (if XFixes extension enabled).</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstXImageSrc::endx</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= G_MAXINT</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>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstXImageSrc::endy</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= G_MAXINT</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>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstXImageSrc::startx</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= G_MAXINT</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>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstXImageSrc::starty</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= G_MAXINT</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>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstXImageSrc::use-damage</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Use XDamage</NICK>
+<BLURB>Use XDamage (if XDamage extension enabled).</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstXImageSrc::remote</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Remote dispay</NICK>
+<BLURB>Whether the display is remote.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstXImageSrc::xid</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Window XID</NICK>
+<BLURB>Window XID to capture from.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstXImageSrc::xname</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Window name</NICK>
+<BLURB>Window name to capture from.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoBalance::brightness</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Brightness</NICK>
+<BLURB>brightness.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoBalance::contrast</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Contrast</NICK>
+<BLURB>contrast.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoBalance::hue</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Hue</NICK>
+<BLURB>hue.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoBalance::saturation</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Saturation</NICK>
+<BLURB>saturation.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultipartDemux::boundary</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Boundary</NICK>
+<BLURB>The boundary string separating data, automatic if NULL.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMultipartDemux::single-stream</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Single Stream</NICK>
+<BLURB>Assume that there is only one stream whose content-type will not change and emit no-more-pads as soon as the first boundary content is parsed, decoded, and pads are linked.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAviMux::bigfile</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Bigfile Support (>2GB)</NICK>
+<BLURB>Support for openDML-2.0 (big) AVI files.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJpegDec::idct-method</NAME>
+<TYPE>GstIDCTMethod</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>IDCT Method</NICK>
+<BLURB>The IDCT algorithm to use.</BLURB>
+<DEFAULT>Faster, less accurate integer method</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJpegDec::max-errors</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Maximum Consecutive Decoding Errors</NICK>
+<BLURB>(Deprecated) Error out after receiving N consecutive decoding errors (-1 = never fail, 0 = automatic, 1 = fail on first error).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPiLBCDepay::mode</NAME>
+<TYPE>iLBCMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>iLBC frame mode.</BLURB>
+<DEFAULT>30ms frames</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioPanorama::panorama</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Panorama</NICK>
+<BLURB>Position in stereo panorama (-1.0 left -> 1.0 right).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioPanorama::method</NAME>
+<TYPE>GstAudioPanoramaMethod</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Panning method</NICK>
+<BLURB>Psychoacoustic mode keeps same perceived loudness, simple mode just controls volume of one channel.</BLURB>
+<DEFAULT>Psychoacoustic Panning (default)</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioInvert::degree</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Degree</NICK>
+<BLURB>Degree of inversion.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioAmplify::amplification</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Amplification</NICK>
+<BLURB>Factor of amplification.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioAmplify::clipping-method</NAME>
+<TYPE>GstAudioAmplifyClippingMethod</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Clipping method</NICK>
+<BLURB>Selects how to handle values higher than the maximum.</BLURB>
+<DEFAULT>Normal clipping (default)</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioDynamic::characteristics</NAME>
+<TYPE>GstAudioDynamicCharacteristics</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Characteristics</NICK>
+<BLURB>Selects whether the ratio should be applied smooth (soft-knee) or hard (hard-knee).</BLURB>
+<DEFAULT>Hard Knee (default)</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioDynamic::mode</NAME>
+<TYPE>GstAudioDynamicMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Selects whether the filter should work on loud samples (compressor) orquiet samples (expander).</BLURB>
+<DEFAULT>Compressor (default)</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioDynamic::ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Ratio</NICK>
+<BLURB>Ratio that should be applied.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioDynamic::threshold</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Threshold</NICK>
+<BLURB>Threshold until the filter is activated.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstWavpackEnc::bitrate</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 9600000</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Bitrate</NICK>
+<BLURB>Try to encode with this average bitrate (bits/sec). This enables lossy encoding, values smaller than 24000 disable it again.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstWavpackEnc::bits-per-sample</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,24]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Bits per sample</NICK>
+<BLURB>Try to encode with this amount of bits per sample. This enables lossy encoding, values smaller than 2.0 disable it again.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstWavpackEnc::correction-mode</NAME>
+<TYPE>GstWavpackEncCorrectionMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Correction stream mode</NICK>
+<BLURB>Use this mode for the correction stream. Only works in lossy mode!.</BLURB>
+<DEFAULT>Create no correction file</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstWavpackEnc::extra-processing</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 6</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Extra processing</NICK>
+<BLURB>Use better but slower filters for better compression/quality.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstWavpackEnc::joint-stereo-mode</NAME>
+<TYPE>GstWavpackEncJSMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Joint-Stereo mode</NICK>
+<BLURB>Use this joint-stereo mode.</BLURB>
+<DEFAULT>auto</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstWavpackEnc::md5</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>MD5</NICK>
+<BLURB>Store MD5 hash of raw samples within the file.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstWavpackEnc::mode</NAME>
+<TYPE>GstWavpackEncMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Encoding mode</NICK>
+<BLURB>Speed versus compression tradeoff.</BLURB>
+<DEFAULT>Normal Compression</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpMP2TDepay::skip-first-bytes</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Skip first bytes</NICK>
+<BLURB>The amount of bytes that need to be skipped at the beginning of the payload.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpH263PPay::fragmentation-mode</NAME>
+<TYPE>GstFragmentationMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Fragmentation Mode</NICK>
+<BLURB>Packet Fragmentation Mode.</BLURB>
+<DEFAULT>Normal</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstGamma::gamma</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0.01,10]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Gamma</NICK>
+<BLURB>gamma.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoCrop::bottom</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Bottom</NICK>
+<BLURB>Pixels to crop at bottom (-1 to auto-crop).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoCrop::left</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Left</NICK>
+<BLURB>Pixels to crop at left (-1 to auto-crop).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoCrop::right</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Right</NICK>
+<BLURB>Pixels to crop at right (-1 to auto-crop).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoCrop::top</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Top</NICK>
+<BLURB>Pixels to crop at top (-1 to auto-crop).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Src::device</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Device</NICK>
+<BLURB>Device location.</BLURB>
+<DEFAULT>"/dev/video0"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Src::device-name</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Device name</NICK>
+<BLURB>Name of the device.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Src::flags</NAME>
+<TYPE>GstV4l2DeviceTypeFlags</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Flags</NICK>
+<BLURB>Device type flags.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Src::device-fd</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>File descriptor</NICK>
+<BLURB>File descriptor of the device.</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Src::brightness</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Brightness</NICK>
+<BLURB>Picture brightness, or more precisely, the black level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Src::contrast</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Contrast</NICK>
+<BLURB>Picture contrast or luma gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Src::hue</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Hue</NICK>
+<BLURB>Hue or color balance.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Src::saturation</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Saturation</NICK>
+<BLURB>Picture color saturation or chroma gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Src::norm</NAME>
+<TYPE>V4L2_TV_norms</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>TV norm</NICK>
+<BLURB>video standard.</BLURB>
+<DEFAULT>none</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Src::io-mode</NAME>
+<TYPE>GstV4l2IOMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>IO mode</NICK>
+<BLURB>I/O mode.</BLURB>
+<DEFAULT>GST_V4L2_IO_AUTO</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Src::extra-controls</NAME>
+<TYPE>GstStructure*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Extra Controls</NICK>
+<BLURB>Extra v4l2 controls (CIDs) for the device.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Src::force-aspect-ratio</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Force aspect ratio</NICK>
+<BLURB>When enabled, the pixel aspect ratio will be enforced.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Src::pixel-aspect-ratio</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Pixel Aspect Ratio</NICK>
+<BLURB>Overwrite the pixel aspect ratio of the device.</BLURB>
+<DEFAULT>"1/1"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioChebBand::lower-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100000]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Lower frequency</NICK>
+<BLURB>Start frequency of the band (Hz).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioChebBand::mode</NAME>
+<TYPE>GstAudioChebBandMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Low pass or high pass mode.</BLURB>
+<DEFAULT>Band pass (default)</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioChebBand::poles</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[4,32]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Poles</NICK>
+<BLURB>Number of poles to use, will be rounded up to the next multiply of four.</BLURB>
+<DEFAULT>4</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioChebBand::ripple</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,200]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Ripple</NICK>
+<BLURB>Amount of ripple (dB).</BLURB>
+<DEFAULT>0.25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioChebBand::type</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,2]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Type</NICK>
+<BLURB>Type of the chebychev filter.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioChebBand::upper-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100000]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Upper frequency</NICK>
+<BLURB>Stop frequency of the band (Hz).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioChebLimit::cutoff</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100000]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Cutoff</NICK>
+<BLURB>Cut off frequency (Hz).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioChebLimit::mode</NAME>
+<TYPE>GstAudioChebLimitMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Low pass or high pass mode.</BLURB>
+<DEFAULT>Low pass (default)</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioChebLimit::poles</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[2,32]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Poles</NICK>
+<BLURB>Number of poles to use, will be rounded up to the next even number.</BLURB>
+<DEFAULT>4</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioChebLimit::ripple</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,200]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Ripple</NICK>
+<BLURB>Amount of ripple (dB).</BLURB>
+<DEFAULT>0.25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioChebLimit::type</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,2]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Type</NICK>
+<BLURB>Type of the chebychev filter.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioWSincBand::lower-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100000]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Lower Frequency</NICK>
+<BLURB>Cut-off lower frequency (Hz).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioWSincBand::upper-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100000]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Upper Frequency</NICK>
+<BLURB>Cut-off upper frequency (Hz).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioWSincBand::mode</NAME>
+<TYPE>GstAudioWSincBandMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Band pass or band reject mode.</BLURB>
+<DEFAULT>Band pass (default)</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioWSincBand::window</NAME>
+<TYPE>GstAudioWSincBandWindow</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Window</NICK>
+<BLURB>Window function to use.</BLURB>
+<DEFAULT>Hamming window (default)</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioWSincBand::length</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[3,256000]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Length</NICK>
+<BLURB>Filter kernel length, will be rounded to the next odd number.</BLURB>
+<DEFAULT>101</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioWSincLimit::length</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[3,256000]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Length</NICK>
+<BLURB>Filter kernel length, will be rounded to the next odd number.</BLURB>
+<DEFAULT>101</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioWSincLimit::mode</NAME>
+<TYPE>GstAudioWSincLimitMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Low pass or high pass mode.</BLURB>
+<DEFAULT>Low pass (default)</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioWSincLimit::window</NAME>
+<TYPE>GstAudioWSincLimitWindow</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Window</NICK>
+<BLURB>Window function to use.</BLURB>
+<DEFAULT>Hamming window (default)</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioWSincLimit::cutoff</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100000]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Cutoff</NICK>
+<BLURB>Cut-off Frequency (Hz).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRndBufferSize::max</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 1</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>maximum</NICK>
+<BLURB>maximum buffer size.</BLURB>
+<DEFAULT>8192</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRndBufferSize::min</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>mininum</NICK>
+<BLURB>mininum buffer size.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRndBufferSize::seed</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>random number seed</NICK>
+<BLURB>seed for randomness (initialized when going from READY to PAUSED).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAutoAudioSink::ts-offset</NAME>
+<TYPE>gint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>TS Offset</NICK>
+<BLURB>Timestamp offset in nanoseconds.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAutoAudioSink::sync</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Sync</NICK>
+<BLURB>Sync on the clock.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAutoVideoSink::ts-offset</NAME>
+<TYPE>gint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>TS Offset</NICK>
+<BLURB>Timestamp offset in nanoseconds.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAutoVideoSink::sync</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Sync</NICK>
+<BLURB>Sync on the clock.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOsxAudioSink::device</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Device ID</NICK>
+<BLURB>Device ID of output device.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOsxAudioSrc::device</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Device ID</NICK>
+<BLURB>Device ID of input device.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOSXVideoSink::embed</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>embed</NICK>
+<BLURB>When enabled, it  can be embedded.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOSXVideoSink::fullscreen</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>fullscreen</NICK>
+<BLURB>When enabled, the view  is fullscreen.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstGdkPixbufSink::last-pixbuf</NAME>
+<TYPE>GdkPixbuf*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Last Pixbuf</NICK>
+<BLURB>Last GdkPixbuf object rendered.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstGdkPixbufSink::post-messages</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Post Messages</NICK>
+<BLURB>Whether to post messages containing pixbufs on the bus.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::automatic-redirect</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>automatic-redirect</NICK>
+<BLURB>Automatically follow HTTP redirects (HTTP Status Code 3xx).</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::cookies</NAME>
+<TYPE>GStrv</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Cookies</NICK>
+<BLURB>HTTP request cookies.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::iradio-mode</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>iradio-mode</NICK>
+<BLURB>Enable internet radio mode (ask server to send shoutcast/icecast metadata interleaved with the actual stream data).</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::location</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Location</NICK>
+<BLURB>Location to read from.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::proxy</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Proxy</NICK>
+<BLURB>HTTP proxy server URI.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::user-agent</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>User-Agent</NICK>
+<BLURB>Value of the User-Agent HTTP request header field.</BLURB>
+<DEFAULT>"GStreamer souphttpsrc 1.13.0.1 "</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::is-live</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>is-live</NICK>
+<BLURB>Act like a live source.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::proxy-id</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>proxy-id</NICK>
+<BLURB>HTTP proxy URI user id for authentication.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::proxy-pw</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>proxy-pw</NICK>
+<BLURB>HTTP proxy URI user password for authentication.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::user-id</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>user-id</NICK>
+<BLURB>HTTP location URI user id for authentication.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::user-pw</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>user-pw</NICK>
+<BLURB>HTTP location URI user password for authentication.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::extra-headers</NAME>
+<TYPE>GstStructure*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Extra Headers</NICK>
+<BLURB>Extra headers to append to the HTTP request.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::timeout</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 3600</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>timeout</NICK>
+<BLURB>Value in seconds to timeout a blocking I/O (0 = No timeout).</BLURB>
+<DEFAULT>15</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::compress</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Compress</NICK>
+<BLURB>Allow compressed content encodings.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::http-log-level</NAME>
+<TYPE>SoupLoggerLogLevel</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>HTTP log level</NICK>
+<BLURB>Set log level for soup's HTTP session log.</BLURB>
+<DEFAULT>SOUP_LOGGER_LOG_HEADERS</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::keep-alive</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>keep-alive</NICK>
+<BLURB>Use HTTP persistent connections.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::retries</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Retries</NICK>
+<BLURB>Maximum number of retries until giving up (-1=infinite).</BLURB>
+<DEFAULT>3</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::ssl-ca-file</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>SSL CA File</NICK>
+<BLURB>Location of a SSL anchor CA file to use.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::ssl-strict</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>SSL Strict</NICK>
+<BLURB>Strict SSL certificate checking.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::ssl-use-system-ca-file</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Use System CA File</NICK>
+<BLURB>Use system CA file.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::tls-database</NAME>
+<TYPE>GTlsDatabase*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>TLS database</NICK>
+<BLURB>TLS database with anchor certificate authorities used to validate the server certificate.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::method</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>HTTP method</NICK>
+<BLURB>The HTTP method to use (GET, HEAD, OPTIONS, etc).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHTTPSrc::tls-interaction</NAME>
+<TYPE>GTlsInteraction*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>TLS interaction</NICK>
+<BLURB>A GTlsInteraction object to be used when the connection or certificate database need to interact with the user.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPDVPay::mode</NAME>
+<TYPE>GstDVPayMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>The payload mode of payloading.</BLURB>
+<DEFAULT>Video only</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpH264Pay::sprop-parameter-sets</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>sprop-parameter-sets</NICK>
+<BLURB>The base64 sprop-parameter-sets to set in out caps (set to NULL to extract from stream).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpH264Pay::config-interval</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[G_MAXULONG,3600]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>SPS PPS Send Interval</NICK>
+<BLURB>Send SPS and PPS Insertion Interval in seconds (sprop parameter sets will be multiplexed in the data stream when detected.) (0 = disabled, -1 = send with every IDR frame).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hardLimiter::Residue-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Residue-level</NICK>
+<BLURB>Residue-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hardLimiter::Wet-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wet-level</NICK>
+<BLURB>Wet-level.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hardLimiter::dB-limit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>dB-limit</NICK>
+<BLURB>dB-limit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dj-eq-mono::Hi-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,6]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Hi-gain</NICK>
+<BLURB>Hi-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dj-eq-mono::Lo-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,6]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Lo-gain</NICK>
+<BLURB>Lo-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dj-eq-mono::Mid-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,6]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mid-gain</NICK>
+<BLURB>Mid-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dj-eq-mono::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dj-eq::Hi-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,6]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Hi-gain</NICK>
+<BLURB>Hi-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dj-eq::Lo-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,6]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Lo-gain</NICK>
+<BLURB>Lo-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dj-eq::Mid-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,6]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mid-gain</NICK>
+<BLURB>Mid-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dj-eq::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-branch-ic-ococ::First-Output</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>First-Output</NICK>
+<BLURB>First-Output.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-branch-ic-ococ::Input</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input</NICK>
+<BLURB>Input.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-branch-ic-ococ::Second-Output</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Second-Output</NICK>
+<BLURB>Second-Output.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Exaggerate::amount</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>amount</NICK>
+<BLURB>amount.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Transpose::transpose</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-24,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>transpose</NICK>
+<BLURB>transpose.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Accumulate::decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>decay</NICK>
+<BLURB>decay.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Accumulate::glissando</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>glissando</NICK>
+<BLURB>glissando.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sinusWavewrapper::Wrap-degree</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wrap-degree</NICK>
+<BLURB>Wrap-degree.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-foverdrive::Drive-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,3]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Drive-level</NICK>
+<BLURB>Drive-level.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::param-10000Hz-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-10000Hz-gain</NICK>
+<BLURB>param-10000Hz-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::param-100Hz-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-100Hz-gain</NICK>
+<BLURB>param-100Hz-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::param-1250Hz-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-1250Hz-gain</NICK>
+<BLURB>param-1250Hz-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::param-156Hz-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-156Hz-gain</NICK>
+<BLURB>param-156Hz-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::param-1750Hz-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-1750Hz-gain</NICK>
+<BLURB>param-1750Hz-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::param-20000Hz-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-20000Hz-gain</NICK>
+<BLURB>param-20000Hz-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::param-220Hz-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-220Hz-gain</NICK>
+<BLURB>param-220Hz-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::param-2500Hz-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-2500Hz-gain</NICK>
+<BLURB>param-2500Hz-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::param-311Hz-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-311Hz-gain</NICK>
+<BLURB>param-311Hz-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::param-3500Hz-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-3500Hz-gain</NICK>
+<BLURB>param-3500Hz-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::param-440Hz-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-440Hz-gain</NICK>
+<BLURB>param-440Hz-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::param-5000Hz-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-5000Hz-gain</NICK>
+<BLURB>param-5000Hz-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::param-50Hz-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-50Hz-gain</NICK>
+<BLURB>param-50Hz-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::param-622Hz-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-622Hz-gain</NICK>
+<BLURB>param-622Hz-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-mbeq::param-880Hz-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-880Hz-gain</NICK>
+<BLURB>param-880Hz-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delayorama::Amplitude-change</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Amplitude-change</NICK>
+<BLURB>Amplitude-change.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delayorama::Amplitude-random</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Amplitude-random</NICK>
+<BLURB>Amplitude-random.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delayorama::Delay-change</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-change</NICK>
+<BLURB>Delay-change.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delayorama::Delay-random</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-random</NICK>
+<BLURB>Delay-random.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delayorama::Delay-range</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0001,6]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-range</NICK>
+<BLURB>Delay-range.</BLURB>
+<DEFAULT>6</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delayorama::Dry-wet-mix</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-wet-mix</NICK>
+<BLURB>Dry-wet-mix.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delayorama::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delayorama::First-delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>First-delay</NICK>
+<BLURB>First-delay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delayorama::Input-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-96,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input-gain</NICK>
+<BLURB>Input-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delayorama::Number-of-taps</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[2,128]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Number-of-taps</NICK>
+<BLURB>Number-of-taps.</BLURB>
+<DEFAULT>2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delayorama::Random-seed</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,1000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Random-seed</NICK>
+<BLURB>Random-seed.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-1-Bandwidth--octaves-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-1-Bandwidth--octaves-</NICK>
+<BLURB>Band-1-Bandwidth--octaves-.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-1-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[40,280]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-1-Freq--Hz-</NICK>
+<BLURB>Band-1-Freq--Hz-.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-1-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-1-Gain--dB-</NICK>
+<BLURB>Band-1-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-2-Bandwidth--octaves-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-2-Bandwidth--octaves-</NICK>
+<BLURB>Band-2-Bandwidth--octaves-.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-2-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[100,500]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-2-Freq--Hz-</NICK>
+<BLURB>Band-2-Freq--Hz-.</BLURB>
+<DEFAULT>200</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-2-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-2-Gain--dB-</NICK>
+<BLURB>Band-2-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-3-Bandwidth--octaves-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-3-Bandwidth--octaves-</NICK>
+<BLURB>Band-3-Bandwidth--octaves-.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-3-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[200,1000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-3-Freq--Hz-</NICK>
+<BLURB>Band-3-Freq--Hz-.</BLURB>
+<DEFAULT>400</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-3-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-3-Gain--dB-</NICK>
+<BLURB>Band-3-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-4-Bandwidth--octaves-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-4-Bandwidth--octaves-</NICK>
+<BLURB>Band-4-Bandwidth--octaves-.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-4-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[400,2800]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-4-Freq--Hz-</NICK>
+<BLURB>Band-4-Freq--Hz-.</BLURB>
+<DEFAULT>1000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-4-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-4-Gain--dB-</NICK>
+<BLURB>Band-4-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-5-Bandwidth--octaves-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-5-Bandwidth--octaves-</NICK>
+<BLURB>Band-5-Bandwidth--octaves-.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-5-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1000,5000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-5-Freq--Hz-</NICK>
+<BLURB>Band-5-Freq--Hz-.</BLURB>
+<DEFAULT>3000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-5-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-5-Gain--dB-</NICK>
+<BLURB>Band-5-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-6-Bandwidth--octaves-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-6-Bandwidth--octaves-</NICK>
+<BLURB>Band-6-Bandwidth--octaves-.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-6-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[3000,9000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-6-Freq--Hz-</NICK>
+<BLURB>Band-6-Freq--Hz-.</BLURB>
+<DEFAULT>6000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-6-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-6-Gain--dB-</NICK>
+<BLURB>Band-6-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-7-Bandwidth--octaves-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-7-Bandwidth--octaves-</NICK>
+<BLURB>Band-7-Bandwidth--octaves-.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-7-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[6000,18000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-7-Freq--Hz-</NICK>
+<BLURB>Band-7-Freq--Hz-.</BLURB>
+<DEFAULT>12000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-7-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-7-Gain--dB-</NICK>
+<BLURB>Band-7-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-8-Bandwidth--octaves-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-8-Bandwidth--octaves-</NICK>
+<BLURB>Band-8-Bandwidth--octaves-.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-8-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[10000,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-8-Freq--Hz-</NICK>
+<BLURB>Band-8-Freq--Hz-.</BLURB>
+<DEFAULT>15000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer-bw::Band-8-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-8-Gain--dB-</NICK>
+<BLURB>Band-8-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-crossoverDist::Crossover-amplitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Crossover-amplitude</NICK>
+<BLURB>Crossover-amplitude.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-crossoverDist::Smoothing</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Smoothing</NICK>
+<BLURB>Smoothing.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fadDelay::Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fadDelay::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-multivoiceChorus::Delay-base</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[10,40]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-base</NICK>
+<BLURB>Delay-base.</BLURB>
+<DEFAULT>10</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-multivoiceChorus::Detune</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Detune</NICK>
+<BLURB>Detune.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-multivoiceChorus::LFO-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO-frequency</NICK>
+<BLURB>LFO-frequency.</BLURB>
+<DEFAULT>9</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-multivoiceChorus::Number-of-voices</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Number-of-voices</NICK>
+<BLURB>Number-of-voices.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-multivoiceChorus::Output-attenuation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-attenuation</NICK>
+<BLURB>Output-attenuation.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-multivoiceChorus::Voice-separation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Voice-separation</NICK>
+<BLURB>Voice-separation.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-syncsquare-fcga-oa::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,64]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>16</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-smoothDecimate::Resample-rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,44100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resample-rate</NICK>
+<BLURB>Resample-rate.</BLURB>
+<DEFAULT>44100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-smoothDecimate::Smoothing</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Smoothing</NICK>
+<BLURB>Smoothing.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-allpass-n::Decay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay-Time</NICK>
+<BLURB>Decay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-allpass-n::Delay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-Time</NICK>
+<BLURB>Delay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-allpass-n::Max-Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Max-Delay</NICK>
+<BLURB>Max-Delay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-allpass-l::Decay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay-Time</NICK>
+<BLURB>Decay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-allpass-l::Delay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-Time</NICK>
+<BLURB>Delay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-allpass-l::Max-Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Max-Delay</NICK>
+<BLURB>Max-Delay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-allpass-c::Decay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay-Time</NICK>
+<BLURB>Decay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-allpass-c::Delay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-Time</NICK>
+<BLURB>Delay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-allpass-c::Max-Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Max-Delay</NICK>
+<BLURB>Max-Delay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fmOsc::Waveform</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Waveform</NICK>
+<BLURB>Waveform.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-foldover::Drive</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Drive</NICK>
+<BLURB>Drive.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-foldover::Skew</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Skew</NICK>
+<BLURB>Skew.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-valve::Distortion-character</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Distortion-character</NICK>
+<BLURB>Distortion-character.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-valve::Distortion-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Distortion-level</NICK>
+<BLURB>Distortion-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-difference-iamc-oa::Input-to-Subtract</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input-to-Subtract</NICK>
+<BLURB>Input-to-Subtract.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-difference-icma-oa::Input</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input</NICK>
+<BLURB>Input.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-difference-icmc-oc::Difference-Output</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Difference-Output</NICK>
+<BLURB>Difference-Output.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-difference-icmc-oc::Input</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input</NICK>
+<BLURB>Input.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-difference-icmc-oc::Input-to-Subtract</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input-to-Subtract</NICK>
+<BLURB>Input-to-Subtract.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-1::Exp-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Exp-FM-gain</NICK>
+<BLURB>Exp-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-1::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-6,6]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-1::Input-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-60,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input-gain</NICK>
+<BLURB>Input-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-1::Output-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-15,15]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-gain</NICK>
+<BLURB>Output-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-1::Resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance</NICK>
+<BLURB>Resonance.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-1::Resonance-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance-gain</NICK>
+<BLURB>Resonance-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-2::Exp-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Exp-FM-gain</NICK>
+<BLURB>Exp-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-2::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-6,6]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-2::Input-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-60,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input-gain</NICK>
+<BLURB>Input-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-2::Output-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-15,15]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-gain</NICK>
+<BLURB>Output-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-2::Resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance</NICK>
+<BLURB>Resonance.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-2::Resonance-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance-gain</NICK>
+<BLURB>Resonance-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-3::Exp-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Exp-FM-gain</NICK>
+<BLURB>Exp-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-3::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-6,6]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-3::Input-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-60,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input-gain</NICK>
+<BLURB>Input-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-3::Output-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-15,15]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-gain</NICK>
+<BLURB>Output-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-3::Resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance</NICK>
+<BLURB>Resonance.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-3::Resonance-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance-gain</NICK>
+<BLURB>Resonance-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-4::Exp-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Exp-FM-gain</NICK>
+<BLURB>Exp-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-4::Filter-poles</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filter-poles</NICK>
+<BLURB>Filter-poles.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-4::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-6,6]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-4::Input-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-60,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input-gain</NICK>
+<BLURB>Input-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-4::Output-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-15,15]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-gain</NICK>
+<BLURB>Output-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-4::Resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance</NICK>
+<BLURB>Resonance.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvclpf-4::Resonance-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance-gain</NICK>
+<BLURB>Resonance-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-alienwah-mono::Delay</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[5,50]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-alienwah-mono::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-alienwah-mono::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,inf]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-alienwah-mono::Initial-phase-for-stereo</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Initial-phase-for-stereo</NICK>
+<BLURB>Initial-phase-for-stereo.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-alienwah-stereo::Delay</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[5,50]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-alienwah-stereo::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-alienwah-stereo::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,inf]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-alienwah-stereo::Initial-phase-for-stereo</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,6,28319]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Initial-phase-for-stereo</NICK>
+<BLURB>Initial-phase-for-stereo.</BLURB>
+<DEFAULT>6,28319</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gongBeater::Impulse-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Impulse-gain</NICK>
+<BLURB>Impulse-gain.</BLURB>
+<DEFAULT>-70</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gongBeater::Strike-duration</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Strike-duration</NICK>
+<BLURB>Strike-duration.</BLURB>
+<DEFAULT>0,1005</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gongBeater::Strike-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Strike-gain</NICK>
+<BLURB>Strike-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Chorus1::Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Chorus1::Mod-Amplitude-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mod-Amplitude-1</NICK>
+<BLURB>Mod-Amplitude-1.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Chorus1::Mod-Amplitude-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,3]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mod-Amplitude-2</NICK>
+<BLURB>Mod-Amplitude-2.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Chorus1::Mod-Frequency-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,003,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mod-Frequency-1</NICK>
+<BLURB>Mod-Frequency-1.</BLURB>
+<DEFAULT>0,003</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Chorus1::Mod-Frequency-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mod-Frequency-2</NICK>
+<BLURB>Mod-Frequency-2.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Chorus2::Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Chorus2::Mod-Amplitude-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mod-Amplitude-1</NICK>
+<BLURB>Mod-Amplitude-1.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Chorus2::Mod-Amplitude-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,3]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mod-Amplitude-2</NICK>
+<BLURB>Mod-Amplitude-2.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Chorus2::Mod-Frequency-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,003,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mod-Frequency-1</NICK>
+<BLURB>Mod-Frequency-1.</BLURB>
+<DEFAULT>0,003</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Chorus2::Mod-Frequency-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mod-Frequency-2</NICK>
+<BLURB>Mod-Frequency-2.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hilbert::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tapeDelay::Dry-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-level</NICK>
+<BLURB>Dry-level.</BLURB>
+<DEFAULT>-90</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tapeDelay::Tap-1-distance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tap-1-distance</NICK>
+<BLURB>Tap-1-distance.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tapeDelay::Tap-1-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tap-1-level</NICK>
+<BLURB>Tap-1-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tapeDelay::Tap-2-distance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tap-2-distance</NICK>
+<BLURB>Tap-2-distance.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tapeDelay::Tap-2-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tap-2-level</NICK>
+<BLURB>Tap-2-level.</BLURB>
+<DEFAULT>-90</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tapeDelay::Tap-3-distance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tap-3-distance</NICK>
+<BLURB>Tap-3-distance.</BLURB>
+<DEFAULT>2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tapeDelay::Tap-3-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tap-3-level</NICK>
+<BLURB>Tap-3-level.</BLURB>
+<DEFAULT>-90</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tapeDelay::Tap-4-distance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tap-4-distance</NICK>
+<BLURB>Tap-4-distance.</BLURB>
+<DEFAULT>3</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tapeDelay::Tap-4-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tap-4-level</NICK>
+<BLURB>Tap-4-level.</BLURB>
+<DEFAULT>-90</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tapeDelay::Tape-speed</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tape-speed</NICK>
+<BLURB>Tape-speed.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sum-iaic-oa::Second-Input</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Second-Input</NICK>
+<BLURB>Second-Input.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sum-icic-oc::First-Input</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>First-Input</NICK>
+<BLURB>First-Input.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sum-icic-oc::Second-Input</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Second-Input</NICK>
+<BLURB>Second-Input.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sum-icic-oc::Summed-Output</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Summed-Output</NICK>
+<BLURB>Summed-Output.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc1::Attack-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,400]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attack-time</NICK>
+<BLURB>Attack-time.</BLURB>
+<DEFAULT>101,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc1::Knee-radius</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Knee-radius</NICK>
+<BLURB>Knee-radius.</BLURB>
+<DEFAULT>3,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc1::Makeup-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Makeup-gain</NICK>
+<BLURB>Makeup-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc1::Ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Ratio</NICK>
+<BLURB>Ratio.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc1::Release-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,800]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Release-time</NICK>
+<BLURB>Release-time.</BLURB>
+<DEFAULT>401</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc1::Threshold-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-30,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Threshold-level</NICK>
+<BLURB>Threshold-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-combSplitter::Band-separation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[16,640]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-separation</NICK>
+<BLURB>Band-separation.</BLURB>
+<DEFAULT>172</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4m::Amplitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-40,12]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Amplitude</NICK>
+<BLURB>Amplitude.</BLURB>
+<DEFAULT>-40</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4m::Attack-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,5,400]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attack-time</NICK>
+<BLURB>Attack-time.</BLURB>
+<DEFAULT>101,125</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4m::Gain-reduction</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-24,0]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Gain-reduction</NICK>
+<BLURB>Gain-reduction.</BLURB>
+<DEFAULT>-24</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4m::Knee-radius</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Knee-radius</NICK>
+<BLURB>Knee-radius.</BLURB>
+<DEFAULT>3,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4m::Makeup-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Makeup-gain</NICK>
+<BLURB>Makeup-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4m::RMS-peak</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>RMS-peak</NICK>
+<BLURB>RMS-peak.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4m::Ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Ratio</NICK>
+<BLURB>Ratio.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4m::Release-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,800]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Release-time</NICK>
+<BLURB>Release-time.</BLURB>
+<DEFAULT>401</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4m::Threshold-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-30,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Threshold-level</NICK>
+<BLURB>Threshold-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-preamp::fc</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[20,4000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>fc</NICK>
+<BLURB>fc.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-preamp::gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>gain</NICK>
+<BLURB>gain.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lsFilter::Cutoff-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[88,2,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Cutoff-frequency</NICK>
+<BLURB>Cutoff-frequency.</BLURB>
+<DEFAULT>1394,56</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lsFilter::Filter-type</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filter-type</NICK>
+<BLURB>Filter-type.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lsFilter::Resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance</NICK>
+<BLURB>Resonance.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-matrixMSSt::Width</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Width</NICK>
+<BLURB>Width.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lpf::Cutoff-Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Cutoff-Frequency</NICK>
+<BLURB>Cutoff-Frequency.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hpf::Cutoff-Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Cutoff-Frequency</NICK>
+<BLURB>Cutoff-Frequency.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Match-Range</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Match-Range</NICK>
+<BLURB>Match-Range.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Mode</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Mode.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Quantise-Range-Maximum</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Quantise-Range-Maximum</NICK>
+<BLURB>Quantise-Range-Maximum.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Quantise-Range-Minimum</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Quantise-Range-Minimum</NICK>
+<BLURB>Quantise-Range-Minimum.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Steps</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,50]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Steps</NICK>
+<BLURB>Steps.</BLURB>
+<DEFAULT>50</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-0</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-0</NICK>
+<BLURB>Value-0.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-1</NICK>
+<BLURB>Value-1.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-10</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-10</NICK>
+<BLURB>Value-10.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-11</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-11</NICK>
+<BLURB>Value-11.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-12</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-12</NICK>
+<BLURB>Value-12.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-13</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-13</NICK>
+<BLURB>Value-13.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-14</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-14</NICK>
+<BLURB>Value-14.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-15</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-15</NICK>
+<BLURB>Value-15.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-16</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-16</NICK>
+<BLURB>Value-16.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-17</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-17</NICK>
+<BLURB>Value-17.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-18</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-18</NICK>
+<BLURB>Value-18.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-19</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-19</NICK>
+<BLURB>Value-19.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-2</NICK>
+<BLURB>Value-2.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-20</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-20</NICK>
+<BLURB>Value-20.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-21</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-21</NICK>
+<BLURB>Value-21.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-22</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-22</NICK>
+<BLURB>Value-22.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-23</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-23</NICK>
+<BLURB>Value-23.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-24</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-24</NICK>
+<BLURB>Value-24.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-25</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-25</NICK>
+<BLURB>Value-25.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-26</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-26</NICK>
+<BLURB>Value-26.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-27</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-27</NICK>
+<BLURB>Value-27.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-28</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-28</NICK>
+<BLURB>Value-28.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-29</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-29</NICK>
+<BLURB>Value-29.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-3</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-3</NICK>
+<BLURB>Value-3.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-30</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-30</NICK>
+<BLURB>Value-30.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-31</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-31</NICK>
+<BLURB>Value-31.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-32</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-32</NICK>
+<BLURB>Value-32.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-33</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-33</NICK>
+<BLURB>Value-33.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-34</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-34</NICK>
+<BLURB>Value-34.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-35</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-35</NICK>
+<BLURB>Value-35.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-36</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-36</NICK>
+<BLURB>Value-36.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-37</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-37</NICK>
+<BLURB>Value-37.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-38</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-38</NICK>
+<BLURB>Value-38.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-39</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-39</NICK>
+<BLURB>Value-39.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-4</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-4</NICK>
+<BLURB>Value-4.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-40</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-40</NICK>
+<BLURB>Value-40.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-41</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-41</NICK>
+<BLURB>Value-41.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-42</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-42</NICK>
+<BLURB>Value-42.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-43</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-43</NICK>
+<BLURB>Value-43.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-44</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-44</NICK>
+<BLURB>Value-44.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-45</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-45</NICK>
+<BLURB>Value-45.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-46</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-46</NICK>
+<BLURB>Value-46.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-47</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-47</NICK>
+<BLURB>Value-47.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-48</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-48</NICK>
+<BLURB>Value-48.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-49</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-49</NICK>
+<BLURB>Value-49.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-5</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-5</NICK>
+<BLURB>Value-5.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-6</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-6</NICK>
+<BLURB>Value-6.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-7</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-7</NICK>
+<BLURB>Value-7.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-8</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-8</NICK>
+<BLURB>Value-8.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser50::Value-9</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-9</NICK>
+<BLURB>Value-9.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-plate::Damping</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Damping</NICK>
+<BLURB>Damping.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-plate::Dry-wet-mix</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-wet-mix</NICK>
+<BLURB>Dry-wet-mix.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-plate::Reverb-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reverb-time</NICK>
+<BLURB>Reverb-time.</BLURB>
+<DEFAULT>4,255</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-diode::Mode</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,3]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Mode.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Match-Range</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Match-Range</NICK>
+<BLURB>Match-Range.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Mode</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Mode.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Quantise-Range-Maximum</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Quantise-Range-Maximum</NICK>
+<BLURB>Quantise-Range-Maximum.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Quantise-Range-Minimum</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Quantise-Range-Minimum</NICK>
+<BLURB>Quantise-Range-Minimum.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Steps</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Steps</NICK>
+<BLURB>Steps.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-0</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-0</NICK>
+<BLURB>Value-0.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-1</NICK>
+<BLURB>Value-1.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-10</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-10</NICK>
+<BLURB>Value-10.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-11</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-11</NICK>
+<BLURB>Value-11.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-12</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-12</NICK>
+<BLURB>Value-12.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-13</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-13</NICK>
+<BLURB>Value-13.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-14</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-14</NICK>
+<BLURB>Value-14.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-15</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-15</NICK>
+<BLURB>Value-15.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-16</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-16</NICK>
+<BLURB>Value-16.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-17</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-17</NICK>
+<BLURB>Value-17.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-18</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-18</NICK>
+<BLURB>Value-18.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-19</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-19</NICK>
+<BLURB>Value-19.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-2</NICK>
+<BLURB>Value-2.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-20</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-20</NICK>
+<BLURB>Value-20.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-21</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-21</NICK>
+<BLURB>Value-21.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-22</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-22</NICK>
+<BLURB>Value-22.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-23</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-23</NICK>
+<BLURB>Value-23.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-24</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-24</NICK>
+<BLURB>Value-24.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-25</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-25</NICK>
+<BLURB>Value-25.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-26</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-26</NICK>
+<BLURB>Value-26.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-27</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-27</NICK>
+<BLURB>Value-27.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-28</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-28</NICK>
+<BLURB>Value-28.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-29</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-29</NICK>
+<BLURB>Value-29.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-3</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-3</NICK>
+<BLURB>Value-3.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-30</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-30</NICK>
+<BLURB>Value-30.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-31</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-31</NICK>
+<BLURB>Value-31.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-32</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-32</NICK>
+<BLURB>Value-32.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-33</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-33</NICK>
+<BLURB>Value-33.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-34</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-34</NICK>
+<BLURB>Value-34.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-35</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-35</NICK>
+<BLURB>Value-35.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-36</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-36</NICK>
+<BLURB>Value-36.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-37</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-37</NICK>
+<BLURB>Value-37.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-38</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-38</NICK>
+<BLURB>Value-38.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-39</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-39</NICK>
+<BLURB>Value-39.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-4</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-4</NICK>
+<BLURB>Value-4.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-40</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-40</NICK>
+<BLURB>Value-40.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-41</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-41</NICK>
+<BLURB>Value-41.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-42</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-42</NICK>
+<BLURB>Value-42.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-43</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-43</NICK>
+<BLURB>Value-43.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-44</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-44</NICK>
+<BLURB>Value-44.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-45</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-45</NICK>
+<BLURB>Value-45.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-46</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-46</NICK>
+<BLURB>Value-46.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-47</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-47</NICK>
+<BLURB>Value-47.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-48</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-48</NICK>
+<BLURB>Value-48.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-49</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-49</NICK>
+<BLURB>Value-49.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-5</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-5</NICK>
+<BLURB>Value-5.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-50</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-50</NICK>
+<BLURB>Value-50.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-51</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-51</NICK>
+<BLURB>Value-51.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-52</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-52</NICK>
+<BLURB>Value-52.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-53</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-53</NICK>
+<BLURB>Value-53.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-54</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-54</NICK>
+<BLURB>Value-54.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-55</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-55</NICK>
+<BLURB>Value-55.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-56</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-56</NICK>
+<BLURB>Value-56.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-57</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-57</NICK>
+<BLURB>Value-57.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-58</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-58</NICK>
+<BLURB>Value-58.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-59</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-59</NICK>
+<BLURB>Value-59.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-6</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-6</NICK>
+<BLURB>Value-6.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-60</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-60</NICK>
+<BLURB>Value-60.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-61</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-61</NICK>
+<BLURB>Value-61.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-62</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-62</NICK>
+<BLURB>Value-62.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-63</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-63</NICK>
+<BLURB>Value-63.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-64</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-64</NICK>
+<BLURB>Value-64.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-65</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-65</NICK>
+<BLURB>Value-65.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-66</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-66</NICK>
+<BLURB>Value-66.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-67</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-67</NICK>
+<BLURB>Value-67.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-68</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-68</NICK>
+<BLURB>Value-68.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-69</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-69</NICK>
+<BLURB>Value-69.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-7</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-7</NICK>
+<BLURB>Value-7.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-70</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-70</NICK>
+<BLURB>Value-70.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-71</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-71</NICK>
+<BLURB>Value-71.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-72</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-72</NICK>
+<BLURB>Value-72.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-73</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-73</NICK>
+<BLURB>Value-73.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-74</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-74</NICK>
+<BLURB>Value-74.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-75</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-75</NICK>
+<BLURB>Value-75.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-76</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-76</NICK>
+<BLURB>Value-76.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-77</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-77</NICK>
+<BLURB>Value-77.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-78</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-78</NICK>
+<BLURB>Value-78.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-79</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-79</NICK>
+<BLURB>Value-79.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-8</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-8</NICK>
+<BLURB>Value-8.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-80</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-80</NICK>
+<BLURB>Value-80.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-81</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-81</NICK>
+<BLURB>Value-81.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-82</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-82</NICK>
+<BLURB>Value-82.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-83</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-83</NICK>
+<BLURB>Value-83.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-84</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-84</NICK>
+<BLURB>Value-84.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-85</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-85</NICK>
+<BLURB>Value-85.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-86</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-86</NICK>
+<BLURB>Value-86.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-87</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-87</NICK>
+<BLURB>Value-87.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-88</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-88</NICK>
+<BLURB>Value-88.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-89</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-89</NICK>
+<BLURB>Value-89.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-9</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-9</NICK>
+<BLURB>Value-9.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-90</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-90</NICK>
+<BLURB>Value-90.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-91</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-91</NICK>
+<BLURB>Value-91.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-92</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-92</NICK>
+<BLURB>Value-92.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-93</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-93</NICK>
+<BLURB>Value-93.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-94</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-94</NICK>
+<BLURB>Value-94.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-95</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-95</NICK>
+<BLURB>Value-95.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-96</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-96</NICK>
+<BLURB>Value-96.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-97</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-97</NICK>
+<BLURB>Value-97.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-98</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-98</NICK>
+<BLURB>Value-98.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser100::Value-99</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-99</NICK>
+<BLURB>Value-99.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-tubewarmth::Drive</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Drive</NICK>
+<BLURB>Drive.</BLURB>
+<DEFAULT>2,575</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-tubewarmth::Tape--Tube-Blend</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-10,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tape--Tube-Blend</NICK>
+<BLURB>Tape--Tube-Blend.</BLURB>
+<DEFAULT>10</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-reslp::Frequency-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[20,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Offset</NICK>
+<BLURB>Frequency-Offset.</BLURB>
+<DEFAULT>20</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-reslp::Frequency-Pitch</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Pitch</NICK>
+<BLURB>Frequency-Pitch.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-reslp::Gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain</NICK>
+<BLURB>Gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-reslp::Resonance-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance-Offset</NICK>
+<BLURB>Resonance-Offset.</BLURB>
+<DEFAULT>0,001</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-lp::Frequency-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[20,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Offset</NICK>
+<BLURB>Frequency-Offset.</BLURB>
+<DEFAULT>20</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-lp::Frequency-Pitch</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Pitch</NICK>
+<BLURB>Frequency-Pitch.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-lp::Gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain</NICK>
+<BLURB>Gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-lp::Resonance-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance-Offset</NICK>
+<BLURB>Resonance-Offset.</BLURB>
+<DEFAULT>0,001</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-hp::Frequency-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[20,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Offset</NICK>
+<BLURB>Frequency-Offset.</BLURB>
+<DEFAULT>20</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-hp::Frequency-Pitch</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Pitch</NICK>
+<BLURB>Frequency-Pitch.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-hp::Gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain</NICK>
+<BLURB>Gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-hp::Resonance-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance-Offset</NICK>
+<BLURB>Resonance-Offset.</BLURB>
+<DEFAULT>0,001</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-bp1::Frequency-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[20,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Offset</NICK>
+<BLURB>Frequency-Offset.</BLURB>
+<DEFAULT>20</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-bp1::Frequency-Pitch</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Pitch</NICK>
+<BLURB>Frequency-Pitch.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-bp1::Gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain</NICK>
+<BLURB>Gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-bp1::Resonance-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance-Offset</NICK>
+<BLURB>Resonance-Offset.</BLURB>
+<DEFAULT>0,001</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-bp2::Frequency-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[20,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Offset</NICK>
+<BLURB>Frequency-Offset.</BLURB>
+<DEFAULT>20</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-bp2::Frequency-Pitch</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Pitch</NICK>
+<BLURB>Frequency-Pitch.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-bp2::Gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain</NICK>
+<BLURB>Gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-bp2::Resonance-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance-Offset</NICK>
+<BLURB>Resonance-Offset.</BLURB>
+<DEFAULT>0,001</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-notch::Frequency-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[20,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Offset</NICK>
+<BLURB>Frequency-Offset.</BLURB>
+<DEFAULT>20</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-notch::Frequency-Pitch</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Pitch</NICK>
+<BLURB>Frequency-Pitch.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-notch::Gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain</NICK>
+<BLURB>Gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-notch::Resonance-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance-Offset</NICK>
+<BLURB>Resonance-Offset.</BLURB>
+<DEFAULT>0,001</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-peakeq::Frequency-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[20,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Offset</NICK>
+<BLURB>Frequency-Offset.</BLURB>
+<DEFAULT>20</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-peakeq::Frequency-Pitch</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Pitch</NICK>
+<BLURB>Frequency-Pitch.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-peakeq::Gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain</NICK>
+<BLURB>Gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-peakeq::Resonance-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance-Offset</NICK>
+<BLURB>Resonance-Offset.</BLURB>
+<DEFAULT>0,001</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-peakeq::dBgain-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[6,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>dBgain-Offset</NICK>
+<BLURB>dBgain-Offset.</BLURB>
+<DEFAULT>6</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-lshelf::Frequency-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[20,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Offset</NICK>
+<BLURB>Frequency-Offset.</BLURB>
+<DEFAULT>20</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-lshelf::Frequency-Pitch</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Pitch</NICK>
+<BLURB>Frequency-Pitch.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-lshelf::Gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain</NICK>
+<BLURB>Gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-lshelf::Resonance-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance-Offset</NICK>
+<BLURB>Resonance-Offset.</BLURB>
+<DEFAULT>0,001</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-lshelf::dBgain-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[6,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>dBgain-Offset</NICK>
+<BLURB>dBgain-Offset.</BLURB>
+<DEFAULT>6</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-hshelf::Frequency-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[20,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Offset</NICK>
+<BLURB>Frequency-Offset.</BLURB>
+<DEFAULT>20</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-hshelf::Frequency-Pitch</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Pitch</NICK>
+<BLURB>Frequency-Pitch.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-hshelf::Gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain</NICK>
+<BLURB>Gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-hshelf::Resonance-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance-Offset</NICK>
+<BLURB>Resonance-Offset.</BLURB>
+<DEFAULT>0,001</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf-hshelf::dBgain-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[6,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>dBgain-Offset</NICK>
+<BLURB>dBgain-Offset.</BLURB>
+<DEFAULT>6</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-satanMaximiser::Decay-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay-time</NICK>
+<BLURB>Decay-time.</BLURB>
+<DEFAULT>30</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-satanMaximiser::Knee-point</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Knee-point</NICK>
+<BLURB>Knee-point.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-syncpulse-fcpcga-oa::Frequenz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,64]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequenz</NICK>
+<BLURB>Frequenz.</BLURB>
+<DEFAULT>16</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-syncpulse-fcpcga-oa::Pulse-Width</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Pulse-Width</NICK>
+<BLURB>Pulse-Width.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-transient::Attack-speed</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attack-speed</NICK>
+<BLURB>Attack-speed.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-transient::Sustain-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sustain-time</NICK>
+<BLURB>Sustain-time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc3::Attack-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,400]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attack-time</NICK>
+<BLURB>Attack-time.</BLURB>
+<DEFAULT>101,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc3::Chain-balance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Chain-balance</NICK>
+<BLURB>Chain-balance.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc3::Knee-radius</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Knee-radius</NICK>
+<BLURB>Knee-radius.</BLURB>
+<DEFAULT>3,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc3::Makeup-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Makeup-gain</NICK>
+<BLURB>Makeup-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc3::Ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Ratio</NICK>
+<BLURB>Ratio.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc3::Release-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,800]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Release-time</NICK>
+<BLURB>Release-time.</BLURB>
+<DEFAULT>401</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc3::Threshold-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-30,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Threshold-level</NICK>
+<BLURB>Threshold-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-sigmoid::Post-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Post-Gain--dB-</NICK>
+<BLURB>Post-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-sigmoid::Pre-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Pre-Gain--dB-</NICK>
+<BLURB>Pre-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogueOsc::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0441,22005,9]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogueOsc::Instability</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Instability</NICK>
+<BLURB>Instability.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogueOsc::Warmth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Warmth</NICK>
+<BLURB>Warmth.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogueOsc::Waveform</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Waveform</NICK>
+<BLURB>Waveform.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-adsr::Abklingzeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Abklingzeit</NICK>
+<BLURB>Abklingzeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-adsr::Ausklingzeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Ausklingzeit</NICK>
+<BLURB>Ausklingzeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-adsr::Einschwingzeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Einschwingzeit</NICK>
+<BLURB>Einschwingzeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-adsr::Haltewert</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Haltewert</NICK>
+<BLURB>Haltewert.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-adsr::Trigger-Threshold</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Trigger-Threshold</NICK>
+<BLURB>Trigger-Threshold.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sifter::Sift-size</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,1000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sift-size</NICK>
+<BLURB>Sift-size.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-adsr-g+t::Abklingzeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Abklingzeit</NICK>
+<BLURB>Abklingzeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-adsr-g+t::Ausklingzeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Ausklingzeit</NICK>
+<BLURB>Ausklingzeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-adsr-g+t::Einschwingzeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Einschwingzeit</NICK>
+<BLURB>Einschwingzeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-adsr-g+t::Haltewert</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Haltewert</NICK>
+<BLURB>Haltewert.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ratio-nadc-oa::Denominator</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Denominator</NICK>
+<BLURB>Denominator.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ratio-ncda-oa::Numerator</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Numerator</NICK>
+<BLURB>Numerator.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ratio-ncdc-oc::Denominator</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Denominator</NICK>
+<BLURB>Denominator.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ratio-ncdc-oc::Numerator</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Numerator</NICK>
+<BLURB>Numerator.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ratio-ncdc-oc::Ratio-Output</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Ratio-Output</NICK>
+<BLURB>Ratio-Output.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-giantFlange::Delay-1-range</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-1-range</NICK>
+<BLURB>Delay-1-range.</BLURB>
+<DEFAULT>2,625</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-giantFlange::Delay-2-range</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-2-range</NICK>
+<BLURB>Delay-2-range.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-giantFlange::Double-delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Double-delay</NICK>
+<BLURB>Double-delay.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-giantFlange::Dry-Wet-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Wet-level</NICK>
+<BLURB>Dry-Wet-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-giantFlange::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-100,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-giantFlange::LFO-frequency-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO-frequency-1</NICK>
+<BLURB>LFO-frequency-1.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-giantFlange::LFO-frequency-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO-frequency-2</NICK>
+<BLURB>LFO-frequency-2.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-svf::Filter-Q</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filter-Q</NICK>
+<BLURB>Filter-Q.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-svf::Filter-freq</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,6000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filter-freq</NICK>
+<BLURB>Filter-freq.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-svf::Filter-resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filter-resonance</NICK>
+<BLURB>Filter-resonance.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-svf::Filter-type</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filter-type</NICK>
+<BLURB>Filter-type.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lp4pole-fcrcia-oa::Cutoff-Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,91875,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Cutoff-Frequency</NICK>
+<BLURB>Cutoff-Frequency.</BLURB>
+<DEFAULT>22050</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lp4pole-fcrcia-oa::Resonanz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonanz</NICK>
+<BLURB>Resonanz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-pitch::Dry-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Level--dB-</NICK>
+<BLURB>Dry-Level--dB-.</BLURB>
+<DEFAULT>-90</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-pitch::Rate-Shift----</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Rate-Shift----</NICK>
+<BLURB>Rate-Shift----.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-pitch::Semitone-Shift</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-12,12]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Semitone-Shift</NICK>
+<BLURB>Semitone-Shift.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-pitch::Wet-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wet-Level--dB-</NICK>
+<BLURB>Wet-Level--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-pitch::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,16027]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>16027</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-square-fc-oa::Frequenz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,91875,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequenz</NICK>
+<BLURB>Frequenz.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-bandpass-a-iir::Bandwidth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,19845]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Bandwidth</NICK>
+<BLURB>Bandwidth.</BLURB>
+<DEFAULT>295,832</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-bandpass-a-iir::Center-Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,19845]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Center-Frequency</NICK>
+<BLURB>Center-Frequency.</BLURB>
+<DEFAULT>36,1195</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-amp-mono::Gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain</NICK>
+<BLURB>Gain.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-amp-stereo::Gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain</NICK>
+<BLURB>Gain.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ringmod-2i1o::Modulation-depth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Modulation-depth</NICK>
+<BLURB>Modulation-depth.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ringmod-1i1o1l::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,1000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ringmod-1i1o1l::Modulation-depth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Modulation-depth</NICK>
+<BLURB>Modulation-depth.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ringmod-1i1o1l::Sawtooth-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sawtooth-level</NICK>
+<BLURB>Sawtooth-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ringmod-1i1o1l::Sine-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sine-level</NICK>
+<BLURB>Sine-level.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ringmod-1i1o1l::Square-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Square-level</NICK>
+<BLURB>Square-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ringmod-1i1o1l::Triangle-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Triangle-level</NICK>
+<BLURB>Triangle-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-n::Delay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-Time</NICK>
+<BLURB>Delay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-n::Max-Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Max-Delay</NICK>
+<BLURB>Max-Delay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-l::Delay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-Time</NICK>
+<BLURB>Delay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-l::Max-Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Max-Delay</NICK>
+<BLURB>Max-Delay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-c::Delay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-Time</NICK>
+<BLURB>Delay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-c::Max-Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Max-Delay</NICK>
+<BLURB>Max-Delay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fmod-famc-oa::Modulation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Modulation</NICK>
+<BLURB>Modulation.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fmod-fcma-oa::Frequenz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,91875,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequenz</NICK>
+<BLURB>Frequenz.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fmod-fcmc-oc::Frequenz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,91875,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequenz</NICK>
+<BLURB>Frequenz.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fmod-fcmc-oc::Modulation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Modulation</NICK>
+<BLURB>Modulation.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fmod-fcmc-oc::Modulierte-Frequenz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Modulierte-Frequenz</NICK>
+<BLURB>Modulierte-Frequenz.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gverb::Damping</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Damping</NICK>
+<BLURB>Damping.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gverb::Dry-signal-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-signal-level</NICK>
+<BLURB>Dry-signal-level.</BLURB>
+<DEFAULT>-70</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gverb::Early-reflection-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Early-reflection-level</NICK>
+<BLURB>Early-reflection-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gverb::Input-bandwidth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input-bandwidth</NICK>
+<BLURB>Input-bandwidth.</BLURB>
+<DEFAULT>0,75</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gverb::Reverb-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reverb-time</NICK>
+<BLURB>Reverb-time.</BLURB>
+<DEFAULT>7,575</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gverb::Roomsize</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,300]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Roomsize</NICK>
+<BLURB>Roomsize.</BLURB>
+<DEFAULT>75,75</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gverb::Tail-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tail-level</NICK>
+<BLURB>Tail-level.</BLURB>
+<DEFAULT>-17,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-se4::Amplitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-40,12]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Amplitude</NICK>
+<BLURB>Amplitude.</BLURB>
+<DEFAULT>-40</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-se4::Attack-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,5,400]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attack-time</NICK>
+<BLURB>Attack-time.</BLURB>
+<DEFAULT>101,125</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-se4::Attenuation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-24,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attenuation</NICK>
+<BLURB>Attenuation.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-se4::Gain-expansion</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,24]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Gain-expansion</NICK>
+<BLURB>Gain-expansion.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-se4::Knee-radius</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Knee-radius</NICK>
+<BLURB>Knee-radius.</BLURB>
+<DEFAULT>3,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-se4::RMS-peak</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>RMS-peak</NICK>
+<BLURB>RMS-peak.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-se4::Ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Ratio</NICK>
+<BLURB>Ratio.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-se4::Release-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,800]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Release-time</NICK>
+<BLURB>Release-time.</BLURB>
+<DEFAULT>401</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-se4::Threshold-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-30,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Threshold-level</NICK>
+<BLURB>Threshold-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Inner-damping</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Inner-damping</NICK>
+<BLURB>Inner-damping.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Inner-size-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Inner-size-1</NICK>
+<BLURB>Inner-size-1.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Inner-size-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Inner-size-2</NICK>
+<BLURB>Inner-size-2.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Inner-size-3</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Inner-size-3</NICK>
+<BLURB>Inner-size-3.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Inner-size-4</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Inner-size-4</NICK>
+<BLURB>Inner-size-4.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Inner-stiffness-1--</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Inner-stiffness-1--</NICK>
+<BLURB>Inner-stiffness-1--.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Inner-stiffness-1---1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Inner-stiffness-1---1</NICK>
+<BLURB>Inner-stiffness-1---1.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Inner-stiffness-2--</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Inner-stiffness-2--</NICK>
+<BLURB>Inner-stiffness-2--.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Inner-stiffness-2---1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Inner-stiffness-2---1</NICK>
+<BLURB>Inner-stiffness-2---1.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Inner-stiffness-3--</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Inner-stiffness-3--</NICK>
+<BLURB>Inner-stiffness-3--.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Inner-stiffness-3---1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Inner-stiffness-3---1</NICK>
+<BLURB>Inner-stiffness-3---1.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Inner-stiffness-4--</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Inner-stiffness-4--</NICK>
+<BLURB>Inner-stiffness-4--.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Inner-stiffness-4---1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Inner-stiffness-4---1</NICK>
+<BLURB>Inner-stiffness-4---1.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Mic-position</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mic-position</NICK>
+<BLURB>Mic-position.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Outer-damping</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Outer-damping</NICK>
+<BLURB>Outer-damping.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Outer-size-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Outer-size-1</NICK>
+<BLURB>Outer-size-1.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Outer-size-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Outer-size-2</NICK>
+<BLURB>Outer-size-2.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Outer-size-3</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Outer-size-3</NICK>
+<BLURB>Outer-size-3.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Outer-size-4</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Outer-size-4</NICK>
+<BLURB>Outer-size-4.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Outer-stiffness-1--</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Outer-stiffness-1--</NICK>
+<BLURB>Outer-stiffness-1--.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Outer-stiffness-1---1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Outer-stiffness-1---1</NICK>
+<BLURB>Outer-stiffness-1---1.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Outer-stiffness-2--</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Outer-stiffness-2--</NICK>
+<BLURB>Outer-stiffness-2--.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Outer-stiffness-2---1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Outer-stiffness-2---1</NICK>
+<BLURB>Outer-stiffness-2---1.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Outer-stiffness-3--</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Outer-stiffness-3--</NICK>
+<BLURB>Outer-stiffness-3--.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Outer-stiffness-3---1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Outer-stiffness-3---1</NICK>
+<BLURB>Outer-stiffness-3---1.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Outer-stiffness-4--</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Outer-stiffness-4--</NICK>
+<BLURB>Outer-stiffness-4--.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gong::Outer-stiffness-4---1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Outer-stiffness-4---1</NICK>
+<BLURB>Outer-stiffness-4---1.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-encode-bformat::Sound-Source-X-Coordinate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sound-Source-X-Coordinate</NICK>
+<BLURB>Sound-Source-X-Coordinate.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-encode-bformat::Sound-Source-Y-Coordinate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sound-Source-Y-Coordinate</NICK>
+<BLURB>Sound-Source-Y-Coordinate.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-encode-bformat::Sound-Source-Z-Coordinate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sound-Source-Z-Coordinate</NICK>
+<BLURB>Sound-Source-Z-Coordinate.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-encode-fmh::Sound-Source-X-Coordinate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sound-Source-X-Coordinate</NICK>
+<BLURB>Sound-Source-X-Coordinate.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-encode-fmh::Sound-Source-Y-Coordinate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sound-Source-Y-Coordinate</NICK>
+<BLURB>Sound-Source-Y-Coordinate.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-encode-fmh::Sound-Source-Z-Coordinate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sound-Source-Z-Coordinate</NICK>
+<BLURB>Sound-Source-Z-Coordinate.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-bf-rotate-z::Angle-of-Rotation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-180,180]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Angle-of-Rotation</NICK>
+<BLURB>Angle-of-Rotation.</BLURB>
+<DEFAULT>90</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fmh-rotate-z::Angle-of-Rotation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-180,180]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Angle-of-Rotation</NICK>
+<BLURB>Angle-of-Rotation.</BLURB>
+<DEFAULT>90</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO1-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO1-Attack</NICK>
+<BLURB>DCO1-Attack.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO1-Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO1-Decay</NICK>
+<BLURB>DCO1-Decay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO1-LFO-Frequency-Modulation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO1-LFO-Frequency-Modulation</NICK>
+<BLURB>DCO1-LFO-Frequency-Modulation.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO1-LFO-Pulse-Width-Modulation</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO1-LFO-Pulse-Width-Modulation</NICK>
+<BLURB>DCO1-LFO-Pulse-Width-Modulation.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO1-Octave</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO1-Octave</NICK>
+<BLURB>DCO1-Octave.</BLURB>
+<DEFAULT>0,001</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO1-Release</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO1-Release</NICK>
+<BLURB>DCO1-Release.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO1-Sustain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO1-Sustain</NICK>
+<BLURB>DCO1-Sustain.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO1-Waveform</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO1-Waveform</NICK>
+<BLURB>DCO1-Waveform.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO2-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO2-Attack</NICK>
+<BLURB>DCO2-Attack.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO2-Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO2-Decay</NICK>
+<BLURB>DCO2-Decay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO2-LFO-Frequency-Modulation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO2-LFO-Frequency-Modulation</NICK>
+<BLURB>DCO2-LFO-Frequency-Modulation.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO2-LFO-Pulse-Width-Modulation</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO2-LFO-Pulse-Width-Modulation</NICK>
+<BLURB>DCO2-LFO-Pulse-Width-Modulation.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO2-Octave</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO2-Octave</NICK>
+<BLURB>DCO2-Octave.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO2-Release</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO2-Release</NICK>
+<BLURB>DCO2-Release.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO2-Sustain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO2-Sustain</NICK>
+<BLURB>DCO2-Sustain.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::DCO2-Waveform</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO2-Waveform</NICK>
+<BLURB>DCO2-Waveform.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::Filter-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filter-Attack</NICK>
+<BLURB>Filter-Attack.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::Filter-Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filter-Decay</NICK>
+<BLURB>Filter-Decay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::Filter-Envelope-Modulation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filter-Envelope-Modulation</NICK>
+<BLURB>Filter-Envelope-Modulation.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::Filter-LFO-Modulation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filter-LFO-Modulation</NICK>
+<BLURB>Filter-LFO-Modulation.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::Filter-Release</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filter-Release</NICK>
+<BLURB>Filter-Release.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::Filter-Resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filter-Resonance</NICK>
+<BLURB>Filter-Resonance.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::Filter-Sustain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filter-Sustain</NICK>
+<BLURB>Filter-Sustain.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::Gate</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gate</NICK>
+<BLURB>Gate.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::LFO-Fadein</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO-Fadein</NICK>
+<BLURB>LFO-Fadein.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::LFO-Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO-Frequency</NICK>
+<BLURB>LFO-Frequency.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-analogue::Velocity</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Velocity</NICK>
+<BLURB>Velocity.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-canyon-delay::Left-to-Right-Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Left-to-Right-Feedback</NICK>
+<BLURB>Left-to-Right-Feedback.</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-canyon-delay::Left-to-Right-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,0,99]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Left-to-Right-Time</NICK>
+<BLURB>Left-to-Right-Time.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-canyon-delay::Low-Pass-Cutoff</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,5000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Low-Pass-Cutoff</NICK>
+<BLURB>Low-Pass-Cutoff.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-canyon-delay::Right-to-Left-Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Right-to-Left-Feedback</NICK>
+<BLURB>Right-to-Left-Feedback.</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-canyon-delay::Right-to-Left-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,0,99]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Right-to-Left-Time</NICK>
+<BLURB>Right-to-Left-Time.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-disintegrator::Multiplier</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Multiplier</NICK>
+<BLURB>Multiplier.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-disintegrator::Probability</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Probability</NICK>
+<BLURB>Probability.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sledgehammer::Carrier-influence</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Carrier-influence</NICK>
+<BLURB>Carrier-influence.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sledgehammer::Modulator-influence</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Modulator-influence</NICK>
+<BLURB>Modulator-influence.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sledgehammer::Rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1e-05,0,001]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Rate</NICK>
+<BLURB>Rate.</BLURB>
+<DEFAULT>0,000505</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-0-01s::Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0,01]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-0-01s::Dry-Wet-Balance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Wet-Balance</NICK>
+<BLURB>Dry-Wet-Balance.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-0-1s::Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>0,1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-0-1s::Dry-Wet-Balance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Wet-Balance</NICK>
+<BLURB>Dry-Wet-Balance.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-1s::Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-1s::Dry-Wet-Balance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Wet-Balance</NICK>
+<BLURB>Dry-Wet-Balance.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-5s::Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-5s::Dry-Wet-Balance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Wet-Balance</NICK>
+<BLURB>Dry-Wet-Balance.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-60s::Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,60]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-delay-60s::Dry-Wet-Balance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Wet-Balance</NICK>
+<BLURB>Dry-Wet-Balance.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-track-max-peak::Envelope-Forgetting-Factor</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Envelope-Forgetting-Factor</NICK>
+<BLURB>Envelope-Forgetting-Factor.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-track-max-peak::Output</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Output</NICK>
+<BLURB>Output.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-track-max-rms::Envelope-Forgetting-Factor</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Envelope-Forgetting-Factor</NICK>
+<BLURB>Envelope-Forgetting-Factor.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-track-max-rms::Output</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Output</NICK>
+<BLURB>Output.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-track-peak::Output</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Output</NICK>
+<BLURB>Output.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-track-peak::Smoothing-Factor</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Smoothing-Factor</NICK>
+<BLURB>Smoothing-Factor.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-track-rms::Output</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Output</NICK>
+<BLURB>Output.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-track-rms::Smoothing-Factor</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Smoothing-Factor</NICK>
+<BLURB>Smoothing-Factor.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fbdelay-0-01s::Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0,01]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fbdelay-0-01s::Dry-Wet-Balance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Wet-Balance</NICK>
+<BLURB>Dry-Wet-Balance.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fbdelay-0-01s::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fbdelay-0-1s::Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>0,1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fbdelay-0-1s::Dry-Wet-Balance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Wet-Balance</NICK>
+<BLURB>Dry-Wet-Balance.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fbdelay-0-1s::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fbdelay-1s::Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fbdelay-1s::Dry-Wet-Balance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Wet-Balance</NICK>
+<BLURB>Dry-Wet-Balance.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fbdelay-1s::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fbdelay-5s::Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fbdelay-5s::Dry-Wet-Balance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Wet-Balance</NICK>
+<BLURB>Dry-Wet-Balance.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fbdelay-5s::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fbdelay-60s::Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,60]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fbdelay-60s::Dry-Wet-Balance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Wet-Balance</NICK>
+<BLURB>Dry-Wet-Balance.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fbdelay-60s::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-freeverb3::Damping</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Damping</NICK>
+<BLURB>Damping.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-freeverb3::Dry-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Level</NICK>
+<BLURB>Dry-Level.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-freeverb3::Freeze-Mode</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Freeze-Mode</NICK>
+<BLURB>Freeze-Mode.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-freeverb3::Room-Size</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Room-Size</NICK>
+<BLURB>Room-Size.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-freeverb3::Wet-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wet-Level</NICK>
+<BLURB>Wet-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-freeverb3::Width</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Width</NICK>
+<BLURB>Width.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-grain-scatter::Density</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Density</NICK>
+<BLURB>Density.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-grain-scatter::Grain-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Grain-Attack</NICK>
+<BLURB>Grain-Attack.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-grain-scatter::Grain-Length</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Grain-Length</NICK>
+<BLURB>Grain-Length.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-grain-scatter::Scatter</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Scatter</NICK>
+<BLURB>Scatter.</BLURB>
+<DEFAULT>2,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hard-gate::Threshold</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Threshold</NICK>
+<BLURB>Threshold.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-identity-control::Input</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input</NICK>
+<BLURB>Input.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-identity-control::Output</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Output</NICK>
+<BLURB>Output.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lofi::Crackling</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Crackling</NICK>
+<BLURB>Crackling.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lofi::Opamp-Bandwidth-Limiting</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,10000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Opamp-Bandwidth-Limiting</NICK>
+<BLURB>Opamp-Bandwidth-Limiting.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lofi::Powersupply-Overloading</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Powersupply-Overloading</NICK>
+<BLURB>Powersupply-Overloading.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-logistic::Step-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,44,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Step-frequency</NICK>
+<BLURB>Step-frequency.</BLURB>
+<DEFAULT>22,05</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-logistic::param--r--parameter</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,9,3,9999]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param--r--parameter</NICK>
+<BLURB>param--r--parameter.</BLURB>
+<DEFAULT>3,9999</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-noise-source-white::Amplitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Amplitude</NICK>
+<BLURB>Amplitude.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-null-ci::Input</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input</NICK>
+<BLURB>Input.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-null-co::Output</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Output</NICK>
+<BLURB>Output.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::Attack-Hi</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attack-Hi</NICK>
+<BLURB>Attack-Hi.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::Attack-Lo</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attack-Lo</NICK>
+<BLURB>Attack-Lo.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::Brass</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Brass</NICK>
+<BLURB>Brass.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::Decay-Hi</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay-Hi</NICK>
+<BLURB>Decay-Hi.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::Decay-Lo</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay-Lo</NICK>
+<BLURB>Decay-Lo.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::Flute</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Flute</NICK>
+<BLURB>Flute.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::Gate</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gate</NICK>
+<BLURB>Gate.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::Reed</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reed</NICK>
+<BLURB>Reed.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::Release-Hi</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Release-Hi</NICK>
+<BLURB>Release-Hi.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::Release-Lo</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Release-Lo</NICK>
+<BLURB>Release-Lo.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::Sustain-Hi</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sustain-Hi</NICK>
+<BLURB>Sustain-Hi.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::Sustain-Lo</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sustain-Lo</NICK>
+<BLURB>Sustain-Lo.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::Velocity</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Velocity</NICK>
+<BLURB>Velocity.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::param-16th-Harmonic</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-16th-Harmonic</NICK>
+<BLURB>param-16th-Harmonic.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::param-2-2-3rd-Harmonic</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-2-2-3rd-Harmonic</NICK>
+<BLURB>param-2-2-3rd-Harmonic.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::param-2nd-Harmonic</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-2nd-Harmonic</NICK>
+<BLURB>param-2nd-Harmonic.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::param-4th-Harmonic</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-4th-Harmonic</NICK>
+<BLURB>param-4th-Harmonic.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::param-5-1-3rd-Harmonic</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-5-1-3rd-Harmonic</NICK>
+<BLURB>param-5-1-3rd-Harmonic.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-organ::param-8th-Harmonic</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-8th-Harmonic</NICK>
+<BLURB>param-8th-Harmonic.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-peak::Peak</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Peak</NICK>
+<BLURB>Peak.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO1-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO1-Attack</NICK>
+<BLURB>DCO1-Attack.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO1-Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO1-Decay</NICK>
+<BLURB>DCO1-Decay.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO1-Modulation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO1-Modulation</NICK>
+<BLURB>DCO1-Modulation.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO1-Octave</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO1-Octave</NICK>
+<BLURB>DCO1-Octave.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO1-Release</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO1-Release</NICK>
+<BLURB>DCO1-Release.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO1-Sustain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO1-Sustain</NICK>
+<BLURB>DCO1-Sustain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO1-Waveform</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO1-Waveform</NICK>
+<BLURB>DCO1-Waveform.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO2-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO2-Attack</NICK>
+<BLURB>DCO2-Attack.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO2-Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO2-Decay</NICK>
+<BLURB>DCO2-Decay.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO2-Modulation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO2-Modulation</NICK>
+<BLURB>DCO2-Modulation.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO2-Octave</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO2-Octave</NICK>
+<BLURB>DCO2-Octave.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO2-Release</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO2-Release</NICK>
+<BLURB>DCO2-Release.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO2-Sustain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO2-Sustain</NICK>
+<BLURB>DCO2-Sustain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO2-Waveform</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO2-Waveform</NICK>
+<BLURB>DCO2-Waveform.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO3-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO3-Attack</NICK>
+<BLURB>DCO3-Attack.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO3-Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO3-Decay</NICK>
+<BLURB>DCO3-Decay.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO3-Modulation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO3-Modulation</NICK>
+<BLURB>DCO3-Modulation.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO3-Octave</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO3-Octave</NICK>
+<BLURB>DCO3-Octave.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO3-Release</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO3-Release</NICK>
+<BLURB>DCO3-Release.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO3-Sustain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO3-Sustain</NICK>
+<BLURB>DCO3-Sustain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO3-Waveform</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO3-Waveform</NICK>
+<BLURB>DCO3-Waveform.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO4-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO4-Attack</NICK>
+<BLURB>DCO4-Attack.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO4-Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO4-Decay</NICK>
+<BLURB>DCO4-Decay.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO4-Modulation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO4-Modulation</NICK>
+<BLURB>DCO4-Modulation.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO4-Octave</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO4-Octave</NICK>
+<BLURB>DCO4-Octave.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO4-Release</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO4-Release</NICK>
+<BLURB>DCO4-Release.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO4-Sustain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO4-Sustain</NICK>
+<BLURB>DCO4-Sustain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO4-Waveform</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO4-Waveform</NICK>
+<BLURB>DCO4-Waveform.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO5-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO5-Attack</NICK>
+<BLURB>DCO5-Attack.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO5-Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO5-Decay</NICK>
+<BLURB>DCO5-Decay.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO5-Modulation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO5-Modulation</NICK>
+<BLURB>DCO5-Modulation.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO5-Octave</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO5-Octave</NICK>
+<BLURB>DCO5-Octave.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO5-Release</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO5-Release</NICK>
+<BLURB>DCO5-Release.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO5-Sustain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO5-Sustain</NICK>
+<BLURB>DCO5-Sustain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO5-Waveform</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO5-Waveform</NICK>
+<BLURB>DCO5-Waveform.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO6-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO6-Attack</NICK>
+<BLURB>DCO6-Attack.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO6-Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO6-Decay</NICK>
+<BLURB>DCO6-Decay.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO6-Modulation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO6-Modulation</NICK>
+<BLURB>DCO6-Modulation.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO6-Octave</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-2,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO6-Octave</NICK>
+<BLURB>DCO6-Octave.</BLURB>
+<DEFAULT>-2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO6-Release</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO6-Release</NICK>
+<BLURB>DCO6-Release.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO6-Sustain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO6-Sustain</NICK>
+<BLURB>DCO6-Sustain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::DCO6-Waveform</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>DCO6-Waveform</NICK>
+<BLURB>DCO6-Waveform.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::Gate</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gate</NICK>
+<BLURB>Gate.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phasemod::Velocity</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Velocity</NICK>
+<BLURB>Velocity.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-pink-interpolated-audio::Highest-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,44100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Highest-frequency</NICK>
+<BLURB>Highest-frequency.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-pink-sh::Sample-and-hold-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,882]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sample-and-hold-frequency</NICK>
+<BLURB>Sample-and-hold-frequency.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-compress-peak::Compression-Ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE><= 1</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Compression-Ratio</NICK>
+<BLURB>Compression-Ratio.</BLURB>
+<DEFAULT>-1,70141e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-compress-peak::Output-Envelope-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-Envelope-Attack</NICK>
+<BLURB>Output-Envelope-Attack.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-compress-peak::Output-Envelope-Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-Envelope-Decay</NICK>
+<BLURB>Output-Envelope-Decay.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-compress-peak::Threshold</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Threshold</NICK>
+<BLURB>Threshold.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-compress-rms::Compression-Ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE><= 1</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Compression-Ratio</NICK>
+<BLURB>Compression-Ratio.</BLURB>
+<DEFAULT>-1,70141e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-compress-rms::Output-Envelope-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-Envelope-Attack</NICK>
+<BLURB>Output-Envelope-Attack.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-compress-rms::Output-Envelope-Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-Envelope-Decay</NICK>
+<BLURB>Output-Envelope-Decay.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-compress-rms::Threshold</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Threshold</NICK>
+<BLURB>Threshold.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-expand-peak::Expansion-Ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE><= 1</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Expansion-Ratio</NICK>
+<BLURB>Expansion-Ratio.</BLURB>
+<DEFAULT>-1,70141e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-expand-peak::Output-Envelope-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-Envelope-Attack</NICK>
+<BLURB>Output-Envelope-Attack.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-expand-peak::Output-Envelope-Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-Envelope-Decay</NICK>
+<BLURB>Output-Envelope-Decay.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-expand-peak::Threshold</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Threshold</NICK>
+<BLURB>Threshold.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-expand-rms::Expansion-Ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE><= 1</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Expansion-Ratio</NICK>
+<BLURB>Expansion-Ratio.</BLURB>
+<DEFAULT>-1,70141e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-expand-rms::Output-Envelope-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-Envelope-Attack</NICK>
+<BLURB>Output-Envelope-Attack.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-expand-rms::Output-Envelope-Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-Envelope-Decay</NICK>
+<BLURB>Output-Envelope-Decay.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-expand-rms::Threshold</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Threshold</NICK>
+<BLURB>Threshold.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-limit-peak::Output-Envelope-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-Envelope-Attack</NICK>
+<BLURB>Output-Envelope-Attack.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-limit-peak::Output-Envelope-Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-Envelope-Decay</NICK>
+<BLURB>Output-Envelope-Decay.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-limit-peak::Threshold</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Threshold</NICK>
+<BLURB>Threshold.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-limit-rms::Output-Envelope-Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-Envelope-Attack</NICK>
+<BLURB>Output-Envelope-Attack.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-limit-rms::Output-Envelope-Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-Envelope-Decay</NICK>
+<BLURB>Output-Envelope-Decay.</BLURB>
+<DEFAULT>3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-limit-rms::Threshold</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Threshold</NICK>
+<BLURB>Threshold.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sine-faac::Amplitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Amplitude</NICK>
+<BLURB>Amplitude.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sine-fcaa::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sine-fcac::Amplitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Amplitude</NICK>
+<BLURB>Amplitude.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sine-fcac::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-syndrum::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-syndrum::Frequency-Ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-Ratio</NICK>
+<BLURB>Frequency-Ratio.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-syndrum::Resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance</NICK>
+<BLURB>Resonance.</BLURB>
+<DEFAULT>0,001</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-syndrum::Trigger</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Trigger</NICK>
+<BLURB>Trigger.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-syndrum::Velocity</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Velocity</NICK>
+<BLURB>Velocity.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf303::Cutoff</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Cutoff</NICK>
+<BLURB>Cutoff.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf303::Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay</NICK>
+<BLURB>Decay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf303::Envelope-Modulation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Envelope-Modulation</NICK>
+<BLURB>Envelope-Modulation.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf303::Resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance</NICK>
+<BLURB>Resonance.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vcf303::Trigger</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Trigger</NICK>
+<BLURB>Trigger.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-wshape-sine::Limiting-Amplitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Limiting-Amplitude</NICK>
+<BLURB>Limiting-Amplitude.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-chebstortion::Distortion</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,3]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Distortion</NICK>
+<BLURB>Distortion.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lcrDelay::C-delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2700]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>C-delay</NICK>
+<BLURB>C-delay.</BLURB>
+<DEFAULT>675</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lcrDelay::C-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,50]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>C-level</NICK>
+<BLURB>C-level.</BLURB>
+<DEFAULT>25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lcrDelay::Dry-Wet-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Wet-level</NICK>
+<BLURB>Dry-Wet-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lcrDelay::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-100,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lcrDelay::High-damp</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>High-damp</NICK>
+<BLURB>High-damp.</BLURB>
+<DEFAULT>50</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lcrDelay::L-delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2700]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>L-delay</NICK>
+<BLURB>L-delay.</BLURB>
+<DEFAULT>675</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lcrDelay::L-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,50]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>L-level</NICK>
+<BLURB>L-level.</BLURB>
+<DEFAULT>25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lcrDelay::Low-damp</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Low-damp</NICK>
+<BLURB>Low-damp.</BLURB>
+<DEFAULT>50</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lcrDelay::R-delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2700]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>R-delay</NICK>
+<BLURB>R-delay.</BLURB>
+<DEFAULT>675</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lcrDelay::R-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,50]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>R-level</NICK>
+<BLURB>R-level.</BLURB>
+<DEFAULT>25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lcrDelay::Spread</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,50]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Spread</NICK>
+<BLURB>Spread.</BLURB>
+<DEFAULT>25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-divider::Denominator</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Denominator</NICK>
+<BLURB>Denominator.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-random-fasc-oa::Wave-Smoothness</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wave-Smoothness</NICK>
+<BLURB>Wave-Smoothness.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-random-fcsa-oa::Frequenz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,91875,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequenz</NICK>
+<BLURB>Frequenz.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-random-fcsc-oa::Frequenz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,91875,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequenz</NICK>
+<BLURB>Frequenz.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-random-fcsc-oa::Wave-Smoothness</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wave-Smoothness</NICK>
+<BLURB>Wave-Smoothness.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lfoPhaser::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lfoPhaser::LFO-depth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO-depth</NICK>
+<BLURB>LFO-depth.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lfoPhaser::LFO-rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO-rate</NICK>
+<BLURB>LFO-rate.</BLURB>
+<DEFAULT>25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lfoPhaser::Spread</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Spread</NICK>
+<BLURB>Spread.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fourByFourPole::Feedback-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback-1</NICK>
+<BLURB>Feedback-1.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fourByFourPole::Feedback-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback-2</NICK>
+<BLURB>Feedback-2.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fourByFourPole::Feedback-3</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback-3</NICK>
+<BLURB>Feedback-3.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fourByFourPole::Feedback-4</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback-4</NICK>
+<BLURB>Feedback-4.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fourByFourPole::Frequency-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-1</NICK>
+<BLURB>Frequency-1.</BLURB>
+<DEFAULT>5000,75</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fourByFourPole::Frequency-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-2</NICK>
+<BLURB>Frequency-2.</BLURB>
+<DEFAULT>10000,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fourByFourPole::Frequency-3</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-3</NICK>
+<BLURB>Frequency-3.</BLURB>
+<DEFAULT>15000,2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fourByFourPole::Frequency-4</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-4</NICK>
+<BLURB>Frequency-4.</BLURB>
+<DEFAULT>20000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-autoPhaser::Attack-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attack-time</NICK>
+<BLURB>Attack-time.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-autoPhaser::Decay-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay-time</NICK>
+<BLURB>Decay-time.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-autoPhaser::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-autoPhaser::Modulation-depth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Modulation-depth</NICK>
+<BLURB>Modulation-depth.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-autoPhaser::Spread</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Spread</NICK>
+<BLURB>Spread.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-reflector::Dry-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Level--dB-</NICK>
+<BLURB>Dry-Level--dB-.</BLURB>
+<DEFAULT>-90</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-reflector::Fragment-Length--ms-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[20,1600]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Fragment-Length--ms-</NICK>
+<BLURB>Fragment-Length--ms-.</BLURB>
+<DEFAULT>415</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-reflector::Wet-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wet-Level--dB-</NICK>
+<BLURB>Wet-Level--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fastLookaheadLimiter::Attenuation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,70]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Attenuation</NICK>
+<BLURB>Attenuation.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fastLookaheadLimiter::Input-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input-gain</NICK>
+<BLURB>Input-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fastLookaheadLimiter::Limit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Limit</NICK>
+<BLURB>Limit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fastLookaheadLimiter::Release-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Release-time</NICK>
+<BLURB>Release-time.</BLURB>
+<DEFAULT>0,5075</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-fastLookaheadLimiter::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Match-Range</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Match-Range</NICK>
+<BLURB>Match-Range.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Mode</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Mode.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Quantise-Range-Maximum</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Quantise-Range-Maximum</NICK>
+<BLURB>Quantise-Range-Maximum.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Quantise-Range-Minimum</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Quantise-Range-Minimum</NICK>
+<BLURB>Quantise-Range-Minimum.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Steps</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Steps</NICK>
+<BLURB>Steps.</BLURB>
+<DEFAULT>20</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-0</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-0</NICK>
+<BLURB>Value-0.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-1</NICK>
+<BLURB>Value-1.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-10</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-10</NICK>
+<BLURB>Value-10.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-11</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-11</NICK>
+<BLURB>Value-11.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-12</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-12</NICK>
+<BLURB>Value-12.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-13</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-13</NICK>
+<BLURB>Value-13.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-14</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-14</NICK>
+<BLURB>Value-14.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-15</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-15</NICK>
+<BLURB>Value-15.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-16</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-16</NICK>
+<BLURB>Value-16.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-17</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-17</NICK>
+<BLURB>Value-17.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-18</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-18</NICK>
+<BLURB>Value-18.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-19</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-19</NICK>
+<BLURB>Value-19.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-2</NICK>
+<BLURB>Value-2.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-3</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-3</NICK>
+<BLURB>Value-3.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-4</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-4</NICK>
+<BLURB>Value-4.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-5</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-5</NICK>
+<BLURB>Value-5.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-6</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-6</NICK>
+<BLURB>Value-6.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-7</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-7</NICK>
+<BLURB>Value-7.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-8</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-8</NICK>
+<BLURB>Value-8.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-quantiser20::Value-9</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-9</NICK>
+<BLURB>Value-9.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vynil::Crackle</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Crackle</NICK>
+<BLURB>Crackle.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vynil::RPM</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[33,78]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>RPM</NICK>
+<BLURB>RPM.</BLURB>
+<DEFAULT>33</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vynil::Surface-warping</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Surface-warping</NICK>
+<BLURB>Surface-warping.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vynil::Wear</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wear</NICK>
+<BLURB>Wear.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vynil::Year</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1900,1990]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Year</NICK>
+<BLURB>Year.</BLURB>
+<DEFAULT>1990</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-const::Signal-amplitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Signal-amplitude</NICK>
+<BLURB>Signal-amplitude.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-product-iaic-oa::Second-Input</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Second-Input</NICK>
+<BLURB>Second-Input.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-product-icic-oc::First-Input</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>First-Input</NICK>
+<BLURB>First-Input.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-product-icic-oc::Product-Output</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Product-Output</NICK>
+<BLURB>Product-Output.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-product-icic-oc::Second-Input</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Second-Input</NICK>
+<BLURB>Second-Input.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-reverb::Allpass-Filters</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Allpass-Filters</NICK>
+<BLURB>Allpass-Filters.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-reverb::Bandpass-Filter</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Bandpass-Filter</NICK>
+<BLURB>Bandpass-Filter.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-reverb::Comb-Filters</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Comb-Filters</NICK>
+<BLURB>Comb-Filters.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-reverb::Decay--ms-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay--ms-</NICK>
+<BLURB>Decay--ms-.</BLURB>
+<DEFAULT>2500</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-reverb::Dry-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Level--dB-</NICK>
+<BLURB>Dry-Level--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-reverb::Enhanced-Stereo</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Enhanced-Stereo</NICK>
+<BLURB>Enhanced-Stereo.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-reverb::Reverb-Type</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,42]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reverb-Type</NICK>
+<BLURB>Reverb-Type.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-reverb::Wet-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wet-Level--dB-</NICK>
+<BLURB>Wet-Level--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Pulse-VCO::Exp-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Exp-FM-gain</NICK>
+<BLURB>Exp-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Pulse-VCO::LP-filter</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LP-filter</NICK>
+<BLURB>LP-filter.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Pulse-VCO::Lin-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Lin-FM-gain</NICK>
+<BLURB>Lin-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Pulse-VCO::Octave</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[-4,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Octave</NICK>
+<BLURB>Octave.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Pulse-VCO::Tune</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tune</NICK>
+<BLURB>Tune.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Saw-VCO::Exp-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Exp-FM-gain</NICK>
+<BLURB>Exp-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Saw-VCO::LP-filter</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LP-filter</NICK>
+<BLURB>LP-filter.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Saw-VCO::Lin-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Lin-FM-gain</NICK>
+<BLURB>Lin-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Saw-VCO::Octave</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[-4,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Octave</NICK>
+<BLURB>Octave.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Saw-VCO::Tune</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tune</NICK>
+<BLURB>Tune.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Rec-VCO::Exp-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Exp-FM-gain</NICK>
+<BLURB>Exp-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Rec-VCO::Form-mod</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Form-mod</NICK>
+<BLURB>Form-mod.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Rec-VCO::LP-filter</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LP-filter</NICK>
+<BLURB>LP-filter.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Rec-VCO::Lin-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Lin-FM-gain</NICK>
+<BLURB>Lin-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Rec-VCO::Octave</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[-4,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Octave</NICK>
+<BLURB>Octave.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Rec-VCO::Tune</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tune</NICK>
+<BLURB>Tune.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Rec-VCO::Waveform</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Waveform</NICK>
+<BLURB>Waveform.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-singlePara::Bandwidth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Bandwidth</NICK>
+<BLURB>Bandwidth.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-singlePara::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,17640]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-singlePara::Gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain</NICK>
+<BLURB>Gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gate::Attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,1000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attack</NICK>
+<BLURB>Attack.</BLURB>
+<DEFAULT>250,008</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gate::Decay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,4000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay</NICK>
+<BLURB>Decay.</BLURB>
+<DEFAULT>2001</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gate::HF-key-filter</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[220,5,21609]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>HF-key-filter</NICK>
+<BLURB>HF-key-filter.</BLURB>
+<DEFAULT>21609</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gate::Hold</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,2000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Hold</NICK>
+<BLURB>Hold.</BLURB>
+<DEFAULT>1500,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gate::LF-key-filter</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[30,87,4410]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LF-key-filter</NICK>
+<BLURB>LF-key-filter.</BLURB>
+<DEFAULT>30,87</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gate::Output-select</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-select</NICK>
+<BLURB>Output-select.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gate::Range</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Range</NICK>
+<BLURB>Range.</BLURB>
+<DEFAULT>-90</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gate::Threshold</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Threshold</NICK>
+<BLURB>Threshold.</BLURB>
+<DEFAULT>-70</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-st::Attack--ms-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,500]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attack--ms-</NICK>
+<BLURB>Attack--ms-.</BLURB>
+<DEFAULT>128</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-st::Envelope-Volume</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-60,20]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Envelope-Volume</NICK>
+<BLURB>Envelope-Volume.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-st::Envelope-Volume-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-60,20]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Envelope-Volume-1</NICK>
+<BLURB>Envelope-Volume-1.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-st::Function</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,14]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Function</NICK>
+<BLURB>Function.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-st::Gain-Adjustment</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-60,20]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Gain-Adjustment</NICK>
+<BLURB>Gain-Adjustment.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-st::Gain-Adjustment-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-60,20]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Gain-Adjustment-1</NICK>
+<BLURB>Gain-Adjustment-1.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-st::Makeup-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Makeup-Gain--dB-</NICK>
+<BLURB>Makeup-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-st::Offset-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Offset-Gain--dB-</NICK>
+<BLURB>Offset-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-st::Release--ms-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,1000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Release--ms-</NICK>
+<BLURB>Release--ms-.</BLURB>
+<DEFAULT>502</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-st::Stereo-Mode</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Stereo-Mode</NICK>
+<BLURB>Stereo-Mode.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Bandwidth-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,125,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Bandwidth-1</NICK>
+<BLURB>Bandwidth-1.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Bandwidth-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,125,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Bandwidth-2</NICK>
+<BLURB>Bandwidth-2.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Bandwidth-3</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,125,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Bandwidth-3</NICK>
+<BLURB>Bandwidth-3.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Bandwidth-4</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,125,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Bandwidth-4</NICK>
+<BLURB>Bandwidth-4.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Filter</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filter</NICK>
+<BLURB>Filter.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Frequency-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[20,2000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-1</NICK>
+<BLURB>Frequency-1.</BLURB>
+<DEFAULT>200</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Frequency-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[40,4000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-2</NICK>
+<BLURB>Frequency-2.</BLURB>
+<DEFAULT>400</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Frequency-3</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[100,10000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-3</NICK>
+<BLURB>Frequency-3.</BLURB>
+<DEFAULT>1000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Frequency-4</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[200,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-4</NICK>
+<BLURB>Frequency-4.</BLURB>
+<DEFAULT>2000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain</NICK>
+<BLURB>Gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Gain-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain-1</NICK>
+<BLURB>Gain-1.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Gain-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain-2</NICK>
+<BLURB>Gain-2.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Gain-3</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain-3</NICK>
+<BLURB>Gain-3.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Gain-4</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain-4</NICK>
+<BLURB>Gain-4.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Section-1</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Section-1</NICK>
+<BLURB>Section-1.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Section-2</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Section-2</NICK>
+<BLURB>Section-2.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Section-3</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Section-3</NICK>
+<BLURB>Section-3.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Parametric1::Section-4</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Section-4</NICK>
+<BLURB>Section-4.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sinCos::Base-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0441,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Base-frequency</NICK>
+<BLURB>Base-frequency.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sinCos::Pitch-offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Pitch-offset</NICK>
+<BLURB>Pitch-offset.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-matrixSpatialiser::Width</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[-512,512]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Width</NICK>
+<BLURB>Width.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-limiter::Limit-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-30,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Limit-Level--dB-</NICK>
+<BLURB>Limit-Level--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-limiter::Output-Volume--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-30,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-Volume--dB-</NICK>
+<BLURB>Output-Volume--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-limiter::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2500,1]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>2500,1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-bodeShifterCV::Base-shift</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Base-shift</NICK>
+<BLURB>Base-shift.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-bodeShifterCV::CV-Attenuation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>CV-Attenuation</NICK>
+<BLURB>CV-Attenuation.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-bodeShifterCV::Mix</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mix</NICK>
+<BLURB>Mix.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-bodeShifterCV::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Phaser1::Exp-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Exp-FM-gain</NICK>
+<BLURB>Exp-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Phaser1::Feedback-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback-gain</NICK>
+<BLURB>Feedback-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Phaser1::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-6,6]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Phaser1::Input-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-40,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input-gain</NICK>
+<BLURB>Input-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Phaser1::Lin-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Lin-FM-gain</NICK>
+<BLURB>Lin-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Phaser1::Output-mix</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-mix</NICK>
+<BLURB>Output-mix.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Phaser1::Sections</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sections</NICK>
+<BLURB>Sections.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Phaser1+LFO::Feedback-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback-gain</NICK>
+<BLURB>Feedback-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Phaser1+LFO::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-6,6]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Phaser1+LFO::Input-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-40,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input-gain</NICK>
+<BLURB>Input-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Phaser1+LFO::LFO-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO-frequency</NICK>
+<BLURB>LFO-frequency.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Phaser1+LFO::LFO-waveform</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO-waveform</NICK>
+<BLURB>LFO-waveform.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Phaser1+LFO::Modulation-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Modulation-gain</NICK>
+<BLURB>Modulation-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Phaser1+LFO::Output-mix</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-mix</NICK>
+<BLURB>Output-mix.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Phaser1+LFO::Sections</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sections</NICK>
+<BLURB>Sections.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-decimator::Bit-depth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Bit-depth</NICK>
+<BLURB>Bit-depth.</BLURB>
+<DEFAULT>24</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-decimator::Sample-rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[44,1,44100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sample-rate</NICK>
+<BLURB>Sample-rate.</BLURB>
+<DEFAULT>44100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-shaper::Waveshape</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-10,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Waveshape</NICK>
+<BLURB>Waveshape.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triangle-fasc-oa::Slope</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Slope</NICK>
+<BLURB>Slope.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triangle-fcsa-oa::Frequenz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,91875,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequenz</NICK>
+<BLURB>Frequenz.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triangle-fcsc-oa::Frequenz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,91875,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequenz</NICK>
+<BLURB>Frequenz.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triangle-fcsc-oa::Slope</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Slope</NICK>
+<BLURB>Slope.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-djFlanger::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-100,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-djFlanger::LFO-depth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO-depth</NICK>
+<BLURB>LFO-depth.</BLURB>
+<DEFAULT>4</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-djFlanger::LFO-period</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,32]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO-period</NICK>
+<BLURB>LFO-period.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-djFlanger::LFO-sync</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO-sync</NICK>
+<BLURB>LFO-sync.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-imp::Gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain</NICK>
+<BLURB>Gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-imp::High-latency-mode</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>High-latency-mode</NICK>
+<BLURB>High-latency-mode.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-imp::Impulse-ID</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,21]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Impulse-ID</NICK>
+<BLURB>Impulse-ID.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-imp::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-m::Attack--ms-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,500]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attack--ms-</NICK>
+<BLURB>Attack--ms-.</BLURB>
+<DEFAULT>128</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-m::Envelope-Volume--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-60,20]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Envelope-Volume--dB-</NICK>
+<BLURB>Envelope-Volume--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-m::Function</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,14]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Function</NICK>
+<BLURB>Function.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-m::Gain-Adjustment--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-60,20]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Gain-Adjustment--dB-</NICK>
+<BLURB>Gain-Adjustment--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-m::Makeup-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Makeup-Gain--dB-</NICK>
+<BLURB>Makeup-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-m::Offset-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Offset-Gain--dB-</NICK>
+<BLURB>Offset-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-dynamics-m::Release--ms-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,1000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Release--ms-</NICK>
+<BLURB>Release--ms-.</BLURB>
+<DEFAULT>502</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-xfade::Crossfade</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Crossfade</NICK>
+<BLURB>Crossfade.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-xfade4::Crossfade</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Crossfade</NICK>
+<BLURB>Crossfade.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-tremolo::Depth----</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Depth----</NICK>
+<BLURB>Depth----.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-tremolo::Frequency--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency--Hz-</NICK>
+<BLURB>Frequency--Hz-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-tremolo::Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain--dB-</NICK>
+<BLURB>Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-pitchScale::Pitch-co-efficient</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Pitch-co-efficient</NICK>
+<BLURB>Pitch-co-efficient.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-pitchScale::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-pitchScaleHQ::Pitch-co-efficient</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Pitch-co-efficient</NICK>
+<BLURB>Pitch-co-efficient.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-pitchScaleHQ::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-valveRect::Distortion</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Distortion</NICK>
+<BLURB>Distortion.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-valveRect::Sag-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sag-level</NICK>
+<BLURB>Sag-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-pinknoise::Fractal-Dimension</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Fractal-Dimension</NICK>
+<BLURB>Fractal-Dimension.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-pinknoise::Noise-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Noise-Level--dB-</NICK>
+<BLURB>Noise-Level--dB-.</BLURB>
+<DEFAULT>-90</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-pinknoise::Signal-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Signal-Level--dB-</NICK>
+<BLURB>Signal-Level--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-interpolator::Control-Input</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Control-Input</NICK>
+<BLURB>Control-Input.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Band-1-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-1-gain</NICK>
+<BLURB>Band-1-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Band-2-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-2-gain</NICK>
+<BLURB>Band-2-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Band-3-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-3-gain</NICK>
+<BLURB>Band-3-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Delay1-feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay1-feedback</NICK>
+<BLURB>Delay1-feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Delay1-length</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay1-length</NICK>
+<BLURB>Delay1-length.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Delay1-wetness</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay1-wetness</NICK>
+<BLURB>Delay1-wetness.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Delay2-feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay2-feedback</NICK>
+<BLURB>Delay2-feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Delay2-length</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay2-length</NICK>
+<BLURB>Delay2-length.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Delay2-wetness</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay2-wetness</NICK>
+<BLURB>Delay2-wetness.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Delay3-feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay3-feedback</NICK>
+<BLURB>Delay3-feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Delay3-length</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay3-length</NICK>
+<BLURB>Delay3-length.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Delay3-wetness</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay3-wetness</NICK>
+<BLURB>Delay3-wetness.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Dist1-drive</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,3]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dist1-drive</NICK>
+<BLURB>Dist1-drive.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Dist2-drive</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,3]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dist2-drive</NICK>
+<BLURB>Dist2-drive.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Dist3-drive</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,3]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dist3-drive</NICK>
+<BLURB>Dist3-drive.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt1-LFO1-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-500,500]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt1-LFO1-level</NICK>
+<BLURB>Filt1-LFO1-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt1-LFO2-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-500,500]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt1-LFO2-level</NICK>
+<BLURB>Filt1-LFO2-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt1-freq</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,8000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt1-freq</NICK>
+<BLURB>Filt1-freq.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt1-q</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt1-q</NICK>
+<BLURB>Filt1-q.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt1-resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt1-resonance</NICK>
+<BLURB>Filt1-resonance.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt1-type</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt1-type</NICK>
+<BLURB>Filt1-type.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt2-LFO1-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-500,500]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt2-LFO1-level</NICK>
+<BLURB>Filt2-LFO1-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt2-LFO2-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-500,500]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt2-LFO2-level</NICK>
+<BLURB>Filt2-LFO2-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt2-freq</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,8000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt2-freq</NICK>
+<BLURB>Filt2-freq.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt2-q</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt2-q</NICK>
+<BLURB>Filt2-q.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt2-resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt2-resonance</NICK>
+<BLURB>Filt2-resonance.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt2-type</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt2-type</NICK>
+<BLURB>Filt2-type.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt3-LFO1-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-500,500]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt3-LFO1-level</NICK>
+<BLURB>Filt3-LFO1-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt3-LFO2-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-500,500]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt3-LFO2-level</NICK>
+<BLURB>Filt3-LFO2-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt3-freq</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,8000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt3-freq</NICK>
+<BLURB>Filt3-freq.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt3-q</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt3-q</NICK>
+<BLURB>Filt3-q.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt3-resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt3-resonance</NICK>
+<BLURB>Filt3-resonance.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Filt3-type</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Filt3-type</NICK>
+<BLURB>Filt3-type.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Input-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input-gain</NICK>
+<BLURB>Input-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::LFO1-freq</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO1-freq</NICK>
+<BLURB>LFO1-freq.</BLURB>
+<DEFAULT>250</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::LFO1-wave</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO1-wave</NICK>
+<BLURB>LFO1-wave.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::LFO2-freq</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO2-freq</NICK>
+<BLURB>LFO2-freq.</BLURB>
+<DEFAULT>250</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::LFO2-wave</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO2-wave</NICK>
+<BLURB>LFO2-wave.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Osc1-freq</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Osc1-freq</NICK>
+<BLURB>Osc1-freq.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Osc1-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Osc1-gain</NICK>
+<BLURB>Osc1-gain.</BLURB>
+<DEFAULT>-70</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Osc1-wave</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Osc1-wave</NICK>
+<BLURB>Osc1-wave.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Osc2-freq</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Osc2-freq</NICK>
+<BLURB>Osc2-freq.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Osc2-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Osc2-gain</NICK>
+<BLURB>Osc2-gain.</BLURB>
+<DEFAULT>-70</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Osc2-wave</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Osc2-wave</NICK>
+<BLURB>Osc2-wave.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::RM1-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>RM1-gain</NICK>
+<BLURB>RM1-gain.</BLURB>
+<DEFAULT>-70</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::RM2-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>RM2-gain</NICK>
+<BLURB>RM2-gain.</BLURB>
+<DEFAULT>-70</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::RM3-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>RM3-gain</NICK>
+<BLURB>RM3-gain.</BLURB>
+<DEFAULT>-70</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Ringmod-1-depth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Ringmod-1-depth</NICK>
+<BLURB>Ringmod-1-depth.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Ringmod-2-depth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Ringmod-2-depth</NICK>
+<BLURB>Ringmod-2-depth.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Ringmod-3-depth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Ringmod-3-depth</NICK>
+<BLURB>Ringmod-3-depth.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Xover-lower-freq</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[50,6000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Xover-lower-freq</NICK>
+<BLURB>Xover-lower-freq.</BLURB>
+<DEFAULT>1537,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-hermesFilter::Xover-upper-freq</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1000,10000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Xover-upper-freq</NICK>
+<BLURB>Xover-upper-freq.</BLURB>
+<DEFAULT>7750</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-impulse-fc::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-bodeShifter::Frequency-shift</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency-shift</NICK>
+<BLURB>Frequency-shift.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-bodeShifter::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-harmonicGen::Fundamental-magnitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Fundamental-magnitude</NICK>
+<BLURB>Fundamental-magnitude.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-harmonicGen::param-10th-harmonic-magnitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-10th-harmonic-magnitude</NICK>
+<BLURB>param-10th-harmonic-magnitude.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-harmonicGen::param-2nd-harmonic-magnitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-2nd-harmonic-magnitude</NICK>
+<BLURB>param-2nd-harmonic-magnitude.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-harmonicGen::param-3rd-harmonic-magnitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-3rd-harmonic-magnitude</NICK>
+<BLURB>param-3rd-harmonic-magnitude.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-harmonicGen::param-4th-harmonic-magnitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-4th-harmonic-magnitude</NICK>
+<BLURB>param-4th-harmonic-magnitude.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-harmonicGen::param-5th-harmonic-magnitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-5th-harmonic-magnitude</NICK>
+<BLURB>param-5th-harmonic-magnitude.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-harmonicGen::param-6th-harmonic-magnitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-6th-harmonic-magnitude</NICK>
+<BLURB>param-6th-harmonic-magnitude.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-harmonicGen::param-7th-harmonic-magnitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-7th-harmonic-magnitude</NICK>
+<BLURB>param-7th-harmonic-magnitude.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-harmonicGen::param-8th-harmonic-magnitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-8th-harmonic-magnitude</NICK>
+<BLURB>param-8th-harmonic-magnitude.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-harmonicGen::param-9th-harmonic-magnitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-9th-harmonic-magnitude</NICK>
+<BLURB>param-9th-harmonic-magnitude.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-pulse-fapc-oa::Pulse-Width</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Pulse-Width</NICK>
+<BLURB>Pulse-Width.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-pulse-fcpa-oa::Frequenz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,91875,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequenz</NICK>
+<BLURB>Frequenz.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-pulse-fcpc-oa::Frequenz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,91875,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequenz</NICK>
+<BLURB>Frequenz.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-pulse-fcpc-oa::Pulse-Width</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Pulse-Width</NICK>
+<BLURB>Pulse-Width.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lowpass-iir::Cutoff-Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,19845]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Cutoff-Frequency</NICK>
+<BLURB>Cutoff-Frequency.</BLURB>
+<DEFAULT>2422,97</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-lowpass-iir::Stages-2-poles-per-stage-</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Stages-2-poles-per-stage-</NICK>
+<BLURB>Stages-2-poles-per-stage-.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-rotspeak::Horn-Frequency--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Horn-Frequency--Hz-</NICK>
+<BLURB>Horn-Frequency--Hz-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-rotspeak::Mic-Distance----</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mic-Distance----</NICK>
+<BLURB>Mic-Distance----.</BLURB>
+<DEFAULT>25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-rotspeak::Rotor-Frequency--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Rotor-Frequency--Hz-</NICK>
+<BLURB>Rotor-Frequency--Hz-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-rotspeak::Rotor-Horn-Mix</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Rotor-Horn-Mix</NICK>
+<BLURB>Rotor-Horn-Mix.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-rotspeak::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,9200]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>9200</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-vibrato::Depth----</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Depth----</NICK>
+<BLURB>Depth----.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-vibrato::Dry-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Level--dB-</NICK>
+<BLURB>Dry-Level--dB-.</BLURB>
+<DEFAULT>-90</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-vibrato::Frequency--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency--Hz-</NICK>
+<BLURB>Frequency--Hz-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-vibrato::Wet-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wet-Level--dB-</NICK>
+<BLURB>Wet-Level--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-vibrato::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,6300]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>6300</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-stepMuxer::Crossfade-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Crossfade-time</NICK>
+<BLURB>Crossfade-time.</BLURB>
+<DEFAULT>50</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-flanger::Delay-base</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,25]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-base</NICK>
+<BLURB>Delay-base.</BLURB>
+<DEFAULT>6,325</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-flanger::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-flanger::LFO-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,05,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LFO-frequency</NICK>
+<BLURB>LFO-frequency.</BLURB>
+<DEFAULT>0,33437</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-flanger::Max-slowdown</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Max-slowdown</NICK>
+<BLURB>Max-slowdown.</BLURB>
+<DEFAULT>2,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-amp::Amps-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,70]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Amps-gain</NICK>
+<BLURB>Amps-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dahdsr-g+t-control::Abklingzeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Abklingzeit</NICK>
+<BLURB>Abklingzeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dahdsr-g+t-control::Ausklingzeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Ausklingzeit</NICK>
+<BLURB>Ausklingzeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dahdsr-g+t-control::Einschwingzeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Einschwingzeit</NICK>
+<BLURB>Einschwingzeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dahdsr-g+t-control::Haltewert</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Haltewert</NICK>
+<BLURB>Haltewert.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dahdsr-g+t-control::Haltezeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Haltezeit</NICK>
+<BLURB>Haltezeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dahdsr-g+t-control::Verz--gerungszeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Verz--gerungszeit</NICK>
+<BLURB>Verz--gerungszeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dahdsr-cg+t-control::Abklingzeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Abklingzeit</NICK>
+<BLURB>Abklingzeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dahdsr-cg+t-control::Ausklingzeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Ausklingzeit</NICK>
+<BLURB>Ausklingzeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dahdsr-cg+t-control::Ausl--ser</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Ausl--ser</NICK>
+<BLURB>Ausl--ser.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dahdsr-cg+t-control::Einschwingzeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Einschwingzeit</NICK>
+<BLURB>Einschwingzeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dahdsr-cg+t-control::Gatter</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gatter</NICK>
+<BLURB>Gatter.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dahdsr-cg+t-control::Haltewert</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Haltewert</NICK>
+<BLURB>Haltewert.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dahdsr-cg+t-control::Haltezeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Haltezeit</NICK>
+<BLURB>Haltezeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dahdsr-cg+t-control::Verz--gerungszeit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Verz--gerungszeit</NICK>
+<BLURB>Verz--gerungszeit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Saw-VCO::Exp-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Exp-FM-gain</NICK>
+<BLURB>Exp-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Saw-VCO::LP-filter</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LP-filter</NICK>
+<BLURB>LP-filter.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Saw-VCO::Lin-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Lin-FM-gain</NICK>
+<BLURB>Lin-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Saw-VCO::Octave</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[-4,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Octave</NICK>
+<BLURB>Octave.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Saw-VCO::Tune</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tune</NICK>
+<BLURB>Tune.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Rect-VCO::Exp-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Exp-FM-gain</NICK>
+<BLURB>Exp-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Rect-VCO::LP-filter</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LP-filter</NICK>
+<BLURB>LP-filter.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Rect-VCO::Lin-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Lin-FM-gain</NICK>
+<BLURB>Lin-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Rect-VCO::Octave</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[-4,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Octave</NICK>
+<BLURB>Octave.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Rect-VCO::Tune</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tune</NICK>
+<BLURB>Tune.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Rect-VCO::WMod-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>WMod-gain</NICK>
+<BLURB>WMod-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Rect-VCO::Waveform</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Waveform</NICK>
+<BLURB>Waveform.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Tri-VCO::Exp-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Exp-FM-gain</NICK>
+<BLURB>Exp-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Tri-VCO::LP-filter</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LP-filter</NICK>
+<BLURB>LP-filter.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Tri-VCO::Lin-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Lin-FM-gain</NICK>
+<BLURB>Lin-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Tri-VCO::Octave</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[-4,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Octave</NICK>
+<BLURB>Octave.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Tri-VCO::Tune</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tune</NICK>
+<BLURB>Tune.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Tri-VCO::WMod-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>WMod-gain</NICK>
+<BLURB>WMod-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sync-Tri-VCO::Waveform</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Waveform</NICK>
+<BLURB>Waveform.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-bwxover-iir::Cutoff-Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,19845]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Cutoff-Frequency</NICK>
+<BLURB>Cutoff-Frequency.</BLURB>
+<DEFAULT>36,1195</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-bwxover-iir::Resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,1,41]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance</NICK>
+<BLURB>Resonance.</BLURB>
+<DEFAULT>0,755</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-buttlow-iir::Cutoff-Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,19845]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Cutoff-Frequency</NICK>
+<BLURB>Cutoff-Frequency.</BLURB>
+<DEFAULT>36,1195</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-buttlow-iir::Resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,1,41]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance</NICK>
+<BLURB>Resonance.</BLURB>
+<DEFAULT>0,755</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-butthigh-iir::Cutoff-Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,19845]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Cutoff-Frequency</NICK>
+<BLURB>Cutoff-Frequency.</BLURB>
+<DEFAULT>36,1195</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-butthigh-iir::Resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,1,41]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance</NICK>
+<BLURB>Resonance.</BLURB>
+<DEFAULT>0,755</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvchpf-1::Exp-FM-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Exp-FM-gain</NICK>
+<BLURB>Exp-FM-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvchpf-1::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-6,6]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvchpf-1::Input-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-60,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input-gain</NICK>
+<BLURB>Input-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Mvchpf-1::Output-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-15,15]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Output-gain</NICK>
+<BLURB>Output-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tracker-gaacdcia-oa::Attack-Rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,91875,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attack-Rate</NICK>
+<BLURB>Attack-Rate.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tracker-gaacdcia-oa::Attack-Rate-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,91875,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attack-Rate-1</NICK>
+<BLURB>Attack-Rate-1.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tracker-gaacdcia-oa::Decay-Rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,91875,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay-Rate</NICK>
+<BLURB>Decay-Rate.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tracker-gaacdcia-oa::Decay-Rate-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,91875,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay-Rate-1</NICK>
+<BLURB>Decay-Rate-1.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-doubler::Dry-Left-Position</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Left-Position</NICK>
+<BLURB>Dry-Left-Position.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-doubler::Dry-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Level--dB-</NICK>
+<BLURB>Dry-Level--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-doubler::Dry-Right-Position</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Right-Position</NICK>
+<BLURB>Dry-Right-Position.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-doubler::Pitch-Tracking</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Pitch-Tracking</NICK>
+<BLURB>Pitch-Tracking.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-doubler::Time-Tracking</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Time-Tracking</NICK>
+<BLURB>Time-Tracking.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-doubler::Wet-Left-Position</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wet-Left-Position</NICK>
+<BLURB>Wet-Left-Position.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-doubler::Wet-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wet-Level--dB-</NICK>
+<BLURB>Wet-Level--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-doubler::Wet-Right-Position</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wet-Right-Position</NICK>
+<BLURB>Wet-Right-Position.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-amp-gcia-oa::Verst--rkung</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-96,96]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Verst--rkung</NICK>
+<BLURB>Verst--rkung.</BLURB>
+<DEFAULT>-96</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Closed-Gate-Value</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Closed-Gate-Value</NICK>
+<BLURB>Closed-Gate-Value.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Loop-Steps</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,16]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Loop-Steps</NICK>
+<BLURB>Loop-Steps.</BLURB>
+<DEFAULT>16</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Reset-to-Value-on-Gate-Close-</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reset-to-Value-on-Gate-Close-</NICK>
+<BLURB>Reset-to-Value-on-Gate-Close-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-0</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-0</NICK>
+<BLURB>Value-Step-0.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-1</NICK>
+<BLURB>Value-Step-1.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-10</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-10</NICK>
+<BLURB>Value-Step-10.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-11</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-11</NICK>
+<BLURB>Value-Step-11.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-12</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-12</NICK>
+<BLURB>Value-Step-12.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-13</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-13</NICK>
+<BLURB>Value-Step-13.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-14</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-14</NICK>
+<BLURB>Value-Step-14.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-15</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-15</NICK>
+<BLURB>Value-Step-15.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-2</NICK>
+<BLURB>Value-Step-2.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-3</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-3</NICK>
+<BLURB>Value-Step-3.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-4</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-4</NICK>
+<BLURB>Value-Step-4.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-5</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-5</NICK>
+<BLURB>Value-Step-5.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-6</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-6</NICK>
+<BLURB>Value-Step-6.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-7</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-7</NICK>
+<BLURB>Value-Step-7.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-8</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-8</NICK>
+<BLURB>Value-Step-8.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer16::Value-Step-9</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-9</NICK>
+<BLURB>Value-Step-9.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc2::Attack-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,400]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attack-time</NICK>
+<BLURB>Attack-time.</BLURB>
+<DEFAULT>101,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc2::Knee-radius</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Knee-radius</NICK>
+<BLURB>Knee-radius.</BLURB>
+<DEFAULT>3,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc2::Makeup-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Makeup-gain</NICK>
+<BLURB>Makeup-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc2::Ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Ratio</NICK>
+<BLURB>Ratio.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc2::Release-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,800]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Release-time</NICK>
+<BLURB>Release-time.</BLURB>
+<DEFAULT>401</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc2::Threshold-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-30,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Threshold-level</NICK>
+<BLURB>Threshold-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dysonCompress::Compression-ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Compression-ratio</NICK>
+<BLURB>Compression-ratio.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dysonCompress::Fast-compression-ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Fast-compression-ratio</NICK>
+<BLURB>Fast-compression-ratio.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dysonCompress::Peak-limit</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-30,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Peak-limit</NICK>
+<BLURB>Peak-limit.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-dysonCompress::Release-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Release-time</NICK>
+<BLURB>Release-time.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-decay::Decay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay-Time</NICK>
+<BLURB>Decay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-alias::Aliasing-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Aliasing-level</NICK>
+<BLURB>Aliasing-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::Cycle-Length-Out</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Cycle-Length-Out</NICK>
+<BLURB>Cycle-Length-Out.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::Dry-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Level</NICK>
+<BLURB>Dry-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::Free-Sample-Mem</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Free-Sample-Mem</NICK>
+<BLURB>Free-Sample-Mem.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::Loop-Length-Out</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Loop-Length-Out</NICK>
+<BLURB>Loop-Length-Out.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::Loop-Position-Out</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Loop-Position-Out</NICK>
+<BLURB>Loop-Position-Out.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::Multi-Control</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,127]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Multi-Control</NICK>
+<BLURB>Multi-Control.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::MultiCtrl-10s</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,12]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>MultiCtrl-10s</NICK>
+<BLURB>MultiCtrl-10s.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::QuantizeMode</NAME>
+<TYPE>gint</TYPE>
+<RANGE><= G_MININT</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>QuantizeMode</NICK>
+<BLURB>QuantizeMode.</BLURB>
+<DEFAULT>-2147483648</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::Rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-4,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Rate</NICK>
+<BLURB>Rate.</BLURB>
+<DEFAULT>-4</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::RedoTapMode</NAME>
+<TYPE>gint</TYPE>
+<RANGE><= G_MININT</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>RedoTapMode</NICK>
+<BLURB>RedoTapMode.</BLURB>
+<DEFAULT>-2147483648</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::RoundMode</NAME>
+<TYPE>gint</TYPE>
+<RANGE><= G_MININT</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>RoundMode</NICK>
+<BLURB>RoundMode.</BLURB>
+<DEFAULT>-2147483648</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::Scratch-Destination</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Scratch-Destination</NICK>
+<BLURB>Scratch-Destination.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::State-Output</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>State-Output</NICK>
+<BLURB>State-Output.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::Tap-Delay-Trigger</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tap-Delay-Trigger</NICK>
+<BLURB>Tap-Delay-Trigger.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::Total-Sample-Mem</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Total-Sample-Mem</NICK>
+<BLURB>Total-Sample-Mem.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::Trigger-Threshold</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Trigger-Threshold</NICK>
+<BLURB>Trigger-Threshold.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SooperLooper::Wet-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wet-Level</NICK>
+<BLURB>Wet-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vlevel-mono::Current-Multiplier</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,20]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Current-Multiplier</NICK>
+<BLURB>Current-Multiplier.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vlevel-mono::Look-ahead</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Look-ahead</NICK>
+<BLURB>Look-ahead.</BLURB>
+<DEFAULT>2,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vlevel-mono::Maximum-Multiplier</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Maximum-Multiplier</NICK>
+<BLURB>Maximum-Multiplier.</BLURB>
+<DEFAULT>10</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vlevel-mono::Strength</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Strength</NICK>
+<BLURB>Strength.</BLURB>
+<DEFAULT>0,75</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vlevel-mono::Undo</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Undo</NICK>
+<BLURB>Undo.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vlevel-mono::Use-Maximum-Multiplier</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Use-Maximum-Multiplier</NICK>
+<BLURB>Use-Maximum-Multiplier.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vlevel-stereo::Current-Multiplier</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,20]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Current-Multiplier</NICK>
+<BLURB>Current-Multiplier.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vlevel-stereo::Look-ahead</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Look-ahead</NICK>
+<BLURB>Look-ahead.</BLURB>
+<DEFAULT>2,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vlevel-stereo::Maximum-Multiplier</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Maximum-Multiplier</NICK>
+<BLURB>Maximum-Multiplier.</BLURB>
+<DEFAULT>10</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vlevel-stereo::Strength</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Strength</NICK>
+<BLURB>Strength.</BLURB>
+<DEFAULT>0,75</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vlevel-stereo::Undo</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Undo</NICK>
+<BLURB>Undo.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vlevel-stereo::Use-Maximum-Multiplier</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Use-Maximum-Multiplier</NICK>
+<BLURB>Use-Maximum-Multiplier.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-artificialLatency::Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay.</BLURB>
+<DEFAULT>2500</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-artificialLatency::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triplePara::Band-1-bandwidth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-1-bandwidth</NICK>
+<BLURB>Band-1-bandwidth.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triplePara::Band-1-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,21609]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-1-frequency</NICK>
+<BLURB>Band-1-frequency.</BLURB>
+<DEFAULT>36,8967</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triplePara::Band-1-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-1-gain</NICK>
+<BLURB>Band-1-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triplePara::Band-2-bandwidth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-2-bandwidth</NICK>
+<BLURB>Band-2-bandwidth.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triplePara::Band-2-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,21609]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-2-frequency</NICK>
+<BLURB>Band-2-frequency.</BLURB>
+<DEFAULT>308,7</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triplePara::Band-2-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-2-gain</NICK>
+<BLURB>Band-2-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triplePara::Band-3-bandwidth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-3-bandwidth</NICK>
+<BLURB>Band-3-bandwidth.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triplePara::Band-3-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,21609]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-3-frequency</NICK>
+<BLURB>Band-3-frequency.</BLURB>
+<DEFAULT>2582,77</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triplePara::Band-3-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-3-gain</NICK>
+<BLURB>Band-3-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triplePara::High-shelving-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,21609]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>High-shelving-frequency</NICK>
+<BLURB>High-shelving-frequency.</BLURB>
+<DEFAULT>21609</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triplePara::High-shelving-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>High-shelving-gain</NICK>
+<BLURB>High-shelving-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triplePara::High-shelving-slope</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>High-shelving-slope</NICK>
+<BLURB>High-shelving-slope.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triplePara::Low-shelving-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,21609]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Low-shelving-frequency</NICK>
+<BLURB>Low-shelving-frequency.</BLURB>
+<DEFAULT>4,41</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triplePara::Low-shelving-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Low-shelving-gain</NICK>
+<BLURB>Low-shelving-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-triplePara::Low-shelving-slope</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Low-shelving-slope</NICK>
+<BLURB>Low-shelving-slope.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-revdelay::Crossfade-samples</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Crossfade-samples</NICK>
+<BLURB>Crossfade-samples.</BLURB>
+<DEFAULT>1250</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-revdelay::Delay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-Time</NICK>
+<BLURB>Delay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-revdelay::Dry-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Level</NICK>
+<BLURB>Dry-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-revdelay::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-revdelay::Wet-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wet-Level</NICK>
+<BLURB>Wet-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-1-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[40,280]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-1-Freq--Hz-</NICK>
+<BLURB>Band-1-Freq--Hz-.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-1-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-1-Gain--dB-</NICK>
+<BLURB>Band-1-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-2-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[100,500]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-2-Freq--Hz-</NICK>
+<BLURB>Band-2-Freq--Hz-.</BLURB>
+<DEFAULT>200</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-2-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-2-Gain--dB-</NICK>
+<BLURB>Band-2-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-3-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[200,1000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-3-Freq--Hz-</NICK>
+<BLURB>Band-3-Freq--Hz-.</BLURB>
+<DEFAULT>400</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-3-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-3-Gain--dB-</NICK>
+<BLURB>Band-3-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-4-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[400,2800]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-4-Freq--Hz-</NICK>
+<BLURB>Band-4-Freq--Hz-.</BLURB>
+<DEFAULT>1000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-4-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-4-Gain--dB-</NICK>
+<BLURB>Band-4-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-5-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1000,5000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-5-Freq--Hz-</NICK>
+<BLURB>Band-5-Freq--Hz-.</BLURB>
+<DEFAULT>3000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-5-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-5-Gain--dB-</NICK>
+<BLURB>Band-5-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-6-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[3000,9000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-6-Freq--Hz-</NICK>
+<BLURB>Band-6-Freq--Hz-.</BLURB>
+<DEFAULT>6000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-6-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-6-Gain--dB-</NICK>
+<BLURB>Band-6-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-7-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[6000,18000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-7-Freq--Hz-</NICK>
+<BLURB>Band-7-Freq--Hz-.</BLURB>
+<DEFAULT>12000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-7-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-7-Gain--dB-</NICK>
+<BLURB>Band-7-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-8-Freq--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[10000,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-8-Freq--Hz-</NICK>
+<BLURB>Band-8-Freq--Hz-.</BLURB>
+<DEFAULT>15000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-equalizer::Band-8-Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-8-Gain--dB-</NICK>
+<BLURB>Band-8-Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-retroFlange::Average-stall</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Average-stall</NICK>
+<BLURB>Average-stall.</BLURB>
+<DEFAULT>2,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-retroFlange::Flange-frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5,8]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Flange-frequency</NICK>
+<BLURB>Flange-frequency.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Ambisonics-mono-panner::Azimuth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-180,180]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Azimuth</NICK>
+<BLURB>Azimuth.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Ambisonics-mono-panner::Elevation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,90]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Elevation</NICK>
+<BLURB>Elevation.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Ambisonics-stero-panner::Azimuth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-180,180]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Azimuth</NICK>
+<BLURB>Azimuth.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Ambisonics-stero-panner::Elevation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,90]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Elevation</NICK>
+<BLURB>Elevation.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Ambisonics-stero-panner::Width</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,90]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Width</NICK>
+<BLURB>Width.</BLURB>
+<DEFAULT>90</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Ambisonics-rotator::Angle</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-180,180]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Angle</NICK>
+<BLURB>Angle.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Ambisonics-square-decoder::Distance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Distance</NICK>
+<BLURB>Distance.</BLURB>
+<DEFAULT>30</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Ambisonics-square-decoder::Front</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Front</NICK>
+<BLURB>Front.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Ambisonics-square-decoder::LF-ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LF-ratio</NICK>
+<BLURB>LF-ratio.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Ambisonics-hexagon-decoder::Distance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Distance</NICK>
+<BLURB>Distance.</BLURB>
+<DEFAULT>30</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Ambisonics-hexagon-decoder::Front</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Front</NICK>
+<BLURB>Front.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Ambisonics-hexagon-decoder::LF-ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>LF-ratio</NICK>
+<BLURB>LF-ratio.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-G2reverb::Damping</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Damping</NICK>
+<BLURB>Damping.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-G2reverb::Dry-sound</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-80,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-sound</NICK>
+<BLURB>Dry-sound.</BLURB>
+<DEFAULT>-80</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-G2reverb::Input-BW</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Input-BW</NICK>
+<BLURB>Input-BW.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-G2reverb::Reflections</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-80,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reflections</NICK>
+<BLURB>Reflections.</BLURB>
+<DEFAULT>-80</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-G2reverb::Reverb-tail</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-80,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reverb-tail</NICK>
+<BLURB>Reverb-tail.</BLURB>
+<DEFAULT>-80</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-G2reverb::Reverb-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reverb-time</NICK>
+<BLURB>Reverb-time.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-G2reverb::Room-size</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[10,150]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Room-size</NICK>
+<BLURB>Room-size.</BLURB>
+<DEFAULT>10</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-amPitchshift::Buffer-size</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,7]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Buffer-size</NICK>
+<BLURB>Buffer-size.</BLURB>
+<DEFAULT>4</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-amPitchshift::Pitch-shift</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,25,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Pitch-shift</NICK>
+<BLURB>Pitch-shift.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-amPitchshift::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-modDelay::Base-delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Base-delay</NICK>
+<BLURB>Base-delay.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-autopan::Depth----</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Depth----</NICK>
+<BLURB>Depth----.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-autopan::Frequency--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency--Hz-</NICK>
+<BLURB>Frequency--Hz-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-autopan::Gain--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Gain--dB-</NICK>
+<BLURB>Gain--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-rateShifter::Rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-4,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Rate</NICK>
+<BLURB>Rate.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Filter::Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[10,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency</NICK>
+<BLURB>Frequency.</BLURB>
+<DEFAULT>10</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Filter::Inertia</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[5,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Inertia</NICK>
+<BLURB>Inertia.</BLURB>
+<DEFAULT>5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Filter::Mode</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Mode.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Filter::Resonance</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,707,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Resonance</NICK>
+<BLURB>Resonance.</BLURB>
+<DEFAULT>0,707</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Flanger::Amount</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Amount</NICK>
+<BLURB>Amount.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Flanger::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-0,99,0,99]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>-0,99</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Flanger::Minimum-delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Minimum-delay</NICK>
+<BLURB>Minimum-delay.</BLURB>
+<DEFAULT>0,1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Flanger::Modulation-depth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Modulation-depth</NICK>
+<BLURB>Modulation-depth.</BLURB>
+<DEFAULT>0,1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Flanger::Modulation-rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Modulation-rate</NICK>
+<BLURB>Modulation-rate.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Flanger::Reset</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reset</NICK>
+<BLURB>Reset.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Flanger::Stereo-phase</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,360]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Stereo-phase</NICK>
+<BLURB>Stereo-phase.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Reverb::Amount</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Amount</NICK>
+<BLURB>Amount.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Reverb::Decay-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5,15]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay-time</NICK>
+<BLURB>Decay-time.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Reverb::Diffusion</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Diffusion</NICK>
+<BLURB>Diffusion.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Reverb::High-Frq-Damp</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2000,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>High-Frq-Damp</NICK>
+<BLURB>High-Frq-Damp.</BLURB>
+<DEFAULT>2000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Reverb::Room-size</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,3]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Room-size</NICK>
+<BLURB>Room-size.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VintageDelay::Amount</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Amount</NICK>
+<BLURB>Amount.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VintageDelay::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VintageDelay::Medium</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Medium</NICK>
+<BLURB>Medium.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VintageDelay::Mix-mode</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mix-mode</NICK>
+<BLURB>Mix-mode.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VintageDelay::Subdivide</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,16]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Subdivide</NICK>
+<BLURB>Subdivide.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VintageDelay::Tempo</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[30,300]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tempo</NICK>
+<BLURB>Tempo.</BLURB>
+<DEFAULT>30</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VintageDelay::Time-L</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,16]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Time-L</NICK>
+<BLURB>Time-L.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VintageDelay::Time-R</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,16]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Time-R</NICK>
+<BLURB>Time-R.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-RotarySpeaker::Speed-Mode</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Speed-Mode</NICK>
+<BLURB>Speed-Mode.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-RotarySpeaker::Tap-Offset</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tap-Offset</NICK>
+<BLURB>Tap-Offset.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-RotarySpeaker::Tap-Spacing</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tap-Spacing</NICK>
+<BLURB>Tap-Spacing.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phaser::Amount</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Amount</NICK>
+<BLURB>Amount.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phaser::Center-Freq</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[20,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Center-Freq</NICK>
+<BLURB>Center-Freq.</BLURB>
+<DEFAULT>20</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phaser::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-0,99,0,99]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>-0,99</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phaser::Modulation-depth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10800]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Modulation-depth</NICK>
+<BLURB>Modulation-depth.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phaser::Modulation-rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,01,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Modulation-rate</NICK>
+<BLURB>Modulation-rate.</BLURB>
+<DEFAULT>0,01</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phaser::Reset</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reset</NICK>
+<BLURB>Reset.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phaser::Stereo-phase</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,360]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Stereo-phase</NICK>
+<BLURB>Stereo-phase.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-phaser::param---Stages</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,12]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param---Stages</NICK>
+<BLURB>param---Stages.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq::param-1-kHz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-1-kHz</NICK>
+<BLURB>param-1-kHz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq::param-125-Hz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-125-Hz</NICK>
+<BLURB>param-125-Hz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq::param-16-kHz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-16-kHz</NICK>
+<BLURB>param-16-kHz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq::param-2-kHz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-2-kHz</NICK>
+<BLURB>param-2-kHz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq::param-250-Hz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-250-Hz</NICK>
+<BLURB>param-250-Hz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq::param-31-Hz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-31-Hz</NICK>
+<BLURB>param-31-Hz.</BLURB>
+<DEFAULT>-30</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq::param-4-kHz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-4-kHz</NICK>
+<BLURB>param-4-kHz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq::param-500-Hz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-500-Hz</NICK>
+<BLURB>param-500-Hz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq::param-63-Hz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-63-Hz</NICK>
+<BLURB>param-63-Hz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq::param-8-kHz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-8-kHz</NICK>
+<BLURB>param-8-kHz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq2x2::param-1-kHz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-1-kHz</NICK>
+<BLURB>param-1-kHz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq2x2::param-125-Hz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-125-Hz</NICK>
+<BLURB>param-125-Hz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq2x2::param-16-kHz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-16-kHz</NICK>
+<BLURB>param-16-kHz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq2x2::param-2-kHz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-2-kHz</NICK>
+<BLURB>param-2-kHz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq2x2::param-250-Hz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-250-Hz</NICK>
+<BLURB>param-250-Hz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq2x2::param-31-Hz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-31-Hz</NICK>
+<BLURB>param-31-Hz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq2x2::param-4-kHz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-4-kHz</NICK>
+<BLURB>param-4-kHz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq2x2::param-500-Hz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-500-Hz</NICK>
+<BLURB>param-500-Hz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq2x2::param-63-Hz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-63-Hz</NICK>
+<BLURB>param-63-Hz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Eq2x2::param-8-kHz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-48,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-8-kHz</NICK>
+<BLURB>param-8-kHz.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Compress::attack</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>attack</NICK>
+<BLURB>attack.</BLURB>
+<DEFAULT>0,001</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Compress::gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>gain</NICK>
+<BLURB>gain.</BLURB>
+<DEFAULT>6</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Compress::knee-radius</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>knee-radius</NICK>
+<BLURB>knee-radius.</BLURB>
+<DEFAULT>3,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Compress::ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>ratio</NICK>
+<BLURB>ratio.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Compress::release</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>release</NICK>
+<BLURB>release.</BLURB>
+<DEFAULT>0,5005</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Compress::threshold</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-30,400]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>threshold</NICK>
+<BLURB>threshold.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Pan::mono</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>mono</NICK>
+<BLURB>mono.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Pan::pan</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>pan</NICK>
+<BLURB>pan.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Pan::t</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,40]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>t</NICK>
+<BLURB>t.</BLURB>
+<DEFAULT>10,075</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Pan::width</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>width</NICK>
+<BLURB>width.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PreampIII::gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>gain</NICK>
+<BLURB>gain.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PreampIII::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PreampIII::temperature</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,005,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>temperature</NICK>
+<BLURB>temperature.</BLURB>
+<DEFAULT>0,25375</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PreampIV::bass</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>bass</NICK>
+<BLURB>bass.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PreampIV::gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>gain</NICK>
+<BLURB>gain.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PreampIV::hi</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>hi</NICK>
+<BLURB>hi.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PreampIV::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PreampIV::mid</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>mid</NICK>
+<BLURB>mid.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PreampIV::temperature</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,005,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>temperature</NICK>
+<BLURB>temperature.</BLURB>
+<DEFAULT>0,5025</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PreampIV::treble</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>treble</NICK>
+<BLURB>treble.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ToneStack::bass</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>bass</NICK>
+<BLURB>bass.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ToneStack::mid</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>mid</NICK>
+<BLURB>mid.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ToneStack::model</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>model</NICK>
+<BLURB>model.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ToneStack::treble</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>treble</NICK>
+<BLURB>treble.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ToneStackLT::bass</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>bass</NICK>
+<BLURB>bass.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ToneStackLT::mid</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>mid</NICK>
+<BLURB>mid.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ToneStackLT::treble</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>treble</NICK>
+<BLURB>treble.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpIII::drive</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>drive</NICK>
+<BLURB>drive.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpIII::gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>gain</NICK>
+<BLURB>gain.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpIII::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpIII::temperature</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,005,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>temperature</NICK>
+<BLURB>temperature.</BLURB>
+<DEFAULT>0,5025</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpIV::bass</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>bass</NICK>
+<BLURB>bass.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpIV::drive</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>drive</NICK>
+<BLURB>drive.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpIV::gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>gain</NICK>
+<BLURB>gain.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpIV::hi</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>hi</NICK>
+<BLURB>hi.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpIV::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpIV::mid</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>mid</NICK>
+<BLURB>mid.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpIV::temperature</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,005,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>temperature</NICK>
+<BLURB>temperature.</BLURB>
+<DEFAULT>0,5025</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpIV::treble</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-20,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>treble</NICK>
+<BLURB>treble.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpV::bass</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-9,9]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>bass</NICK>
+<BLURB>bass.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpV::drive</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>drive</NICK>
+<BLURB>drive.</BLURB>
+<DEFAULT>0,750025</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpV::gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,3]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>gain</NICK>
+<BLURB>gain.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpV::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpV::tone</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>tone</NICK>
+<BLURB>tone.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpV::watts</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[5,150]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>watts</NICK>
+<BLURB>watts.</BLURB>
+<DEFAULT>77,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpVTS::bass</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>bass</NICK>
+<BLURB>bass.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpVTS::drive</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>drive</NICK>
+<BLURB>drive.</BLURB>
+<DEFAULT>0,250075</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpVTS::gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,3]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>gain</NICK>
+<BLURB>gain.</BLURB>
+<DEFAULT>2,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpVTS::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpVTS::mid</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>mid</NICK>
+<BLURB>mid.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpVTS::model</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>model</NICK>
+<BLURB>model.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpVTS::treble</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>treble</NICK>
+<BLURB>treble.</BLURB>
+<DEFAULT>0,75</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AmpVTS::watts</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>watts</NICK>
+<BLURB>watts.</BLURB>
+<DEFAULT>0,750025</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-CabinetI::gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-24,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>gain</NICK>
+<BLURB>gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-CabinetI::model</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>model</NICK>
+<BLURB>model.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-CabinetII::gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-24,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>gain</NICK>
+<BLURB>gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-CabinetII::model</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>model</NICK>
+<BLURB>model.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Clip::gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-72,72]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>gain</NICK>
+<BLURB>gain.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Clip::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ChorusI::blend</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>blend</NICK>
+<BLURB>blend.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ChorusI::feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>feedback</NICK>
+<BLURB>feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ChorusI::feedforward</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>feedforward</NICK>
+<BLURB>feedforward.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ChorusI::rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>rate</NICK>
+<BLURB>rate.</BLURB>
+<DEFAULT>1,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ChorusI::t</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,5,40]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>t</NICK>
+<BLURB>t.</BLURB>
+<DEFAULT>5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ChorusI::width</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>width</NICK>
+<BLURB>width.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-StereoChorusI::blend</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>blend</NICK>
+<BLURB>blend.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-StereoChorusI::feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>feedback</NICK>
+<BLURB>feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-StereoChorusI::feedforward</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>feedforward</NICK>
+<BLURB>feedforward.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-StereoChorusI::phase</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>phase</NICK>
+<BLURB>phase.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-StereoChorusI::rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>rate</NICK>
+<BLURB>rate.</BLURB>
+<DEFAULT>1,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-StereoChorusI::t</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,5,40]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>t</NICK>
+<BLURB>t.</BLURB>
+<DEFAULT>2,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-StereoChorusI::width</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>width</NICK>
+<BLURB>width.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ChorusII::blend</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>blend</NICK>
+<BLURB>blend.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ChorusII::feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>feedback</NICK>
+<BLURB>feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ChorusII::feedforward</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>feedforward</NICK>
+<BLURB>feedforward.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ChorusII::rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>rate</NICK>
+<BLURB>rate.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ChorusII::t</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,5,40]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>t</NICK>
+<BLURB>t.</BLURB>
+<DEFAULT>5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-ChorusII::width</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>width</NICK>
+<BLURB>width.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-StereoChorusII::blend</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>blend</NICK>
+<BLURB>blend.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-StereoChorusII::feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>feedback</NICK>
+<BLURB>feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-StereoChorusII::feedforward</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>feedforward</NICK>
+<BLURB>feedforward.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-StereoChorusII::rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>rate</NICK>
+<BLURB>rate.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-StereoChorusII::t</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,5,40]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>t</NICK>
+<BLURB>t.</BLURB>
+<DEFAULT>11,875</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-StereoChorusII::width</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>width</NICK>
+<BLURB>width.</BLURB>
+<DEFAULT>2,875</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PhaserI::depth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>depth</NICK>
+<BLURB>depth.</BLURB>
+<DEFAULT>0,75</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PhaserI::feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0,999]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>feedback</NICK>
+<BLURB>feedback.</BLURB>
+<DEFAULT>0,74925</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PhaserI::rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>rate</NICK>
+<BLURB>rate.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PhaserI::spread</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,3,14159]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>spread</NICK>
+<BLURB>spread.</BLURB>
+<DEFAULT>0,785398</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PhaserII::depth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>depth</NICK>
+<BLURB>depth.</BLURB>
+<DEFAULT>0,75</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PhaserII::feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0,999]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>feedback</NICK>
+<BLURB>feedback.</BLURB>
+<DEFAULT>0,74925</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PhaserII::rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>rate</NICK>
+<BLURB>rate.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-PhaserII::spread</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1,5708]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>spread</NICK>
+<BLURB>spread.</BLURB>
+<DEFAULT>0,392699</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFI::Q</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,0,999]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Q</NICK>
+<BLURB>Q.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFI::depth-x</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>depth-x</NICK>
+<BLURB>depth-x.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFI::depth-y</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>depth-y</NICK>
+<BLURB>depth-y.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFI::depth-z</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>depth-z</NICK>
+<BLURB>depth-z.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFI::f</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[83,3383]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>f</NICK>
+<BLURB>f.</BLURB>
+<DEFAULT>209,717</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFI::h</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>h</NICK>
+<BLURB>h.</BLURB>
+<DEFAULT>0,25075</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFI::mode</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>mode</NICK>
+<BLURB>mode.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFII::Q</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,0,999]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Q</NICK>
+<BLURB>Q.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFII::Q-depth-x</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Q-depth-x</NICK>
+<BLURB>Q-depth-x.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFII::Q-depth-y</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Q-depth-y</NICK>
+<BLURB>Q-depth-y.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFII::Q-depth-z</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Q-depth-z</NICK>
+<BLURB>Q-depth-z.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFII::Q-h</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Q-h</NICK>
+<BLURB>Q-h.</BLURB>
+<DEFAULT>0,25075</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFII::f</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[83,3383]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>f</NICK>
+<BLURB>f.</BLURB>
+<DEFAULT>209,717</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFII::f-depth-x</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>f-depth-x</NICK>
+<BLURB>f-depth-x.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFII::f-depth-y</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>f-depth-y</NICK>
+<BLURB>f-depth-y.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFII::f-depth-z</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>f-depth-z</NICK>
+<BLURB>f-depth-z.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFII::f-h</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>f-h</NICK>
+<BLURB>f-h.</BLURB>
+<DEFAULT>0,25075</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-SweepVFII::mode</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>mode</NICK>
+<BLURB>mode.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AutoWah::Q</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,001,0,999]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Q</NICK>
+<BLURB>Q.</BLURB>
+<DEFAULT>0,2505</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AutoWah::depth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>depth</NICK>
+<BLURB>depth.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-AutoWah::f</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[43,933]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>f</NICK>
+<BLURB>f.</BLURB>
+<DEFAULT>92,8051</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Scape::blend</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>blend</NICK>
+<BLURB>blend.</BLURB>
+<DEFAULT>0,75</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Scape::bpm</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[30,240]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>bpm</NICK>
+<BLURB>bpm.</BLURB>
+<DEFAULT>82,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Scape::divider</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[2,4]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>divider</NICK>
+<BLURB>divider.</BLURB>
+<DEFAULT>2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Scape::dry</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>dry</NICK>
+<BLURB>dry.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Scape::feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>feedback</NICK>
+<BLURB>feedback.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VCOs::f</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,5751]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>f</NICK>
+<BLURB>f.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VCOs::param------square</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param------square</NICK>
+<BLURB>param------square.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VCOs::tri----saw</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>tri----saw</NICK>
+<BLURB>tri----saw.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VCOs::volume</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1e-06,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>volume</NICK>
+<BLURB>volume.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VCOd::blend</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>blend</NICK>
+<BLURB>blend.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VCOd::f</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,5751]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>f</NICK>
+<BLURB>f.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VCOd::param-1-------square</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-1-------square</NICK>
+<BLURB>param-1-------square.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VCOd::param-1--tri----saw</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-1--tri----saw</NICK>
+<BLURB>param-1--tri----saw.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VCOd::param-2-------square</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-2-------square</NICK>
+<BLURB>param-2-------square.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VCOd::param-2--tri----saw</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-2--tri----saw</NICK>
+<BLURB>param-2--tri----saw.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VCOd::param-2--tune</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-12,12]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>param-2--tune</NICK>
+<BLURB>param-2--tune.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VCOd::sync</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>sync</NICK>
+<BLURB>sync.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-VCOd::volume</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1e-06,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>volume</NICK>
+<BLURB>volume.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-CEO::damping</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>damping</NICK>
+<BLURB>damping.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-CEO::mpm</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,244]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>mpm</NICK>
+<BLURB>mpm.</BLURB>
+<DEFAULT>184</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-CEO::volume</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>volume</NICK>
+<BLURB>volume.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sin::f</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0001,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>f</NICK>
+<BLURB>f.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Sin::volume</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1e-06,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>volume</NICK>
+<BLURB>volume.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-White::volume</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1e-06,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>volume</NICK>
+<BLURB>volume.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Lorenz::h</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>h</NICK>
+<BLURB>h.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Lorenz::volume</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1e-06,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>volume</NICK>
+<BLURB>volume.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Lorenz::x</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>x</NICK>
+<BLURB>x.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Lorenz::y</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>y</NICK>
+<BLURB>y.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Lorenz::z</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>z</NICK>
+<BLURB>z.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Roessler::h</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>h</NICK>
+<BLURB>h.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Roessler::volume</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1e-06,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>volume</NICK>
+<BLURB>volume.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Roessler::x</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>x</NICK>
+<BLURB>x.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Roessler::y</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>y</NICK>
+<BLURB>y.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Roessler::z</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>z</NICK>
+<BLURB>z.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-JVRev::blend</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0,28]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>blend</NICK>
+<BLURB>blend.</BLURB>
+<DEFAULT>0,07</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-JVRev::t60</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,4,6]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>t60</NICK>
+<BLURB>t60.</BLURB>
+<DEFAULT>2,3</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Plate::bandwidth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,005,0,999]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>bandwidth</NICK>
+<BLURB>bandwidth.</BLURB>
+<DEFAULT>0,502</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Plate::blend</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>blend</NICK>
+<BLURB>blend.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Plate::damping</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0005,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>damping</NICK>
+<BLURB>damping.</BLURB>
+<DEFAULT>0,250375</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Plate::tail</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0,749]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>tail</NICK>
+<BLURB>tail.</BLURB>
+<DEFAULT>0,3745</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Plate2x2::bandwidth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,005,0,999]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>bandwidth</NICK>
+<BLURB>bandwidth.</BLURB>
+<DEFAULT>0,502</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Plate2x2::blend</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>blend</NICK>
+<BLURB>blend.</BLURB>
+<DEFAULT>0,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Plate2x2::damping</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0005,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>damping</NICK>
+<BLURB>damping.</BLURB>
+<DEFAULT>0,250375</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Plate2x2::tail</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,0,749]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>tail</NICK>
+<BLURB>tail.</BLURB>
+<DEFAULT>0,3745</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Click::bpm</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,244]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>bpm</NICK>
+<BLURB>bpm.</BLURB>
+<DEFAULT>64</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Click::damping</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>damping</NICK>
+<BLURB>damping.</BLURB>
+<DEFAULT>0,75</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Click::volume</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>volume</NICK>
+<BLURB>volume.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Dirac::damping</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>damping</NICK>
+<BLURB>damping.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Dirac::ppm</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[30,60]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>ppm</NICK>
+<BLURB>ppm.</BLURB>
+<DEFAULT>30</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-Dirac::volume</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>volume</NICK>
+<BLURB>volume.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-HRTF::pan</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[-36,36]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>pan</NICK>
+<BLURB>pan.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Closed-Gate-Value</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Closed-Gate-Value</NICK>
+<BLURB>Closed-Gate-Value.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Loop-Steps</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,64]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Loop-Steps</NICK>
+<BLURB>Loop-Steps.</BLURB>
+<DEFAULT>64</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Reset-to-Value-on-Gate-Close-</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reset-to-Value-on-Gate-Close-</NICK>
+<BLURB>Reset-to-Value-on-Gate-Close-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-0</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-0</NICK>
+<BLURB>Value-Step-0.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-1</NICK>
+<BLURB>Value-Step-1.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-10</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-10</NICK>
+<BLURB>Value-Step-10.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-11</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-11</NICK>
+<BLURB>Value-Step-11.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-12</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-12</NICK>
+<BLURB>Value-Step-12.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-13</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-13</NICK>
+<BLURB>Value-Step-13.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-14</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-14</NICK>
+<BLURB>Value-Step-14.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-15</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-15</NICK>
+<BLURB>Value-Step-15.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-16</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-16</NICK>
+<BLURB>Value-Step-16.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-17</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-17</NICK>
+<BLURB>Value-Step-17.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-18</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-18</NICK>
+<BLURB>Value-Step-18.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-19</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-19</NICK>
+<BLURB>Value-Step-19.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-2</NICK>
+<BLURB>Value-Step-2.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-20</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-20</NICK>
+<BLURB>Value-Step-20.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-21</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-21</NICK>
+<BLURB>Value-Step-21.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-22</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-22</NICK>
+<BLURB>Value-Step-22.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-23</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-23</NICK>
+<BLURB>Value-Step-23.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-24</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-24</NICK>
+<BLURB>Value-Step-24.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-25</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-25</NICK>
+<BLURB>Value-Step-25.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-26</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-26</NICK>
+<BLURB>Value-Step-26.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-27</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-27</NICK>
+<BLURB>Value-Step-27.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-28</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-28</NICK>
+<BLURB>Value-Step-28.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-29</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-29</NICK>
+<BLURB>Value-Step-29.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-3</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-3</NICK>
+<BLURB>Value-Step-3.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-30</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-30</NICK>
+<BLURB>Value-Step-30.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-31</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-31</NICK>
+<BLURB>Value-Step-31.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-32</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-32</NICK>
+<BLURB>Value-Step-32.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-33</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-33</NICK>
+<BLURB>Value-Step-33.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-34</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-34</NICK>
+<BLURB>Value-Step-34.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-35</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-35</NICK>
+<BLURB>Value-Step-35.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-36</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-36</NICK>
+<BLURB>Value-Step-36.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-37</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-37</NICK>
+<BLURB>Value-Step-37.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-38</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-38</NICK>
+<BLURB>Value-Step-38.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-39</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-39</NICK>
+<BLURB>Value-Step-39.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-4</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-4</NICK>
+<BLURB>Value-Step-4.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-40</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-40</NICK>
+<BLURB>Value-Step-40.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-41</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-41</NICK>
+<BLURB>Value-Step-41.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-42</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-42</NICK>
+<BLURB>Value-Step-42.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-43</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-43</NICK>
+<BLURB>Value-Step-43.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-44</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-44</NICK>
+<BLURB>Value-Step-44.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-45</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-45</NICK>
+<BLURB>Value-Step-45.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-46</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-46</NICK>
+<BLURB>Value-Step-46.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-47</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-47</NICK>
+<BLURB>Value-Step-47.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-48</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-48</NICK>
+<BLURB>Value-Step-48.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-49</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-49</NICK>
+<BLURB>Value-Step-49.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-5</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-5</NICK>
+<BLURB>Value-Step-5.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-50</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-50</NICK>
+<BLURB>Value-Step-50.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-51</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-51</NICK>
+<BLURB>Value-Step-51.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-52</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-52</NICK>
+<BLURB>Value-Step-52.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-53</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-53</NICK>
+<BLURB>Value-Step-53.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-54</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-54</NICK>
+<BLURB>Value-Step-54.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-55</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-55</NICK>
+<BLURB>Value-Step-55.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-56</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-56</NICK>
+<BLURB>Value-Step-56.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-57</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-57</NICK>
+<BLURB>Value-Step-57.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-58</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-58</NICK>
+<BLURB>Value-Step-58.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-59</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-59</NICK>
+<BLURB>Value-Step-59.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-6</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-6</NICK>
+<BLURB>Value-Step-6.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-60</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-60</NICK>
+<BLURB>Value-Step-60.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-61</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-61</NICK>
+<BLURB>Value-Step-61.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-62</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-62</NICK>
+<BLURB>Value-Step-62.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-63</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-63</NICK>
+<BLURB>Value-Step-63.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-7</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-7</NICK>
+<BLURB>Value-Step-7.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-8</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-8</NICK>
+<BLURB>Value-Step-8.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer64::Value-Step-9</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-9</NICK>
+<BLURB>Value-Step-9.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-pointerCastDistortion::Dry-wet-mix</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-wet-mix</NICK>
+<BLURB>Dry-wet-mix.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-pointerCastDistortion::Effect-cutoff-freq</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,13230]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Effect-cutoff-freq</NICK>
+<BLURB>Effect-cutoff-freq.</BLURB>
+<DEFAULT>32,6376</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-comb::Band-separation</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[16,640]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-separation</NICK>
+<BLURB>Band-separation.</BLURB>
+<DEFAULT>172</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-comb::Feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-0,99,0,99]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-stereo-echo::Cross-Mode</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Cross-Mode</NICK>
+<BLURB>Cross-Mode.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-stereo-echo::Dry-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Level--dB-</NICK>
+<BLURB>Dry-Level--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-stereo-echo::Haas-Effect</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Haas-Effect</NICK>
+<BLURB>Haas-Effect.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-stereo-echo::L-Delay--ms-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>L-Delay--ms-</NICK>
+<BLURB>L-Delay--ms-.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-stereo-echo::L-Echo-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>L-Echo-Level--dB-</NICK>
+<BLURB>L-Echo-Level--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-stereo-echo::L-Feedback----</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>L-Feedback----</NICK>
+<BLURB>L-Feedback----.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-stereo-echo::R-Echo-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>R-Echo-Level--dB-</NICK>
+<BLURB>R-Echo-Level--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-stereo-echo::R-Haas-Delay--ms-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,2000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>R-Haas-Delay--ms-</NICK>
+<BLURB>R-Haas-Delay--ms-.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-stereo-echo::R-Haas-Feedback----</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>R-Haas-Feedback----</NICK>
+<BLURB>R-Haas-Feedback----.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-stereo-echo::Swap-Outputs</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Swap-Outputs</NICK>
+<BLURB>Swap-Outputs.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gsm::Dry-wet-mix</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-wet-mix</NICK>
+<BLURB>Dry-wet-mix.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gsm::Error-rate</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,30]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Error-rate</NICK>
+<BLURB>Error-rate.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gsm::Number-of-passes</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Number-of-passes</NICK>
+<BLURB>Number-of-passes.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-gsm::latency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>latency</NICK>
+<BLURB>latency.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-highpass-iir::Cutoff-Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,19845]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Cutoff-Frequency</NICK>
+<BLURB>Cutoff-Frequency.</BLURB>
+<DEFAULT>36,1195</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-highpass-iir::Stages-2-poles-per-stage-</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Stages-2-poles-per-stage-</NICK>
+<BLURB>Stages-2-poles-per-stage-.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-1-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-1-Level</NICK>
+<BLURB>Band-1-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-10-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-10-Level</NICK>
+<BLURB>Band-10-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-11-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-11-Level</NICK>
+<BLURB>Band-11-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-12-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-12-Level</NICK>
+<BLURB>Band-12-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-13-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-13-Level</NICK>
+<BLURB>Band-13-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-14-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-14-Level</NICK>
+<BLURB>Band-14-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-15-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-15-Level</NICK>
+<BLURB>Band-15-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-16-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-16-Level</NICK>
+<BLURB>Band-16-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-2-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-2-Level</NICK>
+<BLURB>Band-2-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-3-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-3-Level</NICK>
+<BLURB>Band-3-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-4-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-4-Level</NICK>
+<BLURB>Band-4-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-5-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-5-Level</NICK>
+<BLURB>Band-5-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-6-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-6-Level</NICK>
+<BLURB>Band-6-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-7-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-7-Level</NICK>
+<BLURB>Band-7-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-8-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-8-Level</NICK>
+<BLURB>Band-8-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Band-9-Level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Band-9-Level</NICK>
+<BLURB>Band-9-Level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-vocoder::Number-of-bands</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,16]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Number-of-bands</NICK>
+<BLURB>Number-of-bands.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-karaoke::Vocal-volume</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-70,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Vocal-volume</NICK>
+<BLURB>Vocal-volume.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-jaminController::Scene-no-</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Scene-no-</NICK>
+<BLURB>Scene-no-.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-chorusflanger::Contour--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[20,20000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Contour--Hz-</NICK>
+<BLURB>Contour--Hz-.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-chorusflanger::Delay--ms-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay--ms-</NICK>
+<BLURB>Delay--ms-.</BLURB>
+<DEFAULT>25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-chorusflanger::Depth----</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Depth----</NICK>
+<BLURB>Depth----.</BLURB>
+<DEFAULT>75</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-chorusflanger::Dry-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Dry-Level--dB-</NICK>
+<BLURB>Dry-Level--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-chorusflanger::Frequency--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,5]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency--Hz-</NICK>
+<BLURB>Frequency--Hz-.</BLURB>
+<DEFAULT>1,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-chorusflanger::L-R-Phase-Shift--deg-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,180]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>L-R-Phase-Shift--deg-</NICK>
+<BLURB>L-R-Phase-Shift--deg-.</BLURB>
+<DEFAULT>90</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-chorusflanger::Wet-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-90,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Wet-Level--dB-</NICK>
+<BLURB>Wet-Level--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-bandpass-iir::Bandwidth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,19845]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Bandwidth</NICK>
+<BLURB>Bandwidth.</BLURB>
+<DEFAULT>295,832</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-bandpass-iir::Center-Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,19845]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Center-Frequency</NICK>
+<BLURB>Center-Frequency.</BLURB>
+<DEFAULT>295,832</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-bandpass-iir::Stages-2-poles-per-stage-</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Stages-2-poles-per-stage-</NICK>
+<BLURB>Stages-2-poles-per-stage-.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4::Amplitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-40,12]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Amplitude</NICK>
+<BLURB>Amplitude.</BLURB>
+<DEFAULT>-40</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4::Attack-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,5,400]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Attack-time</NICK>
+<BLURB>Attack-time.</BLURB>
+<DEFAULT>101,125</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4::Gain-reduction</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-24,0]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Gain-reduction</NICK>
+<BLURB>Gain-reduction.</BLURB>
+<DEFAULT>-24</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4::Knee-radius</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Knee-radius</NICK>
+<BLURB>Knee-radius.</BLURB>
+<DEFAULT>3,25</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4::Makeup-gain</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,24]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Makeup-gain</NICK>
+<BLURB>Makeup-gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4::RMS-peak</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>RMS-peak</NICK>
+<BLURB>RMS-peak.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4::Ratio</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[1,20]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Ratio</NICK>
+<BLURB>Ratio.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4::Release-time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2,800]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Release-time</NICK>
+<BLURB>Release-time.</BLURB>
+<DEFAULT>401</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sc4::Threshold-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-30,0]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Threshold-level</NICK>
+<BLURB>Threshold-level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sawtooth-fc-oa::Frequenz</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,91875,22050]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequenz</NICK>
+<BLURB>Frequenz.</BLURB>
+<DEFAULT>440</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-notch-iir::Bandwidth</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,19845]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Bandwidth</NICK>
+<BLURB>Bandwidth.</BLURB>
+<DEFAULT>295,832</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-notch-iir::Center-Frequency</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[4,41,19845]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Center-Frequency</NICK>
+<BLURB>Center-Frequency.</BLURB>
+<DEFAULT>295,832</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-notch-iir::Stages-2-poles-per-stage-</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Stages-2-poles-per-stage-</NICK>
+<BLURB>Stages-2-poles-per-stage-.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-freqTracker::Tracking-speed</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Tracking-speed</NICK>
+<BLURB>Tracking-speed.</BLURB>
+<DEFAULT>0,5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-comb-n::Decay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay-Time</NICK>
+<BLURB>Decay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-comb-n::Delay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-Time</NICK>
+<BLURB>Delay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-comb-n::Max-Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Max-Delay</NICK>
+<BLURB>Max-Delay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-comb-l::Decay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay-Time</NICK>
+<BLURB>Decay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-comb-l::Delay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-Time</NICK>
+<BLURB>Delay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-comb-l::Max-Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Max-Delay</NICK>
+<BLURB>Max-Delay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-comb-c::Decay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Decay-Time</NICK>
+<BLURB>Decay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-comb-c::Delay-Time</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Delay-Time</NICK>
+<BLURB>Delay-Time.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-comb-c::Max-Delay</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Max-Delay</NICK>
+<BLURB>Max-Delay.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Closed-Gate-Value</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Closed-Gate-Value</NICK>
+<BLURB>Closed-Gate-Value.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Loop-Steps</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,32]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Loop-Steps</NICK>
+<BLURB>Loop-Steps.</BLURB>
+<DEFAULT>32</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Reset-to-Value-on-Gate-Close-</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reset-to-Value-on-Gate-Close-</NICK>
+<BLURB>Reset-to-Value-on-Gate-Close-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-0</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-0</NICK>
+<BLURB>Value-Step-0.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-1</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-1</NICK>
+<BLURB>Value-Step-1.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-10</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-10</NICK>
+<BLURB>Value-Step-10.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-11</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-11</NICK>
+<BLURB>Value-Step-11.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-12</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-12</NICK>
+<BLURB>Value-Step-12.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-13</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-13</NICK>
+<BLURB>Value-Step-13.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-14</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-14</NICK>
+<BLURB>Value-Step-14.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-15</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-15</NICK>
+<BLURB>Value-Step-15.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-16</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-16</NICK>
+<BLURB>Value-Step-16.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-17</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-17</NICK>
+<BLURB>Value-Step-17.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-18</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-18</NICK>
+<BLURB>Value-Step-18.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-19</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-19</NICK>
+<BLURB>Value-Step-19.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-2</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-2</NICK>
+<BLURB>Value-Step-2.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-20</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-20</NICK>
+<BLURB>Value-Step-20.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-21</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-21</NICK>
+<BLURB>Value-Step-21.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-22</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-22</NICK>
+<BLURB>Value-Step-22.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-23</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-23</NICK>
+<BLURB>Value-Step-23.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-24</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-24</NICK>
+<BLURB>Value-Step-24.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-25</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-25</NICK>
+<BLURB>Value-Step-25.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-26</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-26</NICK>
+<BLURB>Value-Step-26.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-27</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-27</NICK>
+<BLURB>Value-Step-27.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-28</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-28</NICK>
+<BLURB>Value-Step-28.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-29</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-29</NICK>
+<BLURB>Value-Step-29.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-3</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-3</NICK>
+<BLURB>Value-Step-3.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-30</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-30</NICK>
+<BLURB>Value-Step-30.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-31</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-31</NICK>
+<BLURB>Value-Step-31.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-4</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-4</NICK>
+<BLURB>Value-Step-4.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-5</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-5</NICK>
+<BLURB>Value-Step-5.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-6</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-6</NICK>
+<BLURB>Value-Step-6.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-7</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-7</NICK>
+<BLURB>Value-Step-7.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-8</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-8</NICK>
+<BLURB>Value-Step-8.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-sequencer32::Value-Step-9</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Value-Step-9</NICK>
+<BLURB>Value-Step-9.</BLURB>
+<DEFAULT>-3,40282e+38</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-deesser::Attenuation--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Attenuation--dB-</NICK>
+<BLURB>Attenuation--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-deesser::Frequency--Hz-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[2000,16000]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Frequency--Hz-</NICK>
+<BLURB>Frequency--Hz-.</BLURB>
+<DEFAULT>5500</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-deesser::Monitor</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Monitor</NICK>
+<BLURB>Monitor.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-deesser::Sidechain-Filter</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Sidechain-Filter</NICK>
+<BLURB>Sidechain-Filter.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-tap-deesser::Threshold-Level--dB-</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-50,10]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Threshold-Level--dB-</NICK>
+<BLURB>Threshold-Level--dB-.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>ladspa-noise-white::Amplitude</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Amplitude</NICK>
+<BLURB>Amplitude.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSMPTEAlpha::border</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Border</NICK>
+<BLURB>The border width of the transition.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSMPTEAlpha::depth</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,24]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Depth</NICK>
+<BLURB>Depth of the mask in bits.</BLURB>
+<DEFAULT>16</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSMPTEAlpha::position</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Position</NICK>
+<BLURB>Position of the transition effect.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSMPTEAlpha::type</NAME>
+<TYPE>GstSMPTEAlphaTransitionType</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Type</NICK>
+<BLURB>The type of transition to use.</BLURB>
+<DEFAULT>A bar moves from left to right</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSMPTEAlpha::invert</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Invert</NICK>
+<BLURB>Invert transition mask.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioKaraoke::filter-band</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,441]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Filter Band</NICK>
+<BLURB>The Frequency band of the filter.</BLURB>
+<DEFAULT>220</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioKaraoke::filter-width</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Filter Width</NICK>
+<BLURB>The Frequency width of the filter.</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioKaraoke::level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Level</NICK>
+<BLURB>Level of the effect (1.0 = full).</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioKaraoke::mono-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mono Level</NICK>
+<BLURB>Level of the mono channel (1.0 = full).</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSink::device</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Device</NICK>
+<BLURB>The PulseAudio sink device to connect to.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSink::server</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Server</NICK>
+<BLURB>The PulseAudio server to connect to.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSink::device-name</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Device name</NICK>
+<BLURB>Human-readable name of the sound device.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSink::volume</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Volume</NICK>
+<BLURB>Linear volume of this stream, 1.0=100%.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSink::mute</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mute</NICK>
+<BLURB>Mute state of this stream.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSink::stream-properties</NAME>
+<TYPE>GstStructure*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>stream properties</NICK>
+<BLURB>list of pulseaudio stream properties.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSink::client-name</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Client Name</NICK>
+<BLURB>The PulseAudio client name to use.</BLURB>
+<DEFAULT>"gst-plugins-good-plugins-scan"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSink::current-device</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Current Device</NICK>
+<BLURB>The current PulseAudio sink device.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSrc::device</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Device</NICK>
+<BLURB>The PulseAudio source device to connect to.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSrc::server</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Server</NICK>
+<BLURB>The PulseAudio server to connect to.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSrc::device-name</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Device name</NICK>
+<BLURB>Human-readable name of the sound device.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSrc::stream-properties</NAME>
+<TYPE>GstStructure*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>stream properties</NICK>
+<BLURB>list of pulseaudio stream properties.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSrc::mute</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mute</NICK>
+<BLURB>Mute state of this stream.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSrc::source-output-index</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>source output index</NICK>
+<BLURB>The index of the PulseAudio source output corresponding to this record stream.</BLURB>
+<DEFAULT>4294967295</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSrc::volume</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Volume</NICK>
+<BLURB>Linear volume of this stream, 1.0=100%.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSrc::client-name</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Client Name</NICK>
+<BLURB>The PulseAudio client_name_to_use.</BLURB>
+<DEFAULT>"gst-plugins-good-plugins-scan"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPulseSrc::current-device</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Current Device</NICK>
+<BLURB>The current PulseAudio source device.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTagInject::tags</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>w</FLAGS>
+<NICK>taglist</NICK>
+<BLURB>List of tags to inject into the target file.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDeinterleave::keep-positions</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Keep positions</NICK>
+<BLURB>Keep the original channel positions on the output buffers.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstInterleave::channel-positions</NAME>
+<TYPE>GValueArray*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Channel positions</NICK>
+<BLURB>Channel positions used on the output.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstInterleave::channel-positions-from-input</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Channel positions from input</NICK>
+<BLURB>Take channel positions from the input.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRgVolume::album-mode</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Album mode</NICK>
+<BLURB>Prefer album over track gain.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRgVolume::fallback-gain</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-60,60]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Fallback gain</NICK>
+<BLURB>Gain for streams missing tags [dB].</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRgVolume::headroom</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,60]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Headroom</NICK>
+<BLURB>Extra headroom [dB].</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRgVolume::pre-amp</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-60,60]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Pre-amp</NICK>
+<BLURB>Extra gain [dB].</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRgVolume::result-gain</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-120,120]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Result-gain</NICK>
+<BLURB>Applied gain [dB].</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRgVolume::target-gain</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-120,120]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Target-gain</NICK>
+<BLURB>Applicable gain [dB].</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRgLimiter::enabled</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Enabled</NICK>
+<BLURB>Enable processing.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRgAnalysis::forced</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Forced</NICK>
+<BLURB>Analyze even if ReplayGain tags exist.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRgAnalysis::num-tracks</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Number of album tracks</NICK>
+<BLURB>Number of remaining album tracks.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRgAnalysis::reference-level</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,150]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Reference level</NICK>
+<BLURB>Reference level [dB].</BLURB>
+<DEFAULT>89</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRgAnalysis::message</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Message</NICK>
+<BLURB>Post statics messages.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstHDV1394Src::channel</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,64]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Channel</NICK>
+<BLURB>Channel number for listening.</BLURB>
+<DEFAULT>63</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstHDV1394Src::device-name</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>device name</NICK>
+<BLURB>user-friendly name of the device.</BLURB>
+<DEFAULT>"Default"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstHDV1394Src::guid</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>GUID</NICK>
+<BLURB>select one of multiple DV devices by its GUID. use a hexadecimal like 0xhhhhhhhhhhhhhhhh. (0 = no guid).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstHDV1394Src::port</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[G_MAXULONG,16]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Port</NICK>
+<BLURB>Port number (-1 automatic).</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstHDV1394Src::use-avc</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Use AV/C</NICK>
+<BLURB>Use AV/C VTR control.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJPEGPay::quality</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,255]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Quality</NICK>
+<BLURB>Quality factor on JPEG data (unused).</BLURB>
+<DEFAULT>255</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJPEGPay::type</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,255]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Type</NICK>
+<BLURB>Default JPEG Type, overwritten by SOF when present.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioFIRFilter::kernel</NAME>
+<TYPE>GValueArray*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Filter Kernel</NICK>
+<BLURB>Filter kernel for the FIR filter.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioFIRFilter::latency</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Latecy</NICK>
+<BLURB>Filter latency in samples.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioIIRFilter::a</NAME>
+<TYPE>GValueArray*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>A</NICK>
+<BLURB>Filter coefficients (denominator of transfer function).</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioIIRFilter::b</NAME>
+<TYPE>GValueArray*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>B</NICK>
+<BLURB>Filter coefficients (numerator of transfer function).</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioEcho::delay</NAME>
+<TYPE>guint64</TYPE>
+<RANGE>>= 1</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Delay</NICK>
+<BLURB>Delay of the echo in nanoseconds.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioEcho::feedback</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Amount of feedback.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioEcho::intensity</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Intensity</NICK>
+<BLURB>Intensity of the echo.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioEcho::max-delay</NAME>
+<TYPE>guint64</TYPE>
+<RANGE>>= 1</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Maximum Delay</NICK>
+<BLURB>Maximum delay of the echo in nanoseconds (can't be changed in PLAYING or PAUSED state).</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioEcho::surround-delay</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Enable Surround Delay</NICK>
+<BLURB>Delay Surround Channels when TRUE instead of applying an echo effect.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAudioEcho::surround-mask</NAME>
+<TYPE>guint64</TYPE>
+<RANGE>>= 1</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Surround Mask</NICK>
+<BLURB>A bitmask of channels that are considered surround and delayed when surround-delay = TRUE.</BLURB>
+<DEFAULT>18446744073709551612</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAspectRatioCrop::aspect-ratio</NAME>
+<TYPE>GstFraction</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>aspect-ratio</NICK>
+<BLURB>Target aspect-ratio of video.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpG726Depay::force-aal2</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Force AAL2</NICK>
+<BLURB>Force AAL2 decoding for compatibility with bad payloaders.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpG726Pay::force-aal2</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Force AAL2</NICK>
+<BLURB>Force AAL2 encoding for compatibility with bad depayloaders.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpH263Pay::modea-only</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Fragment packets in mode A Only</NICK>
+<BLURB>Disable packetization modes B and C.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDeinterlace::fields</NAME>
+<TYPE>GstDeinterlaceFields</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>fields</NICK>
+<BLURB>Fields to use for deinterlacing.</BLURB>
+<DEFAULT>All fields</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDeinterlace::method</NAME>
+<TYPE>GstDeinterlaceMethods</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Method</NICK>
+<BLURB>Deinterlace Method.</BLURB>
+<DEFAULT>Linear</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDeinterlace::mode</NAME>
+<TYPE>GstDeinterlaceModes</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Deinterlace Mode.</BLURB>
+<DEFAULT>Auto detection (best effort)</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDeinterlace::tff</NAME>
+<TYPE>GstDeinterlaceFieldLayout</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>tff</NICK>
+<BLURB>Deinterlace top field first.</BLURB>
+<DEFAULT>Auto detection</DEFAULT>
+</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>
+<FLAGS>rw</FLAGS>
+<NICK>Color Aging</NICK>
+<BLURB>Color Aging.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAgingTV::dusts</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Dusts</NICK>
+<BLURB>Dusts.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAgingTV::pits</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Pits</NICK>
+<BLURB>Pits.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstAgingTV::scratch-lines</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 20</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Scratch Lines</NICK>
+<BLURB>Number of scratch lines.</BLURB>
+<DEFAULT>7</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOpTV::mode</NAME>
+<TYPE>GstOpTVMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Mode.</BLURB>
+<DEFAULT>Maelstrom</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOpTV::speed</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Speed</NICK>
+<BLURB>Effect speed.</BLURB>
+<DEFAULT>16</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOpTV::threshold</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= G_MAXINT</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Threshold</NICK>
+<BLURB>Luma threshold.</BLURB>
+<DEFAULT>60</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRadioacTV::color</NAME>
+<TYPE>GstRadioacTVColor</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Color</NICK>
+<BLURB>Color.</BLURB>
+<DEFAULT>White</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRadioacTV::interval</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= G_MAXINT</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interval</NICK>
+<BLURB>Snapshot interval (in strobe mode).</BLURB>
+<DEFAULT>3</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRadioacTV::mode</NAME>
+<TYPE>GstRadioacTVMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Mode.</BLURB>
+<DEFAULT>Normal</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRadioacTV::trigger</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Trigger</NICK>
+<BLURB>Trigger (in trigger mode).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstStreakTV::feedback</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Feedback</NICK>
+<BLURB>Feedback.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRippleTV::mode</NAME>
+<TYPE>GstRippleTVMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Mode.</BLURB>
+<DEFAULT>Motion Detection</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRippleTV::reset</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>w</FLAGS>
+<NICK>Reset</NICK>
+<BLURB>Reset all current ripples.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::do-lost</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Do Lost</NICK>
+<BLURB>Send an event downstream when a packet is lost.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::latency</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Buffer latency in ms</NICK>
+<BLURB>Default amount of ms to buffer in the jitterbuffers.</BLURB>
+<DEFAULT>200</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::sdes</NAME>
+<TYPE>GstStructure*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>SDES</NICK>
+<BLURB>The SDES items of this session.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::ignore-pt</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Ignore PT</NICK>
+<BLURB>Do not demultiplex based on PT values.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::autoremove</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Auto Remove</NICK>
+<BLURB>Automatically remove timed out sources.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::buffer-mode</NAME>
+<TYPE>RTPJitterBufferMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Buffer Mode</NICK>
+<BLURB>Control the buffering algorithm in use.</BLURB>
+<DEFAULT>Slave receiver to sender clock</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::ntp-sync</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Sync on NTP clock</NICK>
+<BLURB>Synchronize received streams to the NTP clock.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::use-pipeline-clock</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Use pipeline clock</NICK>
+<BLURB>Use the pipeline running-time to set the NTP time in the RTCP SR messages (DEPRECATED: Use ntp-time-source property).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::rtcp-sync</NAME>
+<TYPE>GstRTCPSync</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTCP Sync</NICK>
+<BLURB>Use of RTCP SR in synchronization.</BLURB>
+<DEFAULT>always</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::rtcp-sync-interval</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTCP Sync Interval</NICK>
+<BLURB>RTCP SR interval synchronization (ms) (0 = always).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::drop-on-latency</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Drop buffers when maximum latency is reached</NICK>
+<BLURB>Tells the jitterbuffer to never exceed the given latency in size.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::do-sync-event</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Do Sync Event</NICK>
+<BLURB>Send event downstream when a stream is synchronized to the sender.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::do-retransmission</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Do retransmission</NICK>
+<BLURB>Enable retransmission on all streams.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::rtp-profile</NAME>
+<TYPE>GstRTPProfile</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTP Profile</NICK>
+<BLURB>Default RTP profile of newly created sessions.</BLURB>
+<DEFAULT>GST_RTP_PROFILE_AVP</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::ntp-time-source</NAME>
+<TYPE>GstRtpNtpTimeSource</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>NTP Time Source</NICK>
+<BLURB>NTP time source for RTCP packets.</BLURB>
+<DEFAULT>NTP time based on realtime clock</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::max-dropout-time</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max dropout time</NICK>
+<BLURB>The maximum time (milliseconds) of missing packets tolerated.</BLURB>
+<DEFAULT>60000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::max-misorder-time</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max misorder time</NICK>
+<BLURB>The maximum time (milliseconds) of misordered packets tolerated.</BLURB>
+<DEFAULT>2000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::max-rtcp-rtp-time-diff</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max RTCP RTP Time Diff</NICK>
+<BLURB>Maximum amount of time in ms that the RTP time in RTCP SRs is allowed to be ahead (-1 disabled).</BLURB>
+<DEFAULT>1000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::rtcp-sync-send-time</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTCP Sync Send Time</NICK>
+<BLURB>Use send time or capture time for RTCP sync (TRUE = send time, FALSE = capture time).</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::rfc7273-sync</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Sync on RFC7273 clock</NICK>
+<BLURB>Synchronize received streams to the RFC7273 clock (requires clock and offset to be provided).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::max-streams</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Streams</NICK>
+<BLURB>The maximum number of streams to create for one session.</BLURB>
+<DEFAULT>4294967295</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::max-ts-offset</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max TS Offset</NICK>
+<BLURB>The maximum absolute value of the time offset in (nanoseconds). Note, if the ntp-sync parameter is set the default value is changed to 0 (no limit).</BLURB>
+<DEFAULT>3000000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpBin::max-ts-offset-adjustment</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Timestamp Offset Adjustment</NICK>
+<BLURB>The maximum number of nanoseconds per frame that time stamp offsets may be adjusted (0 = no limit).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::do-lost</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Do Lost</NICK>
+<BLURB>Send an event downstream when a packet is lost.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::drop-on-latency</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Drop buffers when maximum latency is reached</NICK>
+<BLURB>Tells the jitterbuffer to never exceed the given latency in size.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::latency</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Buffer latency in ms</NICK>
+<BLURB>Amount of ms to buffer.</BLURB>
+<DEFAULT>200</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::ts-offset</NAME>
+<TYPE>gint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Timestamp Offset</NICK>
+<BLURB>Adjust buffer timestamps with offset in nanoseconds.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::mode</NAME>
+<TYPE>RTPJitterBufferMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Control the buffering algorithm in use.</BLURB>
+<DEFAULT>Slave receiver to sender clock</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::percent</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>percent</NICK>
+<BLURB>The buffer filled percent.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::do-retransmission</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Do Retransmission</NICK>
+<BLURB>Send retransmission events upstream when a packet is late.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::rtx-delay</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTX Delay</NICK>
+<BLURB>Extra time in ms to wait before sending retransmission event (-1 automatic).</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::rtx-delay-reorder</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTX Delay Reorder</NICK>
+<BLURB>Sending retransmission event when this much reordering (0 disable, -1 automatic).</BLURB>
+<DEFAULT>3</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::rtx-retry-period</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTX Retry Period</NICK>
+<BLURB>Try to get a retransmission for this many ms (-1 automatic).</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::rtx-retry-timeout</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTX Retry Timeout</NICK>
+<BLURB>Retry sending a transmission event after this timeout in ms (-1 automatic).</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::stats</NAME>
+<TYPE>GstStructure*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Statistics</NICK>
+<BLURB>Various statistics.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::rtx-min-delay</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Minimum RTX Delay</NICK>
+<BLURB>Minimum time in ms to wait before sending retransmission event.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::rtx-min-retry-timeout</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTX Min Retry Timeout</NICK>
+<BLURB>Minimum timeout between sending a transmission event in ms (-1 automatic).</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::rtx-max-retries</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTX Max Retries</NICK>
+<BLURB>The maximum number of retries to request a retransmission. (-1 not limited).</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::rtx-next-seqnum</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTX next seqnum</NICK>
+<BLURB>Estimate when the next packet should arrive and schedule a retransmission request for it.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::max-dropout-time</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max dropout time</NICK>
+<BLURB>The maximum time (milliseconds) of missing packets tolerated.</BLURB>
+<DEFAULT>60000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::max-misorder-time</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max misorder time</NICK>
+<BLURB>The maximum time (milliseconds) of misordered packets tolerated.</BLURB>
+<DEFAULT>2000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::max-rtcp-rtp-time-diff</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max RTCP RTP Time Diff</NICK>
+<BLURB>Maximum amount of time in ms that the RTP time in RTCP SRs is allowed to be ahead (-1 disabled).</BLURB>
+<DEFAULT>1000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::rfc7273-sync</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Sync on RFC7273 clock</NICK>
+<BLURB>Synchronize received streams to the RFC7273 clock (requires clock and offset to be provided).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::rtx-deadline</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTX Deadline (ms)</NICK>
+<BLURB>The deadline for a valid RTX request in milliseconds. (-1 automatic).</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::rtx-stats-timeout</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTX Statistics Timeout</NICK>
+<BLURB>The time to wait for a retransmitted packet after it has been considered lost in order to collect statistics (ms).</BLURB>
+<DEFAULT>1000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::faststart-min-packets</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Faststart minimum packets</NICK>
+<BLURB>The number of consecutive packets needed to start (set to 0 to disable faststart. The jitterbuffer will by default start after the latency has elapsed).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpJitterBuffer::max-ts-offset-adjustment</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Timestamp Offset Adjustment</NICK>
+<BLURB>The maximum number of nanoseconds per frame that time stamp offsets may be adjusted (0 = no limit).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::bandwidth</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Bandwidth</NICK>
+<BLURB>The bandwidth of the session in bytes per second (0 for auto-discover).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::internal-session</NAME>
+<TYPE>RTPSession*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Internal Session</NICK>
+<BLURB>The internal RTPSession object.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::num-active-sources</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Num Active Sources</NICK>
+<BLURB>The number of active sources in the session.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::num-sources</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Num Sources</NICK>
+<BLURB>The number of sources in the session.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::rtcp-fraction</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTCP Fraction</NICK>
+<BLURB>The RTCP bandwidth of the session in bytes per second (or as a real fraction of the RTP bandwidth if < 1.0).</BLURB>
+<DEFAULT>0.05</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::sdes</NAME>
+<TYPE>GstStructure*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>SDES</NICK>
+<BLURB>The SDES items of this session.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::rtcp-rr-bandwidth</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTCP RR bandwidth</NICK>
+<BLURB>The RTCP bandwidth used for receivers in bytes per second (-1 = default).</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::rtcp-rs-bandwidth</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTCP RS bandwidth</NICK>
+<BLURB>The RTCP bandwidth used for senders in bytes per second (-1 = default).</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::use-pipeline-clock</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Use pipeline clock</NICK>
+<BLURB>Use the pipeline running-time to set the NTP time in the RTCP SR messages (DEPRECATED: Use ntp-time-source property).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::rtcp-min-interval</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Minimum RTCP interval</NICK>
+<BLURB>Minimum interval between Regular RTCP packet (in ns).</BLURB>
+<DEFAULT>5000000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::probation</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Number of probations</NICK>
+<BLURB>Consecutive packet sequence numbers to accept the source.</BLURB>
+<DEFAULT>2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::stats</NAME>
+<TYPE>GstStructure*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Statistics</NICK>
+<BLURB>Various statistics.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::rtp-profile</NAME>
+<TYPE>GstRTPProfile</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTP Profile</NICK>
+<BLURB>RTP profile to use.</BLURB>
+<DEFAULT>GST_RTP_PROFILE_AVP</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::ntp-time-source</NAME>
+<TYPE>GstRtpNtpTimeSource</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>NTP Time Source</NICK>
+<BLURB>NTP time source for RTCP packets.</BLURB>
+<DEFAULT>NTP time based on realtime clock</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::max-dropout-time</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max dropout time</NICK>
+<BLURB>The maximum time (milliseconds) of missing packets tolerated.</BLURB>
+<DEFAULT>60000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::max-misorder-time</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max misorder time</NICK>
+<BLURB>The maximum time (milliseconds) of misordered packets tolerated.</BLURB>
+<DEFAULT>2000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSession::rtcp-sync-send-time</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>RTCP Sync Send Time</NICK>
+<BLURB>Use send time or capture time for RTCP sync (TRUE = send time, FALSE = capture time).</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpRtxSend::max-size-time</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Size Time</NICK>
+<BLURB>Amount of ms to queue (0 = unlimited).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpRtxSend::max-size-packets</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 32767</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Size Packets</NICK>
+<BLURB>Amount of packets to queue (0 = unlimited).</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpRtxSend::num-rtx-requests</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Num RTX Requests</NICK>
+<BLURB>Number of retransmission events received.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpRtxSend::num-rtx-packets</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Num RTX Packets</NICK>
+<BLURB> Number of retransmission packets sent.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpRtxSend::payload-type-map</NAME>
+<TYPE>GstStructure*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Payload Type Map</NICK>
+<BLURB>Map of original payload types to their retransmission payload types.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpRtxSend::ssrc-map</NAME>
+<TYPE>GstStructure*</TYPE>
+<RANGE></RANGE>
+<FLAGS>w</FLAGS>
+<NICK>SSRC Map</NICK>
+<BLURB>Map of SSRCs to their retransmission SSRCs for SSRC-multiplexed mode (default = random).</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpRtxReceive::num-rtx-requests</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Num RTX Requests</NICK>
+<BLURB>Number of retransmission events received.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpRtxReceive::num-rtx-packets</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Num RTX Packets</NICK>
+<BLURB> Number of retransmission packets received.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpRtxReceive::num-rtx-assoc-packets</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Num RTX Associated Packets</NICK>
+<BLURB>Number of retransmission packets correctly associated with retransmission requests.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpRtxReceive::payload-type-map</NAME>
+<TYPE>GstStructure*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Payload Type Map</NICK>
+<BLURB>Map of original payload types to their retransmission payload types.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::device</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Device</NICK>
+<BLURB>Device location.</BLURB>
+<DEFAULT>"/dev/video1"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::device-fd</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>File descriptor</NICK>
+<BLURB>File descriptor of the device.</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::device-name</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Device name</NICK>
+<BLURB>Name of the device.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::flags</NAME>
+<TYPE>GstV4l2DeviceTypeFlags</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Flags</NICK>
+<BLURB>Device type flags.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::overlay-height</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Overlay height</NICK>
+<BLURB>The height of the video overlay; default is equal to negotiated image height.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::overlay-left</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Overlay left</NICK>
+<BLURB>The leftmost (x) coordinate of the video overlay; top left corner of screen is 0,0.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::overlay-top</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Overlay top</NICK>
+<BLURB>The topmost (y) coordinate of the video overlay; top left corner of screen is 0,0.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::overlay-width</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Overlay width</NICK>
+<BLURB>The width of the video overlay; default is equal to negotiated image width.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::brightness</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Brightness</NICK>
+<BLURB>Picture brightness, or more precisely, the black level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::contrast</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Contrast</NICK>
+<BLURB>Picture contrast or luma gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::hue</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Hue</NICK>
+<BLURB>Hue or color balance.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::saturation</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Saturation</NICK>
+<BLURB>Picture color saturation or chroma gain.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::crop-height</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Crop height</NICK>
+<BLURB>The height of the video crop; default is equal to negotiated image height.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::crop-left</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Crop left</NICK>
+<BLURB>The leftmost (x) coordinate of the video crop; top left corner of image is 0,0.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::crop-top</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Crop top</NICK>
+<BLURB>The topmost (y) coordinate of the video crop; top left corner of image is 0,0.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::crop-width</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Crop width</NICK>
+<BLURB>The width of the video crop; default is equal to negotiated image width.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::io-mode</NAME>
+<TYPE>GstV4l2IOMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>IO mode</NICK>
+<BLURB>I/O mode.</BLURB>
+<DEFAULT>GST_V4L2_IO_AUTO</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::norm</NAME>
+<TYPE>V4L2_TV_norms</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>TV norm</NICK>
+<BLURB>video standard.</BLURB>
+<DEFAULT>none</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::extra-controls</NAME>
+<TYPE>GstStructure*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Extra Controls</NICK>
+<BLURB>Extra v4l2 controls (CIDs) for the device.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::force-aspect-ratio</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Force aspect ratio</NICK>
+<BLURB>When enabled, the pixel aspect ratio will be enforced.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Sink::pixel-aspect-ratio</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Pixel Aspect Ratio</NICK>
+<BLURB>Overwrite the pixel aspect ratio of the device.</BLURB>
+<DEFAULT>"1/1"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstShapeWipe::border</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Border</NICK>
+<BLURB>Border of the mask.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstShapeWipe::position</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Position</NICK>
+<BLURB>Position of the mask.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlvMux::streamable</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>streamable</NICK>
+<BLURB>If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlvMux::metadatacreator</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>metadatacreator</NICK>
+<BLURB>The value of metadatacreator in the meta packet.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstCapsSetter::caps</NAME>
+<TYPE>GstCaps*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Merge caps</NICK>
+<BLURB>Merge these caps (thereby overwriting) in the stream.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstCapsSetter::join</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Join</NICK>
+<BLURB>Match incoming caps' mime-type to mime-type of provided caps.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstCapsSetter::replace</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Replace</NICK>
+<BLURB>Drop fields of incoming caps.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOss4Source::device</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Device</NICK>
+<BLURB>OSS4 device (e.g. /dev/oss/hdaudio0/pcm0 or /dev/dspN) (NULL = use first available device).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOss4Source::device-name</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Device name</NICK>
+<BLURB>Human-readable name of the sound device.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOss4Sink::device</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Device</NICK>
+<BLURB>OSS4 device (e.g. /dev/oss/hdaudio0/pcm0 or /dev/dspN) (NULL = use first available playback device).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOss4Sink::device-name</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Device name</NICK>
+<BLURB>Human-readable name of the sound device.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOss4Sink::mute</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mute</NICK>
+<BLURB>Mute state of this stream.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstOss4Sink::volume</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,10]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Volume</NICK>
+<BLURB>Linear volume of this stream, 1.0=100%.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpTheoraPay::config-interval</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 3600</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Config Send Interval</NICK>
+<BLURB>Send Config Insertion Interval in seconds (configuration headers will be multiplexed in the data stream when detected.) (0 = disabled).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoMixer2::background</NAME>
+<TYPE>GstVideoMixer2Background</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Background</NICK>
+<BLURB>Background type.</BLURB>
+<DEFAULT>Checker pattern</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJackAudioSrc::client</NAME>
+<TYPE>JackClient*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>JackClient</NICK>
+<BLURB>Handle for jack client.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJackAudioSrc::connect</NAME>
+<TYPE>GstJackConnect</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Connect</NICK>
+<BLURB>Specify how the input ports will be connected.</BLURB>
+<DEFAULT>Automatically connect ports to physical ports</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJackAudioSrc::server</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Server</NICK>
+<BLURB>The Jack server to connect to (NULL = default).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJackAudioSrc::client-name</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Client name</NICK>
+<BLURB>The client name of the Jack instance (NULL = default).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJackAudioSrc::transport</NAME>
+<TYPE>GstJackTransport</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Transport mode</NICK>
+<BLURB>Jack transport behaviour of the client.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJackAudioSrc::port-pattern</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>port pattern</NICK>
+<BLURB>A pattern to select which ports to connect to (NULL = first physical ports).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJackAudioSink::client</NAME>
+<TYPE>JackClient*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>JackClient</NICK>
+<BLURB>Handle for jack client.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJackAudioSink::connect</NAME>
+<TYPE>GstJackConnect</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Connect</NICK>
+<BLURB>Specify how the output ports will be connected.</BLURB>
+<DEFAULT>Automatically connect ports to physical ports</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJackAudioSink::server</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Server</NICK>
+<BLURB>The Jack server to connect to (NULL = default).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJackAudioSink::client-name</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Client name</NICK>
+<BLURB>The client name of the Jack instance (NULL = default).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJackAudioSink::transport</NAME>
+<TYPE>GstJackTransport</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Transport mode</NICK>
+<BLURB>Jack transport behaviour of the client.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstJackAudioSink::port-pattern</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>port pattern</NICK>
+<BLURB>A pattern to select which ports to connect to (NULL = first physical ports).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstFlacParse::check-frame-checksums</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Check Frame Checksums</NICK>
+<BLURB>Check the overall checksums of every frame.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Radio::device</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Radio device location</NICK>
+<BLURB>Video4Linux2 radio device location.</BLURB>
+<DEFAULT>"/dev/radio0"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstV4l2Radio::frequency</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[87500000,108000000]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Station frequency</NICK>
+<BLURB>Station frequency in Hz.</BLURB>
+<DEFAULT>100000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::dts-method</NAME>
+<TYPE>GstQTMuxDtsMethods</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>dts-method</NICK>
+<BLURB>Method to determine DTS time (DEPRECATED).</BLURB>
+<DEFAULT>reorder</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::faststart</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Format file to faststart</NICK>
+<BLURB>If the file should be formatted for faststart (headers first).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::faststart-file</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>File to use for storing buffers</NICK>
+<BLURB>File that will be used temporarily to store data from the stream when creating a faststart file. If null a filepath will be created automatically.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::fragment-duration</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Fragment duration</NICK>
+<BLURB>Fragment durations in ms (produce a fragmented file if > 0).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::moov-recovery-file</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>File to store data for posterior moov atom recovery</NICK>
+<BLURB>File to be used to store data for moov atom making movie file recovery possible in case of a crash during muxing. Null for disabled. (Experimental).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::movie-timescale</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Movie timescale</NICK>
+<BLURB>Timescale to use in the movie (units per second, 0 == default).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::presentation-time</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Include presentation-time info</NICK>
+<BLURB>Calculate and include presentation/composition time (in addition to decoding time).</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::streamable</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Streamable</NICK>
+<BLURB>If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written. (DEPRECATED, only valid for fragmented MP4).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::trak-timescale</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Track timescale</NICK>
+<BLURB>Timescale to use for the tracks (units per second, 0 is automatic).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::reserved-bytes-per-sec</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 10000</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reserved MOOV bytes per second, per track</NICK>
+<BLURB>Multiplier for converting reserved-max-duration into bytes of header to reserve, per second, per track.</BLURB>
+<DEFAULT>550</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::reserved-duration-remaining</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Report the approximate amount of remaining recording space (ns)</NICK>
+<BLURB>Reports the approximate amount of remaining moov header space reserved using reserved-max-duration.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::reserved-max-duration</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Reserved maximum file duration (ns)</NICK>
+<BLURB>When set to a value > 0, reserves space for index tables at the beginning of the file.</BLURB>
+<DEFAULT>18446744073709551615</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::reserved-moov-update-period</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interval at which to update index tables (ns)</NICK>
+<BLURB>When used with reserved-max-duration, periodically updates the index tables with information muxed so far.</BLURB>
+<DEFAULT>18446744073709551615</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::interleave-bytes</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interleave (bytes)</NICK>
+<BLURB>Interleave between streams in bytes.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::interleave-time</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interleave (time)</NICK>
+<BLURB>Interleave between streams in nanoseconds.</BLURB>
+<DEFAULT>250000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::max-raw-audio-drift</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Raw Audio Drift</NICK>
+<BLURB>Maximum allowed drift of raw audio samples vs. timestamps in nanoseconds.</BLURB>
+<DEFAULT>40000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMux::reserved-prefill</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reserved Prefill Samples Table</NICK>
+<BLURB>Prefill samples table of reserved duration.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMoovRecover::broken-input</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Path to broken input file</NICK>
+<BLURB>Path to broken input file. (If qtmux was on faststart mode, this file is the faststart file).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMoovRecover::faststart-mode</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>If the broken input is from faststart mode</NICK>
+<BLURB>If the broken input is from faststart mode.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMoovRecover::fixed-output</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Path to write the fixed file</NICK>
+<BLURB>Path to write the fixed file to (used as output).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstQTMoovRecover::recovery-input</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Path to recovery file</NICK>
+<BLURB>Path to recovery file (used as input).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::dts-method</NAME>
+<TYPE>GstQTMuxDtsMethods</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>dts-method</NICK>
+<BLURB>Method to determine DTS time (DEPRECATED).</BLURB>
+<DEFAULT>reorder</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::faststart</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Format file to faststart</NICK>
+<BLURB>If the file should be formatted for faststart (headers first).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::faststart-file</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>File to use for storing buffers</NICK>
+<BLURB>File that will be used temporarily to store data from the stream when creating a faststart file. If null a filepath will be created automatically.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::fragment-duration</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Fragment duration</NICK>
+<BLURB>Fragment durations in ms (produce a fragmented file if > 0).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::moov-recovery-file</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>File to store data for posterior moov atom recovery</NICK>
+<BLURB>File to be used to store data for moov atom making movie file recovery possible in case of a crash during muxing. Null for disabled. (Experimental).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::movie-timescale</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Movie timescale</NICK>
+<BLURB>Timescale to use in the movie (units per second, 0 == default).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::presentation-time</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Include presentation-time info</NICK>
+<BLURB>Calculate and include presentation/composition time (in addition to decoding time).</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::streamable</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Streamable</NICK>
+<BLURB>If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written. (DEPRECATED, only valid for fragmented MP4).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::trak-timescale</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Track timescale</NICK>
+<BLURB>Timescale to use for the tracks (units per second, 0 is automatic).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::reserved-bytes-per-sec</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 10000</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reserved MOOV bytes per second, per track</NICK>
+<BLURB>Multiplier for converting reserved-max-duration into bytes of header to reserve, per second, per track.</BLURB>
+<DEFAULT>550</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::reserved-duration-remaining</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Report the approximate amount of remaining recording space (ns)</NICK>
+<BLURB>Reports the approximate amount of remaining moov header space reserved using reserved-max-duration.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::reserved-max-duration</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Reserved maximum file duration (ns)</NICK>
+<BLURB>When set to a value > 0, reserves space for index tables at the beginning of the file.</BLURB>
+<DEFAULT>18446744073709551615</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::reserved-moov-update-period</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interval at which to update index tables (ns)</NICK>
+<BLURB>When used with reserved-max-duration, periodically updates the index tables with information muxed so far.</BLURB>
+<DEFAULT>18446744073709551615</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::interleave-bytes</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interleave (bytes)</NICK>
+<BLURB>Interleave between streams in bytes.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::interleave-time</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interleave (time)</NICK>
+<BLURB>Interleave between streams in nanoseconds.</BLURB>
+<DEFAULT>250000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::max-raw-audio-drift</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Raw Audio Drift</NICK>
+<BLURB>Maximum allowed drift of raw audio samples vs. timestamps in nanoseconds.</BLURB>
+<DEFAULT>40000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMP4Mux::reserved-prefill</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reserved Prefill Samples Table</NICK>
+<BLURB>Prefill samples table of reserved duration.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::dts-method</NAME>
+<TYPE>GstQTMuxDtsMethods</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>dts-method</NICK>
+<BLURB>Method to determine DTS time (DEPRECATED).</BLURB>
+<DEFAULT>reorder</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::faststart</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Format file to faststart</NICK>
+<BLURB>If the file should be formatted for faststart (headers first).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::faststart-file</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>File to use for storing buffers</NICK>
+<BLURB>File that will be used temporarily to store data from the stream when creating a faststart file. If null a filepath will be created automatically.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::fragment-duration</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Fragment duration</NICK>
+<BLURB>Fragment durations in ms (produce a fragmented file if > 0).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::moov-recovery-file</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>File to store data for posterior moov atom recovery</NICK>
+<BLURB>File to be used to store data for moov atom making movie file recovery possible in case of a crash during muxing. Null for disabled. (Experimental).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::movie-timescale</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Movie timescale</NICK>
+<BLURB>Timescale to use in the movie (units per second, 0 == default).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::presentation-time</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Include presentation-time info</NICK>
+<BLURB>Calculate and include presentation/composition time (in addition to decoding time).</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::streamable</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Streamable</NICK>
+<BLURB>If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written. (DEPRECATED, only valid for fragmented MP4).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::trak-timescale</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Track timescale</NICK>
+<BLURB>Timescale to use for the tracks (units per second, 0 is automatic).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::reserved-bytes-per-sec</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 10000</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reserved MOOV bytes per second, per track</NICK>
+<BLURB>Multiplier for converting reserved-max-duration into bytes of header to reserve, per second, per track.</BLURB>
+<DEFAULT>550</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::reserved-duration-remaining</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Report the approximate amount of remaining recording space (ns)</NICK>
+<BLURB>Reports the approximate amount of remaining moov header space reserved using reserved-max-duration.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::reserved-max-duration</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Reserved maximum file duration (ns)</NICK>
+<BLURB>When set to a value > 0, reserves space for index tables at the beginning of the file.</BLURB>
+<DEFAULT>18446744073709551615</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::reserved-moov-update-period</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interval at which to update index tables (ns)</NICK>
+<BLURB>When used with reserved-max-duration, periodically updates the index tables with information muxed so far.</BLURB>
+<DEFAULT>18446744073709551615</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::interleave-bytes</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interleave (bytes)</NICK>
+<BLURB>Interleave between streams in bytes.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::interleave-time</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interleave (time)</NICK>
+<BLURB>Interleave between streams in nanoseconds.</BLURB>
+<DEFAULT>250000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::max-raw-audio-drift</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Raw Audio Drift</NICK>
+<BLURB>Maximum allowed drift of raw audio samples vs. timestamps in nanoseconds.</BLURB>
+<DEFAULT>40000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMJ2Mux::reserved-prefill</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reserved Prefill Samples Table</NICK>
+<BLURB>Prefill samples table of reserved duration.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::dts-method</NAME>
+<TYPE>GstQTMuxDtsMethods</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>dts-method</NICK>
+<BLURB>Method to determine DTS time (DEPRECATED).</BLURB>
+<DEFAULT>reorder</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::faststart</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Format file to faststart</NICK>
+<BLURB>If the file should be formatted for faststart (headers first).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::faststart-file</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>File to use for storing buffers</NICK>
+<BLURB>File that will be used temporarily to store data from the stream when creating a faststart file. If null a filepath will be created automatically.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::fragment-duration</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Fragment duration</NICK>
+<BLURB>Fragment durations in ms (produce a fragmented file if > 0).</BLURB>
+<DEFAULT>2000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::moov-recovery-file</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>File to store data for posterior moov atom recovery</NICK>
+<BLURB>File to be used to store data for moov atom making movie file recovery possible in case of a crash during muxing. Null for disabled. (Experimental).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::movie-timescale</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Movie timescale</NICK>
+<BLURB>Timescale to use in the movie (units per second, 0 == default).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::presentation-time</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Include presentation-time info</NICK>
+<BLURB>Calculate and include presentation/composition time (in addition to decoding time).</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::streamable</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Streamable</NICK>
+<BLURB>If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::trak-timescale</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Track timescale</NICK>
+<BLURB>Timescale to use for the tracks (units per second, 0 is automatic).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::reserved-bytes-per-sec</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 10000</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reserved MOOV bytes per second, per track</NICK>
+<BLURB>Multiplier for converting reserved-max-duration into bytes of header to reserve, per second, per track.</BLURB>
+<DEFAULT>550</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::reserved-duration-remaining</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Report the approximate amount of remaining recording space (ns)</NICK>
+<BLURB>Reports the approximate amount of remaining moov header space reserved using reserved-max-duration.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::reserved-max-duration</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Reserved maximum file duration (ns)</NICK>
+<BLURB>When set to a value > 0, reserves space for index tables at the beginning of the file.</BLURB>
+<DEFAULT>18446744073709551615</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::reserved-moov-update-period</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interval at which to update index tables (ns)</NICK>
+<BLURB>When used with reserved-max-duration, periodically updates the index tables with information muxed so far.</BLURB>
+<DEFAULT>18446744073709551615</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::interleave-bytes</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interleave (bytes)</NICK>
+<BLURB>Interleave between streams in bytes.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::interleave-time</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interleave (time)</NICK>
+<BLURB>Interleave between streams in nanoseconds.</BLURB>
+<DEFAULT>250000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::max-raw-audio-drift</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Raw Audio Drift</NICK>
+<BLURB>Maximum allowed drift of raw audio samples vs. timestamps in nanoseconds.</BLURB>
+<DEFAULT>40000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstISMLMux::reserved-prefill</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reserved Prefill Samples Table</NICK>
+<BLURB>Prefill samples table of reserved duration.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::dts-method</NAME>
+<TYPE>GstQTMuxDtsMethods</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>dts-method</NICK>
+<BLURB>Method to determine DTS time (DEPRECATED).</BLURB>
+<DEFAULT>reorder</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::faststart</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Format file to faststart</NICK>
+<BLURB>If the file should be formatted for faststart (headers first).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::faststart-file</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>File to use for storing buffers</NICK>
+<BLURB>File that will be used temporarily to store data from the stream when creating a faststart file. If null a filepath will be created automatically.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::fragment-duration</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Fragment duration</NICK>
+<BLURB>Fragment durations in ms (produce a fragmented file if > 0).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::moov-recovery-file</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>File to store data for posterior moov atom recovery</NICK>
+<BLURB>File to be used to store data for moov atom making movie file recovery possible in case of a crash during muxing. Null for disabled. (Experimental).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::movie-timescale</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Movie timescale</NICK>
+<BLURB>Timescale to use in the movie (units per second, 0 == default).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::presentation-time</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Include presentation-time info</NICK>
+<BLURB>Calculate and include presentation/composition time (in addition to decoding time).</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::streamable</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Streamable</NICK>
+<BLURB>If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written. (DEPRECATED, only valid for fragmented MP4).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::trak-timescale</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Track timescale</NICK>
+<BLURB>Timescale to use for the tracks (units per second, 0 is automatic).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::reserved-bytes-per-sec</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 10000</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reserved MOOV bytes per second, per track</NICK>
+<BLURB>Multiplier for converting reserved-max-duration into bytes of header to reserve, per second, per track.</BLURB>
+<DEFAULT>550</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::reserved-duration-remaining</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Report the approximate amount of remaining recording space (ns)</NICK>
+<BLURB>Reports the approximate amount of remaining moov header space reserved using reserved-max-duration.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::reserved-max-duration</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Reserved maximum file duration (ns)</NICK>
+<BLURB>When set to a value > 0, reserves space for index tables at the beginning of the file.</BLURB>
+<DEFAULT>18446744073709551615</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::reserved-moov-update-period</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interval at which to update index tables (ns)</NICK>
+<BLURB>When used with reserved-max-duration, periodically updates the index tables with information muxed so far.</BLURB>
+<DEFAULT>18446744073709551615</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::interleave-bytes</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interleave (bytes)</NICK>
+<BLURB>Interleave between streams in bytes.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::interleave-time</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interleave (time)</NICK>
+<BLURB>Interleave between streams in nanoseconds.</BLURB>
+<DEFAULT>250000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::max-raw-audio-drift</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Raw Audio Drift</NICK>
+<BLURB>Maximum allowed drift of raw audio samples vs. timestamps in nanoseconds.</BLURB>
+<DEFAULT>40000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>Gst3GPPMux::reserved-prefill</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Reserved Prefill Samples Table</NICK>
+<BLURB>Prefill samples table of reserved duration.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSplitFileSrc::location</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>File Location</NICK>
+<BLURB>Wildcard pattern to match file names of the input files. If the location is an absolute path or contains directory components, only the base file name part will be considered for pattern matching. The results will be sorted.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstMatroskaDemux::max-gap-time</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Maximum gap time</NICK>
+<BLURB>The demuxer sends out segment events for skipping gaps longer than this (0 = disabled).</BLURB>
+<DEFAULT>2000000000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHttpClientSink::automatic-redirect</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>automatic-redirect</NICK>
+<BLURB>Automatically follow HTTP redirects (HTTP Status Code 3xx).</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHttpClientSink::cookies</NAME>
+<TYPE>GStrv</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Cookies</NICK>
+<BLURB>HTTP request cookies.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHttpClientSink::location</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Location</NICK>
+<BLURB>URI to send to.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHttpClientSink::proxy</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Proxy</NICK>
+<BLURB>HTTP proxy server URI.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHttpClientSink::proxy-id</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>proxy-id</NICK>
+<BLURB>user id for proxy authentication.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHttpClientSink::proxy-pw</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>proxy-pw</NICK>
+<BLURB>user password for proxy authentication.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHttpClientSink::session</NAME>
+<TYPE>SoupSession*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>session</NICK>
+<BLURB>SoupSession object to use for communication.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHttpClientSink::user-agent</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>User-Agent</NICK>
+<BLURB>Value of the User-Agent HTTP request header field.</BLURB>
+<DEFAULT>"GStreamer souphttpclientsink "</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHttpClientSink::user-id</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>user-id</NICK>
+<BLURB>user id for authentication.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHttpClientSink::user-pw</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>user-pw</NICK>
+<BLURB>user password for authentication.</BLURB>
+<DEFAULT>""</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHttpClientSink::http-log-level</NAME>
+<TYPE>SoupLoggerLogLevel</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>HTTP log level</NICK>
+<BLURB>Set log level for soup's HTTP session log.</BLURB>
+<DEFAULT>SOUP_LOGGER_LOG_NONE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHttpClientSink::retries</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Retries</NICK>
+<BLURB>Maximum number of retries, zero to disable, -1 to retry forever.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSoupHttpClientSink::retry-delay</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 1</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Retry Delay</NICK>
+<BLURB>Delay in seconds between retries after a failure.</BLURB>
+<DEFAULT>5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstWavParse::ignore-length</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Ignore length</NICK>
+<BLURB>Ignore length from the Wave header.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstGdkPixbufOverlay::location</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>location</NICK>
+<BLURB>Location of image file to overlay.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstGdkPixbufOverlay::offset-x</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>X Offset</NICK>
+<BLURB>For positive value, horizontal offset of overlay image in pixels from left of video image. For negative value, horizontal offset of overlay image in pixels from right of video image.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstGdkPixbufOverlay::offset-y</NAME>
+<TYPE>gint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Y Offset</NICK>
+<BLURB>For positive value, vertical offset of overlay image in pixels from top of video image. For negative value, vertical offset of overlay image in pixels from bottom of video image.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstGdkPixbufOverlay::overlay-height</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Overlay Height</NICK>
+<BLURB>Height of overlay image in pixels (0 = same as overlay image).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstGdkPixbufOverlay::overlay-width</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Overlay Width</NICK>
+<BLURB>Width of overlay image in pixels (0 = same as overlay image).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstGdkPixbufOverlay::relative-x</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Relative X Offset</NICK>
+<BLURB>Horizontal offset of overlay image in fractions of video image width, from top-left corner of video image (in relative positioning).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstGdkPixbufOverlay::relative-y</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Relative Y Offset</NICK>
+<BLURB>Vertical offset of overlay image in fractions of video image height, from top-left corner of video image (in relative positioning).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstGdkPixbufOverlay::alpha</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Alpha</NICK>
+<BLURB>Global alpha of overlay image.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstGdkPixbufOverlay::pixbuf</NAME>
+<TYPE>GdkPixbuf*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Pixbuf</NICK>
+<BLURB>GdkPixbuf object to render.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstGdkPixbufOverlay::positioning-mode</NAME>
+<TYPE>GstGdkPixbufPositioningMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Positioning mode</NICK>
+<BLURB>Positioning mode of offset-x and offset-y properties.</BLURB>
+<DEFAULT>pixels-relative-to-edges</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstGdkPixbufOverlay::coef-x</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Relative X Offset</NICK>
+<BLURB>Horizontal offset of overlay image in fractions of video image width, from top-left corner of video image (absolute positioning).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstGdkPixbufOverlay::coef-y</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-1,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Relative Y Offset</NICK>
+<BLURB>Vertical offset of overlay image in fractions of video image height, from top-left corner of video image (absolute positioning).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::arnr-maxframes</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,15]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>AltRef max frames</NICK>
+<BLURB>AltRef maximum number of frames.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::arnr-strength</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,6]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>AltRef strength</NICK>
+<BLURB>AltRef strength.</BLURB>
+<DEFAULT>3</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::arnr-type</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,3]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>AltRef type</NICK>
+<BLURB>AltRef type.</BLURB>
+<DEFAULT>3</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::auto-alt-ref</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Auto alt reference frames</NICK>
+<BLURB>Automatically generate AltRef frames.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::buffer-initial-size</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Buffer initial size</NICK>
+<BLURB>Initial client buffer size (ms).</BLURB>
+<DEFAULT>4000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::buffer-optimal-size</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Buffer optimal size</NICK>
+<BLURB>Optimal client buffer size (ms).</BLURB>
+<DEFAULT>5000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::buffer-size</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Buffer size</NICK>
+<BLURB>Client buffer size (ms).</BLURB>
+<DEFAULT>6000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::cpu-used</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[-16,16]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>CPU used</NICK>
+<BLURB>CPU used.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::cq-level</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,63]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Constrained quality level</NICK>
+<BLURB>Constrained quality level.</BLURB>
+<DEFAULT>10</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::deadline</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Deadline</NICK>
+<BLURB>Deadline per frame (usec, 0=disabled).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::dropframe-threshold</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Drop Frame Threshold</NICK>
+<BLURB>Temporal resampling threshold (buf %).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::end-usage</NAME>
+<TYPE>GstVP8EncEndUsage</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Rate control mode</NICK>
+<BLURB>Rate control mode.</BLURB>
+<DEFAULT>Variable Bit Rate (VBR) mode</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::error-resilient</NAME>
+<TYPE>GstVP8EncErFlags</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Error resilient</NICK>
+<BLURB>Error resilience flags.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::lag-in-frames</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,25]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Lag in frames</NICK>
+<BLURB>Maximum number of frames to lag.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::max-quantizer</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,63]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Maximum Quantizer</NICK>
+<BLURB>Maximum Quantizer (worst).</BLURB>
+<DEFAULT>63</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::min-quantizer</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,63]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Minimum Quantizer</NICK>
+<BLURB>Minimum Quantizer (best).</BLURB>
+<DEFAULT>4</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::multipass-cache-file</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Multipass Cache File</NICK>
+<BLURB>Multipass cache file. If stream caps reinited, multiple files will be created: file, file.1, file.2, ... and so on.</BLURB>
+<DEFAULT>"multipass.cache"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::multipass-mode</NAME>
+<TYPE>GstVP8EncMultipassMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Multipass Mode</NICK>
+<BLURB>Multipass encode mode.</BLURB>
+<DEFAULT>One pass encoding (default)</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::noise-sensitivity</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,6]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Noise sensitivity</NICK>
+<BLURB>Noise sensisivity (frames to blur).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::resize-allowed</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Resize Allowed</NICK>
+<BLURB>Allow spatial resampling.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::resize-down-threshold</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Resize Down Threshold</NICK>
+<BLURB>Downscale threshold (buf %).</BLURB>
+<DEFAULT>60</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::resize-up-threshold</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Resize Up Threshold</NICK>
+<BLURB>Upscale threshold (buf %).</BLURB>
+<DEFAULT>30</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::sharpness</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,7]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Sharpness</NICK>
+<BLURB>Filter sharpness.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::static-threshold</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Static Threshold</NICK>
+<BLURB>Motion detection threshold.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::target-bitrate</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Target bitrate</NICK>
+<BLURB>Target bitrate (in bits/sec).</BLURB>
+<DEFAULT>256000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::threads</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,64]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Threads</NICK>
+<BLURB>Number of threads to use.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::token-partitions</NAME>
+<TYPE>GstVP8EncTokenPartitions</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Token partitions</NICK>
+<BLURB>Number of token partitions.</BLURB>
+<DEFAULT>One token partition</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::tuning</NAME>
+<TYPE>GstVP8EncTuning</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Tuning</NICK>
+<BLURB>Tuning.</BLURB>
+<DEFAULT>Tune for PSNR</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::horizontal-scaling-mode</NAME>
+<TYPE>GstVP8EncScalingMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Horizontal scaling mode</NICK>
+<BLURB>Horizontal scaling mode.</BLURB>
+<DEFAULT>Normal</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::keyframe-max-dist</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Keyframe max distance</NICK>
+<BLURB>Maximum distance between keyframes (number of frames).</BLURB>
+<DEFAULT>128</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::keyframe-mode</NAME>
+<TYPE>GstVP8EncKfMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Keyframe Mode</NICK>
+<BLURB>Keyframe placement.</BLURB>
+<DEFAULT>Determine optimal placement automatically</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::max-intra-bitrate</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Intra bitrate</NICK>
+<BLURB>Maximum Intra frame bitrate.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::overshoot</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,1000]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Overshoot PCT</NICK>
+<BLURB>Datarate overshoot (max) target (%).</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::temporal-scalability-layer-id</NAME>
+<TYPE>GValueArray*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Coding layer identification</NICK>
+<BLURB>Sequence defining coding layer membership.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::temporal-scalability-number-layers</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,5]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Number of coding layers</NICK>
+<BLURB>Number of coding layers to use.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::temporal-scalability-periodicity</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,16]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Coding layer periodicity</NICK>
+<BLURB>Length of sequence that defines layer membership periodicity.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::temporal-scalability-rate-decimator</NAME>
+<TYPE>GValueArray*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Coding layer rate decimator</NICK>
+<BLURB>Rate decimation factors for each layer.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::temporal-scalability-target-bitrate</NAME>
+<TYPE>GValueArray*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Coding layer target bitrates</NICK>
+<BLURB>Target bitrates for coding layers (one per layer, decreasing).</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::twopass-vbr-bias</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>2-pass VBR bias</NICK>
+<BLURB>CBR/VBR bias (0=CBR, 100=VBR).</BLURB>
+<DEFAULT>50</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::twopass-vbr-maxsection</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>2-pass GOP max bitrate</NICK>
+<BLURB>GOP maximum bitrate (% target).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::twopass-vbr-minsection</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>2-pass GOP min bitrate</NICK>
+<BLURB>GOP minimum bitrate (% target).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::undershoot</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,1000]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Undershoot PCT</NICK>
+<BLURB>Datarate undershoot (min) target (%).</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::vertical-scaling-mode</NAME>
+<TYPE>GstVP8EncScalingMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Vertical scaling mode</NICK>
+<BLURB>Vertical scaling mode.</BLURB>
+<DEFAULT>Normal</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Enc::timebase</NAME>
+<TYPE>GstFraction</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Shortest interframe time</NICK>
+<BLURB>Fraction of one second that is the shortest interframe time - normally left as zero which will default to the framerate.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Dec::deblocking-level</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 16</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Deblocking Level</NICK>
+<BLURB>Deblocking level.</BLURB>
+<DEFAULT>4</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Dec::noise-level</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 16</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Noise Level</NICK>
+<BLURB>Noise level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Dec::post-processing</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Post Processing</NICK>
+<BLURB>Enable post processing.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Dec::post-processing-flags</NAME>
+<TYPE>GstVP8DecPostProcessingFlags</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Post Processing Flags</NICK>
+<BLURB>Flags to control post processing.</BLURB>
+<DEFAULT>Deblock|Demacroblock|Multi-frame quality enhancement</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP8Dec::threads</NAME>
+<TYPE>guint</TYPE>
+<RANGE>[1,16]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Threads</NICK>
+<BLURB>Maximum number of decoding threads.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoMedian::filtersize</NAME>
+<TYPE>GstVideoMedianSize</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Filtersize</NICK>
+<BLURB>The size of the filter.</BLURB>
+<DEFAULT>Median of 5 neighbour pixels</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVideoMedian::lum-only</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Lum Only</NICK>
+<BLURB>Only apply filter on luminance.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstScaletempo::overlap</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Overlap Length</NICK>
+<BLURB>Percentage of stride to overlap.</BLURB>
+<DEFAULT>0.2</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstScaletempo::rate</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[-2.14748e+09,2.14748e+09]</RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Playback Rate</NICK>
+<BLURB>Current playback rate.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstScaletempo::search</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 500</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Search Length</NICK>
+<BLURB>Length in milliseconds to search for best overlap position.</BLURB>
+<DEFAULT>14</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstScaletempo::stride</NAME>
+<TYPE>guint</TYPE>
+<RANGE>[1,5000]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Stride Length</NICK>
+<BLURB>Length in milliseconds to output each stride.</BLURB>
+<DEFAULT>30</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPMux::seqnum</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Sequence number</NICK>
+<BLURB>The RTP sequence number of the last processed packet.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPMux::seqnum-offset</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Sequence number Offset</NICK>
+<BLURB>Offset to add to all outgoing seqnum (-1 = random).</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPMux::ssrc</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>SSRC</NICK>
+<BLURB>The SSRC of the packets (default == random).</BLURB>
+<DEFAULT>4294967295</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPMux::timestamp-offset</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Timestamp Offset</NICK>
+<BLURB>Offset to add to all outgoing timestamps (-1 = random).</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSBCPay::min-frames</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>minimum frame number</NICK>
+<BLURB>Minimum quantity of frames to send in one packet (-1 for maximum allowed by the mtu).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPDTMFSrc::clock-rate</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>clockrate</NICK>
+<BLURB>The clock-rate at which to generate the dtmf packets.</BLURB>
+<DEFAULT>8000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPDTMFSrc::packet-redundancy</NAME>
+<TYPE>guint</TYPE>
+<RANGE>[1,5]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Packet Redundancy</NICK>
+<BLURB>Number of packets to send to indicate start and stop dtmf events.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPDTMFSrc::pt</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 128</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>payload type</NICK>
+<BLURB>The payload type of the packets.</BLURB>
+<DEFAULT>96</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPDTMFSrc::seqnum</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Sequence number</NICK>
+<BLURB>The RTP sequence number of the last processed packet.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPDTMFSrc::seqnum-offset</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Sequence number Offset</NICK>
+<BLURB>Offset to add to all outgoing seqnum (-1 = random).</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPDTMFSrc::ssrc</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>SSRC</NICK>
+<BLURB>The SSRC of the packets (-1 == random).</BLURB>
+<DEFAULT>4294967295</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPDTMFSrc::timestamp</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Timestamp</NICK>
+<BLURB>The RTP timestamp of the last processed packet.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPDTMFSrc::timestamp-offset</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= G_MAXULONG</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Timestamp Offset</NICK>
+<BLURB>Offset to add to all outgoing timestamps (-1 = random).</BLURB>
+<DEFAULT>-1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpDTMFDepay::max-duration</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Maximum duration</NICK>
+<BLURB>The maxumimum duration (ms) of the outgoing soundpacket. (0 = no limit).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpDTMFDepay::unit-time</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 1000</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Duration unittime</NICK>
+<BLURB>The smallest unit (ms) the duration must be a multiple of (0 disables it).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstDTMFSrc::interval</NAME>
+<TYPE>guint</TYPE>
+<RANGE>[10,50]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Interval between tone packets</NICK>
+<BLURB>Interval in ms between two tone packets.</BLURB>
+<DEFAULT>50</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpVorbisPay::config-interval</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 3600</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Config Send Interval</NICK>
+<BLURB>Send Config Insertion Interval in seconds (configuration headers will be multiplexed in the data stream when detected.) (0 = disabled).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPRtxQueue::max-size-packets</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Size Packets</NICK>
+<BLURB>Amount of packets to queue (0 = unlimited).</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPRtxQueue::max-size-time</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Size Times</NICK>
+<BLURB>Amount of ms to queue (0 = unlimited).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPRtxQueue::fulfilled-requests</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Fulfilled Requests</NICK>
+<BLURB>Number of fulfilled retransmission requests.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRTPRtxQueue::requests</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>r</FLAGS>
+<NICK>Requests</NICK>
+<BLURB>Total number of retransmission requests.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpGSTPay::config-interval</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 3600</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Caps/Tags Send Interval</NICK>
+<BLURB>Interval for sending caps and TAG events in seconds (0 = disabled).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpVP8Pay::picture-id-mode</NAME>
+<TYPE>GstVP8RTPPayMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Picture ID Mode</NICK>
+<BLURB>The picture ID mode for payloading.</BLURB>
+<DEFAULT>No Picture ID</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::arnr-maxframes</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,15]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>AltRef max frames</NICK>
+<BLURB>AltRef maximum number of frames.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::arnr-strength</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,6]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>AltRef strength</NICK>
+<BLURB>AltRef strength.</BLURB>
+<DEFAULT>3</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::arnr-type</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,3]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>AltRef type</NICK>
+<BLURB>AltRef type.</BLURB>
+<DEFAULT>3</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::auto-alt-ref</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Auto alt reference frames</NICK>
+<BLURB>Automatically generate AltRef frames.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::buffer-initial-size</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Buffer initial size</NICK>
+<BLURB>Initial client buffer size (ms).</BLURB>
+<DEFAULT>4000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::buffer-optimal-size</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Buffer optimal size</NICK>
+<BLURB>Optimal client buffer size (ms).</BLURB>
+<DEFAULT>5000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::buffer-size</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Buffer size</NICK>
+<BLURB>Client buffer size (ms).</BLURB>
+<DEFAULT>6000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::cpu-used</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[-16,16]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>CPU used</NICK>
+<BLURB>CPU used.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::cq-level</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,63]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Constrained quality level</NICK>
+<BLURB>Constrained quality level.</BLURB>
+<DEFAULT>10</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::deadline</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Deadline</NICK>
+<BLURB>Deadline per frame (usec, 0=disabled).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::dropframe-threshold</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Drop Frame Threshold</NICK>
+<BLURB>Temporal resampling threshold (buf %).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::end-usage</NAME>
+<TYPE>GstVP9EncEndUsage</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Rate control mode</NICK>
+<BLURB>Rate control mode.</BLURB>
+<DEFAULT>Variable Bit Rate (VBR) mode</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::error-resilient</NAME>
+<TYPE>GstVP9EncErFlags</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Error resilient</NICK>
+<BLURB>Error resilience flags.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::horizontal-scaling-mode</NAME>
+<TYPE>GstVP9EncScalingMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Horizontal scaling mode</NICK>
+<BLURB>Horizontal scaling mode.</BLURB>
+<DEFAULT>Normal</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::keyframe-max-dist</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Keyframe max distance</NICK>
+<BLURB>Maximum distance between keyframes (number of frames).</BLURB>
+<DEFAULT>128</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::keyframe-mode</NAME>
+<TYPE>GstVP9EncKfMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Keyframe Mode</NICK>
+<BLURB>Keyframe placement.</BLURB>
+<DEFAULT>Determine optimal placement automatically</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::lag-in-frames</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,25]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Lag in frames</NICK>
+<BLURB>Maximum number of frames to lag.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::max-intra-bitrate</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Intra bitrate</NICK>
+<BLURB>Maximum Intra frame bitrate.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::max-quantizer</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,63]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Maximum Quantizer</NICK>
+<BLURB>Maximum Quantizer (worst).</BLURB>
+<DEFAULT>63</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::min-quantizer</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,63]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Minimum Quantizer</NICK>
+<BLURB>Minimum Quantizer (best).</BLURB>
+<DEFAULT>4</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::multipass-cache-file</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Multipass Cache File</NICK>
+<BLURB>Multipass cache file. If stream caps reinited, multiple files will be created: file, file.1, file.2, ... and so on.</BLURB>
+<DEFAULT>"multipass.cache"</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::multipass-mode</NAME>
+<TYPE>GstVP9EncMultipassMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Multipass Mode</NICK>
+<BLURB>Multipass encode mode.</BLURB>
+<DEFAULT>One pass encoding (default)</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::noise-sensitivity</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,6]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Noise sensitivity</NICK>
+<BLURB>Noise sensisivity (frames to blur).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::overshoot</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,1000]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Overshoot PCT</NICK>
+<BLURB>Datarate overshoot (max) target (%).</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::resize-allowed</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Resize Allowed</NICK>
+<BLURB>Allow spatial resampling.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::resize-down-threshold</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Resize Down Threshold</NICK>
+<BLURB>Downscale threshold (buf %).</BLURB>
+<DEFAULT>60</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::resize-up-threshold</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Resize Up Threshold</NICK>
+<BLURB>Upscale threshold (buf %).</BLURB>
+<DEFAULT>30</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::sharpness</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,7]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Sharpness</NICK>
+<BLURB>Filter sharpness.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::static-threshold</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Static Threshold</NICK>
+<BLURB>Motion detection threshold.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::target-bitrate</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Target bitrate</NICK>
+<BLURB>Target bitrate (in bits/sec).</BLURB>
+<DEFAULT>256000</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::temporal-scalability-layer-id</NAME>
+<TYPE>GValueArray*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Coding layer identification</NICK>
+<BLURB>Sequence defining coding layer membership.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::temporal-scalability-number-layers</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[1,5]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Number of coding layers</NICK>
+<BLURB>Number of coding layers to use.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::temporal-scalability-periodicity</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,16]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Coding layer periodicity</NICK>
+<BLURB>Length of sequence that defines layer membership periodicity.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::temporal-scalability-rate-decimator</NAME>
+<TYPE>GValueArray*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Coding layer rate decimator</NICK>
+<BLURB>Rate decimation factors for each layer.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::temporal-scalability-target-bitrate</NAME>
+<TYPE>GValueArray*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Coding layer target bitrates</NICK>
+<BLURB>Target bitrates for coding layers (one per layer, decreasing).</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::threads</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,64]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Threads</NICK>
+<BLURB>Number of threads to use.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::timebase</NAME>
+<TYPE>GstFraction</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Shortest interframe time</NICK>
+<BLURB>Fraction of one second that is the shortest interframe time - normally left as zero which will default to the framerate.</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::token-partitions</NAME>
+<TYPE>GstVP9EncTokenPartitions</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Token partitions</NICK>
+<BLURB>Number of token partitions.</BLURB>
+<DEFAULT>One token partition</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::tuning</NAME>
+<TYPE>GstVP9EncTuning</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Tuning</NICK>
+<BLURB>Tuning.</BLURB>
+<DEFAULT>Tune for PSNR</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::twopass-vbr-bias</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,100]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>2-pass VBR bias</NICK>
+<BLURB>CBR/VBR bias (0=CBR, 100=VBR).</BLURB>
+<DEFAULT>50</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::twopass-vbr-maxsection</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>2-pass GOP max bitrate</NICK>
+<BLURB>GOP maximum bitrate (% target).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::twopass-vbr-minsection</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>2-pass GOP min bitrate</NICK>
+<BLURB>GOP minimum bitrate (% target).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::undershoot</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,1000]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Undershoot PCT</NICK>
+<BLURB>Datarate undershoot (min) target (%).</BLURB>
+<DEFAULT>100</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Enc::vertical-scaling-mode</NAME>
+<TYPE>GstVP9EncScalingMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Vertical scaling mode</NICK>
+<BLURB>Vertical scaling mode.</BLURB>
+<DEFAULT>Normal</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Dec::deblocking-level</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 16</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Deblocking Level</NICK>
+<BLURB>Deblocking level.</BLURB>
+<DEFAULT>4</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Dec::noise-level</NAME>
+<TYPE>guint</TYPE>
+<RANGE><= 16</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Noise Level</NICK>
+<BLURB>Noise level.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Dec::post-processing</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Post Processing</NICK>
+<BLURB>Enable post processing.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Dec::post-processing-flags</NAME>
+<TYPE>GstVP9DecPostProcessingFlags</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Post Processing Flags</NICK>
+<BLURB>Flags to control post processing.</BLURB>
+<DEFAULT>Deblock|Demacroblock</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstVP9Dec::threads</NAME>
+<TYPE>guint</TYPE>
+<RANGE>[1,16]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max Threads</NICK>
+<BLURB>Maximum number of decoding threads.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpVRawPay::chunks-per-frame</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 1</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Chunks per Frame</NICK>
+<BLURB>Split and send out each frame in multiple chunks to reduce overhead.</BLURB>
+<DEFAULT>10</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPushFileSrc::applied-rate</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>>= G_MINDOUBLE</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Applied Rate</NICK>
+<BLURB>Applied rate to use in TIME SEGMENT.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPushFileSrc::initial-timestamp</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Initial Timestamp</NICK>
+<BLURB>Initial Buffer Timestamp (if time-segment TRUE).</BLURB>
+<DEFAULT>18446744073709551615</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPushFileSrc::location</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>File Location</NICK>
+<BLURB>Location of the file to read.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPushFileSrc::rate</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>>= G_MINDOUBLE</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Rate</NICK>
+<BLURB>Rate to use in TIME SEGMENT.</BLURB>
+<DEFAULT>1</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPushFileSrc::start-time</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Start Time</NICK>
+<BLURB>Initial Start Time (if time-segment TRUE).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPushFileSrc::stream-time</NAME>
+<TYPE>gint64</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Stream Time</NICK>
+<BLURB>Initial Stream Time (if time-segment TRUE).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstPushFileSrc::time-segment</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Time Segment</NICK>
+<BLURB>Emit TIME SEGMENTS.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSplitMuxSrc::location</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>File Input Pattern</NICK>
+<BLURB>Glob pattern for the location of the files to read.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSplitMuxSink::location</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>File Output Pattern</NICK>
+<BLURB>Format string pattern for the location of the files to write (e.g. video%05d.mp4).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSplitMuxSink::max-size-bytes</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max. size bytes</NICK>
+<BLURB>Max. amount of data per file (in bytes, 0=disable).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSplitMuxSink::max-size-time</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max. size (ns)</NICK>
+<BLURB>Max. amount of time per file (in ns, 0=disable).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSplitMuxSink::mux-overhead</NAME>
+<TYPE>gdouble</TYPE>
+<RANGE>[0,1]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Muxing Overhead</NICK>
+<BLURB>Extra size overhead of muxing (0.02 = 2%).</BLURB>
+<DEFAULT>0.02</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSplitMuxSink::muxer</NAME>
+<TYPE>GstElement*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Muxer</NICK>
+<BLURB>The muxer element to use (NULL = default mp4mux).</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSplitMuxSink::sink</NAME>
+<TYPE>GstElement*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Sink</NICK>
+<BLURB>The sink element (or element chain) to use (NULL = default filesink).</BLURB>
+<DEFAULT></DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSplitMuxSink::max-files</NAME>
+<TYPE>guint</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Max files</NICK>
+<BLURB>Maximum number of files to keep on disk. Once the maximum is reached,old files start to be deleted to make room for new ones.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSplitMuxSink::send-keyframe-requests</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Request keyframes at max-size-time</NICK>
+<BLURB>Request a keyframe every max-size-time ns to try splitting at that point. Needs max-size-bytes to be 0 in order to be effective.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSplitMuxSink::max-size-timecode</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Maximum timecode difference</NICK>
+<BLURB>Maximum difference in timecode between first and last frame. Separator is assumed to be ":" everywhere (e.g. 01:00:00:00). Will only be effective if a timecode track is present.</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSplitMuxSink::alignment-threshold</NAME>
+<TYPE>guint64</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Alignment threshold (ns)</NICK>
+<BLURB>Allow non-reference streams to be that many ns before the reference stream.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstSplitMuxSink::use-robust-muxing</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Support robust-muxing mode of some muxers</NICK>
+<BLURB>Check if muxers support robust muxing via the reserved-max-duration and reserved-duration-remaining properties and use them if so. (Only present on qtmux and mp4mux for now). splitmuxsink may then also  create new fragments if the reserved header space is about to overflow. Note this does not set reserved-moov-update-period - apps should do that manually.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpVP9Pay::picture-id-mode</NAME>
+<TYPE>GstVP9RTPPayMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Picture ID Mode</NICK>
+<BLURB>The picture ID mode for payloading.</BLURB>
+<DEFAULT>No Picture ID</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpH265Pay::config-interval</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[G_MAXULONG,3600]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>VPS SPS PPS Send Interval</NICK>
+<BLURB>Send VPS, SPS and PPS Insertion Interval in seconds (sprop parameter sets will be multiplexed in the data stream when detected.) (0 = disabled, -1 = send with every IDR frame).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpH265Pay::sprop-parameter-sets</NAME>
+<TYPE>gchar*</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>sprop-parameter-sets</NICK>
+<BLURB>The base64 sprop-parameter-sets to set in out caps (set to NULL to extract from stream).</BLURB>
+<DEFAULT>NULL</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstLameMP3Enc::bitrate</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[8,320]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Bitrate (kb/s)</NICK>
+<BLURB>Bitrate in kbit/sec (Only valid if target is bitrate, for CBR one of 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256 or 320).</BLURB>
+<DEFAULT>128</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstLameMP3Enc::cbr</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>CBR</NICK>
+<BLURB>Enforce constant bitrate encoding (Only valid if target is bitrate).</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstLameMP3Enc::encoding-engine-quality</NAME>
+<TYPE>GstLameMP3EncEncodingEngineQuality</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Encoding Engine Quality</NICK>
+<BLURB>Quality/speed of the encoding engine, this does not affect the bitrate!.</BLURB>
+<DEFAULT>Standard</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstLameMP3Enc::mono</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Mono</NICK>
+<BLURB>Enforce mono encoding.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstLameMP3Enc::quality</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[0,9.999]</RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Quality</NICK>
+<BLURB>VBR Quality from 0 to 10, 0 being the best (Only valid if target is quality).</BLURB>
+<DEFAULT>4</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstLameMP3Enc::target</NAME>
+<TYPE>GstLameMP3EncTarget</TYPE>
+<RANGE></RANGE>
+<FLAGS>rwx</FLAGS>
+<NICK>Target</NICK>
+<BLURB>Optimize for quality or bitrate.</BLURB>
+<DEFAULT>Quality</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTwoLame::ath-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>ATH Level</NICK>
+<BLURB>ATH Level in dB.</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTwoLame::bitrate</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[8,384]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Bitrate (kb/s)</NICK>
+<BLURB>Bitrate in kbit/sec (8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192, 224, 256, 320, 384).</BLURB>
+<DEFAULT>192</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTwoLame::copyright</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Copyright</NICK>
+<BLURB>Mark as copyright.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTwoLame::emphasis</NAME>
+<TYPE>GstTwoLameEmphasis</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Emphasis</NICK>
+<BLURB>Pre-emphasis to apply to the decoded audio.</BLURB>
+<DEFAULT>No emphasis</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTwoLame::energy-level-extension</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Energy Level Extension</NICK>
+<BLURB>Write peak PCM level to each frame.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTwoLame::error-protection</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Error protection</NICK>
+<BLURB>Adds checksum to every frame.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTwoLame::mode</NAME>
+<TYPE>GstTwoLameMode</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Mode</NICK>
+<BLURB>Encoding mode.</BLURB>
+<DEFAULT>Joint Stereo</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTwoLame::original</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Original</NICK>
+<BLURB>Mark as original.</BLURB>
+<DEFAULT>TRUE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTwoLame::padding</NAME>
+<TYPE>GstTwoLamePadding</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Padding</NICK>
+<BLURB>Padding type.</BLURB>
+<DEFAULT>No Padding</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTwoLame::psymodel</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[G_MAXULONG,4]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Psychoacoustic Model</NICK>
+<BLURB>Psychoacoustic model used to encode the audio.</BLURB>
+<DEFAULT>3</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTwoLame::quick-mode</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Quick mode</NICK>
+<BLURB>Calculate Psymodel every frames.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTwoLame::quick-mode-count</NAME>
+<TYPE>gint</TYPE>
+<RANGE>>= 0</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Quick mode count</NICK>
+<BLURB>Calculate Psymodel every n frames.</BLURB>
+<DEFAULT>10</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTwoLame::vbr</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>VBR</NICK>
+<BLURB>Enable variable bitrate mode.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTwoLame::vbr-level</NAME>
+<TYPE>gfloat</TYPE>
+<RANGE>[-10,10]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>VBR Level</NICK>
+<BLURB>VBR Level.</BLURB>
+<DEFAULT>5</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstTwoLame::vbr-max-bitrate</NAME>
+<TYPE>gint</TYPE>
+<RANGE>[0,384]</RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>VBR max bitrate</NICK>
+<BLURB>Specify maximum VBR bitrate (0=off, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192, 224, 256, 320, 384).</BLURB>
+<DEFAULT>0</DEFAULT>
+</ARG>
+
+<ARG>
+<NAME>GstRtpSbcDepay::ignore-timestamps</NAME>
+<TYPE>gboolean</TYPE>
+<RANGE></RANGE>
+<FLAGS>rw</FLAGS>
+<NICK>Ignore Timestamps</NICK>
+<BLURB>Various statistics.</BLURB>
+<DEFAULT>FALSE</DEFAULT>
+</ARG>
+
diff --git a/docs/plugins/gst-plugins-good-plugins.hierarchy b/docs/plugins/gst-plugins-good-plugins.hierarchy
new file mode 100644
index 0000000..82bd3d7
--- /dev/null
+++ b/docs/plugins/gst-plugins-good-plugins.hierarchy
@@ -0,0 +1,371 @@
+GObject
+  GIOStream
+    GTlsConnection
+  GInitiallyUnowned
+    GstObject
+      GstAllocator
+        GstAllocatorSysmem
+      GstAudioRingBuffer
+        GstAudioSinkRingBuffer
+        GstAudioSrcRingBuffer
+        GstJackAudioSinkRingBuffer
+        GstJackAudioSrcRingBuffer
+      GstBus
+      GstClock
+        GstSystemClock
+          GstAudioClock
+      GstControlBinding
+      GstControlSource
+      GstDeviceProvider
+        GstPulseDeviceProvider
+        GstV4l2DeviceProvider
+      GstElement
+        Gst3GPPMux
+        GstAggregator
+          GstFlvMux
+        GstAsteriskh263
+        GstAuParse
+        GstAudioDecoder
+          GstALawDec
+          GstFlacDec
+          GstMpg123AudioDec
+          GstMuLawDec
+          GstSpeexDec
+          GstWavpackDec
+        GstAudioEncoder
+          GstALawEnc
+          GstFlacEnc
+          GstLameMP3Enc
+          GstMuLawEnc
+          GstSpeexEnc
+          GstTwoLame
+          GstWavpackEnc
+        GstAudioVisualizer
+          GstGoom
+          GstGoom2k1
+        GstAviDemux
+        GstAviMux
+        GstAviSubtitle
+        GstBaseParse
+          GstAacParse
+          GstAc3Parse
+          GstAmrParse
+          GstDcaParse
+          GstFlacParse
+          GstMpegAudioParse
+          GstRtpStreamDepay
+          GstSbcParse
+          GstWavpackParse
+        GstBaseSink
+          GstAudioBaseSink
+            GstAudioSink
+              GstOss4Sink
+              GstOssSink
+            GstJackAudioSink
+            GstPulseSink
+          GstCACASink
+          GstDynUDPSink
+          GstMultiFileSink
+          GstMultiUDPSink
+            GstUDPSink
+          GstShout2send
+          GstSoupHttpClientSink
+          GstTest
+          GstVideoSink
+            GstAASink
+            GstGdkPixbufSink
+            GstV4l2Sink
+        GstBaseSrc
+          GstDTMFSrc
+          GstPushSrc
+            GstAudioBaseSrc
+              GstAudioSrc
+                GstOss4Source
+                GstOssSrc
+                GstPulseSrc
+              GstJackAudioSrc
+            GstDV1394Src
+            GstHDV1394Src
+            GstMultiFileSrc
+            GstSoupHTTPSrc
+            GstUDPSrc
+            GstV4l2Src
+            GstXImageSrc
+          GstRTPDTMFSrc
+          GstSplitFileSrc
+        GstBaseTransform
+          GstAudioFilter
+            GstAudioAmplify
+            GstAudioDynamic
+            GstAudioEcho
+            GstAudioFXBaseFIRFilter
+              GstAudioFIRFilter
+              GstAudioWSincBand
+              GstAudioWSincLimit
+            GstAudioFXBaseIIRFilter
+              GstAudioChebBand
+              GstAudioChebLimit
+              GstAudioIIRFilter
+            GstAudioInvert
+            GstAudioKaraoke
+            GstIirEqualizer
+              GstIirEqualizer10Bands
+              GstIirEqualizer3Bands
+              GstIirEqualizerNBands
+            GstSpectrum
+          GstAudioPanorama
+          GstBreakMyData
+          GstCapsSetter
+          GstCpuReport
+          GstLevel
+          GstNavSeek
+          GstProgressReport
+          GstRgAnalysis
+          GstRgLimiter
+          GstScaletempo
+          GstTagInject
+          GstVideoFilter
+            GstAgingTV
+            GstAlpha
+            GstAlphaColor
+            GstCairoOverlay
+            GstDiceTV
+            GstEdgeTV
+            GstGamma
+            GstGdkPixbufOverlay
+            GstNavigationtest
+            GstOpTV
+            GstQuarkTV
+            GstRadioacTV
+            GstRevTV
+            GstRippleTV
+            GstSMPTEAlpha
+            GstShagadelicTV
+            GstStreakTV
+            GstVertigoTV
+            GstVideoBalance
+            GstVideoBox
+            GstVideoCrop
+            GstVideoFlip
+            GstVideoMedian
+            GstWarpTV
+        GstBin
+          GstAspectRatioCrop
+          GstAutoDetect
+            GstAutoAudioSink
+            GstAutoAudioSrc
+            GstAutoVideoSink
+            GstAutoVideoSrc
+          GstPipeline
+            GstQTMoovRecover
+          GstPushFileSrc
+          GstRTSPSrc
+          GstRgVolume
+          GstRtpBin
+          GstSplitMuxSink
+          GstSplitMuxSrc
+        GstCutter
+        GstDVDec
+        GstDVDemux
+        GstDeinterlace
+        GstDeinterleave
+        GstFlacTag
+        GstFlvDemux
+        GstFlxDec
+        GstGdkPixbufDec
+        GstICYDemux
+        GstISMLMux
+        GstImageFreeze
+        GstInterleave
+        GstMJ2Mux
+        GstMP4Mux
+        GstMatroskaDemux
+        GstMatroskaMux
+          GstWebMMux
+        GstMatroskaParse
+        GstMultipartDemux
+        GstMultipartMux
+        GstQTDemux
+        GstQTMux
+        GstRTPBaseDepayload
+          GstRTPBVDepay
+          GstRTPDVDepay
+          GstRTPGSMDepay
+          GstRTPOpusDepay
+          GstRTPSirenDepay
+          GstRTPiLBCDepay
+          GstRtpAC3Depay
+          GstRtpAMRDepay
+          GstRtpCELTDepay
+          GstRtpDTMFDepay
+          GstRtpG722Depay
+          GstRtpG723Depay
+          GstRtpG726Depay
+          GstRtpG729Depay
+          GstRtpGSTDepay
+          GstRtpH261Depay
+          GstRtpH263Depay
+          GstRtpH263PDepay
+          GstRtpH264Depay
+          GstRtpH265Depay
+          GstRtpJ2KDepay
+          GstRtpJPEGDepay
+          GstRtpKlvDepay
+          GstRtpL16Depay
+          GstRtpL24Depay
+          GstRtpL8Depay
+          GstRtpMP1SDepay
+          GstRtpMP2TDepay
+          GstRtpMP4ADepay
+          GstRtpMP4GDepay
+          GstRtpMP4VDepay
+          GstRtpMPADepay
+          GstRtpMPARobustDepay
+          GstRtpMPVDepay
+          GstRtpPcmaDepay
+          GstRtpPcmuDepay
+          GstRtpQCELPDepay
+          GstRtpQDM2Depay
+          GstRtpSPEEXDepay
+          GstRtpSV3VDepay
+          GstRtpSbcDepay
+          GstRtpTheoraDepay
+          GstRtpVP8Depay
+          GstRtpVP9Depay
+          GstRtpVRawDepay
+          GstRtpVorbisDepay
+          GstRtpXQTDepay
+        GstRTPBasePayload
+          GstRTPBaseAudioPayload
+            GstRTPBVPay
+            GstRTPILBCPay
+            GstRTPSirenPay
+            GstRtpG722Pay
+            GstRtpG726Pay
+            GstRtpL16Pay
+            GstRtpL24Pay
+            GstRtpL8Pay
+            GstRtpPcmaPay
+            GstRtpPcmuPay
+          GstRTPDVPay
+          GstRTPG723Pay
+          GstRTPG729Pay
+          GstRTPGSMPay
+          GstRTPMP2TPay
+          GstRTPMPVPay
+          GstRtpAC3Pay
+          GstRtpAMRPay
+          GstRtpCELTPay
+          GstRtpGSTPay
+          GstRtpH261Pay
+          GstRtpH263PPay
+          GstRtpH263Pay
+          GstRtpH264Pay
+          GstRtpH265Pay
+          GstRtpJ2KPay
+          GstRtpJPEGPay
+          GstRtpKlvPay
+          GstRtpMP4APay
+          GstRtpMP4GPay
+          GstRtpMP4VPay
+          GstRtpMPAPay
+          GstRtpOPUSPay
+          GstRtpSBCPay
+          GstRtpSPEEXPay
+          GstRtpTheoraPay
+          GstRtpVP8Pay
+          GstRtpVP9Pay
+          GstRtpVRawPay
+          GstRtpVorbisPay
+        GstRTPDec
+        GstRTPMux
+          GstRTPDTMFMux
+        GstRTPRtxQueue
+        GstRndBufferSize
+        GstRtpJitterBuffer
+        GstRtpPtDemux
+        GstRtpRtxReceive
+        GstRtpRtxSend
+        GstRtpSession
+        GstRtpSsrcDemux
+        GstRtpStreamPay
+        GstSMPTE
+        GstShapeWipe
+        GstTagDemux
+          GstApeDemux
+          GstID3Demux
+        GstTagMux
+          GstApev2Mux
+          GstId3v2Mux
+        GstV4l2Radio
+        GstVideoDecoder
+          GstJpegDec
+          GstPngDec
+          GstVPXDec
+            GstVP8Dec
+            GstVP9Dec
+        GstVideoEncoder
+          GstJpegEnc
+          GstPngEnc
+          GstVPXEnc
+            GstVP8Enc
+            GstVP9Enc
+          GstY4mEncode
+        GstVideoMixer2
+        GstWavEnc
+        GstWavParse
+      GstPad
+        GstAggregatorPad
+          GstFlvMuxPad
+        GstInterleavePad
+        GstVideoMixer2Pad
+      GstPadTemplate
+      GstPlugin
+      GstPluginFeature
+        GstDeviceProviderFactory
+        GstDynamicTypeFactory
+        GstElementFactory
+        GstTracerFactory
+        GstTypeFindFactory
+      GstRegistry
+      GstTask
+      GstTaskPool
+  GResolver
+  GSocket
+  GSocketAddress
+    GInetSocketAddress
+      GProxyAddress
+  GSocketClient
+  GSocketControlMessage
+    GstIPPktinfoMessage
+    GstIPV6PktinfoMessage
+  GSocketListener
+    GSocketService
+  GTlsCertificate
+  GTlsDatabase
+  GTlsInteraction
+  GdkPixbuf
+  GstColorBalanceChannel
+  GstTunerChannel
+  GstTunerNorm
+  RTPSession
+  SoupSession
+GInterface
+  GDatagramBased
+  GIcon
+  GInitable
+  GLoadableIcon
+  GProxyResolver
+  GSocketConnectable
+  GTypePlugin
+  GstChildProxy
+  GstColorBalance
+  GstPreset
+  GstStreamVolume
+  GstTagSetter
+  GstTagXmpWriter
+  GstTocSetter
+  GstTuner
+  GstURIHandler
+  GstVideoDirection
+  GstVideoOrientation
diff --git a/docs/plugins/gst-plugins-good-plugins.interfaces b/docs/plugins/gst-plugins-good-plugins.interfaces
new file mode 100644
index 0000000..1c6eca5
--- /dev/null
+++ b/docs/plugins/gst-plugins-good-plugins.interfaces
@@ -0,0 +1,114 @@
+GInetSocketAddress GSocketConnectable
+GProxyAddress GSocketConnectable
+GSocket GInitable
+GSocket GInitable GDatagramBased
+GSocketAddress GSocketConnectable
+GdkPixbuf GIcon
+GdkPixbuf GIcon GLoadableIcon
+Gst3GPPMux GstTagSetter GstTagXmpWriter
+Gst3GPPMux GstTagSetter GstTagXmpWriter GstPreset
+GstALawEnc GstPreset
+GstApev2Mux GstTagSetter
+GstAspectRatioCrop GstChildProxy
+GstAudioEncoder GstPreset
+GstAutoAudioSink GstChildProxy
+GstAutoAudioSrc GstChildProxy
+GstAutoDetect GstChildProxy
+GstAutoVideoSink GstChildProxy
+GstAutoVideoSrc GstChildProxy
+GstAviMux GstTagSetter
+GstBin GstChildProxy
+GstDV1394Src GstURIHandler
+GstDV1394Src GstURIHandler GstPropertyProbe
+GstDeinterlace GstChildProxy
+GstFlacEnc GstPreset GstTagSetter
+GstFlacEnc GstPreset GstTagSetter GstTocSetter
+GstFlacEnc GstTagSetter GstPreset
+GstFlacTag GstTagSetter
+GstFlvMux GstTagSetter
+GstGConfAudioSink GstChildProxy
+GstGConfAudioSrc GstChildProxy
+GstGConfVideoSink GstChildProxy
+GstGConfVideoSrc GstChildProxy
+GstGPPMux GstTagSetter GstTagXmpWriter
+GstHDV1394Src GstURIHandler
+GstHDV1394Src GstURIHandler GstPropertyProbe
+GstHalAudioSink GstChildProxy
+GstHalAudioSrc GstChildProxy
+GstISMLMux GstTagSetter GstTagXmpWriter
+GstISMLMux GstTagSetter GstTagXmpWriter GstPreset
+GstId3v2Mux GstTagSetter
+GstIirEqualizer GstChildProxy
+GstIirEqualizer GstChildProxy GstPreset
+GstIirEqualizer10Bands GstChildProxy GstPreset
+GstIirEqualizer3Bands GstChildProxy GstPreset
+GstIirEqualizerNBands GstChildProxy
+GstIirEqualizerNBands GstChildProxy GstPreset
+GstJpegEnc GstPreset
+GstLameMP3Enc GstPreset
+GstMJ2Mux GstTagSetter GstTagXmpWriter
+GstMJ2Mux GstTagSetter GstTagXmpWriter GstPreset
+GstMP4Mux GstTagSetter GstTagXmpWriter
+GstMP4Mux GstTagSetter GstTagXmpWriter GstPreset
+GstMatroskaMux GstTagSetter
+GstMatroskaMux GstTagSetter GstTocSetter
+GstMuLawEnc GstPreset
+GstOss4Mixer GstImplementsInterface GstMixer GstPropertyProbe
+GstOss4Sink GstStreamVolume
+GstOss4Sink GstStreamVolume GstPropertyProbe
+GstOss4Source GstImplementsInterface GstMixer GstPropertyProbe
+GstOssMixerElement GstImplementsInterface GstMixer
+GstOssSrc GstImplementsInterface GstMixer
+GstPipeline GstChildProxy
+GstPngEnc GstPreset
+GstPulseAudioSink GstChildProxy
+GstPulseMixer GstImplementsInterface GstMixer GstPropertyProbe
+GstPulseMixer GstMixer
+GstPulseSink GstStreamVolume
+GstPulseSink GstStreamVolume GstImplementsInterface GstPropertyProbe
+GstPulseSrc GstImplementsInterface GstMixer GstPropertyProbe
+GstPulseSrc GstMixer GstStreamVolume
+GstPulseSrc GstStreamVolume
+GstPulseSrc GstStreamVolume GstImplementsInterface GstMixer GstPropertyProbe
+GstPushFileSrc GstChildProxy GstURIHandler
+GstQTMoovRecover GstChildProxy
+GstQTMux GstTagSetter GstTagXmpWriter
+GstQTMux GstTagSetter GstTagXmpWriter GstPreset
+GstRTSPSrc GstChildProxy GstURIHandler
+GstRgVolume GstChildProxy
+GstRtpBin GstChildProxy
+GstShout2send GstTagSetter
+GstSoupHTTPSrc GstURIHandler
+GstSpeexEnc GstPreset GstTagSetter
+GstSpeexEnc GstTagSetter GstPreset
+GstSplitFileSrc GstURIHandler
+GstSplitMuxSink GstChildProxy
+GstSplitMuxSrc GstChildProxy GstURIHandler
+GstSwitchSink GstChildProxy
+GstSwitchSrc GstChildProxy
+GstTagLibMux GstTagSetter
+GstTagMux GstTagSetter
+GstTwoLame GstPreset
+GstUDPSink GstURIHandler
+GstUDPSrc GstURIHandler
+GstV4l2Radio GstURIHandler GstImplementsInterface GstTuner GstPropertyProbe
+GstV4l2Radio GstURIHandler GstTuner
+GstV4l2Sink GstImplementsInterface GstXOverlay GstNavigation GstColorBalance GstVideoOrientation GstPropertyProbe
+GstV4l2Sink GstTuner GstColorBalance GstVideoOrientation
+GstV4l2Sink GstTuner GstVideoOverlay GstNavigation GstColorBalance GstVideoOrientation
+GstV4l2Src GstURIHandler GstImplementsInterface GstTuner GstColorBalance GstVideoOrientation GstPropertyProbe
+GstV4l2Src GstURIHandler GstTuner GstColorBalance GstVideoOrientation
+GstVP8Enc GstPreset GstTagSetter
+GstVP9Enc GstPreset GstTagSetter
+GstVPXEnc GstPreset GstTagSetter
+GstVideoBalance GstColorBalance
+GstVideoBalance GstImplementsInterface GstColorBalance
+GstVideoEncoder GstPreset
+GstVideoFlip GstVideoDirection
+GstVideoMixer GstChildProxy
+GstVideoMixer2 GstChildProxy
+GstWavEnc GstTagSetter GstTocSetter
+GstWavpackEnc GstPreset
+GstWebMMux GstTagSetter
+GstWebMMux GstTagSetter GstTocSetter
+GstY4mEncode GstPreset
diff --git a/docs/plugins/gst-plugins-good-plugins.prerequisites b/docs/plugins/gst-plugins-good-plugins.prerequisites
new file mode 100644
index 0000000..5dafa15
--- /dev/null
+++ b/docs/plugins/gst-plugins-good-plugins.prerequisites
@@ -0,0 +1,18 @@
+GDatagramBased GObject
+GIcon GObject
+GInitable GObject
+GLoadableIcon GIcon GObject
+GProxyResolver GObject
+GSocketConnectable GObject
+GstChildProxy GObject
+GstChildProxy GstObject
+GstColorBalance GstImplementsInterface GstElement
+GstImplementsInterface GstElement
+GstMixer GstImplementsInterface GstElement
+GstStreamVolume GObject
+GstTagSetter GstElement
+GstTagXmpWriter GstElement
+GstTocSetter GstElement
+GstTuner GstImplementsInterface GstElement
+GstVideoOrientation GstImplementsInterface GstElement
+GstXOverlay GstImplementsInterface GstElement
diff --git a/docs/plugins/gst-plugins-good-plugins.signals b/docs/plugins/gst-plugins-good-plugins.signals
new file mode 100644
index 0000000..cdc6fbb
--- /dev/null
+++ b/docs/plugins/gst-plugins-good-plugins.signals
@@ -0,0 +1,702 @@
+<SIGNAL>
+<NAME>GstMultiUDPSink::add</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>la</FLAGS>
+GstMultiUDPSink *gstmultiudpsink
+gchar *arg1
+gint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstMultiUDPSink::clear</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>la</FLAGS>
+GstMultiUDPSink *gstmultiudpsink
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstMultiUDPSink::client-added</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstMultiUDPSink *gstmultiudpsink
+gchar *arg1
+gint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstMultiUDPSink::client-removed</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstMultiUDPSink *gstmultiudpsink
+gchar *arg1
+gint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstMultiUDPSink::get-stats</NAME>
+<RETURNS>GstStructure*</RETURNS>
+<FLAGS>la</FLAGS>
+GstMultiUDPSink *gstmultiudpsink
+gchar *arg1
+gint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstMultiUDPSink::remove</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>la</FLAGS>
+GstMultiUDPSink *gstmultiudpsink
+gchar *arg1
+gint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstDynUDPSink::get-stats</NAME>
+<RETURNS>GstStructure*</RETURNS>
+<FLAGS>la</FLAGS>
+GstDynUDPSink *gstdynudpsink
+gchar *arg1
+gint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstShout2send::connection-problem</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>c</FLAGS>
+GstShout2send *gstshout2send
+gint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstDV1394Src::frame-dropped</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstDV1394Src *gstdv1394src
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRTPDec::clear-pt-map</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRTPDec *gstrtpdec
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRTPDec::request-pt-map</NAME>
+<RETURNS>GstCaps*</RETURNS>
+<FLAGS>l</FLAGS>
+GstRTPDec *gstrtpdec
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRTPDec::on-bye-ssrc</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRTPDec *gstrtpdec
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRTPDec::on-bye-timeout</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRTPDec *gstrtpdec
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRTPDec::on-new-ssrc</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRTPDec *gstrtpdec
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRTPDec::on-ssrc-collision</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRTPDec *gstrtpdec
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRTPDec::on-ssrc-validated</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRTPDec *gstrtpdec
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRTPDec::on-timeout</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRTPDec *gstrtpdec
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstAudioFIRFilter::rate-changed</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstAudioFIRFilter *gstaudiofirfilter
+gint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstAudioIIRFilter::rate-changed</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstAudioIIRFilter *gstaudioiirfilter
+gint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::clear-pt-map</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>la</FLAGS>
+GstRtpBin *gstrtpbin
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::get-internal-session</NAME>
+<RETURNS>RTPSession*</RETURNS>
+<FLAGS>la</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::on-bye-ssrc</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::on-bye-timeout</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::on-new-ssrc</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::on-npt-stop</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::on-sender-timeout</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::on-ssrc-active</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::on-ssrc-collision</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::on-ssrc-sdes</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::on-ssrc-validated</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::on-timeout</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::request-pt-map</NAME>
+<RETURNS>GstCaps*</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::reset-sync</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>la</FLAGS>
+GstRtpBin *gstrtpbin
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::payload-type-change</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::new-jitterbuffer</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+GstElement *arg1
+guint  arg2
+guint  arg3
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::request-aux-receiver</NAME>
+<RETURNS>GstElement*</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::request-aux-sender</NAME>
+<RETURNS>GstElement*</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::request-rtcp-decoder</NAME>
+<RETURNS>GstElement*</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::request-rtcp-encoder</NAME>
+<RETURNS>GstElement*</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::request-rtp-decoder</NAME>
+<RETURNS>GstElement*</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::request-rtp-encoder</NAME>
+<RETURNS>GstElement*</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::on-new-sender-ssrc</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::on-sender-ssrc-active</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+guint  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::get-session</NAME>
+<RETURNS>GstElement*</RETURNS>
+<FLAGS>la</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpBin::on-bundled-ssrc</NAME>
+<RETURNS>guint</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpBin *gstrtpbin
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpJitterBuffer::clear-pt-map</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>la</FLAGS>
+GstRtpJitterBuffer *gstrtpjitterbuffer
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpJitterBuffer::handle-sync</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpJitterBuffer *gstrtpjitterbuffer
+GstStructure *arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpJitterBuffer::on-npt-stop</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpJitterBuffer *gstrtpjitterbuffer
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpJitterBuffer::request-pt-map</NAME>
+<RETURNS>GstCaps*</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpJitterBuffer *gstrtpjitterbuffer
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpJitterBuffer::set-active</NAME>
+<RETURNS>guint64</RETURNS>
+<FLAGS>la</FLAGS>
+GstRtpJitterBuffer *gstrtpjitterbuffer
+gboolean  arg1
+guint64  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpPtDemux::clear-pt-map</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>la</FLAGS>
+GstRtpPtDemux *gstrtpptdemux
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpPtDemux::new-payload-type</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpPtDemux *gstrtpptdemux
+guint  arg1
+GstPad *arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpPtDemux::payload-type-change</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpPtDemux *gstrtpptdemux
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpPtDemux::request-pt-map</NAME>
+<RETURNS>GstCaps*</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpPtDemux *gstrtpptdemux
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSession::clear-pt-map</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>a</FLAGS>
+GstRtpSession *gstrtpsession
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSession::on-bye-ssrc</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpSession *gstrtpsession
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSession::on-bye-timeout</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpSession *gstrtpsession
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSession::on-new-ssrc</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpSession *gstrtpsession
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSession::on-sender-timeout</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpSession *gstrtpsession
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSession::on-ssrc-active</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpSession *gstrtpsession
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSession::on-ssrc-collision</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpSession *gstrtpsession
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSession::on-ssrc-sdes</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpSession *gstrtpsession
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSession::on-ssrc-validated</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpSession *gstrtpsession
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSession::on-timeout</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpSession *gstrtpsession
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSession::request-pt-map</NAME>
+<RETURNS>GstCaps*</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpSession *gstrtpsession
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSession::on-new-sender-ssrc</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpSession *gstrtpsession
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSession::on-sender-ssrc-active</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpSession *gstrtpsession
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSsrcDemux::clear-ssrc</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>la</FLAGS>
+GstRtpSsrcDemux *gstrtpssrcdemux
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSsrcDemux::new-ssrc-pad</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpSsrcDemux *gstrtpssrcdemux
+guint  arg1
+GstPad *arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRtpSsrcDemux::removed-ssrc-pad</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstRtpSsrcDemux *gstrtpssrcdemux
+guint  arg1
+GstPad *arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstCairoOverlay::caps-changed</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS></FLAGS>
+GstCairoOverlay *gstcairooverlay
+GstCaps *arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstCairoOverlay::draw</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS></FLAGS>
+GstCairoOverlay *gstcairooverlay
+CairoContext *arg1
+guint64  arg2
+guint64  arg3
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstV4l2Src::prepare-format</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstV4l2Src *gstv4l2src
+gint  arg1
+GstCaps *arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRTSPSrc::handle-request</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS></FLAGS>
+GstRTSPSrc *gstrtspsrc
+gpointer  arg1
+gpointer  arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRTSPSrc::on-sdp</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS></FLAGS>
+GstRTSPSrc *gstrtspsrc
+GstSDPMessage *arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRTSPSrc::select-stream</NAME>
+<RETURNS>gboolean</RETURNS>
+<FLAGS>fc</FLAGS>
+GstRTSPSrc *gstrtspsrc
+guint  arg1
+GstCaps *arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRTSPSrc::new-manager</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>fc</FLAGS>
+GstRTSPSrc *gstrtspsrc
+GstElement *arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRTSPSrc::request-rtcp-key</NAME>
+<RETURNS>GstCaps*</RETURNS>
+<FLAGS>l</FLAGS>
+GstRTSPSrc *gstrtspsrc
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRTSPSrc::accept-certificate</NAME>
+<RETURNS>gboolean</RETURNS>
+<FLAGS>l</FLAGS>
+GstRTSPSrc *gstrtspsrc
+GTlsConnection *arg1
+GTlsCertificate *arg2
+GTlsCertificateFlags  arg3
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstRTSPSrc::before-send</NAME>
+<RETURNS>gboolean</RETURNS>
+<FLAGS>fc</FLAGS>
+GstRTSPSrc *gstrtspsrc
+GstRTSPMessage *arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstSplitMuxSink::format-location</NAME>
+<RETURNS>gchar*</RETURNS>
+<FLAGS>l</FLAGS>
+GstSplitMuxSink *gstsplitmuxsink
+guint  arg1
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstSplitMuxSink::format-location-full</NAME>
+<RETURNS>gchar*</RETURNS>
+<FLAGS>l</FLAGS>
+GstSplitMuxSink *gstsplitmuxsink
+guint  arg1
+GstSample *arg2
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstSplitMuxSink::split-now</NAME>
+<RETURNS>void</RETURNS>
+<FLAGS>l</FLAGS>
+GstSplitMuxSink *gstsplitmuxsink
+</SIGNAL>
+
+<SIGNAL>
+<NAME>GstSplitMuxSrc::format-location</NAME>
+<RETURNS>GStrv</RETURNS>
+<FLAGS>l</FLAGS>
+GstSplitMuxSrc *gstsplitmuxsrc
+</SIGNAL>
+
diff --git a/docs/plugins/gst-plugins-good-plugins.types b/docs/plugins/gst-plugins-good-plugins.types
new file mode 100644
index 0000000..c15b4b4
--- /dev/null
+++ b/docs/plugins/gst-plugins-good-plugins.types
@@ -0,0 +1,4 @@
+#include <gst/gst.h>
+
+type:GstIirEqualizer
+type:GstVideoMixerPad
diff --git a/docs/plugins/inspect/plugin-1394.xml b/docs/plugins/inspect/plugin-1394.xml
new file mode 100644
index 0000000..141c8ce
--- /dev/null
+++ b/docs/plugins/inspect/plugin-1394.xml
@@ -0,0 +1,43 @@
+<plugin>
+  <name>1394</name>
+  <description>Source for video data via IEEE1394 interface</description>
+  <filename>../../ext/raw1394/.libs/libgst1394.so</filename>
+  <basename>libgst1394.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>dv1394src</name>
+      <longname>Firewire (1394) DV video source</longname>
+      <class>Source/Video</class>
+      <description>Source for DV video data from firewire port</description>
+      <author>Erik Walthinsen &lt;omega@temple-baptist.com&gt;, Daniel Fischer &lt;dan@f3c.com&gt;, Wim Taymans &lt;wim@fluendo.com&gt;, Zaheer Abbas Merali &lt;zaheerabbas at merali dot org&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-dv, format=(string){ NTSC, PAL }, systemstream=(boolean)true</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>hdv1394src</name>
+      <longname>Firewire (1394) HDV video source</longname>
+      <class>Source/Video</class>
+      <description>Source for MPEG-TS video data from firewire port</description>
+      <author>Edward Hervey &lt;bilboed@bilboed.com&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/mpegts, systemstream=(boolean)true, packetsize=(int)188</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-aasink.xml b/docs/plugins/inspect/plugin-aasink.xml
new file mode 100644
index 0000000..ea1e388
--- /dev/null
+++ b/docs/plugins/inspect/plugin-aasink.xml
@@ -0,0 +1,28 @@
+<plugin>
+  <name>aasink</name>
+  <description>ASCII Art video sink</description>
+  <filename>../../ext/aalib/.libs/libgstaasink.so</filename>
+  <basename>libgstaasink.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>aasink</name>
+      <longname>ASCII art video sink</longname>
+      <class>Sink/Video</class>
+      <description>An ASCII art videosink</description>
+      <author>Wim Taymans &lt;wim.taymans@chello.be&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)I420, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-alaw.xml b/docs/plugins/inspect/plugin-alaw.xml
new file mode 100644
index 0000000..2eeb0e9
--- /dev/null
+++ b/docs/plugins/inspect/plugin-alaw.xml
@@ -0,0 +1,55 @@
+<plugin>
+  <name>alaw</name>
+  <description>ALaw audio conversion routines</description>
+  <filename>../../gst/law/.libs/libgstalaw.so</filename>
+  <basename>libgstalaw.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>alawdec</name>
+      <longname>A Law audio decoder</longname>
+      <class>Codec/Decoder/Audio</class>
+      <description>Convert 8bit A law to 16bit PCM</description>
+      <author>Zaheer Abbas Merali &lt;zaheerabbas at merali dot org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-alaw, rate=(int)[ 8000, 192000 ], channels=(int)[ 1, 2 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S16LE, layout=(string)interleaved, rate=(int)[ 8000, 192000 ], channels=(int)[ 1, 2 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>alawenc</name>
+      <longname>A Law audio encoder</longname>
+      <class>Codec/Encoder/Audio</class>
+      <description>Convert 16bit PCM to 8bit A law</description>
+      <author>Zaheer Abbas Merali &lt;zaheerabbas at merali dot org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S16LE, layout=(string)interleaved, rate=(int)[ 8000, 192000 ], channels=(int)[ 1, 2 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-alaw, rate=(int)[ 8000, 192000 ], channels=(int)[ 1, 2 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-alpha.xml b/docs/plugins/inspect/plugin-alpha.xml
new file mode 100644
index 0000000..9d923c8
--- /dev/null
+++ b/docs/plugins/inspect/plugin-alpha.xml
@@ -0,0 +1,36 @@
+<plugin>
+  <name>alpha</name>
+  <description>adds an alpha channel to video - constant or via chroma-keying</description>
+  <filename>../../gst/alpha/.libs/libgstalpha.so</filename>
+  <basename>libgstalpha.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>alpha</name>
+      <longname>Alpha filter</longname>
+      <class>Filter/Effect/Video</class>
+      <description>Adds an alpha channel to video - uniform or via chroma-keying</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;
+Edward Hervey &lt;edward.hervey@collabora.co.uk&gt;
+Jan Schmidt &lt;thaytan@noraisin.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, BGRx, xBGR, RGBx, RGB, BGR, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, BGRx, xBGR, RGBx, RGB, BGR, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-alphacolor.xml b/docs/plugins/inspect/plugin-alphacolor.xml
new file mode 100644
index 0000000..011eb2f
--- /dev/null
+++ b/docs/plugins/inspect/plugin-alphacolor.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>alphacolor</name>
+  <description>RGBA from/to AYUV colorspace conversion preserving the alpha channel</description>
+  <filename>../../gst/alpha/.libs/libgstalphacolor.so</filename>
+  <basename>libgstalphacolor.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>alphacolor</name>
+      <longname>Alpha color filter</longname>
+      <class>Filter/Converter/Video</class>
+      <description>ARGB from/to AYUV colorspace conversion preserving the alpha channel</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBA, BGRA, ARGB, ABGR, AYUV }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBA, BGRA, ARGB, ABGR, AYUV }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-apetag.xml b/docs/plugins/inspect/plugin-apetag.xml
new file mode 100644
index 0000000..376527c
--- /dev/null
+++ b/docs/plugins/inspect/plugin-apetag.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>apetag</name>
+  <description>APEv1/2 tag reader</description>
+  <filename>../../gst/apetag/.libs/libgstapetag.so</filename>
+  <basename>libgstapetag.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>apedemux</name>
+      <longname>APE tag demuxer</longname>
+      <class>Codec/Demuxer/Metadata</class>
+      <description>Read and output APE tags while demuxing the contents</description>
+      <author>Tim-Philipp Müller &lt;tim centricular net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-apetag</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-audiofx.xml b/docs/plugins/inspect/plugin-audiofx.xml
new file mode 100644
index 0000000..8529a63
--- /dev/null
+++ b/docs/plugins/inspect/plugin-audiofx.xml
@@ -0,0 +1,286 @@
+<plugin>
+  <name>audiofx</name>
+  <description>Audio effects plugin</description>
+  <filename>../../gst/audiofx/.libs/libgstaudiofx.so</filename>
+  <basename>libgstaudiofx.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>audioamplify</name>
+      <longname>Audio amplifier</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Amplifies an audio stream by a given factor</description>
+      <author>Sebastian Dröge &lt;slomo@circular-chaos.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S8, S16LE, S32LE, F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string){ interleaved, non-interleaved }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S8, S16LE, S32LE, F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string){ interleaved, non-interleaved }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>audiochebband</name>
+      <longname>Band pass &amp; band reject filter</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Chebyshev band pass and band reject filter</description>
+      <author>Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>audiocheblimit</name>
+      <longname>Low pass &amp; high pass filter</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Chebyshev low pass and high pass filter</description>
+      <author>Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>audiodynamic</name>
+      <longname>Dynamic range controller</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Compressor and Expander</description>
+      <author>Sebastian Dröge &lt;slomo@circular-chaos.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, F32LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string){ interleaved, non-interleaved }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, F32LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string){ interleaved, non-interleaved }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>audioecho</name>
+      <longname>Audio echo</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Adds an echo or reverb effect to an audio stream</description>
+      <author>Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>audiofirfilter</name>
+      <longname>Audio FIR filter</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Generic audio FIR filter with custom filter kernel</description>
+      <author>Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>audioiirfilter</name>
+      <longname>Audio IIR filter</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Generic audio IIR filter with custom filter kernel</description>
+      <author>Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>audioinvert</name>
+      <longname>Audio inversion</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Swaps upper and lower half of audio samples</description>
+      <author>Sebastian Dröge &lt;slomo@circular-chaos.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, F32LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string){ interleaved, non-interleaved }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, F32LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string){ interleaved, non-interleaved }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>audiokaraoke</name>
+      <longname>AudioKaraoke</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Removes voice from sound</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, F32LE }, rate=(int)[ 1, 2147483647 ], channels=(int)2, channel-mask=(bitmask)0x0000000000000003, layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, F32LE }, rate=(int)[ 1, 2147483647 ], channels=(int)2, channel-mask=(bitmask)0x0000000000000003, layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>audiopanorama</name>
+      <longname>Stereo positioning</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Positions audio streams in the stereo panorama</description>
+      <author>Stefan Kost &lt;ensonic@users.sf.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, S16LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2 ], layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, S16LE }, rate=(int)[ 1, 2147483647 ], channels=(int)2, layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>audiowsincband</name>
+      <longname>Band pass &amp; band reject filter</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Band pass and band reject windowed sinc filter</description>
+      <author>Thomas Vander Stichele &lt;thomas at apestaart dot org&gt;, Steven W. Smith, Dreamlab Technologies Ltd. &lt;mathis.hofer@dreamlab.net&gt;, Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>audiowsinclimit</name>
+      <longname>Low pass &amp; high pass filter</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Low pass and high pass windowed sinc filter</description>
+      <author>Thomas Vander Stichele &lt;thomas at apestaart dot org&gt;, Steven W. Smith, Dreamlab Technologies Ltd. &lt;mathis.hofer@dreamlab.net&gt;, Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>scaletempo</name>
+      <longname>Scaletempo</longname>
+      <class>Filter/Effect/Rate</class>
+      <description>Sync audio tempo with playback rate</description>
+      <author>Rov Juvano &lt;rovjuvano@users.sourceforge.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)F32LE, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]; audio/x-raw, format=(string)F64LE, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]; audio/x-raw, format=(string)S16LE, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)F32LE, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]; audio/x-raw, format=(string)F64LE, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]; audio/x-raw, format=(string)S16LE, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-audioparsers.xml b/docs/plugins/inspect/plugin-audioparsers.xml
new file mode 100644
index 0000000..af4cd2a
--- /dev/null
+++ b/docs/plugins/inspect/plugin-audioparsers.xml
@@ -0,0 +1,181 @@
+<plugin>
+  <name>audioparsers</name>
+  <description>Parsers for various audio formats</description>
+  <filename>../../gst/audioparsers/.libs/libgstaudioparsers.so</filename>
+  <basename>libgstaudioparsers.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>aacparse</name>
+      <longname>AAC audio stream parser</longname>
+      <class>Codec/Parser/Audio</class>
+      <description>Advanced Audio Coding parser</description>
+      <author>Stefan Kost &lt;stefan.kost@nokia.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/mpeg, mpegversion=(int){ 2, 4 }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/mpeg, framed=(boolean)true, mpegversion=(int){ 2, 4 }, stream-format=(string){ raw, adts, adif, loas }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>ac3parse</name>
+      <longname>AC3 audio stream parser</longname>
+      <class>Codec/Parser/Converter/Audio</class>
+      <description>AC3 parser</description>
+      <author>Tim-Philipp Müller &lt;tim centricular net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-ac3; audio/x-eac3; audio/ac3; audio/x-private1-ac3</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-ac3, framed=(boolean)true, channels=(int)[ 1, 6 ], rate=(int)[ 8000, 48000 ], alignment=(string){ iec61937, frame }; audio/x-eac3, framed=(boolean)true, channels=(int)[ 1, 6 ], rate=(int)[ 8000, 48000 ], alignment=(string){ iec61937, frame }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>amrparse</name>
+      <longname>AMR audio stream parser</longname>
+      <class>Codec/Parser/Audio</class>
+      <description>Adaptive Multi-Rate audio parser</description>
+      <author>Ronald Bultje &lt;rbultje@ronald.bitfreak.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-amr-nb-sh; audio/x-amr-wb-sh</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/AMR, rate=(int)8000, channels=(int)1; audio/AMR-WB, rate=(int)16000, channels=(int)1</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>dcaparse</name>
+      <longname>DTS Coherent Acoustics audio stream parser</longname>
+      <class>Codec/Parser/Audio</class>
+      <description>DCA parser</description>
+      <author>Tim-Philipp Müller &lt;tim centricular net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-dts; audio/x-private1-dts</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-dts, framed=(boolean)true, channels=(int)[ 1, 8 ], rate=(int)[ 8000, 192000 ], depth=(int){ 14, 16 }, endianness=(int){ 1234, 4321 }, block-size=(int)[ 1, 2147483647 ], frame-size=(int)[ 1, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>flacparse</name>
+      <longname>FLAC audio parser</longname>
+      <class>Codec/Parser/Audio</class>
+      <description>Parses audio with the FLAC lossless audio codec</description>
+      <author>Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-flac</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-flac, framed=(boolean)true, channels=(int)[ 1, 8 ], rate=(int)[ 1, 655350 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>mpegaudioparse</name>
+      <longname>MPEG1 Audio Parser</longname>
+      <class>Codec/Parser/Audio</class>
+      <description>Parses and frames mpeg1 audio streams (levels 1-3), provides seek</description>
+      <author>Jan Schmidt &lt;thaytan@mad.scientist.com&gt;,Mark Nauwelaerts &lt;mark.nauwelaerts@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/mpeg, mpegversion=(int)1</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/mpeg, mpegversion=(int)1, layer=(int)[ 1, 3 ], mpegaudioversion=(int)[ 1, 3 ], rate=(int)[ 8000, 48000 ], channels=(int)[ 1, 2 ], parsed=(boolean)true</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>sbcparse</name>
+      <longname>SBC audio parser</longname>
+      <class>Codec/Parser/Audio</class>
+      <description>Parses an SBC bluetooth audio stream</description>
+      <author>Tim-Philipp Müller &lt;tim.muller@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-sbc</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-sbc, parsed=(boolean)true, channels=(int)[ 1, 2 ], rate=(int){ 16000, 32000, 44100, 48000 }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>wavpackparse</name>
+      <longname>Wavpack audio stream parser</longname>
+      <class>Codec/Parser/Audio</class>
+      <description>Wavpack parser</description>
+      <author>Mark Nauwelaerts &lt;mark.nauwelaerts@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-wavpack</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-wavpack, depth=(int)[ 1, 32 ], channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], framed=(boolean)true; audio/x-wavpack-correction, framed=(boolean)true</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-auparse.xml b/docs/plugins/inspect/plugin-auparse.xml
new file mode 100644
index 0000000..d936b8c
--- /dev/null
+++ b/docs/plugins/inspect/plugin-auparse.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>auparse</name>
+  <description>parses au streams</description>
+  <filename>../../gst/auparse/.libs/libgstauparse.so</filename>
+  <basename>libgstauparse.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>auparse</name>
+      <longname>AU audio demuxer</longname>
+      <class>Codec/Demuxer/Audio</class>
+      <description>Parse an .au file into raw audio</description>
+      <author>Erik Walthinsen &lt;omega@cse.ogi.edu&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-au</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S8, S16LE, S16BE, S24LE, S24BE, S32LE, S32BE, F32LE, F32BE, F64LE, F64BE }, rate=(int)[ 8000, 192000 ], channels=(int)1, layout=(string)interleaved; audio/x-raw, format=(string){ S8, S16LE, S16BE, S24LE, S24BE, S32LE, S32BE, F32LE, F32BE, F64LE, F64BE }, rate=(int)[ 8000, 192000 ], channels=(int)2, channel-mask=(bitmask)0x0000000000000003, layout=(string)interleaved; audio/x-alaw, rate=(int)[ 8000, 192000 ], channels=(int)[ 1, 2 ]; audio/x-mulaw, rate=(int)[ 8000, 192000 ], channels=(int)[ 1, 2 ]; audio/x-adpcm, layout=(string){ g721, g722, g723_3, g723_5 }</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-autodetect.xml b/docs/plugins/inspect/plugin-autodetect.xml
new file mode 100644
index 0000000..c028411
--- /dev/null
+++ b/docs/plugins/inspect/plugin-autodetect.xml
@@ -0,0 +1,73 @@
+<plugin>
+  <name>autodetect</name>
+  <description>Plugin contains auto-detection plugins for video/audio in- and outputs</description>
+  <filename>../../gst/autodetect/.libs/libgstautodetect.so</filename>
+  <basename>libgstautodetect.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>autoaudiosink</name>
+      <longname>Auto audio sink</longname>
+      <class>Sink/Audio</class>
+      <description>Wrapper audio sink for automatically detected audio sink</description>
+      <author>Jan Schmidt &lt;thaytan@noraisin.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>autoaudiosrc</name>
+      <longname>Auto audio source</longname>
+      <class>Source/Audio</class>
+      <description>Wrapper audio source for automatically detected audio source</description>
+      <author>Jan Schmidt &lt;thaytan@noraisin.net&gt;, Stefan Kost &lt;ensonic@users.sf.net&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>autovideosink</name>
+      <longname>Auto video sink</longname>
+      <class>Sink/Video</class>
+      <description>Wrapper video sink for automatically detected video sink</description>
+      <author>Jan Schmidt &lt;thaytan@noraisin.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>autovideosrc</name>
+      <longname>Auto video source</longname>
+      <class>Source/Video</class>
+      <description>Wrapper video source for automatically detected video source</description>
+      <author>Jan Schmidt &lt;thaytan@noraisin.net&gt;, Stefan Kost &lt;ensonic@users.sf.net&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-avi.xml b/docs/plugins/inspect/plugin-avi.xml
new file mode 100644
index 0000000..13b09b7
--- /dev/null
+++ b/docs/plugins/inspect/plugin-avi.xml
@@ -0,0 +1,100 @@
+<plugin>
+  <name>avi</name>
+  <description>AVI stream handling</description>
+  <filename>../../gst/avi/.libs/libgstavi.so</filename>
+  <basename>libgstavi.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>avidemux</name>
+      <longname>Avi demuxer</longname>
+      <class>Codec/Demuxer</class>
+      <description>Demultiplex an avi file into audio and video</description>
+      <author>Erik Walthinsen &lt;omega@cse.ogi.edu&gt;, Wim Taymans &lt;wim.taymans@chello.be&gt;, Thijs Vermeir &lt;thijsvermeir@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-msvideo</details>
+        </caps>
+        <caps>
+          <name>audio_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>audio/ms-gsm; audio/mpeg, mpegversion=(int)1, layer=(int)3; audio/mpeg, mpegversion=(int)1, layer=(int)2; audio/x-raw, format=(string){ S8, U8, S16LE, U16LE, S24LE, U24LE, S32LE, U32LE }, layout=(string)interleaved; audio/x-vorbis; audio/x-ac3; audio/x-dts; audio/mpeg, mpegversion=(int)4; audio/x-alaw; audio/x-mulaw; audio/x-wms, bitrate=(int)[ 0, 2147483647 ], block_align=(int)[ 1, 2147483647 ]; audio/x-adpcm, layout=(string)microsoft, block_align=(int)[ 1, 2147483647 ]; audio/x-adpcm, layout=(string)dvi, block_align=(int)[ 1, 2147483647 ]; audio/x-truespeech; audio/x-wma, wmaversion=(int)1, bitrate=(int)[ 0, 2147483647 ], block_align=(int)[ 1, 2147483647 ]; audio/x-wma, wmaversion=(int)2, bitrate=(int)[ 0, 2147483647 ], block_align=(int)[ 1, 2147483647 ]; audio/x-wma, wmaversion=(int)3, bitrate=(int)[ 0, 2147483647 ], block_align=(int)[ 1, 2147483647 ]; audio/x-vnd.sony.atrac3; audio/x-raw, format=(string){ F32LE, F64LE }, layout=(string)interleaved; audio/x-voxware, voxwaretype=(int)117; audio/x-adpcm, layout=(string)dk4; audio/x-adpcm, layout=(string)dk3; audio/x-adpcm, layout=(string)dvi; audio/AMR; audio/AMR-WB; audio/x-siren; application/x-ogg-avi; audio/x-avi-unknown</details>
+        </caps>
+        <caps>
+          <name>subpicture_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>subpicture/x-xsub</details>
+        </caps>
+        <caps>
+          <name>subtitle_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>application/x-subtitle-avi</details>
+        </caps>
+        <caps>
+          <name>video_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>video/mpeg, mpegversion=(int)4, systemstream=(boolean)false, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-asus, asusversion=(int)1, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-asus, asusversion=(int)2, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-cirrus-logic-accupak, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-camstudio, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-compressed-yuv, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-raw, format=(string){ RGB8P, BGR, BGRx }, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-divx, divxversion=(int)3, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-divx, divxversion=(int)4, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-truemotion, trueversion=(int)1, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-dv, systemstream=(boolean)false, dvversion=(int)25, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-dv, systemstream=(boolean)false, dvversion=(int)50, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-divx, divxversion=(int)5, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/mpeg, mpegversion=(int)4, systemstream=(boolean)false, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-flash-video, flvversion=(int)1, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-vp6-flash, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-h263, variant=(string)itu, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-h263, variant=(string)lucent, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-h264, variant=(string)itu, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-huffyuv, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-intel-h263, variant=(string)intel, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-raw, format=(string)I420, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-indeo, indeoversion=(int)3, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-indeo, indeoversion=(int)4, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-indeo, indeoversion=(int)5, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-h263, variant=(string)lead, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-h264, variant=(string)lead, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-h263, variant=(string)microsoft, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/mpeg, mpegversion=(int)4, systemstream=(boolean)false, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; image/jpeg, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-msmpeg, msmpegversion=(int)42, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-msmpeg, msmpegversion=(int)43, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/mpeg, systemstream=(boolean)false, mpegversion=(int)1, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/mpeg, systemstream=(boolean)false, mpegversion=(int)2, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-msmpeg, msmpegversion=(int)41, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-mszh, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; image/png, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-rle, layout=(string)microsoft, depth=(int)[ 1, 64 ], framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-indeo, indeoversion=(int)2, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/sp5x, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-truemotion, trueversion=(int)2, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-camtasia, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-ultimotion, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-raw, format=(string)UYVY, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-ati-vcr, vcrversion=(int)1, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-ati-vcr, vcrversion=(int)2, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-h263, variant=(string)vdolive, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-h263, variant=(string)vivo, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-vmnc, version=(int)1, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-vp3, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-h264, variant=(string)videosoft, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-wmv, wmvversion=(int)1, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-wmv, wmvversion=(int)2, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-wmv, wmvversion=(int)3, format=(string)WMV3, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/mpeg, mpegversion=(int)4, systemstream=(boolean)false, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-xan, wcversion=(int)4, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-raw, format=(string)YUY2, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-raw, format=(string)YVU9, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-zlib, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-cinepak, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-h264, variant=(string)itu, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-msvideocodec, msvideoversion=(int)1, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-h263, variant=(string)xirlink, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-dirac, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-ffv, ffvversion=(int)1, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-kmvc, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-vp5, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-vp6, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-vp6-flash, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-vp7, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-vp8, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-mimic, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-apple-video, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-theora, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-fraps, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-aasc, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-raw, format=(string)YV12, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-loco, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-zmbv, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-raw, format=(string)v210, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-raw, format=(string)r210, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]; video/x-dv, systemstream=(boolean)true; video/x-avi-unknown</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>avimux</name>
+      <longname>Avi muxer</longname>
+      <class>Codec/Muxer</class>
+      <description>Muxes audio and video into an avi stream</description>
+      <author>GStreamer maintainers &lt;gstreamer-devel@lists.freedesktop.org&gt;</author>
+      <pads>
+        <caps>
+          <name>audio_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>audio/x-raw, format=(string){ U8, S16LE }, rate=(int)[ 1000, 96000 ], channels=(int)[ 1, 2 ]; audio/mpeg, mpegversion=(int)1, layer=(int)[ 1, 3 ], rate=(int)[ 1000, 96000 ], channels=(int)[ 1, 2 ]; audio/mpeg, mpegversion=(int)4, stream-format=(string)raw, rate=(int)[ 1000, 96000 ], channels=(int)[ 1, 2 ]; audio/x-ac3, rate=(int)[ 1000, 96000 ], channels=(int)[ 1, 6 ]; audio/x-alaw, rate=(int)[ 1000, 48000 ], channels=(int)[ 1, 2 ]; audio/x-mulaw, rate=(int)[ 1000, 48000 ], channels=(int)[ 1, 2 ]; audio/x-wma, rate=(int)[ 1000, 96000 ], channels=(int)[ 1, 2 ], wmaversion=(int)[ 1, 2 ]</details>
+        </caps>
+        <caps>
+          <name>video_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>video/x-raw, format=(string){ YUY2, I420, BGR, BGRx, BGRA, GRAY8, UYVY }, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; image/jpeg, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-divx, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ], divxversion=(int)[ 3, 5 ]; video/x-msmpeg, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ], msmpegversion=(int)[ 41, 43 ]; video/mpeg, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ], mpegversion=(int){ 1, 2, 4 }, systemstream=(boolean)false; video/x-h263, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-h264, stream-format=(string)byte-stream, alignment=(string)au, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-dv, width=(int)720, height=(int){ 576, 480 }, framerate=(fraction)[ 0/1, 2147483647/1 ], systemstream=(boolean)false; video/x-huffyuv, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-wmv, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ], wmvversion=(int)[ 1, 3 ]; image/x-jpc, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-vp8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; image/png, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-msvideo</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>avisubtitle</name>
+      <longname>Avi subtitle parser</longname>
+      <class>Codec/Parser/Subtitle</class>
+      <description>Parse avi subtitle stream</description>
+      <author>Thijs Vermeir &lt;thijsvermeir@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-subtitle-avi</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-subtitle</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-cacasink.xml b/docs/plugins/inspect/plugin-cacasink.xml
new file mode 100644
index 0000000..c3bce0e
--- /dev/null
+++ b/docs/plugins/inspect/plugin-cacasink.xml
@@ -0,0 +1,28 @@
+<plugin>
+  <name>cacasink</name>
+  <description>Colored ASCII Art video sink</description>
+  <filename>../../ext/libcaca/.libs/libgstcacasink.so</filename>
+  <basename>libgstcacasink.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>cacasink</name>
+      <longname>A colored ASCII art video sink</longname>
+      <class>Sink/Video</class>
+      <description>A colored ASCII art videosink</description>
+      <author>Zeeshan Ali &lt;zak147@yahoo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGB, BGR, RGBx, xRGB, BGRx, xBGR, RGB16, RGB15 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-cairo.xml b/docs/plugins/inspect/plugin-cairo.xml
new file mode 100644
index 0000000..97c2a2f
--- /dev/null
+++ b/docs/plugins/inspect/plugin-cairo.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>cairo</name>
+  <description>Cairo-based elements</description>
+  <filename>../../ext/cairo/.libs/libgstcairo.so</filename>
+  <basename>libgstcairo.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>cairooverlay</name>
+      <longname>Cairo overlay</longname>
+      <class>Filter/Editor/Video</class>
+      <description>Render overlay on a video stream using Cairo</description>
+      <author>Jon Nordby &lt;jononor@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ BGRx, BGRA, RGB16 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ BGRx, BGRA, RGB16 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-cutter.xml b/docs/plugins/inspect/plugin-cutter.xml
new file mode 100644
index 0000000..2f0d218
--- /dev/null
+++ b/docs/plugins/inspect/plugin-cutter.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>cutter</name>
+  <description>Audio Cutter to split audio into non-silent bits</description>
+  <filename>../../gst/cutter/.libs/libgstcutter.so</filename>
+  <basename>libgstcutter.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>cutter</name>
+      <longname>Audio cutter</longname>
+      <class>Filter/Editor/Audio</class>
+      <description>Audio Cutter to split audio into non-silent bits</description>
+      <author>Thomas Vander Stichele &lt;thomas at apestaart dot org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S8, S16LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S8, S16LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-debug.xml b/docs/plugins/inspect/plugin-debug.xml
new file mode 100644
index 0000000..d5d91c2
--- /dev/null
+++ b/docs/plugins/inspect/plugin-debug.xml
@@ -0,0 +1,190 @@
+<plugin>
+  <name>debug</name>
+  <description>elements for testing and debugging</description>
+  <filename>../../gst/debugutils/.libs/libgstdebug.so</filename>
+  <basename>libgstdebug.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>breakmydata</name>
+      <longname>Break my data</longname>
+      <class>Testing</class>
+      <description>randomly change data in the stream</description>
+      <author>Benjamin Otte &lt;otte@gnome&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>capssetter</name>
+      <longname>CapsSetter</longname>
+      <class>Generic</class>
+      <description>Set/merge caps on stream</description>
+      <author>Mark Nauwelaerts &lt;mnauw@users.sourceforge.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>cpureport</name>
+      <longname>CPU report</longname>
+      <class>Testing</class>
+      <description>Post cpu usage information every buffer</description>
+      <author>Zaheer Abbas Merali &lt;zaheerabbas at merali dot org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>navseek</name>
+      <longname>Seek based on left-right arrows</longname>
+      <class>Filter/Video</class>
+      <description>Seek based on navigation keys left-right</description>
+      <author>Jan Schmidt &lt;thaytan@mad.scientist.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>progressreport</name>
+      <longname>Progress report</longname>
+      <class>Testing</class>
+      <description>Periodically query and report on processing progress</description>
+      <author>Jan Schmidt &lt;thaytan@mad.scientist.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>pushfilesrc</name>
+      <longname>Push File Source</longname>
+      <class>Testing</class>
+      <description>Implements pushfile:// URI-handler for push-based file access</description>
+      <author>Tim-Philipp Müller &lt;tim centricular net&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rndbuffersize</name>
+      <longname>Random buffer size</longname>
+      <class>Testing</class>
+      <description>pull random sized buffers</description>
+      <author>Stefan Kost &lt;stefan.kost@nokia.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>taginject</name>
+      <longname>TagInject</longname>
+      <class>Generic</class>
+      <description>inject metadata tags</description>
+      <author>Stefan Kost &lt;ensonic@users.sf.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>testsink</name>
+      <longname>Test plugin</longname>
+      <class>Testing</class>
+      <description>perform a number of tests</description>
+      <author>Benjamin Otte &lt;otte@gnome&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-deinterlace.xml b/docs/plugins/inspect/plugin-deinterlace.xml
new file mode 100644
index 0000000..9ec83e6
--- /dev/null
+++ b/docs/plugins/inspect/plugin-deinterlace.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>deinterlace</name>
+  <description>Deinterlacer</description>
+  <filename>../../gst/deinterlace/.libs/libgstdeinterlace.so</filename>
+  <basename>libgstdeinterlace.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>deinterlace</name>
+      <longname>Deinterlacer</longname>
+      <class>Filter/Effect/Video/Deinterlace</class>
+      <description>Deinterlace Methods ported from DScaler/TvTime</description>
+      <author>Martin Eikermann &lt;meiker@upb.de&gt;, Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ AYUV, ARGB, ABGR, RGBA, BGRA, Y444, xRGB, xBGR, RGBx, BGRx, RGB, BGR, YUY2, YVYU, UYVY, Y42B, I420, YV12, Y41B, NV12, NV21 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(ANY), format=(string){ I420, YV12, YUY2, UYVY, AYUV, RGBx, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, RGB, BGR, Y41B, Y42B, YVYU, Y444, v210, v216, NV12, NV21, GRAY8, GRAY16_BE, GRAY16_LE, v308, RGB16, BGR16, RGB15, BGR15, UYVP, A420, RGB8P, YUV9, YVU9, IYU1, ARGB64, AYUV64, r210, I420_10BE, I420_10LE, I422_10BE, I422_10LE, Y444_10BE, Y444_10LE, GBR, GBR_10BE, GBR_10LE, NV16, NV24, NV12_64Z32, A420_10BE, A420_10LE, A422_10BE, A422_10LE, A444_10BE, A444_10LE, NV61, P010_10BE, P010_10LE, IYU2, VYUY, GBRA, GBRA_10BE, GBRA_10LE, GBR_12BE, GBR_12LE, GBRA_12BE, GBRA_12LE, I420_12BE, I420_12LE, I422_12BE, I422_12LE, Y444_12BE, Y444_12LE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ AYUV, ARGB, ABGR, RGBA, BGRA, Y444, xRGB, xBGR, RGBx, BGRx, RGB, BGR, YUY2, YVYU, UYVY, Y42B, I420, YV12, Y41B, NV12, NV21 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(ANY), format=(string){ I420, YV12, YUY2, UYVY, AYUV, RGBx, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, RGB, BGR, Y41B, Y42B, YVYU, Y444, v210, v216, NV12, NV21, GRAY8, GRAY16_BE, GRAY16_LE, v308, RGB16, BGR16, RGB15, BGR15, UYVP, A420, RGB8P, YUV9, YVU9, IYU1, ARGB64, AYUV64, r210, I420_10BE, I420_10LE, I422_10BE, I422_10LE, Y444_10BE, Y444_10LE, GBR, GBR_10BE, GBR_10LE, NV16, NV24, NV12_64Z32, A420_10BE, A420_10LE, A422_10BE, A422_10LE, A444_10BE, A444_10LE, NV61, P010_10BE, P010_10LE, IYU2, VYUY, GBRA, GBRA_10BE, GBRA_10LE, GBR_12BE, GBR_12LE, GBRA_12BE, GBRA_12LE, I420_12BE, I420_12LE, I422_12BE, I422_12LE, Y444_12BE, Y444_12LE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-directsound.xml b/docs/plugins/inspect/plugin-directsound.xml
new file mode 100644
index 0000000..899ccd6
--- /dev/null
+++ b/docs/plugins/inspect/plugin-directsound.xml
@@ -0,0 +1,20 @@
+<plugin>
+  <name>directsound</name>
+  <description>DirectSound plugin</description>
+  <filename>../../win32/vs6/release/libgstdirectsound.dll</filename>
+  <basename>libgstdirectsound.dll</basename>
+  <version>0.10.4.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-bad</source>
+  <package>GStreamer Good Plug-ins CVS</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>directsoundsink</name>
+      <longname>DirectSound audio sink</longname>
+      <class>Sink/Audio</class>
+      <description>DirectSound audio sink</description>
+      <author>Sebastien Moutte &lt;sebastien@moutte.net&gt;</author>
+    </element>
+  </elements>
+</plugin>
diff --git a/docs/plugins/inspect/plugin-dtmf.xml b/docs/plugins/inspect/plugin-dtmf.xml
new file mode 100644
index 0000000..0164845
--- /dev/null
+++ b/docs/plugins/inspect/plugin-dtmf.xml
@@ -0,0 +1,64 @@
+<plugin>
+  <name>dtmf</name>
+  <description>DTMF plugins</description>
+  <filename>../../gst/dtmf/.libs/libgstdtmf.so</filename>
+  <basename>libgstdtmf.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>dtmfsrc</name>
+      <longname>DTMF tone generator</longname>
+      <class>Source/Audio</class>
+      <description>Generates DTMF tones</description>
+      <author>Youness Alaoui &lt;youness.alaoui@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S16LE, rate=(int)[ 1, 2147483647 ], channels=(int)1</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpdtmfdepay</name>
+      <longname>RTP DTMF packet depayloader</longname>
+      <class>Codec/Depayloader/Network</class>
+      <description>Generates DTMF Sound from telephone-event RTP packets</description>
+      <author>Youness Alaoui &lt;youness.alaoui@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)[ 0, 2147483647 ], encoding-name=(string)TELEPHONE-EVENT</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S16LE, rate=(int)[ 1, 2147483647 ], channels=(int)1</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpdtmfsrc</name>
+      <longname>RTP DTMF packet generator</longname>
+      <class>Source/Network</class>
+      <description>Generates RTP DTMF packets</description>
+      <author>Zeeshan Ali &lt;zeeshan.ali@nokia.com&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)[ 0, 2147483647 ], encoding-name=(string)TELEPHONE-EVENT</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-dv.xml b/docs/plugins/inspect/plugin-dv.xml
new file mode 100644
index 0000000..b13950c
--- /dev/null
+++ b/docs/plugins/inspect/plugin-dv.xml
@@ -0,0 +1,61 @@
+<plugin>
+  <name>dv</name>
+  <description>DV demuxer and decoder based on libdv (libdv.sf.net)</description>
+  <filename>../../ext/dv/.libs/libgstdv.so</filename>
+  <basename>libgstdv.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>dvdec</name>
+      <longname>DV video decoder</longname>
+      <class>Codec/Decoder/Video</class>
+      <description>Uses libdv to decode DV video (smpte314) (libdv.sourceforge.net)</description>
+      <author>Erik Walthinsen &lt;omega@cse.ogi.edu&gt;,Wim Taymans &lt;wim@fluendo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-dv, systemstream=(boolean)false</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ YUY2, BGRx, RGB }, framerate=(fraction)[ 1/1, 60/1 ], width=(int)720, height=(int){ 576, 480 }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>dvdemux</name>
+      <longname>DV system stream demuxer</longname>
+      <class>Codec/Demuxer</class>
+      <description>Uses libdv to separate DV audio from DV video (libdv.sourceforge.net)</description>
+      <author>Erik Walthinsen &lt;omega@cse.ogi.edu&gt;, Wim Taymans &lt;wim@fluendo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-dv, systemstream=(boolean)true</details>
+        </caps>
+        <caps>
+          <name>audio</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>audio/x-raw, format=(string)S16LE, layout=(string)interleaved, rate=(int){ 32000, 44100, 48000 }, channels=(int){ 2, 4 }</details>
+        </caps>
+        <caps>
+          <name>video</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>video/x-dv, systemstream=(boolean)false</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-effectv.xml b/docs/plugins/inspect/plugin-effectv.xml
new file mode 100644
index 0000000..3e22adb
--- /dev/null
+++ b/docs/plugins/inspect/plugin-effectv.xml
@@ -0,0 +1,265 @@
+<plugin>
+  <name>effectv</name>
+  <description>effect plugins from the effectv project</description>
+  <filename>../../gst/effectv/.libs/libgsteffectv.so</filename>
+  <basename>libgsteffectv.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>agingtv</name>
+      <longname>AgingTV effect</longname>
+      <class>Filter/Effect/Video</class>
+      <description>AgingTV adds age to video input using scratches and dust</description>
+      <author>Sam Lantinga &lt;slouken@devolution.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ BGRx, RGBx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ BGRx, RGBx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>dicetv</name>
+      <longname>DiceTV effect</longname>
+      <class>Filter/Effect/Video</class>
+      <description>&apos;Dices&apos; the screen up into many small squares</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.be&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBx, xRGB, BGRx, xBGR }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBx, xRGB, BGRx, xBGR }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>edgetv</name>
+      <longname>EdgeTV effect</longname>
+      <class>Filter/Effect/Video</class>
+      <description>Apply edge detect on video</description>
+      <author>Wim Taymans &lt;wim.taymans@chello.be&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ BGRx, RGBx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ BGRx, RGBx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>optv</name>
+      <longname>OpTV effect</longname>
+      <class>Filter/Effect/Video</class>
+      <description>Optical art meets real-time video effect</description>
+      <author>FUKUCHI, Kentarou &lt;fukuchi@users.sourceforge.net&gt;, Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ BGRx, RGBx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ BGRx, RGBx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>quarktv</name>
+      <longname>QuarkTV effect</longname>
+      <class>Filter/Effect/Video</class>
+      <description>Motion dissolver</description>
+      <author>FUKUCHI, Kentarou &lt;fukuchi@users.sourceforge.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ xRGB, xBGR, BGRx, RGBx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ xRGB, xBGR, BGRx, RGBx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>radioactv</name>
+      <longname>RadioacTV effect</longname>
+      <class>Filter/Effect/Video</class>
+      <description>motion-enlightment effect</description>
+      <author>FUKUCHI, Kentarou &lt;fukuchi@users.sourceforge.net&gt;, Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBx, BGRx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBx, BGRx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>revtv</name>
+      <longname>RevTV effect</longname>
+      <class>Filter/Effect/Video</class>
+      <description>A video waveform monitor for each line of video processed</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.be&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ BGRx, RGBx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ BGRx, RGBx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rippletv</name>
+      <longname>RippleTV effect</longname>
+      <class>Filter/Effect/Video</class>
+      <description>RippleTV does ripple mark effect on the video input</description>
+      <author>FUKUCHI, Kentarou &lt;fukuchi@users.sourceforge.net&gt;, Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ BGRx, RGBx, xBGR, xRGB }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ BGRx, RGBx, xBGR, xRGB }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>shagadelictv</name>
+      <longname>ShagadelicTV</longname>
+      <class>Filter/Effect/Video</class>
+      <description>Oh behave, ShagedelicTV makes images shagadelic!</description>
+      <author>Wim Taymans &lt;wim.taymans@chello.be&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)BGRx, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)BGRx, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>streaktv</name>
+      <longname>StreakTV effect</longname>
+      <class>Filter/Effect/Video</class>
+      <description>StreakTV makes after images of moving objects</description>
+      <author>FUKUCHI, Kentarou &lt;fukuchi@users.sourceforge.net&gt;, Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ BGRx, RGBx, xBGR, xRGB }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ BGRx, RGBx, xBGR, xRGB }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>vertigotv</name>
+      <longname>VertigoTV effect</longname>
+      <class>Filter/Effect/Video</class>
+      <description>A loopback alpha blending effector with rotating and scaling</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.be&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBx, BGRx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBx, BGRx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>warptv</name>
+      <longname>WarpTV effect</longname>
+      <class>Filter/Effect/Video</class>
+      <description>WarpTV does realtime goo&apos;ing of the video input</description>
+      <author>Sam Lantinga &lt;slouken@devolution.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBx, xRGB, BGRx, xBGR }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBx, xRGB, BGRx, xBGR }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-equalizer.xml b/docs/plugins/inspect/plugin-equalizer.xml
new file mode 100644
index 0000000..7e6b676
--- /dev/null
+++ b/docs/plugins/inspect/plugin-equalizer.xml
@@ -0,0 +1,76 @@
+<plugin>
+  <name>equalizer</name>
+  <description>GStreamer audio equalizers</description>
+  <filename>../../gst/equalizer/.libs/libgstequalizer.so</filename>
+  <basename>libgstequalizer.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>equalizer-10bands</name>
+      <longname>10 Band Equalizer</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Direct Form 10 band IIR equalizer</description>
+      <author>Stefan Kost &lt;ensonic@users.sf.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, F32LE, F64LE }, rate=(int)[ 1000, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, F32LE, F64LE }, rate=(int)[ 1000, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>equalizer-3bands</name>
+      <longname>3 Band Equalizer</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Direct Form 3 band IIR equalizer</description>
+      <author>Stefan Kost &lt;ensonic@users.sf.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, F32LE, F64LE }, rate=(int)[ 1000, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, F32LE, F64LE }, rate=(int)[ 1000, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>equalizer-nbands</name>
+      <longname>N Band Equalizer</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Direct Form IIR equalizer</description>
+      <author>Benjamin Otte &lt;otte@gnome.org&gt;, Stefan Kost &lt;ensonic@users.sf.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, F32LE, F64LE }, rate=(int)[ 1000, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, F32LE, F64LE }, rate=(int)[ 1000, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-flac.xml b/docs/plugins/inspect/plugin-flac.xml
new file mode 100644
index 0000000..f81a0b0
--- /dev/null
+++ b/docs/plugins/inspect/plugin-flac.xml
@@ -0,0 +1,76 @@
+<plugin>
+  <name>flac</name>
+  <description>The FLAC Lossless compressor Codec</description>
+  <filename>../../ext/flac/.libs/libgstflac.so</filename>
+  <basename>libgstflac.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>flacdec</name>
+      <longname>FLAC audio decoder</longname>
+      <class>Codec/Decoder/Audio</class>
+      <description>Decodes FLAC lossless audio streams</description>
+      <author>Tim-Philipp Müller &lt;tim@centricular.net&gt;, Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-flac, framed=(boolean)true, rate=(int)[ 1, 655350 ], channels=(int)[ 1, 8 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S8, S16LE, S24_32LE, S32LE }, layout=(string)interleaved, rate=(int)[ 1, 655350 ], channels=(int)[ 1, 8 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>flacenc</name>
+      <longname>FLAC audio encoder</longname>
+      <class>Codec/Encoder/Audio</class>
+      <description>Encodes audio with the FLAC lossless audio encoder</description>
+      <author>Wim Taymans &lt;wim.taymans@chello.be&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S8, S16LE, S24LE, S24_32LE }, layout=(string)interleaved, rate=(int)[ 1, 655350 ], channels=(int)1; audio/x-raw, format=(string){ S8, S16LE, S24LE, S24_32LE }, layout=(string)interleaved, rate=(int)[ 1, 655350 ], channels=(int)2, channel-mask=(bitmask)0x0000000000000003; audio/x-raw, format=(string){ S8, S16LE, S24LE, S24_32LE }, layout=(string)interleaved, rate=(int)[ 1, 655350 ], channels=(int)3, channel-mask=(bitmask)0x0000000000000007; audio/x-raw, format=(string){ S8, S16LE, S24LE, S24_32LE }, layout=(string)interleaved, rate=(int)[ 1, 655350 ], channels=(int)4, channel-mask=(bitmask)0x0000000000000033; audio/x-raw, format=(string){ S8, S16LE, S24LE, S24_32LE }, layout=(string)interleaved, rate=(int)[ 1, 655350 ], channels=(int)5, channel-mask=(bitmask)0x0000000000000037; audio/x-raw, format=(string){ S8, S16LE, S24LE, S24_32LE }, layout=(string)interleaved, rate=(int)[ 1, 655350 ], channels=(int)6, channel-mask=(bitmask)0x000000000000003f; audio/x-raw, format=(string){ S8, S16LE, S24LE, S24_32LE }, layout=(string)interleaved, rate=(int)[ 1, 655350 ], channels=(int)7, channel-mask=(bitmask)0x000000000000013f; audio/x-raw, format=(string){ S8, S16LE, S24LE, S24_32LE }, layout=(string)interleaved, rate=(int)[ 1, 655350 ], channels=(int)8, channel-mask=(bitmask)0x0000000000000c3f</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-flac</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>flactag</name>
+      <longname>FLAC tagger</longname>
+      <class>Formatter/Metadata</class>
+      <description>Rewrite tags in a FLAC file</description>
+      <author>Christophe Fergeau &lt;teuf@gnome.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-flac</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-flac</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-flv.xml b/docs/plugins/inspect/plugin-flv.xml
new file mode 100644
index 0000000..c37952e
--- /dev/null
+++ b/docs/plugins/inspect/plugin-flv.xml
@@ -0,0 +1,67 @@
+<plugin>
+  <name>flv</name>
+  <description>FLV muxing and demuxing plugin</description>
+  <filename>../../gst/flv/.libs/libgstflv.so</filename>
+  <basename>libgstflv.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>flvdemux</name>
+      <longname>FLV Demuxer</longname>
+      <class>Codec/Demuxer</class>
+      <description>Demux FLV feeds into digital streams</description>
+      <author>Julien Moutte &lt;julien@moutte.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-flv</details>
+        </caps>
+        <caps>
+          <name>audio</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>audio/x-adpcm, layout=(string)swf, channels=(int){ 1, 2 }, rate=(int){ 5512, 11025, 22050, 44100 }; audio/mpeg, mpegversion=(int)1, layer=(int)3, channels=(int){ 1, 2 }, rate=(int){ 5512, 8000, 11025, 22050, 44100 }, parsed=(boolean)true; audio/mpeg, mpegversion=(int)4, stream-format=(string)raw, framed=(boolean)true; audio/x-nellymoser, channels=(int){ 1, 2 }, rate=(int){ 5512, 8000, 11025, 16000, 22050, 44100 }; audio/x-raw, format=(string){ U8, S16LE }, layout=(string)interleaved, channels=(int){ 1, 2 }, rate=(int){ 5512, 11025, 22050, 44100 }; audio/x-alaw, channels=(int){ 1, 2 }, rate=(int){ 5512, 11025, 22050, 44100 }; audio/x-mulaw, channels=(int){ 1, 2 }, rate=(int){ 5512, 11025, 22050, 44100 }; audio/x-speex, channels=(int)1, rate=(int)16000</details>
+        </caps>
+        <caps>
+          <name>video</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>video/x-flash-video, flvversion=(int)1; video/x-flash-screen; video/x-vp6-flash; video/x-vp6-alpha; video/x-h264, stream-format=(string)avc</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>flvmux</name>
+      <longname>FLV muxer</longname>
+      <class>Codec/Muxer</class>
+      <description>Muxes video/audio streams into a FLV stream</description>
+      <author>Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>audio</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>audio/x-adpcm, layout=(string)swf, channels=(int){ 1, 2 }, rate=(int){ 5512, 11025, 22050, 44100 }; audio/mpeg, mpegversion=(int)1, layer=(int)3, channels=(int){ 1, 2 }, rate=(int){ 5512, 8000, 11025, 22050, 44100 }, parsed=(boolean)true; audio/mpeg, mpegversion=(int){ 4, 2 }, stream-format=(string)raw; audio/x-nellymoser, channels=(int){ 1, 2 }, rate=(int){ 5512, 8000, 11025, 16000, 22050, 44100 }; audio/x-raw, format=(string){ U8, S16LE }, layout=(string)interleaved, channels=(int){ 1, 2 }, rate=(int){ 5512, 11025, 22050, 44100 }; audio/x-alaw, channels=(int){ 1, 2 }, rate=(int){ 5512, 11025, 22050, 44100 }; audio/x-mulaw, channels=(int){ 1, 2 }, rate=(int){ 5512, 11025, 22050, 44100 }; audio/x-speex, channels=(int)1, rate=(int)16000</details>
+        </caps>
+        <caps>
+          <name>video</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>video/x-flash-video; video/x-flash-screen; video/x-vp6-flash; video/x-vp6-alpha; video/x-h264, stream-format=(string)avc</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-flv</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-flxdec.xml b/docs/plugins/inspect/plugin-flxdec.xml
new file mode 100644
index 0000000..a7f310a
--- /dev/null
+++ b/docs/plugins/inspect/plugin-flxdec.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>flxdec</name>
+  <description>FLC/FLI/FLX video decoder</description>
+  <filename>../../gst/flx/.libs/libgstflxdec.so</filename>
+  <basename>libgstflxdec.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>flxdec</name>
+      <longname>FLX video decoder</longname>
+      <class>Codec/Decoder/Video</class>
+      <description>FLC/FLI/FLX video decoder</description>
+      <author>Sepp Wijnands &lt;mrrazz@garbage-coderz.net&gt;, Zeeshan Ali &lt;zeenix@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-fli</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)BGRx, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-gdkpixbuf.xml b/docs/plugins/inspect/plugin-gdkpixbuf.xml
new file mode 100644
index 0000000..58dfbd4
--- /dev/null
+++ b/docs/plugins/inspect/plugin-gdkpixbuf.xml
@@ -0,0 +1,70 @@
+<plugin>
+  <name>gdkpixbuf</name>
+  <description>GdkPixbuf-based image decoder, overlay and sink</description>
+  <filename>../../ext/gdk_pixbuf/.libs/libgstgdkpixbuf.so</filename>
+  <basename>libgstgdkpixbuf.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>gdkpixbufdec</name>
+      <longname>GdkPixbuf image decoder</longname>
+      <class>Codec/Decoder/Image</class>
+      <description>Decodes images in a video stream using GdkPixbuf</description>
+      <author>David A. Schleef &lt;ds@schleef.org&gt;, Renato Filho &lt;renato.filho@indt.org.br&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>image/png; image/x-icon; application/x-navi-animation; image/x-cmu-raster; image/x-sun-raster; image/x-pixmap; image/tiff; image/x-portable-anymap; image/x-portable-bitmap; image/x-portable-graymap; image/x-portable-pixmap; image/bmp; image/x-bmp; image/x-MS-bmp; image/vnd.wap.wbmp; image/x-bitmap; image/x-tga; image/x-pcx; image/svg; image/svg+xml</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)RGB, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>gdkpixbufoverlay</name>
+      <longname>GdkPixbuf Overlay</longname>
+      <class>Filter/Effect/Video</class>
+      <description>Overlay an image onto a video stream</description>
+      <author>Tim-Philipp Müller &lt;tim centricular net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBx, RGB, BGR, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, I420, YV12, AYUV, YUY2, UYVY, v308, v210, v216, Y41B, Y42B, Y444, YVYU, NV12, NV21, UYVP, RGB16, BGR16, RGB15, BGR15, UYVP, A420, YUV9, YVU9, IYU1, ARGB64, AYUV64, r210, I420_10LE, I420_10BE, GRAY8, GRAY16_BE, GRAY16_LE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBx, RGB, BGR, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, I420, YV12, AYUV, YUY2, UYVY, v308, v210, v216, Y41B, Y42B, Y444, YVYU, NV12, NV21, UYVP, RGB16, BGR16, RGB15, BGR15, UYVP, A420, YUV9, YVU9, IYU1, ARGB64, AYUV64, r210, I420_10LE, I420_10BE, GRAY8, GRAY16_BE, GRAY16_LE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>gdkpixbufsink</name>
+      <longname>GdkPixbuf sink</longname>
+      <class>Sink/Video</class>
+      <description>Output images as GdkPixbuf objects in bus messages</description>
+      <author>Tim-Philipp Müller &lt;tim centricular net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)RGB, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-goom.xml b/docs/plugins/inspect/plugin-goom.xml
new file mode 100644
index 0000000..b843181
--- /dev/null
+++ b/docs/plugins/inspect/plugin-goom.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>goom</name>
+  <description>GOOM visualization filter</description>
+  <filename>../../gst/goom/.libs/libgstgoom.so</filename>
+  <basename>libgstgoom.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>goom</name>
+      <longname>GOOM: what a GOOM!</longname>
+      <class>Visualization</class>
+      <description>Takes frames of data and outputs video frames using the GOOM filter</description>
+      <author>Wim Taymans &lt;wim@fluendo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S16LE, rate=(int)[ 8000, 96000 ], channels=(int)1, layout=(string)interleaved; audio/x-raw, format=(string)S16LE, rate=(int)[ 8000, 96000 ], channels=(int)2, channel-mask=(bitmask)0x0000000000000003, layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)BGRx, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-goom2k1.xml b/docs/plugins/inspect/plugin-goom2k1.xml
new file mode 100644
index 0000000..e904479
--- /dev/null
+++ b/docs/plugins/inspect/plugin-goom2k1.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>goom2k1</name>
+  <description>GOOM 2k1 visualization filter</description>
+  <filename>../../gst/goom2k1/.libs/libgstgoom2k1.so</filename>
+  <basename>libgstgoom2k1.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>goom2k1</name>
+      <longname>GOOM: what a GOOM! 2k1 edition</longname>
+      <class>Visualization</class>
+      <description>Takes frames of data and outputs video frames using the GOOM 2k1 filter</description>
+      <author>Wim Taymans &lt;wim@fluendo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S16LE, rate=(int)[ 8000, 96000 ], channels=(int)1, layout=(string)interleaved; audio/x-raw, format=(string)S16LE, rate=(int)[ 8000, 96000 ], channels=(int)2, channel-mask=(bitmask)0x0000000000000003, layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)BGRx, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-icydemux.xml b/docs/plugins/inspect/plugin-icydemux.xml
new file mode 100644
index 0000000..74e20df
--- /dev/null
+++ b/docs/plugins/inspect/plugin-icydemux.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>icydemux</name>
+  <description>Demux ICY tags from a stream</description>
+  <filename>../../gst/icydemux/.libs/libgsticydemux.so</filename>
+  <basename>libgsticydemux.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>icydemux</name>
+      <longname>ICY tag demuxer</longname>
+      <class>Codec/Demuxer/Metadata</class>
+      <description>Read and output ICY tags while demuxing the contents</description>
+      <author>Jan Schmidt &lt;thaytan@mad.scientist.com&gt;, Michael Smith &lt;msmith@fluendo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-icy, metadata-interval=(int)[ 0, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-id3demux.xml b/docs/plugins/inspect/plugin-id3demux.xml
new file mode 100644
index 0000000..c3af37c
--- /dev/null
+++ b/docs/plugins/inspect/plugin-id3demux.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>id3demux</name>
+  <description>Demux ID3v1 and ID3v2 tags from a file</description>
+  <filename>../../gst/id3demux/.libs/libgstid3demux.so</filename>
+  <basename>libgstid3demux.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>id3demux</name>
+      <longname>ID3 tag demuxer</longname>
+      <class>Codec/Demuxer/Metadata</class>
+      <description>Read and output ID3v1 and ID3v2 tags while demuxing the contents</description>
+      <author>Jan Schmidt &lt;thaytan@mad.scientist.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-id3</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-imagefreeze.xml b/docs/plugins/inspect/plugin-imagefreeze.xml
new file mode 100644
index 0000000..3b844a5
--- /dev/null
+++ b/docs/plugins/inspect/plugin-imagefreeze.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>imagefreeze</name>
+  <description>Still frame stream generator</description>
+  <filename>../../gst/imagefreeze/.libs/libgstimagefreeze.so</filename>
+  <basename>libgstimagefreeze.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>imagefreeze</name>
+      <longname>Still frame stream generator</longname>
+      <class>Filter/Video</class>
+      <description>Generates a still frame stream from an image</description>
+      <author>Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-interleave.xml b/docs/plugins/inspect/plugin-interleave.xml
new file mode 100644
index 0000000..4044225
--- /dev/null
+++ b/docs/plugins/inspect/plugin-interleave.xml
@@ -0,0 +1,55 @@
+<plugin>
+  <name>interleave</name>
+  <description>Audio interleaver/deinterleaver</description>
+  <filename>../../gst/interleave/.libs/libgstinterleave.so</filename>
+  <basename>libgstinterleave.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>deinterleave</name>
+      <longname>Audio deinterleaver</longname>
+      <class>Filter/Converter/Audio</class>
+      <description>Splits one interleaved multichannel audio stream into many mono audio streams</description>
+      <author>Andy Wingo &lt;wingo at pobox.com&gt;, Iain &lt;iain@prettypeople.org&gt;, Sebastian Dröge &lt;slomo@circular-chaos.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S8, U8, S16LE, S16BE, U16LE, U16BE, S24_32LE, S24_32BE, U24_32LE, U24_32BE, S32LE, S32BE, U32LE, U32BE, S24LE, S24BE, U24LE, U24BE, S20LE, S20BE, U20LE, U20BE, S18LE, S18BE, U18LE, U18BE, F32LE, F32BE, F64LE, F64BE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>audio/x-raw, format=(string){ S8, U8, S16LE, S16BE, U16LE, U16BE, S24_32LE, S24_32BE, U24_32LE, U24_32BE, S32LE, S32BE, U32LE, U32BE, S24LE, S24BE, U24LE, U24BE, S20LE, S20BE, U20LE, U20BE, S18LE, S18BE, U18LE, U18BE, F32LE, F32BE, F64LE, F64BE }, rate=(int)[ 1, 2147483647 ], channels=(int)1, layout=(string){ non-interleaved, interleaved }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>interleave</name>
+      <longname>Audio interleaver</longname>
+      <class>Filter/Converter/Audio</class>
+      <description>Folds many mono channels into one interleaved audio stream</description>
+      <author>Andy Wingo &lt;wingo at pobox.com&gt;, Sebastian Dröge &lt;slomo@circular-chaos.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>audio/x-raw, rate=(int)[ 1, 2147483647 ], channels=(int)1, format=(string){ S8, U8, S16LE, S16BE, U16LE, U16BE, S24_32LE, S24_32BE, U24_32LE, U24_32BE, S32LE, S32BE, U32LE, U32BE, S24LE, S24BE, U24LE, U24BE, S20LE, S20BE, U20LE, U20BE, S18LE, S18BE, U18LE, U18BE, F32LE, F32BE, F64LE, F64BE }, layout=(string){ non-interleaved, interleaved }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], format=(string){ S8, U8, S16LE, S16BE, U16LE, U16BE, S24_32LE, S24_32BE, U24_32LE, U24_32BE, S32LE, S32BE, U32LE, U32BE, S24LE, S24BE, U24LE, U24BE, S20LE, S20BE, U20LE, U20BE, S18LE, S18BE, U18LE, U18BE, F32LE, F32BE, F64LE, F64BE }, layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-isomp4.xml b/docs/plugins/inspect/plugin-isomp4.xml
new file mode 100644
index 0000000..24b9c7b
--- /dev/null
+++ b/docs/plugins/inspect/plugin-isomp4.xml
@@ -0,0 +1,229 @@
+<plugin>
+  <name>isomp4</name>
+  <description>ISO base media file format support (mp4, 3gpp, qt, mj2)</description>
+  <filename>../../gst/isomp4/.libs/libgstisomp4.so</filename>
+  <basename>libgstisomp4.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>3gppmux</name>
+      <longname>3GPP Muxer</longname>
+      <class>Codec/Muxer</class>
+      <description>Multiplex audio and video into a 3GPP file</description>
+      <author>Thiago Sousa Santos &lt;thiagoss@embedded.ufcg.edu.br&gt;</author>
+      <pads>
+        <caps>
+          <name>audio_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>audio/AMR, rate=(int)8000, channels=(int)[ 1, 2 ]; audio/AMR-WB, rate=(int)16000, channels=(int)[ 1, 2 ]; audio/mpeg, mpegversion=(int)1, layer=(int)3, channels=(int)[ 1, 2 ], rate=(int)[ 1, 2147483647 ]; audio/mpeg, mpegversion=(int)4, stream-format=(string)raw, channels=(int)[ 1, 8 ], rate=(int)[ 1, 2147483647 ]; audio/x-ac3, channels=(int)[ 1, 6 ], rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>subtitle_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>text/x-raw, format=(string)utf8</details>
+        </caps>
+        <caps>
+          <name>video_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>video/x-h263, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/mpeg, mpegversion=(int)4, systemstream=(boolean)false, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-divx, divxversion=(int)5, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-h264, stream-format=(string)avc, alignment=(string)au, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/quicktime, variant=(string)3gpp</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>ismlmux</name>
+      <longname>ISML Muxer</longname>
+      <class>Codec/Muxer</class>
+      <description>Multiplex audio and video into a ISML file</description>
+      <author>Thiago Sousa Santos &lt;thiagoss@embedded.ufcg.edu.br&gt;</author>
+      <pads>
+        <caps>
+          <name>audio_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>audio/mpeg, mpegversion=(int)1, layer=(int)3, channels=(int)[ 1, 2 ], rate=(int)[ 1, 2147483647 ]; audio/mpeg, mpegversion=(int)4, stream-format=(string)raw, channels=(int)[ 1, 8 ], rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>video_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>video/mpeg, mpegversion=(int)4, systemstream=(boolean)false, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-divx, divxversion=(int)5, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-h264, stream-format=(string)avc, alignment=(string)au, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/quicktime, variant=(string)iso-fragmented</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>mj2mux</name>
+      <longname>MJ2 Muxer</longname>
+      <class>Codec/Muxer</class>
+      <description>Multiplex audio and video into a MJ2 file</description>
+      <author>Thiago Sousa Santos &lt;thiagoss@embedded.ufcg.edu.br&gt;</author>
+      <pads>
+        <caps>
+          <name>audio_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>audio/x-raw, format=(string){ S16LE, S16BE, S8, U8 }, layout=(string)interleaved, channels=(int)[ 1, 2 ], rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>video_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>image/x-j2c, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; image/x-jpc, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/mj2</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>mp4mux</name>
+      <longname>MP4 Muxer</longname>
+      <class>Codec/Muxer</class>
+      <description>Multiplex audio and video into a MP4 file</description>
+      <author>Thiago Sousa Santos &lt;thiagoss@embedded.ufcg.edu.br&gt;</author>
+      <pads>
+        <caps>
+          <name>audio_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>audio/mpeg, mpegversion=(int)1, layer=(int)[ 1, 3 ], channels=(int)[ 1, 2 ], rate=(int)[ 1, 2147483647 ]; audio/mpeg, mpegversion=(int)4, stream-format=(string)raw, channels=(int)[ 1, 8 ], rate=(int)[ 1, 2147483647 ]; audio/x-ac3, channels=(int)[ 1, 6 ], rate=(int)[ 1, 2147483647 ]; audio/x-alac, channels=(int)[ 1, 2 ], rate=(int)[ 1, 2147483647 ]; audio/x-opus, channel-mapping-family=(int)[ 0, 255 ], channels=(int)[ 1, 8 ], rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>subtitle_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>text/x-raw, format=(string)utf8</details>
+        </caps>
+        <caps>
+          <name>video_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>video/mpeg, mpegversion=(int)4, systemstream=(boolean)false, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-divx, divxversion=(int)5, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-h264, stream-format=(string)avc, alignment=(string)au, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-h265, stream-format=(string){ hvc1, hev1 }, alignment=(string)au, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-mp4-part, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/quicktime, variant=(string)iso</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>qtdemux</name>
+      <longname>QuickTime demuxer</longname>
+      <class>Codec/Demuxer</class>
+      <description>Demultiplex a QuickTime file into audio and video streams</description>
+      <author>David Schleef &lt;ds@schleef.org&gt;, Wim Taymans &lt;wim@fluendo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/quicktime; video/mj2; audio/x-m4a; application/x-3gp</details>
+        </caps>
+        <caps>
+          <name>audio_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>subtitle_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>video_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>qtmoovrecover</name>
+      <longname>QT Moov Recover</longname>
+      <class>Util</class>
+      <description>Recovers unfinished qtmux files</description>
+      <author>Thiago Santos &lt;thiago.sousa.santos@collabora.co.uk&gt;</author>
+      <pads>
+      </pads>
+    </element>
+    <element>
+      <name>qtmux</name>
+      <longname>QuickTime Muxer</longname>
+      <class>Codec/Muxer</class>
+      <description>Multiplex audio and video into a QuickTime file</description>
+      <author>Thiago Sousa Santos &lt;thiagoss@embedded.ufcg.edu.br&gt;</author>
+      <pads>
+        <caps>
+          <name>audio_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>audio/x-raw, format=(string){ S32LE, S32BE, S24LE, S24BE, S16LE, S16BE, S8, U8 }, layout=(string)interleaved, channels=(int)[ 1, 2 ], rate=(int)[ 1, 2147483647 ]; audio/x-raw, format=(string){ S32LE, S32BE, S24LE, S24BE, S16LE, S16BE, S8, U8 }, layout=(string)interleaved, channel-mask=(bitmask)0x0000000000000000, channels=(int)[ 1, 16 ], rate=(int)[ 1, 2147483647 ]; audio/mpeg, mpegversion=(int)1, layer=(int)[ 1, 3 ], channels=(int)[ 1, 2 ], rate=(int)[ 1, 2147483647 ]; audio/mpeg, mpegversion=(int)4, stream-format=(string)raw, channels=(int)[ 1, 8 ], rate=(int)[ 1, 2147483647 ]; audio/x-ac3, channels=(int)[ 1, 6 ], rate=(int)[ 1, 2147483647 ]; audio/x-adpcm, layout=(string)dvi, block_align=(int)[ 64, 8096 ], channels=(int)[ 1, 2 ], rate=(int)[ 1, 2147483647 ]; audio/x-alaw, channels=(int)[ 1, 2 ], rate=(int)[ 1, 2147483647 ]; audio/x-mulaw, channels=(int)[ 1, 2 ], rate=(int)[ 1, 2147483647 ]; audio/AMR, rate=(int)8000, channels=(int)[ 1, 2 ]; audio/AMR-WB, rate=(int)16000, channels=(int)[ 1, 2 ]; audio/x-alac, channels=(int)[ 1, 2 ], rate=(int)[ 1, 2147483647 ]; audio/x-opus, channel-mapping-family=(int)[ 0, 255 ], channels=(int)[ 1, 8 ], rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>subtitle_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>text/x-raw, format=(string)utf8</details>
+        </caps>
+        <caps>
+          <name>video_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>video/x-raw, format=(string){ RGB, UYVY, v210 }, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/mpeg, mpegversion=(int)4, systemstream=(boolean)false, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-divx, divxversion=(int)5, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-prores, variant=(string){ standard, lt, hq, proxy, 4444, 4444xq }, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-cineform, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-h263, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-h264, stream-format=(string)avc, alignment=(string)au, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-h265, stream-format=(string){ hvc1, hev1 }, alignment=(string)au, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-svq, svqversion=(int)3, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-dv, systemstream=(boolean)false, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; image/jpeg, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; image/png, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-vp8, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-vp9, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-dirac, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-qt-part, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/quicktime, variant=(string)apple; video/quicktime</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpxqtdepay</name>
+      <longname>RTP packet depayloader</longname>
+      <class>Codec/Depayloader/Network</class>
+      <description>Extracts Quicktime audio/video from RTP packets</description>
+      <author>Wim Taymans &lt;wim@fluendo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, payload=(int)[ 96, 127 ], media=(string){ audio, video }, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string){ X-QT, X-QUICKTIME }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-jack.xml b/docs/plugins/inspect/plugin-jack.xml
new file mode 100644
index 0000000..8a55f4c
--- /dev/null
+++ b/docs/plugins/inspect/plugin-jack.xml
@@ -0,0 +1,43 @@
+<plugin>
+  <name>jack</name>
+  <description>JACK audio elements</description>
+  <filename>../../ext/jack/.libs/libgstjack.so</filename>
+  <basename>libgstjack.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>jackaudiosink</name>
+      <longname>Audio Sink (Jack)</longname>
+      <class>Sink/Audio</class>
+      <description>Output audio to a JACK server</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)F32LE, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>jackaudiosrc</name>
+      <longname>Audio Source (Jack)</longname>
+      <class>Source/Audio</class>
+      <description>Captures audio from a JACK server</description>
+      <author>Tristan Matthews &lt;tristan@sat.qc.ca&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)F32LE, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-jpeg.xml b/docs/plugins/inspect/plugin-jpeg.xml
new file mode 100644
index 0000000..d5031d3
--- /dev/null
+++ b/docs/plugins/inspect/plugin-jpeg.xml
@@ -0,0 +1,55 @@
+<plugin>
+  <name>jpeg</name>
+  <description>JPeg plugin library</description>
+  <filename>../../ext/jpeg/.libs/libgstjpeg.so</filename>
+  <basename>libgstjpeg.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>jpegdec</name>
+      <longname>JPEG image decoder</longname>
+      <class>Codec/Decoder/Image</class>
+      <description>Decode images from JPEG format</description>
+      <author>Wim Taymans &lt;wim@fluendo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>image/jpeg</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ I420, RGB, BGR, RGBx, xRGB, BGRx, xBGR, GRAY8 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>jpegenc</name>
+      <longname>JPEG image encoder</longname>
+      <class>Codec/Encoder/Image</class>
+      <description>Encode images in JPEG format</description>
+      <author>Wim Taymans &lt;wim.taymans@tvd.be&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ I420, YV12, YUY2, UYVY, Y41B, Y42B, YVYU, Y444, NV21, NV12, RGB, BGR, RGBx, xRGB, BGRx, xBGR, GRAY8 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>image/jpeg, width=(int)[ 16, 65535 ], height=(int)[ 16, 65535 ], framerate=(fraction)[ 0/1, 2147483647/1 ], sof-marker=(int){ 0, 1, 2, 9 }</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-lame.xml b/docs/plugins/inspect/plugin-lame.xml
new file mode 100644
index 0000000..67fc2e6
--- /dev/null
+++ b/docs/plugins/inspect/plugin-lame.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>lame</name>
+  <description>Encode MP3s with LAME</description>
+  <filename>../../ext/lame/.libs/libgstlame.so</filename>
+  <basename>libgstlame.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>lamemp3enc</name>
+      <longname>L.A.M.E. mp3 encoder</longname>
+      <class>Codec/Encoder/Audio</class>
+      <description>High-quality free MP3 encoder</description>
+      <author>Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S16LE, layout=(string)interleaved, rate=(int){ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, channels=(int)1; audio/x-raw, format=(string)S16LE, layout=(string)interleaved, rate=(int){ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, channels=(int)2, channel-mask=(bitmask)0x0000000000000003</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/mpeg, mpegversion=(int)1, layer=(int)3, rate=(int){ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, channels=(int)[ 1, 2 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-level.xml b/docs/plugins/inspect/plugin-level.xml
new file mode 100644
index 0000000..2d8ae40
--- /dev/null
+++ b/docs/plugins/inspect/plugin-level.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>level</name>
+  <description>Audio level plugin</description>
+  <filename>../../gst/level/.libs/libgstlevel.so</filename>
+  <basename>libgstlevel.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>level</name>
+      <longname>Level</longname>
+      <class>Filter/Analyzer/Audio</class>
+      <description>RMS/Peak/Decaying Peak Level messager for audio/raw</description>
+      <author>Thomas Vander Stichele &lt;thomas at apestaart dot org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S8, S16LE, S32LE, F32LE, F64LE }, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S8, S16LE, S32LE, F32LE, F64LE }, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-matroska.xml b/docs/plugins/inspect/plugin-matroska.xml
new file mode 100644
index 0000000..d9f6e12
--- /dev/null
+++ b/docs/plugins/inspect/plugin-matroska.xml
@@ -0,0 +1,133 @@
+<plugin>
+  <name>matroska</name>
+  <description>Matroska and WebM stream handling</description>
+  <filename>../../gst/matroska/.libs/libgstmatroska.so</filename>
+  <basename>libgstmatroska.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>matroskademux</name>
+      <longname>Matroska demuxer</longname>
+      <class>Codec/Demuxer</class>
+      <description>Demuxes Matroska/WebM streams into video/audio/subtitles</description>
+      <author>GStreamer maintainers &lt;gstreamer-devel@lists.freedesktop.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-matroska; video/x-matroska; video/x-matroska-3d; audio/webm; video/webm</details>
+        </caps>
+        <caps>
+          <name>audio_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>subtitle_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>text/x-raw, format=(string)pango-markup; application/x-ssa; application/x-ass; application/x-usf; subpicture/x-dvd; subpicture/x-pgs; subtitle/x-kate; application/x-subtitle-unknown</details>
+        </caps>
+        <caps>
+          <name>video_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>matroskamux</name>
+      <longname>Matroska muxer</longname>
+      <class>Codec/Muxer</class>
+      <description>Muxes video/audio/subtitle streams into a matroska stream</description>
+      <author>GStreamer maintainers &lt;gstreamer-devel@lists.freedesktop.org&gt;</author>
+      <pads>
+        <caps>
+          <name>audio_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>audio/mpeg, mpegversion=(int)1, layer=(int)[ 1, 3 ], channels=(int)[ 1, 2147483647 ], rate=(int)[ 1, 2147483647 ]; audio/mpeg, mpegversion=(int){ 2, 4 }, stream-format=(string)raw, channels=(int)[ 1, 2147483647 ], rate=(int)[ 1, 2147483647 ]; audio/x-ac3, channels=(int)[ 1, 2147483647 ], rate=(int)[ 1, 2147483647 ]; audio/x-eac3, channels=(int)[ 1, 2147483647 ], rate=(int)[ 1, 2147483647 ]; audio/x-dts, channels=(int)[ 1, 2147483647 ], rate=(int)[ 1, 2147483647 ]; audio/x-vorbis, channels=(int)[ 1, 2147483647 ], rate=(int)[ 1, 2147483647 ]; audio/x-flac, channels=(int)[ 1, 2147483647 ], rate=(int)[ 1, 2147483647 ]; audio/x-opus; audio/x-speex, channels=(int)[ 1, 2147483647 ], rate=(int)[ 1, 2147483647 ]; audio/x-raw, format=(string){ U8, S16BE, S16LE, S24BE, S24LE, S32BE, S32LE, F32LE, F64LE }, layout=(string)interleaved, channels=(int)[ 1, 2147483647 ], rate=(int)[ 1, 2147483647 ]; audio/x-tta, width=(int){ 8, 16, 24 }, channels=(int){ 1, 2 }, rate=(int)[ 8000, 96000 ]; audio/x-pn-realaudio, raversion=(int){ 1, 2, 8 }, channels=(int)[ 1, 2147483647 ], rate=(int)[ 1, 2147483647 ]; audio/x-wma, wmaversion=(int)[ 1, 3 ], block_align=(int)[ 0, 65535 ], bitrate=(int)[ 0, 524288 ], channels=(int)[ 1, 2147483647 ], rate=(int)[ 1, 2147483647 ]; audio/x-alaw, channels=(int){ 1, 2 }, rate=(int)[ 8000, 192000 ]; audio/x-mulaw, channels=(int){ 1, 2 }, rate=(int)[ 8000, 192000 ]; audio/x-adpcm, layout=(string)dvi, block_align=(int)[ 64, 8192 ], channels=(int){ 1, 2 }, rate=(int)[ 8000, 96000 ]; audio/G722, channels=(int)1, rate=(int)16000; audio/x-adpcm, layout=(string)g726, channels=(int)1, rate=(int)8000</details>
+        </caps>
+        <caps>
+          <name>subtitle_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>subtitle/x-kate; text/x-raw, format=(string)utf8; application/x-ssa; application/x-ass; application/x-usf; subpicture/x-dvd; application/x-subtitle-unknown</details>
+        </caps>
+        <caps>
+          <name>video_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>video/mpeg, mpegversion=(int){ 1, 2, 4 }, systemstream=(boolean)false, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-h264, stream-format=(string)avc, alignment=(string)au, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-h265, stream-format=(string)hvc1, alignment=(string)au, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-divx, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-huffyuv, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-dv, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-h263, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-msmpeg, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; image/jpeg, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-theora; video/x-dirac, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-pn-realvideo, rmversion=(int)[ 1, 4 ], width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-vp8, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-vp9, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-raw, format=(string){ YUY2, I420, YV12, UYVY, AYUV, GRAY8, BGR, RGB }, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-prores, width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]; video/x-wmv, wmvversion=(int)[ 1, 3 ], width=(int)[ 16, 2147483647 ], height=(int)[ 16, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-matroska; video/x-matroska-3d; audio/x-matroska</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>matroskaparse</name>
+      <longname>Matroska parser</longname>
+      <class>Codec/Parser</class>
+      <description>Parses Matroska/WebM streams into video/audio/subtitles</description>
+      <author>GStreamer maintainers &lt;gstreamer-devel@lists.freedesktop.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-matroska; video/x-matroska; video/x-matroska-3d; audio/webm; video/webm</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-matroska; video/x-matroska; video/x-matroska-3d; audio/webm; video/webm</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>webmmux</name>
+      <longname>WebM muxer</longname>
+      <class>Codec/Muxer</class>
+      <description>Muxes video and audio streams into a WebM stream</description>
+      <author>GStreamer maintainers &lt;gstreamer-devel@lists.freedesktop.org&gt;</author>
+      <pads>
+        <caps>
+          <name>audio_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>audio/x-vorbis, channels=(int)[ 1, 2147483647 ], rate=(int)[ 1, 2147483647 ]; audio/x-opus, channels=(int)[ 1, 2147483647 ], rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>subtitle_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>subtitle/x-kate; text/x-raw, format=(string)utf8; application/x-ssa; application/x-ass; application/x-usf; subpicture/x-dvd; application/x-subtitle-unknown</details>
+        </caps>
+        <caps>
+          <name>video_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>video/x-vp8, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-vp9, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-av1, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/webm; audio/webm</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-monoscope.xml b/docs/plugins/inspect/plugin-monoscope.xml
new file mode 100644
index 0000000..5a11635
--- /dev/null
+++ b/docs/plugins/inspect/plugin-monoscope.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>monoscope</name>
+  <description>Monoscope visualization</description>
+  <filename>../../gst/monoscope/.libs/libgstmonoscope.so</filename>
+  <basename>libgstmonoscope.so</basename>
+  <version>1.1.3</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins source release</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>monoscope</name>
+      <longname>Monoscope</longname>
+      <class>Visualization</class>
+      <description>Displays a highly stabilised waveform of audio input</description>
+      <author>Richard Boulton &lt;richard@tartarus.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S16LE, rate=(int)[ 8000, 96000 ], channels=(int)1, layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)BGRx, width=(int)256, height=(int)128, framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-mpg123.xml b/docs/plugins/inspect/plugin-mpg123.xml
new file mode 100644
index 0000000..b040904
--- /dev/null
+++ b/docs/plugins/inspect/plugin-mpg123.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>mpg123</name>
+  <description>mp3 decoding based on the mpg123 library</description>
+  <filename>../../ext/mpg123/.libs/libgstmpg123.so</filename>
+  <basename>libgstmpg123.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>mpg123audiodec</name>
+      <longname>mpg123 mp3 decoder</longname>
+      <class>Codec/Decoder/Audio</class>
+      <description>Decodes mp3 streams using the mpg123 library</description>
+      <author>Carlos Rafael Giani &lt;dv@pseudoterminal.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/mpeg, mpegversion=(int)1, layer=(int)[ 1, 3 ], rate=(int){ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, channels=(int)[ 1, 2 ], parsed=(boolean)true</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, U16LE, S32LE, U32LE, S24LE, U24LE, F32LE }, rate=(int){ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, channels=(int)[ 1, 2 ], layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-mulaw.xml b/docs/plugins/inspect/plugin-mulaw.xml
new file mode 100644
index 0000000..56ddaa4
--- /dev/null
+++ b/docs/plugins/inspect/plugin-mulaw.xml
@@ -0,0 +1,55 @@
+<plugin>
+  <name>mulaw</name>
+  <description>MuLaw audio conversion routines</description>
+  <filename>../../gst/law/.libs/libgstmulaw.so</filename>
+  <basename>libgstmulaw.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>mulawdec</name>
+      <longname>Mu Law audio decoder</longname>
+      <class>Codec/Decoder/Audio</class>
+      <description>Convert 8bit mu law to 16bit PCM</description>
+      <author>Zaheer Abbas Merali &lt;zaheerabbas at merali dot org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-mulaw, rate=(int)[ 8000, 192000 ], channels=(int)[ 1, 2 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S16LE, layout=(string)interleaved, rate=(int)[ 8000, 192000 ], channels=(int)[ 1, 2 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>mulawenc</name>
+      <longname>Mu Law audio encoder</longname>
+      <class>Codec/Encoder/Audio</class>
+      <description>Convert 16bit PCM to 8bit mu law</description>
+      <author>Zaheer Abbas Merali &lt;zaheerabbas at merali dot org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S16LE, layout=(string)interleaved, rate=(int)[ 8000, 192000 ], channels=(int)[ 1, 2 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-mulaw, rate=(int)[ 8000, 192000 ], channels=(int)[ 1, 2 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-multifile.xml b/docs/plugins/inspect/plugin-multifile.xml
new file mode 100644
index 0000000..24d01a0
--- /dev/null
+++ b/docs/plugins/inspect/plugin-multifile.xml
@@ -0,0 +1,112 @@
+<plugin>
+  <name>multifile</name>
+  <description>Reads/Writes buffers from/to sequentially named files</description>
+  <filename>../../gst/multifile/.libs/libgstmultifile.so</filename>
+  <basename>libgstmultifile.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>multifilesink</name>
+      <longname>Multi-File Sink</longname>
+      <class>Sink/File</class>
+      <description>Write buffers to a sequentially named set of files</description>
+      <author>David Schleef &lt;ds@schleef.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>multifilesrc</name>
+      <longname>Multi-File Source</longname>
+      <class>Source/File</class>
+      <description>Read a sequentially named set of files into buffers</description>
+      <author>David Schleef &lt;ds@schleef.org&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>splitfilesrc</name>
+      <longname>Split-File Source</longname>
+      <class>Source/File</class>
+      <description>Read a sequentially named set of files as if it was one large file</description>
+      <author>Tim-Philipp Müller &lt;tim.muller@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>splitmuxsink</name>
+      <longname>Split Muxing Bin</longname>
+      <class>Generic/Bin/Muxer</class>
+      <description>Convenience bin that muxes incoming streams into multiple time/size limited files</description>
+      <author>Jan Schmidt &lt;jan@centricular.com&gt;</author>
+      <pads>
+        <caps>
+          <name>audio_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>subtitle_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>video</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>splitmuxsrc</name>
+      <longname>Split File Demuxing Bin</longname>
+      <class>Generic/Bin/Demuxer</class>
+      <description>Source that reads a set of files created by splitmuxsink</description>
+      <author>Jan Schmidt &lt;jan@centricular.com&gt;</author>
+      <pads>
+        <caps>
+          <name>audio_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>subtitle_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>video</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-multipart.xml b/docs/plugins/inspect/plugin-multipart.xml
new file mode 100644
index 0000000..12d548b
--- /dev/null
+++ b/docs/plugins/inspect/plugin-multipart.xml
@@ -0,0 +1,55 @@
+<plugin>
+  <name>multipart</name>
+  <description>multipart stream manipulation</description>
+  <filename>../../gst/multipart/.libs/libgstmultipart.so</filename>
+  <basename>libgstmultipart.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>multipartdemux</name>
+      <longname>Multipart demuxer</longname>
+      <class>Codec/Demuxer</class>
+      <description>demux multipart streams</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;, Sjoerd Simons &lt;sjoerd@luon.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>multipart/x-mixed-replace</details>
+        </caps>
+        <caps>
+          <name>src_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>multipartmux</name>
+      <longname>Multipart muxer</longname>
+      <class>Codec/Muxer</class>
+      <description>mux multipart streams</description>
+      <author>Wim Taymans &lt;wim@fluendo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>multipart/x-mixed-replace</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-navigationtest.xml b/docs/plugins/inspect/plugin-navigationtest.xml
new file mode 100644
index 0000000..9ad2bf1
--- /dev/null
+++ b/docs/plugins/inspect/plugin-navigationtest.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>navigationtest</name>
+  <description>Template for a video filter</description>
+  <filename>../../gst/debugutils/.libs/libgstnavigationtest.so</filename>
+  <basename>libgstnavigationtest.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>navigationtest</name>
+      <longname>Video navigation test</longname>
+      <class>Filter/Effect/Video</class>
+      <description>Handle navigation events showing a black square following mouse pointer</description>
+      <author>David Schleef &lt;ds@schleef.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)I420, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)I420, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-oss4.xml b/docs/plugins/inspect/plugin-oss4.xml
new file mode 100644
index 0000000..f75f67b
--- /dev/null
+++ b/docs/plugins/inspect/plugin-oss4.xml
@@ -0,0 +1,43 @@
+<plugin>
+  <name>oss4</name>
+  <description>Open Sound System (OSS) version 4 support for GStreamer</description>
+  <filename>../../sys/oss4/.libs/libgstoss4.so</filename>
+  <basename>libgstoss4.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>oss4sink</name>
+      <longname>OSS v4 Audio Sink</longname>
+      <class>Sink/Audio</class>
+      <description>Output to a sound card via OSS version 4</description>
+      <author>Tim-Philipp Müller &lt;tim centricular net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-alaw, rate=(int)[ 1, 192000 ], channels=(int)[ 1, 4096 ]; audio/x-mulaw, rate=(int)[ 1, 192000 ], channels=(int)[ 1, 4096 ]; audio/x-raw, format=(string){ S32LE, S32BE, S24_32LE, S24_32BE, S24LE, S16LE, S16BE, U16LE, U16BE, S8, U8 }, layout=(string)interleaved, rate=(int)[ 1, 192000 ], channels=(int)[ 1, 4096 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>oss4src</name>
+      <longname>OSS v4 Audio Source</longname>
+      <class>Source/Audio</class>
+      <description>Capture from a sound card via OSS version 4</description>
+      <author>Tim-Philipp Müller &lt;tim centricular net&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-alaw, rate=(int)[ 1, 192000 ], channels=(int)[ 1, 4096 ]; audio/x-mulaw, rate=(int)[ 1, 192000 ], channels=(int)[ 1, 4096 ]; audio/x-raw, format=(string){ S32LE, S32BE, S24_32LE, S24_32BE, S24LE, S16LE, S16BE, U16LE, U16BE, S8, U8 }, layout=(string)interleaved, rate=(int)[ 1, 192000 ], channels=(int)[ 1, 4096 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-ossaudio.xml b/docs/plugins/inspect/plugin-ossaudio.xml
new file mode 100644
index 0000000..4ddcc3e
--- /dev/null
+++ b/docs/plugins/inspect/plugin-ossaudio.xml
@@ -0,0 +1,43 @@
+<plugin>
+  <name>ossaudio</name>
+  <description>OSS (Open Sound System) support for GStreamer</description>
+  <filename>../../sys/oss/.libs/libgstossaudio.so</filename>
+  <basename>libgstossaudio.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>osssink</name>
+      <longname>Audio Sink (OSS)</longname>
+      <class>Sink/Audio</class>
+      <description>Output to a sound card via OSS</description>
+      <author>Erik Walthinsen &lt;omega@cse.ogi.edu&gt;, Wim Taymans &lt;wim.taymans@chello.be&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, U16LE, S8, U8 }, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)1; audio/x-raw, format=(string){ S16LE, U16LE, S8, U8 }, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)2, channel-mask=(bitmask)0x0000000000000003</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>osssrc</name>
+      <longname>Audio Source (OSS)</longname>
+      <class>Source/Audio</class>
+      <description>Capture from a sound card via OSS</description>
+      <author>Erik Walthinsen &lt;omega@cse.ogi.edu&gt;, Wim Taymans &lt;wim@fluendo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, U16LE, S8, U8 }, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)1; audio/x-raw, format=(string){ S16LE, U16LE, S8, U8 }, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)2, channel-mask=(bitmask)0x0000000000000003</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-osxaudio.xml b/docs/plugins/inspect/plugin-osxaudio.xml
new file mode 100644
index 0000000..4718a4a
--- /dev/null
+++ b/docs/plugins/inspect/plugin-osxaudio.xml
@@ -0,0 +1,27 @@
+<plugin>
+  <name>osxaudio</name>
+  <description>OSX (Mac OS X) audio support for GStreamer</description>
+  <filename>../../sys/osxaudio/.libs/libgstosxaudio.so</filename>
+  <basename>libgstosxaudio.so</basename>
+  <version>0.10.5.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins CVS/prerelease</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>osxaudiosink</name>
+      <longname>Audio Sink (OSX)</longname>
+      <class>Sink/Audio</class>
+      <description>Output to a sound card in OS X</description>
+      <author>Zaheer Abbas Merali &lt;zaheerabbas at merali dot org&gt;</author>
+    </element>
+    <element>
+      <name>osxaudiosrc</name>
+      <longname>Audio Source (OSX)</longname>
+      <class>Source/Audio</class>
+      <description>Input from a sound card in OS X</description>
+      <author>Zaheer Abbas Merali &lt;zaheerabbas at merali dot org&gt;</author>
+    </element>
+  </elements>
+</plugin>
diff --git a/docs/plugins/inspect/plugin-osxvideo.xml b/docs/plugins/inspect/plugin-osxvideo.xml
new file mode 100644
index 0000000..45bdeeb
--- /dev/null
+++ b/docs/plugins/inspect/plugin-osxvideo.xml
@@ -0,0 +1,20 @@
+<plugin>
+  <name>osxvideo</name>
+  <description>OSX native video output plugin</description>
+  <filename>../../ext/osxvideo/.libs/libgstosxvideo.so</filename>
+  <basename>libgstosxvideo.so</basename>
+  <version>0.10.4</version>
+  <license>LGPL</license>
+  <source>gst-plugins-bad</source>
+  <package>Gstreamer</package>
+  <origin>http://gstreamer.freedesktop.org</origin>
+  <elements>
+    <element>
+      <name>osxvideosink</name>
+      <longname>OSX Video sink</longname>
+      <class>Sink/Video</class>
+      <description>OSX native videosink</description>
+      <author>Zaheer Abbas Merali &lt;zaheerabas at merali dot org&gt;</author>
+    </element>
+  </elements>
+</plugin>
diff --git a/docs/plugins/inspect/plugin-png.xml b/docs/plugins/inspect/plugin-png.xml
new file mode 100644
index 0000000..09a3e48
--- /dev/null
+++ b/docs/plugins/inspect/plugin-png.xml
@@ -0,0 +1,55 @@
+<plugin>
+  <name>png</name>
+  <description>PNG plugin library</description>
+  <filename>../../ext/libpng/.libs/libgstpng.so</filename>
+  <basename>libgstpng.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>pngdec</name>
+      <longname>PNG image decoder</longname>
+      <class>Codec/Decoder/Image</class>
+      <description>Decode a png video frame to a raw image</description>
+      <author>Wim Taymans &lt;wim@fluendo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>image/png</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBA, RGB, ARGB64, GRAY8, GRAY16_BE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>pngenc</name>
+      <longname>PNG image encoder</longname>
+      <class>Codec/Encoder/Image</class>
+      <description>Encode a video frame to a .png image</description>
+      <author>Jeremy SIMON &lt;jsimon13@yahoo.fr&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBA, RGB, GRAY8, GRAY16_BE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>image/png, width=(int)[ 16, 1000000 ], height=(int)[ 16, 1000000 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-pulseaudio.xml b/docs/plugins/inspect/plugin-pulseaudio.xml
new file mode 100644
index 0000000..9806798
--- /dev/null
+++ b/docs/plugins/inspect/plugin-pulseaudio.xml
@@ -0,0 +1,43 @@
+<plugin>
+  <name>pulseaudio</name>
+  <description>PulseAudio plugin library</description>
+  <filename>../../ext/pulse/.libs/libgstpulseaudio.so</filename>
+  <basename>libgstpulseaudio.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>pulsesink</name>
+      <longname>PulseAudio Audio Sink</longname>
+      <class>Sink/Audio</class>
+      <description>Plays audio to a PulseAudio server</description>
+      <author>Lennart Poettering</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, S16BE, F32LE, F32BE, S32LE, S32BE, S24LE, S24BE, S24_32LE, S24_32BE, U8 }, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-alaw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-mulaw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-ac3, framed=(boolean)true; audio/x-eac3, framed=(boolean)true; audio/x-dts, framed=(boolean)true, block-size=(int){ 512, 1024, 2048 }; audio/mpeg, mpegversion=(int)1, mpegaudioversion=(int)[ 1, 3 ], parsed=(boolean)true; audio/mpeg, mpegversion=(int){ 2, 4 }, framed=(boolean)true, stream-format=(string)adts</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>pulsesrc</name>
+      <longname>PulseAudio Audio Source</longname>
+      <class>Source/Audio</class>
+      <description>Captures audio from a PulseAudio server</description>
+      <author>Lennart Poettering</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, S16BE, F32LE, F32BE, S32LE, S32BE, S24LE, S24BE, S24_32LE, S24_32BE, U8 }, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-alaw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-mulaw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-replaygain.xml b/docs/plugins/inspect/plugin-replaygain.xml
new file mode 100644
index 0000000..3abaada
--- /dev/null
+++ b/docs/plugins/inspect/plugin-replaygain.xml
@@ -0,0 +1,76 @@
+<plugin>
+  <name>replaygain</name>
+  <description>ReplayGain volume normalization</description>
+  <filename>../../gst/replaygain/.libs/libgstreplaygain.so</filename>
+  <basename>libgstreplaygain.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>rganalysis</name>
+      <longname>ReplayGain analysis</longname>
+      <class>Filter/Analyzer/Audio</class>
+      <description>Perform the ReplayGain analysis</description>
+      <author>René Stadler &lt;mail@renestadler.de&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, S16LE }, layout=(string)interleaved, channels=(int)1, rate=(int){ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }; audio/x-raw, format=(string){ F32LE, S16LE }, layout=(string)interleaved, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, rate=(int){ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, S16LE }, layout=(string)interleaved, channels=(int)1, rate=(int){ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }; audio/x-raw, format=(string){ F32LE, S16LE }, layout=(string)interleaved, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, rate=(int){ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rglimiter</name>
+      <longname>ReplayGain limiter</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Apply signal compression to raw audio data</description>
+      <author>René Stadler &lt;mail@renestadler.de&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)F32LE, layout=(string){ interleaved, non-interleaved }, channels=(int)[ 1, 2147483647 ], rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)F32LE, layout=(string){ interleaved, non-interleaved }, channels=(int)[ 1, 2147483647 ], rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rgvolume</name>
+      <longname>ReplayGain volume</longname>
+      <class>Filter/Effect/Audio</class>
+      <description>Apply ReplayGain volume adjustment</description>
+      <author>René Stadler &lt;mail@renestadler.de&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, S16LE }, layout=(string){ interleaved, non-interleaved }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, S16LE }, layout=(string){ interleaved, non-interleaved }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-rtp.xml b/docs/plugins/inspect/plugin-rtp.xml
new file mode 100644
index 0000000..0afaed6
--- /dev/null
+++ b/docs/plugins/inspect/plugin-rtp.xml
@@ -0,0 +1,1861 @@
+<plugin>
+  <name>rtp</name>
+  <description>Real-time protocol plugins</description>
+  <filename>../../gst/rtp/.libs/libgstrtp.so</filename>
+  <basename>libgstrtp.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>asteriskh263</name>
+      <longname>RTP Asterisk H263 depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts H263 video from RTP and encodes in Asterisk H263 format</description>
+      <author>Neil Stratford &lt;neils@vipadia.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)H263-1998</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-asteriskh263</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpL16depay</name>
+      <longname>RTP audio depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts raw audio from RTP packets</description>
+      <author>Zeeshan Ali &lt;zak147@yahoo.com&gt;,Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)L16; application/x-rtp, media=(string)audio, payload=(int){ 10, 11 }, clock-rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S16BE, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpL16pay</name>
+      <longname>RTP audio payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encode Raw audio into RTP packets (RFC 3551)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S16BE, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)L16, channels=(int)[ 1, 2147483647 ]; application/x-rtp, media=(string)audio, encoding-name=(string)L16, payload=(int)10, clock-rate=(int)44100; application/x-rtp, media=(string)audio, encoding-name=(string)L16, payload=(int)11, clock-rate=(int)44100</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpL24depay</name>
+      <longname>RTP audio depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts raw 24-bit audio from RTP packets</description>
+      <author>Zeeshan Ali &lt;zak147@yahoo.com&gt;,Wim Taymans &lt;wim.taymans@gmail.com&gt;,David Holroyd &lt;dave@badgers-in-foil.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)L24</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S24BE, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpL24pay</name>
+      <longname>RTP audio payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encode Raw 24-bit audio into RTP packets (RFC 3190)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;,David Holroyd &lt;dave@badgers-in-foil.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S24BE, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)L24, channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpL8depay</name>
+      <longname>RTP audio depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts raw audio from RTP packets</description>
+      <author>Zeeshan Ali &lt;zak147@yahoo.com&gt;,Wim Taymans &lt;wim.taymans@gmail.com&gt;, GE Intelligent Platforms Embedded Systems, Inc.</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)L8</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)U8, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpL8pay</name>
+      <longname>RTP audio payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encode Raw audio into RTP packets (RFC 3551)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;, GE Intelligent Platforms Embedded Systems, Inc.</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)U8, layout=(string)interleaved, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)L8, channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpac3depay</name>
+      <longname>RTP AC3 depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts AC3 audio from RTP packets (RFC 4184)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int){ 32000, 44100, 48000 }, encoding-name=(string)AC3</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/ac3</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpac3pay</name>
+      <longname>RTP AC3 audio payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload AC3 audio as RTP packets (RFC 4184)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/ac3; audio/x-ac3</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int){ 32000, 44100, 48000 }, encoding-name=(string)AC3</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpamrdepay</name>
+      <longname>RTP AMR depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts AMR or AMR-WB audio from RTP packets (RFC 3267)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)8000, encoding-name=(string)AMR, octet-align=(string)1; application/x-rtp, media=(string)audio, clock-rate=(int)16000, encoding-name=(string)AMR-WB, octet-align=(string)1</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/AMR, channels=(int)1, rate=(int)8000; audio/AMR-WB, channels=(int)1, rate=(int)16000</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpamrpay</name>
+      <longname>RTP AMR payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encode AMR or AMR-WB audio into RTP packets (RFC 3267)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/AMR, channels=(int)1, rate=(int)8000; audio/AMR-WB, channels=(int)1, rate=(int)16000</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)8000, encoding-name=(string)AMR, encoding-params=(string)1, octet-align=(string)1, crc=(string)0, robust-sorting=(string)0, interleaving=(string)0, mode-set=(int)[ 0, 7 ], mode-change-period=(int)[ 1, 2147483647 ], mode-change-neighbor=(string){ 0, 1 }, maxptime=(int)[ 20, 2147483647 ], ptime=(int)[ 20, 2147483647 ]; application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)16000, encoding-name=(string)AMR-WB, encoding-params=(string)1, octet-align=(string)1, crc=(string)0, robust-sorting=(string)0, interleaving=(string)0, mode-set=(int)[ 0, 7 ], mode-change-period=(int)[ 1, 2147483647 ], mode-change-neighbor=(string){ 0, 1 }, maxptime=(int)[ 20, 2147483647 ], ptime=(int)[ 20, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpbvdepay</name>
+      <longname>RTP BroadcomVoice depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts BroadcomVoice audio from RTP packets (RFC 4298)</description>
+      <author>Wim Taymans &lt;wim.taymans@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)8000, encoding-name=(string)BV16; application/x-rtp, media=(string)audio, clock-rate=(int)16000, encoding-name=(string)BV32</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-bv, mode=(int){ 16, 32 }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpbvpay</name>
+      <longname>RTP BV Payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Packetize BroadcomVoice audio streams into RTP packets (RFC 4298)</description>
+      <author>Wim Taymans &lt;wim.taymans@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-bv, mode=(int){ 16, 32 }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)8000, encoding-name=(string)BV16; application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)16000, encoding-name=(string)BV32</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpceltdepay</name>
+      <longname>RTP CELT depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts CELT audio from RTP packets</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)[ 32000, 48000 ], encoding-name=(string)CELT</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-celt</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpceltpay</name>
+      <longname>RTP CELT payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encodes CELT audio into a RTP packet</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-celt, rate=(int)[ 32000, 64000 ], channels=(int)[ 1, 2 ], frame-size=(int)[ 64, 512 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)[ 32000, 48000 ], encoding-name=(string)CELT</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpdvdepay</name>
+      <longname>RTP DV Depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Depayloads DV from RTP packets (RFC 3189)</description>
+      <author>Marcel Moreaux &lt;marcelm@spacelabs.nl&gt;, Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string){ video, audio }, encoding-name=(string)DV, clock-rate=(int)90000, encode=(string){ SD-VCR/525-60, SD-VCR/625-50, HD-VCR/1125-60, HD-VCR/1250-50, SDL-VCR/525-60, SDL-VCR/625-50, 306M/525-60, 306M/625-50, 314M-25/525-60, 314M-25/625-50, 314M-50/525-60, 314M-50/625-50 }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-dv</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpdvpay</name>
+      <longname>RTP DV Payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payloads DV into RTP packets (RFC 3189)</description>
+      <author>Marcel Moreaux &lt;marcelm@spacelabs.nl&gt;, Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-dv</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string){ video, audio }, payload=(int)[ 96, 127 ], encoding-name=(string)DV, clock-rate=(int)90000, encode=(string){ SD-VCR/525-60, SD-VCR/625-50, HD-VCR/1125-60, HD-VCR/1250-50, SDL-VCR/525-60, SDL-VCR/625-50, 306M/525-60, 306M/625-50, 314M-25/525-60, 314M-25/625-50, 314M-50/525-60, 314M-50/625-50 }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpg722depay</name>
+      <longname>RTP audio depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts G722 audio from RTP packets</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)8000, encoding-name=(string)G722; application/x-rtp, media=(string)audio, payload=(int)9, clock-rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/G722, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpg722pay</name>
+      <longname>RTP audio payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encode Raw audio into RTP packets (RFC 3551)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/G722, rate=(int)16000, channels=(int)1</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, encoding-name=(string)G722, payload=(int)9, encoding-params=(string)1, clock-rate=(int)8000; application/x-rtp, media=(string)audio, encoding-name=(string)G722, payload=(int)[ 96, 127 ], encoding-params=(string)1, clock-rate=(int)8000</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpg723depay</name>
+      <longname>RTP G.723 depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts G.723 audio from RTP packets (RFC 3551)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)8000, encoding-name=(string)G723; application/x-rtp, media=(string)audio, payload=(int)4, clock-rate=(int)8000</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/G723, channels=(int)1, rate=(int)8000</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpg723pay</name>
+      <longname>RTP G.723 payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Packetize G.723 audio into RTP packets</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/G723, channels=(int)1, rate=(int)8000</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)4, clock-rate=(int)8000, encoding-name=(string)G723; application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)8000, encoding-name=(string)G723</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpg726depay</name>
+      <longname>RTP G.726 depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts G.726 audio from RTP packets</description>
+      <author>Axis Communications &lt;dev-gstreamer@axis.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, encoding-name=(string){ G726, G726-16, G726-24, G726-32, G726-40, AAL2-G726-16, AAL2-G726-24, AAL2-G726-32, AAL2-G726-40 }, clock-rate=(int)8000</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-adpcm, channels=(int)1, rate=(int)8000, bitrate=(int){ 16000, 24000, 32000, 40000 }, block_align=(int){ 2, 3, 4, 5 }, layout=(string)g726</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpg726pay</name>
+      <longname>RTP G.726 payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encodes G.726 audio into a RTP packet</description>
+      <author>Axis Communications &lt;dev-gstreamer@axis.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-adpcm, channels=(int)1, rate=(int)8000, bitrate=(int){ 16000, 24000, 32000, 40000 }, layout=(string)g726</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)8000, encoding-name=(string){ G726-16, G726-24, G726-32, G726-40, AAL2-G726-16, AAL2-G726-24, AAL2-G726-32, AAL2-G726-40 }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpg729depay</name>
+      <longname>RTP G.729 depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts G.729 audio from RTP packets (RFC 3551)</description>
+      <author>Laurent Glayal &lt;spglegle@yahoo.fr&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)8000, encoding-name=(string)G729; application/x-rtp, media=(string)audio, payload=(int)18, clock-rate=(int)8000</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/G729, channels=(int)1, rate=(int)8000</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpg729pay</name>
+      <longname>RTP G.729 payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Packetize G.729 audio into RTP packets</description>
+      <author>Olivier Crete &lt;olivier.crete@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/G729, channels=(int)1, rate=(int)8000</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)18, clock-rate=(int)8000, encoding-name=(string)G729; application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)8000, encoding-name=(string)G729</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpgsmdepay</name>
+      <longname>RTP GSM depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts GSM audio from RTP packets</description>
+      <author>Zeeshan Ali &lt;zeenix@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)8000, encoding-name=(string)GSM; application/x-rtp, media=(string)audio, payload=(int)3, clock-rate=(int)8000</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-gsm, rate=(int)8000, channels=(int)1</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpgsmpay</name>
+      <longname>RTP GSM payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encodes GSM audio into a RTP packet</description>
+      <author>Zeeshan Ali &lt;zeenix@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-gsm, rate=(int)8000, channels=(int)1</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)3, clock-rate=(int)8000, encoding-name=(string)GSM; application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)8000, encoding-name=(string)GSM</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpgstdepay</name>
+      <longname>GStreamer depayloader</longname>
+      <class>Codec/Depayloader/Network</class>
+      <description>Extracts GStreamer buffers from RTP packets</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)application, clock-rate=(int)90000, encoding-name=(string)X-GST</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpgstpay</name>
+      <longname>RTP GStreamer payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload GStreamer buffers as RTP packets</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)application, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)X-GST</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtph261depay</name>
+      <longname>RTP H261 depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts H261 video from RTP packets (RFC 4587)</description>
+      <author>Stian Selnes &lt;stian@pexip.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, payload=(int)31, clock-rate=(int)90000, encoding-name=(string)H261; application/x-rtp, media=(string)video, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)H261</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-h261</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtph261pay</name>
+      <longname>RTP H261 packet payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encodes H261 video in RTP packets (RFC 4587)</description>
+      <author>Stian Selnes &lt;stian@pexip.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-h261</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, payload=(int)31, clock-rate=(int)90000, encoding-name=(string)H261; application/x-rtp, media=(string)video, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)H261</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtph263depay</name>
+      <longname>RTP H263 depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts H263 video from RTP packets (RFC 2190)</description>
+      <author>Philippe Kalaf &lt;philippe.kalaf@collabora.co.uk&gt;, Edward Hervey &lt;bilboed@bilboed.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, payload=(int)34, clock-rate=(int)90000; application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H263</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-h263, variant=(string)itu, h263version=(string)h263</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtph263pay</name>
+      <longname>RTP H263 packet payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encodes H263 video in RTP packets (RFC 2190)</description>
+      <author>Neil Stratford &lt;neils@vipadia.com&gt;Dejan Sakelsak &lt;dejan.sakelsak@marand.si&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-h263, variant=(string)itu, h263version=(string)h263</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, payload=(int)34, clock-rate=(int)90000, encoding-name=(string)H263; application/x-rtp, media=(string)video, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)H263</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtph263pdepay</name>
+      <longname>RTP H263 depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts H263/+/++ video from RTP packets (RFC 4629)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)H263-1998; application/x-rtp, media=(string)video, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)H263-2000</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-h263, variant=(string)itu</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtph263ppay</name>
+      <longname>RTP H263 payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encodes H263/+/++ video in RTP packets (RFC 4629)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-h263, variant=(string)itu</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)H263-1998; application/x-rtp, media=(string)video, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)H263-2000</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtph264depay</name>
+      <longname>RTP H264 depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts H264 video from RTP packets (RFC 3984)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-h264, stream-format=(string)avc, alignment=(string)au; video/x-h264, stream-format=(string)byte-stream, alignment=(string){ nal, au }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtph264pay</name>
+      <longname>RTP H264 payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encode H264 video into RTP packets (RFC 3984)</description>
+      <author>Laurent Glayal &lt;spglegle@yahoo.fr&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-h264, stream-format=(string)avc, alignment=(string)au; video/x-h264, stream-format=(string)byte-stream, alignment=(string){ nal, au }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)H264</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtph265depay</name>
+      <longname>RTP H265 depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts H265 video from RTP packets (RFC 7798)</description>
+      <author>Jurgen Slowack &lt;jurgenslowack@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H265</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-h265, stream-format=(string)hvc1, alignment=(string)au; video/x-h265, stream-format=(string)byte-stream, alignment=(string){ nal, au }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtph265pay</name>
+      <longname>RTP H265 payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encode H265 video into RTP packets (RFC 7798)</description>
+      <author>Jurgen Slowack &lt;jurgenslowack@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-h265, stream-format=(string)hvc1, alignment=(string)au; video/x-h265, stream-format=(string)byte-stream, alignment=(string){ nal, au }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)H265</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpilbcdepay</name>
+      <longname>RTP iLBC depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts iLBC audio from RTP packets (RFC 3952)</description>
+      <author>Philippe Kalaf &lt;philippe.kalaf@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)8000, encoding-name=(string)ILBC</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-iLBC, mode=(int){ 20, 30 }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpilbcpay</name>
+      <longname>RTP iLBC Payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Packetize iLBC audio streams into RTP packets</description>
+      <author>Philippe Kalaf &lt;philippe.kalaf@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-iLBC, mode=(int){ 20, 30 }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)8000, encoding-name=(string)ILBC, mode=(string){ 20, 30 }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpj2kdepay</name>
+      <longname>RTP JPEG 2000 depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts JPEG 2000 video from RTP packets (RFC 5371)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, clock-rate=(int)90000, sampling=(string){ RGB, BGR, RGBA, BGRA, YCbCrA, YCbCr-4:4:4, YCbCr-4:2:2, YCbCr-4:2:0, YCbCr-4:1:1, GRAYSCALE }, encoding-name=(string)JPEG2000; application/x-rtp, media=(string)video, clock-rate=(int)90000, colorspace=(string){ sRGB, sYUV, GRAY }, encoding-name=(string)JPEG2000</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>image/x-jpc, colorspace=(string){ sRGB, sYUV, GRAY }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpj2kpay</name>
+      <longname>RTP JPEG 2000 payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encodes JPEG 2000 pictures into RTP packets (RFC 5371)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>image/x-jpc, sampling=(string){ RGB, BGR, RGBA, BGRA, YCbCrA, YCbCr-4:4:4, YCbCr-4:2:2, YCbCr-4:2:0, YCbCr-4:1:1, GRAYSCALE }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, payload=(int)[ 96, 127 ], clock-rate=(int)90000, sampling=(string){ RGB, BGR, RGBA, BGRA, YCbCrA, YCbCr-4:4:4, YCbCr-4:2:2, YCbCr-4:2:0, YCbCr-4:1:1, GRAYSCALE }, encoding-name=(string)JPEG2000</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpjpegdepay</name>
+      <longname>RTP JPEG depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts JPEG video from RTP packets (RFC 2435)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)JPEG; application/x-rtp, media=(string)video, payload=(int)26, clock-rate=(int)90000</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>image/jpeg</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpjpegpay</name>
+      <longname>RTP JPEG payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encodes JPEG pictures into RTP packets (RFC 2435)</description>
+      <author>Axis Communications &lt;dev-gstreamer@axis.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>image/jpeg; video/x-jpeg</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, payload=(int)26, clock-rate=(int)90000, encoding-name=(string)JPEG, width=(int)[ 1, 65536 ], height=(int)[ 1, 65536 ]; application/x-rtp, media=(string)video, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)JPEG, width=(int)[ 1, 65536 ], height=(int)[ 1, 65536 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpklvdepay</name>
+      <longname>RTP KLV Depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts KLV (SMPTE ST 336) metadata from RTP packets</description>
+      <author>Tim-Philipp Müller &lt;tim@centricular.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)application, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)SMPTE336M</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>meta/x-klv, parsed=(boolean)true</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpklvpay</name>
+      <longname>RTP KLV Payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payloads KLV (SMPTE ST 336) metadata as RTP packets</description>
+      <author>Tim-Philipp Müller &lt;tim@centricular.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>meta/x-klv, parsed=(boolean)true</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)application, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)SMPTE336M</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpmp1sdepay</name>
+      <longname>RTP MPEG1 System Stream depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts MPEG1 System Streams from RTP packets (RFC 3555)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)other, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)MP1S; application/x-rtp, media=(string)video, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)MP1S</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/mpeg, systemstream=(boolean)true</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpmp2tdepay</name>
+      <longname>RTP MPEG Transport Stream depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts MPEG2 TS from RTP packets (RFC 2250)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;, Thijs Vermeir &lt;thijs.vermeir@barco.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string){ MP2T, MP2T-ES }; application/x-rtp, media=(string)video, payload=(int)33, clock-rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/mpegts, packetsize=(int)188, systemstream=(boolean)true</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpmp2tpay</name>
+      <longname>RTP MPEG2 Transport Stream payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encodes MPEG2 TS into RTP packets (RFC 2250)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/mpegts, packetsize=(int)188, systemstream=(boolean)true</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, payload=(int)33, clock-rate=(int)90000, encoding-name=(string)MP2T; application/x-rtp, media=(string)video, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)MP2T</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpmp4adepay</name>
+      <longname>RTP MPEG4 audio depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts MPEG4 audio from RTP packets (RFC 3016)</description>
+      <author>Nokia Corporation (contact &lt;stefan.kost@nokia.com&gt;), Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)MP4A-LATM</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/mpeg, mpegversion=(int)4, framed=(boolean){ false, true }, stream-format=(string)raw</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpmp4apay</name>
+      <longname>RTP MPEG4 audio payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload MPEG4 audio as RTP packets (RFC 3016)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/mpeg, mpegversion=(int)4, stream-format=(string)raw</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)MP4A-LATM</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpmp4gdepay</name>
+      <longname>RTP MPEG4 ES depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts MPEG4 elementary streams from RTP packets (RFC 3640)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string){ video, audio, application }, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)MPEG4-GENERIC, mode=(string){ generic, CELP-cbr, CELP-vbr, AAC-lbr, AAC-hbr }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/mpeg, mpegversion=(int)4, systemstream=(boolean)false; audio/mpeg, mpegversion=(int)4, stream-format=(string)raw</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpmp4gpay</name>
+      <longname>RTP MPEG4 ES payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload MPEG4 elementary streams as RTP packets (RFC 3640)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/mpeg, mpegversion=(int)4, systemstream=(boolean)false; audio/mpeg, mpegversion=(int)4, stream-format=(string)raw</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string){ video, audio, application }, payload=(int)[ 96, 127 ], clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)MPEG4-GENERIC, streamtype=(string){ 4, 5 }, mode=(string){ generic, CELP-cbr, CELP-vbr, AAC-lbr, AAC-hbr }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpmp4vdepay</name>
+      <longname>RTP MPEG4 video depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts MPEG4 video from RTP packets (RFC 3016)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)MP4V-ES</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/mpeg, mpegversion=(int)4, systemstream=(boolean)false</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpmp4vpay</name>
+      <longname>RTP MPEG4 Video payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload MPEG-4 video as RTP packets (RFC 3016)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/mpeg, mpegversion=(int)4, systemstream=(boolean)false; video/x-divx</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, payload=(int)[ 96, 127 ], clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)MP4V-ES</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpmpadepay</name>
+      <longname>RTP MPEG audio depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts MPEG audio from RTP packets (RFC 2038)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)14, clock-rate=(int)90000; application/x-rtp, media=(string)audio, encoding-name=(string)MPA, clock-rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/mpeg, mpegversion=(int)1</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpmpapay</name>
+      <longname>RTP MPEG audio payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload MPEG audio as RTP packets (RFC 2038)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/mpeg, mpegversion=(int)1</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)14, clock-rate=(int)90000; application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)MPA</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpmparobustdepay</name>
+      <longname>RTP MPEG audio depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts MPEG audio from RTP packets (RFC 5219)</description>
+      <author>Mark Nauwelaerts &lt;mark.nauwelaerts@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)90000, encoding-name=(string)MPA-ROBUST; application/x-rtp, media=(string)audio, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string){ X-MP3-DRAFT-00, X-MP3-DRAFT-01, X-MP3-DRAFT-02, X-MP3-DRAFT-03, X-MP3-DRAFT-04, X-MP3-DRAFT-05, X-MP3-DRAFT-06 }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/mpeg, mpegversion=(int)1</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpmpvdepay</name>
+      <longname>RTP MPEG video depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts MPEG video from RTP packets (RFC 2250)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)MPV; application/x-rtp, media=(string)video, payload=(int)32, clock-rate=(int)90000</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/mpeg, mpegversion=(int)2, systemstream=(boolean)false</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpmpvpay</name>
+      <longname>RTP MPEG2 ES video payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encodes MPEG2 ES into RTP packets (RFC 2250)</description>
+      <author>Thijs Vermeir &lt;thijsvermeir@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/mpeg, mpegversion=(int)2, systemstream=(boolean)false</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, payload=(int)32, clock-rate=(int)90000, encoding-name=(string)MPV; application/x-rtp, media=(string)video, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)MPV</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpopusdepay</name>
+      <longname>RTP Opus packet depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts Opus audio from RTP packets</description>
+      <author>Danilo Cesar Lemes de Paula &lt;danilo.cesar@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)48000, encoding-name=(string){ OPUS, X-GST-OPUS-DRAFT-SPITTKA-00 }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-opus, channel-mapping-family=(int)0</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpopuspay</name>
+      <longname>RTP Opus payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Puts Opus audio in RTP packets</description>
+      <author>Danilo Cesar Lemes de Paula &lt;danilo.cesar@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-opus, channels=(int)[ 1, 2 ], channel-mapping-family=(int)0</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)48000, encoding-params=(string)2, encoding-name=(string){ OPUS, X-GST-OPUS-DRAFT-SPITTKA-00 }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtppcmadepay</name>
+      <longname>RTP PCMA depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts PCMA audio from RTP packets</description>
+      <author>Edgard Lima &lt;edgard.lima@gmail.com&gt;, Zeeshan Ali &lt;zeenix@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)8, clock-rate=(int)8000; application/x-rtp, media=(string)audio, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)PCMA</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-alaw, channels=(int)1, rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtppcmapay</name>
+      <longname>RTP PCMA payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encodes PCMA audio into a RTP packet</description>
+      <author>Edgard Lima &lt;edgard.lima@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-alaw, channels=(int)1, rate=(int)8000</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)8, clock-rate=(int)8000, encoding-name=(string)PCMA; application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)PCMA</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtppcmudepay</name>
+      <longname>RTP PCMU depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts PCMU audio from RTP packets</description>
+      <author>Edgard Lima &lt;edgard.lima@gmail.com&gt;, Zeeshan Ali &lt;zeenix@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)0, clock-rate=(int)8000; application/x-rtp, media=(string)audio, encoding-name=(string)PCMU, clock-rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-mulaw, channels=(int)1, rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtppcmupay</name>
+      <longname>RTP PCMU payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encodes PCMU audio into a RTP packet</description>
+      <author>Edgard Lima &lt;edgard.lima@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-mulaw, channels=(int)1, rate=(int)8000</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)0, clock-rate=(int)8000, encoding-name=(string)PCMU; application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)PCMU</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpqcelpdepay</name>
+      <longname>RTP QCELP depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts QCELP (PureVoice) audio from RTP packets (RFC 2658)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)8000, encoding-name=(string)QCELP; application/x-rtp, media=(string)audio, payload=(int)12, clock-rate=(int)8000</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/qcelp, channels=(int)1, rate=(int)8000</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpqdm2depay</name>
+      <longname>RTP QDM2 depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts QDM2 audio from RTP packets (no RFC)</description>
+      <author>Edward Hervey &lt;bilboed@bilboed.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, encoding-name=(string)X-QDM</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-qdm2</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpsbcdepay</name>
+      <longname>RTP SBC audio depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts SBC audio from RTP packets</description>
+      <author>Arun Raghavan &lt;arun.raghavan@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int){ 16000, 32000, 44100, 48000 }, encoding-name=(string)SBC</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-sbc, rate=(int){ 16000, 32000, 44100, 48000 }, channels=(int)[ 1, 2 ], mode=(string){ mono, dual, stereo, joint }, blocks=(int){ 4, 8, 12, 16 }, subbands=(int){ 4, 8 }, allocation-method=(string){ snr, loudness }, bitpool=(int)[ 2, 64 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpsbcpay</name>
+      <longname>RTP packet payloader</longname>
+      <class>Codec/Payloader/Network</class>
+      <description>Payload SBC audio as RTP packets</description>
+      <author>Thiago Sousa Santos &lt;thiagoss@lcc.ufcg.edu.br&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-sbc, rate=(int){ 16000, 32000, 44100, 48000 }, channels=(int)[ 1, 2 ], channel-mode=(string){ mono, dual, stereo, joint }, blocks=(int){ 4, 8, 12, 16 }, subbands=(int){ 4, 8 }, allocation-method=(string){ snr, loudness }, bitpool=(int)[ 2, 64 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int){ 16000, 32000, 44100, 48000 }, encoding-name=(string)SBC</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpsirendepay</name>
+      <longname>RTP Siren packet depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts Siren audio from RTP packets</description>
+      <author>Philippe Kalaf &lt;philippe.kalaf@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)16000, encoding-name=(string)SIREN</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-siren, dct-length=(int)320</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpsirenpay</name>
+      <longname>RTP Payloader for Siren Audio</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Packetize Siren audio streams into RTP packets</description>
+      <author>Youness Alaoui &lt;kakaroto@kakaroto.homelinux.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-siren, dct-length=(int)320</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)16000, encoding-name=(string)SIREN, bitrate=(string)16000, dct-length=(int)320</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpspeexdepay</name>
+      <longname>RTP Speex depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts Speex audio from RTP packets</description>
+      <author>Edgard Lima &lt;edgard.lima@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)[ 6000, 48000 ], encoding-name=(string)SPEEX</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-speex</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpspeexpay</name>
+      <longname>RTP Speex payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encodes Speex audio into a RTP packet</description>
+      <author>Edgard Lima &lt;edgard.lima@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-speex, rate=(int)[ 6000, 48000 ], channels=(int)1</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)[ 6000, 48000 ], encoding-name=(string)SPEEX, encoding-params=(string)1</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpstreamdepay</name>
+      <longname>RTP Stream Depayloading</longname>
+      <class>Codec/Depayloader/Network</class>
+      <description>Depayloads RTP/RTCP packets for streaming protocols according to RFC4571</description>
+      <author>Sebastian Dröge &lt;sebastian@centricular.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp-stream; application/x-rtcp-stream; application/x-srtp-stream; application/x-srtcp-stream</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp; application/x-rtcp; application/x-srtp; application/x-srtcp</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpstreampay</name>
+      <longname>RTP Stream Payloading</longname>
+      <class>Codec/Payloader/Network</class>
+      <description>Payloads RTP/RTCP packets for streaming protocols according to RFC4571</description>
+      <author>Sebastian Dröge &lt;sebastian@centricular.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp; application/x-rtcp; application/x-srtp; application/x-srtcp</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp-stream; application/x-rtcp-stream; application/x-srtp-stream; application/x-srtcp-stream</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpsv3vdepay</name>
+      <longname>RTP SVQ3 depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts SVQ3 video from RTP packets (no RFC)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string){ X-SV3V-ES, X-SORENSON-VIDEO, X-SORENSONVIDEO, X-SorensonVideo }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-svq, svqversion=(int)3</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtptheoradepay</name>
+      <longname>RTP Theora depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts Theora video from RTP packets (draft-01 of RFC XXXX)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)THEORA</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-theora</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtptheorapay</name>
+      <longname>RTP Theora payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encode Theora video into RTP packets (draft-01 RFC XXXX)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-theora</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)THEORA</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpvorbisdepay</name>
+      <longname>RTP Vorbis depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts Vorbis Audio from RTP packets (RFC 5215)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)VORBIS</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-vorbis</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpvorbispay</name>
+      <longname>RTP Vorbis payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload-encode Vorbis audio into RTP packets (RFC 5215)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-vorbis</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)audio, payload=(int)[ 96, 127 ], clock-rate=(int)[ 1, 2147483647 ], encoding-name=(string)VORBIS</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpvp8depay</name>
+      <longname>RTP VP8 depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts VP8 video from RTP packets)</description>
+      <author>Sjoerd Simons &lt;sjoerd@luon.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, clock-rate=(int)90000, media=(string)video, encoding-name=(string){ VP8, VP8-DRAFT-IETF-01 }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-vp8</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpvp8pay</name>
+      <longname>RTP VP8 payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Puts VP8 video in RTP packets</description>
+      <author>Sjoerd Simons &lt;sjoerd@luon.net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-vp8</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string){ VP8, VP8-DRAFT-IETF-01 }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpvp9depay</name>
+      <longname>RTP VP9 depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts VP9 video from RTP packets)</description>
+      <author>Stian Selnes &lt;stian@pexip.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, clock-rate=(int)90000, media=(string)video, encoding-name=(string){ VP9, VP9-DRAFT-IETF-01 }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-vp9</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpvp9pay</name>
+      <longname>RTP VP9 payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Puts VP9 video in RTP packets)</description>
+      <author>Stian Selnes &lt;stian@pexip.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-vp9</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string){ VP9, VP9-DRAFT-IETF-01 }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpvrawdepay</name>
+      <longname>RTP Raw Video depayloader</longname>
+      <class>Codec/Depayloader/Network/RTP</class>
+      <description>Extracts raw video from RTP packets (RFC 4175)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)RAW, sampling=(string){ RGB, RGBA, BGR, BGRA, YCbCr-4:4:4, YCbCr-4:2:2, YCbCr-4:2:0, YCbCr-4:1:1 }, depth=(string){ 8, 10, 12, 16 }</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpvrawpay</name>
+      <longname>RTP Raw Video payloader</longname>
+      <class>Codec/Payloader/Network/RTP</class>
+      <description>Payload raw video as RTP packets (RFC 4175)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGB, RGBA, BGR, BGRA, AYUV, UYVY, I420, Y41B, UYVP }, width=(int)[ 1, 32767 ], height=(int)[ 1, 32767 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, media=(string)video, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)RAW, sampling=(string){ RGB, RGBA, BGR, BGRA, YCbCr-4:4:4, YCbCr-4:2:2, YCbCr-4:2:0, YCbCr-4:1:1 }, depth=(string){ 8, 10, 12, 16 }, colorimetry=(string){ BT601-5, BT709-2, SMPTE240M }</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-rtpmanager.xml b/docs/plugins/inspect/plugin-rtpmanager.xml
new file mode 100644
index 0000000..d84eeaf
--- /dev/null
+++ b/docs/plugins/inspect/plugin-rtpmanager.xml
@@ -0,0 +1,301 @@
+<plugin>
+  <name>rtpmanager</name>
+  <description>RTP session management plugin library</description>
+  <filename>../../gst/rtpmanager/.libs/libgstrtpmanager.so</filename>
+  <basename>libgstrtpmanager.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>rtpbin</name>
+      <longname>RTP Bin</longname>
+      <class>Filter/Network/RTP</class>
+      <description>Real-Time Transport Protocol bin</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>recv_rtcp_sink_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>application/x-rtcp; application/x-srtcp</details>
+        </caps>
+        <caps>
+          <name>recv_rtp_sink_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>application/x-rtp; application/x-srtp</details>
+        </caps>
+        <caps>
+          <name>send_rtp_sink_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>recv_rtp_src_%u_%u_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>send_rtp_src_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>application/x-rtp; application/x-srtp</details>
+        </caps>
+        <caps>
+          <name>send_rtcp_src_%u</name>
+          <direction>source</direction>
+          <presence>request</presence>
+          <details>application/x-rtcp; application/x-srtcp</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpdtmfmux</name>
+      <longname>RTP muxer</longname>
+      <class>Codec/Muxer</class>
+      <description>mixes RTP DTMF streams into other RTP streams</description>
+      <author>Zeeshan Ali &lt;first.last@nokia.com&gt;</author>
+      <pads>
+        <caps>
+          <name>priority_sink_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>sink_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpjitterbuffer</name>
+      <longname>RTP packet jitter-buffer</longname>
+      <class>Filter/Network/RTP</class>
+      <description>A buffer that deals with network jitter and other transmission faults</description>
+      <author>Philippe Kalaf &lt;philippe.kalaf@collabora.co.uk&gt;, Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>sink_rtcp</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>application/x-rtcp</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpmux</name>
+      <longname>RTP muxer</longname>
+      <class>Codec/Muxer</class>
+      <description>multiplex N rtp streams into one</description>
+      <author>Zeeshan Ali &lt;first.last@nokia.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpptdemux</name>
+      <longname>RTP Demux</longname>
+      <class>Demux/Network/RTP</class>
+      <description>Parses codec streams transmitted in the same RTP session</description>
+      <author>Kai Vehmanen &lt;kai.vehmanen@nokia.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>src_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>application/x-rtp, payload=(int)[ 0, 255 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtprtxqueue</name>
+      <longname>RTP Retransmission Queue</longname>
+      <class>Codec</class>
+      <description>Keep RTP packets in a queue for retransmission</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtprtxreceive</name>
+      <longname>RTP Retransmission receiver</longname>
+      <class>Codec</class>
+      <description>Receive retransmitted RTP packets according to RFC4588</description>
+      <author>Julien Isorce &lt;julien.isorce@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtprtxsend</name>
+      <longname>RTP Retransmission Sender</longname>
+      <class>Codec</class>
+      <description>Retransmit RTP packets when needed, according to RFC4588</description>
+      <author>Julien Isorce &lt;julien.isorce@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp, clock-rate=(int)[ 1, 2147483647 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-rtp</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpsession</name>
+      <longname>RTP Session</longname>
+      <class>Filter/Network/RTP</class>
+      <description>Implement an RTP session</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>recv_rtcp_sink</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>application/x-rtcp</details>
+        </caps>
+        <caps>
+          <name>recv_rtp_sink</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>send_rtp_sink</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>recv_rtp_src</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>send_rtp_src</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>sync_src</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>application/x-rtcp</details>
+        </caps>
+        <caps>
+          <name>send_rtcp_src</name>
+          <direction>source</direction>
+          <presence>request</presence>
+          <details>application/x-rtcp</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtpssrcdemux</name>
+      <longname>RTP SSRC Demux</longname>
+      <class>Demux/Network/RTP</class>
+      <description>Splits RTP streams based on the SSRC</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>rtcp_sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtcp</details>
+        </caps>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>rtcp_src_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>application/x-rtcp</details>
+        </caps>
+        <caps>
+          <name>src_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>application/x-rtp</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-rtsp.xml b/docs/plugins/inspect/plugin-rtsp.xml
new file mode 100644
index 0000000..75529b4
--- /dev/null
+++ b/docs/plugins/inspect/plugin-rtsp.xml
@@ -0,0 +1,61 @@
+<plugin>
+  <name>rtsp</name>
+  <description>transfer data via RTSP</description>
+  <filename>../../gst/rtsp/.libs/libgstrtsp.so</filename>
+  <basename>libgstrtsp.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>rtpdec</name>
+      <longname>RTP Decoder</longname>
+      <class>Codec/Parser/Network</class>
+      <description>Accepts raw RTP and RTCP packets and sends them forward</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>recv_rtcp_sink_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>application/x-rtcp</details>
+        </caps>
+        <caps>
+          <name>recv_rtp_sink_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>recv_rtp_src_%u_%u_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>application/x-rtp</details>
+        </caps>
+        <caps>
+          <name>rtcp_src_%u</name>
+          <direction>source</direction>
+          <presence>request</presence>
+          <details>application/x-rtcp</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>rtspsrc</name>
+      <longname>RTSP packet receiver</longname>
+      <class>Source/Network</class>
+      <description>Receive data over the network via RTSP (RFC 2326)</description>
+      <author>Wim Taymans &lt;wim@fluendo.com&gt;, Thijs Vermeir &lt;thijs.vermeir@barco.com&gt;, Lutz Mueller &lt;lutz@topfrose.de&gt;</author>
+      <pads>
+        <caps>
+          <name>stream_%u</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>application/x-rtp; application/x-rdt</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-shapewipe.xml b/docs/plugins/inspect/plugin-shapewipe.xml
new file mode 100644
index 0000000..4d322f1
--- /dev/null
+++ b/docs/plugins/inspect/plugin-shapewipe.xml
@@ -0,0 +1,40 @@
+<plugin>
+  <name>shapewipe</name>
+  <description>Shape Wipe transition filter</description>
+  <filename>../../gst/shapewipe/.libs/libgstshapewipe.so</filename>
+  <basename>libgstshapewipe.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>shapewipe</name>
+      <longname>Shape Wipe transition filter</longname>
+      <class>Filter/Editor/Video</class>
+      <description>Adds a shape wipe transition to a video stream</description>
+      <author>Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>mask_sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)GRAY8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)0/1; video/x-raw, format=(string)GRAY16_LE, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)0/1</details>
+        </caps>
+        <caps>
+          <name>video_sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ AYUV, ARGB, BGRA, ABGR, RGBA }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ AYUV, ARGB, BGRA, ABGR, RGBA }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-shout2.xml b/docs/plugins/inspect/plugin-shout2.xml
new file mode 100644
index 0000000..4a13a1a
--- /dev/null
+++ b/docs/plugins/inspect/plugin-shout2.xml
@@ -0,0 +1,28 @@
+<plugin>
+  <name>shout2</name>
+  <description>Sends data to an icecast server using libshout2</description>
+  <filename>../../ext/shout2/.libs/libgstshout2.so</filename>
+  <basename>libgstshout2.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>shout2send</name>
+      <longname>Icecast network sink</longname>
+      <class>Sink/Network</class>
+      <description>Sends data to an icecast server</description>
+      <author>Wim Taymans &lt;wim.taymans@chello.be&gt;, Pedro Corte-Real &lt;typo@netcabo.pt&gt;, Zaheer Abbas Merali &lt;zaheerabbas at merali dot org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>application/ogg; audio/ogg; video/ogg; audio/mpeg, mpegversion=(int)1, layer=(int)[ 1, 3 ]; video/webm; audio/webm</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-smpte.xml b/docs/plugins/inspect/plugin-smpte.xml
new file mode 100644
index 0000000..bed10e9
--- /dev/null
+++ b/docs/plugins/inspect/plugin-smpte.xml
@@ -0,0 +1,61 @@
+<plugin>
+  <name>smpte</name>
+  <description>Apply the standard SMPTE transitions on video images</description>
+  <filename>../../gst/smpte/.libs/libgstsmpte.so</filename>
+  <basename>libgstsmpte.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>smpte</name>
+      <longname>SMPTE transitions</longname>
+      <class>Filter/Editor/Video</class>
+      <description>Apply the standard SMPTE transitions on video images</description>
+      <author>Wim Taymans &lt;wim.taymans@chello.be&gt;</author>
+      <pads>
+        <caps>
+          <name>sink1</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)I420, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>sink2</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)I420, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)I420, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>smptealpha</name>
+      <longname>SMPTE transitions</longname>
+      <class>Filter/Editor/Video</class>
+      <description>Apply the standard SMPTE transitions as alpha on video images</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)I420, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string)YV12, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string)AYUV, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string)ARGB, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string)BGRA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string)ARGB, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)AYUV, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string)ARGB, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string)BGRA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string)ARGB, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-soup.xml b/docs/plugins/inspect/plugin-soup.xml
new file mode 100644
index 0000000..7b2c62e
--- /dev/null
+++ b/docs/plugins/inspect/plugin-soup.xml
@@ -0,0 +1,43 @@
+<plugin>
+  <name>soup</name>
+  <description>libsoup HTTP client src/sink</description>
+  <filename>../../ext/soup/.libs/libgstsoup.so</filename>
+  <basename>libgstsoup.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>souphttpclientsink</name>
+      <longname>HTTP client sink</longname>
+      <class>Generic</class>
+      <description>Sends streams to HTTP server via PUT</description>
+      <author>David Schleef &lt;ds@entropywave.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>souphttpsrc</name>
+      <longname>HTTP client source</longname>
+      <class>Source/Network</class>
+      <description>Receive data as a client over the network via HTTP using SOUP</description>
+      <author>Wouter Cloetens &lt;wouter@mind.be&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-spectrum.xml b/docs/plugins/inspect/plugin-spectrum.xml
new file mode 100644
index 0000000..a5bdd3c
--- /dev/null
+++ b/docs/plugins/inspect/plugin-spectrum.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>spectrum</name>
+  <description>Run an FFT on the audio signal, output spectrum data</description>
+  <filename>../../gst/spectrum/.libs/libgstspectrum.so</filename>
+  <basename>libgstspectrum.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>spectrum</name>
+      <longname>Spectrum analyzer</longname>
+      <class>Filter/Analyzer/Audio</class>
+      <description>Run an FFT on the audio signal, output spectrum data</description>
+      <author>Erik Walthinsen &lt;omega@cse.ogi.edu&gt;, Stefan Kost &lt;ensonic@users.sf.net&gt;, Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, S24LE, S32LE, F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ S16LE, S24LE, S32LE, F32LE, F64LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-speex.xml b/docs/plugins/inspect/plugin-speex.xml
new file mode 100644
index 0000000..f7839db
--- /dev/null
+++ b/docs/plugins/inspect/plugin-speex.xml
@@ -0,0 +1,55 @@
+<plugin>
+  <name>speex</name>
+  <description>Speex plugin library</description>
+  <filename>../../ext/speex/.libs/libgstspeex.so</filename>
+  <basename>libgstspeex.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>speexdec</name>
+      <longname>Speex audio decoder</longname>
+      <class>Codec/Decoder/Audio</class>
+      <description>decode speex streams to audio</description>
+      <author>Wim Taymans &lt;wim@fluendo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-speex</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S16LE, layout=(string)interleaved, rate=(int)[ 6000, 48000 ], channels=(int)[ 1, 2 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>speexenc</name>
+      <longname>Speex audio encoder</longname>
+      <class>Codec/Encoder/Audio</class>
+      <description>Encodes audio in Speex format</description>
+      <author>Wim Taymans &lt;wim@fluendo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S16LE, layout=(string)interleaved, rate=(int)[ 6000, 48000 ], channels=(int)1; audio/x-raw, format=(string)S16LE, layout=(string)interleaved, rate=(int)[ 6000, 48000 ], channels=(int)2, channel-mask=(bitmask)0x0000000000000003</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-speex, rate=(int)[ 6000, 48000 ], channels=(int)[ 1, 2 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-taglib.xml b/docs/plugins/inspect/plugin-taglib.xml
new file mode 100644
index 0000000..1913fa9
--- /dev/null
+++ b/docs/plugins/inspect/plugin-taglib.xml
@@ -0,0 +1,55 @@
+<plugin>
+  <name>taglib</name>
+  <description>Tag writing plug-in based on taglib</description>
+  <filename>../../ext/taglib/.libs/libgsttaglib.so</filename>
+  <basename>libgsttaglib.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>apev2mux</name>
+      <longname>TagLib-based APEv2 Muxer</longname>
+      <class>Formatter/Metadata</class>
+      <description>Adds an APEv2 header to the beginning of files using taglib</description>
+      <author>Sebastian Dröge &lt;slomo@circular-chaos.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-apetag</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>id3v2mux</name>
+      <longname>TagLib-based ID3v2 Muxer</longname>
+      <class>Formatter/Metadata</class>
+      <description>Adds an ID3v2 header to the beginning of MP3 files using taglib</description>
+      <author>Christophe Fergeau &lt;teuf@gnome.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-id3</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-twolame.xml b/docs/plugins/inspect/plugin-twolame.xml
new file mode 100644
index 0000000..5f0a9bd
--- /dev/null
+++ b/docs/plugins/inspect/plugin-twolame.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>twolame</name>
+  <description>Encode MP2s with TwoLAME</description>
+  <filename>../../ext/twolame/.libs/libgsttwolame.so</filename>
+  <basename>libgsttwolame.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>twolamemp2enc</name>
+      <longname>TwoLAME mp2 encoder</longname>
+      <class>Codec/Encoder/Audio</class>
+      <description>High-quality free MP2 encoder</description>
+      <author>Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string){ F32LE, S16LE }, layout=(string)interleaved, rate=(int){ 16000, 22050, 24000, 32000, 44100, 48000 }, channels=(int)1; audio/x-raw, format=(string){ F32LE, S16LE }, layout=(string)interleaved, rate=(int){ 16000, 22050, 24000, 32000, 44100, 48000 }, channels=(int)2, channel-mask=(bitmask)0x0000000000000003</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/mpeg, mpegversion=(int)1, layer=(int)2, rate=(int){ 16000, 22050, 24000, 32000, 44100, 48000 }, channels=(int)[ 1, 2 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-udp.xml b/docs/plugins/inspect/plugin-udp.xml
new file mode 100644
index 0000000..8b9ba71
--- /dev/null
+++ b/docs/plugins/inspect/plugin-udp.xml
@@ -0,0 +1,73 @@
+<plugin>
+  <name>udp</name>
+  <description>transfer data via UDP</description>
+  <filename>../../gst/udp/.libs/libgstudp.so</filename>
+  <basename>libgstudp.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>dynudpsink</name>
+      <longname>UDP packet sender</longname>
+      <class>Sink/Network</class>
+      <description>Send data over the network via UDP with packet destinations picked up dynamically from meta on the buffers passed</description>
+      <author>Philippe Khalaf &lt;burger@speedy.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>multiudpsink</name>
+      <longname>UDP packet sender</longname>
+      <class>Sink/Network</class>
+      <description>Send data over the network via UDP to one or multiple recipients which can be added or removed at runtime using action signals</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>udpsink</name>
+      <longname>UDP packet sender</longname>
+      <class>Sink/Network</class>
+      <description>Send data over the network via UDP</description>
+      <author>Wim Taymans &lt;wim@fluendo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>udpsrc</name>
+      <longname>UDP packet receiver</longname>
+      <class>Source/Network</class>
+      <description>Receive data over the network via UDP</description>
+      <author>Wim Taymans &lt;wim@fluendo.com&gt;, Thijs Vermeir &lt;thijs.vermeir@barco.com&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>ANY</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-video4linux2.xml b/docs/plugins/inspect/plugin-video4linux2.xml
new file mode 100644
index 0000000..2e91a24
--- /dev/null
+++ b/docs/plugins/inspect/plugin-video4linux2.xml
@@ -0,0 +1,52 @@
+<plugin>
+  <name>video4linux2</name>
+  <description>elements for Video 4 Linux</description>
+  <filename>../../sys/v4l2/.libs/libgstvideo4linux2.so</filename>
+  <basename>libgstvideo4linux2.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>v4l2radio</name>
+      <longname>Radio (video4linux2) Tuner</longname>
+      <class>Tuner</class>
+      <description>Controls a Video4Linux2 radio device</description>
+      <author>Alexey Chernov &lt;4ernov@gmail.com&gt;</author>
+      <pads>
+      </pads>
+    </element>
+    <element>
+      <name>v4l2sink</name>
+      <longname>Video (video4linux2) Sink</longname>
+      <class>Sink/Video</class>
+      <description>Displays frames on a video4linux2 device</description>
+      <author>Rob Clark &lt;rob@ti.com&gt;,</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>image/jpeg; video/mpeg, mpegversion=(int)4, systemstream=(boolean)false; video/mpeg, mpegversion=(int)2; video/mpegts, systemstream=(boolean)true; video/x-bayer, format=(string){ bggr, gbrg, grbg, rggb }, width=(int)[ 1, 32768 ], height=(int)[ 1, 32768 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-dv, systemstream=(boolean)true; video/x-h263, variant=(string)itu; video/x-h264, stream-format=(string){ byte-stream, avc }, alignment=(string)au; video/x-pwc1, width=(int)[ 1, 32768 ], height=(int)[ 1, 32768 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-pwc2, width=(int)[ 1, 32768 ], height=(int)[ 1, 32768 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string){ RGB16, BGR, RGB, GRAY8, GRAY16_LE, GRAY16_BE, YVU9, YV12, YUY2, YVYU, UYVY, Y42B, Y41B, YUV9, NV12_64Z32, NV24, NV61, NV16, NV21, NV12, I420, BGRA, BGRx, ARGB, xRGB, BGR15, RGB15 }, width=(int)[ 1, 32768 ], height=(int)[ 1, 32768 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-sonix, width=(int)[ 1, 32768 ], height=(int)[ 1, 32768 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-vp8; video/x-vp9; video/x-wmv, wmvversion=(int)3, format=(string)WVC1</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>v4l2src</name>
+      <longname>Video (video4linux2) Source</longname>
+      <class>Source/Video</class>
+      <description>Reads frames from a Video4Linux2 device</description>
+      <author>Edgard Lima &lt;edgard.lima@gmail.com&gt;, Stefan Kost &lt;ensonic@users.sf.net&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>image/jpeg; video/mpeg, mpegversion=(int)4, systemstream=(boolean)false; video/mpeg, mpegversion=(int)2; video/mpegts, systemstream=(boolean)true; video/x-bayer, format=(string){ bggr, gbrg, grbg, rggb }, width=(int)[ 1, 32768 ], height=(int)[ 1, 32768 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-dv, systemstream=(boolean)true; video/x-h263, variant=(string)itu; video/x-h264, stream-format=(string){ byte-stream, avc }, alignment=(string)au; video/x-pwc1, width=(int)[ 1, 32768 ], height=(int)[ 1, 32768 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-pwc2, width=(int)[ 1, 32768 ], height=(int)[ 1, 32768 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string){ RGB16, BGR, RGB, GRAY8, GRAY16_LE, GRAY16_BE, YVU9, YV12, YUY2, YVYU, UYVY, Y42B, Y41B, YUV9, NV12_64Z32, NV24, NV61, NV16, NV21, NV12, I420, BGRA, BGRx, ARGB, xRGB, BGR15, RGB15 }, width=(int)[ 1, 32768 ], height=(int)[ 1, 32768 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-sonix, width=(int)[ 1, 32768 ], height=(int)[ 1, 32768 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-vp8; video/x-vp9; video/x-wmv, wmvversion=(int)3, format=(string)WVC1</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-videobox.xml b/docs/plugins/inspect/plugin-videobox.xml
new file mode 100644
index 0000000..3737958
--- /dev/null
+++ b/docs/plugins/inspect/plugin-videobox.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>videobox</name>
+  <description>resizes a video by adding borders or cropping</description>
+  <filename>../../gst/videobox/.libs/libgstvideobox.so</filename>
+  <basename>libgstvideobox.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>videobox</name>
+      <longname>Video box filter</longname>
+      <class>Filter/Effect/Video</class>
+      <description>Resizes a video by adding borders or cropping</description>
+      <author>Wim Taymans &lt;wim@fluendo.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ AYUV, ARGB, BGRA, ABGR, RGBA, xRGB, BGRx, xBGR, RGBx, RGB, BGR, Y444, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B, GRAY8, GRAY16_BE, GRAY16_LE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ AYUV, ARGB, BGRA, ABGR, RGBA, xRGB, BGRx, xBGR, RGBx, RGB, BGR, Y444, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B, GRAY8, GRAY16_BE, GRAY16_LE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-videocrop.xml b/docs/plugins/inspect/plugin-videocrop.xml
new file mode 100644
index 0000000..9ea6609
--- /dev/null
+++ b/docs/plugins/inspect/plugin-videocrop.xml
@@ -0,0 +1,55 @@
+<plugin>
+  <name>videocrop</name>
+  <description>Crops video into a user-defined region</description>
+  <filename>../../gst/videocrop/.libs/libgstvideocrop.so</filename>
+  <basename>libgstvideocrop.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>aspectratiocrop</name>
+      <longname>aspectratiocrop</longname>
+      <class>Filter/Effect/Video</class>
+      <description>Crops video into a user-defined aspect-ratio</description>
+      <author>Thijs Vermeir &lt;thijsvermeir@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBx, xRGB, BGRx, xBGR, RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, YVYU, UYVY, I420, YV12, RGB16, RGB15, GRAY8, NV12, NV21, GRAY16_LE, GRAY16_BE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBx, xRGB, BGRx, xBGR, RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, YVYU, UYVY, I420, YV12, RGB16, RGB15, GRAY8, NV12, NV21, GRAY16_LE, GRAY16_BE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>videocrop</name>
+      <longname>Crop</longname>
+      <class>Filter/Effect/Video</class>
+      <description>Crops video into a user-defined region</description>
+      <author>Tim-Philipp Müller &lt;tim centricular net&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBx, xRGB, BGRx, xBGR, RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, YVYU, UYVY, I420, YV12, RGB16, RGB15, GRAY8, NV12, NV21, GRAY16_LE, GRAY16_BE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ RGBx, xRGB, BGRx, xBGR, RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, YVYU, UYVY, I420, YV12, RGB16, RGB15, GRAY8, NV12, NV21, GRAY16_LE, GRAY16_BE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-videofilter.xml b/docs/plugins/inspect/plugin-videofilter.xml
new file mode 100644
index 0000000..5d1d312
--- /dev/null
+++ b/docs/plugins/inspect/plugin-videofilter.xml
@@ -0,0 +1,97 @@
+<plugin>
+  <name>videofilter</name>
+  <description>Video filters plugin</description>
+  <filename>../../gst/videofilter/.libs/libgstvideofilter.so</filename>
+  <basename>libgstvideofilter.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>gamma</name>
+      <longname>Video gamma correction</longname>
+      <class>Filter/Effect/Video</class>
+      <description>Adjusts gamma on a video stream</description>
+      <author>Arwed v. Merkatz &lt;v.merkatz@gmx.net</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, Y42B, NV12, NV21, YUY2, UYVY, YVYU, I420, YV12, IYUV, Y41B }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, Y42B, NV12, NV21, YUY2, UYVY, YVYU, I420, YV12, IYUV, Y41B }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>videobalance</name>
+      <longname>Video balance</longname>
+      <class>Filter/Effect/Video</class>
+      <description>Adjusts brightness, contrast, hue, saturation on a video stream</description>
+      <author>David Schleef &lt;ds@schleef.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, Y42B, YUY2, UYVY, YVYU, I420, YV12, IYUV, Y41B, NV12, NV21 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(ANY)</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, Y42B, YUY2, UYVY, YVYU, I420, YV12, IYUV, Y41B, NV12, NV21 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(ANY)</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>videoflip</name>
+      <longname>Video flipper</longname>
+      <class>Filter/Effect/Video</class>
+      <description>Flips and rotates video</description>
+      <author>David Schleef &lt;ds@schleef.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21, GRAY8, GRAY16_BE, GRAY16_LE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21, GRAY8, GRAY16_BE, GRAY16_LE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>videomedian</name>
+      <longname>Median effect</longname>
+      <class>Filter/Effect/Video</class>
+      <description>Apply a median filter to an image</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ I420, YV12 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ I420, YV12 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-videomixer.xml b/docs/plugins/inspect/plugin-videomixer.xml
new file mode 100644
index 0000000..a3463f8
--- /dev/null
+++ b/docs/plugins/inspect/plugin-videomixer.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>videomixer</name>
+  <description>Video mixer</description>
+  <filename>../../gst/videomixer/.libs/libgstvideomixer.so</filename>
+  <basename>libgstvideomixer.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>videomixer</name>
+      <longname>Video mixer 2</longname>
+      <class>Filter/Editor/Video/Compositor</class>
+      <description>Mix multiple video streams</description>
+      <author>Wim Taymans &lt;wim@fluendo.com&gt;, Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink_%u</name>
+          <direction>sink</direction>
+          <presence>request</presence>
+          <details>video/x-raw, format=(string){ AYUV, BGRA, ARGB, RGBA, ABGR, Y444, Y42B, YUY2, UYVY, YVYU, I420, YV12, NV12, NV21, Y41B, RGB, BGR, xRGB, xBGR, RGBx, BGRx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ AYUV, BGRA, ARGB, RGBA, ABGR, Y444, Y42B, YUY2, UYVY, YVYU, I420, YV12, NV12, NV21, Y41B, RGB, BGR, xRGB, xBGR, RGBx, BGRx }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-vpx.xml b/docs/plugins/inspect/plugin-vpx.xml
new file mode 100644
index 0000000..dcd51f8
--- /dev/null
+++ b/docs/plugins/inspect/plugin-vpx.xml
@@ -0,0 +1,97 @@
+<plugin>
+  <name>vpx</name>
+  <description>VP8 plugin</description>
+  <filename>../../ext/vpx/.libs/libgstvpx.so</filename>
+  <basename>libgstvpx.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>vp8dec</name>
+      <longname>On2 VP8 Decoder</longname>
+      <class>Codec/Decoder/Video</class>
+      <description>Decode VP8 video streams</description>
+      <author>David Schleef &lt;ds@entropywave.com&gt;, Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-vp8</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)I420, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>vp8enc</name>
+      <longname>On2 VP8 Encoder</longname>
+      <class>Codec/Encoder/Video</class>
+      <description>Encode VP8 video streams</description>
+      <author>David Schleef &lt;ds@entropywave.com&gt;, Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string)I420, width=(int)[ 1, 16383 ], height=(int)[ 1, 16383 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-vp8, profile=(string){ 0, 1, 2, 3 }</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>vp9dec</name>
+      <longname>On2 VP9 Decoder</longname>
+      <class>Codec/Decoder/Video</class>
+      <description>Decode VP9 video streams</description>
+      <author>David Schleef &lt;ds@entropywave.com&gt;, Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-vp9</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ I420, YV12, Y42B, Y444 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>vp9enc</name>
+      <longname>On2 VP9 Encoder</longname>
+      <class>Codec/Encoder/Video</class>
+      <description>Encode VP9 video streams</description>
+      <author>David Schleef &lt;ds@entropywave.com&gt;, Sebastian Dröge &lt;sebastian.droege@collabora.co.uk&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ I420, YV12 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-vp9, profile=(string){ 0, 1, 2, 3 }</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-waveform.xml b/docs/plugins/inspect/plugin-waveform.xml
new file mode 100644
index 0000000..edd277e
--- /dev/null
+++ b/docs/plugins/inspect/plugin-waveform.xml
@@ -0,0 +1,20 @@
+<plugin>
+  <name>waveform</name>
+  <description>WaveForm API based plugin</description>
+  <filename>../../win32/vs6/release/libgstwaveform.dll</filename>
+  <basename>libgstwaveform.dll</basename>
+  <version>0.10.4.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-bad</source>
+  <package>GStreamer Good Plug-ins CVS</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>waveformsink</name>
+      <longname>WaveForm audio sink</longname>
+      <class>Sink/Audio</class>
+      <description>WaveForm audio sink</description>
+      <author>Sebastien Moutte &lt;sebastien@moutte.net&gt;</author>
+    </element>
+  </elements>
+</plugin>
diff --git a/docs/plugins/inspect/plugin-wavenc.xml b/docs/plugins/inspect/plugin-wavenc.xml
new file mode 100644
index 0000000..ab988b3
--- /dev/null
+++ b/docs/plugins/inspect/plugin-wavenc.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>wavenc</name>
+  <description>Encode raw audio into WAV</description>
+  <filename>../../gst/wavenc/.libs/libgstwavenc.so</filename>
+  <basename>libgstwavenc.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>wavenc</name>
+      <longname>WAV audio muxer</longname>
+      <class>Codec/Muxer/Audio</class>
+      <description>Encode raw audio into WAV</description>
+      <author>Iain Holmes &lt;iain@prettypeople.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 65535 ], format=(string){ S32LE, S24LE, S16LE, U8, F32LE, F64LE }, layout=(string)interleaved; audio/x-alaw, rate=(int)[ 8000, 192000 ], channels=(int)[ 1, 2 ]; audio/x-mulaw, rate=(int)[ 8000, 192000 ], channels=(int)[ 1, 2 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-wav; audio/x-rf64</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-wavpack.xml b/docs/plugins/inspect/plugin-wavpack.xml
new file mode 100644
index 0000000..707ec83
--- /dev/null
+++ b/docs/plugins/inspect/plugin-wavpack.xml
@@ -0,0 +1,61 @@
+<plugin>
+  <name>wavpack</name>
+  <description>Wavpack lossless/lossy audio format handling</description>
+  <filename>../../ext/wavpack/.libs/libgstwavpack.so</filename>
+  <basename>libgstwavpack.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>wavpackdec</name>
+      <longname>Wavpack audio decoder</longname>
+      <class>Codec/Decoder/Audio</class>
+      <description>Decodes Wavpack audio data</description>
+      <author>Arwed v. Merkatz &lt;v.merkatz@gmx.net&gt;, Sebastian Dröge &lt;slomo@circular-chaos.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-wavpack, depth=(int)[ 1, 32 ], channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], framed=(boolean)true</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S8, layout=(string)interleaved, channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ]; audio/x-raw, format=(string)S16LE, layout=(string)interleaved, channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ]; audio/x-raw, format=(string)S32LE, layout=(string)interleaved, channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ]</details>
+        </caps>
+      </pads>
+    </element>
+    <element>
+      <name>wavpackenc</name>
+      <longname>Wavpack audio encoder</longname>
+      <class>Codec/Encoder/Audio</class>
+      <description>Encodes audio with the Wavpack lossless/lossy audio codec</description>
+      <author>Sebastian Dröge &lt;slomo@circular-chaos.org&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-raw, format=(string)S32LE, layout=(string)interleaved, channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/x-wavpack, depth=(int)[ 1, 32 ], channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], framed=(boolean)true</details>
+        </caps>
+        <caps>
+          <name>wvcsrc</name>
+          <direction>source</direction>
+          <presence>sometimes</presence>
+          <details>audio/x-wavpack-correction, framed=(boolean)true</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-wavparse.xml b/docs/plugins/inspect/plugin-wavparse.xml
new file mode 100644
index 0000000..cc2e2b1
--- /dev/null
+++ b/docs/plugins/inspect/plugin-wavparse.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>wavparse</name>
+  <description>Parse a .wav file into raw audio</description>
+  <filename>../../gst/wavparse/.libs/libgstwavparse.so</filename>
+  <basename>libgstwavparse.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>wavparse</name>
+      <longname>WAV audio demuxer</longname>
+      <class>Codec/Demuxer/Audio</class>
+      <description>Parse a .wav file into raw audio</description>
+      <author>Erik Walthinsen &lt;omega@cse.ogi.edu&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>audio/x-wav</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>audio/ms-gsm; audio/mpeg, mpegversion=(int)1, layer=(int)3; audio/mpeg, mpegversion=(int)1, layer=(int)2; audio/x-raw, format=(string){ S8, U8, S16LE, U16LE, S24LE, U24LE, S32LE, U32LE }, layout=(string)interleaved; audio/x-vorbis; audio/x-ac3; audio/x-dts; audio/mpeg, mpegversion=(int)4; audio/x-alaw; audio/x-mulaw; audio/x-wms, bitrate=(int)[ 0, 2147483647 ], block_align=(int)[ 1, 2147483647 ]; audio/x-adpcm, layout=(string)microsoft, block_align=(int)[ 1, 2147483647 ]; audio/x-adpcm, layout=(string)dvi, block_align=(int)[ 1, 2147483647 ]; audio/x-truespeech; audio/x-wma, wmaversion=(int)1, bitrate=(int)[ 0, 2147483647 ], block_align=(int)[ 1, 2147483647 ]; audio/x-wma, wmaversion=(int)2, bitrate=(int)[ 0, 2147483647 ], block_align=(int)[ 1, 2147483647 ]; audio/x-wma, wmaversion=(int)3, bitrate=(int)[ 0, 2147483647 ], block_align=(int)[ 1, 2147483647 ]; audio/x-vnd.sony.atrac3; audio/x-raw, format=(string){ F32LE, F64LE }, layout=(string)interleaved; audio/x-voxware, voxwaretype=(int)117; audio/x-adpcm, layout=(string)dk4; audio/x-adpcm, layout=(string)dk3; audio/x-adpcm, layout=(string)dvi; audio/AMR; audio/AMR-WB; audio/x-siren; application/x-ogg-avi</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-ximagesrc.xml b/docs/plugins/inspect/plugin-ximagesrc.xml
new file mode 100644
index 0000000..16080bd
--- /dev/null
+++ b/docs/plugins/inspect/plugin-ximagesrc.xml
@@ -0,0 +1,28 @@
+<plugin>
+  <name>ximagesrc</name>
+  <description>X11 video input plugin using standard Xlib calls</description>
+  <filename>../../sys/ximage/.libs/libgstximagesrc.so</filename>
+  <basename>libgstximagesrc.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>ximagesrc</name>
+      <longname>Ximage video source</longname>
+      <class>Source/Video</class>
+      <description>Creates a screenshot video stream</description>
+      <author>Lutz Mueller &lt;lutz@users.sourceforge.net&gt;, Jan Schmidt &lt;thaytan@mad.scientist.com&gt;, Zaheer Merali &lt;zaheerabbas at merali dot org&gt;</author>
+      <pads>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>video/x-raw, framerate=(fraction)[ 0/1, 2147483647/1 ], width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], pixel-aspect-ratio=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/plugins/inspect/plugin-y4menc.xml b/docs/plugins/inspect/plugin-y4menc.xml
new file mode 100644
index 0000000..2a5433b
--- /dev/null
+++ b/docs/plugins/inspect/plugin-y4menc.xml
@@ -0,0 +1,34 @@
+<plugin>
+  <name>y4menc</name>
+  <description>Encodes a YUV frame into the yuv4mpeg format (mjpegtools)</description>
+  <filename>../../gst/y4m/.libs/libgsty4menc.so</filename>
+  <basename>libgsty4menc.so</basename>
+  <version>1.13.0.1</version>
+  <license>LGPL</license>
+  <source>gst-plugins-good</source>
+  <package>GStreamer Good Plug-ins git</package>
+  <origin>Unknown package origin</origin>
+  <elements>
+    <element>
+      <name>y4menc</name>
+      <longname>YUV4MPEG video encoder</longname>
+      <class>Codec/Encoder/Video</class>
+      <description>Encodes a YUV frame into the yuv4mpeg format (mjpegtools)</description>
+      <author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
+      <pads>
+        <caps>
+          <name>sink</name>
+          <direction>sink</direction>
+          <presence>always</presence>
+          <details>video/x-raw, format=(string){ IYUV, I420, Y42B, Y41B, Y444 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
+        </caps>
+        <caps>
+          <name>src</name>
+          <direction>source</direction>
+          <presence>always</presence>
+          <details>application/x-yuv4mpeg, y4mversion=(int)2</details>
+        </caps>
+      </pads>
+    </element>
+  </elements>
+</plugin>
\ No newline at end of file
diff --git a/docs/random/ChangeLog-0.8 b/docs/random/ChangeLog-0.8
new file mode 100644
index 0000000..c63ef6c
--- /dev/null
+++ b/docs/random/ChangeLog-0.8
@@ -0,0 +1,17501 @@
+2005-08-28  Andy Wingo  <wingo@pobox.com>
+
+	* Updates for two-arg init from GST_BOILERPLATE.
+
+	* ext/ladspa/gstsignalprocessor.c (gst_signal_processor_init): Use
+	the second arg for the class, because G_OBJECT_GET_CLASS (self)
+	returns the wrong thing.
+	(gst_signal_processor_add_pad_from_template): Make pads of the
+	right type.
+
+	* ext/ladspa/gstladspa.c (gst_ladspa_class_get_param_spec): Make
+	writable param specs G_PARAM_CONSTRUCT so default values work.
+	(gst_ladspa_init): Use the second arg for the class.
+
+2005-08-26  Andy Wingo  <wingo@pobox.com>
+
+	* ext/ladspa/gstladspa.c: 
+	* ext/ladspa/gstladspa.h: Finish porting, still doesn't work but
+	it does compile and register. I have more features than you.
+	
+	* ext/ladspa/gstsignalprocessor.h: 
+	* ext/ladspa/gstsignalprocessor.c: Updates, bug fixen.
+
+2005-08-26  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/effectv/gstquark.c: (gst_quarktv_init),
+	(gst_quarktv_change_state):
+	  do proper cleanup/creation, fixes state changes
+
+2005-08-25  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* gst/level/gstlevel.c: (gst_level_message_new):
+	Revert unpopular change for GST_MESSAGE_SRC to GObject.
+
+2005-08-25  Andy Wingo  <wingo@pobox.com>
+
+	* ext/ladspa/gstladspa.h: 
+	* ext/ladspa/gstladspa.c: Halfway-ported. Doesn't compile yet.
+
+	* ext/ladspa/gstsignalprocessor.h:
+	* ext/ladspa/gstsignalprocessor.c: New files, the start of a base
+	class for DSP elements.
+
+	* configure.ac: Sort the external libs checks, add a ladspa check,
+	output the ladspa makefile.
+
+2005-08-25  Owen Fraser-Green  <owen@discobabe.net>
+
+	* gst/realmedia/rmdemux.c (gst_rmdemux_loop, gst_rmdemux_chain):
+	Fixed EOS.
+	(gst_rmdemux_parse_indx_data, gst_rmdemux_parse_indx): Handle
+	malformed index headers where the packet size is incorrect.
+
+2005-08-24  Andy Wingo  <wingo@pobox.com>
+
+	* ext/dv/gstdvdemux.c (gst_dvdemux_demux_frame): Send out valid
+	segment end timestamps.
+
+2005-08-24  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	  lame and mpegaudioparse seem to work
+	* gst/videobox/gstvideobox.c: (gst_video_box_class_init),
+	(gst_video_box_transform_caps), (gst_video_box_get_unit_size):
+	  update for basetransform changes
+
+2005-08-24  Jan Schmidt  <thaytan@mad.scientist.com>
+	* gst/level/gstlevel.c: (gst_level_message_new):
+	  GST_MESSAGE_SRC became a GObject
+
+2005-08-23  Stefan Kost  <ensonic@users.sf.net>
+
+	* ext/speex/gstspeexenc.h:
+	  Fixed include path of adapter
+
+2005-08-23  Wim Taymans  <wim@fluendo.com>
+
+	* ext/speex/gstspeexdec.c: (gst_speex_dec_class_init):
+	* ext/speex/gstspeexenc.c: (gst_speexenc_class_init):
+	Fix property warning.
+
+2005-08-23  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtp/gstrtpamrdec.c: (gst_rtpamrdec_init),
+	(gst_rtpamrdec_sink_setcaps), (gst_rtpamrdec_chain):
+	* gst/rtp/gstrtpamrenc.c: (gst_rtpamrenc_class_init),
+	(gst_rtpamrenc_init), (gst_rtpamrenc_chain):
+	* gst/rtp/gstrtph263penc.c: (gst_rtph263penc_class_init),
+	(gst_rtph263penc_flush), (gst_rtph263penc_chain):
+	Small updates, RFC reference to payload encoders.
+
+2005-08-23  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/speex/Makefile.am:
+	* ext/speex/gstspeex.c: (plugin_init):
+	* ext/speex/gstspeexdec.c: (speex_get_query_types),
+	(gst_speex_dec_init), (speex_dec_src_query), (speex_dec_src_event),
+	(speex_dec_event), (speex_dec_chain):
+	  Port speexdec. Leads to some unfamiliar warnings on console,
+	  but works otherwise.
+
+2005-08-23  Andy Wingo  <wingo@pobox.com>
+
+	* sys/oss/gstosssrc.c (gst_oss_src_open): Set the device-name
+	property after opening the mixer.
+
+	* sys/oss/gstosssrc.c: 
+	* sys/oss/gstosssrc.h: Easy to implement a mixer, eh...
+
+	* sys/oss/gstossmixerelement.h:
+	* sys/oss/gstossmixerelement.c: Added mixer element like
+	alsamixer.
+
+	* sys/oss/Makefile.am: 
+	* sys/oss/gstossaudio.c: Register the ossmixer element.
+	
+	* sys/oss/gstossmixer.h:
+	* sys/oss/gstossmixer.c: Refactored to be more like alsamixer.
+
+	* sys/oss/gstossmixertrack.h:
+	* sys/oss/gstossmixertrack.c: Split out from gstossmixer.[ch],
+	like gstalsamixer.
+
+	* sys/oss/gstosssrc.c:
+	* sys/oss/gstosssink.c: Where before we used a gstosselement
+	object as a helper library, now just call functions from
+	gstosshelper.
+
+	* sys/oss/gstosshelper.h:
+	* sys/oss/gstosshelper.c: Made a real library. Removed
+	propertyprobe for now, should add it back later.
+	
+	* sys/oss/gstosselement.h:
+	* sys/oss/gstosselement.c: Removed, we don't have a shared base
+	class.
+	
+	* sys/oss/gstosshelper.c (gst_oss_helper_probe_caps): Search
+	higher-to-lower, makes 16 bit appear earlier in the caps, which
+	makes it preferred.
+
+	* sys/oss/gstosssrc.h: 
+	* sys/oss/gstosssrc.c: Totally ported, dude.
+
+	* sys/oss/Makefile.am:
+	* sys/oss/gstossaudio.c: Add osssrc.
+	
+	* sys/oss/gstosssink.c: We do native byte order.
+
+2005-08-23  Owen Fraser-Green  <owen@discobabe.net>
+
+	* gst/realmedia/rmdemux.c (gst_rmdemux_src_event): Fixed bug
+	causing events to be passed wrong way.
+	(gst_rmdemux_parse_packet): Avoid accidentally skipping audio.
+
+2005-08-22  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_init),
+	(gst_id3_tag_sink_event), (gst_id3_tag_do_caps_nego),
+	(gst_id3_tag_chain), (gst_id3_tag_change_state), (plugin_init):
+	  Works a bit better now, but still needs a rewrite to use
+	  get_range instead of this seeking nastiness.
+
+2005-08-22  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/flac/Makefile.am:
+	* ext/flac/gstflac.c: (plugin_init):
+	* ext/flac/gstflacdec.c: (flacdec_get_type), (gst_flacdec_init),
+	(gst_flacdec_update_metadata), (gst_flacdec_seek),
+	(gst_flacdec_tell), (gst_flacdec_length), (gst_flacdec_read),
+	(gst_flacdec_write), (gst_flacdec_loop),
+	(gst_flacdec_get_src_query_types), (gst_flacdec_src_query),
+	(gst_flacdec_src_event), (gst_flacdec_sink_activate),
+	(gst_flacdec_sink_activate_pull), (gst_flacdec_change_state):
+	* ext/flac/gstflacdec.h:
+	  Port flacdec (seeking is still slow'ish).
+
+2005-08-22  Owen Fraser-Green  <owen@discobabe.net>
+
+	* gst/realmedia/rmdemux.c: 
+	(gst_rmdemux_perform_seek, gst_rmdemux_parse_packet): 
+	Seeking improvements.
+
+2005-08-19  Wim Taymans  <wim@fluendo.com>
+
+	* gst/udp/gstmultiudpsink.c: (gst_multiudpsink_class_init):
+	Remove get_time code that is both wrong and unneeded.
+
+2005-08-19  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtp/gstrtph263penc.c: (gst_rtph263penc_class_init),
+	(gst_rtph263penc_flush), (gst_rtph263penc_chain),
+	(gst_rtph263penc_set_property), (gst_rtph263penc_get_property):
+	* gst/rtp/gstrtph263penc.h:
+	Added configurable pt and ssrc, to be merged in the caps or
+	a base class...
+
+2005-08-19  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtp/gstrtph263pdec.c: (gst_rtph263pdec_init),
+	(gst_rtph263pdec_chain):
+	* gst/rtp/gstrtph263penc.c: (gst_rtph263penc_class_init),
+	(gst_rtph263penc_flush), (gst_rtph263penc_chain):
+	Some cleanups in the h263p (de)payloaders.
+
+2005-08-19  Wim Taymans  <wim@fluendo.com>
+
+	* ext/amrnb/amrnbdec.c:
+	* ext/amrnb/amrnbenc.c: (gst_amrnbenc_setcaps):
+	* ext/amrnb/amrnbparse.c:
+	Update caps with audio/AMR.
+	
+	* gst/rtp/gstrtpamrdec.c: (gst_rtpamrdec_init),
+	(gst_rtpamrdec_sink_setcaps), (gst_rtpamrdec_chain),
+	(gst_rtpamrdec_change_state):
+	* gst/rtp/gstrtpamrdec.h:
+	* gst/rtp/gstrtpamrenc.c: (gst_rtpamrenc_class_init),
+	(gst_rtpamrenc_init), (gst_rtpamrenc_chain):
+	Dont set FT headers twice, it was already in the encoded
+	bitstream.
+	
+	* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send), (gst_rtspsrc_open),
+	(gst_rtspsrc_close), (gst_rtspsrc_play):
+	* gst/rtsp/rtspconnection.c: (parse_line):
+	Cleanups
+	
+	* gst/udp/gstudpsrc.c: (gst_udpsrc_class_init),
+	(gst_udpsrc_create), (gst_udpsrc_set_property),
+	(gst_udpsrc_get_property):
+	* gst/udp/gstudpsrc.h:
+	Added caps property, we need this soon to type the buffers.
+
+2005-08-18  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtp/gstrtpamrdec.c: (gst_rtpamrdec_init),
+	(gst_rtpamrdec_chain):
+	Fix up amr depayloader a bit.
+
+	* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send), (gst_rtspsrc_open),
+	(gst_rtspsrc_close), (gst_rtspsrc_play):
+	Look for options result in Public and Allow header fields..
+	spec says Allow but some servers return Public...
+
+2005-08-18  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtp/gstrtpamrenc.c: (gst_rtpamrenc_class_init),
+	(gst_rtpamrenc_init), (gst_rtpamrenc_chain),
+	(gst_rtpamrenc_set_property), (gst_rtpamrenc_get_property):
+	* gst/rtp/gstrtpamrenc.h:
+	Added payload_type and ssrc properties to the payloader.
+
+	* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send), (gst_rtspsrc_open),
+	(gst_rtspsrc_close), (gst_rtspsrc_play):
+	Options need to be stripped and are in the Public header field.
+
+	* gst/rtsp/rtspurl.c: (rtsp_url_parse):
+	Fix url / parsing...
+
+
+2005-08-18  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c: (plugin_init):
+	* gst/rtp/gstrtpamrdec.c: (gst_rtpamrdec_get_type),
+	(gst_rtpamrdec_base_init), (gst_rtpamrdec_class_init),
+	(gst_rtpamrdec_init), (gst_rtpamrdec_chain),
+	(gst_rtpamrdec_set_property), (gst_rtpamrdec_get_property),
+	(gst_rtpamrdec_change_state), (gst_rtpamrdec_plugin_init):
+	* gst/rtp/gstrtpamrdec.h:
+	* gst/rtp/gstrtpamrenc.c: (gst_rtpamrenc_get_type),
+	(gst_rtpamrenc_base_init), (gst_rtpamrenc_class_init),
+	(gst_rtpamrenc_init), (gst_rtpamrenc_chain),
+	(gst_rtpamrenc_set_property), (gst_rtpamrenc_get_property),
+	(gst_rtpamrenc_change_state), (gst_rtpamrenc_plugin_init):
+	* gst/rtp/gstrtpamrenc.h:
+	* gst/rtp/gstrtpmpaenc.c: (gst_rtpmpaenc_class_init),
+	(gst_rtpmpaenc_flush), (gst_rtpmpaenc_chain):
+	Added very simplistic amr payloader. depayloader does not
+	work yet.
+
+2005-08-18  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send), (gst_rtspsrc_open),
+	(gst_rtspsrc_close), (gst_rtspsrc_play), (gst_rtspsrc_pause),
+	(gst_rtspsrc_change_state):
+	* gst/rtsp/gstrtspsrc.h:
+	* gst/rtsp/rtspdefs.c: (rtsp_method_as_text), (rtsp_find_method):
+	* gst/rtsp/rtspdefs.h:
+	* gst/rtsp/rtsptransport.c: (rtsp_transport_parse):
+	Handle RTSP defaults better.
+	Issue OPTIONS request to figure out what we are allowed to do.
+	Make the methods a bitfield so we can easily collect supported 
+	options.
+	Fix rtsp_find_method.
+	Do proper RTSP connection shutdown.
+
+2005-08-18  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp-common.h:
+	* gst/rtp/gstrtp.c: (plugin_init):
+	* gst/rtp/gstrtpL16enc.h:
+	* gst/rtp/gstrtpdec.c: (gst_rtpdec_get_type),
+	(gst_rtpdec_class_init), (gst_rtpdec_chain_rtp),
+	(gst_rtpdec_chain_rtcp), (gst_rtpdec_change_state),
+	(gst_rtpdec_plugin_init):
+	* gst/rtp/gstrtph263pdec.c: (gst_rtph263pdec_get_type),
+	(gst_rtph263pdec_base_init), (gst_rtph263pdec_class_init),
+	(gst_rtph263pdec_init), (gst_rtph263pdec_chain),
+	(gst_rtph263pdec_set_property), (gst_rtph263pdec_get_property),
+	(gst_rtph263pdec_change_state), (gst_rtph263pdec_plugin_init):
+	* gst/rtp/gstrtph263pdec.h:
+	* gst/rtp/gstrtph263penc.c: (gst_rtph263penc_get_type),
+	(gst_rtph263penc_base_init), (gst_rtph263penc_class_init),
+	(gst_rtph263penc_init), (gst_rtph263penc_flush),
+	(gst_rtph263penc_chain), (gst_rtph263penc_set_property),
+	(gst_rtph263penc_get_property), (gst_rtph263penc_change_state),
+	(gst_rtph263penc_plugin_init):
+	* gst/rtp/gstrtph263penc.h:
+	* gst/rtp/gstrtpmpadec.c: (gst_rtpmpadec_get_type),
+	(gst_rtpmpadec_base_init), (gst_rtpmpadec_class_init),
+	(gst_rtpmpadec_init), (gst_rtpmpadec_chain),
+	(gst_rtpmpadec_set_property), (gst_rtpmpadec_get_property),
+	(gst_rtpmpadec_change_state), (gst_rtpmpadec_plugin_init):
+	* gst/rtp/gstrtpmpadec.h:
+	* gst/rtp/gstrtpmpaenc.c: (gst_rtpmpaenc_get_type),
+	(gst_rtpmpaenc_base_init), (gst_rtpmpaenc_class_init),
+	(gst_rtpmpaenc_init), (gst_rtpmpaenc_flush), (gst_rtpmpaenc_chain),
+	(gst_rtpmpaenc_set_property), (gst_rtpmpaenc_get_property),
+	(gst_rtpmpaenc_change_state), (gst_rtpmpaenc_plugin_init):
+	* gst/rtp/gstrtpmpaenc.h:
+	* gst/rtp/rtp-packet.c:
+	* gst/rtp/rtp-packet.h:
+	Remove old code that is now in gst-libs/gst/rtp/.
+	Added some payload/depayloaders.
+
+	* gst/udp/gstudpsink.c: (gst_udpsink_class_init):
+	Fix port number range.
+
+2005-08-17  Wim Taymans  <wim@fluendo.com>
+
+	* configure.ac:
+	Added mpegaudioparse
+
+	* ext/lame/gstlame.c: (gst_lame_src_getcaps),
+	(gst_lame_src_setcaps), (gst_lame_sink_setcaps),
+	(gst_lame_sink_event), (gst_lame_chain):
+	Some cleanups.
+	Fix memleak.
+
+	* gst/mpegaudioparse/gstmpegaudioparse.c:
+	(gst_mp3parse_class_init), (gst_mp3parse_init),
+	(gst_mp3parse_chain), (gst_mp3parse_change_state):
+	* gst/mpegaudioparse/gstmpegaudioparse.h:
+	Ported mpegaudioparse
+
+2005-08-17  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_open), (gst_rtspsrc_play):
+	Support absolute control urls too.
+
+2005-08-16  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_parse_stream),
+	(gst_avi_demux_stream_header):
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_change_state),
+	(gst_qtdemux_add_stream), (qtdemux_parse_tree):
+	  Uncomment metadata and codec-name handling.
+
+2005-08-16  Wim Taymans  <wim@fluendo.com>
+
+	* configure.ac:
+	* ext/amrnb/amrnbparse.c: (gst_amrnbparse_read_header):
+	Fix compile warning.
+
+	* ext/lame/gstlame.c: (gst_lame_class_init),
+	(gst_lame_src_getcaps), (gst_lame_src_setcaps),
+	(gst_lame_sink_setcaps), (gst_lame_init), (gst_lame_sink_event),
+	(gst_lame_chain), (gst_lame_change_state):
+	* ext/lame/gstlame.h:
+	Port lame plugin
+
+2005-08-16  Andy Wingo  <wingo@pobox.com>
+
+	* ext/dv/gstdvdemux.c (gst_dvdemux_flush): Use gst_adapter_take so
+	we have our own copy of the data.
+	(gst_dvdemux_demux_video): Set the take() data as malloc_data so
+	it will get freed later.
+
+	* ext/raw1394/gstdv1394src.c (gst_dv1394src_iso_receive): Note
+	license info in the source code -- was only in the commit log
+	before.
+
+	* ext/dv/gstdvdec.h:
+	* ext/dv/gstdvdec.c: Only decodes systemstream=FALSE dv video --
+	old pipelines using dvdec should probably have a dvdemux first.
+
+	* ext/dv/gstdvdemux.h:
+	* ext/dv/gstdvdemux.c: Split out from dvdec, chunks the incoming
+	systemstream=TRUE data into frames, sets caps data, and spits out
+	PCM audio in addition to systemstream=FALSE video frames. Operates
+	in chain mode only for now; should make a getrange version as
+	well.
+
+	* ext/dv/gstdv.c: New file, registers the libgstdv plugin.
+
+	* ext/dv/Makefile.am: Library name changed to libgstdv. Split
+	dvdec into dvdemux and dvdec.
+
+2005-08-16  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/faad/gstfaad.c: (gst_faad_event), (gst_faad_chain):
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header):
+	  Handle _push() return values.
+
+2005-08-15  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/faad/gstfaad.c: (gst_faad_event):
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header):
+	  Fix debug.
+
+2005-08-15  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/qtdemux/qtdemux.c: (qtdemux_parse_trak),
+	(qtdemux_video_caps):
+	  Forwardport from 0.8 to implement RLE.
+
+2005-08-15  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtsp/README:
+	Added rtsp server implementation docs.
+
+2005-08-14  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/aalib/gstaasink.c:
+	  aalib is LGPL, so this plugin can be LGPL
+	* ext/arts/gst_arts.c: (plugin_init):
+	  rename, we don't like underscores
+	* ext/audiofile/gstaf.c:
+	* ext/sndfile/gstsf.c:
+	  rename, we like a descriptive plugin name
+	* ext/gconf/gstgconfelements.c:
+	  change description a little
+	* ext/musicbrainz/gsttrm.c:
+	  musicbrainz is LGPL, so plugin can be LGPL
+	* ext/raw1394/gst1394.c:
+	  rename, we like all-digit names
+	* gst/equalizer/gstiirequalizer.c:
+	* gst/fdsrc/gstfdsrc.c:
+	* gst/multifilesink/gstmultifilesink.c:
+	  rename
+	* gst/virtualdub/gstvirtualdub.c:
+	  use GST_PLUGIN_DEFINE
+	* sys/dxr3/dxr3init.c:
+	  only uses system headers, and code is LGPL, so plugin is LGPL
+
+2005-08-13  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/mad/Makefile.am:
+	* gst/avi/Makefile.am:
+	* gst/effectv/Makefile.am:
+	* gst/udp/Makefile.am:
+	* gst/wavparse/Makefile.am:
+	  Use -lgstfoo-@GST_MAJORMINOR@ instead of -lgstfoo-0.9
+
+2005-08-12  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_decode_indirect),
+	(gst_jpeg_dec_decode_direct), (gst_jpeg_dec_chain):
+	  Fix decoding of pictures with certain uneven or unaligned
+	  widths where jpeglib needs more horizontal padding than our
+	  I420 buffers provide, resulting in blocky artifacts at the
+	  left side of the picture (#164176). 
+	  Also make use of our shiny new GST_ROUND_N() macros.
+
+2005-08-11  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_init), (gst_jpeg_dec_chain),
+	(gst_jpeg_dec_change_state):
+	* ext/jpeg/gstjpegdec.h:
+	  Fix crashes/invalid memory access for pictures that have a height
+	  that is not a multiple of 16 (or rather: v_samp_factor * DCTSIZE).
+	  
+	  Also fix the state change function for downwards state changes
+	  (need to chain up to parent before destroying our resources, to 
+	  make sure pads get deactivated and our chain function isn't
+	  running and using those very same resources in another thread).
+
+	  The jpeg line buffer only needs to be v_samp_factor*DCTSIZE lines
+	  per plane, not picture_height lines; allocate that on the stack.
+
+2005-08-10  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_stream_headers),
+	(gst_wavparse_stream_data):
+	  Add some fixes from 0.8 branch: allow 24/32bps songs and
+	  blockalign samples to the header-specified size, if any
+	  (#311070); error out on channels==0 or bitrate==0 
+	  (#309043, #304588).
+
+2005-08-10  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/level/gstlevel.c: (gst_level_init), (gst_level_set_caps),
+	(gst_level_transform):
+	* gst/level/gstlevel.h:
+	  remove unused MS struct member
+	  don't reset the CS values for channels on every _chain, so that
+	  level actually correctly calculates the RMS value.  sigh.
+	  calculate RMS values correctly for peak and decay peak sums;
+	  before we were signalling them as if they already were amplitude
+	  and not power values.  sigh.
+	Remind me to not try and pretend I'm writing DSP code.
+
+2005-08-10  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/faad/gstfaad.c: (gst_faad_class_init), (gst_faad_setcaps):
+	  Add debug category, remove Close() call that made it crash
+	  whenever reusing, renegotiating or anything; Close() actually
+	  free()s the handle and should only be called on READY->NULL.
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header):
+	  Actually set caps on buffer (in addition to pad), also.
+
+2005-08-10  Owen Fraser-Green  <owen@discobabe.net>
+
+	* gst/realmedia/rmdemux.c (gst_rmdemux_sink_activate) 
+	(gst_rmdemux_sink_activate_push, gst_rmdemux_sink_activate_pull) 
+	(gst_rmdemux_loop, gst_rmdemux_src_event) 
+	(gst_rmdemux_perform_seek, gst_rmdemux_src_query): Implemented
+	push-pull and seeking.
+
+2005-08-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/faad/gstfaad.c: (gst_faad_event):
+	  Sign/unsign mismatch.
+	* configure.ac:
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_class_init),
+	(gst_qtdemux_init), (gst_qtdemux_get_src_query_types),
+	(gst_qtdemux_handle_src_query), (gst_qtdemux_handle_src_event),
+	(plugin_init), (gst_qtdemux_handle_sink_event),
+	(gst_qtdemux_change_state), (gst_qtdemux_loop_header),
+	(qtdemux_sink_activate), (qtdemux_sink_activate_pull),
+	(gst_qtdemux_add_stream), (qtdemux_parse), (qtdemux_parse_tree),
+	(qtdemux_parse_trak), (qtdemux_video_caps), (qtdemux_audio_caps):
+	* gst/qtdemux/qtdemux.h:
+	  Half-assed port (hey, it works).
+
+2005-08-09  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_stream_header):
+	  Fix AVI header parsing: add missing break statement after
+	  GST_RIFF_INFO_LIST parsing code; gst_riff_read_chunk() has
+	  already advanced the avi->offset, no need to do it twice
+	  (fixes MovieOfMovies.avi).
+
+2005-08-09  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_init),
+	(gst_jpeg_dec_setcaps), (gst_jpeg_dec_chain),
+	(gst_jpeg_dec_change_state):
+	* ext/jpeg/gstjpegdec.h:
+	  Make mjpeg actually work and skip jpeg data parsing if we
+	  know that the input is packetized (ie. each input buffer
+	  is exactly one jpeg frame).
+
+2005-08-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mad/gstmad.c: (gst_mad_init), (gst_mad_chain):
+	  It'd be nice if I could listen to my mp3 files, so send out an
+	  initial discont, as the sink apparently wants.
+
+2005-08-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_event),
+	(gst_avi_demux_handle_seek):
+	  Fix seeking (or, well, fix threading issue where a variable was
+	  set before a lock was taken and was already unset before that
+	  same lock was taken and was thus no longer in existance when it
+	  actually had to be used).
+
+2005-08-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_process_next_entry):
+	  Mixing binary and logical operators is not going to work; fix
+	  position-querying in Totem.
+
+2005-08-08  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/faad/gstfaad.c: (gst_faad_base_init), (gst_faad_class_init),
+	(gst_faad_init), (gst_faad_setcaps), (gst_faad_srcgetcaps),
+	(gst_faad_event), (gst_faad_update_caps), (gst_faad_chain),
+	(gst_faad_change_state):
+	* ext/faad/gstfaad.h:
+	  Fix negotiation (#310932) and miscellaneous other stuff. Probably
+	  still needs some more work.
+
+2005-08-08  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_init),
+	(gst_jpeg_dec_setcaps), (gst_jpeg_dec_chain):
+	  Add setcaps() function (for mjpeg).
+
+2005-08-08  Andy Wingo  <wingo@pobox.com>
+
+	* ext/esd/esdsink.c (gst_esdsink_getcaps): Seems that wierd
+	va_list caps setting function was borked. Fixed esdsink.
+
+	* sys/oss/gstosssink.c (gst_oss_sink_open, gst_oss_sink_close) 
+	(gst_oss_sink_prepare, gst_oss_sink_unprepare): Update for newer
+	audiosink api.
+
+	* ext/raw1394/gstdv1394src.c (gst_dv1394src_get_property) 
+	(gst_dv1394src_set_property): Style. All about the style.
+
+	* ext/esd/esdsink.c (gst_esdsink_getcaps): Return specific caps
+	only if in READY or higher (i.e., if _open() has been called.)
+	(gst_esdsink_open, gst_esdsink_close, gst_esdsink_prepare) 
+	(gst_esdsink_unprepare): Update for audiosink changes.
+	(gst_esdsink_change_state): Die!
+
+2005-08-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/jpeg/Makefile.am:
+	  Fix compile.
+
+2005-08-08  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/jpeg/Makefile.am:
+	* ext/jpeg/gstjpeg.c: (plugin_init):
+	* ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_get_type),
+	(gst_jpeg_dec_finalize), (gst_jpeg_dec_base_init),
+	(gst_jpeg_dec_class_init), (gst_jpeg_dec_fill_input_buffer),
+	(gst_jpeg_dec_init_source), (gst_jpeg_dec_skip_input_data),
+	(gst_jpeg_dec_resync_to_restart), (gst_jpeg_dec_term_source),
+	(gst_jpeg_dec_my_output_message), (gst_jpeg_dec_my_emit_message),
+	(gst_jpeg_dec_my_error_exit), (gst_jpeg_dec_init),
+	(is_jpeg_start_marker), (is_jpeg_end_marker),
+	(gst_jpeg_dec_find_jpeg_header), (gst_jpeg_dec_ensure_header),
+	(gst_jpeg_dec_have_end_marker),
+	(gst_jpeg_dec_parse_tag_has_entropy_segment),
+	(gst_jpeg_dec_parse_image_data), (gst_jpeg_dec_chain),
+	(gst_jpeg_dec_change_state):
+	* ext/jpeg/gstjpegdec.h:
+	  Port jpegdec to 0.9; handles 'progressive loading' now, ie. input does
+	  no longer need to be one single buffer.
+
+2005-08-04  Andy Wingo  <wingo@pobox.com>
+
+	* sys/oss/gstossaudio.c (plugin_init): Second-class citizen.
+
+	* gst/videobox/gstvideobox.c (gst_video_box_get_size): Update for
+	API changes.
+
+	* configure.ac (DEFAULT_AUDIOSINK, DEFAULT_VIDEOSINK): Set to
+	autoaudiosink and autovideosink.
+
+2005-08-04  Edward Hervey  <edward@fluendo.com>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_reset),
+	(gst_avi_demux_parse_stream), (gst_avi_demux_process_next_entry):
+	You need to allocatate (len+1) characters to store a len size string.
+	Also don't stop the processing task if the output pad is not linked.
+
+2005-08-03  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_reset),
+	(gst_gconf_audio_sink_init), (do_toggle_element),
+	(cb_toggle_element), (gst_gconf_audio_sink_change_state):
+	* ext/gconf/gstgconfaudiosink.h:
+	* ext/gconf/gstgconfvideosink.c: (gst_gconf_video_sink_reset),
+	(gst_gconf_video_sink_init), (do_toggle_element),
+	(cb_toggle_element), (gst_gconf_video_sink_change_state):
+	* ext/gconf/gstgconfvideosink.h:
+	* gst/autodetect/gstautoaudiosink.c: (gst_auto_audio_sink_reset),
+	(gst_auto_audio_sink_init), (gst_auto_audio_sink_detect),
+	(gst_auto_audio_sink_change_state):
+	* gst/autodetect/gstautoaudiosink.h:
+	* gst/autodetect/gstautovideosink.c: (gst_auto_video_sink_reset),
+	(gst_auto_video_sink_init), (gst_auto_video_sink_detect),
+	(gst_auto_video_sink_change_state):
+	* gst/autodetect/gstautovideosink.h:
+	  Use new ghostpad API; now they actually work in Totem, also.
+
+2005-08-03  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/libpng/Makefile.am:
+	  Fix uninstalled build.
+
+2005-08-02  Edward Hervey  <edward@fluendo.com>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/libpng/Makefile.am:
+	* ext/libpng/gstpng.c:
+	* ext/libpng/gstpngenc.c:
+	Ported pngenc , still have to port pngdec...
+
+2005-08-01  Stefan Kost  <ensonic@users.sf.net>
+
+	reviewed by: <delete if not using a buddy>
+
+	* configure.ac:
+	* ext/ladspa/Makefile.am:
+	* ext/ladspa/gstladspa.c: (gst_ladspa_init), (gst_ladspa_loop),
+	(gst_ladspa_chain), (gst_ladspa_get), (plugin_init):
+	* ext/ladspa/gstladspa.h:
+          deactivate and remove dparams (libgstcontrol)
+
+2005-07-27  Wim Taymans  <wim@fluendo.com>
+
+	* ext/faad/gstfaad.c: (gst_faad_event):
+	Compile fixes.
+
+2005-07-27  Wim Taymans  <wim@fluendo.com>
+
+	* ext/amrnb/amrnbparse.c: (gst_amrnbparse_event),
+	(gst_amrnbparse_loop):
+	* ext/dv/gstdvdec.c: (gst_dvdec_handle_sink_event),
+	(gst_dvdec_handle_src_event), (gst_dvdec_decode_frame):
+	* ext/mad/gstid3tag.c: (gst_id3_tag_src_event),
+	(gst_id3_tag_sink_event), (gst_id3_tag_chain):
+	* ext/mad/gstmad.c: (gst_mad_src_query), (index_seek),
+	(normal_seek), (gst_mad_sink_event), (gst_mad_chain):
+	* ext/mpeg2dec/gstmpeg2dec.c:
+	* ext/shout2/gstshout2.c: (gst_shout2send_event):
+	* ext/sidplay/gstsiddec.cc:
+	* gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_event),
+	(gst_avi_demux_send_event), (gst_avi_demux_stream_header),
+	(gst_avi_demux_handle_seek), (gst_avi_demux_process_next_entry):
+	* gst/goom/gstgoom.c: (gst_goom_event):
+	* gst/realmedia/rmdemux.c: (gst_rmdemux_sink_event),
+	(gst_rmdemux_chain), (gst_rmdemux_send_event),
+	(gst_rmdemux_add_stream):
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_handle_seek),
+	(gst_wavparse_stream_headers), (gst_wavparse_stream_data),
+	(gst_wavparse_loop), (gst_wavparse_srcpad_event):
+	Various event updates and cleanups.
+
+2005-07-25  Christian Schaller  <uraeus@gnome.org>
+
+
+	* gst-plugins.spec.in: add silence and videoflip
+	* gst/videofilter/Makefile.am: add missing header to noinst
+
+2005-07-25  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/videofilter/Makefile.am:
+	* gst/videofilter/gstgamma.c: (gst_gamma_setup):
+	* gst/videofilter/gstvideobalance.c: (gst_videobalance_setup):
+	* gst/videofilter/gstvideofilter.c: (gst_videofilter_class_init),
+	(gst_videofilter_getcaps), (gst_videofilter_setcaps),
+	(gst_videofilter_init), (gst_videofilter_chain),
+	(gst_videofilter_set_property), (gst_videofilter_get_property),
+	(gst_videofilter_setup), (gst_videofilter_class_add_pad_templates):
+	* gst/videofilter/gstvideofilter.h:
+	* gst/videofilter/gstvideoflip.c: (gst_videoflip_init),
+	(gst_videoflip_set_property), (gst_videoflip_get_property),
+	(plugin_init), (gst_videoflip_setup), (gst_videoflip_planar411):
+	  forward port from 0.9 and enable videoflip now that it works
+
+2005-07-23  Edward Hervey  <edward@fluendo.com>
+
+	* configure.ac:
+	* gst/silence/Makefile.am:
+	* gst/silence/gstsilence.h:
+	* gst/silence/gstsilence.c:
+	Ported silence to 0.9 using GstBaseSrc ... 180 lines :)
+
+2005-07-22  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mad/gstmad.c: (gst_mad_src_event):
+	  First try forwarding events, makes seeking in AVI files with mp3
+	  audio work again.
+
+2005-07-20  Andy Wingo  <wingo@pobox.com>
+
+	* ext/mpeg2dec/gstmpeg2dec.c (gst_mpeg2dec_sink_event): Signedness
+	fix.
+
+2005-07-20  Edward Hervey  <edward@fluendo.com>
+
+	* configure.ac: 
+	* gst/wavparse/gstwavparse.c: 
+	* gst/wavparse/gstwavparse.h:
+	* gst/wavparse/Makefile.am:
+	Ported wavparse to 0.9 . Playing, seeking and state changes work.
+	Could need more loving on the headers though.
+
+2005-07-20  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/gconf/Makefile.am:
+	* ext/gconf/gconf.c: (gst_bin_find_unconnected_pad),
+	(gst_gconf_render_bin_from_description),
+	(gst_gconf_get_default_video_sink):
+	* ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_base_init),
+	(gst_gconf_audio_sink_class_init), (gst_gconf_audio_sink_dispose),
+	(cb_toggle_element), (gst_gconf_audio_sink_change_state):
+	* ext/gconf/gstgconfelements.h:
+	* ext/gconf/gstgconfvideosink.c: (gst_gconf_video_sink_base_init),
+	(gst_gconf_video_sink_class_init), (gst_gconf_video_sink_dispose),
+	(cb_toggle_element), (gst_gconf_video_sink_change_state):
+	* gst/autodetect/gstautoaudiosink.c:
+	(gst_auto_audio_sink_base_init), (gst_auto_audio_sink_class_init),
+	(gst_auto_audio_sink_detect), (gst_auto_audio_sink_change_state):
+	* gst/autodetect/gstautovideosink.c:
+	(gst_auto_video_sink_base_init), (gst_auto_video_sink_class_init),
+	(gst_auto_video_sink_find_best), (gst_auto_video_sink_detect):
+	  Port auto/gconfsinks to 0.9. They actually appear to work here in
+	  Totem as well, making them actually useful.
+
+2005-07-20  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/faad/Makefile.am:
+	  Fix uninstalled build.
+
+2005-07-19  Wim Taymans  <wim@fluendo.com>
+
+	* sys/oss/gstosssink.c: (gst_oss_sink_get_format),
+	(gst_oss_sink_open):
+	Parse spec to set correct oss values.
+
+2005-07-19  Edgard N. A. G. Lima <edgard.lima@indt.org.br>
+
+        * configure.ac
+	* ext/Makefile.am
+	* ext/amrnb/amrnbdec.c
+	* ext/amrnb/amrnbenc.c
+	* ext/amrnb/amrnbparse.c
+	* ext/faad/gstfaad.c
+	* ext/mpeg2dec/gstmpeg2dec.c
+	Ported amrnb, faad, mpeg2dec to 0.9
+
+2005-07-19  Andy Wingo  <wingo@pobox.com>
+
+	* ext/dv/gstdvdec.c (gst_dvdec_decode_video): Set the proper
+	framerate on the outbound buffer.
+
+	* ext/dv/gstdvdec.c (gst_dvdec_decode_video): Don't clobber
+	alloc_buffer's return value.
+	(gst_dvdec_decode_frame): Handle unlinked pads with grace and
+	agility.
+
+	* ext/dv/gstdvdec.h: Fix signedness error.
+
+2005-07-19  Wim Taymans  <wim@fluendo.com>
+
+	* ext/dv/gstdvdec.c: (gst_dvdec_init), (gst_dvdec_src_convert),
+	(gst_dvdec_sink_convert), (gst_dvdec_get_src_query_types),
+	(gst_dvdec_src_query), (gst_dvdec_get_sink_query_types),
+	(gst_dvdec_sink_query), (gst_dvdec_send_event),
+	(gst_dvdec_handle_sink_event), (gst_dvdec_handle_src_event),
+	(gst_dvdec_decode_audio), (gst_dvdec_decode_video),
+	(gst_dvdec_decode_frame), (gst_dvdec_flush), (gst_dvdec_chain):
+	* ext/dv/gstdvdec.h:
+	Implemented seeking in dvdec.
+
+2005-07-19  Andy Wingo  <wingo@pobox.com>
+
+	* ext/Makefile.am: Enable dvdev and raw1394src.
+
+2005-07-18  Andy Wingo  <wingo@pobox.com>
+
+	* configure.ac: Use AS_LIBTOOL_TAGS. Fix crap gettext commit
+	comment.
+
+2005-07-18  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_add_element),
+	(gst_rtspsrc_play):
+	Fix for core changes.
+
+2005-07-18  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_sink_event):
+	  When returning to NORMAL state after reading tags,
+	  pass on the discont event.
+
+2005-07-18  Wim Taymans  <wim@fluendo.com>
+
+	* gst/realmedia/rmdemux.c: (gst_rmdemux_sink_event),
+	(gst_rmdemux_change_state), (gst_rmdemux_chain),
+	(gst_rmdemux_get_stream_by_id), (gst_rmdemux_send_event),
+	(gst_rmdemux_add_stream):
+	Send discont event before pushing first buffer.
+
+2005-07-17  Philippe Khalaf <burger@speedy.org>
+
+	* gst/fdsrc/gstfdsrc.c:
+	Removed #include <gst_private.h>
+
+2005-07-16  Philippe Khalaf <burger@speedy.org>
+
+	* gst/fdsrc/gstfdsrc.c:
+	* gst/fdsrc/gstfdsrc.h:
+	* gst/fdsrc/Makefile.am:
+	Moved fdsrc 0.9 port from gstreamer/gst/elements to here.
+
+2005-07-16  Wim Taymans  <wim@fluendo.com>
+
+	* ext/mad/gstmad.c: (gst_mad_src_query), (gst_mad_sink_event),
+	(gst_mad_chain):
+	Add convert function for proper timestamp calculations.
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_send_event),
+	(gst_avi_demux_stream_header), (gst_avi_demux_handle_seek),
+	(gst_avi_demux_process_next_entry), (gst_avi_demux_loop):
+	Send out initial discont.
+
+2005-07-15  Wim Taymans  <wim@fluendo.com>
+
+	* gst/level/gstlevel.c: (gst_level_transform):
+	* gst/videobox/gstvideobox.c: (gst_video_box_class_init),
+	(gst_video_box_get_size), (gst_video_box_transform):
+	Port to new base class.
+
+2005-07-14  Wim Taymans  <wim@fluendo.com>
+
+	* ext/raw1394/gstdv1394src.c: (gst_dv1394src_get_type),
+	(gst_dv1394src_class_init), (gst_dv1394src_init),
+	(gst_dv1394src_iso_receive), (gst_dv1394src_create),
+	(gst_dv1394src_change_state), (gst_dv1394src_query):
+	It's PUSH_SRC now.
+
+2005-07-14  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/udp/gstudpsrc.c: (gst_udpsrc_get_type),
+	(gst_udpsrc_class_init):
+	  more autistic cleanliness in functions/names/defines
+
+
+2005-07-10  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/aalib/gstaasink.c: (gst_aasink_get_type),
+	(gst_aasink_class_init), (gst_aasink_init):
+	* ext/esd/esdsink.c: (gst_esdsink_get_type),
+	(gst_esdsink_class_init):
+	* ext/libcaca/gstcacasink.c: (gst_cacasink_get_type),
+	(gst_cacasink_class_init), (gst_cacasink_init):
+	* ext/shout2/gstshout2.c: (gst_shout2send_get_type),
+	(gst_shout2send_class_init), (gst_shout2send_init):
+	* gst/udp/gstdynudpsink.c: (gst_dynudpsink_get_type),
+	(gst_dynudpsink_class_init):
+	* gst/udp/gstmultiudpsink.c: (gst_multiudpsink_get_type),
+	(gst_multiudpsink_class_init):
+	  more macro splitting
+
+2005-07-08  Andy Wingo  <wingo@pobox.com>
+
+	* sys/oss/: Port from THREADED+wim's fixes.
+
+	* gst/avi/Makefile.am (libgstavi_la_CFLAGS): No gettext hacks, the
+	defines come from config.h.
+
+	* autogen.sh: Run autopoint, etc.
+
+	* Makefile.am (DIST_SUBDIRS, SUBDIRS): Go into po/.
+
+	* configure.ac: Add gettext stuff.
+
+2005-07-07  Wim Taymans  <wim@fluendo.com>
+
+	* gst/videobox/gstvideobox.c: (gst_video_box_init),
+	(gst_video_box_transform_caps), (gst_video_box_set_caps):
+	Logic was reversed. Needs some  more fixes in the transform
+	function to include AYUV output.
+	Moved AYUV as prefered format.
+
+2005-07-07  Wim Taymans  <wim@fluendo.com>
+
+	* configure.ac:
+	* ext/dv/Makefile.am:
+	* ext/dv/gstdvdec.c: (gst_dvdec_class_init), (gst_dvdec_init),
+	(gst_dvdec_get_src_query_types), (gst_dvdec_src_query),
+	(gst_dvdec_handle_sink_event), (gst_dvdec_handle_src_event),
+	(gst_dvdec_video_getcaps), (gst_dvdec_video_setcaps),
+	(gst_dvdec_decode_audio), (gst_dvdec_decode_video),
+	(gst_dvdec_decode_frame), (gst_dvdec_chain),
+	(gst_dvdec_change_state), (gst_dvdec_set_property),
+	(gst_dvdec_get_property), (plugin_init):
+	* ext/dv/gstdvdec.h:
+	* ext/esd/esdsink.c: (gst_esdsink_class_init):
+	Ported DVdec to 0.9.
+	Parent of esdsink is GstAudioSink.
+
+2005-07-07  Wim Taymans  <wim@fluendo.com>
+
+	* configure.ac:
+	* ext/raw1394/Makefile.am:
+	* ext/raw1394/gstdv1394src.c: (gst_dv1394src_get_type),
+	(gst_dv1394src_class_init), (gst_dv1394src_init),
+	(gst_dv1394src_iso_receive), (gst_dv1394src_create),
+	(gst_dv1394src_change_state), (gst_dv1394src_convert),
+	(gst_dv1394src_get_query_types), (gst_dv1394src_query):
+	* ext/raw1394/gstdv1394src.h:
+	Ported the 1394 source to 0.9.
+
+2005-07-07  Wim Taymans  <wim@fluendo.com>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_get_query_types):
+	* ext/mad/gstmad.c: (gst_mad_get_query_types), (gst_mad_src_query):
+	* gst/avi/gstavidemux.c: (gst_avi_demux_get_src_query_types):
+	Remove deprecated/unsed code.
+
+2005-07-06  Edward Hervey  <edward@fluendo.com>
+
+	* gst/udp/gstudpsrc.c: (gst_udpsrc_init): 
+	GST_BASESRC --> GST_BASE_SRC
+
+2005-07-05  Andy Wingo  <wingo@pobox.com>
+
+	* gst/oneton: Removed (replaced by deinterleave).
+
+	* gst/adder:
+	* gst/audioconvert:
+	* gst/audiorate:
+	* gst/audioscale:
+	* gst/ffmpegcolorspace:
+	* gst/playback:
+	* gst/sine:
+	* gst/subparse:
+	* gst/tags:
+	* gst/tcp:
+	* gst/videoscale:
+	* gst/volume: Removed dirs that are now in gst-plugins-base.
+
+2005-07-05  Edward Hervey  <edward@fluendo.com>
+
+	* configure.ac: (GST_PLUGINS_ALL): 
+	videofilter must be compiled first, since other plugins depend ont it.
+
+2005-07-05  Andy Wingo  <wingo@pobox.com>
+
+	* Way, way, way too many files:
+	Remove crack comment from the 2000 era.
+
+2005-07-05  Andy Wingo  <wingo@pobox.com>
+
+	* gst/videobox/gstvideobox.c: Clean up, port to 0.9, use
+	BaseTransform.
+
+	* gst/videobox/Makefile.am: Link to base libs, include
+	plugins-base cflags, dist the README.
+
+	* configure.ac (GST_PLUGIN_ALL, AC_CONFIG_FILES): Add videobox to
+	the build.
+
+2005-07-04  Wim Taymans  <wim@fluendo.com>
+
+	* gst/realmedia/rmdemux.c:
+	I don't think that piece of changelog should go there.
+
+2005-07-04  Andy Wingo  <wingo@pobox.com>
+
+	* examples/level/:
+	* examples/level/Makefile.am:
+	* examples/level/README:
+	* examples/level/demo.c:
+	* examples/level/plot.c: Examples moved out of the source dir. Not
+	updated tho.
+
+	* configure.ac: Add level to the build.
+
+	* gst/level/Makefile.am:
+	* gst/level/gstlevel.h:
+	* gst/level/gstlevel.c: Cleaned up, ported to 0.9.
+
+	* ext/aalib/gstaasink.c (gst_aasink_fixate): Update for newer
+	fixate prototype.
+
+2005-07-03  Owen Fraser-Green  <owen@discobabe.net>
+
+	* gst/realmedia/rmdemux.c (gst_rmdemux_add_stream),
+	(gst_rmdemux_src_getcaps), (gst_rmdemux_chain): 
+	Added getcaps function no_more_pads call
+
+2005-07-01  Philippe Khalaf <burger@speedy.org>
+	* gst/udp/Makefile.am:
+	* gst/udp/gstudp.c:
+	* gst/udp/gstdynudpsink.c: (new)
+	* gst/udp/gstdynudpsink.h: (new)
+	  Added new element (udpdynsink) that receives GstNetBuffers and sends the
+	  udp packets to the source given in the buffer. It's used by rtpsession
+	  element for now.
+	* gst/udp/gstudpsrc.c:
+	  Fixed memory leak.
+
+2005-07-01  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* configure.ac:
+	* ext/mad/Makefile.am:
+	* sys/oss/Makefile.am:
+	Roll gstreamer-interfaces-0.9.pc into gstreamer-plugins-base-0.9.pc
+
+2005-07-01  Jan Schmidt  <thaytan@mad.scientist.com>
+	* ext/libcaca/Makefile.am:
+	* ext/mad/Makefile.am:
+	* gst/effectv/Makefile.am:
+	* gst/udp/Makefile.am:
+	  Replace GST_PLUGINS_LIBS_* with GST_PLUGINS_BASE_*
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_src_query),
+	(gst_id3_tag_src_event), (gst_id3_tag_sink_event),
+	(gst_id3_tag_chain), (plugin_init):
+	* ext/mad/gstmad.c: (gst_mad_src_query), (gst_mad_chain):
+	  Signedness warning fix, use gst_pad_get_peer instead of GST_PAD_PEER
+	  in querying and event handling, because we're not holding the pad
+	  lock and the peer may disappear.
+	* gst/avi/gstavidemux.c: (gst_avi_demux_parse_subindex),
+	(gst_avi_demux_parse_index), (gst_avi_demux_massage_index):
+	  Signedness warning fixes.
+
+	* gst/videofilter/gstvideotemplate.c: (plugin_init):
+	  Remove gst_library_load
+
+2005-06-30  Edward Hervey  <edward@fluendo.com>
+
+	* gst/avi/Makefile.am: (libgstavi_la_LIBADD):
+	Added linking to libgstriff-0.9
+	
+	* ext/mad/gstmad.c: (gst_mad_src_query): 
+	check the format of the upstream query and return query if it's the
+	same format as the requested one.
+
+2005-06-30  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query):
+	  Compiler pains.
+
+2005-06-30  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* gst/avi/Makefile.am:
+	* gst/avi/gstavi.c: (plugin_init):
+	* gst/avi/gstavidemux.c: (gst_avi_demux_get_type),
+	(gst_avi_demux_class_init), (gst_avi_demux_init),
+	(gst_avi_demux_reset), (gst_avi_demux_index_next),
+	(gst_avi_demux_index_entry_for_time),
+	(gst_avi_demux_index_entry_for_byte),
+	(gst_avi_demux_index_entry_for_frame), (gst_avi_demux_src_convert),
+	(gst_avi_demux_handle_src_query), (gst_avi_demux_handle_src_event),
+	(gst_avi_demux_parse_file_header), (gst_avi_demux_stream_init),
+	(gst_avi_demux_parse_avih), (gst_avi_demux_parse_superindex),
+	(gst_avi_demux_parse_subindex), (gst_avi_demux_read_subindexes),
+	(gst_avi_demux_parse_stream), (gst_avi_demux_parse_odml),
+	(gst_avi_demux_parse_index), (gst_avi_demux_stream_index),
+	(gst_avi_demux_stream_scan), (gst_avi_demux_massage_index),
+	(gst_avi_demux_stream_header), (gst_avi_demux_handle_seek),
+	(gst_avi_demux_process_next_entry), (gst_avi_demux_stream_data),
+	(gst_avi_demux_loop), (gst_avi_demux_sink_activate),
+	(gst_avi_demux_sink_activate_pull):
+	* gst/avi/gstavidemux.h:
+	  Port from -THREADED to HEAD, and fix for latest API changes of
+	  the day. Keep avimux dead for now.
+
+2005-06-29  Wim Taymans  <wim@fluendo.com>
+
+	* ext/shout2/gstshout2.c: (gst_shout2send_render):
+	Fix build.
+
+2005-06-29  Andy Wingo  <wingo@pobox.com>
+
+	* gst/videofilter/gstvideoexample.c: Removed gst_library_load, I
+	think. Whatever this plugin actually does, that I don't know.
+
+2005-06-29  Andy Wingo  <wingo@pobox.com>
+
+	* ext/mad/gstid3tag.c (gst_id3_tag_get_event_masks): Reschmoove.
+
+	* ext/mad/gstmad.c (gst_mad_get_event_masks): Remove.
+	(gst_mad_chain): Appease GCC.
+
+	* ext/libcaca/gstcacasink.c (gst_cacasink_setcaps): Signedness.
+
+	* ext/aalib/gstaasink.c (gst_aasink_fixate): Unref caps, not free.
+	(gst_aasink_scale): Signedness.
+
+	* gst/udp/gstudpsink.c (gst_udpsink_get_type): Actually add the
+	URI handler.
+
+	* gst/udp/gstudpsrc.c (gst_udpsrc_start):
+	(gst_udpsrc_create): Signedness.
+
+	* gst/rtsp/sdpmessage.c (sdp_message_parse_buffer): Thanks
+	compiler!
+	(sdp_parse_line): Signedness fix.
+
+	* configure.ac (GST_CFLAGS): GCC strikes back!!! Let the build
+	breakage ensue!!!
+
+	* gst/rtsp/gstrtspsrc.c (gst_rtspsrc_loop, gst_rtspsrc_open):
+	Signedness, unused var fixes.
+	(gst_rtspsrc_close): Unused?
+
+	* gst/realmedia/rmdemux.c (re_hexdump_bytes): Unused.
+
+	* gst/law/mulaw-encode.c (gst_mulawenc_chain): Signeness fix.
+
+	* gst/law/alaw-encode.c (alawenc_getcaps): Remove unneeded
+	declarations. Typo (probably crasher) fix.
+	
+	* gst/law/mulaw-encode.c (mulawdec_getcaps): 
+	* gst/law/mulaw-encode.c (mulawenc_getcaps): 
+	* gst/law/alaw-decode.c (alawdec_getcaps): Same crasher fix.
+
+	* gst/goom/gstgoom.c (gst_goom_init): Hook up the event function.
+
+	* gst/effectv/gstwarp.c (gst_warptv_setup): Signedness fix.
+
+	* gst/effectv/gstdice.c (gst_dicetv_draw): Um, deferencing
+	uninitialized pointer not good.
+
+	* gst/videofilter/gstvideoexample.c (plugin_init): 
+	* gst/videofilter/Makefile.am (libgstvideoexample_la_LIBADD): Link
+	to libgstvideofilter instead of gst_library_load.
+
+	* gst/alpha/gstalpha.c (gst_alpha_chroma_key_i420) 
+	(gst_alpha_chroma_key_ayuv): Signedness fixen.
+
+2005-06-29  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtsp/gstrtspsrc.c: (gst_rtsp_proto_get_type),
+	(gst_rtspsrc_class_init), (gst_rtspsrc_create_stream),
+	(gst_rtspsrc_add_element), (gst_rtspsrc_set_state),
+	(gst_rtspsrc_stream_setup_rtp),
+	(gst_rtspsrc_stream_configure_transport), (find_stream),
+	(gst_rtspsrc_loop), (gst_rtspsrc_open), (gst_rtspsrc_play),
+	(gst_rtspsrc_change_state):
+	Fix case where outpad could not be decided.
+
+2005-06-29  Andy Wingo  <wingo@pobox.com>
+
+	* ext/Makefile.am (MAD_DIR): Add mad to the build.
+
+2005-06-28  Wim Taymans  <wim@fluendo.com>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_src_link):
+	* gst/udp/gstudpsrc.c: (gst_udpsrc_init):
+	Fix old RPAD macro.
+	basesrc -> base_src
+
+2005-06-27  Wim Taymans  <wim@fluendo.com>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_src_link):
+	* ext/mad/gstmad.c: (gst_mad_chain):
+	RPAD_ -> PAD
+	Fix args in bufferalloc function call.
+	Makes the mad plugin compile again
+
+2005-06-27  Owen Fraser-Green  <owen@discobabe.net>
+
+	* gst/realmedia/rmdemux.c: Rewrote to use gstadapter. Also parses
+	audio and video header packets for known properties.
+
+2005-06-23  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtsp/gstrtspsrc.c: (gst_rtsp_proto_get_type),
+	(gst_rtspsrc_class_init), (gst_rtspsrc_create_stream),
+	(gst_rtspsrc_add_element), (gst_rtspsrc_set_state),
+	(gst_rtspsrc_stream_setup_rtp),
+	(gst_rtspsrc_stream_configure_transport), (find_stream),
+	(gst_rtspsrc_loop), (gst_rtspsrc_open), (gst_rtspsrc_play),
+	(gst_rtspsrc_change_state):
+	* gst/rtsp/rtspurl.c: (rtsp_url_parse):
+	Make rtspsrc a live source.
+	Don't try to parse NULL urls.
+
+2005-06-23  Wim Taymans  <wim@fluendo.com>
+
+	* gst/udp/gstudpsrc.c: (gst_udpsrc_init):
+	Make udpsrc a live source.
+
+2005-06-02  Wim Taymans  <wim@fluendo.com>
+
+	* gst/udp/Makefile.am:
+	Use versioned net lib.
+
+2005-06-02  Wim Taymans  <wim@fluendo.com>
+
+	* gst/udp/Makefile.am:
+	Fix hack in makefile.
+
+2005-06-02  Andy Wingo  <wingo@pobox.com>
+
+	* ext/mad/gstid3tag.c: Finish porting to 0.9: no more gstdata,
+	check for link functions before calling them, give
+	gst_message_new_tag its own copy of the tag list, set the parser
+	state before sending the event (because in 0.9 events are
+	processed immediately), casting fixes.
+
+	* ext/mad/Makefile.am (libgstmad_la_LDFLAGS): Link with
+	gsttagedit.
+
+2005-06-02  Wim Taymans  <wim@fluendo.com>
+
+	* gst/udp/Makefile.am:
+	* gst/udp/gstmultiudpsink.c: (gst_multiudpsink_get_type),
+	(gst_multiudpsink_base_init), (gst_multiudpsink_class_init),
+	(gst_multiudpsink_init), (gst_multiudpsink_finalize),
+	(gst_multiudpsink_get_times), (gst_multiudpsink_render),
+	(gst_multiudpsink_set_property), (gst_multiudpsink_init_send),
+	(gst_multiudpsink_add), (client_compare), (free_client),
+	(gst_multiudpsink_remove), (gst_multiudpsink_clear),
+	(gst_multiudpsink_get_stats):
+	* gst/udp/gstudpsrc.c: (gst_udpsrc_get_type),
+	(gst_udpsrc_base_init), (gst_udpsrc_class_init),
+	(gst_udpsrc_create), (gst_udpsrc_set_uri), (gst_udpsrc_start),
+	(gst_udpsrc_unlock), (gst_udpsrc_stop):
+	Use NetBuffer and small cleanups.
+	Implement client removal in multiudpsink.
+
+2005-06-02  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtsp/README:
+	* gst/rtsp/gstrtspsrc.c: (gst_rtsp_proto_get_type),
+	(gst_rtspsrc_class_init), (gst_rtspsrc_create_stream),
+	(gst_rtspsrc_add_element), (gst_rtspsrc_set_state),
+	(gst_rtspsrc_stream_setup_rtp),
+	(gst_rtspsrc_stream_configure_transport), (find_stream),
+	(gst_rtspsrc_loop), (gst_rtspsrc_open), (gst_rtspsrc_play),
+	(gst_rtspsrc_change_state):
+	* gst/rtsp/rtsptransport.c: (rtsp_transport_new),
+	(rtsp_transport_init), (parse_mode), (parse_range),
+	(rtsp_transport_parse), (rtsp_transport_free):
+	RTSP cleanups.
+
+2005-06-02  Wim Taymans  <wim@fluendo.com>
+
+	* gst/effectv/gstquark.c: (gst_quarktv_chain):
+	* gst/goom/gstgoom.c: (gst_goom_chain):
+	* gst/videobox/Makefile.am:
+	* gst/videobox/gstvideobox.c: (gst_video_box_class_init),
+	(gst_video_box_init), (gst_video_box_sink_setcaps),
+	(gst_video_box_chain):
+	* gst/videofilter/gstvideofilter.c: (gst_videofilter_chain):
+	* gst/videorate/gstvideorate.c: (gst_videorate_class_init),
+	(gst_videorate_getcaps), (gst_videorate_setcaps),
+	(gst_videorate_init), (gst_videorate_event), (gst_videorate_chain),
+	(gst_videorate_change_state):
+	Bufferalloc changes.
+
+2005-05-25  Wim Taymans  <wim@fluendo.com>
+
+	* ext/mad/gstmad.c: (gst_mad_chain), (gst_mad_change_state):
+	* ext/sidplay/gstsiddec.cc:
+	* gst/alpha/gstalpha.c: (gst_alpha_chain):
+	* gst/goom/gstgoom.c: (gst_goom_chain):
+	No need to take the lock anymore,  core already did
+	that before calling us.
+
+2005-05-25  Wim Taymans  <wim@fluendo.com>
+
+	* ext/amrnb/amrnbdec.c: (gst_amrnbdec_init), (gst_amrnbdec_chain),
+	(gst_amrnbdec_state_change):
+	* ext/amrnb/amrnbenc.c: (gst_amrnbenc_base_init),
+	(gst_amrnbenc_finalize), (gst_amrnbenc_chain),
+	(gst_amrnbenc_state_change):
+	* ext/amrnb/amrnbparse.c: (gst_amrnbparse_init),
+	(gst_amrnbparse_query), (gst_amrnbparse_chain),
+	(gst_amrnbparse_read_header), (gst_amrnbparse_loop),
+	(gst_amrnbparse_sink_activate), (gst_amrnbparse_state_change):
+	Core already took the lock.
+
+2005-05-19  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* ext/esd/Makefile.am:
+	  Disable tcp elements and esdmon (they don't compile).
+
+2005-05-19  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* Makefile.am:
+	* ext/Makefile.am:
+	* sys/Makefile.am:
+	  Make my automake version shut up about undefined variables
+	* gst/goom/gstgoom.c:
+	  GstAdapter moved to base objects. 
+
+2005-05-18  Wim Taymans  <wim@fluendo.com>
+
+	* ext/amrnb/Makefile.am:
+	* ext/amrnb/amrnb.c: (plugin_init):
+	* ext/amrnb/amrnbdec.c: (gst_amrnbdec_init),
+	(gst_amrnbdec_setcaps), (gst_amrnbdec_chain),
+	(gst_amrnbdec_state_change):
+	* ext/amrnb/amrnbdec.h:
+	* ext/amrnb/amrnbenc.c: (gst_amrnbenc_get_type),
+	(gst_amrnbenc_base_init), (gst_amrnbenc_class_init),
+	(gst_amrnbenc_init), (gst_amrnbenc_finalize),
+	(gst_amrnbenc_setcaps), (gst_amrnbenc_chain),
+	(gst_amrnbenc_state_change):
+	* ext/amrnb/amrnbenc.h:
+	* ext/amrnb/amrnbparse.c: (gst_amrnbparse_init),
+	(gst_amrnbparse_query), (gst_amrnbparse_event),
+	(gst_amrnbparse_chain), (gst_amrnbparse_read_header),
+	(gst_amrnbparse_loop), (gst_amrnbparse_sink_activate),
+	(gst_amrnbparse_state_change):
+	* ext/amrnb/amrnbparse.h:
+	Ported AMR decoder/parse.
+	Added AMR encoder.
+
+2005-05-18  Wim Taymans  <wim@fluendo.com>
+
+	* configure.ac:
+	* gst/goom/Makefile.am:
+	* gst/goom/gstgoom.c: (gst_goom_init), (gst_goom_sink_setcaps),
+	(gst_goom_src_setcaps), (gst_goom_src_negotiate), (gst_goom_event),
+	(gst_goom_chain), (gst_goom_change_state), (plugin_init):
+	Ported goom.
+	Added goom and alpha to build.
+
+2005-05-17  Wim Taymans  <wim@fluendo.com>
+
+	* configure.ac:
+	* gst/alpha/Makefile.am:
+	* gst/alpha/gstalpha.c: (gst_alpha_class_init), (gst_alpha_init),
+	(gst_alpha_sink_setcaps), (gst_alpha_chain):
+	Ported alpha,  remove alphacolor as functionality is in
+	ffmpegcolorspace.
+
+2005-05-17  Wim Taymans  <wim@fluendo.com>
+
+	* ext/libcaca/gstcacasink.c: (gst_cacasink_setcaps),
+	(gst_cacasink_render), (gst_cacasink_open), (gst_cacasink_close),
+	(gst_cacasink_change_state):
+	* ext/libcaca/gstcacasink.h:
+	Cleanups.
+
+2005-05-15  David Schleef  <ds@schleef.org>
+
+	Move core plugins out of core.  I don't mind fdsrc/fdsink
+	going back into the core; they were just disabled there, so
+	I moved them.  Some of this stuff could (should) be deleted.
+	* gst/oldcore/Makefile.am:
+	* gst/oldcore/gstaggregator.c:
+	* gst/oldcore/gstaggregator.h:
+	* gst/oldcore/gstelements.c:
+	* gst/oldcore/gstfdsink.c:
+	* gst/oldcore/gstfdsink.h:
+	* gst/oldcore/gstfdsrc.c:
+	* gst/oldcore/gstfdsrc.h:
+	* gst/oldcore/gstmd5sink.c:
+	* gst/oldcore/gstmd5sink.h:
+	* gst/oldcore/gstmultifilesrc.c:
+	* gst/oldcore/gstmultifilesrc.h:
+	* gst/oldcore/gstpipefilter.c:
+	* gst/oldcore/gstpipefilter.h:
+	* gst/oldcore/gstshaper.c:
+	* gst/oldcore/gstshaper.h:
+	* gst/oldcore/gststatistics.c:
+	* gst/oldcore/gststatistics.h:
+
+2005-05-13  Christian Schaller  <uraeus@gnome.org>
+
+	* ext/Makefile.am: dist esd directory
+	* gst-plugins.spec.in: add rtp plugins and esd plugin
+	* gst/effectv/Makefile.am: fix videofilter linking
+	* gst/rtp/Makefile.am: add missing headers 
+	* gst/rtsp/Makefile.am: add missing headers
+
+2005-05-12  Wim Taymans  <wim@fluendo.com>
+
+	* configure.ac:
+	* ext/sidplay/gstsiddec.cc:
+	Add working plugins to build.
+	Make sidplay compile again.
+
+2005-05-12  Wim Taymans  <wim@fluendo.com>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_src_query):
+	* ext/mad/gstmad.c: (gst_mad_chain):
+	Fix mad and id3tag compilation again.
+
+2005-05-12  Wim Taymans  <wim@fluendo.com>
+
+	* gst/udp/.cvsignore:
+	* gst/udp/Makefile.am:
+	* gst/udp/gstmultiudpsink.c: (gst_multiudpsink_get_type),
+	(gst_multiudpsink_base_init), (gst_multiudpsink_class_init),
+	(gst_multiudpsink_init), (gst_multiudpsink_finalize),
+	(gst_multiudpsink_get_times), (gst_multiudpsink_render),
+	(gst_multiudpsink_set_property), (gst_multiudpsink_get_property),
+	(gst_multiudpsink_init_send), (gst_multiudpsink_close),
+	(gst_multiudpsink_add), (gst_multiudpsink_remove),
+	(gst_multiudpsink_clear), (gst_multiudpsink_get_stats),
+	(gst_multiudpsink_change_state):
+	* gst/udp/gstmultiudpsink.h:
+	* gst/udp/gstudp-marshal.list:
+	* gst/udp/gstudp.c: (plugin_init):
+	* gst/udp/gstudp.h:
+	* gst/udp/gstudpsink.c: (gst_udpsink_get_type),
+	(gst_udpsink_base_init), (gst_udpsink_class_init),
+	(gst_udpsink_init), (gst_udpsink_set_uri),
+	(gst_udpsink_set_property), (gst_udpsink_get_property),
+	(gst_udpsink_uri_get_type), (gst_udpsink_uri_get_protocols),
+	(gst_udpsink_uri_get_uri), (gst_udpsink_uri_set_uri),
+	(gst_udpsink_uri_handler_init):
+	* gst/udp/gstudpsink.h:
+	* gst/udp/gstudpsrc.c: (gst_udpsrc_get_type),
+	(gst_udpsrc_base_init), (gst_udpsrc_class_init),
+	(gst_udpsrc_create), (gst_udpsrc_set_uri), (gst_udpsrc_start),
+	(gst_udpsrc_unlock), (gst_udpsrc_stop):
+	* gst/udp/gstudpsrc.h:
+	Added multifdsink to send UDP to multiple addresses.
+	Cleaned up UDP source/sink elements some more.
+	Make UDP sink extends from multiudpsink.
+
+2005-05-12  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/mad/gstmad.c: (gst_mad_src_query), (gst_mad_sink_event):
+	  Make queries actually work (update core first).
+
+2005-05-12  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtsp/README:
+	* gst/tcp/gsttcpclientsrc.c: (gst_tcpclientsrc_get_type),
+	(gst_tcpclientsrc_base_init), (gst_tcpclientsrc_class_init),
+	(gst_tcpclientsrc_init), (gst_tcpclientsrc_getcaps),
+	(gst_tcpclientsrc_stop), (gst_tcpclientsrc_eos),
+	(gst_tcpclientsrc_create), (gst_tcpclientsrc_start):
+	* gst/tcp/gsttcpclientsrc.h:
+	* gst/tcp/gsttcpserversrc.c: (gst_tcpserversrc_get_type),
+	(gst_tcpserversrc_base_init), (gst_tcpserversrc_class_init),
+	(gst_tcpserversrc_init), (gst_tcpserversrc_create),
+	(gst_tcpserversrc_start), (gst_tcpserversrc_stop):
+	* gst/tcp/gsttcpserversrc.h:
+	* gst/tcp/gsttcpsrc.c: (gst_tcpsrc_get_type),
+	(gst_tcpsrc_base_init), (gst_tcpsrc_class_init), (gst_tcpsrc_init),
+	(gst_tcpsrc_create), (gst_tcpsrc_start), (gst_tcpsrc_stop):
+	* gst/tcp/gsttcpsrc.h:
+	* gst/udp/gstudpsink.c: (gst_udpsink_base_init),
+	(gst_udpsink_init), (gst_udpsink_get_times), (gst_udpsink_render),
+	(gst_udpsink_set_property), (gst_udpsink_get_property),
+	(gst_udpsink_change_state):
+	* gst/udp/gstudpsink.h:
+	* gst/udp/gstudpsrc.c: (gst_udpsrc_get_type),
+	(gst_udpsrc_base_init), (gst_udpsrc_class_init), (gst_udpsrc_init),
+	(gst_udpsrc_create), (gst_udpsrc_set_uri), (gst_udpsrc_start),
+	(gst_udpsrc_stop):
+	* gst/udp/gstudpsrc.h:
+	Make UDP and TCP elements use PushSrc.
+
+
+2005-05-11  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/mad/gstmad.c: (gst_mad_init), (gst_mad_src_query),
+	(index_seek), (normal_seek), (gst_mad_sink_event):
+	  Port to new query API and replace gst_pad_convert()
+	  and gst_pad_get_formats() usage. gstid3tag looks like
+	  it needs some more love before it will work again, if 
+	  not a rewrite.
+
+2005-05-12  Zeeshan Ali  <zeenix@gmail.com>
+
+	* gst/effectv/Makefile.am:
+	Fixed the effectv build again.
+
+2005-05-11  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/Makefile.am:
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_get_type),
+	(gst_multifdsink_base_init), (gst_multifdsink_class_init),
+	(gst_multifdsink_init), (gst_multifdsink_handle_client_write),
+	(gst_multifdsink_queue_buffer), (gst_multifdsink_render),
+	(gst_multifdsink_change_state):
+	* gst/tcp/gstmultifdsink.h:
+	* gst/tcp/gsttcp.c:
+	* gst/tcp/gsttcpclientsink.c: (gst_tcpclientsink_get_type),
+	(gst_tcpclientsink_base_init), (gst_tcpclientsink_class_init),
+	(gst_tcpclientsink_init), (gst_tcpclientsink_render),
+	(gst_tcpclientsink_set_property), (gst_tcpclientsink_get_property),
+	(gst_tcpclientsink_change_state):
+	* gst/tcp/gsttcpclientsink.h:
+	* gst/tcp/gsttcpclientsrc.c: (gst_tcpclientsrc_class_init),
+	(gst_tcpclientsrc_init_receive):
+	* gst/tcp/gsttcpplugin.c: (plugin_init):
+	* gst/tcp/gsttcpserversink.c: (gst_tcpserversink_class_init):
+	* gst/tcp/gsttcpserversink.h:
+	* gst/tcp/gsttcpserversrc.c: (gst_tcpserversrc_class_init):
+	* gst/tcp/gsttcpsink.c: (gst_tcpsink_get_type),
+	(gst_tcpsink_base_init), (gst_tcpsink_class_init),
+	(gst_tcpsink_setcaps), (gst_tcpsink_init), (gst_tcpsink_get_times),
+	(gst_tcpsink_render), (gst_tcpsink_set_property),
+	(gst_tcpsink_get_property):
+	* gst/tcp/gsttcpsink.h:
+	* gst/tcp/gsttcpsrc.c: (gst_tcpsrc_class_init), (gst_tcpsrc_get):
+	Ported over some sink elements.
+	Sources not ported yet as they require a PushSource base class.
+
+2005-05-11  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* gst/effectv/Makefile.am:
+	* gst/videofilter/Makefile.am:
+	  Turn videofilter into a library (private for now)
+
+2005-05-11  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtsp/README:
+	* gst/rtsp/gstrtspsrc.c: (gst_rtsp_proto_get_type),
+	(gst_rtspsrc_class_init), (gst_rtspsrc_create_stream),
+	(gst_rtspsrc_add_element), (gst_rtspsrc_set_state),
+	(gst_rtspsrc_stream_setup_rtp),
+	(gst_rtspsrc_stream_configure_transport), (find_stream),
+	(gst_rtspsrc_loop), (gst_rtspsrc_open), (gst_rtspsrc_play):
+	* gst/rtsp/rtsp.h:
+	* gst/rtsp/rtspconnection.c: (rtsp_connection_create),
+	(rtsp_connection_send), (read_line), (parse_request_line),
+	(parse_line), (read_body), (rtsp_connection_receive),
+	(rtsp_connection_free):
+	* gst/rtsp/rtspconnection.h:
+	* gst/rtsp/rtspdefs.c: (rtsp_find_method):
+	* gst/rtsp/rtspdefs.h:
+	* gst/rtsp/rtspmessage.c: (rtsp_message_set_body),
+	(rtsp_message_take_body):
+	* gst/rtsp/rtspmessage.h:
+	* gst/rtsp/rtspstream.h:
+	* gst/rtsp/sdpmessage.c: (sdp_parse_line):
+	Added README
+	Some cleanups.
+
+2005-05-11  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtsp/gstrtspsrc.c: (gst_rtsp_proto_get_type),
+	(gst_rtspsrc_class_init), (gst_rtspsrc_init),
+	(gst_rtspsrc_create_stream), (gst_rtspsrc_add_element),
+	(gst_rtspsrc_set_state), (gst_rtspsrc_stream_setup_rtp),
+	(gst_rtspsrc_stream_configure_transport), (find_stream),
+	(gst_rtspsrc_loop), (gst_rtspsrc_open), (gst_rtspsrc_close),
+	(gst_rtspsrc_play), (gst_rtspsrc_change_state):
+	* gst/rtsp/gstrtspsrc.h:
+	Setup UDP sources correctly, receives raw data from RTSP
+	compliant servers now.
+
+2005-05-11  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtsp/.cvsignore:
+	* gst/rtsp/Makefile.am:
+	* gst/rtsp/gstrtsp.c: (plugin_init):
+	* gst/rtsp/gstrtsp.h:
+	* gst/rtsp/gstrtspsrc.c: (gst_rtsp_proto_get_type),
+	(gst_rtspsrc_get_type), (gst_rtspsrc_base_init),
+	(gst_rtspsrc_class_init), (gst_rtspsrc_init),
+	(gst_rtspsrc_set_property), (gst_rtspsrc_get_property),
+	(gst_rtspsrc_create_stream), (rtspsrc_add_element),
+	(gst_rtspsrc_stream_setup_rtp),
+	(gst_rtspsrc_stream_configure_transport), (find_stream),
+	(gst_rtspsrc_loop), (gst_rtspsrc_send), (gst_rtspsrc_open),
+	(gst_rtspsrc_close), (gst_rtspsrc_play), (gst_rtspsrc_pause),
+	(gst_rtspsrc_activate), (gst_rtspsrc_change_state):
+	* gst/rtsp/gstrtspsrc.h:
+	* gst/rtsp/rtsp.h:
+	* gst/rtsp/rtspconnection.c: (rtsp_connection_open),
+	(rtsp_connection_create), (append_header), (rtsp_connection_send),
+	(read_line), (read_string), (read_key), (parse_response_status),
+	(parse_line), (read_body), (rtsp_connection_receive),
+	(rtsp_connection_close):
+	* gst/rtsp/rtspconnection.h:
+	* gst/rtsp/rtspdefs.c: (rtsp_init_status), (rtsp_method_as_text),
+	(rtsp_header_as_text), (rtsp_status_as_text),
+	(rtsp_status_to_string), (rtsp_find_header_field):
+	* gst/rtsp/rtspdefs.h:
+	* gst/rtsp/rtspmessage.c: (rtsp_message_new_request),
+	(rtsp_message_init_request), (rtsp_message_new_response),
+	(rtsp_message_init_response), (rtsp_message_init_data),
+	(rtsp_message_add_header), (rtsp_message_remove_header),
+	(rtsp_message_get_header), (rtsp_message_get_header_copy),
+	(rtsp_message_set_body), (rtsp_message_set_body_copy),
+	(rtsp_message_get_body), (rtsp_message_get_body_copy), (dump_mem),
+	(dump_key_value), (rtsp_message_dump):
+	* gst/rtsp/rtspmessage.h:
+	* gst/rtsp/rtspstream.h:
+	* gst/rtsp/rtsptransport.c: (rtsp_transport_new),
+	(rtsp_transport_init), (parse_mode), (parse_range),
+	(rtsp_transport_parse), (rtsp_transport_free):
+	* gst/rtsp/rtsptransport.h:
+	* gst/rtsp/rtspurl.c: (rtsp_url_parse), (rtsp_url_free):
+	* gst/rtsp/rtspurl.h:
+	* gst/rtsp/sdp.h:
+	* gst/rtsp/sdpmessage.c: (sdp_message_new), (sdp_message_init),
+	(sdp_message_clean), (sdp_message_free), (sdp_media_new),
+	(sdp_media_init), (sdp_message_set_origin),
+	(sdp_message_get_origin), (sdp_message_set_connection),
+	(sdp_message_get_connection), (sdp_message_add_bandwidth),
+	(sdp_message_add_time), (sdp_message_add_zone),
+	(sdp_message_set_key), (sdp_message_get_key),
+	(sdp_message_get_attribute_val), (sdp_message_add_attribute),
+	(sdp_message_add_media), (sdp_media_add_attribute),
+	(sdp_media_add_bandwidth), (sdp_media_add_format),
+	(sdp_media_get_attribute_val), (read_string), (read_string_del),
+	(sdp_parse_line), (sdp_message_parse_buffer), (print_media),
+	(sdp_message_dump):
+	* gst/rtsp/sdpmessage.h:
+	* gst/rtsp/test.c: (main):
+	Ported to 0.9.
+	Set up transports, init UDP ports, init RTP session managers.
+
+2005-05-11  Wim Taymans  <wim@fluendo.com>
+
+	* gst/rtp/Makefile.am:
+	* gst/rtp/gstrtp.c: (plugin_init):
+	* gst/rtp/gstrtpdec.c: (gst_rtpdec_get_type),
+	(gst_rtpdec_class_init), (gst_rtpdec_init), (gst_rtpdec_chain_rtp),
+	(gst_rtpdec_chain_rtcp), (gst_rtpdec_set_property),
+	(gst_rtpdec_get_property), (gst_rtpdec_change_state),
+	(gst_rtpdec_plugin_init):
+	* gst/rtp/gstrtpdec.h:
+	* gst/udp/gstudpsink.c: (gst_udpsink_base_init),
+	(gst_udpsink_get_times), (gst_udpsink_render),
+	(gst_udpsink_change_state):
+	* gst/udp/gstudpsrc.c: (gst_udpsrc_get_type),
+	(gst_udpsrc_base_init), (gst_udpsrc_class_init), (gst_udpsrc_init),
+	(gst_udpsrc_loop), (gst_udpsrc_set_uri), (gst_udpsrc_set_property),
+	(gst_udpsrc_get_property), (gst_udpsrc_init_receive),
+	(gst_udpsrc_activate), (gst_udpsrc_change_state),
+	(gst_udpsrc_uri_get_type), (gst_udpsrc_uri_get_protocols),
+	(gst_udpsrc_uri_get_uri), (gst_udpsrc_uri_set_uri),
+	(gst_udpsrc_uri_handler_init):
+	* gst/udp/gstudpsrc.h:
+	UDP fixes, added uri handler.
+	Added rtpdec that will manage the RTP session in the future.
+
+2005-05-10  Arwed v. Merkatz  <v.merkatz@gmx.net>
+
+	* PORTED_09:
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/esd/Makefile.am:
+	* ext/esd/esdsink.c: (gst_esdsink_get_type),
+	(gst_esdsink_class_init), (gst_esdsink_init),
+	(gst_esdsink_dispose), (gst_esdsink_change_state),
+	(gst_caps_set_each), (gst_esdsink_getcaps), (gst_esdsink_open),
+	(gst_esdsink_close), (gst_esdsink_write), (gst_esdsink_delay),
+	(gst_esdsink_reset), (gst_esdsink_set_property),
+	(gst_esdsink_get_property), (gst_esdsink_factory_init):
+	* ext/esd/esdsink.h:
+	* ext/esd/gstesd.c: (plugin_init):
+	Ported esdsink plugin
+
+2005-05-10  Wim Taymans  <wim@fluendo.com>
+
+	* gst/udp/Makefile.am:
+	* gst/udp/gstudpsink.c: (gst_udpsink_get_type),
+	(gst_udpsink_base_init), (gst_udpsink_class_init),
+	(gst_udpsink_init), (gst_udpsink_get_times), (gst_udpsink_render),
+	(gst_udpsink_set_property), (gst_udpsink_get_property),
+	(gst_udpsink_init_send), (gst_udpsink_close),
+	(gst_udpsink_change_state):
+	* gst/udp/gstudpsink.h:
+	* gst/udp/gstudpsrc.c: (gst_udpsrc_base_init),
+	(gst_udpsrc_class_init), (gst_udpsrc_init), (gst_udpsrc_loop),
+	(gst_udpsrc_set_property), (gst_udpsrc_get_property),
+	(gst_udpsrc_init_receive), (gst_udpsrc_close),
+	(gst_udpsrc_activate), (gst_udpsrc_change_state):
+	* gst/udp/gstudpsrc.h:
+	Ported udp src/sink.
+
+2005-05-09  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* PORTED_09:
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/shout2/Makefile.am:
+	* ext/shout2/gstshout2.c: (gst_shout2send_get_type),
+	(gst_shout2send_base_init), (gst_shout2send_class_init),
+	(gst_shout2send_init), (gst_shout2send_event),
+	(gst_shout2send_render), (gst_shout2send_set_property),
+	(gst_shout2send_get_property), (gst_shout2send_setcaps),
+	(gst_shout2send_change_state):
+	* ext/shout2/gstshout2.h:
+
+	Port shout2 plugin
+
+2005-05-08  Zeeshan Ali   <zeenix@gmail.com>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/libcaca/Makefile.am:
+	* ext/libcaca/gstcacasink.c: (gst_cacasink_get_type),
+	(gst_cacasink_class_init), (gst_cacasink_get_times),
+	(gst_cacasink_setcaps), (gst_cacasink_init), (gst_cacasink_render),
+	(plugin_init):
+	* ext/libcaca/gstcacasink.h:
+	Ported the libcaca plugin.
+
+2005-05-08  Zeeshan Ali  <zeenix@gmail.com>
+
+	* configure.ac:
+	* ext/mad/Makefile.am:
+	* effectv/Makefile.am:
+	Fixed a few things to enable the mad and effectv to be able to find the
+	headers in the gst-plugins-base/gst-libs and to link against the libs
+	in there.
+
+2005-05-07  Zeeshan Ali  <zeenix@gmail.com>
+
+	* configure.ac:
+	Fixed the build by fixing a small mistake of Wim.
+	
+2005-05-06  Wim Taymans  <wim@fluendo.com>
+
+	* configure.ac:
+	* ext/aalib/Makefile.am:
+	* ext/aalib/gstaasink.c: (gst_aasink_get_type),
+	(gst_aasink_class_init), (gst_aasink_fixate), (gst_aasink_setcaps),
+	(gst_aasink_init), (gst_aasink_get_times), (gst_aasink_render),
+	(gst_aasink_set_property), (gst_aasink_get_property),
+	(gst_aasink_open), (gst_aasink_close), (gst_aasink_change_state):
+	* ext/aalib/gstaasink.h:
+	* gst/smpte/Makefile.am:
+	* gst/smpte/gstsmpte.c: (gst_smpte_setcaps), (gst_smpte_init),
+	(gst_smpte_collected):
+	* gst/smpte/gstsmpte.h:
+	Ported 2 more plugins. usgly hack in the Makefile.am though, I'm
+	sure someone will fix it.
+
+2005-05-06  Christian Schaller  <uraeus@gnome.org>
+
+	* configure.ac: add sidplay
+	* ext/Makefile.am: add sidplay
+	* ext/sidplay/Makefile.am: add GST_PLUGINS_CFLAGS
+	* ext/sidplay/gstsiddec.cc: remove bytestream.h
+
+2005-05-06  Christian Schaller  <uraeus@gnome.org>
+
+	* configure.ac: add gst-plugins-libs
+
+2005-05-06  Wim Taymans  <wim@fluendo.com>
+
+	* configure.ac:
+	* ext/sidplay/gstsiddec.cc:
+	* ext/sidplay/gstsiddec.h:
+	Ported sidplay.
+
+2005-05-06  Christian Schaller  <uraeus@gnome.org>
+
+	* configure.ac: 
+	* ext/mad/Makefile.am: add linking of gstinterfaces
+	* ext/mad/gstid3tag.c: (plugin_init): remove library_load
+	* gst-plugins.spec.in: 
+	* gst/effectv/Makefile.am: link to libgstvideofilter
+	* gst/effectv/gsteffectv.c: (plugin_init): same as for mad
+	* gst/videofilter/Makefile.am: make sure videoflip is not built
+
+2005-05-06  Wim Taymans  <wim@fluendo.com>
+
+	* gst/law/alaw-decode.c: (alawdec_getcaps), (alawdec_setcaps),
+	(gst_alawdec_init), (gst_alawdec_chain):
+	* gst/law/alaw-encode.c: (alawenc_getcaps), (alawenc_setcaps),
+	(gst_alawenc_init), (gst_alawenc_chain):
+	* gst/law/mulaw-decode.c: (mulawdec_getcaps), (mulawdec_setcaps),
+	(gst_mulawdec_init), (gst_mulawdec_chain):
+	* gst/law/mulaw-encode.c: (mulawenc_getcaps), (mulawenc_setcaps),
+	(gst_mulawenc_init), (gst_mulawenc_chain):
+	Ported alaw and mulaw plugins to 0.9, fixed the negotiation as
+	well.
+
+2005-05-06  Christian Schaller  <uraeus@gnome.org>
+
+	* ext/alsa: removed plugins that are now in gst-plugins-base
+	* ext/gnomevfs:
+	* ext/theora:
+	* ext/vorbis:
+	* gst/adder:
+	* gst/audioconvert:
+	* gst/ffmpegcolorspace:
+	* gst/typefind:
+	* gst/videofilter: comment out videoflip and gamma plugins
+
+2005-05-06  Christian Schaller  <uraeus@gnome.org>
+
+	* gst-libs: Remove all files as this is in gst-plugins-base now
+	* gst-libs/README: add a remove informing of this move
+
+2005-05-06  Christian Schaller <uraeus@gnome.org> 
+
+	* PORTED_09: update to add videofilter
+	* configure.ac: re-add videofilter
+	* gst/videofilter/Makefile.am: remove videobalance (not ported yet)
+	* gst/videofilter/gstgamma.c: (gst_gamma_class_init):
+	* gst/videofilter/gstvideobalance.c: (gst_videobalance_class_init):
+	* gst/videofilter/gstvideofilter.c: (gst_videofilter_getcaps),
+	(gst_videofilter_setcaps), (gst_videofilter_init),
+	(gst_videofilter_chain), (gst_videofilter_set_output_size):
+	* gst/videofilter/gstvideoflip.c: (gst_videoflip_class_init):
+
+2005-05-06  Christian Schaller <uraeus@gnome.org>
+
+	* ext/mad: ported plugin from threaded branch
+	* gst/effectv: ported plugins from threaded branch
+	* gst/law: enable law plugin as it compiles (Wim will fixor)
+
+2005-05-06  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* configure.ac:
+	fix typo
+
+2005-05-05  Christian Schaller <uraeus@gnome.org>
+
+	* Update configure.ac and Makefiles to only build what is actually
+	ported and not moved into gst-plugins-base
+
+2005-02-22  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	  hunting season on 0.9 is now OPEN
+
+2005-02-22  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/oss/gstosselement.c: (gst_osselement_class_probe_devices):
+	  Kick the hell out of gcc for not warning me about a symbol conflict.
+
+2005-02-22  Luca Ognibene  <luogni@tin.it>
+
+	Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/gdk_pixbuf/pixbufscale.c: (gst_pixbufscale_link):
+	  Don't leak caps string (fixes #168134)
+
+	* ext/jpeg/gstjpegenc.c: (gst_jpegenc_class_init),
+	(gst_jpegenc_init), (gst_jpegenc_finalize),
+	(gst_jpegenc_change_state):
+	  Don't leak line buffers and context struct (fixes #168133).
+
+2005-02-21  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* configure.ac:
+	* ext/dirac/gstdiracdec.cc:
+	(gst_diracdec_chain):
+	  Since dirac 0.5.0 the framerate in dirac is expressed as a
+	  rational number. Fix build and up requirement to 0.5.0, and
+	  also pass parameters to gst_diracdec_link in the right order
+	  (fixes #167959).
+
+2005-02-21  Maciej Katafiasz  <mathrick@freedesktop.org>
+
+	* ext/faad/gstfaad.c: (gst_faad_sinkconnect), (gst_faad_chain):
+	* ext/faad/gstfaad.h:
+	TEH LONGEST DEBUGGING SESSION EVAR is over. Fix interaction with 
+	certain invalid muxed streams, where some packets will contain 
+	junk after decoder data. Partially fixes #149158.
+
+2005-02-21  Jan Schmidt <thaytan@mad.scientist.com>
+	* gst/dvdlpcmdec/gstdvdlpcmdec.c: (gst_dvdlpcmdec_chain):
+          Make sure we only write to writable buffers
+
+2005-02-20  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_audio_caps_with_data):
+	  Do actually fix invalid RIFF fmt header values for alaw
+	  and mulaw audio instead of just saying so.
+
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_fmt):
+	  Give gst_riff_create_audio_caps_with_data() a chance to
+	  fix up broken format header fields before extracting any
+	  parameters from the header. (fixes #167633)
+
+2005-02-19  Martin Holters  <martin.holters@gmx.de>
+
+	Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+
+	* gst/audioconvert/bufferframesconvert.c:
+	(buffer_frames_convert_link):
+	  Don't leak othercaps. (fixes #167878)
+
+2005-02-19  Arwed v. Merkatz  <v.merkatz@gmx.net>>
+
+	* configure.ac:
+	* ext/libvisual/visual.c: (gst_visual_srclink),
+	(gst_visual_change_state):
+	  Support libvisual 0.2.0.
+
+2005-02-18  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/jpeg/gstjpegdec.c: (gst_jpegdec_chain):
+	* ext/jpeg/gstjpegenc.c: (gst_jpegenc_resync), (gst_jpegenc_chain):
+	  Use same rowstrides for I420 as used everywhere else.
+
+2005-02-17  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_invert):
+	  Declare variables at beginning of block and make gcc-2.95 happy
+	  (fixes # 167482, patch by Gergely Nagy).
+	  
+	* gst/tcp/gsttcpclientsrc.c:
+	* gst/tcp/gsttcpclientsrc.h:
+	  Move some includes into the header, so that struct sockaddr_in is
+	  defined when it should be defined on FreeBSD as well (fixes
+	  #167483).
+	  
+	* gst/tcp/gsttcpserversrc.c: (gst_tcpserversrc_init_receive):
+	  Don't pass uninitialised values to setsockopt() here either.
+
+2005-02-17  Luca Ognibene  <luogni at tin dot it>
+
+	Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+
+	* gst/tcp/gsttcpserversink.c: (gst_tcpserversink_init_send):
+	  Don't pass uninitialised values to setsockopt(). (fixes #167704)
+
+2005-02-16  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybin.c: (add_sink):
+	  Invert bin_add/link order to workaround deadlock in opt.
+
+2005-02-15  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/modplug/gstmodplug.cc:
+	  Add missing break causing position queries to fail.
+
+2005-02-15  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_pad_populate):
+	  Granpos can apparently be -1, which screws up calculations...
+
+2005-02-16  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_chain),
+	(gst_ximagesink_send_pending_navigation),
+	(gst_ximagesink_navigation_send_event), (gst_ximagesink_finalize),
+	(gst_ximagesink_init):
+	* sys/ximage/ximagesink.h:
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_chain),
+	(gst_xvimagesink_send_pending_navigation),
+	(gst_xvimagesink_navigation_send_event),
+	(gst_xvimagesink_finalize), (gst_xvimagesink_init):
+	* sys/xvimage/xvimagesink.h:
+	  Use a mutex protected list to marshal navigation
+	  events into the stream thread from whichever thread
+	  sends them.
+
+2005-02-15  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* gst/speed/demo-mp3.c: (time_tick_cb), (main):
+	  Display current position and track length; misc. clean-ups.
+	  
+	* gst/speed/gstspeed.c: (speed_get_query_types), (speed_src_query),
+	(speed_init), (speed_chain):
+	  Add query function, so that the stream length and current position
+	  get adjusted when queried (note that current position queries may
+	  still be wrong if the audio sink returns values based on buffer
+	  timestamps instead of passing on the query).
+
+2005-02-13  Benjamin Otte  <otte@gnome.org>
+
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_link),
+	(gst_audio_convert_channels):
+	  create channel conversion matrix when linking
+	* gst/audioconvert/.cvsignore:
+	* gst/audioconvert/Makefile.am:
+	* gst/audioconvert/channelmixtest.c: (main):
+	  add (ugly) test that ensures stereo <=> mono conversion works
+	  correctly
+
+2005-02-13  Benjamin Otte  <otte@gnome.org>
+
+	* gst/audioconvert/gstchannelmix.h:
+	  include missing header file
+	* gst/audioconvert/gstchannelmix.c:
+	(gst_audio_convert_fill_compatible):
+	  use same sign for both channels when converting to/from compatible
+	  channel. Previously used different signs made the signals cancel
+	  each other out and appear like silence. (fixes #167269)
+
+2005-02-12  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* gst/ffmpegcolorspace/avcodec.h:
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c:
+	(gst_ffmpeg_pixfmt_to_caps), (gst_ffmpeg_caps_to_pixfmt),
+	(gst_ffmpegcsp_avpicture_fill):
+	* gst/ffmpegcolorspace/imgconvert.c:
+	  Convert to and from YV12 (fixes #156379).
+
+2005-02-12  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xwindow_new),
+	(gst_ximagesink_sink_link), (gst_ximagesink_change_state),
+	(gst_ximagesink_chain), (gst_ximagesink_set_xwindow_id),
+	(gst_ximagesink_expose), (gst_ximagesink_set_property),
+	(gst_ximagesink_finalize), (gst_ximagesink_init): Protect interface
+        methods from chain and negotiation and vice versa (Fixes #166142).
+	* sys/ximage/ximagesink.h: Add stream_lock.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_sink_link),
+	(gst_xvimagesink_chain), (gst_xvimagesink_buffer_free),
+	(gst_xvimagesink_buffer_alloc), (gst_xvimagesink_set_xwindow_id),
+	(gst_xvimagesink_expose): Check for xcontext before trying to link.
+
+2005-02-12  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/dvdnav/dvdnavsrc.c: (dvdnavsrc_open):
+	  Don't send "Hey! You gave me a NULL pointer you naughty person" as
+	  error message when we can't open the DVD device (when dvdnav_open()
+	  fails, src->dvdnav is NULL, so dvdnav_err_to_string() will return
+	  the above). Send something more useful instead (fixes #167117).
+
+2005-02-11  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xvimage_put),
+	(gst_xvimagesink_sink_link), (gst_xvimagesink_change_state),
+	(gst_xvimagesink_chain), (gst_xvimagesink_buffer_free),
+	(gst_xvimagesink_buffer_alloc), (gst_xvimagesink_set_xwindow_id),
+	(gst_xvimagesink_expose), (gst_xvimagesink_set_property),
+	(gst_xvimagesink_finalize), (gst_xvimagesink_init): Protect interface
+	methods from chain and negotiation and vice versa (Fixes #166142).
+	Fix a possible bug of images in the buffer pool being discarded because
+	we are looking at the wrong geometry.
+	* sys/xvimage/xvimagesink.h: Add stream_lock.
+
+2005-02-11  David Schleef  <ds@schleef.org>
+
+	* ext/mpeg2dec/gstmpeg2dec.c: (crop_buffer): Change uint to
+	unsigned int. (fixes #167128)
+
+2005-02-11  David Schleef  <ds@schleef.org>
+
+	* gst/librfb/Makefile.am: Testing stuff before committing is
+	  for wimps... and people with fast machines.  Fix stupid
+	  mistake.
+
+2005-02-11  David Schleef  <ds@schleef.org>
+
+	* configure.ac: Pull in librfb from my CVS tree, because it is
+	  too small and annoying to be separate.  Move rfbsrc plugin
+	  to gst/.
+	* ext/Makefile.am:
+	* ext/librfb/Makefile.am:
+	* ext/librfb/gstrfbsrc.c:
+	* gst/librfb/Makefile.am:
+	* gst/librfb/gstrfbsrc.c:
+	* gst/librfb/rfb.c:
+	* gst/librfb/rfb.h:
+	* gst/librfb/rfbbuffer.c:
+	* gst/librfb/rfbbuffer.h:
+	* gst/librfb/rfbbytestream.c:
+	* gst/librfb/rfbbytestream.h:
+	* gst/librfb/rfbcontext.h:
+	* gst/librfb/rfbdecoder.c:
+	* gst/librfb/rfbdecoder.h:
+	* gst/librfb/rfbutil.h:
+
+2005-02-10  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* gst/speed/Makefile.am:
+	* gst/speed/demo-mp3.c: (main):
+	* gst/speed/filter.func:
+	* gst/speed/gstspeed.c: (speed_link), (speed_parse_caps),
+	(speed_class_init), (speed_init), (speed_chain_int16),
+	(speed_chain_float32), (speed_chain), (speed_set_property),
+	(speed_get_property), (speed_change_state):
+	* gst/speed/gstspeed.h:
+	  Fix speed element and make it chain-based (fixes #156467),
+	  and make it handle more than one channel.
+
+2005-02-10  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/dts/gstdtsdec.c: (gst_dtsdec_init), (gst_dtsdec_channels),
+	(gst_dtsdec_handle_event), (gst_dtsdec_handle_frame),
+	(gst_dtsdec_chain), (gst_dtsdec_change_state):
+	* ext/dts/gstdtsdec.h:
+          Don't clobber the stack constructing the channels array.
+	  Make the element chain-based. DTS tracks can now be played.
+	  
+2005-02-09  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* gst-libs/gst/audio/multichannel.h:
+	* gst-libs/gst/gconf/gconf.h:
+	* gst-libs/gst/idct/idct.h:
+	* gst-libs/gst/media-info/media-info-priv.h:
+	* gst-libs/gst/play/play.h:
+	* gst-libs/gst/resample/private.h:
+	* gst-libs/gst/resample/resample.h:
+	* gst-libs/gst/riff/riff-ids.h:
+	* gst-libs/gst/video/video.h:
+	* gst-libs/gst/video/videosink.h:
+	  Add G_BEGIN_DECLS and G_END_DECLS around headers where
+	  missing, so that they work when included from C++ code.
+
+2005-02-09  David Schleef  <ds@schleef.org>
+
+	* testsuite/gst-lint: Check for non-statically scoped
+	  parent_class variables.  This won't be a problem once
+	  plugins are loaded with RTLD_LOCAL.
+
+2005-02-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mplex/gstmplexibitstream.cc:
+	  gcc madness.
+
+2005-02-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstogmparse.c:
+	* gst/debug/gstnavigationtest.c:
+	  Die, thou faulty symbol pollutors (non-static parent_class).
+
+2005-02-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mplex/gstmplexibitstream.cc:
+	  Fix event handling (#165525).
+
+2005-02-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mikmod/gstmikmod.c:
+	* gst/modplug/gstmodplug.cc:
+	  Add missing endianness to template (fixes #165509).
+
+2005-02-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_handle_data):
+	  Fix wrong order of reading of optional bytes (#165290).
+
+2005-02-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event):
+	  Implement FILLER event awareness.
+
+2005-02-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/cdparanoia/gstcdparanoia.c: (cdparanoia_convert):
+	  Fix track calculations (#166208).
+
+2005-02-08  Gergely Nagy  <algernon@bonehunter.rulez.org>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/libpng/gstpngdec.c: (gst_pngdec_init), (gst_pngdec_chain):
+	* ext/libpng/gstpngenc.c:
+	  Fix byte-order, use proper fixed caps. Fixes #164197.
+
+2005-02-08  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* configure.ac:
+	  Add dvdlpcmdec 
+
+	* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_reset),
+	(free_all_buffers), (gst_mpeg2dec_alloc_buffer):
+	  Don't push buffers if the src pad isn't negotiated yet.
+	  
+	* gst/audioconvert/gstaudioconvert.c:
+	(gst_audio_convert_buffer_to_default_format),
+	(gst_audio_convert_buffer_from_default_format):
+	  Add support for 24-bit width.
+
+	* gst/dvdlpcmdec/.cvsignore:
+	* gst/dvdlpcmdec/Makefile.am:
+	* gst/dvdlpcmdec/gstdvdlpcmdec.c: (gst_dvdlpcmdec_get_type),
+	(gst_dvdlpcmdec_base_init), (gst_dvdlpcmdec_class_init),
+	(gst_dvdlpcm_reset), (gst_dvdlpcmdec_init), (gst_dvdlpcmdec_link),
+	(gst_dvdlpcmdec_chain), (gst_dvdlpcmdec_change_state),
+	(plugin_init):
+	* gst/dvdlpcmdec/gstdvdlpcmdec.h:
+	  New decoder for rearranging DVD LPCM into our audio/x-raw-int
+	  format. Needs support for the channels maps if someone can find 
+	  a DVD LPCM track with > 2 channels.
+
+	* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_handle_dvd_event),
+	(gst_dvd_demux_send_discont), (gst_dvd_demux_handle_discont),
+	(gst_dvd_demux_get_audio_stream), (gst_dvd_demux_process_private):
+	* gst/mpegstream/gstdvddemux.h:
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_send_discont),
+	(gst_mpeg_demux_new_output_pad), (gst_mpeg_demux_init_stream),
+	(gst_mpeg_demux_send_subbuffer), (gst_mpeg_demux_handle_src_query):
+	* gst/mpegstream/gstmpegdemux.h:
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_reset),
+	(gst_mpeg_parse_parse_packhead), (gst_mpeg_parse_loop),
+	(gst_mpeg_parse_get_rate), (gst_mpeg_parse_convert_src),
+	(gst_mpeg_parse_handle_src_query),
+	(gst_mpeg_parse_handle_src_event):
+	  Use audio/x-dvd-lpcm for LPCM output.
+	  Add DTS output.
+
+2005-02-08  Gergely Nagy  <algernon@bonehunter.rulez.org>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/alpha/gstalphacolor.c: (gst_alpha_color_sink_link),
+	(transform_rgb), (transform_bgr), (gst_alpha_color_chain):
+	  Add BGRA handling (#165736).
+
+2005-02-08  Francis Labonte  <francis_labonte@hotmail.com>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/law/alaw-decode.c: (alawdec_link):
+	* gst/law/alaw-encode.c: (alawenc_link):
+	* gst/law/mulaw-decode.c: (mulawdec_link):
+	* gst/law/mulaw-encode.c: (mulawenc_link):
+	  Fix caps memleaks (#166600).
+
+2005-02-08  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/tarkin/mem.h:
+	* ext/tarkin/wavelet.h:
+	* ext/tarkin/yuv.h:
+	* gst/ffmpegcolorspace/avcodec.h:
+	  Include "_stdint.h" instead of <stdint.h>. Fixes build on
+	  systems that don't have stdint.h, like Solaris9 (fixes #166631).
+
+2005-02-05  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_change_state):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xwindow_clear),
+	(gst_xvimagesink_change_state):
+	  Clear window on PAUSED->READY instead of READY->PAUSED. Stop
+	  Xv video (and thereby regenerate Xv colourkey) in clear() so
+	  that PLAY -> READY -> PLAY works (fixes #162504).
+
+2005-02-05  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_getcaps):
+	  Switch to list instead of range, since MJPEG-devices really just
+	  support decimations, not any size.
+
+2005-02-05  Jan Schmidt  <thaytan@mad.scientist.com>
+	* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_open_decoder),
+	(gst_mpeg2dec_reset), (free_all_buffers),
+	(gst_mpeg2dec_alloc_buffer), (handle_sequence):
+	* ext/mpeg2dec/gstmpeg2dec.h:
+	  The libmpeg2 user-allocated buffer management is awkward, 
+	  to say the least. Hopefully this fixes things.
+
+2005-02-04  Andy Wingo  <wingo@pobox.com>
+
+	* gst/audioconvert/bufferframesconvert.c
+	(buffer_frames_convert_fixate): New function, fixates to 256
+	frames per buffer by default. (Much better than 1.)
+	(buffer_frames_convert_init): Set the fixate function for both src
+	and sink pad.
+	(buffer_frames_convert_link): After success setting nonfixed caps,
+	get the negotiated caps so we can know how many buffer-frames it
+	will be. No idea how this worked at all before.
+
+2005-02-05  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_init),
+	(gst_mpeg2dec_close_decoder), (put_buffer), (check_buffer),
+	(free_buffer), (free_all_buffers), (gst_mpeg2dec_alloc_buffer),
+	(handle_sequence), (handle_picture):
+	* ext/mpeg2dec/gstmpeg2dec.h:
+	  Rearrange buffer tracking and refcounting and refactor
+	  a little for readability. 
+
+2005-02-04  Jan Schmidt  <thaytan@mad.scientist.com>
+	* sys/v4l/gstv4l.c: (plugin_init):
+	* sys/v4l/gstv4ljpegsrc.c: (gst_v4ljpegsrc_get_type),
+	(gst_v4ljpegsrc_base_init), (gst_v4ljpegsrc_class_init),
+	(gst_v4ljpegsrc_init), (gst_v4ljpegsrc_src_link),
+	(gst_v4ljpegsrc_getcaps), (gst_v4ljpegsrc_get):
+	* sys/v4l/gstv4ljpegsrc.h:
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_open), (gst_v4lsrc_src_link):
+	* sys/v4l/v4l_calls.h:
+	* sys/v4l/v4lsrc_calls.c: (gst_v4lsrc_palette_name),
+	(gst_v4lsrc_get_fps):
+	* sys/v4l/v4lsrc_calls.h:
+	  Add new v4ljpegsrc for handling the ov51x hacky "I'll give
+	  you jpeg inside rgb frames" driver.
+	  Don't error in the v4lsrc link function, just return 
+	  REFUSED.
+
+2005-02-03  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/qcam/gstqcamsrc.c: (gst_qcamsrc_change_state),
+	(gst_qcamsrc_open):
+	  Use GST_ELEMENT_ERROR, not g_warning, if open failed.
+
+2005-02-02  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/qtdemux/qtdemux.c: (qtdemux_video_caps):
+	  Change caps on MJPEG-B so it doesn't interfere with MJPEG/JPEG.
+
+2005-02-02  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/raw1394/gstdv1394src.c: (gst_dv1394src_change_state):
+	  Reset negotiated state on PAUSED->READY.
+
+2005-02-02  David Schleef  <ds@schleef.org>
+
+	* configure.ac: Put DEFAULT_AUDIOSINK in config.h and use
+	whereever possible.  (Fixes #165997)
+	* examples/capsfilter/capsfilter1.c: (main):
+	* examples/dynparams/filter.c: (create_ui):
+	* examples/seeking/cdparanoia.c: (get_track_info), (main):
+	* examples/seeking/chained.c: (main):
+	* examples/seeking/seek.c: (make_mod_pipeline), (make_dv_pipeline),
+	(make_wav_pipeline), (make_flac_pipeline), (make_sid_pipeline),
+	(make_vorbis_pipeline), (make_mp3_pipeline), (make_avi_pipeline),
+	(make_mpeg_pipeline), (make_mpegnt_pipeline):
+	* examples/seeking/spider_seek.c: (make_spider_pipeline):
+	* examples/switch/switcher.c: (main):
+	* ext/dv/demo-play.c: (main):
+	* ext/faad/gstfaad.c: (gst_faad_change_state):
+	* ext/mad/gstmad.c: (gst_mad_chain):
+	* ext/smoothwave/demo-osssrc.c: (main):
+	* gst-libs/gst/gconf/gconf.c: (gst_gconf_set_string),
+	(gst_gconf_render_bin_from_description),
+	(gst_gconf_get_default_audio_sink),
+	(gst_gconf_get_default_video_sink),
+	(gst_gconf_get_default_audio_src),
+	(gst_gconf_get_default_video_src),
+	(gst_gconf_get_default_visualization_element):
+	* gst/level/demo.c: (main):
+	* gst/level/plot.c: (main):
+	* gst/playback/gstplaybin.c: (gen_video_element),
+	(gen_audio_element):
+	* gst/playback/test.c: (gen_video_element), (gen_audio_element):
+	* gst/playondemand/demo-mp3.c: (setup_pipeline):
+	* gst/sine/demo-dparams.c: (main):
+	* gst/spectrum/demo-osssrc.c: (main):
+	* gst/speed/demo-mp3.c: (main):
+	* gst/volume/demo.c: (main):
+	* testsuite/embed/embed.c: (main):
+
+2005-02-02  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* gst/tcp/gsttcpclientsink.c: (gst_tcpclientsink_class_init),
+	(gst_tcpclientsink_finalize):
+	* gst/tcp/gsttcpclientsrc.c: (gst_tcpclientsrc_class_init),
+	(gst_tcpclientsrc_finalize):
+	* gst/tcp/gsttcpserversink.c: (gst_tcpserversink_class_init),
+	(gst_tcpserversink_init), (gst_tcpserversink_finalize):
+	* gst/tcp/gsttcpserversrc.c: (gst_tcpserversrc_class_init),
+	(gst_tcpserversrc_init), (gst_tcpserversrc_finalize):
+	  Don't leak the hostname when shutting down.
+	  In tcpserversrc, take a copy of the default hostname.
+
+2005-02-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/raw1394/gstdv1394src.c: (gst_dv1394src_iso_receive):
+	  Set caps to systemstream=TRUE.
+
+2005-02-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* testsuite/Makefile.am:
+	  Fix more OSX buildbots.
+
+2005-02-02  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/mpeg2dec/gstmpeg2dec.c:
+	  Don't send things to NULL PAD_PEERs
+
+	* gst/deinterlace/gstdeinterlace.c: (gst_deinterlace_chain):
+	  Copy-on-write the incoming buffer.
+
+	* gst/mpegstream/gstdvddemux.h:
+	* gst/mpegstream/gstmpegclock.h:
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_parse_syshead),
+	(normal_seek), (gst_mpeg_demux_handle_src_event):
+	* gst/mpegstream/gstmpegdemux.h:
+	* gst/mpegstream/gstmpegpacketize.h:
+	* gst/mpegstream/gstmpegparse.c:
+	(gst_mpeg_parse_update_streaminfo), (gst_mpeg_parse_reset),
+	(gst_mpeg_parse_handle_discont), (gst_mpeg_parse_parse_packhead),
+	(gst_mpeg_parse_loop), (gst_mpeg_parse_get_rate),
+	(gst_mpeg_parse_convert_src), (gst_mpeg_parse_handle_src_query),
+	(gst_mpeg_parse_handle_src_event), (gst_mpeg_parse_change_state):
+	* gst/mpegstream/gstmpegparse.h:
+	* gst/mpegstream/gstrfc2250enc.h:
+          Various changes to the way time is computed that make seeking and
+	  total time estimation much better here.
+	  Use G_BEGIN/END_DECLS instead of __cplusplus
+
+	* gst/videocrop/gstvideocrop.c: (gst_video_crop_chain):
+	  Use gst_buffer_stamp instead of only copying the TIMESTAMP
+
+2005-02-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/subparse/gstsubparse.c:
+	  Fix OSX buildbot.
+
+2005-01-31  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/theora/theoraenc.c: (theora_buffer_from_packet),
+	(theora_enc_chain), (theora_enc_change_state):
+	* ext/vorbis/vorbisenc.c: (gst_vorbisenc_init),
+	(gst_vorbisenc_buffer_from_packet), (gst_vorbisenc_chain),
+	(gst_vorbisenc_change_state):
+	* ext/vorbis/vorbisenc.h:
+	  Set granulepos and timestamp correctly for streams not
+	  starting at 0, taking into account the initial delay.
+
+2005-01-31  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* gst/mpegstream/gstdvddemux.c:
+	  Add audio/x-dts to audio pad template caps
+
+2005-01-30  David Schleef  <ds@schleef.org>
+
+	* ext/polyp/polypsink.c: (gst_polypsink_base_init),
+	(create_context), (gst_polypsink_link): Fix silly endianness
+	bug.  Add some debugging.  Remove float from caps; it doesn't
+	work.  Attempt to get remote audio working.
+
+2005-01-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/qtdemux/qtdemux.c: (qtdemux_video_caps):
+	  Add 3IV2 fourcc.
+
+2005-01-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_add_stream), (swap_line),
+	(gst_avi_demux_invert), (gst_avi_demux_process_next_entry),
+	(gst_avi_demux_stream_data):
+	* gst/avi/gstavidemux.h:
+	  Invert DIB images. Fixes #132341.
+
+2005-01-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+	(gst_ffmpegcsp_chain):
+	  D'oh, reference the palette data, not the palette structure.
+	  Fixes color distortion in #132341.
+
+2005-01-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/videoscale/gstvideoscale.c: (gst_videoscale_link):
+	  PAR can be non-fixed when not provided as argument (#162626).
+
+2005-01-29  David Moore  <dcm@acm.org>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_change_state),
+	(gst_qtdemux_loop_header):
+	  Re-apply patch from #142272 that allows non-seekable sources,
+	  re-proposed by Daniel Drake <dsd@gentoo.org>.
+
+2005-01-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/rtp/gstrtpgsmenc.c: (gst_rtpgsmenc_init):
+	  Use the src template for creating the src pad (#162330).
+
+2005-01-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* ext/musepack/Makefile.am:
+	* ext/musepack/gstmusepackdec.c: (gst_musepackdec_class_init),
+	(gst_musepackdec_init), (gst_musepackdec_dispose),
+	(gst_musepackdec_src_query), (gst_musepackdec_src_convert),
+	(gst_musepack_stream_init), (gst_musepackdec_loop),
+	(gst_musepackdec_change_state):
+	* ext/musepack/gstmusepackdec.cpp:
+	* ext/musepack/gstmusepackdec.h:
+	* ext/musepack/gstmusepackreader.c: (gst_musepack_reader_peek),
+	(gst_musepack_reader_read), (gst_musepack_reader_seek),
+	(gst_musepack_reader_tell), (gst_musepack_reader_get_size),
+	(gst_musepack_reader_canseek), (gst_musepack_init_reader):
+	* ext/musepack/gstmusepackreader.cpp:
+	* ext/musepack/gstmusepackreader.h:
+	  Update to 1.1 API (#165446).
+
+2005-01-28  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/Makefile.am:
+	  Unbreak buildbot.
+
+2005-01-28  Andy Wingo  <wingo@pobox.com>
+
+	* ext/dv/gstdvdec.c: Change the pixel aspect ratio of dvdec output
+	to reflect a different dubious internet source. Add a reference
+	and some commentary.
+
+2005-01-28  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gststreamselector.c: (gst_stream_selector_init),
+	(gst_stream_selector_get_caps), (gst_stream_selector_chain):
+	* gst/playback/gststreamselector.h:
+	  Be more selective when we're redoing caps negotiation from
+	  within the chain function on a stream change.
+
+2005-01-28  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/amrnb/Makefile.am:
+	* ext/amrnb/amrnb.c: (plugin_init):
+	* ext/amrnb/amrnbdec.c: (gst_amrnbdec_get_type),
+	(gst_amrnbdec_base_init), (gst_amrnbdec_class_init),
+	(gst_amrnbdec_init), (gst_amrnbdec_link), (gst_amrnbdec_chain),
+	(gst_amrnbdec_state_change):
+	* ext/amrnb/amrnbdec.h:
+	* ext/amrnb/amrnbparse.c: (gst_amrnbparse_get_type),
+	(gst_amrnbparse_base_init), (gst_amrnbparse_class_init),
+	(gst_amrnbparse_init), (gst_amrnbparse_formats),
+	(gst_amrnbparse_querytypes), (gst_amrnbparse_query),
+	(gst_amrnbparse_handle_event), (gst_amrnbparse_reserve),
+	(gst_amrnbparse_loop), (gst_amrnbparse_state_change):
+	* ext/amrnb/amrnbparse.h:
+	  Add support for AMR-NB (mobile phone audio format; #155163, #163286).
+	* gst/typefind/gsttypefindfunctions.c: (plugin_init):
+	  Add AMR-NB/-WB raw formats.
+	* ext/alsa/gstalsa.c: (gst_alsa_link):
+	  Keep valid time when changing format.
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header),
+	(qtdemux_parse_trak):
+	  Add some more format-specific options (#140141, #143555, #155163).
+
+2005-01-28  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/matroska-demux.c:
+	(gst_matroska_demux_parse_blockgroup):
+	  Fix logic error in timing of subtitle stream synchronization.
+	* gst/typefind/gsttypefindfunctions.c: (qt_type_find):
+	  Add skip-chunk, which is found in kodak-camera streams.
+
+2005-01-27  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* po/LINGUAS:
+	* po/vi.po:
+	  Adding Vietnamese translation (submitted by Clytie Siddall)
+
+2005-01-27  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstdecodebin.c: (try_to_link_1):
+	  Use realpad for signal.
+
+2005-01-27  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mad/gstid3demuxbin.c: (gst_id3demux_bin_base_init):
+	  Fix category so decodebin picks it up.
+
+2005-01-27  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mad/Makefile.am:
+	* ext/mad/gstid3demuxbin.c: (gst_id3demux_bin_get_type),
+	(gst_id3demux_bin_base_init), (gst_id3demux_bin_class_init),
+	(gst_id3demux_bin_init), (gst_id3demux_bin_remove_pad),
+	(found_type), (gst_id3demux_bin_change_state):
+	* ext/mad/gstid3tag.c: (gst_id3_tag_add_src_pad),
+	(gst_id3_tag_init), (gst_id3_tag_handle_event),
+	(gst_id3_tag_src_link), (gst_id3_tag_chain),
+	(gst_id3_tag_change_state), (plugin_init):
+	* ext/mad/gstmad.h:
+	  Add id3demuxbin (which is a simple bin consisting of id3demux
+	  and typefind), take over rank from id3demux, remove typefind
+	  code from id3demux. Makes all broken mp3s that I know of work,
+	  and thereby fixes #152688.
+
+2005-01-27  Edward Hervey  <bilboed@bilboed.com>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mad/gstmad.c: (gst_mad_src_event):
+	* gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_event):
+	  Allow seeks on audio pad, make mad forward those (#164826).
+	* gst/audioscale/gstaudioscale.c: (gst_audioscale_chain):
+	  Set duration (#165335).
+
+2005-01-27  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_init),
+	(gst_asf_demux_commit_taglist), (gst_asf_demux_process_comment),
+	(gst_asf_demux_process_ext_content_desc),
+	(gst_asf_demux_change_state), (gst_asf_demux_add_audio_stream),
+	(gst_asf_demux_add_video_stream), (gst_asf_demux_setup_pad):
+	* gst/asfdemux/gstasfdemux.h:
+	  Improve metadata display, e.g. if the metadata comes before the
+	  streams are loaded (which is perfectly valid).
+
+2005-01-27  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* tools/gst-launch-ext-m.m:
+	  Fix AVI/ASF pipelines (#165340).
+
+2005-01-26  Amaury Jacquot  <sxpert@esitcom.org>
+	* ext/cairo/gsttextoverlay.c: include  string.h and strings.h to fix
+	build failure on amd64
+
+2005-01-26  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/mad/gstid3tag.c: (mad_id3_parse_latin1_string),
+	(mad_id3_parse_comment_frame), (gst_mad_id3_to_tag_list):
+	  Check environment variables GST_ID3V2_TAG_ENCODING,
+	  GST_ID3_TAG_ENCODING and GST_TAG_ENCODING for a colon-separated
+	  list of character encodings to force interpretation of non-unicode
+	  strings stored in an ID3v2 tag to a particular encoding. If none
+	  is specified, try to use current locale's encoding, then fall back
+	  to ISO-8859-1 (which will always succeed). (Resolves #149274)
+	* gst/tags/gstid3tag.c: (gst_tag_from_id3_tag),
+	(gst_tag_extract_id3v1_string), (gst_tag_list_new_from_id3v1):
+	  Check environment variables GST_ID3V1_TAG_ENCODING,
+	  GST_ID3_TAG_ENCODING and GST_TAG_ENCODING for a colon-separated
+	  list of character encodings to use in case a string encountered
+	  in an ID3v1 tag is not valid UTF-8 already. If no encoding is
+	  specified, try to use the current locale's encoding, then fall
+	  back to ISO-8859-1 (which will always succeed).
+
+2005-01-25  Benjamin Otte  <otte@gnome.org>
+
+	* ext/mad/gstmad.c: (gst_mad_check_caps_reset), (gst_mad_chain):
+	  - on half framerate, compute the rate in advance so the comparisons
+	    don't compare wrong values
+	  - don't use mad_synth/frame_mute anymore, this mirrors mad_decoder
+	    behaviour
+	  - don't use mad_header_decode anymore, mad_frame_decode does that
+	    automatically
+	  - when getting rid of consumed bytes, reset the stream's skiplen
+	  (fixes #163867)
+
+2005-01-26  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_class_init)
+	  Use 1/2 a second for default max_discont, as PES streams from DVB
+	  seem to have larger spacings in the SCR. 
+	  Fix a typo.
+
+2005-01-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (group_commit):
+	  Notify delayed stream-info availability.
+
+2005-01-26  Jan Schmidt  <thaytan@mad.scientist.com>
+	* ext/a52dec/gsta52dec.c: (gst_a52dec_push),
+	(gst_a52dec_handle_event), (gst_a52dec_chain):
+	Add some debug output. Check that a discont has a valid
+	time associated.
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event),
+	(gst_alsa_sink_loop):
+	Ignore TAG events. A little extra debug for broken timestamps.
+	* ext/dvdnav/dvdnavsrc.c: (dvdnavsrc_init), (dvdnavsrc_loop),
+	(dvdnavsrc_change_state):
+	Ensure we send a discont to engage the link before we send any
+	other events.
+	* ext/dvdread/dvdreadsrc.c: (dvdreadsrc_init),
+	(dvdreadsrc_finalize), (_close), (_open), (_seek_title),
+	(_seek_chapter), (seek_sector), (dvdreadsrc_get),
+	(dvdreadsrc_uri_get_uri), (dvdreadsrc_uri_set_uri):
+	Handle URI of the form dvd://title[,chapter[,angle]]. Currently only
+	dvd://title works in totem because typefinding sends a seek that ends
+	up going back to chapter 1 regardless.
+	* ext/mpeg2dec/gstmpeg2dec.c:
+	* ext/mpeg2dec/gstmpeg2dec.h:
+	Output correct timestamps and handle disconts.
+	* ext/ogg/gstoggdemux.c: (get_relative):
+	Small guard against a null dereference.
+	* ext/pango/gsttextoverlay.c: (gst_textoverlay_finalize),
+	(gst_textoverlay_set_property):
+	Free memory when done. Don't call gst_event_filler_get_duration on
+	EOS events. Use GST_LOG and GST_WARNING instead of g_message and
+	g_warning.
+	* ext/smoothwave/gstsmoothwave.c: (gst_smoothwave_init),
+	(draw_line), (gst_smoothwave_dispose), (gst_sw_sinklink),
+	(gst_sw_srclink), (gst_smoothwave_chain):
+	Draw solid lines, prettier colours.
+	* gst/mpeg2sub/gstmpeg2subt.c: (gst_mpeg2subt_init):
+	Add a default palette that'll work for some movies.
+	* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_init),
+	(gst_dvd_demux_handle_dvd_event), (gst_dvd_demux_send_discont),
+	(gst_dvd_demux_send_subbuffer), (gst_dvd_demux_reset):
+	* gst/mpegstream/gstdvddemux.h:
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_send_discont),
+	(gst_mpeg_demux_parse_syshead), (gst_mpeg_demux_parse_pes):
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_init),
+	(gst_mpeg_parse_handle_discont), (gst_mpeg_parse_parse_packhead):
+	* gst/mpegstream/gstmpegparse.h:
+	Use PTM/NAV events when for timestamp adjustment when connected to 
+	dvdnavsrc. Don't use many discont events where one suffices.
+	* gst/playback/gstplaybasebin.c: (group_destroy),
+	(gen_preroll_element), (gst_play_base_bin_add_element):
+	* gst/playback/gstplaybasebin.h:
+	Make sure we remove subtitles from the same bin we put them in.
+	* gst/subparse/gstsubparse.c: (convert_encoding), (parse_subrip),
+	(gst_subparse_buffer_format_autodetect),
+	(gst_subparse_change_state):
+	Fix some memleaks and invalid accesses.
+	* gst/typefind/gsttypefindfunctions.c: (ogganx_type_find),
+	(oggskel_type_find), (cmml_type_find), (plugin_init):
+	Some typefind functions for Annodex v3.0 files
+	* gst/wavparse/gstwavparse.h:
+	GstRiffReadClass is the correct parent class.
+
+2005-01-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_video_caps_with_data):
+	  Add extradata to huffyuv (fixes #165013).
+	* gst-libs/gst/riff/riff-read.c:
+	(gst_riff_read_strf_vids_with_data):
+	  Fix extradata extraction if it is in the chunk size.
+
+2005-01-25  Edward Hervey  <bilboed@bilboed.com>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/effectv/gstquark.c: (gst_quarktv_class_init),
+	(gst_quarktv_change_state), (gst_quarktv_dispose):
+	  Memory free'ing location fix (#164708).
+
+2005-01-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (group_commit),
+	(gen_preroll_element), (probe_triggered), (gen_source_element),
+	(setup_source), (gst_play_base_bin_change_state),
+	(gst_play_base_bin_add_element):
+	  Don't block for streams.
+	* gst/playback/gststreaminfo.c: (stream_info_change_state),
+	(gst_stream_info_set_mute):
+	  Use gst_pad_set_active_recursive.
+
+2005-01-25  Andy Wingo  <wingo@pobox.com>
+
+	* sys/v4l/gstv4lelement.c (gst_v4l_iface_supported): Fix compile
+	for #ifndef HAVE_XVIDEO.
+
+2005-01-24  Jeffrey C. Ollie
+
+	reviewed by: Maciej Katafiasz  <mathrick@freedesktop.org>
+
+	* ext/gsm/gstgsmdec.c: (gst_gsmdec_init), (gst_gsmdec_chain):
+	* ext/gsm/gstgsmdec.h:
+	* ext/gsm/gstgsmenc.c: (gst_gsmenc_init), (gst_gsmenc_chain):
+	* ext/gsm/gstgsmenc.h:
+	Fix rate to 8kHz as per spec, removes obscure errors when no rate
+	was given by property. Add proper buffer timestamps and offsets.
+
+2005-01-24  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_audio_caps_with_data):
+	  Audio can be <8000Hz.
+
+2005-01-22  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_change_state):
+	  Explicit state change to workaround refcount bugs.
+
+2005-01-22  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavimux.c: (gst_avimux_write_tag),
+	(gst_avimux_riff_get_avi_header):
+	  Fix...
+
+2005-01-19  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_peek_element_data),
+	(gst_riff_read_element_data):
+	* gst-libs/gst/riff/riff-read.h:
+	  Add _peek version (req'ed in CDXA).
+	* gst/cdxaparse/gstcdxaparse.c: (gst_cdxaparse_init),
+	(gst_cdxaparse_loop):
+	  Fix parsing in playbin.
+	* gst/playback/gstdecodebin.c: (close_pad_link):
+	  Ignore current_ pads, they cause major annoyance.
+
+2005-01-19  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_loop):
+	  Safety guard.
+
+2005-01-19  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavimux.c: (gst_avimux_write_tag):
+	  Fix padding...
+
+2005-01-19  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/ebml-read.c: (gst_ebml_read_buffer):
+	  Allow for 0-sized buffers. Fixes length query problems in
+	  starwars.mkv from the testsuite.
+
+2005-01-19  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* gst/videobox/gstvideobox.c: (gst_video_box_copy_plane_i420),
+	(gst_video_box_i420), (gst_video_box_chain):
+	  Fix row strides for I420 (fixes #163159)
+	  
+2005-01-19  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_parse_packhead):
+	  MPEG2 has a useful rate property, so we can actually use that.
+	  For MPEG-1, continue using the bytes/time properties.
+
+2005-01-19  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_video_caps_with_data),
+	(gst_riff_create_video_template_caps):
+	  Add intel-h263.
+
+2005-01-19  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mad/gstmad.c: (gst_mad_check_caps_reset), (gst_mad_chain):
+	  Fail if caps negotiation fails. Should fix #162184, and should
+	  definately be in there regardless of it fixing the actual bug.
+	* gst/avi/gstavimux.c: (gst_avimux_get_type), (gst_avimux_init),
+	(gst_avimux_write_tag), (gst_avimux_riff_get_avi_header),
+	(gst_avimux_riff_get_avix_header),
+	(gst_avimux_riff_get_video_header),
+	(gst_avimux_riff_get_audio_header), (gst_avimux_write_index),
+	(gst_avimux_start_file), (gst_avimux_handle_event),
+	(gst_avimux_change_state):
+	* gst/avi/gstavimux.h:
+	  Refactor structure writing to use GST_WRITE_UINT macros, add
+	  metadata writing support.
+
+2005-01-18  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gststreaminfo.c: (gst_stream_info_dispose):
+	  Elements may already be destroyed when this function is called.
+
+2005-01-18  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_change_state),
+	(gst_qtdemux_loop_header), (gst_qtdemux_handle_esds):
+	  More memory leak fixes (#149162).
+
+2005-01-18  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_change_state),
+	(gst_qtdemux_add_stream):
+	  Fix two memleaks.
+
+2005-01-18  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/faad/gstfaad.c: (gst_faad_srcgetcaps):
+	  Argh...
+
+2005-01-17  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/faad/gstfaad.c: (gst_faad_srcgetcaps):
+	  Fix off-by-one bug. Fixes warnings during playback of sincity.mp4
+	  when fixating to six channels in Totem.
+
+2005-01-17  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/dvdread/dvdreadsrc.c: (get_next_cell_for):
+	  Fix compile warnings on Solaris 10 buildbot
+
+2005-01-17  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/dvdread/dvdreadsrc.c: (_read):
+	  Don't read beyond the last cell in a chapter (fixes 
+	  invalid memory access)
+
+2005-01-17  Tim-Philipp Müller  <tim at centricular dot net>
+
+	* ext/dvdread/stream_labels.c:
+	(dvdreadsrc_get_audio_stream_labels):
+	  Use NULL for an empty GList instead of g_list_alloc(); fix 
+	  memory leaks; s/LCPM/LPCM/; use g_strdup_printf() instead 
+	  of GString (easier to bulk free later)
+
+2005-01-17  Gergely Nagy  <algernon@bonehunter.rulez.org>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c:
+	(gst_ffmpeg_pixfmt_to_caps):
+	  Fix BGRA32 caps (#164209).
+
+2005-01-17  Gergely Nagy  <algernon@bonehunter.rulez.org>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c:
+	(gst_ffmpeg_caps_to_pixfmt):
+	  alpha_mask can be RGBA/ABGR. Fixes #164265.
+
+2005-01-17  Francis Labonte  <francis_labonte@hotmail.com>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mpeg2dec/gstmpeg2dec.c: (crop_buffer),
+	(gst_mpeg2dec_alloc_buffer):
+	* ext/mpeg2dec/gstmpeg2dec.h:
+	  Crop if decoding size is not the actual image size (#163676).
+
+2005-01-17  Steve Baker  <steve@stevebaker.org>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/typefind/gsttypefindfunctions.c: (aiff_type_find),
+	(svx_type_find), (sds_type_find), (ircam_type_find), (plugin_init):
+	  Add libsndfile typefind functions (#163309).
+
+2005-01-17  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* tools/gst-launch-ext-m.m:
+	  Add .aac, fix .m1v/.m2v (#163891).
+
+2005-01-17  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsaclock.c: (gst_alsa_clock_wait):
+	  Sanity check, don't wait endlessly since the clock might not
+	  actually run at this point (which is a deadlock). Fixes #164069.
+
+2005-01-16  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (probe_triggered):
+	  Of course, only pause if group is done...
+
+2005-01-16  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (probe_triggered):
+	  Thread safety.
+
+2005-01-16  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/swfdec/gstswfdec.c: (gst_swfdec_change_state):
+	  Don't return state change success when the parent
+	  failed.
+
+2005-01-16  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavimux.c: (gst_avimux_handle_event):
+	  Free events (fix memleak in #162905).
+
+2005-01-15  Gergely Nagy  <algernon@bonehunter.rulez.org>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c:
+	(gst_ffmpeg_caps_to_pixfmt):
+	  Fix for depth = 15. Fixes #161675.
+
+2005-01-14  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_getcaps):
+	  Set FPS correctly, even for webcams and the like.
+	* sys/v4l/v4l_calls.c: (gst_v4l_set_chan_norm):
+	  Don error on setting while capturing.
+
+2005-01-14  Stephane LOEUILLET  <stephane.loeuillet@tiscali.fr>
+
+	* ext/dv/gstdvdec.c:
+	* gst/subparse/gstsubparse.c: (parse_mdvdsub):
+	* gst/y4m/gsty4mencode.c: (gst_y4mencode_sinkconnect):
+	  I'm a bad boy. using /1001. to force C to do float division
+	  and not integer division (as it did in my last commit)
+	  Thanks to David I. Lehn for pointing this mistake.
+
+2005-01-14  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l/gstv4lelement.c: (gst_v4l_iface_supported):
+	  Revert Johan´s 1.35->1.36 since it breaks compat.
+
+2005-01-14  Stephane LOEUILLET  <stephane.loeuillet@tiscali.fr>
+
+	* ext/dv/gstdvdec.c:
+	* ext/libfame/gstlibfame.c:
+	* gst/subparse/gstsubparse.c: (parse_mdvdsub):
+	* gst/y4m/gsty4mencode.c: (gst_y4mencode_sinkconnect):
+          replace framerate aproximations by their real value
+          (24000/1001, 30000/1001, 60000/1001)
+          Finish fixing bug #164049
+
+2005-01-13  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/ogg/gstoggmux.c:
+	  eos/bos debugging
+	* gst/tcp/gstmultifdsink.c:
+	* gst/tcp/gstmultifdsink.h:
+	* gst/tcp/gsttcp.c:
+	* gst/tcp/gsttcp.h:
+	* gst/tcp/gsttcpclientsink.c:
+	* gst/tcp/gsttcpclientsrc.c:
+	* gst/tcp/gsttcpserversink.c:
+	* gst/tcp/gsttcpserversrc.c:
+	  improve reusability of elements after state changes and errors
+	  make multifdsink throw away streamheaders when receiving new ones
+
+2005-01-13  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_rates_probe):
+	  Fix for if items are already in list...
+
+2005-01-12  Benjamin Otte  <otte@gnome.org>
+
+	* gst/adder/gstadder.c: (gst_adder_loop):
+	  fix adder a bit so it doesn't screw up with events as much anymore
+
+2005-01-12  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/gdk_pixbuf/pixbufscale.c: (gst_pixbufscale_link),
+	(pixbufscale_scale), (gst_pixbufscale_chain):
+	* ext/gdk_pixbuf/pixbufscale.h:
+	  Incorporate changes from Tim-Philipp Mueller <t.i.m@orange.net>
+	  to ensure rowstrides are calculated the same way as 
+	  ffmpegcolorspace
+	  Use gst_buffer_stamp instead of copying TIMESTAMP manually, so
+	  that we pick up duration and offset also.
+
+2005-01-11  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavimux.c: (gst_avimux_class_init),
+	(gst_avimux_pad_unlink), (gst_avimux_release_pad):
+	  Reusability fixes.
+
+2005-01-11  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_update),
+	(gst_alsa_mixer_get_volume), (gst_alsa_mixer_set_volume),
+	(gst_alsa_mixer_set_mute), (gst_alsa_mixer_set_record),
+	(gst_alsa_mixer_set_option), (gst_alsa_mixer_get_option):
+	  Update flags when requested.
+
+2005-01-11  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_rates_probe):
+	  Fix dmix.
+
+2005-01-11  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init),
+	(gst_play_base_bin_init), (gst_play_base_bin_dispose),
+	(probe_triggered), (new_decoded_pad), (gen_source_element),
+	(gst_play_base_bin_set_property), (gst_play_base_bin_get_property):
+	* gst/playback/gstplaybasebin.h:
+	* gst/playback/gstplaybin.c: (gst_play_bin_class_init),
+	(gst_play_bin_init), (group_switch), (remove_sinks), (setup_sinks),
+	(gst_play_bin_change_state):
+	  Implement group-switch signal for use in apps to clear metadata
+	  cache, clean up subtitle, add suburi property instead of # hack,
+	  some error-out fixes.
+
+2005-01-11  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_chain):
+	  Debug.
+	* sys/v4l/v4lsrc_calls.c: (gst_v4lsrc_grab_frame):
+	  If we got a state change in the _get handler, don't return success.
+
+2005-01-10  Stephane LOEUILLET  <stephane.loeuillet@tiscali.fr>
+
+	* ext/jpeg/gstjpegdec.c: (gst_jpegdec_my_output_message),
+	(gst_jpegdec_my_emit_message), (gst_jpegdec_init):
+	  Make jpegdec quiet on MJPEG decoding
+	* gst/asfdemux/README:
+	  Fix mimetypes for MJPEG and H263
+
+2005-01-10  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/theora/theoradec.c: (theora_dec_chain):
+	  Fix broken code generation by gcc by swapping arguments.
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_src_query):
+	  Fix \n in debug.
+
+2005-01-10  Stephane LOEUILLET  <stephane.loeuillet@tiscali.fr>
+
+	* TODO:
+	  delete this file, it is by far outdated
+	* ext/alsa/gstalsa.1: remove
+	* ext/alsa/gstalsa.c: (add_rates), (add_channels), (gst_alsa_caps),
+	(gst_alsa_check_sample_rates), (gst_alsa_rates_probe),
+	(gst_alsa_get_caps):
+	  Add HW probing for supported sample rates. Fixes #161704
+
+2005-01-10  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/audioscale/gstaudioscale.c: (gst_audioscale_chain):
+	  Don't crash, biatch! :).
+
+2005-01-10  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/musepack/gstmusepackreader.cpp:
+	* gst/apetag/apedemux.c: (gst_ape_demux_stream_data):
+	  Some work on tags - still doesn't work in playbin...
+	* gst/audioscale/gstaudioscale.c: (gst_audioscale_chain):
+	  Handle events...
+
+2005-01-10  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/qtdemux/qtdemux.c: (qtdemux_parse_tree):
+	  Also shove tags on kid pads.
+
+2005-01-10  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_read_use_event):
+	  Don't bail on unknown events.
+	* gst/audioscale/gstaudioscale.c: (gst_audioscale_chain):
+	  Don't crash on events before negotiation.
+	* gst/avi/gstavidemux.c: (gst_avi_demux_add_stream):
+	  Send tags on pads, too.
+	* gst/playback/gststreamselector.c:
+	(gst_stream_selector_request_new_pad):
+	  Forward events on first pad if no input was selected yet.
+
+2005-01-10  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (setup_substreams):
+	  Don't disable streamtype if the stream doesn't exist, since
+	  then playing a video after audio will disable both and nothing
+	  will happen. Fixes the testsuite.
+
+2005-01-10  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l/gstv4lxoverlay.c: (gst_v4l_xoverlay_interface_init),
+	(gst_v4l_xoverlay_set_xwindow_id):
+	* sys/v4l2/gstv4l2xoverlay.c: (gst_v4l2_xoverlay_interface_init),
+	(gst_v4l2_xoverlay_set_xwindow_id):
+	  Add debug categories, fix overlay disabling.
+
+2005-01-10  Stephane LOEUILLET  <stephane.loeuillet@tiscali.fr>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_class_init), (gst_alsa_get_caps):
+	* ext/alsa/gstalsa.h:
+	  Add HW probing for period_count/size and buffer_size MIX/MAX
+	  Adjust default/user defined value if out of bounds
+	  Should fix bug #162024
+
+2005-01-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_handle_sink_event):
+	  Fix warning (#161191).
+
+2005-01-09  Stephane LOEUILLET  <stephane.loeuillet@tiscali.fr>
+
+	* ext/dvdread/stream_labels.c:
+	(dvdreadsrc_get_audio_stream_labels):
+	  Fix warning (init the good variable in switch default)
+
+2005-01-09  Koop Mast  <kwm@rainbow-runner.nl>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/tta/gstttaparse.c: (gst_tta_src_event):
+	  Fix gcc-2.95 compile (#163485).
+
+2005-01-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* ext/flac/gstflacenc.c: (gst_flacenc_init),
+	(gst_flacenc_seek_callback), (gst_flacenc_write_callback),
+	(gst_flacenc_tell_callback), (gst_flacenc_chain),
+	(gst_flacenc_change_state):
+	* ext/flac/gstflacenc.h:
+	  Update for API change in flac-1.1.1. Update requirement in
+	  configure.ac. Fixes #162974.
+
+2005-01-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (group_destroy):
+	  Remove hack to get rid of assert and get rid of unlinked
+	  signals properly.
+
+2005-01-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (setup_source):
+	  Set source to NULL so that resources are free'ed. Fixes issues
+	  with playback of CDDA and similar device-accessing things.
+
+2005-01-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* testsuite/embed/Makefile.am:
+	  test->noinst, fix make test in buildbot.
+
+2005-01-09  Stephane LOEUILLET  <stephane.loeuillet@tiscali.fr>
+
+	* ext/dvdread/stream_labels.c: new file
+	* ext/dvdread/stream_labels.h: new file
+	* ext/dvdread/Makefile.am:
+	* ext/dvdread/dvdreadsrc.c: (_seek_title):
+	  Extract audio stream label from DVD IFO files.
+	  It only dump them on the console for now, still have to
+	  make playbin aware of them.
+
+2005-01-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (setup_source):
+	  Fix hanging subs.
+
+2005-01-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_init),
+	(gen_preroll_element), (remove_groups), (setup_subtitle),
+	(gen_source_element), (setup_source):
+	* gst/playback/gstplaybasebin.h:
+	  Multiple .sub files is just a stupid idea... Fix some threading
+	  mistakes. Interestingly, external .sub files cause playbin to
+	  hang, I don't know why... Parsing fixes contributed by François
+	  Kooman <fkooman@tuxed.net>.
+
+2005-01-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* testsuite/embed/Makefile.am:
+	  Fix buildbot.
+
+2005-01-09  Gergely Nagy  <algernon@bonehunter.rulez.org>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/libpng/gstpngenc.c: (gst_pngenc_class_init),
+	(gst_pngenc_init), (gst_pngenc_chain), (gst_pngenc_get_property),
+	(gst_pngenc_set_property):
+	* ext/libpng/gstpngenc.h:
+	  Add compression level property (#163323).
+
+2005-01-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* examples/capsfilter/capsfilter1.c: (main):
+	* examples/seeking/spider_seek.c: (make_spider_pipeline):
+	* ext/dvdread/Makefile.am:
+	* ext/dvdread/demo-play:
+	* ext/dvdread/demo-play.c:
+	* gconf/gstreamer.schemas.in:
+	* gst-libs/gst/gconf/gconf.c:
+	* sys/v4l/TODO:
+	* testsuite/Makefile.am:
+	* testsuite/embed/Makefile.am:
+	* testsuite/embed/embed.c: (cb_expose), (main):
+	  Remove all references to xvideosink, fix examples (#140845).
+	* gst/playback/gstplaybasebin.c: (group_destroy):
+	  Apparently, disposal does not unlink - so do explicitely.
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event):
+	  Add debug.
+
+2005-01-09  Maciej Katafiasz <mathrick@freedesktop.org>
+
+	* README: fix PKG_CONFIG_PATH instructions, what was there
+	previously was breaking default search path, not nice. 
+	Fixes #163358
+
+2005-01-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/audioscale/gstaudioscale.c: (gst_audioscale_init),
+	(gst_audioscale_chain):
+	  %#^@^#@^@#^#@^#@^@#^@#^@#^@#^#@^#@^#@^@#^#@ fix seeking
+	  when resampling - how the ^@$^!@^! is this possible?!?
+
+2005-01-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_change_state):
+	  Reset variables on READY.
+	* gst/matroska/matroska-mux.c: (gst_matroska_mux_request_new_pad),
+	(gst_matroska_mux_loop):
+	  Require data before writing header.
+
+2005-01-09  Francis Labonte  <francis_labonte@hotmail.com>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mad/gstmad.c: (gst_mad_chain):
+	  Don't call mad_stream_sync() directly after recovering sync.
+	  Fixes #151661.
+
+2005-01-09  Martin Eikermann  <meiker@upb.de>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/snapshot/gstsnapshot.c: (gst_snapshot_class_init),
+	(snapshot_handler), (gst_snapshot_sinkconnect),
+	(gst_snapshot_chain):
+	  Allocate resources when required, fix recursive signal emission
+	  and fix caps. Fixes #161667.
+
+2005-01-09  Gergely Nagy  <algernon@bonehunter.rulez.org>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/libpng/gstpngdec.c: (gst_pngdec_src_getcaps),
+	(gst_pngdec_chain):
+	  Handle only 8-bppc (bits-per-pixel-component) images, better
+	  error handling and correct strides. Fixes #163177.
+	* ext/libpng/gstpngenc.c: (gst_pngenc_sinklink),
+	(gst_pngenc_chain):
+	  Better error handling. Fixes #163348.
+
+2005-01-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/dvdnav/dvdnavsrc.c: (dvdnavsrc_get_type),
+	(dvdnavsrc_uri_get_type), (dvdnavsrc_uri_get_protocols),
+	(dvdnavsrc_uri_get_uri), (dvdnavsrc_uri_set_uri),
+	(dvdnavsrc_uri_handler_init):
+	  Add DVD-nav URI (dvdnav://) for Totem testing purposes.
+	* gst/playback/gstplaybasebin.c: (gen_source_element):
+	  Add MMS to streaming URIs.
+
+2005-01-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_navigation_send_event):
+	* sys/xvimage/xvimagesink.c:
+	(gst_xvimagesink_navigation_send_event):
+	  Check for pad availability before sending event.
+
+2005-01-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-plugins.spec.in:
+	  Add subparse.
+
+2005-01-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	  Since we use functions from CVS, up requirement.
+
+2005-01-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/Makefile.am:
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init),
+	(group_destroy), (group_commit), (group_is_muted),
+	(gen_preroll_element), (add_stream), (unknown_type),
+	(probe_triggered), (preroll_unlinked), (mute_stream),
+	(silence_stream), (new_decoded_pad), (setup_substreams),
+	(setup_source), (get_active_source), (mute_group_type),
+	(muted_group_change_state), (set_active_source),
+	(gst_play_base_bin_set_property), (gst_play_base_bin_get_property),
+	(play_base_eos), (gst_play_base_bin_change_state):
+	* gst/playback/gstplaybasebin.h:
+	* gst/playback/gstplaybin.c: (add_sink), (setup_sinks):
+	* gst/playback/gststreaminfo.c: (gst_stream_info_class_init),
+	(gst_stream_info_dispose), (stream_info_mute_pad),
+	(stream_info_change_state), (gst_stream_info_set_mute):
+	* gst/playback/gststreamselector.c: (gst_stream_selector_get_type),
+	(gst_stream_selector_base_init), (gst_stream_selector_class_init),
+	(gst_stream_selector_init), (gst_stream_selector_dispose),
+	(gst_stream_selector_get_linked_pad),
+	(gst_stream_selector_get_caps), (gst_stream_selector_link),
+	(gst_stream_selector_get_linked_pads),
+	(gst_stream_selector_request_new_pad), (gst_stream_selector_chain):
+	* gst/playback/gststreamselector.h:
+	  Adding stream selection support plus required properties for
+	  applications to use this. Fully fixes #100931.
+
+2005-01-08  Benjamin Otte  <otte@gnome.org>
+
+	* gst/games/gstpuzzle.c: (nav_event_handler):
+	  - handle nav events differently: forward every event no matter if it
+	    was handled or not.
+	  - translate events
+	  You can now cheat by using navigationtest ! puzzle and moving the
+	  mouse close to the edge of a tile. ;)
+
+2005-01-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* ext/ogg/gstoggdemux.c: (gst_ogg_pad_new):
+	* ext/ogg/gstogmparse.c: (gst_ogm_text_parse_get_type),
+	(gst_ogm_text_parse_base_init), (gst_ogm_text_parse_init),
+	(gst_ogm_parse_get_sink_querytypes), (gst_ogm_parse_sink_convert),
+	(gst_ogm_parse_sink_query), (gst_ogm_parse_chain),
+	(gst_ogm_parse_plugin_init):
+	* ext/pango/gsttextoverlay.c: (gst_textoverlay_linkedpads),
+	(gst_textoverlay_link), (gst_textoverlay_getcaps),
+	(gst_textoverlay_event), (gst_textoverlay_video_chain),
+	(gst_textoverlay_loop), (gst_textoverlay_init), (plugin_init):
+	* ext/pango/gsttextoverlay.h:
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream),
+	(gst_matroska_demux_handle_seek_event),
+	(gst_matroska_demux_sync_streams),
+	(gst_matroska_demux_parse_blockgroup),
+	(gst_matroska_demux_subtitle_caps),
+	(gst_matroska_demux_plugin_init):
+	* gst/matroska/matroska-ids.h:
+	* gst/playback/gstdecodebin.c: (close_pad_link):
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_init),
+	(gen_preroll_element), (remove_groups), (add_stream),
+	(new_decoded_pad), (setup_subtitles), (gen_source_element),
+	(setup_source):
+	* gst/playback/gstplaybasebin.h:
+	* gst/playback/gstplaybin.c: (gen_text_element), (setup_sinks):
+	* gst/subparse/Makefile.am:
+	* gst/subparse/gstsubparse.c: (gst_subparse_get_type),
+	(gst_subparse_base_init), (gst_subparse_class_init),
+	(gst_subparse_init), (gst_subparse_formats),
+	(gst_subparse_eventmask), (gst_subparse_event),
+	(gst_subparse_handle_event), (convert_encoding), (get_next_line),
+	(parse_mdvdsub), (parse_mdvdsub_init), (parse_subrip),
+	(parse_subrip_deinit), (parse_subrip_init), (parse_mpsub),
+	(parse_mpsub_deinit), (parse_mpsub_init),
+	(gst_subparse_buffer_format_autodetect),
+	(gst_subparse_format_autodetect), (gst_subparse_loop),
+	(gst_subparse_change_state), (gst_subparse_type_find),
+	(plugin_init):
+	* gst/subparse/gstsubparse.h:
+	* gst/typefind/gsttypefindfunctions.c: (ogmtext_type_find),
+	(plugin_init):
+	  Add subtitle support, .sub parser (supports SRT and MPsub),
+	  OGM text support, Matroska UTF-8 text support, deadlock fixes
+	  all over the place, subtitle awareness in decodebin/playbin
+	  and some fixes to textoverlay to handle subtitles in a stream
+	  correctly. Fixes #100931.
+
+2005-01-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_src_query):
+	  Check for pad availability before doing a query on it.
+
+2005-01-08  Stephane LOEUILLET  <stephane.loeuillet@tiscali.fr>
+
+	* ext/dv/gstdvdec.c:
+	  really fix bpp24/32 dvdec caps (classic rgba indeed)
+	* gst/asfdemux/gstasfdemux.c:
+	(gst_asf_demux_process_ext_content_desc):
+	  don't send text tags if they are empty (bis repetita)
+
+2005-01-08  Stephane LOEUILLET  <stephane.loeuillet@tiscali.fr>
+
+	* ext/dv/gstdvdec.c:
+	 remove unneeded comment from dvdec
+	  (related to DV 4CC codes in AVI files)
+	  moved them in gstreamer/docs/random/mimetypes
+	* gst/asfdemux/gstasfdemux.c:
+	(gst_asf_demux_process_ext_content_desc):
+	 don't send text tags if they are empty
+	 fix mem leak on error path
+	* gst/ffmpegcolorspace/avcodec.h:
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c:
+	(gst_ffmpeg_pixfmt_to_caps), (gst_ffmpeg_caps_to_pixfmt),
+	(gst_ffmpegcsp_avpicture_fill):
+	* gst/ffmpegcolorspace/imgconvert.c: (img_get_alpha_info):
+	* gst/ffmpegcolorspace/imgconvert_template.h:
+	 adds BGR32 and BGRA32 to ffmpegcolorspace
+	  (still bad colors, fixing it on next commit)
+	  helps with dvdec outputing BGR32
+
+2005-01-08  Stephane LOEUILLET  <stephane.loeuillet@tiscali.fr>
+
+	* ext/dv/gstdvdec.c:
+	 Fix audio caps i just broke (missing ',')
+	* gst/matroska/matroska-mux.c: (gst_matroska_mux_get_type),
+	(gst_matroska_mux_reset):
+	 Fix typo + add FIXME about old "x-gst-metadata" crap
+
+2005-01-07  Stephane LOEUILLET  <stephane.loeuillet@tiscali.fr>
+
+	* ext/dv/demo-play.c: (main):
+	 xvideosink -> xvimagesink
+	* ext/dv/gstdvdec.c:
+	 change rgb 32/32 caps to 24/32 (no alpha)
+	 change nb of channels to be a list (2 or 4, not 2)
+	 change sample rate to be a list (32, 44.1, 48 kHz) not a range
+	* gst/asfdemux/gstasfdemux.c:
+	(gst_asf_demux_process_ext_content_desc):
+	 Add 'date/year' to extracted metadata list
+
+2005-01-07  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_fixate):
+	  The return value of fixate_to does not imply that the requested
+	  value was set, so don't assume.
+
+2005-01-07  Gergely Nagy  <algernon@bonehunter.rulez.org>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/libpng/gstpngdec.c:
+	* ext/libpng/gstpngenc.c: (gst_pngenc_base_init),
+	(gst_pngenc_sinklink), (gst_pngenc_init), (gst_pngenc_chain):
+	* ext/libpng/gstpngenc.h:
+	  Alpha support (encoder; #163161), mime fixage.
+
+2005-01-07  Sebastien Cote  <sc5@hermes.usherb.ca>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/faac/gstfaac.c: (gst_faac_outputformat_get_type),
+	(gst_faac_class_init), (gst_faac_init), (gst_faac_srcconnect),
+	(gst_faac_set_property), (gst_faac_get_property):
+	* ext/faac/gstfaac.h:
+	  Allow for ADTS output (#153434).
+
+2005-01-07  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l2/gstv4l2src.c: (gst_v4l2src_getcaps):
+	  Fix against template (#150576).
+
+2005-01-06  Benjamin Otte  <otte@gnome.org>
+
+	* gst/games/gstpuzzle.c: (draw_puzzle):
+	  don't draw a puzzle if either width or height of tiles would be 0.
+
+2005-01-06  Benjamin Otte  <otte@gnome.org>
+
+	* gst/games/gstpuzzle.c: (gst_puzzle_get_type),
+	(gst_puzzle_class_init), (gst_puzzle_finalize):
+	  no memleaks, please
+	(gst_puzzle_create), (gst_puzzle_init),
+	(gst_puzzle_set_property), (gst_puzzle_setup):
+	  change initialization code around so we don't reshuffle on resize
+	(draw_puzzle):
+	  fix another stupid typo
+
+2005-01-06  Benjamin Otte  <otte@gnome.org>
+
+	* gst/games/gstvideoimage.c: (copy_hline_YUY2):
+	  fix stupid typo that borked copying on YUY2
+
+2005-01-06  Benjamin Otte  <otte@gnome.org>
+
+	* gst/games/gstpuzzle.c: (draw_puzzle):
+	  fix edges when image sizes aren't multiples of tile sizes
+
+2005-01-06  Benjamin Otte  <otte@gnome.org>
+
+	* gst/games/gstpuzzle.c: (gst_puzzle_base_init):
+	  make RGB endianness work correctly
+	(gst_puzzle_show), (gst_puzzle_swap), (gst_puzzle_move):
+	  refactor and fix race with initial shuffling
+	(nav_event_handler):
+	  allow using the mouse to puzzle
+	(draw_puzzle):
+	  insist on tiles having width and height as multiples of 4 to get
+	  clean YUV image handling
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xvimage_new),
+	(gst_xvimagesink_handle_xevents), (gst_xvimagesink_buffer_alloc):
+	  s/DEBUG/LOG/ for common messages
+	(gst_xvimagesink_navigation_send_event):
+	  fix mouse event translation to not include screen PAR
+	* sys/ximage/ximagesink.c: (gst_ximagesink_navigation_send_event):
+	  fix mouse event translation to actually work
+
+2005-01-06  Stephane LOEUILLET  <stephane.loeuillet@tiscali.fr>
+
+	* gst/asfdemux/gstasfdemux.c:
+	(gst_asf_demux_process_ext_content_desc):
+	 Extract TrackNumber metadata + clean up code
+	* gst/games/gstvideoimage.c: (gst_video_image_draw_rectangle):
+	 Hope this is the good fix (var used unitialised)
+
+2005-01-06  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/faad/gstfaad.c: (gst_faad_chain):
+	  Only increment timestamp if it's valid. Fixes raw AAC streams.
+
+2005-01-06  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* configure.ac:
+	* gst/games/Makefile.am:
+	* gst/games/gstpuzzle.c:
+	  add a puzzle game with...
+	* gst/games/gstvideoimage.c:
+	* gst/games/gstvideoimage.h:
+	  ... full colorspace support (that includes YUV9 and RGB16)) stolen
+	  from videotestsrc and made into something that would be a nice
+	  library for a lot of other plugins.
+
+2005-01-06  Stephane LOEUILLET  <stephane.loeuillet@tiscali.fr>
+
+	* configure.ac:
+	 don't compile faad plugin if a RC of 2.0 is found
+	 Fixes #155346 (and FC1 buildbot)
+	* gst/asfdemux/gstasfdemux.c:
+	(gst_asf_demux_process_ext_content_desc):
+	 try to make Solaris compiler happier
+
+2005-01-06  Paul Jack  <pjack@sfaf.org>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/snapshot/gstsnapshot.c: (gst_snapshot_class_init):
+	  Fix segfault (#161667).
+
+2005-01-05  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_getcaps):
+	  Fix framerate reporting.
+
+2005-01-05  Stephane LOEUILLET  <stephane.loeuillet@tiscali.fr>
+
+	* gst-libs/gst/riff/riff-ids.h:
+	* gst/wavenc/riff.h:
+	 Add AMR (VBR and CBR) ids to riff.h audio codec list
+	* gst/asfdemux/gstasfdemux.c:
+	(gst_asf_demux_process_ext_content_desc),
+	(gst_asf_demux_process_object):
+	  Retrieve more tags from ASF files (Genre, AlbumTitle, Artist)
+
+2005-01-05  Martin Eikermann  <meiker@upb.de>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_class_init),
+	(gst_dvd_demux_handle_discont):
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_class_init),
+	(gst_mpeg_demux_handle_discont):
+	  Recreate pads on new-media (#160730).
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_new_pad):
+	  Send discont even if manager changes timestamps (#161929).
+
+2005-01-05  Sebastien Cote  <sc5@hermes.usherb.ca>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/resample/resample.c: (gst_resample_sinc_ft_s16):
+	  Fix invalid memory access (#159211).
+
+2005-01-05  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* examples/gstplay/player.c: (main):
+	  Don't iterate.
+	* examples/seeking/seek.c: (fixate), (make_playerbin_pipeline):
+	  Add visualizations.
+	* ext/a52dec/gsta52dec.c: (gst_a52dec_push),
+	(gst_a52dec_handle_frame):
+	  Set duration.
+	* ext/dvdnav/gst-dvd:
+	  Add audioconvert. Fixes #161325.
+	* ext/dvdread/dvdreadsrc.c: (dvdreadsrc_get):
+	  Explicitely case to gint64. Possible valgrind error.
+	* gst-libs/gst/play/play.c: (caps_set), (setup_size),
+	(gst_play_tick_callback), (gst_play_change_state),
+	(gst_play_dispose), (gst_play_init), (gst_play_class_init),
+	(gst_play_set_location), (gst_play_get_location),
+	(gst_play_seek_to_time), (gst_play_set_data_src),
+	(gst_play_set_video_sink), (gst_play_set_audio_sink),
+	(gst_play_set_visualization), (gst_play_connect_visualization),
+	(gst_play_get_framerate), (gst_play_get_all_by_interface),
+	(gst_play_new):
+	  Use playbin. Fixes #139749 and #147744.
+	* gst/apetag/apedemux.c: (gst_ape_demux_parse_tags):
+	  Add genre tag.
+	* gst/audioscale/gstaudioscale.c: (gst_audioscale_method_get_type),
+	(audioscale_get_type), (gst_audioscale_base_init),
+	(gst_audioscale_class_init), (gst_audioscale_expand_caps),
+	(gst_audioscale_getcaps), (gst_audioscale_fixate),
+	(gst_audioscale_link), (gst_audioscale_get_buffer),
+	(gst_audioscale_decrease_rate), (gst_audioscale_increase_rate),
+	(gst_audioscale_init), (gst_audioscale_dispose),
+	(gst_audioscale_chain), (gst_audioscale_set_property),
+	(gst_audioscale_get_property), (plugin_init):
+	  Indent properly.
+	* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_process_private):
+	  Fix LPCM.
+	* gst/qtdemux/qtdemux.c: (qtdemux_parse_udta),
+	(qtdemux_tag_add_str), (qtdemux_tag_add_num),
+	(qtdemux_tag_add_gnre), (qtdemux_video_caps):
+	  Add more metadata (fixes #162656).
+
+2005-01-05  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	  back to cvs
+
+=== release 0.8.7 ===
+
+2005-01-05  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	  releasing 0.8.7, "Hyperspace"
+
+2005-01-05  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	patch by: Tim-Philipp Müller  <t.i.m@zen.co.uk>
+
+	* gst/playback/gstplaybasebin.c:
+	 Fix for #162924 - free caps after use, not before
+
+2005-01-04  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	patch by: Ronald Bultje <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c:
+	* gst/wavparse/gstwavparse.c:
+	  Fix for #154773 - fixes playback of small .wav files
+
+2005-01-03  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	patch by: Ronald Bultje <rbultje@ronald.bitfreak.net>
+
+	* gst/audioscale/gstaudioscale.c:
+	  Fix for #162819 - make audioscale reusable
+	  Fixes playback of more than one file with playbin/totem
+
+2004-12-29  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/ffmpegcolorspace/avcodec.h:
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c:
+	* gst/ffmpegcolorspace/imgconvert.c:
+	  clean up the mess that made me cry and avoid needless duplication
+
+2004-12-29  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/ffmpegcolorspace/imgconvert.c:
+	  give some indication of why we're segfaulting
+
+2004-12-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	  Fix indentation, fix v4l2 plugin detection.
+	* ext/Makefile.am:
+	  Fix libmms location (Maciej, use diff -u!).
+	* ext/alsa/gstalsa.c: (gst_alsa_init):
+	  Initialize caps cache to NULL.
+	* gst/playback/gstplaybin.c: (gst_play_bin_change_state):
+	  Only change state on audiosink if it exists.
+
+2004-12-28  Maciej Katafiasz  <mathrick@mathrick.org>
+
+	* gst/matroska/matroska-demux.c:
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-demux.h:
+	Fix Vorbis streams failing to decode in some files, where cluster_time
+	isn't 0, because then it doesn't send codec_priv before actual data.
+	Remove time-based test and replace it with marker set on beginning of
+	new stream
+
+2004-12-28  David Schleef  <ds@schleef.org>
+
+	Merge patch from Ronald fixing problems with streaming
+	text.
+	* ext/cairo/gstcairo.c: (plugin_init):
+	* ext/cairo/gsttextoverlay.c: (gst_textoverlay_render_text),
+	(gst_text_overlay_blit_1), (gst_text_overlay_blit_sub2x2),
+	(gst_textoverlay_video_chain), (gst_textoverlay_loop),
+	(gst_textoverlay_font_init), (gst_textoverlay_init),
+	(gst_textoverlay_set_property):
+	* ext/cairo/gsttextoverlay.h:
+
+2004-12-27  David Schleef  <ds@schleef.org>
+
+	* ext/cairo/gsttextoverlay.c: (gst_textoverlay_render_text),
+	(gst_text_overlay_blit_1), (gst_text_overlay_blit_sub2x2),
+	(gst_textoverlay_video_chain), (gst_textoverlay_loop),
+	(gst_textoverlay_font_init), (gst_textoverlay_init),
+	(gst_textoverlay_set_property): Improvements to actually
+	render text as white on black outline on video, including
+	font selection and horizontal/vertical alignment.  (Ronald's
+	christmas present)
+	* ext/cairo/gsttextoverlay.h:
+
+2004-12-26  Stephane Loeuillet  <stephane.loeuillet@tiscali.fr>
+
+	* ext/ogg/gstogg.c:
+	* ext/ogg/gstogmparse.c:
+	  fix ogm[audio/video]parse plugin registration
+	  (riff won't load if bytestream is already loaded)
+
+2004-12-24  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/audioconvert/gstchannelmix.c:
+	  fix for GLIB < 2.4
+
+2004-12-24  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* Makefile.am:
+	* configure.ac:
+	  disable docs again until it actually passes make distcheck.
+
+2004-12-24  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/qtdemux/qtdemux.c: (qtdemux_type_get), (qtdemux_audio_caps):
+	* gst/typefind/gsttypefindfunctions.c: (q3gp_type_find),
+	(plugin_init):
+	  Add 3GP (variables name Q3GP because they can't start with a
+	  number). Add samr audio fourcc (used in .3gp files), decoder
+	  is work in progress. Also do a GST_WARNING instead of ERROR
+	  in case of unknown nodes, to decrease output.
+
+2004-12-24  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* Makefile.am:
+	  really fix dist
+
+2004-12-23  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	* ext/speex/gstspeexdec.h:
+	* ext/speex/gstspeexenc.h:
+	  Fixes #158382.  Make speex plugin compatible with both 1.0 and 1.1.
+	  Fix detection code in configure.ac
+
+2004-12-23  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/matroska-demux.c:
+	(gst_matroska_demux_parse_blockgroup):
+	  Save position, so that queries give proper return values. Don't
+	  know how this could ever have worked before...
+
+2004-12-23  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	  Put additional LAME check inside the conditional.  Fixes #152339
+
+2004-12-23  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_stream_index),
+	(gst_avi_demux_stream_scan):
+	  Add some more debug. Fix logic error when setting movi offset
+	  while reading index.
+
+2004-12-23  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_stream_index),
+	(gst_avi_demux_stream_scan), (gst_avi_demux_handle_seek),
+	(gst_avi_demux_process_next_entry):
+	  Add some debugging. Better detection of broken indexes and the
+	  accompanying index recovery. No infinite loops on state changes
+	  when we're still in our loopfunction.
+
+2004-12-22  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	  Fix up.
+
+2004-12-22  Archana Shah  <archana.shah@wipro.com>
+
+	Reviewed by:  Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+
+	* sys/sunaudio/gstsunmixer.c: (gst_sunaudiomixer_set_volume):
+	  Normalizing the value before setting
+	(gst_sunaudiomixer_get_volume):
+	  Normalizing the value after getting. Fixes bug# 161980
+
+2004-12-22  Christian Fredrik Kalager Schaller  <uraeus@gnome.org>
+
+	* Makefile.am: Make sure docs gets disted
+	* docs/Makefile.am: Make sure all needed files get disted
+	* gst-plugins.spec.in: latest updates
+
+2004-12-22  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_add_element):
+	Revert patch 1.38 as clock distribution over schedulers does
+	not work correcly in the core yet.
+
+2004-12-21  Stephane Loeuillet  <stephane.loeuillet@tiscali.fr>
+
+	* sys/oss/README: remove this file, which predates my birth
+	  (and which content is by far outdated)
+
+2004-12-20  Stefan Kost  <ensonic@users.sf.net>
+
+	* Makefile.am:
+	* configure.ac:
+	* docs/Makefile.am:
+	* docs/libs/Makefile.am:
+	* docs/libs/gst-plugins-libs-docs.sgml:
+	* docs/libs/gst-plugins-libs-sections.txt:
+	* docs/libs/tmpl/gstgconf.sgml:
+	* docs/upload.mak:
+	* docs/version.entities.in:
+	  Added boilerplate gtk-doc files for plugin-libs documentation.
+
+2004-12-19  Stephane Loeuillet  <stephane.loeuillet@tiscali.fr>
+
+	* gst/auparse/gstauparse.c: fix int and float audio caps
+
+2004-12-19  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l/gstv4lelement.c: (gst_v4l_iface_supported):
+	* sys/v4l2/gstv4l2element.c: (gst_v4l2_iface_supported):
+	  g_assert() can be a macro, don't use #ifdef inside it.
+
+2004-12-19  Edward Hervey  <bilboed@bilboed.com>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/videorate/gstvideorate.c: (gst_videorate_blank_data),
+	(gst_videorate_init), (gst_videorate_chain),
+	(gst_videorate_change_state):
+	  Event handling (fixes #159986).
+
+2004-12-19  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_video_caps_with_data):
+	  Add BLZ0 (Blizzard's version of DivX) fourcc.
+
+2004-12-18  David Schleef  <ds@schleef.org>
+
+	* gst/tta/gstttadec.c: (gst_tta_dec_link): And yet another
+	portability fix.
+
+2004-12-18  David Schleef  <ds@schleef.org>
+
+	* gst/tta/ttadec.h: Disable some header code that isn't used
+	and clearly isn't portable.
+
+2004-12-18  David Schleef  <ds@schleef.org>
+
+	* gst/ffmpegcolorspace/imgconvert.c: (get_pix_fmt_info),
+	(avcodec_get_chroma_sub_sample), (avcodec_get_pix_fmt_name),
+	(avcodec_get_pix_fmt), (avpicture_layout),
+	(avcodec_get_pix_fmt_loss), (avg_bits_per_pixel), (img_copy),
+	(get_convert_table_entry), (img_convert), (img_get_alpha_info):
+	Fix code to not use GCC extensions (and c99 extensions that
+	Forte does not like.)
+
+2004-12-19  Tim-Philipp Müller  <t.i.m@zen.co.uk>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/deinterlace/gstdeinterlace.c: (gst_deinterlace_link),
+	(gst_deinterlace_chain):
+	  Rowstride fixes. Fixes #161039.
+	* gst/videocrop/gstvideocrop.c: (gst_video_crop_init),
+	(gst_video_crop_get_property), (gst_video_crop_add_to_struct_val),
+	(gst_video_crop_getcaps), (gst_video_crop_link),
+	(gst_video_crop_i420), (gst_video_crop_chain),
+	(gst_video_crop_change_state):
+	  Rework of negotiation. Actually works now. Fixes #158650.
+
+2004-12-18  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/matroska-demux.c: (gst_matroska_ebmlnum_sint):
+	  That was very stupid.
+
+2004-12-18  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/matroska-demux.c:
+	(gst_matroska_demux_parse_blockgroup):
+	  Fix possible crasher.
+
+2004-12-18  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/matroska-demux.c: (gst_matroska_ebmlnum_uint),
+	(gst_matroska_ebmlnum_sint), (gst_matroska_demux_parse_blockgroup):
+	  Lace sizes can be zero.
+
+2004-12-18  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/musepack/gstmusepackdec.cpp:
+	  Fetch error return values. Fixes #161624.
+	* gst/apetag/apedemux.c: (gst_ape_demux_stream_data):
+	  Really EOS.
+
+2004-12-18  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_stream_index):
+	  Work for truncated (unfinished download etc.) files. Fixes #160514.
+
+2004-12-18  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_loop):
+	  Fix for integer overflow. Makes #156001 not crash. Probably masks
+	  the real bug.
+
+2004-12-17  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/ac3parse/gstac3parse.c: (plugin_init):
+	  Parsers never have ranks. Fixes #159651.
+
+2004-12-17  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/playback/gstdecodebin.c: (compare_ranks):
+	  make sure the facotries are ordered the same every time even if they
+	  have the same rank by using the name
+	* gst/playback/gstdecodebin.c: (find_compatibles):
+	  make sure we don't add factories to the list twice
+
+2004-12-16  David Schleef  <ds@schleef.org>
+
+	* configure.ac: look for musepack headers as musepack/*.h
+	(fixes #159847)
+	* ext/musepack/gstmusepackdec.h: use <musepack/*.h>
+	* ext/musepack/gstmusepackreader.h: same
+
+2004-12-17  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-read.c:
+	(gst_riff_read_strf_auds_with_data):
+	  Read extradata correctly (fixes #155879).
+
+2004-12-16  David Schleef  <ds@schleef.org>
+
+	* gst/audioscale/gstaudioscale.c: allow passthru of >2 channel
+	audio.  does _not_ attempt or allow conversion unless channels
+	is 1 or 2.
+
+2004-12-16  Christian Fredrik Kalager Schaller  <uraeus@gnome.org>
+
+	* tools/gst-launch-ext-m.m: fix mpeg and vob pipelines
+
+2004-12-16  David Schleef  <ds@schleef.org>
+
+	* gst/audioscale/gstaudioscale.c: the resample library only
+	handles 1 or 2 channels.  Change caps to compensate.
+
+2004-12-16  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/matroska-demux.c: (aac_rate_idx), (aac_profile_idx),
+	(gst_matroska_demux_audio_caps):
+	  Some MPEG-AAC hacks, because else it doesn't work...
+
+2004-12-16  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_video_caps_with_data),
+	(gst_riff_create_video_template_caps):
+	  Add h264.
+
+2004-12-16  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/audio/Makefile.am:
+	  Try to fix buildbot.
+
+2004-12-16  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/tcp/gstmultifdsink.c:
+	  Clean up and uniformize debugging.
+
+2004-12-16  Edward Hervey  <bilboed@bilboed.com>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_class_init),
+	(gst_dvd_demux_reset), (gst_dvd_demux_change_state):
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_reset),
+	(gst_mpeg_demux_change_state):
+	  Reset on ready. Fixes 160276.
+
+2004-12-16  Sebastien Cote  <sc5@hermes.usherb.ca>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+	(gst_ffmpegcsp_pad_link):
+	  Fix memleak (#154815).
+
+2004-12-16  James Bowes  <bowes@cs.dal.ca>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/musicbrainz/gsttrm.c: (gst_musicbrainz_class_init),
+	(gst_musicbrainz_init), (gst_musicbrainz_chain),
+	(gst_musicbrainz_set_property), (gst_musicbrainz_get_property):
+	* ext/musicbrainz/gsttrm.h:
+	  Add support for using a proxy server when getting a trm id from
+	  the MusicBrainz database (#149613).
+
+2004-12-16  Christophe Fergeau  <teuf@gnome.org>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstdecodebin.c: (new_pad), (close_link):
+	* gst/playback/gstplaybasebin.c: (new_decoded_pad):
+	  Fix memleaks (#157233).
+
+2004-12-16  Sebastien Cote  <sc5@hermes.usherb.ca>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/resample/resample.c: (gst_resample_close):
+	* gst-libs/gst/resample/resample.h:
+	* gst/audioscale/gstaudioscale.c:
+	  Fix memleak (#159215).
+
+2004-12-16  Toni Willberg  <toniw@iki.fi>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/oss/gstosselement.c: (gst_osselement_probe_caps):
+	* sys/oss/oss_probe.c: (main):
+	  Check for mono/stereo support (similar to samplerate probing),
+	  fixes #159433. Also add missing copyright header to oss_probe.c.
+
+2004-12-15  David Schleef  <ds@schleef.org>
+
+	* configure.ac: add audioresample and cairo plugins.  Remove
+	HAVE_MMX stuff, because it's not used.
+	* ext/Makefile.am: same
+	* ext/audioresample/Makefile.am: You are not ready for an
+	audio resampling element based on audioresample.
+	* ext/audioresample/gstaudioresample.c:
+	* ext/audioresample/gstaudioresample.h:
+	* ext/cairo/Makefile.am: You are not ready for overlay elements
+	based on cairo.  Don't look too closely, these elements kinda
+	suck right now.
+	* ext/cairo/gstcairo.c: new
+	* ext/cairo/gsttextoverlay.c: new
+	* ext/cairo/gsttextoverlay.h: new
+	* ext/cairo/gsttimeoverlay.c: new
+	* ext/cairo/gsttimeoverlay.h: new
+	* gst-libs/gst/media-info/media-info-priv.h: fix compile
+	problem with compilers that don't support variadic macros.
+
+2004-12-15  Balamurali Viswanathan  <balamurali.viswanathan@wipro.com>
+
+	Reviewed by:  David Schleef  <ds@schleef.org>
+
+	* sys/sunaudio/gstsunaudio.c: (plugin_init):  Apply patch from
+	Bala, registering sunaudiosrc (oops!), and cleaning up code a
+	bit.  Also ran indent-gst.
+	* sys/sunaudio/gstsunaudiosrc.c: (gst_sunaudiosrc_init),
+	(gst_sunaudiosrc_change_state), (gst_sunaudiosrc_get),
+	(gst_sunaudiosrc_setparams):
+
+2004-12-14  David Schleef  <ds@schleef.org>
+
+	* gst/festival/gstfestival.c: (gst_festival_chain): Set the
+	output rate to 16000.  Should fix #160235.
+
+2004-12-14  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* gst/typefind/gsttypefindfunctions.c: (mpeg2_sys_type_find):
+	Add typefinding for mpeg2 pes streams
+
+2004-12-13  David Schleef  <ds@schleef.org>
+
+	* configure.ac:  Applied patch from bug #143659, making default
+	sources and sinks OS-dependent (for Solaris), and added code
+	for OS/X.
+	* gconf/gstreamer.schemas.in: use OS-dependent sinks in gconf.
+
+2004-12-13  Stephane Loeuillet  <stephane.loeuillet@tiscali.fr>
+
+	* gst-libs/gst/riff/riff-media.c:
+	  forgot to add h2.64 to avidemux template caps
+
+2004-12-13  Stephane Loeuillet  <stephane.loeuillet@tiscali.fr>
+
+	* gst/wavenc/riff.h:
+	* gst-libs/gst/riff/riff-media.c:
+	* gst-libs/gst/riff/riff-ids.h:
+	* gst/avi/gstavimux.c
+	add 4CC code for VideoSoft h264 in AVI (VSSH)
+	  fixes bug #160655
+	remove s323 from riff, it's quicktime specific :(
+
+2004-12-13  Stephane Loeuillet  <stephane.loeuillet@tiscali.fr>
+
+	* gst/asfdemux/README
+	* gst/wavenc/riff.h
+	* gst-libs/gst/riff/riff-ids.h
+	* gst-libs/gst/riff/riff-media.c
+	* gst/qtdemux/qtdemux.c:
+	  add new 4CC codes for h263 related codecs
+	  fixes partially bug #155163
+
+2004-12-12  Christian Fredrik Kalager Schaller  <christian at fluendo dot com>
+
+	* configure.ac: Update polyaudio requirement to 0.7
+	* ext/polyp/polypsink.c: (create_stream): add patch from iain (158258)
+
+2004-12-11  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* gst/interleave/deinterleave.c:
+	fix my name's spelling! :)
+
+2004-12-11  Stephane Loeuillet  <stephane.loeuillet@tiscali.fr>
+
+	* AUTHORS ChangeLog
+	* gst/auparse/gstauparse.c
+	* gst/interleave/deinterleave.c
+	* gst/law/:
+		alaw-decode.c alaw-encode.c
+		mulaw-decode.c mulaw-encode.c
+	* gst/oneton/gstoneton.c
+	* sys/osxaudio/:
+		gstosxaudioelement.c gstosxaudiosink.c gstosxaudiosrc.c
+	* sys/osxvideo/:
+		cocoawindow.h cocoawindow.m
+		osxvideosink.h osxvideosink.m
+
+	put the same mail address for Zaheer Abbas Merali everywhere
+
+2004-12-10  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_loop):
+	  Align by packetsize, and assert that we a packet available before
+	  playing. The first makes webstreams work (they often include
+	  trailing padding data in a packet), the second allows pausing a
+	  ASF stream in totem without getting demux errors afterwards.
+
+2004-12-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (get_relative):
+	  Check for non-NULL before accessing member (end-of-chain).
+
+2004-12-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/cdparanoia/gstcdparanoia.c: (cdparanoia_class_init),
+	(cdparanoia_set_property), (cdparanoia_get_property):
+	* ext/dvdnav/dvdnavsrc.c: (dvdnavsrc_class_init),
+	(dvdnavsrc_set_property), (dvdnavsrc_get_property):
+	* ext/dvdread/dvdreadsrc.c: (dvdreadsrc_class_init),
+	(dvdreadsrc_init), (dvdreadsrc_set_property),
+	(dvdreadsrc_get_property):
+	* sys/vcd/vcdsrc.c: (gst_vcdsrc_class_init),
+	(gst_vcdsrc_set_property), (gst_vcdsrc_get_property):
+	  Synchronize property names where not yet the case. Devices are
+	  now device=X, other versions are deprecated (but still exist).
+	  Also use g_free() unconditionally.
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init),
+	(setup_source), (gst_play_base_bin_get_property):
+	  Expose source.
+
+2004-12-09  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac: move GCONF macro outside conditional for the am
+	  conditional. Fixes #160439
+
+2004-12-08  David Schleef  <ds@schleef.org>
+
+	* tools/gst-visualise-m.m: Switch to elements that currently
+	exist.
+
+2004-12-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstogmparse.c: (gst_ogm_parse_chain):
+	  We love wrong commas.
+
+2004-12-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/matroska-demux.c:
+	(gst_matroska_demux_handle_src_query):
+	  Don't set DEFAULT, unsupported - makes length display incorrectly
+	  in some cases.
+
+2004-12-07  Christian Fredrik Kalager Schaller  <uraeus@gnome.org>
+
+	* gst/monoscope/README: remove blurb about files being GPL
+	* gst/monoscope/gstmonoscope.c: Change license field to LGPL
+	* gst/monoscope/monoscope.c: Change license to BSD with explanation
+	  monoscope is now effectively LGPL licensed
+
+2004-12-07  Christian Fredrik Kalager Schaller  <uraeus@gnome.org>
+
+	* gst/monoscope/README: Update information to be more correct
+	* gst/monoscope/convolve.c: Relicense to LGPL
+	* gst/monoscope/convolve.h: Relicense to LGPL
+
+2004-12-06  Arwed v. Merkatz <v.merkatz@gmx.net>
+
+	* gst/mpegaudioparse/gstmpegaudioparse.c: (gst_mp3parse_chain):
+	  set BUFFER_DURATION to correct values (mpeg1 audio frame length is fixed)
+	* gst/matroska/matroska-mux.c: (gst_matroska_mux_audio_pad_link):
+	  set default_duration for mpeg1 audio
+
+2004-12-06  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_get_caps), (gst_alsa_close_audio):
+	* ext/alsa/gstalsa.h:
+	  refactor big chunks of the core caps negotiation code to make it
+	  a lot faster, because people claim it's really slow
+	  (actually, just cache the getcaps when the device is opened)
+
+2004-12-06  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/a52dec/gsta52dec.c: (gst_a52dec_init),
+	(gst_a52dec_handle_event), (gst_a52dec_update_streaminfo),
+	(gst_a52dec_handle_frame), (gst_a52dec_chain),
+	(gst_a52dec_change_state), (plugin_init):
+	* ext/a52dec/gsta52dec.h:
+	  Do something useful with timestamps. Make chain-based (since
+	  there's really no reason to be loopbased).
+	* gst/avi/gstavidemux.c: (gst_avi_demux_process_next_entry):
+	  Update current_byte/frame correctly.
+
+2004-12-04  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/apetag/apedemux.c: (gst_ape_demux_parse_tags),
+	(gst_ape_demux_stream_init):
+	  Forward tags, too.
+
+2004-12-04  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/apetag/apedemux.c: (gst_ape_demux_stream_init):
+	  Let's make sure we're done typefinding when detecting tags.
+
+2004-12-03  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/ebml-read.c: (gst_ebml_read_class_init),
+	(gst_ebml_read_init), (gst_ebml_read_use_event),
+	(gst_ebml_read_element_id), (gst_ebml_peek_id),
+	(gst_ebml_read_seek), (gst_ebml_read_skip),
+	(gst_ebml_read_reserve), (gst_ebml_read_buffer),
+	(gst_ebml_read_master):
+	* gst/matroska/ebml-read.h:
+	* gst/matroska/matroska-demux.c:
+	(gst_matroska_demux_parse_contents),
+	(gst_matroska_demux_loop_stream), (gst_matroska_demux_audio_caps):
+	  Disgustingly evil hack for working around INTERRUPT events and
+	  their extremely annoying habit of being a pain in the ass. We
+	  simply peek a cluster before reading any of it.
+
+2004-12-03  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/musepack/gstmusepackdec.cpp:
+	  There's also floating point libmusepacks.
+
+2004-12-03  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/faad/gstfaad.c: (gst_faad_chanpos_from_gst),
+	(gst_faad_chanpos_to_gst), (gst_faad_chain):
+	  Set DURATION even if source buffer didn't. Also use increasing
+	  timestamps.
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_audio_caps_with_data):
+	  Block_align can have larger values than 8192.
+
+2004-12-02  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/law/alaw-decode.c: (alawdec_getcaps), (alawdec_link):
+	* gst/law/alaw-encode.c: (alawenc_getcaps), (alawenc_link):
+	* gst/law/mulaw-decode.c: (mulawdec_getcaps), (mulawdec_link):
+	* gst/law/mulaw-encode.c: (mulawenc_getcaps), (mulawenc_link):
+	  Fix caps.
+
+2004-12-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l/v4l_calls.c: (gst_v4l_get_chan_names):
+	  Fix logic bug.
+
+2004-12-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_type_find):
+	  Yay, another one.
+
+2004-12-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/esd/esdsink.c: (gst_esdsink_chain):
+	  Make error actually say something useful (fixes #156798).
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_video_caps_with_data),
+	(gst_riff_create_video_template_caps):
+	  Add Intel Video 5.0 fourcc (IV50).
+
+2004-12-01  Christophe Fergeau  <teuf@gnome.org>
+
+	* ext/mad/gstmad.c: (mpg123_parse_xing_header): fix xing header
+	detection on mono and stereo mp3 files.
+
+2004-12-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_change_state):
+	  Don't crash on EMPTY caps (e.g. when the demuxer didn't recognize
+	  the contained stream).
+
+2004-12-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/faad/gstfaad.c: (gst_faad_srcconnect), (gst_faad_chain):
+	  Oops, remove debug.
+
+2004-12-01  Sebastien Cote  <sc5@hermes.usherb.ca>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/law/alaw-decode.c: (alawdec_getcaps):
+	* gst/law/mulaw-decode.c: (mulawdec_getcaps):
+	  Prevent warnings when negotiating caps (fixes #159338).
+
+2004-12-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+	(gst_ffmpegcsp_chain):
+	  Remove old leftover that shouldn't be there...
+
+2004-12-01  Sebastien Cote  <sc5@hermes.usherb.ca>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_read_use_event):
+	  Don't forward DISCONT events (fixes #159684).
+
+2004-12-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybin.c: (remove_sinks), (setup_sinks):
+	  Unlink manually since sometimes bin disposal (and therefore
+	  pad unlinking) is delayed, which will cause a new media file
+	  to not be able to start playing instantly.
+
+2004-11-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gststreaminfo.c: (stream_info_mute_pad):
+	  On mute of an unlinked stream, check for pad availability so
+	  we don't crash on unlinked pad.
+
+2004-11-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_stream_index),
+	(gst_avi_demux_massage_index):
+	  Fix quite humiliating bug in omitting 0-sized index chunks but
+	  forgetting to count them for timestamps.
+
+2004-11-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/a52dec/gsta52dec.c: (gst_a52dec_loop):
+	  Actually leave the loop if we failed to sync. Don't crash.
+
+2004-11-28  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_get_audio_stream),
+	(gst_dvd_demux_process_private):
+	* gst/mpegstream/gstdvddemux.h:
+	  Fix crash (#159759). Doesn't work, though. :-(.
+
+2004-11-28  Benjamin Otte  <otte@gnome.org>
+
+	* gst/audioconvert/gstchannelmix.c: (gst_audio_convert_mix):
+	  more overwriting protection due to modifying channels one by one
+	  instead of all at once
+
+2004-11-28  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/audioconvert/gstchannelmix.c:
+	(gst_audio_convert_fill_normalize):
+	  Normalize using absolute values.
+
+2004-11-28  Julien MOUTTE  <julien@moutte.net>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/directfb/Makefile.am:
+	* ext/directfb/directfbvideosink.c: (gst_directfbvideosink_create),
+	(gst_directfbvideosink_get_pixel_format),
+	(gst_directfbvideosink_get_format_from_fourcc),
+	(gst_directfbvideosink_fixate), (gst_directfbvideosink_getcaps),
+	(gst_directfbvideosink_sink_link),
+	(gst_directfbvideosink_change_state),
+	(gst_directfbvideosink_chain), (gst_directfbvideosink_buffer_free),
+	(gst_directfbvideosink_buffer_alloc),
+	(gst_directfbvideosink_interface_supported),
+	(gst_directfbvideosink_interface_init),
+	(gst_directfbvideosink_navigation_send_event),
+	(gst_directfbvideosink_navigation_init),
+	(gst_directfbvideosink_set_property),
+	(gst_directfbvideosink_get_property),
+	(gst_directfbvideosink_finalize), (gst_directfbvideosink_init),
+	(gst_directfbvideosink_base_init),
+	(gst_directfbvideosink_class_init),
+	(gst_directfbvideosink_get_type), (plugin_init):
+	* ext/directfb/directfbvideosink.h: Adding a first version of
+	directfbvideosink.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_init): Initializing some
+	more.
+
+2004-11-28  Benjamin Otte  <otte@gnome.org>
+
+	* gst/audioconvert/gstchannelmix.c: (gst_audio_convert_mix):
+	  walk the samples backwards if out_channels > in_channels so we don't
+	  overwrite data
+
+2004-11-28  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/audioconvert/Makefile.am:
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_init),
+	(gst_audio_convert_link), (gst_audio_convert_change_state),
+	(gst_audio_convert_channels):
+	* gst/audioconvert/gstchannelmix.c:
+	(gst_audio_convert_unset_matrix),
+	(gst_audio_convert_fill_identical),
+	(gst_audio_convert_fill_compatible),
+	(gst_audio_convert_detect_pos), (gst_audio_convert_fill_one_other),
+	(gst_audio_convert_fill_others),
+	(gst_audio_convert_fill_normalize),
+	(gst_audio_convert_fill_matrix), (gst_audio_convert_setup_matrix),
+	(gst_audio_convert_passthrough), (gst_audio_convert_mix):
+	* gst/audioconvert/gstchannelmix.h:
+	  Implement a channel mixer.
+
+2004-11-28  Martin Soto  <martinsoto@users.sourceforge.net>
+
+	* ext/alsa/gstalsasink.c (gst_alsa_sink_loop):
+	* ext/alsa/gstalsa.h:
+	* ext/alsa/gstalsa.c (gst_alsa_set_clock):
+	Make alsasink actually honor gst_element_set_clock and use that
+	clock instead of its internal one.
+
+2004-11-27  Christophe Fergeau  <teuf@gnome.org>
+
+	* gst/playback/gstplaybasebin.c: (setup_source): fixed a caps leak
+	(gst_play_base_bin_change_state): nullify source and decoder when
+	going from READY to NULL so that we don't try to do weird stuff with
+	them when going from NULL to READY
+	* gst/playback/gstplaybin.c: (gst_play_bin_init): use gst_object_unref
+	instead of g_object_unref
+	(gen_video_element), (gen_audio_element): more refcounting fixes, now
+	it should be correct
+	(gst_play_bin_change_state): don't call remove_sinks if we are
+	currently disposing the object
+
+2004-11-27  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/a52dec/gsta52dec.c: (gst_a52dec_loop):
+	  Don't forget bass if it's there. Else left channel is silent...
+
+2004-11-27  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/a52dec/gsta52dec.c: (gst_a52dec_loop),
+	(gst_a52dec_change_state):
+	  Don't do sample adjusting anymore, we use float audio now.
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_fixate):
+	  Don't fixate to non-existing properties.
+
+2004-11-27  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/a52dec/gsta52dec.c: (gst_a52dec_channels),
+	(gst_a52dec_change_state):
+	  Advertise that we can do surround sound.
+
+2004-11-27  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/a52dec/gsta52dec.c: (gst_a52dec_reneg):
+	  Add buffer-frames=0.
+	* ext/dvdread/dvdreadsrc.c: (dvdreadsrc_get_type),
+	(dvdreadsrc_init), (dvdreadsrc_get_event_mask),
+	(dvdreadsrc_get_query_types), (dvdreadsrc_get_formats),
+	(dvdreadsrc_srcpad_event), (dvdreadsrc_srcpad_query),
+	(_seek_title), (_seek_chapter), (get_next_cell_for), (_read),
+	(seek_sector), (dvdreadsrc_get), (dvdreadsrc_open_file),
+	(dvdreadsrc_change_state), (dvdreadsrc_uri_get_type),
+	(dvdreadsrc_uri_get_protocols), (dvdreadsrc_uri_get_uri),
+	(dvdreadsrc_uri_set_uri), (dvdreadsrc_uri_handler_init):
+	* ext/dvdread/dvdreadsrc.h:
+	  Add seeking, querying for bytes, sectors, title, angle and
+	  chapter. Handle multiple chapters. Relicense to LGPL because
+	  Billy agreed on that (thanks Billy!).
+
+2004-11-27  Christophe Fergeau  <teuf@gnome.org>
+
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_dispose):
+	call parent dispose method
+
+2004-11-27  Martin Soto  <martinsoto@users.sourceforge.net>
+
+	* gst-libs/gst/audio/audioclock.c (gst_audio_clock_set_active)
+	(gst_audio_clock_get_internal_time):
+	Fix active <-> inactive transitions: ensure time value always
+	grows and avoid abrupt value changes.
+
+2004-11-27  Arwed v. Merkatz <v.merkatz@gmx.net>
+
+	* configure.ac:
+	* gst/tta/Makefile.am:
+	* gst/tta/crc32.h:
+	* gst/tta/filters.h:
+	* gst/tta/gsttta.c:
+	* gst/tta/gstttadec.c:
+	* gst/tta/gstttadec.h:
+	* gst/tta/gstttaparse.c:
+	* gst/tta/gstttaparse.h:
+	* gst/tta/ttadec.h:
+	  added TTA parser and decoder
+
+2004-11-26  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init),
+	(probe_triggered), (check_queue), (buffer_underrun),
+	(buffer_running), (buffer_overrun), (gen_source_element),
+	(setup_source):
+	* gst/playback/gstplaybasebin.h:
+	  Implement buffering. Needs some more work.
+
+2004-11-26  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/theora/theoradec.c: (theora_dec_chain):
+	  Fix ilog mask range overflow.
+
+2004-11-26  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_get_caps):
+	  Don't omit the last (which in case of dmix is the only :) )
+	  channel count. Don't set channels if <= 2.
+
+2004-11-26  Christophe Fergeau  <teuf@gnome.org>
+
+	* gst/playback/gstplaybin.c: (gen_video_element),
+	(gen_audio_element): Removed 2 obsolete comments
+
+2004-11-26  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* ext/vorbis/oggvorbisenc.c
+	* ext/vorbis/vorbisenc.c :
+	  change description fields of those plugins to differentiate them
+	  (pitivi show Encoders by description, they had the same one)
+
+2004-11-25  Christophe Fergeau  <teuf@gnome.org>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybin.c: (gst_play_bin_dispose),
+	(gst_play_bin_set_property), (gen_video_element),
+	(gen_audio_element):
+	  Refcounting fixes for provided audio-/videosinks.
+
+2004-11-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybin.c: (gen_video_element),
+	(gen_audio_element), (setup_sinks), (gst_play_bin_change_state):
+	  Don't reference all sinks, but only the video- and audiosinks.
+	  The vis. element should be disposed when we're done with it.
+	  We don't have any reason to keep it around. This fixes warnings
+	  when reusing playbin for playing multiple audio files with
+	  vis. enabled. Also release audio device on pause - idea stolen
+	  from Rhythmbox.
+
+2004-11-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/a52dec/gsta52dec.c: (gst_a52dec_channels), (gst_a52dec_push),
+	(gst_a52dec_reneg), (gst_a52dec_loop), (plugin_init):
+	* ext/alsa/gstalsa.c: (gst_alsa_get_caps):
+	* ext/alsa/gstalsaplugin.c: (plugin_init):
+	* ext/dts/gstdtsdec.c: (gst_dtsdec_channels),
+	(gst_dtsdec_renegotiate), (gst_dtsdec_loop), (plugin_init):
+	* ext/faad/gstfaad.c: (gst_faad_init), (gst_faad_chanpos_from_gst),
+	(gst_faad_chanpos_to_gst), (gst_faad_sinkconnect),
+	(gst_faad_srcgetcaps), (gst_faad_srcconnect), (gst_faad_chain),
+	(gst_faad_change_state), (plugin_init):
+	* ext/faad/gstfaad.h:
+	* ext/vorbis/vorbis.c: (plugin_init):
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_chain):
+	* gst-libs/gst/audio/Makefile.am:
+	* gst-libs/gst/audio/audio.c: (plugin_init):
+	* gst-libs/gst/audio/multichannel.c:
+	(gst_audio_check_channel_positions),
+	(gst_audio_get_channel_positions),
+	(gst_audio_set_channel_positions),
+	(gst_audio_set_structure_channel_positions_list),
+	(add_list_to_struct), (gst_audio_set_caps_channel_positions_list),
+	(gst_audio_fixate_channel_positions):
+	* gst-libs/gst/audio/multichannel.h:
+	* gst-libs/gst/audio/testchannels.c: (main):
+	* gst/audioconvert/gstaudioconvert.c:
+	(gst_audio_convert_class_init), (gst_audio_convert_init),
+	(gst_audio_convert_dispose), (gst_audio_convert_getcaps),
+	(gst_audio_convert_parse_caps), (gst_audio_convert_link),
+	(gst_audio_convert_fixate), (gst_audio_convert_channels):
+	* gst/audioconvert/plugin.c: (plugin_init):
+	  Surround sound support.
+
+2004-11-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_push):
+	  Fix position for discont if we're close as well. Nitpicking, but
+	  saves a few milliseconds of extra waiting or skipping.
+
+2004-11-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_factory_filter):
+	  We sometimes need parsers for playback, so add those too.
+
+2004-11-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* gst/apetag/Makefile.am:
+	* gst/apetag/apedemux.c: (gst_ape_demux_get_type),
+	(gst_ape_demux_base_init), (gst_ape_demux_class_init),
+	(gst_ape_demux_init), (gst_ape_demux_get_src_formats),
+	(gst_ape_demux_get_src_query_types),
+	(gst_ape_demux_handle_src_query), (gst_ape_demux_get_event_mask),
+	(gst_ape_demux_handle_src_event), (gst_ape_demux_handle_event),
+	(gst_ape_demux_typefind_peek), (gst_ape_demux_typefind_get_length),
+	(gst_ape_demux_typefind_suggest), (gst_ape_demux_typefind),
+	(gst_ape_demux_parse_tags), (gst_ape_demux_stream_init),
+	(gst_ape_demux_stream_data), (gst_ape_demux_loop),
+	(gst_ape_demux_change_state):
+	* gst/apetag/apedemux.h:
+	* gst/apetag/apetag.c: (plugin_init):
+	* gst/typefind/gsttypefindfunctions.c: (apetag_type_find),
+	(plugin_init):
+	  APE v1/2 tag reader plus typefind function.
+
+2004-11-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_add_element):
+	* gst/typefind/gsttypefindfunctions.c: (mp3_type_find):
+	  Remove hacks for older core. Require newer core version
+	  accordingly.
+
+2004-11-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/cdxaparse/Makefile.am:
+	* gst/cdxaparse/gstcdxaparse.c: (gst_cdxaparse_get_type),
+	(gst_cdxaparse_class_init), (gst_cdxaparse_init),
+	(gst_cdxaparse_loop), (gst_cdxaparse_change_state), (plugin_init):
+	* gst/cdxaparse/gstcdxaparse.h:
+	* gst/cdxaparse/gstcdxastrip.c: (gst_cdxastrip_get_type),
+	(gst_cdxastrip_base_init), (gst_cdxastrip_class_init),
+	(gst_cdxastrip_init), (gst_cdxastrip_get_src_formats),
+	(gst_cdxastrip_get_src_query_types),
+	(gst_cdxastrip_handle_src_query), (gst_cdxastrip_get_event_mask),
+	(gst_cdxastrip_handle_src_event), (gst_cdxastrip_strip),
+	(gst_cdxastrip_sync), (gst_cdxastrip_handle_event),
+	(gst_cdxastrip_chain), (gst_cdxastrip_change_state):
+	* gst/cdxaparse/gstcdxastrip.h:
+	  SVCD/VCD header stripping separated from CDXA image parsing.
+	* gst/typefind/gsttypefindfunctions.c: (mp3_type_find),
+	(plugin_init):
+	  Add VCD/SVCD header typefinding for VCD/SVCD.
+	* sys/vcd/vcdsrc.c: (gst_vcdsrc_get_type), (gst_vcdsrc_base_init),
+	(gst_vcdsrc_class_init), (gst_vcdsrc_init),
+	(gst_vcdsrc_set_property), (gst_vcdsrc_get_property),
+	(gst_vcdsrc_get_event_mask), (gst_vcdsrc_get_query_types),
+	(gst_vcdsrc_get_formats), (gst_vcdsrc_srcpad_event),
+	(gst_vcdsrc_srcpad_query), (gst_vcdsrc_get),
+	(gst_vcdsrc_open_file), (gst_vcdsrc_close_file),
+	(gst_vcdsrc_change_state), (gst_vcdsrc_msf),
+	(gst_vcdsrc_recalculate), (gst_vcdsrc_uri_get_type),
+	(gst_vcdsrc_uri_get_protocols), (gst_vcdsrc_uri_get_uri),
+	(gst_vcdsrc_uri_set_uri), (gst_vcdsrc_uri_handler_init):
+	* sys/vcd/vcdsrc.h:
+	  Fix up, add seeking, querying, URI interface. Works in totem now.
+
+2004-11-25  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	  back to CVS
+
+=== release 0.8.6 ===
+
+2004-11-25  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/it.po:
+	* po/nb.po:
+	* po/nl.po:
+	* po/or.po:
+	* po/sq.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	  releasing 0.8.6, "IOU Love"
+
+2004-11-23  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	patch by: Ronald Bultje <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c:
+	  Fix unplayable files error handling.  Fixes #158365
+
+2004-11-23  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	patch by: Ronald Bultje <rbultje@ronald.bitfreak.net>
+
+	* gst/typefind/gsttypefindfunctions.c:
+	  Fix broken mp3 typefinding.  Fixes #158375
+
+2004-11-23  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	patch by: Ronald Bultje <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c:
+	  Fix sync on broken files.  Fixes #158976
+
+2004-11-23  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	patch by: Edward Hervey <bilboed@bilboed.com>
+
+	* ext/libpng/gstpngenc.c:
+	  Copy over buffer properties.  Fixes #158832
+
+2004-11-23  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	patch by: Tim-Philipp Müller <t.i.m@zen.co.uk>
+
+	* ext/dvdread/dvdreadsrc.c:
+	  Fixes invalid reads (#158462)
+
+2004-11-23  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/v4l/gstv4lsrc.c:
+	* sys/v4l/gstv4lsrc.h:
+	* sys/v4l/v4lsrc_calls.c:
+	  Probe less and cache it.  Fixes #159187.
+
+2004-11-23  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/videorate/gstvideorate.c:
+	  Handle all video formats. Fixes #159186.
+
+2004-11-16  Jan Schmidt  <thaytan@mad.scientist.com>
+	* gst/synaesthesia/gstsynaesthesia.c:
+	(gst_synaesthesia_class_init), (gst_synaesthesia_init),
+	(gst_synaesthesia_dispose), (gst_synaesthesia_finalize),
+	(gst_synaesthesia_sink_link), (gst_synaesthesia_src_getcaps),
+	(gst_synaesthesia_src_link), (gst_synaesthesia_chain),
+	(gst_synaesthesia_change_state), (plugin_init):
+	Fix up synaesthesia to work under different samplerates/ buffer sizes.
+	Force 320x200 output, as that's the only thing the underlying
+	synaesthesia implementation supports. Still needs to be made
+	re-entrant.
+
+2004-11-14  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	  Fix mpeg2enc configure check (similar to mplex check below).
+
+2004-11-14  Koop Mast  <kwm@rainbow-runner.nl>
+
+	reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c:
+	  Fix for gcc-2.95 (fixes #158221).
+
+2004-11-13  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_add_element):
+	  Re-add clock distribution hack (until new core is released).
+	  Fixes #158125.
+
+2004-11-13  Arwed v. Merkatz  <v.merkatz@gmx.net>
+	* configure.ac:
+	  fix mplex configure check segfaulting on some systems (bug #140994)
+
+2004-11-13  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_pcm_wait):
+	  add debugging
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_loop):
+	  do a wait when we enter the loop func with no data available to
+	  write instead of getting into an 100% CPU loop by just returning and
+	  being called again by the scheduler
+
+2004-11-13  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* configure.ac:
+	* ext/libvisual/visual.c: (gst_visual_get_type),
+	(libvisual_log_handler), (gst_visual_getcaps),
+	(gst_visual_srclink), (gst_visual_change_state), (make_valid_name),
+	(plugin_init):
+	  Update libvisual to 0.1.7. Link in the debug handling to gstreamer
+	* ext/smoothwave/Makefile.am:
+	* ext/smoothwave/demo-osssrc.c: (main):
+	* ext/smoothwave/gstsmoothwave.c: (gst_smoothwave_class_init),
+	(gst_smoothwave_init), (gst_smoothwave_dispose), (gst_sw_sinklink),
+	(gst_sw_srclink), (gst_smoothwave_chain), (gst_sw_change_state),
+	(plugin_init):
+	* ext/smoothwave/gstsmoothwave.h:
+	  Make gstsmoothwave a working element in the 20th century.
+
+	* gst/chart/gstchart.c: (gst_chart_init), (gst_chart_srcconnect):
+	  Fix incorrect link function
+
+2004-11-12  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/volume/gstvolume.c:
+	  Allow buffer-frames=0.
+
+2004-11-12 Iain <iaingnome@gmail.com>
+
+	* configure.ac: Check for polypaudio
+
+	* ext/Makefile.am: Build the polyp dir
+
+	* ext/polyp: The polypsink sources.
+
+2004-10-30 Iain <iaingnome@gmail.com>
+
+	* gst/interleave/interleave.c (interleave_unlink): Change the src pads
+	caps to reflect the new number of channels.
+
+2004-11-12  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_loop):
+	  Fix for negotiation order problem. This would show when the
+	  ALSA loopfuction was called before any other function. ALSA
+	  wouldn't do anything because we're not negotiated yet, leading
+	  to an infinite loop. Showed in e.g. Rhythmbox. Fixes #158006.
+
+2004-11-11  Tim-Philipp Müller  <t.i.m@zen.co.uk>
+
+	reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_src_query):
+	  No warnings (#157986).
+
+2004-11-11  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/typefind/gsttypefindfunctions.c: (plugin_init):
+	  Prefer apev1/2 and id3v1 (at end of file) over musepack.
+
+2004-11-11  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_loop_stream):
+	  Signal no-more-pads (so it works in playbin).
+
+2004-11-11  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/musepack/gstmusepackreader.cpp:
+	  Workaround for older core.
+
+2004-11-11  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/ffmpegcolorspace/imgconvert.c: (yuv420p_to_yuv422):
+	  Actually test for odd width/height rather than testing whether
+	  a temporary variable that was 0 before we subtracted 1 is now
+	  not equal to zero (which it always is).
+
+2004-11-11  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* sys/v4l2/gstv4l2element.c: (gst_v4l2_iface_supported):
+	Fix compilation if HAVE_XVIDEO is not defined
+
+2004-11-11  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* sys/v4l/gstv4lelement.c: (gst_v4l_iface_supported):
+	Fix compilation if HAVE_XVIDEO is not defined
+
+2004-11-11  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* gst/goom/gstgoom.c: (gst_goom_class_init), (gst_goom_init),
+	(gst_goom_dispose), (gst_goom_sinkconnect), (gst_goom_chain),
+	(gst_goom_change_state), (plugin_init):
+	Use the bytestream adapter so goom doesn't depend on the input
+	buffer size.
+	Add a debug category
+
+2004-11-11  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_change_state):
+	  Only set hardware parameters *after* negotiation. Before
+	  negotiation, it will set ANY and that seems to cause crashes
+	  (see e.g. #151288, #153227).
+
+2004-11-10  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_get_time):
+	  This seems to be antique leftover. It needs to pass error
+	  checking.
+	* ext/sdl/sdlvideosink.c: (gst_sdlvideosink_init),
+	(gst_sdlvideosink_deinitsdl), (gst_sdlvideosink_initsdl),
+	(gst_sdlvideosink_destroy), (gst_sdlvideosink_create),
+	(gst_sdlvideosink_sinkconnect), (gst_sdlvideosink_chain):
+	  Fix GstXOverlay implementation (#151059).
+
+2004-11-10  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_change_state):
+	  Don't assert (#157853).
+
+2004-11-10  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event),
+	  Fix bytes/samples confustion.
+	(gst_alsa_sink_mmap), (gst_alsa_sink_loop):
+	  Fix for underrun (#144389).
+
+2004-11-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/typefind/gsttypefindfunctions.c: (mp3_type_find):
+	  Disable halfway-seek for pending release (since it needs a new
+	  core release).
+
+2004-11-09  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/v4l/gstv4lsrc.c:
+	* sys/v4l/gstv4lsrc.h:
+	* sys/v4l/v4lsrc_calls.c:
+	  add autoprobe-fps property so we can separate autoprobing parts
+
+2004-11-09  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/v4l/gstv4lsrc.c:
+	* sys/v4l/v4lsrc_calls.c:
+	initialise fourcc to catch unset fourcc's, and debug
+
+2004-11-09  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/README:
+	* gst/playback/gstdecodebin.c: (close_pad_link), (try_to_link_1):
+	* gst/playback/gstplaybin.c: (gst_play_bin_init),
+	(gst_play_bin_dispose), (gst_play_bin_set_property),
+	(remove_sinks), (setup_sinks), (gst_play_bin_change_state),
+	(gst_play_bin_get_event_masks), (gst_play_bin_send_event),
+	(gst_play_bin_get_formats), (gst_play_bin_convert),
+	(gst_play_bin_get_query_types), (gst_play_bin_query):
+	Cleanups and some more documentation.
+
+2004-11-09  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/libcaca/gstcacasink.c: (gst_cacasink_class_init),
+	(gst_cacasink_init), (gst_cacasink_chain):
+	* ext/libcaca/gstcacasink.h:
+	Cacasink inherits from VideoSink, so let that store the clock.
+
+2004-11-09  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/README:
+	* gst/playback/gstplaybasebin.c: (group_destroy), (group_is_muted),
+	(add_stream), (unknown_type), (add_element_stream), (no_more_pads),
+	(probe_triggered), (preroll_unlinked), (new_decoded_pad),
+	(gst_play_base_bin_change_state), (gst_play_base_bin_found_tag):
+	* gst/playback/gstplaybin.c: (gen_vis_element), (remove_sinks),
+	(setup_sinks):
+	* gst/playback/gststreaminfo.c: (gst_stream_info_set_mute),
+	(gst_stream_info_is_mute), (gst_stream_info_set_property):
+	* gst/playback/gststreaminfo.h:
+	Updated README.
+	Only switch groups if all streams have muted (EOSed).
+	Send Tags in sync with the stream playback instead of in
+	the playback/preroll phase.
+	Some cleanups, free the fakesrc elements.
+
+2004-11-09  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_get_caps_internal):
+	  buffer-frames property was missing
+	* ext/arts/gst_arts.c:
+	  rate missing from sinkcaps
+	* ext/audiofile/gstafparse.c:
+	* ext/audiofile/gstafsink.c:
+	* ext/audiofile/gstafsrc.c:
+	* ext/swfdec/gstswfdec.c:
+	  int audio doesn't know buffer-frames
+	* ext/cdparanoia/gstcdparanoia.c:
+	  int audio doesn't know chunksize either
+	* ext/nas/nassink.c:
+	  it's endianness, not endianess
+	* gst-libs/gst/audio/audio.h:
+	  make float standard pad template caps really describe float
+	* gst/law/mulaw.c: (linear_factory):
+	  signed only, please
+	* gst/mpegstream/gstdvddemux.c:
+	  widths of 20 are not valid
+
+2004-11-08  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	Submitted by: Luca Ferretti <elle.uca@infinito.it>
+
+	* po/LINGUAS:
+	* po/it.po:
+	  Add Italian
+
+2004-11-08  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/README:
+	* gst/playback/gstdecodebin.c: (close_pad_link), (try_to_link_1):
+	* gst/playback/gstplaybasebin.c: (probe_triggered),
+	(gst_play_base_bin_change_state):
+	Updated README, added more comments for fixmes etc..
+
+2004-11-08  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_add_element):
+	We can remove this hack now.
+
+2004-11-08  Wim Taymans  <wim@fluendo.com>
+
+	* gst/videomixer/videomixer.c: (gst_videomixer_blend_ayuv_ayuv),
+	(gst_videomixer_fill_checker), (gst_videomixer_fill_color),
+	(gst_videomixer_blend_buffers), (gst_videomixer_loop):
+	Only mix AYUV for maximum quality.
+
+2004-11-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (get_relative), (gst_ogg_demux_src_query),
+	(gst_ogg_demux_push), (gst_ogg_pad_push):
+	  Let's act as if we're synchronized now! :).
+	* ext/theora/theoradec.c: (theora_dec_chain):
+	  Add some debug.
+
+2004-11-08  Wim Taymans  <wim@fluendo.com>
+
+	* gst/alpha/gstalpha.c: (gst_alpha_method_get_type),
+	(gst_alpha_set_property), (gst_alpha_sink_link),
+	(gst_alpha_set_ayuv), (gst_alpha_set_i420),
+	(gst_alpha_chroma_key_ayuv), (gst_alpha_chroma_key_i420),
+	(gst_alpha_init_params), (gst_alpha_chain):
+	Implement alpha functions for AYUV too, this increases
+	accuracy quite a bit.
+
+2004-11-08  Wim Taymans  <wim@fluendo.com>
+
+	* gst/ffmpegcolorspace/avcodec.h:
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c:
+	(gst_ffmpeg_pixfmt_to_caps), (gst_ffmpeg_caps_to_pixfmt),
+	(gst_ffmpegcsp_avpicture_fill):
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+	(gst_ffmpegcsp_caps_remove_format_info):
+	* gst/ffmpegcolorspace/imgconvert.c: (avpicture_get_size),
+	(shrink12), (img_get_alpha_info), (deinterlace_line),
+	(deinterlace_line_inplace):
+	* gst/ffmpegcolorspace/imgconvert_template.h:
+	Added AYUV colorspace and handle RGBA a bit more respectful.
+
+2004-11-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_pad_push):
+	  Actually always send a discont (cornercase when resending the
+	  same serial-tagged chain twice).
+
+2004-11-08  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xcontext_clear),
+	(gst_ximagesink_finalize):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xcontext_clear),
+	(gst_xvimagesink_finalize): Some more cleanups, leaks fixed and checks.
+
+2004-11-08  Wim Taymans  <wim@fluendo.com>
+
+	* gst/typefind/gsttypefindfunctions.c: (aac_type_find):
+	Don't segfault on NULL data.
+
+2004-11-08  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstdecodebin.c: (unlinked):
+	* gst/playback/gstplay-marshal.list:
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init),
+	(gst_play_base_bin_init), (group_create), (get_active_group),
+	(get_building_group), (group_destroy), (group_commit),
+	(queue_overrun), (remove_groups), (add_stream), (unknown_type),
+	(add_element_stream), (no_more_pads), (probe_triggered),
+	(preroll_unlinked), (new_decoded_pad), (removed_decoded_pad),
+	(state_change), (setup_source), (gst_play_base_bin_get_property),
+	(gst_play_base_bin_change_state), (gst_play_base_bin_add_element),
+	(gst_play_base_bin_link_stream),
+	(gst_play_base_bin_get_streaminfo):
+	* gst/playback/gstplaybasebin.h:
+	* gst/playback/gstplaybin.c: (gst_play_bin_class_init),
+	(remove_sinks), (setup_sinks), (gst_play_bin_change_state):
+	Add support for chained ogg files. Prepare for playlist
+	support. This patch introduces the concept of pad groups, which
+	together compose one playable media file.
+
+2004-11-07  David Schleef  <ds@schleef.org>
+
+	* testsuite/gst-lint: Check for pad templates that aren't statically
+	scoped.
+
+2004-11-07  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/musepack/Makefile.am:
+	* ext/musepack/gstmusepackdec.cpp:
+	* ext/musepack/gstmusepackdec.h:
+	* ext/musepack/gstmusepackreader.cpp:
+	* ext/musepack/gstmusepackreader.h:
+	  Add musepack decoder.
+	* ext/faad/gstfaad.c: (gst_faad_base_init):
+	  Make pad templates static.
+	* gst/typefind/gsttypefindfunctions.c: (mp3_type_find),
+	(plugin_init):
+	  Add musepack typefinder, make mp3 typefinding work halfway stream,
+	  which doesn't actually work yet because id3demux doesn't implement
+	  _get_length().
+
+2004-11-07  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_next_buffer),
+	(gst_ogg_mux_queue_pads), (gst_ogg_mux_loop):
+	  Fix interrupt event handling (#144436).
+
+2004-11-07  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_do_typefind):
+	  Hide unused glory.
+
+2004-11-06  Tim-Philipp Müller  <t.i.m@zen.co.uk>
+
+	reviewed by: Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/vorbis/vorbisenc.c: (raw_caps_factory):
+	  Fix weird caps (#157548).
+
+2004-11-06  Tim-Philipp Müller  <t.i.m@zen.co.uk>
+
+	Reviewed by: Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/rtp/gstrtpgsmparse.c: (gst_rtpgsm_caps_nego):
+	  Add missing NULL terminator (#157543).
+
+2004-11-05  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/tcp/gsttcp.h:
+	* gst/tcp/gsttcpclientsink.c:
+	* gst/tcp/gsttcpclientsrc.c:
+	* gst/tcp/gsttcpserversink.c:
+	* gst/tcp/gsttcpserversrc.c:
+	  ports can go up to 65535.  Move common defines to gsttcp.h
+
+2004-11-05  Wim Taymans  <wim@fluendo.com>
+
+	* gst/videotestsrc/videotestsrc.c: (paint_setup_Y41B),
+	(paint_hline_Y41B), (paint_setup_Y42B), (paint_hline_Y42B):
+	Added two more colorspaces.
+
+2004-11-05  Wim Taymans  <wim@fluendo.com>
+
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c:
+	(gst_ffmpegcsp_avpicture_fill):
+	* gst/ffmpegcolorspace/imgconvert.c: (avpicture_get_size),
+	(yuv422p_to_yuv422), (yuv420p_to_yuv422), (shrink12),
+	(img_convert), (deinterlace_line), (deinterlace_line_inplace):
+	More stride fixes.
+
+2004-11-05  Wim Taymans  <wim@fluendo.com>
+
+	* gst/alpha/gstalpha.c: (gst_alpha_set_property), (gst_alpha_add),
+	(gst_alpha_chroma_key), (gst_alpha_init_params), (gst_alpha_chain):
+	* gst/videomixer/videomixer.c: (gst_videomixer_blend_ayuv_i420),
+	(gst_videomixer_fill_checker), (gst_videomixer_blend_buffers),
+	(gst_videomixer_loop):
+	More stride fixes.
+
+2004-11-05  Benjamin Otte  <otte@gnome.org>
+
+	* ext/mad/gstmad.c: (gst_mad_chain):
+	  don't overflow data buffer. Flush not needed sync data when syncing
+	  failed.
+
+2004-11-04  Wim Taymans  <wim@fluendo.com>
+
+	* gst/alpha/gstalpha.c: (gst_alpha_method_get_type),
+	(gst_alpha_class_init), (gst_alpha_init), (gst_alpha_set_property),
+	(gst_alpha_get_property), (gst_alpha_add), (gst_alpha_chroma_key),
+	(gst_alpha_init_params), (gst_alpha_chain),
+	(gst_alpha_change_state):
+	Updated the chroma keying algorithm with something more
+	sophisticated.
+
+2004-11-03  Wim Taymans  <wim@fluendo.com>
+
+	* gst/videomixer/videomixer.c: (gst_videomixer_blend_ayuv_i420),
+	(gst_videomixer_fill_checker), (gst_videomixer_fill_color),
+	(gst_videomixer_blend_buffers), (gst_videomixer_loop):
+	Fix stride issues. Does not completely work for odd
+	heights.
+
+2004-11-03  Wim Taymans  <wim@fluendo.com>
+
+	* gst/alpha/gstalpha.c: (gst_alpha_method_get_type),
+	(gst_alpha_chroma_key), (gst_alpha_chain):
+	Fix stride issues. Does not completely work for odd
+	heights.
+
+2004-11-03  Christophe Fergeau  <teuf@gnome.org>
+
+	* gst/videoscale/gstvideoscale.c: (gst_videoscale_getcaps):
+	* gst/videoscale/videoscale.c: (videoscale_find_by_structure):
+	leak fixes
+
+2004-11-03  Wim Taymans  <wim@fluendo.com>
+
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c:
+	(gst_ffmpegcsp_avpicture_fill):
+	* gst/ffmpegcolorspace/imgconvert.c: (avpicture_get_size),
+	(avpicture_alloc):
+	* gst/ffmpegcolorspace/imgconvert_template.h:
+	Use correct _fill function to get correct strides.
+
+2004-11-02  David Schleef  <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header),
+	(gst_qtdemux_add_stream), (qtdemux_parse), (qtdemux_parse_tree),
+	(qtdemux_parse_udta), (qtdemux_tag_add), (gst_qtdemux_handle_esds):
+	Change all g_print()s to debugging.  Add a bunch of consistency
+	checks.
+
+2004-11-02  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_class_init),
+	(try_to_link_1), (get_our_ghost_pad), (remove_element_chain),
+	(unlinked), (no_more_pads), (close_link):
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_init),
+	(unknown_type), (add_element_stream), (new_decoded_pad),
+	(removed_decoded_pad), (setup_source):
+	* gst/playback/gststreaminfo.c: (gst_stream_info_get_type),
+	(gst_stream_info_class_init), (gst_stream_info_init),
+	(gst_stream_info_new), (gst_stream_info_dispose),
+	(stream_info_mute_pad), (gst_stream_info_set_property),
+	(gst_stream_info_get_property):
+	* gst/playback/gststreaminfo.h:
+	Fix playback of multiple files.
+	a slightly different approach to handling dynamic pad removals.
+	This one only looks at pads that we have linked.
+
+2004-11-01  Christophe Fergeau  <teuf@gnome.org>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_finalize): fix an "invalid
+	free" warning from libc.
+
+2004-11-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_class_init),
+	(get_unconnected_element), (remove_starting_from), (pad_removed),
+	(close_link):
+	  Implement support for dynamic pad changing. We listen to "live"
+	  pad removals (i.e. while playing) and re-setup autoplugging
+	  after that. Playbasebin/playbin need some more work for this
+	  to finally work, but decodebin supports (and replugs) chained
+	  ogg now.
+
+2004-11-02  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_class_init), (gst_alsa_dispose),
+	(gst_alsa_finalize):
+	* ext/cdaudio/gstcdaudio.c: (gst_cdaudio_class_init),
+	(gst_cdaudio_finalize):
+	* ext/cdparanoia/gstcdparanoia.c: (cdparanoia_class_init),
+	(cdparanoia_finalize):
+	* ext/divx/gstdivxdec.c: (gst_divxdec_dispose):
+	* ext/divx/gstdivxenc.c: (gst_divxenc_dispose):
+	* ext/dvdread/dvdreadsrc.c: (dvdreadsrc_class_init),
+	(dvdreadsrc_finalize):
+	* ext/flac/gstflacdec.c: (gst_flacdec_class_init),
+	(gst_flacdec_finalize):
+	* ext/flac/gstflacenc.c: (gst_flacenc_class_init),
+	(gst_flacenc_finalize):
+	* ext/gnomevfs/gstgnomevfssink.c: (gst_gnomevfssink_class_init),
+	(gst_gnomevfssink_finalize):
+	* ext/gnomevfs/gstgnomevfssrc.c: (gst_gnomevfssrc_class_init),
+	(gst_gnomevfssrc_finalize):
+	* ext/libfame/gstlibfame.c: (gst_fameenc_class_init),
+	(gst_fameenc_finalize):
+	* ext/nas/nassink.c: (gst_nassink_class_init),
+	(gst_nassink_finalize):
+	* ext/sdl/sdlvideosink.c: (gst_sdlvideosink_finalize),
+	(gst_sdlvideosink_class_init):
+	* ext/sndfile/gstsf.c: (gst_sf_dispose):
+	* gst-libs/gst/mixer/mixertrack.c: (gst_mixer_track_dispose):
+	* gst-libs/gst/tuner/tunerchannel.c: (gst_tuner_channel_dispose):
+	* gst-libs/gst/tuner/tunernorm.c: (gst_tuner_norm_dispose):
+	* gst-libs/gst/xwindowlistener/xwindowlistener.c:
+	(gst_x_window_listener_dispose):
+	* gst/audioscale/gstaudioscale.c:
+	* gst/playondemand/gstplayondemand.c: (play_on_demand_class_init),
+	(play_on_demand_finalize):
+	* gst/videofilter/gstvideobalance.c: (gst_videobalance_dispose):
+	* gst/videoscale/gstvideoscale.c: (gst_videoscale_chain):
+	* sys/cdrom/gstcdplayer.c: (cdplayer_class_init),
+	(cdplayer_finalize):
+	* sys/glsink/glimagesink.c: (gst_glimagesink_finalize),
+	(gst_glimagesink_class_init):
+	* sys/oss/gstosselement.c: (gst_osselement_class_init),
+	(gst_osselement_finalize):
+	* sys/oss/gstosssink.c: (gst_osssink_dispose):
+	* sys/oss/gstosssrc.c: (gst_osssrc_dispose):
+	* sys/v4l/gstv4lelement.c: (gst_v4lelement_dispose):
+	  Fixes a bunch of problems with finalize and dispose functions,
+	  either assumptions that dispose is only called once, or not calling
+	  the parent class dispose/finalize function
+
+2004-11-01  Stefan Kost  <ensonic@users.sf.net>
+
+	* ext/esd/esdsink.c: (gst_esdsink_init), (gst_esdsink_link):
+	  added two api precondition guards
+	  use g_strdup with getenv to fix crash when using ENVVAR
+
+2004-11-01  Jan Schmidt  <thaytan@mad.scientist.com>
+	* ext/esd/esdsink.c: (gst_esdsink_class_init),
+	(gst_esdsink_finalize):
+	Use a finalize function, not dispose, and more importantly,
+	call the parent class finalize function too
+
+2004-11-01  Johan Dahlin  <johan@gnome.org>
+
+	* ext/ogg/gstoggdemux.c:
+	* gst/tags/gstvorbistag.c:
+	Plug leaks.
+
+2004-10-31  Benjamin Otte  <otte@gnome.org>
+
+	* gst/tags/gstvorbistag.c: (gst_vorbis_tag_chain):
+	  lotsa memleaks today. But they're all small...
+
+2004-10-31  Benjamin Otte  <otte@gnome.org>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_pad_push):
+	  another memleak crushed
+
+2004-10-31  Benjamin Otte  <otte@gnome.org>
+
+	* gst/tags/gstvorbistag.c: (gst_tag_to_vorbis_comments):
+	  fix memleak
+
+2004-10-31  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_pad_push):
+	  Hack to prevent crash when going to READY inside signal handler
+	  while this function is active.
+
+2004-10-31  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/ffmpegcolorspace/Makefile.am:
+	* gst/ffmpegcolorspace/avcodec.h:
+	* gst/ffmpegcolorspace/common.h:
+	* gst/ffmpegcolorspace/dsputil.c: (dsputil_static_init):
+	* gst/ffmpegcolorspace/dsputil.h:
+	* gst/ffmpegcolorspace/gstffmpeg.c: (plugin_init):
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c:
+	(gst_ffmpeg_get_palette), (gst_ffmpeg_set_palette),
+	(gst_ffmpeg_pixfmt_to_caps), (gst_ffmpeg_smpfmt_to_caps),
+	(gst_ffmpegcsp_codectype_to_caps), (gst_ffmpeg_caps_to_smpfmt),
+	(gst_ffmpeg_caps_to_pixfmt), (gst_ffmpegcsp_caps_with_codectype),
+	(gst_ffmpegcsp_avpicture_fill):
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.h:
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+	(gst_ffmpegcsp_caps_remove_format_info), (gst_ffmpegcsp_getcaps),
+	(gst_ffmpegcsp_pad_link), (gst_ffmpegcsp_get_type),
+	(gst_ffmpegcsp_base_init), (gst_ffmpegcsp_class_init),
+	(gst_ffmpegcsp_init), (gst_ffmpegcsp_chain),
+	(gst_ffmpegcsp_change_state), (gst_ffmpegcsp_set_property),
+	(gst_ffmpegcsp_get_property), (gst_ffmpegcolorspace_register):
+	* gst/ffmpegcolorspace/imgconvert.c:
+	(avcodec_get_chroma_sub_sample), (avcodec_get_pix_fmt_name),
+	(avcodec_get_pix_fmt), (avpicture_fill), (avpicture_layout),
+	(avpicture_get_size), (avcodec_get_pix_fmt_loss),
+	(avg_bits_per_pixel), (avcodec_find_best_pix_fmt1),
+	(avcodec_find_best_pix_fmt), (img_copy_plane), (img_copy),
+	(yuv422_to_yuv420p), (uyvy422_to_yuv420p), (uyvy422_to_yuv422p),
+	(yuv422_to_yuv422p), (yuv422p_to_yuv422), (yuv422p_to_uyvy422),
+	(uyvy411_to_yuv411p), (yuv420p_to_yuv422), (C_JPEG_TO_CCIR),
+	(img_convert_init), (img_apply_table), (shrink41), (shrink21),
+	(shrink12), (shrink22), (shrink44), (grow21_line), (grow41_line),
+	(grow21), (grow22), (grow41), (grow44), (conv411),
+	(gif_clut_index), (build_rgb_palette), (bitcopy_n), (mono_to_gray),
+	(monowhite_to_gray), (monoblack_to_gray), (gray_to_mono),
+	(gray_to_monowhite), (gray_to_monoblack), (avpicture_alloc),
+	(avpicture_free), (is_yuv_planar), (img_convert),
+	(get_alpha_info_pal8), (img_get_alpha_info), (deinterlace_line),
+	(deinterlace_line_inplace), (deinterlace_bottom_field),
+	(deinterlace_bottom_field_inplace), (avpicture_deinterlace):
+	* gst/ffmpegcolorspace/imgconvert_template.h:
+	* gst/ffmpegcolorspace/mem.c: (av_malloc), (av_realloc), (av_free):
+	* gst/ffmpegcolorspace/mmx.h:
+	* gst/ffmpegcolorspace/utils.c: (av_mallocz), (av_strdup),
+	(av_fast_realloc), (av_mallocz_static), (av_free_static),
+	(av_freep), (avcodec_get_context_defaults),
+	(avcodec_alloc_context), (avcodec_init):
+	  Sync back from gst-ffmpeg. Deprecates ffcolorspace. Adds palette
+	  handling plus update from ffmpeg CVS. Large clean-up.
+
+2004-10-31  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/Makefile.am:
+	  We need the marshallers for decodebin, too.
+
+2004-10-30  David Schleef  <ds@schleef.org>
+
+	* gst/typefind/gsttypefindfunctions.c: (qt_type_find): Make
+	  quicktime typefinding work with 64-bit offsets.
+
+2004-10-30  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/dv/gstdvdec.c: (gst_dvdec_handle_sink_event):
+	  Set EOS on the element when processing an EOS event.
+	* ext/speex/gstspeexdec.h:
+	* ext/speex/gstspeexenc.h:
+	  Only keep a const ptr to the mode
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_audio_caps_with_data),
+	(gst_riff_create_audio_template_caps):
+	  Allow WMAV3, with up to 6 channels.
+	* gst/asfdemux/gstasfmux.c: (gst_asfmux_request_new_pad):
+	  Don't call gst_pad_set_event_function on a sink pad.
+	* gst/mpegstream/gstdvddemux.c:
+	(gst_dvd_demux_get_subpicture_stream),
+	(gst_dvd_demux_set_cur_audio), (gst_dvd_demux_set_cur_subpicture):
+	  Copy the explicit caps that were set across to the cur_* pads,
+	  instead of trying to use a possibly non-existent negotiated caps.
+	  Reset the type of subpicture pads to UNKNOWN after calling
+	  init_stream, so that the caps get set.
+
+2004-10-29  Martin Pitt  <martin.pitt@canonical.com>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_process_chunk):
+	  Don't touch buffer if it is of size 0 (fixes #151064).
+
+2004-10-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_push), (gst_ogg_pad_push):
+	  Synchronized discont handling.
+
+2004-10-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_src_event),
+	(gst_ogg_demux_push):
+	  Make seeking sort-of exact again (fixes #156387).
+
+2004-10-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (unknown_type),
+	(add_element_stream), (new_decoded_pad),
+	(gst_play_base_bin_change_state):
+	* gst/playback/gststreaminfo.c: (gst_stream_info_class_init),
+	(gst_stream_info_init), (gst_stream_info_new),
+	(gst_stream_info_dispose), (gst_stream_info_get_property):
+	* gst/playback/gststreaminfo.h:
+	  Make caps explicitely available. Makes testing for unsupported
+	  types possible. Improves error reporting.
+
+2004-10-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/audioconvert/gstaudioconvert.c:
+	(gst_audio_convert_buffer_to_default_format):
+	  Really don't touch read-only buffers (#156563).
+
+2004-10-29  Sebastien Cote  <sc5@hermes.usherb.ca>
+
+	Reviewd by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_fmt):
+	  Fix memleak (#155223).
+
+2004-10-29  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/.cvsignore:
+	* gst/tcp/gstmultifdsink.c: (gst_sync_method_get_type),
+	(gst_multifdsink_class_init), (gst_multifdsink_init),
+	(gst_multifdsink_add), (gst_multifdsink_remove),
+	(gst_multifdsink_remove_client_link), (is_sync_frame),
+	(gst_multifdsink_new_client),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_recover_client), (gst_multifdsink_queue_buffer),
+	(gst_multifdsink_handle_clients), (gst_multifdsink_set_property),
+	(gst_multifdsink_get_property):
+	* gst/tcp/gstmultifdsink.h:
+	Added burst on connect sync_method, deprecated sync_clients,
+	streamlined the sync code some more.
+
+2004-10-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (thread_error), (setup_source),
+	(gst_play_base_bin_change_state):
+	  Improve error reporting.
+
+2004-10-28  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/Makefile.am:
+	* gst/tcp/fdsetstress.c: (mess_some_more), (run_test), (main):
+	* gst/tcp/gstfdset.c: (nearest_pow), (resize), (ensure_size),
+	(gst_fdset_new), (gst_fdset_free), (gst_fdset_set_mode),
+	(gst_fdset_fd_ctl_write), (gst_fdset_fd_ctl_read),
+	(gst_fdset_fd_has_closed), (gst_fdset_fd_has_error),
+	(gst_fdset_fd_can_read), (gst_fdset_fd_can_write),
+	(gst_fdset_wait):
+	Added more locks around fdset structures. Fixed/reworked
+	the poll array resizing code.
+	Added stress test for fdset.
+
+2004-10-28  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* gst-libs/gst/audio/gstaudiofilter.c: (gst_audiofilter_link):
+	fix build
+
+2004-10-28  Benjamin Otte  <otte@gnome.org>
+
+	* gst-libs/gst/audio/gstaudiofilter.c: (gst_audiofilter_link):
+	  fix link function to always query channels and query width for
+	  floats
+	* configure.ac:
+	  add equalizer dir
+	* gst/equalizer/Makefile.am:
+	* gst/equalizer/gstiirequalizer.c: (gst_iir_equalizer_get_type),
+	(gst_iir_equalizer_base_init), (gst_iir_equalizer_class_init),
+	(gst_iir_equalizer_init), (gst_iir_equalizer_finalize),
+	(arg_to_scale), (setup_filter),
+	(gst_iir_equalizer_compute_frequencies),
+	(gst_iir_equalizer_set_property), (gst_iir_equalizer_get_property),
+	(gst_iir_equalizer_filter_inplace), (gst_iir_equalizer_setup),
+	(plugin_init):
+	  add an equalizer
+
+2004-10-27  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	Submitted by: Kjartan Maraas <kmaraas@broadpark.no>
+
+	* po/LINGUAS:
+	* po/nb.po:
+	  Added Norwegian Bokmaal translation
+
+2004-10-27  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_build_list):
+	  Don't break on options (fixes #156488).
+
+2004-10-27  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	* ext/cdaudio/Makefile.am:
+	* sys/Makefile.am:
+	  fix build on older automake
+
+2004-10-26  Wim Taymans  <wim@fluendo.com>
+
+	* ext/dv/gstdvdec.c: (gst_dvdec_video_getcaps),
+	(gst_dvdec_video_link), (gst_dvdec_push), (gst_dvdec_loop):
+	Allow a little margin when negotiating the framerate.
+
+2004-10-26  Stefan Kost  <ensonic@users.sf.net>
+
+	* gst/level/gstlevel.c:
+	  synchonised naming of pads and pad-templates
+
+2004-10-26  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_src_event),
+	(gst_ogg_demux_handle_event), (_find_chain_get_unknown_part),
+	(_find_streams_check), (gst_ogg_demux_push):
+	Fix EOS again. Needs to be done in a better way. We should not
+	remove the pad if there is no new chained stream.
+
+2004-10-26 Iain <iaingnome@gmail.com>
+
+	* ext/ogg/gstoggdemux.c (gst_ogg_pad_new): Free the tag list.
+	* gst/audioscale/gstaudioscale.c (gst_audioscale_link): Free the copy
+	of the caps.
+	* gst/interleave/interleave.c (interleave_class_init): Hook up release
+	pad.
+	(interleave_release_pad): Remove the pad.
+	* gst/level/gstlevel.c: Allow the level to take 1 or 2 channels.
+	* sys/sunaudio/gstsunaudio.c (gst_sunaudio_setparams): Pay attention to
+	the set device.
+	* sys/xvimage/xvimagesink.c (gst_xvimagesink_get_xv_support): Free the
+	attrs
+	(gst_xvimagesink_xcontext_clear): Free the xcontext.
+	(gst_xvimagesink_finalize): Free the par.
+
+2004-10-26  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavimux.c: (gst_avimux_audsinkconnect),
+	(gst_avimux_stop_file):
+	  First calculate the rate, and only then use it. Hdr.rate is a
+	  multiple and not a derivative of hdr.scale. Scale is not the
+	  same as blockalign but is solely related to rate.
+
+2004-10-26  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/gnomevfs/gstgnomevfssink.c: (gst_gnomevfssink_init),
+	(gst_gnomevfssink_handle_event), (gst_gnomevfssink_chain):
+	  Implement seeking.
+
+2004-10-25  James Henstridge  <james@jamesh.id.au>
+
+	Reviewed by:  David Schleef  <ds@schleef.org>
+
+	* examples/gstplay/player.c: (got_stream_length), (main):
+	* examples/seeking/cdplayer.c: (update_scale):
+	* examples/seeking/seek.c: (format_value), (update_scale):
+	* examples/seeking/spider_seek.c: (format_value), (update_scale),
+	(stop_seek):
+	Build fixes on AMD64.
+
+2004-10-25  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	reviewed by: Ronald Bultje <rbultje at gnome dot org>
+
+	* sys/v4l/v4l_calls.c: (gst_v4l_get_chan_names):
+	Fix for some v4l cards which hang in v4lsrc
+
+2004-10-25  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_pad_remove),
+	(gst_ogg_demux_push), (gst_ogg_chains_clear):
+	Make sure to remove the pad when a new chain is
+	encountered. Set some vars to NULL so we don't try
+	to reference freed memory.
+
+2004-10-25  Wim Taymans  <wim@fluendo.com>
+
+	* examples/seeking/Makefile.am:
+	* examples/seeking/cdplayer.c: (update_scale):
+	* examples/seeking/chained.c: (unlinked), (new_pad), (main):
+	* examples/seeking/playbin.c: (make_playerbin_pipeline),
+	(format_value), (update_scale), (iterate), (start_seek),
+	(stop_seek), (print_media_info), (play_cb), (pause_cb), (stop_cb),
+	(print_usage), (main):
+	Added some more examples, update others.
+
+2004-10-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/flac/gstflacdec.c: (gst_flacdec_update_metadata):
+	* ext/speex/gstspeexdec.c: (speex_dec_chain):
+	* ext/theora/theoradec.c: (theora_dec_chain):
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_chain):
+	  Add codec-name metadata.
+
+2004-10-25  Takao Fujiwara  <Takao.Fujiwara@Sun.COM>
+
+	Reviewd by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_build_list):
+	* ext/alsa/gstalsamixertrack.c: (gst_alsa_mixer_track_new):
+	* ext/alsa/gstalsamixertrack.h:
+	* po/POTFILES.in:
+	  ALSA mixer track label internationalization (#154054).
+
+2004-10-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/theora/theoradec.c: (theora_dec_chain):
+	  Export bitrate as metadata.
+
+2004-10-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_build_list):
+	* ext/alsa/gstalsamixertrack.c: (gst_alsa_mixer_track_new):
+	* ext/alsa/gstalsamixertrack.h:
+	  Fix names, fix loop.
+
+2004-10-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/speex/gstspeexdec.c: (gst_speex_dec_init),
+	(speex_dec_convert):
+	  sinkconvert function so oggdemux can get the file length (totem).
+
+2004-10-25  James Morrison  <ja2morri@csclub.uwaterloo.ca>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_process_chunk):
+	  Don't push incomplete packets.
+	* gst/typefind/gsttypefindfunctions.c: (m4a_type_find):
+	  Fix MPEG-4 audio typefinding.
+
+2004-10-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l/Makefile.am:
+	* sys/v4l/gstv4l.c: (plugin_init):
+	* sys/v4l/gstv4lelement.c: (gst_v4lelement_get_type),
+	(gst_v4lelement_init), (gst_v4lelement_dispose),
+	(gst_v4lelement_change_state):
+	* sys/v4l/gstv4lelement.h:
+	* sys/v4l/gstv4lxoverlay.c: (gst_v4l_xoverlay_open),
+	(gst_v4l_xoverlay_close), (idle_refresh),
+	(gst_v4l_xoverlay_set_xwindow_id):
+	* sys/v4l/gstv4lxoverlay.h:
+	* sys/v4l/v4l-overlay_calls.c:
+	* sys/v4l/v4l_calls.h:
+	* sys/v4l2/Makefile.am:
+	* sys/v4l2/gstv4l2.c: (plugin_init):
+	* sys/v4l2/gstv4l2element.c: (gst_v4l2element_get_type),
+	(gst_v4l2element_init), (gst_v4l2element_dispose),
+	(gst_v4l2element_change_state):
+	* sys/v4l2/gstv4l2element.h:
+	* sys/v4l2/gstv4l2xoverlay.c: (gst_v4l2_xoverlay_open),
+	(gst_v4l2_xoverlay_close), (idle_refresh),
+	(gst_v4l2_xoverlay_set_xwindow_id):
+	* sys/v4l2/gstv4l2xoverlay.h:
+	* sys/v4l2/v4l2-overlay_calls.c:
+	* sys/v4l2/v4l2_calls.h:
+	  Remove client-side overlay handling, use the X-server v4l plugin
+	  for that. Nicer overlay, less code. Also make the plugin
+	  compileable without X (but then without overlay, obviously).
+	  Makes xwindowlistener obsolete, should we remove that?
+
+2004-10-25  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/oss/gstosssrc.c: (gst_osssrc_get_time), (gst_osssrc_get),
+	(gst_osssrc_src_query):
+	* sys/oss/gstosssrc.h:
+	  OK, so people want offset in DEFAULT. This time, actually fix all
+	  cases.
+	* sys/v4l2/gstv4l2src.c: (gst_v4l2src_getcaps):
+	  Add FPS properly.
+
+2004-10-24  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/asfdemux/gstasfmux.c:
+	* gst/avi/gstavimux.c:
+	  Framerate.
+
+2004-10-24  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l2/gstv4l2element.c: (gst_v4l2element_set_property):
+	  Fix properties (channel, norm, frequency).
+
+2004-10-24  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l2/gstv4l2element.c: (gst_v4l2element_get_property):
+	  Flag typo.
+	* sys/v4l2/v4l2_calls.c: (gst_v4l2_set_defaults):
+	  No warnings.
+
+2004-10-24  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l2/v4l2src_calls.c: (gst_v4l2src_clear_format_list):
+	  Fix hang.
+
+2004-10-24  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l2/gstv4l2element.h:
+	  Yet Another Hack (tm) for kernel header borkedness.
+	* sys/v4l2/gstv4l2src.c: (gst_v4l2src_init),
+	(gst_v4l2src_v4l2fourcc_to_caps), (gst_v4l2_fourcc_from_structure),
+	(gst_v4l2src_link), (gst_v4l2src_getcaps),
+	(gst_v4l2src_change_state):
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/v4l2src_calls.c: (gst_v4l2src_capture_init),
+	(gst_v4l2src_capture_start), (gst_v4l2src_capture_stop):
+	  Fix caps, keep track of state, work.
+
+2004-10-24  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_getcaps):
+	  Quiet.
+
+2004-10-24  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/oss/gstosssrc.c: (gst_osssrc_get):
+	  Don't mix bytes and samples.
+
+2004-10-24  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggmux.c:
+	  Basic pad template which accepts OGM tracks, speex, flac, vorbis
+	  and theora. Any is incorrect.
+	* gst/asfdemux/gstasfmux.c: (gst_asfmux_vidsink_link):
+	  Fix caps.
+	* sys/v4l/gstv4lmjpegsink.c: (gst_v4lmjpegsink_base_init):
+	* sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_base_init),
+	(gst_v4lmjpegsrc_init), (gst_v4lmjpegsrc_srcconnect),
+	(gst_v4lmjpegsrc_getcaps), (gst_v4lmjpegsrc_change_state):
+	* sys/v4l/gstv4lmjpegsrc.h:
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_src_link), (gst_v4lsrc_getcaps),
+	(gst_v4lsrc_change_state):
+	* sys/v4l/v4lmjpegsrc_calls.c: (gst_v4lmjpegsrc_capture_start),
+	(gst_v4lmjpegsrc_capture_stop):
+	  Fix caps. Keep track of internal state. Work.
+
+2004-10-23  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/Makefile.am:
+	  Fix the build fixes.
+
+2004-10-23  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_src_query),
+	(gst_ogg_demux_src_event), (_find_chain_seek),
+	(gst_ogg_pad_push):
+	  Check for pad availability before using it.
+	* ext/ogg/gstoggdemux.c: (_find_chain_process):
+	  Fix parsing of chained ogg. Needs more work on the decoder side.
+
+2004-10-22  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/spectrum/Makefile.am:
+	* gst/spectrum/demo-osssrc.c: (spectrum_chain), (main),
+	(idle_func):
+	  Fix demo and reenable it. Yes, I'm currently playing with audio
+	  analysis tools
+
+2004-10-22  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_pad_push):
+	  We love it if files that start at zero work too...
+
+2004-10-22  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_iterate):
+	  Handle files with missing EOS headers.
+
+2004-10-21  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* gst/tcp/gsttcpserversink.c:
+	(gst_tcpserversink_handle_server_read),
+	(gst_tcpserversink_init_send):
+	Zero some variables first (need for accept not to return EINVAL)
+
+2004-10-20  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_src_query),
+	(gst_ogg_demux_src_event), (gst_ogg_pad_push):
+	* ext/theora/theoradec.c: (theora_dec_sink_convert),
+	(theora_dec_chain):
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_get_formats),
+	(gst_vorbis_dec_init), (vorbis_dec_convert), (vorbis_dec_chain):
+	  Seeking and querying finetune.
+
+2004-10-20  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/raw1394/Makefile.am:
+	  fix the build
+
+2004-10-20  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_iterate):
+	  Wrong return.
+	* gst/playback/Makefile.am:
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_class_init):
+	* gst/playback/gstplay-marshal.list:
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init):
+	  Fix marshallers.
+
+2004-10-18  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_src_event):
+	  Silence.
+
+2004-10-18  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_src_query),
+	(gst_ogg_demux_src_event), (gst_ogg_pad_populate),
+	(gst_ogg_pad_push):
+	  Yay for non-lineair granulepos in theora.
+
+2004-10-18  Wim Taymans  <wim@fluendo.com>
+
+	* ext/dv/gstdvdec.c: (gst_dvdec_init), (gst_dvdec_video_getcaps),
+	(gst_dvdec_video_link), (gst_dvdec_push), (gst_dvdec_loop):
+	* ext/dv/gstdvdec.h:
+	Make sure we renegotiate aspect ratio when the camera switches.
+
+2004-10-18  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_src_query),
+	(gst_ogg_demux_src_event), (gst_ogg_pad_push):
+	  Start at zero.
+	* ext/theora/theoradec.c: (theora_dec_chain):
+	  Skip headers. Bad idea for chained ogg, but fixes seeking.
+
+2004-10-18  Wim Taymans  <wim@fluendo.com>
+
+	* configure.ac:
+	I swear, this is the last time I touch this.
+
+2004-10-18  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_src_query),
+	(gst_ogg_demux_src_event), (gst_ogg_pad_populate),
+	(_read_bos_process), (gst_ogg_demux_iterate), (gst_ogg_pad_new):
+	  Faster seeking.
+	* ext/theora/theoradec.c: (theora_dec_sink_convert):
+	  Time-to-default conversion.
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_chain):
+	  Don't error on unknown packets, just skip. We should probably
+	  read them if we want to support chained ogg.
+
+2004-10-18  Wim Taymans  <wim@fluendo.com>
+
+	* configure.ac:
+	Added cdaudio to wrong list.
+
+2004-10-18  Wim Taymans  <wim@fluendo.com>
+
+	* configure.ac:
+	Revive cdaudio.
+
+2004-10-18  Wim Taymans  <wim@fluendo.com>
+
+	* ext/dv/gstdvdec.c: (gst_dvdec_video_getcaps),
+	(gst_dvdec_video_link), (gst_dvdec_push):
+	* ext/jpeg/gstsmokeenc.c: (gst_smokeenc_class_init),
+	(gst_smokeenc_resync), (gst_smokeenc_chain):
+	Fix mimetype on smoke encoder.
+	Add aspect ratio to dvdec. Not sure if these
+	values are correct though....
+
+2004-10-18  Wim Taymans  <wim@fluendo.com>
+
+	* ext/vorbis/vorbisenc.c: (gst_vorbisenc_class_init):
+	Fix vorbis property descriptions and ranges.
+
+2004-10-18  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_iterate):
+	Really do nothing when no data is available.
+	Go to the playing state when the stream is not seekable
+	instead of failing.
+
+2004-10-18  Wim Taymans  <wim@fluendo.com>
+
+	* ext/cdaudio/gstcdaudio.c: (_do_init), (gst_cdaudio_base_init),
+	(gst_cdaudio_get_event_masks), (gst_cdaudio_send_event),
+	(gst_cdaudio_query), (plugin_init), (cdaudio_uri_get_type),
+	(cdaudio_uri_get_protocols), (cdaudio_uri_get_uri),
+	(cdaudio_uri_set_uri), (cdaudio_uri_handler_init):
+	Added uri handler for cd://
+	Port to new API.
+
+2004-10-18  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_class_init),
+	(gst_decode_bin_init), (find_compatibles), (close_pad_link),
+	(try_to_link_1), (no_more_pads), (close_link), (type_found):
+	* gst/playback/gstplaybasebin.c: (gen_preroll_element),
+	(remove_prerolls), (unknown_type), (add_element_stream),
+	(new_decoded_pad), (setup_source), (gst_play_base_bin_add_element),
+	(gst_play_base_bin_remove_element),
+	(gst_play_base_bin_link_stream):
+	* gst/playback/gstplaybin.c: (gen_video_element),
+	(gen_vis_element), (remove_sinks), (setup_sinks):
+	* gst/playback/gststreaminfo.c: (gst_stream_type_get_type),
+	(gst_stream_info_get_type), (gst_stream_info_class_init),
+	(gst_stream_info_init), (gst_stream_info_new),
+	(gst_stream_info_dispose), (stream_info_mute_pad),
+	(gst_stream_info_set_property), (gst_stream_info_get_property):
+	* gst/playback/gststreaminfo.h:
+	Add sink padtemplate to decodebin.
+	Added some more comments.
+	Make queue size configurable in playbasebin.
+	Added possibility to use elements as sinks (ex cdaudio).
+
+2004-10-15  Wim Taymans  <wim@fluendo.com>
+
+	* ext/speex/gstspeexenc.c: (gst_speexenc_class_init),
+	(gst_speexenc_chain):
+	Fix speex timestamps so that it gets muxed properly.
+
+2004-10-15  Wim Taymans  <wim@fluendo.com>
+
+	* ext/raw1394/gstdv1394src.c: (gst_dv1394src_get_type),
+	(gst_dv1394src_base_init), (gst_dv1394src_class_init),
+	(gst_dv1394src_init), (gst_dv1394src_dispose),
+	(gst_dv1394src_iso_receive), (gst_dv1394src_discover_avc_node),
+	(gst_dv1394src_change_state), (gst_dv1394src_get_event_mask),
+	(gst_dv1394src_event), (gst_dv1394src_get_formats),
+	(gst_dv1394src_convert), (gst_dv1394src_get_query_types),
+	(gst_dv1394src_query), (gst_dv1394src_uri_get_type),
+	(gst_dv1394src_uri_get_protocols), (gst_dv1394src_uri_get_uri),
+	(gst_dv1394src_uri_set_uri), (gst_dv1394src_uri_handler_init):
+	* ext/raw1394/gstdv1394src.h:
+	Added conversion/query functions.
+	Update buffer timestamps,
+	Added signals.
+	Added uri dv:// so it might play from the firewire in playbin.
+	Fix a possible leak.
+	Added debugging.
+
+2004-10-15  Wim Taymans  <wim@fluendo.com>
+
+	* ext/raw1394/gstdv1394src.c: (gst_dv1394src_class_init),
+	(gst_dv1394src_init), (gst_dv1394src_set_property),
+	(gst_dv1394src_get_property), (gst_dv1394src_iso_receive),
+	(gst_dv1394src_discover_avc_node), (gst_dv1394src_change_state):
+	* ext/raw1394/gstdv1394src.h:
+	Added AV/C VTR control support needed for some cameras.
+	Added automatic port detection.
+	Added properties for selecting the channel.
+	The configure.ac script is not yet updated to reflect the
+	new libavc1394 and librom1394 dependencies.
+
+2004-10-15  Wim Taymans  <wim@fluendo.com>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header),
+	(qtdemux_parse), (gst_qtdemux_handle_esds):
+	An esds box is not a container.
+	Fix parsing of mp4v boxes.
+	Do not try to renegotiate fps for each frame. Need to
+	find a better method. This should fix mp4 playback.
+
+2004-10-14  David Schleef  <ds@schleef.org>
+
+	* configure.ac: update for swfdec-0.3 and liboil-0.2
+	* ext/swfdec/gstswfdec.c: update for swfdec-0.3
+	* ext/swfdec/gstswfdec.h: same
+	* gst/videofilter/gstvideobalance.c: update for liboil-0.2
+	* gst/videotestsrc/videotestsrc.c: same
+
+2004-10-14  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_add),
+	(gst_multifdsink_remove), (gst_multifdsink_remove_client_link),
+	(is_sync_frame), (gst_multifdsink_new_client),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_recover_client), (gst_multifdsink_queue_buffer),
+	(gst_multifdsink_handle_clients), (gst_multifdsink_change_state):
+	Turn warnings into info.
+	Don't allow a state change in the streaming thread.
+
+2004-10-14  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/vorbis/oggvorbisenc.c:
+	* ext/vorbis/vorbisdec.c:
+	  fix template sample rate
+
+2004-10-13  Wim Taymans  <wim@fluendo.com>
+
+	* ext/mad/gstmad.c: (gst_mad_check_caps_reset), (gst_mad_chain):
+	Decoding the header first fixes some problems in resyncing
+	in more mp3s.
+
+2004-10-12  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstplaybin.c: (gen_video_element),
+	(gen_vis_element), (remove_sinks), (setup_sinks):
+	Added vis plugin support, need to configure the vis
+	element to activate it.
+
+2004-10-12  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/gnomevfs/gstgnomevfssrc.c: (gst_gnomevfssrc_get),
+	(gst_gnomevfssrc_srcpad_query), (gst_gnomevfssrc_srcpad_event):
+	  Some debug.
+	* gst/avi/gstavidemux.c: (gst_avi_demux_reset),
+	(gst_avi_demux_handle_src_event), (gst_avi_demux_read_superindex),
+	(gst_avi_demux_read_subindexes), (gst_avi_demux_add_stream),
+	(gst_avi_demux_stream_index), (gst_avi_demux_skip),
+	(gst_avi_demux_sync), (gst_avi_demux_stream_scan),
+	(gst_avi_demux_massage_index), (gst_avi_demux_stream_header):
+	* gst/avi/gstavidemux.h:
+	  Support for openDML-2.0 indx/ix## chunks. Support for broken index
+	  recovery (where, if part of the index is broken, we will still read
+	  the rest of the index and recover the broken part by stream
+	  scanning). More broken media support. EOS workarounds. General AVI
+	  braindamage headache recovery. Aspirin included.
+
+2004-10-11  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/cdparanoia/gstcdparanoia.c: (cdparanoia_open),
+	(cdparanoia_event), (cdparanoia_query):
+	  Get rid of hideous lead-in.
+
+2004-10-11  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstplaybasebin.c: (setup_source):
+	Wrong var used to get g_list_next.
+
+2004-10-11  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/cdparanoia/gstcdparanoia.c: (cdparanoia_class_init),
+	(cdparanoia_get), (cdparanoia_open):
+	  Report discid as metadata, add duration.
+
+2004-10-11  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstplaybasebin.c: (setup_source):
+	Cleanup the previous pipeline a little earlier for the
+	case that a source element provides raw data.
+
+2004-10-11  Benjamin Otte  <otte@gnome.org>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_chain):
+	  reset v1 tag offset when there is no v1 tag. Fixes id3demux always
+	  consuming the last 128 bytes, even though it was valid mp3 data.
+
+2004-10-10  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_palette_to_caps),
+	(gst_v4lsrc_getcaps), (gst_v4lsrc_get):
+	* sys/v4l/v4l-overlay_calls.c: (gst_v4l_set_overlay):
+	Change g_warnings to GST_WARNING_OBJECT and fix colourspace issue
+
+2004-10-10  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_src_link), (gst_v4lsrc_getcaps):
+	Fix for webcams that support only specific width or height
+
+2004-10-09  Tim-Philipp Müller  <t.i.m@zen.co.uk>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/wavenc/gstwavenc.c: (gst_wavenc_stop_file):
+	  Fix wrong discont event setup (fixes #154967).
+
+2004-10-09  Sebastien Cote  <sc5@hermes.usherb.ca>
+
+	Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/auparse/gstauparse.c: (gst_auparse_chain):
+	  Error out on invalid data (fixes #154807).
+
+2004-10-09  Tim-Philipp Müller  <t.i.m@zen.co.uk>
+
+	Reviewed by: Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/dvdread/dvdreadsrc.c: (_read):
+	  Make titles > 0 work again (fixes #154834).
+
+2004-10-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_video_template_caps):
+	  WMV3 missing in template caps.
+
+2004-10-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_massage_index):
+	  OK, so the original code was too strict. It makes random AVI files
+	  hang for seconds upon opening, which is unacceptable and is far
+	  beyond the original goal of getting multiple chunks for one-chunk
+	  sounc stream files. So now do just that.
+
+2004-10-09  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (setup_source),
+	(gst_play_base_bin_change_state):
+	  Actually clean up streaminfo if output fails. This would trigger
+	  if, for example, there was no CD in the drive. No preroll, so
+	  a streaminfo structure is created, but the subsequent state change
+	  of the thread fails.
+	* gst/playback/gstplaybin.c: (gst_play_bin_change_state):
+	  Don't change state if parent failed.
+
+2004-10-08  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybin.c: (gst_play_bin_class_init),
+	(gst_play_bin_init), (gst_play_bin_get_property), (handoff),
+	(gen_video_element), (remove_sinks):
+	  Add small bits of code for screenshot handling.
+
+2004-10-08  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstplaybin.c: (gst_play_bin_set_property),
+	(gen_video_element), (gen_audio_element), (setup_sinks):
+	Don't assume the user provided sinks are named "sink"...
+
+2004-10-08  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstplaybasebin.c: (gen_preroll_element),
+	(unknown_type), (setup_source), (gst_play_base_bin_remove_element),
+	(gst_play_base_bin_link_stream):
+	Do not try to autoplug sources that generate raw streams like
+	cdparanoia.
+	disconnect the preroll overrun signal when we don't need it anymore.
+
+2004-10-08  Milosz Derezynski  <internalerror.rez@fhtw-berlin.de>
+
+	* ext/cdparanoia/gstcdparanoia.c: (_do_init),
+	Added reworked patch from #154903 from milosz derezynski (deadchip).
+
+2004-10-08  Wim Taymans  <wim@fluendo.com>
+
+	* ext/cdparanoia/gstcdparanoia.c: (_do_init),
+	(cdparanoia_base_init), (cdparanoia_class_init), (cdparanoia_init),
+	(cdparanoia_dispose), (cdparanoia_get), (cdparanoia_change_state),
+	(cdparanoia_convert), (cdparanoia_uri_get_type),
+	(cdparanoia_uri_get_protocols), (cdparanoia_uri_get_uri),
+	(cdparanoia_uri_set_uri), (cdparanoia_uri_handler_init):
+	* ext/cdparanoia/gstcdparanoia.h:
+	This adds the cdda://<tracknum> uri.
+
+2004-10-08  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_class_init),
+	(gst_decode_bin_init), (find_compatibles), (close_pad_link),
+	(try_to_link_1), (no_more_pads), (close_link), (type_found):
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init),
+	(unknown_type), (gst_play_base_bin_remove_element),
+	(gst_play_base_bin_link_stream):
+	* gst/playback/gstplaybasebin.h:
+	* gst/playback/gstplaybin.c: (gst_play_bin_init),
+	(gst_play_bin_set_property), (gen_video_element),
+	(gen_audio_element), (setup_sinks):
+	* gst/playback/gststreaminfo.c: (gst_stream_type_get_type),
+	(gst_stream_info_get_type), (gst_stream_info_class_init),
+	(gst_stream_info_init), (gst_stream_info_new),
+	(gst_stream_info_dispose), (stream_info_mute_pad),
+	(gst_stream_info_set_property), (gst_stream_info_get_property):
+	* gst/playback/gststreaminfo.h:
+	Reuse the audio and video bins.
+	Some internal cleanups in the stream selection code.
+
+2004-10-08  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_sink_link),
+	(gst_ximagesink_set_xwindow_id), (gst_ximagesink_init):
+	* sys/ximage/ximagesink.h:
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_sink_link),
+	(gst_xvimagesink_set_xwindow_id), (gst_xvimagesink_init):
+	* sys/xvimage/xvimagesink.h: Reverting Ronald's changes as the issue is
+	not coming from those elements. Moreover these elements should not keep
+	the xid they have been given when in NULL state.
+
+2004-10-07  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_sink_link),
+	(gst_ximagesink_set_xwindow_id), (gst_ximagesink_init):
+	* sys/ximage/ximagesink.h:
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_sink_link),
+	(gst_xvimagesink_set_xwindow_id), (gst_xvimagesink_init):
+	* sys/xvimage/xvimagesink.h:
+	  Actually only create a new toplevel window if we're not gonna
+	  embed it right after.
+
+2004-10-07  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstplaybasebin.c: (play_base_bin_mute_pad),
+	(gst_play_base_bin_mute_stream), (gst_play_base_bin_link_stream):
+	* gst/playback/gstplaybin.c: (setup_sinks):
+	Implement muting/unmuting of streams, mute streams that are not
+	used.
+
+2004-10-07  Wim Taymans  <wim@fluendo.com>
+
+	* gst/typefind/gsttypefindfunctions.c: (ac3_type_find),
+	(plugin_init):
+	Added lame audio/x-ac3 typefind function.
+
+2004-10-06  Thomas Vander Stichele  <thomas (at) apestaart (dot) org>
+
+	* configure.ac:
+	  bump nano to cvs
+
+=== release 0.8.5 ===
+
+2004-10-06  Thomas Vander Stichele  <thomas (at) apestaart (dot) org>
+
+	* NEWS:
+	* RELEASE:
+	* configure.ac:
+	  releasing 0.8.5, "Take You On"
+
+2004-10-06  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_init),
+	(find_compatibles), (close_pad_link), (try_to_link_1), (new_pad),
+	(no_more_pads), (close_link), (type_found):
+	* gst/playback/gstplaybasebin.c: (new_decoded_pad):
+	* gst/playback/gstplaybin.c: (gen_video_element):
+	Do not signal the no_more_pads after the first pad when
+	we are plugging a non dynamic element with multiple
+	output pads (like swfdec, dvdec, ...).
+
+2004-10-06  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	  bump for prerelease
+
+2004-10-06  Stephane Loeuillet  <stephane.loeuillet@tiscali.fr>
+
+	* gst/wavparse/gstwavparse.c:
+	  add ATRAC3 to STATIC CAPS to fix a warning
+
+	* gst/matroska/ebml-read.c:
+	* gst-libs/gst/riff/riff-read.c:
+	  fix typos
+
+2004-10-06  Stephane Loeuillet  <stephane.loeuillet@tiscali.fr>
+
+	* gst-libs/gst/riff/riff-media.c:
+	  generate caps for ATRAC3 audio streams
+
+	* gst/realmedia/rmdemux.c:
+	  generate caps for ATRAC3 audio streams
+
+2004-10-06  Stephane Loeuillet  <stephane.loeuillet@tiscali.fr>
+
+	* gst/wavparse/Makefile.am
+	* gst/wavparse/riff.h
+	* gst/wavparse/wavparse.vcproj
+	  riff.h removal (unused and duplication with riff-ids.h)
+
+2004-10-06  Stephane Loeuillet  <stephane.loeuillet@tiscali.fr>
+
+	* gst/wavparse/gstwavparse.h
+	  remove duplicated defines for audio codec codes
+
+	* gst-libs/gst/riff/riff-ids.h
+	* gst/wavenc/riff.h:
+	  add "4CC" code for ATRAC3 audio streams
+	  add "4CC" code for ITU_G721_ADPCM (unused for now)
+
+2004-10-06  Wim Taymans  <wim@fluendo.com>
+
+	* gst/flx/gstflxdec.c: (gst_flxdec_init), (gst_flxdec_loop):
+	Actually _do_ negotiation. Pass gdouble as arg instead
+	of guint64 for the framerate.
+
+2004-10-06  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_init),
+	(find_compatibles), (close_pad_link), (try_to_link_1),
+	(no_more_pads), (close_link), (type_found):
+	* gst/playback/gstplaybasebin.c: (new_decoded_pad):
+	* gst/playback/gstplaybin.c: (gen_video_element),
+	(gen_audio_element):
+	Set state on newly added element to READY so that negotiation
+	can happen ASAP.
+	Addes some more debug info.
+	Do not try to plug pads with multiple caps structures or ANY
+	because it is too dangerous since we do not do dynamic
+	replugging.
+
+2004-10-06  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	written by: Gora Mohanty <gora_mohanty@yahoo.co.in>
+
+	* po/LINGUAS:
+	* po/or.po:
+	  add Oriya translation
+
+2004-10-05  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_massage_index):
+	  Prevent overwrite of size member. Makes audio sound crappy.
+
+2004-10-05  Stephane Loeuillet  <stephane.loeuillet@tiscali.fr>
+
+	* gst/typefind/gsttypefindfunctions.c: (plugin_init):
+	Add rmvb to the list of known RealMedia extensions
+
+2004-10-05  Wim Taymans  <wim@fluendo.com>
+
+	* ext/libmng/gstmngdec.c: (gst_mngdec_loop), (mngdec_error),
+	(mngdec_openstream), (mngdec_closestream),
+	(mngdec_handle_sink_event), (mngdec_readdata),
+	(mngdec_gettickcount), (mngdec_settimer), (mngdec_processheader),
+	(mngdec_getcanvasline), (mngdec_refresh),
+	(gst_mngdec_change_state):
+	Set the framerate correctly.
+
+2004-10-04  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_massage_index):
+	  There was something wrong with the index massaging.
+
+2004-10-04  Wim Taymans  <wim@fluendo.com>
+
+	* ext/jpeg/gstjpeg.c: (smoke_type_find), (plugin_init):
+	* ext/jpeg/gstsmokedec.c: (gst_smokedec_init),
+	(gst_smokedec_chain):
+	* ext/jpeg/gstsmokedec.h:
+	* ext/jpeg/gstsmokeenc.c: (gst_smokeenc_class_init),
+	(gst_smokeenc_init), (gst_smokeenc_resync), (gst_smokeenc_chain):
+	* ext/jpeg/gstsmokeenc.h:
+	* ext/jpeg/smokecodec.c: (smokecodec_encode_new),
+	(smokecodec_decode_new), (smokecodec_info_free),
+	(smokecodec_set_quality), (smokecodec_get_quality),
+	(smokecodec_set_threshold), (smokecodec_get_threshold),
+	(smokecodec_set_bitrate), (smokecodec_get_bitrate),
+	(find_best_size), (abs_diff), (put), (smokecodec_encode_id),
+	(smokecodec_encode), (smokecodec_parse_id),
+	(smokecodec_parse_header), (smokecodec_decode):
+	* ext/jpeg/smokecodec.h:
+	* ext/jpeg/smokeformat.h:
+	Updated smoke, new bitstream, allows embedding in ogg.
+
+2004-10-04  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_event):
+	  Fix seeking in some files. All this code is no longer needed (and
+	  actually breaks stuff) because we now synchronize the full index
+	  right when reading the header.
+
+2004-10-04  Wim Taymans  <wim@fluendo.com>
+
+	* configure.ac:
+	configure update for libmng.
+
+2004-10-04  Wim Taymans  <wim@fluendo.com>
+
+	* ext/libmng/Makefile.am:
+	* ext/libmng/gstmng.c: (plugin_init):
+	* ext/libmng/gstmng.h:
+	* ext/libmng/gstmngdec.c: (gst_mngdec_get_type),
+	(gst_mngdec_base_init), (gst_mngdec_class_init),
+	(gst_mngdec_sinklink), (gst_mngdec_init), (gst_mngdec_src_getcaps),
+	(gst_mngdec_loop), (gst_mngdec_get_property),
+	(gst_mngdec_set_property), (mngdec_error), (mngdec_openstream),
+	(mngdec_closestream), (mngdec_handle_sink_event),
+	(mngdec_readdata), (mngdec_gettickcount), (mngdec_settimer),
+	(mngdec_processheader), (mngdec_getcanvasline), (mngdec_refresh),
+	(gst_mngdec_change_state):
+	* ext/libmng/gstmngdec.h:
+	* ext/libmng/gstmngenc.c: (gst_mngenc_get_type),
+	(mng_caps_factory), (raw_caps_factory), (gst_mngenc_base_init),
+	(gst_mngenc_class_init), (gst_mngenc_sinklink), (gst_mngenc_init),
+	(gst_mngenc_chain), (gst_mngenc_get_property),
+	(gst_mngenc_set_property):
+	* ext/libmng/gstmngenc.h:
+	Added basic MNG decoder. Needs more work. The encoder does
+	not work yet.
+
+2004-10-04  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/realmedia/rmdemux.c: (gst_rmdemux_handle_sink_event),
+	(gst_rmdemux_loop), (gst_rmdemux_add_stream),
+	(gst_rmdemux_parse_mdpr), (gst_rmdemux_dump_mdpr):
+	  Don't hang on length=0 chunks. Some negotiation fixes. Signal
+	  no-more-pads.
+
+2004-10-04  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	  you need at least 1.0.4 of speex
+
+2004-10-04 Iain <iaingnome@gmail.com>
+
+	* ext/speex/gstspeexdec.h: Revert the includes changes.
+
+	* ext/speex/gstspeexenc.[ch]: Revert the includes changes.
+
+2004-09-30 Iain <iaingnome@gmail.com>
+
+	* sys/sunaudio/gstsunaudio.c (gst_sunaudiosink_open): Use the device
+	found during init or set as a property instead of hardcoding /dev/audio
+
+2004-10-04  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/realmedia/rmdemux.c: (gst_rmdemux_class_init),
+	(gst_rmdemux_init), (gst_rmdemux_handle_sink_event),
+	(gst_rmdemux_loop), (gst_rmdemux_add_stream), (re_hexdump_bytes),
+	(re_dump_pascal_string), (gst_rmdemux_dump__rmf),
+	(gst_rmdemux_dump_prop), (gst_rmdemux_parse_mdpr),
+	(gst_rmdemux_dump_mdpr), (gst_rmdemux_dump_indx),
+	(gst_rmdemux_dump_data):
+	  Use debug category, fix EOS handling. filesrc ! rmdemux now
+	  works.
+
+2004-10-04  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_stream_index),
+	(gst_avi_demux_stream_scan), (sort), (gst_avi_demux_massage_index),
+	(gst_avi_demux_stream_header), (gst_avi_demux_stream_data):
+	  Improve allocation, cutting and sorting of the index. How takes a
+	  few seconds instead of minutes.
+
+2004-10-03  Christophe Fergeau  <teuf@gnome.org>
+
+	* gst/realmedia/rmdemux.c: (gst_rmdemux_parse_mdpr):
+	  fixed compilation
+
+2004-10-02  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_video_caps_with_data),
+	(gst_riff_create_video_template_caps):
+	  Add wing commander format mimetype/fourccs.
+	* gst/avi/gstavidemux.c: (gst_avi_demux_massage_index):
+	  Don't crash if some value is 0.
+
+2004-10-02  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_video_caps_with_data),
+	(gst_riff_create_video_template_caps):
+	  Add DIB fourcc (raw, palettized 8-bit RGB).
+	* gst-libs/gst/riff/riff-read.c:
+	(gst_riff_read_strf_vids_with_data):
+	  Oops, fix strf_data reading bug.
+	* gst/avi/gstavidemux.c: (gst_avi_demux_add_stream):
+	  Use a non-NULL tag.
+	* gst/qtdemux/qtdemux.c: (qtdemux_parse_trak):
+	  Time for hacks. Sorry Dave. At least one quicktime movie (a
+	  trailer) that I've encountered contains multiple video tracks.
+	  One of those is the actual video track, the other are one-frame
+	  tracks (images). Unfortunately, the number of frames according
+	  to the trak header is 1 for each, so that doesn't help. So
+	  instead, I look at the duration and discard tracks with a
+	  duration shorter than 20% of the length of the stream. Better
+	  than nothing.
+
+2004-10-01  Christian Schaller <christian@fluendo.com>
+
+	* ext/ivorbis/vorbis.c:
+	  Patch from Phil Blundell (Bug 152341)
+
+2004-10-01  Wim Taymans  <wim@fluendo.com>
+
+	* ext/speex/gstspeexdec.c: (gst_speex_dec_class_init),
+	(speex_dec_get_formats), (speex_dec_convert),
+	(speex_dec_src_query), (speex_dec_src_event), (speex_dec_event),
+	(speex_dec_chain), (gst_speexdec_get_property),
+	(gst_speexdec_set_property):
+	Small cleanups.
+
+2004-10-01  Wim Taymans  <wim@fluendo.com>
+
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_class_init),
+	(gst_wavparse_stream_init), (gst_wavparse_fmt),
+	(gst_wavparse_other), (gst_wavparse_loop),
+	(gst_wavparse_pad_convert), (gst_wavparse_pad_query),
+	(gst_wavparse_srcpad_event):
+	* gst/wavparse/gstwavparse.h:
+	Added some more debugging info.
+	Fix the case where the length of the file is 0.
+	Make sure we seek to sample borders.
+
+2004-10-01  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/README:
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_factory_filter),
+	(gst_decode_bin_init), (find_compatibles), (close_pad_link),
+	(try_to_link_1), (no_more_pads), (close_link), (type_found):
+	Add some debug info to decodebin, update README
+
+2004-10-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/dvdnav/dvdnavsrc.c: (dvdnav_handle_navigation_event):
+	  Don't use g_print(); use GST_DEBUG().
+
+2004-10-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_next_buffer),
+	(gst_ogg_mux_queue_pads):
+	  Handle EOS properly.
+
+2004-10-01  Sebastien Cote  <sc5@hermes.usherb.ca>
+
+	Reviewed by: Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/faad/gstfaad.c: (gst_faad_init), (gst_faad_sinkconnect),
+	(gst_faad_chain), (gst_faad_change_state):
+	* ext/faad/gstfaad.h:
+	  Allow playback of raw (unframed) MPEG AAC files (#148993).
+
+2004-10-01  Sebastien Cote  <sc5@hermes.usherb.ca>
+
+	Reviewed by: Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_fmt):
+	  Throw error if we didn't recognize the stream. Fixes #152289.
+
+2004-10-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/videoscale/gstvideoscale.c: (gst_videoscale_link):
+	  Fix negotiation.
+
+2004-10-01  Francis Labonte  <francis_labonte@hotmail.com>
+
+	Reviewed by: Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_fmt):
+	  Fix memleak.
+
+2004-10-01  Balamurali Viswanathan  <balamurali.viswanathan@wipro.com>
+
+	Reviewed by: Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/sunaudio/gstsunaudio.c: (gst_sunaudiosink_setparams):
+	  Solve #152805.
+	* sys/sunaudio/gstsunmixer.c: (gst_sunaudiomixer_set_mute):
+	  Solve 152806.
+
+2004-10-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_video_caps_with_data),
+	(gst_riff_create_audio_caps_with_data):
+	  Add codec_data handling (like asfdemux used to do).
+	* gst/asfdemux/gstasf.c: (plugin_init):
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_base_init),
+	(gst_asf_demux_add_audio_stream), (gst_asf_demux_add_video_stream):
+	  Use riff-media for caps creation instead of our own (mostly
+	  broken) copy of its functions.
+
+2004-10-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l/v4lsrc_calls.c: (gst_v4lsrc_try_capture):
+	  Don't actually error out if we get another return value than
+	  -EINVAL. Opposite to what I first thought, drivers have random
+	  return values for this, although -EINVAL is the expected return
+	  value. Since this is not fatal, we shouldn't use
+	  GST_ELEMENT_ERROR() but just GST_ERROR_OBJECT().
+
+2004-10-01  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/dvdread/dvdreadsrc.c: (dvdreadsrc_class_init),
+	(dvdreadsrc_init), (dvdreadsrc_dispose), (dvdreadsrc_set_property),
+	(dvdreadsrc_get_property), (_open), (_seek), (_read),
+	(dvdreadsrc_get), (dvdreadsrc_open_file),
+	(dvdreadsrc_change_state):
+	  Fix. Don't do one big huge loop around the whole DVD, that will
+	  cache all data and thus eat sizeof(dvd) (several GB) before we
+	  see something.
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_read_seek):
+	  Actually NULL'ify event after using it.
+	* gst/matroska/ebml-read.c: (gst_ebml_read_use_event),
+	(gst_ebml_read_handle_event), (gst_ebml_read_element_id),
+	(gst_ebml_read_element_length), (gst_ebml_read_element_data),
+	(gst_ebml_read_seek), (gst_ebml_read_skip):
+	  Handle events.
+	* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_base_init),
+	(gst_dvd_demux_init), (gst_dvd_demux_get_audio_stream),
+	(gst_dvd_demux_get_subpicture_stream), (gst_dvd_demux_plugin_init):
+	  Fix timing (this will probably break if I seek using menus, but
+	  I didn't get there yet). VOBs and normal DVDs should now work.
+	  Add a mpeg2-only pad with high rank so this get autoplugged for
+	  MPEG-2 movies.
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_base_init),
+	(gst_mpeg_demux_class_init), (gst_mpeg_demux_init),
+	(gst_mpeg_demux_new_output_pad), (gst_mpeg_demux_get_video_stream),
+	(gst_mpeg_demux_get_audio_stream),
+	(gst_mpeg_demux_get_private_stream), (gst_mpeg_demux_parse_packet),
+	(gst_mpeg_demux_parse_pes), (gst_mpeg_demux_plugin_init):
+	  Use this as second rank for MPEG-1 and MPEG-2. Still use this for
+	  MPEG-1 but use dvddemux for MPEG-2.
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_class_init),
+	(gst_mpeg_parse_init), (gst_mpeg_parse_new_pad),
+	(gst_mpeg_parse_parse_packhead):
+	  Timing. Only add pad template if it exists. Add sink template from
+	  class and not from ourselves. This means we will always use the
+	  correct sink template even if it is not the one defined in this
+	  file.
+
+2004-09-29  Wim Taymans  <wim@fluendo.com>
+
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_parse_packet),
+	(gst_mpeg_demux_parse_pes):
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_parse_packhead):
+	Fix playback of mpeg again, timestamps where screwed up by
+	patch 1.61.
+
+2004-09-29  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/flac/gstflacdec.c: (gst_flacdec_src_query):
+	  Only return true if we actually filled something in. Prevents
+	  player applications from showing a random length for flac files.
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_read_class_init),
+	(gst_riff_read_use_event), (gst_riff_read_handle_event),
+	(gst_riff_read_seek), (gst_riff_read_skip), (gst_riff_read_strh),
+	(gst_riff_read_strf_vids_with_data),
+	(gst_riff_read_strf_auds_with_data), (gst_riff_read_strf_iavs):
+	  OK, ok, so I implemented event handling. Apparently it's normal
+	  that we receive random events at random points without asking
+	  for it.
+	* gst/avi/gstavidemux.c: (gst_avi_demux_reset),
+	(gst_avi_demux_src_convert), (gst_avi_demux_handle_src_query),
+	(gst_avi_demux_handle_src_event), (gst_avi_demux_stream_index),
+	(gst_avi_demux_sync), (gst_avi_demux_stream_scan),
+	(gst_avi_demux_massage_index), (gst_avi_demux_stream_header),
+	(gst_avi_demux_handle_seek), (gst_avi_demux_process_next_entry),
+	(gst_avi_demux_stream_data), (gst_avi_demux_loop):
+	* gst/avi/gstavidemux.h:
+	  Implement non-lineair chunk handling and subchunk processing.
+	  The first solves playback of AVI files where the audio and video
+	  data of individual buffers that we read are not synchronized.
+	  This should not happen according to the wonderful AVI specs, but
+	  of course it does happen in reality. It is also a prerequisite for
+	  the second. Subchunk processing allows us to cut chunks in small
+	  pieces and process each of these pieces separately. This is
+	  required because I've seen several AVI files with incredibly large
+	  audio chunks, even some files with only one audio chunk for the
+	  whole file. This allows for proper playback including seeking.
+	  This patch is supposed to fix all AVI A/V sync issues.
+	* gst/flx/gstflxdec.c: (gst_flxdec_class_init),
+	(flx_decode_chunks), (flx_decode_color), (gst_flxdec_loop):
+	  Work.
+	* gst/modplug/gstmodplug.cc:
+	  Proper return value setting for the query() function.
+	* gst/playback/gstplaybasebin.c: (setup_source):
+	  Being in non-playing state (after, e.g., EOS) is not necessarily
+	  a bad thing. Allow for that. This fixes playback of short files.
+	  They don't actually playback fully now, because the clock already
+	  runs. This means that small files (<500kB) with a small length
+	  (<2sec) will still not or barely play. Other files, such as mod
+	  or flx, will work correctly, however.
+
+2004-09-28  Wim Taymans  <wim@fluendo.com>
+
+	* ext/speex/gstspeex.c: (plugin_init):
+	* ext/speex/gstspeexdec.c: (gst_speex_dec_base_init),
+	(gst_speex_dec_class_init), (speex_dec_get_formats),
+	(speex_get_event_masks), (speex_get_query_types),
+	(gst_speex_dec_init), (speex_dec_convert), (speex_dec_src_query),
+	(speex_dec_src_event), (speex_dec_event), (speex_dec_chain),
+	(gst_speexdec_get_property), (gst_speexdec_set_property),
+	(speex_dec_change_state):
+	* ext/speex/gstspeexdec.h:
+	* ext/speex/gstspeexenc.c: (gst_speexenc_get_formats),
+	(gst_speexenc_get_type), (speex_caps_factory), (raw_caps_factory),
+	(gst_speexenc_base_init), (gst_speexenc_class_init),
+	(gst_speexenc_sinkconnect), (gst_speexenc_convert_src),
+	(gst_speexenc_convert_sink), (gst_speexenc_get_query_types),
+	(gst_speexenc_src_query), (gst_speexenc_init),
+	(gst_speexenc_get_tag_value), (comment_init), (comment_add),
+	(gst_speexenc_metadata_set1), (gst_speexenc_set_metadata),
+	(gst_speexenc_setup), (gst_speexenc_buffer_from_data),
+	(gst_speexenc_push_buffer), (gst_speexenc_set_header_on_caps),
+	(gst_speexenc_chain), (gst_speexenc_get_property),
+	(gst_speexenc_set_property), (gst_speexenc_change_state):
+	* ext/speex/gstspeexenc.h:
+	Rewrote speex encoder, make sure it can be embedded in ogg.
+	Implemented speex decoder.
+
+2004-09-28  Christian Schaller <christian@fluendo.com>
+
+	* configure.ac:
+	Remove kioslave plugin. Markey is brewing a new working one
+	* ext/Makefile.am: Remove kioslave plugin
+	* ext/kio: remove
+	* gst-plugins.spec.in: remove kio plugin from spec
+
+2004-09-27  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_add),
+	(gst_multifdsink_remove), (gst_multifdsink_remove_client_link),
+	(is_sync_frame), (gst_multifdsink_client_queue_buffer),
+	(gst_multifdsink_new_client),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_recover_client), (gst_multifdsink_queue_buffer),
+	(gst_multifdsink_handle_clients):
+	* gst/tcp/gstmultifdsink.h:
+	Make syncing to keyframes actually work for new clients and lagging
+	clients.
+
+2004-09-26  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/debug/gstnavigationtest.c: (gst_navigationtest_class_init),
+	(gst_navigationtest_handle_src_event), (draw_box_planar411),
+	(gst_navigationtest_planar411), (gst_navigationtest_change_state):
+	* gst/debug/gstnavigationtest.h:
+	  make navigationtest display button-press and button-release events
+
+2004-09-26 Iain <iaingnome@gmail.com>
+
+	* gst/interleave/interleave.c (all_channels_new_media): Checks if all
+	the channels have received a new media event.
+	(interleave_buffered_loop): Compresses a new media event on all
+	channels into one.
+
+2004-09-26 Iain <iaingnome@gmail.com>
+
+	* gst/wavenc/gstwavenc.c (gst_wavenc_chain): Company says we need to
+	call the sinkpad's default event handler and not the srcpads. He also
+	says this is confusing :)
+	(gst_wavenc_stop_file): Company says that seek events only go upstream
+	we should send a discontinuous downstream instead.
+
+2004-09-25  Christian Schaller <christian@fluendo.com>
+
+	* Update SPEC file to be usable in conjunction with Fedora Core,
+	  Fedora.us and freshrpms packages
+	* Fix typo in multifilesrc test Makefile
+
+2004-09-24  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstplaybasebin.c: (new_decoded_pad):
+	Only signal the no_more_pads signal when we have
+	added the stream to our list.
+
+2004-09-24  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstplaybasebin.c: (remove_prerolls),
+	(new_decoded_pad):
+	* gst/playback/gstplaybasebin.h:
+	* gst/playback/gstplaybin.c: (setup_sinks):
+	Don't try to preroll or decode more than one audio/video
+	track.
+
+2004-09-24  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_change_state):
+	  Throw error if we failed to find a suitable output. This should
+	  throw an error if we successfully set up a pipeline (e.g. because
+	  we recognized a media file) but found no decodable streams in it
+	  (e.g. because it contains only media stream types for which we
+	  have no decoders, or because it's not a media type).
+
+2004-09-23  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/dirac/Makefile.am:
+	* ext/dirac/gstdirac.cc:
+	* ext/dirac/gstdiracdec.cc:
+	* ext/dirac/gstdiracdec.h:
+	  Do something. Don't actually know if this works because I don't
+	  have a demuxer yet.
+	* ext/gsm/gstgsmdec.c: (gst_gsmdec_getcaps):
+	  Add channels=1 to caps returned from _getcaps().
+	* ext/ogg/gstogmparse.c: (gst_ogm_audio_parse_get_type),
+	(gst_ogm_video_parse_get_type), (gst_ogm_audio_parse_base_init),
+	(gst_ogm_video_parse_base_init), (gst_ogm_parse_init),
+	(gst_ogm_audio_parse_init), (gst_ogm_video_parse_init),
+	(gst_ogm_parse_sink_convert), (gst_ogm_parse_chain),
+	(gst_ogm_parse_change_state):
+	  Separate between audio/video so ogmaudioparse actually uses the
+	  audio pad templates. Both audio and video work now, including
+	  autoplugging. Also use sometimes-srcpad hack.
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_read_seek):
+	  Handle events better. Don't hang on infinite loops.
+	* gst/avi/gstavidemux.c: (gst_avi_demux_class_init),
+	(gst_avi_demux_init), (gst_avi_demux_reset),
+	(gst_avi_demux_src_convert), (gst_avi_demux_handle_src_query),
+	(gst_avi_demux_stream_header), (gst_avi_demux_stream_data),
+	(gst_avi_demux_change_state):
+	* gst/avi/gstavidemux.h:
+	  Improve A/V sync. Still not perfect.
+	* gst/matroska/ebml-read.c: (gst_ebml_read_seek),
+	(gst_ebml_read_skip):
+	  Handle events better.
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_handle_sink_event),
+	(gst_qtdemux_loop_header), (qtdemux_parse_trak),
+	(qtdemux_audio_caps):
+	  Add IMA4. Improve event handling. Save offset after a seek when
+	  the headers are at the end of the file so that we don't end up in
+	  an infinite loop.
+	* gst/typefind/gsttypefindfunctions.c: (qt_type_find):
+	  Add low-priority typefind support for files with no length.
+
+2004-09-23  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* testsuite/multifilesink/Makefile.am:
+	fix typo
+
+2004-09-22  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_ximage_destroy):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_check_xshm_calls): Fix
+	mistakes from thaytan's patches.
+
+2004-09-23  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_ximage_destroy):
+	  For completeness, XSync in the destroy function as xvimage does.
+
+2004-09-23  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/gdk_pixbuf/pixbufscale.c: (gst_pixbufscale_getcaps):
+	   Correct caps negotiation
+	* gst/volume/gstvolume.c: (volume_chain_float),
+	(volume_chain_int16):
+	   Modify debug output to be little more informative
+	* sys/ximage/ximagesink.c: (gst_ximagesink_check_xshm_calls):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_check_xshm_calls),
+	(gst_xvimagesink_xvimage_destroy):
+	  Add XSync calls after detaching from the shared memory segment to
+	  avoid a crash.
+
+2004-09-22  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_init),
+	(gst_ogg_mux_next_buffer), (gst_ogg_mux_loop):
+	* ext/vorbis/vorbis.c: (plugin_init):
+	* ext/vorbis/vorbisenc.c: (gst_vorbisenc_init),
+	(gst_vorbisenc_chain):
+	* ext/vorbis/vorbisenc.h:
+	remove explicit newmedia support from oggmux and vorbisenc
+	add debug category to vorbisenc
+	* gst/multifilesink/gstmultifilesink.c:
+	(gst_multifilesink_class_init), (gst_multifilesink_init),
+	(gst_multifilesink_dispose), (gst_multifilesink_set_location),
+	(gst_multifilesink_set_property), (gst_multifilesink_next_file),
+	(gst_multifilesink_handle_event), (gst_multifilesink_chain),
+	(plugin_init):
+	* gst/multifilesink/gstmultifilesink.h:
+	add support for streamheader in multifilesink
+
+2004-09-22  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/asfdemux/gstasfdemux.c: (_read_var_length), (_read_guid),
+	(gst_asf_demux_process_segment), (gst_asf_demux_handle_data),
+	(gst_asf_demux_process_chunk), (gst_asf_demux_handle_sink_event):
+	  Prevent infinite loops. More correct error reporting.
+	* gst/auparse/gstauparse.c: (gst_auparse_chain):
+	  Error out if negotiation fails.
+	* gst/playback/gstplaybasebin.c: (setup_source),
+	(gst_play_base_bin_change_state), (gst_play_base_bin_error),
+	(gst_play_base_bin_found_tag):
+	  Error/tag forwarding. Pre-roll fixes for source errors on state
+	  changes (e.g. "file does not exist") to prevent hangs.
+
+2004-09-21  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* testsuite/multifilesink/Makefile.am:
+	* testsuite/multifilesink/lame_test.c: (gst_newmedia_base_init),
+	(gst_newmedia_class_init), (gst_newmedia_init),
+	(gst_newmedia_chain), (gst_newmedia_trigger), (test_format),
+	(newfile_signal), (test_signal), (main):
+	* testsuite/multifilesink/multifilesrc_test.c: (main):
+	* testsuite/multifilesink/oggtheora_test.c:
+	(gst_newmedia_base_init), (gst_newmedia_class_init),
+	(gst_newmedia_init), (gst_newmedia_chain), (gst_newmedia_trigger),
+	(test_format), (newfile_signal), (test_signal), (main):
+	* testsuite/multifilesink/oggvorbis_test.c:
+	(gst_newmedia_base_init), (gst_newmedia_class_init),
+	(gst_newmedia_init), (gst_newmedia_chain), (gst_newmedia_trigger),
+	(test_format), (newfile_signal), (test_signal), (main):
+	* testsuite/multifilesink/wavenc_test.c: (gst_newmedia_base_init),
+	(gst_newmedia_class_init), (gst_newmedia_init),
+	(gst_newmedia_chain), (gst_newmedia_trigger), (test_format),
+	(newfile_signal), (test_signal), (main):
+	New media tests
+
+2004-09-20  Christian Schaller <christian@fluendo.com>
+
+	* Fix mikmod license to LGPL as they have relicensed
+	* Move Dirac and Effectv into LGPL section of README_license
+
+2004-09-20  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mad/gstmad.c: (gst_mad_check_caps_reset),
+	(gst_mad_change_state):
+	  Allow for mp3 rate/channels changes. However, only very
+	  conservatively. Reason that we *have* to enable this is smiply
+	  because the mad find_sync() function is not good enough, it will
+	  regularly sync on random data as valid frames and therefore make
+	  us provide random caps as *final* caps of the stream. The best fix
+	  I could think of is to simply require several of the same stream
+	  changes in a row before we change caps.
+	  The actual testcase that works now is #
+	* ext/ogg/Makefile.am:
+	* ext/ogg/gstogg.c: (plugin_init):
+	* ext/ogg/gstogmparse.c:
+	  OGM support (video only for now; I need an audio sample file).
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_base_init),
+	(gst_asf_demux_process_stream), (gst_asf_demux_video_caps),
+	(gst_asf_demux_add_video_stream):
+	  WMV extradata.
+	* gst/playback/gstplaybasebin.c: (unknown_type):
+	  Don't error out on single unknown-types after all. It's wrong.
+	  If we found type of video and audio but not of a subtitle stream,
+	  it will still error out (which is unwanted). Will find a better fix
+	  later on.
+	* gst/typefind/gsttypefindfunctions.c: (ogmvideo_type_find),
+	(ogmaudio_type_find), (plugin_init):
+	  OGM support.
+
+2004-09-20  Johan Dahlin  <johan@gnome.org>
+
+	* ext/jpeg/gstjpegdec.c (gst_jpegdec_chain): Allocate the buffer
+	after setting caps.
+
+2004-09-19  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* gst/wavenc/gstwavenc.c: (gst_wavenc_init), (gst_wavenc_chain):
+	* gst/wavenc/gstwavenc.h:
+	Added newmedia support to wavenc
+
+2004-09-17  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstfdset.c: (gst_fdset_fd_has_closed),
+	(gst_fdset_fd_has_error), (gst_fdset_fd_can_read),
+	(gst_fdset_fd_can_write), (gst_fdset_wait):
+	* gst/tcp/gstmultifdsink.c: (gst_client_status_get_type),
+	(gst_multifdsink_init), (gst_multifdsink_add),
+	(gst_multifdsink_remove), (gst_multifdsink_get_stats),
+	(gst_multifdsink_remove_client_link),
+	(gst_multifdsink_client_queue_buffer),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_recover_client), (gst_multifdsink_handle_clients),
+	(gst_multifdsink_close), (gst_multifdsink_change_state):
+	* gst/tcp/gstmultifdsink.h:
+	* gst/tcp/gsttcpserversink.c: (gst_tcpserversink_class_init),
+	(gst_tcpserversink_removed):
+	Small cleanups in fdset.c
+	Use a hastable to map fd to the client structure for faster
+	lookup in _remove and get_stats.
+	Added virtual function to close the fds.
+	Handle clients even when the select/poll call was unblocked because
+	of a command.
+	Implement syncing to keyframe in the recovery procedure.
+
+2004-09-16 Iain <iaingnome@gmail.com>
+
+	* gst/audioconvert/gstaudioconvert.c (_fixate_caps_to_int): Free the
+	try caps.
+
+2004-09-15  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_get_audio_stream):
+	  Caps are only set if the type of the stream is unknown, but this
+	  is initialized in ->init_stream(), so set to UNKNOWN after calling
+	  ->init_stream() so that capsnego starts.
+
+2004-09-15  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query),
+	(gst_avi_demux_stream_data):
+	  Just hardcode for raw audio then. AVI audio sucks.
+
+2004-09-15  Arwed v. Merkatz  <v.merkatz@gmx.net>
+
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_audio_caps):
+	* gst/matroska/matroska-mux.c: (audiosink_templ),
+	(gst_matroska_mux_audio_pad_link):
+	* gst/typefind/gsttypefindfunctions.c: (tta_caps), (plugin_init):
+	Use audio/x-ttafile for tta files and audio/x-tta for raw tta frames.
+
+2004-09-15  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query),
+	(gst_avi_demux_stream_data):
+	  Try to fix a/v sync issues.
+
+2004-09-15  David Schleef  <ds@schleef.org>
+
+	* configure.ac: remove NASM check, since we don't use it.  Update
+	dirac check to 0.4
+	* ext/dirac/gstdiracdec.cc: update to current 0.4 API
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_link):
+	Initialized variables.
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_change_state),
+	(gst_qtdemux_loop_header), (qtdemux_parse), (qtdemux_parse_trak),
+	(gst_qtdemux_handle_esds), (qtdemux_audio_caps): Fix seeking, add
+	SVQ3 format
+
+2004-09-15  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query),
+	(gst_avi_demux_add_stream), (gst_avi_demux_stream_data):
+	* gst/avi/gstavidemux.h:
+	  Fix for compressed audio (mp3) timestamp generation. How did this
+	  ever work?
+
+2004-09-15  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybin.c: (gst_play_bin_get_property):
+	  Volume is a double not a float.
+
+2004-09-15  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_remove_client_link),
+	(gst_multifdsink_handle_clients), (gst_multifdsink_change_state):
+	Don't close the fd in multifdsink as we didn't open it in the
+	first place. Some cleanups.
+
+2004-09-15  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_pad_push):
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_next_buffer),
+	(gst_ogg_mux_send_headers), (gst_ogg_mux_loop):
+	Fix the case where the muxer would mark pages as delta
+	frames when they are not (vorbis only ogg).
+
+2004-09-15  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c: (state_change), (setup_source),
+	(gst_play_base_bin_change_state):
+	  Handle the case where we failed to setup a clear pipeline. This
+	  will throw an error (or EOS, another nice case) and if you don't
+	  catch that, the app will wait for the signal forever (and thus
+	  hang).
+
+2004-09-15  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/gnomevfs/gstgnomevfssink.c:
+	(gst_gnomevfssink_uri_get_protocols):
+	* ext/gnomevfs/gstgnomevfssrc.c:
+	(gst_gnomevfssrc_uri_get_protocols):
+	* ext/gnomevfs/gstgnomevfsuri.c: (gst_gnomevfs_get_supported_uris):
+	* ext/gnomevfs/gstgnomevfsuri.h:
+	  Use _uri_new() instead of _open(), so it doesn't take as long and
+	  Christophe's computer won't hang.
+	* gst/playback/gstplaybasebin.c: (unknown_type):
+	  Throw error on unknown media type, so apps actually display it.
+
+2004-09-14  Brian Cameron  <brian.cameron@sun.com
+
+	* tools/gst-launch-ext-m.m:  Changed ~ to $ENV{HOME} to allow
+	  this script to work on Solaris since bash shell handles echo
+	  differenly than bash.
+
+2004-09-17  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstplaybasebin.c: (queue_overrun), (no_more_pads),
+	(setup_source), (gst_play_base_bin_set_property),
+	(gst_play_base_bin_add_element):
+	* gst/playback/gstplaybin.c: (gst_play_bin_send_event):
+	Some more work on making sure seeking pauses the pipeline and
+	that changing the uri actually does something.
+
+2004-09-17  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstfdset.c: (gst_fdset_wait):
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_close):
+	* gst/tcp/gsttcpserversink.c: (gst_tcpserversink_init_send),
+	(gst_tcpserversink_close):
+	Be a bit more paranoid when freeing memory.
+
+2004-09-13  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_add_stream),
+	(qtdemux_parse_trak):
+	  Don't crash by dividing by zero (see sample movie in #126922).
+
+2004-09-13  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/qtdemux/qtdemux.c: (qtdemux_audio_caps):
+	  Don't touch non-existing data (fixes crash on file in #140147).
+
+2004-09-13  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/playback/gstplaybasebin.c:
+	(gst_play_base_bin_dispose), (gst_play_base_bin_set_property):
+	  Handle double disposals, and proper change of URIs.
+
+2004-09-13  Martin Eikermann <meiker@upb.de>
+
+	* gst/mpegstream/gstmpegparse.c:
+	  fix synchronistation for streams recorded from digital PCR
+	  fixes bug #119376
+
+2004-09-13  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/gnomevfs/Makefile.am:
+	* ext/gnomevfs/gstgnomevfs.c: (plugin_init):
+	* ext/gnomevfs/gstgnomevfssink.c: (gst_gnomevfssink_get_type),
+	(gst_gnomevfssink_dispose), (gst_gnomevfssink_init),
+	(gst_gnomevfssink_uri_get_type),
+	(gst_gnomevfssink_uri_get_protocols),
+	(gst_gnomevfssink_uri_get_uri), (gst_gnomevfssink_uri_set_uri),
+	(gst_gnomevfssink_uri_handler_init),
+	(gst_gnomevfssink_set_property), (gst_gnomevfssink_get_property),
+	(gst_gnomevfssink_open_file), (gst_gnomevfssink_close_file):
+	* ext/gnomevfs/gstgnomevfssrc.c: (gst_gnomevfssrc_get_type),
+	(gst_gnomevfssrc_init), (gst_gnomevfssrc_dispose),
+	(gst_gnomevfssrc_uri_get_type),
+	(gst_gnomevfssrc_uri_get_protocols), (gst_gnomevfssrc_uri_get_uri),
+	(gst_gnomevfssrc_uri_set_uri), (gst_gnomevfssrc_uri_handler_init),
+	(gst_gnomevfssrc_set_property), (gst_gnomevfssrc_get_property),
+	(gst_gnomevfssrc_open_file), (gst_gnomevfssrc_close_file):
+	* ext/gnomevfs/gstgnomevfsuri.c: (gst_gnomevfs_get_supported_uris):
+	* ext/gnomevfs/gstgnomevfsuri.h:
+	  Add URI support to Gnome-VFS plugins. Tries to load a fixed list
+	  of fake URIs to see which this version of Gnome-VFS likes, and
+	  uses that for the Gst-URI interface. Makes playbin support http://
+	  streams. Also fix up some stupid behaviour in gnomevfssrc.
+
+2004-09-13  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_update),
+	(gst_alsa_mixer_get_volume), (gst_alsa_mixer_set_volume),
+	(gst_alsa_mixer_set_mute), (gst_alsa_mixer_set_record),
+	(gst_alsa_mixer_set_option), (gst_alsa_mixer_get_option):
+	  Update mixer (to sync with other sessions) if we try to obtain
+	  a new value. This makes alsamixer work accross applications.
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_get_time):
+	  Only call sync functions if we're running, else alsalib asserts.
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_src_query):
+	  Sometimes fails to compile. Possibly a gcc bug.
+	* gst/playback/gstplaybin.c: (gen_video_element),
+	(gen_audio_element):
+	  Add a reference to an application-provided object, because we lose
+	  this same reference if we add it to the bin. If we don't do this,
+	  we can only use this object once and thus crash if we go from
+	  ready to playing, back to ready and back to playing again.
+	  Also add an audioscale element because several cheap soundcards -
+	  like mine - don't support all samplerates.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xcontext_get),
+	(gst_ximagesink_xcontext_clear), (gst_ximagesink_change_state):
+	  Fix wrong order or PAR calls. Makes automatically obtained PAR
+	  from the X server atually being used.
+
+2004-09-12  David Schleef  <ds@schleef.org>
+
+	Fixes: #151879, #151881, #151882, #151883, #151884, #151886,
+	#151887, #152102, #152247.
+	* examples/indexing/indexmpeg.c: 64-bit warning fixes.
+	* examples/seeking/cdparanoia.c: same
+	* examples/seeking/cdplayer.c: same
+	* examples/seeking/seek.c: same
+	* examples/seeking/spider_seek.c: same
+	* examples/seeking/vorbisfile.c: same
+	* examples/stats/mp2ogg.c: same
+	* ext/esd/esdsink.c: (gst_esdsink_class_init),
+	(gst_esdsink_dispose): Dispose of element properly.
+	* ext/ivorbis/vorbisfile.c: (gst_ivorbisfile_seek): 64-bit warning
+	fixes.
+	* ext/nas/nassink.c: (gst_nassink_class_init),
+	(gst_nassink_dispose): Dispose of element correctly.
+	* gst/wavenc/gstwavenc.c: (gst_wavenc_chain): Fix leak.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_check_xshm_calls),
+	(gst_ximagesink_ximage_new), (gst_ximagesink_ximage_destroy):
+	Fix 64-bit warning.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_check_xshm_calls),
+	(gst_xvimagesink_xvimage_new), (gst_xvimagesink_xvimage_destroy):
+	Fix 64-bit warning.
+
+2004-09-12  Stephane Loeuillet  <stephane.loeuillet@tiscali.fr>
+
+	* configure.ac : change speex detection as 1.1.6 now uses
+	  .pc/pkg-config and they changed their headers location.
+
+2004-09-09  Arwed v. Merkatz  <v.merkatz@gmx.net>
+
+	* gst/matroska/matroska-mux.h:
+	* gst/matroska/matroska-mux.c: (gst_matroska_mux_reset),
+	(gst_matroska_mux_start), (gst_matroska_mux_finish),
+	(gst_matroska_mux_write_data):
+	  Write multiple blocks/frames per cluster.
+		Write meta-seek information (seek heads).
+
+2004-09-09  Scott Wheeler <wheeler@kde.org>
+
+	* gst/gstplaybin.c: (gst_play_bin_class_init), (gst_play_bin_init),
+	(gst_play_bin_set_property), (gst_play_bin_get_property),
+	(gen_audio_element), (gen_audio_element):
+	  Add a volume element / property to the pipeline.
+
+2004-09-07  Wim Taymans  <wim@fluendo.com>
+
+	* gst/videomixer/videomixer.c: (gst_videomixer_blend_buffers):
+	Copy timestamps from the master pad to the output buffers.
+
+2004-09-03  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/raw1394/gstdv1394src.c:
+	  throw errors when applicable
+
+2004-09-01  Arwed v. Merkatz  <v.merkatz@gmx.net>
+
+	* gst/matroska/ebml-ids.h:
+	* gst/matroska/ebml-read.c: (gst_ebml_read_date):
+	* gst/matroska/ebml-write.c: (gst_ebml_write_date):
+	* gst/matroska/matroska-mux.c: (gst_matroska_mux_finish):
+	  automatically convert unix time <-> ebml time when reading/writing
+	  a date, use gst_ebml_write_uint to write CUETIME,
+	  not gst_ebml_write_date.
+	* gst/matroska/matroska-ids.h:
+	* gst/matroska/matroska-mux.c: (gst_matroska_mux_create_uid),
+	(gst_matroska_mux_reset), (gst_matroska_mux_audio_pad_link),
+	(gst_matroska_mux_track_header), (gst_matroska_mux_start),
+	(gst_matroska_mux_write_data):
+	  Write track and segment UIDs, write muxing date, write
+	  TRACKDEFAULTDURATION for TTA audio, write BLOCKDURATION if known.
+	  Create cues for audio only files.
+
+2004-08-31  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_build_list):
+	* ext/alsa/gstalsamixertrack.c: (gst_alsa_mixer_track_new):
+	  Re-commit ALSA switches.
+	* gst/adder/gstadder.c: (gst_adder_loop):
+	  64-bit fix (#151416).
+	* gst/debug/progressreport.c: (gst_progressreport_report):
+	  64-bit fix (#151419).
+	* gst/matroska/matroska-demux.c:
+	(gst_matroska_demux_parse_contents):
+	  64-bit fix (#151420).
+	* gst/playback/test3.c: (update_scale):
+	  64-bit fix (#151421).
+
+2004-08-31  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	  bump nano to cvs
+
+=== release 0.8.4 ===
+
+2004-08-02  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac: releasing 0.8.4, "Alias"
+
+2004-08-31  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/theora/Makefile.am:
+	  fix makefile.  Fixes #151462.
+
+2004-08-30  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstfdset.c: (gst_fdset_free), (gst_fdset_wait):
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_add),
+	(gst_multifdsink_remove_client_link),
+	(gst_multifdsink_client_queue_buffer),
+	(gst_multifdsink_handle_client_write):
+	* gst/tcp/gsttcpclientsink.c: (gst_tcpclientsink_init_send):
+	* gst/tcp/gsttcpclientsrc.c: (gst_tcpclientsrc_init_receive):
+	Fix some memory leaks.
+
+2004-08-30  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	Patch by: David Schleef
+
+	* configure.ac:
+	* sys/Makefile.am:
+	  rename our detection macro for V4L2.  Fixes #151236.
+
+2004-08-30  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	Patch by: David Schleef
+
+	* configure.ac:
+	  check to define LAMEPRESET.  Fixes #151232.
+
+2004-08-27  David Schleef  <ds@schleef.org>
+
+	* sys/glsink/glimagesink.c: (gst_glimagesink_ximage_put),
+	(gst_glimagesink_xwindow_new), (gst_glimagesink_xcontext_get),
+	(gst_glimagesink_fixate):  Move local variable declarations to
+	make gcc-2.95 happy.
+
+2004-08-27  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	  bump nano for prerelease
+
+2004-08-27  David Schleef  <ds@schleef.org>
+
+	* sys/sunaudio/Makefile.am: Add sunaudiosrc patch from Bala
+	* sys/sunaudio/gstsunaudiosrc.c:
+	* sys/sunaudio/gstsunaudiosrc.h:
+
+2004-08-27 Arwed v. Merkatz <v.merkatz@gmx.net>
+
+	* gst/matroska/ebml-read.c: (gst_ebml_peed_id), (gst_ebml_read_element_id),
+	handle EOS correctly
+	* gst/matroska/matroska-mux.c: (gst_matroska_mux_video_pad_link):
+	* gst/matroska/matroska-mux.h:
+	added BITMAPINFOHEADER structure, mux video/x-divx and video/x-xvid in
+	VFW compatibility mode
+
+2004-08-27  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	patch by: Zaheer Abbas Merali
+
+	* ext/ogg/gstoggmux.c:
+	* ext/vorbis/vorbisenc.c:
+	* ext/vorbis/vorbisenc.h:
+	  handle NEWMEDIA
+
+2004-08-26 Arwed v. Merkatz <v.merkatz@gmx.net>
+
+	* gst/matroska/ebml-write.c: (gst_ebml_write_float),
+	fix byte order reversion on little endian machines.
+	* gst/matroska/matroska-mux.c: (audiosink_templ),
+	(gst_matroska_mux_audio_pad_link):
+	add TTA codec to the list of supported codecs.
+	* gst/matroska/matroska-mux.c: (gst_matroska_mux_init),
+	(gst_matroska_mux_start), (gst_matroska_mux_finish),
+	(gst_matroska_mux_write_data):
+	* gst/matroska/matroska-mux.h:
+	write segment duration correctly, write muxing app string, fixes bugs
+	#140897 and #140898.
+	* gst/matroska/matroska-mux.c: (gst_matroska_mux_loop),
+	wait for all pads to be negotiated before starting to mux.
+
+2004-08-26  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* ext/lame/gstlame.c: (gst_lame_init), (gst_lame_chain):
+	* ext/lame/gstlame.h:
+	Added new media support to lame
+
+2004-08-25 Arwed v. Merkatz <v.merkatz@gmx.net>
+
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_parse_blockgroup),
+	send vorbis headers at the beginning of a stream, fixes bug #141554.
+	Interpret BLOCKDURATION and set buffer duration accordingly, fixes
+	bug #148950.
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_audio_caps),
+	(gst_matroska_demux_plugin_init):
+	* gst/matroska/matroska-ids.h:
+	enable demuxing of TTA audio streams, fixes bug #148951.
+	* gst/typefind/gsttypefindfunctions.c: (tta_type_find), (plugin_init),
+	enable typefinding for TTA audio files, fixes bug #148711.
+	* ext/xvid/gstxviddec.c: (gst_xviddec_chain),
+	set XVID_LOWDELAY flag for decoding so xvid always returns an image,
+	fixes playback of packed bitstream and xvid with bframes, bug #135407.
+
+2004-08-24  Sebastien Cote  <sc5@hermes.usherb.ca>
+
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_peek_head),
+	(gst_riff_read_element_data), (gst_riff_read_seek),
+	(gst_riff_read_skip): fix infinite loop in wavparse, fixes bug
+	#144616, patch reviewed by Ronald and committed by Christophe Fergeau
+	<teuf@gnome.org>
+
+2004-08-23 Iain <iaingnome@gmail.com>
+
+	* ext/mad/gstid3tag.c (gst_mad_id3_to_tag_list): Special case COMM
+	tags. They appear to be handled differently to normal.
+	(tag_list_to_id3_tag_foreach): Ditto.
+
+2004-08-22  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_next_buffer),
+	(gst_ogg_mux_send_headers), (gst_ogg_mux_loop):
+	Make sure we never send -1 granulepos.
+
+2004-08-20  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_next_buffer),
+	(gst_ogg_mux_loop):
+	I will accept bitchslappings with non sharp objects.
+
+2004-08-20  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* configure.ac:
+	Clean up the test for lame presets
+
+2004-08-19  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* configure.ac:
+	* ext/lame/Makefile.am:
+	* ext/lame/gstlame.c: (gst_lame_class_init),
+	(gst_lame_set_property), (gst_lame_get_property), (gst_lame_setup):
+	Only enable lame presets if version of lame has presets in API
+
+2004-08-19  Jan Schmidt  <thaytan@mad.scientist.com>
+	* gst/udp/gstudpsrc.c: (gst_udpsrc_init), (gst_udpsrc_get):
+	* gst/udp/gstudpsrc.h:
+	  Don't call gst_pad_push in a get function. Fixes #150449
+
+2004-08-18  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstfdset.c: (gst_fdset_free), (gst_fdset_set_mode),
+	(gst_fdset_get_mode), (gst_fdset_add_fd), (gst_fdset_remove_fd),
+	(gst_fdset_fd_ctl_write), (gst_fdset_fd_ctl_read),
+	(gst_fdset_fd_has_closed), (gst_fdset_fd_has_error),
+	(gst_fdset_fd_can_read), (gst_fdset_fd_can_write),
+	(gst_fdset_wait):
+	* gst/tcp/gstfdset.h:
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_add),
+	(gst_multifdsink_client_queue_buffer),
+	(gst_multifdsink_handle_client_write):
+	* gst/tcp/gstmultifdsink.h:
+	Some extra checks in gstfdset.
+	Only use send() when the fd is a socket. Don't try to
+	read from write only fds.
+
+2004-08-18  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstfdset.c: (gst_fdset_add_fd), (gst_fdset_remove_fd),
+	(gst_fdset_fd_ctl_write), (gst_fdset_fd_ctl_read),
+	(gst_fdset_fd_has_closed), (gst_fdset_fd_has_error),
+	(gst_fdset_fd_can_read), (gst_fdset_fd_can_write),
+	(gst_fdset_wait):
+	Add more locking and bounds checking.
+
+2004-08-18  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstfdset.c: (ensure_size), (gst_fdset_wait):
+	Realloc test fdset in the lock and right before starting
+	the poll call. Bump the limit to 4096.
+
+2004-08-17  David Schleef  <ds@schleef.org>
+
+	* sys/sunaudio/Makefile.am:
+	* sys/sunaudio/gstsunaudio.c: Fix caps to handle full range
+	of rates and channels.  Make debugging less obnoxious.
+
+	Patch from Balamurali Viswanathan implementing a mixer for
+	Sun audio.  (bug #144091):
+	* sys/sunaudio/gstsunelement.c:
+	* sys/sunaudio/gstsunelement.h:
+	* sys/sunaudio/gstsunmixer.c:
+	* sys/sunaudio/gstsunmixer.h:
+
+2004-08-17  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* gst/audioscale/gstaudioscale.c:
+	* gst/audioscale/gstaudioscale.h:
+	made audioscale resample from any sample rate to any sample rate
+
+2004-08-17  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/libpng/gstpngdec.c:
+	  error out on unsupported types
+
+2004-08-17  Iain <iaingnome@gmail.com>
+
+	* ext/flac/gstflacenc.c (gst_flacenc_update_quality): Only set the
+	mid_side and loose_mid_side properties if its a stereo stream.
+
+2004-08-17  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/theoradec.c: (gst_theora_dec_class_init),
+	(theora_get_formats), (theora_dec_src_convert),
+	(theora_dec_sink_convert), (theora_dec_src_query),
+	(theora_dec_src_event), (theora_dec_event), (theora_dec_chain):
+	Add a debug line.
+
+2004-08-17  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_iterate),
+	(gst_ogg_pad_push):
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_init),
+	(gst_ogg_mux_request_new_pad), (gst_ogg_mux_next_buffer),
+	(gst_ogg_mux_buffer_from_page), (gst_ogg_mux_push_page),
+	(gst_ogg_mux_send_headers), (gst_ogg_mux_loop):
+	Mark delta units in the muxer.
+	Try to decode the packet after an out-of-sync error from
+	libogg.
+
+2004-08-17  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_class_init),
+	(gst_multifdsink_init), (gst_multifdsink_add),
+	(gst_multifdsink_client_queue_buffer),
+	(gst_multifdsink_set_property), (gst_multifdsink_get_property):
+	* gst/tcp/gstmultifdsink.h:
+	Added option to send a keyframe to clients as the first buffer.
+	Make timeout property writable.
+
+2004-08-17  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	patch by: Wim Taymans
+
+	* gst/tcp/gstfdset.c:
+	* gst/tcp/gstmultifdsink.c:
+	  fix index comparison, should include 0
+
+2004-08-16  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstfdset.c: (ensure_size), (gst_fdset_new),
+	(gst_fdset_add_fd), (gst_fdset_remove_fd),
+	(gst_fdset_fd_has_closed), (gst_fdset_fd_has_error),
+	(gst_fdset_fd_can_read), (gst_fdset_fd_can_write),
+	(gst_fdset_wait):
+	  copy when reallocing for poll so the select arguments don't get
+	  changed during the call
+
+2004-08-16  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/theoraenc.c: (gst_border_mode_get_type),
+	(gst_theora_enc_class_init), (theora_enc_sink_link),
+	(theora_buffer_from_packet), (theora_enc_chain):
+	Fix bug where buffers were not marked as keyframes
+	correctly.
+
+2004-08-15  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* ext/lame/gstlame.c: (gst_lame_vbrmode_get_type),
+	(gst_lame_preset_get_type), (gst_lame_class_init):
+	describe the enum values for vbr mode and presets more verbosely
+
+2004-08-13  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* ext/lame/gstlame.c: (gst_lame_mode_get_type),
+	(gst_lame_quality_get_type), (gst_lame_padding_get_type),
+	(gst_lame_preset_get_type), (gst_lame_class_init), (gst_lame_init),
+	(gst_lame_set_property), (gst_lame_get_property), (gst_lame_setup):
+	* ext/lame/gstlame.h:
+	add preset property to lame so it can use lame presets
+
+2004-08-13  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* ext/lame/gstlame.c: (gst_lame_get_property):
+	whoops forgot break, thanks teuf
+
+2004-08-13  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* ext/lame/gstlame.c: (gst_lame_vbrmode_get_type),
+	(gst_lame_class_init), (gst_lame_src_getcaps),
+	(gst_lame_sink_link), (gst_lame_init), (gst_lame_set_property),
+	(gst_lame_get_property), (gst_lame_setup):
+	* ext/lame/gstlame.h:
+	fix lame's broken vbr stuff, allow it to resample if need be, and also
+	make xing header optional
+
+2004-08-12  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* ext/lame/gstlame.c: (gst_lame_src_getcaps), (gst_lame_init):
+	added getcaps function so samplerate doesnt get fixated to silly values
+
+2004-08-12  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* ext/lame/gstlame.c: (gst_lame_src_link):
+	revert previous fix
+
+2004-08-12  Johan Dahlin  <johan@gnome.org>
+
+	* sys/v4l/gstv4lelement.c (gst_v4l_iface_supported): Remove bogus
+	checks. Doesn't matter what state we are in. Interfaces are a
+	compile time thing, not runtime. It also broke the python bindings.
+
+2004-08-12  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* ext/lame/gstlame.c: (gst_lame_src_link):
+	made source pad link function check if sinkpad is ok..fixes the problem
+	where core fixates the output rate of lame stupidly
+
+2004-08-12  Thomas Vander Stichele  <thomas (at) apestaart (dot) org>
+
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_src_link), (gst_v4lsrc_fixate):
+	* sys/v4l/v4l_calls.c:
+	* sys/v4l/v4lsrc_calls.c: (gst_v4lsrc_set_capture):
+	  fix fixate function to handle nonsimple caps.
+	  remove bogus check in _link
+	  cleanups
+
+2004-08-12  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* ext/lame/gstlame.c: (gst_lame_class_init), (gst_lame_init):
+	set default compression ratio parameter to 0.0 so bitrate parameter
+	works :)
+
+2004-08-11  David Schleef  <ds@schleef.org>
+
+	* gst/tcp/gstfdset.c: Fix compile problem on OS/X.
+
+2004-08-11  David Schleef  <ds@schleef.org>
+
+	* gst/mpeg1sys/gstmpeg1systemencode.c: Oops, this was correct
+	before.
+
+2004-08-11  David Schleef  <ds@schleef.org>
+
+	* gst-libs/gst/video/videosink.h: Change copyright block to LGPL.
+
+2004-08-11  David Schleef  <ds@schleef.org>
+
+	* ext/pango/gsttextoverlay.c: Add copyright block and fix plugin
+	  license field
+	* gst-libs/gst/idct/Makefile.am: Remove mmx/sse code
+	* gst-libs/gst/video/gstvideosink.c: Change copyright block to
+	  LGPL.
+	* gst/auparse/gstauparse.c: Fix plugin license field.
+	* gst/monoscope/gstmonoscope.c: Fix plugin license field.
+	* gst/mpeg1sys/gstmpeg1systemencode.c: Fix plugin license field.
+	* gst/rtp/gstrtp.c: Fix plugin license field.
+
+2004-08-11  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/Makefile.am:
+	* gst/tcp/gstfdset.c: (gst_fdset_mode_get_type), (nearest_pow),
+	(ensure_size), (gst_fdset_new), (gst_fdset_free),
+	(gst_fdset_set_mode), (gst_fdset_get_mode), (gst_fdset_add_fd),
+	(gst_fdset_remove_fd), (gst_fdset_fd_ctl_write),
+	(gst_fdset_fd_ctl_read), (gst_fdset_fd_has_closed),
+	(gst_fdset_fd_has_error), (gst_fdset_fd_can_read),
+	(gst_fdset_fd_can_write), (gst_fdset_wait):
+	* gst/tcp/gstfdset.h:
+	* gst/tcp/gstmultifdsink.c: (gst_unit_type_get_type),
+	(gst_multifdsink_class_init), (gst_multifdsink_init),
+	(gst_multifdsink_add), (gst_multifdsink_remove),
+	(gst_multifdsink_clear), (gst_multifdsink_get_stats),
+	(gst_multifdsink_remove_client_link),
+	(gst_multifdsink_handle_client_read),
+	(gst_multifdsink_client_queue_data),
+	(gst_multifdsink_client_queue_caps),
+	(gst_multifdsink_client_queue_buffer),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_recover_client), (gst_multifdsink_queue_buffer),
+	(gst_multifdsink_handle_clients), (gst_multifdsink_set_property),
+	(gst_multifdsink_get_property), (gst_multifdsink_init_send),
+	(gst_multifdsink_close):
+	* gst/tcp/gstmultifdsink.h:
+	* gst/tcp/gsttcpserversink.c: (gst_tcpserversink_class_init),
+	(gst_tcpserversink_init), (gst_tcpserversink_handle_server_read),
+	(gst_tcpserversink_handle_wait), (gst_tcpserversink_init_send),
+	(gst_tcpserversink_close):
+	* gst/tcp/gsttcpserversink.h:
+	Abstracted away the select call, implemented poll (yes we ran into
+	the 1024 limit in production).
+
+2004-08-11  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/tcp/gsttcp.c:
+	* gst/tcp/gsttcpplugin.c:
+	  improve debuggging, remove assert
+
+2004-08-10  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstmultifdsink.c: (gst_unit_type_get_type),
+	(gst_client_status_get_type), (gst_multifdsink_class_init),
+	(gst_multifdsink_init), (gst_multifdsink_remove_client_link),
+	(gst_multifdsink_handle_client_read),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_recover_client), (gst_multifdsink_queue_buffer),
+	(gst_multifdsink_handle_clients), (gst_multifdsink_set_property),
+	(gst_multifdsink_get_property):
+	* gst/tcp/gstmultifdsink.h:
+	* gst/tcp/gsttcp-marshal.list:
+	Starting to prepare for specifying buffer time in other units
+	than buffers. Expose remove reason in signal.
+
+2004-08-10  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_add),
+	(gst_multifdsink_remove), (gst_multifdsink_clear),
+	(gst_multifdsink_remove_client_link),
+	(gst_multifdsink_handle_client_read),
+	(gst_multifdsink_client_queue_data),
+	(gst_multifdsink_client_queue_buffer),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_queue_buffer), (gst_multifdsink_handle_clients),
+	(gst_multifdsink_chain), (gst_multifdsink_close):
+	* gst/tcp/gstmultifdsink.h:
+	Added more debugging info. Changed the way clients are
+	removed from the lists. Fixed a bug where a bad file descriptor
+	could cause many clients to be removed.
+
+2004-08-06  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/videotestsrc/gstvideotestsrc.c: (generate_capslist):
+	  allow all pixel-aspect-ratios, not just 1:1
+
+2004-08-09  David Schleef  <ds@schleef.org>
+
+	* sys/glsink/ARB_multitexture.h:  Remove old files.
+	* sys/glsink/EXT_paletted_texture.h:
+	* sys/glsink/NV_register_combiners.h:
+	* sys/glsink/gstgl_nvimage.c:
+	* sys/glsink/gstgl_pdrimage.c:
+	* sys/glsink/gstgl_rgbimage.c:
+	* sys/glsink/gstglsink.c:
+	* sys/glsink/gstglsink.h:
+	* sys/glsink/gstglxwindow.c:
+	* sys/glsink/regcomb_yuvrgb.c:
+
+2004-08-09  David Schleef  <ds@schleef.org>
+
+	Patch from Gernot Ziegler <gz@lysator.liu.se> rewriting the
+	GL sink plugin.  (Bug #147302)
+
+	* configure.ac: Test for OpenGL
+	* sys/Makefile.am: Use test for OpenGL
+	* sys/glsink/Makefile.am:
+	* sys/glsink/glimagesink.c: rewrite
+	* sys/glsink/glimagesink.h: rewrite
+
+2004-08-09  David Schleef  <ds@schleef.org>
+
+	* ext/sdl/sdlvideosink.c: (gst_sdlvideosink_base_init):  Only allow
+	sane framerates.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xcontext_get): same
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_xv_support): same
+	* testsuite/gst-lint: Test for G_GUINT64_FORMAT usage near gettext.
+
+2004-08-09  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_class_init),
+	(gst_multifdsink_add), (gst_multifdsink_get_stats),
+	(gst_multifdsink_client_remove),
+	(gst_multifdsink_handle_client_read),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_queue_buffer), (gst_multifdsink_handle_clients):
+	Do a bit more logging, make the client_read code more robust.
+
+2004-08-09  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/jpeg/gstjpegdec.c: (gst_jpegdec_init_source),
+	(gst_jpegdec_fill_input_buffer), (gst_jpegdec_skip_input_data),
+	(gst_jpegdec_resync_to_restart), (gst_jpegdec_term_source),
+	(gst_jpegdec_init), (gst_jpegdec_chain):
+	* gst/multipart/multipartdemux.c: (gst_multipart_demux_init),
+	(gst_multipart_demux_chain), (gst_multipart_demux_change_state):
+	  cleanups, debugging fixes and memleak plugging
+
+2004-08-09  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/theoradec.c: (gst_theora_dec_class_init),
+	(theora_get_formats), (theora_dec_src_convert),
+	(theora_dec_sink_convert), (theora_dec_src_query),
+	(theora_dec_src_event), (theora_dec_event), (theora_dec_chain),
+	(theora_dec_change_state):
+	Don't crash on missing header packets.
+
+2004-08-09  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* po/LINGUAS:
+	* po/sq.po:
+	  Added Albanian translation (Laurent Dhima)
+	* po/cs.po:
+	  updated
+
+2004-08-09  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/lame/gstlame.c:
+	  fix/add debugging
+
+2004-08-09  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/ximage/ximagesink.c:
+	* sys/xvimage/xvimagesink.c:
+	  assign all TOO_LAZY's to a real category.  Thanks to Warthy Warthog.
+
+2004-08-06  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_class_init),
+	(gst_multifdsink_add), (gst_multifdsink_get_stats),
+	(gst_multifdsink_client_remove),
+	(gst_multifdsink_handle_client_read),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_queue_buffer), (gst_multifdsink_handle_clients):
+	Make sure we don't try to read more from a client that what
+	ioctl says us or we deadlock.
+
+2004-08-05  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/videotestsrc/gstvideotestsrc.c: (gst_videotestsrc_src_link),
+	(gst_videotestsrc_change_state), (gst_videotestsrc_src_query),
+	(gst_videotestsrc_handle_src_event), (gst_videotestsrc_get):
+	  decouple running_time and n_frames so it can handle changing
+	  framerate while running
+
+2004-08-05  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* po/nl.po:
+	* po/sv.po:
+	  updated translations
+
+2004-08-04  Benjamin Otte  <otte@gnome.org>
+
+	* gst/videotestsrc/gstvideotestsrc.c:
+	(gst_videotestsrc_get_capslist), (generate_capslist),
+	(plugin_init):
+	  generate the list of supported caps at startup and reuse it instead
+	  of always generating it
+
+2004-07-30  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/multipart/multipartmux.c: (gst_multipart_mux_pad_link):
+	  whoops, last checkin broke normal build
+
+2004-08-03  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_get_volume),
+	(gst_alsa_mixer_set_volume), (gst_alsa_mixer_set_mute),
+	(gst_alsa_mixer_set_record), (gst_alsa_mixer_set_option),
+	(gst_alsa_mixer_get_option):
+	* ext/dvdnav/dvdnavsrc.c: (dvdnav_get_event_name),
+	(dvdnavsrc_print_event):
+	* ext/ogg/gstoggdemux.c: (_find_chain_process), (gst_ogg_print):
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_pad_link),
+	(gst_ogg_mux_pad_unlink):
+	* gst/multipart/multipartmux.c: (gst_multipart_mux_pad_link),
+	(gst_multipart_mux_pad_unlink):
+	* gst/videofilter/gstvideobalance.c:
+	(gst_videobalance_colorbalance_set_value):
+	* gst/videomixer/videomixer.c: (gst_videomixer_pad_link),
+	(gst_videomixer_pad_unlink):
+	* po/uk.po:
+	* sys/oss/gstossmixer.c:
+	* sys/v4l/gstv4lcolorbalance.c:
+	* sys/v4l/gstv4ltuner.c:
+	* sys/v4l/v4lsrc_calls.c:
+	* sys/v4l2/gstv4l2colorbalance.c:
+	* sys/v4l2/gstv4l2tuner.c:
+	  compile fixes for --disable-gst-debug, G_DISABLE_ASSERT and friends
+
+2004-08-03  Benjamin Otte  <otte@gnome.org>
+
+	* examples/dynparams/filter.c: (ui_control_create):
+	* examples/gstplay/player.c: (print_tag):
+	* ext/alsa/gstalsa.c: (gst_alsa_request_new_pad):
+	* ext/gdk_pixbuf/gstgdkanimation.c:
+	(gst_gdk_animation_iter_may_advance):
+	* ext/jack/gstjack.c: (gst_jack_request_new_pad):
+	* ext/mad/gstid3tag.c: (gst_mad_id3_to_tag_list),
+	(tag_list_to_id3_tag_foreach), (gst_id3_tag_handle_event):
+	* ext/vorbis/oggvorbisenc.c: (gst_oggvorbisenc_get_tag_value):
+	* ext/vorbis/vorbisenc.c: (gst_vorbisenc_get_tag_value):
+	* ext/xine/xineaudiodec.c: (gst_xine_audio_dec_chain):
+	* gst-libs/gst/media-info/media-info-test.c: (print_tag):
+	* gst/sine/demo-dparams.c: (main):
+	* gst/tags/gstvorbistag.c: (gst_tag_to_vorbis_comments):
+	* testsuite/alsa/formats.c: (create_pipeline):
+	* testsuite/alsa/sinesrc.c: (sinesrc_force_caps), (sinesrc_get):
+	  fixes for G_DISABLE_ASSERT and friends
+	* gst/typefind/gsttypefindfunctions.c: (aac_type_find),
+	(mp3_type_frame_length_from_header), (mp3_type_find),
+	(plugin_init):
+	  require mp3 typefinding to have at least MIN_HEADERS valid headers
+	  add typefinding for AAC adts files
+
+2004-08-04  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* sys/ximage/ximagesink.c:
+	(gst_ximagesink_calculate_pixel_aspect_ratio):
+	* sys/xvimage/xvimagesink.c:
+	(gst_xvimagesink_calculate_pixel_aspect_ratio):
+	Make sure we calculate pixel-aspect-ratio using floating point maths
+
+2004-08-03  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* po/uk.po:
+	  updated translation
+
+2004-08-03  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xcontext_get):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xcontext_get):
+	  add debugging for display PAR calculation
+
+2004-08-02  David Schleef  <ds@schleef.org>
+
+	* configure.ac: Fix mikmod CFLAGS.
+
+2004-07-27  Benjamin Otte  <otte@gnome.org>
+
+	* gst/audioscale/gstaudioscale.c:
+	- fix templates to only support S16, it's the only format that works
+	- make caps nego code use try_set_caps_nonfixed and fixation instead
+	of try_set_caps twice, which is not nice for autopluggers
+	- change rank to secondary, so autopluggers can pick it up after
+	audioconvert
+
+2004-08-02  Iain <iain@prettypeople.org>
+
+	* gst/interleave/interleave.c (interleave_init),
+	(interleave_request_new_pad),
+	(interleave_pad_removed),
+	(interleave_buffered_loop): Use the real pad count, not the artificial
+	one.
+
+2004-08-02  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac: bump nano back to development
+
+=== release 0.8.3 ===
+
+2004-08-02  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac: releasing 0.8.3, "Water"
+
+2004-08-02  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/xvimage/xvimagesink.c:
+	(gst_xvimagesink_calculate_pixel_aspect_ratio),
+	(gst_xvimagesink_xcontext_clear), (gst_xvimagesink_sink_link),
+	(gst_xvimagesink_change_state), (gst_xvimagesink_buffer_alloc),
+	(gst_xvimagesink_set_property), (gst_xvimagesink_get_property),
+	(gst_xvimagesink_init), (gst_xvimagesink_class_init):
+	* sys/xvimage/xvimagesink.h:
+	  apply similar PAR fixes as to ximagesink
+
+2004-08-02  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	patch from: Benjamin Otte
+
+	* ext/lame/gstlame.c: (gst_lame_src_link), (gst_lame_init):
+	  add link function to lame.  Fixes #148986.
+
+2004-08-02  Johan Dahlin  <johan@gnome.org>
+
+	* gst/multipart/multipartmux.c (gst_multipart_mux_next_buffer):
+	fix debugging log
+
+2004-07-30  David Schleef  <ds@schleef.org>
+
+	* gst/videomixer/Makefile.am: Fix things that should have been
+	fixed in the last checkin.
+
+2004-07-30  David Schleef  <ds@schleef.org>
+
+	* gst/multipart/Makefile.am: Fix things that should have been
+	fixed in the last checkin.
+
+2004-07-30  David Schleef  <ds@schleef.org>
+
+	* testsuite/multifilesink/Makefile.am: Fix unused variable.
+
+2004-07-30  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	  bump nano for prerelease
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/nl.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	  updates
+
+2004-07-30  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_class_init),
+	(gst_multifdsink_add), (gst_multifdsink_remove),
+	(gst_multifdsink_clear), (gst_multifdsink_get_stats),
+	(gst_multifdsink_client_remove),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_queue_buffer), (gst_multifdsink_handle_clients):
+	* gst/tcp/gstmultifdsink.h:
+	Recover from a select with a bad file descriptor by removing
+	the client.
+
+2004-07-30  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	  fix requirement of core
+	* gst-libs/gst/play/play.c: (gst_play_error_plugin),
+	(gst_play_pipeline_setup):
+	  don't use colorspace element.  do use hermescolorspace element.
+	  make macro to get a colorspace element.
+	  mark strings for translation.
+	* po/POTFILES.in:
+	  add play.c
+	* po/af.po:
+	* po/az.po:
+	* po/cs.po:
+	* po/en_GB.po:
+	* po/hu.po:
+	* po/nl.po:
+	* po/sr.po:
+	* po/sv.po:
+	* po/uk.po:
+	  update translations
+
+2004-07-30  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* ext/libpng/gstpngenc.c: (gst_pngenc_class_init):
+	fix default for newmedia flag
+
+2004-07-30  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/theoradec.c: (gst_theora_dec_class_init),
+	(gst_theora_dec_init), (theora_get_formats),
+	(theora_dec_src_convert), (theora_dec_sink_convert),
+	(theora_dec_src_query), (theora_dec_src_event), (theora_dec_event),
+	(theora_dec_chain), (theora_dec_set_property),
+	(theora_dec_get_property):
+	* ext/theora/theoraenc.c: (gst_border_mode_get_type),
+	(gst_theora_enc_class_init), (gst_theora_enc_init),
+	(theora_enc_sink_link), (theora_enc_chain),
+	(theora_enc_set_property), (theora_enc_get_property):
+	Added cropping option to theora decoder.
+	Added border option to theora encoder.
+
+2004-07-30  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* ext/libpng/gstpngenc.c: (gst_pngenc_class_init),
+	(gst_pngenc_init), (gst_pngenc_chain), (gst_pngenc_get_property),
+	(gst_pngenc_set_property):
+	* ext/libpng/gstpngenc.h:
+	Added newmedia support to pngenc so now gst-launch-0.8 videotestsrc ! ffmpegcolorspace ! pngenc snapshot=false newmedia=true ! multifilesink location=blah%d.png works as expected
+
+2004-07-30  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/theoraenc.c: (gst_theora_enc_class_init),
+	(theora_enc_sink_link), (theora_enc_chain),
+	(theora_enc_set_property), (theora_enc_get_property):
+	Fix encoding of non-multiple-of-16 video.
+
+2004-07-29  David Schleef  <ds@schleef.org>
+
+	* configure.ac: make test for audiofile more strict
+
+2004-07-25  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/typefind/gsttypefindfunctions.c: (plugin_init):
+	  give different names to typefind functions
+
+2004-07-28  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_renegotiate_size),
+	(gst_ximagesink_calculate_pixel_aspect_ratio),
+	(gst_ximagesink_xcontext_get), (gst_ximagesink_getcaps),
+	(gst_ximagesink_sink_link), (gst_ximagesink_change_state),
+	(gst_ximagesink_set_xwindow_id), (gst_ximagesink_set_property),
+	(gst_ximagesink_get_property), (gst_ximagesink_init):
+	* sys/ximage/ximagesink.h:
+	  allocate PAR's dynamically.
+	  use autodetected PAR if no object-set PAR is given.
+	  add workaround for directfb's X not setting physical size.
+	  fix to xvimagesink will follow tomorrow.
+
+2004-07-28  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* ext/lame/gstlame.c: (gst_lame_chain): send tag events downstream
+	* ext/shout2/gstshout2.c: (gst_shout2send_protocol_get_type),
+	(gst_shout2send_get_type), (gst_shout2send_set_clock),
+	(gst_shout2send_class_init), (gst_shout2send_init),
+	(set_shout_metadata), (gst_shout2send_set_metadata),
+	(gst_shout2send_chain), (gst_shout2send_set_property),
+	(gst_shout2send_get_property), (gst_shout2send_connect),
+	(gst_shout2send_change_state):
+	* ext/shout2/gstshout2.h:
+	- fix for sending mp3 audio to icecast2 server, if pad link function not
+	called before PAUSED state
+	- added option to use GStreamer clock sync (as opposed to libshout's own sync)
+	- added tagging support for mp3 audio broadcasted
+	* gst/monoscope/gstmonoscope.c: (gst_monoscope_class_init):
+	debug info
+
+2004-07-28  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_src_query),
+	(gst_ogg_demux_push):
+	Return query failure when we don't know the length of
+	an ogg stream insteda of returning TRUE with a bogus value.
+
+2004-07-28  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/theoradec.c: (theora_get_formats),
+	(theora_dec_src_convert), (theora_dec_sink_convert),
+	(theora_dec_src_query), (theora_dec_src_event), (theora_dec_event),
+	(theora_dec_chain):
+	Don't screw up the 1 Chroma for 1 luma sample situation when we
+	have an odd offset/width by adding a black border in those cases.
+
+2004-07-28  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/theoradec.c: (theora_get_formats),
+	(theora_dec_src_convert), (theora_dec_sink_convert),
+	(theora_dec_src_query), (theora_dec_src_event), (theora_dec_event),
+	(theora_dec_chain):
+	* ext/theora/theoraenc.c: (theora_enc_sink_link):
+	Added first attempt at cropping of the image as required by the
+	theora spec. We need more properties in the caps (offset_x,
+	offset_y,stride) to implement this correctly.
+
+2004-07-28  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/dvdnav/README:
+	  Update the README to use dvddemux
+	* ext/gdk_pixbuf/pixbufscale.c: (gst_pixbufscale_getcaps):
+	  Ensure getcaps returns a subset of the template caps
+	* gst/mpeg2sub/gstmpeg2subt.c: (gst_mpeg2subt_base_init),
+	(gst_mpeg2subt_init):
+	  Ensure getcaps returns a subset of the template caps
+	* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_class_init),
+	(gst_dvd_demux_init), (gst_dvd_demux_get_video_stream),
+	(gst_dvd_demux_get_subpicture_stream),
+	(gst_dvd_demux_send_subbuffer), (gst_dvd_demux_set_cur_subpicture):
+	* gst/mpegstream/gstdvddemux.h:
+	  Set the explicit caps on the current_video pad before pushing
+	  anything
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_get_video_stream),
+	(gst_mpeg_demux_get_audio_stream):
+	  Free caps used to gst_pad_set_explicit_caps, which takes a const
+	  GstCaps *
+
+2004-07-28  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac: update GStreamer requirement to 0.8.4 because of
+	  GstFraction.
+
+2004-07-28  Wim Taymans  <wim@fluendo.com>
+
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_fmt),
+	(gst_wavparse_handle_seek), (gst_wavparse_srcpad_event):
+	Add the pad to the element after setting up the caps. This
+	makes it a lot easier to autoplug.
+
+2004-07-27  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* gst/median/gstmedian.c:
+	* gst/mpeg2subt/gstmpeg2subt.c:
+	* gst/mpegaudioparse/gstmpegaudioparse.c:
+	* gst/mpegstream/gstdvddemux.c:
+	* gst/mpegstream/gstmpegdemux.c:
+	* gst/mpegstream/gstmpegpacketize.c:
+	* gst/rtjpeg/gstrtjpeg.c:
+	* gst/rtjpeg/gstrtjpegdec.c:
+	* gst/rtjpeg/gstrtjpegenc.c:
+	* gst/sine/gstsinesrc.c:
+	* gst/smooth/gstsmooth.c:
+	* gst/smpte/gstsmpte.c:
+	* gst/smpte/gstsmpte.h:
+	* gst/stereo/gststereo.c:
+	* gst/videofilter/gstgamma.c:
+	* gst/videofilter/gstvideobalance.c:
+	* gst/videofilter/gstvideofilter.c:
+	* gst/videofilter/gstvideoflip.c:
+	* gst/videoscale/gstvideoscale.c:
+	* gst/videoscale/videoscale.c:
+	* gst/videotestsrc/gstvideotestsrc.c:
+	* gst/videotestsrc/videotestsrc.c:
+	* gst/wavenc/gstwavenc.c:
+	* gst/wavparse/gstwavparse.c:
+	  fix local includes and 64 bits constants
+
+2004-07-27  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* win32/gst.sln:
+	* gst-libs/gst/*/*.vcproj:
+	* gst/*/*.vcproj:
+	  more working plugins
+
+2004-07-27  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* testsuite/alsa/Makefile.am:
+	* testsuite/alsa/srcstate.c:
+	add test for alsasrc changing state
+
+2004-07-27  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* gst/silence/gstsilence.c: (gst_silence_init), (gst_silence_link),
+	(gst_silence_get):
+	* gst/silence/gstsilence.h:
+	fix silence generation for 16bit raw audio
+
+2004-07-27  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/matroska/matroska-demux.c:
+	(gst_matroska_demux_parse_metadata),
+	(gst_matroska_demux_video_caps), (gst_matroska_demux_plugin_init):
+	* gst/mpegaudio/common.c:
+	* gst/videoscale/gstvideoscale.c: (gst_videoscale_class_init),
+	(gst_videoscale_getcaps), (gst_videoscale_link),
+	(gst_videoscale_src_fixate), (gst_videoscale_init),
+	(gst_videoscale_finalize):
+	* gst/videoscale/gstvideoscale.h:
+	* gst/videotestsrc/gstvideotestsrc.c:
+	(gst_videotestsrc_get_capslist):
+	* gst/wavenc/gstwavenc.c:
+	* sys/oss/gstossmixer.c: (fill_labels):
+	* sys/ximage/ximagesink.c: (gst_ximagesink_renegotiate_size),
+	(gst_ximagesink_handle_xevents),
+	(gst_ximagesink_calculate_pixel_aspect_ratio),
+	(gst_ximagesink_xcontext_get), (gst_ximagesink_fixate),
+	(gst_ximagesink_getcaps), (gst_ximagesink_sink_link),
+	(gst_ximagesink_chain), (gst_ximagesink_set_xwindow_id),
+	(gst_ximagesink_set_property), (gst_ximagesink_get_property),
+	(gst_ximagesink_init), (gst_ximagesink_class_init):
+	* sys/ximage/ximagesink.h:
+	* sys/xvimage/xvimagesink.c:
+	(gst_xvimagesink_calculate_pixel_aspect_ratio),
+	(gst_xvimagesink_xcontext_get), (gst_xvimagesink_sink_link),
+	(gst_xvimagesink_chain), (gst_xvimagesink_buffer_alloc),
+	(gst_xvimagesink_set_property), (gst_xvimagesink_get_property),
+	(gst_xvimagesink_init), (gst_xvimagesink_class_init):
+	* sys/xvimage/xvimagesink.h:
+	  first batch of pixel aspect ratio commits.
+
+2004-07-27  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+	(gst_ffmpegcolorspace_class_init), (gst_ffmpegcolorspace_chain):
+	* gst/ffmpegcolorspace/imgconvert.c: (avpicture_fill):
+	  handle stride, needs work if we want to move stride handling
+	  upstream, but works correctly for our purposes.
+
+2004-07-27  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/videoscale/README:
+	  add testing examples
+	* gst/videoscale/gstvideoscale.c: (gst_videoscale_link),
+	(gst_videoscale_chain):
+	* gst/videoscale/videoscale.c: (gst_videoscale_setup),
+	(gst_videoscale_get_size):
+	  add get_size function that handles stride like videotestsrc.
+	  fixes conversion for YUV formats for as much as I can test them.
+
+2004-07-27  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_check_xshm_calls),
+	(gst_ximagesink_ximage_new), (gst_ximagesink_ximage_destroy):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_check_xshm_calls),
+	(gst_xvimagesink_xvimage_new), (gst_xvimagesink_xvimage_destroy),
+	(gst_xvimagesink_xvimage_put):
+	  further cleanups, logging, error handling and synchronizing
+
+2004-07-27  Wim Taymans  <wim@fluendo.com>
+
+	* gst/videomixer/videomixer.c: (gst_videomixer_pad_get_type),
+	(gst_videomixer_pad_class_init), (gst_videomixer_pad_get_property),
+	(gst_videomixer_pad_set_property),
+	(gst_videomixer_pad_sinkconnect), (gst_videomixer_pad_init),
+	(gst_video_mixer_background_get_type), (gst_videomixer_get_type),
+	(gst_videomixer_class_init), (gst_videomixer_init),
+	(gst_videomixer_getcaps), (gst_videomixer_request_new_pad),
+	(gst_videomixer_blend_ayuv_i420), (pad_zorder_compare),
+	(gst_videomixer_sort_pads), (gst_videomixer_fill_checker),
+	(gst_videomixer_fill_color), (gst_videomixer_fill_queues),
+	(gst_videomixer_blend_buffers), (gst_videomixer_update_queues),
+	(gst_videomixer_loop), (plugin_init):
+	Be a nicer negotiation citizen and provide a getcaps function on
+	the srcpad. This also fixes a crash when resizing.
+
+2004-07-27  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_check_xshm_calls),
+	(gst_xvimagesink_xvimage_new): Some fixes to image size calculation.
+
+2004-07-27  Wim Taymans  <wim@fluendo.com>
+
+	* ext/libpng/gstpngdec.c: (gst_pngdec_src_getcaps):
+	* ext/libpng/gstpngenc.c: (gst_pngenc_class_init),
+	(gst_pngenc_init), (gst_pngenc_chain), (gst_pngenc_get_property),
+	(gst_pngenc_set_property):
+	* ext/libpng/gstpngenc.h:
+	Added snapshot property to pngenc.
+	removed g_print from pngdec
+
+2004-07-27  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* gst/ac3parse/ac3parse.vcproj
+	* gst/adder/adder.vcproj
+	* gst/alpha/alpha.vcproj
+	* gst/alpha/alphacolor.vcproj
+	* gst/asfdemux/asf.vcproj
+	* gst/audioconvert/audioconvert.vcproj
+	* gst/audiorate/audiorate.vcproj
+	* gst/audioscale/audioscale.vcproj
+	* gst/auparse/auparse.vcproj
+	* gst/avi/avi.vcproj
+	* gst/cdxaparse/cdxaparse.vcproj
+	* gst/chart/chart.vcproj
+	* gst/colorspace/colorspace.vcproj
+	* gst/cutter/cutter.vcproj
+	* gst/debug/debug.vcproj
+	* gst/debug/efence.vcproj
+	* gst/debug/navigationtest.vcproj
+	* gst/deinterlace/deinterlace.vcproj
+	* gst/effectv/effectv.vcproj
+	* gst/ffmpegcolorspace/ffmpegcolorspace.vcproj
+	* gst/filter/filter.vcproj
+	* gst/flx/flxdec.vcproj
+	* gst/goom/goom.vcproj
+	* gst/interleave/interleave.vcproj
+	* gst/law/alaw.vcproj
+	* gst/law/mulaw.vcproj
+	* gst/matroska/matroska.vcproj
+	* gst/median/median.vcproj
+	* gst/mixmatrix/mixmatrix.vcproj
+	* gst/mpeg1sys/mpeg1systemencode.vcproj
+	* gst/mpeg1videoparse/mp1videoparse.vcproj
+	* gst/mpeg2sub/mpeg2subt.vcproj
+	* gst/mpegaudio/mpegaudio.vcproj
+	* gst/mpegaudioparse/mpegaudioparse.vcproj
+	* gst/mpegstream/mpegstream.vcproj
+	* gst/multifilesink/multifilesink.vcproj
+	* gst/multipart/multipart.vcproj
+	* gst/oneton/oneton.vcproj
+	* gst/overlay/overlay.vcproj
+	* gst/passthrough/passthrough.vcproj
+	* gst/qtdemux/qtdemux.vcproj
+	* gst/realmedia/rmdemux.vcproj
+	* gst/rtjpeg/rtjpeg.vcproj
+	* gst/rtp/rtp.vcproj
+	* gst/silence/silence.vcproj
+	* gst/sine/sinesrc.vcproj
+	* gst/smooth/smooth.vcproj
+	* gst/smpte/smpte.vcproj
+	* gst/spectrum/spectrum.vcproj
+	* gst/speed/speed.vcproj
+	* gst/stereo/stereo.vcproj
+	* gst/switch/switch.vcproj
+	* gst/tags/tagedit.vcproj
+	* gst/tcp/tcp.vcproj
+	* gst/typefind/typefindfunctions.vcproj
+	* gst/udp/udp.vcproj
+	* gst/videobox/videobox.vcproj
+	* gst/videocrop/videocrop.vcproj
+	* gst/videodrop/videodrop.vcproj
+	* gst/videofilter/gamma.vcproj
+	* gst/videofilter/videobalance.vcproj
+	* gst/videofilter/videofilter.vcproj
+	* gst/videofilter/videoflip.vcproj
+	* gst/videoflip/videoflip.vcproj
+	* gst/videomixer/videomixer.vcproj
+	* gst/videorate/videorate.vcproj
+	* gst/videoscale/videoscale.vcproj
+	* gst/videotestsrc/videotestsrc.vcproj
+	* gst/virtualdub/virtualdub.vcproj
+	* gst/volenv/volenv.vcproj
+	* gst/volume/volume.vcproj
+	* gst/wavenc/wavenc.vcproj
+	* gst/wavparse/wavparse.vcproj
+	* gst/y4m/y4menc.vcproj
+	* gst-libs/gst/audio/audio.vcproj
+	* gst-libs/gst/audio/audiofilter.vcproj
+	* gst-libs/gst/colorbalance/colorbalance.vcproj
+	* gst-libs/gst/idct/idtc.vcproj
+	* gst-libs/gst/media-info/media-info.vcproj
+	* gst-libs/gst/mixer/mixer.vcproj
+	* gst-libs/gst/navigation/navigation.vcproj
+	* gst-libs/gst/play/play.vcproj
+	* gst-libs/gst/propertyprobe/propertyprobe.vcproj
+	* gst-libs/gst/resample/resample.vcproj
+	* gst-libs/gst/riff/riff.vcproj
+	* gst-libs/gst/tuner/tuner.vcproj
+	* gst-libs/gst/video/video.vcproj
+	* gst-libs/gst/xoverlay/xoverlay.vcproj
+	  avoid problems with math.h, fix release dependancy
+	  rename GStreamer-0.8.lib to libgstreamer.lib
+
+2004-07-27  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xwindow_decorate):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xwindow_decorate): When
+	the atom is not available we have to unlock the mutex. Fixes #148023
+
+2004-07-26  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* gst-libs/gst/media-info/media-info.h:
+	  issue for a vararg macro with MSVC
+
+2004-07-26  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* gst/effectv/effectv.vcproj
+	* gst-libs/gst/idct/idct.vcproj:
+	* gst-libs/gst/media-info/media-info.vcproj:
+	* gst-libs/gst/navigation/navigation.vcproj:
+	* gst-libs/gst/propertyprobe/propertyprobe.vcproj:
+	* gst-libs/gst/video/video.vcproj:
+	* gst-libs/gst/xoverlay/xoverlay.vcproj:
+	  fixes for build problems
+
+2004-07-26  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* gst-libs/gst/audio/audio.def:
+	* gst-libs/gst/audio/riff.def:
+	  add some definitions needed by plugins
+
+2004-07-26  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* gst/asfdemux/gstasfmux.c
+	  Fix some 64 bits constants to be glib friendly
+
+2004-07-26  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* gst/ac3parse/gstac3parse.c
+	* gst/audioscale/gstaudioscale.c
+	* gst/auparse/gstauparse.c
+	* gst/colorspace/gstcolorspace.c
+	* gst/colorspace/yuv2rgb.h
+	  local include fixes
+
+2004-07-26  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* win32/gst.sln
+	  add more plugins to the build
+
+2004-07-26  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_check_xshm_calls),
+	(gst_ximagesink_ximage_new): Some more fixes to image size calculation.
+
+2004-07-26  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/level/gstlevel.c: (gst_level_link), (gst_level_chain),
+	(gst_level_set_property), (gst_level_get_property),
+	(gst_level_base_init), (gst_level_class_init):
+	  add debugging categories.  cleanups.
+
+2004-07-26  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/videoscale/videoscale.c: (gst_videoscale_setup),
+	(gst_videoscale_planar411), (gst_videoscale_planar400),
+	(gst_videoscale_packed422), (gst_videoscale_packed422rev),
+	(gst_videoscale_scale_nearest_str1),
+	(gst_videoscale_scale_nearest_str2),
+	(gst_videoscale_scale_nearest_str4),
+	(gst_videoscale_scale_nearest_16bit),
+	(gst_videoscale_scale_nearest_24bit):
+	  fixed stride issues
+	  tested with 320x240 -> 321, 322, 324 x240
+	  tested with YV12, I420, YUY2, UYVY
+	  fixed packed422rev (don't think it could have worked before)
+	  by testing with UYVY
+
+2004-07-26  Benjamin Otte  <otte@gnome.org>
+
+	* ext/lame/gstlame.c: (gst_lame_sink_link), (gst_lame_init),
+	(gst_lame_chain), (gst_lame_setup), (gst_lame_change_state),
+	(plugin_init):
+	  add debugging category, add error checks like checking return values
+	  of setup calls, make sure it still works after
+	  PLAYING=>NULL=>PLAYING, fix encoding of mono streams
+
+2004-07-26  Wim Taymans  <wim@fluendo.com>
+
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_get_video_stream),
+	(gst_mpeg_demux_get_audio_stream),
+	(gst_mpeg_demux_process_private):
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_send_data):
+	Check for error codes from the negotiation functions. Make sure
+	we really set the pad caps when a new pad is created.
+
+2004-07-26  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c:
+	(gst_ffmpeg_caps_to_pix_fmt):
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.h:
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+	(gst_ffmpegcolorspace_pad_link):
+	  don't make function do two things at the same time without reason.
+
+2004-07-26  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* gst/ac3parse/ac3parse.vcproj
+	* gst/adder/adder.vcproj
+	* gst/alpha/alpha.vcproj
+	* gst/alpha/alphacolor.vcproj
+	* gst/asfdemux/asf.vcproj
+	* gst/audioconvert/audioconvert.vcproj
+	* gst/audiorate/audiorate.vcproj
+	* gst/audioscale/audioscale.vcproj
+	* gst/auparse/auparse.vcproj
+	* gst/avi/avi.vcproj
+	* gst/cdxaparse/cdxaparse.vcproj
+	* gst/chart/chart.vcproj
+	* gst/colorspace/colorspace.vcproj
+	* gst/cutter/cutter.vcproj
+	* gst/debug/debug.vcproj
+	* gst/debug/efence.vcproj
+	* gst/debug/navigationtest.vcproj
+	* gst/deinterlace/deinterlace.vcproj
+	* gst/effectv/effectv.vcproj
+	* gst/ffmpegcolorspace/ffmpegcolorspace.vcproj
+	* gst/filter/filter.vcproj
+	* gst/flx/flxdec.vcproj
+	* gst/goom/goom.vcproj
+	* gst/interleave/interleave.vcproj
+	* gst/law/alaw.vcproj
+	* gst/law/mulaw.vcproj
+	* gst/matroska/matroska.vcproj
+	* gst/median/median.vcproj
+	* gst/mixmatrix/mixmatrix.vcproj
+	* gst/mpeg1sys/mpeg1systemencode.vcproj
+	* gst/mpeg1videoparse/mp1videoparse.vcproj
+	* gst/mpeg2sub/mpeg2subt.vcproj
+	* gst/mpegaudio/mpegaudio.vcproj
+	* gst/mpegaudioparse/mpegaudioparse.vcproj
+	* gst/mpegstream/mpegstream.vcproj
+	* gst/multifilesink/multifilesink.vcproj
+	* gst/multipart/multipart.vcproj
+	* gst/oneton/oneton.vcproj
+	* gst/overlay/overlay.vcproj
+	* gst/passthrough/passthrough.vcproj
+	* gst/qtdemux/qtdemux.vcproj
+	* gst/realmedia/rmdemux.vcproj
+	* gst/rtjpeg/rtjpeg.vcproj
+	* gst/rtp/rtp.vcproj
+	* gst/silence/silence.vcproj
+	* gst/sine/sinesrc.vcproj
+	* gst/smooth/smooth.vcproj
+	* gst/smpte/smpte.vcproj
+	* gst/spectrum/spectrum.vcproj
+	* gst/speed/speed.vcproj
+	* gst/stereo/stereo.vcproj
+	* gst/switch/switch.vcproj
+	* gst/tags/tagedit.vcproj
+	* gst/tcp/tcp.vcproj
+	* gst/typefind/typefindfunctions.vcproj
+	* gst/udp/udp.vcproj
+	* gst/videobox/videobox.vcproj
+	* gst/videocrop/videocrop.vcproj
+	* gst/videodrop/videodrop.vcproj
+	* gst/videofilter/gamma.vcproj
+	* gst/videofilter/videobalance.vcproj
+	* gst/videofilter/videofilter.vcproj
+	* gst/videofilter/videoflip.vcproj
+	* gst/videoflip/videoflip.vcproj
+	* gst/videomixer/videomixer.vcproj
+	* gst/videorate/videorate.vcproj
+	* gst/videoscale/videoscale.vcproj
+	* gst/videotestsrc/videotestsrc.vcproj
+	* gst/virtualdub/virtualdub.vcproj
+	* gst/volenv/volenv.vcproj
+	* gst/volume/volume.vcproj
+	* gst/wavenc/wavenc.vcproj
+	* gst/wavparse/wavparse.vcproj
+	* gst/y4m/y4menc.vcproj
+	  more plugins supported under windows
+
+2004-07-26  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_ximage_new),
+	(gst_ximagesink_ximage_put), (gst_ximagesink_renegotiate_size),
+	(gst_ximagesink_chain), (gst_ximagesink_buffer_alloc):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xvimage_new),
+	(gst_xvimagesink_chain), (gst_xvimagesink_buffer_alloc):
+	  Add debugging statements.  Use the sizes as returned by the
+	  *CreateImage calls.
+
+2004-07-26  Johan Dahlin  <johan@gnome.org>
+
+	* gst/tcp/gsttcpclientsrc.c (gst_tcpclientsrc_get): Make sure that
+	the pad is negotiated.
+
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c (gst_ffmpegcolorspace_chain): Ditto
+
+2004-07-26  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* gst-libs/gst/colorbalance/colorbalance.vcproj:
+	* gst-libs/gst/idct/idct.vcproj:
+	* gst-libs/gst/media-info/media-info.vcproj:
+	* gst-libs/gst/mixer/mixer.vcproj:
+	* gst-libs/gst/navigation/navigation.vcproj:
+	* gst-libs/gst/play/play.vcproj:
+	* gst-libs/gst/propertyprobe/propertyprobe.vcproj:
+	* gst-libs/gst/resample/resample.vcproj:
+	* gst-libs/gst/tuner/tuner.vcproj:
+	* gst-libs/gst/video/video.vcproj:
+	* gst-libs/gst/xoverlay/xoverlay.vcproj:
+	  more plugins supported under windows
+
+2004-07-25 Iain <iain@prettypeople.org>
+
+	* gst/wavparse/gstwavparse.c (gst_wavparse_fmt): Set the caps on the
+	pad now rather than when the pad is created because state changes wipe
+	explicit caps (fixes #148043).
+
+2004-07-25  Sebastien Cote  <sc5@hermes.usherb.ca>
+
+	reviewed by Benjamin Otte  <otte@gnome.org>
+
+	* ext/mad/gstmad.c:
+	  fix mad plugin crashing on Sun (fixes #148289)
+
+2004-07-25  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* gst/avi/avi.def:
+	* gst/avi/avi.vcproj:
+	* gst/matroska/matroska.def:
+	* gst/matroska/matroska.vcproj:
+	  remove unused .def files
+
+2004-07-25  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* gst-libs/gst/audio/gstaudiofilter.c:
+	  Clean the local include
+
+2004-07-25  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* win32/gst.sln:
+	* gst-libs/gst/audio/audio.def:
+	* gst-libs/gst/audio/audio.vcproj:
+	* gst-libs/gst/audio/audiofilter.vcproj:
+	* gst-libs/gst/audio/riff.def:
+	* gst-libs/gst/audio/riff.vcproj:
+	* gst-libs/gst/gst-libs.def:
+	* gst-libs/gst/gst-libs.vcproj:
+	* gst/avi/avi.vcproj:
+	* gst/avi/avi.vcproj:
+	  Copy the files where needed after building, cleaner projects
+
+2004-07-25  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* gst/matroska/ebml-write.c:
+	  Fix some 64 bits constants to be glib friendly
+
+2004-07-24  Steve Lhomme  <steve.lhomme@free.fr>
+
+	* win32/gst.sln:
+	* gst-libs/gst/gst-libs.def:
+	* gst-libs/gst/gst-libs.vcproj:
+	* gst/matroska/matroska.def:
+	* gst/matroska/matroska.vcproj:
+	  Add the preliminary canvas to build plugins on Win32
+
+2004-07-23  Benjamin Otte  <otte@gnome.org>
+
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_link):
+	  don't enfore negotiation from source side, it breaks
+	  sinesrc ! audioconvert ! osssink
+
+2004-07-22  David Schleef  <ds@schleef.org>
+
+	* gst/typefind/gsttypefindfunctions.c: (plugin_init): Add typefind
+	for ELF files, since they can easily be recognized as audio/mpeg.
+	(bug #147441)
+
+2004-07-22  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/videoscale/videoscale.c: (gst_videoscale_setup),
+	(gst_videoscale_planar411), (gst_videoscale_scale_nearest_32bit),
+	(gst_videoscale_scale_nearest_24bit),
+	(gst_videoscale_scale_nearest_16bit):
+	  fix 16bit and 24bit for stride (24bit might need testing)
+	  don't pretend we do more than one algorithm
+
+2004-07-22  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* configure.ac:
+	* gst/Makefile.am:
+	* gst/multifilesink/Makefile.am:
+	* gst/multifilesink/gstmultifilesink.c:
+	(gst_multifilesink_get_formats),
+	(gst_multifilesink_get_query_types), (_do_init),
+	(gst_multifilesink_base_init), (gst_multifilesink_class_init),
+	(gst_multifilesink_init), (gst_multifilesink_dispose),
+	(gst_multifilesink_set_location), (gst_multifilesink_set_property),
+	(gst_multifilesink_get_property), (gst_multifilesink_open_file),
+	(gst_multifilesink_close_file), (gst_multifilesink_next_file),
+	(gst_multifilesink_pad_query), (gst_multifilesink_handle_event),
+	(gst_multifilesink_chain), (gst_multifilesink_change_state),
+	(gst_multifilesink_uri_get_type),
+	(gst_multifilesink_uri_get_protocols),
+	(gst_multifilesink_uri_get_uri), (gst_multifilesink_uri_set_uri),
+	(gst_multifilesink_uri_handler_init), (plugin_init):
+	* gst/multifilesink/gstmultifilesink.h:
+	* testsuite/Makefile.am:
+	* testsuite/multifilesink/Makefile.am:
+	* testsuite/multifilesink/fakesrc_test.c: (gst_newmedia_base_init),
+	(gst_newmedia_class_init), (gst_newmedia_init),
+	(gst_newmedia_chain), (gst_newmedia_trigger), (test_format),
+	(newfile_signal), (test_signal), (main):
+	multifilesink plugin for creating new files every time a new media
+	discontinuity event occurs
+
+2004-07-22  Wim Taymans  <wim@fluendo.com>
+
+	* gst/alpha/Makefile.am:
+	* gst/alpha/gstalphacolor.c: (gst_alpha_color_get_type),
+	(gst_alpha_color_base_init), (gst_alpha_color_class_init),
+	(gst_alpha_color_init), (gst_alpha_color_set_property),
+	(gst_alpha_color_get_property), (gst_alpha_color_sink_link),
+	(transform), (gst_alpha_color_chain),
+	(gst_alpha_color_change_state), (plugin_init):
+	Stupid plugin to to RGBA to AYUV conversion because none of
+	the colorspace plugins can handle that yet.
+
+2004-07-22  Wim Taymans  <wim@fluendo.com>
+
+	* examples/seeking/seek.c: (update_scale), (main):
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_get_type),
+	(gst_decode_bin_class_init), (gst_decode_bin_is_dynamic),
+	(gst_decode_bin_factory_filter), (compare_ranks), (print_feature),
+	(gst_decode_bin_init), (gst_decode_bin_dispose),
+	(find_compatibles), (close_pad_link), (try_to_link_1), (new_pad),
+	(no_more_pads), (close_link), (type_found),
+	(gst_decode_bin_set_property), (gst_decode_bin_get_property),
+	(plugin_init):
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_get_type),
+	(gst_play_base_bin_class_init), (gst_play_base_bin_init),
+	(gst_play_base_bin_dispose), (queue_overrun),
+	(gen_preroll_element), (remove_prerolls), (unknown_type),
+	(no_more_pads), (new_stream), (setup_source),
+	(gst_play_base_bin_set_property), (gst_play_base_bin_get_property),
+	(play_base_eos), (gst_play_base_bin_change_state),
+	(gst_play_base_bin_add_element),
+	(gst_play_base_bin_remove_element),
+	(gst_play_base_bin_mute_stream), (gst_play_base_bin_link_stream),
+	(gst_play_base_bin_unlink_stream),
+	(gst_play_base_bin_get_streaminfo):
+	* gst/playback/gstplaybin.c: (gen_video_element),
+	(gen_audio_element):
+	* gst/playback/gststreaminfo.h:
+	More playback updates, attempt to fix things after the state change
+	breakage.
+
+2004-07-22  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/videoscale/videoscale.c: (gst_videoscale_planar411),
+	(gst_videoscale_scale_nearest_16bit):
+	  comment algorithm
+
+2004-07-22  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/videotestsrc/gstvideotestsrc.c:
+	(gst_videotestsrc_class_init), (gst_videotestsrc_src_link),
+	(gst_videotestsrc_init), (gst_videotestsrc_get),
+	(gst_videotestsrc_set_pattern), (gst_videotestsrc_set_property),
+	(gst_videotestsrc_get_property):
+	* gst/videotestsrc/gstvideotestsrc.h:
+	* gst/videotestsrc/videotestsrc.c:
+	* gst/videotestsrc/videotestsrc.h:
+	  cleanup and commenting
+
+2004-07-21  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_init),
+	(gst_ogg_demux_get_formats), (gst_ogg_demux_src_query),
+	(gst_ogg_demux_src_event), (gst_ogg_demux_src_convert),
+	(gst_ogg_demux_handle_event), (gst_ogg_demux_seek_before),
+	(_find_chain_get_unknown_part), (_find_streams_check),
+	(gst_ogg_demux_push), (gst_ogg_pad_push):
+	* ext/theora/theoradec.c: (theora_get_formats),
+	(theora_dec_src_convert), (theora_dec_sink_convert),
+	(theora_dec_src_query), (theora_dec_src_event), (theora_dec_event),
+	(theora_dec_chain):
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_get_formats),
+	(vorbis_dec_convert), (vorbis_dec_src_query),
+	(vorbis_dec_src_event), (vorbis_dec_event):
+	More seeking fixes, oggdemux now supports seeking to time and
+	uses the downstream element to convert granulepos to time.
+	Seeking in theora-only ogg files now works.
+
+2004-07-21  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/theoradec.c: (gst_theora_dec_init),
+	(theora_get_formats), (theora_get_event_masks),
+	(theora_get_query_types), (theora_dec_src_convert),
+	(theora_dec_sink_convert), (theora_dec_src_query),
+	(theora_dec_src_event), (theora_dec_event), (theora_dec_chain):
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_get_formats),
+	(vorbis_get_event_masks), (vorbis_get_query_types),
+	(gst_vorbis_dec_init), (vorbis_dec_convert),
+	(vorbis_dec_src_query), (vorbis_dec_src_event), (vorbis_dec_event):
+	Added query/convert/formats functions to vorbis and theora decoders
+	so that the outside world can use them too. Fixed seeking on an
+	ogg/theora/vorbis file by disabling the seeking seeking on the
+	theora srcpad.
+
+2004-07-21  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_ximage_new),
+	(gst_ximagesink_renegotiate_size), (gst_ximagesink_sink_link),
+	(gst_ximagesink_chain), (gst_ximagesink_set_xwindow_id): Optimize
+	images creation for both elements. We don't create the image on caps
+	nego or renego, we just destroy the internal one if present if it does
+	not match the needs. The chain function takes care of creating a new
+	image when needed.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xvimage_new),
+	(gst_xvimagesink_xwindow_decorate), (gst_xvimagesink_sink_link),
+	(gst_xvimagesink_chain), (gst_xvimagesink_buffer_alloc),
+	(gst_xvimagesink_set_xwindow_id): Additionally xvimage now contains
+	the image format information. The buffer pool checks for the context
+	image format and discard images with different formats.
+	* sys/xvimage/xvimagesink.h: Adding im_format in the xvimage structure.
+
+2004-07-21  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+	(gst_ffmpegcolorspace_chain):
+	  no point in doing any chaining if the pad we want to push from
+	  isn't usable.
+
+2004-07-20  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_audio_caps_with_data):
+	  Fix double end-to-native symbol conversion (#148021).
+
+2004-07-20  David Schleef  <ds@schleef.org>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xwindow_decorate):
+	Don't use an Atom that doesn't exist.
+
+2004-07-20  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_class_init),
+	(gst_multifdsink_add), (gst_multifdsink_get_stats),
+	(gst_multifdsink_client_remove),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_queue_buffer):
+	* gst/tcp/gstmultifdsink.h:
+	More multifdsink stats. Avoid deadlock by releasing locks
+	before sending out a signal.
+
+2004-07-20  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* po/LINGUAS:
+	* po/hu.po:
+	  added Hungarian translation (Laszlo Dvornik)
+
+2004-07-20  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_class_init),
+	(gst_multifdsink_add), (gst_multifdsink_client_remove),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_queue_buffer):
+	* gst/tcp/gsttcp-marshal.list:
+	Fixed the stupid marshal definition.
+
+2004-07-20  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_class_init),
+	(gst_multifdsink_init), (gst_multifdsink_add),
+	(gst_multifdsink_client_remove),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_queue_buffer), (gst_multifdsink_chain),
+	(gst_multifdsink_set_property), (gst_multifdsink_get_property),
+	(gst_multifdsink_init_send):
+	* gst/tcp/gstmultifdsink.h:
+	Added more stats, added timeout for a client, fixed some typos
+	and added some comments.
+
+2004-07-20  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_class_init),
+	(gst_multifdsink_add), (gst_multifdsink_get_stats),
+	(gst_multifdsink_client_remove),
+	(gst_multifdsink_handle_client_write):
+	* gst/tcp/gstmultifdsink.h:
+	* gst/tcp/gsttcp-marshal.list:
+	Added get_stats method that returns a GValueArray of
+	stats values.
+
+2004-07-19  Benjamin Otte  <otte@gnome.org>
+
+	* ext/ladspa/gstladspa.c: (gst_ladspa_base_init):
+	  make sure longname, description and author are valid UTF-8
+
+2004-07-19  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_change_state),
+	(gst_ximagesink_set_property):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_change_state),
+	(gst_xvimagesink_set_property):
+	  make sure SYNCHRONOUS is respected after getting the X context
+
+2004-07-18  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/matroska/matroska-demux.c:
+	(gst_matroska_demux_handle_src_event),
+	(gst_matroska_demux_parse_blockgroup):
+	* gst/matroska/matroska-ids.h:
+	  add BlockReference tag and ignore it to clear out log.
+	  ignore NAVIGATION events to clear out log.
+
+2004-07-18  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_class_init),
+	(gst_matroska_demux_add_stream):
+	* gst/matroska/matroska-mux.c: (gst_matroska_mux_class_init):
+	  add debug categories
+
+2004-07-16  Wim Taymans  <wim@fluendo.com>
+
+	* ext/libpng/Makefile.am:
+	* ext/libpng/gstpng.c: (plugin_init):
+	* ext/libpng/gstpngdec.c: (user_error_fn), (user_warning_fn),
+	(gst_pngdec_get_type), (gst_pngdec_base_init),
+	(gst_pngdec_class_init), (gst_pngdec_sinklink), (gst_pngdec_init),
+	(gst_pngdec_src_getcaps), (user_read_data), (gst_pngdec_chain):
+	* ext/libpng/gstpngdec.h:
+	Added png decoder.
+
+2004-07-16  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_handle_xerror),
+	(gst_ximagesink_check_xshm_calls), (gst_ximagesink_ximage_new),
+	(gst_ximagesink_ximage_destroy), (gst_ximagesink_sink_link),
+	(gst_ximagesink_chain), (gst_ximagesink_buffer_free),
+	(gst_ximagesink_buffer_alloc):
+	* sys/ximage/ximagesink.h:
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_check_xshm_calls),
+	(gst_xvimagesink_xvimage_new), (gst_xvimagesink_xvimage_destroy),
+	(gst_xvimagesink_chain), (gst_xvimagesink_buffer_free),
+	(gst_xvimagesink_buffer_alloc):
+	* sys/xvimage/xvimagesink.h: Getting the 2 video sinks synchronized
+	again. Using internal data pointer of the x(v)image to store image's
+	data to be coherent with the buffer alloc mechanism. Investigated the
+	image destruction code to be sure that everything gets freed correctly.
+
+2004-07-16  Wim Taymans  <wim@fluendo.com>
+
+	* gst-libs/gst/riff/riff-read.c:
+	(gst_riff_read_strf_vids_with_data),
+	(gst_riff_read_strf_auds_with_data):
+	* gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query),
+	(gst_avi_demux_add_stream), (gst_avi_demux_stream_header):
+	Make sure we don't create 0 sized subbuffers in riff-read.
+	Signal the no more pads signal after reading the avi header.
+
+2004-07-16  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_get_type),
+	(gst_decode_bin_class_init), (gst_decode_bin_is_dynamic),
+	(gst_decode_bin_factory_filter), (compare_ranks), (print_feature),
+	(gst_decode_bin_init), (gst_decode_bin_dispose),
+	(find_compatibles), (close_pad_link), (try_to_link_1), (new_pad),
+	(no_more_pads), (close_link), (type_found),
+	(gst_decode_bin_set_property), (gst_decode_bin_get_property),
+	(gst_decode_bin_change_state), (plugin_init):
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_get_type),
+	(gst_play_base_bin_class_init), (gst_play_base_bin_init),
+	(gst_play_base_bin_dispose), (queue_overrun),
+	(gen_preroll_element), (remove_prerolls), (unknown_type),
+	(no_more_pads), (new_stream), (setup_source),
+	(gst_play_base_bin_set_property), (gst_play_base_bin_get_property),
+	(play_base_eos), (gst_play_base_bin_change_state),
+	(gst_play_base_bin_add_element),
+	(gst_play_base_bin_remove_element),
+	(gst_play_base_bin_mute_stream), (gst_play_base_bin_link_stream),
+	(gst_play_base_bin_unlink_stream),
+	(gst_play_base_bin_get_streaminfo):
+	* gst/playback/gstplaybasebin.h:
+	Better error recovery. Added configurable preroll queue size. Faster
+	detection of no-more-pads.
+
+2004-07-16  Wim Taymans  <wim@fluendo.com>
+
+	* gst-libs/gst/video/video.h:
+	Added 32 bits RGBA. Not sure if we should use another mime-type
+	for alpha rgb. Currently the presence of the alpha_mask property
+	signals an alpha channel.
+
+2004-07-16  Wim Taymans  <wim@fluendo.com>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xcontext_get):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_xv_support):
+	FPS seems to be 0.0 to MAX everywhere else.
+
+2004-07-15  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_video_caps_with_data):
+	  mp42/mp43 (no caps) exist too.
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_video_caps):
+	  Set pixel_width/height; we've got them in-caps.
+	* gst/typefind/gsttypefindfunctions.c: (plugin_init):
+	* gst/wavparse/gstwavparse.c: (plugin_init):
+	  Both are valid primary.
+	* sys/oss/gstossmixer.c:
+	  Remove i18n hack and enable translations.
+
+2004-07-15  Benjamin Otte  <otte@gnome.org>
+
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_check_xshm_calls),
+	(gst_xvimagesink_xvimage_new), (gst_xvimagesink_xvimage_destroy):
+	  fix for non-shm xv. Original patch by Tim Ringenbach (fixes #147248)
+
+2004-07-15  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_open_audio),
+	(gst_alsa_sw_params_dump), (gst_alsa_hw_params_dump),
+	(gst_alsa_close_audio):
+	  disable some of the debugging code for now. Writing debugging to a
+	  buffer is broken in current alsalib releases.
+
+2004-07-12  Benjamin Otte  <otte@gnome.org>
+
+	* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_alloc_buffer):
+	  use bufferpools
+
+2004-07-14  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/theora/theoradec.c: (gst_theora_dec_class_init),
+	(theora_dec_src_query), (theora_dec_event):
+	* ext/theora/theoraenc.c: (gst_theora_enc_class_init):
+	  add debugging categories.  Remove \n's.
+
+2004-07-13  Johan Dahlin  <johan@gnome.org>
+
+	* gst/playback/gstplaybin.c (gst_play_bin_set_property)
+	(gst_play_bin_get_property): Impl.
+
+2004-07-13  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_seek_before):
+	When trying to find the stream length, seek back N pages
+	instead of just one, where N is the number of streams in
+	the current chain.
+
+2004-07-13  Wim Taymans  <wim@fluendo.com>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_audio_caps_with_data),
+	(gst_riff_create_audio_caps),
+	(gst_riff_create_audio_template_caps):
+	* gst-libs/gst/riff/riff-media.h:
+	* gst-libs/gst/riff/riff-read.c:
+	(gst_riff_read_strf_vids_with_data),
+	(gst_riff_read_strf_auds_with_data), (gst_riff_read_strf_auds):
+	* gst-libs/gst/riff/riff-read.h:
+	* gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query),
+	(gst_avi_demux_add_stream):
+	Set codec_data on caps for avidemuxer.
+
+2004-07-12  David Schleef  <ds@schleef.org>
+
+	* configure.ac: Fix test for Objective C
+
+2004-07-12  Jan Schmidt  <thaytan@mad.scientist.com>
+	* ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_get_capslist),
+	(gst_gdk_pixbuf_chain):
+	  Add svg and pcx to template caps, and ensure that getcaps returns a
+	  subset of the template caps.
+	  Copy each row manually for output, as gdkpixbuf may pad the
+	  rowstride to a 32-bit word boundary.
+
+2004-07-12  Wim Taymans  <wim@fluendo.com>
+
+	* gst-libs/gst/riff/riff-media.c: (gst_riff_create_audio_caps),
+	(gst_riff_create_video_template_caps):
+	Fix the template caps to include some more media types.
+
+2004-07-12  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_get_type),
+	(gst_decode_bin_class_init), (gst_decode_bin_factory_filter),
+	(compare_ranks), (print_feature), (gst_decode_bin_init),
+	(gst_decode_bin_dispose), (find_compatibles), (close_pad_link),
+	(try_to_link_1), (new_pad), (close_link), (type_found),
+	(gst_decode_bin_set_property), (gst_decode_bin_get_property),
+	(gst_decode_bin_change_state), (plugin_init):
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_get_type),
+	(gst_play_base_bin_class_init), (gst_play_base_bin_init),
+	(gst_play_base_bin_dispose), (queue_overrun),
+	(gen_preroll_element), (remove_prerolls), (no_more_pads),
+	(new_stream), (setup_source), (gst_play_base_bin_set_property),
+	(gst_play_base_bin_get_property), (play_base_eos),
+	(gst_play_base_bin_change_state), (gst_play_base_bin_add_element),
+	(gst_play_base_bin_remove_element),
+	(gst_play_base_bin_mute_stream), (gst_play_base_bin_link_stream),
+	(gst_play_base_bin_unlink_stream),
+	(gst_play_base_bin_get_streaminfo):
+	* gst/playback/gstplaybasebin.h:
+	* gst/playback/gstplaybin.c: (gst_play_bin_get_type),
+	(gst_play_bin_class_init), (gst_play_bin_init),
+	(gst_play_bin_dispose), (gst_play_bin_set_property),
+	(gst_play_bin_get_property), (gen_video_element),
+	(gen_audio_element), (remove_sinks), (setup_sinks),
+	(gst_play_bin_change_state), (gst_play_bin_get_event_masks),
+	(gst_play_bin_send_event), (gst_play_bin_get_formats),
+	(gst_play_bin_convert), (gst_play_bin_get_query_types),
+	(gst_play_bin_query), (plugin_init):
+	* gst/playback/test4.c: (main):
+	More fixes on reusing of the element.
+
+2004-07-11  Benjamin Otte  <otte@gnome.org>
+
+	* ext/mad/gstmad.c: (normal_seek):
+	  allow seeking for other methods than just SET
+
+2004-07-11  Andy Wingo  <wingo@pobox.com>
+
+	* gst/audioconvert/gstaudioconvert.c (gst_audio_convert_link): For
+	float, "any" caps -> buffer_frames=[0,MAX].
+
+	* gst/interleave/interleave.c (interleave_getcaps): Seems the core
+	doesn't intersect our caps with the template any more. Do it
+	ourselves.
+	(interleave_buffered_loop): Use g_newa instead of malloc/free.
+
+2004-07-09  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_get_type),
+	(gst_decode_bin_class_init), (gst_decode_bin_factory_filter),
+	(compare_ranks), (print_feature), (gst_decode_bin_init),
+	(gst_decode_bin_dispose), (find_compatibles), (close_pad_link),
+	(try_to_link_1), (new_pad), (close_link), (type_found),
+	(gst_decode_bin_set_property), (gst_decode_bin_get_property),
+	(gst_decode_bin_change_state), (plugin_init):
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_get_type),
+	(gst_play_base_bin_class_init), (gst_play_base_bin_init),
+	(gst_play_base_bin_dispose), (queue_overrun),
+	(gen_preroll_element), (remove_prerolls), (no_more_pads),
+	(new_stream), (setup_source), (gst_play_base_bin_set_property),
+	(gst_play_base_bin_get_property), (play_base_eos),
+	(gst_play_base_bin_change_state), (gst_play_base_bin_add_element),
+	(gst_play_base_bin_remove_element),
+	(gst_play_base_bin_mute_stream), (gst_play_base_bin_link_stream),
+	(gst_play_base_bin_unlink_stream),
+	(gst_play_base_bin_get_streaminfo):
+	* gst/playback/gstplaybasebin.h:
+	* gst/playback/gstplaybin.c: (gst_play_bin_get_type),
+	(gst_play_bin_class_init), (gst_play_bin_init),
+	(gst_play_bin_dispose), (gst_play_bin_set_property),
+	(gst_play_bin_get_property), (gen_video_element),
+	(gen_audio_element), (remove_sinks), (setup_sinks),
+	(gst_play_bin_change_state), (gst_play_bin_get_event_masks),
+	(gst_play_bin_send_event), (gst_play_bin_get_formats),
+	(gst_play_bin_convert), (gst_play_bin_get_query_types),
+	(gst_play_bin_query), (plugin_init):
+	* gst/playback/test4.c: (main):
+	Work on object reuse and seeking.
+
+2004-07-09  Wim Taymans  <wim@fluendo.com>
+
+	* examples/seeking/seek.c: (iterate):
+	Don't consume all CPU in the idle loop.
+
+2004-07-09  Wim Taymans  <wim@fluendo.com>
+
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_new_output_pad),
+	(gst_mpeg_demux_parse_packet), (gst_mpeg_demux_process_private):
+	Add pad to element *after* setting the pad functions so that
+	the scheduler can use the correct ones.
+
+2004-07-09  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/theoradec.c: (theora_dec_from_granulepos),
+	(theora_dec_src_query), (theora_dec_src_event), (theora_dec_chain):
+	Sync to keyframe after seek
+
+2004-07-09  Thomas Vander Stichele  <thomas (at) apestaart (dot) org>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_change_state):
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event),
+	(gst_alsa_sink_loop), (gst_alsa_sink_change_state):
+	* ext/alsa/gstalsasrc.c: (gst_alsa_src_change_state):
+	* ext/libvisual/visual.c: (gst_visual_change_state):
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_change_state):
+	* ext/theora/theoradec.c: (theora_dec_change_state):
+	* ext/theora/theoraenc.c: (theora_enc_change_state):
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_change_state):
+	* gst-libs/gst/navigation/navigation.c:
+	* gst/adder/gstadder.c: (gst_adder_change_state):
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_chain),
+	(gst_audio_convert_get_buffer):
+	* gst/multipart/multipartdemux.c:
+	(gst_multipart_demux_change_state):
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_change_state):
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_change_state):
+	* gst/playback/gstplaybin.c: (gst_play_bin_change_state):
+	* gst/videoscale/gstvideoscale.c:
+	(gst_videoscale_handle_src_event):
+	* gst/volume/gstvolume.c: (volume_chain_int16):
+	  don't assert in state change, this should be done by the base
+	  GstElement class.
+	  various debugging fixes.
+
+2004-07-08  Thomas Vander Stichele  <thomas (at) apestaart (dot) org>
+
+	* configure.ac:
+	* gst-libs/gst/play/play.c: (gst_play_pipeline_setup),
+	(gst_play_dispose), (gst_play_set_location),
+	(gst_play_set_data_src), (gst_play_set_video_sink),
+	(gst_play_set_audio_sink), (gst_play_set_visualization),
+	(gst_play_connect_visualization), (gst_play_get_sink_element),
+	(gst_play_get_all_by_interface):
+	* gst-libs/gst/play/play.h:
+	  add new method to get elements implementing an interface.
+	  add various error logging
+
+2004-07-08  Wim Taymans  <wim@fluendo.com>
+
+	* examples/seeking/seek.c: (make_dv_pipeline), (make_avi_pipeline),
+	(make_mpeg_pipeline), (make_mpegnt_pipeline),
+	(make_playerbin_pipeline), (query_durations_elems),
+	(query_durations_pads), (query_positions_elems),
+	(query_positions_pads), (update_scale), (iterate), (stop_seek),
+	(main):
+	Added playbin seeking example.
+
+2004-07-08  Thomas Vander Stichele  <thomas (at) apestaart (dot) org>
+
+	* gst-libs/gst/play/play.c: (gst_play_set_location),
+	(gst_play_set_data_src), (gst_play_set_video_sink),
+	(gst_play_set_audio_sink), (gst_play_set_visualization),
+	(gst_play_connect_visualization), (gst_play_get_framerate):
+	  use a macro to look up elements from hash table
+
+2004-07-08  Thomas Vander Stichele  <thomas (at) apestaart (dot) org>
+
+	* gst-libs/gst/play/play.c: (gst_play_pipeline_setup),
+	(gst_play_get_length_callback), (gst_play_set_location),
+	(gst_play_seek_to_time), (gst_play_set_data_src),
+	(gst_play_set_video_sink), (gst_play_set_audio_sink),
+	(gst_play_set_visualization), (gst_play_connect_visualization),
+	(gst_play_get_sink_element):
+	- add debugging info
+	- fix looking up sink elements by iterating over complete caps
+	- put everything except for source and autoplugger in a complete bin
+
+2004-07-08  Thomas Vander Stichele  <thomas (at) apestaart (dot) org>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_drain_audio):
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_flush_one_pad),
+	(gst_alsa_sink_check_event), (gst_alsa_sink_mmap),
+	(gst_alsa_sink_write), (gst_alsa_sink_loop):
+	* ext/alsa/gstalsasink.h:
+	- add debugging info
+	- clean up schizophrenia of data/buffer/event
+	- fix double event unref error
+
+2004-07-08  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/Makefile.am:
+	Add headers to noinst
+
+2004-07-08  Thomas Vander Stichele  <thomas (at) apestaart (dot) org>
+
+	* tools/gst-launch-ext-m.m:
+	* tools/gst-launch-ext.1.in:
+	  convert to the third millenium
+
+2004-07-07  David Schleef  <ds@schleef.org>
+
+	* sys/dxr3/Makefile.am: noinst_SOURCES should be nodist_SOURCES
+
+2004-07-07  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/Makefile.am:
+	* gst/playback/README:
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_get_type),
+	(gst_decode_bin_class_init), (gst_decode_bin_factory_filter),
+	(compare_ranks), (print_feature), (gst_decode_bin_init),
+	(gst_decode_bin_dispose), (find_compatibles), (close_pad_link),
+	(try_to_link_1), (new_pad), (close_link), (type_found),
+	(gst_decode_bin_set_property), (gst_decode_bin_get_property),
+	(plugin_init):
+	* gst/playback/gstplaybasebin.c: (gst_play_base_bin_get_type),
+	(gst_play_base_bin_class_init), (gst_play_base_bin_init),
+	(gst_play_base_bin_dispose), (rebuild_pipeline), (queue_overrun),
+	(gen_preroll_element), (no_more_pads), (new_stream),
+	(setup_source), (gst_play_base_bin_set_property),
+	(gst_play_base_bin_get_property), (gst_play_base_bin_change_state),
+	(gst_play_base_bin_add_element),
+	(gst_play_base_bin_remove_element),
+	(gst_play_base_bin_mute_stream), (gst_play_base_bin_link_stream),
+	(gst_play_base_bin_unlink_stream),
+	(gst_play_base_bin_get_streaminfo):
+	* gst/playback/gstplaybasebin.h:
+	* gst/playback/gstplaybin.c: (gst_play_bin_get_type),
+	(gst_play_bin_class_init), (gst_play_bin_init),
+	(gst_play_bin_dispose), (gst_play_bin_set_property),
+	(gst_play_bin_get_property), (gen_video_element),
+	(gen_audio_element), (setup_sinks), (gst_play_bin_change_state),
+	(gst_play_bin_get_event_masks), (gst_play_bin_send_event),
+	(gst_play_bin_get_formats), (gst_play_bin_convert),
+	(gst_play_bin_get_query_types), (gst_play_bin_query),
+	(plugin_init):
+	* gst/playback/gststreaminfo.c: (gst_stream_type_get_type),
+	(gst_stream_info_get_type), (gst_stream_info_class_init),
+	(gst_stream_info_init), (gst_stream_info_new),
+	(gst_stream_info_dispose), (gst_stream_info_set_property),
+	(gst_stream_info_get_property):
+	* gst/playback/gststreaminfo.h:
+	* gst/playback/test.c: (gen_video_element), (gen_audio_element),
+	(main):
+	* gst/playback/test2.c: (main):
+	* gst/playback/test3.c: (update_scale), (main):
+	More playbin fixes. Added README. Do better element filtering.
+	Added base class to preroll media. Added test apps.
+
+2004-07-07  Thomas Vander Stichele  <thomas (at) apestaart (dot) org>
+
+	* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_flush_decoder):
+	* ext/mpeg2dec/gstmpeg2dec.h:
+	  various debugging improvements.  Reset stream to next picture
+	  instead of sequence header, otherwise seeks cannot work.
+
+2004-07-07  Wim Taymans  <wim@fluendo.com>
+
+	* gst/videobox/gstvideobox.c: (gst_video_box_fill_get_type),
+	(gst_video_box_class_init), (gst_video_box_set_property),
+	(gst_video_box_i420), (gst_video_box_ayuv), (gst_video_box_chain):
+	Use pad_alloc where possible.
+
+2004-07-07  Wim Taymans  <wim@fluendo.com>
+
+	* sys/oss/gstosselement.c: (gst_osselement_reset),
+	(gst_osselement_parse_caps):
+	* sys/oss/gstosselement.h:
+	* sys/oss/gstosssrc.c: (gst_osssrc_get):
+	Fix offset on osssrc.
+
+2004-07-07  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/theora.c: (plugin_init):
+	* ext/theora/theoradec.c: (theora_dec_from_granulepos),
+	(theora_dec_src_query), (theora_dec_chain):
+	* ext/theora/theoraenc.c: (gst_theora_enc_class_init),
+	(theora_enc_sink_link), (theora_buffer_from_packet),
+	(theora_push_packet), (theora_enc_chain):
+	Fix theora granulepos calculation.
+	Fix overflow in duration/position calculation.
+	Bump rank to PRIMARY for theoradec.
+	Use granulepos of last packet to calculate position.
+	Set keyframe flag on buffers when needed.
+
+2004-07-06  David Schleef  <ds@schleef.org>
+
+	* gst/playback/Makefile.am: 'test' in bin_PROGRAMS?  Are you
+	serious?  (Fixed, obviously.)
+
+2004-07-06  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* po/LINGUAS:
+	* po/cs.po:
+	  added Czech translation (Miloslav Trmac)
+
+2004-07-05  Wim Taymans  <wim@fluendo.com>
+
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_get_type),
+	(gst_decode_bin_class_init), (gst_decode_bin_factory_filter),
+	(compare_ranks), (gst_decode_bin_init), (gst_decode_bin_dispose),
+	(find_compatibles), (close_pad_link), (try_to_link_1), (new_pad),
+	(close_link), (type_found), (gst_decode_bin_set_property),
+	(gst_decode_bin_get_property), (gst_decode_bin_get_event_masks),
+	(gst_decode_bin_send_event), (gst_decode_bin_get_formats),
+	(gst_decode_bin_convert), (gst_decode_bin_get_query_types),
+	(gst_decode_bin_query), (plugin_init):
+	* gst/playback/gstplaybin.c: (gst_play_bin_get_type),
+	(gst_play_bin_class_init), (gst_play_bin_init),
+	(gst_play_bin_dispose), (rebuild_pipeline), (get_audio_element),
+	(get_video_element), (new_pad), (setup_source),
+	(gst_play_bin_set_property), (gst_play_bin_get_property),
+	(gst_play_bin_change_state), (gst_play_bin_add_element),
+	(gst_play_bin_remove_element), (gst_play_bin_get_event_masks),
+	(gst_play_bin_send_event), (gst_play_bin_get_formats),
+	(gst_play_bin_convert), (gst_play_bin_get_query_types),
+	(gst_play_bin_query), (gst_play_bin_get_clock), (plugin_init):
+	* gst/playback/test.c: (main):
+	More fixes, cleaned up playbin, make it use decodebin. Added
+	threaded property to playbin.
+
+2004-07-05  Wim Taymans  <wim@fluendo.com>
+
+	* configure.ac:
+	* gst/playback/Makefile.am:
+	* gst/playback/decodetest.c: (main):
+	* gst/playback/gstdecodebin.c: (gst_decode_bin_get_type),
+	(gst_decode_bin_class_init), (gst_decode_bin_factory_filter),
+	(compare_ranks), (gst_decode_bin_init), (gst_decode_bin_dispose),
+	(find_compatibles), (close_pad_link), (try_to_link_1), (new_pad),
+	(close_link), (type_found), (gst_decode_bin_set_property),
+	(gst_decode_bin_get_property), (gst_decode_bin_change_state),
+	(gst_decode_bin_get_event_masks), (gst_decode_bin_send_event),
+	(gst_decode_bin_get_formats), (gst_decode_bin_convert),
+	(gst_decode_bin_get_query_types), (gst_decode_bin_query),
+	(plugin_init):
+	* gst/playback/gstplaybin.c: (gst_play_bin_get_type),
+	(gst_play_bin_class_init), (gst_play_bin_init),
+	(gst_play_bin_dispose), (gen_default_output), (rebuild_pipeline),
+	(collect_sink_pads), (find_compatibles), (close_pad_link),
+	(try_to_link_1), (new_pad), (close_link), (type_found),
+	(setup_source), (gst_play_bin_set_property),
+	(gst_play_bin_get_property), (gst_play_bin_factory_filter),
+	(compare_ranks), (gst_play_bin_collect_factories),
+	(gst_play_bin_change_state), (gst_play_bin_add_element),
+	(gst_play_bin_remove_element), (gst_play_bin_get_event_masks),
+	(gst_play_bin_send_event), (gst_play_bin_get_formats),
+	(gst_play_bin_convert), (gst_play_bin_get_query_types),
+	(gst_play_bin_query), (gst_play_bin_get_clock), (plugin_init):
+	* gst/playback/test.c: (main):
+	Added some playback helper elements and some test apps, very alpha
+	still.
+
+2004-07-04  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_xrun_recovery):
+	  only restart audio when we indeed have an xrun to fix repeated
+	  xruns. Fix suggested by Giuliano Pochini.
+
+2004-07-03  David Schleef  <ds@schleef.org>
+
+	* ext/alsa/gstalsaplugin.c: (gst_alsa_error_wrapper): Disable
+	call to gst_debug_log() if debugging is disabled (bug #145118)
+
+2004-07-03  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_xrun_recovery):
+	  use our own functions for restarting the alsa device.
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event):
+	  I should apply patches myself - use MIN for the third argument, not
+	  the second, this fixes seeking
+
+2004-07-02  David Schleef  <ds@schleef.org>
+
+	* ext/flac/gstflacdec.c: (gst_flacdec_class_init),
+	(gst_flacdec_write):  Actually, GST_PAD_CAPS() has nothing to
+	do with the logic.
+
+2004-07-02  David Schleef  <ds@schleef.org>
+
+	* ext/flac/gstflacdec.c: (gst_flacdec_write):  Set duration on
+	output buffers.  Fix logic mistake.  (bug #144866)
+
+2004-07-02  David Schleef  <ds@schleef.org>
+
+	* gst-libs/gst/xoverlay/Makefile.am: xoverlay no longer depends
+	on X.  (bug #144753)
+
+2004-07-02  David Schleef  <ds@schleef.org>
+
+	* gst/wavenc/gstwavenc.c: (gst_wavenc_setup),
+	(gst_wavenc_stop_file): Switch to GST_WRITE_UINT32_LE macros
+	(bug #144624)
+	* sys/oss/gstosselement.c: (gst_osselement_probe_caps),
+	(gst_osselement_rate_probe_check): Add another workaround for
+	buggy drivers (bug #145336)
+
+2004-07-02  David Schleef  <ds@schleef.org>
+
+	* gst/tcp/gstmultifdsink.c: (gst_multifdsink_handle_client_write):
+	Most systems don't have MSG_NOSIGNAL.
+
+2004-07-02  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* Makefile.am:
+	* gst-libs/gst/colorbalance/Makefile.am:
+	* gst-libs/gst/mixer/Makefile.am:
+	* gst-libs/gst/play/Makefile.am:
+	* gst-libs/gst/tuner/Makefile.am:
+	  (hopefully) fix both install and dist and make error message useful.
+	  needs testing across automakes.
+
+2004-07-02  Benjamin Otte  <otte@gnome.org>
+
+	* ext/ogg/gstogg.c: (plugin_init):
+	  we require bytestream now
+	* ext/ogg/gstoggdemux.c:
+	  huge diff to implement chain setup in a fast and generic way. This
+	  improves tag reading and startup of huge files (read: Theora videos)
+	  quite a bit. It probably contains bugs, too, so please test.
+	  Seeking is not improved to the fast method.
+
+2004-06-29  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_pad_push):
+	* ext/ogg/gstoggmux.c:
+	Fix memleak in oggdemux when running unconnected pads.
+	doc update in mux, start working on keyframe mode.
+
+2004-06-29  Benjamin Otte  <otte@gnome.org>
+
+	* sys/oss/gstosssink.c:
+	* sys/oss/gstosssrc.c:
+	  advertise correct template caps - we indeed do non-native endianness
+	  and 8bit audio has no endianness
+	* sys/ximage/ximagesink.c: (gst_ximagesink_getcaps):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_getcaps):
+	  avoid (wrong) duplications in getcaps function and return
+	  template caps
+
+2004-06-29  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstmultifdsink.c: (gst_recover_policy_get_type),
+	(gst_multifdsink_class_init), (gst_multifdsink_add),
+	(gst_multifdsink_remove), (gst_multifdsink_clear),
+	(gst_multifdsink_client_remove),
+	(gst_multifdsink_handle_client_read),
+	(gst_multifdsink_client_queue_data),
+	(gst_multifdsink_client_queue_caps),
+	(gst_multifdsink_client_queue_buffer),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_recover_client), (gst_multifdsink_queue_buffer),
+	(gst_multifdsink_handle_clients), (gst_multifdsink_thread),
+	(gst_multifdsink_init_send), (gst_multifdsink_close):
+	Fix wrong GList iteration that could crash the server when
+	more then 2 clients disconnect at the same time. Read all the
+	pending commands in one batch to recover from command storms under
+	very heavy load.
+
+2004-06-28  Wim Taymans  <wim@fluendo.com>
+
+	* gst/videomixer/videomixer.c: (gst_videomixer_pad_get_type),
+	(gst_videomixer_pad_class_init), (gst_videomixer_pad_get_property),
+	(gst_videomixer_pad_set_property),
+	(gst_videomixer_pad_sinkconnect), (gst_videomixer_pad_init),
+	(gst_video_mixer_background_get_type), (gst_videomixer_get_type),
+	(gst_videomixer_class_init), (gst_videomixer_init),
+	(gst_videomixer_request_new_pad), (gst_videomixer_blend_ayuv_i420),
+	(pad_zorder_compare), (gst_videomixer_sort_pads),
+	(gst_videomixer_fill_checker), (gst_videomixer_fill_color),
+	(gst_videomixer_fill_queues), (gst_videomixer_blend_buffers),
+	(gst_videomixer_update_queues), (gst_videomixer_loop),
+	(plugin_init):
+	Avoid divide by zero, choose masterpad as the pad with the highest
+	framerate.
+
+2004-06-27  Julien Moutte  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xwindow_decorate),
+	(gst_ximagesink_xwindow_new):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xwindow_decorate),
+	(gst_xvimagesink_xwindow_new): I prefer locking the mutex in the
+	function directly. We might want to call it from somewhere else one day.
+
+2004-06-27  Julien Moutte  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xwindow_decorate),
+	(gst_ximagesink_xwindow_new):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xwindow_decorate),
+	(gst_xvimagesink_xwindow_new): Trying to fix the random behaviour of
+	window decorations.
+
+2004-06-27  Wim Taymans  <wim@fluendo.com>
+
+	* ext/dv/gstdvdec.c: (gst_dvdec_class_init), (gst_dvdec_init),
+	(gst_dvdec_video_getcaps), (gst_dvdec_video_link),
+	(gst_dvdec_push), (gst_dvdec_loop), (gst_dvdec_change_state),
+	(gst_dvdec_set_property), (gst_dvdec_get_property):
+	* ext/dv/gstdvdec.h:
+	Implement drop_factor property to lower the framerate with
+	a factor.
+
+2004-06-27  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/colorbalance/Makefile.am:
+	* gst-libs/gst/mixer/Makefile.am:
+	* gst-libs/gst/play/Makefile.am:
+	* gst-libs/gst/tuner/Makefile.am:
+	  unbreak Company's fix that didn't install the -enum.h files
+
+2004-06-27  Wim Taymans  <wim@fluendo.com>
+
+	* ext/dv/gstdvdec.c: (gst_dvdec_push), (gst_dvdec_loop),
+	(gst_dvdec_change_state):
+	* ext/dv/gstdvdec.h:
+	Fix timestamp, duration and offset of the buffers.
+
+2004-06-27  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gstmultifdsink.c: (gst_recover_policy_get_type),
+	(gst_multifdsink_class_init), (gst_multifdsink_add),
+	(gst_multifdsink_remove), (gst_multifdsink_clear),
+	(gst_multifdsink_client_remove),
+	(gst_multifdsink_handle_client_read),
+	(gst_multifdsink_client_queue_data),
+	(gst_multifdsink_client_queue_caps),
+	(gst_multifdsink_client_queue_buffer),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_recover_client), (gst_multifdsink_queue_buffer),
+	(gst_multifdsink_handle_clients), (gst_multifdsink_thread),
+	(gst_multifdsink_init_send), (gst_multifdsink_close):
+	* gst/tcp/gstmultifdsink.h:
+	* gst/tcp/gsttcpserversink.c:
+	(gst_tcpserversink_handle_server_read),
+	(gst_tcpserversink_handle_select), (gst_tcpserversink_close):
+	More multifdsink fixes, more recovery policy fixes.
+	Removed stupid g_print
+
+2004-06-26  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/Makefile.am:
+	* gst/tcp/gstmultifdsink.c: (gst_recover_policy_get_type),
+	(gst_multifdsink_get_type), (gst_multifdsink_base_init),
+	(gst_multifdsink_class_init), (gst_multifdsink_init),
+	(gst_multifdsink_debug_fdset), (gst_multifdsink_client_remove),
+	(gst_multifdsink_handle_client_read),
+	(gst_multifdsink_client_queue_data),
+	(gst_multifdsink_client_queue_caps),
+	(gst_multifdsink_client_queue_buffer),
+	(gst_multifdsink_handle_client_write),
+	(gst_multifdsink_recover_client), (gst_multifdsink_queue_buffer),
+	(gst_multifdsink_handle_clients), (gst_multifdsink_thread),
+	(gst_multifdsink_chain), (gst_multifdsink_set_property),
+	(gst_multifdsink_get_property), (gst_multifdsink_init_send),
+	(gst_multifdsink_close), (gst_multifdsink_change_state):
+	* gst/tcp/gstmultifdsink.h:
+	* gst/tcp/gsttcpplugin.c: (plugin_init):
+	* gst/tcp/gsttcpserversink.c: (gst_tcpserversink_get_type),
+	(gst_tcpserversink_class_init), (gst_tcpserversink_init),
+	(gst_tcpserversink_handle_server_read),
+	(gst_tcpserversink_handle_select),
+	(gst_tcpserversink_set_property), (gst_tcpserversink_get_property),
+	(gst_tcpserversink_init_send), (gst_tcpserversink_close):
+	* gst/tcp/gsttcpserversink.h:
+	Added multifdsink, made tcpserversink a subclass of fdsink, removed
+	one of the locks, added recovery policy to multifdsink.
+
+2004-06-26  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/videorate/gstvideorate.c: (gst_videorate_chain):
+	  fix decision for when getting frames with same timestamp
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_class_init), (gst_v4lsrc_init),
+	(gst_v4lsrc_get), (gst_v4lsrc_set_property),
+	(gst_v4lsrc_get_property):
+	* sys/v4l/gstv4lsrc.h:
+	  add latency offset property
+
+2004-06-26  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/videorate/gstvideorate.c: (gst_videorate_chain),
+	(plugin_init):
+	  fix debugging. add category.
+
+2004-06-25  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/sine/gstsinesrc.c: (gst_sinesrc_get):
+          fix wrong offsets
+
+2004-06-25  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/alsa/gstalsasrc.c: (gst_alsa_src_init),
+	(gst_alsa_src_get_time), (gst_alsa_src_loop),
+	(gst_alsa_src_change_state):
+	  return a time that is in sync with the element's processing
+
+2004-06-25  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gsttcpserversink.c: (gst_tcpserversink_class_init),
+	(gst_tcpserversink_init), (gst_tcpserversink_handle_server_read),
+	(gst_tcpserversink_client_remove),
+	(gst_tcpserversink_handle_client_read),
+	(gst_tcpserversink_client_queue_data),
+	(gst_tcpserversink_client_queue_caps),
+	(gst_tcpserversink_client_queue_buffer),
+	(gst_tcpserversink_handle_client_write),
+	(gst_tcpserversink_queue_buffer),
+	(gst_tcpserversink_handle_clients), (gst_tcpserversink_thread),
+	(gst_tcpserversink_chain), (gst_tcpserversink_set_property),
+	(gst_tcpserversink_get_property), (gst_tcpserversink_init_send),
+	(gst_tcpserversink_close):
+	* gst/tcp/gsttcpserversink.h:
+	Serversink rewrite. Really do non blocking writes to clients and
+	maintain an internal queue to handle slower clients while not
+	disturbing fast clients.
+
+2004-06-25  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/tcp/gsttcpclientsrc.c: (gst_tcpclientsrc_get):
+	  better debug, don't override OFFSET and OFFSET_END
+
+2004-06-25  Iain <iain@prettypeople.org>
+
+	* gst-libs/gst/media-info/media-info-priv.c (gmi_set_mime): Add
+	name=source for the wavparse pipeline.
+
+2004-06-24  Johan Dahlin  <johan@gnome.org>
+
+	* ext/theora/theoraenc.c (theora_enc_chain): Call
+	gst_pad_try_set_caps instead of gst_pad_set_explicit_caps so the
+	streamheader caps are set correctly.
+
+2004-06-24  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/vorbis/vorbisenc.c: (raw_caps_factory),
+	(gst_vorbisenc_setup), (gst_vorbisenc_set_property):
+	  respect minimum bitrate; same could be done for max bitrate
+
+2004-06-24  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/vorbis/vorbisenc.c: (raw_caps_factory),
+	(gst_vorbisenc_setup):
+	  fix sample rate range
+
+2004-06-24  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/vorbis/oggvorbisenc.c: (gst_oggvorbisenc_class_init),
+	(gst_oggvorbisenc_setup):
+	* ext/vorbis/vorbisenc.c: (gst_vorbisenc_class_init),
+	(gst_vorbisenc_setup):
+	  resolve ambiguities in code and description
+
+2004-06-24  Wim Taymans  <wim@fluendo.com>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_start), (gst_alsa_xrun_recovery):
+	* ext/alsa/gstalsa.h:
+	* ext/alsa/gstalsasrc.c: (gst_alsa_src_init),
+	(gst_alsa_src_update_avail), (gst_alsa_src_loop):
+	Use alsa trigger_tstamp to get the timestamp of the first
+	sample in the buffer for more precise sync. Some cleanups.
+
+2004-06-24  Wim Taymans  <wim@fluendo.com>
+
+	* gst/audiorate/gstaudiorate.c: (gst_audiorate_link),
+	(gst_audiorate_init), (gst_audiorate_chain),
+	(gst_audiorate_set_property), (gst_audiorate_get_property):
+	* gst/videorate/gstvideorate.c: (gst_videorate_class_init),
+	(gst_videorate_chain):
+	Added some logging, fixed an overflow bug in videorate.
+
+2004-06-24  Benjamin Otte  <otte@gnome.org>
+
+	* ext/kio/Makefile.am:
+	  fix for builddir != srcdir and distcheck
+
+2004-06-24  Benjamin Otte  <otte@gnome.org>
+
+	* gst-libs/gst/colorbalance/Makefile.am:
+	* gst-libs/gst/mixer/Makefile.am:
+	* gst-libs/gst/play/Makefile.am:
+	* gst-libs/gst/tuner/Makefile.am:
+	* gst/tcp/Makefile.am:
+	* sys/dxr3/Makefile.am:
+	  don't include -enumtypes.[ch] or -marshal.[ch] files in the disted
+	  tarball.
+	  Also add all *.list files that were missing.
+	* Makefile.am:
+	  add a distcheck hook to ensure the above doesn't happen again.
+
+2004-06-23  David I. Lehn  <dlehn@users.sourceforge.net>
+
+	* ext/Makefile.am: s/DTS_DIR=dvdread/DTS_DIR=dts/
+
+2004-06-23  Colin Walters  <walters@redhat.com>
+
+	* m4/Makefile.am: Distribute gst-fionread.m4.
+
+2004-06-23  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac: back to dev
+
+2004-06-23  Wim Taymans  <wim@fluendo.com>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_change_state), (gst_alsa_start),
+	(gst_alsa_xrun_recovery):
+	* ext/alsa/gstalsa.h:
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event),
+	(gst_alsa_sink_loop), (gst_alsa_sink_get_time):
+	* ext/alsa/gstalsasrc.c: (gst_alsa_src_init),
+	(gst_alsa_src_get_time), (gst_alsa_src_update_avail),
+	(gst_alsa_src_loop):
+	Add clock to alsasrc. Take new capture timestamp when
+	restarting after an overrun. Split up some functions between
+	alsasrc and alsasink.
+
+=== release 0.8.2 ===
+
+2004-06-23  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_init), (gst_alsa_dispose),
+	(gst_alsa_change_state), (gst_alsa_update_avail),
+	(gst_alsa_xrun_recovery):
+	* ext/alsa/gstalsa.h:
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event):
+	  merge back changes from release
+
+2004-06-23  Wim Taymans  <wim@fluendo.com>
+
+	* gst/audiorate/gstaudiorate.c: (gst_audiorate_class_init),
+	(gst_audiorate_init), (gst_audiorate_chain),
+	(gst_audiorate_set_property), (gst_audiorate_get_property):
+	Implement sample dropping and notify
+
+2004-06-22  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/theoraenc.c: (gst_theora_enc_class_init),
+	(theora_enc_sink_link), (theora_buffer_from_packet),
+	(theora_push_packet), (theora_enc_chain):
+	Some cleanups, make sure the timestamps are correct.
+
+2004-06-22  Wim Taymans  <wim@fluendo.com>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_get_time), (gst_alsa_clock_update),
+	(gst_alsa_change_state), (gst_alsa_update_avail),
+	(gst_alsa_xrun_recovery):
+	* ext/alsa/gstalsa.h:
+	* ext/alsa/gstalsasrc.c: (gst_alsa_src_loop):
+	Cleanups, take queued samples into account when reporting
+	the time.
+
+2004-06-22  Wim Taymans  <wim@fluendo.com>
+
+	* gst/videorate/gstvideorate.c: (gst_videorate_class_init),
+	(gst_videorate_init):
+	Initialize the property as well.
+
+2004-06-22  Wim Taymans  <wim@fluendo.com>
+
+	* gst/videorate/gstvideorate.c: (gst_videorate_class_init),
+	(gst_videorate_init), (gst_videorate_chain),
+	(gst_videorate_set_property), (gst_videorate_get_property):
+	Add property to make videorate silent.
+	Add property to prefer new frames over old ones.
+
+2004-06-22  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* sys/osxvideo/Makefile.am:
+        Workaround so that the osxvideo .so file gets linked with the
+        Cocoa, OpenGL and QuickTime frameworks
+
+2004-06-22  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* sys/osxaudio/Makefile.am:
+        Workaround so that the osxaudio .so file gets linked with the
+        CoreAudio framework
+
+2004-06-22  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* configure.ac:
+	Whoops, my fault...fixed build issues
+
+2004-06-22  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* configure.ac:
+        Add objective-c support if running in Darwin/Mac OS X
+	* sys/Makefile.am:
+        * sys/osxvideo:
+        * sys/osxvideo/Makefile.am:
+        * sys/osxvideo/osxvideosink.h:
+        * sys/osxvideo/osxvideosink.m:
+        * sys/osxvideo/cocoawindow.h:
+        * sys/osxvideo/cocoawindow.m:
+        Add osxvideosink, a cocoa-based osx video sink
+
+
+2004-06-19  Jan Schmidt  <thaytan@mad.scientist.com>
+	* ext/dvdnav/gst-dvd:
+	Grab the gconf key from the right spot
+	* gst/debug/gstnavseek.c: (gst_navseek_init),
+	(gst_navseek_segseek), (gst_navseek_handle_src_event),
+	(gst_navseek_chain):
+	* gst/debug/gstnavseek.h:
+	  Add 's', 'e' and 'l' keypresses to navseek to define the start,end
+	  and loop parameters of a segment seek.
+	* gst/videotestsrc/gstvideotestsrc.c: (gst_videotestsrc_init),
+	(gst_videotestsrc_get_event_masks),
+	(gst_videotestsrc_handle_src_event), (gst_videotestsrc_get):
+	* gst/videotestsrc/gstvideotestsrc.h:
+	  Add seeking support to videotestsrc
+	  Initialise the timestamp_offset variable.
+
+2004-06-18  Wim Taymans  <wim@fluendo.com>
+
+	* ext/sidplay/gstsiddec.cc:
+	Fix negotiation and set correct end offset.
+
+2004-06-18  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac: branch and prerelease
+
+2004-06-17  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/tcp/gsttcpclientsrc.c: (gst_tcpclientsrc_init),
+	(gst_tcpclientsrc_getcaps), (gst_tcpclientsrc_get),
+	(gst_tcpclientsrc_init_receive):
+	* gst/tcp/gsttcpclientsrc.h:
+          read caps when connecting to server for GDP so we set them correctly
+
+2004-06-17  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/videorate/gstvideorate.c: (gst_videorate_chain):
+	  notify drops and duplicates
+	* gst/videoscale/videoscale.c: (videoscale_get_structure):
+	  no good reason to limit ourselves to 100x100
+
+2004-06-17  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_class_init), (gst_v4lsrc_init),
+	(gst_v4lsrc_open), (gst_v4lsrc_src_link), (gst_v4lsrc_getcaps),
+	(gst_v4lsrc_get), (gst_v4lsrc_set_property),
+	(gst_v4lsrc_get_property):
+	* sys/v4l/gstv4lsrc.h:
+	* sys/v4l/v4l_calls.c: (gst_v4l_set_window_properties),
+	(gst_v4l_open), (gst_v4l_get_picture), (gst_v4l_get_audio),
+	(gst_v4l_set_audio):
+	* sys/v4l/v4lsrc_calls.c: (gst_v4lsrc_grab_frame),
+	(gst_v4lsrc_try_capture):
+	* sys/v4l/v4lsrc_calls.h:
+	  change try_palette to more general try_capture
+	  add autoprobe option so we can turn off autoprobing
+	  various fixes
+
+2004-06-17  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	  add videorate
+	* sys/ximage/ximagesink.c: (gst_ximagesink_finalize),
+	(gst_ximagesink_class_init):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_finalize),
+	(gst_xvimagesink_class_init):
+          run them as finalize, not dispose, since dispose can be invoked
+          multiple times
+
+2004-06-17  Wim Taymans  <wim@fluendo.com>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_init), (gst_alsa_dispose),
+	(gst_alsa_get_time), (gst_alsa_xrun_recovery):
+	* ext/alsa/gstalsa.h:
+	* ext/alsa/gstalsaclock.c: (gst_alsa_clock_get_type):
+	* ext/alsa/gstalsasrc.c: (gst_alsa_src_init), (gst_alsa_src_loop),
+	(gst_alsa_src_change_state):
+	* ext/alsa/gstalsasrc.h:
+	Make the xrun code timestamp and offset the buffers correctly.
+	moved the clock to the base class, use alsa methods to get time.
+	Do correct timestamping on outgoing buffers.
+
+2004-06-17  Wim Taymans  <wim@fluendo.com>
+
+	* gst/audiorate/Makefile.am:
+	* gst/audiorate/gstaudiorate.c: (gst_audiorate_get_type),
+	(gst_audiorate_base_init), (gst_audiorate_class_init),
+	(gst_audiorate_link), (gst_audiorate_init), (gst_audiorate_chain),
+	(gst_audiorate_set_property), (gst_audiorate_get_property),
+	(gst_audiorate_change_state), (plugin_init):
+	Added an audiorate converter that fills in gaps.
+
+2004-06-17  Johan Dahlin  <johan@gnome.org>
+
+	* ext/tcp/*: Revert Zaheer changes, to make things actually work again.
+
+2004-06-16  Wim Taymans  <wim@fluendo.com>
+
+	* sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_get):
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_sync_mode_get_type),
+	(gst_v4lsrc_class_init), (gst_v4lsrc_init), (gst_v4lsrc_get_fps),
+	(gst_v4lsrc_get), (gst_v4lsrc_set_property),
+	(gst_v4lsrc_get_property):
+	* sys/v4l/gstv4lsrc.h:
+	Added a copy mode to v4lsrc where it will output a copied version
+	of its internal hardware buffer.
+	Fix the wrong FLAG_SET usage. The flags are integers, not bits, you
+	can't | them.
+
+2004-06-16  Wim Taymans  <wim@fluendo.com>
+
+	* sys/oss/gstosssrc.c: (gst_osssrc_get):
+	Timestamp fixes.
+
+2004-06-16  Wim Taymans  <wim@fluendo.com>
+
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_sync_mode_get_type),
+	(gst_v4lsrc_class_init), (gst_v4lsrc_init), (gst_v4lsrc_get_fps),
+	(gst_v4lsrc_get), (gst_v4lsrc_set_property),
+	(gst_v4lsrc_get_property):
+	* sys/v4l/gstv4lsrc.h:
+	* sys/v4l/v4l-overlay_calls.c: (gst_v4l_set_overlay):
+	Added a sync mode enum property to control v4lsrc timestamp method
+	Removed the use-fixed-fps property and moved functionality in
+	the enum.
+	Don't error on an error value from v4l-conf, it might not always
+	be a real error.
+
+2004-06-16  Wim Taymans  <wim@fluendo.com>
+
+	* gst/videorate/Makefile.am:
+	* gst/videorate/gstvideorate.c: (gst_videorate_get_type),
+	(gst_videorate_base_init), (gst_videorate_class_init),
+	(gst_videorate_getcaps), (gst_videorate_link),
+	(gst_videorate_init), (gst_videorate_chain),
+	(gst_videorate_set_property), (gst_videorate_get_property),
+	(gst_videorate_change_state), (plugin_init):
+	Added a video timestamp corrector.
+
+2004-06-15  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	fixed a potential leak with previous commit
+
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_peek_head):
+
+2004-06-15  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_peek_head):
+	Added missing refcount, fixes bug #144425
+	Cheers Tim for finding the bug
+
+2004-06-15  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/v4l/gstv4l.c: (plugin_init):
+	* sys/v4l/gstv4lcolorbalance.c:
+	* sys/v4l/gstv4lcolorbalance.h:
+	* sys/v4l/gstv4lelement.c:
+	* sys/v4l/gstv4lelement.h:
+	* sys/v4l/gstv4lmjpegsink.c: (gst_v4lmjpegsink_class_init):
+	* sys/v4l/gstv4lmjpegsink.h:
+	* sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_class_init):
+	* sys/v4l/gstv4lmjpegsrc.h:
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_get_fps_list),
+	(gst_v4lsrc_get_fps), (gst_v4lsrc_srcconnect),
+	(gst_v4lsrc_getcaps), (gst_v4lsrc_get):
+	* sys/v4l/gstv4lsrc.h:
+	* sys/v4l/gstv4ltuner.c:
+	* sys/v4l/gstv4ltuner.h:
+	* sys/v4l/gstv4lxoverlay.c:
+	* sys/v4l/gstv4lxoverlay.h:
+	* sys/v4l/v4l-overlay_calls.c: (gst_v4l_set_overlay),
+	(gst_v4l_set_window), (gst_v4l_enable_overlay):
+	* sys/v4l/v4l_calls.c: (gst_v4l_set_window_properties),
+	(gst_v4l_open), (gst_v4l_get_picture), (gst_v4l_get_audio),
+	(gst_v4l_set_audio):
+	* sys/v4l/v4l_calls.h:
+	* sys/v4l/v4lmjpegsink_calls.c: (gst_v4lmjpegsink_sync_thread),
+	(gst_v4lmjpegsink_queue_frame), (gst_v4lmjpegsink_sync_frame),
+	(gst_v4lmjpegsink_set_buffer), (gst_v4lmjpegsink_set_playback),
+	(gst_v4lmjpegsink_playback_init),
+	(gst_v4lmjpegsink_playback_start), (gst_v4lmjpegsink_get_buffer),
+	(gst_v4lmjpegsink_play_frame), (gst_v4lmjpegsink_wait_frame),
+	(gst_v4lmjpegsink_playback_stop),
+	(gst_v4lmjpegsink_playback_deinit):
+	* sys/v4l/v4lmjpegsink_calls.h:
+	* sys/v4l/v4lmjpegsrc_calls.c: (gst_v4lmjpegsrc_queue_frame),
+	(gst_v4lmjpegsrc_sync_next_frame), (gst_v4lmjpegsrc_set_buffer),
+	(gst_v4lmjpegsrc_set_capture), (gst_v4lmjpegsrc_set_capture_m),
+	(gst_v4lmjpegsrc_capture_init), (gst_v4lmjpegsrc_capture_start),
+	(gst_v4lmjpegsrc_grab_frame), (gst_v4lmjpegsrc_requeue_frame),
+	(gst_v4lmjpegsrc_capture_stop), (gst_v4lmjpegsrc_capture_deinit):
+	* sys/v4l/v4lmjpegsrc_calls.h:
+	* sys/v4l/v4lsrc_calls.c: (gst_v4lsrc_queue_frame),
+	(gst_v4lsrc_sync_frame), (gst_v4lsrc_set_capture),
+	(gst_v4lsrc_capture_init), (gst_v4lsrc_capture_start),
+	(gst_v4lsrc_grab_frame), (gst_v4lsrc_requeue_frame),
+	(gst_v4lsrc_capture_stop), (gst_v4lsrc_capture_deinit),
+	(gst_v4lsrc_try_palette):
+	* sys/v4l/v4lsrc_calls.h:
+	  bunch of paranoia cleanups
+
+2004-06-14  David Schleef  <ds@schleef.org>
+
+	* ext/cdparanoia/gstcdparanoia.c: (cdparanoia_init),
+	(cdparanoia_get), (cdparanoia_open), (cdparanoia_change_state):
+	Send discont events and change timestamps appropriately when
+	we get a seek event.  (bug #144240)
+	* ext/cdparanoia/gstcdparanoia.h:
+
+2004-06-14  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsa.c: Use snd_pcm_hw_params_set_rate _near instead of
+	  snd_pcm_hw_params_set_rate  since the latter fails for no good
+	  reason on some setups.
+
+2004-06-14  David Schleef  <ds@schleef.org>
+
+	* gst/volume/demo.c: (value_changed_callback): exp10() is not
+	standard.  Thank you for playing.
+
+2004-06-14  Wim Taymans  <wim@fluendo.com>
+
+	* gst/ffmpegcolorspace/imgconvert.c: (img_convert):
+	Patch 1.3 broke the ordering of the colorspace info and
+	made the plugin basically work by coincidence, reordered
+	the info.
+
+2004-06-14  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/lame/gstlame.c:
+	* ext/mad/gstmad.c:
+	  sync caps.  Make sure mad can only output a list of rates, not
+	  a full range.  In the future, have three caps lists for each of the
+	  mpeg versions.  Change mpegversion to a double as well.
+
+2004-06-14  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/volume/.cvsignore:
+	* gst/volume/Makefile.am:
+	* gst/volume/demo.c: (value_changed_callback), (idler),
+	(setup_gui), (main):
+	  added small demo app
+
+2004-06-13  Jan Schmidt  <thaytan@mad.scientist.com>
+	* ext/esd/esdsink.c: (gst_esdsink_change_state):
+	* ext/esd/esdsink.h:
+	Close the esd connection on pause, because esd will just wait -
+	blocking all other esd clients indefinitely.
+
+2004-06-12  Christophe Fergeau  <teuf@gnome.org>
+
+	* gst/tags/gstvorbistag.c: replaced a g_warning which I added in my
+	  previous commit with GST_DEBUG
+
+2004-06-12  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	  add a header check for a dvdread header in dvdnav.  Fixes #133002
+
+2004-06-12  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* gst/tcp/gsttcpclientsink.c: (gst_tcpclientsink_init_send):
+	* gst/tcp/gsttcpclientsink.h:
+	* gst/tcp/gsttcpclientsrc.c: (gst_tcpclientsrc_init_receive):
+	* gst/tcp/gsttcpclientsrc.h:
+	* gst/tcp/gsttcpserversink.c: (gst_tcpserversink_init),
+	(gst_tcpserversink_handle_server_read),
+	(gst_tcpserversink_init_send):
+	* gst/tcp/gsttcpserversink.h:
+	* gst/tcp/gsttcpserversrc.c: (gst_tcpserversrc_init_receive):
+	* gst/tcp/gsttcpserversrc.h:
+	Modified the tcp plugins so they are portable (IPv4,IPv6, any future
+        version of IP)
+
+2004-06-12  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* configure.ac:
+	Added ogg library so that OSX detects libtheora properly
+
+2004-06-11  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/theoradec.c: (theora_dec_chain),
+	(theora_dec_change_state):
+	Don't try to decode frames before we received a keyframe.
+
+2004-06-11  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_class_init),
+	(gst_ogg_mux_init), (gst_ogg_mux_next_buffer),
+	(gst_ogg_mux_get_headers), (gst_ogg_mux_set_header_on_caps),
+	(gst_ogg_mux_send_headers), (gst_ogg_mux_loop),
+	(gst_ogg_mux_get_property), (gst_ogg_mux_set_property):
+	Added property to set the maximum delay of a page.
+
+2004-06-10  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_class_init),
+	(gst_ogg_mux_init), (gst_ogg_mux_next_buffer),
+	(gst_ogg_mux_get_headers), (gst_ogg_mux_set_header_on_caps),
+	(gst_ogg_mux_send_headers), (gst_ogg_mux_loop),
+	(gst_ogg_mux_get_property), (gst_ogg_mux_set_property):
+	Added max-delay property to control the maximum amount
+	of data to put in one page.
+
+2004-06-10  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/theoraenc.c: (gst_theora_enc_class_init),
+	(gst_theora_enc_init), (theora_enc_sink_link),
+	(theora_buffer_from_packet), (theora_enc_set_property),
+	(theora_enc_get_property):
+	Set duration on encoded buffer, added some more properties
+
+2004-06-10  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_next_buffer),
+	(gst_ogg_mux_get_headers), (gst_ogg_mux_set_header_on_caps),
+	(gst_ogg_mux_send_headers), (gst_ogg_mux_loop):
+	* ext/theora/theoraenc.c: (theora_enc_chain):
+	Fix refcounting bugs
+
+2004-06-10  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_init),
+	(gst_asf_demux_loop), (gst_asf_demux_process_file),
+	(gst_asf_demux_process_data), (gst_asf_demux_handle_data),
+	(gst_asf_demux_process_object), (gst_asf_demux_get_stream),
+	(gst_asf_demux_process_chunk), (gst_asf_demux_handle_sink_event),
+	(gst_asf_demux_handle_src_event), (gst_asf_demux_handle_src_query),
+	(gst_asf_demux_change_state):
+	* gst/asfdemux/gstasfdemux.h:
+	  You know Chimaira? "I - HATE - EVERYTHING". Yeah, that's what this
+	  feels like. I think we should set a new requirement for demuxers
+	  from now on to implement sane loop functions, data loops, query
+	  and seek functions before first commit into CVS. And this commit
+	  fixes all of the above.
+
+2004-06-10  Christophe Fergeau  <teuf@gnome.org>
+
+	* gst/tags/gstvorbistag.c: (gst_vorbis_tag_add): make sure parsed
+	  vorbis comments are properly encoded in UTF-8 before adding them
+	  to a GstTagList
+
+2004-06-09  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsa.c: (add_channels):
+	  handle min <= max correctly
+	* ext/alsa/gstalsa.c: (gst_alsa_fixate_to_mimetype),
+	(gst_alsa_fixate_field_nearest_int), (gst_alsa_fixate):
+	  add fixation functions so we fixate correctly. No preferring of alaw
+	  anymore because it's the first structure.
+	* ext/alsa/gstalsa.h:
+	* ext/alsa/gstalsa.c: (gst_alsa_sw_params_dump),
+	(gst_alsa_hw_params_dump):
+	  add functions to ease debugging in alsalib
+	* ext/alsa/gstalsa.c: (gst_alsa_probe_hw_params),
+	(gst_alsa_set_hw_params), (gst_alsa_set_sw_params),
+	(gst_alsa_start_audio):
+	  only specify hw params if we really setup a format (fixes #134007 -
+	  or at least works around it)
+
+2004-06-09  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_init),
+	(gst_ogg_mux_next_buffer), (gst_ogg_mux_buffer_from_page),
+	(gst_ogg_mux_push_page), (gst_ogg_mux_get_headers),
+	(gst_ogg_mux_set_header_on_caps), (gst_ogg_mux_send_headers),
+	(gst_ogg_mux_loop):
+	Use stream caps to setup the initial pages in the ogg stream.
+	Correctly set the streamheader caps on the srcpad.
+
+2004-06-09  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_get_fps_list),
+	(gst_v4lsrc_get_fps), (gst_v4lsrc_srcconnect),
+	(gst_v4lsrc_getcaps):
+	* sys/v4l/v4l_calls.c: (gst_v4l_set_window_properties),
+	(gst_v4l_get_picture), (gst_v4l_get_audio), (gst_v4l_set_audio):
+	  add querying of fps lists for webcams.  Negotiating to a framerate
+	  now works.
+
+2004-06-08  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/theora/theoraenc.c: (theora_buffer_from_packet),
+	(theora_push_buffer), (theora_push_packet),
+	(theora_set_header_on_caps), (theora_enc_chain):
+	  mark buffers and put on streamheader, raw theora streaming
+	  now works too, whee
+
+2004-06-08  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/tcp/gsttcp.c: (gst_tcp_gdp_read_header),
+	(gst_tcp_gdp_read_caps):
+          do a looping read for caps and GDP headers too
+
+2004-06-08  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/tcp/gsttcpclientsrc.c: (gst_tcpclientsrc_get):
+	* gst/tcp/gsttcpserversrc.c: (gst_tcpserversrc_get):
+          return EOS instead of NULL in _get
+
+2004-06-08  Wim Taymans  <wim@fluendo.com>
+
+	* gst/tcp/gsttcp.c: (gst_tcp_gdp_read_header),
+	(gst_tcp_gdp_read_caps), (gst_tcp_gdp_write_header),
+	(gst_tcp_gdp_write_caps):
+	* gst/tcp/gsttcpclientsrc.c: (gst_tcpclientsrc_get):
+	* gst/tcp/gsttcpserversrc.c: (gst_tcpserversrc_gdp_read_caps),
+	(gst_tcpserversrc_gdp_read_header), (gst_tcpserversrc_get):
+	Memory leak fixes
+
+2004-06-08  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/vorbis/Makefile.am:
+	* ext/vorbis/vorbis.c: (plugin_init):
+	* ext/vorbis/vorbisparse.c: (gst_vorbis_parse_base_init),
+	(gst_vorbis_parse_class_init), (gst_vorbis_parse_init),
+	(vorbis_parse_set_header_on_caps), (vorbis_parse_chain),
+	(vorbis_parse_change_state):
+	* ext/vorbis/vorbisparse.h:
+          adding a vorbisparse element that marks the buffers, streaming
+          raw vorbis using GDP now works, whee
+
+2004-06-08  Wim Taymans  <wim@fluendo.com>
+
+	* ext/jpeg/Makefile.am:
+	* ext/jpeg/README:
+	* ext/jpeg/gstjpeg.c: (plugin_init):
+	* ext/jpeg/gstsmokedec.c: (gst_smokedec_get_type),
+	(gst_smokedec_base_init), (gst_smokedec_class_init),
+	(gst_smokedec_init), (gst_smokedec_link), (gst_smokedec_chain):
+	* ext/jpeg/gstsmokedec.h:
+	* ext/jpeg/gstsmokeenc.c: (gst_smokeenc_get_type),
+	(gst_smokeenc_base_init), (gst_smokeenc_class_init),
+	(gst_smokeenc_init), (gst_smokeenc_getcaps), (gst_smokeenc_link),
+	(gst_smokeenc_resync), (gst_smokeenc_chain),
+	(gst_smokeenc_set_property), (gst_smokeenc_get_property):
+	* ext/jpeg/gstsmokeenc.h:
+	* ext/jpeg/smokecodec.c: (smokecodec_init_destination),
+	(smokecodec_flush_destination), (smokecodec_term_destination),
+	(smokecodec_init_source), (smokecodec_fill_input_buffer),
+	(smokecodec_skip_input_data), (smokecodec_resync_to_restart),
+	(smokecodec_term_source), (smokecodec_encode_new),
+	(smokecodec_decode_new), (smokecodec_info_free),
+	(smokecodec_set_quality), (smokecodec_get_quality),
+	(smokecodec_set_threshold), (smokecodec_get_threshold),
+	(smokecodec_set_bitrate), (smokecodec_get_bitrate),
+	(find_best_size), (abs_diff), (put), (smokecodec_encode),
+	(smokecodec_parse_header), (smokecodec_decode):
+	* ext/jpeg/smokecodec.h:
+	Added a new simple jpeg based codec
+
+2004-06-08  Wim Taymans  <wim@fluendo.com>
+
+	* gst/multipart/multipartmux.c: (gst_multipart_mux_class_init),
+	(gst_multipart_mux_loop):
+	Fix memory leak
+
+2004-06-08  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/tcp/gsttcpclientsrc.c: (gst_tcpclientsrc_get):
+	* gst/tcp/gsttcpserversink.c: (gst_tcpserversink_client_remove),
+	(gst_tcpserversink_handle_client_read), (gst_tcp_buffer_write),
+	(gst_tcpserversink_handle_client_write), (gst_tcpserversink_chain),
+	(gst_tcpserversink_init_send), (gst_tcpserversink_close):
+	* gst/tcp/gsttcpserversink.h:
+          take streamheader into account
+
+2004-06-08  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/level/Makefile.am:
+	* gst/level/gstlevel.c: (gst_level_class_init):
+	  clean up marshal generation
+
+2004-06-08  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/tcp/Makefile.am:
+	* gst/tcp/gsttcpclientsink.c: (gst_tcpclientsink_get_type),
+	(gst_tcpclientsink_class_init), (gst_tcpclientsink_init),
+	(gst_tcpclientsink_set_property), (gst_tcpclientsink_get_property):
+	* gst/tcp/gsttcpclientsrc.c: (gst_tcpclientsrc_class_init),
+	(gst_tcpclientsrc_init), (gst_tcpclientsrc_set_property),
+	(gst_tcpclientsrc_get_property):
+	* gst/tcp/gsttcpserversink.c: (gst_tcpserversink_class_init),
+	(gst_tcpserversink_init), (gst_tcpserversink_handle_server_read),
+	(gst_tcpserversink_handle_client_read),
+	(gst_tcpserversink_handle_client_write),
+	(gst_tcpserversink_set_property), (gst_tcpserversink_get_property):
+	* gst/tcp/gsttcpserversink.h:
+	  add signals client-added and client-removed
+	* gst/tcp/gsttcpserversrc.c: (gst_tcpserversrc_class_init),
+	(gst_tcpserversrc_init), (gst_tcpserversrc_set_property),
+	(gst_tcpserversrc_get_property):
+	uniformized, change default protocol to NONE
+	* gst/tcp/gsttcp-marshal.list: added
+2004-06-07  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event):
+	  handle discont events if they happen before caps nego
+
+2004-06-07  Wim Taymans  <wim@fluendo.com>
+
+	* gst/multipart/multipartdemux.c: (gst_multipart_demux_base_init),
+	(gst_multipart_find_pad_by_mime), (gst_multipart_demux_chain),
+	(gst_multipart_demux_plugin_init):
+	* gst/multipart/multipartmux.c: (gst_multipart_mux_class_init),
+	(gst_multipart_mux_init), (gst_multipart_mux_loop),
+	(gst_multipart_mux_change_state):
+	Small updates, fix a memleak
+
+2004-06-07  Stephane Loeuillet  <stephane.loeuillet@tiscali.fr>
+
+	* configure.ac: OSS portability
+	* ext/arts/gst_arts.c: idem
+	* sys/oss/gstosselement.c: idem
+	* sys/oss/gstossmixer.c: idem
+	* sys/oss/gstosssink.c: idem
+	* sys/oss/gstosssrc.c: idem
+	* sys/oss/oss_probe.c: idem
+	  - check for soundcard.h in different places for some BSD
+
+2004-06-07  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* AUTHORS:
+	Add me to the authors file
+	* configure.ac:
+	Increase the libdv requirement to >= version 0.100
+	* ext/dv/gstdvdec.c: (gst_dvdec_init), (gst_dvdec_src_convert),
+	(gst_dvdec_src_query), (gst_dvdec_handle_sink_event),
+	(gst_dvdec_push), (gst_dvdec_loop), (gst_dvdec_change_state):
+	* ext/dv/gstdvdec.h:
+	Add support for the new_media flag when sending DISCONT events
+	Make the querying work when video pad is not linked
+
+2004-06-07  Tim-Philipp Müller  <t.i.m@zen.co.uk>
+
+	reviewed by Benjamin Otte  <otte@gnome.org>
+
+	* gst/mixmatrix/mixmatrix.c: (gst_mixmatrix_init):
+	  create a NULL-initialized array of pads, so we don't think they
+	  exist already. (fixes #143130)
+
+2004-06-07  Benjamin Otte  <otte@gnome.org>
+
+	* gst/mixmatrix/mixmatrix.c: (gst_mixmatrix_init),
+	(mixmatrix_resize), (gst_mixmatrix_set_all_caps),
+	(gst_mixmatrix_request_new_pad), (gst_mixmatrix_loop):
+	  don't use // coments
+
+2004-06-07  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_samples_to_timestamp):
+	  cast to GstClockTime to get higher granularity
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event):
+	  use gst_element_set_time_delay to get the exact time
+	* ext/mad/gstmad.c: (gst_mad_chain):
+	  use the negotiated rate instead of the current frame's rate which
+	  might be wrong because of bit errors. This avoids emitting totally
+	  bogus timestamps and screwing sync.
+	(fixes #143454)
+
+2004-06-07  Tim-Philipp Müller  <t.i.m@zen.co.uk>
+
+	reviewed by Benjamin Otte  <otte@gnome.org>
+
+	* gst/adder/gstadder.c: (gst_adder_loop):
+	  properly error out when no negotiation has happened yet. (fixes
+	  #143032)
+
+2004-06-06  Benjamin Otte  <otte@gnome.org>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_handle_event):
+	  forward correctly transformed offset in discont events. Based on
+	  patch by Arwed v. Merkatz. (fixes #142851)
+
+2004-06-06  David Schleef  <ds@schleef.org>
+
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c: that's
+	G_HAVE_GNUC_VARARGS, not G_HAVE_GNU_VARARGS.  Should fix compile
+	problems on several systems.
+
+2004-06-06  Benjamin Otte  <otte@gnome.org>
+
+	* ext/vorbis/vorbisdec.c: (gst_vorbis_dec_init):
+	  use explicit caps on the srcpad
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_chain):
+	  properly error out if caps couldn't be set (fixes #142764)
+
+2004-06-06  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_probe_hw_params),
+	(gst_alsa_set_hw_params), (gst_alsa_set_sw_params),
+	(gst_alsa_start_audio):
+	  - don't call set_periods_integer anymore, it breaks the
+	  configuration randomly
+	  - call snd_pcm_hw_params_set_access directly instead of using masks
+	  - don't fail if the sw_params can't be set, just use the default
+	  params and hope it works. Alsalib has weird issues when you touch
+	  sw_params and does no proper error reporting about what failed.
+	* ext/alsa/gstalsa.c: (gst_alsa_open_audio),
+	(gst_alsa_close_audio):
+	  make our alsa debugging go via gst debugging and not conditionally
+	  defined
+	* ext/alsa/gstalsa.h:
+	  add ALSA_DEBUG_FLUSH macro
+	* ext/alsa/gstalsaplugin.c: (gst_alsa_error_wrapper),
+	(plugin_init):
+	  wrap alsa errors to be printed via the gst debugging system and not
+	  spammed to stderr
+
+2004-06-04  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_init),
+	(gst_qtdemux_handle_src_query), (gst_qtdemux_handle_src_event),
+	(gst_qtdemux_handle_sink_event), (gst_qtdemux_change_state),
+	(gst_qtdemux_loop_header), (qtdemux_dump_mvhd),
+	(qtdemux_parse_trak):
+	* gst/qtdemux/qtdemux.h:
+	  Bitch. Also known as seeking, querying & co.
+	* sys/oss/gstosssink.c: (gst_osssink_init), (gst_osssink_chain),
+	(gst_osssink_change_state):
+	* sys/oss/gstosssink.h:
+	  Resyncing is for weenies, this hack is no longer needed and was
+	  broken anyway (since it - unintendedly - always leaves resync to
+	  TRUE).
+
+2004-06-05  Andrew Turner <zxombie@hotpop.com>
+
+	* gst/tcp/gsttcp.c: portability (Solaris 10/FreeBSD)
+	* gst/tcp/gsttcpclientsrc.h: idem
+	  - define MSG_NOSIGNAL if not done
+	  - include unistd.h for off_t
+          (fixes #143749)
+
+2004-06-05  Benjamin Otte  <otte@gnome.org>
+
+	* configure.ac:
+	* ext/kio/Makefile.am:
+	  check for qt's moc preprocessor explicitly and use it
+
+2004-06-03  Thomas Vander Stichele  <thomas (at) apestaart (dot) org>
+
+	* gst/tcp/gsttcp.c: (gst_tcp_socket_write):
+	  don't get a signal for EPIPE on socket writes
+	  (somebody check if this works on other platforms)
+
+2004-06-02  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/alsa/gstalsaclock.c: (gst_alsa_clock_get_type):
+	* ext/alsa/gstalsasrc.c: (gst_alsa_src_loop):
+          check error condition on available samples correctly
+
+2004-06-02  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/alsa/gstalsasrc.c: (gst_alsa_src_get_time):
+          avoid a segfault
+	* gst/tcp/gsttcp.c: (gst_tcp_socket_write), (gst_tcp_socket_read),
+	(gst_tcp_gdp_read_header), (gst_tcp_gdp_read_caps):
+	* gst/tcp/gsttcpserversrc.c: (gst_tcpserversrc_gdp_read_caps),
+	(gst_tcpserversrc_gdp_read_header):
+         use ssize_t over size_t since the former is signed and thus the
+         check for error codes can work
+
+2004-06-02  Wim Taymans  <wim@fluendo.com>
+
+	reviewed by: Johan
+
+	* gst/multipart/multipartmux.c: (gst_multipart_mux_class_init),
+	(gst_multipart_mux_loop):
+	Oops
+
+2004-06-02  Wim Taymans  <wim@fluendo.com>
+
+	* gst/multipart/multipartmux.c: (gst_multipart_mux_class_init),
+	(gst_multipart_mux_init), (gst_multipart_mux_loop),
+	(gst_multipart_mux_get_property), (gst_multipart_mux_set_property),
+	(gst_multipart_mux_change_state):
+	Added configurable boundary specifier, added the value as a
+	caps field as well.
+
+2004-06-02  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* gst/tcp/gsttcp.c:
+	* gst/tcp/gsttcpclientsrc.c:
+	* gst/tcp/gsttcpclientsrc.h:
+	* gst/tcp/gsttcpserversrc.c:
+	  - portability fix, to compile on OSX
+            (fixes #143146)
+
+	* sys/osxaudio/gstosxaudioelement.c:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	  - compilation warnings on OSX
+            (fixes #143153)
+
+2004-06-02  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* ext/vorbis/vorbisdec.c : sign warning fixes
+
+	* gst-libs/gst/mixer/mixertrack.c :
+	  do no use defines which are glib 2.4 specific
+
+2004-06-01  Christophe Fergeau  <teuf@gnome.org>
+
+	* ext/flac/gstflactag.c: strip ending framing bit from vorbiscomment
+	  buffer since libflac doesn't expect it (reports a sync error when
+	  it encounters that)
+
+
+2004-06-01  Owen Fraser-Green  <owen@discobabe.net>
+
+	* gst-libs/gst/mixer/mixertrack.h: Changed struct syntax
+	* gst-libs/gst/mixer/mixertrack.c:
+	(gst_mixer_track_get_property), (get_mixer_track_init),
+	(get_mixer_track_get_property): Added property accessors
+	* gst-libs/gst/mixer/mixeroptions.h: Changed struct syntax
+	* gst-libs/gst/mixer/mixeroptions.c:
+	(gst_mixer_options_get_values): Added
+	* gst-libs/gst/mixer/mixer.h: Changed GstMixerClass syntax
+	* gst-libs/gst/mixer/mixer.c: Fixed comment
+
+
+2004-06-01  Thomas Vander Stichele  <thomas (at) apestaart (dot) org>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_open_audio):
+          improve error messages on open
+
+
+2004-06-01  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/v4l/v4l-overlay_calls.c: (gst_v4l_set_overlay):
+          check if v4l-conf is in path
+
+2004-06-01  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/media-info/media-info-priv.c: (gmi_set_mime):
+          change assert to a more readable error message
+
+2004-05-31  Stephane Loeuillet  <stephane.loeuillet@tiscali.fr>
+
+	* gst-libs/gst/tuner/tunerchannel.h:
+	  - add a freq_multiplicator field to make the conversion
+	    between internal frequency unit and Hz
+	* sys/v4l/gstv4lelement.c:
+	* sys/v4l2/gstv4l2element.c:
+	  - change default video device to /dev/video0
+	* sys/v4l/v4l_calls.c:
+	* sys/v4l2/v4l2_calls.c:
+	  - we only expose frequency to the user in Hz instead of
+	    bastard v4lX unit (either 62.5kHz or 62.5Hz)
+
+2004-05-31  Jan Schmidt  <thaytan@mad.scientist.com>
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_chain):
+	  Initialise b_o_s and e_o_s variables
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_video_caps_with_data):
+	  Add some unusual fourcc's from mplayer avi's
+	* gst/multipart/multipartmux.c: (gst_multipart_mux_plugin_init):
+	  Make the muxer have rank GST_RANK_NONE, so it doesn't mess up
+	  autoplugging.
+
+2004-05-28  Wim Taymans  <wim@fluendo.com>
+
+	* configure.ac:
+	* gst/alpha/Makefile.am:
+	* gst/alpha/gstalpha.c: (gst_alpha_method_get_type),
+	(gst_alpha_get_type), (gst_alpha_base_init),
+	(gst_alpha_class_init), (gst_alpha_init), (gst_alpha_set_property),
+	(gst_alpha_get_property), (gst_alpha_sink_link), (gst_alpha_add),
+	(gst_alpha_chroma_key), (gst_alpha_chain),
+	(gst_alpha_change_state), (plugin_init):
+	A plugin to add an alpha channel to I420 video. Can optionally do
+	chroma keying.
+	* gst/multipart/Makefile.am:
+	* gst/multipart/multipart.c: (plugin_init):
+	* gst/multipart/multipartdemux.c: (gst_multipart_demux_base_init),
+	(gst_multipart_demux_class_init), (gst_multipart_demux_init),
+	(gst_multipart_demux_finalize), (gst_multipart_demux_handle_event),
+	(gst_multipart_find_pad_by_mime), (gst_multipart_demux_chain),
+	(gst_multipart_demux_change_state),
+	(gst_multipart_demux_plugin_init):
+	* gst/multipart/multipartmux.c: (gst_multipart_mux_get_type),
+	(gst_multipart_mux_base_init), (gst_multipart_mux_class_init),
+	(gst_multipart_mux_get_sink_event_masks), (gst_multipart_mux_init),
+	(gst_multipart_mux_sinkconnect), (gst_multipart_mux_pad_link),
+	(gst_multipart_mux_pad_unlink),
+	(gst_multipart_mux_request_new_pad),
+	(gst_multipart_mux_handle_src_event),
+	(gst_multipart_mux_next_buffer), (gst_multipart_mux_compare_pads),
+	(gst_multipart_mux_queue_pads), (gst_multipart_mux_loop),
+	(gst_multipart_mux_get_property), (gst_multipart_mux_set_property),
+	(gst_multipart_mux_change_state), (gst_multipart_mux_plugin_init):
+	A Multipart demuxer/muxer. Not sure if it violates specs. Used to
+	send multipart jpeg images to a browser.
+	* gst/videobox/Makefile.am:
+	* gst/videobox/README:
+	* gst/videobox/gstvideobox.c: (gst_video_box_fill_get_type),
+	(gst_video_box_get_type), (gst_video_box_base_init),
+	(gst_video_box_class_init), (gst_video_box_init),
+	(gst_video_box_set_property), (gst_video_box_get_property),
+	(gst_video_box_sink_link), (gst_video_box_i420),
+	(gst_video_box_ayuv), (gst_video_box_chain),
+	(gst_video_box_change_state), (plugin_init):
+	Crops or adds borders around an image. can do alpha channel
+	borders as well.
+	* gst/videomixer/Makefile.am:
+	* gst/videomixer/README:
+	* gst/videomixer/videomixer.c: (gst_videomixer_pad_get_type),
+	(gst_videomixer_pad_base_init), (gst_videomixer_pad_class_init),
+	(gst_videomixer_pad_get_sink_event_masks),
+	(gst_videomixer_pad_get_property),
+	(gst_videomixer_pad_set_property),
+	(gst_videomixer_pad_sinkconnect), (gst_videomixer_pad_link),
+	(gst_videomixer_pad_unlink), (gst_videomixer_pad_init),
+	(gst_video_mixer_background_get_type), (gst_videomixer_get_type),
+	(gst_videomixer_base_init), (gst_videomixer_class_init),
+	(gst_videomixer_init), (gst_videomixer_request_new_pad),
+	(gst_videomixer_handle_src_event),
+	(gst_videomixer_blend_ayuv_i420), (gst_videomixer_fill_checker),
+	(gst_videomixer_fill_color), (gst_videomixer_fill_queues),
+	(gst_videomixer_blend_buffers), (gst_videomixer_update_queues),
+	(gst_videomixer_loop), (gst_videomixer_get_property),
+	(gst_videomixer_set_property), (gst_videomixer_change_state),
+	(plugin_init):
+	Generic video mixer plugin, can handle multiple inputs all with
+	different framerates and video sizes. Is fully alpha channel
+	aware.
+
+2004-05-27  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_build_list):
+	  Select first track as master track. Not sure how else to handle
+	  that...
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_next_buffer):
+	  Discard discont events. Should fix #142962.
+
+2004-05-26  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/Makefile.am:
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_interface_init),
+	(gst_alsa_mixer_build_list), (gst_alsa_mixer_get_volume),
+	(gst_alsa_mixer_set_volume), (gst_alsa_mixer_set_mute),
+	(gst_alsa_mixer_set_record), (gst_alsa_mixer_set_option),
+	(gst_alsa_mixer_get_option):
+	* ext/alsa/gstalsamixer.h:
+	* ext/alsa/gstalsamixeroptions.c:
+	(gst_alsa_mixer_options_get_type),
+	(gst_alsa_mixer_options_class_init), (gst_alsa_mixer_options_init),
+	(gst_alsa_mixer_options_new):
+	* ext/alsa/gstalsamixeroptions.h:
+	* ext/alsa/gstalsamixertrack.c: (gst_alsa_mixer_track_new):
+	* ext/alsa/gstalsamixertrack.h:
+	  Add enumerations (as GstMixerOptions). Make correct distinction
+	  between input/output tracks. Add capture/playback private flag.
+	  Use flag to decide on whether to set capture or playback volumes
+	  or switches. Use playback and record switches.
+	* gst-libs/gst/mixer/Makefile.am:
+	* gst-libs/gst/mixer/mixer-marshal.list:
+	* gst-libs/gst/mixer/mixer.c: (gst_mixer_class_init),
+	(gst_mixer_set_option), (gst_mixer_get_option),
+	(gst_mixer_mute_toggled), (gst_mixer_record_toggled),
+	(gst_mixer_volume_changed), (gst_mixer_option_changed):
+	* gst-libs/gst/mixer/mixer.h:
+	* gst-libs/gst/mixer/mixeroptions.c: (gst_mixer_options_get_type),
+	(gst_mixer_options_class_init), (gst_mixer_options_init),
+	(gst_mixer_options_dispose):
+	* gst-libs/gst/mixer/mixeroptions.h:
+	  Add GstMixerOptions.
+	* sys/oss/gstosselement.c: (gst_osselement_class_probe_devices):
+	  Rename Audio Mixer to OSS Mixer (similar to Alsa Mixer). Fix
+	  broken device detection on computers with multiple OSS sound
+	  cards.
+
+2004-05-26  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_fixate):
+	  fixate nicely even when the peer is not negotiating
+
+2004-05-25  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/audioconvert/gstaudioconvert.c:
+	(gst_audio_convert_parse_caps):
+	  make sure we don't allow depth > width
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_fixate):
+	  fixate endianness to G_BYTE_ORDER as default
+	* gst/audioscale/gstaudioscale.c:
+	  we don't handle another endianness as host-endianness
+
+2004-05-25  David Schleef  <ds@schleef.org>
+
+	* gst/ffmpegcolorspace/mem.c:  malloc() is in stdlib.h, not malloc.h
+
+2004-05-24  Benjamin Otte  <otte@gnome.org>
+
+	* ext/vorbis/oggvorbisenc.c: (gst_oggvorbisenc_sinkconnect),
+	(gst_oggvorbisenc_setup):
+	  properly fail when we can't setup the vorbis encoder due to
+	  unsupported settings
+	* ext/vorbis/vorbisenc.c: (gst_vorbisenc_sinkconnect),
+	(gst_vorbisenc_setup):
+	  same
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_link):
+	  fix case where warnings occured when one pad was unlinked while the
+	  other's link function was called
+
+2004-05-24  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/tcp/Makefile.am:
+          use GST_ENABLE_NEW
+
+2004-05-24  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst-libs/gst/resample/private.h:
+	  don't use optimizations that are #if 0'ed
+
+2004-05-24  Wim Taymans  <wim@fluendo.com>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query):
+	Fix potential division by zero error and hopefully get
+	the position query right to get correct timestamps on avi
+	audio.
+
+2004-05-24  Wim Taymans  <wim@fluendo.com>
+
+	* gst/videoscale/videoscale.c: (gst_videoscale_scale_nearest),
+	(gst_videoscale_scale_nearest_str2),
+	(gst_videoscale_scale_nearest_str4),
+	(gst_videoscale_scale_nearest_32bit),
+	(gst_videoscale_scale_nearest_24bit),
+	(gst_videoscale_scale_nearest_16bit):
+	Fix the scaling algorithm and avoid a buffer overflow.
+        removed the while loop in the scaling function as it
+	was used for point sampling only.
+
+2004-05-24  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_get_type),
+	(gst_id3_tag_class_init), (gst_id3_tag_init),
+	(gst_id3_tag_set_property), (gst_id3_tag_get_tag_to_render),
+	(gst_id3_tag_handle_event), (gst_id3_tag_do_caps_nego),
+	(gst_id3_tag_send_tag_event):
+	  lots of fixes to make id3mux work and id3demux work correctly
+
+2004-05-24  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* ext/Makefile.am:
+	  add rules to build shout2send (was removed by accident
+	  when this module was no more marked experimental/broken)
+
+2004-05-24  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	* ext/shout2/gstshout2.c:
+	* ext/shout2/gstshout2.h:
+	  adding a "connection problem" signal to shout2send
+	  (fixes #142954)
+
+2004-05-21  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/kio/kioreceiver.cpp:
+	* ext/kio/kioreceiver.h:
+          fix sign comparison issues
+
+2004-05-21  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* gst/cdxaparse/gstcdxaparse.c:
+	* gst/cdxaparse/gstcdxaparse.h:
+	  some renaming
+	  add some checks/sanity
+	  prepare for seek addition
+
+	* sys/sunaudio/gstsunaudio.c:
+	  remove exported dupe init function
+
+2004-05-21  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/dv/gstdvdec.c: (gst_dvdec_init), (gst_dvdec_get_formats),
+	(gst_dvdec_src_convert), (gst_dvdec_sink_convert):
+	  Fix format conversion and position querying.
+	* gst/debug/progressreport.c: (gst_progressreport_report):
+	  Don't output a bogus total value that we didn't query.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_xv_support):
+	  Always set XV_AUTOPAINT_COLORKEY to true. Fixes xvimagesink showing
+	  only a blank window after xine has been used.
+
+2004-05-21  Thomas Vander Stichele  <thomas (at) apestaart (dot) org>
+
+	* m4/as-arts.m4:
+	  sync with upstream version to fix test on FC2
+	  readd with -ko to preserve Id header
+
+2004-05-20  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* configure.ac:
+	  test for FIONREAD ioctl in sys/filio.h for Solaris compat.
+	* gst/tcp/gsttcpclientsrc.c: idem
+	* gst/tcp/gsttcpserversink.c: idem
+	* gst/tcp/gsttcpserversrc.c: idem
+	* m4/gst-fionread.m4: idem
+
+	* sys/sunaudio/gstsunaudio.c: change category to Sink/Audio
+
+	* configure.ac: enable speex plugin for speex 1.1.5+
+	* ext/speex/gstspeexenc.c: fix cast warning
+
+	* ext/esd/README: fix typo
+
+2004-05-20  David Schleef  <ds@schleef.org>
+
+	* configure.ac: Minor cosmetic change to convince the buildbot to
+	reautogen.
+	* sys/sunaudio/gstsunaudio.c: (gst_sunaudiosink_class_init),
+	(gst_sunaudiosink_init), (gst_sunaudiosink_getcaps),
+	(gst_sunaudiosink_pad_link), (gst_sunaudiosink_chain),
+	(gst_sunaudiosink_setparams), (gst_sunaudiosink_open),
+	(gst_sunaudiosink_close), (gst_sunaudiosink_change_state),
+	(gst_sunaudiosink_set_property), (gst_sunaudiosink_get_property):
+	More hacking.  Plays audio now.
+
+2004-05-20  David Schleef  <ds@schleef.org>
+
+	* configure.ac:
+	* sys/Makefile.am:
+
+2004-05-20  David Schleef  <ds@schleef.org>
+
+	* sys/osxaudio/Makefile.am:  New OS X audio plugin by Zaheer Abbas Merali
+	* sys/osxaudio/gstosxaudio.c:
+	* sys/osxaudio/gstosxaudioelement.c:
+	* sys/osxaudio/gstosxaudioelement.h:
+	* sys/osxaudio/gstosxaudiosink.c:
+	* sys/osxaudio/gstosxaudiosink.h:
+	* sys/osxaudio/gstosxaudiosrc.c:
+	* sys/osxaudio/gstosxaudiosrc.h:
+
+2004-05-20  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/vorbis/vorbisenc.c: (gst_vorbisenc_set_header_on_caps),
+	(gst_vorbisenc_chain):
+          put the codec headers on the caps as streamheader as well as
+          pushing them out
+
+2004-05-20  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/vorbis/vorbisenc.c: (vorbis_granule_time_copy),
+	(gst_vorbisenc_buffer_from_packet), (gst_vorbisenc_push_buffer),
+	(gst_vorbisenc_push_packet), (gst_vorbisenc_chain):
+        split up push_packet into two functions
+
+2004-05-20  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/tcp/.cvsignore:
+	  ignore enums
+	* gst/tcp/Makefile.am:
+	* gst/tcp/README:
+	* gst/tcp/gsttcp.c:
+	* gst/tcp/gsttcp.h:
+	* gst/tcp/gsttcpclientsink.c:
+	* gst/tcp/gsttcpclientsink.h:
+	* gst/tcp/gsttcpclientsrc.c:
+	* gst/tcp/gsttcpclientsrc.h:
+	* gst/tcp/gsttcpplugin.c:
+	* gst/tcp/gsttcpserversink.c:
+	* gst/tcp/gsttcpserversink.h:
+	* gst/tcp/gsttcpserversrc.c:
+	* gst/tcp/gsttcpserversrc.h:
+          add new tcp elements
+
+2004-05-19  Wim Taymans  <wim@fluendo.com>
+
+	* gst/law/mulaw-conversion.c: (mulaw_encode):
+	Fix overflow bug in ulaw encoding.
+
+2004-05-19  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/mad/gstmad.c: (gst_mad_handle_event):
+	  don't unref the event twice
+
+2004-05-19  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* configure.ac:
+	  remove -Wno-sign-compare
+
+2004-05-19  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* configure.ac:
+	  remove -DG_DISABLE_DEPRECATED. It's not usable without workarounds
+	  if you want to work against glib 2.2 and 2.4
+
+2004-05-19  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/tcp/Makefile.am:
+	* gst/tcp/gsttcp.c:
+	* gst/tcp/gsttcp.h:
+	* gst/tcp/gsttcpsink.h:
+	* gst/tcp/gsttcpsrc.h:
+          gsttcp -> gsttcpplugin + CVS surgery in preparation for tcp merge
+
+2004-05-19  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/debug/tests.c: (md5_get_value):
+	  fix segfault on gst-inspect
+
+2004-05-19  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/debug/testplugin.c:
+	* gst/debug/tests.c:
+	* gst/debug/tests.h:
+	  add new extensible and configurable testing element. Current tests
+	  include buffer count, stream length, timestamp/duration matching and
+	  md5.
+	* gst/debug/Makefile.am:
+	* gst/debug/gstdebug.c: (plugin_init):
+	  add infrastructure for new element
+
+2004-05-19  Johan Dahlin  <johan@gnome.org>
+
+	* ext/dv/gstdvdec.c (gst_dvdec_quality_get_type): Add proper
+	ending of the array. Fixes gst-inspect segfault on ppc.
+
+2004-05-19  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* ext/dirac/gstdiracdec.cc : change category to Codec/Decoder/Video
+
+	* m4/a52.m4 : don't fix a test that should fail with current a52dec lib
+
+2004-05-18  David Schleef  <ds@schleef.org>
+
+	* gst/ffmpegcolorspace/imgconvert.c: (img_convert): Fixes for
+	warnings (bugs, actually) noticed by gcc but not forte.
+
+2004-05-18  David Schleef  <ds@schleef.org>
+
+	* sys/sunaudio/Makefile.am:
+	* sys/sunaudio/gstsunaudio.c: New sunaudiosink
+
+2004-05-18  David Schleef  <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_change_state),
+	(gst_qtdemux_loop_header):  Patch from dcm@acm.org (David Moore)
+	to allow qtdemux to use non-seekable streams. (bug #142272)
+
+2004-05-18  David Schleef  <ds@schleef.org>
+
+	* gst-libs/gst/resample/resample.c: (gst_resample_sinc_ft_s16),
+	(gst_resample_sinc_ft_float): Remove use of static temporary
+	buffer.  This code was obviously not supposed to last long, but
+	it's stuck in our ABI, so it required a little hack to make it
+	ABI-compatible.  Fixes #142585.
+	* gst-libs/gst/resample/resample.h: same.
+
+2004-05-18  David Schleef  <ds@schleef.org>
+
+	* configure.ac: Add sunaudio
+	* examples/Makefile.am: make gstplay depend on gconf
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c: Remove c99-isms
+	* gst/ffmpegcolorspace/imgconvert.c: (build_rgb_palette),
+	(convert_table_lookup), (img_convert): remove c99-isms
+	* gst/ffmpegcolorspace/imgconvert_template.h: make a constant
+          unsigned, to fix a warning on Solaris
+	* gst/mpeg1sys/systems.c: bcopy->memcpy
+	* gst/rtjpeg/RTjpeg.c: (RTjpeg_yuvrgb8): bcopy->memcpy
+	* sys/Makefile.am: Add sunaudio
+
+2004-05-18  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_get_type), (gst_ogg_mux_init),
+	(gst_ogg_mux_sinkconnect), (gst_ogg_mux_request_new_pad),
+	(gst_ogg_mux_next_buffer), (gst_ogg_mux_push_page),
+	(gst_ogg_mux_compare_pads), (gst_ogg_mux_queue_pads),
+	(gst_ogg_mux_loop):
+	Fix an ugly memleak where the muxer didn't flush enough ogg
+	pages. This also resulted in badly muxed ogg files.
+
+2004-05-18  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* gst/asfdemux/asfheaders.c :
+	* gst/asfdemux/asfheaders.h :
+	* gst/asfdemux/gstasfdemux.c :
+	  - fix ASF_OBJ_PADDING guid
+	  - add 3 new object guids (language list, metadata,
+            extended stream properties)
+          - add a function to parse extended header objects
+
+2004-05-18  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* sys/oss/gstosselement.c: (gst_osselement_sync_parms):
+	  remove leftover debugging g_print
+
+2004-05-17  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mad/gstmad.c: (gst_mad_handle_event):
+	  Fix for when the first format in a discont event is not a
+	  byte-based one. Should fix #137710.
+
+2004-05-18  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* m4/a52.m4 : fix compilation with -Wall -Werror
+	* m4/libfame.m4 : idem
+	* m4/libmikmod.m4 : idem
+
+2004-05-17  Benjamin Otte  <otte@gnome.org>
+
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_process_comment):
+	  signal the new tags before giving up the reference
+
+2004-05-17  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/shout2/gstshout2.c:
+	  use application/ogg instead of application/x-ogg (patch by Patrick
+	  Guimond, fixes #142432)
+	* sys/oss/gstosselement.c: (gst_osselement_reset),
+	(gst_osselement_sync_parms):
+	  don't set fragment size unless specified (fixes #142493)
+
+2004-05-17  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* configure.ac : fix compilation of v4l2src with "-Wall -Werror"
+	  fixes #142664
+
+2004-05-17  Benjamin Otte  <otte@gnome.org>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_chain):
+	  compute offsets correctly for internal buffers so timestamps are set
+	  correctly when we can't seek. Also handle cases where there are no
+	  offsets. (based on a patch by David Moore, fixes #142507)
+
+2004-05-17  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_loop):
+	  use correct variable when determining amount of data to skip so we
+	  don't skip into the void and segfault
+
+2004-05-16  Benjamin Otte  <otte@gnome.org>
+
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_audio_caps):
+	  Hi, I'm a memleak
+
+2004-05-16  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* gst/asfdemux/gstasfdemux.c:
+	  - fix a mem leak and always propagate tags
+	  - add WMV3 to known video codecs (but no decoder yet)
+	  - replace "surplus data" at end of audio header for what
+	    it is : codec specific data
+	  - fix a typo
+
+2004-05-16  Arwed v. Merkatz  <v.merkatz@gmx.net>
+
+	reviewed by: Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/audio/audioclock.c:
+	  Fix wrong return type (#142205).
+
+2004-05-16  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mad/gstmad.c: (gst_mad_class_init), (gst_mad_init):
+	  Ignore CRCs by default (fixes #142566).
+
+2004-05-16  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_open),
+	(gst_alsa_mixer_close), (gst_alsa_mixer_supported),
+	(gst_alsa_mixer_build_list), (gst_alsa_mixer_free_list),
+	(gst_alsa_mixer_change_state), (gst_alsa_mixer_list_tracks),
+	(gst_alsa_mixer_get_volume), (gst_alsa_mixer_set_volume),
+	(gst_alsa_mixer_set_mute), (gst_alsa_mixer_set_record):
+	  Fix for cases where we fail to attach to a mixer.
+
+2004-05-16  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_read_seek):
+	  Don't touch events after not owning them anymore.
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_base_init),
+	(gst_wavparse_fmt), (gst_wavparse_other),
+	(gst_wavparse_handle_seek), (gst_wavparse_loop),
+	(gst_wavparse_pad_convert), (gst_wavparse_pad_query),
+	(gst_wavparse_srcpad_event):
+	* gst/wavparse/gstwavparse.h:
+	  Add seeking, fix querying.
+
+2004-05-16  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_process_comment):
+	  - process comments even if they don't end with \0\0
+            g_convert would ignore them if present and works well without them
+
+2004-05-16  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_caps), (gst_alsa_get_caps):
+	  simplify caps
+
+2004-05-16  Benjamin Otte  <otte@gnome.org>
+
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_process_comment):
+	  don't write to memory we might not write to - g_convert does that
+	  for us anyway (fixes #142613)
+	(gst_asf_demux_audio_caps):
+	  comment out gst_util_dump_mem
+
+2004-05-16  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_loop):
+	  compute correct expected timestamps after seek (broken since
+	  last commit)
+	* ext/gdk_pixbuf/pixbufscale.c: (pixbufscale_init):
+	  rename element and debugging category to gdkpixbufscale
+
+2004-05-16  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_loop):
+	  add error checking to snd_pcm_delay and remove duplicate call to
+	  snd_pcm_delay that caused issues (see inline code comments)
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_get_time):
+	  make more readable and fix return value when snd_pcm_delay fails
+	(fixes #142586)
+
+2004-05-15  Jan Schmidt  <thaytan@mad.scientisti.com>
+	* ext/gdk_pixbuf/pixbufscale.c: (gst_pixbufscale_method_get_type),
+	(gst_pixbufscale_get_type), (gst_pixbufscale_base_init),
+	(gst_pixbufscale_class_init), (gst_pixbufscale_getcaps),
+	(gst_pixbufscale_link), (gst_pixbufscale_init),
+	(gst_pixbufscale_handle_src_event), (pixbufscale_scale),
+	(gst_pixbufscale_chain), (gst_pixbufscale_set_property),
+	(gst_pixbufscale_get_property), (pixbufscale_init):
+	* ext/gdk_pixbuf/pixbufscale.h:
+	Add these files I forgot earlier
+
+2004-05-15  Jan Schmidt  <thaytan@mad.scientist.com>
+	* ext/gdk_pixbuf/Makefile.am:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c: (plugin_init):
+	* ext/gdk_pixbuf/gstgdkpixbuf.h:
+	Add new pixbufscale element to scale RGB video
+	using gdk_pixbuf, because gdk_pixbuf does BILINEAR
+	and HYPER interpolation correctly.
+	* ext/theora/theoraenc.c: (theora_enc_chain),
+	Discard buffer and return if explicit caps could not be set
+	(theora_enc_get_property):
+	Make _get return kbps for the bitrate consistent with
+	the _set function.
+
+
+2004-05-14  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/libvisual/visual.c: (gst_visual_chain):
+	  add missing visual_audio_analyze
+
+2004-05-14  David Schleef  <ds@schleef.org>
+
+	* ext/esd/esdsink.c: (gst_esdsink_chain): Fix crash when ESD
+	is killed while we're playing.
+	* gst/qtdemux/qtdemux.c: (qtdemux_parse): call
+	gst_element_no_more_pads().
+
+2004-05-14  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* gst-libs/gst/riff/riff-read.c :
+	  - fix INFO tag extraction in RIFF/AVI files
+            because gst_event_unref (event) also freed taglist
+          - avoid a mem leak
+
+2004-05-13  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* ext/mad/gstid3tag.c : move from "Codec/(Dem/M)uxer" to "Codec/(Dem/M)uxer/Audio"
+	* gst/wavenc/gstwavenc.c : move from "Codec/Encoder/Audio" to "Codec/Muxer/Audio"
+
+	* gst/auparse/gstauparse.c :
+	  - add code (commented for now) to support audio/x-adpcm on src pad
+	    (we have no decoder for those layout yet)
+
+	* gst/cdxaparse/gstcdxaparse.c :
+	* gst/cdxaparse/gstcdxaparse.h :
+	  - partial rewrite using RiffRead (ripped iain's wavparse code)
+
+	* gst/rtp/gstrtpL16enc.c : typo
+	* gst/rtp/gstrtpgsmenc.c : typo
+
+2004-05-13  Benjamin Otte  <otte@gnome.org>
+
+	* configure.ac:
+	  check for exact version of libvisual, it's not supposed to be
+	  API/ABI stable yet
+
+2004-05-13  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_push):
+	  signal no-more-pads
+
+2004-05-13  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/dv/gstdvdec.c: (gst_dvdec_src_convert)
+	Report which format was used for GST_FORMAT_DEFAULT
+	* gst/debug/Makefile.am:
+	* gst/debug/gstdebug.c: (plugin_init):
+	* gst/debug/progressreport.c: (gst_progressreport_base_init),
+	(gst_progressreport_class_init), (gst_progressreport_init),
+	(gst_progressreport_report), (gst_progressreport_set_property),
+	(gst_progressreport_get_property), (gst_progressreport_chain),
+	(gst_progressreport_plugin_init):
+	Add progressreport element for testing.
+
+2004-05-13  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_get), (gst_v4lsrc_change_state):
+	* sys/v4l/gstv4lsrc.h:
+	* sys/v4l/v4lmjpegsink_calls.c: (gst_v4lmjpegsink_playback_init):
+	* sys/v4l/v4lmjpegsrc_calls.c: (gst_v4lmjpegsrc_capture_init):
+	* sys/v4l/v4lsrc_calls.c: (gst_v4lsrc_capture_init),
+	(gst_v4lsrc_grab_frame):
+          add more debugging
+          send a discont at start
+
+2004-05-12  Colin Walters  <walters@redhat.com>
+
+	* gst/asfdemux/gstasfdemux.c (gst_asf_demux_process_segment): Avoid
+	inflooping if we can't find a chunk.  Or in other words, don't blow
+	chunks if we don't have a chunk to blow.
+
+2004-05-13  Jan Schmidt  <thaytan@mad.scientist.com>
+	* ext/audiofile/gstafsrc.c: (gst_afsrc_get):
+	Remove old debug output
+	* ext/dv/gstdvdec.c: (gst_dvdec_quality_get_type),
+	(gst_dvdec_class_init), (gst_dvdec_loop), (gst_dvdec_change_state),
+	(gst_dvdec_set_property), (gst_dvdec_get_property):
+	Change the quality setting to an enum, so it works from gst-launch
+	Don't renegotiate a non-linked pad. Allows audio only decoding.
+	* gst/deinterlace/gstdeinterlace.c: (gst_deinterlace_getcaps),
+	(gst_deinterlace_link), (gst_deinterlace_init):
+	* gst/videodrop/gstvideodrop.c: (gst_videodrop_getcaps),
+	(gst_videodrop_link):
+	Some caps negotiation fixes
+
+2004-05-12  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* ext/tarkin/gsttarkin.c :
+	  - Change RANK from NONE to PRIMARY
+	* ext/gdk_pixbuf/gstgdkpixbuf.c :
+	  - Change RANK from NONE to MARGINAL
+	* ext/divx/gstdivxenc.c :
+	  - Change RANK from PRIMARY to NONE (encoder/spider issue)
+
+2004-05-12  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/vorbis/vorbisenc.c: (vorbis_granule_time_copy),
+	(gst_vorbisenc_push_packet):
+          copy a function that was added between 1.0 and 1.0.1 until we
+          depend on worthwhile features of post-1.0
+
+2004-05-12  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* configure.ac:
+	  enable shout2 by default
+	* ext/shout2/gstshout2.c: (gst_shout2send_protocol_get_type),
+	(gst_shout2send_base_init), (gst_shout2send_init),
+	(gst_shout2send_connect), (gst_shout2send_change_state):
+	* ext/shout2/gstshout2.h:
+	  make this work again. Based on a patch by Zaheer Abbas Merali (fixes
+	  #142262)
+	* ext/theora/theora.c: (plugin_init):
+	  don't set rank on encoders
+
+2004-05-11  Jeremy Simon  <jesimon@libertysurf.fr>
+
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_audio_caps):
+	  Use codec_data property instead of flag1 and flag2 for wma
+
+2004-05-11  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* gst/cdxaparse/gstcdxaparse.c :
+	  - Add mpegversion to CAPS to make it link
+	  - Rank is as GST_RANK_SECONDARY instead of NONE
+	* gst/auparse/gstauparse.c :
+	  - Document all audio encoding we can encounter from Solaris 9
+	    headers and libsndfile information.
+	  - Increase max. rate from 48000 to 192000 (to match other elements)
+	  - Don't try to play junk data between header and samples
+
+2004-05-11  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/libvisual/visual.c: (gst_visual_getcaps):
+	  use the right caps depending on endianness (I hope)
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_plugin_init):
+	  use GST_RANK_NONE for all non-decoding elements or spider gets
+	  mighty confused
+
+2004-05-11  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_process_comment):
+	  Fix some odd cases and fix BE metadata parsing of unicode16 text.
+
+2004-05-11  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/switch/gstswitch.c: (gst_switch_release_pad),
+	(gst_switch_request_new_pad), (gst_switch_poll_sinkpads),
+	(gst_switch_loop), (gst_switch_get_type):
+	  whoever that was: DO NOT IMPORT PRIVATE SYMBOLS THAT ARE NOT IN
+	  HEADERS. Had to be said.
+
+2004-05-10  David Schleef  <ds@schleef.org>
+
+	* configure.ac: Add prototype Dirac support.
+	* ext/Makefile.am:
+	* ext/dirac/Makefile.am:
+	* ext/dirac/gstdirac.cc:
+	* ext/dirac/gstdiracdec.cc:
+
+2004-05-10  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/auparse/gstauparse.c: (gst_auparse_class_init),
+	(gst_auparse_init), (gst_auparse_chain),
+	(gst_auparse_change_state):
+	  Hack around spider. Remove me some day please.
+
+2004-05-10  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/auparse/gstauparse.c: (gst_auparse_chain):
+	  Fix for some uninitialized variables in previous patch, also
+	  makes it work. Fixes #142286 while we're at it.
+
+2004-05-11  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* gst/auparse/gstauparse.c:
+		fixes a-law, adds mu-law, linear pcm (8,16,24,32), ieee (32, 64)
+		only unsupported formats are ADPCM/CCITT G.72x
+		reviewed by Ronald
+	* gst-libs/gst/audio/audio.h: adds 24bit depth to PCM (x-raw-int)
+
+2004-05-10  Wim Taymans  <wim@fluendo.com>
+
+	* ext/vorbis/Makefile.am:
+	* ext/vorbis/README:
+	* ext/vorbis/oggvorbisenc.c: (gst_oggvorbisenc_get_formats),
+	(oggvorbisenc_get_type), (vorbis_caps_factory), (raw_caps_factory),
+	(gst_oggvorbisenc_base_init), (gst_oggvorbisenc_class_init),
+	(gst_oggvorbisenc_sinkconnect), (gst_oggvorbisenc_convert_src),
+	(gst_oggvorbisenc_convert_sink),
+	(gst_oggvorbisenc_get_query_types), (gst_oggvorbisenc_src_query),
+	(gst_oggvorbisenc_init), (gst_oggvorbisenc_get_tag_value),
+	(gst_oggvorbisenc_metadata_set1), (gst_oggvorbisenc_set_metadata),
+	(get_constraints_string), (update_start_message),
+	(gst_oggvorbisenc_setup), (gst_oggvorbisenc_write_page),
+	(gst_oggvorbisenc_chain), (gst_oggvorbisenc_get_property),
+	(gst_oggvorbisenc_set_property), (gst_oggvorbisenc_change_state):
+	* ext/vorbis/oggvorbisenc.h:
+	* ext/vorbis/vorbis.c: (plugin_init):
+	* ext/vorbis/vorbisenc.c: (vorbis_caps_factory),
+	(raw_caps_factory), (gst_vorbisenc_class_init),
+	(gst_vorbisenc_init), (gst_vorbisenc_setup),
+	(gst_vorbisenc_push_packet), (gst_vorbisenc_chain),
+	(gst_vorbisenc_get_property), (gst_vorbisenc_set_property):
+	* ext/vorbis/vorbisenc.h:
+	Added a raw vorbis encoder to be used with the oggmuxer.
+	We still need the old encoder for some gnome applications,
+	read the README to find out how that works.
+	The raw encoder is called "rawvorbisenc" until 0.9.
+
+2004-05-10  Wim Taymans  <wim@fluendo.com>
+
+	* ext/ogg/gstogg.c: (plugin_init):
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_plugin_init),
+	(gst_ogg_print):
+	* ext/ogg/gstoggmux.c: (gst_ogg_mux_get_type),
+	(gst_ogg_mux_base_init), (gst_ogg_mux_class_init),
+	(gst_ogg_mux_get_sink_event_masks), (gst_ogg_mux_init),
+	(gst_ogg_mux_sinkconnect), (gst_ogg_mux_pad_link),
+	(gst_ogg_mux_pad_unlink), (gst_ogg_mux_request_new_pad),
+	(gst_ogg_mux_handle_src_event), (gst_ogg_mux_next_buffer),
+	(gst_ogg_mux_push_page), (gst_ogg_mux_compare_pads),
+	(gst_ogg_mux_queue_pads), (gst_ogg_mux_loop),
+	(gst_ogg_mux_get_property), (gst_ogg_mux_set_property),
+	(gst_ogg_mux_change_state), (gst_ogg_mux_plugin_init):
+	Added an ogg muxer.
+	Small typo fixes in the demuxer.
+
+2004-05-10  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/theoraenc.c: (gst_theora_enc_class_init),
+	(theora_enc_sink_link), (theora_push_packet), (theora_enc_chain),
+	(theora_enc_change_state), (theora_enc_set_property),
+	(theora_enc_get_property):
+	Mark the last packet with an EOS flag which is not really needed
+	in gstreamer.
+	Do some better video framerate initialisation.
+	Update the buffer timestamp.
+
+2004-05-10  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/dv/gstdvdec.c: (gst_dvdec_change_state):
+	Return the result of the parent state change call
+
+2004-05-10  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* gst/law/alaw.c : alawdec should be registered with type ALAWDEC, not ALAWENC
+	* gst/law/alaw-decode.c : put audio/x-alaw on pads, instead of audio/x-mulaw
+	* gst/law/alaw-encode.c : (idem)
+	* ext/a52dec/gsta52dec.c : mark audio/a52, audio/ac3 as deprecated in a comment
+	* gst/ac3parse/gstac3parse.c : audio/ac3 => audio/x-ac3
+	* gst/realmedia/rmdemux.c : audio/a52 => audio/x-ac3
+
+2004-05-09  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsasrc.c: (gst_alsa_src_loop):
+	  don't use a fixed buffer size when writing variable length data to
+	  it. Fixes memory corruption and makes alsasrc work
+
+2004-05-09  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/gnomevfs/gstgnomevfssink.c:
+	(_gst_boolean_allow_overwrite_accumulator),
+	(gst_gnomevfssink_class_init), (gst_gnomevfssink_open_file):
+	  Run glib's default signal handler (??) in RUN_CLEANUP rather than
+	  RUN_LAST, and don't use that to set the accumulator value because
+	  then it's always FALSE.
+
+2004-05-09  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_video_caps_with_data),
+	(gst_riff_create_audio_caps),
+	(gst_riff_create_audio_template_caps):
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_peek_head):
+	  Fix for unaligned RIFF files (i.e. where all the chunks together
+	  in a LIST chunk are not of the same size as the size given in
+	  the LIST chunk header). Fixes several odd WAVE files. Also fix
+	  ADPCM (block_align property) in audio, so that wavparse based
+	  on this works now as it used to stand-alone.
+
+2004-05-09  Edward Hervey  <bilboed@bilboed.com>
+
+	reviewed by Benjamin Otte  <otte@gnome.org>
+
+	* ext/a52dec/gsta52dec.c:
+	* ext/divx/gstdivxdec.c:
+	* ext/divx/gstdivxenc.c:
+	* ext/dts/gstdtsdec.c: (gst_dtsdec_base_init):
+	* ext/faac/gstfaac.c: (gst_faac_base_init):
+	* ext/faad/gstfaad.c: (gst_faad_base_init):
+	* ext/ivorbis/vorbisfile.c:
+	* ext/lame/gstlame.c:
+	* ext/libfame/gstlibfame.c:
+	* ext/mpeg2enc/gstmpeg2enc.cc:
+	* ext/musicbrainz/gsttrm.c: (gst_musicbrainz_base_init):
+	* ext/sidplay/gstsiddec.cc:
+	* ext/speex/gstspeexdec.c:
+	* ext/speex/gstspeexenc.c:
+	* ext/xvid/gstxviddec.c:
+	* ext/xvid/gstxvidenc.c:
+	  correct klasses. Mostly s,Codec/(Audio|Video),\1/Codec,
+	  (fixes #142193)
+
+2004-05-08  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsa.c: (device_list),
+	(gst_alsa_class_probe_devices):
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_open):
+	  Fix alsa oddness in mixer after the combination of using mixer
+	  in source/sink elements and using hw:x,y instead of just hw:x.
+
+2004-05-09  Benjamin Otte  <otte@gnome.org>
+
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_destroy_sourcepad),
+	(gst_wavparse_create_sourcepad):
+	  make PAUSED=>READY=>PAUSED=READY work by not destroying NULL
+	  sourcepads
+
+2004-05-09  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event):
+	  allow discont events before caps nego
+
+2004-05-08  Benjamin Otte  <otte@gnome.org>
+
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_event):
+	  don't leak events
+
+2004-05-08  Benjamin Otte  <otte@gnome.org>
+
+	* gst/level/gstlevel.c: (gst_level_link), (gst_level_chain),
+	(gst_level_change_state), (gst_level_init):
+	* gst/level/gstlevel.h:
+	  figure out if we're initialized directly instead of keeping a
+	  variable that's wrong in 90% of cases
+	  don't initialize pads and then leak them and use a new unitialized
+	  pad. (fixes #142084)
+	  these were bugs so n00bish I didn't find them for an hour :/
+
+2004-05-08 Iain <iain@prettypeople.org>
+
+	* gst/wavparse/gstwavparse.[ch]: Rewrote to use RiffRead instead.
+	* gst-libs/gst/riff/riff-read.c (gst_riff_read_peek_head): Unstatic it
+	(gst_riff_read_element_data): Ditto, and added a got_bytes argument to
+	return the length that was read.
+	(gst_riff_read_strf_auds): Allow fmt tags as well.
+
+2004-05-07  David Schleef  <ds@schleef.org>
+
+	* ext/faad/gstfaad.c: (gst_faad_sinkconnect): HACK to correct
+	signed char assumption in faad.h.
+
+2004-05-07  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l2/gstv4l2src.c: (gst_v4l2src_v4l2fourcc_to_caps):
+	  Missing break, detected by Daniel Gazard <daniel.gazard@free.fr>.
+
+2004-05-07  Colin Walters  <walters@redhat.com>
+
+	* gst/volume/gstvolume.c (gst_volume_dispose): Unref dpman.
+	* ext/flac/gstflacdec.c (gst_flacdec_dispose): Add dispose
+	function.
+	* gst/audioscale/gstaudioscale.c (gst_audioscale_dispose):
+	Add dispose function.
+
+2004-05-08  Jan Schmidt  <thaytan@mad.scientist.com>
+	* ext/dv/gstdvdec.c: (gst_dvdec_video_link):
+	  Fix caps nego and pad templates. RGB mode caps should
+	  work now.
+	* ext/dvdnav/gst-dvd:
+	  Move mpeg2dec inside the thread because otherwise the
+	  queue rejects cap changes mid-stream
+	* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_get_type),
+	(gst_mpeg2dec_flush_decoder):
+	  For mpeg2dec > 0.4.0, call the flush function instead of
+	  manually extracting all in-flight frames.
+	* ext/raw1394/gstdv1394src.c: (gst_dv1394src_factory),
+	(gst_dv1394src_init), (gst_dv1394src_iso_receive):
+	  Change mime type video/dv go video/x-dv to match the
+	  rest of gst-plugins
+
+2004-05-07  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_build_list):
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_get_type),
+	(gst_alsa_sink_class_init):
+	* ext/alsa/gstalsasink.h:
+	* ext/alsa/gstalsasrc.c: (gst_alsa_src_get_type),
+	(gst_alsa_src_class_init):
+	* ext/alsa/gstalsasrc.h:
+	  Make alsasink/src a subclass of alsamixer so that mixer stuff
+	  shows up in gst-rec. Needs some finetuning.
+
+2004-05-05  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/lame/gstlame.c: (gst_lame_chain):
+	  simplify
+	* ext/mad/gstmad.c: (gst_mad_handle_event):
+	  fix event leak
+	* gst/typefind/gsttypefindfunctions.c: (mp3_type_find):
+	  be able to detect mp3 files < 4096 bytes
+
+2004-05-06  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/theoraenc.c: (gst_theora_enc_class_init),
+	(theora_enc_sink_link), (theora_push_packet), (theora_enc_chain),
+	(theora_enc_set_property), (theora_enc_get_property):
+	Also encode the first frame, cleanup some code.
+
+2004-05-06  Wim Taymans  <wim@fluendo.com>
+
+	* ext/mpeg2enc/gstmpeg2enc.cc:
+	Forward events first before deciding that negotiation was
+	not performed.
+
+2004-05-06  Wim Taymans  <wim@fluendo.com>
+
+	* gst/wavenc/gstwavenc.c: (gst_wavenc_chain):
+	First process the events before deciding that negotiation
+	was not performed.
+
+2004-05-06  Wim Taymans  <wim@fluendo.com>
+
+	* ext/theora/Makefile.am:
+	* ext/theora/theora.c: (plugin_init):
+	* ext/theora/theoradec.c: (theora_dec_change_state):
+	* ext/theora/theoraenc.c: (gst_theora_enc_base_init),
+	(gst_theora_enc_class_init), (gst_theora_enc_init),
+	(theora_enc_sink_link), (theora_enc_event), (theora_push_packet),
+	(theora_enc_chain), (theora_enc_change_state),
+	(theora_enc_set_property), (theora_enc_get_property):
+	Added a theora encoder, grouped the encoder and decoder into the
+	same plugin.
+
+2004-05-05  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/jpeg/gstjpegenc.c: (gst_jpegenc_get_type),
+	(gst_jpegenc_chain):
+        fix DURATION on outgoing buffers
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_handle_sink_event):
+        debug using time formats
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xcontext_get):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_xv_support),
+	(gst_xvimagesink_sink_link):
+        windows with width/height 0 generate X errors, so don't allow them
+
+2004-05-05  Wim Taymans  <wim@fluendo.com>
+
+	* ext/mpeg2dec/gstmpeg2dec.c: (src_templ),
+	(gst_mpeg2dec_base_init), (gst_mpeg2dec_init),
+	(gst_mpeg2dec_negotiate_format):
+	* ext/mpeg2dec/gstmpeg2dec.h:
+	  removed the static pad template so that we can add the
+	  more accurate framerate value to the caps.
+
+
+2004-05-04  Benjamin Otte  <otte@gnome.org>
+
+	* configure.ac:
+	  check for kdemacros.h, too (should fix #141821)
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_event), (vorbis_dec_chain):
+	  don't crash if no header was sent, but nicely error out (fixes part
+	  of #141554)
+
+2004-05-04  Wim Taymans  <wim@fluendo.com>
+
+	* ext/mpeg2enc/gstmpeg2enc.cc: (gst_mpeg2enc_dispose): call the
+	parent dispose function to avoid segfault on destroy.
+
+2004-05-04  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_sink_link),
+	(plugin_init):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xcontext_get),
+	(gst_xvimagesink_sink_link):
+        clean up debugging caps
+        also recreate xvimage when format has changed
+
+2004-05-04  Benjamin Otte  <otte@gnome.org>
+
+	* ext/libvisual/Makefile.am:
+	* ext/libvisual/visual.c: (gst_visual_class_init),
+	(gst_visual_init), (gst_visual_dispose), (gst_visual_getcaps),
+	(gst_visual_srclink), (gst_visual_chain),
+	(gst_visual_change_state), (plugin_init):
+	  use a GstAdapter to correctly adapt buffer sizes - allows using a
+	  framerate
+
+2004-05-03  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/v4l/gstv4lelement.h:
+	* sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_class_init):
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_get_fps), (gst_v4lsrc_getcaps),
+	(gst_v4lsrc_buffer_free):
+	* sys/v4l/v4l_calls.c: (gst_v4l_get_capabilities):
+	* sys/v4l/v4lsrc_calls.c: (gst_v4lsrc_queue_frame),
+	(gst_v4lsrc_sync_frame), (gst_v4lsrc_grab_frame),
+	(gst_v4lsrc_requeue_frame):
+        move some debugging categories around
+        query for fps index and set accordingly if found
+
+2004-05-03  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* ext/lame/gstlame.c:
+	correct defaults that lame_init puts out of range
+
+2004-05-03  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/divx/gstdivxenc.c: (gst_divxenc_get_type),
+	(gst_divxenc_class_init):
+        fix range since -1 is the default
+	* gst/mpeg1sys/gstmpeg1systemencode.c:
+	(gst_mpeg1_system_encode_get_type), (gst_system_encode_multiplex):
+	* gst/rtjpeg/gstrtjpegdec.c: (gst_rtjpegdec_get_type),
+	(gst_rtjpegdec_chain):
+	* gst/rtjpeg/gstrtjpegenc.c: (gst_rtjpegenc_get_type),
+	(gst_rtjpegenc_chain):
+	* sys/qcam/gstqcamsrc.c: (gst_autoexp_mode_get_type),
+	(gst_qcamsrc_get_type), (gst_qcamsrc_change_state):
+	* sys/v4l/gstv4lmjpegsink.c: (gst_v4lmjpegsink_get_type):
+	* sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_get_type):
+	* sys/v4l/gstv4lsrc.c:
+	* sys/v4l/v4l_calls.c: (gst_v4l_open):
+	* sys/v4l/v4lmjpegsink_calls.c: (gst_v4lmjpegsink_playback_init):
+	* sys/v4l/v4lmjpegsrc_calls.c: (gst_v4lmjpegsrc_capture_init):
+	* sys/v4l/v4lsrc_calls.c: (gst_v4lsrc_capture_init):
+	* sys/vcd/vcdsrc.c: (vcdsrc_get_type), (vcdsrc_get):
+          remove gst_info calls
+
+2004-05-03  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* Makefile.am:
+	* po/af.po:
+	* po/az.po:
+	* po/en_GB.po:
+	* po/nl.po:
+	* po/sr.po:
+	* po/sv.po:
+          Updated translations
+
+2004-05-03  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/audioconvert/gstaudioconvert.c: (_fixate_caps_to_int):
+          refactor/comment code
+
+2004-05-02  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/asfdemux/Makefile.am:
+	* gst/asfdemux/asfheaders.c:
+	* gst/asfdemux/asfheaders.h:
+	* gst/asfdemux/gstasf.c: (plugin_init):
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_get_type),
+	(gst_asf_demux_base_init), (gst_asf_demux_process_comment),
+	(gst_asf_demux_setup_pad):
+	* gst/asfdemux/gstasfdemux.h:
+	* gst/asfdemux/gstasfmux.c:
+	* gst/asfdemux/gstasfmux.h:
+	  Add tagging support to demuxer, split out registration in its own
+	  file instead of in demux (hacky), and prevent having some tables
+	  in our memory multiple times (in asfheaders.h).
+
+2004-05-01  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/matroska-demux.c:
+	(gst_matroska_demux_parse_metadata):
+	* gst/matroska/matroska-ids.h:
+	  Basic tag reading support.
+
+2004-04-30  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_audio_caps):
+	  Really detect ac-3 audio.
+	* gst/typefind/gsttypefindfunctions.c: (matroska_type_find):
+	  really detect matroska files (off-by-1).
+
+2004-04-30  David Schleef  <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header),
+	(gst_qtdemux_add_stream), (qtdemux_parse), (qtdemux_type_get),
+	(qtdemux_dump_stsz), (qtdemux_dump_stco), (qtdemux_dump_co64),
+	(qtdemux_dump_unknown), (qtdemux_parse_tree), (qtdemux_parse_udta),
+	(qtdemux_tag_add), (get_size), (gst_qtdemux_handle_esds): More qtdemux
+	hackage -- parse a lot more atoms, extract a few tags.  One might even
+	mistake this for tag support.  Maybe it is.
+	* gst/qtdemux/qtdemux.h:
+
+2004-04-30  Colin Walters  <walters@verbum.org>
+
+	* ext/alsa/gstalsasink.c (gst_alsa_sink_mmap): Plug a memleak.
+
+2004-04-30  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+	(gst_ffmpegcolorspace_getcaps):
+          remove broken nego fix
+
+2004-04-30  Benjamin Otte  <otte@gnome.org>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/libvisual/Makefile.am:
+	* ext/libvisual/visual.c:
+	  add initial support for libvisual (http://libvisual.sourceforge.net)
+	  libvisual is still quite alpha, so expect crashes in there :)
+
+2004-04-29  David Schleef  <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_add_stream), (qtdemux_parse),
+	(qtdemux_parse_trak), (get_size), (gst_qtdemux_handle_esds): Hacked
+	up qtdemux to make it spit out codec_data.  Do _not_ look at this
+	code; you will no longer respect me.
+
+2004-04-29  Stephane Loeuillet <stephane.loeuillet@tiscali.fr>
+
+	* ext/alsa/gstalsa.c : (gst_alsa_class_probe_devices)
+	* ext/alsa/gstalsa.h :
+	change alsa pcm device discovery to find more than 1 device
+	per card. code review by Ronald.
+
+2004-04-29  David Schleef  <ds@schleef.org>
+
+	* sys/oss/gstosselement.c: (gst_osselement_rate_probe_check):
+	Add a check for a driver bug on FreeBSD.  (bug #140565)
+
+2004-04-29  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/jpeg/gstjpegdec.c: (gst_jpegdec_get_type):
+	* ext/jpeg/gstjpegenc.c: (gst_jpegenc_get_type),
+	(gst_jpegenc_getcaps):
+          move format setting to inner loop
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+	(gst_ffmpegcolorspace_getcaps):
+          use GST_PAD_CAPS if available so that we use already negotiated
+          caps
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header),
+	(qtdemux_parse_moov), (qtdemux_parse):
+          extra debugging
+	* sys/qcam/qcam-Linux.c: (qc_lock_wait), (qc_unlock):
+	* sys/qcam/qcam-os.c: (qc_lock_wait), (qc_unlock):
+          move hardcoded path to DEFINE
+
+2004-04-28  David Schleef  <ds@schleef.org>
+
+	* gst/speed/gstspeed.c: (speed_parse_caps):  Fix caps parsing.
+	(bug #140064)
+
+2004-04-28  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_class_probe_devices):
+	  Don't probe for playback device if we're a source element. Fixes
+	  #139658.
+
+2004-04-29  Benjamin Otte  <otte@gnome.org>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_handle_event),
+	(gst_id3_tag_chain):
+	  rewrite buffer offset
+
+2004-04-28  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/dts/Makefile.am:
+	* ext/dts/gstdtsdec.c: (gst_dtsdec_get_type),
+	(gst_dtsdec_base_init), (gst_dtsdec_class_init), (gst_dtsdec_init),
+	(gst_dtsdec_channels), (gst_dtsdec_renegotiate),
+	(gst_dtsdec_handle_event), (gst_dtsdec_update_streaminfo),
+	(gst_dtsdec_loop), (gst_dtsdec_change_state),
+	(gst_dtsdec_set_property), (gst_dtsdec_get_property),
+	(plugin_init):
+	* ext/dts/gstdtsdec.h:
+	  New DTS decoder.
+	* ext/faad/gstfaad.c: (gst_faad_sinkconnect),
+	(gst_faad_srcconnect):
+	  Add ESDS atom handling (.m4a).
+
+2004-04-27  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/divx/gstdivxdec.c: (plugin_init):
+	  Remove comment that makes no sense.
+	* ext/mad/gstid3tag.c: (gst_id3_tag_set_property):
+	  Fix for obvious typo that resulted in warnings during gst-register.
+	* ext/xvid/gstxviddec.c: (gst_xviddec_src_link),
+	(gst_xviddec_sink_link):
+	  Fix caps negotiation a bit better.
+	* gst/qtdemux/qtdemux.c: (qtdemux_parse_trak):
+	  We call this 'codec_data', not 'esds'.
+
+2004-04-27  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/monoscope/gstmonoscope.c:
+	  make sure we only provide 256x128
+	* gst/monoscope/monoscope.c: (monoscope_init):
+	  assert size of 256x128
+
+2004-04-27  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* Makefile.am:
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_init), (gst_v4lsrc_fixate),
+	(gst_v4lsrc_getcaps), (gst_v4lsrc_buffer_free):
+          fixate to max width and height of device
+
+2004-04-27  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* Makefile.am:
+	* sys/v4l/gstv4l.c:
+	* sys/v4l/gstv4lsrc.c:
+	* sys/v4l/v4l_calls.c:
+	* sys/v4l/v4lsrc_calls.c:
+          fix for qc-usb driver which fakes having more than one buffer
+          by handing the same buffer twice, which confused GStreamer's/v4lsrc
+          buffer_free override
+          add debugging
+
+2004-04-27  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* Makefile.am:
+	* gst/videotestsrc/gstvideotestsrc.c:
+	(gst_videotestsrc_class_init), (gst_videotestsrc_change_state),
+	(gst_videotestsrc_init), (gst_videotestsrc_get),
+	(gst_videotestsrc_set_property), (gst_videotestsrc_get_property):
+	* gst/videotestsrc/gstvideotestsrc.h:
+          add num-buffers property
+
+	2004-04-26  Benjamin Otte  <otte@gnome.org>
+
+	* ext/mad/gstid3tag.c: (plugin_init):
+	  set id3mux rank to NONE so it doesn't confuse spider
+	  require audio/mpeg,mpegversion=1 in id3mux
+
+2004-04-26  Benjamin Otte  <otte@gnome.org>
+
+	* configure.ac:
+	  detect faad correctly as non-working if it's indeed non-working
+
+2004-04-26  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* Makefile.am:
+	* ext/jpeg/gstjpegenc.c: (gst_jpegenc_get_type),
+	(gst_jpegenc_class_init), (gst_jpegenc_getcaps):
+        fix _getcaps so it only negotiates to its supported format
+
+2004-04-25  Benjamin Otte  <otte@gnome.org>
+
+	* gst/audioconvert/gstaudioconvert.c: (_fixate_caps_to_int):
+	  fix memleak
+
+2004-04-23  Benjamin Otte  <otte@gnome.org>
+
+	* gst-libs/gst/riff/riff-media.c: (gst_riff_create_audio_caps):
+	  audio/x-raw-int with height rules! not. Now it's depth.
+
+2004-04-22  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_create_sourcepad),
+	(gst_wavparse_parse_fmt), (gst_wavparse_handle_sink_event),
+	(gst_wavparse_loop):
+	  Missing variable initialization. Add handling of DVI ADPCM. Fix
+	  mis-parsing of LIST chunks. This works around a bug where we mis-
+	  parse non-aligning LIST chunks (so LIST chunks where the contents
+	  don't align with the actual LIST size). The correct fix is to use
+	  rifflib, I'm not going to fix wavparse - too much work. All this
+	  fixes #104878.
+
+2004-04-22  Zaheer Abbas Merali  <zaheerabbas at merali dot org>
+
+	reviewed by Benjamin Otte  <otte@gnome.org>
+
+	* ext/shout/gstshout.c: (gst_icecastsend_change_state):
+	  fix shoutcast not working (fixes #140844)
+
+2004-04-22  Benjamin Otte  <otte@gnome.org>
+
+	* ext/hermes/gsthermescolorspace.c:
+	(gst_hermes_colorspace_caps_remove_format_info):
+	* gst/colorspace/gstcolorspace.c:
+	(gst_colorspace_caps_remove_format_info):
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+	(gst_ffmpegcolorspace_caps_remove_format_info):
+	  s/gst_caps_simplify/gst_caps_do_simplify/
+
+2004-04-22  Benjamin Otte  <otte@gnome.org>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_video_caps_with_data):
+	  mpegversion is an int
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_base_init):
+	  don't try to create pad templates with NULL caps, use any caps
+	  instead.
+
+2004-04-20  David Schleef  <ds@schleef.org>
+
+	* ext/sdl/Makefile.am: Link against libgstinterfaces, not
+	libgstxoverlay.  jmmv@menta.net (Julio M. Merino Vidal)
+	(bug #140384)
+
+2004-04-20  Daniel Gazard  <daniel.gazard@epita.fr>
+
+	reviewed by David Schleef
+
+	* ext/mad/gstid3tag.c: Add stdlib.h
+	* gst/rtp/gstrtpgsmenc.c: same
+	* gst/tags/gstid3tag.c: same
+	* gst/udp/gstudpsrc.c: (gst_udpsrc_get): Fix GST_DISABLE_LOADSAVE
+	* gst/tcp/gsttcpsink.c: (gst_tcpsink_sink_link): Adjust
+	GST_DISABLE_LOADSAVE use.
+	* gst/udp/gstudpsink.c: (gst_udpsink_sink_link): Likewise.
+	* gst/tcp/gsttcpsrc.c: (gst_tcpsrc_get): Likewise.
+	* ext/gnomevfs/gstgnomevfssrc.c: Include <stdlib.h> (needed by
+	atol(3)).
+	* sys/oss/gstosselement.h: Include <sys/types.h> (needed for dev_t).
+	* gst/tags/gstvorbistag.c: Include <stdlib.h> (needed by
+	strtoul(3)).
+	* gst/rtp/gstrtpL16enc.c: Include <stdlib.h> (needed by random(3)).
+	* ext/mad/Makefile.am: (libgstmad_la_CFLAGS): Add $(MAD_CFLAGS)
+	$(ID3_CFLAGS).
+	* ext/libfame/Makefile.am: (libgstlibfame_la_CFLAGS): Add
+	$(LIBFAME_CFLAGS).
+
+2004-04-20  David Schleef  <ds@schleef.org>
+
+	* gst/realmedia/rmdemux.c:  This was supposed to part of the
+	last checkin.  Same idea.
+
+2004-04-20  Daniel Gazard  <daniel.gazard@epita.fr>
+
+	reviewed by David Schleef
+
+	* configure.ac: bump required gstreamer version to 0.8.1.1
+	because of following changes [--ds]
+
+	* gst-libs/gst/riff/riff-read.c:  Include gst/gstutils.h.
+	(gst_riff_peek_head, gst_riff_peek_list, gst_riff_read_list)
+	(gst_riff_read_header):  Use GST_READ_UINT*
+	macros to access possibly unaligned memory.
+
+	* gst/typefind/gsttypefindfunctions.c: Include gst/gstutils.h.
+	(mp3_type_find):  Use GST_READ_UINT*
+	macros to access possibly unaligned memory.
+	(mp3_type_find, mpeg1_parse_header, qt_type_find)
+	(speex_type_find): Likewise
+
+	* gst/tags/gstvorbistag.c: (ADVANCE): Likewise
+
+	* gst/qtdemux/qtdemux.c: Include stdlib.h (needed by realloc).
+	(QTDEMUX_GUINT32_GET, QTDEMUX_GUINT16_GET, QTDEMUX_FP32_GET)
+	(QTDEMUX_FP16_GET, QTDEMUX_FOURCC_GET)
+	(gst_qtdemux_loop_header, gst_qtdemux_loop_header)
+	(qtdemux_node_dump_foreach, qtdemux_tree_get_child_by_type)
+	(qtdemux_tree_get_sibling_by_type):  Use GST_READ_UINT*
+	macros to access possibly unaligned memory.
+
+	* gst/mpegstream/gstmpegpacketize.c: (parse_generic, parse_chunk):
+	Likewise.
+
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_parse_syshead)
+	(gst_mpeg_demux_parse_packet, gst_mpeg_demux_parse_pes): Likewise.
+
+	* gst/mpegaudioparse/gstmpegaudioparse.c: (gst_mp3parse_chain):
+	Likewise.
+
+	* gst/mpeg2sub/gstmpeg2subt.c: (GST_BUFFER_DATA)
+	(gst_mpeg2subt_chain_subtitle): Likewise.
+
+	* gst/mpeg1videoparse/gstmp1videoparse.c: (mp1videoparse_parse_seq)
+	(gst_mp1videoparse_time_code, gst_mp1videoparse_real_chain):
+	Likewise.
+
+	* gst/mpeg1sys/buffer.c: (mpeg1mux_buffer_update_audio_info):
+	Likewise.
+
+	* gst/cdxaparse/gstcdxaparse.c: (gst_bytestream_peek_bytes):
+	Likewise.
+
+	* gst/asfdemux/gstasfdemux.c: (_read_var_length, _read_uint):
+	Likewise.
+
+2004-04-20  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+          update required version of GStreamer because of GST_TIME_FORMAT
+
+2004-04-20  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_init):
+	  remove leftover g_print
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_link):
+	  don't try setting only a subset of the caps. We don't want to kill
+	  autoplugging on purpose
+
+2004-04-20  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/ximage/ximagesink.c: (plugin_init):
+	* sys/xvimage/xvimagesink.c: (plugin_init):
+          add debugging categories
+
+2004-04-20  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* po/en_GB.po:
+        * po/LINGUAS:
+          Adding en_GB translation (Gareth Owen)
+
+2004-04-20  David Schleef  <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_handle_sink_event),
+	(qtdemux_parse), (qtdemux_type_get), (qtdemux_dump_mvhd),
+	(qtdemux_dump_tkhd), (qtdemux_dump_stsd), (qtdemux_dump_unknown),
+	(qtdemux_parse_trak), (qtdemux_video_caps), (qtdemux_audio_caps):
+	A number of new features and hacks to extract the esds atom and
+	put it into the caps.  (bug #137724)
+
+2004-04-19  David Schleef  <ds@schleef.org>
+
+	* gconf/Makefile.am: Fix for non-GNU make
+	* gst-libs/gst/Makefile.am: Change directory order to handle
+	GstPlay linking with gstinterfaces
+	* gst-libs/gst/audio/make_filter: make use of tr portable
+	* gst-libs/gst/play/Makefile.am: Add intended \
+	* gst-libs/gst/xwindowlistener/xwindowlistener.c:
+	(gst_xwin_set_clips): Switch to ISO variadic macro. Use a
+	function prototype instead of void *.
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c: Switch to ISO variadic
+	macro.
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+	(gst_ffmpegcolorspace_chain): wrap NULL in GST_ELEMENT_ERROR call
+	* gst/videofilter/make_filter: make use of tr portable
+	* pkgconfig/Makefile.am: Remove GNU extension in Makefile target
+
+2004-04-19  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* po/LINGUAS:
+	* po/uk.po:
+          Added Ukrainian translation (Maxim V. Dziumanenko)
+
+2004-04-18  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/gsm/gstgsmdec.c: (gst_gsmdec_init), (gst_gsmdec_getcaps),
+	(gst_gsmdec_link), (gst_gsmdec_chain):
+	  Fix capsnego, simplify chain function slightly.
+	* gst/qtdemux/qtdemux.c: (qtdemux_audio_caps):
+	  Add GSM.
+
+2004-04-18  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_init),
+	(gst_wavparse_destroy_sourcepad), (gst_wavparse_create_sourcepad),
+	(gst_wavparse_parse_fmt), (gst_wavparse_change_state):
+	  Hack to make wavparse work with spider (always -> sometimes pad).
+	  Fixes #135862 && #140411.
+
+2004-04-18  Benjamin Otte  <otte@gnome.org>
+
+	* sys/oss/gstosselement.c: (gst_osselement_sync_parms),
+	(gst_osselement_rate_probe_check),
+	(gst_osselement_rate_check_rate), (gst_osselement_rate_add_rate):
+	  get rid of \n in debug output
+
+2004-04-17  Iain <iain@prettypeople.org>
+
+	* gst/wavparse/gstwavparse.c (gst_wavparse_loop): Allow all events,
+	not just EOS.
+
+2004-04-17  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_get_type),
+	(gst_id3_tag_class_init), (gst_id3_tag_get_caps),
+	(gst_id3_tag_add_src_pad), (gst_id3_tag_init),
+	(gst_id3_tag_set_property), (gst_id3_tag_do_caps_nego),
+	(gst_id3_tag_src_link), (gst_id3_tag_chain),
+	(gst_id3_tag_change_state), (plugin_init):
+	  deprecate id3tag element and replace with id3demux/id3mux.
+	  great side effect: this ugly file is now even uglier, yay!
+	* ext/mad/gstmad.h:
+	  remove non-available function
+	  update for new get_type
+
+2004-04-17  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* configure.ac:
+	  require mpeg2dec >= 0.4.0
+
+2004-04-17  Benjamin Otte  <otte@gnome.org>
+
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_xv_support),
+	(gst_xvimagesink_xcontext_get), (gst_xvimagesink_change_state),
+	(gst_xvimagesink_set_xwindow_id):
+	  call GST_ELEMENT_ERROR whenever get_xcontext fails. Includes
+	  assorted cleanup fixes.
+
+2004-04-16  David Schleef  <ds@schleef.org>
+
+	* sys/ximage/ximagesink.h: Compile fix for FreeBSD. (bug #140268)
+	* sys/xvimage/xvimagesink.h: same
+
+2004-04-16  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/gnomevfs/gstgnomevfssink.c: (gst_gnomevfssink_open_file):
+          Fix GST_ELEMENT_ERROR with (NULL)
+
+2004-04-15  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_video_caps_with_data):
+	  Add div[3456] as fourccs for DivX 3 (fixes #140137).
+
+2004-04-15  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c:
+	(gst_riff_create_video_caps_with_data),
+	(gst_riff_create_video_caps), (gst_riff_create_audio_caps),
+	(gst_riff_create_video_template_caps),
+	(gst_riff_create_audio_template_caps):
+	* gst-libs/gst/riff/riff-media.h:
+	* gst-libs/gst/riff/riff-read.c:
+	(gst_riff_read_strf_vids_with_data), (gst_riff_read_strf_vids):
+	* gst-libs/gst/riff/riff-read.h:
+	* gst/avi/gstavidemux.c: (gst_avi_demux_add_stream):
+	  Add MS RLE support. I added some functions to read out strf chunks
+	  into strf chunks and the data behind it. This is usually color
+	  palettes (as in RLE, but also in 8-bit RGB). Also use those during
+	  caps creation. Lastly, add ADPCM (similar to wavparse - which
+	  should eventually be rifflib based).
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_class_init),
+	(gst_matroska_demux_init), (gst_matroska_demux_reset):
+	* gst/matroska/matroska-demux.h:
+	  Remove placeholders for some prehistoric tagging system. Didn't add
+	  support for any tag system really anyway.
+	* gst/qtdemux/qtdemux.c:
+	  Add support for audio/x-m4a (MPEG-4) through spider.
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_parse_fmt),
+	(gst_wavparse_loop):
+	  ADPCM support (#135862). Increase max. buffer size because we
+	  cannot split buffers for ADPCM (screws references) and I've seen
+	  files with 2048 byte chunks. 4096 seems safe for now.
+
+2004-04-15  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac: bump nano to 1
+
+=== release 0.8.1 ===
+
+2004-04-15  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac: releasing 0.8.1, "Comforting Sounds"
+
+2004-04-14  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c: (gst_riff_create_video_caps):
+	  Fix typo in divxversion (3 instead of 4 for "DIVX" fourcc).
+	  Fixes #140058
+
+2004-04-14  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_plugin_init):
+          lower rank of dvddemux so that it's not used for mpeg playback.
+
+2004-04-14  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* configure.ac:
+	  save libs correctly when checking mad
+
+2004-04-14  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/mad/gstid3tag.c: (plugin_init):
+          lower rank of id3tag as proposed by Benjamin.  Fixes #139926.
+
+2004-04-13  David Schleef  <ds@schleef.org>
+
+	* common/m4/gst-feature.m4: Call -config scripts with
+	--plugin-libs if it is supported.
+	* gst/avi/gstavimux.c: (gst_avimux_vidsinkconnect): sequences of
+	JPEG images are image/jpeg.
+	* gst/debug/Makefile.am:
+	* gst/debug/negotiation.c: (gst_negotiation_class_init),
+	(gst_negotiation_getcaps), (gst_negotiation_pad_link),
+	(gst_negotiation_update_caps), (gst_negotiation_get_property),
+	(gst_negotiation_plugin_init): Add a property that acts like
+	filter caps.
+	* testsuite/gst-lint:  Move license checking to be a standard
+	test.
+
+2004-04-13  David Schleef  <ds@schleef.org>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_reset): Fix memleak.
+	patch from Sebastien Cote (bug #139958)
+
+2004-04-13  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* examples/gstplay/Makefile.am:
+	* examples/gstplay/player.c: (main):
+          make the commandline player example use gconf settings
+
+2004-04-13  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/libcaca/gstcacasink.c: (gst_cacasink_class_init),
+	(gst_cacasink_sinkconnect), (gst_cacasink_init),
+	(gst_cacasink_chain), (gst_cacasink_open), (gst_cacasink_close):
+          init/end library during state transition, not object
+          creation/disposal.  get rid of custom dispose handler.
+
+
+2004-04-12  Christian Schaller <Uraeus@gnome.org>
+
+	* sys/oss/gstosselement.c: s/lstat/stat/ from freeBSD, since it can
+	be a symlink
+
+2004-04-11  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_stream_data):
+	  Handle JUNK chunks inside data section. Prevents warnings.
+
+2004-04-11  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c: (gst_riff_create_video_caps),
+	(gst_riff_create_video_template_caps):
+	  Add MS video v1.
+	* gst/avi/gstavidemux.c: (gst_avi_demux_stream_index),
+	(gst_avi_demux_stream_data):
+	  Add support for "rec-list" chunks.
+
+2004-04-11  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c: (gst_riff_create_audio_caps):
+	  Fix another codecname mismatch.
+
+2004-04-11  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-media.c: (gst_riff_create_video_caps):
+	  Fix divx caps mismatch and move from video/x-jpeg to image/jpeg
+	  so that MJPEG plays back.
+
+2004-04-10  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/mpeg1videoparse/gstmp1videoparse.c: (gst_mp1videoparse_init),
+	(gst_mp1videoparse_real_chain), (gst_mp1videoparse_change_state):
+	* gst/mpeg1videoparse/gstmp1videoparse.h:
+	  Fix for some slight mis-cuts in buffer parsing, and for some
+	  potential overflows or faults-causers. Adds disconts. Also fixes
+	  #139105 while we're at it.
+
+2004-04-10  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* sys/v4l2/gstv4l2element.h:
+	  Workaround for missing struct v4l2_buffer declaration in Suse 9
+	  and Mandrake 10 linux/videodev2.h header file (#135919).
+
+2004-04-10  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/gnomevfs/gstgnomevfssink.c: (gst_gnomevfssink_open_file):
+	  Bail out if no filename was given.
+
+2004-04-10  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l2/gstv4l2src.c: (gst_v4l2src_v4l2fourcc_to_caps),
+	(gst_v4l2_fourcc_from_structure):
+	  Add Y41B/Y42B YUV formats (see #125732), fix Y41P (was typo'ed to
+	  Y41B somewhere).
+
+2004-04-09  Benjamin Otte  <otte@gnome.org>
+
+	* ext/gnomevfs/gstgnomevfssink.c:
+	(_gst_boolean_allow_overwrite_accumulator),
+	(gst_gnomevfssink_class_init):
+	  fix erase signal - if any handler returns false the file will not be
+	  overwritten. If no handler is connected, the file will not be
+	  overwritten either.
+	  renamed signal to "allow-overwrite"
+	* ext/mad/gstid3tag.c: (tag_list_to_id3_tag_foreach):
+	  free string when adding it to ID3 failed
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_event):
+	  unref event when done
+	* gst/audioconvert/gstaudioconvert.c: (_fixate_caps_to_int):
+	  free caps
+	* gst/typefind/gsttypefindfunctions.c:
+	(mpeg_video_stream_type_find):
+	  fix invalid read
+
+2004-04-08  David Schleef  <ds@schleef.org>
+
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+	(gst_ffmpegcolorspace_register): Change rank to PRIMARY.
+
+2004-04-08  David Schleef  <ds@schleef.org>
+
+	* gst/colorspace/gstcolorspace.c: Don't advertise a conversion
+	we don't support (bug #139532)
+
+2004-04-07  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/mad/gstmad.c: (gst_mad_handle_event),
+	(gst_mad_check_caps_reset), (gst_mad_chain),
+	(gst_mad_change_state):
+          only set explicit caps if they haven't been set before for
+          this stream.  MPEG-audio sample rate/channels aren't allowed
+          to change in-stream.
+          Fixes #139382
+
+2004-04-06  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/gnomevfs/gstgnomevfssink.c: (gst_gnomevfssink_base_init),
+	(_gst_boolean_did_something_accumulator),
+	(gst_gnomevfssink_class_init), (gst_gnomevfssink_dispose),
+	(gst_gnomevfssink_init), (gst_gnomevfssink_set_property),
+	(gst_gnomevfssink_get_property), (gst_gnomevfssink_open_file),
+	(gst_gnomevfssink_close_file), (gst_gnomevfssink_chain),
+	(gst_gnomevfssink_change_state):
+	  Fix erase signal. Don't erase by default. Remove handoff signal.
+	  Remove erase property. Don't segfault. General cleanup.
+
+2004-04-07  Benjamin Otte  <otte@gnome.org>
+
+	* gst-libs/gst/gconf/test-gconf.c: (main):
+	  add missing gst_init
+
+2004-04-07  Benjamin Otte  <otte@gnome.org>
+
+	* ext/gnomevfs/gstgnomevfssrc.c: (gst_gnomevfssrc_dispose):
+	  free the mutexes, too
+
+2004-04-07  Benjamin Otte  <otte@gnome.org>
+
+	* ext/gnomevfs/gstgnomevfssrc.c: (gst_gnomevfssrc_dispose):
+	  actually free the URI string
+	* ext/mad/gstid3tag.c: (gst_id3_tag_src_event):
+	  compute offset correctly when passing discont events
+	* ext/mad/gstid3tag.c: (gst_id3_tag_handle_event):
+	  don't leak discont events
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_video_caps):
+	  add some missing breaks so caps aren't copied randomly
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_get_video_stream):
+	  if we realloc memory, we better use it
+
+2004-04-06  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/mad/gstmad.c: (normal_seek):
+	  fix GST_FORMAT_TIME usage
+
+2004-04-05  David Schleef  <ds@schleef.org>
+
+	* ext/kio/kiosrc.cpp:  Undefine KDE_DEPRECATED so we can use
+	a deprecated function (hack!)
+
+2004-04-05  Benjamin Otte  <otte@gnome.org>
+
+	* ext/esd/esdmon.c: (gst_esdmon_get):
+	  fix nonterminated vararg and memleak
+
+2004-04-05  Benjamin Otte  <otte@gnome.org>
+
+	* ext/ladspa/gstladspa.c: (gst_ladspa_class_init),
+	(gst_ladspa_init), (gst_ladspa_force_src_caps),
+	(gst_ladspa_set_property), (gst_ladspa_get_property),
+	(gst_ladspa_instantiate), (gst_ladspa_activate),
+	(gst_ladspa_deactivate), (gst_ladspa_loop), (gst_ladspa_chain):
+	  clean up debugging
+
+2004-04-05  Stefan Kost <kost@imn.htwk-leipzig.de>
+
+	reviewed by Benjamin Otte  <otte@gnome.org>
+
+	* ext/ladspa/gstladspa.c: (gst_ladspa_class_init):
+	  check for broken LADSPA parameters (fixes #138635)
+
+2004-04-05  Benjamin Otte  <otte@gnome.org>
+
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_getcaps):
+	  advertise buffer-frames correctly on sinkpads
+
+2004-04-05  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/mad/gstmad.c: (gst_mad_get_type), (gst_mad_layer_get_type),
+	(gst_mad_mode_get_type), (gst_mad_emphasis_get_type),
+	(gst_mad_get_event_masks), (gst_mad_get_query_types), (index_seek),
+	(normal_seek), (gst_mad_src_event), (gst_mad_handle_event),
+	(gst_mad_check_caps_reset), (gst_mad_chain):
+        add more debugging, only reset caps when we're not in error state
+
+2004-04-05  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/mad/gstmad.c: add debugging category, comment + cleanups
+
+2004-04-05  Julio M. Merino Vidal  <jmmv@menta.net>
+
+	reviewed by Benjamin Otte  <otte@gnome.org>
+
+	* configure.ac:
+	  fix == in test(1) operator
+
+2004-04-05  Julio M. Merino Vidal  <jmmv@menta.net>
+
+	reviewed by Benjamin Otte  <otte@gnome.org>
+
+	* configure.ac:
+	  fix --export-symblos-regex to a working regex.
+
+2004-04-04  Benjamin Otte  <otte@gnome.org>
+
+	* sys/oss/.cvsignore:
+	  add for oss_probe
+
+2004-04-03  Tim-Phillip Müller <t.i.m@zen.co.uk>
+
+	reviewed by Benjamin Otte  <otte@gnome.org>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_handle_event):
+	  add missing 'new_media' argument (fixes #138168)
+	* gst/matroska/matroska-demux.c:
+	(gst_matroska_demux_handle_seek_event):
+	  add vararg terminator (fixes #138169)
+
+2004-04-02  David Schleef  <ds@schleef.org>
+
+	* ext/gdk_pixbuf/Makefile.am:  Make sure gstgdkanimation.h is
+	disted (bug #138914)
+
+2004-04-01  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_change_state),
+	(gst_alsa_close_audio):
+	  handle case better where a soundcard can't pause
+	* ext/ogg/gstoggdemux.c:
+	  don't crash when we get events but don't have pads yet
+
+2004-04-01  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/oss/gstosselement.c: (gst_osselement_probe_caps):
+          throw an error if we couldn't probe any caps.
+
+2004-04-01  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/dvdnav/gst-dvd:
+	Add a really simple sample DVD player
+
+2004-04-01  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/a52dec/gsta52dec.c: (gst_a52dec_get_type), (gst_a52dec_init),
+	(gst_a52dec_push), (gst_a52dec_handle_event),
+	(gst_a52dec_update_streaminfo), (gst_a52dec_loop),
+	(gst_a52dec_change_state):
+	* ext/a52dec/gsta52dec.h:
+	  Use a debug category, Output timestamps correctly
+	  Emit tag info, Handle events, tell liba52dec about cpu
+	  capabilities so it can use MMX etc.
+	* ext/dv/gstdvdec.c: (gst_dvdec_loop), (gst_dvdec_change_state):
+	  Fix a crasher accessing invalid memory
+	* ext/dvdnav/dvdnavsrc.c: (dvdnavsrc_init),
+	(dvdnavsrc_update_highlight), (dvdnavsrc_loop),
+	(dvdnavsrc_get_event_mask), (dvdnav_handle_navigation_event),
+	(dvdnavsrc_event), (dvdnavsrc_get_formats), (dvdnavsrc_convert),
+	(dvdnavsrc_query):
+	  Some support for byte-format seeking.
+	  Small fixes for still frames and menu button overlays
+	* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_get_type),
+	(gst_mpeg2dec_alloc_buffer):
+	  Use a debug category. Adjust the report level of several items to
+	  LOG. Call mpeg2_custom_fbuf to mark our buffers as 'custom buffers'
+	  so it doesn't lose the GstBuffer pointer
+	* gst/debug/Makefile.am:
+	* gst/debug/gstdebug.c: (plugin_init):
+	* gst/debug/gstnavseek.c: (gst_navseek_get_type),
+	(gst_navseek_base_init), (gst_navseek_class_init),
+	(gst_navseek_init), (gst_navseek_seek),
+	(gst_navseek_handle_src_event), (gst_navseek_set_property),
+	(gst_navseek_get_property), (gst_navseek_chain),
+	(gst_navseek_plugin_init):
+	* gst/debug/gstnavseek.h:
+	  Add the navseek debug element for seeking back and forth in a
+	  video stream using arrow keys.
+	* gst/mpeg2sub/gstmpeg2subt.c: (gst_mpeg2subt_get_type),
+	(gst_mpeg2subt_base_init), (gst_mpeg2subt_class_init),
+	(gst_mpeg2subt_init), (gst_mpeg2subt_finalize),
+	(gst_mpeg2subt_getcaps_video), (gst_mpeg2subt_link_video),
+	(gst_mpeg2subt_handle_video), (gst_mpeg2subt_src_event),
+	(gst_mpeg2subt_parse_header), (gst_get_nibble),
+	(gst_setup_palette), (gst_get_rle_code), (gst_draw_rle_line),
+	(gst_merge_uv_data), (gst_mpeg2subt_merge_title),
+	(gst_update_still_frame), (gst_mpeg2subt_handle_subtitle),
+	(gst_mpeg2subt_handle_dvd_event), (gst_mpeg2subt_loop):
+	* gst/mpeg2sub/gstmpeg2subt.h:
+	  Pretty much a complete rewrite. Now a loopbased element. May still
+	  require work to properly synchronise subtitle buffers.
+	* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_process_private),
+	(gst_dvd_demux_send_subbuffer):
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_send_subbuffer):
+	  Don't attempt to create subbuffers of size 0
+	  Reduce a couple of error outputs to warnings.
+	* gst/y4m/gsty4mencode.c: (gst_y4mencode_sinkconnect),
+	(gst_y4mencode_chain):
+	Output the y4m frame header correctly.
+
+2004-04-01  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/adder/gstadder.c: (gst_adder_get_type), (gst_adder_loop):
+          throw errors instead of allowing SIGFPE
+
+2004-04-01  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/gconf/gconf.c: (gst_gconf_get_string),
+	(gst_gconf_render_bin_from_key):
+          leak plugging and style fixing
+
+2004-03-31  David Schleef  <ds@schleef.org>
+
+	* gst/audioscale/gstaudioscale.c: (gst_audioscale_expand_value),
+	(gst_audioscale_getcaps): Fix getcaps to expand and union lists.
+	(bug #138225)
+	* gst/debug/Makefile.am:
+	* gst/debug/breakmydata.c: (gst_break_my_data_plugin_init):
+	* gst/debug/gstdebug.c: (plugin_init):  Merge elements into one
+	plugin.
+	* gst/debug/negotiation.c: (gst_gst_negotiation_get_type),
+	(gst_negotiation_base_init), (gst_negotiation_class_init),
+	(gst_negotiation_init), (gst_negotiation_getcaps),
+	(gst_negotiation_pad_link), (gst_negotiation_chain),
+	(gst_negotiation_set_property), (gst_negotiation_get_property),
+	(gst_negotiation_plugin_init):  New element to talk about random
+	negotiation things happening in a pipeline.
+
+2004-03-31  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/adder/gstadder.c: (gst_adder_get_type), (gst_adder_loop):
+          fix integer addition with help of Stefan Kost
+
+2004-03-31  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* po/nl.po: updated Dutch translation (Elros Cyriatan)
+
+2004-03-30  David Schleef  <ds@schleef.org>
+
+	* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_alloc_buffer),
+	(gst_mpeg2dec_negotiate_format):  Handle Y42B-format MPEG
+	video, patch from Matthew.Spencer@eu.sony.com (Matthew Spencer)
+	(bug #137504)
+	* ext/mpeg2dec/gstmpeg2dec.h:
+
+2004-03-30  David Schleef  <ds@schleef.org>
+
+	* ext/gdk_pixbuf/Makefile.am: Remove spurious rules. (bug #136527)
+
+2004-03-30  David Schleef  <ds@schleef.org>
+
+	* tools/gst-launch-ext-m.m:  Applied patch from gnome@flyn.org (W.
+	Michael Petullo) to handle .mov
+
+2004-03-30  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* sys/oss/gstosselement.c: (gst_osselement_probe_caps),
+	(gst_osselement_rate_check_rate):
+	  probe caps correctly for sound cards that only support one format
+
+2004-03-30  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/kio/kiosrc.cpp: (process_events):
+	  update handling event processing if inside KDE - untested
+
+2004-03-29  David Schleef  <ds@schleef.org>
+
+	* ext/hermes/gsthermescolorspace.c: (plugin_init): decrease rank
+	by 2 to not interfere with other colorspaces.
+	* ext/pango/gsttextoverlay.c: (plugin_init): change rank to NONE
+	* gst/colorspace/gstcolorspace.c: (plugin_init): decrease rank by
+	one to not interfere with ffmpeg_colorspace.
+
+2004-03-29  David Schleef  <ds@schleef.org>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_fixate): Don't fixate fields that
+	aren't in the caps.
+	* gst/sine/gstsinesrc.c: change rate caps to [1,MAX]
+	* gst/videocrop/gstvideocrop.c: (plugin_init): Change rank to NONE.
+
+2004-03-30  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst-libs/gst/riff/riff-media.c:
+	  fail on error, don't try to set stuff on NULL caps
+
+2004-03-30  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/kio/Makefile.am:
+	* ext/kio/kioreceiver.cpp:
+	* ext/kio/kioreceiver.h:
+	* ext/kio/kiosrc.cpp:
+	* ext/kio/kiosrc.h:
+	  add experimental kiosrc plugin
+	* ext/alsa/gstalsaplugin.c: (plugin_init):
+	  initialize debugging category only when we're sure registering the
+	  plugins worked.
+
+2004-03-29  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* examples/gstplay/player.c: (main):
+	* gst-libs/gst/play/play.c: (gst_play_class_init),
+	(gst_play_set_location), (gst_play_set_data_src),
+	(gst_play_set_video_sink), (gst_play_set_audio_sink),
+	(gst_play_set_visualization), (gst_play_connect_visualization):
+          check return values of element_set_state and return FALSE where
+          failed
+
+2004-03-29  Benjamin Otte  <otte@gnome.org>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_handle_event):
+	  try harder to check if an event is really a discont
+
+2004-03-29  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* po/LINGUAS: adding Azerbaijani (Mətin Əmirov)
+	* po/az.po:
+
+2004-03-28  Benjamin Otte  <otte@gnome.org>
+
+	* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_process_private):
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_parse_syshead),
+	(gst_mpeg_demux_parse_packet), (gst_mpeg_demux_parse_pes):
+	  get rid of non-standard "..." ranges in case statements.
+
+2004-03-27  Martin Soto  <martinsoto@users.sourceforge.net>
+
+	* gst/mpegstream/gstmpegdemux.c:
+	* gst/mpegstream/gstmpegdemux.h: Complete overhaul. All DVD
+	specific functionality split to the new dvddemux element.
+	* gst/mpegstream/gstdvddemux.c:
+	* gst/mpegstream/gstdvddemux.h: New demultiplexer for DVD (VOB)
+	streams, derived from mpegdemux.
+	* gst/mpegstream/gstmpegparse.c: Discontinuity handling cleaned
+	up. SCR based timestamp rewriting can be turned off (will probably
+	completely disappear soon).
+	* ext/dvdnav/dvdnavsrc.c: Changes resulting from a few months
+	hacking. General cleanup. All printf statements replaced by
+	debugging messages. Almost complete libdvdnav support.
+	(dvdnavsrc_class_init): Got rid of unnecessary signals (replaced
+	by events. New properties for audio and subpicture languages.
+	(dvdnavsrc_update_highlight): Now uses events.
+	(dvdnavsrc_user_op): Cleaned up.
+	(dvdnavsrc_get): Renamed to dvdnavsrc_loop (element is now loop
+	based). Lots of cleanup, and propper support for most libdvdnav
+	events.
+	(dvdnavsrc_make_dvd_event): New function.
+	(dvdnavsrc_make_dvd_nav_packet_event): New function.
+	(dvdnavsrc_make_clut_change_event): New function.
+
+2004-03-26  Benjamin Otte  <otte@gnome.org>
+
+	* gst/typefind/gsttypefindfunctions.c: (theora_type_find):
+	  fix bug where typefinding would claim it's theora whenever less then
+	  7 bytes of data were available
+
+2004-03-25  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/law/alaw-decode.c: (alawdec_getcaps), (alawdec_link),
+	(gst_alawdec_base_init), (gst_alawdec_class_init),
+	(gst_alawdec_init), (gst_alawdec_chain):
+	* gst/law/alaw-encode.c: (alawenc_getcaps), (alawenc_link),
+	(gst_alawenc_base_init), (gst_alawenc_class_init),
+	(gst_alawenc_init), (gst_alawenc_chain):
+	* gst/law/mulaw-decode.c: (mulawdec_getcaps), (mulawdec_link),
+	(gst_mulawdec_base_init), (gst_mulawdec_class_init),
+	(gst_mulawdec_init), (gst_mulawdec_chain):
+	* gst/law/mulaw-encode.c: (mulawenc_getcaps), (mulawenc_link),
+	(gst_mulawenc_base_init), (gst_mulawenc_class_init),
+	(gst_mulawenc_init), (gst_mulawenc_chain):
+	  Fix capsnego in all four, remove the unused property functions and
+	  simplify the chain functions slightly. I guess we could use macros
+	  or something similar for those, since the code is so similar, but
+	  I'm currently too lazy...
+
+2004-03-24  David Schleef  <ds@schleef.org>
+
+	* sys/oss/gstosselement.c: (gst_osselement_sync_parms),
+	(gst_osselement_close_audio), (gst_osselement_probe_caps),
+	(gst_osselement_get_format_structure),
+	(gst_osselement_rate_probe_check), (gst_osselement_rate_add_range),
+	(gst_osselement_rate_check_rate), (gst_osselement_rate_add_rate),
+	(gst_osselement_rate_int_compare): Add code to handle rate probing
+	(bug #120883)
+	* sys/oss/gstosselement.h: same
+	* sys/oss/gstosssink.c: (gst_osssink_init), (gst_osssink_getcaps):
+	Use rate probing provided by osselement.
+	* sys/oss/gstosssrc.c: (gst_osssrc_init), (gst_osssrc_getcaps): same
+
+2004-03-24  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/xvid/gstxvidenc.c: (gst_xvidenc_set_property),
+	(gst_xvidenc_get_property):
+	  ulong/int mess-up.
+
+2004-03-24  David Schleef  <ds@schleef.org>
+
+	* ext/speex/gstspeexdec.c: (gst_speexdec_base_init),
+	(gst_speexdec_init):
+	* ext/speex/gstspeexenc.c: (gst_speexenc_base_init),
+	(gst_speexenc_init):  Create the pad template correctly (from
+	the static pad template, not a NULL pointer.)
+
+2004-03-25  Benjamin Otte  <otte@gnome.org>
+
+	* gst/debug/Makefile.am:
+	* gst/debug/breakmydata.c:
+	  add element that quasi-randomly changes bytes in the stream.
+	  Intended use is robustness checking of demuxers and decoders in
+	  media tests.
+
+2004-03-24  Benjamin Otte  <otte@gnome.org>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_open_audio),
+	(gst_alsa_probe_hw_params):
+	* ext/alsa/gstalsa.h:
+	  debugging output fixes
+
+2004-03-24  Benjamin Otte  <otte@gnome.org>
+
+	* ext/gnomevfs/gstgnomevfssrc.c: (gst_gnomevfssrc_set_property):
+	  don't g_return_if_fail if element is PLAYING, fail silently as every
+	  other element.
+	* gst/effectv/gstquark.c: (gst_quarktv_chain):
+	  only fix needed for cast lvalue issues in gst-plugins
+	* gst/volenv/gstvolenv.c: (gst_volenv_init):
+	  add proxy_getcaps
+
+2004-03-24  Benjamin Otte  <otte@gnome.org>
+
+	* gst/level/gstlevel.c: (gst_level_init):
+	  add proxying getcaps function, so level doesn't advertise impossible
+	  caps
+
+2004-03-24  David Schleef  <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_handle_sink_event),
+	(gst_qtdemux_loop_header), (qtdemux_parse_moov), (qtdemux_parse),
+	(qtdemux_node_dump_foreach), (qtdemux_dump_mvhd),
+	(qtdemux_dump_tkhd), (qtdemux_dump_elst), (qtdemux_dump_mdhd),
+	(qtdemux_dump_hdlr), (qtdemux_dump_vmhd), (qtdemux_dump_dref),
+	(qtdemux_dump_stsd), (qtdemux_dump_stts), (qtdemux_dump_stss),
+	(qtdemux_dump_stsc), (qtdemux_dump_stsz), (qtdemux_dump_stco),
+	(qtdemux_dump_co64), (qtdemux_dump_dcom), (qtdemux_dump_cmvd),
+	(qtdemux_parse_tree), (qtdemux_parse_trak):  Fix debugging
+	messages.  Divide the chunk size by the compression ratio
+	(needed for MACE audio)
+
+2004-03-23  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/mpegaudioparse/gstmpegaudioparse.c: (gst_mp3parse_chain):
+	  Fix buffer overflow read error.
+
+2004-03-23  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsa.h:
+	  Remove unused entry.
+	* gst-libs/gst/riff/riff-media.c: (gst_riff_create_video_caps):
+	  Add cinepak.
+	* gst/videodrop/gstvideodrop.c: (gst_videodrop_getcaps),
+	(gst_videodrop_link), (gst_videodrop_chain):
+	  Fix, sort of. Was horribly broken with new capsnego. Bah...
+
+2004-03-23  Jeremy Simon  <jesimon@libertysurf.fr>
+
+	* gst/typefind/gsttypefindfunctions.c: (ape_type_find),
+	(plugin_init):
+	Add a monkeysaudio typefind function
+
+2004-03-23  Johan Dahlin  <johan@gnome.org>
+
+	* gst-libs/gst/play/play.c (gst_play_audio_fixate)
+	(gst_play_video_fixate): Check so the structure has the field
+	before trying to fixate them, this makes it possible to have
+	fakesinks for video and audio output without printing errors on
+	the output console.
+
+2004-03-22  David Schleef  <ds@schleef.org>
+
+	* sys/oss/Makefile.am:
+	* sys/oss/oss_probe.c: (main), (probe_check), (add_range),
+	(check_rate), (add_rate):  Rate probing test app.
+
+2004-03-21  Benjamin Otte  <otte@gnome.org>
+
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_link),
+	(_fixate_caps_to_int), (gst_audio_convert_fixate):
+	  add a fixation function that pretty much does the right thing (fixes
+	  #137556)
+
+2004-03-20  David I. Lehn  <dlehn@users.sourceforge.net>
+
+	* configure.ac: GST_PACKAGE default: s/GStreamer/GStreamer Plugins/
+
+2004-03-20  Tim-Phillip Müller <t.i.m@zen.co.uk>
+
+	reviewed by: Benjamin Otte  <otte@gnome.org>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_pad_push):
+	  terminate gst_event_new_discontinuous correctly (fixes parts of
+	  #137711)
+
+2004-03-19  David Schleef  <ds@schleef.org>
+
+	* gst-libs/gst/Makefile.am:  Enable xoverlay unconditionally,
+	since it doesn't depend on X, and it's part of our ABI.
+
+2004-03-19  Iain <iain@prettypeople.org>
+
+	* gst/interleave/deinterleave.c (deinterleave_sink_link): Use the
+	is_int in the structure, not the local variable.
+
+2004-03-19  David Schleef  <ds@schleef.org>
+
+	* ext/librfb/gstrfbsrc.c: (gst_rfbsrc_change_state),
+	(gst_rfbsrc_init), (gst_rfbsrc_getcaps), (gst_rfbsrc_fixate),
+	(gst_rfbsrc_link), (gst_rfbsrc_paint_rect), (gst_rfbsrc_get):
+	Improvements in caps negotiation.
+
+2004-03-18  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* po/LINGUAS:
+	* po/af.po:
+          adding Afrikaans (Petri Jooste)
+
+2004-03-18  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+	(gst_ffmpegcolorspace_chain):
+        throw error instead of g_critical (#137588)
+
+2004-03-18  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* Makefile.am:
+	* configure.ac:
+          dist common and m4 correctly
+	* po/sv.po:
+
+2004-03-17  David Schleef  <ds@schleef.org>
+
+	* pkgconfig/gstreamer-media-info.pc.in:  Add Version.
+	(bug #137348)
+
+2004-03-17  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* po/LINGUAS:
+	* po/sv.po:
+          adding Swedish translation (Christian Rose)
+
+2004-03-17  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* Makefile.am: use release.mak
+
+2004-03-16  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* common/ChangeLog:
+	* common/gst-autogen.sh:
+          add some explanation about the version detection
+	* configure.ac:
+          fix X check
+
+2004-03-16  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac: bump nano to 1
+
+=== release 0.8.0 ===
+
+2004-03-16  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac: release 0.8.0, "Pharmaceutical Itch"
+
+2004-03-16  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+          update libtool version
+	* gst-libs/gst/media-info/Makefile.am:
+          actually use libtool version
+
+2004-03-15  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac: fix speex detection to work with 1.0 but not 1.1
+
+2004-03-15  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	* gst-plugins.spec.in:
+	* pkgconfig/Makefile.am:
+	* pkgconfig/gstreamer-gconf-uninstalled.pc.in:
+	* pkgconfig/gstreamer-interfaces-uninstalled.pc.in:
+	* pkgconfig/gstreamer-libs-uninstalled.pc.in:
+	* pkgconfig/gstreamer-libs.pc.in:
+	* pkgconfig/gstreamer-media-info-uninstalled.pc.in:
+	* pkgconfig/gstreamer-play-uninstalled.pc.in:
+	* pkgconfig/gstreamer-plugins-uninstalled.pc.in:
+	* pkgconfig/gstreamer-plugins.pc.in:
+          remove @VERSION@ from some of the pc files since core and plugins
+          are decoupled.
+          created gstreamer-plugins.pc as it's a better name, but keeping
+          -libs around for now to get fixes upstream done first.
+
+2004-03-15  Julien MOUTTE <julien@moutte.net>
+
+	* gst-libs/gst/play/play.c: (gst_play_get_framerate),
+	(gst_play_get_sink_element): First draft of gst_play_get_framerate.
+	* gst-libs/gst/play/play.h:
+
+2004-03-15  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* *.c, *.cc: don't mix tabs and spaces
+
+2004-03-15  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/play/play.c: (gst_play_pipeline_setup):
+          use the new ffmpegcolorspace
+	* gst-plugins.spec.in:
+          package new colorspace and media-info
+	* configure.ac:
+	* pkgconfig/Makefile.am:
+          fix some more disting issues
+	* pkgconfig/gstreamer-media-info-uninstalled.pc.in:
+	* pkgconfig/gstreamer-media-info.pc.in:
+          generate media-info pc files
+
+2004-03-15  Johan Dahlin  <johan@gnome.org>
+
+	* *.h: Revert indenting
+
+2004-03-15  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+          adding ffmpegcolorspace element
+	* gst/ffmpegcolorspace/Makefile.am:
+	* gst/ffmpegcolorspace/avcodec.h:
+	* gst/ffmpegcolorspace/common.h:
+	* gst/ffmpegcolorspace/dsputil.c: (dsputil_static_init):
+	* gst/ffmpegcolorspace/dsputil.h:
+	* gst/ffmpegcolorspace/gstffmpeg.c: (plugin_init):
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.c:
+	(gst_ffmpeg_pixfmt_to_caps), (gst_ffmpeg_pix_fmt_to_caps),
+	(gst_ffmpeg_caps_to_pix_fmt):
+	* gst/ffmpegcolorspace/gstffmpegcodecmap.h:
+	* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+	(gst_ffmpegcolorspace_caps_remove_format_info),
+	(gst_ffmpegcolorspace_getcaps), (gst_ffmpegcolorspace_pad_link),
+	(gst_ffmpegcolorspace_get_type), (gst_ffmpegcolorspace_base_init),
+	(gst_ffmpegcolorspace_class_init), (gst_ffmpegcolorspace_init),
+	(gst_ffmpegcolorspace_chain), (gst_ffmpegcolorspace_change_state),
+	(gst_ffmpegcolorspace_set_property),
+	(gst_ffmpegcolorspace_get_property),
+	(gst_ffmpegcolorspace_register):
+	* gst/ffmpegcolorspace/imgconvert.c:
+	(avcodec_get_chroma_sub_sample), (avcodec_get_pix_fmt_name),
+	(avcodec_get_pix_fmt), (avpicture_fill), (avpicture_layout),
+	(avpicture_get_size), (avcodec_get_pix_fmt_loss),
+	(avg_bits_per_pixel), (avcodec_find_best_pix_fmt1),
+	(avcodec_find_best_pix_fmt), (img_copy_plane), (img_copy),
+	(yuv422_to_yuv420p), (yuv422_to_yuv422p), (yuv422p_to_yuv422),
+	(C_JPEG_TO_CCIR), (img_convert_init), (img_apply_table),
+	(shrink41), (shrink21), (shrink12), (shrink22), (shrink44),
+	(grow21_line), (grow41_line), (grow21), (grow22), (grow41),
+	(grow44), (conv411), (gif_clut_index), (build_rgb_palette),
+	(bitcopy_n), (mono_to_gray), (monowhite_to_gray),
+	(monoblack_to_gray), (gray_to_mono), (gray_to_monowhite),
+	(gray_to_monoblack), (avpicture_alloc), (avpicture_free),
+	(is_yuv_planar), (img_convert), (get_alpha_info_pal8),
+	(img_get_alpha_info), (deinterlace_line),
+	(deinterlace_line_inplace), (deinterlace_bottom_field),
+	(deinterlace_bottom_field_inplace), (avpicture_deinterlace):
+	* gst/ffmpegcolorspace/imgconvert_template.h:
+	* gst/ffmpegcolorspace/mem.c: (av_malloc), (av_realloc), (av_free):
+	* gst/ffmpegcolorspace/mmx.h:
+	* gst/ffmpegcolorspace/utils.c: (avcodec_init):
+          adding ffmpegcolorspace element supplied by Ronald after cleaning
+          up and pulling in the right bits of upstream source.
+          I'm sure a better C/compiler wizard could do some cleaning up (for
+          example use GLIB's malloc stuff), but as a first pass this
+          works very well
+
+2004-03-15  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/alsa/gstalsa.h:
+	  I assume Ronald forgot to commit the change to have cardname
+          as a struct member.  Expect some public spanking at the next
+          opportunity.
+
+2004-03-15  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_get_property),
+	(gst_alsa_open_audio), (gst_alsa_close_audio):
+	* ext/alsa/gstalsa.c:
+	  Don't open the device if we're a mixer (= padless).
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_class_init),
+	(gst_alsa_mixer_init), (gst_alsa_mixer_open),
+	(gst_alsa_mixer_close), (gst_alsa_mixer_change_state):
+	  Open mixer during state change rather than during object
+	  initialization. Also, get a device name. Currently in a somewhat
+	  hackish fashion, but I didn't really find something better.
+
+2004-03-14  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* *.c, *.h: run gst-indent
+
+2004-03-14  Benjamin Otte  <otte@gnome.org>
+
+	* gst/modplug/gstmodplug.cc:
+	* gst/modplug/gstmodplug.h:
+	  set correct timestamps on outgoing buffers
+
+2004-03-14  Benjamin Otte  <otte@gnome.org>
+
+	* gst/modplug/gstmodplug.cc:
+	  handle events - don't do crap when a discont arrives that's not
+	  necessary
+	  This allows correct loading and playback of mods in Rhythmbox
+
+2004-03-14  Benjamin Otte  <otte@gnome.org>
+
+	* configure.ac:
+	* gst-libs/gst/gconf/Makefile.am:
+	* pkgconfig/Makefile.am:
+	  move gstreamer-gconf pkgconfig files to pkgconfig/ dir. Make sure
+	  they get rebuilt properly
+	* configure.ac:
+	  when checking for vorbis, try pkgconfig first.
+	* gst/modplug/gstmodplug.cc:
+	  add fixate function
+
+2004-03-14  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/qtdemux/qtdemux.c: (qtdemux_parse_trak):
+	  Fix for obvious mistake, where we first shift the offset and then
+	  read a samplesize element assuming the old offset. Note that this
+	  part still has something weird, i.e. my movies containing those
+	  don't actually play well, but at least there's something that looks
+	  like sound now.
+
+2004-03-14  Jan Schmidt  <thaytan@mad.scientist.com>
+	* gst/typefind/gsttypefindfunctions.c: (speex_type_find),
+	(plugin_init):
+	Add a typefind function for speex format
+
+2004-03-13  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_video_caps),
+	(gst_asf_demux_setup_pad):
+	  Use 25fps as our "fake" fps value (marked for fixage in 0.9.x)
+	  instead of 0. Reason is simple: some elements have a fps range
+	  of 1-max instead of 0-max. So now ASF video actually works.
+
+2004-03-13  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* po/LINGUAS:
+	* po/sr.po:
+	  adding serbian as a language
+
+2004-03-13  Benjamin Otte  <otte@gnome.org>
+
+	* gst/sine/gstsinesrc.c: (gst_sinesrc_get):
+	  return taglist correctly from _get function, don't gst_pad_push it.
+	  (fixes #137042)
+
+2004-03-13  Jan Schmidt  <thaytan@mad.scientist.com>
+	* ext/alsa/gstalsa.c: (gst_alsa_class_probe_devices):
+
+2004-03-13  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_free_list):
+	* ext/alsa/gstalsamixertrack.c: (gst_alsa_mixer_track_class_init),
+	(gst_alsa_mixer_track_new):
+	* ext/alsa/gstalsamixertrack.h:
+	  Fix ancient leftovers... MixerTrack is a GObject.
+
+2004-03-13  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_class_probe_devices):
+	* sys/oss/gstosselement.c: (gst_osselement_class_probe_devices):
+	  Don't block during probing...
+
+2004-03-12  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_get_type), (gst_alsa_class_init),
+	(gst_alsa_get_property), (gst_alsa_probe_get_properties),
+	(gst_alsa_class_probe_devices), (gst_alsa_class_list_devices),
+	(gst_alsa_probe_probe_property), (gst_alsa_probe_needs_probe),
+	(gst_alsa_probe_get_values), (gst_alsa_probe_interface_init),
+	(gst_alsa_open_audio), (gst_alsa_close_audio):
+	* ext/alsa/gstalsa.h:
+	  Add propertyprobe interface implementation, add some device-name
+	  property, all this so that it looks good in gnome-volume-control.
+
+2004-03-12  David Schleef  <ds@schleef.org>
+
+	* configure.ac: the Hermes library controls hermescolorspace, not
+	colorspace.
+	* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_base_init),
+	(gst_mpeg2dec_init): minor pet peeve: disable code with #ifdef,
+	not /* */
+	* ext/sdl/sdlvideosink.c: Change XID to unsigned long.
+	* ext/sdl/sdlvideosink.h: ditto.
+	* gst/colorspace/gstcolorspace.c: Fix old comments about Hermes
+
+2004-03-12  Benjamin Otte  <otte@gnome.org>
+
+	* gst-libs/gst/xoverlay/xoverlay.c: (gst_x_overlay_set_xwindow_id),
+	(gst_x_overlay_got_xwindow_id):
+	* gst-libs/gst/xoverlay/xoverlay.h:
+	  replace XID with unsigned long to get rid of the xlibs dependency in
+	  XOverlay (fixes #137004)
+
+2004-03-13  Jan Schmidt  <thaytan@mad.scientist.com>
+	* gst/effectv/gstaging.c: (gst_agingtv_base_init),
+	(gst_agingtv_setup):
+	* gst/effectv/gstdice.c: (gst_dicetv_get_type),
+	(gst_dicetv_base_init), (gst_dicetv_class_init),
+	(gst_dicetv_setup), (gst_dicetv_init), (gst_dicetv_draw):
+	* gst/effectv/gstedge.c: (gst_edgetv_get_type),
+	(gst_edgetv_base_init), (gst_edgetv_class_init), (gst_edgetv_init),
+	(gst_edgetv_setup), (gst_edgetv_rgb32):
+	* gst/effectv/gsteffectv.c:
+	* gst/effectv/gstquark.c: (gst_quarktv_link), (gst_quarktv_init),
+	(gst_quarktv_set_property):
+	* gst/effectv/gstrev.c: (gst_revtv_get_type),
+	(gst_revtv_base_init), (gst_revtv_class_init), (gst_revtv_init),
+	(gst_revtv_setup), (gst_revtv_rgb32):
+	* gst/effectv/gstshagadelic.c: (gst_shagadelictv_get_type),
+	(gst_shagadelictv_base_init), (gst_shagadelictv_class_init),
+	(gst_shagadelictv_init), (gst_shagadelictv_setup),
+	(gst_shagadelictv_rgb32):
+	* gst/effectv/gstvertigo.c: (gst_vertigotv_get_type),
+	(gst_vertigotv_base_init), (gst_vertigotv_class_init),
+	(gst_vertigotv_setup), (gst_vertigotv_init), (gst_vertigotv_rgb32):
+	* gst/effectv/gstwarp.c:
+	Port everything that can be ported to videofilter and fix up the caps.
+	Can someone with a big-endian machine please check these?
+
+2004-03-10  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/oss/gstosssink.c: (gst_osssink_init), (gst_osssink_get_time),
+	(gst_osssink_chain), (gst_osssink_change_state):
+	  Latest fixes for A/V sync, audio playback and such. This is about
+	  all... MPEG playback issues are mostly related to the async build-
+	  up of MPEG files, I cannot fix that. Use basicgthread to solve it.
+
+2004-03-10  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	patch from: Stephane Loeuillet
+
+	* configure.ac:
+	  use pkg-config for some libraries, falling back to the old .m4 way
+          (fixes #131270)
+	* m4/libdv.m4:
+          removed
+
+2004-03-10  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	* tools/Makefile.am:
+	* tools/Makefile.in:
+	* tools/gst-launch-ext-m.m:
+	* tools/gst-launch-ext.1.in:
+	* tools/gst-visualise-m.m:
+	* tools/gst-visualise.1:
+	* tools/gst-visualise.1.in:
+          reorganizing generation of script tools
+
+2004-03-10  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/divx/gstdivxdec.c:
+	  Downgrade priority. We prefer ffdec_mpeg4.
+	* ext/faad/gstfaad.c: (gst_faad_srcgetcaps), (gst_faad_srcconnect),
+	(gst_faad_chain), (gst_faad_change_state):
+	  Fix capsnego. Doesn't work for some sounds because we don't have
+	  a 5:1 to stereo element.
+	* ext/xvid/gstxvid.c: (plugin_init):
+	  Add priority.
+	* sys/oss/gstosssink.c: (gst_osssink_init), (gst_osssink_chain),
+	(gst_osssink_change_state):
+	  Add discont handling.
+
+2004-03-09  Colin Walters  <walters@verbum.org>
+
+	* gst/audioconvert/gstaudioconvert.c: Fix typo in width 8
+	conversion.
+
+2004-03-09  Benjamin Otte  <otte@gnome.org>
+
+	* gst-libs/gst/mixer/mixer.c: (gst_mixer_class_init):
+	  the signals take 2 arguments
+
+2004-03-09  David Schleef  <ds@schleef.org>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_request_new_pad),
+	(gst_alsa_fixate): Add fixate function.  (bug #136686)
+	* ext/alsa/gstalsa.h:
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_init):
+
+2004-03-09  Benjamin Otte  <otte@gnome.org>
+
+	* ext/mikmod/gstmikmod.c: (gst_mikmod_init), (gst_mikmod_loop),
+	(gst_mikmod_change_state):
+	* ext/mikmod/gstmikmod.h:
+	  make mikmod's loop function not loop infinitely and call
+	  gst_element_yield anymore
+	* gst/modplug/gstmodplug.cc:
+	  fix pad negotiation (fixes #136590)
+
+2004-03-09  David Schleef  <ds@schleef.org>
+
+	* ext/lcs/Makefile.am:  Fix so that the lcs colorspace plugin
+	doesn't conflict with the internal colorspace plugin.
+	* gst-libs/gst/audio/make_filter:  Use `` instead of $() to
+	satisfy the crappy-ass shell shipped by a certain vendor.
+	* gst/videofilter/make_filter: same (bug #135299)
+
+2004-03-09  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac: bump nano to 1
+
+=== release 0.7.6 ===
+
+2004-03-09  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.in: releasing 0.7.6, "There"
+
+2004-03-09  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* pkgconfig/gstreamer-play-uninstalled.pc.in:
+	* pkgconfig/gstreamer-play.pc.in:
+          synchronize the two
+
+2004-03-09  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/cdparanoia/gstcdparanoia.c: (cdparanoia_base_init),
+	(cdparanoia_open), (cdparanoia_event):
+	  fix/add error handling
+	* po/POTFILES.in:
+	  add cdparanoia source
+	* tools/Makefile.am:
+	  make scripts executable
+
+2004-03-09  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	* ext/vorbis/Makefile.am:
+	* sys/Makefile.am:
+	  remove id3types, vorbisfile and xvideosink from the build (#133783)
+
+2004-03-08  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_read_info):
+	  Fix metadata read crash (#136537).
+
+2004-03-08  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/media-info/media-info-priv.c: (gmi_set_mime):
+	* gst-libs/gst/media-info/media-info.c: (gst_media_info_read):
+          adding mime types, fixing the one-stop function
+
+2004-03-08  Christian Schaller <Uraeus@gnome.org>
+
+	* ext/nas/nassink.c and /ext/nas/nassink.h:
+	More NAS love from Arwed von Merkatz
+	So lets all sing 'Can you feel the NAS tonight'
+
+2004-03-08  Christian Schaller <Uraeus@gnome.org>
+
+	* tools/gst-launch-ext.in:
+	Replace vorbisfile with oggdemux/vorbisdec/audioconvert
+
+2004-03-08  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_base_init),
+	(gst_mpeg2dec_init):
+        remove the user_data pad for now, because it is being used in
+        fixating causing MPEG playback to fixate on 1000 Hz for playback.
+        If someone knows how to fix this properly, please do.
+
+2004-03-08  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/oss/gstosssink.c: (gst_osssink_get_delay),
+	(gst_osssink_get_time):
+        add a warning, IMO this won't get triggered anymore, remove later
+
+2004-03-07  David Schleef  <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c: (qtdemux_video_caps):  Added Cinepak
+	format (bug #136470)
+
+2004-03-07  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/Makefile.am:
+	* gst-libs/gst/media-info/Makefile.am:
+	* gst-libs/gst/media-info/media-info-priv.c: (found_tag_callback),
+	(error_callback), (gst_media_info_error_create),
+	(gst_media_info_error_element), (gmip_init), (gmip_reset),
+	(gmi_clear_decoder), (gmip_find_type_pre), (gmip_find_type):
+	* gst-libs/gst/media-info/media-info-priv.h:
+	* gst-libs/gst/media-info/media-info-test.c: (main):
+	* gst-libs/gst/media-info/media-info.c: (gst_media_info_init),
+	(gst_media_info_class_init), (gst_media_info_instance_init),
+	(gst_media_info_set_source), (gst_media_info_read_with_idler),
+	(gst_media_info_read_idler), (gst_media_info_read):
+	* gst-libs/gst/media-info/media-info.h:
+	fixed, should work now
+
+2004-03-07  Christian Schaller <Uraeus@gnome.org>
+
+	* ext/nas/nassink.c:
+	A bunch of NAS fixes from Arwed von Merkatz
+
+2004-03-06  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_add_stream),
+	(qtdemux_parse_trak):
+	  Fix crash (j might be greater than n_samples, in which case we're
+	  writing outside the allocated space for the array) and memleak.
+
+2004-03-06  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/oss/gstosssink.c: (gst_osssink_chain):
+	  And another caller that couldn't handle delay < 0 (unsigned
+	  integer overflow). Video now continues playing on an audio
+	  buffer underrun, and the clock continues working. Audio still
+	  stalls.
+
+2004-03-06  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/oss/gstosssink.c: (gst_osssink_get_delay),
+	(gst_osssink_get_time):
+	  get_delay() may return values lower than 0. In those cases, we
+	  should not actually cast to *unsigned* int64, that will break
+	  stuff horribly. In my case, it screwed up A/V sync in movies
+	  in totem rather badly.
+
+2004-03-06  Christophe Fergeau  <teuf@gnome.org>
+
+	* ext/faac/gstfaac.c: (gst_faac_chain):
+	* ext/flac/gstflactag.c: (gst_flac_tag_chain):
+	* ext/libpng/gstpngenc.c: (user_write_data):
+	* ext/mikmod/gstmikmod.c: (gst_mikmod_loop):
+	* gst/ac3parse/gstac3parse.c: (gst_ac3parse_chain):
+	* gst/mpeg2sub/gstmpeg2subt.c: (gst_mpeg2subt_chain_subtitle):
+	* gst/mpegstream/gstrfc2250enc.c: (gst_rfc2250_enc_add_slice):
+	Fix several misuse of gst_buffer_merge (it doesn't take ownership
+	of any buffer), should fix some leaks. I hope I didn't unref buffers
+	that shouldn't be...
+
+2004-03-06  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/media-info/media-info-priv.c: (have_type_callback),
+	(deep_notify_callback), (tag_flag_score), (found_tag_callback),
+	(error_callback), (gmi_reset), (gmi_seek_to_track),
+	(gmi_get_decoder), (gmi_set_mime), (gmip_find_type_pre),
+	(gmip_find_type_post), (gmip_find_stream_post),
+	(gmip_find_track_streaminfo_post):
+	* gst-libs/gst/media-info/media-info-priv.h:
+	* gst-libs/gst/media-info/media-info-test.c: (print_tag),
+	(info_print), (main):
+	* gst-libs/gst/media-info/media-info.c:
+	(gst_media_info_error_create), (gst_media_info_error_element),
+	(gst_media_info_instance_init), (gst_media_info_get_property),
+	(gst_media_info_new), (gst_media_info_set_source),
+	(gst_media_info_read_idler), (gst_media_info_read):
+	* gst-libs/gst/media-info/media-info.h:
+          first pass at making this work again.  This seems to work on
+          tagged ogg/vorbis and mp3 files.
+
+2004-03-06  Benjamin Otte  <otte@gnome.org>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_chain):
+	  fix huge leak: gst_buffer_merge doesn't unref the first argument
+	  itself.
+
+2004-03-06  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/mad/gstmad.c: (gst_mad_class_init), (gst_mad_update_info):
+          report layer/mode/emphasis
+
+2004-03-06  Christophe Fergeau  <teuf@gnome.org>
+
+	* ext/mad/gstmad.c: (gst_mad_chain): fixed caps leak
+
+2004-03-06  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_pad_new):
+          signal serial
+
+2004-03-06  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/vorbis/vorbis.c: (plugin_init):
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_get_formats),
+	(gst_vorbis_dec_init), (vorbis_dec_event):
+        add debug category
+        make vorbisdec handle _BYTE and _TIME queries
+
+2004-03-06  Christophe Fergeau  <teuf@gnome.org>
+
+	* ext/mad/gstmad.c: (gst_mad_chain): send the average bitrate read
+	  from the xing header
+
+2004-03-06  Benjamin Otte  <otte@gnome.org>
+
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_getcaps),
+	(gst_audio_convert_link), (gst_audio_convert_change_state),
+	(gst_audio_convert_buffer_from_default_format):
+	  do conversions from/to float correctly, fix some caps nego errors,
+	  export correct supported caps in template and getcaps, use correct
+	  caps in try_set_caps functions
+
+2004-03-06  Christophe Fergeau  <teuf@gnome.org>
+
+	For some reason, I only committed a ChangeLog entry yesterday and
+	not the corresponding code...
+	* ext/mad/gstmad.c: Fix detection of Xing headers
+	* gst/tags/gstid3tag.c: Changes to support TLEN tags
+
+2004-03-06  Benjamin Otte  <otte@gnome.org>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_get_pad_by_pad),
+	(gst_ogg_demux_src_query):
+	  make sure to handle the case where there's no current chain
+	  gracefully.
+
+2004-03-05  David Schleef  <ds@schleef.org>
+
+	* ext/aalib/gstaasink.c: (gst_aasink_fixate), (gst_aasink_init):
+	Add fixate function. (bug #131128)
+	* ext/sdl/sdlvideosink.c: (gst_sdlvideosink_init),
+	(gst_sdlvideosink_fixate):  Add fixate function.
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_link):
+	Fix attempt to print a non-pointer using GST_PTR_FORMAT.
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_parse_fmt):
+	Fix missing break that was causing ulaw to be interpreted as
+	raw int.
+
+2004-03-05  David Schleef  <ds@schleef.org>
+
+	* gst/mpegstream/gstrfc2250enc.c: (gst_rfc2250_enc_add_slice):
+	Fix code that ignores return value of gst_buffer_merge().
+	(bug #114560)
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_descramble_segment):
+	* gst/mpegstream/gstrfc2250enc.c: (gst_rfc2250_enc_add_slice): same
+	* testsuite/gst-lint:  Check for above.
+
+2004-03-05  David Schleef  <ds@schleef.org>
+
+	* gst/udp/gstudpsrc.c: (gst_udpsrc_get):  Check for unfixed
+	caps and throw an element error.  (bug #136334)
+
+2004-03-05  David Schleef  <ds@schleef.org>
+
+	* ext/faad/gstfaad.c: (gst_faad_init), (gst_faad_srcgetcaps),
+	(gst_faad_chain): Fix negotiation.
+	* ext/librfb/gstrfbsrc.c: (gst_rfbsrc_handle_src_event): Add
+	key and button events.
+	* gst-libs/gst/floatcast/floatcast.h: Fix a minor bug in this
+	dung heap of code.
+	* gst-libs/gst/gconf/gstreamer-gconf-uninstalled.pc.in: gstgconf
+	depends on gconf
+	* gst-libs/gst/gconf/gstreamer-gconf.pc.in: same
+	* gst-libs/gst/play/play.c: (gst_play_pipeline_setup),
+	(gst_play_video_fixate), (gst_play_audio_fixate): Add a fixate
+	function to encourage better negotiation, particularly between
+	audioconvert and osssink.
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_chain):
+	* gst/qtdemux/qtdemux.c: (qtdemux_parse_trak):  Make some debugging
+	more important.
+	* gst/typefind/gsttypefindfunctions.c:  Fix mistake in flash
+	typefinding.
+	* gst/vbidec/vbiscreen.c:  Add glib header
+	* pkgconfig/gstreamer-play.pc.in:  Depends on gst-interfaces.
+
+2004-03-06  Christophe Fergeau  <teuf@users.sourceforge.net>
+
+	* ext/mad/gstmad.c: Fix detection of Xing headers
+	* gst/tags/gstid3tag.c: Changes to support TLEN tags
+
+2004-03-06  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_parse_fmt),
+	(gst_wavparse_pad_convert), (gst_wavparse_pad_query):
+          debug updates
+
+2004-03-06  Christophe Fergeau  <teuf@gnome.org>
+
+	* ext/mad/gstid3tag.c: (gst_mad_id3_to_tag_list):
+	* ext/mad/gstmad.c: (gst_mad_init), (is_xhead),
+	(mpg123_parse_xing_header), (gst_mad_chain): parse Xing header in vbr
+	files, and report the parsed length as a GST_TAG_DURATION tag.
+	* gst/tags/gstid3tag.c: support TLEN (duration) tag
+
+2004-03-05  Benjamin Otte  <otte@gnome.org>
+
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_channels):
+	  convert channels correctly. convert correctly to unsigned.
+
+2004-03-05  Julien MOUTTE <julien@moutte.net>
+
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_change_state): Check if
+	we have a window before clearing it.
+
+2004-03-05  Julien MOUTTE <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_change_state): Check if we
+	have a window before clearing it.
+
+2004-03-05  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gconf/gstreamer.schemas.in:
+	* gst-libs/gst/gconf/Makefile.am:
+          version installation path the same way as for 0.6
+	* pkgconfig/gstreamer-interfaces-uninstalled.pc.in:
+	* pkgconfig/gstreamer-libs-uninstalled.pc.in:
+	* pkgconfig/gstreamer-play-uninstalled.pc.in:
+          remove comment that was fixed
+
+2004-03-05  David Schleef  <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_get_src_formats),
+	(gst_qtdemux_src_convert), (gst_qtdemux_get_src_query_types),
+	(gst_qtdemux_get_event_mask), (gst_qtdemux_handle_src_query),
+	(gst_qtdemux_handle_src_event), (gst_qtdemux_add_stream):
+	Add prototype code for handling seeking and querying.
+
+2004-03-04  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* examples/gstplay/player.c: (main):
+	  Initialize variables to NULL. Prevents a segfault because the
+	  (uninitialized) variable is not NULL, resulting in a crash on
+	  trying to reach error->message.
+
+2004-03-05  Benjamin Otte  <otte@gnome.org>
+
+	* gst/audioconvert/gstaudioconvert.c:
+	(gst_audio_convert_buffer_to_default_format):
+	make float=>int conversion work correctly even in cornercases.
+
+2004-03-04  David I. Lehn  <dlehn@users.sourceforge.net>
+
+	* debian/README.Debian:
+	* debian/build-deps:
+	* debian/changelog:
+	* debian/control:
+	* debian/control.in:
+	* debian/copyright:
+	* debian/gstreamer-a52dec.files:
+	* debian/gstreamer-aa.files:
+	* debian/gstreamer-alsa.files:
+	* debian/gstreamer-alsa.manpages:
+	* debian/gstreamer-arts.files:
+	* debian/gstreamer-artsd.files:
+	* debian/gstreamer-audiofile.files:
+	* debian/gstreamer-avifile.files:
+	* debian/gstreamer-cdparanoia.files:
+	* debian/gstreamer-colorspace.files:
+	* debian/gstreamer-doc.files:
+	* debian/gstreamer-dv.files:
+	* debian/gstreamer-dvd.files:
+	* debian/gstreamer-esd.files:
+	* debian/gstreamer-festival.files:
+	* debian/gstreamer-flac.files:
+	* debian/gstreamer-gconf.conffiles:
+	* debian/gstreamer-gconf.files:
+	* debian/gstreamer-gconf.postinst:
+	* debian/gstreamer-gnomevfs.files:
+	* debian/gstreamer-gsm.files:
+	* debian/gstreamer-http.files:
+	* debian/gstreamer-jack.files:
+	* debian/gstreamer-jpeg.files:
+	* debian/gstreamer-mad.files:
+	* debian/gstreamer-mikmod.files:
+	* debian/gstreamer-misc.files:
+	* debian/gstreamer-mpeg2dec.files:
+	* debian/gstreamer-oss.files:
+	* debian/gstreamer-plugin-apps.files:
+	* debian/gstreamer-plugin-apps.manpages:
+	* debian/gstreamer-plugin-libs-dev.files:
+	* debian/gstreamer-plugin-libs.files:
+	* debian/gstreamer-plugin-template.postinst:
+	* debian/gstreamer-plugin-template.postrm:
+	* debian/gstreamer-sdl.files:
+	* debian/gstreamer-sid.files:
+	* debian/gstreamer-vorbis.files:
+	* debian/gstreamer-x.files:
+	* debian/mk.control:
+	* debian/rules:
+	Debian package info not maintained here.
+
+2004-03-04  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/aalib/gstaasink.c: (gst_aasink_class_init):
+	* ext/cdaudio/gstcdaudio.c: (gst_cdaudio_class_init):
+	* ext/cdparanoia/gstcdparanoia.c: (cdparanoia_class_init):
+	* ext/divx/gstdivxenc.c: (gst_divxenc_class_init):
+	* ext/dvdnav/dvdnavsrc.c: (dvdnavsrc_class_init):
+	* ext/gsm/gstgsmenc.c: (gst_gsmenc_class_init):
+	* ext/jpeg/gstjpegenc.c: (gst_jpegenc_class_init):
+	* ext/musicbrainz/gsttrm.c: (gst_musicbrainz_class_init):
+	* ext/speex/gstspeexenc.c: (gst_speexenc_class_init):
+	* ext/xvid/gstxvidenc.c: (gst_xvidenc_class_init):
+	* gst-libs/gst/colorbalance/colorbalance.c:
+	(gst_color_balance_class_init):
+	* gst-libs/gst/colorbalance/colorbalancechannel.c:
+	(gst_color_balance_channel_class_init):
+	* gst-libs/gst/mixer/mixer.c: (gst_mixer_class_init):
+	* gst-libs/gst/play/play.c: (gst_play_class_init):
+	* gst-libs/gst/propertyprobe/propertyprobe.c:
+	(gst_property_probe_iface_init):
+	* gst-libs/gst/tuner/tuner.c: (gst_tuner_class_init):
+	* gst-libs/gst/tuner/tunerchannel.c:
+	(gst_tuner_channel_class_init):
+	* gst-libs/gst/xoverlay/xoverlay.c: (gst_x_overlay_base_init):
+	* gst/cutter/gstcutter.c: (gst_cutter_class_init):
+	* gst/effectv/gstvertigo.c: (gst_vertigotv_class_init):
+	* sys/cdrom/gstcdplayer.c: (cdplayer_class_init):
+	* sys/dxr3/dxr3spusink.c: (dxr3spusink_class_init):
+	* sys/v4l/gstv4lmjpegsink.c: (gst_v4lmjpegsink_class_init):
+	* sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_class_init):
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_class_init):
+	* sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init):
+          fix signals to use - instead of _
+	* ext/libcaca/gstcacasink.h:
+	* ext/sdl/sdlvideosink.h:
+          fix header rename
+
+2004-03-04  David Schleef  <ds@schleef.org>
+
+	* testsuite/gst-lint:  Add a check for bad signal names.
+
+2004-03-04  <kost@imn.htwk-leipzig.de>
+
+	reviewed by David Schleef
+
+	* gst/videofilter/gstgamma.c: (gst_gamma_rgb32): Fix typo that
+	modified the alpha channel and caused a warning. (bug #136192)
+
+2004-04-03  Christian Schaller <Uraeus@gnome.org>
+
+	* gst-plugins.spec.in:
+	Change names of plugins to actually be correct. Try to keep things
+	alphabetical to avoid getting beat up by Thomas
+
+2004-03-03  Julien MOUTTE <julien@moutte.net>
+
+	* gst-libs/gst/gconf/gconf.c: (gst_gconf_get_default_video_sink):
+	Using ximagesink as a default if no gconf key found. We should
+	probably consider using alsasink instead of osssink for the audio
+	part.
+
+2004-03-02  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	  fix --with-plugins, don't think it ever worked before
+	* gst-plugins.spec.in:
+          even more updates
+
+2004-03-01  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/sdl/sdlvideosink.h:
+	* sys/ximage/ximagesink.h:
+	* sys/xvideo/xvideosink.h:
+	* sys/xvimage/xvimagesink.h:
+	  Fix for move of gstvideosink.h -> videosink.h.
+
+2004-03-02  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/xwindowlistener/Makefile.am:
+	  this is a plugin library, not a library
+
+2004-03-01  David Schleef  <ds@schleef.org>
+
+	* AUTHORS:  Added some names.  Add yourself if you're still
+	missing.
+
+2004-03-01  David Schleef  <ds@schleef.org>
+
+	* MAINTAINERS: Add
+
+2004-03-01  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-plugins.spec.in: clean up spec file
+
+2004-03-01  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/video/Makefile.am:
+	* gst-libs/gst/video/gstvideosink.c:
+	* gst-libs/gst/video/gstvideosink.h:
+          rename gstvideosink.h to videosink.h to match other headers
+	* gst/mixmatrix/Makefile.am:
+          fix plugin filename
+	* gst/tags/Makefile.am: fix plugin filename
+
+2004-03-01  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/tags/Makefile.am: fix plugin filename
+
+2004-03-01  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* examples/gstplay/player.c: (got_time_tick), (main):
+	  add error handler
+          display time_tick more readably
+	* gst/mixmatrix/Makefile.am:
+          fix plugin file name
+
+2004-02-29  Christophe Fergeau  <teuf@gnome.org>
+
+	* sys/oss/gstosselement.c: (gst_osselement_probe),
+	(device_combination_append), (gst_osselement_class_probe_devices):
+	* sys/oss/gstosselement.h:
+	  Reworked enumeration of oss dsps and mixers so that gst-mixer works
+	  on my system using alsa oss emulation, fixes bug #135597
+
+2004-02-29  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/videodrop/gstvideodrop.c: (gst_videodrop_init),
+	(gst_videodrop_chain), (gst_videodrop_change_state):
+	* gst/videodrop/gstvideodrop.h:
+	  Work based on timestamp of input data, not based on the expected
+	  framerate from the input. The consequence is that this element now
+	  not only scales framerates, but also functions as a framerate
+	  corrector or framerate stabilizer/constantizer.
+
+2004-02-27  David Schleef  <ds@schleef.org>
+
+	patches from jmmv@menta.net (Julio M. Merino Vidal)
+
+	* gst/interleave/deinterleave.c: (deinterleave_chain): Fix
+	GST_ELEMENT_ERROR call (bug #135634)
+	* gst/interleave/interleave.c: (interleave_buffered_loop),
+	(interleave_bytestream_loop): Don't use alloca() (bug #135640)
+	* sys/cdrom/gstcdplayer_ioctl_bsd.h: Fix ioctls on NetBSD (bug #135645)
+	* sys/oss/gstosssink.c: (gst_osssink_get_delay),
+	(gst_osssink_chain): Fix ioctls on NetBSD. (bug #135644)
+	* sys/v4l/v4lmjpegsrc_calls.c: (gst_v4lmjpegsrc_sync_next_frame),
+	(gst_v4lmjpegsrc_set_capture), (gst_v4lmjpegsrc_set_capture_m),
+	(gst_v4lmjpegsrc_capture_init), (gst_v4lmjpegsrc_requeue_frame):
+	Fix GST_ELEMENT_ERROR call.
+	* sys/v4l/v4lsrc_calls.c: (gst_v4lsrc_try_palette): Fix
+	GST_ELEMENT_ERROR call.
+
+2004-02-27  Benjamin Otte  <otte@gnome.org>
+
+	* gst-libs/gst/audio/audio.h:
+	  add macro to make sure header isn't included twice
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_process_chunk):
+	  don't use gst_buffer_free
+	* gst/playondemand/filter.func:
+	  don't use gst_data_free. Free data only once.
+
+2004-02-26  David Schleef  <ds@schleef.org>
+
+	* gst-libs/gst/colorbalance/Makefile.am:
+	* gst-libs/gst/mixer/Makefile.am:
+	* gst-libs/gst/tuner/Makefile.am:
+	* gst/level/Makefile.am: -marshal.[ch] and -enum.[ch] files
+	should not be disted, -marshal.h files should not be installed,
+	and -enum.h files _should_ be installed.  Fix to make this the
+	case.
+
+=== release 0.7.5 ===
+
+2004-02-26  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac: release 0.7.5, "Under The Sea"
+
+2004-02-25  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_link),
+	(gst_audio_convert_change_state), (gst_audio_convert_get_buffer):
+	* gst/videoscale/gstvideoscale.c:
+	* sys/oss/gstosselement.c: (gst_osselement_sync_parms):
+          assorted debug/warning fixes
+
+2004-02-25  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/videoscale/gstvideoscale.c: (gst_videoscale_getcaps),
+	(gst_videoscale_init), (gst_videoscale_chain),
+	(gst_videoscale_set_property), (plugin_init):
+	* gst/videoscale/gstvideoscale.h:
+	* gst/videoscale/videoscale.c: (gst_videoscale_setup),
+	(gst_videoscale_scale_rgb), (gst_videoscale_planar411),
+	(gst_videoscale_planar400), (gst_videoscale_packed422),
+	(gst_videoscale_packed422rev), (gst_videoscale_32bit),
+	(gst_videoscale_24bit), (gst_videoscale_16bit),
+	(gst_videoscale_bilinear), (gst_videoscale_bicubic),
+	(gst_videoscale_scale_plane_slow),
+	(gst_videoscale_scale_point_sample),
+	(gst_videoscale_scale_nearest),
+	(gst_videoscale_scale_nearest_str2),
+	(gst_videoscale_scale_nearest_str4),
+	(gst_videoscale_scale_nearest_32bit),
+	(gst_videoscale_scale_nearest_24bit),
+	(gst_videoscale_scale_nearest_16bit):
+        add debugging category and use it properly
+        fix use of GST_PTR_FORMAT
+
+2004-02-25  Andy Wingo  <wingo@pobox.com>
+
+	* gst/interleave/interleave.c (interleave_buffered_loop): Always
+	push only when channel->buffer is NULL. Prevents segfaults doing
+	the state change after a nonlocal exit, like a scheme exception.
+
+	* gst/audioconvert/gstaudioconvert.c (gst_audio_convert_getcaps):
+	Handle the case where the intersected caps is empty.
+
+2004-02-25  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/law/mulaw-decode.c: (mulawdec_link):
+	* gst/law/mulaw.c: (plugin_init):
+          fix mulawdec so it actually works again
+
+2004-02-24  Arwed v. Merkatz  <v.merkatz@gmx.net>
+
+	reviewed by: David Schleef  <ds@schleef.org>
+
+	* gst/videofilter/gstgamma.c: (gst_gamma_class_init),
+	(gst_gamma_init), (gst_gamma_set_property),
+	(gst_gamma_get_property), (gst_gamma_calculate_tables),
+	(gst_gamma_rgb24), (gst_gamma_rgb32):  Adds gamma correction
+	for RGB, with separate r g and b correction factors. (#131167)
+
+2004-02-24  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_chain):
+          only signal tags for bitrate if they're > 0 (#134894)
+
+2004-02-24  David Schleef  <ds@schleef.org>
+
+	* gst/qtdemux/qtdemux.c: (plugin_init), (gst_qtdemux_loop_header),
+	(qtdemux_parse_moov), (qtdemux_parse), (qtdemux_node_dump_foreach),
+	(qtdemux_dump_mvhd), (qtdemux_dump_tkhd), (qtdemux_dump_elst),
+	(qtdemux_dump_mdhd), (qtdemux_dump_hdlr), (qtdemux_dump_vmhd),
+	(qtdemux_dump_dref), (qtdemux_dump_stsd), (qtdemux_dump_stts),
+	(qtdemux_dump_stss), (qtdemux_dump_stsc), (qtdemux_dump_stsz),
+	(qtdemux_dump_stco), (qtdemux_dump_co64), (qtdemux_dump_dcom),
+	(qtdemux_dump_cmvd), (qtdemux_parse_tree), (qtdemux_parse_trak):
+	Cleanups.  Convert g_prints to GST_LOGs.  Add qtdemux debug
+	category.  Attempt to fix timestamp calculation.
+
+2004-02-24  Johan Dahlin  <johan@gnome.org>
+
+	* gst-libs/gst/gconf/gconf.c: Add \n to g_print error messages
+
+2004-02-23  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	* gconf/Makefile.am:
+	* gconf/gstreamer.schemas:
+	* gst-libs/gst/gconf/Makefile.am:
+	* gst-libs/gst/gconf/gconf.c:
+          version gconf schemas and install locations
+
+2004-02-23  Benjamin Otte  <otte@gnome.org>
+
+	* ext/xine/xineinput.c: (gst_xine_input_dispose):
+	(gst_xine_input_subclass_init):
+	  call parent dispose.
+	  change pad template for CD reader correctly
+	* ext/xine/Makefile.am:
+	* ext/xine/gstxine.h:
+	* ext/xine/xine.c: (plugin_init):
+	* ext/xine/xineaudiosink.c:
+	  wrap audio sinks, too
+	* gst-libs/gst/resample/private.h:
+	* gst-libs/gst/resample/resample.c: (gst_resample_init),
+	(gst_resample_reinit), (gst_resample_scale),
+	(gst_resample_nearest_s16), (gst_resample_bilinear_s16),
+	(gst_resample_sinc_slow_s16), (gst_resample_sinc_s16),
+	(gst_resample_sinc_ft_s16), (gst_resample_nearest_float),
+	(gst_resample_bilinear_float), (gst_resample_sinc_slow_float),
+	(gst_resample_sinc_float), (gst_resample_sinc_ft_float):
+	* gst-libs/gst/resample/resample.h:
+	* gst/audioscale/gstaudioscale.c: (gst_audioscale_method_get_type),
+	(gst_audioscale_class_init), (gst_audioscale_link),
+	(gst_audioscale_get_buffer), (gst_audioscale_init),
+	(gst_audioscale_chain), (gst_audioscale_set_property),
+	(gst_audioscale_get_property):
+	* gst/audioscale/gstaudioscale.h:
+	  s/resample_*/gst_resample_*/i to not clobber namespaces
+
+2004-02-23  Julien MOUTTE  <julien@moutte.net>
+
+	* gst-libs/gst/riff/riff-media.c: (gst_riff_create_video_caps),
+	(gst_riff_create_audio_caps), (gst_riff_create_iavs_caps),
+	(gst_riff_create_video_template_caps),
+	(gst_riff_create_audio_template_caps),
+	(gst_riff_create_iavs_template_caps):
+	* gst-libs/gst/riff/riff-media.h:
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_base_init),
+	(gst_asf_demux_audio_caps), (gst_asf_demux_add_audio_stream),
+	(gst_asf_demux_video_caps), (gst_asf_demux_add_video_stream):
+	* gst/avi/gstavidemux.c: (gst_avi_demux_add_stream):
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream),
+	(gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps),
+	(gst_matroska_demux_plugin_init): First batch implementing audio and
+	video codec tags in demuxers.
+
+2004-02-22  Benjamin Otte  <otte@gnome.org>
+
+	* ext/xine/Makefile.am:
+	* ext/xine/gstxine.h:
+	* ext/xine/xine.c: (plugin_init):
+	* ext/xine/xineinput.c:
+	  add input plugin wrapper. Playback from files, http, mms and cdda
+	  works.
+	* ext/xine/xineaudiodec.c: (gst_xine_audio_dec_chain):
+	  remove leftover G_GNUC_UNUSED
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_process_stream),
+	(gst_asf_demux_identify_guid):
+	  improve debugging output
+
+2004-02-22  Benjamin Otte  <otte@gnome.org>
+
+	reported by: Padraig O'Briain <padraig.obriain@sun.com>
+
+	* autogen.sh:
+	  replace test -e with test -x for mkinstalldirs to be more portable.
+	  (fixes #134816)
+
+2004-02-22  Benjamin Otte  <otte@gnome.org>
+
+	reported by: Stefan Kost <kost@imn.htwk-leipzig.de>
+
+	* gst/audioconvert/gstaudioconvert.c: (plugin_init):
+	  set rank to PRIMARY
+	* gst/volume/gstvolume.c: (plugin_init):
+	  set rank to NONE
+	fixes #134960
+
+2004-02-22   Julio M. Merino Vidal <jmmv@menta.net>
+
+	reviewed by Benjamin Otte  <otte@gnome.org>
+
+	* ext/flac/gstflacenc.c: (gst_flacenc_chain):
+	  escape NULL strings in GST_ELEMENT_ERROR properly (fixes #135116)
+
+2004-02-22  Benjamin Otte  <otte@gnome.org>
+
+	* configure.ac:
+	  export [_]*{gst,Gst,GST}.* symbols from plugins
+
+2004-02-22  Christophe Fergeau <teuf@gnome.org>
+
+	reviewed by: Benjamin Otte  <otte@gnome.org>
+
+	* ext/lame/gstlame.c: (add_one_tag):
+	* ext/mad/gstid3tag.c: (gst_mad_id3_to_tag_list):
+	* ext/vorbis/vorbisenc.c: (gst_vorbisenc_get_tag_value),
+	(gst_vorbisenc_metadata_set1):
+	* gst/tags/gstid3tag.c:
+	* gst/tags/gstvorbistag.c: (gst_vorbis_tag_add):
+	  apply fixes from bugs #135042 (lame can't write tags) and #133817
+	  (add GST_ALBUM_VOLUME_{COUNT,NUMBER} tags)
+
+2004-02-22 Ramon Garcia <ramon_garcia_f@yahoo.com>
+
+	* configure.ac: Export only gst_plugin_desc from plugins.
+         Note that this change only makes any effect with Linux using libtool
+	 1.5.2 or higher. Otherwise it is silently ignored, but it would build
+         fine. And don't try to have several versions of libtool in different
+         directories.
+
+2004-02-20  Andy Wingo  <wingo@pobox.com>
+
+	* gst/intfloat/, gst/oneton: Removed, replaced by audioconvert and
+	interleave respectively.
+
+	* gst/interleave/deinterleave.c: New plugin: deinterleave
+	(replaces on oneton).
+	* gst/interleave/interleave.c: New plugin: interleave.
+	* gst/interleave/plugin.h: Support file.
+	* gst/interleave/plugin.c: Support file.
+
+	* configure.ac: Remove intfloat and oneton, add interleave.
+
+	* ext/sndfile/gstsf.c: Handle events better.
+
+	* gst/audioconvert/gstaudioconvert.c: Change to support int2float
+	and float2int operation. int2float has scheduling problems as
+	noted in in2float_chain.
+
+2004-02-20  Benjamin Otte  <otte@gnome.org>
+
+	* ext/xine/Makefile.am:
+	* ext/xine/gstxine.h:
+	* ext/xine/xine.c:
+	* ext/xine/xineaudiodec.c:
+	* ext/xine/xinecaps.c:
+	  add first version of xine plugin wrapper. Currently only wraps the
+	  QDM2 win32 DLL, and even that only in proof-of-concept quality.
+	* configure.ac:
+	* ext/Makefile.am:
+	  add xine plugin wrapper, disabled by default. Use --enable-xine to
+	  build. Note that it'll segfault on gst-register if you don't remove
+	  the goom and tvtime post plugins from xine.
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_handle_sink_event),
+	(qtdemux_parse), (qtdemux_parse_trak), (qtdemux_audio_caps):
+	  add extradata parsing for QDM2.
+	  change around debugging prints.
+
+2004-02-19  Benjamin Otte  <otte@gnome.org>
+
+	* ext/lame/gstlame.c: (gst_lame_chain):
+	* ext/vorbis/vorbisenc.c: (gst_vorbisenc_chain):
+	  use gst_tag_list_insert when you want to insert tags
+
+2004-02-18  David Schleef  <ds@schleef.org>
+
+	* configure.ac:  Move massink to gst-rotten
+	* ext/Makefile.am:
+	* ext/mas/Makefile.am:
+	* ext/mas/massink.c:
+	* ext/mas/massink.h:
+
+2004-02-18  David Schleef  <ds@schleef.org>
+
+	* ext/gdk_pixbuf/gstgdkpixbuf.c: (plugin_init): Disable gdk_pixbuf
+	typefinding, since it seems to be worse than nothing.
+	* gst/typefind/gsttypefindfunctions.c: (qt_type_find):  Add ftyp
+	atom to recognize .mp4 and .m4a files as video/quicktime.
+
+2004-02-18  David Schleef  <ds@schleef.org>
+
+	* gst/sine/demo-dparams.c: (quit_live),
+	(dynparm_log_value_changed), (dynparm_value_changed), (main):
+	Use double dparams, not float.
+	* gst/sine/gstsinesrc.c: (gst_sinesrc_class_init),
+	(gst_sinesrc_init): Change sync default to FALSE, since multiple
+	sync'd elements don't really work correctly.
+	* gst/volume/gstvolume.c: (volume_class_init), (volume_init),
+	(volume_update_volume), (volume_get_property):  Change dparam
+	to double.
+
+2004-02-18  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c:
+	(gst_ximagesink_xwindow_update_geometry),
+	(gst_ximagesink_renegotiate_size), (gst_ximagesink_handle_xevents),
+	(gst_ximagesink_change_state), (gst_ximagesink_expose),
+	(gst_ximagesink_init): Rework the way software video scaling works. So
+	now we check on each chain call if the video frames are feeling the
+	window. If not we try to renegotiate caps. On failure we memorize that
+	and we won't try again for that PLAYING sessions.
+	* sys/ximage/ximagesink.h: Adding a boolean to store the caps renego
+	failure.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_init): initialize the
+	synchronous flag.
+
+2004-02-18  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/play/play.c: (gst_play_pipeline_setup):
+          break up _link so we can give a better debug message for errors
+
+2004-02-18  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/gdk_pixbuf/gstgdkpixbuf.c: (plugin_init):
+          set up debug category
+
+2004-02-18  Julien MOUTTE <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_renegotiate_size),
+	(gst_ximagesink_handle_xevents), (gst_ximagesink_expose): Reorganizing
+	the way renegotiation work. The event handling function is not taking
+	care of external windows and renegotiate method check for pad flags
+	NEGOTIATING. Should fix : #133209
+
+2004-02-17  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_expose): Checking if the
+	pad is negotiating before trying renegotiation.
+
+2004-02-17  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_type_find):
+          pass on all possible mime types as typefind hints
+
+2004-02-17  Julien MOUTTE <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_ximage_new):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xvimage_new): Fix a
+	possible SHM leak if we crash. All other apps using XShm are doing
+	that.
+
+2004-02-17  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_renegotiate_size),
+	(gst_ximagesink_expose): Renegotiate size on expose.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_expose): Update window
+	size on expose.
+
+2004-02-16  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* testsuite/alsa/sinesrc.c:
+	  cosmetic fix to fix compile issue with gcc 2.95.4
+
+2004-02-16  Julien MOUTTE <julien@moutte.net>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_open_audio),
+	(gst_alsa_timestamp_to_bytes): Alsa should trigger an error if it
+	failed opening the audio device.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_ximage_new),
+	(gst_ximagesink_ximage_destroy), (gst_ximagesink_ximage_put),
+	(gst_ximagesink_xwindow_new), (gst_ximagesink_xwindow_destroy),
+	(gst_ximagesink_xwindow_resize), (gst_ximagesink_xwindow_clear),
+	(gst_ximagesink_renegotiate_size), (gst_ximagesink_handle_xevents),
+	(gst_ximagesink_xcontext_get), (gst_ximagesink_xcontext_clear),
+	(gst_ximagesink_change_state), (gst_ximagesink_chain),
+	(gst_ximagesink_set_xwindow_id): Clearing window in READY TO PAUSED.
+	Removing some useless g_return_if_fail like wingo suggested.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xvimage_new),
+	(gst_xvimagesink_xvimage_destroy), (gst_xvimagesink_xvimage_put),
+	(gst_xvimagesink_xwindow_new), (gst_xvimagesink_xwindow_destroy),
+	(gst_xvimagesink_xwindow_resize), (gst_xvimagesink_xwindow_clear),
+	(gst_xvimagesink_update_colorbalance),
+	(gst_xvimagesink_handle_xevents), (gst_xvimagesink_xcontext_get),
+	(gst_xvimagesink_xcontext_clear),
+	(gst_xvimagesink_get_fourcc_from_caps),
+	(gst_xvimagesink_change_state), (gst_xvimagesink_chain),
+	(gst_xvimagesink_set_xwindow_id),
+	(gst_xvimagesink_colorbalance_list_channels),
+	(gst_xvimagesink_colorbalance_set_value),
+	(gst_xvimagesink_colorbalance_get_value): Clearing window in READY TO
+	PAUSED. Removing some useless g_return_if_fail like wingo suggested.
+
+2004-02-16  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_chain):
+          throw error when not negotiated instead of asserting
+
+2004-02-15  Julien MOUTTE  <julien@moutte.net>
+
+	* gst/switch/gstswitch.c: (gst_switch_loop): More fixes for
+	correct data refcounting.
+
+2004-02-15  Julien MOUTTE  <julien@moutte.net>
+
+	* gst/switch/gstswitch.c: (gst_switch_change_state),
+	(gst_switch_class_init): Cleaning the sinkpads correctly on state
+	change, mostly the EOS flag.
+
+2004-02-15  Julien MOUTTE  <julien@moutte.net>
+
+	* examples/gstplay/player.c: (got_eos), (main): Adding some
+	output for debugging.
+	* gst-libs/gst/play/play.c: (gst_play_state_change): Stop our
+	timeouts if we go to any state different from PLAYING.
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_read_seek): Fix some
+	more EOS bugs in riff lib.
+
+2004-02-14  Julien MOUTTE  <julien@moutte.net>
+
+	* gst-libs/gst/play/play.c: (gst_play_connect_visualization): Disable
+	visualization until i find a way to fix switch correctly.
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_peek_head): Fix a bug when
+	EOS arrives.
+	* gst/switch/gstswitch.c: (gst_switch_release_pad),
+	(gst_switch_request_new_pad), (gst_switch_poll_sinkpads),
+	(gst_switch_loop), (gst_switch_dispose), (gst_switch_class_init):
+	Reworked switch to get a more correct behaviour with events and refing
+	of data stored in sinkpads.
+	* gst/switch/gstswitch.h: Adding an eos flag for every sinkpad so that
+	we don't pull from a pad in EOS.
+
+2004-02-14  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_chain):
+	  remove v1 tag even if we can't read it (makes sure we don't detect
+	  it again)
+
+2004-02-14  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_pcm_wait),
+	(gst_alsa_xrun_recovery):
+	* ext/alsa/gstalsa.h:
+	  try xrun recovery when wait failed. Make xrun recovery function
+	  return TRUE/FALSE to indicate success. (might fix #134354)
+
+2004-02-13  David Schleef  <ds@schleef.org>
+
+	* gst/sine/demo-dparams.c: (dynparm_log_value_changed),
+	(dynparm_value_changed), (main): Convert from float to double.
+	* gst/sine/gstsinesrc.c: (gst_sinesrc_init): same.
+
+2004-02-13  David Schleef  <ds@schleef.org>
+
+	* gst/silence/gstsilence.c: (gst_silence_class_init),
+	(gst_silence_set_clock), (gst_silence_get),
+	(gst_silence_set_property), (gst_silence_get_property):
+	* gst/silence/gstsilence.h: Add sync property.
+	* gst/sine/gstsinesrc.c: (gst_sinesrc_class_init),
+	(gst_sinesrc_init), (gst_sinesrc_set_clock), (gst_sinesrc_get),
+	(gst_sinesrc_set_property), (gst_sinesrc_get_property):
+	* gst/sine/gstsinesrc.h: Add sync property.
+
+2004-02-13  David Schleef  <ds@schleef.org>
+
+	* gst/intfloat/gstint2float.c: (conv_f32_s16),
+	(gst_int2float_chain_gint16):  Change stdint usage to glib types.
+
+2004-02-13  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* gst-libs/ext/Makefile.am:
+          move ffmpeg plugin to gst-ffmpeg module
+
+2004-02-13  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac: use GST_ARCH to detect architecture
+
+2004-02-12  Julien MOUTTE  <julien@moutte.net>
+
+	* gst/vbidec/vbiscreen.c: Fixing thomasvs fixes. Missing header.
+
+2004-02-12  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/ladspa/gstladspa.c: (gst_ladspa_base_init):
+          classify LADSPA plugins based on number of src/sink pads
+	  (#133663, Stefan Kost)
+	* gst/sine/gstsinesrc.c: (gst_sinesrc_init):
+          fix dparams registration
+	  (#133528, Stefan Kost)
+	* gst/vbidec/vbiscreen.c: (vbiscreen_set_current_cell):
+          fix use of isprint and use g_ascii_isprint instead
+	  (#133316, Stefan Kost)
+
+2004-02-11  David Schleef  <ds@schleef.org>
+
+	Convert a few inner loops to use liboil.  This is currently
+	optional, and is only enabled if liboil is present (duh!).
+	* configure.ac: Check for liboil-0.1
+	* gst/intfloat/Makefile.am:
+	* gst/intfloat/gstint2float.c: (conv_f32_s16), (scalarmult_f32),
+	(gst_int2float_chain_gint16):
+	* gst/videofilter/Makefile.am:
+	* gst/videofilter/gstvideobalance.c: (gst_videobalance_class_init),
+	(tablelookup_u8), (gst_videobalance_planar411):
+	* gst/videotestsrc/Makefile.am:
+	* gst/videotestsrc/gstvideotestsrc.c: (plugin_init):
+	* gst/videotestsrc/videotestsrc.c: (splat_u8), (paint_hline_YUY2),
+	(paint_hline_IYU2), (paint_hline_str4), (paint_hline_str3),
+	(paint_hline_RGB565), (paint_hline_xRGB1555):
+
+2004-02-11  David Schleef  <ds@schleef.org>
+
+	* ext/lcs/gstcolorspace.c: (colorspace_find_lcs_format),
+	(gst_colorspace_caps_get_fourcc), (colorspace_setup_converter),
+	(gst_colorspace_getcaps), (gst_colorspace_link),
+	(gst_colorspace_base_init), (gst_colorspace_init),
+	(gst_colorspace_chain), (gst_colorspace_change_state),
+	(plugin_init): Merge Ronald's patch (bug #117897) and update
+	for new caps and negotiation.  Seems to work, although it
+	shows off bugs in lcs.
+
+2004-02-11  David Schleef  <ds@schleef.org>
+
+	* ext/alsa/Makefile.am: Fix linking against libgstinterfaces.
+	(bug #133886)  Noticed by bugs@leroutier.net (Stephane LOEUILLET)
+
+2004-02-11  David Schleef  <ds@schleef.org>
+
+	* ext/librfb/gstrfbsrc.c: (gst_rfbsrc_class_init),
+	(gst_rfbsrc_change_state), (gst_rfbsrc_init),
+	(gst_rfbsrc_set_property), (gst_rfbsrc_get_property):
+	Add server and port properties
+
+2004-02-11  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* m4/a52.m4:
+	* m4/aalib.m4:
+	* m4/as-ffmpeg.m4:
+	* m4/as-liblame.m4:
+	* m4/as-slurp-ffmpeg.m4:
+	* m4/check-libheader.m4:
+	* m4/esd.m4:
+	* m4/freetype2.m4:
+	* m4/gconf-2.m4:
+	* m4/glib.m4:
+	* m4/gst-alsa.m4:
+	* m4/gst-artsc.m4:
+	* m4/gst-ivorbis.m4:
+	* m4/gst-matroska.m4:
+	* m4/gst-sdl.m4:
+	* m4/gst-shout2.m4:
+	* m4/gst-sid.m4:
+	* m4/gtk.m4:
+	* m4/libdv.m4:
+	* m4/libfame.m4:
+	* m4/libmikmod.m4:
+	* m4/ogg.m4:
+	* m4/vorbis.m4:
+          fix underquotedness of macros (#133800)
+	* m4/as-avifile.m4:
+	* m4/xmms.m4:
+          removed because no longer used
+
+2004-02-11  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+          require gettext 0.11.5 so ulonglong.m4 gets checked out and copied
+          by autopoint (fixes #132996)
+
+2004-02-11  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_base_init):
+	* ext/ffmpeg/gstffmpegdemux.c: (gst_ffmpegdemux_base_init):
+	* ext/ffmpeg/gstffmpegenc.c: (gst_ffmpegenc_base_init):
+	* ext/ffmpeg/gstffmpegmux.c: (gst_ffmpegmux_base_init):
+	  fix memleaks
+
+2004-02-11  David Schleef  <ds@schleef.org>
+
+	* ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_sink_link),
+	(gst_gdk_pixbuf_chain): Fix logic bug causing spurious errors.
+	* ext/jpeg/gstjpegdec.c: (gst_jpegdec_base_init),
+	(gst_jpegdec_init), (gst_jpegdec_chain): Fix negotiation.
+	* ext/jpeg/gstjpegenc.c: (gst_jpegenc_base_init),
+	(gst_jpegenc_class_init), (gst_jpegenc_init),
+	(gst_jpegenc_getcaps), (gst_jpegenc_link), (gst_jpegenc_resync),
+	(gst_jpegenc_chain), (gst_jpegenc_set_property),
+	(gst_jpegenc_get_property):  Fix negotiation.  Add some properties.
+	* ext/jpeg/gstjpegenc.h: Fix negotiation.
+
+2004-02-10  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/mikmod/gstmikmod.c: (gst_mikmod_init),
+	(gst_mikmod_srcfixate), (gst_mikmod_srclink), (gst_mikmod_loop):
+	* ext/mikmod/gstmikmod.h:
+	  fix caps negotiation in mikmod
+	* ext/ogg/gstoggdemux.c: (gst_ogg_print):
+	  output debug information
+
+2004-02-08  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst-libs/gst/colorbalance/Makefile.am:
+	* gst-libs/gst/navigation/Makefile.am:
+	* gst-libs/gst/xoverlay/Makefile.am:
+	  remove unused GST_OPT_CFLAGS from Makefiles
+	  include X_CFLAGS and X_LIBS in xoverlay. (#131948)
+
+2004-02-07  David Schleef  <ds@schleef.org>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_handle_event): Don't
+	push events to pads that haven't been created (#133508)
+
+2004-02-07  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/dv/gstdvdec.c: (gst_dvdec_init), (gst_dvdec_src_convert),
+	(gst_dvdec_sink_convert), (gst_dvdec_handle_sink_event),
+	(gst_dvdec_video_getcaps), (gst_dvdec_video_link),
+	(gst_dvdec_loop), (gst_dvdec_change_state):
+	Second attempt at committing a working dvdec element.
+
+2004-02-06  David Schleef  <ds@schleef.org>
+
+	Build fixes for OS X: (see #129600)
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_read_strh),
+	(gst_riff_read_strf_vids), (gst_riff_read_strf_auds),
+	(gst_riff_read_strf_iavs):
+	* gst/avi/gstavidemux.c: (gst_avi_demux_stream_avih),
+	(gst_avi_demux_stream_odml):
+	* gst/playondemand/Makefile.am:
+	* gst/rtp/rtp-packet.c:
+
+2004-02-05  David Schleef  <ds@schleef.org>
+
+	* ext/dv/gstdvdec.c: (gst_dvdec_init), (gst_dvdec_loop): Revert
+	last change, because it Just Doesn't Compile.
+
+2004-02-05  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_chain):
+	  skip undecodable id3v2 tag instead of keeping it
+
+2004-02-05  David Schleef  <ds@schleef.org>
+
+	* gst/mpegaudioparse/gstmpegaudioparse.c: (gst_mp3parse_chain):
+	Unref leaked buffer.  (Noticed by Ronald)
+
+2004-02-05  David I. Lehn  <dlehn@users.sourceforge.net>
+
+	* pkgconfig/gstreamer-libs-uninstalled.pc.in:
+	Sync requires with other checks.  >= vs =.
+
+2004-02-06  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/dv/gstdvdec.c: (gst_dvdec_init), (gst_dvdec_video_getcaps),
+	(gst_dvdec_video_link), (gst_dvdec_loop):
+	* ext/dv/gstdvdec.h:
+	  rework the caps negotiation so that dvdec works again instead
+	  of just segfaulting.
+
+=== release 0.7.4 ===
+
+2004-02-06  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* NEWS: GStreamer Plugins 0.7.4 "For Great Justice" released
+	* configure.ac: changed for release
+
+2004-02-05  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/gconf/gstreamer-gconf-uninstalled.pc.in:
+	* pkgconfig/gstreamer-interfaces-uninstalled.pc.in:
+	* pkgconfig/gstreamer-libs-uninstalled.pc.in:
+	* pkgconfig/gstreamer-play-uninstalled.pc.in:
+          reworked patch by David Lehn to fix libdir and includedir for
+          uninstalled libraries
+          removed play and gconf from gstreamer-libs since they have their
+          own pkgconfig files
+
+2004-02-04  David Schleef  <ds@schleef.org>
+
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_parse_fmt): Fix a caps
+	memleak.
+
+2004-02-05  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_read_info):
+	  use correct GST_TAG_ENCODER tag
+
+2004-02-05  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_change_state):
+	  be sure to stop the clock when going to paused
+	* sys/oss/gstosssink.c: (gst_osssink_change_state):
+	  reset number of transmitted when going to ready.
+	fixes #132935
+
+2004-02-05  Charles Schmidt <cschmidt2@emich.edu>
+
+	reviewed by Benjamin Otte
+
+	* ext/mad/gstid3tag.c: (gst_mad_id3_to_tag_list):
+	  extract track count (fixes #133410)
+
+2004-02-04  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_do_caps_nego):
+	  that should be !=, not == (fixes #132519)
+
+2004-02-04  David Schleef  <ds@schleef.org>
+
+	Make sure set_explicit_caps() is called before adding pad.
+	* ext/ffmpeg/gstffmpegdemux.c: (gst_ffmpegdemux_loop):
+	* gst/id3/gstid3types.c: (gst_id3types_loop):
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_parse_syshead):
+	* gst/realmedia/rmdemux.c: (gst_rmdemux_add_stream):
+
+2004-02-04  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+          bump nano to 2, first prerelease
+          put back AM_PROG_LIBTOOL
+
+2004-02-04  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* testsuite/alsa/Makefile.am:
+          these are user test apps, not automatic testsuite tests
+
+2004-02-04  David Schleef  <ds@schleef.org>
+
+	Convert GST_DEBUG_CAPS() to GST_DEBUG():
+	* gst/mpeg1videoparse/gstmp1videoparse.c:
+	(mp1videoparse_parse_seq):
+	* gst/realmedia/rmdemux.c: (gst_rmdemux_add_stream):
+	* gst/videoscale/gstvideoscale.c: (gst_videoscale_getcaps):
+	* sys/xvideo/gstxwindow.c: (_gst_xwindow_new):
+	* sys/xvideo/xvideosink.c: (gst_xvideosink_sinkconnect),
+	(gst_xvideosink_getcaps):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_xv_support):
+	* testsuite/gst-lint: more tests
+
+2004-02-04  David Schleef  <ds@schleef.org>
+
+	Replace use of GST_PAD_FORMATS_FUNCTION() and similar macros
+	with the code that they would expand to.
+	* ext/flac/gstflacdec.c: (gst_flacdec_get_src_formats),
+	(gst_flacdec_get_src_query_types),
+	(gst_flacdec_get_src_event_masks):
+	* ext/gnomevfs/gstgnomevfssrc.c: (gst_gnomevfssrc_get_formats),
+	(gst_gnomevfssrc_get_query_types),
+	(gst_gnomevfssrc_get_event_mask):
+
+2004-02-04  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/sine/gstsinesrc.c: (gst_sinesrc_class_init),
+	(gst_sinesrc_dispose):
+	  fix memleak by properly disposing sinesrc
+
+2004-02-04  Julien MOUTTE  <julien@moutte.net>
+
+	* gst-libs/gst/xoverlay/xoverlay.c: (gst_x_overlay_expose):
+	* gst-libs/gst/xoverlay/xoverlay.h: Adding the _expose method to tell
+	an overlay to redraw the image because it has been exposed.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_ximage_destroy),
+	(gst_ximagesink_ximage_put), (gst_ximagesink_expose),
+	(gst_ximagesink_xoverlay_init), (gst_ximagesink_init):
+	* sys/ximage/ximagesink.h: Implement expose method from XOverlay
+	interface
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xvimage_destroy),
+	(gst_xvimagesink_xvimage_put), (gst_xvimagesink_expose),
+	(gst_xvimagesink_xoverlay_init), (gst_xvimagesink_init):
+	* sys/xvimage/xvimagesink.h: Implement expose method from XOverlay
+	interface
+
+2004-02-03  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_type_find):
+	  more memleak fixage
+
+2004-02-03  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/gdk_pixbuf/gstgdkpixbuf.c: (plugin_init):
+	* gst/typefind/gsttypefindfunctions.c:
+	  fix memleaks shown by gst-typefind
+
+2004-02-03  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* common/glib-gen.mak:
+          add hack rule to touch .Plo files
+	* gst-libs/gst/colorbalance/Makefile.am:
+	* gst-libs/gst/mixer/Makefile.am:
+	* gst-libs/gst/play/Makefile.am:
+	* gst-libs/gst/tuner/Makefile.am:
+          remove glib_root variable
+
+2004-02-03  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_add_stream):
+	  set explicit caps before adding the element, so the autopluggers can
+	  plug correctly.
+	* gst/typefind/gsttypefindfunctions.c: (mp3_type_find),
+	(mpeg2_sys_type_find), (mpeg1_sys_type_find),
+	(mpeg_video_type_find), (mpeg_video_stream_type_find),
+	(dv_type_find):
+	  fix memleaks in typefind functions. gst_type_find_suggest takes a const
+	  argument.
+
+2004-02-03  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/colorbalance/Makefile.am:
+	* gst-libs/gst/colorbalance/colorbalance-marshal.list:
+	* gst-libs/gst/colorbalance/colorbalance.c:
+	* gst-libs/gst/colorbalance/colorbalance.h:
+	* gst-libs/gst/colorbalance/colorbalancemarshal.list:
+	* gst-libs/gst/mixer/Makefile.am:
+	* gst-libs/gst/mixer/mixer-marshal.list:
+	* gst-libs/gst/mixer/mixer.c:
+	* gst-libs/gst/mixer/mixer.h:
+	* gst-libs/gst/mixer/mixermarshal.list:
+	* gst-libs/gst/play/Makefile.am:
+	* gst-libs/gst/play/play.h:
+	* gst-libs/gst/tuner/Makefile.am:
+	* gst-libs/gst/tuner/tuner-marshal.list:
+	* gst-libs/gst/tuner/tuner.c:
+	* gst-libs/gst/tuner/tuner.h:
+	* gst-libs/gst/tuner/tunermarshal.list:
+          use new glib-gen.mak snippet to clean up Makefile.am
+          fix various bugs in Makefile.am's
+
+2004-02-03  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_chain):
+	  handle chain parsing correctly in the multichain case
+	* ext/theora/theoradec.c: (gst_theora_dec_init), (_theora_ilog),
+	(theora_dec_from_granulepos), (theora_dec_to_granulepos),
+	(theora_dec_src_query), (theora_dec_src_event), (theora_dec_event),
+	(theora_dec_chain):
+	  handle events and queries correctly
+
+2004-02-03  David I. Lehn  <dlehn@users.sourceforge.net>
+
+	* .cvsignore:
+	Ignore generated file _stdint.h.
+
+2004-02-03  David I. Lehn  <dlehn@users.sourceforge.net>
+
+	* gst-libs/gst/colorbalance/Makefile.am:
+	* gst-libs/gst/colorbalance/colorbalance.h:
+	* gst-libs/gst/mixer/Makefile.am:
+	* gst-libs/gst/mixer/mixer.h:
+	* gst-libs/gst/play/Makefile.am:
+	* gst-libs/gst/play/play.h:
+	* gst-libs/gst/tuner/Makefile.am:
+	* gst-libs/gst/tuner/tuner.h:
+	Generate enum type code with glib-mkenums.
+	* gst-libs/gst/colorbalance/.cvsignore:
+	* gst-libs/gst/mixer/.cvsignore:
+	* gst-libs/gst/play/.cvsignore:
+	* gst-libs/gst/tuner/.cvsignore:
+	Ignore generated files.
+
+2004-02-03  David I. Lehn  <dlehn@users.sourceforge.net>
+
+	* gst-libs/gst/audio/.cvsignore:
+	Ignore generated file.
+	* gst-libs/gst/audio/Makefile.am:
+	Do not install example filter.
+
+2004-02-03  David I. Lehn  <dlehn@users.sourceforge.net>
+
+	* examples/switch/.cvsignore:
+	Ignore generated file.
+
+2004-02-03  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* common/m4/ax_create_stdint_h.m4:
+	* configure.ac:
+	  add AX_CREATE_STDINT_H to get correct type definitions for a52dec in
+	  _stdint.h.
+	* Makefile.am:
+	  remove generated _stdint.h in DISTCLEANFILES
+	* ext/a52dec/gsta52dec.c:
+	  include _stdint.h for a52dec. (should fix #133064)
+
+2004-02-02  Jeremy Simon  <jesimon@libertysurf.fr>
+
+	* gst/tags/gstvorbistag.c: (gst_vorbis_tag_add),
+	(gst_tag_to_vorbis_comments):
+	Add replaygain support to vorbistag
+
+2004-02-02  Jeremy Simon  <jesimon@libertysurf.fr>
+	* ext/ffmpeg/gstffmpegcodecmap.c: (gst_ffmpeg_codecid_to_caps),
+	(gst_ffmpeg_caps_to_extradata):
+	  Fix SVQ3 caps flag properties
+	  Use glib macro for bytes swap
+
+2004-02-02  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/audiofile/gstafsink.c: (gst_afsink_plugin_init):
+	* ext/audiofile/gstafsrc.c: (gst_afsrc_plugin_init):
+	* ext/gnomevfs/gstgnomevfs.c: (plugin_init):
+	* ext/sndfile/gstsf.c: (plugin_init):
+	* gst/avi/gstavi.c: (plugin_init):
+	* sys/dxr3/dxr3init.c: (plugin_init):
+	* sys/oss/gstossaudio.c: (plugin_init):
+	* sys/v4l/gstv4l.c: (plugin_init):
+	* sys/v4l2/gstv4l2.c: (plugin_init):
+          remove textdomain calls
+	* po/nl.po:
+          update Dutch translation
+
+2004-02-02  Julien MOUTTE  <julien@moutte.net>
+
+	* gst-libs/gst/play/play.c: (gst_play_pipeline_setup),
+	(gst_play_set_audio_sink): Moving volume in the audio thread for
+	instantaneous volume change. Maybe i will add another volume in front
+	of visualization later, not sure yet though.
+
+2004-02-02  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_renegotiate_size),
+	(gst_ximagesink_handle_xevents): Better X events handling, only take
+	the latest events for configure and motion.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_handle_xevents): same.
+
+2004-02-02  Jon Trowbridge  <trow@gnu.org>
+
+	reviewed by: David Schleef  <ds@schleef.org>
+
+	Fix memory leaks:
+	* ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_register):
+	* ext/ffmpeg/gstffmpegenc.c: (gst_ffmpegenc_register):
+
+2004-02-02  David Schleef  <ds@schleef.org>
+
+	code cleanup.  Change bzero() to memset().  Remove duplicate ; at ends
+	of lines.
+	* ext/cdparanoia/gstcdparanoia.c: (cdparanoia_event):
+	* ext/flac/gstflactag.c: (gst_flac_tag_chain):
+	* ext/xvid/gstxviddec.c: (gst_xviddec_src_link):
+	* gst-libs/gst/play/play.c: (gst_play_get_sink_element):
+	* gst/ac3parse/gstac3parse.c: (gst_ac3parse_chain):
+	* gst/effectv/gstedge.c: (gst_edgetv_sinkconnect):
+	* gst/effectv/gstvertigo.c: (gst_vertigotv_sinkconnect):
+	* gst/intfloat/float22int.c: (gst_float2_2_int_getcaps),
+	(gst_float2_2_int_link):
+	* gst/mpeg2sub/gstmpeg2subt.c: (gst_mpeg2subt_chain_subtitle):
+	* gst/rtjpeg/RTjpeg.c: (RTjpeg_init_mcompress):
+	* gst/tcp/gsttcpsink.c: (gst_tcpsink_init_send):
+	* gst/tcp/gsttcpsrc.c: (gst_tcpsrc_init_receive):
+	* gst/udp/gstudpsink.c: (gst_udpsink_init_send):
+	* gst/udp/gstudpsrc.c: (gst_udpsrc_init_receive):
+	* sys/v4l/gstv4lelement.c: (gst_v4lelement_init):
+	* sys/v4l2/v4l2src_calls.c: (gst_v4l2src_set_capture):
+	* testsuite/gst-lint: Add tests for bzero and ;;
+
+2004-02-02  David Schleef  <ds@schleef.org>
+
+	* gst/debug/efence.c: Add fallback if MAP_ANONYMOUS isn't defined.
+
+2004-02-02  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/aalib/gstaasink.c: (gst_aasink_open):
+	* ext/alsa/gstalsa.c: (gst_alsa_link), (gst_alsa_xrun_recovery):
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_loop):
+	* ext/alsa/gstalsasrc.c: (gst_alsa_src_loop):
+	* ext/audiofile/gstafsink.c: (gst_afsink_open_file),
+	(gst_afsink_close_file):
+	* ext/audiofile/gstafsrc.c: (gst_afsrc_open_file),
+	(gst_afsrc_close_file):
+	* ext/divx/gstdivxdec.c: (gst_divxdec_setup), (gst_divxdec_chain):
+	* ext/divx/gstdivxenc.c: (gst_divxenc_setup), (gst_divxenc_chain):
+	* ext/dv/gstdvdec.c: (gst_dvdec_loop):
+	* ext/dvdnav/dvdnavsrc.c: (dvdnavsrc_user_op), (dvdnavsrc_get):
+	* ext/esd/esdmon.c: (gst_esdmon_get):
+	* ext/esd/esdsink.c: (gst_esdsink_chain), (gst_esdsink_open_audio):
+	* ext/faac/gstfaac.c: (gst_faac_chain):
+	* ext/faad/gstfaad.c: (gst_faad_chain):
+	* ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_chain):
+	* ext/ffmpeg/gstffmpegdemux.c: (gst_ffmpegdemux_loop):
+	* ext/ffmpeg/gstffmpegmux.c: (gst_ffmpegmux_loop):
+	* ext/flac/gstflacdec.c: (gst_flacdec_error_callback),
+	(gst_flacdec_loop):
+	* ext/flac/gstflacenc.c: (gst_flacenc_chain):
+	* ext/flac/gstflactag.c: (gst_flac_tag_chain):
+	* ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_chain):
+	* ext/gnomevfs/gstgnomevfssink.c: (gst_gnomevfssink_open_file),
+	(gst_gnomevfssink_close_file):
+	* ext/gnomevfs/gstgnomevfssrc.c: (audiocast_init),
+	(gst_gnomevfssrc_open_file):
+	* ext/ivorbis/vorbisfile.c: (gst_ivorbisfile_loop):
+	* ext/lame/gstlame.c: (gst_lame_sink_link), (gst_lame_chain):
+	* ext/lcs/gstcolorspace.c: (gst_colorspace_srcconnect_func):
+	* ext/mad/gstid3tag.c: (gst_id3_tag_handle_event),
+	(gst_id3_tag_do_typefind), (gst_id3_tag_chain):
+	* ext/mad/gstmad.c: (gst_mad_chain):
+	* ext/mikmod/gstmikmod.c: (gst_mikmod_loop):
+	* ext/mpeg2dec/gstmpeg2dec.c:
+	* ext/mpeg2enc/gstmpeg2enc.cc:
+	* ext/mplex/gstmplex.cc:
+	* ext/mplex/gstmplexibitstream.cc:
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_chain),
+	(gst_ogg_demux_push):
+	* ext/raw1394/gstdv1394src.c:
+	* ext/sdl/sdlvideosink.c: (gst_sdlvideosink_lock),
+	(gst_sdlvideosink_initsdl), (gst_sdlvideosink_create):
+	* ext/sndfile/gstsf.c: (gst_sf_open_file), (gst_sf_close_file),
+	(gst_sf_loop):
+	* ext/speex/gstspeexenc.c: (gst_speexenc_chain):
+	* ext/swfdec/gstswfdec.c: (gst_swfdec_loop):
+	* ext/tarkin/gsttarkindec.c: (gst_tarkindec_chain):
+	* ext/tarkin/gsttarkinenc.c: (gst_tarkinenc_chain):
+	* ext/vorbis/vorbisenc.c: (gst_vorbisenc_chain):
+	* ext/vorbis/vorbisfile.c: (gst_vorbisfile_loop):
+	* ext/xvid/gstxviddec.c: (gst_xviddec_setup), (gst_xviddec_chain):
+	* ext/xvid/gstxvidenc.c: (gst_xvidenc_setup), (gst_xvidenc_chain):
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_peek_head),
+	(gst_riff_read_element_data), (gst_riff_read_seek),
+	(gst_riff_peek_list), (gst_riff_read_list), (gst_riff_read_header):
+	* gst/adder/gstadder.c: (gst_adder_loop):
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_process_segment),
+	(gst_asf_demux_process_stream), (gst_asf_demux_get_stream):
+	* gst/avi/gstavidemux.c: (gst_avi_demux_stream_init),
+	(gst_avi_demux_add_stream), (gst_avi_demux_stream_header):
+	* gst/avi/gstavimux.c: (gst_avimux_stop_file):
+	* gst/flx/gstflxdec.c: (gst_flxdec_loop):
+	* gst/goom/gstgoom.c: (gst_goom_chain):
+	* gst/id3/gstid3types.c: (gst_id3types_loop):
+	* gst/intfloat/float22int.c: (gst_float2_2_int_chain):
+	* gst/intfloat/gstfloat2int.c: (gst_float2int_loop):
+	* gst/intfloat/gstint2float.c: (gst_int2float_chain_gint16):
+	* gst/matroska/ebml-read.c: (gst_ebml_read_element_id),
+	(gst_ebml_read_element_length), (gst_ebml_read_element_data),
+	(gst_ebml_read_seek), (gst_ebml_read_uint), (gst_ebml_read_sint),
+	(gst_ebml_read_float), (gst_ebml_read_header):
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_init_stream),
+	(gst_matroska_demux_parse_blockgroup):
+	* gst/monoscope/gstmonoscope.c: (gst_monoscope_chain):
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_loop):
+	* gst/oneton/gstoneton.c: (gst_oneton_chain):
+	* gst/silence/gstsilence.c: (gst_silence_get):
+	* gst/sine/gstsinesrc.c: (gst_sinesrc_get):
+	* gst/smpte/gstsmpte.c: (gst_smpte_loop):
+	* gst/speed/gstspeed.c: (speed_loop):
+	* gst/tags/gstvorbistag.c: (gst_vorbis_tag_chain):
+	* gst/videotestsrc/gstvideotestsrc.c: (gst_videotestsrc_get):
+	* gst/volenv/gstvolenv.c: (gst_volenv_chain):
+	* gst/wavenc/gstwavenc.c: (gst_wavenc_chain):
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_parse_fmt),
+	(gst_wavparse_loop):
+	* sys/dxr3/dxr3audiosink.c: (dxr3audiosink_open),
+	(dxr3audiosink_set_mode_pcm), (dxr3audiosink_set_mode_ac3),
+	(dxr3audiosink_close):
+	* sys/dxr3/dxr3spusink.c: (dxr3spusink_open), (dxr3spusink_close):
+	* sys/dxr3/dxr3videosink.c: (dxr3videosink_open),
+	(dxr3videosink_close), (dxr3videosink_write_data):
+	* sys/oss/gstosselement.c: (gst_osselement_open_audio):
+	* sys/oss/gstosssink.c: (gst_osssink_chain):
+	* sys/oss/gstosssrc.c: (gst_osssrc_get):
+	* sys/v4l/gstv4lmjpegsink.c: (gst_v4lmjpegsink_chain):
+	* sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_buffer_free):
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_buffer_free):
+	* sys/v4l/v4l-overlay_calls.c: (gst_v4l_set_overlay),
+	(gst_v4l_set_window), (gst_v4l_enable_overlay):
+	* sys/v4l/v4l_calls.c: (gst_v4l_get_capabilities), (gst_v4l_open),
+	(gst_v4l_set_chan_norm), (gst_v4l_get_signal),
+	(gst_v4l_get_frequency), (gst_v4l_set_frequency),
+	(gst_v4l_get_picture), (gst_v4l_set_picture), (gst_v4l_get_audio),
+	(gst_v4l_set_audio):
+	* sys/v4l/v4l_calls.h:
+	* sys/v4l/v4lmjpegsink_calls.c: (gst_v4lmjpegsink_sync_thread),
+	(gst_v4lmjpegsink_queue_frame), (gst_v4lmjpegsink_set_playback),
+	(gst_v4lmjpegsink_playback_init),
+	(gst_v4lmjpegsink_playback_start):
+	* sys/v4l/v4lmjpegsrc_calls.c: (gst_v4lmjpegsrc_queue_frame):
+	* sys/v4l/v4lsrc_calls.c: (gst_v4lsrc_queue_frame),
+	(gst_v4lsrc_sync_frame), (gst_v4lsrc_capture_init),
+	(gst_v4lsrc_requeue_frame), (gst_v4lsrc_try_palette):
+	* sys/v4l2/gstv4l2src.c: (gst_v4l2src_get):
+	* sys/v4l2/v4l2-overlay_calls.c: (gst_v4l2_set_display),
+	(gst_v4l2_set_window), (gst_v4l2_enable_overlay):
+	* sys/v4l2/v4l2_calls.c: (gst_v4l2_get_capabilities),
+	(gst_v4l2_fill_lists), (gst_v4l2_open), (gst_v4l2_get_norm),
+	(gst_v4l2_set_norm), (gst_v4l2_get_input), (gst_v4l2_set_input),
+	(gst_v4l2_get_output), (gst_v4l2_set_output),
+	(gst_v4l2_get_frequency), (gst_v4l2_set_frequency),
+	(gst_v4l2_signal_strength), (gst_v4l2_get_attribute),
+	(gst_v4l2_set_attribute):
+	* sys/v4l2/v4l2_calls.h:
+	* sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list),
+	(gst_v4l2src_queue_frame), (gst_v4l2src_grab_frame),
+	(gst_v4l2src_get_capture), (gst_v4l2src_set_capture),
+	(gst_v4l2src_capture_init), (gst_v4l2src_capture_start),
+	(gst_v4l2src_capture_stop):
+	* sys/vcd/vcdsrc.c: (vcdsrc_open_file):
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xcontext_get),
+	(gst_ximagesink_chain):
+	* sys/xvideo/xvideosink.c: (gst_xvideosink_buffer_new),
+	(gst_xvideosink_sinkconnect), (gst_xvideosink_chain),
+	(gst_xvideosink_xwindow_new):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xcontext_get),
+	(gst_xvimagesink_chain):
+
+2004-02-02  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/volume/gstvolume.c: (gst_volume_set_volume),
+	(gst_volume_get_volume), (volume_class_init), (volume_init),
+	(volume_chain_int16), (volume_update_volume):
+	* gst/volume/gstvolume.h:
+          make code more readable by removing magic numbers
+          make mixer interface export 0-100 range
+          make it internally map to 0.0-1.0 range so users don't distort
+          output by putting the sliders at full volume
+
+2004-02-02  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/play/play.c: (gst_play_tick_callback),
+	(gst_play_state_change), (gst_play_seek_to_time):
+        block the tick callback for 0.5 secs after doing a seek
+
+2004-02-02  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/play/play.c: (gst_play_new):
+          check for GError
+
+2004-02-01  Julien MOUTTE  <julien@moutte.net>
+
+	* gst-libs/gst/play/play.c: (gst_play_seek_to_time),
+	(gst_play_new): Accepting NULL GError, blocking time tick while seeking.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_sink_link),
+	(gst_ximagesink_chain), (gst_ximagesink_init): s/sinkconnect/sink_link
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_sink_link),
+	(gst_xvimagesink_chain), (gst_xvimagesink_init): s/sinkconnect/sink_link
+
+2004-02-01  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* configure.ac:
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_event):
+          check for a function added in vorbis 1.1
+
+2004-01-31  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_change_state), (gst_alsa_start),
+	(gst_alsa_drain_audio), (gst_alsa_stop_audio):
+	  really start/stop clock only on PLAYING <=> PAUSED
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_loop):
+	  remove \n from debugging lines
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_chain):
+	  make it work when seeking does not
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_event):
+	  reset on DISCONT
+
+2004-01-31  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_change_state), (gst_alsa_start):
+	  start clock on PAUSED=>PLAYING, not later
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event):
+	  extract correct time for different discont formats
+	(gst_alsa_sink_get_time):
+	  don't segfault when no format is negotiated yet, just return 0
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_src_event),
+	(gst_ogg_demux_handle_event), (gst_ogg_demux_push),
+	(gst_ogg_pad_push):
+	  handle flush and discont events correctly
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_event), (vorbis_dec_chain):
+	  handle discont events correctly
+
+2004-01-31  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/play/play.c: (gst_play_error_quark),
+	(gst_play_error_create), (gst_play_error_plugin),
+	(gst_play_pipeline_setup), (gst_play_init), (gst_play_new):
+	* gst-libs/gst/play/play.h:
+          add error handling during creation
+	* examples/gstplay/player.c: (main):
+          use new gst_play_new
+
+
+2004-01-31  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/theora/theoradec.c: (theora_dec_chain):
+	  make comments work
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_src_query),
+	(vorbis_dec_src_event), (vorbis_dec_chain):
+	  add encoder tag, fix tag reading to be more error tolerant, change
+	  BITRATE to NOMINAL_BITRATE, add debugging, don't unref events after
+	  gst_pad_event_default.
+	* gst/tags/gstvorbistag.c:
+	(gst_tag_list_from_vorbiscomment_buffer):
+	  undefine function specific define at end of function
+
+2004-01-31  Jeremy Simon  <jesimon@libertysurf.fr>
+
+	* ext/flac/gstflac.c: (plugin_init):
+	* ext/flac/gstflacdec.c: (gst_flacdec_class_init):
+	* ext/flac/gstflacdec.h:
+	* ext/flac/gstflacenc.h:
+	  Fix typos
+
+2004-01-30  David I. Lehn  <dlehn@users.sourceforge.net>
+
+	* examples/gstplay/player.c: s/gstplay.h/play.h/
+
+2004-01-30  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/play/Makefile.am:
+	* gst-libs/gst/play/gstplay.c:
+	* gst-libs/gst/play/gstplay.h:
+	* gst-libs/gst/play/play.c:
+          more surgery, operation complete
+
+2004-01-30  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/play/play.old.c:
+	* gst-libs/gst/play/play.old.h:
+          after CVS surgery by moving, remove
+	* gst-libs/gst/play/playpipelines.c:
+          remove
+
+	* gst/intfloat/float22int.c: (gst_float2_2_int_chain):
+          add negotiation error
+
+2004-01-30  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_src_event),
+	(gst_ogg_demux_push):
+          add some seeking debug info
+          send a flush when seeking
+
+2004-01-30  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* configure.ac:
+	  use AC_C_INLINE
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/theora/Makefile.am:
+	* ext/theora/theoradec.c:
+	  add theora video decoder. Does just do simple decoding for now and
+	  has been tested against Theora cvs only. It only works when theora
+	  is compiled with --enable-static.
+	* ext/vorbis/vorbisdec.c: (vorbis_dec_event):
+	  always reset packetno on DISCONT
+
+2004-01-30  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_parse_syshead):
+	  Fix audio.
+
+2004-01-30  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/mpegaudioparse/gstmpegaudioparse.c:
+	(mp3_type_frame_length_from_header):
+	  Fix header parsing - stolen from ffmpeg (thank you! :) ).
+
+2004-01-30  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/esd/esdsink.c: (gst_esdsink_init):
+	  Since we have static pad template caps, we don't need to negotiate;
+	  either the core errors out or we know the format.
+
+2004-01-30  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_peek_head),
+	(gst_riff_read_seek):
+	* gst/matroska/ebml-read.c: (gst_ebml_read_element_id),
+	(gst_ebml_read_seek):
+	  Fix event handling.
+
+2004-01-30  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/ffmpeg/gstffmpegcodecmap.c: (gst_ffmpeg_codecid_to_caps):
+	  removee video/x-theora from vp3 decoder, it doesn't handle raw
+	  theora streams
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_init):
+	  fix bug with finalizing element that never went to PAUSED
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_src_query):
+	  length and position queries were swapped
+	* ext/vorbis/vorbisdec.c: (gst_vorbis_dec_init),
+	(vorbis_dec_from_granulepos), (vorbis_dec_src_query),
+	(vorbis_dec_src_event):
+	  implement querying time and bytes
+
+2004-01-30  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+        * just about every source file:
+          gst_element_error -> GST_ELEMENT_ERROR
+
+2004-01-29  Julien MOUTTE  <julien@moutte.net>
+
+	* ext/gnomevfs/gstgnomevfssrc.c: (gst_gnomevfssrc_get): Fixing seeking
+	emiting FLUSH and even before DISCONT.
+	* gst-libs/gst/play/gstplay.c: (gst_play_seek_to_time): Fix seeking to
+	get the best instant seeking as possible yay!
+
+2004-01-29  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/mpeg1videoparse/gstmp1videoparse.c:
+	(gst_mp1videoparse_real_chain):
+	  Committed wrong version last week... Grr... Didn't notice until now.
+
+2004-01-29  Julien MOUTTE <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xwindow_new):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xwindow_new): Emit the
+	have_xwindow_id signal in xwindow_create.
+
+2004-01-29  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/ogg/gstoggdemux.c:
+	  lots of changes - mainly support for chained bitstreams, seeking,
+	  querying and bugfixes of course
+	* ext/vorbis/Makefile.am:
+	* ext/vorbis/vorbisdec.c:
+	* ext/vorbis/vorbisdec.h:
+	  add vorbisdec raw vorbis decoder
+	* ext/vorbis/vorbis.c: (plugin_init):
+	  register vorbisdec as PRIMARY, vorbisfile as SECONDARY
+	* gst/intfloat/Makefile.am:
+	* gst/intfloat/float22int.c:
+	* gst/intfloat/float22int.h:
+	* gst/intfloat/gstintfloatconvert.c: (plugin_init):
+	  add float2intnew plugin. It converts multichannel interleaved float to
+	  multichannel interleaved int. The name should probably be changed.
+	* gst/typefind/gsttypefindfunctions.c: (theora_type_find),
+	(plugin_init):
+	  add typefinding for raw theora video so oggdemux can detect it.
+
+2004-01-28  Julien MOUTTE  <julien@moutte.net>
+
+	* gst-libs/gst/play/gstplay.c: (gst_play_seek_to_time): seek on video
+	sink element first.
+	* gst/videoscale/gstvideoscale.c:
+	(gst_videoscale_handle_src_event): Fixing src event handler.
+
+2004-01-28  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_class_init), (gst_v4lsrc_init),
+	(gst_v4lsrc_open), (gst_v4lsrc_close),
+	(gst_v4lsrc_palette_to_caps), (gst_v4lsrc_srcconnect),
+	(gst_v4lsrc_getcaps), (gst_v4lsrc_set_clock):
+	* sys/v4l/gstv4lsrc.h:
+	* sys/v4l/v4lsrc_calls.c: (gst_v4lsrc_capture_start),
+	(gst_v4lsrc_grab_frame), (gst_v4lsrc_capture_stop):
+	  Implement resizing... Hack. But that's why v4l is b0rked...
+
+2004-01-28  Julien MOUTTE <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_check_xshm_calls),
+	(gst_ximagesink_ximage_new), (gst_ximagesink_ximage_destroy),
+	(gst_ximagesink_ximage_put), (gst_ximagesink_xwindow_new),
+	(gst_ximagesink_xwindow_destroy):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_check_xshm_calls),
+	(gst_xvimagesink_xvimage_new), (gst_xvimagesink_xvimage_destroy),
+	(gst_xvimagesink_xwindow_new), (gst_xvimagesink_xwindow_destroy),
+	(gst_xvimagesink_xwindow_resize), (gst_xvimagesink_get_xv_support),
+	(gst_xvimagesink_xcontext_get): Removing some useless debugs messages,
+	correctly cleaning the image created to check xshm calls on succes,
+	added a lot of XSync calls in X11 functions, and fixed a segfault when
+	no image format was defined before negotiation happened.
+
+2004-01-28  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_query_func):
+	  use gst_element_get_time to get correct time
+
+2004-01-28  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_handle_xerror),
+	(gst_ximagesink_check_xshm_calls), (gst_ximagesink_ximage_destroy),
+	(gst_ximagesink_xcontext_get), (gst_ximagesink_class_init):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_handle_xerror),
+	(gst_xvimagesink_check_xshm_calls),
+	(gst_xvimagesink_xvimage_destroy), (gst_xvimagesink_xcontext_get): Our
+	X plugins are now able to detect that XShm calls will fail even if the
+	server claims that it has XShm support (remote displays most of the
+	time). We then log the error as a GST_DEBUG and set use_shm to FALSE
+	so that we use non XShm functions. This feature is almost useless for
+	xvimagesink as Xv is not supported on remote displays anyway, but
+	it might happen than even on the local display XShm calls fail.
+
+2004-01-27  David Schleef  <ds@schleef.org>
+
+	* ext/esd/esdsink.c: (gst_esdsink_class_init), (gst_esdsink_init),
+	(gst_esdsink_link), (gst_esdsink_get_time), (gst_esdsink_chain),
+	(gst_esdsink_change_state):  Fix sync issues in esdsink.  Also
+	changed esdsink to only use 44100,16,2, since esd sucks at rate
+	conversion and esdsink has had difficulty negotiating.
+
+2004-01-27  Julien MOUTTE <julien@moutte.net>
+
+	* gst-libs/gst/play/gstplay.c: (gst_play_tick_callback),
+	(gst_play_seek_to_time): Fixing the way to get current position.
+
+2004-01-27  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* sys/oss/gstosssink.c: (gst_osssink_sink_query):
+	  use gst_element_get_time to get correct time
+
+2004-01-27  Julien MOUTTE <julien@moutte.net>
+
+	* gst-libs/gst/play/gstplay.c: (gst_play_set_location): The easiest
+	fix ever... Inverting 2 lines of code make spider autoplug correctly
+	tagged mp3 !
+
+2004-01-27  David Schleef  <ds@schleef.org>
+
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_link):
+	Use gst_pad_try_set_caps_nonfixed().
+
+2004-01-27  David Schleef  <ds@schleef.org>
+
+	* gst/ac3parse/gstac3parse.c: update to checklist 5
+	* gst/adder/gstadder.c: rewrite negotiation.  update to checklist 5
+	* gst/audioconvert/gstaudioconvert.c: update to checklist 5
+	* gst/audioscale/gstaudioscale.c: same
+	* gst/auparse/gstauparse.c: same
+	* gst/avi/gstavidemux.c: same
+
+2004-01-27  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_handle_sink_event):
+	  stop processing after EOS
+
+2004-01-27  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/asfdemux/asfheaders.h:
+	* gst/asfdemux/gstasfdemux.c:
+	* gst/asfdemux/gstasfmux.c: (gst_asfmux_put_guid),
+	(gst_asfmux_put_string), (gst_asfmux_put_wav_header),
+	(gst_asfmux_put_vid_header), (gst_asfmux_put_bmp_header):
+	  lot's of fixes to make data extraction simpler and get the code
+	  architecture and compiler independant. Add debugging category
+	* gst/goom/gstgoom.c: (gst_goom_change_state):
+	  reset channel count on PAUSED=>READY, not READY=>PAUSED
+
+2004-01-26  Colin Walters  <walters@verbum.org>
+
+	* ext/gnomevfs/gstgnomevfssrc.c (gst_gnomevfssrc_get): Remove ugly
+	code to pull a bigger buffer in iradio mode.  This as a side effect
+	makes typefinding work.
+
+2004-01-26  Jeremy Simon  <jesimon@libertysurf.fr>
+
+	* ext/ffmpeg/gstffmpegcodecmap.c: (gst_ffmpeg_caps_to_extradata):
+	Fix SVQ3 decoding on PPC
+
+2004-01-26  Julien MOUTTE <julien@moutte.net>
+
+	* gst/videoscale/gstvideoscale.c: (gst_videoscale_chain): Dunno how
+	that one managed to stay there... Fixed.
+
+2004-01-26  Jeremy Simon  <jesimon@libertysurf.fr>
+
+	* ext/ffmpeg/gstffmpegcodecmap.c: (gst_ffmpeg_codecid_to_caps),
+	(gst_ffmpeg_caps_to_extradata), (gst_ffmpeg_caps_to_pixfmt):
+	* gst/qtdemux/qtdemux.c: (plugin_init), (qtdemux_parse_trak),
+	(qtdemux_video_caps):
+	* gst/qtdemux/qtdemux.h:
+	Add SVQ3 specific flags to qtdemux and ffmpeg
+
+2004-01-26  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst-libs/gst/audio/audio.h:
+	  remove buffer-frames from audio caps
+	* gst/audioconvert/gstaudioconvert.c:
+	  fix plugin to really work.
+
+2004-01-25  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/mixer/mixer.c:
+	* gst-libs/gst/propertyprobe/propertyprobe.c:
+	* gst-libs/gst/tuner/tuner.c: (gst_tuner_find_norm_by_name),
+	(gst_tuner_find_channel_by_name):
+	* gst-libs/gst/tuner/tuner.h:
+	  Add gtk-doc style comments. Also fix a function name.
+
+2004-01-25  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/divx/gstdivxdec.c: (gst_divxdec_init),
+	(gst_divxdec_negotiate):
+	  Fix for new capsnego - also fixes gst-player with divxdec.
+
+2004-01-25  Julien MOUTTE  <julien@moutte.net>
+
+	* gst-libs/gst/play/gstplay.c: (gst_play_pipeline_setup),
+	(gst_play_identity_handoff), (gst_play_set_location),
+	(gst_play_set_visualization), (gst_play_connect_visualization): Another
+	try in visualization implementation. Still have an issue with switch
+	blocking when pulling from video_queue and only audio comes out of
+	spider.
+	* gst/switch/gstswitch.c: (gst_switch_release_pad),
+	(gst_switch_poll_sinkpads), (gst_switch_class_init): Implementing pad
+	release method. And check if the pad is usable before pulling.
+
+2004-01-25  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/videofilter/gstvideobalance.c: (gst_videobalance_dispose),
+	(gst_videobalance_init),
+	(gst_videobalance_colorbalance_list_channels),
+	(gst_videobalance_colorbalance_set_value),
+	(gst_videobalance_colorbalance_get_value),
+	(gst_videobalance_update_properties),
+	(gst_videobalance_update_tables_planar411),
+	(gst_videobalance_planar411):
+	* gst/videofilter/gstvideobalance.h:
+	  Implement lookup-tables. +/- 10x faster.
+
+2004-01-25  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_stream_avih),
+	(gst_avi_demux_stream_odml), (gst_avi_demux_stream_index):
+	  The index reading was broken. The rest worked fine, but the whole
+	  goal of my rewrite was to make avidemux readable, and this was
+	  not at all readable. Please use typed variables.
+
+2004-01-25  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_read_info):
+	  Additional pad usability check.
+	* gst/mpeg1videoparse/gstmp1videoparse.c: (gst_mp1videoparse_init),
+	(mp1videoparse_find_next_gop), (gst_mp1videoparse_time_code),
+	(gst_mp1videoparse_real_chain):
+	  Fix MPEG video stream parsing. The original plugin had several
+	  issues, including not timestamping streams where the source was
+	  not timestamped (this happens with PTS values in mpeg system
+	  streams, but MPEG video is also a valid stream on its own so
+	  that needs timestamps too). We use the display time code for that
+	  for now. Also, if one incoming buffer contains multiple valid
+	  frames, we push them all on correctly now, including proper EOS
+	  handling. Lastly, several potential segfaults were fixed, and we
+	  properly sync on new sequence/gop headers to include them in next,
+	  not previous frames (since they're header for the next frame, not
+	  the previous). Also see #119206.
+	* gst/mpegaudioparse/gstmpegaudioparse.c: (gst_mp3parse_chain),
+	(bpf_from_header):
+	  Move caps setting so we only do it after finding several valid
+	  MPEG-1 fraes sequentially, not right after the first one (which
+	  might be coincidental).
+	* gst/typefind/gsttypefindfunctions.c: (mpeg1_sys_type_find),
+	(mpeg_video_type_find), (mpeg_video_stream_type_find),
+	(plugin_init):
+	  Add unsynced MPEG video stream typefinding, and change some
+	  probability values so we detect streams rightly. The idea is as
+	  follows: I can have an unsynced system stream which contains
+	  video. In the current code, I would randomly get a type for either
+	  system or video stream type found, because the probabilities are
+	  being calculated rather randomly. I now use fixed values, so we
+	  always prefer system stream if that was found (and that is how it
+	  should be). If no system stream was found, we can still identity		  the stream as video-only.
+
+2004-01-23  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/avi/gstavidemux.c: (gst_avi_demux_stream_avih),
+	(gst_avi_demux_stream_odml), (gst_avi_demux_stream_index):
+	  don't write to buffer. Extract data without the need of
+	  __attribute__ ((packed))
+
+2004-01-23  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/typefind/gsttypefindfunctions.c: (mpeg1_parse_header),
+	(mpeg1_sys_type_find):
+	  Fix MPEG-1 stream typefinding.
+
+2004-01-23  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/typefind/gsttypefindfunctions.c: (mpeg2_sys_type_find):
+	  Fix typefinding for MPEG-1 system streams, similar to MPEG-2.
+
+2004-01-23  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/esd/esdsink.c: (gst_esdsink_open_audio):
+	* ext/esd/gstesd.c: (plugin_init):
+          private debugging, better error reporting
+
+2004-01-23  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_read_class_init),
+	(gst_riff_read_init), (gst_riff_read_change_state):
+	* gst-libs/gst/riff/riff-read.h:
+	  Remove stuff fromold metadata system.
+
+2004-01-23  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ogg/gstoggdemux.c:
+	  Fix wrong file comment.
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_read_info):
+	* gst/avi/gstavidemux.c: (gst_avi_demux_stream_header):
+	  Add metadata reading properly.
+
+2004-01-23  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/Makefile.am:
+          Fix nas DIST_SUBDIRS
+          Uraeus:
+          Fix bug where make distcheck doesn't get run on adding stuff to
+          the build.
+
+2004-01-23  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/divx/gstdivxdec.c: (gst_divxdec_init), (gst_divxdec_setup):
+	* ext/divx/gstdivxdec.h:
+	  Fix divx3 ("msmpeg4") playback using divxdec.
+
+2004-01-23  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/typefind/gsttypefindfunctions.c:
+	(mp3_type_frame_length_from_header): fix bug in length computation
+	(mp3_type_find): improve debugging output
+
+2004-01-23  Julien MOUTTE  <julien@moutte.net>
+
+	* gst-libs/gst/play/gstplay.c: (gst_play_pipeline_setup),
+	(gst_play_set_location), (gst_play_seek_to_time),
+	(gst_play_set_audio_sink), (gst_play_set_visualization),
+	(gst_play_connect_visualization), (gst_play_get_sink_element): Reworked
+	the pipeline from scratch. Visualization is back and switch went out as
+	i realized it was not possible to use the way i wanted.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_imagepool_clear),
+	(gst_ximagesink_change_state), (gst_ximagesink_dispose): Move xcontext
+	clearing in state change from READY to NULL. So that one can clean the
+	X ressources keeping the element.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xcontext_get),
+	(gst_xvimagesink_imagepool_clear), (gst_xvimagesink_change_state),
+	(gst_xvimagesink_colorbalance_set_value),
+	(gst_xvimagesink_colorbalance_get_value),
+	(gst_xvimagesink_set_property), (gst_xvimagesink_dispose),
+	(gst_xvimagesink_init): Same xcontext cleaning than ximagesink in state
+	change from READY to NULL and fixed some stupid bugs in colorbalance
+	get/set values. Also added the following feature : when nobody tries to
+	set some values to the colorbalance levels before the xcontext is
+	grabbed, then when creating channels list from Xv attributes we set the
+	internal values to the Xv defaults. This way we handle buggy Xv drivers
+	that set default hue values far from the middle of the range (Thanks
+	to Jon Trowbridge for pointing that issue).
+	* sys/xvimage/xvimagesink.h: Adding a cb_changed boolean to know if
+	colorbalance levels have been set before xcontext is grabbed.
+
+2004-01-22  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/oss/gstosselement.c: (gst_osselement_class_probe_devices):
+	  Fix the ossmixer case where we shouldn't open /dev/dsp* because
+	  it might block operations (which is bad for a mixer).
+
+2004-01-22  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/media-info/media-info-priv.c: (have_type_callback),
+	(deep_notify_callback), (gmi_set_decoder), (gmi_clear_decoder),
+	(gmip_find_type_pre):
+	* gst-libs/gst/media-info/media-info-priv.h:
+	* gst-libs/gst/media-info/media-info.c:
+	(gst_media_info_instance_init), (gst_media_info_read_idler):
+        add fakesink to get caps on decoder src pad again
+        fix callback prototype to match new have_type signal signature
+
+2004-01-22  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/adder/gstadder.c: (gst_adder_link):
+          fix non-compile and cut-n-paste code
+
+2004-01-21  David Schleef  <ds@schleef.org>
+
+	* ext/swfdec/gstswfdec.c: (gst_swfdec_video_getcaps),
+	(gst_swfdec_video_link), (copy_image), (gst_swfdec_loop),
+	(gst_swfdec_init), (gst_swfdec_change_state):
+	* ext/swfdec/gstswfdec.h:
+	Fix negotiation.
+	* gst/adder/gstadder.c: (gst_adder_link), (gst_adder_init),
+	(gst_adder_request_new_pad): Fix negotiation.
+	* gst/goom/gstgoom.c: (gst_goom_init), (gst_goom_src_fixate):
+	Add a fixate function.
+	* gst/intfloat/gstfloat2int.c:
+	* gst/intfloat/gstfloat2int.h:
+	* gst/intfloat/gstint2float.c:
+	* gst/intfloat/gstint2float.h:
+	Completely rewrite the negotiation.  Doesn't quite work yet,
+	due to some buffer-frames problem.
+
+2004-01-21  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/gnomevfs/gstgnomevfssrc.c:
+	* sys/v4l2/v4l2_calls.h:
+          fix includes for distcheck
+
+2004-01-21  Christian Schaller <uraeus@gnome.org>
+
+	* ext/nas/
+	Add libnas (network audio system) plugin, patch from Arwed von Merkatz
+	based on earlier patch from Laurent Vivier
+
+2004-01-20  Jeremy Simon  <jesimon@libertysurf.fr>
+
+	* ext/ffmpeg/gstffmpegcodecmap.c: (gst_ffmpeg_caps_to_extradata):
+	Fix wma caps property
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_audio_caps):
+	Fix typo (flags1 and flags2)
+
+2004-01-20  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/media-info/media-info-priv.c:
+	(deep_notify_callback), (gmi_seek_to_track), (gmi_get_decoder),
+	(gmip_find_type_pre), (gmip_find_type), (gmip_find_stream_post),
+	(gmip_find_stream), (gmip_find_track_metadata),
+	(gmip_find_track_streaminfo_post), (gmip_find_track_streaminfo),
+	(gmip_find_track_format):
+	* gst-libs/gst/media-info/media-info-priv.h:
+	* gst-libs/gst/media-info/media-info-test.c: (main):
+	* gst-libs/gst/media-info/media-info.c: (gst_media_info_init),
+	(gst_media_info_read_idler), (gst_media_info_read):
+	* gst-libs/gst/media-info/media-info.h:
+          register debugging category and use it for debugging
+
+2004-01-20  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/vorbis/vorbisfile.c: (gst_vorbisfile_update_streaminfo),
+	(gst_vorbisfile_new_link):
+          signal streaminfo through tags
+
+2004-01-20  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mplex/gstmplex.cc:
+	* ext/mplex/gstmplexibitstream.cc:
+	  g++ doesn't like NULL in our i18n/error macros, should be
+	  either (NULL) or ("").
+
+2004-01-20  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/dxr3/dxr3audiosink.c:
+	* sys/dxr3/dxr3init.c:
+	* sys/dxr3/dxr3spusink.c: (dxr3spusink_close):
+	* sys/dxr3/dxr3videosink.c: (dxr3videosink_close):
+	  Fix more error error error errors (missing includes here).
+
+2004-01-20  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mpeg2enc/gstmpeg2encpicturereader.cc:
+	  fix thomas' error errors.
+
+2004-01-20  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/mpeg2enc/gstmpeg2enc.cc:
+          fix error errors.
+
+2004-01-20  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/divx/gstdivxdec.c: (gst_divxdec_setup), (gst_divxdec_chain):
+	* ext/divx/gstdivxenc.c: (gst_divxenc_setup), (gst_divxenc_chain):
+	  Fix for new error system.
+
+2004-01-20  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/divx/gstdivxenc.c: (gst_divxenc_setup), (gst_divxenc_chain):
+          fix for new error reporting
+
+2004-01-20  David Schleef  <ds@schleef.org>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_handle_xevents),
+	(gst_ximagesink_xcontext_get), (gst_ximagesink_getcaps),
+	(gst_ximagesink_set_xwindow_id): Change to using a framerate
+	of [1,100] instead of [0,MAX], since 0 isn't handled correctly,
+	and neither is 100+, most likely.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_xv_support),
+	(gst_xvimagesink_getcaps): same
+
+2004-01-19  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* configure.ac:
+	  Up version requirement to 2.0.3 (not yet released) to avoid symbol
+	  clashes with ffmpeg.
+
+2004-01-20  Julien MOUTTE  <julien@moutte.net>
+
+	* gst/switch/gstswitch.c: (gst_switch_request_new_pad),
+	(gst_switch_init): Fixed switch element : proxying link and setting
+	caps from src to sink on request.
+
+2004-01-19  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/v4l/v4l-overlay_calls.c: (gst_v4l_set_overlay):
+	* sys/v4l2/v4l2-overlay_calls.c: (gst_v4l2_set_display),
+	(gst_v4l2_set_window), (gst_v4l2_enable_overlay):
+        fix element_error
+
+2004-01-19  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/v4l/v4l_calls.h:
+	* sys/v4l2/v4l2_calls.h:
+          element_error fixes
+
+2004-01-19  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/gst-i18n-plugin.h:
+          add locale.h
+          remove config.h inclusion
+
+2004-01-19  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* autogen.sh:
+          adding autopoint invocation
+	* Makefile.am:
+	* configure.ac:
+	* gst-libs/gst/gettext.h:
+          adding gettext bits
+	* ext/audiofile/gstafsink.c: (gst_afsink_plugin_init):
+	* ext/audiofile/gstafsrc.c: (gst_afsrc_plugin_init):
+	* ext/gnomevfs/gstgnomevfs.c: (plugin_init):
+	* ext/gnomevfs/gstgnomevfssink.c: (gst_gnomevfssink_open_file),
+	(gst_gnomevfssink_close_file):
+	* ext/gnomevfs/gstgnomevfssrc.c: (gst_gnomevfssrc_open_file):
+	* ext/sndfile/gstsf.c: (gst_sf_loop), (plugin_init):
+	* gst-libs/gst/gst-i18n-plugin.h:
+	* gst/avi/gstavi.c: (plugin_init):
+	* sys/dxr3/dxr3init.c: (plugin_init):
+	* sys/dxr3/dxr3videosink.c: (dxr3videosink_write_data):
+	* sys/oss/gstossaudio.c: (plugin_init):
+	* sys/oss/gstosselement.c: (gst_osselement_open_audio):
+	* sys/v4l/gstv4l.c: (plugin_init):
+	* sys/v4l/v4l_calls.c: (gst_v4l_open):
+	* sys/v4l2/gstv4l2.c: (plugin_init):
+	* sys/v4l2/v4l2_calls.c: (gst_v4l2_get_capabilities),
+	(gst_v4l2_fill_lists), (gst_v4l2_get_norm), (gst_v4l2_set_norm),
+	(gst_v4l2_get_input), (gst_v4l2_set_input), (gst_v4l2_get_output),
+	(gst_v4l2_set_output), (gst_v4l2_get_frequency),
+	(gst_v4l2_set_frequency), (gst_v4l2_signal_strength),
+	(gst_v4l2_get_attribute), (gst_v4l2_set_attribute):
+	  make sure locale and translation domain are set
+          fix translated strings
+	* po/.cvsignore:
+	* po/LINGUAS:
+	* po/Makevars:
+	* po/POTFILES.in:
+	* po/nl.po:
+          put translation files into place
+	* sys/xvideo/imagetest.c: (main):
+	* ext/dv/demo-play.c: (main):
+          fix unnecessary translations
+
+2004-01-19  Thomas Vander Stichele  <thomas (at) apestaart (dot) org>
+
+	* ext/sndfile/gstsf.c:
+	* gst/avi/gstavimux.c:
+	* ext/audiofile/gstafsink.c:
+	* ext/audiofile/gstafsrc.c:
+	* ext/gnomevfs/gstgnomevfssink.c:
+	* ext/gnomevfs/gstgnomevfssrc.c:
+	* sys/oss/gstosselement.c:
+	* sys/v4l/v4l_calls.h:
+          fix i18n include
+
+2004-01-19  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/v4l2/v4l2_calls.c: (gst_v4l2_get_capabilities),
+	(gst_v4l2_fill_lists), (gst_v4l2_open), (gst_v4l2_get_norm),
+	(gst_v4l2_set_norm), (gst_v4l2_get_input), (gst_v4l2_set_input),
+	(gst_v4l2_get_output), (gst_v4l2_set_output),
+	(gst_v4l2_get_frequency), (gst_v4l2_set_frequency),
+	(gst_v4l2_signal_strength), (gst_v4l2_get_attribute),
+	(gst_v4l2_set_attribute):
+        update to new error handling
+
+2004-01-19  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ext/sidplay/gstsiddec.cc:
+	* gst/modplug/gstmodplug.cc:
+          parenthese NULL because C++ seems angry about it
+
+2004-01-19  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/gst-i18n-plugin.h:
+          add skeleton i18n stuff, but needs to be further implemented
+
+2004-01-18  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* examples/gstplay/player.c: (main):
+	* ext/aalib/gstaasink.c: (gst_aasink_open):
+	* ext/alsa/gstalsa.c: (gst_alsa_link), (gst_alsa_xrun_recovery):
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_loop):
+	* ext/alsa/gstalsasrc.c: (gst_alsa_src_loop):
+	* ext/audiofile/gstafsink.c: (gst_afsink_open_file),
+	(gst_afsink_close_file):
+	* ext/audiofile/gstafsrc.c: (gst_afsrc_open_file),
+	(gst_afsrc_close_file):
+	* ext/divx/gstdivxdec.c: (gst_divxdec_setup), (gst_divxdec_chain):
+	* ext/dv/gstdvdec.c: (gst_dvdec_loop):
+	* ext/dvdnav/dvdnavsrc.c: (dvdnavsrc_user_op), (dvdnavsrc_get):
+	* ext/esd/esdmon.c: (gst_esdmon_get):
+	* ext/esd/esdsink.c: (gst_esdsink_chain):
+	* ext/faac/gstfaac.c: (gst_faac_chain):
+	* ext/faad/gstfaad.c: (gst_faad_chain):
+	* ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_chain):
+	* ext/ffmpeg/gstffmpegdemux.c: (gst_ffmpegdemux_loop):
+	* ext/ffmpeg/gstffmpegmux.c: (gst_ffmpegmux_loop):
+	* ext/flac/gstflacdec.c: (gst_flacdec_error_callback),
+	(gst_flacdec_loop):
+	* ext/flac/gstflacenc.c: (gst_flacenc_chain):
+	* ext/flac/gstflactag.c: (gst_flac_tag_chain):
+	* ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_chain):
+	* ext/gnomevfs/gstgnomevfssink.c: (gst_gnomevfssink_open_file),
+	(gst_gnomevfssink_close_file):
+	* ext/gnomevfs/gstgnomevfssrc.c: (audiocast_init),
+	(gst_gnomevfssrc_open_file):
+	* ext/ivorbis/vorbisfile.c: (gst_ivorbisfile_loop):
+	* ext/lame/gstlame.c: (gst_lame_sink_link), (gst_lame_chain):
+	* ext/lcs/gstcolorspace.c: (gst_colorspace_srcconnect_func):
+	* ext/mad/gstid3tag.c: (gst_id3_tag_handle_event),
+	(gst_id3_tag_do_typefind), (gst_id3_tag_chain):
+	* ext/mad/gstmad.c: (gst_mad_chain):
+	* ext/mikmod/gstmikmod.c: (gst_mikmod_loop):
+	* ext/mpeg2dec/gstmpeg2dec.c:
+	* ext/mpeg2enc/gstmpeg2enc.cc:
+	* ext/mpeg2enc/gstmpeg2encpicturereader.cc:
+	* ext/mplex/gstmplex.cc:
+	* ext/mplex/gstmplexibitstream.cc:
+	* ext/ogg/gstoggdemux.c: (gst_ogg_demux_chain),
+	(gst_ogg_demux_push), (gst_ogg_pad_push):
+	* ext/raw1394/gstdv1394src.c:
+	* ext/sdl/sdlvideosink.c: (gst_sdlvideosink_lock),
+	(gst_sdlvideosink_initsdl), (gst_sdlvideosink_create):
+	* ext/sidplay/gstsiddec.cc:
+	* ext/sndfile/gstsf.c: (gst_sf_open_file), (gst_sf_close_file),
+	(gst_sf_loop):
+	* ext/speex/gstspeexenc.c: (gst_speexenc_chain):
+	* ext/tarkin/gsttarkindec.c: (gst_tarkindec_chain):
+	* ext/tarkin/gsttarkinenc.c: (gst_tarkinenc_chain):
+	* ext/vorbis/vorbisenc.c: (gst_vorbisenc_chain):
+	* ext/vorbis/vorbisfile.c: (gst_vorbisfile_loop):
+	* ext/xvid/gstxviddec.c: (gst_xviddec_setup), (gst_xviddec_chain):
+	* ext/xvid/gstxvidenc.c: (gst_xvidenc_setup), (gst_xvidenc_chain):
+	* gst-libs/gst/Makefile.am:
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_peek_head),
+	(gst_riff_read_element_data), (gst_riff_read_seek),
+	(gst_riff_peek_list), (gst_riff_read_list), (gst_riff_read_header):
+	* gst/adder/gstadder.c: (gst_adder_parse_caps), (gst_adder_loop):
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_process_segment),
+	(gst_asf_demux_process_stream), (gst_asf_demux_get_stream):
+	* gst/avi/gstavidemux.c: (gst_avi_demux_stream_init),
+	(gst_avi_demux_add_stream), (gst_avi_demux_stream_header):
+	* gst/avi/gstavimux.c: (gst_avimux_stop_file):
+	* gst/flx/gstflxdec.c: (gst_flxdec_loop):
+	* gst/goom/gstgoom.c: (gst_goom_chain):
+	* gst/id3/gstid3types.c: (gst_id3types_loop):
+	* gst/intfloat/gstfloat2int.c: (gst_float2int_loop):
+	* gst/intfloat/gstint2float.c: (gst_int2float_chain_gint16):
+	* gst/matroska/ebml-read.c: (gst_ebml_read_element_id),
+	(gst_ebml_read_element_length), (gst_ebml_read_element_data),
+	(gst_ebml_read_seek), (gst_ebml_read_uint), (gst_ebml_read_sint),
+	(gst_ebml_read_float), (gst_ebml_read_header):
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_init_stream),
+	(gst_matroska_demux_parse_blockgroup):
+	* gst/modplug/gstmodplug.cc:
+	* gst/monoscope/gstmonoscope.c: (gst_monoscope_chain):
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_loop):
+	* gst/oneton/gstoneton.c: (gst_oneton_chain):
+	* gst/silence/gstsilence.c: (gst_silence_get):
+	* gst/sine/gstsinesrc.c: (gst_sinesrc_get):
+	* gst/smpte/gstsmpte.c: (gst_smpte_loop):
+	* gst/speed/gstspeed.c: (speed_loop):
+	* gst/tags/gstvorbistag.c: (gst_vorbis_tag_chain):
+	* gst/videotestsrc/gstvideotestsrc.c: (gst_videotestsrc_get):
+	* gst/volenv/gstvolenv.c: (gst_volenv_chain):
+	* gst/wavenc/gstwavenc.c: (gst_wavenc_chain):
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_parse_fmt),
+	(gst_wavparse_loop):
+	* sys/dxr3/dxr3audiosink.c: (dxr3audiosink_open),
+	(dxr3audiosink_set_mode_pcm), (dxr3audiosink_set_mode_ac3),
+	(dxr3audiosink_close):
+	* sys/dxr3/dxr3spusink.c: (dxr3spusink_open), (dxr3spusink_close):
+	* sys/dxr3/dxr3videosink.c: (dxr3videosink_open),
+	(dxr3videosink_close), (dxr3videosink_write_data):
+	* sys/oss/gstosselement.c: (gst_osselement_open_audio):
+	* sys/oss/gstosselement.h:
+	* sys/oss/gstosssink.c: (gst_osssink_get_type), (gst_osssink_init),
+	(gst_osssink_chain):
+	* sys/oss/gstosssrc.c: (gst_osssrc_get):
+	* sys/v4l/gstv4lmjpegsink.c: (gst_v4lmjpegsink_chain):
+	* sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_buffer_free):
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_buffer_free):
+	* sys/v4l/v4l-overlay_calls.c: (gst_v4l_set_window),
+	(gst_v4l_enable_overlay):
+	* sys/v4l/v4l_calls.c: (gst_v4l_get_capabilities), (gst_v4l_open),
+	(gst_v4l_set_chan_norm), (gst_v4l_get_signal),
+	(gst_v4l_get_frequency), (gst_v4l_set_frequency),
+	(gst_v4l_get_picture), (gst_v4l_set_picture), (gst_v4l_get_audio),
+	(gst_v4l_set_audio):
+	* sys/v4l/v4l_calls.h:
+	* sys/v4l/v4lmjpegsink_calls.c: (gst_v4lmjpegsink_sync_thread),
+	(gst_v4lmjpegsink_queue_frame), (gst_v4lmjpegsink_set_playback),
+	(gst_v4lmjpegsink_playback_init),
+	(gst_v4lmjpegsink_playback_start):
+	* sys/v4l/v4lmjpegsrc_calls.c: (gst_v4lmjpegsrc_queue_frame),
+	(gst_v4lmjpegsrc_sync_next_frame), (gst_v4lmjpegsrc_set_capture),
+	(gst_v4lmjpegsrc_set_capture_m), (gst_v4lmjpegsrc_capture_init),
+	(gst_v4lmjpegsrc_requeue_frame):
+	* sys/v4l/v4lsrc_calls.c: (gst_v4lsrc_queue_frame),
+	(gst_v4lsrc_sync_frame), (gst_v4lsrc_capture_init),
+	(gst_v4lsrc_requeue_frame), (gst_v4lsrc_try_palette):
+	* sys/v4l2/gstv4l2src.c: (gst_v4l2src_get):
+	* sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list),
+	(gst_v4l2src_queue_frame), (gst_v4l2src_grab_frame),
+	(gst_v4l2src_get_capture), (gst_v4l2src_set_capture),
+	(gst_v4l2src_capture_init), (gst_v4l2src_capture_start),
+	(gst_v4l2src_capture_stop):
+	* sys/vcd/vcdsrc.c: (vcdsrc_open_file):
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xcontext_get),
+	(gst_ximagesink_chain):
+	* sys/xvideo/xvideosink.c: (gst_xvideosink_buffer_new),
+	(gst_xvideosink_sinkconnect), (gst_xvideosink_chain),
+	(gst_xvideosink_xwindow_new):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xcontext_get),
+	(gst_xvimagesink_chain):
+        use new error signal, function and categories
+
+2004-01-18  Jeremy Simon <jesimon@libertysurf.fr>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/musicbrainz/gsttrm.c:
+	* ext/musicbrainz/gsttrm.h:
+	* ext/musicbrainz/Makefile.am:
+	Add a trm plugin
+
+2004-01-18  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_set_property),
+	(gst_ximagesink_get_property), (gst_ximagesink_class_init): Adding
+	synchronous property for debugging.
+	* sys/ximage/ximagesink.h: Adding the synchronous boolean flag.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xcontext_get),
+	(gst_xvimagesink_set_property): Moving a pointer declaration to a
+	smaller block, fixing indent.
+
+2004-01-16  David Schleef  <ds@schleef.org>
+
+	* gst/videofilter/gstvideobalance.c: Fix regression; changing a
+	property affects the video stream.
+	* sys/xvimage/xvimagesink.c:
+	* sys/xvimage/xvimagesink.h:
+	Add synchronous property for debugging.  Should probably be
+	disabled in non-CVS builds.  Make sure that the Xv attribute
+	exists before we set it (crash!).  Fix a silly float bug that
+	caused colorbalance to just not work.
+
+2004-01-17  Christian Schaller <Uraeus@gnome.org>
+
+	* tools/gst-launch-ext.in - update for new plugins
+
+2004-01-16  David Schleef  <ds@schleef.org>
+
+	* ext/ffmpeg/gstffmpegenc.c: (gst_ffmpegenc_connect): Fix use of
+	already-freed caps.
+
+2994-01-16  Christian Schaller <Uraeus@gnome.org>
+
+	* Update spec for new colorspace plugin and libcaca plugin
+	* Fix compilation of libcaca plugin (clock -> id)
+
+2004-01-16  Julien MOUTTE <julien@moutte.net>
+
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_update_colorbalance),
+	(gst_xvimagesink_xcontext_get), (gst_xvimagesink_change_state),
+	(gst_xvimagesink_set_xwindow_id),
+	(gst_xvimagesink_colorbalance_set_value),
+	(gst_xvimagesink_colorbalance_get_value),
+	(gst_xvimagesink_set_property), (gst_xvimagesink_get_property),
+	(gst_xvimagesink_init), (gst_xvimagesink_class_init): Implementing
+	correct colorbalance properties. They can now be set when the element
+	is still in NULL state. The values will be committed to the Xv Port
+	when xcontext is initialized.
+	* sys/xvimage/xvimagesink.h: Added hue, saturation, contrast,
+	brightness int values in the GstXvImagesink structure.
+
+2004-01-16  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst-libs/gst/Makefile.am:
+	  restructure so having local patches works easier.
+
+2004-01-16  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mpeg2enc/Makefile.am:
+	* ext/mpeg2enc/gstmpeg2enc.cc:
+	* ext/mpeg2enc/gstmpeg2encpicturereader.cc:
+	  Bugfix with respect to EOS handling.
+
+2004-01-16  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ffmpeg/gstffmpegenc.c: (gst_ffmpegenc_connect):
+	  Link with right caps (else, it segfaults).
+	* ext/mplex/gstmplexjob.cc:
+	  Fix for slight API change in 1.6.1.93 release of mjpegtools.
+
+2004-01-15  David Schleef  <ds@schleef.org>
+
+	* gst-libs/gst/audio/Makefile.am:
+	Add gstaudiofiltertemplate.c and building of gstaudiofilterexample.c
+	from the template.
+	* gst-libs/gst/audio/gstaudiofilter.c:
+	* gst-libs/gst/audio/gstaudiofilter.h:
+	Add bytes_per_sample and size and n_samples calculation.
+	* gst-libs/gst/audio/gstaudiofilterexample.c:
+	Remove, now autogenerated.
+	* gst-libs/gst/audio/gstaudiofiltertemplate.c:
+	Moved from gstaudiofilterexample, object name changed, code added
+	so that it actually works.
+	* gst-libs/gst/audio/make_filter:
+	Script to build an audiofilter subclass from the template.
+	* gst/colorspace/Makefile.am:
+	* gst/colorspace/yuv2yuv.c:
+	Remove file, since it's GPL, and we don't use it.
+
+2004-01-15  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_chain):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_chain): Making both of
+	them use the buffer free function to test how the buffer was allocated.
+
+2004-01-15  David Schleef  <ds@schleef.org>
+
+	* ext/esd/esdsink.c: (gst_esdsink_class_init): Remove property
+	that handles osssink fallback.
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_init),
+	(gst_audio_convert_getcaps):
+	* gst/qtdemux/qtdemux.c: (qtdemux_audio_caps):
+	Add audio/x-qdm2 for QDM2 audio.
+	* gst/sine/gstsinesrc.c: (gst_sinesrc_get):
+	* gst/sine/gstsinesrc.h: Add example of how to implement tags.
+	* gst/videoscale/gstvideoscale.c: (gst_videoscale_getcaps):
+	Decrease minimum size to 16x16.
+	* gst/wavparse/gstwavparse.c:
+	Convert disabled pad template caps to new caps.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xcontext_get):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xcontext_get),
+	(gst_xvimagesink_chain): Throw element error when display cannot
+	be opened.  Increase minimum framerate to 1.0.  Check the data
+	free function on a buffer to make sure it is the type we expect
+	before manipulating it.
+
+2004-01-15  Julien MOUTTE <julien@moutte.net>
+
+	* gst/videofilter/gstvideobalance.c: (gst_videobalance_init),
+	(gst_videobalance_colorbalance_set_value): Implement passthru if
+	settings are in the middle.
+	* tools/gst-launch-ext.in: Stop using xvideosink, use ximagesink.
+
+2004-01-15  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/videofilter/Makefile.am:
+	* gst/volume/Makefile.am:
+	  Since we use videofilter symbols, link to it.
+
+2004-01-15  Julien MOUTTE <julien@moutte.net>
+
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_interface_init): Setting
+	mixer interface type to HARDWARE.
+	* gst-libs/gst/mixer/mixer.c: (gst_mixer_class_init): Adding a default
+	type to SOFTWARE.
+	* gst-libs/gst/mixer/mixer.h: Adding mixer interface type and macro.
+	* gst-libs/gst/mixer/mixertrack.h: Adding mixertrack flag SOFTWARE.
+	* gst/volume/gstvolume.c: (gst_volume_interface_supported),
+	(gst_volume_interface_init), (gst_volume_list_tracks),
+	(gst_volume_set_volume), (gst_volume_get_volume),
+	(gst_volume_set_mute), (gst_volume_mixer_init),
+	(gst_volume_dispose), (gst_volume_get_type), (volume_class_init),
+	(volume_init): Implementing mixer interface.
+	* gst/volume/gstvolume.h: Adding tracklist for mixer interface.
+	* sys/oss/gstosselement.c: (gst_osselement_get_type),
+	(gst_osselement_change_state): Removing some trailing commas in
+	structures.
+	* sys/oss/gstossmixer.c: (gst_ossmixer_interface_init): Setting mixer
+	interface type to HARDWARE.
+	* sys/v4l/gstv4lcolorbalance.c:
+	(gst_v4l_color_balance_interface_init): Setting colorbalance interface
+	type to HARDWARE.
+	* sys/v4l2/gstv4l2colorbalance.c:
+	(gst_v4l2_color_balance_interface_init): Setting colorbalance
+	interface type to HARDWARE.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_chain): use exactly the
+	same code than ximagesink for event handling.
+
+2004-01-15  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/snapshot/Makefile.am:
+	* ext/snapshot/gstsnapshot.c: (gst_snapshot_sinkconnect),
+	(gst_snapshot_chain):
+	* ext/snapshot/gstsnapshot.h:
+	  This has to be a joke... Snapshot should be connected to a tee,
+	  colorspace element before it and EOS after that, where the other
+	  src of the tee receives normal data.
+	  The current way is *wrong*.
+
+2004-01-15  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/hermes/gsthermescolorspace.c:
+	  Fix another compile error. Same as below.
+
+2004-01-15  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/colorspace/gstcolorspace.c:
+	* gst/colorspace/yuv2yuv.c: (gst_colorspace_yuy2_to_i420),
+	(gst_colorspace_i420_to_yv12):
+	  Fix compiling... Didn't test if it actually works.
+
+2004-01-15  David Schleef  <ds@schleef.org>
+
+	* configure.ac:
+	* gst/colorspace/Makefile.am:
+	* gst/colorspace/gstcolorspace.c:
+	* gst/colorspace/gstcolorspace.h:
+	* gst/colorspace/yuv2rgb.c:
+	* gst/colorspace/yuv2rgb.h:
+	Duplicate the ext/hermes colorspace plugin, and remove Hermes
+	code and GPL code.  Fix for new caps negotiation.  Rewrite
+	much of the format handling code, and some of the conversion
+	code.  Basically, rewrote almost everything.  This element
+	handles I420, YV12 to RGB conversions.
+	* ext/hermes/Makefile.am:
+	* ext/hermes/gsthermescolorspace.c:
+	Rename colorspace to hermescolorspace.  Fix negotiation issues.
+	Remove non-Hermes related code.  This element handles lots of
+	RGB to RGB conversions, but no YUV.
+	* ext/hermes/gstcolorspace.c:
+	* ext/hermes/gstcolorspace.h:
+	* ext/hermes/rgb2yuv.c:
+	* ext/hermes/yuv2rgb.c:
+	* ext/hermes/yuv2rgb.h:
+	* ext/hermes/yuv2rgb_mmx16.s:
+	* ext/hermes/yuv2yuv.c:
+	* ext/hermes/yuv2yuv.h:
+	Remove old code.
+
+2004-01-14  Colin Walters  <walters@verbum.org>
+
+	* ext/mad/gstid3tag.c (gst_id3_tag_chain): Don't nego caps if
+	they've already been.
+
+2004-01-15  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_do_caps_nego):
+	  assume tag mode when pad is not connected
+
+2004-01-15  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event):
+	  Don't update the time of the clock
+	(gst_alsa_sink_loop):
+	  sync to the clock given to alsasink, not the own clock
+	* sys/oss/gstosssink.c: (gst_osssink_chain):
+	  sync to the clock
+	(gst_osssink_change_state):
+	  activate the clock
+	* sys/ximage/ximagesink.c: (gst_ximagesink_chain):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_chain):
+	  remove bogus code that made DISCONT events unhandled
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_video_caps):
+	  explicitly case to double in _set_simple. (fixes 2nd warning in bug
+	  #131502)
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_read_object_header),
+	(gst_asf_demux_handle_sink_event), (gst_asf_demux_audio_caps),
+	(gst_asf_demux_add_audio_stream), (gst_asf_demux_video_caps):
+	  convert g_warning because of wrong asf data to GST_WARNINGs (fixes
+	  2nd warning in bug #131502)
+
+2004-01-14  Julien MOUTTE  <julien@moutte.net>
+
+	* gst/videofilter/gstvideobalance.c: (gst_videobalance_init),
+	(gst_videobalance_colorbalance_set_value),
+	(gst_videobalance_colorbalance_get_value): Fixing videobalance ranges
+	for colorbalance interface implementation.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xcontext_get),
+	(gst_ximagesink_set_property), (gst_ximagesink_get_property),
+	(gst_ximagesink_dispose), (gst_ximagesink_init),
+	(gst_ximagesink_class_init): Adding DISPLAY property.
+	* sys/ximage/ximagesink.h: Adding display_name to store display.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xcontext_get),
+	(gst_xvimagesink_set_property), (gst_xvimagesink_get_property),
+	(gst_xvimagesink_dispose), (gst_xvimagesink_init),
+	(gst_xvimagesink_class_init): Adding DISPLAY property and colorbalance
+	properties (they still need polishing though for gst-launch use : no
+	xcontext yet, i ll do that tomorrow).
+	* sys/xvimage/xvimagesink.h: Adding display_name to store display.
+
+2004-01-14  Julien MOUTTE  <julien@moutte.net>
+
+	* gst-libs/gst/play/gstplay.c: (gst_play_pipeline_setup),
+	(gst_play_set_location), (gst_play_set_visualization): Preparing
+	switch integration, adding videobalance in the pipeline.
+
+2004-01-14  Julien MOUTTE <julien@moutte.net>
+
+	* gst-libs/gst/colorbalance/colorbalance.c:
+	(gst_color_balance_class_init): Adding a default type.
+	* gst-libs/gst/colorbalance/colorbalance.h: Adding a macro to access
+	the type.
+	* gst/videofilter/gstvideobalance.c: (gst_videobalance_get_type),
+	(gst_videobalance_dispose), (gst_videobalance_class_init),
+	(gst_videobalance_init), (gst_videobalance_interface_supported),
+	(gst_videobalance_interface_init),
+	(gst_videobalance_colorbalance_list_channels),
+	(gst_videobalance_colorbalance_set_value),
+	(gst_videobalance_colorbalance_get_value),
+	(gst_videobalance_colorbalance_init): Implementing colorbalance
+	interface.
+	* gst/videofilter/gstvideobalance.h: Adding colorbalance channels
+	list.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_set_xwindow_id): Fixing a
+	bug which was triggering a BadAccess X error when setting an overlay
+	before pad was really negotiated.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_colorbalance_init):
+	Using the colorbalance type macro.
+
+2004-01-14  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/flac/gstflacenc.c: (gst_flacenc_set_metadata),
+	(gst_flacenc_chain):
+	  handle tags correctly
+	* gst/tags/gstid3tag.c: (gst_tag_list_new_from_id3v1):
+	  extract ID3v1 tags correctly
+
+2004-01-14  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/typefind/gsttypefindfunctions.c: (matroska_type_find),
+	(plugin_init):
+	  Improve matroska typefinding for odd-typed headers...
+
+2004-01-14  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream):
+	  Fix for using incremental number on padnames.
+
+2004-01-14  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/divx/gstdivxdec.c:
+	* ext/divx/gstdivxenc.c:
+	  Set category to divx4linux instead of divx (too generic).
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_init),
+	(gst_wavparse_parse_fmt), (gst_wavparse_handle_sink_event),
+	(gst_wavparse_loop), (gst_wavparse_change_state):
+	* gst/wavparse/gstwavparse.h:
+	  fix parsing of WAV files with non-standard fmt-tag size and fix
+	  skipping of unrecognized chunks... Someone please fix this thing
+	  to use rifflib so all this is automated.
+	* sys/v4l/Makefile.am:
+	* sys/v4l2/Makefile.am:
+	  Add X_CFLAGS because we depend on X (for overlay).
+
+2004-01-14  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/mpeg2dec/gstmpeg2dec.c:
+	  Don't issue a timestamp unless we tagged the frame
+	  with a PTS.
+
+2004-01-14  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst-libs/gst/play/gstplay.c: (gst_play_tick_callback):
+	  Query the audio element to get the time, not the clock. We're
+	  interested in the element's time here.
+
+2004-01-14  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/aalib/gstaasink.c: (gst_aasink_chain):
+	* ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event):
+	* ext/esd/esdsink.c: (gst_esdsink_chain):
+	* ext/libcaca/gstcacasink.c: (gst_cacasink_chain):
+	* ext/mas/massink.c: (gst_massink_chain):
+	* ext/sdl/sdlvideosink.c: (gst_sdlvideosink_chain):
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_parse_index),
+	(gst_matroska_demux_parse_metadata):
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_loop),
+	(gst_mpeg_parse_release_locks):
+	* gst/tcp/gsttcpsink.c: (gst_tcpsink_chain):
+	* gst/udp/gstudpsink.c: (gst_udpsink_chain):
+	* gst/videotestsrc/gstvideotestsrc.c: (gst_videotestsrc_get):
+	* sys/oss/gstosssink.c: (gst_osssink_init), (gst_osssink_chain),
+	(gst_osssink_change_state):
+	* sys/v4l/gstv4lmjpegsink.c: (gst_v4lmjpegsink_chain):
+	* sys/ximage/ximagesink.c: (gst_ximagesink_chain):
+	* sys/xvideo/xvideosink.c: (gst_xvideosink_chain),
+	(gst_xvideosink_release_locks):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_chain):
+	  use element time.
+	* ext/alsa/gstalsaclock.c: (gst_alsa_clock_start),
+	(gst_alsa_clock_stop):
+	* gst-libs/gst/audio/audioclock.c: (gst_audio_clock_set_active),
+	(gst_audio_clock_get_internal_time):
+	  simplify for use with new clocking code.
+	* testsuite/alsa/Makefile.am:
+	* testsuite/alsa/sinesrc.c: (sinesrc_init), (sinesrc_force_caps):
+	  fix testsuite for new caps system
+
+2004-01-14  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/flac/gstflacdec.c: (gst_flacdec_update_metadata):
+	* ext/flac/gstflacenc.c: (add_one_tag):
+	  length is already host endian, no need to convert. Fixes playback of
+	  tagged files on PPC. (bug #128384)
+
+2004-01-13  Julien MOUTTE <julien@moutte.net>
+
+	* gst-libs/gst/colorbalance/colorbalance.h: Adding a type to the
+	colorbalance interface stating if it is hardware based or software
+	based.
+	* gst/videofilter/gstvideobalance.c: (gst_videobalance_planar411):
+	Removing a trailing comma.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xcontext_get),
+	(gst_xvimagesink_colorbalance_init): Integrating a patch from Jon
+	Trowbridge <trow@ximian.com> querying Xv adaptor for min/max value as
+	the documentation seems to be wrong on the -1000 to 1000 interval.
+
+2004-01-12  David Schleef  <ds@schleef.org>
+
+	* gst/debug/efence.c: (gst_efence_init), (gst_efence_chain),
+	(gst_efence_buffer_alloc), (gst_fenced_buffer_new),
+	(gst_fenced_buffer_default_free), (gst_fenced_buffer_default_copy):
+	Fix negotiation.  Add a bufferalloc function for the sink pad,
+	and generally clean up some of the code.
+
+2004-01-12  Julien MOUTTE <julien@moutte.net>
+
+	* gst-libs/gst/colorbalance/colorbalancechannel.c:
+	(gst_color_balance_channel_dispose): Adding safety check in dispose
+	method.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xcontext_get),
+	(gst_xvimagesink_xcontext_clear),
+	(gst_xvimagesink_interface_supported),
+	(gst_xvimagesink_colorbalance_list_channels),
+	(gst_xvimagesink_colorbalance_set_value),
+	(gst_xvimagesink_colorbalance_get_value),
+	(gst_xvimagesink_colorbalance_init), (gst_xvimagesink_get_type):
+	Adding colorbalance interface support to set XV parameters such as
+	HUE, BRIGHTNESS, CONTRAST, SATURATION.
+	* sys/xvimage/xvimagesink.h: Adding the channels list for colorbalance
+	interface.
+
+2004-01-12  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_get_type),
+	(gst_audio_convert_class_init), (gst_audioconvert_getcaps),
+	(gst_audio_convert_init), (gst_audio_convert_set_property),
+	(gst_audio_convert_get_property), (gst_audio_convert_chain),
+	(gst_audio_convert_link),
+	(gst_audio_convert_buffer_to_default_format),
+	(gst_audio_convert_buffer_from_default_format), (plugin_init):
+          - implement _getcaps and use it
+          - improve linking
+          - remove float caps since no float conversion is actually done
+          - remove properties and arguments that were to be used for rate
+            conversion
+
+2004-01-12  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst-libs/gst/audio/audio.c: (_gst_audio_structure_set_list),
+	(gst_audio_structure_set_int):
+	* gst-libs/gst/audio/audio.h:
+          add helper functions for _getcaps matching the standard audio
+          templates
+
+2004-01-12  David Schleef  <ds@schleef.org>
+
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_link):
+	Test that pad is negotiated before getting its caps.
+
+2004-01-12  Julien MOUTTE <julien@moutte.net>
+
+	* gst-libs/gst/play/gstplay.c: (gst_play_get_sink_element): When
+	analyzing the pads of an element the bin is mostly in READY state so
+	no caps were negotiated. This helper function needs to work with
+	_get_caps directly then. I was not freeing them though, added that to
+	fix the mem leak.
+
+2004-01-12  Julien MOUTTE <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_chain):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_chain): Fixing the
+	direct put buffers detection. I prefer checking GST_BUFFER_PRIVATE
+	than the free_func.
+
+2004-01-12  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* sys/oss/gstossaudio.c: (plugin_init):
+	* sys/oss/gstosselement.c: (gst_osselement_sync_parms):
+	* sys/oss/gstosselement.h:
+          make an oss debugging category
+          make failure more descriptive
+
+2004-01-11  David Schleef  <ds@schleef.org>
+
+	* ext/ffmpeg/gstffmpeg.c:
+	* ext/ffmpeg/gstffmpegcodecmap.c:
+	* ext/ffmpeg/gstffmpegdec.c:
+	* ext/ffmpeg/gstffmpegenc.c:
+	* ext/ffmpeg/gstffmpegprotocol.c:
+	* ext/gdk_pixbuf/gstgdkanimation.c:
+	* ext/jpeg/gstjpeg.c:
+	* ext/libpng/gstpng.c:
+	* ext/mpeg2dec/perftest.c:
+	* ext/speex/gstspeex.c:
+	* gst-libs/gst/resample/dtos.c:
+	* gst/intfloat/gstintfloatconvert.c:
+	* gst/oneton/gstoneton.c:
+	* gst/rtjpeg/RTjpeg.c:
+	* gst/rtp/gstrtp.c:
+	* sys/dxr3/dxr3init.c:
+	* sys/glsink/gstgl_nvimage.c:
+	* sys/glsink/gstgl_pdrimage.c:
+	* sys/glsink/gstglsink.c:
+	* testsuite/gst-lint:
+	Make sure everybody wraps #include "config.h" in #ifdef HAVE_CONFIG_H
+
+2004-01-11  David Schleef  <ds@schleef.org>
+
+	* ext/alsa/gstalsasrc.c: (gst_alsa_src_set_caps):
+	* ext/faac/gstfaac.c: (gst_faac_sinkconnect):
+	* ext/gdk_pixbuf/gstgdkanimation.c:
+	(gst_gdk_animation_iter_create_pixbuf):
+	* ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_sink_link),
+	(gst_gdk_pixbuf_chain):
+	* ext/gdk_pixbuf/gstgdkpixbuf.h:
+	* ext/jack/gstjack.c: (gst_jack_change_state):
+	* ext/xvid/gstxviddec.c: (gst_xviddec_sink_link):
+	* gst-libs/gst/play/gstplay.c: (gst_play_get_sink_element):
+	* gst-libs/gst/play/play.c: (gst_play_get_sink_element):
+	* gst/videofilter/gstvideofilter.c:
+	(gst_videofilter_set_output_size):
+	Remove all usage of gst_pad_get_caps(), and replace it with
+	gst_pad_get_allowed_caps() or gst_pad_get_negotiated_cap().
+
+2004-01-11  David Schleef  <ds@schleef.org>
+
+	* configure.ac:
+	* ext/Makefile.am: Fixes to make ext/libcaca compile.
+	* ext/divx/gstdivxdec.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_sink_link),
+	(gst_gdk_pixbuf_init), (gst_gdk_pixbuf_chain): Make gdkpixbufdec
+	handle images that span multiple buffers.  Now work with both
+	filesrc ! gdkpixbufdec and qtdemux ! gdkpixbufdec.
+	* ext/gdk_pixbuf/gstgdkpixbuf.h:
+	* ext/libcaca/gstcacasink.h: Fixes needed due to recent
+	video/video.h changes
+	* ext/xvid/gstxvid.c: (gst_xvid_csp_to_caps): same
+	* sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_get),
+	(gst_v4lmjpegsrc_buffer_free): Use buffer free function instead
+	of GstData free function.
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_get), (gst_v4lsrc_buffer_free):
+	same.
+
+2004-01-12  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* sys/v4l2/gstv4l2element.c: (gst_v4l2element_class_init),
+	(gst_v4l2element_dispose), (gst_v4l2element_set_property),
+	(gst_v4l2element_get_property):
+	* sys/v4l2/v4l2_calls.c: (gst_v4l2_set_defaults), (gst_v4l2_open):
+	  add norm, channel and frequency properties.
+	* sys/v4l2/gstv4l2tuner.c:
+	  fixes for tuner interface changes
+	* sys/v4l2/gstv4l2element.h:
+	* sys/v4l2/gstv4l2src.c:
+	* sys/v4l2/gstv4l2src.h:
+	* sys/v4l2/v4l2src_calls.c:
+	* sys/v4l2/v4l2src_calls.h:
+	  rework v4l2src to work with saa1734 cards and allow mmaped buffers.
+
+2004-01-12  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst-libs/gst/tuner/tuner.c: (gst_tuner_class_init),
+	(gst_tuner_find_norm_by_name), (gst_v4l2_find_channel_by_name),
+	(gst_tuner_channel_changed), (gst_tuner_norm_changed),
+	(gst_tuner_frequency_changed), (gst_tuner_signal_changed):
+	* gst-libs/gst/tuner/tuner.h:
+	  GObjects aren't const.
+	  Add find_by_name functions.
+	  Add checks to _changed functions.
+	* sys/v4l/gstv4ltuner.c: (gst_v4l_tuner_get_channel),
+	(gst_v4l_tuner_get_norm):
+	  Fixes for above.
+
+2004-01-12  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst-libs/gst/video/video.h:
+	  Fix caps template names to be understandable.
+	  Prefix everything with GST_VIDEO.
+	* ext/aalib/gstaasink.c:
+	* ext/divx/gstdivxdec.c:
+	* ext/divx/gstdivxenc.c:
+	* ext/gdk_pixbuf/gstgdkpixbuf.c:
+	* ext/hermes/gstcolorspace.c: (gst_colorspace_base_init):
+	* ext/jpeg/gstjpegdec.c: (raw_caps_factory):
+	* ext/jpeg/gstjpegenc.c: (raw_caps_factory):
+	* ext/libcaca/gstcacasink.c:
+	* ext/libpng/gstpngenc.c: (raw_caps_factory):
+	* ext/snapshot/gstsnapshot.c:
+	* ext/swfdec/gstswfdec.c:
+	* ext/xvid/gstxviddec.c:
+	* ext/xvid/gstxvidenc.c:
+	* gst/chart/gstchart.c:
+	* gst/deinterlace/gstdeinterlace.c:
+	* gst/effectv/gsteffectv.c:
+	* gst/flx/gstflxdec.c: (gst_flxdec_loop):
+	* gst/goom/gstgoom.c:
+	* gst/median/gstmedian.c:
+	* gst/monoscope/gstmonoscope.c: (gst_monoscope_init),
+	(gst_monoscope_srcconnect), (gst_monoscope_chain):
+	* gst/overlay/gstoverlay.c:
+	* gst/smooth/gstsmooth.c:
+	* gst/smpte/gstsmpte.c:
+	* gst/synaesthesia/gstsynaesthesia.c:
+	* gst/videocrop/gstvideocrop.c:
+	* gst/videodrop/gstvideodrop.c:
+	* gst/y4m/gsty4mencode.c:
+	* sys/qcam/gstqcamsrc.c:
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_palette_to_caps):
+	  Make them work with new video.h file.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_chain),
+	(gst_ximagesink_buffer_free), (gst_ximagesink_buffer_alloc):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_chain),
+	(gst_xvimagesink_buffer_free), (gst_xvimagesink_buffer_alloc):
+	  Make it work with new buffer allocation system.
+
+2004-01-11  Julien MOUTTE  <julien@moutte.net>
+
+	* ext/ffmpeg/gstffmpegcolorspace.c: (gst_ffmpegcsp_chain): Fixing the
+	pad_alloc_buffer implementation to use ->srcpad
+	* ext/hermes/gstcolorspace.c: (gst_colorspace_chain): Fixing the
+        pad_alloc_buffer implementation to use ->srcpad
+	* gst/videoscale/gstvideoscale.c: (gst_videoscale_chain):  Fixing the
+        pad_alloc_buffer implementation to use ->srcpad
+	* sys/ximage/ximagesink.c: (gst_ximagesink_ximage_new),
+	(gst_ximagesink_chain), (gst_ximagesink_buffer_free),
+	(gst_ximagesink_buffer_alloc): Now only use GST_BUFFER_PRIVATE to keep
+	a reference to everything we need.
+	* sys/ximage/ximagesink.h: adding a reference to the sink in the image.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xvimage_new),
+	(gst_xvimagesink_chain), (gst_xvimagesink_buffer_free),
+	(gst_xvimagesink_buffer_alloc): Now only use GST_BUFFER_PRIVATE to keep
+        a reference to everything we need.
+	* sys/xvimage/xvimagesink.h: adding a reference to the sink in the image
+
+2004-01-11  David Schleef  <ds@schleef.org>
+
+	* ext/divx/gstdivxenc.c: remove bogus gst_caps_is_fixed() test
+	* gst/debug/efence.c: (gst_efence_chain), (gst_fenced_buffer_new),
+	(gst_fenced_buffer_default_copy): Fix for rename of buffer private
+	structure members.
+	* gst/effectv/gstwarp.c: (gst_warptv_setup): Don't reset the time
+	value during a resize/renegotiation.
+	* gst/videofilter/gstvideofilter.c: (gst_videofilter_chain): use
+	gst_pad_alloc_buffer();
+	* sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_get),
+	(gst_v4lmjpegsrc_buffer_free): Fix for rename of buffer private
+	structure members.
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_get), (gst_v4lsrc_buffer_free):
+	Fix for rename of buffer private structure members.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_chain),
+	(gst_ximagesink_buffer_free), (gst_ximagesink_buffer_alloc):
+	Fix for rename of buffer private structure members.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_chain),
+	(gst_xvimagesink_buffer_free), (gst_xvimagesink_buffer_alloc):
+	Fix for rename of buffer private structure members.
+
+2004-01-11  Arwed v. Merkatz <v.merkatz@gmx.net>
+
+	reviewed by: David Schleef <ds@schleef.org>
+
+	* gst/videofilter/Makefile.am:
+	* gst/videofilter/gstgamma.c: Gamma correction filter.  Modified
+	from the patch by ds to fit in with recent make_filter changes.
+
+2004-01-11  Julien MOUTTE  <julien@moutte.net>
+
+	* configure.ac: Adding examples/switch/Makefile
+	* examples/Makefile.am: Adding examples/switch
+	* examples/switch/Makefile.am: Adding switcher example.
+	* examples/switch/switcher.c: (got_eos), (idle_iterate),
+	(switch_timer), (main): Adding an example demonstrating switch usage
+	with 2 videotestsrc showing different patterns.
+	* gst/switch/gstswitch.c: (gst_switch_request_new_pad),
+	(gst_switch_init): Fixing switch with the new caps system.
+
+2004-01-11  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst-libs/gst/video/video.h:
+	  Fix 32bit caps. Issue remaining: The macro names are chosen poorly.
+	  They should probably be like
+	  GST_VIDEO_PAD_TEMPLATE_CAPS_{RGB,BGR,RGBx,BGRx}.
+
+2004-01-11  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header),
+	(qtdemux_parse_trak):
+	  fix audio chunk size/timestamp calculation
+
+2004-01-11  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/ffmpeg/gstffmpegcodecmap.c: (gst_ffmpeg_codecid_to_caps):
+	  fix SVQ3 caps
+
+2004-01-11  Steve Baker  <steve@stevebaker.org>
+
+	* gst/effectv/gstaging.c: (gst_agingtv_get_type),
+	(gst_agingtv_base_init), (gst_agingtv_class_init),
+	(gst_agingtv_init), (gst_agingtv_setup), (gst_agingtv_rgb32),
+	(gst_agingtv_set_property), (gst_agingtv_get_property):
+        Port agingTV to videofilter
+
+2004-01-09  Julien MOUTTE <julien@moutte.net>
+
+	* ext/hermes/gstcolorspace.c: (gst_colorspace_chain):
+	Implementing gst_pad_alloc_buffer to use optimized buffer allocation.
+
+2004-01-09  Julien MOUTTE <julien@moutte.net>
+
+	* ext/ffmpeg/gstffmpegcolorspace.c: (gst_ffmpegcsp_chain):
+	Implementing gst_pad_alloc_buffer to use optimized buffer allocation.
+	* gst-libs/gst/xoverlay/xoverlay.c:
+	(gst_x_overlay_got_desired_size): Updating doc for the xid being 0.
+	* gst/videoscale/gstvideoscale.c: (gst_videoscale_chain):
+	Implementing gst_pad_alloc_buffer to use optimized buffer allocation.
+	* gst/videotestsrc/gstvideotestsrc.c: (gst_videotestsrc_get):
+	Implementing gst_pad_alloc_buffer to use optimized buffer allocation.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_chain),
+	(gst_ximagesink_buffer_free), (gst_ximagesink_buffer_alloc),
+	(gst_ximagesink_set_xwindow_id), (gst_ximagesink_init): Implementing
+	the bufferalloc_function to replace bufferpools, fixing the XOverlay
+	interface implementation to handle xid being 0 and fix some bugs
+	triggered by Benjamin's testcase.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_chain),
+	(gst_xvimagesink_buffer_free), (gst_xvimagesink_buffer_alloc),
+	(gst_xvimagesink_set_xwindow_id), (gst_xvimagesink_init): Implementing
+	the bufferalloc_function to replace bufferpools, fixing the XOverlay
+	interface implementation to handle xid being 0 and fix some bugs
+	triggered by Benjamin's testcase.
+
+2004-01-09  David Schleef  <ds@schleef.org>
+
+	* ext/librfb/gstrfbsrc.c:  Hacking.  Added actual decoding and
+	mouse pointer events.  It works.
+
+2004-01-09  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/divx/gstdivxenc.c: (gst_divxenc_init):
+	  Use explicit caps - fix capsnego.
+	* ext/xvid/gstxviddec.c:
+	* ext/xvid/gstxvidenc.c:
+	  Remove macro-inside-macro which caused compile errors.
+	* gst-libs/gst/riff/riff-read.c: (gst_riff_read_header):
+	  Error out if it's not a RIFF file. Else we error out without
+	  gst_element_error() which is not good...
+
+2004-01-08  David Schleef  <ds@schleef.org>
+
+	* ext/ffmpeg/gstffmpegenc.c: (gst_ffmpegenc_connect):
+	Fix pad_link function to handle formats that ffmpeg returns
+	as multiple caps structures.
+	* gst/videofilter/gstvideofilter.c: (gst_videofilter_chain):
+	Only complain if source buffer is _smaller_ than expected.
+	* gst/videoscale/gstvideoscale.c: (gst_videoscale_init),
+	(gst_videoscale_handle_src_event): Resize navigation events
+	when passing them upstream.
+	* gst/videotestsrc/gstvideotestsrc.c:
+	* gst/videotestsrc/gstvideotestsrc.h:
+	* gst/videotestsrc/videotestsrc.c:
+	* gst/videotestsrc/videotestsrc.h:
+	Rewrite many of the buffer painting functions to handle odd
+	sizes (for many formats, size%4!=0 or size%8!=0).  Most have
+	been verified to work with my video card.
+	* testsuite/gst-lint:  Add check for elements calling
+	gst_pad_get_caps() instead of gst_pad_get_allowed_caps().
+
+2004-01-08  David Schleef  <ds@schleef.org>
+
+	* gst/videodrop/gstvideodrop.c: (gst_videodrop_getcaps),
+	(gst_videodrop_link), (gst_videodrop_init): Fix negotiation.
+
+2004-01-08  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_handle_xevents): A
+	configure event is not emiting the desired size signal. That fixes
+	aspect ratio issues with gst-player.
+
+2004-01-08  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/median/gstmedian.c: (gst_median_link), (gst_median_init):
+	  Fix capsnego.
+
+2004-01-08  Julien MOUTTE  <julien@moutte.net>
+
+	* ext/sdl/sdlvideosink.c: (gst_sdlvideosink_create): Using XOverlay
+	public method to fire size signal.
+
+2004-01-07  Julien MOUTTE  <julien@moutte.net>
+
+	* examples/gstplay/Makefile.am: Adding the interface library.
+	* gst-libs/gst/play/Makefile.am: Adding the interface library.
+	* gst-libs/gst/play/gstplay.c: (gst_play_set_video_sink): Connecting to 	the XOverlay size signal instead of GstVideoSink.
+	* gst-libs/gst/play/gstplay.h: Including the XOverlay interface to check
+	GST_IS_X_OVERLAY before signal connect.
+	* gst-libs/gst/video/gstvideosink.c: (gst_videosink_class_init):
+	Removing the have_video_size signal.
+	* gst-libs/gst/video/gstvideosink.h: Removing the have_video_size signal
+	and associated public method.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_handle_xevents),
+	(gst_ximagesink_sinkconnect): Using XOverlay public method to fire size
+	signal.
+	* sys/xvideo/xvideosink.c: (gst_xvideosink_sinkconnect),
+	(gst_xvideosink_xwindow_new): Using XOverlay public method to fire size
+        signal.
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_sinkconnect):
+	Using XOverlay public method to fire size signal.
+
+2004-01-07  David Schleef  <ds@schleef.org>
+
+	* gst/videofilter/Makefile.am:
+	* gst/videofilter/gstvideotemplate.c:
+	* gst/videofilter/make_filter:
+	Create gstvideoexample.c in a srcdir!=builddir friendly way.
+	Convert make_filter to /bin/sh script.
+
+2004-01-07  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* gst/modplug/gstmodplug.cc: fix element description
+
+2004-01-07  Julien MOUTTE  <julien@moutte.net>
+
+	* examples/gstplay/player.c: (got_time_tick), (got_stream_length),
+	(got_video_size): Adding some new lines in g_print calls.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xwindow_new),
+	(gst_ximagesink_xwindow_destroy), (gst_ximagesink_xwindow_resize),
+	(gst_ximagesink_handle_xevents), (gst_ximagesink_fixate),
+	(gst_ximagesink_sinkconnect), (gst_ximagesink_change_state),
+	(gst_ximagesink_chain), (gst_ximagesink_buffer_new),
+	(gst_ximagesink_set_xwindow_id), (gst_ximagesink_get_desired_size):
+	Complete code review, reverting some stuff i disagree with, adding
+	some fixes : time synchronization on invalid timestamps, renegotiation
+	of private window.
+	* sys/ximage/ximagesink.h:
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xwindow_destroy),
+	(gst_xvimagesink_xwindow_resize), (gst_xvimagesink_handle_xevents),
+	(gst_xvimagesink_get_xv_support), (gst_xvimagesink_xcontext_get),
+	(gst_xvimagesink_fixate), (gst_xvimagesink_sinkconnect),
+	(gst_xvimagesink_change_state), (gst_xvimagesink_chain),
+	(gst_xvimagesink_buffer_new),
+	(gst_xvimagesink_navigation_send_event),
+	(gst_xvimagesink_set_xwindow_id),
+	(gst_xvimagesink_get_desired_size),
+	(gst_xvimagesink_xoverlay_init): Complete code review, reverting some
+	stuff i disagree with, adding some fixes : Renegotiation of private
+	window, implementing get_desired_size.
+
+2004-01-07  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/audiofile/gstafsink.c: (gst_afsink_init), (gst_afsink_chain),
+	(gst_afsink_handle_event):
+	* ext/jpeg/gstjpegenc.c: (gst_jpegenc_init):
+	* gst/avi/gstavimux.c: (gst_avimux_request_new_pad):
+	* sys/dxr3/dxr3audiosink.c: (dxr3audiosink_init):
+	* sys/dxr3/dxr3spusink.c: (dxr3spusink_init):
+	* sys/dxr3/dxr3videosink.c: (dxr3videosink_init):
+	  Fix for instantiate-test (see core). Also remove dead code from
+	  jpegenc (which still needs fixing, but that's lower on my TODO
+	  list...).
+	* sys/v4l2/gstv4l2src.c: (gst_v4l2src_getcaps):
+	  Never return NULL as caps.
+
+2004-01-07  David Schleef  <ds@schleef.org>
+
+	* configure.ac:
+	* ext/Makefile.am:
+	* ext/librfb/Makefile.am:
+	* ext/librfb/gstrfbsrc.c:
+	New source plugin based on librfb-0.1.  RFB (remote framebuffer)
+	is the protocol used by VNC.
+
+2004-01-07  David Schleef  <ds@schleef.org>
+
+	* gst/videofilter/gstvideotemplate.c:
+	* gst/videofilter/gstvideotemplate.h:
+	* gst/videofilter/make_filter:
+	Merge videotemplate header into source file.
+	* gst/effectv/Makefile.am:
+	* gst/effectv/gsteffectv.c: (plugin_init):
+	* gst/effectv/gstwarp.c:
+	Make warpTV a subclass of videofilter.
+
+2004-01-07  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/mad/gstid3tag.c: (gst_mad_id3_to_tag_list):
+	  Add guard against invalid utf-8 conversions in mad. Just in case.
+
+2004-01-07  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* sys/oss/gstosssink.c: (gst_osssink_sink_fixate):
+	  Fix for bug shown by poisoning
+
+2004-01-06  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_get),
+	(gst_v4lmjpegsrc_buffer_free):
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_palette_to_caps),
+	(gst_v4lsrc_srcconnect), (gst_v4lsrc_getcaps), (gst_v4lsrc_get),
+	(gst_v4lsrc_buffer_free):
+	  Fix for removed bufferpools.
+
+2004-01-07  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/dv/gstdvdec.c: (gst_dvdec_loop):
+	Fix caps negotiation.
+
+	* ext/dvdnav/dvdnavsrc.c: (dvdnavsrc_class_init),
+	(dvdnavsrc_update_buttoninfo), (dvdnavsrc_get),
+	(dvdnavsrc_get_event_mask), (dvdnav_handle_navigation_event),
+	(dvdnavsrc_event):
+	* ext/mpeg2dec/gstmpeg2dec.c:
+	* gst-libs/gst/navigation/navigation.c:
+	(gst_navigation_send_key_event), (gst_navigation_send_mouse_event):
+	* gst-libs/gst/navigation/navigation.h:
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_handle_src_event):
+	* sys/ximage/ximagesink.c: (gst_ximagesink_handle_xevents):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_handle_xevents):
+	Super-simple first version of mouse and keyboard events. Clicking
+	on a DVD menu now works, although it may not take you where you
+	expected.
+
+	* gst/sine/gstsinesrc.c: (gst_sinesrc_src_fixate):
+	* gst/videotestsrc/gstvideotestsrc.c:
+	(gst_videotestsrc_src_fixate):
+	These fixate functions were broken - they never actually
+	fixated :)
+
+2004-01-06  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/shout/gstshout.c: (gst_icecastsend_base_init),
+	(gst_icecastsend_init):
+	  fix for new caps system.
+	* gst-libs/gst/mixer/mixertrack.h:
+	* sys/oss/gstossmixer.c: (gst_ossmixer_build_list):
+	  Add 'master track' flag (for tools like ACME that only want to
+	  change the main volume).
+
+2004-01-07  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* ext/xvid/gstxvid.c: (gst_xvid_structure_to_csp),
+	(gst_xvid_csp_to_caps):
+	* ext/xvid/gstxviddec.c: (gst_xviddec_src_getcaps):
+	* ext/xvid/gstxvidenc.c:
+	ifdef out ARGB type when it isn't available
+	in xvidcore 1.0.0beta2
+
+2004-01-06  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_loop):
+	  When we have received a new SCR right in the first buffer after
+	  a seek (so in the same cycle that handles the discont), we should
+	  handle the buffer instead of unreffing it, else we lose data.
+
+2004-01-06  Iain <iain@prettypeople.org>
+
+	* gst/intfloat/gstint2float.c (gst_int2float_link): Set the
+	  buffer-frames caps too.
+
+	* gst/oneton/gstoneton.c (gst_oneton_sink_connect): Only create the new
+	  caps that we need, don't destroy them all and rebuild them. And when
+	  creating src pads, use the src pad template rather than the sink...
+
+2004-01-05  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_parse_syshead):
+	  Add pad to element *after* setting functions such as event handler.
+	  Without this, the scheduler (opt) will link pads, set the event
+	  handler from the default event function (dispatcher in gstpad.c)
+	  and *after* that, we will set our own event function, which will
+	  thus never be used (and thus mpegdemux doesn't handle events).
+
+2004-01-04  David Schleef  <ds@schleef.org>
+
+	Fix the fixate functions to handle new prototype:
+	* gst/sine/gstsinesrc.c: (gst_sinesrc_src_fixate):
+	* gst/videotestsrc/gstvideotestsrc.c:
+	(gst_videotestsrc_src_fixate):
+	* sys/oss/gstosssink.c: (gst_osssink_sink_fixate):
+	* sys/ximage/ximagesink.c: (gst_ximagesink_fixate):
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_fixate):
+
+2004-01-04  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* sys/ximage/ximagesink.h:
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xwindow_new),
+	(gst_ximagesink_xwindow_destroy), (gst_ximagesink_sinkconnect),
+	(gst_ximagesink_change_state), (gst_ximagesink_set_xwindow_id),
+	(gst_ximagesink_xoverlay_init):
+	  assorted fixes to make (re)embedding work
+	* sys/ximage/ximagesink.c: (gst_ximagesink_sinkconnect),
+	(gst_ximagesink_get_desired_size):
+	  implement desired size additions to XOverlay
+
+2004-01-04  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst-libs/gst/xoverlay/xoverlay.c: (gst_x_overlay_base_init),
+	(gst_x_overlay_got_xwindow_id), (gst_x_overlay_get_desired_size),
+	(gst_x_overlay_got_desired_size):
+	* gst-libs/gst/xoverlay/xoverlay.h:
+	  Add optional "desired size" signal and querying.
+
+2004-01-04  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/matroska-demux.c:
+	(gst_matroska_demux_parse_blockgroup):
+	  Fix EBML-laced block parsing. Diffs are relative to previous
+	  lace, not the first lace. Thanks to Mosu from the Matroska
+	  team for detecting this.
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_init),
+	(gst_wavparse_parse_fmt), (gst_wavparse_getcaps),
+	(gst_wavparse_handle_sink_event), (gst_wavparse_loop),
+	(gst_wavparse_change_state):
+	* gst/wavparse/gstwavparse.h:
+	  Quickfix for capsnego.
+
+2004-01-04  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/wavenc/gstwavenc.c: (set_property), (gst_wavenc_init):
+	  Fix indenting, fix pad creation.
+
+2004-01-04  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/xvid/gstxviddec.c: (gst_xviddec_init),
+	(gst_xviddec_src_getcaps), (gst_xviddec_src_link),
+	(gst_xviddec_sink_link):
+	  Implement src_getcaps() so proper size caps is negotiated.
+
+2004-01-04  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/flac/gstflacdec.c: (gst_flacdec_loop):
+	  Finish flac decoder on EOS. See #116178.
+
+2004-01-04  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_src_getcaps),
+	(gst_matroska_demux_add_stream):
+	* gst/matroska/matroska-ids.h:
+	  Add getcaps() function to fix capsnego...
+
+2004-01-04  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_parse_syshead),
+	(gst_mpeg_demux_parse_packet), (gst_mpeg_demux_parse_pes):
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_parse_packhead):
+	  Fix more integer overflows. Again, see #126967.
+
+2004-01-03  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mpeg2dec/gstmpeg2dec.c:
+	  Add support for mpeg2dec-0.4.0 (released two weeks ago). See
+	  #130416.
+
+2004-01-03  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	* ext/xvid/gstxvid.c: (gst_xvid_init), (gst_xvid_error),
+	(gst_xvid_structure_to_csp), (gst_xvid_csp_to_caps):
+	* ext/xvid/gstxvid.h:
+	* ext/xvid/gstxviddec.c: (gst_xviddec_class_init),
+	(gst_xviddec_init), (gst_xviddec_setup), (gst_xviddec_chain),
+	(gst_xviddec_src_link), (gst_xviddec_sink_link),
+	(gst_xviddec_change_state):
+	* ext/xvid/gstxviddec.h:
+	* ext/xvid/gstxvidenc.c: (gst_xvidenc_profile_get_type),
+	(gst_xvidenc_base_init), (gst_xvidenc_class_init),
+	(gst_xvidenc_init), (gst_xvidenc_setup), (gst_xvidenc_chain),
+	(gst_xvidenc_link), (gst_xvidenc_set_property),
+	(gst_xvidenc_get_property), (gst_xvidenc_change_state):
+	* ext/xvid/gstxvidenc.h:
+	  Update xvid plugin to latest xvid (1.0.0-beta3) API.
+
+2004-01-03  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/rtp/rtp-packet.c:
+	  Add sys/types.h include, since OS X doesn't define in_addr_t
+	  in netinet/in.h, like it does on Linux (see #129600).
+
+2004-01-03  Thomas Canty <tommydal@optushome.com.au>
+
+	reviewed by: Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_dispose):
+	  Correct logic of dispose function (see #129306).
+
+2004-01-03  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_parse_pes):
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_class_init),
+	(gst_mpeg_parse_init):
+	* gst/mpegstream/gstmpegparse.h:
+	  Remove clock (which was never provided, i.e. dead code), and
+	  also fix integer overflows at high PTS values (see #126967).
+
+2004-01-03  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/flac/gstflacdec.c:
+	* ext/libpng/gstpngenc.h:
+	* ext/mikmod/gstmikmod.h:
+	  OS X fixes (see #126628).
+
+2004-01-02  David Schleef  <ds@schleef.org>
+
+	* ext/alsa/gstalsasrc.c: (gst_alsa_src_pad_factory),
+	(gst_alsa_src_base_init): Remove bogus "src" request pad.
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_base_init),
+	(gst_mpeg_parse_class_init): Move pad template registration
+	to class_init, since the derived class (mpegdemux) doesn't
+	want them.
+
+2004-01-03  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/ximage/Makefile.am:
+	* sys/xvideo/Makefile.am:
+	* sys/xvimage/Makefile.am:
+	  Move interface libs from LDFLAGS to LIBADD, fix relocation errors
+	  after installation (see #127664).
+
+2004-01-02  David Schleef  <ds@schleef.org>
+
+	* ext/ffmpeg/gstffmpegenc.c: (gst_ffmpegenc_init),
+	(gst_ffmpegenc_connect):  Negotiation fixes.
+	* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_negotiate_format):
+	Remove inappropriate gst_caps_free().
+	* sys/ximage/ximagesink.c: (gst_ximagesink_sinkconnect):
+	Reenable Ronald's internal resize code, since the core handles
+	it correctly now.
+
+2004-01-02  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/v4l/gstv4lmjpegsink.c: (gst_v4lmjpegsink_init):
+	* sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_init):
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_base_init), (gst_v4lsrc_init):
+	  Fix pad template stuff.
+
+2004-01-02  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* gst/matroska/ebml-read.c: (gst_ebml_read_sint):
+	* gst/matroska/ebml-write.c: (gst_ebml_write_sint):
+	  fix signed integer reading/writing.
+
+2004-01-02  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/alsa/README:
+	  Remove outdated document
+
+2004-01-03  Jan Schmidt  <thaytan@mad.scientist.com>
+
+	* gst/cutter/gstcutter.c: (gst_cutter_init):
+	  src pad was being created twice - oops.
+
+2004-01-02  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_sinkconnect):
+	  Comment out internal resize. It doesn't handle the resulting
+	  XEvent internally, does another try_set_caps() which leads to
+	  a really nice loop.
+	  Real fix will come when Julien and Dave are awake. ;).
+
+2004-01-02  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/mpeg2enc/gstmpeg2enc.cc:
+	  fix const/nonconst compile issue.
+
+2004-01-02  David Schleef  <ds@schleef.org>
+
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_fixate),
+	(gst_xvimagesink_sinkconnect), (gst_xvimagesink_init):
+	Add fixate function and a check for bad formats.
+
+2004-01-01  David Schleef  <ds@schleef.org>
+
+	Negotiation fixes:
+	* gst-libs/gst/audio/gstaudiofilter.c: (gst_audiofilter_link),
+	(gst_audiofilter_init):
+	* gst/debug/efence.c: (gst_efence_init):
+	* gst/deinterlace/gstdeinterlace.c: (gst_deinterlace_link),
+	(gst_deinterlace_init):
+	* gst/volume/gstvolume.c: (volume_connect):
+
+2004-01-01  David Schleef  <ds@schleef.org>
+
+	Convert elements to use gst_pad_use_explicit_caps() where
+	appropriate:
+	* ext/a52dec/gsta52dec.c: (gst_a52dec_init), (gst_a52dec_reneg):
+	* ext/audiofile/gstafparse.c: (gst_afparse_init),
+	(gst_afparse_open_file):
+	* ext/audiofile/gstafsrc.c: (gst_afsrc_init),
+	(gst_afsrc_open_file):
+	* ext/esd/esdmon.c: (gst_esdmon_init), (gst_esdmon_get):
+	* ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_init),
+	(gst_ffmpegdec_chain):
+	* ext/ffmpeg/gstffmpegdemux.c: (gst_ffmpegdemux_loop):
+	* ext/flac/gstflacdec.c: (gst_flacdec_init), (gst_flacdec_write):
+	* ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_init),
+	(gst_gdk_pixbuf_chain):
+	* ext/jpeg/gstjpegdec.c: (gst_jpegdec_init), (gst_jpegdec_link),
+	(gst_jpegdec_chain):
+	* ext/mad/gstmad.c: (gst_mad_init), (gst_mad_chain):
+	* ext/mikmod/gstmikmod.c: (gst_mikmod_init),
+	(gst_mikmod_negotiate):
+	* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_init),
+	(gst_mpeg2dec_negotiate_format):
+	* ext/mpeg2enc/gstmpeg2enc.cc:
+	* ext/ogg/gstoggdemux.c: (gst_ogg_pad_push):
+	* ext/speex/gstspeexdec.c: (gst_speexdec_init),
+	(gst_speexdec_sinkconnect):
+	* ext/swfdec/gstswfdec.c: (gst_swfdec_loop), (gst_swfdec_init):
+	* ext/vorbis/vorbisfile.c: (gst_vorbisfile_init),
+	(gst_vorbisfile_new_link):
+	* gst/ac3parse/gstac3parse.c: (gst_ac3parse_init),
+	(gst_ac3parse_chain):
+	* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_add_audio_stream),
+	(gst_asf_demux_setup_pad):
+	* gst/auparse/gstauparse.c: (gst_auparse_init),
+	(gst_auparse_chain):
+	* gst/id3/gstid3types.c: (gst_id3types_loop):
+	* gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream):
+	* gst/mpeg1videoparse/gstmp1videoparse.c: (gst_mp1videoparse_init),
+	(mp1videoparse_parse_seq):
+	* gst/mpegaudioparse/gstmpegaudioparse.c: (gst_mp3parse_init),
+	(bpf_from_header):
+	* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_parse_syshead),
+	(gst_mpeg_demux_parse_pes), (gst_mpeg_demux_lpcm_set_caps):
+	* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_init),
+	(gst_mpeg_parse_send_data):
+	* gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header),
+	(gst_qtdemux_add_stream):
+	* gst/realmedia/rmdemux.c: (gst_rmdemux_add_stream):
+	* gst/wavparse/gstwavparse.c: (gst_wavparse_init),
+	(gst_wavparse_parse_fmt):
+
+2004-01-01  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	  Fix configure check for mpeg2enc. We need 1.6.1.93 instead of
+	  1.6.1.92, since the pkg-config file of 1.6.1.92 is borked and
+	  it therefore uses the wrong include paths. Too bad... Note
+	  that 1.6.1.93 is not release yet. ;).
+	  Also add a check for mplex, which is now using the lib'ified
+	  mplex from mjpegtools, too.
+	* ext/ffmpeg/gstffmpegcodecmap.c:
+	  Add codec_tag for 3ivx/xvid. For xvid, this should fix playback
+	  issues. I don't think ffmpeg handles 3ivx correctly, so this
+	  probably won't work. But it won't hurt either.
+	* ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_connect),
+	(gst_ffmpegdec_chain):
+	* ext/ffmpeg/gstffmpegenc.c: (gst_ffmpegenc_connect),
+	(gst_ffmpegenc_chain_audio):
+	  Fix memleak in audio encoding. Close codec if open fails, this
+	  calls the cleanup routines so we can re-use the context.
+	* ext/mpeg2enc/gstmpeg2enc.cc:
+	  Fix pad template names/types, fix memory issue with getcaps().
+	* ext/mpeg2enc/gstmpeg2encoder.cc:
+	* ext/mpeg2enc/gstmpeg2encoder.hh:
+	  Fix compile issue with new caps system (const thingy).
+	* ext/mpeg2enc/gstmpeg2encpicturereader.cc:
+	* ext/mpeg2enc/gstmpeg2encpicturereader.hh:
+	  We read a first frame right on initing, so that we have a caps
+	  when we init the output. This caps is cached in padprivate and
+	  read as first frame.
+	* ext/mplex/Makefile.am:
+	* ext/mplex/gstmplex.cc:
+	* ext/mplex/gstmplex.h:
+	* ext/mplex/gstmplex.hh:
+	* ext/mplex/gstmplexibitstream.cc:
+	* ext/mplex/gstmplexibitstream.hh:
+	* ext/mplex/gstmplexjob.cc:
+	* ext/mplex/gstmplexjob.hh:
+	* ext/mplex/gstmplexoutputstream.cc:
+	* ext/mplex/gstmplexoutputstream.hh:
+	  We wrap mjpegtools mplex. So I rewrote the plugin. The old plugin
+	  had issues, didn't do capsnego, supported only a subset of the
+	  mplex features and required a mplex fork in our local CVS. Plus
+	  that it worked agaist a very old mplex version. Rewriting was
+	  faster than updating it.
+	* gst-libs/ext/Makefile.am:
+	* gst-libs/ext/mplex/INSTRUCT:
+	* gst-libs/ext/mplex/Makefile.am:
+	* gst-libs/ext/mplex/README:
+	* gst-libs/ext/mplex/TODO:
+	* gst-libs/ext/mplex/ac3strm_in.cc:
+	* gst-libs/ext/mplex/audiostrm.hh:
+	* gst-libs/ext/mplex/audiostrm_out.cc:
+	* gst-libs/ext/mplex/aunit.hh:
+	* gst-libs/ext/mplex/bits.cc:
+	* gst-libs/ext/mplex/bits.hh:
+	* gst-libs/ext/mplex/buffer.cc:
+	* gst-libs/ext/mplex/buffer.hh:
+	* gst-libs/ext/mplex/fastintfns.h:
+	* gst-libs/ext/mplex/format_codes.h:
+	* gst-libs/ext/mplex/inputstrm.cc:
+	* gst-libs/ext/mplex/inputstrm.hh:
+	* gst-libs/ext/mplex/lpcmstrm_in.cc:
+	* gst-libs/ext/mplex/mjpeg_logging.cc:
+	* gst-libs/ext/mplex/mjpeg_logging.h:
+	* gst-libs/ext/mplex/mjpeg_types.h:
+	* gst-libs/ext/mplex/mpastrm_in.cc:
+	* gst-libs/ext/mplex/mpegconsts.cc:
+	* gst-libs/ext/mplex/mpegconsts.h:
+	* gst-libs/ext/mplex/mplexconsts.hh:
+	* gst-libs/ext/mplex/multplex.cc:
+	* gst-libs/ext/mplex/outputstream.hh:
+	* gst-libs/ext/mplex/padstrm.cc:
+	* gst-libs/ext/mplex/padstrm.hh:
+	* gst-libs/ext/mplex/stillsstream.cc:
+	* gst-libs/ext/mplex/stillsstream.hh:
+	* gst-libs/ext/mplex/systems.cc:
+	* gst-libs/ext/mplex/systems.hh:
+	* gst-libs/ext/mplex/vector.cc:
+	* gst-libs/ext/mplex/vector.hh:
+	* gst-libs/ext/mplex/videostrm.hh:
+	* gst-libs/ext/mplex/videostrm_in.cc:
+	* gst-libs/ext/mplex/videostrm_out.cc:
+	* gst-libs/ext/mplex/yuv4mpeg.cc:
+	* gst-libs/ext/mplex/yuv4mpeg.h:
+	* gst-libs/ext/mplex/yuv4mpeg_intern.h:
+	* gst-libs/ext/mplex/yuv4mpeg_ratio.cc:
+	  We don't fork mjpegtools' mplex in our CVS anymore.
+	* gst/avi/gstavidemux.c: (gst_avi_demux_src_getcaps),
+	(gst_avi_demux_add_stream):
+	* gst/avi/gstavidemux.h:
+	  Add getcaps() function for proper caps nego. This makes some
+	  parts of AVI playback/reading work.
+	* sys/ximage/ximagesink.c: (gst_ximagesink_sinkconnect):
+	  Resize window on new capsnego. This is probably wrong, but
+	  I'm still committing it because with current capsnego, the
+	  first successfull capsnego is auto-fixated, therefore rounded
+	  down to the lowest values in the caps. this results in a 16x16
+	  XWindow that is not reized when real capsnego finishes.
+	  Dave, I see more cases of this, do you know a proper solution?
+	* tools/gst-launch-ext.in:
+	  Fix MPEG-4 AAC (Apple iPod/iTunes) file commandline.
+
+2003-12-31  David Schleef  <ds@schleef.org>
+
+	* gst/tcp/gsttcpsrc.c: (gst_tcpsrc_get):
+	* gst/udp/gstudpsrc.c: (gst_udpsrc_get):
+	  Change gst_pad_proxy_link() to gst_pad_try_set_caps()
+
+2003-12-30  David Schleef  <ds@schleef.org>
+
+	* ext/ffmpeg/gstffmpegcolorspace.c:
+	(gst_ffmpegcsp_caps_remove_format_info), (gst_ffmpegcsp_getcaps),
+	(gst_ffmpegcsp_pad_link), (gst_ffmpegcsp_init),
+	(gst_ffmpegcsp_chain): Negotiation fixes
+	* ext/mad/gstmad.c: (gst_mad_chain): Negotiation fixes
+	* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_chain),
+	(gst_audio_convert_link), (gst_audio_convert_channels):
+	* gst/audioscale/gstaudioscale.c: (gst_audioscale_getcaps),
+	(gst_audioscale_link), (gst_audioscale_get_buffer),
+	(gst_audioscale_chain): Negotiation fixes
+	* gst/audioscale/gstaudioscale.h:
+	* gst/videofilter/gstvideofilter.c:
+	(gst_videofilter_format_get_structure), (gst_videofilter_getcaps),
+	(gst_videofilter_link), (gst_videofilter_init),
+	(gst_videofilter_set_output_size), (gst_videofilter_setup),
+	(gst_videofilter_find_format_by_structure):
+	* gst/videofilter/gstvideofilter.h: Negotiation fixes
+	* gst/videoscale/gstvideoscale.c: (gst_videoscale_getcaps),
+	(gst_videoscale_link):
+	* gst/videoscale/videoscale.c: (videoscale_get_structure),
+	(videoscale_find_by_structure), (gst_videoscale_setup):
+	* gst/videoscale/videoscale.h: Negotiation fixes
+	* sys/ximage/ximagesink.c: (gst_ximagesink_handle_xevents),
+	(gst_ximagesink_fixate), (gst_ximagesink_init): Add a fixate
+	function, restrict resizing to a multiple of 4 (hack until
+	everyone supports odd sizes correctly).
+
+2003-12-29  Colin Walters  <walters@verbum.org>
+
+	* ext/esd/esdsink.c (gst_esdsink_link): Fix typo; get depth instead of
+	signed.
+
+2003-12-30  Jan Schmidt <thaytan@mad.scientist.com>
+
+	* ext/sndfile/gstsf.c: (gst_sf_loop):
+	  Fix warning about discarding const qualifier
+
+2003-12-27  Jeremy Simon   <jesimon@libertysurf.fr>
+
+	* gst/cutter/gstcutter.c:
+	* gst/videoscale/gstvideoscale.c:
+	* gst/volenv/gstvolenv.c:
+	* gst-libs/gst/audio/audio.c:
+	* gst-libs/gst/video/video.c:
+	  Fix warnings
+
+2003-12-27  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_open_audio):
+	  Don't send ALSA debugging to stderr.
+	* ext/alsa/gstalsa.h:
+	  Use GST_WARNING instead of g_warning when ALSA functions fail.
+
+2003-12-27  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_xv_support):
+	  Free XVAdapterInfo correctly.
+
+2003-12-27  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/mad/gstid3tag.c: (gst_id3_tag_add_src_pad),
+	(gst_id3_tag_do_caps_nego), (gst_id3_tag_src_link):
+	  Make id3tag use correct caps nego.
+
+2003-12-27  Amaury Jacquot <sxpert@esitcom.org>
+
+	* ext/ivorbis/vorbis.c:
+	* ext/ivorbis/vorbisenc.h:
+	* ext/ivorbis/vorbisfile.c:
+	  Modify so that it uses the new caps things
+
+2003-12-27  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* testsuite/spider/spider1.c: (main):
+	* testsuite/spider/spider2.c: (main):
+	* testsuite/spider/spider3.c: (main):
+	  Make tests compile again. They probably don't work.
+
+2003-12-24  Colin Walters  <walters@verbum.org>
+
+	* sys/oss/gstosssink.c (gst_osssink_sink_fixate): Return NULL if
+	we can't fixate the caps anymore.
+
+2003-12-23  David Schleef  <ds@schleef.org>
+
+	* gst/volume/gstvolume.c: (volume_init): Proxy getcaps.
+	* sys/oss/gstosssink.c: (gst_osssink_init),
+	(gst_osssink_sink_fixate): Add fixate function.
+
+2003-12-24  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/ffmpeg/gstffmpegcodecmap.c:
+	* ext/ffmpeg/gstffmpegcolorspace.c: (gst_ffmpegcsp_getcaps),
+	(gst_ffmpegcsp_srcconnect_func), (gst_ffmpegcsp_sinkconnect),
+	(gst_ffmpegcsp_srcconnect), (gst_ffmpegcsp_get_type),
+	(gst_ffmpegcsp_base_init), (gst_ffmpegcsp_class_init),
+	(gst_ffmpegcsp_init), (gst_ffmpegcsp_chain),
+	(gst_ffmpegcsp_change_state), (gst_ffmpegcsp_set_property),
+	(gst_ffmpegcsp_get_property), (gst_ffmpegcsp_register):
+	  fix typo in RGB masks, and move back to "old" colorspace
+	  capsnego code until whoever wrote this new crap has actually
+	  tested it so that it works.
+	  And yes, this works, keep it that way please.
+
+2003-12-23  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* ext/divx/gstdivxdec.c: (gst_divxdec_base_init),
+	(gst_divxdec_init), (gst_divxdec_negotiate):
+	* ext/divx/gstdivxdec.h:
+	* ext/divx/gstdivxenc.c: (gst_divxenc_base_init),
+	(gst_divxenc_init):
+	* ext/faac/gstfaac.c: (gst_faac_base_init), (gst_faac_init),
+	(gst_faac_sinkconnect), (gst_faac_srcconnect):
+	* ext/mpeg2enc/gstmpeg2enc.cc:
+	* ext/mpeg2enc/gstmpeg2encoder.cc:
+	* ext/mpeg2enc/gstmpeg2encpicturereader.cc:
+	* sys/dxr3/dxr3audiosink.c: (dxr3audiosink_base_init),
+	(dxr3audiosink_init), (dxr3audiosink_pcm_sinklink):
+	* sys/dxr3/dxr3spusink.c: (dxr3spusink_base_init),
+	(dxr3spusink_init):
+	* sys/dxr3/dxr3videosink.c: (dxr3videosink_base_init),
+	(dxr3videosink_init):
+	  Fix caps breakage after Dave's caps branch merge.
+
+2003-12-23  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* sys/ximage/ximagesink.c: (gst_ximagesink_xcontext_get):
+	  Fix for 24bpp display.
+
+2003-12-23  Colin Walters  <walters@verbum.org>
+
+	* ext/gnomevfs/gstgnomevfssink.c: Add ARG_HANDLE property that takes
+	a GnomeVFSHandle directly.
+
+2003-12-22  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/volume/Makefile.am:
+	* gst/volume/gstvolume.c: (volume_connect), (volume_parse_caps),
+	(volume_base_init), (volume_init):
+	  Reenable volume element and fix to work with new caps stuff.
+	  Rhythmbox needs this.
+
+2003-12-22  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* gst/qtdemux/qtdemux.c: (plugin_init):
+	  qtdemux requires bytestream
+
+2003-12-22  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/alsa/gstalsa.c: (gst_alsa_get_caps), (gst_alsa_link):
+	  Fix remaining caps handling errors due to CAPS merge.
+
+2003-12-22  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+	* ext/faad/gstfaad.c: (gst_faad_base_init), (gst_faad_init),
+	(gst_faad_sinkconnect), (gst_faad_srcgetcaps),
+	(gst_faad_srcconnect):
+	  Port to new caps system.
+
+2003-12-21  Julien MOUTTE  <julien@moutte.net>
+
+	* examples/gstplay/player.c: (got_time_tick), (got_stream_length),
+	(got_video_size), (main): using g_print instead of g_message.
+	* gst-libs/gst/play/gstplay.c: (gst_play_pipeline_setup): Fixing EOS
+	signal which was not emitted because of "switch" element added to the
+	bin but not connected. (Removing from the bin temporarily)
+
+2003-12-21  Julien MOUTTE  <julien@moutte.net>
+
+	* configure.ac: X_DISPLAY_MISSING is set to 1 if AC_PATH_XTRA fails to
+	find X development files. I don't understand the previous tests and
+	they fail on my debian/ppc unstable. This one works.
+	* examples/gstplay/player.c: (main): Set the pipeline to READY before
+	exiting.
+	* gst-libs/gst/play/gstplay.c: (gst_play_get_length_callback),
+	(gst_play_set_video_sink), (gst_play_set_audio_sink),
+	(gst_play_set_visualization): Add some safety checks in set_ methods
+	and state_change. This was throwing some ugly CRITICAL messages when
+	pipeline was getting disposed and casts were failing.
+
+2003-12-21  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+	* configure.ac:
+	  Improve mpeg2enc detection. This is for distributions that do
+	  ship mjpegtools, but without mpeg2enc. Also does object check
+	  for might there ever be ABI incompatibility.
+	* ext/mpeg2enc/gstmpeg2enc.cc:
+	  Add Andrew as second maintainer (he's helping me), and also add
+	  an error if no caps was set. This happens if I pull before capsnego
+	  and that's something I should solve sometime else.
+	* gst/matroska/matroska-demux.c:
+	(gst_matroska_demux_parse_blockgroup):
+	  Fix time parsing.
+	* gst/matroska/matroska-mux.c: (gst_matroska_mux_audio_pad_link),
+	(gst_matroska_mux_track_header):
+	  Add caps to templates.
+	* gst/mpegaudioparse/gstmpegaudioparse.c: (mp3_sink_factory):
+	  Add mpegversion=1 to prevent confusion with MPEG/AAC.
+	* gst/mpegstream/gstmpegdemux.c:
+	  Remove layer since it causes warnings about unfixed caps.
+	* gst/videotestsrc/gstvideotestsrc.c: (gst_videotestsrc_get):
+	  Fix obvious typo (we error out if caps were set, we should of
+	  course error out if *no* caps were set).
+	* sys/oss/gstosselement.c: (gst_osselement_convert):
+	  Fix format conversion, we confused bits/bytes.
+	* sys/oss/gstosselement.h:
+	  Improve documentation for 'bps'.
+	* sys/v4l/TODO:
+	  Remove stuff about plugins that need removing - this was done
+	  ages ago.
+	* sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_init),
+	(gst_v4lmjpegsrc_src_convert), (gst_v4lmjpegsrc_src_query):
+	* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_init), (gst_v4lsrc_src_convert),
+	(gst_v4lsrc_src_query):
+	* sys/v4l2/gstv4l2src.c: (gst_v4l2src_init),
+	(gst_v4l2src_src_convert), (gst_v4l2src_src_query):
+	  Add get_query_types(), get_formats() and query() functions.
+
+2003-12-21  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* ChangeLog: moved to gstreamer/docs/random/old/ChangeLog.gst-plugins
+        * moved CVS to freedesktop.org
+
diff --git a/docs/random/PORTED_09 b/docs/random/PORTED_09
new file mode 100644
index 0000000..f96297d
--- /dev/null
+++ b/docs/random/PORTED_09
@@ -0,0 +1,20 @@
+When porting a plugin start with 0.8 CVS head, not the old code in this module. There are many bugfixes which have gone into 0.8 which you want to keep.
+
+List of ported plugins (update when you commit a ported plugin):
+speexenc (alima)
+auparse (alima)
+effectv (wim)
+mad	(wim)
+videofilter (wim)
+aalib	(wim)
+libcaca	(zeeshan)
+law	(wim)
+shout2  (zaheer) - not fully tested
+esdsink (arwed)
+multipart (dolphy)
+
+osssink is partially done in the threaded branch (wim)
+
+- Remember that some plugins are already ported and now in the gst-plugins-base module.
+
+When you have ported a plugin remember to copy the relevant parts from configure.ac.orig into configure.ac and re-enable it in the Makefile.am files.
diff --git a/docs/version.entities.in b/docs/version.entities.in
new file mode 100644
index 0000000..286989f
--- /dev/null
+++ b/docs/version.entities.in
@@ -0,0 +1,2 @@
+<!ENTITY GST_API_VERSION "@GST_API_VERSION@">
+<!ENTITY GST_VERSION "@VERSION@">
diff --git a/ext/Makefile.am b/ext/Makefile.am
new file mode 100644
index 0000000..7d34902
--- /dev/null
+++ b/ext/Makefile.am
@@ -0,0 +1,167 @@
+if USE_AALIB
+AALIB_DIR = aalib
+else
+AALIB_DIR =
+endif
+
+if USE_CAIRO
+CAIRO_DIR = cairo
+else
+CAIRO_DIR =
+endif
+
+if USE_FLAC
+FLAC_DIR = flac
+else
+FLAC_DIR =
+endif
+
+if USE_GDK_PIXBUF
+GDK_PIXBUF_DIR = gdk_pixbuf
+else
+GDK_PIXBUF_DIR =
+endif
+
+if USE_JACK
+JACK_DIR=jack
+else
+JACK_DIR=
+endif
+
+if USE_JPEG
+JPEG_DIR = jpeg
+else
+JPEG_DIR =
+endif
+
+if USE_LAME
+LAME_DIR = lame
+else
+LAME_DIR =
+endif
+
+if USE_LIBCACA
+LIBCACA_DIR = libcaca
+else
+LIBCACA_DIR =
+endif
+
+if USE_LIBDV
+LIBDV_DIR = dv
+else
+LIBDV_DIR =
+endif
+
+if USE_LIBPNG
+LIBPNG_DIR = libpng
+else
+LIBPNG_DIR =
+endif
+
+if USE_MPG123
+MPG123_DIR = mpg123
+else
+MPG123_DIR =
+endif
+
+if USE_DV1394
+DV1394_DIR = raw1394
+else
+DV1394_DIR =
+endif
+
+if USE_PULSE
+PULSE_DIR = pulse
+else
+PULSE_DIR =
+endif
+
+
+if USE_SHOUT2
+SHOUT2_DIR = shout2
+else
+SHOUT2_DIR =
+endif
+
+if USE_SOUP
+SOUP_DIR=soup
+else
+SOUP_DIR=
+endif
+
+if USE_SPEEX
+SPEEX_DIR = speex
+else
+SPEEX_DIR =
+endif
+
+if USE_TAGLIB
+TAGLIB_DIR = taglib
+else
+TAGLIB_DIR =
+endif
+
+if USE_TWOLAME
+TWOLAME_DIR = twolame
+else
+TWOLAME_DIR =
+endif
+
+if USE_VPX
+VPX_DIR=vpx
+else
+VPX_DIR=
+endif
+
+if USE_WAVPACK
+WAVPACK_DIR=wavpack
+else
+WAVPACK_DIR=
+endif
+
+SUBDIRS = \
+	$(AALIB_DIR) \
+	$(CAIRO_DIR) \
+	$(DV1394_DIR) \
+	$(FLAC_DIR) \
+	$(GDK_PIXBUF_DIR) \
+	$(JACK_DIR) \
+	$(JPEG_DIR) \
+	$(LAME_DIR) \
+	$(LIBCACA_DIR) \
+	$(LIBDV_DIR) \
+	$(LIBMNG_DIR) \
+	$(LIBPNG_DIR) \
+	$(MPG123_DIR) \
+	$(PULSE_DIR) \
+	$(SHOUT2_DIR) \
+	$(SOUP_DIR) \
+	$(SPEEX_DIR) \
+	$(TAGLIB_DIR) \
+	$(TWOLAME_DIR) \
+	$(VPX_DIR) \
+	$(WAVPACK_DIR)
+
+DIST_SUBDIRS = \
+	aalib \
+	cairo \
+	dv \
+	flac \
+	gdk_pixbuf \
+	jack \
+	jpeg \
+	lame \
+	libcaca \
+	libpng \
+	mpg123 \
+	pulse \
+	raw1394 \
+	shout2 \
+	soup \
+	speex \
+	taglib \
+	twolame \
+	vpx \
+	wavpack
+
+include $(top_srcdir)/common/parallel-subdirs.mak
diff --git a/ext/aalib/Makefile.am b/ext/aalib/Makefile.am
new file mode 100644
index 0000000..41b66eb
--- /dev/null
+++ b/ext/aalib/Makefile.am
@@ -0,0 +1,8 @@
+plugin_LTLIBRARIES = libgstaasink.la
+
+libgstaasink_la_SOURCES = gstaasink.c
+libgstaasink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AALIB_CFLAGS)
+libgstaasink_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) $(GST_BASE_LIBS) $(GST_LIBS) $(AALIB_LIBS)
+libgstaasink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstaasink.h
diff --git a/ext/aalib/gstaasink.c b/ext/aalib/gstaasink.c
new file mode 100644
index 0000000..880e479
--- /dev/null
+++ b/ext/aalib/gstaasink.c
@@ -0,0 +1,595 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-aasink
+ * @see_also: #GstCACASink
+ *
+ * Displays video as b/w ascii art.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=test.avi ! decodebin ! videoconvert ! aasink
+ * ]| This pipeline renders a video to ascii art into a separate window.
+ * |[
+ * gst-launch-1.0 filesrc location=test.avi ! decodebin ! videoconvert ! aasink driver=curses
+ * ]| This pipeline renders a video to ascii art into the current terminal.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <sys/time.h>
+
+#include <gst/video/gstvideometa.h>
+#include "gstaasink.h"
+
+/* aasink signals and args */
+enum
+{
+  LAST_SIGNAL
+};
+
+
+enum
+{
+  PROP_0,
+  PROP_WIDTH,
+  PROP_HEIGHT,
+  PROP_DRIVER,
+  PROP_DITHER,
+  PROP_BRIGHTNESS,
+  PROP_CONTRAST,
+  PROP_GAMMA,
+  PROP_INVERSION,
+  PROP_RANDOMVAL,
+  PROP_FRAMES_DISPLAYED,
+  PROP_FRAME_TIME
+};
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420"))
+    );
+
+static GstCaps *gst_aasink_fixate (GstBaseSink * bsink, GstCaps * caps);
+static gboolean gst_aasink_setcaps (GstBaseSink * bsink, GstCaps * caps);
+static void gst_aasink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
+    GstClockTime * start, GstClockTime * end);
+static gboolean gst_aasink_propose_allocation (GstBaseSink * bsink,
+    GstQuery * query);
+static GstFlowReturn gst_aasink_show_frame (GstVideoSink * videosink,
+    GstBuffer * buffer);
+
+static void gst_aasink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_aasink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn gst_aasink_change_state (GstElement * element,
+    GstStateChange transition);
+
+#define gst_aasink_parent_class parent_class
+G_DEFINE_TYPE (GstAASink, gst_aasink, GST_TYPE_VIDEO_SINK);
+
+#define GST_TYPE_AADRIVERS (gst_aasink_drivers_get_type())
+static GType
+gst_aasink_drivers_get_type (void)
+{
+  static GType driver_type = 0;
+
+  if (!driver_type) {
+    GEnumValue *drivers;
+    const struct aa_driver *driver;
+    gint n_drivers;
+    gint i;
+
+    for (n_drivers = 0; aa_drivers[n_drivers]; n_drivers++) {
+      /* count number of drivers */
+    }
+
+    drivers = g_new0 (GEnumValue, n_drivers + 1);
+
+    for (i = 0; i < n_drivers; i++) {
+      driver = aa_drivers[i];
+      drivers[i].value = i;
+      drivers[i].value_name = g_strdup (driver->name);
+      drivers[i].value_nick = g_utf8_strdown (driver->shortname, -1);
+    }
+    drivers[i].value = 0;
+    drivers[i].value_name = NULL;
+    drivers[i].value_nick = NULL;
+
+    driver_type = g_enum_register_static ("GstAASinkDrivers", drivers);
+  }
+  return driver_type;
+}
+
+#define GST_TYPE_AADITHER (gst_aasink_dither_get_type())
+static GType
+gst_aasink_dither_get_type (void)
+{
+  static GType dither_type = 0;
+
+  if (!dither_type) {
+    GEnumValue *ditherers;
+    gint n_ditherers;
+    gint i;
+
+    for (n_ditherers = 0; aa_dithernames[n_ditherers]; n_ditherers++) {
+      /* count number of ditherers */
+    }
+
+    ditherers = g_new0 (GEnumValue, n_ditherers + 1);
+
+    for (i = 0; i < n_ditherers; i++) {
+      ditherers[i].value = i;
+      ditherers[i].value_name = g_strdup (aa_dithernames[i]);
+      ditherers[i].value_nick =
+          g_strdelimit (g_strdup (aa_dithernames[i]), " _", '-');
+    }
+    ditherers[i].value = 0;
+    ditherers[i].value_name = NULL;
+    ditherers[i].value_nick = NULL;
+
+    dither_type = g_enum_register_static ("GstAASinkDitherers", ditherers);
+  }
+  return dither_type;
+}
+
+static void
+gst_aasink_class_init (GstAASinkClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSinkClass *gstbasesink_class;
+  GstVideoSinkClass *gstvideosink_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesink_class = (GstBaseSinkClass *) klass;
+  gstvideosink_class = (GstVideoSinkClass *) klass;
+
+  gobject_class->set_property = gst_aasink_set_property;
+  gobject_class->get_property = gst_aasink_get_property;
+
+  /* FIXME: add long property descriptions */
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_WIDTH,
+      g_param_spec_int ("width", "width", "width", G_MININT, G_MAXINT, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HEIGHT,
+      g_param_spec_int ("height", "height", "height", G_MININT, G_MAXINT, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DRIVER,
+      g_param_spec_enum ("driver", "driver", "driver", GST_TYPE_AADRIVERS, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DITHER,
+      g_param_spec_enum ("dither", "dither", "dither", GST_TYPE_AADITHER, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BRIGHTNESS,
+      g_param_spec_int ("brightness", "brightness", "brightness", G_MININT,
+          G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CONTRAST,
+      g_param_spec_int ("contrast", "contrast", "contrast", G_MININT, G_MAXINT,
+          0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_GAMMA,
+      g_param_spec_float ("gamma", "gamma", "gamma", 0.0, 5.0, 1.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_INVERSION,
+      g_param_spec_boolean ("inversion", "inversion", "inversion", TRUE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_RANDOMVAL,
+      g_param_spec_int ("randomval", "randomval", "randomval", G_MININT,
+          G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_FRAMES_DISPLAYED, g_param_spec_int ("frames-displayed",
+          "frames displayed", "frames displayed", G_MININT, G_MAXINT, 0,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FRAME_TIME,
+      g_param_spec_int ("frame-time", "frame time", "frame time", G_MININT,
+          G_MAXINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "ASCII art video sink", "Sink/Video", "An ASCII art videosink",
+      "Wim Taymans <wim.taymans@chello.be>");
+
+  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_aasink_change_state);
+
+  gstbasesink_class->fixate = GST_DEBUG_FUNCPTR (gst_aasink_fixate);
+  gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_aasink_setcaps);
+  gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_aasink_get_times);
+  gstbasesink_class->propose_allocation =
+      GST_DEBUG_FUNCPTR (gst_aasink_propose_allocation);
+
+  gstvideosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_aasink_show_frame);
+}
+
+static GstCaps *
+gst_aasink_fixate (GstBaseSink * bsink, GstCaps * caps)
+{
+  GstStructure *structure;
+
+  caps = gst_caps_make_writable (caps);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  gst_structure_fixate_field_nearest_int (structure, "width", 320);
+  gst_structure_fixate_field_nearest_int (structure, "height", 240);
+  gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1);
+
+  caps = GST_BASE_SINK_CLASS (parent_class)->fixate (bsink, caps);
+
+  return caps;
+}
+
+static gboolean
+gst_aasink_setcaps (GstBaseSink * basesink, GstCaps * caps)
+{
+  GstAASink *aasink;
+  GstVideoInfo info;
+
+  aasink = GST_AASINK (basesink);
+
+  if (!gst_video_info_from_caps (&info, caps))
+    goto invalid_caps;
+
+  aasink->info = info;
+
+  return TRUE;
+
+  /* ERRORS */
+invalid_caps:
+  {
+    GST_DEBUG_OBJECT (aasink, "invalid caps");
+    return FALSE;
+  }
+}
+
+static void
+gst_aasink_init (GstAASink * aasink)
+{
+  memcpy (&aasink->ascii_surf, &aa_defparams,
+      sizeof (struct aa_hardware_params));
+  aasink->ascii_parms.bright = 0;
+  aasink->ascii_parms.contrast = 16;
+  aasink->ascii_parms.gamma = 1.0;
+  aasink->ascii_parms.dither = 0;
+  aasink->ascii_parms.inversion = 0;
+  aasink->ascii_parms.randomval = 0;
+  aasink->aa_driver = 0;
+}
+
+static void
+gst_aasink_scale (GstAASink * aasink, guchar * src, guchar * dest,
+    gint sw, gint sh, gint ss, gint dw, gint dh)
+{
+  gint ypos, yinc, y;
+  gint xpos, xinc, x;
+
+  g_return_if_fail ((dw != 0) && (dh != 0));
+
+  ypos = 0x10000;
+  yinc = (sh << 16) / dh;
+  xinc = (sw << 16) / dw;
+
+  for (y = dh; y; y--) {
+    while (ypos > 0x10000) {
+      ypos -= 0x10000;
+      src += ss;
+    }
+    xpos = 0x10000;
+    {
+      guchar *destp = dest;
+      guchar *srcp = src;
+
+      for (x = dw; x; x--) {
+        while (xpos >= 0x10000L) {
+          srcp++;
+          xpos -= 0x10000L;
+        }
+        *destp++ = *srcp;
+        xpos += xinc;
+      }
+    }
+    dest += dw;
+    ypos += yinc;
+  }
+}
+
+static void
+gst_aasink_get_times (GstBaseSink * sink, GstBuffer * buffer,
+    GstClockTime * start, GstClockTime * end)
+{
+  *start = GST_BUFFER_TIMESTAMP (buffer);
+  if (GST_BUFFER_DURATION_IS_VALID (buffer))
+    *end = *start + GST_BUFFER_DURATION (buffer);
+}
+
+static gboolean
+gst_aasink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
+{
+  GstCaps *caps;
+  GstVideoInfo info;
+  guint size;
+
+  gst_query_parse_allocation (query, &caps, NULL);
+
+  if (caps == NULL)
+    goto no_caps;
+
+  if (!gst_video_info_from_caps (&info, caps))
+    goto invalid_caps;
+
+  size = GST_VIDEO_INFO_SIZE (&info);
+
+  /* we need at least 2 buffer because we hold on to the last one */
+  gst_query_add_allocation_pool (query, NULL, size, 2, 0);
+
+  /* we support various metadata */
+  gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
+
+  return TRUE;
+
+  /* ERRORS */
+no_caps:
+  {
+    GST_DEBUG_OBJECT (bsink, "no caps specified");
+    return FALSE;
+  }
+invalid_caps:
+  {
+    GST_DEBUG_OBJECT (bsink, "invalid caps specified");
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_aasink_show_frame (GstVideoSink * videosink, GstBuffer * buffer)
+{
+  GstAASink *aasink;
+  GstVideoFrame frame;
+
+  aasink = GST_AASINK (videosink);
+
+  GST_DEBUG ("show frame");
+
+  if (!gst_video_frame_map (&frame, &aasink->info, buffer, GST_MAP_READ))
+    goto invalid_frame;
+
+  gst_aasink_scale (aasink, GST_VIDEO_FRAME_PLANE_DATA (&frame, 0),     /* src */
+      aa_image (aasink->context),       /* dest */
+      GST_VIDEO_INFO_WIDTH (&aasink->info),     /* sw */
+      GST_VIDEO_INFO_HEIGHT (&aasink->info),    /* sh */
+      GST_VIDEO_FRAME_PLANE_STRIDE (&frame, 0), /* ss */
+      aa_imgwidth (aasink->context),    /* dw */
+      aa_imgheight (aasink->context));  /* dh */
+
+  aa_render (aasink->context, &aasink->ascii_parms,
+      0, 0, aa_imgwidth (aasink->context), aa_imgheight (aasink->context));
+  aa_flush (aasink->context);
+  aa_getevent (aasink->context, FALSE);
+  gst_video_frame_unmap (&frame);
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+invalid_frame:
+  {
+    GST_DEBUG_OBJECT (aasink, "invalid frame");
+    return GST_FLOW_ERROR;
+  }
+}
+
+
+static void
+gst_aasink_set_property (GObject * object, guint prop_id, const GValue * value,
+    GParamSpec * pspec)
+{
+  GstAASink *aasink;
+
+  aasink = GST_AASINK (object);
+
+  switch (prop_id) {
+    case PROP_WIDTH:
+      aasink->ascii_surf.width = g_value_get_int (value);
+      break;
+    case PROP_HEIGHT:
+      aasink->ascii_surf.height = g_value_get_int (value);
+      break;
+    case PROP_DRIVER:{
+      aasink->aa_driver = g_value_get_enum (value);
+      break;
+    }
+    case PROP_DITHER:{
+      aasink->ascii_parms.dither = g_value_get_enum (value);
+      break;
+    }
+    case PROP_BRIGHTNESS:{
+      aasink->ascii_parms.bright = g_value_get_int (value);
+      break;
+    }
+    case PROP_CONTRAST:{
+      aasink->ascii_parms.contrast = g_value_get_int (value);
+      break;
+    }
+    case PROP_GAMMA:{
+      aasink->ascii_parms.gamma = g_value_get_float (value);
+      break;
+    }
+    case PROP_INVERSION:{
+      aasink->ascii_parms.inversion = g_value_get_boolean (value);
+      break;
+    }
+    case PROP_RANDOMVAL:{
+      aasink->ascii_parms.randomval = g_value_get_int (value);
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+static void
+gst_aasink_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstAASink *aasink;
+
+  aasink = GST_AASINK (object);
+
+  switch (prop_id) {
+    case PROP_WIDTH:{
+      g_value_set_int (value, aasink->ascii_surf.width);
+      break;
+    }
+    case PROP_HEIGHT:{
+      g_value_set_int (value, aasink->ascii_surf.height);
+      break;
+    }
+    case PROP_DRIVER:{
+      g_value_set_enum (value, aasink->aa_driver);
+      break;
+    }
+    case PROP_DITHER:{
+      g_value_set_enum (value, aasink->ascii_parms.dither);
+      break;
+    }
+    case PROP_BRIGHTNESS:{
+      g_value_set_int (value, aasink->ascii_parms.bright);
+      break;
+    }
+    case PROP_CONTRAST:{
+      g_value_set_int (value, aasink->ascii_parms.contrast);
+      break;
+    }
+    case PROP_GAMMA:{
+      g_value_set_float (value, aasink->ascii_parms.gamma);
+      break;
+    }
+    case PROP_INVERSION:{
+      g_value_set_boolean (value, aasink->ascii_parms.inversion);
+      break;
+    }
+    case PROP_RANDOMVAL:{
+      g_value_set_int (value, aasink->ascii_parms.randomval);
+      break;
+    }
+    case PROP_FRAMES_DISPLAYED:{
+      g_value_set_int (value, aasink->frames_displayed);
+      break;
+    }
+    case PROP_FRAME_TIME:{
+      g_value_set_int (value, aasink->frame_time / 1000000);
+      break;
+    }
+    default:{
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+  }
+}
+
+static gboolean
+gst_aasink_open (GstAASink * aasink)
+{
+  if (!aasink->context) {
+    aa_recommendhidisplay (aa_drivers[aasink->aa_driver]->shortname);
+
+    aasink->context = aa_autoinit (&aasink->ascii_surf);
+    if (aasink->context == NULL) {
+      GST_ELEMENT_ERROR (GST_ELEMENT (aasink), LIBRARY, TOO_LAZY, (NULL),
+          ("error opening aalib context"));
+      return FALSE;
+    }
+    aa_autoinitkbd (aasink->context, 0);
+    aa_resizehandler (aasink->context, (void *) aa_resize);
+  }
+  return TRUE;
+}
+
+static gboolean
+gst_aasink_close (GstAASink * aasink)
+{
+  aa_close (aasink->context);
+  aasink->context = NULL;
+
+  return TRUE;
+}
+
+static GstStateChangeReturn
+gst_aasink_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      if (!gst_aasink_open (GST_AASINK (element)))
+        goto open_failed;
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      gst_aasink_close (GST_AASINK (element));
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+
+open_failed:
+  {
+    return GST_STATE_CHANGE_FAILURE;
+  }
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "aasink", GST_RANK_NONE, GST_TYPE_AASINK))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    aasink,
+    "ASCII Art video sink",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/ext/aalib/gstaasink.h b/ext/aalib/gstaasink.h
new file mode 100644
index 0000000..6386c25
--- /dev/null
+++ b/ext/aalib/gstaasink.h
@@ -0,0 +1,75 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_AASINK_H__
+#define __GST_AASINK_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideosink.h>
+
+#include <aalib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_AASINK \
+  (gst_aasink_get_type())
+#define GST_AASINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AASINK,GstAASink))
+#define GST_AASINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AASINK,GstAASinkClass))
+#define GST_IS_AASINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AASINK))
+#define GST_IS_AASINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AASINK))
+
+typedef struct _GstAASink GstAASink;
+typedef struct _GstAASinkClass GstAASinkClass;
+
+struct _GstAASink {
+  GstVideoSink parent;
+
+  GstVideoInfo info;
+
+  gint frames_displayed;
+  guint64 frame_time;
+
+  aa_context *context;
+  struct aa_hardware_params ascii_surf;
+  struct aa_renderparams ascii_parms;
+  aa_palette palette;
+  gint aa_driver;
+};
+
+struct _GstAASinkClass {
+  GstVideoSinkClass parent_class;
+};
+
+GType gst_aasink_get_type(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_AASINKE_H__ */
diff --git a/ext/aalib/meson.build b/ext/aalib/meson.build
new file mode 100644
index 0000000..12cdf72
--- /dev/null
+++ b/ext/aalib/meson.build
@@ -0,0 +1,14 @@
+# Very much not going to implement all kinds of logic around aalib-config
+# or cater for non-standard prefixes.
+if cc.has_header('aalib.h')
+  libaa_dep = cc.find_library('aa', required : false)
+  if libaa_dep.found()
+    library('gstaasink', 'gstaasink.c',
+      c_args : gst_plugins_good_args,
+      link_args : noseh_link_args,
+      include_directories : [configinc],
+      dependencies : [gstvideo_dep, gstbase_dep, libaa_dep],
+      install : true,
+      install_dir : plugins_install_dir)
+  endif
+endif
diff --git a/ext/cairo/Makefile.am b/ext/cairo/Makefile.am
new file mode 100644
index 0000000..8a37110
--- /dev/null
+++ b/ext/cairo/Makefile.am
@@ -0,0 +1,16 @@
+plugin_LTLIBRARIES = libgstcairo.la
+
+noinst_HEADERS = \
+	gstcairooverlay.h
+libgstcairo_la_SOURCES = \
+	gstcairo.c \
+	gstcairooverlay.c
+libgstcairo_la_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS) $(CAIRO_CFLAGS)
+libgstcairo_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) $(GST_LIBS) $(CAIRO_LIBS) $(LIBM)
+libgstcairo_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
diff --git a/ext/cairo/gstcairo.c b/ext/cairo/gstcairo.c
new file mode 100644
index 0000000..5b94387
--- /dev/null
+++ b/ext/cairo/gstcairo.c
@@ -0,0 +1,45 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003,2004> David Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gstcairooverlay.h>
+
+#include <string.h>
+#include <math.h>
+
+GST_DEBUG_CATEGORY (cairo_debug);
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  gst_element_register (plugin, "cairooverlay", GST_RANK_NONE,
+      GST_TYPE_CAIRO_OVERLAY);
+
+  GST_DEBUG_CATEGORY_INIT (cairo_debug, "cairo", 0, "Cairo elements");
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, cairo,
+    "Cairo-based elements", plugin_init, VERSION,
+    GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/ext/cairo/gstcairooverlay.c b/ext/cairo/gstcairooverlay.c
new file mode 100644
index 0000000..9aa4c53
--- /dev/null
+++ b/ext/cairo/gstcairooverlay.c
@@ -0,0 +1,255 @@
+/* GStreamer
+ * Copyright (C) <2011> Jon Nordby <jononor@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-cairooverlay
+ *
+ * cairooverlay renders an overlay using a application provided render function.
+ *
+ * The full example can be found in tests/examples/cairo/cairo_overlay.c
+ * <refsect2>
+ * <title>Example code</title>
+ * |[
+ *
+ * #include &lt;gst/gst.h&gt;
+ * #include &lt;gst/video/video.h&gt;
+ *
+ * ...
+ *
+ * typedef struct {
+ *   gboolean valid;
+ *   int width;
+ *   int height;
+ * } CairoOverlayState;
+ * 
+ * ...
+ *
+ * static void
+ * prepare_overlay (GstElement * overlay, GstCaps * caps, gpointer user_data)
+ * {
+ *   CairoOverlayState *state = (CairoOverlayState *)user_data;
+ *
+ *   gst_video_format_parse_caps (caps, NULL, &amp;state-&gt;width, &amp;state-&gt;height);
+ *   state-&gt;valid = TRUE;
+ * }
+ *
+ * static void
+ * draw_overlay (GstElement * overlay, cairo_t * cr, guint64 timestamp, 
+ *   guint64 duration, gpointer user_data)
+ * {
+ *   CairoOverlayState *s = (CairoOverlayState *)user_data;
+ *   double scale;
+ *
+ *   if (!s-&gt;valid)
+ *     return;
+ *
+ *   scale = 2*(((timestamp/(int)1e7) % 70)+30)/100.0;
+ *   cairo_translate(cr, s-&gt;width/2, (s-&gt;height/2)-30);
+ *   cairo_scale (cr, scale, scale);
+ *
+ *   cairo_move_to (cr, 0, 0);
+ *   cairo_curve_to (cr, 0,-30, -50,-30, -50,0);
+ *   cairo_curve_to (cr, -50,30, 0,35, 0,60 );
+ *   cairo_curve_to (cr, 0,35, 50,30, 50,0 ); *  
+ *   cairo_curve_to (cr, 50,-30, 0,-30, 0,0 );
+ *   cairo_set_source_rgba (cr, 0.9, 0.0, 0.1, 0.7);
+ *   cairo_fill (cr);
+ * }
+ *
+ * ...
+ *
+ * cairo_overlay = gst_element_factory_make (&quot;cairooverlay&quot;, &quot;overlay&quot;);
+ *
+ * g_signal_connect (cairo_overlay, &quot;draw&quot;, G_CALLBACK (draw_overlay),
+ *   overlay_state);
+ * g_signal_connect (cairo_overlay, &quot;caps-changed&quot;, 
+ *   G_CALLBACK (prepare_overlay), overlay_state);
+ * ...
+ *
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstcairooverlay.h"
+
+#include <gst/video/video.h>
+
+#include <cairo.h>
+
+/* RGB16 is native-endianness in GStreamer */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define TEMPLATE_CAPS GST_VIDEO_CAPS_MAKE("{ BGRx, BGRA, RGB16 }")
+#else
+#define TEMPLATE_CAPS GST_VIDEO_CAPS_MAKE("{ xRGB, ARGB, RGB16 }")
+#endif
+
+static GstStaticPadTemplate gst_cairo_overlay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (TEMPLATE_CAPS)
+    );
+
+static GstStaticPadTemplate gst_cairo_overlay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (TEMPLATE_CAPS)
+    );
+
+G_DEFINE_TYPE (GstCairoOverlay, gst_cairo_overlay, GST_TYPE_VIDEO_FILTER);
+
+enum
+{
+  SIGNAL_DRAW,
+  SIGNAL_CAPS_CHANGED,
+  N_SIGNALS
+};
+
+static guint gst_cairo_overlay_signals[N_SIGNALS];
+
+static gboolean
+gst_cairo_overlay_set_info (GstVideoFilter * vfilter, GstCaps * in_caps,
+    GstVideoInfo * in_info, GstCaps * out_caps, GstVideoInfo * out_info)
+{
+  GstCairoOverlay *overlay = GST_CAIRO_OVERLAY (vfilter);
+
+  g_signal_emit (overlay, gst_cairo_overlay_signals[SIGNAL_CAPS_CHANGED], 0,
+      in_caps, NULL);
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_cairo_overlay_transform_frame_ip (GstVideoFilter * vfilter,
+    GstVideoFrame * frame)
+{
+  GstCairoOverlay *overlay = GST_CAIRO_OVERLAY (vfilter);
+  cairo_surface_t *surface;
+  cairo_t *cr;
+  cairo_format_t format;
+
+  switch (GST_VIDEO_FRAME_FORMAT (frame)) {
+    case GST_VIDEO_FORMAT_ARGB:
+    case GST_VIDEO_FORMAT_BGRA:
+      format = CAIRO_FORMAT_ARGB32;
+      break;
+    case GST_VIDEO_FORMAT_xRGB:
+    case GST_VIDEO_FORMAT_BGRx:
+      format = CAIRO_FORMAT_RGB24;
+      break;
+    case GST_VIDEO_FORMAT_RGB16:
+      format = CAIRO_FORMAT_RGB16_565;
+      break;
+    default:
+    {
+      GST_WARNING ("No matching cairo format for %s",
+          gst_video_format_to_string (GST_VIDEO_FRAME_FORMAT (frame)));
+      return GST_FLOW_ERROR;
+    }
+  }
+
+  surface =
+      cairo_image_surface_create_for_data (GST_VIDEO_FRAME_PLANE_DATA (frame,
+          0), format, GST_VIDEO_FRAME_WIDTH (frame),
+      GST_VIDEO_FRAME_HEIGHT (frame), GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0));
+
+  if (G_UNLIKELY (!surface))
+    return GST_FLOW_ERROR;
+
+  cr = cairo_create (surface);
+  if (G_UNLIKELY (!cr)) {
+    cairo_surface_destroy (surface);
+    return GST_FLOW_ERROR;
+  }
+
+  g_signal_emit (overlay, gst_cairo_overlay_signals[SIGNAL_DRAW], 0,
+      cr, GST_BUFFER_PTS (frame->buffer), GST_BUFFER_DURATION (frame->buffer),
+      NULL);
+
+  cairo_destroy (cr);
+  cairo_surface_destroy (surface);
+
+  return GST_FLOW_OK;
+}
+
+static void
+gst_cairo_overlay_class_init (GstCairoOverlayClass * klass)
+{
+  GstVideoFilterClass *vfilter_class;
+  GstElementClass *element_class;
+
+  vfilter_class = (GstVideoFilterClass *) klass;
+  element_class = (GstElementClass *) klass;
+
+  vfilter_class->set_info = gst_cairo_overlay_set_info;
+  vfilter_class->transform_frame_ip = gst_cairo_overlay_transform_frame_ip;
+
+  /**
+   * GstCairoOverlay::draw:
+   * @overlay: Overlay element emitting the signal.
+   * @cr: Cairo context to draw to.
+   * @timestamp: Timestamp (see #GstClockTime) of the current buffer.
+   * @duration: Duration (see #GstClockTime) of the current buffer.
+   * 
+   * This signal is emitted when the overlay should be drawn.
+   */
+  gst_cairo_overlay_signals[SIGNAL_DRAW] =
+      g_signal_new ("draw",
+      G_TYPE_FROM_CLASS (klass),
+      0,
+      0,
+      NULL,
+      NULL,
+      g_cclosure_marshal_generic,
+      G_TYPE_NONE, 3, CAIRO_GOBJECT_TYPE_CONTEXT, G_TYPE_UINT64, G_TYPE_UINT64);
+
+  /**
+   * GstCairoOverlay::caps-changed:
+   * @overlay: Overlay element emitting the signal.
+   * @caps: The #GstCaps of the element.
+   * 
+   * This signal is emitted when the caps of the element has changed.
+   */
+  gst_cairo_overlay_signals[SIGNAL_CAPS_CHANGED] =
+      g_signal_new ("caps-changed",
+      G_TYPE_FROM_CLASS (klass),
+      0,
+      0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_CAPS);
+
+  gst_element_class_set_static_metadata (element_class, "Cairo overlay",
+      "Filter/Editor/Video",
+      "Render overlay on a video stream using Cairo",
+      "Jon Nordby <jononor@gmail.com>");
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_cairo_overlay_sink_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_cairo_overlay_src_template);
+}
+
+static void
+gst_cairo_overlay_init (GstCairoOverlay * overlay)
+{
+  /* nothing to do */
+}
diff --git a/ext/cairo/gstcairooverlay.h b/ext/cairo/gstcairooverlay.h
new file mode 100644
index 0000000..9c67a7b
--- /dev/null
+++ b/ext/cairo/gstcairooverlay.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) <2011> Jon Nordby <jononor@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_CAIRO_OVERLAY_H__
+#define __GST_CAIRO_OVERLAY_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+#include <cairo.h>
+#include <cairo-gobject.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CAIRO_OVERLAY \
+  (gst_cairo_overlay_get_type())
+#define GST_CAIRO_OVERLAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAIRO_OVERLAY,GstCairoOverlay))
+#define GST_CAIRO_OVERLAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAIRO_OVERLAY,GstCairoOverlayClass))
+#define GST_IS_CAIRO_OVERLAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAIRO_OVERLAY))
+#define GST_IS_CAIRO_OVERLAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAIRO_OVERLAY))
+
+typedef struct _GstCairoOverlay GstCairoOverlay;
+typedef struct _GstCairoOverlayClass GstCairoOverlayClass;
+
+struct _GstCairoOverlay {
+  GstVideoFilter video_filter;
+};
+
+struct _GstCairoOverlayClass {
+  GstVideoFilterClass video_filter_class;
+};
+
+GType gst_cairo_overlay_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_CAIRO_OVERLAY_H__ */
diff --git a/ext/cairo/meson.build b/ext/cairo/meson.build
new file mode 100644
index 0000000..9601bc7
--- /dev/null
+++ b/ext/cairo/meson.build
@@ -0,0 +1,13 @@
+cairo_dep = dependency('cairo-gobject', version : '>=1.10.0', required : false)
+
+if cairo_dep.found()
+  gstcairo = library('gstcairo',
+    'gstcairo.c', 'gstcairooverlay.c',
+    c_args : gst_plugins_good_args,
+    link_args : noseh_link_args,
+    include_directories : [configinc],
+    dependencies : [gstbase_dep, gstvideo_dep, cairo_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/ext/dv/Makefile.am b/ext/dv/Makefile.am
new file mode 100644
index 0000000..73d19f6
--- /dev/null
+++ b/ext/dv/Makefile.am
@@ -0,0 +1,19 @@
+plugin_LTLIBRARIES = libgstdv.la
+
+libgstdv_la_SOURCES = gstdv.c gstdvdec.c gstdvdemux.c gstsmptetimecode.c
+libgstdv_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(LIBDV_CFLAGS)
+libgstdv_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) -lgstvideo-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) $(GST_LIBS) $(LIBDV_LIBS)
+libgstdv_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstdvdemux.h gstdvdec.h gstsmptetimecode.h
+
+EXTRA_DIST = NOTES
+
+noinst_PROGRAMS = smpte_test
+
+smpte_test_SOURCES = smpte_test.c gstsmptetimecode.c
+smpte_test_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(LIBDV_CFLAGS)
+smpte_test_LDADD = $(GST_BASE_LIBS) $(GST_LIBS)
+
diff --git a/ext/dv/NOTES b/ext/dv/NOTES
new file mode 100644
index 0000000..8421159
--- /dev/null
+++ b/ext/dv/NOTES
@@ -0,0 +1,13 @@
+Packets come from 1394 480 bytes at a time.  This is not a video segment
+length.  This causes problems, since a packet boundary crossing a video
+segment can split a video segment if we lose an iso packet.  We can
+recover from this, sorta, with significant changes to the parser.  We have
+to deal with the idea that a) some macroblocks just don't exist (we have
+zero's for them) and b) when any of the 5 macroblocks doesn't exist, we
+can't do pass 3.
+
+Since things are bitstream-based, we can deal with this, but we have to
+add a layer of code that tries to save time (maybe) by not decoding things
+that don't exist.  Not sure how this is gonna work with the parse code
+being based on video segments, and not easily splittable into
+macroblock-level parsing (or is it?).
diff --git a/ext/dv/gstdv.c b/ext/dv/gstdv.c
new file mode 100644
index 0000000..9861bf6
--- /dev/null
+++ b/ext/dv/gstdv.c
@@ -0,0 +1,48 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *               <2005> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstdvdec.h"
+#include "gstdvdemux.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  dv_init (0, 0);
+
+  if (!gst_element_register (plugin, "dvdemux", GST_RANK_PRIMARY,
+          gst_dvdemux_get_type ()))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "dvdec", GST_RANK_MARGINAL,
+          gst_dvdec_get_type ()))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    dv,
+    "DV demuxer and decoder based on libdv (libdv.sf.net)",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/ext/dv/gstdvdec.c b/ext/dv/gstdvdec.c
new file mode 100644
index 0000000..c7c193d
--- /dev/null
+++ b/ext/dv/gstdvdec.c
@@ -0,0 +1,690 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *               <2005> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-dvdec
+ *
+ * dvdec decodes DV video into raw video. The element expects a full DV frame
+ * as input, which is 120000 bytes for NTSC and 144000 for PAL video.
+ *
+ * This element can perform simple frame dropping with the #GstDVDec:drop-factor
+ * property. Setting this property to a value N > 1 will only decode every 
+ * Nth frame.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=test.dv ! dvdemux name=demux ! dvdec ! xvimagesink
+ * ]| This pipeline decodes and renders the raw DV stream to a videosink.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+#include <math.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideometa.h>
+#include <gst/video/gstvideopool.h>
+
+#include "gstdvdec.h"
+
+/* sizes of one input buffer */
+#define NTSC_HEIGHT 480
+#define NTSC_BUFFER 120000
+#define NTSC_FRAMERATE_NUMERATOR 30000
+#define NTSC_FRAMERATE_DENOMINATOR 1001
+
+#define PAL_HEIGHT 576
+#define PAL_BUFFER 144000
+#define PAL_FRAMERATE_NUMERATOR 25
+#define PAL_FRAMERATE_DENOMINATOR 1
+
+#define PAL_NORMAL_PAR_X        16
+#define PAL_NORMAL_PAR_Y        15
+#define PAL_WIDE_PAR_X          64
+#define PAL_WIDE_PAR_Y          45
+
+#define NTSC_NORMAL_PAR_X       8
+#define NTSC_NORMAL_PAR_Y       9
+#define NTSC_WIDE_PAR_X         32
+#define NTSC_WIDE_PAR_Y         27
+
+#define DV_DEFAULT_QUALITY DV_QUALITY_BEST
+#define DV_DEFAULT_DECODE_NTH 1
+
+GST_DEBUG_CATEGORY_STATIC (dvdec_debug);
+#define GST_CAT_DEFAULT dvdec_debug
+
+enum
+{
+  PROP_0,
+  PROP_CLAMP_LUMA,
+  PROP_CLAMP_CHROMA,
+  PROP_QUALITY,
+  PROP_DECODE_NTH
+};
+
+const gint qualities[] = {
+  DV_QUALITY_DC,
+  DV_QUALITY_AC_1,
+  DV_QUALITY_AC_2,
+  DV_QUALITY_DC | DV_QUALITY_COLOR,
+  DV_QUALITY_AC_1 | DV_QUALITY_COLOR,
+  DV_QUALITY_AC_2 | DV_QUALITY_COLOR
+};
+
+static GstStaticPadTemplate sink_temp = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-dv, systemstream = (boolean) false")
+    );
+
+static GstStaticPadTemplate src_temp = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-raw, "
+        "format = (string) { YUY2, BGRx, RGB }, "
+        "framerate = (fraction) [ 1/1, 60/1 ], "
+        "width = (int) 720, " "height = (int) { 576, 480 }")
+    );
+
+#define GST_TYPE_DVDEC_QUALITY (gst_dvdec_quality_get_type())
+static GType
+gst_dvdec_quality_get_type (void)
+{
+  static GType qtype = 0;
+
+  if (qtype == 0) {
+    static const GEnumValue values[] = {
+      {0, "Monochrome, DC (Fastest)", "fastest"},
+      {1, "Monochrome, first AC coefficient", "monochrome-ac"},
+      {2, "Monochrome, highest quality", "monochrome-best"},
+      {3, "Colour, DC, fastest", "colour-fastest"},
+      {4, "Colour, using only the first AC coefficient", "colour-ac"},
+      {5, "Highest quality colour decoding", "best"},
+      {0, NULL, NULL},
+    };
+
+    qtype = g_enum_register_static ("GstDVDecQualityEnum", values);
+  }
+  return qtype;
+}
+
+#define gst_dvdec_parent_class parent_class
+G_DEFINE_TYPE (GstDVDec, gst_dvdec, GST_TYPE_ELEMENT);
+
+static GstFlowReturn gst_dvdec_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer);
+static gboolean gst_dvdec_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+
+static GstStateChangeReturn gst_dvdec_change_state (GstElement * element,
+    GstStateChange transition);
+
+static void gst_dvdec_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_dvdec_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void
+gst_dvdec_class_init (GstDVDecClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_dvdec_set_property;
+  gobject_class->get_property = gst_dvdec_get_property;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CLAMP_LUMA,
+      g_param_spec_boolean ("clamp-luma", "Clamp luma", "Clamp luma",
+          FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CLAMP_CHROMA,
+      g_param_spec_boolean ("clamp-chroma", "Clamp chroma", "Clamp chroma",
+          FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
+      g_param_spec_enum ("quality", "Quality", "Decoding quality",
+          GST_TYPE_DVDEC_QUALITY, DV_DEFAULT_QUALITY,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DECODE_NTH,
+      g_param_spec_int ("drop-factor", "Drop Factor", "Only decode Nth frame",
+          1, G_MAXINT, DV_DEFAULT_DECODE_NTH,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_dvdec_change_state);
+
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_temp);
+  gst_element_class_add_static_pad_template (gstelement_class, &src_temp);
+
+  gst_element_class_set_static_metadata (gstelement_class, "DV video decoder",
+      "Codec/Decoder/Video",
+      "Uses libdv to decode DV video (smpte314) (libdv.sourceforge.net)",
+      "Erik Walthinsen <omega@cse.ogi.edu>," "Wim Taymans <wim@fluendo.com>");
+
+  GST_DEBUG_CATEGORY_INIT (dvdec_debug, "dvdec", 0, "DV decoding element");
+}
+
+static void
+gst_dvdec_init (GstDVDec * dvdec)
+{
+  dvdec->sinkpad = gst_pad_new_from_static_template (&sink_temp, "sink");
+  gst_pad_set_chain_function (dvdec->sinkpad, gst_dvdec_chain);
+  gst_pad_set_event_function (dvdec->sinkpad, gst_dvdec_sink_event);
+  gst_element_add_pad (GST_ELEMENT (dvdec), dvdec->sinkpad);
+
+  dvdec->srcpad = gst_pad_new_from_static_template (&src_temp, "src");
+  gst_pad_use_fixed_caps (dvdec->srcpad);
+  gst_element_add_pad (GST_ELEMENT (dvdec), dvdec->srcpad);
+
+  dvdec->framerate_numerator = 0;
+  dvdec->framerate_denominator = 0;
+  dvdec->wide = FALSE;
+  dvdec->drop_factor = 1;
+
+  dvdec->clamp_luma = FALSE;
+  dvdec->clamp_chroma = FALSE;
+  dvdec->quality = DV_DEFAULT_QUALITY;
+}
+
+static gboolean
+gst_dvdec_sink_setcaps (GstDVDec * dvdec, GstCaps * caps)
+{
+  GstStructure *s;
+  const GValue *par = NULL, *rate = NULL;
+
+  /* first parse the caps */
+  s = gst_caps_get_structure (caps, 0);
+
+  /* we allow framerate and PAR to be overwritten. framerate is mandatory. */
+  if (!(rate = gst_structure_get_value (s, "framerate")))
+    goto no_framerate;
+  par = gst_structure_get_value (s, "pixel-aspect-ratio");
+
+  if (par) {
+    dvdec->par_x = gst_value_get_fraction_numerator (par);
+    dvdec->par_y = gst_value_get_fraction_denominator (par);
+    dvdec->need_par = FALSE;
+  } else {
+    dvdec->par_x = 0;
+    dvdec->par_y = 0;
+    dvdec->need_par = TRUE;
+  }
+  dvdec->framerate_numerator = gst_value_get_fraction_numerator (rate);
+  dvdec->framerate_denominator = gst_value_get_fraction_denominator (rate);
+  dvdec->sink_negotiated = TRUE;
+  dvdec->src_negotiated = FALSE;
+
+  return TRUE;
+
+  /* ERRORS */
+no_framerate:
+  {
+    GST_DEBUG_OBJECT (dvdec, "no framerate specified in caps");
+    return FALSE;
+  }
+}
+
+static void
+gst_dvdec_negotiate_pool (GstDVDec * dec, GstCaps * caps, GstVideoInfo * info)
+{
+  GstQuery *query;
+  GstBufferPool *pool;
+  guint size, min, max;
+  GstStructure *config;
+
+  /* find a pool for the negotiated caps now */
+  query = gst_query_new_allocation (caps, TRUE);
+
+  if (!gst_pad_peer_query (dec->srcpad, query)) {
+    GST_DEBUG_OBJECT (dec, "didn't get downstream ALLOCATION hints");
+  }
+
+  if (gst_query_get_n_allocation_pools (query) > 0) {
+    /* we got configuration from our peer, parse them */
+    gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
+    size = MAX (size, info->size);
+  } else {
+    pool = NULL;
+    size = info->size;
+    min = max = 0;
+  }
+
+  if (pool == NULL) {
+    /* we did not get a pool, make one ourselves then */
+    pool = gst_video_buffer_pool_new ();
+  }
+
+  if (dec->pool) {
+    gst_buffer_pool_set_active (dec->pool, FALSE);
+    gst_object_unref (dec->pool);
+  }
+  dec->pool = pool;
+
+  config = gst_buffer_pool_get_config (pool);
+  gst_buffer_pool_config_set_params (config, caps, size, min, max);
+
+  if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
+    /* just set the option, if the pool can support it we will transparently use
+     * it through the video info API. We could also see if the pool support this
+     * option and only activate it then. */
+    gst_buffer_pool_config_add_option (config,
+        GST_BUFFER_POOL_OPTION_VIDEO_META);
+  }
+  gst_buffer_pool_set_config (pool, config);
+
+  /* and activate */
+  gst_buffer_pool_set_active (pool, TRUE);
+
+  gst_query_unref (query);
+}
+
+static gboolean
+gst_dvdec_src_negotiate (GstDVDec * dvdec)
+{
+  GstCaps *othercaps;
+  gboolean ret;
+
+  /* no PAR was specified in input, derive from encoded data */
+  if (dvdec->need_par) {
+    if (dvdec->PAL) {
+      if (dvdec->wide) {
+        dvdec->par_x = PAL_WIDE_PAR_X;
+        dvdec->par_y = PAL_WIDE_PAR_Y;
+      } else {
+        dvdec->par_x = PAL_NORMAL_PAR_X;
+        dvdec->par_y = PAL_NORMAL_PAR_Y;
+      }
+    } else {
+      if (dvdec->wide) {
+        dvdec->par_x = NTSC_WIDE_PAR_X;
+        dvdec->par_y = NTSC_WIDE_PAR_Y;
+      } else {
+        dvdec->par_x = NTSC_NORMAL_PAR_X;
+        dvdec->par_y = NTSC_NORMAL_PAR_Y;
+      }
+    }
+    GST_DEBUG_OBJECT (dvdec, "Inferred PAR %d/%d from video format",
+        dvdec->par_x, dvdec->par_y);
+  }
+
+  /* ignoring rgb, bgr0 for now */
+  dvdec->bpp = 2;
+
+  gst_video_info_set_format (&dvdec->vinfo, GST_VIDEO_FORMAT_YUY2,
+      720, dvdec->height);
+  dvdec->vinfo.fps_n = dvdec->framerate_numerator;
+  dvdec->vinfo.fps_d = dvdec->framerate_denominator;
+  dvdec->vinfo.par_n = dvdec->par_x;
+  dvdec->vinfo.par_d = dvdec->par_y;
+  if (dvdec->interlaced) {
+    dvdec->vinfo.interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
+  } else {
+    dvdec->vinfo.interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
+  }
+
+  othercaps = gst_video_info_to_caps (&dvdec->vinfo);
+  ret = gst_pad_set_caps (dvdec->srcpad, othercaps);
+
+  gst_dvdec_negotiate_pool (dvdec, othercaps, &dvdec->vinfo);
+  gst_caps_unref (othercaps);
+
+  dvdec->src_negotiated = TRUE;
+
+  return ret;
+}
+
+static gboolean
+gst_dvdec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstDVDec *dvdec;
+  gboolean res = TRUE;
+
+  dvdec = GST_DVDEC (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      gst_segment_init (&dvdec->segment, GST_FORMAT_UNDEFINED);
+      dvdec->need_segment = FALSE;
+      break;
+    case GST_EVENT_SEGMENT:{
+      const GstSegment *segment;
+
+      gst_event_parse_segment (event, &segment);
+
+      GST_DEBUG_OBJECT (dvdec, "Got SEGMENT %" GST_SEGMENT_FORMAT, &segment);
+
+      gst_segment_copy_into (segment, &dvdec->segment);
+      if (!gst_pad_has_current_caps (dvdec->srcpad)) {
+        dvdec->need_segment = TRUE;
+        gst_event_unref (event);
+        event = NULL;
+        res = TRUE;
+      } else {
+        dvdec->need_segment = FALSE;
+      }
+      break;
+    }
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      res = gst_dvdec_sink_setcaps (dvdec, caps);
+      gst_event_unref (event);
+      event = NULL;
+      break;
+    }
+
+    default:
+      break;
+  }
+
+  if (event)
+    res = gst_pad_push_event (dvdec->srcpad, event);
+
+  return res;
+}
+
+static GstFlowReturn
+gst_dvdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstDVDec *dvdec;
+  guint8 *inframe;
+  guint8 *outframe_ptrs[3];
+  gint outframe_pitches[3];
+  GstMapInfo map;
+  GstVideoFrame frame;
+  GstBuffer *outbuf;
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint length;
+  guint64 cstart = GST_CLOCK_TIME_NONE, cstop = GST_CLOCK_TIME_NONE;
+  gboolean PAL, wide;
+
+  dvdec = GST_DVDEC (parent);
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  inframe = map.data;
+
+  /* buffer should be at least the size of one NTSC frame, this should
+   * be enough to decode the header. */
+  if (G_UNLIKELY (map.size < NTSC_BUFFER))
+    goto wrong_size;
+
+  /* preliminary dropping. unref and return if outside of configured segment */
+  if ((dvdec->segment.format == GST_FORMAT_TIME) &&
+      (!(gst_segment_clip (&dvdec->segment, GST_FORMAT_TIME,
+                  GST_BUFFER_TIMESTAMP (buf),
+                  GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf),
+                  &cstart, &cstop))))
+    goto dropping;
+
+  if (G_UNLIKELY (dv_parse_header (dvdec->decoder, inframe) < 0))
+    goto parse_header_error;
+
+  /* get size */
+  PAL = dv_system_50_fields (dvdec->decoder);
+  wide = dv_format_wide (dvdec->decoder);
+
+  /* check the buffer is of right size after we know if we are
+   * dealing with PAL or NTSC */
+  length = (PAL ? PAL_BUFFER : NTSC_BUFFER);
+  if (G_UNLIKELY (map.size < length))
+    goto wrong_size;
+
+  dv_parse_packs (dvdec->decoder, inframe);
+
+  if (dvdec->video_offset % dvdec->drop_factor != 0)
+    goto skip;
+
+  /* renegotiate on change */
+  if (PAL != dvdec->PAL || wide != dvdec->wide) {
+    dvdec->src_negotiated = FALSE;
+    dvdec->PAL = PAL;
+    dvdec->wide = wide;
+  }
+
+  dvdec->height = (dvdec->PAL ? PAL_HEIGHT : NTSC_HEIGHT);
+
+  dvdec->interlaced = !dv_is_progressive (dvdec->decoder);
+
+  /* negotiate if not done yet */
+  if (!dvdec->src_negotiated) {
+    if (!gst_dvdec_src_negotiate (dvdec))
+      goto not_negotiated;
+  }
+
+  if (gst_pad_check_reconfigure (dvdec->srcpad)) {
+    GstCaps *caps;
+
+    caps = gst_pad_get_current_caps (dvdec->srcpad);
+    if (!caps)
+      goto flushing;
+
+    gst_dvdec_negotiate_pool (dvdec, caps, &dvdec->vinfo);
+    gst_caps_unref (caps);
+  }
+
+  if (dvdec->need_segment) {
+    gst_pad_push_event (dvdec->srcpad, gst_event_new_segment (&dvdec->segment));
+    dvdec->need_segment = FALSE;
+  }
+
+  ret = gst_buffer_pool_acquire_buffer (dvdec->pool, &outbuf, NULL);
+  if (G_UNLIKELY (ret != GST_FLOW_OK))
+    goto no_buffer;
+
+  gst_video_frame_map (&frame, &dvdec->vinfo, outbuf, GST_MAP_WRITE);
+
+  outframe_ptrs[0] = GST_VIDEO_FRAME_COMP_DATA (&frame, 0);
+  outframe_pitches[0] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0);
+
+  /* the rest only matters for YUY2 */
+  if (dvdec->bpp < 3) {
+    outframe_ptrs[1] = GST_VIDEO_FRAME_COMP_DATA (&frame, 1);
+    outframe_ptrs[2] = GST_VIDEO_FRAME_COMP_DATA (&frame, 2);
+
+    outframe_pitches[1] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 1);
+    outframe_pitches[2] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 2);
+  }
+
+  GST_DEBUG_OBJECT (dvdec, "decoding and pushing buffer");
+  dv_decode_full_frame (dvdec->decoder, inframe,
+      e_dv_color_yuv, outframe_ptrs, outframe_pitches);
+
+  gst_video_frame_unmap (&frame);
+
+  GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
+
+  GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buf);
+  GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
+
+  /* FIXME : Compute values when using non-TIME segments,
+   * but for the moment make sure we at least don't set bogus values
+   */
+  if (GST_CLOCK_TIME_IS_VALID (cstart)) {
+    GST_BUFFER_TIMESTAMP (outbuf) = cstart;
+    if (GST_CLOCK_TIME_IS_VALID (cstop))
+      GST_BUFFER_DURATION (outbuf) = cstop - cstart;
+  }
+
+  ret = gst_pad_push (dvdec->srcpad, outbuf);
+
+skip:
+  dvdec->video_offset++;
+
+done:
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+
+  return ret;
+
+  /* ERRORS */
+wrong_size:
+  {
+    GST_ELEMENT_ERROR (dvdec, STREAM, DECODE,
+        (NULL), ("Input buffer too small"));
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+parse_header_error:
+  {
+    GST_ELEMENT_ERROR (dvdec, STREAM, DECODE,
+        (NULL), ("Error parsing DV header"));
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+not_negotiated:
+  {
+    GST_DEBUG_OBJECT (dvdec, "could not negotiate output");
+    if (GST_PAD_IS_FLUSHING (dvdec->srcpad))
+      ret = GST_FLOW_FLUSHING;
+    else
+      ret = GST_FLOW_NOT_NEGOTIATED;
+    goto done;
+  }
+flushing:
+  {
+    GST_DEBUG_OBJECT (dvdec, "have no current caps");
+    ret = GST_FLOW_FLUSHING;
+    goto done;
+  }
+no_buffer:
+  {
+    GST_DEBUG_OBJECT (dvdec, "could not allocate buffer");
+    goto done;
+  }
+
+dropping:
+  {
+    GST_DEBUG_OBJECT (dvdec,
+        "dropping buffer since it's out of the configured segment");
+    goto done;
+  }
+}
+
+static GstStateChangeReturn
+gst_dvdec_change_state (GstElement * element, GstStateChange transition)
+{
+  GstDVDec *dvdec = GST_DVDEC (element);
+  GstStateChangeReturn ret;
+
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      dvdec->decoder =
+          dv_decoder_new (0, dvdec->clamp_luma, dvdec->clamp_chroma);
+      dvdec->decoder->quality = qualities[dvdec->quality];
+      dv_set_error_log (dvdec->decoder, NULL);
+      gst_video_info_init (&dvdec->vinfo);
+      gst_segment_init (&dvdec->segment, GST_FORMAT_UNDEFINED);
+      dvdec->src_negotiated = FALSE;
+      dvdec->sink_negotiated = FALSE;
+      dvdec->need_segment = FALSE;
+      /* 
+       * Enable this function call when libdv2 0.100 or higher is more
+       * common
+       */
+      /* dv_set_quality (dvdec->decoder, qualities [dvdec->quality]); */
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      dv_decoder_free (dvdec->decoder);
+      dvdec->decoder = NULL;
+      if (dvdec->pool) {
+        gst_buffer_pool_set_active (dvdec->pool, FALSE);
+        gst_object_unref (dvdec->pool);
+        dvdec->pool = NULL;
+      }
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+static void
+gst_dvdec_set_property (GObject * object, guint prop_id, const GValue * value,
+    GParamSpec * pspec)
+{
+  GstDVDec *dvdec = GST_DVDEC (object);
+
+  switch (prop_id) {
+    case PROP_CLAMP_LUMA:
+      dvdec->clamp_luma = g_value_get_boolean (value);
+      break;
+    case PROP_CLAMP_CHROMA:
+      dvdec->clamp_chroma = g_value_get_boolean (value);
+      break;
+    case PROP_QUALITY:
+      dvdec->quality = g_value_get_enum (value);
+      if ((dvdec->quality < 0) || (dvdec->quality > 5))
+        dvdec->quality = 0;
+      break;
+    case PROP_DECODE_NTH:
+      dvdec->drop_factor = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_dvdec_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstDVDec *dvdec = GST_DVDEC (object);
+
+  switch (prop_id) {
+    case PROP_CLAMP_LUMA:
+      g_value_set_boolean (value, dvdec->clamp_luma);
+      break;
+    case PROP_CLAMP_CHROMA:
+      g_value_set_boolean (value, dvdec->clamp_chroma);
+      break;
+    case PROP_QUALITY:
+      g_value_set_enum (value, dvdec->quality);
+      break;
+    case PROP_DECODE_NTH:
+      g_value_set_int (value, dvdec->drop_factor);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/ext/dv/gstdvdec.h b/ext/dv/gstdvdec.h
new file mode 100644
index 0000000..4031ef0
--- /dev/null
+++ b/ext/dv/gstdvdec.h
@@ -0,0 +1,98 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_DVDEC_H__
+#define __GST_DVDEC_H__
+
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include <libdv/dv.h>
+
+
+G_BEGIN_DECLS
+
+
+#define GST_TYPE_DVDEC \
+  (gst_dvdec_get_type())
+#define GST_DVDEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DVDEC,GstDVDec))
+#define GST_DVDEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DVDEC,GstDVDecClass))
+#define GST_IS_DVDEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DVDEC))
+#define GST_IS_DVDEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DVDEC))
+
+
+typedef struct _GstDVDec GstDVDec;
+typedef struct _GstDVDecClass GstDVDecClass;
+
+
+struct _GstDVDec {
+  GstElement     element;
+
+  GstPad        *sinkpad;
+  GstPad        *srcpad;
+
+  dv_decoder_t  *decoder;
+  gboolean       clamp_luma;
+  gboolean       clamp_chroma;
+  gint           quality;
+
+  gboolean       PAL;
+  gboolean       interlaced;
+  gboolean       wide;
+
+  /* input caps */
+  gboolean       sink_negotiated;
+  GstVideoInfo   vinfo;
+  gint           framerate_numerator;
+  gint           framerate_denominator;
+  gint           height;
+  gint           par_x;
+  gint           par_y;
+  gboolean       need_par;
+
+  /* negotiated output */
+  gint           bpp;
+  gboolean       src_negotiated;
+  
+  gint           video_offset;
+  gint           drop_factor;
+
+  GstBufferPool *pool;
+  GstSegment     segment;
+  gboolean       need_segment;
+};
+
+struct _GstDVDecClass {
+  GstElementClass parent_class;
+};
+
+
+GType gst_dvdec_get_type (void);
+
+
+G_END_DECLS
+
+
+#endif /* __GST_DVDEC_H__ */
diff --git a/ext/dv/gstdvdemux.c b/ext/dv/gstdvdemux.c
new file mode 100644
index 0000000..b76d7da
--- /dev/null
+++ b/ext/dv/gstdvdemux.c
@@ -0,0 +1,2047 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *               <2005> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <math.h>
+
+#include <gst/audio/audio.h>
+#include "gstdvdemux.h"
+#include "gstsmptetimecode.h"
+
+/**
+ * SECTION:element-dvdemux
+ *
+ * dvdemux splits raw DV into its audio and video components. The audio will be
+ * decoded raw samples and the video will be encoded DV video.
+ *
+ * This element can operate in both push and pull mode depending on the
+ * capabilities of the upstream peer.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=test.dv ! dvdemux name=demux ! queue ! audioconvert ! alsasink demux. ! queue ! dvdec ! xvimagesink
+ * ]| This pipeline decodes and renders the raw DV stream to an audio and a videosink.
+ * </refsect2>
+ */
+
+/* DV output has two modes, normal and wide. The resolution is the same in both
+ * cases: 720 pixels wide by 576 pixels tall in PAL format, and 720x480 for
+ * NTSC.
+ *
+ * Each of the modes has its own pixel aspect ratio, which is fixed in practice
+ * by ITU-R BT.601 (also known as "CCIR-601" or "Rec.601"). Or so claims a
+ * reference that I culled from the reliable "internet",
+ * http://www.mir.com/DMG/aspect.html. Normal PAL is 59/54 and normal NTSC is
+ * 10/11. Because the pixel resolution is the same for both cases, we can get
+ * the pixel aspect ratio for wide recordings by multiplying by the ratio of
+ * display aspect ratios, 16/9 (for wide) divided by 4/3 (for normal):
+ *
+ * Wide NTSC: 10/11 * (16/9)/(4/3) = 40/33
+ * Wide PAL: 59/54 * (16/9)/(4/3) = 118/81
+ *
+ * However, the pixel resolution coming out of a DV source does not combine with
+ * the standard pixel aspect ratios to give a proper display aspect ratio. An
+ * image 480 pixels tall, with a 4:3 display aspect ratio, will be 768 pixels
+ * wide. But, if we take the normal PAL aspect ratio of 59/54, and multiply it
+ * with the width of the DV image (720 pixels), we get 786.666..., which is
+ * nonintegral and too wide. The camera is not outputting a 4:3 image.
+ * 
+ * If the video sink for this stream has fixed dimensions (such as for
+ * fullscreen playback, or for a java applet in a web page), you then have two
+ * choices. Either you show the whole image, but pad the image with black
+ * borders on the top and bottom (like watching a widescreen video on a 4:3
+ * device), or you crop the video to the proper ratio. Apparently the latter is
+ * the standard practice.
+ *
+ * For its part, GStreamer is concerned with accuracy and preservation of
+ * information. This element outputs the 720x576 or 720x480 video that it
+ * recieves, noting the proper aspect ratio. This should not be a problem for
+ * windowed applications, which can change size to fit the video. Applications
+ * with fixed size requirements should decide whether to crop or pad which
+ * an element such as videobox can do.
+ */
+
+#define NTSC_HEIGHT 480
+#define NTSC_BUFFER 120000
+#define NTSC_FRAMERATE_NUMERATOR 30000
+#define NTSC_FRAMERATE_DENOMINATOR 1001
+
+#define PAL_HEIGHT 576
+#define PAL_BUFFER 144000
+#define PAL_FRAMERATE_NUMERATOR 25
+#define PAL_FRAMERATE_DENOMINATOR 1
+
+#define PAL_NORMAL_PAR_X        16
+#define PAL_NORMAL_PAR_Y        15
+#define PAL_WIDE_PAR_X          64
+#define PAL_WIDE_PAR_Y          45
+
+#define NTSC_NORMAL_PAR_X       8
+#define NTSC_NORMAL_PAR_Y       9
+#define NTSC_WIDE_PAR_X         32
+#define NTSC_WIDE_PAR_Y         27
+
+GST_DEBUG_CATEGORY_STATIC (dvdemux_debug);
+#define GST_CAT_DEFAULT dvdemux_debug
+
+static GstStaticPadTemplate sink_temp = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-dv, systemstream = (boolean) true")
+    );
+
+static GstStaticPadTemplate video_src_temp = GST_STATIC_PAD_TEMPLATE ("video",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("video/x-dv, systemstream = (boolean) false")
+    );
+
+static GstStaticPadTemplate audio_src_temp = GST_STATIC_PAD_TEMPLATE ("audio",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (S16) ", "
+        "layout = (string) interleaved, "
+        "rate = (int) { 32000, 44100, 48000 }, " "channels = (int) {2, 4}")
+    );
+
+
+#define gst_dvdemux_parent_class parent_class
+G_DEFINE_TYPE (GstDVDemux, gst_dvdemux, GST_TYPE_ELEMENT);
+
+static void gst_dvdemux_finalize (GObject * object);
+
+/* query functions */
+static gboolean gst_dvdemux_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+static gboolean gst_dvdemux_sink_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+
+/* convert functions */
+static gboolean gst_dvdemux_sink_convert (GstDVDemux * demux,
+    GstFormat src_format, gint64 src_value, GstFormat dest_format,
+    gint64 * dest_value);
+static gboolean gst_dvdemux_src_convert (GstDVDemux * demux, GstPad * pad,
+    GstFormat src_format, gint64 src_value, GstFormat dest_format,
+    gint64 * dest_value);
+
+/* event functions */
+static gboolean gst_dvdemux_send_event (GstElement * element, GstEvent * event);
+static gboolean gst_dvdemux_handle_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static gboolean gst_dvdemux_handle_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+
+/* scheduling functions */
+static void gst_dvdemux_loop (GstPad * pad);
+static GstFlowReturn gst_dvdemux_flush (GstDVDemux * dvdemux);
+static GstFlowReturn gst_dvdemux_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer);
+
+/* state change functions */
+static gboolean gst_dvdemux_sink_activate (GstPad * sinkpad,
+    GstObject * parent);
+static gboolean gst_dvdemux_sink_activate_mode (GstPad * sinkpad,
+    GstObject * parent, GstPadMode mode, gboolean active);
+static GstStateChangeReturn gst_dvdemux_change_state (GstElement * element,
+    GstStateChange transition);
+
+static void
+gst_dvdemux_class_init (GstDVDemuxClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->finalize = gst_dvdemux_finalize;
+
+  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_dvdemux_change_state);
+  gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_dvdemux_send_event);
+
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_temp);
+  gst_element_class_add_static_pad_template (gstelement_class, &video_src_temp);
+  gst_element_class_add_static_pad_template (gstelement_class, &audio_src_temp);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "DV system stream demuxer", "Codec/Demuxer",
+      "Uses libdv to separate DV audio from DV video (libdv.sourceforge.net)",
+      "Erik Walthinsen <omega@cse.ogi.edu>, Wim Taymans <wim@fluendo.com>");
+
+  GST_DEBUG_CATEGORY_INIT (dvdemux_debug, "dvdemux", 0, "DV demuxer element");
+}
+
+static void
+gst_dvdemux_init (GstDVDemux * dvdemux)
+{
+  gint i;
+
+  dvdemux->sinkpad = gst_pad_new_from_static_template (&sink_temp, "sink");
+  /* we can operate in pull and push mode so we install
+   * a custom activate function */
+  gst_pad_set_activate_function (dvdemux->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_dvdemux_sink_activate));
+  /* the function to activate in push mode */
+  gst_pad_set_activatemode_function (dvdemux->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_dvdemux_sink_activate_mode));
+  /* for push mode, this is the chain function */
+  gst_pad_set_chain_function (dvdemux->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_dvdemux_chain));
+  /* handling events (in push mode only) */
+  gst_pad_set_event_function (dvdemux->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_dvdemux_handle_sink_event));
+  /* query functions */
+  gst_pad_set_query_function (dvdemux->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_dvdemux_sink_query));
+
+  /* now add the pad */
+  gst_element_add_pad (GST_ELEMENT (dvdemux), dvdemux->sinkpad);
+
+  dvdemux->adapter = gst_adapter_new ();
+
+  /* we need 4 temp buffers for audio decoding which are of a static
+   * size and which we can allocate here */
+  for (i = 0; i < 4; i++) {
+    dvdemux->audio_buffers[i] =
+        (gint16 *) g_malloc (DV_AUDIO_MAX_SAMPLES * sizeof (gint16));
+  }
+}
+
+static void
+gst_dvdemux_finalize (GObject * object)
+{
+  GstDVDemux *dvdemux;
+  gint i;
+
+  dvdemux = GST_DVDEMUX (object);
+
+  g_object_unref (dvdemux->adapter);
+
+  /* clean up temp audio buffers */
+  for (i = 0; i < 4; i++) {
+    g_free (dvdemux->audio_buffers[i]);
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* reset to default values before starting streaming */
+static void
+gst_dvdemux_reset (GstDVDemux * dvdemux)
+{
+  dvdemux->frame_offset = 0;
+  dvdemux->audio_offset = 0;
+  dvdemux->video_offset = 0;
+  dvdemux->discont = TRUE;
+  g_atomic_int_set (&dvdemux->found_header, 0);
+  dvdemux->frame_len = -1;
+  dvdemux->need_segment = FALSE;
+  dvdemux->new_media = FALSE;
+  dvdemux->framerate_numerator = 0;
+  dvdemux->framerate_denominator = 0;
+  dvdemux->height = 0;
+  dvdemux->frequency = 0;
+  dvdemux->channels = 0;
+  dvdemux->wide = FALSE;
+  gst_segment_init (&dvdemux->byte_segment, GST_FORMAT_BYTES);
+  gst_segment_init (&dvdemux->time_segment, GST_FORMAT_TIME);
+  dvdemux->segment_seqnum = 0;
+  dvdemux->upstream_time_segment = FALSE;
+  dvdemux->have_group_id = FALSE;
+  dvdemux->group_id = G_MAXUINT;
+  dvdemux->tag_event = NULL;
+}
+
+static gboolean
+have_group_id (GstDVDemux * demux)
+{
+  GstEvent *event;
+
+  event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
+  if (event) {
+    if (gst_event_parse_group_id (event, &demux->group_id))
+      demux->have_group_id = TRUE;
+    else
+      demux->have_group_id = FALSE;
+    gst_event_unref (event);
+  } else if (!demux->have_group_id) {
+    demux->have_group_id = TRUE;
+    demux->group_id = gst_util_group_id_next ();
+  }
+
+  return demux->have_group_id;
+}
+
+static GstEvent *
+gst_dvdemux_create_global_tag_event (GstDVDemux * dvdemux)
+{
+  gchar rec_datetime[40];
+  GstDateTime *rec_dt;
+  GstTagList *tags;
+
+  tags = gst_tag_list_new (GST_TAG_CONTAINER_FORMAT, "DV", NULL);
+  gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
+
+  if (dv_get_recording_datetime (dvdemux->decoder, rec_datetime)) {
+    rec_dt = gst_date_time_new_from_iso8601_string (rec_datetime);
+    if (rec_dt) {
+      gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME,
+          rec_dt, NULL);
+      gst_date_time_unref (rec_dt);
+    }
+  }
+
+  return gst_event_new_tag (tags);
+}
+
+static GstPad *
+gst_dvdemux_add_pad (GstDVDemux * dvdemux, GstStaticPadTemplate * template,
+    GstCaps * caps)
+{
+  GstPad *pad;
+  GstEvent *event;
+  gchar *stream_id;
+
+  pad = gst_pad_new_from_static_template (template, template->name_template);
+
+  gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_dvdemux_src_query));
+
+  gst_pad_set_event_function (pad,
+      GST_DEBUG_FUNCPTR (gst_dvdemux_handle_src_event));
+  gst_pad_use_fixed_caps (pad);
+  gst_pad_set_active (pad, TRUE);
+
+  stream_id =
+      gst_pad_create_stream_id (pad,
+      GST_ELEMENT_CAST (dvdemux),
+      template == &video_src_temp ? "video" : "audio");
+  event = gst_event_new_stream_start (stream_id);
+  if (have_group_id (dvdemux))
+    gst_event_set_group_id (event, dvdemux->group_id);
+  gst_pad_push_event (pad, event);
+  g_free (stream_id);
+
+  gst_pad_set_caps (pad, caps);
+
+  gst_pad_push_event (pad, gst_event_new_segment (&dvdemux->time_segment));
+
+  gst_element_add_pad (GST_ELEMENT (dvdemux), pad);
+
+  if (!dvdemux->tag_event) {
+    dvdemux->tag_event = gst_dvdemux_create_global_tag_event (dvdemux);
+  }
+
+  if (dvdemux->tag_event) {
+    gst_pad_push_event (pad, gst_event_ref (dvdemux->tag_event));
+  }
+
+  return pad;
+}
+
+static void
+gst_dvdemux_remove_pads (GstDVDemux * dvdemux)
+{
+  if (dvdemux->videosrcpad) {
+    gst_element_remove_pad (GST_ELEMENT (dvdemux), dvdemux->videosrcpad);
+    dvdemux->videosrcpad = NULL;
+  }
+  if (dvdemux->audiosrcpad) {
+    gst_element_remove_pad (GST_ELEMENT (dvdemux), dvdemux->audiosrcpad);
+    dvdemux->audiosrcpad = NULL;
+  }
+}
+
+static gboolean
+gst_dvdemux_src_convert (GstDVDemux * dvdemux, GstPad * pad,
+    GstFormat src_format, gint64 src_value, GstFormat dest_format,
+    gint64 * dest_value)
+{
+  gboolean res = TRUE;
+
+  if (dest_format == src_format || src_value == -1) {
+    *dest_value = src_value;
+    goto done;
+  }
+
+  if (dvdemux->frame_len <= 0)
+    goto error;
+
+  if (dvdemux->decoder == NULL)
+    goto error;
+
+  GST_INFO_OBJECT (pad,
+      "src_value:%" G_GINT64_FORMAT ", src_format:%d, dest_format:%d",
+      src_value, src_format, dest_format);
+
+  switch (src_format) {
+    case GST_FORMAT_BYTES:
+      switch (dest_format) {
+        case GST_FORMAT_DEFAULT:
+          if (pad == dvdemux->videosrcpad)
+            *dest_value = src_value / dvdemux->frame_len;
+          else if (pad == dvdemux->audiosrcpad)
+            *dest_value = src_value / (2 * dvdemux->channels);
+          break;
+        case GST_FORMAT_TIME:
+          if (pad == dvdemux->videosrcpad)
+            *dest_value = gst_util_uint64_scale (src_value,
+                GST_SECOND * dvdemux->framerate_denominator,
+                dvdemux->frame_len * dvdemux->framerate_numerator);
+          else if (pad == dvdemux->audiosrcpad)
+            *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
+                2 * dvdemux->frequency * dvdemux->channels);
+          break;
+        default:
+          res = FALSE;
+      }
+      break;
+    case GST_FORMAT_TIME:
+      switch (dest_format) {
+        case GST_FORMAT_BYTES:
+          if (pad == dvdemux->videosrcpad)
+            *dest_value = gst_util_uint64_scale (src_value,
+                dvdemux->frame_len * dvdemux->framerate_numerator,
+                dvdemux->framerate_denominator * GST_SECOND);
+          else if (pad == dvdemux->audiosrcpad)
+            *dest_value = gst_util_uint64_scale_int (src_value,
+                2 * dvdemux->frequency * dvdemux->channels, GST_SECOND);
+          break;
+        case GST_FORMAT_DEFAULT:
+          if (pad == dvdemux->videosrcpad) {
+            if (src_value)
+              *dest_value = gst_util_uint64_scale (src_value,
+                  dvdemux->framerate_numerator,
+                  dvdemux->framerate_denominator * GST_SECOND);
+            else
+              *dest_value = 0;
+          } else if (pad == dvdemux->audiosrcpad) {
+            *dest_value = gst_util_uint64_scale (src_value,
+                dvdemux->frequency, GST_SECOND);
+          }
+          break;
+        default:
+          res = FALSE;
+      }
+      break;
+    case GST_FORMAT_DEFAULT:
+      switch (dest_format) {
+        case GST_FORMAT_TIME:
+          if (pad == dvdemux->videosrcpad) {
+            *dest_value = gst_util_uint64_scale (src_value,
+                GST_SECOND * dvdemux->framerate_denominator,
+                dvdemux->framerate_numerator);
+          } else if (pad == dvdemux->audiosrcpad) {
+            if (src_value)
+              *dest_value = gst_util_uint64_scale (src_value,
+                  GST_SECOND, dvdemux->frequency);
+            else
+              *dest_value = 0;
+          }
+          break;
+        case GST_FORMAT_BYTES:
+          if (pad == dvdemux->videosrcpad) {
+            *dest_value = src_value * dvdemux->frame_len;
+          } else if (pad == dvdemux->audiosrcpad) {
+            *dest_value = src_value * 2 * dvdemux->channels;
+          }
+          break;
+        default:
+          res = FALSE;
+      }
+      break;
+    default:
+      res = FALSE;
+  }
+
+done:
+  GST_INFO_OBJECT (pad,
+      "Result : dest_format:%d, dest_value:%" G_GINT64_FORMAT ", res:%d",
+      dest_format, *dest_value, res);
+  return res;
+
+  /* ERRORS */
+error:
+  {
+    GST_INFO ("source conversion failed");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_dvdemux_sink_convert (GstDVDemux * dvdemux, GstFormat src_format,
+    gint64 src_value, GstFormat dest_format, gint64 * dest_value)
+{
+  gboolean res = TRUE;
+
+  GST_DEBUG_OBJECT (dvdemux, "%d -> %d", src_format, dest_format);
+  GST_INFO_OBJECT (dvdemux,
+      "src_value:%" G_GINT64_FORMAT ", src_format:%d, dest_format:%d",
+      src_value, src_format, dest_format);
+
+  if (dest_format == src_format || src_value == -1) {
+    *dest_value = src_value;
+    goto done;
+  }
+
+  if (dvdemux->frame_len <= 0)
+    goto error;
+
+  switch (src_format) {
+    case GST_FORMAT_BYTES:
+      switch (dest_format) {
+        case GST_FORMAT_TIME:
+        {
+          guint64 frame;
+
+          /* get frame number, rounds down so don't combine this
+           * line and the next line. */
+          frame = src_value / dvdemux->frame_len;
+
+          *dest_value = gst_util_uint64_scale (frame,
+              GST_SECOND * dvdemux->framerate_denominator,
+              dvdemux->framerate_numerator);
+          break;
+        }
+        default:
+          res = FALSE;
+      }
+      break;
+    case GST_FORMAT_TIME:
+      switch (dest_format) {
+        case GST_FORMAT_BYTES:
+        {
+          guint64 frame;
+
+          /* calculate the frame */
+          frame =
+              gst_util_uint64_scale (src_value, dvdemux->framerate_numerator,
+              dvdemux->framerate_denominator * GST_SECOND);
+
+          /* calculate the offset from the rounded frame */
+          *dest_value = frame * dvdemux->frame_len;
+          break;
+        }
+        default:
+          res = FALSE;
+      }
+      break;
+    default:
+      res = FALSE;
+  }
+  GST_INFO_OBJECT (dvdemux,
+      "Result : dest_format:%d, dest_value:%" G_GINT64_FORMAT ", res:%d",
+      dest_format, *dest_value, res);
+
+done:
+  return res;
+
+error:
+  {
+    GST_INFO_OBJECT (dvdemux, "sink conversion failed");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_dvdemux_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  gboolean res = TRUE;
+  GstDVDemux *dvdemux;
+
+  dvdemux = GST_DVDEMUX (parent);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:
+    {
+      GstFormat format;
+      gint64 cur;
+
+      /* get target format */
+      gst_query_parse_position (query, &format, NULL);
+
+      /* bring the position to the requested format. */
+      if (!(res = gst_dvdemux_src_convert (dvdemux, pad,
+                  GST_FORMAT_TIME, dvdemux->time_segment.position,
+                  format, &cur)))
+        goto error;
+      gst_query_set_position (query, format, cur);
+      break;
+    }
+    case GST_QUERY_DURATION:
+    {
+      GstFormat format;
+      gint64 end;
+      GstQuery *pquery;
+
+      /* First ask the peer in the original format */
+      if (!gst_pad_peer_query (dvdemux->sinkpad, query)) {
+        /* get target format */
+        gst_query_parse_duration (query, &format, NULL);
+
+        /* Now ask the peer in BYTES format and try to convert */
+        pquery = gst_query_new_duration (GST_FORMAT_BYTES);
+        if (!gst_pad_peer_query (dvdemux->sinkpad, pquery)) {
+          gst_query_unref (pquery);
+          goto error;
+        }
+
+        /* get peer total length */
+        gst_query_parse_duration (pquery, NULL, &end);
+        gst_query_unref (pquery);
+
+        /* convert end to requested format */
+        if (end != -1) {
+          if (!(res = gst_dvdemux_sink_convert (dvdemux,
+                      GST_FORMAT_BYTES, end, format, &end))) {
+            goto error;
+          }
+          gst_query_set_duration (query, format, end);
+        }
+      }
+      break;
+    }
+    case GST_QUERY_CONVERT:
+    {
+      GstFormat src_fmt, dest_fmt;
+      gint64 src_val, dest_val;
+
+      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
+      if (!(res =
+              gst_dvdemux_src_convert (dvdemux, pad, src_fmt, src_val,
+                  dest_fmt, &dest_val)))
+        goto error;
+      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+      break;
+    }
+    case GST_QUERY_SEEKING:
+    {
+      GstFormat fmt;
+      GstQuery *peerquery;
+      gboolean seekable;
+
+      gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
+
+      /* We can only handle TIME seeks really */
+      if (fmt != GST_FORMAT_TIME) {
+        gst_query_set_seeking (query, fmt, FALSE, -1, -1);
+        break;
+      }
+
+      /* First ask upstream */
+      if (gst_pad_peer_query (dvdemux->sinkpad, query)) {
+        gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
+        if (seekable) {
+          res = TRUE;
+          break;
+        }
+      }
+
+      res = TRUE;
+
+      peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
+      seekable = gst_pad_peer_query (dvdemux->sinkpad, peerquery);
+
+      if (seekable)
+        gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
+      gst_query_unref (peerquery);
+
+      if (seekable) {
+        peerquery = gst_query_new_duration (GST_FORMAT_TIME);
+        seekable = gst_dvdemux_src_query (pad, parent, peerquery);
+
+        if (seekable) {
+          gint64 duration;
+
+          gst_query_parse_duration (peerquery, NULL, &duration);
+          gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
+        } else {
+          gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
+        }
+
+        gst_query_unref (peerquery);
+      } else {
+        gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
+      }
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+
+  return res;
+
+  /* ERRORS */
+error:
+  {
+    GST_DEBUG ("error source query");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_dvdemux_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  gboolean res = TRUE;
+  GstDVDemux *dvdemux;
+
+  dvdemux = GST_DVDEMUX (parent);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CONVERT:
+    {
+      GstFormat src_fmt, dest_fmt;
+      gint64 src_val, dest_val;
+
+      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
+      if (!(res =
+              gst_dvdemux_sink_convert (dvdemux, src_fmt, src_val, dest_fmt,
+                  &dest_val)))
+        goto error;
+      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+
+  return res;
+
+  /* ERRORS */
+error:
+  {
+    GST_DEBUG ("error handling sink query");
+    return FALSE;
+  }
+}
+
+/* takes ownership of the event */
+static gboolean
+gst_dvdemux_push_event (GstDVDemux * dvdemux, GstEvent * event)
+{
+  gboolean res = FALSE;
+
+  if (dvdemux->videosrcpad) {
+    gst_event_ref (event);
+    res |= gst_pad_push_event (dvdemux->videosrcpad, event);
+  }
+
+  if (dvdemux->audiosrcpad)
+    res |= gst_pad_push_event (dvdemux->audiosrcpad, event);
+  else {
+    gst_event_unref (event);
+    res = TRUE;
+  }
+
+  return res;
+}
+
+static gboolean
+gst_dvdemux_handle_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstDVDemux *dvdemux = GST_DVDEMUX (parent);
+  gboolean res = TRUE;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      /* we are not blocking on anything exect the push() calls
+       * to the peer which will be unblocked by forwarding the
+       * event.*/
+      res = gst_dvdemux_push_event (dvdemux, event);
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      gst_adapter_clear (dvdemux->adapter);
+      GST_DEBUG ("cleared adapter");
+      gst_segment_init (&dvdemux->byte_segment, GST_FORMAT_BYTES);
+      gst_segment_init (&dvdemux->time_segment, GST_FORMAT_TIME);
+      dvdemux->discont = TRUE;
+      res = gst_dvdemux_push_event (dvdemux, event);
+      break;
+    case GST_EVENT_SEGMENT:
+    {
+      const GstSegment *segment;
+
+      gst_event_parse_segment (event, &segment);
+      switch (segment->format) {
+        case GST_FORMAT_BYTES:
+          gst_segment_copy_into (segment, &dvdemux->byte_segment);
+          dvdemux->need_segment = TRUE;
+          dvdemux->segment_seqnum = gst_event_get_seqnum (event);
+          gst_event_unref (event);
+          break;
+        case GST_FORMAT_TIME:
+          gst_segment_copy_into (segment, &dvdemux->time_segment);
+
+          dvdemux->upstream_time_segment = TRUE;
+          dvdemux->segment_seqnum = gst_event_get_seqnum (event);
+
+          /* and we can just forward this time event */
+          res = gst_dvdemux_push_event (dvdemux, event);
+          break;
+        default:
+          gst_event_unref (event);
+          /* cannot accept this format */
+          res = FALSE;
+          break;
+      }
+      break;
+    }
+    case GST_EVENT_EOS:
+      /* flush any pending data, should be nothing left. */
+      gst_dvdemux_flush (dvdemux);
+      /* forward event */
+      res = gst_dvdemux_push_event (dvdemux, event);
+      /* and clear the adapter */
+      gst_adapter_clear (dvdemux->adapter);
+      break;
+    case GST_EVENT_CAPS:
+      gst_event_unref (event);
+      break;
+    default:
+      res = gst_dvdemux_push_event (dvdemux, event);
+      break;
+  }
+
+  return res;
+}
+
+/* convert a pair of values on the given srcpad */
+static gboolean
+gst_dvdemux_convert_src_pair (GstDVDemux * dvdemux, GstPad * pad,
+    GstFormat src_format, gint64 src_start, gint64 src_stop,
+    GstFormat dst_format, gint64 * dst_start, gint64 * dst_stop)
+{
+  gboolean res;
+
+  GST_INFO ("starting conversion of start");
+  /* bring the format to time on srcpad. */
+  if (!(res = gst_dvdemux_src_convert (dvdemux, pad,
+              src_format, src_start, dst_format, dst_start))) {
+    goto done;
+  }
+  GST_INFO ("Finished conversion of start: %" G_GINT64_FORMAT, *dst_start);
+
+  GST_INFO ("starting conversion of stop");
+  /* bring the format to time on srcpad. */
+  if (!(res = gst_dvdemux_src_convert (dvdemux, pad,
+              src_format, src_stop, dst_format, dst_stop))) {
+    /* could not convert seek format to time offset */
+    goto done;
+  }
+  GST_INFO ("Finished conversion of stop: %" G_GINT64_FORMAT, *dst_stop);
+done:
+  return res;
+}
+
+/* convert a pair of values on the sinkpad */
+static gboolean
+gst_dvdemux_convert_sink_pair (GstDVDemux * dvdemux,
+    GstFormat src_format, gint64 src_start, gint64 src_stop,
+    GstFormat dst_format, gint64 * dst_start, gint64 * dst_stop)
+{
+  gboolean res;
+
+  GST_INFO ("starting conversion of start");
+  /* bring the format to time on srcpad. */
+  if (!(res = gst_dvdemux_sink_convert (dvdemux,
+              src_format, src_start, dst_format, dst_start))) {
+    goto done;
+  }
+  GST_INFO ("Finished conversion of start: %" G_GINT64_FORMAT, *dst_start);
+
+  GST_INFO ("starting conversion of stop");
+  /* bring the format to time on srcpad. */
+  if (!(res = gst_dvdemux_sink_convert (dvdemux,
+              src_format, src_stop, dst_format, dst_stop))) {
+    /* could not convert seek format to time offset */
+    goto done;
+  }
+  GST_INFO ("Finished conversion of stop: %" G_GINT64_FORMAT, *dst_stop);
+done:
+  return res;
+}
+
+/* convert a pair of values on the srcpad to a pair of
+ * values on the sinkpad 
+ */
+static gboolean
+gst_dvdemux_convert_src_to_sink (GstDVDemux * dvdemux, GstPad * pad,
+    GstFormat src_format, gint64 src_start, gint64 src_stop,
+    GstFormat dst_format, gint64 * dst_start, gint64 * dst_stop)
+{
+  GstFormat conv;
+  gboolean res;
+
+  conv = GST_FORMAT_TIME;
+  /* convert to TIME intermediate format */
+  if (!(res = gst_dvdemux_convert_src_pair (dvdemux, pad,
+              src_format, src_start, src_stop, conv, dst_start, dst_stop))) {
+    /* could not convert format to time offset */
+    goto done;
+  }
+  /* convert to dst format on sinkpad */
+  if (!(res = gst_dvdemux_convert_sink_pair (dvdemux,
+              conv, *dst_start, *dst_stop, dst_format, dst_start, dst_stop))) {
+    /* could not convert format to time offset */
+    goto done;
+  }
+done:
+  return res;
+}
+
+#if 0
+static gboolean
+gst_dvdemux_convert_segment (GstDVDemux * dvdemux, GstSegment * src,
+    GstSegment * dest)
+{
+  dest->rate = src->rate;
+  dest->abs_rate = src->abs_rate;
+  dest->flags = src->flags;
+
+  return TRUE;
+}
+#endif
+
+/* handle seek in push base mode.
+ *
+ * Convert the time seek to a bytes seek and send it
+ * upstream
+ * Does not take ownership of the event.
+ */
+static gboolean
+gst_dvdemux_handle_push_seek (GstDVDemux * dvdemux, GstPad * pad,
+    GstEvent * event)
+{
+  gboolean res = FALSE;
+  gdouble rate;
+  GstSeekFlags flags;
+  GstFormat format;
+  GstSeekType cur_type, stop_type;
+  gint64 cur, stop;
+  gint64 start_position, end_position;
+  GstEvent *newevent;
+
+  gst_event_parse_seek (event, &rate, &format, &flags,
+      &cur_type, &cur, &stop_type, &stop);
+
+  /* First try if upstream can handle time based seeks */
+  if (format == GST_FORMAT_TIME)
+    res = gst_pad_push_event (dvdemux->sinkpad, gst_event_ref (event));
+
+  if (!res) {
+    /* we convert the start/stop on the srcpad to the byte format
+     * on the sinkpad and forward the event */
+    res = gst_dvdemux_convert_src_to_sink (dvdemux, pad,
+        format, cur, stop, GST_FORMAT_BYTES, &start_position, &end_position);
+    if (!res)
+      goto done;
+
+    /* now this is the updated seek event on bytes */
+    newevent = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags,
+        cur_type, start_position, stop_type, end_position);
+    gst_event_set_seqnum (newevent, gst_event_get_seqnum (event));
+
+    res = gst_pad_push_event (dvdemux->sinkpad, newevent);
+  }
+done:
+  return res;
+}
+
+static void
+gst_dvdemux_update_frame_offsets (GstDVDemux * dvdemux, GstClockTime timestamp)
+{
+  /* calculate current frame number */
+  gst_dvdemux_src_convert (dvdemux, dvdemux->videosrcpad,
+      dvdemux->time_segment.format, timestamp,
+      GST_FORMAT_DEFAULT, &dvdemux->video_offset);
+
+  /* calculate current audio number */
+  gst_dvdemux_src_convert (dvdemux, dvdemux->audiosrcpad,
+      dvdemux->time_segment.format, timestamp,
+      GST_FORMAT_DEFAULT, &dvdemux->audio_offset);
+
+  /* every DV frame corresponts with one video frame */
+  dvdemux->frame_offset = dvdemux->video_offset;
+}
+
+/* position ourselves to the configured segment, used in pull mode.
+ * The input segment is in TIME format. We convert the time values
+ * to bytes values into our byte_segment which we use to pull data from
+ * the sinkpad peer.
+ */
+static gboolean
+gst_dvdemux_do_seek (GstDVDemux * demux, GstSegment * segment)
+{
+  gboolean res;
+  GstFormat format;
+
+  /* position to value configured is last_stop, this will round down
+   * to the byte position where the frame containing the given 
+   * timestamp can be found. */
+  format = GST_FORMAT_BYTES;
+  res = gst_dvdemux_sink_convert (demux,
+      segment->format, segment->position,
+      format, (gint64 *) & demux->byte_segment.position);
+  if (!res)
+    goto done;
+
+  /* update byte segment start */
+  gst_dvdemux_sink_convert (demux,
+      segment->format, segment->start, format,
+      (gint64 *) & demux->byte_segment.start);
+
+  /* update byte segment stop */
+  gst_dvdemux_sink_convert (demux,
+      segment->format, segment->stop, format,
+      (gint64 *) & demux->byte_segment.stop);
+
+  /* update byte segment time */
+  gst_dvdemux_sink_convert (demux,
+      segment->format, segment->time, format,
+      (gint64 *) & demux->byte_segment.time);
+
+  gst_dvdemux_update_frame_offsets (demux, segment->start);
+
+  demux->discont = TRUE;
+
+done:
+  return res;
+}
+
+/* handle seek in pull base mode.
+ *
+ * Does not take ownership of the event.
+ */
+static gboolean
+gst_dvdemux_handle_pull_seek (GstDVDemux * demux, GstPad * pad,
+    GstEvent * event)
+{
+  gboolean res;
+  gdouble rate;
+  GstFormat format;
+  GstSeekFlags flags;
+  GstSeekType cur_type, stop_type;
+  gint64 cur, stop;
+  gboolean flush;
+  gboolean update;
+  GstSegment seeksegment;
+  GstEvent *new_event;
+
+  GST_DEBUG_OBJECT (demux, "doing seek");
+
+  /* first bring the event format to TIME, our native format
+   * to perform the seek on */
+  if (event) {
+    GstFormat conv;
+
+    gst_event_parse_seek (event, &rate, &format, &flags,
+        &cur_type, &cur, &stop_type, &stop);
+
+    /* can't seek backwards yet */
+    if (rate <= 0.0)
+      goto wrong_rate;
+
+    /* convert input format to TIME */
+    conv = GST_FORMAT_TIME;
+    if (!(gst_dvdemux_convert_src_pair (demux, pad,
+                format, cur, stop, conv, &cur, &stop)))
+      goto no_format;
+
+    format = GST_FORMAT_TIME;
+  } else {
+    flags = 0;
+  }
+
+  demux->segment_seqnum = gst_event_get_seqnum (event);
+
+  flush = flags & GST_SEEK_FLAG_FLUSH;
+
+  /* send flush start */
+  if (flush) {
+    new_event = gst_event_new_flush_start ();
+    gst_event_set_seqnum (new_event, demux->segment_seqnum);
+    gst_dvdemux_push_event (demux, new_event);
+  } else {
+    gst_pad_pause_task (demux->sinkpad);
+  }
+
+  /* grab streaming lock, this should eventually be possible, either
+   * because the task is paused or our streaming thread stopped
+   * because our peer is flushing. */
+  GST_PAD_STREAM_LOCK (demux->sinkpad);
+
+  /* make copy into temp structure, we can only update the main one
+   * when the subclass actually could to the seek. */
+  memcpy (&seeksegment, &demux->time_segment, sizeof (GstSegment));
+
+  /* now configure the seek segment */
+  if (event) {
+    gst_segment_do_seek (&seeksegment, rate, format, flags,
+        cur_type, cur, stop_type, stop, &update);
+  }
+
+  GST_DEBUG_OBJECT (demux, "segment configured from %" G_GINT64_FORMAT
+      " to %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT,
+      seeksegment.start, seeksegment.stop, seeksegment.position);
+
+  /* do the seek, segment.position contains new position. */
+  res = gst_dvdemux_do_seek (demux, &seeksegment);
+
+  /* and prepare to continue streaming */
+  if (flush) {
+    /* send flush stop, peer will accept data and events again. We
+     * are not yet providing data as we still have the STREAM_LOCK. */
+    new_event = gst_event_new_flush_stop (TRUE);
+    gst_event_set_seqnum (new_event, demux->segment_seqnum);
+    gst_dvdemux_push_event (demux, new_event);
+  }
+
+  /* if successfull seek, we update our real segment and push
+   * out the new segment. */
+  if (res) {
+    memcpy (&demux->time_segment, &seeksegment, sizeof (GstSegment));
+
+    if (demux->time_segment.flags & GST_SEEK_FLAG_SEGMENT) {
+      GstMessage *message;
+
+      message = gst_message_new_segment_start (GST_OBJECT_CAST (demux),
+          demux->time_segment.format, demux->time_segment.position);
+      gst_message_set_seqnum (message, demux->segment_seqnum);
+      gst_element_post_message (GST_ELEMENT_CAST (demux), message);
+    }
+    if ((stop = demux->time_segment.stop) == -1)
+      stop = demux->time_segment.duration;
+
+    GST_INFO_OBJECT (demux,
+        "Saving newsegment event to be sent in streaming thread");
+
+    if (demux->pending_segment)
+      gst_event_unref (demux->pending_segment);
+
+    demux->pending_segment = gst_event_new_segment (&demux->time_segment);
+    gst_event_set_seqnum (demux->pending_segment, demux->segment_seqnum);
+
+    demux->need_segment = FALSE;
+  }
+
+  /* and restart the task in case it got paused explicitely or by
+   * the FLUSH_START event we pushed out. */
+  gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_dvdemux_loop,
+      demux->sinkpad, NULL);
+
+  /* and release the lock again so we can continue streaming */
+  GST_PAD_STREAM_UNLOCK (demux->sinkpad);
+
+  return TRUE;
+
+  /* ERRORS */
+wrong_rate:
+  {
+    GST_DEBUG_OBJECT (demux, "negative playback rate %lf not supported.", rate);
+    return FALSE;
+  }
+no_format:
+  {
+    GST_DEBUG_OBJECT (demux, "cannot convert to TIME format, seek aborted.");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_dvdemux_send_event (GstElement * element, GstEvent * event)
+{
+  GstDVDemux *dvdemux = GST_DVDEMUX (element);
+  gboolean res = FALSE;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+    {
+      /* checking header and configuring the seek must be atomic */
+      GST_OBJECT_LOCK (dvdemux);
+      if (g_atomic_int_get (&dvdemux->found_header) == 0) {
+        GstEvent **event_p;
+
+        event_p = &dvdemux->seek_event;
+
+        /* We don't have pads yet. Keep the event. */
+        GST_INFO_OBJECT (dvdemux, "Keeping the seek event for later");
+
+        gst_event_replace (event_p, event);
+        GST_OBJECT_UNLOCK (dvdemux);
+
+        res = TRUE;
+      } else {
+        GST_OBJECT_UNLOCK (dvdemux);
+
+        if (dvdemux->seek_handler)
+          res = dvdemux->seek_handler (dvdemux, dvdemux->videosrcpad, event);
+        gst_event_unref (event);
+      }
+      break;
+    }
+    default:
+      res = GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
+      break;
+  }
+
+  return res;
+}
+
+/* handle an event on the source pad, it's most likely a seek */
+static gboolean
+gst_dvdemux_handle_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  gboolean res = FALSE;
+  GstDVDemux *dvdemux;
+
+  dvdemux = GST_DVDEMUX (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+      /* seek handler is installed based on scheduling mode */
+      if (dvdemux->seek_handler)
+        res = dvdemux->seek_handler (dvdemux, pad, event);
+      gst_event_unref (event);
+      break;
+    default:
+      res = gst_pad_push_event (dvdemux->sinkpad, event);
+      break;
+  }
+
+  return res;
+}
+
+/* does not take ownership of buffer */
+static GstFlowReturn
+gst_dvdemux_demux_audio (GstDVDemux * dvdemux, GstBuffer * buffer,
+    guint64 duration)
+{
+  gint num_samples;
+  GstFlowReturn ret;
+  GstMapInfo map;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  dv_decode_full_audio (dvdemux->decoder, map.data, dvdemux->audio_buffers);
+  gst_buffer_unmap (buffer, &map);
+
+  if (G_LIKELY ((num_samples = dv_get_num_samples (dvdemux->decoder)) > 0)) {
+    gint16 *a_ptr;
+    gint i, j;
+    GstBuffer *outbuf;
+    gint frequency, channels;
+
+    /* get initial format or check if format changed */
+    frequency = dv_get_frequency (dvdemux->decoder);
+    channels = dv_get_num_channels (dvdemux->decoder);
+
+    if (G_UNLIKELY ((dvdemux->audiosrcpad == NULL)
+            || (frequency != dvdemux->frequency)
+            || (channels != dvdemux->channels))) {
+      GstCaps *caps;
+      GstAudioInfo info;
+
+      dvdemux->frequency = frequency;
+      dvdemux->channels = channels;
+
+      gst_audio_info_init (&info);
+      gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16LE,
+          frequency, channels, NULL);
+      caps = gst_audio_info_to_caps (&info);
+      if (G_UNLIKELY (dvdemux->audiosrcpad == NULL)) {
+        dvdemux->audiosrcpad =
+            gst_dvdemux_add_pad (dvdemux, &audio_src_temp, caps);
+
+        if (dvdemux->videosrcpad && dvdemux->audiosrcpad)
+          gst_element_no_more_pads (GST_ELEMENT (dvdemux));
+
+      } else {
+        gst_pad_set_caps (dvdemux->audiosrcpad, caps);
+      }
+      gst_caps_unref (caps);
+    }
+
+    outbuf = gst_buffer_new_and_alloc (num_samples *
+        sizeof (gint16) * dvdemux->channels);
+
+    gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+    a_ptr = (gint16 *) map.data;
+
+    for (i = 0; i < num_samples; i++) {
+      for (j = 0; j < dvdemux->channels; j++) {
+        *(a_ptr++) = dvdemux->audio_buffers[j][i];
+      }
+    }
+    gst_buffer_unmap (outbuf, &map);
+
+    GST_DEBUG ("pushing audio %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (dvdemux->time_segment.position));
+
+    GST_BUFFER_TIMESTAMP (outbuf) = dvdemux->time_segment.position;
+    GST_BUFFER_DURATION (outbuf) = duration;
+    GST_BUFFER_OFFSET (outbuf) = dvdemux->audio_offset;
+    dvdemux->audio_offset += num_samples;
+    GST_BUFFER_OFFSET_END (outbuf) = dvdemux->audio_offset;
+
+    if (dvdemux->new_media || dvdemux->discont)
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+    ret = gst_pad_push (dvdemux->audiosrcpad, outbuf);
+  } else {
+    /* no samples */
+    ret = GST_FLOW_OK;
+  }
+
+  return ret;
+}
+
+/* takes ownership of buffer */
+static GstFlowReturn
+gst_dvdemux_demux_video (GstDVDemux * dvdemux, GstBuffer * buffer,
+    guint64 duration)
+{
+  GstBuffer *outbuf;
+  gint height;
+  gboolean wide;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  /* get params */
+  /* framerate is already up-to-date */
+  height = dvdemux->decoder->height;
+  wide = dv_format_wide (dvdemux->decoder);
+
+  /* see if anything changed */
+  if (G_UNLIKELY ((dvdemux->videosrcpad == NULL) || (dvdemux->height != height)
+          || dvdemux->wide != wide)) {
+    gint par_x, par_y;
+    GstCaps *caps;
+
+    dvdemux->height = height;
+    dvdemux->wide = wide;
+
+    if (dvdemux->decoder->system == e_dv_system_625_50) {
+      if (wide) {
+        par_x = PAL_WIDE_PAR_X;
+        par_y = PAL_WIDE_PAR_Y;
+      } else {
+        par_x = PAL_NORMAL_PAR_X;
+        par_y = PAL_NORMAL_PAR_Y;
+      }
+    } else {
+      if (wide) {
+        par_x = NTSC_WIDE_PAR_X;
+        par_y = NTSC_WIDE_PAR_Y;
+      } else {
+        par_x = NTSC_NORMAL_PAR_X;
+        par_y = NTSC_NORMAL_PAR_Y;
+      }
+    }
+
+    caps = gst_caps_new_simple ("video/x-dv",
+        "systemstream", G_TYPE_BOOLEAN, FALSE,
+        "width", G_TYPE_INT, 720,
+        "height", G_TYPE_INT, height,
+        "framerate", GST_TYPE_FRACTION, dvdemux->framerate_numerator,
+        dvdemux->framerate_denominator,
+        "pixel-aspect-ratio", GST_TYPE_FRACTION, par_x, par_y, NULL);
+
+    if (G_UNLIKELY (dvdemux->videosrcpad == NULL)) {
+      dvdemux->videosrcpad =
+          gst_dvdemux_add_pad (dvdemux, &video_src_temp, caps);
+
+      if (dvdemux->videosrcpad && dvdemux->audiosrcpad)
+        gst_element_no_more_pads (GST_ELEMENT (dvdemux));
+
+    } else {
+      gst_pad_set_caps (dvdemux->videosrcpad, caps);
+    }
+    gst_caps_unref (caps);
+  }
+
+  /* takes ownership of buffer here, we just need to modify
+   * the metadata. */
+  outbuf = gst_buffer_make_writable (buffer);
+
+  GST_BUFFER_TIMESTAMP (outbuf) = dvdemux->time_segment.position;
+  GST_BUFFER_OFFSET (outbuf) = dvdemux->video_offset;
+  GST_BUFFER_OFFSET_END (outbuf) = dvdemux->video_offset + 1;
+  GST_BUFFER_DURATION (outbuf) = duration;
+
+  if (dvdemux->new_media || dvdemux->discont)
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+
+  GST_DEBUG ("pushing video %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (dvdemux->time_segment.position));
+
+  ret = gst_pad_push (dvdemux->videosrcpad, outbuf);
+
+  dvdemux->video_offset++;
+
+  return ret;
+}
+
+static int
+get_ssyb_offset (int dif, int ssyb)
+{
+  int offset;
+
+  offset = dif * 12000;         /* to dif */
+  offset += 80 * (1 + (ssyb / 6));      /* to subcode pack */
+  offset += 3;                  /* past header */
+  offset += 8 * (ssyb % 6);     /* to ssyb */
+
+  return offset;
+}
+
+static gboolean
+gst_dvdemux_get_timecode (GstDVDemux * dvdemux, GstBuffer * buffer,
+    GstSMPTETimeCode * timecode)
+{
+  guint8 *data;
+  GstMapInfo map;
+  int offset;
+  int dif;
+  int n_difs = dvdemux->decoder->num_dif_seqs;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  data = map.data;
+  for (dif = 0; dif < n_difs; dif++) {
+    offset = get_ssyb_offset (dif, 3);
+    if (data[offset + 3] == 0x13) {
+      timecode->frames = ((data[offset + 4] >> 4) & 0x3) * 10 +
+          (data[offset + 4] & 0xf);
+      timecode->seconds = ((data[offset + 5] >> 4) & 0x3) * 10 +
+          (data[offset + 5] & 0xf);
+      timecode->minutes = ((data[offset + 6] >> 4) & 0x3) * 10 +
+          (data[offset + 6] & 0xf);
+      timecode->hours = ((data[offset + 7] >> 4) & 0x3) * 10 +
+          (data[offset + 7] & 0xf);
+      GST_DEBUG ("got timecode %" GST_SMPTE_TIME_CODE_FORMAT,
+          GST_SMPTE_TIME_CODE_ARGS (timecode));
+      gst_buffer_unmap (buffer, &map);
+      return TRUE;
+    }
+  }
+
+  gst_buffer_unmap (buffer, &map);
+  return FALSE;
+}
+
+static gboolean
+gst_dvdemux_is_new_media (GstDVDemux * dvdemux, GstBuffer * buffer)
+{
+  guint8 *data;
+  GstMapInfo map;
+  int aaux_offset;
+  int dif;
+  int n_difs;
+
+  n_difs = dvdemux->decoder->num_dif_seqs;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  data = map.data;
+  for (dif = 0; dif < n_difs; dif++) {
+    if (dif & 1) {
+      aaux_offset = (dif * 12000) + (6 + 16 * 1) * 80 + 3;
+    } else {
+      aaux_offset = (dif * 12000) + (6 + 16 * 4) * 80 + 3;
+    }
+    if (data[aaux_offset + 0] == 0x51) {
+      if ((data[aaux_offset + 2] & 0x80) == 0) {
+        gst_buffer_unmap (buffer, &map);
+        return TRUE;
+      }
+    }
+  }
+
+  gst_buffer_unmap (buffer, &map);
+  return FALSE;
+}
+
+/* takes ownership of buffer */
+static GstFlowReturn
+gst_dvdemux_demux_frame (GstDVDemux * dvdemux, GstBuffer * buffer)
+{
+  GstClockTime next_ts;
+  GstFlowReturn aret, vret, ret;
+  GstMapInfo map;
+  guint64 duration;
+  GstSMPTETimeCode timecode;
+  int frame_number;
+
+  if (dvdemux->need_segment) {
+    GstFormat format;
+    GstEvent *event;
+
+    g_assert (!dvdemux->upstream_time_segment);
+
+    /* convert to time and store as start/end_timestamp */
+    format = GST_FORMAT_TIME;
+    if (!(gst_dvdemux_convert_sink_pair (dvdemux,
+                GST_FORMAT_BYTES, dvdemux->byte_segment.start,
+                dvdemux->byte_segment.stop, format,
+                (gint64 *) & dvdemux->time_segment.start,
+                (gint64 *) & dvdemux->time_segment.stop)))
+      goto segment_error;
+
+    dvdemux->time_segment.time = dvdemux->time_segment.start;
+    dvdemux->time_segment.rate = dvdemux->byte_segment.rate;
+
+    gst_dvdemux_sink_convert (dvdemux,
+        GST_FORMAT_BYTES, dvdemux->byte_segment.position,
+        GST_FORMAT_TIME, (gint64 *) & dvdemux->time_segment.position);
+
+    gst_dvdemux_update_frame_offsets (dvdemux, dvdemux->time_segment.position);
+
+    GST_DEBUG_OBJECT (dvdemux, "sending segment start: %" GST_TIME_FORMAT
+        ", stop: %" GST_TIME_FORMAT ", time: %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (dvdemux->time_segment.start),
+        GST_TIME_ARGS (dvdemux->time_segment.stop),
+        GST_TIME_ARGS (dvdemux->time_segment.start));
+
+    event = gst_event_new_segment (&dvdemux->time_segment);
+    if (dvdemux->segment_seqnum)
+      gst_event_set_seqnum (event, dvdemux->segment_seqnum);
+    gst_dvdemux_push_event (dvdemux, event);
+
+    dvdemux->need_segment = FALSE;
+  }
+
+  gst_dvdemux_get_timecode (dvdemux, buffer, &timecode);
+  gst_smpte_time_code_get_frame_number (
+      (dvdemux->decoder->system == e_dv_system_625_50) ?
+      GST_SMPTE_TIME_CODE_SYSTEM_25 : GST_SMPTE_TIME_CODE_SYSTEM_30,
+      &frame_number, &timecode);
+
+  if (dvdemux->time_segment.rate < 0) {
+    next_ts = gst_util_uint64_scale_int (
+        (dvdemux->frame_offset >
+            0 ? dvdemux->frame_offset - 1 : 0) * GST_SECOND,
+        dvdemux->framerate_denominator, dvdemux->framerate_numerator);
+    duration = dvdemux->time_segment.position - next_ts;
+  } else {
+    next_ts = gst_util_uint64_scale_int (
+        (dvdemux->frame_offset + 1) * GST_SECOND,
+        dvdemux->framerate_denominator, dvdemux->framerate_numerator);
+    duration = next_ts - dvdemux->time_segment.position;
+  }
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  dv_parse_packs (dvdemux->decoder, map.data);
+  gst_buffer_unmap (buffer, &map);
+  dvdemux->new_media = FALSE;
+  if (gst_dvdemux_is_new_media (dvdemux, buffer) &&
+      dvdemux->frames_since_new_media > 2) {
+    dvdemux->new_media = TRUE;
+    dvdemux->frames_since_new_media = 0;
+  }
+  dvdemux->frames_since_new_media++;
+
+  /* does not take ownership of buffer */
+  aret = ret = gst_dvdemux_demux_audio (dvdemux, buffer, duration);
+  if (G_UNLIKELY (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)) {
+    gst_buffer_unref (buffer);
+    goto done;
+  }
+
+  /* takes ownership of buffer */
+  vret = ret = gst_dvdemux_demux_video (dvdemux, buffer, duration);
+  if (G_UNLIKELY (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED))
+    goto done;
+
+  /* if both are not linked, we stop */
+  if (G_UNLIKELY (aret == GST_FLOW_NOT_LINKED && vret == GST_FLOW_NOT_LINKED)) {
+    ret = GST_FLOW_NOT_LINKED;
+    goto done;
+  }
+
+  dvdemux->discont = FALSE;
+  dvdemux->time_segment.position = next_ts;
+
+  if (dvdemux->time_segment.rate < 0) {
+    if (dvdemux->frame_offset > 0)
+      dvdemux->frame_offset--;
+    else
+      GST_WARNING_OBJECT (dvdemux,
+          "Got before frame offset 0 in reverse playback");
+  } else {
+    dvdemux->frame_offset++;
+  }
+
+  /* check for the end of the segment */
+  if ((dvdemux->time_segment.rate > 0 && dvdemux->time_segment.stop != -1
+          && next_ts > dvdemux->time_segment.stop)
+      || (dvdemux->time_segment.rate < 0
+          && dvdemux->time_segment.start > next_ts))
+    ret = GST_FLOW_EOS;
+  else
+    ret = GST_FLOW_OK;
+
+done:
+  return ret;
+
+  /* ERRORS */
+segment_error:
+  {
+    GST_DEBUG ("error generating new_segment event");
+    gst_buffer_unref (buffer);
+    return GST_FLOW_ERROR;
+  }
+}
+
+/* flush any remaining data in the adapter, used in chain based scheduling mode */
+static GstFlowReturn
+gst_dvdemux_flush (GstDVDemux * dvdemux)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  while (gst_adapter_available (dvdemux->adapter) >= dvdemux->frame_len) {
+    const guint8 *data;
+    gint length;
+
+    /* get the accumulated bytes */
+    data = gst_adapter_map (dvdemux->adapter, dvdemux->frame_len);
+
+    /* parse header to know the length and other params */
+    if (G_UNLIKELY (dv_parse_header (dvdemux->decoder, data) < 0)) {
+      gst_adapter_unmap (dvdemux->adapter);
+      goto parse_header_error;
+    }
+    gst_adapter_unmap (dvdemux->adapter);
+
+    /* after parsing the header we know the length of the data */
+    length = dvdemux->frame_len = dvdemux->decoder->frame_size;
+    if (dvdemux->decoder->system == e_dv_system_625_50) {
+      dvdemux->framerate_numerator = PAL_FRAMERATE_NUMERATOR;
+      dvdemux->framerate_denominator = PAL_FRAMERATE_DENOMINATOR;
+    } else {
+      dvdemux->framerate_numerator = NTSC_FRAMERATE_NUMERATOR;
+      dvdemux->framerate_denominator = NTSC_FRAMERATE_DENOMINATOR;
+    }
+    g_atomic_int_set (&dvdemux->found_header, 1);
+
+    /* let demux_video set the height, it needs to detect when things change so
+     * it can reset caps */
+
+    /* if we still have enough for a frame, start decoding */
+    if (G_LIKELY (gst_adapter_available (dvdemux->adapter) >= length)) {
+      GstBuffer *buffer;
+
+      buffer = gst_adapter_take_buffer (dvdemux->adapter, length);
+
+      /* and decode the buffer, takes ownership */
+      ret = gst_dvdemux_demux_frame (dvdemux, buffer);
+      if (G_UNLIKELY (ret != GST_FLOW_OK))
+        goto done;
+    }
+  }
+done:
+  return ret;
+
+  /* ERRORS */
+parse_header_error:
+  {
+    GST_ELEMENT_ERROR (dvdemux, STREAM, DECODE,
+        (NULL), ("Error parsing DV header"));
+    return GST_FLOW_ERROR;
+  }
+}
+
+/* streaming operation: 
+ *
+ * accumulate data until we have a frame, then decode. 
+ */
+static GstFlowReturn
+gst_dvdemux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstDVDemux *dvdemux;
+  GstFlowReturn ret;
+  GstClockTime timestamp;
+
+  dvdemux = GST_DVDEMUX (parent);
+
+  /* a discontinuity in the stream, we need to get rid of
+   * accumulated data in the adapter and assume a new frame
+   * starts after the discontinuity */
+  if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))) {
+    gst_adapter_clear (dvdemux->adapter);
+    dvdemux->discont = TRUE;
+
+    /* Should recheck where we are */
+    if (!dvdemux->upstream_time_segment)
+      dvdemux->need_segment = TRUE;
+  }
+
+  /* a timestamp always should be respected */
+  timestamp = GST_BUFFER_TIMESTAMP (buffer);
+  if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+    dvdemux->time_segment.position = timestamp;
+
+    if (dvdemux->discont)
+      gst_dvdemux_update_frame_offsets (dvdemux,
+          dvdemux->time_segment.position);
+  } else if (dvdemux->upstream_time_segment && dvdemux->discont) {
+    /* This will probably fail later to provide correct
+     * timestamps and/or durations but also should not happen */
+    GST_ERROR_OBJECT (dvdemux,
+        "Upstream provides TIME segment but no PTS after discont");
+  }
+
+  gst_adapter_push (dvdemux->adapter, buffer);
+
+  /* Apparently dv_parse_header can read from the body of the frame
+   * too, so it needs more than header_size bytes. Wacky!
+   */
+  if (G_UNLIKELY (dvdemux->frame_len == -1)) {
+    /* if we don't know the length of a frame, we assume it is
+     * the NTSC_BUFFER length, as this is enough to figure out 
+     * if this is PAL or NTSC */
+    dvdemux->frame_len = NTSC_BUFFER;
+  }
+
+  /* and try to flush pending frames */
+  ret = gst_dvdemux_flush (dvdemux);
+
+  return ret;
+}
+
+/* pull based operation.
+ *
+ * Read header first to figure out the frame size. Then read
+ * and decode full frames.
+ */
+static void
+gst_dvdemux_loop (GstPad * pad)
+{
+  GstFlowReturn ret;
+  GstDVDemux *dvdemux;
+  GstBuffer *buffer = NULL;
+  GstMapInfo map;
+
+  dvdemux = GST_DVDEMUX (gst_pad_get_parent (pad));
+
+  if (G_UNLIKELY (g_atomic_int_get (&dvdemux->found_header) == 0)) {
+    GST_DEBUG_OBJECT (dvdemux, "pulling first buffer");
+    /* pull in NTSC sized buffer to figure out the frame
+     * length */
+    ret = gst_pad_pull_range (dvdemux->sinkpad,
+        dvdemux->byte_segment.position, NTSC_BUFFER, &buffer);
+    if (G_UNLIKELY (ret != GST_FLOW_OK))
+      goto pause;
+
+    /* check buffer size, don't want to read small buffers */
+    if (G_UNLIKELY (gst_buffer_get_size (buffer) < NTSC_BUFFER))
+      goto small_buffer;
+
+    gst_buffer_map (buffer, &map, GST_MAP_READ);
+    /* parse header to know the length and other params */
+    if (G_UNLIKELY (dv_parse_header (dvdemux->decoder, map.data) < 0)) {
+      gst_buffer_unmap (buffer, &map);
+      goto parse_header_error;
+    }
+    gst_buffer_unmap (buffer, &map);
+
+    /* after parsing the header we know the length of the data */
+    dvdemux->frame_len = dvdemux->decoder->frame_size;
+    if (dvdemux->decoder->system == e_dv_system_625_50) {
+      dvdemux->framerate_numerator = PAL_FRAMERATE_NUMERATOR;
+      dvdemux->framerate_denominator = PAL_FRAMERATE_DENOMINATOR;
+    } else {
+      dvdemux->framerate_numerator = NTSC_FRAMERATE_NUMERATOR;
+      dvdemux->framerate_denominator = NTSC_FRAMERATE_DENOMINATOR;
+    }
+    dvdemux->need_segment = TRUE;
+
+    /* see if we need to read a larger part */
+    if (dvdemux->frame_len != NTSC_BUFFER) {
+      gst_buffer_unref (buffer);
+      buffer = NULL;
+    }
+
+    {
+      GstEvent *event;
+
+      /* setting header and prrforming the seek must be atomic */
+      GST_OBJECT_LOCK (dvdemux);
+      /* got header now */
+      g_atomic_int_set (&dvdemux->found_header, 1);
+
+      /* now perform pending seek if any. */
+      event = dvdemux->seek_event;
+      if (event)
+        gst_event_ref (event);
+      GST_OBJECT_UNLOCK (dvdemux);
+
+      if (event) {
+        if (!gst_dvdemux_handle_pull_seek (dvdemux, dvdemux->videosrcpad,
+                event)) {
+          GST_ELEMENT_WARNING (dvdemux, STREAM, DECODE, (NULL),
+              ("Error perfoming initial seek"));
+        }
+        gst_event_unref (event);
+
+        /* and we need to pull a new buffer in all cases. */
+        if (buffer) {
+          gst_buffer_unref (buffer);
+          buffer = NULL;
+        }
+      }
+    }
+  }
+
+  if (G_UNLIKELY (dvdemux->pending_segment)) {
+
+    /* now send the newsegment */
+    GST_DEBUG_OBJECT (dvdemux, "Sending newsegment from");
+
+    gst_dvdemux_push_event (dvdemux, dvdemux->pending_segment);
+    dvdemux->pending_segment = NULL;
+  }
+
+  if (G_LIKELY (buffer == NULL)) {
+    GST_DEBUG_OBJECT (dvdemux, "pulling buffer at offset %" G_GINT64_FORMAT,
+        dvdemux->byte_segment.position);
+
+    ret = gst_pad_pull_range (dvdemux->sinkpad,
+        dvdemux->byte_segment.position, dvdemux->frame_len, &buffer);
+    if (ret != GST_FLOW_OK)
+      goto pause;
+
+    /* check buffer size, don't want to read small buffers */
+    if (gst_buffer_get_size (buffer) < dvdemux->frame_len)
+      goto small_buffer;
+  }
+  /* and decode the buffer */
+  ret = gst_dvdemux_demux_frame (dvdemux, buffer);
+  if (G_UNLIKELY (ret != GST_FLOW_OK))
+    goto pause;
+
+  /* and position ourselves for the next buffer */
+  dvdemux->byte_segment.position += dvdemux->frame_len;
+
+done:
+  gst_object_unref (dvdemux);
+
+  return;
+
+  /* ERRORS */
+parse_header_error:
+  {
+    GstEvent *event;
+
+    GST_ELEMENT_ERROR (dvdemux, STREAM, DECODE,
+        (NULL), ("Error parsing DV header"));
+    gst_buffer_unref (buffer);
+    gst_pad_pause_task (dvdemux->sinkpad);
+    event = gst_event_new_eos ();
+    if (dvdemux->segment_seqnum)
+      gst_event_set_seqnum (event, dvdemux->segment_seqnum);
+    gst_dvdemux_push_event (dvdemux, event);
+    goto done;
+  }
+small_buffer:
+  {
+    GstEvent *event;
+
+    GST_ELEMENT_ERROR (dvdemux, STREAM, DECODE,
+        (NULL), ("Error reading buffer"));
+    gst_buffer_unref (buffer);
+    gst_pad_pause_task (dvdemux->sinkpad);
+    event = gst_event_new_eos ();
+    if (dvdemux->segment_seqnum)
+      gst_event_set_seqnum (event, dvdemux->segment_seqnum);
+    gst_dvdemux_push_event (dvdemux, event);
+    goto done;
+  }
+pause:
+  {
+    GST_INFO_OBJECT (dvdemux, "pausing task, %s", gst_flow_get_name (ret));
+    gst_pad_pause_task (dvdemux->sinkpad);
+    if (ret == GST_FLOW_EOS) {
+      GST_LOG_OBJECT (dvdemux, "got eos");
+      /* so align our position with the end of it, if there is one
+       * this ensures a subsequent will arrive at correct base/acc time */
+      if (dvdemux->time_segment.rate > 0.0 &&
+          GST_CLOCK_TIME_IS_VALID (dvdemux->time_segment.stop))
+        dvdemux->time_segment.position = dvdemux->time_segment.stop;
+      else if (dvdemux->time_segment.rate < 0.0)
+        dvdemux->time_segment.position = dvdemux->time_segment.start;
+      /* perform EOS logic */
+      if (dvdemux->time_segment.flags & GST_SEEK_FLAG_SEGMENT) {
+        GstMessage *message;
+        GstEvent *event;
+
+        event = gst_event_new_segment_done (dvdemux->time_segment.format,
+            dvdemux->time_segment.position);
+        if (dvdemux->segment_seqnum)
+          gst_event_set_seqnum (event, dvdemux->segment_seqnum);
+
+        message = gst_message_new_segment_done (GST_OBJECT_CAST (dvdemux),
+            dvdemux->time_segment.format, dvdemux->time_segment.position);
+        if (dvdemux->segment_seqnum)
+          gst_message_set_seqnum (message, dvdemux->segment_seqnum);
+
+        gst_element_post_message (GST_ELEMENT (dvdemux), message);
+        gst_dvdemux_push_event (dvdemux, event);
+      } else {
+        GstEvent *event = gst_event_new_eos ();
+        if (dvdemux->segment_seqnum)
+          gst_event_set_seqnum (event, dvdemux->segment_seqnum);
+        gst_dvdemux_push_event (dvdemux, event);
+      }
+    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
+      GstEvent *event = gst_event_new_eos ();
+      /* for fatal errors or not-linked we post an error message */
+      GST_ELEMENT_FLOW_ERROR (dvdemux, ret);
+      if (dvdemux->segment_seqnum)
+        gst_event_set_seqnum (event, dvdemux->segment_seqnum);
+      gst_dvdemux_push_event (dvdemux, event);
+    }
+    goto done;
+  }
+}
+
+static gboolean
+gst_dvdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
+    GstPadMode mode, gboolean active)
+{
+  gboolean res;
+  GstDVDemux *demux = GST_DVDEMUX (parent);
+
+  switch (mode) {
+    case GST_PAD_MODE_PULL:
+      if (active) {
+        demux->seek_handler = gst_dvdemux_handle_pull_seek;
+        res = gst_pad_start_task (sinkpad,
+            (GstTaskFunction) gst_dvdemux_loop, sinkpad, NULL);
+      } else {
+        demux->seek_handler = NULL;
+        res = gst_pad_stop_task (sinkpad);
+      }
+      break;
+    case GST_PAD_MODE_PUSH:
+      if (active) {
+        GST_DEBUG_OBJECT (demux, "activating push/chain function");
+        demux->seek_handler = gst_dvdemux_handle_push_seek;
+      } else {
+        GST_DEBUG_OBJECT (demux, "deactivating push/chain function");
+        demux->seek_handler = NULL;
+      }
+      res = TRUE;
+      break;
+    default:
+      res = FALSE;
+      break;
+  }
+  return res;
+}
+
+/* decide on push or pull based scheduling */
+static gboolean
+gst_dvdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
+{
+  GstQuery *query;
+  gboolean pull_mode;
+
+  query = gst_query_new_scheduling ();
+
+  if (!gst_pad_peer_query (sinkpad, query)) {
+    gst_query_unref (query);
+    goto activate_push;
+  }
+
+  pull_mode = gst_query_has_scheduling_mode_with_flags (query,
+      GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
+  gst_query_unref (query);
+
+  if (!pull_mode)
+    goto activate_push;
+
+  GST_DEBUG_OBJECT (sinkpad, "activating pull");
+  return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
+
+activate_push:
+  {
+    GST_DEBUG_OBJECT (sinkpad, "activating push");
+    return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
+  }
+}
+
+static GstStateChangeReturn
+gst_dvdemux_change_state (GstElement * element, GstStateChange transition)
+{
+  GstDVDemux *dvdemux = GST_DVDEMUX (element);
+  GstStateChangeReturn ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      dvdemux->decoder = dv_decoder_new (0, FALSE, FALSE);
+      dv_set_error_log (dvdemux->decoder, NULL);
+      gst_dvdemux_reset (dvdemux);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_adapter_clear (dvdemux->adapter);
+      dv_decoder_free (dvdemux->decoder);
+      dvdemux->decoder = NULL;
+
+      gst_dvdemux_remove_pads (dvdemux);
+
+      if (dvdemux->tag_event) {
+        gst_event_unref (dvdemux->tag_event);
+        dvdemux->tag_event = NULL;
+      }
+
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+    {
+      GstEvent **event_p;
+
+      event_p = &dvdemux->seek_event;
+      gst_event_replace (event_p, NULL);
+      if (dvdemux->pending_segment)
+        gst_event_unref (dvdemux->pending_segment);
+      dvdemux->pending_segment = NULL;
+      break;
+    }
+    default:
+      break;
+  }
+  return ret;
+}
diff --git a/ext/dv/gstdvdemux.h b/ext/dv/gstdvdemux.h
new file mode 100644
index 0000000..95c9320
--- /dev/null
+++ b/ext/dv/gstdvdemux.h
@@ -0,0 +1,102 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_DVDEMUX_H__
+#define __GST_DVDEMUX_H__
+
+#include <gst/gst.h>
+#include <libdv/dv.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DVDEMUX \
+  (gst_dvdemux_get_type())
+#define GST_DVDEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DVDEMUX,GstDVDemux))
+#define GST_DVDEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DVDEMUX,GstDVDemuxClass))
+#define GST_IS_DVDEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DVDEMUX))
+#define GST_IS_DVDEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DVDEMUX))
+
+
+typedef struct _GstDVDemux GstDVDemux;
+typedef struct _GstDVDemuxClass GstDVDemuxClass;
+
+typedef gboolean (*GstDVDemuxSeekHandler) (GstDVDemux *demux, GstPad * pad, GstEvent * event);
+
+
+struct _GstDVDemux {
+  GstElement     element;
+
+  GstPad        *sinkpad;
+  GstPad        *videosrcpad;
+  GstPad        *audiosrcpad;
+
+  gboolean       have_group_id;
+  guint          group_id;
+
+  dv_decoder_t  *decoder;
+
+  GstAdapter    *adapter;
+  gint           frame_len;
+
+  /* video params */
+  gint           framerate_numerator;
+  gint           framerate_denominator;
+  gint           height;
+  gboolean       wide;
+  /* audio params */
+  gint           frequency;
+  gint           channels;
+
+  gboolean       discont;
+  gint64         frame_offset;
+  gint64         audio_offset;
+  gint64         video_offset;
+
+  GstDVDemuxSeekHandler seek_handler;
+  GstSegment     byte_segment;
+  gboolean       upstream_time_segment;
+  GstSegment     time_segment;
+  gboolean       need_segment;
+  guint32        segment_seqnum;
+  gboolean       new_media;
+  int            frames_since_new_media;
+  
+  gint           found_header; /* ATOMIC */
+  GstEvent      *seek_event;
+  GstEvent	*pending_segment;
+  GstEvent      *tag_event;
+
+  gint16        *audio_buffers[4];
+};
+
+struct _GstDVDemuxClass {
+  GstElementClass parent_class;
+};
+
+GType gst_dvdemux_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_DVDEMUX_H__ */
diff --git a/ext/dv/gstsmptetimecode.c b/ext/dv/gstsmptetimecode.c
new file mode 100644
index 0000000..b2204ea
--- /dev/null
+++ b/ext/dv/gstsmptetimecode.c
@@ -0,0 +1,240 @@
+/* GStreamer
+ * Copyright (C) 2009 David A. Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Utility functions for handing SMPTE Time Codes, as described in
+ * SMPTE Standard 12M-1999.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstsmptetimecode.h"
+
+#define NTSC_FRAMES_PER_10_MINS (10*60*30 - 10*2 + 2)
+#define NTSC_FRAMES_PER_HOUR (6*NTSC_FRAMES_PER_10_MINS)
+
+/**
+ * gst_smpte_time_code_from_frame_number:
+ * @system: SMPTE Time Code system
+ * @time_code: pointer to time code structure
+ * @frame_number: integer frame number
+ *
+ * Converts a frame number to a time code.
+ *
+ * Returns: TRUE if the conversion was successful
+ */
+gboolean
+gst_smpte_time_code_from_frame_number (GstSMPTETimeCodeSystem system,
+    GstSMPTETimeCode * time_code, int frame_number)
+{
+  int ten_mins;
+  int n;
+
+  g_return_val_if_fail (time_code != NULL, FALSE);
+  g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system), FALSE);
+
+  time_code->hours = 99;
+  time_code->minutes = 99;
+  time_code->seconds = 99;
+  time_code->frames = 99;
+
+  if (frame_number < 0)
+    return FALSE;
+
+  switch (system) {
+    case GST_SMPTE_TIME_CODE_SYSTEM_30:
+      if (frame_number >= 24 * NTSC_FRAMES_PER_HOUR)
+        return FALSE;
+
+      ten_mins = frame_number / NTSC_FRAMES_PER_10_MINS;
+      frame_number -= ten_mins * NTSC_FRAMES_PER_10_MINS;
+
+      time_code->hours = ten_mins / 6;
+      time_code->minutes = 10 * (ten_mins % 6);
+
+      if (frame_number < 2) {
+        /* treat the first two frames of each ten minutes specially */
+        time_code->seconds = 0;
+        time_code->frames = frame_number;
+      } else {
+        n = (frame_number - 2) / (60 * 30 - 2);
+        time_code->minutes += n;
+        frame_number -= n * (60 * 30 - 2);
+
+        time_code->seconds = frame_number / 30;
+        time_code->frames = frame_number % 30;
+      }
+      break;
+    case GST_SMPTE_TIME_CODE_SYSTEM_25:
+      if (frame_number >= 24 * 60 * 60 * 25)
+        return FALSE;
+
+      time_code->frames = frame_number % 25;
+      frame_number /= 25;
+      time_code->seconds = frame_number % 60;
+      frame_number /= 60;
+      time_code->minutes = frame_number % 60;
+      frame_number /= 60;
+      time_code->hours = frame_number;
+      break;
+    case GST_SMPTE_TIME_CODE_SYSTEM_24:
+      if (frame_number >= 24 * 60 * 60 * 24)
+        return FALSE;
+
+      time_code->frames = frame_number % 24;
+      frame_number /= 24;
+      time_code->seconds = frame_number % 60;
+      frame_number /= 60;
+      time_code->minutes = frame_number % 60;
+      frame_number /= 60;
+      time_code->hours = frame_number;
+      break;
+  }
+
+  return TRUE;
+}
+
+/**
+ * gst_smpte_time_code_is_valid:
+ * @system: SMPTE Time Code system
+ * @time_code: pointer to time code structure
+ *
+ * Checks that the time code represents a valid time code.
+ *
+ * Returns: TRUE if the time code is valid
+ */
+gboolean
+gst_smpte_time_code_is_valid (GstSMPTETimeCodeSystem system,
+    GstSMPTETimeCode * time_code)
+{
+  g_return_val_if_fail (time_code != NULL, FALSE);
+  g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system), FALSE);
+
+  if (time_code->hours < 0 || time_code->hours >= 24)
+    return FALSE;
+  if (time_code->minutes < 0 || time_code->minutes >= 60)
+    return FALSE;
+  if (time_code->seconds < 0 || time_code->seconds >= 60)
+    return FALSE;
+  if (time_code->frames < 0)
+    return FALSE;
+
+  switch (system) {
+    case GST_SMPTE_TIME_CODE_SYSTEM_30:
+      if (time_code->frames >= 30)
+        return FALSE;
+      if (time_code->frames >= 2 || time_code->seconds > 0)
+        return TRUE;
+      if (time_code->minutes % 10 != 0)
+        return FALSE;
+      break;
+    case GST_SMPTE_TIME_CODE_SYSTEM_25:
+      if (time_code->frames >= 25)
+        return FALSE;
+      break;
+    case GST_SMPTE_TIME_CODE_SYSTEM_24:
+      if (time_code->frames >= 24)
+        return FALSE;
+      break;
+  }
+  return TRUE;
+}
+
+/**
+ * gst_smpte_time_get_frame_number:
+ * @system: SMPTE Time Code system
+ * @frame_number: pointer to frame number
+ * @time_code: pointer to time code structure
+ *
+ * Converts the time code structure to a linear frame number.
+ *
+ * Returns: TRUE if the time code could be converted
+ */
+gboolean
+gst_smpte_time_code_get_frame_number (GstSMPTETimeCodeSystem system,
+    int *frame_number, GstSMPTETimeCode * time_code)
+{
+  int frame = 0;
+
+  g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system), FALSE);
+  g_return_val_if_fail (time_code != NULL, FALSE);
+
+  if (!gst_smpte_time_code_is_valid (system, time_code)) {
+    return FALSE;
+  }
+
+  switch (system) {
+    case GST_SMPTE_TIME_CODE_SYSTEM_30:
+      frame = time_code->hours * NTSC_FRAMES_PER_HOUR;
+      frame += (time_code->minutes / 10) * NTSC_FRAMES_PER_10_MINS;
+      frame += (time_code->minutes % 10) * (30 * 60 - 2);
+      frame += time_code->seconds * 30;
+      break;
+    case GST_SMPTE_TIME_CODE_SYSTEM_25:
+      time_code->frames =
+          25 * ((time_code->hours * 60 + time_code->minutes) * 60 +
+          time_code->seconds);
+      break;
+    case GST_SMPTE_TIME_CODE_SYSTEM_24:
+      time_code->frames =
+          24 * ((time_code->hours * 60 + time_code->minutes) * 60 +
+          time_code->seconds);
+      break;
+  }
+  frame += time_code->frames;
+
+  if (frame_number) {
+    *frame_number = frame;
+  }
+
+  return TRUE;
+}
+
+/**
+ * gst_smpte_time_get_timestamp:
+ * @system: SMPTE Time Code system
+ * @time_code: pointer to time code structure
+ *
+ * Converts the time code structure to a timestamp.
+ *
+ * Returns: Time stamp for time code, or GST_CLOCK_TIME_NONE if time
+ *   code is invalid.
+ */
+GstClockTime
+gst_smpte_time_code_get_timestamp (GstSMPTETimeCodeSystem system,
+    GstSMPTETimeCode * time_code)
+{
+  int frame_number;
+
+  g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system),
+      GST_CLOCK_TIME_NONE);
+  g_return_val_if_fail (time_code != NULL, GST_CLOCK_TIME_NONE);
+
+  if (gst_smpte_time_code_get_frame_number (system, &frame_number, time_code)) {
+    static const int framerate_n[3] = { 3000, 25, 24 };
+    static const int framerate_d[3] = { 1001, 1, 1 };
+
+    return gst_util_uint64_scale (frame_number,
+        GST_SECOND * framerate_d[system], framerate_n[system]);
+  }
+
+  return GST_CLOCK_TIME_NONE;
+}
diff --git a/ext/dv/gstsmptetimecode.h b/ext/dv/gstsmptetimecode.h
new file mode 100644
index 0000000..2042046
--- /dev/null
+++ b/ext/dv/gstsmptetimecode.h
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) 2009 David A. Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GST_SMPTE_TIME_CODE_H_
+#define _GST_SMPTE_TIME_CODE_H_
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstSMPTETimeCode GstSMPTETimeCode;
+
+/**
+ * GstSMPTETimeCode:
+ * @GST_SMPTE_TIME_CODE_SYSTEM_30: 29.97 frame per second system (NTSC)
+ * @GST_SMPTE_TIME_CODE_SYSTEM_25: 25 frame per second system (PAL)
+ * @GST_SMPTE_TIME_CODE_SYSTEM_24: 24 frame per second system
+ *
+ * Enum value representing SMPTE Time Code system.
+ */
+typedef enum {
+  GST_SMPTE_TIME_CODE_SYSTEM_30 = 0,
+  GST_SMPTE_TIME_CODE_SYSTEM_25,
+  GST_SMPTE_TIME_CODE_SYSTEM_24
+} GstSMPTETimeCodeSystem;
+
+struct _GstSMPTETimeCode {
+  int hours;
+  int minutes;
+  int seconds;
+  int frames;
+};
+
+#define GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID(x) \
+  ((x) >= GST_SMPTE_TIME_CODE_SYSTEM_30 && (x) <= GST_SMPTE_TIME_CODE_SYSTEM_24)
+
+#define GST_SMPTE_TIME_CODE_FORMAT "02d:%02d:%02d:%02d"
+#define GST_SMPTE_TIME_CODE_ARGS(timecode) \
+  (timecode)->hours, (timecode)->minutes, \
+  (timecode)->seconds, (timecode)->frames
+
+gboolean gst_smpte_time_code_is_valid (GstSMPTETimeCodeSystem system,
+    GstSMPTETimeCode *time_code);
+gboolean gst_smpte_time_code_from_frame_number (GstSMPTETimeCodeSystem system,
+    GstSMPTETimeCode *time_code, int frame_number);
+gboolean gst_smpte_time_code_get_frame_number (GstSMPTETimeCodeSystem system,
+    int *frame_number, GstSMPTETimeCode *time_code);
+GstClockTime gst_smpte_time_code_get_timestamp (GstSMPTETimeCodeSystem system,
+    GstSMPTETimeCode *time_code);
+
+G_END_DECLS
+
+#endif
+
diff --git a/ext/dv/meson.build b/ext/dv/meson.build
new file mode 100644
index 0000000..dd0aa08
--- /dev/null
+++ b/ext/dv/meson.build
@@ -0,0 +1,25 @@
+dv_sources = [
+  'gstdv.c',
+  'gstdvdec.c',
+  'gstdvdemux.c',
+  'gstsmptetimecode.c',
+  'smpte_test.c',
+]
+
+dv_dep = dependency('libdv', version : '>= 0.100', required : false)
+
+if dv_dep.found()
+  gstdv = library('gstdv',
+    dv_sources,
+    c_args : gst_plugins_good_args,
+    include_directories : [configinc, libsinc],
+    dependencies : [gstbase_dep, gsttag_dep, gstaudio_dep, gstvideo_dep, dv_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+
+  #executable('smpte_test',
+  #  'smpte_test.c', 'gstsmptetimecode.c',
+  #  dependencies : [gstbase_dep, gsttag_dep, gstaudio_dep, gstvideo_dep, dv_dep],
+  #  install : false)
+endif
diff --git a/ext/dv/smpte_test.c b/ext/dv/smpte_test.c
new file mode 100644
index 0000000..f18113c
--- /dev/null
+++ b/ext/dv/smpte_test.c
@@ -0,0 +1,81 @@
+
+#include "config.h"
+
+#include "gstsmptetimecode.h"
+
+#include <glib.h>
+
+#define NTSC_FRAMES_PER_10_MINS (10*60*30 - 10*2 + 2)
+#define NTSC_FRAMES_PER_HOUR (6*NTSC_FRAMES_PER_10_MINS)
+
+
+int
+main (int argc, char *argv[])
+{
+  GstSMPTETimeCode tc;
+  int i;
+  int min;
+
+  for (min = 0; min < 3; min++) {
+    g_print ("--- minute %d ---\n", min);
+    for (i = min * 60 * 30 - 5; i <= min * 60 * 30 + 5; i++) {
+      gst_smpte_time_code_from_frame_number (GST_SMPTE_TIME_CODE_SYSTEM_30, &tc,
+          i);
+      g_print ("%d %02d:%02d:%02d:%02d\n", i, tc.hours, tc.minutes, tc.seconds,
+          tc.frames);
+    }
+  }
+
+  for (min = 9; min < 12; min++) {
+    g_print ("--- minute %d ---\n", min);
+    for (i = min * 60 * 30 - 5 - 18; i <= min * 60 * 30 + 5 - 18; i++) {
+      gst_smpte_time_code_from_frame_number (GST_SMPTE_TIME_CODE_SYSTEM_30, &tc,
+          i);
+      g_print ("%d %02d:%02d:%02d:%02d\n", i, tc.hours, tc.minutes, tc.seconds,
+          tc.frames);
+    }
+  }
+
+  for (min = -1; min < 2; min++) {
+    int offset = NTSC_FRAMES_PER_HOUR;
+
+    g_print ("--- minute %d ---\n", min);
+    for (i = offset + min * 60 * 30 - 5; i <= offset + min * 60 * 30 + 5; i++) {
+      gst_smpte_time_code_from_frame_number (GST_SMPTE_TIME_CODE_SYSTEM_30, &tc,
+          i);
+      g_print ("%d %02d:%02d:%02d:%02d\n", i, tc.hours, tc.minutes, tc.seconds,
+          tc.frames);
+    }
+  }
+
+  for (min = 0; min < 1; min++) {
+    int offset = NTSC_FRAMES_PER_HOUR;
+
+    g_print ("--- minute %d ---\n", min);
+    for (i = 24 * offset - 5; i <= 24 * offset + 5; i++) {
+      gst_smpte_time_code_from_frame_number (GST_SMPTE_TIME_CODE_SYSTEM_30, &tc,
+          i);
+      g_print ("%d %02d:%02d:%02d:%02d\n", i, tc.hours, tc.minutes, tc.seconds,
+          tc.frames);
+    }
+  }
+
+  for (i = 0; i < 24 * NTSC_FRAMES_PER_HOUR; i++) {
+    int fn;
+    int ret;
+
+    gst_smpte_time_code_from_frame_number (GST_SMPTE_TIME_CODE_SYSTEM_30, &tc,
+        i);
+
+    ret = gst_smpte_time_code_get_frame_number (GST_SMPTE_TIME_CODE_SYSTEM_30,
+        &fn, &tc);
+    if (!ret) {
+      g_print ("bad valid at %d\n", i);
+    }
+    if (fn != i) {
+      g_print ("index mismatch %d != %d\n", fn, i);
+    }
+  }
+
+  return 0;
+}
diff --git a/ext/flac/Makefile.am b/ext/flac/Makefile.am
new file mode 100644
index 0000000..994955c
--- /dev/null
+++ b/ext/flac/Makefile.am
@@ -0,0 +1,12 @@
+plugin_LTLIBRARIES = libgstflac.la
+
+libgstflac_la_SOURCES = gstflac.c gstflacdec.c gstflacenc.c gstflactag.c
+libgstflac_la_CFLAGS = -DGST_USE_UNSTABLE_API \
+	$(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(FLAC_CFLAGS)
+libgstflac_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_API_VERSION) \
+	-lgstaudio-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) $(GST_LIBS) $(FLAC_LIBS)
+libgstflac_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstflacenc.h gstflacdec.h gstflactag.h
diff --git a/ext/flac/gstflac.c b/ext/flac/gstflac.c
new file mode 100644
index 0000000..2b88b2a
--- /dev/null
+++ b/ext/flac/gstflac.c
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstflacenc.h"
+#include "gstflacdec.h"
+#include "gstflactag.h"
+
+#include <gst/tag/tag.h>
+#include <gst/gst-i18n-plugin.h>
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+#ifdef ENABLE_NLS
+  GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
+      LOCALEDIR);
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+
+  if (!gst_element_register (plugin, "flacenc", GST_RANK_PRIMARY,
+          GST_TYPE_FLAC_ENC))
+    return FALSE;
+  if (!gst_element_register (plugin, "flacdec", GST_RANK_PRIMARY,
+          GST_TYPE_FLAC_DEC))
+    return FALSE;
+  if (!gst_element_register (plugin, "flactag", GST_RANK_PRIMARY,
+          gst_flac_tag_get_type ()))
+    return FALSE;
+
+  gst_tag_register_musicbrainz_tags ();
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    flac,
+    "The FLAC Lossless compressor Codec",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/flac/gstflacdec.c b/ext/flac/gstflacdec.c
new file mode 100644
index 0000000..15f19e6
--- /dev/null
+++ b/ext/flac/gstflacdec.c
@@ -0,0 +1,816 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2006,2011> Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) <2006> Jan Schmidt <thaytan at mad scientist com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-flacdec
+ * @see_also: #GstFlacEnc
+ *
+ * flacdec decodes FLAC streams.
+ * <ulink url="http://flac.sourceforge.net/">FLAC</ulink>
+ * is a Free Lossless Audio Codec.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=media/small/dark.441-16-s.flac ! flacparse ! flacdec ! audioconvert ! audioresample ! autoaudiosink
+ * ]|
+ * |[
+ * gst-launch-1.0 souphttpsrc location=http://gstreamer.freedesktop.org/media/small/dark.441-16-s.flac ! flacparse ! flacdec ! audioconvert ! audioresample ! queue min-threshold-buffers=10 ! autoaudiosink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstflacdec.h"
+#include <gst/gst-i18n-plugin.h>
+#include <gst/tag/tag.h>
+
+/* Taken from http://flac.sourceforge.net/format.html#frame_header */
+static const GstAudioChannelPosition channel_positions[8][8] = {
+  {GST_AUDIO_CHANNEL_POSITION_MONO},
+  {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+      GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+      GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+      GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+      GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+        GST_AUDIO_CHANNEL_POSITION_LFE1,
+        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+      GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
+  /* FIXME: 7/8 channel layouts are not defined in the FLAC specs */
+  {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+        GST_AUDIO_CHANNEL_POSITION_LFE1,
+      GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+        GST_AUDIO_CHANNEL_POSITION_LFE1,
+        GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+      GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}
+};
+
+GST_DEBUG_CATEGORY_STATIC (flacdec_debug);
+#define GST_CAT_DEFAULT flacdec_debug
+
+static FLAC__StreamDecoderReadStatus
+gst_flac_dec_read_stream (const FLAC__StreamDecoder * decoder,
+    FLAC__byte buffer[], size_t * bytes, void *client_data);
+static FLAC__StreamDecoderWriteStatus
+gst_flac_dec_write_stream (const FLAC__StreamDecoder * decoder,
+    const FLAC__Frame * frame,
+    const FLAC__int32 * const buffer[], void *client_data);
+static gboolean
+gst_flac_dec_handle_decoder_error (GstFlacDec * dec, gboolean msg);
+static void gst_flac_dec_metadata_cb (const FLAC__StreamDecoder *
+    decoder, const FLAC__StreamMetadata * metadata, void *client_data);
+static void gst_flac_dec_error_cb (const FLAC__StreamDecoder *
+    decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+static void gst_flac_dec_flush (GstAudioDecoder * audio_dec, gboolean hard);
+static gboolean gst_flac_dec_set_format (GstAudioDecoder * dec, GstCaps * caps);
+static gboolean gst_flac_dec_start (GstAudioDecoder * dec);
+static gboolean gst_flac_dec_stop (GstAudioDecoder * dec);
+static GstFlowReturn gst_flac_dec_handle_frame (GstAudioDecoder * audio_dec,
+    GstBuffer * buf);
+
+G_DEFINE_TYPE (GstFlacDec, gst_flac_dec, GST_TYPE_AUDIO_DECODER);
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define FORMATS "{ S8, S16LE, S24_32LE, S32LE } "
+#else
+#define FORMATS "{ S8, S16BE, S24_32BE, S32BE } "
+#endif
+
+#define GST_FLAC_DEC_SRC_CAPS                             \
+    "audio/x-raw, "                                       \
+    "format = (string) " FORMATS ", "                     \
+    "layout = (string) interleaved, "                     \
+    "rate = (int) [ 1, 655350 ], "                        \
+    "channels = (int) [ 1, 8 ]"
+
+#define GST_FLAC_DEC_SINK_CAPS                            \
+    "audio/x-flac, "                                      \
+    "framed = (boolean) true, "                           \
+    "rate = (int) [ 1, 655350 ], "                        \
+    "channels = (int) [ 1, 8 ]"
+
+static GstStaticPadTemplate flac_dec_src_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_FLAC_DEC_SRC_CAPS));
+static GstStaticPadTemplate flac_dec_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_FLAC_DEC_SINK_CAPS));
+
+static void
+gst_flac_dec_class_init (GstFlacDecClass * klass)
+{
+  GstAudioDecoderClass *audiodecoder_class;
+  GstElementClass *gstelement_class;
+
+  audiodecoder_class = (GstAudioDecoderClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (flacdec_debug, "flacdec", 0, "flac decoder");
+
+  audiodecoder_class->stop = GST_DEBUG_FUNCPTR (gst_flac_dec_stop);
+  audiodecoder_class->start = GST_DEBUG_FUNCPTR (gst_flac_dec_start);
+  audiodecoder_class->flush = GST_DEBUG_FUNCPTR (gst_flac_dec_flush);
+  audiodecoder_class->set_format = GST_DEBUG_FUNCPTR (gst_flac_dec_set_format);
+  audiodecoder_class->handle_frame =
+      GST_DEBUG_FUNCPTR (gst_flac_dec_handle_frame);
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &flac_dec_src_factory);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &flac_dec_sink_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class, "FLAC audio decoder",
+      "Codec/Decoder/Audio", "Decodes FLAC lossless audio streams",
+      "Tim-Philipp Müller <tim@centricular.net>, "
+      "Wim Taymans <wim.taymans@gmail.com>");
+}
+
+static void
+gst_flac_dec_init (GstFlacDec * flacdec)
+{
+  flacdec->do_resync = FALSE;
+  gst_audio_decoder_set_needs_format (GST_AUDIO_DECODER (flacdec), TRUE);
+  gst_audio_decoder_set_use_default_pad_acceptcaps (GST_AUDIO_DECODER_CAST
+      (flacdec), TRUE);
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_DECODER_SINK_PAD (flacdec));
+}
+
+static gboolean
+gst_flac_dec_start (GstAudioDecoder * audio_dec)
+{
+  FLAC__StreamDecoderInitStatus s;
+  GstFlacDec *dec;
+
+  dec = GST_FLAC_DEC (audio_dec);
+
+  dec->adapter = gst_adapter_new ();
+
+  dec->decoder = FLAC__stream_decoder_new ();
+
+  gst_audio_info_init (&dec->info);
+  dec->depth = 0;
+
+  /* no point calculating MD5 since it's never checked here */
+  FLAC__stream_decoder_set_md5_checking (dec->decoder, false);
+
+  GST_DEBUG_OBJECT (dec, "initializing decoder");
+  s = FLAC__stream_decoder_init_stream (dec->decoder,
+      gst_flac_dec_read_stream, NULL, NULL, NULL, NULL,
+      gst_flac_dec_write_stream, gst_flac_dec_metadata_cb,
+      gst_flac_dec_error_cb, dec);
+
+  if (s != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+    GST_ELEMENT_ERROR (GST_ELEMENT (dec), LIBRARY, INIT, (NULL), (NULL));
+    return FALSE;
+  }
+
+  dec->got_headers = FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+gst_flac_dec_stop (GstAudioDecoder * dec)
+{
+  GstFlacDec *flacdec = GST_FLAC_DEC (dec);
+
+  if (flacdec->decoder) {
+    FLAC__stream_decoder_delete (flacdec->decoder);
+    flacdec->decoder = NULL;
+  }
+
+  if (flacdec->adapter) {
+    gst_adapter_clear (flacdec->adapter);
+    g_object_unref (flacdec->adapter);
+    flacdec->adapter = NULL;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_flac_dec_set_format (GstAudioDecoder * dec, GstCaps * caps)
+{
+  const GValue *headers;
+  GstFlacDec *flacdec;
+  GstStructure *s;
+  guint i, num;
+
+  flacdec = GST_FLAC_DEC (dec);
+
+  GST_LOG_OBJECT (dec, "sink caps: %" GST_PTR_FORMAT, caps);
+
+  s = gst_caps_get_structure (caps, 0);
+  headers = gst_structure_get_value (s, "streamheader");
+  if (headers == NULL || !GST_VALUE_HOLDS_ARRAY (headers)) {
+    GST_WARNING_OBJECT (dec, "no 'streamheader' field in input caps, try "
+        "adding a flacparse element upstream");
+    return FALSE;
+  }
+
+  if (gst_adapter_available (flacdec->adapter) > 0) {
+    GST_WARNING_OBJECT (dec, "unexpected data left in adapter");
+    gst_adapter_clear (flacdec->adapter);
+  }
+
+  num = gst_value_array_get_size (headers);
+  for (i = 0; i < num; ++i) {
+    const GValue *header_val;
+    GstBuffer *header_buf;
+
+    header_val = gst_value_array_get_value (headers, i);
+    if (header_val == NULL || !GST_VALUE_HOLDS_BUFFER (header_val))
+      return FALSE;
+
+    header_buf = g_value_dup_boxed (header_val);
+    GST_INFO_OBJECT (dec, "pushing header buffer of %" G_GSIZE_FORMAT " bytes "
+        "into adapter", gst_buffer_get_size (header_buf));
+    gst_adapter_push (flacdec->adapter, header_buf);
+  }
+
+  GST_DEBUG_OBJECT (dec, "Processing headers and metadata");
+  if (!FLAC__stream_decoder_process_until_end_of_metadata (flacdec->decoder)) {
+    GST_WARNING_OBJECT (dec, "process_until_end_of_metadata failed");
+    if (FLAC__stream_decoder_get_state (flacdec->decoder) ==
+        FLAC__STREAM_DECODER_ABORTED) {
+      GST_WARNING_OBJECT (flacdec, "Read callback caused internal abort");
+      /* allow recovery */
+      gst_adapter_clear (flacdec->adapter);
+      FLAC__stream_decoder_flush (flacdec->decoder);
+      gst_flac_dec_handle_decoder_error (flacdec, TRUE);
+    }
+  }
+  GST_INFO_OBJECT (dec, "headers and metadata are now processed");
+  return TRUE;
+}
+
+/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */
+static const guint8 crc8_table[256] = {
+  0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
+  0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
+  0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
+  0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
+  0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
+  0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
+  0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
+  0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
+  0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
+  0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
+  0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
+  0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
+  0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
+  0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
+  0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
+  0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
+  0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
+  0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
+  0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
+  0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
+  0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
+  0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
+  0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
+  0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
+  0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
+  0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
+  0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
+  0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
+  0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
+  0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
+  0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
+  0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
+};
+
+static guint8
+gst_flac_calculate_crc8 (const guint8 * data, guint length)
+{
+  guint8 crc = 0;
+
+  while (length--) {
+    crc = crc8_table[crc ^ *data];
+    ++data;
+  }
+
+  return crc;
+}
+
+/* FIXME: for our purposes it's probably enough to just check for the sync
+ * marker - we just want to know if it's a header frame or not */
+static gboolean
+gst_flac_dec_scan_got_frame (GstFlacDec * flacdec, const guint8 * data,
+    guint size)
+{
+  guint headerlen;
+  guint sr_from_end = 0;        /* can be 0, 8 or 16 */
+  guint bs_from_end = 0;        /* can be 0, 8 or 16 */
+  guint32 val = 0;
+  guint8 bs, sr, ca, ss, pb;
+  gboolean vbs;
+
+  if (size < 10)
+    return FALSE;
+
+  /* sync */
+  if (data[0] != 0xFF || (data[1] & 0xFC) != 0xF8)
+    return FALSE;
+
+  vbs = ! !(data[1] & 1);       /* variable blocksize */
+  bs = (data[2] & 0xF0) >> 4;   /* blocksize marker   */
+  sr = (data[2] & 0x0F);        /* samplerate marker  */
+  ca = (data[3] & 0xF0) >> 4;   /* channel assignment */
+  ss = (data[3] & 0x0F) >> 1;   /* sample size marker */
+  pb = (data[3] & 0x01);        /* padding bit        */
+
+  GST_LOG_OBJECT (flacdec,
+      "got sync, vbs=%d,bs=%x,sr=%x,ca=%x,ss=%x,pb=%x", vbs, bs, sr, ca, ss,
+      pb);
+
+  if (bs == 0 || sr == 0x0F || ca >= 0x0B || ss == 0x03 || ss == 0x07) {
+    return FALSE;
+  }
+
+  /* read block size from end of header? */
+  if (bs == 6)
+    bs_from_end = 8;
+  else if (bs == 7)
+    bs_from_end = 16;
+
+  /* read sample rate from end of header? */
+  if (sr == 0x0C)
+    sr_from_end = 8;
+  else if (sr == 0x0D || sr == 0x0E)
+    sr_from_end = 16;
+
+  val = data[4];
+  /* This is slightly faster than a loop */
+  if (!(val & 0x80)) {
+    val = 0;
+  } else if ((val & 0xc0) && !(val & 0x20)) {
+    val = 1;
+  } else if ((val & 0xe0) && !(val & 0x10)) {
+    val = 2;
+  } else if ((val & 0xf0) && !(val & 0x08)) {
+    val = 3;
+  } else if ((val & 0xf8) && !(val & 0x04)) {
+    val = 4;
+  } else if ((val & 0xfc) && !(val & 0x02)) {
+    val = 5;
+  } else if ((val & 0xfe) && !(val & 0x01)) {
+    val = 6;
+  } else {
+    GST_LOG_OBJECT (flacdec, "failed to read sample/frame");
+    return FALSE;
+  }
+
+  val++;
+  headerlen = 4 + val + (bs_from_end / 8) + (sr_from_end / 8);
+
+  if (gst_flac_calculate_crc8 (data, headerlen) != data[headerlen]) {
+    GST_LOG_OBJECT (flacdec, "invalid checksum");
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_flac_dec_handle_decoder_error (GstFlacDec * dec, gboolean msg)
+{
+  gboolean ret;
+
+  dec->error_count++;
+  if (dec->error_count > 10) {
+    if (msg)
+      GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), (NULL));
+    dec->last_flow = GST_FLOW_ERROR;
+    ret = TRUE;
+  } else {
+    GST_DEBUG_OBJECT (dec, "ignoring error for now at count %d",
+        dec->error_count);
+    ret = FALSE;
+  }
+
+  return ret;
+}
+
+static void
+gst_flac_dec_metadata_cb (const FLAC__StreamDecoder * decoder,
+    const FLAC__StreamMetadata * metadata, void *client_data)
+{
+  GstFlacDec *flacdec = GST_FLAC_DEC (client_data);
+  GstAudioChannelPosition position[8];
+
+  GST_LOG_OBJECT (flacdec, "metadata type: %d", metadata->type);
+
+  switch (metadata->type) {
+    case FLAC__METADATA_TYPE_STREAMINFO:{
+      gint64 samples;
+      guint depth, width, gdepth, channels;
+
+      samples = metadata->data.stream_info.total_samples;
+
+      flacdec->min_blocksize = metadata->data.stream_info.min_blocksize;
+      flacdec->max_blocksize = metadata->data.stream_info.max_blocksize;
+      flacdec->depth = depth = metadata->data.stream_info.bits_per_sample;
+
+      if (depth < 9) {
+        gdepth = width = 8;
+      } else if (depth < 17) {
+        gdepth = width = 16;
+      } else if (depth < 25) {
+        gdepth = 24;
+        width = 32;
+      } else {
+        gdepth = width = 32;
+      }
+
+      channels = metadata->data.stream_info.channels;
+      memcpy (position, channel_positions[channels - 1], sizeof (position));
+      gst_audio_channel_positions_to_valid_order (position, channels);
+      /* Note: we create the inverse reordering map here */
+      gst_audio_get_channel_reorder_map (channels,
+          position, channel_positions[channels - 1],
+          flacdec->channel_reorder_map);
+
+      gst_audio_info_set_format (&flacdec->info,
+          gst_audio_format_build_integer (TRUE, G_BYTE_ORDER, width, gdepth),
+          metadata->data.stream_info.sample_rate,
+          metadata->data.stream_info.channels, position);
+
+      GST_DEBUG_OBJECT (flacdec, "blocksize: min=%u, max=%u",
+          flacdec->min_blocksize, flacdec->max_blocksize);
+      GST_DEBUG_OBJECT (flacdec, "sample rate: %u, channels: %u",
+          flacdec->info.rate, flacdec->info.channels);
+      GST_DEBUG_OBJECT (flacdec, "depth: %u, width: %u", flacdec->depth,
+          flacdec->info.finfo->width);
+
+      GST_DEBUG_OBJECT (flacdec, "total samples = %" G_GINT64_FORMAT, samples);
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+static void
+gst_flac_dec_error_cb (const FLAC__StreamDecoder * d,
+    FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+  const gchar *error;
+  GstFlacDec *dec;
+
+  dec = GST_FLAC_DEC (client_data);
+
+  switch (status) {
+    case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
+      dec->do_resync = TRUE;
+      return;
+    case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
+      error = "bad header";
+      break;
+    case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
+      error = "CRC mismatch";
+      break;
+    default:
+      error = "unknown error";
+      break;
+  }
+
+  if (gst_flac_dec_handle_decoder_error (dec, FALSE))
+    GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("%s (%d)", error, status));
+}
+
+static FLAC__StreamDecoderReadStatus
+gst_flac_dec_read_stream (const FLAC__StreamDecoder * decoder,
+    FLAC__byte buffer[], size_t * bytes, void *client_data)
+{
+  GstFlacDec *dec = GST_FLAC_DEC (client_data);
+  guint len;
+
+  len = MIN (gst_adapter_available (dec->adapter), *bytes);
+
+  if (len == 0) {
+    GST_LOG_OBJECT (dec, "0 bytes available at the moment");
+    return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+  }
+
+  GST_LOG_OBJECT (dec, "feeding %u bytes to decoder "
+      "(available=%" G_GSIZE_FORMAT ", bytes=%u)",
+      len, gst_adapter_available (dec->adapter), (guint) * bytes);
+  gst_adapter_copy (dec->adapter, buffer, 0, len);
+  *bytes = len;
+
+  gst_adapter_flush (dec->adapter, len);
+
+  return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+}
+
+static FLAC__StreamDecoderWriteStatus
+gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
+    const FLAC__int32 * const buffer[])
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBuffer *outbuf;
+  guint depth = frame->header.bits_per_sample;
+  guint width, gdepth;
+  guint sample_rate = frame->header.sample_rate;
+  guint channels = frame->header.channels;
+  guint samples = frame->header.blocksize;
+  guint j, i;
+  GstMapInfo map;
+  gboolean caps_changed;
+  GstAudioChannelPosition chanpos[8];
+
+  GST_LOG_OBJECT (flacdec, "samples in frame header: %d", samples);
+
+  if (depth == 0) {
+    if (flacdec->depth < 4 || flacdec->depth > 32) {
+      GST_ERROR_OBJECT (flacdec, "unsupported depth %d from STREAMINFO",
+          flacdec->depth);
+      ret = GST_FLOW_ERROR;
+      goto done;
+    }
+
+    depth = flacdec->depth;
+  }
+
+  switch (depth) {
+    case 8:
+      gdepth = width = 8;
+      break;
+    case 12:
+    case 16:
+      gdepth = width = 16;
+      break;
+    case 20:
+    case 24:
+      gdepth = 24;
+      width = 32;
+      break;
+    case 32:
+      gdepth = width = 32;
+      break;
+    default:
+      GST_ERROR_OBJECT (flacdec, "unsupported depth %d", depth);
+      ret = GST_FLOW_ERROR;
+      goto done;
+  }
+
+  if (sample_rate == 0) {
+    if (flacdec->info.rate != 0) {
+      sample_rate = flacdec->info.rate;
+    } else {
+      GST_ERROR_OBJECT (flacdec, "unknown sample rate");
+      ret = GST_FLOW_ERROR;
+      goto done;
+    }
+  }
+
+  caps_changed = (sample_rate != GST_AUDIO_INFO_RATE (&flacdec->info))
+      || (width != GST_AUDIO_INFO_WIDTH (&flacdec->info))
+      || (gdepth != GST_AUDIO_INFO_DEPTH (&flacdec->info))
+      || (channels != GST_AUDIO_INFO_CHANNELS (&flacdec->info));
+
+  if (caps_changed
+      || !gst_pad_has_current_caps (GST_AUDIO_DECODER_SRC_PAD (flacdec))) {
+    GST_DEBUG_OBJECT (flacdec, "Negotiating %d Hz @ %d channels", sample_rate,
+        channels);
+
+    memcpy (chanpos, channel_positions[flacdec->info.channels - 1],
+        sizeof (chanpos));
+    gst_audio_channel_positions_to_valid_order (chanpos,
+        flacdec->info.channels);
+    gst_audio_info_set_format (&flacdec->info,
+        gst_audio_format_build_integer (TRUE, G_BYTE_ORDER, width, gdepth),
+        sample_rate, channels, chanpos);
+
+    /* Note: we create the inverse reordering map here */
+    gst_audio_get_channel_reorder_map (flacdec->info.channels,
+        flacdec->info.position, channel_positions[flacdec->info.channels - 1],
+        flacdec->channel_reorder_map);
+
+    flacdec->depth = depth;
+
+    gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (flacdec),
+        &flacdec->info);
+  }
+
+  outbuf =
+      gst_buffer_new_allocate (NULL, samples * channels * (width / 8), NULL);
+
+  gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+  if (width == 8) {
+    gint8 *outbuffer = (gint8 *) map.data;
+    gint *reorder_map = flacdec->channel_reorder_map;
+
+    g_assert (gdepth == 8 && depth == 8);
+    for (i = 0; i < samples; i++) {
+      for (j = 0; j < channels; j++) {
+        *outbuffer++ = (gint8) buffer[reorder_map[j]][i];
+      }
+    }
+  } else if (width == 16) {
+    gint16 *outbuffer = (gint16 *) map.data;
+    gint *reorder_map = flacdec->channel_reorder_map;
+
+    if (gdepth != depth) {
+      for (i = 0; i < samples; i++) {
+        for (j = 0; j < channels; j++) {
+          *outbuffer++ =
+              (gint16) (buffer[reorder_map[j]][i] << (gdepth - depth));
+        }
+      }
+    } else {
+      for (i = 0; i < samples; i++) {
+        for (j = 0; j < channels; j++) {
+          *outbuffer++ = (gint16) buffer[reorder_map[j]][i];
+        }
+      }
+    }
+  } else if (width == 32) {
+    gint32 *outbuffer = (gint32 *) map.data;
+    gint *reorder_map = flacdec->channel_reorder_map;
+
+    if (gdepth != depth) {
+      for (i = 0; i < samples; i++) {
+        for (j = 0; j < channels; j++) {
+          *outbuffer++ =
+              (gint32) (buffer[reorder_map[j]][i] << (gdepth - depth));
+        }
+      }
+    } else {
+      for (i = 0; i < samples; i++) {
+        for (j = 0; j < channels; j++) {
+          *outbuffer++ = (gint32) buffer[reorder_map[j]][i];
+        }
+      }
+    }
+  } else {
+    g_assert_not_reached ();
+  }
+  gst_buffer_unmap (outbuf, &map);
+
+  GST_DEBUG_OBJECT (flacdec, "pushing %d samples", samples);
+  if (flacdec->error_count)
+    flacdec->error_count--;
+
+  ret = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (flacdec), outbuf, 1);
+
+  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+    GST_DEBUG_OBJECT (flacdec, "finish_frame flow %s", gst_flow_get_name (ret));
+  }
+
+done:
+
+  /* we act on the flow return value later in the handle_frame function, as we
+   * don't want to mess up the internal decoder state by returning ABORT when
+   * the error is in fact non-fatal (like a pad in flushing mode) and we want
+   * to continue later. So just pretend everything's dandy and act later. */
+  flacdec->last_flow = ret;
+
+  return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static FLAC__StreamDecoderWriteStatus
+gst_flac_dec_write_stream (const FLAC__StreamDecoder * decoder,
+    const FLAC__Frame * frame,
+    const FLAC__int32 * const buffer[], void *client_data)
+{
+  return gst_flac_dec_write (GST_FLAC_DEC (client_data), frame, buffer);
+}
+
+static void
+gst_flac_dec_flush (GstAudioDecoder * audio_dec, gboolean hard)
+{
+  GstFlacDec *dec = GST_FLAC_DEC (audio_dec);
+
+  if (!hard) {
+    guint available = gst_adapter_available (dec->adapter);
+
+    if (available > 0) {
+      GST_INFO_OBJECT (dec, "draining, %u bytes left in adapter", available);
+      FLAC__stream_decoder_process_until_end_of_stream (dec->decoder);
+    }
+  }
+
+  dec->do_resync = FALSE;
+  FLAC__stream_decoder_flush (dec->decoder);
+  gst_adapter_clear (dec->adapter);
+}
+
+static GstFlowReturn
+gst_flac_dec_handle_frame (GstAudioDecoder * audio_dec, GstBuffer * buf)
+{
+  GstFlacDec *dec;
+
+  dec = GST_FLAC_DEC (audio_dec);
+
+  /* drain remaining data? */
+  if (G_UNLIKELY (buf == NULL)) {
+    gst_flac_dec_flush (audio_dec, FALSE);
+    return GST_FLOW_OK;
+  }
+
+  if (dec->do_resync) {
+    GST_WARNING_OBJECT (dec, "Lost sync, flushing decoder");
+    FLAC__stream_decoder_flush (dec->decoder);
+    dec->do_resync = FALSE;
+  }
+
+  GST_LOG_OBJECT (dec, "frame: ts %" GST_TIME_FORMAT ", flags 0x%04x, "
+      "%" G_GSIZE_FORMAT " bytes", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
+      GST_BUFFER_FLAGS (buf), gst_buffer_get_size (buf));
+
+  /* drop any in-stream headers, we've processed those in set_format already */
+  if (G_UNLIKELY (!dec->got_headers)) {
+    gboolean got_audio_frame;
+    GstMapInfo map;
+
+    /* check if this is a flac audio frame (rather than a header or junk) */
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    got_audio_frame = gst_flac_dec_scan_got_frame (dec, map.data, map.size);
+    gst_buffer_unmap (buf, &map);
+
+    if (!got_audio_frame) {
+      GST_INFO_OBJECT (dec, "dropping in-stream header, %" G_GSIZE_FORMAT " "
+          "bytes", map.size);
+      gst_audio_decoder_finish_frame (audio_dec, NULL, 1);
+      return GST_FLOW_OK;
+    }
+
+    GST_INFO_OBJECT (dec, "first audio frame, got all in-stream headers now");
+    dec->got_headers = TRUE;
+  }
+
+  gst_adapter_push (dec->adapter, gst_buffer_ref (buf));
+  buf = NULL;
+
+  dec->last_flow = GST_FLOW_OK;
+
+  /* framed - there should always be enough data to decode something */
+  GST_LOG_OBJECT (dec, "%" G_GSIZE_FORMAT " bytes available",
+      gst_adapter_available (dec->adapter));
+
+  if (!FLAC__stream_decoder_process_single (dec->decoder)) {
+    GST_INFO_OBJECT (dec, "process_single failed");
+    if (FLAC__stream_decoder_get_state (dec->decoder) ==
+        FLAC__STREAM_DECODER_ABORTED) {
+      GST_WARNING_OBJECT (dec, "Read callback caused internal abort");
+      /* allow recovery */
+      gst_adapter_clear (dec->adapter);
+      FLAC__stream_decoder_flush (dec->decoder);
+      gst_flac_dec_handle_decoder_error (dec, TRUE);
+    }
+  }
+
+  return dec->last_flow;
+}
diff --git a/ext/flac/gstflacdec.h b/ext/flac/gstflacdec.h
new file mode 100644
index 0000000..c63b300
--- /dev/null
+++ b/ext/flac/gstflacdec.h
@@ -0,0 +1,74 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2011> Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_FLAC_DEC_H__
+#define __GST_FLAC_DEC_H__
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiodecoder.h>
+
+#include <FLAC/all.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_FLAC_DEC gst_flac_dec_get_type()
+#define GST_FLAC_DEC(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, GST_TYPE_FLAC_DEC, GstFlacDec)
+#define GST_FLAC_DEC_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, GST_TYPE_FLAC_DEC, GstFlacDecClass)
+#define GST_IS_FLAC_DEC(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, GST_TYPE_FLAC_DEC)
+#define GST_IS_FLAC_DEC_CLASS(klass) G_TYPE_CHECK_CLASS_TYPE(klass, GST_TYPE_FLAC_DEC)
+
+typedef struct _GstFlacDec GstFlacDec;
+typedef struct _GstFlacDecClass GstFlacDecClass;
+
+struct _GstFlacDec {
+  GstAudioDecoder  audiodecoder;
+
+  /*< private >*/
+  FLAC__StreamDecoder         *decoder;
+  GstAdapter                  *adapter;
+
+  gboolean       got_headers; /* have we received all the header buffers yet? */
+
+  GstFlowReturn  last_flow;   /* to marshal flow return from finis_frame to
+                               * handle_frame via flac callbacks */
+
+  GstAudioInfo   info;
+  gint           channel_reorder_map[8];
+  gint           depth;
+
+  /* from the stream info, needed for scanning */
+  guint16        min_blocksize;
+  guint16        max_blocksize;
+
+  gboolean       do_resync;
+  gint           error_count;
+};
+
+struct _GstFlacDecClass {
+  GstAudioDecoderClass  audiodecoder;
+};
+
+GType gst_flac_dec_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_FLAC_DEC_H__ */
diff --git a/ext/flac/gstflacenc.c b/ext/flac/gstflacenc.c
new file mode 100644
index 0000000..d31de07
--- /dev/null
+++ b/ext/flac/gstflacenc.c
@@ -0,0 +1,1586 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-flacenc
+ * @see_also: #GstFlacDec
+ *
+ * flacenc encodes FLAC streams.
+ * <ulink url="http://flac.sourceforge.net/">FLAC</ulink>
+ * is a Free Lossless Audio Codec. FLAC audio can directly be written into
+ * a file, or embedded into containers such as oggmux or matroskamux.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc num-buffers=100 ! flacenc ! filesink location=beep.flac
+ * ]| Encode a short sine wave into FLAC
+ * |[
+ * gst-launch-1.0 cdparanoiasrc mode=continuous ! queue ! audioconvert ! flacenc ! filesink location=cd.flac
+ * ]| Rip a whole audio CD into a single FLAC file, with the track table saved as a CUE sheet inside the FLAC file
+ * |[
+ * gst-launch-1.0 cdparanoiasrc track=5 ! queue ! audioconvert ! flacenc ! filesink location=track5.flac
+ * ]| Rip track 5 of an audio CD and encode it losslessly to a FLAC file
+ * </refsect2>
+ */
+
+/* TODO: - We currently don't handle discontinuities in the stream in a useful
+ *         way and instead rely on the developer plugging in audiorate if
+ *         the stream contains discontinuities.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include <gstflacenc.h>
+#include <gst/audio/audio.h>
+#include <gst/tag/tag.h>
+#include <gst/gsttagsetter.h>
+
+/* Taken from http://flac.sourceforge.net/format.html#frame_header */
+static const GstAudioChannelPosition channel_positions[8][8] = {
+  {GST_AUDIO_CHANNEL_POSITION_MONO},
+  {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+      GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+      GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+      GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+      GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+        GST_AUDIO_CHANNEL_POSITION_LFE1,
+        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+      GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
+  /* FIXME: 7/8 channel layouts are not defined in the FLAC specs */
+  {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+        GST_AUDIO_CHANNEL_POSITION_LFE1,
+      GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+        GST_AUDIO_CHANNEL_POSITION_LFE1,
+        GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+      GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}
+};
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-flac")
+    );
+
+enum
+{
+  PROP_0,
+  PROP_QUALITY,
+  PROP_STREAMABLE_SUBSET,
+  PROP_MID_SIDE_STEREO,
+  PROP_LOOSE_MID_SIDE_STEREO,
+  PROP_BLOCKSIZE,
+  PROP_MAX_LPC_ORDER,
+  PROP_QLP_COEFF_PRECISION,
+  PROP_QLP_COEFF_PREC_SEARCH,
+  PROP_ESCAPE_CODING,
+  PROP_EXHAUSTIVE_MODEL_SEARCH,
+  PROP_MIN_RESIDUAL_PARTITION_ORDER,
+  PROP_MAX_RESIDUAL_PARTITION_ORDER,
+  PROP_RICE_PARAMETER_SEARCH_DIST,
+  PROP_PADDING,
+  PROP_SEEKPOINTS
+};
+
+GST_DEBUG_CATEGORY_STATIC (flacenc_debug);
+#define GST_CAT_DEFAULT flacenc_debug
+
+#define gst_flac_enc_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstFlacEnc, gst_flac_enc, GST_TYPE_AUDIO_ENCODER,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL)
+    G_IMPLEMENT_INTERFACE (GST_TYPE_TOC_SETTER, NULL)
+    );
+
+static gboolean gst_flac_enc_start (GstAudioEncoder * enc);
+static gboolean gst_flac_enc_stop (GstAudioEncoder * enc);
+static gboolean gst_flac_enc_set_format (GstAudioEncoder * enc,
+    GstAudioInfo * info);
+static GstFlowReturn gst_flac_enc_handle_frame (GstAudioEncoder * enc,
+    GstBuffer * in_buf);
+static GstCaps *gst_flac_enc_getcaps (GstAudioEncoder * enc, GstCaps * filter);
+static gboolean gst_flac_enc_sink_event (GstAudioEncoder * enc,
+    GstEvent * event);
+static gboolean gst_flac_enc_sink_query (GstAudioEncoder * enc,
+    GstQuery * query);
+
+static void gst_flac_enc_finalize (GObject * object);
+
+static GstCaps *gst_flac_enc_generate_sink_caps (void);
+
+static gboolean gst_flac_enc_update_quality (GstFlacEnc * flacenc,
+    gint quality);
+static void gst_flac_enc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_flac_enc_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static FLAC__StreamEncoderWriteStatus
+gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
+    const FLAC__byte buffer[], size_t bytes,
+    unsigned samples, unsigned current_frame, void *client_data);
+static FLAC__StreamEncoderSeekStatus
+gst_flac_enc_seek_callback (const FLAC__StreamEncoder * encoder,
+    FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__StreamEncoderTellStatus
+gst_flac_enc_tell_callback (const FLAC__StreamEncoder * encoder,
+    FLAC__uint64 * absolute_byte_offset, void *client_data);
+
+typedef struct
+{
+  gboolean exhaustive_model_search;
+  gboolean escape_coding;
+  gboolean mid_side;
+  gboolean loose_mid_side;
+  guint qlp_coeff_precision;
+  gboolean qlp_coeff_prec_search;
+  guint min_residual_partition_order;
+  guint max_residual_partition_order;
+  guint rice_parameter_search_dist;
+  guint max_lpc_order;
+  guint blocksize;
+}
+GstFlacEncParams;
+
+static const GstFlacEncParams flacenc_params[] = {
+  {FALSE, FALSE, FALSE, FALSE, 0, FALSE, 2, 2, 0, 0, 1152},
+  {FALSE, FALSE, TRUE, TRUE, 0, FALSE, 2, 2, 0, 0, 1152},
+  {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, 3, 0, 0, 1152},
+  {FALSE, FALSE, FALSE, FALSE, 0, FALSE, 3, 3, 0, 6, 4608},
+  {FALSE, FALSE, TRUE, TRUE, 0, FALSE, 3, 3, 0, 8, 4608},
+  {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 3, 3, 0, 8, 4608},
+  {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, 4, 0, 8, 4608},
+  {TRUE, FALSE, TRUE, FALSE, 0, FALSE, 0, 6, 0, 8, 4608},
+  {TRUE, FALSE, TRUE, FALSE, 0, FALSE, 0, 6, 0, 12, 4608},
+  {TRUE, TRUE, TRUE, FALSE, 0, FALSE, 0, 16, 0, 32, 4608},
+};
+
+#define DEFAULT_QUALITY 5
+#define DEFAULT_PADDING 0
+#define DEFAULT_SEEKPOINTS -10
+
+#define GST_TYPE_FLAC_ENC_QUALITY (gst_flac_enc_quality_get_type ())
+static GType
+gst_flac_enc_quality_get_type (void)
+{
+  static GType qtype = 0;
+
+  if (qtype == 0) {
+    static const GEnumValue values[] = {
+      {0, "0 - Fastest compression", "0"},
+      {1, "1", "1"},
+      {2, "2", "2"},
+      {3, "3", "3"},
+      {4, "4", "4"},
+      {5, "5 - Default", "5"},
+      {6, "6", "6"},
+      {7, "7", "7"},
+      {8, "8 - Highest compression", "8"},
+      {9, "9 - Insane", "9"},
+      {0, NULL, NULL}
+    };
+
+    qtype = g_enum_register_static ("GstFlacEncQuality", values);
+  }
+  return qtype;
+}
+
+static void
+gst_flac_enc_class_init (GstFlacEncClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstAudioEncoderClass *base_class;
+  GstCaps *sink_caps;
+  GstPadTemplate *sink_templ;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  base_class = (GstAudioEncoderClass *) (klass);
+
+  GST_DEBUG_CATEGORY_INIT (flacenc_debug, "flacenc", 0,
+      "Flac encoding element");
+
+  gobject_class->set_property = gst_flac_enc_set_property;
+  gobject_class->get_property = gst_flac_enc_get_property;
+  gobject_class->finalize = gst_flac_enc_finalize;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
+      g_param_spec_enum ("quality",
+          "Quality",
+          "Speed versus compression tradeoff",
+          GST_TYPE_FLAC_ENC_QUALITY, DEFAULT_QUALITY,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_STREAMABLE_SUBSET, g_param_spec_boolean ("streamable-subset",
+          "Streamable subset",
+          "true to limit encoder to generating a Subset stream, else false",
+          TRUE,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MID_SIDE_STEREO,
+      g_param_spec_boolean ("mid-side-stereo", "Do mid side stereo",
+          "Do mid side stereo (only for stereo input)",
+          flacenc_params[DEFAULT_QUALITY].mid_side,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_LOOSE_MID_SIDE_STEREO, g_param_spec_boolean ("loose-mid-side-stereo",
+          "Loose mid side stereo", "Loose mid side stereo",
+          flacenc_params[DEFAULT_QUALITY].loose_mid_side,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BLOCKSIZE,
+      g_param_spec_uint ("blocksize", "Blocksize", "Blocksize in samples",
+          FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE,
+          flacenc_params[DEFAULT_QUALITY].blocksize,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_LPC_ORDER,
+      g_param_spec_uint ("max-lpc-order", "Max LPC order",
+          "Max LPC order; 0 => use only fixed predictors", 0,
+          FLAC__MAX_LPC_ORDER, flacenc_params[DEFAULT_QUALITY].max_lpc_order,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_QLP_COEFF_PRECISION, g_param_spec_uint ("qlp-coeff-precision",
+          "QLP coefficients precision",
+          "Precision in bits of quantized linear-predictor coefficients; 0 = automatic",
+          0, 32, flacenc_params[DEFAULT_QUALITY].qlp_coeff_precision,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_QLP_COEFF_PREC_SEARCH, g_param_spec_boolean ("qlp-coeff-prec-search",
+          "Do QLP coefficients precision search",
+          "false = use qlp_coeff_precision, "
+          "true = search around qlp_coeff_precision, take best",
+          flacenc_params[DEFAULT_QUALITY].qlp_coeff_prec_search,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ESCAPE_CODING,
+      g_param_spec_boolean ("escape-coding", "Do Escape coding",
+          "search for escape codes in the entropy coding stage "
+          "for slightly better compression",
+          flacenc_params[DEFAULT_QUALITY].escape_coding,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_EXHAUSTIVE_MODEL_SEARCH,
+      g_param_spec_boolean ("exhaustive-model-search",
+          "Do exhaustive model search",
+          "do exhaustive search of LP coefficient quantization (expensive!)",
+          flacenc_params[DEFAULT_QUALITY].exhaustive_model_search,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_MIN_RESIDUAL_PARTITION_ORDER,
+      g_param_spec_uint ("min-residual-partition-order",
+          "Min residual partition order",
+          "Min residual partition order (above 4 doesn't usually help much)", 0,
+          16, flacenc_params[DEFAULT_QUALITY].min_residual_partition_order,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_MAX_RESIDUAL_PARTITION_ORDER,
+      g_param_spec_uint ("max-residual-partition-order",
+          "Max residual partition order",
+          "Max residual partition order (above 4 doesn't usually help much)", 0,
+          16, flacenc_params[DEFAULT_QUALITY].max_residual_partition_order,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_RICE_PARAMETER_SEARCH_DIST,
+      g_param_spec_uint ("rice-parameter-search-dist",
+          "rice_parameter_search_dist",
+          "0 = try only calc'd parameter k; else try all [k-dist..k+dist] "
+          "parameters, use best", 0, FLAC__MAX_RICE_PARTITION_ORDER,
+          flacenc_params[DEFAULT_QUALITY].rice_parameter_search_dist,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_PADDING,
+      g_param_spec_uint ("padding",
+          "Padding",
+          "Write a PADDING block with this length in bytes", 0, G_MAXUINT,
+          DEFAULT_PADDING,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_SEEKPOINTS,
+      g_param_spec_int ("seekpoints",
+          "Seekpoints",
+          "Add SEEKTABLE metadata (if > 0, number of entries, if < 0, interval in sec)",
+          -G_MAXINT, G_MAXINT,
+          DEFAULT_SEEKPOINTS,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+
+  sink_caps = gst_flac_enc_generate_sink_caps ();
+  sink_templ = gst_pad_template_new ("sink",
+      GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps);
+  gst_element_class_add_pad_template (gstelement_class, sink_templ);
+  gst_caps_unref (sink_caps);
+
+  gst_element_class_set_static_metadata (gstelement_class, "FLAC audio encoder",
+      "Codec/Encoder/Audio",
+      "Encodes audio with the FLAC lossless audio encoder",
+      "Wim Taymans <wim.taymans@chello.be>");
+
+  base_class->start = GST_DEBUG_FUNCPTR (gst_flac_enc_start);
+  base_class->stop = GST_DEBUG_FUNCPTR (gst_flac_enc_stop);
+  base_class->set_format = GST_DEBUG_FUNCPTR (gst_flac_enc_set_format);
+  base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_flac_enc_handle_frame);
+  base_class->getcaps = GST_DEBUG_FUNCPTR (gst_flac_enc_getcaps);
+  base_class->sink_event = GST_DEBUG_FUNCPTR (gst_flac_enc_sink_event);
+  base_class->sink_query = GST_DEBUG_FUNCPTR (gst_flac_enc_sink_query);
+}
+
+static void
+gst_flac_enc_init (GstFlacEnc * flacenc)
+{
+  GstAudioEncoder *enc = GST_AUDIO_ENCODER (flacenc);
+
+  flacenc->encoder = FLAC__stream_encoder_new ();
+  gst_flac_enc_update_quality (flacenc, DEFAULT_QUALITY);
+
+  /* arrange granulepos marking (and required perfect ts) */
+  gst_audio_encoder_set_mark_granule (enc, TRUE);
+  gst_audio_encoder_set_perfect_timestamp (enc, TRUE);
+}
+
+static void
+gst_flac_enc_finalize (GObject * object)
+{
+  GstFlacEnc *flacenc = GST_FLAC_ENC (object);
+
+  FLAC__stream_encoder_delete (flacenc->encoder);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_flac_enc_start (GstAudioEncoder * enc)
+{
+  GstFlacEnc *flacenc = GST_FLAC_ENC (enc);
+
+  GST_DEBUG_OBJECT (enc, "start");
+  flacenc->stopped = TRUE;
+  flacenc->got_headers = FALSE;
+  flacenc->last_flow = GST_FLOW_OK;
+  flacenc->offset = 0;
+  flacenc->eos = FALSE;
+  flacenc->tags = gst_tag_list_new_empty ();
+  flacenc->toc = NULL;
+  flacenc->samples_in = 0;
+  flacenc->samples_out = 0;
+
+  return TRUE;
+}
+
+static gboolean
+gst_flac_enc_stop (GstAudioEncoder * enc)
+{
+  GstFlacEnc *flacenc = GST_FLAC_ENC (enc);
+
+  GST_DEBUG_OBJECT (enc, "stop");
+  gst_tag_list_unref (flacenc->tags);
+  flacenc->tags = NULL;
+  if (flacenc->toc)
+    gst_toc_unref (flacenc->toc);
+  flacenc->toc = NULL;
+  if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
+      FLAC__STREAM_ENCODER_UNINITIALIZED) {
+    flacenc->stopped = TRUE;
+    FLAC__stream_encoder_finish (flacenc->encoder);
+  }
+  if (flacenc->meta) {
+    FLAC__metadata_object_delete (flacenc->meta[0]);
+
+    if (flacenc->meta[1])
+      FLAC__metadata_object_delete (flacenc->meta[1]);
+
+    if (flacenc->meta[2])
+      FLAC__metadata_object_delete (flacenc->meta[2]);
+
+    if (flacenc->meta[3])
+      FLAC__metadata_object_delete (flacenc->meta[3]);
+
+    g_free (flacenc->meta);
+    flacenc->meta = NULL;
+  }
+  g_list_foreach (flacenc->headers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (flacenc->headers);
+  flacenc->headers = NULL;
+
+  gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
+  gst_toc_setter_reset (GST_TOC_SETTER (enc));
+
+  return TRUE;
+}
+
+static void
+add_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
+{
+  GList *comments;
+  GList *it;
+  GstFlacEnc *flacenc = GST_FLAC_ENC (user_data);
+
+  /* IMAGE and PREVIEW_IMAGE tags are already written
+   * differently, no need to store them inside the
+   * vorbiscomments too */
+  if (strcmp (tag, GST_TAG_IMAGE) == 0
+      || strcmp (tag, GST_TAG_PREVIEW_IMAGE) == 0)
+    return;
+
+  comments = gst_tag_to_vorbis_comments (list, tag);
+  for (it = comments; it != NULL; it = it->next) {
+    FLAC__StreamMetadata_VorbisComment_Entry commment_entry;
+
+    commment_entry.length = strlen (it->data);
+    commment_entry.entry = it->data;
+    FLAC__metadata_object_vorbiscomment_insert_comment (flacenc->meta[0],
+        flacenc->meta[0]->data.vorbis_comment.num_comments,
+        commment_entry, TRUE);
+    g_free (it->data);
+  }
+  g_list_free (comments);
+}
+
+static gboolean
+add_cuesheet (const GstToc * toc, guint sample_rate,
+    FLAC__StreamMetadata * cuesheet)
+{
+  gint8 track_num = 0;
+  gint64 start, stop;
+  gchar *isrc = NULL;
+  const gchar *is_legal;
+  GList *list;
+  GstTagList *tags;
+  GstTocEntry *entry, *subentry = NULL;
+  FLAC__StreamMetadata_CueSheet *cs;
+  FLAC__StreamMetadata_CueSheet_Track *track;
+
+  cs = &cuesheet->data.cue_sheet;
+  if (!cs)
+    return FALSE;
+
+  /* check if the TOC entries is valid */
+  list = gst_toc_get_entries (toc);
+  entry = list->data;
+  if (gst_toc_entry_is_alternative (entry)) {
+    list = gst_toc_entry_get_sub_entries (entry);
+    while (list) {
+      subentry = list->data;
+      if (!gst_toc_entry_is_sequence (subentry))
+        return FALSE;
+      list = g_list_next (list);
+    }
+    list = gst_toc_entry_get_sub_entries (entry);
+  }
+  if (gst_toc_entry_is_sequence (entry)) {
+    while (list) {
+      entry = list->data;
+      if (!gst_toc_entry_is_sequence (entry))
+        return FALSE;
+      list = g_list_next (list);
+    }
+    list = gst_toc_get_entries (toc);
+  }
+
+  /* add tracks in cuesheet */
+  while (list) {
+    entry = list->data;
+    gst_toc_entry_get_start_stop_times (entry, &start, &stop);
+    tags = gst_toc_entry_get_tags (entry);
+    if (tags)
+      gst_tag_list_get_string (tags, GST_TAG_ISRC, &isrc);
+    track = FLAC__metadata_object_cuesheet_track_new ();
+    track->offset =
+        (FLAC__uint64) gst_util_uint64_scale_round (start, sample_rate,
+        GST_SECOND);
+    track->number = (FLAC__byte) track_num + 1;
+    if (isrc != NULL && strlen (isrc) <= 12)
+      g_strlcpy (track->isrc, isrc, 13);
+    if (track->number <= 0)
+      return FALSE;
+    if (!FLAC__metadata_object_cuesheet_insert_track (cuesheet, track_num,
+            track, FALSE))
+      return FALSE;
+    if (!FLAC__metadata_object_cuesheet_track_insert_blank_index (cuesheet,
+            track_num, 0))
+      return FALSE;
+    track_num++;
+    list = g_list_next (list);
+  }
+
+  if (cs->num_tracks <= 0)
+    return FALSE;
+
+  /* add lead-out track in cuesheet */
+  track = FLAC__metadata_object_cuesheet_track_new ();
+  track->offset =
+      (FLAC__uint64) gst_util_uint64_scale_round (stop, sample_rate,
+      GST_SECOND);
+  track->number = 255;
+  if (!FLAC__metadata_object_cuesheet_insert_track (cuesheet, cs->num_tracks,
+          track, FALSE))
+    return FALSE;
+
+  /* check if the cuesheet is valid */
+  if (!FLAC__metadata_object_cuesheet_is_legal (cuesheet, FALSE, &is_legal)) {
+    g_warning ("%s\n", is_legal);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static void
+gst_flac_enc_set_metadata (GstFlacEnc * flacenc, GstAudioInfo * info,
+    guint64 total_samples)
+{
+  const GstTagList *user_tags;
+  GstTagList *copy;
+  gint entries = 1;
+  gint n_images, n_preview_images;
+  FLAC__StreamMetadata *cuesheet;
+
+  g_return_if_fail (flacenc != NULL);
+
+  user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (flacenc));
+  if ((flacenc->tags == NULL) && (user_tags == NULL)) {
+    return;
+  }
+  copy = gst_tag_list_merge (user_tags, flacenc->tags,
+      gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (flacenc)));
+  n_images = gst_tag_list_get_tag_size (copy, GST_TAG_IMAGE);
+  n_preview_images = gst_tag_list_get_tag_size (copy, GST_TAG_PREVIEW_IMAGE);
+
+  flacenc->meta =
+      g_new0 (FLAC__StreamMetadata *, 4 + n_images + n_preview_images);
+
+  flacenc->meta[0] =
+      FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
+  gst_tag_list_foreach (copy, add_one_tag, flacenc);
+
+  if (!flacenc->toc)
+    flacenc->toc = gst_toc_setter_get_toc (GST_TOC_SETTER (flacenc));
+
+  if (flacenc->toc) {
+    cuesheet = FLAC__metadata_object_new (FLAC__METADATA_TYPE_CUESHEET);
+    if (add_cuesheet (flacenc->toc, GST_AUDIO_INFO_RATE (info), cuesheet)) {
+      flacenc->meta[entries] = cuesheet;
+      entries++;
+    } else {
+      FLAC__metadata_object_delete (cuesheet);
+      flacenc->meta[entries] = NULL;
+    }
+  }
+
+  if (n_images + n_preview_images > 0) {
+    GstSample *sample;
+    GstBuffer *buffer;
+    GstCaps *caps;
+    const GstStructure *structure;
+    GstTagImageType image_type = GST_TAG_IMAGE_TYPE_NONE;
+    gint i, width = 0, height = 0, png_icon_count = 0, other_icon_count = 0;
+    GstMapInfo map;
+
+    for (i = 0; i < n_images + n_preview_images; i++) {
+      gboolean is_preview_image = (i >= n_images);
+
+      if (i < n_images) {
+        if (!gst_tag_list_get_sample_index (copy, GST_TAG_IMAGE, i, &sample))
+          continue;
+      } else {
+        if (!gst_tag_list_get_sample_index (copy, GST_TAG_PREVIEW_IMAGE,
+                i - n_images, &sample))
+          continue;
+      }
+
+      structure = gst_sample_get_info (sample);
+      caps = gst_sample_get_caps (sample);
+      if (!caps) {
+        GST_FIXME_OBJECT (flacenc, "Image tag without caps");
+        gst_sample_unref (sample);
+        continue;
+      }
+
+      flacenc->meta[entries] =
+          FLAC__metadata_object_new (FLAC__METADATA_TYPE_PICTURE);
+
+      GST_LOG_OBJECT (flacenc, "image info: %" GST_PTR_FORMAT, structure);
+
+      if (structure)
+        gst_structure_get (structure, "image-type", GST_TYPE_TAG_IMAGE_TYPE,
+            &image_type, NULL);
+      else
+        image_type = GST_TAG_IMAGE_TYPE_NONE;
+
+      GST_LOG_OBJECT (flacenc, "image caps: %" GST_PTR_FORMAT, caps);
+
+      structure = gst_caps_get_structure (caps, 0);
+      gst_structure_get (structure, "width", G_TYPE_INT, &width,
+          "height", G_TYPE_INT, &height, NULL);
+
+      /* Convert to ID3v2 APIC image type */
+      if (image_type == GST_TAG_IMAGE_TYPE_NONE) {
+        if (is_preview_image) {
+          /* 1 - 32x32 pixels 'file icon' (PNG only)
+           * 2 - Other file icon
+           * There may only be one each of picture type 1 and 2 in a file. */
+          if (width == 32 && height == 32
+              && gst_structure_has_name (structure, "image/png")
+              && png_icon_count++ == 0) {
+            image_type = 1;
+          } else if (width <= 32 && height <= 32 && other_icon_count++ == 0) {
+            image_type = 2;
+          } else {
+            image_type = 0;     /* Other */
+          }
+        } else {
+          image_type = 0;       /* Other */
+        }
+      } else {
+        /* GStreamer enum is the same but without the two icon types 1+2 */
+        image_type = image_type + 2;
+      }
+
+      buffer = gst_sample_get_buffer (sample);
+      gst_buffer_map (buffer, &map, GST_MAP_READ);
+      FLAC__metadata_object_picture_set_data (flacenc->meta[entries],
+          map.data, map.size, TRUE);
+      gst_buffer_unmap (buffer, &map);
+
+      GST_LOG_OBJECT (flacenc, "Setting picture type %d", image_type);
+      flacenc->meta[entries]->data.picture.type = image_type;
+
+      if (width > 0 && height > 0) {
+        flacenc->meta[entries]->data.picture.width = width;
+        flacenc->meta[entries]->data.picture.height = height;
+      }
+
+      FLAC__metadata_object_picture_set_mime_type (flacenc->meta[entries],
+          (char *) gst_structure_get_name (structure), TRUE);
+
+      gst_sample_unref (sample);
+      entries++;
+    }
+  }
+
+  if (flacenc->seekpoints && total_samples != GST_CLOCK_TIME_NONE) {
+    gboolean res;
+    guint samples;
+
+    flacenc->meta[entries] =
+        FLAC__metadata_object_new (FLAC__METADATA_TYPE_SEEKTABLE);
+    if (flacenc->seekpoints > 0) {
+      res =
+          FLAC__metadata_object_seektable_template_append_spaced_points
+          (flacenc->meta[entries], flacenc->seekpoints, total_samples);
+    } else {
+      samples = -flacenc->seekpoints * GST_AUDIO_INFO_RATE (info);
+      res =
+          FLAC__metadata_object_seektable_template_append_spaced_points_by_samples
+          (flacenc->meta[entries], samples, total_samples);
+    }
+    if (!res) {
+      GST_DEBUG_OBJECT (flacenc, "adding seekpoint template %d failed",
+          flacenc->seekpoints);
+      FLAC__metadata_object_delete (flacenc->meta[1]);
+      flacenc->meta[entries] = NULL;
+    } else {
+      entries++;
+    }
+  } else if (flacenc->seekpoints && total_samples == GST_CLOCK_TIME_NONE) {
+    GST_WARNING_OBJECT (flacenc, "total time unknown; can not add seekpoints");
+  }
+
+  if (flacenc->padding > 0) {
+    flacenc->meta[entries] =
+        FLAC__metadata_object_new (FLAC__METADATA_TYPE_PADDING);
+    flacenc->meta[entries]->length = flacenc->padding;
+    entries++;
+  }
+
+  if (FLAC__stream_encoder_set_metadata (flacenc->encoder,
+          flacenc->meta, entries) != true)
+    g_warning ("Dude, i'm already initialized!");
+
+  gst_tag_list_unref (copy);
+}
+
+static GstCaps *
+gst_flac_enc_generate_sink_caps (void)
+{
+  GstCaps *ret;
+  gint i;
+  GValue v_list = { 0, };
+  GValue v = { 0, };
+  GstStructure *s, *s2;
+
+  g_value_init (&v_list, GST_TYPE_LIST);
+  g_value_init (&v, G_TYPE_STRING);
+
+  /* Use system's endianness */
+  g_value_set_static_string (&v, "S8");
+  gst_value_list_append_value (&v_list, &v);
+  g_value_set_static_string (&v, GST_AUDIO_NE (S16));
+  gst_value_list_append_value (&v_list, &v);
+  g_value_set_static_string (&v, GST_AUDIO_NE (S24));
+  gst_value_list_append_value (&v_list, &v);
+  g_value_set_static_string (&v, GST_AUDIO_NE (S24_32));
+  gst_value_list_append_value (&v_list, &v);
+  g_value_unset (&v);
+
+  s = gst_structure_new_empty ("audio/x-raw");
+  gst_structure_take_value (s, "format", &v_list);
+
+  gst_structure_set (s, "layout", G_TYPE_STRING, "interleaved",
+      "rate", GST_TYPE_INT_RANGE, 1, 655350, NULL);
+
+  ret = gst_caps_new_empty ();
+  s2 = gst_structure_copy (s);
+  gst_structure_set (s2, "channels", G_TYPE_INT, 1, NULL);
+  gst_caps_append_structure (ret, s2);
+  for (i = 2; i <= 8; i++) {
+    guint64 channel_mask;
+
+    s2 = gst_structure_copy (s);
+    gst_audio_channel_positions_to_mask (channel_positions[i - 1], i,
+        FALSE, &channel_mask);
+    gst_structure_set (s2, "channels", G_TYPE_INT, i, "channel-mask",
+        GST_TYPE_BITMASK, channel_mask, NULL);
+
+    gst_caps_append_structure (ret, s2);
+  }
+  gst_structure_free (s);
+
+  return ret;
+}
+
+static GstCaps *
+gst_flac_enc_getcaps (GstAudioEncoder * enc, GstCaps * filter)
+{
+  GstCaps *ret = NULL, *caps = NULL;
+  GstPad *pad;
+
+  pad = GST_AUDIO_ENCODER_SINK_PAD (enc);
+
+  ret = gst_pad_get_current_caps (pad);
+  if (ret == NULL) {
+    ret = gst_pad_get_pad_template_caps (pad);
+  }
+
+  GST_DEBUG_OBJECT (pad, "Return caps %" GST_PTR_FORMAT, ret);
+
+  caps = gst_audio_encoder_proxy_getcaps (enc, ret, filter);
+  gst_caps_unref (ret);
+
+  return caps;
+}
+
+static guint64
+gst_flac_enc_peer_query_total_samples (GstFlacEnc * flacenc, GstPad * pad)
+{
+  gint64 duration;
+  GstAudioInfo *info =
+      gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (flacenc));
+
+  GST_DEBUG_OBJECT (flacenc, "querying peer for DEFAULT format duration");
+  if (gst_pad_peer_query_duration (pad, GST_FORMAT_DEFAULT, &duration)
+      && duration != GST_CLOCK_TIME_NONE)
+    goto done;
+
+  GST_DEBUG_OBJECT (flacenc, "querying peer for TIME format duration");
+
+  if (gst_pad_peer_query_duration (pad, GST_FORMAT_TIME, &duration)
+      && duration != GST_CLOCK_TIME_NONE) {
+    GST_DEBUG_OBJECT (flacenc, "peer reported duration %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (duration));
+    duration = GST_CLOCK_TIME_TO_FRAMES (duration, GST_AUDIO_INFO_RATE (info));
+
+    goto done;
+  }
+
+  GST_DEBUG_OBJECT (flacenc, "Upstream reported no total samples");
+  return GST_CLOCK_TIME_NONE;
+
+done:
+  GST_DEBUG_OBJECT (flacenc,
+      "Upstream reported %" G_GUINT64_FORMAT " total samples", duration);
+
+  return duration;
+}
+
+static gboolean
+gst_flac_enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
+{
+  GstFlacEnc *flacenc;
+  guint64 total_samples = GST_CLOCK_TIME_NONE;
+  FLAC__StreamEncoderInitStatus init_status;
+
+  flacenc = GST_FLAC_ENC (enc);
+
+  /* if configured again, means something changed, can't handle that */
+  if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
+      FLAC__STREAM_ENCODER_UNINITIALIZED)
+    goto encoder_already_initialized;
+
+  /* delay setting output caps/format until we have all headers */
+
+  gst_audio_get_channel_reorder_map (GST_AUDIO_INFO_CHANNELS (info),
+      channel_positions[GST_AUDIO_INFO_CHANNELS (info) - 1], info->position,
+      flacenc->channel_reorder_map);
+
+  total_samples = gst_flac_enc_peer_query_total_samples (flacenc,
+      GST_AUDIO_ENCODER_SINK_PAD (enc));
+
+  FLAC__stream_encoder_set_bits_per_sample (flacenc->encoder,
+      GST_AUDIO_INFO_DEPTH (info));
+  FLAC__stream_encoder_set_sample_rate (flacenc->encoder,
+      GST_AUDIO_INFO_RATE (info));
+  FLAC__stream_encoder_set_channels (flacenc->encoder,
+      GST_AUDIO_INFO_CHANNELS (info));
+
+  if (total_samples != GST_CLOCK_TIME_NONE)
+    FLAC__stream_encoder_set_total_samples_estimate (flacenc->encoder,
+        MIN (total_samples, G_GUINT64_CONSTANT (0x0FFFFFFFFF)));
+
+  gst_flac_enc_set_metadata (flacenc, info, total_samples);
+
+  /* callbacks clear to go now;
+   * write callbacks receives headers during init */
+  flacenc->stopped = FALSE;
+
+  init_status = FLAC__stream_encoder_init_stream (flacenc->encoder,
+      gst_flac_enc_write_callback, gst_flac_enc_seek_callback,
+      gst_flac_enc_tell_callback, NULL, flacenc);
+  if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
+    goto failed_to_initialize;
+
+  /* no special feedback to base class; should provide all available samples */
+
+  return TRUE;
+
+encoder_already_initialized:
+  {
+    g_warning ("flac already initialized -- fixme allow this");
+    return FALSE;
+  }
+failed_to_initialize:
+  {
+    GST_ELEMENT_ERROR (flacenc, LIBRARY, INIT, (NULL),
+        ("could not initialize encoder (wrong parameters?) %d", init_status));
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_flac_enc_update_quality (GstFlacEnc * flacenc, gint quality)
+{
+  GstAudioInfo *info =
+      gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (flacenc));
+
+  flacenc->quality = quality;
+
+#define DO_UPDATE(name, val, str)                                               \
+  G_STMT_START {                                                                \
+    if (FLAC__stream_encoder_get_##name (flacenc->encoder) !=                   \
+        flacenc_params[quality].val) {                                          \
+      FLAC__stream_encoder_set_##name (flacenc->encoder,                        \
+          flacenc_params[quality].val);                                         \
+      g_object_notify (G_OBJECT (flacenc), str);                                \
+    }                                                                           \
+  } G_STMT_END
+
+  g_object_freeze_notify (G_OBJECT (flacenc));
+
+  if (GST_AUDIO_INFO_CHANNELS (info) == 2
+      || GST_AUDIO_INFO_CHANNELS (info) == 0) {
+    DO_UPDATE (do_mid_side_stereo, mid_side, "mid_side_stereo");
+    DO_UPDATE (loose_mid_side_stereo, loose_mid_side, "loose_mid_side");
+  }
+
+  DO_UPDATE (blocksize, blocksize, "blocksize");
+  DO_UPDATE (max_lpc_order, max_lpc_order, "max_lpc_order");
+  DO_UPDATE (qlp_coeff_precision, qlp_coeff_precision, "qlp_coeff_precision");
+  DO_UPDATE (do_qlp_coeff_prec_search, qlp_coeff_prec_search,
+      "qlp_coeff_prec_search");
+  DO_UPDATE (do_escape_coding, escape_coding, "escape_coding");
+  DO_UPDATE (do_exhaustive_model_search, exhaustive_model_search,
+      "exhaustive_model_search");
+  DO_UPDATE (min_residual_partition_order, min_residual_partition_order,
+      "min_residual_partition_order");
+  DO_UPDATE (max_residual_partition_order, max_residual_partition_order,
+      "max_residual_partition_order");
+  DO_UPDATE (rice_parameter_search_dist, rice_parameter_search_dist,
+      "rice_parameter_search_dist");
+
+#undef DO_UPDATE
+
+  g_object_thaw_notify (G_OBJECT (flacenc));
+
+  return TRUE;
+}
+
+static FLAC__StreamEncoderSeekStatus
+gst_flac_enc_seek_callback (const FLAC__StreamEncoder * encoder,
+    FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+  GstFlacEnc *flacenc;
+  GstPad *peerpad;
+  GstSegment seg;
+
+  flacenc = GST_FLAC_ENC (client_data);
+
+  if (flacenc->stopped)
+    return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
+
+  if ((peerpad = gst_pad_get_peer (GST_AUDIO_ENCODER_SRC_PAD (flacenc)))) {
+    GstEvent *event;
+    gboolean ret;
+    GstQuery *query;
+    gboolean seekable = FALSE;
+
+    /* try to seek to the beginning of the output */
+    query = gst_query_new_seeking (GST_FORMAT_BYTES);
+    if (gst_pad_query (peerpad, query)) {
+      GstFormat format;
+
+      gst_query_parse_seeking (query, &format, &seekable, NULL, NULL);
+      if (format != GST_FORMAT_BYTES)
+        seekable = FALSE;
+    } else {
+      GST_LOG_OBJECT (flacenc, "SEEKING query not handled");
+    }
+    gst_query_unref (query);
+
+    if (!seekable) {
+      GST_DEBUG_OBJECT (flacenc, "downstream not seekable; not rewriting");
+      gst_object_unref (peerpad);
+      return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
+    }
+
+    gst_segment_init (&seg, GST_FORMAT_BYTES);
+    seg.start = absolute_byte_offset;
+    seg.stop = GST_BUFFER_OFFSET_NONE;
+    seg.time = 0;
+    event = gst_event_new_segment (&seg);
+
+    ret = gst_pad_send_event (peerpad, event);
+    gst_object_unref (peerpad);
+
+    if (ret) {
+      GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s",
+          (guint64) absolute_byte_offset, "succeeded");
+    } else {
+      GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s",
+          (guint64) absolute_byte_offset, "failed");
+      return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
+    }
+  } else {
+    GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " failed (no peer pad)",
+        (guint64) absolute_byte_offset);
+  }
+
+  flacenc->offset = absolute_byte_offset;
+  return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
+}
+
+static void
+notgst_value_array_append_buffer (GValue * array_val, GstBuffer * buf)
+{
+  GValue value = { 0, };
+
+  g_value_init (&value, GST_TYPE_BUFFER);
+  /* copy buffer to avoid problems with circular refcounts */
+  buf = gst_buffer_copy (buf);
+  /* again, for good measure */
+  GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
+  gst_value_set_buffer (&value, buf);
+  gst_buffer_unref (buf);
+  gst_value_array_append_value (array_val, &value);
+  g_value_unset (&value);
+}
+
+#define HDR_TYPE_STREAMINFO     0
+#define HDR_TYPE_VORBISCOMMENT  4
+
+static GstFlowReturn
+gst_flac_enc_process_stream_headers (GstFlacEnc * enc)
+{
+  GstBuffer *vorbiscomment = NULL;
+  GstBuffer *streaminfo = NULL;
+  GstBuffer *marker = NULL;
+  GValue array = { 0, };
+  GstCaps *caps;
+  GList *l;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstAudioInfo *info =
+      gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (enc));
+
+  caps = gst_caps_new_simple ("audio/x-flac",
+      "channels", G_TYPE_INT, GST_AUDIO_INFO_CHANNELS (info),
+      "rate", G_TYPE_INT, GST_AUDIO_INFO_RATE (info), NULL);
+
+  for (l = enc->headers; l != NULL; l = l->next) {
+    GstBuffer *buf;
+    GstMapInfo map;
+    guint8 *data;
+    gsize size;
+
+    /* mark buffers so oggmux will ignore them if it already muxed the
+     * header buffers from the streamheaders field in the caps */
+    l->data = gst_buffer_make_writable (GST_BUFFER_CAST (l->data));
+
+    buf = GST_BUFFER_CAST (l->data);
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
+
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    data = map.data;
+    size = map.size;
+
+    /* find initial 4-byte marker which we need to skip later on */
+    if (size == 4 && memcmp (data, "fLaC", 4) == 0) {
+      marker = buf;
+    } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_STREAMINFO) {
+      streaminfo = buf;
+    } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_VORBISCOMMENT) {
+      vorbiscomment = buf;
+    }
+
+    gst_buffer_unmap (buf, &map);
+  }
+
+  if (marker == NULL || streaminfo == NULL || vorbiscomment == NULL) {
+    GST_WARNING_OBJECT (enc, "missing header %p %p %p, muxing into container "
+        "formats may be broken", marker, streaminfo, vorbiscomment);
+    goto push_headers;
+  }
+
+  g_value_init (&array, GST_TYPE_ARRAY);
+
+  /* add marker including STREAMINFO header */
+  {
+    GstBuffer *buf;
+    guint16 num;
+    GstMapInfo map;
+    guint8 *bdata;
+    gsize slen;
+
+    /* minus one for the marker that is merged with streaminfo here */
+    num = g_list_length (enc->headers) - 1;
+
+    slen = gst_buffer_get_size (streaminfo);
+    buf = gst_buffer_new_and_alloc (13 + slen);
+
+    gst_buffer_map (buf, &map, GST_MAP_WRITE);
+    bdata = map.data;
+    bdata[0] = 0x7f;
+    memcpy (bdata + 1, "FLAC", 4);
+    bdata[5] = 0x01;            /* mapping version major */
+    bdata[6] = 0x00;            /* mapping version minor */
+    bdata[7] = (num & 0xFF00) >> 8;
+    bdata[8] = (num & 0x00FF) >> 0;
+    memcpy (bdata + 9, "fLaC", 4);
+    gst_buffer_extract (streaminfo, 0, bdata + 13, slen);
+    gst_buffer_unmap (buf, &map);
+
+    notgst_value_array_append_buffer (&array, buf);
+    gst_buffer_unref (buf);
+  }
+
+  /* add VORBISCOMMENT header */
+  notgst_value_array_append_buffer (&array, vorbiscomment);
+
+  /* add other headers, if there are any */
+  for (l = enc->headers; l != NULL; l = l->next) {
+    GstBuffer *buf = GST_BUFFER_CAST (l->data);
+
+    if (buf != marker && buf != streaminfo && buf != vorbiscomment) {
+      notgst_value_array_append_buffer (&array, buf);
+    }
+  }
+
+  gst_structure_set_value (gst_caps_get_structure (caps, 0),
+      "streamheader", &array);
+  g_value_unset (&array);
+
+push_headers:
+  gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (enc), caps);
+
+  gst_audio_encoder_set_headers (GST_AUDIO_ENCODER (enc), enc->headers);
+  enc->headers = NULL;
+
+  gst_caps_unref (caps);
+
+  return ret;
+}
+
+static FLAC__StreamEncoderWriteStatus
+gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
+    const FLAC__byte buffer[], size_t bytes,
+    unsigned samples, unsigned current_frame, void *client_data)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstFlacEnc *flacenc;
+  GstBuffer *outbuf;
+  GstSegment *segment;
+  GstClockTime duration;
+
+  flacenc = GST_FLAC_ENC (client_data);
+
+  if (flacenc->stopped)
+    return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+
+  outbuf = gst_buffer_new_and_alloc (bytes);
+  gst_buffer_fill (outbuf, 0, buffer, bytes);
+
+  /* we assume libflac passes us stuff neatly framed */
+  if (!flacenc->got_headers) {
+    if (samples == 0) {
+      GST_DEBUG_OBJECT (flacenc, "Got header, queueing (%u bytes)",
+          (guint) bytes);
+      flacenc->headers = g_list_append (flacenc->headers, outbuf);
+      /* note: it's important that we increase our byte offset */
+      goto out;
+    } else {
+      GST_INFO_OBJECT (flacenc, "Non-header packet, we have all headers now");
+      ret = gst_flac_enc_process_stream_headers (flacenc);
+      flacenc->got_headers = TRUE;
+    }
+  }
+
+  if (flacenc->got_headers && samples == 0) {
+    /* header fixup, push downstream directly */
+    GST_DEBUG_OBJECT (flacenc, "Fixing up headers at pos=%" G_GUINT64_FORMAT
+        ", size=%u", flacenc->offset, (guint) bytes);
+#if 0
+    GST_MEMDUMP_OBJECT (flacenc, "Presumed header fragment",
+        GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf));
+#endif
+    ret = gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (flacenc), outbuf);
+  } else {
+    /* regular frame data, pass to base class */
+    if (flacenc->eos && flacenc->samples_in == flacenc->samples_out + samples) {
+      /* If encoding part of a frame, and we have no set stop time on
+       * the output segment, we update the segment stop time to reflect
+       * the last sample. This will let oggmux set the last page's
+       * granpos to tell a decoder the dummy samples should be clipped.
+       */
+      segment = &GST_AUDIO_ENCODER_OUTPUT_SEGMENT (flacenc);
+      if (!GST_CLOCK_TIME_IS_VALID (segment->stop)) {
+        GST_DEBUG_OBJECT (flacenc,
+            "No stop time and partial frame, updating segment");
+        duration =
+            gst_util_uint64_scale (flacenc->samples_out + samples,
+            GST_SECOND,
+            FLAC__stream_encoder_get_sample_rate (flacenc->encoder));
+        segment->stop = segment->start + duration;
+        GST_DEBUG_OBJECT (flacenc, "new output segment %" GST_SEGMENT_FORMAT,
+            segment);
+        gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (flacenc),
+            gst_event_new_segment (segment));
+      }
+    }
+
+    GST_LOG ("Pushing buffer: samples=%u, size=%u, pos=%" G_GUINT64_FORMAT,
+        samples, (guint) bytes, flacenc->offset);
+    ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (flacenc),
+        outbuf, samples);
+  }
+
+  if (ret != GST_FLOW_OK)
+    GST_DEBUG_OBJECT (flacenc, "flow: %s", gst_flow_get_name (ret));
+
+  flacenc->last_flow = ret;
+
+out:
+  flacenc->offset += bytes;
+
+  if (ret != GST_FLOW_OK)
+    return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+
+  return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
+
+static FLAC__StreamEncoderTellStatus
+gst_flac_enc_tell_callback (const FLAC__StreamEncoder * encoder,
+    FLAC__uint64 * absolute_byte_offset, void *client_data)
+{
+  GstFlacEnc *flacenc = GST_FLAC_ENC (client_data);
+
+  *absolute_byte_offset = flacenc->offset;
+
+  return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
+}
+
+static gboolean
+gst_flac_enc_sink_event (GstAudioEncoder * enc, GstEvent * event)
+{
+  GstFlacEnc *flacenc;
+  GstTagList *taglist;
+  GstToc *toc;
+  gboolean ret = FALSE;
+
+  flacenc = GST_FLAC_ENC (enc);
+
+  GST_DEBUG ("Received %s event on sinkpad, %" GST_PTR_FORMAT,
+      GST_EVENT_TYPE_NAME (event), event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+      flacenc->eos = TRUE;
+      ret = GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (enc, event);
+      break;
+    case GST_EVENT_TAG:
+      if (flacenc->tags) {
+        gst_event_parse_tag (event, &taglist);
+        gst_tag_list_insert (flacenc->tags, taglist,
+            gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (flacenc)));
+      } else {
+        g_assert_not_reached ();
+      }
+      ret = GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (enc, event);
+      break;
+    case GST_EVENT_TOC:
+      gst_event_parse_toc (event, &toc, NULL);
+      if (toc) {
+        if (flacenc->toc != toc) {
+          if (flacenc->toc)
+            gst_toc_unref (flacenc->toc);
+          flacenc->toc = toc;
+        }
+      }
+      ret = GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (enc, event);
+      break;
+    case GST_EVENT_SEGMENT:
+      flacenc->samples_in = 0;
+      flacenc->samples_out = 0;
+      ret = GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (enc, event);
+      break;
+    default:
+      ret = GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (enc, event);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_flac_enc_sink_query (GstAudioEncoder * enc, GstQuery * query)
+{
+  GstPad *pad = GST_AUDIO_ENCODER_SINK_PAD (enc);
+  gboolean ret = FALSE;
+
+  GST_DEBUG ("Received %s query on sinkpad, %" GST_PTR_FORMAT,
+      GST_QUERY_TYPE_NAME (query), query);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_ACCEPT_CAPS:{
+      GstCaps *acceptable, *caps;
+
+      acceptable = gst_pad_get_current_caps (pad);
+      if (acceptable == NULL) {
+        acceptable = gst_pad_get_pad_template_caps (pad);
+      }
+
+      gst_query_parse_accept_caps (query, &caps);
+
+      gst_query_set_accept_caps_result (query,
+          gst_caps_is_subset (caps, acceptable));
+      gst_caps_unref (acceptable);
+      ret = TRUE;
+    }
+      break;
+    default:
+      ret = GST_AUDIO_ENCODER_CLASS (parent_class)->sink_query (enc, query);
+      break;
+  }
+
+  return ret;
+}
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define READ_INT24 GST_READ_UINT24_LE
+#else
+#define READ_INT24 GST_READ_UINT24_BE
+#endif
+
+static GstFlowReturn
+gst_flac_enc_handle_frame (GstAudioEncoder * enc, GstBuffer * buffer)
+{
+  GstFlacEnc *flacenc;
+  FLAC__int32 *data;
+  gint samples, width, channels;
+  gulong i;
+  gint j;
+  FLAC__bool res;
+  GstMapInfo map;
+  GstAudioInfo *info =
+      gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (enc));
+  gint *reorder_map;
+
+  flacenc = GST_FLAC_ENC (enc);
+
+  /* base class ensures configuration */
+  g_return_val_if_fail (GST_AUDIO_INFO_WIDTH (info) != 0,
+      GST_FLOW_NOT_NEGOTIATED);
+
+  width = GST_AUDIO_INFO_WIDTH (info);
+  channels = GST_AUDIO_INFO_CHANNELS (info);
+  reorder_map = flacenc->channel_reorder_map;
+
+  if (G_UNLIKELY (!buffer)) {
+    if (flacenc->eos) {
+      GST_DEBUG_OBJECT (flacenc, "finish encoding");
+      FLAC__stream_encoder_finish (flacenc->encoder);
+    } else {
+      /* can't handle intermittent draining/resyncing */
+      GST_ELEMENT_WARNING (flacenc, STREAM, FORMAT, (NULL),
+          ("Stream discontinuity detected. "
+              "The output may have wrong timestamps, "
+              "consider using audiorate to handle discontinuities"));
+    }
+    return flacenc->last_flow;
+  }
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  samples = map.size / (width >> 3);
+
+  data = g_malloc (samples * sizeof (FLAC__int32));
+
+  samples /= channels;
+  GST_LOG_OBJECT (flacenc, "processing %d samples, %d channels", samples,
+      channels);
+  if (width == 8) {
+    gint8 *indata = (gint8 *) map.data;
+
+    for (i = 0; i < samples; i++)
+      for (j = 0; j < channels; j++)
+        data[i * channels + reorder_map[j]] =
+            (FLAC__int32) indata[i * channels + j];
+  } else if (width == 16) {
+    gint16 *indata = (gint16 *) map.data;
+
+    for (i = 0; i < samples; i++)
+      for (j = 0; j < channels; j++)
+        data[i * channels + reorder_map[j]] =
+            (FLAC__int32) indata[i * channels + j];
+  } else if (width == 24) {
+    guint8 *indata = (guint8 *) map.data;
+    guint32 val;
+
+    for (i = 0; i < samples; i++)
+      for (j = 0; j < channels; j++) {
+        val = READ_INT24 (&indata[3 * (i * channels + j)]);
+        if (val & 0x00800000)
+          val |= 0xff000000;
+        data[i * channels + reorder_map[j]] = (FLAC__int32) val;
+      }
+  } else if (width == 32) {
+    gint32 *indata = (gint32 *) map.data;
+
+    for (i = 0; i < samples; i++)
+      for (j = 0; j < channels; j++)
+        data[i * channels + reorder_map[j]] =
+            (FLAC__int32) indata[i * channels + j];
+  } else {
+    g_assert_not_reached ();
+  }
+  gst_buffer_unmap (buffer, &map);
+
+  res = FLAC__stream_encoder_process_interleaved (flacenc->encoder,
+      (const FLAC__int32 *) data, samples);
+  flacenc->samples_in += samples;
+
+  g_free (data);
+
+  if (!res) {
+    if (flacenc->last_flow == GST_FLOW_OK)
+      return GST_FLOW_ERROR;
+    else
+      return flacenc->last_flow;
+  }
+
+  return GST_FLOW_OK;
+}
+
+static void
+gst_flac_enc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstFlacEnc *this = GST_FLAC_ENC (object);
+
+  GST_OBJECT_LOCK (this);
+
+  switch (prop_id) {
+    case PROP_QUALITY:
+      gst_flac_enc_update_quality (this, g_value_get_enum (value));
+      break;
+    case PROP_STREAMABLE_SUBSET:
+      FLAC__stream_encoder_set_streamable_subset (this->encoder,
+          g_value_get_boolean (value));
+      break;
+    case PROP_MID_SIDE_STEREO:
+      FLAC__stream_encoder_set_do_mid_side_stereo (this->encoder,
+          g_value_get_boolean (value));
+      break;
+    case PROP_LOOSE_MID_SIDE_STEREO:
+      FLAC__stream_encoder_set_loose_mid_side_stereo (this->encoder,
+          g_value_get_boolean (value));
+      break;
+    case PROP_BLOCKSIZE:
+      FLAC__stream_encoder_set_blocksize (this->encoder,
+          g_value_get_uint (value));
+      break;
+    case PROP_MAX_LPC_ORDER:
+      FLAC__stream_encoder_set_max_lpc_order (this->encoder,
+          g_value_get_uint (value));
+      break;
+    case PROP_QLP_COEFF_PRECISION:
+      FLAC__stream_encoder_set_qlp_coeff_precision (this->encoder,
+          g_value_get_uint (value));
+      break;
+    case PROP_QLP_COEFF_PREC_SEARCH:
+      FLAC__stream_encoder_set_do_qlp_coeff_prec_search (this->encoder,
+          g_value_get_boolean (value));
+      break;
+    case PROP_ESCAPE_CODING:
+      FLAC__stream_encoder_set_do_escape_coding (this->encoder,
+          g_value_get_boolean (value));
+      break;
+    case PROP_EXHAUSTIVE_MODEL_SEARCH:
+      FLAC__stream_encoder_set_do_exhaustive_model_search (this->encoder,
+          g_value_get_boolean (value));
+      break;
+    case PROP_MIN_RESIDUAL_PARTITION_ORDER:
+      FLAC__stream_encoder_set_min_residual_partition_order (this->encoder,
+          g_value_get_uint (value));
+      break;
+    case PROP_MAX_RESIDUAL_PARTITION_ORDER:
+      FLAC__stream_encoder_set_max_residual_partition_order (this->encoder,
+          g_value_get_uint (value));
+      break;
+    case PROP_RICE_PARAMETER_SEARCH_DIST:
+      FLAC__stream_encoder_set_rice_parameter_search_dist (this->encoder,
+          g_value_get_uint (value));
+      break;
+    case PROP_PADDING:
+      this->padding = g_value_get_uint (value);
+      break;
+    case PROP_SEEKPOINTS:
+      this->seekpoints = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  GST_OBJECT_UNLOCK (this);
+}
+
+static void
+gst_flac_enc_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstFlacEnc *this = GST_FLAC_ENC (object);
+
+  GST_OBJECT_LOCK (this);
+
+  switch (prop_id) {
+    case PROP_QUALITY:
+      g_value_set_enum (value, this->quality);
+      break;
+    case PROP_STREAMABLE_SUBSET:
+      g_value_set_boolean (value,
+          FLAC__stream_encoder_get_streamable_subset (this->encoder));
+      break;
+    case PROP_MID_SIDE_STEREO:
+      g_value_set_boolean (value,
+          FLAC__stream_encoder_get_do_mid_side_stereo (this->encoder));
+      break;
+    case PROP_LOOSE_MID_SIDE_STEREO:
+      g_value_set_boolean (value,
+          FLAC__stream_encoder_get_loose_mid_side_stereo (this->encoder));
+      break;
+    case PROP_BLOCKSIZE:
+      g_value_set_uint (value,
+          FLAC__stream_encoder_get_blocksize (this->encoder));
+      break;
+    case PROP_MAX_LPC_ORDER:
+      g_value_set_uint (value,
+          FLAC__stream_encoder_get_max_lpc_order (this->encoder));
+      break;
+    case PROP_QLP_COEFF_PRECISION:
+      g_value_set_uint (value,
+          FLAC__stream_encoder_get_qlp_coeff_precision (this->encoder));
+      break;
+    case PROP_QLP_COEFF_PREC_SEARCH:
+      g_value_set_boolean (value,
+          FLAC__stream_encoder_get_do_qlp_coeff_prec_search (this->encoder));
+      break;
+    case PROP_ESCAPE_CODING:
+      g_value_set_boolean (value,
+          FLAC__stream_encoder_get_do_escape_coding (this->encoder));
+      break;
+    case PROP_EXHAUSTIVE_MODEL_SEARCH:
+      g_value_set_boolean (value,
+          FLAC__stream_encoder_get_do_exhaustive_model_search (this->encoder));
+      break;
+    case PROP_MIN_RESIDUAL_PARTITION_ORDER:
+      g_value_set_uint (value,
+          FLAC__stream_encoder_get_min_residual_partition_order
+          (this->encoder));
+      break;
+    case PROP_MAX_RESIDUAL_PARTITION_ORDER:
+      g_value_set_uint (value,
+          FLAC__stream_encoder_get_max_residual_partition_order
+          (this->encoder));
+      break;
+    case PROP_RICE_PARAMETER_SEARCH_DIST:
+      g_value_set_uint (value,
+          FLAC__stream_encoder_get_rice_parameter_search_dist (this->encoder));
+      break;
+    case PROP_PADDING:
+      g_value_set_uint (value, this->padding);
+      break;
+    case PROP_SEEKPOINTS:
+      g_value_set_int (value, this->seekpoints);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  GST_OBJECT_UNLOCK (this);
+}
diff --git a/ext/flac/gstflacenc.h b/ext/flac/gstflacenc.h
new file mode 100644
index 0000000..11aec4e
--- /dev/null
+++ b/ext/flac/gstflacenc.h
@@ -0,0 +1,80 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_FLAC_ENC_H__
+#define __GST_FLAC_ENC_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudioencoder.h>
+
+#include <FLAC/all.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_FLAC_ENC (gst_flac_enc_get_type())
+#define GST_FLAC_ENC(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, GST_TYPE_FLAC_ENC, GstFlacEnc)
+#define GST_FLAC_ENC_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, GST_TYPE_FLAC_ENC, GstFlacEncClass)
+#define GST_IS_FLAC_ENC(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, GST_TYPE_FLAC_ENC)
+#define GST_IS_FLAC_ENC_CLASS(klass) G_TYPE_CHECK_CLASS_TYPE(klass, GST_TYPE_FLAC_ENC)
+
+typedef struct _GstFlacEnc GstFlacEnc;
+typedef struct _GstFlacEncClass GstFlacEncClass;
+
+struct _GstFlacEnc {
+  GstAudioEncoder  element;
+
+  /* < private > */
+
+  GstFlowReturn  last_flow; /* save flow from last push so we can pass the
+                             * correct flow return upstream in case the push
+                             * fails for some reason */
+
+  guint64        offset;
+  gint           quality;
+  gboolean       stopped;
+  guint           padding;
+  gint            seekpoints;
+
+  FLAC__StreamEncoder *encoder;
+
+  FLAC__StreamMetadata **meta;
+
+  GstTagList *     tags;
+  GstToc *         toc;
+
+  guint64          samples_in;
+  guint64          samples_out;
+  gboolean         eos;
+  /* queue headers until we have them all so we can add streamheaders to caps */
+  gboolean         got_headers;
+  GList           *headers;
+
+  gint             channel_reorder_map[8];
+};
+
+struct _GstFlacEncClass {
+  GstAudioEncoderClass parent_class;
+};
+
+GType gst_flac_enc_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_FLAC_ENC_H__ */
diff --git a/ext/flac/gstflactag.c b/ext/flac/gstflactag.c
new file mode 100644
index 0000000..e2e239f
--- /dev/null
+++ b/ext/flac/gstflactag.c
@@ -0,0 +1,501 @@
+/* GStreamer
+ * Copyright (C) 2003 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2008 Jonathan Matthew <jonathan@d14n.org>
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * gstflactag.c: plug-in for reading/modifying vorbis comments in flac files
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-flactag
+ * @see_also: #flacenc, #flacdec, #GstTagSetter
+ *
+ * The flactag element can change the tag contained within a raw
+ * FLAC stream. Specifically, it modifies the comments header packet
+ * of the FLAC stream.
+ *
+ * Applications can set the tags to write using the #GstTagSetter interface.
+ * Tags contained withing the FLAC bitstream will be picked up
+ * automatically (and merged according to the merge mode set via the tag
+ * setter interface).
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -v filesrc location=foo.flac ! flactag ! filesink location=bar.flac
+ * ]| This element is not useful with gst-launch, because it does not support
+ * setting the tags on a #GstTagSetter interface. Conceptually, the element
+ * will usually be used in this order though.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/gsttagsetter.h>
+#include <gst/base/gstadapter.h>
+#include <gst/tag/tag.h>
+#include <string.h>
+
+#include "gstflactag.h"
+
+GST_DEBUG_CATEGORY_STATIC (flactag_debug);
+#define GST_CAT_DEFAULT flactag_debug
+
+/* elementfactory information */
+static GstStaticPadTemplate flac_tag_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-flac")
+    );
+
+static GstStaticPadTemplate flac_tag_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-flac")
+    );
+
+
+static void gst_flac_tag_dispose (GObject * object);
+
+static GstFlowReturn gst_flac_tag_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer);
+
+static GstStateChangeReturn gst_flac_tag_change_state (GstElement * element,
+    GstStateChange transition);
+
+static gboolean gst_flac_tag_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+
+#define gst_flac_tag_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstFlacTag, gst_flac_tag, GST_TYPE_ELEMENT,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
+
+
+static void
+gst_flac_tag_class_init (GstFlacTagClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GObjectClass *gobject_class;
+
+  GST_DEBUG_CATEGORY_INIT (flactag_debug, "flactag", 0, "flac tag rewriter");
+
+  gstelement_class = (GstElementClass *) klass;
+  gobject_class = (GObjectClass *) klass;
+
+  gobject_class->dispose = gst_flac_tag_dispose;
+  gstelement_class->change_state = gst_flac_tag_change_state;
+
+  gst_element_class_set_static_metadata (gstelement_class, "FLAC tagger",
+      "Formatter/Metadata",
+      "Rewrite tags in a FLAC file", "Christophe Fergeau <teuf@gnome.org>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &flac_tag_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &flac_tag_src_template);
+}
+
+static void
+gst_flac_tag_dispose (GObject * object)
+{
+  GstFlacTag *tag = GST_FLAC_TAG (object);
+
+  if (tag->adapter) {
+    g_object_unref (tag->adapter);
+    tag->adapter = NULL;
+  }
+  if (tag->vorbiscomment) {
+    gst_buffer_unref (tag->vorbiscomment);
+    tag->vorbiscomment = NULL;
+  }
+  if (tag->tags) {
+    gst_tag_list_unref (tag->tags);
+    tag->tags = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+
+static void
+gst_flac_tag_init (GstFlacTag * tag)
+{
+  /* create the sink and src pads */
+  tag->sinkpad =
+      gst_pad_new_from_static_template (&flac_tag_sink_template, "sink");
+  gst_pad_set_chain_function (tag->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_flac_tag_chain));
+  gst_pad_set_event_function (tag->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_flac_tag_sink_event));
+  gst_element_add_pad (GST_ELEMENT (tag), tag->sinkpad);
+
+  tag->srcpad =
+      gst_pad_new_from_static_template (&flac_tag_src_template, "src");
+  gst_element_add_pad (GST_ELEMENT (tag), tag->srcpad);
+
+  tag->adapter = gst_adapter_new ();
+}
+
+static gboolean
+gst_flac_tag_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstFlacTag *tag;
+  gboolean ret;
+
+  tag = GST_FLAC_TAG (parent);
+
+  GST_DEBUG_OBJECT (pad, "Received %s event on sinkpad, %" GST_PTR_FORMAT,
+      GST_EVENT_TYPE_NAME (event), event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+      /* FIXME: parse and store the caps. Once we parsed and built the headers,
+       * update the "streamheader" field in the caps and send a new caps event
+       */
+      ret = gst_pad_push_event (tag->srcpad, event);
+      break;
+    default:
+      ret = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return ret;
+}
+
+#define FLAC_MAGIC "fLaC"
+#define FLAC_MAGIC_SIZE (sizeof (FLAC_MAGIC) - 1)
+
+static GstFlowReturn
+gst_flac_tag_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstFlacTag *tag;
+  GstFlowReturn ret;
+  GstMapInfo map;
+  gsize size;
+
+  ret = GST_FLOW_OK;
+  tag = GST_FLAC_TAG (parent);
+
+  gst_adapter_push (tag->adapter, buffer);
+
+  GST_LOG_OBJECT (pad, "state: %d", tag->state);
+
+  /* Initial state, we don't even know if we are dealing with a flac file */
+  if (tag->state == GST_FLAC_TAG_STATE_INIT) {
+    GstBuffer *id_buffer;
+
+    if (gst_adapter_available (tag->adapter) < sizeof (FLAC_MAGIC))
+      goto cleanup;
+
+    id_buffer = gst_adapter_take_buffer (tag->adapter, FLAC_MAGIC_SIZE);
+    GST_DEBUG_OBJECT (tag, "looking for " FLAC_MAGIC " identifier");
+    if (gst_buffer_memcmp (id_buffer, 0, FLAC_MAGIC, FLAC_MAGIC_SIZE) == 0) {
+
+      GST_DEBUG_OBJECT (tag, "pushing " FLAC_MAGIC " identifier buffer");
+      ret = gst_pad_push (tag->srcpad, id_buffer);
+      if (ret != GST_FLOW_OK)
+        goto cleanup;
+
+      tag->state = GST_FLAC_TAG_STATE_METADATA_BLOCKS;
+    } else {
+      /* FIXME: does that work well with FLAC files containing ID3v2 tags ? */
+      gst_buffer_unref (id_buffer);
+      GST_ELEMENT_ERROR (tag, STREAM, WRONG_TYPE, (NULL), (NULL));
+      ret = GST_FLOW_ERROR;
+    }
+  }
+
+
+  /* The fLaC magic string has been skipped, try to detect the beginning
+   * of a metadata block
+   */
+  if (tag->state == GST_FLAC_TAG_STATE_METADATA_BLOCKS) {
+    guint type;
+    gboolean is_last;
+    const guint8 *block_header;
+
+    g_assert (tag->metadata_block_size == 0);
+    g_assert (tag->metadata_last_block == FALSE);
+
+    /* The header of a flac metadata block is 4 bytes long:
+     * 1st bit: indicates whether this is the last metadata info block
+     * 7 next bits: 4 if vorbis comment block
+     * 24 next bits: size of the metadata to follow (big endian)
+     */
+    if (gst_adapter_available (tag->adapter) < 4)
+      goto cleanup;
+
+    block_header = gst_adapter_map (tag->adapter, 4);
+
+    is_last = ((block_header[0] & 0x80) == 0x80);
+    type = block_header[0] & 0x7F;
+    size = (block_header[1] << 16)
+        | (block_header[2] << 8)
+        | block_header[3];
+    gst_adapter_unmap (tag->adapter);
+
+    /* The 4 bytes long header isn't included in the metadata size */
+    tag->metadata_block_size = size + 4;
+    tag->metadata_last_block = is_last;
+
+    GST_DEBUG_OBJECT (tag,
+        "got metadata block: %" G_GSIZE_FORMAT " bytes, type %d, "
+        "is vorbiscomment: %d, is last: %d",
+        size, type, (type == 0x04), is_last);
+
+    /* Metadata blocks of type 4 are vorbis comment blocks */
+    if (type == 0x04) {
+      tag->state = GST_FLAC_TAG_STATE_VC_METADATA_BLOCK;
+    } else {
+      tag->state = GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK;
+    }
+  }
+
+
+  /* Reads a metadata block */
+  if ((tag->state == GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK) ||
+      (tag->state == GST_FLAC_TAG_STATE_VC_METADATA_BLOCK)) {
+    GstBuffer *metadata_buffer;
+
+    if (gst_adapter_available (tag->adapter) < tag->metadata_block_size)
+      goto cleanup;
+
+    metadata_buffer = gst_adapter_take_buffer (tag->adapter,
+        tag->metadata_block_size);
+    /* clear the is-last flag, as the last metadata block will
+     * be the vorbis comment block which we will build ourselves.
+     */
+    gst_buffer_map (metadata_buffer, &map, GST_MAP_READWRITE);
+    map.data[0] &= (~0x80);
+    gst_buffer_unmap (metadata_buffer, &map);
+
+    if (tag->state == GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK) {
+      GST_DEBUG_OBJECT (tag, "pushing metadata block buffer");
+      ret = gst_pad_push (tag->srcpad, metadata_buffer);
+      if (ret != GST_FLOW_OK)
+        goto cleanup;
+    } else {
+      tag->vorbiscomment = metadata_buffer;
+    }
+    tag->metadata_block_size = 0;
+    tag->state = GST_FLAC_TAG_STATE_METADATA_NEXT_BLOCK;
+  }
+
+  /* This state is mainly used to be able to stop as soon as we read
+   * a vorbiscomment block from the flac file if we are in an only output
+   * tags mode
+   */
+  if (tag->state == GST_FLAC_TAG_STATE_METADATA_NEXT_BLOCK) {
+    /* Check if in the previous iteration we read a vorbis comment metadata 
+     * block, and stop now if the user only wants to read tags
+     */
+    if (tag->vorbiscomment != NULL) {
+      guint8 id_data[4];
+      /* We found some tags, try to parse them and notify the other elements
+       * that we encountered some tags
+       */
+      GST_DEBUG_OBJECT (tag, "emitting vorbiscomment tags");
+      gst_buffer_extract (tag->vorbiscomment, 0, id_data, 4);
+      tag->tags = gst_tag_list_from_vorbiscomment_buffer (tag->vorbiscomment,
+          id_data, 4, NULL);
+      if (tag->tags != NULL) {
+        gst_pad_push_event (tag->srcpad,
+            gst_event_new_tag (gst_tag_list_ref (tag->tags)));
+      }
+
+      gst_buffer_unref (tag->vorbiscomment);
+      tag->vorbiscomment = NULL;
+    }
+
+    /* Skip to next state */
+    if (tag->metadata_last_block == FALSE) {
+      tag->state = GST_FLAC_TAG_STATE_METADATA_BLOCKS;
+    } else {
+      tag->state = GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT;
+    }
+  }
+
+
+  /* Creates a vorbis comment block from the metadata which was set
+   * on the gstreamer element, and add it to the flac stream
+   */
+  if (tag->state == GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT) {
+    GstBuffer *buffer;
+    const GstTagList *user_tags;
+    GstTagList *merged_tags;
+
+    /* merge the tag lists */
+    user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (tag));
+    if (user_tags != NULL) {
+      merged_tags = gst_tag_list_merge (user_tags, tag->tags,
+          gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (tag)));
+    } else {
+      merged_tags = gst_tag_list_copy (tag->tags);
+    }
+
+    if (merged_tags == NULL) {
+      /* If we get a NULL list of tags, we must generate a padding block
+       * which is marked as the last metadata block, otherwise we'll
+       * end up with a corrupted flac file.
+       */
+      GST_WARNING_OBJECT (tag, "No tags found");
+      buffer = gst_buffer_new_and_alloc (12);
+      if (buffer == NULL)
+        goto no_buffer;
+
+      gst_buffer_map (buffer, &map, GST_MAP_WRITE);
+      memset (map.data, 0, map.size);
+      map.data[0] = 0x81;       /* 0x80 = Last metadata block, 
+                                 * 0x01 = padding block */
+      gst_buffer_unmap (buffer, &map);
+    } else {
+      guchar header[4];
+      guint8 fbit[1];
+
+      memset (header, 0, sizeof (header));
+      header[0] = 0x84;         /* 0x80 = Last metadata block, 
+                                 * 0x04 = vorbiscomment block */
+      buffer = gst_tag_list_to_vorbiscomment_buffer (merged_tags, header,
+          sizeof (header), NULL);
+      GST_DEBUG_OBJECT (tag, "Writing tags %" GST_PTR_FORMAT, merged_tags);
+      gst_tag_list_unref (merged_tags);
+      if (buffer == NULL)
+        goto no_comment;
+
+      size = gst_buffer_get_size (buffer);
+      if ((size < 4) || ((size - 4) > 0xFFFFFF))
+        goto comment_too_long;
+
+      fbit[0] = 1;
+      /* Get rid of the framing bit at the end of the vorbiscomment buffer 
+       * if it exists since libFLAC seems to lose sync because of this
+       * bit in gstflacdec
+       */
+      if (gst_buffer_memcmp (buffer, size - 1, fbit, 1) == 0) {
+        buffer = gst_buffer_make_writable (buffer);
+        gst_buffer_resize (buffer, 0, size - 1);
+      }
+    }
+
+    /* The 4 byte metadata block header isn't accounted for in the total
+     * size of the metadata block
+     */
+    gst_buffer_map (buffer, &map, GST_MAP_WRITE);
+    map.data[1] = (((map.size - 4) & 0xFF0000) >> 16);
+    map.data[2] = (((map.size - 4) & 0x00FF00) >> 8);
+    map.data[3] = ((map.size - 4) & 0x0000FF);
+    gst_buffer_unmap (buffer, &map);
+
+    GST_DEBUG_OBJECT (tag, "pushing %" G_GSIZE_FORMAT " byte vorbiscomment "
+        "buffer", map.size);
+
+    ret = gst_pad_push (tag->srcpad, buffer);
+    if (ret != GST_FLOW_OK) {
+      goto cleanup;
+    }
+    tag->state = GST_FLAC_TAG_STATE_AUDIO_DATA;
+  }
+
+  /* The metadata blocks have been read, now we are reading audio data */
+  if (tag->state == GST_FLAC_TAG_STATE_AUDIO_DATA) {
+    GstBuffer *buffer;
+    guint avail;
+
+    avail = gst_adapter_available (tag->adapter);
+    if (avail > 0) {
+      buffer = gst_adapter_take_buffer (tag->adapter, avail);
+      ret = gst_pad_push (tag->srcpad, buffer);
+    }
+  }
+
+cleanup:
+  GST_LOG_OBJECT (pad, "state: %d, ret: %d", tag->state, ret);
+  return ret;
+
+  /* ERRORS */
+no_buffer:
+  {
+    GST_ELEMENT_ERROR (tag, CORE, TOO_LAZY, (NULL),
+        ("Error creating 12-byte buffer for padding block"));
+    ret = GST_FLOW_ERROR;
+    goto cleanup;
+  }
+no_comment:
+  {
+    GST_ELEMENT_ERROR (tag, CORE, TAG, (NULL),
+        ("Error converting tag list to vorbiscomment buffer"));
+    ret = GST_FLOW_ERROR;
+    goto cleanup;
+  }
+comment_too_long:
+  {
+    /* FLAC vorbis comment blocks are limited to 2^24 bytes, 
+     * while the vorbis specs allow more than that. Shouldn't 
+     * be a real world problem though
+     */
+    GST_ELEMENT_ERROR (tag, CORE, TAG, (NULL),
+        ("Vorbis comment of size %" G_GSIZE_FORMAT " too long", size));
+    ret = GST_FLOW_ERROR;
+    goto cleanup;
+  }
+}
+
+static GstStateChangeReturn
+gst_flac_tag_change_state (GstElement * element, GstStateChange transition)
+{
+  GstFlacTag *tag;
+
+  tag = GST_FLAC_TAG (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      /* do something to get out of the chain function faster */
+      break;
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_adapter_clear (tag->adapter);
+      if (tag->vorbiscomment) {
+        gst_buffer_unref (tag->vorbiscomment);
+        tag->vorbiscomment = NULL;
+      }
+      if (tag->tags) {
+        gst_tag_list_unref (tag->tags);
+        tag->tags = NULL;
+      }
+      tag->metadata_block_size = 0;
+      tag->metadata_last_block = FALSE;
+      tag->state = GST_FLAC_TAG_STATE_INIT;
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+}
diff --git a/ext/flac/gstflactag.h b/ext/flac/gstflactag.h
new file mode 100644
index 0000000..106541a
--- /dev/null
+++ b/ext/flac/gstflactag.h
@@ -0,0 +1,78 @@
+/* GStreamer
+ * Copyright (C) 2003 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2008 Jonathan Matthew <jonathan@d14n.org>
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * gstflactag.c: plug-in for reading/modifying vorbis comments in flac files
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GST_FLAC_TAG_H
+#define GST_FLAC_TAG_H
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+#define GST_TYPE_FLAC_TAG (gst_flac_tag_get_type())
+#define GST_FLAC_TAG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FLAC_TAG, GstFlacTag))
+#define GST_FLAC_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FLAC_TAG, GstFlacTag))
+#define GST_IS_FLAC_TAG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLAC_TAG))
+#define GST_IS_FLAC_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLAC_TAG))
+
+typedef struct _GstFlacTag GstFlacTag;
+typedef struct _GstFlacTagClass GstFlacTagClass;
+
+typedef enum
+{
+  GST_FLAC_TAG_STATE_INIT,
+  GST_FLAC_TAG_STATE_METADATA_BLOCKS,
+  GST_FLAC_TAG_STATE_METADATA_NEXT_BLOCK,
+  GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK,
+  GST_FLAC_TAG_STATE_VC_METADATA_BLOCK,
+  GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT,
+  GST_FLAC_TAG_STATE_AUDIO_DATA
+}
+GstFlacTagState;
+
+struct _GstFlacTag
+{
+  GstElement element;
+
+  /* < private > */
+
+  /* pads */
+  GstPad *sinkpad;
+  GstPad *srcpad;
+
+  GstFlacTagState state;
+
+  GstAdapter *adapter;
+  GstBuffer *vorbiscomment;
+  GstTagList *tags;
+
+  guint metadata_block_size;
+  gboolean metadata_last_block;
+};
+
+struct _GstFlacTagClass
+{
+  GstElementClass parent_class;
+};
+
+GType gst_flac_tag_get_type (void);
+
+#endif /* GST_FLAC_TAG_H */
diff --git a/ext/flac/meson.build b/ext/flac/meson.build
new file mode 100644
index 0000000..9b66d16
--- /dev/null
+++ b/ext/flac/meson.build
@@ -0,0 +1,20 @@
+flac_sources = [
+  'gstflac.c',
+  'gstflacdec.c',
+  'gstflacenc.c',
+  'gstflactag.c',
+]
+
+flac_dep = dependency('flac', version : '>=1.1.4', required : false)
+
+if flac_dep.found()
+  gstflac = library('gstflac',
+    flac_sources,
+    c_args : gst_plugins_good_args + ['-DGST_USE_UNSTABLE_API'],
+    link_args : noseh_link_args,
+    include_directories : [configinc, libsinc],
+    dependencies : [gstbase_dep, gsttag_dep, gstaudio_dep, flac_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/ext/gdk_pixbuf/Makefile.am b/ext/gdk_pixbuf/Makefile.am
new file mode 100644
index 0000000..5840086
--- /dev/null
+++ b/ext/gdk_pixbuf/Makefile.am
@@ -0,0 +1,26 @@
+plugin_LTLIBRARIES = libgstgdkpixbuf.la
+
+# gstgdkanimation.[ch] - GdkPixbuf animations decode everything from the start,
+# which means it's easy to make us go OOM with manipulated input, disabled
+
+libgstgdkpixbuf_la_SOURCES = \
+	gstgdkpixbufdec.c \
+	gstgdkpixbufoverlay.c \
+	gstgdkpixbufplugin.c \
+	gstgdkpixbufsink.c
+libgstgdkpixbuf_la_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_CONTROLLER_CFLAGS) \
+	$(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS) $(GDK_PIXBUF_CFLAGS)
+libgstgdkpixbuf_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) \
+	$(GST_CONTROLLER_LIBS) \
+	$(GST_BASE_LIBS) \
+	$(GST_LIBS) $(GDK_PIXBUF_LIBS)
+libgstgdkpixbuf_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = \
+	gstgdkpixbufdec.h \
+	gstgdkpixbufoverlay.h \
+	gstgdkpixbufsink.h
diff --git a/ext/gdk_pixbuf/gstgdkanimation.c b/ext/gdk_pixbuf/gstgdkanimation.c
new file mode 100644
index 0000000..42037fe
--- /dev/null
+++ b/ext/gdk_pixbuf/gstgdkanimation.c
@@ -0,0 +1,661 @@
+/*
+ * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstgdkanimation.h"
+#include <unistd.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_gdk_animation_debug);
+#define GST_CAT_DEFAULT gst_gdk_animation_debug
+
+static void gst_gdk_animation_class_init (gpointer g_class,
+    gpointer class_data);
+static void gst_gdk_animation_finalize (GObject * object);
+
+static gboolean gst_gdk_animation_is_static_image (GdkPixbufAnimation *
+    animation);
+static GdkPixbuf *gst_gdk_animation_get_static_image (GdkPixbufAnimation *
+    animation);
+static void gst_gdk_animation_get_size (GdkPixbufAnimation * anim, gint * width,
+    gint * height);
+static GdkPixbufAnimationIter *gst_gdk_animation_get_iter (GdkPixbufAnimation *
+    anim, const GTimeVal * start_time);
+
+
+static gpointer parent_class;
+
+GType
+gst_gdk_animation_get_type (void)
+{
+  static GType object_type = 0;
+
+  if (!object_type) {
+    static const GTypeInfo object_info = {
+      sizeof (GstGdkAnimationClass),
+      NULL,
+      NULL,
+      gst_gdk_animation_class_init,
+      NULL,                     /* class_finalize */
+      NULL,                     /* class_data */
+      sizeof (GstGdkAnimation),
+      0,                        /* n_preallocs */
+      NULL,
+    };
+
+    object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
+        "GstGdkAnimation", &object_info, 0);
+
+    GST_DEBUG_CATEGORY_INIT (gst_gdk_animation_debug, "gstloader_animation", 0,
+        "GStreamer GdkPixbuf loader - GdkAnimation class");
+  }
+
+  return object_type;
+}
+
+static void
+gst_gdk_animation_class_init (gpointer g_class, gpointer class_data)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (g_class);
+  GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (g_class);
+
+  parent_class = g_type_class_peek_parent (g_class);
+
+  object_class->finalize = gst_gdk_animation_finalize;
+
+  anim_class->is_static_image = gst_gdk_animation_is_static_image;
+  anim_class->get_static_image = gst_gdk_animation_get_static_image;
+  anim_class->get_size = gst_gdk_animation_get_size;
+  anim_class->get_iter = gst_gdk_animation_get_iter;
+}
+
+static void
+gst_gdk_animation_finalize (GObject * object)
+{
+  GstGdkAnimation *ani = GST_GDK_ANIMATION (object);
+
+  if (ani->temp_fd) {
+    close (ani->temp_fd);
+  }
+  if (ani->temp_location) {
+    remove (ani->temp_location);
+    g_free (ani->temp_location);
+  }
+  if (ani->pixbuf) {
+    g_object_unref (ani->pixbuf);
+    ani->pixbuf = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+GstGdkAnimation *
+gst_gdk_animation_new (GError ** error)
+{
+  GstGdkAnimation *ani =
+      GST_GDK_ANIMATION (g_object_new (GST_TYPE_GDK_ANIMATION, NULL));
+
+  return ani;
+}
+
+gboolean
+gst_gdk_animation_add_data (GstGdkAnimation * ani, const guint8 * data,
+    guint size)
+{
+  return (write (ani->temp_fd, data, size) == size);
+}
+
+void
+gst_gdk_animation_done_adding (GstGdkAnimation * ani)
+{
+  close (ani->temp_fd);
+  ani->temp_fd = 0;
+}
+
+static gboolean
+gst_gdk_animation_is_static_image (GdkPixbufAnimation * animation)
+{
+  return FALSE;
+}
+
+static void
+gst_gdk_animation_get_size (GdkPixbufAnimation * anim, gint * width,
+    int *height)
+{
+  GstGdkAnimation *ani = GST_GDK_ANIMATION (anim);
+
+  GST_LOG_OBJECT (ani, "get_size called (%p, %p) %d x %d", width, height,
+      ani->width, ani->height);
+  if (width)
+    *width = ani->width;
+
+  if (height)
+    *height = ani->height;
+}
+
+
+static void gst_gdk_animation_iter_class_init (gpointer g_class,
+    gpointer class_data);
+static void gst_gdk_animation_iter_init (GTypeInstance * instance,
+    gpointer g_class);
+static void gst_gdk_animation_iter_finalize (GObject * object);
+
+static gint gst_gdk_animation_iter_get_delay_time (GdkPixbufAnimationIter *
+    iter);
+static GdkPixbuf *gst_gdk_animation_iter_get_pixbuf (GdkPixbufAnimationIter *
+    iter);
+static gboolean
+gst_gdk_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *
+    iter);
+static gboolean gst_gdk_animation_iter_advance (GdkPixbufAnimationIter * iter,
+    const GTimeVal * current_time);
+
+static gpointer iter_parent_class;
+
+GType
+gst_gdk_animation_iter_get_type (void)
+{
+  static GType object_type = 0;
+
+  if (!object_type) {
+    static const GTypeInfo object_info = {
+      sizeof (GstGdkAnimationIterClass),
+      NULL,
+      NULL,
+      gst_gdk_animation_iter_class_init,
+      NULL,                     /* class_finalize */
+      NULL,                     /* class_data */
+      sizeof (GstGdkAnimationIter),
+      0,                        /* n_preallocs */
+      gst_gdk_animation_iter_init,
+    };
+
+    object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
+        "GdkPixbufAniAnimIter", &object_info, 0);
+  }
+
+  return object_type;
+}
+
+static void
+gst_gdk_animation_iter_class_init (gpointer g_class, gpointer class_data)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (g_class);
+  GdkPixbufAnimationIterClass *anim_iter_class =
+      GDK_PIXBUF_ANIMATION_ITER_CLASS (g_class);
+
+  iter_parent_class = g_type_class_peek_parent (g_class);
+
+  object_class->finalize = gst_gdk_animation_iter_finalize;
+
+  anim_iter_class->get_delay_time = gst_gdk_animation_iter_get_delay_time;
+  anim_iter_class->get_pixbuf = gst_gdk_animation_iter_get_pixbuf;
+  anim_iter_class->on_currently_loading_frame =
+      gst_gdk_animation_iter_on_currently_loading_frame;
+  anim_iter_class->advance = gst_gdk_animation_iter_advance;
+}
+
+static void
+gst_gdk_animation_iter_init (GTypeInstance * instance, gpointer g_class)
+{
+  GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (instance);
+
+  iter->buffers = g_queue_new ();
+  iter->eos = FALSE;
+}
+
+static void
+gst_gdk_animation_iter_finalize (GObject * object)
+{
+  GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (object);
+
+  g_object_unref (iter->ani);
+
+  if (iter->pipeline)
+    g_object_unref (iter->pipeline);
+  if (iter->pixbuf)
+    g_object_unref (iter->pixbuf);
+  while (iter->buffers) {
+    GstBuffer *buffer = GST_BUFFER (g_queue_pop_head (iter->buffers));
+
+    if (buffer) {
+      GST_LOG_OBJECT (iter, "unreffing buffer %p on finalize", buffer);
+      gst_data_unref (GST_DATA (buffer));
+    } else {
+      g_queue_free (iter->buffers);
+      iter->buffers = NULL;
+    }
+  }
+  G_OBJECT_CLASS (iter_parent_class)->finalize (object);
+}
+
+static void
+got_handoff (GstElement * fakesink, GstBuffer * buffer, GstPad * pad,
+    GstGdkAnimationIter * iter)
+{
+  GST_LOG_OBJECT (iter, "enqueing buffer %p (timestamp %" G_GUINT64_FORMAT ")",
+      buffer, GST_BUFFER_TIMESTAMP (buffer));
+  gst_data_ref (GST_DATA (buffer));
+  g_queue_push_tail (iter->buffers, buffer);
+}
+
+static gboolean
+gst_gdk_animation_iter_create_pipeline (GstGdkAnimationIter * iter)
+{
+  GstElement *src, *typefind, *autoplugger, *sink, *colorspace;
+  GstCaps *caps = GST_CAPS_NEW ("pixbuf_filter32",
+      "video/x-raw-rgb",
+      "endianness", GST_PROPS_INT (G_BIG_ENDIAN),
+      "bpp", GST_PROPS_INT (32),
+      "red_mask", GST_PROPS_INT (0xFF000000),
+      "green_mask", GST_PROPS_INT (0x00FF0000),
+      "blue_mask", GST_PROPS_INT (0x0000FF00)
+      );
+
+  gst_caps_append (caps, GST_CAPS_NEW ("pixbuf_filter24",
+          "video/x-raw-rgb",
+          "endianness", GST_PROPS_INT (G_BIG_ENDIAN),
+          "bpp", GST_PROPS_INT (24),
+          "red_mask", GST_PROPS_INT (0xFF0000),
+          "green_mask", GST_PROPS_INT (0x00FF00),
+          "blue_mask", GST_PROPS_INT (0x0000FF)
+      ));
+
+  iter->pipeline = gst_element_factory_make ("pipeline", "main_pipeline");
+  if (iter->pipeline == NULL)
+    return FALSE;
+
+  if (!(src = gst_element_factory_make ("filesrc", "source")))
+    goto error;
+  gst_bin_add (GST_BIN (iter->pipeline), src);
+  if (iter->ani->temp_location) {
+    g_object_set (src, "location", iter->ani->temp_location, NULL);
+    GST_INFO_OBJECT (iter, "using file '%s'", iter->ani->temp_location);
+  } else {
+    gchar *filename = g_strdup_printf ("/proc/self/fd/%d", iter->ani->temp_fd);
+
+    g_object_set (src, "location", filename, NULL);
+    GST_INFO_OBJECT (iter, "using file '%s'", filename);
+    g_free (filename);
+  }
+
+  /* add typefind for correct typefinding */
+  if ((typefind = gst_element_factory_make ("typefind", "typefind"))) {
+    gst_bin_add (GST_BIN (iter->pipeline), typefind);
+    if (!gst_element_link (src, typefind))
+      goto error;
+  }
+
+  if (!(autoplugger = gst_element_factory_make ("spider", "autoplugger")))
+    goto error;
+  gst_bin_add (GST_BIN (iter->pipeline), autoplugger);
+  if (!gst_element_link (typefind, autoplugger))
+    goto error;
+
+  /* try ffcolorspace if available so we get svq1, too */
+  colorspace = gst_element_factory_make ("ffcolorspace", "ffcolorspace");
+  if (!colorspace)
+    colorspace = gst_element_factory_make ("colorspace", "colorspace");
+  if (!colorspace)
+    goto error;
+  gst_bin_add (GST_BIN (iter->pipeline), colorspace);
+  if (!gst_element_link (autoplugger, colorspace))
+    goto error;
+
+  if (!(sink = gst_element_factory_make ("fakesink", "sink")))
+    goto error;
+  g_object_set (sink, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (sink, "handoff", (GCallback) got_handoff, iter);
+  gst_bin_add (GST_BIN (iter->pipeline), sink);
+  if (!gst_element_link_filtered (colorspace, sink, caps))
+    goto error;
+  if (gst_element_set_state (iter->pipeline,
+          GST_STATE_PLAYING) != GST_STATE_CHANGE_SUCCESS)
+    goto error;
+
+  return TRUE;
+error:
+  g_object_unref (iter->pipeline);
+  iter->pipeline = NULL;
+  return FALSE;
+}
+
+static gboolean
+gst_gdk_animation_iter_may_advance (GstGdkAnimationIter * iter)
+{
+  GstFormat bytes = GST_FORMAT_BYTES;
+  gint64 offset;
+  gint64 data_amount;
+
+  if (iter->ani->temp_fd == 0 || iter->ani->temp_location == NULL)
+    return TRUE;
+
+  data_amount = lseek (iter->ani->temp_fd, 0, SEEK_CUR);
+  g_assert (data_amount >= 0);
+  if (!gst_element_query (gst_bin_get_by_name (GST_BIN (iter->pipeline),
+              "source"), GST_QUERY_POSITION, &bytes, &offset))
+    g_assert_not_reached ();
+  if (data_amount - offset > GST_GDK_BUFFER_SIZE)
+    return TRUE;
+
+  return FALSE;
+}
+
+static gboolean
+gst_gdk_animation_get_more_buffers (GstGdkAnimationIter * iter)
+{
+  GstBuffer *last = g_queue_peek_tail (iter->buffers);
+
+  do {
+    GST_LOG_OBJECT (iter, "iterating...");
+    if (!gst_gdk_animation_iter_may_advance (iter)) {
+      GST_LOG_OBJECT (iter, "no more data available");
+      break;
+    }
+    if (!gst_bin_iterate (GST_BIN (iter->pipeline))) {
+      GST_LOG_OBJECT (iter, "iterating done, setting EOS");
+      iter->eos = TRUE;
+      break;
+    }
+  } while (last == g_queue_peek_tail (iter->buffers));
+  return last != g_queue_peek_tail (iter->buffers);
+}
+
+static void
+pixbuf_destroy_notify (guchar * pixels, gpointer data)
+{
+  GST_LOG ("unreffing buffer %p because pixbuf was destroyed", data);
+  gst_data_unref (GST_DATA (data));
+}
+
+static void
+gst_gdk_animation_iter_create_pixbuf (GstGdkAnimationIter * iter)
+{
+  GstBuffer *buf;
+  GstGdkAnimation *ani = iter->ani;
+
+  buf = g_queue_pop_head (iter->buffers);
+  g_assert (buf);
+  if (iter->pixbuf) {
+    GST_LOG_OBJECT (iter, "unreffing pixbuf %p", iter->pixbuf);
+    g_object_unref (iter->pixbuf);
+  }
+  if (ani->width == 0) {
+    GstPad *pad;
+    GstCaps *caps;
+    GstElement *fakesink =
+        gst_bin_get_by_name (GST_BIN (iter->pipeline), "sink");
+    g_assert (fakesink);
+    pad = gst_element_get_pad (fakesink, "sink");
+    g_assert (pad);
+    caps = gst_pad_get_negotiated_caps (pad);
+    g_assert (caps);
+    g_assert (GST_CAPS_IS_FIXED (caps));
+    g_assert (gst_caps_has_fixed_property (caps, "bpp") &&
+        gst_caps_has_fixed_property (caps, "width") &&
+        gst_caps_has_fixed_property (caps, "height"));
+    gst_caps_get_int (caps, "width", &ani->width);
+    gst_caps_get_int (caps, "height", &ani->height);
+    gst_caps_get_int (caps, "bpp", &ani->bpp);
+    GST_DEBUG_OBJECT (ani, "found format (width %d, height %d, bpp %d)",
+        ani->width, ani->height, ani->bpp);
+  }
+  g_assert (GST_BUFFER_SIZE (buf) == ani->width * ani->height * ani->bpp / 8);
+  if (ani->bpp == 32) {
+    gint i;
+    guint32 *data = (guint32 *) GST_BUFFER_DATA (buf);
+
+    /* ensure opacity */
+    for (i = 0; i < ani->width * ani->height; i++) {
+      data[i] |= 0xFF000000;
+    }
+  }
+  iter->pixbuf = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buf),
+      GDK_COLORSPACE_RGB, ani->bpp == 32, 8, ani->width, ani->height,
+      ani->width * ani->bpp / 8, pixbuf_destroy_notify, buf);
+  GST_LOG_OBJECT (iter, "created pixbuf %p from buffer %p (refcount %d)",
+      iter->pixbuf, buf, GST_DATA_REFCOUNT_VALUE (buf));
+}
+
+static GdkPixbufAnimationIter *
+gst_gdk_animation_get_iter (GdkPixbufAnimation * anim,
+    const GTimeVal * start_time)
+{
+  GstGdkAnimation *ani = GST_GDK_ANIMATION (anim);
+  GstGdkAnimationIter *iter;
+
+  if (ani->temp_fd != 0 && ani->temp_location != NULL &&
+      lseek (ani->temp_fd, 0, SEEK_CUR) < GST_GDK_BUFFER_SIZE) {
+    GST_DEBUG_OBJECT (ani, "Not enough data to create iterator.");
+    return NULL;
+  }
+
+  iter = g_object_new (GST_TYPE_GDK_ANIMATION_ITER, NULL);
+
+  iter->start = *start_time;
+
+  iter->ani = ani;
+  g_object_ref (ani);
+  if (!gst_gdk_animation_iter_create_pipeline (iter))
+    goto error;
+
+  if (!gst_gdk_animation_get_more_buffers (iter))
+    goto error;
+
+  gst_gdk_animation_iter_create_pixbuf (iter);
+
+  return GDK_PIXBUF_ANIMATION_ITER (iter);
+
+error:
+  g_object_unref (iter);
+  return NULL;
+}
+
+static gboolean
+gst_gdk_animation_iter_advance (GdkPixbufAnimationIter * anim_iter,
+    const GTimeVal * current_time)
+{
+  GstClockTime offset;
+  GstBuffer *buffer = NULL;
+  GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (anim_iter);
+
+  /* compute timestamp that next buffer must match */
+  offset =
+      ((GstClockTime) current_time->tv_sec - iter->start.tv_sec) * GST_SECOND;
+  if (iter->start.tv_usec > current_time->tv_usec) {
+    offset -=
+        ((GstClockTime) iter->start.tv_usec -
+        current_time->tv_usec) * GST_SECOND / G_USEC_PER_SEC;
+  } else {
+    offset +=
+        ((GstClockTime) current_time->tv_usec -
+        iter->start.tv_usec) * GST_SECOND / G_USEC_PER_SEC;
+  }
+  GST_DEBUG_OBJECT (iter,
+      "advancing to %ld:%ld (started at %ld:%ld) need offset %"
+      G_GUINT64_FORMAT, current_time->tv_sec, current_time->tv_usec,
+      iter->start.tv_sec, iter->start.tv_usec, offset);
+  if (!iter->just_seeked
+      && offset - iter->last_timestamp > GST_GDK_MAX_DELAY_TO_SEEK) {
+    GST_INFO_OBJECT (iter,
+        "current pipeline timestamp is too old (%" G_GUINT64_FORMAT " vs %"
+        G_GUINT64_FORMAT "), seeking there", iter->last_timestamp, offset);
+    if (gst_element_send_event (gst_bin_get_by_name (GST_BIN (iter->pipeline),
+                "sink"),
+            gst_event_new_seek (GST_FORMAT_TIME | GST_SEEK_METHOD_SET |
+                GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, offset))) {
+      iter->last_timestamp = offset;
+      iter->just_seeked = TRUE;
+    } else {
+      GST_WARNING_OBJECT (iter,
+          "seek to %" G_GUINT64_FORMAT " didn't work. Iterating there...",
+          offset);
+    }
+  } else if (iter->just_seeked) {
+    iter->just_seeked = FALSE;
+  }
+
+  while (TRUE) {
+    if (g_queue_is_empty (iter->buffers)) {
+      if (iter->eos)
+        return FALSE;
+      if (gst_gdk_animation_get_more_buffers (iter))
+        continue;
+      break;
+    }
+    if (GST_BUFFER_TIMESTAMP (g_queue_peek_head (iter->buffers)) > offset)
+      break;
+    if (buffer) {
+      GST_LOG_OBJECT (iter, "unreffing buffer %p, because timestamp too low (%"
+          G_GUINT64_FORMAT " vs %" G_GUINT64_FORMAT ")",
+          buffer, GST_BUFFER_TIMESTAMP (buffer), offset);
+      gst_data_unref (GST_DATA (buffer));
+    }
+    buffer = GST_BUFFER (g_queue_pop_head (iter->buffers));
+  }
+  if (!buffer)
+    return FALSE;
+  if (GST_BUFFER_TIMESTAMP (buffer) < iter->last_timestamp) {
+    gst_data_unref (GST_DATA (buffer));
+    iter->last_timestamp = offset;
+    return FALSE;
+  }
+  iter->last_timestamp = GST_BUFFER_TIMESTAMP (buffer);
+  g_queue_push_head (iter->buffers, buffer);
+  gst_gdk_animation_iter_create_pixbuf (iter);
+  return TRUE;
+}
+
+static gint
+gst_gdk_animation_iter_get_delay_time (GdkPixbufAnimationIter * anim_iter)
+{
+  gint delay;
+  GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (anim_iter);
+
+  while (g_queue_is_empty (iter->buffers)) {
+    if (iter->eos) {
+      GST_LOG_OBJECT (iter, "returning delay of infinite, we're EOS");
+      return -1;
+    }
+    if (!gst_gdk_animation_get_more_buffers (iter))
+      return -1;                /* FIXME? */
+  }
+
+  delay =
+      (GST_BUFFER_TIMESTAMP (g_queue_peek_head (iter->buffers)) -
+      iter->last_timestamp) * 1000 / GST_SECOND;
+  GST_LOG_OBJECT (iter, "returning delay of %d ms", delay);
+  return delay;
+}
+
+GdkPixbuf *
+gst_gdk_animation_iter_get_pixbuf (GdkPixbufAnimationIter * anim_iter)
+{
+  GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (anim_iter);
+
+  GST_LOG_OBJECT (iter, "returning pixbuf %p", iter->pixbuf);
+  return iter->pixbuf;
+}
+
+static gboolean
+gst_gdk_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *
+    anim_iter)
+{
+  GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (anim_iter);
+
+  /* EOS - last frame */
+  if (iter->eos && g_queue_is_empty (iter->buffers))
+    return TRUE;
+
+  /* can't load more frames */
+  if (!gst_gdk_animation_iter_may_advance (iter))
+    return FALSE;
+
+  return TRUE;
+}
+
+static GdkPixbuf *
+gst_gdk_animation_get_static_image (GdkPixbufAnimation * animation)
+{
+  GstGdkAnimation *ani = GST_GDK_ANIMATION (animation);
+  GTimeVal tv;
+  GstGdkAnimationIter *iter;
+
+  if (!ani->pixbuf) {
+    GST_LOG_OBJECT (ani, "trying to create pixbuf");
+    g_get_current_time (&tv);
+    iter =
+        GST_GDK_ANIMATION_ITER (gdk_pixbuf_animation_get_iter (animation, &tv));
+    if (iter) {
+      guint64 offset;
+      GstBuffer *buf;
+      GstFormat time = GST_FORMAT_TIME;
+
+      if (!gst_element_query (gst_bin_get_by_name (GST_BIN (iter->pipeline),
+                  "sink"), GST_QUERY_TOTAL, &time, &offset)) {
+        offset = 0;
+      }
+      if (offset > 120 * GST_SECOND) {
+        offset = 120 * GST_SECOND;
+      } else if (offset < 120 * GST_SECOND && offset >= 10 * GST_SECOND) {
+        offset = offset / 2;
+      }
+      g_assert (time == GST_FORMAT_TIME);
+      GST_LOG_OBJECT (ani,
+          "using time offset %" G_GUINT64_FORMAT " for creating static image",
+          offset);
+      while ((buf = g_queue_pop_head (iter->buffers)) != NULL) {
+        gst_data_unref (GST_DATA (buf));
+      }
+      /* now we do evil stuff, be sure to get rid of the iterator afterwards */
+      if (!gst_element_send_event (gst_bin_get_by_name (GST_BIN
+                  (iter->pipeline), "sink"),
+              gst_event_new_seek (GST_FORMAT_TIME | GST_SEEK_METHOD_SET |
+                  GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, offset))) {
+        GST_INFO_OBJECT (ani, "seeking didn't work. Using next image");
+      }
+
+      do {
+        if (g_queue_is_empty (iter->buffers)) {
+          if (iter->eos)
+            return FALSE;
+          if (gst_gdk_animation_get_more_buffers (iter))
+            continue;
+        }
+      } while (FALSE);
+      if (!g_queue_is_empty (iter->buffers)) {
+        gst_gdk_animation_iter_create_pixbuf (iter);
+        ani->pixbuf =
+            gst_gdk_animation_iter_get_pixbuf (GDK_PIXBUF_ANIMATION_ITER
+            (iter));
+        g_object_ref (ani->pixbuf);
+      } else {
+        g_assert (ani->pixbuf == NULL);
+      }
+      /* DiE iterator, DiE */
+      g_object_unref (iter);
+    } else {
+      GST_DEBUG_OBJECT (ani, "Could not get an iterator. No pixbuf available");
+    }
+  }
+  GST_LOG_OBJECT (ani, "Returning pixbuf %p\n", ani->pixbuf);
+  return ani->pixbuf;
+}
diff --git a/ext/gdk_pixbuf/gstgdkanimation.h b/ext/gdk_pixbuf/gstgdkanimation.h
new file mode 100644
index 0000000..c5584dc
--- /dev/null
+++ b/ext/gdk_pixbuf/gstgdkanimation.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_LOADER_H__
+#define __GST_LOADER_H__
+
+#include <gst/gst.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk-pixbuf/gdk-pixbuf-animation.h>
+#include <gdk-pixbuf/gdk-pixbuf-io.h>
+#include <stdio.h>
+
+G_BEGIN_DECLS
+
+/* how many bytes we need to have available before we dare to start a new iteration */
+#define GST_GDK_BUFFER_SIZE (102400)
+/* how far behind we need to be before we attempt to seek */
+#define GST_GDK_MAX_DELAY_TO_SEEK (GST_SECOND / 4)
+
+
+#define GST_TYPE_GDK_ANIMATION                  (gst_gdk_animation_get_type())
+#define GST_GDK_ANIMATION(obj)                  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GDK_ANIMATION,GstGdkAnimation))
+#define GST_GDK_ANIMATION_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GDK_ANIMATION,GstGdkAnimationClass))
+#define GST_IS_GDK_ANIMATION(obj)               (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GDK_ANIMATION))
+#define GST_IS_GDK_ANIMATION_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GDK_ANIMATION))
+
+typedef struct _GstGdkAnimation      GstGdkAnimation;
+typedef struct _GstGdkAnimationClass GstGdkAnimationClass;
+
+typedef struct _GstGdkAnimationIter GstGdkAnimationIter;
+typedef struct _GstGdkAnimationIterClass GstGdkAnimationIterClass;
+
+struct _GstGdkAnimation
+{
+  GdkPixbufAnimation            parent;
+
+  /* name of temporary buffer file */
+  gchar *                       temp_location;
+  /* file descriptor to temporary file or 0 if we're done writing */
+  int                           temp_fd;
+
+  /* size of image */
+  gint                          width;
+  gint                          height;
+  gint                          bpp;
+  /* static image we use */
+  GdkPixbuf *                   pixbuf;
+};
+
+struct _GstGdkAnimationClass 
+{
+  GdkPixbufAnimationClass       parent_class;
+};
+
+GType                   gst_gdk_animation_get_type      (void);
+
+GstGdkAnimation *       gst_gdk_animation_new           (GError **error);
+
+gboolean                gst_gdk_animation_add_data      (GstGdkAnimation *      ani,
+                                                         const guint8 *         data,
+                                                         guint                  size);
+void                    gst_gdk_animation_done_adding   (GstGdkAnimation *      ani);
+
+
+#define GST_TYPE_GDK_ANIMATION_ITER             (gst_gdk_animation_iter_get_type ())
+#define GST_GDK_ANIMATION_ITER(object)          (G_TYPE_CHECK_INSTANCE_CAST ((object), GST_TYPE_GDK_ANIMATION_ITER, GstGdkAnimationIter))
+#define GST_IS_GDK_ANIMATION_ITER(object)       (G_TYPE_CHECK_INSTANCE_TYPE ((object), GST_TYPE_GDK_ANIMATION_ITER))
+
+#define GST_GDK_ANIMATION_ITER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GDK_ANIMATION_ITER, GstGdkAnimationIterClass))
+#define GST_IS_GDK_ANIMATION_ITER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GDK_ANIMATION_ITER))
+#define GST_GDK_ANIMATION_ITER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_GDK_ANIMATION_ITER, GstGdkAnimationIterClass))
+
+struct _GstGdkAnimationIter {
+  GdkPixbufAnimationIter        parent;
+        
+  /* our animation */
+  GstGdkAnimation *             ani;
+  /* start timeval */
+  GTimeVal                      start;
+  /* timestamp of last buffer */
+  GstClockTime                  last_timestamp;
+  
+  /* pipeline we're using */
+  GstElement *                  pipeline;
+  gboolean                      eos;
+  gboolean                      just_seeked;
+  
+  /* current image and the buffers containing the data */
+  GdkPixbuf *                   pixbuf;
+  GQueue *                      buffers;
+};
+
+struct _GstGdkAnimationIterClass {
+  GdkPixbufAnimationIterClass   parent_class;
+};
+
+GType gst_gdk_animation_iter_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GST_GDK_ANIMATION_H__ */
diff --git a/ext/gdk_pixbuf/gstgdkpixbufdec.c b/ext/gdk_pixbuf/gstgdkpixbufdec.c
new file mode 100644
index 0000000..09211bf
--- /dev/null
+++ b/ext/gdk_pixbuf/gstgdkpixbufdec.c
@@ -0,0 +1,562 @@
+/* GStreamer GdkPixbuf-based image decoder
+ * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2003 David A. Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <string.h>
+
+#include "gstgdkpixbufdec.h"
+
+GST_DEBUG_CATEGORY_STATIC (gdkpixbufdec_debug);
+#define GST_CAT_DEFAULT gdkpixbufdec_debug
+
+static GstStaticPadTemplate gst_gdk_pixbuf_dec_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("image/png; "
+        /* "image/jpeg; " disabled because we can't handle MJPEG */
+        /*"image/gif; " disabled because we can't handle animated gifs */
+        "image/x-icon; "
+        "application/x-navi-animation; "
+        "image/x-cmu-raster; "
+        "image/x-sun-raster; "
+        "image/x-pixmap; "
+        "image/tiff; "
+        "image/x-portable-anymap; "
+        "image/x-portable-bitmap; "
+        "image/x-portable-graymap; "
+        "image/x-portable-pixmap; "
+        "image/bmp; "
+        "image/x-bmp; "
+        "image/x-MS-bmp; "
+        "image/vnd.wap.wbmp; " "image/x-bitmap; " "image/x-tga; "
+        "image/x-pcx; image/svg; image/svg+xml")
+    );
+
+static GstStaticPadTemplate gst_gdk_pixbuf_dec_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB") "; "
+        GST_VIDEO_CAPS_MAKE ("RGBA"))
+    );
+
+static GstStateChangeReturn
+gst_gdk_pixbuf_dec_change_state (GstElement * element,
+    GstStateChange transition);
+static GstFlowReturn gst_gdk_pixbuf_dec_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer);
+static gboolean gst_gdk_pixbuf_dec_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+
+#define gst_gdk_pixbuf_dec_parent_class parent_class
+G_DEFINE_TYPE (GstGdkPixbufDec, gst_gdk_pixbuf_dec, GST_TYPE_ELEMENT);
+
+static gboolean
+gst_gdk_pixbuf_dec_sink_setcaps (GstGdkPixbufDec * filter, GstCaps * caps)
+{
+  const GValue *framerate;
+  GstStructure *s;
+
+  s = gst_caps_get_structure (caps, 0);
+
+  if ((framerate = gst_structure_get_value (s, "framerate")) != NULL) {
+    filter->in_fps_n = gst_value_get_fraction_numerator (framerate);
+    filter->in_fps_d = gst_value_get_fraction_denominator (framerate);
+    GST_DEBUG_OBJECT (filter, "got framerate of %d/%d fps => packetized mode",
+        filter->in_fps_n, filter->in_fps_d);
+  } else {
+    filter->in_fps_n = 0;
+    filter->in_fps_d = 1;
+    GST_DEBUG_OBJECT (filter, "no framerate, assuming single image");
+  }
+
+  return TRUE;
+}
+
+static GstCaps *
+gst_gdk_pixbuf_dec_get_capslist (GstCaps * filter)
+{
+  GSList *slist;
+  GSList *slist0;
+  GstCaps *capslist = NULL;
+  GstCaps *return_caps = NULL;
+  GstCaps *tmpl_caps;
+
+  capslist = gst_caps_new_empty ();
+  slist0 = gdk_pixbuf_get_formats ();
+
+  for (slist = slist0; slist; slist = g_slist_next (slist)) {
+    GdkPixbufFormat *pixbuf_format;
+    char **mimetypes;
+    char **mimetype;
+
+    pixbuf_format = slist->data;
+    mimetypes = gdk_pixbuf_format_get_mime_types (pixbuf_format);
+
+    for (mimetype = mimetypes; *mimetype; mimetype++) {
+      gst_caps_append_structure (capslist, gst_structure_new_empty (*mimetype));
+    }
+    g_strfreev (mimetypes);
+  }
+  g_slist_free (slist0);
+
+  tmpl_caps =
+      gst_static_caps_get (&gst_gdk_pixbuf_dec_sink_template.static_caps);
+  return_caps = gst_caps_intersect (capslist, tmpl_caps);
+
+  gst_caps_unref (tmpl_caps);
+  gst_caps_unref (capslist);
+
+  if (filter && return_caps) {
+    GstCaps *temp;
+
+    temp = gst_caps_intersect (return_caps, filter);
+    gst_caps_unref (return_caps);
+    return_caps = temp;
+  }
+
+  return return_caps;
+}
+
+static gboolean
+gst_gdk_pixbuf_dec_sink_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  gboolean res;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *filter, *caps;
+
+      gst_query_parse_caps (query, &filter);
+      caps = gst_gdk_pixbuf_dec_get_capslist (filter);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+
+      res = TRUE;
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+  return res;
+}
+
+
+/* initialize the plugin's class */
+static void
+gst_gdk_pixbuf_dec_class_init (GstGdkPixbufDecClass * klass)
+{
+  GstElementClass *gstelement_class;
+
+  gstelement_class = (GstElementClass *) klass;
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_dec_change_state);
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_gdk_pixbuf_dec_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_gdk_pixbuf_dec_sink_template);
+  gst_element_class_set_static_metadata (gstelement_class,
+      "GdkPixbuf image decoder", "Codec/Decoder/Image",
+      "Decodes images in a video stream using GdkPixbuf",
+      "David A. Schleef <ds@schleef.org>, Renato Filho <renato.filho@indt.org.br>");
+
+  GST_DEBUG_CATEGORY_INIT (gdkpixbufdec_debug, "gdkpixbuf", 0,
+      "GdkPixbuf image decoder");
+}
+
+static void
+gst_gdk_pixbuf_dec_init (GstGdkPixbufDec * filter)
+{
+  filter->sinkpad =
+      gst_pad_new_from_static_template (&gst_gdk_pixbuf_dec_sink_template,
+      "sink");
+  gst_pad_set_query_function (filter->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_dec_sink_query));
+  gst_pad_set_chain_function (filter->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_dec_chain));
+  gst_pad_set_event_function (filter->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_dec_sink_event));
+  gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
+
+  filter->srcpad =
+      gst_pad_new_from_static_template (&gst_gdk_pixbuf_dec_src_template,
+      "src");
+  gst_pad_use_fixed_caps (filter->srcpad);
+  gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
+
+  filter->last_timestamp = GST_CLOCK_TIME_NONE;
+  filter->pixbuf_loader = NULL;
+  filter->packetized = FALSE;
+}
+
+static gboolean
+gst_gdk_pixbuf_dec_setup_pool (GstGdkPixbufDec * filter, GstVideoInfo * info)
+{
+  GstCaps *target;
+  GstQuery *query;
+  GstBufferPool *pool;
+  GstStructure *config;
+  guint size, min, max;
+
+  target = gst_pad_get_current_caps (filter->srcpad);
+  if (!target)
+    return FALSE;
+
+  /* try to get a bufferpool now */
+  /* find a pool for the negotiated caps now */
+  query = gst_query_new_allocation (target, TRUE);
+
+  if (!gst_pad_peer_query (filter->srcpad, query)) {
+    /* not a problem, we use the query defaults */
+    GST_DEBUG_OBJECT (filter, "ALLOCATION query failed");
+  }
+
+  if (gst_query_get_n_allocation_pools (query) > 0) {
+    /* we got configuration from our peer, parse them */
+    gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
+  } else {
+    pool = NULL;
+    size = info->size;
+    min = max = 0;
+  }
+
+  gst_query_unref (query);
+
+  if (pool == NULL) {
+    /* we did not get a pool, make one ourselves then */
+    pool = gst_buffer_pool_new ();
+  }
+
+  /* and configure */
+  config = gst_buffer_pool_get_config (pool);
+  gst_buffer_pool_config_set_params (config, target, size, min, max);
+  gst_buffer_pool_set_config (pool, config);
+
+  if (filter->pool) {
+    gst_buffer_pool_set_active (filter->pool, FALSE);
+    gst_object_unref (filter->pool);
+  }
+  filter->pool = pool;
+
+  /* and activate */
+  gst_buffer_pool_set_active (filter->pool, TRUE);
+
+  gst_caps_unref (target);
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_gdk_pixbuf_dec_flush (GstGdkPixbufDec * filter)
+{
+  GstBuffer *outbuf;
+  GdkPixbuf *pixbuf;
+  int y;
+  guint8 *out_pix;
+  guint8 *in_pix;
+  int in_rowstride, out_rowstride;
+  GstFlowReturn ret;
+  GstCaps *caps = NULL;
+  gint width, height;
+  gint n_channels;
+  GstVideoFrame frame;
+
+  pixbuf = gdk_pixbuf_loader_get_pixbuf (filter->pixbuf_loader);
+  if (pixbuf == NULL)
+    goto no_pixbuf;
+
+  width = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
+
+  if (GST_VIDEO_INFO_FORMAT (&filter->info) == GST_VIDEO_FORMAT_UNKNOWN) {
+    GstVideoInfo info;
+    GstVideoFormat fmt;
+    GList *l;
+
+    GST_DEBUG ("Set size to %dx%d", width, height);
+
+    n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+    switch (n_channels) {
+      case 3:
+        fmt = GST_VIDEO_FORMAT_RGB;
+        break;
+      case 4:
+        fmt = GST_VIDEO_FORMAT_RGBA;
+        break;
+      default:
+        goto channels_not_supported;
+    }
+
+
+    gst_video_info_init (&info);
+    gst_video_info_set_format (&info, fmt, width, height);
+    info.fps_n = filter->in_fps_n;
+    info.fps_d = filter->in_fps_d;
+    caps = gst_video_info_to_caps (&info);
+
+    filter->info = info;
+
+    gst_pad_set_caps (filter->srcpad, caps);
+    gst_caps_unref (caps);
+
+    gst_gdk_pixbuf_dec_setup_pool (filter, &info);
+
+    for (l = filter->pending_events; l; l = l->next)
+      gst_pad_push_event (filter->srcpad, l->data);
+    g_list_free (filter->pending_events);
+    filter->pending_events = NULL;
+  }
+
+  ret = gst_buffer_pool_acquire_buffer (filter->pool, &outbuf, NULL);
+  if (ret != GST_FLOW_OK)
+    goto no_buffer;
+
+  GST_BUFFER_TIMESTAMP (outbuf) = filter->last_timestamp;
+  GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
+
+  in_pix = gdk_pixbuf_get_pixels (pixbuf);
+  in_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+
+  gst_video_frame_map (&frame, &filter->info, outbuf, GST_MAP_WRITE);
+  out_pix = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0);
+  out_rowstride = GST_VIDEO_FRAME_PLANE_STRIDE (&frame, 0);
+
+  for (y = 0; y < height; y++) {
+    memcpy (out_pix, in_pix, width * GST_VIDEO_FRAME_COMP_PSTRIDE (&frame, 0));
+    in_pix += in_rowstride;
+    out_pix += out_rowstride;
+  }
+
+  gst_video_frame_unmap (&frame);
+
+  GST_DEBUG ("pushing... %" G_GSIZE_FORMAT " bytes",
+      gst_buffer_get_size (outbuf));
+  ret = gst_pad_push (filter->srcpad, outbuf);
+
+  if (ret != GST_FLOW_OK)
+    GST_DEBUG_OBJECT (filter, "flow: %s", gst_flow_get_name (ret));
+
+  return ret;
+
+  /* ERRORS */
+no_pixbuf:
+  {
+    GST_ELEMENT_ERROR (filter, STREAM, DECODE, (NULL), ("error geting pixbuf"));
+    return GST_FLOW_ERROR;
+  }
+channels_not_supported:
+  {
+    GST_ELEMENT_ERROR (filter, STREAM, DECODE, (NULL),
+        ("%d channels not supported", n_channels));
+    return GST_FLOW_ERROR;
+  }
+no_buffer:
+  {
+    GST_DEBUG ("Failed to create outbuffer - %s", gst_flow_get_name (ret));
+    return ret;
+  }
+}
+
+static gboolean
+gst_gdk_pixbuf_dec_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstFlowReturn res = GST_FLOW_OK;
+  gboolean ret = TRUE, forward = TRUE;
+  GstGdkPixbufDec *pixbuf;
+
+  pixbuf = GST_GDK_PIXBUF_DEC (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      ret = gst_gdk_pixbuf_dec_sink_setcaps (pixbuf, caps);
+      forward = FALSE;
+      break;
+    }
+    case GST_EVENT_EOS:
+      if (pixbuf->pixbuf_loader != NULL) {
+        gdk_pixbuf_loader_close (pixbuf->pixbuf_loader, NULL);
+        res = gst_gdk_pixbuf_dec_flush (pixbuf);
+        g_object_unref (G_OBJECT (pixbuf->pixbuf_loader));
+        pixbuf->pixbuf_loader = NULL;
+        /* as long as we don't have flow returns for event functions we need
+         * to post an error here, or the application might never know that
+         * things failed */
+        if (res != GST_FLOW_OK && res != GST_FLOW_FLUSHING
+            && res != GST_FLOW_EOS && res != GST_FLOW_NOT_LINKED) {
+          GST_ELEMENT_FLOW_ERROR (pixbuf, res);
+          forward = FALSE;
+          ret = FALSE;
+        }
+      }
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      g_list_free_full (pixbuf->pending_events,
+          (GDestroyNotify) gst_event_unref);
+      pixbuf->pending_events = NULL;
+      /* Fall through */
+    case GST_EVENT_SEGMENT:
+    {
+      const GstSegment *segment;
+      gst_event_parse_segment (event, &segment);
+      if (segment->format == GST_FORMAT_BYTES)
+        pixbuf->packetized = FALSE;
+      else
+        pixbuf->packetized = TRUE;
+      if (pixbuf->pixbuf_loader != NULL) {
+        gdk_pixbuf_loader_close (pixbuf->pixbuf_loader, NULL);
+        g_object_unref (G_OBJECT (pixbuf->pixbuf_loader));
+        pixbuf->pixbuf_loader = NULL;
+      }
+      break;
+    }
+    default:
+      break;
+  }
+  if (forward) {
+    if (!gst_pad_has_current_caps (pixbuf->srcpad) &&
+        GST_EVENT_IS_SERIALIZED (event)
+        && GST_EVENT_TYPE (event) > GST_EVENT_CAPS
+        && GST_EVENT_TYPE (event) != GST_EVENT_FLUSH_STOP
+        && GST_EVENT_TYPE (event) != GST_EVENT_EOS) {
+      ret = TRUE;
+      pixbuf->pending_events = g_list_prepend (pixbuf->pending_events, event);
+    } else {
+      ret = gst_pad_event_default (pad, parent, event);
+    }
+  } else {
+    gst_event_unref (event);
+  }
+  return ret;
+}
+
+static GstFlowReturn
+gst_gdk_pixbuf_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstGdkPixbufDec *filter;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GError *error = NULL;
+  GstClockTime timestamp;
+  GstMapInfo map;
+
+  filter = GST_GDK_PIXBUF_DEC (parent);
+
+  timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+  if (GST_CLOCK_TIME_IS_VALID (timestamp))
+    filter->last_timestamp = timestamp;
+
+  GST_LOG_OBJECT (filter, "buffer with ts: %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (filter->pixbuf_loader == NULL)
+    filter->pixbuf_loader = gdk_pixbuf_loader_new ();
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  GST_LOG_OBJECT (filter, "Writing buffer size %d", (gint) map.size);
+  if (!gdk_pixbuf_loader_write (filter->pixbuf_loader, map.data, map.size,
+          &error))
+    goto error;
+
+  if (filter->packetized == TRUE) {
+    gdk_pixbuf_loader_close (filter->pixbuf_loader, NULL);
+    ret = gst_gdk_pixbuf_dec_flush (filter);
+    g_object_unref (filter->pixbuf_loader);
+    filter->pixbuf_loader = NULL;
+  }
+
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+
+  return ret;
+
+  /* ERRORS */
+error:
+  {
+    GST_ELEMENT_ERROR (filter, STREAM, DECODE, (NULL),
+        ("gdk_pixbuf_loader_write error: %s", error->message));
+    g_error_free (error);
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstStateChangeReturn
+gst_gdk_pixbuf_dec_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+  GstGdkPixbufDec *dec = GST_GDK_PIXBUF_DEC (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      /* default to single image mode, setcaps function might not be called */
+      dec->in_fps_n = 0;
+      dec->in_fps_d = 1;
+      gst_video_info_init (&dec->info);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      dec->in_fps_n = 0;
+      dec->in_fps_d = 0;
+      if (dec->pool) {
+        gst_buffer_pool_set_active (dec->pool, FALSE);
+        gst_object_replace ((GstObject **) & dec->pool, NULL);
+      }
+      g_list_free_full (dec->pending_events, (GDestroyNotify) gst_event_unref);
+      dec->pending_events = NULL;
+      if (dec->pixbuf_loader != NULL) {
+        gdk_pixbuf_loader_close (dec->pixbuf_loader, NULL);
+        g_object_unref (G_OBJECT (dec->pixbuf_loader));
+        dec->pixbuf_loader = NULL;
+      }
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
diff --git a/ext/gdk_pixbuf/gstgdkpixbufdec.h b/ext/gdk_pixbuf/gstgdkpixbufdec.h
new file mode 100644
index 0000000..4b12f48
--- /dev/null
+++ b/ext/gdk_pixbuf/gstgdkpixbufdec.h
@@ -0,0 +1,70 @@
+/* GStreamer GdkPixbuf-based image decoder
+ * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2003 David A. Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_GDK_PIXBUF_DEC_H__
+#define __GST_GDK_PIXBUF_DEC_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GDK_PIXBUF_DEC			\
+  (gst_gdk_pixbuf_dec_get_type())
+#define GST_GDK_PIXBUF_DEC(obj)						\
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GDK_PIXBUF_DEC,GstGdkPixbufDec))
+#define GST_GDK_PIXBUF_DEC_CLASS(klass)					\
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GDK_PIXBUF_DEC,GstGdkPixbufDecClass))
+#define GST_IS_GDK_PIXBUF_DEC(obj)					\
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GDK_PIXBUF_DEC))
+#define GST_IS_GDK_PIXBUF_DEC_CLASS(klass)				\
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GDK_PIXBUF_DEC))
+
+typedef struct _GstGdkPixbufDec      GstGdkPixbufDec;
+typedef struct _GstGdkPixbufDecClass GstGdkPixbufDecClass;
+
+struct _GstGdkPixbufDec
+{
+  GstElement element;
+
+  GstPad *sinkpad, *srcpad;
+
+  GstClockTime      last_timestamp;
+  GdkPixbufLoader  *pixbuf_loader;
+
+  gint in_fps_n, in_fps_d;
+
+  GstVideoInfo   info;
+  GstBufferPool *pool;
+  GList         *pending_events;
+  gboolean       packetized;
+};
+
+struct _GstGdkPixbufDecClass
+{
+  GstElementClass parent_class;
+};
+
+GType gst_gdk_pixbuf_dec_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_GDK_PIXBUF_DEC_H__ */
diff --git a/ext/gdk_pixbuf/gstgdkpixbufoverlay.c b/ext/gdk_pixbuf/gstgdkpixbufoverlay.c
new file mode 100644
index 0000000..38b8ecc
--- /dev/null
+++ b/ext/gdk_pixbuf/gstgdkpixbufoverlay.c
@@ -0,0 +1,712 @@
+/* GStreamer GdkPixbuf overlay
+ * Copyright (C) 2012-2014 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
+ * Boston, MA 02110-1335, USA.
+ */
+
+/**
+ * SECTION:element-gdkpixbufoverlay
+ *
+ * The gdkpixbufoverlay element overlays an image loaded from file onto
+ * a video stream.
+ *
+ * Changing the positioning or overlay width and height properties at runtime
+ * is supported, but it might be prudent to to protect the property setting
+ * code with GST_BASE_TRANSFORM_LOCK and GST_BASE_TRANSFORM_UNLOCK, as
+ * g_object_set() is not atomic for multiple properties passed in one go.
+ *
+ * Changing the image at runtime is currently not supported.
+ *
+ * Negative offsets are also not yet supported.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! gdkpixbufoverlay location=image.png ! autovideosink
+ * ]|
+ * Overlays the image in image.png onto the test video picture produced by
+ * videotestsrc.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include "gstgdkpixbufoverlay.h"
+
+#include <gst/video/gstvideometa.h>
+
+GST_DEBUG_CATEGORY_STATIC (gdkpixbufoverlay_debug);
+#define GST_CAT_DEFAULT gdkpixbufoverlay_debug
+
+static void gst_gdk_pixbuf_overlay_set_property (GObject * object,
+    guint property_id, const GValue * value, GParamSpec * pspec);
+static void gst_gdk_pixbuf_overlay_get_property (GObject * object,
+    guint property_id, GValue * value, GParamSpec * pspec);
+static void gst_gdk_pixbuf_overlay_finalize (GObject * object);
+
+static gboolean gst_gdk_pixbuf_overlay_start (GstBaseTransform * trans);
+static gboolean gst_gdk_pixbuf_overlay_stop (GstBaseTransform * trans);
+static GstFlowReturn
+gst_gdk_pixbuf_overlay_transform_frame_ip (GstVideoFilter * filter,
+    GstVideoFrame * frame);
+static void gst_gdk_pixbuf_overlay_before_transform (GstBaseTransform * trans,
+    GstBuffer * outbuf);
+static gboolean gst_gdk_pixbuf_overlay_set_info (GstVideoFilter * filter,
+    GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
+    GstVideoInfo * out_info);
+static gboolean
+gst_gdk_pixbuf_overlay_load_image (GstGdkPixbufOverlay * overlay,
+    GError ** err);
+static void gst_gdk_pixbuf_overlay_set_pixbuf (GstGdkPixbufOverlay * overlay,
+    GdkPixbuf * pixbuf);
+
+enum
+{
+  PROP_0,
+  PROP_LOCATION,
+  PROP_PIXBUF,
+  PROP_POSITIONING_MODE,
+  PROP_OFFSET_X,
+  PROP_OFFSET_Y,
+  PROP_RELATIVE_X,
+  PROP_RELATIVE_Y,
+  PROP_COEF_X,
+  PROP_COEF_Y,
+  PROP_OVERLAY_WIDTH,
+  PROP_OVERLAY_HEIGHT,
+  PROP_ALPHA
+};
+
+#define VIDEO_FORMATS "{ RGBx, RGB, BGR, BGRx, xRGB, xBGR, " \
+    "RGBA, BGRA, ARGB, ABGR, I420, YV12, AYUV, YUY2, UYVY, " \
+    "v308, v210, v216, Y41B, Y42B, Y444, YVYU, NV12, NV21, UYVP, " \
+    "RGB16, BGR16, RGB15, BGR15, UYVP, A420, YUV9, YVU9, " \
+    "IYU1, ARGB64, AYUV64, r210, I420_10LE, I420_10BE, " \
+    "GRAY8, GRAY16_BE, GRAY16_LE }"
+
+/* FIXME 2.0: change to absolute positioning */
+#define DEFAULT_POSITIONING_MODE \
+    GST_GDK_PIXBUF_POSITIONING_PIXELS_RELATIVE_TO_EDGES
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (VIDEO_FORMATS))
+    );
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (VIDEO_FORMATS))
+    );
+
+G_DEFINE_TYPE (GstGdkPixbufOverlay, gst_gdk_pixbuf_overlay,
+    GST_TYPE_VIDEO_FILTER);
+
+#define GST_TYPE_GDK_PIXBUF_POSITIONING_MODE \
+    (gst_gdk_pixbuf_positioning_mode_get_type())
+
+static GType
+gst_gdk_pixbuf_positioning_mode_get_type (void)
+{
+  static const GEnumValue pos_modes[] = {
+    {GST_GDK_PIXBUF_POSITIONING_PIXELS_RELATIVE_TO_EDGES,
+        "pixels-relative-to-edges", "pixels-relative-to-edges"},
+    {GST_GDK_PIXBUF_POSITIONING_PIXELS_ABSOLUTE, "pixels-absolute",
+        "pixels-absolute"},
+    {0, NULL, NULL},
+  };
+
+  static GType type;            /* 0 */
+
+  if (!type) {
+    type = g_enum_register_static ("GstGdkPixbufPositioningMode", pos_modes);
+  }
+
+  return type;
+}
+
+static void
+gst_gdk_pixbuf_overlay_class_init (GstGdkPixbufOverlayClass * klass)
+{
+  GstVideoFilterClass *videofilter_class = GST_VIDEO_FILTER_CLASS (klass);
+  GstBaseTransformClass *basetrans_class = GST_BASE_TRANSFORM_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = gst_gdk_pixbuf_overlay_set_property;
+  gobject_class->get_property = gst_gdk_pixbuf_overlay_get_property;
+  gobject_class->finalize = gst_gdk_pixbuf_overlay_finalize;
+
+  basetrans_class->start = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_start);
+  basetrans_class->stop = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_stop);
+
+  basetrans_class->before_transform =
+      GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_before_transform);
+
+  videofilter_class->set_info =
+      GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_set_info);
+  videofilter_class->transform_frame_ip =
+      GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_transform_frame_ip);
+
+  g_object_class_install_property (gobject_class, PROP_LOCATION,
+      g_param_spec_string ("location", "location",
+          "Location of image file to overlay", NULL, GST_PARAM_CONTROLLABLE
+          | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE
+          | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_OFFSET_X,
+      g_param_spec_int ("offset-x", "X Offset",
+          "For positive value, horizontal offset of overlay image in pixels from"
+          " left of video image. For negative value, horizontal offset of overlay"
+          " image in pixels from right of video image", G_MININT, G_MAXINT, 0,
+          GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE
+          | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_OFFSET_Y,
+      g_param_spec_int ("offset-y", "Y Offset",
+          "For positive value, vertical offset of overlay image in pixels from"
+          " top of video image. For negative value, vertical offset of overlay"
+          " image in pixels from bottom of video image", G_MININT, G_MAXINT, 0,
+          GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE
+          | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_RELATIVE_X,
+      g_param_spec_double ("relative-x", "Relative X Offset",
+          "Horizontal offset of overlay image in fractions of video image "
+          "width, from top-left corner of video image"
+          " (in relative positioning)", -1.0, 1.0, 0.0,
+          GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE
+          | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_RELATIVE_Y,
+      g_param_spec_double ("relative-y", "Relative Y Offset",
+          "Vertical offset of overlay image in fractions of video image "
+          "height, from top-left corner of video image"
+          " (in relative positioning)", -1.0, 1.0, 0.0,
+          GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE
+          | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_OVERLAY_WIDTH,
+      g_param_spec_int ("overlay-width", "Overlay Width",
+          "Width of overlay image in pixels (0 = same as overlay image)", 0,
+          G_MAXINT, 0,
+          GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE
+          | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_OVERLAY_HEIGHT,
+      g_param_spec_int ("overlay-height", "Overlay Height",
+          "Height of overlay image in pixels (0 = same as overlay image)", 0,
+          G_MAXINT, 0,
+          GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE
+          | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_ALPHA,
+      g_param_spec_double ("alpha", "Alpha", "Global alpha of overlay image",
+          0.0, 1.0, 1.0, GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING
+          | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstGdkPixbufOverlay:pixbuf:
+   *
+   * GdkPixbuf object to render.
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_PIXBUF,
+      g_param_spec_object ("pixbuf", "Pixbuf", "GdkPixbuf object to render",
+          GDK_TYPE_PIXBUF, GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING
+          | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstGdkPixbufOverlay:positioning-mode:
+   *
+   * Positioning mode of offset-x and offset-y properties. Determines how
+   * negative x/y offsets will be interpreted. By default negative values
+   * are for positioning relative to the right/bottom edge of the video
+   * image, but you can use this property to select absolute positioning
+   * relative to a (0, 0) origin in the top-left corner. That way negative
+   * offsets will be to the left/above the video image, which allows you to
+   * smoothly slide logos into and out of the frame if desired.
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_POSITIONING_MODE,
+      g_param_spec_enum ("positioning-mode", "Positioning mode",
+          "Positioning mode of offset-x and offset-y properties",
+          GST_TYPE_GDK_PIXBUF_POSITIONING_MODE, DEFAULT_POSITIONING_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /* FIXME the following actually act as a RELATIVE_X/RELATIVE_Y,
+   * but those were already slightly mutated/abused with ABSOLUTE positioning,
+   * so let's keep that and follow suit
+   * Suffice it to say all that could do with cleanup (2.0 ??) */
+  /**
+   * GstGdkPixbufOverlay:coef-x:
+   *
+   * In absolute positioning mode, the x coordinate of overlay image's
+   * top-left corner is now given by
+   * offset-x + (relative-x * overlay_width) + (coef-x * video_width).
+   * This allows to align the image absolutely and relatively
+   * to any edge or center position.
+   *
+   * Since: 1.12
+   */
+  g_object_class_install_property (gobject_class, PROP_COEF_X,
+      g_param_spec_double ("coef-x", "Relative X Offset",
+          "Horizontal offset of overlay image in fractions of video image "
+          "width, from top-left corner of video image (absolute positioning)",
+          -1.0, 1.0, 0.0, GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING
+          | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstGdkPixbufOverlay:coef-y:
+   *
+   * In absolute positioning mode, the y coordinate of overlay image's
+   * top-left corner is now given by
+   * offset-y + (relative-y * overlay_height) + (coef-y * video_height).
+   * This allows to align the image absolutely and relatively
+   * to any edge or center position.
+   *
+   * Since: 1.12
+   */
+  g_object_class_install_property (gobject_class, PROP_COEF_Y,
+      g_param_spec_double ("coef-y", "Relative Y Offset",
+          "Vertical offset of overlay image in fractions of video image "
+          "height, from top-left corner of video image (absolute positioning)",
+          -1.0, 1.0, 0.0, GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING
+          | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "GdkPixbuf Overlay", "Filter/Effect/Video",
+      "Overlay an image onto a video stream",
+      "Tim-Philipp Müller <tim centricular net>");
+  GST_DEBUG_CATEGORY_INIT (gdkpixbufoverlay_debug, "gdkpixbufoverlay", 0,
+      "debug category for gdkpixbufoverlay element");
+}
+
+static void
+gst_gdk_pixbuf_overlay_init (GstGdkPixbufOverlay * overlay)
+{
+  overlay->offset_x = 0;
+  overlay->offset_y = 0;
+
+  overlay->relative_x = 0.0;
+  overlay->relative_y = 0.0;
+
+  overlay->coef_x = 0.0;
+  overlay->coef_y = 0.0;
+
+  overlay->positioning_mode = DEFAULT_POSITIONING_MODE;
+
+  overlay->overlay_width = 0;
+  overlay->overlay_height = 0;
+
+  overlay->alpha = 1.0;
+
+  overlay->pixbuf = NULL;
+}
+
+void
+gst_gdk_pixbuf_overlay_set_property (GObject * object, guint property_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (object);
+
+  GST_OBJECT_LOCK (overlay);
+
+  switch (property_id) {
+    case PROP_LOCATION:{
+      GError *err = NULL;
+      g_free (overlay->location);
+      overlay->location = g_value_dup_string (value);
+      if (!gst_gdk_pixbuf_overlay_load_image (overlay, &err)) {
+        GST_ERROR_OBJECT (overlay, "Could not load overlay image: %s",
+            err->message);
+        g_error_free (err);
+      }
+      break;
+    }
+    case PROP_PIXBUF:{
+      GdkPixbuf *pixbuf = g_value_get_object (value);
+
+      if (overlay->pixbuf != NULL)
+        g_object_unref (overlay->pixbuf);
+      if (pixbuf) {
+        overlay->pixbuf = g_object_ref (pixbuf);
+        gst_gdk_pixbuf_overlay_set_pixbuf (overlay, g_object_ref (pixbuf));
+      } else {
+        overlay->pixbuf = NULL;
+        gst_buffer_replace (&overlay->pixels, NULL);
+      }
+      break;
+    }
+    case PROP_OFFSET_X:
+      overlay->offset_x = g_value_get_int (value);
+      overlay->update_composition = TRUE;
+      break;
+    case PROP_OFFSET_Y:
+      overlay->offset_y = g_value_get_int (value);
+      overlay->update_composition = TRUE;
+      break;
+    case PROP_RELATIVE_X:
+      overlay->relative_x = g_value_get_double (value);
+      overlay->update_composition = TRUE;
+      break;
+    case PROP_RELATIVE_Y:
+      overlay->relative_y = g_value_get_double (value);
+      overlay->update_composition = TRUE;
+      break;
+    case PROP_COEF_X:
+      overlay->coef_x = g_value_get_double (value);
+      overlay->update_composition = TRUE;
+      break;
+    case PROP_COEF_Y:
+      overlay->coef_y = g_value_get_double (value);
+      overlay->update_composition = TRUE;
+      break;
+    case PROP_OVERLAY_WIDTH:
+      overlay->overlay_width = g_value_get_int (value);
+      overlay->update_composition = TRUE;
+      break;
+    case PROP_OVERLAY_HEIGHT:
+      overlay->overlay_height = g_value_get_int (value);
+      overlay->update_composition = TRUE;
+      break;
+    case PROP_ALPHA:
+      overlay->alpha = g_value_get_double (value);
+      overlay->update_composition = TRUE;
+      break;
+    case PROP_POSITIONING_MODE:
+      overlay->positioning_mode = g_value_get_enum (value);
+      overlay->update_composition = TRUE;
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+
+  GST_OBJECT_UNLOCK (overlay);
+}
+
+void
+gst_gdk_pixbuf_overlay_get_property (GObject * object, guint property_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (object);
+
+  GST_OBJECT_LOCK (overlay);
+
+  switch (property_id) {
+    case PROP_LOCATION:
+      g_value_set_string (value, overlay->location);
+      break;
+    case PROP_PIXBUF:
+      g_value_set_object (value, overlay->pixbuf);
+      break;
+    case PROP_OFFSET_X:
+      g_value_set_int (value, overlay->offset_x);
+      break;
+    case PROP_OFFSET_Y:
+      g_value_set_int (value, overlay->offset_y);
+      break;
+    case PROP_RELATIVE_X:
+      g_value_set_double (value, overlay->relative_x);
+      break;
+    case PROP_RELATIVE_Y:
+      g_value_set_double (value, overlay->relative_y);
+      break;
+    case PROP_COEF_X:
+      g_value_set_double (value, overlay->coef_x);
+      break;
+    case PROP_COEF_Y:
+      g_value_set_double (value, overlay->coef_y);
+      break;
+    case PROP_OVERLAY_WIDTH:
+      g_value_set_int (value, overlay->overlay_width);
+      break;
+    case PROP_OVERLAY_HEIGHT:
+      g_value_set_int (value, overlay->overlay_height);
+      break;
+    case PROP_ALPHA:
+      g_value_set_double (value, overlay->alpha);
+      break;
+    case PROP_POSITIONING_MODE:
+      g_value_set_enum (value, overlay->positioning_mode);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+
+  GST_OBJECT_UNLOCK (overlay);
+}
+
+void
+gst_gdk_pixbuf_overlay_finalize (GObject * object)
+{
+  GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (object);
+
+  g_free (overlay->location);
+  overlay->location = NULL;
+
+  G_OBJECT_CLASS (gst_gdk_pixbuf_overlay_parent_class)->finalize (object);
+}
+
+static gboolean
+gst_gdk_pixbuf_overlay_load_image (GstGdkPixbufOverlay * overlay, GError ** err)
+{
+  GdkPixbuf *pixbuf;
+
+  pixbuf = gdk_pixbuf_new_from_file (overlay->location, err);
+
+  if (pixbuf == NULL)
+    return FALSE;
+
+  gst_gdk_pixbuf_overlay_set_pixbuf (overlay, pixbuf);
+  return TRUE;
+}
+
+/* Takes ownership of pixbuf; call with OBJECT_LOCK */
+static void
+gst_gdk_pixbuf_overlay_set_pixbuf (GstGdkPixbufOverlay * overlay,
+    GdkPixbuf * pixbuf)
+{
+  GstVideoMeta *video_meta;
+  guint8 *pixels, *p;
+  gint width, height, stride, w, h, plane;
+
+  if (!gdk_pixbuf_get_has_alpha (pixbuf)) {
+    GdkPixbuf *alpha_pixbuf;
+
+    /* FIXME: we could do this much more efficiently ourselves below, but
+     * we're lazy for now */
+    /* FIXME: perhaps expose substitute_color via properties */
+    alpha_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
+    g_object_unref (pixbuf);
+    pixbuf = alpha_pixbuf;
+  }
+
+  width = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
+  stride = gdk_pixbuf_get_rowstride (pixbuf);
+  pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+  /* the memory layout in GdkPixbuf is R-G-B-A, we want:
+   *  - B-G-R-A on little-endian platforms
+   *  - A-R-G-B on big-endian platforms
+   */
+  for (h = 0; h < height; ++h) {
+    p = pixels + (h * stride);
+    for (w = 0; w < width; ++w) {
+      guint8 tmp;
+
+      /* R-G-B-A ==> B-G-R-A */
+      tmp = p[0];
+      p[0] = p[2];
+      p[2] = tmp;
+
+      if (G_BYTE_ORDER == G_BIG_ENDIAN) {
+        /* B-G-R-A ==> A-R-G-B */
+        /* we can probably assume sane alignment */
+        *((guint32 *) p) = GUINT32_SWAP_LE_BE (*((guint32 *) p));
+      }
+
+      p += 4;
+    }
+  }
+
+  if (overlay->pixels)
+    gst_buffer_unref (overlay->pixels);
+
+  /* assume we have row padding even for the last row */
+  /* transfer ownership of pixbuf to the buffer */
+  overlay->pixels = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+      pixels, height * stride, 0, height * stride, pixbuf,
+      (GDestroyNotify) g_object_unref);
+
+  video_meta = gst_buffer_add_video_meta (overlay->pixels,
+      GST_VIDEO_FRAME_FLAG_NONE, GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB,
+      width, height);
+
+  for (plane = 0; plane < video_meta->n_planes; ++plane)
+    video_meta->stride[plane] = stride;
+
+  overlay->update_composition = TRUE;
+
+  GST_INFO_OBJECT (overlay, "Updated pixbuf, %d x %d", width, height);
+}
+
+static gboolean
+gst_gdk_pixbuf_overlay_start (GstBaseTransform * trans)
+{
+  GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (trans);
+  GError *err = NULL;
+
+  if (overlay->location != NULL) {
+    if (!gst_gdk_pixbuf_overlay_load_image (overlay, &err))
+      goto error_loading_image;
+
+    gst_base_transform_set_passthrough (trans, FALSE);
+  } else {
+    GST_WARNING_OBJECT (overlay, "no image location set, doing nothing");
+    gst_base_transform_set_passthrough (trans, TRUE);
+  }
+
+  return TRUE;
+
+/* ERRORS */
+error_loading_image:
+  {
+    GST_ELEMENT_ERROR (overlay, RESOURCE, OPEN_READ,
+        ("Could not load overlay image."), ("%s", err->message));
+    g_error_free (err);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_gdk_pixbuf_overlay_stop (GstBaseTransform * trans)
+{
+  GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (trans);
+
+  if (overlay->comp) {
+    gst_video_overlay_composition_unref (overlay->comp);
+    overlay->comp = NULL;
+  }
+
+  gst_buffer_replace (&overlay->pixels, NULL);
+
+  return TRUE;
+}
+
+static gboolean
+gst_gdk_pixbuf_overlay_set_info (GstVideoFilter * filter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GST_INFO_OBJECT (filter, "caps: %" GST_PTR_FORMAT, incaps);
+  return TRUE;
+}
+
+static void
+gst_gdk_pixbuf_overlay_update_composition (GstGdkPixbufOverlay * overlay)
+{
+  GstGdkPixbufPositioningMode positioning_mode;
+  GstVideoOverlayComposition *comp;
+  GstVideoOverlayRectangle *rect;
+  GstVideoMeta *overlay_meta;
+  gint x, y, width, height;
+  gint video_width =
+      GST_VIDEO_INFO_WIDTH (&GST_VIDEO_FILTER (overlay)->in_info);
+  gint video_height =
+      GST_VIDEO_INFO_HEIGHT (&GST_VIDEO_FILTER (overlay)->in_info);
+
+  if (overlay->comp) {
+    gst_video_overlay_composition_unref (overlay->comp);
+    overlay->comp = NULL;
+  }
+
+  if (overlay->alpha == 0.0 || overlay->pixels == NULL)
+    return;
+
+  overlay_meta = gst_buffer_get_video_meta (overlay->pixels);
+
+  positioning_mode = overlay->positioning_mode;
+  GST_DEBUG_OBJECT (overlay, "overlay positioning mode %d", positioning_mode);
+
+  width = overlay->overlay_width;
+  if (width == 0)
+    width = overlay_meta->width;
+
+  height = overlay->overlay_height;
+  if (height == 0)
+    height = overlay_meta->height;
+
+  if (positioning_mode == GST_GDK_PIXBUF_POSITIONING_PIXELS_ABSOLUTE) {
+    x = overlay->offset_x + (overlay->relative_x * width) +
+        (overlay->coef_x * video_width);
+    y = overlay->offset_y + (overlay->relative_y * height) +
+        (overlay->coef_y * video_height);
+  } else {
+    x = overlay->offset_x < 0 ?
+        video_width + overlay->offset_x - width +
+        (overlay->relative_x * video_width) :
+        overlay->offset_x + (overlay->relative_x * video_width);
+    y = overlay->offset_y < 0 ?
+        video_height + overlay->offset_y - height +
+        (overlay->relative_y * video_height) :
+        overlay->offset_y + (overlay->relative_y * video_height);
+  }
+
+  GST_DEBUG_OBJECT (overlay, "overlay image dimensions: %d x %d, alpha=%.2f",
+      overlay_meta->width, overlay_meta->height, overlay->alpha);
+  GST_DEBUG_OBJECT (overlay, "properties: x,y: %d,%d "
+      "(%g%%,%g%%) coef (%g%%,%g%%) - WxH: %dx%d",
+      overlay->offset_x, overlay->offset_y,
+      overlay->relative_x * 100.0, overlay->relative_y * 100.0,
+      overlay->coef_x * 100.0, overlay->coef_y * 100.0,
+      overlay->overlay_height, overlay->overlay_width);
+  GST_DEBUG_OBJECT (overlay, "overlay rendered: %d x %d @ %d,%d (onto %d x %d)",
+      width, height, x, y, video_width, video_height);
+
+  rect = gst_video_overlay_rectangle_new_raw (overlay->pixels,
+      x, y, width, height, GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
+
+  if (overlay->alpha != 1.0)
+    gst_video_overlay_rectangle_set_global_alpha (rect, overlay->alpha);
+
+  comp = gst_video_overlay_composition_new (rect);
+  gst_video_overlay_rectangle_unref (rect);
+
+  overlay->comp = comp;
+}
+
+static void
+gst_gdk_pixbuf_overlay_before_transform (GstBaseTransform * trans,
+    GstBuffer * outbuf)
+{
+  GstClockTime stream_time;
+  GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (trans);
+  gboolean set_passthrough = FALSE;
+
+  stream_time = gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
+      GST_BUFFER_TIMESTAMP (outbuf));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (trans), stream_time);
+
+  /* now properties have been sync'ed; maybe need to update composition */
+  GST_OBJECT_LOCK (overlay);
+  if (G_UNLIKELY (overlay->update_composition)) {
+    gst_gdk_pixbuf_overlay_update_composition (overlay);
+    overlay->update_composition = FALSE;
+    set_passthrough = TRUE;
+  }
+  GST_OBJECT_UNLOCK (overlay);
+
+  /* determine passthrough mode so the buffer is writable if needed
+   * when passed into _transform_ip */
+  if (G_UNLIKELY (set_passthrough))
+    gst_base_transform_set_passthrough (trans, overlay->comp == NULL);
+}
+
+static GstFlowReturn
+gst_gdk_pixbuf_overlay_transform_frame_ip (GstVideoFilter * filter,
+    GstVideoFrame * frame)
+{
+  GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (filter);
+
+  if (overlay->comp != NULL)
+    gst_video_overlay_composition_blend (overlay->comp, frame);
+
+  return GST_FLOW_OK;
+}
diff --git a/ext/gdk_pixbuf/gstgdkpixbufoverlay.h b/ext/gdk_pixbuf/gstgdkpixbufoverlay.h
new file mode 100644
index 0000000..8d80b01
--- /dev/null
+++ b/ext/gdk_pixbuf/gstgdkpixbufoverlay.h
@@ -0,0 +1,94 @@
+/* GStreamer GdkPixbuf overlay
+ * Copyright (C) 2012-2014 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GST_GDK_PIXBUF_OVERLAY_H_
+#define _GST_GDK_PIXBUF_OVERLAY_H_
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+#include <gst/video/video-overlay-composition.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GDK_PIXBUF_OVERLAY   (gst_gdk_pixbuf_overlay_get_type())
+#define GST_GDK_PIXBUF_OVERLAY(obj)   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GDK_PIXBUF_OVERLAY,GstGdkPixbufOverlay))
+#define GST_GDK_PIXBUF_OVERLAY_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GDK_PIXBUF_OVERLAY,GstGdkPixbufOverlayClass))
+#define GST_IS_GDK_PIXBUF_OVERLAY(obj)   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GDK_PIXBUF_OVERLAY))
+#define GST_IS_GDK_PIXBUF_OVERLAY_CLASS(obj)   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GDK_PIXBUF_OVERLAY))
+
+typedef struct _GstGdkPixbufOverlay GstGdkPixbufOverlay;
+typedef struct _GstGdkPixbufOverlayClass GstGdkPixbufOverlayClass;
+
+typedef enum {
+  GST_GDK_PIXBUF_POSITIONING_PIXELS_RELATIVE_TO_EDGES,
+  GST_GDK_PIXBUF_POSITIONING_PIXELS_ABSOLUTE
+} GstGdkPixbufPositioningMode;
+
+/**
+ * GstGdkPixbufOverlay:
+ *
+ * The opaque element instance structure.
+ */
+struct _GstGdkPixbufOverlay
+{
+  GstVideoFilter               videofilter;
+
+  /* properties */
+  gchar                      * location;
+
+  /* pixbuf set via pixbuf property */
+  GdkPixbuf                  * pixbuf;
+
+  gint                         offset_x;
+  gint                         offset_y;
+
+  gdouble                      relative_x;
+  gdouble                      relative_y;
+
+  gdouble                      coef_x;
+  gdouble                      coef_y;
+
+  GstGdkPixbufPositioningMode  positioning_mode;
+
+  gint                         overlay_width;
+  gint                         overlay_height;
+
+  gdouble                      alpha;
+
+  /* the loaded image, as BGRA/ARGB pixels, with GstVideoMeta */
+  GstBuffer                  * pixels;               /* OBJECT_LOCK */
+
+  GstVideoOverlayComposition * comp;
+
+  /* render position or dimension has changed */
+  gboolean                     update_composition;
+};
+
+struct _GstGdkPixbufOverlayClass
+{
+  GstVideoFilterClass  videofilter_class;
+};
+
+GType gst_gdk_pixbuf_overlay_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ext/gdk_pixbuf/gstgdkpixbufplugin.c b/ext/gdk_pixbuf/gstgdkpixbufplugin.c
new file mode 100644
index 0000000..4f58b9d
--- /dev/null
+++ b/ext/gdk_pixbuf/gstgdkpixbufplugin.c
@@ -0,0 +1,108 @@
+/* GStreamer GdkPixbuf plugin
+ * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2003 David A. Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "gstgdkpixbufdec.h"
+#include "gstgdkpixbufoverlay.h"
+#include "gstgdkpixbufsink.h"
+
+
+#if 0
+static void gst_gdk_pixbuf_type_find (GstTypeFind * tf, gpointer ignore);
+
+#define GST_GDK_PIXBUF_TYPE_FIND_SIZE 1024
+
+static void
+gst_gdk_pixbuf_type_find (GstTypeFind * tf, gpointer ignore)
+{
+  guint8 *data;
+  GdkPixbufLoader *pixbuf_loader;
+  GdkPixbufFormat *format;
+
+  data = gst_type_find_peek (tf, 0, GST_GDK_PIXBUF_TYPE_FIND_SIZE);
+  if (data == NULL)
+    return;
+
+  GST_DEBUG ("creating new loader");
+
+  pixbuf_loader = gdk_pixbuf_loader_new ();
+
+  gdk_pixbuf_loader_write (pixbuf_loader, data, GST_GDK_PIXBUF_TYPE_FIND_SIZE,
+      NULL);
+
+  format = gdk_pixbuf_loader_get_format (pixbuf_loader);
+
+  if (format != NULL) {
+    GstCaps *caps;
+    gchar **p;
+    gchar **mlist = gdk_pixbuf_format_get_mime_types (format);
+
+    for (p = mlist; *p; ++p) {
+      GST_DEBUG ("suggesting mime type %s", *p);
+      caps = gst_caps_new_simple (*p, NULL);
+      gst_type_find_suggest (tf, GST_TYPE_FIND_MINIMUM, caps);
+      gst_caps_free (caps);
+    }
+    g_strfreev (mlist);
+  }
+
+  GST_DEBUG ("closing pixbuf loader, hope it doesn't hang ...");
+  /* librsvg 2.4.x has a bug where it triggers an endless loop in trying
+     to close a gzip that's not an svg; fixed upstream but no good way
+     to work around it */
+  gdk_pixbuf_loader_close (pixbuf_loader, NULL);
+  GST_DEBUG ("closed pixbuf loader");
+  g_object_unref (G_OBJECT (pixbuf_loader));
+}
+#endif
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "gdkpixbufdec", GST_RANK_SECONDARY,
+          GST_TYPE_GDK_PIXBUF_DEC))
+    return FALSE;
+
+#if 0
+  gst_type_find_register (plugin, "image/*", GST_RANK_MARGINAL,
+      gst_gdk_pixbuf_type_find, NULL, GST_CAPS_ANY, NULL);
+#endif
+
+  if (!gst_element_register (plugin, "gdkpixbufoverlay", GST_RANK_NONE,
+          GST_TYPE_GDK_PIXBUF_OVERLAY))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "gdkpixbufsink", GST_RANK_NONE,
+          GST_TYPE_GDK_PIXBUF_SINK))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    gdkpixbuf,
+    "GdkPixbuf-based image decoder, overlay and sink",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/gdk_pixbuf/gstgdkpixbufsink.c b/ext/gdk_pixbuf/gstgdkpixbufsink.c
new file mode 100644
index 0000000..6c4cf3d
--- /dev/null
+++ b/ext/gdk_pixbuf/gstgdkpixbufsink.c
@@ -0,0 +1,439 @@
+/* GStreamer GdkPixbuf sink
+ * Copyright (C) 2006-2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is free software; you can redistribute it and/or
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-gdkpixbufsink
+ *
+ * This sink element takes RGB or RGBA images as input and wraps them into
+ * #GdkPixbuf objects, for easy saving to file via the
+ * GdkPixbuf library API or displaying in Gtk+ applications (e.g. using
+ * the #GtkImage widget).
+ *
+ * There are two ways to use this element and obtain the #GdkPixbuf objects
+ * created:
+ * <itemizedlist>
+ * <listitem>
+ * Watching for element messages named <classname>&quot;preroll-pixbuf&quot;
+ * </classname> or <classname>&quot;pixbuf&quot;</classname> on the bus, which
+ * will be posted whenever an image would usually be rendered. See below for
+ * more details on these messages and how to extract the pixbuf object
+ * contained in them.
+ * </listitem>
+ * <listitem>
+ * Retrieving the current pixbuf via the #GstGdkPixbufSink:last-pixbuf property
+ * when needed. This is the easiest way to get at pixbufs for snapshotting
+ * purposes - just wait until the pipeline is prerolled (ASYNC_DONE message
+ * on the bus), then read the property. If you use this method, you may want
+ * to disable message posting by setting the #GstGdkPixbufSink:post-messages
+ * property to %FALSE. This avoids unnecessary memory overhead.
+ * </listitem>
+ * </itemizedlist>
+ *
+ * The primary purpose of this element is to abstract away the #GstBuffer to
+ * #GdkPixbuf conversion. Other than that it's very similar to the fakesink
+ * element.
+ *
+ * This element is meant for easy no-hassle video snapshotting. It is not
+ * suitable for video playback or video display at high framerates. Use
+ * ximagesink, xvimagesink or some other suitable video sink in connection
+ * with the #GstXOverlay interface instead if you want to do video playback.
+ *
+ * <refsect2>
+ * <title>Message details</title>
+ * As mentioned above, this element will by default post element messages
+ * containing structures named <classname>&quot;preroll-pixbuf&quot;
+ * </classname> or <classname>&quot;pixbuf&quot;</classname> on the bus (this
+ * can be disabled by setting the #GstGdkPixbufSink:post-messages property
+ * to %FALSE though). The element message structure has the following fields:
+ * <itemizedlist>
+ * <listitem>
+ *   <classname>&quot;pixbuf&quot;</classname>: the #GdkPixbuf object
+ * </listitem>
+ * <listitem>
+ *   <classname>&quot;pixel-aspect-ratio&quot;</classname>: the pixel aspect
+ *   ratio (PAR) of the input image (this field contains a #GstFraction); the
+ *   PAR is usually 1:1 for images, but is often something non-1:1 in the case
+ *   of video input. In this case the image may be distorted and you may need
+ *   to rescale it accordingly before saving it to file or displaying it. This
+ *   can easily be done using gdk_pixbuf_scale() (the reason this is not done
+ *   automatically is that the application will often scale the image anyway
+ *   according to the size of the output window, in which case it is much more
+ *   efficient to only scale once rather than twice). You can put a videoscale
+ *   element and a capsfilter element with
+ *   <literal>video/x-raw-rgb,pixel-aspect-ratio=(fraction)1/1</literal> caps
+ *   in front of this element to make sure the pixbufs always have a 1:1 PAR.
+ * </listitem>
+ * </itemizedlist>
+ * </refsect2>
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 -m -v videotestsrc num-buffers=1 ! gdkpixbufsink
+ * ]| Process one single test image as pixbuf (note that the output you see will
+ * be slightly misleading. The message structure does contain a valid pixbuf
+ * object even if the structure string says &apos;(NULL)&apos;).
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstgdkpixbufsink.h"
+
+#include <gst/video/video.h>
+
+#define DEFAULT_SEND_MESSAGES TRUE
+#define DEFAULT_POST_MESSAGES TRUE
+
+enum
+{
+  PROP_0,
+  PROP_POST_MESSAGES,
+  PROP_LAST_PIXBUF,
+  PROP_LAST
+};
+
+
+G_DEFINE_TYPE (GstGdkPixbufSink, gst_gdk_pixbuf_sink, GST_TYPE_VIDEO_SINK);
+
+static void gst_gdk_pixbuf_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gdk_pixbuf_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_gdk_pixbuf_sink_start (GstBaseSink * basesink);
+static gboolean gst_gdk_pixbuf_sink_stop (GstBaseSink * basesink);
+static gboolean gst_gdk_pixbuf_sink_set_caps (GstBaseSink * basesink,
+    GstCaps * caps);
+static GstFlowReturn gst_gdk_pixbuf_sink_render (GstBaseSink * bsink,
+    GstBuffer * buf);
+static GstFlowReturn gst_gdk_pixbuf_sink_preroll (GstBaseSink * bsink,
+    GstBuffer * buf);
+static GdkPixbuf *gst_gdk_pixbuf_sink_get_pixbuf_from_buffer (GstGdkPixbufSink *
+    sink, GstBuffer * buf);
+
+static GstStaticPadTemplate pixbufsink_sink_factory =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB") ";"
+        GST_VIDEO_CAPS_MAKE ("RGBA"))
+    );
+
+static void
+gst_gdk_pixbuf_sink_class_init (GstGdkPixbufSinkClass * klass)
+{
+  GstBaseSinkClass *basesink_class = GST_BASE_SINK_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gst_element_class_set_static_metadata (element_class, "GdkPixbuf sink",
+      "Sink/Video", "Output images as GdkPixbuf objects in bus messages",
+      "Tim-Philipp Müller <tim centricular net>");
+
+  gst_element_class_add_static_pad_template (element_class,
+      &pixbufsink_sink_factory);
+
+  gobject_class->set_property = gst_gdk_pixbuf_sink_set_property;
+  gobject_class->get_property = gst_gdk_pixbuf_sink_get_property;
+
+  /**
+   * GstGdkPixbuf:post-messages:
+   *
+   * Post messages on the bus containing pixbufs.
+   */
+  g_object_class_install_property (gobject_class, PROP_POST_MESSAGES,
+      g_param_spec_boolean ("post-messages", "Post Messages",
+          "Whether to post messages containing pixbufs on the bus",
+          DEFAULT_POST_MESSAGES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_LAST_PIXBUF,
+      g_param_spec_object ("last-pixbuf", "Last Pixbuf",
+          "Last GdkPixbuf object rendered", GDK_TYPE_PIXBUF,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  basesink_class->start = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_start);
+  basesink_class->stop = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_stop);
+  basesink_class->render = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_render);
+  basesink_class->preroll = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_preroll);
+  basesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_set_caps);
+}
+
+static void
+gst_gdk_pixbuf_sink_init (GstGdkPixbufSink * sink)
+{
+  sink->par_n = 0;
+  sink->par_d = 0;
+  sink->has_alpha = FALSE;
+  sink->last_pixbuf = NULL;
+  sink->post_messages = DEFAULT_POST_MESSAGES;
+
+  /* we're not a real video sink, we just derive from GstVideoSink in case
+   * anything interesting is added to it in future */
+  gst_base_sink_set_max_lateness (GST_BASE_SINK (sink), -1);
+  gst_base_sink_set_qos_enabled (GST_BASE_SINK (sink), FALSE);
+}
+
+
+static gboolean
+gst_gdk_pixbuf_sink_start (GstBaseSink * basesink)
+{
+  GST_LOG_OBJECT (basesink, "start");
+
+  return TRUE;
+}
+
+static gboolean
+gst_gdk_pixbuf_sink_stop (GstBaseSink * basesink)
+{
+  GstGdkPixbufSink *sink = GST_GDK_PIXBUF_SINK (basesink);
+
+  GST_VIDEO_SINK_WIDTH (sink) = 0;
+  GST_VIDEO_SINK_HEIGHT (sink) = 0;
+
+  sink->par_n = 0;
+  sink->par_d = 0;
+  sink->has_alpha = FALSE;
+
+  if (sink->last_pixbuf) {
+    g_object_unref (sink->last_pixbuf);
+    sink->last_pixbuf = NULL;
+  }
+
+  GST_LOG_OBJECT (sink, "stop");
+
+  return TRUE;
+}
+
+static gboolean
+gst_gdk_pixbuf_sink_set_caps (GstBaseSink * basesink, GstCaps * caps)
+{
+  GstGdkPixbufSink *sink = GST_GDK_PIXBUF_SINK (basesink);
+  GstVideoInfo info;
+  GstVideoFormat fmt;
+  gint w, h, par_n, par_d;
+
+  GST_LOG_OBJECT (sink, "caps: %" GST_PTR_FORMAT, caps);
+
+  if (!gst_video_info_from_caps (&info, caps)) {
+    GST_WARNING_OBJECT (sink, "parse_caps failed");
+    return FALSE;
+  }
+
+  fmt = GST_VIDEO_INFO_FORMAT (&info);
+  w = GST_VIDEO_INFO_WIDTH (&info);
+  h = GST_VIDEO_INFO_HEIGHT (&info);
+  par_n = GST_VIDEO_INFO_PAR_N (&info);
+  par_d = GST_VIDEO_INFO_PAR_N (&info);
+
+#ifndef G_DISABLE_ASSERT
+  {
+    gint s;
+    s = GST_VIDEO_INFO_COMP_PSTRIDE (&info, 0);
+    g_assert ((fmt == GST_VIDEO_FORMAT_RGB && s == 3) ||
+        (fmt == GST_VIDEO_FORMAT_RGBA && s == 4));
+  }
+#endif
+
+  GST_VIDEO_SINK_WIDTH (sink) = w;
+  GST_VIDEO_SINK_HEIGHT (sink) = h;
+
+  sink->par_n = par_n;
+  sink->par_d = par_d;
+
+  sink->has_alpha = GST_VIDEO_INFO_HAS_ALPHA (&info);
+
+  GST_INFO_OBJECT (sink, "format             : %d", fmt);
+  GST_INFO_OBJECT (sink, "width x height     : %d x %d", w, h);
+  GST_INFO_OBJECT (sink, "pixel-aspect-ratio : %d/%d", par_n, par_d);
+
+  sink->info = info;
+
+  return TRUE;
+}
+
+static void
+gst_gdk_pixbuf_sink_pixbuf_destroy_notify (guchar * pixels,
+    GstVideoFrame * frame)
+{
+  gst_video_frame_unmap (frame);
+  gst_buffer_unref (frame->buffer);
+  g_slice_free (GstVideoFrame, frame);
+}
+
+static GdkPixbuf *
+gst_gdk_pixbuf_sink_get_pixbuf_from_buffer (GstGdkPixbufSink * sink,
+    GstBuffer * buf)
+{
+  GdkPixbuf *pix = NULL;
+  GstVideoFrame *frame;
+  gint minsize, bytes_per_pixel;
+
+  g_return_val_if_fail (GST_VIDEO_SINK_WIDTH (sink) > 0, NULL);
+  g_return_val_if_fail (GST_VIDEO_SINK_HEIGHT (sink) > 0, NULL);
+
+  frame = g_slice_new0 (GstVideoFrame);
+  gst_video_frame_map (frame, &sink->info, buf, GST_MAP_READ);
+
+  bytes_per_pixel = (sink->has_alpha) ? 4 : 3;
+
+  /* last row needn't have row padding */
+  minsize = (GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) *
+      (GST_VIDEO_SINK_HEIGHT (sink) - 1)) +
+      (bytes_per_pixel * GST_VIDEO_SINK_WIDTH (sink));
+
+  g_return_val_if_fail (gst_buffer_get_size (buf) >= minsize, NULL);
+
+  gst_buffer_ref (buf);
+  pix = gdk_pixbuf_new_from_data (GST_VIDEO_FRAME_COMP_DATA (frame, 0),
+      GDK_COLORSPACE_RGB, sink->has_alpha, 8, GST_VIDEO_SINK_WIDTH (sink),
+      GST_VIDEO_SINK_HEIGHT (sink), GST_VIDEO_FRAME_COMP_STRIDE (frame, 0),
+      (GdkPixbufDestroyNotify) gst_gdk_pixbuf_sink_pixbuf_destroy_notify,
+      frame);
+
+  return pix;
+}
+
+static GstFlowReturn
+gst_gdk_pixbuf_sink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf,
+    const gchar * msg_name)
+{
+  GstGdkPixbufSink *sink;
+  GdkPixbuf *pixbuf;
+  gboolean do_post;
+
+  sink = GST_GDK_PIXBUF_SINK (basesink);
+
+  pixbuf = gst_gdk_pixbuf_sink_get_pixbuf_from_buffer (sink, buf);
+
+  GST_OBJECT_LOCK (sink);
+
+  do_post = sink->post_messages;
+
+  if (sink->last_pixbuf)
+    g_object_unref (sink->last_pixbuf);
+
+  sink->last_pixbuf = pixbuf;   /* take ownership */
+
+  GST_OBJECT_UNLOCK (sink);
+
+  if (G_UNLIKELY (pixbuf == NULL))
+    goto error;
+
+  if (do_post) {
+    GstStructure *s;
+    GstMessage *msg;
+    GstFormat format;
+    GstClockTime timestamp;
+    GstClockTime running_time, stream_time;
+
+    GstSegment *segment = &basesink->segment;
+    format = segment->format;
+
+    timestamp = GST_BUFFER_PTS (buf);
+    running_time = gst_segment_to_running_time (segment, format, timestamp);
+    stream_time = gst_segment_to_stream_time (segment, format, timestamp);
+
+    /* it's okay to keep using pixbuf here, we can be sure no one is going to
+     * unref or change sink->last_pixbuf before we return from this function.
+     * The structure will take its own ref to the pixbuf. */
+    s = gst_structure_new (msg_name,
+        "pixbuf", GDK_TYPE_PIXBUF, pixbuf,
+        "pixel-aspect-ratio", GST_TYPE_FRACTION, sink->par_n, sink->par_d,
+        "timestamp", G_TYPE_UINT64, timestamp,
+        "stream-time", G_TYPE_UINT64, stream_time,
+        "running-time", G_TYPE_UINT64, running_time, NULL);
+
+    msg = gst_message_new_element (GST_OBJECT_CAST (sink), s);
+    gst_element_post_message (GST_ELEMENT_CAST (sink), msg);
+  }
+
+  g_object_notify (G_OBJECT (sink), "last-pixbuf");
+
+  return GST_FLOW_OK;
+
+/* ERRORS */
+error:
+  {
+    /* This shouldn't really happen */
+    GST_ELEMENT_ERROR (sink, LIBRARY, FAILED,
+        ("Couldn't create pixbuf from RGB image."),
+        ("Probably not enough free memory"));
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstFlowReturn
+gst_gdk_pixbuf_sink_preroll (GstBaseSink * basesink, GstBuffer * buf)
+{
+  return gst_gdk_pixbuf_sink_handle_buffer (basesink, buf, "preroll-pixbuf");
+}
+
+static GstFlowReturn
+gst_gdk_pixbuf_sink_render (GstBaseSink * basesink, GstBuffer * buf)
+{
+  return gst_gdk_pixbuf_sink_handle_buffer (basesink, buf, "pixbuf");
+}
+
+static void
+gst_gdk_pixbuf_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstGdkPixbufSink *sink;
+
+  sink = GST_GDK_PIXBUF_SINK (object);
+
+  switch (prop_id) {
+    case PROP_POST_MESSAGES:
+      GST_OBJECT_LOCK (sink);
+      sink->post_messages = g_value_get_boolean (value);
+      GST_OBJECT_UNLOCK (sink);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gdk_pixbuf_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstGdkPixbufSink *sink;
+
+  sink = GST_GDK_PIXBUF_SINK (object);
+
+  switch (prop_id) {
+    case PROP_POST_MESSAGES:
+      GST_OBJECT_LOCK (sink);
+      g_value_set_boolean (value, sink->post_messages);
+      GST_OBJECT_UNLOCK (sink);
+      break;
+    case PROP_LAST_PIXBUF:
+      GST_OBJECT_LOCK (sink);
+      g_value_set_object (value, sink->last_pixbuf);
+      GST_OBJECT_UNLOCK (sink);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/ext/gdk_pixbuf/gstgdkpixbufsink.h b/ext/gdk_pixbuf/gstgdkpixbufsink.h
new file mode 100644
index 0000000..964437a
--- /dev/null
+++ b/ext/gdk_pixbuf/gstgdkpixbufsink.h
@@ -0,0 +1,75 @@
+/* GStreamer GdkPixbuf sink
+ * Copyright (C) 2006-2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GST_GDK_PIXBUF_SINK_H
+#define GST_GDK_PIXBUF_SINK_H
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideosink.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define GST_TYPE_GDK_PIXBUF_SINK            (gst_gdk_pixbuf_sink_get_type())
+#define GST_GDK_PIXBUF_SINK(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GDK_PIXBUF_SINK,GstGdkPixbufSink))
+#define GST_GDK_PIXBUF_SINK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GDK_PIXBUF_SINK,GstGdkPixbufSinkClass))
+#define GST_IS_GDK_PIXBUF_SINK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GDK_PIXBUF_SINK))
+#define GST_IS_GDK_PIXBUF_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GDK_PIXBUF_SINK))
+
+typedef struct _GstGdkPixbufSink       GstGdkPixbufSink;
+typedef struct _GstGdkPixbufSinkClass  GstGdkPixbufSinkClass;
+
+/**
+ * GstGdkPixbufSink:
+ *
+ * Opaque element structure.
+ */
+struct _GstGdkPixbufSink
+{
+  GstVideoSink  basesink;
+
+  /*< private >*/
+
+  /* current caps */
+  GstVideoInfo info;
+  gint         width;
+  gint         height;
+  gint         par_n;
+  gint         par_d;
+  gboolean     has_alpha;
+
+  /* properties */
+  gboolean     post_messages;
+  GdkPixbuf  * last_pixbuf;
+};
+
+/**
+ * GstGdkPixbufSinkClass:
+ *
+ * Opaque element class structure.
+ */
+struct _GstGdkPixbufSinkClass 
+{
+  GstVideoSinkClass  basesinkclass;
+};
+
+GType   gst_gdk_pixbuf_sink_get_type (void);
+
+#endif /* GST_GDK_PIXBUF_SINK_H */
+
diff --git a/ext/gdk_pixbuf/meson.build b/ext/gdk_pixbuf/meson.build
new file mode 100644
index 0000000..0079a9d
--- /dev/null
+++ b/ext/gdk_pixbuf/meson.build
@@ -0,0 +1,20 @@
+pixbuf_sources = [
+  'gstgdkpixbufdec.c',
+  'gstgdkpixbufoverlay.c',
+  'gstgdkpixbufplugin.c',
+  'gstgdkpixbufsink.c',
+]
+
+gdkpixbuf_dep = dependency('gdk-pixbuf-2.0', version : '>=2.8.0', required : false)
+
+if gdkpixbuf_dep.found()
+  gstgdkpixbuf = library('gstgdkpixbuf',
+    pixbuf_sources,
+    c_args : gst_plugins_good_args,
+    link_args : noseh_link_args,
+    include_directories : [configinc],
+    dependencies : [gstbase_dep, gstvideo_dep, gstcontroller_dep, gdkpixbuf_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/ext/jack/.gitignore b/ext/jack/.gitignore
new file mode 100644
index 0000000..916f265
--- /dev/null
+++ b/ext/jack/.gitignore
@@ -0,0 +1 @@
+*.loT
diff --git a/ext/jack/Makefile.am b/ext/jack/Makefile.am
new file mode 100644
index 0000000..a8ef27a
--- /dev/null
+++ b/ext/jack/Makefile.am
@@ -0,0 +1,9 @@
+
+plugin_LTLIBRARIES = libgstjack.la
+
+libgstjack_la_SOURCES = gstjackutil.c gstjack.c gstjackaudiosrc.c gstjackaudiosink.c gstjackaudioclient.c
+libgstjack_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(JACK_CFLAGS)
+libgstjack_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(JACK_LIBS)
+libgstjack_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstjackutil.h gstjackaudiosrc.h gstjackaudiosink.h gstjackaudioclient.h gstjack.h gstjackringbuffer.h
diff --git a/ext/jack/gstjack.c b/ext/jack/gstjack.c
new file mode 100644
index 0000000..ca98dc4
--- /dev/null
+++ b/ext/jack/gstjack.c
@@ -0,0 +1,117 @@
+/* GStreamer Jack plugins
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstjack.h"
+#include "gstjackaudiosrc.h"
+#include "gstjackaudiosink.h"
+
+GType
+gst_jack_connect_get_type (void)
+{
+  static volatile gsize jack_connect_type = 0;
+
+  if (g_once_init_enter (&jack_connect_type)) {
+    static const GEnumValue jack_connect_enums[] = {
+      {GST_JACK_CONNECT_NONE,
+          "Don't automatically connect ports to physical ports", "none"},
+      {GST_JACK_CONNECT_AUTO,
+          "Automatically connect ports to physical ports", "auto"},
+      {GST_JACK_CONNECT_AUTO_FORCED,
+            "Automatically connect ports to as many physical ports as possible",
+          "auto-forced"},
+      {0, NULL, NULL},
+    };
+    GType tmp = g_enum_register_static ("GstJackConnect", jack_connect_enums);
+    g_once_init_leave (&jack_connect_type, tmp);
+  }
+  return (GType) jack_connect_type;
+}
+
+GType
+gst_jack_transport_get_type (void)
+{
+  static volatile gsize type = 0;
+
+  if (g_once_init_enter (&type)) {
+    static const GFlagsValue flag_values[] = {
+      {GST_JACK_TRANSPORT_MASTER,
+          "Start and stop transport with state changes", "master"},
+      {GST_JACK_TRANSPORT_SLAVE,
+          "Follow transport state changes", "slave"},
+      {0, NULL, NULL},
+    };
+    GType tmp = g_flags_register_static ("GstJackTransport", flag_values);
+    g_once_init_leave (&type, tmp);
+  }
+  return (GType) type;
+}
+
+
+static gpointer
+gst_jack_client_copy (gpointer jclient)
+{
+  return jclient;
+}
+
+
+static void
+gst_jack_client_free (gpointer jclient)
+{
+  return;
+}
+
+
+GType
+gst_jack_client_get_type (void)
+{
+  static volatile gsize jack_client_type = 0;
+
+  if (g_once_init_enter (&jack_client_type)) {
+    /* hackish, but makes it show up nicely in gst-inspect */
+    GType tmp = g_boxed_type_register_static ("JackClient",
+        (GBoxedCopyFunc) gst_jack_client_copy,
+        (GBoxedFreeFunc) gst_jack_client_free);
+    g_once_init_leave (&jack_client_type, tmp);
+  }
+
+  return (GType) jack_client_type;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "jackaudiosrc", GST_RANK_PRIMARY,
+          GST_TYPE_JACK_AUDIO_SRC))
+    return FALSE;
+  if (!gst_element_register (plugin, "jackaudiosink", GST_RANK_PRIMARY,
+          GST_TYPE_JACK_AUDIO_SINK))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    jack,
+    "JACK audio elements",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/jack/gstjack.h b/ext/jack/gstjack.h
new file mode 100644
index 0000000..15b040e
--- /dev/null
+++ b/ext/jack/gstjack.h
@@ -0,0 +1,79 @@
+/* GStreamer
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ *
+ * gstjack.h:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GST_JACK_H_
+#define _GST_JACK_H_
+
+#include <jack/jack.h>
+#include <gst/audio/audio.h>
+
+/**
+ * GstJackConnect:
+ * @GST_JACK_CONNECT_NONE: Don't automatically connect to physical ports.
+ *     In this mode, the element will accept any number of input channels and will
+ *     create (but not connect) an output port for each channel.
+ * @GST_JACK_CONNECT_AUTO: In this mode, the element will try to connect each
+ *     output port to a random physical jack input pin. The sink will
+ *     expose the number of physical channels on its pad caps.
+ * @GST_JACK_CONNECT_AUTO_FORCED: In this mode, the element will try to connect each
+ *     output port to a random physical jack input pin. The  element will accept any number
+ *     of input channels.
+ *
+ * Specify how the output ports will be connected.
+ */
+typedef enum {
+  GST_JACK_CONNECT_NONE,
+  GST_JACK_CONNECT_AUTO,
+  GST_JACK_CONNECT_AUTO_FORCED
+} GstJackConnect;
+
+/**
+ * GstJackTransport:
+ * @GST_JACK_TRANSPORT_AUTONOMOUS: no transport support
+ * @GST_JACK_TRANSPORT_MASTER: start and stop transport with state-changes
+ * @GST_JACK_TRANSPORT_SLAVE: follow transport state changes
+ *
+ * The jack transport state allow to sync multiple clients. This enum defines a
+ * client behaviour regarding to the transport mechanism.
+ */
+typedef enum {
+  GST_JACK_TRANSPORT_AUTONOMOUS = 0,
+  GST_JACK_TRANSPORT_MASTER = (1 << 0),
+  GST_JACK_TRANSPORT_SLAVE = (1 << 1),
+} GstJackTransport;
+
+typedef jack_default_audio_sample_t sample_t;
+
+#define GST_TYPE_JACK_CONNECT   (gst_jack_connect_get_type ())
+#define GST_TYPE_JACK_TRANSPORT (gst_jack_transport_get_type ())
+#define GST_TYPE_JACK_CLIENT    (gst_jack_client_get_type ())
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define GST_JACK_FORMAT_STR "F32LE"
+#else
+#define GST_JACK_FORMAT_STR "F32BE"
+#endif
+
+GType gst_jack_client_get_type(void);
+GType gst_jack_connect_get_type(void);
+GType gst_jack_transport_get_type(void);
+
+#endif  // _GST_JACK_H_
diff --git a/ext/jack/gstjackaudioclient.c b/ext/jack/gstjackaudioclient.c
new file mode 100644
index 0000000..19022c0
--- /dev/null
+++ b/ext/jack/gstjackaudioclient.c
@@ -0,0 +1,637 @@
+/* GStreamer
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ *
+ * gstjackaudioclient.c: jack audio client implementation
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+
+#include "gstjackaudioclient.h"
+#include "gstjack.h"
+
+#include <gst/glib-compat-private.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_jack_audio_client_debug);
+#define GST_CAT_DEFAULT gst_jack_audio_client_debug
+
+static void
+jack_log_error (const gchar * msg)
+{
+  GST_ERROR ("%s", msg);
+}
+
+static void
+jack_info_error (const gchar * msg)
+{
+  GST_INFO ("%s", msg);
+}
+
+void
+gst_jack_audio_client_init (void)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_jack_audio_client_debug, "jackclient", 0,
+      "jackclient helpers");
+
+  jack_set_error_function (jack_log_error);
+  jack_set_info_function (jack_info_error);
+}
+
+/* a list of global connections indexed by id and server. */
+G_LOCK_DEFINE_STATIC (connections_lock);
+static GList *connections;
+
+/* the connection to a server  */
+typedef struct
+{
+  gint refcount;
+  GMutex lock;
+  GCond flush_cond;
+
+  /* id/server pair and the connection */
+  gchar *id;
+  gchar *server;
+  jack_client_t *client;
+
+  /* lists of GstJackAudioClients */
+  gint n_clients;
+  GList *src_clients;
+  GList *sink_clients;
+
+  /* transport state handling */
+  gint cur_ts;
+  GstState transport_state;
+} GstJackAudioConnection;
+
+/* an object sharing a jack_client_t connection. */
+struct _GstJackAudioClient
+{
+  GstJackAudioConnection *conn;
+
+  GstJackClientType type;
+  gboolean active;
+  gboolean deactivate;
+  gboolean server_down;
+
+  JackShutdownCallback shutdown;
+  JackProcessCallback process;
+  JackBufferSizeCallback buffer_size;
+  JackSampleRateCallback sample_rate;
+  gpointer user_data;
+};
+
+typedef struct
+{
+  jack_nframes_t nframes;
+  gpointer user_data;
+} JackCB;
+
+static gboolean
+jack_handle_transport_change (GstJackAudioClient * client, GstState state)
+{
+  GstObject *obj = GST_OBJECT_PARENT (client->user_data);
+  guint mode;
+
+  g_object_get (obj, "transport", &mode, NULL);
+  if ((mode & GST_JACK_TRANSPORT_SLAVE) && (GST_STATE (obj) != state)) {
+    GST_INFO_OBJECT (obj, "requesting state change: %s",
+        gst_element_state_get_name (state));
+    gst_element_post_message (GST_ELEMENT (obj),
+        gst_message_new_request_state (obj, state));
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static int
+jack_process_cb (jack_nframes_t nframes, void *arg)
+{
+  GstJackAudioConnection *conn = (GstJackAudioConnection *) arg;
+  GList *walk;
+  int res = 0;
+  jack_transport_state_t ts = jack_transport_query (conn->client, NULL);
+
+  if (ts != conn->cur_ts) {
+    conn->cur_ts = ts;
+    switch (ts) {
+      case JackTransportStopped:
+        GST_DEBUG ("transport state is 'stopped'");
+        conn->transport_state = GST_STATE_PAUSED;
+        break;
+      case JackTransportStarting:
+        GST_DEBUG ("transport state is 'starting'");
+        conn->transport_state = GST_STATE_READY;
+        break;
+      case JackTransportRolling:
+        GST_DEBUG ("transport state is 'rolling'");
+        conn->transport_state = GST_STATE_PLAYING;
+        break;
+      default:
+        break;
+    }
+    GST_DEBUG ("num of clients: src=%d, sink=%d",
+        g_list_length (conn->src_clients), g_list_length (conn->sink_clients));
+  }
+
+  g_mutex_lock (&conn->lock);
+  /* call sources first, then sinks. Sources will either push data into the
+   * ringbuffer of the sinks, which will then pull the data out of it, or
+   * sinks will pull the data from the sources. */
+  for (walk = conn->src_clients; walk; walk = g_list_next (walk)) {
+    GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
+
+    /* only call active clients */
+    if ((client->active || client->deactivate) && client->process) {
+      res = client->process (nframes, client->user_data);
+      if (client->deactivate) {
+        client->deactivate = FALSE;
+        g_cond_signal (&conn->flush_cond);
+      }
+    }
+  }
+  for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) {
+    GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
+
+    /* only call active clients */
+    if ((client->active || client->deactivate) && client->process) {
+      res = client->process (nframes, client->user_data);
+      if (client->deactivate) {
+        client->deactivate = FALSE;
+        g_cond_signal (&conn->flush_cond);
+      }
+    }
+  }
+
+  /* handle transport state requisition, do sinks first, stop after the first
+   * element that handled it */
+  if (conn->transport_state != GST_STATE_VOID_PENDING) {
+    for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) {
+      if (jack_handle_transport_change ((GstJackAudioClient *) walk->data,
+              conn->transport_state)) {
+        conn->transport_state = GST_STATE_VOID_PENDING;
+        break;
+      }
+    }
+  }
+  if (conn->transport_state != GST_STATE_VOID_PENDING) {
+    for (walk = conn->src_clients; walk; walk = g_list_next (walk)) {
+      if (jack_handle_transport_change ((GstJackAudioClient *) walk->data,
+              conn->transport_state)) {
+        conn->transport_state = GST_STATE_VOID_PENDING;
+        break;
+      }
+    }
+  }
+  g_mutex_unlock (&conn->lock);
+
+  return res;
+}
+
+static void
+jack_shutdown_cb (void *arg)
+{
+  GstJackAudioConnection *conn = (GstJackAudioConnection *) arg;
+  GList *walk;
+
+  GST_DEBUG ("disconnect client %s from server %s", conn->id,
+      GST_STR_NULL (conn->server));
+
+  g_mutex_lock (&conn->lock);
+  for (walk = conn->src_clients; walk; walk = g_list_next (walk)) {
+    GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
+
+    client->server_down = TRUE;
+    g_cond_signal (&conn->flush_cond);
+    if (client->shutdown)
+      client->shutdown (client->user_data);
+  }
+  for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) {
+    GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
+
+    client->server_down = TRUE;
+    g_cond_signal (&conn->flush_cond);
+    if (client->shutdown)
+      client->shutdown (client->user_data);
+  }
+  g_mutex_unlock (&conn->lock);
+}
+
+/* we error out */
+static int
+jack_sample_rate_cb (jack_nframes_t nframes, void *arg)
+{
+  jack_shutdown_cb (arg);
+  return 0;
+}
+
+/* we error out */
+static int
+jack_buffer_size_cb (jack_nframes_t nframes, void *arg)
+{
+  jack_shutdown_cb (arg);
+  return 0;
+}
+
+typedef struct
+{
+  const gchar *id;
+  const gchar *server;
+} FindData;
+
+static gint
+connection_find (GstJackAudioConnection * conn, FindData * data)
+{
+  /* id's must match */
+  if (strcmp (conn->id, data->id))
+    return 1;
+
+  /* both the same or NULL */
+  if (conn->server == data->server)
+    return 0;
+
+  /* we cannot compare NULL */
+  if (conn->server == NULL || data->server == NULL)
+    return 1;
+
+  if (strcmp (conn->server, data->server))
+    return 1;
+
+  return 0;
+}
+
+/* make a connection with @id and @server. Returns NULL on failure with the
+ * status set. */
+static GstJackAudioConnection *
+gst_jack_audio_make_connection (const gchar * id, const gchar * server,
+    jack_client_t * jclient, jack_status_t * status)
+{
+  GstJackAudioConnection *conn;
+  jack_options_t options;
+  gint res;
+
+  *status = 0;
+
+  GST_DEBUG ("new client %s, connecting to server %s", id,
+      GST_STR_NULL (server));
+
+  /* never start a server */
+  options = JackNoStartServer;
+  /* if we have a servername, use it */
+  if (server != NULL)
+    options |= JackServerName;
+  /* open the client */
+  if (jclient == NULL)
+    jclient = jack_client_open (id, options, status, server);
+  if (jclient == NULL)
+    goto could_not_open;
+
+  /* now create object */
+  conn = g_new (GstJackAudioConnection, 1);
+  conn->refcount = 1;
+  g_mutex_init (&conn->lock);
+  g_cond_init (&conn->flush_cond);
+  conn->id = g_strdup (id);
+  conn->server = g_strdup (server);
+  conn->client = jclient;
+  conn->n_clients = 0;
+  conn->src_clients = NULL;
+  conn->sink_clients = NULL;
+  conn->cur_ts = -1;
+  conn->transport_state = GST_STATE_VOID_PENDING;
+
+  /* set our callbacks  */
+  jack_set_process_callback (jclient, jack_process_cb, conn);
+  /* these callbacks cause us to error */
+  jack_set_buffer_size_callback (jclient, jack_buffer_size_cb, conn);
+  jack_set_sample_rate_callback (jclient, jack_sample_rate_cb, conn);
+  jack_on_shutdown (jclient, jack_shutdown_cb, conn);
+
+  /* all callbacks are set, activate the client */
+  GST_INFO ("activate jack_client %p", jclient);
+  if ((res = jack_activate (jclient)))
+    goto could_not_activate;
+
+  GST_DEBUG ("opened connection %p", conn);
+
+  return conn;
+
+  /* ERRORS */
+could_not_open:
+  {
+    GST_DEBUG ("failed to open jack client, %d", *status);
+    return NULL;
+  }
+could_not_activate:
+  {
+    GST_ERROR ("Could not activate client (%d)", res);
+    *status = JackFailure;
+    g_mutex_clear (&conn->lock);
+    g_free (conn->id);
+    g_free (conn->server);
+    g_free (conn);
+    return NULL;
+  }
+}
+
+static GstJackAudioConnection *
+gst_jack_audio_get_connection (const gchar * id, const gchar * server,
+    jack_client_t * jclient, jack_status_t * status)
+{
+  GstJackAudioConnection *conn;
+  GList *found;
+  FindData data;
+
+  GST_DEBUG ("getting connection for id %s, server %s", id,
+      GST_STR_NULL (server));
+
+  data.id = id;
+  data.server = server;
+
+  G_LOCK (connections_lock);
+  found =
+      g_list_find_custom (connections, &data, (GCompareFunc) connection_find);
+  if (found != NULL && jclient != NULL) {
+    /* we found it, increase refcount and return it */
+    conn = (GstJackAudioConnection *) found->data;
+    conn->refcount++;
+
+    GST_DEBUG ("found connection %p", conn);
+  } else {
+    /* make new connection */
+    conn = gst_jack_audio_make_connection (id, server, jclient, status);
+    if (conn != NULL) {
+      GST_DEBUG ("created connection %p", conn);
+      /* add to list on success */
+      connections = g_list_prepend (connections, conn);
+    } else {
+      GST_WARNING ("could not create connection");
+    }
+  }
+  G_UNLOCK (connections_lock);
+
+  return conn;
+}
+
+static void
+gst_jack_audio_unref_connection (GstJackAudioConnection * conn)
+{
+  gint res;
+  gboolean zero;
+
+  GST_DEBUG ("unref connection %p refcnt %d", conn, conn->refcount);
+
+  G_LOCK (connections_lock);
+  conn->refcount--;
+  if ((zero = (conn->refcount == 0))) {
+    GST_DEBUG ("closing connection %p", conn);
+    /* remove from list, we can release the mutex after removing the connection
+     * from the list because after that, nobody can access the connection anymore. */
+    connections = g_list_remove (connections, conn);
+  }
+  G_UNLOCK (connections_lock);
+
+  /* if we are zero, close and cleanup the connection */
+  if (zero) {
+    /* don't use conn->lock here. two reasons:
+     *
+     *  1) its not necessary: jack_deactivate() will not return until the JACK thread
+     *      associated with this connection is cleaned up by a thread join, hence 
+     *      no more callbacks can occur or be in progress.
+     *
+     * 2) it would deadlock anyway, because jack_deactivate() will sleep
+     *      waiting for the JACK thread, and can thus cause deadlock in 
+     *      jack_process_cb()
+     */
+    GST_INFO ("deactivate jack_client %p", conn->client);
+    if ((res = jack_deactivate (conn->client))) {
+      /* we only warn, this means the server is probably shut down and the client
+       * is gone anyway. */
+      GST_WARNING ("Could not deactivate Jack client (%d)", res);
+    }
+    /* close connection */
+    if ((res = jack_client_close (conn->client))) {
+      /* we assume the client is gone. */
+      GST_WARNING ("close failed (%d)", res);
+    }
+
+    /* free resources */
+    g_mutex_clear (&conn->lock);
+    g_cond_clear (&conn->flush_cond);
+    g_free (conn->id);
+    g_free (conn->server);
+    g_free (conn);
+  }
+}
+
+static void
+gst_jack_audio_connection_add_client (GstJackAudioConnection * conn,
+    GstJackAudioClient * client)
+{
+  g_mutex_lock (&conn->lock);
+  switch (client->type) {
+    case GST_JACK_CLIENT_SOURCE:
+      conn->src_clients = g_list_append (conn->src_clients, client);
+      conn->n_clients++;
+      break;
+    case GST_JACK_CLIENT_SINK:
+      conn->sink_clients = g_list_append (conn->sink_clients, client);
+      conn->n_clients++;
+      break;
+    default:
+      g_warning ("trying to add unknown client type");
+      break;
+  }
+  g_mutex_unlock (&conn->lock);
+}
+
+static void
+gst_jack_audio_connection_remove_client (GstJackAudioConnection * conn,
+    GstJackAudioClient * client)
+{
+  g_mutex_lock (&conn->lock);
+  switch (client->type) {
+    case GST_JACK_CLIENT_SOURCE:
+      conn->src_clients = g_list_remove (conn->src_clients, client);
+      conn->n_clients--;
+      break;
+    case GST_JACK_CLIENT_SINK:
+      conn->sink_clients = g_list_remove (conn->sink_clients, client);
+      conn->n_clients--;
+      break;
+    default:
+      g_warning ("trying to remove unknown client type");
+      break;
+  }
+  g_mutex_unlock (&conn->lock);
+}
+
+/**
+ * gst_jack_audio_client_get:
+ * @id: the client id
+ * @server: the server to connect to or NULL for the default server
+ * @type: the client type
+ * @shutdown: a callback when the jack server shuts down
+ * @process: a callback when samples are available
+ * @buffer_size: a callback when the buffer_size changes
+ * @sample_rate: a callback when the sample_rate changes
+ * @user_data: user data passed to the callbacks
+ * @status: pointer to hold the jack status code in case of errors
+ *
+ * Get the jack client connection for @id and @server. Connections to the same
+ * @id and @server will receive the same physical Jack client connection and
+ * will therefore be scheduled in the same process callback.
+ * 
+ * Returns: a #GstJackAudioClient.
+ */
+GstJackAudioClient *
+gst_jack_audio_client_new (const gchar * id, const gchar * server,
+    jack_client_t * jclient, GstJackClientType type,
+    void (*shutdown) (void *arg), JackProcessCallback process,
+    JackBufferSizeCallback buffer_size, JackSampleRateCallback sample_rate,
+    gpointer user_data, jack_status_t * status)
+{
+  GstJackAudioClient *client;
+  GstJackAudioConnection *conn;
+
+  g_return_val_if_fail (id != NULL, NULL);
+  g_return_val_if_fail (status != NULL, NULL);
+
+  /* first get a connection for the id/server pair */
+  conn = gst_jack_audio_get_connection (id, server, jclient, status);
+  if (conn == NULL)
+    goto no_connection;
+
+  GST_INFO ("new client %s", id);
+
+  /* make new client using the connection */
+  client = g_new (GstJackAudioClient, 1);
+  client->active = client->deactivate = FALSE;
+  client->conn = conn;
+  client->type = type;
+  client->shutdown = shutdown;
+  client->process = process;
+  client->buffer_size = buffer_size;
+  client->sample_rate = sample_rate;
+  client->user_data = user_data;
+  client->server_down = FALSE;
+
+  /* add the client to the connection */
+  gst_jack_audio_connection_add_client (conn, client);
+
+  return client;
+
+  /* ERRORS */
+no_connection:
+  {
+    GST_DEBUG ("Could not get server connection (%d)", *status);
+    return NULL;
+  }
+}
+
+/**
+ * gst_jack_audio_client_free:
+ * @client: a #GstJackAudioClient
+ *
+ * Free the resources used by @client.
+ */
+void
+gst_jack_audio_client_free (GstJackAudioClient * client)
+{
+  GstJackAudioConnection *conn;
+
+  g_return_if_fail (client != NULL);
+
+  GST_INFO ("free client");
+
+  conn = client->conn;
+
+  /* remove from connection first so that it's not scheduled anymore after this
+   * call */
+  gst_jack_audio_connection_remove_client (conn, client);
+  gst_jack_audio_unref_connection (conn);
+
+  g_free (client);
+}
+
+/**
+ * gst_jack_audio_client_get_client:
+ * @client: a #GstJackAudioClient
+ *
+ * Get the jack audio client for @client. This function is used to perform
+ * operations on the jack server from this client.
+ *
+ * Returns: The jack audio client.
+ */
+jack_client_t *
+gst_jack_audio_client_get_client (GstJackAudioClient * client)
+{
+  g_return_val_if_fail (client != NULL, NULL);
+
+  /* no lock needed, the connection and the client does not change 
+   * once the client is created. */
+  return client->conn->client;
+}
+
+/**
+ * gst_jack_audio_client_set_active:
+ * @client: a #GstJackAudioClient
+ * @active: new mode for the client
+ *
+ * Activate or deactive @client. When a client is activated it will receive
+ * callbacks when data should be processed.
+ *
+ * Returns: 0 if all ok.
+ */
+gint
+gst_jack_audio_client_set_active (GstJackAudioClient * client, gboolean active)
+{
+  g_return_val_if_fail (client != NULL, -1);
+
+  /* make sure that we are not dispatching the client */
+  g_mutex_lock (&client->conn->lock);
+  if (client->active && !active) {
+    /* we need to process once more to flush the port */
+    client->deactivate = TRUE;
+
+    /* need to wait for process_cb run once more */
+    while (client->deactivate && !client->server_down)
+      g_cond_wait (&client->conn->flush_cond, &client->conn->lock);
+  }
+  client->active = active;
+  g_mutex_unlock (&client->conn->lock);
+
+  return 0;
+}
+
+/**
+ * gst_jack_audio_client_get_transport_state:
+ * @client: a #GstJackAudioClient
+ *
+ * Check the current transport state. The client can use this to request a state
+ * change from the application.
+ *
+ * Returns: the state, %GST_STATE_VOID_PENDING for no change in the transport
+ * state
+ */
+GstState
+gst_jack_audio_client_get_transport_state (GstJackAudioClient * client)
+{
+  GstState state = client->conn->transport_state;
+
+  client->conn->transport_state = GST_STATE_VOID_PENDING;
+  return state;
+}
diff --git a/ext/jack/gstjackaudioclient.h b/ext/jack/gstjackaudioclient.h
new file mode 100644
index 0000000..5dcd70c
--- /dev/null
+++ b/ext/jack/gstjackaudioclient.h
@@ -0,0 +1,61 @@
+/* GStreamer
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ *
+ * gstjackaudioclient.h:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_JACK_AUDIO_CLIENT_H__
+#define __GST_JACK_AUDIO_CLIENT_H__
+
+#include <jack/jack.h>
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef enum 
+{
+  GST_JACK_CLIENT_SOURCE,
+  GST_JACK_CLIENT_SINK
+} GstJackClientType;
+
+typedef struct _GstJackAudioClient GstJackAudioClient;
+
+void                  gst_jack_audio_client_init           (void);
+
+
+GstJackAudioClient *  gst_jack_audio_client_new            (const gchar *id, const gchar *server,
+                                                            jack_client_t *jclient,
+                                                            GstJackClientType type,
+                                                            void (*shutdown) (void *arg),
+                                                            JackProcessCallback    process,
+                                                            JackBufferSizeCallback buffer_size,
+                                                            JackSampleRateCallback sample_rate,
+							    gpointer user_data,
+							    jack_status_t *status);
+void                  gst_jack_audio_client_free           (GstJackAudioClient *client);
+
+jack_client_t *       gst_jack_audio_client_get_client     (GstJackAudioClient *client);
+
+gboolean              gst_jack_audio_client_set_active     (GstJackAudioClient *client, gboolean active);
+
+GstState              gst_jack_audio_client_get_transport_state (GstJackAudioClient *client);
+
+G_END_DECLS
+
+#endif /* __GST_JACK_AUDIO_CLIENT_H__ */
diff --git a/ext/jack/gstjackaudiosink.c b/ext/jack/gstjackaudiosink.c
new file mode 100644
index 0000000..4f49f25
--- /dev/null
+++ b/ext/jack/gstjackaudiosink.c
@@ -0,0 +1,973 @@
+/* GStreamer
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ *
+ * gstjackaudiosink.c: jack audio sink implementation
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-jackaudiosink
+ * @see_also: #GstAudioBaseSink, #GstAudioRingBuffer
+ *
+ * A Sink that outputs data to Jack ports.
+ * 
+ * It will create N Jack ports named out_&lt;name&gt;_&lt;num&gt; where 
+ * &lt;name&gt; is the element name and &lt;num&gt; is starting from 1.
+ * Each port corresponds to a gstreamer channel.
+ * 
+ * The samplerate as exposed on the caps is always the same as the samplerate of
+ * the jack server.
+ * 
+ * When the #GstJackAudioSink:connect property is set to auto, this element
+ * will try to connect each output port to a random physical jack input pin. In
+ * this mode, the sink will expose the number of physical channels on its pad
+ * caps.
+ * 
+ * When the #GstJackAudioSink:connect property is set to none, the element will
+ * accept any number of input channels and will create (but not connect) an
+ * output port for each channel.
+ * 
+ * The element will generate an error when the Jack server is shut down when it
+ * was PAUSED or PLAYING. This element does not support dynamic rate and buffer
+ * size changes at runtime.
+ * 
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc ! jackaudiosink
+ * ]| Play a sine wave to using jack.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst-i18n-plugin.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gst/audio/audio.h>
+
+#include "gstjackaudiosink.h"
+#include "gstjackringbuffer.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_jack_audio_sink_debug);
+#define GST_CAT_DEFAULT gst_jack_audio_sink_debug
+
+static gboolean
+gst_jack_audio_sink_allocate_channels (GstJackAudioSink * sink, gint channels)
+{
+  jack_client_t *client;
+
+  client = gst_jack_audio_client_get_client (sink->client);
+
+  /* remove ports we don't need */
+  while (sink->port_count > channels) {
+    jack_port_unregister (client, sink->ports[--sink->port_count]);
+  }
+
+  /* alloc enough output ports */
+  sink->ports = g_realloc (sink->ports, sizeof (jack_port_t *) * channels);
+  sink->buffers = g_realloc (sink->buffers, sizeof (sample_t *) * channels);
+
+  /* create an output port for each channel */
+  while (sink->port_count < channels) {
+    gchar *name;
+
+    /* port names start from 1 and are local to the element */
+    name =
+        g_strdup_printf ("out_%s_%d", GST_ELEMENT_NAME (sink),
+        sink->port_count + 1);
+    sink->ports[sink->port_count] =
+        jack_port_register (client, name, JACK_DEFAULT_AUDIO_TYPE,
+        JackPortIsOutput, 0);
+    if (sink->ports[sink->port_count] == NULL)
+      return FALSE;
+
+    sink->port_count++;
+
+    g_free (name);
+  }
+  return TRUE;
+}
+
+static void
+gst_jack_audio_sink_free_channels (GstJackAudioSink * sink)
+{
+  gint res, i = 0;
+  jack_client_t *client;
+
+  client = gst_jack_audio_client_get_client (sink->client);
+
+  /* get rid of all ports */
+  while (sink->port_count) {
+    GST_LOG_OBJECT (sink, "unregister port %d", i);
+    if ((res = jack_port_unregister (client, sink->ports[i++]))) {
+      GST_DEBUG_OBJECT (sink, "unregister of port failed (%d)", res);
+    }
+    sink->port_count--;
+  }
+  g_free (sink->ports);
+  sink->ports = NULL;
+  g_free (sink->buffers);
+  sink->buffers = NULL;
+}
+
+/* ringbuffer abstract base class */
+static GType
+gst_jack_ring_buffer_get_type (void)
+{
+  static volatile gsize ringbuffer_type = 0;
+
+  if (g_once_init_enter (&ringbuffer_type)) {
+    static const GTypeInfo ringbuffer_info = {
+      sizeof (GstJackRingBufferClass),
+      NULL,
+      NULL,
+      (GClassInitFunc) gst_jack_ring_buffer_class_init,
+      NULL,
+      NULL,
+      sizeof (GstJackRingBuffer),
+      0,
+      (GInstanceInitFunc) gst_jack_ring_buffer_init,
+      NULL
+    };
+    GType tmp = g_type_register_static (GST_TYPE_AUDIO_RING_BUFFER,
+        "GstJackAudioSinkRingBuffer", &ringbuffer_info, 0);
+    g_once_init_leave (&ringbuffer_type, tmp);
+  }
+
+  return (GType) ringbuffer_type;
+}
+
+static void
+gst_jack_ring_buffer_class_init (GstJackRingBufferClass * klass)
+{
+  GstAudioRingBufferClass *gstringbuffer_class;
+
+  gstringbuffer_class = (GstAudioRingBufferClass *) klass;
+
+  ring_parent_class = g_type_class_peek_parent (klass);
+
+  gstringbuffer_class->open_device =
+      GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_open_device);
+  gstringbuffer_class->close_device =
+      GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_close_device);
+  gstringbuffer_class->acquire =
+      GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_acquire);
+  gstringbuffer_class->release =
+      GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_release);
+  gstringbuffer_class->start = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_start);
+  gstringbuffer_class->pause = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_pause);
+  gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_start);
+  gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_stop);
+
+  gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_delay);
+}
+
+/* this is the callback of jack. This should RT-safe.
+ */
+static int
+jack_process_cb (jack_nframes_t nframes, void *arg)
+{
+  GstJackAudioSink *sink;
+  GstAudioRingBuffer *buf;
+  gint readseg, len;
+  guint8 *readptr;
+  gint i, j, flen, channels;
+  sample_t *data;
+
+  buf = GST_AUDIO_RING_BUFFER_CAST (arg);
+  sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+  channels = GST_AUDIO_INFO_CHANNELS (&buf->spec.info);
+
+  /* get target buffers */
+  for (i = 0; i < channels; i++) {
+    sink->buffers[i] =
+        (sample_t *) jack_port_get_buffer (sink->ports[i], nframes);
+  }
+
+  if (gst_audio_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) {
+    flen = len / channels;
+
+    /* the number of samples must be exactly the segment size */
+    if (nframes * sizeof (sample_t) != flen)
+      goto wrong_size;
+
+    GST_DEBUG_OBJECT (sink, "copy %d frames: %p, %d bytes, %d channels",
+        nframes, readptr, flen, channels);
+    data = (sample_t *) readptr;
+
+    /* the samples in the ringbuffer have the channels interleaved, we need to
+     * deinterleave into the jack target buffers */
+    for (i = 0; i < nframes; i++) {
+      for (j = 0; j < channels; j++) {
+        sink->buffers[j][i] = *data++;
+      }
+    }
+
+    /* clear written samples in the ringbuffer */
+    gst_audio_ring_buffer_clear (buf, readseg);
+
+    /* we wrote one segment */
+    gst_audio_ring_buffer_advance (buf, 1);
+  } else {
+    GST_DEBUG_OBJECT (sink, "write %d frames silence", nframes);
+    /* We are not allowed to read from the ringbuffer, write silence to all
+     * jack output buffers */
+    for (i = 0; i < channels; i++) {
+      memset (sink->buffers[i], 0, nframes * sizeof (sample_t));
+    }
+  }
+  return 0;
+
+  /* ERRORS */
+wrong_size:
+  {
+    GST_ERROR_OBJECT (sink, "nbytes (%d) != flen (%d)",
+        (gint) (nframes * sizeof (sample_t)), flen);
+    return 1;
+  }
+}
+
+/* we error out */
+static int
+jack_sample_rate_cb (jack_nframes_t nframes, void *arg)
+{
+  GstJackAudioSink *sink;
+  GstJackRingBuffer *abuf;
+
+  abuf = GST_JACK_RING_BUFFER_CAST (arg);
+  sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (arg));
+
+  if (abuf->sample_rate != -1 && abuf->sample_rate != nframes)
+    goto not_supported;
+
+  return 0;
+
+  /* ERRORS */
+not_supported:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS,
+        (NULL), ("Jack changed the sample rate, which is not supported"));
+    return 1;
+  }
+}
+
+/* we error out */
+static int
+jack_buffer_size_cb (jack_nframes_t nframes, void *arg)
+{
+  GstJackAudioSink *sink;
+  GstJackRingBuffer *abuf;
+
+  abuf = GST_JACK_RING_BUFFER_CAST (arg);
+  sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (arg));
+
+  if (abuf->buffer_size != -1 && abuf->buffer_size != nframes)
+    goto not_supported;
+
+  return 0;
+
+  /* ERRORS */
+not_supported:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS,
+        (NULL), ("Jack changed the buffer size, which is not supported"));
+    return 1;
+  }
+}
+
+static void
+jack_shutdown_cb (void *arg)
+{
+  GstJackAudioSink *sink;
+
+  sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (arg));
+
+  GST_DEBUG_OBJECT (sink, "shutdown");
+
+  GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
+      (NULL), ("Jack server shutdown"));
+}
+
+static void
+gst_jack_ring_buffer_init (GstJackRingBuffer * buf,
+    GstJackRingBufferClass * g_class)
+{
+  buf->channels = -1;
+  buf->buffer_size = -1;
+  buf->sample_rate = -1;
+}
+
+/* the _open_device method should make a connection with the server
+ */
+static gboolean
+gst_jack_ring_buffer_open_device (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSink *sink;
+  jack_status_t status = 0;
+  const gchar *name;
+
+  sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+  GST_DEBUG_OBJECT (sink, "open");
+
+  if (sink->client_name) {
+    name = sink->client_name;
+  } else {
+    name = g_get_application_name ();
+  }
+  if (!name)
+    name = "GStreamer";
+
+  sink->client = gst_jack_audio_client_new (name, sink->server,
+      sink->jclient,
+      GST_JACK_CLIENT_SINK,
+      jack_shutdown_cb,
+      jack_process_cb, jack_buffer_size_cb, jack_sample_rate_cb, buf, &status);
+  if (sink->client == NULL)
+    goto could_not_open;
+
+  GST_DEBUG_OBJECT (sink, "opened");
+
+  return TRUE;
+
+  /* ERRORS */
+could_not_open:
+  {
+    if (status & JackServerFailed) {
+      GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
+          (_("Jack server not found")),
+          ("Cannot connect to the Jack server (status %d)", status));
+    } else {
+      GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
+          (NULL), ("Jack client open error (status %d)", status));
+    }
+    return FALSE;
+  }
+}
+
+/* close the connection with the server
+ */
+static gboolean
+gst_jack_ring_buffer_close_device (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSink *sink;
+
+  sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+  GST_DEBUG_OBJECT (sink, "close");
+
+  gst_jack_audio_sink_free_channels (sink);
+  gst_jack_audio_client_free (sink->client);
+  sink->client = NULL;
+
+  return TRUE;
+}
+
+/* allocate a buffer and setup resources to process the audio samples of
+ * the format as specified in @spec.
+ *
+ * We allocate N jack ports, one for each channel. If we are asked to
+ * automatically make a connection with physical ports, we connect as many
+ * ports as there are physical ports, leaving leftover ports unconnected.
+ *
+ * It is assumed that samplerate and number of channels are acceptable since our
+ * getcaps method will always provide correct values. If unacceptable caps are
+ * received for some reason, we fail here.
+ */
+static gboolean
+gst_jack_ring_buffer_acquire (GstAudioRingBuffer * buf,
+    GstAudioRingBufferSpec * spec)
+{
+  GstJackAudioSink *sink;
+  GstJackRingBuffer *abuf;
+  const char **ports;
+  gint sample_rate, buffer_size;
+  gint i, rate, bpf, channels, res;
+  jack_client_t *client;
+
+  sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+  abuf = GST_JACK_RING_BUFFER_CAST (buf);
+
+  GST_DEBUG_OBJECT (sink, "acquire");
+
+  client = gst_jack_audio_client_get_client (sink->client);
+
+  rate = GST_AUDIO_INFO_RATE (&spec->info);
+
+  /* sample rate must be that of the server */
+  sample_rate = jack_get_sample_rate (client);
+  if (sample_rate != rate)
+    goto wrong_samplerate;
+
+  channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
+  bpf = GST_AUDIO_INFO_BPF (&spec->info);
+
+  if (!gst_jack_audio_sink_allocate_channels (sink, channels))
+    goto out_of_ports;
+
+  buffer_size = jack_get_buffer_size (client);
+
+  /* the segment size in bytes, this is large enough to hold a buffer of 32bit floats
+   * for all channels  */
+  spec->segsize = buffer_size * sizeof (gfloat) * channels;
+  spec->latency_time = gst_util_uint64_scale (spec->segsize,
+      (GST_SECOND / GST_USECOND), rate * bpf);
+  /* segtotal based on buffer-time latency */
+  spec->segtotal = spec->buffer_time / spec->latency_time;
+  if (spec->segtotal < 2) {
+    spec->segtotal = 2;
+    spec->buffer_time = spec->latency_time * spec->segtotal;
+  }
+
+  GST_DEBUG_OBJECT (sink, "buffer time: %" G_GINT64_FORMAT " usec",
+      spec->buffer_time);
+  GST_DEBUG_OBJECT (sink, "latency time: %" G_GINT64_FORMAT " usec",
+      spec->latency_time);
+  GST_DEBUG_OBJECT (sink, "buffer_size %d, segsize %d, segtotal %d",
+      buffer_size, spec->segsize, spec->segtotal);
+
+  /* allocate the ringbuffer memory now */
+  buf->size = spec->segtotal * spec->segsize;
+  buf->memory = g_malloc0 (buf->size);
+
+  if ((res = gst_jack_audio_client_set_active (sink->client, TRUE)))
+    goto could_not_activate;
+
+  /* if we need to automatically connect the ports, do so now. We must do this
+   * after activating the client. */
+  if (sink->connect == GST_JACK_CONNECT_AUTO
+      || sink->connect == GST_JACK_CONNECT_AUTO_FORCED) {
+    /* find all the physical input ports. A physical input port is a port
+     * associated with a hardware device. Someone needs connect to a physical
+     * port in order to hear something. */
+    if (sink->port_pattern == NULL) {
+      ports = jack_get_ports (client, NULL, NULL,
+          JackPortIsPhysical | JackPortIsInput);
+    } else {
+      ports = jack_get_ports (client, sink->port_pattern, NULL,
+          JackPortIsInput);
+    }
+    if (ports == NULL) {
+      /* no ports? fine then we don't do anything except for posting a warning
+       * message. */
+      GST_ELEMENT_WARNING (sink, RESOURCE, NOT_FOUND, (NULL),
+          ("No physical input ports found, leaving ports unconnected"));
+      goto done;
+    }
+
+    for (i = 0; i < channels; i++) {
+      /* stop when all input ports are exhausted */
+      if (ports[i] == NULL) {
+        /* post a warning that we could not connect all ports */
+        GST_ELEMENT_WARNING (sink, RESOURCE, NOT_FOUND, (NULL),
+            ("No more physical ports, leaving some ports unconnected"));
+        break;
+      }
+      GST_DEBUG_OBJECT (sink, "try connecting to %s",
+          jack_port_name (sink->ports[i]));
+      /* connect the port to a physical port */
+      res = jack_connect (client, jack_port_name (sink->ports[i]), ports[i]);
+      if (res != 0 && res != EEXIST)
+        goto cannot_connect;
+    }
+    free (ports);
+  }
+done:
+
+  abuf->sample_rate = sample_rate;
+  abuf->buffer_size = buffer_size;
+  abuf->channels = channels;
+
+  return TRUE;
+
+  /* ERRORS */
+wrong_samplerate:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
+        ("Wrong samplerate, server is running at %d and we received %d",
+            sample_rate, rate));
+    return FALSE;
+  }
+out_of_ports:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
+        ("Cannot allocate more Jack ports"));
+    return FALSE;
+  }
+could_not_activate:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
+        ("Could not activate client (%d:%s)", res, g_strerror (res)));
+    return FALSE;
+  }
+cannot_connect:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
+        ("Could not connect output ports to physical ports (%d:%s)",
+            res, g_strerror (res)));
+    free (ports);
+    return FALSE;
+  }
+}
+
+/* function is called with LOCK */
+static gboolean
+gst_jack_ring_buffer_release (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSink *sink;
+  GstJackRingBuffer *abuf;
+  gint res;
+
+  abuf = GST_JACK_RING_BUFFER_CAST (buf);
+  sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+  GST_DEBUG_OBJECT (sink, "release");
+
+  if ((res = gst_jack_audio_client_set_active (sink->client, FALSE))) {
+    /* we only warn, this means the server is probably shut down and the client
+     * is gone anyway. */
+    GST_ELEMENT_WARNING (sink, RESOURCE, CLOSE, (NULL),
+        ("Could not deactivate Jack client (%d)", res));
+  }
+
+  abuf->channels = -1;
+  abuf->buffer_size = -1;
+  abuf->sample_rate = -1;
+
+  /* free the buffer */
+  g_free (buf->memory);
+  buf->memory = NULL;
+
+  return TRUE;
+}
+
+static gboolean
+gst_jack_ring_buffer_start (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSink *sink;
+
+  sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+  GST_DEBUG_OBJECT (sink, "start");
+
+  if (sink->transport & GST_JACK_TRANSPORT_MASTER) {
+    jack_client_t *client;
+
+    client = gst_jack_audio_client_get_client (sink->client);
+    jack_transport_start (client);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_jack_ring_buffer_pause (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSink *sink;
+
+  sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+  GST_DEBUG_OBJECT (sink, "pause");
+
+  if (sink->transport & GST_JACK_TRANSPORT_MASTER) {
+    jack_client_t *client;
+
+    client = gst_jack_audio_client_get_client (sink->client);
+    jack_transport_stop (client);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_jack_ring_buffer_stop (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSink *sink;
+
+  sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+  GST_DEBUG_OBJECT (sink, "stop");
+
+  if (sink->transport & GST_JACK_TRANSPORT_MASTER) {
+    jack_client_t *client;
+
+    client = gst_jack_audio_client_get_client (sink->client);
+    jack_transport_stop (client);
+  }
+
+  return TRUE;
+}
+
+#if defined (HAVE_JACK_0_120_1) || defined(HAVE_JACK_1_9_7)
+static guint
+gst_jack_ring_buffer_delay (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSink *sink;
+  guint i, res = 0;
+  jack_latency_range_t range;
+
+  sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+  for (i = 0; i < sink->port_count; i++) {
+    jack_port_get_latency_range (sink->ports[i], JackPlaybackLatency, &range);
+    if (range.max > res)
+      res = range.max;
+  }
+
+  GST_LOG_OBJECT (sink, "delay %u", res);
+
+  return res;
+}
+#else /* !(defined (HAVE_JACK_0_120_1) || defined(HAVE_JACK_1_9_7)) */
+static guint
+gst_jack_ring_buffer_delay (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSink *sink;
+  guint i, res = 0;
+  guint latency;
+  jack_client_t *client;
+
+  sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+  client = gst_jack_audio_client_get_client (sink->client);
+
+  for (i = 0; i < sink->port_count; i++) {
+    latency = jack_port_get_total_latency (client, sink->ports[i]);
+    if (latency > res)
+      res = latency;
+  }
+
+  GST_LOG_OBJECT (sink, "delay %u", res);
+
+  return res;
+}
+#endif
+
+static GstStaticPadTemplate jackaudiosink_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_JACK_FORMAT_STR ", "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+    );
+
+/* AudioSink signals and args */
+enum
+{
+  /* FILL ME */
+  SIGNAL_LAST
+};
+
+#define DEFAULT_PROP_CONNECT 		GST_JACK_CONNECT_AUTO
+#define DEFAULT_PROP_SERVER 		NULL
+#define DEFAULT_PROP_CLIENT_NAME	NULL
+#define DEFAULT_PROP_PORT_PATTERN      	NULL
+#define DEFAULT_PROP_TRANSPORT	GST_JACK_TRANSPORT_AUTONOMOUS
+
+enum
+{
+  PROP_0,
+  PROP_CONNECT,
+  PROP_SERVER,
+  PROP_CLIENT,
+  PROP_CLIENT_NAME,
+  PROP_PORT_PATTERN,
+  PROP_TRANSPORT,
+  PROP_LAST
+};
+
+#define gst_jack_audio_sink_parent_class parent_class
+G_DEFINE_TYPE (GstJackAudioSink, gst_jack_audio_sink, GST_TYPE_AUDIO_BASE_SINK);
+
+static void gst_jack_audio_sink_dispose (GObject * object);
+static void gst_jack_audio_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_jack_audio_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_jack_audio_sink_getcaps (GstBaseSink * bsink,
+    GstCaps * filter);
+static GstAudioRingBuffer
+    * gst_jack_audio_sink_create_ringbuffer (GstAudioBaseSink * sink);
+
+static void
+gst_jack_audio_sink_class_init (GstJackAudioSinkClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSinkClass *gstbasesink_class;
+  GstAudioBaseSinkClass *gstaudiobasesink_class;
+
+  GST_DEBUG_CATEGORY_INIT (gst_jack_audio_sink_debug, "jacksink", 0,
+      "jacksink element");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesink_class = (GstBaseSinkClass *) klass;
+  gstaudiobasesink_class = (GstAudioBaseSinkClass *) klass;
+
+  gobject_class->dispose = gst_jack_audio_sink_dispose;
+  gobject_class->get_property = gst_jack_audio_sink_get_property;
+  gobject_class->set_property = gst_jack_audio_sink_set_property;
+
+  g_object_class_install_property (gobject_class, PROP_CONNECT,
+      g_param_spec_enum ("connect", "Connect",
+          "Specify how the output ports will be connected",
+          GST_TYPE_JACK_CONNECT, DEFAULT_PROP_CONNECT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_SERVER,
+      g_param_spec_string ("server", "Server",
+          "The Jack server to connect to (NULL = default)",
+          DEFAULT_PROP_SERVER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstJackAudioSink:client-name:
+   *
+   * The client name to use.
+   */
+  g_object_class_install_property (gobject_class, PROP_CLIENT_NAME,
+      g_param_spec_string ("client-name", "Client name",
+          "The client name of the Jack instance (NULL = default)",
+          DEFAULT_PROP_CLIENT_NAME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CLIENT,
+      g_param_spec_boxed ("client", "JackClient", "Handle for jack client",
+          GST_TYPE_JACK_CLIENT,
+          GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
+          G_PARAM_STATIC_STRINGS));
+
+   /**
+   * GstJackAudioSink:port-pattern
+   *
+   * autoconnect to ports matching pattern, when NULL connect to physical ports
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_PORT_PATTERN,
+      g_param_spec_string ("port-pattern", "port pattern",
+          "A pattern to select which ports to connect to (NULL = first physical ports)",
+          DEFAULT_PROP_PORT_PATTERN,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstJackAudioSink:transport:
+   *
+   * The jack transport behaviour for the client.
+   */
+  g_object_class_install_property (gobject_class, PROP_TRANSPORT,
+      g_param_spec_flags ("transport", "Transport mode",
+          "Jack transport behaviour of the client",
+          GST_TYPE_JACK_TRANSPORT, DEFAULT_PROP_TRANSPORT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class, "Audio Sink (Jack)",
+      "Sink/Audio", "Output audio to a JACK server",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &jackaudiosink_sink_factory);
+
+  gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_jack_audio_sink_getcaps);
+
+  gstaudiobasesink_class->create_ringbuffer =
+      GST_DEBUG_FUNCPTR (gst_jack_audio_sink_create_ringbuffer);
+
+  /* ref class from a thread-safe context to work around missing bit of
+   * thread-safety in GObject */
+  g_type_class_ref (GST_TYPE_JACK_RING_BUFFER);
+
+  gst_jack_audio_client_init ();
+}
+
+static void
+gst_jack_audio_sink_init (GstJackAudioSink * sink)
+{
+  sink->connect = DEFAULT_PROP_CONNECT;
+  sink->server = g_strdup (DEFAULT_PROP_SERVER);
+  sink->jclient = NULL;
+  sink->ports = NULL;
+  sink->port_count = 0;
+  sink->buffers = NULL;
+  sink->client_name = g_strdup (DEFAULT_PROP_CLIENT_NAME);
+  sink->transport = DEFAULT_PROP_TRANSPORT;
+}
+
+static void
+gst_jack_audio_sink_dispose (GObject * object)
+{
+  GstJackAudioSink *sink = GST_JACK_AUDIO_SINK (object);
+
+  gst_caps_replace (&sink->caps, NULL);
+
+  if (sink->client_name != NULL) {
+    g_free (sink->client_name);
+    sink->client_name = NULL;
+  }
+
+  if (sink->port_pattern != NULL) {
+    g_free (sink->port_pattern);
+    sink->port_pattern = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_jack_audio_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstJackAudioSink *sink;
+
+  sink = GST_JACK_AUDIO_SINK (object);
+
+  switch (prop_id) {
+    case PROP_CLIENT_NAME:
+      g_free (sink->client_name);
+      sink->client_name = g_value_dup_string (value);
+      break;
+    case PROP_PORT_PATTERN:
+      g_free (sink->port_pattern);
+      sink->port_pattern = g_value_dup_string (value);
+      break;
+    case PROP_CONNECT:
+      sink->connect = g_value_get_enum (value);
+      break;
+    case PROP_SERVER:
+      g_free (sink->server);
+      sink->server = g_value_dup_string (value);
+      break;
+    case PROP_CLIENT:
+      if (GST_STATE (sink) == GST_STATE_NULL ||
+          GST_STATE (sink) == GST_STATE_READY) {
+        sink->jclient = g_value_get_boxed (value);
+      }
+      break;
+    case PROP_TRANSPORT:
+      sink->transport = g_value_get_flags (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_jack_audio_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstJackAudioSink *sink;
+
+  sink = GST_JACK_AUDIO_SINK (object);
+
+  switch (prop_id) {
+    case PROP_CLIENT_NAME:
+      g_value_set_string (value, sink->client_name);
+      break;
+    case PROP_PORT_PATTERN:
+      g_value_set_string (value, sink->port_pattern);
+      break;
+    case PROP_CONNECT:
+      g_value_set_enum (value, sink->connect);
+      break;
+    case PROP_SERVER:
+      g_value_set_string (value, sink->server);
+      break;
+    case PROP_CLIENT:
+      g_value_set_boxed (value, sink->jclient);
+      break;
+    case PROP_TRANSPORT:
+      g_value_set_flags (value, sink->transport);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstCaps *
+gst_jack_audio_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
+{
+  GstJackAudioSink *sink = GST_JACK_AUDIO_SINK (bsink);
+  const char **ports;
+  gint min, max;
+  gint rate;
+  jack_client_t *client;
+
+  if (sink->client == NULL)
+    goto no_client;
+
+  client = gst_jack_audio_client_get_client (sink->client);
+
+  if (sink->connect == GST_JACK_CONNECT_AUTO) {
+    /* get a port count, this is the number of channels we can automatically
+     * connect. */
+    ports = jack_get_ports (client, NULL, NULL,
+        JackPortIsPhysical | JackPortIsInput);
+    max = 0;
+    if (ports != NULL) {
+      for (; ports[max]; max++);
+      free (ports);
+    } else
+      max = 0;
+  } else {
+    /* we allow any number of pads, something else is going to connect the
+     * pads. */
+    max = G_MAXINT;
+  }
+  min = MIN (1, max);
+
+  rate = jack_get_sample_rate (client);
+
+  GST_DEBUG_OBJECT (sink, "got %d-%d ports, samplerate: %d", min, max, rate);
+
+  if (!sink->caps) {
+    sink->caps = gst_caps_new_simple ("audio/x-raw",
+        "format", G_TYPE_STRING, GST_JACK_FORMAT_STR,
+        "layout", G_TYPE_STRING, "interleaved",
+        "rate", G_TYPE_INT, rate,
+        "channels", GST_TYPE_INT_RANGE, min, max, NULL);
+  }
+  GST_INFO_OBJECT (sink, "returning caps %" GST_PTR_FORMAT, sink->caps);
+
+  return gst_caps_ref (sink->caps);
+
+  /* ERRORS */
+no_client:
+  {
+    GST_DEBUG_OBJECT (sink, "device not open, using template caps");
+    /* base class will get template caps for us when we return NULL */
+    return NULL;
+  }
+}
+
+static GstAudioRingBuffer *
+gst_jack_audio_sink_create_ringbuffer (GstAudioBaseSink * sink)
+{
+  GstAudioRingBuffer *buffer;
+
+  buffer = g_object_new (GST_TYPE_JACK_RING_BUFFER, NULL);
+  GST_DEBUG_OBJECT (sink, "created ringbuffer @%p", buffer);
+
+  return buffer;
+}
diff --git a/ext/jack/gstjackaudiosink.h b/ext/jack/gstjackaudiosink.h
new file mode 100644
index 0000000..7fccc8a
--- /dev/null
+++ b/ext/jack/gstjackaudiosink.h
@@ -0,0 +1,82 @@
+/* GStreamer
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ *
+ * gstjacksink.h:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_JACK_AUDIO_SINK_H__
+#define __GST_JACK_AUDIO_SINK_H__
+
+#include <jack/jack.h>
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiobasesink.h>
+
+#include "gstjack.h"
+#include "gstjackaudioclient.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_JACK_AUDIO_SINK             (gst_jack_audio_sink_get_type())
+#define GST_JACK_AUDIO_SINK(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_JACK_AUDIO_SINK,GstJackAudioSink))
+#define GST_JACK_AUDIO_SINK_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_JACK_AUDIO_SINK,GstJackAudioSinkClass))
+#define GST_JACK_AUDIO_SINK_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_JACK_AUDIO_SINK,GstJackAudioSinkClass))
+#define GST_IS_JACK_AUDIO_SINK(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_JACK_AUDIO_SINK))
+#define GST_IS_JACK_AUDIO_SINK_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_JACK_AUDIO_SINK))
+
+typedef struct _GstJackAudioSink GstJackAudioSink;
+typedef struct _GstJackAudioSinkClass GstJackAudioSinkClass;
+
+/**
+ * GstJackAudioSink:
+ * 
+ * Opaque #GstJackAudioSink.
+ */
+struct _GstJackAudioSink {
+  GstAudioBaseSink element;
+
+  /*< private >*/
+  /* cached caps */
+  GstCaps         *caps;
+
+  /* properties */
+  GstJackConnect   connect;
+  gchar           *server;
+  jack_client_t   *jclient;
+  gchar           *client_name;
+  gchar           *port_pattern;
+  guint            transport;
+
+  /* our client */
+  GstJackAudioClient *client;
+
+  /* our ports */
+  jack_port_t    **ports;
+  int              port_count;
+  sample_t       **buffers;
+};
+
+struct _GstJackAudioSinkClass {
+  GstAudioBaseSinkClass parent_class;
+};
+
+GType gst_jack_audio_sink_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_JACK_AUDIO_SINK_H__ */
diff --git a/ext/jack/gstjackaudiosrc.c b/ext/jack/gstjackaudiosrc.c
new file mode 100644
index 0000000..53ebee7
--- /dev/null
+++ b/ext/jack/gstjackaudiosrc.c
@@ -0,0 +1,990 @@
+/* GStreamer
+ * Copyright (C) 2008 Tristan Matthews <tristan@sat.qc.ca>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-jackaudiosrc
+ * @see_also: #GstAudioBaseSrc, #GstAudioRingBuffer
+ *
+ * A Src that inputs data from Jack ports.
+ * 
+ * It will create N Jack ports named in_&lt;name&gt;_&lt;num&gt; where 
+ * &lt;name&gt; is the element name and &lt;num&gt; is starting from 1.
+ * Each port corresponds to a gstreamer channel.
+ * 
+ * The samplerate as exposed on the caps is always the same as the samplerate of
+ * the jack server.
+ * 
+ * When the #GstJackAudioSrc:connect property is set to auto, this element
+ * will try to connect each input port to a random physical jack output pin. 
+ * 
+ * When the #GstJackAudioSrc:connect property is set to none, the element will
+ * accept any number of output channels and will create (but not connect) an
+ * input port for each channel.
+ * 
+ * The element will generate an error when the Jack server is shut down when it
+ * was PAUSED or PLAYING. This element does not support dynamic rate and buffer
+ * size changes at runtime.
+ * 
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 jackaudiosrc connect=0 ! jackaudiosink connect=0
+ * ]| Get audio input into gstreamer from jack.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst-i18n-plugin.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gst/audio/audio.h>
+
+#include "gstjackaudiosrc.h"
+#include "gstjackringbuffer.h"
+#include "gstjackutil.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_jack_audio_src_debug);
+#define GST_CAT_DEFAULT gst_jack_audio_src_debug
+
+static gboolean
+gst_jack_audio_src_allocate_channels (GstJackAudioSrc * src, gint channels)
+{
+  jack_client_t *client;
+
+  client = gst_jack_audio_client_get_client (src->client);
+
+  /* remove ports we don't need */
+  while (src->port_count > channels)
+    jack_port_unregister (client, src->ports[--src->port_count]);
+
+  /* alloc enough input ports */
+  src->ports = g_realloc (src->ports, sizeof (jack_port_t *) * channels);
+  src->buffers = g_realloc (src->buffers, sizeof (sample_t *) * channels);
+
+  /* create an input port for each channel */
+  while (src->port_count < channels) {
+    gchar *name;
+
+    /* port names start from 1 and are local to the element */
+    name =
+        g_strdup_printf ("in_%s_%d", GST_ELEMENT_NAME (src),
+        src->port_count + 1);
+    src->ports[src->port_count] =
+        jack_port_register (client, name, JACK_DEFAULT_AUDIO_TYPE,
+        JackPortIsInput, 0);
+    if (src->ports[src->port_count] == NULL)
+      return FALSE;
+
+    src->port_count++;
+
+    g_free (name);
+  }
+  return TRUE;
+}
+
+static void
+gst_jack_audio_src_free_channels (GstJackAudioSrc * src)
+{
+  gint res, i = 0;
+  jack_client_t *client;
+
+  client = gst_jack_audio_client_get_client (src->client);
+
+  /* get rid of all ports */
+  while (src->port_count) {
+    GST_LOG_OBJECT (src, "unregister port %d", i);
+    if ((res = jack_port_unregister (client, src->ports[i++])))
+      GST_DEBUG_OBJECT (src, "unregister of port failed (%d)", res);
+
+    src->port_count--;
+  }
+  g_free (src->ports);
+  src->ports = NULL;
+  g_free (src->buffers);
+  src->buffers = NULL;
+}
+
+/* ringbuffer abstract base class */
+static GType
+gst_jack_ring_buffer_get_type (void)
+{
+  static volatile gsize ringbuffer_type = 0;
+
+  if (g_once_init_enter (&ringbuffer_type)) {
+    static const GTypeInfo ringbuffer_info = { sizeof (GstJackRingBufferClass),
+      NULL,
+      NULL,
+      (GClassInitFunc) gst_jack_ring_buffer_class_init,
+      NULL,
+      NULL,
+      sizeof (GstJackRingBuffer),
+      0,
+      (GInstanceInitFunc) gst_jack_ring_buffer_init,
+      NULL
+    };
+    GType tmp = g_type_register_static (GST_TYPE_AUDIO_RING_BUFFER,
+        "GstJackAudioSrcRingBuffer", &ringbuffer_info, 0);
+    g_once_init_leave (&ringbuffer_type, tmp);
+  }
+
+  return (GType) ringbuffer_type;
+}
+
+static void
+gst_jack_ring_buffer_class_init (GstJackRingBufferClass * klass)
+{
+  GstAudioRingBufferClass *gstringbuffer_class;
+
+  gstringbuffer_class = (GstAudioRingBufferClass *) klass;
+
+  ring_parent_class = g_type_class_peek_parent (klass);
+
+  gstringbuffer_class->open_device =
+      GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_open_device);
+  gstringbuffer_class->close_device =
+      GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_close_device);
+  gstringbuffer_class->acquire =
+      GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_acquire);
+  gstringbuffer_class->release =
+      GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_release);
+  gstringbuffer_class->start = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_start);
+  gstringbuffer_class->pause = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_pause);
+  gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_start);
+  gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_stop);
+
+  gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_delay);
+}
+
+/* this is the callback of jack. This should be RT-safe.
+ * Writes samples from the jack input port's buffer to the gst ring buffer.
+ */
+static int
+jack_process_cb (jack_nframes_t nframes, void *arg)
+{
+  GstJackAudioSrc *src;
+  GstAudioRingBuffer *buf;
+  gint len;
+  guint8 *writeptr;
+  gint writeseg;
+  gint channels, i, j, flen;
+  sample_t *data;
+
+  buf = GST_AUDIO_RING_BUFFER_CAST (arg);
+  src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+  channels = GST_AUDIO_INFO_CHANNELS (&buf->spec.info);
+
+  /* get input buffers */
+  for (i = 0; i < channels; i++)
+    src->buffers[i] =
+        (sample_t *) jack_port_get_buffer (src->ports[i], nframes);
+
+  if (gst_audio_ring_buffer_prepare_read (buf, &writeseg, &writeptr, &len)) {
+    flen = len / channels;
+
+    /* the number of samples must be exactly the segment size */
+    if (nframes * sizeof (sample_t) != flen)
+      goto wrong_size;
+
+    /* the samples in the jack input buffers have to be interleaved into the
+     * ringbuffer */
+    data = (sample_t *) writeptr;
+    for (i = 0; i < nframes; ++i)
+      for (j = 0; j < channels; ++j)
+        *data++ = src->buffers[j][i];
+
+    GST_DEBUG ("copy %d frames: %p, %d bytes, %d channels", nframes, writeptr,
+        len / channels, channels);
+
+    /* we wrote one segment */
+    gst_audio_ring_buffer_advance (buf, 1);
+  }
+  return 0;
+
+  /* ERRORS */
+wrong_size:
+  {
+    GST_ERROR_OBJECT (src, "nbytes (%d) != flen (%d)",
+        (gint) (nframes * sizeof (sample_t)), flen);
+    return 1;
+  }
+}
+
+/* we error out */
+static int
+jack_sample_rate_cb (jack_nframes_t nframes, void *arg)
+{
+  GstJackAudioSrc *src;
+  GstJackRingBuffer *abuf;
+
+  abuf = GST_JACK_RING_BUFFER_CAST (arg);
+  src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (arg));
+
+  if (abuf->sample_rate != -1 && abuf->sample_rate != nframes)
+    goto not_supported;
+
+  return 0;
+
+  /* ERRORS */
+not_supported:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
+        (NULL), ("Jack changed the sample rate, which is not supported"));
+    return 1;
+  }
+}
+
+/* we error out */
+static int
+jack_buffer_size_cb (jack_nframes_t nframes, void *arg)
+{
+  GstJackAudioSrc *src;
+  GstJackRingBuffer *abuf;
+
+  abuf = GST_JACK_RING_BUFFER_CAST (arg);
+  src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (arg));
+
+  if (abuf->buffer_size != -1 && abuf->buffer_size != nframes)
+    goto not_supported;
+
+  return 0;
+
+  /* ERRORS */
+not_supported:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
+        (NULL), ("Jack changed the buffer size, which is not supported"));
+    return 1;
+  }
+}
+
+static void
+jack_shutdown_cb (void *arg)
+{
+  GstJackAudioSrc *src;
+
+  src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (arg));
+
+  GST_DEBUG_OBJECT (src, "shutdown");
+
+  GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
+      (NULL), ("Jack server shutdown"));
+}
+
+static void
+gst_jack_ring_buffer_init (GstJackRingBuffer * buf,
+    GstJackRingBufferClass * g_class)
+{
+  buf->channels = -1;
+  buf->buffer_size = -1;
+  buf->sample_rate = -1;
+}
+
+/* the _open_device method should make a connection with the server
+*/
+static gboolean
+gst_jack_ring_buffer_open_device (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSrc *src;
+  jack_status_t status = 0;
+  const gchar *name;
+
+  src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+  GST_DEBUG_OBJECT (src, "open");
+
+  if (src->client_name) {
+    name = src->client_name;
+  } else {
+    name = g_get_application_name ();
+  }
+  if (!name)
+    name = "GStreamer";
+
+  src->client = gst_jack_audio_client_new (name, src->server,
+      src->jclient,
+      GST_JACK_CLIENT_SOURCE,
+      jack_shutdown_cb,
+      jack_process_cb, jack_buffer_size_cb, jack_sample_rate_cb, buf, &status);
+  if (src->client == NULL)
+    goto could_not_open;
+
+  GST_DEBUG_OBJECT (src, "opened");
+
+  return TRUE;
+
+  /* ERRORS */
+could_not_open:
+  {
+    if (status & (JackServerFailed | JackFailure)) {
+      GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
+          (_("Jack server not found")),
+          ("Cannot connect to the Jack server (status %d)", status));
+    } else {
+      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+          (NULL), ("Jack client open error (status %d)", status));
+    }
+    return FALSE;
+  }
+}
+
+/* close the connection with the server
+*/
+static gboolean
+gst_jack_ring_buffer_close_device (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSrc *src;
+
+  src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+  GST_DEBUG_OBJECT (src, "close");
+
+  gst_jack_audio_src_free_channels (src);
+  gst_jack_audio_client_free (src->client);
+  src->client = NULL;
+
+  return TRUE;
+}
+
+
+/* allocate a buffer and setup resources to process the audio samples of
+ * the format as specified in @spec.
+ *
+ * We allocate N jack ports, one for each channel. If we are asked to
+ * automatically make a connection with physical ports, we connect as many
+ * ports as there are physical ports, leaving leftover ports unconnected.
+ *
+ * It is assumed that samplerate and number of channels are acceptable since our
+ * getcaps method will always provide correct values. If unacceptable caps are
+ * received for some reason, we fail here.
+ */
+static gboolean
+gst_jack_ring_buffer_acquire (GstAudioRingBuffer * buf,
+    GstAudioRingBufferSpec * spec)
+{
+  GstJackAudioSrc *src;
+  GstJackRingBuffer *abuf;
+  const char **ports;
+  gint sample_rate, buffer_size;
+  gint i, bpf, rate, channels, res;
+  jack_client_t *client;
+
+  src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+  abuf = GST_JACK_RING_BUFFER_CAST (buf);
+
+  GST_DEBUG_OBJECT (src, "acquire");
+
+  client = gst_jack_audio_client_get_client (src->client);
+
+  rate = GST_AUDIO_INFO_RATE (&spec->info);
+
+  /* sample rate must be that of the server */
+  sample_rate = jack_get_sample_rate (client);
+  if (sample_rate != rate)
+    goto wrong_samplerate;
+
+  bpf = GST_AUDIO_INFO_BPF (&spec->info);
+  channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
+
+  if (!gst_jack_audio_src_allocate_channels (src, channels))
+    goto out_of_ports;
+
+  gst_jack_set_layout (buf, spec);
+
+  buffer_size = jack_get_buffer_size (client);
+
+  /* the segment size in bytes, this is large enough to hold a buffer of 32bit floats
+   * for all channels  */
+  spec->segsize = buffer_size * sizeof (gfloat) * channels;
+  spec->latency_time = gst_util_uint64_scale (spec->segsize,
+      (GST_SECOND / GST_USECOND), rate * bpf);
+  /* segtotal based on buffer-time latency */
+  spec->segtotal = spec->buffer_time / spec->latency_time;
+  if (spec->segtotal < 2) {
+    spec->segtotal = 2;
+    spec->buffer_time = spec->latency_time * spec->segtotal;
+  }
+
+  GST_DEBUG_OBJECT (src, "buffer time: %" G_GINT64_FORMAT " usec",
+      spec->buffer_time);
+  GST_DEBUG_OBJECT (src, "latency time: %" G_GINT64_FORMAT " usec",
+      spec->latency_time);
+  GST_DEBUG_OBJECT (src, "buffer_size %d, segsize %d, segtotal %d",
+      buffer_size, spec->segsize, spec->segtotal);
+
+  /* allocate the ringbuffer memory now */
+  buf->size = spec->segtotal * spec->segsize;
+  buf->memory = g_malloc0 (buf->size);
+
+  if ((res = gst_jack_audio_client_set_active (src->client, TRUE)))
+    goto could_not_activate;
+
+  /* if we need to automatically connect the ports, do so now. We must do this
+   * after activating the client. */
+  if (src->connect == GST_JACK_CONNECT_AUTO
+      || src->connect == GST_JACK_CONNECT_AUTO_FORCED) {
+    /* find all the physical output ports. A physical output port is a port
+     * associated with a hardware device. Someone needs connect to a physical
+     * port in order to capture something. */
+
+    if (src->port_pattern == NULL) {
+      ports = jack_get_ports (client, NULL, NULL,
+          JackPortIsPhysical | JackPortIsOutput);
+    } else {
+      ports = jack_get_ports (client, src->port_pattern, NULL,
+          JackPortIsOutput);
+    }
+
+    if (ports == NULL) {
+      /* no ports? fine then we don't do anything except for posting a warning
+       * message. */
+      GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND, (NULL),
+          ("No physical output ports found, leaving ports unconnected"));
+      goto done;
+    }
+
+    for (i = 0; i < channels; i++) {
+      /* stop when all output ports are exhausted */
+      if (ports[i] == NULL) {
+        /* post a warning that we could not connect all ports */
+        GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND, (NULL),
+            ("No more physical ports, leaving some ports unconnected"));
+        break;
+      }
+      GST_DEBUG_OBJECT (src, "try connecting to %s",
+          jack_port_name (src->ports[i]));
+
+      /* connect the physical port to a port */
+      res = jack_connect (client, ports[i], jack_port_name (src->ports[i]));
+      if (res != 0 && res != EEXIST)
+        goto cannot_connect;
+    }
+    free (ports);
+  }
+done:
+
+  abuf->sample_rate = sample_rate;
+  abuf->buffer_size = buffer_size;
+  abuf->channels = channels;
+
+  return TRUE;
+
+  /* ERRORS */
+wrong_samplerate:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+        ("Wrong samplerate, server is running at %d and we received %d",
+            sample_rate, rate));
+    return FALSE;
+  }
+out_of_ports:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+        ("Cannot allocate more Jack ports"));
+    return FALSE;
+  }
+could_not_activate:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+        ("Could not activate client (%d:%s)", res, g_strerror (res)));
+    return FALSE;
+  }
+cannot_connect:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+        ("Could not connect input ports to physical ports (%d:%s)",
+            res, g_strerror (res)));
+    free (ports);
+    return FALSE;
+  }
+}
+
+/* function is called with LOCK */
+static gboolean
+gst_jack_ring_buffer_release (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSrc *src;
+  GstJackRingBuffer *abuf;
+  gint res;
+
+  abuf = GST_JACK_RING_BUFFER_CAST (buf);
+  src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+  GST_DEBUG_OBJECT (src, "release");
+
+  if ((res = gst_jack_audio_client_set_active (src->client, FALSE))) {
+    /* we only warn, this means the server is probably shut down and the client
+     * is gone anyway. */
+    GST_ELEMENT_WARNING (src, RESOURCE, CLOSE, (NULL),
+        ("Could not deactivate Jack client (%d)", res));
+  }
+
+  abuf->channels = -1;
+  abuf->buffer_size = -1;
+  abuf->sample_rate = -1;
+
+  /* free the buffer */
+  g_free (buf->memory);
+  buf->memory = NULL;
+
+  return TRUE;
+}
+
+static gboolean
+gst_jack_ring_buffer_start (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSrc *src;
+
+  src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+  GST_DEBUG_OBJECT (src, "start");
+
+  if (src->transport & GST_JACK_TRANSPORT_MASTER) {
+    jack_client_t *client;
+
+    client = gst_jack_audio_client_get_client (src->client);
+    jack_transport_start (client);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_jack_ring_buffer_pause (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSrc *src;
+
+  src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+  GST_DEBUG_OBJECT (src, "pause");
+
+  if (src->transport & GST_JACK_TRANSPORT_MASTER) {
+    jack_client_t *client;
+
+    client = gst_jack_audio_client_get_client (src->client);
+    jack_transport_stop (client);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_jack_ring_buffer_stop (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSrc *src;
+
+  src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+  GST_DEBUG_OBJECT (src, "stop");
+
+  if (src->transport & GST_JACK_TRANSPORT_MASTER) {
+    jack_client_t *client;
+
+    client = gst_jack_audio_client_get_client (src->client);
+    jack_transport_stop (client);
+  }
+
+  return TRUE;
+}
+
+#if defined (HAVE_JACK_0_120_1) || defined(HAVE_JACK_1_9_7)
+static guint
+gst_jack_ring_buffer_delay (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSrc *src;
+  guint i, res = 0;
+  jack_latency_range_t range;
+
+  src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+  for (i = 0; i < src->port_count; i++) {
+    jack_port_get_latency_range (src->ports[i], JackCaptureLatency, &range);
+    if (range.max > res)
+      res = range.max;
+  }
+
+  GST_DEBUG_OBJECT (src, "delay %u", res);
+
+  return res;
+}
+#else /* !(defined (HAVE_JACK_0_120_1) || defined(HAVE_JACK_1_9_7)) */
+static guint
+gst_jack_ring_buffer_delay (GstAudioRingBuffer * buf)
+{
+  GstJackAudioSrc *src;
+  guint i, res = 0;
+  guint latency;
+  jack_client_t *client;
+
+  src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+  client = gst_jack_audio_client_get_client (src->client);
+
+  for (i = 0; i < src->port_count; i++) {
+    latency = jack_port_get_total_latency (client, src->ports[i]);
+    if (latency > res)
+      res = latency;
+  }
+
+  GST_DEBUG_OBJECT (src, "delay %u", res);
+
+  return res;
+}
+#endif
+
+/* Audiosrc signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+#define DEFAULT_PROP_CONNECT 		GST_JACK_CONNECT_AUTO
+#define DEFAULT_PROP_SERVER 		NULL
+#define DEFAULT_PROP_CLIENT_NAME	NULL
+#define DEFAULT_PROP_TRANSPORT	GST_JACK_TRANSPORT_AUTONOMOUS
+#define DEFAULT_PROP_PORT_PATTERN     	NULL
+enum
+{
+  PROP_0,
+  PROP_CONNECT,
+  PROP_SERVER,
+  PROP_CLIENT,
+  PROP_CLIENT_NAME,
+  PROP_PORT_PATTERN,
+  PROP_TRANSPORT,
+  PROP_LAST
+};
+
+/* the capabilities of the inputs and outputs.
+ *
+ * describe the real formats here.
+ */
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_JACK_FORMAT_STR ", "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+    );
+
+#define gst_jack_audio_src_parent_class parent_class
+G_DEFINE_TYPE (GstJackAudioSrc, gst_jack_audio_src, GST_TYPE_AUDIO_BASE_SRC);
+
+static void gst_jack_audio_src_dispose (GObject * object);
+static void gst_jack_audio_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_jack_audio_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_jack_audio_src_getcaps (GstBaseSrc * bsrc,
+    GstCaps * filter);
+static GstAudioRingBuffer *gst_jack_audio_src_create_ringbuffer (GstAudioBaseSrc
+    * src);
+
+/* GObject vmethod implementations */
+
+/* initialize the jack_audio_src's class */
+static void
+gst_jack_audio_src_class_init (GstJackAudioSrcClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSrcClass *gstbasesrc_class;
+  GstAudioBaseSrcClass *gstaudiobasesrc_class;
+
+  GST_DEBUG_CATEGORY_INIT (gst_jack_audio_src_debug, "jacksrc", 0,
+      "jacksrc element");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesrc_class = (GstBaseSrcClass *) klass;
+  gstaudiobasesrc_class = (GstAudioBaseSrcClass *) klass;
+
+  gobject_class->dispose = gst_jack_audio_src_dispose;
+  gobject_class->set_property = gst_jack_audio_src_set_property;
+  gobject_class->get_property = gst_jack_audio_src_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_CONNECT,
+      g_param_spec_enum ("connect", "Connect",
+          "Specify how the input ports will be connected",
+          GST_TYPE_JACK_CONNECT, DEFAULT_PROP_CONNECT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_SERVER,
+      g_param_spec_string ("server", "Server",
+          "The Jack server to connect to (NULL = default)",
+          DEFAULT_PROP_SERVER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstJackAudioSrc:client-name:
+   *
+   * The client name to use.
+   */
+  g_object_class_install_property (gobject_class, PROP_CLIENT_NAME,
+      g_param_spec_string ("client-name", "Client name",
+          "The client name of the Jack instance (NULL = default)",
+          DEFAULT_PROP_CLIENT_NAME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CLIENT,
+      g_param_spec_boxed ("client", "JackClient", "Handle for jack client",
+          GST_TYPE_JACK_CLIENT,
+          GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
+          G_PARAM_STATIC_STRINGS));
+   /**
+    * GstJackAudioSrc:port-pattern
+    *
+    * autoconnect to ports matching pattern, when NULL connect to physical ports
+    *
+    * Since: 1.6
+    */
+  g_object_class_install_property (gobject_class, PROP_PORT_PATTERN,
+      g_param_spec_string ("port-pattern", "port pattern",
+          "A pattern to select which ports to connect to (NULL = first physical ports)",
+          DEFAULT_PROP_PORT_PATTERN,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstJackAudioSink:transport:
+   *
+   * The jack transport behaviour for the client.
+   */
+  g_object_class_install_property (gobject_class, PROP_TRANSPORT,
+      g_param_spec_flags ("transport", "Transport mode",
+          "Jack transport behaviour of the client",
+          GST_TYPE_JACK_TRANSPORT, DEFAULT_PROP_TRANSPORT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Audio Source (Jack)", "Source/Audio",
+      "Captures audio from a JACK server",
+      "Tristan Matthews <tristan@sat.qc.ca>");
+
+  gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_jack_audio_src_getcaps);
+  gstaudiobasesrc_class->create_ringbuffer =
+      GST_DEBUG_FUNCPTR (gst_jack_audio_src_create_ringbuffer);
+
+  /* ref class from a thread-safe context to work around missing bit of
+   * thread-safety in GObject */
+  g_type_class_ref (GST_TYPE_JACK_RING_BUFFER);
+
+  gst_jack_audio_client_init ();
+}
+
+static void
+gst_jack_audio_src_init (GstJackAudioSrc * src)
+{
+  //gst_base_src_set_live(GST_BASE_SRC (src), TRUE);
+  src->connect = DEFAULT_PROP_CONNECT;
+  src->server = g_strdup (DEFAULT_PROP_SERVER);
+  src->jclient = NULL;
+  src->ports = NULL;
+  src->port_count = 0;
+  src->buffers = NULL;
+  src->client_name = g_strdup (DEFAULT_PROP_CLIENT_NAME);
+  src->transport = DEFAULT_PROP_TRANSPORT;
+}
+
+static void
+gst_jack_audio_src_dispose (GObject * object)
+{
+  GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object);
+
+  gst_caps_replace (&src->caps, NULL);
+
+  if (src->client_name != NULL) {
+    g_free (src->client_name);
+    src->client_name = NULL;
+  }
+
+  if (src->port_pattern != NULL) {
+    g_free (src->port_pattern);
+    src->port_pattern = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_jack_audio_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object);
+
+  switch (prop_id) {
+    case PROP_CLIENT_NAME:
+      g_free (src->client_name);
+      src->client_name = g_value_dup_string (value);
+      break;
+    case PROP_PORT_PATTERN:
+      g_free (src->port_pattern);
+      src->port_pattern = g_value_dup_string (value);
+      break;
+    case PROP_CONNECT:
+      src->connect = g_value_get_enum (value);
+      break;
+    case PROP_SERVER:
+      g_free (src->server);
+      src->server = g_value_dup_string (value);
+      break;
+    case PROP_CLIENT:
+      if (GST_STATE (src) == GST_STATE_NULL ||
+          GST_STATE (src) == GST_STATE_READY) {
+        src->jclient = g_value_get_boxed (value);
+      }
+      break;
+    case PROP_TRANSPORT:
+      src->transport = g_value_get_flags (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_jack_audio_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object);
+
+  switch (prop_id) {
+    case PROP_CLIENT_NAME:
+      g_value_set_string (value, src->client_name);
+      break;
+    case PROP_PORT_PATTERN:
+      g_value_set_string (value, src->port_pattern);
+      break;
+    case PROP_CONNECT:
+      g_value_set_enum (value, src->connect);
+      break;
+    case PROP_SERVER:
+      g_value_set_string (value, src->server);
+      break;
+    case PROP_CLIENT:
+      g_value_set_boxed (value, src->jclient);
+      break;
+    case PROP_TRANSPORT:
+      g_value_set_flags (value, src->transport);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstCaps *
+gst_jack_audio_src_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
+{
+  GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (bsrc);
+  const char **ports;
+  gint min, max;
+  gint rate;
+  jack_client_t *client;
+
+  if (src->client == NULL)
+    goto no_client;
+
+  client = gst_jack_audio_client_get_client (src->client);
+
+  if (src->connect == GST_JACK_CONNECT_AUTO) {
+    /* get a port count, this is the number of channels we can automatically
+     * connect. */
+    ports = jack_get_ports (client, NULL, NULL,
+        JackPortIsPhysical | JackPortIsOutput);
+    max = 0;
+    if (ports != NULL) {
+      for (; ports[max]; max++);
+
+      free (ports);
+    } else
+      max = 0;
+  } else {
+    /* we allow any number of pads, something else is going to connect the
+     * pads. */
+    max = G_MAXINT;
+  }
+  min = MIN (1, max);
+
+  rate = jack_get_sample_rate (client);
+
+  GST_DEBUG_OBJECT (src, "got %d-%d ports, samplerate: %d", min, max, rate);
+
+  if (!src->caps) {
+    src->caps = gst_caps_new_simple ("audio/x-raw",
+        "format", G_TYPE_STRING, GST_JACK_FORMAT_STR,
+        "layout", G_TYPE_STRING, "interleaved",
+        "rate", G_TYPE_INT, rate,
+        "channels", GST_TYPE_INT_RANGE, min, max, NULL);
+  }
+  GST_INFO_OBJECT (src, "returning caps %" GST_PTR_FORMAT, src->caps);
+
+  return gst_caps_ref (src->caps);
+
+  /* ERRORS */
+no_client:
+  {
+    GST_DEBUG_OBJECT (src, "device not open, using template caps");
+    /* base class will get template caps for us when we return NULL */
+    return NULL;
+  }
+}
+
+static GstAudioRingBuffer *
+gst_jack_audio_src_create_ringbuffer (GstAudioBaseSrc * src)
+{
+  GstAudioRingBuffer *buffer;
+
+  buffer = g_object_new (GST_TYPE_JACK_RING_BUFFER, NULL);
+  GST_DEBUG_OBJECT (src, "created ringbuffer @%p", buffer);
+
+  return buffer;
+}
diff --git a/ext/jack/gstjackaudiosrc.h b/ext/jack/gstjackaudiosrc.h
new file mode 100644
index 0000000..63ffe3f
--- /dev/null
+++ b/ext/jack/gstjackaudiosrc.h
@@ -0,0 +1,100 @@
+/* GStreamer
+ * Copyright (C) 2008 Tristan Matthews <tristan@sat.qc.ca>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_JACK_AUDIO_SRC_H__
+#define __GST_JACK_AUDIO_SRC_H__
+
+#include <jack/jack.h>
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosrc.h>
+
+#include "gstjackaudioclient.h"
+#include "gstjack.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_JACK_AUDIO_SRC             (gst_jack_audio_src_get_type())
+#define GST_JACK_AUDIO_SRC(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_JACK_AUDIO_SRC,GstJackAudioSrc))
+#define GST_JACK_AUDIO_SRC_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_JACK_AUDIO_SRC,GstJackAudioSrcClass))
+#define GST_JACK_AUDIO_SRC_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_JACK_AUDIO_SRC,GstJackAudioSrcClass))
+#define GST_IS_JACK_AUDIO_SRC(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_JACK_AUDIO_SRC))
+#define GST_IS_JACK_AUDIO_SRC_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_JACK_AUDIO_SRC))
+
+typedef struct _GstJackAudioSrc GstJackAudioSrc;
+typedef struct _GstJackAudioSrcClass GstJackAudioSrcClass;
+
+struct _GstJackAudioSrc
+{
+    GstAudioBaseSrc src;
+
+    /*< private >*/
+    /* cached caps */
+    GstCaps         *caps;
+
+    /* properties */
+    GstJackConnect   connect;
+    gchar           *server;
+    jack_client_t   *jclient;
+    gchar           *client_name;
+    gchar           *port_pattern;
+    guint            transport;
+
+    /* our client */
+    GstJackAudioClient *client;
+
+    /* our ports */
+    jack_port_t    **ports;
+    int port_count;
+    sample_t **buffers;
+};
+
+struct _GstJackAudioSrcClass
+{
+    GstAudioBaseSrcClass parent_class;
+};
+
+GType gst_jack_audio_src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_JACK_AUDIO_SRC_H__ */
diff --git a/ext/jack/gstjackringbuffer.h b/ext/jack/gstjackringbuffer.h
new file mode 100644
index 0000000..94de4b8
--- /dev/null
+++ b/ext/jack/gstjackringbuffer.h
@@ -0,0 +1,88 @@
+/*
+ * GStreamer
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ * Copyright (C) 2008 Tristan Matthews <tristan@sat.qc.ca>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_JACK_RING_BUFFER_H__
+#define __GST_JACK_RING_BUFFER_H__
+
+#define GST_TYPE_JACK_RING_BUFFER               (gst_jack_ring_buffer_get_type())
+#define GST_JACK_RING_BUFFER(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_JACK_RING_BUFFER,GstJackRingBuffer))
+#define GST_JACK_RING_BUFFER_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_JACK_RING_BUFFER,GstJackRingBufferClass))
+#define GST_JACK_RING_BUFFER_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_JACK_RING_BUFFER,GstJackRingBufferClass))
+#define GST_JACK_RING_BUFFER_CAST(obj)          ((GstJackRingBuffer *)obj)
+#define GST_IS_JACK_RING_BUFFER(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_JACK_RING_BUFFER))
+#define GST_IS_JACK_RING_BUFFER_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_JACK_RING_BUFFER))
+
+typedef struct _GstJackRingBuffer GstJackRingBuffer;
+typedef struct _GstJackRingBufferClass GstJackRingBufferClass;
+
+struct _GstJackRingBuffer
+{
+  GstAudioRingBuffer object;
+
+  gint sample_rate;
+  gint buffer_size;
+  gint channels;
+};
+
+struct _GstJackRingBufferClass
+{
+  GstAudioRingBufferClass parent_class;
+};
+
+static void gst_jack_ring_buffer_class_init(GstJackRingBufferClass * klass);
+static void gst_jack_ring_buffer_init(GstJackRingBuffer * ringbuffer,
+    GstJackRingBufferClass * klass);
+
+static GstAudioRingBufferClass *ring_parent_class = NULL;
+
+static gboolean gst_jack_ring_buffer_open_device(GstAudioRingBuffer * buf);
+static gboolean gst_jack_ring_buffer_close_device(GstAudioRingBuffer * buf);
+static gboolean gst_jack_ring_buffer_acquire(GstAudioRingBuffer * buf,GstAudioRingBufferSpec * spec);
+static gboolean gst_jack_ring_buffer_release(GstAudioRingBuffer * buf);
+static gboolean gst_jack_ring_buffer_start(GstAudioRingBuffer * buf);
+static gboolean gst_jack_ring_buffer_pause(GstAudioRingBuffer * buf);
+static gboolean gst_jack_ring_buffer_stop(GstAudioRingBuffer * buf);
+static guint gst_jack_ring_buffer_delay(GstAudioRingBuffer * buf);
+
+#endif 
diff --git a/ext/jack/gstjackutil.c b/ext/jack/gstjackutil.c
new file mode 100644
index 0000000..490e14a
--- /dev/null
+++ b/ext/jack/gstjackutil.c
@@ -0,0 +1,110 @@
+/* GStreamer Jack utility functions
+ * Copyright (C) 2010 Tristan Matthews <tristan@sat.qc.ca>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "gstjackutil.h"
+#include <gst/audio/audio.h>
+
+static const GstAudioChannelPosition default_positions[8][8] = {
+  /* 1 channel */
+  {
+        GST_AUDIO_CHANNEL_POSITION_MONO,
+      },
+  /* 2 channels */
+  {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+      },
+  /* 3 channels (2.1) */
+  {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_LFE1,        /* or FRONT_CENTER for 3.0? */
+      },
+  /* 4 channels (4.0 or 3.1?) */
+  {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+      },
+  /* 5 channels */
+  {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+      },
+  /* 6 channels */
+  {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+        GST_AUDIO_CHANNEL_POSITION_LFE1,
+      },
+  /* 7 channels */
+  {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+        GST_AUDIO_CHANNEL_POSITION_LFE1,
+        GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
+      },
+  /* 8 channels */
+  {
+        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+        GST_AUDIO_CHANNEL_POSITION_LFE1,
+        GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+      }
+};
+
+
+/* if channels are less than or equal to 8, we set a default layout,
+ * otherwise set layout to an array of GST_AUDIO_CHANNEL_POSITION_NONE */
+void
+gst_jack_set_layout (GstAudioRingBuffer * buffer, GstAudioRingBufferSpec * spec)
+{
+  gint i;
+
+  if (spec->info.channels <= 8) {
+    for (i = 0; i < spec->info.channels; i++)
+      spec->info.position[i] = default_positions[spec->info.channels - 1][i];
+    gst_audio_channel_positions_to_valid_order (spec->info.position,
+        spec->info.channels);
+    gst_audio_ring_buffer_set_channel_positions (buffer,
+        default_positions[spec->info.channels - 1]);
+  } else {
+    spec->info.flags |= GST_AUDIO_FLAG_UNPOSITIONED;
+    for (i = 0; i < G_N_ELEMENTS (spec->info.position); i++)
+      spec->info.position[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
+    gst_audio_ring_buffer_set_channel_positions (buffer, spec->info.position);
+  }
+
+  gst_caps_unref (spec->caps);
+  spec->caps = gst_audio_info_to_caps (&spec->info);
+}
diff --git a/ext/jack/gstjackutil.h b/ext/jack/gstjackutil.h
new file mode 100644
index 0000000..7a4bcc5
--- /dev/null
+++ b/ext/jack/gstjackutil.h
@@ -0,0 +1,31 @@
+/* GStreamer
+ * Copyright (C) 2010 Tristan Matthews <tristan@sat.qc.ca>
+ *
+ * gstjackutil.h:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GST_JACK_UTIL_H_
+#define _GST_JACK_UTIL_H_
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+
+void
+gst_jack_set_layout (GstAudioRingBuffer * buffer, GstAudioRingBufferSpec *spec);
+
+#endif  // _GST_JACK_UTIL_H_
diff --git a/ext/jack/meson.build b/ext/jack/meson.build
new file mode 100644
index 0000000..1a98a05
--- /dev/null
+++ b/ext/jack/meson.build
@@ -0,0 +1,20 @@
+jack_sources = [
+  'gstjackaudioclient.c',
+  'gstjackaudiosink.c',
+  'gstjackaudiosrc.c',
+  'gstjack.c',
+  'gstjackutil.c',
+]
+
+libjack_dep = dependency('jack', version : '>= 1.9.7', required : false)
+
+if libjack_dep.found()
+  gstjack = library('gstjack',
+    jack_sources,
+    c_args : gst_plugins_good_args + ['-DHAVE_JACK_1_9_7'],
+    include_directories : [configinc, libsinc],
+    dependencies : [gst_dep, gstbase_dep, gstaudio_dep, libjack_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/ext/jpeg/Makefile.am b/ext/jpeg/Makefile.am
new file mode 100644
index 0000000..7975455
--- /dev/null
+++ b/ext/jpeg/Makefile.am
@@ -0,0 +1,17 @@
+plugin_LTLIBRARIES = libgstjpeg.la
+
+libgstjpeg_la_SOURCES = \
+	gstjpeg.c \
+	gstjpegenc.c \
+	gstjpegdec.c
+# deprected gstsmokeenc.c smokecodec.c gstsmokedec.c
+
+libgstjpeg_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstjpeg_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) -lgstvideo-$(GST_API_VERSION) \
+	$(JPEG_LIBS) $(LIBM)
+libgstjpeg_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = \
+	gstjpeg.h \
+	gstjpegdec.h gstjpegenc.h
+# deprecated gstsmokeenc.h gstsmokedec.h smokecodec.h smokeformat.h
diff --git a/ext/jpeg/README b/ext/jpeg/README
new file mode 100644
index 0000000..ffa1d0c
--- /dev/null
+++ b/ext/jpeg/README
@@ -0,0 +1,20 @@
+The Smoke Codec
+---------------
+
+This is a very simple compression algorithm I was toying with when doing a
+Java based player. Decoding a JPEG in Java has acceptable speed so this codec
+tries to exploit that feature. The algorithm first compares the last and the 
+new image and finds all 16x16 blocks that have a squared difference bigger than
+a configurable threshold. Then all these blocks are compressed into an NxM JPEG.
+The quality of the JPEG is inversely proportional to the number of blocks, this
+way, the picture quality degrades with heavy motion scenes but the bitrate stays
+more or less constant.
+Decoding decompresses the JPEG and then updates the old picture with the new
+blocks.
+
+
+TODO:
+----
+- make format extensible
+- motion vectors
+- do some real bitrate control
diff --git a/ext/jpeg/gstjpeg.c b/ext/jpeg/gstjpeg.c
new file mode 100644
index 0000000..9ecdd5d
--- /dev/null
+++ b/ext/jpeg/gstjpeg.c
@@ -0,0 +1,81 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <gst/gst.h>
+
+#include "gstjpeg.h"
+#include "gstjpegdec.h"
+#include "gstjpegenc.h"
+#if 0
+#include "gstsmokeenc.h"
+#include "gstsmokedec.h"
+#endif
+
+GType
+gst_idct_method_get_type (void)
+{
+  static GType idct_method_type = 0;
+  static const GEnumValue idct_method[] = {
+    {JDCT_ISLOW, "Slow but accurate integer algorithm", "islow"},
+    {JDCT_IFAST, "Faster, less accurate integer method", "ifast"},
+    {JDCT_FLOAT, "Floating-point: accurate, fast on fast HW", "float"},
+    {0, NULL, NULL},
+  };
+
+  if (!idct_method_type) {
+    idct_method_type = g_enum_register_static ("GstIDCTMethod", idct_method);
+  }
+  return idct_method_type;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+
+  if (!gst_element_register (plugin, "jpegenc", GST_RANK_PRIMARY,
+          GST_TYPE_JPEGENC))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "jpegdec", GST_RANK_PRIMARY,
+          GST_TYPE_JPEG_DEC))
+    return FALSE;
+
+#if 0
+  if (!gst_element_register (plugin, "smokeenc", GST_RANK_PRIMARY,
+          GST_TYPE_SMOKEENC))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "smokedec", GST_RANK_PRIMARY,
+          GST_TYPE_SMOKEDEC))
+    return FALSE;
+#endif
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    jpeg,
+    "JPeg plugin library",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/jpeg/gstjpeg.h b/ext/jpeg/gstjpeg.h
new file mode 100644
index 0000000..afa30a2
--- /dev/null
+++ b/ext/jpeg/gstjpeg.h
@@ -0,0 +1,35 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_JPEG_H__
+#define __GST_JPEG_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+
+#define GST_TYPE_IDCT_METHOD (gst_idct_method_get_type())
+GType gst_idct_method_get_type (void);
+
+
+G_END_DECLS
+
+#endif /* __GST_JPEG_H__ */
diff --git a/ext/jpeg/gstjpegdec.c b/ext/jpeg/gstjpegdec.c
new file mode 100644
index 0000000..d88b258
--- /dev/null
+++ b/ext/jpeg/gstjpegdec.c
@@ -0,0 +1,1555 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2012 Collabora Ltd.
+ *	Author : Edward Hervey <edward@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-jpegdec
+ *
+ * Decodes jpeg images.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v filesrc location=mjpeg.avi ! avidemux !  queue ! jpegdec ! videoconvert ! videoscale ! autovideosink
+ * ]| The above pipeline decode the mjpeg stream and renders it to the screen.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+
+#include "gstjpegdec.h"
+#include "gstjpeg.h"
+#include <gst/video/video.h>
+#include <gst/video/gstvideometa.h>
+#include <gst/video/gstvideopool.h>
+#include "gst/gst-i18n-plugin.h"
+#include <jerror.h>
+
+#define MIN_WIDTH  1
+#define MAX_WIDTH  65535
+#define MIN_HEIGHT 1
+#define MAX_HEIGHT 65535
+
+#define CINFO_GET_JPEGDEC(cinfo_ptr) \
+        (((struct GstJpegDecSourceMgr*)((cinfo_ptr)->src))->dec)
+
+#define JPEG_DEFAULT_IDCT_METHOD	JDCT_FASTEST
+#define JPEG_DEFAULT_MAX_ERRORS 	0
+
+enum
+{
+  PROP_0,
+  PROP_IDCT_METHOD,
+  PROP_MAX_ERRORS
+};
+
+/* *INDENT-OFF* */
+static GstStaticPadTemplate gst_jpeg_dec_src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
+        ("{ I420, RGB, BGR, RGBx, xRGB, BGRx, xBGR, GRAY8 }"))
+    );
+/* *INDENT-ON* */
+
+/* FIXME: sof-marker is for IJG libjpeg 8, should be different for 6.2 */
+/* FIXME: add back "sof-marker = (int) { 0, 1, 2, 5, 6, 7, 9, 10, 13, 14 }"
+ * once we have a parser and/or demuxer set caps properly */
+static GstStaticPadTemplate gst_jpeg_dec_sink_pad_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("image/jpeg")
+    );
+
+GST_DEBUG_CATEGORY_STATIC (jpeg_dec_debug);
+#define GST_CAT_DEFAULT jpeg_dec_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
+
+static void gst_jpeg_dec_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_jpeg_dec_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_jpeg_dec_set_format (GstVideoDecoder * dec,
+    GstVideoCodecState * state);
+static gboolean gst_jpeg_dec_start (GstVideoDecoder * bdec);
+static gboolean gst_jpeg_dec_stop (GstVideoDecoder * bdec);
+static gboolean gst_jpeg_dec_flush (GstVideoDecoder * bdec);
+static GstFlowReturn gst_jpeg_dec_parse (GstVideoDecoder * bdec,
+    GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos);
+static GstFlowReturn gst_jpeg_dec_handle_frame (GstVideoDecoder * bdec,
+    GstVideoCodecFrame * frame);
+static gboolean gst_jpeg_dec_decide_allocation (GstVideoDecoder * bdec,
+    GstQuery * query);
+static gboolean gst_jpeg_dec_sink_event (GstVideoDecoder * bdec,
+    GstEvent * event);
+
+#define gst_jpeg_dec_parent_class parent_class
+G_DEFINE_TYPE (GstJpegDec, gst_jpeg_dec, GST_TYPE_VIDEO_DECODER);
+
+static void
+gst_jpeg_dec_finalize (GObject * object)
+{
+  GstJpegDec *dec = GST_JPEG_DEC (object);
+
+  jpeg_destroy_decompress (&dec->cinfo);
+  if (dec->input_state)
+    gst_video_codec_state_unref (dec->input_state);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_jpeg_dec_class_init (GstJpegDecClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+  GstVideoDecoderClass *vdec_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = (GstElementClass *) klass;
+  vdec_class = (GstVideoDecoderClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gst_jpeg_dec_finalize;
+  gobject_class->set_property = gst_jpeg_dec_set_property;
+  gobject_class->get_property = gst_jpeg_dec_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_IDCT_METHOD,
+      g_param_spec_enum ("idct-method", "IDCT Method",
+          "The IDCT algorithm to use", GST_TYPE_IDCT_METHOD,
+          JPEG_DEFAULT_IDCT_METHOD,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstJpegDec:max-errors:
+   *
+   * Error out after receiving N consecutive decoding errors
+   * (-1 = never error out, 0 = automatic, 1 = fail on first error, etc.)
+   *
+   * Deprecated: 1.3.1: Property wasn't used internally
+   */
+#ifndef GST_REMOVE_DEPRECATED
+  g_object_class_install_property (gobject_class, PROP_MAX_ERRORS,
+      g_param_spec_int ("max-errors", "Maximum Consecutive Decoding Errors",
+          "(Deprecated) Error out after receiving N consecutive decoding errors"
+          " (-1 = never fail, 0 = automatic, 1 = fail on first error)",
+          -1, G_MAXINT, JPEG_DEFAULT_MAX_ERRORS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
+#endif
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_jpeg_dec_src_pad_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_jpeg_dec_sink_pad_template);
+  gst_element_class_set_static_metadata (element_class, "JPEG image decoder",
+      "Codec/Decoder/Image", "Decode images from JPEG format",
+      "Wim Taymans <wim@fluendo.com>");
+
+  vdec_class->start = gst_jpeg_dec_start;
+  vdec_class->stop = gst_jpeg_dec_stop;
+  vdec_class->flush = gst_jpeg_dec_flush;
+  vdec_class->parse = gst_jpeg_dec_parse;
+  vdec_class->set_format = gst_jpeg_dec_set_format;
+  vdec_class->handle_frame = gst_jpeg_dec_handle_frame;
+  vdec_class->decide_allocation = gst_jpeg_dec_decide_allocation;
+  vdec_class->sink_event = gst_jpeg_dec_sink_event;
+
+  GST_DEBUG_CATEGORY_INIT (jpeg_dec_debug, "jpegdec", 0, "JPEG decoder");
+  GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
+}
+
+static boolean
+gst_jpeg_dec_fill_input_buffer (j_decompress_ptr cinfo)
+{
+  /* We pass in full frame initially, if this get called, the frame is most likely
+   * corrupted */
+  return FALSE;
+}
+
+static void
+gst_jpeg_dec_init_source (j_decompress_ptr cinfo)
+{
+  GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "init_source");
+}
+
+
+static void
+gst_jpeg_dec_skip_input_data (j_decompress_ptr cinfo, glong num_bytes)
+{
+  GstJpegDec *dec = CINFO_GET_JPEGDEC (cinfo);
+
+  GST_DEBUG_OBJECT (dec, "skip %ld bytes", num_bytes);
+
+  if (num_bytes > 0 && cinfo->src->bytes_in_buffer >= num_bytes) {
+    cinfo->src->next_input_byte += (size_t) num_bytes;
+    cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
+  }
+}
+
+static boolean
+gst_jpeg_dec_resync_to_restart (j_decompress_ptr cinfo, gint desired)
+{
+  GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "resync_to_start");
+  return TRUE;
+}
+
+static void
+gst_jpeg_dec_term_source (j_decompress_ptr cinfo)
+{
+  GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "term_source");
+  return;
+}
+
+METHODDEF (void)
+    gst_jpeg_dec_my_output_message (j_common_ptr cinfo)
+{
+  return;                       /* do nothing */
+}
+
+METHODDEF (void)
+    gst_jpeg_dec_my_emit_message (j_common_ptr cinfo, int msg_level)
+{
+  /* GST_LOG_OBJECT (CINFO_GET_JPEGDEC (&cinfo), "msg_level=%d", msg_level); */
+  return;
+}
+
+METHODDEF (void)
+    gst_jpeg_dec_my_error_exit (j_common_ptr cinfo)
+{
+  struct GstJpegDecErrorMgr *err_mgr = (struct GstJpegDecErrorMgr *) cinfo->err;
+
+  (*cinfo->err->output_message) (cinfo);
+  longjmp (err_mgr->setjmp_buffer, 1);
+}
+
+static void
+gst_jpeg_dec_init (GstJpegDec * dec)
+{
+  GST_DEBUG ("initializing");
+
+  /* setup jpeglib */
+  memset (&dec->cinfo, 0, sizeof (dec->cinfo));
+  memset (&dec->jerr, 0, sizeof (dec->jerr));
+  dec->cinfo.err = jpeg_std_error (&dec->jerr.pub);
+  dec->jerr.pub.output_message = gst_jpeg_dec_my_output_message;
+  dec->jerr.pub.emit_message = gst_jpeg_dec_my_emit_message;
+  dec->jerr.pub.error_exit = gst_jpeg_dec_my_error_exit;
+
+  jpeg_create_decompress (&dec->cinfo);
+
+  dec->cinfo.src = (struct jpeg_source_mgr *) &dec->jsrc;
+  dec->cinfo.src->init_source = gst_jpeg_dec_init_source;
+  dec->cinfo.src->fill_input_buffer = gst_jpeg_dec_fill_input_buffer;
+  dec->cinfo.src->skip_input_data = gst_jpeg_dec_skip_input_data;
+  dec->cinfo.src->resync_to_restart = gst_jpeg_dec_resync_to_restart;
+  dec->cinfo.src->term_source = gst_jpeg_dec_term_source;
+  dec->jsrc.dec = dec;
+
+  /* init properties */
+  dec->idct_method = JPEG_DEFAULT_IDCT_METHOD;
+  dec->max_errors = JPEG_DEFAULT_MAX_ERRORS;
+
+  gst_video_decoder_set_use_default_pad_acceptcaps (GST_VIDEO_DECODER_CAST
+      (dec), TRUE);
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_DECODER_SINK_PAD (dec));
+}
+
+static inline gboolean
+gst_jpeg_dec_parse_tag_has_entropy_segment (guint8 tag)
+{
+  if (tag == 0xda || (tag >= 0xd0 && tag <= 0xd7))
+    return TRUE;
+  return FALSE;
+}
+
+static GstFlowReturn
+gst_jpeg_dec_parse (GstVideoDecoder * bdec, GstVideoCodecFrame * frame,
+    GstAdapter * adapter, gboolean at_eos)
+{
+  guint size;
+  gint toadd = 0;
+  gboolean resync;
+  gint offset = 0, noffset;
+  GstJpegDec *dec = (GstJpegDec *) bdec;
+
+  GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
+
+  /* FIXME : The overhead of using scan_uint32 is massive */
+
+  size = gst_adapter_available (adapter);
+  GST_DEBUG ("Parsing jpeg image data (%u bytes)", size);
+
+  if (at_eos) {
+    GST_DEBUG ("Flushing all data out");
+    toadd = size;
+
+    /* If we have leftover data, throw it away */
+    if (!dec->saw_header)
+      goto drop_frame;
+    goto have_full_frame;
+  }
+
+  if (size < 8)
+    goto need_more_data;
+
+  if (!dec->saw_header) {
+    gint ret;
+    /* we expect at least 4 bytes, first of which start marker */
+    ret =
+        gst_adapter_masked_scan_uint32 (adapter, 0xffff0000, 0xffd80000, 0,
+        size - 4);
+
+    GST_DEBUG ("ret:%d", ret);
+    if (ret < 0)
+      goto need_more_data;
+
+    if (ret) {
+      gst_adapter_flush (adapter, ret);
+      size -= ret;
+    }
+    dec->saw_header = TRUE;
+  }
+
+  while (1) {
+    guint frame_len;
+    guint32 value;
+
+    GST_DEBUG ("offset:%d, size:%d", offset, size);
+
+    noffset =
+        gst_adapter_masked_scan_uint32_peek (adapter, 0x0000ff00, 0x0000ff00,
+        offset, size - offset, &value);
+
+    /* lost sync if 0xff marker not where expected */
+    if ((resync = (noffset != offset))) {
+      GST_DEBUG ("Lost sync at 0x%08x, resyncing", offset + 2);
+    }
+    /* may have marker, but could have been resyncng */
+    resync = resync || dec->parse_resync;
+    /* Skip over extra 0xff */
+    while ((noffset >= 0) && ((value & 0xff) == 0xff)) {
+      noffset++;
+      noffset =
+          gst_adapter_masked_scan_uint32_peek (adapter, 0x0000ff00, 0x0000ff00,
+          noffset, size - noffset, &value);
+    }
+    /* enough bytes left for marker? (we need 0xNN after the 0xff) */
+    if (noffset < 0) {
+      GST_DEBUG ("at end of input and no EOI marker found, need more data");
+      goto need_more_data;
+    }
+
+    /* now lock on the marker we found */
+    offset = noffset;
+    value = value & 0xff;
+    if (value == 0xd9) {
+      GST_DEBUG ("0x%08x: EOI marker", offset + 2);
+      /* clear parse state */
+      dec->saw_header = FALSE;
+      dec->parse_resync = FALSE;
+      toadd = offset + 4;
+      goto have_full_frame;
+    }
+    if (value == 0xd8) {
+      GST_DEBUG ("0x%08x: SOI marker before EOI marker", offset + 2);
+
+      /* clear parse state */
+      dec->saw_header = FALSE;
+      dec->parse_resync = FALSE;
+      toadd = offset;
+      goto have_full_frame;
+    }
+
+
+    if (value >= 0xd0 && value <= 0xd7)
+      frame_len = 0;
+    else {
+      /* peek tag and subsequent length */
+      if (offset + 2 + 4 > size)
+        goto need_more_data;
+      else
+        gst_adapter_masked_scan_uint32_peek (adapter, 0x0, 0x0, offset + 2, 4,
+            &frame_len);
+      frame_len = frame_len & 0xffff;
+    }
+    GST_DEBUG ("0x%08x: tag %02x, frame_len=%u", offset + 2, value, frame_len);
+    /* the frame length includes the 2 bytes for the length; here we want at
+     * least 2 more bytes at the end for an end marker */
+    if (offset + 2 + 2 + frame_len + 2 > size) {
+      goto need_more_data;
+    }
+
+    if (gst_jpeg_dec_parse_tag_has_entropy_segment (value)) {
+      guint eseglen = dec->parse_entropy_len;
+
+      GST_DEBUG ("0x%08x: finding entropy segment length (eseglen:%d)",
+          offset + 2, eseglen);
+      if (size < offset + 2 + frame_len + eseglen)
+        goto need_more_data;
+      noffset = offset + 2 + frame_len + dec->parse_entropy_len;
+      while (1) {
+        GST_DEBUG ("noffset:%d, size:%d, size - noffset:%d",
+            noffset, size, size - noffset);
+        noffset = gst_adapter_masked_scan_uint32_peek (adapter, 0x0000ff00,
+            0x0000ff00, noffset, size - noffset, &value);
+        if (noffset < 0) {
+          /* need more data */
+          dec->parse_entropy_len = size - offset - 4 - frame_len - 2;
+          goto need_more_data;
+        }
+        if ((value & 0xff) != 0x00) {
+          eseglen = noffset - offset - frame_len - 2;
+          break;
+        }
+        noffset++;
+      }
+      dec->parse_entropy_len = 0;
+      frame_len += eseglen;
+      GST_DEBUG ("entropy segment length=%u => frame_len=%u", eseglen,
+          frame_len);
+    }
+    if (resync) {
+      /* check if we will still be in sync if we interpret
+       * this as a sync point and skip this frame */
+      noffset = offset + frame_len + 2;
+      noffset = gst_adapter_masked_scan_uint32 (adapter, 0x0000ff00, 0x0000ff00,
+          noffset, 4);
+      if (noffset < 0) {
+        /* ignore and continue resyncing until we hit the end
+         * of our data or find a sync point that looks okay */
+        offset++;
+        continue;
+      }
+      GST_DEBUG ("found sync at 0x%x", offset + 2);
+    }
+
+    /* Add current data to output buffer */
+    toadd += frame_len + 2;
+    offset += frame_len + 2;
+  }
+
+need_more_data:
+  if (toadd)
+    gst_video_decoder_add_to_frame (bdec, toadd);
+  return GST_VIDEO_DECODER_FLOW_NEED_DATA;
+
+have_full_frame:
+  if (toadd)
+    gst_video_decoder_add_to_frame (bdec, toadd);
+  GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
+  return gst_video_decoder_have_frame (bdec);
+
+drop_frame:
+  gst_adapter_flush (adapter, size);
+  return GST_FLOW_OK;
+}
+
+
+/* shamelessly ripped from jpegutils.c in mjpegtools */
+static void
+add_huff_table (j_decompress_ptr dinfo,
+    JHUFF_TBL ** htblptr, const UINT8 * bits, const UINT8 * val)
+/* Define a Huffman table */
+{
+  int nsymbols, len;
+
+  if (*htblptr == NULL)
+    *htblptr = jpeg_alloc_huff_table ((j_common_ptr) dinfo);
+
+  g_assert (*htblptr);
+
+  /* Copy the number-of-symbols-of-each-code-length counts */
+  memcpy ((*htblptr)->bits, bits, sizeof ((*htblptr)->bits));
+
+  /* Validate the counts.  We do this here mainly so we can copy the right
+   * number of symbols from the val[] array, without risking marching off
+   * the end of memory.  jchuff.c will do a more thorough test later.
+   */
+  nsymbols = 0;
+  for (len = 1; len <= 16; len++)
+    nsymbols += bits[len];
+  if (nsymbols < 1 || nsymbols > 256)
+    g_error ("jpegutils.c:  add_huff_table failed badly. ");
+
+  memcpy ((*htblptr)->huffval, val, nsymbols * sizeof (UINT8));
+}
+
+
+
+static void
+std_huff_tables (j_decompress_ptr dinfo)
+/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
+/* IMPORTANT: these are only valid for 8-bit data precision! */
+{
+  static const UINT8 bits_dc_luminance[17] =
+      { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
+  static const UINT8 val_dc_luminance[] =
+      { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+
+  static const UINT8 bits_dc_chrominance[17] =
+      { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
+  static const UINT8 val_dc_chrominance[] =
+      { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+
+  static const UINT8 bits_ac_luminance[17] =
+      { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
+  static const UINT8 val_ac_luminance[] =
+      { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+    0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+    0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+    0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+    0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+    0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+    0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+    0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+    0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+    0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+    0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+    0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+    0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+    0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+    0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+    0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+    0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+    0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+    0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+    0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+    0xf9, 0xfa
+  };
+
+  static const UINT8 bits_ac_chrominance[17] =
+      { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
+  static const UINT8 val_ac_chrominance[] =
+      { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+    0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+    0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+    0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+    0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+    0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+    0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+    0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+    0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+    0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+    0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+    0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+    0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+    0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+    0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+    0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+    0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+    0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+    0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+    0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+    0xf9, 0xfa
+  };
+
+  add_huff_table (dinfo, &dinfo->dc_huff_tbl_ptrs[0],
+      bits_dc_luminance, val_dc_luminance);
+  add_huff_table (dinfo, &dinfo->ac_huff_tbl_ptrs[0],
+      bits_ac_luminance, val_ac_luminance);
+  add_huff_table (dinfo, &dinfo->dc_huff_tbl_ptrs[1],
+      bits_dc_chrominance, val_dc_chrominance);
+  add_huff_table (dinfo, &dinfo->ac_huff_tbl_ptrs[1],
+      bits_ac_chrominance, val_ac_chrominance);
+}
+
+
+
+static void
+guarantee_huff_tables (j_decompress_ptr dinfo)
+{
+  if ((dinfo->dc_huff_tbl_ptrs[0] == NULL) &&
+      (dinfo->dc_huff_tbl_ptrs[1] == NULL) &&
+      (dinfo->ac_huff_tbl_ptrs[0] == NULL) &&
+      (dinfo->ac_huff_tbl_ptrs[1] == NULL)) {
+    GST_DEBUG ("Generating standard Huffman tables for this frame.");
+    std_huff_tables (dinfo);
+  }
+}
+
+static gboolean
+gst_jpeg_dec_set_format (GstVideoDecoder * dec, GstVideoCodecState * state)
+{
+  GstJpegDec *jpeg = GST_JPEG_DEC (dec);
+
+  if (jpeg->input_state)
+    gst_video_codec_state_unref (jpeg->input_state);
+  jpeg->input_state = gst_video_codec_state_ref (state);
+
+  return TRUE;
+}
+
+
+/* yuk */
+static void
+hresamplecpy1 (guint8 * dest, const guint8 * src, guint len)
+{
+  gint i;
+
+  for (i = 0; i < len; ++i) {
+    /* equivalent to: dest[i] = src[i << 1] */
+    *dest = *src;
+    ++dest;
+    ++src;
+    ++src;
+  }
+}
+
+static void
+gst_jpeg_dec_free_buffers (GstJpegDec * dec)
+{
+  gint i;
+
+  for (i = 0; i < 16; i++) {
+    g_free (dec->idr_y[i]);
+    g_free (dec->idr_u[i]);
+    g_free (dec->idr_v[i]);
+    dec->idr_y[i] = NULL;
+    dec->idr_u[i] = NULL;
+    dec->idr_v[i] = NULL;
+  }
+
+  dec->idr_width_allocated = 0;
+}
+
+static inline gboolean
+gst_jpeg_dec_ensure_buffers (GstJpegDec * dec, guint maxrowbytes)
+{
+  gint i;
+
+  if (G_LIKELY (dec->idr_width_allocated == maxrowbytes))
+    return TRUE;
+
+  /* FIXME: maybe just alloc one or three blocks altogether? */
+  for (i = 0; i < 16; i++) {
+    dec->idr_y[i] = g_try_realloc (dec->idr_y[i], maxrowbytes);
+    dec->idr_u[i] = g_try_realloc (dec->idr_u[i], maxrowbytes);
+    dec->idr_v[i] = g_try_realloc (dec->idr_v[i], maxrowbytes);
+
+    if (G_UNLIKELY (!dec->idr_y[i] || !dec->idr_u[i] || !dec->idr_v[i])) {
+      GST_WARNING_OBJECT (dec, "out of memory, i=%d, bytes=%u", i, maxrowbytes);
+      return FALSE;
+    }
+  }
+
+  dec->idr_width_allocated = maxrowbytes;
+  GST_LOG_OBJECT (dec, "allocated temp memory, %u bytes/row", maxrowbytes);
+  return TRUE;
+}
+
+static void
+gst_jpeg_dec_decode_grayscale (GstJpegDec * dec, GstVideoFrame * frame,
+    guint field, guint num_fields)
+{
+  guchar *rows[16];
+  guchar **scanarray[1] = { rows };
+  gint i, j, k;
+  gint lines;
+  guint8 *base[1];
+  gint width, height;
+  gint pstride, rstride;
+
+  GST_DEBUG_OBJECT (dec, "indirect decoding of grayscale");
+
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame) / num_fields;
+
+  if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
+    return;
+
+  base[0] = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
+  if (field == 2) {
+    base[0] += GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
+  }
+
+  pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
+  rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) * num_fields;
+
+  memcpy (rows, dec->idr_y, 16 * sizeof (gpointer));
+
+  i = 0;
+  while (i < height) {
+    lines = jpeg_read_raw_data (&dec->cinfo, scanarray, DCTSIZE);
+    if (G_LIKELY (lines > 0)) {
+      for (j = 0; (j < DCTSIZE) && (i < height); j++, i++) {
+        gint p;
+
+        p = 0;
+        for (k = 0; k < width; k++) {
+          base[0][p] = rows[j][k];
+          p += pstride;
+        }
+        base[0] += rstride;
+      }
+    } else {
+      GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
+    }
+  }
+}
+
+static void
+gst_jpeg_dec_decode_rgb (GstJpegDec * dec, GstVideoFrame * frame,
+    guint field, guint num_fields)
+{
+  guchar *r_rows[16], *g_rows[16], *b_rows[16];
+  guchar **scanarray[3] = { r_rows, g_rows, b_rows };
+  gint i, j, k;
+  gint lines;
+  guint8 *base[3];
+  guint pstride, rstride;
+  gint width, height;
+
+  GST_DEBUG_OBJECT (dec, "indirect decoding of RGB");
+
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame) / num_fields;
+
+  if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
+    return;
+
+  for (i = 0; i < 3; i++) {
+    base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
+    if (field == 2)
+      base[i] += GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
+  }
+
+  pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
+  rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) * num_fields;
+
+  memcpy (r_rows, dec->idr_y, 16 * sizeof (gpointer));
+  memcpy (g_rows, dec->idr_u, 16 * sizeof (gpointer));
+  memcpy (b_rows, dec->idr_v, 16 * sizeof (gpointer));
+
+  i = 0;
+  while (i < height) {
+    lines = jpeg_read_raw_data (&dec->cinfo, scanarray, DCTSIZE);
+    if (G_LIKELY (lines > 0)) {
+      for (j = 0; (j < DCTSIZE) && (i < height); j++, i++) {
+        gint p;
+
+        p = 0;
+        for (k = 0; k < width; k++) {
+          base[0][p] = r_rows[j][k];
+          base[1][p] = g_rows[j][k];
+          base[2][p] = b_rows[j][k];
+          p += pstride;
+        }
+        base[0] += rstride;
+        base[1] += rstride;
+        base[2] += rstride;
+      }
+    } else {
+      GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
+    }
+  }
+}
+
+static void
+gst_jpeg_dec_decode_indirect (GstJpegDec * dec, GstVideoFrame * frame, gint r_v,
+    gint r_h, gint comp, guint field, guint num_fields)
+{
+  guchar *y_rows[16], *u_rows[16], *v_rows[16];
+  guchar **scanarray[3] = { y_rows, u_rows, v_rows };
+  gint i, j, k;
+  gint lines;
+  guchar *base[3], *last[3];
+  gint rowsize[3], stride[3];
+  gint width, height;
+
+  GST_DEBUG_OBJECT (dec,
+      "unadvantageous width or r_h, taking slow route involving memcpy");
+
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
+
+  if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
+    return;
+
+  for (i = 0; i < 3; i++) {
+    base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
+    stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i) * num_fields;
+    rowsize[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
+    /* make sure we don't make jpeglib write beyond our buffer,
+     * which might happen if (height % (r_v*DCTSIZE)) != 0 */
+    last[i] = base[i] + (GST_VIDEO_FRAME_COMP_STRIDE (frame, i) *
+        (GST_VIDEO_FRAME_COMP_HEIGHT (frame, i) - 1));
+
+    if (field == 2) {
+      base[i] += GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
+    }
+  }
+
+  memcpy (y_rows, dec->idr_y, 16 * sizeof (gpointer));
+  memcpy (u_rows, dec->idr_u, 16 * sizeof (gpointer));
+  memcpy (v_rows, dec->idr_v, 16 * sizeof (gpointer));
+
+  /* fill chroma components for grayscale */
+  if (comp == 1) {
+    GST_DEBUG_OBJECT (dec, "grayscale, filling chroma");
+    for (i = 0; i < 16; i++) {
+      memset (u_rows[i], GST_ROUND_UP_32 (width), 0x80);
+      memset (v_rows[i], GST_ROUND_UP_32 (width), 0x80);
+    }
+  }
+
+  for (i = 0; i < height; i += r_v * DCTSIZE) {
+    lines = jpeg_read_raw_data (&dec->cinfo, scanarray, r_v * DCTSIZE);
+    if (G_LIKELY (lines > 0)) {
+      for (j = 0, k = 0; j < (r_v * DCTSIZE); j += r_v, k++) {
+        if (G_LIKELY (base[0] <= last[0])) {
+          memcpy (base[0], y_rows[j], rowsize[0]);
+          base[0] += stride[0];
+        }
+        if (r_v == 2) {
+          if (G_LIKELY (base[0] <= last[0])) {
+            memcpy (base[0], y_rows[j + 1], rowsize[0]);
+            base[0] += stride[0];
+          }
+        }
+        if (G_LIKELY (base[1] <= last[1] && base[2] <= last[2])) {
+          if (r_h == 2) {
+            memcpy (base[1], u_rows[k], rowsize[1]);
+            memcpy (base[2], v_rows[k], rowsize[2]);
+          } else if (r_h == 1) {
+            hresamplecpy1 (base[1], u_rows[k], rowsize[1]);
+            hresamplecpy1 (base[2], v_rows[k], rowsize[2]);
+          } else {
+            /* FIXME: implement (at least we avoid crashing by doing nothing) */
+          }
+        }
+
+        if (r_v == 2 || (k & 1) != 0) {
+          base[1] += stride[1];
+          base[2] += stride[2];
+        }
+      }
+    } else {
+      GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
+    }
+  }
+}
+
+static GstFlowReturn
+gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame,
+    guint field, guint num_fields)
+{
+  guchar **line[3];             /* the jpeg line buffer         */
+  guchar *y[4 * DCTSIZE] = { NULL, };   /* alloc enough for the lines   */
+  guchar *u[4 * DCTSIZE] = { NULL, };   /* r_v will be <4               */
+  guchar *v[4 * DCTSIZE] = { NULL, };
+  gint i, j;
+  gint lines, v_samp[3];
+  guchar *base[3], *last[3];
+  gint stride[3];
+  guint height;
+
+  line[0] = y;
+  line[1] = u;
+  line[2] = v;
+
+  v_samp[0] = dec->cinfo.comp_info[0].v_samp_factor;
+  v_samp[1] = dec->cinfo.comp_info[1].v_samp_factor;
+  v_samp[2] = dec->cinfo.comp_info[2].v_samp_factor;
+
+  if (G_UNLIKELY (v_samp[0] > 2 || v_samp[1] > 2 || v_samp[2] > 2))
+    goto format_not_supported;
+
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
+
+  for (i = 0; i < 3; i++) {
+    base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
+    stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i) * num_fields;
+    /* make sure we don't make jpeglib write beyond our buffer,
+     * which might happen if (height % (r_v*DCTSIZE)) != 0 */
+    last[i] = base[i] + (GST_VIDEO_FRAME_COMP_STRIDE (frame, i) *
+        (GST_VIDEO_FRAME_COMP_HEIGHT (frame, i) - 1));
+
+    if (field == 2) {
+      base[i] += GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
+    }
+  }
+
+  /* let jpeglib decode directly into our final buffer */
+  GST_DEBUG_OBJECT (dec, "decoding directly into output buffer");
+
+  for (i = 0; i < height; i += v_samp[0] * DCTSIZE) {
+    for (j = 0; j < (v_samp[0] * DCTSIZE); ++j) {
+      /* Y */
+      line[0][j] = base[0] + (i + j) * stride[0];
+      if (G_UNLIKELY (line[0][j] > last[0]))
+        line[0][j] = last[0];
+      /* U */
+      if (v_samp[1] == v_samp[0]) {
+        line[1][j] = base[1] + ((i + j) / 2) * stride[1];
+      } else if (j < (v_samp[1] * DCTSIZE)) {
+        line[1][j] = base[1] + ((i / 2) + j) * stride[1];
+      }
+      if (G_UNLIKELY (line[1][j] > last[1]))
+        line[1][j] = last[1];
+      /* V */
+      if (v_samp[2] == v_samp[0]) {
+        line[2][j] = base[2] + ((i + j) / 2) * stride[2];
+      } else if (j < (v_samp[2] * DCTSIZE)) {
+        line[2][j] = base[2] + ((i / 2) + j) * stride[2];
+      }
+      if (G_UNLIKELY (line[2][j] > last[2]))
+        line[2][j] = last[2];
+    }
+
+    lines = jpeg_read_raw_data (&dec->cinfo, line, v_samp[0] * DCTSIZE);
+    if (G_UNLIKELY (!lines)) {
+      GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
+    }
+  }
+  return GST_FLOW_OK;
+
+format_not_supported:
+  {
+    gboolean ret = GST_FLOW_OK;
+
+    GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
+        (_("Failed to decode JPEG image")),
+        ("Unsupported subsampling schema: v_samp factors: %u %u %u", v_samp[0],
+            v_samp[1], v_samp[2]), ret);
+
+    return ret;
+  }
+}
+
+static void
+gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc,
+    gboolean interlaced)
+{
+  GstVideoCodecState *outstate;
+  GstVideoInfo *info;
+  GstVideoFormat format;
+
+  switch (clrspc) {
+    case JCS_RGB:
+      format = GST_VIDEO_FORMAT_RGB;
+      break;
+    case JCS_GRAYSCALE:
+      format = GST_VIDEO_FORMAT_GRAY8;
+      break;
+    default:
+      format = GST_VIDEO_FORMAT_I420;
+      break;
+  }
+
+  /* Compare to currently configured output state */
+  outstate = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (dec));
+  if (outstate) {
+    info = &outstate->info;
+
+    if (width == GST_VIDEO_INFO_WIDTH (info) &&
+        height == GST_VIDEO_INFO_HEIGHT (info) &&
+        format == GST_VIDEO_INFO_FORMAT (info)) {
+      gst_video_codec_state_unref (outstate);
+      return;
+    }
+    gst_video_codec_state_unref (outstate);
+  }
+
+  outstate =
+      gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec), format,
+      width, height, dec->input_state);
+
+  switch (clrspc) {
+    case JCS_RGB:
+    case JCS_GRAYSCALE:
+      break;
+    default:
+      outstate->info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
+      outstate->info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
+      outstate->info.colorimetry.transfer = GST_VIDEO_TRANSFER_UNKNOWN;
+      outstate->info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
+      break;
+  }
+
+  if (interlaced) {
+    outstate->info.interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
+    GST_VIDEO_INFO_FIELD_ORDER (&outstate->info) =
+        GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST;
+  }
+
+  gst_video_codec_state_unref (outstate);
+
+  gst_video_decoder_negotiate (GST_VIDEO_DECODER (dec));
+
+  GST_DEBUG_OBJECT (dec, "max_v_samp_factor=%d", dec->cinfo.max_v_samp_factor);
+  GST_DEBUG_OBJECT (dec, "max_h_samp_factor=%d", dec->cinfo.max_h_samp_factor);
+}
+
+static GstFlowReturn
+gst_jpeg_dec_prepare_decode (GstJpegDec * dec)
+{
+  G_GNUC_UNUSED GstFlowReturn ret;
+  guint r_h, r_v, hdr_ok;
+
+  /* read header */
+  hdr_ok = jpeg_read_header (&dec->cinfo, TRUE);
+  if (G_UNLIKELY (hdr_ok != JPEG_HEADER_OK)) {
+    GST_WARNING_OBJECT (dec, "reading the header failed, %d", hdr_ok);
+  }
+
+  GST_LOG_OBJECT (dec, "num_components=%d", dec->cinfo.num_components);
+  GST_LOG_OBJECT (dec, "jpeg_color_space=%d", dec->cinfo.jpeg_color_space);
+
+  if (!dec->cinfo.num_components || !dec->cinfo.comp_info)
+    goto components_not_supported;
+
+  r_h = dec->cinfo.comp_info[0].h_samp_factor;
+  r_v = dec->cinfo.comp_info[0].v_samp_factor;
+
+  GST_LOG_OBJECT (dec, "r_h = %d, r_v = %d", r_h, r_v);
+
+  if (dec->cinfo.num_components > 3)
+    goto components_not_supported;
+
+  /* verify color space expectation to avoid going *boom* or bogus output */
+  if (dec->cinfo.jpeg_color_space != JCS_YCbCr &&
+      dec->cinfo.jpeg_color_space != JCS_GRAYSCALE &&
+      dec->cinfo.jpeg_color_space != JCS_RGB)
+    goto unsupported_colorspace;
+
+#ifndef GST_DISABLE_GST_DEBUG
+  {
+    gint i;
+
+    for (i = 0; i < dec->cinfo.num_components; ++i) {
+      GST_LOG_OBJECT (dec, "[%d] h_samp_factor=%d, v_samp_factor=%d, cid=%d",
+          i, dec->cinfo.comp_info[i].h_samp_factor,
+          dec->cinfo.comp_info[i].v_samp_factor,
+          dec->cinfo.comp_info[i].component_id);
+    }
+  }
+#endif
+
+  /* prepare for raw output */
+  dec->cinfo.do_fancy_upsampling = FALSE;
+  dec->cinfo.do_block_smoothing = FALSE;
+  dec->cinfo.out_color_space = dec->cinfo.jpeg_color_space;
+  dec->cinfo.dct_method = dec->idct_method;
+  dec->cinfo.raw_data_out = TRUE;
+
+  GST_LOG_OBJECT (dec, "starting decompress");
+  guarantee_huff_tables (&dec->cinfo);
+  if (!jpeg_start_decompress (&dec->cinfo)) {
+    GST_WARNING_OBJECT (dec, "failed to start decompression cycle");
+  }
+
+  /* sanity checks to get safe and reasonable output */
+  switch (dec->cinfo.jpeg_color_space) {
+    case JCS_GRAYSCALE:
+      if (dec->cinfo.num_components != 1)
+        goto invalid_yuvrgbgrayscale;
+      break;
+    case JCS_RGB:
+      if (dec->cinfo.num_components != 3 || dec->cinfo.max_v_samp_factor > 1 ||
+          dec->cinfo.max_h_samp_factor > 1)
+        goto invalid_yuvrgbgrayscale;
+      break;
+    case JCS_YCbCr:
+      if (dec->cinfo.num_components != 3 ||
+          r_v > 2 || r_v < dec->cinfo.comp_info[0].v_samp_factor ||
+          r_v < dec->cinfo.comp_info[1].v_samp_factor ||
+          r_h < dec->cinfo.comp_info[0].h_samp_factor ||
+          r_h < dec->cinfo.comp_info[1].h_samp_factor)
+        goto invalid_yuvrgbgrayscale;
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+
+  if (G_UNLIKELY (dec->cinfo.output_width < MIN_WIDTH ||
+          dec->cinfo.output_width > MAX_WIDTH ||
+          dec->cinfo.output_height < MIN_HEIGHT ||
+          dec->cinfo.output_height > MAX_HEIGHT))
+    goto wrong_size;
+
+  return GST_FLOW_OK;
+
+/* ERRORS */
+wrong_size:
+  {
+    ret = GST_FLOW_ERROR;
+    GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
+        (_("Failed to decode JPEG image")),
+        ("Picture is too small or too big (%ux%u)", dec->cinfo.output_width,
+            dec->cinfo.output_height), ret);
+    return GST_FLOW_ERROR;
+  }
+components_not_supported:
+  {
+    ret = GST_FLOW_ERROR;
+    GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
+        (_("Failed to decode JPEG image")),
+        ("number of components not supported: %d (max 3)",
+            dec->cinfo.num_components), ret);
+    jpeg_abort_decompress (&dec->cinfo);
+    return GST_FLOW_ERROR;
+  }
+unsupported_colorspace:
+  {
+    ret = GST_FLOW_ERROR;
+    GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
+        (_("Failed to decode JPEG image")),
+        ("Picture has unknown or unsupported colourspace"), ret);
+    jpeg_abort_decompress (&dec->cinfo);
+    return GST_FLOW_ERROR;
+  }
+invalid_yuvrgbgrayscale:
+  {
+    ret = GST_FLOW_ERROR;
+    GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
+        (_("Failed to decode JPEG image")),
+        ("Picture is corrupt or unhandled YUV/RGB/grayscale layout"), ret);
+    jpeg_abort_decompress (&dec->cinfo);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstFlowReturn
+gst_jpeg_dec_decode (GstJpegDec * dec, GstVideoFrame * vframe, guint width,
+    guint height, guint field, guint num_fields)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  if (dec->cinfo.jpeg_color_space == JCS_RGB) {
+    gst_jpeg_dec_decode_rgb (dec, vframe, field, num_fields);
+  } else if (dec->cinfo.jpeg_color_space == JCS_GRAYSCALE) {
+    gst_jpeg_dec_decode_grayscale (dec, vframe, field, num_fields);
+  } else {
+    GST_LOG_OBJECT (dec, "decompressing (required scanline buffer height = %u)",
+        dec->cinfo.rec_outbuf_height);
+
+    /* For some widths jpeglib requires more horizontal padding than I420 
+     * provides. In those cases we need to decode into separate buffers and then
+     * copy over the data into our final picture buffer, otherwise jpeglib might
+     * write over the end of a line into the beginning of the next line,
+     * resulting in blocky artifacts on the left side of the picture. */
+    if (G_UNLIKELY (width % (dec->cinfo.max_h_samp_factor * DCTSIZE) != 0
+            || dec->cinfo.comp_info[0].h_samp_factor != 2
+            || dec->cinfo.comp_info[1].h_samp_factor != 1
+            || dec->cinfo.comp_info[2].h_samp_factor != 1)) {
+      GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, dec,
+          "indirect decoding using extra buffer copy");
+      gst_jpeg_dec_decode_indirect (dec, vframe,
+          dec->cinfo.comp_info[0].v_samp_factor,
+          dec->cinfo.comp_info[0].h_samp_factor, dec->cinfo.num_components,
+          field, num_fields);
+    } else {
+      ret = gst_jpeg_dec_decode_direct (dec, vframe, field, num_fields);
+    }
+  }
+
+  GST_LOG_OBJECT (dec, "decompressing finished: %s", gst_flow_get_name (ret));
+
+  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+    jpeg_abort_decompress (&dec->cinfo);
+  } else {
+    jpeg_finish_decompress (&dec->cinfo);
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_jpeg_dec_handle_frame (GstVideoDecoder * bdec, GstVideoCodecFrame * frame)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstJpegDec *dec = (GstJpegDec *) bdec;
+  GstVideoFrame vframe;
+  gint num_fields;              /* number of fields (1 or 2) */
+  gint output_height;           /* height of output image (one or two fields) */
+  gint height;                  /* height of current frame (whole image or a field) */
+  gint width;
+  guint code;
+  gboolean need_unmap = TRUE;
+  GstVideoCodecState *state = NULL;
+  gboolean release_frame = TRUE;
+  gboolean has_eoi;
+  guint8 *data;
+  gsize nbytes;
+
+  gst_buffer_map (frame->input_buffer, &dec->current_frame_map, GST_MAP_READ);
+
+  data = dec->current_frame_map.data;
+  nbytes = dec->current_frame_map.size;
+  has_eoi = ((data[nbytes - 2] != 0xff) || (data[nbytes - 1] != 0xd9));
+
+  /* some cameras fail to send an end-of-image marker (EOI),
+   * add it if that is the case. */
+  if (!has_eoi) {
+    GstMapInfo map;
+    GstBuffer *eoibuf = gst_buffer_new_and_alloc (2);
+
+    /* unmap, will add EOI and remap at the end */
+    gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
+
+    gst_buffer_map (eoibuf, &map, GST_MAP_WRITE);
+    map.data[0] = 0xff;
+    map.data[1] = 0xd9;
+    gst_buffer_unmap (eoibuf, &map);
+
+    /* append to input buffer, and remap */
+    frame->input_buffer = gst_buffer_append (frame->input_buffer, eoibuf);
+
+    gst_buffer_map (frame->input_buffer, &dec->current_frame_map, GST_MAP_READ);
+    GST_DEBUG ("fixup EOI marker added");
+  }
+
+  dec->current_frame = frame;
+  dec->cinfo.src->next_input_byte = dec->current_frame_map.data;
+  dec->cinfo.src->bytes_in_buffer = dec->current_frame_map.size;
+
+  if (setjmp (dec->jerr.setjmp_buffer)) {
+    code = dec->jerr.pub.msg_code;
+
+    if (code == JERR_INPUT_EOF) {
+      GST_DEBUG ("jpeg input EOF error, we probably need more data");
+      goto need_more_data;
+    }
+    goto decode_error;
+  }
+
+  /* read header and check values */
+  ret = gst_jpeg_dec_prepare_decode (dec);
+  if (G_UNLIKELY (ret == GST_FLOW_ERROR))
+    goto done;
+
+  width = dec->cinfo.output_width;
+  height = dec->cinfo.output_height;
+
+  /* is it interlaced MJPEG? (we really don't want to scan the jpeg data
+   * to see if there are two SOF markers in the packet to detect this) */
+  if (gst_video_decoder_get_packetized (bdec) &&
+      dec->input_state->info.height > height &&
+      dec->input_state->info.height <= (height * 2)
+      && dec->input_state->info.width == width) {
+    GST_LOG_OBJECT (dec,
+        "looks like an interlaced image: "
+        "input width/height of %dx%d with JPEG frame width/height of %dx%d",
+        dec->input_state->info.width, dec->input_state->info.height, width,
+        height);
+    output_height = dec->input_state->info.height;
+    height = dec->input_state->info.height / 2;
+    num_fields = 2;
+    GST_LOG_OBJECT (dec, "field height=%d", height);
+  } else {
+    output_height = height;
+    num_fields = 1;
+  }
+
+  gst_jpeg_dec_negotiate (dec, width, output_height,
+      dec->cinfo.jpeg_color_space, num_fields == 2);
+
+  state = gst_video_decoder_get_output_state (bdec);
+  ret = gst_video_decoder_allocate_output_frame (bdec, frame);
+  if (G_UNLIKELY (ret != GST_FLOW_OK))
+    goto alloc_failed;
+
+  if (!gst_video_frame_map (&vframe, &state->info, frame->output_buffer,
+          GST_MAP_READWRITE))
+    goto alloc_failed;
+
+  if (setjmp (dec->jerr.setjmp_buffer)) {
+    code = dec->jerr.pub.msg_code;
+    gst_video_frame_unmap (&vframe);
+    goto decode_error;
+  }
+
+  GST_LOG_OBJECT (dec, "width %d, height %d, fields %d", width, output_height,
+      num_fields);
+
+  ret = gst_jpeg_dec_decode (dec, &vframe, width, height, 1, num_fields);
+  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+    gst_video_frame_unmap (&vframe);
+    goto decode_failed;
+  }
+
+  if (setjmp (dec->jerr.setjmp_buffer)) {
+    code = dec->jerr.pub.msg_code;
+    gst_video_frame_unmap (&vframe);
+    goto decode_error;
+  }
+
+  /* decode second field if there is one */
+  if (num_fields == 2) {
+    GstVideoFormat field2_format;
+
+    /* skip any chunk or padding bytes before the next SOI marker; both fields
+     * are in one single buffer here, so direct access should be fine here */
+    while (dec->jsrc.pub.bytes_in_buffer > 2 &&
+        GST_READ_UINT16_BE (dec->jsrc.pub.next_input_byte) != 0xffd8) {
+      --dec->jsrc.pub.bytes_in_buffer;
+      ++dec->jsrc.pub.next_input_byte;
+    }
+
+    if (gst_jpeg_dec_prepare_decode (dec) != GST_FLOW_OK) {
+      GST_WARNING_OBJECT (dec, "problem reading jpeg header of 2nd field");
+      /* FIXME: post a warning message here? */
+      gst_video_frame_unmap (&vframe);
+      goto decode_failed;
+    }
+
+    /* check if format has changed for the second field */
+    switch (dec->cinfo.jpeg_color_space) {
+      case JCS_RGB:
+        field2_format = GST_VIDEO_FORMAT_RGB;
+        break;
+      case JCS_GRAYSCALE:
+        field2_format = GST_VIDEO_FORMAT_GRAY8;
+        break;
+      default:
+        field2_format = GST_VIDEO_FORMAT_I420;
+        break;
+    }
+
+    GST_LOG_OBJECT (dec,
+        "got for second field of interlaced image: "
+        "input width/height of %dx%d with JPEG frame width/height of %dx%d",
+        dec->input_state->info.width, dec->input_state->info.height,
+        dec->cinfo.output_width, dec->cinfo.output_height);
+
+    if (dec->cinfo.output_width != GST_VIDEO_INFO_WIDTH (&state->info) ||
+        GST_VIDEO_INFO_HEIGHT (&state->info) <= dec->cinfo.output_height ||
+        GST_VIDEO_INFO_HEIGHT (&state->info) > (dec->cinfo.output_height * 2) ||
+        field2_format != GST_VIDEO_INFO_FORMAT (&state->info)) {
+      GST_WARNING_OBJECT (dec, "second field has different format than first");
+      gst_video_frame_unmap (&vframe);
+      goto decode_failed;
+    }
+
+    ret = gst_jpeg_dec_decode (dec, &vframe, width, height, 2, 2);
+    if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+      gst_video_frame_unmap (&vframe);
+      goto decode_failed;
+    }
+  }
+  gst_video_frame_unmap (&vframe);
+
+  gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
+  ret = gst_video_decoder_finish_frame (bdec, frame);
+  release_frame = FALSE;
+  need_unmap = FALSE;
+
+done:
+
+exit:
+
+  if (need_unmap)
+    gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
+
+  if (release_frame)
+    gst_video_decoder_release_frame (bdec, frame);
+
+  if (state)
+    gst_video_codec_state_unref (state);
+
+  return ret;
+
+  /* special cases */
+need_more_data:
+  {
+    GST_LOG_OBJECT (dec, "we need more data");
+    ret = GST_FLOW_OK;
+    goto exit;
+  }
+  /* ERRORS */
+decode_error:
+  {
+    gchar err_msg[JMSG_LENGTH_MAX];
+
+    dec->jerr.pub.format_message ((j_common_ptr) (&dec->cinfo), err_msg);
+
+    GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
+        (_("Failed to decode JPEG image")), ("Decode error #%u: %s", code,
+            err_msg), ret);
+
+    gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
+    gst_video_decoder_drop_frame (bdec, frame);
+    release_frame = FALSE;
+    need_unmap = FALSE;
+    jpeg_abort_decompress (&dec->cinfo);
+
+    goto done;
+  }
+decode_failed:
+  {
+    /* already posted an error message */
+    goto done;
+  }
+alloc_failed:
+  {
+    const gchar *reason;
+
+    reason = gst_flow_get_name (ret);
+
+    GST_DEBUG_OBJECT (dec, "failed to alloc buffer, reason %s", reason);
+    /* Reset for next time */
+    jpeg_abort_decompress (&dec->cinfo);
+    if (ret != GST_FLOW_EOS && ret != GST_FLOW_FLUSHING &&
+        ret != GST_FLOW_NOT_LINKED) {
+      GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
+          (_("Failed to decode JPEG image")),
+          ("Buffer allocation failed, reason: %s", reason), ret);
+      jpeg_abort_decompress (&dec->cinfo);
+    }
+    goto exit;
+  }
+}
+
+static gboolean
+gst_jpeg_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
+{
+  GstBufferPool *pool = NULL;
+  GstStructure *config;
+
+  if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (bdec, query))
+    return FALSE;
+
+  if (gst_query_get_n_allocation_pools (query) > 0)
+    gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
+
+  if (pool == NULL)
+    return FALSE;
+
+  config = gst_buffer_pool_get_config (pool);
+  if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
+    gst_buffer_pool_config_add_option (config,
+        GST_BUFFER_POOL_OPTION_VIDEO_META);
+  }
+  gst_buffer_pool_set_config (pool, config);
+  gst_object_unref (pool);
+
+  return TRUE;
+}
+
+static gboolean
+gst_jpeg_dec_sink_event (GstVideoDecoder * bdec, GstEvent * event)
+{
+  const GstSegment *segment;
+
+  if (GST_EVENT_TYPE (event) != GST_EVENT_SEGMENT)
+    goto done;
+
+  gst_event_parse_segment (event, &segment);
+
+  if (segment->format == GST_FORMAT_TIME)
+    gst_video_decoder_set_packetized (bdec, TRUE);
+  else
+    gst_video_decoder_set_packetized (bdec, FALSE);
+
+done:
+  return GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (bdec, event);
+}
+
+static gboolean
+gst_jpeg_dec_start (GstVideoDecoder * bdec)
+{
+  GstJpegDec *dec = (GstJpegDec *) bdec;
+
+  dec->saw_header = FALSE;
+  dec->parse_entropy_len = 0;
+  dec->parse_resync = FALSE;
+
+  gst_video_decoder_set_packetized (bdec, FALSE);
+
+  return TRUE;
+}
+
+static gboolean
+gst_jpeg_dec_flush (GstVideoDecoder * bdec)
+{
+  GstJpegDec *dec = (GstJpegDec *) bdec;
+
+  jpeg_abort_decompress (&dec->cinfo);
+  dec->parse_entropy_len = 0;
+  dec->parse_resync = FALSE;
+  dec->saw_header = FALSE;
+
+  return TRUE;
+}
+
+static void
+gst_jpeg_dec_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstJpegDec *dec;
+
+  dec = GST_JPEG_DEC (object);
+
+  switch (prop_id) {
+    case PROP_IDCT_METHOD:
+      dec->idct_method = g_value_get_enum (value);
+      break;
+#ifndef GST_REMOVE_DEPRECATED
+    case PROP_MAX_ERRORS:
+      g_atomic_int_set (&dec->max_errors, g_value_get_int (value));
+      break;
+#endif
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_jpeg_dec_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstJpegDec *dec;
+
+  dec = GST_JPEG_DEC (object);
+
+  switch (prop_id) {
+    case PROP_IDCT_METHOD:
+      g_value_set_enum (value, dec->idct_method);
+      break;
+#ifndef GST_REMOVE_DEPRECATED
+    case PROP_MAX_ERRORS:
+      g_value_set_int (value, g_atomic_int_get (&dec->max_errors));
+      break;
+#endif
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_jpeg_dec_stop (GstVideoDecoder * bdec)
+{
+  GstJpegDec *dec = (GstJpegDec *) bdec;
+
+  gst_jpeg_dec_free_buffers (dec);
+
+  return TRUE;
+}
diff --git a/ext/jpeg/gstjpegdec.h b/ext/jpeg/gstjpegdec.h
new file mode 100644
index 0000000..e8fa2fc
--- /dev/null
+++ b/ext/jpeg/gstjpegdec.h
@@ -0,0 +1,107 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2012 Collabora Ltd.
+ *	Author : Edward Hervey <edward@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_JPEG_DEC_H__
+#define __GST_JPEG_DEC_H__
+
+
+#include <setjmp.h>
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideodecoder.h>
+#include <gst/base/gstadapter.h>
+
+/* this is a hack hack hack to get around jpeglib header bugs... */
+#ifdef HAVE_STDLIB_H
+# undef HAVE_STDLIB_H
+#endif
+#include <stdio.h>
+#include <jpeglib.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_JPEG_DEC \
+  (gst_jpeg_dec_get_type())
+#define GST_JPEG_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_JPEG_DEC,GstJpegDec))
+#define GST_JPEG_DEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_JPEG_DEC,GstJpegDecClass))
+#define GST_IS_JPEG_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_JPEG_DEC))
+#define GST_IS_JPEG_DEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_JPEG_DEC))
+
+typedef struct _GstJpegDec           GstJpegDec;
+typedef struct _GstJpegDecClass      GstJpegDecClass;
+
+struct GstJpegDecErrorMgr {
+  struct jpeg_error_mgr    pub;   /* public fields */
+  jmp_buf                  setjmp_buffer;
+};
+
+struct GstJpegDecSourceMgr {
+  struct jpeg_source_mgr   pub;   /* public fields */
+  GstJpegDec              *dec;
+};
+
+/* Can't use GstBaseTransform, because GstBaseTransform
+ * doesn't handle the N buffers in, 1 buffer out case,
+ * but only the 1-in 1-out case */
+struct _GstJpegDec {
+  GstVideoDecoder decoder;
+
+  /* negotiated state */
+  GstVideoCodecState *input_state;
+  GstVideoCodecFrame *current_frame;
+  GstMapInfo current_frame_map;
+
+  /* parse state */
+  gboolean saw_header;
+  gint     parse_entropy_len;
+  gint     parse_resync;
+
+  /* properties */
+  gint     idct_method;
+  gint     max_errors;  /* ATOMIC */
+
+  struct jpeg_decompress_struct cinfo;
+  struct GstJpegDecErrorMgr     jerr;
+  struct GstJpegDecSourceMgr    jsrc;
+
+  /* arrays for indirect decoding */
+  gboolean idr_width_allocated;
+  guchar *idr_y[16],*idr_u[16],*idr_v[16];
+  /* current (parsed) image size */
+  guint    rem_img_len;
+};
+
+struct _GstJpegDecClass {
+  GstVideoDecoderClass decoder_class;
+};
+
+GType gst_jpeg_dec_get_type(void);
+
+
+G_END_DECLS
+
+
+#endif /* __GST_JPEG_DEC_H__ */
diff --git a/ext/jpeg/gstjpegenc.c b/ext/jpeg/gstjpegenc.c
new file mode 100644
index 0000000..3f4be06
--- /dev/null
+++ b/ext/jpeg/gstjpegenc.c
@@ -0,0 +1,659 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2012 Collabora Ltd.
+ *	Author : Edward Hervey <edward@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-jpegenc
+ *
+ * Encodes jpeg images.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 videotestsrc num-buffers=50 ! video/x-raw, framerate='(fraction)'5/1 ! jpegenc ! avimux ! filesink location=mjpeg.avi
+ * ]| a pipeline to mux 5 JPEG frames per second into a 10 sec. long motion jpeg
+ * avi.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+
+#include "gstjpegenc.h"
+#include "gstjpeg.h"
+#include <gst/video/video.h>
+#include <gst/video/gstvideometa.h>
+#include <gst/base/base.h>
+
+/* experimental */
+/* setting smoothig seems to have no effect in libjepeg
+#define ENABLE_SMOOTHING 1
+*/
+
+GST_DEBUG_CATEGORY_STATIC (jpegenc_debug);
+#define GST_CAT_DEFAULT jpegenc_debug
+
+#define JPEG_DEFAULT_QUALITY 85
+#define JPEG_DEFAULT_SMOOTHING 0
+#define JPEG_DEFAULT_IDCT_METHOD	JDCT_FASTEST
+#define JPEG_DEFAULT_SNAPSHOT		FALSE
+
+/* JpegEnc signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_QUALITY,
+  PROP_SMOOTHING,
+  PROP_IDCT_METHOD,
+  PROP_SNAPSHOT
+};
+
+static void gst_jpegenc_finalize (GObject * object);
+
+static void gst_jpegenc_resync (GstJpegEnc * jpegenc);
+static void gst_jpegenc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_jpegenc_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_jpegenc_start (GstVideoEncoder * benc);
+static gboolean gst_jpegenc_stop (GstVideoEncoder * benc);
+static gboolean gst_jpegenc_set_format (GstVideoEncoder * encoder,
+    GstVideoCodecState * state);
+static GstFlowReturn gst_jpegenc_handle_frame (GstVideoEncoder * encoder,
+    GstVideoCodecFrame * frame);
+static gboolean gst_jpegenc_propose_allocation (GstVideoEncoder * encoder,
+    GstQuery * query);
+
+/* static guint gst_jpegenc_signals[LAST_SIGNAL] = { 0 }; */
+
+#define gst_jpegenc_parent_class parent_class
+G_DEFINE_TYPE (GstJpegEnc, gst_jpegenc, GST_TYPE_VIDEO_ENCODER);
+
+/* *INDENT-OFF* */
+static GstStaticPadTemplate gst_jpegenc_sink_pad_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
+        ("{ I420, YV12, YUY2, UYVY, Y41B, Y42B, YVYU, Y444, NV21, "
+         "NV12, RGB, BGR, RGBx, xRGB, BGRx, xBGR, GRAY8 }"))
+    );
+/* *INDENT-ON* */
+
+static GstStaticPadTemplate gst_jpegenc_src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("image/jpeg, "
+        "width = (int) [ 16, 65535 ], "
+        "height = (int) [ 16, 65535 ], "
+        "framerate = (fraction) [ 0/1, MAX ], "
+        "sof-marker = (int) { 0, 1, 2, 9 }")
+    );
+
+static void
+gst_jpegenc_class_init (GstJpegEncClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+  GstVideoEncoderClass *venc_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = (GstElementClass *) klass;
+  venc_class = (GstVideoEncoderClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gst_jpegenc_finalize;
+  gobject_class->set_property = gst_jpegenc_set_property;
+  gobject_class->get_property = gst_jpegenc_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_QUALITY,
+      g_param_spec_int ("quality", "Quality", "Quality of encoding",
+          0, 100, JPEG_DEFAULT_QUALITY,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+          GST_PARAM_MUTABLE_PLAYING));
+
+#ifdef ENABLE_SMOOTHING
+  /* disabled, since it doesn't seem to work */
+  g_object_class_install_property (gobject_class, PROP_SMOOTHING,
+      g_param_spec_int ("smoothing", "Smoothing", "Smoothing factor",
+          0, 100, JPEG_DEFAULT_SMOOTHING,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#endif
+
+  g_object_class_install_property (gobject_class, PROP_IDCT_METHOD,
+      g_param_spec_enum ("idct-method", "IDCT Method",
+          "The IDCT algorithm to use", GST_TYPE_IDCT_METHOD,
+          JPEG_DEFAULT_IDCT_METHOD,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstJpegEnc:snapshot:
+   *
+   * Send EOS after encoding a frame, useful for snapshots.
+   *
+   * Since: 1.14
+   */
+  g_object_class_install_property (gobject_class, PROP_SNAPSHOT,
+      g_param_spec_boolean ("snapshot", "Snapshot",
+          "Send EOS after encoding a frame, useful for snapshots",
+          JPEG_DEFAULT_SNAPSHOT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_jpegenc_sink_pad_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_jpegenc_src_pad_template);
+
+  gst_element_class_set_static_metadata (element_class, "JPEG image encoder",
+      "Codec/Encoder/Image", "Encode images in JPEG format",
+      "Wim Taymans <wim.taymans@tvd.be>");
+
+  venc_class->start = gst_jpegenc_start;
+  venc_class->stop = gst_jpegenc_stop;
+  venc_class->set_format = gst_jpegenc_set_format;
+  venc_class->handle_frame = gst_jpegenc_handle_frame;
+  venc_class->propose_allocation = gst_jpegenc_propose_allocation;
+
+  GST_DEBUG_CATEGORY_INIT (jpegenc_debug, "jpegenc", 0,
+      "JPEG encoding element");
+}
+
+static void
+gst_jpegenc_init_destination (j_compress_ptr cinfo)
+{
+  GST_DEBUG ("gst_jpegenc_chain: init_destination");
+}
+
+static void
+ensure_memory (GstJpegEnc * jpegenc)
+{
+  GstMemory *new_memory;
+  GstMapInfo map;
+  gsize old_size, desired_size, new_size;
+  guint8 *new_data;
+  static GstAllocationParams params = { 0, 3, 0, 0, };
+
+  old_size = jpegenc->output_map.size;
+  if (old_size == 0)
+    desired_size = jpegenc->bufsize;
+  else
+    desired_size = old_size * 2;
+
+  /* Our output memory wasn't big enough.
+   * Make a new memory that's twice the size, */
+  new_memory = gst_allocator_alloc (NULL, desired_size, &params);
+  gst_memory_map (new_memory, &map, GST_MAP_READWRITE);
+  new_data = map.data;
+  new_size = map.size;
+
+  /* copy previous data if any */
+  if (jpegenc->output_mem) {
+    memcpy (new_data, jpegenc->output_map.data, old_size);
+    gst_memory_unmap (jpegenc->output_mem, &jpegenc->output_map);
+    gst_memory_unref (jpegenc->output_mem);
+  }
+
+  /* drop it into place, */
+  jpegenc->output_mem = new_memory;
+  jpegenc->output_map = map;
+
+  /* and last, update libjpeg on where to work. */
+  jpegenc->jdest.next_output_byte = new_data + old_size;
+  jpegenc->jdest.free_in_buffer = new_size - old_size;
+}
+
+static boolean
+gst_jpegenc_flush_destination (j_compress_ptr cinfo)
+{
+  GstJpegEnc *jpegenc = (GstJpegEnc *) (cinfo->client_data);
+
+  GST_DEBUG_OBJECT (jpegenc,
+      "gst_jpegenc_chain: flush_destination: buffer too small");
+
+  ensure_memory (jpegenc);
+
+  return TRUE;
+}
+
+static void
+gst_jpegenc_term_destination (j_compress_ptr cinfo)
+{
+  GstBuffer *outbuf;
+  GstJpegEnc *jpegenc = (GstJpegEnc *) (cinfo->client_data);
+  gsize memory_size = jpegenc->output_map.size - jpegenc->jdest.free_in_buffer;
+  GstByteReader reader =
+      GST_BYTE_READER_INIT (jpegenc->output_map.data, memory_size);
+  guint16 marker;
+  gint sof_marker = -1;
+
+  GST_DEBUG_OBJECT (jpegenc, "gst_jpegenc_chain: term_source");
+
+  /* Find the SOF marker */
+  while (gst_byte_reader_get_uint16_be (&reader, &marker)) {
+    /* SOF marker */
+    if (marker >> 4 == 0x0ffc) {
+      sof_marker = marker & 0x4;
+      break;
+    }
+  }
+
+  gst_memory_unmap (jpegenc->output_mem, &jpegenc->output_map);
+  /* Trim the buffer size. we will push it in the chain function */
+  gst_memory_resize (jpegenc->output_mem, 0, memory_size);
+  jpegenc->output_map.data = NULL;
+  jpegenc->output_map.size = 0;
+
+  if (jpegenc->sof_marker != sof_marker || jpegenc->input_caps_changed) {
+    GstVideoCodecState *output;
+    output =
+        gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (jpegenc),
+        gst_caps_new_simple ("image/jpeg", "sof-marker", G_TYPE_INT, sof_marker,
+            NULL), jpegenc->input_state);
+    gst_video_codec_state_unref (output);
+    jpegenc->sof_marker = sof_marker;
+    jpegenc->input_caps_changed = FALSE;
+  }
+
+  outbuf = gst_buffer_new ();
+  gst_buffer_copy_into (outbuf, jpegenc->current_frame->input_buffer,
+      GST_BUFFER_COPY_METADATA, 0, -1);
+  gst_buffer_append_memory (outbuf, jpegenc->output_mem);
+  jpegenc->output_mem = NULL;
+
+  jpegenc->current_frame->output_buffer = outbuf;
+
+  gst_video_frame_unmap (&jpegenc->current_vframe);
+
+  GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (jpegenc->current_frame);
+
+  jpegenc->res = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (jpegenc),
+      jpegenc->current_frame);
+  jpegenc->current_frame = NULL;
+}
+
+static void
+gst_jpegenc_init (GstJpegEnc * jpegenc)
+{
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_ENCODER_SINK_PAD (jpegenc));
+
+  /* setup jpeglib */
+  memset (&jpegenc->cinfo, 0, sizeof (jpegenc->cinfo));
+  memset (&jpegenc->jerr, 0, sizeof (jpegenc->jerr));
+  jpegenc->cinfo.err = jpeg_std_error (&jpegenc->jerr);
+  jpeg_create_compress (&jpegenc->cinfo);
+
+  jpegenc->jdest.init_destination = gst_jpegenc_init_destination;
+  jpegenc->jdest.empty_output_buffer = gst_jpegenc_flush_destination;
+  jpegenc->jdest.term_destination = gst_jpegenc_term_destination;
+  jpegenc->cinfo.dest = &jpegenc->jdest;
+  jpegenc->cinfo.client_data = jpegenc;
+
+  /* init properties */
+  jpegenc->quality = JPEG_DEFAULT_QUALITY;
+  jpegenc->smoothing = JPEG_DEFAULT_SMOOTHING;
+  jpegenc->idct_method = JPEG_DEFAULT_IDCT_METHOD;
+  jpegenc->snapshot = JPEG_DEFAULT_SNAPSHOT;
+}
+
+static void
+gst_jpegenc_finalize (GObject * object)
+{
+  GstJpegEnc *filter = GST_JPEGENC (object);
+
+  jpeg_destroy_compress (&filter->cinfo);
+
+  if (filter->input_state)
+    gst_video_codec_state_unref (filter->input_state);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_jpegenc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state)
+{
+  GstJpegEnc *enc = GST_JPEGENC (encoder);
+  gint i;
+  GstVideoInfo *info = &state->info;
+
+  if (enc->input_state)
+    gst_video_codec_state_unref (enc->input_state);
+  enc->input_state = gst_video_codec_state_ref (state);
+
+  /* prepare a cached image description  */
+  enc->channels = GST_VIDEO_INFO_N_COMPONENTS (info);
+
+  /* ... but any alpha is disregarded in encoding */
+  if (GST_VIDEO_INFO_IS_GRAY (info))
+    enc->channels = 1;
+
+  enc->h_max_samp = 0;
+  enc->v_max_samp = 0;
+  for (i = 0; i < enc->channels; ++i) {
+    enc->cwidth[i] = GST_VIDEO_INFO_COMP_WIDTH (info, i);
+    enc->cheight[i] = GST_VIDEO_INFO_COMP_HEIGHT (info, i);
+    enc->inc[i] = GST_VIDEO_INFO_COMP_PSTRIDE (info, i);
+    enc->h_samp[i] =
+        GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (info)) / enc->cwidth[i];
+    enc->h_max_samp = MAX (enc->h_max_samp, enc->h_samp[i]);
+    enc->v_samp[i] =
+        GST_ROUND_UP_4 (GST_VIDEO_INFO_HEIGHT (info)) / enc->cheight[i];
+    enc->v_max_samp = MAX (enc->v_max_samp, enc->v_samp[i]);
+  }
+  /* samp should only be 1, 2 or 4 */
+  g_assert (enc->h_max_samp <= 4);
+  g_assert (enc->v_max_samp <= 4);
+
+  /* now invert */
+  /* maximum is invariant, as one of the components should have samp 1 */
+  for (i = 0; i < enc->channels; ++i) {
+    GST_DEBUG ("%d %d", enc->h_samp[i], enc->h_max_samp);
+    enc->h_samp[i] = enc->h_max_samp / enc->h_samp[i];
+    enc->v_samp[i] = enc->v_max_samp / enc->v_samp[i];
+  }
+  enc->planar = (enc->inc[0] == 1 && enc->inc[1] == 1 && enc->inc[2] == 1);
+
+  enc->input_caps_changed = TRUE;
+  gst_jpegenc_resync (enc);
+
+  return TRUE;
+}
+
+static void
+gst_jpegenc_resync (GstJpegEnc * jpegenc)
+{
+  GstVideoInfo *info;
+  gint width, height;
+  gint i, j;
+
+  GST_DEBUG_OBJECT (jpegenc, "resync");
+
+  if (!jpegenc->input_state)
+    return;
+
+  info = &jpegenc->input_state->info;
+
+  jpegenc->cinfo.image_width = width = GST_VIDEO_INFO_WIDTH (info);
+  jpegenc->cinfo.image_height = height = GST_VIDEO_INFO_HEIGHT (info);
+  jpegenc->cinfo.input_components = jpegenc->channels;
+
+  GST_DEBUG_OBJECT (jpegenc, "width %d, height %d", width, height);
+  GST_DEBUG_OBJECT (jpegenc, "format %d", GST_VIDEO_INFO_FORMAT (info));
+
+  if (GST_VIDEO_INFO_IS_RGB (info)) {
+    GST_DEBUG_OBJECT (jpegenc, "RGB");
+    jpegenc->cinfo.in_color_space = JCS_RGB;
+  } else if (GST_VIDEO_INFO_IS_GRAY (info)) {
+    GST_DEBUG_OBJECT (jpegenc, "gray");
+    jpegenc->cinfo.in_color_space = JCS_GRAYSCALE;
+  } else {
+    GST_DEBUG_OBJECT (jpegenc, "YUV");
+    jpegenc->cinfo.in_color_space = JCS_YCbCr;
+  }
+
+  /* input buffer size as max output */
+  jpegenc->bufsize = GST_VIDEO_INFO_SIZE (info);
+  jpeg_set_defaults (&jpegenc->cinfo);
+  jpegenc->cinfo.raw_data_in = TRUE;
+  /* duh, libjpeg maps RGB to YUV ... and don't expect some conversion */
+  if (jpegenc->cinfo.in_color_space == JCS_RGB)
+    jpeg_set_colorspace (&jpegenc->cinfo, JCS_RGB);
+
+  GST_DEBUG_OBJECT (jpegenc, "h_max_samp=%d, v_max_samp=%d",
+      jpegenc->h_max_samp, jpegenc->v_max_samp);
+  /* image dimension info */
+  for (i = 0; i < jpegenc->channels; i++) {
+    GST_DEBUG_OBJECT (jpegenc, "comp %i: h_samp=%d, v_samp=%d", i,
+        jpegenc->h_samp[i], jpegenc->v_samp[i]);
+    jpegenc->cinfo.comp_info[i].h_samp_factor = jpegenc->h_samp[i];
+    jpegenc->cinfo.comp_info[i].v_samp_factor = jpegenc->v_samp[i];
+    g_free (jpegenc->line[i]);
+    jpegenc->line[i] = g_new (guchar *, jpegenc->v_max_samp * DCTSIZE);
+    if (!jpegenc->planar) {
+      for (j = 0; j < jpegenc->v_max_samp * DCTSIZE; j++) {
+        g_free (jpegenc->row[i][j]);
+        jpegenc->row[i][j] = g_malloc (width);
+        jpegenc->line[i][j] = jpegenc->row[i][j];
+      }
+    }
+  }
+
+  /* guard against a potential error in gst_jpegenc_term_destination
+     which occurs iff bufsize % 4 < free_space_remaining */
+  jpegenc->bufsize = GST_ROUND_UP_4 (jpegenc->bufsize);
+
+  jpeg_suppress_tables (&jpegenc->cinfo, TRUE);
+
+  GST_DEBUG_OBJECT (jpegenc, "resync done");
+}
+
+static GstFlowReturn
+gst_jpegenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
+{
+  GstJpegEnc *jpegenc;
+  guint height;
+  guchar *base[3], *end[3];
+  guint stride[3];
+  gint i, j, k;
+  static GstAllocationParams params = { 0, 0, 0, 3, };
+
+  jpegenc = GST_JPEGENC (encoder);
+
+  GST_LOG_OBJECT (jpegenc, "got new frame");
+
+  if (!gst_video_frame_map (&jpegenc->current_vframe,
+          &jpegenc->input_state->info, frame->input_buffer, GST_MAP_READ))
+    goto invalid_frame;
+
+  jpegenc->current_frame = frame;
+
+  height = GST_VIDEO_INFO_HEIGHT (&jpegenc->input_state->info);
+
+  for (i = 0; i < jpegenc->channels; i++) {
+    base[i] = GST_VIDEO_FRAME_COMP_DATA (&jpegenc->current_vframe, i);
+    stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (&jpegenc->current_vframe, i);
+    end[i] =
+        base[i] + GST_VIDEO_FRAME_COMP_HEIGHT (&jpegenc->current_vframe,
+        i) * stride[i];
+  }
+
+  jpegenc->res = GST_FLOW_OK;
+  jpegenc->output_mem = gst_allocator_alloc (NULL, jpegenc->bufsize, &params);
+  gst_memory_map (jpegenc->output_mem, &jpegenc->output_map, GST_MAP_READWRITE);
+
+  jpegenc->jdest.next_output_byte = jpegenc->output_map.data;
+  jpegenc->jdest.free_in_buffer = jpegenc->output_map.size;
+
+  /* prepare for raw input */
+#if JPEG_LIB_VERSION >= 70
+  jpegenc->cinfo.do_fancy_downsampling = FALSE;
+#endif
+
+  GST_OBJECT_LOCK (jpegenc);
+  jpegenc->cinfo.smoothing_factor = jpegenc->smoothing;
+  jpegenc->cinfo.dct_method = jpegenc->idct_method;
+  jpeg_set_quality (&jpegenc->cinfo, jpegenc->quality, TRUE);
+  GST_OBJECT_UNLOCK (jpegenc);
+
+  jpeg_start_compress (&jpegenc->cinfo, TRUE);
+
+  GST_LOG_OBJECT (jpegenc, "compressing");
+
+  if (jpegenc->planar) {
+    for (i = 0; i < height; i += jpegenc->v_max_samp * DCTSIZE) {
+      for (k = 0; k < jpegenc->channels; k++) {
+        for (j = 0; j < jpegenc->v_samp[k] * DCTSIZE; j++) {
+          jpegenc->line[k][j] = base[k];
+          if (base[k] + stride[k] < end[k])
+            base[k] += stride[k];
+        }
+      }
+      jpeg_write_raw_data (&jpegenc->cinfo, jpegenc->line,
+          jpegenc->v_max_samp * DCTSIZE);
+    }
+  } else {
+    for (i = 0; i < height; i += jpegenc->v_max_samp * DCTSIZE) {
+      for (k = 0; k < jpegenc->channels; k++) {
+        for (j = 0; j < jpegenc->v_samp[k] * DCTSIZE; j++) {
+          guchar *src, *dst;
+          gint l;
+
+          /* ouch, copy line */
+          src = base[k];
+          dst = jpegenc->line[k][j];
+          for (l = jpegenc->cwidth[k]; l > 0; l--) {
+            *dst = *src;
+            src += jpegenc->inc[k];
+            dst++;
+          }
+          if (base[k] + stride[k] < end[k])
+            base[k] += stride[k];
+        }
+      }
+      jpeg_write_raw_data (&jpegenc->cinfo, jpegenc->line,
+          jpegenc->v_max_samp * DCTSIZE);
+    }
+  }
+
+  /* This will ensure that gst_jpegenc_term_destination is called */
+  jpeg_finish_compress (&jpegenc->cinfo);
+  GST_LOG_OBJECT (jpegenc, "compressing done");
+
+  return (jpegenc->snapshot) ? GST_FLOW_EOS : jpegenc->res;
+
+invalid_frame:
+  {
+    GST_WARNING_OBJECT (jpegenc, "invalid frame received");
+    return gst_video_encoder_finish_frame (encoder, frame);
+  }
+}
+
+static gboolean
+gst_jpegenc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
+{
+  gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
+
+  return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
+      query);
+}
+
+static void
+gst_jpegenc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstJpegEnc *jpegenc = GST_JPEGENC (object);
+
+  GST_OBJECT_LOCK (jpegenc);
+
+  switch (prop_id) {
+    case PROP_QUALITY:
+      jpegenc->quality = g_value_get_int (value);
+      break;
+#ifdef ENABLE_SMOOTHING
+    case PROP_SMOOTHING:
+      jpegenc->smoothing = g_value_get_int (value);
+      break;
+#endif
+    case PROP_IDCT_METHOD:
+      jpegenc->idct_method = g_value_get_enum (value);
+      break;
+    case PROP_SNAPSHOT:
+      jpegenc->snapshot = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  GST_OBJECT_UNLOCK (jpegenc);
+}
+
+static void
+gst_jpegenc_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstJpegEnc *jpegenc = GST_JPEGENC (object);
+
+  GST_OBJECT_LOCK (jpegenc);
+
+  switch (prop_id) {
+    case PROP_QUALITY:
+      g_value_set_int (value, jpegenc->quality);
+      break;
+#ifdef ENABLE_SMOOTHING
+    case PROP_SMOOTHING:
+      g_value_set_int (value, jpegenc->smoothing);
+      break;
+#endif
+    case PROP_IDCT_METHOD:
+      g_value_set_enum (value, jpegenc->idct_method);
+      break;
+    case PROP_SNAPSHOT:
+      g_value_set_boolean (value, jpegenc->snapshot);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  GST_OBJECT_UNLOCK (jpegenc);
+}
+
+static gboolean
+gst_jpegenc_start (GstVideoEncoder * benc)
+{
+  GstJpegEnc *enc = (GstJpegEnc *) benc;
+
+  enc->line[0] = NULL;
+  enc->line[1] = NULL;
+  enc->line[2] = NULL;
+  enc->sof_marker = -1;
+
+  return TRUE;
+}
+
+static gboolean
+gst_jpegenc_stop (GstVideoEncoder * benc)
+{
+  GstJpegEnc *enc = (GstJpegEnc *) benc;
+  gint i, j;
+
+  g_free (enc->line[0]);
+  g_free (enc->line[1]);
+  g_free (enc->line[2]);
+  enc->line[0] = NULL;
+  enc->line[1] = NULL;
+  enc->line[2] = NULL;
+  for (i = 0; i < 3; i++) {
+    for (j = 0; j < 4 * DCTSIZE; j++) {
+      g_free (enc->row[i][j]);
+      enc->row[i][j] = NULL;
+    }
+  }
+
+  return TRUE;
+}
diff --git a/ext/jpeg/gstjpegenc.h b/ext/jpeg/gstjpegenc.h
new file mode 100644
index 0000000..df75299
--- /dev/null
+++ b/ext/jpeg/gstjpegenc.h
@@ -0,0 +1,103 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2012 Collabora Ltd.
+ *	Author : Edward Hervey <edward@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_JPEGENC_H__
+#define __GST_JPEGENC_H__
+
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideoencoder.h>
+/* this is a hack hack hack to get around jpeglib header bugs... */
+#ifdef HAVE_STDLIB_H
+# undef HAVE_STDLIB_H
+#endif
+#include <stdio.h>
+#include <jpeglib.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_JPEGENC \
+  (gst_jpegenc_get_type())
+#define GST_JPEGENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_JPEGENC,GstJpegEnc))
+#define GST_JPEGENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_JPEGENC,GstJpegEncClass))
+#define GST_IS_JPEGENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_JPEGENC))
+#define GST_IS_JPEGENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_JPEGENC))
+
+typedef struct _GstJpegEnc GstJpegEnc;
+typedef struct _GstJpegEncClass GstJpegEncClass;
+
+struct _GstJpegEnc
+{
+  GstVideoEncoder encoder;
+
+  GstVideoCodecState *input_state;
+  GstVideoFrame current_vframe;
+  GstVideoCodecFrame *current_frame;
+  GstFlowReturn res;
+
+  gboolean input_caps_changed;
+
+  guint channels;
+
+  gint inc[GST_VIDEO_MAX_COMPONENTS];
+  gint cwidth[GST_VIDEO_MAX_COMPONENTS];
+  gint cheight[GST_VIDEO_MAX_COMPONENTS];
+  gint h_samp[GST_VIDEO_MAX_COMPONENTS];
+  gint v_samp[GST_VIDEO_MAX_COMPONENTS];
+  gint h_max_samp;
+  gint v_max_samp;
+  gboolean planar;
+  gint sof_marker;
+  /* the video buffer */
+  gint bufsize;
+  /* the jpeg line buffer */
+  guchar **line[3];
+  /* indirect encoding line buffers */
+  guchar *row[3][4 * DCTSIZE];
+
+  struct jpeg_compress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+  struct jpeg_destination_mgr jdest;
+
+  /* properties */
+  gint quality;
+  gint smoothing;
+  gint idct_method;
+  gboolean snapshot;
+
+  GstMemory *output_mem;
+  GstMapInfo output_map;
+};
+
+struct _GstJpegEncClass
+{
+  GstVideoEncoderClass parent_class;
+};
+
+GType gst_jpegenc_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_JPEGENC_H__ */
diff --git a/ext/jpeg/gstsmokedec.c b/ext/jpeg/gstsmokedec.c
new file mode 100644
index 0000000..816d954
--- /dev/null
+++ b/ext/jpeg/gstsmokedec.c
@@ -0,0 +1,332 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-smokedec
+ *
+ * Decodes images in smoke format.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+
+/*#define DEBUG_ENABLED*/
+#include "gstsmokedec.h"
+#include <gst/video/video.h>
+
+GST_DEBUG_CATEGORY_STATIC (smokedec_debug);
+#define GST_CAT_DEFAULT smokedec_debug
+
+/* SmokeDec signals and args */
+enum
+{
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0
+};
+
+static void gst_smokedec_base_init (gpointer g_class);
+static void gst_smokedec_class_init (GstSmokeDec * klass);
+static void gst_smokedec_init (GstSmokeDec * smokedec);
+static void gst_smokedec_finalize (GObject * object);
+
+static GstStateChangeReturn
+gst_smokedec_change_state (GstElement * element, GstStateChange transition);
+
+static GstFlowReturn gst_smokedec_chain (GstPad * pad, GstBuffer * buf);
+
+static GstElementClass *parent_class = NULL;
+
+/*static guint gst_smokedec_signals[LAST_SIGNAL] = { 0 }; */
+
+GType
+gst_smokedec_get_type (void)
+{
+  static GType smokedec_type = 0;
+
+  if (!smokedec_type) {
+    static const GTypeInfo smokedec_info = {
+      sizeof (GstSmokeDecClass),
+      gst_smokedec_base_init,
+      NULL,
+      (GClassInitFunc) gst_smokedec_class_init,
+      NULL,
+      NULL,
+      sizeof (GstSmokeDec),
+      0,
+      (GInstanceInitFunc) gst_smokedec_init,
+    };
+
+    smokedec_type =
+        g_type_register_static (GST_TYPE_ELEMENT, "GstSmokeDec", &smokedec_info,
+        0);
+  }
+  return smokedec_type;
+}
+
+static GstStaticPadTemplate gst_smokedec_src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
+    );
+
+static GstStaticPadTemplate gst_smokedec_sink_pad_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-smoke, "
+        "width = (int) [ 16, 4096 ], "
+        "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0/1, MAX ]")
+    );
+
+static void
+gst_smokedec_base_init (gpointer g_class)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_smokedec_src_pad_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_smokedec_sink_pad_template);
+  gst_element_class_set_static_metadata (element_class, "Smoke video decoder",
+      "Codec/Decoder/Video", "Decode video from Smoke format",
+      "Wim Taymans <wim@fluendo.com>");
+}
+
+static void
+gst_smokedec_class_init (GstSmokeDec * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gst_smokedec_finalize;
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_smokedec_change_state);
+
+  GST_DEBUG_CATEGORY_INIT (smokedec_debug, "smokedec", 0, "Smoke decoder");
+}
+
+static void
+gst_smokedec_init (GstSmokeDec * smokedec)
+{
+  GST_DEBUG_OBJECT (smokedec, "gst_smokedec_init: initializing");
+  /* create the sink and src pads */
+
+  smokedec->sinkpad =
+      gst_pad_new_from_static_template (&gst_smokedec_sink_pad_template,
+      "sink");
+  gst_pad_set_chain_function (smokedec->sinkpad, gst_smokedec_chain);
+  gst_element_add_pad (GST_ELEMENT (smokedec), smokedec->sinkpad);
+
+  smokedec->srcpad =
+      gst_pad_new_from_static_template (&gst_smokedec_src_pad_template, "src");
+  gst_pad_use_fixed_caps (smokedec->srcpad);
+  gst_element_add_pad (GST_ELEMENT (smokedec), smokedec->srcpad);
+
+  smokecodec_decode_new (&smokedec->info);
+}
+
+static void
+gst_smokedec_finalize (GObject * object)
+{
+  GstSmokeDec *dec = GST_SMOKEDEC (object);
+
+  smokecodec_info_free (dec->info);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstFlowReturn
+gst_smokedec_chain (GstPad * pad, GstBuffer * buf)
+{
+  GstSmokeDec *smokedec;
+  guint8 *data, *outdata;
+  gulong size, outsize;
+  GstBuffer *outbuf;
+  SmokeCodecFlags flags;
+  GstClockTime time;
+  guint width, height;
+  guint fps_num, fps_denom;
+  gint smokeret;
+  GstFlowReturn ret;
+
+  smokedec = GST_SMOKEDEC (gst_pad_get_parent (pad));
+
+  data = GST_BUFFER_DATA (buf);
+  size = GST_BUFFER_SIZE (buf);
+  time = GST_BUFFER_TIMESTAMP (buf);
+
+  if (size < 1)
+    goto too_small;
+
+  GST_LOG_OBJECT (smokedec, "got buffer of %lu bytes", size);
+
+  /* have the ID packet. */
+  if (data[0] == SMOKECODEC_TYPE_ID) {
+    smokeret = smokecodec_parse_id (smokedec->info, data, size);
+    if (smokeret != SMOKECODEC_OK)
+      goto header_error;
+
+    ret = GST_FLOW_OK;
+    goto done;
+  }
+
+  /* now handle data packets */
+  GST_DEBUG_OBJECT (smokedec, "reading header %08lx", *(gulong *) data);
+  smokecodec_parse_header (smokedec->info, data, size, &flags, &width, &height,
+      &fps_num, &fps_denom);
+
+  if (smokedec->height != height || smokedec->width != width ||
+      smokedec->fps_num != fps_num || smokedec->fps_denom != fps_denom) {
+    GstCaps *caps;
+
+    GST_DEBUG_OBJECT (smokedec, "parameter change: %dx%d @ %d/%dfps",
+        width, height, fps_num, fps_denom);
+
+    smokedec->height = height;
+    smokedec->width = width;
+
+    caps = gst_caps_new_simple ("video/x-raw-yuv",
+        "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
+        "width", G_TYPE_INT, width,
+        "height", G_TYPE_INT, height,
+        "framerate", GST_TYPE_FRACTION, fps_num, fps_denom, NULL);
+
+    gst_pad_set_caps (smokedec->srcpad, caps);
+    gst_caps_unref (caps);
+  }
+
+  if (smokedec->need_keyframe) {
+    if (!(flags & SMOKECODEC_KEYFRAME))
+      goto keyframe_skip;
+
+    smokedec->need_keyframe = FALSE;
+  }
+
+  outsize = width * height + width * height / 2;
+  outbuf = gst_buffer_new_and_alloc (outsize);
+  outdata = GST_BUFFER_DATA (outbuf);
+
+  GST_BUFFER_DURATION (outbuf) =
+      gst_util_uint64_scale_int (GST_SECOND, fps_denom, fps_num);
+  GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buf);
+  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (smokedec->srcpad));
+
+  if (time == GST_CLOCK_TIME_NONE) {
+    if (GST_BUFFER_OFFSET (buf) == -1) {
+      time = smokedec->next_time;
+    } else {
+      time = GST_BUFFER_OFFSET (buf) * GST_BUFFER_DURATION (outbuf);
+    }
+  }
+  GST_BUFFER_TIMESTAMP (outbuf) = time;
+  if (time != -1)
+    smokedec->next_time = time + GST_BUFFER_DURATION (outbuf);
+  else
+    smokedec->next_time = -1;
+
+  smokeret = smokecodec_decode (smokedec->info, data, size, outdata);
+  if (smokeret != SMOKECODEC_OK)
+    goto decode_error;
+
+  GST_DEBUG_OBJECT (smokedec, "gst_smokedec_chain: sending buffer");
+  ret = gst_pad_push (smokedec->srcpad, outbuf);
+
+done:
+  gst_buffer_unref (buf);
+  gst_object_unref (smokedec);
+
+  return ret;
+
+  /* ERRORS */
+too_small:
+  {
+    GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
+        (NULL), ("Input buffer too small"));
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+header_error:
+  {
+    GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
+        (NULL), ("Could not parse smoke header, reason: %d", smokeret));
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+keyframe_skip:
+  {
+    GST_DEBUG_OBJECT (smokedec, "dropping buffer while waiting for keyframe");
+    ret = GST_FLOW_OK;
+    goto done;
+  }
+decode_error:
+  {
+    GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
+        (NULL), ("Could not decode smoke frame, reason: %d", smokeret));
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+}
+
+static GstStateChangeReturn
+gst_smokedec_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstSmokeDec *dec;
+
+  dec = GST_SMOKEDEC (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      /* reset the initial video state */
+      dec->format = -1;
+      dec->width = -1;
+      dec->height = -1;
+      dec->fps_num = -1;
+      dec->fps_denom = -1;
+      dec->next_time = 0;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret != GST_STATE_CHANGE_SUCCESS)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
diff --git a/ext/jpeg/gstsmokedec.h b/ext/jpeg/gstsmokedec.h
new file mode 100644
index 0000000..0719077
--- /dev/null
+++ b/ext/jpeg/gstsmokedec.h
@@ -0,0 +1,75 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_SMOKEDEC_H__
+#define __GST_SMOKEDEC_H__
+
+
+#include <gst/gst.h>
+#include "smokecodec.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SMOKEDEC \
+  (gst_smokedec_get_type())
+#define GST_SMOKEDEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SMOKEDEC,GstSmokeDec))
+#define GST_SMOKEDEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SMOKEDEC,GstSmokeDecClass))
+#define GST_IS_SMOKEDEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SMOKEDEC))
+#define GST_IS_SMOKEDEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SMOKEDEC))
+
+typedef struct _GstSmokeDec GstSmokeDec;
+typedef struct _GstSmokeDecClass GstSmokeDecClass;
+
+struct _GstSmokeDec {
+  GstElement element;
+
+  /* pads */
+  GstPad *sinkpad,*srcpad;
+
+  /* video state */
+  gint format;
+  gint width;
+  gint height;
+  gint fps_num;
+  gint fps_denom;
+  GstClockTime next_time;
+
+  SmokeCodecInfo *info;
+
+  gint threshold;
+  gint quality;
+  gint smoothing;
+
+  gboolean need_keyframe;
+};
+
+struct _GstSmokeDecClass {
+  GstElementClass parent_class;
+};
+
+GType gst_smokedec_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_SMOKEDEC_H__ */
diff --git a/ext/jpeg/gstsmokeenc.c b/ext/jpeg/gstsmokeenc.c
new file mode 100644
index 0000000..32b0687
--- /dev/null
+++ b/ext/jpeg/gstsmokeenc.c
@@ -0,0 +1,509 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-smokeenc
+ *
+ * Encodes images in smoke format.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+
+#include "gstsmokeenc.h"
+#include <gst/video/video.h>
+
+GST_DEBUG_CATEGORY_STATIC (smokeenc_debug);
+#define GST_CAT_DEFAULT smokeenc_debug
+
+
+/* SmokeEnc signals and args */
+enum
+{
+  FRAME_ENCODED,
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+#define DEFAULT_PROP_MIN_QUALITY 10
+#define DEFAULT_PROP_MAX_QUALITY 85
+#define DEFAULT_PROP_THRESHOLD 3000
+#define DEFAULT_PROP_KEYFRAME 20
+
+enum
+{
+  PROP_0,
+  PROP_MIN_QUALITY,
+  PROP_MAX_QUALITY,
+  PROP_THRESHOLD,
+  PROP_KEYFRAME
+      /* FILL ME */
+};
+
+static void gst_smokeenc_base_init (gpointer g_class);
+static void gst_smokeenc_class_init (GstSmokeEnc * klass);
+static void gst_smokeenc_init (GstSmokeEnc * smokeenc);
+static void gst_smokeenc_finalize (GObject * object);
+
+static GstStateChangeReturn
+gst_smokeenc_change_state (GstElement * element, GstStateChange transition);
+
+static GstFlowReturn gst_smokeenc_chain (GstPad * pad, GstBuffer * buf);
+static GstCaps *gst_smokeenc_getcaps (GstPad * pad);
+static gboolean gst_smokeenc_setcaps (GstPad * pad, GstCaps * caps);
+
+static gboolean gst_smokeenc_resync (GstSmokeEnc * smokeenc);
+static void gst_smokeenc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_smokeenc_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstElementClass *parent_class = NULL;
+
+GType
+gst_smokeenc_get_type (void)
+{
+  static GType smokeenc_type = 0;
+
+  if (!smokeenc_type) {
+    static const GTypeInfo smokeenc_info = {
+      sizeof (GstSmokeEncClass),
+      (GBaseInitFunc) gst_smokeenc_base_init,
+      NULL,
+      (GClassInitFunc) gst_smokeenc_class_init,
+      NULL,
+      NULL,
+      sizeof (GstSmokeEnc),
+      0,
+      (GInstanceInitFunc) gst_smokeenc_init,
+    };
+
+    smokeenc_type =
+        g_type_register_static (GST_TYPE_ELEMENT, "GstSmokeEnc", &smokeenc_info,
+        0);
+  }
+  return smokeenc_type;
+}
+
+static GstStaticPadTemplate gst_smokeenc_sink_pad_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
+    );
+
+static GstStaticPadTemplate gst_smokeenc_src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-smoke, "
+        "width = (int) [ 16, 4096 ], "
+        "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0/1, MAX ]")
+    );
+
+static void
+gst_smokeenc_base_init (gpointer g_class)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_smokeenc_sink_pad_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_smokeenc_src_pad_template);
+  gst_element_class_set_static_metadata (element_class, "Smoke video encoder",
+      "Codec/Encoder/Video", "Encode images into the Smoke format",
+      "Wim Taymans <wim@fluendo.com>");
+}
+
+static void
+gst_smokeenc_class_init (GstSmokeEnc * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gst_smokeenc_finalize;
+  gobject_class->set_property = gst_smokeenc_set_property;
+  gobject_class->get_property = gst_smokeenc_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_MIN_QUALITY,
+      g_param_spec_int ("qmin", "Qmin", "Minimum quality",
+          0, 100, DEFAULT_PROP_MIN_QUALITY,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MAX_QUALITY,
+      g_param_spec_int ("qmax", "Qmax", "Maximum quality",
+          0, 100, DEFAULT_PROP_MAX_QUALITY,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_THRESHOLD,
+      g_param_spec_int ("threshold", "Threshold", "Motion estimation threshold",
+          0, 100000000, DEFAULT_PROP_THRESHOLD,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_KEYFRAME,
+      g_param_spec_int ("keyframe", "Keyframe",
+          "Insert keyframe every N frames", 1, 100000,
+          DEFAULT_PROP_KEYFRAME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_smokeenc_change_state);
+
+  GST_DEBUG_CATEGORY_INIT (smokeenc_debug, "smokeenc", 0,
+      "Smoke encoding element");
+}
+
+static void
+gst_smokeenc_init (GstSmokeEnc * smokeenc)
+{
+  /* create the sink and src pads */
+  smokeenc->sinkpad =
+      gst_pad_new_from_static_template (&gst_smokeenc_sink_pad_template,
+      "sink");
+  gst_pad_set_chain_function (smokeenc->sinkpad, gst_smokeenc_chain);
+  gst_pad_set_getcaps_function (smokeenc->sinkpad, gst_smokeenc_getcaps);
+  gst_pad_set_setcaps_function (smokeenc->sinkpad, gst_smokeenc_setcaps);
+  gst_element_add_pad (GST_ELEMENT (smokeenc), smokeenc->sinkpad);
+
+  smokeenc->srcpad =
+      gst_pad_new_from_static_template (&gst_smokeenc_src_pad_template, "src");
+  gst_pad_set_getcaps_function (smokeenc->srcpad, gst_smokeenc_getcaps);
+  gst_pad_use_fixed_caps (smokeenc->srcpad);
+  gst_element_add_pad (GST_ELEMENT (smokeenc), smokeenc->srcpad);
+
+  smokeenc->min_quality = DEFAULT_PROP_MIN_QUALITY;
+  smokeenc->max_quality = DEFAULT_PROP_MAX_QUALITY;
+  smokeenc->threshold = DEFAULT_PROP_THRESHOLD;
+  smokeenc->keyframe = DEFAULT_PROP_KEYFRAME;
+}
+
+static void
+gst_smokeenc_finalize (GObject * object)
+{
+  GstSmokeEnc *enc = GST_SMOKEENC (object);
+
+  if (enc->info)
+    smokecodec_info_free (enc->info);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstCaps *
+gst_smokeenc_getcaps (GstPad * pad)
+{
+  GstSmokeEnc *smokeenc = GST_SMOKEENC (gst_pad_get_parent (pad));
+  GstPad *otherpad;
+  GstCaps *result, *caps;
+  const GstCaps *tcaps;
+  const char *name;
+  int i;
+  GstStructure *structure = NULL;
+
+  /* we want to proxy properties like width, height and framerate from the
+     other end of the element */
+  otherpad = (pad == smokeenc->srcpad) ? smokeenc->sinkpad : smokeenc->srcpad;
+
+  /* get template caps, we always need this to fiter the peer caps */
+  tcaps = gst_pad_get_pad_template_caps (otherpad);
+
+  /* get any constraints on the peer pad */
+  caps = gst_pad_peer_get_caps (otherpad);
+
+  if (caps == NULL)
+    caps = gst_caps_copy (tcaps);
+  else
+    caps = gst_caps_make_writable (caps);
+
+  /* intersect with the template */
+  result = gst_caps_intersect (caps, tcaps);
+  gst_caps_unref (caps);
+
+  if (pad == smokeenc->srcpad) {
+    name = "video/x-smoke";
+  } else {
+    name = "video/x-raw-yuv";
+  }
+
+  /* we can only copy width, height, framerate from one side to the other */
+  for (i = 0; i < gst_caps_get_size (result); i++) {
+    structure = gst_caps_get_structure (result, i);
+
+    gst_structure_set_name (structure, name);
+    gst_structure_remove_field (structure, "format");
+    /* ... but for the sink pad, we only do I420 anyway, so add that */
+    if (pad == smokeenc->sinkpad) {
+      gst_structure_set (structure, "format", GST_TYPE_FOURCC,
+          GST_STR_FOURCC ("I420"), NULL);
+    }
+  }
+
+  gst_object_unref (smokeenc);
+
+  return result;
+}
+
+static gboolean
+gst_smokeenc_setcaps (GstPad * pad, GstCaps * caps)
+{
+  GstSmokeEnc *smokeenc;
+  GstStructure *structure;
+  const GValue *framerate;
+  gboolean ret;
+  GstCaps *srccaps;
+
+  smokeenc = GST_SMOKEENC (gst_pad_get_parent (pad));
+
+  structure = gst_caps_get_structure (caps, 0);
+  framerate = gst_structure_get_value (structure, "framerate");
+  if (framerate) {
+    smokeenc->fps_num = gst_value_get_fraction_numerator (framerate);
+    smokeenc->fps_denom = gst_value_get_fraction_denominator (framerate);
+  } else {
+    smokeenc->fps_num = 0;
+    smokeenc->fps_denom = 1;
+  }
+
+  gst_structure_get_int (structure, "width", &smokeenc->width);
+  gst_structure_get_int (structure, "height", &smokeenc->height);
+
+  if ((smokeenc->width & 0x0f) != 0 || (smokeenc->height & 0x0f) != 0)
+    goto width_or_height_notx16;
+
+  if (!gst_smokeenc_resync (smokeenc))
+    goto init_failed;
+
+  srccaps = gst_caps_new_simple ("video/x-smoke",
+      "width", G_TYPE_INT, smokeenc->width,
+      "height", G_TYPE_INT, smokeenc->height,
+      "framerate", GST_TYPE_FRACTION, smokeenc->fps_num, smokeenc->fps_denom,
+      NULL);
+
+  ret = gst_pad_set_caps (smokeenc->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  gst_object_unref (smokeenc);
+
+  return ret;
+
+width_or_height_notx16:
+  {
+    GST_WARNING_OBJECT (smokeenc, "width and height must be multiples of 16"
+        ", %dx%d not allowed", smokeenc->width, smokeenc->height);
+    gst_object_unref (smokeenc);
+    return FALSE;
+  }
+init_failed:
+  {
+    GST_WARNING_OBJECT (smokeenc, "could not init decoder");
+    gst_object_unref (smokeenc);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_smokeenc_resync (GstSmokeEnc * smokeenc)
+{
+  int ret;
+
+  GST_DEBUG ("resync: %dx%d@%d/%dfps", smokeenc->width, smokeenc->height,
+      smokeenc->fps_num, smokeenc->fps_denom);
+
+  if (smokeenc->info)
+    smokecodec_info_free (smokeenc->info);
+
+  ret = smokecodec_encode_new (&smokeenc->info, smokeenc->width,
+      smokeenc->height, smokeenc->fps_num, smokeenc->fps_denom);
+
+  if (ret != SMOKECODEC_OK)
+    goto init_failed;
+
+  smokecodec_set_quality (smokeenc->info, smokeenc->min_quality,
+      smokeenc->max_quality);
+
+  GST_DEBUG ("resync done");
+  return TRUE;
+
+  /* ERRORS */
+init_failed:
+  {
+    GST_WARNING_OBJECT (smokeenc, "smokecodec_encode_new() failed: %d", ret);
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_smokeenc_chain (GstPad * pad, GstBuffer * buf)
+{
+  GstSmokeEnc *smokeenc;
+  guchar *data, *outdata;
+  gulong size;
+  gint outsize;
+  guint encsize;
+  GstBuffer *outbuf;
+  SmokeCodecFlags flags;
+  GstFlowReturn ret;
+
+  smokeenc = GST_SMOKEENC (GST_OBJECT_PARENT (pad));
+
+  data = GST_BUFFER_DATA (buf);
+  size = GST_BUFFER_SIZE (buf);
+
+  GST_LOG_OBJECT (smokeenc, "got buffer of %lu bytes", size);
+
+  if (smokeenc->need_header) {
+    outbuf = gst_buffer_new_and_alloc (256);
+    outdata = GST_BUFFER_DATA (outbuf);
+
+    GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
+    GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
+
+    smokecodec_encode_id (smokeenc->info, outdata, &encsize);
+
+    GST_BUFFER_SIZE (outbuf) = encsize;
+    gst_buffer_set_caps (outbuf, GST_PAD_CAPS (smokeenc->srcpad));
+
+    ret = gst_pad_push (smokeenc->srcpad, outbuf);
+    if (ret != GST_FLOW_OK)
+      goto done;
+
+    smokeenc->need_header = FALSE;
+  }
+
+  encsize = outsize = smokeenc->width * smokeenc->height * 3;
+  outbuf = gst_buffer_new_and_alloc (outsize);
+  outdata = GST_BUFFER_DATA (outbuf);
+
+  GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
+  GST_BUFFER_DURATION (outbuf) =
+      gst_util_uint64_scale_int (GST_SECOND, smokeenc->fps_denom,
+      smokeenc->fps_num);
+  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (smokeenc->srcpad));
+
+  flags = 0;
+  if ((smokeenc->frame % smokeenc->keyframe) == 0) {
+    flags |= SMOKECODEC_KEYFRAME;
+  }
+  smokecodec_set_quality (smokeenc->info, smokeenc->min_quality,
+      smokeenc->max_quality);
+  smokecodec_set_threshold (smokeenc->info, smokeenc->threshold);
+  smokecodec_encode (smokeenc->info, data, flags, outdata, &encsize);
+  gst_buffer_unref (buf);
+
+  GST_BUFFER_SIZE (outbuf) = encsize;
+  GST_BUFFER_OFFSET (outbuf) = smokeenc->frame;
+  GST_BUFFER_OFFSET_END (outbuf) = smokeenc->frame + 1;
+
+  ret = gst_pad_push (smokeenc->srcpad, outbuf);
+
+  smokeenc->frame++;
+
+done:
+
+  return ret;
+}
+
+static void
+gst_smokeenc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstSmokeEnc *smokeenc;
+
+  g_return_if_fail (GST_IS_SMOKEENC (object));
+  smokeenc = GST_SMOKEENC (object);
+
+  switch (prop_id) {
+    case PROP_MIN_QUALITY:
+      smokeenc->min_quality = g_value_get_int (value);
+      break;
+    case PROP_MAX_QUALITY:
+      smokeenc->max_quality = g_value_get_int (value);
+      break;
+    case PROP_THRESHOLD:
+      smokeenc->threshold = g_value_get_int (value);
+      break;
+    case PROP_KEYFRAME:
+      smokeenc->keyframe = g_value_get_int (value);
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_smokeenc_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstSmokeEnc *smokeenc;
+
+  g_return_if_fail (GST_IS_SMOKEENC (object));
+  smokeenc = GST_SMOKEENC (object);
+
+  switch (prop_id) {
+    case PROP_MIN_QUALITY:
+      g_value_set_int (value, smokeenc->min_quality);
+      break;
+    case PROP_MAX_QUALITY:
+      g_value_set_int (value, smokeenc->max_quality);
+      break;
+    case PROP_THRESHOLD:
+      g_value_set_int (value, smokeenc->threshold);
+      break;
+    case PROP_KEYFRAME:
+      g_value_set_int (value, smokeenc->keyframe);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStateChangeReturn
+gst_smokeenc_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstSmokeEnc *enc;
+
+  enc = GST_SMOKEENC (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      /* reset the initial video state */
+      enc->width = 0;
+      enc->height = 0;
+      enc->frame = 0;
+      enc->need_header = TRUE;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret != GST_STATE_CHANGE_SUCCESS)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
diff --git a/ext/jpeg/gstsmokeenc.h b/ext/jpeg/gstsmokeenc.h
new file mode 100644
index 0000000..013b28c
--- /dev/null
+++ b/ext/jpeg/gstsmokeenc.h
@@ -0,0 +1,75 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_SMOKEENC_H__
+#define __GST_SMOKEENC_H__
+
+
+#include <gst/gst.h>
+#include "smokecodec.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SMOKEENC \
+  (gst_smokeenc_get_type())
+#define GST_SMOKEENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SMOKEENC,GstSmokeEnc))
+#define GST_SMOKEENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SMOKEENC,GstSmokeEncClass))
+#define GST_IS_SMOKEENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SMOKEENC))
+#define GST_IS_SMOKEENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SMOKEENC))
+
+typedef struct _GstSmokeEnc GstSmokeEnc;
+typedef struct _GstSmokeEncClass GstSmokeEncClass;
+
+struct _GstSmokeEnc {
+  GstElement element;
+
+  /* pads */
+  GstPad *sinkpad,*srcpad;
+
+  /* video state */
+  gint format;
+  gint width;
+  gint height;
+  gint frame;
+  gint keyframe;
+  gint fps_num, fps_denom;
+
+  SmokeCodecInfo *info;
+
+  gint threshold;
+  gint min_quality;
+  gint max_quality;
+
+  gboolean need_header;
+};
+
+struct _GstSmokeEncClass {
+  GstElementClass parent_class;
+};
+
+GType gst_smokeenc_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_SMOKEENC_H__ */
diff --git a/ext/jpeg/meson.build b/ext/jpeg/meson.build
new file mode 100644
index 0000000..e3628cb
--- /dev/null
+++ b/ext/jpeg/meson.build
@@ -0,0 +1,19 @@
+jpeg_sources = [
+  'gstjpeg.c',
+  'gstjpegenc.c',
+  'gstjpegdec.c',
+]
+
+jpeglib = cc.find_library('jpeg', required : false)
+
+if jpeglib.found()
+  gstjpeg = library('gstjpeg',
+    jpeg_sources,
+    c_args : gst_plugins_good_args,
+    link_args : noseh_link_args,
+    include_directories : [configinc, libsinc],
+    dependencies : [gst_dep, gstbase_dep, gstvideo_dep, jpeglib, libm],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/ext/jpeg/smokecodec.c b/ext/jpeg/smokecodec.c
new file mode 100644
index 0000000..a13152d
--- /dev/null
+++ b/ext/jpeg/smokecodec.c
@@ -0,0 +1,709 @@
+/* Smoke codec
+ * Copyright (C) <2004> Wim Taymans <wim@fluendo.com> 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+/* this is a hack hack hack to get around jpeglib header bugs... */
+#ifdef HAVE_STDLIB_H
+# undef HAVE_STDLIB_H
+#endif
+#include <jpeglib.h>
+
+#include "smokecodec.h"
+#include "smokeformat.h"
+
+#include <gst/gstinfo.h>
+
+struct _SmokeCodecInfo
+{
+  unsigned int width;
+  unsigned int height;
+  unsigned int fps_num;
+  unsigned int fps_denom;
+
+  unsigned int minquality;
+  unsigned int maxquality;
+  unsigned int bitrate;
+  unsigned int threshold;
+
+  unsigned int refdec;
+
+  unsigned char **line[3];
+  unsigned char *compbuf[3];
+
+  struct jpeg_error_mgr jerr;
+
+  struct jpeg_compress_struct cinfo;
+  struct jpeg_destination_mgr jdest;
+
+  struct jpeg_decompress_struct dinfo;
+  struct jpeg_source_mgr jsrc;
+
+  int need_keyframe;
+  unsigned char *reference;
+};
+
+static void
+smokecodec_init_destination (j_compress_ptr cinfo)
+{
+}
+
+static boolean
+smokecodec_flush_destination (j_compress_ptr cinfo)
+{
+  return 1;
+}
+
+static void
+smokecodec_term_destination (j_compress_ptr cinfo)
+{
+}
+
+static void
+smokecodec_init_source (j_decompress_ptr cinfo)
+{
+}
+
+static boolean
+smokecodec_fill_input_buffer (j_decompress_ptr cinfo)
+{
+  return 1;
+}
+
+static void
+smokecodec_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+}
+
+static boolean
+smokecodec_resync_to_restart (j_decompress_ptr cinfo, int desired)
+{
+  return 1;
+}
+
+static void
+smokecodec_term_source (j_decompress_ptr cinfo)
+{
+}
+
+
+int
+smokecodec_encode_new (SmokeCodecInfo ** info,
+    const unsigned int width,
+    const unsigned int height,
+    const unsigned int fps_num, const unsigned int fps_denom)
+{
+  SmokeCodecInfo *newinfo;
+  int i, j;
+  unsigned char *base[3];
+
+  if (!info)
+    return SMOKECODEC_NULLPTR;
+  if ((width & 0xf) || (height & 0xf))
+    return SMOKECODEC_WRONGSIZE;
+
+  newinfo = malloc (sizeof (SmokeCodecInfo));
+  if (!newinfo) {
+    return SMOKECODEC_NOMEM;
+  }
+  newinfo->width = width;
+  newinfo->height = height;
+  newinfo->fps_num = fps_num;
+  newinfo->fps_denom = fps_denom;
+
+  /* setup jpeglib */
+  memset (&newinfo->cinfo, 0, sizeof (newinfo->cinfo));
+  memset (&newinfo->jerr, 0, sizeof (newinfo->jerr));
+  newinfo->cinfo.err = jpeg_std_error (&newinfo->jerr);
+  jpeg_create_compress (&newinfo->cinfo);
+  newinfo->cinfo.input_components = 3;
+  jpeg_set_defaults (&newinfo->cinfo);
+
+  newinfo->cinfo.dct_method = JDCT_FASTEST;
+
+  /* prepare for raw input */
+#if JPEG_LIB_VERSION >= 70
+  newinfo->cinfo.do_fancy_downsampling = FALSE;
+#endif
+
+  newinfo->cinfo.raw_data_in = TRUE;
+  newinfo->cinfo.in_color_space = JCS_YCbCr;
+  newinfo->cinfo.comp_info[0].h_samp_factor = 2;
+  newinfo->cinfo.comp_info[0].v_samp_factor = 2;
+  newinfo->cinfo.comp_info[1].h_samp_factor = 1;
+  newinfo->cinfo.comp_info[1].v_samp_factor = 1;
+  newinfo->cinfo.comp_info[2].h_samp_factor = 1;
+  newinfo->cinfo.comp_info[2].v_samp_factor = 1;
+
+  newinfo->line[0] = malloc (DCTSIZE * 2 * sizeof (char *));
+  newinfo->line[1] = malloc (DCTSIZE * sizeof (char *));
+  newinfo->line[2] = malloc (DCTSIZE * sizeof (char *));
+  base[0] = newinfo->compbuf[0] = malloc (256 * 2 * DCTSIZE * 2 * DCTSIZE);
+  base[1] = newinfo->compbuf[1] = malloc (256 * DCTSIZE * DCTSIZE);
+  base[2] = newinfo->compbuf[2] = malloc (256 * DCTSIZE * DCTSIZE);
+
+  for (i = 0, j = 0; i < 2 * DCTSIZE; i += 2, j++) {
+    newinfo->line[0][i] = base[0];
+    base[0] += 2 * DCTSIZE * 256;
+    newinfo->line[0][i + 1] = base[0];
+    base[0] += 2 * DCTSIZE * 256;
+    newinfo->line[1][j] = base[1];
+    base[1] += DCTSIZE * 256;
+    newinfo->line[2][j] = base[2];
+    base[2] += DCTSIZE * 256;
+  }
+
+  newinfo->jdest.init_destination = smokecodec_init_destination;
+  newinfo->jdest.empty_output_buffer = smokecodec_flush_destination;
+  newinfo->jdest.term_destination = smokecodec_term_destination;
+  newinfo->cinfo.dest = &newinfo->jdest;
+
+  jpeg_suppress_tables (&newinfo->cinfo, FALSE);
+
+  memset (&newinfo->dinfo, 0, sizeof (newinfo->dinfo));
+  newinfo->dinfo.err = jpeg_std_error (&newinfo->jerr);
+  jpeg_create_decompress (&newinfo->dinfo);
+
+  newinfo->jsrc.init_source = smokecodec_init_source;
+  newinfo->jsrc.fill_input_buffer = smokecodec_fill_input_buffer;
+  newinfo->jsrc.skip_input_data = smokecodec_skip_input_data;
+  newinfo->jsrc.resync_to_restart = smokecodec_resync_to_restart;
+  newinfo->jsrc.term_source = smokecodec_term_source;
+  newinfo->dinfo.src = &newinfo->jsrc;
+
+  newinfo->need_keyframe = 1;
+  newinfo->threshold = 4000;
+  newinfo->minquality = 10;
+  newinfo->maxquality = 85;
+  newinfo->reference = malloc (3 * (width * height) / 2);
+  newinfo->refdec = 0;
+
+  *info = newinfo;
+
+  return SMOKECODEC_OK;
+}
+
+int
+smokecodec_decode_new (SmokeCodecInfo ** info)
+{
+  return smokecodec_encode_new (info, 16, 16, 1, 1);
+}
+
+int
+smokecodec_info_free (SmokeCodecInfo * info)
+{
+  free (info->line[0]);
+  free (info->line[1]);
+  free (info->line[2]);
+  free (info->compbuf[0]);
+  free (info->compbuf[1]);
+  free (info->compbuf[2]);
+  free (info->reference);
+  jpeg_destroy_compress (&info->cinfo);
+  jpeg_destroy_decompress (&info->dinfo);
+  free (info);
+
+  return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_set_quality (SmokeCodecInfo * info,
+    const unsigned int min, const unsigned int max)
+{
+  info->minquality = min;
+  info->maxquality = max;
+
+  return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_get_quality (SmokeCodecInfo * info,
+    unsigned int *min, unsigned int *max)
+{
+  *min = info->minquality;
+  *max = info->maxquality;
+
+  return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_set_threshold (SmokeCodecInfo * info, const unsigned int threshold)
+{
+  info->threshold = threshold;
+
+  return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_get_threshold (SmokeCodecInfo * info, unsigned int *threshold)
+{
+  *threshold = info->threshold;
+
+  return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_set_bitrate (SmokeCodecInfo * info, const unsigned int bitrate)
+{
+  info->bitrate = bitrate;
+
+  return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_get_bitrate (SmokeCodecInfo * info, unsigned int *bitrate)
+{
+  *bitrate = info->bitrate;
+
+  return SMOKECODEC_OK;
+}
+
+static void
+find_best_size (int blocks, unsigned int *width, unsigned int *height)
+{
+  int sqchng;
+  int w, h;
+  int best, bestw;
+  int free;
+
+  sqchng = ceil (sqrt (blocks));
+  w = sqchng;
+  h = sqchng;
+
+  GST_DEBUG ("guess: %d %d", w, h);
+
+  free = w * h - blocks;
+  best = free;
+  bestw = w;
+
+  while (w < 256) {
+    GST_DEBUG ("current: %d %d", w, h);
+    if (free < best) {
+      best = free;
+      bestw = w;
+      if (free == 0)
+        break;
+    }
+    // if we cannot reduce the height, increase width
+    if (free < w) {
+      w++;
+      free += h;
+    }
+    // reduce height while possible
+    while (free >= w) {
+      h--;
+      free -= w;
+    }
+  }
+  *width = bestw;
+  *height = (blocks + best) / bestw;
+}
+
+static int
+abs_diff (const unsigned char *in1, const unsigned char *in2, const int stride)
+{
+  int s;
+  int i, j, diff;
+
+  s = 0;
+
+  for (i = 0; i < 2 * DCTSIZE; i++) {
+    for (j = 0; j < 2 * DCTSIZE; j++) {
+      diff = in1[j] - in2[j];
+      s += diff * diff;
+    }
+    in1 += stride;
+    in2 += stride;
+  }
+  return s;
+}
+
+static void
+put (const unsigned char *src, unsigned char *dest,
+    int width, int height, int srcstride, int deststride)
+{
+  int i, j;
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      dest[j] = src[j];
+    }
+    src += srcstride;
+    dest += deststride;
+  }
+}
+
+/* encoding */
+SmokeCodecResult
+smokecodec_encode_id (SmokeCodecInfo * info,
+    unsigned char *out, unsigned int *outsize)
+{
+  int i;
+
+  *out++ = SMOKECODEC_TYPE_ID;
+  for (i = 0; i < strlen (SMOKECODEC_ID_STRING); i++) {
+    *out++ = SMOKECODEC_ID_STRING[i];
+  }
+  *out++ = 0;
+  *out++ = 1;
+  *out++ = 0;
+
+  *outsize = 9;
+
+  return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_encode (SmokeCodecInfo * info,
+    const unsigned char *in,
+    SmokeCodecFlags flags, unsigned char *out, unsigned int *outsize)
+{
+  unsigned int i, j, s;
+  const unsigned char *ip;
+  unsigned char *op;
+  unsigned int blocks, encoding;
+  unsigned int size;
+  unsigned int width, height;
+  unsigned int blocks_w, blocks_h;
+  unsigned int threshold;
+  unsigned int max;
+
+  if (info->need_keyframe) {
+    flags |= SMOKECODEC_KEYFRAME;
+    info->need_keyframe = 0;
+  }
+
+  if (flags & SMOKECODEC_KEYFRAME)
+    threshold = 0;
+  else
+    threshold = info->threshold;
+
+  ip = in;
+  op = info->reference;
+
+  width = info->width;
+  height = info->height;
+
+  blocks_w = width / (DCTSIZE * 2);
+  blocks_h = height / (DCTSIZE * 2);
+
+  max = blocks_w * blocks_h;
+
+  out[IDX_TYPE] = SMOKECODEC_TYPE_DATA;
+
+#define STORE16(var, pos, x) \
+   var[pos]   = (x >> 8); \
+   var[pos+1] = (x & 0xff);
+#define STORE32(var, pos, x) \
+   var[pos]   = ((x >> 24) & 0xff); \
+   var[pos+1] = ((x >> 16) & 0xff); \
+   var[pos+2] = ((x >> 8) & 0xff); \
+   var[pos+3] =  (x & 0xff);
+
+  /* write dimension */
+  STORE16 (out, IDX_WIDTH, width);
+  STORE16 (out, IDX_HEIGHT, height);
+
+  /* write framerate */
+  STORE32 (out, IDX_FPS_NUM, info->fps_num);
+  STORE32 (out, IDX_FPS_DENOM, info->fps_denom);
+
+  if (!(flags & SMOKECODEC_KEYFRAME)) {
+    int block = 0;
+
+    blocks = 0;
+    for (i = 0; i < height; i += 2 * DCTSIZE) {
+      for (j = 0; j < width; j += 2 * DCTSIZE) {
+        s = abs_diff (ip, op, width);
+        if (s >= threshold) {
+          STORE16 (out, blocks * 2 + IDX_BLOCKS, block);
+          blocks++;
+        }
+
+        ip += 2 * DCTSIZE;
+        op += 2 * DCTSIZE;
+        block++;
+      }
+      ip += (2 * DCTSIZE - 1) * width;
+      op += (2 * DCTSIZE - 1) * width;
+    }
+    if (blocks == max) {
+      flags |= SMOKECODEC_KEYFRAME;
+      blocks = 0;
+      encoding = max;
+    } else {
+      encoding = blocks;
+    }
+  } else {
+    blocks = 0;
+    encoding = max;
+  }
+  STORE16 (out, IDX_NUM_BLOCKS, blocks);
+  out[IDX_FLAGS] = (flags & 0xff);
+
+  GST_DEBUG ("blocks %d, encoding %d", blocks, encoding);
+
+  info->jdest.next_output_byte = &out[blocks * 2 + OFFS_PICT];
+  info->jdest.free_in_buffer = (*outsize) - OFFS_PICT;
+
+  if (encoding > 0) {
+    int quality;
+
+    if (!(flags & SMOKECODEC_KEYFRAME))
+      find_best_size (encoding, &blocks_w, &blocks_h);
+
+    GST_DEBUG ("best: %d %d", blocks_w, blocks_h);
+
+    info->cinfo.image_width = blocks_w * DCTSIZE * 2;
+    info->cinfo.image_height = blocks_h * DCTSIZE * 2;
+
+    if (flags & SMOKECODEC_KEYFRAME) {
+      quality = (info->maxquality * 60) / 100;
+    } else {
+      quality =
+          info->maxquality - ((info->maxquality -
+              info->minquality) * blocks) / max;
+    }
+
+    GST_DEBUG ("set q %d %d %d", quality, encoding, max);
+    jpeg_set_quality (&info->cinfo, quality, TRUE);
+    GST_DEBUG ("start");
+    jpeg_start_compress (&info->cinfo, TRUE);
+
+    for (i = 0; i < encoding; i++) {
+      int pos;
+      int x, y;
+
+      if (flags & SMOKECODEC_KEYFRAME)
+        pos = i;
+      else
+        pos = (out[i * 2 + IDX_BLOCKS] << 8) | (out[i * 2 + IDX_BLOCKS + 1]);
+
+      x = pos % (width / (DCTSIZE * 2));
+      y = pos / (width / (DCTSIZE * 2));
+
+      ip = in + (x * (DCTSIZE * 2)) + (y * (DCTSIZE * 2) * width);
+      op = info->compbuf[0] + (i % blocks_w) * (DCTSIZE * 2);
+      put (ip, op, 2 * DCTSIZE, 2 * DCTSIZE, width, 256 * (DCTSIZE * 2));
+
+      ip = in + width * height + (x * DCTSIZE) + (y * DCTSIZE * width / 2);
+      op = info->compbuf[1] + (i % blocks_w) * (DCTSIZE);
+      put (ip, op, DCTSIZE, DCTSIZE, width / 2, 256 * DCTSIZE);
+
+      ip = in + 5 * (width * height) / 4 + (x * DCTSIZE) +
+          (y * DCTSIZE * width / 2);
+      op = info->compbuf[2] + (i % blocks_w) * (DCTSIZE);
+      put (ip, op, DCTSIZE, DCTSIZE, width / 2, 256 * DCTSIZE);
+
+      if ((i % blocks_w) == (blocks_w - 1) || (i == encoding - 1)) {
+        GST_DEBUG ("write %d", pos);
+        jpeg_write_raw_data (&info->cinfo, info->line, 2 * DCTSIZE);
+      }
+    }
+    GST_DEBUG ("finish");
+    jpeg_finish_compress (&info->cinfo);
+  }
+
+  size = ((((*outsize) - OFFS_PICT - info->jdest.free_in_buffer) + 3) & ~3);
+  STORE16 (out, IDX_SIZE, size);
+
+  *outsize = size + blocks * 2 + OFFS_PICT;
+  GST_DEBUG ("outsize %d", *outsize);
+
+  // and decode in reference frame again
+  if (info->refdec) {
+    smokecodec_decode (info, out, *outsize, info->reference);
+  } else {
+    memcpy (info->reference, in, 3 * (width * height) / 2);
+  }
+
+  return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_parse_id (SmokeCodecInfo * info,
+    const unsigned char *in, const unsigned int insize)
+{
+  int i;
+
+  if (insize < 4 + strlen (SMOKECODEC_ID_STRING)) {
+    return SMOKECODEC_WRONGVERSION;
+  }
+
+  if (*in++ != SMOKECODEC_TYPE_ID)
+    return SMOKECODEC_ERROR;
+
+  for (i = 0; i < strlen (SMOKECODEC_ID_STRING); i++) {
+    if (*in++ != SMOKECODEC_ID_STRING[i])
+      return SMOKECODEC_ERROR;
+  }
+  if (*in++ != 0 || *in++ != 1 || *in++ != 0)
+    return SMOKECODEC_ERROR;
+
+  return SMOKECODEC_OK;
+}
+
+#define READ16(var, pos, x) \
+ x = var[pos]<<8 | var[pos+1];
+
+#define READ32(var, pos, x) \
+ x = var[pos]<<24 | var[pos+1]<<16 | \
+     var[pos+2]<<8 | var[pos+3];
+
+/* decoding */
+SmokeCodecResult
+smokecodec_parse_header (SmokeCodecInfo * info,
+    const unsigned char *in,
+    const unsigned int insize,
+    SmokeCodecFlags * flags,
+    unsigned int *width,
+    unsigned int *height, unsigned int *fps_num, unsigned int *fps_denom)
+{
+
+  READ16 (in, IDX_WIDTH, *width);
+  READ16 (in, IDX_HEIGHT, *height);
+  *flags = in[IDX_FLAGS];
+  READ32 (in, IDX_FPS_NUM, *fps_num);
+  READ32 (in, IDX_FPS_DENOM, *fps_denom);
+
+  if (info->width != *width ||
+      info->height != *height ||
+      info->fps_num != *fps_num || info->fps_denom != *fps_denom) {
+    GST_DEBUG ("new width: %d %d", *width, *height);
+
+    info->reference = realloc (info->reference, 3 * ((*width) * (*height)) / 2);
+    info->width = *width;
+    info->height = *height;
+    info->fps_num = *fps_num;
+    info->fps_denom = *fps_denom;
+  }
+
+  return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_decode (SmokeCodecInfo * info,
+    const unsigned char *in, const unsigned int insize, unsigned char *out)
+{
+  unsigned int width, height;
+  unsigned int fps_num, fps_denom;
+  SmokeCodecFlags flags;
+  int i, j;
+  int blocks_w, blocks_h;
+  int blockptr;
+  int blocks, decoding;
+  const unsigned char *ip;
+  unsigned char *op;
+  int res;
+
+  smokecodec_parse_header (info, in, insize, &flags, &width, &height,
+      &fps_num, &fps_denom);
+
+  READ16 (in, IDX_NUM_BLOCKS, blocks);
+  GST_DEBUG ("blocks %d", blocks);
+
+  if (flags & SMOKECODEC_KEYFRAME)
+    decoding = width / (DCTSIZE * 2) * height / (DCTSIZE * 2);
+  else
+    decoding = blocks;
+
+  if (decoding > 0) {
+    info->jsrc.next_input_byte = &in[blocks * 2 + OFFS_PICT];
+    info->jsrc.bytes_in_buffer = insize - (blocks * 2 + OFFS_PICT);
+
+    GST_DEBUG ("header %02x %d", in[blocks * 2 + OFFS_PICT], insize);
+    res = jpeg_read_header (&info->dinfo, TRUE);
+    GST_DEBUG ("header %d %d %d", res, info->dinfo.image_width,
+        info->dinfo.image_height);
+
+    blocks_w = info->dinfo.image_width / (2 * DCTSIZE);
+    blocks_h = info->dinfo.image_height / (2 * DCTSIZE);
+
+    info->dinfo.output_width = info->dinfo.image_width;
+    info->dinfo.output_height = info->dinfo.image_height;
+
+    GST_DEBUG ("start");
+    info->dinfo.do_fancy_upsampling = FALSE;
+    info->dinfo.do_block_smoothing = FALSE;
+    info->dinfo.out_color_space = JCS_YCbCr;
+    info->dinfo.dct_method = JDCT_IFAST;
+    info->dinfo.raw_data_out = TRUE;
+    jpeg_start_decompress (&info->dinfo);
+
+    blockptr = 0;
+
+    for (i = 0; i < blocks_h; i++) {
+      GST_DEBUG ("read");
+      jpeg_read_raw_data (&info->dinfo, info->line, 2 * DCTSIZE);
+
+      GST_DEBUG ("copy %d", blocks_w);
+      for (j = 0; j < blocks_w; j++) {
+        int pos;
+        int x, y;
+
+        if (flags & SMOKECODEC_KEYFRAME)
+          pos = blockptr;
+        else
+          READ16 (in, blockptr * 2 + IDX_BLOCKS, pos);
+
+        x = pos % (width / (DCTSIZE * 2));
+        y = pos / (width / (DCTSIZE * 2));
+
+        GST_DEBUG ("block %d %d %d", pos, x, y);
+
+        ip = info->compbuf[0] + j * (DCTSIZE * 2);
+        op = info->reference + (x * (DCTSIZE * 2)) +
+            (y * (DCTSIZE * 2) * width);
+        put (ip, op, 2 * DCTSIZE, 2 * DCTSIZE, 256 * (DCTSIZE * 2), width);
+
+        ip = info->compbuf[1] + j * (DCTSIZE);
+        op = info->reference + width * height + (x * DCTSIZE) +
+            (y * DCTSIZE * width / 2);
+        put (ip, op, DCTSIZE, DCTSIZE, 256 * DCTSIZE, width / 2);
+
+        ip = info->compbuf[2] + j * (DCTSIZE);
+        op = info->reference + 5 * (width * height) / 4 + (x * DCTSIZE) +
+            (y * DCTSIZE * width / 2);
+        put (ip, op, DCTSIZE, DCTSIZE, 256 * DCTSIZE, width / 2);
+
+        GST_DEBUG ("block done %d %d %d", pos, x, y);
+        blockptr++;
+        if (blockptr >= decoding)
+          break;
+      }
+    }
+    GST_DEBUG ("finish");
+    jpeg_finish_decompress (&info->dinfo);
+  }
+
+  GST_DEBUG ("copy");
+  if (out != info->reference)
+    memcpy (out, info->reference, 3 * (width * height) / 2);
+  GST_DEBUG ("copy done");
+
+  return SMOKECODEC_OK;
+}
diff --git a/ext/jpeg/smokecodec.h b/ext/jpeg/smokecodec.h
new file mode 100644
index 0000000..f7d8a32
--- /dev/null
+++ b/ext/jpeg/smokecodec.h
@@ -0,0 +1,119 @@
+/* Smoke Codec
+ * Copyright (C) <2004> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __SMOKECODEC_H__
+#define __SMOKECODEC_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+typedef struct _SmokeCodecInfo SmokeCodecInfo;
+
+typedef enum {
+  SMOKECODEC_WRONGVERSION       = -5,
+  SMOKECODEC_WRONGSIZE          = -4,
+  SMOKECODEC_ERROR              = -3,
+  SMOKECODEC_NOMEM              = -2,
+  SMOKECODEC_NULLPTR            = -1,
+  SMOKECODEC_OK                 =  0 
+} SmokeCodecResult;
+        
+typedef enum {
+  SMOKECODEC_KEYFRAME           = (1<<0),
+  SMOKECODEC_MOTION_VECTORS     = (1<<1)
+} SmokeCodecFlags;
+        
+#define SMOKECODEC_ID_STRING "smoke"
+
+typedef enum {
+  SMOKECODEC_TYPE_ID            = 0x80,
+  SMOKECODEC_TYPE_COMMENT       = 0x81,
+  SMOKECODEC_TYPE_EXTRA         = 0x83,
+  SMOKECODEC_TYPE_DATA          = 0x40 
+} SmokePacketType;
+
+/* init */
+int                     smokecodec_encode_new   (SmokeCodecInfo **info,
+                                                 const unsigned int width,
+                                                 const unsigned int height,
+                                                 const unsigned int fps_num,
+                                                 const unsigned int fps_denom);
+
+int                     smokecodec_decode_new   (SmokeCodecInfo **info);
+
+int                     smokecodec_info_free    (SmokeCodecInfo * info);
+
+/* config */
+SmokeCodecResult        smokecodec_set_quality  (SmokeCodecInfo *info,
+                                                 const unsigned int min,
+                                                 const unsigned int max);
+SmokeCodecResult        smokecodec_get_quality  (SmokeCodecInfo *info,
+                                                 unsigned int *min,
+                                                 unsigned int *max);
+
+SmokeCodecResult        smokecodec_set_threshold (SmokeCodecInfo *info,
+                                                 const unsigned int threshold);
+SmokeCodecResult        smokecodec_get_threshold (SmokeCodecInfo *info,
+                                                 unsigned int *threshold);
+
+SmokeCodecResult        smokecodec_set_bitrate  (SmokeCodecInfo *info,
+                                                 const unsigned int bitrate);
+SmokeCodecResult        smokecodec_get_bitrate  (SmokeCodecInfo *info,
+                                                 unsigned int *bitrate);
+
+/* encoding */
+SmokeCodecResult        smokecodec_encode_id    (SmokeCodecInfo *info,
+                                                 unsigned char *out,
+                                                 unsigned int *outsize);
+
+SmokeCodecResult        smokecodec_encode       (SmokeCodecInfo *info,
+                                                 const unsigned char *in,
+                                                 SmokeCodecFlags flags,
+                                                 unsigned char *out,
+                                                 unsigned int *outsize);
+
+/* decoding */
+SmokeCodecResult        smokecodec_parse_id     (SmokeCodecInfo *info,
+                                                 const unsigned char *in,
+                                                 const unsigned int insize);
+
+SmokeCodecResult        smokecodec_parse_header (SmokeCodecInfo *info,
+                                                 const unsigned char *in,
+                                                 const unsigned int insize,
+                                                 SmokeCodecFlags *flags,
+                                                 unsigned int *width,
+                                                 unsigned int *height,
+                                                 unsigned int *fps_num,
+                                                 unsigned int *fps_denom);
+
+SmokeCodecResult        smokecodec_decode       (SmokeCodecInfo *info,
+                                                 const unsigned char *in,
+                                                 const unsigned int insize,
+                                                 unsigned char *out);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __SMOKECODEC_H__ */
diff --git a/ext/jpeg/smokeformat.h b/ext/jpeg/smokeformat.h
new file mode 100644
index 0000000..e5c756d
--- /dev/null
+++ b/ext/jpeg/smokeformat.h
@@ -0,0 +1,46 @@
+/* Smoke Codec
+ * Copyright (C) <2004> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __SMOKEFORMAT_H__
+#define __SMOKEFORMAT_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define IDX_TYPE        0
+#define IDX_WIDTH       1
+#define IDX_HEIGHT      3
+#define IDX_FPS_NUM     5
+#define IDX_FPS_DENOM   9
+#define IDX_FLAGS       13
+#define IDX_NUM_BLOCKS  14
+#define IDX_SIZE        16
+#define IDX_BLOCKS      18
+#define OFFS_PICT       18
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __SMOKEFORMAT_H__ */
diff --git a/ext/lame/Makefile.am b/ext/lame/Makefile.am
new file mode 100644
index 0000000..46198c8
--- /dev/null
+++ b/ext/lame/Makefile.am
@@ -0,0 +1,10 @@
+plugin_LTLIBRARIES = libgstlame.la
+
+libgstlame_la_SOURCES = gstlamemp3enc.c plugin.c
+libgstlame_la_CFLAGS = \
+        $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(LAME_CFLAGS)
+libgstlame_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) $(GST_LIBS) $(LAME_LIBS)
+libgstlame_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstlamemp3enc.h
diff --git a/ext/lame/gstlamemp3enc.c b/ext/lame/gstlamemp3enc.c
new file mode 100644
index 0000000..a4a637a
--- /dev/null
+++ b/ext/lame/gstlamemp3enc.c
@@ -0,0 +1,934 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2004> Wim Taymans <wim@fluendo.com>
+ * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-lamemp3enc
+ * @see_also: lame, mad, vorbisenc
+ *
+ * This element encodes raw integer audio into an MPEG-1 layer 3 (MP3) stream.
+ * Note that <ulink url="http://en.wikipedia.org/wiki/MP3">MP3</ulink> is not
+ * a free format, there are licensing and patent issues to take into
+ * consideration. See <ulink url="http://www.vorbis.com/">Ogg/Vorbis</ulink>
+ * for a royalty free (and often higher quality) alternative.
+ *
+ * <refsect2>
+ * <title>Output sample rate</title>
+ * If no fixed output sample rate is negotiated on the element's src pad,
+ * the element will choose an optimal sample rate to resample to internally.
+ * For example, a 16-bit 44.1 KHz mono audio stream encoded at 48 kbit will
+ * get resampled to 32 KHz.  Use filter caps on the src pad to force a
+ * particular sample rate.
+ * </refsect2>
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc wave=sine num-buffers=100 ! audioconvert ! lamemp3enc ! filesink location=sine.mp3
+ * ]| Encode a test sine signal to MP3.
+ * |[
+ * gst-launch-1.0 -v autoaudiosrc ! audioconvert ! lamemp3enc target=bitrate bitrate=192 ! filesink location=alsasrc.mp3
+ * ]| Record from a sound card using ALSA and encode to MP3 with an average bitrate of 192kbps
+ * |[
+ * gst-launch-1.0 -v filesrc location=music.wav ! decodebin ! audioconvert ! audioresample ! lamemp3enc target=quality quality=0 ! id3v2mux ! filesink location=music.mp3
+ * ]| Transcode from a .wav file to MP3 (the id3v2mux element is optional) with best VBR quality
+ * |[
+ * gst-launch-1.0 -v cdda://5 ! audioconvert ! lamemp3enc target=bitrate cbr=true bitrate=192 ! filesink location=track5.mp3
+ * ]| Encode Audio CD track 5 to MP3 with a constant bitrate of 192kbps
+ * |[
+ * gst-launch-1.0 -v audiotestsrc num-buffers=10 ! audio/x-raw,rate=44100,channels=1 ! lamemp3enc target=bitrate cbr=true bitrate=48 ! filesink location=test.mp3
+ * ]| Encode to a fixed sample rate
+ * </refsect2>
+ *
+ * Since: 0.10.12
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include "gstlamemp3enc.h"
+#include <gst/gst-i18n-plugin.h>
+
+/* lame < 3.98 */
+#ifndef HAVE_LAME_SET_VBR_QUALITY
+#define lame_set_VBR_quality(flags,q) lame_set_VBR_q((flags),(int)(q))
+#endif
+
+GST_DEBUG_CATEGORY_STATIC (debug);
+#define GST_CAT_DEFAULT debug
+
+/* elementfactory information */
+
+/* LAMEMP3ENC can do MPEG-1, MPEG-2, and MPEG-2.5, so it has 9 possible
+ * sample rates it supports */
+static GstStaticPadTemplate gst_lamemp3enc_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (S16) ", "
+        "layout = (string) interleaved, "
+        "rate = (int) { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, "
+        "channels = (int) 1; "
+        "audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (S16) ", "
+        "layout = (string) interleaved, "
+        "rate = (int) { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, "
+        "channels = (int) 2, " "channel-mask = (bitmask) 0x3")
+    );
+
+static GstStaticPadTemplate gst_lamemp3enc_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/mpeg, "
+        "mpegversion = (int) 1, "
+        "layer = (int) 3, "
+        "rate = (int) { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, "
+        "channels = (int) [ 1, 2 ]")
+    );
+
+/********** Define useful types for non-programmatic interfaces **********/
+enum
+{
+  LAMEMP3ENC_TARGET_QUALITY = 0,
+  LAMEMP3ENC_TARGET_BITRATE
+};
+
+#define GST_TYPE_LAMEMP3ENC_TARGET (gst_lamemp3enc_target_get_type())
+static GType
+gst_lamemp3enc_target_get_type (void)
+{
+  static GType lame_target_type = 0;
+  static const GEnumValue lame_targets[] = {
+    {LAMEMP3ENC_TARGET_QUALITY, "Quality", "quality"},
+    {LAMEMP3ENC_TARGET_BITRATE, "Bitrate", "bitrate"},
+    {0, NULL, NULL}
+  };
+
+  if (!lame_target_type) {
+    lame_target_type =
+        g_enum_register_static ("GstLameMP3EncTarget", lame_targets);
+  }
+  return lame_target_type;
+}
+
+enum
+{
+  LAMEMP3ENC_ENCODING_ENGINE_QUALITY_FAST = 0,
+  LAMEMP3ENC_ENCODING_ENGINE_QUALITY_STANDARD,
+  LAMEMP3ENC_ENCODING_ENGINE_QUALITY_HIGH
+};
+
+#define GST_TYPE_LAMEMP3ENC_ENCODING_ENGINE_QUALITY (gst_lamemp3enc_encoding_engine_quality_get_type())
+static GType
+gst_lamemp3enc_encoding_engine_quality_get_type (void)
+{
+  static GType lame_encoding_engine_quality_type = 0;
+  static const GEnumValue lame_encoding_engine_quality[] = {
+    {0, "Fast", "fast"},
+    {1, "Standard", "standard"},
+    {2, "High", "high"},
+    {0, NULL, NULL}
+  };
+
+  if (!lame_encoding_engine_quality_type) {
+    lame_encoding_engine_quality_type =
+        g_enum_register_static ("GstLameMP3EncEncodingEngineQuality",
+        lame_encoding_engine_quality);
+  }
+  return lame_encoding_engine_quality_type;
+}
+
+/********** Standard stuff for signals and arguments **********/
+
+enum
+{
+  ARG_0,
+  ARG_TARGET,
+  ARG_BITRATE,
+  ARG_CBR,
+  ARG_QUALITY,
+  ARG_ENCODING_ENGINE_QUALITY,
+  ARG_MONO
+};
+
+#define DEFAULT_TARGET LAMEMP3ENC_TARGET_QUALITY
+#define DEFAULT_BITRATE 128
+#define DEFAULT_CBR FALSE
+#define DEFAULT_QUALITY 4
+#define DEFAULT_ENCODING_ENGINE_QUALITY LAMEMP3ENC_ENCODING_ENGINE_QUALITY_STANDARD
+#define DEFAULT_MONO FALSE
+
+static gboolean gst_lamemp3enc_start (GstAudioEncoder * enc);
+static gboolean gst_lamemp3enc_stop (GstAudioEncoder * enc);
+static gboolean gst_lamemp3enc_set_format (GstAudioEncoder * enc,
+    GstAudioInfo * info);
+static GstFlowReturn gst_lamemp3enc_handle_frame (GstAudioEncoder * enc,
+    GstBuffer * in_buf);
+static void gst_lamemp3enc_flush (GstAudioEncoder * enc);
+
+static void gst_lamemp3enc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_lamemp3enc_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static gboolean gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags);
+
+#define gst_lamemp3enc_parent_class parent_class
+G_DEFINE_TYPE (GstLameMP3Enc, gst_lamemp3enc, GST_TYPE_AUDIO_ENCODER);
+
+static void
+gst_lamemp3enc_release_memory (GstLameMP3Enc * lame)
+{
+  if (lame->lgf) {
+    lame_close (lame->lgf);
+    lame->lgf = NULL;
+  }
+}
+
+static void
+gst_lamemp3enc_finalize (GObject * obj)
+{
+  gst_lamemp3enc_release_memory (GST_LAMEMP3ENC (obj));
+
+  G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gst_lamemp3enc_class_init (GstLameMP3EncClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstAudioEncoderClass *base_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  base_class = (GstAudioEncoderClass *) klass;
+
+  gobject_class->set_property = gst_lamemp3enc_set_property;
+  gobject_class->get_property = gst_lamemp3enc_get_property;
+  gobject_class->finalize = gst_lamemp3enc_finalize;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_lamemp3enc_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_lamemp3enc_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "L.A.M.E. mp3 encoder", "Codec/Encoder/Audio",
+      "High-quality free MP3 encoder",
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  base_class->start = GST_DEBUG_FUNCPTR (gst_lamemp3enc_start);
+  base_class->stop = GST_DEBUG_FUNCPTR (gst_lamemp3enc_stop);
+  base_class->set_format = GST_DEBUG_FUNCPTR (gst_lamemp3enc_set_format);
+  base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_lamemp3enc_handle_frame);
+  base_class->flush = GST_DEBUG_FUNCPTR (gst_lamemp3enc_flush);
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TARGET,
+      g_param_spec_enum ("target", "Target",
+          "Optimize for quality or bitrate", GST_TYPE_LAMEMP3ENC_TARGET,
+          DEFAULT_TARGET,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
+      g_param_spec_int ("bitrate", "Bitrate (kb/s)",
+          "Bitrate in kbit/sec (Only valid if target is bitrate, for CBR one "
+          "of 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, "
+          "256 or 320)", 8, 320, DEFAULT_BITRATE,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CBR,
+      g_param_spec_boolean ("cbr", "CBR", "Enforce constant bitrate encoding "
+          "(Only valid if target is bitrate)", DEFAULT_CBR,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
+      g_param_spec_float ("quality", "Quality",
+          "VBR Quality from 0 to 10, 0 being the best "
+          "(Only valid if target is quality)", 0.0, 9.999,
+          DEFAULT_QUALITY,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      ARG_ENCODING_ENGINE_QUALITY, g_param_spec_enum ("encoding-engine-quality",
+          "Encoding Engine Quality", "Quality/speed of the encoding engine, "
+          "this does not affect the bitrate!",
+          GST_TYPE_LAMEMP3ENC_ENCODING_ENGINE_QUALITY,
+          DEFAULT_ENCODING_ENGINE_QUALITY,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MONO,
+      g_param_spec_boolean ("mono", "Mono", "Enforce mono encoding",
+          DEFAULT_MONO,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_lamemp3enc_init (GstLameMP3Enc * lame)
+{
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (lame));
+}
+
+static gboolean
+gst_lamemp3enc_start (GstAudioEncoder * enc)
+{
+  GstLameMP3Enc *lame = GST_LAMEMP3ENC (enc);
+
+  GST_DEBUG_OBJECT (lame, "start");
+
+  if (!lame->adapter)
+    lame->adapter = gst_adapter_new ();
+  gst_adapter_clear (lame->adapter);
+
+  return TRUE;
+}
+
+static gboolean
+gst_lamemp3enc_stop (GstAudioEncoder * enc)
+{
+  GstLameMP3Enc *lame = GST_LAMEMP3ENC (enc);
+
+  GST_DEBUG_OBJECT (lame, "stop");
+
+  if (lame->adapter) {
+    g_object_unref (lame->adapter);
+    lame->adapter = NULL;
+  }
+
+  gst_lamemp3enc_release_memory (lame);
+  return TRUE;
+}
+
+static gboolean
+gst_lamemp3enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
+{
+  GstLameMP3Enc *lame;
+  gint out_samplerate;
+  gint version;
+  GstCaps *othercaps;
+  GstClockTime latency;
+  GstTagList *tags = NULL;
+
+  lame = GST_LAMEMP3ENC (enc);
+
+  /* parameters already parsed for us */
+  lame->samplerate = GST_AUDIO_INFO_RATE (info);
+  lame->num_channels = GST_AUDIO_INFO_CHANNELS (info);
+
+  /* but we might be asked to reconfigure, so reset */
+  gst_lamemp3enc_release_memory (lame);
+
+  GST_DEBUG_OBJECT (lame, "setting up lame");
+  if (!gst_lamemp3enc_setup (lame, &tags))
+    goto setup_failed;
+
+  out_samplerate = lame_get_out_samplerate (lame->lgf);
+  if (out_samplerate == 0)
+    goto zero_output_rate;
+  if (out_samplerate != lame->samplerate) {
+    GST_WARNING_OBJECT (lame,
+        "output samplerate %d is different from incoming samplerate %d",
+        out_samplerate, lame->samplerate);
+  }
+  lame->out_samplerate = out_samplerate;
+
+  version = lame_get_version (lame->lgf);
+  if (version == 0)
+    version = 2;
+  else if (version == 1)
+    version = 1;
+  else if (version == 2)
+    version = 3;
+
+  othercaps =
+      gst_caps_new_simple ("audio/mpeg",
+      "mpegversion", G_TYPE_INT, 1,
+      "mpegaudioversion", G_TYPE_INT, version,
+      "layer", G_TYPE_INT, 3,
+      "channels", G_TYPE_INT, lame->mono ? 1 : lame->num_channels,
+      "rate", G_TYPE_INT, out_samplerate, NULL);
+
+  /* and use these caps */
+  gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (enc), othercaps);
+  gst_caps_unref (othercaps);
+
+  /* base class feedback:
+   * - we will handle buffers, just hand us all available
+   * - report latency */
+  latency = gst_util_uint64_scale_int (lame_get_framesize (lame->lgf),
+      GST_SECOND, lame->samplerate);
+  gst_audio_encoder_set_latency (enc, latency, latency);
+
+  if (tags) {
+    gst_audio_encoder_merge_tags (enc, tags, GST_TAG_MERGE_REPLACE);
+    gst_tag_list_unref (tags);
+  }
+
+  return TRUE;
+
+zero_output_rate:
+  {
+    if (tags)
+      gst_tag_list_unref (tags);
+    GST_ELEMENT_ERROR (lame, LIBRARY, SETTINGS, (NULL),
+        ("LAME mp3 audio decided on a zero sample rate"));
+    return FALSE;
+  }
+setup_failed:
+  {
+    GST_ELEMENT_ERROR (lame, LIBRARY, SETTINGS,
+        (_("Failed to configure LAME mp3 audio encoder. Check your encoding parameters.")), (NULL));
+    return FALSE;
+  }
+}
+
+/* <php-emulation-mode>three underscores for ___rate is really really really
+ * private as opposed to one underscore<php-emulation-mode> */
+/* call this MACRO outside of the NULL state so that we have a higher chance
+ * of actually having a pipeline and bus to get the message through */
+
+#define CHECK_AND_FIXUP_BITRATE(obj,param,rate)		 		  \
+G_STMT_START {                                                            \
+  gint ___rate = rate;                                                    \
+  gint maxrate = 320;							  \
+  gint multiplier = 64;							  \
+  if (rate == 0) {                                                        \
+    ___rate = rate;                                                       \
+  } else if (rate <= 64) {				                  \
+    maxrate = 64; multiplier = 8;                                         \
+    if ((rate % 8) != 0) ___rate = GST_ROUND_UP_8 (rate); 		  \
+  } else if (rate <= 128) {						  \
+    maxrate = 128; multiplier = 16;                                       \
+    if ((rate % 16) != 0) ___rate = GST_ROUND_UP_16 (rate);               \
+  } else if (rate <= 256) {						  \
+    maxrate = 256; multiplier = 32;                                       \
+    if ((rate % 32) != 0) ___rate = GST_ROUND_UP_32 (rate);               \
+  } else if (rate <= 320) { 						  \
+    maxrate = 320; multiplier = 64;                                       \
+    if ((rate % 64) != 0) ___rate = GST_ROUND_UP_64 (rate);               \
+  }                                                                       \
+  if (___rate != rate) {                                                  \
+    GST_ELEMENT_WARNING (obj, LIBRARY, SETTINGS,			  \
+      (_("The requested bitrate %d kbit/s for property '%s' "             \
+       "is not allowed. "  					          \
+       "The bitrate was changed to %d kbit/s."), rate,		          \
+         param,  ___rate), 					          \
+       ("A bitrate below %d should be a multiple of %d.", 		  \
+          maxrate, multiplier));		  			  \
+    rate = ___rate;                                                       \
+  }                                                                       \
+} G_STMT_END
+
+static void
+gst_lamemp3enc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstLameMP3Enc *lame;
+
+  lame = GST_LAMEMP3ENC (object);
+
+  switch (prop_id) {
+    case ARG_TARGET:
+      lame->target = g_value_get_enum (value);
+      break;
+    case ARG_BITRATE:
+      lame->bitrate = g_value_get_int (value);
+      break;
+    case ARG_CBR:
+      lame->cbr = g_value_get_boolean (value);
+      break;
+    case ARG_QUALITY:
+      lame->quality = g_value_get_float (value);
+      break;
+    case ARG_ENCODING_ENGINE_QUALITY:
+      lame->encoding_engine_quality = g_value_get_enum (value);
+      break;
+    case ARG_MONO:
+      lame->mono = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_lamemp3enc_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstLameMP3Enc *lame;
+
+  lame = GST_LAMEMP3ENC (object);
+
+  switch (prop_id) {
+    case ARG_TARGET:
+      g_value_set_enum (value, lame->target);
+      break;
+    case ARG_BITRATE:
+      g_value_set_int (value, lame->bitrate);
+      break;
+    case ARG_CBR:
+      g_value_set_boolean (value, lame->cbr);
+      break;
+    case ARG_QUALITY:
+      g_value_set_float (value, lame->quality);
+      break;
+    case ARG_ENCODING_ENGINE_QUALITY:
+      g_value_set_enum (value, lame->encoding_engine_quality);
+      break;
+    case ARG_MONO:
+      g_value_set_boolean (value, lame->mono);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* **** credits go to mpegaudioparse **** */
+
+static const guint mp3types_bitrates[2][3][16] = {
+  {
+        {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,},
+        {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,},
+        {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,}
+      },
+  {
+        {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,},
+        {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,},
+        {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}
+      },
+};
+
+static const guint mp3types_freqs[3][3] = { {44100, 48000, 32000},
+{22050, 24000, 16000},
+{11025, 12000, 8000}
+};
+
+static inline guint
+mp3_type_frame_length_from_header (GstLameMP3Enc * lame, guint32 header,
+    guint * put_version, guint * put_layer, guint * put_channels,
+    guint * put_bitrate, guint * put_samplerate, guint * put_mode,
+    guint * put_crc)
+{
+  guint length;
+  gulong mode, samplerate, bitrate, layer, channels, padding, crc;
+  gulong version;
+  gint lsf, mpg25;
+
+  if (header & (1 << 20)) {
+    lsf = (header & (1 << 19)) ? 0 : 1;
+    mpg25 = 0;
+  } else {
+    lsf = 1;
+    mpg25 = 1;
+  }
+
+  version = 1 + lsf + mpg25;
+
+  layer = 4 - ((header >> 17) & 0x3);
+
+  crc = (header >> 16) & 0x1;
+
+  bitrate = (header >> 12) & 0xF;
+  bitrate = mp3types_bitrates[lsf][layer - 1][bitrate] * 1000;
+  /* The caller has ensured we have a valid header, so bitrate can't be
+     zero here. */
+  g_assert (bitrate != 0);
+
+  samplerate = (header >> 10) & 0x3;
+  samplerate = mp3types_freqs[lsf + mpg25][samplerate];
+
+  padding = (header >> 9) & 0x1;
+
+  mode = (header >> 6) & 0x3;
+  channels = (mode == 3) ? 1 : 2;
+
+  switch (layer) {
+    case 1:
+      length = 4 * ((bitrate * 12) / samplerate + padding);
+      break;
+    case 2:
+      length = (bitrate * 144) / samplerate + padding;
+      break;
+    default:
+    case 3:
+      length = (bitrate * 144) / (samplerate << lsf) + padding;
+      break;
+  }
+
+  GST_DEBUG_OBJECT (lame, "Calculated mp3 frame length of %u bytes", length);
+  GST_DEBUG_OBJECT (lame, "samplerate = %lu, bitrate = %lu, version = %lu, "
+      "layer = %lu, channels = %lu", samplerate, bitrate, version,
+      layer, channels);
+
+  if (put_version)
+    *put_version = version;
+  if (put_layer)
+    *put_layer = layer;
+  if (put_channels)
+    *put_channels = channels;
+  if (put_bitrate)
+    *put_bitrate = bitrate;
+  if (put_samplerate)
+    *put_samplerate = samplerate;
+  if (put_mode)
+    *put_mode = mode;
+  if (put_crc)
+    *put_crc = crc;
+
+  return length;
+}
+
+static gboolean
+mp3_sync_check (GstLameMP3Enc * lame, unsigned long head)
+{
+  GST_DEBUG_OBJECT (lame, "checking mp3 header 0x%08lx", head);
+  /* if it's not a valid sync */
+  if ((head & 0xffe00000) != 0xffe00000) {
+    GST_WARNING_OBJECT (lame, "invalid sync");
+    return FALSE;
+  }
+  /* if it's an invalid MPEG version */
+  if (((head >> 19) & 3) == 0x1) {
+    GST_WARNING_OBJECT (lame, "invalid MPEG version: 0x%lx", (head >> 19) & 3);
+    return FALSE;
+  }
+  /* if it's an invalid layer */
+  if (!((head >> 17) & 3)) {
+    GST_WARNING_OBJECT (lame, "invalid layer: 0x%lx", (head >> 17) & 3);
+    return FALSE;
+  }
+  /* if it's an invalid bitrate */
+  if (((head >> 12) & 0xf) == 0x0) {
+    GST_WARNING_OBJECT (lame, "invalid bitrate: 0x%lx."
+        "Free format files are not supported yet", (head >> 12) & 0xf);
+    return FALSE;
+  }
+  if (((head >> 12) & 0xf) == 0xf) {
+    GST_WARNING_OBJECT (lame, "invalid bitrate: 0x%lx", (head >> 12) & 0xf);
+    return FALSE;
+  }
+  /* if it's an invalid samplerate */
+  if (((head >> 10) & 0x3) == 0x3) {
+    GST_WARNING_OBJECT (lame, "invalid samplerate: 0x%lx", (head >> 10) & 0x3);
+    return FALSE;
+  }
+
+  if ((head & 0x3) == 0x2) {
+    /* Ignore this as there are some files with emphasis 0x2 that can
+     * be played fine. See BGO #537235 */
+    GST_WARNING_OBJECT (lame, "invalid emphasis: 0x%lx", head & 0x3);
+  }
+
+  return TRUE;
+}
+
+/* **** end mpegaudioparse **** */
+
+static GstFlowReturn
+gst_lamemp3enc_finish_frames (GstLameMP3Enc * lame)
+{
+  gint av;
+  guint header;
+  GstFlowReturn result = GST_FLOW_OK;
+
+  /* limited parsing, we don't expect to lose sync here */
+  while ((result == GST_FLOW_OK) &&
+      ((av = gst_adapter_available (lame->adapter)) > 4)) {
+    guint rate, version, layer, size;
+    GstBuffer *mp3_buf;
+    const guint8 *data;
+    guint samples_per_frame;
+
+    data = gst_adapter_map (lame->adapter, 4);
+    header = GST_READ_UINT32_BE (data);
+    gst_adapter_unmap (lame->adapter);
+
+    if (!mp3_sync_check (lame, header))
+      goto invalid_header;
+
+    size = mp3_type_frame_length_from_header (lame, header, &version, &layer,
+        NULL, NULL, &rate, NULL, NULL);
+
+    if (G_UNLIKELY (layer != 3 || rate != lame->out_samplerate)) {
+      GST_DEBUG_OBJECT (lame,
+          "unexpected mp3 header with rate %u, version %u, layer %u",
+          rate, version, layer);
+      goto invalid_header;
+    }
+
+    if (size > av) {
+      /* pretty likely to occur when lame is holding back on us */
+      GST_LOG_OBJECT (lame, "frame size %u (> %d)", size, av);
+      break;
+    }
+
+    /* Account for the internal resampling, finish frame really wants to
+     * know about the number of incoming samples
+     */
+    samples_per_frame = (version == 1) ? 1152 : 576;
+    samples_per_frame *= lame->samplerate;
+    samples_per_frame /= lame->out_samplerate;
+
+    /* should be ok now */
+    mp3_buf = gst_adapter_take_buffer (lame->adapter, size);
+    /* number of samples for MPEG-1, layer 3 */
+    result = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (lame),
+        mp3_buf, samples_per_frame);
+  }
+
+exit:
+  return result;
+
+  /* ERRORS */
+invalid_header:
+  {
+    GST_ELEMENT_ERROR (lame, STREAM, ENCODE,
+        ("invalid lame mp3 sync header %08X", header), (NULL));
+    result = GST_FLOW_ERROR;
+    goto exit;
+  }
+}
+
+static GstFlowReturn
+gst_lamemp3enc_flush_full (GstLameMP3Enc * lame, gboolean push)
+{
+  GstBuffer *buf;
+  GstMapInfo map;
+  gint size;
+  GstFlowReturn result = GST_FLOW_OK;
+  gint av;
+
+  if (!lame->lgf)
+    return GST_FLOW_OK;
+
+  buf = gst_buffer_new_and_alloc (7200);
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  size = lame_encode_flush (lame->lgf, map.data, 7200);
+
+  if (size > 0) {
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_resize (buf, 0, size);
+    GST_DEBUG_OBJECT (lame, "collecting final %d bytes", size);
+    gst_adapter_push (lame->adapter, buf);
+  } else {
+    gst_buffer_unmap (buf, &map);
+    GST_DEBUG_OBJECT (lame, "no final packet (size=%d, push=%d)", size, push);
+    gst_buffer_unref (buf);
+    result = GST_FLOW_OK;
+  }
+
+  if (push) {
+    result = gst_lamemp3enc_finish_frames (lame);
+  } else {
+    /* never mind */
+    gst_adapter_clear (lame->adapter);
+  }
+
+  /* either way, we expect nothing left */
+  if ((av = gst_adapter_available (lame->adapter))) {
+    /* should this be more fatal ?? */
+    GST_WARNING_OBJECT (lame, "unparsed %d bytes left after flushing", av);
+    /* clean up anyway */
+    gst_adapter_clear (lame->adapter);
+  }
+
+  return result;
+}
+
+static void
+gst_lamemp3enc_flush (GstAudioEncoder * enc)
+{
+  gst_lamemp3enc_flush_full (GST_LAMEMP3ENC (enc), FALSE);
+}
+
+static GstFlowReturn
+gst_lamemp3enc_handle_frame (GstAudioEncoder * enc, GstBuffer * in_buf)
+{
+  GstLameMP3Enc *lame;
+  gint mp3_buffer_size, mp3_size;
+  GstBuffer *mp3_buf;
+  GstFlowReturn result;
+  gint num_samples;
+  GstMapInfo in_map, mp3_map;
+
+  lame = GST_LAMEMP3ENC (enc);
+
+  /* squeeze remaining and push */
+  if (G_UNLIKELY (in_buf == NULL))
+    return gst_lamemp3enc_flush_full (lame, TRUE);
+
+  gst_buffer_map (in_buf, &in_map, GST_MAP_READ);
+
+  num_samples = in_map.size / 2;
+
+  /* allocate space for output */
+  mp3_buffer_size = 1.25 * num_samples + 7200;
+  mp3_buf = gst_buffer_new_allocate (NULL, mp3_buffer_size, NULL);
+  gst_buffer_map (mp3_buf, &mp3_map, GST_MAP_WRITE);
+
+  /* lame seems to be too stupid to get mono interleaved going */
+  if (lame->num_channels == 1) {
+    mp3_size = lame_encode_buffer (lame->lgf,
+        (short int *) in_map.data,
+        (short int *) in_map.data, num_samples, mp3_map.data, mp3_buffer_size);
+  } else {
+    mp3_size = lame_encode_buffer_interleaved (lame->lgf,
+        (short int *) in_map.data,
+        num_samples / lame->num_channels, mp3_map.data, mp3_buffer_size);
+  }
+  gst_buffer_unmap (in_buf, &in_map);
+
+  GST_LOG_OBJECT (lame, "encoded %" G_GSIZE_FORMAT " bytes of audio "
+      "to %d bytes of mp3", in_map.size, mp3_size);
+
+  if (G_LIKELY (mp3_size > 0)) {
+    /* unfortunately lame does not provide frame delineated output,
+     * so collect output and parse into frames ... */
+    gst_buffer_unmap (mp3_buf, &mp3_map);
+    gst_buffer_resize (mp3_buf, 0, mp3_size);
+    gst_adapter_push (lame->adapter, mp3_buf);
+    result = gst_lamemp3enc_finish_frames (lame);
+  } else {
+    gst_buffer_unmap (mp3_buf, &mp3_map);
+    if (mp3_size < 0) {
+      /* eat error ? */
+      g_warning ("error %d", mp3_size);
+    }
+    gst_buffer_unref (mp3_buf);
+    result = GST_FLOW_OK;
+  }
+
+  return result;
+}
+
+/* set up the encoder state */
+static gboolean
+gst_lamemp3enc_setup (GstLameMP3Enc * lame, GstTagList ** tags)
+{
+  gboolean res;
+
+#define CHECK_ERROR(command) G_STMT_START {\
+  if ((command) < 0) { \
+    GST_ERROR_OBJECT (lame, "setup failed: " G_STRINGIFY (command)); \
+    if (*tags) { \
+      gst_tag_list_unref (*tags); \
+      *tags = NULL; \
+    } \
+    return FALSE; \
+  } \
+}G_STMT_END
+
+  int retval;
+  GstCaps *allowed_caps;
+
+  GST_DEBUG_OBJECT (lame, "starting setup");
+
+  lame->lgf = lame_init ();
+
+  if (lame->lgf == NULL)
+    return FALSE;
+
+  *tags = gst_tag_list_new_empty ();
+
+  /* copy the parameters over */
+  lame_set_in_samplerate (lame->lgf, lame->samplerate);
+
+  /* let lame choose default samplerate unless outgoing sample rate is fixed */
+  allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (lame));
+
+  if (allowed_caps != NULL) {
+    GstStructure *structure;
+    gint samplerate;
+
+    structure = gst_caps_get_structure (allowed_caps, 0);
+
+    if (gst_structure_get_int (structure, "rate", &samplerate)) {
+      GST_DEBUG_OBJECT (lame, "Setting sample rate to %d as fixed in src caps",
+          samplerate);
+      lame_set_out_samplerate (lame->lgf, samplerate);
+    } else {
+      GST_DEBUG_OBJECT (lame, "Letting lame choose sample rate");
+      lame_set_out_samplerate (lame->lgf, 0);
+    }
+    gst_caps_unref (allowed_caps);
+    allowed_caps = NULL;
+  } else {
+    GST_DEBUG_OBJECT (lame, "No peer yet, letting lame choose sample rate");
+    lame_set_out_samplerate (lame->lgf, 0);
+  }
+
+  CHECK_ERROR (lame_set_num_channels (lame->lgf, lame->num_channels));
+  CHECK_ERROR (lame_set_bWriteVbrTag (lame->lgf, 0));
+
+  if (lame->target == LAMEMP3ENC_TARGET_QUALITY) {
+    CHECK_ERROR (lame_set_VBR (lame->lgf, vbr_default));
+    CHECK_ERROR (lame_set_VBR_quality (lame->lgf, lame->quality));
+  } else {
+    if (lame->cbr) {
+      CHECK_AND_FIXUP_BITRATE (lame, "bitrate", lame->bitrate);
+      CHECK_ERROR (lame_set_VBR (lame->lgf, vbr_off));
+      CHECK_ERROR (lame_set_brate (lame->lgf, lame->bitrate));
+    } else {
+      CHECK_ERROR (lame_set_VBR (lame->lgf, vbr_abr));
+      CHECK_ERROR (lame_set_VBR_mean_bitrate_kbps (lame->lgf, lame->bitrate));
+    }
+    gst_tag_list_add (*tags, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
+        lame->bitrate * 1000, NULL);
+  }
+
+  if (lame->encoding_engine_quality == LAMEMP3ENC_ENCODING_ENGINE_QUALITY_FAST)
+    CHECK_ERROR (lame_set_quality (lame->lgf, 7));
+  else if (lame->encoding_engine_quality ==
+      LAMEMP3ENC_ENCODING_ENGINE_QUALITY_HIGH)
+    CHECK_ERROR (lame_set_quality (lame->lgf, 2));
+  /* else default */
+
+  if (lame->mono)
+    CHECK_ERROR (lame_set_mode (lame->lgf, MONO));
+
+  /* initialize the lame encoder */
+  if ((retval = lame_init_params (lame->lgf)) >= 0) {
+    /* FIXME: it would be nice to print out the mode here */
+    GST_INFO
+        ("lame encoder setup (target %s, quality %f, bitrate %d, %d Hz, %d channels)",
+        (lame->target == LAMEMP3ENC_TARGET_QUALITY) ? "quality" : "bitrate",
+        lame->quality, lame->bitrate, lame->samplerate, lame->num_channels);
+    res = TRUE;
+  } else {
+    GST_ERROR_OBJECT (lame, "lame_init_params returned %d", retval);
+    res = FALSE;
+  }
+
+  GST_DEBUG_OBJECT (lame, "done with setup");
+  return res;
+#undef CHECK_ERROR
+}
+
+gboolean
+gst_lamemp3enc_register (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (debug, "lamemp3enc", 0, "lame mp3 encoder");
+
+  if (!gst_element_register (plugin, "lamemp3enc", GST_RANK_PRIMARY,
+          GST_TYPE_LAMEMP3ENC))
+    return FALSE;
+
+  return TRUE;
+}
diff --git a/ext/lame/gstlamemp3enc.h b/ext/lame/gstlamemp3enc.h
new file mode 100644
index 0000000..25dbc46
--- /dev/null
+++ b/ext/lame/gstlamemp3enc.h
@@ -0,0 +1,83 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_LAMEMP3ENC_H__
+#define __GST_LAMEMP3ENC_H__
+
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudioencoder.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#include <lame/lame.h>
+
+#define GST_TYPE_LAMEMP3ENC \
+  (gst_lamemp3enc_get_type())
+#define GST_LAMEMP3ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_LAMEMP3ENC,GstLameMP3Enc))
+#define GST_LAMEMP3ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_LAMEMP3ENC,GstLameMP3EncClass))
+#define GST_IS_LAMEMP3ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_LAMEMP3ENC))
+#define GST_IS_LAMEMP3ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_LAMEMP3ENC))
+
+typedef struct _GstLameMP3Enc GstLameMP3Enc;
+typedef struct _GstLameMP3EncClass GstLameMP3EncClass;
+
+/**
+ * GstLameMP3Enc:
+ *
+ * Opaque data structure.
+ */
+struct _GstLameMP3Enc {
+  GstAudioEncoder element;
+
+  /*< private >*/
+  gint samplerate;
+  gint out_samplerate;
+  gint num_channels;
+
+  /* properties */
+  gint target;
+  gint bitrate;
+  gboolean cbr;
+  gfloat quality;
+  gint encoding_engine_quality;
+  gboolean mono;
+
+  lame_global_flags *lgf;
+
+  GstAdapter *adapter;
+};
+
+struct _GstLameMP3EncClass {
+  GstAudioEncoderClass parent_class;
+};
+
+GType gst_lamemp3enc_get_type(void);
+gboolean gst_lamemp3enc_register (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_LAMEMP3ENC_H__ */
diff --git a/ext/lame/meson.build b/ext/lame/meson.build
new file mode 100644
index 0000000..e3e61b6
--- /dev/null
+++ b/ext/lame/meson.build
@@ -0,0 +1,19 @@
+lame_dep = cc.find_library('mp3lame', required : false)
+
+if lame_dep.found() and cc.has_header_symbol('lame/lame.h', 'lame_init')
+  lame_extra_c_args = []
+  if cc.has_header_symbol('lame/lame.h', 'lame_set_VBR_quality')
+    lame_extra_c_args += ['-DHAVE_LAME_SET_VBR_QUALITY']
+  endif
+  if cc.has_header_symbol('lame/lame.h', 'MEDIUM')
+    lame_extra_c_args += ['-DGSTLAME_PRESET']
+  endif
+  lame = library('gstlame',
+    ['gstlamemp3enc.c', 'plugin.c'],
+    c_args : gst_plugins_good_args + lame_extra_c_args,
+    include_directories : [configinc, libsinc],
+    dependencies : [gstaudio_dep, lame_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/ext/lame/plugin.c b/ext/lame/plugin.c
new file mode 100644
index 0000000..6aae21e
--- /dev/null
+++ b/ext/lame/plugin.c
@@ -0,0 +1,44 @@
+/* GStreamer
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/gst-i18n-plugin.h>
+
+#include "gstlamemp3enc.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+#ifdef ENABLE_NLS
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif /* ENABLE_NLS */
+
+  return gst_lamemp3enc_register (plugin);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    lame,
+    "Encode MP3s with LAME",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/ext/libcaca/Makefile.am b/ext/libcaca/Makefile.am
new file mode 100644
index 0000000..93371e3
--- /dev/null
+++ b/ext/libcaca/Makefile.am
@@ -0,0 +1,17 @@
+plugin_LTLIBRARIES = libgstcacasink.la
+
+libgstcacasink_la_SOURCES = gstcacasink.c
+libgstcacasink_la_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS) \
+	$(LIBCACA_CFLAGS)
+libgstcacasink_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) \
+	-lgstvideo-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) \
+	$(GST_LIBS) \
+	$(LIBCACA_LIBS)
+libgstcacasink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstcacasink.h
diff --git a/ext/libcaca/gstcacasink.c b/ext/libcaca/gstcacasink.c
new file mode 100644
index 0000000..40fb52a
--- /dev/null
+++ b/ext/libcaca/gstcacasink.c
@@ -0,0 +1,419 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-cacasink
+ * @see_also: #GstAASink
+ *
+ * Displays video as color ascii art.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * CACA_GEOMETRY=160x60 CACA_FONT=5x7 gst-launch-1.0 filesrc location=test.avi ! decodebin ! videoconvert ! cacasink
+ * ]| This pipeline renders a video to ascii art into a separate window using a
+ * small font and specifying the ascii resolution.
+ * |[
+ * CACA_DRIVER=ncurses gst-launch-1.0 filesrc location=test.avi ! decodebin ! videoconvert ! cacasink
+ * ]| This pipeline renders a video to ascii art into the current terminal.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include "gstcacasink.h"
+
+
+//#define GST_CACA_DEFAULT_RED_MASK R_MASK_32_REVERSE_INT
+//#define GST_CACA_DEFAULT_GREEN_MASK G_MASK_32_REVERSE_INT
+//#define GST_CACA_DEFAULT_BLUE_MASK B_MASK_32_REVERSE_INT
+
+/* cacasink signals and args */
+enum
+{
+  LAST_SIGNAL
+};
+
+#define GST_CACA_DEFAULT_SCREEN_WIDTH 80
+#define GST_CACA_DEFAULT_SCREEN_HEIGHT 25
+#define GST_CACA_DEFAULT_DITHER CACA_DITHERING_NONE
+#define GST_CACA_DEFAULT_ANTIALIASING TRUE
+
+enum
+{
+  PROP_0,
+  PROP_SCREEN_WIDTH,
+  PROP_SCREEN_HEIGHT,
+  PROP_DITHER,
+  PROP_ANTIALIASING
+};
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
+        ("{ RGB, BGR, RGBx, xRGB, BGRx, xBGR, RGB16, RGB15 }"))
+    );
+
+static gboolean gst_cacasink_setcaps (GstBaseSink * pad, GstCaps * caps);
+static void gst_cacasink_get_times (GstBaseSink * sink, GstBuffer * buffer,
+    GstClockTime * start, GstClockTime * end);
+static GstFlowReturn gst_cacasink_render (GstBaseSink * basesink,
+    GstBuffer * buffer);
+
+static void gst_cacasink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_cacasink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn gst_cacasink_change_state (GstElement * element,
+    GstStateChange transition);
+
+#define gst_cacasink_parent_class parent_class
+G_DEFINE_TYPE (GstCACASink, gst_cacasink, GST_TYPE_BASE_SINK);
+
+#define GST_TYPE_CACADITHER (gst_cacasink_dither_get_type())
+static GType
+gst_cacasink_dither_get_type (void)
+{
+  static GType dither_type = 0;
+
+  static const GEnumValue dither_types[] = {
+    {CACA_DITHERING_NONE, "No dithering", "none"},
+    {CACA_DITHERING_ORDERED2, "Ordered 2x2 Bayer dithering", "2x2"},
+    {CACA_DITHERING_ORDERED4, "Ordered 4x4 Bayer dithering", "4x4"},
+    {CACA_DITHERING_ORDERED8, "Ordered 8x8 Bayer dithering", "8x8"},
+    {CACA_DITHERING_RANDOM, "Random dithering", "random"},
+    {0, NULL, NULL},
+  };
+
+  if (!dither_type) {
+    dither_type = g_enum_register_static ("GstCACASinkDithering", dither_types);
+  }
+  return dither_type;
+}
+
+static void
+gst_cacasink_class_init (GstCACASinkClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSinkClass *gstbasesink_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesink_class = (GstBaseSinkClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->set_property = gst_cacasink_set_property;
+  gobject_class->get_property = gst_cacasink_get_property;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SCREEN_WIDTH,
+      g_param_spec_int ("screen-width", "Screen Width",
+          "The width of the screen", 0, G_MAXINT, GST_CACA_DEFAULT_SCREEN_WIDTH,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SCREEN_HEIGHT,
+      g_param_spec_int ("screen-height", "Screen Height",
+          "The height of the screen", 0, G_MAXINT,
+          GST_CACA_DEFAULT_SCREEN_HEIGHT,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DITHER,
+      g_param_spec_enum ("dither", "Dither Type", "Set type of Dither",
+          GST_TYPE_CACADITHER, GST_CACA_DEFAULT_DITHER,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ANTIALIASING,
+      g_param_spec_boolean ("anti-aliasing", "Anti Aliasing",
+          "Enables Anti-Aliasing", GST_CACA_DEFAULT_ANTIALIASING,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->change_state = gst_cacasink_change_state;
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "A colored ASCII art video sink", "Sink/Video",
+      "A colored ASCII art videosink", "Zeeshan Ali <zak147@yahoo.com>");
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+
+  gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_cacasink_setcaps);
+  gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_cacasink_get_times);
+  gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_cacasink_render);
+  gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_cacasink_render);
+}
+
+static void
+gst_cacasink_get_times (GstBaseSink * sink, GstBuffer * buffer,
+    GstClockTime * start, GstClockTime * end)
+{
+  *start = GST_BUFFER_TIMESTAMP (buffer);
+  *end = *start + GST_BUFFER_DURATION (buffer);
+}
+
+static gboolean
+gst_cacasink_setcaps (GstBaseSink * basesink, GstCaps * caps)
+{
+  GstCACASink *cacasink;
+  GstVideoInfo info;
+  guint bpp, red_mask, green_mask, blue_mask;
+
+  cacasink = GST_CACASINK (basesink);
+
+  if (!gst_video_info_from_caps (&info, caps))
+    goto caps_error;
+
+  switch (GST_VIDEO_INFO_FORMAT (&info)) {
+    case GST_VIDEO_FORMAT_RGB:
+    case GST_VIDEO_FORMAT_BGR:
+    case GST_VIDEO_FORMAT_RGBx:
+    case GST_VIDEO_FORMAT_xRGB:
+    case GST_VIDEO_FORMAT_BGRx:
+    case GST_VIDEO_FORMAT_xBGR:
+      bpp = 8 * info.finfo->pixel_stride[0];
+      red_mask = 0xff << (8 * info.finfo->poffset[GST_VIDEO_COMP_R]);
+      green_mask = 0xff << (8 * info.finfo->poffset[GST_VIDEO_COMP_G]);
+      blue_mask = 0xff << (8 * info.finfo->poffset[GST_VIDEO_COMP_B]);
+      break;
+    case GST_VIDEO_FORMAT_RGB16:
+      bpp = 16;
+      red_mask = 0xf800;
+      green_mask = 0x07e0;
+      blue_mask = 0x001f;
+      break;
+    case GST_VIDEO_FORMAT_RGB15:
+      bpp = 16;
+      red_mask = 0x7c00;
+      green_mask = 0x03e0;
+      blue_mask = 0x001f;
+      break;
+    default:
+      goto invalid_format;
+  }
+
+  if (cacasink->bitmap) {
+    caca_free_bitmap (cacasink->bitmap);
+  }
+  cacasink->bitmap = caca_create_bitmap (bpp,
+      GST_VIDEO_INFO_WIDTH (&info),
+      GST_VIDEO_INFO_HEIGHT (&info),
+      GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * bpp / 8),
+      red_mask, green_mask, blue_mask, 0);
+  if (!cacasink->bitmap)
+    goto no_bitmap;
+
+  cacasink->info = info;
+
+  return TRUE;
+
+  /* ERROS */
+caps_error:
+  {
+    GST_ERROR_OBJECT (cacasink, "error parsing caps");
+    return FALSE;
+  }
+invalid_format:
+  {
+    GST_ERROR_OBJECT (cacasink, "invalid format");
+    return FALSE;
+  }
+no_bitmap:
+  {
+    GST_ERROR_OBJECT (cacasink, "could not create bitmap");
+    return FALSE;
+  }
+}
+
+static void
+gst_cacasink_init (GstCACASink * cacasink)
+{
+  cacasink->screen_width = GST_CACA_DEFAULT_SCREEN_WIDTH;
+  cacasink->screen_height = GST_CACA_DEFAULT_SCREEN_HEIGHT;
+
+  cacasink->dither = GST_CACA_DEFAULT_DITHER;
+  cacasink->antialiasing = GST_CACA_DEFAULT_ANTIALIASING;
+}
+
+static GstFlowReturn
+gst_cacasink_render (GstBaseSink * basesink, GstBuffer * buffer)
+{
+  GstCACASink *cacasink = GST_CACASINK (basesink);
+  GstVideoFrame frame;
+
+  GST_DEBUG ("render");
+
+  if (!gst_video_frame_map (&frame, &cacasink->info, buffer, GST_MAP_READ))
+    goto invalid_frame;
+
+  caca_clear ();
+  caca_draw_bitmap (0, 0, cacasink->screen_width - 1,
+      cacasink->screen_height - 1, cacasink->bitmap,
+      GST_VIDEO_FRAME_PLANE_DATA (&frame, 0));
+  caca_refresh ();
+
+  gst_video_frame_unmap (&frame);
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+invalid_frame:
+  {
+    GST_ERROR_OBJECT (cacasink, "invalid frame received");
+    return GST_FLOW_ERROR;
+  }
+}
+
+static void
+gst_cacasink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstCACASink *cacasink;
+
+  g_return_if_fail (GST_IS_CACASINK (object));
+
+  cacasink = GST_CACASINK (object);
+
+  switch (prop_id) {
+    case PROP_DITHER:{
+      cacasink->dither = g_value_get_enum (value);
+      caca_set_dithering (cacasink->dither + CACA_DITHERING_NONE);
+      break;
+    }
+    case PROP_ANTIALIASING:{
+      cacasink->antialiasing = g_value_get_boolean (value);
+      if (cacasink->antialiasing) {
+        caca_set_feature (CACA_ANTIALIASING_MAX);
+      } else {
+        caca_set_feature (CACA_ANTIALIASING_MIN);
+      }
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+static void
+gst_cacasink_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstCACASink *cacasink;
+
+  cacasink = GST_CACASINK (object);
+
+  switch (prop_id) {
+    case PROP_SCREEN_WIDTH:{
+      g_value_set_int (value, cacasink->screen_width);
+      break;
+    }
+    case PROP_SCREEN_HEIGHT:{
+      g_value_set_int (value, cacasink->screen_height);
+      break;
+    }
+    case PROP_DITHER:{
+      g_value_set_enum (value, cacasink->dither);
+      break;
+    }
+    case PROP_ANTIALIASING:{
+      g_value_set_boolean (value, cacasink->antialiasing);
+      break;
+    }
+    default:{
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+  }
+}
+
+static gboolean
+gst_cacasink_open (GstCACASink * cacasink)
+{
+  cacasink->bitmap = NULL;
+
+  if (caca_init () < 0)
+    goto init_failed;
+
+  cacasink->screen_width = caca_get_width ();
+  cacasink->screen_height = caca_get_height ();
+  cacasink->antialiasing = TRUE;
+  caca_set_feature (CACA_ANTIALIASING_MAX);
+  cacasink->dither = 0;
+  caca_set_dithering (CACA_DITHERING_NONE);
+
+  return TRUE;
+
+  /* ERRORS */
+init_failed:
+  {
+    GST_ELEMENT_ERROR (cacasink, RESOURCE, OPEN_WRITE, (NULL),
+        ("caca_init() failed"));
+    return FALSE;
+  }
+}
+
+static void
+gst_cacasink_close (GstCACASink * cacasink)
+{
+  if (cacasink->bitmap) {
+    caca_free_bitmap (cacasink->bitmap);
+    cacasink->bitmap = NULL;
+  }
+  caca_end ();
+}
+
+static GstStateChangeReturn
+gst_cacasink_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      if (!gst_cacasink_open (GST_CACASINK (element)))
+        return GST_STATE_CHANGE_FAILURE;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_cacasink_close (GST_CACASINK (element));
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "cacasink", GST_RANK_NONE,
+          GST_TYPE_CACASINK))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    cacasink,
+    "Colored ASCII Art video sink",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/libcaca/gstcacasink.h b/ext/libcaca/gstcacasink.h
new file mode 100644
index 0000000..327a6a8
--- /dev/null
+++ b/ext/libcaca/gstcacasink.h
@@ -0,0 +1,71 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_CACASINK_H__
+#define __GST_CACASINK_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesink.h>
+#include <gst/video/video.h>
+
+#include <caca.h>
+#ifdef CACA_API_VERSION_1
+#   include <caca0.h>
+#endif
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CACASINK \
+  (gst_cacasink_get_type())
+#define GST_CACASINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CACASINK,GstCACASink))
+#define GST_CACASINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CACASINK,GstCACASinkClass))
+#define GST_IS_CACASINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CACASINK))
+#define GST_IS_CACASINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CACASINK))
+
+typedef struct _GstCACASink GstCACASink;
+typedef struct _GstCACASinkClass GstCACASinkClass;
+
+struct _GstCACASink {
+  GstBaseSink parent;
+
+  GstVideoInfo info;
+  gint screen_width, screen_height;
+
+  guint dither;
+  gboolean antialiasing;
+
+  struct caca_bitmap *bitmap;
+};
+
+struct _GstCACASinkClass {
+  GstBaseSinkClass parent_class;
+
+  /* signals */
+};
+
+GType gst_cacasink_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_CACASINK_H__ */
diff --git a/ext/libcaca/meson.build b/ext/libcaca/meson.build
new file mode 100644
index 0000000..5ff8714
--- /dev/null
+++ b/ext/libcaca/meson.build
@@ -0,0 +1,11 @@
+libcaca_dep = dependency('caca', required : false)
+
+if libcaca_dep.found()
+  library('gstcacasink', 'gstcacasink.c',
+    c_args : gst_plugins_good_args,
+    link_args : noseh_link_args,
+    include_directories : [configinc],
+    dependencies : [gstvideo_dep, gstbase_dep, libcaca_dep],
+    install : true,
+    install_dir : plugins_install_dir)
+endif
diff --git a/ext/libpng/Makefile.am b/ext/libpng/Makefile.am
new file mode 100644
index 0000000..598c8e3
--- /dev/null
+++ b/ext/libpng/Makefile.am
@@ -0,0 +1,9 @@
+plugin_LTLIBRARIES = libgstpng.la
+
+libgstpng_la_SOURCES = gstpng.c gstpngenc.c gstpngdec.c
+libgstpng_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(LIBPNG_CFLAGS)
+libgstpng_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_API_VERSION@ \
+	$(GST_BASE_LIBS) $(GST_LIBS) $(LIBPNG_LIBS)
+libgstpng_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstpngdec.h gstpngenc.h
diff --git a/ext/libpng/gstpng.c b/ext/libpng/gstpng.c
new file mode 100644
index 0000000..92ff479
--- /dev/null
+++ b/ext/libpng/gstpng.c
@@ -0,0 +1,47 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * Filter:
+ * Copyright (C) 2000 Donald A. Graft
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <gst/gst.h>
+
+#include "gstpngdec.h"
+#include "gstpngenc.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "pngdec", GST_RANK_PRIMARY,
+          GST_TYPE_PNGDEC))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "pngenc", GST_RANK_PRIMARY,
+          GST_TYPE_PNGENC))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    png,
+    "PNG plugin library", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
+    GST_PACKAGE_ORIGIN)
diff --git a/ext/libpng/gstpng.h b/ext/libpng/gstpng.h
new file mode 100644
index 0000000..1cc8afc
--- /dev/null
+++ b/ext/libpng/gstpng.h
@@ -0,0 +1,25 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * Filter:
+ * Copyright (C) 2000 Donald A. Graft
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <gst/gst.h>
+#include <png.h>
+
+GType gst_pngenc_get_type (void);
+
+extern GstPadTemplate *gst_png_sink_factory ();
+extern GstPadTemplate *gst_png_src_factory ();
diff --git a/ext/libpng/gstpngdec.c b/ext/libpng/gstpngdec.c
new file mode 100644
index 0000000..581e3a9
--- /dev/null
+++ b/ext/libpng/gstpngdec.c
@@ -0,0 +1,708 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2012 Collabora Ltd.
+ *	Author : Edward Hervey <edward@collabora.com>
+ * Copyright (C) 2013 Collabora Ltd.
+ *	Author : Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *	         Olivier Crete <olivier.crete@collabora.com>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+/**
+ * SECTION:element-pngdec
+ *
+ * Decodes png images. If there is no framerate set on sink caps, it sends EOS
+ * after the first picture.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstpngdec.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/base/gstbytereader.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideometa.h>
+#include <gst/video/gstvideopool.h>
+#include <gst/gst-i18n-plugin.h>
+
+GST_DEBUG_CATEGORY_STATIC (pngdec_debug);
+#define GST_CAT_DEFAULT pngdec_debug
+
+static gboolean gst_pngdec_libpng_init (GstPngDec * pngdec);
+
+static GstFlowReturn gst_pngdec_caps_create_and_set (GstPngDec * pngdec);
+
+static gboolean gst_pngdec_start (GstVideoDecoder * decoder);
+static gboolean gst_pngdec_stop (GstVideoDecoder * decoder);
+static gboolean gst_pngdec_flush (GstVideoDecoder * decoder);
+static gboolean gst_pngdec_set_format (GstVideoDecoder * Decoder,
+    GstVideoCodecState * state);
+static GstFlowReturn gst_pngdec_parse (GstVideoDecoder * decoder,
+    GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos);
+static GstFlowReturn gst_pngdec_handle_frame (GstVideoDecoder * decoder,
+    GstVideoCodecFrame * frame);
+static gboolean gst_pngdec_decide_allocation (GstVideoDecoder * decoder,
+    GstQuery * query);
+static gboolean gst_pngdec_sink_event (GstVideoDecoder * bdec,
+    GstEvent * event);
+
+#define parent_class gst_pngdec_parent_class
+G_DEFINE_TYPE (GstPngDec, gst_pngdec, GST_TYPE_VIDEO_DECODER);
+
+static GstStaticPadTemplate gst_pngdec_src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
+        ("{ RGBA, RGB, ARGB64, GRAY8, GRAY16_BE }"))
+    );
+
+static GstStaticPadTemplate gst_pngdec_sink_pad_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("image/png")
+    );
+
+static void
+gst_pngdec_class_init (GstPngDecClass * klass)
+{
+  GstElementClass *element_class = (GstElementClass *) klass;
+  GstVideoDecoderClass *vdec_class = (GstVideoDecoderClass *) klass;
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_pngdec_src_pad_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_pngdec_sink_pad_template);
+  gst_element_class_set_static_metadata (element_class, "PNG image decoder",
+      "Codec/Decoder/Image", "Decode a png video frame to a raw image",
+      "Wim Taymans <wim@fluendo.com>");
+
+  vdec_class->start = gst_pngdec_start;
+  vdec_class->stop = gst_pngdec_stop;
+  vdec_class->flush = gst_pngdec_flush;
+  vdec_class->set_format = gst_pngdec_set_format;
+  vdec_class->parse = gst_pngdec_parse;
+  vdec_class->handle_frame = gst_pngdec_handle_frame;
+  vdec_class->decide_allocation = gst_pngdec_decide_allocation;
+  vdec_class->sink_event = gst_pngdec_sink_event;
+
+  GST_DEBUG_CATEGORY_INIT (pngdec_debug, "pngdec", 0, "PNG image decoder");
+}
+
+static void
+gst_pngdec_init (GstPngDec * pngdec)
+{
+  pngdec->png = NULL;
+  pngdec->info = NULL;
+  pngdec->endinfo = NULL;
+
+  pngdec->color_type = -1;
+
+  pngdec->image_ready = FALSE;
+  pngdec->read_data = 0;
+
+  gst_video_decoder_set_use_default_pad_acceptcaps (GST_VIDEO_DECODER_CAST
+      (pngdec), TRUE);
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_DECODER_SINK_PAD (pngdec));
+}
+
+static void
+user_error_fn (png_structp png_ptr, png_const_charp error_msg)
+{
+  GST_ERROR ("%s", error_msg);
+}
+
+static void
+user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
+{
+  GST_WARNING ("%s", warning_msg);
+}
+
+static void
+user_info_callback (png_structp png_ptr, png_infop info)
+{
+  GstPngDec *pngdec = NULL;
+  GstFlowReturn ret;
+
+  GST_LOG ("info ready");
+
+  pngdec = GST_PNGDEC (png_get_io_ptr (png_ptr));
+  /* Generate the caps and configure */
+  ret = gst_pngdec_caps_create_and_set (pngdec);
+  if (ret != GST_FLOW_OK) {
+    goto beach;
+  }
+
+  /* Allocate output buffer */
+  ret =
+      gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER (pngdec),
+      pngdec->current_frame);
+  if (G_UNLIKELY (ret != GST_FLOW_OK))
+    GST_DEBUG_OBJECT (pngdec, "failed to acquire buffer");
+
+beach:
+  pngdec->ret = ret;
+}
+
+static gboolean
+gst_pngdec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
+{
+  GstPngDec *pngdec = (GstPngDec *) decoder;
+
+  if (pngdec->input_state)
+    gst_video_codec_state_unref (pngdec->input_state);
+  pngdec->input_state = gst_video_codec_state_ref (state);
+
+  /* We'll set format later on */
+
+  return TRUE;
+}
+
+static void
+user_endrow_callback (png_structp png_ptr, png_bytep new_row,
+    png_uint_32 row_num, int pass)
+{
+  GstPngDec *pngdec = NULL;
+
+  pngdec = GST_PNGDEC (png_get_io_ptr (png_ptr));
+
+  /* If buffer_out doesn't exist, it means buffer_alloc failed, which 
+   * will already have set the return code */
+  if (new_row && GST_IS_BUFFER (pngdec->current_frame->output_buffer)) {
+    GstVideoFrame frame;
+    GstBuffer *buffer = pngdec->current_frame->output_buffer;
+    size_t offset;
+    guint8 *data;
+
+    if (!gst_video_frame_map (&frame, &pngdec->output_state->info, buffer,
+            GST_MAP_WRITE)) {
+      pngdec->ret = GST_FLOW_ERROR;
+      return;
+    }
+
+    data = GST_VIDEO_FRAME_COMP_DATA (&frame, 0);
+    offset = row_num * GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0);
+    GST_LOG ("got row %u at pass %d, copying in buffer %p at offset %"
+        G_GSIZE_FORMAT, (guint) row_num, pass,
+        pngdec->current_frame->output_buffer, offset);
+    png_progressive_combine_row (pngdec->png, data + offset, new_row);
+    gst_video_frame_unmap (&frame);
+    pngdec->ret = GST_FLOW_OK;
+  } else
+    pngdec->ret = GST_FLOW_OK;
+}
+
+static void
+user_end_callback (png_structp png_ptr, png_infop info)
+{
+  GstPngDec *pngdec = NULL;
+
+  pngdec = GST_PNGDEC (png_get_io_ptr (png_ptr));
+
+  GST_LOG_OBJECT (pngdec, "and we are done reading this image");
+
+  if (!pngdec->current_frame->output_buffer)
+    return;
+
+  gst_buffer_unmap (pngdec->current_frame->input_buffer,
+      &pngdec->current_frame_map);
+
+  pngdec->ret =
+      gst_video_decoder_finish_frame (GST_VIDEO_DECODER (pngdec),
+      pngdec->current_frame);
+
+  pngdec->image_ready = TRUE;
+}
+
+
+static GstFlowReturn
+gst_pngdec_caps_create_and_set (GstPngDec * pngdec)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  gint bpc = 0, color_type;
+  png_uint_32 width, height;
+  GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
+
+  g_return_val_if_fail (GST_IS_PNGDEC (pngdec), GST_FLOW_ERROR);
+
+  /* Get bits per channel */
+  bpc = png_get_bit_depth (pngdec->png, pngdec->info);
+
+  /* Get Color type */
+  color_type = png_get_color_type (pngdec->png, pngdec->info);
+
+  /* Add alpha channel if 16-bit depth, but not for GRAY images */
+  if ((bpc > 8) && (color_type != PNG_COLOR_TYPE_GRAY)) {
+    png_set_add_alpha (pngdec->png, 0xffff, PNG_FILLER_BEFORE);
+    png_set_swap (pngdec->png);
+  }
+#if 0
+  /* We used to have this HACK to reverse the outgoing bytes, but the problem
+   * that originally required the hack seems to have been in videoconvert's
+   * RGBA descriptions. It doesn't seem needed now that's fixed, but might
+   * still be needed on big-endian systems, I'm not sure. J.S. 6/7/2007 */
+  if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+    png_set_bgr (pngdec->png);
+#endif
+
+  /* Gray scale with alpha channel converted to RGB */
+  if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+    GST_LOG_OBJECT (pngdec,
+        "converting grayscale png with alpha channel to RGB");
+    png_set_gray_to_rgb (pngdec->png);
+  }
+
+  /* Gray scale converted to upscaled to 8 bits */
+  if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
+      (color_type == PNG_COLOR_TYPE_GRAY)) {
+    if (bpc < 8) {              /* Convert to 8 bits */
+      GST_LOG_OBJECT (pngdec, "converting grayscale image to 8 bits");
+#if PNG_LIBPNG_VER < 10400
+      png_set_gray_1_2_4_to_8 (pngdec->png);
+#else
+      png_set_expand_gray_1_2_4_to_8 (pngdec->png);
+#endif
+    }
+  }
+
+  /* Palette converted to RGB */
+  if (color_type == PNG_COLOR_TYPE_PALETTE) {
+    GST_LOG_OBJECT (pngdec, "converting palette png to RGB");
+    png_set_palette_to_rgb (pngdec->png);
+  }
+
+  png_set_interlace_handling (pngdec->png);
+
+  /* Update the info structure */
+  png_read_update_info (pngdec->png, pngdec->info);
+
+  /* Get IHDR header again after transformation settings */
+  png_get_IHDR (pngdec->png, pngdec->info, &width, &height,
+      &bpc, &pngdec->color_type, NULL, NULL, NULL);
+
+  GST_LOG_OBJECT (pngdec, "this is a %dx%d PNG image", (gint) width,
+      (gint) height);
+
+  switch (pngdec->color_type) {
+    case PNG_COLOR_TYPE_RGB:
+      GST_LOG_OBJECT (pngdec, "we have no alpha channel, depth is 24 bits");
+      if (bpc == 8)
+        format = GST_VIDEO_FORMAT_RGB;
+      break;
+    case PNG_COLOR_TYPE_RGB_ALPHA:
+      GST_LOG_OBJECT (pngdec,
+          "we have an alpha channel, depth is 32 or 64 bits");
+      if (bpc == 8)
+        format = GST_VIDEO_FORMAT_RGBA;
+      else if (bpc == 16)
+        format = GST_VIDEO_FORMAT_ARGB64;
+      break;
+    case PNG_COLOR_TYPE_GRAY:
+      GST_LOG_OBJECT (pngdec,
+          "We have an gray image, depth is 8 or 16 (be) bits");
+      if (bpc == 8)
+        format = GST_VIDEO_FORMAT_GRAY8;
+      else if (bpc == 16)
+        format = GST_VIDEO_FORMAT_GRAY16_BE;
+      break;
+    default:
+      break;
+  }
+
+  if (format == GST_VIDEO_FORMAT_UNKNOWN) {
+    GST_ELEMENT_ERROR (pngdec, STREAM, NOT_IMPLEMENTED, (NULL),
+        ("pngdec does not support this color type"));
+    ret = GST_FLOW_NOT_SUPPORTED;
+    goto beach;
+  }
+
+  /* Check if output state changed */
+  if (pngdec->output_state) {
+    GstVideoInfo *info = &pngdec->output_state->info;
+
+    if (width == GST_VIDEO_INFO_WIDTH (info) &&
+        height == GST_VIDEO_INFO_HEIGHT (info) &&
+        GST_VIDEO_INFO_FORMAT (info) == format) {
+      goto beach;
+    }
+    gst_video_codec_state_unref (pngdec->output_state);
+  }
+#ifdef HAVE_LIBPNG_1_5
+  if ((pngdec->color_type & PNG_COLOR_MASK_COLOR)
+      && !(pngdec->color_type & PNG_COLOR_MASK_PALETTE)
+      && png_get_valid (pngdec->png, pngdec->info, PNG_INFO_iCCP)) {
+    png_charp icc_name;
+    png_bytep icc_profile;
+    int icc_compression_type;
+    png_uint_32 icc_proflen = 0;
+    png_uint_32 ret = png_get_iCCP (pngdec->png, pngdec->info, &icc_name,
+        &icc_compression_type, &icc_profile, &icc_proflen);
+
+    if ((ret & PNG_INFO_iCCP)) {
+      gpointer gst_icc_prof = g_memdup (icc_profile, icc_proflen);
+      GstBuffer *tagbuffer = NULL;
+      GstSample *tagsample = NULL;
+      GstTagList *taglist = NULL;
+      GstStructure *info = NULL;
+      GstCaps *caps;
+
+      GST_DEBUG_OBJECT (pngdec, "extracted ICC profile '%s' length=%i",
+          icc_name, (guint32) icc_proflen);
+
+      tagbuffer = gst_buffer_new_wrapped (gst_icc_prof, icc_proflen);
+
+      caps = gst_caps_new_empty_simple ("application/vnd.iccprofile");
+      info = gst_structure_new_empty ("application/vnd.iccprofile");
+
+      if (icc_name)
+        gst_structure_set (info, "icc-name", G_TYPE_STRING, icc_name, NULL);
+
+      tagsample = gst_sample_new (tagbuffer, caps, NULL, info);
+
+      gst_buffer_unref (tagbuffer);
+      gst_caps_unref (caps);
+
+      taglist = gst_tag_list_new_empty ();
+      gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_ATTACHMENT,
+          tagsample, NULL);
+      gst_sample_unref (tagsample);
+
+      gst_video_decoder_merge_tags (GST_VIDEO_DECODER (pngdec), taglist,
+          GST_TAG_MERGE_APPEND);
+      gst_tag_list_unref (taglist);
+    }
+  }
+#endif
+
+  pngdec->output_state =
+      gst_video_decoder_set_output_state (GST_VIDEO_DECODER (pngdec), format,
+      width, height, pngdec->input_state);
+  gst_video_decoder_negotiate (GST_VIDEO_DECODER (pngdec));
+  GST_DEBUG ("Final %d %d", GST_VIDEO_INFO_WIDTH (&pngdec->output_state->info),
+      GST_VIDEO_INFO_HEIGHT (&pngdec->output_state->info));
+
+beach:
+  return ret;
+}
+
+static GstFlowReturn
+gst_pngdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
+{
+  GstPngDec *pngdec = (GstPngDec *) decoder;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  GST_LOG_OBJECT (pngdec, "Got buffer, size=%u",
+      (guint) gst_buffer_get_size (frame->input_buffer));
+
+  /* Let libpng come back here on error */
+  if (setjmp (png_jmpbuf (pngdec->png))) {
+    GST_WARNING_OBJECT (pngdec, "error during decoding");
+    ret = GST_FLOW_ERROR;
+    goto beach;
+  }
+
+  pngdec->current_frame = frame;
+
+  /* Progressive loading of the PNG image */
+  if (!gst_buffer_map (frame->input_buffer, &pngdec->current_frame_map,
+          GST_MAP_READ)) {
+    GST_WARNING_OBJECT (pngdec, "Failed to map input buffer");
+    ret = GST_FLOW_ERROR;
+    goto beach;
+  }
+
+  png_process_data (pngdec->png, pngdec->info,
+      pngdec->current_frame_map.data, pngdec->current_frame_map.size);
+
+  if (pngdec->image_ready) {
+    /* Reset ourselves for the next frame */
+    gst_pngdec_flush (decoder);
+    GST_LOG_OBJECT (pngdec, "setting up callbacks for next frame");
+    png_set_progressive_read_fn (pngdec->png, pngdec,
+        user_info_callback, user_endrow_callback, user_end_callback);
+    pngdec->image_ready = FALSE;
+  } else {
+    /* An error happened and we have to unmap */
+    gst_buffer_unmap (pngdec->current_frame->input_buffer,
+        &pngdec->current_frame_map);
+  }
+
+  ret = pngdec->ret;
+beach:
+
+  return ret;
+}
+
+/* Based on pngparse */
+#define PNG_SIGNATURE G_GUINT64_CONSTANT (0x89504E470D0A1A0A)
+
+static GstFlowReturn
+gst_pngdec_parse (GstVideoDecoder * decoder, GstVideoCodecFrame * frame,
+    GstAdapter * adapter, gboolean at_eos)
+{
+  gsize toadd = 0;
+  GstByteReader reader;
+  gconstpointer data;
+  guint64 signature;
+  gsize size;
+  GstPngDec *pngdec = (GstPngDec *) decoder;
+
+  GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
+
+  /* FIXME : The overhead of using scan_uint32 is massive */
+
+  size = gst_adapter_available (adapter);
+  GST_DEBUG ("Parsing PNG image data (%" G_GSIZE_FORMAT " bytes)", size);
+
+  if (size < 8)
+    goto need_more_data;
+
+  data = gst_adapter_map (adapter, size);
+  gst_byte_reader_init (&reader, data, size);
+
+  if (pngdec->read_data == 0) {
+    if (!gst_byte_reader_peek_uint64_be (&reader, &signature))
+      goto need_more_data;
+
+    if (signature != PNG_SIGNATURE) {
+      for (;;) {
+        guint offset;
+
+        offset = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff,
+            0x89504E47, 0, gst_byte_reader_get_remaining (&reader));
+
+        if (offset == -1) {
+          gst_adapter_flush (adapter,
+              gst_byte_reader_get_remaining (&reader) - 4);
+          goto need_more_data;
+        }
+
+        if (!gst_byte_reader_skip (&reader, offset))
+          goto need_more_data;
+
+        if (!gst_byte_reader_peek_uint64_be (&reader, &signature))
+          goto need_more_data;
+
+        if (signature == PNG_SIGNATURE) {
+          /* We're skipping, go out, we'll be back */
+          gst_adapter_flush (adapter, gst_byte_reader_get_pos (&reader));
+          goto need_more_data;
+        }
+        if (!gst_byte_reader_skip (&reader, 4))
+          goto need_more_data;
+      }
+    }
+    pngdec->read_data = 8;
+  }
+
+  if (!gst_byte_reader_skip (&reader, pngdec->read_data))
+    goto need_more_data;
+
+  for (;;) {
+    guint32 length;
+    guint32 code;
+
+    if (!gst_byte_reader_get_uint32_be (&reader, &length))
+      goto need_more_data;
+    if (!gst_byte_reader_get_uint32_le (&reader, &code))
+      goto need_more_data;
+
+    if (!gst_byte_reader_skip (&reader, length + 4))
+      goto need_more_data;
+
+    if (code == GST_MAKE_FOURCC ('I', 'E', 'N', 'D')) {
+      /* Have complete frame */
+      toadd = gst_byte_reader_get_pos (&reader);
+      GST_DEBUG_OBJECT (decoder, "Have complete frame of size %" G_GSIZE_FORMAT,
+          toadd);
+      pngdec->read_data = 0;
+      goto have_full_frame;
+    } else
+      pngdec->read_data += length + 12;
+  }
+
+  g_assert_not_reached ();
+  return GST_FLOW_ERROR;
+
+need_more_data:
+  return GST_VIDEO_DECODER_FLOW_NEED_DATA;
+
+have_full_frame:
+  if (toadd)
+    gst_video_decoder_add_to_frame (decoder, toadd);
+  return gst_video_decoder_have_frame (decoder);
+}
+
+static gboolean
+gst_pngdec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
+{
+  GstBufferPool *pool = NULL;
+  GstStructure *config;
+
+  if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (bdec, query))
+    return FALSE;
+
+  if (gst_query_get_n_allocation_pools (query) > 0)
+    gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
+
+  if (pool == NULL)
+    return FALSE;
+
+  config = gst_buffer_pool_get_config (pool);
+  if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
+    gst_buffer_pool_config_add_option (config,
+        GST_BUFFER_POOL_OPTION_VIDEO_META);
+  }
+  gst_buffer_pool_set_config (pool, config);
+  gst_object_unref (pool);
+
+  return TRUE;
+}
+
+static gboolean
+gst_pngdec_sink_event (GstVideoDecoder * bdec, GstEvent * event)
+{
+  const GstSegment *segment;
+
+  if (GST_EVENT_TYPE (event) != GST_EVENT_SEGMENT)
+    goto done;
+
+  gst_event_parse_segment (event, &segment);
+
+  if (segment->format == GST_FORMAT_TIME)
+    gst_video_decoder_set_packetized (bdec, TRUE);
+  else
+    gst_video_decoder_set_packetized (bdec, FALSE);
+
+done:
+  return GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (bdec, event);
+}
+
+static gboolean
+gst_pngdec_libpng_init (GstPngDec * pngdec)
+{
+  g_return_val_if_fail (GST_IS_PNGDEC (pngdec), FALSE);
+
+  GST_LOG ("init libpng structures");
+
+  /* initialize png struct stuff */
+  pngdec->png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
+      (png_voidp) NULL, user_error_fn, user_warning_fn);
+
+  if (pngdec->png == NULL)
+    goto init_failed;
+
+  pngdec->info = png_create_info_struct (pngdec->png);
+  if (pngdec->info == NULL)
+    goto info_failed;
+
+  pngdec->endinfo = png_create_info_struct (pngdec->png);
+  if (pngdec->endinfo == NULL)
+    goto endinfo_failed;
+
+  png_set_progressive_read_fn (pngdec->png, pngdec,
+      user_info_callback, user_endrow_callback, user_end_callback);
+
+  return TRUE;
+
+  /* ERRORS */
+init_failed:
+  {
+    GST_ELEMENT_ERROR (pngdec, LIBRARY, INIT, (NULL),
+        ("Failed to initialize png structure"));
+    return FALSE;
+  }
+info_failed:
+  {
+    GST_ELEMENT_ERROR (pngdec, LIBRARY, INIT, (NULL),
+        ("Failed to initialize info structure"));
+    return FALSE;
+  }
+endinfo_failed:
+  {
+    GST_ELEMENT_ERROR (pngdec, LIBRARY, INIT, (NULL),
+        ("Failed to initialize endinfo structure"));
+    return FALSE;
+  }
+}
+
+
+static void
+gst_pngdec_libpng_clear (GstPngDec * pngdec)
+{
+  png_infopp info = NULL, endinfo = NULL;
+
+  GST_LOG ("cleaning up libpng structures");
+
+  if (pngdec->info) {
+    info = &pngdec->info;
+  }
+
+  if (pngdec->endinfo) {
+    endinfo = &pngdec->endinfo;
+  }
+
+  if (pngdec->png) {
+    png_destroy_read_struct (&(pngdec->png), info, endinfo);
+    pngdec->png = NULL;
+    pngdec->info = NULL;
+    pngdec->endinfo = NULL;
+  }
+
+  pngdec->color_type = -1;
+  pngdec->read_data = 0;
+}
+
+static gboolean
+gst_pngdec_start (GstVideoDecoder * decoder)
+{
+  GstPngDec *pngdec = (GstPngDec *) decoder;
+
+  gst_video_decoder_set_packetized (GST_VIDEO_DECODER (pngdec), FALSE);
+  gst_pngdec_libpng_init (pngdec);
+
+  return TRUE;
+}
+
+static gboolean
+gst_pngdec_stop (GstVideoDecoder * decoder)
+{
+  GstPngDec *pngdec = (GstPngDec *) decoder;
+
+  gst_pngdec_libpng_clear (pngdec);
+
+  if (pngdec->input_state) {
+    gst_video_codec_state_unref (pngdec->input_state);
+    pngdec->input_state = NULL;
+  }
+  if (pngdec->output_state) {
+    gst_video_codec_state_unref (pngdec->output_state);
+    pngdec->output_state = NULL;
+  }
+
+  return TRUE;
+}
+
+/* Clean up the libpng structures */
+static gboolean
+gst_pngdec_flush (GstVideoDecoder * decoder)
+{
+  gst_pngdec_libpng_clear ((GstPngDec *) decoder);
+  gst_pngdec_libpng_init ((GstPngDec *) decoder);
+
+  return TRUE;
+}
diff --git a/ext/libpng/gstpngdec.h b/ext/libpng/gstpngdec.h
new file mode 100644
index 0000000..a995851
--- /dev/null
+++ b/ext/libpng/gstpngdec.h
@@ -0,0 +1,71 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2012 Collabora Ltd.
+ *	Author : Edward Hervey <edward@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_PNGDEC_H__
+#define __GST_PNGDEC_H__
+
+#include <gst/gst.h>
+#include <gst/video/gstvideodecoder.h>
+#include <png.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_PNGDEC (gst_pngdec_get_type())
+#define GST_PNGDEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PNGDEC,GstPngDec))
+#define GST_PNGDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PNGDEC,GstPngDecClass))
+#define GST_IS_PNGDEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PNGDEC))
+#define GST_IS_PNGDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PNGDEC))
+
+typedef struct _GstPngDec GstPngDec;
+typedef struct _GstPngDecClass GstPngDecClass;
+
+struct _GstPngDec
+{
+  GstVideoDecoder parent;
+
+  GstVideoCodecState *input_state;
+  GstVideoCodecState *output_state;
+  GstMapInfo current_frame_map;
+  GstVideoCodecFrame *current_frame;
+
+  GstFlowReturn ret;
+
+  png_structp png;
+  png_infop info;
+  png_infop endinfo;
+
+  gint color_type;
+
+  gboolean image_ready;
+  gsize read_data;
+};
+
+struct _GstPngDecClass
+{
+  GstVideoDecoderClass parent_class;
+};
+
+GType gst_pngdec_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_PNGDEC_H__ */
diff --git a/ext/libpng/gstpngenc.c b/ext/libpng/gstpngenc.c
new file mode 100644
index 0000000..e9050b1
--- /dev/null
+++ b/ext/libpng/gstpngenc.c
@@ -0,0 +1,426 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * Filter:
+ * Copyright (C) 2000 Donald A. Graft
+ *
+ * Copyright (C) 2012 Collabora Ltd.
+ *	Author : Edward Hervey <edward@collabora.com>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+/**
+ * SECTION:element-pngenc
+ *
+ * Encodes png images.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideometa.h>
+#include <zlib.h>
+
+#include "gstpngenc.h"
+
+GST_DEBUG_CATEGORY_STATIC (pngenc_debug);
+#define GST_CAT_DEFAULT pngenc_debug
+
+/* Filter signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+#define DEFAULT_SNAPSHOT                FALSE
+#define DEFAULT_COMPRESSION_LEVEL       6
+
+enum
+{
+  ARG_0,
+  ARG_SNAPSHOT,
+  ARG_COMPRESSION_LEVEL
+};
+
+static GstStaticPadTemplate pngenc_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("image/png, "
+        "width = (int) [ 16, 1000000 ], "
+        "height = (int) [ 16, 1000000 ], " "framerate = " GST_VIDEO_FPS_RANGE)
+    );
+
+static GstStaticPadTemplate pngenc_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBA, RGB, GRAY8, GRAY16_BE }"))
+    );
+
+#define parent_class gst_pngenc_parent_class
+G_DEFINE_TYPE (GstPngEnc, gst_pngenc, GST_TYPE_VIDEO_ENCODER);
+
+static void gst_pngenc_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_pngenc_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+static GstFlowReturn gst_pngenc_handle_frame (GstVideoEncoder * encoder,
+    GstVideoCodecFrame * frame);
+static gboolean gst_pngenc_set_format (GstVideoEncoder * encoder,
+    GstVideoCodecState * state);
+static gboolean gst_pngenc_propose_allocation (GstVideoEncoder * encoder,
+    GstQuery * query);
+
+static void gst_pngenc_finalize (GObject * object);
+
+static void
+user_error_fn (png_structp png_ptr, png_const_charp error_msg)
+{
+  g_warning ("%s", error_msg);
+}
+
+static void
+user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
+{
+  g_warning ("%s", warning_msg);
+}
+
+static void
+gst_pngenc_class_init (GstPngEncClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+  GstVideoEncoderClass *venc_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = (GstElementClass *) klass;
+  venc_class = (GstVideoEncoderClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->get_property = gst_pngenc_get_property;
+  gobject_class->set_property = gst_pngenc_set_property;
+
+  g_object_class_install_property (gobject_class, ARG_SNAPSHOT,
+      g_param_spec_boolean ("snapshot", "Snapshot",
+          "Send EOS after encoding a frame, useful for snapshots",
+          DEFAULT_SNAPSHOT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, ARG_COMPRESSION_LEVEL,
+      g_param_spec_uint ("compression-level", "compression-level",
+          "PNG compression level",
+          Z_NO_COMPRESSION, Z_BEST_COMPRESSION,
+          DEFAULT_COMPRESSION_LEVEL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template
+      (element_class, &pngenc_sink_template);
+  gst_element_class_add_static_pad_template
+      (element_class, &pngenc_src_template);
+  gst_element_class_set_static_metadata (element_class, "PNG image encoder",
+      "Codec/Encoder/Image",
+      "Encode a video frame to a .png image",
+      "Jeremy SIMON <jsimon13@yahoo.fr>");
+
+  venc_class->set_format = gst_pngenc_set_format;
+  venc_class->handle_frame = gst_pngenc_handle_frame;
+  venc_class->propose_allocation = gst_pngenc_propose_allocation;
+  gobject_class->finalize = gst_pngenc_finalize;
+
+  GST_DEBUG_CATEGORY_INIT (pngenc_debug, "pngenc", 0, "PNG image encoder");
+}
+
+
+static gboolean
+gst_pngenc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state)
+{
+  GstPngEnc *pngenc;
+  gboolean ret = TRUE;
+  GstVideoInfo *info;
+  GstVideoCodecState *output_state;
+
+  pngenc = GST_PNGENC (encoder);
+  info = &state->info;
+
+  switch (GST_VIDEO_INFO_FORMAT (info)) {
+    case GST_VIDEO_FORMAT_RGBA:
+      pngenc->png_color_type = PNG_COLOR_TYPE_RGBA;
+      break;
+    case GST_VIDEO_FORMAT_RGB:
+      pngenc->png_color_type = PNG_COLOR_TYPE_RGB;
+      break;
+    case GST_VIDEO_FORMAT_GRAY8:
+    case GST_VIDEO_FORMAT_GRAY16_BE:
+      pngenc->png_color_type = PNG_COLOR_TYPE_GRAY;
+      break;
+    default:
+      ret = FALSE;
+      goto done;
+  }
+
+  switch (GST_VIDEO_INFO_FORMAT (info)) {
+    case GST_VIDEO_FORMAT_GRAY16_BE:
+      pngenc->depth = 16;
+      break;
+    default:                   /* GST_VIDEO_FORMAT_RGB and GST_VIDEO_FORMAT_GRAY8 */
+      pngenc->depth = 8;
+      break;
+  }
+
+  if (pngenc->input_state)
+    gst_video_codec_state_unref (pngenc->input_state);
+  pngenc->input_state = gst_video_codec_state_ref (state);
+
+  output_state =
+      gst_video_encoder_set_output_state (encoder,
+      gst_caps_new_empty_simple ("image/png"), state);
+  gst_video_codec_state_unref (output_state);
+
+done:
+
+  return ret;
+}
+
+static void
+gst_pngenc_init (GstPngEnc * pngenc)
+{
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_ENCODER_SINK_PAD (pngenc));
+
+  /* init settings */
+  pngenc->png_struct_ptr = NULL;
+  pngenc->png_info_ptr = NULL;
+
+  pngenc->snapshot = DEFAULT_SNAPSHOT;
+  pngenc->compression_level = DEFAULT_COMPRESSION_LEVEL;
+}
+
+static void
+gst_pngenc_finalize (GObject * object)
+{
+  GstPngEnc *pngenc = GST_PNGENC (object);
+
+  if (pngenc->input_state)
+    gst_video_codec_state_unref (pngenc->input_state);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+user_flush_data (png_structp png_ptr G_GNUC_UNUSED)
+{
+}
+
+static void
+user_write_data (png_structp png_ptr, png_bytep data, png_uint_32 length)
+{
+  GstPngEnc *pngenc;
+  GstMemory *mem;
+  GstMapInfo minfo;
+
+  pngenc = (GstPngEnc *) png_get_io_ptr (png_ptr);
+
+  mem = gst_allocator_alloc (NULL, length, NULL);
+  if (!mem) {
+    GST_ERROR_OBJECT (pngenc, "Failed to allocate memory");
+    png_error (png_ptr, "Failed to allocate memory");
+
+    /* never reached */
+    return;
+  }
+
+  if (!gst_memory_map (mem, &minfo, GST_MAP_WRITE)) {
+    GST_ERROR_OBJECT (pngenc, "Failed to map memory");
+    gst_memory_unref (mem);
+
+    png_error (png_ptr, "Failed to map memory");
+
+    /* never reached */
+    return;
+  }
+
+  memcpy (minfo.data, data, length);
+  gst_memory_unmap (mem, &minfo);
+
+  gst_buffer_append_memory (pngenc->buffer_out, mem);
+}
+
+static GstFlowReturn
+gst_pngenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
+{
+  GstPngEnc *pngenc;
+  gint row_index;
+  png_byte **row_pointers;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstVideoInfo *info;
+  GstVideoFrame vframe;
+
+  pngenc = GST_PNGENC (encoder);
+  info = &pngenc->input_state->info;
+
+  GST_DEBUG_OBJECT (pngenc, "BEGINNING");
+
+  /* initialize png struct stuff */
+  pngenc->png_struct_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
+      (png_voidp) NULL, user_error_fn, user_warning_fn);
+  if (pngenc->png_struct_ptr == NULL)
+    goto struct_init_fail;
+
+  pngenc->png_info_ptr = png_create_info_struct (pngenc->png_struct_ptr);
+  if (!pngenc->png_info_ptr)
+    goto png_info_fail;
+
+  /* non-0 return is from a longjmp inside of libpng */
+  if (setjmp (png_jmpbuf (pngenc->png_struct_ptr)) != 0)
+    goto longjmp_fail;
+
+  png_set_filter (pngenc->png_struct_ptr, 0,
+      PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE);
+  png_set_compression_level (pngenc->png_struct_ptr, pngenc->compression_level);
+
+  png_set_IHDR (pngenc->png_struct_ptr,
+      pngenc->png_info_ptr,
+      GST_VIDEO_INFO_WIDTH (info),
+      GST_VIDEO_INFO_HEIGHT (info),
+      pngenc->depth,
+      pngenc->png_color_type,
+      PNG_INTERLACE_NONE,
+      PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+  png_set_write_fn (pngenc->png_struct_ptr, pngenc,
+      (png_rw_ptr) user_write_data, user_flush_data);
+
+  if (!gst_video_frame_map (&vframe, &pngenc->input_state->info,
+          frame->input_buffer, GST_MAP_READ)) {
+    GST_ELEMENT_ERROR (pngenc, STREAM, FORMAT, (NULL),
+        ("Failed to map video frame, caps problem?"));
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+
+  row_pointers = g_new (png_byte *, GST_VIDEO_INFO_HEIGHT (info));
+
+  for (row_index = 0; row_index < GST_VIDEO_INFO_HEIGHT (info); row_index++) {
+    row_pointers[row_index] = GST_VIDEO_FRAME_COMP_DATA (&vframe, 0) +
+        (row_index * GST_VIDEO_FRAME_COMP_STRIDE (&vframe, 0));
+  }
+
+  /* allocate the output buffer */
+  pngenc->buffer_out = gst_buffer_new ();
+
+  png_write_info (pngenc->png_struct_ptr, pngenc->png_info_ptr);
+  png_write_image (pngenc->png_struct_ptr, row_pointers);
+  png_write_end (pngenc->png_struct_ptr, NULL);
+
+  g_free (row_pointers);
+  gst_video_frame_unmap (&vframe);
+
+  png_destroy_info_struct (pngenc->png_struct_ptr, &pngenc->png_info_ptr);
+  png_destroy_write_struct (&pngenc->png_struct_ptr, (png_infopp) NULL);
+
+  /* Set final size and store */
+  frame->output_buffer = pngenc->buffer_out;
+
+  pngenc->buffer_out = NULL;
+
+  if ((ret = gst_video_encoder_finish_frame (encoder, frame)) != GST_FLOW_OK)
+    goto done;
+
+  if (pngenc->snapshot)
+    ret = GST_FLOW_EOS;
+
+done:
+  GST_DEBUG_OBJECT (pngenc, "END, ret:%d", ret);
+
+  return ret;
+
+  /* ERRORS */
+struct_init_fail:
+  {
+    GST_ELEMENT_ERROR (pngenc, LIBRARY, INIT, (NULL),
+        ("Failed to initialize png structure"));
+    return GST_FLOW_ERROR;
+  }
+
+png_info_fail:
+  {
+    png_destroy_write_struct (&(pngenc->png_struct_ptr), (png_infopp) NULL);
+    GST_ELEMENT_ERROR (pngenc, LIBRARY, INIT, (NULL),
+        ("Failed to initialize the png info structure"));
+    return GST_FLOW_ERROR;
+  }
+
+longjmp_fail:
+  {
+    png_destroy_write_struct (&pngenc->png_struct_ptr, &pngenc->png_info_ptr);
+    GST_ELEMENT_ERROR (pngenc, LIBRARY, FAILED, (NULL),
+        ("returning from longjmp"));
+    return GST_FLOW_ERROR;
+  }
+}
+
+static gboolean
+gst_pngenc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
+{
+  gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
+
+  return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
+      query);
+}
+
+static void
+gst_pngenc_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstPngEnc *pngenc;
+
+  pngenc = GST_PNGENC (object);
+
+  switch (prop_id) {
+    case ARG_SNAPSHOT:
+      g_value_set_boolean (value, pngenc->snapshot);
+      break;
+    case ARG_COMPRESSION_LEVEL:
+      g_value_set_uint (value, pngenc->compression_level);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+
+static void
+gst_pngenc_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstPngEnc *pngenc;
+
+  pngenc = GST_PNGENC (object);
+
+  switch (prop_id) {
+    case ARG_SNAPSHOT:
+      pngenc->snapshot = g_value_get_boolean (value);
+      break;
+    case ARG_COMPRESSION_LEVEL:
+      pngenc->compression_level = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/ext/libpng/gstpngenc.h b/ext/libpng/gstpngenc.h
new file mode 100644
index 0000000..e71d97c
--- /dev/null
+++ b/ext/libpng/gstpngenc.h
@@ -0,0 +1,75 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2012 Collabora Ltd.
+ *	Author : Edward Hervey <edward@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_PNGENC_H__
+#define __GST_PNGENC_H__
+
+#include <gst/gst.h>
+#include <gst/video/gstvideoencoder.h>
+#include <png.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_PNGENC            (gst_pngenc_get_type())
+#define GST_PNGENC(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PNGENC,GstPngEnc))
+#define GST_PNGENC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PNGENC,GstPngEncClass))
+#define GST_IS_PNGENC(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PNGENC))
+#define GST_IS_PNGENC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PNGENC))
+
+typedef struct _GstPngEnc GstPngEnc;
+typedef struct _GstPngEncClass GstPngEncClass;
+
+struct _GstPngEnc
+{
+  GstVideoEncoder parent;
+
+  GstVideoCodecState *input_state;
+  GstBuffer *buffer_out;
+
+  png_structp png_struct_ptr;
+  png_infop png_info_ptr;
+
+  gint png_color_type;
+  gint depth;
+  guint compression_level;
+
+  gboolean snapshot;
+  gboolean newmedia;
+};
+
+struct _GstPngEncClass
+{
+  GstVideoEncoderClass parent_class;
+};
+
+GType gst_pngenc_get_type(void);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_PNGENC_H__ */
diff --git a/ext/libpng/meson.build b/ext/libpng/meson.build
new file mode 100644
index 0000000..7e01e9f
--- /dev/null
+++ b/ext/libpng/meson.build
@@ -0,0 +1,19 @@
+png_sources = [
+  'gstpng.c',
+  'gstpngenc.c',
+  'gstpngdec.c',
+]
+
+libpng_dep = dependency('libpng', version : '>=1.2', required : false)
+
+if libpng_dep.found()
+  gstpng = library('gstpng',
+    png_sources,
+    c_args : gst_plugins_good_args,
+    link_args : noseh_link_args,
+    include_directories : [configinc, libsinc],
+    dependencies : [gstbase_dep, gstvideo_dep, libpng_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/ext/meson.build b/ext/meson.build
new file mode 100644
index 0000000..2758877
--- /dev/null
+++ b/ext/meson.build
@@ -0,0 +1,28 @@
+subdir('aalib')
+subdir('cairo')
+subdir('flac')
+subdir('gdk_pixbuf')
+subdir('jack')
+subdir('jpeg')
+subdir('lame')
+subdir('libcaca')
+# FIXME: dv plugin fails to link with msvc, wants pthread.lib
+if cc.get_id() != 'msvc'
+  subdir('dv')
+endif
+subdir('libpng')
+subdir('mpg123')
+subdir('raw1394')
+subdir('pulse')
+subdir('shout2')
+subdir('soup')
+subdir('speex')
+# FIXME: taglib fails to compile and link with msvc
+if cc.get_id() == 'msvc'
+  message('Building with MSVC, disabling taglib support. Patches welcome!')
+else
+  subdir('taglib')
+endif
+subdir('twolame')
+subdir('vpx')
+subdir('wavpack')
diff --git a/ext/mpg123/Makefile.am b/ext/mpg123/Makefile.am
new file mode 100644
index 0000000..465f325
--- /dev/null
+++ b/ext/mpg123/Makefile.am
@@ -0,0 +1,11 @@
+plugin_LTLIBRARIES = libgstmpg123.la
+
+libgstmpg123_la_SOURCES = gstmpg123audiodec.c
+libgstmpg123_la_CFLAGS = -DGST_USE_UNSTABLE_API \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) $(GST_CFLAGS) $(MPG123_CFLAGS)
+libgstmpg123_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-@GST_API_VERSION@ \
+	$(GST_BASE_LIBS) $(GST_LIBS) $(MPG123_LIBS)
+libgstmpg123_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstmpg123audiodec.h
diff --git a/ext/mpg123/gstmpg123audiodec.c b/ext/mpg123/gstmpg123audiodec.c
new file mode 100644
index 0000000..fa6743c
--- /dev/null
+++ b/ext/mpg123/gstmpg123audiodec.c
@@ -0,0 +1,634 @@
+/*  MP3 decoding plugin for GStreamer using the mpg123 library
+ *  Copyright (C) 2012 Carlos Rafael Giani
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/**
+ * SECTION: element-mpg123audiodec
+ * @see_also: lamemp3enc, mad
+ *
+ * Audio decoder for MPEG-1 layer 1/2/3 audio data.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 filesrc location=music.mp3 ! mpegaudioparse ! mpg123audiodec ! audioconvert ! audioresample ! autoaudiosink
+ * ]| Decode and play the mp3 file
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstmpg123audiodec.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+GST_DEBUG_CATEGORY_STATIC (mpg123_debug);
+#define GST_CAT_DEFAULT mpg123_debug
+
+/* Omitted sample formats that mpg123 supports (or at least can support):
+ *  - 8bit integer signed
+ *  - 8bit integer unsigned
+ *  - a-law
+ *  - mu-law
+ *  - 64bit float
+ *
+ * The first four formats are not supported by the GstAudioDecoder base class.
+ * (The internal gst_audio_format_from_caps_structure() call fails.)
+ *
+ * The 64bit float issue is tricky. mpg123 actually decodes to "real",
+ * not necessarily to "float".
+ *
+ * "real" can be fixed point, 32bit float, 64bit float. There seems to be
+ * no way how to find out which one of them is actually used.
+ *
+ * However, in all known installations, "real" equals 32bit float, so that's
+ * what is used. */
+
+static GstStaticPadTemplate static_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/mpeg, "
+        "mpegversion = (int) 1, "
+        "layer = (int) [ 1, 3 ], "
+        "rate = (int) { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, "
+        "channels = (int) [ 1, 2 ], " "parsed = (boolean) true ")
+    );
+
+static gboolean gst_mpg123_audio_dec_start (GstAudioDecoder * dec);
+static gboolean gst_mpg123_audio_dec_stop (GstAudioDecoder * dec);
+static GstFlowReturn gst_mpg123_audio_dec_push_decoded_bytes (GstMpg123AudioDec
+    * mpg123_decoder, unsigned char const *decoded_bytes,
+    size_t const num_decoded_bytes);
+static GstFlowReturn gst_mpg123_audio_dec_handle_frame (GstAudioDecoder * dec,
+    GstBuffer * input_buffer);
+static gboolean gst_mpg123_audio_dec_set_format (GstAudioDecoder * dec,
+    GstCaps * input_caps);
+static void gst_mpg123_audio_dec_flush (GstAudioDecoder * dec, gboolean hard);
+
+G_DEFINE_TYPE (GstMpg123AudioDec, gst_mpg123_audio_dec, GST_TYPE_AUDIO_DECODER);
+
+static void
+gst_mpg123_audio_dec_class_init (GstMpg123AudioDecClass * klass)
+{
+  GstAudioDecoderClass *base_class;
+  GstElementClass *element_class;
+  GstPadTemplate *src_template, *sink_template;
+  int error;
+
+  GST_DEBUG_CATEGORY_INIT (mpg123_debug, "mpg123", 0, "mpg123 mp3 decoder");
+
+  base_class = GST_AUDIO_DECODER_CLASS (klass);
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gst_element_class_set_static_metadata (element_class,
+      "mpg123 mp3 decoder",
+      "Codec/Decoder/Audio",
+      "Decodes mp3 streams using the mpg123 library",
+      "Carlos Rafael Giani <dv@pseudoterminal.org>");
+
+  /* Not using static pad template for srccaps, since the comma-separated list
+   * of formats needs to be created depending on whatever mpg123 supports */
+  {
+    const int *format_list;
+    const long *rates_list;
+    size_t num, i;
+    GString *s;
+    GstCaps *src_template_caps;
+
+    s = g_string_new ("audio/x-raw, ");
+
+    mpg123_encodings (&format_list, &num);
+    g_string_append (s, "format = { ");
+    for (i = 0; i < num; ++i) {
+      switch (format_list[i]) {
+        case MPG123_ENC_SIGNED_16:
+          g_string_append (s, (i > 0) ? ", " : "");
+          g_string_append (s, GST_AUDIO_NE (S16));
+          break;
+        case MPG123_ENC_UNSIGNED_16:
+          g_string_append (s, (i > 0) ? ", " : "");
+          g_string_append (s, GST_AUDIO_NE (U16));
+          break;
+        case MPG123_ENC_SIGNED_24:
+          g_string_append (s, (i > 0) ? ", " : "");
+          g_string_append (s, GST_AUDIO_NE (S24));
+          break;
+        case MPG123_ENC_UNSIGNED_24:
+          g_string_append (s, (i > 0) ? ", " : "");
+          g_string_append (s, GST_AUDIO_NE (U24));
+          break;
+        case MPG123_ENC_SIGNED_32:
+          g_string_append (s, (i > 0) ? ", " : "");
+          g_string_append (s, GST_AUDIO_NE (S32));
+          break;
+        case MPG123_ENC_UNSIGNED_32:
+          g_string_append (s, (i > 0) ? ", " : "");
+          g_string_append (s, GST_AUDIO_NE (U32));
+          break;
+        case MPG123_ENC_FLOAT_32:
+          g_string_append (s, (i > 0) ? ", " : "");
+          g_string_append (s, GST_AUDIO_NE (F32));
+          break;
+        default:
+          GST_DEBUG ("Ignoring mpg123 format %d", format_list[i]);
+          break;
+      }
+    }
+    g_string_append (s, " }, ");
+
+    mpg123_rates (&rates_list, &num);
+    g_string_append (s, "rate = (int) { ");
+    for (i = 0; i < num; ++i) {
+      g_string_append_printf (s, "%s%lu", (i > 0) ? ", " : "", rates_list[i]);
+    }
+    g_string_append (s, "}, ");
+
+    g_string_append (s, "channels = (int) [ 1, 2 ], ");
+    g_string_append (s, "layout = (string) interleaved");
+
+    src_template_caps = gst_caps_from_string (s->str);
+    src_template = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+        src_template_caps);
+    gst_caps_unref (src_template_caps);
+
+    g_string_free (s, TRUE);
+  }
+
+  sink_template = gst_static_pad_template_get (&static_sink_template);
+
+  gst_element_class_add_pad_template (element_class, sink_template);
+  gst_element_class_add_pad_template (element_class, src_template);
+
+  base_class->start = GST_DEBUG_FUNCPTR (gst_mpg123_audio_dec_start);
+  base_class->stop = GST_DEBUG_FUNCPTR (gst_mpg123_audio_dec_stop);
+  base_class->handle_frame =
+      GST_DEBUG_FUNCPTR (gst_mpg123_audio_dec_handle_frame);
+  base_class->set_format = GST_DEBUG_FUNCPTR (gst_mpg123_audio_dec_set_format);
+  base_class->flush = GST_DEBUG_FUNCPTR (gst_mpg123_audio_dec_flush);
+
+  error = mpg123_init ();
+  if (G_UNLIKELY (error != MPG123_OK))
+    GST_ERROR ("Could not initialize mpg123 library: %s",
+        mpg123_plain_strerror (error));
+  else
+    GST_INFO ("mpg123 library initialized");
+}
+
+
+void
+gst_mpg123_audio_dec_init (GstMpg123AudioDec * mpg123_decoder)
+{
+  mpg123_decoder->handle = NULL;
+  gst_audio_decoder_set_needs_format (GST_AUDIO_DECODER (mpg123_decoder), TRUE);
+  gst_audio_decoder_set_use_default_pad_acceptcaps (GST_AUDIO_DECODER_CAST
+      (mpg123_decoder), TRUE);
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_DECODER_SINK_PAD (mpg123_decoder));
+}
+
+
+static gboolean
+gst_mpg123_audio_dec_start (GstAudioDecoder * dec)
+{
+  GstMpg123AudioDec *mpg123_decoder;
+  int error;
+
+  mpg123_decoder = GST_MPG123_AUDIO_DEC (dec);
+  error = 0;
+
+  mpg123_decoder->handle = mpg123_new (NULL, &error);
+  mpg123_decoder->has_next_audioinfo = FALSE;
+  mpg123_decoder->frame_offset = 0;
+
+  /* Initially, the mpg123 handle comes with a set of default formats
+   * supported. This clears this set.  This is necessary, since only one
+   * format shall be supported (see set_format for more). */
+  mpg123_format_none (mpg123_decoder->handle);
+
+  /* Built-in mpg123 support for gapless decoding is disabled for now,
+   * since it does not work well with seeking */
+  mpg123_param (mpg123_decoder->handle, MPG123_REMOVE_FLAGS, MPG123_GAPLESS, 0);
+  /* Tells mpg123 to use a small read-ahead buffer for better MPEG sync;
+   * essential for MP3 radio streams */
+  mpg123_param (mpg123_decoder->handle, MPG123_ADD_FLAGS, MPG123_SEEKBUFFER, 0);
+  /* Sets the resync limit to the end of the stream (otherwise mpg123 may give
+   * up on decoding prematurely, especially with mp3 web radios) */
+  mpg123_param (mpg123_decoder->handle, MPG123_RESYNC_LIMIT, -1, 0);
+#if MPG123_API_VERSION >= 36
+  /* The precise API version where MPG123_AUTO_RESAMPLE appeared is
+   * somewhere between 29 and 36 */
+  /* Don't let mpg123 resample output */
+  mpg123_param (mpg123_decoder->handle, MPG123_REMOVE_FLAGS,
+      MPG123_AUTO_RESAMPLE, 0);
+#endif
+  /* Don't let mpg123 print messages to stdout/stderr */
+  mpg123_param (mpg123_decoder->handle, MPG123_ADD_FLAGS, MPG123_QUIET, 0);
+
+  /* Open in feed mode (= encoded data is fed manually into the handle). */
+  error = mpg123_open_feed (mpg123_decoder->handle);
+
+  if (G_UNLIKELY (error != MPG123_OK)) {
+    GST_ELEMENT_ERROR (dec, LIBRARY, INIT, (NULL),
+        ("%s", mpg123_strerror (mpg123_decoder->handle)));
+    mpg123_close (mpg123_decoder->handle);
+    mpg123_delete (mpg123_decoder->handle);
+    mpg123_decoder->handle = NULL;
+    return FALSE;
+  }
+
+  GST_INFO_OBJECT (dec, "mpg123 decoder started");
+
+  return TRUE;
+}
+
+
+static gboolean
+gst_mpg123_audio_dec_stop (GstAudioDecoder * dec)
+{
+  GstMpg123AudioDec *mpg123_decoder = GST_MPG123_AUDIO_DEC (dec);
+
+  if (G_LIKELY (mpg123_decoder->handle != NULL)) {
+    mpg123_close (mpg123_decoder->handle);
+    mpg123_delete (mpg123_decoder->handle);
+    mpg123_decoder->handle = NULL;
+  }
+
+  GST_INFO_OBJECT (dec, "mpg123 decoder stopped");
+
+  return TRUE;
+}
+
+
+static GstFlowReturn
+gst_mpg123_audio_dec_push_decoded_bytes (GstMpg123AudioDec * mpg123_decoder,
+    unsigned char const *decoded_bytes, size_t const num_decoded_bytes)
+{
+  GstBuffer *output_buffer;
+  GstAudioDecoder *dec;
+
+  output_buffer = NULL;
+  dec = GST_AUDIO_DECODER (mpg123_decoder);
+
+  if ((num_decoded_bytes == 0) || (decoded_bytes == NULL)) {
+    /* This occurs in the first few frames, which do not carry data; once
+     * MPG123_AUDIO_DEC_NEW_FORMAT is received, the empty frames stop occurring */
+    GST_DEBUG_OBJECT (mpg123_decoder,
+        "cannot decode yet, need more data -> no output buffer to push");
+    return GST_FLOW_OK;
+  }
+
+  output_buffer = gst_buffer_new_allocate (NULL, num_decoded_bytes, NULL);
+
+  if (output_buffer == NULL) {
+    /* This is necessary to advance playback in time,
+     * even when nothing was decoded. */
+    return gst_audio_decoder_finish_frame (dec, NULL, 1);
+  } else {
+    GstMapInfo info;
+
+    if (gst_buffer_map (output_buffer, &info, GST_MAP_WRITE)) {
+      memcpy (info.data, decoded_bytes, num_decoded_bytes);
+      gst_buffer_unmap (output_buffer, &info);
+    } else {
+      GST_ERROR_OBJECT (mpg123_decoder, "gst_buffer_map() returned NULL");
+      gst_buffer_unref (output_buffer);
+      output_buffer = NULL;
+    }
+
+    return gst_audio_decoder_finish_frame (dec, output_buffer, 1);
+  }
+}
+
+
+static GstFlowReturn
+gst_mpg123_audio_dec_handle_frame (GstAudioDecoder * dec,
+    GstBuffer * input_buffer)
+{
+  GstMpg123AudioDec *mpg123_decoder;
+  int decode_error;
+  unsigned char *decoded_bytes;
+  size_t num_decoded_bytes;
+  GstFlowReturn retval;
+
+  mpg123_decoder = GST_MPG123_AUDIO_DEC (dec);
+
+  g_assert (mpg123_decoder->handle != NULL);
+
+  /* The actual decoding */
+  {
+    /* feed input data (if there is any) */
+    if (G_LIKELY (input_buffer != NULL)) {
+      GstMapInfo info;
+
+      if (gst_buffer_map (input_buffer, &info, GST_MAP_READ)) {
+        mpg123_feed (mpg123_decoder->handle, info.data, info.size);
+        gst_buffer_unmap (input_buffer, &info);
+      } else {
+        GST_AUDIO_DECODER_ERROR (mpg123_decoder, 1, RESOURCE, READ, (NULL),
+            ("gst_memory_map() failed"), retval);
+        return retval;
+      }
+    }
+
+    /* Try to decode a frame */
+    decoded_bytes = NULL;
+    num_decoded_bytes = 0;
+    decode_error = mpg123_decode_frame (mpg123_decoder->handle,
+        &mpg123_decoder->frame_offset, &decoded_bytes, &num_decoded_bytes);
+  }
+
+  retval = GST_FLOW_OK;
+
+  switch (decode_error) {
+    case MPG123_NEW_FORMAT:
+      /* As mentioned in gst_mpg123_audio_dec_set_format(), the next audioinfo
+       * is not set immediately; instead, the code waits for mpg123 to take
+       * note of the new format, and then sets the audioinfo. This fixes glitches
+       * with mp3s containing several format headers (for example, first half
+       * using 44.1kHz, second half 32 kHz) */
+
+      GST_LOG_OBJECT (dec,
+          "mpg123 reported a new format -> setting next srccaps");
+
+      gst_mpg123_audio_dec_push_decoded_bytes (mpg123_decoder, decoded_bytes,
+          num_decoded_bytes);
+
+      /* If there is a next audioinfo, use it, then set has_next_audioinfo to
+       * FALSE, to make sure gst_audio_decoder_set_output_format() isn't called
+       * again until set_format is called by the base class */
+      if (mpg123_decoder->has_next_audioinfo) {
+        if (!gst_audio_decoder_set_output_format (dec,
+                &(mpg123_decoder->next_audioinfo))) {
+          GST_WARNING_OBJECT (dec, "Unable to set output format");
+          retval = GST_FLOW_NOT_NEGOTIATED;
+        }
+        mpg123_decoder->has_next_audioinfo = FALSE;
+      }
+
+      break;
+
+    case MPG123_NEED_MORE:
+    case MPG123_OK:
+      retval = gst_mpg123_audio_dec_push_decoded_bytes (mpg123_decoder,
+          decoded_bytes, num_decoded_bytes);
+      break;
+
+    case MPG123_DONE:
+      /* If this happens, then the upstream parser somehow missed the ending
+       * of the bitstream */
+      GST_LOG_OBJECT (dec, "mpg123 is done decoding");
+      gst_mpg123_audio_dec_push_decoded_bytes (mpg123_decoder, decoded_bytes,
+          num_decoded_bytes);
+      retval = GST_FLOW_EOS;
+      break;
+
+    default:
+    {
+      /* Anything else is considered an error */
+      int errcode;
+      retval = GST_FLOW_ERROR;  /* use error by default */
+      switch (decode_error) {
+        case MPG123_ERR:
+          errcode = mpg123_errcode (mpg123_decoder->handle);
+          break;
+        default:
+          errcode = decode_error;
+      }
+      switch (errcode) {
+        case MPG123_BAD_OUTFORMAT:{
+          GstCaps *input_caps =
+              gst_pad_get_current_caps (GST_AUDIO_DECODER_SINK_PAD (dec));
+          GST_ELEMENT_ERROR (dec, STREAM, FORMAT, (NULL),
+              ("Output sample format could not be used when trying to decode frame. "
+                  "This is typically caused when the input caps (often the sample "
+                  "rate) do not match the actual format of the audio data. "
+                  "Input caps: %" GST_PTR_FORMAT, input_caps)
+              );
+          gst_caps_unref (input_caps);
+          break;
+        }
+        default:{
+          char const *errmsg = mpg123_plain_strerror (errcode);
+          /* GST_AUDIO_DECODER_ERROR sets a new return value according to
+           * its estimations */
+          GST_AUDIO_DECODER_ERROR (mpg123_decoder, 1, STREAM, DECODE, (NULL),
+              ("mpg123 decoding error: %s", errmsg), retval);
+        }
+      }
+    }
+  }
+
+  return retval;
+}
+
+
+static gboolean
+gst_mpg123_audio_dec_set_format (GstAudioDecoder * dec, GstCaps * input_caps)
+{
+  /* "encoding" is the sample format specifier for mpg123 */
+  int encoding;
+  int sample_rate, num_channels;
+  GstAudioFormat format;
+  GstMpg123AudioDec *mpg123_decoder;
+  gboolean retval = FALSE;
+
+  mpg123_decoder = GST_MPG123_AUDIO_DEC (dec);
+
+  g_assert (mpg123_decoder->handle != NULL);
+
+  mpg123_decoder->has_next_audioinfo = FALSE;
+
+  /* Get sample rate and number of channels from input_caps */
+  {
+    GstStructure *structure;
+    gboolean err = FALSE;
+
+    /* Only the first structure is used (multiple
+     * input caps structures don't make sense */
+    structure = gst_caps_get_structure (input_caps, 0);
+
+    if (!gst_structure_get_int (structure, "rate", &sample_rate)) {
+      err = TRUE;
+      GST_ERROR_OBJECT (dec, "Input caps do not have a rate value");
+    }
+    if (!gst_structure_get_int (structure, "channels", &num_channels)) {
+      err = TRUE;
+      GST_ERROR_OBJECT (dec, "Input caps do not have a channel value");
+    }
+
+    if (G_UNLIKELY (err))
+      goto done;
+  }
+
+  /* Get sample format from the allowed src caps */
+  {
+    GstCaps *allowed_srccaps =
+        gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (dec));
+
+    if (allowed_srccaps == NULL) {
+      /* srcpad is not linked (yet), so no peer information is available;
+       * just use the default sample format (16 bit signed integer) */
+      GST_DEBUG_OBJECT (mpg123_decoder,
+          "srcpad is not linked (yet) -> using S16 sample format");
+      format = GST_AUDIO_FORMAT_S16;
+      encoding = MPG123_ENC_SIGNED_16;
+    } else if (gst_caps_is_empty (allowed_srccaps)) {
+      gst_caps_unref (allowed_srccaps);
+      goto done;
+    } else {
+      gchar const *format_str;
+      GValue const *format_value;
+
+      /* Look at the sample format values from the first structure */
+      GstStructure *structure = gst_caps_get_structure (allowed_srccaps, 0);
+      format_value = gst_structure_get_value (structure, "format");
+
+      if (format_value == NULL) {
+        gst_caps_unref (allowed_srccaps);
+        goto done;
+      } else if (GST_VALUE_HOLDS_LIST (format_value)) {
+        /* if value is a format list, pick the first entry */
+        GValue const *fmt_list_value =
+            gst_value_list_get_value (format_value, 0);
+        format_str = g_value_get_string (fmt_list_value);
+      } else if (G_VALUE_HOLDS_STRING (format_value)) {
+        /* if value is a string, use it directly */
+        format_str = g_value_get_string (format_value);
+      } else {
+        GST_ERROR_OBJECT (mpg123_decoder, "unexpected type for 'format' field "
+            "in caps structure %" GST_PTR_FORMAT, structure);
+        gst_caps_unref (allowed_srccaps);
+        goto done;
+      }
+
+      /* get the format value from the string */
+      format = gst_audio_format_from_string (format_str);
+      gst_caps_unref (allowed_srccaps);
+
+      g_assert (format != GST_AUDIO_FORMAT_UNKNOWN);
+
+      /* convert format to mpg123 encoding */
+      switch (format) {
+        case GST_AUDIO_FORMAT_S16:
+          encoding = MPG123_ENC_SIGNED_16;
+          break;
+        case GST_AUDIO_FORMAT_S24:
+          encoding = MPG123_ENC_SIGNED_24;
+          break;
+        case GST_AUDIO_FORMAT_S32:
+          encoding = MPG123_ENC_SIGNED_32;
+          break;
+        case GST_AUDIO_FORMAT_U16:
+          encoding = MPG123_ENC_UNSIGNED_16;
+          break;
+        case GST_AUDIO_FORMAT_U24:
+          encoding = MPG123_ENC_UNSIGNED_24;
+          break;
+        case GST_AUDIO_FORMAT_U32:
+          encoding = MPG123_ENC_UNSIGNED_32;
+          break;
+        case GST_AUDIO_FORMAT_F32:
+          encoding = MPG123_ENC_FLOAT_32;
+          break;
+        default:
+          g_assert_not_reached ();
+          goto done;
+      }
+    }
+  }
+
+  /* Sample rate, number of channels, and sample format are known at this point.
+   * Set the audioinfo structure's values and the mpg123 format. */
+  {
+    int err;
+
+    /* clear all existing format settings from the mpg123 instance */
+    mpg123_format_none (mpg123_decoder->handle);
+    /* set the chosen format */
+    err =
+        mpg123_format (mpg123_decoder->handle, sample_rate, num_channels,
+        encoding);
+
+    if (err != MPG123_OK) {
+      GST_WARNING_OBJECT (dec,
+          "mpg123_format() failed: %s",
+          mpg123_strerror (mpg123_decoder->handle));
+    } else {
+      gst_audio_info_init (&(mpg123_decoder->next_audioinfo));
+      gst_audio_info_set_format (&(mpg123_decoder->next_audioinfo), format,
+          sample_rate, num_channels, NULL);
+      GST_LOG_OBJECT (dec, "The next audio format is: %s, %u Hz, %u channels",
+          gst_audio_format_to_string (format), sample_rate, num_channels);
+      mpg123_decoder->has_next_audioinfo = TRUE;
+
+      retval = TRUE;
+    }
+  }
+
+done:
+  return retval;
+}
+
+
+static void
+gst_mpg123_audio_dec_flush (GstAudioDecoder * dec, gboolean hard)
+{
+  int error;
+  GstMpg123AudioDec *mpg123_decoder;
+
+  GST_LOG_OBJECT (dec, "Flushing decoder");
+
+  mpg123_decoder = GST_MPG123_AUDIO_DEC (dec);
+
+  g_assert (mpg123_decoder->handle != NULL);
+
+  /* Flush by reopening the feed */
+  mpg123_close (mpg123_decoder->handle);
+  error = mpg123_open_feed (mpg123_decoder->handle);
+
+  if (G_UNLIKELY (error != MPG123_OK)) {
+    GST_ELEMENT_ERROR (dec, LIBRARY, INIT, (NULL),
+        ("Error while reopening mpg123 feed: %s",
+            mpg123_plain_strerror (error)));
+    mpg123_close (mpg123_decoder->handle);
+    mpg123_delete (mpg123_decoder->handle);
+    mpg123_decoder->handle = NULL;
+  }
+
+  if (hard)
+    mpg123_decoder->has_next_audioinfo = FALSE;
+
+  /* opening/closing feeds do not affect the format defined by the
+   * mpg123_format() call that was made in gst_mpg123_audio_dec_set_format(),
+   * and since the up/downstream caps are not expected to change here, no
+   * mpg123_format() calls are done */
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "mpg123audiodec",
+      GST_RANK_MARGINAL, gst_mpg123_audio_dec_get_type ());
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    mpg123, "mp3 decoding based on the mpg123 library",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/mpg123/gstmpg123audiodec.h b/ext/mpg123/gstmpg123audiodec.h
new file mode 100644
index 0000000..b865c41
--- /dev/null
+++ b/ext/mpg123/gstmpg123audiodec.h
@@ -0,0 +1,74 @@
+/*  MP3 decoding plugin for GStreamer using the mpg123 library
+ *  Copyright (C) 2012 Carlos Rafael Giani
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GST_MPG123_AUDIO_DEC_H__
+#define __GST_MPG123_AUDIO_DEC_H__
+
+/* This is what the visual studio build in mpg123 does before including the
+ * original header file. Without this we get syntax errors in the
+ * replace_reader function declarations because it doesn't know ssize_t etc.
+ * It doesn't realy matter for us if the ssize_t typedef here is correct. */
+#ifdef _MSC_VER
+#include <tchar.h>
+#include <stdlib.h>
+#include <sys/types.h>
+typedef long ssize_t;
+#include <stdint.h>
+#endif
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiodecoder.h>
+#include <mpg123.h>
+
+
+G_BEGIN_DECLS
+
+
+typedef struct _GstMpg123AudioDec GstMpg123AudioDec;
+typedef struct _GstMpg123AudioDecClass GstMpg123AudioDecClass;
+
+
+#define GST_TYPE_MPG123_AUDIO_DEC             (gst_mpg123_audio_dec_get_type())
+#define GST_MPG123_AUDIO_DEC(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_MPG123_AUDIO_DEC,GstMpg123AudioDec))
+#define GST_MPG123_AUDIO_DEC_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_MPG123_AUDIO_DEC,GstMpg123AudioDecClass))
+#define GST_IS_MPG123_AUDIO_DEC(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_MPG123_AUDIO_DEC))
+#define GST_IS_MPG123_AUDIO_DEC_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_MPG123_AUDIO_DEC))
+
+struct _GstMpg123AudioDec
+{
+  GstAudioDecoder parent;
+
+  mpg123_handle *handle;
+
+  GstAudioInfo next_audioinfo;
+  gboolean has_next_audioinfo;
+
+  off_t frame_offset;
+};
+
+
+struct _GstMpg123AudioDecClass
+{
+  GstAudioDecoderClass parent_class;
+};
+
+G_GNUC_INTERNAL GType gst_mpg123_audio_dec_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ext/mpg123/meson.build b/ext/mpg123/meson.build
new file mode 100644
index 0000000..3891fd7
--- /dev/null
+++ b/ext/mpg123/meson.build
@@ -0,0 +1,12 @@
+mpg123_dep = dependency('libmpg123', version : '>= 1.3', required : false)
+
+if mpg123_dep.found()
+  gstmpg123 = library('gstmpg123',
+    'gstmpg123audiodec.c',
+    c_args : gst_plugins_good_args,
+    include_directories : [configinc],
+    dependencies : [gstaudio_dep, mpg123_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/ext/pulse/Makefile.am b/ext/pulse/Makefile.am
new file mode 100644
index 0000000..90e0002
--- /dev/null
+++ b/ext/pulse/Makefile.am
@@ -0,0 +1,21 @@
+plugin_LTLIBRARIES = libgstpulseaudio.la
+
+libgstpulseaudio_la_SOURCES = \
+	plugin.c \
+	pulsesink.c \
+	pulsesrc.c \
+	pulsedeviceprovider.c \
+	pulseutil.c
+
+libgstpulseaudio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(PULSE_CFLAGS)
+libgstpulseaudio_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) \
+	-lgstpbutils-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) $(GST_LIBS) $(PULSE_LIBS)
+libgstpulseaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = \
+	pulsesink.h \
+	pulsesrc.h \
+	pulsedeviceprovider.h \
+	pulseutil.h
+
diff --git a/ext/pulse/meson.build b/ext/pulse/meson.build
new file mode 100644
index 0000000..d685f91
--- /dev/null
+++ b/ext/pulse/meson.build
@@ -0,0 +1,20 @@
+pulse_sources = [
+  'plugin.c',
+  'pulsesink.c',
+  'pulsesrc.c',
+  'pulsedeviceprovider.c',
+  'pulseutil.c',
+]
+
+libpulse_dep = dependency('libpulse', version : '>=2.0', required : false)
+
+if libpulse_dep.found()
+  gstpulse = library('gstpulseaudio',
+    pulse_sources,
+    c_args : gst_plugins_good_args,
+    include_directories : [configinc, libsinc],
+    dependencies : [gst_dep, gstbase_dep, gstaudio_dep, gstpbutils_dep, libpulse_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/ext/pulse/plugin.c b/ext/pulse/plugin.c
new file mode 100644
index 0000000..a2c8fe5
--- /dev/null
+++ b/ext/pulse/plugin.c
@@ -0,0 +1,64 @@
+/*
+ *  GStreamer pulseaudio plugin
+ *
+ *  Copyright (c) 2004-2008 Lennart Poettering
+ *
+ *  gst-pulse is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as
+ *  published by the Free Software Foundation; either version 2.1 of the
+ *  License, or (at your option) any later version.
+ *
+ *  gst-pulse 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with gst-pulse; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ *  USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst-i18n-plugin.h>
+
+#include "pulsesink.h"
+#include "pulsesrc.h"
+#include "pulsedeviceprovider.h"
+
+GST_DEBUG_CATEGORY (pulse_debug);
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+#ifdef ENABLE_NLS
+  GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
+      LOCALEDIR);
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+
+  if (!gst_element_register (plugin, "pulsesink", GST_RANK_PRIMARY + 10,
+          GST_TYPE_PULSESINK))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "pulsesrc", GST_RANK_PRIMARY + 10,
+          GST_TYPE_PULSESRC))
+    return FALSE;
+
+  if (!gst_device_provider_register (plugin, "pulsedeviceprovider",
+          GST_RANK_PRIMARY, GST_TYPE_PULSE_DEVICE_PROVIDER))
+    return FALSE;
+
+  GST_DEBUG_CATEGORY_INIT (pulse_debug, "pulse", 0, "PulseAudio elements");
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    pulseaudio,
+    "PulseAudio plugin library",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/pulse/pulsedeviceprovider.c b/ext/pulse/pulsedeviceprovider.c
new file mode 100644
index 0000000..a1964da
--- /dev/null
+++ b/ext/pulse/pulsedeviceprovider.c
@@ -0,0 +1,690 @@
+/* GStreamer
+ * Copyright (C) 2012 Olivier Crete <olivier.crete@collabora.com>
+ *
+ * pulsedeviceprovider.c: pulseaudio device probing and monitoring
+ *
+ * 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 "pulsedeviceprovider.h"
+
+#include <string.h>
+
+#include <gst/gst.h>
+
+#include "pulsesrc.h"
+#include "pulsesink.h"
+#include "pulseutil.h"
+
+
+GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
+#define GST_CAT_DEFAULT pulse_debug
+
+
+static GstDevice *gst_pulse_device_new (guint id,
+    const gchar * device_name, GstCaps * caps, const gchar * internal_name,
+    GstPulseDeviceType type, GstStructure * properties);
+
+G_DEFINE_TYPE (GstPulseDeviceProvider, gst_pulse_device_provider,
+    GST_TYPE_DEVICE_PROVIDER);
+
+static void gst_pulse_device_provider_finalize (GObject * object);
+static void gst_pulse_device_provider_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_pulse_device_provider_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+
+static GList *gst_pulse_device_provider_probe (GstDeviceProvider * provider);
+static gboolean gst_pulse_device_provider_start (GstDeviceProvider * provider);
+static void gst_pulse_device_provider_stop (GstDeviceProvider * provider);
+
+enum
+{
+  PROP_0,
+  PROP_SERVER,
+  PROP_CLIENT_NAME,
+  PROP_LAST
+};
+
+
+static void
+gst_pulse_device_provider_class_init (GstPulseDeviceProviderClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS (klass);
+  gchar *client_name;
+
+  gobject_class->set_property = gst_pulse_device_provider_set_property;
+  gobject_class->get_property = gst_pulse_device_provider_get_property;
+  gobject_class->finalize = gst_pulse_device_provider_finalize;
+
+  dm_class->probe = gst_pulse_device_provider_probe;
+  dm_class->start = gst_pulse_device_provider_start;
+  dm_class->stop = gst_pulse_device_provider_stop;
+
+  g_object_class_install_property (gobject_class,
+      PROP_SERVER,
+      g_param_spec_string ("server", "Server",
+          "The PulseAudio server to connect to", NULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  client_name = gst_pulse_client_name ();
+  g_object_class_install_property (gobject_class,
+      PROP_CLIENT_NAME,
+      g_param_spec_string ("client-name", "Client Name",
+          "The PulseAudio client_name_to_use", client_name,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+          GST_PARAM_MUTABLE_READY));
+  g_free (client_name);
+
+  gst_device_provider_class_set_static_metadata (dm_class,
+      "PulseAudio Device Provider", "Sink/Source/Audio",
+      "List and provider PulseAudio source and sink devices",
+      "Olivier Crete <olivier.crete@collabora.com>");
+}
+
+static void
+gst_pulse_device_provider_init (GstPulseDeviceProvider * self)
+{
+  self->client_name = gst_pulse_client_name ();
+}
+
+static void
+gst_pulse_device_provider_finalize (GObject * object)
+{
+  GstPulseDeviceProvider *self = GST_PULSE_DEVICE_PROVIDER (object);
+
+  g_free (self->client_name);
+  g_free (self->server);
+
+  G_OBJECT_CLASS (gst_pulse_device_provider_parent_class)->finalize (object);
+}
+
+
+static void
+gst_pulse_device_provider_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstPulseDeviceProvider *self = GST_PULSE_DEVICE_PROVIDER (object);
+
+  switch (prop_id) {
+    case PROP_SERVER:
+      g_free (self->server);
+      self->server = g_value_dup_string (value);
+      break;
+    case PROP_CLIENT_NAME:
+      g_free (self->client_name);
+      if (!g_value_get_string (value)) {
+        GST_WARNING_OBJECT (self,
+            "Empty PulseAudio client name not allowed. "
+            "Resetting to default value");
+        self->client_name = gst_pulse_client_name ();
+      } else
+        self->client_name = g_value_dup_string (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_pulse_device_provider_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstPulseDeviceProvider *self = GST_PULSE_DEVICE_PROVIDER (object);
+
+  switch (prop_id) {
+    case PROP_SERVER:
+      g_value_set_string (value, self->server);
+      break;
+    case PROP_CLIENT_NAME:
+      g_value_set_string (value, self->client_name);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+context_state_cb (pa_context * c, void *userdata)
+{
+  GstPulseDeviceProvider *self = userdata;
+
+  switch (pa_context_get_state (c)) {
+    case PA_CONTEXT_READY:
+    case PA_CONTEXT_TERMINATED:
+    case PA_CONTEXT_FAILED:
+      pa_threaded_mainloop_signal (self->mainloop, 0);
+      break;
+
+    case PA_CONTEXT_UNCONNECTED:
+    case PA_CONTEXT_CONNECTING:
+    case PA_CONTEXT_AUTHORIZING:
+    case PA_CONTEXT_SETTING_NAME:
+      break;
+  }
+}
+
+static GstDevice *
+new_source (const pa_source_info * info)
+{
+  GstCaps *caps;
+  GstStructure *props;
+  guint i;
+
+  caps = gst_caps_new_empty ();
+
+  for (i = 0; i < info->n_formats; i++)
+    gst_caps_append (caps, gst_pulse_format_info_to_caps (info->formats[i]));
+
+  props = gst_pulse_make_structure (info->proplist);
+
+  return gst_pulse_device_new (info->index, info->description,
+      caps, info->name, GST_PULSE_DEVICE_TYPE_SOURCE, props);
+}
+
+static GstDevice *
+new_sink (const pa_sink_info * info)
+{
+  GstCaps *caps;
+  GstStructure *props;
+  guint i;
+
+  caps = gst_caps_new_empty ();
+
+  for (i = 0; i < info->n_formats; i++)
+    gst_caps_append (caps, gst_pulse_format_info_to_caps (info->formats[i]));
+
+  props = gst_pulse_make_structure (info->proplist);
+
+  return gst_pulse_device_new (info->index, info->description,
+      caps, info->name, GST_PULSE_DEVICE_TYPE_SINK, props);
+}
+
+static void
+get_source_info_cb (pa_context * context,
+    const pa_source_info * info, int eol, void *userdata)
+{
+  GstPulseDeviceProvider *self = userdata;
+  GstDevice *dev;
+
+  if (eol) {
+    pa_threaded_mainloop_signal (self->mainloop, 0);
+    return;
+  }
+
+  dev = new_source (info);
+
+  if (dev)
+    gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), dev);
+}
+
+static void
+get_sink_info_cb (pa_context * context,
+    const pa_sink_info * info, int eol, void *userdata)
+{
+  GstPulseDeviceProvider *self = userdata;
+  GstDevice *dev;
+
+  if (eol) {
+    pa_threaded_mainloop_signal (self->mainloop, 0);
+    return;
+  }
+
+  dev = new_sink (info);
+
+  if (dev)
+    gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), dev);
+}
+
+static void
+context_subscribe_cb (pa_context * context, pa_subscription_event_type_t type,
+    uint32_t idx, void *userdata)
+{
+  GstPulseDeviceProvider *self = userdata;
+  GstDeviceProvider *provider = userdata;
+  pa_subscription_event_type_t facility =
+      type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
+  pa_subscription_event_type_t event_type =
+      type & PA_SUBSCRIPTION_EVENT_TYPE_MASK;
+
+  if (facility != PA_SUBSCRIPTION_EVENT_SOURCE &&
+      facility != PA_SUBSCRIPTION_EVENT_SINK)
+    return;
+
+  if (event_type == PA_SUBSCRIPTION_EVENT_NEW) {
+    /* Microphone in the source output has changed */
+
+    if (facility == PA_SUBSCRIPTION_EVENT_SOURCE)
+      pa_context_get_source_info_by_index (context, idx, get_source_info_cb,
+          self);
+    else if (facility == PA_SUBSCRIPTION_EVENT_SINK)
+      pa_context_get_sink_info_by_index (context, idx, get_sink_info_cb, self);
+  } else if (event_type == PA_SUBSCRIPTION_EVENT_REMOVE) {
+    GstPulseDevice *dev = NULL;
+    GList *item;
+
+    GST_OBJECT_LOCK (self);
+    for (item = provider->devices; item; item = item->next) {
+      dev = item->data;
+
+      if (((facility == PA_SUBSCRIPTION_EVENT_SOURCE &&
+                  dev->type == GST_PULSE_DEVICE_TYPE_SOURCE) ||
+              (facility == PA_SUBSCRIPTION_EVENT_SINK &&
+                  dev->type == GST_PULSE_DEVICE_TYPE_SINK)) &&
+          dev->device_index == idx) {
+        gst_object_ref (dev);
+        break;
+      }
+      dev = NULL;
+    }
+    GST_OBJECT_UNLOCK (self);
+
+    if (dev) {
+      gst_device_provider_device_remove (GST_DEVICE_PROVIDER (self),
+          GST_DEVICE (dev));
+      gst_object_unref (dev);
+    }
+  }
+}
+
+static void
+get_source_info_list_cb (pa_context * context, const pa_source_info * info,
+    int eol, void *userdata)
+{
+  GList **devices = userdata;
+
+  if (eol)
+    return;
+
+  *devices = g_list_prepend (*devices, gst_object_ref_sink (new_source (info)));
+}
+
+static void
+get_sink_info_list_cb (pa_context * context, const pa_sink_info * info,
+    int eol, void *userdata)
+{
+  GList **devices = userdata;
+
+  if (eol)
+    return;
+
+  *devices = g_list_prepend (*devices, gst_object_ref_sink (new_sink (info)));
+}
+
+static GList *
+gst_pulse_device_provider_probe (GstDeviceProvider * provider)
+{
+  GstPulseDeviceProvider *self = GST_PULSE_DEVICE_PROVIDER (provider);
+  GList *devices = NULL;
+  pa_mainloop *m = NULL;
+  pa_context *c = NULL;
+  pa_operation *o;
+
+  if (!(m = pa_mainloop_new ()))
+    return NULL;
+
+  if (!(c = pa_context_new (pa_mainloop_get_api (m), self->client_name))) {
+    GST_ERROR_OBJECT (self, "Failed to create context");
+    goto failed;
+  }
+
+  if (pa_context_connect (c, self->server, 0, NULL) < 0) {
+    GST_ERROR_OBJECT (self, "Failed to connect: %s",
+        pa_strerror (pa_context_errno (self->context)));
+    goto failed;
+  }
+
+  for (;;) {
+    pa_context_state_t state;
+
+    state = pa_context_get_state (c);
+
+    if (!PA_CONTEXT_IS_GOOD (state)) {
+      GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("Failed to connect: %s",
+              pa_strerror (pa_context_errno (c))), (NULL));
+      goto failed;
+    }
+
+    if (state == PA_CONTEXT_READY)
+      break;
+
+    /* Wait until the context is ready */
+    if (pa_mainloop_iterate (m, TRUE, NULL) < 0)
+      goto failed;
+
+  }
+  GST_DEBUG_OBJECT (self, "connected");
+
+  o = pa_context_get_sink_info_list (c, get_sink_info_list_cb, &devices);
+  while (pa_operation_get_state (o) == PA_OPERATION_RUNNING &&
+      pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+    if (pa_mainloop_iterate (m, TRUE, NULL) < 0)
+      break;
+  }
+  pa_operation_unref (o);
+
+  o = pa_context_get_source_info_list (c, get_source_info_list_cb, &devices);
+  while (pa_operation_get_state (o) == PA_OPERATION_RUNNING &&
+      pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+    if (pa_mainloop_iterate (m, TRUE, NULL) < 0)
+      break;
+  }
+  pa_operation_unref (o);
+
+  pa_context_disconnect (c);
+  pa_mainloop_free (m);
+
+  return devices;
+
+failed:
+
+  return NULL;
+}
+
+static gboolean
+gst_pulse_device_provider_start (GstDeviceProvider * provider)
+{
+  GstPulseDeviceProvider *self = GST_PULSE_DEVICE_PROVIDER (provider);
+  pa_operation *initial_operation;
+
+  if (!(self->mainloop = pa_threaded_mainloop_new ())) {
+    GST_ERROR_OBJECT (self, "Could not create pulseaudio mainloop");
+    goto mainloop_failed;
+  }
+  if (pa_threaded_mainloop_start (self->mainloop) < 0) {
+    GST_ERROR_OBJECT (self, "Could not start pulseaudio mainloop");
+    pa_threaded_mainloop_free (self->mainloop);
+    self->mainloop = NULL;
+    goto mainloop_failed;
+  }
+
+  pa_threaded_mainloop_lock (self->mainloop);
+
+  if (!(self->context =
+          pa_context_new (pa_threaded_mainloop_get_api (self->mainloop),
+              self->client_name))) {
+    GST_ERROR_OBJECT (self, "Failed to create context");
+    goto unlock_and_fail;
+  }
+
+  pa_context_set_state_callback (self->context, context_state_cb, self);
+  pa_context_set_subscribe_callback (self->context, context_subscribe_cb, self);
+
+
+  GST_DEBUG_OBJECT (self, "connect to server %s", GST_STR_NULL (self->server));
+
+  if (pa_context_connect (self->context, self->server, 0, NULL) < 0) {
+    GST_ERROR_OBJECT (self, "Failed to connect: %s",
+        pa_strerror (pa_context_errno (self->context)));
+    goto unlock_and_fail;
+  }
+
+  for (;;) {
+    pa_context_state_t state;
+
+    state = pa_context_get_state (self->context);
+
+    if (!PA_CONTEXT_IS_GOOD (state)) {
+      GST_ERROR_OBJECT (self, "Failed to connect: %s",
+          pa_strerror (pa_context_errno (self->context)));
+      goto unlock_and_fail;
+    }
+
+    if (state == PA_CONTEXT_READY)
+      break;
+
+    /* Wait until the context is ready */
+    pa_threaded_mainloop_wait (self->mainloop);
+  }
+  GST_DEBUG_OBJECT (self, "connected");
+
+  pa_context_subscribe (self->context,
+      PA_SUBSCRIPTION_MASK_SOURCE | PA_SUBSCRIPTION_MASK_SINK, NULL, NULL);
+
+  initial_operation = pa_context_get_source_info_list (self->context,
+      get_source_info_cb, self);
+  while (pa_operation_get_state (initial_operation) == PA_OPERATION_RUNNING) {
+    if (!PA_CONTEXT_IS_GOOD (pa_context_get_state ((self->context))))
+      goto cancel_and_fail;
+
+    pa_threaded_mainloop_wait (self->mainloop);
+  }
+  pa_operation_unref (initial_operation);
+
+  initial_operation = pa_context_get_sink_info_list (self->context,
+      get_sink_info_cb, self);
+  if (!initial_operation)
+    goto unlock_and_fail;
+  while (pa_operation_get_state (initial_operation) == PA_OPERATION_RUNNING) {
+    if (!PA_CONTEXT_IS_GOOD (pa_context_get_state ((self->context))))
+      goto cancel_and_fail;
+
+    pa_threaded_mainloop_wait (self->mainloop);
+  }
+  pa_operation_unref (initial_operation);
+
+  pa_threaded_mainloop_unlock (self->mainloop);
+
+  return TRUE;
+
+unlock_and_fail:
+  pa_threaded_mainloop_unlock (self->mainloop);
+  gst_pulse_device_provider_stop (provider);
+  return FALSE;
+
+mainloop_failed:
+  return FALSE;
+
+cancel_and_fail:
+  pa_operation_cancel (initial_operation);
+  pa_operation_unref (initial_operation);
+  goto unlock_and_fail;
+}
+
+static void
+gst_pulse_device_provider_stop (GstDeviceProvider * provider)
+{
+  GstPulseDeviceProvider *self = GST_PULSE_DEVICE_PROVIDER (provider);
+
+  pa_threaded_mainloop_stop (self->mainloop);
+
+  if (self->context) {
+    pa_context_disconnect (self->context);
+
+    /* Make sure we don't get any further callbacks */
+    pa_context_set_state_callback (self->context, NULL, NULL);
+    pa_context_set_subscribe_callback (self->context, NULL, NULL);
+
+    pa_context_unref (self->context);
+    self->context = NULL;
+  }
+
+  pa_threaded_mainloop_free (self->mainloop);
+  self->mainloop = NULL;
+}
+
+enum
+{
+  PROP_INTERNAL_NAME = 1,
+};
+
+G_DEFINE_TYPE (GstPulseDevice, gst_pulse_device, GST_TYPE_DEVICE);
+
+static void gst_pulse_device_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_pulse_device_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_pulse_device_finalize (GObject * object);
+static GstElement *gst_pulse_device_create_element (GstDevice * device,
+    const gchar * name);
+static gboolean gst_pulse_device_reconfigure_element (GstDevice * device,
+    GstElement * element);
+
+static void
+gst_pulse_device_class_init (GstPulseDeviceClass * klass)
+{
+  GstDeviceClass *dev_class = GST_DEVICE_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  dev_class->create_element = gst_pulse_device_create_element;
+  dev_class->reconfigure_element = gst_pulse_device_reconfigure_element;
+
+  object_class->get_property = gst_pulse_device_get_property;
+  object_class->set_property = gst_pulse_device_set_property;
+  object_class->finalize = gst_pulse_device_finalize;
+
+  g_object_class_install_property (object_class, PROP_INTERNAL_NAME,
+      g_param_spec_string ("internal-name", "Internal PulseAudio device name",
+          "The internal name of the PulseAudio device", "",
+          G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gst_pulse_device_init (GstPulseDevice * device)
+{
+}
+
+static void
+gst_pulse_device_finalize (GObject * object)
+{
+  GstPulseDevice *device = GST_PULSE_DEVICE (object);
+
+  g_free (device->internal_name);
+
+  G_OBJECT_CLASS (gst_pulse_device_parent_class)->finalize (object);
+}
+
+static GstElement *
+gst_pulse_device_create_element (GstDevice * device, const gchar * name)
+{
+  GstPulseDevice *pulse_dev = GST_PULSE_DEVICE (device);
+  GstElement *elem;
+
+  elem = gst_element_factory_make (pulse_dev->element, name);
+  g_object_set (elem, "device", pulse_dev->internal_name, NULL);
+
+  return elem;
+}
+
+static gboolean
+gst_pulse_device_reconfigure_element (GstDevice * device, GstElement * element)
+{
+  GstPulseDevice *pulse_dev = GST_PULSE_DEVICE (device);
+
+  if (!strcmp (pulse_dev->element, "pulsesrc")) {
+    if (!GST_IS_PULSESRC (element))
+      return FALSE;
+  } else if (!strcmp (pulse_dev->element, "pulsesink")) {
+    if (!GST_IS_PULSESINK (element))
+      return FALSE;
+  } else {
+    g_assert_not_reached ();
+  }
+
+  g_object_set (element, "device", pulse_dev->internal_name, NULL);
+
+  return TRUE;
+}
+
+/* Takes ownership of @caps and @props */
+static GstDevice *
+gst_pulse_device_new (guint device_index, const gchar * device_name,
+    GstCaps * caps, const gchar * internal_name, GstPulseDeviceType type,
+    GstStructure * props)
+{
+  GstPulseDevice *gstdev;
+  const gchar *element = NULL;
+  const gchar *klass = NULL;
+
+  g_return_val_if_fail (device_name, NULL);
+  g_return_val_if_fail (internal_name, NULL);
+  g_return_val_if_fail (caps, NULL);
+
+
+  switch (type) {
+    case GST_PULSE_DEVICE_TYPE_SOURCE:
+      element = "pulsesrc";
+      klass = "Audio/Source";
+      break;
+    case GST_PULSE_DEVICE_TYPE_SINK:
+      element = "pulsesink";
+      klass = "Audio/Sink";
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+
+
+  gstdev = g_object_new (GST_TYPE_PULSE_DEVICE,
+      "display-name", device_name, "caps", caps, "device-class", klass,
+      "internal-name", internal_name, "properties", props, NULL);
+
+  gstdev->type = type;
+  gstdev->device_index = device_index;
+  gstdev->element = element;
+
+  gst_structure_free (props);
+  gst_caps_unref (caps);
+
+  return GST_DEVICE (gstdev);
+}
+
+
+static void
+gst_pulse_device_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstPulseDevice *device;
+
+  device = GST_PULSE_DEVICE_CAST (object);
+
+  switch (prop_id) {
+    case PROP_INTERNAL_NAME:
+      g_value_set_string (value, device->internal_name);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+
+static void
+gst_pulse_device_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstPulseDevice *device;
+
+  device = GST_PULSE_DEVICE_CAST (object);
+
+  switch (prop_id) {
+    case PROP_INTERNAL_NAME:
+      device->internal_name = g_value_dup_string (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/ext/pulse/pulsedeviceprovider.h b/ext/pulse/pulsedeviceprovider.h
new file mode 100644
index 0000000..0892ad5
--- /dev/null
+++ b/ext/pulse/pulsedeviceprovider.h
@@ -0,0 +1,98 @@
+/* GStreamer
+ * Copyright (C) 2012 Olivier Crete <olivier.crete@collabora.com>
+ *
+ * pulsedeviceprovider.h: Device probing and monitoring
+ *
+ * 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_PULSE_DEVICE_PROVIDER_H__
+#define __GST_PULSE_DEVICE_PROVIDER_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <pulse/pulseaudio.h>
+#include <pulse/thread-mainloop.h>
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstPulseDeviceProvider GstPulseDeviceProvider;
+typedef struct _GstPulseDeviceProviderClass GstPulseDeviceProviderClass;
+
+#define GST_TYPE_PULSE_DEVICE_PROVIDER                 (gst_pulse_device_provider_get_type())
+#define GST_IS_PULSE_DEVICE_PROVIDER(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PULSE_DEVICE_PROVIDER))
+#define GST_IS_PULSE_DEVICE_PROVIDER_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PULSE_DEVICE_PROVIDER))
+#define GST_PULSE_DEVICE_PROVIDER_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PULSE_DEVICE_PROVIDER, GstPulseDeviceProviderClass))
+#define GST_PULSE_DEVICE_PROVIDER(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PULSE_DEVICE_PROVIDER, GstPulseDeviceProvider))
+#define GST_PULSE_DEVICE_PROVIDER_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE_PROVIDER, GstPulseDeviceProviderClass))
+#define GST_PULSE_DEVICE_PROVIDER_CAST(obj)            ((GstPulseDeviceProvider *)(obj))
+
+struct _GstPulseDeviceProvider {
+  GstDeviceProvider         parent;
+
+  gchar *server;
+  gchar *client_name;
+
+  pa_threaded_mainloop *mainloop;
+  pa_context *context;
+};
+
+typedef enum {
+  GST_PULSE_DEVICE_TYPE_SOURCE,
+  GST_PULSE_DEVICE_TYPE_SINK
+} GstPulseDeviceType;
+
+struct _GstPulseDeviceProviderClass {
+  GstDeviceProviderClass    parent_class;
+};
+
+GType        gst_pulse_device_provider_get_type (void);
+
+
+typedef struct _GstPulseDevice GstPulseDevice;
+typedef struct _GstPulseDeviceClass GstPulseDeviceClass;
+
+#define GST_TYPE_PULSE_DEVICE                 (gst_pulse_device_get_type())
+#define GST_IS_PULSE_DEVICE(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PULSE_DEVICE))
+#define GST_IS_PULSE_DEVICE_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PULSE_DEVICE))
+#define GST_PULSE_DEVICE_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PULSE_DEVICE, GstPulseDeviceClass))
+#define GST_PULSE_DEVICE(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PULSE_DEVICE, GstPulseDevice))
+#define GST_PULSE_DEVICE_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE, GstPulseDeviceClass))
+#define GST_PULSE_DEVICE_CAST(obj)            ((GstPulseDevice *)(obj))
+
+struct _GstPulseDevice {
+  GstDevice         parent;
+
+  GstPulseDeviceType type;
+  guint             device_index;
+  gchar            *internal_name;
+  const gchar      *element;
+};
+
+struct _GstPulseDeviceClass {
+  GstDeviceClass    parent_class;
+};
+
+GType        gst_pulse_device_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_PULSE_DEVICE_PROVIDER_H__ */
diff --git a/ext/pulse/pulsesink.c b/ext/pulse/pulsesink.c
new file mode 100644
index 0000000..521c4a6
--- /dev/null
+++ b/ext/pulse/pulsesink.c
@@ -0,0 +1,3307 @@
+/*-*- Mode: C; c-basic-offset: 2 -*-*/
+
+/*  GStreamer pulseaudio plugin
+ *
+ *  Copyright (c) 2004-2008 Lennart Poettering
+ *            (c) 2009      Wim Taymans
+ *
+ *  gst-pulse is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as
+ *  published by the Free Software Foundation; either version 2.1 of the
+ *  License, or (at your option) any later version.
+ *
+ *  gst-pulse 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with gst-pulse; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ *  USA.
+ */
+
+/**
+ * SECTION:element-pulsesink
+ * @see_also: pulsesrc
+ *
+ * This element outputs audio to a
+ * <ulink href="http://www.pulseaudio.org">PulseAudio sound server</ulink>.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! pulsesink
+ * ]| Play an Ogg/Vorbis file.
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! audioconvert ! volume volume=0.4 ! pulsesink
+ * ]| Play a 440Hz sine wave.
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! pulsesink stream-properties="props,media.title=test"
+ * ]| Play a sine wave and set a stream property. The property can be checked
+ * with "pactl list".
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include <gst/base/gstbasesink.h>
+#include <gst/gsttaglist.h>
+#include <gst/audio/audio.h>
+#include <gst/gst-i18n-plugin.h>
+
+#include <gst/pbutils/pbutils.h>        /* only used for GST_PLUGINS_BASE_VERSION_* */
+
+#include <gst/glib-compat-private.h>
+
+#include "pulsesink.h"
+#include "pulseutil.h"
+
+GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
+#define GST_CAT_DEFAULT pulse_debug
+
+#define DEFAULT_SERVER          NULL
+#define DEFAULT_DEVICE          NULL
+#define DEFAULT_CURRENT_DEVICE  NULL
+#define DEFAULT_DEVICE_NAME     NULL
+#define DEFAULT_VOLUME          1.0
+#define DEFAULT_MUTE            FALSE
+#define MAX_VOLUME              10.0
+
+enum
+{
+  PROP_0,
+  PROP_SERVER,
+  PROP_DEVICE,
+  PROP_CURRENT_DEVICE,
+  PROP_DEVICE_NAME,
+  PROP_VOLUME,
+  PROP_MUTE,
+  PROP_CLIENT_NAME,
+  PROP_STREAM_PROPERTIES,
+  PROP_LAST
+};
+
+#define GST_TYPE_PULSERING_BUFFER        \
+        (gst_pulseringbuffer_get_type())
+#define GST_PULSERING_BUFFER(obj)        \
+        (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PULSERING_BUFFER,GstPulseRingBuffer))
+#define GST_PULSERING_BUFFER_CLASS(klass) \
+        (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PULSERING_BUFFER,GstPulseRingBufferClass))
+#define GST_PULSERING_BUFFER_GET_CLASS(obj) \
+        (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PULSERING_BUFFER, GstPulseRingBufferClass))
+#define GST_PULSERING_BUFFER_CAST(obj)        \
+        ((GstPulseRingBuffer *)obj)
+#define GST_IS_PULSERING_BUFFER(obj)     \
+        (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PULSERING_BUFFER))
+#define GST_IS_PULSERING_BUFFER_CLASS(klass)\
+        (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PULSERING_BUFFER))
+
+typedef struct _GstPulseRingBuffer GstPulseRingBuffer;
+typedef struct _GstPulseRingBufferClass GstPulseRingBufferClass;
+
+typedef struct _GstPulseContext GstPulseContext;
+
+/* A note on threading.
+ *
+ * We use a pa_threaded_mainloop to interact with the PulseAudio server. This
+ * starts up a separate thread that runs a mainloop to carry back events,
+ * messages and timing updates from the PulseAudio server.
+ *
+ * In most cases, the PulseAudio API we use communicates with the server and
+ * processes replies asynchronously. Operations on PA objects that result in
+ * such communication are protected with a pa_threaded_mainloop_lock() and
+ * pa_threaded_mainloop_unlock(). These guarantee mutual exclusion with the
+ * mainloop thread -- when an iteration of the mainloop thread begins, it first
+ * tries to acquire this lock, and cannot do so if our code also holds that
+ * lock.
+ *
+ * When we need to complete an operation synchronously, we use
+ * pa_threaded_mainloop_wait() and pa_threaded_mainloop_signal(). These work
+ * much as pthread conditionals do. pa_threaded_mainloop_wait() is called with
+ * the mainloop lock held. It releases the lock (thereby allowing the mainloop
+ * to execute), and waits till one of our callbacks to be executed by the
+ * mainloop thread calls pa_threaded_mainloop_signal(). At the end of the
+ * mainloop iteration, the pa_threaded_mainloop_wait() will reacquire the
+ * mainloop lock and return control to the caller.
+ */
+
+/* Store the PA contexts in a hash table to allow easy sharing among
+ * multiple instances of the sink. Keys are $context_name@$server_name
+ * (strings) and values should be GstPulseContext pointers.
+ */
+struct _GstPulseContext
+{
+  pa_context *context;
+  GSList *ring_buffers;
+};
+
+static GHashTable *gst_pulse_shared_contexts = NULL;
+
+/* use one static main-loop for all instances
+ * this is needed to make the context sharing work as the contexts are
+ * released when releasing their parent main-loop
+ */
+static pa_threaded_mainloop *mainloop = NULL;
+static guint mainloop_ref_ct = 0;
+
+/* lock for access to shared resources */
+static GMutex pa_shared_resource_mutex;
+
+/* We keep a custom ringbuffer that is backed up by data allocated by
+ * pulseaudio. We must also overide the commit function to write into
+ * pulseaudio memory instead. */
+struct _GstPulseRingBuffer
+{
+  GstAudioRingBuffer object;
+
+  gchar *context_name;
+  gchar *stream_name;
+
+  pa_context *context;
+  pa_stream *stream;
+  pa_stream *probe_stream;
+
+  pa_format_info *format;
+  guint channels;
+  gboolean is_pcm;
+
+  void *m_data;
+  size_t m_towrite;
+  size_t m_writable;
+  gint64 m_offset;
+  gint64 m_lastoffset;
+
+  gboolean corked:1;
+  gboolean in_commit:1;
+  gboolean paused:1;
+};
+struct _GstPulseRingBufferClass
+{
+  GstAudioRingBufferClass parent_class;
+};
+
+static GType gst_pulseringbuffer_get_type (void);
+static void gst_pulseringbuffer_finalize (GObject * object);
+
+static GstAudioRingBufferClass *ring_parent_class = NULL;
+
+static gboolean gst_pulseringbuffer_open_device (GstAudioRingBuffer * buf);
+static gboolean gst_pulseringbuffer_close_device (GstAudioRingBuffer * buf);
+static gboolean gst_pulseringbuffer_acquire (GstAudioRingBuffer * buf,
+    GstAudioRingBufferSpec * spec);
+static gboolean gst_pulseringbuffer_release (GstAudioRingBuffer * buf);
+static gboolean gst_pulseringbuffer_start (GstAudioRingBuffer * buf);
+static gboolean gst_pulseringbuffer_pause (GstAudioRingBuffer * buf);
+static gboolean gst_pulseringbuffer_stop (GstAudioRingBuffer * buf);
+static void gst_pulseringbuffer_clear (GstAudioRingBuffer * buf);
+static guint gst_pulseringbuffer_commit (GstAudioRingBuffer * buf,
+    guint64 * sample, guchar * data, gint in_samples, gint out_samples,
+    gint * accum);
+
+G_DEFINE_TYPE (GstPulseRingBuffer, gst_pulseringbuffer,
+    GST_TYPE_AUDIO_RING_BUFFER);
+
+static void
+gst_pulsesink_init_contexts (void)
+{
+  g_mutex_init (&pa_shared_resource_mutex);
+  gst_pulse_shared_contexts = g_hash_table_new_full (g_str_hash, g_str_equal,
+      g_free, NULL);
+}
+
+static void
+gst_pulseringbuffer_class_init (GstPulseRingBufferClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstAudioRingBufferClass *gstringbuffer_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstringbuffer_class = (GstAudioRingBufferClass *) klass;
+
+  ring_parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gst_pulseringbuffer_finalize;
+
+  gstringbuffer_class->open_device =
+      GST_DEBUG_FUNCPTR (gst_pulseringbuffer_open_device);
+  gstringbuffer_class->close_device =
+      GST_DEBUG_FUNCPTR (gst_pulseringbuffer_close_device);
+  gstringbuffer_class->acquire =
+      GST_DEBUG_FUNCPTR (gst_pulseringbuffer_acquire);
+  gstringbuffer_class->release =
+      GST_DEBUG_FUNCPTR (gst_pulseringbuffer_release);
+  gstringbuffer_class->start = GST_DEBUG_FUNCPTR (gst_pulseringbuffer_start);
+  gstringbuffer_class->pause = GST_DEBUG_FUNCPTR (gst_pulseringbuffer_pause);
+  gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_pulseringbuffer_start);
+  gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_pulseringbuffer_stop);
+  gstringbuffer_class->clear_all =
+      GST_DEBUG_FUNCPTR (gst_pulseringbuffer_clear);
+
+  gstringbuffer_class->commit = GST_DEBUG_FUNCPTR (gst_pulseringbuffer_commit);
+}
+
+static void
+gst_pulseringbuffer_init (GstPulseRingBuffer * pbuf)
+{
+  pbuf->stream_name = NULL;
+  pbuf->context = NULL;
+  pbuf->stream = NULL;
+  pbuf->probe_stream = NULL;
+
+  pbuf->format = NULL;
+  pbuf->channels = 0;
+  pbuf->is_pcm = FALSE;
+
+  pbuf->m_data = NULL;
+  pbuf->m_towrite = 0;
+  pbuf->m_writable = 0;
+  pbuf->m_offset = 0;
+  pbuf->m_lastoffset = 0;
+
+  pbuf->corked = TRUE;
+  pbuf->in_commit = FALSE;
+  pbuf->paused = FALSE;
+}
+
+/* Call with mainloop lock held if wait == TRUE) */
+static void
+gst_pulse_destroy_stream (pa_stream * stream, gboolean wait)
+{
+  /* Make sure we don't get any further callbacks */
+  pa_stream_set_write_callback (stream, NULL, NULL);
+  pa_stream_set_underflow_callback (stream, NULL, NULL);
+  pa_stream_set_overflow_callback (stream, NULL, NULL);
+
+  pa_stream_disconnect (stream);
+
+  if (wait)
+    pa_threaded_mainloop_wait (mainloop);
+
+  pa_stream_set_state_callback (stream, NULL, NULL);
+  pa_stream_unref (stream);
+}
+
+static void
+gst_pulsering_destroy_stream (GstPulseRingBuffer * pbuf)
+{
+  if (pbuf->probe_stream) {
+    gst_pulse_destroy_stream (pbuf->probe_stream, FALSE);
+    pbuf->probe_stream = NULL;
+  }
+
+  if (pbuf->stream) {
+
+    if (pbuf->m_data) {
+      /* drop shm memory buffer */
+      pa_stream_cancel_write (pbuf->stream);
+
+      /* reset internal variables */
+      pbuf->m_data = NULL;
+      pbuf->m_towrite = 0;
+      pbuf->m_writable = 0;
+      pbuf->m_offset = 0;
+      pbuf->m_lastoffset = 0;
+    }
+    if (pbuf->format) {
+      pa_format_info_free (pbuf->format);
+      pbuf->format = NULL;
+      pbuf->channels = 0;
+      pbuf->is_pcm = FALSE;
+    }
+
+    pa_stream_disconnect (pbuf->stream);
+
+    /* Make sure we don't get any further callbacks */
+    pa_stream_set_state_callback (pbuf->stream, NULL, NULL);
+    pa_stream_set_write_callback (pbuf->stream, NULL, NULL);
+    pa_stream_set_underflow_callback (pbuf->stream, NULL, NULL);
+    pa_stream_set_overflow_callback (pbuf->stream, NULL, NULL);
+
+    pa_stream_unref (pbuf->stream);
+    pbuf->stream = NULL;
+  }
+
+  g_free (pbuf->stream_name);
+  pbuf->stream_name = NULL;
+}
+
+static void
+gst_pulsering_destroy_context (GstPulseRingBuffer * pbuf)
+{
+  g_mutex_lock (&pa_shared_resource_mutex);
+
+  GST_DEBUG_OBJECT (pbuf, "destroying ringbuffer %p", pbuf);
+
+  gst_pulsering_destroy_stream (pbuf);
+
+  if (pbuf->context) {
+    pa_context_unref (pbuf->context);
+    pbuf->context = NULL;
+  }
+
+  if (pbuf->context_name) {
+    GstPulseContext *pctx;
+
+    pctx = g_hash_table_lookup (gst_pulse_shared_contexts, pbuf->context_name);
+
+    GST_DEBUG_OBJECT (pbuf, "releasing context with name %s, pbuf=%p, pctx=%p",
+        pbuf->context_name, pbuf, pctx);
+
+    if (pctx) {
+      pctx->ring_buffers = g_slist_remove (pctx->ring_buffers, pbuf);
+      if (pctx->ring_buffers == NULL) {
+        GST_DEBUG_OBJECT (pbuf,
+            "destroying final context with name %s, pbuf=%p, pctx=%p",
+            pbuf->context_name, pbuf, pctx);
+
+        pa_context_disconnect (pctx->context);
+
+        /* Make sure we don't get any further callbacks */
+        pa_context_set_state_callback (pctx->context, NULL, NULL);
+        pa_context_set_subscribe_callback (pctx->context, NULL, NULL);
+
+        g_hash_table_remove (gst_pulse_shared_contexts, pbuf->context_name);
+
+        pa_context_unref (pctx->context);
+        g_slice_free (GstPulseContext, pctx);
+      }
+    }
+    g_free (pbuf->context_name);
+    pbuf->context_name = NULL;
+  }
+  g_mutex_unlock (&pa_shared_resource_mutex);
+}
+
+static void
+gst_pulseringbuffer_finalize (GObject * object)
+{
+  GstPulseRingBuffer *ringbuffer;
+
+  ringbuffer = GST_PULSERING_BUFFER_CAST (object);
+
+  gst_pulsering_destroy_context (ringbuffer);
+  G_OBJECT_CLASS (ring_parent_class)->finalize (object);
+}
+
+
+#define CONTEXT_OK(c) ((c) && PA_CONTEXT_IS_GOOD (pa_context_get_state ((c))))
+#define STREAM_OK(s) ((s) && PA_STREAM_IS_GOOD (pa_stream_get_state ((s))))
+
+static gboolean
+gst_pulsering_is_dead (GstPulseSink * psink, GstPulseRingBuffer * pbuf,
+    gboolean check_stream)
+{
+  if (!CONTEXT_OK (pbuf->context))
+    goto error;
+
+  if (check_stream && !STREAM_OK (pbuf->stream))
+    goto error;
+
+  return FALSE;
+
+error:
+  {
+    const gchar *err_str =
+        pbuf->context ? pa_strerror (pa_context_errno (pbuf->context)) : NULL;
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED, ("Disconnected: %s",
+            err_str), (NULL));
+    return TRUE;
+  }
+}
+
+static void
+gst_pulsering_context_state_cb (pa_context * c, void *userdata)
+{
+  pa_context_state_t state;
+  pa_threaded_mainloop *mainloop = (pa_threaded_mainloop *) userdata;
+
+  state = pa_context_get_state (c);
+
+  GST_LOG ("got new context state %d", state);
+
+  switch (state) {
+    case PA_CONTEXT_READY:
+    case PA_CONTEXT_TERMINATED:
+    case PA_CONTEXT_FAILED:
+      GST_LOG ("signaling");
+      pa_threaded_mainloop_signal (mainloop, 0);
+      break;
+
+    case PA_CONTEXT_UNCONNECTED:
+    case PA_CONTEXT_CONNECTING:
+    case PA_CONTEXT_AUTHORIZING:
+    case PA_CONTEXT_SETTING_NAME:
+      break;
+  }
+}
+
+static void
+gst_pulsering_context_subscribe_cb (pa_context * c,
+    pa_subscription_event_type_t t, uint32_t idx, void *userdata)
+{
+  GstPulseSink *psink;
+  GstPulseContext *pctx = (GstPulseContext *) userdata;
+  GSList *walk;
+
+  if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT | PA_SUBSCRIPTION_EVENT_CHANGE) &&
+      t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT | PA_SUBSCRIPTION_EVENT_NEW))
+    return;
+
+  for (walk = pctx->ring_buffers; walk; walk = g_slist_next (walk)) {
+    GstPulseRingBuffer *pbuf = (GstPulseRingBuffer *) walk->data;
+    psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+    GST_LOG_OBJECT (psink, "type %04x, idx %u", t, idx);
+
+    if (!pbuf->stream)
+      continue;
+
+    if (idx != pa_stream_get_index (pbuf->stream))
+      continue;
+
+    if (psink->device && pbuf->is_pcm &&
+        !g_str_equal (psink->device,
+            pa_stream_get_device_name (pbuf->stream))) {
+      /* Underlying sink changed. And this is not a passthrough stream. Let's
+       * see if someone upstream wants to try to renegotiate. */
+      GstEvent *renego;
+
+      g_free (psink->device);
+      psink->device = g_strdup (pa_stream_get_device_name (pbuf->stream));
+
+      GST_INFO_OBJECT (psink, "emitting sink-changed");
+
+      /* FIXME: send reconfigure event instead and let decodebin/playbin
+       * handle that. Also take care of ac3 alignment. See "pulse-format-lost" */
+      renego = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+          gst_structure_new_empty ("pulse-sink-changed"));
+
+      if (!gst_pad_push_event (GST_BASE_SINK (psink)->sinkpad, renego))
+        GST_DEBUG_OBJECT (psink, "Emitted sink-changed - nobody was listening");
+    }
+
+    /* Actually this event is also triggered when other properties of
+     * the stream change that are unrelated to the volume. However it is
+     * probably cheaper to signal the change here and check for the
+     * volume when the GObject property is read instead of querying it always. */
+
+    /* inform streaming thread to notify */
+    g_atomic_int_compare_and_exchange (&psink->notify, 0, 1);
+  }
+}
+
+/* will be called when the device should be opened. In this case we will connect
+ * to the server. We should not try to open any streams in this state. */
+static gboolean
+gst_pulseringbuffer_open_device (GstAudioRingBuffer * buf)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+  GstPulseContext *pctx;
+  pa_mainloop_api *api;
+  gboolean need_unlock_shared;
+
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (buf));
+  pbuf = GST_PULSERING_BUFFER_CAST (buf);
+
+  g_assert (!pbuf->stream);
+  g_assert (psink->client_name);
+
+  if (psink->server)
+    pbuf->context_name = g_strdup_printf ("%s@%s", psink->client_name,
+        psink->server);
+  else
+    pbuf->context_name = g_strdup (psink->client_name);
+
+  pa_threaded_mainloop_lock (mainloop);
+
+  g_mutex_lock (&pa_shared_resource_mutex);
+  need_unlock_shared = TRUE;
+
+  pctx = g_hash_table_lookup (gst_pulse_shared_contexts, pbuf->context_name);
+  if (pctx == NULL) {
+    pctx = g_slice_new0 (GstPulseContext);
+
+    /* get the mainloop api and create a context */
+    GST_INFO_OBJECT (psink, "new context with name %s, pbuf=%p, pctx=%p",
+        pbuf->context_name, pbuf, pctx);
+    api = pa_threaded_mainloop_get_api (mainloop);
+    if (!(pctx->context = pa_context_new (api, pbuf->context_name)))
+      goto create_failed;
+
+    pctx->ring_buffers = g_slist_prepend (pctx->ring_buffers, pbuf);
+    g_hash_table_insert (gst_pulse_shared_contexts,
+        g_strdup (pbuf->context_name), (gpointer) pctx);
+    /* register some essential callbacks */
+    pa_context_set_state_callback (pctx->context,
+        gst_pulsering_context_state_cb, mainloop);
+    pa_context_set_subscribe_callback (pctx->context,
+        gst_pulsering_context_subscribe_cb, pctx);
+
+    /* try to connect to the server and wait for completion, we don't want to
+     * autospawn a deamon */
+    GST_LOG_OBJECT (psink, "connect to server %s",
+        GST_STR_NULL (psink->server));
+    if (pa_context_connect (pctx->context, psink->server,
+            PA_CONTEXT_NOAUTOSPAWN, NULL) < 0)
+      goto connect_failed;
+  } else {
+    GST_INFO_OBJECT (psink,
+        "reusing shared context with name %s, pbuf=%p, pctx=%p",
+        pbuf->context_name, pbuf, pctx);
+    pctx->ring_buffers = g_slist_prepend (pctx->ring_buffers, pbuf);
+  }
+
+  g_mutex_unlock (&pa_shared_resource_mutex);
+  need_unlock_shared = FALSE;
+
+  /* context created or shared okay */
+  pbuf->context = pa_context_ref (pctx->context);
+
+  for (;;) {
+    pa_context_state_t state;
+
+    state = pa_context_get_state (pbuf->context);
+
+    GST_LOG_OBJECT (psink, "context state is now %d", state);
+
+    if (!PA_CONTEXT_IS_GOOD (state))
+      goto connect_failed;
+
+    if (state == PA_CONTEXT_READY)
+      break;
+
+    /* Wait until the context is ready */
+    GST_LOG_OBJECT (psink, "waiting..");
+    pa_threaded_mainloop_wait (mainloop);
+  }
+
+  if (pa_context_get_server_protocol_version (pbuf->context) < 22) {
+    /* We need PulseAudio >= 1.0 on the server side for the extended API */
+    goto bad_server_version;
+  }
+
+  GST_LOG_OBJECT (psink, "opened the device");
+
+  pa_threaded_mainloop_unlock (mainloop);
+
+  return TRUE;
+
+  /* ERRORS */
+unlock_and_fail:
+  {
+    if (need_unlock_shared)
+      g_mutex_unlock (&pa_shared_resource_mutex);
+    gst_pulsering_destroy_context (pbuf);
+    pa_threaded_mainloop_unlock (mainloop);
+    return FALSE;
+  }
+create_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("Failed to create context"), (NULL));
+    g_slice_free (GstPulseContext, pctx);
+    goto unlock_and_fail;
+  }
+connect_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED, ("Failed to connect: %s",
+            pa_strerror (pa_context_errno (pctx->context))), (NULL));
+    goto unlock_and_fail;
+  }
+bad_server_version:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED, ("PulseAudio server version "
+            "is too old."), (NULL));
+    goto unlock_and_fail;
+  }
+}
+
+/* close the device */
+static gboolean
+gst_pulseringbuffer_close_device (GstAudioRingBuffer * buf)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+
+  pbuf = GST_PULSERING_BUFFER_CAST (buf);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (buf));
+
+  GST_LOG_OBJECT (psink, "closing device");
+
+  pa_threaded_mainloop_lock (mainloop);
+  gst_pulsering_destroy_context (pbuf);
+  pa_threaded_mainloop_unlock (mainloop);
+
+  GST_LOG_OBJECT (psink, "closed device");
+
+  return TRUE;
+}
+
+static void
+gst_pulsering_stream_state_cb (pa_stream * s, void *userdata)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+  pa_stream_state_t state;
+
+  pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+  state = pa_stream_get_state (s);
+  GST_LOG_OBJECT (psink, "got new stream state %d", state);
+
+  switch (state) {
+    case PA_STREAM_READY:
+    case PA_STREAM_FAILED:
+    case PA_STREAM_TERMINATED:
+      GST_LOG_OBJECT (psink, "signaling");
+      pa_threaded_mainloop_signal (mainloop, 0);
+      break;
+    case PA_STREAM_UNCONNECTED:
+    case PA_STREAM_CREATING:
+      break;
+  }
+}
+
+static void
+gst_pulsering_stream_request_cb (pa_stream * s, size_t length, void *userdata)
+{
+  GstPulseSink *psink;
+  GstAudioRingBuffer *rbuf;
+  GstPulseRingBuffer *pbuf;
+
+  rbuf = GST_AUDIO_RING_BUFFER_CAST (userdata);
+  pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+  GST_LOG_OBJECT (psink, "got request for length %" G_GSIZE_FORMAT, length);
+
+  if (pbuf->in_commit && (length >= rbuf->spec.segsize)) {
+    /* only signal when we are waiting in the commit thread
+     * and got request for atleast a segment */
+    pa_threaded_mainloop_signal (mainloop, 0);
+  }
+}
+
+static void
+gst_pulsering_stream_underflow_cb (pa_stream * s, void *userdata)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+
+  pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+  GST_WARNING_OBJECT (psink, "Got underflow");
+}
+
+static void
+gst_pulsering_stream_overflow_cb (pa_stream * s, void *userdata)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+
+  pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+  GST_WARNING_OBJECT (psink, "Got overflow");
+}
+
+static void
+gst_pulsering_stream_latency_cb (pa_stream * s, void *userdata)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+  GstAudioRingBuffer *ringbuf;
+  const pa_timing_info *info;
+  pa_usec_t sink_usec;
+
+  info = pa_stream_get_timing_info (s);
+
+  pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+  ringbuf = GST_AUDIO_RING_BUFFER (pbuf);
+
+  if (!info) {
+    GST_LOG_OBJECT (psink, "latency update (information unknown)");
+    return;
+  }
+
+  if (!info->read_index_corrupt) {
+    /* Update segdone based on the read index. segdone is of segment
+     * granularity, while the read index is at byte granularity. We take the
+     * ceiling while converting the latter to the former since it is more
+     * conservative to report that we've read more than we have than to report
+     * less. One concern here is that latency updates happen every 100ms, which
+     * means segdone is not updated very often, but increasing the update
+     * frequency would mean more communication overhead. */
+    g_atomic_int_set (&ringbuf->segdone,
+        (int) gst_util_uint64_scale_ceil (info->read_index, 1,
+            ringbuf->spec.segsize));
+  }
+
+  sink_usec = info->configured_sink_usec;
+
+  GST_LOG_OBJECT (psink,
+      "latency_update, %" G_GUINT64_FORMAT ", %d:%" G_GINT64_FORMAT ", %d:%"
+      G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT,
+      GST_TIMEVAL_TO_TIME (info->timestamp), info->write_index_corrupt,
+      info->write_index, info->read_index_corrupt, info->read_index,
+      info->sink_usec, sink_usec);
+}
+
+static void
+gst_pulsering_stream_suspended_cb (pa_stream * p, void *userdata)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+
+  pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+  if (pa_stream_is_suspended (p))
+    GST_DEBUG_OBJECT (psink, "stream suspended");
+  else
+    GST_DEBUG_OBJECT (psink, "stream resumed");
+}
+
+static void
+gst_pulsering_stream_started_cb (pa_stream * p, void *userdata)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+
+  pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+  GST_DEBUG_OBJECT (psink, "stream started");
+}
+
+static void
+gst_pulsering_stream_event_cb (pa_stream * p, const char *name,
+    pa_proplist * pl, void *userdata)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+
+  pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+  if (!strcmp (name, PA_STREAM_EVENT_REQUEST_CORK)) {
+    /* the stream wants to PAUSE, post a message for the application. */
+    GST_DEBUG_OBJECT (psink, "got request for CORK");
+    gst_element_post_message (GST_ELEMENT_CAST (psink),
+        gst_message_new_request_state (GST_OBJECT_CAST (psink),
+            GST_STATE_PAUSED));
+
+  } else if (!strcmp (name, PA_STREAM_EVENT_REQUEST_UNCORK)) {
+    GST_DEBUG_OBJECT (psink, "got request for UNCORK");
+    gst_element_post_message (GST_ELEMENT_CAST (psink),
+        gst_message_new_request_state (GST_OBJECT_CAST (psink),
+            GST_STATE_PLAYING));
+  } else if (!strcmp (name, PA_STREAM_EVENT_FORMAT_LOST)) {
+    GstEvent *renego;
+
+    if (g_atomic_int_get (&psink->format_lost)) {
+      /* Duplicate event before we're done reconfiguring, discard */
+      return;
+    }
+
+    GST_DEBUG_OBJECT (psink, "got FORMAT LOST");
+    g_atomic_int_set (&psink->format_lost, 1);
+    psink->format_lost_time = g_ascii_strtoull (pa_proplist_gets (pl,
+            "stream-time"), NULL, 0) * 1000;
+
+    g_free (psink->device);
+    psink->device = g_strdup (pa_proplist_gets (pl, "device"));
+
+    /* FIXME: send reconfigure event instead and let decodebin/playbin
+     * handle that. Also take care of ac3 alignment */
+    renego = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+        gst_structure_new_empty ("pulse-format-lost"));
+
+#if 0
+    if (g_str_equal (gst_structure_get_name (st), "audio/x-eac3")) {
+      GstStructure *event_st = gst_structure_new ("ac3parse-set-alignment",
+          "alignment", G_TYPE_STRING, pbin->dbin ? "frame" : "iec61937", NULL);
+
+      if (!gst_pad_push_event (pbin->sinkpad,
+              gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, event_st)))
+        GST_WARNING_OBJECT (pbin->sinkpad, "Could not update alignment");
+    }
+#endif
+
+    if (!gst_pad_push_event (GST_BASE_SINK (psink)->sinkpad, renego)) {
+      /* Nobody handled the format change - emit an error */
+      GST_ELEMENT_ERROR (psink, STREAM, FORMAT, ("Sink format changed"),
+          ("Sink format changed"));
+    }
+  } else {
+    GST_DEBUG_OBJECT (psink, "got unknown event %s", name);
+  }
+}
+
+/* Called with the mainloop locked */
+static gboolean
+gst_pulsering_wait_for_stream_ready (GstPulseSink * psink, pa_stream * stream)
+{
+  pa_stream_state_t state;
+
+  for (;;) {
+    state = pa_stream_get_state (stream);
+
+    GST_LOG_OBJECT (psink, "stream state is now %d", state);
+
+    if (!PA_STREAM_IS_GOOD (state))
+      return FALSE;
+
+    if (state == PA_STREAM_READY)
+      return TRUE;
+
+    /* Wait until the stream is ready */
+    pa_threaded_mainloop_wait (mainloop);
+  }
+}
+
+
+/* This method should create a new stream of the given @spec. No playback should
+ * start yet so we start in the corked state. */
+static gboolean
+gst_pulseringbuffer_acquire (GstAudioRingBuffer * buf,
+    GstAudioRingBufferSpec * spec)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+  pa_buffer_attr wanted;
+  const pa_buffer_attr *actual;
+  pa_channel_map channel_map;
+  pa_operation *o = NULL;
+  pa_cvolume v;
+  pa_cvolume *pv = NULL;
+  pa_stream_flags_t flags;
+  const gchar *name;
+  GstAudioClock *clock;
+  pa_format_info *formats[1];
+#ifndef GST_DISABLE_GST_DEBUG
+  gchar print_buf[PA_FORMAT_INFO_SNPRINT_MAX];
+#endif
+
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (buf));
+  pbuf = GST_PULSERING_BUFFER_CAST (buf);
+
+  GST_LOG_OBJECT (psink, "creating sample spec");
+  /* convert the gstreamer sample spec to the pulseaudio format */
+  if (!gst_pulse_fill_format_info (spec, &pbuf->format, &pbuf->channels))
+    goto invalid_spec;
+  pbuf->is_pcm = pa_format_info_is_pcm (pbuf->format);
+
+  pa_threaded_mainloop_lock (mainloop);
+
+  /* we need a context and a no stream */
+  g_assert (pbuf->context);
+  g_assert (!pbuf->stream);
+
+  /* if we have a probe, disconnect it first so that if we're creating a
+   * compressed stream, it doesn't get blocked by a PCM stream */
+  if (pbuf->probe_stream) {
+    gst_pulse_destroy_stream (pbuf->probe_stream, TRUE);
+    pbuf->probe_stream = NULL;
+  }
+
+  /* enable event notifications */
+  GST_LOG_OBJECT (psink, "subscribing to context events");
+  if (!(o = pa_context_subscribe (pbuf->context,
+              PA_SUBSCRIPTION_MASK_SINK_INPUT, NULL, NULL)))
+    goto subscribe_failed;
+
+  pa_operation_unref (o);
+
+  /* initialize the channel map */
+  if (pbuf->is_pcm && gst_pulse_gst_to_channel_map (&channel_map, spec))
+    pa_format_info_set_channel_map (pbuf->format, &channel_map);
+
+  /* find a good name for the stream */
+  if (psink->stream_name)
+    name = psink->stream_name;
+  else
+    name = "Playback Stream";
+
+  /* create a stream */
+  formats[0] = pbuf->format;
+  if (!(pbuf->stream = pa_stream_new_extended (pbuf->context, name, formats, 1,
+              psink->proplist)))
+    goto stream_failed;
+
+  /* install essential callbacks */
+  pa_stream_set_state_callback (pbuf->stream,
+      gst_pulsering_stream_state_cb, pbuf);
+  pa_stream_set_write_callback (pbuf->stream,
+      gst_pulsering_stream_request_cb, pbuf);
+  pa_stream_set_underflow_callback (pbuf->stream,
+      gst_pulsering_stream_underflow_cb, pbuf);
+  pa_stream_set_overflow_callback (pbuf->stream,
+      gst_pulsering_stream_overflow_cb, pbuf);
+  pa_stream_set_latency_update_callback (pbuf->stream,
+      gst_pulsering_stream_latency_cb, pbuf);
+  pa_stream_set_suspended_callback (pbuf->stream,
+      gst_pulsering_stream_suspended_cb, pbuf);
+  pa_stream_set_started_callback (pbuf->stream,
+      gst_pulsering_stream_started_cb, pbuf);
+  pa_stream_set_event_callback (pbuf->stream,
+      gst_pulsering_stream_event_cb, pbuf);
+
+  /* buffering requirements. When setting prebuf to 0, the stream will not pause
+   * when we cause an underrun, which causes time to continue. */
+  memset (&wanted, 0, sizeof (wanted));
+  wanted.tlength = spec->segtotal * spec->segsize;
+  wanted.maxlength = -1;
+  wanted.prebuf = 0;
+  wanted.minreq = spec->segsize;
+
+  GST_INFO_OBJECT (psink, "tlength:   %d", wanted.tlength);
+  GST_INFO_OBJECT (psink, "maxlength: %d", wanted.maxlength);
+  GST_INFO_OBJECT (psink, "prebuf:    %d", wanted.prebuf);
+  GST_INFO_OBJECT (psink, "minreq:    %d", wanted.minreq);
+
+  /* configure volume when we changed it, else we leave the default */
+  if (psink->volume_set) {
+    GST_LOG_OBJECT (psink, "have volume of %f", psink->volume);
+    pv = &v;
+    if (pbuf->is_pcm)
+      gst_pulse_cvolume_from_linear (pv, pbuf->channels, psink->volume);
+    else {
+      GST_DEBUG_OBJECT (psink, "passthrough stream, not setting volume");
+      pv = NULL;
+    }
+  } else {
+    pv = NULL;
+  }
+
+  /* construct the flags */
+  flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE |
+      PA_STREAM_ADJUST_LATENCY | PA_STREAM_START_CORKED;
+
+  if (psink->mute_set) {
+    if (psink->mute)
+      flags |= PA_STREAM_START_MUTED;
+    else
+      flags |= PA_STREAM_START_UNMUTED;
+  }
+
+  /* we always start corked (see flags above) */
+  pbuf->corked = TRUE;
+
+  /* try to connect now */
+  GST_LOG_OBJECT (psink, "connect for playback to device %s",
+      GST_STR_NULL (psink->device));
+  if (pa_stream_connect_playback (pbuf->stream, psink->device,
+          &wanted, flags, pv, NULL) < 0)
+    goto connect_failed;
+
+  /* our clock will now start from 0 again */
+  clock = GST_AUDIO_CLOCK (GST_AUDIO_BASE_SINK (psink)->provided_clock);
+  gst_audio_clock_reset (clock, 0);
+
+  if (!gst_pulsering_wait_for_stream_ready (psink, pbuf->stream))
+    goto connect_failed;
+
+  g_free (psink->device);
+  psink->device = g_strdup (pa_stream_get_device_name (pbuf->stream));
+
+#ifndef GST_DISABLE_GST_DEBUG
+  pa_format_info_snprint (print_buf, sizeof (print_buf),
+      pa_stream_get_format_info (pbuf->stream));
+  GST_INFO_OBJECT (psink, "negotiated to: %s", print_buf);
+#endif
+
+  /* After we passed the volume off of to PA we never want to set it
+     again, since it is PA's job to save/restore volumes.  */
+  psink->volume_set = psink->mute_set = FALSE;
+
+  GST_LOG_OBJECT (psink, "stream is acquired now");
+
+  /* get the actual buffering properties now */
+  actual = pa_stream_get_buffer_attr (pbuf->stream);
+
+  GST_INFO_OBJECT (psink, "tlength:   %d (wanted: %d)", actual->tlength,
+      wanted.tlength);
+  GST_INFO_OBJECT (psink, "maxlength: %d", actual->maxlength);
+  GST_INFO_OBJECT (psink, "prebuf:    %d", actual->prebuf);
+  GST_INFO_OBJECT (psink, "minreq:    %d (wanted %d)", actual->minreq,
+      wanted.minreq);
+
+  spec->segsize = actual->minreq;
+  spec->segtotal = actual->tlength / spec->segsize;
+
+  pa_threaded_mainloop_unlock (mainloop);
+
+  return TRUE;
+
+  /* ERRORS */
+unlock_and_fail:
+  {
+    gst_pulsering_destroy_stream (pbuf);
+    pa_threaded_mainloop_unlock (mainloop);
+
+    return FALSE;
+  }
+invalid_spec:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, SETTINGS,
+        ("Invalid sample specification."), (NULL));
+    return FALSE;
+  }
+subscribe_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("pa_context_subscribe() failed: %s",
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto unlock_and_fail;
+  }
+stream_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("Failed to create stream: %s",
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto unlock_and_fail;
+  }
+connect_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("Failed to connect stream: %s",
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto unlock_and_fail;
+  }
+}
+
+/* free the stream that we acquired before */
+static gboolean
+gst_pulseringbuffer_release (GstAudioRingBuffer * buf)
+{
+  GstPulseRingBuffer *pbuf;
+
+  pbuf = GST_PULSERING_BUFFER_CAST (buf);
+
+  pa_threaded_mainloop_lock (mainloop);
+  gst_pulsering_destroy_stream (pbuf);
+  pa_threaded_mainloop_unlock (mainloop);
+
+  {
+    GstPulseSink *psink;
+
+    psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+    g_atomic_int_set (&psink->format_lost, FALSE);
+    psink->format_lost_time = GST_CLOCK_TIME_NONE;
+  }
+
+  return TRUE;
+}
+
+static void
+gst_pulsering_success_cb (pa_stream * s, int success, void *userdata)
+{
+  pa_threaded_mainloop_signal (mainloop, 0);
+}
+
+/* update the corked state of a stream, must be called with the mainloop
+ * lock */
+static gboolean
+gst_pulsering_set_corked (GstPulseRingBuffer * pbuf, gboolean corked,
+    gboolean wait)
+{
+  pa_operation *o = NULL;
+  GstPulseSink *psink;
+  gboolean res = FALSE;
+
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+  if (g_atomic_int_get (&psink->format_lost)) {
+    /* Sink format changed, stream's gone so fake being paused */
+    return TRUE;
+  }
+
+  GST_DEBUG_OBJECT (psink, "setting corked state to %d", corked);
+  if (pbuf->corked != corked) {
+    if (!(o = pa_stream_cork (pbuf->stream, corked,
+                gst_pulsering_success_cb, pbuf)))
+      goto cork_failed;
+
+    while (wait && pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+      pa_threaded_mainloop_wait (mainloop);
+      if (gst_pulsering_is_dead (psink, pbuf, TRUE))
+        goto server_dead;
+    }
+    pbuf->corked = corked;
+  } else {
+    GST_DEBUG_OBJECT (psink, "skipping, already in requested state");
+  }
+  res = TRUE;
+
+cleanup:
+  if (o)
+    pa_operation_unref (o);
+
+  return res;
+
+  /* ERRORS */
+server_dead:
+  {
+    GST_DEBUG_OBJECT (psink, "the server is dead");
+    goto cleanup;
+  }
+cork_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("pa_stream_cork() failed: %s",
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto cleanup;
+  }
+}
+
+static void
+gst_pulseringbuffer_clear (GstAudioRingBuffer * buf)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+  pa_operation *o = NULL;
+
+  pbuf = GST_PULSERING_BUFFER_CAST (buf);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+  pa_threaded_mainloop_lock (mainloop);
+  GST_DEBUG_OBJECT (psink, "clearing");
+  if (pbuf->stream) {
+    /* don't wait for the flush to complete */
+    if ((o = pa_stream_flush (pbuf->stream, NULL, pbuf)))
+      pa_operation_unref (o);
+  }
+  pa_threaded_mainloop_unlock (mainloop);
+}
+
+#if 0
+/* called from pulse thread with the mainloop lock */
+static void
+mainloop_enter_defer_cb (pa_mainloop_api * api, void *userdata)
+{
+  GstPulseSink *pulsesink = GST_PULSESINK (userdata);
+  GstMessage *message;
+  GValue val = { 0 };
+
+  GST_DEBUG_OBJECT (pulsesink, "posting ENTER stream status");
+  message = gst_message_new_stream_status (GST_OBJECT (pulsesink),
+      GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT (pulsesink));
+  g_value_init (&val, GST_TYPE_G_THREAD);
+  g_value_set_boxed (&val, g_thread_self ());
+  gst_message_set_stream_status_object (message, &val);
+  g_value_unset (&val);
+
+  gst_element_post_message (GST_ELEMENT (pulsesink), message);
+
+  g_return_if_fail (pulsesink->defer_pending);
+  pulsesink->defer_pending--;
+  pa_threaded_mainloop_signal (mainloop, 0);
+}
+#endif
+
+/* start/resume playback ASAP, we don't uncork here but in the commit method */
+static gboolean
+gst_pulseringbuffer_start (GstAudioRingBuffer * buf)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+
+  pbuf = GST_PULSERING_BUFFER_CAST (buf);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+  pa_threaded_mainloop_lock (mainloop);
+
+  GST_DEBUG_OBJECT (psink, "starting");
+  pbuf->paused = FALSE;
+
+  /* EOS needs running clock */
+  if (GST_BASE_SINK_CAST (psink)->eos ||
+      g_atomic_int_get (&GST_AUDIO_BASE_SINK (psink)->eos_rendering))
+    gst_pulsering_set_corked (pbuf, FALSE, FALSE);
+
+#if 0
+  GST_DEBUG_OBJECT (psink, "scheduling stream status");
+  psink->defer_pending++;
+  pa_mainloop_api_once (pa_threaded_mainloop_get_api (mainloop),
+      mainloop_enter_defer_cb, psink);
+
+  /* Wait for the stream status message to be posted. This needs to be done
+   * synchronously because the callback will take the mainloop lock
+   * (implicitly) and then take the GST_OBJECT_LOCK. Everywhere else, we take
+   * the locks in the reverse order, so not doing this synchronously could
+   * cause a deadlock. */
+  GST_DEBUG_OBJECT (psink, "waiting for stream status (ENTER) to be posted");
+  pa_threaded_mainloop_wait (mainloop);
+#endif
+
+  pa_threaded_mainloop_unlock (mainloop);
+
+  return TRUE;
+}
+
+/* pause/stop playback ASAP */
+static gboolean
+gst_pulseringbuffer_pause (GstAudioRingBuffer * buf)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+  gboolean res;
+
+  pbuf = GST_PULSERING_BUFFER_CAST (buf);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+  pa_threaded_mainloop_lock (mainloop);
+  GST_DEBUG_OBJECT (psink, "pausing and corking");
+  /* make sure the commit method stops writing */
+  pbuf->paused = TRUE;
+  res = gst_pulsering_set_corked (pbuf, TRUE, TRUE);
+  if (pbuf->in_commit) {
+    /* we are waiting in a commit, signal */
+    GST_DEBUG_OBJECT (psink, "signal commit");
+    pa_threaded_mainloop_signal (mainloop, 0);
+  }
+  pa_threaded_mainloop_unlock (mainloop);
+
+  return res;
+}
+
+#if 0
+/* called from pulse thread with the mainloop lock */
+static void
+mainloop_leave_defer_cb (pa_mainloop_api * api, void *userdata)
+{
+  GstPulseSink *pulsesink = GST_PULSESINK (userdata);
+  GstMessage *message;
+  GValue val = { 0 };
+
+  GST_DEBUG_OBJECT (pulsesink, "posting LEAVE stream status");
+  message = gst_message_new_stream_status (GST_OBJECT (pulsesink),
+      GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT (pulsesink));
+  g_value_init (&val, GST_TYPE_G_THREAD);
+  g_value_set_boxed (&val, g_thread_self ());
+  gst_message_set_stream_status_object (message, &val);
+  g_value_unset (&val);
+
+  gst_element_post_message (GST_ELEMENT (pulsesink), message);
+
+  g_return_if_fail (pulsesink->defer_pending);
+  pulsesink->defer_pending--;
+  pa_threaded_mainloop_signal (mainloop, 0);
+}
+#endif
+
+/* stop playback, we flush everything. */
+static gboolean
+gst_pulseringbuffer_stop (GstAudioRingBuffer * buf)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+  gboolean res = FALSE;
+  pa_operation *o = NULL;
+
+  pbuf = GST_PULSERING_BUFFER_CAST (buf);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+  pa_threaded_mainloop_lock (mainloop);
+
+  pbuf->paused = TRUE;
+  res = gst_pulsering_set_corked (pbuf, TRUE, TRUE);
+
+  /* Inform anyone waiting in _commit() call that it shall wakeup */
+  if (pbuf->in_commit) {
+    GST_DEBUG_OBJECT (psink, "signal commit thread");
+    pa_threaded_mainloop_signal (mainloop, 0);
+  }
+  if (g_atomic_int_get (&psink->format_lost)) {
+    /* Don't try to flush, the stream's probably gone by now */
+    res = TRUE;
+    goto cleanup;
+  }
+
+  /* then try to flush, it's not fatal when this fails */
+  GST_DEBUG_OBJECT (psink, "flushing");
+  if ((o = pa_stream_flush (pbuf->stream, gst_pulsering_success_cb, pbuf))) {
+    while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+      GST_DEBUG_OBJECT (psink, "wait for completion");
+      pa_threaded_mainloop_wait (mainloop);
+      if (gst_pulsering_is_dead (psink, pbuf, TRUE))
+        goto server_dead;
+    }
+    GST_DEBUG_OBJECT (psink, "flush completed");
+  }
+  res = TRUE;
+
+cleanup:
+  if (o) {
+    pa_operation_cancel (o);
+    pa_operation_unref (o);
+  }
+#if 0
+  GST_DEBUG_OBJECT (psink, "scheduling stream status");
+  psink->defer_pending++;
+  pa_mainloop_api_once (pa_threaded_mainloop_get_api (mainloop),
+      mainloop_leave_defer_cb, psink);
+
+  /* Wait for the stream status message to be posted. This needs to be done
+   * synchronously because the callback will take the mainloop lock
+   * (implicitly) and then take the GST_OBJECT_LOCK. Everywhere else, we take
+   * the locks in the reverse order, so not doing this synchronously could
+   * cause a deadlock. */
+  GST_DEBUG_OBJECT (psink, "waiting for stream status (LEAVE) to be posted");
+  pa_threaded_mainloop_wait (mainloop);
+#endif
+
+  pa_threaded_mainloop_unlock (mainloop);
+
+  return res;
+
+  /* ERRORS */
+server_dead:
+  {
+    GST_DEBUG_OBJECT (psink, "the server is dead");
+    goto cleanup;
+  }
+}
+
+/* in_samples >= out_samples, rate > 1.0 */
+#define FWD_UP_SAMPLES(s,se,d,de)               \
+G_STMT_START {                                  \
+  guint8 *sb = s, *db = d;                      \
+  while (s <= se && d < de) {                   \
+    memcpy (d, s, bpf);                         \
+    s += bpf;                                   \
+    *accum += outr;                             \
+    if ((*accum << 1) >= inr) {                 \
+      *accum -= inr;                            \
+      d += bpf;                                 \
+    }                                           \
+  }                                             \
+  in_samples -= (s - sb)/bpf;                   \
+  out_samples -= (d - db)/bpf;                  \
+  GST_DEBUG ("fwd_up end %d/%d",*accum,*toprocess);     \
+} G_STMT_END
+
+/* out_samples > in_samples, for rates smaller than 1.0 */
+#define FWD_DOWN_SAMPLES(s,se,d,de)             \
+G_STMT_START {                                  \
+  guint8 *sb = s, *db = d;                      \
+  while (s <= se && d < de) {                   \
+    memcpy (d, s, bpf);                         \
+    d += bpf;                                   \
+    *accum += inr;                              \
+    if ((*accum << 1) >= outr) {                \
+      *accum -= outr;                           \
+      s += bpf;                                 \
+    }                                           \
+  }                                             \
+  in_samples -= (s - sb)/bpf;                   \
+  out_samples -= (d - db)/bpf;                  \
+  GST_DEBUG ("fwd_down end %d/%d",*accum,*toprocess);   \
+} G_STMT_END
+
+#define REV_UP_SAMPLES(s,se,d,de)               \
+G_STMT_START {                                  \
+  guint8 *sb = se, *db = d;                     \
+  while (s <= se && d < de) {                   \
+    memcpy (d, se, bpf);                        \
+    se -= bpf;                                  \
+    *accum += outr;                             \
+    while (d < de && (*accum << 1) >= inr) {    \
+      *accum -= inr;                            \
+      d += bpf;                                 \
+    }                                           \
+  }                                             \
+  in_samples -= (sb - se)/bpf;                  \
+  out_samples -= (d - db)/bpf;                  \
+  GST_DEBUG ("rev_up end %d/%d",*accum,*toprocess);     \
+} G_STMT_END
+
+#define REV_DOWN_SAMPLES(s,se,d,de)             \
+G_STMT_START {                                  \
+  guint8 *sb = se, *db = d;                     \
+  while (s <= se && d < de) {                   \
+    memcpy (d, se, bpf);                        \
+    d += bpf;                                   \
+    *accum += inr;                              \
+    while (s <= se && (*accum << 1) >= outr) {  \
+      *accum -= outr;                           \
+      se -= bpf;                                \
+    }                                           \
+  }                                             \
+  in_samples -= (sb - se)/bpf;                  \
+  out_samples -= (d - db)/bpf;                  \
+  GST_DEBUG ("rev_down end %d/%d",*accum,*toprocess);   \
+} G_STMT_END
+
+/* our custom commit function because we write into the buffer of pulseaudio
+ * instead of keeping our own buffer */
+static guint
+gst_pulseringbuffer_commit (GstAudioRingBuffer * buf, guint64 * sample,
+    guchar * data, gint in_samples, gint out_samples, gint * accum)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+  guint result;
+  guint8 *data_end;
+  gboolean reverse;
+  gint *toprocess;
+  gint inr, outr, bpf;
+  gint64 offset;
+  guint bufsize;
+
+  pbuf = GST_PULSERING_BUFFER_CAST (buf);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+  /* FIXME post message rather than using a signal (as mixer interface) */
+  if (g_atomic_int_compare_and_exchange (&psink->notify, 1, 0)) {
+    g_object_notify (G_OBJECT (psink), "volume");
+    g_object_notify (G_OBJECT (psink), "mute");
+    g_object_notify (G_OBJECT (psink), "current-device");
+  }
+
+  /* make sure the ringbuffer is started */
+  if (G_UNLIKELY (g_atomic_int_get (&buf->state) !=
+          GST_AUDIO_RING_BUFFER_STATE_STARTED)) {
+    /* see if we are allowed to start it */
+    if (G_UNLIKELY (g_atomic_int_get (&buf->may_start) == FALSE))
+      goto no_start;
+
+    GST_DEBUG_OBJECT (buf, "start!");
+    if (!gst_audio_ring_buffer_start (buf))
+      goto start_failed;
+  }
+
+  pa_threaded_mainloop_lock (mainloop);
+
+  GST_DEBUG_OBJECT (psink, "entering commit");
+  pbuf->in_commit = TRUE;
+
+  bpf = GST_AUDIO_INFO_BPF (&buf->spec.info);
+  bufsize = buf->spec.segsize * buf->spec.segtotal;
+
+  /* our toy resampler for trick modes */
+  reverse = out_samples < 0;
+  out_samples = ABS (out_samples);
+
+  if (in_samples >= out_samples)
+    toprocess = &in_samples;
+  else
+    toprocess = &out_samples;
+
+  inr = in_samples - 1;
+  outr = out_samples - 1;
+
+  GST_DEBUG_OBJECT (psink, "in %d, out %d", inr, outr);
+
+  /* data_end points to the last sample we have to write, not past it. This is
+   * needed to properly handle reverse playback: it points to the last sample. */
+  data_end = data + (bpf * inr);
+
+  if (g_atomic_int_get (&psink->format_lost)) {
+    /* Sink format changed, drop the data and hope upstream renegotiates */
+    goto fake_done;
+  }
+
+  if (pbuf->paused)
+    goto was_paused;
+
+  /* offset is in bytes */
+  offset = *sample * bpf;
+
+  while (*toprocess > 0) {
+    size_t avail;
+    guint towrite;
+
+    GST_LOG_OBJECT (psink,
+        "need to write %d samples at offset %" G_GINT64_FORMAT, *toprocess,
+        offset);
+
+    if (offset != pbuf->m_lastoffset)
+      GST_LOG_OBJECT (psink, "discontinuity, offset is %" G_GINT64_FORMAT ", "
+          "last offset was %" G_GINT64_FORMAT, offset, pbuf->m_lastoffset);
+
+    towrite = out_samples * bpf;
+
+    /* Wait for at least segsize bytes to become available */
+    if (towrite > buf->spec.segsize)
+      towrite = buf->spec.segsize;
+
+    if ((pbuf->m_writable < towrite) || (offset != pbuf->m_lastoffset)) {
+      /* if no room left or discontinuity in offset,
+         we need to flush data and get a new buffer */
+
+      /* flush the buffer if possible */
+      if ((pbuf->m_data != NULL) && (pbuf->m_towrite > 0)) {
+
+        GST_LOG_OBJECT (psink,
+            "flushing %u samples at offset %" G_GINT64_FORMAT,
+            (guint) pbuf->m_towrite / bpf, pbuf->m_offset);
+
+        if (pa_stream_write (pbuf->stream, (uint8_t *) pbuf->m_data,
+                pbuf->m_towrite, NULL, pbuf->m_offset, PA_SEEK_ABSOLUTE) < 0) {
+          goto write_failed;
+        }
+      }
+      pbuf->m_towrite = 0;
+      pbuf->m_offset = offset;  /* keep track of current offset */
+
+      /* get a buffer to write in for now on */
+      for (;;) {
+        pbuf->m_writable = pa_stream_writable_size (pbuf->stream);
+
+        if (g_atomic_int_get (&psink->format_lost)) {
+          /* Sink format changed, give up and hope upstream renegotiates */
+          goto fake_done;
+        }
+
+        if (pbuf->m_writable == (size_t) - 1)
+          goto writable_size_failed;
+
+        pbuf->m_writable /= bpf;
+        pbuf->m_writable *= bpf;        /* handle only complete samples */
+
+        if (pbuf->m_writable >= towrite)
+          break;
+
+        /* see if we need to uncork because we have no free space */
+        if (pbuf->corked) {
+          if (!gst_pulsering_set_corked (pbuf, FALSE, FALSE))
+            goto uncork_failed;
+        }
+
+        /* we can't write segsize bytes, wait a bit */
+        GST_LOG_OBJECT (psink, "waiting for free space");
+        pa_threaded_mainloop_wait (mainloop);
+
+        if (pbuf->paused)
+          goto was_paused;
+      }
+
+      /* Recalculate what we can write in the next chunk */
+      towrite = out_samples * bpf;
+      if (pbuf->m_writable > towrite)
+        pbuf->m_writable = towrite;
+
+      GST_LOG_OBJECT (psink, "requesting %" G_GSIZE_FORMAT " bytes of "
+          "shared memory", pbuf->m_writable);
+
+      if (pa_stream_begin_write (pbuf->stream, &pbuf->m_data,
+              &pbuf->m_writable) < 0) {
+        GST_LOG_OBJECT (psink, "pa_stream_begin_write() failed");
+        goto writable_size_failed;
+      }
+
+      GST_LOG_OBJECT (psink, "got %" G_GSIZE_FORMAT " bytes of shared memory",
+          pbuf->m_writable);
+
+    }
+
+    if (towrite > pbuf->m_writable)
+      towrite = pbuf->m_writable;
+    avail = towrite / bpf;
+
+    GST_LOG_OBJECT (psink, "writing %u samples at offset %" G_GUINT64_FORMAT,
+        (guint) avail, offset);
+
+    /* No trick modes for passthrough streams */
+    if (G_UNLIKELY (!pbuf->is_pcm && (inr != outr || reverse))) {
+      GST_WARNING_OBJECT (psink, "Passthrough stream can't run in trick mode");
+      goto unlock_and_fail;
+    }
+
+    if (G_LIKELY (inr == outr && !reverse)) {
+      /* no rate conversion, simply write out the samples */
+      /* copy the data into internal buffer */
+
+      memcpy ((guint8 *) pbuf->m_data + pbuf->m_towrite, data, towrite);
+      pbuf->m_towrite += towrite;
+      pbuf->m_writable -= towrite;
+
+      data += towrite;
+      in_samples -= avail;
+      out_samples -= avail;
+    } else {
+      guint8 *dest, *d, *d_end;
+
+      /* write into the PulseAudio shm buffer */
+      dest = d = (guint8 *) pbuf->m_data + pbuf->m_towrite;
+      d_end = d + towrite;
+
+      if (!reverse) {
+        if (inr >= outr)
+          /* forward speed up */
+          FWD_UP_SAMPLES (data, data_end, d, d_end);
+        else
+          /* forward slow down */
+          FWD_DOWN_SAMPLES (data, data_end, d, d_end);
+      } else {
+        if (inr >= outr)
+          /* reverse speed up */
+          REV_UP_SAMPLES (data, data_end, d, d_end);
+        else
+          /* reverse slow down */
+          REV_DOWN_SAMPLES (data, data_end, d, d_end);
+      }
+      /* see what we have left to write */
+      towrite = (d - dest);
+      pbuf->m_towrite += towrite;
+      pbuf->m_writable -= towrite;
+
+      avail = towrite / bpf;
+    }
+
+    /* flush the buffer if it's full */
+    if ((pbuf->m_data != NULL) && (pbuf->m_towrite > 0)
+        && (pbuf->m_writable == 0)) {
+      GST_LOG_OBJECT (psink, "flushing %u samples at offset %" G_GINT64_FORMAT,
+          (guint) pbuf->m_towrite / bpf, pbuf->m_offset);
+
+      if (pa_stream_write (pbuf->stream, (uint8_t *) pbuf->m_data,
+              pbuf->m_towrite, NULL, pbuf->m_offset, PA_SEEK_ABSOLUTE) < 0) {
+        goto write_failed;
+      }
+      pbuf->m_towrite = 0;
+      pbuf->m_offset = offset + towrite;        /* keep track of current offset */
+    }
+
+    *sample += avail;
+    offset += avail * bpf;
+    pbuf->m_lastoffset = offset;
+
+    /* check if we need to uncork after writing the samples */
+    if (pbuf->corked) {
+      const pa_timing_info *info;
+
+      if ((info = pa_stream_get_timing_info (pbuf->stream))) {
+        GST_LOG_OBJECT (psink,
+            "read_index at %" G_GUINT64_FORMAT ", offset %" G_GINT64_FORMAT,
+            info->read_index, offset);
+
+        /* we uncork when the read_index is too far behind the offset we need
+         * to write to. */
+        if (info->read_index + bufsize <= offset) {
+          if (!gst_pulsering_set_corked (pbuf, FALSE, FALSE))
+            goto uncork_failed;
+        }
+      } else {
+        GST_LOG_OBJECT (psink, "no timing info available yet");
+      }
+    }
+  }
+
+fake_done:
+  /* we consumed all samples here */
+  data = data_end + bpf;
+
+  pbuf->in_commit = FALSE;
+  pa_threaded_mainloop_unlock (mainloop);
+
+done:
+  result = inr - ((data_end - data) / bpf);
+  GST_LOG_OBJECT (psink, "wrote %d samples", result);
+
+  return result;
+
+  /* ERRORS */
+unlock_and_fail:
+  {
+    pbuf->in_commit = FALSE;
+    GST_LOG_OBJECT (psink, "we are reset");
+    pa_threaded_mainloop_unlock (mainloop);
+    goto done;
+  }
+no_start:
+  {
+    GST_LOG_OBJECT (psink, "we can not start");
+    return 0;
+  }
+start_failed:
+  {
+    GST_LOG_OBJECT (psink, "failed to start the ringbuffer");
+    return 0;
+  }
+uncork_failed:
+  {
+    pbuf->in_commit = FALSE;
+    GST_ERROR_OBJECT (psink, "uncork failed");
+    pa_threaded_mainloop_unlock (mainloop);
+    goto done;
+  }
+was_paused:
+  {
+    pbuf->in_commit = FALSE;
+    GST_LOG_OBJECT (psink, "we are paused");
+    pa_threaded_mainloop_unlock (mainloop);
+    goto done;
+  }
+writable_size_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("pa_stream_writable_size() failed: %s",
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto unlock_and_fail;
+  }
+write_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("pa_stream_write() failed: %s",
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto unlock_and_fail;
+  }
+}
+
+/* write pending local samples, must be called with the mainloop lock */
+static void
+gst_pulsering_flush (GstPulseRingBuffer * pbuf)
+{
+  GstPulseSink *psink;
+
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+  GST_DEBUG_OBJECT (psink, "entering flush");
+
+  /* flush the buffer if possible */
+  if (pbuf->stream && (pbuf->m_data != NULL) && (pbuf->m_towrite > 0)) {
+#ifndef GST_DISABLE_GST_DEBUG
+    gint bpf;
+
+    bpf = (GST_AUDIO_RING_BUFFER_CAST (pbuf))->spec.info.bpf;
+    GST_LOG_OBJECT (psink,
+        "flushing %u samples at offset %" G_GINT64_FORMAT,
+        (guint) pbuf->m_towrite / bpf, pbuf->m_offset);
+#endif
+
+    if (pa_stream_write (pbuf->stream, (uint8_t *) pbuf->m_data,
+            pbuf->m_towrite, NULL, pbuf->m_offset, PA_SEEK_ABSOLUTE) < 0) {
+      goto write_failed;
+    }
+
+    pbuf->m_towrite = 0;
+    pbuf->m_offset += pbuf->m_towrite;  /* keep track of current offset */
+  }
+
+done:
+  return;
+
+  /* ERRORS */
+write_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("pa_stream_write() failed: %s",
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto done;
+  }
+}
+
+static void gst_pulsesink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_pulsesink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_pulsesink_finalize (GObject * object);
+
+static gboolean gst_pulsesink_event (GstBaseSink * sink, GstEvent * event);
+static gboolean gst_pulsesink_query (GstBaseSink * sink, GstQuery * query);
+
+static GstStateChangeReturn gst_pulsesink_change_state (GstElement * element,
+    GstStateChange transition);
+
+static GstStaticPadTemplate pad_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (PULSE_SINK_TEMPLATE_CAPS));
+
+#define gst_pulsesink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstPulseSink, gst_pulsesink, GST_TYPE_AUDIO_BASE_SINK,
+    gst_pulsesink_init_contexts ();
+    G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL)
+    );
+
+static GstAudioRingBuffer *
+gst_pulsesink_create_ringbuffer (GstAudioBaseSink * sink)
+{
+  GstAudioRingBuffer *buffer;
+
+  GST_DEBUG_OBJECT (sink, "creating ringbuffer");
+  buffer = g_object_new (GST_TYPE_PULSERING_BUFFER, NULL);
+  GST_DEBUG_OBJECT (sink, "created ringbuffer @%p", buffer);
+
+  return buffer;
+}
+
+static GstBuffer *
+gst_pulsesink_payload (GstAudioBaseSink * sink, GstBuffer * buf)
+{
+  switch (sink->ringbuffer->spec.type) {
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3:
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS:
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG:
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG2_AAC:
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG4_AAC:
+    {
+      /* FIXME: alloc memory from PA if possible */
+      gint framesize = gst_audio_iec61937_frame_size (&sink->ringbuffer->spec);
+      GstBuffer *out;
+      GstMapInfo inmap, outmap;
+      gboolean res;
+
+      if (framesize <= 0)
+        return NULL;
+
+      out = gst_buffer_new_and_alloc (framesize);
+
+      gst_buffer_map (buf, &inmap, GST_MAP_READ);
+      gst_buffer_map (out, &outmap, GST_MAP_WRITE);
+
+      res = gst_audio_iec61937_payload (inmap.data, inmap.size,
+          outmap.data, outmap.size, &sink->ringbuffer->spec, G_BIG_ENDIAN);
+
+      gst_buffer_unmap (buf, &inmap);
+      gst_buffer_unmap (out, &outmap);
+
+      if (!res) {
+        gst_buffer_unref (out);
+        return NULL;
+      }
+
+      gst_buffer_copy_into (out, buf, GST_BUFFER_COPY_METADATA, 0, -1);
+      return out;
+    }
+
+    default:
+      return gst_buffer_ref (buf);
+  }
+}
+
+static void
+gst_pulsesink_class_init (GstPulseSinkClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
+  GstBaseSinkClass *bc;
+  GstAudioBaseSinkClass *gstaudiosink_class = GST_AUDIO_BASE_SINK_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  gchar *clientname;
+
+  gobject_class->finalize = gst_pulsesink_finalize;
+  gobject_class->set_property = gst_pulsesink_set_property;
+  gobject_class->get_property = gst_pulsesink_get_property;
+
+  gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_pulsesink_event);
+  gstbasesink_class->query = GST_DEBUG_FUNCPTR (gst_pulsesink_query);
+
+  /* restore the original basesink pull methods */
+  bc = g_type_class_peek (GST_TYPE_BASE_SINK);
+  gstbasesink_class->activate_pull = GST_DEBUG_FUNCPTR (bc->activate_pull);
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_pulsesink_change_state);
+
+  gstaudiosink_class->create_ringbuffer =
+      GST_DEBUG_FUNCPTR (gst_pulsesink_create_ringbuffer);
+  gstaudiosink_class->payload = GST_DEBUG_FUNCPTR (gst_pulsesink_payload);
+
+  /* Overwrite GObject fields */
+  g_object_class_install_property (gobject_class,
+      PROP_SERVER,
+      g_param_spec_string ("server", "Server",
+          "The PulseAudio server to connect to", DEFAULT_SERVER,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DEVICE,
+      g_param_spec_string ("device", "Device",
+          "The PulseAudio sink device to connect to", DEFAULT_DEVICE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CURRENT_DEVICE,
+      g_param_spec_string ("current-device", "Current Device",
+          "The current PulseAudio sink device", DEFAULT_CURRENT_DEVICE,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_DEVICE_NAME,
+      g_param_spec_string ("device-name", "Device name",
+          "Human-readable name of the sound device", DEFAULT_DEVICE_NAME,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_VOLUME,
+      g_param_spec_double ("volume", "Volume",
+          "Linear volume of this stream, 1.0=100%", 0.0, MAX_VOLUME,
+          DEFAULT_VOLUME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_MUTE,
+      g_param_spec_boolean ("mute", "Mute",
+          "Mute state of this stream", DEFAULT_MUTE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstPulseSink:client-name:
+   *
+   * The PulseAudio client name to use.
+   */
+  clientname = gst_pulse_client_name ();
+  g_object_class_install_property (gobject_class,
+      PROP_CLIENT_NAME,
+      g_param_spec_string ("client-name", "Client Name",
+          "The PulseAudio client name to use", clientname,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+          GST_PARAM_MUTABLE_READY));
+  g_free (clientname);
+
+  /**
+   * GstPulseSink:stream-properties:
+   *
+   * List of pulseaudio stream properties. A list of defined properties can be
+   * found in the <ulink url="http://0pointer.de/lennart/projects/pulseaudio/doxygen/proplist_8h.html">pulseaudio api docs</ulink>.
+   *
+   * Below is an example for registering as a music application to pulseaudio.
+   * |[
+   * GstStructure *props;
+   *
+   * props = gst_structure_from_string ("props,media.role=music", NULL);
+   * g_object_set (pulse, "stream-properties", props, NULL);
+   * gst_structure_free
+   * ]|
+   */
+  g_object_class_install_property (gobject_class,
+      PROP_STREAM_PROPERTIES,
+      g_param_spec_boxed ("stream-properties", "stream properties",
+          "list of pulseaudio stream properties",
+          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "PulseAudio Audio Sink",
+      "Sink/Audio", "Plays audio to a PulseAudio server", "Lennart Poettering");
+  gst_element_class_add_static_pad_template (gstelement_class, &pad_template);
+}
+
+static void
+free_device_info (GstPulseDeviceInfo * device_info)
+{
+  GList *l;
+
+  g_free (device_info->description);
+
+  for (l = g_list_first (device_info->formats); l; l = g_list_next (l))
+    pa_format_info_free ((pa_format_info *) l->data);
+
+  g_list_free (device_info->formats);
+}
+
+/* Returns the current time of the sink ringbuffer. The timing_info is updated
+ * on every data write/flush and every 100ms (PA_STREAM_AUTO_TIMING_UPDATE).
+ */
+static GstClockTime
+gst_pulsesink_get_time (GstClock * clock, GstAudioBaseSink * sink)
+{
+  GstPulseSink *psink;
+  GstPulseRingBuffer *pbuf;
+  pa_usec_t time;
+
+  if (!sink->ringbuffer || !sink->ringbuffer->acquired)
+    return GST_CLOCK_TIME_NONE;
+
+  pbuf = GST_PULSERING_BUFFER_CAST (sink->ringbuffer);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+  if (g_atomic_int_get (&psink->format_lost)) {
+    /* Stream was lost in a format change, it'll get set up again once
+     * upstream renegotiates */
+    return psink->format_lost_time;
+  }
+
+  pa_threaded_mainloop_lock (mainloop);
+  if (gst_pulsering_is_dead (psink, pbuf, TRUE))
+    goto server_dead;
+
+  /* if we don't have enough data to get a timestamp, just return NONE, which
+   * will return the last reported time */
+  if (pa_stream_get_time (pbuf->stream, &time) < 0) {
+    GST_DEBUG_OBJECT (psink, "could not get time");
+    time = GST_CLOCK_TIME_NONE;
+  } else
+    time *= 1000;
+  pa_threaded_mainloop_unlock (mainloop);
+
+  GST_LOG_OBJECT (psink, "current time is %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (time));
+
+  return time;
+
+  /* ERRORS */
+server_dead:
+  {
+    GST_DEBUG_OBJECT (psink, "the server is dead");
+    pa_threaded_mainloop_unlock (mainloop);
+
+    return GST_CLOCK_TIME_NONE;
+  }
+}
+
+static void
+gst_pulsesink_sink_info_cb (pa_context * c, const pa_sink_info * i, int eol,
+    void *userdata)
+{
+  GstPulseDeviceInfo *device_info = (GstPulseDeviceInfo *) userdata;
+  guint8 j;
+
+  if (!i)
+    goto done;
+
+  device_info->description = g_strdup (i->description);
+
+  device_info->formats = NULL;
+  for (j = 0; j < i->n_formats; j++)
+    device_info->formats = g_list_prepend (device_info->formats,
+        pa_format_info_copy (i->formats[j]));
+
+done:
+  pa_threaded_mainloop_signal (mainloop, 0);
+}
+
+/* Call with mainloop lock held */
+static pa_stream *
+gst_pulsesink_create_probe_stream (GstPulseSink * psink,
+    GstPulseRingBuffer * pbuf, pa_format_info * format)
+{
+  pa_format_info *formats[1] = { format };
+  pa_stream *stream;
+  pa_stream_flags_t flags;
+
+  GST_LOG_OBJECT (psink, "Creating probe stream");
+
+  if (!(stream = pa_stream_new_extended (pbuf->context, "pulsesink probe",
+              formats, 1, psink->proplist)))
+    goto error;
+
+  /* construct the flags */
+  flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE |
+      PA_STREAM_ADJUST_LATENCY | PA_STREAM_START_CORKED;
+
+  pa_stream_set_state_callback (stream, gst_pulsering_stream_state_cb, pbuf);
+
+  if (pa_stream_connect_playback (stream, psink->device, NULL, flags, NULL,
+          NULL) < 0)
+    goto error;
+
+  if (!gst_pulsering_wait_for_stream_ready (psink, stream))
+    goto error;
+
+  return stream;
+
+error:
+  if (stream)
+    pa_stream_unref (stream);
+  return NULL;
+}
+
+static GstCaps *
+gst_pulsesink_query_getcaps (GstPulseSink * psink, GstCaps * filter)
+{
+  GstPulseRingBuffer *pbuf = NULL;
+  GstPulseDeviceInfo device_info = { NULL, NULL };
+  GstCaps *ret = NULL;
+  GList *i;
+  pa_operation *o = NULL;
+  pa_stream *stream;
+
+  GST_OBJECT_LOCK (psink);
+  pbuf = GST_PULSERING_BUFFER_CAST (GST_AUDIO_BASE_SINK (psink)->ringbuffer);
+  if (pbuf != NULL)
+    gst_object_ref (pbuf);
+  GST_OBJECT_UNLOCK (psink);
+
+  if (!pbuf) {
+    ret = gst_pad_get_pad_template_caps (GST_AUDIO_BASE_SINK_PAD (psink));
+    goto out;
+  }
+
+  GST_OBJECT_LOCK (pbuf);
+  pa_threaded_mainloop_lock (mainloop);
+
+  if (!pbuf->context) {
+    ret = gst_pad_get_pad_template_caps (GST_AUDIO_BASE_SINK_PAD (psink));
+    goto unlock;
+  }
+
+  ret = gst_caps_new_empty ();
+
+  if (pbuf->stream) {
+    /* We're in PAUSED or higher */
+    stream = pbuf->stream;
+
+  } else if (pbuf->probe_stream) {
+    /* We're not paused, but have a cached probe stream */
+    stream = pbuf->probe_stream;
+
+  } else {
+    /* We're not yet in PAUSED and still need to create a probe stream.
+     *
+     * FIXME: PA doesn't accept "any" format. We fix something reasonable since
+     * this is merely a probe. This should eventually be fixed in PA and
+     * hard-coding the format should be dropped. */
+    pa_format_info *format = pa_format_info_new ();
+    format->encoding = PA_ENCODING_PCM;
+    pa_format_info_set_sample_format (format, PA_SAMPLE_S16LE);
+    pa_format_info_set_rate (format, GST_AUDIO_DEF_RATE);
+    pa_format_info_set_channels (format, GST_AUDIO_DEF_CHANNELS);
+
+    pbuf->probe_stream = gst_pulsesink_create_probe_stream (psink, pbuf,
+        format);
+
+    pa_format_info_free (format);
+
+    if (!pbuf->probe_stream) {
+      GST_WARNING_OBJECT (psink, "Could not create probe stream");
+      goto unlock;
+    }
+
+    stream = pbuf->probe_stream;
+  }
+
+  if (!(o = pa_context_get_sink_info_by_name (pbuf->context,
+              pa_stream_get_device_name (stream), gst_pulsesink_sink_info_cb,
+              &device_info)))
+    goto info_failed;
+
+  while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+    pa_threaded_mainloop_wait (mainloop);
+    if (gst_pulsering_is_dead (psink, pbuf, FALSE))
+      goto unlock;
+  }
+
+  for (i = g_list_first (device_info.formats); i; i = g_list_next (i)) {
+    gst_caps_append (ret,
+        gst_pulse_format_info_to_caps ((pa_format_info *) i->data));
+  }
+
+unlock:
+  pa_threaded_mainloop_unlock (mainloop);
+  /* FIXME: this could be freed after device_name is got */
+  GST_OBJECT_UNLOCK (pbuf);
+
+  if (filter) {
+    GstCaps *tmp = gst_caps_intersect_full (filter, ret,
+        GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (ret);
+    ret = tmp;
+  }
+
+out:
+  free_device_info (&device_info);
+
+  if (o)
+    pa_operation_unref (o);
+
+  if (pbuf)
+    gst_object_unref (pbuf);
+
+  GST_DEBUG_OBJECT (psink, "caps %" GST_PTR_FORMAT, ret);
+
+  return ret;
+
+info_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("pa_context_get_sink_input_info() failed: %s",
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto unlock;
+  }
+}
+
+static gboolean
+gst_pulsesink_query_acceptcaps (GstPulseSink * psink, GstCaps * caps)
+{
+  GstPulseRingBuffer *pbuf = NULL;
+  GstPulseDeviceInfo device_info = { NULL, NULL };
+  GstCaps *pad_caps;
+  GstStructure *st;
+  gboolean ret = FALSE;
+
+  GstAudioRingBufferSpec spec = { 0 };
+  pa_operation *o = NULL;
+  pa_channel_map channel_map;
+  pa_format_info *format = NULL;
+  guint channels;
+
+  pad_caps = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (psink));
+  ret = gst_caps_is_subset (caps, pad_caps);
+  gst_caps_unref (pad_caps);
+
+  GST_DEBUG_OBJECT (psink, "caps %" GST_PTR_FORMAT, caps);
+
+  /* Template caps didn't match */
+  if (!ret)
+    goto done;
+
+  /* If we've not got fixed caps, creating a stream might fail, so let's just
+   * return from here with default acceptcaps behaviour */
+  if (!gst_caps_is_fixed (caps))
+    goto done;
+
+  GST_OBJECT_LOCK (psink);
+  pbuf = GST_PULSERING_BUFFER_CAST (GST_AUDIO_BASE_SINK (psink)->ringbuffer);
+  if (pbuf != NULL)
+    gst_object_ref (pbuf);
+  GST_OBJECT_UNLOCK (psink);
+
+  /* We're still in NULL state */
+  if (pbuf == NULL)
+    goto done;
+
+  GST_OBJECT_LOCK (pbuf);
+  pa_threaded_mainloop_lock (mainloop);
+
+  if (pbuf->context == NULL)
+    goto out;
+
+  ret = FALSE;
+
+  spec.latency_time = GST_AUDIO_BASE_SINK (psink)->latency_time;
+  if (!gst_audio_ring_buffer_parse_caps (&spec, caps))
+    goto out;
+
+  if (!gst_pulse_fill_format_info (&spec, &format, &channels))
+    goto out;
+
+  /* Make sure input is framed (one frame per buffer) and can be payloaded */
+  if (!pa_format_info_is_pcm (format)) {
+    gboolean framed = FALSE, parsed = FALSE;
+    st = gst_caps_get_structure (caps, 0);
+
+    gst_structure_get_boolean (st, "framed", &framed);
+    gst_structure_get_boolean (st, "parsed", &parsed);
+    if ((!framed && !parsed) || gst_audio_iec61937_frame_size (&spec) <= 0)
+      goto out;
+  }
+
+  /* initialize the channel map */
+  if (pa_format_info_is_pcm (format) &&
+      gst_pulse_gst_to_channel_map (&channel_map, &spec))
+    pa_format_info_set_channel_map (format, &channel_map);
+
+  if (pbuf->stream || pbuf->probe_stream) {
+    /* We're already in PAUSED or above, so just reuse this stream to query
+     * sink formats and use those. */
+    GList *i;
+    const char *device_name = pa_stream_get_device_name (pbuf->stream ?
+        pbuf->stream : pbuf->probe_stream);
+
+    if (!(o = pa_context_get_sink_info_by_name (pbuf->context, device_name,
+                gst_pulsesink_sink_info_cb, &device_info)))
+      goto info_failed;
+
+    while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+      pa_threaded_mainloop_wait (mainloop);
+      if (gst_pulsering_is_dead (psink, pbuf, FALSE))
+        goto out;
+    }
+
+    for (i = g_list_first (device_info.formats); i; i = g_list_next (i)) {
+      if (pa_format_info_is_compatible ((pa_format_info *) i->data, format)) {
+        ret = TRUE;
+        break;
+      }
+    }
+  } else {
+    /* We're in READY, let's connect a stream to see if the format is
+     * accepted by whatever sink we're routed to */
+    pbuf->probe_stream = gst_pulsesink_create_probe_stream (psink, pbuf,
+        format);
+    if (pbuf->probe_stream)
+      ret = TRUE;
+  }
+
+out:
+  if (format)
+    pa_format_info_free (format);
+
+  free_device_info (&device_info);
+
+  if (o)
+    pa_operation_unref (o);
+
+  pa_threaded_mainloop_unlock (mainloop);
+  GST_OBJECT_UNLOCK (pbuf);
+
+  gst_caps_replace (&spec.caps, NULL);
+  gst_object_unref (pbuf);
+
+done:
+
+  return ret;
+
+info_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("pa_context_get_sink_input_info() failed: %s",
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto out;
+  }
+}
+
+static void
+gst_pulsesink_init (GstPulseSink * pulsesink)
+{
+  pulsesink->server = NULL;
+  pulsesink->device = NULL;
+  pulsesink->device_info.description = NULL;
+  pulsesink->client_name = gst_pulse_client_name ();
+
+  pulsesink->device_info.formats = NULL;
+
+  pulsesink->volume = DEFAULT_VOLUME;
+  pulsesink->volume_set = FALSE;
+
+  pulsesink->mute = DEFAULT_MUTE;
+  pulsesink->mute_set = FALSE;
+
+  pulsesink->notify = 0;
+
+  g_atomic_int_set (&pulsesink->format_lost, FALSE);
+  pulsesink->format_lost_time = GST_CLOCK_TIME_NONE;
+
+  pulsesink->properties = NULL;
+  pulsesink->proplist = NULL;
+
+  /* override with a custom clock */
+  if (GST_AUDIO_BASE_SINK (pulsesink)->provided_clock)
+    gst_object_unref (GST_AUDIO_BASE_SINK (pulsesink)->provided_clock);
+
+  GST_AUDIO_BASE_SINK (pulsesink)->provided_clock =
+      gst_audio_clock_new ("GstPulseSinkClock",
+      (GstAudioClockGetTimeFunc) gst_pulsesink_get_time, pulsesink, NULL);
+}
+
+static void
+gst_pulsesink_finalize (GObject * object)
+{
+  GstPulseSink *pulsesink = GST_PULSESINK_CAST (object);
+
+  g_free (pulsesink->server);
+  g_free (pulsesink->device);
+  g_free (pulsesink->client_name);
+  g_free (pulsesink->current_sink_name);
+
+  free_device_info (&pulsesink->device_info);
+
+  if (pulsesink->properties)
+    gst_structure_free (pulsesink->properties);
+  if (pulsesink->proplist)
+    pa_proplist_free (pulsesink->proplist);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_pulsesink_set_volume (GstPulseSink * psink, gdouble volume)
+{
+  pa_cvolume v;
+  pa_operation *o = NULL;
+  GstPulseRingBuffer *pbuf;
+  uint32_t idx;
+
+  if (!mainloop)
+    goto no_mainloop;
+
+  pa_threaded_mainloop_lock (mainloop);
+
+  GST_DEBUG_OBJECT (psink, "setting volume to %f", volume);
+
+  pbuf = GST_PULSERING_BUFFER_CAST (GST_AUDIO_BASE_SINK (psink)->ringbuffer);
+  if (pbuf == NULL || pbuf->stream == NULL)
+    goto no_buffer;
+
+  if ((idx = pa_stream_get_index (pbuf->stream)) == PA_INVALID_INDEX)
+    goto no_index;
+
+  if (pbuf->is_pcm)
+    gst_pulse_cvolume_from_linear (&v, pbuf->channels, volume);
+  else
+    /* FIXME: this will eventually be superceded by checks to see if the volume
+     * is readable/writable */
+    goto unlock;
+
+  if (!(o = pa_context_set_sink_input_volume (pbuf->context, idx,
+              &v, NULL, NULL)))
+    goto volume_failed;
+
+  /* We don't really care about the result of this call */
+unlock:
+
+  if (o)
+    pa_operation_unref (o);
+
+  pa_threaded_mainloop_unlock (mainloop);
+
+  return;
+
+  /* ERRORS */
+no_mainloop:
+  {
+    psink->volume = volume;
+    psink->volume_set = TRUE;
+
+    GST_DEBUG_OBJECT (psink, "we have no mainloop");
+    return;
+  }
+no_buffer:
+  {
+    psink->volume = volume;
+    psink->volume_set = TRUE;
+
+    GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+    goto unlock;
+  }
+no_index:
+  {
+    GST_DEBUG_OBJECT (psink, "we don't have a stream index");
+    goto unlock;
+  }
+volume_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("pa_stream_set_sink_input_volume() failed: %s",
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto unlock;
+  }
+}
+
+static void
+gst_pulsesink_set_mute (GstPulseSink * psink, gboolean mute)
+{
+  pa_operation *o = NULL;
+  GstPulseRingBuffer *pbuf;
+  uint32_t idx;
+
+  if (!mainloop)
+    goto no_mainloop;
+
+  pa_threaded_mainloop_lock (mainloop);
+
+  GST_DEBUG_OBJECT (psink, "setting mute state to %d", mute);
+
+  pbuf = GST_PULSERING_BUFFER_CAST (GST_AUDIO_BASE_SINK (psink)->ringbuffer);
+  if (pbuf == NULL || pbuf->stream == NULL)
+    goto no_buffer;
+
+  if ((idx = pa_stream_get_index (pbuf->stream)) == PA_INVALID_INDEX)
+    goto no_index;
+
+  if (!(o = pa_context_set_sink_input_mute (pbuf->context, idx,
+              mute, NULL, NULL)))
+    goto mute_failed;
+
+  /* We don't really care about the result of this call */
+unlock:
+
+  if (o)
+    pa_operation_unref (o);
+
+  pa_threaded_mainloop_unlock (mainloop);
+
+  return;
+
+  /* ERRORS */
+no_mainloop:
+  {
+    psink->mute = mute;
+    psink->mute_set = TRUE;
+
+    GST_DEBUG_OBJECT (psink, "we have no mainloop");
+    return;
+  }
+no_buffer:
+  {
+    psink->mute = mute;
+    psink->mute_set = TRUE;
+
+    GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+    goto unlock;
+  }
+no_index:
+  {
+    GST_DEBUG_OBJECT (psink, "we don't have a stream index");
+    goto unlock;
+  }
+mute_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("pa_stream_set_sink_input_mute() failed: %s",
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto unlock;
+  }
+}
+
+static void
+gst_pulsesink_sink_input_info_cb (pa_context * c, const pa_sink_input_info * i,
+    int eol, void *userdata)
+{
+  GstPulseRingBuffer *pbuf;
+  GstPulseSink *psink;
+
+  pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+  psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+  if (!i)
+    goto done;
+
+  if (!pbuf->stream)
+    goto done;
+
+  /* If the index doesn't match our current stream,
+   * it implies we just recreated the stream (caps change)
+   */
+  if (i->index == pa_stream_get_index (pbuf->stream)) {
+    psink->volume = pa_sw_volume_to_linear (pa_cvolume_max (&i->volume));
+    psink->mute = i->mute;
+    psink->current_sink_idx = i->sink;
+
+    if (psink->volume > MAX_VOLUME) {
+      GST_WARNING_OBJECT (psink, "Clipped volume from %f to %f", psink->volume,
+          MAX_VOLUME);
+      psink->volume = MAX_VOLUME;
+    }
+  }
+
+done:
+  pa_threaded_mainloop_signal (mainloop, 0);
+}
+
+static void
+gst_pulsesink_get_sink_input_info (GstPulseSink * psink, gdouble * volume,
+    gboolean * mute)
+{
+  GstPulseRingBuffer *pbuf;
+  pa_operation *o = NULL;
+  uint32_t idx;
+
+  if (!mainloop)
+    goto no_mainloop;
+
+  pa_threaded_mainloop_lock (mainloop);
+
+  pbuf = GST_PULSERING_BUFFER_CAST (GST_AUDIO_BASE_SINK (psink)->ringbuffer);
+  if (pbuf == NULL || pbuf->stream == NULL)
+    goto no_buffer;
+
+  if ((idx = pa_stream_get_index (pbuf->stream)) == PA_INVALID_INDEX)
+    goto no_index;
+
+  if (!(o = pa_context_get_sink_input_info (pbuf->context, idx,
+              gst_pulsesink_sink_input_info_cb, pbuf)))
+    goto info_failed;
+
+  while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+    pa_threaded_mainloop_wait (mainloop);
+    if (gst_pulsering_is_dead (psink, pbuf, TRUE))
+      goto unlock;
+  }
+
+unlock:
+  if (volume)
+    *volume = psink->volume;
+  if (mute)
+    *mute = psink->mute;
+
+  if (o)
+    pa_operation_unref (o);
+
+  pa_threaded_mainloop_unlock (mainloop);
+
+  return;
+
+  /* ERRORS */
+no_mainloop:
+  {
+    if (volume)
+      *volume = psink->volume;
+    if (mute)
+      *mute = psink->mute;
+
+    GST_DEBUG_OBJECT (psink, "we have no mainloop");
+    return;
+  }
+no_buffer:
+  {
+    GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+    goto unlock;
+  }
+no_index:
+  {
+    GST_DEBUG_OBJECT (psink, "we don't have a stream index");
+    goto unlock;
+  }
+info_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("pa_context_get_sink_input_info() failed: %s",
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto unlock;
+  }
+}
+
+static void
+gst_pulsesink_current_sink_info_cb (pa_context * c, const pa_sink_info * i,
+    int eol, void *userdata)
+{
+  GstPulseSink *psink;
+
+  psink = GST_PULSESINK_CAST (userdata);
+
+  if (!i)
+    goto done;
+
+  /* If the index doesn't match our current stream,
+   * it implies we just recreated the stream (caps change)
+   */
+  if (i->index == psink->current_sink_idx) {
+    g_free (psink->current_sink_name);
+    psink->current_sink_name = g_strdup (i->name);
+  }
+
+done:
+  pa_threaded_mainloop_signal (mainloop, 0);
+}
+
+static gchar *
+gst_pulsesink_get_current_device (GstPulseSink * pulsesink)
+{
+  pa_operation *o = NULL;
+  GstPulseRingBuffer *pbuf;
+  gchar *current_sink;
+
+  if (!mainloop)
+    goto no_mainloop;
+
+  pbuf =
+      GST_PULSERING_BUFFER_CAST (GST_AUDIO_BASE_SINK (pulsesink)->ringbuffer);
+  if (pbuf == NULL || pbuf->stream == NULL)
+    goto no_buffer;
+
+  gst_pulsesink_get_sink_input_info (pulsesink, NULL, NULL);
+
+  pa_threaded_mainloop_lock (mainloop);
+
+  if (!(o = pa_context_get_sink_info_by_index (pbuf->context,
+              pulsesink->current_sink_idx, gst_pulsesink_current_sink_info_cb,
+              pulsesink)))
+    goto info_failed;
+
+  while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+    pa_threaded_mainloop_wait (mainloop);
+    if (gst_pulsering_is_dead (pulsesink, pbuf, TRUE))
+      goto unlock;
+  }
+
+unlock:
+
+  current_sink = g_strdup (pulsesink->current_sink_name);
+
+  if (o)
+    pa_operation_unref (o);
+
+  pa_threaded_mainloop_unlock (mainloop);
+
+  return current_sink;
+
+  /* ERRORS */
+no_mainloop:
+  {
+    GST_DEBUG_OBJECT (pulsesink, "we have no mainloop");
+    return NULL;
+  }
+no_buffer:
+  {
+    GST_DEBUG_OBJECT (pulsesink, "we have no ringbuffer");
+    return NULL;
+  }
+info_failed:
+  {
+    GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
+        ("pa_context_get_sink_input_info() failed: %s",
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto unlock;
+  }
+}
+
+static gchar *
+gst_pulsesink_device_description (GstPulseSink * psink)
+{
+  GstPulseRingBuffer *pbuf;
+  pa_operation *o = NULL;
+  gchar *t;
+
+  if (!mainloop)
+    goto no_mainloop;
+
+  pa_threaded_mainloop_lock (mainloop);
+  pbuf = GST_PULSERING_BUFFER_CAST (GST_AUDIO_BASE_SINK (psink)->ringbuffer);
+  if (pbuf == NULL)
+    goto no_buffer;
+
+  free_device_info (&psink->device_info);
+  if (!(o = pa_context_get_sink_info_by_name (pbuf->context,
+              psink->device, gst_pulsesink_sink_info_cb, &psink->device_info)))
+    goto info_failed;
+
+  while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+    pa_threaded_mainloop_wait (mainloop);
+    if (gst_pulsering_is_dead (psink, pbuf, FALSE))
+      goto unlock;
+  }
+
+unlock:
+  if (o)
+    pa_operation_unref (o);
+
+  t = g_strdup (psink->device_info.description);
+  pa_threaded_mainloop_unlock (mainloop);
+
+  return t;
+
+  /* ERRORS */
+no_mainloop:
+  {
+    GST_DEBUG_OBJECT (psink, "we have no mainloop");
+    return NULL;
+  }
+no_buffer:
+  {
+    GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+    goto unlock;
+  }
+info_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("pa_context_get_sink_info_by_index() failed: %s",
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto unlock;
+  }
+}
+
+static void
+gst_pulsesink_set_stream_device (GstPulseSink * psink, const gchar * device)
+{
+  pa_operation *o = NULL;
+  GstPulseRingBuffer *pbuf;
+  uint32_t idx;
+
+  if (!mainloop)
+    goto no_mainloop;
+
+  pa_threaded_mainloop_lock (mainloop);
+
+  pbuf = GST_PULSERING_BUFFER_CAST (GST_AUDIO_BASE_SINK (psink)->ringbuffer);
+  if (pbuf == NULL || pbuf->stream == NULL)
+    goto no_buffer;
+
+  if ((idx = pa_stream_get_index (pbuf->stream)) == PA_INVALID_INDEX)
+    goto no_index;
+
+
+  GST_DEBUG_OBJECT (psink, "setting stream device to %s", device);
+
+  if (!(o = pa_context_move_sink_input_by_name (pbuf->context, idx, device,
+              NULL, NULL)))
+    goto move_failed;
+
+unlock:
+
+  if (o)
+    pa_operation_unref (o);
+
+  pa_threaded_mainloop_unlock (mainloop);
+
+  return;
+
+  /* ERRORS */
+no_mainloop:
+  {
+    GST_DEBUG_OBJECT (psink, "we have no mainloop");
+    return;
+  }
+no_buffer:
+  {
+    GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+    goto unlock;
+  }
+no_index:
+  {
+    GST_DEBUG_OBJECT (psink, "we don't have a stream index");
+    return;
+  }
+move_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("pa_context_move_sink_input_by_name(%s) failed: %s", device,
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto unlock;
+  }
+}
+
+
+static void
+gst_pulsesink_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstPulseSink *pulsesink = GST_PULSESINK_CAST (object);
+
+  switch (prop_id) {
+    case PROP_SERVER:
+      g_free (pulsesink->server);
+      pulsesink->server = g_value_dup_string (value);
+      break;
+    case PROP_DEVICE:
+      g_free (pulsesink->device);
+      pulsesink->device = g_value_dup_string (value);
+      gst_pulsesink_set_stream_device (pulsesink, pulsesink->device);
+      break;
+    case PROP_VOLUME:
+      gst_pulsesink_set_volume (pulsesink, g_value_get_double (value));
+      break;
+    case PROP_MUTE:
+      gst_pulsesink_set_mute (pulsesink, g_value_get_boolean (value));
+      break;
+    case PROP_CLIENT_NAME:
+      g_free (pulsesink->client_name);
+      if (!g_value_get_string (value)) {
+        GST_WARNING_OBJECT (pulsesink,
+            "Empty PulseAudio client name not allowed. Resetting to default value");
+        pulsesink->client_name = gst_pulse_client_name ();
+      } else
+        pulsesink->client_name = g_value_dup_string (value);
+      break;
+    case PROP_STREAM_PROPERTIES:
+      if (pulsesink->properties)
+        gst_structure_free (pulsesink->properties);
+      pulsesink->properties =
+          gst_structure_copy (gst_value_get_structure (value));
+      if (pulsesink->proplist)
+        pa_proplist_free (pulsesink->proplist);
+      pulsesink->proplist = gst_pulse_make_proplist (pulsesink->properties);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_pulsesink_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+
+  GstPulseSink *pulsesink = GST_PULSESINK_CAST (object);
+
+  switch (prop_id) {
+    case PROP_SERVER:
+      g_value_set_string (value, pulsesink->server);
+      break;
+    case PROP_DEVICE:
+      g_value_set_string (value, pulsesink->device);
+      break;
+    case PROP_CURRENT_DEVICE:
+    {
+      gchar *current_device = gst_pulsesink_get_current_device (pulsesink);
+      if (current_device)
+        g_value_take_string (value, current_device);
+      else
+        g_value_set_string (value, "");
+      break;
+    }
+    case PROP_DEVICE_NAME:
+      g_value_take_string (value, gst_pulsesink_device_description (pulsesink));
+      break;
+    case PROP_VOLUME:
+    {
+      gdouble volume;
+
+      gst_pulsesink_get_sink_input_info (pulsesink, &volume, NULL);
+      g_value_set_double (value, volume);
+      break;
+    }
+    case PROP_MUTE:
+    {
+      gboolean mute;
+
+      gst_pulsesink_get_sink_input_info (pulsesink, NULL, &mute);
+      g_value_set_boolean (value, mute);
+      break;
+    }
+    case PROP_CLIENT_NAME:
+      g_value_set_string (value, pulsesink->client_name);
+      break;
+    case PROP_STREAM_PROPERTIES:
+      gst_value_set_structure (value, pulsesink->properties);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_pulsesink_change_title (GstPulseSink * psink, const gchar * t)
+{
+  pa_operation *o = NULL;
+  GstPulseRingBuffer *pbuf;
+
+  pa_threaded_mainloop_lock (mainloop);
+
+  pbuf = GST_PULSERING_BUFFER_CAST (GST_AUDIO_BASE_SINK (psink)->ringbuffer);
+
+  if (pbuf == NULL || pbuf->stream == NULL)
+    goto no_buffer;
+
+  g_free (pbuf->stream_name);
+  pbuf->stream_name = g_strdup (t);
+
+  if (!(o = pa_stream_set_name (pbuf->stream, pbuf->stream_name, NULL, NULL)))
+    goto name_failed;
+
+  /* We're not interested if this operation failed or not */
+unlock:
+
+  if (o)
+    pa_operation_unref (o);
+  pa_threaded_mainloop_unlock (mainloop);
+
+  return;
+
+  /* ERRORS */
+no_buffer:
+  {
+    GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+    goto unlock;
+  }
+name_failed:
+  {
+    GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+        ("pa_stream_set_name() failed: %s",
+            pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+    goto unlock;
+  }
+}
+
+static void
+gst_pulsesink_change_props (GstPulseSink * psink, GstTagList * l)
+{
+  static const gchar *const map[] = {
+    GST_TAG_TITLE, PA_PROP_MEDIA_TITLE,
+
+    /* might get overriden in the next iteration by GST_TAG_ARTIST */
+    GST_TAG_PERFORMER, PA_PROP_MEDIA_ARTIST,
+
+    GST_TAG_ARTIST, PA_PROP_MEDIA_ARTIST,
+    GST_TAG_LANGUAGE_CODE, PA_PROP_MEDIA_LANGUAGE,
+    GST_TAG_LOCATION, PA_PROP_MEDIA_FILENAME,
+    /* We might add more here later on ... */
+    NULL
+  };
+  pa_proplist *pl = NULL;
+  const gchar *const *t;
+  gboolean empty = TRUE;
+  pa_operation *o = NULL;
+  GstPulseRingBuffer *pbuf;
+
+  pl = pa_proplist_new ();
+
+  for (t = map; *t; t += 2) {
+    gchar *n = NULL;
+
+    if (gst_tag_list_get_string (l, *t, &n)) {
+
+      if (n && *n) {
+        pa_proplist_sets (pl, *(t + 1), n);
+        empty = FALSE;
+      }
+
+      g_free (n);
+    }
+  }
+  if (empty)
+    goto finish;
+
+  pa_threaded_mainloop_lock (mainloop);
+  pbuf = GST_PULSERING_BUFFER_CAST (GST_AUDIO_BASE_SINK (psink)->ringbuffer);
+  if (pbuf == NULL || pbuf->stream == NULL)
+    goto no_buffer;
+
+  /* We're not interested if this operation failed or not */
+  if (!(o = pa_stream_proplist_update (pbuf->stream, PA_UPDATE_REPLACE,
+              pl, NULL, NULL))) {
+    GST_DEBUG_OBJECT (psink, "pa_stream_proplist_update() failed");
+  }
+
+unlock:
+
+  if (o)
+    pa_operation_unref (o);
+
+  pa_threaded_mainloop_unlock (mainloop);
+
+finish:
+
+  if (pl)
+    pa_proplist_free (pl);
+
+  return;
+
+  /* ERRORS */
+no_buffer:
+  {
+    GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+    goto unlock;
+  }
+}
+
+static void
+gst_pulsesink_flush_ringbuffer (GstPulseSink * psink)
+{
+  GstPulseRingBuffer *pbuf;
+
+  pa_threaded_mainloop_lock (mainloop);
+
+  pbuf = GST_PULSERING_BUFFER_CAST (GST_AUDIO_BASE_SINK (psink)->ringbuffer);
+
+  if (pbuf == NULL || pbuf->stream == NULL)
+    goto no_buffer;
+
+  gst_pulsering_flush (pbuf);
+
+  /* Uncork if we haven't already (happens when waiting to get enough data
+   * to send out the first time) */
+  if (pbuf->corked)
+    gst_pulsering_set_corked (pbuf, FALSE, FALSE);
+
+  /* We're not interested if this operation failed or not */
+unlock:
+  pa_threaded_mainloop_unlock (mainloop);
+
+  return;
+
+  /* ERRORS */
+no_buffer:
+  {
+    GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+    goto unlock;
+  }
+}
+
+static gboolean
+gst_pulsesink_event (GstBaseSink * sink, GstEvent * event)
+{
+  GstPulseSink *pulsesink = GST_PULSESINK_CAST (sink);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_TAG:{
+      gchar *title = NULL, *artist = NULL, *location = NULL, *description =
+          NULL, *t = NULL, *buf = NULL;
+      GstTagList *l;
+
+      gst_event_parse_tag (event, &l);
+
+      gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
+      gst_tag_list_get_string (l, GST_TAG_ARTIST, &artist);
+      gst_tag_list_get_string (l, GST_TAG_LOCATION, &location);
+      gst_tag_list_get_string (l, GST_TAG_DESCRIPTION, &description);
+
+      if (!artist)
+        gst_tag_list_get_string (l, GST_TAG_PERFORMER, &artist);
+
+      if (title && artist)
+        /* TRANSLATORS: 'song title' by 'artist name' */
+        t = buf = g_strdup_printf (_("'%s' by '%s'"), g_strstrip (title),
+            g_strstrip (artist));
+      else if (title)
+        t = g_strstrip (title);
+      else if (description)
+        t = g_strstrip (description);
+      else if (location)
+        t = g_strstrip (location);
+
+      if (t)
+        gst_pulsesink_change_title (pulsesink, t);
+
+      g_free (title);
+      g_free (artist);
+      g_free (location);
+      g_free (description);
+      g_free (buf);
+
+      gst_pulsesink_change_props (pulsesink, l);
+
+      break;
+    }
+    case GST_EVENT_GAP:{
+      GstClockTime timestamp, duration;
+
+      gst_event_parse_gap (event, &timestamp, &duration);
+      if (duration == GST_CLOCK_TIME_NONE)
+        gst_pulsesink_flush_ringbuffer (pulsesink);
+      break;
+    }
+    case GST_EVENT_EOS:
+      gst_pulsesink_flush_ringbuffer (pulsesink);
+      break;
+    default:
+      ;
+  }
+
+  return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
+}
+
+static gboolean
+gst_pulsesink_query (GstBaseSink * sink, GstQuery * query)
+{
+  GstPulseSink *pulsesink = GST_PULSESINK_CAST (sink);
+  gboolean ret = FALSE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *caps, *filter;
+
+      gst_query_parse_caps (query, &filter);
+      caps = gst_pulsesink_query_getcaps (pulsesink, filter);
+
+      if (caps) {
+        gst_query_set_caps_result (query, caps);
+        gst_caps_unref (caps);
+        ret = TRUE;
+      }
+      break;
+    }
+    case GST_QUERY_ACCEPT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_query_parse_accept_caps (query, &caps);
+      ret = gst_pulsesink_query_acceptcaps (pulsesink, caps);
+      gst_query_set_accept_caps_result (query, ret);
+      ret = TRUE;
+      break;
+    }
+    default:
+      ret = GST_BASE_SINK_CLASS (parent_class)->query (sink, query);
+      break;
+  }
+  return ret;
+}
+
+static void
+gst_pulsesink_release_mainloop (GstPulseSink * psink)
+{
+  if (!mainloop)
+    return;
+
+  pa_threaded_mainloop_lock (mainloop);
+  while (psink->defer_pending) {
+    GST_DEBUG_OBJECT (psink, "waiting for stream status message emission");
+    pa_threaded_mainloop_wait (mainloop);
+  }
+  pa_threaded_mainloop_unlock (mainloop);
+
+  g_mutex_lock (&pa_shared_resource_mutex);
+  mainloop_ref_ct--;
+  if (!mainloop_ref_ct) {
+    GST_INFO_OBJECT (psink, "terminating pa main loop thread");
+    pa_threaded_mainloop_stop (mainloop);
+    pa_threaded_mainloop_free (mainloop);
+    mainloop = NULL;
+  }
+  g_mutex_unlock (&pa_shared_resource_mutex);
+}
+
+static GstStateChangeReturn
+gst_pulsesink_change_state (GstElement * element, GstStateChange transition)
+{
+  GstPulseSink *pulsesink = GST_PULSESINK (element);
+  GstStateChangeReturn ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      g_mutex_lock (&pa_shared_resource_mutex);
+      if (!mainloop_ref_ct) {
+        GST_INFO_OBJECT (element, "new pa main loop thread");
+        if (!(mainloop = pa_threaded_mainloop_new ()))
+          goto mainloop_failed;
+        if (pa_threaded_mainloop_start (mainloop) < 0) {
+          pa_threaded_mainloop_free (mainloop);
+          goto mainloop_start_failed;
+        }
+        mainloop_ref_ct = 1;
+        g_mutex_unlock (&pa_shared_resource_mutex);
+      } else {
+        GST_INFO_OBJECT (element, "reusing pa main loop thread");
+        mainloop_ref_ct++;
+        g_mutex_unlock (&pa_shared_resource_mutex);
+      }
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_element_post_message (element,
+          gst_message_new_clock_provide (GST_OBJECT_CAST (element),
+              GST_AUDIO_BASE_SINK (pulsesink)->provided_clock, TRUE));
+      break;
+
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    goto state_failure;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      /* format_lost is reset in release() in audiobasesink */
+      gst_element_post_message (element,
+          gst_message_new_clock_lost (GST_OBJECT_CAST (element),
+              GST_AUDIO_BASE_SINK (pulsesink)->provided_clock));
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      gst_pulsesink_release_mainloop (pulsesink);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+
+  /* ERRORS */
+mainloop_failed:
+  {
+    g_mutex_unlock (&pa_shared_resource_mutex);
+    GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
+        ("pa_threaded_mainloop_new() failed"), (NULL));
+    return GST_STATE_CHANGE_FAILURE;
+  }
+mainloop_start_failed:
+  {
+    g_mutex_unlock (&pa_shared_resource_mutex);
+    GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
+        ("pa_threaded_mainloop_start() failed"), (NULL));
+    return GST_STATE_CHANGE_FAILURE;
+  }
+state_failure:
+  {
+    if (transition == GST_STATE_CHANGE_NULL_TO_READY) {
+      /* Clear the PA mainloop if audiobasesink failed to open the ring_buffer */
+      g_assert (mainloop);
+      gst_pulsesink_release_mainloop (pulsesink);
+    }
+    return ret;
+  }
+}
diff --git a/ext/pulse/pulsesink.h b/ext/pulse/pulsesink.h
new file mode 100644
index 0000000..de3b932
--- /dev/null
+++ b/ext/pulse/pulsesink.h
@@ -0,0 +1,107 @@
+/*-*- Mode: C; c-basic-offset: 2 -*-*/
+
+/*
+ *  GStreamer pulseaudio plugin
+ *
+ *  Copyright (c) 2004-2008 Lennart Poettering
+ *
+ *  gst-pulse is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as
+ *  published by the Free Software Foundation; either version 2.1 of the
+ *  License, or (at your option) any later version.
+ *
+ *  gst-pulse 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with gst-pulse; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ *  USA.
+ */
+
+#ifndef __GST_PULSESINK_H__
+#define __GST_PULSESINK_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiosink.h>
+
+#include <pulse/pulseaudio.h>
+#include <pulse/thread-mainloop.h>
+
+#include "pulseutil.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_PULSESINK \
+  (gst_pulsesink_get_type())
+#define GST_PULSESINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PULSESINK,GstPulseSink))
+#define GST_PULSESINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PULSESINK,GstPulseSinkClass))
+#define GST_IS_PULSESINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PULSESINK))
+#define GST_IS_PULSESINK_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PULSESINK))
+#define GST_PULSESINK_CAST(obj) \
+  ((GstPulseSink *)(obj))
+
+typedef struct _GstPulseSink GstPulseSink;
+typedef struct _GstPulseSinkClass GstPulseSinkClass;
+
+typedef struct _GstPulseDeviceInfo {
+  gchar *description;
+  GList *formats;
+} GstPulseDeviceInfo;
+
+struct _GstPulseSink
+{
+  GstAudioBaseSink sink;
+
+  gchar *server, *device, *stream_name, *client_name;
+  GstPulseDeviceInfo device_info;
+
+  gdouble volume;
+  gboolean volume_set:1;
+  gboolean mute:1;
+  gboolean mute_set:1;
+  guint32 current_sink_idx;
+  gchar *current_sink_name;
+
+  guint defer_pending;
+
+  gint notify; /* atomic */
+
+  const gchar *pa_version;
+
+  GstStructure *properties;
+  pa_proplist *proplist;
+
+  volatile gint format_lost;
+  GstClockTime format_lost_time;
+};
+
+struct _GstPulseSinkClass
+{
+  GstAudioBaseSinkClass parent_class;
+};
+
+GType gst_pulsesink_get_type (void);
+
+#define PULSE_SINK_TEMPLATE_CAPS \
+  _PULSE_CAPS_PCM \
+  _PULSE_CAPS_AC3 \
+  _PULSE_CAPS_EAC3 \
+  _PULSE_CAPS_DTS \
+  _PULSE_CAPS_MP3 \
+  _PULSE_CAPS_AAC
+
+G_END_DECLS
+
+#endif /* __GST_PULSESINK_H__ */
diff --git a/ext/pulse/pulsesrc.c b/ext/pulse/pulsesrc.c
new file mode 100644
index 0000000..7af74ee
--- /dev/null
+++ b/ext/pulse/pulsesrc.c
@@ -0,0 +1,1884 @@
+/*
+ *  GStreamer pulseaudio plugin
+ *
+ *  Copyright (c) 2004-2008 Lennart Poettering
+ *
+ *  gst-pulse is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as
+ *  published by the Free Software Foundation; either version 2.1 of the
+ *  License, or (at your option) any later version.
+ *
+ *  gst-pulse 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with gst-pulse; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ *  USA.
+ */
+
+/**
+ * SECTION:element-pulsesrc
+ * @see_also: pulsesink
+ *
+ * This element captures audio from a
+ * <ulink href="http://www.pulseaudio.org">PulseAudio sound server</ulink>.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -v pulsesrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=alsasrc.ogg
+ * ]| Record from a sound card using pulseaudio and encode to Ogg/Vorbis.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include <gst/base/gstbasesrc.h>
+#include <gst/gsttaglist.h>
+#include <gst/audio/audio.h>
+
+#include "pulsesrc.h"
+#include "pulseutil.h"
+
+GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
+#define GST_CAT_DEFAULT pulse_debug
+
+#define DEFAULT_SERVER            NULL
+#define DEFAULT_DEVICE            NULL
+#define DEFAULT_CURRENT_DEVICE    NULL
+#define DEFAULT_DEVICE_NAME       NULL
+
+#define DEFAULT_VOLUME          1.0
+#define DEFAULT_MUTE            FALSE
+#define MAX_VOLUME              10.0
+
+/* See the pulsesink code for notes on how we interact with the PA mainloop
+ * thread. */
+
+enum
+{
+  PROP_0,
+  PROP_SERVER,
+  PROP_DEVICE,
+  PROP_DEVICE_NAME,
+  PROP_CURRENT_DEVICE,
+  PROP_CLIENT_NAME,
+  PROP_STREAM_PROPERTIES,
+  PROP_SOURCE_OUTPUT_INDEX,
+  PROP_VOLUME,
+  PROP_MUTE,
+  PROP_LAST
+};
+
+static void gst_pulsesrc_destroy_stream (GstPulseSrc * pulsesrc);
+static void gst_pulsesrc_destroy_context (GstPulseSrc * pulsesrc);
+
+static void gst_pulsesrc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_pulsesrc_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_pulsesrc_finalize (GObject * object);
+
+static gboolean gst_pulsesrc_set_corked (GstPulseSrc * psrc, gboolean corked,
+    gboolean wait);
+static gboolean gst_pulsesrc_open (GstAudioSrc * asrc);
+
+static gboolean gst_pulsesrc_close (GstAudioSrc * asrc);
+
+static gboolean gst_pulsesrc_prepare (GstAudioSrc * asrc,
+    GstAudioRingBufferSpec * spec);
+
+static gboolean gst_pulsesrc_unprepare (GstAudioSrc * asrc);
+
+static guint gst_pulsesrc_read (GstAudioSrc * asrc, gpointer data,
+    guint length, GstClockTime * timestamp);
+static guint gst_pulsesrc_delay (GstAudioSrc * asrc);
+
+static void gst_pulsesrc_reset (GstAudioSrc * src);
+
+static gboolean gst_pulsesrc_negotiate (GstBaseSrc * basesrc);
+static gboolean gst_pulsesrc_event (GstBaseSrc * basesrc, GstEvent * event);
+
+static GstStateChangeReturn gst_pulsesrc_change_state (GstElement *
+    element, GstStateChange transition);
+
+static GstClockTime gst_pulsesrc_get_time (GstClock * clock, GstPulseSrc * src);
+
+static GstStaticPadTemplate pad_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (_PULSE_CAPS_PCM)
+    );
+
+#define gst_pulsesrc_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstPulseSrc, gst_pulsesrc, GST_TYPE_AUDIO_SRC,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL));
+
+static void
+gst_pulsesrc_class_init (GstPulseSrcClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstAudioSrcClass *gstaudiosrc_class = GST_AUDIO_SRC_CLASS (klass);
+  GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  gchar *clientname;
+
+  gobject_class->finalize = gst_pulsesrc_finalize;
+  gobject_class->set_property = gst_pulsesrc_set_property;
+  gobject_class->get_property = gst_pulsesrc_get_property;
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_pulsesrc_change_state);
+
+  gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_pulsesrc_event);
+  gstbasesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_pulsesrc_negotiate);
+
+  gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_pulsesrc_open);
+  gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_pulsesrc_close);
+  gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_pulsesrc_prepare);
+  gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_pulsesrc_unprepare);
+  gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_pulsesrc_read);
+  gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_pulsesrc_delay);
+  gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_pulsesrc_reset);
+
+  /* Overwrite GObject fields */
+  g_object_class_install_property (gobject_class,
+      PROP_SERVER,
+      g_param_spec_string ("server", "Server",
+          "The PulseAudio server to connect to", DEFAULT_SERVER,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DEVICE,
+      g_param_spec_string ("device", "Device",
+          "The PulseAudio source device to connect to", DEFAULT_DEVICE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CURRENT_DEVICE,
+      g_param_spec_string ("current-device", "Current Device",
+          "The current PulseAudio source device", DEFAULT_CURRENT_DEVICE,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_DEVICE_NAME,
+      g_param_spec_string ("device-name", "Device name",
+          "Human-readable name of the sound device", DEFAULT_DEVICE_NAME,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  clientname = gst_pulse_client_name ();
+  /**
+   * GstPulseSrc:client-name
+   *
+   * The PulseAudio client name to use.
+   */
+  g_object_class_install_property (gobject_class,
+      PROP_CLIENT_NAME,
+      g_param_spec_string ("client-name", "Client Name",
+          "The PulseAudio client_name_to_use", clientname,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+          GST_PARAM_MUTABLE_READY));
+  g_free (clientname);
+
+  /**
+   * GstPulseSrc:stream-properties:
+   *
+   * List of pulseaudio stream properties. A list of defined properties can be
+   * found in the <ulink href="http://0pointer.de/lennart/projects/pulseaudio/doxygen/proplist_8h.html">pulseaudio api docs</ulink>.
+   *
+   * Below is an example for registering as a music application to pulseaudio.
+   * |[
+   * GstStructure *props;
+   *
+   * props = gst_structure_from_string ("props,media.role=music", NULL);
+   * g_object_set (pulse, "stream-properties", props, NULL);
+   * gst_structure_free (props);
+   * ]|
+   */
+  g_object_class_install_property (gobject_class,
+      PROP_STREAM_PROPERTIES,
+      g_param_spec_boxed ("stream-properties", "stream properties",
+          "list of pulseaudio stream properties",
+          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstPulseSrc:source-output-index:
+   *
+   * The index of the PulseAudio source output corresponding to this element.
+   */
+  g_object_class_install_property (gobject_class,
+      PROP_SOURCE_OUTPUT_INDEX,
+      g_param_spec_uint ("source-output-index", "source output index",
+          "The index of the PulseAudio source output corresponding to this "
+          "record stream", 0, G_MAXUINT, PA_INVALID_INDEX,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "PulseAudio Audio Source",
+      "Source/Audio",
+      "Captures audio from a PulseAudio server", "Lennart Poettering");
+  gst_element_class_add_static_pad_template (gstelement_class, &pad_template);
+
+  /**
+   * GstPulseSrc:volume:
+   *
+   * The volume of the record stream.
+   */
+  g_object_class_install_property (gobject_class,
+      PROP_VOLUME, g_param_spec_double ("volume", "Volume",
+          "Linear volume of this stream, 1.0=100%",
+          0.0, MAX_VOLUME, DEFAULT_VOLUME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstPulseSrc:mute:
+   *
+   * Whether the stream is muted or not.
+   */
+  g_object_class_install_property (gobject_class,
+      PROP_MUTE, g_param_spec_boolean ("mute", "Mute",
+          "Mute state of this stream",
+          DEFAULT_MUTE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_pulsesrc_init (GstPulseSrc * pulsesrc)
+{
+  pulsesrc->server = NULL;
+  pulsesrc->device = NULL;
+  pulsesrc->client_name = gst_pulse_client_name ();
+  pulsesrc->device_description = NULL;
+
+  pulsesrc->context = NULL;
+  pulsesrc->stream = NULL;
+  pulsesrc->stream_connected = FALSE;
+  pulsesrc->source_output_idx = PA_INVALID_INDEX;
+
+  pulsesrc->read_buffer = NULL;
+  pulsesrc->read_buffer_length = 0;
+
+  pa_sample_spec_init (&pulsesrc->sample_spec);
+
+  pulsesrc->operation_success = FALSE;
+  pulsesrc->paused = TRUE;
+  pulsesrc->in_read = FALSE;
+
+  pulsesrc->volume = DEFAULT_VOLUME;
+  pulsesrc->volume_set = FALSE;
+
+  pulsesrc->mute = DEFAULT_MUTE;
+  pulsesrc->mute_set = FALSE;
+
+  pulsesrc->notify = 0;
+
+  pulsesrc->properties = NULL;
+  pulsesrc->proplist = NULL;
+
+  /* this should be the default but it isn't yet */
+  gst_audio_base_src_set_slave_method (GST_AUDIO_BASE_SRC (pulsesrc),
+      GST_AUDIO_BASE_SRC_SLAVE_SKEW);
+
+  /* override with a custom clock */
+  if (GST_AUDIO_BASE_SRC (pulsesrc)->clock)
+    gst_object_unref (GST_AUDIO_BASE_SRC (pulsesrc)->clock);
+
+  GST_AUDIO_BASE_SRC (pulsesrc)->clock =
+      gst_audio_clock_new ("GstPulseSrcClock",
+      (GstAudioClockGetTimeFunc) gst_pulsesrc_get_time, pulsesrc, NULL);
+}
+
+static void
+gst_pulsesrc_destroy_stream (GstPulseSrc * pulsesrc)
+{
+  if (pulsesrc->stream) {
+    pa_stream_disconnect (pulsesrc->stream);
+    pa_stream_unref (pulsesrc->stream);
+    pulsesrc->stream = NULL;
+    pulsesrc->stream_connected = FALSE;
+    pulsesrc->source_output_idx = PA_INVALID_INDEX;
+    g_object_notify (G_OBJECT (pulsesrc), "source-output-index");
+  }
+
+  g_free (pulsesrc->device_description);
+  pulsesrc->device_description = NULL;
+}
+
+static void
+gst_pulsesrc_destroy_context (GstPulseSrc * pulsesrc)
+{
+
+  gst_pulsesrc_destroy_stream (pulsesrc);
+
+  if (pulsesrc->context) {
+    pa_context_disconnect (pulsesrc->context);
+
+    /* Make sure we don't get any further callbacks */
+    pa_context_set_state_callback (pulsesrc->context, NULL, NULL);
+    pa_context_set_subscribe_callback (pulsesrc->context, NULL, NULL);
+
+    pa_context_unref (pulsesrc->context);
+
+    pulsesrc->context = NULL;
+  }
+}
+
+static void
+gst_pulsesrc_finalize (GObject * object)
+{
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (object);
+
+  g_free (pulsesrc->server);
+  g_free (pulsesrc->device);
+  g_free (pulsesrc->client_name);
+  g_free (pulsesrc->current_source_name);
+
+  if (pulsesrc->properties)
+    gst_structure_free (pulsesrc->properties);
+  if (pulsesrc->proplist)
+    pa_proplist_free (pulsesrc->proplist);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+#define CONTEXT_OK(c) ((c) && PA_CONTEXT_IS_GOOD (pa_context_get_state ((c))))
+#define STREAM_OK(s) ((s) && PA_STREAM_IS_GOOD (pa_stream_get_state ((s))))
+
+static gboolean
+gst_pulsesrc_is_dead (GstPulseSrc * pulsesrc, gboolean check_stream)
+{
+  if (!pulsesrc->stream_connected)
+    return TRUE;
+
+  if (!CONTEXT_OK (pulsesrc->context))
+    goto error;
+
+  if (check_stream && !STREAM_OK (pulsesrc->stream))
+    goto error;
+
+  return FALSE;
+
+error:
+  {
+    const gchar *err_str = pulsesrc->context ?
+        pa_strerror (pa_context_errno (pulsesrc->context)) : NULL;
+    GST_ELEMENT_ERROR ((pulsesrc), RESOURCE, FAILED, ("Disconnected: %s",
+            err_str), (NULL));
+    return TRUE;
+  }
+}
+
+static void
+gst_pulsesrc_source_info_cb (pa_context * c, const pa_source_info * i, int eol,
+    void *userdata)
+{
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata);
+
+  if (!i)
+    goto done;
+
+  g_free (pulsesrc->device_description);
+  pulsesrc->device_description = g_strdup (i->description);
+
+done:
+  pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
+}
+
+static gchar *
+gst_pulsesrc_device_description (GstPulseSrc * pulsesrc)
+{
+  pa_operation *o = NULL;
+  gchar *t;
+
+  if (!pulsesrc->mainloop)
+    goto no_mainloop;
+
+  pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+  if (!(o = pa_context_get_source_info_by_name (pulsesrc->context,
+              pulsesrc->device, gst_pulsesrc_source_info_cb, pulsesrc))) {
+
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+        ("pa_stream_get_source_info() failed: %s",
+            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+    goto unlock;
+  }
+
+  while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+
+    if (gst_pulsesrc_is_dead (pulsesrc, FALSE))
+      goto unlock;
+
+    pa_threaded_mainloop_wait (pulsesrc->mainloop);
+  }
+
+unlock:
+
+  if (o)
+    pa_operation_unref (o);
+
+  t = g_strdup (pulsesrc->device_description);
+
+  pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+  return t;
+
+no_mainloop:
+  {
+    GST_DEBUG_OBJECT (pulsesrc, "have no mainloop");
+    return NULL;
+  }
+}
+
+static void
+gst_pulsesrc_source_output_info_cb (pa_context * c,
+    const pa_source_output_info * i, int eol, void *userdata)
+{
+  GstPulseSrc *psrc;
+
+  psrc = GST_PULSESRC_CAST (userdata);
+
+  if (!i)
+    goto done;
+
+  /* If the index doesn't match our current stream,
+   * it implies we just recreated the stream (caps change)
+   */
+  if (i->index == psrc->source_output_idx) {
+    psrc->volume = pa_sw_volume_to_linear (pa_cvolume_max (&i->volume));
+    psrc->mute = i->mute;
+    psrc->current_source_idx = i->source;
+
+    if (G_UNLIKELY (psrc->volume > MAX_VOLUME)) {
+      GST_WARNING_OBJECT (psrc, "Clipped volume from %f to %f",
+          psrc->volume, MAX_VOLUME);
+      psrc->volume = MAX_VOLUME;
+    }
+  }
+
+done:
+  pa_threaded_mainloop_signal (psrc->mainloop, 0);
+}
+
+static void
+gst_pulsesrc_get_source_output_info (GstPulseSrc * pulsesrc, gdouble * volume,
+    gboolean * mute)
+{
+  pa_operation *o = NULL;
+
+  if (!pulsesrc->mainloop)
+    goto no_mainloop;
+
+  if (pulsesrc->source_output_idx == PA_INVALID_INDEX)
+    goto no_index;
+
+  pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+  if (!(o = pa_context_get_source_output_info (pulsesrc->context,
+              pulsesrc->source_output_idx, gst_pulsesrc_source_output_info_cb,
+              pulsesrc)))
+    goto info_failed;
+
+  while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+    pa_threaded_mainloop_wait (pulsesrc->mainloop);
+    if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
+      goto unlock;
+  }
+
+unlock:
+
+  if (volume)
+    *volume = pulsesrc->volume;
+  if (mute)
+    *mute = pulsesrc->mute;
+
+  if (o)
+    pa_operation_unref (o);
+
+  pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+  return;
+
+  /* ERRORS */
+no_mainloop:
+  {
+    GST_DEBUG_OBJECT (pulsesrc, "we have no mainloop");
+    if (volume)
+      *volume = pulsesrc->volume;
+    if (mute)
+      *mute = pulsesrc->mute;
+    return;
+  }
+no_index:
+  {
+    GST_DEBUG_OBJECT (pulsesrc, "we don't have a stream index");
+    if (volume)
+      *volume = pulsesrc->volume;
+    if (mute)
+      *mute = pulsesrc->mute;
+    return;
+  }
+info_failed:
+  {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+        ("pa_context_get_source_output_info() failed: %s",
+            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+    goto unlock;
+  }
+}
+
+static void
+gst_pulsesrc_current_source_info_cb (pa_context * c, const pa_source_info * i,
+    int eol, void *userdata)
+{
+  GstPulseSrc *psrc;
+
+  psrc = GST_PULSESRC_CAST (userdata);
+
+  if (!i)
+    goto done;
+
+  /* If the index doesn't match our current stream,
+   * it implies we just recreated the stream (caps change)
+   */
+  if (i->index == psrc->current_source_idx) {
+    g_free (psrc->current_source_name);
+    psrc->current_source_name = g_strdup (i->name);
+  }
+
+done:
+  pa_threaded_mainloop_signal (psrc->mainloop, 0);
+}
+
+static gchar *
+gst_pulsesrc_get_current_device (GstPulseSrc * pulsesrc)
+{
+  pa_operation *o = NULL;
+  gchar *current_src;
+
+  if (!pulsesrc->mainloop)
+    goto no_mainloop;
+
+  if (pulsesrc->source_output_idx == PA_INVALID_INDEX)
+    goto no_index;
+
+  gst_pulsesrc_get_source_output_info (pulsesrc, NULL, NULL);
+
+  pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+
+  if (!(o = pa_context_get_source_info_by_index (pulsesrc->context,
+              pulsesrc->current_source_idx, gst_pulsesrc_current_source_info_cb,
+              pulsesrc)))
+    goto info_failed;
+
+  while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+    pa_threaded_mainloop_wait (pulsesrc->mainloop);
+    if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
+      goto unlock;
+  }
+
+unlock:
+
+  current_src = g_strdup (pulsesrc->current_source_name);
+
+  if (o)
+    pa_operation_unref (o);
+
+  pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+  return current_src;
+
+  /* ERRORS */
+no_mainloop:
+  {
+    GST_DEBUG_OBJECT (pulsesrc, "we have no mainloop");
+    return NULL;
+  }
+no_index:
+  {
+    GST_DEBUG_OBJECT (pulsesrc, "we don't have a stream index");
+    return NULL;
+  }
+info_failed:
+  {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+        ("pa_context_get_source_output_info() failed: %s",
+            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+    goto unlock;
+  }
+}
+
+static void
+gst_pulsesrc_set_stream_volume (GstPulseSrc * pulsesrc, gdouble volume)
+{
+  pa_cvolume v;
+  pa_operation *o = NULL;
+
+  if (!pulsesrc->mainloop)
+    goto no_mainloop;
+
+  if (!pulsesrc->source_output_idx)
+    goto no_index;
+
+  pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+  GST_DEBUG_OBJECT (pulsesrc, "setting volume to %f", volume);
+
+  gst_pulse_cvolume_from_linear (&v, pulsesrc->sample_spec.channels, volume);
+
+  if (!(o = pa_context_set_source_output_volume (pulsesrc->context,
+              pulsesrc->source_output_idx, &v, NULL, NULL)))
+    goto volume_failed;
+
+  /* We don't really care about the result of this call */
+unlock:
+
+  if (o)
+    pa_operation_unref (o);
+
+  pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+  return;
+
+  /* ERRORS */
+no_mainloop:
+  {
+    pulsesrc->volume = volume;
+    pulsesrc->volume_set = TRUE;
+    GST_DEBUG_OBJECT (pulsesrc, "we have no mainloop");
+    return;
+  }
+no_index:
+  {
+    pulsesrc->volume = volume;
+    pulsesrc->volume_set = TRUE;
+    GST_DEBUG_OBJECT (pulsesrc, "we don't have a stream index");
+    return;
+  }
+volume_failed:
+  {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+        ("pa_stream_set_source_output_volume() failed: %s",
+            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+    goto unlock;
+  }
+}
+
+static void
+gst_pulsesrc_set_stream_mute (GstPulseSrc * pulsesrc, gboolean mute)
+{
+  pa_operation *o = NULL;
+
+  if (!pulsesrc->mainloop)
+    goto no_mainloop;
+
+  if (!pulsesrc->source_output_idx)
+    goto no_index;
+
+  pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+  GST_DEBUG_OBJECT (pulsesrc, "setting mute state to %d", mute);
+
+  if (!(o = pa_context_set_source_output_mute (pulsesrc->context,
+              pulsesrc->source_output_idx, mute, NULL, NULL)))
+    goto mute_failed;
+
+  /* We don't really care about the result of this call */
+unlock:
+
+  if (o)
+    pa_operation_unref (o);
+
+  pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+  return;
+
+  /* ERRORS */
+no_mainloop:
+  {
+    pulsesrc->mute = mute;
+    pulsesrc->mute_set = TRUE;
+    GST_DEBUG_OBJECT (pulsesrc, "we have no mainloop");
+    return;
+  }
+no_index:
+  {
+    pulsesrc->mute = mute;
+    pulsesrc->mute_set = TRUE;
+    GST_DEBUG_OBJECT (pulsesrc, "we don't have a stream index");
+    return;
+  }
+mute_failed:
+  {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+        ("pa_stream_set_source_output_mute() failed: %s",
+            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+    goto unlock;
+  }
+}
+
+static void
+gst_pulsesrc_set_stream_device (GstPulseSrc * pulsesrc, const gchar * device)
+{
+  pa_operation *o = NULL;
+
+  if (!pulsesrc->mainloop)
+    goto no_mainloop;
+
+  if (!pulsesrc->source_output_idx)
+    goto no_index;
+
+  pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+  GST_DEBUG_OBJECT (pulsesrc, "setting stream device to %s", device);
+
+  if (!(o = pa_context_move_source_output_by_name (pulsesrc->context,
+              pulsesrc->source_output_idx, device, NULL, NULL)))
+    goto move_failed;
+
+unlock:
+
+  if (o)
+    pa_operation_unref (o);
+
+  pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+  return;
+
+  /* ERRORS */
+no_mainloop:
+  {
+    GST_DEBUG_OBJECT (pulsesrc, "we have no mainloop");
+    return;
+  }
+no_index:
+  {
+    GST_DEBUG_OBJECT (pulsesrc, "we don't have a stream index");
+    return;
+  }
+move_failed:
+  {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+        ("pa_context_move_source_output_by_name(%s) failed: %s",
+            device, pa_strerror (pa_context_errno (pulsesrc->context))),
+        (NULL));
+    goto unlock;
+  }
+}
+
+static void
+gst_pulsesrc_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (object);
+
+  switch (prop_id) {
+    case PROP_SERVER:
+      g_free (pulsesrc->server);
+      pulsesrc->server = g_value_dup_string (value);
+      break;
+    case PROP_DEVICE:
+      g_free (pulsesrc->device);
+      pulsesrc->device = g_value_dup_string (value);
+      gst_pulsesrc_set_stream_device (pulsesrc, pulsesrc->device);
+      break;
+    case PROP_CLIENT_NAME:
+      g_free (pulsesrc->client_name);
+      if (!g_value_get_string (value)) {
+        GST_WARNING_OBJECT (pulsesrc,
+            "Empty PulseAudio client name not allowed. Resetting to default value");
+        pulsesrc->client_name = gst_pulse_client_name ();
+      } else
+        pulsesrc->client_name = g_value_dup_string (value);
+      break;
+    case PROP_STREAM_PROPERTIES:
+      if (pulsesrc->properties)
+        gst_structure_free (pulsesrc->properties);
+      pulsesrc->properties =
+          gst_structure_copy (gst_value_get_structure (value));
+      if (pulsesrc->proplist)
+        pa_proplist_free (pulsesrc->proplist);
+      pulsesrc->proplist = gst_pulse_make_proplist (pulsesrc->properties);
+      break;
+    case PROP_VOLUME:
+      gst_pulsesrc_set_stream_volume (pulsesrc, g_value_get_double (value));
+      break;
+    case PROP_MUTE:
+      gst_pulsesrc_set_stream_mute (pulsesrc, g_value_get_boolean (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_pulsesrc_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (object);
+
+  switch (prop_id) {
+    case PROP_SERVER:
+      g_value_set_string (value, pulsesrc->server);
+      break;
+    case PROP_DEVICE:
+      g_value_set_string (value, pulsesrc->device);
+      break;
+    case PROP_CURRENT_DEVICE:
+    {
+      gchar *current_device = gst_pulsesrc_get_current_device (pulsesrc);
+      if (current_device)
+        g_value_take_string (value, current_device);
+      else
+        g_value_set_string (value, "");
+      break;
+    }
+    case PROP_DEVICE_NAME:
+      g_value_take_string (value, gst_pulsesrc_device_description (pulsesrc));
+      break;
+    case PROP_CLIENT_NAME:
+      g_value_set_string (value, pulsesrc->client_name);
+      break;
+    case PROP_STREAM_PROPERTIES:
+      gst_value_set_structure (value, pulsesrc->properties);
+      break;
+    case PROP_SOURCE_OUTPUT_INDEX:
+      g_value_set_uint (value, pulsesrc->source_output_idx);
+      break;
+    case PROP_VOLUME:
+    {
+      gdouble volume;
+      gst_pulsesrc_get_source_output_info (pulsesrc, &volume, NULL);
+      g_value_set_double (value, volume);
+      break;
+    }
+    case PROP_MUTE:
+    {
+      gboolean mute;
+      gst_pulsesrc_get_source_output_info (pulsesrc, NULL, &mute);
+      g_value_set_boolean (value, mute);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_pulsesrc_context_state_cb (pa_context * c, void *userdata)
+{
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata);
+
+  switch (pa_context_get_state (c)) {
+    case PA_CONTEXT_READY:
+    case PA_CONTEXT_TERMINATED:
+    case PA_CONTEXT_FAILED:
+      pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
+      break;
+
+    case PA_CONTEXT_UNCONNECTED:
+    case PA_CONTEXT_CONNECTING:
+    case PA_CONTEXT_AUTHORIZING:
+    case PA_CONTEXT_SETTING_NAME:
+      break;
+  }
+}
+
+static void
+gst_pulsesrc_stream_state_cb (pa_stream * s, void *userdata)
+{
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata);
+
+  switch (pa_stream_get_state (s)) {
+
+    case PA_STREAM_READY:
+    case PA_STREAM_FAILED:
+    case PA_STREAM_TERMINATED:
+      pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
+      break;
+
+    case PA_STREAM_UNCONNECTED:
+    case PA_STREAM_CREATING:
+      break;
+  }
+}
+
+static void
+gst_pulsesrc_stream_request_cb (pa_stream * s, size_t length, void *userdata)
+{
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata);
+
+  GST_LOG_OBJECT (pulsesrc, "got request for length %" G_GSIZE_FORMAT, length);
+
+  if (pulsesrc->in_read) {
+    /* only signal when reading */
+    pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
+  }
+}
+
+static void
+gst_pulsesrc_stream_latency_update_cb (pa_stream * s, void *userdata)
+{
+  const pa_timing_info *info;
+  pa_usec_t source_usec;
+
+  info = pa_stream_get_timing_info (s);
+
+  if (!info) {
+    GST_LOG_OBJECT (GST_PULSESRC_CAST (userdata),
+        "latency update (information unknown)");
+    return;
+  }
+  source_usec = info->configured_source_usec;
+
+  GST_LOG_OBJECT (GST_PULSESRC_CAST (userdata),
+      "latency_update, %" G_GUINT64_FORMAT ", %d:%" G_GINT64_FORMAT ", %d:%"
+      G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT,
+      GST_TIMEVAL_TO_TIME (info->timestamp), info->write_index_corrupt,
+      info->write_index, info->read_index_corrupt, info->read_index,
+      info->source_usec, source_usec);
+}
+
+static void
+gst_pulsesrc_stream_underflow_cb (pa_stream * s, void *userdata)
+{
+  GST_WARNING_OBJECT (GST_PULSESRC_CAST (userdata), "Got underflow");
+}
+
+static void
+gst_pulsesrc_stream_overflow_cb (pa_stream * s, void *userdata)
+{
+  GST_WARNING_OBJECT (GST_PULSESRC_CAST (userdata), "Got overflow");
+}
+
+static void
+gst_pulsesrc_context_subscribe_cb (pa_context * c,
+    pa_subscription_event_type_t t, uint32_t idx, void *userdata)
+{
+  GstPulseSrc *psrc = GST_PULSESRC (userdata);
+
+  if (t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT | PA_SUBSCRIPTION_EVENT_CHANGE)
+      && t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT | PA_SUBSCRIPTION_EVENT_NEW))
+    return;
+
+  if (idx != psrc->source_output_idx)
+    return;
+
+  /* Actually this event is also triggered when other properties of the stream
+   * change that are unrelated to the volume. However it is probably cheaper to
+   * signal the change here and check for the volume when the GObject property
+   * is read instead of querying it always. */
+
+  /* inform streaming thread to notify */
+  g_atomic_int_compare_and_exchange (&psrc->notify, 0, 1);
+}
+
+static gboolean
+gst_pulsesrc_open (GstAudioSrc * asrc)
+{
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
+
+  pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+  g_assert (!pulsesrc->context);
+  g_assert (!pulsesrc->stream);
+
+  GST_DEBUG_OBJECT (pulsesrc, "opening device");
+
+  if (!(pulsesrc->context =
+          pa_context_new (pa_threaded_mainloop_get_api (pulsesrc->mainloop),
+              pulsesrc->client_name))) {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to create context"),
+        (NULL));
+    goto unlock_and_fail;
+  }
+
+  pa_context_set_state_callback (pulsesrc->context,
+      gst_pulsesrc_context_state_cb, pulsesrc);
+  pa_context_set_subscribe_callback (pulsesrc->context,
+      gst_pulsesrc_context_subscribe_cb, pulsesrc);
+
+  GST_DEBUG_OBJECT (pulsesrc, "connect to server %s",
+      GST_STR_NULL (pulsesrc->server));
+
+  if (pa_context_connect (pulsesrc->context, pulsesrc->server, 0, NULL) < 0) {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect: %s",
+            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+    goto unlock_and_fail;
+  }
+
+  for (;;) {
+    pa_context_state_t state;
+
+    state = pa_context_get_state (pulsesrc->context);
+
+    if (!PA_CONTEXT_IS_GOOD (state)) {
+      GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect: %s",
+              pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+      goto unlock_and_fail;
+    }
+
+    if (state == PA_CONTEXT_READY)
+      break;
+
+    /* Wait until the context is ready */
+    pa_threaded_mainloop_wait (pulsesrc->mainloop);
+  }
+  GST_DEBUG_OBJECT (pulsesrc, "connected");
+
+  pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+  return TRUE;
+
+  /* ERRORS */
+unlock_and_fail:
+  {
+    gst_pulsesrc_destroy_context (pulsesrc);
+
+    pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_pulsesrc_close (GstAudioSrc * asrc)
+{
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
+
+  pa_threaded_mainloop_lock (pulsesrc->mainloop);
+  gst_pulsesrc_destroy_context (pulsesrc);
+  pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+  return TRUE;
+}
+
+static gboolean
+gst_pulsesrc_unprepare (GstAudioSrc * asrc)
+{
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
+
+  pa_threaded_mainloop_lock (pulsesrc->mainloop);
+  gst_pulsesrc_destroy_stream (pulsesrc);
+
+  pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+  pulsesrc->read_buffer = NULL;
+  pulsesrc->read_buffer_length = 0;
+
+  return TRUE;
+}
+
+static guint
+gst_pulsesrc_read (GstAudioSrc * asrc, gpointer data, guint length,
+    GstClockTime * timestamp)
+{
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
+  size_t sum = 0;
+
+  if (g_atomic_int_compare_and_exchange (&pulsesrc->notify, 1, 0)) {
+    g_object_notify (G_OBJECT (pulsesrc), "volume");
+    g_object_notify (G_OBJECT (pulsesrc), "mute");
+    g_object_notify (G_OBJECT (pulsesrc), "current-device");
+  }
+
+  pa_threaded_mainloop_lock (pulsesrc->mainloop);
+  pulsesrc->in_read = TRUE;
+
+  if (!pulsesrc->stream_connected)
+    goto not_connected;
+
+  if (pulsesrc->paused)
+    goto was_paused;
+
+  while (length > 0) {
+    size_t l;
+
+    GST_LOG_OBJECT (pulsesrc, "reading %u bytes", length);
+
+    /*check if we have a leftover buffer */
+    if (!pulsesrc->read_buffer) {
+      for (;;) {
+        if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
+          goto unlock_and_fail;
+
+        /* read all available data, we keep a pointer to the data and the length
+         * and take from it what we need. */
+        if (pa_stream_peek (pulsesrc->stream, &pulsesrc->read_buffer,
+                &pulsesrc->read_buffer_length) < 0)
+          goto peek_failed;
+
+        GST_LOG_OBJECT (pulsesrc, "have data of %" G_GSIZE_FORMAT " bytes",
+            pulsesrc->read_buffer_length);
+
+        /* if we have data, process if */
+        if (pulsesrc->read_buffer && pulsesrc->read_buffer_length)
+          break;
+
+        /* now wait for more data to become available */
+        GST_LOG_OBJECT (pulsesrc, "waiting for data");
+        pa_threaded_mainloop_wait (pulsesrc->mainloop);
+
+        if (pulsesrc->paused)
+          goto was_paused;
+      }
+    }
+
+    l = pulsesrc->read_buffer_length >
+        length ? length : pulsesrc->read_buffer_length;
+
+    memcpy (data, pulsesrc->read_buffer, l);
+
+    pulsesrc->read_buffer = (const guint8 *) pulsesrc->read_buffer + l;
+    pulsesrc->read_buffer_length -= l;
+
+    data = (guint8 *) data + l;
+    length -= l;
+    sum += l;
+
+    if (pulsesrc->read_buffer_length <= 0) {
+      /* we copied all of the data, drop it now */
+      if (pa_stream_drop (pulsesrc->stream) < 0)
+        goto drop_failed;
+
+      /* reset pointer to data */
+      pulsesrc->read_buffer = NULL;
+      pulsesrc->read_buffer_length = 0;
+    }
+  }
+
+  pulsesrc->in_read = FALSE;
+  pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+  return sum;
+
+  /* ERRORS */
+not_connected:
+  {
+    GST_LOG_OBJECT (pulsesrc, "we are not connected");
+    goto unlock_and_fail;
+  }
+was_paused:
+  {
+    GST_LOG_OBJECT (pulsesrc, "we are paused");
+    goto unlock_and_fail;
+  }
+peek_failed:
+  {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+        ("pa_stream_peek() failed: %s",
+            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+    goto unlock_and_fail;
+  }
+drop_failed:
+  {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+        ("pa_stream_drop() failed: %s",
+            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+    goto unlock_and_fail;
+  }
+unlock_and_fail:
+  {
+    pulsesrc->in_read = FALSE;
+    pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+    return (guint) - 1;
+  }
+}
+
+/* return the delay in samples */
+static guint
+gst_pulsesrc_delay (GstAudioSrc * asrc)
+{
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
+  pa_usec_t t;
+  int negative, res;
+  guint result;
+
+  pa_threaded_mainloop_lock (pulsesrc->mainloop);
+  if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
+    goto server_dead;
+
+  /* get the latency, this can fail when we don't have a latency update yet.
+   * We don't want to wait for latency updates here but we just return 0. */
+  res = pa_stream_get_latency (pulsesrc->stream, &t, &negative);
+
+  pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+  if (res < 0) {
+    GST_DEBUG_OBJECT (pulsesrc, "could not get latency");
+    result = 0;
+  } else {
+    if (negative)
+      result = 0;
+    else
+      result = (guint) ((t * pulsesrc->sample_spec.rate) / 1000000LL);
+  }
+  return result;
+
+  /* ERRORS */
+server_dead:
+  {
+    GST_DEBUG_OBJECT (pulsesrc, "the server is dead");
+    pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+    return 0;
+  }
+}
+
+static gboolean
+gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps ** caps,
+    GstAudioRingBufferSpec * rspec)
+{
+  pa_channel_map channel_map;
+  const pa_channel_map *m;
+  GstStructure *s;
+  gboolean need_channel_layout = FALSE;
+  GstAudioRingBufferSpec new_spec, *spec = NULL;
+  const gchar *name;
+  int i;
+
+  /* If we already have a stream (renegotiation), free it first */
+  if (pulsesrc->stream)
+    gst_pulsesrc_destroy_stream (pulsesrc);
+
+  if (rspec) {
+    /* Post-negotiation, we already have a ringbuffer spec, so we just need to
+     * use it to create a stream. */
+    spec = rspec;
+
+    /* At this point, we expect the channel-mask to be set in caps, so we just
+     * use that */
+    if (!gst_pulse_gst_to_channel_map (&channel_map, spec))
+      goto invalid_spec;
+
+  } else if (caps) {
+    /* At negotiation time, we get a fixed caps and use it to set up a stream */
+    s = gst_caps_get_structure (*caps, 0);
+    gst_structure_get_int (s, "channels", &new_spec.info.channels);
+    if (!gst_structure_has_field (s, "channel-mask")) {
+      if (new_spec.info.channels == 1) {
+        pa_channel_map_init_mono (&channel_map);
+      } else if (new_spec.info.channels == 2) {
+        pa_channel_map_init_stereo (&channel_map);
+      } else {
+        need_channel_layout = TRUE;
+        gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK,
+            G_GUINT64_CONSTANT (0), NULL);
+      }
+    }
+
+    memset (&new_spec, 0, sizeof (GstAudioRingBufferSpec));
+    new_spec.latency_time = GST_SECOND;
+    if (!gst_audio_ring_buffer_parse_caps (&new_spec, *caps))
+      goto invalid_caps;
+
+    /* Keep the refcount of the caps at 1 to make them writable */
+    gst_caps_unref (new_spec.caps);
+
+    if (!need_channel_layout
+        && !gst_pulse_gst_to_channel_map (&channel_map, &new_spec)) {
+      need_channel_layout = TRUE;
+      gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK,
+          G_GUINT64_CONSTANT (0), NULL);
+      for (i = 0; i < G_N_ELEMENTS (new_spec.info.position); i++)
+        new_spec.info.position[i] = GST_AUDIO_CHANNEL_POSITION_INVALID;
+    }
+
+    spec = &new_spec;
+  } else {
+    /* !rspec && !caps */
+    g_assert_not_reached ();
+  }
+
+  if (!gst_pulse_fill_sample_spec (spec, &pulsesrc->sample_spec))
+    goto invalid_spec;
+
+  pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+  if (!pulsesrc->context)
+    goto bad_context;
+
+  name = "Record Stream";
+  if (pulsesrc->proplist) {
+    if (!(pulsesrc->stream = pa_stream_new_with_proplist (pulsesrc->context,
+                name, &pulsesrc->sample_spec,
+                (need_channel_layout) ? NULL : &channel_map,
+                pulsesrc->proplist)))
+      goto create_failed;
+
+  } else if (!(pulsesrc->stream = pa_stream_new (pulsesrc->context,
+              name, &pulsesrc->sample_spec,
+              (need_channel_layout) ? NULL : &channel_map)))
+    goto create_failed;
+
+  if (caps) {
+    m = pa_stream_get_channel_map (pulsesrc->stream);
+    gst_pulse_channel_map_to_gst (m, &new_spec);
+    gst_audio_channel_positions_to_valid_order (new_spec.info.position,
+        new_spec.info.channels);
+    gst_caps_unref (*caps);
+    *caps = gst_audio_info_to_caps (&new_spec.info);
+
+    GST_DEBUG_OBJECT (pulsesrc, "Caps are %" GST_PTR_FORMAT, *caps);
+  }
+
+
+  pa_stream_set_state_callback (pulsesrc->stream, gst_pulsesrc_stream_state_cb,
+      pulsesrc);
+  pa_stream_set_read_callback (pulsesrc->stream, gst_pulsesrc_stream_request_cb,
+      pulsesrc);
+  pa_stream_set_underflow_callback (pulsesrc->stream,
+      gst_pulsesrc_stream_underflow_cb, pulsesrc);
+  pa_stream_set_overflow_callback (pulsesrc->stream,
+      gst_pulsesrc_stream_overflow_cb, pulsesrc);
+  pa_stream_set_latency_update_callback (pulsesrc->stream,
+      gst_pulsesrc_stream_latency_update_cb, pulsesrc);
+
+  pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+  return TRUE;
+
+  /* ERRORS */
+invalid_caps:
+  {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, SETTINGS,
+        ("Can't parse caps."), (NULL));
+    goto fail;
+  }
+invalid_spec:
+  {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, SETTINGS,
+        ("Invalid sample specification."), (NULL));
+    goto fail;
+  }
+bad_context:
+  {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Bad context"), (NULL));
+    goto unlock_and_fail;
+  }
+create_failed:
+  {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+        ("Failed to create stream: %s",
+            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+    goto unlock_and_fail;
+  }
+unlock_and_fail:
+  {
+    gst_pulsesrc_destroy_stream (pulsesrc);
+
+    pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+  fail:
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_pulsesrc_event (GstBaseSrc * basesrc, GstEvent * event)
+{
+  GST_DEBUG_OBJECT (basesrc, "handle event %" GST_PTR_FORMAT, event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_RECONFIGURE:
+      gst_pad_check_reconfigure (GST_BASE_SRC_PAD (basesrc));
+      break;
+    default:
+      break;
+  }
+  return GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event);
+}
+
+/* This is essentially gst_base_src_negotiate_default() but the caps
+ * are guaranteed to have a channel layout for > 2 channels
+ */
+static gboolean
+gst_pulsesrc_negotiate (GstBaseSrc * basesrc)
+{
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (basesrc);
+  GstCaps *thiscaps;
+  GstCaps *caps = NULL;
+  GstCaps *peercaps = NULL;
+  gboolean result = FALSE;
+
+  /* first see what is possible on our source pad */
+  thiscaps = gst_pad_query_caps (GST_BASE_SRC_PAD (basesrc), NULL);
+  GST_DEBUG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps);
+  /* nothing or anything is allowed, we're done */
+  if (thiscaps == NULL || gst_caps_is_any (thiscaps))
+    goto no_nego_needed;
+
+  /* get the peer caps */
+  peercaps = gst_pad_peer_query_caps (GST_BASE_SRC_PAD (basesrc), NULL);
+  GST_DEBUG_OBJECT (basesrc, "caps of peer: %" GST_PTR_FORMAT, peercaps);
+  if (peercaps) {
+    /* get intersection */
+    caps = gst_caps_intersect (thiscaps, peercaps);
+    GST_DEBUG_OBJECT (basesrc, "intersect: %" GST_PTR_FORMAT, caps);
+    gst_caps_unref (thiscaps);
+    gst_caps_unref (peercaps);
+  } else {
+    /* no peer, work with our own caps then */
+    caps = thiscaps;
+  }
+  if (caps) {
+    /* take first (and best, since they are sorted) possibility */
+    caps = gst_caps_truncate (caps);
+
+    /* now fixate */
+    if (!gst_caps_is_empty (caps)) {
+      caps = GST_BASE_SRC_CLASS (parent_class)->fixate (basesrc, caps);
+      GST_DEBUG_OBJECT (basesrc, "fixated to: %" GST_PTR_FORMAT, caps);
+
+      if (gst_caps_is_any (caps)) {
+        /* hmm, still anything, so element can do anything and
+         * nego is not needed */
+        result = TRUE;
+      } else if (gst_caps_is_fixed (caps)) {
+        /* yay, fixed caps, use those then */
+        result = gst_pulsesrc_create_stream (pulsesrc, &caps, NULL);
+        if (result)
+          result = gst_base_src_set_caps (basesrc, caps);
+      }
+    }
+    gst_caps_unref (caps);
+  }
+  return result;
+
+no_nego_needed:
+  {
+    GST_DEBUG_OBJECT (basesrc, "no negotiation needed");
+    if (thiscaps)
+      gst_caps_unref (thiscaps);
+    return TRUE;
+  }
+}
+
+static gboolean
+gst_pulsesrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec)
+{
+  pa_buffer_attr wanted;
+  const pa_buffer_attr *actual;
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
+  pa_stream_flags_t flags;
+  pa_operation *o;
+  GstAudioClock *clock;
+
+  pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+  if (!pulsesrc->stream)
+    gst_pulsesrc_create_stream (pulsesrc, NULL, spec);
+
+  {
+    GstAudioRingBufferSpec s = *spec;
+    const pa_channel_map *m;
+
+    m = pa_stream_get_channel_map (pulsesrc->stream);
+    gst_pulse_channel_map_to_gst (m, &s);
+    gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SRC
+        (pulsesrc)->ringbuffer, s.info.position);
+  }
+
+  /* enable event notifications */
+  GST_LOG_OBJECT (pulsesrc, "subscribing to context events");
+  if (!(o = pa_context_subscribe (pulsesrc->context,
+              PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, NULL, NULL))) {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+        ("pa_context_subscribe() failed: %s",
+            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+    goto unlock_and_fail;
+  }
+
+  pa_operation_unref (o);
+
+  /* There's a bit of a disconnect here between the audio ringbuffer and what
+   * PulseAudio provides. The audio ringbuffer provide a total of buffer_time
+   * worth of buffering, divided into segments of latency_time size. We're
+   * asking PulseAudio to provide a total latency of latency_time, which, with
+   * PA_STREAM_ADJUST_LATENCY, effectively sets itself up as a ringbuffer with
+   * one segment being the hardware buffer, and the other the software buffer.
+   * This segment size is returned as the fragsize.
+   *
+   * Since the two concepts don't map very well, what we do is keep segsize as
+   * it is (unless fragsize is even larger, in which case we use that). We'll
+   * get data from PulseAudio in smaller chunks than we want to pass on as an
+   * element, and we coalesce those chunks in the ringbuffer memory and pass it
+   * on in the expected chunk size. */
+  wanted.maxlength = spec->segsize * spec->segtotal;
+  wanted.tlength = -1;
+  wanted.prebuf = 0;
+  wanted.minreq = -1;
+  wanted.fragsize = spec->segsize;
+
+  GST_INFO_OBJECT (pulsesrc, "maxlength: %d", wanted.maxlength);
+  GST_INFO_OBJECT (pulsesrc, "tlength:   %d", wanted.tlength);
+  GST_INFO_OBJECT (pulsesrc, "prebuf:    %d", wanted.prebuf);
+  GST_INFO_OBJECT (pulsesrc, "minreq:    %d", wanted.minreq);
+  GST_INFO_OBJECT (pulsesrc, "fragsize:  %d", wanted.fragsize);
+
+  flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE |
+      PA_STREAM_NOT_MONOTONIC | PA_STREAM_ADJUST_LATENCY |
+      PA_STREAM_START_CORKED;
+
+  if (pa_stream_connect_record (pulsesrc->stream, pulsesrc->device, &wanted,
+          flags) < 0) {
+    goto connect_failed;
+  }
+
+  /* our clock will now start from 0 again */
+  clock = GST_AUDIO_CLOCK (GST_AUDIO_BASE_SRC (pulsesrc)->clock);
+  gst_audio_clock_reset (clock, 0);
+
+  pulsesrc->corked = TRUE;
+
+  for (;;) {
+    pa_stream_state_t state;
+
+    state = pa_stream_get_state (pulsesrc->stream);
+
+    if (!PA_STREAM_IS_GOOD (state))
+      goto stream_is_bad;
+
+    if (state == PA_STREAM_READY)
+      break;
+
+    /* Wait until the stream is ready */
+    pa_threaded_mainloop_wait (pulsesrc->mainloop);
+  }
+  pulsesrc->stream_connected = TRUE;
+
+  /* store the source output index so it can be accessed via a property */
+  pulsesrc->source_output_idx = pa_stream_get_index (pulsesrc->stream);
+  g_object_notify (G_OBJECT (pulsesrc), "source-output-index");
+
+  /* Although source output stream muting is supported, there is a bug in
+   * PulseAudio that doesn't allow us to do this at startup, so we mute
+   * manually post-connect. This should be moved back pre-connect once things
+   * are fixed on the PulseAudio side. */
+  if (pulsesrc->mute_set && pulsesrc->mute) {
+    gst_pulsesrc_set_stream_mute (pulsesrc, pulsesrc->mute);
+    pulsesrc->mute_set = FALSE;
+  }
+
+  if (pulsesrc->volume_set) {
+    gst_pulsesrc_set_stream_volume (pulsesrc, pulsesrc->volume);
+    pulsesrc->volume_set = FALSE;
+  }
+
+  /* get the actual buffering properties now */
+  actual = pa_stream_get_buffer_attr (pulsesrc->stream);
+
+  GST_INFO_OBJECT (pulsesrc, "maxlength: %d", actual->maxlength);
+  GST_INFO_OBJECT (pulsesrc, "tlength:   %d (wanted: %d)",
+      actual->tlength, wanted.tlength);
+  GST_INFO_OBJECT (pulsesrc, "prebuf:    %d", actual->prebuf);
+  GST_INFO_OBJECT (pulsesrc, "minreq:    %d (wanted %d)", actual->minreq,
+      wanted.minreq);
+  GST_INFO_OBJECT (pulsesrc, "fragsize:  %d (wanted %d)",
+      actual->fragsize, wanted.fragsize);
+
+  if (actual->fragsize >= spec->segsize) {
+    spec->segsize = actual->fragsize;
+  } else {
+    /* fragsize is smaller than what we wanted, so let the read function
+     * coalesce the smaller chunks as they come in */
+  }
+
+  /* Fix up the total ringbuffer size based on what we actually got */
+  spec->segtotal = actual->maxlength / spec->segsize;
+  /* Don't buffer less than 2 segments as the ringbuffer can't deal with it */
+  if (spec->segtotal < 2)
+    spec->segtotal = 2;
+
+  if (!pulsesrc->paused) {
+    GST_DEBUG_OBJECT (pulsesrc, "uncorking because we are playing");
+    gst_pulsesrc_set_corked (pulsesrc, FALSE, FALSE);
+  }
+  pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+  return TRUE;
+
+  /* ERRORS */
+connect_failed:
+  {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+        ("Failed to connect stream: %s",
+            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+    goto unlock_and_fail;
+  }
+stream_is_bad:
+  {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+        ("Failed to connect stream: %s",
+            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+    goto unlock_and_fail;
+  }
+unlock_and_fail:
+  {
+    gst_pulsesrc_destroy_stream (pulsesrc);
+
+    pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+    return FALSE;
+  }
+}
+
+static void
+gst_pulsesrc_success_cb (pa_stream * s, int success, void *userdata)
+{
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata);
+
+  pulsesrc->operation_success = ! !success;
+  pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
+}
+
+static void
+gst_pulsesrc_reset (GstAudioSrc * asrc)
+{
+  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
+  pa_operation *o = NULL;
+
+  pa_threaded_mainloop_lock (pulsesrc->mainloop);
+  GST_DEBUG_OBJECT (pulsesrc, "reset");
+
+  if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
+    goto unlock_and_fail;
+
+  if (!(o =
+          pa_stream_flush (pulsesrc->stream, gst_pulsesrc_success_cb,
+              pulsesrc))) {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+        ("pa_stream_flush() failed: %s",
+            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+    goto unlock_and_fail;
+  }
+
+  pulsesrc->paused = TRUE;
+  /* Inform anyone waiting in _write() call that it shall wakeup */
+  if (pulsesrc->in_read) {
+    pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
+  }
+
+  pulsesrc->operation_success = FALSE;
+  while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+
+    if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
+      goto unlock_and_fail;
+
+    pa_threaded_mainloop_wait (pulsesrc->mainloop);
+  }
+
+  if (!pulsesrc->operation_success) {
+    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Flush failed: %s",
+            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+    goto unlock_and_fail;
+  }
+
+unlock_and_fail:
+
+  if (o) {
+    pa_operation_cancel (o);
+    pa_operation_unref (o);
+  }
+
+  pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+}
+
+/* update the corked state of a stream, must be called with the mainloop
+ * lock */
+static gboolean
+gst_pulsesrc_set_corked (GstPulseSrc * psrc, gboolean corked, gboolean wait)
+{
+  pa_operation *o = NULL;
+  gboolean res = FALSE;
+
+  GST_DEBUG_OBJECT (psrc, "setting corked state to %d", corked);
+  if (!psrc->stream_connected)
+    return TRUE;
+
+  if (psrc->corked != corked) {
+    if (!(o = pa_stream_cork (psrc->stream, corked,
+                gst_pulsesrc_success_cb, psrc)))
+      goto cork_failed;
+
+    while (wait && pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+      pa_threaded_mainloop_wait (psrc->mainloop);
+      if (gst_pulsesrc_is_dead (psrc, TRUE))
+        goto server_dead;
+    }
+    psrc->corked = corked;
+  } else {
+    GST_DEBUG_OBJECT (psrc, "skipping, already in requested state");
+  }
+  res = TRUE;
+
+cleanup:
+  if (o)
+    pa_operation_unref (o);
+
+  return res;
+
+  /* ERRORS */
+server_dead:
+  {
+    GST_DEBUG_OBJECT (psrc, "the server is dead");
+    goto cleanup;
+  }
+cork_failed:
+  {
+    GST_ELEMENT_ERROR (psrc, RESOURCE, FAILED,
+        ("pa_stream_cork() failed: %s",
+            pa_strerror (pa_context_errno (psrc->context))), (NULL));
+    goto cleanup;
+  }
+}
+
+/* start/resume playback ASAP */
+static gboolean
+gst_pulsesrc_play (GstPulseSrc * psrc)
+{
+  pa_threaded_mainloop_lock (psrc->mainloop);
+  GST_DEBUG_OBJECT (psrc, "playing");
+  psrc->paused = FALSE;
+  gst_pulsesrc_set_corked (psrc, FALSE, FALSE);
+  pa_threaded_mainloop_unlock (psrc->mainloop);
+
+  return TRUE;
+}
+
+/* pause/stop playback ASAP */
+static gboolean
+gst_pulsesrc_pause (GstPulseSrc * psrc)
+{
+  pa_threaded_mainloop_lock (psrc->mainloop);
+  GST_DEBUG_OBJECT (psrc, "pausing");
+  /* make sure the commit method stops writing */
+  psrc->paused = TRUE;
+  if (psrc->in_read) {
+    /* we are waiting in a read, signal */
+    GST_DEBUG_OBJECT (psrc, "signal read");
+    pa_threaded_mainloop_signal (psrc->mainloop, 0);
+  }
+  pa_threaded_mainloop_unlock (psrc->mainloop);
+
+  return TRUE;
+}
+
+static GstStateChangeReturn
+gst_pulsesrc_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstPulseSrc *this = GST_PULSESRC_CAST (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      if (!(this->mainloop = pa_threaded_mainloop_new ()))
+        goto mainloop_failed;
+      if (pa_threaded_mainloop_start (this->mainloop) < 0) {
+        pa_threaded_mainloop_free (this->mainloop);
+        this->mainloop = NULL;
+        goto mainloop_start_failed;
+      }
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_element_post_message (element,
+          gst_message_new_clock_provide (GST_OBJECT_CAST (element),
+              GST_AUDIO_BASE_SRC (this)->clock, TRUE));
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      /* uncork and start recording */
+      gst_pulsesrc_play (this);
+      break;
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      /* stop recording ASAP by corking */
+      pa_threaded_mainloop_lock (this->mainloop);
+      GST_DEBUG_OBJECT (this, "corking");
+      gst_pulsesrc_set_corked (this, TRUE, FALSE);
+      pa_threaded_mainloop_unlock (this->mainloop);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      /* now make sure we get out of the _read method */
+      gst_pulsesrc_pause (this);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      if (this->mainloop)
+        pa_threaded_mainloop_stop (this->mainloop);
+
+      gst_pulsesrc_destroy_context (this);
+
+      if (this->mainloop) {
+        pa_threaded_mainloop_free (this->mainloop);
+        this->mainloop = NULL;
+      }
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      /* format_lost is reset in release() in baseaudiosink */
+      gst_element_post_message (element,
+          gst_message_new_clock_lost (GST_OBJECT_CAST (element),
+              GST_AUDIO_BASE_SRC (this)->clock));
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+
+  /* ERRORS */
+mainloop_failed:
+  {
+    GST_ELEMENT_ERROR (this, RESOURCE, FAILED,
+        ("pa_threaded_mainloop_new() failed"), (NULL));
+    return GST_STATE_CHANGE_FAILURE;
+  }
+mainloop_start_failed:
+  {
+    GST_ELEMENT_ERROR (this, RESOURCE, FAILED,
+        ("pa_threaded_mainloop_start() failed"), (NULL));
+    return GST_STATE_CHANGE_FAILURE;
+  }
+}
+
+static GstClockTime
+gst_pulsesrc_get_time (GstClock * clock, GstPulseSrc * src)
+{
+  pa_usec_t time = 0;
+
+  if (src->mainloop == NULL)
+    goto out;
+
+  pa_threaded_mainloop_lock (src->mainloop);
+  if (!src->stream)
+    goto unlock_and_out;
+
+  if (gst_pulsesrc_is_dead (src, TRUE))
+    goto unlock_and_out;
+
+  if (pa_stream_get_time (src->stream, &time) < 0) {
+    GST_DEBUG_OBJECT (src, "could not get time");
+    time = GST_CLOCK_TIME_NONE;
+  } else {
+    time *= 1000;
+  }
+
+
+unlock_and_out:
+  pa_threaded_mainloop_unlock (src->mainloop);
+
+out:
+  return time;
+}
diff --git a/ext/pulse/pulsesrc.h b/ext/pulse/pulsesrc.h
new file mode 100644
index 0000000..efa7d97
--- /dev/null
+++ b/ext/pulse/pulsesrc.h
@@ -0,0 +1,98 @@
+/*-*- Mode: C; c-basic-offset: 2 -*-*/
+
+/*
+ *  GStreamer pulseaudio plugin
+ *
+ *  Copyright (c) 2004-2008 Lennart Poettering
+ *
+ *  gst-pulse is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as
+ *  published by the Free Software Foundation; either version 2.1 of the
+ *  License, or (at your option) any later version.
+ *
+ *  gst-pulse 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with gst-pulse; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ *  USA.
+ */
+
+#ifndef __GST_PULSESRC_H__
+#define __GST_PULSESRC_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosrc.h>
+
+#include <pulse/pulseaudio.h>
+#include <pulse/thread-mainloop.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_PULSESRC \
+  (gst_pulsesrc_get_type())
+#define GST_PULSESRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PULSESRC,GstPulseSrc))
+#define GST_PULSESRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PULSESRC,GstPulseSrcClass))
+#define GST_IS_PULSESRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PULSESRC))
+#define GST_IS_PULSESRC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PULSESRC))
+#define GST_PULSESRC_CAST(obj) \
+  ((GstPulseSrc *)(obj))
+
+typedef struct _GstPulseSrc GstPulseSrc;
+typedef struct _GstPulseSrcClass GstPulseSrcClass;
+
+struct _GstPulseSrc
+{
+  GstAudioSrc src;
+
+  gchar *server, *device, *client_name;
+
+  pa_threaded_mainloop *mainloop;
+
+  pa_context *context;
+  pa_stream *stream;
+  guint32 source_output_idx;
+
+  pa_sample_spec sample_spec;
+
+  const void *read_buffer;
+  size_t read_buffer_length;
+
+  gchar *device_description;
+
+  gdouble volume;
+  gboolean volume_set:1;
+  gboolean mute:1;
+  gboolean mute_set:1;
+  guint32 current_source_idx;
+  gchar *current_source_name;
+
+  gint notify; /* atomic */
+
+  gboolean corked:1;
+  gboolean stream_connected:1;
+  gboolean operation_success:1;
+  gboolean paused:1;
+  gboolean in_read:1;
+
+  GstStructure *properties;
+  pa_proplist *proplist;
+};
+
+struct _GstPulseSrcClass
+{
+  GstAudioSrcClass parent_class;
+};
+
+GType gst_pulsesrc_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_PULSESRC_H__ */
diff --git a/ext/pulse/pulseutil.c b/ext/pulse/pulseutil.c
new file mode 100644
index 0000000..83aa4b6
--- /dev/null
+++ b/ext/pulse/pulseutil.c
@@ -0,0 +1,509 @@
+/*
+ *  GStreamer pulseaudio plugin
+ *
+ *  Copyright (c) 2004-2008 Lennart Poettering
+ *
+ *  gst-pulse is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as
+ *  published by the Free Software Foundation; either version 2.1 of the
+ *  License, or (at your option) any later version.
+ *
+ *  gst-pulse 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with gst-pulse; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ *  USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/audio/audio.h>
+
+#include "pulseutil.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>            /* getpid on UNIX */
+#endif
+#ifdef HAVE_PROCESS_H
+# include <process.h>           /* getpid on win32 */
+#endif
+
+static const struct
+{
+  GstAudioChannelPosition gst_pos;
+  pa_channel_position_t pa_pos;
+} gst_pa_pos_table[] = {
+  {
+  GST_AUDIO_CHANNEL_POSITION_MONO, PA_CHANNEL_POSITION_MONO}, {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_LEFT}, {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_FRONT_RIGHT}, {
+  GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, PA_CHANNEL_POSITION_REAR_CENTER}, {
+  GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_LEFT}, {
+  GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_REAR_RIGHT}, {
+  GST_AUDIO_CHANNEL_POSITION_LFE1, PA_CHANNEL_POSITION_LFE}, {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_FRONT_CENTER}, {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
+        PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER}, {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
+        PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, {
+  GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_LEFT}, {
+  GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, PA_CHANNEL_POSITION_SIDE_RIGHT}, {
+  GST_AUDIO_CHANNEL_POSITION_TOP_CENTER, PA_CHANNEL_POSITION_TOP_CENTER}, {
+  GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT,
+        PA_CHANNEL_POSITION_TOP_FRONT_LEFT}, {
+  GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT,
+        PA_CHANNEL_POSITION_TOP_FRONT_RIGHT}, {
+  GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER,
+        PA_CHANNEL_POSITION_TOP_FRONT_CENTER}, {
+  GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT, PA_CHANNEL_POSITION_TOP_REAR_LEFT}, {
+  GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT,
+        PA_CHANNEL_POSITION_TOP_REAR_RIGHT}, {
+  GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER,
+        PA_CHANNEL_POSITION_TOP_REAR_CENTER}, {
+  GST_AUDIO_CHANNEL_POSITION_NONE, PA_CHANNEL_POSITION_INVALID}
+};
+
+static gboolean
+gstaudioformat_to_pasampleformat (GstAudioFormat format,
+    pa_sample_format_t * sf)
+{
+  switch (format) {
+    case GST_AUDIO_FORMAT_U8:
+      *sf = PA_SAMPLE_U8;
+      break;
+    case GST_AUDIO_FORMAT_S16LE:
+      *sf = PA_SAMPLE_S16LE;
+      break;
+    case GST_AUDIO_FORMAT_S16BE:
+      *sf = PA_SAMPLE_S16BE;
+      break;
+    case GST_AUDIO_FORMAT_F32LE:
+      *sf = PA_SAMPLE_FLOAT32LE;
+      break;
+    case GST_AUDIO_FORMAT_F32BE:
+      *sf = PA_SAMPLE_FLOAT32BE;
+      break;
+    case GST_AUDIO_FORMAT_S32LE:
+      *sf = PA_SAMPLE_S32LE;
+      break;
+    case GST_AUDIO_FORMAT_S32BE:
+      *sf = PA_SAMPLE_S32BE;
+      break;
+    case GST_AUDIO_FORMAT_S24LE:
+      *sf = PA_SAMPLE_S24LE;
+      break;
+    case GST_AUDIO_FORMAT_S24BE:
+      *sf = PA_SAMPLE_S24BE;
+      break;
+    case GST_AUDIO_FORMAT_S24_32LE:
+      *sf = PA_SAMPLE_S24_32LE;
+      break;
+    case GST_AUDIO_FORMAT_S24_32BE:
+      *sf = PA_SAMPLE_S24_32BE;
+      break;
+    default:
+      return FALSE;
+  }
+  return TRUE;
+}
+
+gboolean
+gst_pulse_fill_sample_spec (GstAudioRingBufferSpec * spec, pa_sample_spec * ss)
+{
+  if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) {
+    if (!gstaudioformat_to_pasampleformat (GST_AUDIO_INFO_FORMAT (&spec->info),
+            &ss->format))
+      return FALSE;
+  } else if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW) {
+    ss->format = PA_SAMPLE_ULAW;
+  } else if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW) {
+    ss->format = PA_SAMPLE_ALAW;
+  } else
+    return FALSE;
+
+  ss->channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
+  ss->rate = GST_AUDIO_INFO_RATE (&spec->info);
+
+  if (!pa_sample_spec_valid (ss))
+    return FALSE;
+
+  return TRUE;
+}
+
+gboolean
+gst_pulse_fill_format_info (GstAudioRingBufferSpec * spec, pa_format_info ** f,
+    guint * channels)
+{
+  pa_format_info *format;
+  pa_sample_format_t sf = PA_SAMPLE_INVALID;
+  GstAudioInfo *ainfo = &spec->info;
+
+  format = pa_format_info_new ();
+
+  if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW) {
+    format->encoding = PA_ENCODING_PCM;
+    sf = PA_SAMPLE_ULAW;
+  } else if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW) {
+    format->encoding = PA_ENCODING_PCM;
+    sf = PA_SAMPLE_ALAW;
+  } else if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) {
+    format->encoding = PA_ENCODING_PCM;
+    if (!gstaudioformat_to_pasampleformat (GST_AUDIO_INFO_FORMAT (ainfo), &sf))
+      goto fail;
+  } else if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3) {
+    format->encoding = PA_ENCODING_AC3_IEC61937;
+  } else if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3) {
+    format->encoding = PA_ENCODING_EAC3_IEC61937;
+  } else if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS) {
+    format->encoding = PA_ENCODING_DTS_IEC61937;
+  } else if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG) {
+    format->encoding = PA_ENCODING_MPEG_IEC61937;
+#if PA_CHECK_VERSION(3,99,0)
+  } else if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG2_AAC) {
+    format->encoding = PA_ENCODING_MPEG2_AAC_IEC61937;
+  } else if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG4_AAC) {
+    /* HACK. treat MPEG4 AAC as MPEG2 AAC for the moment */
+    format->encoding = PA_ENCODING_MPEG2_AAC_IEC61937;
+#endif
+  } else {
+    goto fail;
+  }
+
+  if (format->encoding == PA_ENCODING_PCM) {
+    pa_format_info_set_sample_format (format, sf);
+    pa_format_info_set_channels (format, GST_AUDIO_INFO_CHANNELS (ainfo));
+  }
+
+  pa_format_info_set_rate (format, GST_AUDIO_INFO_RATE (ainfo));
+
+  if (!pa_format_info_valid (format))
+    goto fail;
+
+  *f = format;
+  *channels = GST_AUDIO_INFO_CHANNELS (ainfo);
+
+  return TRUE;
+
+fail:
+  if (format)
+    pa_format_info_free (format);
+  return FALSE;
+}
+
+const char *
+gst_pulse_sample_format_to_caps_format (pa_sample_format_t sf)
+{
+  switch (sf) {
+    case PA_SAMPLE_U8:
+      return "U8";
+
+    case PA_SAMPLE_S16LE:
+      return "S16LE";
+
+    case PA_SAMPLE_S16BE:
+      return "S16BE";
+
+    case PA_SAMPLE_FLOAT32LE:
+      return "F32LE";
+
+    case PA_SAMPLE_FLOAT32BE:
+      return "F32BE";
+
+    case PA_SAMPLE_S32LE:
+      return "S32LE";
+
+    case PA_SAMPLE_S32BE:
+      return "S32BE";
+
+    case PA_SAMPLE_S24LE:
+      return "S24LE";
+
+    case PA_SAMPLE_S24BE:
+      return "S24BE";
+
+    case PA_SAMPLE_S24_32LE:
+      return "S24_32LE";
+
+    case PA_SAMPLE_S24_32BE:
+      return "S24_32BE";
+
+    default:
+      return NULL;
+  }
+}
+
+/* PATH_MAX is not defined everywhere, e.g. on GNU Hurd */
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+gchar *
+gst_pulse_client_name (void)
+{
+  gchar buf[PATH_MAX];
+
+  const char *c;
+
+  if ((c = g_get_application_name ()))
+    return g_strdup (c);
+  else if (pa_get_binary_name (buf, sizeof (buf)))
+    return g_strdup (buf);
+  else
+    return g_strdup_printf ("GStreamer-pid-%lu", (gulong) getpid ());
+}
+
+pa_channel_map *
+gst_pulse_gst_to_channel_map (pa_channel_map * map,
+    const GstAudioRingBufferSpec * spec)
+{
+  gint i, j;
+  gint channels;
+  const GstAudioChannelPosition *pos;
+
+  pa_channel_map_init (map);
+
+  channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
+  pos = spec->info.position;
+
+  for (j = 0; j < channels; j++) {
+    for (i = 0; i < G_N_ELEMENTS (gst_pa_pos_table); i++) {
+      if (pos[j] == gst_pa_pos_table[i].gst_pos) {
+        map->map[j] = gst_pa_pos_table[i].pa_pos;
+        break;
+      }
+    }
+    if (i == G_N_ELEMENTS (gst_pa_pos_table))
+      return NULL;
+  }
+
+  if (j != spec->info.channels) {
+    return NULL;
+  }
+
+  map->channels = spec->info.channels;
+
+  if (!pa_channel_map_valid (map)) {
+    return NULL;
+  }
+
+  return map;
+}
+
+GstAudioRingBufferSpec *
+gst_pulse_channel_map_to_gst (const pa_channel_map * map,
+    GstAudioRingBufferSpec * spec)
+{
+  gint i, j;
+  gboolean invalid = FALSE;
+  gint channels;
+  GstAudioChannelPosition *pos;
+
+  channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
+
+  g_return_val_if_fail (map->channels == channels, NULL);
+
+  pos = spec->info.position;
+
+  for (j = 0; j < channels; j++) {
+    for (i = 0; j < channels && i < G_N_ELEMENTS (gst_pa_pos_table); i++) {
+      if (map->map[j] == gst_pa_pos_table[i].pa_pos) {
+        pos[j] = gst_pa_pos_table[i].gst_pos;
+        break;
+      }
+    }
+    if (i == G_N_ELEMENTS (gst_pa_pos_table))
+      return NULL;
+  }
+
+  if (!invalid
+      && !gst_audio_check_valid_channel_positions (pos, channels, FALSE))
+    invalid = TRUE;
+
+  if (invalid) {
+    for (i = 0; i < channels; i++)
+      pos[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
+  } else {
+    if (pos[0] != GST_AUDIO_CHANNEL_POSITION_NONE)
+      spec->info.flags &= ~GST_AUDIO_FLAG_UNPOSITIONED;
+  }
+
+  return spec;
+}
+
+void
+gst_pulse_cvolume_from_linear (pa_cvolume * v, unsigned channels,
+    gdouble volume)
+{
+  pa_cvolume_set (v, channels, pa_sw_volume_from_linear (volume));
+}
+
+static gboolean
+make_proplist_item (GQuark field_id, const GValue * value, gpointer user_data)
+{
+  pa_proplist *p = (pa_proplist *) user_data;
+  gchar *prop_id = (gchar *) g_quark_to_string (field_id);
+
+  /* http://0pointer.de/lennart/projects/pulseaudio/doxygen/proplist_8h.html */
+
+  /* match prop id */
+
+  /* check type */
+  switch (G_VALUE_TYPE (value)) {
+    case G_TYPE_STRING:
+      pa_proplist_sets (p, prop_id, g_value_get_string (value));
+      break;
+    default:
+      GST_WARNING ("unmapped property type %s", G_VALUE_TYPE_NAME (value));
+      break;
+  }
+
+  return TRUE;
+}
+
+pa_proplist *
+gst_pulse_make_proplist (const GstStructure * properties)
+{
+  pa_proplist *proplist = pa_proplist_new ();
+
+  /* iterate the structure and fill the proplist */
+  gst_structure_foreach (properties, make_proplist_item, proplist);
+  return proplist;
+}
+
+GstStructure *
+gst_pulse_make_structure (pa_proplist * properties)
+{
+  GstStructure *str;
+  void *state = NULL;
+
+  str = gst_structure_new_empty ("pulse-proplist");
+
+  while (TRUE) {
+    const char *key, *val;
+
+    key = pa_proplist_iterate (properties, &state);
+    if (key == NULL)
+      break;
+
+    val = pa_proplist_gets (properties, key);
+
+    gst_structure_set (str, key, G_TYPE_STRING, val, NULL);
+  }
+  return str;
+}
+
+static gboolean
+gst_pulse_format_info_int_prop_to_value (pa_format_info * format,
+    const char *key, GValue * value)
+{
+  GValue v = { 0, };
+  int i;
+  int *a, n;
+  int min, max;
+
+  if (pa_format_info_get_prop_int (format, key, &i) == 0) {
+    g_value_init (value, G_TYPE_INT);
+    g_value_set_int (value, i);
+
+  } else if (pa_format_info_get_prop_int_array (format, key, &a, &n) == 0) {
+    g_value_init (value, GST_TYPE_LIST);
+    g_value_init (&v, G_TYPE_INT);
+
+    for (i = 0; i < n; i++) {
+      g_value_set_int (&v, a[i]);
+      gst_value_list_append_value (value, &v);
+    }
+
+    pa_xfree (a);
+
+  } else if (pa_format_info_get_prop_int_range (format, key, &min, &max) == 0) {
+    g_value_init (value, GST_TYPE_INT_RANGE);
+    gst_value_set_int_range (value, min, max);
+
+  } else {
+    /* Property not available or is not an int type */
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+GstCaps *
+gst_pulse_format_info_to_caps (pa_format_info * format)
+{
+  GstCaps *ret = NULL;
+  GValue v = { 0, };
+  pa_sample_spec ss;
+
+  switch (format->encoding) {
+    case PA_ENCODING_PCM:{
+      char *tmp = NULL;
+
+      pa_format_info_to_sample_spec (format, &ss, NULL);
+
+      if (pa_format_info_get_prop_string (format,
+              PA_PROP_FORMAT_SAMPLE_FORMAT, &tmp)) {
+        /* No specific sample format means any sample format */
+        ret = gst_caps_from_string (_PULSE_CAPS_PCM);
+        goto out;
+
+      } else if (ss.format == PA_SAMPLE_ALAW) {
+        ret = gst_caps_from_string (_PULSE_CAPS_ALAW);
+
+      } else if (ss.format == PA_SAMPLE_ULAW) {
+        ret = gst_caps_from_string (_PULSE_CAPS_MULAW);
+
+      } else {
+        /* Linear PCM format */
+        const char *sformat =
+            gst_pulse_sample_format_to_caps_format (ss.format);
+
+        ret = gst_caps_from_string (_PULSE_CAPS_LINEAR);
+
+        if (sformat)
+          gst_caps_set_simple (ret, "format", G_TYPE_STRING, NULL);
+      }
+
+      pa_xfree (tmp);
+      break;
+    }
+
+    case PA_ENCODING_AC3_IEC61937:
+      ret = gst_caps_from_string (_PULSE_CAPS_AC3);
+      break;
+
+    case PA_ENCODING_EAC3_IEC61937:
+      ret = gst_caps_from_string (_PULSE_CAPS_EAC3);
+      break;
+
+    case PA_ENCODING_DTS_IEC61937:
+      ret = gst_caps_from_string (_PULSE_CAPS_DTS);
+      break;
+
+    case PA_ENCODING_MPEG_IEC61937:
+      ret = gst_caps_from_string (_PULSE_CAPS_MP3);
+      break;
+
+    default:
+      GST_WARNING ("Found a PA format that we don't support yet");
+      goto out;
+  }
+
+  if (gst_pulse_format_info_int_prop_to_value (format, PA_PROP_FORMAT_RATE, &v))
+    gst_caps_set_value (ret, "rate", &v);
+
+  g_value_unset (&v);
+
+  if (gst_pulse_format_info_int_prop_to_value (format, PA_PROP_FORMAT_CHANNELS,
+          &v))
+    gst_caps_set_value (ret, "channels", &v);
+
+out:
+  return ret;
+}
diff --git a/ext/pulse/pulseutil.h b/ext/pulse/pulseutil.h
new file mode 100644
index 0000000..ef11424
--- /dev/null
+++ b/ext/pulse/pulseutil.h
@@ -0,0 +1,94 @@
+/*
+ *  GStreamer pulseaudio plugin
+ *
+ *  Copyright (c) 2004-2008 Lennart Poettering
+ *
+ *  gst-pulse is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as
+ *  published by the Free Software Foundation; either version 2.1 of the
+ *  License, or (at your option) any later version.
+ *
+ *  gst-pulse 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with gst-pulse; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ *  USA.
+ */
+
+#ifndef __GST_PULSEUTIL_H__
+#define __GST_PULSEUTIL_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <pulse/pulseaudio.h>
+#include <gst/audio/gstaudioringbuffer.h>
+#include <gst/audio/gstaudiosink.h>
+
+
+#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
+# define _PULSE_FORMATS   "{ S16LE, S16BE, F32LE, F32BE, S32LE, S32BE, " \
+                     "S24LE, S24BE, S24_32LE, S24_32BE, U8 }"
+#else
+# define _PULSE_FORMATS   "{ S16BE, S16LE, F32BE, F32LE, S32BE, S32LE, " \
+                     "S24BE, S24LE, S24_32BE, S24_32LE, U8 }"
+#endif
+
+#define _PULSE_CAPS_LINEAR \
+    "audio/x-raw, " \
+      "format = (string) " _PULSE_FORMATS ", " \
+      "layout = (string) interleaved, " \
+      "rate = (int) [ 1, MAX ], " \
+      "channels = (int) [ 1, 32 ]; "
+#define _PULSE_CAPS_ALAW \
+    "audio/x-alaw, " \
+      "rate = (int) [ 1, MAX], " \
+      "channels = (int) [ 1, 32 ]; "
+#define _PULSE_CAPS_MULAW \
+    "audio/x-mulaw, " \
+      "rate = (int) [ 1, MAX], " \
+      "channels = (int) [ 1, 32 ]; "
+
+#define _PULSE_CAPS_AC3 "audio/x-ac3, framed = (boolean) true; "
+#define _PULSE_CAPS_EAC3 "audio/x-eac3, framed = (boolean) true; "
+#define _PULSE_CAPS_DTS "audio/x-dts, framed = (boolean) true, " \
+    "block-size = (int) { 512, 1024, 2048 }; "
+#define _PULSE_CAPS_MP3 "audio/mpeg, mpegversion = (int) 1, " \
+    "mpegaudioversion = (int) [ 1, 3 ], parsed = (boolean) true;"
+#define _PULSE_CAPS_AAC "audio/mpeg, mpegversion = (int) { 2, 4 }, " \
+    "framed = (boolean) true, stream-format = (string) adts;"
+
+#define _PULSE_CAPS_PCM \
+  _PULSE_CAPS_LINEAR \
+  _PULSE_CAPS_ALAW \
+  _PULSE_CAPS_MULAW
+
+
+gboolean gst_pulse_fill_sample_spec (GstAudioRingBufferSpec * spec,
+    pa_sample_spec * ss);
+gboolean gst_pulse_fill_format_info (GstAudioRingBufferSpec * spec,
+    pa_format_info ** f, guint * channels);
+const char * gst_pulse_sample_format_to_caps_format (pa_sample_format_t sf);
+
+gchar *gst_pulse_client_name (void);
+
+pa_channel_map *gst_pulse_gst_to_channel_map (pa_channel_map * map,
+    const GstAudioRingBufferSpec * spec);
+
+GstAudioRingBufferSpec *gst_pulse_channel_map_to_gst (const pa_channel_map * map,
+    GstAudioRingBufferSpec * spec);
+
+void gst_pulse_cvolume_from_linear (pa_cvolume *v, unsigned channels, gdouble volume);
+
+pa_proplist *gst_pulse_make_proplist (const GstStructure *properties);
+GstStructure *gst_pulse_make_structure (pa_proplist *properties);
+
+GstCaps * gst_pulse_format_info_to_caps (pa_format_info * format);
+
+#endif
diff --git a/ext/raw1394/.gitignore b/ext/raw1394/.gitignore
new file mode 100644
index 0000000..f8b5186
--- /dev/null
+++ b/ext/raw1394/.gitignore
@@ -0,0 +1 @@
+libgst1394_la-gstdv1394src.loT
diff --git a/ext/raw1394/Makefile.am b/ext/raw1394/Makefile.am
new file mode 100644
index 0000000..25b6a48
--- /dev/null
+++ b/ext/raw1394/Makefile.am
@@ -0,0 +1,28 @@
+plugin_LTLIBRARIES = libgst1394.la
+
+if USE_LIBIEC61883
+hdvsource = gsthdv1394src.c
+hdvheaders = gsthdv1394src.h
+else
+hdvsource = 
+hdvheaders = 
+endif
+
+libgst1394_la_SOURCES = \
+	gst1394.c gst1394probe.c gstdv1394src.c $(hdvsource) \
+	gst1394clock.c
+libgst1394_la_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS) \
+	$(DV1394_CFLAGS)
+libgst1394_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) \
+	$(GST_BASE_LIBS) \
+	$(GST_LIBS) \
+	$(DV1394_LIBS)
+libgst1394_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstdv1394src.h gst1394probe.h $(hdvheaders) \
+	gst1394clock.h
+
diff --git a/ext/raw1394/gst1394.c b/ext/raw1394/gst1394.c
new file mode 100644
index 0000000..77a9e93
--- /dev/null
+++ b/ext/raw1394/gst1394.c
@@ -0,0 +1,51 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <gst/gst.h>
+
+
+#include "gstdv1394src.h"
+#ifdef HAVE_LIBIEC61883
+#include "gsthdv1394src.h"
+#endif
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "dv1394src", GST_RANK_NONE,
+          GST_TYPE_DV1394SRC))
+    return FALSE;
+#ifdef HAVE_LIBIEC61883
+  if (!gst_element_register (plugin, "hdv1394src", GST_RANK_NONE,
+          GST_TYPE_HDV1394SRC))
+    return FALSE;
+#endif
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    1394,
+    "Source for video data via IEEE1394 interface",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/ext/raw1394/gst1394clock.c b/ext/raw1394/gst1394clock.c
new file mode 100644
index 0000000..9a3411d
--- /dev/null
+++ b/ext/raw1394/gst1394clock.c
@@ -0,0 +1,158 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wtay@chello.be>
+ * Copyright (C) 2009      David Schleef <ds@schleef.org>
+ *
+ * gst1394clock.c: Clock for use by IEEE 1394 plugins
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gst1394clock.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_1394_clock_debug);
+#define GST_CAT_DEFAULT gst_1394_clock_debug
+
+static void gst_1394_clock_class_init (Gst1394ClockClass * klass);
+static void gst_1394_clock_init (Gst1394Clock * clock);
+
+static GstClockTime gst_1394_clock_get_internal_time (GstClock * clock);
+
+static GstSystemClockClass *parent_class = NULL;
+
+/* static guint gst_1394_clock_signals[LAST_SIGNAL] = { 0 }; */
+
+GType
+gst_1394_clock_get_type (void)
+{
+  static GType clock_type = 0;
+
+  if (!clock_type) {
+    static const GTypeInfo clock_info = {
+      sizeof (Gst1394ClockClass),
+      NULL,
+      NULL,
+      (GClassInitFunc) gst_1394_clock_class_init,
+      NULL,
+      NULL,
+      sizeof (Gst1394Clock),
+      4,
+      (GInstanceInitFunc) gst_1394_clock_init,
+      NULL
+    };
+
+    clock_type = g_type_register_static (GST_TYPE_SYSTEM_CLOCK, "Gst1394Clock",
+        &clock_info, 0);
+  }
+  return clock_type;
+}
+
+
+static void
+gst_1394_clock_class_init (Gst1394ClockClass * klass)
+{
+  GstClockClass *gstclock_class;
+
+  gstclock_class = (GstClockClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gstclock_class->get_internal_time = gst_1394_clock_get_internal_time;
+
+  GST_DEBUG_CATEGORY_INIT (gst_1394_clock_debug, "1394clock", 0, "1394clock");
+}
+
+static void
+gst_1394_clock_init (Gst1394Clock * clock)
+{
+  GST_OBJECT_FLAG_SET (clock, GST_CLOCK_FLAG_CAN_SET_MASTER);
+}
+
+/**
+ * gst_1394_clock_new:
+ * @name: the name of the clock
+ *
+ * Create a new #Gst1394Clock instance.
+ *
+ * Returns: a new #Gst1394Clock
+ */
+Gst1394Clock *
+gst_1394_clock_new (const gchar * name)
+{
+  Gst1394Clock *_1394clock =
+      GST_1394_CLOCK (g_object_new (GST_TYPE_1394_CLOCK, "name", name,
+          "clock-type", GST_CLOCK_TYPE_OTHER, NULL));
+
+  /* Clear floating flag */
+  gst_object_ref_sink (_1394clock);
+
+  return _1394clock;
+}
+
+static GstClockTime
+gst_1394_clock_get_internal_time (GstClock * clock)
+{
+  Gst1394Clock *_1394clock;
+  GstClockTime result;
+  guint32 cycle_timer;
+  guint64 local_time;
+
+  _1394clock = GST_1394_CLOCK_CAST (clock);
+
+  if (_1394clock->handle != NULL) {
+    GST_OBJECT_LOCK (clock);
+    raw1394_read_cycle_timer (_1394clock->handle, &cycle_timer, &local_time);
+
+    if (cycle_timer < _1394clock->cycle_timer_lo) {
+      GST_LOG_OBJECT (clock, "overflow %u to %u",
+          _1394clock->cycle_timer_lo, cycle_timer);
+
+      _1394clock->cycle_timer_hi++;
+    }
+    _1394clock->cycle_timer_lo = cycle_timer;
+
+    /* get the seconds from the cycleSeconds counter */
+    result = (((((guint64) _1394clock->cycle_timer_hi) << 32) |
+            cycle_timer) >> 25) * GST_SECOND;
+    /* add the microseconds from the cycleCount counter */
+    result += (((cycle_timer >> 12) & 0x1fff) * 125) * GST_USECOND;
+
+    GST_LOG_OBJECT (clock, "result %" GST_TIME_FORMAT, GST_TIME_ARGS (result));
+    GST_OBJECT_UNLOCK (clock);
+  } else {
+    result = GST_CLOCK_TIME_NONE;
+  }
+
+  return result;
+}
+
+void
+gst_1394_clock_set_handle (Gst1394Clock * clock, raw1394handle_t handle)
+{
+  clock->handle = handle;
+  clock->cycle_timer_lo = 0;
+  clock->cycle_timer_hi = 0;
+}
+
+void
+gst_1394_clock_unset_handle (Gst1394Clock * clock)
+{
+  clock->handle = NULL;
+}
diff --git a/ext/raw1394/gst1394clock.h b/ext/raw1394/gst1394clock.h
new file mode 100644
index 0000000..411251e
--- /dev/null
+++ b/ext/raw1394/gst1394clock.h
@@ -0,0 +1,77 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2005 Wim Taymans <wim@fluendo.com>
+ * Copyright (C) 2009      David Schleef <ds@schleef.org>
+ *
+ * gst1394clock.h: Clock for use by the IEEE 1394
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_1394_CLOCK_H__
+#define __GST_1394_CLOCK_H__
+
+#include <gst/gst.h>
+#include <gst/gstsystemclock.h>
+
+#include <libraw1394/raw1394.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_1394_CLOCK \
+  (gst_1394_clock_get_type())
+#define GST_1394_CLOCK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_1394_CLOCK,Gst1394Clock))
+#define GST_1394_CLOCK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_1394_CLOCK,Gst1394ClockClass))
+#define GST_IS_1394_CLOCK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_1394_CLOCK))
+#define GST_IS_1394_CLOCK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_1394_CLOCK))
+#define GST_1394_CLOCK_CAST(obj) \
+  ((Gst1394Clock*)(obj))
+
+typedef struct _Gst1394Clock Gst1394Clock;
+typedef struct _Gst1394ClockClass Gst1394ClockClass;
+
+/**
+ * Gst1394Clock:
+ * @clock: parent #GstSystemClock
+ *
+ * Opaque #Gst1394Clock.
+ */
+struct _Gst1394Clock {
+  GstSystemClock clock;
+
+  raw1394handle_t handle;
+
+  guint32 cycle_timer_lo;
+  guint32 cycle_timer_hi;
+};
+
+struct _Gst1394ClockClass {
+  GstSystemClockClass parent_class;
+};
+
+GType           gst_1394_clock_get_type        (void);
+Gst1394Clock*   gst_1394_clock_new             (const gchar *name);
+void            gst_1394_clock_set_handle      (Gst1394Clock *clock,
+    raw1394handle_t handle);
+void            gst_1394_clock_unset_handle      (Gst1394Clock *clock);
+
+G_END_DECLS
+
+#endif /* __GST_1394_CLOCK_H__ */
diff --git a/ext/raw1394/gst1394probe.c b/ext/raw1394/gst1394probe.c
new file mode 100644
index 0000000..2d11a01
--- /dev/null
+++ b/ext/raw1394/gst1394probe.c
@@ -0,0 +1,143 @@
+/* GStreamer
+ * Copyright (C) 2007 Julien Puydt <jpuydt@free.fr>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <libavc1394/avc1394.h>
+#include <libavc1394/avc1394_vcr.h>
+#include <libavc1394/rom1394.h>
+#include <libraw1394/raw1394.h>
+
+#include <gst/gst.h>
+
+#include "gst1394probe.h"
+
+#if 0
+
+static GValueArray *
+gst_1394_get_guid_array (void)
+{
+  GValueArray *result = NULL;
+  raw1394handle_t handle = NULL;
+  int num_ports = 0;
+  int port = 0;
+  int num_nodes = 0;
+  int node = 0;
+  rom1394_directory directory;
+  GValue value = { 0, };
+
+  handle = raw1394_new_handle ();
+
+  if (handle == NULL)
+    return NULL;
+
+  num_ports = raw1394_get_port_info (handle, NULL, 0);
+  for (port = 0; port < num_ports; port++) {
+    if (raw1394_set_port (handle, port) >= 0) {
+      num_nodes = raw1394_get_nodecount (handle);
+      for (node = 0; node < num_nodes; node++) {
+        rom1394_get_directory (handle, node, &directory);
+        if (rom1394_get_node_type (&directory) == ROM1394_NODE_TYPE_AVC &&
+            avc1394_check_subunit_type (handle, node,
+                AVC1394_SUBUNIT_TYPE_VCR)) {
+          if (result == NULL)
+            result = g_value_array_new (3);     /* looks like a sensible default */
+          g_value_init (&value, G_TYPE_UINT64);
+          g_value_set_uint64 (&value, rom1394_get_guid (handle, node));
+          g_value_array_append (result, &value);
+          g_value_unset (&value);
+        }
+      }
+    }
+  }
+
+  return result;
+}
+
+static const GList *
+gst_1394_property_probe_get_properties (GstPropertyProbe * probe)
+{
+  static GList *result = NULL;
+  GObjectClass *klass = NULL;
+  GParamSpec *spec = NULL;
+
+  if (result == NULL) {
+    klass = G_OBJECT_GET_CLASS (probe);
+    spec = g_object_class_find_property (klass, "guid");
+    result = g_list_append (result, spec);
+  }
+
+  return result;
+}
+
+static void
+gst_1394_property_probe_probe_property (GstPropertyProbe * probe, guint prop_id,
+    const GParamSpec * pspec)
+{
+  if (!g_str_equal (pspec->name, "guid"))
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
+}
+
+static gboolean
+gst_1394_property_probe_needs_probe (GstPropertyProbe * probe, guint prop_id,
+    const GParamSpec * pspec)
+{
+  return TRUE;
+}
+
+static GValueArray *
+gst_1394_property_probe_get_values (GstPropertyProbe * probe, guint prop_id,
+    const GParamSpec * pspec)
+{
+  GValueArray *result = NULL;
+
+  if (!g_str_equal (pspec->name, "guid")) {
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
+    return NULL;
+  }
+
+  result = gst_1394_get_guid_array ();
+
+  if (result == NULL)
+    GST_LOG_OBJECT (probe, "No guid found");
+
+  return result;
+}
+
+static void
+gst_1394_property_probe_interface_init (GstPropertyProbeInterface * iface)
+{
+  iface->get_properties = gst_1394_property_probe_get_properties;
+  iface->probe_property = gst_1394_property_probe_probe_property;
+  iface->needs_probe = gst_1394_property_probe_needs_probe;
+  iface->get_values = gst_1394_property_probe_get_values;
+}
+
+void
+gst_1394_type_add_property_probe_interface (GType type)
+{
+  static const GInterfaceInfo probe_iface_info = {
+    (GInterfaceInitFunc) gst_1394_property_probe_interface_init,
+    NULL,
+    NULL,
+  };
+
+  g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
+      &probe_iface_info);
+}
+
+#endif
diff --git a/ext/raw1394/gst1394probe.h b/ext/raw1394/gst1394probe.h
new file mode 100644
index 0000000..54a3232
--- /dev/null
+++ b/ext/raw1394/gst1394probe.h
@@ -0,0 +1,34 @@
+/* GStreamer
+ * Copyright (C) 2007 Julien Puydt <jpuydt@free.fr>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GST_1394_PROBE_H
+#define GST_1394_PROBE_H
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#if 0
+void gst_1394_type_add_property_probe_interface (GType type);
+#endif
+
+G_END_DECLS
+
+#endif /* __GST_1394_PROBE_H */
+
diff --git a/ext/raw1394/gstdv1394src.c b/ext/raw1394/gstdv1394src.c
new file mode 100644
index 0000000..bee1af1
--- /dev/null
+++ b/ext/raw1394/gstdv1394src.c
@@ -0,0 +1,1112 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *               <2000> Daniel Fischer <dan@f3c.com>
+ *               <2004> Wim Taymans <wim@fluendo.com>
+ *               <2006> Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-dv1394src
+ *
+ * Read DV (digital video) data from firewire port.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 dv1394src ! queue ! dvdemux name=d ! queue ! dvdec ! xvimagesink d. ! queue ! alsasink
+ * ]| This pipeline captures from the firewire port and displays it (might need
+ * format converters for audio/video).
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <unistd.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <libavc1394/avc1394.h>
+#include <libavc1394/avc1394_vcr.h>
+#include <libavc1394/rom1394.h>
+#include <libraw1394/raw1394.h>
+#ifdef HAVE_LIBIEC61883
+#include <libiec61883/iec61883.h>
+#endif
+
+#include <gst/gst.h>
+
+#include "gstdv1394src.h"
+#include "gst1394probe.h"
+#include "gst1394clock.h"
+
+
+#define CONTROL_STOP            'S'     /* stop the select call */
+#define CONTROL_SOCKETS(src)   src->control_sock
+#define WRITE_SOCKET(src)      src->control_sock[1]
+#define READ_SOCKET(src)       src->control_sock[0]
+
+#define SEND_COMMAND(src, command)          \
+G_STMT_START {                              \
+  int G_GNUC_UNUSED _res; unsigned char c; c = command;   \
+  _res = write (WRITE_SOCKET(src), &c, 1);  \
+} G_STMT_END
+
+#define READ_COMMAND(src, command, res)        \
+G_STMT_START {                                 \
+  res = read(READ_SOCKET(src), &command, 1);   \
+} G_STMT_END
+
+
+GST_DEBUG_CATEGORY_STATIC (dv1394src_debug);
+#define GST_CAT_DEFAULT (dv1394src_debug)
+
+#define PAL_FRAMESIZE 144000
+#define PAL_FRAMERATE 25
+
+#define NTSC_FRAMESIZE 120000
+#define NTSC_FRAMERATE 30
+
+enum
+{
+  SIGNAL_FRAME_DROPPED,
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+#define DEFAULT_PORT    -1
+#define DEFAULT_CHANNEL   63
+#define DEFAULT_CONSECUTIVE 1
+#define DEFAULT_SKIP    0
+#define DEFAULT_DROP_INCOMPLETE TRUE
+#define DEFAULT_USE_AVC   TRUE
+#define DEFAULT_GUID    0
+
+enum
+{
+  PROP_0,
+  PROP_PORT,
+  PROP_CHANNEL,
+  PROP_CONSECUTIVE,
+  PROP_SKIP,
+  PROP_DROP_INCOMPLETE,
+  PROP_USE_AVC,
+  PROP_GUID,
+  PROP_DEVICE_NAME
+};
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-dv, "
+        "format = (string) { NTSC, PAL }, " "systemstream = (boolean) true")
+    );
+
+static void gst_dv1394src_uri_handler_init (gpointer g_iface,
+    gpointer iface_data);
+
+static void gst_dv1394src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_dv1394src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_dv1394src_dispose (GObject * object);
+
+static GstClock *gst_dv1394src_provide_clock (GstElement * element);
+static GstStateChangeReturn gst_dv1394_src_change_state (GstElement * element,
+    GstStateChange transition);
+
+static gboolean gst_dv1394src_start (GstBaseSrc * bsrc);
+static gboolean gst_dv1394src_stop (GstBaseSrc * bsrc);
+static gboolean gst_dv1394src_unlock (GstBaseSrc * bsrc);
+
+static GstFlowReturn gst_dv1394src_create (GstPushSrc * psrc, GstBuffer ** buf);
+
+static gboolean gst_dv1394src_query (GstBaseSrc * src, GstQuery * query);
+static void gst_dv1394src_update_device_name (GstDV1394Src * src);
+
+#define gst_dv1394src_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstDV1394Src, gst_dv1394src, GST_TYPE_PUSH_SRC,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
+        gst_dv1394src_uri_handler_init));
+
+static guint gst_dv1394src_signals[LAST_SIGNAL] = { 0 };
+
+static void
+gst_dv1394src_class_init (GstDV1394SrcClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSrcClass *gstbasesrc_class;
+  GstPushSrcClass *gstpushsrc_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesrc_class = (GstBaseSrcClass *) klass;
+  gstpushsrc_class = (GstPushSrcClass *) klass;
+
+  gobject_class->set_property = gst_dv1394src_set_property;
+  gobject_class->get_property = gst_dv1394src_get_property;
+  gobject_class->dispose = gst_dv1394src_dispose;
+
+  gstelement_class->provide_clock = gst_dv1394src_provide_clock;
+  gstelement_class->change_state = gst_dv1394_src_change_state;
+
+  gst_dv1394src_signals[SIGNAL_FRAME_DROPPED] =
+      g_signal_new ("frame-dropped", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDV1394SrcClass, frame_dropped),
+      NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PORT,
+      g_param_spec_int ("port", "Port", "Port number (-1 automatic)",
+          -1, 16, DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CHANNEL,
+      g_param_spec_int ("channel", "Channel", "Channel number for listening",
+          0, 64, DEFAULT_CHANNEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CONSECUTIVE,
+      g_param_spec_int ("consecutive", "consecutive frames",
+          "send n consecutive frames after skipping", 1, G_MAXINT,
+          DEFAULT_CONSECUTIVE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SKIP,
+      g_param_spec_int ("skip", "skip frames", "skip n frames",
+          0, G_MAXINT, DEFAULT_SKIP,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DROP_INCOMPLETE,
+      g_param_spec_boolean ("drop-incomplete", "drop incomplete",
+          "drop incomplete frames", DEFAULT_DROP_INCOMPLETE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_USE_AVC,
+      g_param_spec_boolean ("use-avc", "Use AV/C", "Use AV/C VTR control",
+          DEFAULT_USE_AVC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_GUID,
+      g_param_spec_uint64 ("guid", "GUID",
+          "select one of multiple DV devices by its GUID. use a hexadecimal "
+          "like 0xhhhhhhhhhhhhhhhh. (0 = no guid)", 0, G_MAXUINT64,
+          DEFAULT_GUID, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstDV1394Src:device-name:
+   *
+   * Descriptive name of the currently opened device
+   */
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEVICE_NAME,
+      g_param_spec_string ("device-name", "device name",
+          "user-friendly name of the device", "Default",
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  gstbasesrc_class->negotiate = NULL;
+  gstbasesrc_class->start = gst_dv1394src_start;
+  gstbasesrc_class->stop = gst_dv1394src_stop;
+  gstbasesrc_class->unlock = gst_dv1394src_unlock;
+  gstbasesrc_class->query = gst_dv1394src_query;
+
+  gstpushsrc_class->create = gst_dv1394src_create;
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Firewire (1394) DV video source", "Source/Video",
+      "Source for DV video data from firewire port",
+      "Erik Walthinsen <omega@temple-baptist.com>, "
+      "Daniel Fischer <dan@f3c.com>, " "Wim Taymans <wim@fluendo.com>, "
+      "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
+
+  GST_DEBUG_CATEGORY_INIT (dv1394src_debug, "dv1394src", 0,
+      "DV firewire source");
+}
+
+static void
+gst_dv1394src_init (GstDV1394Src * dv1394src)
+{
+  GstPad *srcpad = GST_BASE_SRC_PAD (dv1394src);
+
+  gst_base_src_set_live (GST_BASE_SRC (dv1394src), TRUE);
+  gst_base_src_set_format (GST_BASE_SRC (dv1394src), GST_FORMAT_TIME);
+  gst_base_src_set_do_timestamp (GST_BASE_SRC (dv1394src), TRUE);
+  gst_pad_use_fixed_caps (srcpad);
+
+  dv1394src->port = DEFAULT_PORT;
+  dv1394src->channel = DEFAULT_CHANNEL;
+
+  dv1394src->consecutive = DEFAULT_CONSECUTIVE;
+  dv1394src->skip = DEFAULT_SKIP;
+  dv1394src->drop_incomplete = DEFAULT_DROP_INCOMPLETE;
+  dv1394src->use_avc = DEFAULT_USE_AVC;
+  dv1394src->guid = DEFAULT_GUID;
+  dv1394src->uri = g_strdup_printf ("dv://%d", dv1394src->port);
+  dv1394src->device_name = g_strdup_printf ("Default");
+
+  READ_SOCKET (dv1394src) = -1;
+  WRITE_SOCKET (dv1394src) = -1;
+
+  /* initialized when first header received */
+  dv1394src->frame_size = 0;
+
+  dv1394src->buf = NULL;
+  dv1394src->frame = NULL;
+  dv1394src->frame_sequence = 0;
+
+  dv1394src->provided_clock = gst_1394_clock_new ("dv1394clock");
+}
+
+static void
+gst_dv1394src_dispose (GObject * object)
+{
+  GstDV1394Src *src = GST_DV1394SRC (object);
+
+  if (src->provided_clock) {
+    g_object_unref (src->provided_clock);
+  }
+
+  g_free (src->uri);
+  src->uri = NULL;
+
+  g_free (src->device_name);
+  src->device_name = NULL;
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_dv1394src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstDV1394Src *filter = GST_DV1394SRC (object);
+
+  switch (prop_id) {
+    case PROP_PORT:
+      filter->port = g_value_get_int (value);
+      g_free (filter->uri);
+      filter->uri = g_strdup_printf ("dv://%d", filter->port);
+      break;
+    case PROP_CHANNEL:
+      filter->channel = g_value_get_int (value);
+      break;
+    case PROP_SKIP:
+      filter->skip = g_value_get_int (value);
+      break;
+    case PROP_CONSECUTIVE:
+      filter->consecutive = g_value_get_int (value);
+      break;
+    case PROP_DROP_INCOMPLETE:
+      filter->drop_incomplete = g_value_get_boolean (value);
+      break;
+    case PROP_USE_AVC:
+      filter->use_avc = g_value_get_boolean (value);
+      break;
+    case PROP_GUID:
+      filter->guid = g_value_get_uint64 (value);
+      gst_dv1394src_update_device_name (filter);
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_dv1394src_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstDV1394Src *filter = GST_DV1394SRC (object);
+
+  switch (prop_id) {
+    case PROP_PORT:
+      g_value_set_int (value, filter->port);
+      break;
+    case PROP_CHANNEL:
+      g_value_set_int (value, filter->channel);
+      break;
+    case PROP_SKIP:
+      g_value_set_int (value, filter->skip);
+      break;
+    case PROP_CONSECUTIVE:
+      g_value_set_int (value, filter->consecutive);
+      break;
+    case PROP_DROP_INCOMPLETE:
+      g_value_set_boolean (value, filter->drop_incomplete);
+      break;
+    case PROP_USE_AVC:
+      g_value_set_boolean (value, filter->use_avc);
+      break;
+    case PROP_GUID:
+      g_value_set_uint64 (value, filter->guid);
+      break;
+    case PROP_DEVICE_NAME:
+      g_value_set_string (value, filter->device_name);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstClock *
+gst_dv1394src_provide_clock (GstElement * element)
+{
+  GstDV1394Src *dv1394src = GST_DV1394SRC (element);
+
+  return GST_CLOCK_CAST (gst_object_ref (dv1394src->provided_clock));
+}
+
+static GstStateChangeReturn
+gst_dv1394_src_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+  GstDV1394Src *src = GST_DV1394SRC (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      gst_element_post_message (element,
+          gst_message_new_clock_lost (GST_OBJECT_CAST (element),
+              GST_CLOCK_CAST (src->provided_clock)));
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      gst_element_post_message (element,
+          gst_message_new_clock_provide (GST_OBJECT_CAST (element),
+              GST_CLOCK_CAST (src->provided_clock), TRUE));
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+#ifdef HAVE_LIBIEC61883
+static GstDV1394Src *
+gst_dv1394src_from_raw1394handle (raw1394handle_t handle)
+{
+  iec61883_dv_t dv = (iec61883_dv_t) raw1394_get_userdata (handle);
+  iec61883_dv_fb_t dv_fb =
+      (iec61883_dv_fb_t) iec61883_dv_get_callback_data (dv);
+  return GST_DV1394SRC (iec61883_dv_fb_get_callback_data (dv_fb));
+}
+#else /* HAVE_LIBIEC61883 */
+static GstDV1394Src *
+gst_dv1394src_from_raw1394handle (raw1394handle_t handle)
+{
+  return GST_DV1394SRC (raw1394_get_userdata (handle));
+}
+#endif /* HAVE_LIBIEC61883 */
+
+#ifdef HAVE_LIBIEC61883
+static int
+gst_dv1394src_iec61883_receive (unsigned char *data, int len,
+    int complete, void *cbdata)
+{
+  GstDV1394Src *dv1394src = GST_DV1394SRC (cbdata);
+
+  if (G_UNLIKELY (!gst_pad_has_current_caps (GST_BASE_SRC_PAD (dv1394src)))) {
+    GstCaps *caps;
+    unsigned char *p = data;
+
+    // figure format (NTSC/PAL)
+    if (p[3] & 0x80) {
+      // PAL
+      dv1394src->frame_size = PAL_FRAMESIZE;
+      dv1394src->frame_rate = PAL_FRAMERATE;
+      GST_DEBUG ("PAL data");
+      caps = gst_caps_new_simple ("video/x-dv",
+          "format", G_TYPE_STRING, "PAL",
+          "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
+    } else {
+      // NTSC (untested)
+      dv1394src->frame_size = NTSC_FRAMESIZE;
+      dv1394src->frame_rate = NTSC_FRAMERATE;
+      GST_DEBUG
+          ("NTSC data [untested] - please report success/failure to <dan@f3c.com>");
+      caps = gst_caps_new_simple ("video/x-dv",
+          "format", G_TYPE_STRING, "NTSC",
+          "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
+    }
+    gst_pad_set_caps (GST_BASE_SRC_PAD (dv1394src), caps);
+    gst_caps_unref (caps);
+  }
+
+  dv1394src->frame = NULL;
+  if (G_LIKELY ((dv1394src->frame_sequence + 1) % (dv1394src->skip +
+              dv1394src->consecutive) < dv1394src->consecutive)) {
+    if (complete && len == dv1394src->frame_size) {
+      GstBuffer *buf;
+
+      buf = gst_buffer_new_and_alloc (dv1394src->frame_size);
+
+      GST_BUFFER_OFFSET (buf) = dv1394src->frame_sequence;
+      gst_buffer_fill (buf, 0, data, len);
+      dv1394src->buf = buf;
+    }
+  }
+  dv1394src->frame_sequence++;
+  return 0;
+}
+
+#else
+static int
+gst_dv1394src_iso_receive (raw1394handle_t handle, int channel, size_t len,
+    quadlet_t * data)
+{
+  GstDV1394Src *dv1394src = gst_dv1394src_from_raw1394handle (handle);
+
+  if (len > 16) {
+    /*
+       the following code taken from kino-0.51 (Dan Dennedy/Charles Yates)
+       Kindly relicensed under the LGPL. See the commit log for version 1.6 of
+       this file in CVS.
+     */
+    unsigned char *p = (unsigned char *) &data[3];
+
+    int section_type = p[0] >> 5;       /* section type is in bits 5 - 7 */
+    int dif_sequence = p[1] >> 4;       /* dif sequence number is in bits 4 - 7 */
+    int dif_block = p[2];
+
+    /* if we are at the beginning of a frame, 
+       we set buf=frame, and alloc a new buffer for frame
+     */
+    if (section_type == 0 && dif_sequence == 0) {       // dif header
+      if (!GST_PAD_CAPS (GST_BASE_SRC_PAD (dv1394src))) {
+        GstCaps *caps;
+
+        // figure format (NTSC/PAL)
+        if (p[3] & 0x80) {
+          // PAL
+          dv1394src->frame_size = PAL_FRAMESIZE;
+          dv1394src->frame_rate = PAL_FRAMERATE;
+          GST_DEBUG ("PAL data");
+          caps = gst_caps_new_simple ("video/x-dv",
+              "format", G_TYPE_STRING, "PAL",
+              "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
+        } else {
+          // NTSC (untested)
+          dv1394src->frame_size = NTSC_FRAMESIZE;
+          dv1394src->frame_rate = NTSC_FRAMERATE;
+          GST_DEBUG
+              ("NTSC data [untested] - please report success/failure to <dan@f3c.com>");
+          caps = gst_caps_new_simple ("video/x-dv",
+              "format", G_TYPE_STRING, "NTSC",
+              "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
+        }
+        gst_pad_set_caps (GST_BASE_SRC_PAD (dv1394src), caps);
+        gst_caps_unref (caps);
+      }
+      // drop last frame when not complete
+      if (!dv1394src->drop_incomplete
+          || dv1394src->bytes_in_frame == dv1394src->frame_size) {
+        dv1394src->buf = dv1394src->frame;
+      } else {
+        GST_INFO_OBJECT (GST_ELEMENT (dv1394src), "incomplete frame dropped");
+        g_signal_emit (G_OBJECT (dv1394src),
+            gst_dv1394src_signals[SIGNAL_FRAME_DROPPED], 0);
+        if (dv1394src->frame) {
+          gst_buffer_unref (dv1394src->frame);
+        }
+      }
+      if ((dv1394src->frame_sequence + 1) % (dv1394src->skip +
+              dv1394src->consecutive) < dv1394src->consecutive) {
+        GstBuffer *buf;
+        gint64 i64;
+
+        buf = gst_buffer_new_and_alloc (dv1394src->frame_size);
+
+        /* fill in offset, duration, timestamp */
+        GST_BUFFER_OFFSET (buf) = dv1394src->frame_sequence;
+        dv1394src->frame = buf;
+      }
+      dv1394src->frame_sequence++;
+      dv1394src->bytes_in_frame = 0;
+    }
+
+    if (dv1394src->frame != NULL) {
+      guint8 *data = GST_BUFFER_DATA (dv1394src->frame);
+
+      switch (section_type) {
+        case 0:                /* 1 Header block */
+          /* p[3] |= 0x80; // hack to force PAL data */
+          memcpy (data + dif_sequence * 150 * 80, p, 480);
+          break;
+
+        case 1:                /* 2 Subcode blocks */
+          memcpy (data + dif_sequence * 150 * 80 + (1 + dif_block) * 80, p,
+              480);
+          break;
+
+        case 2:                /* 3 VAUX blocks */
+          memcpy (data + dif_sequence * 150 * 80 + (3 + dif_block) * 80, p,
+              480);
+          break;
+
+        case 3:                /* 9 Audio blocks interleaved with video */
+          memcpy (data + dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80, p,
+              480);
+          break;
+
+        case 4:                /* 135 Video blocks interleaved with audio */
+          memcpy (data + dif_sequence * 150 * 80 + (7 + (dif_block / 15) +
+                  dif_block) * 80, p, 480);
+          break;
+
+        default:               /* we can't handle any other data */
+          break;
+      }
+      dv1394src->bytes_in_frame += 480;
+    }
+  }
+
+  return 0;
+}
+#endif
+/*
+ * When an ieee1394 bus reset happens, usually a device has been removed
+ * or added.  We send a message on the message bus with the node count 
+ * and whether the capture device used in this element connected, disconnected 
+ * or was unchanged
+ * Message structure:
+ * nodecount - integer with number of nodes on bus
+ * current-device-change - integer (1 if device connected, 0 if no change to
+ *                         current device status, -1 if device disconnected)
+ */
+static int
+gst_dv1394src_bus_reset (raw1394handle_t handle, unsigned int generation)
+{
+  GstDV1394Src *src;
+  gint nodecount;
+  GstMessage *message;
+  GstStructure *structure;
+  gint current_device_change;
+  gint i;
+
+  src = gst_dv1394src_from_raw1394handle (handle);
+
+  GST_INFO_OBJECT (src, "have bus reset");
+
+  /* update generation - told to do so by docs */
+  raw1394_update_generation (handle, generation);
+  nodecount = raw1394_get_nodecount (handle);
+  /* allocate memory for portinfo */
+
+  /* current_device_change is -1 if camera disconnected, 0 if other device
+   * connected or 1 if camera has now connected */
+  current_device_change = -1;
+  for (i = 0; i < nodecount; i++) {
+    if (src->guid == rom1394_get_guid (handle, i)) {
+      /* Camera is with us */
+      GST_DEBUG ("Camera is with us");
+      if (!src->connected) {
+        current_device_change = 1;
+        src->connected = TRUE;
+      } else
+        current_device_change = 0;
+    }
+  }
+  if (src->connected && current_device_change == -1) {
+    GST_DEBUG ("Camera has disconnected");
+    src->connected = FALSE;
+  } else if (!src->connected && current_device_change == -1) {
+    GST_DEBUG ("Camera is still not with us");
+    current_device_change = 0;
+  }
+
+  structure = gst_structure_new ("ieee1394-bus-reset", "nodecount", G_TYPE_INT,
+      nodecount, "current-device-change", G_TYPE_INT, current_device_change,
+      NULL);
+  message = gst_message_new_element (GST_OBJECT (src), structure);
+  gst_element_post_message (GST_ELEMENT (src), message);
+
+  return 0;
+}
+
+static GstFlowReturn
+gst_dv1394src_create (GstPushSrc * psrc, GstBuffer ** buf)
+{
+  GstDV1394Src *dv1394src = GST_DV1394SRC (psrc);
+  struct pollfd pollfds[2];
+
+  pollfds[0].fd = raw1394_get_fd (dv1394src->handle);
+  pollfds[0].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
+  pollfds[1].fd = READ_SOCKET (dv1394src);
+  pollfds[1].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
+
+  if (G_UNLIKELY (dv1394src->buf)) {
+    /* maybe we had an error before, and there's a stale buffer? */
+    gst_buffer_unref (dv1394src->buf);
+    dv1394src->buf = NULL;
+  }
+
+  while (TRUE) {
+    int res = poll (pollfds, 2, -1);
+
+    if (G_UNLIKELY (res < 0)) {
+      if (errno == EAGAIN || errno == EINTR)
+        continue;
+      else
+        goto error_while_polling;
+    }
+
+    if (G_UNLIKELY (pollfds[1].revents)) {
+      char command;
+
+      if (pollfds[1].revents & POLLIN)
+        READ_COMMAND (dv1394src, command, res);
+
+      goto told_to_stop;
+    } else if (G_LIKELY (pollfds[0].revents & POLLIN)) {
+      /* shouldn't block in theory */
+      raw1394_loop_iterate (dv1394src->handle);
+
+      if (dv1394src->buf)
+        break;
+    }
+  }
+
+  g_assert (dv1394src->buf);
+
+  *buf = dv1394src->buf;
+  dv1394src->buf = NULL;
+  return GST_FLOW_OK;
+
+error_while_polling:
+  {
+    GST_ELEMENT_ERROR (dv1394src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
+    return GST_FLOW_EOS;
+  }
+told_to_stop:
+  {
+    GST_DEBUG_OBJECT (dv1394src, "told to stop, shutting down");
+    return GST_FLOW_FLUSHING;
+  }
+}
+
+static int
+gst_dv1394src_discover_avc_node (GstDV1394Src * src)
+{
+  int node = -1;
+  int i, j = 0;
+  int m = src->num_ports;
+
+  if (src->port >= 0) {
+    /* search on explicit port */
+    j = src->port;
+    m = j + 1;
+  }
+
+  /* loop over all our ports */
+  for (; j < m && node == -1; j++) {
+    raw1394handle_t handle;
+    struct raw1394_portinfo pinf[16];
+
+    /* open the port */
+    handle = raw1394_new_handle ();
+    if (!handle) {
+      GST_WARNING ("raw1394 - failed to get handle: %s.\n", strerror (errno));
+      continue;
+    }
+    if (raw1394_get_port_info (handle, pinf, 16) < 0) {
+      GST_WARNING ("raw1394 - failed to get port info: %s.\n",
+          strerror (errno));
+      goto next;
+    }
+
+    /* tell raw1394 which host adapter to use */
+    if (raw1394_set_port (handle, j) < 0) {
+      GST_WARNING ("raw1394 - failed to set set port: %s.\n", strerror (errno));
+      goto next;
+    }
+
+    /* now loop over all the nodes */
+    for (i = 0; i < raw1394_get_nodecount (handle); i++) {
+      /* are we looking for an explicit GUID ? */
+      if (src->guid != 0) {
+        if (src->guid == rom1394_get_guid (handle, i)) {
+          node = i;
+          src->port = j;
+          g_free (src->uri);
+          src->uri = g_strdup_printf ("dv://%d", src->port);
+          break;
+        }
+      } else {
+        rom1394_directory rom_dir;
+
+        /* select first AV/C Tape Recorder Player node */
+        if (rom1394_get_directory (handle, i, &rom_dir) < 0) {
+          GST_WARNING ("error reading config rom directory for node %d\n", i);
+          continue;
+        }
+        if ((rom1394_get_node_type (&rom_dir) == ROM1394_NODE_TYPE_AVC) &&
+            avc1394_check_subunit_type (handle, i, AVC1394_SUBUNIT_TYPE_VCR)) {
+          node = i;
+          src->port = j;
+          src->guid = rom1394_get_guid (handle, i);
+          g_free (src->uri);
+          src->uri = g_strdup_printf ("dv://%d", src->port);
+          g_free (src->device_name);
+          src->device_name = g_strdup (rom_dir.label);
+          break;
+        }
+        rom1394_free_directory (&rom_dir);
+      }
+    }
+  next:
+    raw1394_destroy_handle (handle);
+  }
+  return node;
+}
+
+static gboolean
+gst_dv1394src_start (GstBaseSrc * bsrc)
+{
+  GstDV1394Src *src = GST_DV1394SRC (bsrc);
+  int control_sock[2];
+
+  src->connected = FALSE;
+
+  if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
+    goto socket_pair;
+
+  READ_SOCKET (src) = control_sock[0];
+  WRITE_SOCKET (src) = control_sock[1];
+
+  if (fcntl (READ_SOCKET (src), F_SETFL, O_NONBLOCK) < 0)
+    GST_ERROR_OBJECT (src, "failed to make read socket non-blocking: %s",
+        g_strerror (errno));
+  if (fcntl (WRITE_SOCKET (src), F_SETFL, O_NONBLOCK) < 0)
+    GST_ERROR_OBJECT (src, "failed to make write socket non-blocking: %s",
+        g_strerror (errno));
+
+  src->handle = raw1394_new_handle ();
+
+  if (!src->handle) {
+    if (errno == EACCES)
+      goto permission_denied;
+    else if (errno == ENOENT)
+      goto not_found;
+    else
+      goto no_handle;
+  }
+
+  src->num_ports = raw1394_get_port_info (src->handle, src->pinfo, 16);
+
+  if (src->num_ports == 0)
+    goto no_ports;
+
+  if (src->use_avc || src->port == -1)
+    src->avc_node = gst_dv1394src_discover_avc_node (src);
+
+  /* lets destroy handle and create one on port
+     this is more reliable than setting port on
+     the existing handle */
+  raw1394_destroy_handle (src->handle);
+  src->handle = raw1394_new_handle_on_port (src->port);
+  if (!src->handle)
+    goto cannot_set_port;
+
+  raw1394_set_userdata (src->handle, src);
+  raw1394_set_bus_reset_handler (src->handle, gst_dv1394src_bus_reset);
+
+#ifdef HAVE_LIBIEC61883
+  if ((src->iec61883dv =
+          iec61883_dv_fb_init (src->handle,
+              gst_dv1394src_iec61883_receive, src)) == NULL)
+    goto cannot_initialise_dv;
+
+#else
+  raw1394_set_iso_handler (src->handle, src->channel,
+      gst_dv1394src_iso_receive);
+#endif
+
+  GST_DEBUG_OBJECT (src, "successfully opened up 1394 connection");
+  src->connected = TRUE;
+
+#ifdef HAVE_LIBIEC61883
+  if (iec61883_dv_fb_start (src->iec61883dv, src->channel) != 0)
+    goto cannot_start;
+#else
+  if (raw1394_start_iso_rcv (src->handle, src->channel) < 0)
+    goto cannot_start;
+#endif
+
+  if (src->use_avc) {
+    raw1394handle_t avc_handle = raw1394_new_handle_on_port (src->port);
+
+    /* start the VCR */
+    if (avc_handle) {
+      if (!avc1394_vcr_is_recording (avc_handle, src->avc_node)
+          && avc1394_vcr_is_playing (avc_handle, src->avc_node)
+          != AVC1394_VCR_OPERAND_PLAY_FORWARD)
+        avc1394_vcr_play (avc_handle, src->avc_node);
+      raw1394_destroy_handle (avc_handle);
+    } else {
+      GST_WARNING_OBJECT (src, "Starting VCR via avc1394 failed: %s",
+          g_strerror (errno));
+    }
+  }
+
+  gst_1394_clock_set_handle (src->provided_clock, src->handle);
+
+  return TRUE;
+
+socket_pair:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL),
+        GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+permission_denied:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+not_found:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+no_handle:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
+        ("can't get raw1394 handle (%s)", g_strerror (errno)));
+    return FALSE;
+  }
+no_ports:
+  {
+    raw1394_destroy_handle (src->handle);
+    src->handle = NULL;
+    GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
+        ("no ports available for raw1394"));
+    return FALSE;
+  }
+cannot_set_port:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+        ("can't set 1394 port %d", src->port));
+    return FALSE;
+  }
+cannot_start:
+  {
+    raw1394_destroy_handle (src->handle);
+    src->handle = NULL;
+#ifdef HAVE_LIBIEC61883
+    iec61883_dv_fb_close (src->iec61883dv);
+    src->iec61883dv = NULL;
+#endif
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+        ("can't start 1394 iso receive"));
+    return FALSE;
+  }
+#ifdef HAVE_LIBIEC61883
+cannot_initialise_dv:
+  {
+    raw1394_destroy_handle (src->handle);
+    src->handle = NULL;
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+        ("can't initialise iec61883 dv"));
+    return FALSE;
+  }
+#endif
+}
+
+static gboolean
+gst_dv1394src_stop (GstBaseSrc * bsrc)
+{
+  GstDV1394Src *src = GST_DV1394SRC (bsrc);
+
+  close (READ_SOCKET (src));
+  close (WRITE_SOCKET (src));
+  READ_SOCKET (src) = -1;
+  WRITE_SOCKET (src) = -1;
+#ifdef HAVE_LIBIEC61883
+  iec61883_dv_fb_close (src->iec61883dv);
+#else
+  raw1394_stop_iso_rcv (src->handle, src->channel);
+#endif
+
+  if (src->use_avc) {
+    raw1394handle_t avc_handle = raw1394_new_handle_on_port (src->port);
+
+    /* pause and stop the VCR */
+    if (avc_handle) {
+      if (!avc1394_vcr_is_recording (avc_handle, src->avc_node)
+          && (avc1394_vcr_is_playing (avc_handle, src->avc_node)
+              != AVC1394_VCR_OPERAND_PLAY_FORWARD_PAUSE))
+        avc1394_vcr_pause (avc_handle, src->avc_node);
+      avc1394_vcr_stop (avc_handle, src->avc_node);
+      raw1394_destroy_handle (avc_handle);
+    } else {
+      GST_WARNING_OBJECT (src, "Starting VCR via avc1394 failed: %s",
+          g_strerror (errno));
+    }
+  }
+
+  gst_1394_clock_unset_handle (src->provided_clock);
+
+  raw1394_destroy_handle (src->handle);
+
+  return TRUE;
+}
+
+static gboolean
+gst_dv1394src_unlock (GstBaseSrc * bsrc)
+{
+  GstDV1394Src *src = GST_DV1394SRC (bsrc);
+
+  SEND_COMMAND (src, CONTROL_STOP);
+
+  return TRUE;
+}
+
+static gboolean
+gst_dv1394src_query (GstBaseSrc * basesrc, GstQuery * query)
+{
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_LATENCY:
+    {
+      gst_query_set_latency (query, TRUE, GST_SECOND / 25, GST_SECOND / 25);
+    }
+      break;
+    default:
+      goto not_supported;
+  }
+
+  return TRUE;
+
+not_supported:
+  return GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
+}
+
+static void
+gst_dv1394src_update_device_name (GstDV1394Src * src)
+{
+  raw1394handle_t handle;
+  gint portcount, port, nodecount, node;
+  rom1394_directory directory;
+
+  g_free (src->device_name);
+  src->device_name = NULL;
+
+  GST_LOG_OBJECT (src, "updating device name for current GUID");
+
+  handle = raw1394_new_handle ();
+
+  if (handle == NULL)
+    goto gethandle_failed;
+
+  portcount = raw1394_get_port_info (handle, NULL, 0);
+  for (port = 0; port < portcount; port++) {
+    if (raw1394_set_port (handle, port) >= 0) {
+      nodecount = raw1394_get_nodecount (handle);
+      for (node = 0; node < nodecount; node++) {
+        if (src->guid == rom1394_get_guid (handle, node)) {
+          if (rom1394_get_directory (handle, node, &directory) >= 0) {
+            g_free (src->device_name);
+            src->device_name = g_strdup (directory.label);
+            rom1394_free_directory (&directory);
+            goto done;
+          } else {
+            GST_WARNING ("error reading rom directory for node %d", node);
+          }
+        }
+      }
+    }
+  }
+
+  src->device_name = g_strdup ("Unknown");      /* FIXME: translate? */
+
+done:
+
+  raw1394_destroy_handle (handle);
+  return;
+
+/* ERRORS */
+gethandle_failed:
+  {
+    GST_WARNING ("failed to get raw1394 handle: %s", g_strerror (errno));
+    src->device_name = g_strdup ("Unknown");    /* FIXME: translate? */
+    return;
+  }
+}
+
+/*** GSTURIHANDLER INTERFACE *************************************************/
+
+static GstURIType
+gst_dv1394src_uri_get_type (GType type)
+{
+  return GST_URI_SRC;
+}
+
+static const gchar *const *
+gst_dv1394src_uri_get_protocols (GType type)
+{
+  static const gchar *protocols[] = { (char *) "dv", NULL };
+
+  return protocols;
+}
+
+static gchar *
+gst_dv1394src_uri_get_uri (GstURIHandler * handler)
+{
+  GstDV1394Src *gst_dv1394src = GST_DV1394SRC (handler);
+
+  return gst_dv1394src->uri;
+}
+
+static gboolean
+gst_dv1394src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+    GError ** error)
+{
+  gchar *protocol, *location;
+  gboolean ret = TRUE;
+  GstDV1394Src *gst_dv1394src = GST_DV1394SRC (handler);
+
+  protocol = gst_uri_get_protocol (uri);
+  if (strcmp (protocol, "dv") != 0) {
+    g_free (protocol);
+    g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, "Invalid DV URI");
+    return FALSE;
+  }
+  g_free (protocol);
+
+  location = gst_uri_get_location (uri);
+  if (location && *location != '\0')
+    gst_dv1394src->port = strtol (location, NULL, 10);
+  else
+    gst_dv1394src->port = DEFAULT_PORT;
+  g_free (location);
+  g_free (gst_dv1394src->uri);
+  gst_dv1394src->uri = g_strdup_printf ("dv://%d", gst_dv1394src->port);
+
+  return ret;
+}
+
+static void
+gst_dv1394src_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+  iface->get_type = gst_dv1394src_uri_get_type;
+  iface->get_protocols = gst_dv1394src_uri_get_protocols;
+  iface->get_uri = gst_dv1394src_uri_get_uri;
+  iface->set_uri = gst_dv1394src_uri_set_uri;
+}
diff --git a/ext/raw1394/gstdv1394src.h b/ext/raw1394/gstdv1394src.h
new file mode 100644
index 0000000..e2f3308
--- /dev/null
+++ b/ext/raw1394/gstdv1394src.h
@@ -0,0 +1,101 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_GST1394_H__
+#define __GST_GST1394_H__
+
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+#include "gst1394clock.h"
+
+#include <libraw1394/raw1394.h>
+#ifdef HAVE_LIBIEC61883
+#include <libiec61883/iec61883.h>
+#endif
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DV1394SRC \
+  (gst_dv1394src_get_type())
+#define GST_DV1394SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DV1394SRC,GstDV1394Src))
+#define GST_DV1394SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DV1394SRC,GstDV1394SrcClass))
+#define GST_IS_DV1394SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DV1394SRC))
+#define GST_IS_DV1394SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DV1394SRC))
+
+typedef struct _GstDV1394Src GstDV1394Src;
+typedef struct _GstDV1394SrcClass GstDV1394SrcClass;
+
+struct _GstDV1394Src {
+  GstPushSrc element;
+
+  // consecutive=2, skip=4 will skip 4 frames, then let 2 consecutive ones thru
+  gint consecutive;
+  gint skip;
+  gboolean drop_incomplete;
+
+  gint num_ports;
+  gint port;
+  gint channel;
+  octlet_t guid;
+  gint avc_node;
+  gboolean use_avc;
+
+  struct raw1394_portinfo pinfo[16];
+  raw1394handle_t handle;
+
+  GstBuffer *buf;
+  
+  GstBuffer *frame;
+  guint frame_size;
+  guint frame_rate;
+  guint bytes_in_frame;
+  guint frame_sequence;
+
+  int control_sock[2];
+
+  gchar *uri;
+
+  gchar *device_name;
+
+  gboolean connected;
+  #ifdef HAVE_LIBIEC61883
+  iec61883_dv_fb_t iec61883dv;
+  #endif
+
+  Gst1394Clock *provided_clock;
+};
+
+struct _GstDV1394SrcClass {
+  GstPushSrcClass parent_class;
+
+  /* signal */
+  void (*frame_dropped)  (GstElement *elem);
+};
+
+GType gst_dv1394src_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_GST1394_H__ */
diff --git a/ext/raw1394/gsthdv1394src.c b/ext/raw1394/gsthdv1394src.c
new file mode 100644
index 0000000..04ceb4f
--- /dev/null
+++ b/ext/raw1394/gsthdv1394src.c
@@ -0,0 +1,841 @@
+/* GStreamer
+ * Copyright (C) <2008> Edward Hervey <bilboed@bilboed.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-hdv1394src
+ *
+ * Read MPEG-TS data from firewire port.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 hdv1394src ! queue ! decodebin name=d ! queue ! xvimagesink d. ! queue ! alsasink
+ * ]| captures from the firewire port and plays the streams.
+ * |[
+ * gst-launch-1.0 hdv1394src ! queue ! filesink location=mydump.ts
+ * ]| capture to a disk file
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <unistd.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <libavc1394/avc1394.h>
+#include <libavc1394/avc1394_vcr.h>
+#include <libavc1394/rom1394.h>
+#include <libraw1394/raw1394.h>
+#include <libiec61883/iec61883.h>
+
+#include <gst/gst.h>
+
+#include "gsthdv1394src.h"
+#include "gst1394probe.h"
+
+
+#define CONTROL_STOP            'S'     /* stop the select call */
+#define CONTROL_SOCKETS(src)   src->control_sock
+#define WRITE_SOCKET(src)      src->control_sock[1]
+#define READ_SOCKET(src)       src->control_sock[0]
+
+#define SEND_COMMAND(src, command)          \
+G_STMT_START {                              \
+  int G_GNUC_UNUSED _res; unsigned char c; c = command;   \
+  _res = write (WRITE_SOCKET(src), &c, 1);  \
+} G_STMT_END
+
+#define READ_COMMAND(src, command, res)        \
+G_STMT_START {                                 \
+  res = read(READ_SOCKET(src), &command, 1);   \
+} G_STMT_END
+
+
+GST_DEBUG_CATEGORY_STATIC (hdv1394src_debug);
+#define GST_CAT_DEFAULT (hdv1394src_debug)
+
+#define DEFAULT_PORT    -1
+#define DEFAULT_CHANNEL   63
+#define DEFAULT_USE_AVC   TRUE
+#define DEFAULT_GUID    0
+
+enum
+{
+  PROP_0,
+  PROP_PORT,
+  PROP_CHANNEL,
+  PROP_USE_AVC,
+  PROP_GUID,
+  PROP_DEVICE_NAME
+};
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS
+    ("video/mpegts,systemstream=(boolean)true,packetsize=(int)188")
+    );
+
+static void gst_hdv1394src_uri_handler_init (gpointer g_iface,
+    gpointer iface_data);
+
+static void gst_hdv1394src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_hdv1394src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_hdv1394src_dispose (GObject * object);
+
+static gboolean gst_hdv1394src_start (GstBaseSrc * bsrc);
+static gboolean gst_hdv1394src_stop (GstBaseSrc * bsrc);
+static gboolean gst_hdv1394src_unlock (GstBaseSrc * bsrc);
+
+static GstFlowReturn gst_hdv1394src_create (GstPushSrc * psrc,
+    GstBuffer ** buf);
+
+static void gst_hdv1394src_update_device_name (GstHDV1394Src * src);
+
+#define gst_hdv1394src_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstHDV1394Src, gst_hdv1394src, GST_TYPE_PUSH_SRC,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
+        gst_hdv1394src_uri_handler_init));
+
+static void
+gst_hdv1394src_class_init (GstHDV1394SrcClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSrcClass *gstbasesrc_class;
+  GstPushSrcClass *gstpushsrc_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesrc_class = (GstBaseSrcClass *) klass;
+  gstpushsrc_class = (GstPushSrcClass *) klass;
+
+  gobject_class->set_property = gst_hdv1394src_set_property;
+  gobject_class->get_property = gst_hdv1394src_get_property;
+  gobject_class->dispose = gst_hdv1394src_dispose;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PORT,
+      g_param_spec_int ("port", "Port", "Port number (-1 automatic)",
+          -1, 16, DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CHANNEL,
+      g_param_spec_int ("channel", "Channel", "Channel number for listening",
+          0, 64, DEFAULT_CHANNEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_USE_AVC,
+      g_param_spec_boolean ("use-avc", "Use AV/C", "Use AV/C VTR control",
+          DEFAULT_USE_AVC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_GUID,
+      g_param_spec_uint64 ("guid", "GUID",
+          "select one of multiple DV devices by its GUID. use a hexadecimal "
+          "like 0xhhhhhhhhhhhhhhhh. (0 = no guid)", 0, G_MAXUINT64,
+          DEFAULT_GUID, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstHDV1394Src:device-name:
+   *
+   * Descriptive name of the currently opened device
+   */
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEVICE_NAME,
+      g_param_spec_string ("device-name", "device name",
+          "user-friendly name of the device", "Default",
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  gstbasesrc_class->negotiate = NULL;
+  gstbasesrc_class->start = gst_hdv1394src_start;
+  gstbasesrc_class->stop = gst_hdv1394src_stop;
+  gstbasesrc_class->unlock = gst_hdv1394src_unlock;
+
+  gstpushsrc_class->create = gst_hdv1394src_create;
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Firewire (1394) HDV video source", "Source/Video",
+      "Source for MPEG-TS video data from firewire port",
+      "Edward Hervey <bilboed@bilboed.com>");
+
+  GST_DEBUG_CATEGORY_INIT (hdv1394src_debug, "hdv1394src", 0,
+      "MPEG-TS firewire source");
+}
+
+static void
+gst_hdv1394src_init (GstHDV1394Src * dv1394src)
+{
+  GstPad *srcpad = GST_BASE_SRC_PAD (dv1394src);
+
+  gst_base_src_set_live (GST_BASE_SRC (dv1394src), TRUE);
+  gst_pad_use_fixed_caps (srcpad);
+
+  dv1394src->port = DEFAULT_PORT;
+  dv1394src->channel = DEFAULT_CHANNEL;
+
+  dv1394src->use_avc = DEFAULT_USE_AVC;
+  dv1394src->guid = DEFAULT_GUID;
+  dv1394src->uri = g_strdup_printf ("hdv://%d", dv1394src->port);
+  dv1394src->device_name = g_strdup_printf ("Default");
+
+  READ_SOCKET (dv1394src) = -1;
+  WRITE_SOCKET (dv1394src) = -1;
+
+  dv1394src->frame_sequence = 0;
+}
+
+static void
+gst_hdv1394src_dispose (GObject * object)
+{
+  GstHDV1394Src *src = GST_HDV1394SRC (object);
+
+  g_free (src->uri);
+  src->uri = NULL;
+
+  g_free (src->device_name);
+  src->device_name = NULL;
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_hdv1394src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstHDV1394Src *filter = GST_HDV1394SRC (object);
+
+  switch (prop_id) {
+    case PROP_PORT:
+      filter->port = g_value_get_int (value);
+      g_free (filter->uri);
+      filter->uri = g_strdup_printf ("hdv://%d", filter->port);
+      break;
+    case PROP_CHANNEL:
+      filter->channel = g_value_get_int (value);
+      break;
+    case PROP_USE_AVC:
+      filter->use_avc = g_value_get_boolean (value);
+      break;
+    case PROP_GUID:
+      filter->guid = g_value_get_uint64 (value);
+      gst_hdv1394src_update_device_name (filter);
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_hdv1394src_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstHDV1394Src *filter = GST_HDV1394SRC (object);
+
+  switch (prop_id) {
+    case PROP_PORT:
+      g_value_set_int (value, filter->port);
+      break;
+    case PROP_CHANNEL:
+      g_value_set_int (value, filter->channel);
+      break;
+    case PROP_USE_AVC:
+      g_value_set_boolean (value, filter->use_avc);
+      break;
+    case PROP_GUID:
+      g_value_set_uint64 (value, filter->guid);
+      break;
+    case PROP_DEVICE_NAME:
+      g_value_set_string (value, filter->device_name);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstHDV1394Src *
+gst_hdv1394src_from_raw1394handle (raw1394handle_t handle)
+{
+  iec61883_mpeg2_t mpeg2 = (iec61883_mpeg2_t) raw1394_get_userdata (handle);
+  return GST_HDV1394SRC (iec61883_mpeg2_get_callback_data (mpeg2));
+}
+
+/* Within one loop iteration (which may call _receive() many times), it seems
+ * as though '*data' will always be different.
+ *
+ * We can therefore assume that any '*data' given to us will stay allocated until
+ * the next loop iteration.
+ */
+
+static int
+gst_hdv1394src_iec61883_receive (unsigned char *data, int len,
+    unsigned int dropped, void *cbdata)
+{
+  GstHDV1394Src *dv1394src = GST_HDV1394SRC (cbdata);
+
+  GST_LOG ("data:%p, len:%d, dropped:%d", data, len, dropped);
+
+  /* error out if we don't have enough room ! */
+  if (G_UNLIKELY (dv1394src->outoffset > (2048 * 188 - len)))
+    return -1;
+
+  if (G_LIKELY (len == IEC61883_MPEG2_TSP_SIZE)) {
+    memcpy ((guint8 *) dv1394src->outdata + dv1394src->outoffset, data, len);
+    dv1394src->outoffset += len;
+  }
+  dv1394src->frame_sequence++;
+  return 0;
+}
+
+/*
+ * When an ieee1394 bus reset happens, usually a device has been removed
+ * or added.  We send a message on the message bus with the node count 
+ * and whether the capture device used in this element connected, disconnected 
+ * or was unchanged
+ * Message structure:
+ * nodecount - integer with number of nodes on bus
+ * current-device-change - integer (1 if device connected, 0 if no change to
+ *                         current device status, -1 if device disconnected)
+ */
+static int
+gst_hdv1394src_bus_reset (raw1394handle_t handle, unsigned int generation)
+{
+  GstHDV1394Src *src;
+  gint nodecount;
+  GstMessage *message;
+  GstStructure *structure;
+  gint current_device_change;
+  gint i;
+
+  src = gst_hdv1394src_from_raw1394handle (handle);
+
+  GST_INFO_OBJECT (src, "have bus reset");
+
+  /* update generation - told to do so by docs */
+  raw1394_update_generation (handle, generation);
+  nodecount = raw1394_get_nodecount (handle);
+  /* allocate memory for portinfo */
+
+  /* current_device_change is -1 if camera disconnected, 0 if other device
+   * connected or 1 if camera has now connected */
+  current_device_change = -1;
+  for (i = 0; i < nodecount; i++) {
+    if (src->guid == rom1394_get_guid (handle, i)) {
+      /* Camera is with us */
+      GST_DEBUG ("Camera is with us");
+      if (!src->connected) {
+        current_device_change = 1;
+        src->connected = TRUE;
+      } else
+        current_device_change = 0;
+    }
+  }
+  if (src->connected && current_device_change == -1) {
+    GST_DEBUG ("Camera has disconnected");
+    src->connected = FALSE;
+  } else if (!src->connected && current_device_change == -1) {
+    GST_DEBUG ("Camera is still not with us");
+    current_device_change = 0;
+  }
+
+  structure = gst_structure_new ("ieee1394-bus-reset", "nodecount", G_TYPE_INT,
+      nodecount, "current-device-change", G_TYPE_INT, current_device_change,
+      NULL);
+  message = gst_message_new_element (GST_OBJECT (src), structure);
+  gst_element_post_message (GST_ELEMENT (src), message);
+
+  return 0;
+}
+
+static GstFlowReturn
+gst_hdv1394src_create (GstPushSrc * psrc, GstBuffer ** buf)
+{
+  GstHDV1394Src *dv1394src = GST_HDV1394SRC (psrc);
+  struct pollfd pollfds[2];
+
+  pollfds[0].fd = raw1394_get_fd (dv1394src->handle);
+  pollfds[0].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
+  pollfds[1].fd = READ_SOCKET (dv1394src);
+  pollfds[1].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
+
+  /* allocate a 2048 samples buffer */
+  dv1394src->outdata = g_malloc (2048 * 188);
+  dv1394src->outoffset = 0;
+
+  GST_DEBUG ("Create...");
+
+  while (TRUE) {
+    int res = poll (pollfds, 2, -1);
+
+    GST_LOG ("res:%d", res);
+
+    if (G_UNLIKELY (res < 0)) {
+      if (errno == EAGAIN || errno == EINTR)
+        continue;
+      else
+        goto error_while_polling;
+    }
+
+    if (G_UNLIKELY (pollfds[1].revents)) {
+      char command;
+
+      if (pollfds[1].revents & POLLIN)
+        READ_COMMAND (dv1394src, command, res);
+
+      goto told_to_stop;
+    } else if (G_LIKELY (pollfds[0].revents & POLLIN)) {
+      int pt;
+
+      pt = dv1394src->frame_sequence;
+      /* shouldn't block in theory */
+      GST_LOG ("Iterating ! (%d)", dv1394src->frame_sequence);
+      raw1394_loop_iterate (dv1394src->handle);
+      GST_LOG ("After iteration : %d (diff:%d)",
+          dv1394src->frame_sequence, dv1394src->frame_sequence - pt);
+      if (dv1394src->outoffset)
+        break;
+    }
+  }
+
+  g_assert (dv1394src->outoffset);
+
+  GST_LOG ("We have some frames (%u bytes)", (guint) dv1394src->outoffset);
+
+  /* Create the buffer */
+  *buf = gst_buffer_new_wrapped (dv1394src->outdata, dv1394src->outoffset);
+  dv1394src->outdata = NULL;
+  dv1394src->outoffset = 0;
+
+  return GST_FLOW_OK;
+
+error_while_polling:
+  {
+    GST_ELEMENT_ERROR (dv1394src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
+    return GST_FLOW_EOS;
+  }
+told_to_stop:
+  {
+    GST_DEBUG_OBJECT (dv1394src, "told to stop, shutting down");
+    return GST_FLOW_FLUSHING;
+  }
+}
+
+static int
+gst_hdv1394src_discover_avc_node (GstHDV1394Src * src)
+{
+  int node = -1;
+  int i, j = 0;
+  int m = src->num_ports;
+
+  if (src->port >= 0) {
+    /* search on explicit port */
+    j = src->port;
+    m = j + 1;
+  }
+
+  /* loop over all our ports */
+  for (; j < m && node == -1; j++) {
+    raw1394handle_t handle;
+    struct raw1394_portinfo pinf[16];
+
+    /* open the port */
+    handle = raw1394_new_handle ();
+    if (!handle) {
+      GST_WARNING ("raw1394 - failed to get handle: %s.\n", strerror (errno));
+      continue;
+    }
+    if (raw1394_get_port_info (handle, pinf, 16) < 0) {
+      GST_WARNING ("raw1394 - failed to get port info: %s.\n",
+          strerror (errno));
+      goto next;
+    }
+
+    /* tell raw1394 which host adapter to use */
+    if (raw1394_set_port (handle, j) < 0) {
+      GST_WARNING ("raw1394 - failed to set set port: %s.\n", strerror (errno));
+      goto next;
+    }
+
+    /* now loop over all the nodes */
+    for (i = 0; i < raw1394_get_nodecount (handle); i++) {
+      /* are we looking for an explicit GUID ? */
+      if (src->guid != 0) {
+        if (src->guid == rom1394_get_guid (handle, i)) {
+          node = i;
+          src->port = j;
+          g_free (src->uri);
+          src->uri = g_strdup_printf ("dv://%d", src->port);
+          break;
+        }
+      } else {
+        rom1394_directory rom_dir;
+
+        /* select first AV/C Tape Recorder Player node */
+        if (rom1394_get_directory (handle, i, &rom_dir) < 0) {
+          GST_WARNING ("error reading config rom directory for node %d\n", i);
+          continue;
+        }
+        if ((rom1394_get_node_type (&rom_dir) == ROM1394_NODE_TYPE_AVC) &&
+            avc1394_check_subunit_type (handle, i, AVC1394_SUBUNIT_TYPE_VCR)) {
+          node = i;
+          src->port = j;
+          src->guid = rom1394_get_guid (handle, i);
+          g_free (src->uri);
+          src->uri = g_strdup_printf ("dv://%d", src->port);
+          g_free (src->device_name);
+          src->device_name = g_strdup (rom_dir.label);
+          break;
+        }
+        rom1394_free_directory (&rom_dir);
+      }
+    }
+  next:
+    raw1394_destroy_handle (handle);
+  }
+  return node;
+}
+
+static gboolean
+gst_hdv1394src_start (GstBaseSrc * bsrc)
+{
+  GstHDV1394Src *src = GST_HDV1394SRC (bsrc);
+  int control_sock[2];
+
+  src->connected = FALSE;
+
+  if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
+    goto socket_pair;
+
+  READ_SOCKET (src) = control_sock[0];
+  WRITE_SOCKET (src) = control_sock[1];
+
+  if (fcntl (READ_SOCKET (src), F_SETFL, O_NONBLOCK) < 0)
+    GST_ERROR_OBJECT (src, "failed to make read socket non-blocking: %s",
+        g_strerror (errno));
+  if (fcntl (WRITE_SOCKET (src), F_SETFL, O_NONBLOCK) < 0)
+    GST_ERROR_OBJECT (src, "failed to make write socket non-blocking: %s",
+        g_strerror (errno));
+
+  src->handle = raw1394_new_handle ();
+
+  if (!src->handle) {
+    if (errno == EACCES)
+      goto permission_denied;
+    else if (errno == ENOENT)
+      goto not_found;
+    else
+      goto no_handle;
+  }
+
+  src->num_ports = raw1394_get_port_info (src->handle, src->pinfo, 16);
+
+  if (src->num_ports == 0)
+    goto no_ports;
+
+  if (src->use_avc || src->port == -1)
+    src->avc_node = gst_hdv1394src_discover_avc_node (src);
+
+  /* lets destroy handle and create one on port
+     this is more reliable than setting port on
+     the existing handle */
+  raw1394_destroy_handle (src->handle);
+  src->handle = raw1394_new_handle_on_port (src->port);
+  if (!src->handle)
+    goto cannot_set_port;
+
+  raw1394_set_userdata (src->handle, src);
+  raw1394_set_bus_reset_handler (src->handle, gst_hdv1394src_bus_reset);
+
+  {
+    nodeid_t m_node = (src->avc_node | 0xffc0);
+    int m_channel = -1;
+    int m_bandwidth = 0;
+    int m_outputPort = -1;
+    int m_inputPort = -1;
+
+    m_channel = iec61883_cmp_connect (src->handle, m_node, &m_outputPort,
+        raw1394_get_local_id (src->handle), &m_inputPort, &m_bandwidth);
+
+    if (m_channel >= 0) {
+      src->channel = m_channel;
+    }
+  }
+
+
+  if ((src->iec61883mpeg2 =
+          iec61883_mpeg2_recv_init (src->handle,
+              gst_hdv1394src_iec61883_receive, src)) == NULL)
+    goto cannot_initialise_dv;
+
+#if 0
+  raw1394_set_iso_handler (src->handle, src->channel,
+      gst_hdv1394src_iso_receive);
+#endif
+
+  GST_DEBUG_OBJECT (src, "successfully opened up 1394 connection");
+  src->connected = TRUE;
+
+  if (iec61883_mpeg2_recv_start (src->iec61883mpeg2, src->channel) != 0)
+    goto cannot_start;
+#if 0
+  if (raw1394_start_iso_rcv (src->handle, src->channel) < 0)
+    goto cannot_start;
+#endif
+
+  if (src->use_avc) {
+    raw1394handle_t avc_handle = raw1394_new_handle_on_port (src->port);
+
+    GST_LOG ("We have an avc_handle");
+
+    /* start the VCR */
+    if (avc_handle) {
+      if (!avc1394_vcr_is_recording (avc_handle, src->avc_node)
+          && avc1394_vcr_is_playing (avc_handle, src->avc_node)
+          != AVC1394_VCR_OPERAND_PLAY_FORWARD) {
+        GST_LOG ("Calling avc1394_vcr_play()");
+        avc1394_vcr_play (avc_handle, src->avc_node);
+      }
+      raw1394_destroy_handle (avc_handle);
+    } else {
+      GST_WARNING_OBJECT (src, "Starting VCR via avc1394 failed: %s",
+          g_strerror (errno));
+    }
+  }
+
+  return TRUE;
+
+socket_pair:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL),
+        GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+permission_denied:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+not_found:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+no_handle:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
+        ("can't get raw1394 handle (%s)", g_strerror (errno)));
+    return FALSE;
+  }
+no_ports:
+  {
+    raw1394_destroy_handle (src->handle);
+    src->handle = NULL;
+    GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
+        ("no ports available for raw1394"));
+    return FALSE;
+  }
+cannot_set_port:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+        ("can't set 1394 port %d", src->port));
+    return FALSE;
+  }
+cannot_start:
+  {
+    raw1394_destroy_handle (src->handle);
+    src->handle = NULL;
+    iec61883_mpeg2_close (src->iec61883mpeg2);
+    src->iec61883mpeg2 = NULL;
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+        ("can't start 1394 iso receive"));
+    return FALSE;
+  }
+cannot_initialise_dv:
+  {
+    raw1394_destroy_handle (src->handle);
+    src->handle = NULL;
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+        ("can't initialise iec61883 hdv"));
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_hdv1394src_stop (GstBaseSrc * bsrc)
+{
+  GstHDV1394Src *src = GST_HDV1394SRC (bsrc);
+
+  close (READ_SOCKET (src));
+  close (WRITE_SOCKET (src));
+  READ_SOCKET (src) = -1;
+  WRITE_SOCKET (src) = -1;
+
+  iec61883_mpeg2_close (src->iec61883mpeg2);
+#if 0
+  raw1394_stop_iso_rcv (src->handle, src->channel);
+#endif
+
+  if (src->use_avc) {
+    raw1394handle_t avc_handle = raw1394_new_handle_on_port (src->port);
+
+    /* pause and stop the VCR */
+    if (avc_handle) {
+      if (!avc1394_vcr_is_recording (avc_handle, src->avc_node)
+          && (avc1394_vcr_is_playing (avc_handle, src->avc_node)
+              != AVC1394_VCR_OPERAND_PLAY_FORWARD_PAUSE))
+        avc1394_vcr_pause (avc_handle, src->avc_node);
+      avc1394_vcr_stop (avc_handle, src->avc_node);
+      raw1394_destroy_handle (avc_handle);
+    } else {
+      GST_WARNING_OBJECT (src, "Starting VCR via avc1394 failed: %s",
+          g_strerror (errno));
+    }
+  }
+
+  raw1394_destroy_handle (src->handle);
+
+  return TRUE;
+}
+
+static gboolean
+gst_hdv1394src_unlock (GstBaseSrc * bsrc)
+{
+  GstHDV1394Src *src = GST_HDV1394SRC (bsrc);
+
+  SEND_COMMAND (src, CONTROL_STOP);
+
+  return TRUE;
+}
+
+static void
+gst_hdv1394src_update_device_name (GstHDV1394Src * src)
+{
+  raw1394handle_t handle;
+  gint portcount, port, nodecount, node;
+  rom1394_directory directory;
+
+  g_free (src->device_name);
+  src->device_name = NULL;
+
+  GST_LOG_OBJECT (src, "updating device name for current GUID");
+
+  handle = raw1394_new_handle ();
+
+  if (handle == NULL)
+    goto gethandle_failed;
+
+  portcount = raw1394_get_port_info (handle, NULL, 0);
+  for (port = 0; port < portcount; port++) {
+    if (raw1394_set_port (handle, port) >= 0) {
+      nodecount = raw1394_get_nodecount (handle);
+      for (node = 0; node < nodecount; node++) {
+        if (src->guid == rom1394_get_guid (handle, node)) {
+          if (rom1394_get_directory (handle, node, &directory) >= 0) {
+            g_free (src->device_name);
+            src->device_name = g_strdup (directory.label);
+            rom1394_free_directory (&directory);
+            goto done;
+          } else {
+            GST_WARNING ("error reading rom directory for node %d", node);
+          }
+        }
+      }
+    }
+  }
+
+  src->device_name = g_strdup ("Unknown");      /* FIXME: translate? */
+
+done:
+
+  raw1394_destroy_handle (handle);
+  return;
+
+/* ERRORS */
+gethandle_failed:
+  {
+    GST_WARNING ("failed to get raw1394 handle: %s", g_strerror (errno));
+    src->device_name = g_strdup ("Unknown");    /* FIXME: translate? */
+    return;
+  }
+}
+
+/*** GSTURIHANDLER INTERFACE *************************************************/
+
+static GstURIType
+gst_hdv1394src_uri_get_type (GType type)
+{
+  return GST_URI_SRC;
+}
+
+static const gchar *const *
+gst_hdv1394src_uri_get_protocols (GType type)
+{
+  static const gchar *protocols[] = { (char *) "hdv", NULL };
+
+  return protocols;
+}
+
+static gchar *
+gst_hdv1394src_uri_get_uri (GstURIHandler * handler)
+{
+  GstHDV1394Src *gst_hdv1394src = GST_HDV1394SRC (handler);
+
+  return gst_hdv1394src->uri;
+}
+
+static gboolean
+gst_hdv1394src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+    GError ** error)
+{
+  gchar *protocol, *location;
+  gboolean ret = TRUE;
+  GstHDV1394Src *gst_hdv1394src = GST_HDV1394SRC (handler);
+
+  protocol = gst_uri_get_protocol (uri);
+  if (strcmp (protocol, "hdv") != 0) {
+    g_free (protocol);
+    g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
+        "Invalid HDV URI");
+    return FALSE;
+  }
+  g_free (protocol);
+
+  location = gst_uri_get_location (uri);
+  if (location && *location != '\0')
+    gst_hdv1394src->port = strtol (location, NULL, 10);
+  else
+    gst_hdv1394src->port = DEFAULT_PORT;
+  g_free (location);
+  g_free (gst_hdv1394src->uri);
+  gst_hdv1394src->uri = g_strdup_printf ("hdv://%d", gst_hdv1394src->port);
+
+  return ret;
+}
+
+static void
+gst_hdv1394src_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+  iface->get_type = gst_hdv1394src_uri_get_type;
+  iface->get_protocols = gst_hdv1394src_uri_get_protocols;
+  iface->get_uri = gst_hdv1394src_uri_get_uri;
+  iface->set_uri = gst_hdv1394src_uri_set_uri;
+}
diff --git a/ext/raw1394/gsthdv1394src.h b/ext/raw1394/gsthdv1394src.h
new file mode 100644
index 0000000..6ae863c
--- /dev/null
+++ b/ext/raw1394/gsthdv1394src.h
@@ -0,0 +1,85 @@
+/* GStreamer
+ * Copyright (C) <2008> Edward Hervey <bilboed@bilboed.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_GSTHDV1394_H__
+#define __GST_GSTHDV1394_H__
+
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+
+#include <libraw1394/raw1394.h>
+#ifdef HAVE_LIBIEC61883
+#include <libiec61883/iec61883.h>
+#endif
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_HDV1394SRC \
+  (gst_hdv1394src_get_type())
+#define GST_HDV1394SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_HDV1394SRC,GstHDV1394Src))
+#define GST_HDV1394SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_HDV1394SRC,GstHDV1394SrcClass))
+#define GST_IS_HDV1394SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_HDV1394SRC))
+#define GST_IS_HDV1394SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_HDV1394SRC))
+
+typedef struct _GstHDV1394Src GstHDV1394Src;
+typedef struct _GstHDV1394SrcClass GstHDV1394SrcClass;
+
+struct _GstHDV1394Src {
+  GstPushSrc element;
+
+  gint num_ports;
+  gint port;
+  gint channel;
+  octlet_t guid;
+  gint avc_node;
+  gboolean use_avc;
+
+  struct raw1394_portinfo pinfo[16];
+  raw1394handle_t handle;
+
+  gpointer outdata;
+  gsize outoffset;
+  guint frame_size;
+  guint frame_sequence;
+
+  int control_sock[2];
+
+  gchar *uri;
+
+  gchar *device_name;
+
+  gboolean connected;
+  iec61883_mpeg2_t iec61883mpeg2;
+};
+
+struct _GstHDV1394SrcClass {
+  GstPushSrcClass parent_class;
+};
+
+GType gst_hdv1394src_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_GST1394_H__ */
diff --git a/ext/raw1394/meson.build b/ext/raw1394/meson.build
new file mode 100644
index 0000000..27a6a5a
--- /dev/null
+++ b/ext/raw1394/meson.build
@@ -0,0 +1,22 @@
+raw1394_dep = dependency('libraw1394', version: '>= 2.0.0', required: false)
+avc1394_dep = dependency('libavc1394', version: '>= 0.5.4', required: false)
+iec61883_dep = dependency('libiec61883', version: '>= 1.0.0', required: false)
+
+have_1394 = false
+if raw1394_dep.found() and iec61883_dep.found() and avc1394_dep.found()
+  if cc.has_function('avc1394_send_command', dependencies: avc1394_dep)
+    if cc.has_function('rom1394_free_directory', dependencies: avc1394_dep)
+      have_1394 = true
+    endif
+  endif
+endif
+
+if have_1394
+  library('gst1394',
+    'gst1394.c', 'gst1394probe.c', 'gstdv1394src.c', 'gsthdv1394src.c', 'gst1394clock.c',
+    c_args : gst_plugins_good_args + ['-DHAVE_LIBIEC61883'],
+    include_directories : [configinc, libsinc],
+    dependencies : [gstvideo_dep, gstbase_dep, raw1394_dep, avc1394_dep, iec61883_dep],
+    install : true,
+    install_dir : plugins_install_dir)
+endif
diff --git a/ext/shout2/Makefile.am b/ext/shout2/Makefile.am
new file mode 100644
index 0000000..67705fb
--- /dev/null
+++ b/ext/shout2/Makefile.am
@@ -0,0 +1,8 @@
+plugin_LTLIBRARIES = libgstshout2.la
+
+libgstshout2_la_SOURCES = gstshout2.c 
+libgstshout2_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(SHOUT2_CFLAGS)
+libgstshout2_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(SHOUT2_LIBS)
+libgstshout2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstshout2.h
diff --git a/ext/shout2/gstshout2.c b/ext/shout2/gstshout2.c
new file mode 100644
index 0000000..3d3f652
--- /dev/null
+++ b/ext/shout2/gstshout2.c
@@ -0,0 +1,948 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) <2012> Ralph Giles <giles@mozilla.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-shout2send
+ *
+ * shout2send pushes a media stream to an Icecast server
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 uridecodebin uri=file:///path/to/audiofile ! audioconvert ! vorbisenc ! oggmux ! shout2send mount=/stream.ogg port=8000 username=source password=somepassword ip=server_IP_address_or_hostname
+ * ]| This pipeline demuxes, decodes, re-encodes and re-muxes an audio
+ * media file into oggvorbis and sends the resulting stream to an Icecast
+ * server. Properties mount, port, username and password are all server-config
+ * dependent.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstshout2.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include "gst/gst-i18n-plugin.h"
+
+GST_DEBUG_CATEGORY_STATIC (shout2_debug);
+#define GST_CAT_DEFAULT shout2_debug
+
+
+enum
+{
+  SIGNAL_CONNECTION_PROBLEM,    /* FIXME 2.0: remove this */
+  LAST_SIGNAL
+};
+
+enum
+{
+  ARG_0,
+  ARG_IP,                       /* the IP address or hostname of the server */
+  ARG_PORT,                     /* the encoder port number on the server */
+  ARG_PASSWORD,                 /* the encoder password on the server */
+  ARG_USERNAME,                 /* the encoder username on the server */
+  ARG_PUBLIC,                   /* is this stream public? */
+  ARG_STREAMNAME,               /* Name of the stream */
+  ARG_DESCRIPTION,              /* Description of the stream */
+  ARG_GENRE,                    /* Genre of the stream */
+
+  ARG_PROTOCOL,                 /* Protocol to connect with */
+
+  ARG_MOUNT,                    /* mountpoint of stream (icecast only) */
+  ARG_URL,                      /* the stream's homepage URL */
+
+  ARG_TIMEOUT                   /* The max amount of time to wait for
+                                   network activity */
+};
+
+#define DEFAULT_IP           "127.0.0.1"
+#define DEFAULT_PORT         8000
+#define DEFAULT_PASSWORD     "hackme"
+#define DEFAULT_USERNAME     "source"
+#define DEFAULT_PUBLIC     FALSE
+#define DEFAULT_STREAMNAME   ""
+#define DEFAULT_DESCRIPTION  ""
+#define DEFAULT_GENRE        ""
+#define DEFAULT_MOUNT        ""
+#define DEFAULT_URL          ""
+#define DEFAULT_PROTOCOL     SHOUT2SEND_PROTOCOL_HTTP
+#define DEFAULT_TIMEOUT      10000
+
+#ifdef SHOUT_FORMAT_WEBM
+#define WEBM_CAPS "; video/webm; audio/webm"
+#else
+#define WEBM_CAPS ""
+#endif
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/ogg; audio/ogg; video/ogg; "
+        "audio/mpeg, mpegversion = (int) 1, layer = (int) [ 1, 3 ]" WEBM_CAPS));
+
+static void gst_shout2send_finalize (GstShout2send * shout2send);
+
+static gboolean gst_shout2send_event (GstBaseSink * sink, GstEvent * event);
+static gboolean gst_shout2send_unlock (GstBaseSink * basesink);
+static gboolean gst_shout2send_unlock_stop (GstBaseSink * basesink);
+static GstFlowReturn gst_shout2send_render (GstBaseSink * sink,
+    GstBuffer * buffer);
+static gboolean gst_shout2send_start (GstBaseSink * basesink);
+static gboolean gst_shout2send_stop (GstBaseSink * basesink);
+
+static void gst_shout2send_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_shout2send_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_shout2send_setcaps (GstBaseSink * basesink, GstCaps * caps);
+
+static guint gst_shout2send_signals[LAST_SIGNAL] = { 0 };
+
+#define GST_TYPE_SHOUT_PROTOCOL (gst_shout2send_protocol_get_type())
+static GType
+gst_shout2send_protocol_get_type (void)
+{
+  static GType shout2send_protocol_type = 0;
+  static const GEnumValue shout2send_protocol[] = {
+    {SHOUT2SEND_PROTOCOL_XAUDIOCAST,
+        "Xaudiocast Protocol (icecast 1.3.x)", "xaudiocast"},
+    {SHOUT2SEND_PROTOCOL_ICY, "Icy Protocol (ShoutCast)", "icy"},
+    {SHOUT2SEND_PROTOCOL_HTTP, "Http Protocol (icecast 2.x)", "http"},
+    {0, NULL, NULL},
+  };
+
+  if (!shout2send_protocol_type) {
+    shout2send_protocol_type =
+        g_enum_register_static ("GstShout2SendProtocol", shout2send_protocol);
+  }
+
+
+  return shout2send_protocol_type;
+}
+
+#define gst_shout2send_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstShout2send, gst_shout2send, GST_TYPE_BASE_SINK,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
+
+static void
+gst_shout2send_class_init (GstShout2sendClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSinkClass *gstbasesink_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesink_class = (GstBaseSinkClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->set_property = gst_shout2send_set_property;
+  gobject_class->get_property = gst_shout2send_get_property;
+  gobject_class->finalize = (GObjectFinalizeFunc) gst_shout2send_finalize;
+
+  /* FIXME: 2.0 Should probably change this prop name to "server" */
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_IP,
+      g_param_spec_string ("ip", "ip", "IP address or hostname", DEFAULT_IP,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PORT,
+      g_param_spec_int ("port", "port", "port", 1, G_MAXUSHORT, DEFAULT_PORT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PASSWORD,
+      g_param_spec_string ("password", "password", "password", DEFAULT_PASSWORD,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_USERNAME,
+      g_param_spec_string ("username", "username", "username", DEFAULT_USERNAME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /* metadata */
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PUBLIC,
+      g_param_spec_boolean ("public", "public",
+          "If the stream should be listed on the server's stream directory",
+          DEFAULT_PUBLIC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STREAMNAME,
+      g_param_spec_string ("streamname", "streamname", "name of the stream",
+          DEFAULT_STREAMNAME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DESCRIPTION,
+      g_param_spec_string ("description", "description", "description",
+          DEFAULT_DESCRIPTION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_GENRE,
+      g_param_spec_string ("genre", "genre", "genre", DEFAULT_GENRE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PROTOCOL,
+      g_param_spec_enum ("protocol", "protocol", "Connection Protocol to use",
+          GST_TYPE_SHOUT_PROTOCOL, DEFAULT_PROTOCOL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+
+  /* icecast only */
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MOUNT,
+      g_param_spec_string ("mount", "mount", "mount", DEFAULT_MOUNT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_URL,
+      g_param_spec_string ("url", "url", "the stream's homepage URL",
+          DEFAULT_URL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TIMEOUT,
+      g_param_spec_uint ("timeout", "timeout",
+          "Max amount of time to wait for network activity, in milliseconds",
+          1, G_MAXUINT, DEFAULT_TIMEOUT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /* signals */
+  gst_shout2send_signals[SIGNAL_CONNECTION_PROBLEM] =
+      g_signal_new ("connection-problem", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_CLEANUP, G_STRUCT_OFFSET (GstShout2sendClass,
+          connection_problem), NULL, NULL, g_cclosure_marshal_VOID__INT,
+      G_TYPE_NONE, 1, G_TYPE_INT);
+
+  gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_shout2send_start);
+  gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_shout2send_stop);
+  gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_shout2send_unlock);
+  gstbasesink_class->unlock_stop =
+      GST_DEBUG_FUNCPTR (gst_shout2send_unlock_stop);
+  gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_shout2send_render);
+  gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_shout2send_event);
+  gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_shout2send_setcaps);
+
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Icecast network sink",
+      "Sink/Network", "Sends data to an icecast server",
+      "Wim Taymans <wim.taymans@chello.be>, "
+      "Pedro Corte-Real <typo@netcabo.pt>, "
+      "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
+
+  GST_DEBUG_CATEGORY_INIT (shout2_debug, "shout2", 0, "shout2send element");
+}
+
+static void
+gst_shout2send_init (GstShout2send * shout2send)
+{
+  gst_base_sink_set_sync (GST_BASE_SINK (shout2send), FALSE);
+
+  shout2send->timer = gst_poll_new (TRUE);
+
+  shout2send->ip = g_strdup (DEFAULT_IP);
+  shout2send->port = DEFAULT_PORT;
+  shout2send->password = g_strdup (DEFAULT_PASSWORD);
+  shout2send->username = g_strdup (DEFAULT_USERNAME);
+  shout2send->streamname = g_strdup (DEFAULT_STREAMNAME);
+  shout2send->description = g_strdup (DEFAULT_DESCRIPTION);
+  shout2send->genre = g_strdup (DEFAULT_GENRE);
+  shout2send->mount = g_strdup (DEFAULT_MOUNT);
+  shout2send->url = g_strdup (DEFAULT_URL);
+  shout2send->protocol = DEFAULT_PROTOCOL;
+  shout2send->ispublic = DEFAULT_PUBLIC;
+  shout2send->timeout = DEFAULT_TIMEOUT;
+
+  shout2send->format = -1;
+  shout2send->tags = gst_tag_list_new_empty ();
+  shout2send->conn = NULL;
+  shout2send->connected = FALSE;
+  shout2send->songmetadata = NULL;
+  shout2send->songartist = NULL;
+  shout2send->songtitle = NULL;
+}
+
+static void
+gst_shout2send_finalize (GstShout2send * shout2send)
+{
+  g_free (shout2send->ip);
+  g_free (shout2send->password);
+  g_free (shout2send->username);
+  g_free (shout2send->streamname);
+  g_free (shout2send->description);
+  g_free (shout2send->genre);
+  g_free (shout2send->mount);
+  g_free (shout2send->url);
+
+  gst_tag_list_unref (shout2send->tags);
+
+  gst_poll_free (shout2send->timer);
+
+  G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (shout2send));
+}
+
+static void
+set_shout_metadata (const GstTagList * list, const gchar * tag,
+    gpointer user_data)
+{
+  GstShout2send *shout2send = (GstShout2send *) user_data;
+  char **shout_metadata = &(shout2send->songmetadata);
+  char **song_artist = &(shout2send->songartist);
+  char **song_title = &(shout2send->songtitle);
+
+  gchar *value;
+
+  GST_DEBUG ("tag: %s being added", tag);
+  if (strcmp (tag, GST_TAG_ARTIST) == 0) {
+    if (gst_tag_get_type (tag) == G_TYPE_STRING) {
+      if (!gst_tag_list_get_string (list, tag, &value)) {
+        GST_DEBUG ("Error reading \"%s\" tag value", tag);
+        return;
+      }
+
+      if (*song_artist != NULL)
+        g_free (*song_artist);
+
+      *song_artist = g_strdup (value);
+    }
+  } else if (strcmp (tag, GST_TAG_TITLE) == 0) {
+    if (gst_tag_get_type (tag) == G_TYPE_STRING) {
+      if (!gst_tag_list_get_string (list, tag, &value)) {
+        GST_DEBUG ("Error reading \"%s\" tag value", tag);
+        return;
+      }
+
+      if (*song_title != NULL)
+        g_free (*song_title);
+
+      *song_title = g_strdup (value);
+    }
+  }
+
+  if (*shout_metadata != NULL)
+    g_free (*shout_metadata);
+
+
+  if (*song_title && *song_artist) {
+    *shout_metadata = g_strdup_printf ("%s - %s", *song_artist, *song_title);
+  } else if (*song_title && *song_artist == NULL) {
+    *shout_metadata = g_strdup_printf ("Unknown - %s", *song_title);
+  } else if (*song_title == NULL && *song_artist) {
+    *shout_metadata = g_strdup_printf ("%s - Unknown", *song_artist);
+  } else {
+    *shout_metadata = g_strdup_printf ("Unknown - Unknown");
+  }
+
+  GST_LOG ("shout metadata is now: %s", *shout_metadata);
+}
+
+#if 0
+static void
+gst_shout2send_set_metadata (GstShout2send * shout2send)
+{
+  const GstTagList *user_tags;
+  GstTagList *copy;
+  char *tempmetadata;
+  shout_metadata_t *pmetadata;
+
+  g_return_if_fail (shout2send != NULL);
+  user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (shout2send));
+  if ((shout2send->tags == NULL) && (user_tags == NULL)) {
+    return;
+  }
+  copy = gst_tag_list_merge (user_tags, shout2send->tags,
+      gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (shout2send)));
+  /* lets get the artist and song tags */
+  tempmetadata = NULL;
+  gst_tag_list_foreach ((GstTagList *) copy, set_shout_metadata,
+      (gpointer) & tempmetadata);
+  if (tempmetadata) {
+    pmetadata = shout_metadata_new ();
+    shout_metadata_add (pmetadata, "song", tempmetadata);
+    shout_set_metadata (shout2send->conn, pmetadata);
+    shout_metadata_free (pmetadata);
+  }
+
+  gst_tag_list_unref (copy);
+}
+#endif
+
+
+static gboolean
+gst_shout2send_event (GstBaseSink * sink, GstEvent * event)
+{
+  GstShout2send *shout2send;
+  gboolean ret = TRUE;
+
+  shout2send = GST_SHOUT2SEND (sink);
+
+  GST_LOG_OBJECT (shout2send, "got %s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_TAG:{
+      /* vorbis audio doesn't need metadata setting on the icecast level, only mp3 */
+      if (shout2send->tags && shout2send->format == SHOUT_FORMAT_MP3) {
+        GstTagList *list;
+
+        gst_event_parse_tag (event, &list);
+        GST_DEBUG_OBJECT (shout2send, "tags=%" GST_PTR_FORMAT, list);
+        gst_tag_list_insert (shout2send->tags,
+            list,
+            gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (shout2send)));
+        /* lets get the artist and song tags */
+        gst_tag_list_foreach ((GstTagList *) list,
+            set_shout_metadata, shout2send);
+        if (shout2send->songmetadata && shout2send->connected) {
+          shout_metadata_t *pmetadata;
+
+          GST_DEBUG_OBJECT (shout2send, "metadata now: %s",
+              shout2send->songmetadata);
+
+          pmetadata = shout_metadata_new ();
+          shout_metadata_add (pmetadata, "song", shout2send->songmetadata);
+          shout_set_metadata (shout2send->conn, pmetadata);
+          shout_metadata_free (pmetadata);
+        }
+      }
+      break;
+    }
+    default:{
+      GST_LOG_OBJECT (shout2send, "let base class handle event");
+      if (GST_BASE_SINK_CLASS (parent_class)->event) {
+        event = gst_event_ref (event);
+        ret = GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
+      }
+      break;
+    }
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_shout2send_start (GstBaseSink * basesink)
+{
+  GstShout2send *sink = GST_SHOUT2SEND (basesink);
+  const gchar *cur_prop;
+  gshort proto = 3;
+  gchar *version_string;
+
+  GST_DEBUG_OBJECT (sink, "starting");
+
+  sink->conn = shout_new ();
+
+  switch (sink->protocol) {
+    case SHOUT2SEND_PROTOCOL_XAUDIOCAST:
+      proto = SHOUT_PROTOCOL_XAUDIOCAST;
+      break;
+    case SHOUT2SEND_PROTOCOL_ICY:
+      proto = SHOUT_PROTOCOL_ICY;
+      break;
+    case SHOUT2SEND_PROTOCOL_HTTP:
+      proto = SHOUT_PROTOCOL_HTTP;
+      break;
+  }
+
+  cur_prop = "protocol";
+  GST_DEBUG_OBJECT (sink, "setting protocol: %d", sink->protocol);
+  if (shout_set_protocol (sink->conn, proto) != SHOUTERR_SUCCESS)
+    goto set_failed;
+
+  cur_prop = "ip";
+  GST_DEBUG_OBJECT (sink, "setting IP/hostname: %s", sink->ip);
+  if (shout_set_host (sink->conn, sink->ip) != SHOUTERR_SUCCESS)
+    goto set_failed;
+
+  cur_prop = "port";
+  GST_DEBUG_OBJECT (sink, "setting port: %u", sink->port);
+  if (shout_set_port (sink->conn, sink->port) != SHOUTERR_SUCCESS)
+    goto set_failed;
+
+  cur_prop = "password";
+  GST_DEBUG_OBJECT (sink, "setting password: %s", sink->password);
+  if (shout_set_password (sink->conn, sink->password) != SHOUTERR_SUCCESS)
+    goto set_failed;
+
+  cur_prop = "public";
+  GST_DEBUG_OBJECT (sink, "setting %s: %u", cur_prop, sink->ispublic);
+  if (shout_set_public (sink->conn,
+          (sink->ispublic ? 1 : 0)) != SHOUTERR_SUCCESS)
+    goto set_failed;
+
+  cur_prop = "streamname";
+  GST_DEBUG_OBJECT (sink, "setting %s: %s", cur_prop, sink->streamname);
+  if (shout_set_name (sink->conn, sink->streamname) != SHOUTERR_SUCCESS)
+    goto set_failed;
+
+  cur_prop = "description";
+  GST_DEBUG_OBJECT (sink, "setting %s: %s", cur_prop, sink->description);
+  if (shout_set_description (sink->conn, sink->description) != SHOUTERR_SUCCESS)
+    goto set_failed;
+
+  cur_prop = "genre";
+  GST_DEBUG_OBJECT (sink, "setting %s: %s", cur_prop, sink->genre);
+  if (shout_set_genre (sink->conn, sink->genre) != SHOUTERR_SUCCESS)
+    goto set_failed;
+
+  cur_prop = "mount";
+  GST_DEBUG_OBJECT (sink, "setting %s: %s", cur_prop, sink->mount);
+  if (shout_set_mount (sink->conn, sink->mount) != SHOUTERR_SUCCESS)
+    goto set_failed;
+
+  cur_prop = "username";
+  GST_DEBUG_OBJECT (sink, "setting %s: %s", cur_prop, sink->username);
+  if (shout_set_user (sink->conn, sink->username) != SHOUTERR_SUCCESS)
+    goto set_failed;
+
+  version_string = gst_version_string ();
+  cur_prop = "agent";
+  GST_DEBUG_OBJECT (sink, "setting %s: %s", cur_prop, version_string);
+  if (shout_set_agent (sink->conn, version_string) != SHOUTERR_SUCCESS) {
+    g_free (version_string);
+    goto set_failed;
+  }
+
+  g_free (version_string);
+  return TRUE;
+
+/* ERROR */
+set_failed:
+  {
+    GST_ELEMENT_ERROR (sink, LIBRARY, SETTINGS, (NULL),
+        ("Error setting %s: %s", cur_prop, shout_get_error (sink->conn)));
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_shout2send_connect (GstShout2send * sink)
+{
+  GstFlowReturn fret = GST_FLOW_OK;
+  gint ret;
+  GstClockTime start_ts;
+
+  GST_DEBUG_OBJECT (sink, "Connection format is: %d", sink->format);
+
+  if (sink->format == -1)
+    goto no_caps;
+
+  if (shout_set_nonblocking (sink->conn, 1) != SHOUTERR_SUCCESS)
+    goto could_not_set_nonblocking;
+
+  if (shout_set_format (sink->conn, sink->format) != SHOUTERR_SUCCESS)
+    goto could_not_set_format;
+
+  GST_DEBUG_OBJECT (sink, "connecting");
+
+  start_ts = gst_util_get_timestamp ();
+  ret = shout_open (sink->conn);
+
+  /* wait for connection or timeout */
+  while (ret == SHOUTERR_BUSY) {
+    if (gst_util_get_timestamp () - start_ts > sink->timeout * GST_MSECOND) {
+      goto connection_timeout;
+    }
+    if (gst_poll_wait (sink->timer, 10 * GST_MSECOND) == -1) {
+      GST_LOG_OBJECT (sink, "unlocked");
+
+      fret = gst_base_sink_wait_preroll (GST_BASE_SINK (sink));
+      if (fret != GST_FLOW_OK)
+        goto done;
+    }
+    ret = shout_get_connected (sink->conn);
+  }
+
+  if (ret != SHOUTERR_CONNECTED && ret != SHOUTERR_SUCCESS)
+    goto could_not_connect;
+
+  GST_DEBUG_OBJECT (sink, "connected to server");
+  sink->connected = TRUE;
+
+  /* initialize sending rate monitoring */
+  sink->prev_queuelen = 0;
+  sink->data_sent = 0;
+  sink->stalled = TRUE;
+  sink->datasent_reset_ts = sink->stalled_ts = gst_util_get_timestamp ();
+
+  /* let's set metadata */
+  if (sink->songmetadata) {
+    shout_metadata_t *pmetadata;
+
+    GST_DEBUG_OBJECT (sink, "shout metadata now: %s", sink->songmetadata);
+    pmetadata = shout_metadata_new ();
+    shout_metadata_add (pmetadata, "song", sink->songmetadata);
+    shout_set_metadata (sink->conn, pmetadata);
+    shout_metadata_free (pmetadata);
+  }
+
+done:
+  return fret;
+
+/* ERRORS */
+no_caps:
+  {
+    GST_ELEMENT_ERROR (sink, CORE, NEGOTIATION, (NULL),
+        ("No input caps received."));
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+
+could_not_set_nonblocking:
+  {
+    GST_ELEMENT_ERROR (sink, LIBRARY, SETTINGS, (NULL),
+        ("Error configuring libshout to use non-blocking i/o: %s",
+            shout_get_error (sink->conn)));
+    return GST_FLOW_ERROR;
+  }
+
+could_not_set_format:
+  {
+    GST_ELEMENT_ERROR (sink, LIBRARY, SETTINGS, (NULL),
+        ("Error setting connection format: %s", shout_get_error (sink->conn)));
+    return GST_FLOW_ERROR;
+  }
+
+could_not_connect:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
+        (_("Could not connect to server")),
+        ("shout_open() failed: err=%s", shout_get_error (sink->conn)));
+    g_signal_emit (sink, gst_shout2send_signals[SIGNAL_CONNECTION_PROBLEM], 0,
+        shout_get_errno (sink->conn));
+    return GST_FLOW_ERROR;
+  }
+
+connection_timeout:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
+        (_("Could not connect to server")), ("connection timed out"));
+    g_signal_emit (sink, gst_shout2send_signals[SIGNAL_CONNECTION_PROBLEM], 0,
+        shout_get_errno (sink->conn));
+    return GST_FLOW_ERROR;
+  }
+}
+
+static gboolean
+gst_shout2send_stop (GstBaseSink * basesink)
+{
+  GstShout2send *sink = GST_SHOUT2SEND (basesink);
+
+  if (sink->conn) {
+    if (sink->connected)
+      shout_close (sink->conn);
+    shout_free (sink->conn);
+    sink->conn = NULL;
+  }
+
+  if (sink->songmetadata) {
+    g_free (sink->songmetadata);
+    sink->songmetadata = NULL;
+  }
+
+  sink->connected = FALSE;
+  sink->format = -1;
+
+  return TRUE;
+}
+
+static gboolean
+gst_shout2send_unlock (GstBaseSink * basesink)
+{
+  GstShout2send *sink;
+
+  sink = GST_SHOUT2SEND (basesink);
+
+  GST_DEBUG_OBJECT (basesink, "unlock");
+  gst_poll_set_flushing (sink->timer, TRUE);
+
+  return TRUE;
+}
+
+static gboolean
+gst_shout2send_unlock_stop (GstBaseSink * basesink)
+{
+  GstShout2send *sink;
+
+  sink = GST_SHOUT2SEND (basesink);
+
+  GST_DEBUG_OBJECT (basesink, "unlock_stop");
+  gst_poll_set_flushing (sink->timer, FALSE);
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_shout2send_render (GstBaseSink * basesink, GstBuffer * buf)
+{
+  GstShout2send *sink;
+  glong ret;
+  gint delay;
+  GstFlowReturn fret = GST_FLOW_OK;
+  GstMapInfo map;
+  GstClockTime now;
+  ssize_t queuelen;
+
+  sink = GST_SHOUT2SEND (basesink);
+
+  /* we connect here because we need to know the format before we can set up
+   * the connection, which we don't know yet in _start(), and also because we
+   * don't want to block the application thread */
+  if (!sink->connected) {
+    fret = gst_shout2send_connect (sink);
+    if (fret != GST_FLOW_OK)
+      goto done;
+  }
+
+  delay = shout_delay (sink->conn);
+
+  if (delay > 0) {
+    GST_LOG_OBJECT (sink, "waiting %d msec", delay);
+    if (gst_poll_wait (sink->timer, GST_MSECOND * delay) == -1) {
+      GST_LOG_OBJECT (sink, "unlocked");
+
+      fret = gst_base_sink_wait_preroll (basesink);
+      if (fret != GST_FLOW_OK)
+        goto done;
+    }
+  } else {
+    GST_LOG_OBJECT (sink, "we're %d msec late", -delay);
+  }
+
+  /* accumulate how much data have actually been sent
+   * to the network since the last call to shout_send() */
+  queuelen = shout_queuelen (sink->conn);
+  if (sink->prev_queuelen > 0)
+    sink->data_sent += sink->prev_queuelen - queuelen;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  /* add map.size instead of re-reading the queue length because
+   * the data may actually be sent immediately */
+  sink->prev_queuelen = queuelen + map.size;
+
+  GST_LOG_OBJECT (sink, "sending %u bytes of data, queue length now is %"
+      G_GUINT64_FORMAT, (guint) map.size, sink->prev_queuelen);
+
+  ret = shout_send (sink->conn, map.data, map.size);
+
+  gst_buffer_unmap (buf, &map);
+  if (ret != SHOUTERR_SUCCESS)
+    goto send_error;
+
+  now = gst_util_get_timestamp ();
+  if (now - sink->datasent_reset_ts >= 500 * GST_MSECOND) {
+    guint64 send_rate;
+
+    send_rate = gst_util_uint64_scale (sink->data_sent, GST_SECOND,
+        now - sink->datasent_reset_ts);
+
+    if (send_rate == 0 && !sink->stalled) {
+      sink->stalled = TRUE;
+      sink->stalled_ts = now;
+    } else if (send_rate > 0 && sink->stalled) {
+      sink->stalled = FALSE;
+    }
+
+    sink->data_sent = 0;
+    sink->datasent_reset_ts = now;
+
+    GST_DEBUG_OBJECT (sink, "sending rate is %" G_GUINT64_FORMAT " bps, "
+        "stalled %d, stalled_ts %" GST_TIME_FORMAT, send_rate, sink->stalled,
+        GST_TIME_ARGS (sink->stalled_ts));
+
+    if (sink->stalled && now - sink->stalled_ts >= sink->timeout * GST_MSECOND) {
+      GST_WARNING_OBJECT (sink, "network send queue is stalled for too long");
+      goto network_error;
+    }
+  }
+
+done:
+
+  return fret;
+
+/* ERRORS */
+send_error:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL),
+        ("shout_send() failed: %s", shout_get_error (sink->conn)));
+    g_signal_emit (sink, gst_shout2send_signals[SIGNAL_CONNECTION_PROBLEM], 0,
+        shout_get_errno (sink->conn));
+    return GST_FLOW_ERROR;
+  }
+
+network_error:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL),
+        ("network timeout reached"));
+    g_signal_emit (sink, gst_shout2send_signals[SIGNAL_CONNECTION_PROBLEM], 0,
+        SHOUTERR_BUSY);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static void
+gst_shout2send_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstShout2send *shout2send;
+
+  shout2send = GST_SHOUT2SEND (object);
+  switch (prop_id) {
+
+    case ARG_IP:
+      g_free (shout2send->ip);
+      shout2send->ip = g_strdup (g_value_get_string (value));
+      break;
+    case ARG_PORT:
+      shout2send->port = g_value_get_int (value);
+      break;
+    case ARG_PASSWORD:
+      g_free (shout2send->password);
+      shout2send->password = g_strdup (g_value_get_string (value));
+      break;
+    case ARG_USERNAME:
+      g_free (shout2send->username);
+      shout2send->username = g_strdup (g_value_get_string (value));
+      break;
+    case ARG_PUBLIC:
+      shout2send->ispublic = g_value_get_boolean (value);
+      break;
+    case ARG_STREAMNAME:       /* Name of the stream */
+      g_free (shout2send->streamname);
+      shout2send->streamname = g_strdup (g_value_get_string (value));
+      break;
+    case ARG_DESCRIPTION:      /* Description of the stream */
+      g_free (shout2send->description);
+      shout2send->description = g_strdup (g_value_get_string (value));
+      break;
+    case ARG_GENRE:            /* Genre of the stream */
+      g_free (shout2send->genre);
+      shout2send->genre = g_strdup (g_value_get_string (value));
+      break;
+    case ARG_PROTOCOL:         /* protocol to connect with */
+      shout2send->protocol = g_value_get_enum (value);
+      break;
+    case ARG_MOUNT:            /* mountpoint of stream (icecast only) */
+      g_free (shout2send->mount);
+      shout2send->mount = g_strdup (g_value_get_string (value));
+      break;
+    case ARG_URL:              /* the stream's homepage URL */
+      g_free (shout2send->url);
+      shout2send->url = g_strdup (g_value_get_string (value));
+      break;
+    case ARG_TIMEOUT:
+      shout2send->timeout = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_shout2send_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstShout2send *shout2send;
+
+  shout2send = GST_SHOUT2SEND (object);
+  switch (prop_id) {
+
+    case ARG_IP:
+      g_value_set_string (value, shout2send->ip);
+      break;
+    case ARG_PORT:
+      g_value_set_int (value, shout2send->port);
+      break;
+    case ARG_PASSWORD:
+      g_value_set_string (value, shout2send->password);
+      break;
+    case ARG_USERNAME:
+      g_value_set_string (value, shout2send->username);
+      break;
+    case ARG_PUBLIC:
+      g_value_set_boolean (value, shout2send->ispublic);
+      break;
+    case ARG_STREAMNAME:       /* Name of the stream */
+      g_value_set_string (value, shout2send->streamname);
+      break;
+    case ARG_DESCRIPTION:      /* Description of the stream */
+      g_value_set_string (value, shout2send->description);
+      break;
+    case ARG_GENRE:            /* Genre of the stream */
+      g_value_set_string (value, shout2send->genre);
+      break;
+    case ARG_PROTOCOL:         /* protocol to connect with */
+      g_value_set_enum (value, shout2send->protocol);
+      break;
+    case ARG_MOUNT:            /* mountpoint of stream (icecast only) */
+      g_value_set_string (value, shout2send->mount);
+      break;
+    case ARG_URL:              /* the stream's homepage URL */
+      g_value_set_string (value, shout2send->url);
+      break;
+    case ARG_TIMEOUT:
+      g_value_set_uint (value, shout2send->timeout);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_shout2send_setcaps (GstBaseSink * basesink, GstCaps * caps)
+{
+  const gchar *mimetype;
+  GstShout2send *shout2send;
+  gboolean ret = TRUE;
+
+  shout2send = GST_SHOUT2SEND (basesink);
+
+  mimetype = gst_structure_get_name (gst_caps_get_structure (caps, 0));
+
+  GST_DEBUG_OBJECT (shout2send, "mimetype of caps given is: %s", mimetype);
+
+  if (!strcmp (mimetype, "audio/mpeg")) {
+    shout2send->format = SHOUT_FORMAT_MP3;
+  } else if (g_str_has_suffix (mimetype, "/ogg")) {
+    shout2send->format = SHOUT_FORMAT_OGG;
+#ifdef SHOUT_FORMAT_WEBM
+  } else if (g_str_has_suffix (mimetype, "/webm")) {
+    shout2send->format = SHOUT_FORMAT_WEBM;
+#endif
+  } else {
+    ret = FALSE;
+  }
+
+  return ret;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+#ifdef ENABLE_NLS
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif /* ENABLE_NLS */
+
+  return gst_element_register (plugin, "shout2send", GST_RANK_NONE,
+      GST_TYPE_SHOUT2SEND);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    shout2,
+    "Sends data to an icecast server using libshout2",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/shout2/gstshout2.h b/ext/shout2/gstshout2.h
new file mode 100644
index 0000000..4087166
--- /dev/null
+++ b/ext/shout2/gstshout2.h
@@ -0,0 +1,104 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_SHOUT2SEND_H__
+#define __GST_SHOUT2SEND_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesink.h>
+#include <shout/shout.h>
+
+G_BEGIN_DECLS
+
+  /* Protocol type enum */
+typedef enum {
+  SHOUT2SEND_PROTOCOL_XAUDIOCAST = 1,
+  SHOUT2SEND_PROTOCOL_ICY,
+  SHOUT2SEND_PROTOCOL_HTTP
+} GstShout2SendProtocol;
+
+
+/* Definition of structure storing data for this element. */
+typedef struct _GstShout2send GstShout2send;
+struct _GstShout2send {
+  GstBaseSink parent;
+
+  GstShout2SendProtocol protocol;
+
+  GstPoll *timer;
+
+  shout_t *conn;
+
+  guint64 prev_queuelen;
+  guint64 data_sent;
+  GstClockTime datasent_reset_ts;
+  gboolean stalled;
+  GstClockTime stalled_ts;
+
+  gchar *ip;
+  guint port;
+  gchar *password;
+  gchar *username;
+  gchar *streamname;
+  gchar *description;
+  gchar *genre;
+  gchar *mount;
+  gchar *url;
+  gboolean connected;
+  gboolean ispublic;
+  gchar *songmetadata;
+  gchar *songartist;
+  gchar *songtitle;
+  gint  format;
+  guint timeout;
+
+  GstTagList* tags;
+};
+
+
+
+/* Standard definition defining a class for this element. */
+typedef struct _GstShout2sendClass GstShout2sendClass;
+struct _GstShout2sendClass {
+  GstBaseSinkClass parent_class;
+
+  /* signal callbacks */
+  void (*connection_problem) (GstElement *element,guint errno);
+};
+
+/* Standard macros for defining types for this element.  */
+#define GST_TYPE_SHOUT2SEND \
+  (gst_shout2send_get_type())
+#define GST_SHOUT2SEND(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SHOUT2SEND,GstShout2send))
+#define GST_SHOUT2SEND_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SHOUT2SEND,GstShout2sendClass))
+#define GST_IS_SHOUT2SEND(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SHOUT2SEND))
+#define GST_IS_SHOUT2SEND_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SHOUT2SEND))
+
+/* Standard function returning type information. */
+GType gst_shout2send_get_type(void);
+
+
+G_END_DECLS
+
+#endif /* __GST_SHOUT2SEND_H__ */
diff --git a/ext/shout2/meson.build b/ext/shout2/meson.build
new file mode 100644
index 0000000..ae77958
--- /dev/null
+++ b/ext/shout2/meson.build
@@ -0,0 +1,14 @@
+shout2_sources = ['gstshout2.c']
+
+shout2_dep = dependency('shout', version : '>= 2.0', required : false)
+
+if shout2_dep.found()
+  gstshout2 = library('gstshout2',
+    shout2_sources,
+    c_args : gst_plugins_good_args,
+    include_directories : [configinc, libsinc],
+    dependencies : [gstbase_dep, shout2_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/ext/soup/Makefile.am b/ext/soup/Makefile.am
new file mode 100644
index 0000000..7751594
--- /dev/null
+++ b/ext/soup/Makefile.am
@@ -0,0 +1,12 @@
+plugin_LTLIBRARIES = libgstsoup.la
+
+libgstsoup_la_SOURCES = gstsouphttpsrc.c gstsouphttpclientsink.c gstsouputils.c gstsoup.c
+
+libgstsoup_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS) $(SOUP_CFLAGS) \
+	-DSOUP_VERSION_MIN_REQUIRED=SOUP_VERSION_2_48 \
+	-DSOUP_VERSION_MAX_ALLOWED=SOUP_DEPRECATED_IN_2_48
+libgstsoup_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgsttag-@GST_API_VERSION@ $(GST_BASE_LIBS) $(SOUP_LIBS)
+libgstsoup_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstsouphttpsrc.h gstsouphttpclientsink.h gstsouputils.h
diff --git a/ext/soup/gstsoup.c b/ext/soup/gstsoup.c
new file mode 100644
index 0000000..3be491d
--- /dev/null
+++ b/ext/soup/gstsoup.c
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) 2007-2008 Wouter Cloetens <wouter@mind.be>
+ *
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst-i18n-plugin.h>
+
+#include "gstsouphttpsrc.h"
+#include "gstsouphttpclientsink.h"
+#include "gstsouputils.h"
+
+GST_DEBUG_CATEGORY (soup_utils_debug);
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+#ifdef ENABLE_NLS
+  GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
+      LOCALEDIR);
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+
+  /* see https://bugzilla.gnome.org/show_bug.cgi?id=674885 */
+  g_type_ensure (G_TYPE_SOCKET);
+  g_type_ensure (G_TYPE_SOCKET_ADDRESS);
+  g_type_ensure (G_TYPE_SOCKET_SERVICE);
+  g_type_ensure (G_TYPE_SOCKET_FAMILY);
+  g_type_ensure (G_TYPE_SOCKET_CLIENT);
+  g_type_ensure (G_TYPE_RESOLVER);
+  g_type_ensure (G_TYPE_PROXY_RESOLVER);
+  g_type_ensure (G_TYPE_PROXY_ADDRESS);
+  g_type_ensure (G_TYPE_TLS_CERTIFICATE);
+  g_type_ensure (G_TYPE_TLS_CONNECTION);
+  g_type_ensure (G_TYPE_TLS_DATABASE);
+  g_type_ensure (G_TYPE_TLS_INTERACTION);
+
+  gst_element_register (plugin, "souphttpsrc", GST_RANK_PRIMARY,
+      GST_TYPE_SOUP_HTTP_SRC);
+  gst_element_register (plugin, "souphttpclientsink", GST_RANK_NONE,
+      GST_TYPE_SOUP_HTTP_CLIENT_SINK);
+  GST_DEBUG_CATEGORY_INIT (soup_utils_debug, "souputils", 0, "Soup utils");
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    soup,
+    "libsoup HTTP client src/sink",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/soup/gstsouphttpclientsink.c b/ext/soup/gstsouphttpclientsink.c
new file mode 100644
index 0000000..c812488
--- /dev/null
+++ b/ext/soup/gstsouphttpclientsink.c
@@ -0,0 +1,921 @@
+/* GStreamer
+ * Copyright (C) 2011 David Schleef <ds@entropywave.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
+ * Boston, MA 02110-1335, USA.
+ */
+/**
+ * SECTION:element-gstsouphttpclientsink
+ *
+ * The souphttpclientsink element sends pipeline data to an HTTP server
+ * using HTTP PUT commands.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc num-buffers=300 ! theoraenc ! oggmux !
+ *   souphttpclientsink location=http://server/filename.ogv
+ * ]|
+ * 
+ * This example encodes 10 seconds of video and sends it to the HTTP
+ * server "server" using HTTP PUT commands.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesink.h>
+#include "gstsouphttpclientsink.h"
+#include "gstsouputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (souphttpclientsink_dbg);
+#define GST_CAT_DEFAULT souphttpclientsink_dbg
+
+/* prototypes */
+
+
+static void gst_soup_http_client_sink_set_property (GObject * object,
+    guint property_id, const GValue * value, GParamSpec * pspec);
+static void gst_soup_http_client_sink_get_property (GObject * object,
+    guint property_id, GValue * value, GParamSpec * pspec);
+static void gst_soup_http_client_sink_dispose (GObject * object);
+static void gst_soup_http_client_sink_finalize (GObject * object);
+
+static gboolean gst_soup_http_client_sink_set_caps (GstBaseSink * sink,
+    GstCaps * caps);
+static void gst_soup_http_client_sink_get_times (GstBaseSink * sink,
+    GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
+static gboolean gst_soup_http_client_sink_start (GstBaseSink * sink);
+static gboolean gst_soup_http_client_sink_stop (GstBaseSink * sink);
+static gboolean gst_soup_http_client_sink_unlock (GstBaseSink * sink);
+static gboolean gst_soup_http_client_sink_event (GstBaseSink * sink,
+    GstEvent * event);
+static GstFlowReturn gst_soup_http_client_sink_preroll (GstBaseSink * sink,
+    GstBuffer * buffer);
+static GstFlowReturn gst_soup_http_client_sink_render (GstBaseSink * sink,
+    GstBuffer * buffer);
+
+static void gst_soup_http_client_sink_reset (GstSoupHttpClientSink *
+    souphttpsink);
+static void authenticate (SoupSession * session, SoupMessage * msg,
+    SoupAuth * auth, gboolean retrying, gpointer user_data);
+static void callback (SoupSession * session, SoupMessage * msg,
+    gpointer user_data);
+static gboolean gst_soup_http_client_sink_set_proxy (GstSoupHttpClientSink *
+    souphttpsink, const gchar * uri);
+
+enum
+{
+  PROP_0,
+  PROP_LOCATION,
+  PROP_USER_AGENT,
+  PROP_AUTOMATIC_REDIRECT,
+  PROP_PROXY,
+  PROP_USER_ID,
+  PROP_USER_PW,
+  PROP_PROXY_ID,
+  PROP_PROXY_PW,
+  PROP_COOKIES,
+  PROP_SESSION,
+  PROP_SOUP_LOG_LEVEL,
+  PROP_RETRY_DELAY,
+  PROP_RETRIES
+};
+
+#define DEFAULT_USER_AGENT           "GStreamer souphttpclientsink "
+#define DEFAULT_SOUP_LOG_LEVEL       SOUP_LOGGER_LOG_NONE
+
+/* pad templates */
+
+static GstStaticPadTemplate gst_soup_http_client_sink_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+
+/* class initialization */
+
+#define gst_soup_http_client_sink_parent_class parent_class
+G_DEFINE_TYPE (GstSoupHttpClientSink, gst_soup_http_client_sink,
+    GST_TYPE_BASE_SINK);
+
+static void
+gst_soup_http_client_sink_class_init (GstSoupHttpClientSinkClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  GstBaseSinkClass *base_sink_class = GST_BASE_SINK_CLASS (klass);
+
+  gobject_class->set_property = gst_soup_http_client_sink_set_property;
+  gobject_class->get_property = gst_soup_http_client_sink_get_property;
+  gobject_class->dispose = gst_soup_http_client_sink_dispose;
+  gobject_class->finalize = gst_soup_http_client_sink_finalize;
+
+  g_object_class_install_property (gobject_class,
+      PROP_LOCATION,
+      g_param_spec_string ("location", "Location",
+          "URI to send to", "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_USER_AGENT,
+      g_param_spec_string ("user-agent", "User-Agent",
+          "Value of the User-Agent HTTP request header field",
+          DEFAULT_USER_AGENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_AUTOMATIC_REDIRECT,
+      g_param_spec_boolean ("automatic-redirect", "automatic-redirect",
+          "Automatically follow HTTP redirects (HTTP Status Code 3xx)",
+          TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_PROXY,
+      g_param_spec_string ("proxy", "Proxy",
+          "HTTP proxy server URI", "",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_USER_ID,
+      g_param_spec_string ("user-id", "user-id",
+          "user id for authentication", "",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_USER_PW,
+      g_param_spec_string ("user-pw", "user-pw",
+          "user password for authentication", "",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_PROXY_ID,
+      g_param_spec_string ("proxy-id", "proxy-id",
+          "user id for proxy authentication", "",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_PROXY_PW,
+      g_param_spec_string ("proxy-pw", "proxy-pw",
+          "user password for proxy authentication", "",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_SESSION,
+      g_param_spec_object ("session", "session",
+          "SoupSession object to use for communication",
+          SOUP_TYPE_SESSION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_COOKIES,
+      g_param_spec_boxed ("cookies", "Cookies", "HTTP request cookies",
+          G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_RETRY_DELAY,
+      g_param_spec_int ("retry-delay", "Retry Delay",
+          "Delay in seconds between retries after a failure", 1, G_MAXINT, 5,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_RETRIES,
+      g_param_spec_int ("retries", "Retries",
+          "Maximum number of retries, zero to disable, -1 to retry forever",
+          -1, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+   * GstSoupHttpClientSink::http-log-level:
+   *
+   * If set and > 0, captures and dumps HTTP session data as
+   * log messages if log level >= GST_LEVEL_TRACE
+   *
+   * Since: 1.4
+   */
+  g_object_class_install_property (gobject_class, PROP_SOUP_LOG_LEVEL,
+      g_param_spec_enum ("http-log-level", "HTTP log level",
+          "Set log level for soup's HTTP session log",
+          SOUP_TYPE_LOGGER_LOG_LEVEL, DEFAULT_SOUP_LOG_LEVEL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_soup_http_client_sink_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "HTTP client sink",
+      "Generic", "Sends streams to HTTP server via PUT",
+      "David Schleef <ds@entropywave.com>");
+
+  base_sink_class->set_caps =
+      GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_set_caps);
+  if (0)
+    base_sink_class->get_times =
+        GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_get_times);
+  base_sink_class->start = GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_start);
+  base_sink_class->stop = GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_stop);
+  base_sink_class->unlock =
+      GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_unlock);
+  base_sink_class->event = GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_event);
+  if (0)
+    base_sink_class->preroll =
+        GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_preroll);
+  base_sink_class->render =
+      GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_render);
+
+  GST_DEBUG_CATEGORY_INIT (souphttpclientsink_dbg, "souphttpclientsink", 0,
+      "souphttpclientsink element");
+
+}
+
+static void
+gst_soup_http_client_sink_init (GstSoupHttpClientSink * souphttpsink)
+{
+  const char *proxy;
+
+  g_mutex_init (&souphttpsink->mutex);
+  g_cond_init (&souphttpsink->cond);
+
+  souphttpsink->location = NULL;
+  souphttpsink->automatic_redirect = TRUE;
+  souphttpsink->user_agent = g_strdup (DEFAULT_USER_AGENT);
+  souphttpsink->user_id = NULL;
+  souphttpsink->user_pw = NULL;
+  souphttpsink->proxy_id = NULL;
+  souphttpsink->proxy_pw = NULL;
+  souphttpsink->prop_session = NULL;
+  souphttpsink->timeout = 1;
+  souphttpsink->log_level = DEFAULT_SOUP_LOG_LEVEL;
+  souphttpsink->retry_delay = 5;
+  souphttpsink->retries = 0;
+  proxy = g_getenv ("http_proxy");
+  if (proxy && !gst_soup_http_client_sink_set_proxy (souphttpsink, proxy)) {
+    GST_WARNING_OBJECT (souphttpsink,
+        "The proxy in the http_proxy env var (\"%s\") cannot be parsed.",
+        proxy);
+  }
+
+  gst_soup_http_client_sink_reset (souphttpsink);
+}
+
+static void
+gst_soup_http_client_sink_reset (GstSoupHttpClientSink * souphttpsink)
+{
+  g_list_free_full (souphttpsink->queued_buffers,
+      (GDestroyNotify) gst_buffer_unref);
+  souphttpsink->queued_buffers = NULL;
+  g_free (souphttpsink->reason_phrase);
+  souphttpsink->reason_phrase = NULL;
+  souphttpsink->status_code = 0;
+  souphttpsink->offset = 0;
+  souphttpsink->failures = 0;
+
+  g_list_free_full (souphttpsink->streamheader_buffers,
+      (GDestroyNotify) gst_buffer_unref);
+  souphttpsink->streamheader_buffers = NULL;
+  g_list_free_full (souphttpsink->sent_buffers,
+      (GDestroyNotify) gst_buffer_unref);
+  souphttpsink->sent_buffers = NULL;
+}
+
+static gboolean
+gst_soup_http_client_sink_set_proxy (GstSoupHttpClientSink * souphttpsink,
+    const gchar * uri)
+{
+  if (souphttpsink->proxy) {
+    soup_uri_free (souphttpsink->proxy);
+    souphttpsink->proxy = NULL;
+  }
+  if (g_str_has_prefix (uri, "http://")) {
+    souphttpsink->proxy = soup_uri_new (uri);
+  } else {
+    gchar *new_uri = g_strconcat ("http://", uri, NULL);
+
+    souphttpsink->proxy = soup_uri_new (new_uri);
+    g_free (new_uri);
+  }
+
+  return TRUE;
+}
+
+void
+gst_soup_http_client_sink_set_property (GObject * object, guint property_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (object);
+
+  g_mutex_lock (&souphttpsink->mutex);
+  switch (property_id) {
+    case PROP_SESSION:
+      if (souphttpsink->prop_session) {
+        g_object_unref (souphttpsink->prop_session);
+      }
+      souphttpsink->prop_session = g_value_dup_object (value);
+      break;
+    case PROP_LOCATION:
+      g_free (souphttpsink->location);
+      souphttpsink->location = g_value_dup_string (value);
+      souphttpsink->offset = 0;
+      if ((souphttpsink->location == NULL)
+          || !gst_uri_is_valid (souphttpsink->location)) {
+        GST_WARNING_OBJECT (souphttpsink,
+            "The location (\"%s\") set, is not a valid uri.",
+            souphttpsink->location);
+        g_free (souphttpsink->location);
+        souphttpsink->location = NULL;
+      }
+      break;
+    case PROP_USER_AGENT:
+      g_free (souphttpsink->user_agent);
+      souphttpsink->user_agent = g_value_dup_string (value);
+      break;
+    case PROP_AUTOMATIC_REDIRECT:
+      souphttpsink->automatic_redirect = g_value_get_boolean (value);
+      break;
+    case PROP_USER_ID:
+      g_free (souphttpsink->user_id);
+      souphttpsink->user_id = g_value_dup_string (value);
+      break;
+    case PROP_USER_PW:
+      g_free (souphttpsink->user_pw);
+      souphttpsink->user_pw = g_value_dup_string (value);
+      break;
+    case PROP_PROXY_ID:
+      g_free (souphttpsink->proxy_id);
+      souphttpsink->proxy_id = g_value_dup_string (value);
+      break;
+    case PROP_PROXY_PW:
+      g_free (souphttpsink->proxy_pw);
+      souphttpsink->proxy_pw = g_value_dup_string (value);
+      break;
+    case PROP_PROXY:
+    {
+      const gchar *proxy;
+
+      proxy = g_value_get_string (value);
+
+      if (proxy == NULL) {
+        GST_WARNING ("proxy property cannot be NULL");
+        goto done;
+      }
+      if (!gst_soup_http_client_sink_set_proxy (souphttpsink, proxy)) {
+        GST_WARNING ("badly formatted proxy URI");
+        goto done;
+      }
+      break;
+    }
+    case PROP_COOKIES:
+      g_strfreev (souphttpsink->cookies);
+      souphttpsink->cookies = g_strdupv (g_value_get_boxed (value));
+      break;
+    case PROP_SOUP_LOG_LEVEL:
+      souphttpsink->log_level = g_value_get_enum (value);
+      break;
+    case PROP_RETRY_DELAY:
+      souphttpsink->retry_delay = g_value_get_int (value);
+      break;
+    case PROP_RETRIES:
+      souphttpsink->retries = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+done:
+  g_mutex_unlock (&souphttpsink->mutex);
+}
+
+void
+gst_soup_http_client_sink_get_property (GObject * object, guint property_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (object);
+
+  switch (property_id) {
+    case PROP_SESSION:
+      g_value_set_object (value, souphttpsink->prop_session);
+      break;
+    case PROP_LOCATION:
+      g_value_set_string (value, souphttpsink->location);
+      break;
+    case PROP_AUTOMATIC_REDIRECT:
+      g_value_set_boolean (value, souphttpsink->automatic_redirect);
+      break;
+    case PROP_USER_AGENT:
+      g_value_set_string (value, souphttpsink->user_agent);
+      break;
+    case PROP_USER_ID:
+      g_value_set_string (value, souphttpsink->user_id);
+      break;
+    case PROP_USER_PW:
+      g_value_set_string (value, souphttpsink->user_pw);
+      break;
+    case PROP_PROXY_ID:
+      g_value_set_string (value, souphttpsink->proxy_id);
+      break;
+    case PROP_PROXY_PW:
+      g_value_set_string (value, souphttpsink->proxy_pw);
+      break;
+    case PROP_PROXY:
+      if (souphttpsink->proxy == NULL)
+        g_value_set_static_string (value, "");
+      else {
+        char *proxy = soup_uri_to_string (souphttpsink->proxy, FALSE);
+
+        g_value_set_string (value, proxy);
+        g_free (proxy);
+      }
+      break;
+    case PROP_COOKIES:
+      g_value_set_boxed (value, g_strdupv (souphttpsink->cookies));
+      break;
+    case PROP_SOUP_LOG_LEVEL:
+      g_value_set_enum (value, souphttpsink->log_level);
+      break;
+    case PROP_RETRY_DELAY:
+      g_value_set_int (value, souphttpsink->retry_delay);
+      break;
+    case PROP_RETRIES:
+      g_value_set_int (value, souphttpsink->retries);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+void
+gst_soup_http_client_sink_dispose (GObject * object)
+{
+  GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (object);
+
+  /* clean up as possible.  may be called multiple times */
+  if (souphttpsink->prop_session)
+    g_object_unref (souphttpsink->prop_session);
+  souphttpsink->prop_session = NULL;
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+void
+gst_soup_http_client_sink_finalize (GObject * object)
+{
+  GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (object);
+
+  /* clean up object here */
+
+  g_free (souphttpsink->user_agent);
+  g_free (souphttpsink->user_id);
+  g_free (souphttpsink->user_pw);
+  g_free (souphttpsink->proxy_id);
+  g_free (souphttpsink->proxy_pw);
+  if (souphttpsink->proxy)
+    soup_uri_free (souphttpsink->proxy);
+  g_free (souphttpsink->location);
+  g_strfreev (souphttpsink->cookies);
+
+  g_cond_clear (&souphttpsink->cond);
+  g_mutex_clear (&souphttpsink->mutex);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+
+static gboolean
+gst_soup_http_client_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
+{
+  GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (sink);
+  GstStructure *structure;
+  const GValue *value_array;
+  int i, n;
+
+  GST_DEBUG_OBJECT (souphttpsink, "new stream headers set");
+  structure = gst_caps_get_structure (caps, 0);
+  value_array = gst_structure_get_value (structure, "streamheader");
+  if (value_array) {
+    g_list_free_full (souphttpsink->streamheader_buffers,
+        (GDestroyNotify) gst_buffer_unref);
+    souphttpsink->streamheader_buffers = NULL;
+
+    n = gst_value_array_get_size (value_array);
+    for (i = 0; i < n; i++) {
+      const GValue *value;
+      GstBuffer *buffer;
+      value = gst_value_array_get_value (value_array, i);
+      buffer = GST_BUFFER (gst_value_get_buffer (value));
+      souphttpsink->streamheader_buffers =
+          g_list_append (souphttpsink->streamheader_buffers,
+          gst_buffer_ref (buffer));
+    }
+  }
+
+  return TRUE;
+}
+
+static void
+gst_soup_http_client_sink_get_times (GstBaseSink * sink, GstBuffer * buffer,
+    GstClockTime * start, GstClockTime * end)
+{
+
+}
+
+static gboolean
+thread_ready_idle_cb (gpointer data)
+{
+  GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (data);
+
+  GST_LOG_OBJECT (souphttpsink, "thread ready");
+
+  g_mutex_lock (&souphttpsink->mutex);
+  g_cond_signal (&souphttpsink->cond);
+  g_mutex_unlock (&souphttpsink->mutex);
+
+  return FALSE;                 /* only run once */
+}
+
+static gpointer
+thread_func (gpointer ptr)
+{
+  GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (ptr);
+
+  GST_DEBUG ("thread start");
+
+  g_main_loop_run (souphttpsink->loop);
+
+  GST_DEBUG ("thread quit");
+
+  return NULL;
+}
+
+static gboolean
+gst_soup_http_client_sink_start (GstBaseSink * sink)
+{
+  GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (sink);
+
+  if (souphttpsink->prop_session) {
+    souphttpsink->session = souphttpsink->prop_session;
+  } else {
+    GSource *source;
+    GError *error = NULL;
+
+    souphttpsink->context = g_main_context_new ();
+
+    /* set up idle source to signal when the main loop is running and
+     * it's safe for ::stop() to call g_main_loop_quit() */
+    source = g_idle_source_new ();
+    g_source_set_callback (source, thread_ready_idle_cb, sink, NULL);
+    g_source_attach (source, souphttpsink->context);
+    g_source_unref (source);
+
+    souphttpsink->loop = g_main_loop_new (souphttpsink->context, TRUE);
+
+    g_mutex_lock (&souphttpsink->mutex);
+
+    souphttpsink->thread = g_thread_try_new ("souphttpclientsink-thread",
+        thread_func, souphttpsink, &error);
+
+    if (error != NULL) {
+      GST_DEBUG_OBJECT (souphttpsink, "failed to start thread, %s",
+          error->message);
+      g_error_free (error);
+      g_mutex_unlock (&souphttpsink->mutex);
+      return FALSE;
+    }
+
+    GST_LOG_OBJECT (souphttpsink, "waiting for main loop thread to start up");
+    g_cond_wait (&souphttpsink->cond, &souphttpsink->mutex);
+    g_mutex_unlock (&souphttpsink->mutex);
+    GST_LOG_OBJECT (souphttpsink, "main loop thread running");
+
+    if (souphttpsink->proxy == NULL) {
+      souphttpsink->session =
+          soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
+          souphttpsink->context, SOUP_SESSION_USER_AGENT,
+          souphttpsink->user_agent, SOUP_SESSION_TIMEOUT, souphttpsink->timeout,
+          SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_DEFAULT,
+          NULL);
+    } else {
+      souphttpsink->session =
+          soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
+          souphttpsink->context, SOUP_SESSION_USER_AGENT,
+          souphttpsink->user_agent, SOUP_SESSION_TIMEOUT, souphttpsink->timeout,
+          SOUP_SESSION_PROXY_URI, souphttpsink->proxy, NULL);
+    }
+
+    g_signal_connect (souphttpsink->session, "authenticate",
+        G_CALLBACK (authenticate), souphttpsink);
+  }
+
+  /* Set up logging */
+  gst_soup_util_log_setup (souphttpsink->session, souphttpsink->log_level,
+      GST_ELEMENT (souphttpsink));
+
+  return TRUE;
+}
+
+static gboolean
+gst_soup_http_client_sink_stop (GstBaseSink * sink)
+{
+  GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (sink);
+
+  GST_DEBUG ("stop");
+
+  if (souphttpsink->prop_session == NULL) {
+    soup_session_abort (souphttpsink->session);
+    g_object_unref (souphttpsink->session);
+  }
+
+  g_mutex_lock (&souphttpsink->mutex);
+  if (souphttpsink->timer) {
+    g_source_destroy (souphttpsink->timer);
+    g_source_unref (souphttpsink->timer);
+    souphttpsink->timer = NULL;
+  }
+  g_mutex_unlock (&souphttpsink->mutex);
+
+  if (souphttpsink->loop) {
+    g_main_loop_quit (souphttpsink->loop);
+    g_mutex_lock (&souphttpsink->mutex);
+    g_cond_signal (&souphttpsink->cond);
+    g_mutex_unlock (&souphttpsink->mutex);
+    g_thread_join (souphttpsink->thread);
+    g_main_loop_unref (souphttpsink->loop);
+    souphttpsink->loop = NULL;
+  }
+  if (souphttpsink->context) {
+    g_main_context_unref (souphttpsink->context);
+    souphttpsink->context = NULL;
+  }
+
+  gst_soup_http_client_sink_reset (souphttpsink);
+
+  return TRUE;
+}
+
+static gboolean
+gst_soup_http_client_sink_unlock (GstBaseSink * sink)
+{
+  GST_DEBUG ("unlock");
+
+  return TRUE;
+}
+
+static gboolean
+gst_soup_http_client_sink_event (GstBaseSink * sink, GstEvent * event)
+{
+  GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (sink);
+
+  GST_DEBUG_OBJECT (souphttpsink, "event");
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
+    GST_DEBUG_OBJECT (souphttpsink, "got eos");
+    g_mutex_lock (&souphttpsink->mutex);
+    while (souphttpsink->message) {
+      GST_DEBUG_OBJECT (souphttpsink, "waiting");
+      g_cond_wait (&souphttpsink->cond, &souphttpsink->mutex);
+    }
+    g_mutex_unlock (&souphttpsink->mutex);
+    GST_DEBUG_OBJECT (souphttpsink, "finished eos");
+  }
+
+  return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
+}
+
+static GstFlowReturn
+gst_soup_http_client_sink_preroll (GstBaseSink * sink, GstBuffer * buffer)
+{
+  GST_DEBUG ("preroll");
+
+  return GST_FLOW_OK;
+}
+
+static void
+send_message_locked (GstSoupHttpClientSink * souphttpsink)
+{
+  GList *g;
+  guint64 n;
+
+  if (souphttpsink->queued_buffers == NULL || souphttpsink->message) {
+    return;
+  }
+
+  /* If the URI went away, drop all these buffers */
+  if (souphttpsink->location == NULL) {
+    GST_DEBUG_OBJECT (souphttpsink, "URI went away, dropping queued buffers");
+    g_list_free_full (souphttpsink->queued_buffers,
+        (GDestroyNotify) gst_buffer_unref);
+    souphttpsink->queued_buffers = NULL;
+    return;
+  }
+
+  souphttpsink->message = soup_message_new ("PUT", souphttpsink->location);
+  if (souphttpsink->message == NULL) {
+    GST_WARNING_OBJECT (souphttpsink,
+        "URI could not be parsed while creating message.");
+    g_list_free_full (souphttpsink->queued_buffers,
+        (GDestroyNotify) gst_buffer_unref);
+    souphttpsink->queued_buffers = NULL;
+    return;
+  }
+
+  soup_message_set_flags (souphttpsink->message,
+      (souphttpsink->automatic_redirect ? 0 : SOUP_MESSAGE_NO_REDIRECT));
+
+  if (souphttpsink->cookies) {
+    gchar **cookie;
+
+    for (cookie = souphttpsink->cookies; *cookie != NULL; cookie++) {
+      soup_message_headers_append (souphttpsink->message->request_headers,
+          "Cookie", *cookie);
+    }
+  }
+
+  n = 0;
+  if (souphttpsink->offset == 0) {
+    for (g = souphttpsink->streamheader_buffers; g; g = g_list_next (g)) {
+      GstBuffer *buffer = g->data;
+      GstMapInfo map;
+
+      GST_DEBUG_OBJECT (souphttpsink, "queueing stream headers");
+      gst_buffer_map (buffer, &map, GST_MAP_READ);
+      /* Stream headers are updated whenever ::set_caps is called, so there's
+       * no guarantees about their lifetime and we ask libsoup to copy them 
+       * into the message body with SOUP_MEMORY_COPY. */
+      soup_message_body_append (souphttpsink->message->request_body,
+          SOUP_MEMORY_COPY, map.data, map.size);
+      n += map.size;
+      gst_buffer_unmap (buffer, &map);
+    }
+  }
+
+  for (g = souphttpsink->queued_buffers; g; g = g_list_next (g)) {
+    GstBuffer *buffer = g->data;
+    if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_HEADER)) {
+      GstMapInfo map;
+
+      gst_buffer_map (buffer, &map, GST_MAP_READ);
+      /* Queued buffers are only freed in the next iteration of the mainloop
+       * after the message body has been written out, so we don't need libsoup
+       * to copy those while appending to the body. However, if the buffer is
+       * used elsewhere, it should be copied. Hence, SOUP_MEMORY_TEMPORARY. */
+      soup_message_body_append (souphttpsink->message->request_body,
+          SOUP_MEMORY_TEMPORARY, map.data, map.size);
+      n += map.size;
+      gst_buffer_unmap (buffer, &map);
+    }
+  }
+
+  if (souphttpsink->offset != 0) {
+    char *s;
+    s = g_strdup_printf ("bytes %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT "/*",
+        souphttpsink->offset, souphttpsink->offset + n - 1);
+    soup_message_headers_append (souphttpsink->message->request_headers,
+        "Content-Range", s);
+    g_free (s);
+  }
+
+  if (n == 0) {
+    GST_DEBUG_OBJECT (souphttpsink,
+        "total size of buffers queued is 0, freeing everything");
+    g_list_free_full (souphttpsink->queued_buffers,
+        (GDestroyNotify) gst_buffer_unref);
+    souphttpsink->queued_buffers = NULL;
+    g_object_unref (souphttpsink->message);
+    souphttpsink->message = NULL;
+    return;
+  }
+
+  souphttpsink->sent_buffers = souphttpsink->queued_buffers;
+  souphttpsink->queued_buffers = NULL;
+
+  GST_DEBUG_OBJECT (souphttpsink,
+      "queue message %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT,
+      souphttpsink->offset, n);
+  soup_session_queue_message (souphttpsink->session, souphttpsink->message,
+      callback, souphttpsink);
+
+  souphttpsink->offset += n;
+}
+
+static gboolean
+send_message (GstSoupHttpClientSink * souphttpsink)
+{
+  g_mutex_lock (&souphttpsink->mutex);
+  send_message_locked (souphttpsink);
+  if (souphttpsink->timer) {
+    g_source_destroy (souphttpsink->timer);
+    g_source_unref (souphttpsink->timer);
+    souphttpsink->timer = NULL;
+  }
+  g_mutex_unlock (&souphttpsink->mutex);
+
+  return FALSE;
+}
+
+static void
+callback (SoupSession * session, SoupMessage * msg, gpointer user_data)
+{
+  GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (user_data);
+
+  GST_DEBUG_OBJECT (souphttpsink, "callback status=%d %s",
+      msg->status_code, msg->reason_phrase);
+
+  g_mutex_lock (&souphttpsink->mutex);
+  g_cond_signal (&souphttpsink->cond);
+  souphttpsink->message = NULL;
+
+  if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+    souphttpsink->failures++;
+    if (souphttpsink->retries &&
+        (souphttpsink->retries < 0 ||
+            souphttpsink->retries >= souphttpsink->failures)) {
+      guint64 retry_delay;
+      const char *retry_after =
+          soup_message_headers_get_one (msg->response_headers,
+          "Retry-After");
+      if (retry_after) {
+        gchar *end = NULL;
+        retry_delay = g_ascii_strtoull (retry_after, &end, 10);
+        if (end || errno) {
+          retry_delay = souphttpsink->retry_delay;
+        } else {
+          retry_delay = MAX (retry_delay, souphttpsink->retry_delay);
+        }
+        GST_WARNING_OBJECT (souphttpsink, "Could not write to HTTP URI: "
+            "status: %d %s (retrying PUT after %" G_GINT64_FORMAT
+            " seconds with Retry-After: %s)", msg->status_code,
+            msg->reason_phrase, retry_delay, retry_after);
+      } else {
+        retry_delay = souphttpsink->retry_delay;
+        GST_WARNING_OBJECT (souphttpsink, "Could not write to HTTP URI: "
+            "status: %d %s (retrying PUT after %" G_GINT64_FORMAT
+            " seconds)", msg->status_code, msg->reason_phrase, retry_delay);
+      }
+      souphttpsink->timer = g_timeout_source_new_seconds (retry_delay);
+      g_source_set_callback (souphttpsink->timer, (GSourceFunc) (send_message),
+          souphttpsink, NULL);
+      g_source_attach (souphttpsink->timer, souphttpsink->context);
+    } else {
+      souphttpsink->status_code = msg->status_code;
+      souphttpsink->reason_phrase = g_strdup (msg->reason_phrase);
+    }
+    g_mutex_unlock (&souphttpsink->mutex);
+    return;
+  }
+
+  g_list_free_full (souphttpsink->sent_buffers,
+      (GDestroyNotify) gst_buffer_unref);
+  souphttpsink->sent_buffers = NULL;
+  souphttpsink->failures = 0;
+
+  send_message_locked (souphttpsink);
+  g_mutex_unlock (&souphttpsink->mutex);
+}
+
+static GstFlowReturn
+gst_soup_http_client_sink_render (GstBaseSink * sink, GstBuffer * buffer)
+{
+  GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (sink);
+  GSource *source;
+  gboolean wake;
+
+  if (souphttpsink->status_code != 0) {
+    GST_ELEMENT_ERROR (souphttpsink, RESOURCE, WRITE,
+        ("Could not write to HTTP URI"),
+        ("status: %d %s", souphttpsink->status_code,
+            souphttpsink->reason_phrase));
+    return GST_FLOW_ERROR;
+  }
+
+  g_mutex_lock (&souphttpsink->mutex);
+  if (souphttpsink->location != NULL) {
+    wake = (souphttpsink->queued_buffers == NULL);
+    souphttpsink->queued_buffers =
+        g_list_append (souphttpsink->queued_buffers, gst_buffer_ref (buffer));
+
+    if (wake) {
+      GST_DEBUG_OBJECT (souphttpsink, "setting callback for new buffers");
+      source = g_idle_source_new ();
+      g_source_set_callback (source, (GSourceFunc) (send_message),
+          souphttpsink, NULL);
+      g_source_attach (source, souphttpsink->context);
+      g_source_unref (source);
+    }
+  }
+  g_mutex_unlock (&souphttpsink->mutex);
+
+  return GST_FLOW_OK;
+}
+
+static void
+authenticate (SoupSession * session, SoupMessage * msg,
+    SoupAuth * auth, gboolean retrying, gpointer user_data)
+{
+  GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (user_data);
+
+  if (!retrying) {
+    /* First time authentication only, if we fail and are called again with retry true fall through */
+    if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
+      if (souphttpsink->user_id && souphttpsink->user_pw)
+        soup_auth_authenticate (auth, souphttpsink->user_id,
+            souphttpsink->user_pw);
+    } else if (msg->status_code == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
+      if (souphttpsink->proxy_id && souphttpsink->proxy_pw)
+        soup_auth_authenticate (auth, souphttpsink->proxy_id,
+            souphttpsink->proxy_pw);
+    }
+  }
+}
diff --git a/ext/soup/gstsouphttpclientsink.h b/ext/soup/gstsouphttpclientsink.h
new file mode 100644
index 0000000..29c4500
--- /dev/null
+++ b/ext/soup/gstsouphttpclientsink.h
@@ -0,0 +1,85 @@
+/* GStreamer
+ * Copyright (C) 2011 David Schleef <ds@entropywave.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GST_SOUP_HTTP_CLIENT_SINK_H_
+#define _GST_SOUP_HTTP_CLIENT_SINK_H_
+
+#include <gst/base/gstbasesink.h>
+#include <libsoup/soup.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SOUP_HTTP_CLIENT_SINK           (gst_soup_http_client_sink_get_type())
+#define GST_SOUP_HTTP_CLIENT_SINK(obj)           (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SOUP_HTTP_CLIENT_SINK,GstSoupHttpClientSink))
+#define GST_SOUP_HTTP_CLIENT_SINK_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SOUP_HTTP_CLIENT_SINK,GstSoupHttpClientSinkClass))
+#define GST_IS_SOUP_HTTP_CLIENT_SINK(obj)        (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SOUP_HTTP_CLIENT_SINK))
+#define GST_IS_SOUP_HTTP_CLIENT_SINK_CLASS(obj)  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SOUP_HTTP_CLIENT_SINK))
+
+typedef struct _GstSoupHttpClientSink GstSoupHttpClientSink;
+typedef struct _GstSoupHttpClientSinkClass GstSoupHttpClientSinkClass;
+
+struct _GstSoupHttpClientSink
+{
+  GstBaseSink base_souphttpsink;
+
+  GMutex mutex;
+  GCond cond;
+  GMainContext *context;
+  GMainLoop *loop;
+  GThread *thread;
+  GSource *timer;
+  SoupMessage *message;
+  SoupSession *session;
+  GList *queued_buffers;
+  GList *sent_buffers;
+  GList *streamheader_buffers;
+
+  int status_code;
+  char *reason_phrase;
+
+  guint64 offset;
+  int timeout;
+  gint failures;
+
+  /* properties */
+  SoupSession *prop_session;
+  char *location;
+  char *user_id;
+  char *user_pw;
+  SoupURI *proxy;
+  char *proxy_id;
+  char *proxy_pw;
+  char *user_agent;
+  gboolean automatic_redirect;
+  gchar **cookies;
+  SoupLoggerLogLevel log_level;
+  gint retry_delay;
+  gint retries;
+};
+
+struct _GstSoupHttpClientSinkClass
+{
+  GstBaseSinkClass base_souphttpsink_class;
+};
+
+GType gst_soup_http_client_sink_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ext/soup/gstsouphttpsrc.c b/ext/soup/gstsouphttpsrc.c
new file mode 100644
index 0000000..28642e3
--- /dev/null
+++ b/ext/soup/gstsouphttpsrc.c
@@ -0,0 +1,2178 @@
+/* GStreamer
+ * Copyright (C) 2007-2008 Wouter Cloetens <wouter@mind.be>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more
+ */
+
+/**
+ * SECTION:element-souphttpsrc
+ *
+ * This plugin reads data from a remote location specified by a URI.
+ * Supported protocols are 'http', 'https'.
+ *
+ * An HTTP proxy must be specified by its URL.
+ * If the "http_proxy" environment variable is set, its value is used.
+ * If built with libsoup's GNOME integration features, the GNOME proxy
+ * configuration will be used, or failing that, proxy autodetection.
+ * The #GstSoupHTTPSrc:proxy property can be used to override the default.
+ *
+ * In case the #GstSoupHTTPSrc:iradio-mode property is set and the location is
+ * an HTTP resource, souphttpsrc will send special Icecast HTTP headers to the
+ * server to request additional Icecast meta-information.
+ * If the server is not an Icecast server, it will behave as if the
+ * #GstSoupHTTPSrc:iradio-mode property were not set. If it is, souphttpsrc will
+ * output data with a media type of application/x-icy, in which case you will
+ * need to use the #ICYDemux element as follow-up element to extract the Icecast
+ * metadata and to determine the underlying media type.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v souphttpsrc location=https://some.server.org/index.html
+ *     ! filesink location=/home/joe/server.html
+ * ]| The above pipeline reads a web page from a server using the HTTPS protocol
+ * and writes it to a local file.
+ * |[
+ * gst-launch-1.0 -v souphttpsrc user-agent="FooPlayer 0.99 beta"
+ *     automatic-redirect=false proxy=http://proxy.intranet.local:8080
+ *     location=http://music.foobar.com/demo.mp3 ! mpgaudioparse
+ *     ! mpg123audiodec ! audioconvert ! audioresample ! autoaudiosink
+ * ]| The above pipeline will read and decode and play an mp3 file from a
+ * web server using the HTTP protocol. If the server sends redirects,
+ * the request fails instead of following the redirect. The specified
+ * HTTP proxy server is used. The User-Agent HTTP request header
+ * is set to a custom string instead of "GStreamer souphttpsrc."
+ * |[
+ * gst-launch-1.0 -v souphttpsrc location=http://10.11.12.13/mjpeg
+ *     do-timestamp=true ! multipartdemux
+ *     ! image/jpeg,width=640,height=480 ! matroskamux
+ *     ! filesink location=mjpeg.mkv
+ * ]| The above pipeline reads a motion JPEG stream from an IP camera
+ * using the HTTP protocol, encoded as mime/multipart image/jpeg
+ * parts, and writes a Matroska motion JPEG file. The width and
+ * height properties are set in the caps to provide the Matroska
+ * multiplexer with the information to set this in the header.
+ * Timestamps are set on the buffers as they arrive from the camera.
+ * These are used by the mime/multipart demultiplexer to emit timestamps
+ * on the JPEG-encoded video frame buffers. This allows the Matroska
+ * multiplexer to timestamp the frames in the resulting file.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>             /* atoi() */
+#endif
+#include <gst/gstelement.h>
+#include <gst/gst-i18n-plugin.h>
+#include <libsoup/soup.h>
+#include "gstsouphttpsrc.h"
+#include "gstsouputils.h"
+
+#include <gst/tag/tag.h>
+
+GST_DEBUG_CATEGORY_STATIC (souphttpsrc_debug);
+#define GST_CAT_DEFAULT souphttpsrc_debug
+
+#define GST_SOUP_SESSION_CONTEXT "gst.soup.session"
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+enum
+{
+  PROP_0,
+  PROP_LOCATION,
+  PROP_IS_LIVE,
+  PROP_USER_AGENT,
+  PROP_AUTOMATIC_REDIRECT,
+  PROP_PROXY,
+  PROP_USER_ID,
+  PROP_USER_PW,
+  PROP_PROXY_ID,
+  PROP_PROXY_PW,
+  PROP_COOKIES,
+  PROP_IRADIO_MODE,
+  PROP_TIMEOUT,
+  PROP_EXTRA_HEADERS,
+  PROP_SOUP_LOG_LEVEL,
+  PROP_COMPRESS,
+  PROP_KEEP_ALIVE,
+  PROP_SSL_STRICT,
+  PROP_SSL_CA_FILE,
+  PROP_SSL_USE_SYSTEM_CA_FILE,
+  PROP_TLS_DATABASE,
+  PROP_RETRIES,
+  PROP_METHOD,
+  PROP_TLS_INTERACTION,
+};
+
+#define DEFAULT_USER_AGENT           "GStreamer souphttpsrc " PACKAGE_VERSION " "
+#define DEFAULT_IRADIO_MODE          TRUE
+#define DEFAULT_SOUP_LOG_LEVEL       SOUP_LOGGER_LOG_HEADERS
+#define DEFAULT_COMPRESS             FALSE
+#define DEFAULT_KEEP_ALIVE           TRUE
+#define DEFAULT_SSL_STRICT           TRUE
+#define DEFAULT_SSL_CA_FILE          NULL
+#define DEFAULT_SSL_USE_SYSTEM_CA_FILE TRUE
+#define DEFAULT_TLS_DATABASE         NULL
+#define DEFAULT_TLS_INTERACTION      NULL
+#define DEFAULT_TIMEOUT              15
+#define DEFAULT_RETRIES              3
+#define DEFAULT_SOUP_METHOD          NULL
+
+#define GROW_BLOCKSIZE_LIMIT 1
+#define GROW_BLOCKSIZE_COUNT 1
+#define GROW_BLOCKSIZE_FACTOR 2
+#define REDUCE_BLOCKSIZE_LIMIT 0.20
+#define REDUCE_BLOCKSIZE_COUNT 2
+#define REDUCE_BLOCKSIZE_FACTOR 0.5
+
+static void gst_soup_http_src_uri_handler_init (gpointer g_iface,
+    gpointer iface_data);
+static void gst_soup_http_src_finalize (GObject * gobject);
+static void gst_soup_http_src_dispose (GObject * gobject);
+
+static void gst_soup_http_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_soup_http_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn gst_soup_http_src_change_state (GstElement *
+    element, GstStateChange transition);
+static void gst_soup_http_src_set_context (GstElement * element,
+    GstContext * context);
+static GstFlowReturn gst_soup_http_src_create (GstPushSrc * psrc,
+    GstBuffer ** outbuf);
+static gboolean gst_soup_http_src_start (GstBaseSrc * bsrc);
+static gboolean gst_soup_http_src_stop (GstBaseSrc * bsrc);
+static gboolean gst_soup_http_src_get_size (GstBaseSrc * bsrc, guint64 * size);
+static gboolean gst_soup_http_src_is_seekable (GstBaseSrc * bsrc);
+static gboolean gst_soup_http_src_do_seek (GstBaseSrc * bsrc,
+    GstSegment * segment);
+static gboolean gst_soup_http_src_query (GstBaseSrc * bsrc, GstQuery * query);
+static gboolean gst_soup_http_src_unlock (GstBaseSrc * bsrc);
+static gboolean gst_soup_http_src_unlock_stop (GstBaseSrc * bsrc);
+static gboolean gst_soup_http_src_set_location (GstSoupHTTPSrc * src,
+    const gchar * uri, GError ** error);
+static gboolean gst_soup_http_src_set_proxy (GstSoupHTTPSrc * src,
+    const gchar * uri);
+static char *gst_soup_http_src_unicodify (const char *str);
+static gboolean gst_soup_http_src_build_message (GstSoupHTTPSrc * src,
+    const gchar * method);
+static void gst_soup_http_src_cancel_message (GstSoupHTTPSrc * src);
+static gboolean gst_soup_http_src_add_range_header (GstSoupHTTPSrc * src,
+    guint64 offset, guint64 stop_offset);
+static gboolean gst_soup_http_src_session_open (GstSoupHTTPSrc * src);
+static void gst_soup_http_src_session_close (GstSoupHTTPSrc * src);
+static GstFlowReturn gst_soup_http_src_parse_status (SoupMessage * msg,
+    GstSoupHTTPSrc * src);
+static GstFlowReturn gst_soup_http_src_got_headers (GstSoupHTTPSrc * src,
+    SoupMessage * msg);
+static void gst_soup_http_src_authenticate_cb (SoupSession * session,
+    SoupMessage * msg, SoupAuth * auth, gboolean retrying,
+    GstSoupHTTPSrc * src);
+
+#define gst_soup_http_src_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstSoupHTTPSrc, gst_soup_http_src, GST_TYPE_PUSH_SRC,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
+        gst_soup_http_src_uri_handler_init));
+
+static void
+gst_soup_http_src_class_init (GstSoupHTTPSrcClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSrcClass *gstbasesrc_class;
+  GstPushSrcClass *gstpushsrc_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesrc_class = (GstBaseSrcClass *) klass;
+  gstpushsrc_class = (GstPushSrcClass *) klass;
+
+  gobject_class->set_property = gst_soup_http_src_set_property;
+  gobject_class->get_property = gst_soup_http_src_get_property;
+  gobject_class->finalize = gst_soup_http_src_finalize;
+  gobject_class->dispose = gst_soup_http_src_dispose;
+
+  g_object_class_install_property (gobject_class,
+      PROP_LOCATION,
+      g_param_spec_string ("location", "Location",
+          "Location to read from", "",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_USER_AGENT,
+      g_param_spec_string ("user-agent", "User-Agent",
+          "Value of the User-Agent HTTP request header field",
+          DEFAULT_USER_AGENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_AUTOMATIC_REDIRECT,
+      g_param_spec_boolean ("automatic-redirect", "automatic-redirect",
+          "Automatically follow HTTP redirects (HTTP Status Code 3xx)",
+          TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_PROXY,
+      g_param_spec_string ("proxy", "Proxy",
+          "HTTP proxy server URI", "",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_USER_ID,
+      g_param_spec_string ("user-id", "user-id",
+          "HTTP location URI user id for authentication", "",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_USER_PW,
+      g_param_spec_string ("user-pw", "user-pw",
+          "HTTP location URI user password for authentication", "",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_PROXY_ID,
+      g_param_spec_string ("proxy-id", "proxy-id",
+          "HTTP proxy URI user id for authentication", "",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_PROXY_PW,
+      g_param_spec_string ("proxy-pw", "proxy-pw",
+          "HTTP proxy URI user password for authentication", "",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_COOKIES,
+      g_param_spec_boxed ("cookies", "Cookies", "HTTP request cookies",
+          G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_IS_LIVE,
+      g_param_spec_boolean ("is-live", "is-live", "Act like a live source",
+          FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_TIMEOUT,
+      g_param_spec_uint ("timeout", "timeout",
+          "Value in seconds to timeout a blocking I/O (0 = No timeout).", 0,
+          3600, DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_EXTRA_HEADERS,
+      g_param_spec_boxed ("extra-headers", "Extra Headers",
+          "Extra headers to append to the HTTP request",
+          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_IRADIO_MODE,
+      g_param_spec_boolean ("iradio-mode", "iradio-mode",
+          "Enable internet radio mode (ask server to send shoutcast/icecast "
+          "metadata interleaved with the actual stream data)",
+          DEFAULT_IRADIO_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+   * GstSoupHTTPSrc::http-log-level:
+   *
+   * If set and > 0, captures and dumps HTTP session data as
+   * log messages if log level >= GST_LEVEL_TRACE
+   *
+   * Since: 1.4
+   */
+  g_object_class_install_property (gobject_class, PROP_SOUP_LOG_LEVEL,
+      g_param_spec_enum ("http-log-level", "HTTP log level",
+          "Set log level for soup's HTTP session log",
+          SOUP_TYPE_LOGGER_LOG_LEVEL, DEFAULT_SOUP_LOG_LEVEL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+   * GstSoupHTTPSrc::compress:
+   *
+   * If set to %TRUE, souphttpsrc will automatically handle gzip
+   * and deflate Content-Encodings. This does not make much difference
+   * and causes more load for normal media files, but makes a real
+   * difference in size for plaintext files.
+   *
+   * Since: 1.4
+   */
+  g_object_class_install_property (gobject_class, PROP_COMPRESS,
+      g_param_spec_boolean ("compress", "Compress",
+          "Allow compressed content encodings",
+          DEFAULT_COMPRESS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+   * GstSoupHTTPSrc::keep-alive:
+   *
+   * If set to %TRUE, souphttpsrc will keep alive connections when being
+   * set to READY state and only will close connections when connecting
+   * to a different server or when going to NULL state..
+   *
+   * Since: 1.4
+   */
+  g_object_class_install_property (gobject_class, PROP_KEEP_ALIVE,
+      g_param_spec_boolean ("keep-alive", "keep-alive",
+          "Use HTTP persistent connections", DEFAULT_KEEP_ALIVE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+   * GstSoupHTTPSrc::ssl-strict:
+   *
+   * If set to %TRUE, souphttpsrc will reject all SSL certificates that
+   * are considered invalid.
+   *
+   * Since: 1.4
+   */
+  g_object_class_install_property (gobject_class, PROP_SSL_STRICT,
+      g_param_spec_boolean ("ssl-strict", "SSL Strict",
+          "Strict SSL certificate checking", DEFAULT_SSL_STRICT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+   * GstSoupHTTPSrc::ssl-ca-file:
+   *
+   * A SSL anchor CA file that should be used for checking certificates
+   * instead of the system CA file.
+   *
+   * If this property is non-%NULL, #GstSoupHTTPSrc::ssl-use-system-ca-file
+   * value will be ignored.
+   *
+   * Deprecated: Use #GstSoupHTTPSrc::tls-database property instead.
+   * Since: 1.4
+   */
+  g_object_class_install_property (gobject_class, PROP_SSL_CA_FILE,
+      g_param_spec_string ("ssl-ca-file", "SSL CA File",
+          "Location of a SSL anchor CA file to use", DEFAULT_SSL_CA_FILE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+   * GstSoupHTTPSrc::ssl-use-system-ca-file:
+   *
+   * If set to %TRUE, souphttpsrc will use the system's CA file for
+   * checking certificates, unless #GstSoupHTTPSrc::ssl-ca-file or
+   * #GstSoupHTTPSrc::tls-database are non-%NULL.
+   *
+   * Since: 1.4
+   */
+  g_object_class_install_property (gobject_class, PROP_SSL_USE_SYSTEM_CA_FILE,
+      g_param_spec_boolean ("ssl-use-system-ca-file", "Use System CA File",
+          "Use system CA file", DEFAULT_SSL_USE_SYSTEM_CA_FILE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstSoupHTTPSrc::tls-database:
+   *
+   * TLS database with anchor certificate authorities used to validate
+   * the server certificate.
+   *
+   * If this property is non-%NULL, #GstSoupHTTPSrc::ssl-use-system-ca-file
+   * and #GstSoupHTTPSrc::ssl-ca-file values will be ignored.
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_TLS_DATABASE,
+      g_param_spec_object ("tls-database", "TLS database",
+          "TLS database with anchor certificate authorities used to validate the server certificate",
+          G_TYPE_TLS_DATABASE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstSoupHTTPSrc::tls-interaction:
+   *
+   * A #GTlsInteraction object to be used when the connection or certificate
+   * database need to interact with the user. This will be used to prompt the
+   * user for passwords or certificate where necessary.
+   *
+   * Since: 1.8
+   */
+  g_object_class_install_property (gobject_class, PROP_TLS_INTERACTION,
+      g_param_spec_object ("tls-interaction", "TLS interaction",
+          "A GTlsInteraction object to be used when the connection or certificate database need to interact with the user.",
+          G_TYPE_TLS_INTERACTION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+   * GstSoupHTTPSrc::retries:
+   *
+   * Maximum number of retries until giving up.
+   *
+   * Since: 1.4
+   */
+  g_object_class_install_property (gobject_class, PROP_RETRIES,
+      g_param_spec_int ("retries", "Retries",
+          "Maximum number of retries until giving up (-1=infinite)", -1,
+          G_MAXINT, DEFAULT_RETRIES,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+   * GstSoupHTTPSrc::method
+   *
+   * The HTTP method to use when making a request
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_METHOD,
+      g_param_spec_string ("method", "HTTP method",
+          "The HTTP method to use (GET, HEAD, OPTIONS, etc)",
+          DEFAULT_SOUP_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
+
+  gst_element_class_set_static_metadata (gstelement_class, "HTTP client source",
+      "Source/Network",
+      "Receive data as a client over the network via HTTP using SOUP",
+      "Wouter Cloetens <wouter@mind.be>");
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_soup_http_src_change_state);
+  gstelement_class->set_context =
+      GST_DEBUG_FUNCPTR (gst_soup_http_src_set_context);
+
+  gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_soup_http_src_start);
+  gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_soup_http_src_stop);
+  gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_soup_http_src_unlock);
+  gstbasesrc_class->unlock_stop =
+      GST_DEBUG_FUNCPTR (gst_soup_http_src_unlock_stop);
+  gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_soup_http_src_get_size);
+  gstbasesrc_class->is_seekable =
+      GST_DEBUG_FUNCPTR (gst_soup_http_src_is_seekable);
+  gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_soup_http_src_do_seek);
+  gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_soup_http_src_query);
+
+  gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_soup_http_src_create);
+
+  GST_DEBUG_CATEGORY_INIT (souphttpsrc_debug, "souphttpsrc", 0,
+      "SOUP HTTP src");
+}
+
+static void
+gst_soup_http_src_reset (GstSoupHTTPSrc * src)
+{
+  src->retry_count = 0;
+  src->have_size = FALSE;
+  src->got_headers = FALSE;
+  src->seekable = FALSE;
+  src->read_position = 0;
+  src->request_position = 0;
+  src->stop_position = -1;
+  src->content_size = 0;
+  src->have_body = FALSE;
+
+  src->reduce_blocksize_count = 0;
+  src->increase_blocksize_count = 0;
+
+  g_cancellable_reset (src->cancellable);
+  if (src->input_stream) {
+    g_object_unref (src->input_stream);
+    src->input_stream = NULL;
+  }
+
+  gst_caps_replace (&src->src_caps, NULL);
+  g_free (src->iradio_name);
+  src->iradio_name = NULL;
+  g_free (src->iradio_genre);
+  src->iradio_genre = NULL;
+  g_free (src->iradio_url);
+  src->iradio_url = NULL;
+}
+
+static void
+gst_soup_http_src_init (GstSoupHTTPSrc * src)
+{
+  const gchar *proxy;
+
+  g_mutex_init (&src->mutex);
+  g_cond_init (&src->have_headers_cond);
+  src->cancellable = g_cancellable_new ();
+  src->location = NULL;
+  src->redirection_uri = NULL;
+  src->automatic_redirect = TRUE;
+  src->user_agent = g_strdup (DEFAULT_USER_AGENT);
+  src->user_id = NULL;
+  src->user_pw = NULL;
+  src->proxy_id = NULL;
+  src->proxy_pw = NULL;
+  src->cookies = NULL;
+  src->iradio_mode = DEFAULT_IRADIO_MODE;
+  src->session = NULL;
+  src->external_session = NULL;
+  src->forced_external_session = FALSE;
+  src->msg = NULL;
+  src->timeout = DEFAULT_TIMEOUT;
+  src->log_level = DEFAULT_SOUP_LOG_LEVEL;
+  src->compress = DEFAULT_COMPRESS;
+  src->keep_alive = DEFAULT_KEEP_ALIVE;
+  src->ssl_strict = DEFAULT_SSL_STRICT;
+  src->ssl_use_system_ca_file = DEFAULT_SSL_USE_SYSTEM_CA_FILE;
+  src->tls_database = DEFAULT_TLS_DATABASE;
+  src->tls_interaction = DEFAULT_TLS_INTERACTION;
+  src->max_retries = DEFAULT_RETRIES;
+  src->method = DEFAULT_SOUP_METHOD;
+  src->minimum_blocksize = gst_base_src_get_blocksize (GST_BASE_SRC_CAST (src));
+  proxy = g_getenv ("http_proxy");
+  if (!gst_soup_http_src_set_proxy (src, proxy)) {
+    GST_WARNING_OBJECT (src,
+        "The proxy in the http_proxy env var (\"%s\") cannot be parsed.",
+        proxy);
+  }
+
+  gst_base_src_set_automatic_eos (GST_BASE_SRC (src), FALSE);
+
+  gst_soup_http_src_reset (src);
+}
+
+static void
+gst_soup_http_src_dispose (GObject * gobject)
+{
+  GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (gobject);
+
+  GST_DEBUG_OBJECT (src, "dispose");
+
+  gst_soup_http_src_session_close (src);
+
+  if (src->external_session) {
+    g_object_unref (src->external_session);
+    src->external_session = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->dispose (gobject);
+}
+
+static void
+gst_soup_http_src_finalize (GObject * gobject)
+{
+  GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (gobject);
+
+  GST_DEBUG_OBJECT (src, "finalize");
+
+  g_mutex_clear (&src->mutex);
+  g_cond_clear (&src->have_headers_cond);
+  g_object_unref (src->cancellable);
+  g_free (src->location);
+  g_free (src->redirection_uri);
+  g_free (src->user_agent);
+  if (src->proxy != NULL) {
+    soup_uri_free (src->proxy);
+  }
+  g_free (src->user_id);
+  g_free (src->user_pw);
+  g_free (src->proxy_id);
+  g_free (src->proxy_pw);
+  g_strfreev (src->cookies);
+
+  if (src->extra_headers) {
+    gst_structure_free (src->extra_headers);
+    src->extra_headers = NULL;
+  }
+
+  g_free (src->ssl_ca_file);
+
+  if (src->tls_database)
+    g_object_unref (src->tls_database);
+  g_free (src->method);
+
+  if (src->tls_interaction)
+    g_object_unref (src->tls_interaction);
+
+  G_OBJECT_CLASS (parent_class)->finalize (gobject);
+}
+
+static void
+gst_soup_http_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+    {
+      const gchar *location;
+
+      location = g_value_get_string (value);
+
+      if (location == NULL) {
+        GST_WARNING ("location property cannot be NULL");
+        goto done;
+      }
+      if (!gst_soup_http_src_set_location (src, location, NULL)) {
+        GST_WARNING ("badly formatted location");
+        goto done;
+      }
+      break;
+    }
+    case PROP_USER_AGENT:
+      g_free (src->user_agent);
+      src->user_agent = g_value_dup_string (value);
+      break;
+    case PROP_IRADIO_MODE:
+      src->iradio_mode = g_value_get_boolean (value);
+      break;
+    case PROP_AUTOMATIC_REDIRECT:
+      src->automatic_redirect = g_value_get_boolean (value);
+      break;
+    case PROP_PROXY:
+    {
+      const gchar *proxy;
+
+      proxy = g_value_get_string (value);
+      if (!gst_soup_http_src_set_proxy (src, proxy)) {
+        GST_WARNING ("badly formatted proxy URI");
+        goto done;
+      }
+      break;
+    }
+    case PROP_COOKIES:
+      g_strfreev (src->cookies);
+      src->cookies = g_strdupv (g_value_get_boxed (value));
+      break;
+    case PROP_IS_LIVE:
+      gst_base_src_set_live (GST_BASE_SRC (src), g_value_get_boolean (value));
+      break;
+    case PROP_USER_ID:
+      g_free (src->user_id);
+      src->user_id = g_value_dup_string (value);
+      break;
+    case PROP_USER_PW:
+      g_free (src->user_pw);
+      src->user_pw = g_value_dup_string (value);
+      break;
+    case PROP_PROXY_ID:
+      g_free (src->proxy_id);
+      src->proxy_id = g_value_dup_string (value);
+      break;
+    case PROP_PROXY_PW:
+      g_free (src->proxy_pw);
+      src->proxy_pw = g_value_dup_string (value);
+      break;
+    case PROP_TIMEOUT:
+      src->timeout = g_value_get_uint (value);
+      break;
+    case PROP_EXTRA_HEADERS:{
+      const GstStructure *s = gst_value_get_structure (value);
+
+      if (src->extra_headers)
+        gst_structure_free (src->extra_headers);
+
+      src->extra_headers = s ? gst_structure_copy (s) : NULL;
+      break;
+    }
+    case PROP_SOUP_LOG_LEVEL:
+      src->log_level = g_value_get_enum (value);
+      break;
+    case PROP_COMPRESS:
+      src->compress = g_value_get_boolean (value);
+      break;
+    case PROP_KEEP_ALIVE:
+      src->keep_alive = g_value_get_boolean (value);
+      break;
+    case PROP_SSL_STRICT:
+      src->ssl_strict = g_value_get_boolean (value);
+      break;
+    case PROP_SSL_CA_FILE:
+      g_free (src->ssl_ca_file);
+      src->ssl_ca_file = g_value_dup_string (value);
+      break;
+    case PROP_SSL_USE_SYSTEM_CA_FILE:
+      src->ssl_use_system_ca_file = g_value_get_boolean (value);
+      break;
+    case PROP_TLS_DATABASE:
+      g_clear_object (&src->tls_database);
+      src->tls_database = g_value_dup_object (value);
+      break;
+    case PROP_TLS_INTERACTION:
+      g_clear_object (&src->tls_interaction);
+      src->tls_interaction = g_value_dup_object (value);
+      break;
+    case PROP_RETRIES:
+      src->max_retries = g_value_get_int (value);
+      break;
+    case PROP_METHOD:
+      g_free (src->method);
+      src->method = g_value_dup_string (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+done:
+  return;
+}
+
+static void
+gst_soup_http_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      g_value_set_string (value, src->location);
+      break;
+    case PROP_USER_AGENT:
+      g_value_set_string (value, src->user_agent);
+      break;
+    case PROP_AUTOMATIC_REDIRECT:
+      g_value_set_boolean (value, src->automatic_redirect);
+      break;
+    case PROP_PROXY:
+      if (src->proxy == NULL)
+        g_value_set_static_string (value, "");
+      else {
+        char *proxy = soup_uri_to_string (src->proxy, FALSE);
+
+        g_value_set_string (value, proxy);
+        g_free (proxy);
+      }
+      break;
+    case PROP_COOKIES:
+      g_value_set_boxed (value, g_strdupv (src->cookies));
+      break;
+    case PROP_IS_LIVE:
+      g_value_set_boolean (value, gst_base_src_is_live (GST_BASE_SRC (src)));
+      break;
+    case PROP_IRADIO_MODE:
+      g_value_set_boolean (value, src->iradio_mode);
+      break;
+    case PROP_USER_ID:
+      g_value_set_string (value, src->user_id);
+      break;
+    case PROP_USER_PW:
+      g_value_set_string (value, src->user_pw);
+      break;
+    case PROP_PROXY_ID:
+      g_value_set_string (value, src->proxy_id);
+      break;
+    case PROP_PROXY_PW:
+      g_value_set_string (value, src->proxy_pw);
+      break;
+    case PROP_TIMEOUT:
+      g_value_set_uint (value, src->timeout);
+      break;
+    case PROP_EXTRA_HEADERS:
+      gst_value_set_structure (value, src->extra_headers);
+      break;
+    case PROP_SOUP_LOG_LEVEL:
+      g_value_set_enum (value, src->log_level);
+      break;
+    case PROP_COMPRESS:
+      g_value_set_boolean (value, src->compress);
+      break;
+    case PROP_KEEP_ALIVE:
+      g_value_set_boolean (value, src->keep_alive);
+      break;
+    case PROP_SSL_STRICT:
+      g_value_set_boolean (value, src->ssl_strict);
+      break;
+    case PROP_SSL_CA_FILE:
+      g_value_set_string (value, src->ssl_ca_file);
+      break;
+    case PROP_SSL_USE_SYSTEM_CA_FILE:
+      g_value_set_boolean (value, src->ssl_use_system_ca_file);
+      break;
+    case PROP_TLS_DATABASE:
+      g_value_set_object (value, src->tls_database);
+      break;
+    case PROP_TLS_INTERACTION:
+      g_value_set_object (value, src->tls_interaction);
+      break;
+    case PROP_RETRIES:
+      g_value_set_int (value, src->max_retries);
+      break;
+    case PROP_METHOD:
+      g_value_set_string (value, src->method);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gchar *
+gst_soup_http_src_unicodify (const gchar * str)
+{
+  const gchar *env_vars[] = { "GST_ICY_TAG_ENCODING",
+    "GST_TAG_ENCODING", NULL
+  };
+
+  return gst_tag_freeform_string_to_utf8 (str, -1, env_vars);
+}
+
+static void
+gst_soup_http_src_cancel_message (GstSoupHTTPSrc * src)
+{
+  g_cancellable_cancel (src->cancellable);
+  g_cond_signal (&src->have_headers_cond);
+}
+
+static gboolean
+gst_soup_http_src_add_range_header (GstSoupHTTPSrc * src, guint64 offset,
+    guint64 stop_offset)
+{
+  gchar buf[64];
+  gint rc;
+
+  soup_message_headers_remove (src->msg->request_headers, "Range");
+  if (offset || stop_offset != -1) {
+    if (stop_offset != -1) {
+      g_assert (offset != stop_offset);
+
+      rc = g_snprintf (buf, sizeof (buf), "bytes=%" G_GUINT64_FORMAT "-%"
+          G_GUINT64_FORMAT, offset, (stop_offset > 0) ? stop_offset - 1 :
+          stop_offset);
+    } else {
+      rc = g_snprintf (buf, sizeof (buf), "bytes=%" G_GUINT64_FORMAT "-",
+          offset);
+    }
+    if (rc > sizeof (buf) || rc < 0)
+      return FALSE;
+    soup_message_headers_append (src->msg->request_headers, "Range", buf);
+  }
+  src->read_position = offset;
+  return TRUE;
+}
+
+static gboolean
+_append_extra_header (GQuark field_id, const GValue * value, gpointer user_data)
+{
+  GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (user_data);
+  const gchar *field_name = g_quark_to_string (field_id);
+  gchar *field_content = NULL;
+
+  if (G_VALUE_TYPE (value) == G_TYPE_STRING) {
+    field_content = g_value_dup_string (value);
+  } else {
+    GValue dest = { 0, };
+
+    g_value_init (&dest, G_TYPE_STRING);
+    if (g_value_transform (value, &dest)) {
+      field_content = g_value_dup_string (&dest);
+    }
+  }
+
+  if (field_content == NULL) {
+    GST_ERROR_OBJECT (src, "extra-headers field '%s' contains no value "
+        "or can't be converted to a string", field_name);
+    return FALSE;
+  }
+
+  GST_DEBUG_OBJECT (src, "Appending extra header: \"%s: %s\"", field_name,
+      field_content);
+  soup_message_headers_append (src->msg->request_headers, field_name,
+      field_content);
+
+  g_free (field_content);
+
+  return TRUE;
+}
+
+static gboolean
+_append_extra_headers (GQuark field_id, const GValue * value,
+    gpointer user_data)
+{
+  if (G_VALUE_TYPE (value) == GST_TYPE_ARRAY) {
+    guint n = gst_value_array_get_size (value);
+    guint i;
+
+    for (i = 0; i < n; i++) {
+      const GValue *v = gst_value_array_get_value (value, i);
+
+      if (!_append_extra_header (field_id, v, user_data))
+        return FALSE;
+    }
+  } else if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
+    guint n = gst_value_list_get_size (value);
+    guint i;
+
+    for (i = 0; i < n; i++) {
+      const GValue *v = gst_value_list_get_value (value, i);
+
+      if (!_append_extra_header (field_id, v, user_data))
+        return FALSE;
+    }
+  } else {
+    return _append_extra_header (field_id, value, user_data);
+  }
+
+  return TRUE;
+}
+
+
+static gboolean
+gst_soup_http_src_add_extra_headers (GstSoupHTTPSrc * src)
+{
+  if (!src->extra_headers)
+    return TRUE;
+
+  return gst_structure_foreach (src->extra_headers, _append_extra_headers, src);
+}
+
+static gboolean
+gst_soup_http_src_session_open (GstSoupHTTPSrc * src)
+{
+  if (src->session) {
+    GST_DEBUG_OBJECT (src, "Session is already open");
+    return TRUE;
+  }
+
+  if (!src->location) {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (_("No URL set.")),
+        ("Missing location property"));
+    return FALSE;
+  }
+
+  if (!src->session) {
+    GstQuery *query;
+    gboolean can_share = (src->timeout == DEFAULT_TIMEOUT)
+        && (src->ssl_strict == DEFAULT_SSL_STRICT)
+        && (src->tls_interaction == NULL) && (src->proxy == NULL)
+        && (src->tls_database == DEFAULT_TLS_DATABASE)
+        && (src->ssl_ca_file == DEFAULT_SSL_CA_FILE)
+        && (src->ssl_use_system_ca_file == DEFAULT_SSL_USE_SYSTEM_CA_FILE);
+
+    query = gst_query_new_context (GST_SOUP_SESSION_CONTEXT);
+    if (gst_pad_peer_query (GST_BASE_SRC_PAD (src), query)) {
+      GstContext *context;
+
+      gst_query_parse_context (query, &context);
+      gst_element_set_context (GST_ELEMENT_CAST (src), context);
+    } else {
+      GstMessage *message;
+
+      message =
+          gst_message_new_need_context (GST_OBJECT_CAST (src),
+          GST_SOUP_SESSION_CONTEXT);
+      gst_element_post_message (GST_ELEMENT_CAST (src), message);
+    }
+    gst_query_unref (query);
+
+    GST_OBJECT_LOCK (src);
+    if (src->external_session && (can_share || src->forced_external_session)) {
+      GST_DEBUG_OBJECT (src, "Using external session %p",
+          src->external_session);
+      src->session = g_object_ref (src->external_session);
+      src->session_is_shared = TRUE;
+    } else {
+      GST_DEBUG_OBJECT (src, "Creating session (can share %d)", can_share);
+
+      /* We explicitly set User-Agent to NULL here and overwrite it per message
+       * to be able to have the same session with different User-Agents per
+       * source */
+      if (src->proxy == NULL) {
+        src->session =
+            soup_session_new_with_options (SOUP_SESSION_USER_AGENT,
+            NULL, SOUP_SESSION_TIMEOUT, src->timeout,
+            SOUP_SESSION_SSL_STRICT, src->ssl_strict,
+            SOUP_SESSION_TLS_INTERACTION, src->tls_interaction, NULL);
+      } else {
+        src->session =
+            soup_session_new_with_options (SOUP_SESSION_PROXY_URI, src->proxy,
+            SOUP_SESSION_TIMEOUT, src->timeout,
+            SOUP_SESSION_SSL_STRICT, src->ssl_strict,
+            SOUP_SESSION_USER_AGENT, NULL,
+            SOUP_SESSION_TLS_INTERACTION, src->tls_interaction, NULL);
+      }
+
+      if (src->session) {
+        gst_soup_util_log_setup (src->session, src->log_level,
+            GST_ELEMENT (src));
+        soup_session_add_feature_by_type (src->session,
+            SOUP_TYPE_CONTENT_DECODER);
+        soup_session_add_feature_by_type (src->session, SOUP_TYPE_COOKIE_JAR);
+
+        if (can_share) {
+          GstContext *context;
+          GstMessage *message;
+          GstStructure *s;
+
+          GST_DEBUG_OBJECT (src, "Sharing session %p", src->session);
+          src->session_is_shared = TRUE;
+
+          /* Unset the limit the number of maximum allowed connection */
+          g_object_set (src->session, SOUP_SESSION_MAX_CONNS, G_MAXINT,
+              SOUP_SESSION_MAX_CONNS_PER_HOST, G_MAXINT, NULL);
+
+          context = gst_context_new (GST_SOUP_SESSION_CONTEXT, TRUE);
+          s = gst_context_writable_structure (context);
+          gst_structure_set (s, "session", SOUP_TYPE_SESSION, src->session,
+              "force", G_TYPE_BOOLEAN, FALSE, NULL);
+
+          gst_object_ref (src->session);
+          GST_OBJECT_UNLOCK (src);
+          gst_element_set_context (GST_ELEMENT_CAST (src), context);
+          message =
+              gst_message_new_have_context (GST_OBJECT_CAST (src), context);
+          gst_element_post_message (GST_ELEMENT_CAST (src), message);
+          GST_OBJECT_LOCK (src);
+          gst_object_unref (src->session);
+        } else {
+          src->session_is_shared = FALSE;
+        }
+      }
+    }
+
+    if (!src->session) {
+      GST_ELEMENT_ERROR (src, LIBRARY, INIT,
+          (NULL), ("Failed to create session"));
+      GST_OBJECT_UNLOCK (src);
+      return FALSE;
+    }
+
+    g_signal_connect (src->session, "authenticate",
+        G_CALLBACK (gst_soup_http_src_authenticate_cb), src);
+
+    if (!src->session_is_shared) {
+      if (src->tls_database)
+        g_object_set (src->session, "tls-database", src->tls_database, NULL);
+      else if (src->ssl_ca_file)
+        g_object_set (src->session, "ssl-ca-file", src->ssl_ca_file, NULL);
+      else
+        g_object_set (src->session, "ssl-use-system-ca-file",
+            src->ssl_use_system_ca_file, NULL);
+    }
+    GST_OBJECT_UNLOCK (src);
+  } else {
+    GST_DEBUG_OBJECT (src, "Re-using session");
+  }
+
+  return TRUE;
+}
+
+static void
+gst_soup_http_src_session_close (GstSoupHTTPSrc * src)
+{
+  GST_DEBUG_OBJECT (src, "Closing session");
+
+  g_mutex_lock (&src->mutex);
+  if (src->msg) {
+    soup_session_cancel_message (src->session, src->msg, SOUP_STATUS_CANCELLED);
+    g_object_unref (src->msg);
+    src->msg = NULL;
+  }
+
+  if (src->session) {
+    if (!src->session_is_shared)
+      soup_session_abort (src->session);
+    g_signal_handlers_disconnect_by_func (src->session,
+        G_CALLBACK (gst_soup_http_src_authenticate_cb), src);
+    g_object_unref (src->session);
+    src->session = NULL;
+  }
+
+  g_mutex_unlock (&src->mutex);
+}
+
+static void
+gst_soup_http_src_authenticate_cb (SoupSession * session, SoupMessage * msg,
+    SoupAuth * auth, gboolean retrying, GstSoupHTTPSrc * src)
+{
+  /* Might be from another user of the shared session */
+  if (!GST_IS_SOUP_HTTP_SRC (src) || msg != src->msg)
+    return;
+
+  if (!retrying) {
+    /* First time authentication only, if we fail and are called again with retry true fall through */
+    if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
+      if (src->user_id && src->user_pw)
+        soup_auth_authenticate (auth, src->user_id, src->user_pw);
+    } else if (msg->status_code == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
+      if (src->proxy_id && src->proxy_pw)
+        soup_auth_authenticate (auth, src->proxy_id, src->proxy_pw);
+    }
+  }
+}
+
+static void
+insert_http_header (const gchar * name, const gchar * value, gpointer user_data)
+{
+  GstStructure *headers = user_data;
+  const GValue *gv;
+
+  if (!g_utf8_validate (name, -1, NULL) || !g_utf8_validate (value, -1, NULL))
+    return;
+
+  gv = gst_structure_get_value (headers, name);
+  if (gv && GST_VALUE_HOLDS_ARRAY (gv)) {
+    GValue v = G_VALUE_INIT;
+
+    g_value_init (&v, G_TYPE_STRING);
+    g_value_set_string (&v, value);
+    gst_value_array_append_value ((GValue *) gv, &v);
+    g_value_unset (&v);
+  } else if (gv && G_VALUE_HOLDS_STRING (gv)) {
+    GValue arr = G_VALUE_INIT;
+    GValue v = G_VALUE_INIT;
+    const gchar *old_value = g_value_get_string (gv);
+
+    g_value_init (&arr, GST_TYPE_ARRAY);
+    g_value_init (&v, G_TYPE_STRING);
+    g_value_set_string (&v, old_value);
+    gst_value_array_append_value (&arr, &v);
+    g_value_set_string (&v, value);
+    gst_value_array_append_value (&arr, &v);
+
+    gst_structure_set_value (headers, name, &arr);
+    g_value_unset (&v);
+    g_value_unset (&arr);
+  } else {
+    gst_structure_set (headers, name, G_TYPE_STRING, value, NULL);
+  }
+}
+
+static GstFlowReturn
+gst_soup_http_src_got_headers (GstSoupHTTPSrc * src, SoupMessage * msg)
+{
+  const char *value;
+  GstTagList *tag_list;
+  GstBaseSrc *basesrc;
+  guint64 newsize;
+  GHashTable *params = NULL;
+  GstEvent *http_headers_event;
+  GstStructure *http_headers, *headers;
+  const gchar *accept_ranges;
+
+  GST_INFO_OBJECT (src, "got headers");
+
+  if (msg->status_code == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED &&
+      src->proxy_id && src->proxy_pw) {
+    /* wait for authenticate callback */
+    return GST_FLOW_OK;
+  }
+
+  http_headers = gst_structure_new_empty ("http-headers");
+  gst_structure_set (http_headers, "uri", G_TYPE_STRING, src->location,
+      "http-status-code", G_TYPE_UINT, msg->status_code, NULL);
+  if (src->redirection_uri)
+    gst_structure_set (http_headers, "redirection-uri", G_TYPE_STRING,
+        src->redirection_uri, NULL);
+  headers = gst_structure_new_empty ("request-headers");
+  soup_message_headers_foreach (msg->request_headers, insert_http_header,
+      headers);
+  gst_structure_set (http_headers, "request-headers", GST_TYPE_STRUCTURE,
+      headers, NULL);
+  gst_structure_free (headers);
+  headers = gst_structure_new_empty ("response-headers");
+  soup_message_headers_foreach (msg->response_headers, insert_http_header,
+      headers);
+  gst_structure_set (http_headers, "response-headers", GST_TYPE_STRUCTURE,
+      headers, NULL);
+  gst_structure_free (headers);
+
+  gst_element_post_message (GST_ELEMENT_CAST (src),
+      gst_message_new_element (GST_OBJECT_CAST (src),
+          gst_structure_copy (http_headers)));
+
+  if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
+    /* force an error */
+    gst_structure_free (http_headers);
+    return gst_soup_http_src_parse_status (msg, src);
+  }
+
+  src->got_headers = TRUE;
+  g_cond_broadcast (&src->have_headers_cond);
+
+  http_headers_event =
+      gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_STICKY, http_headers);
+  gst_event_replace (&src->http_headers_event, http_headers_event);
+  gst_event_unref (http_headers_event);
+
+  /* Parse Content-Length. */
+  if (soup_message_headers_get_encoding (msg->response_headers) ==
+      SOUP_ENCODING_CONTENT_LENGTH) {
+    newsize = src->request_position +
+        soup_message_headers_get_content_length (msg->response_headers);
+    if (!src->have_size || (src->content_size != newsize)) {
+      src->content_size = newsize;
+      src->have_size = TRUE;
+      src->seekable = TRUE;
+      GST_DEBUG_OBJECT (src, "size = %" G_GUINT64_FORMAT, src->content_size);
+
+      basesrc = GST_BASE_SRC_CAST (src);
+      basesrc->segment.duration = src->content_size;
+      gst_element_post_message (GST_ELEMENT (src),
+          gst_message_new_duration_changed (GST_OBJECT (src)));
+    }
+  }
+
+  /* If the server reports Accept-Ranges: none we don't have to try
+   * doing range requests at all
+   */
+  if ((accept_ranges =
+          soup_message_headers_get_one (msg->response_headers,
+              "Accept-Ranges"))) {
+    if (g_ascii_strcasecmp (accept_ranges, "none") == 0)
+      src->seekable = FALSE;
+  }
+
+  /* Icecast stuff */
+  tag_list = gst_tag_list_new_empty ();
+
+  if ((value =
+          soup_message_headers_get_one (msg->response_headers,
+              "icy-metaint")) != NULL) {
+    gint icy_metaint;
+
+    if (g_utf8_validate (value, -1, NULL)) {
+      icy_metaint = atoi (value);
+
+      GST_DEBUG_OBJECT (src, "icy-metaint: %s (parsed: %d)", value,
+          icy_metaint);
+      if (icy_metaint > 0) {
+        if (src->src_caps)
+          gst_caps_unref (src->src_caps);
+
+        src->src_caps = gst_caps_new_simple ("application/x-icy",
+            "metadata-interval", G_TYPE_INT, icy_metaint, NULL);
+
+        gst_base_src_set_caps (GST_BASE_SRC (src), src->src_caps);
+      }
+    }
+  }
+  if ((value =
+          soup_message_headers_get_content_type (msg->response_headers,
+              &params)) != NULL) {
+    if (!g_utf8_validate (value, -1, NULL)) {
+      GST_WARNING_OBJECT (src, "Content-Type is invalid UTF-8");
+    } else if (g_ascii_strcasecmp (value, "audio/L16") == 0) {
+      gint channels = 2;
+      gint rate = 44100;
+      char *param;
+
+      GST_DEBUG_OBJECT (src, "Content-Type: %s", value);
+
+      if (src->src_caps) {
+        gst_caps_unref (src->src_caps);
+        src->src_caps = NULL;
+      }
+
+      param = g_hash_table_lookup (params, "channels");
+      if (param != NULL) {
+        guint64 val = g_ascii_strtoull (param, NULL, 10);
+        if (val < 64)
+          channels = val;
+        else
+          channels = 0;
+      }
+
+      param = g_hash_table_lookup (params, "rate");
+      if (param != NULL) {
+        guint64 val = g_ascii_strtoull (param, NULL, 10);
+        if (val < G_MAXINT)
+          rate = val;
+        else
+          rate = 0;
+      }
+
+      if (rate > 0 && channels > 0) {
+        src->src_caps = gst_caps_new_simple ("audio/x-unaligned-raw",
+            "format", G_TYPE_STRING, "S16BE",
+            "layout", G_TYPE_STRING, "interleaved",
+            "channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, rate, NULL);
+
+        gst_base_src_set_caps (GST_BASE_SRC (src), src->src_caps);
+      }
+    } else {
+      GST_DEBUG_OBJECT (src, "Content-Type: %s", value);
+
+      /* Set the Content-Type field on the caps */
+      if (src->src_caps) {
+        src->src_caps = gst_caps_make_writable (src->src_caps);
+        gst_caps_set_simple (src->src_caps, "content-type", G_TYPE_STRING,
+            value, NULL);
+        gst_base_src_set_caps (GST_BASE_SRC (src), src->src_caps);
+      }
+    }
+  }
+
+  if (params != NULL)
+    g_hash_table_destroy (params);
+
+  if ((value =
+          soup_message_headers_get_one (msg->response_headers,
+              "icy-name")) != NULL) {
+    if (g_utf8_validate (value, -1, NULL)) {
+      g_free (src->iradio_name);
+      src->iradio_name = gst_soup_http_src_unicodify (value);
+      if (src->iradio_name) {
+        gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_ORGANIZATION,
+            src->iradio_name, NULL);
+      }
+    }
+  }
+  if ((value =
+          soup_message_headers_get_one (msg->response_headers,
+              "icy-genre")) != NULL) {
+    if (g_utf8_validate (value, -1, NULL)) {
+      g_free (src->iradio_genre);
+      src->iradio_genre = gst_soup_http_src_unicodify (value);
+      if (src->iradio_genre) {
+        gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_GENRE,
+            src->iradio_genre, NULL);
+      }
+    }
+  }
+  if ((value = soup_message_headers_get_one (msg->response_headers, "icy-url"))
+      != NULL) {
+    if (g_utf8_validate (value, -1, NULL)) {
+      g_free (src->iradio_url);
+      src->iradio_url = gst_soup_http_src_unicodify (value);
+      if (src->iradio_url) {
+        gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_LOCATION,
+            src->iradio_url, NULL);
+      }
+    }
+  }
+  if (!gst_tag_list_is_empty (tag_list)) {
+    GST_DEBUG_OBJECT (src,
+        "calling gst_element_found_tags with %" GST_PTR_FORMAT, tag_list);
+    gst_pad_push_event (GST_BASE_SRC_PAD (src), gst_event_new_tag (tag_list));
+  } else {
+    gst_tag_list_unref (tag_list);
+  }
+
+  /* Handle HTTP errors. */
+  return gst_soup_http_src_parse_status (msg, src);
+}
+
+static GstBuffer *
+gst_soup_http_src_alloc_buffer (GstSoupHTTPSrc * src)
+{
+  GstBaseSrc *basesrc = GST_BASE_SRC_CAST (src);
+  GstFlowReturn rc;
+  GstBuffer *gstbuf;
+
+  rc = GST_BASE_SRC_CLASS (parent_class)->alloc (basesrc, -1,
+      basesrc->blocksize, &gstbuf);
+  if (G_UNLIKELY (rc != GST_FLOW_OK)) {
+    return NULL;
+  }
+
+  return gstbuf;
+}
+
+#define SOUP_HTTP_SRC_ERROR(src,soup_msg,cat,code,error_message)     \
+  do { \
+    GST_ELEMENT_ERROR_WITH_DETAILS ((src), cat, code, ("%s", error_message), \
+        ("%s (%d), URL: %s, Redirect to: %s", (soup_msg)->reason_phrase, \
+            (soup_msg)->status_code, (src)->location, GST_STR_NULL ((src)->redirection_uri)), \
+            ("http-status-code", G_TYPE_UINT, (soup_msg)->status_code, \
+             "http-redirect-uri", G_TYPE_STRING, GST_STR_NULL ((src)->redirection_uri), NULL)); \
+  } while(0)
+
+static GstFlowReturn
+gst_soup_http_src_parse_status (SoupMessage * msg, GstSoupHTTPSrc * src)
+{
+  if (msg->method == SOUP_METHOD_HEAD) {
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
+      GST_DEBUG_OBJECT (src, "Ignoring error %d during HEAD request",
+          msg->status_code);
+    return GST_FLOW_OK;
+  }
+
+  if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
+    switch (msg->status_code) {
+      case SOUP_STATUS_CANT_RESOLVE:
+      case SOUP_STATUS_CANT_RESOLVE_PROXY:
+        SOUP_HTTP_SRC_ERROR (src, msg, RESOURCE, NOT_FOUND,
+            _("Could not resolve server name."));
+        return GST_FLOW_ERROR;
+      case SOUP_STATUS_CANT_CONNECT:
+      case SOUP_STATUS_CANT_CONNECT_PROXY:
+        SOUP_HTTP_SRC_ERROR (src, msg, RESOURCE, OPEN_READ,
+            _("Could not establish connection to server."));
+        return GST_FLOW_ERROR;
+      case SOUP_STATUS_SSL_FAILED:
+        SOUP_HTTP_SRC_ERROR (src, msg, RESOURCE, OPEN_READ,
+            _("Secure connection setup failed."));
+        return GST_FLOW_ERROR;
+      case SOUP_STATUS_IO_ERROR:
+        if (src->max_retries == -1 || src->retry_count < src->max_retries)
+          return GST_FLOW_CUSTOM_ERROR;
+        SOUP_HTTP_SRC_ERROR (src, msg, RESOURCE, READ,
+            _("A network error occurred, or the server closed the connection "
+                "unexpectedly."));
+        return GST_FLOW_ERROR;
+      case SOUP_STATUS_MALFORMED:
+        SOUP_HTTP_SRC_ERROR (src, msg, RESOURCE, READ,
+            _("Server sent bad data."));
+        return GST_FLOW_ERROR;
+      case SOUP_STATUS_CANCELLED:
+        /* No error message when interrupted by program. */
+        break;
+    }
+    return GST_FLOW_OK;
+  }
+
+  if (SOUP_STATUS_IS_CLIENT_ERROR (msg->status_code) ||
+      SOUP_STATUS_IS_REDIRECTION (msg->status_code) ||
+      SOUP_STATUS_IS_SERVER_ERROR (msg->status_code)) {
+    const gchar *reason_phrase;
+
+    reason_phrase = msg->reason_phrase;
+    if (reason_phrase && !g_utf8_validate (reason_phrase, -1, NULL)) {
+      GST_ERROR_OBJECT (src, "Invalid UTF-8 in reason");
+      reason_phrase = "(invalid)";
+    }
+
+    /* Report HTTP error. */
+
+    /* when content_size is unknown and we have just finished receiving
+     * a body message, requests that go beyond the content limits will result
+     * in an error. Here we convert those to EOS */
+    if (msg->status_code == SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE &&
+        src->have_body && !src->have_size) {
+      GST_DEBUG_OBJECT (src, "Requested range out of limits and received full "
+          "body, returning EOS");
+      return GST_FLOW_EOS;
+    }
+
+    /* FIXME: reason_phrase is not translated and not suitable for user
+     * error dialog according to libsoup documentation.
+     */
+    if (msg->status_code == SOUP_STATUS_NOT_FOUND) {
+      SOUP_HTTP_SRC_ERROR (src, msg, RESOURCE, NOT_FOUND, (reason_phrase));
+    } else if (msg->status_code == SOUP_STATUS_UNAUTHORIZED
+        || msg->status_code == SOUP_STATUS_PAYMENT_REQUIRED
+        || msg->status_code == SOUP_STATUS_FORBIDDEN
+        || msg->status_code == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
+      SOUP_HTTP_SRC_ERROR (src, msg, RESOURCE, NOT_AUTHORIZED, (reason_phrase));
+    } else {
+      SOUP_HTTP_SRC_ERROR (src, msg, RESOURCE, OPEN_READ, (reason_phrase));
+    }
+    return GST_FLOW_ERROR;
+  }
+
+  return GST_FLOW_OK;
+}
+
+static void
+gst_soup_http_src_restarted_cb (SoupMessage * msg, GstSoupHTTPSrc * src)
+{
+  if (soup_session_would_redirect (src->session, msg)) {
+    src->redirection_uri =
+        soup_uri_to_string (soup_message_get_uri (msg), FALSE);
+    src->redirection_permanent =
+        (msg->status_code == SOUP_STATUS_MOVED_PERMANENTLY);
+    GST_DEBUG_OBJECT (src, "%u redirect to \"%s\" (permanent %d)",
+        msg->status_code, src->redirection_uri, src->redirection_permanent);
+  }
+}
+
+static gboolean
+gst_soup_http_src_build_message (GstSoupHTTPSrc * src, const gchar * method)
+{
+  g_return_val_if_fail (src->msg == NULL, FALSE);
+
+  src->msg = soup_message_new (method, src->location);
+  if (!src->msg) {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+        ("Error parsing URL."), ("URL: %s", src->location));
+    return FALSE;
+  }
+
+  /* Duplicating the defaults of libsoup here. We don't want to set a
+   * User-Agent in the session as each source might have its own User-Agent
+   * set */
+  if (!src->user_agent || !*src->user_agent) {
+    gchar *user_agent =
+        g_strdup_printf ("libsoup/%u.%u.%u", soup_get_major_version (),
+        soup_get_minor_version (), soup_get_micro_version ());
+    soup_message_headers_append (src->msg->request_headers, "User-Agent",
+        user_agent);
+    g_free (user_agent);
+  } else if (g_str_has_suffix (src->user_agent, " ")) {
+    gchar *user_agent = g_strdup_printf ("%slibsoup/%u.%u.%u", src->user_agent,
+        soup_get_major_version (),
+        soup_get_minor_version (), soup_get_micro_version ());
+    soup_message_headers_append (src->msg->request_headers, "User-Agent",
+        user_agent);
+    g_free (user_agent);
+  } else {
+    soup_message_headers_append (src->msg->request_headers, "User-Agent",
+        src->user_agent);
+  }
+
+  if (!src->keep_alive) {
+    soup_message_headers_append (src->msg->request_headers, "Connection",
+        "close");
+  }
+  if (src->iradio_mode) {
+    soup_message_headers_append (src->msg->request_headers, "icy-metadata",
+        "1");
+  }
+  if (src->cookies) {
+    gchar **cookie;
+
+    for (cookie = src->cookies; *cookie != NULL; cookie++) {
+      soup_message_headers_append (src->msg->request_headers, "Cookie",
+          *cookie);
+    }
+  }
+
+  if (!src->compress)
+    soup_message_disable_feature (src->msg, SOUP_TYPE_CONTENT_DECODER);
+
+  soup_message_set_flags (src->msg, SOUP_MESSAGE_OVERWRITE_CHUNKS |
+      (src->automatic_redirect ? 0 : SOUP_MESSAGE_NO_REDIRECT));
+
+  if (src->automatic_redirect) {
+    g_signal_connect (src->msg, "restarted",
+        G_CALLBACK (gst_soup_http_src_restarted_cb), src);
+  }
+
+  gst_soup_http_src_add_range_header (src, src->request_position,
+      src->stop_position);
+
+  gst_soup_http_src_add_extra_headers (src);
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_soup_http_src_send_message (GstSoupHTTPSrc * src)
+{
+  GstFlowReturn ret;
+  GError *error = NULL;
+
+  g_return_val_if_fail (src->msg != NULL, GST_FLOW_ERROR);
+
+  src->input_stream =
+      soup_session_send (src->session, src->msg, src->cancellable, &error);
+
+  if (g_cancellable_is_cancelled (src->cancellable)) {
+    ret = GST_FLOW_FLUSHING;
+    goto done;
+  }
+
+  ret = gst_soup_http_src_got_headers (src, src->msg);
+  if (ret != GST_FLOW_OK) {
+    goto done;
+  }
+
+  if (!src->input_stream) {
+    GST_DEBUG_OBJECT (src, "Didn't get an input stream: %s", error->message);
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+
+  if (SOUP_STATUS_IS_SUCCESSFUL (src->msg->status_code)) {
+    GST_DEBUG_OBJECT (src, "Successfully got a reply");
+  } else {
+    /* FIXME - be more helpful to people debugging */
+    ret = GST_FLOW_ERROR;
+  }
+
+done:
+  if (error)
+    g_error_free (error);
+  return ret;
+}
+
+static GstFlowReturn
+gst_soup_http_src_do_request (GstSoupHTTPSrc * src, const gchar * method)
+{
+  GstFlowReturn ret;
+
+  if (src->max_retries != -1 && src->retry_count > src->max_retries) {
+    GST_DEBUG_OBJECT (src, "Max retries reached");
+    return GST_FLOW_ERROR;
+  }
+
+  src->retry_count++;
+  /* EOS immediately if we have an empty segment */
+  if (src->request_position == src->stop_position)
+    return GST_FLOW_EOS;
+
+  GST_LOG_OBJECT (src, "Running request for method: %s", method);
+
+  /* Update the position if we are retrying */
+  if (src->msg && src->request_position > 0) {
+    gst_soup_http_src_add_range_header (src, src->request_position,
+        src->stop_position);
+  } else if (src->msg && src->request_position == 0)
+    soup_message_headers_remove (src->msg->request_headers, "Range");
+
+  /* add_range_header() has the side effect of setting read_position to
+   * the requested position. This *needs* to be set regardless of having
+   * a message or not. Failure to do so would result in calculation being
+   * done with stale/wrong read position */
+  src->read_position = src->request_position;
+
+  if (!src->msg) {
+    if (!gst_soup_http_src_build_message (src, method)) {
+      return GST_FLOW_ERROR;
+    }
+  }
+
+  if (g_cancellable_is_cancelled (src->cancellable)) {
+    GST_INFO_OBJECT (src, "interrupted");
+    return GST_FLOW_FLUSHING;
+  }
+
+  ret = gst_soup_http_src_send_message (src);
+
+  /* Check if Range header was respected. */
+  if (ret == GST_FLOW_OK && src->request_position > 0 &&
+      src->msg->status_code != SOUP_STATUS_PARTIAL_CONTENT) {
+    src->seekable = FALSE;
+    GST_ELEMENT_ERROR_WITH_DETAILS (src, RESOURCE, SEEK,
+        (_("Server does not support seeking.")),
+        ("Server does not accept Range HTTP header, URL: %s, Redirect to: %s",
+            src->location, GST_STR_NULL (src->redirection_uri)),
+        ("http-status-code", G_TYPE_UINT, src->msg->status_code,
+            "http-redirection-uri", G_TYPE_STRING,
+            GST_STR_NULL (src->redirection_uri), NULL));
+    ret = GST_FLOW_ERROR;
+  }
+
+  return ret;
+}
+
+/*
+ * Check if the bytes_read is above a certain threshold of the blocksize, if
+ * that happens a few times in a row, increase the blocksize; Do the same in
+ * the opposite direction to reduce the blocksize.
+ */
+static void
+gst_soup_http_src_check_update_blocksize (GstSoupHTTPSrc * src,
+    gint64 bytes_read)
+{
+  guint blocksize = gst_base_src_get_blocksize (GST_BASE_SRC_CAST (src));
+
+  GST_LOG_OBJECT (src, "Checking to update blocksize. Read:%" G_GINT64_FORMAT
+      " blocksize:%u", bytes_read, blocksize);
+
+  if (bytes_read >= blocksize * GROW_BLOCKSIZE_LIMIT) {
+    src->reduce_blocksize_count = 0;
+    src->increase_blocksize_count++;
+
+    if (src->increase_blocksize_count >= GROW_BLOCKSIZE_COUNT) {
+      blocksize *= GROW_BLOCKSIZE_FACTOR;
+      GST_DEBUG_OBJECT (src, "Increased blocksize to %u", blocksize);
+      gst_base_src_set_blocksize (GST_BASE_SRC_CAST (src), blocksize);
+      src->increase_blocksize_count = 0;
+    }
+  } else if (bytes_read < blocksize * REDUCE_BLOCKSIZE_LIMIT) {
+    src->reduce_blocksize_count++;
+    src->increase_blocksize_count = 0;
+
+    if (src->reduce_blocksize_count >= REDUCE_BLOCKSIZE_COUNT) {
+      blocksize *= REDUCE_BLOCKSIZE_FACTOR;
+      blocksize = MAX (blocksize, src->minimum_blocksize);
+      GST_DEBUG_OBJECT (src, "Decreased blocksize to %u", blocksize);
+      gst_base_src_set_blocksize (GST_BASE_SRC_CAST (src), blocksize);
+      src->reduce_blocksize_count = 0;
+    }
+  } else {
+    src->reduce_blocksize_count = src->increase_blocksize_count = 0;
+  }
+}
+
+static void
+gst_soup_http_src_update_position (GstSoupHTTPSrc * src, gint64 bytes_read)
+{
+  GstBaseSrc *basesrc = GST_BASE_SRC_CAST (src);
+  guint64 new_position;
+
+  new_position = src->read_position + bytes_read;
+  if (G_LIKELY (src->request_position == src->read_position))
+    src->request_position = new_position;
+  src->read_position = new_position;
+
+  if (src->have_size) {
+    if (new_position > src->content_size) {
+      GST_DEBUG_OBJECT (src, "Got position previous estimated content size "
+          "(%" G_GINT64_FORMAT " > %" G_GINT64_FORMAT ")", new_position,
+          src->content_size);
+      src->content_size = new_position;
+      basesrc->segment.duration = src->content_size;
+      gst_element_post_message (GST_ELEMENT (src),
+          gst_message_new_duration_changed (GST_OBJECT (src)));
+    } else if (new_position == src->content_size) {
+      GST_DEBUG_OBJECT (src, "We're EOS now");
+    }
+  }
+}
+
+static GstFlowReturn
+gst_soup_http_src_read_buffer (GstSoupHTTPSrc * src, GstBuffer ** outbuf)
+{
+  gssize read_bytes;
+  GstMapInfo mapinfo;
+  GstBaseSrc *bsrc;
+  GstFlowReturn ret;
+
+  bsrc = GST_BASE_SRC_CAST (src);
+
+  *outbuf = gst_soup_http_src_alloc_buffer (src);
+  if (!*outbuf) {
+    GST_WARNING_OBJECT (src, "Failed to allocate buffer");
+    return GST_FLOW_ERROR;
+  }
+
+  if (!gst_buffer_map (*outbuf, &mapinfo, GST_MAP_WRITE)) {
+    GST_WARNING_OBJECT (src, "Failed to map buffer");
+    return GST_FLOW_ERROR;
+  }
+
+  read_bytes =
+      g_input_stream_read (src->input_stream, mapinfo.data, mapinfo.size,
+      src->cancellable, NULL);
+  GST_DEBUG_OBJECT (src, "Read %" G_GSSIZE_FORMAT " bytes from http input",
+      read_bytes);
+
+  g_mutex_lock (&src->mutex);
+  if (g_cancellable_is_cancelled (src->cancellable)) {
+    gst_buffer_unmap (*outbuf, &mapinfo);
+    gst_buffer_unref (*outbuf);
+    g_mutex_unlock (&src->mutex);
+    return GST_FLOW_FLUSHING;
+  }
+
+  gst_buffer_unmap (*outbuf, &mapinfo);
+  if (read_bytes > 0) {
+    gst_buffer_set_size (*outbuf, read_bytes);
+    GST_BUFFER_OFFSET (*outbuf) = bsrc->segment.position;
+    ret = GST_FLOW_OK;
+    gst_soup_http_src_update_position (src, read_bytes);
+
+    /* Got some data, reset retry counter */
+    src->retry_count = 0;
+
+    gst_soup_http_src_check_update_blocksize (src, read_bytes);
+
+    /* If we're at the end of a range request, read again to let libsoup
+     * finalize the request. This allows to reuse the connection again later,
+     * otherwise we would have to cancel the message and close the connection
+     */
+    if (bsrc->segment.stop != -1
+        && bsrc->segment.position + read_bytes >= bsrc->segment.stop) {
+      guint8 tmp[128];
+
+      g_object_unref (src->msg);
+      src->msg = NULL;
+      src->have_body = TRUE;
+
+      /* This should return immediately as we're at the end of the range */
+      read_bytes =
+          g_input_stream_read (src->input_stream, tmp, sizeof (tmp),
+          src->cancellable, NULL);
+      if (read_bytes > 0)
+        GST_ERROR_OBJECT (src,
+            "Read %" G_GSIZE_FORMAT " bytes after end of range", read_bytes);
+    }
+  } else {
+    gst_buffer_unref (*outbuf);
+    if (read_bytes < 0 ||
+        (src->have_size && src->read_position < src->content_size)) {
+      /* Maybe the server disconnected, retry */
+      ret = GST_FLOW_CUSTOM_ERROR;
+    } else {
+      g_object_unref (src->msg);
+      src->msg = NULL;
+      ret = GST_FLOW_EOS;
+      src->have_body = TRUE;
+    }
+  }
+  g_mutex_unlock (&src->mutex);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_soup_http_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
+{
+  GstSoupHTTPSrc *src;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstEvent *http_headers_event = NULL;
+
+  src = GST_SOUP_HTTP_SRC (psrc);
+
+retry:
+  g_mutex_lock (&src->mutex);
+
+  /* Check for pending position change */
+  if (src->request_position != src->read_position) {
+    if (src->input_stream) {
+      g_input_stream_close (src->input_stream, src->cancellable, NULL);
+      g_object_unref (src->input_stream);
+      src->input_stream = NULL;
+    }
+  }
+
+  if (g_cancellable_is_cancelled (src->cancellable)) {
+    ret = GST_FLOW_FLUSHING;
+    g_mutex_unlock (&src->mutex);
+    goto done;
+  }
+
+  /* If we have no open connection to the server, start one */
+  if (!src->input_stream) {
+    *outbuf = NULL;
+    ret =
+        gst_soup_http_src_do_request (src,
+        src->method ? src->method : SOUP_METHOD_GET);
+    http_headers_event = src->http_headers_event;
+    src->http_headers_event = NULL;
+  }
+  g_mutex_unlock (&src->mutex);
+
+  if (ret == GST_FLOW_OK || ret == GST_FLOW_CUSTOM_ERROR) {
+    if (http_headers_event) {
+      gst_pad_push_event (GST_BASE_SRC_PAD (src), http_headers_event);
+      http_headers_event = NULL;
+    }
+  }
+
+  if (ret == GST_FLOW_OK)
+    ret = gst_soup_http_src_read_buffer (src, outbuf);
+
+done:
+  GST_DEBUG_OBJECT (src, "Returning %d %s", ret, gst_flow_get_name (ret));
+  if (ret != GST_FLOW_OK) {
+    if (http_headers_event)
+      gst_event_unref (http_headers_event);
+
+    g_mutex_lock (&src->mutex);
+    if (src->input_stream) {
+      g_object_unref (src->input_stream);
+      src->input_stream = NULL;
+    }
+    g_mutex_unlock (&src->mutex);
+    if (ret == GST_FLOW_CUSTOM_ERROR) {
+      ret = GST_FLOW_OK;
+      goto retry;
+    }
+  }
+
+  if (ret == GST_FLOW_FLUSHING) {
+    g_mutex_lock (&src->mutex);
+    src->retry_count = 0;
+    g_mutex_unlock (&src->mutex);
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_soup_http_src_start (GstBaseSrc * bsrc)
+{
+  GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (bsrc);
+
+  GST_DEBUG_OBJECT (src, "start(\"%s\")", src->location);
+
+  return gst_soup_http_src_session_open (src);
+}
+
+static gboolean
+gst_soup_http_src_stop (GstBaseSrc * bsrc)
+{
+  GstSoupHTTPSrc *src;
+
+  src = GST_SOUP_HTTP_SRC (bsrc);
+  GST_DEBUG_OBJECT (src, "stop()");
+  if (src->keep_alive && !src->msg && !src->session_is_shared)
+    gst_soup_http_src_cancel_message (src);
+  else
+    gst_soup_http_src_session_close (src);
+
+  gst_soup_http_src_reset (src);
+  return TRUE;
+}
+
+static GstStateChangeReturn
+gst_soup_http_src_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstSoupHTTPSrc *src;
+
+  src = GST_SOUP_HTTP_SRC (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      gst_soup_http_src_session_close (src);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  return ret;
+}
+
+static void
+gst_soup_http_src_set_context (GstElement * element, GstContext * context)
+{
+  GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (element);
+
+  if (g_strcmp0 (gst_context_get_context_type (context),
+          GST_SOUP_SESSION_CONTEXT) == 0) {
+    const GstStructure *s = gst_context_get_structure (context);
+
+    GST_OBJECT_LOCK (src);
+    if (src->external_session)
+      g_object_unref (src->external_session);
+    src->external_session = NULL;
+    gst_structure_get (s, "session", SOUP_TYPE_SESSION, &src->external_session,
+        NULL);
+    src->forced_external_session = FALSE;
+    gst_structure_get (s, "force", G_TYPE_BOOLEAN,
+        &src->forced_external_session, NULL);
+
+    GST_DEBUG_OBJECT (src, "Setting external session %p (force: %d)",
+        src->external_session, src->forced_external_session);
+    GST_OBJECT_UNLOCK (src);
+  }
+
+  GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
+}
+
+/* Interrupt a blocking request. */
+static gboolean
+gst_soup_http_src_unlock (GstBaseSrc * bsrc)
+{
+  GstSoupHTTPSrc *src;
+
+  src = GST_SOUP_HTTP_SRC (bsrc);
+  GST_DEBUG_OBJECT (src, "unlock()");
+
+  gst_soup_http_src_cancel_message (src);
+  return TRUE;
+}
+
+/* Interrupt interrupt. */
+static gboolean
+gst_soup_http_src_unlock_stop (GstBaseSrc * bsrc)
+{
+  GstSoupHTTPSrc *src;
+
+  src = GST_SOUP_HTTP_SRC (bsrc);
+  GST_DEBUG_OBJECT (src, "unlock_stop()");
+
+  g_cancellable_reset (src->cancellable);
+  return TRUE;
+}
+
+static gboolean
+gst_soup_http_src_get_size (GstBaseSrc * bsrc, guint64 * size)
+{
+  GstSoupHTTPSrc *src;
+
+  src = GST_SOUP_HTTP_SRC (bsrc);
+
+  if (src->have_size) {
+    GST_DEBUG_OBJECT (src, "get_size() = %" G_GUINT64_FORMAT,
+        src->content_size);
+    *size = src->content_size;
+    return TRUE;
+  }
+  GST_DEBUG_OBJECT (src, "get_size() = FALSE");
+  return FALSE;
+}
+
+static void
+gst_soup_http_src_check_seekable (GstSoupHTTPSrc * src)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  /* Special case to check if the server allows range requests
+   * before really starting to get data in the buffer creation
+   * loops.
+   */
+  if (!src->got_headers && GST_STATE (src) >= GST_STATE_PAUSED) {
+    g_mutex_lock (&src->mutex);
+    while (!src->got_headers && !g_cancellable_is_cancelled (src->cancellable)
+        && ret == GST_FLOW_OK) {
+      if ((src->msg && src->msg->method != SOUP_METHOD_HEAD)) {
+        /* wait for the current request to finish */
+        g_cond_wait (&src->have_headers_cond, &src->mutex);
+      } else {
+        if (gst_soup_http_src_session_open (src)) {
+          ret = gst_soup_http_src_do_request (src, SOUP_METHOD_HEAD);
+        }
+      }
+    }
+    g_mutex_unlock (&src->mutex);
+  }
+}
+
+static gboolean
+gst_soup_http_src_is_seekable (GstBaseSrc * bsrc)
+{
+  GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (bsrc);
+
+  gst_soup_http_src_check_seekable (src);
+
+  return src->seekable;
+}
+
+static gboolean
+gst_soup_http_src_do_seek (GstBaseSrc * bsrc, GstSegment * segment)
+{
+  GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (bsrc);
+
+  GST_DEBUG_OBJECT (src, "do_seek(%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT
+      ")", segment->start, segment->stop);
+  if (src->read_position == segment->start &&
+      src->request_position == src->read_position &&
+      src->stop_position == segment->stop) {
+    GST_DEBUG_OBJECT (src,
+        "Seek to current read/end position and no seek pending");
+    return TRUE;
+  }
+
+  gst_soup_http_src_check_seekable (src);
+
+  /* If we have no headers we don't know yet if it is seekable or not.
+   * Store the start position and error out later if it isn't */
+  if (src->got_headers && !src->seekable) {
+    GST_WARNING_OBJECT (src, "Not seekable");
+    return FALSE;
+  }
+
+  if (segment->rate < 0.0 || segment->format != GST_FORMAT_BYTES) {
+    GST_WARNING_OBJECT (src, "Invalid seek segment");
+    return FALSE;
+  }
+
+  if (src->have_size && segment->start >= src->content_size) {
+    GST_WARNING_OBJECT (src,
+        "Potentially seeking behind end of file, might EOS immediately");
+  }
+
+  /* Wait for create() to handle the jump in offset. */
+  src->request_position = segment->start;
+  src->stop_position = segment->stop;
+
+  return TRUE;
+}
+
+static gboolean
+gst_soup_http_src_query (GstBaseSrc * bsrc, GstQuery * query)
+{
+  GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (bsrc);
+  gboolean ret;
+  GstSchedulingFlags flags;
+  gint minsize, maxsize, align;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_URI:
+      gst_query_set_uri (query, src->location);
+      if (src->redirection_uri != NULL) {
+        gst_query_set_uri_redirection (query, src->redirection_uri);
+        gst_query_set_uri_redirection_permanent (query,
+            src->redirection_permanent);
+      }
+      ret = TRUE;
+      break;
+    default:
+      ret = FALSE;
+      break;
+  }
+
+  if (!ret)
+    ret = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_SCHEDULING:
+      gst_query_parse_scheduling (query, &flags, &minsize, &maxsize, &align);
+      flags |= GST_SCHEDULING_FLAG_BANDWIDTH_LIMITED;
+      gst_query_set_scheduling (query, flags, minsize, maxsize, align);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_soup_http_src_set_location (GstSoupHTTPSrc * src, const gchar * uri,
+    GError ** error)
+{
+  const char *alt_schemes[] = { "icy://", "icyx://" };
+  guint i;
+
+  if (src->location) {
+    g_free (src->location);
+    src->location = NULL;
+  }
+
+  if (uri == NULL)
+    return FALSE;
+
+  for (i = 0; i < G_N_ELEMENTS (alt_schemes); i++) {
+    if (g_str_has_prefix (uri, alt_schemes[i])) {
+      src->location =
+          g_strdup_printf ("http://%s", uri + strlen (alt_schemes[i]));
+      return TRUE;
+    }
+  }
+
+  if (src->redirection_uri) {
+    g_free (src->redirection_uri);
+    src->redirection_uri = NULL;
+  }
+
+  src->location = g_strdup (uri);
+
+  return TRUE;
+}
+
+static gboolean
+gst_soup_http_src_set_proxy (GstSoupHTTPSrc * src, const gchar * uri)
+{
+  if (src->proxy) {
+    soup_uri_free (src->proxy);
+    src->proxy = NULL;
+  }
+
+  if (uri == NULL || *uri == '\0')
+    return TRUE;
+
+  if (g_strstr_len (uri, -1, "://")) {
+    src->proxy = soup_uri_new (uri);
+  } else {
+    gchar *new_uri = g_strconcat ("http://", uri, NULL);
+
+    src->proxy = soup_uri_new (new_uri);
+    g_free (new_uri);
+  }
+
+  return (src->proxy != NULL);
+}
+
+static guint
+gst_soup_http_src_uri_get_type (GType type)
+{
+  return GST_URI_SRC;
+}
+
+static const gchar *const *
+gst_soup_http_src_uri_get_protocols (GType type)
+{
+  static const gchar *protocols[] = { "http", "https", "icy", "icyx", NULL };
+
+  return protocols;
+}
+
+static gchar *
+gst_soup_http_src_uri_get_uri (GstURIHandler * handler)
+{
+  GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (handler);
+
+  /* FIXME: make thread-safe */
+  return g_strdup (src->location);
+}
+
+static gboolean
+gst_soup_http_src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+    GError ** error)
+{
+  GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (handler);
+
+  return gst_soup_http_src_set_location (src, uri, error);
+}
+
+static void
+gst_soup_http_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+  iface->get_type = gst_soup_http_src_uri_get_type;
+  iface->get_protocols = gst_soup_http_src_uri_get_protocols;
+  iface->get_uri = gst_soup_http_src_uri_get_uri;
+  iface->set_uri = gst_soup_http_src_uri_set_uri;
+}
diff --git a/ext/soup/gstsouphttpsrc.h b/ext/soup/gstsouphttpsrc.h
new file mode 100644
index 0000000..06851dd
--- /dev/null
+++ b/ext/soup/gstsouphttpsrc.h
@@ -0,0 +1,129 @@
+/* GStreamer
+ * Copyright (C) 2007-2008 Wouter Cloetens <wouter@mind.be>
+ *
+ * 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 
+ */
+
+#ifndef __GST_SOUP_HTTP_SRC_H__
+#define __GST_SOUP_HTTP_SRC_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#include <libsoup/soup.h>
+
+#define GST_TYPE_SOUP_HTTP_SRC \
+  (gst_soup_http_src_get_type())
+#define GST_SOUP_HTTP_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SOUP_HTTP_SRC,GstSoupHTTPSrc))
+#define GST_SOUP_HTTP_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), \
+      GST_TYPE_SOUP_HTTP_SRC,GstSoupHTTPSrcClass))
+#define GST_IS_SOUP_HTTP_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SOUP_HTTP_SRC))
+#define GST_IS_SOUP_HTTP_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SOUP_HTTP_SRC))
+
+typedef struct _GstSoupHTTPSrc GstSoupHTTPSrc;
+typedef struct _GstSoupHTTPSrcClass GstSoupHTTPSrcClass;
+
+typedef enum {
+  GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_IDLE,
+  GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_QUEUED,
+  GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING,
+  GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_CANCELLED,
+} GstSoupHTTPSrcSessionIOStatus;
+
+struct _GstSoupHTTPSrc {
+  GstPushSrc element;
+
+  gchar *location;             /* Full URI. */
+  gchar *redirection_uri;      /* Full URI after redirections. */
+  gboolean redirection_permanent; /* Permanent or temporary redirect? */
+  gchar *user_agent;           /* User-Agent HTTP header. */
+  gboolean automatic_redirect; /* Follow redirects. */
+  SoupURI *proxy;              /* HTTP proxy URI. */
+  gchar *user_id;              /* Authentication user id for location URI. */
+  gchar *user_pw;              /* Authentication user password for location URI. */
+  gchar *proxy_id;             /* Authentication user id for proxy URI. */
+  gchar *proxy_pw;             /* Authentication user password for proxy URI. */
+  gchar **cookies;             /* HTTP request cookies. */
+  SoupSession *session;        /* Async context. */
+  gboolean session_is_shared;
+  SoupSession *external_session; /* Shared via GstContext */
+  gboolean forced_external_session; /* If session was explicitly set from application */
+  SoupMessage *msg;            /* Request message. */
+  gint retry_count;            /* Number of retries since we received data */
+  gint max_retries;            /* Maximum number of retries */
+  gchar *method;               /* HTTP method */
+
+  gboolean got_headers;        /* Already received headers from the server */
+  gboolean have_size;          /* Received and parsed Content-Length
+                                  header. */
+  guint64 content_size;        /* Value of Content-Length header. */
+  guint64 read_position;       /* Current position. */
+  gboolean seekable;           /* FALSE if the server does not support
+                                  Range. */
+  guint64 request_position;    /* Seek to this position. */
+  guint64 stop_position;       /* Stop at this position. */
+  gboolean have_body;          /* Indicates if it has just been signaled the
+                                * end of the message body. This is used to
+                                * decide if an out of range request should be
+                                * handled as an error or EOS when the content
+                                * size is unknown */
+  gboolean keep_alive;         /* Use keep-alive sessions */
+  gboolean ssl_strict;
+  gchar *ssl_ca_file;
+  gboolean ssl_use_system_ca_file;
+  GTlsDatabase *tls_database;
+  GTlsInteraction *tls_interaction;
+
+  GCancellable *cancellable;
+  GInputStream *input_stream;
+
+  gint reduce_blocksize_count;
+  gint increase_blocksize_count;
+  guint minimum_blocksize;
+
+  /* Shoutcast/icecast metadata extraction handling. */
+  gboolean iradio_mode;
+  GstCaps *src_caps;
+  gchar *iradio_name;
+  gchar *iradio_genre;
+  gchar *iradio_url;
+
+  GstStructure *extra_headers;
+
+  SoupLoggerLogLevel log_level;/* Soup HTTP session logger level */
+
+  gboolean compress;
+
+  guint timeout;
+
+  GMutex mutex;
+  GCond have_headers_cond;
+
+  GstEvent *http_headers_event;
+};
+
+struct _GstSoupHTTPSrcClass {
+  GstPushSrcClass parent_class;
+};
+
+GType gst_soup_http_src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_SOUP_HTTP_SRC_H__ */
+
diff --git a/ext/soup/gstsouputils.c b/ext/soup/gstsouputils.c
new file mode 100644
index 0000000..72c1ef1
--- /dev/null
+++ b/ext/soup/gstsouputils.c
@@ -0,0 +1,97 @@
+/* GStreamer
+ *
+ * Copyright (C) 2014 Samsung Electronics. All rights reserved.
+ *     @Author: Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more
+ */
+
+
+#include <glib.h>
+#include <gst/gst.h>
+#include <libsoup/soup.h>
+#include "gstsouputils.h"
+
+/**
+ * Soup logger funcs
+ */
+
+GST_DEBUG_CATEGORY_EXTERN (soup_utils_debug);
+#define GST_CAT_DEFAULT soup_utils_debug
+
+static inline gchar
+gst_soup_util_log_make_level_tag (SoupLoggerLogLevel level)
+{
+  gchar c;
+
+  if (G_UNLIKELY ((gint) level > 9))
+    return '?';
+
+  switch (level) {
+    case SOUP_LOGGER_LOG_MINIMAL:
+      c = 'M';
+      break;
+    case SOUP_LOGGER_LOG_HEADERS:
+      c = 'H';
+      break;
+    case SOUP_LOGGER_LOG_BODY:
+      c = 'B';
+      break;
+    default:
+      /* Unknown level. If this is hit libsoup likely added a new
+       * log level to SoupLoggerLogLevel and it should be added
+       * as a case */
+      c = level + '0';
+      break;
+  }
+  return c;
+}
+
+static void
+gst_soup_util_log_printer_cb (SoupLogger G_GNUC_UNUSED * logger,
+    SoupLoggerLogLevel level, char direction, const char *data,
+    gpointer user_data)
+{
+  gchar c;
+  c = gst_soup_util_log_make_level_tag (level);
+  GST_TRACE_OBJECT (GST_ELEMENT (user_data), "HTTP_SESSION(%c): %c %s", c,
+      direction, data);
+}
+
+void
+gst_soup_util_log_setup (SoupSession * session, SoupLoggerLogLevel level,
+    GstElement * element)
+{
+  SoupLogger *logger;
+
+  if (!level) {
+    GST_INFO_OBJECT (element, "Not attaching a logger with level 0");
+    return;
+  }
+
+  g_assert (session && element);
+
+  if (gst_debug_category_get_threshold (GST_CAT_DEFAULT)
+      < GST_LEVEL_TRACE) {
+    GST_INFO_OBJECT (element, "Not setting up HTTP session logger. "
+        "Need at least GST_LEVEL_TRACE");
+    return;
+  }
+
+  /* Create a new logger and set body_size_limit to -1 (no limit) */
+  logger = soup_logger_new (level, -1);
+  soup_logger_set_printer (logger, gst_soup_util_log_printer_cb,
+      gst_object_ref (element), (GDestroyNotify) gst_object_unref);
+
+  /* Attach logger to session */
+  soup_session_add_feature (session, SOUP_SESSION_FEATURE (logger));
+  g_object_unref (logger);
+}
diff --git a/ext/soup/gstsouputils.h b/ext/soup/gstsouputils.h
new file mode 100644
index 0000000..e73525d
--- /dev/null
+++ b/ext/soup/gstsouputils.h
@@ -0,0 +1,31 @@
+/* GStreamer
+ *
+ * Copyright (C) 2014 Samsung Electronics. All rights reserved.
+ *     @Author: Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more
+ */
+
+#ifndef __GST_SOUP_UTILS_H__
+#define __GST_SOUP_UTILS_H__
+
+#include <glib.h>
+#include <gst/gst.h>
+#include <libsoup/soup.h>
+
+G_BEGIN_DECLS
+
+void gst_soup_util_log_setup (SoupSession * session, SoupLoggerLogLevel level,
+    GstElement * element);
+
+G_END_DECLS
+
+#endif
diff --git a/ext/soup/meson.build b/ext/soup/meson.build
new file mode 100644
index 0000000..3fd7129
--- /dev/null
+++ b/ext/soup/meson.build
@@ -0,0 +1,25 @@
+soup_sources = [
+  'gstsouphttpsrc.c',
+  'gstsouphttpclientsink.c',
+  'gstsouputils.c',
+  'gstsoup.c',
+]
+
+soup_args = [
+  '-DSOUP_VERSION_MIN_REQUIRED=SOUP_VERSION_2_48',
+  '-DSOUP_VERSION_MAX_ALLOWED=SOUP_DEPRECATED_IN_2_48',
+]
+
+libsoup_dep = dependency('libsoup-2.4', version : '>=2.48', required : false)
+
+if libsoup_dep.found()
+  gstsouphttpsrc = library('gstsoup',
+    soup_sources,
+    c_args : gst_plugins_good_args + soup_args,
+    link_args : noseh_link_args,
+    include_directories : [configinc, libsinc],
+    dependencies : [gst_dep, gstbase_dep, gsttag_dep, libsoup_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/ext/speex/Makefile.am b/ext/speex/Makefile.am
new file mode 100644
index 0000000..930f594
--- /dev/null
+++ b/ext/speex/Makefile.am
@@ -0,0 +1,17 @@
+plugin_LTLIBRARIES = libgstspeex.la
+
+libgstspeex_la_SOURCES = gstspeex.c gstspeexdec.c gstspeexenc.c
+libgstspeex_la_CFLAGS = -DGST_USE_UNSTABLE_API \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS) \
+	$(SPEEX_CFLAGS)
+libgstspeex_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) \
+	-lgsttag-$(GST_API_VERSION) -lgstaudio-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) \
+	$(GST_LIBS) \
+	$(SPEEX_LIBS)
+libgstspeex_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(LIBM)
+
+noinst_HEADERS = gstspeexenc.h gstspeexdec.h 
diff --git a/ext/speex/gstspeex.c b/ext/speex/gstspeex.c
new file mode 100644
index 0000000..9688cd5
--- /dev/null
+++ b/ext/speex/gstspeex.c
@@ -0,0 +1,49 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstspeexdec.h"
+#include "gstspeexenc.h"
+
+#include <gst/tag/tag.h>
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+
+  if (!gst_element_register (plugin, "speexenc", GST_RANK_PRIMARY,
+          GST_TYPE_SPEEX_ENC))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "speexdec", GST_RANK_PRIMARY,
+          GST_TYPE_SPEEX_DEC))
+    return FALSE;
+
+  gst_tag_register_musicbrainz_tags ();
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    speex,
+    "Speex plugin library",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/speex/gstspeexdec.c b/ext/speex/gstspeexdec.c
new file mode 100644
index 0000000..cc123ce
--- /dev/null
+++ b/ext/speex/gstspeexdec.c
@@ -0,0 +1,574 @@
+/* GStreamer
+ * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-speexdec
+ * @see_also: speexenc, oggdemux
+ *
+ * This element decodes a Speex stream to raw integer audio.
+ * <ulink url="http://www.speex.org/">Speex</ulink> is a royalty-free
+ * audio codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
+ * Foundation</ulink>.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -v filesrc location=speex.ogg ! oggdemux ! speexdec ! audioconvert ! audioresample ! alsasink
+ * ]| Decode an Ogg/Speex file. To create an Ogg/Speex file refer to the
+ * documentation of speexenc.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "gstspeexdec.h"
+#include <stdlib.h>
+#include <string.h>
+#include <gst/tag/tag.h>
+#include <gst/audio/audio.h>
+
+GST_DEBUG_CATEGORY_STATIC (speexdec_debug);
+#define GST_CAT_DEFAULT speexdec_debug
+
+#define DEFAULT_ENH   TRUE
+
+enum
+{
+  ARG_0,
+  ARG_ENH
+};
+
+#define FORMAT_STR GST_AUDIO_NE(S16)
+
+static GstStaticPadTemplate speex_dec_src_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " FORMAT_STR ", "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 6000, 48000 ], " "channels = (int) [ 1, 2 ]")
+    );
+
+static GstStaticPadTemplate speex_dec_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-speex")
+    );
+
+#define gst_speex_dec_parent_class parent_class
+G_DEFINE_TYPE (GstSpeexDec, gst_speex_dec, GST_TYPE_AUDIO_DECODER);
+
+static gboolean gst_speex_dec_start (GstAudioDecoder * dec);
+static gboolean gst_speex_dec_stop (GstAudioDecoder * dec);
+static gboolean gst_speex_dec_set_format (GstAudioDecoder * bdec,
+    GstCaps * caps);
+static GstFlowReturn gst_speex_dec_handle_frame (GstAudioDecoder * dec,
+    GstBuffer * buffer);
+
+static void gst_speex_dec_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_speex_dec_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+
+static void
+gst_speex_dec_class_init (GstSpeexDecClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstAudioDecoderClass *base_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  base_class = (GstAudioDecoderClass *) klass;
+
+  gobject_class->set_property = gst_speex_dec_set_property;
+  gobject_class->get_property = gst_speex_dec_get_property;
+
+  base_class->start = GST_DEBUG_FUNCPTR (gst_speex_dec_start);
+  base_class->stop = GST_DEBUG_FUNCPTR (gst_speex_dec_stop);
+  base_class->set_format = GST_DEBUG_FUNCPTR (gst_speex_dec_set_format);
+  base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_speex_dec_handle_frame);
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ENH,
+      g_param_spec_boolean ("enh", "Enh", "Enable perceptual enhancement",
+          DEFAULT_ENH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &speex_dec_src_factory);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &speex_dec_sink_factory);
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Speex audio decoder", "Codec/Decoder/Audio",
+      "decode speex streams to audio", "Wim Taymans <wim@fluendo.com>");
+
+  GST_DEBUG_CATEGORY_INIT (speexdec_debug, "speexdec", 0,
+      "speex decoding element");
+}
+
+static void
+gst_speex_dec_reset (GstSpeexDec * dec)
+{
+  dec->packetno = 0;
+  dec->frame_size = 0;
+  dec->frame_duration = 0;
+  dec->mode = NULL;
+  free (dec->header);
+  dec->header = NULL;
+  speex_bits_destroy (&dec->bits);
+  speex_bits_set_bit_buffer (&dec->bits, NULL, 0);
+
+  gst_buffer_replace (&dec->streamheader, NULL);
+  gst_buffer_replace (&dec->vorbiscomment, NULL);
+
+  if (dec->stereo) {
+    speex_stereo_state_destroy (dec->stereo);
+    dec->stereo = NULL;
+  }
+
+  if (dec->state) {
+    speex_decoder_destroy (dec->state);
+    dec->state = NULL;
+  }
+}
+
+static void
+gst_speex_dec_init (GstSpeexDec * dec)
+{
+  gst_audio_decoder_set_needs_format (GST_AUDIO_DECODER (dec), TRUE);
+  gst_audio_decoder_set_use_default_pad_acceptcaps (GST_AUDIO_DECODER_CAST
+      (dec), TRUE);
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_DECODER_SINK_PAD (dec));
+
+  dec->enh = DEFAULT_ENH;
+
+  gst_speex_dec_reset (dec);
+}
+
+static gboolean
+gst_speex_dec_start (GstAudioDecoder * dec)
+{
+  GstSpeexDec *sd = GST_SPEEX_DEC (dec);
+
+  GST_DEBUG_OBJECT (dec, "start");
+  gst_speex_dec_reset (sd);
+
+  /* we know about concealment */
+  gst_audio_decoder_set_plc_aware (dec, TRUE);
+
+  return TRUE;
+}
+
+static gboolean
+gst_speex_dec_stop (GstAudioDecoder * dec)
+{
+  GstSpeexDec *sd = GST_SPEEX_DEC (dec);
+
+  GST_DEBUG_OBJECT (dec, "stop");
+  gst_speex_dec_reset (sd);
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_speex_dec_parse_header (GstSpeexDec * dec, GstBuffer * buf)
+{
+  GstMapInfo map;
+  GstAudioInfo info;
+  static const GstAudioChannelPosition chan_pos[2][2] = {
+    {GST_AUDIO_CHANNEL_POSITION_MONO},
+    {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}
+  };
+
+  /* get the header */
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  dec->header = speex_packet_to_header ((gchar *) map.data, map.size);
+  gst_buffer_unmap (buf, &map);
+
+  if (!dec->header)
+    goto no_header;
+
+  if (dec->header->mode >= SPEEX_NB_MODES || dec->header->mode < 0)
+    goto mode_too_old;
+
+  dec->mode = speex_lib_get_mode (dec->header->mode);
+
+  /* initialize the decoder */
+  dec->state = speex_decoder_init (dec->mode);
+  if (!dec->state)
+    goto init_failed;
+
+  speex_decoder_ctl (dec->state, SPEEX_SET_ENH, &dec->enh);
+  speex_decoder_ctl (dec->state, SPEEX_GET_FRAME_SIZE, &dec->frame_size);
+
+  if (dec->header->nb_channels != 1) {
+    dec->stereo = speex_stereo_state_init ();
+    dec->callback.callback_id = SPEEX_INBAND_STEREO;
+    dec->callback.func = speex_std_stereo_request_handler;
+    dec->callback.data = dec->stereo;
+    speex_decoder_ctl (dec->state, SPEEX_SET_HANDLER, &dec->callback);
+  }
+
+  speex_decoder_ctl (dec->state, SPEEX_SET_SAMPLING_RATE, &dec->header->rate);
+
+  dec->frame_duration = gst_util_uint64_scale_int (dec->frame_size,
+      GST_SECOND, dec->header->rate);
+
+  speex_bits_init (&dec->bits);
+
+  /* set caps */
+  gst_audio_info_init (&info);
+  gst_audio_info_set_format (&info,
+      GST_AUDIO_FORMAT_S16,
+      dec->header->rate,
+      dec->header->nb_channels, chan_pos[dec->header->nb_channels - 1]);
+
+  if (!gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (dec), &info))
+    goto nego_failed;
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+no_header:
+  {
+    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
+        (NULL), ("couldn't read header"));
+    return GST_FLOW_ERROR;
+  }
+mode_too_old:
+  {
+    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
+        (NULL),
+        ("Mode number %d does not (yet/any longer) exist in this version",
+            dec->header->mode));
+    return GST_FLOW_ERROR;
+  }
+init_failed:
+  {
+    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
+        (NULL), ("couldn't initialize decoder"));
+    return GST_FLOW_ERROR;
+  }
+nego_failed:
+  {
+    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
+        (NULL), ("couldn't negotiate format"));
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+}
+
+static GstFlowReturn
+gst_speex_dec_parse_comments (GstSpeexDec * dec, GstBuffer * buf)
+{
+  GstTagList *list;
+  gchar *ver, *encoder = NULL;
+
+  list = gst_tag_list_from_vorbiscomment_buffer (buf, NULL, 0, &encoder);
+
+  if (!list) {
+    GST_WARNING_OBJECT (dec, "couldn't decode comments");
+    list = gst_tag_list_new_empty ();
+  }
+
+  if (encoder) {
+    gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+        GST_TAG_ENCODER, encoder, NULL);
+  }
+
+  gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+      GST_TAG_AUDIO_CODEC, "Speex", NULL);
+
+  ver = g_strndup (dec->header->speex_version, SPEEX_HEADER_VERSION_LENGTH);
+  g_strstrip (ver);
+
+  if (ver != NULL && *ver != '\0') {
+    gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+        GST_TAG_ENCODER_VERSION, ver, NULL);
+  }
+
+  if (dec->header->bitrate > 0) {
+    gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+        GST_TAG_BITRATE, (guint) dec->header->bitrate, NULL);
+  }
+
+  GST_INFO_OBJECT (dec, "tags: %" GST_PTR_FORMAT, list);
+
+  gst_audio_decoder_merge_tags (GST_AUDIO_DECODER (dec), list,
+      GST_TAG_MERGE_REPLACE);
+  gst_tag_list_unref (list);
+
+  g_free (encoder);
+  g_free (ver);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_speex_dec_set_format (GstAudioDecoder * bdec, GstCaps * caps)
+{
+  GstSpeexDec *dec = GST_SPEEX_DEC (bdec);
+  gboolean ret = TRUE;
+  GstStructure *s;
+  const GValue *streamheader;
+
+  s = gst_caps_get_structure (caps, 0);
+  if ((streamheader = gst_structure_get_value (s, "streamheader")) &&
+      G_VALUE_HOLDS (streamheader, GST_TYPE_ARRAY) &&
+      gst_value_array_get_size (streamheader) >= 2) {
+    const GValue *header, *vorbiscomment;
+    GstBuffer *buf;
+    GstFlowReturn res = GST_FLOW_OK;
+
+    header = gst_value_array_get_value (streamheader, 0);
+    if (header && G_VALUE_HOLDS (header, GST_TYPE_BUFFER)) {
+      buf = gst_value_get_buffer (header);
+      res = gst_speex_dec_parse_header (dec, buf);
+      if (res != GST_FLOW_OK)
+        goto done;
+      gst_buffer_replace (&dec->streamheader, buf);
+    }
+
+    vorbiscomment = gst_value_array_get_value (streamheader, 1);
+    if (vorbiscomment && G_VALUE_HOLDS (vorbiscomment, GST_TYPE_BUFFER)) {
+      buf = gst_value_get_buffer (vorbiscomment);
+      res = gst_speex_dec_parse_comments (dec, buf);
+      if (res != GST_FLOW_OK)
+        goto done;
+      gst_buffer_replace (&dec->vorbiscomment, buf);
+    }
+  }
+
+done:
+  return ret;
+}
+
+static GstFlowReturn
+gst_speex_dec_parse_data (GstSpeexDec * dec, GstBuffer * buf)
+{
+  GstFlowReturn res = GST_FLOW_OK;
+  gint i, fpp;
+  SpeexBits *bits;
+  GstMapInfo map;
+
+  if (!dec->frame_duration)
+    goto not_negotiated;
+
+  if (G_LIKELY (gst_buffer_get_size (buf))) {
+    /* send data to the bitstream */
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    speex_bits_read_from (&dec->bits, (gchar *) map.data, map.size);
+    gst_buffer_unmap (buf, &map);
+
+    fpp = dec->header->frames_per_packet;
+    bits = &dec->bits;
+
+    GST_DEBUG_OBJECT (dec, "received buffer of size %" G_GSIZE_FORMAT
+        ", fpp %d, %d bits", map.size, fpp, speex_bits_remaining (bits));
+  } else {
+    /* FIXME ? actually consider how much concealment is needed */
+    /* concealment data, pass NULL as the bits parameters */
+    GST_DEBUG_OBJECT (dec, "creating concealment data");
+    fpp = dec->header->frames_per_packet;
+    bits = NULL;
+  }
+
+  /* now decode each frame, catering for unknown number of them (e.g. rtp) */
+  for (i = 0; i < fpp; i++) {
+    GstBuffer *outbuf;
+    gboolean corrupted = FALSE;
+    gint ret;
+
+    GST_LOG_OBJECT (dec, "decoding frame %d/%d, %d bits remaining", i, fpp,
+        bits ? speex_bits_remaining (bits) : -1);
+#if 0
+    res =
+        gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec),
+        GST_BUFFER_OFFSET_NONE, dec->frame_size * dec->header->nb_channels * 2,
+        GST_PAD_CAPS (GST_AUDIO_DECODER_SRC_PAD (dec)), &outbuf);
+
+    if (res != GST_FLOW_OK) {
+      GST_DEBUG_OBJECT (dec, "buf alloc flow: %s", gst_flow_get_name (res));
+      return res;
+    }
+#endif
+    /* FIXME, we can use a bufferpool because we have fixed size buffers. We
+     * could also use an allocator */
+    outbuf =
+        gst_buffer_new_allocate (NULL,
+        dec->frame_size * dec->header->nb_channels * 2, NULL);
+
+    gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+    ret = speex_decode_int (dec->state, bits, (spx_int16_t *) map.data);
+
+    if (ret == -1) {
+      /* uh? end of stream */
+      GST_WARNING_OBJECT (dec, "Unexpected end of stream found");
+      corrupted = TRUE;
+    } else if (ret == -2) {
+      GST_WARNING_OBJECT (dec, "Decoding error: corrupted stream?");
+      corrupted = TRUE;
+    }
+
+    if (bits && speex_bits_remaining (bits) < 0) {
+      GST_WARNING_OBJECT (dec, "Decoding overflow: corrupted stream?");
+      corrupted = TRUE;
+    }
+    if (dec->header->nb_channels == 2)
+      speex_decode_stereo_int ((spx_int16_t *) map.data, dec->frame_size,
+          dec->stereo);
+
+    gst_buffer_unmap (outbuf, &map);
+
+    if (!corrupted) {
+      res = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), outbuf, 1);
+    } else {
+      res = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), NULL, 1);
+      gst_buffer_unref (outbuf);
+    }
+
+    if (res != GST_FLOW_OK) {
+      GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (res));
+      break;
+    }
+  }
+
+  return res;
+
+  /* ERRORS */
+not_negotiated:
+  {
+    GST_ELEMENT_ERROR (dec, CORE, NEGOTIATION, (NULL),
+        ("decoder not initialized"));
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+}
+
+static gboolean
+memcmp_buffers (GstBuffer * buf1, GstBuffer * buf2)
+{
+  GstMapInfo map;
+  gsize size1, size2;
+  gboolean res;
+
+  size1 = gst_buffer_get_size (buf1);
+  size2 = gst_buffer_get_size (buf2);
+
+  if (size1 != size2)
+    return FALSE;
+
+  gst_buffer_map (buf1, &map, GST_MAP_READ);
+  res = gst_buffer_memcmp (buf2, 0, map.data, map.size) == 0;
+  gst_buffer_unmap (buf1, &map);
+
+  return res;
+}
+
+static GstFlowReturn
+gst_speex_dec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buf)
+{
+  GstFlowReturn res;
+  GstSpeexDec *dec;
+
+  /* no fancy draining */
+  if (G_UNLIKELY (!buf))
+    return GST_FLOW_OK;
+
+  dec = GST_SPEEX_DEC (bdec);
+
+  /* If we have the streamheader and vorbiscomment from the caps already
+   * ignore them here */
+  if (dec->streamheader && dec->vorbiscomment) {
+    if (memcmp_buffers (dec->streamheader, buf)) {
+      GST_DEBUG_OBJECT (dec, "found streamheader");
+      gst_audio_decoder_finish_frame (bdec, NULL, 1);
+      res = GST_FLOW_OK;
+    } else if (memcmp_buffers (dec->vorbiscomment, buf)) {
+      GST_DEBUG_OBJECT (dec, "found vorbiscomments");
+      gst_audio_decoder_finish_frame (bdec, NULL, 1);
+      res = GST_FLOW_OK;
+    } else {
+      res = gst_speex_dec_parse_data (dec, buf);
+    }
+  } else {
+    /* Otherwise fall back to packet counting and assume that the
+     * first two packets are the headers. */
+    switch (dec->packetno) {
+      case 0:
+        GST_DEBUG_OBJECT (dec, "counted streamheader");
+        res = gst_speex_dec_parse_header (dec, buf);
+        gst_audio_decoder_finish_frame (bdec, NULL, 1);
+        break;
+      case 1:
+        GST_DEBUG_OBJECT (dec, "counted vorbiscomments");
+        res = gst_speex_dec_parse_comments (dec, buf);
+        gst_audio_decoder_finish_frame (bdec, NULL, 1);
+        break;
+      default:
+      {
+        res = gst_speex_dec_parse_data (dec, buf);
+        break;
+      }
+    }
+  }
+
+  dec->packetno++;
+
+  return res;
+}
+
+static void
+gst_speex_dec_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstSpeexDec *speexdec;
+
+  speexdec = GST_SPEEX_DEC (object);
+
+  switch (prop_id) {
+    case ARG_ENH:
+      g_value_set_boolean (value, speexdec->enh);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_speex_dec_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstSpeexDec *speexdec;
+
+  speexdec = GST_SPEEX_DEC (object);
+
+  switch (prop_id) {
+    case ARG_ENH:
+      speexdec->enh = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/ext/speex/gstspeexdec.h b/ext/speex/gstspeexdec.h
new file mode 100644
index 0000000..5e1e171
--- /dev/null
+++ b/ext/speex/gstspeexdec.h
@@ -0,0 +1,76 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_SPEEX_DEC_H__
+#define __GST_SPEEX_DEC_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiodecoder.h>
+
+#include <speex/speex.h>
+#include <speex/speex_callbacks.h>
+#include <speex/speex_header.h>
+#include <speex/speex_stereo.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SPEEX_DEC \
+  (gst_speex_dec_get_type())
+#define GST_SPEEX_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPEEX_DEC,GstSpeexDec))
+#define GST_SPEEX_DEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPEEX_DEC,GstSpeexDecClass))
+#define GST_IS_SPEEX_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPEEX_DEC))
+#define GST_IS_SPEEX_DEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPEEX_DEC))
+
+typedef struct _GstSpeexDec GstSpeexDec;
+typedef struct _GstSpeexDecClass GstSpeexDecClass;
+
+struct _GstSpeexDec {
+  GstAudioDecoder   element;
+
+  void                  *state;
+  SpeexStereoState      *stereo;
+  const SpeexMode       *mode;
+  SpeexHeader           *header;
+  SpeexCallback         callback;
+  SpeexBits             bits;
+
+  gboolean              enh;
+
+  gint                  frame_size;
+  GstClockTime          frame_duration;
+  guint64               packetno;
+
+  GstBuffer             *streamheader;
+  GstBuffer             *vorbiscomment;
+};
+
+struct _GstSpeexDecClass {
+  GstAudioDecoderClass parent_class;
+};
+
+GType gst_speex_dec_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_SPEEX_DEC_H__ */
diff --git a/ext/speex/gstspeexenc.c b/ext/speex/gstspeexenc.c
new file mode 100644
index 0000000..4266af6
--- /dev/null
+++ b/ext/speex/gstspeexenc.c
@@ -0,0 +1,844 @@
+/* GStreamer Speex Encoder
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-speexenc
+ * @see_also: speexdec, oggmux
+ *
+ * This element encodes audio as a Speex stream.
+ * <ulink url="http://www.speex.org/">Speex</ulink> is a royalty-free
+ * audio codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
+ * Foundation</ulink>.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc num-buffers=100 ! speexenc ! oggmux ! filesink location=beep.ogg
+ * ]| Encode an Ogg/Speex file.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#include <speex/speex.h>
+#include <speex/speex_stereo.h>
+
+#include <gst/gsttagsetter.h>
+#include <gst/tag/tag.h>
+#include <gst/audio/audio.h>
+#include "gstspeexenc.h"
+
+GST_DEBUG_CATEGORY_STATIC (speexenc_debug);
+#define GST_CAT_DEFAULT speexenc_debug
+
+#define FORMAT_STR GST_AUDIO_NE(S16)
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " FORMAT_STR ", "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 6000, 48000 ], "
+        "channels = (int) 1; "
+        "audio/x-raw, "
+        "format = (string) " FORMAT_STR ", "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 6000, 48000 ], "
+        "channels = (int) 2, " "channel-mask = (bitmask) 0x3")
+    );
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-speex, "
+        "rate = (int) [ 6000, 48000 ], " "channels = (int) [ 1, 2]")
+    );
+
+#define DEFAULT_QUALITY         8.0
+#define DEFAULT_BITRATE         0
+#define DEFAULT_MODE            GST_SPEEX_ENC_MODE_AUTO
+#define DEFAULT_VBR             FALSE
+#define DEFAULT_ABR             0
+#define DEFAULT_VAD             FALSE
+#define DEFAULT_DTX             FALSE
+#define DEFAULT_COMPLEXITY      3
+#define DEFAULT_NFRAMES         1
+
+enum
+{
+  PROP_0,
+  PROP_QUALITY,
+  PROP_BITRATE,
+  PROP_MODE,
+  PROP_VBR,
+  PROP_ABR,
+  PROP_VAD,
+  PROP_DTX,
+  PROP_COMPLEXITY,
+  PROP_NFRAMES,
+  PROP_LAST_MESSAGE
+};
+
+#define GST_TYPE_SPEEX_ENC_MODE (gst_speex_enc_mode_get_type())
+static GType
+gst_speex_enc_mode_get_type (void)
+{
+  static GType speex_enc_mode_type = 0;
+  static const GEnumValue speex_enc_modes[] = {
+    {GST_SPEEX_ENC_MODE_AUTO, "Auto", "auto"},
+    {GST_SPEEX_ENC_MODE_UWB, "Ultra Wide Band", "uwb"},
+    {GST_SPEEX_ENC_MODE_WB, "Wide Band", "wb"},
+    {GST_SPEEX_ENC_MODE_NB, "Narrow Band", "nb"},
+    {0, NULL, NULL},
+  };
+  if (G_UNLIKELY (speex_enc_mode_type == 0)) {
+    speex_enc_mode_type = g_enum_register_static ("GstSpeexEncMode",
+        speex_enc_modes);
+  }
+  return speex_enc_mode_type;
+}
+
+static void gst_speex_enc_finalize (GObject * object);
+
+static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
+
+static void gst_speex_enc_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_speex_enc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+
+static GstFlowReturn gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf);
+
+static gboolean gst_speex_enc_start (GstAudioEncoder * enc);
+static gboolean gst_speex_enc_stop (GstAudioEncoder * enc);
+static gboolean gst_speex_enc_set_format (GstAudioEncoder * enc,
+    GstAudioInfo * info);
+static GstFlowReturn gst_speex_enc_handle_frame (GstAudioEncoder * enc,
+    GstBuffer * in_buf);
+static gboolean gst_speex_enc_sink_event (GstAudioEncoder * enc,
+    GstEvent * event);
+
+#define gst_speex_enc_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstSpeexEnc, gst_speex_enc, GST_TYPE_AUDIO_ENCODER,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
+    G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
+
+static void
+gst_speex_enc_class_init (GstSpeexEncClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstAudioEncoderClass *base_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  base_class = (GstAudioEncoderClass *) klass;
+
+  gobject_class->finalize = gst_speex_enc_finalize;
+  gobject_class->set_property = gst_speex_enc_set_property;
+  gobject_class->get_property = gst_speex_enc_get_property;
+
+  base_class->start = GST_DEBUG_FUNCPTR (gst_speex_enc_start);
+  base_class->stop = GST_DEBUG_FUNCPTR (gst_speex_enc_stop);
+  base_class->set_format = GST_DEBUG_FUNCPTR (gst_speex_enc_set_format);
+  base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_speex_enc_handle_frame);
+  base_class->sink_event = GST_DEBUG_FUNCPTR (gst_speex_enc_sink_event);
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
+      g_param_spec_float ("quality", "Quality", "Encoding quality",
+          0.0, 10.0, DEFAULT_QUALITY,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
+      g_param_spec_int ("bitrate", "Encoding Bit-rate",
+          "Specify an encoding bit-rate (in bps). (0 = automatic)",
+          0, G_MAXINT, DEFAULT_BITRATE,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MODE,
+      g_param_spec_enum ("mode", "Mode", "The encoding mode",
+          GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
+      g_param_spec_boolean ("vbr", "VBR",
+          "Enable variable bit-rate", DEFAULT_VBR,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
+      g_param_spec_int ("abr", "ABR",
+          "Enable average bit-rate (0 = disabled)",
+          0, G_MAXINT, DEFAULT_ABR,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
+      g_param_spec_boolean ("vad", "VAD",
+          "Enable voice activity detection", DEFAULT_VAD,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
+      g_param_spec_boolean ("dtx", "DTX",
+          "Enable discontinuous transmission", DEFAULT_DTX,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
+      g_param_spec_int ("complexity", "Complexity",
+          "Set encoding complexity",
+          0, G_MAXINT, DEFAULT_COMPLEXITY,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
+      g_param_spec_int ("nframes", "NFrames",
+          "Number of frames per buffer",
+          0, G_MAXINT, DEFAULT_NFRAMES,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
+      g_param_spec_string ("last-message", "last-message",
+          "The last status message", NULL,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Speex audio encoder", "Codec/Encoder/Audio",
+      "Encodes audio in Speex format", "Wim Taymans <wim@fluendo.com>");
+
+  GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
+}
+
+static void
+gst_speex_enc_finalize (GObject * object)
+{
+  GstSpeexEnc *enc;
+
+  enc = GST_SPEEX_ENC (object);
+
+  g_free (enc->last_message);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_speex_enc_init (GstSpeexEnc * enc)
+{
+  GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
+
+  /* arrange granulepos marking (and required perfect ts) */
+  gst_audio_encoder_set_mark_granule (benc, TRUE);
+  gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (enc));
+}
+
+static gboolean
+gst_speex_enc_start (GstAudioEncoder * benc)
+{
+  GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
+
+  GST_DEBUG_OBJECT (enc, "start");
+  speex_bits_init (&enc->bits);
+  enc->tags = gst_tag_list_new_empty ();
+  enc->header_sent = FALSE;
+  enc->encoded_samples = 0;
+
+  return TRUE;
+}
+
+static gboolean
+gst_speex_enc_stop (GstAudioEncoder * benc)
+{
+  GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
+
+  GST_DEBUG_OBJECT (enc, "stop");
+  enc->header_sent = FALSE;
+  if (enc->state) {
+    speex_encoder_destroy (enc->state);
+    enc->state = NULL;
+  }
+  speex_bits_destroy (&enc->bits);
+  speex_bits_set_bit_buffer (&enc->bits, NULL, 0);
+  gst_tag_list_unref (enc->tags);
+  enc->tags = NULL;
+
+  gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
+
+  return TRUE;
+}
+
+static gint64
+gst_speex_enc_get_latency (GstSpeexEnc * enc)
+{
+  /* See the Speex manual section "Latency and algorithmic delay" */
+  if (enc->rate == 8000)
+    return 30 * GST_MSECOND;
+  else
+    return 34 * GST_MSECOND;
+}
+
+static gboolean
+gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
+{
+  GstSpeexEnc *enc;
+
+  enc = GST_SPEEX_ENC (benc);
+
+  enc->channels = GST_AUDIO_INFO_CHANNELS (info);
+  enc->rate = GST_AUDIO_INFO_RATE (info);
+
+  /* handle reconfigure */
+  if (enc->state) {
+    speex_encoder_destroy (enc->state);
+    enc->state = NULL;
+  }
+
+  if (!gst_speex_enc_setup (enc))
+    return FALSE;
+
+  /* feedback to base class */
+  gst_audio_encoder_set_latency (benc,
+      gst_speex_enc_get_latency (enc), gst_speex_enc_get_latency (enc));
+  gst_audio_encoder_set_lookahead (benc, enc->lookahead);
+
+  if (enc->nframes == 0) {
+    /* as many frames as available input allows */
+    gst_audio_encoder_set_frame_samples_min (benc, enc->frame_size);
+    gst_audio_encoder_set_frame_samples_max (benc, enc->frame_size);
+    gst_audio_encoder_set_frame_max (benc, 0);
+  } else {
+    /* exactly as many frames as configured */
+    gst_audio_encoder_set_frame_samples_min (benc,
+        enc->frame_size * enc->nframes);
+    gst_audio_encoder_set_frame_samples_max (benc,
+        enc->frame_size * enc->nframes);
+    gst_audio_encoder_set_frame_max (benc, 1);
+  }
+
+  return TRUE;
+}
+
+static GstBuffer *
+gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
+{
+  const GstTagList *user_tags;
+  GstTagList *merged_tags;
+  GstBuffer *comments = NULL;
+
+  user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
+
+  GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
+  GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
+
+  /* gst_tag_list_merge() will handle NULL for either or both lists fine */
+  merged_tags = gst_tag_list_merge (user_tags, enc->tags,
+      gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
+
+  if (merged_tags == NULL)
+    merged_tags = gst_tag_list_new_empty ();
+
+  GST_DEBUG_OBJECT (enc, "merged   tags = %" GST_PTR_FORMAT, merged_tags);
+  comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
+      0, "Encoded with GStreamer Speexenc");
+  gst_tag_list_unref (merged_tags);
+
+  GST_BUFFER_OFFSET (comments) = 0;
+  GST_BUFFER_OFFSET_END (comments) = 0;
+
+  return comments;
+}
+
+static void
+gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
+{
+  g_free (enc->last_message);
+  enc->last_message = g_strdup (msg);
+  GST_WARNING_OBJECT (enc, "%s", msg);
+  g_object_notify (G_OBJECT (enc), "last-message");
+}
+
+static gboolean
+gst_speex_enc_setup (GstSpeexEnc * enc)
+{
+  switch (enc->mode) {
+    case GST_SPEEX_ENC_MODE_UWB:
+      GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
+      enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
+      break;
+    case GST_SPEEX_ENC_MODE_WB:
+      GST_LOG_OBJECT (enc, "configuring for requested WB mode");
+      enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
+      break;
+    case GST_SPEEX_ENC_MODE_NB:
+      GST_LOG_OBJECT (enc, "configuring for requested NB mode");
+      enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
+      break;
+    case GST_SPEEX_ENC_MODE_AUTO:
+      /* fall through */
+      GST_LOG_OBJECT (enc, "finding best mode");
+    default:
+      break;
+  }
+
+  if (enc->rate > 25000) {
+    if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
+      GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
+      enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
+    } else {
+      if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
+        gst_speex_enc_set_last_msg (enc,
+            "Warning: suggest to use ultra wide band mode for this rate");
+      }
+    }
+  } else if (enc->rate > 12500) {
+    if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
+      GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
+      enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
+    } else {
+      if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
+        gst_speex_enc_set_last_msg (enc,
+            "Warning: suggest to use wide band mode for this rate");
+      }
+    }
+  } else {
+    if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
+      GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
+      enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
+    } else {
+      if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
+        gst_speex_enc_set_last_msg (enc,
+            "Warning: suggest to use narrow band mode for this rate");
+      }
+    }
+  }
+
+  if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
+    gst_speex_enc_set_last_msg (enc,
+        "Warning: speex is optimized for 8, 16 and 32 KHz");
+  }
+
+  speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
+  enc->header.frames_per_packet = enc->nframes;
+  enc->header.vbr = enc->vbr;
+  enc->header.nb_channels = enc->channels;
+
+  /*Initialize Speex encoder */
+  enc->state = speex_encoder_init (enc->speex_mode);
+
+  speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
+  speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
+  speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
+
+  if (enc->vbr)
+    speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
+  else {
+    gint tmp = floor (enc->quality);
+
+    speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
+  }
+  if (enc->bitrate) {
+    if (enc->quality >= 0.0 && enc->vbr) {
+      gst_speex_enc_set_last_msg (enc,
+          "Warning: bitrate option is overriding quality");
+    }
+    speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
+  }
+  if (enc->vbr) {
+    gint tmp = 1;
+
+    speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
+  } else if (enc->vad) {
+    gint tmp = 1;
+
+    speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
+  }
+
+  if (enc->dtx) {
+    gint tmp = 1;
+
+    speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
+  }
+
+  if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
+    gst_speex_enc_set_last_msg (enc,
+        "Warning: dtx is useless without vad, vbr or abr");
+  } else if ((enc->vbr || enc->abr) && (enc->vad)) {
+    gst_speex_enc_set_last_msg (enc,
+        "Warning: vad is already implied by vbr or abr");
+  }
+
+  if (enc->abr) {
+    speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
+  }
+
+  speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
+
+  GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
+      enc->lookahead);
+
+  return TRUE;
+}
+
+static gboolean
+gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
+{
+  GstSpeexEnc *enc;
+
+  enc = GST_SPEEX_ENC (benc);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_TAG:
+    {
+      if (enc->tags) {
+        GstTagList *list;
+
+        gst_event_parse_tag (event, &list);
+        gst_tag_list_insert (enc->tags, list,
+            gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
+      } else {
+        g_assert_not_reached ();
+      }
+      break;
+    }
+    case GST_EVENT_SEGMENT:
+      enc->encoded_samples = 0;
+      break;
+    default:
+      break;
+  }
+
+  /* we only peeked, let base class handle it */
+  return GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (benc, event);
+}
+
+static GstFlowReturn
+gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
+{
+  gint frame_size = enc->frame_size;
+  gint bytes = frame_size * 2 * enc->channels, samples;
+  gint outsize, written, dtx_ret = 0;
+  GstMapInfo map;
+  guint8 *data, *data0 = NULL, *bdata;
+  gsize bsize, size;
+  GstBuffer *outbuf;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstSegment *segment;
+  GstClockTime duration;
+
+  if (G_LIKELY (buf)) {
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    bdata = map.data;
+    bsize = map.size;
+
+    if (G_UNLIKELY (bsize % bytes)) {
+      GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
+
+      /* If encoding part of a frame, and we have no set stop time on
+       * the output segment, we update the segment stop time to reflect
+       * the last sample. This will let oggmux set the last page's
+       * granpos to tell a decoder the dummy samples should be clipped.
+       */
+      segment = &GST_AUDIO_ENCODER_OUTPUT_SEGMENT (enc);
+      GST_DEBUG_OBJECT (enc, "existing output segment %" GST_SEGMENT_FORMAT,
+          segment);
+      if (!GST_CLOCK_TIME_IS_VALID (segment->stop)) {
+        int input_samples = bsize / (enc->channels * 2);
+        GST_DEBUG_OBJECT (enc,
+            "No stop time and partial frame, updating segment");
+        duration =
+            gst_util_uint64_scale (enc->encoded_samples + input_samples,
+            GST_SECOND, enc->rate);
+        segment->stop = segment->start + duration;
+        GST_DEBUG_OBJECT (enc, "new output segment %" GST_SEGMENT_FORMAT,
+            segment);
+        gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (enc),
+            gst_event_new_segment (segment));
+      }
+
+      size = ((bsize / bytes) + 1) * bytes;
+      data0 = data = g_malloc0 (size);
+      memcpy (data, bdata, bsize);
+      gst_buffer_unmap (buf, &map);
+      bdata = NULL;
+    } else {
+      data = bdata;
+      size = bsize;
+    }
+  } else {
+    GST_DEBUG_OBJECT (enc, "nothing to drain");
+    goto done;
+  }
+
+  samples = size / (2 * enc->channels);
+  speex_bits_reset (&enc->bits);
+
+  /* FIXME what about dropped samples if DTS enabled ?? */
+
+  while (size) {
+    GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
+
+    if (enc->channels == 2) {
+      speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
+    }
+    dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
+
+    data += bytes;
+    size -= bytes;
+  }
+
+  speex_bits_insert_terminator (&enc->bits);
+  outsize = speex_bits_nbytes (&enc->bits);
+
+  if (bdata)
+    gst_buffer_unmap (buf, &map);
+
+#if 0
+  ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
+      GST_BUFFER_OFFSET_NONE, outsize,
+      GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
+
+  if ((GST_FLOW_OK != ret))
+    goto done;
+#endif
+  outbuf = gst_buffer_new_allocate (NULL, outsize, NULL);
+  gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+
+  written = speex_bits_write (&enc->bits, (gchar *) map.data, outsize);
+
+  if (G_UNLIKELY (written < outsize)) {
+    GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
+  } else if (G_UNLIKELY (written > outsize)) {
+    GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
+    written = outsize;
+  }
+  gst_buffer_unmap (outbuf, &map);
+  gst_buffer_resize (outbuf, 0, written);
+
+  if (!dtx_ret)
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
+
+  ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
+      outbuf, samples);
+  enc->encoded_samples += frame_size;
+
+done:
+  g_free (data0);
+  return ret;
+}
+
+/*
+ * (really really) FIXME: move into core (dixit tpm)
+ */
+/*
+ * _gst_caps_set_buffer_array:
+ * @caps: (transfer full): a #GstCaps
+ * @field: field in caps to set
+ * @buf: header buffers
+ *
+ * Adds given buffers to an array of buffers set as the given @field
+ * on the given @caps.  List of buffer arguments must be NULL-terminated.
+ *
+ * Returns: (transfer full): input caps with a streamheader field added, or NULL
+ *     if some error occurred
+ */
+static GstCaps *
+_gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
+    GstBuffer * buf, ...)
+{
+  GstStructure *structure = NULL;
+  va_list va;
+  GValue array = { 0 };
+  GValue value = { 0 };
+
+  g_return_val_if_fail (caps != NULL, NULL);
+  g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
+  g_return_val_if_fail (field != NULL, NULL);
+
+  caps = gst_caps_make_writable (caps);
+  structure = gst_caps_get_structure (caps, 0);
+
+  g_value_init (&array, GST_TYPE_ARRAY);
+
+  va_start (va, buf);
+  /* put buffers in a fixed list */
+  while (buf) {
+    g_assert (gst_buffer_is_writable (buf));
+
+    /* mark buffer */
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
+
+    g_value_init (&value, GST_TYPE_BUFFER);
+    buf = gst_buffer_copy (buf);
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
+    gst_value_set_buffer (&value, buf);
+    gst_buffer_unref (buf);
+    gst_value_array_append_value (&array, &value);
+    g_value_unset (&value);
+
+    buf = va_arg (va, GstBuffer *);
+  }
+  va_end (va);
+
+  gst_structure_set_value (structure, field, &array);
+  g_value_unset (&array);
+
+  return caps;
+}
+
+static GstFlowReturn
+gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
+{
+  GstSpeexEnc *enc;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  enc = GST_SPEEX_ENC (benc);
+
+  if (!enc->header_sent) {
+    /* Speex streams begin with two headers; the initial header (with
+       most of the codec setup parameters) which is mandated by the Ogg
+       bitstream spec.  The second header holds any comment fields.
+       We merely need to make the headers, then pass them to libspeex 
+       one at a time; libspeex handles the additional Ogg bitstream 
+       constraints */
+    GstBuffer *buf1, *buf2;
+    GstCaps *caps;
+    guchar *data;
+    gint data_len;
+    GList *headers;
+
+    /* create header buffer */
+    data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
+    buf1 = gst_buffer_new_wrapped (data, data_len);
+    GST_BUFFER_OFFSET_END (buf1) = 0;
+    GST_BUFFER_OFFSET (buf1) = 0;
+
+    /* create comment buffer */
+    buf2 = gst_speex_enc_create_metadata_buffer (enc);
+
+    /* mark and put on caps */
+    caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
+        "channels", G_TYPE_INT, enc->channels, NULL);
+    caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
+
+    /* negotiate with these caps */
+    GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
+
+    gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (enc), caps);
+    gst_caps_unref (caps);
+
+    /* push out buffers */
+    /* store buffers for later pre_push sending */
+    headers = NULL;
+    GST_DEBUG_OBJECT (enc, "storing header buffers");
+    headers = g_list_prepend (headers, buf2);
+    headers = g_list_prepend (headers, buf1);
+    gst_audio_encoder_set_headers (benc, headers);
+
+    enc->header_sent = TRUE;
+  }
+
+  GST_DEBUG_OBJECT (enc, "received buffer %p of %" G_GSIZE_FORMAT " bytes", buf,
+      buf ? gst_buffer_get_size (buf) : 0);
+
+  ret = gst_speex_enc_encode (enc, buf);
+
+  return ret;
+}
+
+static void
+gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstSpeexEnc *enc;
+
+  enc = GST_SPEEX_ENC (object);
+
+  switch (prop_id) {
+    case PROP_QUALITY:
+      g_value_set_float (value, enc->quality);
+      break;
+    case PROP_BITRATE:
+      g_value_set_int (value, enc->bitrate);
+      break;
+    case PROP_MODE:
+      g_value_set_enum (value, enc->mode);
+      break;
+    case PROP_VBR:
+      g_value_set_boolean (value, enc->vbr);
+      break;
+    case PROP_ABR:
+      g_value_set_int (value, enc->abr);
+      break;
+    case PROP_VAD:
+      g_value_set_boolean (value, enc->vad);
+      break;
+    case PROP_DTX:
+      g_value_set_boolean (value, enc->dtx);
+      break;
+    case PROP_COMPLEXITY:
+      g_value_set_int (value, enc->complexity);
+      break;
+    case PROP_NFRAMES:
+      g_value_set_int (value, enc->nframes);
+      break;
+    case PROP_LAST_MESSAGE:
+      g_value_set_string (value, enc->last_message);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_speex_enc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstSpeexEnc *enc;
+
+  enc = GST_SPEEX_ENC (object);
+
+  switch (prop_id) {
+    case PROP_QUALITY:
+      enc->quality = g_value_get_float (value);
+      break;
+    case PROP_BITRATE:
+      enc->bitrate = g_value_get_int (value);
+      break;
+    case PROP_MODE:
+      enc->mode = g_value_get_enum (value);
+      break;
+    case PROP_VBR:
+      enc->vbr = g_value_get_boolean (value);
+      break;
+    case PROP_ABR:
+      enc->abr = g_value_get_int (value);
+      break;
+    case PROP_VAD:
+      enc->vad = g_value_get_boolean (value);
+      break;
+    case PROP_DTX:
+      enc->dtx = g_value_get_boolean (value);
+      break;
+    case PROP_COMPLEXITY:
+      enc->complexity = g_value_get_int (value);
+      break;
+    case PROP_NFRAMES:
+      enc->nframes = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/ext/speex/gstspeexenc.h b/ext/speex/gstspeexenc.h
new file mode 100644
index 0000000..29fcc72
--- /dev/null
+++ b/ext/speex/gstspeexenc.h
@@ -0,0 +1,98 @@
+/* GStreamer Speex Encoder
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_SPEEX_ENC_H__
+#define __GST_SPEEX_ENC_H__
+
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudioencoder.h>
+
+#include <speex/speex.h>
+#include <speex/speex_header.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SPEEX_ENC \
+  (gst_speex_enc_get_type())
+#define GST_SPEEX_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPEEX_ENC,GstSpeexEnc))
+#define GST_SPEEX_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPEEX_ENC,GstSpeexEncClass))
+#define GST_IS_SPEEX_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPEEX_ENC))
+#define GST_IS_SPEEX_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPEEX_ENC))
+
+typedef enum
+{
+  GST_SPEEX_ENC_MODE_AUTO,
+  GST_SPEEX_ENC_MODE_UWB,
+  GST_SPEEX_ENC_MODE_WB,
+  GST_SPEEX_ENC_MODE_NB
+} GstSpeexMode;
+
+typedef struct _GstSpeexEnc GstSpeexEnc;
+typedef struct _GstSpeexEncClass GstSpeexEncClass;
+
+struct _GstSpeexEnc {
+  GstAudioEncoder   element;
+
+  SpeexBits             bits;
+  SpeexHeader           header;
+  const SpeexMode       *speex_mode;
+  void                  *state;
+
+  /* properties */
+  GstSpeexMode          mode;
+  gfloat                quality;
+  gint                  bitrate;
+  gboolean              vbr;
+  gint                  abr;
+  gboolean              vad;
+  gboolean              dtx;
+  gint                  complexity;
+  gint                  nframes;
+  gchar                 *last_message;
+
+  gint                  channels;
+  gint                  rate;
+
+  gboolean              header_sent;
+  guint64               encoded_samples;
+
+  GstTagList            *tags;
+
+  gint                  frame_size;
+  gint                  lookahead;
+
+  guint8                *comments;
+  gint                  comment_len;
+};
+
+struct _GstSpeexEncClass {
+  GstAudioEncoderClass parent_class;
+};
+
+GType gst_speex_enc_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_SPEEXENC_H__ */
diff --git a/ext/speex/meson.build b/ext/speex/meson.build
new file mode 100644
index 0000000..b682f08
--- /dev/null
+++ b/ext/speex/meson.build
@@ -0,0 +1,19 @@
+speex_sources = [
+  'gstspeex.c',
+  'gstspeexdec.c',
+  'gstspeexenc.c',
+]
+
+speex_dep = dependency('speex', version : '>=1.1.6', required : false)
+
+if speex_dep.found()
+  gstspeex = library('gstspeex',
+    speex_sources,
+    c_args : gst_plugins_good_args + ['-DGST_USE_UNSTABLE_API'],
+    link_args : noseh_link_args,
+    include_directories : [configinc],
+    dependencies : [gstbase_dep, gsttag_dep, gstaudio_dep, speex_dep, libm],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/ext/taglib/.gitignore b/ext/taglib/.gitignore
new file mode 100644
index 0000000..4682982
--- /dev/null
+++ b/ext/taglib/.gitignore
@@ -0,0 +1 @@
+gsttaglibmux.loT
diff --git a/ext/taglib/Makefile.am b/ext/taglib/Makefile.am
new file mode 100644
index 0000000..515b342
--- /dev/null
+++ b/ext/taglib/Makefile.am
@@ -0,0 +1,18 @@
+plugin_LTLIBRARIES = libgsttaglib.la
+
+libgsttaglib_la_SOURCES = gsttaglibplugin.c gstid3v2mux.cc gstapev2mux.cc
+libgsttaglib_la_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_CFLAGS) \
+	$(TAGLIB_CFLAGS)
+libgsttaglib_la_CXXFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_CXXFLAGS) \
+	$(TAGLIB_CXXFLAGS)
+libgsttaglib_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_API_VERSION) \
+	$(GST_LIBS) \
+	$(TAGLIB_LIBS)
+libgsttaglib_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstid3v2mux.h gstapev2mux.h
diff --git a/ext/taglib/gstapev2mux.cc b/ext/taglib/gstapev2mux.cc
new file mode 100644
index 0000000..9659daf
--- /dev/null
+++ b/ext/taglib/gstapev2mux.cc
@@ -0,0 +1,408 @@
+/* GStreamer taglib-based APEv2 muxer
+ * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-apev2mux
+ * @see_also: #GstTagSetter
+ *
+ * This element adds APEv2 tags to the beginning of a stream using the taglib
+ * library.
+ *
+ * Applications can set the tags to write using the #GstTagSetter interface.
+ * Tags sent by upstream elements will be picked up automatically (and merged
+ * according to the merge mode set via the tag setter interface).
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -v filesrc location=foo.ogg ! decodebin ! audioconvert ! lame ! apev2mux ! filesink location=foo.mp3
+ * ]| A pipeline that transcodes a file from Ogg/Vorbis to mp3 format with an
+ * APEv2 that contains the same as the the Ogg/Vorbis file. Make sure the
+ * Ogg/Vorbis file actually has comments to preserve.
+ * |[
+ * gst-launch-1.0 -m filesrc location=foo.mp3 ! apedemux ! fakesink silent=TRUE 2&gt; /dev/null | grep taglist
+ * ]| Verify that tags have been written.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstapev2mux.h"
+
+#include <string.h>
+
+#include <apetag.h>
+#include <gst/tag/tag.h>
+
+using namespace TagLib;
+
+GST_DEBUG_CATEGORY_STATIC (gst_apev2_mux_debug);
+#define GST_CAT_DEFAULT gst_apev2_mux_debug
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-apetag"));
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("ANY"));
+
+G_DEFINE_TYPE (GstApev2Mux, gst_apev2_mux, GST_TYPE_TAG_MUX);
+
+static GstBuffer *gst_apev2_mux_render_start_tag (GstTagMux * mux,
+    const GstTagList * taglist);
+static GstBuffer *gst_apev2_mux_render_end_tag (GstTagMux * mux,
+    const GstTagList * taglist);
+
+static void
+gst_apev2_mux_class_init (GstApev2MuxClass * klass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+  GST_TAG_MUX_CLASS (klass)->render_start_tag =
+      GST_DEBUG_FUNCPTR (gst_apev2_mux_render_start_tag);
+  GST_TAG_MUX_CLASS (klass)->render_end_tag =
+      GST_DEBUG_FUNCPTR (gst_apev2_mux_render_end_tag);
+
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "TagLib-based APEv2 Muxer", "Formatter/Metadata",
+      "Adds an APEv2 header to the beginning of files using taglib",
+      "Sebastian Dröge <slomo@circular-chaos.org>");
+
+  GST_DEBUG_CATEGORY_INIT (gst_apev2_mux_debug, "apev2mux", 0,
+      "taglib-based APEv2 tag muxer");
+}
+
+static void
+gst_apev2_mux_init (GstApev2Mux * apev2mux)
+{
+  /* nothing to do */
+}
+
+static gboolean
+gst_apev2_mux_have_wavpack (GstApev2Mux * apev2mux)
+{
+  const GstStructure *s;
+  gboolean ret;
+  GstCaps *caps;
+  GstPad *sink;
+
+  sink = gst_element_get_static_pad (GST_ELEMENT_CAST (apev2mux), "sink");
+  caps = gst_pad_get_current_caps (sink);
+  gst_object_unref (sink);
+
+  if (caps == NULL)
+    return FALSE;
+
+  s = gst_caps_get_structure (caps, 0);
+  ret = gst_structure_has_name (s, "audio/x-wavpack");
+  gst_caps_unref (caps);
+
+  GST_LOG_OBJECT (apev2mux, "got wavpack input: %s", ret ? "yes" : "no");
+  return ret;
+}
+
+static void
+add_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
+{
+  APE::Tag * apev2tag = (APE::Tag *) user_data;
+  gboolean result;
+
+  /* FIXME: if there are several values set for the same tag, this won't
+   * work, only the first value will be taken into account
+   */
+  if (strcmp (tag, GST_TAG_TITLE) == 0) {
+    const char *title;
+
+    result = gst_tag_list_peek_string_index (list, tag, 0, &title);
+    if (result != FALSE) {
+      GST_DEBUG ("Setting title to %s", title);
+      apev2tag->setTitle (String (title, String::UTF8));
+    }
+  } else if (strcmp (tag, GST_TAG_ALBUM) == 0) {
+    const char *album;
+
+    result = gst_tag_list_peek_string_index (list, tag, 0, &album);
+    if (result != FALSE) {
+      GST_DEBUG ("Setting album to %s", album);
+      apev2tag->setAlbum (String (album, String::UTF8));
+    }
+  } else if (strcmp (tag, GST_TAG_ARTIST) == 0) {
+    const char *artist;
+
+    result = gst_tag_list_peek_string_index (list, tag, 0, &artist);
+    if (result != FALSE) {
+      GST_DEBUG ("Setting artist to %s", artist);
+      apev2tag->setArtist (String (artist, String::UTF8));
+    }
+  } else if (strcmp (tag, GST_TAG_COMPOSER) == 0) {
+    const char *composer;
+
+    result = gst_tag_list_peek_string_index (list, tag, 0, &composer);
+    if (result != FALSE) {
+      GST_DEBUG ("Setting composer to %s", composer);
+      apev2tag->addValue (String ("COMPOSER", String::UTF8),
+          String (composer, String::UTF8));
+    }
+  } else if (strcmp (tag, GST_TAG_GENRE) == 0) {
+    const char *genre;
+
+    result = gst_tag_list_peek_string_index (list, tag, 0, &genre);
+    if (result != FALSE) {
+      GST_DEBUG ("Setting genre to %s", genre);
+      apev2tag->setGenre (String (genre, String::UTF8));
+    }
+  } else if (strcmp (tag, GST_TAG_COMMENT) == 0) {
+    const char *comment;
+
+    result = gst_tag_list_peek_string_index (list, tag, 0, &comment);
+    if (result != FALSE) {
+      GST_DEBUG ("Setting comment to %s", comment);
+      apev2tag->setComment (String (comment, String::UTF8));
+    }
+  } else if (strcmp (tag, GST_TAG_DATE) == 0) {
+    GDate *date;
+
+    result = gst_tag_list_get_date_index (list, tag, 0, &date);
+    if (result != FALSE) {
+      GDateYear year;
+
+      year = g_date_get_year (date);
+      GST_DEBUG ("Setting track year to %d", year);
+      apev2tag->setYear (year);
+      g_date_free (date);
+    }
+  } else if (strcmp (tag, GST_TAG_TRACK_NUMBER) == 0) {
+    guint track_number;
+
+    result = gst_tag_list_get_uint_index (list, tag, 0, &track_number);
+    if (result != FALSE) {
+      guint total_tracks;
+
+      result = gst_tag_list_get_uint_index (list, GST_TAG_TRACK_COUNT,
+          0, &total_tracks);
+      if (result) {
+        gchar *tag_str;
+
+        tag_str = g_strdup_printf ("%d/%d", track_number, total_tracks);
+        GST_DEBUG ("Setting track number to %s", tag_str);
+        apev2tag->addValue (String ("TRACK", String::UTF8),
+            String (tag_str, String::UTF8), true);
+        g_free (tag_str);
+      } else {
+        GST_DEBUG ("Setting track number to %d", track_number);
+        apev2tag->setTrack (track_number);
+      }
+    }
+  } else if (strcmp (tag, GST_TAG_TRACK_COUNT) == 0) {
+    guint n;
+
+    if (gst_tag_list_get_uint_index (list, GST_TAG_TRACK_NUMBER, 0, &n)) {
+      GST_DEBUG ("track-count handled with track-number, skipping");
+    } else if (gst_tag_list_get_uint_index (list, GST_TAG_TRACK_COUNT, 0, &n)) {
+      gchar *tag_str;
+
+      tag_str = g_strdup_printf ("0/%d", n);
+      GST_DEBUG ("Setting track number to %s", tag_str);
+      apev2tag->addValue (String ("TRACK", String::UTF8),
+          String (tag_str, String::UTF8), true);
+      g_free (tag_str);
+    }
+#if 0
+  } else if (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0) {
+    guint volume_number;
+
+    result = gst_tag_list_get_uint_index (list, tag, 0, &volume_number);
+
+    if (result != FALSE) {
+      guint volume_count;
+      gchar *tag_str;
+
+      result = gst_tag_list_get_uint_index (list, GST_TAG_ALBUM_VOLUME_COUNT,
+          0, &volume_count);
+
+      if (result) {
+        tag_str = g_strdup_printf ("CD %d/%d", volume_number, volume_count);
+      } else {
+        tag_str = g_strdup_printf ("CD %d", volume_number);
+      }
+
+      GST_DEBUG ("Setting album number to %s", tag_str);
+
+      apev2tag->addValue (String ("MEDIA", String::UTF8),
+          String (tag_str, String::UTF8), true);
+      g_free (tag_str);
+    }
+  } else if (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0) {
+    guint n;
+
+    if (gst_tag_list_get_uint_index (list, GST_TAG_ALBUM_VOLUME_NUMBER, 0, &n)) {
+      GST_DEBUG ("volume-count handled with volume-number, skipping");
+    } else if (gst_tag_list_get_uint_index (list, GST_TAG_ALBUM_VOLUME_COUNT,
+            0, &n)) {
+      gchar *tag_str;
+
+      tag_str = g_strdup_printf ("CD 0/%u", n);
+      GST_DEBUG ("Setting album volume number/count to %s", tag_str);
+
+      apev2tag->addValue (String ("MEDIA", String::UTF8),
+          String (tag_str, String::UTF8), true);
+      g_free (tag_str);
+    }
+#endif
+  } else if (strcmp (tag, GST_TAG_COPYRIGHT) == 0) {
+    const gchar *copyright;
+
+    result = gst_tag_list_peek_string_index (list, tag, 0, &copyright);
+
+    if (result != FALSE) {
+      GST_DEBUG ("Setting copyright to %s", copyright);
+      apev2tag->addValue (String ("COPYRIGHT", String::UTF8),
+          String (copyright, String::UTF8), true);
+    }
+  } else if (strcmp (tag, GST_TAG_LOCATION) == 0) {
+    const gchar *location;
+
+    result = gst_tag_list_peek_string_index (list, tag, 0, &location);
+
+    if (result != FALSE) {
+      GST_DEBUG ("Setting location to %s", location);
+      apev2tag->addValue (String ("FILE", String::UTF8),
+          String (location, String::UTF8), true);
+    }
+  } else if (strcmp (tag, GST_TAG_ISRC) == 0) {
+    const gchar *isrc;
+
+    result = gst_tag_list_peek_string_index (list, tag, 0, &isrc);
+
+    if (result != FALSE) {
+      GST_DEBUG ("Setting ISRC to %s", isrc);
+      apev2tag->addValue (String ("ISRC", String::UTF8),
+          String (isrc, String::UTF8), true);
+    }
+  } else if (strcmp (tag, GST_TAG_TRACK_GAIN) == 0) {
+    gdouble value;
+
+    result = gst_tag_list_get_double_index (list, tag, 0, &value);
+
+    if (result != FALSE) {
+      gchar *track_gain = (gchar *) g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
+
+      track_gain = g_ascii_dtostr (track_gain, G_ASCII_DTOSTR_BUF_SIZE, value);
+      GST_DEBUG ("Setting track gain to %s", track_gain);
+      apev2tag->addValue (String ("REPLAYGAIN_TRACK_GAIN",
+              String::UTF8), String (track_gain, String::UTF8), true);
+      g_free (track_gain);
+    }
+  } else if (strcmp (tag, GST_TAG_TRACK_PEAK) == 0) {
+    gdouble value;
+
+    result = gst_tag_list_get_double_index (list, tag, 0, &value);
+
+    if (result != FALSE) {
+      gchar *track_peak = (gchar *) g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
+
+      track_peak = g_ascii_dtostr (track_peak, G_ASCII_DTOSTR_BUF_SIZE, value);
+      GST_DEBUG ("Setting track peak to %s", track_peak);
+      apev2tag->addValue (String ("REPLAYGAIN_TRACK_PEAK",
+              String::UTF8), String (track_peak, String::UTF8), true);
+      g_free (track_peak);
+    }
+  } else if (strcmp (tag, GST_TAG_ALBUM_GAIN) == 0) {
+    gdouble value;
+
+    result = gst_tag_list_get_double_index (list, tag, 0, &value);
+
+    if (result != FALSE) {
+      gchar *album_gain = (gchar *) g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
+
+      album_gain = g_ascii_dtostr (album_gain, G_ASCII_DTOSTR_BUF_SIZE, value);
+      GST_DEBUG ("Setting album gain to %s", album_gain);
+      apev2tag->addValue (String ("REPLAYGAIN_ALBUM_GAIN",
+              String::UTF8), String (album_gain, String::UTF8), true);
+      g_free (album_gain);
+    }
+  } else if (strcmp (tag, GST_TAG_ALBUM_PEAK) == 0) {
+    gdouble value;
+
+    result = gst_tag_list_get_double_index (list, tag, 0, &value);
+
+    if (result != FALSE) {
+      gchar *album_peak = (gchar *) g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
+
+      album_peak = g_ascii_dtostr (album_peak, G_ASCII_DTOSTR_BUF_SIZE, value);
+      GST_DEBUG ("Setting album peak to %s", album_peak);
+      apev2tag->addValue (String ("REPLAYGAIN_ALBUM_PEAK",
+              String::UTF8), String (album_peak, String::UTF8), true);
+      g_free (album_peak);
+    }
+  } else {
+    GST_WARNING ("Unsupported tag: %s", tag);
+  }
+}
+
+static GstBuffer *
+gst_apev2_mux_render_tag (GstTagMux * mux, const GstTagList * taglist)
+{
+  APE::Tag apev2tag;
+  ByteVector rendered_tag;
+  GstBuffer *buf;
+  guint tag_size;
+
+  /* Render the tag */
+  gst_tag_list_foreach (taglist, add_one_tag, &apev2tag);
+
+  rendered_tag = apev2tag.render ();
+  tag_size = rendered_tag.size ();
+
+  GST_LOG_OBJECT (mux, "tag size = %d bytes", tag_size);
+
+  /* Create buffer with tag */
+  buf = gst_buffer_new_and_alloc (tag_size);
+  gst_buffer_fill (buf, 0, rendered_tag.data (), tag_size);
+
+  return buf;
+}
+
+static GstBuffer *
+gst_apev2_mux_render_start_tag (GstTagMux * mux, const GstTagList * taglist)
+{
+  if (gst_apev2_mux_have_wavpack (GST_APEV2_MUX (mux)))
+    return NULL;
+
+  return gst_apev2_mux_render_tag (mux, taglist);
+}
+
+static GstBuffer *
+gst_apev2_mux_render_end_tag (GstTagMux * mux, const GstTagList * taglist)
+{
+  if (gst_apev2_mux_have_wavpack (GST_APEV2_MUX (mux)))
+    return gst_apev2_mux_render_tag (mux, taglist);
+
+  return NULL;
+}
diff --git a/ext/taglib/gstapev2mux.h b/ext/taglib/gstapev2mux.h
new file mode 100644
index 0000000..8eceb57
--- /dev/null
+++ b/ext/taglib/gstapev2mux.h
@@ -0,0 +1,55 @@
+/* GStreamer taglib-based APEv2 muxer
+ * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GST_APEV2_MUX_H
+#define GST_APEV2_MUX_H
+
+#include <gst/tag/gsttagmux.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstApev2Mux GstApev2Mux;
+typedef struct _GstApev2MuxClass GstApev2MuxClass;
+
+struct _GstApev2Mux {
+  GstTagMux  tagmux;
+};
+
+struct _GstApev2MuxClass {
+  GstTagMuxClass  tagmux_class;
+};
+
+#define GST_TYPE_APEV2_MUX \
+  (gst_apev2_mux_get_type())
+#define GST_APEV2_MUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_APEV2_MUX,GstApev2Mux))
+#define GST_APEV2_MUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_APEV2_MUX,GstApev2MuxClass))
+#define GST_IS_APEV2_MUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_APEV2_MUX))
+#define GST_IS_APEV2_MUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_APEV2_MUX))
+
+GType gst_apev2_mux_get_type (void);
+
+G_END_DECLS
+
+#endif /* GST_APEV2_MUX_H */
diff --git a/ext/taglib/gstid3v2mux.cc b/ext/taglib/gstid3v2mux.cc
new file mode 100644
index 0000000..3ec9116
--- /dev/null
+++ b/ext/taglib/gstid3v2mux.cc
@@ -0,0 +1,804 @@
+/* GStreamer taglib-based ID3v2 muxer
+ * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-id3v2mux
+ * @see_also: #GstID3Demux, #GstTagSetter
+ *
+ * This element adds ID3v2 tags to the beginning of a stream using the taglib
+ * library. More precisely, the tags written are ID3 version 2.4.0 tags (which
+ * means in practice that some hardware players or outdated programs might not
+ * be able to read them properly).
+ *
+ * Applications can set the tags to write using the #GstTagSetter interface.
+ * Tags sent by upstream elements will be picked up automatically (and merged
+ * according to the merge mode set via the tag setter interface).
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -v filesrc location=foo.ogg ! decodebin ! audioconvert ! lame ! id3v2mux ! filesink location=foo.mp3
+ * ]| A pipeline that transcodes a file from Ogg/Vorbis to mp3 format with an
+ * ID3v2 that contains the same as the the Ogg/Vorbis file. Make sure the
+ * Ogg/Vorbis file actually has comments to preserve.
+ * |[
+ * gst-launch-1.0 -m filesrc location=foo.mp3 ! id3demux ! fakesink silent=TRUE 2&gt; /dev/null | grep taglist
+ * ]| Verify that tags have been written.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstid3v2mux.h"
+
+#include <string.h>
+
+#include <textidentificationframe.h>
+#include <uniquefileidentifierframe.h>
+#include <attachedpictureframe.h>
+#include <relativevolumeframe.h>
+#include <commentsframe.h>
+#include <unknownframe.h>
+#include <id3v2synchdata.h>
+#include <id3v2tag.h>
+#include <gst/tag/tag.h>
+
+using namespace TagLib;
+
+GST_DEBUG_CATEGORY_STATIC (gst_id3v2_mux_debug);
+#define GST_CAT_DEFAULT gst_id3v2_mux_debug
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-id3"));
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("ANY"));
+
+G_DEFINE_TYPE (GstId3v2Mux, gst_id3v2_mux, GST_TYPE_TAG_MUX);
+
+static GstBuffer *gst_id3v2_mux_render_tag (GstTagMux * mux,
+    const GstTagList * taglist);
+static GstBuffer *gst_id3v2_mux_render_end_tag (GstTagMux * mux,
+    const GstTagList * taglist);
+
+static void
+gst_id3v2_mux_class_init (GstId3v2MuxClass * klass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+  GST_TAG_MUX_CLASS (klass)->render_start_tag =
+      GST_DEBUG_FUNCPTR (gst_id3v2_mux_render_tag);
+  GST_TAG_MUX_CLASS (klass)->render_end_tag =
+      GST_DEBUG_FUNCPTR (gst_id3v2_mux_render_end_tag);
+
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "TagLib-based ID3v2 Muxer", "Formatter/Metadata",
+      "Adds an ID3v2 header to the beginning of MP3 files using taglib",
+      "Christophe Fergeau <teuf@gnome.org>");
+
+  GST_DEBUG_CATEGORY_INIT (gst_id3v2_mux_debug, "id3v2mux", 0,
+      "taglib-based ID3v2 tag muxer");
+}
+
+static void
+gst_id3v2_mux_init (GstId3v2Mux * id3v2mux)
+{
+  /* nothing to do */
+}
+
+#if 0
+static void
+add_one_txxx_tag (ID3v2::Tag * id3v2tag, const gchar * key, const gchar * val)
+{
+  ID3v2::UserTextIdentificationFrame * frame;
+
+  if (val == NULL)
+    return;
+
+  GST_DEBUG ("Setting %s to %s", key, val);
+  frame = new ID3v2::UserTextIdentificationFrame (String::UTF8);
+  id3v2tag->addFrame (frame);
+  frame->setDescription (key);
+  frame->setText (val);
+}
+#endif
+
+typedef void (*GstId3v2MuxAddTagFunc) (ID3v2::Tag * id3v2tag,
+    const GstTagList * list,
+    const gchar * tag, guint num_tags, const gchar * data);
+
+static void
+add_encoder_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+    const gchar * tag, guint num_tags, const gchar * unused)
+{
+  TagLib::StringList string_list;
+  guint n;
+
+  /* ENCODER_VERSION is either handled with the ENCODER tag or not at all */
+  if (strcmp (tag, GST_TAG_ENCODER_VERSION) == 0)
+    return;
+
+  for (n = 0; n < num_tags; ++n) {
+    gchar *encoder = NULL;
+
+    if (gst_tag_list_get_string_index (list, tag, n, &encoder) && encoder) {
+      guint encoder_version;
+      gchar *s;
+
+      if (gst_tag_list_get_uint_index (list, GST_TAG_ENCODER_VERSION, n,
+              &encoder_version) && encoder_version > 0) {
+        s = g_strdup_printf ("%s %u", encoder, encoder_version);
+      } else {
+        s = g_strdup (encoder);
+      }
+
+      GST_LOG ("encoder[%u] = '%s'", n, s);
+      string_list.append (String (s, String::UTF8));
+      g_free (s);
+      g_free (encoder);
+    }
+  }
+
+  if (!string_list.isEmpty ()) {
+    ID3v2::TextIdentificationFrame * f;
+
+    f = new ID3v2::TextIdentificationFrame ("TSSE", String::UTF8);
+    id3v2tag->addFrame (f);
+    f->setText (string_list);
+  } else {
+    GST_WARNING ("Empty list for tag %s, skipping", tag);
+  }
+}
+
+static void
+add_date_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+    const gchar * tag, guint num_tags, const gchar * unused)
+{
+  TagLib::StringList string_list;
+  guint n;
+
+  GST_LOG ("Adding date frame");
+
+  for (n = 0; n < num_tags; ++n) {
+    GDate *date = NULL;
+
+    if (gst_tag_list_get_date_index (list, tag, n, &date) && date != NULL) {
+      GDateYear year;
+      gchar *s;
+
+      year = g_date_get_year (date);
+      if (year > 500 && year < 2100) {
+        s = g_strdup_printf ("%u", year);
+        GST_LOG ("%s[%u] = '%s'", tag, n, s);
+        string_list.append (String (s, String::UTF8));
+        g_free (s);
+      } else {
+        GST_WARNING ("invalid year %u, skipping", year);
+      }
+
+      g_date_free (date);
+    }
+  }
+
+  if (!string_list.isEmpty ()) {
+    ID3v2::TextIdentificationFrame * f;
+
+    f = new ID3v2::TextIdentificationFrame ("TDRC", String::UTF8);
+    id3v2tag->addFrame (f);
+    f->setText (string_list);
+  } else {
+    GST_WARNING ("Empty list for tag %s, skipping", tag);
+  }
+}
+
+static void
+add_count_or_num_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+    const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+  static const struct
+  {
+    const gchar *gst_tag;
+    const gchar *corr_count;    /* corresponding COUNT tag (if number) */
+    const gchar *corr_num;      /* corresponding NUMBER tag (if count) */
+  } corr[] = {
+    {
+    GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, NULL}, {
+    GST_TAG_TRACK_COUNT, NULL, GST_TAG_TRACK_NUMBER}, {
+    GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT, NULL}, {
+    GST_TAG_ALBUM_VOLUME_COUNT, NULL, GST_TAG_ALBUM_VOLUME_NUMBER}
+  };
+  guint idx;
+
+  for (idx = 0; idx < G_N_ELEMENTS (corr); ++idx) {
+    if (strcmp (corr[idx].gst_tag, tag) == 0)
+      break;
+  }
+
+  g_assert (idx < G_N_ELEMENTS (corr));
+  g_assert (frame_id && strlen (frame_id) == 4);
+
+  if (corr[idx].corr_num == NULL) {
+    guint number;
+
+    /* number tag */
+    if (gst_tag_list_get_uint_index (list, tag, 0, &number)) {
+      ID3v2::TextIdentificationFrame * frame;
+      gchar *tag_str;
+      guint count;
+
+      if (gst_tag_list_get_uint_index (list, corr[idx].corr_count, 0, &count))
+        tag_str = g_strdup_printf ("%u/%u", number, count);
+      else
+        tag_str = g_strdup_printf ("%u", number);
+
+      GST_DEBUG ("Setting %s to %s (frame_id = %s)", tag, tag_str, frame_id);
+      frame = new ID3v2::TextIdentificationFrame (frame_id, String::UTF8);
+      id3v2tag->addFrame (frame);
+      frame->setText (tag_str);
+      g_free (tag_str);
+    }
+  } else if (corr[idx].corr_count == NULL) {
+    guint count;
+
+    /* count tag */
+    if (gst_tag_list_get_uint_index (list, corr[idx].corr_num, 0, &count)) {
+      GST_DEBUG ("%s handled with %s, skipping", tag, corr[idx].corr_num);
+    } else if (gst_tag_list_get_uint_index (list, tag, 0, &count)) {
+      ID3v2::TextIdentificationFrame * frame;
+      gchar *tag_str;
+
+      tag_str = g_strdup_printf ("0/%u", count);
+      GST_DEBUG ("Setting %s to %s (frame_id = %s)", tag, tag_str, frame_id);
+      frame = new ID3v2::TextIdentificationFrame (frame_id, String::UTF8);
+      id3v2tag->addFrame (frame);
+      frame->setText (tag_str);
+      g_free (tag_str);
+    }
+  }
+
+  if (num_tags > 1) {
+    GST_WARNING ("more than one %s, can only handle one", tag);
+  }
+}
+
+static void
+add_unique_file_id_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+    const gchar * tag, guint num_tags, const gchar * unused)
+{
+  const gchar *origin = "http://musicbrainz.org";
+  gchar *id_str = NULL;
+
+  if (gst_tag_list_get_string_index (list, tag, 0, &id_str) && id_str) {
+    ID3v2::UniqueFileIdentifierFrame * frame;
+
+    GST_LOG ("Adding %s (%s): %s", tag, origin, id_str);
+    frame = new ID3v2::UniqueFileIdentifierFrame (origin, id_str);
+    id3v2tag->addFrame (frame);
+    g_free (id_str);
+  }
+}
+
+static void
+add_musicbrainz_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+    const gchar * tag, guint num_tags, const gchar * data)
+{
+  static const struct
+  {
+    const gchar gst_tag[28];
+    const gchar spec_id[28];
+    const gchar realworld_id[28];
+  } mb_ids[] = {
+    {
+    GST_TAG_MUSICBRAINZ_ARTISTID, "MusicBrainz Artist Id",
+          "musicbrainz_artistid"}, {
+    GST_TAG_MUSICBRAINZ_ALBUMID, "MusicBrainz Album Id", "musicbrainz_albumid"}, {
+    GST_TAG_MUSICBRAINZ_ALBUMARTISTID, "MusicBrainz Album Artist Id",
+          "musicbrainz_albumartistid"}, {
+    GST_TAG_MUSICBRAINZ_TRMID, "MusicBrainz TRM Id", "musicbrainz_trmid"}, {
+    GST_TAG_CDDA_MUSICBRAINZ_DISCID, "MusicBrainz DiscID",
+          "musicbrainz_discid"}, {
+      /* the following one is more or less made up, there seems to be little
+       * evidence that any popular application is actually putting this info
+       * into TXXX frames; the first one comes from a musicbrainz wiki 'proposed
+       * tags' page, the second one is analogue to the vorbis/ape/flac tag. */
+    GST_TAG_CDDA_CDDB_DISCID, "CDDB DiscID", "discid"}
+  };
+  guint i, idx;
+
+  idx = (guint8) data[0];
+  g_assert (idx < G_N_ELEMENTS (mb_ids));
+
+  for (i = 0; i < num_tags; ++i) {
+    ID3v2::UserTextIdentificationFrame * frame;
+    gchar *id_str;
+
+    if (gst_tag_list_get_string_index (list, tag, 0, &id_str) && id_str) {
+      GST_DEBUG ("Setting '%s' to '%s'", mb_ids[idx].spec_id, id_str);
+
+      /* add two frames, one with the ID the musicbrainz.org spec mentions
+       * and one with the ID that applications use in the real world */
+      frame = new ID3v2::UserTextIdentificationFrame (String::Latin1);
+      id3v2tag->addFrame (frame);
+      frame->setDescription (mb_ids[idx].spec_id);
+      frame->setText (id_str);
+
+      frame = new ID3v2::UserTextIdentificationFrame (String::Latin1);
+      id3v2tag->addFrame (frame);
+      frame->setDescription (mb_ids[idx].realworld_id);
+      frame->setText (id_str);
+
+      g_free (id_str);
+    }
+  }
+}
+
+static void
+add_id3v2frame_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+    const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+  ID3v2::FrameFactory * factory = ID3v2::FrameFactory::instance ();
+  guint i;
+
+  for (i = 0; i < num_tags; ++i) {
+    ID3v2::Frame * frame;
+    const GValue *val;
+    GstBuffer *buf;
+    GstSample *sample;
+
+    val = gst_tag_list_get_value_index (list, tag, i);
+    sample = (GstSample *) g_value_get_boxed (val);
+
+    if (sample && (buf = gst_sample_get_buffer (sample)) &&
+        gst_sample_get_caps (sample)) {
+      GstStructure *s;
+      gint version = 0;
+
+      s = gst_caps_get_structure (gst_sample_get_caps (sample), 0);
+      if (s && gst_structure_get_int (s, "version", &version) && version > 0) {
+        GstMapInfo map;
+
+        gst_buffer_map (buf, &map, GST_MAP_READ);
+        GST_DEBUG ("Injecting ID3v2.%u frame %u/%u of length %" G_GSIZE_FORMAT " and type %"
+            GST_PTR_FORMAT, version, i, num_tags, map.size, s);
+
+        frame = factory->createFrame (ByteVector ((const char *) map.data,
+                map.size), (TagLib::uint) version);
+        if (frame)
+          id3v2tag->addFrame (frame);
+
+        gst_buffer_unmap (buf, &map);
+      }
+    }
+  }
+}
+
+static void
+add_image_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+    const gchar * tag, guint num_tags, const gchar * unused)
+{
+  guint n;
+
+  for (n = 0; n < num_tags; ++n) {
+    const GValue *val;
+    GstSample *sample;
+    GstBuffer *image;
+
+    GST_DEBUG ("image %u/%u", n + 1, num_tags);
+
+    val = gst_tag_list_get_value_index (list, tag, n);
+    sample = (GstSample *) g_value_get_boxed (val);
+
+    if (GST_IS_SAMPLE (sample) && (image = gst_sample_get_buffer (sample)) &&
+        GST_IS_BUFFER (image) && gst_buffer_get_size (image) > 0 &&
+        gst_sample_get_caps (sample) != NULL &&
+        !gst_caps_is_empty (gst_sample_get_caps (sample))) {
+      const gchar *mime_type;
+      GstStructure *s;
+
+      s = gst_caps_get_structure (gst_sample_get_caps (sample), 0);
+      mime_type = gst_structure_get_name (s);
+      if (mime_type != NULL) {
+        ID3v2::AttachedPictureFrame * frame;
+        const gchar *desc = NULL;
+        GstMapInfo map;
+        const GstStructure *info_struct;
+
+        info_struct = gst_sample_get_info (sample);
+        if (!info_struct
+            || !gst_structure_has_name (info_struct, "GstTagImageInfo"))
+          info_struct = NULL;
+
+        if (strcmp (mime_type, "text/uri-list") == 0)
+          mime_type = "-->";
+
+        frame = new ID3v2::AttachedPictureFrame ();
+
+        gst_buffer_map (image, &map, GST_MAP_READ);
+
+        GST_DEBUG ("Attaching picture of %" G_GSIZE_FORMAT " bytes and mime type %s",
+            map.size, mime_type);
+
+        id3v2tag->addFrame (frame);
+        frame->setPicture (ByteVector ((const char *) map.data, map.size));
+        frame->setTextEncoding (String::UTF8);
+        frame->setMimeType (mime_type);
+
+        gst_buffer_unmap (image, &map);
+
+        if (info_struct)
+          desc = gst_structure_get_string (info_struct, "image-description");
+
+        frame->setDescription ((desc) ? desc : "");
+
+        if (strcmp (tag, GST_TAG_PREVIEW_IMAGE) == 0) {
+          frame->setType (ID3v2::AttachedPictureFrame::FileIcon);
+        } else {
+          int image_type = ID3v2::AttachedPictureFrame::Other;
+
+          if (info_struct) {
+            if (gst_structure_get (info_struct, "image-type",
+                    GST_TYPE_TAG_IMAGE_TYPE, &image_type, NULL)) {
+              if (image_type > 0 && image_type <= 18) {
+                image_type += 2;
+              } else {
+                image_type = ID3v2::AttachedPictureFrame::Other;
+              }
+            }
+          }
+
+          frame->setType ((TagLib::ID3v2::AttachedPictureFrame::Type) image_type);
+        }
+      }
+    } else {
+      GST_WARNING ("NULL image or no caps on image sample (%p, caps=%"
+          GST_PTR_FORMAT ")", sample,
+          (sample) ? gst_sample_get_caps (sample) : NULL);
+    }
+  }
+}
+
+static void
+add_comment_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+    const gchar * tag, guint num_tags, const gchar * unused)
+{
+  TagLib::StringList string_list;
+  guint n;
+
+  GST_LOG ("Adding comment frames");
+  for (n = 0; n < num_tags; ++n) {
+    gchar *s = NULL;
+
+    if (gst_tag_list_get_string_index (list, tag, n, &s) && s != NULL) {
+      ID3v2::CommentsFrame * f;
+      gchar *desc = NULL, *val = NULL, *lang = NULL;
+
+      f = new ID3v2::CommentsFrame (String::UTF8);
+
+      if (strcmp (tag, GST_TAG_COMMENT) == 0 ||
+          !gst_tag_parse_extended_comment (s, &desc, &lang, &val, TRUE)) {
+        /* create dummy description to allow for multiple comment frames
+         * (taglib will drop comment frames if descriptions are not unique) */
+        desc = g_strdup_printf ("c%u", n);
+        val = g_strdup (s);
+      }
+
+      GST_LOG ("%s[%u] = '%s' (%s|%s|%s)", tag, n, s, GST_STR_NULL (desc),
+          GST_STR_NULL (lang), GST_STR_NULL (val));
+
+      f->setDescription (desc);
+      f->setText (val);
+      if (lang) {
+        f->setLanguage (lang);
+      }
+
+      g_free (lang);
+      g_free (desc);
+      g_free (val);
+
+      id3v2tag->addFrame (f);
+    }
+    g_free (s);
+  }
+}
+
+static void
+add_text_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+    const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+  ID3v2::TextIdentificationFrame * f;
+  TagLib::StringList string_list;
+  guint n;
+
+  GST_LOG ("Adding '%s' frame", frame_id);
+  for (n = 0; n < num_tags; ++n) {
+    gchar *s = NULL;
+
+    if (gst_tag_list_get_string_index (list, tag, n, &s) && s != NULL) {
+      GST_LOG ("%s: %s[%u] = '%s'", frame_id, tag, n, s);
+      string_list.append (String (s, String::UTF8));
+      g_free (s);
+    }
+  }
+
+  if (!string_list.isEmpty ()) {
+    f = new ID3v2::TextIdentificationFrame (frame_id, String::UTF8);
+    id3v2tag->addFrame (f);
+    f->setText (string_list);
+  } else {
+    GST_WARNING ("Empty list for tag %s, skipping", tag);
+  }
+}
+
+static void
+add_uri_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+    const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+  gchar *url = NULL;
+
+  g_assert (frame_id != NULL);
+
+  /* URI tags are limited to one of each per taglist */
+  if (gst_tag_list_get_string_index (list, tag, 0, &url) && url != NULL) {
+    guint url_len;
+
+    url_len = strlen (url);
+    if (url_len > 0 && gst_uri_is_valid (url)) {
+      ID3v2::FrameFactory * factory = ID3v2::FrameFactory::instance ();
+      ID3v2::Frame * frame;
+      char *data;
+
+      data = g_new0 (char, 10 + url_len);
+
+      memcpy (data, frame_id, 4);
+      memcpy (data + 4, ID3v2::SynchData::fromUInt (url_len).data (), 4);
+      memcpy (data + 10, url, url_len);
+      ByteVector bytes (data, 10 + url_len);
+
+      g_free (data);
+
+      frame = factory->createFrame (bytes, (TagLib::uint) 4);
+      if (frame) {
+        id3v2tag->addFrame (frame);
+
+        GST_LOG ("%s: %s = '%s'", frame_id, tag, url);
+      }
+    } else {
+      GST_WARNING ("Tag %s does not contain a valid URI (%s)", tag, url);
+    }
+
+    g_free (url);
+  }
+}
+
+static void
+add_relative_volume_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+    const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+  const char *gain_tag_name;
+  const char *peak_tag_name;
+  gdouble peak_val;
+  gdouble gain_val;
+  ID3v2::RelativeVolumeFrame * frame;
+
+  frame = new ID3v2::RelativeVolumeFrame ();
+
+  /* figure out tag names and the identification string to use */
+  if (strcmp (tag, GST_TAG_TRACK_PEAK) == 0 ||
+      strcmp (tag, GST_TAG_TRACK_GAIN) == 0) {
+    gain_tag_name = GST_TAG_TRACK_GAIN;
+    peak_tag_name = GST_TAG_TRACK_PEAK;
+    frame->setIdentification ("track");
+    GST_DEBUG ("adding track relative-volume frame");
+  } else {
+    gain_tag_name = GST_TAG_ALBUM_GAIN;
+    peak_tag_name = GST_TAG_ALBUM_PEAK;
+    frame->setIdentification ("album");
+    GST_DEBUG ("adding album relative-volume frame");
+  }
+
+  /* find the value for the paired tag (gain, if this is peak, and
+   * vice versa).  if both tags exist, only write the frame when
+   * we're processing the peak tag.
+   */
+  if (strcmp (tag, GST_TAG_TRACK_PEAK) == 0 ||
+      strcmp (tag, GST_TAG_ALBUM_PEAK) == 0) {
+    ID3v2::RelativeVolumeFrame::PeakVolume encoded_peak;
+    short peak_int;
+
+    gst_tag_list_get_double (list, tag, &peak_val);
+
+    if (gst_tag_list_get_tag_size (list, gain_tag_name) > 0) {
+      gst_tag_list_get_double (list, gain_tag_name, &gain_val);
+      GST_DEBUG ("setting volume adjustment %g", gain_val);
+      frame->setVolumeAdjustment (gain_val);
+    }
+
+    /* copying mutagen: always write as 16 bits for sanity. */
+    peak_int = (short)(peak_val * G_MAXSHORT);
+    encoded_peak.bitsRepresentingPeak = 16;
+    encoded_peak.peakVolume = ByteVector::fromShort(peak_int, true);
+    GST_DEBUG ("setting peak value %g", peak_val);
+    frame->setPeakVolume(encoded_peak);
+
+  } else {
+    gst_tag_list_get_double (list, tag, &gain_val);
+    GST_DEBUG ("setting volume adjustment %g", gain_val);
+    frame->setVolumeAdjustment (gain_val);
+
+    if (gst_tag_list_get_tag_size (list, peak_tag_name) != 0) {
+      GST_DEBUG ("both gain and peak tags exist, not adding frame this time around");
+      delete frame;
+      return;
+    }
+  }
+
+  id3v2tag->addFrame (frame);
+}
+
+static void
+add_bpm_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+    const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+  gdouble bpm;
+
+  if (gst_tag_list_get_double_index (list, tag, 0, &bpm)) {
+    ID3v2::TextIdentificationFrame * frame;
+    gchar *tag_str;
+
+    tag_str = g_strdup_printf ("%u", (guint)bpm);
+
+    GST_DEBUG ("Setting %s to %s", tag, tag_str);
+    frame = new ID3v2::TextIdentificationFrame ("TBPM", String::UTF8);
+    id3v2tag->addFrame (frame);
+    frame->setText (tag_str);
+    g_free (tag_str);
+  }
+}
+
+/* id3demux produces these for frames it cannot parse */
+#define GST_ID3_DEMUX_TAG_ID3V2_FRAME "private-id3v2-frame"
+
+static const struct
+{
+  const gchar *gst_tag;
+  const GstId3v2MuxAddTagFunc func;
+  const gchar data[5];
+} add_funcs[] = {
+  {
+  GST_TAG_ARTIST, add_text_tag, "TPE1"}, {
+  GST_TAG_ALBUM_ARTIST, add_text_tag, "TPE2"}, {
+  GST_TAG_TITLE, add_text_tag, "TIT2"}, {
+  GST_TAG_ALBUM, add_text_tag, "TALB"}, {
+  GST_TAG_COPYRIGHT, add_text_tag, "TCOP"}, {
+  GST_TAG_COMPOSER, add_text_tag, "TCOM"}, {
+  GST_TAG_GENRE, add_text_tag, "TCON"}, {
+  GST_TAG_COMMENT, add_comment_tag, ""}, {
+  GST_TAG_EXTENDED_COMMENT, add_comment_tag, ""}, {
+  GST_TAG_DATE, add_date_tag, ""}, {
+  GST_TAG_IMAGE, add_image_tag, ""}, {
+  GST_TAG_PREVIEW_IMAGE, add_image_tag, ""}, {
+  GST_ID3_DEMUX_TAG_ID3V2_FRAME, add_id3v2frame_tag, ""}, {
+  GST_TAG_MUSICBRAINZ_ARTISTID, add_musicbrainz_tag, "\000"}, {
+  GST_TAG_MUSICBRAINZ_ALBUMID, add_musicbrainz_tag, "\001"}, {
+  GST_TAG_MUSICBRAINZ_ALBUMARTISTID, add_musicbrainz_tag, "\002"}, {
+  GST_TAG_MUSICBRAINZ_TRMID, add_musicbrainz_tag, "\003"}, {
+  GST_TAG_CDDA_MUSICBRAINZ_DISCID, add_musicbrainz_tag, "\004"}, {
+  GST_TAG_CDDA_CDDB_DISCID, add_musicbrainz_tag, "\005"}, {
+  GST_TAG_MUSICBRAINZ_TRACKID, add_unique_file_id_tag, ""}, {
+  GST_TAG_ARTIST_SORTNAME, add_text_tag, "TSOP"}, {
+  GST_TAG_ALBUM_SORTNAME, add_text_tag, "TSOA"}, {
+  GST_TAG_TITLE_SORTNAME, add_text_tag, "TSOT"}, {
+  GST_TAG_TRACK_NUMBER, add_count_or_num_tag, "TRCK"}, {
+  GST_TAG_TRACK_COUNT, add_count_or_num_tag, "TRCK"}, {
+  GST_TAG_ALBUM_VOLUME_NUMBER, add_count_or_num_tag, "TPOS"}, {
+  GST_TAG_ALBUM_VOLUME_COUNT, add_count_or_num_tag, "TPOS"}, {
+  GST_TAG_ENCODER, add_encoder_tag, ""}, {
+  GST_TAG_ENCODER_VERSION, add_encoder_tag, ""}, {
+  GST_TAG_COPYRIGHT_URI, add_uri_tag, "WCOP"}, {
+  GST_TAG_LICENSE_URI, add_uri_tag, "WCOP"}, {
+  GST_TAG_TRACK_PEAK, add_relative_volume_tag, ""}, {
+  GST_TAG_TRACK_GAIN, add_relative_volume_tag, ""}, {
+  GST_TAG_ALBUM_PEAK, add_relative_volume_tag, ""}, {
+  GST_TAG_ALBUM_GAIN, add_relative_volume_tag, ""}, {
+  GST_TAG_BEATS_PER_MINUTE, add_bpm_tag, ""}
+};
+
+
+static void
+foreach_add_tag (const GstTagList * list, const gchar * tag, gpointer userdata)
+{
+  ID3v2::Tag * id3v2tag = (ID3v2::Tag *) userdata;
+  TagLib::StringList string_list;
+  guint num_tags, i;
+
+  num_tags = gst_tag_list_get_tag_size (list, tag);
+
+  GST_LOG ("Processing tag %s (num=%u)", tag, num_tags);
+
+  if (num_tags > 1 && gst_tag_is_fixed (tag)) {
+    GST_WARNING ("Multiple occurences of fixed tag '%s', ignoring some", tag);
+    num_tags = 1;
+  }
+
+  for (i = 0; i < G_N_ELEMENTS (add_funcs); ++i) {
+    if (strcmp (add_funcs[i].gst_tag, tag) == 0) {
+      add_funcs[i].func (id3v2tag, list, tag, num_tags, add_funcs[i].data);
+      break;
+    }
+  }
+
+  if (i == G_N_ELEMENTS (add_funcs)) {
+    GST_WARNING ("Unsupported tag '%s' - not written", tag);
+  }
+}
+
+static GstBuffer *
+gst_id3v2_mux_render_tag (GstTagMux * mux, const GstTagList * taglist)
+{
+  ID3v2::Tag id3v2tag;
+  ByteVector rendered_tag;
+  GstBuffer *buf;
+  guint tag_size;
+
+  /* write all strings as UTF-8 by default */
+  TagLib::ID3v2::FrameFactory::instance ()->
+      setDefaultTextEncoding (TagLib::String::UTF8);
+
+  /* Render the tag */
+  gst_tag_list_foreach (taglist, foreach_add_tag, &id3v2tag);
+
+#if 0
+  /* Do we want to add our own signature to the tag somewhere? */
+  {
+    gchar *tag_producer_str;
+
+    tag_producer_str = g_strdup_printf ("(GStreamer id3v2mux %s, using "
+        "taglib %u.%u)", VERSION, TAGLIB_MAJOR_VERSION, TAGLIB_MINOR_VERSION);
+    add_one_txxx_tag (id3v2tag, "tag_encoder", tag_producer_str);
+    g_free (tag_producer_str);
+  }
+#endif
+
+  rendered_tag = id3v2tag.render ();
+  tag_size = rendered_tag.size ();
+
+  GST_LOG_OBJECT (mux, "tag size = %d bytes", tag_size);
+
+  /* Create buffer with tag */
+  buf = gst_buffer_new_and_alloc (tag_size);
+  gst_buffer_fill (buf, 0, rendered_tag.data (), tag_size);
+
+  return buf;
+}
+
+static GstBuffer *
+gst_id3v2_mux_render_end_tag (GstTagMux * mux, const GstTagList * taglist)
+{
+  return NULL;
+}
diff --git a/ext/taglib/gstid3v2mux.h b/ext/taglib/gstid3v2mux.h
new file mode 100644
index 0000000..36c748f
--- /dev/null
+++ b/ext/taglib/gstid3v2mux.h
@@ -0,0 +1,54 @@
+/* GStreamer taglib-based ID3v2 muxer
+ * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GST_ID3V2_MUX_H
+#define GST_ID3V2_MUX_H
+
+#include <gst/tag/gsttagmux.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstId3v2Mux GstId3v2Mux;
+typedef struct _GstId3v2MuxClass GstId3v2MuxClass;
+
+struct _GstId3v2Mux {
+  GstTagMux  tagmux;
+};
+
+struct _GstId3v2MuxClass {
+  GstTagMuxClass  tagmux_class;
+};
+
+#define GST_TYPE_ID3V2_MUX \
+  (gst_id3v2_mux_get_type())
+#define GST_ID3V2_MUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ID3V2_MUX,GstId3v2Mux))
+#define GST_ID3V2_MUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ID3V2_MUX,GstId3v2MuxClass))
+#define GST_IS_ID3V2_MUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ID3V2_MUX))
+#define GST_IS_ID3V2_MUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ID3V2_MUX))
+
+GType gst_id3v2_mux_get_type (void);
+
+G_END_DECLS
+
+#endif /* GST_ID3V2_MUX_H */
diff --git a/ext/taglib/gsttaglibplugin.c b/ext/taglib/gsttaglibplugin.c
new file mode 100644
index 0000000..dce6bf6
--- /dev/null
+++ b/ext/taglib/gsttaglibplugin.c
@@ -0,0 +1,49 @@
+/* GStreamer taglib-based muxer base class
+ * Copyright (C) 2006 Christophe Fergeau  <teuf@gnome.org>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstapev2mux.h"
+#include "gstid3v2mux.h"
+
+#include <gst/tag/tag.h>
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "id3v2mux", GST_RANK_NONE,
+          GST_TYPE_ID3V2_MUX) ||
+      !gst_element_register (plugin, "apev2mux", GST_RANK_NONE,
+          GST_TYPE_APEV2_MUX))
+    return FALSE;
+
+  gst_tag_register_musicbrainz_tags ();
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    taglib,
+    "Tag writing plug-in based on taglib",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/ext/taglib/meson.build b/ext/taglib/meson.build
new file mode 100644
index 0000000..241f9b5
--- /dev/null
+++ b/ext/taglib/meson.build
@@ -0,0 +1,28 @@
+taglib_sources = [
+  'gstapev2mux.cc',
+  'gstid3v2mux.cc',
+  'gsttaglibplugin.c',
+]
+
+taglib_dep = dependency('taglib', version : '>= 1.5', required : false)
+
+if taglib_dep.found() and add_languages('cpp', required : false)
+  extra_args = []
+  cxx = meson.get_compiler('cpp')
+  if cxx.has_argument('-fvisibility=hidden')
+    extra_args += ['-fvisibility=hidden']
+  endif
+  if cxx.has_argument('-fno-strict-aliasing')
+    extra_args += ['-fno-strict-aliasing']
+  endif
+
+  gsttaglib = library('gsttaglib',
+    taglib_sources,
+    c_args : gst_plugins_good_args + ['-DGST_USE_UNSTABLE_API'],
+    cpp_args : gst_plugins_good_args + ['-DGST_USE_UNSTABLE_API'] + extra_args,
+    include_directories : [configinc, libsinc],
+    dependencies : [gsttag_dep, taglib_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/ext/twolame/Makefile.am b/ext/twolame/Makefile.am
new file mode 100644
index 0000000..362ee20
--- /dev/null
+++ b/ext/twolame/Makefile.am
@@ -0,0 +1,11 @@
+plugin_LTLIBRARIES = libgsttwolame.la
+
+libgsttwolame_la_SOURCES = gsttwolamemp2enc.c
+libgsttwolame_la_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(TWOLAME_CFLAGS)
+libgsttwolame_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+	-lgstaudio-@GST_API_VERSION@ -lgstpbutils-@GST_API_VERSION@ \
+	$(GST_LIBS) $(TWOLAME_LIBS)
+libgsttwolame_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gsttwolamemp2enc.h
diff --git a/ext/twolame/gsttwolamemp2enc.c b/ext/twolame/gsttwolamemp2enc.c
new file mode 100644
index 0000000..31bec6b
--- /dev/null
+++ b/ext/twolame/gsttwolamemp2enc.c
@@ -0,0 +1,893 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2004> Wim Taymans <wim@fluendo.com>
+ * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
+ * Copyright (C) <2008> Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Based on the lame element.
+ */
+
+/**
+ * SECTION:element-twolame
+ * @see_also: mad, lame
+ *
+ * This element encodes raw integer audio into an MPEG-1 layer 2 (MP2) stream.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc wave=sine num-buffers=100 ! audioconvert ! twolame ! filesink location=sine.mp2
+ * ]| Encode a test sine signal to MP2.
+ * |[
+ * gst-launch-1.0 -v alsasrc ! audioconvert ! twolame bitrate=192 ! filesink location=alsasrc.mp2
+ * ]| Record from a sound card using ALSA and encode to MP2
+ * |[
+ * gst-launch-1.0 -v filesrc location=music.wav ! decodebin ! audioconvert ! audioresample ! twolame bitrate=192 ! id3v2mux ! filesink location=music.mp2
+ * ]| Transcode from a .wav file to MP2 (the id3v2mux element is optional)
+ * |[
+ * gst-launch-1.0 -v cdda://5 ! audioconvert ! twolame bitrate=192 ! filesink location=track5.mp2
+ * ]| Encode Audio CD track 5 to MP2
+ * </refsect2>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "string.h"
+#include "gsttwolamemp2enc.h"
+#include "gst/gst-i18n-plugin.h"
+
+GST_DEBUG_CATEGORY_STATIC (debug);
+#define GST_CAT_DEFAULT debug
+
+/* TwoLAME can do MPEG-1, MPEG-2 so it has 6 possible
+ * sample rates it supports */
+static GstStaticPadTemplate gst_two_lame_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) { " GST_AUDIO_NE (F32) ", " GST_AUDIO_NE (S16) " }, "
+        "layout = (string) interleaved, "
+        "rate = (int) { 16000, 22050, 24000, 32000, 44100, 48000 }, "
+        "channels = (int) 1; "
+        "audio/x-raw, "
+        "format = (string) { " GST_AUDIO_NE (F32) ", " GST_AUDIO_NE (S16) " }, "
+        "layout = (string) interleaved, "
+        "rate = (int) { 16000, 22050, 24000, 32000, 44100, 48000 }, "
+        "channels = (int) 2," "channel-mask = (bitmask) 0x3")
+    );
+
+static GstStaticPadTemplate gst_two_lame_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/mpeg, "
+        "mpegversion = (int) 1, "
+        "layer = (int) 2, "
+        "rate = (int) { 16000, 22050, 24000, 32000, 44100, 48000 }, "
+        "channels = (int) [ 1, 2 ]")
+    );
+
+static struct
+{
+  gint mode;
+  gint psymodel;
+  gint bitrate;
+  gint padding;
+  gboolean energy_level_extension;
+  gint emphasis;
+  gboolean error_protection;
+  gboolean copyright;
+  gboolean original;
+  gboolean vbr;
+  gfloat vbr_level;
+  gfloat ath_level;
+  gint vbr_max_bitrate;
+  gboolean quick_mode;
+  gint quick_mode_count;
+} gst_two_lame_default_settings;
+
+/********** Define useful types for non-programmatic interfaces **********/
+#define GST_TYPE_TWO_LAME_MODE (gst_two_lame_mode_get_type())
+static GType
+gst_two_lame_mode_get_type (void)
+{
+  static GType two_lame_mode_type = 0;
+  static const GEnumValue two_lame_modes[] = {
+    {TWOLAME_AUTO_MODE, "Auto", "auto"},
+    {TWOLAME_STEREO, "Stereo", "stereo"},
+    {TWOLAME_JOINT_STEREO, "Joint Stereo", "joint"},
+    {TWOLAME_DUAL_CHANNEL, "Dual Channel", "dual"},
+    {TWOLAME_MONO, "Mono", "mono"},
+    {0, NULL, NULL}
+  };
+
+  if (!two_lame_mode_type) {
+    two_lame_mode_type =
+        g_enum_register_static ("GstTwoLameMode", two_lame_modes);
+  }
+  return two_lame_mode_type;
+}
+
+#define GST_TYPE_TWO_LAME_PADDING (gst_two_lame_padding_get_type())
+static GType
+gst_two_lame_padding_get_type (void)
+{
+  static GType two_lame_padding_type = 0;
+  static const GEnumValue two_lame_padding[] = {
+    {TWOLAME_PAD_NO, "No Padding", "never"},
+    {TWOLAME_PAD_ALL, "Always Pad", "always"},
+    {0, NULL, NULL}
+  };
+
+  if (!two_lame_padding_type) {
+    two_lame_padding_type =
+        g_enum_register_static ("GstTwoLamePadding", two_lame_padding);
+  }
+  return two_lame_padding_type;
+}
+
+#define GST_TYPE_TWO_LAME_EMPHASIS (gst_two_lame_emphasis_get_type())
+static GType
+gst_two_lame_emphasis_get_type (void)
+{
+  static GType two_lame_emphasis_type = 0;
+  static const GEnumValue two_lame_emphasis[] = {
+    {TWOLAME_EMPHASIS_N, "No emphasis", "none"},
+    {TWOLAME_EMPHASIS_5, "50/15 ms", "5"},
+    {TWOLAME_EMPHASIS_C, "CCIT J.17", "ccit"},
+    {0, NULL, NULL}
+  };
+
+  if (!two_lame_emphasis_type) {
+    two_lame_emphasis_type =
+        g_enum_register_static ("GstTwoLameEmphasis", two_lame_emphasis);
+  }
+
+  return two_lame_emphasis_type;
+}
+
+/********** Standard stuff for signals and arguments **********/
+
+enum
+{
+  ARG_0,
+  ARG_MODE,
+  ARG_PSYMODEL,
+  ARG_BITRATE,
+  ARG_PADDING,
+  ARG_ENERGY_LEVEL_EXTENSION,
+  ARG_EMPHASIS,
+  ARG_ERROR_PROTECTION,
+  ARG_COPYRIGHT,
+  ARG_ORIGINAL,
+  ARG_VBR,
+  ARG_VBR_LEVEL,
+  ARG_ATH_LEVEL,
+  ARG_VBR_MAX_BITRATE,
+  ARG_QUICK_MODE,
+  ARG_QUICK_MODE_COUNT
+};
+
+static gboolean gst_two_lame_start (GstAudioEncoder * enc);
+static gboolean gst_two_lame_stop (GstAudioEncoder * enc);
+static gboolean gst_two_lame_set_format (GstAudioEncoder * enc,
+    GstAudioInfo * info);
+static GstFlowReturn gst_two_lame_handle_frame (GstAudioEncoder * enc,
+    GstBuffer * in_buf);
+static void gst_two_lame_flush (GstAudioEncoder * enc);
+
+static void gst_two_lame_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_two_lame_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static gboolean gst_two_lame_setup (GstTwoLame * twolame);
+
+G_DEFINE_TYPE (GstTwoLame, gst_two_lame, GST_TYPE_AUDIO_ENCODER);
+
+static void
+gst_two_lame_release_memory (GstTwoLame * twolame)
+{
+  if (twolame->glopts) {
+    twolame_close (&twolame->glopts);
+    twolame->glopts = NULL;
+  }
+}
+
+static void
+gst_two_lame_finalize (GObject * obj)
+{
+  gst_two_lame_release_memory (GST_TWO_LAME (obj));
+
+  G_OBJECT_CLASS (gst_two_lame_parent_class)->finalize (obj);
+}
+
+static void
+gst_two_lame_class_init (GstTwoLameClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstAudioEncoderClass *gstbase_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstbase_class = (GstAudioEncoderClass *) klass;
+
+  gobject_class->set_property = gst_two_lame_set_property;
+  gobject_class->get_property = gst_two_lame_get_property;
+  gobject_class->finalize = gst_two_lame_finalize;
+
+  gstbase_class->start = GST_DEBUG_FUNCPTR (gst_two_lame_start);
+  gstbase_class->stop = GST_DEBUG_FUNCPTR (gst_two_lame_stop);
+  gstbase_class->set_format = GST_DEBUG_FUNCPTR (gst_two_lame_set_format);
+  gstbase_class->handle_frame = GST_DEBUG_FUNCPTR (gst_two_lame_handle_frame);
+  gstbase_class->flush = GST_DEBUG_FUNCPTR (gst_two_lame_flush);
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MODE,
+      g_param_spec_enum ("mode", "Mode", "Encoding mode",
+          GST_TYPE_TWO_LAME_MODE, gst_two_lame_default_settings.mode,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PSYMODEL,
+      g_param_spec_int ("psymodel", "Psychoacoustic Model",
+          "Psychoacoustic model used to encode the audio",
+          -1, 4, gst_two_lame_default_settings.psymodel,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
+      g_param_spec_int ("bitrate", "Bitrate (kb/s)",
+          "Bitrate in kbit/sec (8, 16, 24, 32, 40, 48, 56, 64, 80, 96, "
+          "112, 128, 144, 160, 192, 224, 256, 320, 384)",
+          8, 384, gst_two_lame_default_settings.bitrate,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PADDING,
+      g_param_spec_enum ("padding", "Padding", "Padding type",
+          GST_TYPE_TWO_LAME_PADDING, gst_two_lame_default_settings.padding,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      ARG_ENERGY_LEVEL_EXTENSION,
+      g_param_spec_boolean ("energy-level-extension", "Energy Level Extension",
+          "Write peak PCM level to each frame",
+          gst_two_lame_default_settings.energy_level_extension,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EMPHASIS,
+      g_param_spec_enum ("emphasis", "Emphasis",
+          "Pre-emphasis to apply to the decoded audio",
+          GST_TYPE_TWO_LAME_EMPHASIS, gst_two_lame_default_settings.emphasis,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ERROR_PROTECTION,
+      g_param_spec_boolean ("error-protection", "Error protection",
+          "Adds checksum to every frame",
+          gst_two_lame_default_settings.error_protection,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COPYRIGHT,
+      g_param_spec_boolean ("copyright", "Copyright", "Mark as copyright",
+          gst_two_lame_default_settings.copyright,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ORIGINAL,
+      g_param_spec_boolean ("original", "Original", "Mark as original",
+          gst_two_lame_default_settings.original,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR,
+      g_param_spec_boolean ("vbr", "VBR", "Enable variable bitrate mode",
+          gst_two_lame_default_settings.vbr,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR_LEVEL,
+      g_param_spec_float ("vbr-level", "VBR Level", "VBR Level",
+          -10.0, 10.0, gst_two_lame_default_settings.vbr_level,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ATH_LEVEL,
+      g_param_spec_float ("ath-level", "ATH Level", "ATH Level in dB",
+          -G_MAXFLOAT, G_MAXFLOAT, gst_two_lame_default_settings.ath_level,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR_MAX_BITRATE,
+      g_param_spec_int ("vbr-max-bitrate", "VBR max bitrate",
+          "Specify maximum VBR bitrate (0=off, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, "
+          "112, 128, 144, 160, 192, 224, 256, 320, 384)",
+          0, 384, gst_two_lame_default_settings.vbr_max_bitrate,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUICK_MODE,
+      g_param_spec_boolean ("quick-mode", "Quick mode",
+          "Calculate Psymodel every frames",
+          gst_two_lame_default_settings.quick_mode,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUICK_MODE_COUNT,
+      g_param_spec_int ("quick-mode-count", "Quick mode count",
+          "Calculate Psymodel every n frames",
+          0, G_MAXINT, gst_two_lame_default_settings.quick_mode_count,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS (klass),
+      &gst_two_lame_src_template);
+  gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS (klass),
+      &gst_two_lame_sink_template);
+
+  gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass),
+      "TwoLAME mp2 encoder", "Codec/Encoder/Audio",
+      "High-quality free MP2 encoder",
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+}
+
+static gboolean
+gst_two_lame_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
+{
+  GstTwoLame *twolame;
+  gint out_samplerate;
+  gint version;
+  GstCaps *othercaps;
+
+  twolame = GST_TWO_LAME (enc);
+
+  /* parameters already parsed for us */
+  twolame->samplerate = GST_AUDIO_INFO_RATE (info);
+  twolame->num_channels = GST_AUDIO_INFO_CHANNELS (info);
+  twolame->float_input = !GST_AUDIO_INFO_IS_INTEGER (info);
+
+  /* but we might be asked to reconfigure, so reset */
+  gst_two_lame_release_memory (twolame);
+
+  GST_DEBUG_OBJECT (twolame, "setting up twolame");
+  if (!gst_two_lame_setup (twolame))
+    goto setup_failed;
+
+  out_samplerate = twolame_get_out_samplerate (twolame->glopts);
+  if (out_samplerate == 0)
+    goto zero_output_rate;
+
+  if (out_samplerate != twolame->samplerate) {
+    GST_WARNING_OBJECT (twolame,
+        "output samplerate %d is different from incoming samplerate %d",
+        out_samplerate, twolame->samplerate);
+  }
+
+  version = twolame_get_version (twolame->glopts);
+  if (version == TWOLAME_MPEG2)
+    version = 2;
+  else
+    version = 1;
+
+  othercaps =
+      gst_caps_new_simple ("audio/mpeg",
+      "mpegversion", G_TYPE_INT, 1,
+      "mpegaudioversion", G_TYPE_INT, version,
+      "layer", G_TYPE_INT, 2,
+      "channels", G_TYPE_INT,
+      twolame->mode == TWOLAME_MONO ? 1 : twolame->num_channels, "rate",
+      G_TYPE_INT, out_samplerate, NULL);
+
+  /* and use these caps */
+  gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (twolame), othercaps);
+  gst_caps_unref (othercaps);
+
+  /* report needs to base class:
+   * hand one frame at a time, if we are pretty sure what a frame is */
+  if (out_samplerate == twolame->samplerate) {
+    gst_audio_encoder_set_frame_samples_min (enc, 1152);
+    gst_audio_encoder_set_frame_samples_max (enc, 1152);
+    gst_audio_encoder_set_frame_max (enc, 1);
+  }
+
+  return TRUE;
+
+zero_output_rate:
+  {
+    GST_ELEMENT_ERROR (twolame, LIBRARY, SETTINGS, (NULL),
+        ("TwoLAME decided on a zero sample rate"));
+    return FALSE;
+  }
+setup_failed:
+  {
+    GST_ELEMENT_ERROR (twolame, LIBRARY, SETTINGS,
+        (_("Failed to configure TwoLAME encoder. Check your encoding parameters.")), (NULL));
+    return FALSE;
+  }
+}
+
+static void
+gst_two_lame_init (GstTwoLame * twolame)
+{
+  GST_DEBUG_OBJECT (twolame, "starting initialization");
+
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (twolame));
+
+  twolame->mode = gst_two_lame_default_settings.mode;
+  twolame->psymodel = gst_two_lame_default_settings.psymodel;
+  twolame->bitrate = gst_two_lame_default_settings.bitrate;
+  twolame->padding = gst_two_lame_default_settings.padding;
+  twolame->energy_level_extension =
+      gst_two_lame_default_settings.energy_level_extension;
+  twolame->emphasis = gst_two_lame_default_settings.emphasis;
+  twolame->error_protection = gst_two_lame_default_settings.error_protection;
+  twolame->copyright = gst_two_lame_default_settings.copyright;
+  twolame->original = gst_two_lame_default_settings.original;
+  twolame->vbr = gst_two_lame_default_settings.vbr;
+  twolame->vbr_level = gst_two_lame_default_settings.vbr_level;
+  twolame->ath_level = gst_two_lame_default_settings.ath_level;
+  twolame->vbr_max_bitrate = gst_two_lame_default_settings.vbr_max_bitrate;
+  twolame->quick_mode = gst_two_lame_default_settings.quick_mode;
+  twolame->quick_mode_count = gst_two_lame_default_settings.quick_mode_count;
+
+  GST_DEBUG_OBJECT (twolame, "done initializing");
+}
+
+static gboolean
+gst_two_lame_start (GstAudioEncoder * enc)
+{
+  GstTwoLame *twolame = GST_TWO_LAME (enc);
+
+  GST_DEBUG_OBJECT (twolame, "start");
+  return TRUE;
+}
+
+static gboolean
+gst_two_lame_stop (GstAudioEncoder * enc)
+{
+  GstTwoLame *twolame = GST_TWO_LAME (enc);
+
+  GST_DEBUG_OBJECT (twolame, "stop");
+
+  gst_two_lame_release_memory (twolame);
+  return TRUE;
+}
+
+/* <php-emulation-mode>three underscores for ___rate is really really really
+ * private as opposed to one underscore<php-emulation-mode> */
+/* call this MACRO outside of the NULL state so that we have a higher chance
+ * of actually having a pipeline and bus to get the message through */
+
+#define CHECK_AND_FIXUP_BITRATE(obj,param,rate)         		  \
+G_STMT_START {                                                            \
+  gint ___rate = rate;                                                    \
+  gint maxrate = 320;							  \
+  gint multiplier = 64;							  \
+  if (rate <= 64) {							  \
+    maxrate = 64; multiplier = 8;                                         \
+    if ((rate % 8) != 0) ___rate = GST_ROUND_UP_8 (rate); 		  \
+  } else if (rate <= 144) {						  \
+    maxrate = 144; multiplier = 16;                                       \
+    if ((rate % 16) != 0) ___rate = GST_ROUND_UP_16 (rate);               \
+  } else if (rate <= 256) {						  \
+    maxrate = 256; multiplier = 32;                                       \
+    if ((rate % 32) != 0) ___rate = GST_ROUND_UP_32 (rate);               \
+  } else if (rate <= 384) { 						  \
+    maxrate = 384; multiplier = 64;                                       \
+    if ((rate % 64) != 0) ___rate = GST_ROUND_UP_64 (rate);               \
+  }                                                                       \
+  if (___rate != rate) {                                                  \
+    GST_ELEMENT_WARNING (obj, LIBRARY, SETTINGS,			  \
+        (_("The requested bitrate %d kbit/s for property '%s' "           \
+           "is not allowed. "  					          \
+           "The bitrate was changed to %d kbit/s."), rate,		  \
+         param,  ___rate), 					          \
+        ("A bitrate below %d should be a multiple of %d.", 		  \
+            maxrate, multiplier));		  			  \
+    rate = ___rate;                                                       \
+  }                                                                       \
+} G_STMT_END
+
+static void
+gst_two_lame_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstTwoLame *twolame = GST_TWO_LAME (object);
+
+  switch (prop_id) {
+    case ARG_MODE:
+      twolame->mode = g_value_get_enum (value);
+      break;
+    case ARG_PSYMODEL:
+      twolame->psymodel = g_value_get_int (value);
+      break;
+    case ARG_BITRATE:
+      twolame->bitrate = g_value_get_int (value);
+      break;
+    case ARG_PADDING:
+      twolame->padding = g_value_get_enum (value);
+      break;
+    case ARG_ENERGY_LEVEL_EXTENSION:
+      twolame->energy_level_extension = g_value_get_boolean (value);
+      break;
+    case ARG_EMPHASIS:
+      twolame->emphasis = g_value_get_enum (value);
+      break;
+    case ARG_ERROR_PROTECTION:
+      twolame->error_protection = g_value_get_boolean (value);
+      break;
+    case ARG_COPYRIGHT:
+      twolame->copyright = g_value_get_boolean (value);
+      break;
+    case ARG_ORIGINAL:
+      twolame->original = g_value_get_boolean (value);
+      break;
+    case ARG_VBR:
+      twolame->vbr = g_value_get_boolean (value);
+      break;
+    case ARG_VBR_LEVEL:
+      twolame->vbr_level = g_value_get_float (value);
+      break;
+    case ARG_ATH_LEVEL:
+      twolame->ath_level = g_value_get_float (value);
+      break;
+    case ARG_VBR_MAX_BITRATE:
+      twolame->vbr_max_bitrate = g_value_get_int (value);
+      break;
+    case ARG_QUICK_MODE:
+      twolame->quick_mode = g_value_get_boolean (value);
+      break;
+    case ARG_QUICK_MODE_COUNT:
+      twolame->quick_mode_count = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_two_lame_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstTwoLame *twolame = GST_TWO_LAME (object);
+
+  switch (prop_id) {
+    case ARG_MODE:
+      g_value_set_enum (value, twolame->mode);
+      break;
+    case ARG_PSYMODEL:
+      g_value_set_int (value, twolame->psymodel);
+      break;
+    case ARG_BITRATE:
+      g_value_set_int (value, twolame->bitrate);
+      break;
+    case ARG_PADDING:
+      g_value_set_enum (value, twolame->padding);
+      break;
+    case ARG_ENERGY_LEVEL_EXTENSION:
+      g_value_set_boolean (value, twolame->energy_level_extension);
+      break;
+    case ARG_EMPHASIS:
+      g_value_set_enum (value, twolame->emphasis);
+      break;
+    case ARG_ERROR_PROTECTION:
+      g_value_set_boolean (value, twolame->error_protection);
+      break;
+    case ARG_COPYRIGHT:
+      g_value_set_boolean (value, twolame->copyright);
+      break;
+    case ARG_ORIGINAL:
+      g_value_set_boolean (value, twolame->original);
+      break;
+    case ARG_VBR:
+      g_value_set_boolean (value, twolame->vbr);
+      break;
+    case ARG_VBR_LEVEL:
+      g_value_set_float (value, twolame->vbr_level);
+      break;
+    case ARG_ATH_LEVEL:
+      g_value_set_float (value, twolame->ath_level);
+      break;
+    case ARG_VBR_MAX_BITRATE:
+      g_value_set_int (value, twolame->vbr_max_bitrate);
+      break;
+    case ARG_QUICK_MODE:
+      g_value_set_boolean (value, twolame->quick_mode);
+      break;
+    case ARG_QUICK_MODE_COUNT:
+      g_value_set_int (value, twolame->quick_mode_count);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstFlowReturn
+gst_two_lame_flush_full (GstTwoLame * lame, gboolean push)
+{
+  GstBuffer *buf;
+  GstMapInfo map;
+  gint size;
+  GstFlowReturn result = GST_FLOW_OK;
+
+  if (!lame->glopts)
+    return GST_FLOW_OK;
+
+  buf = gst_buffer_new_and_alloc (16384);
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  size = twolame_encode_flush (lame->glopts, map.data, 16384);
+  gst_buffer_unmap (buf, &map);
+
+  if (size > 0 && push) {
+    gst_buffer_set_size (buf, size);
+    GST_DEBUG_OBJECT (lame, "pushing final packet of %u bytes", size);
+    result = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (lame), buf, -1);
+  } else {
+    GST_DEBUG_OBJECT (lame, "no final packet (size=%d, push=%d)", size, push);
+    gst_buffer_unref (buf);
+    result = GST_FLOW_OK;
+  }
+  return result;
+}
+
+static void
+gst_two_lame_flush (GstAudioEncoder * enc)
+{
+  gst_two_lame_flush_full (GST_TWO_LAME (enc), FALSE);
+}
+
+static GstFlowReturn
+gst_two_lame_handle_frame (GstAudioEncoder * enc, GstBuffer * buf)
+{
+  GstTwoLame *twolame;
+  gint mp3_buffer_size, mp3_size;
+  GstBuffer *mp3_buf;
+  GstFlowReturn result;
+  gint num_samples;
+  GstMapInfo map, mp3_map;
+
+  twolame = GST_TWO_LAME (enc);
+
+  /* squeeze remaining and push */
+  if (G_UNLIKELY (buf == NULL))
+    return gst_two_lame_flush_full (twolame, TRUE);
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  if (twolame->float_input)
+    num_samples = map.size / 4;
+  else
+    num_samples = map.size / 2;
+
+  /* allocate space for output */
+  mp3_buffer_size = 1.25 * num_samples + 16384;
+  mp3_buf = gst_buffer_new_and_alloc (mp3_buffer_size);
+  gst_buffer_map (mp3_buf, &mp3_map, GST_MAP_WRITE);
+
+  if (twolame->num_channels == 1) {
+    if (twolame->float_input)
+      mp3_size = twolame_encode_buffer_float32 (twolame->glopts,
+          (float *) map.data,
+          (float *) map.data, num_samples, mp3_map.data, mp3_buffer_size);
+    else
+      mp3_size = twolame_encode_buffer (twolame->glopts,
+          (short int *) map.data,
+          (short int *) map.data, num_samples, mp3_map.data, mp3_buffer_size);
+  } else {
+    if (twolame->float_input)
+      mp3_size = twolame_encode_buffer_float32_interleaved (twolame->glopts,
+          (float *) map.data,
+          num_samples / twolame->num_channels, mp3_map.data, mp3_buffer_size);
+    else
+      mp3_size = twolame_encode_buffer_interleaved (twolame->glopts,
+          (short int *) map.data,
+          num_samples / twolame->num_channels, mp3_map.data, mp3_buffer_size);
+  }
+
+  GST_LOG_OBJECT (twolame, "encoded %" G_GSIZE_FORMAT " bytes of audio "
+      "to %d bytes of mp3", map.size, mp3_size);
+
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unmap (mp3_buf, &mp3_map);
+
+  if (mp3_size > 0) {
+    gst_buffer_set_size (mp3_buf, mp3_size);
+    result = gst_audio_encoder_finish_frame (enc, mp3_buf, -1);
+  } else {
+    if (mp3_size < 0) {
+      /* eat error ? */
+      g_warning ("error %d", mp3_size);
+    }
+    gst_buffer_unref (mp3_buf);
+    result = GST_FLOW_OK;
+  }
+
+  return result;
+}
+
+/* set up the encoder state */
+static gboolean
+gst_two_lame_setup (GstTwoLame * twolame)
+{
+
+#define CHECK_ERROR(command) G_STMT_START {\
+  if ((command) < 0) { \
+    GST_ERROR_OBJECT (twolame, "setup failed: " G_STRINGIFY (command)); \
+    return FALSE; \
+  } \
+}G_STMT_END
+
+  int retval;
+  GstCaps *allowed_caps;
+
+  GST_DEBUG_OBJECT (twolame, "starting setup");
+
+  /* check if we're already setup; if we are, we might want to check
+   * if this initialization is compatible with the previous one */
+  /* FIXME: do this */
+  if (twolame->setup) {
+    GST_WARNING_OBJECT (twolame, "already setup");
+    twolame->setup = FALSE;
+  }
+
+  twolame->glopts = twolame_init ();
+
+  if (twolame->glopts == NULL)
+    return FALSE;
+
+  /* copy the parameters over */
+  twolame_set_in_samplerate (twolame->glopts, twolame->samplerate);
+
+  /* let twolame choose default samplerate unless outgoing sample rate is fixed */
+  allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (twolame));
+
+  if (allowed_caps != NULL) {
+    GstStructure *structure;
+    gint samplerate;
+
+    structure = gst_caps_get_structure (allowed_caps, 0);
+
+    if (gst_structure_get_int (structure, "rate", &samplerate)) {
+      GST_DEBUG_OBJECT (twolame,
+          "Setting sample rate to %d as fixed in src caps", samplerate);
+      twolame_set_out_samplerate (twolame->glopts, samplerate);
+    } else {
+      GST_DEBUG_OBJECT (twolame, "Letting twolame choose sample rate");
+      twolame_set_out_samplerate (twolame->glopts, 0);
+    }
+    gst_caps_unref (allowed_caps);
+    allowed_caps = NULL;
+  } else {
+    GST_DEBUG_OBJECT (twolame,
+        "No peer yet, letting twolame choose sample rate");
+    twolame_set_out_samplerate (twolame->glopts, 0);
+  }
+
+  /* force mono encoding if we only have one channel */
+  if (twolame->num_channels == 1)
+    twolame->mode = 3;
+
+  /* Fix bitrates and MPEG version */
+
+  CHECK_ERROR (twolame_set_num_channels (twolame->glopts,
+          twolame->num_channels));
+
+  CHECK_ERROR (twolame_set_mode (twolame->glopts, twolame->mode));
+  CHECK_ERROR (twolame_set_psymodel (twolame->glopts, twolame->psymodel));
+  CHECK_AND_FIXUP_BITRATE (twolame, "bitrate", twolame->bitrate);
+  CHECK_ERROR (twolame_set_bitrate (twolame->glopts, twolame->bitrate));
+  CHECK_ERROR (twolame_set_padding (twolame->glopts, twolame->padding));
+  CHECK_ERROR (twolame_set_energy_levels (twolame->glopts,
+          twolame->energy_level_extension));
+  CHECK_ERROR (twolame_set_emphasis (twolame->glopts, twolame->emphasis));
+  CHECK_ERROR (twolame_set_error_protection (twolame->glopts,
+          twolame->error_protection));
+  CHECK_ERROR (twolame_set_copyright (twolame->glopts, twolame->copyright));
+  CHECK_ERROR (twolame_set_original (twolame->glopts, twolame->original));
+  CHECK_ERROR (twolame_set_VBR (twolame->glopts, twolame->vbr));
+  CHECK_ERROR (twolame_set_VBR_level (twolame->glopts, twolame->vbr_level));
+  CHECK_ERROR (twolame_set_ATH_level (twolame->glopts, twolame->ath_level));
+  CHECK_AND_FIXUP_BITRATE (twolame, "vbr-max-bitrate",
+      twolame->vbr_max_bitrate);
+  CHECK_ERROR (twolame_set_VBR_max_bitrate_kbps (twolame->glopts,
+          twolame->vbr_max_bitrate));
+  CHECK_ERROR (twolame_set_quick_mode (twolame->glopts, twolame->quick_mode));
+  CHECK_ERROR (twolame_set_quick_count (twolame->glopts,
+          twolame->quick_mode_count));
+
+  /* initialize the twolame encoder */
+  if ((retval = twolame_init_params (twolame->glopts)) >= 0) {
+    twolame->setup = TRUE;
+    /* FIXME: it would be nice to print out the mode here */
+    GST_INFO ("twolame encoder setup (%d kbit/s, %d Hz, %d channels)",
+        twolame->bitrate, twolame->samplerate, twolame->num_channels);
+  } else {
+    GST_ERROR_OBJECT (twolame, "twolame_init_params returned %d", retval);
+  }
+
+  GST_DEBUG_OBJECT (twolame, "done with setup");
+
+  return twolame->setup;
+#undef CHECK_ERROR
+}
+
+static gboolean
+gst_two_lame_get_default_settings (void)
+{
+  twolame_options *glopts = NULL;
+
+  glopts = twolame_init ();
+  if (glopts == NULL) {
+    GST_ERROR ("Couldn't initialize TwoLAME");
+    return FALSE;
+  }
+
+  twolame_set_num_channels (glopts, 2);
+  twolame_set_in_samplerate (glopts, 44100);
+
+  if (twolame_init_params (glopts) != 0) {
+    GST_ERROR ("Couldn't set default parameters");
+    return FALSE;
+  }
+
+  gst_two_lame_default_settings.mode = TWOLAME_JOINT_STEREO;    /* twolame_get_mode (glopts); */
+  gst_two_lame_default_settings.psymodel = twolame_get_psymodel (glopts);
+  gst_two_lame_default_settings.bitrate = twolame_get_bitrate (glopts);
+  gst_two_lame_default_settings.padding = twolame_get_padding (glopts);
+  gst_two_lame_default_settings.energy_level_extension =
+      twolame_get_energy_levels (glopts);
+  gst_two_lame_default_settings.emphasis = twolame_get_emphasis (glopts);
+  gst_two_lame_default_settings.error_protection =
+      twolame_get_error_protection (glopts);
+  gst_two_lame_default_settings.copyright = twolame_get_copyright (glopts);
+  gst_two_lame_default_settings.original = twolame_get_original (glopts);
+  gst_two_lame_default_settings.vbr = twolame_get_VBR (glopts);
+  gst_two_lame_default_settings.vbr_level = twolame_get_VBR_level (glopts);
+  gst_two_lame_default_settings.ath_level = twolame_get_ATH_level (glopts);
+  gst_two_lame_default_settings.vbr_max_bitrate =
+      twolame_get_VBR_max_bitrate_kbps (glopts);
+  gst_two_lame_default_settings.quick_mode = twolame_get_quick_mode (glopts);
+  gst_two_lame_default_settings.quick_mode_count =
+      twolame_get_quick_count (glopts);
+
+  twolame_close (&glopts);
+
+  return TRUE;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (debug, "twolame", 0, "twolame mp2 encoder");
+
+  if (!gst_two_lame_get_default_settings ())
+    return FALSE;
+
+#ifdef ENABLE_NLS
+  GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
+      LOCALEDIR);
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif /* ENABLE_NLS */
+
+  if (!gst_element_register (plugin, "twolamemp2enc", GST_RANK_PRIMARY,
+          GST_TYPE_TWO_LAME))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    twolame,
+    "Encode MP2s with TwoLAME",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/ext/twolame/gsttwolamemp2enc.h b/ext/twolame/gsttwolamemp2enc.h
new file mode 100644
index 0000000..72a6bea
--- /dev/null
+++ b/ext/twolame/gsttwolamemp2enc.h
@@ -0,0 +1,88 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2008> Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_TWO_LAME_H__
+#define __GST_TWO_LAME_H__
+
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudioencoder.h>
+
+G_BEGIN_DECLS
+
+#include <twolame.h>
+
+#define GST_TYPE_TWO_LAME \
+  (gst_two_lame_get_type())
+#define GST_TWO_LAME(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TWO_LAME,GstTwoLame))
+#define GST_TWO_LAME_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TWO_LAME,GstTwoLameClass))
+#define GST_IS_TWO_LAME(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TWO_LAME))
+#define GST_IS_TWO_LAME_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TWO_LAME))
+
+typedef struct _GstTwoLame GstTwoLame;
+typedef struct _GstTwoLameClass GstTwoLameClass;
+
+/**
+ * GstTwoLame:
+ *
+ * Opaque data structure.
+ */
+struct _GstTwoLame {
+  GstAudioEncoder element;
+
+  gint samplerate;
+  gint num_channels;
+  gboolean float_input;
+  gboolean setup;
+
+  gint mode;
+  gint psymodel;
+  gint bitrate;
+  gint padding;
+  gboolean energy_level_extension;
+  gint emphasis;
+  gboolean error_protection;
+  gboolean copyright;
+  gboolean original;
+  gboolean vbr;
+  gfloat vbr_level;
+  gfloat ath_level;
+  gint vbr_max_bitrate;
+  gboolean quick_mode;
+  gint quick_mode_count;
+
+  twolame_options *glopts;
+};
+
+struct _GstTwoLameClass {
+  GstAudioEncoderClass parent_class;
+};
+
+GType gst_two_lame_get_type(void);
+
+G_END_DECLS
+
+
+#endif /* __GST_TWO_LAME_H__ */
diff --git a/ext/twolame/meson.build b/ext/twolame/meson.build
new file mode 100644
index 0000000..cabab63
--- /dev/null
+++ b/ext/twolame/meson.build
@@ -0,0 +1,12 @@
+twolame_dep = dependency('twolame', version : '>= 0.3.10', required : false)
+
+if twolame_dep.found()
+  twolame = library('gsttwolame',
+    ['gsttwolamemp2enc.c'],
+    c_args : gst_plugins_good_args,
+    include_directories : [configinc, libsinc],
+    dependencies : [gstaudio_dep, twolame_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/ext/vpx/GstVP8Enc.prs b/ext/vpx/GstVP8Enc.prs
new file mode 100644
index 0000000..a013959
--- /dev/null
+++ b/ext/vpx/GstVP8Enc.prs
@@ -0,0 +1,8 @@
+[_presets_]
+version=0.10
+element-name=GstVP8Enc
+
+[Profile Realtime]
+deadline=1
+cpu-used=4
+lag-in-frames=0
diff --git a/ext/vpx/Makefile.am b/ext/vpx/Makefile.am
new file mode 100644
index 0000000..71ce6de
--- /dev/null
+++ b/ext/vpx/Makefile.am
@@ -0,0 +1,37 @@
+plugin_LTLIBRARIES = \
+	libgstvpx.la
+
+libgstvpx_la_SOURCES = \
+    gstvpxdec.c \
+    gstvpxenc.c \
+	gstvp8dec.c \
+	gstvp8enc.c \
+	gstvp8utils.c \
+	gstvp9dec.c \
+	gstvp9enc.c \
+	plugin.c
+
+libgstvpx_la_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS) \
+	$(VPX_CFLAGS) \
+	-DGST_USE_UNSTABLE_API
+libgstvpx_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) -lgsttag-@GST_API_VERSION@ -lgstvideo-@GST_API_VERSION@ \
+	$(GST_BASE_LIBS) $(GST_LIBS) $(VPX_LIBS)
+libgstvpx_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = \
+    gstvpxdec.h \
+    gstvpxenc.h \
+	gstvp8dec.h \
+	gstvp8enc.h \
+	gstvp9dec.h \
+	gstvp9enc.h \
+	gstvp8utils.h
+
+presetdir = $(datadir)/gstreamer-$(GST_API_VERSION)/presets
+preset_DATA = GstVP8Enc.prs
+
+EXTRA_DIST = $(preset_DATA)
diff --git a/ext/vpx/gstvp8dec.c b/ext/vpx/gstvp8dec.c
new file mode 100644
index 0000000..6a9625c
--- /dev/null
+++ b/ext/vpx/gstvp8dec.c
@@ -0,0 +1,157 @@
+/* VP8
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ * Copyright (C) 2008,2009,2010 Entropy Wave Inc
+ * Copyright (C) 2010-2012 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+/**
+ * SECTION:element-vp8dec
+ * @see_also: vp8enc, matroskademux
+ *
+ * This element decodes VP8 streams into raw video.
+ * <ulink url="http://www.webmproject.org">VP8</ulink> is a royalty-free
+ * video codec maintained by <ulink url="http://www.google.com/">Google
+ * </ulink>. It's the successor of On2 VP3, which was the base of the
+ * Theora video codec.
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 -v filesrc location=videotestsrc.webm ! matroskademux ! vp8dec ! videoconvert ! videoscale ! autovideosink
+ * ]| This example pipeline will decode a WebM stream and decodes the VP8 video.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_VP8_DECODER
+
+#include <string.h>
+
+#include "gstvp8dec.h"
+#include "gstvp8utils.h"
+
+#include <gst/video/gstvideometa.h>
+#include <gst/video/gstvideopool.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_vp8dec_debug);
+#define GST_CAT_DEFAULT gst_vp8dec_debug
+
+#define VP8_DECODER_VIDEO_TAG "VP8 video"
+
+static void gst_vp8_dec_set_default_format (GstVPXDec * dec, GstVideoFormat fmt,
+    int width, int height);
+static void gst_vp8_dec_handle_resolution_change (GstVPXDec * dec,
+    vpx_image_t * img, GstVideoFormat fmt);
+
+static GstStaticPadTemplate gst_vp8_dec_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-vp8")
+    );
+
+static GstStaticPadTemplate gst_vp8_dec_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420"))
+    );
+
+#define parent_class gst_vp8_dec_parent_class
+G_DEFINE_TYPE (GstVP8Dec, gst_vp8_dec, GST_TYPE_VPX_DEC);
+
+static void
+gst_vp8_dec_class_init (GstVP8DecClass * klass)
+{
+  GstElementClass *element_class;
+  GstVPXDecClass *vpx_class;
+
+  element_class = GST_ELEMENT_CLASS (klass);
+  vpx_class = GST_VPX_DEC_CLASS (klass);
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_vp8_dec_sink_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_vp8_dec_src_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "On2 VP8 Decoder",
+      "Codec/Decoder/Video",
+      "Decode VP8 video streams", "David Schleef <ds@entropywave.com>, "
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  vpx_class->video_codec_tag = VP8_DECODER_VIDEO_TAG;
+  vpx_class->codec_algo = &vpx_codec_vp8_dx_algo;
+  vpx_class->set_default_format =
+      GST_DEBUG_FUNCPTR (gst_vp8_dec_set_default_format);
+  vpx_class->handle_resolution_change =
+      GST_DEBUG_FUNCPTR (gst_vp8_dec_handle_resolution_change);
+
+  GST_DEBUG_CATEGORY_INIT (gst_vp8dec_debug, "vp8dec", 0, "VP8 Decoder");
+}
+
+static void
+gst_vp8_dec_init (GstVP8Dec * gst_vp8_dec)
+{
+  GST_DEBUG_OBJECT (gst_vp8_dec, "gst_vp8_dec_init");
+}
+
+static void
+gst_vp8_dec_set_default_format (GstVPXDec * dec, GstVideoFormat fmt, int width,
+    int height)
+{
+  GstVPXDecClass *vpxclass = GST_VPX_DEC_GET_CLASS (dec);
+  g_assert (dec->output_state == NULL);
+  dec->output_state =
+      gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec),
+      GST_VIDEO_FORMAT_I420, width, height, dec->input_state);
+  gst_video_decoder_negotiate (GST_VIDEO_DECODER (dec));
+  vpxclass->send_tags (dec);
+}
+
+static void
+gst_vp8_dec_handle_resolution_change (GstVPXDec * dec, vpx_image_t * img,
+    GstVideoFormat fmt)
+{
+  GstVideoInfo *info;
+  GstVideoCodecState *new_output_state;
+
+  info = &dec->output_state->info;
+  if (GST_VIDEO_INFO_WIDTH (info) != img->d_w
+      || GST_VIDEO_INFO_HEIGHT (info) != img->d_h) {
+    GST_DEBUG_OBJECT (dec,
+        "Changed output resolution was %d x %d now is got %u x %u (display %u x %u)",
+        GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), img->w,
+        img->h, img->d_w, img->d_h);
+
+    new_output_state =
+        gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec),
+        GST_VIDEO_FORMAT_I420, img->d_w, img->d_h, dec->output_state);
+    if (dec->output_state) {
+      gst_video_codec_state_unref (dec->output_state);
+    }
+    dec->output_state = new_output_state;
+    /* No need to call negotiate() here, it will be automatically called
+     * by allocate_output_frame()*/
+  }
+}
+
+#endif /* HAVE_VP8_DECODER */
diff --git a/ext/vpx/gstvp8dec.h b/ext/vpx/gstvp8dec.h
new file mode 100644
index 0000000..fc3b161
--- /dev/null
+++ b/ext/vpx/gstvp8dec.h
@@ -0,0 +1,77 @@
+/* VP8
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ * Copyright (C) 2008,2009,2010 Entropy Wave Inc
+ * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __GST_VP8_DEC_H__
+#define __GST_VP8_DEC_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_VP8_DECODER
+
+#include <gst/gst.h>
+#include <gst/video/gstvideodecoder.h>
+#include <gstvpxdec.h>
+
+/* FIXME: Undef HAVE_CONFIG_H because vpx_codec.h uses it,
+ * which causes compilation failures */
+#ifdef HAVE_CONFIG_H
+#undef HAVE_CONFIG_H
+#endif
+
+#include <vpx/vpx_decoder.h>
+#include <vpx/vp8dx.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VP8_DEC \
+  (gst_vp8_dec_get_type())
+#define GST_VP8_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VP8_DEC,GstVP8Dec))
+#define GST_VP8_DEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VP8_DEC,GstVP8DecClass))
+#define GST_IS_VP8_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VP8_DEC))
+#define GST_IS_VP8_DEC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VP8_DEC))
+
+typedef struct _GstVP8Dec GstVP8Dec;
+typedef struct _GstVP8DecClass GstVP8DecClass;
+
+struct _GstVP8Dec
+{
+  GstVPXDec base_vpx_decoder;
+};
+
+struct _GstVP8DecClass
+{
+  GstVPXDecClass base_vpx_class;
+};
+
+GType gst_vp8_dec_get_type (void);
+
+G_END_DECLS
+
+#endif
+
+#endif /* __GST_VP8_DEC_H__ */
diff --git a/ext/vpx/gstvp8enc.c b/ext/vpx/gstvp8enc.c
new file mode 100644
index 0000000..819b388
--- /dev/null
+++ b/ext/vpx/gstvp8enc.c
@@ -0,0 +1,436 @@
+/* VP8
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ * Copyright (C) 2010 Entropy Wave Inc
+ * Copyright (C) 2010-2012 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+/**
+ * SECTION:element-vp8enc
+ * @see_also: vp8dec, webmmux, oggmux
+ *
+ * This element encodes raw video into a VP8 stream.
+ * <ulink url="http://www.webmproject.org">VP8</ulink> is a royalty-free
+ * video codec maintained by <ulink url="http://www.google.com/">Google
+ * </ulink>. It's the successor of On2 VP3, which was the base of the
+ * Theora video codec.
+ *
+ * To control the quality of the encoding, the #GstVP8Enc::target-bitrate,
+ * #GstVP8Enc::min-quantizer, #GstVP8Enc::max-quantizer or #GstVP8Enc::cq-level
+ * properties can be used. Which one is used depends on the mode selected by
+ * the #GstVP8Enc::end-usage property.
+ * See <ulink url="http://www.webmproject.org/docs/encoder-parameters/">Encoder Parameters</ulink>
+ * for explanation, examples for useful encoding parameters and more details
+ * on the encoding parameters.
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc num-buffers=1000 ! vp8enc ! webmmux ! filesink location=videotestsrc.webm
+ * ]| This example pipeline will encode a test video source to VP8 muxed in an
+ * WebM container.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_VP8_ENCODER
+
+/* glib decided in 2.32 it would be a great idea to deprecated GValueArray without
+ * providing an alternative
+ *
+ * See https://bugzilla.gnome.org/show_bug.cgi?id=667228
+ * */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <gst/tag/tag.h>
+#include <gst/video/video.h>
+#include <string.h>
+
+#include "gstvp8utils.h"
+#include "gstvp8enc.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_vp8enc_debug);
+#define GST_CAT_DEFAULT gst_vp8enc_debug
+
+typedef struct
+{
+  vpx_image_t *image;
+  GList *invisible;
+} GstVP8EncUserData;
+
+static void
+_gst_mini_object_unref0 (GstMiniObject * obj)
+{
+  if (obj)
+    gst_mini_object_unref (obj);
+}
+
+static void
+gst_vp8_enc_user_data_free (GstVP8EncUserData * user_data)
+{
+  if (user_data->image)
+    g_slice_free (vpx_image_t, user_data->image);
+
+  g_list_foreach (user_data->invisible, (GFunc) _gst_mini_object_unref0, NULL);
+  g_list_free (user_data->invisible);
+  g_slice_free (GstVP8EncUserData, user_data);
+}
+
+static vpx_codec_iface_t *gst_vp8_enc_get_algo (GstVPXEnc * enc);
+static gboolean gst_vp8_enc_enable_scaling (GstVPXEnc * enc);
+static void gst_vp8_enc_set_image_format (GstVPXEnc * enc, vpx_image_t * image);
+static GstCaps *gst_vp8_enc_get_new_simple_caps (GstVPXEnc * enc);
+static void gst_vp8_enc_set_stream_info (GstVPXEnc * enc, GstCaps * caps,
+    GstVideoInfo * info);
+static void *gst_vp8_enc_process_frame_user_data (GstVPXEnc * enc,
+    GstVideoCodecFrame * frame);
+static GstFlowReturn gst_vp8_enc_handle_invisible_frame_buffer (GstVPXEnc * enc,
+    void *user_data, GstBuffer * buffer);
+static void gst_vp8_enc_set_frame_user_data (GstVPXEnc * enc,
+    GstVideoCodecFrame * frame, vpx_image_t * image);
+
+static GstFlowReturn gst_vp8_enc_pre_push (GstVideoEncoder * encoder,
+    GstVideoCodecFrame * frame);
+
+static GstStaticPadTemplate gst_vp8_enc_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-raw, "
+        "format = (string) \"I420\", "
+        "width = (int) [1, 16383], "
+        "height = (int) [1, 16383], framerate = (fraction) [ 0/1, MAX ]")
+    );
+
+static GstStaticPadTemplate gst_vp8_enc_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-vp8, " "profile = (string) {0, 1, 2, 3}")
+    );
+
+#define parent_class gst_vp8_enc_parent_class
+G_DEFINE_TYPE (GstVP8Enc, gst_vp8_enc, GST_TYPE_VPX_ENC);
+
+static void
+gst_vp8_enc_class_init (GstVP8EncClass * klass)
+{
+  GstElementClass *element_class;
+  GstVideoEncoderClass *video_encoder_class;
+  GstVPXEncClass *vpx_encoder_class;
+
+  element_class = GST_ELEMENT_CLASS (klass);
+  video_encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
+  vpx_encoder_class = GST_VPX_ENC_CLASS (klass);
+
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_vp8_enc_src_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_vp8_enc_sink_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "On2 VP8 Encoder",
+      "Codec/Encoder/Video",
+      "Encode VP8 video streams", "David Schleef <ds@entropywave.com>, "
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  video_encoder_class->pre_push = gst_vp8_enc_pre_push;
+
+  vpx_encoder_class->get_algo = gst_vp8_enc_get_algo;
+  vpx_encoder_class->enable_scaling = gst_vp8_enc_enable_scaling;
+  vpx_encoder_class->set_image_format = gst_vp8_enc_set_image_format;
+  vpx_encoder_class->get_new_vpx_caps = gst_vp8_enc_get_new_simple_caps;
+  vpx_encoder_class->set_stream_info = gst_vp8_enc_set_stream_info;
+  vpx_encoder_class->process_frame_user_data =
+      gst_vp8_enc_process_frame_user_data;
+  vpx_encoder_class->handle_invisible_frame_buffer =
+      gst_vp8_enc_handle_invisible_frame_buffer;
+  vpx_encoder_class->set_frame_user_data = gst_vp8_enc_set_frame_user_data;
+
+  GST_DEBUG_CATEGORY_INIT (gst_vp8enc_debug, "vp8enc", 0, "VP8 Encoder");
+}
+
+static void
+gst_vp8_enc_init (GstVP8Enc * gst_vp8_enc)
+{
+  vpx_codec_err_t status;
+  GstVPXEnc *gst_vpx_enc = GST_VPX_ENC (gst_vp8_enc);
+  GST_DEBUG_OBJECT (gst_vp8_enc, "gst_vp8_enc_init");
+  status =
+      vpx_codec_enc_config_default (gst_vp8_enc_get_algo (gst_vpx_enc),
+      &gst_vpx_enc->cfg, 0);
+  if (status != VPX_CODEC_OK) {
+    GST_ERROR_OBJECT (gst_vpx_enc,
+        "Failed to get default encoder configuration: %s",
+        gst_vpx_error_name (status));
+    gst_vpx_enc->have_default_config = FALSE;
+  } else {
+    gst_vpx_enc->have_default_config = TRUE;
+  }
+}
+
+static vpx_codec_iface_t *
+gst_vp8_enc_get_algo (GstVPXEnc * enc)
+{
+  return &vpx_codec_vp8_cx_algo;
+}
+
+static gboolean
+gst_vp8_enc_enable_scaling (GstVPXEnc * enc)
+{
+  return TRUE;
+}
+
+static void
+gst_vp8_enc_set_image_format (GstVPXEnc * enc, vpx_image_t * image)
+{
+  image->fmt = VPX_IMG_FMT_I420;
+  image->bps = 12;
+  image->x_chroma_shift = image->y_chroma_shift = 1;
+}
+
+static GstCaps *
+gst_vp8_enc_get_new_simple_caps (GstVPXEnc * enc)
+{
+  GstCaps *caps;
+  gchar *profile_str = g_strdup_printf ("%d", enc->cfg.g_profile);
+  caps = gst_caps_new_simple ("video/x-vp8",
+      "profile", G_TYPE_STRING, profile_str, NULL);
+  g_free (profile_str);
+  return caps;
+}
+
+static void
+gst_vp8_enc_set_stream_info (GstVPXEnc * enc, GstCaps * caps,
+    GstVideoInfo * info)
+{
+  GstStructure *s;
+  GstVideoEncoder *video_encoder;
+  GstBuffer *stream_hdr, *vorbiscomment;
+  const GstTagList *iface_tags;
+  GValue array = { 0, };
+  GValue value = { 0, };
+  guint8 *data = NULL;
+  GstMapInfo map;
+
+  video_encoder = GST_VIDEO_ENCODER (enc);
+  s = gst_caps_get_structure (caps, 0);
+
+  /* put buffers in a fixed list */
+  g_value_init (&array, GST_TYPE_ARRAY);
+  g_value_init (&value, GST_TYPE_BUFFER);
+
+  /* Create Ogg stream-info */
+  stream_hdr = gst_buffer_new_and_alloc (26);
+  gst_buffer_map (stream_hdr, &map, GST_MAP_WRITE);
+  data = map.data;
+
+  GST_WRITE_UINT8 (data, 0x4F);
+  GST_WRITE_UINT32_BE (data + 1, 0x56503830);   /* "VP80" */
+  GST_WRITE_UINT8 (data + 5, 0x01);     /* stream info header */
+  GST_WRITE_UINT8 (data + 6, 1);        /* Major version 1 */
+  GST_WRITE_UINT8 (data + 7, 0);        /* Minor version 0 */
+  GST_WRITE_UINT16_BE (data + 8, GST_VIDEO_INFO_WIDTH (info));
+  GST_WRITE_UINT16_BE (data + 10, GST_VIDEO_INFO_HEIGHT (info));
+  GST_WRITE_UINT24_BE (data + 12, GST_VIDEO_INFO_PAR_N (info));
+  GST_WRITE_UINT24_BE (data + 15, GST_VIDEO_INFO_PAR_D (info));
+  GST_WRITE_UINT32_BE (data + 18, GST_VIDEO_INFO_FPS_N (info));
+  GST_WRITE_UINT32_BE (data + 22, GST_VIDEO_INFO_FPS_D (info));
+
+  gst_buffer_unmap (stream_hdr, &map);
+
+  GST_BUFFER_FLAG_SET (stream_hdr, GST_BUFFER_FLAG_HEADER);
+  gst_value_set_buffer (&value, stream_hdr);
+  gst_value_array_append_value (&array, &value);
+  g_value_unset (&value);
+  gst_buffer_unref (stream_hdr);
+
+  iface_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (video_encoder));
+  if (iface_tags) {
+    vorbiscomment =
+        gst_tag_list_to_vorbiscomment_buffer (iface_tags,
+        (const guint8 *) "OVP80\2 ", 7,
+        "Encoded with GStreamer vp8enc " PACKAGE_VERSION);
+
+    GST_BUFFER_FLAG_SET (vorbiscomment, GST_BUFFER_FLAG_HEADER);
+
+    g_value_init (&value, GST_TYPE_BUFFER);
+    gst_value_set_buffer (&value, vorbiscomment);
+    gst_value_array_append_value (&array, &value);
+    g_value_unset (&value);
+    gst_buffer_unref (vorbiscomment);
+  }
+
+  gst_structure_set_value (s, "streamheader", &array);
+  g_value_unset (&array);
+
+}
+
+static void *
+gst_vp8_enc_process_frame_user_data (GstVPXEnc * enc,
+    GstVideoCodecFrame * frame)
+{
+  GstVP8EncUserData *user_data;
+
+  user_data = gst_video_codec_frame_get_user_data (frame);
+
+  if (!user_data) {
+    GST_ERROR_OBJECT (enc, "Have no frame user data");
+    return NULL;
+  }
+
+  if (user_data->image)
+    g_slice_free (vpx_image_t, user_data->image);
+  user_data->image = NULL;
+  return user_data;
+}
+
+static GstFlowReturn
+gst_vp8_enc_handle_invisible_frame_buffer (GstVPXEnc * enc, void *user_data,
+    GstBuffer * buffer)
+{
+  GstVP8EncUserData *vp8_user_data = (GstVP8EncUserData *) user_data;
+
+  if (!vp8_user_data) {
+    GST_ERROR_OBJECT (enc, "Have no frame user data");
+    return GST_FLOW_ERROR;
+  }
+
+  vp8_user_data->invisible = g_list_append (vp8_user_data->invisible, buffer);
+
+  return GST_FLOW_OK;
+}
+
+static void
+gst_vp8_enc_set_frame_user_data (GstVPXEnc * enc, GstVideoCodecFrame * frame,
+    vpx_image_t * image)
+{
+  GstVP8EncUserData *user_data;
+  user_data = g_slice_new0 (GstVP8EncUserData);
+  user_data->image = image;
+  gst_video_codec_frame_set_user_data (frame, user_data,
+      (GDestroyNotify) gst_vp8_enc_user_data_free);
+  return;
+}
+
+static guint64
+_to_granulepos (guint64 frame_end_number, guint inv_count, guint keyframe_dist)
+{
+  guint64 granulepos;
+  guint inv;
+
+  inv = (inv_count == 0) ? 0x3 : inv_count - 1;
+
+  granulepos = (frame_end_number << 32) | (inv << 30) | (keyframe_dist << 3);
+  return granulepos;
+}
+
+static GstFlowReturn
+gst_vp8_enc_pre_push (GstVideoEncoder * video_encoder,
+    GstVideoCodecFrame * frame)
+{
+  GstVP8Enc *encoder;
+  GstVPXEnc *vpx_enc;
+  GstBuffer *buf;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstVP8EncUserData *user_data = gst_video_codec_frame_get_user_data (frame);
+  GList *l;
+  gint inv_count;
+  GstVideoInfo *info;
+
+  GST_DEBUG_OBJECT (video_encoder, "pre_push");
+
+  encoder = GST_VP8_ENC (video_encoder);
+  vpx_enc = GST_VPX_ENC (encoder);
+
+  info = &vpx_enc->input_state->info;
+
+  g_assert (user_data != NULL);
+
+  for (inv_count = 0, l = user_data->invisible; l; inv_count++, l = l->next) {
+    buf = l->data;
+    l->data = NULL;
+
+    /* FIXME : All of this should have already been handled by base classes, no ? */
+    if (l == user_data->invisible
+        && GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) {
+      GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
+      encoder->keyframe_distance = 0;
+    } else {
+      GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
+      encoder->keyframe_distance++;
+    }
+
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DECODE_ONLY);
+    GST_BUFFER_TIMESTAMP (buf) = GST_BUFFER_TIMESTAMP (frame->output_buffer);
+    GST_BUFFER_DURATION (buf) = 0;
+    if (GST_VIDEO_INFO_FPS_D (info) == 0 || GST_VIDEO_INFO_FPS_N (info) == 0) {
+      GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
+      GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
+    } else {
+      GST_BUFFER_OFFSET_END (buf) =
+          _to_granulepos (frame->presentation_frame_number + 1,
+          inv_count, encoder->keyframe_distance);
+      GST_BUFFER_OFFSET (buf) =
+          gst_util_uint64_scale (frame->presentation_frame_number + 1,
+          GST_SECOND * GST_VIDEO_INFO_FPS_D (info),
+          GST_VIDEO_INFO_FPS_N (info));
+    }
+
+    ret = gst_pad_push (GST_VIDEO_ENCODER_SRC_PAD (video_encoder), buf);
+
+    if (ret != GST_FLOW_OK) {
+      GST_WARNING_OBJECT (encoder, "flow error %d", ret);
+      goto done;
+    }
+  }
+
+  buf = frame->output_buffer;
+
+  /* FIXME : All of this should have already been handled by base classes, no ? */
+  if (!user_data->invisible && GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) {
+    GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
+    encoder->keyframe_distance = 0;
+  } else {
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
+    encoder->keyframe_distance++;
+  }
+
+  if (GST_VIDEO_INFO_FPS_D (info) == 0 || GST_VIDEO_INFO_FPS_N (info) == 0) {
+    GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
+    GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
+  } else {
+    GST_BUFFER_OFFSET_END (buf) =
+        _to_granulepos (frame->presentation_frame_number + 1, 0,
+        encoder->keyframe_distance);
+    GST_BUFFER_OFFSET (buf) =
+        gst_util_uint64_scale (frame->presentation_frame_number + 1,
+        GST_SECOND * GST_VIDEO_INFO_FPS_D (info), GST_VIDEO_INFO_FPS_N (info));
+  }
+
+  GST_LOG_OBJECT (video_encoder, "src ts: %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+
+done:
+  return ret;
+}
+
+#endif /* HAVE_VP8_ENCODER */
diff --git a/ext/vpx/gstvp8enc.h b/ext/vpx/gstvp8enc.h
new file mode 100644
index 0000000..47319e2
--- /dev/null
+++ b/ext/vpx/gstvp8enc.h
@@ -0,0 +1,73 @@
+/* VP8
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ * Copyright (C) 2010 Entropy Wave Inc
+ * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+#ifndef __GST_VP8_ENC_H__
+#define __GST_VP8_ENC_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_VP8_ENCODER
+
+#include <gstvpxenc.h>
+
+/* FIXME: Undef HAVE_CONFIG_H because vpx_codec.h uses it,
+ * which causes compilation failures */
+#ifdef HAVE_CONFIG_H
+#undef HAVE_CONFIG_H
+#endif
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VP8_ENC \
+  (gst_vp8_enc_get_type())
+#define GST_VP8_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VP8_ENC,GstVP8Enc))
+#define GST_VP8_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VP8_ENC,GstVP8EncClass))
+#define GST_IS_VP8_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VP8_ENC))
+#define GST_IS_VP8_ENC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VP8_ENC))
+
+typedef struct _GstVP8Enc GstVP8Enc;
+typedef struct _GstVP8EncClass GstVP8EncClass;
+
+struct _GstVP8Enc
+{
+  GstVPXEnc base_vpx_encoder;
+
+  int keyframe_distance;
+};
+
+struct _GstVP8EncClass
+{
+  GstVPXEncClass  base_vpxenc_class;
+};
+
+GType gst_vp8_enc_get_type (void);
+
+G_END_DECLS
+
+#endif
+
+#endif /* __GST_VP8_ENC_H__ */
diff --git a/ext/vpx/gstvp8utils.c b/ext/vpx/gstvp8utils.c
new file mode 100644
index 0000000..1721945
--- /dev/null
+++ b/ext/vpx/gstvp8utils.c
@@ -0,0 +1,64 @@
+/* VP8
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ * Copyright (C) 2010 Entropy Wave Inc
+ * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+/* FIXME: Undef HAVE_CONFIG_H because vpx_codec.h uses it,
+ * which causes compilation failures */
+#ifdef HAVE_CONFIG_H
+#undef HAVE_CONFIG_H
+#endif
+
+#include <vpx/vpx_codec.h>
+
+#include "gstvp8utils.h"
+
+const char *
+gst_vpx_error_name (vpx_codec_err_t status)
+{
+  switch (status) {
+    case VPX_CODEC_OK:
+      return "OK";
+    case VPX_CODEC_ERROR:
+      return "error";
+    case VPX_CODEC_MEM_ERROR:
+      return "mem error";
+    case VPX_CODEC_ABI_MISMATCH:
+      return "abi mismatch";
+    case VPX_CODEC_INCAPABLE:
+      return "incapable";
+    case VPX_CODEC_UNSUP_BITSTREAM:
+      return "unsupported bitstream";
+    case VPX_CODEC_UNSUP_FEATURE:
+      return "unsupported feature";
+    case VPX_CODEC_CORRUPT_FRAME:
+      return "corrupt frame";
+    case VPX_CODEC_INVALID_PARAM:
+      return "invalid parameter";
+    default:
+      return "unknown";
+  }
+}
diff --git a/ext/vpx/gstvp8utils.h b/ext/vpx/gstvp8utils.h
new file mode 100644
index 0000000..ea45df1
--- /dev/null
+++ b/ext/vpx/gstvp8utils.h
@@ -0,0 +1,30 @@
+/* VP8
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ * Copyright (C) 2010 Entropy Wave Inc
+ * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <gst/gst.h>
+#include <vpx/vpx_codec.h>
+
+G_BEGIN_DECLS
+
+const char * gst_vpx_error_name (vpx_codec_err_t status);
+
+G_END_DECLS
diff --git a/ext/vpx/gstvp9dec.c b/ext/vpx/gstvp9dec.c
new file mode 100644
index 0000000..69bb0fb
--- /dev/null
+++ b/ext/vpx/gstvp9dec.c
@@ -0,0 +1,219 @@
+/* VP9
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ * Copyright (C) 2008,2009,2010 Entropy Wave Inc
+ * Copyright (C) 2010-2013 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+/**
+ * SECTION:element-vp9dec
+ * @see_also: vp9enc, matroskademux
+ *
+ * This element decodes VP9 streams into raw video.
+ * <ulink url="http://www.webmproject.org">VP9</ulink> is a royalty-free
+ * video codec maintained by <ulink url="http://www.google.com/">Google
+ * </ulink>. It's the successor of On2 VP3, which was the base of the
+ * Theora video codec.
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 -v filesrc location=videotestsrc.webm ! matroskademux ! vp9dec ! videoconvert ! videoscale ! autovideosink
+ * ]| This example pipeline will decode a WebM stream and decodes the VP9 video.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_VP9_DECODER
+
+#include <string.h>
+
+#include "gstvp8utils.h"
+#include "gstvp9dec.h"
+
+#include <gst/video/gstvideometa.h>
+#include <gst/video/gstvideopool.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_vp9dec_debug);
+#define GST_CAT_DEFAULT gst_vp9dec_debug
+
+#define VP9_DECODER_VIDEO_TAG "VP9 video"
+
+static void gst_vp9_dec_set_stream_info (GstVPXDec * dec,
+    vpx_codec_stream_info_t * stream_info);
+static gboolean gst_vp9_dec_get_valid_format (GstVPXDec * dec,
+    vpx_image_t * img, GstVideoFormat * fmt);
+static void gst_vp9_dec_handle_resolution_change (GstVPXDec * dec,
+    vpx_image_t * img, GstVideoFormat fmt);
+
+static GstStaticPadTemplate gst_vp9_dec_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-vp9")
+    );
+
+static GstStaticPadTemplate gst_vp9_dec_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ I420, YV12, Y42B, Y444 }"))
+    );
+
+#define parent_class gst_vp9_dec_parent_class
+G_DEFINE_TYPE (GstVP9Dec, gst_vp9_dec, GST_TYPE_VPX_DEC);
+
+static void
+gst_vp9_dec_class_init (GstVP9DecClass * klass)
+{
+  GstElementClass *element_class;
+  GstVPXDecClass *vpx_class;
+
+  element_class = GST_ELEMENT_CLASS (klass);
+  vpx_class = GST_VPX_DEC_CLASS (klass);
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_vp9_dec_src_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_vp9_dec_sink_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "On2 VP9 Decoder",
+      "Codec/Decoder/Video",
+      "Decode VP9 video streams", "David Schleef <ds@entropywave.com>, "
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  vpx_class->video_codec_tag = VP9_DECODER_VIDEO_TAG;
+  vpx_class->codec_algo = &vpx_codec_vp9_dx_algo;
+  vpx_class->set_stream_info = GST_DEBUG_FUNCPTR (gst_vp9_dec_set_stream_info);
+  vpx_class->get_frame_format =
+      GST_DEBUG_FUNCPTR (gst_vp9_dec_get_valid_format);
+  vpx_class->handle_resolution_change =
+      GST_DEBUG_FUNCPTR (gst_vp9_dec_handle_resolution_change);
+
+  GST_DEBUG_CATEGORY_INIT (gst_vp9dec_debug, "vp9dec", 0, "VP9 Decoder");
+}
+
+static void
+gst_vp9_dec_init (GstVP9Dec * gst_vp9_dec)
+{
+  GST_DEBUG_OBJECT (gst_vp9_dec, "gst_vp9_dec_init");
+}
+
+static void
+gst_vp9_dec_set_stream_info (GstVPXDec * dec,
+    vpx_codec_stream_info_t * stream_info)
+{
+  /* FIXME: peek_stream_info() does not return valid values, take input caps */
+  stream_info->w = dec->input_state->info.width;
+  stream_info->h = dec->input_state->info.height;
+  return;
+}
+
+static gboolean
+gst_vp9_dec_get_valid_format (GstVPXDec * dec, vpx_image_t * img,
+    GstVideoFormat * fmt)
+{
+  switch (img->fmt) {
+    case VPX_IMG_FMT_I420:
+      *fmt = GST_VIDEO_FORMAT_I420;
+      return TRUE;
+
+    case VPX_IMG_FMT_YV12:
+      *fmt = GST_VIDEO_FORMAT_YV12;
+      return TRUE;
+
+    case VPX_IMG_FMT_I422:
+      *fmt = GST_VIDEO_FORMAT_Y42B;
+      return TRUE;
+
+    case VPX_IMG_FMT_I444:
+      *fmt = GST_VIDEO_FORMAT_Y444;
+      return TRUE;
+#ifdef VPX_IMG_FMT_I440
+    case VPX_IMG_FMT_I440:
+      /* Planar, half height, full width U/V */
+      GST_FIXME_OBJECT (dec, "Please add a 4:4:0 planar frame format");
+      GST_ELEMENT_WARNING (dec, STREAM, NOT_IMPLEMENTED,
+          (NULL), ("Unsupported frame format - 4:4:0 planar"));
+      return FALSE;
+#endif
+#ifdef VPX_IMG_FMT_I42016
+    case VPX_IMG_FMT_I42016:
+      /* VPX_IMG_FMT_I420 | VPX_IMG_FMT_HIGHBITDEPTH */
+      GST_FIXME_OBJECT (dec, "Please add 16-bit I420 format");
+      GST_ELEMENT_WARNING (dec, STREAM, NOT_IMPLEMENTED,
+          (NULL), ("Unsupported frame format - 16-bit 4:2:0 planar"));
+      return FALSE;
+#endif
+#ifdef VPX_IMG_FMT_I42216
+    case VPX_IMG_FMT_I42216:
+      /* VPX_IMG_FMT_I422 | VPX_IMG_FMT_HIGHBITDEPTH */
+      GST_FIXME_OBJECT (dec, "Please add 16-bit Y42B format");
+      GST_ELEMENT_WARNING (dec, STREAM, NOT_IMPLEMENTED,
+          (NULL), ("Unsupported frame format - 16-bit 4:2:2 planar"));
+      return FALSE;
+#endif
+#ifdef VPX_IMG_FMT_I44416
+    case VPX_IMG_FMT_I44416:
+      /* VPX_IMG_FMT_I444 | VPX_IMG_FMT_HIGHBITDEPTH */
+      GST_FIXME_OBJECT (dec, "Please add 16-bit Y444 format");
+      GST_ELEMENT_WARNING (dec, STREAM, NOT_IMPLEMENTED,
+          (NULL), ("Unsupported frame format - 16-bit 4:4:4 planar"));
+      return FALSE;
+#endif
+#ifdef VPX_IMG_FMT_I44016
+    case VPX_IMG_FMT_I44016:
+      /* VPX_IMG_FMT_I440 | VPX_IMG_FMT_HIGHBITDEPTH */
+      GST_FIXME_OBJECT (dec, "Please add 16-bit 4:4:0 planar frame format");
+      GST_ELEMENT_WARNING (dec, STREAM, NOT_IMPLEMENTED,
+          (NULL), ("Unsupported frame format - 16-bit 4:4:0 planar"));
+      return FALSE;
+#endif
+    default:
+      return FALSE;
+  }
+}
+
+static void
+gst_vp9_dec_handle_resolution_change (GstVPXDec * dec, vpx_image_t * img,
+    GstVideoFormat fmt)
+{
+  GstVPXDecClass *vpxclass = GST_VPX_DEC_GET_CLASS (dec);
+
+  if (!dec->output_state || dec->output_state->info.finfo->format != fmt ||
+      dec->output_state->info.width != img->d_w ||
+      dec->output_state->info.height != img->d_h) {
+    gboolean send_tags = !dec->output_state;
+
+    if (dec->output_state)
+      gst_video_codec_state_unref (dec->output_state);
+
+    dec->output_state =
+        gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec),
+        fmt, img->d_w, img->d_h, dec->input_state);
+    gst_video_decoder_negotiate (GST_VIDEO_DECODER (dec));
+
+    if (send_tags)
+      vpxclass->send_tags (dec);
+  }
+}
+
+#endif /* HAVE_VP9_DECODER */
diff --git a/ext/vpx/gstvp9dec.h b/ext/vpx/gstvp9dec.h
new file mode 100644
index 0000000..41332f3
--- /dev/null
+++ b/ext/vpx/gstvp9dec.h
@@ -0,0 +1,77 @@
+/* VP9
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ * Copyright (C) 2008,2009,2010 Entropy Wave Inc
+ * Copyright (C) 2010-2013 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __GST_VP9_DEC_H__
+#define __GST_VP9_DEC_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_VP9_DECODER
+
+#include <gst/gst.h>
+#include <gst/video/gstvideodecoder.h>
+#include <gstvpxdec.h>
+
+/* FIXME: Undef HAVE_CONFIG_H because vpx_codec.h uses it,
+ * which causes compilation failures */
+#ifdef HAVE_CONFIG_H
+#undef HAVE_CONFIG_H
+#endif
+
+#include <vpx/vpx_decoder.h>
+#include <vpx/vp8dx.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VP9_DEC \
+  (gst_vp9_dec_get_type())
+#define GST_VP9_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VP9_DEC,GstVP9Dec))
+#define GST_VP9_DEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VP9_DEC,GstVP9DecClass))
+#define GST_IS_VP9_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VP9_DEC))
+#define GST_IS_VP9_DEC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VP9_DEC))
+
+typedef struct _GstVP9Dec GstVP9Dec;
+typedef struct _GstVP9DecClass GstVP9DecClass;
+
+struct _GstVP9Dec
+{
+  GstVPXDec base_vpx_decoder;
+};
+
+struct _GstVP9DecClass
+{
+  GstVPXDecClass base_vpx_class;
+};
+
+GType gst_vp9_dec_get_type (void);
+
+G_END_DECLS
+
+#endif
+
+#endif /* __GST_VP9_DEC_H__ */
diff --git a/ext/vpx/gstvp9enc.c b/ext/vpx/gstvp9enc.c
new file mode 100644
index 0000000..0d8f9a2
--- /dev/null
+++ b/ext/vpx/gstvp9enc.c
@@ -0,0 +1,252 @@
+/* VP9
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ * Copyright (C) 2010 Entropy Wave Inc
+ * Copyright (C) 2010-2013 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+/**
+ * SECTION:element-vp9enc
+ * @see_also: vp9dec, webmmux, oggmux
+ *
+ * This element encodes raw video into a VP9 stream.
+ * <ulink url="http://www.webmproject.org">VP9</ulink> is a royalty-free
+ * video codec maintained by <ulink url="http://www.google.com/">Google
+ * </ulink>. It's the successor of On2 VP3, which was the base of the
+ * Theora video codec.
+ *
+ * To control the quality of the encoding, the #GstVP9Enc::target-bitrate,
+ * #GstVP9Enc::min-quantizer, #GstVP9Enc::max-quantizer or #GstVP9Enc::cq-level
+ * properties can be used. Which one is used depends on the mode selected by
+ * the #GstVP9Enc::end-usage property.
+ * See <ulink url="http://www.webmproject.org/docs/encoder-parameters/">Encoder Parameters</ulink>
+ * for explanation, examples for useful encoding parameters and more details
+ * on the encoding parameters.
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc num-buffers=1000 ! vp9enc ! webmmux ! filesink location=videotestsrc.webm
+ * ]| This example pipeline will encode a test video source to VP9 muxed in an
+ * WebM container.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_VP9_ENCODER
+
+/* glib decided in 2.32 it would be a great idea to deprecated GValueArray without
+ * providing an alternative
+ *
+ * See https://bugzilla.gnome.org/show_bug.cgi?id=667228
+ * */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <gst/tag/tag.h>
+#include <gst/video/video.h>
+#include <string.h>
+
+#include "gstvp8utils.h"
+#include "gstvp9enc.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_vp9enc_debug);
+#define GST_CAT_DEFAULT gst_vp9enc_debug
+
+
+/* FIXME: Y42B and Y444 do not work yet it seems */
+static GstStaticPadTemplate gst_vp9_enc_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    /*GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ I420, YV12, Y42B, Y444 }")) */
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ I420, YV12 }"))
+    );
+
+static GstStaticPadTemplate gst_vp9_enc_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-vp9, " "profile = (string) {0, 1, 2, 3}")
+    );
+
+#define parent_class gst_vp9_enc_parent_class
+G_DEFINE_TYPE (GstVP9Enc, gst_vp9_enc, GST_TYPE_VPX_ENC);
+
+static vpx_codec_iface_t *gst_vp9_enc_get_algo (GstVPXEnc * enc);
+static gboolean gst_vp9_enc_enable_scaling (GstVPXEnc * enc);
+static void gst_vp9_enc_set_image_format (GstVPXEnc * enc, vpx_image_t * image);
+static GstCaps *gst_vp9_enc_get_new_simple_caps (GstVPXEnc * enc);
+static void gst_vp9_enc_set_stream_info (GstVPXEnc * enc, GstCaps * caps,
+    GstVideoInfo * info);
+static void *gst_vp9_enc_process_frame_user_data (GstVPXEnc * enc,
+    GstVideoCodecFrame * frame);
+static GstFlowReturn gst_vp9_enc_handle_invisible_frame_buffer (GstVPXEnc * enc,
+    void *user_data, GstBuffer * buffer);
+static void gst_vp9_enc_set_frame_user_data (GstVPXEnc * enc,
+    GstVideoCodecFrame * frame, vpx_image_t * image);
+
+static void
+gst_vp9_enc_class_init (GstVP9EncClass * klass)
+{
+  GstElementClass *element_class;
+  GstVPXEncClass *vpx_encoder_class;
+
+  element_class = GST_ELEMENT_CLASS (klass);
+  vpx_encoder_class = GST_VPX_ENC_CLASS (klass);
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_vp9_enc_src_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_vp9_enc_sink_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "On2 VP9 Encoder",
+      "Codec/Encoder/Video",
+      "Encode VP9 video streams", "David Schleef <ds@entropywave.com>, "
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  vpx_encoder_class->get_algo = gst_vp9_enc_get_algo;
+  vpx_encoder_class->enable_scaling = gst_vp9_enc_enable_scaling;
+  vpx_encoder_class->set_image_format = gst_vp9_enc_set_image_format;
+  vpx_encoder_class->get_new_vpx_caps = gst_vp9_enc_get_new_simple_caps;
+  vpx_encoder_class->set_stream_info = gst_vp9_enc_set_stream_info;
+  vpx_encoder_class->process_frame_user_data =
+      gst_vp9_enc_process_frame_user_data;
+  vpx_encoder_class->handle_invisible_frame_buffer =
+      gst_vp9_enc_handle_invisible_frame_buffer;
+  vpx_encoder_class->set_frame_user_data = gst_vp9_enc_set_frame_user_data;
+
+  GST_DEBUG_CATEGORY_INIT (gst_vp9enc_debug, "vp9enc", 0, "VP9 Encoder");
+}
+
+static void
+gst_vp9_enc_init (GstVP9Enc * gst_vp9_enc)
+{
+  vpx_codec_err_t status;
+  GstVPXEnc *gst_vpx_enc = GST_VPX_ENC (gst_vp9_enc);
+  GST_DEBUG_OBJECT (gst_vp9_enc, "gst_vp9_enc_init");
+  status =
+      vpx_codec_enc_config_default (gst_vp9_enc_get_algo (gst_vpx_enc),
+      &gst_vpx_enc->cfg, 0);
+  if (status != VPX_CODEC_OK) {
+    GST_ERROR_OBJECT (gst_vpx_enc,
+        "Failed to get default encoder configuration: %s",
+        gst_vpx_error_name (status));
+    gst_vpx_enc->have_default_config = FALSE;
+  } else {
+    gst_vpx_enc->have_default_config = TRUE;
+  }
+}
+
+static vpx_codec_iface_t *
+gst_vp9_enc_get_algo (GstVPXEnc * enc)
+{
+  return &vpx_codec_vp9_cx_algo;
+}
+
+static gboolean
+gst_vp9_enc_enable_scaling (GstVPXEnc * enc)
+{
+  return FALSE;
+}
+
+static void
+gst_vp9_enc_set_image_format (GstVPXEnc * enc, vpx_image_t * image)
+{
+  switch (enc->input_state->info.finfo->format) {
+    case GST_VIDEO_FORMAT_I420:
+      image->fmt = VPX_IMG_FMT_I420;
+      image->bps = 12;
+      image->x_chroma_shift = image->y_chroma_shift = 1;
+      break;
+    case GST_VIDEO_FORMAT_YV12:
+      image->fmt = VPX_IMG_FMT_YV12;
+      image->bps = 12;
+      image->x_chroma_shift = image->y_chroma_shift = 1;
+      break;
+    case GST_VIDEO_FORMAT_Y42B:
+      image->fmt = VPX_IMG_FMT_I422;
+      image->bps = 16;
+      image->x_chroma_shift = 1;
+      image->y_chroma_shift = 0;
+      break;
+    case GST_VIDEO_FORMAT_Y444:
+      image->fmt = VPX_IMG_FMT_I444;
+      image->bps = 24;
+      image->x_chroma_shift = image->y_chroma_shift = 0;
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+static GstCaps *
+gst_vp9_enc_get_new_simple_caps (GstVPXEnc * enc)
+{
+  GstCaps *caps;
+  gchar *profile_str = g_strdup_printf ("%d", enc->cfg.g_profile);
+  caps = gst_caps_new_simple ("video/x-vp9",
+      "profile", G_TYPE_STRING, profile_str, NULL);
+  g_free (profile_str);
+  return caps;
+}
+
+static void
+gst_vp9_enc_set_stream_info (GstVPXEnc * enc, GstCaps * caps,
+    GstVideoInfo * info)
+{
+  return;
+}
+
+static void *
+gst_vp9_enc_process_frame_user_data (GstVPXEnc * enc,
+    GstVideoCodecFrame * frame)
+{
+  return NULL;
+}
+
+static GstFlowReturn
+gst_vp9_enc_handle_invisible_frame_buffer (GstVPXEnc * enc, void *user_data,
+    GstBuffer * buffer)
+{
+  GstFlowReturn ret;
+  g_mutex_unlock (&enc->encoder_lock);
+  ret = gst_pad_push (GST_VIDEO_ENCODER_SRC_PAD (enc), buffer);
+  g_mutex_lock (&enc->encoder_lock);
+  return ret;
+}
+
+static void
+gst_vp9_enc_user_data_free (vpx_image_t * image)
+{
+  g_slice_free (vpx_image_t, image);
+}
+
+static void
+gst_vp9_enc_set_frame_user_data (GstVPXEnc * enc, GstVideoCodecFrame * frame,
+    vpx_image_t * image)
+{
+  gst_video_codec_frame_set_user_data (frame, image,
+      (GDestroyNotify) gst_vp9_enc_user_data_free);
+  return;
+}
+
+#endif /* HAVE_VP9_ENCODER */
diff --git a/ext/vpx/gstvp9enc.h b/ext/vpx/gstvp9enc.h
new file mode 100644
index 0000000..843372b
--- /dev/null
+++ b/ext/vpx/gstvp9enc.h
@@ -0,0 +1,71 @@
+/* VP9
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ * Copyright (C) 2010 Entropy Wave Inc
+ * Copyright (C) 2010-2013 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+#ifndef __GST_VP9_ENC_H__
+#define __GST_VP9_ENC_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_VP9_ENCODER
+
+#include <gstvpxenc.h>
+
+/* FIXME: Undef HAVE_CONFIG_H because vpx_codec.h uses it,
+ * which causes compilation failures */
+#ifdef HAVE_CONFIG_H
+#undef HAVE_CONFIG_H
+#endif
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VP9_ENC \
+  (gst_vp9_enc_get_type())
+#define GST_VP9_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VP9_ENC,GstVP9Enc))
+#define GST_VP9_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VP9_ENC,GstVP9EncClass))
+#define GST_IS_VP9_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VP9_ENC))
+#define GST_IS_VP9_ENC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VP9_ENC))
+
+typedef struct _GstVP9Enc GstVP9Enc;
+typedef struct _GstVP9EncClass GstVP9EncClass;
+
+struct _GstVP9Enc
+{
+	GstVPXEnc base_vpx_encoder;
+};
+
+struct _GstVP9EncClass
+{
+  GstVPXEncClass  base_vpxenc_class;
+};
+
+GType gst_vp9_enc_get_type (void);
+
+G_END_DECLS
+
+#endif
+
+#endif /* __GST_VP9_ENC_H__ */
diff --git a/ext/vpx/gstvpxdec.c b/ext/vpx/gstvpxdec.c
new file mode 100644
index 0000000..c3f0f62
--- /dev/null
+++ b/ext/vpx/gstvpxdec.c
@@ -0,0 +1,820 @@
+/* VPX
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ * Copyright (C) 2008,2009,2010 Entropy Wave Inc
+ * Copyright (C) 2010-2012 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(HAVE_VP8_DECODER) || defined(HAVE_VP9_DECODER)
+
+#include <string.h>
+
+#include "gstvpxdec.h"
+#include "gstvp8utils.h"
+
+#include <gst/video/gstvideometa.h>
+#include <gst/video/gstvideopool.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_vpxdec_debug);
+#define GST_CAT_DEFAULT gst_vpxdec_debug
+
+#define DEFAULT_POST_PROCESSING FALSE
+#define DEFAULT_POST_PROCESSING_FLAGS (VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE)
+#define DEFAULT_DEBLOCKING_LEVEL 4
+#define DEFAULT_NOISE_LEVEL 0
+#define DEFAULT_THREADS 0
+#define DEFAULT_VIDEO_CODEC_TAG NULL
+#define DEFAULT_CODEC_ALGO NULL
+
+enum
+{
+  PROP_0,
+  PROP_POST_PROCESSING,
+  PROP_POST_PROCESSING_FLAGS,
+  PROP_DEBLOCKING_LEVEL,
+  PROP_NOISE_LEVEL,
+  PROP_THREADS
+};
+
+#define C_FLAGS(v) ((guint) v)
+#define GST_VPX_DEC_TYPE_POST_PROCESSING_FLAGS (gst_vpx_dec_post_processing_flags_get_type())
+static GType
+gst_vpx_dec_post_processing_flags_get_type (void)
+{
+  static const GFlagsValue values[] = {
+    {C_FLAGS (VP8_DEBLOCK), "Deblock", "deblock"},
+    {C_FLAGS (VP8_DEMACROBLOCK), "Demacroblock", "demacroblock"},
+    {C_FLAGS (VP8_ADDNOISE), "Add noise", "addnoise"},
+    {C_FLAGS (VP8_DEBUG_TXT_FRAME_INFO),
+          "Print frame information",
+        "visualize-frame-info"},
+    {C_FLAGS (VP8_DEBUG_TXT_MBLK_MODES),
+          "Show macroblock mode selection overlaid on image",
+        "visualize-macroblock-modes"},
+    {C_FLAGS (VP8_DEBUG_TXT_DC_DIFF),
+          "Show dc diff for each macro block overlaid on image",
+        "visualize-dc-diff"},
+    {C_FLAGS (VP8_DEBUG_TXT_RATE_INFO),
+          "Print video rate info",
+        "visualize-rate-info"},
+    {C_FLAGS (VP8_MFQE), "Multi-frame quality enhancement", "mfqe"},
+    {0, NULL, NULL}
+  };
+  static volatile GType id = 0;
+
+  if (g_once_init_enter ((gsize *) & id)) {
+    GType _id;
+
+    _id = g_flags_register_static ("GstVPXDecPostProcessingFlags", values);
+
+    g_once_init_leave ((gsize *) & id, _id);
+  }
+
+  return id;
+}
+
+#undef C_FLAGS
+
+static void gst_vpx_dec_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_vpx_dec_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_vpx_dec_start (GstVideoDecoder * decoder);
+static gboolean gst_vpx_dec_stop (GstVideoDecoder * decoder);
+static gboolean gst_vpx_dec_set_format (GstVideoDecoder * decoder,
+    GstVideoCodecState * state);
+static gboolean gst_vpx_dec_flush (GstVideoDecoder * decoder);
+static GstFlowReturn
+gst_vpx_dec_handle_frame (GstVideoDecoder * decoder,
+    GstVideoCodecFrame * frame);
+static gboolean gst_vpx_dec_decide_allocation (GstVideoDecoder * decoder,
+    GstQuery * query);
+
+static void gst_vpx_dec_image_to_buffer (GstVPXDec * dec,
+    const vpx_image_t * img, GstBuffer * buffer);
+static GstFlowReturn gst_vpx_dec_open_codec (GstVPXDec * dec,
+    GstVideoCodecFrame * frame);
+static void gst_vpx_dec_default_send_tags (GstVPXDec * dec);
+static void gst_vpx_dec_set_stream_info (GstVPXDec * dec,
+    vpx_codec_stream_info_t * stream_info);
+static void gst_vpx_dec_set_default_format (GstVPXDec * dec, GstVideoFormat fmt,
+    int width, int height);
+static gboolean gst_vpx_dec_default_frame_format (GstVPXDec * dec,
+    vpx_image_t * img, GstVideoFormat * fmt);
+static void gst_vpx_dec_handle_resolution_change (GstVPXDec * dec,
+    vpx_image_t * img, GstVideoFormat fmt);
+
+#define parent_class gst_vpx_dec_parent_class
+G_DEFINE_TYPE (GstVPXDec, gst_vpx_dec, GST_TYPE_VIDEO_DECODER);
+
+static void
+gst_vpx_dec_class_init (GstVPXDecClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstVideoDecoderClass *base_video_decoder_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  base_video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
+
+  gobject_class->set_property = gst_vpx_dec_set_property;
+  gobject_class->get_property = gst_vpx_dec_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_POST_PROCESSING,
+      g_param_spec_boolean ("post-processing", "Post Processing",
+          "Enable post processing", DEFAULT_POST_PROCESSING,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_POST_PROCESSING_FLAGS,
+      g_param_spec_flags ("post-processing-flags", "Post Processing Flags",
+          "Flags to control post processing",
+          GST_VPX_DEC_TYPE_POST_PROCESSING_FLAGS, DEFAULT_POST_PROCESSING_FLAGS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DEBLOCKING_LEVEL,
+      g_param_spec_uint ("deblocking-level", "Deblocking Level",
+          "Deblocking level",
+          0, 16, DEFAULT_DEBLOCKING_LEVEL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NOISE_LEVEL,
+      g_param_spec_uint ("noise-level", "Noise Level",
+          "Noise level",
+          0, 16, DEFAULT_NOISE_LEVEL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_THREADS,
+      g_param_spec_uint ("threads", "Max Threads",
+          "Maximum number of decoding threads",
+          0, 16, DEFAULT_THREADS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  base_video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_vpx_dec_start);
+  base_video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_vpx_dec_stop);
+  base_video_decoder_class->flush = GST_DEBUG_FUNCPTR (gst_vpx_dec_flush);
+  base_video_decoder_class->set_format =
+      GST_DEBUG_FUNCPTR (gst_vpx_dec_set_format);
+  base_video_decoder_class->handle_frame =
+      GST_DEBUG_FUNCPTR (gst_vpx_dec_handle_frame);;
+  base_video_decoder_class->decide_allocation =
+      GST_DEBUG_FUNCPTR (gst_vpx_dec_decide_allocation);
+
+  klass->video_codec_tag = DEFAULT_VIDEO_CODEC_TAG;
+  klass->codec_algo = DEFAULT_CODEC_ALGO;
+  klass->open_codec = GST_DEBUG_FUNCPTR (gst_vpx_dec_open_codec);
+  klass->send_tags = GST_DEBUG_FUNCPTR (gst_vpx_dec_default_send_tags);
+  klass->set_stream_info = NULL;
+  klass->set_default_format = NULL;
+  klass->handle_resolution_change = NULL;
+  klass->get_frame_format =
+      GST_DEBUG_FUNCPTR (gst_vpx_dec_default_frame_format);
+
+  GST_DEBUG_CATEGORY_INIT (gst_vpxdec_debug, "vpxdec", 0, "VPX Decoder");
+}
+
+static void
+gst_vpx_dec_init (GstVPXDec * gst_vpx_dec)
+{
+  GstVideoDecoder *decoder = (GstVideoDecoder *) gst_vpx_dec;
+
+  GST_DEBUG_OBJECT (gst_vpx_dec, "gst_vpx_dec_init");
+  gst_video_decoder_set_packetized (decoder, TRUE);
+  gst_vpx_dec->post_processing = DEFAULT_POST_PROCESSING;
+  gst_vpx_dec->post_processing_flags = DEFAULT_POST_PROCESSING_FLAGS;
+  gst_vpx_dec->deblocking_level = DEFAULT_DEBLOCKING_LEVEL;
+  gst_vpx_dec->noise_level = DEFAULT_NOISE_LEVEL;
+
+  gst_video_decoder_set_needs_format (decoder, TRUE);
+  gst_video_decoder_set_use_default_pad_acceptcaps (decoder, TRUE);
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_DECODER_SINK_PAD (decoder));
+}
+
+static void
+gst_vpx_dec_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVPXDec *dec;
+
+  g_return_if_fail (GST_IS_VPX_DEC (object));
+  dec = GST_VPX_DEC (object);
+
+  GST_DEBUG_OBJECT (object, "gst_vpx_dec_set_property");
+  switch (prop_id) {
+    case PROP_POST_PROCESSING:
+      dec->post_processing = g_value_get_boolean (value);
+      break;
+    case PROP_POST_PROCESSING_FLAGS:
+      dec->post_processing_flags = g_value_get_flags (value);
+      break;
+    case PROP_DEBLOCKING_LEVEL:
+      dec->deblocking_level = g_value_get_uint (value);
+      break;
+    case PROP_NOISE_LEVEL:
+      dec->noise_level = g_value_get_uint (value);
+      break;
+    case PROP_THREADS:
+      dec->threads = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_vpx_dec_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstVPXDec *dec;
+
+  g_return_if_fail (GST_IS_VPX_DEC (object));
+  dec = GST_VPX_DEC (object);
+
+  switch (prop_id) {
+    case PROP_POST_PROCESSING:
+      g_value_set_boolean (value, dec->post_processing);
+      break;
+    case PROP_POST_PROCESSING_FLAGS:
+      g_value_set_flags (value, dec->post_processing_flags);
+      break;
+    case PROP_DEBLOCKING_LEVEL:
+      g_value_set_uint (value, dec->deblocking_level);
+      break;
+    case PROP_NOISE_LEVEL:
+      g_value_set_uint (value, dec->noise_level);
+      break;
+    case PROP_THREADS:
+      g_value_set_uint (value, dec->threads);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_vpx_dec_start (GstVideoDecoder * decoder)
+{
+  GstVPXDec *gst_vpx_dec = GST_VPX_DEC (decoder);
+
+  GST_DEBUG_OBJECT (gst_vpx_dec, "start");
+  gst_vpx_dec->decoder_inited = FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+gst_vpx_dec_stop (GstVideoDecoder * base_video_decoder)
+{
+  GstVPXDec *gst_vpx_dec = GST_VPX_DEC (base_video_decoder);
+
+  GST_DEBUG_OBJECT (gst_vpx_dec, "stop");
+
+  if (gst_vpx_dec->output_state) {
+    gst_video_codec_state_unref (gst_vpx_dec->output_state);
+    gst_vpx_dec->output_state = NULL;
+  }
+
+  if (gst_vpx_dec->input_state) {
+    gst_video_codec_state_unref (gst_vpx_dec->input_state);
+    gst_vpx_dec->input_state = NULL;
+  }
+
+  if (gst_vpx_dec->decoder_inited)
+    vpx_codec_destroy (&gst_vpx_dec->decoder);
+  gst_vpx_dec->decoder_inited = FALSE;
+
+  if (gst_vpx_dec->pool) {
+    gst_buffer_pool_set_active (gst_vpx_dec->pool, FALSE);
+    gst_object_unref (gst_vpx_dec->pool);
+    gst_vpx_dec->pool = NULL;
+    gst_vpx_dec->buf_size = 0;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_vpx_dec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
+{
+  GstVPXDec *gst_vpx_dec = GST_VPX_DEC (decoder);
+
+  GST_DEBUG_OBJECT (gst_vpx_dec, "set_format");
+
+  if (gst_vpx_dec->decoder_inited)
+    vpx_codec_destroy (&gst_vpx_dec->decoder);
+  gst_vpx_dec->decoder_inited = FALSE;
+
+  if (gst_vpx_dec->output_state) {
+    gst_video_codec_state_unref (gst_vpx_dec->output_state);
+    gst_vpx_dec->output_state = NULL;
+  }
+
+  if (gst_vpx_dec->input_state) {
+    gst_video_codec_state_unref (gst_vpx_dec->input_state);
+  }
+
+  gst_vpx_dec->input_state = gst_video_codec_state_ref (state);
+
+  return TRUE;
+}
+
+static gboolean
+gst_vpx_dec_flush (GstVideoDecoder * base_video_decoder)
+{
+  GstVPXDec *decoder;
+
+  GST_DEBUG_OBJECT (base_video_decoder, "flush");
+
+  decoder = GST_VPX_DEC (base_video_decoder);
+
+  if (decoder->output_state) {
+    gst_video_codec_state_unref (decoder->output_state);
+    decoder->output_state = NULL;
+  }
+
+  if (decoder->decoder_inited)
+    vpx_codec_destroy (&decoder->decoder);
+  decoder->decoder_inited = FALSE;
+
+  return TRUE;
+}
+
+static void
+gst_vpx_dec_default_send_tags (GstVPXDec * dec)
+{
+  GstTagList *list;
+  GstVPXDecClass *vpxclass = GST_VPX_DEC_GET_CLASS (dec);
+
+  if (vpxclass->video_codec_tag == NULL)
+    return;
+
+  list = gst_tag_list_new_empty ();
+  gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+      GST_TAG_VIDEO_CODEC, vpxclass->video_codec_tag, NULL);
+
+  gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (dec),
+      gst_event_new_tag (list));
+}
+
+#ifdef HAVE_VPX_1_4
+struct Frame
+{
+  GstMapInfo info;
+  GstBuffer *buffer;
+};
+
+static GstBuffer *
+gst_vpx_dec_prepare_image (GstVPXDec * dec, const vpx_image_t * img)
+{
+  gint comp;
+  GstVideoMeta *vmeta;
+  GstBuffer *buffer;
+  struct Frame *frame = img->fb_priv;
+  GstVideoInfo *info = &dec->output_state->info;
+
+  buffer = gst_buffer_ref (frame->buffer);
+
+  vmeta = gst_buffer_get_video_meta (buffer);
+  vmeta->format = GST_VIDEO_INFO_FORMAT (info);
+  vmeta->width = GST_VIDEO_INFO_WIDTH (info);
+  vmeta->height = GST_VIDEO_INFO_HEIGHT (info);
+  vmeta->n_planes = GST_VIDEO_INFO_N_PLANES (info);
+
+  for (comp = 0; comp < 4; comp++) {
+    vmeta->stride[comp] = img->stride[comp];
+    vmeta->offset[comp] =
+        img->planes[comp] ? img->planes[comp] - frame->info.data : 0;
+  }
+
+  /* FIXME This is a READ/WRITE mapped buffer see bug #754826 */
+
+  return buffer;
+}
+
+static int
+gst_vpx_dec_get_buffer_cb (gpointer priv, gsize min_size,
+    vpx_codec_frame_buffer_t * fb)
+{
+  GstVPXDec *dec = priv;
+  GstBuffer *buffer = NULL;
+  struct Frame *frame;
+  GstFlowReturn ret;
+
+  if (!dec->pool || dec->buf_size != min_size) {
+    GstBufferPool *pool;
+    GstStructure *config;
+    GstCaps *caps;
+    GstAllocator *allocator;
+    GstAllocationParams params;
+
+    if (dec->pool) {
+      gst_buffer_pool_set_active (dec->pool, FALSE);
+      gst_object_unref (dec->pool);
+      dec->pool = NULL;
+      dec->buf_size = 0;
+    }
+
+    gst_video_decoder_get_allocator (GST_VIDEO_DECODER (dec), &allocator,
+        &params);
+
+    if (allocator &&
+        GST_OBJECT_FLAG_IS_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC)) {
+      gst_object_unref (allocator);
+      allocator = NULL;
+    }
+
+    pool = gst_buffer_pool_new ();
+    config = gst_buffer_pool_get_config (pool);
+    gst_buffer_pool_config_set_allocator (config, allocator, &params);
+    caps = gst_caps_from_string ("video/internal");
+    gst_buffer_pool_config_set_params (config, caps, min_size, 2, 0);
+    gst_caps_unref (caps);
+    gst_buffer_pool_set_config (pool, config);
+
+    if (allocator)
+      gst_object_unref (allocator);
+
+    if (!gst_buffer_pool_set_active (pool, TRUE)) {
+      GST_WARNING ("Failed to create internal pool");
+      gst_object_unref (pool);
+      return -1;
+    }
+
+    dec->pool = pool;
+    dec->buf_size = min_size;
+  }
+
+  ret = gst_buffer_pool_acquire_buffer (dec->pool, &buffer, NULL);
+  if (ret != GST_FLOW_OK) {
+    GST_WARNING ("Failed to acquire buffer from internal pool.");
+    return -1;
+  }
+
+  /* Add it now, while the buffer is writable */
+  gst_buffer_add_video_meta (buffer, GST_VIDEO_FRAME_FLAG_NONE,
+      GST_VIDEO_FORMAT_ENCODED, 0, 0);
+
+  frame = g_new0 (struct Frame, 1);
+  if (!gst_buffer_map (buffer, &frame->info, GST_MAP_READWRITE)) {
+    gst_buffer_unref (buffer);
+    g_free (frame);
+    GST_WARNING ("Failed to map buffer from internal pool.");
+    return -1;
+  }
+
+  fb->size = frame->info.size;
+  fb->data = frame->info.data;
+  frame->buffer = buffer;
+  fb->priv = frame;
+
+  GST_TRACE_OBJECT (priv, "Allocated buffer %p", frame->buffer);
+
+  return 0;
+}
+
+static int
+gst_vpx_dec_release_buffer_cb (gpointer priv, vpx_codec_frame_buffer_t * fb)
+{
+  struct Frame *frame = fb->priv;
+
+  /* We're sometimes called without a frame */
+  if (!frame)
+    return 0;
+
+  GST_TRACE_OBJECT (priv, "Release buffer %p", frame->buffer);
+
+  gst_buffer_unmap (frame->buffer, &frame->info);
+  gst_buffer_unref (frame->buffer);
+  g_free (frame);
+  fb->priv = NULL;
+
+  return 0;
+}
+#endif
+
+static void
+gst_vpx_dec_image_to_buffer (GstVPXDec * dec, const vpx_image_t * img,
+    GstBuffer * buffer)
+{
+  int deststride, srcstride, height, width, line, comp;
+  guint8 *dest, *src;
+  GstVideoFrame frame;
+  GstVideoInfo *info = &dec->output_state->info;
+
+  if (!gst_video_frame_map (&frame, info, buffer, GST_MAP_WRITE)) {
+    GST_ERROR_OBJECT (dec, "Could not map video buffer");
+    return;
+  }
+
+  for (comp = 0; comp < 3; comp++) {
+    dest = GST_VIDEO_FRAME_COMP_DATA (&frame, comp);
+    src = img->planes[comp];
+    width = GST_VIDEO_FRAME_COMP_WIDTH (&frame, comp)
+        * GST_VIDEO_FRAME_COMP_PSTRIDE (&frame, comp);
+    height = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, comp);
+    deststride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, comp);
+    srcstride = img->stride[comp];
+
+    if (srcstride == deststride) {
+      GST_TRACE_OBJECT (dec, "Stride matches. Comp %d: %d, copying full plane",
+          comp, srcstride);
+      memcpy (dest, src, srcstride * height);
+    } else {
+      GST_TRACE_OBJECT (dec, "Stride mismatch. Comp %d: %d != %d, copying "
+          "line by line.", comp, srcstride, deststride);
+      for (line = 0; line < height; line++) {
+        memcpy (dest, src, width);
+        dest += deststride;
+        src += srcstride;
+      }
+    }
+  }
+
+  gst_video_frame_unmap (&frame);
+}
+
+static GstFlowReturn
+gst_vpx_dec_open_codec (GstVPXDec * dec, GstVideoCodecFrame * frame)
+{
+  int flags = 0;
+  vpx_codec_stream_info_t stream_info;
+  vpx_codec_caps_t caps;
+  vpx_codec_dec_cfg_t cfg;
+  vpx_codec_err_t status;
+  GstMapInfo minfo;
+  GstVPXDecClass *vpxclass = GST_VPX_DEC_GET_CLASS (dec);
+
+  g_return_val_if_fail (vpxclass->codec_algo != NULL, GST_FLOW_ERROR);
+
+  memset (&stream_info, 0, sizeof (stream_info));
+  memset (&cfg, 0, sizeof (cfg));
+  stream_info.sz = sizeof (stream_info);
+
+  if (!gst_buffer_map (frame->input_buffer, &minfo, GST_MAP_READ)) {
+    GST_ERROR_OBJECT (dec, "Failed to map input buffer");
+    return GST_FLOW_ERROR;
+  }
+
+  status = vpx_codec_peek_stream_info (vpxclass->codec_algo,
+      minfo.data, minfo.size, &stream_info);
+
+  gst_buffer_unmap (frame->input_buffer, &minfo);
+
+  if (status != VPX_CODEC_OK) {
+    GST_WARNING_OBJECT (dec, "VPX preprocessing error: %s",
+        gst_vpx_error_name (status));
+    return GST_FLOW_CUSTOM_SUCCESS_1;
+  }
+  if (!stream_info.is_kf) {
+    GST_WARNING_OBJECT (dec, "No keyframe, skipping");
+    return GST_FLOW_CUSTOM_SUCCESS_1;
+  }
+
+  gst_vpx_dec_set_stream_info (dec, &stream_info);
+  gst_vpx_dec_set_default_format (dec, GST_VIDEO_FORMAT_I420, stream_info.w,
+      stream_info.h);
+
+  cfg.w = stream_info.w;
+  cfg.h = stream_info.h;
+
+  if (dec->threads > 0)
+    cfg.threads = dec->threads;
+  else
+    cfg.threads = g_get_num_processors ();
+
+  caps = vpx_codec_get_caps (vpxclass->codec_algo);
+
+  if (dec->post_processing) {
+    if (!(caps & VPX_CODEC_CAP_POSTPROC)) {
+      GST_WARNING_OBJECT (dec, "Decoder does not support post processing");
+    } else {
+      flags |= VPX_CODEC_USE_POSTPROC;
+    }
+  }
+
+  status =
+      vpx_codec_dec_init (&dec->decoder, vpxclass->codec_algo, &cfg, flags);
+  if (status != VPX_CODEC_OK) {
+    GST_ELEMENT_ERROR (dec, LIBRARY, INIT,
+        ("Failed to initialize VP8 decoder"), ("%s",
+            gst_vpx_error_name (status)));
+    return GST_FLOW_ERROR;
+  }
+
+  if ((caps & VPX_CODEC_CAP_POSTPROC) && dec->post_processing) {
+    vp8_postproc_cfg_t pp_cfg = { 0, };
+
+    pp_cfg.post_proc_flag = dec->post_processing_flags;
+    pp_cfg.deblocking_level = dec->deblocking_level;
+    pp_cfg.noise_level = dec->noise_level;
+
+    status = vpx_codec_control (&dec->decoder, VP8_SET_POSTPROC, &pp_cfg);
+    if (status != VPX_CODEC_OK) {
+      GST_WARNING_OBJECT (dec, "Couldn't set postprocessing settings: %s",
+          gst_vpx_error_name (status));
+    }
+  }
+#ifdef HAVE_VPX_1_4
+  vpx_codec_set_frame_buffer_functions (&dec->decoder,
+      gst_vpx_dec_get_buffer_cb, gst_vpx_dec_release_buffer_cb, dec);
+#endif
+
+  dec->decoder_inited = TRUE;
+
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_vpx_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
+{
+  GstVPXDec *dec;
+  GstFlowReturn ret = GST_FLOW_OK;
+  vpx_codec_err_t status;
+  vpx_codec_iter_t iter = NULL;
+  vpx_image_t *img;
+  long decoder_deadline = 0;
+  GstClockTimeDiff deadline;
+  GstMapInfo minfo;
+  GstVPXDecClass *vpxclass;
+  GstVideoFormat fmt;
+
+  GST_LOG_OBJECT (decoder, "handle_frame");
+
+  dec = GST_VPX_DEC (decoder);
+  vpxclass = GST_VPX_DEC_GET_CLASS (dec);
+
+  if (!dec->decoder_inited) {
+    ret = vpxclass->open_codec (dec, frame);
+    if (ret == GST_FLOW_CUSTOM_SUCCESS_1) {
+      gst_video_decoder_drop_frame (decoder, frame);
+      return GST_FLOW_OK;
+    } else if (ret != GST_FLOW_OK) {
+      gst_video_codec_frame_unref (frame);
+      return ret;
+    }
+  }
+
+  deadline = gst_video_decoder_get_max_decode_time (decoder, frame);
+  if (deadline < 0) {
+    decoder_deadline = 1;
+  } else if (deadline == G_MAXINT64) {
+    decoder_deadline = 0;
+  } else {
+    decoder_deadline = MAX (1, deadline / GST_MSECOND);
+  }
+
+  if (!gst_buffer_map (frame->input_buffer, &minfo, GST_MAP_READ)) {
+    GST_ERROR_OBJECT (dec, "Failed to map input buffer");
+    gst_video_codec_frame_unref (frame);
+    return GST_FLOW_ERROR;
+  }
+
+  status = vpx_codec_decode (&dec->decoder,
+      minfo.data, minfo.size, NULL, decoder_deadline);
+
+  gst_buffer_unmap (frame->input_buffer, &minfo);
+
+  if (status) {
+    GST_VIDEO_DECODER_ERROR (decoder, 1, LIBRARY, ENCODE,
+        ("Failed to decode frame"), ("%s", gst_vpx_error_name (status)), ret);
+    gst_video_codec_frame_unref (frame);
+    return ret;
+  }
+
+  img = vpx_codec_get_frame (&dec->decoder, &iter);
+  if (img) {
+    if (vpxclass->get_frame_format (dec, img, &fmt) == FALSE) {
+      vpx_img_free (img);
+      GST_ELEMENT_ERROR (decoder, LIBRARY, ENCODE,
+          ("Failed to decode frame"), ("Unsupported color format %d",
+              img->fmt));
+      gst_video_codec_frame_unref (frame);
+      return GST_FLOW_ERROR;
+    }
+
+    if (deadline < 0) {
+      GST_LOG_OBJECT (dec, "Skipping late frame (%f s past deadline)",
+          (double) -deadline / GST_SECOND);
+      gst_video_decoder_drop_frame (decoder, frame);
+    } else {
+      gst_vpx_dec_handle_resolution_change (dec, img, fmt);
+#ifdef HAVE_VPX_1_4
+      if (img->fb_priv && dec->have_video_meta) {
+        frame->output_buffer = gst_vpx_dec_prepare_image (dec, img);
+        ret = gst_video_decoder_finish_frame (decoder, frame);
+      } else
+#endif
+      {
+        ret = gst_video_decoder_allocate_output_frame (decoder, frame);
+
+        if (ret == GST_FLOW_OK) {
+          gst_vpx_dec_image_to_buffer (dec, img, frame->output_buffer);
+          ret = gst_video_decoder_finish_frame (decoder, frame);
+        } else {
+          gst_video_decoder_drop_frame (decoder, frame);
+        }
+      }
+    }
+
+    vpx_img_free (img);
+
+    while ((img = vpx_codec_get_frame (&dec->decoder, &iter))) {
+      GST_WARNING_OBJECT (decoder, "Multiple decoded frames... dropping");
+      vpx_img_free (img);
+    }
+  } else {
+    /* Invisible frame */
+    GST_VIDEO_CODEC_FRAME_SET_DECODE_ONLY (frame);
+    gst_video_decoder_finish_frame (decoder, frame);
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_vpx_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
+{
+  GstVPXDec *dec = GST_VPX_DEC (bdec);
+  GstBufferPool *pool;
+  GstStructure *config;
+
+  if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (bdec, query))
+    return FALSE;
+
+  g_assert (gst_query_get_n_allocation_pools (query) > 0);
+  gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
+  g_assert (pool != NULL);
+
+  config = gst_buffer_pool_get_config (pool);
+  if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
+    gst_buffer_pool_config_add_option (config,
+        GST_BUFFER_POOL_OPTION_VIDEO_META);
+    dec->have_video_meta = TRUE;
+  }
+  gst_buffer_pool_set_config (pool, config);
+  gst_object_unref (pool);
+
+  return TRUE;
+}
+
+static void
+gst_vpx_dec_set_stream_info (GstVPXDec * dec,
+    vpx_codec_stream_info_t * stream_info)
+{
+  GstVPXDecClass *vpxclass = GST_VPX_DEC_GET_CLASS (dec);
+  if (vpxclass->set_stream_info != NULL) {
+    vpxclass->set_stream_info (dec, stream_info);
+  }
+}
+
+static void
+gst_vpx_dec_set_default_format (GstVPXDec * dec, GstVideoFormat fmt, int width,
+    int height)
+{
+  GstVPXDecClass *vpxclass = GST_VPX_DEC_GET_CLASS (dec);
+  if (vpxclass->set_default_format != NULL) {
+    vpxclass->set_default_format (dec, fmt, width, height);
+  }
+}
+
+static gboolean
+gst_vpx_dec_default_frame_format (GstVPXDec * dec, vpx_image_t * img,
+    GstVideoFormat * fmt)
+{
+  if (img->fmt == VPX_IMG_FMT_I420) {
+    *fmt = GST_VIDEO_FORMAT_I420;
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+
+}
+
+static void
+gst_vpx_dec_handle_resolution_change (GstVPXDec * dec, vpx_image_t * img,
+    GstVideoFormat fmt)
+{
+  GstVPXDecClass *vpxclass = GST_VPX_DEC_GET_CLASS (dec);
+  if (vpxclass->handle_resolution_change != NULL) {
+    vpxclass->handle_resolution_change (dec, img, fmt);
+  }
+}
+
+#endif /* HAVE_VP8_DECODER ||  HAVE_VP9_DECODER */
diff --git a/ext/vpx/gstvpxdec.h b/ext/vpx/gstvpxdec.h
new file mode 100644
index 0000000..6852f86
--- /dev/null
+++ b/ext/vpx/gstvpxdec.h
@@ -0,0 +1,113 @@
+/* VPX
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ * Copyright (C) 2008,2009,2010 Entropy Wave Inc
+ * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __GST_VPX_DEC_H__
+#define __GST_VPX_DEC_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(HAVE_VP8_DECODER) || defined(HAVE_VP9_DECODER)
+
+#include <gst/gst.h>
+#include <gst/video/gstvideodecoder.h>
+
+/* FIXME: Undef HAVE_CONFIG_H because vpx_codec.h uses it,
+ * which causes compilation failures */
+#ifdef HAVE_CONFIG_H
+#undef HAVE_CONFIG_H
+#endif
+
+#include <vpx/vpx_decoder.h>
+#include <vpx/vp8dx.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VPX_DEC \
+  (gst_vpx_dec_get_type())
+#define GST_VPX_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VPX_DEC,GstVPXDec))
+#define GST_VPX_DEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VPX_DEC,GstVPXDecClass))
+#define GST_IS_VPX_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VPX_DEC))
+#define GST_IS_VPX_DEC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VPX_DEC))
+#define GST_VPX_DEC_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VPX_DEC, GstVPXDecClass))
+
+typedef struct _GstVPXDec GstVPXDec;
+typedef struct _GstVPXDecClass GstVPXDecClass;
+
+struct _GstVPXDec
+{
+  GstVideoDecoder base_video_decoder;
+
+  /* < private > */
+  vpx_codec_ctx_t decoder;
+
+  /* state */
+  gboolean decoder_inited;
+
+  /* properties */
+  gboolean post_processing;
+  enum vp8_postproc_level post_processing_flags;
+  gint deblocking_level;
+  gint noise_level;
+  gint threads;
+
+  GstVideoCodecState *input_state;
+  GstVideoCodecState *output_state;
+
+  /* allocation */
+  gboolean have_video_meta;
+  GstBufferPool *pool;
+  gsize buf_size;
+};
+
+struct _GstVPXDecClass
+{
+  GstVideoDecoderClass base_video_decoder_class;
+  const char* video_codec_tag;
+  /*supported vpx algo*/
+  vpx_codec_iface_t* codec_algo;
+  /*virtual function to open_codec*/
+  GstFlowReturn (*open_codec) (GstVPXDec * dec, GstVideoCodecFrame * frame);
+  /*virtual function to send tags*/
+  void (*send_tags) (GstVPXDec* dec);
+  /*virtual function to set/correct the stream info*/
+  void (*set_stream_info) (GstVPXDec *dec, vpx_codec_stream_info_t *stream_info);
+  /*virtual function to set default format while opening codec*/
+  void (*set_default_format) (GstVPXDec *dec, GstVideoFormat fmt, int width, int height);
+  /*virtual function to negotiate format while handling frame*/
+  void (*handle_resolution_change) (GstVPXDec *dec, vpx_image_t *img, GstVideoFormat fmt);
+  /*virtual function to check valid format*/
+  gboolean (*get_frame_format)(GstVPXDec *dec, vpx_image_t *img, GstVideoFormat* fmt);
+};
+
+GType gst_vpx_dec_get_type (void);
+
+G_END_DECLS
+
+#endif
+
+#endif /* __GST_VP8_DEC_H__ */
diff --git a/ext/vpx/gstvpxenc.c b/ext/vpx/gstvpxenc.c
new file mode 100644
index 0000000..1fa2ccc
--- /dev/null
+++ b/ext/vpx/gstvpxenc.c
@@ -0,0 +1,1968 @@
+/* VPX
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ * Copyright (C) 2010 Entropy Wave Inc
+ * Copyright (C) 2010-2012 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(HAVE_VP8_ENCODER) || defined(HAVE_VP9_ENCODER)
+
+/* glib decided in 2.32 it would be a great idea to deprecated GValueArray without
+ * providing an alternative
+ *
+ * See https://bugzilla.gnome.org/show_bug.cgi?id=667228
+ * */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <gst/tag/tag.h>
+#include <gst/video/video.h>
+#include <string.h>
+
+#include "gstvp8utils.h"
+#include "gstvpxenc.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_vpxenc_debug);
+#define GST_CAT_DEFAULT gst_vpxenc_debug
+
+/* From vp8/vp8_cx_iface.c and vp9/vp9_cx_iface.c */
+#define DEFAULT_PROFILE 0
+
+#define DEFAULT_RC_END_USAGE VPX_VBR
+#define DEFAULT_RC_TARGET_BITRATE 256000
+#define DEFAULT_RC_MIN_QUANTIZER 4
+#define DEFAULT_RC_MAX_QUANTIZER 63
+
+#define DEFAULT_RC_DROPFRAME_THRESH 0
+#define DEFAULT_RC_RESIZE_ALLOWED 0
+#define DEFAULT_RC_RESIZE_UP_THRESH 30
+#define DEFAULT_RC_RESIZE_DOWN_THRESH 60
+#define DEFAULT_RC_UNDERSHOOT_PCT 100
+#define DEFAULT_RC_OVERSHOOT_PCT 100
+#define DEFAULT_RC_BUF_SZ 6000
+#define DEFAULT_RC_BUF_INITIAL_SZ 4000
+#define DEFAULT_RC_BUF_OPTIMAL_SZ 5000
+#define DEFAULT_RC_2PASS_VBR_BIAS_PCT 50
+#define DEFAULT_RC_2PASS_VBR_MINSECTION_PCT 0
+#define DEFAULT_RC_2PASS_VBR_MAXSECTION_PCT 400
+
+#define DEFAULT_KF_MODE VPX_KF_AUTO
+#define DEFAULT_KF_MAX_DIST 128
+
+#define DEFAULT_MULTIPASS_MODE VPX_RC_ONE_PASS
+#define DEFAULT_MULTIPASS_CACHE_FILE "multipass.cache"
+
+#define DEFAULT_TS_NUMBER_LAYERS 1
+#define DEFAULT_TS_TARGET_BITRATE NULL
+#define DEFAULT_TS_RATE_DECIMATOR NULL
+#define DEFAULT_TS_PERIODICITY 0
+#define DEFAULT_TS_LAYER_ID NULL
+
+#define DEFAULT_ERROR_RESILIENT 0
+#define DEFAULT_LAG_IN_FRAMES 0
+
+#define DEFAULT_THREADS 0
+
+#define DEFAULT_H_SCALING_MODE VP8E_NORMAL
+#define DEFAULT_V_SCALING_MODE VP8E_NORMAL
+#define DEFAULT_CPU_USED 0
+#define DEFAULT_ENABLE_AUTO_ALT_REF FALSE
+#define DEFAULT_DEADLINE VPX_DL_BEST_QUALITY
+#define DEFAULT_NOISE_SENSITIVITY 0
+#define DEFAULT_SHARPNESS 0
+#define DEFAULT_STATIC_THRESHOLD 0
+#define DEFAULT_TOKEN_PARTITIONS 0
+#define DEFAULT_ARNR_MAXFRAMES 0
+#define DEFAULT_ARNR_STRENGTH 3
+#define DEFAULT_ARNR_TYPE 3
+#define DEFAULT_TUNING VP8_TUNE_PSNR
+#define DEFAULT_CQ_LEVEL 10
+#define DEFAULT_MAX_INTRA_BITRATE_PCT 0
+#define DEFAULT_TIMEBASE_N 0
+#define DEFAULT_TIMEBASE_D 1
+
+enum
+{
+  PROP_0,
+  PROP_RC_END_USAGE,
+  PROP_RC_TARGET_BITRATE,
+  PROP_RC_MIN_QUANTIZER,
+  PROP_RC_MAX_QUANTIZER,
+  PROP_RC_DROPFRAME_THRESH,
+  PROP_RC_RESIZE_ALLOWED,
+  PROP_RC_RESIZE_UP_THRESH,
+  PROP_RC_RESIZE_DOWN_THRESH,
+  PROP_RC_UNDERSHOOT_PCT,
+  PROP_RC_OVERSHOOT_PCT,
+  PROP_RC_BUF_SZ,
+  PROP_RC_BUF_INITIAL_SZ,
+  PROP_RC_BUF_OPTIMAL_SZ,
+  PROP_RC_2PASS_VBR_BIAS_PCT,
+  PROP_RC_2PASS_VBR_MINSECTION_PCT,
+  PROP_RC_2PASS_VBR_MAXSECTION_PCT,
+  PROP_KF_MODE,
+  PROP_KF_MAX_DIST,
+  PROP_TS_NUMBER_LAYERS,
+  PROP_TS_TARGET_BITRATE,
+  PROP_TS_RATE_DECIMATOR,
+  PROP_TS_PERIODICITY,
+  PROP_TS_LAYER_ID,
+  PROP_MULTIPASS_MODE,
+  PROP_MULTIPASS_CACHE_FILE,
+  PROP_ERROR_RESILIENT,
+  PROP_LAG_IN_FRAMES,
+  PROP_THREADS,
+  PROP_DEADLINE,
+  PROP_H_SCALING_MODE,
+  PROP_V_SCALING_MODE,
+  PROP_CPU_USED,
+  PROP_ENABLE_AUTO_ALT_REF,
+  PROP_NOISE_SENSITIVITY,
+  PROP_SHARPNESS,
+  PROP_STATIC_THRESHOLD,
+  PROP_TOKEN_PARTITIONS,
+  PROP_ARNR_MAXFRAMES,
+  PROP_ARNR_STRENGTH,
+  PROP_ARNR_TYPE,
+  PROP_TUNING,
+  PROP_CQ_LEVEL,
+  PROP_MAX_INTRA_BITRATE_PCT,
+  PROP_TIMEBASE
+};
+
+
+#define GST_VPX_ENC_END_USAGE_TYPE (gst_vpx_enc_end_usage_get_type())
+static GType
+gst_vpx_enc_end_usage_get_type (void)
+{
+  static const GEnumValue values[] = {
+    {VPX_VBR, "Variable Bit Rate (VBR) mode", "vbr"},
+    {VPX_CBR, "Constant Bit Rate (CBR) mode", "cbr"},
+    {VPX_CQ, "Constant Quality Mode (CQ) mode", "cq"},
+    {0, NULL, NULL}
+  };
+  static volatile GType id = 0;
+
+  if (g_once_init_enter ((gsize *) & id)) {
+    GType _id;
+
+    _id = g_enum_register_static ("GstVPXEncEndUsage", values);
+
+    g_once_init_leave ((gsize *) & id, _id);
+  }
+
+  return id;
+}
+
+#define GST_VPX_ENC_MULTIPASS_MODE_TYPE (gst_vpx_enc_multipass_mode_get_type())
+static GType
+gst_vpx_enc_multipass_mode_get_type (void)
+{
+  static const GEnumValue values[] = {
+    {VPX_RC_ONE_PASS, "One pass encoding (default)", "one-pass"},
+    {VPX_RC_FIRST_PASS, "First pass of multipass encoding", "first-pass"},
+    {VPX_RC_LAST_PASS, "Last pass of multipass encoding", "last-pass"},
+    {0, NULL, NULL}
+  };
+  static volatile GType id = 0;
+
+  if (g_once_init_enter ((gsize *) & id)) {
+    GType _id;
+
+    _id = g_enum_register_static ("GstVPXEncMultipassMode", values);
+
+    g_once_init_leave ((gsize *) & id, _id);
+  }
+
+  return id;
+}
+
+#define GST_VPX_ENC_KF_MODE_TYPE (gst_vpx_enc_kf_mode_get_type())
+static GType
+gst_vpx_enc_kf_mode_get_type (void)
+{
+  static const GEnumValue values[] = {
+    {VPX_KF_AUTO, "Determine optimal placement automatically", "auto"},
+    {VPX_KF_DISABLED, "Don't automatically place keyframes", "disabled"},
+    {0, NULL, NULL}
+  };
+  static volatile GType id = 0;
+
+  if (g_once_init_enter ((gsize *) & id)) {
+    GType _id;
+
+    _id = g_enum_register_static ("GstVPXEncKfMode", values);
+
+    g_once_init_leave ((gsize *) & id, _id);
+  }
+
+  return id;
+}
+
+#define GST_VPX_ENC_TUNING_TYPE (gst_vpx_enc_tuning_get_type())
+static GType
+gst_vpx_enc_tuning_get_type (void)
+{
+  static const GEnumValue values[] = {
+    {VP8_TUNE_PSNR, "Tune for PSNR", "psnr"},
+    {VP8_TUNE_SSIM, "Tune for SSIM", "ssim"},
+    {0, NULL, NULL}
+  };
+  static volatile GType id = 0;
+
+  if (g_once_init_enter ((gsize *) & id)) {
+    GType _id;
+
+    _id = g_enum_register_static ("GstVPXEncTuning", values);
+
+    g_once_init_leave ((gsize *) & id, _id);
+  }
+
+  return id;
+}
+
+#define GST_VPX_ENC_SCALING_MODE_TYPE (gst_vpx_enc_scaling_mode_get_type())
+static GType
+gst_vpx_enc_scaling_mode_get_type (void)
+{
+  static const GEnumValue values[] = {
+    {VP8E_NORMAL, "Normal", "normal"},
+    {VP8E_FOURFIVE, "4:5", "4:5"},
+    {VP8E_THREEFIVE, "3:5", "3:5"},
+    {VP8E_ONETWO, "1:2", "1:2"},
+    {0, NULL, NULL}
+  };
+  static volatile GType id = 0;
+
+  if (g_once_init_enter ((gsize *) & id)) {
+    GType _id;
+
+    _id = g_enum_register_static ("GstVPXEncScalingMode", values);
+
+    g_once_init_leave ((gsize *) & id, _id);
+  }
+
+  return id;
+}
+
+#define GST_VPX_ENC_TOKEN_PARTITIONS_TYPE (gst_vpx_enc_token_partitions_get_type())
+static GType
+gst_vpx_enc_token_partitions_get_type (void)
+{
+  static const GEnumValue values[] = {
+    {VP8_ONE_TOKENPARTITION, "One token partition", "1"},
+    {VP8_TWO_TOKENPARTITION, "Two token partitions", "2"},
+    {VP8_FOUR_TOKENPARTITION, "Four token partitions", "4"},
+    {VP8_EIGHT_TOKENPARTITION, "Eight token partitions", "8"},
+    {0, NULL, NULL}
+  };
+  static volatile GType id = 0;
+
+  if (g_once_init_enter ((gsize *) & id)) {
+    GType _id;
+
+    _id = g_enum_register_static ("GstVPXEncTokenPartitions", values);
+
+    g_once_init_leave ((gsize *) & id, _id);
+  }
+
+  return id;
+}
+
+#define GST_VPX_ENC_ER_FLAGS_TYPE (gst_vpx_enc_er_flags_get_type())
+static GType
+gst_vpx_enc_er_flags_get_type (void)
+{
+  static const GFlagsValue values[] = {
+    {VPX_ERROR_RESILIENT_DEFAULT, "Default error resilience", "default"},
+    {VPX_ERROR_RESILIENT_PARTITIONS,
+        "Allow partitions to be decoded independently", "partitions"},
+    {0, NULL, NULL}
+  };
+  static volatile GType id = 0;
+
+  if (g_once_init_enter ((gsize *) & id)) {
+    GType _id;
+
+    _id = g_flags_register_static ("GstVPXEncErFlags", values);
+
+    g_once_init_leave ((gsize *) & id, _id);
+  }
+
+  return id;
+}
+
+static void gst_vpx_enc_finalize (GObject * object);
+static void gst_vpx_enc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_vpx_enc_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_vpx_enc_start (GstVideoEncoder * encoder);
+static gboolean gst_vpx_enc_stop (GstVideoEncoder * encoder);
+static gboolean gst_vpx_enc_set_format (GstVideoEncoder *
+    video_encoder, GstVideoCodecState * state);
+static GstFlowReturn gst_vpx_enc_finish (GstVideoEncoder * video_encoder);
+static gboolean gst_vpx_enc_flush (GstVideoEncoder * video_encoder);
+static GstFlowReturn gst_vpx_enc_drain (GstVideoEncoder * video_encoder);
+static GstFlowReturn gst_vpx_enc_handle_frame (GstVideoEncoder *
+    video_encoder, GstVideoCodecFrame * frame);
+static gboolean gst_vpx_enc_sink_event (GstVideoEncoder *
+    video_encoder, GstEvent * event);
+static gboolean gst_vpx_enc_propose_allocation (GstVideoEncoder * encoder,
+    GstQuery * query);
+
+#define parent_class gst_vpx_enc_parent_class
+G_DEFINE_TYPE_WITH_CODE (GstVPXEnc, gst_vpx_enc, GST_TYPE_VIDEO_ENCODER,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
+    G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL););
+
+static void
+gst_vpx_enc_class_init (GstVPXEncClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstVideoEncoderClass *video_encoder_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  video_encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
+
+  gobject_class->set_property = gst_vpx_enc_set_property;
+  gobject_class->get_property = gst_vpx_enc_get_property;
+  gobject_class->finalize = gst_vpx_enc_finalize;
+
+  video_encoder_class->start = gst_vpx_enc_start;
+  video_encoder_class->stop = gst_vpx_enc_stop;
+  video_encoder_class->handle_frame = gst_vpx_enc_handle_frame;
+  video_encoder_class->set_format = gst_vpx_enc_set_format;
+  video_encoder_class->flush = gst_vpx_enc_flush;
+  video_encoder_class->finish = gst_vpx_enc_finish;
+  video_encoder_class->sink_event = gst_vpx_enc_sink_event;
+  video_encoder_class->propose_allocation = gst_vpx_enc_propose_allocation;
+
+  g_object_class_install_property (gobject_class, PROP_RC_END_USAGE,
+      g_param_spec_enum ("end-usage", "Rate control mode",
+          "Rate control mode",
+          GST_VPX_ENC_END_USAGE_TYPE, DEFAULT_RC_END_USAGE,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_RC_TARGET_BITRATE,
+      g_param_spec_int ("target-bitrate", "Target bitrate",
+          "Target bitrate (in bits/sec)",
+          0, G_MAXINT, DEFAULT_RC_TARGET_BITRATE,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_RC_MIN_QUANTIZER,
+      g_param_spec_int ("min-quantizer", "Minimum Quantizer",
+          "Minimum Quantizer (best)",
+          0, 63, DEFAULT_RC_MIN_QUANTIZER,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_RC_MAX_QUANTIZER,
+      g_param_spec_int ("max-quantizer", "Maximum Quantizer",
+          "Maximum Quantizer (worst)",
+          0, 63, DEFAULT_RC_MAX_QUANTIZER,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_RC_DROPFRAME_THRESH,
+      g_param_spec_int ("dropframe-threshold", "Drop Frame Threshold",
+          "Temporal resampling threshold (buf %)",
+          0, 100, DEFAULT_RC_DROPFRAME_THRESH,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_RC_RESIZE_ALLOWED,
+      g_param_spec_boolean ("resize-allowed", "Resize Allowed",
+          "Allow spatial resampling",
+          DEFAULT_RC_RESIZE_ALLOWED,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_RC_RESIZE_UP_THRESH,
+      g_param_spec_int ("resize-up-threshold", "Resize Up Threshold",
+          "Upscale threshold (buf %)",
+          0, 100, DEFAULT_RC_RESIZE_UP_THRESH,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_RC_RESIZE_DOWN_THRESH,
+      g_param_spec_int ("resize-down-threshold", "Resize Down Threshold",
+          "Downscale threshold (buf %)",
+          0, 100, DEFAULT_RC_RESIZE_DOWN_THRESH,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_RC_UNDERSHOOT_PCT,
+      g_param_spec_int ("undershoot", "Undershoot PCT",
+          "Datarate undershoot (min) target (%)",
+          0, 1000, DEFAULT_RC_UNDERSHOOT_PCT,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_RC_OVERSHOOT_PCT,
+      g_param_spec_int ("overshoot", "Overshoot PCT",
+          "Datarate overshoot (max) target (%)",
+          0, 1000, DEFAULT_RC_OVERSHOOT_PCT,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_RC_BUF_SZ,
+      g_param_spec_int ("buffer-size", "Buffer size",
+          "Client buffer size (ms)",
+          0, G_MAXINT, DEFAULT_RC_BUF_SZ,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_RC_BUF_INITIAL_SZ,
+      g_param_spec_int ("buffer-initial-size", "Buffer initial size",
+          "Initial client buffer size (ms)",
+          0, G_MAXINT, DEFAULT_RC_BUF_INITIAL_SZ,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_RC_BUF_OPTIMAL_SZ,
+      g_param_spec_int ("buffer-optimal-size", "Buffer optimal size",
+          "Optimal client buffer size (ms)",
+          0, G_MAXINT, DEFAULT_RC_BUF_OPTIMAL_SZ,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_RC_2PASS_VBR_BIAS_PCT,
+      g_param_spec_int ("twopass-vbr-bias", "2-pass VBR bias",
+          "CBR/VBR bias (0=CBR, 100=VBR)",
+          0, 100, DEFAULT_RC_2PASS_VBR_BIAS_PCT,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class,
+      PROP_RC_2PASS_VBR_MINSECTION_PCT,
+      g_param_spec_int ("twopass-vbr-minsection", "2-pass GOP min bitrate",
+          "GOP minimum bitrate (% target)", 0, G_MAXINT,
+          DEFAULT_RC_2PASS_VBR_MINSECTION_PCT,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class,
+      PROP_RC_2PASS_VBR_MAXSECTION_PCT,
+      g_param_spec_int ("twopass-vbr-maxsection", "2-pass GOP max bitrate",
+          "GOP maximum bitrate (% target)", 0, G_MAXINT,
+          DEFAULT_RC_2PASS_VBR_MINSECTION_PCT,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_KF_MODE,
+      g_param_spec_enum ("keyframe-mode", "Keyframe Mode",
+          "Keyframe placement",
+          GST_VPX_ENC_KF_MODE_TYPE, DEFAULT_KF_MODE,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_KF_MAX_DIST,
+      g_param_spec_int ("keyframe-max-dist", "Keyframe max distance",
+          "Maximum distance between keyframes (number of frames)",
+          0, G_MAXINT, DEFAULT_KF_MAX_DIST,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_MULTIPASS_MODE,
+      g_param_spec_enum ("multipass-mode", "Multipass Mode",
+          "Multipass encode mode",
+          GST_VPX_ENC_MULTIPASS_MODE_TYPE, DEFAULT_MULTIPASS_MODE,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_MULTIPASS_CACHE_FILE,
+      g_param_spec_string ("multipass-cache-file", "Multipass Cache File",
+          "Multipass cache file. "
+          "If stream caps reinited, multiple files will be created: "
+          "file, file.1, file.2, ... and so on.",
+          DEFAULT_MULTIPASS_CACHE_FILE,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_TS_NUMBER_LAYERS,
+      g_param_spec_int ("temporal-scalability-number-layers",
+          "Number of coding layers", "Number of coding layers to use", 1, 5,
+          DEFAULT_TS_NUMBER_LAYERS,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_TS_TARGET_BITRATE,
+      g_param_spec_value_array ("temporal-scalability-target-bitrate",
+          "Coding layer target bitrates",
+          "Target bitrates for coding layers (one per layer, decreasing)",
+          g_param_spec_int ("target-bitrate", "Target bitrate",
+              "Target bitrate", 0, G_MAXINT, DEFAULT_RC_TARGET_BITRATE,
+              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_TS_RATE_DECIMATOR,
+      g_param_spec_value_array ("temporal-scalability-rate-decimator",
+          "Coding layer rate decimator",
+          "Rate decimation factors for each layer",
+          g_param_spec_int ("rate-decimator", "Rate decimator",
+              "Rate decimator", 0, 1000000000, 0,
+              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_TS_PERIODICITY,
+      g_param_spec_int ("temporal-scalability-periodicity",
+          "Coding layer periodicity",
+          "Length of sequence that defines layer membership periodicity", 0, 16,
+          DEFAULT_TS_PERIODICITY,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_TS_LAYER_ID,
+      g_param_spec_value_array ("temporal-scalability-layer-id",
+          "Coding layer identification",
+          "Sequence defining coding layer membership",
+          g_param_spec_int ("layer-id", "Layer ID", "Layer ID", 0, 4, 0,
+              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_LAG_IN_FRAMES,
+      g_param_spec_int ("lag-in-frames", "Lag in frames",
+          "Maximum number of frames to lag",
+          0, 25, DEFAULT_LAG_IN_FRAMES,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_ERROR_RESILIENT,
+      g_param_spec_flags ("error-resilient", "Error resilient",
+          "Error resilience flags",
+          GST_VPX_ENC_ER_FLAGS_TYPE, DEFAULT_ERROR_RESILIENT,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_THREADS,
+      g_param_spec_int ("threads", "Threads",
+          "Number of threads to use",
+          0, 64, DEFAULT_THREADS,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_DEADLINE,
+      g_param_spec_int64 ("deadline", "Deadline",
+          "Deadline per frame (usec, 0=disabled)",
+          0, G_MAXINT64, DEFAULT_DEADLINE,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_H_SCALING_MODE,
+      g_param_spec_enum ("horizontal-scaling-mode", "Horizontal scaling mode",
+          "Horizontal scaling mode",
+          GST_VPX_ENC_SCALING_MODE_TYPE, DEFAULT_H_SCALING_MODE,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_V_SCALING_MODE,
+      g_param_spec_enum ("vertical-scaling-mode", "Vertical scaling mode",
+          "Vertical scaling mode",
+          GST_VPX_ENC_SCALING_MODE_TYPE, DEFAULT_V_SCALING_MODE,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_CPU_USED,
+      g_param_spec_int ("cpu-used", "CPU used",
+          "CPU used",
+          -16, 16, DEFAULT_CPU_USED,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_ENABLE_AUTO_ALT_REF,
+      g_param_spec_boolean ("auto-alt-ref", "Auto alt reference frames",
+          "Automatically generate AltRef frames",
+          DEFAULT_ENABLE_AUTO_ALT_REF,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_NOISE_SENSITIVITY,
+      g_param_spec_int ("noise-sensitivity", "Noise sensitivity",
+          "Noise sensisivity (frames to blur)",
+          0, 6, DEFAULT_NOISE_SENSITIVITY,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_SHARPNESS,
+      g_param_spec_int ("sharpness", "Sharpness",
+          "Filter sharpness",
+          0, 7, DEFAULT_SHARPNESS,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_STATIC_THRESHOLD,
+      g_param_spec_int ("static-threshold", "Static Threshold",
+          "Motion detection threshold",
+          0, G_MAXINT, DEFAULT_STATIC_THRESHOLD,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_TOKEN_PARTITIONS,
+      g_param_spec_enum ("token-partitions", "Token partitions",
+          "Number of token partitions",
+          GST_VPX_ENC_TOKEN_PARTITIONS_TYPE, DEFAULT_TOKEN_PARTITIONS,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_ARNR_MAXFRAMES,
+      g_param_spec_int ("arnr-maxframes", "AltRef max frames",
+          "AltRef maximum number of frames",
+          0, 15, DEFAULT_ARNR_MAXFRAMES,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_ARNR_STRENGTH,
+      g_param_spec_int ("arnr-strength", "AltRef strength",
+          "AltRef strength",
+          0, 6, DEFAULT_ARNR_STRENGTH,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_ARNR_TYPE,
+      g_param_spec_int ("arnr-type", "AltRef type",
+          "AltRef type",
+          1, 3, DEFAULT_ARNR_TYPE,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+              G_PARAM_DEPRECATED)));
+
+  g_object_class_install_property (gobject_class, PROP_TUNING,
+      g_param_spec_enum ("tuning", "Tuning",
+          "Tuning",
+          GST_VPX_ENC_TUNING_TYPE, DEFAULT_TUNING,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_CQ_LEVEL,
+      g_param_spec_int ("cq-level", "Constrained quality level",
+          "Constrained quality level",
+          0, 63, DEFAULT_CQ_LEVEL,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_INTRA_BITRATE_PCT,
+      g_param_spec_int ("max-intra-bitrate", "Max Intra bitrate",
+          "Maximum Intra frame bitrate",
+          0, G_MAXINT, DEFAULT_MAX_INTRA_BITRATE_PCT,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (gobject_class, PROP_TIMEBASE,
+      gst_param_spec_fraction ("timebase", "Shortest interframe time",
+          "Fraction of one second that is the shortest interframe time - normally left as zero which will default to the framerate",
+          0, 1, G_MAXINT, 1, DEFAULT_TIMEBASE_N, DEFAULT_TIMEBASE_D,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  GST_DEBUG_CATEGORY_INIT (gst_vpxenc_debug, "vpxenc", 0, "VPX Encoder");
+}
+
+static void
+gst_vpx_enc_init (GstVPXEnc * gst_vpx_enc)
+{
+  GST_DEBUG_OBJECT (gst_vpx_enc, "init");
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_ENCODER_SINK_PAD (gst_vpx_enc));
+
+  gst_vpx_enc->cfg.rc_end_usage = DEFAULT_RC_END_USAGE;
+  gst_vpx_enc->cfg.rc_target_bitrate = DEFAULT_RC_TARGET_BITRATE / 1000;
+  gst_vpx_enc->rc_target_bitrate_set = FALSE;
+  gst_vpx_enc->cfg.rc_min_quantizer = DEFAULT_RC_MIN_QUANTIZER;
+  gst_vpx_enc->cfg.rc_max_quantizer = DEFAULT_RC_MAX_QUANTIZER;
+  gst_vpx_enc->cfg.rc_dropframe_thresh = DEFAULT_RC_DROPFRAME_THRESH;
+  gst_vpx_enc->cfg.rc_resize_allowed = DEFAULT_RC_RESIZE_ALLOWED;
+  gst_vpx_enc->cfg.rc_resize_up_thresh = DEFAULT_RC_RESIZE_UP_THRESH;
+  gst_vpx_enc->cfg.rc_resize_down_thresh = DEFAULT_RC_RESIZE_DOWN_THRESH;
+  gst_vpx_enc->cfg.rc_undershoot_pct = DEFAULT_RC_UNDERSHOOT_PCT;
+  gst_vpx_enc->cfg.rc_overshoot_pct = DEFAULT_RC_OVERSHOOT_PCT;
+  gst_vpx_enc->cfg.rc_buf_sz = DEFAULT_RC_BUF_SZ;
+  gst_vpx_enc->cfg.rc_buf_initial_sz = DEFAULT_RC_BUF_INITIAL_SZ;
+  gst_vpx_enc->cfg.rc_buf_optimal_sz = DEFAULT_RC_BUF_OPTIMAL_SZ;
+  gst_vpx_enc->cfg.rc_2pass_vbr_bias_pct = DEFAULT_RC_2PASS_VBR_BIAS_PCT;
+  gst_vpx_enc->cfg.rc_2pass_vbr_minsection_pct =
+      DEFAULT_RC_2PASS_VBR_MINSECTION_PCT;
+  gst_vpx_enc->cfg.rc_2pass_vbr_maxsection_pct =
+      DEFAULT_RC_2PASS_VBR_MAXSECTION_PCT;
+  gst_vpx_enc->cfg.kf_mode = DEFAULT_KF_MODE;
+  gst_vpx_enc->cfg.kf_max_dist = DEFAULT_KF_MAX_DIST;
+  gst_vpx_enc->cfg.g_pass = DEFAULT_MULTIPASS_MODE;
+  gst_vpx_enc->multipass_cache_prefix = g_strdup (DEFAULT_MULTIPASS_CACHE_FILE);
+  gst_vpx_enc->multipass_cache_file = NULL;
+  gst_vpx_enc->multipass_cache_idx = 0;
+  gst_vpx_enc->cfg.ts_number_layers = DEFAULT_TS_NUMBER_LAYERS;
+  gst_vpx_enc->n_ts_target_bitrate = 0;
+  gst_vpx_enc->n_ts_rate_decimator = 0;
+  gst_vpx_enc->cfg.ts_periodicity = DEFAULT_TS_PERIODICITY;
+  gst_vpx_enc->n_ts_layer_id = 0;
+  gst_vpx_enc->cfg.g_error_resilient = DEFAULT_ERROR_RESILIENT;
+  gst_vpx_enc->cfg.g_lag_in_frames = DEFAULT_LAG_IN_FRAMES;
+  gst_vpx_enc->cfg.g_threads = DEFAULT_THREADS;
+  gst_vpx_enc->deadline = DEFAULT_DEADLINE;
+  gst_vpx_enc->h_scaling_mode = DEFAULT_H_SCALING_MODE;
+  gst_vpx_enc->v_scaling_mode = DEFAULT_V_SCALING_MODE;
+  gst_vpx_enc->cpu_used = DEFAULT_CPU_USED;
+  gst_vpx_enc->enable_auto_alt_ref = DEFAULT_ENABLE_AUTO_ALT_REF;
+  gst_vpx_enc->noise_sensitivity = DEFAULT_NOISE_SENSITIVITY;
+  gst_vpx_enc->sharpness = DEFAULT_SHARPNESS;
+  gst_vpx_enc->static_threshold = DEFAULT_STATIC_THRESHOLD;
+  gst_vpx_enc->token_partitions = DEFAULT_TOKEN_PARTITIONS;
+  gst_vpx_enc->arnr_maxframes = DEFAULT_ARNR_MAXFRAMES;
+  gst_vpx_enc->arnr_strength = DEFAULT_ARNR_STRENGTH;
+  gst_vpx_enc->arnr_type = DEFAULT_ARNR_TYPE;
+  gst_vpx_enc->tuning = DEFAULT_TUNING;
+  gst_vpx_enc->cq_level = DEFAULT_CQ_LEVEL;
+  gst_vpx_enc->max_intra_bitrate_pct = DEFAULT_MAX_INTRA_BITRATE_PCT;
+  gst_vpx_enc->timebase_n = DEFAULT_TIMEBASE_N;
+  gst_vpx_enc->timebase_d = DEFAULT_TIMEBASE_D;
+
+  gst_vpx_enc->cfg.g_profile = DEFAULT_PROFILE;
+
+  g_mutex_init (&gst_vpx_enc->encoder_lock);
+}
+
+static void
+gst_vpx_enc_finalize (GObject * object)
+{
+  GstVPXEnc *gst_vpx_enc;
+
+  GST_DEBUG_OBJECT (object, "finalize");
+
+  g_return_if_fail (GST_IS_VPX_ENC (object));
+  gst_vpx_enc = GST_VPX_ENC (object);
+
+  g_free (gst_vpx_enc->multipass_cache_prefix);
+  g_free (gst_vpx_enc->multipass_cache_file);
+  gst_vpx_enc->multipass_cache_idx = 0;
+
+
+  if (gst_vpx_enc->input_state)
+    gst_video_codec_state_unref (gst_vpx_enc->input_state);
+
+  g_mutex_clear (&gst_vpx_enc->encoder_lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_vpx_enc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVPXEnc *gst_vpx_enc;
+  gboolean global = FALSE;
+  vpx_codec_err_t status;
+
+  g_return_if_fail (GST_IS_VPX_ENC (object));
+  gst_vpx_enc = GST_VPX_ENC (object);
+
+  GST_DEBUG_OBJECT (object, "gst_vpx_enc_set_property");
+  g_mutex_lock (&gst_vpx_enc->encoder_lock);
+  switch (prop_id) {
+    case PROP_RC_END_USAGE:
+      gst_vpx_enc->cfg.rc_end_usage = g_value_get_enum (value);
+      global = TRUE;
+      break;
+    case PROP_RC_TARGET_BITRATE:
+      gst_vpx_enc->cfg.rc_target_bitrate = g_value_get_int (value) / 1000;
+      gst_vpx_enc->rc_target_bitrate_set = TRUE;
+      global = TRUE;
+      break;
+    case PROP_RC_MIN_QUANTIZER:
+      gst_vpx_enc->cfg.rc_min_quantizer = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_RC_MAX_QUANTIZER:
+      gst_vpx_enc->cfg.rc_max_quantizer = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_RC_DROPFRAME_THRESH:
+      gst_vpx_enc->cfg.rc_dropframe_thresh = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_RC_RESIZE_ALLOWED:
+      gst_vpx_enc->cfg.rc_resize_allowed = g_value_get_boolean (value);
+      global = TRUE;
+      break;
+    case PROP_RC_RESIZE_UP_THRESH:
+      gst_vpx_enc->cfg.rc_resize_up_thresh = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_RC_RESIZE_DOWN_THRESH:
+      gst_vpx_enc->cfg.rc_resize_down_thresh = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_RC_UNDERSHOOT_PCT:
+      gst_vpx_enc->cfg.rc_undershoot_pct = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_RC_OVERSHOOT_PCT:
+      gst_vpx_enc->cfg.rc_overshoot_pct = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_RC_BUF_SZ:
+      gst_vpx_enc->cfg.rc_buf_sz = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_RC_BUF_INITIAL_SZ:
+      gst_vpx_enc->cfg.rc_buf_initial_sz = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_RC_BUF_OPTIMAL_SZ:
+      gst_vpx_enc->cfg.rc_buf_optimal_sz = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_RC_2PASS_VBR_BIAS_PCT:
+      gst_vpx_enc->cfg.rc_2pass_vbr_bias_pct = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_RC_2PASS_VBR_MINSECTION_PCT:
+      gst_vpx_enc->cfg.rc_2pass_vbr_minsection_pct = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_RC_2PASS_VBR_MAXSECTION_PCT:
+      gst_vpx_enc->cfg.rc_2pass_vbr_maxsection_pct = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_KF_MODE:
+      gst_vpx_enc->cfg.kf_mode = g_value_get_enum (value);
+      global = TRUE;
+      break;
+    case PROP_KF_MAX_DIST:
+      gst_vpx_enc->cfg.kf_max_dist = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_MULTIPASS_MODE:
+      gst_vpx_enc->cfg.g_pass = g_value_get_enum (value);
+      global = TRUE;
+      break;
+    case PROP_MULTIPASS_CACHE_FILE:
+      if (gst_vpx_enc->multipass_cache_prefix)
+        g_free (gst_vpx_enc->multipass_cache_prefix);
+      gst_vpx_enc->multipass_cache_prefix = g_value_dup_string (value);
+      break;
+    case PROP_TS_NUMBER_LAYERS:
+      gst_vpx_enc->cfg.ts_number_layers = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_TS_TARGET_BITRATE:{
+      GValueArray *va = g_value_get_boxed (value);
+
+      memset (&gst_vpx_enc->cfg.ts_target_bitrate, 0,
+          sizeof (gst_vpx_enc->cfg.ts_target_bitrate));
+      if (va == NULL) {
+        gst_vpx_enc->n_ts_target_bitrate = 0;
+      } else if (va->n_values > VPX_TS_MAX_LAYERS) {
+        g_warning ("%s: Only %d layers allowed at maximum",
+            GST_ELEMENT_NAME (gst_vpx_enc), VPX_TS_MAX_LAYERS);
+      } else {
+        gint i;
+
+        for (i = 0; i < va->n_values; i++)
+          gst_vpx_enc->cfg.ts_target_bitrate[i] =
+              g_value_get_int (g_value_array_get_nth (va, i));
+        gst_vpx_enc->n_ts_target_bitrate = va->n_values;
+      }
+      global = TRUE;
+      break;
+    }
+    case PROP_TS_RATE_DECIMATOR:{
+      GValueArray *va = g_value_get_boxed (value);
+
+      memset (&gst_vpx_enc->cfg.ts_rate_decimator, 0,
+          sizeof (gst_vpx_enc->cfg.ts_rate_decimator));
+      if (va == NULL) {
+        gst_vpx_enc->n_ts_rate_decimator = 0;
+      } else if (va->n_values > VPX_TS_MAX_LAYERS) {
+        g_warning ("%s: Only %d layers allowed at maximum",
+            GST_ELEMENT_NAME (gst_vpx_enc), VPX_TS_MAX_LAYERS);
+      } else {
+        gint i;
+
+        for (i = 0; i < va->n_values; i++)
+          gst_vpx_enc->cfg.ts_rate_decimator[i] =
+              g_value_get_int (g_value_array_get_nth (va, i));
+        gst_vpx_enc->n_ts_rate_decimator = va->n_values;
+      }
+      global = TRUE;
+      break;
+    }
+    case PROP_TS_PERIODICITY:
+      gst_vpx_enc->cfg.ts_periodicity = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_TS_LAYER_ID:{
+      GValueArray *va = g_value_get_boxed (value);
+
+      memset (&gst_vpx_enc->cfg.ts_layer_id, 0,
+          sizeof (gst_vpx_enc->cfg.ts_layer_id));
+      if (va && va->n_values > VPX_TS_MAX_PERIODICITY) {
+        g_warning ("%s: Only %d sized layer sequences allowed at maximum",
+            GST_ELEMENT_NAME (gst_vpx_enc), VPX_TS_MAX_PERIODICITY);
+      } else if (va) {
+        gint i;
+
+        for (i = 0; i < va->n_values; i++)
+          gst_vpx_enc->cfg.ts_layer_id[i] =
+              g_value_get_int (g_value_array_get_nth (va, i));
+        gst_vpx_enc->n_ts_layer_id = va->n_values;
+      } else {
+        gst_vpx_enc->n_ts_layer_id = 0;
+      }
+      global = TRUE;
+      break;
+    }
+    case PROP_ERROR_RESILIENT:
+      gst_vpx_enc->cfg.g_error_resilient = g_value_get_flags (value);
+      global = TRUE;
+      break;
+    case PROP_LAG_IN_FRAMES:
+      gst_vpx_enc->cfg.g_lag_in_frames = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_THREADS:
+      gst_vpx_enc->cfg.g_threads = g_value_get_int (value);
+      global = TRUE;
+      break;
+    case PROP_DEADLINE:
+      gst_vpx_enc->deadline = g_value_get_int64 (value);
+      break;
+    case PROP_H_SCALING_MODE:
+      gst_vpx_enc->h_scaling_mode = g_value_get_enum (value);
+      if (gst_vpx_enc->inited) {
+        vpx_scaling_mode_t sm;
+
+        sm.h_scaling_mode = gst_vpx_enc->h_scaling_mode;
+        sm.v_scaling_mode = gst_vpx_enc->v_scaling_mode;
+
+        status =
+            vpx_codec_control (&gst_vpx_enc->encoder, VP8E_SET_SCALEMODE, &sm);
+        if (status != VPX_CODEC_OK) {
+          GST_WARNING_OBJECT (gst_vpx_enc,
+              "Failed to set VP8E_SET_SCALEMODE: %s",
+              gst_vpx_error_name (status));
+        }
+      }
+      break;
+    case PROP_V_SCALING_MODE:
+      gst_vpx_enc->v_scaling_mode = g_value_get_enum (value);
+      if (gst_vpx_enc->inited) {
+        vpx_scaling_mode_t sm;
+
+        sm.h_scaling_mode = gst_vpx_enc->h_scaling_mode;
+        sm.v_scaling_mode = gst_vpx_enc->v_scaling_mode;
+
+        status =
+            vpx_codec_control (&gst_vpx_enc->encoder, VP8E_SET_SCALEMODE, &sm);
+        if (status != VPX_CODEC_OK) {
+          GST_WARNING_OBJECT (gst_vpx_enc,
+              "Failed to set VP8E_SET_SCALEMODE: %s",
+              gst_vpx_error_name (status));
+        }
+      }
+      break;
+    case PROP_CPU_USED:
+      gst_vpx_enc->cpu_used = g_value_get_int (value);
+      if (gst_vpx_enc->inited) {
+        status =
+            vpx_codec_control (&gst_vpx_enc->encoder, VP8E_SET_CPUUSED,
+            gst_vpx_enc->cpu_used);
+        if (status != VPX_CODEC_OK) {
+          GST_WARNING_OBJECT (gst_vpx_enc, "Failed to set VP8E_SET_CPUUSED: %s",
+              gst_vpx_error_name (status));
+        }
+      }
+      break;
+    case PROP_ENABLE_AUTO_ALT_REF:
+      gst_vpx_enc->enable_auto_alt_ref = g_value_get_boolean (value);
+      if (gst_vpx_enc->inited) {
+        status =
+            vpx_codec_control (&gst_vpx_enc->encoder, VP8E_SET_ENABLEAUTOALTREF,
+            (gst_vpx_enc->enable_auto_alt_ref ? 1 : 0));
+        if (status != VPX_CODEC_OK) {
+          GST_WARNING_OBJECT (gst_vpx_enc,
+              "Failed to set VP8E_SET_ENABLEAUTOALTREF: %s",
+              gst_vpx_error_name (status));
+        }
+      }
+      break;
+    case PROP_NOISE_SENSITIVITY:
+      gst_vpx_enc->noise_sensitivity = g_value_get_int (value);
+      if (gst_vpx_enc->inited) {
+        status =
+            vpx_codec_control (&gst_vpx_enc->encoder,
+            VP8E_SET_NOISE_SENSITIVITY, gst_vpx_enc->noise_sensitivity);
+        if (status != VPX_CODEC_OK) {
+          GST_WARNING_OBJECT (gst_vpx_enc,
+              "Failed to set VP8E_SET_NOISE_SENSITIVITY: %s",
+              gst_vpx_error_name (status));
+        }
+      }
+      break;
+    case PROP_SHARPNESS:
+      gst_vpx_enc->sharpness = g_value_get_int (value);
+      if (gst_vpx_enc->inited) {
+        status = vpx_codec_control (&gst_vpx_enc->encoder, VP8E_SET_SHARPNESS,
+            gst_vpx_enc->sharpness);
+        if (status != VPX_CODEC_OK) {
+          GST_WARNING_OBJECT (gst_vpx_enc,
+              "Failed to set VP8E_SET_SHARPNESS: %s",
+              gst_vpx_error_name (status));
+        }
+      }
+      break;
+    case PROP_STATIC_THRESHOLD:
+      gst_vpx_enc->static_threshold = g_value_get_int (value);
+      if (gst_vpx_enc->inited) {
+        status =
+            vpx_codec_control (&gst_vpx_enc->encoder, VP8E_SET_STATIC_THRESHOLD,
+            gst_vpx_enc->static_threshold);
+        if (status != VPX_CODEC_OK) {
+          GST_WARNING_OBJECT (gst_vpx_enc,
+              "Failed to set VP8E_SET_STATIC_THRESHOLD: %s",
+              gst_vpx_error_name (status));
+        }
+      }
+      break;
+    case PROP_TOKEN_PARTITIONS:
+      gst_vpx_enc->token_partitions = g_value_get_enum (value);
+      if (gst_vpx_enc->inited) {
+        status =
+            vpx_codec_control (&gst_vpx_enc->encoder, VP8E_SET_TOKEN_PARTITIONS,
+            gst_vpx_enc->token_partitions);
+        if (status != VPX_CODEC_OK) {
+          GST_WARNING_OBJECT (gst_vpx_enc,
+              "Failed to set VP8E_SET_TOKEN_PARTIONS: %s",
+              gst_vpx_error_name (status));
+        }
+      }
+      break;
+    case PROP_ARNR_MAXFRAMES:
+      gst_vpx_enc->arnr_maxframes = g_value_get_int (value);
+      if (gst_vpx_enc->inited) {
+        status =
+            vpx_codec_control (&gst_vpx_enc->encoder, VP8E_SET_ARNR_MAXFRAMES,
+            gst_vpx_enc->arnr_maxframes);
+        if (status != VPX_CODEC_OK) {
+          GST_WARNING_OBJECT (gst_vpx_enc,
+              "Failed to set VP8E_SET_ARNR_MAXFRAMES: %s",
+              gst_vpx_error_name (status));
+        }
+      }
+      break;
+    case PROP_ARNR_STRENGTH:
+      gst_vpx_enc->arnr_strength = g_value_get_int (value);
+      if (gst_vpx_enc->inited) {
+        status =
+            vpx_codec_control (&gst_vpx_enc->encoder, VP8E_SET_ARNR_STRENGTH,
+            gst_vpx_enc->arnr_strength);
+        if (status != VPX_CODEC_OK) {
+          GST_WARNING_OBJECT (gst_vpx_enc,
+              "Failed to set VP8E_SET_ARNR_STRENGTH: %s",
+              gst_vpx_error_name (status));
+        }
+      }
+      break;
+    case PROP_ARNR_TYPE:
+      gst_vpx_enc->arnr_type = g_value_get_int (value);
+      g_warning ("arnr-type is a no-op since control has been deprecated "
+          "in libvpx");
+      break;
+    case PROP_TUNING:
+      gst_vpx_enc->tuning = g_value_get_enum (value);
+      if (gst_vpx_enc->inited) {
+        status = vpx_codec_control (&gst_vpx_enc->encoder, VP8E_SET_TUNING,
+            gst_vpx_enc->tuning);
+        if (status != VPX_CODEC_OK) {
+          GST_WARNING_OBJECT (gst_vpx_enc,
+              "Failed to set VP8E_SET_TUNING: %s", gst_vpx_error_name (status));
+        }
+      }
+      break;
+    case PROP_CQ_LEVEL:
+      gst_vpx_enc->cq_level = g_value_get_int (value);
+      if (gst_vpx_enc->inited) {
+        status = vpx_codec_control (&gst_vpx_enc->encoder, VP8E_SET_CQ_LEVEL,
+            gst_vpx_enc->cq_level);
+        if (status != VPX_CODEC_OK) {
+          GST_WARNING_OBJECT (gst_vpx_enc,
+              "Failed to set VP8E_SET_CQ_LEVEL: %s",
+              gst_vpx_error_name (status));
+        }
+      }
+      break;
+    case PROP_MAX_INTRA_BITRATE_PCT:
+      gst_vpx_enc->max_intra_bitrate_pct = g_value_get_int (value);
+      if (gst_vpx_enc->inited) {
+        status =
+            vpx_codec_control (&gst_vpx_enc->encoder,
+            VP8E_SET_MAX_INTRA_BITRATE_PCT, gst_vpx_enc->max_intra_bitrate_pct);
+        if (status != VPX_CODEC_OK) {
+          GST_WARNING_OBJECT (gst_vpx_enc,
+              "Failed to set VP8E_SET_MAX_INTRA_BITRATE_PCT: %s",
+              gst_vpx_error_name (status));
+        }
+      }
+      break;
+    case PROP_TIMEBASE:
+      gst_vpx_enc->timebase_n = gst_value_get_fraction_numerator (value);
+      gst_vpx_enc->timebase_d = gst_value_get_fraction_denominator (value);
+      break;
+    default:
+      break;
+  }
+
+  if (global &&gst_vpx_enc->inited) {
+    status =
+        vpx_codec_enc_config_set (&gst_vpx_enc->encoder, &gst_vpx_enc->cfg);
+    if (status != VPX_CODEC_OK) {
+      g_mutex_unlock (&gst_vpx_enc->encoder_lock);
+      GST_ELEMENT_ERROR (gst_vpx_enc, LIBRARY, INIT,
+          ("Failed to set encoder configuration"), ("%s",
+              gst_vpx_error_name (status)));
+    } else {
+      g_mutex_unlock (&gst_vpx_enc->encoder_lock);
+    }
+  } else {
+    g_mutex_unlock (&gst_vpx_enc->encoder_lock);
+  }
+}
+
+static void
+gst_vpx_enc_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstVPXEnc *gst_vpx_enc;
+
+  g_return_if_fail (GST_IS_VPX_ENC (object));
+  gst_vpx_enc = GST_VPX_ENC (object);
+
+  g_mutex_lock (&gst_vpx_enc->encoder_lock);
+  switch (prop_id) {
+    case PROP_RC_END_USAGE:
+      g_value_set_enum (value, gst_vpx_enc->cfg.rc_end_usage);
+      break;
+    case PROP_RC_TARGET_BITRATE:
+      g_value_set_int (value, gst_vpx_enc->cfg.rc_target_bitrate * 1000);
+      break;
+    case PROP_RC_MIN_QUANTIZER:
+      g_value_set_int (value, gst_vpx_enc->cfg.rc_min_quantizer);
+      break;
+    case PROP_RC_MAX_QUANTIZER:
+      g_value_set_int (value, gst_vpx_enc->cfg.rc_max_quantizer);
+      break;
+    case PROP_RC_DROPFRAME_THRESH:
+      g_value_set_int (value, gst_vpx_enc->cfg.rc_dropframe_thresh);
+      break;
+    case PROP_RC_RESIZE_ALLOWED:
+      g_value_set_boolean (value, gst_vpx_enc->cfg.rc_resize_allowed);
+      break;
+    case PROP_RC_RESIZE_UP_THRESH:
+      g_value_set_int (value, gst_vpx_enc->cfg.rc_resize_up_thresh);
+      break;
+    case PROP_RC_RESIZE_DOWN_THRESH:
+      g_value_set_int (value, gst_vpx_enc->cfg.rc_resize_down_thresh);
+      break;
+    case PROP_RC_UNDERSHOOT_PCT:
+      g_value_set_int (value, gst_vpx_enc->cfg.rc_undershoot_pct);
+      break;
+    case PROP_RC_OVERSHOOT_PCT:
+      g_value_set_int (value, gst_vpx_enc->cfg.rc_overshoot_pct);
+      break;
+    case PROP_RC_BUF_SZ:
+      g_value_set_int (value, gst_vpx_enc->cfg.rc_buf_sz);
+      break;
+    case PROP_RC_BUF_INITIAL_SZ:
+      g_value_set_int (value, gst_vpx_enc->cfg.rc_buf_initial_sz);
+      break;
+    case PROP_RC_BUF_OPTIMAL_SZ:
+      g_value_set_int (value, gst_vpx_enc->cfg.rc_buf_optimal_sz);
+      break;
+    case PROP_RC_2PASS_VBR_BIAS_PCT:
+      g_value_set_int (value, gst_vpx_enc->cfg.rc_2pass_vbr_bias_pct);
+      break;
+    case PROP_RC_2PASS_VBR_MINSECTION_PCT:
+      g_value_set_int (value, gst_vpx_enc->cfg.rc_2pass_vbr_minsection_pct);
+      break;
+    case PROP_RC_2PASS_VBR_MAXSECTION_PCT:
+      g_value_set_int (value, gst_vpx_enc->cfg.rc_2pass_vbr_maxsection_pct);
+      break;
+    case PROP_KF_MODE:
+      g_value_set_enum (value, gst_vpx_enc->cfg.kf_mode);
+      break;
+    case PROP_KF_MAX_DIST:
+      g_value_set_int (value, gst_vpx_enc->cfg.kf_max_dist);
+      break;
+    case PROP_MULTIPASS_MODE:
+      g_value_set_enum (value, gst_vpx_enc->cfg.g_pass);
+      break;
+    case PROP_MULTIPASS_CACHE_FILE:
+      g_value_set_string (value, gst_vpx_enc->multipass_cache_prefix);
+      break;
+    case PROP_TS_NUMBER_LAYERS:
+      g_value_set_int (value, gst_vpx_enc->cfg.ts_number_layers);
+      break;
+    case PROP_TS_TARGET_BITRATE:{
+      GValueArray *va;
+
+      if (gst_vpx_enc->n_ts_target_bitrate == 0) {
+        g_value_set_boxed (value, NULL);
+      } else {
+        gint i;
+
+        va = g_value_array_new (gst_vpx_enc->n_ts_target_bitrate);
+        for (i = 0; i < gst_vpx_enc->n_ts_target_bitrate; i++) {
+          GValue v = { 0, };
+
+          g_value_init (&v, G_TYPE_INT);
+          g_value_set_int (&v, gst_vpx_enc->cfg.ts_target_bitrate[i]);
+          g_value_array_append (va, &v);
+          g_value_unset (&v);
+        }
+        g_value_set_boxed (value, va);
+        g_value_array_free (va);
+      }
+      break;
+    }
+    case PROP_TS_RATE_DECIMATOR:{
+      GValueArray *va;
+
+      if (gst_vpx_enc->n_ts_rate_decimator == 0) {
+        g_value_set_boxed (value, NULL);
+      } else {
+        gint i;
+
+        va = g_value_array_new (gst_vpx_enc->n_ts_rate_decimator);
+        for (i = 0; i < gst_vpx_enc->n_ts_rate_decimator; i++) {
+          GValue v = { 0, };
+
+          g_value_init (&v, G_TYPE_INT);
+          g_value_set_int (&v, gst_vpx_enc->cfg.ts_rate_decimator[i]);
+          g_value_array_append (va, &v);
+          g_value_unset (&v);
+        }
+        g_value_set_boxed (value, va);
+        g_value_array_free (va);
+      }
+      break;
+    }
+    case PROP_TS_PERIODICITY:
+      g_value_set_int (value, gst_vpx_enc->cfg.ts_periodicity);
+      break;
+    case PROP_TS_LAYER_ID:{
+      GValueArray *va;
+
+      if (gst_vpx_enc->n_ts_layer_id == 0) {
+        g_value_set_boxed (value, NULL);
+      } else {
+        gint i;
+
+        va = g_value_array_new (gst_vpx_enc->n_ts_layer_id);
+        for (i = 0; i < gst_vpx_enc->n_ts_layer_id; i++) {
+          GValue v = { 0, };
+
+          g_value_init (&v, G_TYPE_INT);
+          g_value_set_int (&v, gst_vpx_enc->cfg.ts_layer_id[i]);
+          g_value_array_append (va, &v);
+          g_value_unset (&v);
+        }
+        g_value_set_boxed (value, va);
+        g_value_array_free (va);
+      }
+      break;
+    }
+    case PROP_ERROR_RESILIENT:
+      g_value_set_flags (value, gst_vpx_enc->cfg.g_error_resilient);
+      break;
+    case PROP_LAG_IN_FRAMES:
+      g_value_set_int (value, gst_vpx_enc->cfg.g_lag_in_frames);
+      break;
+    case PROP_THREADS:
+      g_value_set_int (value, gst_vpx_enc->cfg.g_threads);
+      break;
+    case PROP_DEADLINE:
+      g_value_set_int64 (value, gst_vpx_enc->deadline);
+      break;
+    case PROP_H_SCALING_MODE:
+      g_value_set_enum (value, gst_vpx_enc->h_scaling_mode);
+      break;
+    case PROP_V_SCALING_MODE:
+      g_value_set_enum (value, gst_vpx_enc->v_scaling_mode);
+      break;
+    case PROP_CPU_USED:
+      g_value_set_int (value, gst_vpx_enc->cpu_used);
+      break;
+    case PROP_ENABLE_AUTO_ALT_REF:
+      g_value_set_boolean (value, gst_vpx_enc->enable_auto_alt_ref);
+      break;
+    case PROP_NOISE_SENSITIVITY:
+      g_value_set_int (value, gst_vpx_enc->noise_sensitivity);
+      break;
+    case PROP_SHARPNESS:
+      g_value_set_int (value, gst_vpx_enc->sharpness);
+      break;
+    case PROP_STATIC_THRESHOLD:
+      g_value_set_int (value, gst_vpx_enc->static_threshold);
+      break;
+    case PROP_TOKEN_PARTITIONS:
+      g_value_set_enum (value, gst_vpx_enc->token_partitions);
+      break;
+    case PROP_ARNR_MAXFRAMES:
+      g_value_set_int (value, gst_vpx_enc->arnr_maxframes);
+      break;
+    case PROP_ARNR_STRENGTH:
+      g_value_set_int (value, gst_vpx_enc->arnr_strength);
+      break;
+    case PROP_ARNR_TYPE:
+      g_value_set_int (value, gst_vpx_enc->arnr_type);
+      break;
+    case PROP_TUNING:
+      g_value_set_enum (value, gst_vpx_enc->tuning);
+      break;
+    case PROP_CQ_LEVEL:
+      g_value_set_int (value, gst_vpx_enc->cq_level);
+      break;
+    case PROP_MAX_INTRA_BITRATE_PCT:
+      g_value_set_int (value, gst_vpx_enc->max_intra_bitrate_pct);
+      break;
+    case PROP_TIMEBASE:
+      gst_value_set_fraction (value, gst_vpx_enc->timebase_n,
+          gst_vpx_enc->timebase_d);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  g_mutex_unlock (&gst_vpx_enc->encoder_lock);
+}
+
+static gboolean
+gst_vpx_enc_start (GstVideoEncoder * video_encoder)
+{
+  GstVPXEnc *encoder = GST_VPX_ENC (video_encoder);
+
+  GST_DEBUG_OBJECT (video_encoder, "start");
+
+  if (!encoder->have_default_config) {
+    GST_ELEMENT_ERROR (encoder, LIBRARY, INIT,
+        ("Failed to get default encoder configuration"), (NULL));
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static void
+gst_vpx_enc_destroy_encoder (GstVPXEnc * encoder)
+{
+  g_mutex_lock (&encoder->encoder_lock);
+  if (encoder->inited) {
+    vpx_codec_destroy (&encoder->encoder);
+    encoder->inited = FALSE;
+  }
+
+  if (encoder->first_pass_cache_content) {
+    g_byte_array_free (encoder->first_pass_cache_content, TRUE);
+    encoder->first_pass_cache_content = NULL;
+  }
+
+  if (encoder->cfg.rc_twopass_stats_in.buf) {
+    g_free (encoder->cfg.rc_twopass_stats_in.buf);
+    encoder->cfg.rc_twopass_stats_in.buf = NULL;
+    encoder->cfg.rc_twopass_stats_in.sz = 0;
+  }
+  g_mutex_unlock (&encoder->encoder_lock);
+}
+
+static gboolean
+gst_vpx_enc_stop (GstVideoEncoder * video_encoder)
+{
+  GstVPXEnc *encoder;
+
+  GST_DEBUG_OBJECT (video_encoder, "stop");
+
+  encoder = GST_VPX_ENC (video_encoder);
+
+  gst_vpx_enc_destroy_encoder (encoder);
+
+  gst_tag_setter_reset_tags (GST_TAG_SETTER (encoder));
+
+  g_free (encoder->multipass_cache_file);
+  encoder->multipass_cache_file = NULL;
+  encoder->multipass_cache_idx = 0;
+
+  return TRUE;
+}
+
+static gint
+gst_vpx_enc_get_downstream_profile (GstVPXEnc * encoder)
+{
+  GstCaps *allowed;
+  GstStructure *s;
+  gint profile = DEFAULT_PROFILE;
+
+  allowed = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
+  if (allowed) {
+    allowed = gst_caps_truncate (allowed);
+    s = gst_caps_get_structure (allowed, 0);
+    if (gst_structure_has_field (s, "profile")) {
+      const GValue *v = gst_structure_get_value (s, "profile");
+      const gchar *profile_str = NULL;
+
+      if (GST_VALUE_HOLDS_LIST (v) && gst_value_list_get_size (v) > 0) {
+        profile_str = g_value_get_string (gst_value_list_get_value (v, 0));
+      } else if (G_VALUE_HOLDS_STRING (v)) {
+        profile_str = g_value_get_string (v);
+      }
+
+      if (profile_str) {
+        gchar *endptr = NULL;
+
+        profile = g_ascii_strtoull (profile_str, &endptr, 10);
+        if (*endptr != '\0' || profile < 0 || profile > 3) {
+          GST_ERROR_OBJECT (encoder, "Invalid profile '%s'", profile_str);
+          profile = DEFAULT_PROFILE;
+        }
+      }
+    }
+    gst_caps_unref (allowed);
+  }
+
+  GST_DEBUG_OBJECT (encoder, "Using profile %d", profile);
+
+  return profile;
+}
+
+static gboolean
+gst_vpx_enc_set_format (GstVideoEncoder * video_encoder,
+    GstVideoCodecState * state)
+{
+  GstVPXEnc *encoder;
+  vpx_codec_err_t status;
+  vpx_image_t *image;
+  GstCaps *caps;
+  gboolean ret = TRUE;
+  GstVideoInfo *info = &state->info;
+  GstVideoCodecState *output_state;
+  GstClockTime latency;
+  GstVPXEncClass *vpx_enc_class;
+
+  encoder = GST_VPX_ENC (video_encoder);
+  vpx_enc_class = GST_VPX_ENC_GET_CLASS (encoder);
+  GST_DEBUG_OBJECT (video_encoder, "set_format");
+
+  if (encoder->inited) {
+    gst_vpx_enc_drain (video_encoder);
+    g_mutex_lock (&encoder->encoder_lock);
+    vpx_codec_destroy (&encoder->encoder);
+    encoder->inited = FALSE;
+    encoder->multipass_cache_idx++;
+  } else {
+    g_mutex_lock (&encoder->encoder_lock);
+  }
+
+  encoder->cfg.g_profile = gst_vpx_enc_get_downstream_profile (encoder);
+
+  /* Scale default bitrate to our size */
+  if (!encoder->rc_target_bitrate_set)
+    encoder->cfg.rc_target_bitrate =
+        gst_util_uint64_scale (DEFAULT_RC_TARGET_BITRATE,
+        GST_VIDEO_INFO_WIDTH (info) * GST_VIDEO_INFO_HEIGHT (info),
+        320 * 240 * 1000);
+
+  encoder->cfg.g_w = GST_VIDEO_INFO_WIDTH (info);
+  encoder->cfg.g_h = GST_VIDEO_INFO_HEIGHT (info);
+
+  if (encoder->timebase_n != 0 && encoder->timebase_d != 0) {
+    GST_DEBUG_OBJECT (video_encoder, "Using timebase configuration");
+    encoder->cfg.g_timebase.num = encoder->timebase_n;
+    encoder->cfg.g_timebase.den = encoder->timebase_d;
+  } else {
+    /* Zero framerate and max-framerate but still need to setup the timebase to avoid
+     * a divide by zero error. Presuming the lowest common denominator will be RTP -
+     * VP8 payload draft states clock rate of 90000 which should work for anyone where
+     * FPS < 90000 (shouldn't be too many cases where it's higher) though wouldn't be optimal. RTP specification
+     * http://tools.ietf.org/html/draft-ietf-payload-vp8-01 section 6.3.1 */
+    encoder->cfg.g_timebase.num = 1;
+    encoder->cfg.g_timebase.den = 90000;
+  }
+
+  if (encoder->cfg.g_pass == VPX_RC_FIRST_PASS ||
+      encoder->cfg.g_pass == VPX_RC_LAST_PASS) {
+    if (!encoder->multipass_cache_prefix) {
+      GST_ELEMENT_ERROR (encoder, RESOURCE, OPEN_READ,
+          ("No multipass cache file provided"), (NULL));
+      g_mutex_unlock (&encoder->encoder_lock);
+      return FALSE;
+    }
+
+    g_free (encoder->multipass_cache_file);
+
+    if (encoder->multipass_cache_idx > 0)
+      encoder->multipass_cache_file = g_strdup_printf ("%s.%u",
+          encoder->multipass_cache_prefix, encoder->multipass_cache_idx);
+    else
+      encoder->multipass_cache_file =
+          g_strdup (encoder->multipass_cache_prefix);
+  }
+
+  if (encoder->cfg.g_pass == VPX_RC_FIRST_PASS) {
+    if (encoder->first_pass_cache_content != NULL)
+      g_byte_array_free (encoder->first_pass_cache_content, TRUE);
+
+    encoder->first_pass_cache_content = g_byte_array_sized_new (4096);
+
+  } else if (encoder->cfg.g_pass == VPX_RC_LAST_PASS) {
+    GError *err = NULL;
+
+    if (encoder->cfg.rc_twopass_stats_in.buf != NULL) {
+      g_free (encoder->cfg.rc_twopass_stats_in.buf);
+      encoder->cfg.rc_twopass_stats_in.buf = NULL;
+      encoder->cfg.rc_twopass_stats_in.sz = 0;
+    }
+
+    if (!g_file_get_contents (encoder->multipass_cache_file,
+            (gchar **) & encoder->cfg.rc_twopass_stats_in.buf,
+            &encoder->cfg.rc_twopass_stats_in.sz, &err)) {
+      GST_ELEMENT_ERROR (encoder, RESOURCE, OPEN_READ,
+          ("Failed to read multipass cache file provided"), ("%s",
+              err->message));
+      g_error_free (err);
+      g_mutex_unlock (&encoder->encoder_lock);
+      return FALSE;
+    }
+  }
+
+  status =
+      vpx_codec_enc_init (&encoder->encoder, vpx_enc_class->get_algo (encoder),
+      &encoder->cfg, 0);
+  if (status != VPX_CODEC_OK) {
+    GST_ELEMENT_ERROR (encoder, LIBRARY, INIT,
+        ("Failed to initialize encoder"), ("%s", gst_vpx_error_name (status)));
+    g_mutex_unlock (&encoder->encoder_lock);
+    return FALSE;
+  }
+
+  if (vpx_enc_class->enable_scaling (encoder)) {
+    vpx_scaling_mode_t sm;
+
+    sm.h_scaling_mode = encoder->h_scaling_mode;
+    sm.v_scaling_mode = encoder->v_scaling_mode;
+
+    status = vpx_codec_control (&encoder->encoder, VP8E_SET_SCALEMODE, &sm);
+    if (status != VPX_CODEC_OK) {
+      GST_WARNING_OBJECT (encoder, "Failed to set VP8E_SET_SCALEMODE: %s",
+          gst_vpx_error_name (status));
+    }
+  }
+
+  status =
+      vpx_codec_control (&encoder->encoder, VP8E_SET_CPUUSED,
+      encoder->cpu_used);
+  if (status != VPX_CODEC_OK) {
+    GST_WARNING_OBJECT (encoder, "Failed to set VP8E_SET_CPUUSED: %s",
+        gst_vpx_error_name (status));
+  }
+
+  status =
+      vpx_codec_control (&encoder->encoder, VP8E_SET_ENABLEAUTOALTREF,
+      (encoder->enable_auto_alt_ref ? 1 : 0));
+  if (status != VPX_CODEC_OK) {
+    GST_WARNING_OBJECT (encoder,
+        "Failed to set VP8E_SET_ENABLEAUTOALTREF: %s",
+        gst_vpx_error_name (status));
+  }
+  status = vpx_codec_control (&encoder->encoder, VP8E_SET_NOISE_SENSITIVITY,
+      encoder->noise_sensitivity);
+  if (status != VPX_CODEC_OK) {
+    GST_WARNING_OBJECT (encoder,
+        "Failed to set VP8E_SET_NOISE_SENSITIVITY: %s",
+        gst_vpx_error_name (status));
+  }
+  status = vpx_codec_control (&encoder->encoder, VP8E_SET_SHARPNESS,
+      encoder->sharpness);
+  if (status != VPX_CODEC_OK) {
+    GST_WARNING_OBJECT (encoder,
+        "Failed to set VP8E_SET_SHARPNESS: %s", gst_vpx_error_name (status));
+  }
+  status = vpx_codec_control (&encoder->encoder, VP8E_SET_STATIC_THRESHOLD,
+      encoder->static_threshold);
+  if (status != VPX_CODEC_OK) {
+    GST_WARNING_OBJECT (encoder,
+        "Failed to set VP8E_SET_STATIC_THRESHOLD: %s",
+        gst_vpx_error_name (status));
+  }
+  status = vpx_codec_control (&encoder->encoder, VP8E_SET_TOKEN_PARTITIONS,
+      encoder->token_partitions);
+  if (status != VPX_CODEC_OK) {
+    GST_WARNING_OBJECT (encoder,
+        "Failed to set VP8E_SET_TOKEN_PARTIONS: %s",
+        gst_vpx_error_name (status));
+  }
+  status = vpx_codec_control (&encoder->encoder, VP8E_SET_ARNR_MAXFRAMES,
+      encoder->arnr_maxframes);
+  if (status != VPX_CODEC_OK) {
+    GST_WARNING_OBJECT (encoder,
+        "Failed to set VP8E_SET_ARNR_MAXFRAMES: %s",
+        gst_vpx_error_name (status));
+  }
+  status = vpx_codec_control (&encoder->encoder, VP8E_SET_ARNR_STRENGTH,
+      encoder->arnr_strength);
+  if (status != VPX_CODEC_OK) {
+    GST_WARNING_OBJECT (encoder,
+        "Failed to set VP8E_SET_ARNR_STRENGTH: %s",
+        gst_vpx_error_name (status));
+  }
+  status = vpx_codec_control (&encoder->encoder, VP8E_SET_TUNING,
+      encoder->tuning);
+  if (status != VPX_CODEC_OK) {
+    GST_WARNING_OBJECT (encoder,
+        "Failed to set VP8E_SET_TUNING: %s", gst_vpx_error_name (status));
+  }
+  status = vpx_codec_control (&encoder->encoder, VP8E_SET_CQ_LEVEL,
+      encoder->cq_level);
+  if (status != VPX_CODEC_OK) {
+    GST_WARNING_OBJECT (encoder,
+        "Failed to set VP8E_SET_CQ_LEVEL: %s", gst_vpx_error_name (status));
+  }
+  status = vpx_codec_control (&encoder->encoder, VP8E_SET_MAX_INTRA_BITRATE_PCT,
+      encoder->max_intra_bitrate_pct);
+  if (status != VPX_CODEC_OK) {
+    GST_WARNING_OBJECT (encoder,
+        "Failed to set VP8E_SET_MAX_INTRA_BITRATE_PCT: %s",
+        gst_vpx_error_name (status));
+  }
+
+  if (GST_VIDEO_INFO_FPS_D (info) == 0 || GST_VIDEO_INFO_FPS_N (info) == 0) {
+    /* FIXME: Assume 25fps for unknown framerates. Better than reporting
+     * that we introduce no latency while we actually do
+     */
+    latency = gst_util_uint64_scale (encoder->cfg.g_lag_in_frames,
+        1 * GST_SECOND, 25);
+  } else {
+    latency = gst_util_uint64_scale (encoder->cfg.g_lag_in_frames,
+        GST_VIDEO_INFO_FPS_D (info) * GST_SECOND, GST_VIDEO_INFO_FPS_N (info));
+  }
+  gst_video_encoder_set_latency (video_encoder, latency, latency);
+  encoder->inited = TRUE;
+
+  /* Store input state */
+  if (encoder->input_state)
+    gst_video_codec_state_unref (encoder->input_state);
+  encoder->input_state = gst_video_codec_state_ref (state);
+
+  /* prepare cached image buffer setup */
+  image = &encoder->image;
+  memset (image, 0, sizeof (*image));
+
+  vpx_enc_class->set_image_format (encoder, image);
+
+  image->w = image->d_w = GST_VIDEO_INFO_WIDTH (info);
+  image->h = image->d_h = GST_VIDEO_INFO_HEIGHT (info);
+
+  image->stride[VPX_PLANE_Y] = GST_VIDEO_INFO_COMP_STRIDE (info, 0);
+  image->stride[VPX_PLANE_U] = GST_VIDEO_INFO_COMP_STRIDE (info, 1);
+  image->stride[VPX_PLANE_V] = GST_VIDEO_INFO_COMP_STRIDE (info, 2);
+
+  caps = vpx_enc_class->get_new_vpx_caps (encoder);
+
+  vpx_enc_class->set_stream_info (encoder, caps, info);
+
+  g_mutex_unlock (&encoder->encoder_lock);
+
+  output_state =
+      gst_video_encoder_set_output_state (video_encoder, caps, state);
+  gst_video_codec_state_unref (output_state);
+
+  gst_video_encoder_negotiate (GST_VIDEO_ENCODER (encoder));
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_vpx_enc_process (GstVPXEnc * encoder)
+{
+  vpx_codec_iter_t iter = NULL;
+  const vpx_codec_cx_pkt_t *pkt;
+  GstVideoEncoder *video_encoder;
+  void *user_data;
+  GstVideoCodecFrame *frame;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstVPXEncClass *vpx_enc_class;
+  vpx_codec_pts_t pts;
+
+  video_encoder = GST_VIDEO_ENCODER (encoder);
+  vpx_enc_class = GST_VPX_ENC_GET_CLASS (encoder);
+
+  g_mutex_lock (&encoder->encoder_lock);
+  pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
+  while (pkt != NULL) {
+    GstBuffer *buffer;
+    gboolean invisible;
+
+    GST_DEBUG_OBJECT (encoder, "packet %u type %d", (guint) pkt->data.frame.sz,
+        pkt->kind);
+
+    if (pkt->kind == VPX_CODEC_STATS_PKT
+        && encoder->cfg.g_pass == VPX_RC_FIRST_PASS) {
+      GST_LOG_OBJECT (encoder, "handling STATS packet");
+
+      g_byte_array_append (encoder->first_pass_cache_content,
+          pkt->data.twopass_stats.buf, pkt->data.twopass_stats.sz);
+
+      frame = gst_video_encoder_get_oldest_frame (video_encoder);
+      if (frame != NULL) {
+        buffer = gst_buffer_new ();
+        GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_LIVE);
+        frame->output_buffer = buffer;
+        g_mutex_unlock (&encoder->encoder_lock);
+        ret = gst_video_encoder_finish_frame (video_encoder, frame);
+        g_mutex_lock (&encoder->encoder_lock);
+      }
+
+      pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
+      continue;
+    } else if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) {
+      GST_LOG_OBJECT (encoder, "non frame pkt: %d", pkt->kind);
+      pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
+      continue;
+    }
+
+    invisible = (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE) != 0;
+
+    /* discard older frames that were dropped by libvpx */
+    frame = NULL;
+    do {
+      if (frame)
+        gst_video_encoder_finish_frame (video_encoder, frame);
+      frame = gst_video_encoder_get_oldest_frame (video_encoder);
+      pts =
+          gst_util_uint64_scale (frame->pts,
+          encoder->cfg.g_timebase.den,
+          encoder->cfg.g_timebase.num * (GstClockTime) GST_SECOND);
+      GST_TRACE_OBJECT (encoder, "vpx pts: %" G_GINT64_FORMAT
+          ", gst frame pts: %" G_GINT64_FORMAT, pkt->data.frame.pts, pts);
+    } while (pkt->data.frame.pts > pts);
+
+    g_assert (frame != NULL);
+    if ((pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0)
+      GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
+    else
+      GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
+
+    /* FIXME : It would be nice to avoid the memory copy ... */
+    buffer =
+        gst_buffer_new_wrapped (g_memdup (pkt->data.frame.buf,
+            pkt->data.frame.sz), pkt->data.frame.sz);
+
+    user_data = vpx_enc_class->process_frame_user_data (encoder, frame);
+
+    if (invisible) {
+      ret =
+          vpx_enc_class->handle_invisible_frame_buffer (encoder, user_data,
+          buffer);
+      gst_video_codec_frame_unref (frame);
+    } else {
+      frame->output_buffer = buffer;
+      g_mutex_unlock (&encoder->encoder_lock);
+      ret = gst_video_encoder_finish_frame (video_encoder, frame);
+      g_mutex_lock (&encoder->encoder_lock);
+    }
+
+    pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
+  }
+  g_mutex_unlock (&encoder->encoder_lock);
+
+  return ret;
+}
+
+/* This function should be called holding then stream lock*/
+static GstFlowReturn
+gst_vpx_enc_drain (GstVideoEncoder * video_encoder)
+{
+  GstVPXEnc *encoder;
+  int flags = 0;
+  vpx_codec_err_t status;
+  gint64 deadline;
+  vpx_codec_pts_t pts;
+
+  encoder = GST_VPX_ENC (video_encoder);
+
+  g_mutex_lock (&encoder->encoder_lock);
+  deadline = encoder->deadline;
+
+  pts =
+      gst_util_uint64_scale (encoder->last_pts,
+      encoder->cfg.g_timebase.den,
+      encoder->cfg.g_timebase.num * (GstClockTime) GST_SECOND);
+
+  status = vpx_codec_encode (&encoder->encoder, NULL, pts, 0, flags, deadline);
+  g_mutex_unlock (&encoder->encoder_lock);
+
+  if (status != 0) {
+    GST_ERROR_OBJECT (encoder, "encode returned %d %s", status,
+        gst_vpx_error_name (status));
+    return GST_FLOW_ERROR;
+  }
+
+  /* dispatch remaining frames */
+  gst_vpx_enc_process (encoder);
+
+  g_mutex_lock (&encoder->encoder_lock);
+  if (encoder->cfg.g_pass == VPX_RC_FIRST_PASS && encoder->multipass_cache_file) {
+    GError *err = NULL;
+
+    if (!g_file_set_contents (encoder->multipass_cache_file,
+            (const gchar *) encoder->first_pass_cache_content->data,
+            encoder->first_pass_cache_content->len, &err)) {
+      GST_ELEMENT_ERROR (encoder, RESOURCE, WRITE, (NULL),
+          ("Failed to write multipass cache file: %s", err->message));
+      g_error_free (err);
+    }
+  }
+  g_mutex_unlock (&encoder->encoder_lock);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_vpx_enc_flush (GstVideoEncoder * video_encoder)
+{
+  GstVPXEnc *encoder;
+
+  GST_DEBUG_OBJECT (video_encoder, "flush");
+
+  encoder = GST_VPX_ENC (video_encoder);
+
+  gst_vpx_enc_destroy_encoder (encoder);
+  if (encoder->input_state) {
+    gst_video_codec_state_ref (encoder->input_state);
+    gst_vpx_enc_set_format (video_encoder, encoder->input_state);
+    gst_video_codec_state_unref (encoder->input_state);
+  }
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_vpx_enc_finish (GstVideoEncoder * video_encoder)
+{
+  GstVPXEnc *encoder;
+  GstFlowReturn ret;
+
+  GST_DEBUG_OBJECT (video_encoder, "finish");
+
+  encoder = GST_VPX_ENC (video_encoder);
+
+  if (encoder->inited) {
+    ret = gst_vpx_enc_drain (video_encoder);
+  } else {
+    ret = GST_FLOW_OK;
+  }
+
+  return ret;
+}
+
+static vpx_image_t *
+gst_vpx_enc_buffer_to_image (GstVPXEnc * enc, GstVideoFrame * frame)
+{
+  vpx_image_t *image = g_slice_new (vpx_image_t);
+
+  memcpy (image, &enc->image, sizeof (*image));
+
+  image->planes[VPX_PLANE_Y] = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
+  image->planes[VPX_PLANE_U] = GST_VIDEO_FRAME_COMP_DATA (frame, 1);
+  image->planes[VPX_PLANE_V] = GST_VIDEO_FRAME_COMP_DATA (frame, 2);
+
+  image->stride[VPX_PLANE_Y] = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
+  image->stride[VPX_PLANE_U] = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1);
+  image->stride[VPX_PLANE_V] = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2);
+
+  return image;
+}
+
+static GstFlowReturn
+gst_vpx_enc_handle_frame (GstVideoEncoder * video_encoder,
+    GstVideoCodecFrame * frame)
+{
+  GstVPXEnc *encoder;
+  vpx_codec_err_t status;
+  int flags = 0;
+  vpx_image_t *image;
+  GstVideoFrame vframe;
+  vpx_codec_pts_t pts;
+  unsigned long duration;
+  GstVPXEncClass *vpx_enc_class;
+
+  GST_DEBUG_OBJECT (video_encoder, "handle_frame");
+
+  encoder = GST_VPX_ENC (video_encoder);
+  vpx_enc_class = GST_VPX_ENC_GET_CLASS (encoder);
+
+  GST_DEBUG_OBJECT (video_encoder, "size %d %d",
+      GST_VIDEO_INFO_WIDTH (&encoder->input_state->info),
+      GST_VIDEO_INFO_HEIGHT (&encoder->input_state->info));
+
+  gst_video_frame_map (&vframe, &encoder->input_state->info,
+      frame->input_buffer, GST_MAP_READ);
+  image = gst_vpx_enc_buffer_to_image (encoder, &vframe);
+
+  vpx_enc_class->set_frame_user_data (encoder, frame, image);
+
+  if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
+    flags |= VPX_EFLAG_FORCE_KF;
+  }
+
+  g_mutex_lock (&encoder->encoder_lock);
+  pts =
+      gst_util_uint64_scale (frame->pts,
+      encoder->cfg.g_timebase.den,
+      encoder->cfg.g_timebase.num * (GstClockTime) GST_SECOND);
+  encoder->last_pts = frame->pts;
+
+  if (frame->duration != GST_CLOCK_TIME_NONE) {
+    duration =
+        gst_util_uint64_scale (frame->duration, encoder->cfg.g_timebase.den,
+        encoder->cfg.g_timebase.num * (GstClockTime) GST_SECOND);
+
+    if (duration > 0) {
+      encoder->last_pts += frame->duration;
+    } else {
+      /* We force the path ignoring the duration if we end up with a zero
+       * value for duration after scaling (e.g. duration value too small) */
+      GST_WARNING_OBJECT (encoder,
+          "Ignoring too small frame duration %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (frame->duration));
+      duration = 1;
+    }
+  } else {
+    duration = 1;
+  }
+
+  status = vpx_codec_encode (&encoder->encoder, image,
+      pts, duration, flags, encoder->deadline);
+
+  g_mutex_unlock (&encoder->encoder_lock);
+  gst_video_frame_unmap (&vframe);
+
+  if (status != 0) {
+    GST_ELEMENT_ERROR (encoder, LIBRARY, ENCODE,
+        ("Failed to encode frame"), ("%s", gst_vpx_error_name (status)));
+    gst_video_codec_frame_set_user_data (frame, NULL, NULL);
+    gst_video_codec_frame_unref (frame);
+
+    return GST_FLOW_ERROR;
+  }
+  gst_video_codec_frame_unref (frame);
+  return gst_vpx_enc_process (encoder);
+}
+
+static gboolean
+gst_vpx_enc_sink_event (GstVideoEncoder * benc, GstEvent * event)
+{
+  GstVPXEnc *enc = GST_VPX_ENC (benc);
+
+  /* FIXME : Move this to base encoder class */
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_TAG) {
+    GstTagList *list;
+    GstTagSetter *setter = GST_TAG_SETTER (enc);
+    const GstTagMergeMode mode = gst_tag_setter_get_tag_merge_mode (setter);
+
+    gst_event_parse_tag (event, &list);
+    gst_tag_setter_merge_tags (setter, list, mode);
+  }
+
+  /* just peeked, baseclass handles the rest */
+  return GST_VIDEO_ENCODER_CLASS (parent_class)->sink_event (benc, event);
+}
+
+static gboolean
+gst_vpx_enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
+{
+  gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
+
+  return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
+      query);
+}
+
+#endif /* HAVE_VP8_ENCODER || HAVE_VP9_ENCODER */
diff --git a/ext/vpx/gstvpxenc.h b/ext/vpx/gstvpxenc.h
new file mode 100644
index 0000000..fb01927
--- /dev/null
+++ b/ext/vpx/gstvpxenc.h
@@ -0,0 +1,140 @@
+/* VP8
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ * Copyright (C) 2010 Entropy Wave Inc
+ * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+#ifndef __GST_VPX_ENC_H__
+#define __GST_VPX_ENC_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(HAVE_VP8_ENCODER) || defined(HAVE_VP9_ENCODER)
+
+#include <gst/gst.h>
+#include <gst/video/gstvideoencoder.h>
+
+/* FIXME: Undef HAVE_CONFIG_H because vpx_codec.h uses it,
+ * which causes compilation failures */
+#ifdef HAVE_CONFIG_H
+#undef HAVE_CONFIG_H
+#endif
+
+#include <vpx/vpx_encoder.h>
+#include <vpx/vp8cx.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VPX_ENC \
+  (gst_vpx_enc_get_type())
+#define GST_VPX_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VPX_ENC,GstVPXEnc))
+#define GST_VPX_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VPX_ENC,GstVPXEncClass))
+#define GST_IS_VPX_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VPX_ENC))
+#define GST_IS_VPX_ENC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VPX_ENC))
+#define GST_VPX_ENC_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VPX_ENC, GstVPXEncClass))
+
+typedef struct _GstVPXEnc GstVPXEnc;
+typedef struct _GstVPXEncClass GstVPXEncClass;
+
+struct _GstVPXEnc
+{
+  GstVideoEncoder base_video_encoder;
+
+  /* < private > */
+  vpx_codec_ctx_t encoder;
+  GMutex encoder_lock;
+
+  /* properties */
+  vpx_codec_enc_cfg_t cfg;
+  gboolean have_default_config;
+  gboolean rc_target_bitrate_set;
+  gint n_ts_target_bitrate;
+  gint n_ts_rate_decimator;
+  gint n_ts_layer_id;
+  /* Global two-pass options */
+  gchar *multipass_cache_file;
+  gchar *multipass_cache_prefix;
+  guint multipass_cache_idx;
+  GByteArray *first_pass_cache_content;
+
+  /* Encode parameter */
+  gint64 deadline;
+
+  /* Controls */
+  VPX_SCALING_MODE h_scaling_mode;
+  VPX_SCALING_MODE v_scaling_mode;
+  int cpu_used;
+  gboolean enable_auto_alt_ref;
+  unsigned int noise_sensitivity;
+  unsigned int sharpness;
+  unsigned int static_threshold;
+  vp8e_token_partitions token_partitions;
+  unsigned int arnr_maxframes;
+  unsigned int arnr_strength;
+  unsigned int arnr_type;
+  vp8e_tuning tuning;
+  unsigned int cq_level;
+  unsigned int max_intra_bitrate_pct;
+  /* Timebase - a value of 0 will use the framerate */
+  unsigned int timebase_n;
+  unsigned int timebase_d;
+
+  /* state */
+  gboolean inited;
+
+  vpx_image_t image;
+
+  GstClockTime last_pts;
+
+  GstVideoCodecState *input_state;
+};
+
+struct _GstVPXEncClass
+{
+  GstVideoEncoderClass base_video_encoder_class;
+  /*virtual function to get supported algo*/
+  vpx_codec_iface_t* (*get_algo) (GstVPXEnc *enc);
+  /*enabled scaling*/
+  gboolean (*enable_scaling) (GstVPXEnc *enc);
+  /*set image format info*/
+  void (*set_image_format) (GstVPXEnc *enc, vpx_image_t *image);
+  /*get new simple caps*/
+  GstCaps* (*get_new_vpx_caps) (GstVPXEnc *enc);
+  /*set stream info*/
+  void (*set_stream_info) (GstVPXEnc *enc, GstCaps *caps, GstVideoInfo *info);
+  /*process user data*/
+  void* (*process_frame_user_data) (GstVPXEnc *enc, GstVideoCodecFrame* frame);
+  /*set frame user data*/
+  void (*set_frame_user_data) (GstVPXEnc *enc, GstVideoCodecFrame* frame, vpx_image_t *image);
+  /*Handle invisible frame*/
+  GstFlowReturn (*handle_invisible_frame_buffer) (GstVPXEnc *enc, void* user_data, GstBuffer* buffer);
+};
+
+GType gst_vpx_enc_get_type (void);
+
+G_END_DECLS
+
+#endif
+
+#endif /* __GST_VPX_ENC_H__ */
diff --git a/ext/vpx/meson.build b/ext/vpx/meson.build
new file mode 100644
index 0000000..685aeb7
--- /dev/null
+++ b/ext/vpx/meson.build
@@ -0,0 +1,62 @@
+vpx_sources = [
+  'gstvp8dec.c',
+  'gstvp8enc.c',
+  'gstvp8utils.c',
+  'gstvp9dec.c',
+  'gstvp9enc.c',
+  'gstvpxdec.c',
+  'gstvpxenc.c',
+  'plugin.c',
+]
+
+vpx_features = [
+  [ 'vpx/vp8cx.h', 'vpx_codec_vp8_cx_algo', '-DHAVE_VP8_ENCODER', 'VP8 encoder' ],
+  [ 'vpx/vp8dx.h', 'vpx_codec_vp8_dx_algo', '-DHAVE_VP8_DECODER', 'VP8 decoder' ],
+  [ 'vpx/vp8cx.h', 'vpx_codec_vp9_cx_algo', '-DHAVE_VP9_ENCODER', 'VP9 encoder' ],
+  [ 'vpx/vp8dx.h', 'vpx_codec_vp9_dx_algo', '-DHAVE_VP9_DECODER', 'VP9 decoder' ],
+]
+
+vpx_dep = dependency('vpx', version : '>=1.3.0', required : false)
+
+if vpx_dep.found()
+  vpx_args = []
+  foreach f : vpx_features
+    header = f.get(0)
+    codec_iface = f.get(1)
+    extra_define = f.get(2)
+    link_code = '''#include <@0@>
+                   int main (int a, char ** g) {
+                     const vpx_codec_iface_t *c = &@1@;
+                     return c != 0;
+                   }'''.format(header,codec_iface)
+    # FIXME: should take dependencies : vpx_dep argument
+    if cc.links(link_code, args : ['-lvpx'])
+      vpx_args += extra_define
+      message('libvpx provides @0@ interface (@1@)'.format(f.get(3),f.get(1)))
+      have_vpx_feature = true
+    else
+      message('libvpx does not provide @0@ interface (@1@)'.format(f.get(3),f.get(1)))
+      have_vpx_feature = false
+    endif
+    set_variable('have_' + f.get(3).to_lower().underscorify(), have_vpx_feature)
+  endforeach
+
+  if vpx_args.length() == 0
+    message('WARNING: libvpx was built without any encoder or decoder features!')
+  endif
+
+  if dependency('vpx', version : '>=1.4.0', required : false).found()
+    vpx_args += '-DHAVE_VPX_1_4'
+  endif
+
+  gstvpx = library('gstvpx',
+    vpx_sources,
+    c_args : gst_plugins_good_args + vpx_args,
+    include_directories : [configinc],
+    dependencies : [gstbase_dep, gsttag_dep, gstvideo_dep, vpx_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+
+  install_data(sources: ['GstVP8Enc.prs'], install_dir: presetdir)
+endif
diff --git a/ext/vpx/plugin.c b/ext/vpx/plugin.c
new file mode 100644
index 0000000..4f04efa
--- /dev/null
+++ b/ext/vpx/plugin.c
@@ -0,0 +1,63 @@
+/* VP8
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ * Copyright (C) 2010 Entropy Wave Inc
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "gstvp8dec.h"
+#include "gstvp8enc.h"
+#include "gstvp9dec.h"
+#include "gstvp9enc.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+#ifdef HAVE_VP8_DECODER
+  gst_element_register (plugin, "vp8dec", GST_RANK_PRIMARY,
+      gst_vp8_dec_get_type ());
+#endif
+
+#ifdef HAVE_VP8_ENCODER
+  gst_element_register (plugin, "vp8enc", GST_RANK_PRIMARY,
+      gst_vp8_enc_get_type ());
+#endif
+
+#ifdef HAVE_VP9_DECODER
+  gst_element_register (plugin, "vp9dec", GST_RANK_PRIMARY,
+      gst_vp9_dec_get_type ());
+#endif
+
+#ifdef HAVE_VP9_ENCODER
+  gst_element_register (plugin, "vp9enc", GST_RANK_PRIMARY,
+      gst_vp9_enc_get_type ());
+#endif
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    vpx,
+    "VP8 plugin",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/wavpack/Makefile.am b/ext/wavpack/Makefile.am
new file mode 100644
index 0000000..e6ed6d4
--- /dev/null
+++ b/ext/wavpack/Makefile.am
@@ -0,0 +1,21 @@
+plugin_LTLIBRARIES = libgstwavpack.la
+
+libgstwavpack_la_SOURCES = \
+				gstwavpack.c \
+				gstwavpackcommon.c \
+				gstwavpackdec.c \
+				gstwavpackenc.c \
+				gstwavpackstreamreader.c
+
+libgstwavpack_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
+				$(GST_BASE_CFLAGS) $(GST_CFLAGS) $(WAVPACK_CFLAGS)
+libgstwavpack_la_LIBADD =  $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) \
+				$(GST_BASE_LIBS) $(GST_LIBS) $(WAVPACK_LIBS)
+libgstwavpack_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = \
+		gstwavpackdec.h \
+		gstwavpackenc.h \
+		gstwavpackcommon.h \
+		gstwavpackstreamreader.h
+
diff --git a/ext/wavpack/gstwavpack.c b/ext/wavpack/gstwavpack.c
new file mode 100644
index 0000000..1609aa2
--- /dev/null
+++ b/ext/wavpack/gstwavpack.c
@@ -0,0 +1,54 @@
+/* GStreamer wavpack plugin
+ * (c) 2004 Arwed v. Merkatz <v.merkatz@gmx.net>
+ *
+ * gstwavpack.c: plugin loader
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst-i18n-plugin.h>
+
+#include "gstwavpackdec.h"
+#include "gstwavpackenc.h"
+
+/* debug category for common code */
+GST_DEBUG_CATEGORY (wavpack_debug);
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (wavpack_debug, "wavpack", 0, "Wavpack elements");
+
+#ifdef ENABLE_NLS
+  GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
+      LOCALEDIR);
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+
+  return (gst_wavpack_dec_plugin_init (plugin)
+      && gst_wavpack_enc_plugin_init (plugin));
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    wavpack,
+    "Wavpack lossless/lossy audio format handling",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/wavpack/gstwavpackcommon.c b/ext/wavpack/gstwavpackcommon.c
new file mode 100644
index 0000000..a17c9b2
--- /dev/null
+++ b/ext/wavpack/gstwavpackcommon.c
@@ -0,0 +1,264 @@
+/* GStreamer Wavpack plugin
+ * Copyright (c) 2005 Arwed v. Merkatz <v.merkatz@gmx.net>
+ * Copyright (c) 1998 - 2005 Conifer Software
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackcommon.c: common helper functions
+ * 
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstwavpackcommon.h"
+#include <string.h>
+
+#include <gst/gst.h>
+
+GST_DEBUG_CATEGORY_EXTERN (wavpack_debug);
+#define GST_CAT_DEFAULT wavpack_debug
+
+gboolean
+gst_wavpack_read_header (WavpackHeader * header, guint8 * buf)
+{
+  memmove (header, buf, sizeof (WavpackHeader));
+
+  WavpackLittleEndianToNative (header, (char *) WavpackHeaderFormat);
+
+  return (memcmp (header->ckID, "wvpk", 4) == 0);
+}
+
+/* inspired by the original one in wavpack */
+gboolean
+gst_wavpack_read_metadata (GstWavpackMetadata * wpmd, guint8 * header_data,
+    guint8 ** p_data)
+{
+  WavpackHeader hdr;
+  guint8 *end;
+
+  gst_wavpack_read_header (&hdr, header_data);
+  end = header_data + hdr.ckSize + 8;
+
+  if (end - *p_data < 2)
+    return FALSE;
+
+  wpmd->id = GST_READ_UINT8 (*p_data);
+  wpmd->byte_length = 2 * (guint) GST_READ_UINT8 (*p_data + 1);
+
+  *p_data += 2;
+
+  if ((wpmd->id & ID_LARGE) == ID_LARGE) {
+    guint extra;
+
+    wpmd->id &= ~ID_LARGE;
+
+    if (end - *p_data < 2)
+      return FALSE;
+
+    extra = GST_READ_UINT16_LE (*p_data);
+    wpmd->byte_length += (extra << 9);
+    *p_data += 2;
+  }
+
+  if ((wpmd->id & ID_ODD_SIZE) == ID_ODD_SIZE) {
+    wpmd->id &= ~ID_ODD_SIZE;
+    --wpmd->byte_length;
+  }
+
+  if (wpmd->byte_length > 0) {
+    if (end - *p_data < wpmd->byte_length + (wpmd->byte_length & 1)) {
+      wpmd->data = NULL;
+      return FALSE;
+    }
+
+    wpmd->data = *p_data;
+    *p_data += wpmd->byte_length + (wpmd->byte_length & 1);
+  } else {
+    wpmd->data = NULL;
+  }
+
+  return TRUE;
+}
+
+gint
+gst_wavpack_get_default_channel_mask (gint nchannels)
+{
+  gint channel_mask = 0;
+
+  /* Set the default channel mask for the given number of channels.
+   * It's the same as for WAVE_FORMAT_EXTENDED:
+   * http://www.microsoft.com/whdc/device/audio/multichaud.mspx
+   */
+  switch (nchannels) {
+    case 11:
+      channel_mask |= 0x00400;
+      channel_mask |= 0x00200;
+    case 9:
+      channel_mask |= 0x00100;
+    case 8:
+      channel_mask |= 0x00080;
+      channel_mask |= 0x00040;
+    case 6:
+      channel_mask |= 0x00020;
+      channel_mask |= 0x00010;
+    case 4:
+      channel_mask |= 0x00008;
+    case 3:
+      channel_mask |= 0x00004;
+    case 2:
+      channel_mask |= 0x00002;
+      channel_mask |= 0x00001;
+      break;
+    case 1:
+      /* For mono use front center */
+      channel_mask |= 0x00004;
+      break;
+  }
+
+  return channel_mask;
+}
+
+static const struct
+{
+  const guint32 ms_mask;
+  const GstAudioChannelPosition gst_pos;
+} layout_mapping[] = {
+  {
+  0x00001, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT}, {
+  0x00002, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
+  0x00004, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, {
+  0x00008, GST_AUDIO_CHANNEL_POSITION_LFE1}, {
+  0x00010, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT}, {
+  0x00020, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
+  0x00040, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER}, {
+  0x00080, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, {
+  0x00100, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, {
+  0x00200, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT}, {
+  0x00400, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}, {
+  0x00800, GST_AUDIO_CHANNEL_POSITION_TOP_CENTER}, {
+  0x01000, GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT}, {
+  0x02000, GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER}, {
+  0x04000, GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT}, {
+  0x08000, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT}, {
+  0x10000, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER}, {
+  0x20000, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT}
+};
+
+#define MAX_CHANNEL_POSITIONS G_N_ELEMENTS (layout_mapping)
+
+gboolean
+gst_wavpack_get_channel_positions (gint num_channels, gint layout,
+    GstAudioChannelPosition * pos)
+{
+  gint i, p;
+
+  if (num_channels == 1 && layout == 0x00004) {
+    pos[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
+    return TRUE;
+  }
+
+  p = 0;
+  for (i = 0; i < MAX_CHANNEL_POSITIONS; ++i) {
+    if ((layout & layout_mapping[i].ms_mask) != 0) {
+      if (p >= num_channels) {
+        GST_WARNING ("More bits set in the channel layout map than there "
+            "are channels! Broken file");
+        return FALSE;
+      }
+      if (layout_mapping[i].gst_pos == GST_AUDIO_CHANNEL_POSITION_INVALID) {
+        GST_WARNING ("Unsupported channel position (mask 0x%08x) in channel "
+            "layout map - ignoring those channels", layout_mapping[i].ms_mask);
+        /* what to do? just ignore it and let downstream deal with a channel
+         * layout that has INVALID positions in it for now ... */
+      }
+      pos[p] = layout_mapping[i].gst_pos;
+      ++p;
+    }
+  }
+
+  if (p != num_channels) {
+    GST_WARNING ("Only %d bits set in the channel layout map, but there are "
+        "supposed to be %d channels! Broken file", p, num_channels);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+GstAudioChannelPosition *
+gst_wavpack_get_default_channel_positions (gint nchannels)
+{
+  GstAudioChannelPosition *pos = g_new (GstAudioChannelPosition, nchannels);
+  gint i;
+
+  if (nchannels == 1) {
+    pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
+    return pos;
+  }
+
+  for (i = 0; i < nchannels; i++)
+    pos[i] = layout_mapping[i].gst_pos;
+
+  return pos;
+}
+
+gint
+gst_wavpack_get_channel_mask_from_positions (GstAudioChannelPosition * pos,
+    gint nchannels)
+{
+  gint channel_mask = 0;
+  gint i, j;
+
+  if (nchannels == 1 && pos[0] == GST_AUDIO_CHANNEL_POSITION_MONO) {
+    channel_mask = 0x00000004;
+    return channel_mask;
+  }
+
+  /* FIXME: not exactly efficient but otherwise we need an inverse
+   * mapping table too */
+  for (i = 0; i < nchannels; i++) {
+    for (j = 0; j < MAX_CHANNEL_POSITIONS; j++) {
+      if (pos[i] == layout_mapping[j].gst_pos) {
+        channel_mask |= layout_mapping[j].ms_mask;
+        break;
+      }
+    }
+  }
+
+  return channel_mask;
+}
+
+gboolean
+gst_wavpack_set_channel_mapping (GstAudioChannelPosition * pos, gint nchannels,
+    gint8 * channel_mapping)
+{
+  gint i, j;
+  gboolean ret = TRUE;
+
+  for (i = 0; i < nchannels; i++) {
+    for (j = 0; j < MAX_CHANNEL_POSITIONS; j++) {
+      if (pos[i] == layout_mapping[j].gst_pos) {
+        channel_mapping[i] = j;
+        ret &= (i == j);
+        break;
+      }
+    }
+  }
+
+  return !ret;
+}
diff --git a/ext/wavpack/gstwavpackcommon.h b/ext/wavpack/gstwavpackcommon.h
new file mode 100644
index 0000000..f4a81bf
--- /dev/null
+++ b/ext/wavpack/gstwavpackcommon.h
@@ -0,0 +1,75 @@
+/* GStreamer Wavpack plugin
+ * Copyright (c) 2005 Arwed v. Merkatz <v.merkatz@gmx.net>
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackcommon.h: common helper functions
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_WAVPACK_COMMON_H__
+#define __GST_WAVPACK_COMMON_H__
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <wavpack/wavpack.h>
+
+typedef struct
+{
+  guint32 byte_length;
+  guint8 *data;
+  guint8 id;
+} GstWavpackMetadata;
+
+#define ID_UNIQUE               0x3f
+#define ID_OPTIONAL_DATA        0x20
+#define ID_ODD_SIZE             0x40
+#define ID_LARGE                0x80
+
+#define ID_DUMMY                0x0
+#define ID_ENCODER_INFO         0x1
+#define ID_DECORR_TERMS         0x2
+#define ID_DECORR_WEIGHTS       0x3
+#define ID_DECORR_SAMPLES       0x4
+#define ID_ENTROPY_VARS         0x5
+#define ID_HYBRID_PROFILE       0x6
+#define ID_SHAPING_WEIGHTS      0x7
+#define ID_FLOAT_INFO           0x8
+#define ID_INT32_INFO           0x9
+#define ID_WV_BITSTREAM         0xa
+#define ID_WVC_BITSTREAM        0xb
+#define ID_WVX_BITSTREAM        0xc
+#define ID_CHANNEL_INFO         0xd
+
+#define ID_RIFF_HEADER          (ID_OPTIONAL_DATA | 0x1)
+#define ID_RIFF_TRAILER         (ID_OPTIONAL_DATA | 0x2)
+#define ID_REPLAY_GAIN          (ID_OPTIONAL_DATA | 0x3)
+#define ID_CUESHEET             (ID_OPTIONAL_DATA | 0x4)
+#define ID_CONFIG_BLOCK         (ID_OPTIONAL_DATA | 0x5)
+#define ID_MD5_CHECKSUM         (ID_OPTIONAL_DATA | 0x6)
+#define ID_SAMPLE_RATE          (ID_OPTIONAL_DATA | 0x7)
+
+
+gboolean gst_wavpack_read_header (WavpackHeader * header, guint8 * buf);
+gboolean gst_wavpack_read_metadata (GstWavpackMetadata * meta,
+    guint8 * header_data, guint8 ** p_data);
+gint gst_wavpack_get_default_channel_mask (gint nchannels);
+gboolean gst_wavpack_get_channel_positions (gint nchannels, gint layout, GstAudioChannelPosition *pos);
+GstAudioChannelPosition *gst_wavpack_get_default_channel_positions (gint nchannels);
+gint gst_wavpack_get_channel_mask_from_positions (GstAudioChannelPosition *pos, gint nchannels);
+gboolean gst_wavpack_set_channel_mapping (GstAudioChannelPosition *pos, gint nchannels, gint8 *channel_mapping);
+
+#endif
diff --git a/ext/wavpack/gstwavpackdec.c b/ext/wavpack/gstwavpackdec.c
new file mode 100644
index 0000000..7cce543
--- /dev/null
+++ b/ext/wavpack/gstwavpackdec.c
@@ -0,0 +1,473 @@
+/* GStreamer Wavpack plugin
+ * Copyright (c) 2005 Arwed v. Merkatz <v.merkatz@gmx.net>
+ * Copyright (c) 2006 Edward Hervey <bilboed@gmail.com>
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackdec.c: raw Wavpack bitstream decoder
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-wavpackdec
+ *
+ * WavpackDec decodes framed (for example by the WavpackParse element)
+ * Wavpack streams and decodes them to raw audio.
+ * <ulink url="http://www.wavpack.com/">Wavpack</ulink> is an open-source
+ * audio codec that features both lossless and lossy encoding.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=test.wv ! wavpackparse ! wavpackdec ! audioconvert ! audioresample ! autoaudiosink
+ * ]| This pipeline decodes the Wavpack file test.wv into raw audio buffers and
+ * tries to play it back using an automatically found audio sink.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+
+#include <math.h>
+#include <string.h>
+
+#include <wavpack/wavpack.h>
+#include "gstwavpackdec.h"
+#include "gstwavpackcommon.h"
+#include "gstwavpackstreamreader.h"
+
+
+GST_DEBUG_CATEGORY_STATIC (gst_wavpack_dec_debug);
+#define GST_CAT_DEFAULT gst_wavpack_dec_debug
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-wavpack, "
+        "depth = (int) [ 1, 32 ], "
+        "channels = (int) [ 1, 8 ], "
+        "rate = (int) [ 6000, 192000 ], " "framed = (boolean) true")
+    );
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) S8, "
+        "layout = (string) interleaved, "
+        "channels = (int) [ 1, 8 ], "
+        "rate = (int) [ 6000, 192000 ]; "
+        "audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (S16) ", "
+        "layout = (string) interleaved, "
+        "channels = (int) [ 1, 8 ], "
+        "rate = (int) [ 6000, 192000 ]; "
+        "audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (S32) ", "
+        "layout = (string) interleaved, "
+        "channels = (int) [ 1, 8 ], " "rate = (int) [ 6000, 192000 ]")
+    );
+
+static gboolean gst_wavpack_dec_start (GstAudioDecoder * dec);
+static gboolean gst_wavpack_dec_stop (GstAudioDecoder * dec);
+static gboolean gst_wavpack_dec_set_format (GstAudioDecoder * dec,
+    GstCaps * caps);
+static GstFlowReturn gst_wavpack_dec_handle_frame (GstAudioDecoder * dec,
+    GstBuffer * buffer);
+
+static void gst_wavpack_dec_finalize (GObject * object);
+static void gst_wavpack_dec_post_tags (GstWavpackDec * dec);
+
+#define gst_wavpack_dec_parent_class parent_class
+G_DEFINE_TYPE (GstWavpackDec, gst_wavpack_dec, GST_TYPE_AUDIO_DECODER);
+
+static void
+gst_wavpack_dec_class_init (GstWavpackDecClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *element_class = (GstElementClass *) (klass);
+  GstAudioDecoderClass *base_class = (GstAudioDecoderClass *) (klass);
+
+  gst_element_class_add_static_pad_template (element_class, &src_factory);
+  gst_element_class_add_static_pad_template (element_class, &sink_factory);
+  gst_element_class_set_static_metadata (element_class, "Wavpack audio decoder",
+      "Codec/Decoder/Audio",
+      "Decodes Wavpack audio data",
+      "Arwed v. Merkatz <v.merkatz@gmx.net>, "
+      "Sebastian Dröge <slomo@circular-chaos.org>");
+
+  gobject_class->finalize = gst_wavpack_dec_finalize;
+
+  base_class->start = GST_DEBUG_FUNCPTR (gst_wavpack_dec_start);
+  base_class->stop = GST_DEBUG_FUNCPTR (gst_wavpack_dec_stop);
+  base_class->set_format = GST_DEBUG_FUNCPTR (gst_wavpack_dec_set_format);
+  base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_wavpack_dec_handle_frame);
+}
+
+static void
+gst_wavpack_dec_reset (GstWavpackDec * dec)
+{
+  dec->wv_id.buffer = NULL;
+  dec->wv_id.position = dec->wv_id.length = 0;
+
+  dec->channels = 0;
+  dec->channel_mask = 0;
+  dec->sample_rate = 0;
+  dec->depth = 0;
+}
+
+static void
+gst_wavpack_dec_init (GstWavpackDec * dec)
+{
+  dec->context = NULL;
+  dec->stream_reader = gst_wavpack_stream_reader_new ();
+
+  gst_audio_decoder_set_needs_format (GST_AUDIO_DECODER (dec), TRUE);
+  gst_audio_decoder_set_use_default_pad_acceptcaps (GST_AUDIO_DECODER_CAST
+      (dec), TRUE);
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_DECODER_SINK_PAD (dec));
+
+  gst_wavpack_dec_reset (dec);
+}
+
+static void
+gst_wavpack_dec_finalize (GObject * object)
+{
+  GstWavpackDec *dec = GST_WAVPACK_DEC (object);
+
+  g_free (dec->stream_reader);
+  dec->stream_reader = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_wavpack_dec_start (GstAudioDecoder * dec)
+{
+  GST_DEBUG_OBJECT (dec, "start");
+
+  /* never mind a few errors */
+  gst_audio_decoder_set_max_errors (dec, 16);
+  /* don't bother us with flushing */
+  gst_audio_decoder_set_drainable (dec, FALSE);
+  /* aim for some perfect timestamping */
+  gst_audio_decoder_set_tolerance (dec, 10 * GST_MSECOND);
+
+  return TRUE;
+}
+
+static gboolean
+gst_wavpack_dec_stop (GstAudioDecoder * dec)
+{
+  GstWavpackDec *wpdec = GST_WAVPACK_DEC (dec);
+
+  GST_DEBUG_OBJECT (dec, "stop");
+
+  if (wpdec->context) {
+    WavpackCloseFile (wpdec->context);
+    wpdec->context = NULL;
+  }
+
+  gst_wavpack_dec_reset (wpdec);
+
+  return TRUE;
+}
+
+static void
+gst_wavpack_dec_negotiate (GstWavpackDec * dec)
+{
+  GstAudioInfo info;
+  GstAudioFormat fmt;
+  GstAudioChannelPosition pos[64] = { GST_AUDIO_CHANNEL_POSITION_INVALID, };
+
+  /* arrange for 1, 2 or 4-byte width == depth output */
+  dec->width = dec->depth;
+  switch (dec->depth) {
+    case 8:
+      fmt = GST_AUDIO_FORMAT_S8;
+      break;
+    case 16:
+      fmt = _GST_AUDIO_FORMAT_NE (S16);
+      break;
+    case 24:
+    case 32:
+      fmt = _GST_AUDIO_FORMAT_NE (S32);
+      dec->width = 32;
+      break;
+    default:
+      fmt = GST_AUDIO_FORMAT_UNKNOWN;
+      g_assert_not_reached ();
+      break;
+  }
+
+  g_assert (dec->channel_mask != 0);
+
+  if (!gst_wavpack_get_channel_positions (dec->channels,
+          dec->channel_mask, pos))
+    GST_WARNING_OBJECT (dec, "Failed to set channel layout");
+
+  gst_audio_info_init (&info);
+  gst_audio_info_set_format (&info, fmt, dec->sample_rate, dec->channels, pos);
+
+  gst_audio_channel_positions_to_valid_order (info.position, info.channels);
+  gst_audio_get_channel_reorder_map (info.channels,
+      info.position, pos, dec->channel_reorder_map);
+
+  /* should always succeed */
+  gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (dec), &info);
+}
+
+static gboolean
+gst_wavpack_dec_set_format (GstAudioDecoder * bdec, GstCaps * caps)
+{
+  /* pretty much nothing to do here,
+   * we'll parse it all from the stream and setup then */
+
+  return TRUE;
+}
+
+static void
+gst_wavpack_dec_post_tags (GstWavpackDec * dec)
+{
+  GstTagList *list;
+  GstFormat format_time = GST_FORMAT_TIME, format_bytes = GST_FORMAT_BYTES;
+  gint64 duration, size;
+
+  /* try to estimate the average bitrate */
+  if (gst_pad_peer_query_duration (GST_AUDIO_DECODER_SINK_PAD (dec),
+          format_bytes, &size) &&
+      gst_pad_peer_query_duration (GST_AUDIO_DECODER_SINK_PAD (dec),
+          format_time, &duration) && size > 0 && duration > 0) {
+    guint64 bitrate;
+
+    list = gst_tag_list_new_empty ();
+
+    bitrate = gst_util_uint64_scale (size, 8 * GST_SECOND, duration);
+    gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
+        (guint) bitrate, NULL);
+    gst_audio_decoder_merge_tags (GST_AUDIO_DECODER (dec), list,
+        GST_TAG_MERGE_REPLACE);
+    gst_tag_list_unref (list);
+  }
+}
+
+static GstFlowReturn
+gst_wavpack_dec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buf)
+{
+  GstWavpackDec *dec;
+  GstBuffer *outbuf = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+  WavpackHeader wph;
+  int32_t decoded, unpacked_size;
+  gboolean format_changed;
+  gint width, depth, i, j, max;
+  gint32 *dec_data = NULL;
+  guint8 *out_data;
+  GstMapInfo map, omap;
+
+  dec = GST_WAVPACK_DEC (bdec);
+
+  g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  /* check input, we only accept framed input with complete chunks */
+  if (map.size < sizeof (WavpackHeader))
+    goto input_not_framed;
+
+  if (!gst_wavpack_read_header (&wph, map.data))
+    goto invalid_header;
+
+  if (map.size < wph.ckSize + 4 * 1 + 4)
+    goto input_not_framed;
+
+  if (!(wph.flags & INITIAL_BLOCK))
+    goto input_not_framed;
+
+  dec->wv_id.buffer = map.data;
+  dec->wv_id.length = map.size;
+  dec->wv_id.position = 0;
+
+  /* create a new wavpack context if there is none yet but if there
+   * was already one (i.e. caps were set on the srcpad) check whether
+   * the new one has the same caps */
+  if (!dec->context) {
+    gchar error_msg[80];
+
+    dec->context = WavpackOpenFileInputEx (dec->stream_reader,
+        &dec->wv_id, NULL, error_msg, OPEN_STREAMING, 0);
+
+    /* expect this to work */
+    if (!dec->context) {
+      GST_WARNING_OBJECT (dec, "Couldn't decode buffer: %s", error_msg);
+      goto context_failed;
+    }
+  }
+
+  g_assert (dec->context != NULL);
+
+  format_changed =
+      (dec->sample_rate != WavpackGetSampleRate (dec->context)) ||
+      (dec->channels != WavpackGetNumChannels (dec->context)) ||
+      (dec->depth != WavpackGetBytesPerSample (dec->context) * 8) ||
+      (dec->channel_mask != WavpackGetChannelMask (dec->context));
+
+  if (!gst_pad_has_current_caps (GST_AUDIO_DECODER_SRC_PAD (dec)) ||
+      format_changed) {
+    gint channel_mask;
+
+    dec->sample_rate = WavpackGetSampleRate (dec->context);
+    dec->channels = WavpackGetNumChannels (dec->context);
+    dec->depth = WavpackGetBytesPerSample (dec->context) * 8;
+
+    channel_mask = WavpackGetChannelMask (dec->context);
+    if (channel_mask == 0)
+      channel_mask = gst_wavpack_get_default_channel_mask (dec->channels);
+
+    dec->channel_mask = channel_mask;
+
+    gst_wavpack_dec_negotiate (dec);
+
+    /* send GST_TAG_AUDIO_CODEC and GST_TAG_BITRATE tags before something
+     * is decoded or after the format has changed */
+    gst_wavpack_dec_post_tags (dec);
+  }
+
+  /* alloc output buffer */
+  dec_data = g_malloc (4 * wph.block_samples * dec->channels);
+
+  /* decode */
+  decoded = WavpackUnpackSamples (dec->context, dec_data, wph.block_samples);
+  if (decoded != wph.block_samples)
+    goto decode_error;
+
+  unpacked_size = (dec->width / 8) * wph.block_samples * dec->channels;
+  outbuf = gst_buffer_new_and_alloc (unpacked_size);
+
+  /* legacy; pass along offset, whatever that might entail */
+  GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buf);
+
+  gst_buffer_map (outbuf, &omap, GST_MAP_WRITE);
+  out_data = omap.data;
+
+  width = dec->width;
+  depth = dec->depth;
+  max = dec->channels * wph.block_samples;
+  if (width == 8) {
+    gint8 *outbuffer = (gint8 *) out_data;
+    gint *reorder_map = dec->channel_reorder_map;
+
+    for (i = 0; i < max; i += dec->channels) {
+      for (j = 0; j < dec->channels; j++)
+        *outbuffer++ = (gint8) (dec_data[i + reorder_map[j]]);
+    }
+  } else if (width == 16) {
+    gint16 *outbuffer = (gint16 *) out_data;
+    gint *reorder_map = dec->channel_reorder_map;
+
+    for (i = 0; i < max; i += dec->channels) {
+      for (j = 0; j < dec->channels; j++)
+        *outbuffer++ = (gint16) (dec_data[i + reorder_map[j]]);
+    }
+  } else if (dec->width == 32) {
+    gint32 *outbuffer = (gint32 *) out_data;
+    gint *reorder_map = dec->channel_reorder_map;
+
+    if (width != depth) {
+      for (i = 0; i < max; i += dec->channels) {
+        for (j = 0; j < dec->channels; j++)
+          *outbuffer++ =
+              (gint32) (dec_data[i + reorder_map[j]] << (width - depth));
+      }
+    } else {
+      for (i = 0; i < max; i += dec->channels) {
+        for (j = 0; j < dec->channels; j++)
+          *outbuffer++ = (gint32) (dec_data[i + reorder_map[j]]);
+      }
+    }
+  } else {
+    g_assert_not_reached ();
+  }
+
+  gst_buffer_unmap (outbuf, &omap);
+  gst_buffer_unmap (buf, &map);
+  buf = NULL;
+
+  g_free (dec_data);
+
+  ret = gst_audio_decoder_finish_frame (bdec, outbuf, 1);
+
+out:
+  if (buf)
+    gst_buffer_unmap (buf, &map);
+
+  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+    GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (ret));
+  }
+
+  return ret;
+
+/* ERRORS */
+input_not_framed:
+  {
+    GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Expected framed input"));
+    ret = GST_FLOW_ERROR;
+    goto out;
+  }
+invalid_header:
+  {
+    GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Invalid wavpack header"));
+    ret = GST_FLOW_ERROR;
+    goto out;
+  }
+context_failed:
+  {
+    GST_AUDIO_DECODER_ERROR (bdec, 1, LIBRARY, INIT, (NULL),
+        ("error creating Wavpack context"), ret);
+    goto out;
+  }
+decode_error:
+  {
+    const gchar *reason = "unknown";
+
+    if (dec->context) {
+      reason = WavpackGetErrorMessage (dec->context);
+    } else {
+      reason = "couldn't create decoder context";
+    }
+    GST_AUDIO_DECODER_ERROR (bdec, 1, STREAM, DECODE, (NULL),
+        ("decoding error: %s", reason), ret);
+    g_free (dec_data);
+    if (ret == GST_FLOW_OK)
+      gst_audio_decoder_finish_frame (bdec, NULL, 1);
+    goto out;
+  }
+}
+
+gboolean
+gst_wavpack_dec_plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "wavpackdec",
+          GST_RANK_PRIMARY, GST_TYPE_WAVPACK_DEC))
+    return FALSE;
+  GST_DEBUG_CATEGORY_INIT (gst_wavpack_dec_debug, "wavpackdec", 0,
+      "Wavpack decoder");
+  return TRUE;
+}
diff --git a/ext/wavpack/gstwavpackdec.h b/ext/wavpack/gstwavpackdec.h
new file mode 100644
index 0000000..8a002b4
--- /dev/null
+++ b/ext/wavpack/gstwavpackdec.h
@@ -0,0 +1,78 @@
+/* GStreamer Wavpack plugin
+ * Copyright (c) 2004 Arwed v. Merkatz <v.merkatz@gmx.net>
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackdec.h: raw Wavpack bitstream decoder
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_WAVPACK_DEC_H__
+#define __GST_WAVPACK_DEC_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiodecoder.h>
+
+#include <wavpack/wavpack.h>
+
+#include "gstwavpackstreamreader.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_WAVPACK_DEC \
+  (gst_wavpack_dec_get_type())
+#define GST_WAVPACK_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAVPACK_DEC,GstWavpackDec))
+#define GST_WAVPACK_DEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVPACK_DEC,GstWavpackDecClass))
+#define GST_IS_WAVPACK_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAVPACK_DEC))
+#define GST_IS_WAVPACK_DEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVPACK_DEC))
+typedef struct _GstWavpackDec GstWavpackDec;
+typedef struct _GstWavpackDecClass GstWavpackDecClass;
+
+struct _GstWavpackDec
+{
+  GstAudioDecoder element;
+
+  /*< private > */
+
+  WavpackContext *context;
+  WavpackStreamReader *stream_reader;
+
+  read_id wv_id;
+
+  gint sample_rate;
+  gint depth;
+  gint width;
+  gint channels;
+  gint channel_mask;
+
+  gint channel_reorder_map[64];
+
+};
+
+struct _GstWavpackDecClass
+{
+  GstAudioDecoderClass parent;
+};
+
+GType gst_wavpack_dec_get_type (void);
+
+gboolean gst_wavpack_dec_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_WAVPACK_DEC_H__ */
diff --git a/ext/wavpack/gstwavpackenc.c b/ext/wavpack/gstwavpackenc.c
new file mode 100644
index 0000000..5d6205c
--- /dev/null
+++ b/ext/wavpack/gstwavpackenc.c
@@ -0,0 +1,1005 @@
+/* GStreamer Wavpack encoder plugin
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackdec.c: Wavpack audio encoder
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-wavpackenc
+ *
+ * WavpackEnc encodes raw audio into a framed Wavpack stream.
+ * <ulink url="http://www.wavpack.com/">Wavpack</ulink> is an open-source
+ * audio codec that features both lossless and lossy encoding.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc num-buffers=500 ! audioconvert ! wavpackenc ! filesink location=sinewave.wv
+ * ]| This pipeline encodes audio from audiotestsrc into a Wavpack file. The audioconvert element is needed
+ * as the Wavpack encoder only accepts input with 32 bit width.
+ * |[
+ * gst-launch-1.0 cdda://1 ! audioconvert ! wavpackenc ! filesink location=track1.wv
+ * ]| This pipeline encodes audio from an audio CD into a Wavpack file using
+ * lossless encoding (the file output will be fairly large).
+ * |[
+ * gst-launch-1.0 cdda://1 ! audioconvert ! wavpackenc bitrate=128000 ! filesink location=track1.wv
+ * ]| This pipeline encodes audio from an audio CD into a Wavpack file using
+ * lossy encoding at a certain bitrate (the file will be fairly small).
+ * </refsect2>
+ */
+
+/*
+ * TODO: - add 32 bit float mode. CONFIG_FLOAT_DATA
+ */
+
+#include <string.h>
+#include <gst/gst.h>
+#include <glib/gprintf.h>
+
+#include <wavpack/wavpack.h>
+#include "gstwavpackenc.h"
+#include "gstwavpackcommon.h"
+
+static gboolean gst_wavpack_enc_start (GstAudioEncoder * enc);
+static gboolean gst_wavpack_enc_stop (GstAudioEncoder * enc);
+static gboolean gst_wavpack_enc_set_format (GstAudioEncoder * enc,
+    GstAudioInfo * info);
+static GstFlowReturn gst_wavpack_enc_handle_frame (GstAudioEncoder * enc,
+    GstBuffer * in_buf);
+static gboolean gst_wavpack_enc_sink_event (GstAudioEncoder * enc,
+    GstEvent * event);
+
+static int gst_wavpack_enc_push_block (void *id, void *data, int32_t count);
+static GstFlowReturn gst_wavpack_enc_drain (GstWavpackEnc * enc);
+
+static void gst_wavpack_enc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_wavpack_enc_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+enum
+{
+  ARG_0,
+  ARG_MODE,
+  ARG_BITRATE,
+  ARG_BITSPERSAMPLE,
+  ARG_CORRECTION_MODE,
+  ARG_MD5,
+  ARG_EXTRA_PROCESSING,
+  ARG_JOINT_STEREO_MODE
+};
+
+GST_DEBUG_CATEGORY_STATIC (gst_wavpack_enc_debug);
+#define GST_CAT_DEFAULT gst_wavpack_enc_debug
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (S32) ", "
+        "layout = (string) interleaved, "
+        "channels = (int) [ 1, 8 ], " "rate = (int) [ 6000, 192000 ]")
+    );
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-wavpack, "
+        "depth = (int) [ 1, 32 ], "
+        "channels = (int) [ 1, 8 ], "
+        "rate = (int) [ 6000, 192000 ], " "framed = (boolean) TRUE")
+    );
+
+static GstStaticPadTemplate wvcsrc_factory = GST_STATIC_PAD_TEMPLATE ("wvcsrc",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("audio/x-wavpack-correction, " "framed = (boolean) TRUE")
+    );
+
+enum
+{
+  GST_WAVPACK_ENC_MODE_VERY_FAST = 0,
+  GST_WAVPACK_ENC_MODE_FAST,
+  GST_WAVPACK_ENC_MODE_DEFAULT,
+  GST_WAVPACK_ENC_MODE_HIGH,
+  GST_WAVPACK_ENC_MODE_VERY_HIGH
+};
+
+#define GST_TYPE_WAVPACK_ENC_MODE (gst_wavpack_enc_mode_get_type ())
+static GType
+gst_wavpack_enc_mode_get_type (void)
+{
+  static GType qtype = 0;
+
+  if (qtype == 0) {
+    static const GEnumValue values[] = {
+#if 0
+      /* Very Fast Compression is not supported yet, but will be supported
+       * in future wavpack versions */
+      {GST_WAVPACK_ENC_MODE_VERY_FAST, "Very Fast Compression", "veryfast"},
+#endif
+      {GST_WAVPACK_ENC_MODE_FAST, "Fast Compression", "fast"},
+      {GST_WAVPACK_ENC_MODE_DEFAULT, "Normal Compression", "normal"},
+      {GST_WAVPACK_ENC_MODE_HIGH, "High Compression", "high"},
+      {GST_WAVPACK_ENC_MODE_VERY_HIGH, "Very High Compression", "veryhigh"},
+      {0, NULL, NULL}
+    };
+
+    qtype = g_enum_register_static ("GstWavpackEncMode", values);
+  }
+  return qtype;
+}
+
+enum
+{
+  GST_WAVPACK_CORRECTION_MODE_OFF = 0,
+  GST_WAVPACK_CORRECTION_MODE_ON,
+  GST_WAVPACK_CORRECTION_MODE_OPTIMIZED
+};
+
+#define GST_TYPE_WAVPACK_ENC_CORRECTION_MODE (gst_wavpack_enc_correction_mode_get_type ())
+static GType
+gst_wavpack_enc_correction_mode_get_type (void)
+{
+  static GType qtype = 0;
+
+  if (qtype == 0) {
+    static const GEnumValue values[] = {
+      {GST_WAVPACK_CORRECTION_MODE_OFF, "Create no correction file", "off"},
+      {GST_WAVPACK_CORRECTION_MODE_ON, "Create correction file", "on"},
+      {GST_WAVPACK_CORRECTION_MODE_OPTIMIZED,
+          "Create optimized correction file", "optimized"},
+      {0, NULL, NULL}
+    };
+
+    qtype = g_enum_register_static ("GstWavpackEncCorrectionMode", values);
+  }
+  return qtype;
+}
+
+enum
+{
+  GST_WAVPACK_JS_MODE_AUTO = 0,
+  GST_WAVPACK_JS_MODE_LEFT_RIGHT,
+  GST_WAVPACK_JS_MODE_MID_SIDE
+};
+
+#define GST_TYPE_WAVPACK_ENC_JOINT_STEREO_MODE (gst_wavpack_enc_joint_stereo_mode_get_type ())
+static GType
+gst_wavpack_enc_joint_stereo_mode_get_type (void)
+{
+  static GType qtype = 0;
+
+  if (qtype == 0) {
+    static const GEnumValue values[] = {
+      {GST_WAVPACK_JS_MODE_AUTO, "auto", "auto"},
+      {GST_WAVPACK_JS_MODE_LEFT_RIGHT, "left/right", "leftright"},
+      {GST_WAVPACK_JS_MODE_MID_SIDE, "mid/side", "midside"},
+      {0, NULL, NULL}
+    };
+
+    qtype = g_enum_register_static ("GstWavpackEncJSMode", values);
+  }
+  return qtype;
+}
+
+#define gst_wavpack_enc_parent_class parent_class
+G_DEFINE_TYPE (GstWavpackEnc, gst_wavpack_enc, GST_TYPE_AUDIO_ENCODER);
+
+static void
+gst_wavpack_enc_class_init (GstWavpackEncClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *element_class = (GstElementClass *) (klass);
+  GstAudioEncoderClass *base_class = (GstAudioEncoderClass *) (klass);
+
+  /* add pad templates */
+  gst_element_class_add_static_pad_template (element_class, &sink_factory);
+  gst_element_class_add_static_pad_template (element_class, &src_factory);
+  gst_element_class_add_static_pad_template (element_class, &wvcsrc_factory);
+
+  /* set element details */
+  gst_element_class_set_static_metadata (element_class, "Wavpack audio encoder",
+      "Codec/Encoder/Audio",
+      "Encodes audio with the Wavpack lossless/lossy audio codec",
+      "Sebastian Dröge <slomo@circular-chaos.org>");
+
+  /* set property handlers */
+  gobject_class->set_property = gst_wavpack_enc_set_property;
+  gobject_class->get_property = gst_wavpack_enc_get_property;
+
+  base_class->start = GST_DEBUG_FUNCPTR (gst_wavpack_enc_start);
+  base_class->stop = GST_DEBUG_FUNCPTR (gst_wavpack_enc_stop);
+  base_class->set_format = GST_DEBUG_FUNCPTR (gst_wavpack_enc_set_format);
+  base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_wavpack_enc_handle_frame);
+  base_class->sink_event = GST_DEBUG_FUNCPTR (gst_wavpack_enc_sink_event);
+
+  /* install all properties */
+  g_object_class_install_property (gobject_class, ARG_MODE,
+      g_param_spec_enum ("mode", "Encoding mode",
+          "Speed versus compression tradeoff.",
+          GST_TYPE_WAVPACK_ENC_MODE, GST_WAVPACK_ENC_MODE_DEFAULT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, ARG_BITRATE,
+      g_param_spec_uint ("bitrate", "Bitrate",
+          "Try to encode with this average bitrate (bits/sec). "
+          "This enables lossy encoding, values smaller than 24000 disable it again.",
+          0, 9600000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, ARG_BITSPERSAMPLE,
+      g_param_spec_double ("bits-per-sample", "Bits per sample",
+          "Try to encode with this amount of bits per sample. "
+          "This enables lossy encoding, values smaller than 2.0 disable it again.",
+          0.0, 24.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, ARG_CORRECTION_MODE,
+      g_param_spec_enum ("correction-mode", "Correction stream mode",
+          "Use this mode for the correction stream. Only works in lossy mode!",
+          GST_TYPE_WAVPACK_ENC_CORRECTION_MODE, GST_WAVPACK_CORRECTION_MODE_OFF,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, ARG_MD5,
+      g_param_spec_boolean ("md5", "MD5",
+          "Store MD5 hash of raw samples within the file.", FALSE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, ARG_EXTRA_PROCESSING,
+      g_param_spec_uint ("extra-processing", "Extra processing",
+          "Use better but slower filters for better compression/quality.",
+          0, 6, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, ARG_JOINT_STEREO_MODE,
+      g_param_spec_enum ("joint-stereo-mode", "Joint-Stereo mode",
+          "Use this joint-stereo mode.", GST_TYPE_WAVPACK_ENC_JOINT_STEREO_MODE,
+          GST_WAVPACK_JS_MODE_AUTO,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_wavpack_enc_reset (GstWavpackEnc * enc)
+{
+  /* close and free everything stream related if we already did something */
+  if (enc->wp_context) {
+    WavpackCloseFile (enc->wp_context);
+    enc->wp_context = NULL;
+  }
+  if (enc->wp_config) {
+    g_free (enc->wp_config);
+    enc->wp_config = NULL;
+  }
+  if (enc->first_block) {
+    g_free (enc->first_block);
+    enc->first_block = NULL;
+  }
+  enc->first_block_size = 0;
+  if (enc->md5_context) {
+    g_checksum_free (enc->md5_context);
+    enc->md5_context = NULL;
+  }
+  if (enc->pending_segment)
+    gst_event_unref (enc->pending_segment);
+  enc->pending_segment = NULL;
+
+  if (enc->pending_buffer) {
+    gst_buffer_unref (enc->pending_buffer);
+    enc->pending_buffer = NULL;
+    enc->pending_offset = 0;
+  }
+
+  /* reset the last returns to GST_FLOW_OK. This is only set to something else
+   * while WavpackPackSamples() or more specific gst_wavpack_enc_push_block()
+   * so not valid anymore */
+  enc->srcpad_last_return = enc->wvcsrcpad_last_return = GST_FLOW_OK;
+
+  /* reset stream information */
+  enc->samplerate = 0;
+  enc->depth = 0;
+  enc->channels = 0;
+  enc->channel_mask = 0;
+  enc->need_channel_remap = FALSE;
+
+  enc->timestamp_offset = GST_CLOCK_TIME_NONE;
+  enc->next_ts = GST_CLOCK_TIME_NONE;
+}
+
+static void
+gst_wavpack_enc_init (GstWavpackEnc * enc)
+{
+  GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
+
+  /* initialize object attributes */
+  enc->wp_config = NULL;
+  enc->wp_context = NULL;
+  enc->first_block = NULL;
+  enc->md5_context = NULL;
+  gst_wavpack_enc_reset (enc);
+
+  enc->wv_id.correction = FALSE;
+  enc->wv_id.wavpack_enc = enc;
+  enc->wv_id.passthrough = FALSE;
+  enc->wvc_id.correction = TRUE;
+  enc->wvc_id.wavpack_enc = enc;
+  enc->wvc_id.passthrough = FALSE;
+
+  /* set default values of params */
+  enc->mode = GST_WAVPACK_ENC_MODE_DEFAULT;
+  enc->bitrate = 0;
+  enc->bps = 0.0;
+  enc->correction_mode = GST_WAVPACK_CORRECTION_MODE_OFF;
+  enc->md5 = FALSE;
+  enc->extra_processing = 0;
+  enc->joint_stereo_mode = GST_WAVPACK_JS_MODE_AUTO;
+
+  /* require perfect ts */
+  gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
+
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (enc));
+}
+
+
+static gboolean
+gst_wavpack_enc_start (GstAudioEncoder * enc)
+{
+  GST_DEBUG_OBJECT (enc, "start");
+
+  return TRUE;
+}
+
+static gboolean
+gst_wavpack_enc_stop (GstAudioEncoder * enc)
+{
+  GstWavpackEnc *wpenc = GST_WAVPACK_ENC (enc);
+
+  GST_DEBUG_OBJECT (enc, "stop");
+  gst_wavpack_enc_reset (wpenc);
+
+  return TRUE;
+}
+
+static gboolean
+gst_wavpack_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
+{
+  GstWavpackEnc *enc = GST_WAVPACK_ENC (benc);
+  GstAudioChannelPosition *pos;
+  GstAudioChannelPosition opos[64] = { GST_AUDIO_CHANNEL_POSITION_INVALID, };
+  GstCaps *caps;
+  guint64 mask = 0;
+
+  /* we may be configured again, but that change should have cleanup context */
+  g_assert (enc->wp_context == NULL);
+
+  enc->channels = GST_AUDIO_INFO_CHANNELS (info);
+  enc->depth = GST_AUDIO_INFO_DEPTH (info);
+  enc->samplerate = GST_AUDIO_INFO_RATE (info);
+
+  pos = info->position;
+  g_assert (pos);
+
+  /* If one channel is NONE they'll be all undefined */
+  if (pos != NULL && pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE) {
+    goto invalid_channels;
+  }
+
+  enc->channel_mask =
+      gst_wavpack_get_channel_mask_from_positions (pos, enc->channels);
+  enc->need_channel_remap =
+      gst_wavpack_set_channel_mapping (pos, enc->channels,
+      enc->channel_mapping);
+
+  /* wavpack caps hold gst mask, not wavpack mask */
+  gst_audio_channel_positions_to_mask (opos, enc->channels, FALSE, &mask);
+
+  /* set fixed src pad caps now that we know what we will get */
+  caps = gst_caps_new_simple ("audio/x-wavpack",
+      "channels", G_TYPE_INT, enc->channels,
+      "rate", G_TYPE_INT, enc->samplerate,
+      "depth", G_TYPE_INT, enc->depth, "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+
+  if (mask)
+    gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, mask, NULL);
+
+  if (!gst_audio_encoder_set_output_format (benc, caps))
+    goto setting_src_caps_failed;
+
+  gst_caps_unref (caps);
+
+  /* no special feedback to base class; should provide all available samples */
+
+  return TRUE;
+
+  /* ERRORS */
+setting_src_caps_failed:
+  {
+    GST_DEBUG_OBJECT (enc,
+        "Couldn't set caps on source pad: %" GST_PTR_FORMAT, caps);
+    gst_caps_unref (caps);
+    return FALSE;
+  }
+invalid_channels:
+  {
+    GST_DEBUG_OBJECT (enc, "input has invalid channel layout");
+    return FALSE;
+  }
+}
+
+static void
+gst_wavpack_enc_set_wp_config (GstWavpackEnc * enc)
+{
+  enc->wp_config = g_new0 (WavpackConfig, 1);
+  /* set general stream informations in the WavpackConfig */
+  enc->wp_config->bytes_per_sample = GST_ROUND_UP_8 (enc->depth) / 8;
+  enc->wp_config->bits_per_sample = enc->depth;
+  enc->wp_config->num_channels = enc->channels;
+  enc->wp_config->channel_mask = enc->channel_mask;
+  enc->wp_config->sample_rate = enc->samplerate;
+
+  /*
+   * Set parameters in WavpackConfig
+   */
+
+  /* Encoding mode */
+  switch (enc->mode) {
+#if 0
+    case GST_WAVPACK_ENC_MODE_VERY_FAST:
+      enc->wp_config->flags |= CONFIG_VERY_FAST_FLAG;
+      enc->wp_config->flags |= CONFIG_FAST_FLAG;
+      break;
+#endif
+    case GST_WAVPACK_ENC_MODE_FAST:
+      enc->wp_config->flags |= CONFIG_FAST_FLAG;
+      break;
+    case GST_WAVPACK_ENC_MODE_DEFAULT:
+      break;
+    case GST_WAVPACK_ENC_MODE_HIGH:
+      enc->wp_config->flags |= CONFIG_HIGH_FLAG;
+      break;
+    case GST_WAVPACK_ENC_MODE_VERY_HIGH:
+      enc->wp_config->flags |= CONFIG_HIGH_FLAG;
+      enc->wp_config->flags |= CONFIG_VERY_HIGH_FLAG;
+      break;
+  }
+
+  /* Bitrate, enables lossy mode */
+  if (enc->bitrate) {
+    enc->wp_config->flags |= CONFIG_HYBRID_FLAG;
+    enc->wp_config->flags |= CONFIG_BITRATE_KBPS;
+    enc->wp_config->bitrate = enc->bitrate / 1000.0;
+  } else if (enc->bps) {
+    enc->wp_config->flags |= CONFIG_HYBRID_FLAG;
+    enc->wp_config->bitrate = enc->bps;
+  }
+
+  /* Correction Mode, only in lossy mode */
+  if (enc->wp_config->flags & CONFIG_HYBRID_FLAG) {
+    if (enc->correction_mode > GST_WAVPACK_CORRECTION_MODE_OFF) {
+      GstCaps *caps = gst_caps_new_simple ("audio/x-wavpack-correction",
+          "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+
+      enc->wvcsrcpad =
+          gst_pad_new_from_static_template (&wvcsrc_factory, "wvcsrc");
+
+      /* try to add correction src pad, don't set correction mode on failure */
+      GST_DEBUG_OBJECT (enc, "Adding correction pad with caps %"
+          GST_PTR_FORMAT, caps);
+      if (!gst_pad_set_caps (enc->wvcsrcpad, caps)) {
+        enc->correction_mode = 0;
+        GST_WARNING_OBJECT (enc, "setting correction caps failed");
+      } else {
+        gst_pad_use_fixed_caps (enc->wvcsrcpad);
+        gst_pad_set_active (enc->wvcsrcpad, TRUE);
+        gst_element_add_pad (GST_ELEMENT (enc), enc->wvcsrcpad);
+        enc->wp_config->flags |= CONFIG_CREATE_WVC;
+        if (enc->correction_mode == GST_WAVPACK_CORRECTION_MODE_OPTIMIZED) {
+          enc->wp_config->flags |= CONFIG_OPTIMIZE_WVC;
+        }
+      }
+      gst_caps_unref (caps);
+    }
+  } else {
+    if (enc->correction_mode > GST_WAVPACK_CORRECTION_MODE_OFF) {
+      enc->correction_mode = 0;
+      GST_WARNING_OBJECT (enc, "setting correction mode only has "
+          "any effect if a bitrate is provided.");
+    }
+  }
+  gst_element_no_more_pads (GST_ELEMENT (enc));
+
+  /* MD5, setup MD5 context */
+  if ((enc->md5) && !(enc->md5_context)) {
+    enc->wp_config->flags |= CONFIG_MD5_CHECKSUM;
+    enc->md5_context = g_checksum_new (G_CHECKSUM_MD5);
+  }
+
+  /* Extra encode processing */
+  if (enc->extra_processing) {
+    enc->wp_config->flags |= CONFIG_EXTRA_MODE;
+    enc->wp_config->xmode = enc->extra_processing;
+  }
+
+  /* Joint stereo mode */
+  switch (enc->joint_stereo_mode) {
+    case GST_WAVPACK_JS_MODE_AUTO:
+      break;
+    case GST_WAVPACK_JS_MODE_LEFT_RIGHT:
+      enc->wp_config->flags |= CONFIG_JOINT_OVERRIDE;
+      enc->wp_config->flags &= ~CONFIG_JOINT_STEREO;
+      break;
+    case GST_WAVPACK_JS_MODE_MID_SIDE:
+      enc->wp_config->flags |= (CONFIG_JOINT_OVERRIDE | CONFIG_JOINT_STEREO);
+      break;
+  }
+}
+
+static int
+gst_wavpack_enc_push_block (void *id, void *data, int32_t count)
+{
+  GstWavpackEncWriteID *wid = (GstWavpackEncWriteID *) id;
+  GstWavpackEnc *enc = GST_WAVPACK_ENC (wid->wavpack_enc);
+  GstFlowReturn *flow;
+  GstBuffer *buffer;
+  GstPad *pad;
+  guchar *block = (guchar *) data;
+  gint samples = 0;
+
+  pad = (wid->correction) ? enc->wvcsrcpad : GST_AUDIO_ENCODER_SRC_PAD (enc);
+  flow =
+      (wid->correction) ? &enc->
+      wvcsrcpad_last_return : &enc->srcpad_last_return;
+
+  buffer = gst_buffer_new_and_alloc (count);
+  gst_buffer_fill (buffer, 0, data, count);
+
+  if (count > sizeof (WavpackHeader) && memcmp (block, "wvpk", 4) == 0) {
+    /* if it's a Wavpack block set buffer timestamp and duration, etc */
+    WavpackHeader wph;
+
+    GST_LOG_OBJECT (enc, "got %d bytes of encoded wavpack %sdata",
+        count, (wid->correction) ? "correction " : "");
+
+    gst_wavpack_read_header (&wph, block);
+
+    /* Only set when pushing the first buffer again, in that case
+     * we don't want to delay the buffer or push newsegment events
+     */
+    if (!wid->passthrough) {
+      /* Only push complete blocks */
+      if (enc->pending_buffer == NULL) {
+        enc->pending_buffer = buffer;
+        enc->pending_offset = wph.block_index;
+      } else if (enc->pending_offset == wph.block_index) {
+        enc->pending_buffer = gst_buffer_append (enc->pending_buffer, buffer);
+      } else {
+        GST_ERROR ("Got incomplete block, dropping");
+        gst_buffer_unref (enc->pending_buffer);
+        enc->pending_buffer = buffer;
+        enc->pending_offset = wph.block_index;
+      }
+
+      /* Is this the not-final block of multi-channel data? If so, just
+       * accumulate and return here. */
+      if (!(wph.flags & FINAL_BLOCK) && ((block[32] & ID_OPTIONAL_DATA) == 0))
+        return TRUE;
+
+      buffer = enc->pending_buffer;
+      enc->pending_buffer = NULL;
+      enc->pending_offset = 0;
+
+      /* only send segment on correction pad,
+       * regular pad is handled normally by baseclass */
+      if (wid->correction && enc->pending_segment) {
+        gst_pad_push_event (pad, enc->pending_segment);
+        enc->pending_segment = NULL;
+      }
+
+      if (wph.block_index == 0) {
+        /* save header for later reference, so we can re-send it later on
+         * EOS with fixed up values for total sample count etc. */
+        if (enc->first_block == NULL && !wid->correction) {
+          GstMapInfo map;
+
+          gst_buffer_map (buffer, &map, GST_MAP_READ);
+          enc->first_block = g_memdup (map.data, map.size);
+          enc->first_block_size = map.size;
+          gst_buffer_unmap (buffer, &map);
+        }
+      }
+    }
+    samples = wph.block_samples;
+
+    /* decorate buffer */
+    /* NOTE: this will get overwritten by baseclass, but stay for those
+     * that are pushed directly
+     * FIXME: add setting to baseclass to avoid overwriting it ?? */
+    GST_BUFFER_OFFSET (buffer) = wph.block_index;
+    GST_BUFFER_OFFSET_END (buffer) = wph.block_index + wph.block_samples;
+  } else {
+    /* if it's something else set no timestamp and duration on the buffer */
+    GST_DEBUG_OBJECT (enc, "got %d bytes of unknown data", count);
+  }
+
+  if (wid->correction || wid->passthrough) {
+    /* push the buffer and forward errors */
+    GST_DEBUG_OBJECT (enc, "pushing buffer with %" G_GSIZE_FORMAT " bytes",
+        gst_buffer_get_size (buffer));
+    *flow = gst_pad_push (pad, buffer);
+  } else {
+    GST_DEBUG_OBJECT (enc, "handing frame of %" G_GSIZE_FORMAT " bytes",
+        gst_buffer_get_size (buffer));
+    *flow = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc), buffer,
+        samples);
+  }
+
+  if (*flow != GST_FLOW_OK) {
+    GST_WARNING_OBJECT (enc, "flow on %s:%s = %s",
+        GST_DEBUG_PAD_NAME (pad), gst_flow_get_name (*flow));
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static void
+gst_wavpack_enc_fix_channel_order (GstWavpackEnc * enc, gint32 * data,
+    gint nsamples)
+{
+  gint i, j;
+  gint32 tmp[8];
+
+  for (i = 0; i < nsamples / enc->channels; i++) {
+    for (j = 0; j < enc->channels; j++) {
+      tmp[enc->channel_mapping[j]] = data[j];
+    }
+    for (j = 0; j < enc->channels; j++) {
+      data[j] = tmp[j];
+    }
+    data += enc->channels;
+  }
+}
+
+static GstFlowReturn
+gst_wavpack_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
+{
+  GstWavpackEnc *enc = GST_WAVPACK_ENC (benc);
+  uint32_t sample_count;
+  GstFlowReturn ret;
+  GstMapInfo map;
+
+  /* base class ensures configuration */
+  g_return_val_if_fail (enc->depth != 0, GST_FLOW_NOT_NEGOTIATED);
+
+  /* reset the last returns to GST_FLOW_OK. This is only set to something else
+   * while WavpackPackSamples() or more specific gst_wavpack_enc_push_block()
+   * so not valid anymore */
+  enc->srcpad_last_return = enc->wvcsrcpad_last_return = GST_FLOW_OK;
+
+  if (G_UNLIKELY (!buf))
+    return gst_wavpack_enc_drain (enc);
+
+  sample_count = gst_buffer_get_size (buf) / 4;
+  GST_DEBUG_OBJECT (enc, "got %u raw samples", sample_count);
+
+  /* check if we already have a valid WavpackContext, otherwise make one */
+  if (!enc->wp_context) {
+    /* create raw context */
+    enc->wp_context =
+        WavpackOpenFileOutput (gst_wavpack_enc_push_block, &enc->wv_id,
+        (enc->correction_mode > 0) ? &enc->wvc_id : NULL);
+    if (!enc->wp_context)
+      goto context_failed;
+
+    /* set the WavpackConfig according to our parameters */
+    gst_wavpack_enc_set_wp_config (enc);
+
+    /* set the configuration to the context now that we know everything
+     * and initialize the encoder */
+    if (!WavpackSetConfiguration (enc->wp_context,
+            enc->wp_config, (uint32_t) (-1))
+        || !WavpackPackInit (enc->wp_context)) {
+      WavpackCloseFile (enc->wp_context);
+      goto config_failed;
+    }
+    GST_DEBUG_OBJECT (enc, "setup of encoding context successfull");
+  }
+
+  if (enc->need_channel_remap) {
+    buf = gst_buffer_make_writable (buf);
+    gst_buffer_map (buf, &map, GST_MAP_WRITE);
+    gst_wavpack_enc_fix_channel_order (enc, (gint32 *) map.data, sample_count);
+    gst_buffer_unmap (buf, &map);
+  }
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  /* if we want to append the MD5 sum to the stream update it here
+   * with the current raw samples */
+  if (enc->md5) {
+    g_checksum_update (enc->md5_context, map.data, map.size);
+  }
+
+  /* encode and handle return values from encoding */
+  if (WavpackPackSamples (enc->wp_context, (int32_t *) map.data,
+          sample_count / enc->channels)) {
+    GST_DEBUG_OBJECT (enc, "encoding samples successful");
+    gst_buffer_unmap (buf, &map);
+    ret = GST_FLOW_OK;
+  } else {
+    gst_buffer_unmap (buf, &map);
+    if ((enc->srcpad_last_return == GST_FLOW_OK) ||
+        (enc->wvcsrcpad_last_return == GST_FLOW_OK)) {
+      ret = GST_FLOW_OK;
+    } else if ((enc->srcpad_last_return == GST_FLOW_NOT_LINKED) &&
+        (enc->wvcsrcpad_last_return == GST_FLOW_NOT_LINKED)) {
+      ret = GST_FLOW_NOT_LINKED;
+    } else if ((enc->srcpad_last_return == GST_FLOW_FLUSHING) &&
+        (enc->wvcsrcpad_last_return == GST_FLOW_FLUSHING)) {
+      ret = GST_FLOW_FLUSHING;
+    } else {
+      goto encoding_failed;
+    }
+  }
+
+exit:
+  return ret;
+
+  /* ERRORS */
+encoding_failed:
+  {
+    GST_ELEMENT_ERROR (enc, LIBRARY, ENCODE, (NULL),
+        ("encoding samples failed"));
+    ret = GST_FLOW_ERROR;
+    goto exit;
+  }
+config_failed:
+  {
+    GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL),
+        ("error setting up wavpack encoding context"));
+    ret = GST_FLOW_ERROR;
+    goto exit;
+  }
+context_failed:
+  {
+    GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL),
+        ("error creating Wavpack context"));
+    ret = GST_FLOW_ERROR;
+    goto exit;
+  }
+}
+
+static void
+gst_wavpack_enc_rewrite_first_block (GstWavpackEnc * enc)
+{
+  GstSegment segment;
+  gboolean ret;
+  GstQuery *query;
+  gboolean seekable = FALSE;
+
+  g_return_if_fail (enc);
+  g_return_if_fail (enc->first_block);
+
+  /* update the sample count in the first block */
+  WavpackUpdateNumSamples (enc->wp_context, enc->first_block);
+
+  /* try to seek to the beginning of the output */
+  query = gst_query_new_seeking (GST_FORMAT_BYTES);
+  if (gst_pad_peer_query (GST_AUDIO_ENCODER_SRC_PAD (enc), query)) {
+    GstFormat format;
+
+    gst_query_parse_seeking (query, &format, &seekable, NULL, NULL);
+    if (format != GST_FORMAT_BYTES)
+      seekable = FALSE;
+  } else {
+    GST_LOG_OBJECT (enc, "SEEKING query not handled");
+  }
+  gst_query_unref (query);
+
+  if (!seekable) {
+    GST_DEBUG_OBJECT (enc, "downstream not seekable; not rewriting");
+    return;
+  }
+
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  ret = gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (enc),
+      gst_event_new_segment (&segment));
+  if (ret) {
+    /* try to rewrite the first block */
+    GST_DEBUG_OBJECT (enc, "rewriting first block ...");
+    enc->wv_id.passthrough = TRUE;
+    ret = gst_wavpack_enc_push_block (&enc->wv_id,
+        enc->first_block, enc->first_block_size);
+    enc->wv_id.passthrough = FALSE;
+    g_free (enc->first_block);
+    enc->first_block = NULL;
+  } else {
+    GST_WARNING_OBJECT (enc, "rewriting of first block failed. "
+        "Seeking to first block failed!");
+  }
+}
+
+static GstFlowReturn
+gst_wavpack_enc_drain (GstWavpackEnc * enc)
+{
+  if (!enc->wp_context)
+    return GST_FLOW_OK;
+
+  GST_DEBUG_OBJECT (enc, "draining");
+
+  /* Encode all remaining samples and flush them to the src pads */
+  WavpackFlushSamples (enc->wp_context);
+
+  /* Drop all remaining data, this is no complete block otherwise
+   * it would've been pushed already */
+  if (enc->pending_buffer) {
+    gst_buffer_unref (enc->pending_buffer);
+    enc->pending_buffer = NULL;
+    enc->pending_offset = 0;
+  }
+
+  /* write the MD5 sum if we have to write one */
+  if ((enc->md5) && (enc->md5_context)) {
+    guint8 md5_digest[16];
+    gsize digest_len = sizeof (md5_digest);
+
+    g_checksum_get_digest (enc->md5_context, md5_digest, &digest_len);
+    if (digest_len == sizeof (md5_digest)) {
+      WavpackStoreMD5Sum (enc->wp_context, md5_digest);
+      WavpackFlushSamples (enc->wp_context);
+    } else
+      GST_WARNING_OBJECT (enc, "Calculating MD5 digest failed");
+  }
+
+  /* Try to rewrite the first frame with the correct sample number */
+  if (enc->first_block)
+    gst_wavpack_enc_rewrite_first_block (enc);
+
+  /* close the context if not already happened */
+  if (enc->wp_context) {
+    WavpackCloseFile (enc->wp_context);
+    enc->wp_context = NULL;
+  }
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_wavpack_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
+{
+  GstWavpackEnc *enc = GST_WAVPACK_ENC (benc);
+
+  GST_DEBUG_OBJECT (enc, "Received %s event on sinkpad",
+      GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEGMENT:
+      if (enc->wp_context) {
+        GST_WARNING_OBJECT (enc, "got NEWSEGMENT after encoding "
+            "already started");
+      }
+      /* peek and hold NEWSEGMENT events for sending on correction pad */
+      if (enc->pending_segment)
+        gst_event_unref (enc->pending_segment);
+      enc->pending_segment = gst_event_ref (event);
+      break;
+    default:
+      break;
+  }
+
+  /* baseclass handles rest */
+  return GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (benc, event);
+}
+
+static void
+gst_wavpack_enc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstWavpackEnc *enc = GST_WAVPACK_ENC (object);
+
+  switch (prop_id) {
+    case ARG_MODE:
+      enc->mode = g_value_get_enum (value);
+      break;
+    case ARG_BITRATE:{
+      guint val = g_value_get_uint (value);
+
+      if ((val >= 24000) && (val <= 9600000)) {
+        enc->bitrate = val;
+        enc->bps = 0.0;
+      } else {
+        enc->bitrate = 0;
+        enc->bps = 0.0;
+      }
+      break;
+    }
+    case ARG_BITSPERSAMPLE:{
+      gdouble val = g_value_get_double (value);
+
+      if ((val >= 2.0) && (val <= 24.0)) {
+        enc->bps = val;
+        enc->bitrate = 0;
+      } else {
+        enc->bps = 0.0;
+        enc->bitrate = 0;
+      }
+      break;
+    }
+    case ARG_CORRECTION_MODE:
+      enc->correction_mode = g_value_get_enum (value);
+      break;
+    case ARG_MD5:
+      enc->md5 = g_value_get_boolean (value);
+      break;
+    case ARG_EXTRA_PROCESSING:
+      enc->extra_processing = g_value_get_uint (value);
+      break;
+    case ARG_JOINT_STEREO_MODE:
+      enc->joint_stereo_mode = g_value_get_enum (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_wavpack_enc_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstWavpackEnc *enc = GST_WAVPACK_ENC (object);
+
+  switch (prop_id) {
+    case ARG_MODE:
+      g_value_set_enum (value, enc->mode);
+      break;
+    case ARG_BITRATE:
+      if (enc->bps == 0.0) {
+        g_value_set_uint (value, enc->bitrate);
+      } else {
+        g_value_set_uint (value, 0);
+      }
+      break;
+    case ARG_BITSPERSAMPLE:
+      if (enc->bitrate == 0) {
+        g_value_set_double (value, enc->bps);
+      } else {
+        g_value_set_double (value, 0.0);
+      }
+      break;
+    case ARG_CORRECTION_MODE:
+      g_value_set_enum (value, enc->correction_mode);
+      break;
+    case ARG_MD5:
+      g_value_set_boolean (value, enc->md5);
+      break;
+    case ARG_EXTRA_PROCESSING:
+      g_value_set_uint (value, enc->extra_processing);
+      break;
+    case ARG_JOINT_STEREO_MODE:
+      g_value_set_enum (value, enc->joint_stereo_mode);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+gboolean
+gst_wavpack_enc_plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "wavpackenc",
+          GST_RANK_NONE, GST_TYPE_WAVPACK_ENC))
+    return FALSE;
+
+  GST_DEBUG_CATEGORY_INIT (gst_wavpack_enc_debug, "wavpackenc", 0,
+      "Wavpack encoder");
+
+  return TRUE;
+}
diff --git a/ext/wavpack/gstwavpackenc.h b/ext/wavpack/gstwavpackenc.h
new file mode 100644
index 0000000..26a5b11
--- /dev/null
+++ b/ext/wavpack/gstwavpackenc.h
@@ -0,0 +1,105 @@
+/* GStreamer Wavpack encoder plugin
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackenc.h: Wavpack audio encoder
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_WAVPACK_ENC_H__
+#define __GST_WAVPACK_ENC_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudioencoder.h>
+
+#include <wavpack/wavpack.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_WAVPACK_ENC \
+  (gst_wavpack_enc_get_type())
+#define GST_WAVPACK_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAVPACK_ENC,GstWavpackEnc))
+#define GST_WAVPACK_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVPACK_ENC,GstWavpackEnc))
+#define GST_IS_WAVPACK_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAVPACK_ENC))
+#define GST_IS_WAVPACK_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVPACK_ENC))
+typedef struct _GstWavpackEnc GstWavpackEnc;
+typedef struct _GstWavpackEncClass GstWavpackEncClass;
+
+typedef struct
+{
+  gboolean correction;
+  GstWavpackEnc *wavpack_enc;
+  gboolean passthrough;
+} GstWavpackEncWriteID;
+
+
+struct _GstWavpackEnc
+{
+  GstAudioEncoder element;
+
+  /*< private > */
+  GstPad *wvcsrcpad;
+
+  GstFlowReturn srcpad_last_return;
+  GstFlowReturn wvcsrcpad_last_return;
+
+  WavpackConfig *wp_config;
+  WavpackContext *wp_context;
+
+  gint samplerate;
+  gint channels;
+  gint channel_mask;
+  gint8 channel_mapping[8];
+  gboolean need_channel_remap;
+  gint depth;
+
+  GstWavpackEncWriteID wv_id;
+  GstWavpackEncWriteID wvc_id;
+
+  guint mode;
+  guint bitrate;
+  gdouble bps;
+  guint correction_mode;
+  gboolean md5;
+  GChecksum *md5_context;
+  guint extra_processing;
+  guint joint_stereo_mode;
+
+  void *first_block;
+  int32_t first_block_size;
+
+  GstBuffer *pending_buffer;
+  gint32 pending_offset;
+  GstEvent *pending_segment;
+
+  GstClockTime timestamp_offset;
+  GstClockTime next_ts;
+};
+
+struct _GstWavpackEncClass
+{
+  GstAudioEncoderClass parent;
+};
+
+GType gst_wavpack_enc_get_type (void);
+
+gboolean gst_wavpack_enc_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_WAVPACK_ENC_H__ */
diff --git a/ext/wavpack/gstwavpackstreamreader.c b/ext/wavpack/gstwavpackstreamreader.c
new file mode 100644
index 0000000..dd29a37
--- /dev/null
+++ b/ext/wavpack/gstwavpackstreamreader.c
@@ -0,0 +1,125 @@
+/* GStreamer Wavpack plugin
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackstreamreader.c: stream reader used for decoding
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+#include <math.h>
+#include <gst/gst.h>
+
+#include "gstwavpackstreamreader.h"
+
+GST_DEBUG_CATEGORY_EXTERN (wavpack_debug);
+#define GST_CAT_DEFAULT wavpack_debug
+
+static int32_t
+gst_wavpack_stream_reader_read_bytes (void *id, void *data, int32_t bcount)
+{
+  read_id *rid = (read_id *) id;
+  uint32_t left = rid->length - rid->position;
+  uint32_t to_read = MIN (left, bcount);
+
+  GST_DEBUG ("Trying to read %d of %d bytes from position %d", bcount,
+      rid->length, rid->position);
+
+  if (to_read > 0) {
+    memmove (data, rid->buffer + rid->position, to_read);
+    rid->position += to_read;
+    return to_read;
+  } else {
+    GST_WARNING ("Couldn't read %d bytes", bcount);
+    return 0;
+  }
+}
+
+static uint32_t
+gst_wavpack_stream_reader_get_pos (void *id)
+{
+  GST_DEBUG ("Returning position %d", ((read_id *) id)->position);
+  return ((read_id *) id)->position;
+}
+
+static int
+gst_wavpack_stream_reader_set_pos_abs (void *id, uint32_t pos)
+{
+  GST_WARNING ("Should not be called: tried to set absolute position to %d",
+      pos);
+  return -1;
+}
+
+static int
+gst_wavpack_stream_reader_set_pos_rel (void *id, int32_t delta, int mode)
+{
+  GST_WARNING ("Should not be called: tried to set relative position to %d"
+      " with mode %d", delta, mode);
+  return -1;
+}
+
+static int
+gst_wavpack_stream_reader_push_back_byte (void *id, int c)
+{
+  read_id *rid = (read_id *) id;
+
+  GST_DEBUG ("Pushing back one byte: 0x%x", c);
+
+  if (rid->position == 0)
+    return rid->position;
+
+  rid->position -= 1;
+  return rid->position;
+}
+
+static uint32_t
+gst_wavpack_stream_reader_get_length (void *id)
+{
+  GST_DEBUG ("Returning length %d", ((read_id *) id)->length);
+
+  return ((read_id *) id)->length;
+}
+
+static int
+gst_wavpack_stream_reader_can_seek (void *id)
+{
+  GST_DEBUG ("Can't seek");
+  return FALSE;
+}
+
+static int32_t
+gst_wavpack_stream_reader_write_bytes (void *id, void *data, int32_t bcount)
+{
+  GST_WARNING ("Should not be called, tried to write %d bytes", bcount);
+  return 0;
+}
+
+WavpackStreamReader *
+gst_wavpack_stream_reader_new (void)
+{
+  WavpackStreamReader *stream_reader =
+      (WavpackStreamReader *) g_malloc0 (sizeof (WavpackStreamReader));
+  stream_reader->read_bytes = gst_wavpack_stream_reader_read_bytes;
+  stream_reader->get_pos = gst_wavpack_stream_reader_get_pos;
+  stream_reader->set_pos_abs = gst_wavpack_stream_reader_set_pos_abs;
+  stream_reader->set_pos_rel = gst_wavpack_stream_reader_set_pos_rel;
+  stream_reader->push_back_byte = gst_wavpack_stream_reader_push_back_byte;
+  stream_reader->get_length = gst_wavpack_stream_reader_get_length;
+  stream_reader->can_seek = gst_wavpack_stream_reader_can_seek;
+  stream_reader->write_bytes = gst_wavpack_stream_reader_write_bytes;
+
+  return stream_reader;
+}
diff --git a/ext/wavpack/gstwavpackstreamreader.h b/ext/wavpack/gstwavpackstreamreader.h
new file mode 100644
index 0000000..17412cc
--- /dev/null
+++ b/ext/wavpack/gstwavpackstreamreader.h
@@ -0,0 +1,36 @@
+/* GStreamer Wavpack plugin
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackstreamreader.h: stream reader used for decoding
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_WAVPACK_STREAM_READER_H__
+#define __GST_WAVPACK_STREAM_READER_H__
+
+#include <wavpack/wavpack.h>
+
+typedef struct
+{
+  guint8 *buffer;
+  uint32_t length;
+  uint32_t position;
+} read_id;
+
+WavpackStreamReader *gst_wavpack_stream_reader_new (void);
+
+#endif
diff --git a/ext/wavpack/meson.build b/ext/wavpack/meson.build
new file mode 100644
index 0000000..c4c9071
--- /dev/null
+++ b/ext/wavpack/meson.build
@@ -0,0 +1,21 @@
+wavpack_sources = [
+  'gstwavpack.c',
+  'gstwavpackcommon.c',
+  'gstwavpackdec.c',
+  'gstwavpackenc.c',
+  'gstwavpackstreamreader.c',
+]
+
+wavpack_dep = dependency('wavpack', version : '>= 4.60.0', required : false)
+
+if wavpack_dep.found()
+  gstwavpack = library('gstwavpack',
+    wavpack_sources,
+    c_args : gst_plugins_good_args,
+    link_args : noseh_link_args,
+    include_directories : [configinc, libsinc],
+    dependencies : [gstbase_dep, gstaudio_dep, wavpack_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/gst-libs/gst/gettext.h b/gst-libs/gst/gettext.h
new file mode 100644
index 0000000..fc70ab7
--- /dev/null
+++ b/gst-libs/gst/gettext.h
@@ -0,0 +1,69 @@
+/* Convenience header for conditional use of GNU <libintl.h>.
+   Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc.
+
+   This program 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, or (at your option)
+   any later version.
+
+   This program 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 program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
+   USA.  */
+
+#ifndef _LIBGETTEXT_H
+#define _LIBGETTEXT_H 1
+
+/* NLS can be disabled through the configure --disable-nls option.  */
+#ifdef ENABLE_NLS
+
+/* Get declarations of GNU message catalog functions.  */
+# include <libintl.h>
+
+#else
+
+/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
+   chokes if dcgettext is defined as a macro.  So include it now, to make
+   later inclusions of <locale.h> a NOP.  We don't include <libintl.h>
+   as well because people using "gettext.h" will not include <libintl.h>,
+   and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
+   is OK.  */
+#if defined(__sun)
+# include <locale.h>
+#endif
+
+/* Disabled NLS.
+   The casts to 'const char *' serve the purpose of producing warnings
+   for invalid uses of the value returned from these functions.
+   On pre-ANSI systems without 'const', the config.h file is supposed to
+   contain "#define const".  */
+# define gettext(Msgid) ((const char *) (Msgid))
+# define dgettext(Domainname, Msgid) ((const char *) (Msgid))
+# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
+# define ngettext(Msgid1, Msgid2, N) \
+    ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dngettext(Domainname, Msgid1, Msgid2, N) \
+    ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
+    ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define textdomain(Domainname) ((const char *) (Domainname))
+# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
+# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
+
+#endif
+
+/* A pseudo function call that serves as a marker for the automated
+   extraction of messages, but does not call gettext().  The run-time
+   translation is done at a different place in the code.
+   The argument, String, should be a literal string.  Concatenated strings
+   and other string expressions won't work.
+   The macro's expansion is not parenthesized, so that it is suitable as
+   initializer for static 'char[]' or 'const char[]' variables.  */
+#define gettext_noop(String) String
+
+#endif /* _LIBGETTEXT_H */
diff --git a/gst-libs/gst/glib-compat-private.h b/gst-libs/gst/glib-compat-private.h
new file mode 100644
index 0000000..8f37de2
--- /dev/null
+++ b/gst-libs/gst/glib-compat-private.h
@@ -0,0 +1,36 @@
+/*
+ * glib-compat.c
+ * Functions copied from glib 2.10
+ *
+ * Copyright 2005 David Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GLIB_COMPAT_PRIVATE_H__
+#define __GLIB_COMPAT_PRIVATE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/* copies */
+
+/* adaptations */
+
+G_END_DECLS
+
+#endif
diff --git a/gst-libs/gst/gst-i18n-plugin.h b/gst-libs/gst/gst-i18n-plugin.h
new file mode 100644
index 0000000..ff40ce2
--- /dev/null
+++ b/gst-libs/gst/gst-i18n-plugin.h
@@ -0,0 +1,47 @@
+/* GStreamer
+ * Copyright (C) 2004 Thomas Vander Stichele <thomas@apestaart.org>
+ *
+ * gst-i18n-plugins.h: internationalization macros for the GStreamer plugins
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_I18N_PLUGIN_H__
+#define __GST_I18N_PLUGIN_H__
+
+#ifndef GETTEXT_PACKAGE
+#error You must define GETTEXT_PACKAGE before including this header.
+#endif
+
+#ifdef ENABLE_NLS
+
+#include <locale.h>
+
+#include "gettext.h" /* included with gettext distribution and copied */
+
+/* we want to use shorthand _() for translating and N_() for marking */
+#define _(String) dgettext (GETTEXT_PACKAGE, String)
+#define N_(String) gettext_noop (String)
+/* FIXME: if we need it, we can add Q_ as well, like in glib */
+
+#else
+#define _(String) String
+#define N_(String) String
+#define ngettext(Singular,Plural,Count) ((Count>1)?Plural:Singular)
+
+#endif
+
+#endif /* __GST_I18N_PLUGIN_H__ */
diff --git a/gst-plugins-good.doap b/gst-plugins-good.doap
new file mode 100644
index 0000000..11a70f1
--- /dev/null
+++ b/gst-plugins-good.doap
@@ -0,0 +1,826 @@
+<Project
+  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+  xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+  xmlns="http://usefulinc.com/ns/doap#"
+  xmlns:foaf="http://xmlns.com/foaf/0.1/"
+  xmlns:admin="http://webns.net/mvcb/">
+
+ <name>GStreamer Good Plug-ins</name>
+ <shortname>gst-plugins-good</shortname>
+ <homepage rdf:resource="http://gstreamer.freedesktop.org/modules/gst-plugins-good.html" />
+ <created>2005-09-06</created>
+ <shortdesc xml:lang="en">
+a set of good-quality plug-ins under our preferred license, LGPL
+</shortdesc>
+ <description xml:lang="en">
+GStreamer Good Plug-ins is a set of plug-ins that we consider to have good
+quality code and correct functionality, under our preferred license (LGPL for
+the plug-in code, LGPL or LGPL-compatible for the supporting library).
+</description>
+ <category></category>
+ <bug-database rdf:resource="http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer&amp;component=gst-plugins-good" />
+ <screenshots></screenshots>
+ <mailing-list rdf:resource="http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel" />
+ <programming-language>C</programming-language>
+ <license rdf:resource="http://usefulinc.com/doap/licenses/lgpl"/>
+ <download-page rdf:resource="http://gstreamer.freedesktop.org/download/" />
+
+ <repository>
+   <GitRepository>
+     <location rdf:resource="git://anongit.freedesktop.org/gstreamer/gst-plugins-good"/>
+     <browse rdf:resource="http://cgit.freedesktop.org/gstreamer/gst-plugins-good"/>
+   </GitRepository>
+ </repository> 
+
+ <release>
+  <Version>
+   <revision>1.12.0</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2017-05-04</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.12.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.11.91</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2017-04-27</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.11.91.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.11.90</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2017-04-07</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.11.90.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.11.2</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2017-02-24</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.11.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.11.1</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2017-01-12</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.11.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.10.0</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2016-11-01</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.10.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.9.90</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2016-09-30</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.9.90.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.9.2</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2016-09-01</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.9.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.9.1</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2016-06-06</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.9.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.8.0</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2016-03-24</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.8.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.7.91</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2016-03-15</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.7.91.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.7.90</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2016-03-01</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.7.90.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.7.2</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2016-02-19</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.7.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.7.1</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2015-12-24</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.7.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.6.2</revision>
+   <branch>1.6</branch>
+   <name></name>
+   <created>2015-12-14</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.6.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.6.1</revision>
+   <branch>1.6</branch>
+   <name></name>
+   <created>2015-10-30</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.6.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.6.0</revision>
+   <branch>1.6</branch>
+   <name></name>
+   <created>2015-09-25</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.6.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.5.91</revision>
+   <branch>1.5</branch>
+   <name></name>
+   <created>2015-09-18</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.5.91.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.5.90</revision>
+   <branch>1.5</branch>
+   <name></name>
+   <created>2015-08-19</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.5.90.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.5.2</revision>
+   <branch>1.5</branch>
+   <name></name>
+   <created>2015-06-24</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.5.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.5.1</revision>
+   <branch>1.5</branch>
+   <name></name>
+   <created>2015-06-07</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.5.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.4.0</revision>
+   <branch>1.4</branch>
+   <name></name>
+   <created>2014-07-19</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.4.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.3.91</revision>
+   <branch>1.3</branch>
+   <name></name>
+   <created>2014-07-11</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.3.91.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.3.90</revision>
+   <branch>1.3</branch>
+   <name></name>
+   <created>2014-06-28</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.3.90.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.3.3</revision>
+   <branch>1.3</branch>
+   <name></name>
+   <created>2014-06-22</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.3.3.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.3.2</revision>
+   <branch>1.3</branch>
+   <name></name>
+   <created>2014-05-21</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.3.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.3.1</revision>
+   <branch>1.3</branch>
+   <name></name>
+   <created>2014-05-03</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.3.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.2.0</revision>
+   <branch>1.2</branch>
+   <name></name>
+   <created>2013-09-24</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.2.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.1.90</revision>
+   <branch>1.1</branch>
+   <name></name>
+   <created>2013-09-19</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.1.90.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.1.4</revision>
+   <branch>1.1</branch>
+   <name></name>
+   <created>2013-08-28</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.1.4.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.1.3</revision>
+   <branch>1.1</branch>
+   <name></name>
+   <created>2013-07-29</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.1.3.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.1.2</revision>
+   <branch>1.1</branch>
+   <name></name>
+   <created>2013-07-11</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.1.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.1.1</revision>
+   <branch>1.1</branch>
+   <name></name>
+   <created>2013-06-05</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.1.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.0.2</revision>
+   <branch>1.0</branch>
+   <name></name>
+   <created>2012-10-24</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.0.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.0.1</revision>
+   <branch>1.0</branch>
+   <name></name>
+   <created>2012-10-07</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.0.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.0.0</revision>
+   <branch>1.0</branch>
+   <name></name>
+   <created>2012-09-24</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.0.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.11.99</revision>
+   <branch>0.11</branch>
+   <name>Been Around for a Long Long Year</name>
+   <created>2012-09-17</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.11.99.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.11.94</revision>
+   <branch>0.11</branch>
+   <name>Beatiful Tango</name>
+   <created>2012-09-14</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.11.94.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.11.93</revision>
+   <branch>0.11</branch>
+   <name>Poetic Pitbull Revolutions</name>
+   <created>2012-08-08</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.11.93.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.11.92</revision>
+   <branch>0.11</branch>
+   <name>Money</name>
+   <created>2012-06-07</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.11.92.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.11.91</revision>
+   <branch>0.11</branch>
+   <name>I smell the blood of an Englishman</name>
+   <created>2012-05-13</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.11.91.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.11.90</revision>
+   <branch>0.11</branch>
+   <name>From grief and moan to a gold throne</name>
+   <created>2012-04-12</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.11.90.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.11.90.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.11.2</revision>
+   <branch>0.11</branch>
+   <name>Rite of Devastation</name>
+   <created>2012-03-22</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.11.2.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.11.2.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.11.1</revision>
+   <branch>0.11</branch>
+   <name>The Leper Affinity</name>
+   <created>2012-02-16</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.11.1.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.11.1.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.30</revision>
+   <branch>0.10</branch>
+   <name>Adagio</name>
+   <created>2011-06-15</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.30.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.30.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.29</revision>
+   <branch>0.10</branch>
+   <name>Soft Cheese Enthusiast</name>
+   <created>2011-05-10</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.29.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.29.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.28</revision>
+   <branch>0.10</branch>
+   <name>Inconvenienced by the Solar System</name>
+   <created>2011-03-08</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.28.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.28.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.27</revision>
+   <branch>0.10</branch>
+   <name>Some Kind of Temporal Blend</name>
+   <created>2011-01-21</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.27.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.27.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.26</revision>
+   <branch>0.10</branch>
+   <name>Escapades</name>
+   <created>2010-12-01</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.26.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.26.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.25</revision>
+   <branch>0.10</branch>
+   <name>Woe to You Oh Earth and Sea</name>
+   <created>2010-09-02</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.25.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.25.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.24</revision>
+   <branch>0.10</branch>
+   <name>Taking Liberties</name>
+   <created>2010-07-15</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.24.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.24.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.23</revision>
+   <branch>0.10</branch>
+   <name>Stylish Kids in Riot</name>
+   <created>2010-05-30</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.23.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.23.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.22</revision>
+   <branch>0.10</branch>
+   <name>Square One</name>
+   <created>2010-04-27</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.22.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.22.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.21</revision>
+   <branch>0.10</branch>
+   <name>Lemons</name>
+   <created>2010-03-08</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.21.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.21.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.20</revision>
+   <branch>0.10</branch>
+   <name>Lemonade</name>
+   <created>2010-03-08</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.20.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.20.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.19</revision>
+   <branch>0.10</branch>
+   <name>Closer to the Edit</name>
+   <created>2010-03-06</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.19.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.19.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.18</revision>
+   <branch>0.10</branch>
+   <name>Short Circuit</name>
+   <created>2010-02-10</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.18.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.18.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.17</revision>
+   <branch>0.10</branch>
+   <name>They used to sparkle</name>
+   <created>2009-11-17</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.17.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.17.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.16</revision>
+   <branch>0.10</branch>
+   <name>Secret Handshakes</name>
+   <created>2009-08-28</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.16.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.16.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.15</revision>
+   <branch>0.10</branch>
+   <name>I've been up all night</name>
+   <created>2009-05-20</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.15.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.15.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.14</revision>
+   <branch>0.10</branch>
+   <name>Disaffected Affectation</name>
+   <created>2009-02-19</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.14.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.14.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.13</revision>
+   <branch>0.10</branch>
+   <name>Blatant Discouragement</name>
+   <created>2009-01-22</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.13.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.13.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.12</revision>
+   <branch>0.10</branch>
+   <name>Taken Under Advisement</name>
+   <created>2009-01-22</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.12.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.12.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.11</revision>
+   <branch>0.10</branch>
+   <name>Secondary Consideration</name>
+   <created>2008-10-24</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.11.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.11.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.10</revision>
+   <branch>0.10</branch>
+   <name>Barely Moving</name>
+   <created>2008-08-26</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.10.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.10.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.9</revision>
+   <branch>0.10</branch>
+   <name>Steam Train Rolling</name>
+   <created>2008-07-31</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.9.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.9.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.8</revision>
+   <branch>0.10</branch>
+   <name>One For The Money</name>
+   <created>2008-04-24</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.8.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.8.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.7</revision>
+   <branch>0.10</branch>
+   <name>Red Door Black</name>
+   <created>2008-01-20</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.7.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.7.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.6</revision>
+   <branch>0.10</branch>
+   <name>Wobble Board</name>
+   <created>2007-06-19</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.6.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.6.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.5</revision>
+   <branch>0.10</branch>
+   <name>The Path of Thorns</name>
+   <created>2006-12-21</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.5.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.5.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.4</revision>
+   <branch>0.10</branch>
+   <name>Dear Leader</name>
+   <created>2006-08-14</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.4.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.4.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.3</revision>
+   <branch>0.10</branch>
+   <name>Desplazado</name>
+   <created>2006-05-04</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.3.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.3.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.2</revision>
+   <branch>0.10</branch>
+   <name>Papa was a rolling stone</name>
+   <created>2006-02-09</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.2.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.2.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.1</revision>
+   <branch>0.10</branch>
+   <name>Li</name>
+   <created>2006-01-13</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.1.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.1.tar.gz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>0.10.0</revision>
+   <branch>0.10</branch>
+   <name>Abondance</name>
+   <created>2005-12-05</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.0.tar.bz2" />
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-0.10.0.tar.gz" />
+  </Version>
+ </release>
+
+ <maintainer>
+  <foaf:Person>
+     <foaf:name>Wim Taymans</foaf:name>
+     <foaf:mbox_sha1sum>0d93fde052812d51a05fd86de9bdbf674423daa2</foaf:mbox_sha1sum>
+  </foaf:Person>
+ </maintainer>
+
+</Project>
diff --git a/gst/Makefile.am b/gst/Makefile.am
new file mode 100644
index 0000000..f25a56d
--- /dev/null
+++ b/gst/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = $(GST_PLUGINS_SELECTED)
+DIST_SUBDIRS = $(GST_PLUGINS_ALL)
+
+include $(top_srcdir)/common/parallel-subdirs.mak
diff --git a/gst/alpha/Makefile.am b/gst/alpha/Makefile.am
new file mode 100644
index 0000000..73123dd
--- /dev/null
+++ b/gst/alpha/Makefile.am
@@ -0,0 +1,17 @@
+plugin_LTLIBRARIES = libgstalpha.la libgstalphacolor.la
+
+libgstalpha_la_SOURCES = gstalpha.c
+libgstalpha_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstalpha_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) $(GST_LIBS) $(LIBM)
+libgstalpha_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+libgstalphacolor_la_SOURCES = gstalphacolor.c
+libgstalphacolor_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstalphacolor_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) $(GST_LIBS)
+libgstalphacolor_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstalpha.h gstalphacolor.h
diff --git a/gst/alpha/gstalpha.c b/gst/alpha/gstalpha.c
new file mode 100644
index 0000000..82ad981
--- /dev/null
+++ b/gst/alpha/gstalpha.c
@@ -0,0 +1,2613 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@collabora.co.uk>
+ * Copyright (C) <2007> Edward Hervey <edward.hervey@collabora.co.uk>
+ * Copyright (C) <2007> Jan Schmidt <thaytan@noraisin.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-alpha
+ * 
+ * The alpha element adds an alpha channel to a video stream. The values
+ * of the alpha channel can be either be set to a constant or can be
+ * dynamically calculated via chroma keying, e.g. blue can be set as
+ * the transparent color.
+ *
+ * Sample pipeline:
+ * |[
+ * gst-launch-1.0 videotestsrc pattern=snow ! mixer.sink_0 \
+ *   videotestsrc pattern=smpte75 ! alpha method=green ! mixer.sink_1 \
+ *   videomixer name=mixer sink_0::zorder=0 sink_1::zorder=1 ! \
+ *   videoconvert ! autovideosink
+ * ]| This pipeline adds a alpha channel to the SMPTE color bars
+ * with green as the transparent color and overlays the output on
+ * top of a snow video stream.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstalpha.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifndef M_PI
+#define M_PI  3.14159265358979323846
+#endif
+
+/* Generated by -bad/ext/cog/generate_tables */
+static const int cog_ycbcr_to_rgb_matrix_8bit_hdtv[] = {
+  298, 0, 459, -63514,
+  298, -55, -136, 19681,
+  298, 541, 0, -73988,
+};
+
+static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
+  298, 0, 409, -57068,
+  298, -100, -208, 34707,
+  298, 516, 0, -70870,
+};
+
+static const gint cog_rgb_to_ycbcr_matrix_8bit_hdtv[] = {
+  47, 157, 16, 4096,
+  -26, -87, 112, 32768,
+  112, -102, -10, 32768,
+};
+
+static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
+  66, 129, 25, 4096,
+  -38, -74, 112, 32768,
+  112, -94, -18, 32768,
+};
+
+static const gint cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit[] = {
+  256, -30, -53, 10600,
+  0, 261, 29, -4367,
+  0, 19, 262, -3289,
+};
+
+static const gint cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit[] = {
+  256, 25, 49, -9536,
+  0, 253, -28, 3958,
+  0, -19, 252, 2918,
+};
+
+/* Alpha signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+#define DEFAULT_METHOD ALPHA_METHOD_SET
+#define DEFAULT_ALPHA 1.0
+#define DEFAULT_TARGET_R 0
+#define DEFAULT_TARGET_G 255
+#define DEFAULT_TARGET_B 0
+#define DEFAULT_ANGLE 20.0
+#define DEFAULT_NOISE_LEVEL 2.0
+#define DEFAULT_BLACK_SENSITIVITY 100
+#define DEFAULT_WHITE_SENSITIVITY 100
+#define DEFAULT_PREFER_PASSTHROUGH FALSE
+
+enum
+{
+  PROP_0,
+  PROP_METHOD,
+  PROP_ALPHA,
+  PROP_TARGET_R,
+  PROP_TARGET_G,
+  PROP_TARGET_B,
+  PROP_ANGLE,
+  PROP_NOISE_LEVEL,
+  PROP_BLACK_SENSITIVITY,
+  PROP_WHITE_SENSITIVITY,
+  PROP_PREFER_PASSTHROUGH
+};
+
+static GstStaticPadTemplate gst_alpha_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, "
+            "ARGB, BGRA, ABGR, RGBA, Y444, xRGB, BGRx, xBGR, "
+            "RGBx, RGB, BGR, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B } "))
+    );
+
+static GstStaticPadTemplate gst_alpha_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, "
+            "ARGB, BGRA, ABGR, RGBA, Y444, xRGB, BGRx, xBGR, "
+            "RGBx, RGB, BGR, Y42B, YUY2, YVYU, UYVY, I420, YV12, " "Y41B } "))
+    );
+
+static GstStaticCaps gst_alpha_alpha_caps =
+GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, ARGB, BGRA, ABGR, RGBA }"));
+
+/* FIXME: why do we need our own lock for this? */
+#define GST_ALPHA_LOCK(alpha) G_STMT_START { \
+  GST_LOG_OBJECT (alpha, "Locking alpha from thread %p", g_thread_self ()); \
+  g_mutex_lock (&alpha->lock); \
+  GST_LOG_OBJECT (alpha, "Locked alpha from thread %p", g_thread_self ()); \
+} G_STMT_END
+
+#define GST_ALPHA_UNLOCK(alpha) G_STMT_START { \
+  GST_LOG_OBJECT (alpha, "Unlocking alpha from thread %p", g_thread_self ()); \
+  g_mutex_unlock (&alpha->lock); \
+} G_STMT_END
+
+static GstCaps *gst_alpha_transform_caps (GstBaseTransform * btrans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * filter);
+static void gst_alpha_before_transform (GstBaseTransform * btrans,
+    GstBuffer * buf);
+
+static gboolean gst_alpha_set_info (GstVideoFilter * filter,
+    GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
+    GstVideoInfo * out_info);
+static GstFlowReturn gst_alpha_transform_frame (GstVideoFilter * filter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame);
+
+static void gst_alpha_init_params_full (GstAlpha * alpha,
+    const GstVideoFormatInfo * in_info, const GstVideoFormatInfo * out_info);
+static void gst_alpha_init_params (GstAlpha * alpha);
+static void gst_alpha_set_process_function (GstAlpha * alpha);
+static gboolean gst_alpha_set_process_function_full (GstAlpha * alpha,
+    GstVideoInfo * in_info, GstVideoInfo * out_info);
+
+static void gst_alpha_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_alpha_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_alpha_finalize (GObject * object);
+
+#define gst_alpha_parent_class parent_class
+G_DEFINE_TYPE (GstAlpha, gst_alpha, GST_TYPE_VIDEO_FILTER);
+
+#define GST_TYPE_ALPHA_METHOD (gst_alpha_method_get_type())
+static GType
+gst_alpha_method_get_type (void)
+{
+  static GType alpha_method_type = 0;
+  static const GEnumValue alpha_method[] = {
+    {ALPHA_METHOD_SET, "Set/adjust alpha channel", "set"},
+    {ALPHA_METHOD_GREEN, "Chroma Key on pure green", "green"},
+    {ALPHA_METHOD_BLUE, "Chroma Key on pure blue", "blue"},
+    {ALPHA_METHOD_CUSTOM, "Chroma Key on custom RGB values", "custom"},
+    {0, NULL, NULL},
+  };
+
+  if (!alpha_method_type) {
+    alpha_method_type = g_enum_register_static ("GstAlphaMethod", alpha_method);
+  }
+  return alpha_method_type;
+}
+
+static void
+gst_alpha_class_init (GstAlphaClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBaseTransformClass *btrans_class = (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (gst_alpha_debug, "alpha", 0,
+      "alpha - Element for adding alpha channel to streams");
+
+  gobject_class->set_property = gst_alpha_set_property;
+  gobject_class->get_property = gst_alpha_get_property;
+  gobject_class->finalize = gst_alpha_finalize;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_METHOD,
+      g_param_spec_enum ("method", "Method",
+          "How the alpha channels should be created", GST_TYPE_ALPHA_METHOD,
+          DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALPHA,
+      g_param_spec_double ("alpha", "Alpha", "The value for the alpha channel",
+          0.0, 1.0, DEFAULT_ALPHA,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_R,
+      g_param_spec_uint ("target-r", "Target Red",
+          "The red color value for custom RGB chroma keying", 0, 255,
+          DEFAULT_TARGET_R,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_G,
+      g_param_spec_uint ("target-g", "Target Green",
+          "The green color value for custom RGB chroma keying", 0, 255,
+          DEFAULT_TARGET_G,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_B,
+      g_param_spec_uint ("target-b", "Target Blue",
+          "The blue color value for custom RGB chroma keying", 0, 255,
+          DEFAULT_TARGET_B,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ANGLE,
+      g_param_spec_float ("angle", "Angle", "Size of the colorcube to change",
+          0.0, 90.0, DEFAULT_ANGLE,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NOISE_LEVEL,
+      g_param_spec_float ("noise-level", "Noise Level", "Size of noise radius",
+          0.0, 64.0, DEFAULT_NOISE_LEVEL,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_BLACK_SENSITIVITY, g_param_spec_uint ("black-sensitivity",
+          "Black Sensitivity", "Sensitivity to dark colors", 0, 128,
+          DEFAULT_BLACK_SENSITIVITY,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_WHITE_SENSITIVITY, g_param_spec_uint ("white-sensitivity",
+          "White Sensitivity", "Sensitivity to bright colors", 0, 128,
+          DEFAULT_WHITE_SENSITIVITY,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_PREFER_PASSTHROUGH, g_param_spec_boolean ("prefer-passthrough",
+          "Prefer Passthrough",
+          "Don't do any processing for alpha=1.0 if possible",
+          DEFAULT_PREFER_PASSTHROUGH,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class, "Alpha filter",
+      "Filter/Effect/Video",
+      "Adds an alpha channel to video - uniform or via chroma-keying",
+      "Wim Taymans <wim.taymans@gmail.com>\n"
+      "Edward Hervey <edward.hervey@collabora.co.uk>\n"
+      "Jan Schmidt <thaytan@noraisin.net>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_alpha_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_alpha_src_template);
+
+  btrans_class->before_transform =
+      GST_DEBUG_FUNCPTR (gst_alpha_before_transform);
+  btrans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_alpha_transform_caps);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_alpha_set_info);
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_alpha_transform_frame);
+}
+
+static void
+gst_alpha_init (GstAlpha * alpha)
+{
+  alpha->alpha = DEFAULT_ALPHA;
+  alpha->method = DEFAULT_METHOD;
+  alpha->target_r = DEFAULT_TARGET_R;
+  alpha->target_g = DEFAULT_TARGET_G;
+  alpha->target_b = DEFAULT_TARGET_B;
+  alpha->angle = DEFAULT_ANGLE;
+  alpha->noise_level = DEFAULT_NOISE_LEVEL;
+  alpha->black_sensitivity = DEFAULT_BLACK_SENSITIVITY;
+  alpha->white_sensitivity = DEFAULT_WHITE_SENSITIVITY;
+
+  g_mutex_init (&alpha->lock);
+}
+
+static void
+gst_alpha_finalize (GObject * object)
+{
+  GstAlpha *alpha = GST_ALPHA (object);
+
+  g_mutex_clear (&alpha->lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_alpha_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAlpha *alpha = GST_ALPHA (object);
+  gboolean reconfigure = FALSE;
+
+  GST_ALPHA_LOCK (alpha);
+  switch (prop_id) {
+    case PROP_METHOD:{
+      gint method = g_value_get_enum (value);
+
+      reconfigure = (method != alpha->method) && (method == ALPHA_METHOD_SET
+          || alpha->method == ALPHA_METHOD_SET) && (alpha->alpha == 1.0)
+          && (alpha->prefer_passthrough);
+      alpha->method = method;
+
+      gst_alpha_set_process_function (alpha);
+      gst_alpha_init_params (alpha);
+      break;
+    }
+    case PROP_ALPHA:{
+      gdouble a = g_value_get_double (value);
+
+      reconfigure = (a != alpha->alpha) && (a == 1.0 || alpha->alpha == 1.0)
+          && (alpha->method == ALPHA_METHOD_SET) && (alpha->prefer_passthrough);
+      alpha->alpha = a;
+      break;
+    }
+    case PROP_TARGET_R:
+      alpha->target_r = g_value_get_uint (value);
+      gst_alpha_init_params (alpha);
+      break;
+    case PROP_TARGET_G:
+      alpha->target_g = g_value_get_uint (value);
+      gst_alpha_init_params (alpha);
+      break;
+    case PROP_TARGET_B:
+      alpha->target_b = g_value_get_uint (value);
+      gst_alpha_init_params (alpha);
+      break;
+    case PROP_ANGLE:
+      alpha->angle = g_value_get_float (value);
+      gst_alpha_init_params (alpha);
+      break;
+    case PROP_NOISE_LEVEL:
+      alpha->noise_level = g_value_get_float (value);
+      gst_alpha_init_params (alpha);
+      break;
+    case PROP_BLACK_SENSITIVITY:
+      alpha->black_sensitivity = g_value_get_uint (value);
+      break;
+    case PROP_WHITE_SENSITIVITY:
+      alpha->white_sensitivity = g_value_get_uint (value);
+      break;
+    case PROP_PREFER_PASSTHROUGH:{
+      gboolean prefer_passthrough = g_value_get_boolean (value);
+
+      reconfigure = ((! !prefer_passthrough) != (! !alpha->prefer_passthrough))
+          && (alpha->method == ALPHA_METHOD_SET) && (alpha->alpha == 1.0);
+      alpha->prefer_passthrough = prefer_passthrough;
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  if (reconfigure)
+    gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM_CAST (alpha));
+
+  GST_ALPHA_UNLOCK (alpha);
+}
+
+static void
+gst_alpha_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstAlpha *alpha = GST_ALPHA (object);
+
+  switch (prop_id) {
+    case PROP_METHOD:
+      g_value_set_enum (value, alpha->method);
+      break;
+    case PROP_ALPHA:
+      g_value_set_double (value, alpha->alpha);
+      break;
+    case PROP_TARGET_R:
+      g_value_set_uint (value, alpha->target_r);
+      break;
+    case PROP_TARGET_G:
+      g_value_set_uint (value, alpha->target_g);
+      break;
+    case PROP_TARGET_B:
+      g_value_set_uint (value, alpha->target_b);
+      break;
+    case PROP_ANGLE:
+      g_value_set_float (value, alpha->angle);
+      break;
+    case PROP_NOISE_LEVEL:
+      g_value_set_float (value, alpha->noise_level);
+      break;
+    case PROP_BLACK_SENSITIVITY:
+      g_value_set_uint (value, alpha->black_sensitivity);
+      break;
+    case PROP_WHITE_SENSITIVITY:
+      g_value_set_uint (value, alpha->white_sensitivity);
+      break;
+    case PROP_PREFER_PASSTHROUGH:
+      g_value_set_boolean (value, alpha->prefer_passthrough);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstCaps *
+gst_alpha_transform_caps (GstBaseTransform * btrans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
+{
+  GstAlpha *alpha = GST_ALPHA (btrans);
+  GstCaps *ret, *tmp, *tmp2;
+  GstStructure *structure;
+  gint i;
+
+  tmp = gst_caps_new_empty ();
+
+  GST_ALPHA_LOCK (alpha);
+  for (i = 0; i < gst_caps_get_size (caps); i++) {
+    structure = gst_structure_copy (gst_caps_get_structure (caps, i));
+
+    gst_structure_remove_field (structure, "format");
+    gst_structure_remove_field (structure, "colorimetry");
+    gst_structure_remove_field (structure, "chroma-site");
+
+    gst_caps_append_structure (tmp, structure);
+  }
+
+  if (direction == GST_PAD_SINK) {
+    tmp2 = gst_static_caps_get (&gst_alpha_alpha_caps);
+    ret = gst_caps_intersect (tmp, tmp2);
+    gst_caps_unref (tmp);
+    gst_caps_unref (tmp2);
+    tmp = ret;
+    ret = NULL;
+
+    if (alpha->prefer_passthrough && alpha->method == ALPHA_METHOD_SET
+        && alpha->alpha == 1.0) {
+      ret = gst_caps_copy (caps);
+      gst_caps_append (ret, tmp);
+      tmp = NULL;
+    } else {
+      ret = tmp;
+      tmp = NULL;
+    }
+  } else {
+    ret = tmp;
+    tmp = NULL;
+  }
+
+  GST_DEBUG_OBJECT (alpha,
+      "Transformed %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT, caps, ret);
+
+  if (filter) {
+    GstCaps *intersection;
+
+    GST_DEBUG_OBJECT (alpha, "Using filter caps %" GST_PTR_FORMAT, filter);
+    intersection =
+        gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (ret);
+    ret = intersection;
+    GST_DEBUG_OBJECT (alpha, "Intersection %" GST_PTR_FORMAT, ret);
+  }
+
+
+  GST_ALPHA_UNLOCK (alpha);
+
+  return ret;
+}
+
+static gboolean
+gst_alpha_set_info (GstVideoFilter * filter,
+    GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
+    GstVideoInfo * out_info)
+{
+  GstAlpha *alpha = GST_ALPHA (filter);
+  gboolean passthrough;
+
+  GST_ALPHA_LOCK (alpha);
+
+  alpha->in_sdtv = in_info->colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_BT601;
+  alpha->out_sdtv =
+      out_info->colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_BT601;
+
+  passthrough = alpha->prefer_passthrough &&
+      GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_INFO_FORMAT (out_info)
+      && alpha->in_sdtv == alpha->out_sdtv && alpha->method == ALPHA_METHOD_SET
+      && alpha->alpha == 1.0;
+
+  GST_DEBUG_OBJECT (alpha,
+      "Setting caps %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT
+      " (passthrough: %d)", incaps, outcaps, passthrough);
+  gst_base_transform_set_passthrough (GST_BASE_TRANSFORM_CAST (filter),
+      passthrough);
+
+  if (!gst_alpha_set_process_function_full (alpha, in_info, out_info)
+      && !passthrough)
+    goto no_process;
+
+  gst_alpha_init_params_full (alpha, in_info->finfo, out_info->finfo);
+
+  GST_ALPHA_UNLOCK (alpha);
+
+  return TRUE;
+
+  /* ERRORS */
+no_process:
+  {
+    GST_WARNING_OBJECT (alpha,
+        "No processing function for this caps and no passthrough mode");
+    GST_ALPHA_UNLOCK (alpha);
+    return FALSE;
+  }
+}
+
+/* based on http://www.cs.utah.edu/~michael/chroma/
+ */
+static inline gint
+chroma_keying_yuv (gint a, gint * y, gint * u,
+    gint * v, gint cr, gint cb, gint smin, gint smax, guint8 accept_angle_tg,
+    guint8 accept_angle_ctg, guint8 one_over_kc, guint8 kfgy_scale, gint8 kg,
+    guint noise_level2)
+{
+  gint tmp, tmp1;
+  gint x1, y1;
+  gint x, z;
+  gint b_alpha;
+
+  /* too dark or too bright, keep alpha */
+  if (*y < smin || *y > smax)
+    return a;
+
+  /* Convert foreground to XZ coords where X direction is defined by
+     the key color */
+  tmp = ((*u) * cb + (*v) * cr) >> 7;
+  x = CLAMP (tmp, -128, 127);
+  tmp = ((*v) * cb - (*u) * cr) >> 7;
+  z = CLAMP (tmp, -128, 127);
+
+  /* WARNING: accept angle should never be set greater than "somewhat less
+     than 90 degrees" to avoid dealing with negative/infinite tg. In reality,
+     80 degrees should be enough if foreground is reasonable. If this seems
+     to be a problem, go to alternative ways of checking point position
+     (scalar product or line equations). This angle should not be too small
+     either to avoid infinite ctg (used to suppress foreground without use of
+     division) */
+
+  tmp = (x * accept_angle_tg) >> 4;
+  tmp = MIN (tmp, 127);
+
+  if (abs (z) > tmp) {
+    /* keep foreground Kfg = 0 */
+    return a;
+  }
+  /* Compute Kfg (implicitly) and Kbg, suppress foreground in XZ coord
+     according to Kfg */
+  tmp = (z * accept_angle_ctg) >> 4;
+  tmp = CLAMP (tmp, -128, 127);
+  x1 = abs (tmp);
+  y1 = z;
+
+  tmp1 = x - x1;
+  tmp1 = MAX (tmp1, 0);
+  b_alpha = (tmp1 * one_over_kc) / 2;
+  b_alpha = 255 - CLAMP (b_alpha, 0, 255);
+  b_alpha = (a * b_alpha) >> 8;
+
+  tmp = (tmp1 * kfgy_scale) >> 4;
+  tmp1 = MIN (tmp, 255);
+
+  *y = (*y < tmp1) ? 0 : *y - tmp1;
+
+  /* Convert suppressed foreground back to CbCr */
+  tmp = (x1 * cb - y1 * cr) >> 7;
+  *u = CLAMP (tmp, -128, 127);
+
+  tmp = (x1 * cr + y1 * cb) >> 7;
+  *v = CLAMP (tmp, -128, 127);
+
+  /* Deal with noise. For now, a circle around the key color with
+     radius of noise_level treated as exact key color. Introduces
+     sharp transitions.
+   */
+  tmp = z * z + (x - kg) * (x - kg);
+  tmp = MIN (tmp, 0xffff);
+
+  if (tmp < noise_level2)
+    b_alpha = 0;
+
+  return b_alpha;
+}
+
+#define APPLY_MATRIX(m,o,v1,v2,v3) ((m[o*4] * v1 + m[o*4+1] * v2 + m[o*4+2] * v3 + m[o*4+3]) >> 8)
+
+static void
+gst_alpha_set_argb_ayuv (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint i, j;
+  gint matrix[12];
+  gint y, u, v;
+  gint o[4];
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  o[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 3);
+  o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
+  o[2] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
+  o[3] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
+
+  memcpy (matrix,
+      alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
+      cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      dest[0] = (src[o[0]] * s_alpha) >> 8;
+
+      y = APPLY_MATRIX (matrix, 0, src[o[1]], src[o[2]], src[o[3]]);
+      u = APPLY_MATRIX (matrix, 1, src[o[1]], src[o[2]], src[o[3]]);
+      v = APPLY_MATRIX (matrix, 2, src[o[1]], src[o[2]], src[o[3]]);
+
+      dest[1] = y;
+      dest[2] = u;
+      dest[3] = v;
+
+      dest += 4;
+      src += 4;
+    }
+  }
+}
+
+static void
+gst_alpha_chroma_key_argb_ayuv (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint i, j;
+  gint a, y, u, v;
+  gint r, g, b;
+  gint smin, smax;
+  gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
+  gint8 cb = alpha->cb, cr = alpha->cr;
+  gint8 kg = alpha->kg;
+  guint8 accept_angle_tg = alpha->accept_angle_tg;
+  guint8 accept_angle_ctg = alpha->accept_angle_ctg;
+  guint8 one_over_kc = alpha->one_over_kc;
+  guint8 kfgy_scale = alpha->kfgy_scale;
+  guint noise_level2 = alpha->noise_level2;
+  gint matrix[12];
+  gint o[4];
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  o[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 3);
+  o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
+  o[2] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
+  o[3] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
+
+  smin = 128 - alpha->black_sensitivity;
+  smax = 128 + alpha->white_sensitivity;
+
+  memcpy (matrix,
+      alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
+      cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      a = (src[o[0]] * pa) >> 8;
+      r = src[o[1]];
+      g = src[o[2]];
+      b = src[o[3]];
+
+      y = APPLY_MATRIX (matrix, 0, r, g, b);
+      u = APPLY_MATRIX (matrix, 1, r, g, b) - 128;
+      v = APPLY_MATRIX (matrix, 2, r, g, b) - 128;
+
+      a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
+          smin, smax, accept_angle_tg, accept_angle_ctg,
+          one_over_kc, kfgy_scale, kg, noise_level2);
+
+      u += 128;
+      v += 128;
+
+      dest[0] = a;
+      dest[1] = y;
+      dest[2] = u;
+      dest[3] = v;
+
+      src += 4;
+      dest += 4;
+    }
+  }
+}
+
+static void
+gst_alpha_set_argb_argb (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
+  gint i, j;
+  gint p[4], o[4];
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
+  p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
+  p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
+  p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
+
+  o[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 3);
+  o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
+  o[2] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
+  o[3] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      dest[p[0]] = (src[o[0]] * s_alpha) >> 8;
+
+      dest[p[1]] = src[o[1]];
+      dest[p[2]] = src[o[2]];
+      dest[p[3]] = src[o[3]];
+
+      dest += 4;
+      src += 4;
+    }
+  }
+}
+
+static void
+gst_alpha_chroma_key_argb_argb (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint i, j;
+  gint a, y, u, v;
+  gint r, g, b;
+  gint smin, smax;
+  gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
+  gint8 cb = alpha->cb, cr = alpha->cr;
+  gint8 kg = alpha->kg;
+  guint8 accept_angle_tg = alpha->accept_angle_tg;
+  guint8 accept_angle_ctg = alpha->accept_angle_ctg;
+  guint8 one_over_kc = alpha->one_over_kc;
+  guint8 kfgy_scale = alpha->kfgy_scale;
+  guint noise_level2 = alpha->noise_level2;
+  gint matrix[12], matrix2[12];
+  gint p[4], o[4];
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
+  p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
+  p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
+  p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
+
+  o[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 3);
+  o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
+  o[2] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
+  o[3] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
+
+  smin = 128 - alpha->black_sensitivity;
+  smax = 128 + alpha->white_sensitivity;
+
+  memcpy (matrix, cog_rgb_to_ycbcr_matrix_8bit_sdtv, 12 * sizeof (gint));
+  memcpy (matrix2, cog_ycbcr_to_rgb_matrix_8bit_sdtv, 12 * sizeof (gint));
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      a = (src[o[0]] * pa) >> 8;
+      r = src[o[1]];
+      g = src[o[2]];
+      b = src[o[3]];
+
+      y = APPLY_MATRIX (matrix, 0, r, g, b);
+      u = APPLY_MATRIX (matrix, 1, r, g, b) - 128;
+      v = APPLY_MATRIX (matrix, 2, r, g, b) - 128;
+
+      a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
+          smin, smax, accept_angle_tg, accept_angle_ctg,
+          one_over_kc, kfgy_scale, kg, noise_level2);
+
+      u += 128;
+      v += 128;
+
+      r = APPLY_MATRIX (matrix2, 0, y, u, v);
+      g = APPLY_MATRIX (matrix2, 1, y, u, v);
+      b = APPLY_MATRIX (matrix2, 2, y, u, v);
+
+      dest[p[0]] = a;
+      dest[p[1]] = CLAMP (r, 0, 255);
+      dest[p[2]] = CLAMP (g, 0, 255);
+      dest[p[3]] = CLAMP (b, 0, 255);
+
+      src += 4;
+      dest += 4;
+    }
+  }
+}
+
+static void
+gst_alpha_set_ayuv_argb (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
+  gint y, x;
+  gint matrix[12];
+  gint r, g, b;
+  gint p[4];
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
+  p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
+  p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
+  p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
+
+  memcpy (matrix,
+      alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
+      cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
+
+  for (y = 0; y < height; y++) {
+    for (x = 0; x < width; x++) {
+      dest[p[0]] = (src[0] * s_alpha) >> 8;
+
+      r = APPLY_MATRIX (matrix, 0, src[1], src[2], src[3]);
+      g = APPLY_MATRIX (matrix, 1, src[1], src[2], src[3]);
+      b = APPLY_MATRIX (matrix, 2, src[1], src[2], src[3]);
+
+      dest[p[1]] = CLAMP (r, 0, 255);
+      dest[p[2]] = CLAMP (g, 0, 255);
+      dest[p[3]] = CLAMP (b, 0, 255);
+
+      dest += 4;
+      src += 4;
+    }
+  }
+}
+
+static void
+gst_alpha_chroma_key_ayuv_argb (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint i, j;
+  gint a, y, u, v;
+  gint r, g, b;
+  gint smin, smax;
+  gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
+  gint8 cb = alpha->cb, cr = alpha->cr;
+  gint8 kg = alpha->kg;
+  guint8 accept_angle_tg = alpha->accept_angle_tg;
+  guint8 accept_angle_ctg = alpha->accept_angle_ctg;
+  guint8 one_over_kc = alpha->one_over_kc;
+  guint8 kfgy_scale = alpha->kfgy_scale;
+  guint noise_level2 = alpha->noise_level2;
+  gint matrix[12];
+  gint p[4];
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
+  p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
+  p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
+  p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
+
+  smin = 128 - alpha->black_sensitivity;
+  smax = 128 + alpha->white_sensitivity;
+
+  memcpy (matrix,
+      alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
+      cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      a = (src[0] * pa) >> 8;
+      y = src[1];
+      u = src[2] - 128;
+      v = src[3] - 128;
+
+      a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
+          smin, smax, accept_angle_tg, accept_angle_ctg,
+          one_over_kc, kfgy_scale, kg, noise_level2);
+
+      u += 128;
+      v += 128;
+
+      r = APPLY_MATRIX (matrix, 0, y, u, v);
+      g = APPLY_MATRIX (matrix, 1, y, u, v);
+      b = APPLY_MATRIX (matrix, 2, y, u, v);
+
+      dest[p[0]] = a;
+      dest[p[1]] = CLAMP (r, 0, 255);
+      dest[p[2]] = CLAMP (g, 0, 255);
+      dest[p[3]] = CLAMP (b, 0, 255);
+
+      src += 4;
+      dest += 4;
+    }
+  }
+}
+
+static void
+gst_alpha_set_ayuv_ayuv (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
+  gint y, x;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  if (alpha->in_sdtv == alpha->out_sdtv) {
+    for (y = 0; y < height; y++) {
+      for (x = 0; x < width; x++) {
+        dest[0] = (src[0] * s_alpha) >> 8;
+        dest[1] = src[1];
+        dest[2] = src[2];
+        dest[3] = src[3];
+
+        dest += 4;
+        src += 4;
+      }
+    }
+  } else {
+    gint matrix[12];
+
+    memcpy (matrix,
+        alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+
+    for (y = 0; y < height; y++) {
+      for (x = 0; x < width; x++) {
+        dest[0] = (src[0] * s_alpha) >> 8;
+        dest[1] = APPLY_MATRIX (matrix, 0, src[1], src[2], src[3]);
+        dest[2] = APPLY_MATRIX (matrix, 1, src[1], src[2], src[3]);
+        dest[3] = APPLY_MATRIX (matrix, 2, src[1], src[2], src[3]);
+
+        dest += 4;
+        src += 4;
+      }
+    }
+  }
+}
+
+static void
+gst_alpha_chroma_key_ayuv_ayuv (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint i, j;
+  gint a, y, u, v;
+  gint smin, smax;
+  gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
+  gint8 cb = alpha->cb, cr = alpha->cr;
+  gint8 kg = alpha->kg;
+  guint8 accept_angle_tg = alpha->accept_angle_tg;
+  guint8 accept_angle_ctg = alpha->accept_angle_ctg;
+  guint8 one_over_kc = alpha->one_over_kc;
+  guint8 kfgy_scale = alpha->kfgy_scale;
+  guint noise_level2 = alpha->noise_level2;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  smin = 128 - alpha->black_sensitivity;
+  smax = 128 + alpha->white_sensitivity;
+
+  if (alpha->in_sdtv == alpha->out_sdtv) {
+    for (i = 0; i < height; i++) {
+      for (j = 0; j < width; j++) {
+        a = (src[0] * pa) >> 8;
+        y = src[1];
+        u = src[2] - 128;
+        v = src[3] - 128;
+
+        a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
+            smin, smax, accept_angle_tg, accept_angle_ctg,
+            one_over_kc, kfgy_scale, kg, noise_level2);
+
+        u += 128;
+        v += 128;
+
+        dest[0] = a;
+        dest[1] = y;
+        dest[2] = u;
+        dest[3] = v;
+
+        src += 4;
+        dest += 4;
+      }
+    }
+  } else {
+    gint matrix[12];
+
+    memcpy (matrix,
+        alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+
+    for (i = 0; i < height; i++) {
+      for (j = 0; j < width; j++) {
+        a = (src[0] * pa) >> 8;
+        y = APPLY_MATRIX (matrix, 0, src[1], src[2], src[3]);
+        u = APPLY_MATRIX (matrix, 1, src[1], src[2], src[3]) - 128;
+        v = APPLY_MATRIX (matrix, 2, src[1], src[2], src[3]) - 128;
+
+        a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
+            smin, smax, accept_angle_tg, accept_angle_ctg,
+            one_over_kc, kfgy_scale, kg, noise_level2);
+
+        u += 128;
+        v += 128;
+
+        dest[0] = a;
+        dest[1] = y;
+        dest[2] = u;
+        dest[3] = v;
+
+        src += 4;
+        dest += 4;
+      }
+    }
+  }
+}
+
+static void
+gst_alpha_set_rgb_ayuv (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
+  gint i, j;
+  gint matrix[12];
+  gint y, u, v;
+  gint o[3];
+  gint bpp;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (in_frame, 0);
+  o[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
+  o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
+  o[2] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
+
+  memcpy (matrix,
+      alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
+      cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      dest[0] = s_alpha;
+
+      y = APPLY_MATRIX (matrix, 0, src[o[0]], src[o[1]], src[o[2]]);
+      u = APPLY_MATRIX (matrix, 1, src[o[0]], src[o[1]], src[o[2]]);
+      v = APPLY_MATRIX (matrix, 2, src[o[0]], src[o[1]], src[o[2]]);
+
+      dest[1] = y;
+      dest[2] = u;
+      dest[3] = v;
+
+      dest += 4;
+      src += bpp;
+    }
+  }
+}
+
+static void
+gst_alpha_chroma_key_rgb_ayuv (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint i, j;
+  gint a, y, u, v;
+  gint r, g, b;
+  gint smin, smax;
+  gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
+  gint8 cb = alpha->cb, cr = alpha->cr;
+  gint8 kg = alpha->kg;
+  guint8 accept_angle_tg = alpha->accept_angle_tg;
+  guint8 accept_angle_ctg = alpha->accept_angle_ctg;
+  guint8 one_over_kc = alpha->one_over_kc;
+  guint8 kfgy_scale = alpha->kfgy_scale;
+  guint noise_level2 = alpha->noise_level2;
+  gint matrix[12];
+  gint o[3];
+  gint bpp;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (in_frame, 0);
+
+  o[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
+  o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
+  o[2] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
+
+  smin = 128 - alpha->black_sensitivity;
+  smax = 128 + alpha->white_sensitivity;
+
+  memcpy (matrix,
+      alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
+      cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      a = pa;
+      r = src[o[0]];
+      g = src[o[1]];
+      b = src[o[2]];
+
+      y = APPLY_MATRIX (matrix, 0, r, g, b);
+      u = APPLY_MATRIX (matrix, 1, r, g, b) - 128;
+      v = APPLY_MATRIX (matrix, 2, r, g, b) - 128;
+
+      a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
+          smin, smax, accept_angle_tg, accept_angle_ctg,
+          one_over_kc, kfgy_scale, kg, noise_level2);
+
+      u += 128;
+      v += 128;
+
+      dest[0] = a;
+      dest[1] = y;
+      dest[2] = u;
+      dest[3] = v;
+
+      src += bpp;
+      dest += 4;
+    }
+  }
+}
+
+static void
+gst_alpha_set_rgb_argb (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
+  gint i, j;
+  gint p[4], o[3];
+  gint bpp;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (in_frame, 0);
+
+  o[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
+  o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
+  o[2] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
+
+  p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
+  p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
+  p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
+  p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      dest[p[0]] = s_alpha;
+
+      dest[p[1]] = src[o[0]];
+      dest[p[2]] = src[o[1]];
+      dest[p[3]] = src[o[2]];
+
+      dest += 4;
+      src += bpp;
+    }
+  }
+}
+
+static void
+gst_alpha_chroma_key_rgb_argb (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint i, j;
+  gint a, y, u, v;
+  gint r, g, b;
+  gint smin, smax;
+  gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
+  gint8 cb = alpha->cb, cr = alpha->cr;
+  gint8 kg = alpha->kg;
+  guint8 accept_angle_tg = alpha->accept_angle_tg;
+  guint8 accept_angle_ctg = alpha->accept_angle_ctg;
+  guint8 one_over_kc = alpha->one_over_kc;
+  guint8 kfgy_scale = alpha->kfgy_scale;
+  guint noise_level2 = alpha->noise_level2;
+  gint matrix[12], matrix2[12];
+  gint p[4], o[3];
+  gint bpp;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (in_frame, 0);
+
+  o[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
+  o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
+  o[2] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
+
+  p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
+  p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
+  p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
+  p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
+
+  smin = 128 - alpha->black_sensitivity;
+  smax = 128 + alpha->white_sensitivity;
+
+  memcpy (matrix, cog_rgb_to_ycbcr_matrix_8bit_sdtv, 12 * sizeof (gint));
+  memcpy (matrix2, cog_ycbcr_to_rgb_matrix_8bit_sdtv, 12 * sizeof (gint));
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      a = pa;
+      r = src[o[0]];
+      g = src[o[1]];
+      b = src[o[2]];
+
+      y = APPLY_MATRIX (matrix, 0, r, g, b);
+      u = APPLY_MATRIX (matrix, 1, r, g, b) - 128;
+      v = APPLY_MATRIX (matrix, 2, r, g, b) - 128;
+
+      a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
+          smin, smax, accept_angle_tg, accept_angle_ctg,
+          one_over_kc, kfgy_scale, kg, noise_level2);
+
+      u += 128;
+      v += 128;
+
+      r = APPLY_MATRIX (matrix2, 0, y, u, v);
+      g = APPLY_MATRIX (matrix2, 1, y, u, v);
+      b = APPLY_MATRIX (matrix2, 2, y, u, v);
+
+      dest[p[0]] = a;
+      dest[p[1]] = CLAMP (r, 0, 255);
+      dest[p[2]] = CLAMP (g, 0, 255);
+      dest[p[3]] = CLAMP (b, 0, 255);
+
+      src += bpp;
+      dest += 4;
+    }
+  }
+}
+
+static void
+gst_alpha_set_planar_yuv_ayuv (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  guint8 *dest;
+  gint width, height;
+  gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
+  const guint8 *srcY, *srcY_tmp;
+  const guint8 *srcU, *srcU_tmp;
+  const guint8 *srcV, *srcV_tmp;
+  gint i, j;
+  gint y_stride, uv_stride;
+  gint v_subs, h_subs;
+
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  y_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
+  uv_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 1);
+
+  srcY_tmp = srcY = GST_VIDEO_FRAME_COMP_DATA (in_frame, 0);
+  srcU_tmp = srcU = GST_VIDEO_FRAME_COMP_DATA (in_frame, 1);
+  srcV_tmp = srcV = GST_VIDEO_FRAME_COMP_DATA (in_frame, 2);
+
+  switch (GST_VIDEO_FRAME_FORMAT (in_frame)) {
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+      v_subs = h_subs = 2;
+      break;
+    case GST_VIDEO_FORMAT_Y444:
+      v_subs = h_subs = 1;
+      break;
+    case GST_VIDEO_FORMAT_Y42B:
+      v_subs = 1;
+      h_subs = 2;
+      break;
+    case GST_VIDEO_FORMAT_Y41B:
+      v_subs = 1;
+      h_subs = 4;
+      break;
+    default:
+      g_assert_not_reached ();
+      return;
+  }
+
+  if (alpha->in_sdtv == alpha->out_sdtv) {
+    for (i = 0; i < height; i++) {
+      for (j = 0; j < width; j++) {
+        dest[0] = b_alpha;
+        dest[1] = srcY[0];
+        dest[2] = srcU[0];
+        dest[3] = srcV[0];
+
+        dest += 4;
+        srcY++;
+        if ((j + 1) % h_subs == 0) {
+          srcU++;
+          srcV++;
+        }
+      }
+
+      srcY_tmp = srcY = srcY_tmp + y_stride;
+      if ((i + 1) % v_subs == 0) {
+        srcU_tmp = srcU = srcU_tmp + uv_stride;
+        srcV_tmp = srcV = srcV_tmp + uv_stride;
+      } else {
+        srcU = srcU_tmp;
+        srcV = srcV_tmp;
+      }
+    }
+  } else {
+    gint matrix[12];
+    gint a, y, u, v;
+
+    memcpy (matrix,
+        alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+
+    for (i = 0; i < height; i++) {
+      for (j = 0; j < width; j++) {
+        a = b_alpha;
+        y = srcY[0];
+        u = srcU[0];
+        v = srcV[0];
+
+        dest[0] = a;
+        dest[1] = APPLY_MATRIX (matrix, 0, y, u, v);
+        dest[2] = APPLY_MATRIX (matrix, 1, y, u, v);
+        dest[3] = APPLY_MATRIX (matrix, 2, y, u, v);
+
+        dest += 4;
+        srcY++;
+        if ((j + 1) % h_subs == 0) {
+          srcU++;
+          srcV++;
+        }
+      }
+
+      srcY_tmp = srcY = srcY_tmp + y_stride;
+      if ((i + 1) % v_subs == 0) {
+        srcU_tmp = srcU = srcU_tmp + uv_stride;
+        srcV_tmp = srcV = srcV_tmp + uv_stride;
+      } else {
+        srcU = srcU_tmp;
+        srcV = srcV_tmp;
+      }
+    }
+  }
+}
+
+static void
+gst_alpha_chroma_key_planar_yuv_ayuv (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  guint8 *dest;
+  gint width, height;
+  gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
+  const guint8 *srcY, *srcY_tmp;
+  const guint8 *srcU, *srcU_tmp;
+  const guint8 *srcV, *srcV_tmp;
+  gint i, j;
+  gint a, y, u, v;
+  gint y_stride, uv_stride;
+  gint v_subs, h_subs;
+  gint smin = 128 - alpha->black_sensitivity;
+  gint smax = 128 + alpha->white_sensitivity;
+  gint8 cb = alpha->cb, cr = alpha->cr;
+  gint8 kg = alpha->kg;
+  guint8 accept_angle_tg = alpha->accept_angle_tg;
+  guint8 accept_angle_ctg = alpha->accept_angle_ctg;
+  guint8 one_over_kc = alpha->one_over_kc;
+  guint8 kfgy_scale = alpha->kfgy_scale;
+  guint noise_level2 = alpha->noise_level2;
+
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  y_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
+  uv_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 1);
+
+  srcY_tmp = srcY = GST_VIDEO_FRAME_COMP_DATA (in_frame, 0);
+  srcU_tmp = srcU = GST_VIDEO_FRAME_COMP_DATA (in_frame, 1);
+  srcV_tmp = srcV = GST_VIDEO_FRAME_COMP_DATA (in_frame, 2);
+
+  switch (GST_VIDEO_FRAME_FORMAT (in_frame)) {
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+      v_subs = h_subs = 2;
+      break;
+    case GST_VIDEO_FORMAT_Y444:
+      v_subs = h_subs = 1;
+      break;
+    case GST_VIDEO_FORMAT_Y42B:
+      v_subs = 1;
+      h_subs = 2;
+      break;
+    case GST_VIDEO_FORMAT_Y41B:
+      v_subs = 1;
+      h_subs = 4;
+      break;
+    default:
+      g_assert_not_reached ();
+      return;
+  }
+
+  if (alpha->in_sdtv == alpha->out_sdtv) {
+    for (i = 0; i < height; i++) {
+      for (j = 0; j < width; j++) {
+        a = b_alpha;
+        y = srcY[0];
+        u = srcU[0] - 128;
+        v = srcV[0] - 128;
+
+        a = chroma_keying_yuv (a, &y, &u, &v, cr, cb, smin,
+            smax, accept_angle_tg, accept_angle_ctg,
+            one_over_kc, kfgy_scale, kg, noise_level2);
+
+        u += 128;
+        v += 128;
+
+        dest[0] = a;
+        dest[1] = y;
+        dest[2] = u;
+        dest[3] = v;
+
+        dest += 4;
+        srcY++;
+        if ((j + 1) % h_subs == 0) {
+          srcU++;
+          srcV++;
+        }
+      }
+
+      srcY_tmp = srcY = srcY_tmp + y_stride;
+      if ((i + 1) % v_subs == 0) {
+        srcU_tmp = srcU = srcU_tmp + uv_stride;
+        srcV_tmp = srcV = srcV_tmp + uv_stride;
+      } else {
+        srcU = srcU_tmp;
+        srcV = srcV_tmp;
+      }
+    }
+  } else {
+    gint matrix[12];
+
+    memcpy (matrix,
+        alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+
+    for (i = 0; i < height; i++) {
+      for (j = 0; j < width; j++) {
+        a = b_alpha;
+        y = APPLY_MATRIX (matrix, 0, srcY[0], srcU[0], srcV[0]);
+        u = APPLY_MATRIX (matrix, 1, srcY[0], srcU[0], srcV[0]) - 128;
+        v = APPLY_MATRIX (matrix, 2, srcY[0], srcU[0], srcV[0]) - 128;
+
+        a = chroma_keying_yuv (a, &y, &u, &v, cr, cb, smin,
+            smax, accept_angle_tg, accept_angle_ctg,
+            one_over_kc, kfgy_scale, kg, noise_level2);
+
+        dest[0] = a;
+        dest[1] = y;
+        dest[2] = u + 128;
+        dest[3] = v + 128;
+
+        dest += 4;
+        srcY++;
+        if ((j + 1) % h_subs == 0) {
+          srcU++;
+          srcV++;
+        }
+      }
+
+      srcY_tmp = srcY = srcY_tmp + y_stride;
+      if ((i + 1) % v_subs == 0) {
+        srcU_tmp = srcU = srcU_tmp + uv_stride;
+        srcV_tmp = srcV = srcV_tmp + uv_stride;
+      } else {
+        srcU = srcU_tmp;
+        srcV = srcV_tmp;
+      }
+    }
+  }
+}
+
+static void
+gst_alpha_set_planar_yuv_argb (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  guint8 *dest;
+  gint width, height;
+  gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
+  const guint8 *srcY, *srcY_tmp;
+  const guint8 *srcU, *srcU_tmp;
+  const guint8 *srcV, *srcV_tmp;
+  gint i, j;
+  gint y_stride, uv_stride;
+  gint v_subs, h_subs;
+  gint matrix[12];
+  gint a, y, u, v;
+  gint r, g, b;
+  gint p[4];
+
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
+  p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
+  p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
+  p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
+
+  y_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
+  uv_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 1);
+
+  srcY_tmp = srcY = GST_VIDEO_FRAME_COMP_DATA (in_frame, 0);
+  srcU_tmp = srcU = GST_VIDEO_FRAME_COMP_DATA (in_frame, 1);
+  srcV_tmp = srcV = GST_VIDEO_FRAME_COMP_DATA (in_frame, 2);
+
+  switch (GST_VIDEO_FRAME_FORMAT (in_frame)) {
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+      v_subs = h_subs = 2;
+      break;
+    case GST_VIDEO_FORMAT_Y444:
+      v_subs = h_subs = 1;
+      break;
+    case GST_VIDEO_FORMAT_Y42B:
+      v_subs = 1;
+      h_subs = 2;
+      break;
+    case GST_VIDEO_FORMAT_Y41B:
+      v_subs = 1;
+      h_subs = 4;
+      break;
+    default:
+      g_assert_not_reached ();
+      return;
+  }
+
+  memcpy (matrix,
+      alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
+      cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      a = b_alpha;
+      y = srcY[0];
+      u = srcU[0];
+      v = srcV[0];
+
+      dest[p[0]] = a;
+      r = APPLY_MATRIX (matrix, 0, y, u, v);
+      g = APPLY_MATRIX (matrix, 1, y, u, v);
+      b = APPLY_MATRIX (matrix, 2, y, u, v);
+      dest[p[1]] = CLAMP (r, 0, 255);
+      dest[p[2]] = CLAMP (g, 0, 255);
+      dest[p[3]] = CLAMP (b, 0, 255);
+
+      dest += 4;
+      srcY++;
+      if ((j + 1) % h_subs == 0) {
+        srcU++;
+        srcV++;
+      }
+    }
+
+    srcY_tmp = srcY = srcY_tmp + y_stride;
+    if ((i + 1) % v_subs == 0) {
+      srcU_tmp = srcU = srcU_tmp + uv_stride;
+      srcV_tmp = srcV = srcV_tmp + uv_stride;
+    } else {
+      srcU = srcU_tmp;
+      srcV = srcV_tmp;
+    }
+  }
+}
+
+static void
+gst_alpha_chroma_key_planar_yuv_argb (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  guint8 *dest;
+  gint width, height;
+  gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
+  const guint8 *srcY, *srcY_tmp;
+  const guint8 *srcU, *srcU_tmp;
+  const guint8 *srcV, *srcV_tmp;
+  gint i, j;
+  gint a, y, u, v;
+  gint r, g, b;
+  gint y_stride, uv_stride;
+  gint v_subs, h_subs;
+  gint smin = 128 - alpha->black_sensitivity;
+  gint smax = 128 + alpha->white_sensitivity;
+  gint8 cb = alpha->cb, cr = alpha->cr;
+  gint8 kg = alpha->kg;
+  guint8 accept_angle_tg = alpha->accept_angle_tg;
+  guint8 accept_angle_ctg = alpha->accept_angle_ctg;
+  guint8 one_over_kc = alpha->one_over_kc;
+  guint8 kfgy_scale = alpha->kfgy_scale;
+  guint noise_level2 = alpha->noise_level2;
+  gint matrix[12];
+  gint p[4];
+
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
+  p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
+  p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
+  p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
+
+  y_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
+  uv_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 1);
+
+  srcY_tmp = srcY = GST_VIDEO_FRAME_COMP_DATA (in_frame, 0);
+  srcU_tmp = srcU = GST_VIDEO_FRAME_COMP_DATA (in_frame, 1);
+  srcV_tmp = srcV = GST_VIDEO_FRAME_COMP_DATA (in_frame, 2);
+
+  switch (GST_VIDEO_FRAME_FORMAT (in_frame)) {
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+      v_subs = h_subs = 2;
+      break;
+    case GST_VIDEO_FORMAT_Y444:
+      v_subs = h_subs = 1;
+      break;
+    case GST_VIDEO_FORMAT_Y42B:
+      v_subs = 1;
+      h_subs = 2;
+      break;
+    case GST_VIDEO_FORMAT_Y41B:
+      v_subs = 1;
+      h_subs = 4;
+      break;
+    default:
+      g_assert_not_reached ();
+      return;
+  }
+
+  memcpy (matrix,
+      alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
+      cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      a = b_alpha;
+      y = srcY[0];
+      u = srcU[0] - 128;
+      v = srcV[0] - 128;
+
+      a = chroma_keying_yuv (a, &y, &u, &v, cr, cb, smin,
+          smax, accept_angle_tg, accept_angle_ctg,
+          one_over_kc, kfgy_scale, kg, noise_level2);
+
+      u += 128;
+      v += 128;
+
+      dest[p[0]] = a;
+      r = APPLY_MATRIX (matrix, 0, y, u, v);
+      g = APPLY_MATRIX (matrix, 1, y, u, v);
+      b = APPLY_MATRIX (matrix, 2, y, u, v);
+      dest[p[1]] = CLAMP (r, 0, 255);
+      dest[p[2]] = CLAMP (g, 0, 255);
+      dest[p[3]] = CLAMP (b, 0, 255);
+
+      dest += 4;
+      srcY++;
+      if ((j + 1) % h_subs == 0) {
+        srcU++;
+        srcV++;
+      }
+    }
+
+    srcY_tmp = srcY = srcY_tmp + y_stride;
+    if ((i + 1) % v_subs == 0) {
+      srcU_tmp = srcU = srcU_tmp + uv_stride;
+      srcV_tmp = srcV = srcV_tmp + uv_stride;
+    } else {
+      srcU = srcU_tmp;
+      srcV = srcV_tmp;
+    }
+  }
+}
+
+static void
+gst_alpha_set_packed_422_ayuv (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
+  gint i, j;
+  gint y, u, v;
+  gint p[4];                    /* Y U Y V */
+  gint src_stride;
+  const guint8 *src_tmp;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  src_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
+
+  p[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
+  p[2] = p[0] + 2;
+  p[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
+  p[3] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
+
+  if (alpha->in_sdtv != alpha->out_sdtv) {
+    gint matrix[12];
+
+    memcpy (matrix,
+        alpha->in_sdtv ? cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit :
+        cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit, 12 * sizeof (gint));
+
+    for (i = 0; i < height; i++) {
+      src_tmp = src;
+
+      for (j = 0; j < width - 1; j += 2) {
+        dest[0] = s_alpha;
+        dest[4] = s_alpha;
+
+        y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
+        u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]);
+        v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]);
+
+        dest[1] = y;
+        dest[2] = u;
+        dest[3] = v;
+
+        y = APPLY_MATRIX (matrix, 0, src[p[2]], src[p[1]], src[p[3]]);
+        u = APPLY_MATRIX (matrix, 1, src[p[2]], src[p[1]], src[p[3]]);
+        v = APPLY_MATRIX (matrix, 2, src[p[2]], src[p[1]], src[p[3]]);
+
+        dest[5] = y;
+        dest[6] = u;
+        dest[7] = v;
+
+        dest += 8;
+        src += 4;
+      }
+
+      if (j == width - 1) {
+        dest[0] = s_alpha;
+
+        y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
+        u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]);
+        v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]);
+
+        dest[1] = y;
+        dest[2] = u;
+        dest[3] = v;
+
+        dest += 4;
+      }
+
+      src = src_tmp + src_stride;
+    }
+  } else {
+    for (i = 0; i < height; i++) {
+      src_tmp = src;
+
+      for (j = 0; j < width - 1; j += 2) {
+        dest[0] = s_alpha;
+        dest[4] = s_alpha;
+
+        y = src[p[0]];
+        u = src[p[1]];
+        v = src[p[3]];
+
+        dest[1] = y;
+        dest[2] = u;
+        dest[3] = v;
+
+        y = src[p[2]];
+
+        dest[5] = y;
+        dest[6] = u;
+        dest[7] = v;
+
+        dest += 8;
+        src += 4;
+      }
+
+      if (j == width - 1) {
+        dest[0] = s_alpha;
+
+        y = src[p[0]];
+        u = src[p[1]];
+        v = src[p[3]];
+
+        dest[1] = y;
+        dest[2] = u;
+        dest[3] = v;
+
+        dest += 4;
+      }
+
+      src = src_tmp + src_stride;
+    }
+  }
+}
+
+static void
+gst_alpha_chroma_key_packed_422_ayuv (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint i, j;
+  gint a, y, u, v;
+  gint smin, smax;
+  gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
+  gint8 cb = alpha->cb, cr = alpha->cr;
+  gint8 kg = alpha->kg;
+  guint8 accept_angle_tg = alpha->accept_angle_tg;
+  guint8 accept_angle_ctg = alpha->accept_angle_ctg;
+  guint8 one_over_kc = alpha->one_over_kc;
+  guint8 kfgy_scale = alpha->kfgy_scale;
+  guint noise_level2 = alpha->noise_level2;
+  gint p[4];                    /* Y U Y V */
+  gint src_stride;
+  const guint8 *src_tmp;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  src_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
+
+  p[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
+  p[2] = p[0] + 2;
+  p[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
+  p[3] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
+
+  smin = 128 - alpha->black_sensitivity;
+  smax = 128 + alpha->white_sensitivity;
+
+  if (alpha->in_sdtv != alpha->out_sdtv) {
+    gint matrix[12];
+
+    memcpy (matrix,
+        alpha->in_sdtv ? cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit :
+        cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit, 12 * sizeof (gint));
+
+    for (i = 0; i < height; i++) {
+      src_tmp = src;
+
+      for (j = 0; j < width - 1; j += 2) {
+        y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
+        u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]) - 128;
+        v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]) - 128;
+
+        a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
+            smin, smax, accept_angle_tg, accept_angle_ctg,
+            one_over_kc, kfgy_scale, kg, noise_level2);
+
+        dest[0] = a;
+        dest[1] = y;
+        dest[2] = u + 128;
+        dest[3] = v + 128;
+
+        y = APPLY_MATRIX (matrix, 0, src[p[2]], src[p[1]], src[p[3]]);
+        u = APPLY_MATRIX (matrix, 1, src[p[2]], src[p[1]], src[p[3]]) - 128;
+        v = APPLY_MATRIX (matrix, 2, src[p[2]], src[p[1]], src[p[3]]) - 128;
+
+        a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
+            smin, smax, accept_angle_tg, accept_angle_ctg,
+            one_over_kc, kfgy_scale, kg, noise_level2);
+
+        dest[4] = a;
+        dest[5] = y;
+        dest[6] = u + 128;
+        dest[7] = v + 128;
+
+        dest += 8;
+        src += 4;
+      }
+
+      if (j == width - 1) {
+        y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
+        u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]) - 128;
+        v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]) - 128;
+
+        a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
+            smin, smax, accept_angle_tg, accept_angle_ctg,
+            one_over_kc, kfgy_scale, kg, noise_level2);
+
+        dest[0] = a;
+        dest[1] = y;
+        dest[2] = u + 128;
+        dest[3] = v + 128;
+
+        dest += 4;
+      }
+
+      src = src_tmp + src_stride;
+    }
+  } else {
+    for (i = 0; i < height; i++) {
+      src_tmp = src;
+
+      for (j = 0; j < width - 1; j += 2) {
+        y = src[p[0]];
+        u = src[p[1]] - 128;
+        v = src[p[3]] - 128;
+
+        a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
+            smin, smax, accept_angle_tg, accept_angle_ctg,
+            one_over_kc, kfgy_scale, kg, noise_level2);
+
+        dest[0] = a;
+        dest[1] = y;
+        dest[2] = u + 128;
+        dest[3] = v + 128;
+
+        y = src[p[2]];
+        u = src[p[1]] - 128;
+        v = src[p[3]] - 128;
+
+        a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
+            smin, smax, accept_angle_tg, accept_angle_ctg,
+            one_over_kc, kfgy_scale, kg, noise_level2);
+
+        dest[4] = a;
+        dest[5] = y;
+        dest[6] = u + 128;
+        dest[7] = v + 128;
+
+        dest += 8;
+        src += 4;
+      }
+
+      if (j == width - 1) {
+        y = src[p[0]];
+        u = src[p[1]] - 128;
+        v = src[p[3]] - 128;
+
+        a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
+            smin, smax, accept_angle_tg, accept_angle_ctg,
+            one_over_kc, kfgy_scale, kg, noise_level2);
+
+        dest[0] = a;
+        dest[1] = y;
+        dest[2] = u + 128;
+        dest[3] = v + 128;
+
+        dest += 4;
+      }
+
+      src = src_tmp + src_stride;
+    }
+  }
+}
+
+static void
+gst_alpha_set_packed_422_argb (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
+  gint i, j;
+  gint p[4], o[4];
+  gint src_stride;
+  const guint8 *src_tmp;
+  gint matrix[12];
+  gint r, g, b;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  src_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
+
+  o[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
+  o[2] = o[0] + 2;
+  o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
+  o[3] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
+
+  p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
+  p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
+  p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
+  p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
+
+  memcpy (matrix,
+      alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
+      cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
+
+  for (i = 0; i < height; i++) {
+    src_tmp = src;
+
+    for (j = 0; j < width - 1; j += 2) {
+      r = APPLY_MATRIX (matrix, 0, src[o[0]], src[o[1]], src[o[3]]);
+      g = APPLY_MATRIX (matrix, 1, src[o[0]], src[o[1]], src[o[3]]);
+      b = APPLY_MATRIX (matrix, 2, src[o[0]], src[o[1]], src[o[3]]);
+
+      dest[p[0]] = s_alpha;
+      dest[p[1]] = CLAMP (r, 0, 255);
+      dest[p[2]] = CLAMP (g, 0, 255);
+      dest[p[3]] = CLAMP (b, 0, 255);
+
+      r = APPLY_MATRIX (matrix, 0, src[o[2]], src[o[1]], src[o[3]]);
+      g = APPLY_MATRIX (matrix, 1, src[o[2]], src[o[1]], src[o[3]]);
+      b = APPLY_MATRIX (matrix, 2, src[o[2]], src[o[1]], src[o[3]]);
+
+      dest[4 + p[0]] = s_alpha;
+      dest[4 + p[1]] = CLAMP (r, 0, 255);
+      dest[4 + p[2]] = CLAMP (g, 0, 255);
+      dest[4 + p[3]] = CLAMP (b, 0, 255);
+
+      dest += 8;
+      src += 4;
+    }
+
+    if (j == width - 1) {
+      r = APPLY_MATRIX (matrix, 0, src[o[0]], src[o[1]], src[o[3]]);
+      g = APPLY_MATRIX (matrix, 1, src[o[0]], src[o[1]], src[o[3]]);
+      b = APPLY_MATRIX (matrix, 2, src[o[0]], src[o[1]], src[o[3]]);
+
+      dest[p[0]] = s_alpha;
+      dest[p[1]] = CLAMP (r, 0, 255);
+      dest[p[2]] = CLAMP (g, 0, 255);
+      dest[p[3]] = CLAMP (b, 0, 255);
+
+      dest += 4;
+    }
+
+    src = src_tmp + src_stride;
+  }
+}
+
+static void
+gst_alpha_chroma_key_packed_422_argb (const GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame, GstAlpha * alpha)
+{
+  const guint8 *src;
+  guint8 *dest;
+  gint width, height;
+  gint i, j;
+  gint a, y, u, v;
+  gint r, g, b;
+  gint smin, smax;
+  gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
+  gint8 cb = alpha->cb, cr = alpha->cr;
+  gint8 kg = alpha->kg;
+  guint8 accept_angle_tg = alpha->accept_angle_tg;
+  guint8 accept_angle_ctg = alpha->accept_angle_ctg;
+  guint8 one_over_kc = alpha->one_over_kc;
+  guint8 kfgy_scale = alpha->kfgy_scale;
+  guint noise_level2 = alpha->noise_level2;
+  gint p[4], o[4];
+  gint src_stride;
+  const guint8 *src_tmp;
+  gint matrix[12];
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  src_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
+
+  o[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
+  o[2] = o[0] + 2;
+  o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
+  o[3] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
+
+  p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
+  p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
+  p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
+  p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
+
+  memcpy (matrix,
+      alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
+      cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
+
+  smin = 128 - alpha->black_sensitivity;
+  smax = 128 + alpha->white_sensitivity;
+
+  for (i = 0; i < height; i++) {
+    src_tmp = src;
+
+    for (j = 0; j < width - 1; j += 2) {
+      y = src[o[0]];
+      u = src[o[1]] - 128;
+      v = src[o[3]] - 128;
+
+      a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
+          smin, smax, accept_angle_tg, accept_angle_ctg,
+          one_over_kc, kfgy_scale, kg, noise_level2);
+      u += 128;
+      v += 128;
+
+      r = APPLY_MATRIX (matrix, 0, y, u, v);
+      g = APPLY_MATRIX (matrix, 1, y, u, v);
+      b = APPLY_MATRIX (matrix, 2, y, u, v);
+
+      dest[p[0]] = a;
+      dest[p[1]] = CLAMP (r, 0, 255);
+      dest[p[2]] = CLAMP (g, 0, 255);
+      dest[p[3]] = CLAMP (b, 0, 255);
+
+      y = src[o[2]];
+      u = src[o[1]] - 128;
+      v = src[o[3]] - 128;
+
+      a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
+          smin, smax, accept_angle_tg, accept_angle_ctg,
+          one_over_kc, kfgy_scale, kg, noise_level2);
+      u += 128;
+      v += 128;
+
+      r = APPLY_MATRIX (matrix, 0, y, u, v);
+      g = APPLY_MATRIX (matrix, 1, y, u, v);
+      b = APPLY_MATRIX (matrix, 2, y, u, v);
+
+      dest[4 + p[0]] = a;
+      dest[4 + p[1]] = CLAMP (r, 0, 255);
+      dest[4 + p[2]] = CLAMP (g, 0, 255);
+      dest[4 + p[3]] = CLAMP (b, 0, 255);
+
+      dest += 8;
+      src += 4;
+    }
+
+    if (j == width - 1) {
+      y = src[o[0]];
+      u = src[o[1]] - 128;
+      v = src[o[3]] - 128;
+
+      a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
+          smin, smax, accept_angle_tg, accept_angle_ctg,
+          one_over_kc, kfgy_scale, kg, noise_level2);
+      u += 128;
+      v += 128;
+
+      r = APPLY_MATRIX (matrix, 0, y, u, v);
+      g = APPLY_MATRIX (matrix, 1, y, u, v);
+      b = APPLY_MATRIX (matrix, 2, y, u, v);
+
+      dest[p[0]] = a;
+      dest[p[1]] = CLAMP (r, 0, 255);
+      dest[p[2]] = CLAMP (g, 0, 255);
+      dest[p[3]] = CLAMP (b, 0, 255);
+
+      dest += 4;
+    }
+
+    src = src_tmp + src_stride;
+  }
+}
+
+/* Protected with the alpha lock */
+static void
+gst_alpha_init_params_full (GstAlpha * alpha,
+    const GstVideoFormatInfo * in_info, const GstVideoFormatInfo * out_info)
+{
+  gfloat kgl;
+  gfloat tmp;
+  gfloat tmp1, tmp2;
+  gfloat y;
+  guint target_r = alpha->target_r;
+  guint target_g = alpha->target_g;
+  guint target_b = alpha->target_b;
+  const gint *matrix;
+
+  switch (alpha->method) {
+    case ALPHA_METHOD_GREEN:
+      target_r = 0;
+      target_g = 255;
+      target_b = 0;
+      break;
+    case ALPHA_METHOD_BLUE:
+      target_r = 0;
+      target_g = 0;
+      target_b = 255;
+      break;
+    default:
+      break;
+  }
+
+  /* RGB->RGB: convert to SDTV YUV, chroma keying, convert back
+   * YUV->RGB: chroma keying, convert to RGB
+   * RGB->YUV: convert to YUV, chroma keying
+   * YUV->YUV: convert matrix, chroma keying
+   */
+  if (GST_VIDEO_FORMAT_INFO_IS_RGB (in_info)
+      && GST_VIDEO_FORMAT_INFO_IS_RGB (out_info))
+    matrix = cog_rgb_to_ycbcr_matrix_8bit_sdtv;
+  else if (GST_VIDEO_FORMAT_INFO_IS_YUV (in_info)
+      && GST_VIDEO_FORMAT_INFO_IS_RGB (out_info))
+    matrix =
+        (alpha->in_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
+        cog_rgb_to_ycbcr_matrix_8bit_hdtv;
+  else if (GST_VIDEO_FORMAT_INFO_IS_RGB (in_info)
+      && GST_VIDEO_FORMAT_INFO_IS_YUV (out_info))
+    matrix =
+        (alpha->out_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
+        cog_rgb_to_ycbcr_matrix_8bit_hdtv;
+  else                          /* yuv -> yuv */
+    matrix =
+        (alpha->out_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
+        cog_rgb_to_ycbcr_matrix_8bit_hdtv;
+
+  y = (matrix[0] * ((gint) target_r) +
+      matrix[1] * ((gint) target_g) +
+      matrix[2] * ((gint) target_b) + matrix[3]) >> 8;
+  /* Cb,Cr without offset here because the chroma keying
+   * works with them being in range [-128,127]
+   */
+  tmp1 =
+      (matrix[4] * ((gint) target_r) +
+      matrix[5] * ((gint) target_g) + matrix[6] * ((gint) target_b)) >> 8;
+  tmp2 =
+      (matrix[8] * ((gint) target_r) +
+      matrix[9] * ((gint) target_g) + matrix[10] * ((gint) target_b)) >> 8;
+
+  kgl = sqrt (tmp1 * tmp1 + tmp2 * tmp2);
+  alpha->cb = 127 * (tmp1 / kgl);
+  alpha->cr = 127 * (tmp2 / kgl);
+
+  tmp = 15 * tan (M_PI * alpha->angle / 180);
+  tmp = MIN (tmp, 255);
+  alpha->accept_angle_tg = tmp;
+  tmp = 15 / tan (M_PI * alpha->angle / 180);
+  tmp = MIN (tmp, 255);
+  alpha->accept_angle_ctg = tmp;
+  tmp = 1 / (kgl);
+  alpha->one_over_kc = 255 * 2 * tmp - 255;
+  tmp = 15 * y / kgl;
+  tmp = MIN (tmp, 255);
+  alpha->kfgy_scale = tmp;
+  alpha->kg = MIN (kgl, 127);
+
+  alpha->noise_level2 = alpha->noise_level * alpha->noise_level;
+}
+
+static void
+gst_alpha_init_params (GstAlpha * alpha)
+{
+  const GstVideoFormatInfo *finfo_in, *finfo_out;
+
+  finfo_in = GST_VIDEO_FILTER (alpha)->in_info.finfo;
+  finfo_out = GST_VIDEO_FILTER (alpha)->out_info.finfo;
+
+  if (finfo_in != NULL && finfo_out != NULL) {
+    gst_alpha_init_params_full (alpha, finfo_in, finfo_out);
+  } else {
+    GST_DEBUG_OBJECT (alpha, "video formats not set yet");
+  }
+}
+
+/* Protected with the alpha lock */
+static gboolean
+gst_alpha_set_process_function_full (GstAlpha * alpha, GstVideoInfo * in_info,
+    GstVideoInfo * out_info)
+{
+  alpha->process = NULL;
+
+  switch (alpha->method) {
+    case ALPHA_METHOD_SET:
+      switch (GST_VIDEO_INFO_FORMAT (out_info)) {
+        case GST_VIDEO_FORMAT_AYUV:
+          switch (GST_VIDEO_INFO_FORMAT (in_info)) {
+            case GST_VIDEO_FORMAT_AYUV:
+              alpha->process = gst_alpha_set_ayuv_ayuv;
+              break;
+            case GST_VIDEO_FORMAT_Y444:
+            case GST_VIDEO_FORMAT_Y42B:
+            case GST_VIDEO_FORMAT_I420:
+            case GST_VIDEO_FORMAT_YV12:
+            case GST_VIDEO_FORMAT_Y41B:
+              alpha->process = gst_alpha_set_planar_yuv_ayuv;
+              break;
+            case GST_VIDEO_FORMAT_YUY2:
+            case GST_VIDEO_FORMAT_YVYU:
+            case GST_VIDEO_FORMAT_UYVY:
+              alpha->process = gst_alpha_set_packed_422_ayuv;
+              break;
+            case GST_VIDEO_FORMAT_ARGB:
+            case GST_VIDEO_FORMAT_ABGR:
+            case GST_VIDEO_FORMAT_RGBA:
+            case GST_VIDEO_FORMAT_BGRA:
+              alpha->process = gst_alpha_set_argb_ayuv;
+              break;
+            case GST_VIDEO_FORMAT_xRGB:
+            case GST_VIDEO_FORMAT_xBGR:
+            case GST_VIDEO_FORMAT_RGBx:
+            case GST_VIDEO_FORMAT_BGRx:
+            case GST_VIDEO_FORMAT_RGB:
+            case GST_VIDEO_FORMAT_BGR:
+              alpha->process = gst_alpha_set_rgb_ayuv;
+              break;
+            default:
+              break;
+          }
+          break;
+        case GST_VIDEO_FORMAT_ARGB:
+        case GST_VIDEO_FORMAT_ABGR:
+        case GST_VIDEO_FORMAT_RGBA:
+        case GST_VIDEO_FORMAT_BGRA:
+          switch (GST_VIDEO_INFO_FORMAT (in_info)) {
+            case GST_VIDEO_FORMAT_AYUV:
+              alpha->process = gst_alpha_set_ayuv_argb;
+              break;
+            case GST_VIDEO_FORMAT_Y444:
+            case GST_VIDEO_FORMAT_Y42B:
+            case GST_VIDEO_FORMAT_I420:
+            case GST_VIDEO_FORMAT_YV12:
+            case GST_VIDEO_FORMAT_Y41B:
+              alpha->process = gst_alpha_set_planar_yuv_argb;
+              break;
+            case GST_VIDEO_FORMAT_YUY2:
+            case GST_VIDEO_FORMAT_YVYU:
+            case GST_VIDEO_FORMAT_UYVY:
+              alpha->process = gst_alpha_set_packed_422_argb;
+              break;
+            case GST_VIDEO_FORMAT_ARGB:
+            case GST_VIDEO_FORMAT_ABGR:
+            case GST_VIDEO_FORMAT_RGBA:
+            case GST_VIDEO_FORMAT_BGRA:
+              alpha->process = gst_alpha_set_argb_argb;
+              break;
+            case GST_VIDEO_FORMAT_xRGB:
+            case GST_VIDEO_FORMAT_xBGR:
+            case GST_VIDEO_FORMAT_RGBx:
+            case GST_VIDEO_FORMAT_BGRx:
+            case GST_VIDEO_FORMAT_RGB:
+            case GST_VIDEO_FORMAT_BGR:
+              alpha->process = gst_alpha_set_rgb_argb;
+              break;
+            default:
+              break;
+          }
+          break;
+        default:
+          break;
+      }
+      break;
+    case ALPHA_METHOD_GREEN:
+    case ALPHA_METHOD_BLUE:
+    case ALPHA_METHOD_CUSTOM:
+      switch (GST_VIDEO_INFO_FORMAT (out_info)) {
+        case GST_VIDEO_FORMAT_AYUV:
+          switch (GST_VIDEO_INFO_FORMAT (in_info)) {
+            case GST_VIDEO_FORMAT_AYUV:
+              alpha->process = gst_alpha_chroma_key_ayuv_ayuv;
+              break;
+            case GST_VIDEO_FORMAT_Y444:
+            case GST_VIDEO_FORMAT_Y42B:
+            case GST_VIDEO_FORMAT_I420:
+            case GST_VIDEO_FORMAT_YV12:
+            case GST_VIDEO_FORMAT_Y41B:
+              alpha->process = gst_alpha_chroma_key_planar_yuv_ayuv;
+              break;
+            case GST_VIDEO_FORMAT_YUY2:
+            case GST_VIDEO_FORMAT_YVYU:
+            case GST_VIDEO_FORMAT_UYVY:
+              alpha->process = gst_alpha_chroma_key_packed_422_ayuv;
+              break;
+            case GST_VIDEO_FORMAT_ARGB:
+            case GST_VIDEO_FORMAT_ABGR:
+            case GST_VIDEO_FORMAT_RGBA:
+            case GST_VIDEO_FORMAT_BGRA:
+              alpha->process = gst_alpha_chroma_key_argb_ayuv;
+              break;
+            case GST_VIDEO_FORMAT_xRGB:
+            case GST_VIDEO_FORMAT_xBGR:
+            case GST_VIDEO_FORMAT_RGBx:
+            case GST_VIDEO_FORMAT_BGRx:
+            case GST_VIDEO_FORMAT_RGB:
+            case GST_VIDEO_FORMAT_BGR:
+              alpha->process = gst_alpha_chroma_key_rgb_ayuv;
+              break;
+            default:
+              break;
+          }
+          break;
+        case GST_VIDEO_FORMAT_ARGB:
+        case GST_VIDEO_FORMAT_ABGR:
+        case GST_VIDEO_FORMAT_RGBA:
+        case GST_VIDEO_FORMAT_BGRA:
+          switch (GST_VIDEO_INFO_FORMAT (in_info)) {
+            case GST_VIDEO_FORMAT_AYUV:
+              alpha->process = gst_alpha_chroma_key_ayuv_argb;
+              break;
+            case GST_VIDEO_FORMAT_Y444:
+            case GST_VIDEO_FORMAT_Y42B:
+            case GST_VIDEO_FORMAT_I420:
+            case GST_VIDEO_FORMAT_YV12:
+            case GST_VIDEO_FORMAT_Y41B:
+              alpha->process = gst_alpha_chroma_key_planar_yuv_argb;
+              break;
+            case GST_VIDEO_FORMAT_YUY2:
+            case GST_VIDEO_FORMAT_YVYU:
+            case GST_VIDEO_FORMAT_UYVY:
+              alpha->process = gst_alpha_chroma_key_packed_422_argb;
+              break;
+            case GST_VIDEO_FORMAT_ARGB:
+            case GST_VIDEO_FORMAT_ABGR:
+            case GST_VIDEO_FORMAT_RGBA:
+            case GST_VIDEO_FORMAT_BGRA:
+              alpha->process = gst_alpha_chroma_key_argb_argb;
+              break;
+            case GST_VIDEO_FORMAT_xRGB:
+            case GST_VIDEO_FORMAT_xBGR:
+            case GST_VIDEO_FORMAT_RGBx:
+            case GST_VIDEO_FORMAT_BGRx:
+            case GST_VIDEO_FORMAT_RGB:
+            case GST_VIDEO_FORMAT_BGR:
+              alpha->process = gst_alpha_chroma_key_rgb_argb;
+              break;
+            default:
+              break;
+          }
+          break;
+        default:
+          break;
+      }
+      break;
+    default:
+      break;
+  }
+  return alpha->process != NULL;
+}
+
+static void
+gst_alpha_set_process_function (GstAlpha * alpha)
+{
+  GstVideoInfo *info_in, *info_out;
+
+  info_in = &GST_VIDEO_FILTER (alpha)->in_info;
+  info_out = &GST_VIDEO_FILTER (alpha)->out_info;
+
+  if (info_in->finfo != NULL && info_out->finfo != NULL) {
+    gst_alpha_set_process_function_full (alpha, info_in, info_out);
+  } else {
+    GST_DEBUG_OBJECT (alpha, "video formats not set yet");
+  }
+}
+
+static void
+gst_alpha_before_transform (GstBaseTransform * btrans, GstBuffer * buf)
+{
+  GstAlpha *alpha = GST_ALPHA (btrans);
+  GstClockTime timestamp;
+
+  timestamp = gst_segment_to_stream_time (&btrans->segment, GST_FORMAT_TIME,
+      GST_BUFFER_TIMESTAMP (buf));
+  GST_LOG ("Got stream time of %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp));
+  if (GST_CLOCK_TIME_IS_VALID (timestamp))
+    gst_object_sync_values (GST_OBJECT (alpha), timestamp);
+}
+
+static GstFlowReturn
+gst_alpha_transform_frame (GstVideoFilter * filter, GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame)
+{
+  GstAlpha *alpha = GST_ALPHA (filter);
+
+  GST_ALPHA_LOCK (alpha);
+
+  if (G_UNLIKELY (!alpha->process))
+    goto not_negotiated;
+
+  alpha->process (in_frame, out_frame, alpha);
+
+  GST_ALPHA_UNLOCK (alpha);
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+not_negotiated:
+  {
+    GST_ERROR_OBJECT (alpha, "Not negotiated yet");
+    GST_ALPHA_UNLOCK (alpha);
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "alpha", GST_RANK_NONE, GST_TYPE_ALPHA);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    alpha,
+    "adds an alpha channel to video - constant or via chroma-keying",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/alpha/gstalpha.h b/gst/alpha/gstalpha.h
new file mode 100644
index 0000000..948fb78
--- /dev/null
+++ b/gst/alpha/gstalpha.h
@@ -0,0 +1,114 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@collabora.co.uk>
+ * Copyright (C) <2007> Edward Hervey <edward.hervey@collabora.co.uk>
+ * Copyright (C) <2007> Jan Schmidt <thaytan@noraisin.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_ALPHA_H__
+#define __GST_ALPHA_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_ALPHA \
+  (gst_alpha_get_type())
+#define GST_ALPHA(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALPHA,GstAlpha))
+#define GST_ALPHA_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALPHA,GstAlphaClass))
+#define GST_IS_ALPHA(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALPHA))
+#define GST_IS_ALPHA_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALPHA))
+
+typedef struct _GstAlpha GstAlpha;
+typedef struct _GstAlphaClass GstAlphaClass;
+
+/** 
+ * GstAlphaMethod:
+ * @ALPHA_METHOD_SET: Set/adjust alpha channel
+ * @ALPHA_METHOD_GREEN: Chroma Key green
+ * @ALPHA_METHOD_BLUE: Chroma Key blue
+ * @ALPHA_METHOD_CUSTOM: Chroma Key on target_r/g/b
+ */
+typedef enum
+{
+  ALPHA_METHOD_SET,
+  ALPHA_METHOD_GREEN,
+  ALPHA_METHOD_BLUE,
+  ALPHA_METHOD_CUSTOM,
+}
+GstAlphaMethod;
+
+GST_DEBUG_CATEGORY_STATIC (gst_alpha_debug);
+#define GST_CAT_DEFAULT gst_alpha_debug
+
+struct _GstAlpha
+{
+  GstVideoFilter parent;
+
+  /* <private> */
+
+  /* caps */
+  GMutex lock;
+
+  gboolean in_sdtv, out_sdtv;
+
+  /* properties */
+  gdouble alpha;
+
+  guint target_r;
+  guint target_g;
+  guint target_b;
+
+  GstAlphaMethod method;
+
+  gfloat angle;
+  gfloat noise_level;
+  guint black_sensitivity;
+  guint white_sensitivity;
+
+  gboolean prefer_passthrough;
+
+  /* processing function */
+  void (*process) (const GstVideoFrame *in_frame, GstVideoFrame *out_frame, GstAlpha *alpha);
+
+  /* precalculated values for chroma keying */
+  gint8 cb, cr;
+  gint8 kg;
+  guint8 accept_angle_tg;
+  guint8 accept_angle_ctg;
+  guint8 one_over_kc;
+  guint8 kfgy_scale;
+  guint noise_level2;
+};
+
+struct _GstAlphaClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_alpha_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_ALPHA_H__ */
diff --git a/gst/alpha/gstalphacolor.c b/gst/alpha/gstalphacolor.c
new file mode 100644
index 0000000..e082e74
--- /dev/null
+++ b/gst/alpha/gstalphacolor.c
@@ -0,0 +1,707 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-alphacolor
+ *
+ * The alphacolor element does memory-efficient (in-place) colourspace
+ * conversion from RGBA to AYUV or AYUV to RGBA while preserving the
+ * alpha channel.
+ *
+ * Sample pipeline:
+ * |[
+ * gst-launch-1.0 videotestsrc ! "video/x-raw,format=(fourcc)AYUV" ! \
+ *   alphacolor ! videoconvert ! autovideosink
+ * ]|
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstalphacolor.h"
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include <string.h>
+
+GST_DEBUG_CATEGORY_STATIC (alpha_color_debug);
+#define GST_CAT_DEFAULT alpha_color_debug
+
+/* elementfactory information */
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBA, BGRA, ARGB, ABGR, AYUV }"))
+    );
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBA, BGRA, ARGB, ABGR, AYUV }"))
+    );
+
+G_DEFINE_TYPE (GstAlphaColor, gst_alpha_color, GST_TYPE_VIDEO_FILTER);
+
+static GstCaps *gst_alpha_color_transform_caps (GstBaseTransform * btrans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * filter);
+
+static gboolean gst_alpha_color_set_info (GstVideoFilter * filter,
+    GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
+    GstVideoInfo * out_info);
+static GstFlowReturn gst_alpha_color_transform_frame_ip (GstVideoFilter *
+    filter, GstVideoFrame * frame);
+
+static void
+gst_alpha_color_class_init (GstAlphaColorClass * klass)
+{
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBaseTransformClass *gstbasetransform_class =
+      (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *gstvideofilter_class = (GstVideoFilterClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (alpha_color_debug, "alphacolor", 0,
+      "ARGB<->AYUV colorspace conversion preserving the alpha channels");
+
+  gst_element_class_set_static_metadata (gstelement_class, "Alpha color filter",
+      "Filter/Converter/Video",
+      "ARGB from/to AYUV colorspace conversion preserving the alpha channel",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class, &src_template);
+
+  gstbasetransform_class->transform_caps =
+      GST_DEBUG_FUNCPTR (gst_alpha_color_transform_caps);
+  gstbasetransform_class->transform_ip_on_passthrough = FALSE;
+
+  gstvideofilter_class->set_info = GST_DEBUG_FUNCPTR (gst_alpha_color_set_info);
+  gstvideofilter_class->transform_frame_ip =
+      GST_DEBUG_FUNCPTR (gst_alpha_color_transform_frame_ip);
+}
+
+static void
+gst_alpha_color_init (GstAlphaColor * alpha)
+{
+  GstBaseTransform *btrans = GST_BASE_TRANSFORM (alpha);
+
+  gst_base_transform_set_in_place (btrans, TRUE);
+}
+
+static GstCaps *
+gst_alpha_color_transform_caps (GstBaseTransform * btrans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
+{
+  GstCaps *tmpl_caps = NULL;
+  GstCaps *result = NULL, *local_caps = NULL;
+  guint i;
+
+  local_caps = gst_caps_new_empty ();
+
+  for (i = 0; i < gst_caps_get_size (caps); i++) {
+    GstStructure *structure =
+        gst_structure_copy (gst_caps_get_structure (caps, i));
+
+    /* Remove any specific parameter from the structure */
+    gst_structure_remove_field (structure, "format");
+    gst_structure_remove_field (structure, "colorimetry");
+    gst_structure_remove_field (structure, "chroma-site");
+
+    gst_structure_set_name (structure, "video/x-raw");
+    gst_caps_append_structure (local_caps, structure);
+  }
+
+  /* Get the appropriate template */
+  if (direction == GST_PAD_SINK) {
+    tmpl_caps = gst_static_pad_template_get_caps (&src_template);
+  } else if (direction == GST_PAD_SRC) {
+    tmpl_caps = gst_static_pad_template_get_caps (&sink_template);
+  }
+
+  /* Intersect with our template caps */
+  result = gst_caps_intersect (local_caps, tmpl_caps);
+  gst_caps_unref (tmpl_caps);
+  gst_caps_unref (local_caps);
+
+  result = gst_caps_simplify (result);
+
+  GST_LOG_OBJECT (btrans, "transformed %" GST_PTR_FORMAT " to %" GST_PTR_FORMAT,
+      caps, result);
+
+  if (filter) {
+    GstCaps *intersection;
+
+    GST_DEBUG_OBJECT (btrans, "Using filter caps %" GST_PTR_FORMAT, filter);
+    intersection =
+        gst_caps_intersect_full (filter, result, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (result);
+    result = intersection;
+    GST_DEBUG_OBJECT (btrans, "Intersection %" GST_PTR_FORMAT, result);
+  }
+
+
+  return result;
+}
+
+/* Generated by -bad/ext/cog/generate_tables */
+static const int cog_ycbcr_to_rgb_matrix_8bit_hdtv[] = {
+  298, 0, 459, -63514,
+  298, -55, -136, 19681,
+  298, 541, 0, -73988,
+};
+
+static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
+  298, 0, 409, -57068,
+  298, -100, -208, 34707,
+  298, 516, 0, -70870,
+};
+
+static const gint cog_rgb_to_ycbcr_matrix_8bit_hdtv[] = {
+  47, 157, 16, 4096,
+  -26, -87, 112, 32768,
+  112, -102, -10, 32768,
+};
+
+static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
+  66, 129, 25, 4096,
+  -38, -74, 112, 32768,
+  112, -94, -18, 32768,
+};
+
+static const gint cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit[] = {
+  256, -30, -53, 10600,
+  0, 261, 29, -4367,
+  0, 19, 262, -3289,
+};
+
+static const gint cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit[] = {
+  256, 25, 49, -9536,
+  0, 253, -28, 3958,
+  0, -19, 252, 2918,
+};
+
+#define DEFINE_ARGB_AYUV_FUNCTIONS(name, A, R, G, B) \
+static void \
+transform_##name##_ayuv (GstVideoFrame * frame, const gint *matrix) \
+{ \
+  guint8 *data; \
+  gsize size; \
+  gint y, u, v; \
+  gint yc[4]; \
+  gint uc[4]; \
+  gint vc[4]; \
+  \
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);\
+  size = GST_VIDEO_FRAME_SIZE (frame);\
+  \
+  memcpy (yc, matrix, 4 * sizeof (gint)); \
+  memcpy (uc, matrix + 4, 4 * sizeof (gint)); \
+  memcpy (vc, matrix + 8, 4 * sizeof (gint)); \
+  \
+  while (size > 0) { \
+    y = (data[R] * yc[0] + data[G] * yc[1] + data[B] * yc[2] + yc[3]) >> 8; \
+    u = (data[R] * uc[0] + data[G] * uc[1] + data[B] * uc[2] + uc[3]) >> 8; \
+    v = (data[R] * vc[0] + data[G] * vc[1] + data[B] * vc[2] + vc[3]) >> 8; \
+    \
+    data[0] = data[A]; \
+    data[1] = y; \
+    data[2] = u; \
+    data[3] = v; \
+    \
+    data += 4; \
+    size -= 4; \
+  } \
+} \
+\
+static void \
+transform_ayuv_##name (GstVideoFrame * frame, const gint *matrix) \
+{ \
+  guint8 *data; \
+  gsize size; \
+  gint r, g, b; \
+  gint rc[4]; \
+  gint gc[4]; \
+  gint bc[4]; \
+  \
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);\
+  size = GST_VIDEO_FRAME_SIZE (frame);\
+  \
+  memcpy (rc, matrix, 4 * sizeof (gint)); \
+  memcpy (gc, matrix + 4, 4 * sizeof (gint)); \
+  memcpy (bc, matrix + 8, 4 * sizeof (gint)); \
+  \
+  while (size > 0) { \
+    r = (data[1] * rc[0] + data[2] * rc[1] + data[3] * rc[2] + rc[3]) >> 8; \
+    g = (data[1] * gc[0] + data[2] * gc[1] + data[3] * gc[2] + gc[3]) >> 8; \
+    b = (data[1] * bc[0] + data[2] * bc[1] + data[3] * bc[2] + bc[3]) >> 8; \
+    \
+    data[A] = data[0]; \
+    data[R] = CLAMP (r, 0, 255); \
+    data[G] = CLAMP (g, 0, 255); \
+    data[B] = CLAMP (b, 0, 255); \
+    \
+    data += 4; \
+    size -= 4; \
+  } \
+}
+
+DEFINE_ARGB_AYUV_FUNCTIONS (rgba, 3, 0, 1, 2);
+DEFINE_ARGB_AYUV_FUNCTIONS (bgra, 3, 2, 1, 0);
+DEFINE_ARGB_AYUV_FUNCTIONS (argb, 0, 1, 2, 3);
+DEFINE_ARGB_AYUV_FUNCTIONS (abgr, 0, 3, 2, 1);
+
+static void
+transform_ayuv_ayuv (GstVideoFrame * frame, const gint * matrix)
+{
+  guint8 *data;
+  gsize size;
+  gint y, u, v;
+  gint yc[4];
+  gint uc[4];
+  gint vc[4];
+
+  if (matrix == NULL)
+    return;
+
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  size = GST_VIDEO_FRAME_SIZE (frame);
+
+  memcpy (yc, matrix, 4 * sizeof (gint));
+  memcpy (uc, matrix + 4, 4 * sizeof (gint));
+  memcpy (vc, matrix + 8, 4 * sizeof (gint));
+
+  while (size > 0) {
+    y = (data[1] * yc[0] + data[2] * yc[1] + data[3] * yc[2] + yc[3]) >> 8;
+    u = (data[1] * uc[0] + data[2] * uc[1] + data[3] * uc[2] + uc[3]) >> 8;
+    v = (data[1] * vc[0] + data[2] * vc[1] + data[3] * vc[2] + vc[3]) >> 8;
+
+    data[1] = y;
+    data[2] = u;
+    data[3] = v;
+
+    data += 4;
+    size -= 4;
+  }
+}
+
+static void
+transform_argb_bgra (GstVideoFrame * frame, const gint * matrix)
+{
+  guint8 *data;
+  gsize size;
+  gint r, g, b;
+
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  size = GST_VIDEO_FRAME_SIZE (frame);
+
+  while (size > 0) {
+    r = data[1];
+    g = data[2];
+    b = data[3];
+
+    data[3] = data[0];
+    data[0] = b;
+    data[1] = g;
+    data[2] = r;
+
+    data += 4;
+    size -= 4;
+  }
+}
+
+#define transform_abgr_rgba transform_argb_bgra
+
+static void
+transform_argb_abgr (GstVideoFrame * frame, const gint * matrix)
+{
+  guint8 *data;
+  gsize size;
+  gint r, g, b;
+
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  size = GST_VIDEO_FRAME_SIZE (frame);
+
+  while (size > 0) {
+    r = data[1];
+    g = data[2];
+    b = data[3];
+
+    /* data[0] = data[0]; */
+    data[1] = b;
+    data[2] = g;
+    data[3] = r;
+
+    data += 4;
+    size -= 4;
+  }
+}
+
+#define transform_abgr_argb transform_argb_abgr
+
+static void
+transform_rgba_bgra (GstVideoFrame * frame, const gint * matrix)
+{
+  guint8 *data;
+  gsize size;
+  gint r, g, b;
+
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  size = GST_VIDEO_FRAME_SIZE (frame);
+
+  while (size > 0) {
+    r = data[0];
+    g = data[1];
+    b = data[2];
+
+    /* data[3] = data[3] */ ;
+    data[0] = b;
+    data[1] = g;
+    data[2] = r;
+
+    data += 4;
+    size -= 4;
+  }
+}
+
+#define transform_bgra_rgba transform_rgba_bgra
+
+static void
+transform_argb_rgba (GstVideoFrame * frame, const gint * matrix)
+{
+  guint8 *data;
+  gsize size;
+  gint r, g, b;
+
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  size = GST_VIDEO_FRAME_SIZE (frame);
+
+  while (size > 0) {
+    r = data[1];
+    g = data[2];
+    b = data[3];
+
+    data[3] = data[0];
+    data[0] = r;
+    data[1] = g;
+    data[2] = b;
+
+    data += 4;
+    size -= 4;
+  }
+}
+
+#define transform_abgr_bgra transform_argb_rgba
+
+static void
+transform_bgra_argb (GstVideoFrame * frame, const gint * matrix)
+{
+  guint8 *data;
+  gsize size;
+  gint r, g, b;
+
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  size = GST_VIDEO_FRAME_SIZE (frame);
+
+  while (size > 0) {
+    r = data[2];
+    g = data[1];
+    b = data[0];
+
+    data[0] = data[3];
+    data[1] = r;
+    data[2] = g;
+    data[3] = b;
+
+    data += 4;
+    size -= 4;
+  }
+}
+
+#define transform_rgba_abgr transform_bgra_argb
+
+static void
+transform_rgba_argb (GstVideoFrame * frame, const gint * matrix)
+{
+  guint8 *data;
+  gsize size;
+  gint r, g, b;
+
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  size = GST_VIDEO_FRAME_SIZE (frame);
+
+  while (size > 0) {
+    r = data[0];
+    g = data[1];
+    b = data[2];
+
+    data[0] = data[3];
+    data[1] = r;
+    data[2] = g;
+    data[3] = b;
+
+    data += 4;
+    size -= 4;
+  }
+}
+
+#define transform_bgra_abgr transform_rgba_argb
+
+static gboolean
+gst_alpha_color_set_info (GstVideoFilter * filter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstAlphaColor *alpha = GST_ALPHA_COLOR (filter);
+  gboolean in_sdtv, out_sdtv;
+
+  alpha->process = NULL;
+  alpha->matrix = NULL;
+
+  if (GST_VIDEO_INFO_WIDTH (in_info) != GST_VIDEO_INFO_WIDTH (out_info) ||
+      GST_VIDEO_INFO_HEIGHT (in_info) != GST_VIDEO_INFO_HEIGHT (out_info))
+    goto invalid_caps;
+
+  in_sdtv = in_info->colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_BT601;
+  out_sdtv = out_info->colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_BT601;
+
+  switch (GST_VIDEO_INFO_FORMAT (in_info)) {
+    case GST_VIDEO_FORMAT_ARGB:
+      switch (GST_VIDEO_INFO_FORMAT (out_info)) {
+        case GST_VIDEO_FORMAT_ARGB:
+          alpha->process = NULL;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_BGRA:
+          alpha->process = transform_argb_bgra;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_ABGR:
+          alpha->process = transform_argb_abgr;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_RGBA:
+          alpha->process = transform_argb_rgba;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_AYUV:
+          alpha->process = transform_argb_ayuv;
+          alpha->matrix =
+              out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
+              cog_rgb_to_ycbcr_matrix_8bit_hdtv;
+          break;
+        default:
+          alpha->process = NULL;
+          alpha->matrix = NULL;
+          break;
+      }
+      break;
+    case GST_VIDEO_FORMAT_BGRA:
+      switch (GST_VIDEO_INFO_FORMAT (out_info)) {
+        case GST_VIDEO_FORMAT_BGRA:
+          alpha->process = NULL;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_ARGB:
+          alpha->process = transform_bgra_argb;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_ABGR:
+          alpha->process = transform_bgra_abgr;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_RGBA:
+          alpha->process = transform_bgra_rgba;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_AYUV:
+          alpha->process = transform_bgra_ayuv;
+          alpha->matrix =
+              out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
+              cog_rgb_to_ycbcr_matrix_8bit_hdtv;
+          break;
+        default:
+          alpha->process = NULL;
+          alpha->matrix = NULL;
+          break;
+      }
+      break;
+    case GST_VIDEO_FORMAT_ABGR:
+      switch (GST_VIDEO_INFO_FORMAT (out_info)) {
+        case GST_VIDEO_FORMAT_ABGR:
+          alpha->process = NULL;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_RGBA:
+          alpha->process = transform_abgr_rgba;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_ARGB:
+          alpha->process = transform_abgr_argb;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_BGRA:
+          alpha->process = transform_abgr_bgra;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_AYUV:
+          alpha->process = transform_abgr_ayuv;
+          alpha->matrix =
+              out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
+              cog_rgb_to_ycbcr_matrix_8bit_hdtv;
+          break;
+        default:
+          alpha->process = NULL;
+          alpha->matrix = NULL;
+          break;
+      }
+      break;
+    case GST_VIDEO_FORMAT_RGBA:
+      switch (GST_VIDEO_INFO_FORMAT (out_info)) {
+        case GST_VIDEO_FORMAT_RGBA:
+          alpha->process = NULL;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_ARGB:
+          alpha->process = transform_rgba_argb;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_ABGR:
+          alpha->process = transform_rgba_abgr;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_BGRA:
+          alpha->process = transform_rgba_bgra;
+          alpha->matrix = NULL;
+          break;
+        case GST_VIDEO_FORMAT_AYUV:
+          alpha->process = transform_rgba_ayuv;
+          alpha->matrix =
+              out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
+              cog_rgb_to_ycbcr_matrix_8bit_hdtv;
+          break;
+        default:
+          alpha->process = NULL;
+          alpha->matrix = NULL;
+          break;
+      }
+      break;
+    case GST_VIDEO_FORMAT_AYUV:
+      switch (GST_VIDEO_INFO_FORMAT (out_info)) {
+        case GST_VIDEO_FORMAT_AYUV:
+          if (in_sdtv == out_sdtv) {
+            alpha->process = transform_ayuv_ayuv;
+            alpha->matrix = NULL;
+          } else {
+            alpha->process = transform_ayuv_ayuv;
+            alpha->matrix =
+                out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+                cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit;
+          }
+          break;
+        case GST_VIDEO_FORMAT_ARGB:
+          alpha->process = transform_ayuv_argb;
+          alpha->matrix =
+              in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
+              cog_ycbcr_to_rgb_matrix_8bit_hdtv;
+          break;
+        case GST_VIDEO_FORMAT_BGRA:
+          alpha->process = transform_ayuv_bgra;
+          alpha->matrix =
+              in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
+              cog_ycbcr_to_rgb_matrix_8bit_hdtv;
+          break;
+        case GST_VIDEO_FORMAT_ABGR:
+          alpha->process = transform_ayuv_abgr;
+          alpha->matrix =
+              in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
+              cog_ycbcr_to_rgb_matrix_8bit_hdtv;
+          break;
+        case GST_VIDEO_FORMAT_RGBA:
+          alpha->process = transform_ayuv_rgba;
+          alpha->matrix =
+              in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
+              cog_ycbcr_to_rgb_matrix_8bit_hdtv;
+          break;
+        default:
+          alpha->process = NULL;
+          alpha->matrix = NULL;
+          break;
+      }
+      break;
+    default:
+      alpha->process = NULL;
+      alpha->matrix = NULL;
+      break;
+  }
+
+  if (GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_INFO_FORMAT (out_info)
+      && in_sdtv == out_sdtv)
+    gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), TRUE);
+  else if (!alpha->process)
+    goto no_process;
+
+  return TRUE;
+
+  /* ERRORS */
+invalid_caps:
+  {
+    GST_DEBUG_OBJECT (alpha, "incomplete or invalid caps");
+    return FALSE;
+  }
+no_process:
+  {
+    GST_DEBUG_OBJECT (alpha, "could not find process function");
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_alpha_color_transform_frame_ip (GstVideoFilter * filter,
+    GstVideoFrame * frame)
+{
+  GstAlphaColor *alpha = GST_ALPHA_COLOR (filter);
+
+  if (G_UNLIKELY (!alpha->process))
+    goto not_negotiated;
+
+  /* Transform in place */
+  alpha->process (frame, alpha->matrix);
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+not_negotiated:
+  {
+    GST_ERROR_OBJECT (alpha, "Not negotiated yet");
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "alphacolor", GST_RANK_NONE,
+      GST_TYPE_ALPHA_COLOR);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    alphacolor,
+    "RGBA from/to AYUV colorspace conversion preserving the alpha channel",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/alpha/gstalphacolor.h b/gst/alpha/gstalphacolor.h
new file mode 100644
index 0000000..540f621
--- /dev/null
+++ b/gst/alpha/gstalphacolor.h
@@ -0,0 +1,57 @@
+/* GStreamer alphacolor element
+ * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GST_ALPHA_COLOR_H_
+#define _GST_ALPHA_COLOR_H_
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+#define GST_TYPE_ALPHA_COLOR \
+  (gst_alpha_color_get_type())
+#define GST_ALPHA_COLOR(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALPHA_COLOR,GstAlphaColor))
+#define GST_ALPHA_COLOR_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALPHA_COLOR,GstAlphaColorClass))
+#define GST_IS_ALPHA_COLOR(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALPHA_COLOR))
+#define GST_IS_ALPHA_COLOR_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALPHA_COLOR))
+
+typedef struct _GstAlphaColor GstAlphaColor;
+typedef struct _GstAlphaColorClass GstAlphaColorClass;
+
+struct _GstAlphaColor
+{
+  GstVideoFilter parent;
+
+  /*< private >*/
+  void (*process) (GstVideoFrame * frame, const gint * matrix);
+
+  const gint *matrix;
+};
+
+struct _GstAlphaColorClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_alpha_color_get_type (void);
+
+#endif /* _GST_ALPHA_COLOR_H_ */
diff --git a/gst/alpha/meson.build b/gst/alpha/meson.build
new file mode 100644
index 0000000..265525e
--- /dev/null
+++ b/gst/alpha/meson.build
@@ -0,0 +1,15 @@
+gstalpha = library('gstalpha', 'gstalpha.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstvideo_dep, gst_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
+
+gstalphacolor = library('gstalphacolor', 'gstalphacolor.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstvideo_dep, gst_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/apetag/Makefile.am b/gst/apetag/Makefile.am
new file mode 100644
index 0000000..64aecf5
--- /dev/null
+++ b/gst/apetag/Makefile.am
@@ -0,0 +1,15 @@
+plugin_LTLIBRARIES = libgstapetag.la
+
+libgstapetag_la_SOURCES = gstapedemux.c
+libgstapetag_la_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS)
+libgstapetag_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) -lgsttag-@GST_API_VERSION@ \
+	-lgstpbutils-@GST_API_VERSION@\
+	$(GST_BASE_LIBS) \
+	$(GST_LIBS)
+libgstapetag_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstapedemux.h
diff --git a/gst/apetag/gstapedemux.c b/gst/apetag/gstapedemux.c
new file mode 100644
index 0000000..b3e6289
--- /dev/null
+++ b/gst/apetag/gstapedemux.c
@@ -0,0 +1,445 @@
+/* GStreamer APEv1/2 tag reader
+ * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-apedemux
+ *
+ * apedemux accepts data streams with APE tags at the start or at the end
+ * (or both). The mime type of the data between the tag blocks is detected
+ * using typefind functions, and the appropriate output mime type set on
+ * outgoing buffers.
+ *
+ * The element is only able to read APE tags at the end of a stream from
+ * a seekable stream, ie. when get_range mode is supported by the upstream
+ * elements. If get_range operation is available, apedemux makes it available
+ * downstream. This means that elements which require get_range mode, such as
+ * wavparse or musepackdec, can operate on files containing APE tag
+ * information.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -t filesrc location=file.mpc ! apedemux ! fakesink
+ * ]| This pipeline should read any available APE tag information and output it.
+ * The contents of the file inside the APE tag regions should be detected, and
+ * the appropriate mime type set on buffers produced from apedemux.
+ * </refsect2>
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/gst-i18n-plugin.h>
+#include <gst/pbutils/pbutils.h>
+
+#include "gstapedemux.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#define APE_VERSION_MAJOR(ver)  ((ver)/1000)
+
+GST_DEBUG_CATEGORY_STATIC (apedemux_debug);
+#define GST_CAT_DEFAULT (apedemux_debug)
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-apetag")
+    );
+
+static gboolean gst_ape_demux_identify_tag (GstTagDemux * demux,
+    GstBuffer * buffer, gboolean start_tag, guint * tag_size);
+static GstTagDemuxResult gst_ape_demux_parse_tag (GstTagDemux * demux,
+    GstBuffer * buffer, gboolean start_tag, guint * tag_size,
+    GstTagList ** tags);
+
+G_DEFINE_TYPE (GstApeDemux, gst_ape_demux, GST_TYPE_TAG_DEMUX);
+
+static void
+gst_ape_demux_class_init (GstApeDemuxClass * klass)
+{
+  GstElementClass *element_class;
+  GstTagDemuxClass *tagdemux_class;
+
+  GST_DEBUG_CATEGORY_INIT (apedemux_debug, "apedemux", 0,
+      "GStreamer APE tag demuxer");
+
+  tagdemux_class = GST_TAG_DEMUX_CLASS (klass);
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gst_element_class_set_static_metadata (element_class, "APE tag demuxer",
+      "Codec/Demuxer/Metadata",
+      "Read and output APE tags while demuxing the contents",
+      "Tim-Philipp Müller <tim centricular net>");
+
+  gst_element_class_add_static_pad_template (element_class, &sink_factory);
+
+  tagdemux_class->identify_tag = GST_DEBUG_FUNCPTR (gst_ape_demux_identify_tag);
+  tagdemux_class->parse_tag = GST_DEBUG_FUNCPTR (gst_ape_demux_parse_tag);
+
+  /* no need for a merge function, the default behaviour to prefer start
+   * tags (APEv2) over end tags (usually APEv1, but could theoretically also
+   * be APEv2) is fine */
+
+  tagdemux_class->min_start_size = 32;
+  tagdemux_class->min_end_size = 32;
+}
+
+static void
+gst_ape_demux_init (GstApeDemux * apedemux)
+{
+  /* nothing to do here */
+}
+
+static const struct _GstApeDemuxTagTableEntry
+{
+  const gchar *ape_tag;
+  const gchar *gst_tag;
+} tag_table[] = {
+  {
+  "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
+  "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
+  "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
+  "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
+  "title", GST_TAG_TITLE}, {
+  "artist", GST_TAG_ARTIST}, {
+  "album", GST_TAG_ALBUM}, {
+  "composer", GST_TAG_COMPOSER}, {
+  "comment", GST_TAG_COMMENT}, {
+  "comments", GST_TAG_COMMENT}, {
+  "copyright", GST_TAG_COPYRIGHT}, {
+  "genre", GST_TAG_GENRE}, {
+  "isrc", GST_TAG_ISRC}, {
+  "disc", GST_TAG_ALBUM_VOLUME_NUMBER}, {
+  "disk", GST_TAG_ALBUM_VOLUME_NUMBER}, {
+  "discnumber", GST_TAG_ALBUM_VOLUME_NUMBER}, {
+  "disknumber", GST_TAG_ALBUM_VOLUME_NUMBER}, {
+  "track", GST_TAG_TRACK_NUMBER}, {
+  "tracknumber", GST_TAG_TRACK_NUMBER}, {
+  "year", GST_TAG_DATE}, {
+  "file", GST_TAG_LOCATION}
+};
+
+static gboolean
+ape_demux_get_gst_tag_from_tag (const gchar * ape_tag,
+    const gchar ** gst_tag, GType * gst_tag_type)
+{
+  gint i;
+
+  for (i = 0; i < G_N_ELEMENTS (tag_table); ++i) {
+    if (g_ascii_strcasecmp (tag_table[i].ape_tag, ape_tag) == 0) {
+      *gst_tag = tag_table[i].gst_tag;
+      *gst_tag_type = gst_tag_get_type (tag_table[i].gst_tag);
+      GST_LOG ("Mapped APE tag '%s' to GStreamer tag '%s'", ape_tag, *gst_tag);
+      return TRUE;
+    }
+  }
+
+  GST_WARNING ("Could not map APE tag '%s' to a GStreamer tag", ape_tag);
+  return FALSE;
+}
+
+static GstTagList *
+ape_demux_parse_tags (const guint8 * data, gint size)
+{
+  GstTagList *taglist = gst_tag_list_new_empty ();
+
+  GST_LOG ("Reading tags from chunk of size %u bytes", size);
+
+  /* get rid of header/footer */
+  if (size >= 32 && memcmp (data, "APETAGEX", 8) == 0) {
+    data += 32;
+    size -= 32;
+  }
+  if (size > 32 && memcmp (data + size - 32, "APETAGEX", 8) == 0) {
+    size -= 32;
+  }
+
+  /* read actual tags - at least 10 bytes for tag header */
+  while (size >= 10) {
+    guint len, n = 8;
+    gchar *tag, *val;
+    const gchar *gst_tag;
+    GType gst_tag_type;
+
+    /* find tag type and size */
+    len = GST_READ_UINT32_LE (data);
+    while (n < size && data[n] != 0x0)
+      n++;
+    if (n == size)
+      break;
+    g_assert (data[n] == 0x0);
+    n++;
+    if (size - n < len)
+      break;
+
+    /* If the tag is empty, skip to the next one */
+    if (len == 0)
+      goto next_tag;
+
+    /* read */
+    tag = g_strndup ((gchar *) data + 8, n - 9);
+    val = g_strndup ((gchar *) data + n, len);
+
+    GST_LOG ("tag [%s], val[%s]", tag, val);
+
+    /* special-case 'media' tag, could be e.g. "CD 1/2" */
+    if (g_ascii_strcasecmp (tag, "media") == 0) {
+      gchar *sp, *sp2;
+
+      g_free (tag);
+      tag = g_strdup ("discnumber");
+      /* get rid of the medium in front */
+      sp = strchr (val, ' ');
+      while (sp != NULL && (sp2 = strchr (sp + 1, ' ')) != NULL)
+        sp = sp2;
+      if (sp) {
+        memmove (val, sp + 1, strlen (sp + 1) + 1);
+      }
+    }
+
+    if (ape_demux_get_gst_tag_from_tag (tag, &gst_tag, &gst_tag_type)) {
+      GValue v = { 0, };
+
+      switch (gst_tag_type) {
+        case G_TYPE_INT:{
+          gint v_int;
+
+          if (sscanf (val, "%d", &v_int) == 1) {
+            g_value_init (&v, G_TYPE_INT);
+            g_value_set_int (&v, v_int);
+          }
+          break;
+        }
+        case G_TYPE_UINT:{
+          guint v_uint, count;
+
+          if (strcmp (gst_tag, GST_TAG_TRACK_NUMBER) == 0) {
+            gint dummy;
+
+            if (sscanf (val, "%u", &v_uint) == 1 && v_uint > 0) {
+              g_value_init (&v, G_TYPE_UINT);
+              g_value_set_uint (&v, v_uint);
+            }
+            GST_LOG ("checking for track count: %s", val);
+            /* might be 0/N or -1/N to specify that there is only a count */
+            if (sscanf (val, "%d/%u", &dummy, &count) == 2 && count > 0) {
+              gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
+                  GST_TAG_TRACK_COUNT, count, NULL);
+            }
+          } else if (strcmp (gst_tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0) {
+            gint dummy;
+
+            if (sscanf (val, "%u", &v_uint) == 1 && v_uint > 0) {
+              g_value_init (&v, G_TYPE_UINT);
+              g_value_set_uint (&v, v_uint);
+            }
+            GST_LOG ("checking for volume count: %s", val);
+            /* might be 0/N or -1/N to specify that there is only a count */
+            if (sscanf (val, "%d/%u", &dummy, &count) == 2 && count > 0) {
+              gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
+                  GST_TAG_ALBUM_VOLUME_COUNT, count, NULL);
+            }
+          } else if (sscanf (val, "%u", &v_uint) == 1) {
+            g_value_init (&v, G_TYPE_UINT);
+            g_value_set_uint (&v, v_uint);
+          }
+          break;
+        }
+        case G_TYPE_STRING:{
+          g_value_init (&v, G_TYPE_STRING);
+          g_value_set_string (&v, val);
+          break;
+        }
+        case G_TYPE_DOUBLE:{
+          gdouble v_double;
+          gchar *endptr;
+
+          /* floating point strings can be "4,123" or "4.123" depending on
+           * the locale. We need to be able to parse and read either version
+           * no matter what our current locale is */
+          g_strdelimit (val, ",", '.');
+          v_double = g_ascii_strtod (val, &endptr);
+          if (endptr != val) {
+            g_value_init (&v, G_TYPE_DOUBLE);
+            g_value_set_double (&v, v_double);
+          }
+
+          break;
+        }
+        default:{
+          if (gst_tag_type == G_TYPE_DATE) {
+            gint v_int;
+
+            if (sscanf (val, "%d", &v_int) == 1) {
+              GDate *date = g_date_new_dmy (1, 1, v_int);
+
+              g_value_init (&v, G_TYPE_DATE);
+              g_value_take_boxed (&v, date);
+            }
+          } else {
+            GST_WARNING ("Unhandled tag type '%s' for tag '%s'",
+                g_type_name (gst_tag_type), gst_tag);
+          }
+          break;
+        }
+      }
+      if (G_VALUE_TYPE (&v) != 0) {
+        gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
+            gst_tag, &v, NULL);
+        g_value_unset (&v);
+      }
+    }
+    GST_DEBUG ("Read tag %s: %s", tag, val);
+    g_free (tag);
+    g_free (val);
+
+    /* move data pointer */
+  next_tag:
+    size -= len + n;
+    data += len + n;
+  }
+
+  GST_DEBUG ("Taglist: %" GST_PTR_FORMAT, taglist);
+  return taglist;
+}
+
+static gboolean
+gst_ape_demux_identify_tag (GstTagDemux * demux, GstBuffer * buffer,
+    gboolean start_tag, guint * tag_size)
+{
+  GstMapInfo map;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  if (memcmp (map.data, "APETAGEX", 8) != 0) {
+    GST_DEBUG_OBJECT (demux, "No APETAGEX marker at %s - not an APE file",
+        (start_tag) ? "start" : "end");
+    gst_buffer_unmap (buffer, &map);
+    return FALSE;
+  }
+
+  *tag_size = GST_READ_UINT32_LE (map.data + 12);
+
+  /* size is without header, so add 32 to account for that */
+  *tag_size += 32;
+
+  gst_buffer_unmap (buffer, &map);
+
+  return TRUE;
+}
+
+static GstTagDemuxResult
+gst_ape_demux_parse_tag (GstTagDemux * demux, GstBuffer * buffer,
+    gboolean start_tag, guint * tag_size, GstTagList ** tags)
+{
+  guint8 *data;
+  guint8 *footer;
+  gboolean have_header;
+  gboolean end_tag = !start_tag;
+  GstCaps *sink_caps;
+  guint version, footer_size;
+  GstMapInfo map;
+  gsize size;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  data = map.data;
+  size = map.size;
+
+  GST_LOG_OBJECT (demux, "Parsing buffer of size %" G_GSIZE_FORMAT, size);
+
+  footer = data + size - 32;
+
+  GST_LOG_OBJECT (demux, "Checking for footer at offset 0x%04x",
+      (guint) (footer - data));
+  if (footer > data && memcmp (footer, "APETAGEX", 8) == 0) {
+    GST_DEBUG_OBJECT (demux, "Found footer");
+    footer_size = 32;
+  } else {
+    GST_DEBUG_OBJECT (demux, "No footer");
+    footer_size = 0;
+  }
+
+  /* APE tags at the end must have a footer */
+  if (end_tag && footer_size == 0) {
+    GST_WARNING_OBJECT (demux, "Tag at end of file without footer!");
+    return GST_TAG_DEMUX_RESULT_BROKEN_TAG;
+  }
+
+  /* don't trust the header/footer flags, better detect them ourselves */
+  have_header = (memcmp (data, "APETAGEX", 8) == 0);
+
+  if (start_tag && !have_header) {
+    GST_DEBUG_OBJECT (demux, "Tag at beginning of file without header!");
+    return GST_TAG_DEMUX_RESULT_BROKEN_TAG;
+  }
+
+  if (end_tag && !have_header) {
+    GST_DEBUG_OBJECT (demux, "Tag at end of file has no header (APEv1)");
+    *tag_size -= 32;            /* adjust tag size */
+  }
+
+  if (have_header) {
+    version = GST_READ_UINT32_LE (data + 8);
+  } else {
+    version = GST_READ_UINT32_LE (footer + 8);
+  }
+
+  /* skip header */
+  if (have_header) {
+    data += 32;
+  }
+
+  GST_DEBUG_OBJECT (demux, "APE tag with version %u, size %u at offset 0x%08"
+      G_GINT64_MODIFIER "x", version, *tag_size,
+      GST_BUFFER_OFFSET (buffer) + ((have_header) ? 0 : 32));
+
+  if (APE_VERSION_MAJOR (version) != 1 && APE_VERSION_MAJOR (version) != 2) {
+    GST_WARNING ("APE tag is version %u.%03u, but decoder only supports "
+        "v1 or v2. Ignoring.", APE_VERSION_MAJOR (version), version % 1000);
+    return GST_TAG_DEMUX_RESULT_OK;
+  }
+
+  *tags = ape_demux_parse_tags (data, *tag_size - footer_size);
+
+  sink_caps = gst_static_pad_template_get_caps (&sink_factory);
+  gst_pb_utils_add_codec_description_to_tag_list (*tags,
+      GST_TAG_CONTAINER_FORMAT, sink_caps);
+  gst_caps_unref (sink_caps);
+
+  gst_buffer_unmap (buffer, &map);
+
+  return GST_TAG_DEMUX_RESULT_OK;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "apedemux",
+      GST_RANK_PRIMARY, GST_TYPE_APE_DEMUX);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    apetag,
+    "APEv1/2 tag reader",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/apetag/gstapedemux.h b/gst/apetag/gstapedemux.h
new file mode 100644
index 0000000..f340547
--- /dev/null
+++ b/gst/apetag/gstapedemux.h
@@ -0,0 +1,52 @@
+/* GStreamer APEv1/2 tag reader
+ * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_APE_DEMUX_H__
+#define __GST_APE_DEMUX_H__
+
+#include <gst/tag/gsttagdemux.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_APE_DEMUX             (gst_ape_demux_get_type())
+#define GST_APE_DEMUX(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_APE_DEMUX,GstApeDemux))
+#define GST_APE_DEMUX_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_APE_DEMUX,GstApeDemuxClass))
+#define GST_IS_APE_DEMUX(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_APE_DEMUX))
+#define GST_IS_APE_DEMUX_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_APE_DEMUX))
+
+typedef struct _GstApeDemux      GstApeDemux;
+typedef struct _GstApeDemuxClass GstApeDemuxClass;
+
+struct _GstApeDemux
+{
+  GstTagDemux tagdemux;
+};
+
+struct _GstApeDemuxClass 
+{
+  GstTagDemuxClass parent_class;
+};
+
+GType gst_ape_demux_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_APE_DEMUX_H__ */
+
diff --git a/gst/apetag/meson.build b/gst/apetag/meson.build
new file mode 100644
index 0000000..568c645
--- /dev/null
+++ b/gst/apetag/meson.build
@@ -0,0 +1,7 @@
+gstapetag = library('gstapetag', 'gstapedemux.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc, libsinc],
+  dependencies : [gstpbutils_dep, gsttag_dep, gst_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/audiofx/.gitignore b/gst/audiofx/.gitignore
new file mode 100644
index 0000000..799fc97
--- /dev/null
+++ b/gst/audiofx/.gitignore
@@ -0,0 +1,6 @@
+.deps
+.libs
+*.lo
+*.la
+Makefile
+Makefile.in
diff --git a/gst/audiofx/Makefile.am b/gst/audiofx/Makefile.am
new file mode 100644
index 0000000..13ee7d9
--- /dev/null
+++ b/gst/audiofx/Makefile.am
@@ -0,0 +1,60 @@
+# plugindir is set in configure
+
+plugin_LTLIBRARIES = libgstaudiofx.la
+
+# FIXME 0.11: ignore GValueArray warnings for now until this is sorted
+ERROR_CFLAGS=
+
+ORC_SOURCE=audiopanoramaorc
+include $(top_srcdir)/common/orc.mak
+
+# sources used to compile this plug-in
+libgstaudiofx_la_SOURCES = audiofx.c\
+	audiopanorama.c \
+	audioinvert.c \
+	audioamplify.c \
+	audiodynamic.c \
+	audiokaraoke.c \
+	audiofxbaseiirfilter.c \
+	audiocheblimit.c \
+	audiochebband.c \
+	audioiirfilter.c \
+	audiofxbasefirfilter.c \
+	audiowsincband.c \
+	audiowsinclimit.c \
+	audiofirfilter.c \
+	audioecho.c \
+	gstscaletempo.c
+nodist_libgstaudiofx_la_SOURCES = $(ORC_NODIST_SOURCES)
+
+# flags used to compile this plugin
+libgstaudiofx_la_CFLAGS = $(GST_CFLAGS) \
+	$(GST_BASE_CFLAGS) \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(ORC_CFLAGS)
+libgstaudiofx_la_LIBADD = $(GST_LIBS) \
+	$(GST_BASE_LIBS) \
+	$(GST_PLUGINS_BASE_LIBS) \
+	-lgstaudio-$(GST_API_VERSION) \
+	-lgstfft-$(GST_API_VERSION) \
+	$(ORC_LIBS) \
+	$(LIBM)
+libgstaudiofx_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+# headers we need but don't want installed
+noinst_HEADERS = audiopanorama.h \
+	audioinvert.h \
+	audioamplify.h \
+	audiodynamic.h \
+	audiokaraoke.h \
+	audiofxbaseiirfilter.h \
+	audiocheblimit.h \
+	audiochebband.h \
+	audioiirfilter.h \
+	audiofxbasefirfilter.h \
+	audiowsincband.h \
+        audiowsinclimit.h \
+	audiofirfilter.h \
+	audioecho.h \
+	gstscaletempo.h \
+	math_compat.h
diff --git a/gst/audiofx/audioamplify.c b/gst/audiofx/audioamplify.c
new file mode 100644
index 0000000..726ce0e
--- /dev/null
+++ b/gst/audiofx/audioamplify.c
@@ -0,0 +1,476 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ * Copyright (C) 2006 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-audioamplify
+ *
+ * Amplifies an audio stream by a given factor and allows the selection of different clipping modes.
+ * The difference between the clipping modes is best evaluated by testing.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc wave=saw ! audioamplify amplification=1.5 ! alsasink
+ * gst-launch-1.0 filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audioamplify amplification=1.5 clipping-method=wrap-negative ! alsasink
+ * gst-launch-1.0 audiotestsrc wave=saw ! audioconvert ! audioamplify amplification=1.5 clipping-method=wrap-positive ! audioconvert ! alsasink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audioamplify.h"
+
+#define GST_CAT_DEFAULT gst_audio_amplify_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+/* Filter signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_AMPLIFICATION,
+  PROP_CLIPPING_METHOD
+};
+
+enum
+{
+  METHOD_CLIP = 0,
+  METHOD_WRAP_NEGATIVE,
+  METHOD_WRAP_POSITIVE,
+  METHOD_NOCLIP,
+  NUM_METHODS
+};
+
+#define GST_TYPE_AUDIO_AMPLIFY_CLIPPING_METHOD (gst_audio_amplify_clipping_method_get_type ())
+static GType
+gst_audio_amplify_clipping_method_get_type (void)
+{
+  static GType gtype = 0;
+
+  if (gtype == 0) {
+    static const GEnumValue values[] = {
+      {METHOD_CLIP, "Normal clipping (default)", "clip"},
+      {METHOD_WRAP_NEGATIVE,
+            "Push overdriven values back from the opposite side",
+          "wrap-negative"},
+      {METHOD_WRAP_POSITIVE, "Push overdriven values back from the same side",
+          "wrap-positive"},
+      {METHOD_NOCLIP, "No clipping", "none"},
+      {0, NULL, NULL}
+    };
+    gtype = g_enum_register_static ("GstAudioAmplifyClippingMethod", values);
+  }
+  return gtype;
+}
+
+#define ALLOWED_CAPS                                                  \
+    "audio/x-raw,"                                                    \
+    " format=(string) {S8,"GST_AUDIO_NE(S16)","GST_AUDIO_NE(S32)","   \
+                           GST_AUDIO_NE(F32)","GST_AUDIO_NE(F64)"},"  \
+    " rate=(int)[1,MAX],"                                             \
+    " channels=(int)[1,MAX], "                                        \
+    " layout=(string) {interleaved, non-interleaved}"
+
+G_DEFINE_TYPE (GstAudioAmplify, gst_audio_amplify, GST_TYPE_AUDIO_FILTER);
+
+static gboolean gst_audio_amplify_set_process_function (GstAudioAmplify *
+    filter, gint clipping, GstAudioFormat format);
+static void gst_audio_amplify_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_audio_amplify_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_audio_amplify_setup (GstAudioFilter * filter,
+    const GstAudioInfo * info);
+static GstFlowReturn gst_audio_amplify_transform_ip (GstBaseTransform * base,
+    GstBuffer * buf);
+
+#define MIN_gint8 G_MININT8
+#define MAX_gint8 G_MAXINT8
+#define MIN_gint16 G_MININT16
+#define MAX_gint16 G_MAXINT16
+#define MIN_gint32 G_MININT32
+#define MAX_gint32 G_MAXINT32
+
+#define MAKE_INT_FUNCS(type,largetype)                                        \
+static void                                                                   \
+gst_audio_amplify_transform_##type##_clip (GstAudioAmplify * filter,          \
+    void * data, guint num_samples)                                           \
+{                                                                             \
+  type *d = data;                                                             \
+                                                                              \
+  while (num_samples--) {                                                     \
+    largetype val = *d * filter->amplification;                               \
+    *d++ =  CLAMP (val, MIN_##type, MAX_##type);                              \
+  }                                                                           \
+}                                                                             \
+static void                                                                   \
+gst_audio_amplify_transform_##type##_wrap_negative (GstAudioAmplify * filter, \
+    void * data, guint num_samples)                                           \
+{                                                                             \
+  type *d = data;                                                             \
+                                                                              \
+  while (num_samples--) {                                                     \
+    largetype val = *d * filter->amplification;                               \
+    if (val > MAX_##type)                                                     \
+      val = MIN_##type + (val - MIN_##type) % ((largetype) MAX_##type + 1 -   \
+          MIN_##type);                                                        \
+    else if (val < MIN_##type)                                                \
+      val = MAX_##type - (MAX_##type - val) % ((largetype) MAX_##type + 1 -   \
+          MIN_##type);                                                        \
+    *d++ = val;                                                               \
+  }                                                                           \
+}                                                                             \
+static void                                                                   \
+gst_audio_amplify_transform_##type##_wrap_positive (GstAudioAmplify * filter, \
+    void * data, guint num_samples)                                           \
+{                                                                             \
+  type *d = data;                                                             \
+                                                                              \
+  while (num_samples--) {                                                     \
+    largetype val = *d * filter->amplification;                               \
+    do {                                                                      \
+      if (val > MAX_##type)                                                   \
+        val = MAX_##type - (val - MAX_##type);                                \
+      else if (val < MIN_##type)                                              \
+        val = MIN_##type + (MIN_##type - val);                                \
+      else                                                                    \
+        break;                                                                \
+    } while (1);                                                              \
+    *d++ = val;                                                               \
+  }                                                                           \
+}                                                                             \
+static void                                                                   \
+gst_audio_amplify_transform_##type##_noclip (GstAudioAmplify * filter,        \
+    void * data, guint num_samples)                                           \
+{                                                                             \
+  type *d = data;                                                             \
+                                                                              \
+  while (num_samples--)                                                       \
+    *d++ *= filter->amplification;                                            \
+}
+
+#define MAKE_FLOAT_FUNCS(type)                                                \
+static void                                                                   \
+gst_audio_amplify_transform_##type##_clip (GstAudioAmplify * filter,          \
+    void * data, guint num_samples)                                           \
+{                                                                             \
+  type *d = data;                                                             \
+                                                                              \
+  while (num_samples--) {                                                     \
+    type val = *d* filter->amplification;                                     \
+    *d++ = CLAMP (val, -1.0, +1.0);                                           \
+  }                                                                           \
+}                                                                             \
+static void                                                                   \
+gst_audio_amplify_transform_##type##_wrap_negative (GstAudioAmplify *         \
+    filter, void * data, guint num_samples)                                   \
+{                                                                             \
+  type *d = data;                                                             \
+                                                                              \
+  while (num_samples--) {                                                     \
+    type val = *d * filter->amplification;                                    \
+    do {                                                                      \
+      if (val > 1.0)                                                          \
+        val = -1.0 + (val - 1.0);                                             \
+      else if (val < -1.0)                                                    \
+        val = 1.0 - (1.0 - val);                                              \
+      else                                                                    \
+        break;                                                                \
+    } while (1);                                                              \
+    *d++ = val;                                                               \
+  }                                                                           \
+}                                                                             \
+static void                                                                   \
+gst_audio_amplify_transform_##type##_wrap_positive (GstAudioAmplify * filter, \
+    void * data, guint num_samples)                                           \
+{                                                                             \
+  type *d = data;                                                             \
+                                                                              \
+  while (num_samples--) {                                                     \
+    type val = *d* filter->amplification;                                     \
+    do {                                                                      \
+      if (val > 1.0)                                                          \
+        val = 1.0 - (val - 1.0);                                              \
+      else if (val < -1.0)                                                    \
+        val = -1.0 + (-1.0 - val);                                            \
+      else                                                                    \
+        break;                                                                \
+    } while (1);                                                              \
+    *d++ = val;                                                               \
+  }                                                                           \
+}                                                                             \
+static void                                                                   \
+gst_audio_amplify_transform_##type##_noclip (GstAudioAmplify * filter,        \
+    void * data, guint num_samples)                                           \
+{                                                                             \
+  type *d = data;                                                             \
+                                                                              \
+  while (num_samples--)                                                       \
+    *d++ *= filter->amplification;                                            \
+}
+
+/* *INDENT-OFF* */
+MAKE_INT_FUNCS (gint8,gint)
+MAKE_INT_FUNCS (gint16,gint)
+MAKE_INT_FUNCS (gint32,gint64)
+MAKE_FLOAT_FUNCS (gfloat)
+MAKE_FLOAT_FUNCS (gdouble)
+/* *INDENT-ON* */
+
+/* GObject vmethod implementations */
+
+static void
+gst_audio_amplify_class_init (GstAudioAmplifyClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstCaps *caps;
+
+  GST_DEBUG_CATEGORY_INIT (gst_audio_amplify_debug, "audioamplify", 0,
+      "audioamplify element");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_audio_amplify_set_property;
+  gobject_class->get_property = gst_audio_amplify_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_AMPLIFICATION,
+      g_param_spec_float ("amplification", "Amplification",
+          "Factor of amplification", -G_MAXFLOAT, G_MAXFLOAT,
+          1.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstAudioAmplify:clipping-method
+   *
+   * Clipping method: clip mode set values higher than the maximum to the
+   * maximum. The wrap-negative mode pushes those values back from the
+   * opposite side, wrap-positive pushes them back from the same side.
+   *
+   **/
+  g_object_class_install_property (gobject_class, PROP_CLIPPING_METHOD,
+      g_param_spec_enum ("clipping-method", "Clipping method",
+          "Selects how to handle values higher than the maximum",
+          GST_TYPE_AUDIO_AMPLIFY_CLIPPING_METHOD, METHOD_CLIP,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class, "Audio amplifier",
+      "Filter/Effect/Audio",
+      "Amplifies an audio stream by a given factor",
+      "Sebastian Dröge <slomo@circular-chaos.org>");
+
+  caps = gst_caps_from_string (ALLOWED_CAPS);
+  gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass),
+      caps);
+  gst_caps_unref (caps);
+
+  GST_BASE_TRANSFORM_CLASS (klass)->transform_ip =
+      GST_DEBUG_FUNCPTR (gst_audio_amplify_transform_ip);
+  GST_BASE_TRANSFORM_CLASS (klass)->transform_ip_on_passthrough = FALSE;
+
+  GST_AUDIO_FILTER_CLASS (klass)->setup =
+      GST_DEBUG_FUNCPTR (gst_audio_amplify_setup);
+}
+
+static void
+gst_audio_amplify_init (GstAudioAmplify * filter)
+{
+  filter->amplification = 1.0;
+  gst_audio_amplify_set_process_function (filter, METHOD_CLIP,
+      GST_AUDIO_FORMAT_S16);
+  gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
+  gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE);
+}
+
+static GstAudioAmplifyProcessFunc
+gst_audio_amplify_process_function (gint clipping, GstAudioFormat format)
+{
+  static const struct process
+  {
+    GstAudioFormat format;
+    gint clipping;
+    GstAudioAmplifyProcessFunc func;
+  } process[] = {
+    {
+    GST_AUDIO_FORMAT_F32, METHOD_CLIP, gst_audio_amplify_transform_gfloat_clip}, {
+    GST_AUDIO_FORMAT_F32, METHOD_WRAP_NEGATIVE,
+          gst_audio_amplify_transform_gfloat_wrap_negative}, {
+    GST_AUDIO_FORMAT_F32, METHOD_WRAP_POSITIVE,
+          gst_audio_amplify_transform_gfloat_wrap_positive}, {
+    GST_AUDIO_FORMAT_F32, METHOD_NOCLIP,
+          gst_audio_amplify_transform_gfloat_noclip}, {
+    GST_AUDIO_FORMAT_F64, METHOD_CLIP,
+          gst_audio_amplify_transform_gdouble_clip}, {
+    GST_AUDIO_FORMAT_F64, METHOD_WRAP_NEGATIVE,
+          gst_audio_amplify_transform_gdouble_wrap_negative}, {
+    GST_AUDIO_FORMAT_F64, METHOD_WRAP_POSITIVE,
+          gst_audio_amplify_transform_gdouble_wrap_positive}, {
+    GST_AUDIO_FORMAT_F64, METHOD_NOCLIP,
+          gst_audio_amplify_transform_gdouble_noclip}, {
+    GST_AUDIO_FORMAT_S8, METHOD_CLIP, gst_audio_amplify_transform_gint8_clip}, {
+    GST_AUDIO_FORMAT_S8, METHOD_WRAP_NEGATIVE,
+          gst_audio_amplify_transform_gint8_wrap_negative}, {
+    GST_AUDIO_FORMAT_S8, METHOD_WRAP_POSITIVE,
+          gst_audio_amplify_transform_gint8_wrap_positive}, {
+    GST_AUDIO_FORMAT_S8, METHOD_NOCLIP,
+          gst_audio_amplify_transform_gint8_noclip}, {
+    GST_AUDIO_FORMAT_S16, METHOD_CLIP, gst_audio_amplify_transform_gint16_clip}, {
+    GST_AUDIO_FORMAT_S16, METHOD_WRAP_NEGATIVE,
+          gst_audio_amplify_transform_gint16_wrap_negative}, {
+    GST_AUDIO_FORMAT_S16, METHOD_WRAP_POSITIVE,
+          gst_audio_amplify_transform_gint16_wrap_positive}, {
+    GST_AUDIO_FORMAT_S16, METHOD_NOCLIP,
+          gst_audio_amplify_transform_gint16_noclip}, {
+    GST_AUDIO_FORMAT_S32, METHOD_CLIP, gst_audio_amplify_transform_gint32_clip}, {
+    GST_AUDIO_FORMAT_S32, METHOD_WRAP_NEGATIVE,
+          gst_audio_amplify_transform_gint32_wrap_negative}, {
+    GST_AUDIO_FORMAT_S32, METHOD_WRAP_POSITIVE,
+          gst_audio_amplify_transform_gint32_wrap_positive}, {
+    GST_AUDIO_FORMAT_S32, METHOD_NOCLIP,
+          gst_audio_amplify_transform_gint32_noclip}, {
+    0, 0, NULL}
+  };
+  const struct process *p;
+
+  for (p = process; p->func; p++)
+    if (p->format == format && p->clipping == clipping)
+      return p->func;
+  return NULL;
+}
+
+static gboolean
+gst_audio_amplify_set_process_function (GstAudioAmplify * filter, gint
+    clipping_method, GstAudioFormat format)
+{
+  GstAudioAmplifyProcessFunc process;
+
+  /* set processing function */
+
+  process = gst_audio_amplify_process_function (clipping_method, format);
+  if (!process) {
+    GST_DEBUG ("wrong format");
+    return FALSE;
+  }
+
+  filter->process = process;
+  filter->clipping_method = clipping_method;
+  filter->format = format;
+
+  return TRUE;
+}
+
+static void
+gst_audio_amplify_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAudioAmplify *filter = GST_AUDIO_AMPLIFY (object);
+
+  switch (prop_id) {
+    case PROP_AMPLIFICATION:
+      filter->amplification = g_value_get_float (value);
+      gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter),
+          filter->amplification == 1.0);
+      break;
+    case PROP_CLIPPING_METHOD:
+      gst_audio_amplify_set_process_function (filter, g_value_get_enum (value),
+          filter->format);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_audio_amplify_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAudioAmplify *filter = GST_AUDIO_AMPLIFY (object);
+
+  switch (prop_id) {
+    case PROP_AMPLIFICATION:
+      g_value_set_float (value, filter->amplification);
+      break;
+    case PROP_CLIPPING_METHOD:
+      g_value_set_enum (value, filter->clipping_method);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* GstAudioFilter vmethod implementations */
+static gboolean
+gst_audio_amplify_setup (GstAudioFilter * base, const GstAudioInfo * info)
+{
+  GstAudioAmplify *filter = GST_AUDIO_AMPLIFY (base);
+
+  return gst_audio_amplify_set_process_function (filter,
+      filter->clipping_method, GST_AUDIO_INFO_FORMAT (info));
+}
+
+/* GstBaseTransform vmethod implementations */
+static GstFlowReturn
+gst_audio_amplify_transform_ip (GstBaseTransform * base, GstBuffer * buf)
+{
+  GstAudioAmplify *filter = GST_AUDIO_AMPLIFY (base);
+  guint num_samples;
+  GstClockTime timestamp, stream_time;
+  GstMapInfo map;
+
+  timestamp = GST_BUFFER_TIMESTAMP (buf);
+  stream_time =
+      gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (filter), stream_time);
+
+  if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)))
+    return GST_FLOW_OK;
+
+  gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+  num_samples = map.size / GST_AUDIO_FILTER_BPS (filter);
+
+  filter->process (filter, map.data, num_samples);
+
+  gst_buffer_unmap (buf, &map);
+
+  return GST_FLOW_OK;
+}
diff --git a/gst/audiofx/audioamplify.h b/gst/audiofx/audioamplify.h
new file mode 100644
index 0000000..573eed1
--- /dev/null
+++ b/gst/audiofx/audioamplify.h
@@ -0,0 +1,62 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ * Copyright (C) 2006 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AUDIO_AMPLIFY_H__
+#define __GST_AUDIO_AMPLIFY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_AUDIO_AMPLIFY            (gst_audio_amplify_get_type())
+#define GST_AUDIO_AMPLIFY(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_AMPLIFY,GstAudioAmplify))
+#define GST_IS_AUDIO_AMPLIFY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_AMPLIFY))
+#define GST_AUDIO_AMPLIFY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_AMPLIFY,GstAudioAmplifyClass))
+#define GST_IS_AUDIO_AMPLIFY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_AMPLIFY))
+#define GST_AUDIO_AMPLIFY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_AMPLIFY,GstAudioAmplifyClass))
+typedef struct _GstAudioAmplify GstAudioAmplify;
+typedef struct _GstAudioAmplifyClass GstAudioAmplifyClass;
+
+typedef void (*GstAudioAmplifyProcessFunc) (GstAudioAmplify *, void *, guint);
+
+struct _GstAudioAmplify
+{
+  GstAudioFilter audiofilter;
+
+  gfloat amplification;
+
+  /* < private > */
+  GstAudioAmplifyProcessFunc process;
+  gint clipping_method;
+  GstAudioFormat format;
+};
+
+struct _GstAudioAmplifyClass
+{
+  GstAudioFilterClass parent;
+};
+
+GType gst_audio_amplify_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_AUDIO_AMPLIFY_H__ */
diff --git a/gst/audiofx/audiochebband.c b/gst/audiofx/audiochebband.c
new file mode 100644
index 0000000..78febe9
--- /dev/null
+++ b/gst/audiofx/audiochebband.c
@@ -0,0 +1,660 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* 
+ * Chebyshev type 1 filter design based on
+ * "The Scientist and Engineer's Guide to DSP", Chapter 20.
+ * http://www.dspguide.com/
+ *
+ * For type 2 and Chebyshev filters in general read
+ * http://en.wikipedia.org/wiki/Chebyshev_filter
+ *
+ * Transformation from lowpass to bandpass/bandreject:
+ * http://docs.dewresearch.com/DspHelp/html/IDH_LinearSystems_LowpassToBandPassZ.htm
+ * http://docs.dewresearch.com/DspHelp/html/IDH_LinearSystems_LowpassToBandStopZ.htm
+ * 
+ */
+
+/**
+ * SECTION:element-audiochebband
+ *
+ * Attenuates all frequencies outside (bandpass) or inside (bandreject) of a frequency
+ * band. The number of poles and the ripple parameter control the rolloff.
+ *
+ * This element has the advantage over the windowed sinc bandpass and bandreject filter that it is
+ * much faster and produces almost as good results. It's only disadvantages are the highly
+ * non-linear phase and the slower rolloff compared to a windowed sinc filter with a large kernel.
+ *
+ * For type 1 the ripple parameter specifies how much ripple in dB is allowed in the passband, i.e.
+ * some frequencies in the passband will be amplified by that value. A higher ripple value will allow
+ * a faster rolloff.
+ *
+ * For type 2 the ripple parameter specifies the stopband attenuation. In the stopband the gain will
+ * be at most this value. A lower ripple value will allow a faster rolloff.
+ *
+ * As a special case, a Chebyshev type 1 filter with no ripple is a Butterworth filter.
+ *
+ * <note>
+ * Be warned that a too large number of poles can produce noise. The most poles are possible with
+ * a cutoff frequency at a quarter of the sampling rate.
+ * </note>
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc freq=1500 ! audioconvert ! audiochebband mode=band-pass lower-frequency=1000 upper-frequency=6000 poles=4 ! audioconvert ! alsasink
+ * gst-launch-1.0 filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiochebband mode=band-reject lower-frequency=1000 upper-frequency=4000 ripple=0.2 ! audioconvert ! alsasink
+ * gst-launch-1.0 audiotestsrc wave=white-noise ! audioconvert ! audiochebband mode=band-pass lower-frequency=1000 upper-frequency=4000 type=2 ! audioconvert ! alsasink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include <math.h>
+
+#include "math_compat.h"
+
+#include "audiochebband.h"
+
+#include "gst/glib-compat-private.h"
+
+#define GST_CAT_DEFAULT gst_audio_cheb_band_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+enum
+{
+  PROP_0,
+  PROP_MODE,
+  PROP_TYPE,
+  PROP_LOWER_FREQUENCY,
+  PROP_UPPER_FREQUENCY,
+  PROP_RIPPLE,
+  PROP_POLES
+};
+
+#define gst_audio_cheb_band_parent_class parent_class
+G_DEFINE_TYPE (GstAudioChebBand, gst_audio_cheb_band,
+    GST_TYPE_AUDIO_FX_BASE_IIR_FILTER);
+
+static void gst_audio_cheb_band_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_audio_cheb_band_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+static void gst_audio_cheb_band_finalize (GObject * object);
+
+static gboolean gst_audio_cheb_band_setup (GstAudioFilter * filter,
+    const GstAudioInfo * info);
+
+enum
+{
+  MODE_BAND_PASS = 0,
+  MODE_BAND_REJECT
+};
+
+#define GST_TYPE_AUDIO_CHEBYSHEV_FREQ_BAND_MODE (gst_audio_cheb_band_mode_get_type ())
+static GType
+gst_audio_cheb_band_mode_get_type (void)
+{
+  static GType gtype = 0;
+
+  if (gtype == 0) {
+    static const GEnumValue values[] = {
+      {MODE_BAND_PASS, "Band pass (default)",
+          "band-pass"},
+      {MODE_BAND_REJECT, "Band reject",
+          "band-reject"},
+      {0, NULL, NULL}
+    };
+
+    gtype = g_enum_register_static ("GstAudioChebBandMode", values);
+  }
+  return gtype;
+}
+
+/* GObject vmethod implementations */
+
+static void
+gst_audio_cheb_band_class_init (GstAudioChebBandClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (gst_audio_cheb_band_debug, "audiochebband", 0,
+      "audiochebband element");
+
+  gobject_class->set_property = gst_audio_cheb_band_set_property;
+  gobject_class->get_property = gst_audio_cheb_band_get_property;
+  gobject_class->finalize = gst_audio_cheb_band_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_MODE,
+      g_param_spec_enum ("mode", "Mode",
+          "Low pass or high pass mode", GST_TYPE_AUDIO_CHEBYSHEV_FREQ_BAND_MODE,
+          MODE_BAND_PASS,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_TYPE,
+      g_param_spec_int ("type", "Type", "Type of the chebychev filter", 1, 2, 1,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  /* FIXME: Don't use the complete possible range but restrict the upper boundary
+   * so automatically generated UIs can use a slider without */
+  g_object_class_install_property (gobject_class, PROP_LOWER_FREQUENCY,
+      g_param_spec_float ("lower-frequency", "Lower frequency",
+          "Start frequency of the band (Hz)", 0.0, 100000.0,
+          0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_UPPER_FREQUENCY,
+      g_param_spec_float ("upper-frequency", "Upper frequency",
+          "Stop frequency of the band (Hz)", 0.0, 100000.0, 0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_RIPPLE,
+      g_param_spec_float ("ripple", "Ripple", "Amount of ripple (dB)", 0.0,
+          200.0, 0.25,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  /* FIXME: What to do about this upper boundary? With a frequencies near
+   * rate/4 32 poles are completely possible, with frequencies very low
+   * or very high 16 poles already produces only noise */
+  g_object_class_install_property (gobject_class, PROP_POLES,
+      g_param_spec_int ("poles", "Poles",
+          "Number of poles to use, will be rounded up to the next multiply of four",
+          4, 32, 4,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Band pass & band reject filter", "Filter/Effect/Audio",
+      "Chebyshev band pass and band reject filter",
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_cheb_band_setup);
+}
+
+static void
+gst_audio_cheb_band_init (GstAudioChebBand * filter)
+{
+  filter->lower_frequency = filter->upper_frequency = 0.0;
+  filter->mode = MODE_BAND_PASS;
+  filter->type = 1;
+  filter->poles = 4;
+  filter->ripple = 0.25;
+
+  g_mutex_init (&filter->lock);
+}
+
+static void
+generate_biquad_coefficients (GstAudioChebBand * filter,
+    gint p, gint rate, gdouble * b0, gdouble * b1, gdouble * b2, gdouble * b3,
+    gdouble * b4, gdouble * a1, gdouble * a2, gdouble * a3, gdouble * a4)
+{
+  gint np = filter->poles / 2;
+  gdouble ripple = filter->ripple;
+
+  /* pole location in s-plane */
+  gdouble rp, ip;
+
+  /* zero location in s-plane */
+  gdouble iz = 0.0;
+
+  /* transfer function coefficients for the z-plane */
+  gdouble x0, x1, x2, y1, y2;
+  gint type = filter->type;
+
+  /* Calculate pole location for lowpass at frequency 1 */
+  {
+    gdouble angle = (G_PI / 2.0) * (2.0 * p - 1) / np;
+
+    rp = -sin (angle);
+    ip = cos (angle);
+  }
+
+  /* If we allow ripple, move the pole from the unit
+   * circle to an ellipse and keep cutoff at frequency 1 */
+  if (ripple > 0 && type == 1) {
+    gdouble es, vx;
+
+    es = sqrt (pow (10.0, ripple / 10.0) - 1.0);
+
+    vx = (1.0 / np) * asinh (1.0 / es);
+    rp = rp * sinh (vx);
+    ip = ip * cosh (vx);
+  } else if (type == 2) {
+    gdouble es, vx;
+
+    es = sqrt (pow (10.0, ripple / 10.0) - 1.0);
+    vx = (1.0 / np) * asinh (es);
+    rp = rp * sinh (vx);
+    ip = ip * cosh (vx);
+  }
+
+  /* Calculate inverse of the pole location to move from
+   * type I to type II */
+  if (type == 2) {
+    gdouble mag2 = rp * rp + ip * ip;
+
+    rp /= mag2;
+    ip /= mag2;
+  }
+
+  /* Calculate zero location for frequency 1 on the
+   * unit circle for type 2 */
+  if (type == 2) {
+    gdouble angle = G_PI / (np * 2.0) + ((p - 1) * G_PI) / (np);
+    gdouble mag2;
+
+    iz = cos (angle);
+    mag2 = iz * iz;
+    iz /= mag2;
+  }
+
+  /* Convert from s-domain to z-domain by
+   * using the bilinear Z-transform, i.e.
+   * substitute s by (2/t)*((z-1)/(z+1))
+   * with t = 2 * tan(0.5).
+   */
+  if (type == 1) {
+    gdouble t, m, d;
+
+    t = 2.0 * tan (0.5);
+    m = rp * rp + ip * ip;
+    d = 4.0 - 4.0 * rp * t + m * t * t;
+
+    x0 = (t * t) / d;
+    x1 = 2.0 * x0;
+    x2 = x0;
+    y1 = (8.0 - 2.0 * m * t * t) / d;
+    y2 = (-4.0 - 4.0 * rp * t - m * t * t) / d;
+  } else {
+    gdouble t, m, d;
+
+    t = 2.0 * tan (0.5);
+    m = rp * rp + ip * ip;
+    d = 4.0 - 4.0 * rp * t + m * t * t;
+
+    x0 = (t * t * iz * iz + 4.0) / d;
+    x1 = (-8.0 + 2.0 * iz * iz * t * t) / d;
+    x2 = x0;
+    y1 = (8.0 - 2.0 * m * t * t) / d;
+    y2 = (-4.0 - 4.0 * rp * t - m * t * t) / d;
+  }
+
+  /* Convert from lowpass at frequency 1 to either bandpass
+   * or band reject.
+   *
+   * For bandpass substitute z^(-1) with:
+   *
+   *   -2            -1
+   * -z   + alpha * z   - beta
+   * ----------------------------
+   *         -2            -1
+   * beta * z   - alpha * z   + 1
+   *
+   * alpha = (2*a*b)/(1+b)
+   * beta = (b-1)/(b+1)
+   * a = cos((w1 + w0)/2) / cos((w1 - w0)/2)
+   * b = tan(1/2) * cot((w1 - w0)/2)
+   *
+   * For bandreject substitute z^(-1) with:
+   * 
+   *  -2            -1
+   * z   - alpha * z   + beta
+   * ----------------------------
+   *         -2            -1
+   * beta * z   - alpha * z   + 1
+   *
+   * alpha = (2*a)/(1+b)
+   * beta = (1-b)/(1+b)
+   * a = cos((w1 + w0)/2) / cos((w1 - w0)/2)
+   * b = tan(1/2) * tan((w1 - w0)/2)
+   *
+   */
+  {
+    gdouble a, b, d;
+    gdouble alpha, beta;
+    gdouble w0 = 2.0 * G_PI * (filter->lower_frequency / rate);
+    gdouble w1 = 2.0 * G_PI * (filter->upper_frequency / rate);
+
+    if (filter->mode == MODE_BAND_PASS) {
+      a = cos ((w1 + w0) / 2.0) / cos ((w1 - w0) / 2.0);
+      b = tan (1.0 / 2.0) / tan ((w1 - w0) / 2.0);
+
+      alpha = (2.0 * a * b) / (1.0 + b);
+      beta = (b - 1.0) / (b + 1.0);
+
+      d = 1.0 + beta * (y1 - beta * y2);
+
+      *b0 = (x0 + beta * (-x1 + beta * x2)) / d;
+      *b1 = (alpha * (-2.0 * x0 + x1 + beta * x1 - 2.0 * beta * x2)) / d;
+      *b2 =
+          (-x1 - beta * beta * x1 + 2.0 * beta * (x0 + x2) +
+          alpha * alpha * (x0 - x1 + x2)) / d;
+      *b3 = (alpha * (x1 + beta * (-2.0 * x0 + x1) - 2.0 * x2)) / d;
+      *b4 = (beta * (beta * x0 - x1) + x2) / d;
+      *a1 = (alpha * (2.0 + y1 + beta * y1 - 2.0 * beta * y2)) / d;
+      *a2 =
+          (-y1 - beta * beta * y1 - alpha * alpha * (1.0 + y1 - y2) +
+          2.0 * beta * (-1.0 + y2)) / d;
+      *a3 = (alpha * (y1 + beta * (2.0 + y1) - 2.0 * y2)) / d;
+      *a4 = (-beta * beta - beta * y1 + y2) / d;
+    } else {
+      a = cos ((w1 + w0) / 2.0) / cos ((w1 - w0) / 2.0);
+      b = tan (1.0 / 2.0) * tan ((w1 - w0) / 2.0);
+
+      alpha = (2.0 * a) / (1.0 + b);
+      beta = (1.0 - b) / (1.0 + b);
+
+      d = -1.0 + beta * (beta * y2 + y1);
+
+      *b0 = (-x0 - beta * x1 - beta * beta * x2) / d;
+      *b1 = (alpha * (2.0 * x0 + x1 + beta * x1 + 2.0 * beta * x2)) / d;
+      *b2 =
+          (-x1 - beta * beta * x1 - 2.0 * beta * (x0 + x2) -
+          alpha * alpha * (x0 + x1 + x2)) / d;
+      *b3 = (alpha * (x1 + beta * (2.0 * x0 + x1) + 2.0 * x2)) / d;
+      *b4 = (-beta * beta * x0 - beta * x1 - x2) / d;
+      *a1 = (alpha * (-2.0 + y1 + beta * y1 + 2.0 * beta * y2)) / d;
+      *a2 =
+          -(y1 + beta * beta * y1 + 2.0 * beta * (-1.0 + y2) +
+          alpha * alpha * (-1.0 + y1 + y2)) / d;
+      *a3 = (alpha * (beta * (-2.0 + y1) + y1 + 2.0 * y2)) / d;
+      *a4 = -(-beta * beta + beta * y1 + y2) / d;
+    }
+  }
+}
+
+static void
+generate_coefficients (GstAudioChebBand * filter, const GstAudioInfo * info)
+{
+  gint rate;
+
+  if (info) {
+    rate = GST_AUDIO_INFO_RATE (info);
+  } else {
+    rate = GST_AUDIO_FILTER_RATE (filter);
+  }
+
+  if (rate == 0) {
+    gdouble *a = g_new0 (gdouble, 1);
+    gdouble *b = g_new0 (gdouble, 1);
+
+    a[0] = 1.0;
+    b[0] = 1.0;
+    gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
+        (filter), a, 1, b, 1);
+    GST_LOG_OBJECT (filter, "rate was not set yet");
+    return;
+  }
+
+  if (filter->upper_frequency <= filter->lower_frequency) {
+    gdouble *a = g_new0 (gdouble, 1);
+    gdouble *b = g_new0 (gdouble, 1);
+
+    a[0] = 1.0;
+    b[0] = (filter->mode == MODE_BAND_PASS) ? 0.0 : 1.0;
+    gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
+        (filter), a, 1, b, 1);
+
+    GST_LOG_OBJECT (filter, "frequency band had no or negative dimension");
+    return;
+  }
+
+  if (filter->upper_frequency > rate / 2) {
+    filter->upper_frequency = rate / 2;
+    GST_LOG_OBJECT (filter, "clipped upper frequency to nyquist frequency");
+  }
+
+  if (filter->lower_frequency < 0.0) {
+    filter->lower_frequency = 0.0;
+    GST_LOG_OBJECT (filter, "clipped lower frequency to 0.0");
+  }
+
+  /* Calculate coefficients for the chebyshev filter */
+  {
+    gint np = filter->poles;
+    gdouble *a, *b;
+    gint i, p;
+
+    a = g_new0 (gdouble, np + 5);
+    b = g_new0 (gdouble, np + 5);
+
+    /* Calculate transfer function coefficients */
+    a[4] = 1.0;
+    b[4] = 1.0;
+
+    for (p = 1; p <= np / 4; p++) {
+      gdouble b0, b1, b2, b3, b4, a1, a2, a3, a4;
+      gdouble *ta = g_new0 (gdouble, np + 5);
+      gdouble *tb = g_new0 (gdouble, np + 5);
+
+      generate_biquad_coefficients (filter, p, rate,
+          &b0, &b1, &b2, &b3, &b4, &a1, &a2, &a3, &a4);
+
+      memcpy (ta, a, sizeof (gdouble) * (np + 5));
+      memcpy (tb, b, sizeof (gdouble) * (np + 5));
+
+      /* add the new coefficients for the new two poles
+       * to the cascade by multiplication of the transfer
+       * functions */
+      for (i = 4; i < np + 5; i++) {
+        b[i] =
+            b0 * tb[i] + b1 * tb[i - 1] + b2 * tb[i - 2] + b3 * tb[i - 3] +
+            b4 * tb[i - 4];
+        a[i] =
+            ta[i] - a1 * ta[i - 1] - a2 * ta[i - 2] - a3 * ta[i - 3] -
+            a4 * ta[i - 4];
+      }
+      g_free (ta);
+      g_free (tb);
+    }
+
+    /* Move coefficients to the beginning of the array to move from
+     * the transfer function's coefficients to the difference
+     * equation's coefficients */
+    for (i = 0; i <= np; i++) {
+      a[i] = a[i + 4];
+      b[i] = b[i + 4];
+    }
+
+    /* Normalize to unity gain at frequency 0 and frequency
+     * 0.5 for bandreject and unity gain at band center frequency
+     * for bandpass */
+    if (filter->mode == MODE_BAND_REJECT) {
+      /* gain is sqrt(H(0)*H(0.5)) */
+
+      gdouble gain1 =
+          gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1,
+          1.0, 0.0);
+      gdouble gain2 =
+          gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1,
+          -1.0, 0.0);
+
+      gain1 = sqrt (gain1 * gain2);
+
+      for (i = 0; i <= np; i++) {
+        b[i] /= gain1;
+      }
+    } else {
+      /* gain is H(wc), wc = center frequency */
+
+      gdouble w1 = 2.0 * G_PI * (filter->lower_frequency / rate);
+      gdouble w2 = 2.0 * G_PI * (filter->upper_frequency / rate);
+      gdouble w0 = (w2 + w1) / 2.0;
+      gdouble zr = cos (w0), zi = sin (w0);
+      gdouble gain =
+          gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, zr,
+          zi);
+
+      for (i = 0; i <= np; i++) {
+        b[i] /= gain;
+      }
+    }
+
+    gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
+        (filter), a, np + 1, b, np + 1);
+
+    GST_LOG_OBJECT (filter,
+        "Generated IIR coefficients for the Chebyshev filter");
+    GST_LOG_OBJECT (filter,
+        "mode: %s, type: %d, poles: %d, lower-frequency: %.2f Hz, upper-frequency: %.2f Hz, ripple: %.2f dB",
+        (filter->mode == MODE_BAND_PASS) ? "band-pass" : "band-reject",
+        filter->type, filter->poles, filter->lower_frequency,
+        filter->upper_frequency, filter->ripple);
+
+    GST_LOG_OBJECT (filter, "%.2f dB gain @ 0Hz",
+        20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b,
+                np + 1, 1.0, 0.0)));
+    {
+      gdouble w1 = 2.0 * G_PI * (filter->lower_frequency / rate);
+      gdouble w2 = 2.0 * G_PI * (filter->upper_frequency / rate);
+      gdouble w0 = (w2 + w1) / 2.0;
+      gdouble zr, zi;
+
+      zr = cos (w1);
+      zi = sin (w1);
+      GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
+          20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1,
+                  b, np + 1, zr, zi)), (int) filter->lower_frequency);
+      zr = cos (w0);
+      zi = sin (w0);
+      GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
+          20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1,
+                  b, np + 1, zr, zi)),
+          (int) ((filter->lower_frequency + filter->upper_frequency) / 2.0));
+      zr = cos (w2);
+      zi = sin (w2);
+      GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
+          20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1,
+                  b, np + 1, zr, zi)), (int) filter->upper_frequency);
+    }
+    GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
+        20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b,
+                np + 1, -1.0, 0.0)), rate / 2);
+  }
+}
+
+static void
+gst_audio_cheb_band_finalize (GObject * object)
+{
+  GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object);
+
+  g_mutex_clear (&filter->lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_audio_cheb_band_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object);
+
+  switch (prop_id) {
+    case PROP_MODE:
+      g_mutex_lock (&filter->lock);
+      filter->mode = g_value_get_enum (value);
+      generate_coefficients (filter, NULL);
+      g_mutex_unlock (&filter->lock);
+      break;
+    case PROP_TYPE:
+      g_mutex_lock (&filter->lock);
+      filter->type = g_value_get_int (value);
+      generate_coefficients (filter, NULL);
+      g_mutex_unlock (&filter->lock);
+      break;
+    case PROP_LOWER_FREQUENCY:
+      g_mutex_lock (&filter->lock);
+      filter->lower_frequency = g_value_get_float (value);
+      generate_coefficients (filter, NULL);
+      g_mutex_unlock (&filter->lock);
+      break;
+    case PROP_UPPER_FREQUENCY:
+      g_mutex_lock (&filter->lock);
+      filter->upper_frequency = g_value_get_float (value);
+      generate_coefficients (filter, NULL);
+      g_mutex_unlock (&filter->lock);
+      break;
+    case PROP_RIPPLE:
+      g_mutex_lock (&filter->lock);
+      filter->ripple = g_value_get_float (value);
+      generate_coefficients (filter, NULL);
+      g_mutex_unlock (&filter->lock);
+      break;
+    case PROP_POLES:
+      g_mutex_lock (&filter->lock);
+      filter->poles = GST_ROUND_UP_4 (g_value_get_int (value));
+      generate_coefficients (filter, NULL);
+      g_mutex_unlock (&filter->lock);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_audio_cheb_band_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object);
+
+  switch (prop_id) {
+    case PROP_MODE:
+      g_value_set_enum (value, filter->mode);
+      break;
+    case PROP_TYPE:
+      g_value_set_int (value, filter->type);
+      break;
+    case PROP_LOWER_FREQUENCY:
+      g_value_set_float (value, filter->lower_frequency);
+      break;
+    case PROP_UPPER_FREQUENCY:
+      g_value_set_float (value, filter->upper_frequency);
+      break;
+    case PROP_RIPPLE:
+      g_value_set_float (value, filter->ripple);
+      break;
+    case PROP_POLES:
+      g_value_set_int (value, filter->poles);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* GstAudioFilter vmethod implementations */
+
+static gboolean
+gst_audio_cheb_band_setup (GstAudioFilter * base, const GstAudioInfo * info)
+{
+  GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (base);
+
+  generate_coefficients (filter, info);
+
+  return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, info);
+}
diff --git a/gst/audiofx/audiochebband.h b/gst/audiofx/audiochebband.h
new file mode 100644
index 0000000..58bdaf0
--- /dev/null
+++ b/gst/audiofx/audiochebband.h
@@ -0,0 +1,64 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AUDIO_CHEB_BAND_H__
+#define __GST_AUDIO_CHEB_BAND_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audiofxbaseiirfilter.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_AUDIO_CHEB_BAND            (gst_audio_cheb_band_get_type())
+#define GST_AUDIO_CHEB_BAND(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_CHEB_BAND,GstAudioChebBand))
+#define GST_IS_AUDIO_CHEB_BAND(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_CHEB_BAND))
+#define GST_AUDIO_CHEB_BAND_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_CHEB_BAND,GstAudioChebBandClass))
+#define GST_IS_AUDIO_CHEB_BAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_CHEB_BAND))
+#define GST_AUDIO_CHEB_BAND_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_CHEB_BAND,GstAudioChebBandClass))
+typedef struct _GstAudioChebBand GstAudioChebBand;
+typedef struct _GstAudioChebBandClass GstAudioChebBandClass;
+
+struct _GstAudioChebBand
+{
+  GstAudioFXBaseIIRFilter parent;
+
+  gint mode;
+  gint type;
+  gint poles;
+  gfloat lower_frequency;
+  gfloat upper_frequency;
+  gfloat ripple;
+
+  /* < private > */
+  GMutex lock;
+};
+
+struct _GstAudioChebBandClass
+{
+  GstAudioFXBaseIIRFilterClass parent;
+};
+
+GType gst_audio_cheb_band_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_AUDIO_CHEB_BAND_H__ */
diff --git a/gst/audiofx/audiocheblimit.c b/gst/audiofx/audiocheblimit.c
new file mode 100644
index 0000000..e278886
--- /dev/null
+++ b/gst/audiofx/audiocheblimit.c
@@ -0,0 +1,574 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* 
+ * Chebyshev type 1 filter design based on
+ * "The Scientist and Engineer's Guide to DSP", Chapter 20.
+ * http://www.dspguide.com/
+ *
+ * For type 2 and Chebyshev filters in general read
+ * http://en.wikipedia.org/wiki/Chebyshev_filter
+ *
+ */
+
+/**
+ * SECTION:element-audiocheblimit
+ *
+ * Attenuates all frequencies above the cutoff frequency (low-pass) or all frequencies below the
+ * cutoff frequency (high-pass). The number of poles and the ripple parameter control the rolloff.
+ *
+ * This element has the advantage over the windowed sinc lowpass and highpass filter that it is
+ * much faster and produces almost as good results. It's only disadvantages are the highly
+ * non-linear phase and the slower rolloff compared to a windowed sinc filter with a large kernel.
+ *
+ * For type 1 the ripple parameter specifies how much ripple in dB is allowed in the passband, i.e.
+ * some frequencies in the passband will be amplified by that value. A higher ripple value will allow
+ * a faster rolloff.
+ *
+ * For type 2 the ripple parameter specifies the stopband attenuation. In the stopband the gain will
+ * be at most this value. A lower ripple value will allow a faster rolloff.
+ *
+ * As a special case, a Chebyshev type 1 filter with no ripple is a Butterworth filter.
+ *
+ * <note><para>
+ * Be warned that a too large number of poles can produce noise. The most poles are possible with
+ * a cutoff frequency at a quarter of the sampling rate.
+ * </para></note>
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc freq=1500 ! audioconvert ! audiocheblimit mode=low-pass cutoff=1000 poles=4 ! audioconvert ! alsasink
+ * gst-launch-1.0 filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiocheblimit mode=high-pass cutoff=400 ripple=0.2 ! audioconvert ! alsasink
+ * gst-launch-1.0 audiotestsrc wave=white-noise ! audioconvert ! audiocheblimit mode=low-pass cutoff=800 type=2 ! audioconvert ! alsasink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include <math.h>
+
+#include "math_compat.h"
+
+#include "audiocheblimit.h"
+
+#include "gst/glib-compat-private.h"
+
+#define GST_CAT_DEFAULT gst_audio_cheb_limit_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+enum
+{
+  PROP_0,
+  PROP_MODE,
+  PROP_TYPE,
+  PROP_CUTOFF,
+  PROP_RIPPLE,
+  PROP_POLES
+};
+
+#define gst_audio_cheb_limit_parent_class parent_class
+G_DEFINE_TYPE (GstAudioChebLimit,
+    gst_audio_cheb_limit, GST_TYPE_AUDIO_FX_BASE_IIR_FILTER);
+
+static void gst_audio_cheb_limit_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_audio_cheb_limit_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+static void gst_audio_cheb_limit_finalize (GObject * object);
+
+static gboolean gst_audio_cheb_limit_setup (GstAudioFilter * filter,
+    const GstAudioInfo * info);
+
+enum
+{
+  MODE_LOW_PASS = 0,
+  MODE_HIGH_PASS
+};
+
+#define GST_TYPE_AUDIO_CHEBYSHEV_FREQ_LIMIT_MODE (gst_audio_cheb_limit_mode_get_type ())
+static GType
+gst_audio_cheb_limit_mode_get_type (void)
+{
+  static GType gtype = 0;
+
+  if (gtype == 0) {
+    static const GEnumValue values[] = {
+      {MODE_LOW_PASS, "Low pass (default)",
+          "low-pass"},
+      {MODE_HIGH_PASS, "High pass",
+          "high-pass"},
+      {0, NULL, NULL}
+    };
+
+    gtype = g_enum_register_static ("GstAudioChebLimitMode", values);
+  }
+  return gtype;
+}
+
+/* GObject vmethod implementations */
+
+static void
+gst_audio_cheb_limit_class_init (GstAudioChebLimitClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (gst_audio_cheb_limit_debug, "audiocheblimit", 0,
+      "audiocheblimit element");
+
+  gobject_class->set_property = gst_audio_cheb_limit_set_property;
+  gobject_class->get_property = gst_audio_cheb_limit_get_property;
+  gobject_class->finalize = gst_audio_cheb_limit_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_MODE,
+      g_param_spec_enum ("mode", "Mode",
+          "Low pass or high pass mode",
+          GST_TYPE_AUDIO_CHEBYSHEV_FREQ_LIMIT_MODE, MODE_LOW_PASS,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_TYPE,
+      g_param_spec_int ("type", "Type", "Type of the chebychev filter", 1, 2, 1,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  /* FIXME: Don't use the complete possible range but restrict the upper boundary
+   * so automatically generated UIs can use a slider without */
+  g_object_class_install_property (gobject_class, PROP_CUTOFF,
+      g_param_spec_float ("cutoff", "Cutoff", "Cut off frequency (Hz)", 0.0,
+          100000.0, 0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_RIPPLE,
+      g_param_spec_float ("ripple", "Ripple", "Amount of ripple (dB)", 0.0,
+          200.0, 0.25,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  /* FIXME: What to do about this upper boundary? With a cutoff frequency of
+   * rate/4 32 poles are completely possible, with a cutoff frequency very low
+   * or very high 16 poles already produces only noise */
+  g_object_class_install_property (gobject_class, PROP_POLES,
+      g_param_spec_int ("poles", "Poles",
+          "Number of poles to use, will be rounded up to the next even number",
+          2, 32, 4,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Low pass & high pass filter",
+      "Filter/Effect/Audio",
+      "Chebyshev low pass and high pass filter",
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_cheb_limit_setup);
+}
+
+static void
+gst_audio_cheb_limit_init (GstAudioChebLimit * filter)
+{
+  filter->cutoff = 0.0;
+  filter->mode = MODE_LOW_PASS;
+  filter->type = 1;
+  filter->poles = 4;
+  filter->ripple = 0.25;
+
+  g_mutex_init (&filter->lock);
+}
+
+static void
+generate_biquad_coefficients (GstAudioChebLimit * filter,
+    gint p, gint rate, gdouble * b0, gdouble * b1, gdouble * b2,
+    gdouble * a1, gdouble * a2)
+{
+  gint np = filter->poles;
+  gdouble ripple = filter->ripple;
+
+  /* pole location in s-plane */
+  gdouble rp, ip;
+
+  /* zero location in s-plane */
+  gdouble iz = 0.0;
+
+  /* transfer function coefficients for the z-plane */
+  gdouble x0, x1, x2, y1, y2;
+  gint type = filter->type;
+
+  /* Calculate pole location for lowpass at frequency 1 */
+  {
+    gdouble angle = (G_PI / 2.0) * (2.0 * p - 1) / np;
+
+    rp = -sin (angle);
+    ip = cos (angle);
+  }
+
+  /* If we allow ripple, move the pole from the unit
+   * circle to an ellipse and keep cutoff at frequency 1 */
+  if (ripple > 0 && type == 1) {
+    gdouble es, vx;
+
+    es = sqrt (pow (10.0, ripple / 10.0) - 1.0);
+
+    vx = (1.0 / np) * asinh (1.0 / es);
+    rp = rp * sinh (vx);
+    ip = ip * cosh (vx);
+  } else if (type == 2) {
+    gdouble es, vx;
+
+    es = sqrt (pow (10.0, ripple / 10.0) - 1.0);
+    vx = (1.0 / np) * asinh (es);
+    rp = rp * sinh (vx);
+    ip = ip * cosh (vx);
+  }
+
+  /* Calculate inverse of the pole location to convert from
+   * type I to type II */
+  if (type == 2) {
+    gdouble mag2 = rp * rp + ip * ip;
+
+    rp /= mag2;
+    ip /= mag2;
+  }
+
+  /* Calculate zero location for frequency 1 on the
+   * unit circle for type 2 */
+  if (type == 2) {
+    gdouble angle = G_PI / (np * 2.0) + ((p - 1) * G_PI) / (np);
+    gdouble mag2;
+
+    iz = cos (angle);
+    mag2 = iz * iz;
+    iz /= mag2;
+  }
+
+  /* Convert from s-domain to z-domain by
+   * using the bilinear Z-transform, i.e.
+   * substitute s by (2/t)*((z-1)/(z+1))
+   * with t = 2 * tan(0.5).
+   */
+  if (type == 1) {
+    gdouble t, m, d;
+
+    t = 2.0 * tan (0.5);
+    m = rp * rp + ip * ip;
+    d = 4.0 - 4.0 * rp * t + m * t * t;
+
+    x0 = (t * t) / d;
+    x1 = 2.0 * x0;
+    x2 = x0;
+    y1 = (8.0 - 2.0 * m * t * t) / d;
+    y2 = (-4.0 - 4.0 * rp * t - m * t * t) / d;
+  } else {
+    gdouble t, m, d;
+
+    t = 2.0 * tan (0.5);
+    m = rp * rp + ip * ip;
+    d = 4.0 - 4.0 * rp * t + m * t * t;
+
+    x0 = (t * t * iz * iz + 4.0) / d;
+    x1 = (-8.0 + 2.0 * iz * iz * t * t) / d;
+    x2 = x0;
+    y1 = (8.0 - 2.0 * m * t * t) / d;
+    y2 = (-4.0 - 4.0 * rp * t - m * t * t) / d;
+  }
+
+  /* Convert from lowpass at frequency 1 to either lowpass
+   * or highpass.
+   *
+   * For lowpass substitute z^(-1) with:
+   *  -1
+   * z   - k
+   * ------------
+   *          -1
+   * 1 - k * z
+   *
+   * k = sin((1-w)/2) / sin((1+w)/2)
+   *
+   * For highpass substitute z^(-1) with:
+   *
+   *   -1
+   * -z   - k
+   * ------------
+   *          -1
+   * 1 + k * z
+   *
+   * k = -cos((1+w)/2) / cos((1-w)/2)
+   *
+   */
+  {
+    gdouble k, d;
+    gdouble omega = 2.0 * G_PI * (filter->cutoff / rate);
+
+    if (filter->mode == MODE_LOW_PASS)
+      k = sin ((1.0 - omega) / 2.0) / sin ((1.0 + omega) / 2.0);
+    else
+      k = -cos ((omega + 1.0) / 2.0) / cos ((omega - 1.0) / 2.0);
+
+    d = 1.0 + y1 * k - y2 * k * k;
+    *b0 = (x0 + k * (-x1 + k * x2)) / d;
+    *b1 = (x1 + k * k * x1 - 2.0 * k * (x0 + x2)) / d;
+    *b2 = (x0 * k * k - x1 * k + x2) / d;
+    *a1 = (2.0 * k + y1 + y1 * k * k - 2.0 * y2 * k) / d;
+    *a2 = (-k * k - y1 * k + y2) / d;
+
+    if (filter->mode == MODE_HIGH_PASS) {
+      *a1 = -*a1;
+      *b1 = -*b1;
+    }
+  }
+}
+
+static void
+generate_coefficients (GstAudioChebLimit * filter, const GstAudioInfo * info)
+{
+  gint rate;
+
+  if (info) {
+    rate = GST_AUDIO_INFO_RATE (info);
+  } else {
+    rate = GST_AUDIO_FILTER_RATE (filter);
+  }
+
+  GST_LOG_OBJECT (filter, "cutoff %f", filter->cutoff);
+
+  if (rate == 0) {
+    gdouble *a = g_new0 (gdouble, 1);
+    gdouble *b = g_new0 (gdouble, 1);
+
+    a[0] = 1.0;
+    b[0] = 1.0;
+    gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
+        (filter), a, 1, b, 1);
+
+    GST_LOG_OBJECT (filter, "rate was not set yet");
+    return;
+  }
+
+  if (filter->cutoff >= rate / 2.0) {
+    gdouble *a = g_new0 (gdouble, 1);
+    gdouble *b = g_new0 (gdouble, 1);
+
+    a[0] = 1.0;
+    b[0] = (filter->mode == MODE_LOW_PASS) ? 1.0 : 0.0;
+    gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
+        (filter), a, 1, b, 1);
+    GST_LOG_OBJECT (filter, "cutoff was higher than nyquist frequency");
+    return;
+  } else if (filter->cutoff <= 0.0) {
+    gdouble *a = g_new0 (gdouble, 1);
+    gdouble *b = g_new0 (gdouble, 1);
+
+    a[0] = 1.0;
+    b[0] = (filter->mode == MODE_LOW_PASS) ? 0.0 : 1.0;
+    gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
+        (filter), a, 1, b, 1);
+    GST_LOG_OBJECT (filter, "cutoff is lower than zero");
+    return;
+  }
+
+  /* Calculate coefficients for the chebyshev filter */
+  {
+    gint np = filter->poles;
+    gdouble *a, *b;
+    gint i, p;
+
+    a = g_new0 (gdouble, np + 3);
+    b = g_new0 (gdouble, np + 3);
+
+    /* Calculate transfer function coefficients */
+    a[2] = 1.0;
+    b[2] = 1.0;
+
+    for (p = 1; p <= np / 2; p++) {
+      gdouble b0, b1, b2, a1, a2;
+      gdouble *ta = g_new0 (gdouble, np + 3);
+      gdouble *tb = g_new0 (gdouble, np + 3);
+
+      generate_biquad_coefficients (filter, p, rate, &b0, &b1, &b2, &a1, &a2);
+
+      memcpy (ta, a, sizeof (gdouble) * (np + 3));
+      memcpy (tb, b, sizeof (gdouble) * (np + 3));
+
+      /* add the new coefficients for the new two poles
+       * to the cascade by multiplication of the transfer
+       * functions */
+      for (i = 2; i < np + 3; i++) {
+        b[i] = b0 * tb[i] + b1 * tb[i - 1] + b2 * tb[i - 2];
+        a[i] = ta[i] - a1 * ta[i - 1] - a2 * ta[i - 2];
+      }
+      g_free (ta);
+      g_free (tb);
+    }
+
+    /* Move coefficients to the beginning of the array to move from
+     * the transfer function's coefficients to the difference
+     * equation's coefficients */
+    for (i = 0; i <= np; i++) {
+      a[i] = a[i + 2];
+      b[i] = b[i + 2];
+    }
+
+    /* Normalize to unity gain at frequency 0 for lowpass
+     * and frequency 0.5 for highpass */
+    {
+      gdouble gain;
+
+      if (filter->mode == MODE_LOW_PASS)
+        gain =
+            gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1,
+            1.0, 0.0);
+      else
+        gain =
+            gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1,
+            -1.0, 0.0);
+
+      for (i = 0; i <= np; i++) {
+        b[i] /= gain;
+      }
+    }
+
+    gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
+        (filter), a, np + 1, b, np + 1);
+
+    GST_LOG_OBJECT (filter,
+        "Generated IIR coefficients for the Chebyshev filter");
+    GST_LOG_OBJECT (filter,
+        "mode: %s, type: %d, poles: %d, cutoff: %.2f Hz, ripple: %.2f dB",
+        (filter->mode == MODE_LOW_PASS) ? "low-pass" : "high-pass",
+        filter->type, filter->poles, filter->cutoff, filter->ripple);
+    GST_LOG_OBJECT (filter, "%.2f dB gain @ 0 Hz",
+        20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b,
+                np + 1, 1.0, 0.0)));
+
+#ifndef GST_DISABLE_GST_DEBUG
+    {
+      gdouble wc = 2.0 * G_PI * (filter->cutoff / rate);
+      gdouble zr = cos (wc), zi = sin (wc);
+
+      GST_LOG_OBJECT (filter, "%.2f dB gain @ %d Hz",
+          20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1,
+                  b, np + 1, zr, zi)), (int) filter->cutoff);
+    }
+#endif
+
+    GST_LOG_OBJECT (filter, "%.2f dB gain @ %d Hz",
+        20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b,
+                np + 1, -1.0, 0.0)), rate);
+  }
+}
+
+static void
+gst_audio_cheb_limit_finalize (GObject * object)
+{
+  GstAudioChebLimit *filter = GST_AUDIO_CHEB_LIMIT (object);
+
+  g_mutex_clear (&filter->lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_audio_cheb_limit_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAudioChebLimit *filter = GST_AUDIO_CHEB_LIMIT (object);
+
+  switch (prop_id) {
+    case PROP_MODE:
+      g_mutex_lock (&filter->lock);
+      filter->mode = g_value_get_enum (value);
+      generate_coefficients (filter, NULL);
+      g_mutex_unlock (&filter->lock);
+      break;
+    case PROP_TYPE:
+      g_mutex_lock (&filter->lock);
+      filter->type = g_value_get_int (value);
+      generate_coefficients (filter, NULL);
+      g_mutex_unlock (&filter->lock);
+      break;
+    case PROP_CUTOFF:
+      g_mutex_lock (&filter->lock);
+      filter->cutoff = g_value_get_float (value);
+      generate_coefficients (filter, NULL);
+      g_mutex_unlock (&filter->lock);
+      break;
+    case PROP_RIPPLE:
+      g_mutex_lock (&filter->lock);
+      filter->ripple = g_value_get_float (value);
+      generate_coefficients (filter, NULL);
+      g_mutex_unlock (&filter->lock);
+      break;
+    case PROP_POLES:
+      g_mutex_lock (&filter->lock);
+      filter->poles = GST_ROUND_UP_2 (g_value_get_int (value));
+      generate_coefficients (filter, NULL);
+      g_mutex_unlock (&filter->lock);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_audio_cheb_limit_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAudioChebLimit *filter = GST_AUDIO_CHEB_LIMIT (object);
+
+  switch (prop_id) {
+    case PROP_MODE:
+      g_value_set_enum (value, filter->mode);
+      break;
+    case PROP_TYPE:
+      g_value_set_int (value, filter->type);
+      break;
+    case PROP_CUTOFF:
+      g_value_set_float (value, filter->cutoff);
+      break;
+    case PROP_RIPPLE:
+      g_value_set_float (value, filter->ripple);
+      break;
+    case PROP_POLES:
+      g_value_set_int (value, filter->poles);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* GstAudioFilter vmethod implementations */
+
+static gboolean
+gst_audio_cheb_limit_setup (GstAudioFilter * base, const GstAudioInfo * info)
+{
+  GstAudioChebLimit *filter = GST_AUDIO_CHEB_LIMIT (base);
+
+  generate_coefficients (filter, info);
+
+  return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, info);
+}
diff --git a/gst/audiofx/audiocheblimit.h b/gst/audiofx/audiocheblimit.h
new file mode 100644
index 0000000..1930960
--- /dev/null
+++ b/gst/audiofx/audiocheblimit.h
@@ -0,0 +1,66 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AUDIO_CHEB_LIMIT_H__
+#define __GST_AUDIO_CHEB_LIMIT_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audiofxbaseiirfilter.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AUDIO_CHEB_LIMIT            (gst_audio_cheb_limit_get_type())
+#define GST_AUDIO_CHEB_LIMIT(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_CHEB_LIMIT,GstAudioChebLimit))
+#define GST_IS_AUDIO_CHEB_LIMIT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_CHEB_LIMIT))
+#define GST_AUDIO_CHEB_LIMIT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_CHEB_LIMIT,GstAudioChebLimitClass))
+#define GST_IS_AUDIO_CHEB_LIMIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_CHEB_LIMIT))
+#define GST_AUDIO_CHEB_LIMIT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_CHEB_LIMIT,GstAudioChebLimitClass))
+
+typedef struct _GstAudioChebLimit GstAudioChebLimit;
+typedef struct _GstAudioChebLimitClass GstAudioChebLimitClass;
+
+struct _GstAudioChebLimit
+{
+  GstAudioFXBaseIIRFilter parent;
+
+  gint mode;
+  gint type;
+  gint poles;
+  gfloat cutoff;
+  gfloat ripple;
+
+  /* < private > */
+  GMutex lock;
+};
+
+struct _GstAudioChebLimitClass
+{
+  GstAudioFXBaseIIRFilterClass parent;
+};
+
+GType gst_audio_cheb_limit_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_AUDIO_CHEB_LIMIT_H__ */
diff --git a/gst/audiofx/audiodynamic.c b/gst/audiofx/audiodynamic.c
new file mode 100644
index 0000000..9b3a62c
--- /dev/null
+++ b/gst/audiofx/audiodynamic.c
@@ -0,0 +1,713 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-audiodynamic
+ *
+ * This element can act as a compressor or expander. A compressor changes the
+ * amplitude of all samples above a specific threshold with a specific ratio,
+ * a expander does the same for all samples below a specific threshold. If
+ * soft-knee mode is selected the ratio is applied smoothly.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc wave=saw ! audiodynamic characteristics=soft-knee mode=compressor threshold=0.5 ratio=0.5 ! alsasink
+ * gst-launch-1.0 filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiodynamic characteristics=hard-knee mode=expander threshold=0.2 ratio=4.0 ! alsasink
+ * gst-launch-1.0 audiotestsrc wave=saw ! audioconvert ! audiodynamic ! audioconvert ! alsasink
+ * ]|
+ * </refsect2>
+ */
+
+/* TODO: Implement attack and release parameters */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audiodynamic.h"
+
+#define GST_CAT_DEFAULT gst_audio_dynamic_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+/* Filter signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_CHARACTERISTICS,
+  PROP_MODE,
+  PROP_THRESHOLD,
+  PROP_RATIO
+};
+
+#define ALLOWED_CAPS \
+    "audio/x-raw,"                                                \
+    " format=(string) {"GST_AUDIO_NE(S16)","GST_AUDIO_NE(F32)"}," \
+    " rate=(int)[1,MAX],"                                         \
+    " channels=(int)[1,MAX],"                                     \
+    " layout=(string) {interleaved, non-interleaved}"
+
+G_DEFINE_TYPE (GstAudioDynamic, gst_audio_dynamic, GST_TYPE_AUDIO_FILTER);
+
+static void gst_audio_dynamic_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_audio_dynamic_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_audio_dynamic_setup (GstAudioFilter * filter,
+    const GstAudioInfo * info);
+static GstFlowReturn gst_audio_dynamic_transform_ip (GstBaseTransform * base,
+    GstBuffer * buf);
+
+static void
+gst_audio_dynamic_transform_hard_knee_compressor_int (GstAudioDynamic * filter,
+    gint16 * data, guint num_samples);
+static void
+gst_audio_dynamic_transform_hard_knee_compressor_float (GstAudioDynamic *
+    filter, gfloat * data, guint num_samples);
+static void
+gst_audio_dynamic_transform_soft_knee_compressor_int (GstAudioDynamic * filter,
+    gint16 * data, guint num_samples);
+static void
+gst_audio_dynamic_transform_soft_knee_compressor_float (GstAudioDynamic *
+    filter, gfloat * data, guint num_samples);
+static void gst_audio_dynamic_transform_hard_knee_expander_int (GstAudioDynamic
+    * filter, gint16 * data, guint num_samples);
+static void
+gst_audio_dynamic_transform_hard_knee_expander_float (GstAudioDynamic * filter,
+    gfloat * data, guint num_samples);
+static void gst_audio_dynamic_transform_soft_knee_expander_int (GstAudioDynamic
+    * filter, gint16 * data, guint num_samples);
+static void
+gst_audio_dynamic_transform_soft_knee_expander_float (GstAudioDynamic * filter,
+    gfloat * data, guint num_samples);
+
+static const GstAudioDynamicProcessFunc process_functions[] = {
+  (GstAudioDynamicProcessFunc)
+      gst_audio_dynamic_transform_hard_knee_compressor_int,
+  (GstAudioDynamicProcessFunc)
+      gst_audio_dynamic_transform_hard_knee_compressor_float,
+  (GstAudioDynamicProcessFunc)
+      gst_audio_dynamic_transform_soft_knee_compressor_int,
+  (GstAudioDynamicProcessFunc)
+      gst_audio_dynamic_transform_soft_knee_compressor_float,
+  (GstAudioDynamicProcessFunc)
+      gst_audio_dynamic_transform_hard_knee_expander_int,
+  (GstAudioDynamicProcessFunc)
+      gst_audio_dynamic_transform_hard_knee_expander_float,
+  (GstAudioDynamicProcessFunc)
+      gst_audio_dynamic_transform_soft_knee_expander_int,
+  (GstAudioDynamicProcessFunc)
+  gst_audio_dynamic_transform_soft_knee_expander_float
+};
+
+enum
+{
+  CHARACTERISTICS_HARD_KNEE = 0,
+  CHARACTERISTICS_SOFT_KNEE
+};
+
+#define GST_TYPE_AUDIO_DYNAMIC_CHARACTERISTICS (gst_audio_dynamic_characteristics_get_type ())
+static GType
+gst_audio_dynamic_characteristics_get_type (void)
+{
+  static GType gtype = 0;
+
+  if (gtype == 0) {
+    static const GEnumValue values[] = {
+      {CHARACTERISTICS_HARD_KNEE, "Hard Knee (default)",
+          "hard-knee"},
+      {CHARACTERISTICS_SOFT_KNEE, "Soft Knee (smooth)",
+          "soft-knee"},
+      {0, NULL, NULL}
+    };
+
+    gtype = g_enum_register_static ("GstAudioDynamicCharacteristics", values);
+  }
+  return gtype;
+}
+
+enum
+{
+  MODE_COMPRESSOR = 0,
+  MODE_EXPANDER
+};
+
+#define GST_TYPE_AUDIO_DYNAMIC_MODE (gst_audio_dynamic_mode_get_type ())
+static GType
+gst_audio_dynamic_mode_get_type (void)
+{
+  static GType gtype = 0;
+
+  if (gtype == 0) {
+    static const GEnumValue values[] = {
+      {MODE_COMPRESSOR, "Compressor (default)",
+          "compressor"},
+      {MODE_EXPANDER, "Expander", "expander"},
+      {0, NULL, NULL}
+    };
+
+    gtype = g_enum_register_static ("GstAudioDynamicMode", values);
+  }
+  return gtype;
+}
+
+static void
+gst_audio_dynamic_set_process_function (GstAudioDynamic * filter,
+    const GstAudioInfo * info)
+{
+  gint func_index;
+
+  func_index = (filter->mode == MODE_COMPRESSOR) ? 0 : 4;
+  func_index += (filter->characteristics == CHARACTERISTICS_HARD_KNEE) ? 0 : 2;
+  func_index += (GST_AUDIO_INFO_FORMAT (info) == GST_AUDIO_FORMAT_F32) ? 1 : 0;
+
+  g_assert (func_index >= 0 && func_index < G_N_ELEMENTS (process_functions));
+
+  filter->process = process_functions[func_index];
+}
+
+/* GObject vmethod implementations */
+
+static void
+gst_audio_dynamic_class_init (GstAudioDynamicClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstCaps *caps;
+
+  GST_DEBUG_CATEGORY_INIT (gst_audio_dynamic_debug, "audiodynamic", 0,
+      "audiodynamic element");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_audio_dynamic_set_property;
+  gobject_class->get_property = gst_audio_dynamic_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_CHARACTERISTICS,
+      g_param_spec_enum ("characteristics", "Characteristics",
+          "Selects whether the ratio should be applied smooth (soft-knee) "
+          "or hard (hard-knee).",
+          GST_TYPE_AUDIO_DYNAMIC_CHARACTERISTICS, CHARACTERISTICS_HARD_KNEE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MODE,
+      g_param_spec_enum ("mode", "Mode",
+          "Selects whether the filter should work on loud samples (compressor) or"
+          "quiet samples (expander).",
+          GST_TYPE_AUDIO_DYNAMIC_MODE, MODE_COMPRESSOR,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_THRESHOLD,
+      g_param_spec_float ("threshold", "Threshold",
+          "Threshold until the filter is activated", 0.0, 1.0,
+          0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RATIO,
+      g_param_spec_float ("ratio", "Ratio",
+          "Ratio that should be applied", 0.0, G_MAXFLOAT,
+          1.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Dynamic range controller", "Filter/Effect/Audio",
+      "Compressor and Expander", "Sebastian Dröge <slomo@circular-chaos.org>");
+
+  caps = gst_caps_from_string (ALLOWED_CAPS);
+  gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass),
+      caps);
+  gst_caps_unref (caps);
+
+  GST_AUDIO_FILTER_CLASS (klass)->setup =
+      GST_DEBUG_FUNCPTR (gst_audio_dynamic_setup);
+
+  GST_BASE_TRANSFORM_CLASS (klass)->transform_ip =
+      GST_DEBUG_FUNCPTR (gst_audio_dynamic_transform_ip);
+  GST_BASE_TRANSFORM_CLASS (klass)->transform_ip_on_passthrough = FALSE;
+}
+
+static void
+gst_audio_dynamic_init (GstAudioDynamic * filter)
+{
+  filter->ratio = 1.0;
+  filter->threshold = 0.0;
+  filter->characteristics = CHARACTERISTICS_HARD_KNEE;
+  filter->mode = MODE_COMPRESSOR;
+  gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
+  gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE);
+}
+
+static void
+gst_audio_dynamic_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAudioDynamic *filter = GST_AUDIO_DYNAMIC (object);
+
+  switch (prop_id) {
+    case PROP_CHARACTERISTICS:
+      filter->characteristics = g_value_get_enum (value);
+      gst_audio_dynamic_set_process_function (filter,
+          GST_AUDIO_FILTER_INFO (filter));
+      break;
+    case PROP_MODE:
+      filter->mode = g_value_get_enum (value);
+      gst_audio_dynamic_set_process_function (filter,
+          GST_AUDIO_FILTER_INFO (filter));
+      break;
+    case PROP_THRESHOLD:
+      filter->threshold = g_value_get_float (value);
+      break;
+    case PROP_RATIO:
+      filter->ratio = g_value_get_float (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_audio_dynamic_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAudioDynamic *filter = GST_AUDIO_DYNAMIC (object);
+
+  switch (prop_id) {
+    case PROP_CHARACTERISTICS:
+      g_value_set_enum (value, filter->characteristics);
+      break;
+    case PROP_MODE:
+      g_value_set_enum (value, filter->mode);
+      break;
+    case PROP_THRESHOLD:
+      g_value_set_float (value, filter->threshold);
+      break;
+    case PROP_RATIO:
+      g_value_set_float (value, filter->ratio);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* GstAudioFilter vmethod implementations */
+
+static gboolean
+gst_audio_dynamic_setup (GstAudioFilter * base, const GstAudioInfo * info)
+{
+  GstAudioDynamic *filter = GST_AUDIO_DYNAMIC (base);
+
+  gst_audio_dynamic_set_process_function (filter, info);
+  return TRUE;
+}
+
+static void
+gst_audio_dynamic_transform_hard_knee_compressor_int (GstAudioDynamic * filter,
+    gint16 * data, guint num_samples)
+{
+  glong val;
+  glong thr_p = filter->threshold * G_MAXINT16;
+  glong thr_n = filter->threshold * G_MININT16;
+
+  /* Nothing to do for us if ratio is 1.0 or if the threshold
+   * equals 1.0. */
+  if (filter->threshold == 1.0 || filter->ratio == 1.0)
+    return;
+
+  for (; num_samples; num_samples--) {
+    val = *data;
+
+    if (val > thr_p) {
+      val = thr_p + (val - thr_p) * filter->ratio;
+    } else if (val < thr_n) {
+      val = thr_n + (val - thr_n) * filter->ratio;
+    }
+    *data++ = (gint16) CLAMP (val, G_MININT16, G_MAXINT16);
+  }
+}
+
+static void
+gst_audio_dynamic_transform_hard_knee_compressor_float (GstAudioDynamic *
+    filter, gfloat * data, guint num_samples)
+{
+  gdouble val, threshold = filter->threshold;
+
+  /* Nothing to do for us if ratio == 1.0.
+   * As float values can be above 1.0 we have to do something
+   * if threshold is greater than 1.0. */
+  if (filter->ratio == 1.0)
+    return;
+
+  for (; num_samples; num_samples--) {
+    val = *data;
+
+    if (val > threshold) {
+      val = threshold + (val - threshold) * filter->ratio;
+    } else if (val < -threshold) {
+      val = -threshold + (val + threshold) * filter->ratio;
+    }
+    *data++ = (gfloat) val;
+  }
+}
+
+static void
+gst_audio_dynamic_transform_soft_knee_compressor_int (GstAudioDynamic * filter,
+    gint16 * data, guint num_samples)
+{
+  glong val;
+  glong thr_p = filter->threshold * G_MAXINT16;
+  glong thr_n = filter->threshold * G_MININT16;
+  gdouble a_p, b_p, c_p;
+  gdouble a_n, b_n, c_n;
+
+  /* Nothing to do for us if ratio is 1.0 or if the threshold
+   * equals 1.0. */
+  if (filter->threshold == 1.0 || filter->ratio == 1.0)
+    return;
+
+  /* We build a 2nd degree polynomial here for
+   * values greater than threshold or small than
+   * -threshold with:
+   * f(t) = t, f'(t) = 1, f'(m) = r
+   * =>
+   * a = (1-r)/(2*(t-m))
+   * b = (r*t - m)/(t-m)
+   * c = t * (1 - b - a*t)
+   * f(x) = ax^2 + bx + c
+   */
+
+  /* shouldn't happen because this would only be the case
+   * for threshold == 1.0 which we catch above */
+  g_assert (thr_p - G_MAXINT16 != 0);
+  g_assert (thr_n - G_MININT != 0);
+
+  a_p = (1 - filter->ratio) / (2 * (thr_p - G_MAXINT16));
+  b_p = (filter->ratio * thr_p - G_MAXINT16) / (thr_p - G_MAXINT16);
+  c_p = thr_p * (1 - b_p - a_p * thr_p);
+  a_n = (1 - filter->ratio) / (2 * (thr_n - G_MININT16));
+  b_n = (filter->ratio * thr_n - G_MININT16) / (thr_n - G_MININT16);
+  c_n = thr_n * (1 - b_n - a_n * thr_n);
+
+  for (; num_samples; num_samples--) {
+    val = *data;
+
+    if (val > thr_p) {
+      val = a_p * val * val + b_p * val + c_p;
+    } else if (val < thr_n) {
+      val = a_n * val * val + b_n * val + c_n;
+    }
+    *data++ = (gint16) CLAMP (val, G_MININT16, G_MAXINT16);
+  }
+}
+
+static void
+gst_audio_dynamic_transform_soft_knee_compressor_float (GstAudioDynamic *
+    filter, gfloat * data, guint num_samples)
+{
+  gdouble val;
+  gdouble threshold = filter->threshold;
+  gdouble a_p, b_p, c_p;
+  gdouble a_n, b_n, c_n;
+
+  /* Nothing to do for us if ratio == 1.0.
+   * As float values can be above 1.0 we have to do something
+   * if threshold is greater than 1.0. */
+  if (filter->ratio == 1.0)
+    return;
+
+  /* We build a 2nd degree polynomial here for
+   * values greater than threshold or small than
+   * -threshold with:
+   * f(t) = t, f'(t) = 1, f'(m) = r
+   * =>
+   * a = (1-r)/(2*(t-m))
+   * b = (r*t - m)/(t-m)
+   * c = t * (1 - b - a*t)
+   * f(x) = ax^2 + bx + c
+   */
+
+  /* FIXME: If treshold is the same as the maximum
+   * we need to raise it a bit to prevent
+   * division by zero. */
+  if (threshold == 1.0)
+    threshold = 1.0 + 0.00001;
+
+  a_p = (1.0 - filter->ratio) / (2.0 * (threshold - 1.0));
+  b_p = (filter->ratio * threshold - 1.0) / (threshold - 1.0);
+  c_p = threshold * (1.0 - b_p - a_p * threshold);
+  a_n = (1.0 - filter->ratio) / (2.0 * (-threshold + 1.0));
+  b_n = (-filter->ratio * threshold + 1.0) / (-threshold + 1.0);
+  c_n = -threshold * (1.0 - b_n + a_n * threshold);
+
+  for (; num_samples; num_samples--) {
+    val = *data;
+
+    if (val > 1.0) {
+      val = 1.0 + (val - 1.0) * filter->ratio;
+    } else if (val > threshold) {
+      val = a_p * val * val + b_p * val + c_p;
+    } else if (val < -1.0) {
+      val = -1.0 + (val + 1.0) * filter->ratio;
+    } else if (val < -threshold) {
+      val = a_n * val * val + b_n * val + c_n;
+    }
+    *data++ = (gfloat) val;
+  }
+}
+
+static void
+gst_audio_dynamic_transform_hard_knee_expander_int (GstAudioDynamic * filter,
+    gint16 * data, guint num_samples)
+{
+  glong val;
+  glong thr_p = filter->threshold * G_MAXINT16;
+  glong thr_n = filter->threshold * G_MININT16;
+  gdouble zero_p, zero_n;
+
+  /* Nothing to do for us here if threshold equals 0.0
+   * or ratio equals 1.0 */
+  if (filter->threshold == 0.0 || filter->ratio == 1.0)
+    return;
+
+  /* zero crossing of our function */
+  if (filter->ratio != 0.0) {
+    zero_p = thr_p - thr_p / filter->ratio;
+    zero_n = thr_n - thr_n / filter->ratio;
+  } else {
+    zero_p = zero_n = 0.0;
+  }
+
+  if (zero_p < 0.0)
+    zero_p = 0.0;
+  if (zero_n > 0.0)
+    zero_n = 0.0;
+
+  for (; num_samples; num_samples--) {
+    val = *data;
+
+    if (val < thr_p && val > zero_p) {
+      val = filter->ratio * val + thr_p * (1 - filter->ratio);
+    } else if ((val <= zero_p && val > 0) || (val >= zero_n && val < 0)) {
+      val = 0;
+    } else if (val > thr_n && val < zero_n) {
+      val = filter->ratio * val + thr_n * (1 - filter->ratio);
+    }
+    *data++ = (gint16) CLAMP (val, G_MININT16, G_MAXINT16);
+  }
+}
+
+static void
+gst_audio_dynamic_transform_hard_knee_expander_float (GstAudioDynamic * filter,
+    gfloat * data, guint num_samples)
+{
+  gdouble val, threshold = filter->threshold, zero;
+
+  /* Nothing to do for us here if threshold equals 0.0
+   * or ratio equals 1.0 */
+  if (filter->threshold == 0.0 || filter->ratio == 1.0)
+    return;
+
+  /* zero crossing of our function */
+  if (filter->ratio != 0.0)
+    zero = threshold - threshold / filter->ratio;
+  else
+    zero = 0.0;
+
+  if (zero < 0.0)
+    zero = 0.0;
+
+  for (; num_samples; num_samples--) {
+    val = *data;
+
+    if (val < threshold && val > zero) {
+      val = filter->ratio * val + threshold * (1.0 - filter->ratio);
+    } else if ((val <= zero && val > 0.0) || (val >= -zero && val < 0.0)) {
+      val = 0.0;
+    } else if (val > -threshold && val < -zero) {
+      val = filter->ratio * val - threshold * (1.0 - filter->ratio);
+    }
+    *data++ = (gfloat) val;
+  }
+}
+
+static void
+gst_audio_dynamic_transform_soft_knee_expander_int (GstAudioDynamic * filter,
+    gint16 * data, guint num_samples)
+{
+  glong val;
+  glong thr_p = filter->threshold * G_MAXINT16;
+  glong thr_n = filter->threshold * G_MININT16;
+  gdouble zero_p, zero_n;
+  gdouble a_p, b_p, c_p;
+  gdouble a_n, b_n, c_n;
+  gdouble r2;
+
+  /* Nothing to do for us here if threshold equals 0.0
+   * or ratio equals 1.0 */
+  if (filter->threshold == 0.0 || filter->ratio == 1.0)
+    return;
+
+  /* zero crossing of our function */
+  zero_p = (thr_p * (filter->ratio - 1.0)) / (1.0 + filter->ratio);
+  zero_n = (thr_n * (filter->ratio - 1.0)) / (1.0 + filter->ratio);
+
+  if (zero_p < 0.0)
+    zero_p = 0.0;
+  if (zero_n > 0.0)
+    zero_n = 0.0;
+
+  /* shouldn't happen as this would only happen
+   * with threshold == 0.0 */
+  g_assert (thr_p != 0);
+  g_assert (thr_n != 0);
+
+  /* We build a 2n degree polynomial here for values between
+   * 0 and threshold or 0 and -threshold with:
+   * f(t) = t, f'(t) = 1, f(z) = 0, f'(z) = r
+   * z between 0 and t
+   * =>
+   * a = (1 - r^2) / (4 * t)
+   * b = (1 + r^2) / 2
+   * c = t * (1.0 - b - a*t)
+   * f(x) = ax^2 + bx + c */
+  r2 = filter->ratio * filter->ratio;
+  a_p = (1.0 - r2) / (4.0 * thr_p);
+  b_p = (1.0 + r2) / 2.0;
+  c_p = thr_p * (1.0 - b_p - a_p * thr_p);
+  a_n = (1.0 - r2) / (4.0 * thr_n);
+  b_n = (1.0 + r2) / 2.0;
+  c_n = thr_n * (1.0 - b_n - a_n * thr_n);
+
+  for (; num_samples; num_samples--) {
+    val = *data;
+
+    if (val < thr_p && val > zero_p) {
+      val = a_p * val * val + b_p * val + c_p;
+    } else if ((val <= zero_p && val > 0) || (val >= zero_n && val < 0)) {
+      val = 0;
+    } else if (val > thr_n && val < zero_n) {
+      val = a_n * val * val + b_n * val + c_n;
+    }
+    *data++ = (gint16) CLAMP (val, G_MININT16, G_MAXINT16);
+  }
+}
+
+static void
+gst_audio_dynamic_transform_soft_knee_expander_float (GstAudioDynamic * filter,
+    gfloat * data, guint num_samples)
+{
+  gdouble val;
+  gdouble threshold = filter->threshold;
+  gdouble zero;
+  gdouble a_p, b_p, c_p;
+  gdouble a_n, b_n, c_n;
+  gdouble r2;
+
+  /* Nothing to do for us here if threshold equals 0.0
+   * or ratio equals 1.0 */
+  if (filter->threshold == 0.0 || filter->ratio == 1.0)
+    return;
+
+  /* zero crossing of our function */
+  zero = (threshold * (filter->ratio - 1.0)) / (1.0 + filter->ratio);
+
+  if (zero < 0.0)
+    zero = 0.0;
+
+  /* shouldn't happen as this only happens with
+   * threshold == 0.0 */
+  g_assert (threshold != 0.0);
+
+  /* We build a 2n degree polynomial here for values between
+   * 0 and threshold or 0 and -threshold with:
+   * f(t) = t, f'(t) = 1, f(z) = 0, f'(z) = r
+   * z between 0 and t
+   * =>
+   * a = (1 - r^2) / (4 * t)
+   * b = (1 + r^2) / 2
+   * c = t * (1.0 - b - a*t)
+   * f(x) = ax^2 + bx + c */
+  r2 = filter->ratio * filter->ratio;
+  a_p = (1.0 - r2) / (4.0 * threshold);
+  b_p = (1.0 + r2) / 2.0;
+  c_p = threshold * (1.0 - b_p - a_p * threshold);
+  a_n = (1.0 - r2) / (-4.0 * threshold);
+  b_n = (1.0 + r2) / 2.0;
+  c_n = -threshold * (1.0 - b_n + a_n * threshold);
+
+  for (; num_samples; num_samples--) {
+    val = *data;
+
+    if (val < threshold && val > zero) {
+      val = a_p * val * val + b_p * val + c_p;
+    } else if ((val <= zero && val > 0.0) || (val >= -zero && val < 0.0)) {
+      val = 0.0;
+    } else if (val > -threshold && val < -zero) {
+      val = a_n * val * val + b_n * val + c_n;
+    }
+    *data++ = (gfloat) val;
+  }
+}
+
+/* GstBaseTransform vmethod implementations */
+static GstFlowReturn
+gst_audio_dynamic_transform_ip (GstBaseTransform * base, GstBuffer * buf)
+{
+  GstAudioDynamic *filter = GST_AUDIO_DYNAMIC (base);
+  guint num_samples;
+  GstClockTime timestamp, stream_time;
+  GstMapInfo map;
+
+  timestamp = GST_BUFFER_TIMESTAMP (buf);
+  stream_time =
+      gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (filter), stream_time);
+
+  if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)))
+    return GST_FLOW_OK;
+
+  gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+  num_samples = map.size / GST_AUDIO_FILTER_BPS (filter);
+
+  filter->process (filter, map.data, num_samples);
+
+  gst_buffer_unmap (buf, &map);
+
+  return GST_FLOW_OK;
+}
diff --git a/gst/audiofx/audiodynamic.h b/gst/audiofx/audiodynamic.h
new file mode 100644
index 0000000..ff1e4fb
--- /dev/null
+++ b/gst/audiofx/audiodynamic.h
@@ -0,0 +1,63 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AUDIO_DYNAMIC_H__
+#define __GST_AUDIO_DYNAMIC_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AUDIO_DYNAMIC            (gst_audio_dynamic_get_type())
+#define GST_AUDIO_DYNAMIC(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_DYNAMIC,GstAudioDynamic))
+#define GST_IS_AUDIO_DYNAMIC(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_DYNAMIC))
+#define GST_AUDIO_DYNAMIC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_DYNAMIC,GstAudioDynamicClass))
+#define GST_IS_AUDIO_DYNAMIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_DYNAMIC))
+#define GST_AUDIO_DYNAMIC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_DYNAMIC,GstAudioDynamicClass))
+typedef struct _GstAudioDynamic GstAudioDynamic;
+typedef struct _GstAudioDynamicClass GstAudioDynamicClass;
+
+typedef void (*GstAudioDynamicProcessFunc) (GstAudioDynamic *, guint8 *, guint);
+
+struct _GstAudioDynamic
+{
+  GstAudioFilter audiofilter;
+
+  /* < private > */
+  GstAudioDynamicProcessFunc process;
+  gint characteristics;
+  gint mode;
+  gfloat threshold;
+  gfloat ratio;
+};
+
+struct _GstAudioDynamicClass
+{
+  GstAudioFilterClass parent;
+};
+
+GType gst_audio_dynamic_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_AUDIO_DYNAMIC_H__ */
diff --git a/gst/audiofx/audioecho.c b/gst/audiofx/audioecho.c
new file mode 100644
index 0000000..c65bef1
--- /dev/null
+++ b/gst/audiofx/audioecho.c
@@ -0,0 +1,504 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-audioecho
+ *
+ * audioecho adds an echo or (simple) reverb effect to an audio stream. The echo
+ * delay, intensity and the percentage of feedback can be configured.
+ *
+ * For getting an echo effect you have to set the delay to a larger value,
+ * for example 200ms and more. Everything below will result in a simple
+ * reverb effect, which results in a slightly metallic sound.
+ *
+ * Use the max-delay property to set the maximum amount of delay that
+ * will be used. This can only be set before going to the PAUSED or PLAYING
+ * state and will be set to the current delay by default.
+ *
+ * audioecho can also be used to apply a configurable delay to audio channels
+ * by setting surround-delay=true. In that mode, it just delays "surround
+ * channels" by the delay amount instead of performing an echo. The
+ * channels that are configured surround channels for the delay are
+ * selected using the surround-channels mask property.
+ *
+ * <refsect2>
+ * <title>Example launch lines</title>
+ * |[
+ * gst-launch-1.0 autoaudiosrc ! audioconvert ! audioecho delay=500000000 intensity=0.6 feedback=0.4 ! audioconvert ! autoaudiosink
+ * gst-launch-1.0 filesrc location="melo1.ogg" ! decodebin ! audioconvert ! audioecho delay=50000000 intensity=0.6 feedback=0.4 ! audioconvert ! autoaudiosink
+ * gst-launch-1.0 audiotestsrc ! audioconvert ! audio/x-raw,channels=4 ! audioecho surround-delay=true delay=500000000 ! audioconvert ! autoaudiosink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audioecho.h"
+
+#define GST_CAT_DEFAULT gst_audio_echo_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+/* Everything except the first 2 channels are considered surround */
+#define DEFAULT_SURROUND_MASK ~((guint64)(0x3))
+
+enum
+{
+  PROP_0,
+  PROP_DELAY,
+  PROP_MAX_DELAY,
+  PROP_INTENSITY,
+  PROP_FEEDBACK,
+  PROP_SUR_DELAY,
+  PROP_SUR_MASK
+};
+
+#define ALLOWED_CAPS \
+    "audio/x-raw,"                                                 \
+    " format=(string) {"GST_AUDIO_NE(F32)","GST_AUDIO_NE(F64)"}, " \
+    " rate=(int)[1,MAX],"                                          \
+    " channels=(int)[1,MAX],"                                      \
+    " layout=(string) interleaved"
+
+#define gst_audio_echo_parent_class parent_class
+G_DEFINE_TYPE (GstAudioEcho, gst_audio_echo, GST_TYPE_AUDIO_FILTER);
+
+static void gst_audio_echo_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_audio_echo_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_audio_echo_finalize (GObject * object);
+
+static gboolean gst_audio_echo_setup (GstAudioFilter * self,
+    const GstAudioInfo * info);
+static gboolean gst_audio_echo_stop (GstBaseTransform * base);
+static GstFlowReturn gst_audio_echo_transform_ip (GstBaseTransform * base,
+    GstBuffer * buf);
+
+static void gst_audio_echo_transform_float (GstAudioEcho * self,
+    gfloat * data, guint num_samples);
+static void gst_audio_echo_transform_double (GstAudioEcho * self,
+    gdouble * data, guint num_samples);
+
+/* GObject vmethod implementations */
+
+static void
+gst_audio_echo_class_init (GstAudioEchoClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBaseTransformClass *basetransform_class = (GstBaseTransformClass *) klass;
+  GstAudioFilterClass *audioself_class = (GstAudioFilterClass *) klass;
+  GstCaps *caps;
+
+  GST_DEBUG_CATEGORY_INIT (gst_audio_echo_debug, "audioecho", 0,
+      "audioecho element");
+
+  gobject_class->set_property = gst_audio_echo_set_property;
+  gobject_class->get_property = gst_audio_echo_get_property;
+  gobject_class->finalize = gst_audio_echo_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_DELAY,
+      g_param_spec_uint64 ("delay", "Delay",
+          "Delay of the echo in nanoseconds", 1, G_MAXUINT64,
+          1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
+          | GST_PARAM_CONTROLLABLE));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_DELAY,
+      g_param_spec_uint64 ("max-delay", "Maximum Delay",
+          "Maximum delay of the echo in nanoseconds"
+          " (can't be changed in PLAYING or PAUSED state)",
+          1, G_MAXUINT64, 1,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+          GST_PARAM_MUTABLE_READY));
+
+  g_object_class_install_property (gobject_class, PROP_INTENSITY,
+      g_param_spec_float ("intensity", "Intensity",
+          "Intensity of the echo", 0.0, 1.0,
+          0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
+          | GST_PARAM_CONTROLLABLE));
+
+  g_object_class_install_property (gobject_class, PROP_FEEDBACK,
+      g_param_spec_float ("feedback", "Feedback",
+          "Amount of feedback", 0.0, 1.0,
+          0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
+          | GST_PARAM_CONTROLLABLE));
+
+  g_object_class_install_property (gobject_class, PROP_SUR_DELAY,
+      g_param_spec_boolean ("surround-delay", "Enable Surround Delay",
+          "Delay Surround Channels when TRUE instead of applying an echo effect",
+          FALSE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  g_object_class_install_property (gobject_class, PROP_SUR_MASK,
+      g_param_spec_uint64 ("surround-mask", "Surround Mask",
+          "A bitmask of channels that are considered surround and delayed when surround-delay = TRUE",
+          1, G_MAXUINT64, DEFAULT_SURROUND_MASK,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+          GST_PARAM_MUTABLE_READY));
+
+  gst_element_class_set_static_metadata (gstelement_class, "Audio echo",
+      "Filter/Effect/Audio",
+      "Adds an echo or reverb effect to an audio stream",
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  caps = gst_caps_from_string (ALLOWED_CAPS);
+  gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass),
+      caps);
+  gst_caps_unref (caps);
+
+  audioself_class->setup = GST_DEBUG_FUNCPTR (gst_audio_echo_setup);
+  basetransform_class->transform_ip =
+      GST_DEBUG_FUNCPTR (gst_audio_echo_transform_ip);
+  basetransform_class->stop = GST_DEBUG_FUNCPTR (gst_audio_echo_stop);
+}
+
+static void
+gst_audio_echo_init (GstAudioEcho * self)
+{
+  self->delay = 1;
+  self->max_delay = 1;
+  self->intensity = 0.0;
+  self->feedback = 0.0;
+  self->surdelay = FALSE;
+  self->surround_mask = DEFAULT_SURROUND_MASK;
+
+  g_mutex_init (&self->lock);
+
+  gst_base_transform_set_in_place (GST_BASE_TRANSFORM (self), TRUE);
+}
+
+static void
+gst_audio_echo_finalize (GObject * object)
+{
+  GstAudioEcho *self = GST_AUDIO_ECHO (object);
+
+  g_free (self->buffer);
+  self->buffer = NULL;
+
+  g_mutex_clear (&self->lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_audio_echo_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAudioEcho *self = GST_AUDIO_ECHO (object);
+
+  switch (prop_id) {
+    case PROP_DELAY:{
+      guint64 max_delay, delay;
+      guint rate;
+
+      g_mutex_lock (&self->lock);
+      delay = g_value_get_uint64 (value);
+      max_delay = self->max_delay;
+
+      if (delay > max_delay && GST_STATE (self) > GST_STATE_READY) {
+        GST_WARNING_OBJECT (self, "New delay (%" GST_TIME_FORMAT ") "
+            "is larger than maximum delay (%" GST_TIME_FORMAT ")",
+            GST_TIME_ARGS (delay), GST_TIME_ARGS (max_delay));
+        self->delay = max_delay;
+      } else {
+        self->delay = delay;
+        self->max_delay = MAX (delay, max_delay);
+        if (delay > max_delay) {
+          g_free (self->buffer);
+          self->buffer = NULL;
+        }
+      }
+      rate = GST_AUDIO_FILTER_RATE (self);
+      if (rate > 0)
+        self->delay_frames =
+            MAX (gst_util_uint64_scale (self->delay, rate, GST_SECOND), 1);
+
+      g_mutex_unlock (&self->lock);
+      break;
+    }
+    case PROP_MAX_DELAY:{
+      guint64 max_delay;
+
+      g_mutex_lock (&self->lock);
+      max_delay = g_value_get_uint64 (value);
+
+      if (GST_STATE (self) > GST_STATE_READY) {
+        GST_ERROR_OBJECT (self, "Can't change maximum delay in"
+            " PLAYING or PAUSED state");
+      } else {
+        self->max_delay = max_delay;
+        g_free (self->buffer);
+        self->buffer = NULL;
+      }
+      g_mutex_unlock (&self->lock);
+      break;
+    }
+    case PROP_INTENSITY:{
+      g_mutex_lock (&self->lock);
+      self->intensity = g_value_get_float (value);
+      g_mutex_unlock (&self->lock);
+      break;
+    }
+    case PROP_FEEDBACK:{
+      g_mutex_lock (&self->lock);
+      self->feedback = g_value_get_float (value);
+      g_mutex_unlock (&self->lock);
+      break;
+    }
+    case PROP_SUR_DELAY:{
+      g_mutex_lock (&self->lock);
+      self->surdelay = g_value_get_boolean (value);
+      g_mutex_unlock (&self->lock);
+      break;
+    }
+    case PROP_SUR_MASK:{
+      g_mutex_lock (&self->lock);
+      self->surround_mask = g_value_get_uint64 (value);
+      g_mutex_unlock (&self->lock);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_audio_echo_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAudioEcho *self = GST_AUDIO_ECHO (object);
+
+  switch (prop_id) {
+    case PROP_DELAY:
+      g_mutex_lock (&self->lock);
+      g_value_set_uint64 (value, self->delay);
+      g_mutex_unlock (&self->lock);
+      break;
+    case PROP_MAX_DELAY:
+      g_mutex_lock (&self->lock);
+      g_value_set_uint64 (value, self->max_delay);
+      g_mutex_unlock (&self->lock);
+      break;
+    case PROP_INTENSITY:
+      g_mutex_lock (&self->lock);
+      g_value_set_float (value, self->intensity);
+      g_mutex_unlock (&self->lock);
+      break;
+    case PROP_FEEDBACK:
+      g_mutex_lock (&self->lock);
+      g_value_set_float (value, self->feedback);
+      g_mutex_unlock (&self->lock);
+      break;
+    case PROP_SUR_DELAY:
+      g_mutex_lock (&self->lock);
+      g_value_set_boolean (value, self->surdelay);
+      g_mutex_unlock (&self->lock);
+      break;
+    case PROP_SUR_MASK:{
+      g_mutex_lock (&self->lock);
+      g_value_set_uint64 (value, self->surround_mask);
+      g_mutex_unlock (&self->lock);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* GstAudioFilter vmethod implementations */
+
+static gboolean
+gst_audio_echo_setup (GstAudioFilter * base, const GstAudioInfo * info)
+{
+  GstAudioEcho *self = GST_AUDIO_ECHO (base);
+  gboolean ret = TRUE;
+
+  switch (GST_AUDIO_INFO_FORMAT (info)) {
+    case GST_AUDIO_FORMAT_F32:
+      self->process = (GstAudioEchoProcessFunc)
+          gst_audio_echo_transform_float;
+      break;
+    case GST_AUDIO_FORMAT_F64:
+      self->process = (GstAudioEchoProcessFunc)
+          gst_audio_echo_transform_double;
+      break;
+    default:
+      ret = FALSE;
+      break;
+  }
+
+  g_free (self->buffer);
+  self->buffer = NULL;
+  self->buffer_pos = 0;
+  self->buffer_size = 0;
+  self->buffer_size_frames = 0;
+
+  return ret;
+}
+
+static gboolean
+gst_audio_echo_stop (GstBaseTransform * base)
+{
+  GstAudioEcho *self = GST_AUDIO_ECHO (base);
+
+  g_free (self->buffer);
+  self->buffer = NULL;
+  self->buffer_pos = 0;
+  self->buffer_size = 0;
+  self->buffer_size_frames = 0;
+
+  return TRUE;
+}
+
+#define TRANSFORM_FUNC(name, type) \
+static void \
+gst_audio_echo_transform_##name (GstAudioEcho * self, \
+    type * data, guint num_samples) \
+{ \
+  type *buffer = (type *) self->buffer; \
+  guint channels = GST_AUDIO_FILTER_CHANNELS (self); \
+  guint i, j; \
+  guint echo_offset = self->buffer_size_frames - self->delay_frames; \
+  gdouble intensity = self->intensity; \
+  gdouble feedback = self->feedback; \
+  guint buffer_pos = self->buffer_pos; \
+  guint buffer_size_frames = self->buffer_size_frames; \
+  \
+  if (self->surdelay == FALSE) { \
+    guint read_pos = ((echo_offset + buffer_pos) % buffer_size_frames) * channels; \
+    guint write_pos = (buffer_pos % buffer_size_frames) * channels; \
+    guint buffer_size = buffer_size_frames * channels; \
+    for (i = 0; i < num_samples; i++) { \
+      gdouble in = *data; \
+      gdouble echo = buffer[read_pos]; \
+      type out = in + intensity * echo; \
+      \
+      *data = out; \
+      \
+      buffer[write_pos] = in + feedback * echo; \
+      read_pos = (read_pos + 1) % buffer_size; \
+      write_pos = (write_pos + 1) % buffer_size; \
+      data++; \
+    } \
+    buffer_pos = write_pos / channels; \
+  } else { \
+    guint64 surround_mask = self->surround_mask; \
+    guint read_pos = ((echo_offset + buffer_pos) % buffer_size_frames) * channels; \
+    guint write_pos = (buffer_pos % buffer_size_frames) * channels; \
+    guint buffer_size = buffer_size_frames * channels; \
+    \
+    num_samples /= channels; \
+    \
+    for (i = 0; i < num_samples; i++) { \
+      guint64 channel_mask = 1; \
+      \
+      for (j = 0; j < channels; j++) { \
+        if (channel_mask & surround_mask) { \
+          gdouble in = data[j]; \
+          gdouble echo = buffer[read_pos + j]; \
+          type out = echo; \
+          \
+          data[j] = out; \
+          \
+          buffer[write_pos + j] = in; \
+        } else { \
+          gdouble in = data[j]; \
+          gdouble echo = buffer[read_pos + j]; \
+          type out = in + intensity * echo; \
+          \
+          data[j] = out; \
+          \
+          buffer[write_pos + j] = in + feedback * echo; \
+        } \
+        channel_mask <<= 1; \
+      } \
+      read_pos = (read_pos + channels) % buffer_size; \
+      write_pos = (write_pos + channels) % buffer_size; \
+      data += channels; \
+    } \
+    buffer_pos = write_pos / channels; \
+  } \
+  self->buffer_pos = buffer_pos; \
+}
+
+TRANSFORM_FUNC (float, gfloat);
+TRANSFORM_FUNC (double, gdouble);
+
+/* GstBaseTransform vmethod implementations */
+static GstFlowReturn
+gst_audio_echo_transform_ip (GstBaseTransform * base, GstBuffer * buf)
+{
+  GstAudioEcho *self = GST_AUDIO_ECHO (base);
+  guint num_samples;
+  GstClockTime timestamp, stream_time;
+  GstMapInfo map;
+
+  g_mutex_lock (&self->lock);
+  timestamp = GST_BUFFER_TIMESTAMP (buf);
+  stream_time =
+      gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (self, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (self), stream_time);
+
+  if (self->buffer == NULL) {
+    guint bpf, rate;
+
+    bpf = GST_AUDIO_FILTER_BPF (self);
+    rate = GST_AUDIO_FILTER_RATE (self);
+
+    self->delay_frames =
+        MAX (gst_util_uint64_scale (self->delay, rate, GST_SECOND), 1);
+    self->buffer_size_frames =
+        MAX (gst_util_uint64_scale (self->max_delay, rate, GST_SECOND), 1);
+
+    self->buffer_size = self->buffer_size_frames * bpf;
+    self->buffer = g_try_malloc0 (self->buffer_size);
+    self->buffer_pos = 0;
+
+    if (self->buffer == NULL) {
+      g_mutex_unlock (&self->lock);
+      GST_ERROR_OBJECT (self, "Failed to allocate %u bytes", self->buffer_size);
+      return GST_FLOW_ERROR;
+    }
+  }
+
+  gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+  num_samples = map.size / GST_AUDIO_FILTER_BPS (self);
+
+  self->process (self, map.data, num_samples);
+
+  gst_buffer_unmap (buf, &map);
+  g_mutex_unlock (&self->lock);
+
+  return GST_FLOW_OK;
+}
diff --git a/gst/audiofx/audioecho.h b/gst/audiofx/audioecho.h
new file mode 100644
index 0000000..51689ed
--- /dev/null
+++ b/gst/audiofx/audioecho.h
@@ -0,0 +1,73 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AUDIO_ECHO_H__
+#define __GST_AUDIO_ECHO_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AUDIO_ECHO            (gst_audio_echo_get_type())
+#define GST_AUDIO_ECHO(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_ECHO,GstAudioEcho))
+#define GST_IS_AUDIO_ECHO(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_ECHO))
+#define GST_AUDIO_ECHO_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_ECHO,GstAudioEchoClass))
+#define GST_IS_AUDIO_ECHO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_ECHO))
+#define GST_AUDIO_ECHO_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_ECHO,GstAudioEchoClass))
+typedef struct _GstAudioEcho GstAudioEcho;
+typedef struct _GstAudioEchoClass GstAudioEchoClass;
+
+typedef void (*GstAudioEchoProcessFunc) (GstAudioEcho *, guint8 *, guint);
+
+struct _GstAudioEcho
+{
+  GstAudioFilter audiofilter;
+
+  guint64 delay;
+  guint64 max_delay;
+  gfloat intensity;
+  gfloat feedback;
+  gboolean surdelay;
+  guint64 surround_mask;
+
+  /* < private > */
+  GstAudioEchoProcessFunc process;
+  guint delay_frames;
+  guint8 *buffer;
+  guint buffer_pos;
+  guint buffer_size;
+  guint buffer_size_frames;
+
+  GMutex lock;
+};
+
+struct _GstAudioEchoClass
+{
+  GstAudioFilterClass parent;
+};
+
+GType gst_audio_echo_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_AUDIO_ECHO_H__ */
diff --git a/gst/audiofx/audiofirfilter.c b/gst/audiofx/audiofirfilter.c
new file mode 100644
index 0000000..0ab32f3
--- /dev/null
+++ b/gst/audiofx/audiofirfilter.c
@@ -0,0 +1,262 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * 
+ */
+
+/**
+ * SECTION:element-audiofirfilter
+ *
+ * audiofirfilter implements a generic audio <ulink url="http://en.wikipedia.org/wiki/Finite_impulse_response">FIR filter</ulink>. Before usage the
+ * "kernel" property has to be set to the filter kernel that should be
+ * used and the "latency" property has to be set to the latency (in samples)
+ * that is introduced by the filter kernel. Setting a latency of n samples
+ * will lead to the first n samples being dropped from the output and
+ * n samples added to the end.
+ *
+ * The filter kernel describes the impulse response of the filter. To
+ * calculate the frequency response of the filter you have to calculate
+ * the Fourier Transform of the impulse response.
+ *
+ * To change the filter kernel whenever the sampling rate changes the
+ * "rate-changed" signal can be used. This should be done for most
+ * FIR filters as they're depending on the sampling rate.
+ *
+ * <refsect2>
+ * <title>Example application</title>
+ * <informalexample><programlisting language="C">
+ * <xi:include xmlns:xi="http://www.w3.org/2003/XInclude" parse="text" href="../../../../tests/examples/audiofx/firfilter-example.c" />
+ * </programlisting></informalexample>
+ * </refsect2>
+ */
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <gst/gst.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audiofirfilter.h"
+
+#include "gst/glib-compat-private.h"
+
+#define GST_CAT_DEFAULT gst_audio_fir_filter_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+enum
+{
+  SIGNAL_RATE_CHANGED,
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_KERNEL,
+  PROP_LATENCY
+};
+
+static guint gst_audio_fir_filter_signals[LAST_SIGNAL] = { 0, };
+
+#define gst_audio_fir_filter_parent_class parent_class
+G_DEFINE_TYPE (GstAudioFIRFilter, gst_audio_fir_filter,
+    GST_TYPE_AUDIO_FX_BASE_FIR_FILTER);
+
+static void gst_audio_fir_filter_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_audio_fir_filter_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_audio_fir_filter_finalize (GObject * object);
+
+static gboolean gst_audio_fir_filter_setup (GstAudioFilter * base,
+    const GstAudioInfo * info);
+
+
+static void
+gst_audio_fir_filter_class_init (GstAudioFIRFilterClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (gst_audio_fir_filter_debug, "audiofirfilter", 0,
+      "Generic audio FIR filter plugin");
+
+  gobject_class->set_property = gst_audio_fir_filter_set_property;
+  gobject_class->get_property = gst_audio_fir_filter_get_property;
+  gobject_class->finalize = gst_audio_fir_filter_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_KERNEL,
+      g_param_spec_value_array ("kernel", "Filter Kernel",
+          "Filter kernel for the FIR filter",
+          g_param_spec_double ("Element", "Filter Kernel Element",
+              "Element of the filter kernel", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_LATENCY,
+      g_param_spec_uint64 ("latency", "Latecy",
+          "Filter latency in samples",
+          0, G_MAXUINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_fir_filter_setup);
+
+  /**
+   * GstAudioFIRFilter::rate-changed:
+   * @filter: the filter on which the signal is emitted
+   * @rate: the new sampling rate
+   *
+   * Will be emitted when the sampling rate changes. The callbacks
+   * will be called from the streaming thread and processing will
+   * stop until the event is handled.
+   */
+  gst_audio_fir_filter_signals[SIGNAL_RATE_CHANGED] =
+      g_signal_new ("rate-changed", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstAudioFIRFilterClass, rate_changed),
+      NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Audio FIR filter", "Filter/Effect/Audio",
+      "Generic audio FIR filter with custom filter kernel",
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+}
+
+static void
+gst_audio_fir_filter_update_kernel (GstAudioFIRFilter * self, GValueArray * va)
+{
+  gdouble *kernel;
+  guint i;
+
+  if (va) {
+    if (self->kernel)
+      g_value_array_free (self->kernel);
+
+    self->kernel = va;
+  }
+
+  kernel = g_new (gdouble, self->kernel->n_values);
+
+  for (i = 0; i < self->kernel->n_values; i++) {
+    GValue *v = g_value_array_get_nth (self->kernel, i);
+    kernel[i] = g_value_get_double (v);
+  }
+
+  gst_audio_fx_base_fir_filter_set_kernel (GST_AUDIO_FX_BASE_FIR_FILTER (self),
+      kernel, self->kernel->n_values, self->latency, NULL);
+}
+
+static void
+gst_audio_fir_filter_init (GstAudioFIRFilter * self)
+{
+  GValue v = { 0, };
+  GValueArray *va;
+
+  self->latency = 0;
+  va = g_value_array_new (1);
+
+  g_value_init (&v, G_TYPE_DOUBLE);
+  g_value_set_double (&v, 1.0);
+  g_value_array_append (va, &v);
+  g_value_unset (&v);
+  gst_audio_fir_filter_update_kernel (self, va);
+
+  g_mutex_init (&self->lock);
+}
+
+/* GstAudioFilter vmethod implementations */
+
+/* get notified of caps and plug in the correct process function */
+static gboolean
+gst_audio_fir_filter_setup (GstAudioFilter * base, const GstAudioInfo * info)
+{
+  GstAudioFIRFilter *self = GST_AUDIO_FIR_FILTER (base);
+  gint new_rate = GST_AUDIO_INFO_RATE (info);
+
+  if (GST_AUDIO_FILTER_RATE (self) != new_rate) {
+    g_signal_emit (G_OBJECT (self),
+        gst_audio_fir_filter_signals[SIGNAL_RATE_CHANGED], 0, new_rate);
+  }
+
+  return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, info);
+}
+
+static void
+gst_audio_fir_filter_finalize (GObject * object)
+{
+  GstAudioFIRFilter *self = GST_AUDIO_FIR_FILTER (object);
+
+  g_mutex_clear (&self->lock);
+
+  if (self->kernel)
+    g_value_array_free (self->kernel);
+  self->kernel = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_audio_fir_filter_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAudioFIRFilter *self = GST_AUDIO_FIR_FILTER (object);
+
+  g_return_if_fail (GST_IS_AUDIO_FIR_FILTER (self));
+
+  switch (prop_id) {
+    case PROP_KERNEL:
+      g_mutex_lock (&self->lock);
+      /* update kernel already pushes residues */
+      gst_audio_fir_filter_update_kernel (self, g_value_dup_boxed (value));
+      g_mutex_unlock (&self->lock);
+      break;
+    case PROP_LATENCY:
+      g_mutex_lock (&self->lock);
+      self->latency = g_value_get_uint64 (value);
+      gst_audio_fir_filter_update_kernel (self, NULL);
+      g_mutex_unlock (&self->lock);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_audio_fir_filter_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAudioFIRFilter *self = GST_AUDIO_FIR_FILTER (object);
+
+  switch (prop_id) {
+    case PROP_KERNEL:
+      g_value_set_boxed (value, self->kernel);
+      break;
+    case PROP_LATENCY:
+      g_value_set_uint64 (value, self->latency);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/gst/audiofx/audiofirfilter.h b/gst/audiofx/audiofirfilter.h
new file mode 100644
index 0000000..f3b3475
--- /dev/null
+++ b/gst/audiofx/audiofirfilter.h
@@ -0,0 +1,71 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * 
+ */
+
+#ifndef __GST_AUDIO_FIR_FILTER_H__
+#define __GST_AUDIO_FIR_FILTER_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audiofxbasefirfilter.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AUDIO_FIR_FILTER \
+  (gst_audio_fir_filter_get_type())
+#define GST_AUDIO_FIR_FILTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_FIR_FILTER,GstAudioFIRFilter))
+#define GST_AUDIO_FIR_FILTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_FIR_FILTER,GstAudioFIRFilterClass))
+#define GST_IS_AUDIO_FIR_FILTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_FIR_FILTER))
+#define GST_IS_AUDIO_FIR_FILTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_FIR_FILTER))
+
+typedef struct _GstAudioFIRFilter GstAudioFIRFilter;
+typedef struct _GstAudioFIRFilterClass GstAudioFIRFilterClass;
+
+/**
+ * GstAudioFIRFilter:
+ *
+ * Opaque data structure.
+ */
+struct _GstAudioFIRFilter {
+  GstAudioFXBaseFIRFilter parent;
+
+  GValueArray *kernel;
+  guint64 latency;
+
+  /* < private > */
+  GMutex lock;
+};
+
+struct _GstAudioFIRFilterClass {
+  GstAudioFXBaseFIRFilterClass parent;
+
+  void (*rate_changed) (GstElement * element, gint rate);
+};
+
+GType gst_audio_fir_filter_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_AUDIO_FIR_FILTER_H__ */
diff --git a/gst/audiofx/audiofx.c b/gst/audiofx/audiofx.c
new file mode 100644
index 0000000..dbddabe
--- /dev/null
+++ b/gst/audiofx/audiofx.c
@@ -0,0 +1,81 @@
+/*
+ * GStreamer
+ * Copyright (C) 2006 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "audiopanorama.h"
+#include "audioinvert.h"
+#include "audiokaraoke.h"
+#include "audioamplify.h"
+#include "audiodynamic.h"
+#include "audiocheblimit.h"
+#include "audiochebband.h"
+#include "audioiirfilter.h"
+#include "audiowsincband.h"
+#include "audiowsinclimit.h"
+#include "audiofirfilter.h"
+#include "audioecho.h"
+#include "gstscaletempo.h"
+
+/* entry point to initialize the plug-in
+ * initialize the plug-in itself
+ * register the element factories and pad templates
+ * register the features
+ */
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return (gst_element_register (plugin, "audiopanorama", GST_RANK_NONE,
+          GST_TYPE_AUDIO_PANORAMA) &&
+      gst_element_register (plugin, "audioinvert", GST_RANK_NONE,
+          GST_TYPE_AUDIO_INVERT) &&
+      gst_element_register (plugin, "audiokaraoke", GST_RANK_NONE,
+          GST_TYPE_AUDIO_KARAOKE) &&
+      gst_element_register (plugin, "audioamplify", GST_RANK_NONE,
+          GST_TYPE_AUDIO_AMPLIFY) &&
+      gst_element_register (plugin, "audiodynamic", GST_RANK_NONE,
+          GST_TYPE_AUDIO_DYNAMIC) &&
+      gst_element_register (plugin, "audiocheblimit", GST_RANK_NONE,
+          GST_TYPE_AUDIO_CHEB_LIMIT) &&
+      gst_element_register (plugin, "audiochebband", GST_RANK_NONE,
+          GST_TYPE_AUDIO_CHEB_BAND) &&
+      gst_element_register (plugin, "audioiirfilter", GST_RANK_NONE,
+          GST_TYPE_AUDIO_IIR_FILTER) &&
+      gst_element_register (plugin, "audiowsinclimit", GST_RANK_NONE,
+          GST_TYPE_AUDIO_WSINC_LIMIT) &&
+      gst_element_register (plugin, "audiowsincband", GST_RANK_NONE,
+          GST_TYPE_AUDIO_WSINC_BAND) &&
+      gst_element_register (plugin, "audiofirfilter", GST_RANK_NONE,
+          GST_TYPE_AUDIO_FIR_FILTER) &&
+      gst_element_register (plugin, "audioecho", GST_RANK_NONE,
+          GST_TYPE_AUDIO_ECHO) &&
+      gst_element_register (plugin, "scaletempo", GST_RANK_NONE,
+          GST_TYPE_SCALETEMPO));
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    audiofx,
+    "Audio effects plugin",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/audiofx/audiofxbasefirfilter.c b/gst/audiofx/audiofxbasefirfilter.c
new file mode 100644
index 0000000..ccafb0a
--- /dev/null
+++ b/gst/audiofx/audiofxbasefirfilter.c
@@ -0,0 +1,1086 @@
+/* -*- c-basic-offset: 2 -*-
+ * 
+ * GStreamer
+ * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2006 Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>
+ *               2007-2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <gst/gst.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audiofxbasefirfilter.h"
+
+#define GST_CAT_DEFAULT gst_audio_fx_base_fir_filter_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+#define ALLOWED_CAPS \
+    "audio/x-raw, "                                               \
+    " format=(string){"GST_AUDIO_NE(F32)","GST_AUDIO_NE(F64)"}, " \
+    " rate = (int) [ 1, MAX ], "                                  \
+    " channels = (int) [ 1, MAX ], "                              \
+    " layout=(string) interleaved"
+
+/* Switch from time-domain to FFT convolution for kernels >= this */
+#define FFT_THRESHOLD 32
+
+enum
+{
+  PROP_0 = 0,
+  PROP_LOW_LATENCY,
+  PROP_DRAIN_ON_CHANGES
+};
+
+#define DEFAULT_LOW_LATENCY FALSE
+#define DEFAULT_DRAIN_ON_CHANGES TRUE
+
+#define gst_audio_fx_base_fir_filter_parent_class parent_class
+G_DEFINE_TYPE (GstAudioFXBaseFIRFilter, gst_audio_fx_base_fir_filter,
+    GST_TYPE_AUDIO_FILTER);
+
+static GstFlowReturn gst_audio_fx_base_fir_filter_transform (GstBaseTransform *
+    base, GstBuffer * inbuf, GstBuffer * outbuf);
+static gboolean gst_audio_fx_base_fir_filter_start (GstBaseTransform * base);
+static gboolean gst_audio_fx_base_fir_filter_stop (GstBaseTransform * base);
+static gboolean gst_audio_fx_base_fir_filter_sink_event (GstBaseTransform *
+    base, GstEvent * event);
+static gboolean gst_audio_fx_base_fir_filter_transform_size (GstBaseTransform *
+    base, GstPadDirection direction, GstCaps * caps, gsize size,
+    GstCaps * othercaps, gsize * othersize);
+static gboolean gst_audio_fx_base_fir_filter_setup (GstAudioFilter * base,
+    const GstAudioInfo * info);
+
+static gboolean gst_audio_fx_base_fir_filter_query (GstBaseTransform * trans,
+    GstPadDirection direction, GstQuery * quer);
+
+/*
+ * The code below calculates the linear convolution:
+ *
+ * y[t] = \sum_{u=0}^{M-1} x[t - u] * h[u]
+ *
+ * where y is the output, x is the input, M is the length
+ * of the filter kernel and h is the filter kernel. For x
+ * holds: x[t] == 0 \forall t < 0.
+ *
+ * The runtime complexity of this is O (M) per sample.
+ *
+ */
+#define DEFINE_PROCESS_FUNC(width,ctype) \
+static guint \
+process_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, g##ctype * dst, guint input_samples) \
+{ \
+  gint channels = GST_AUDIO_FILTER_CHANNELS (self); \
+  TIME_DOMAIN_CONVOLUTION_BODY (channels); \
+}
+
+#define DEFINE_PROCESS_FUNC_FIXED_CHANNELS(width,channels,ctype) \
+static guint \
+process_##channels##_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, g##ctype * dst, guint input_samples) \
+{ \
+  TIME_DOMAIN_CONVOLUTION_BODY (channels); \
+}
+
+#define TIME_DOMAIN_CONVOLUTION_BODY(channels) G_STMT_START { \
+  gint kernel_length = self->kernel_length; \
+  gint i, j, k, l; \
+  gint res_start; \
+  gint from_input; \
+  gint off; \
+  gdouble *buffer = self->buffer; \
+  gdouble *kernel = self->kernel; \
+  \
+  if (!buffer) { \
+    self->buffer_length = kernel_length * channels; \
+    self->buffer = buffer = g_new0 (gdouble, self->buffer_length); \
+  } \
+  \
+  input_samples *= channels; \
+  /* convolution */ \
+  for (i = 0; i < input_samples; i++) { \
+    dst[i] = 0.0; \
+    k = i % channels; \
+    l = i / channels; \
+    from_input = MIN (l, kernel_length-1); \
+    off = l * channels + k; \
+    for (j = 0; j <= from_input; j++) { \
+      dst[i] += src[off] * kernel[j]; \
+      off -= channels; \
+    } \
+    /* j == from_input && off == (l - j) * channels + k */ \
+    off += kernel_length * channels; \
+    for (; j < kernel_length; j++) { \
+      dst[i] += buffer[off] * kernel[j]; \
+      off -= channels; \
+    } \
+  } \
+  \
+  /* copy the tail of the current input buffer to the residue, while \
+   * keeping parts of the residue if the input buffer is smaller than \
+   * the kernel length */ \
+  /* from now on take kernel length as length over all channels */ \
+  kernel_length *= channels; \
+  if (input_samples < kernel_length) \
+    res_start = kernel_length - input_samples; \
+  else \
+    res_start = 0; \
+  \
+  for (i = 0; i < res_start; i++) \
+    buffer[i] = buffer[i + input_samples]; \
+  /* i == res_start */ \
+  for (; i < kernel_length; i++) \
+    buffer[i] = src[input_samples - kernel_length + i]; \
+  \
+  self->buffer_fill += kernel_length - res_start; \
+  if (self->buffer_fill > kernel_length) \
+    self->buffer_fill = kernel_length; \
+  \
+  return input_samples / channels; \
+} G_STMT_END
+
+DEFINE_PROCESS_FUNC (32, float);
+DEFINE_PROCESS_FUNC (64, double);
+
+DEFINE_PROCESS_FUNC_FIXED_CHANNELS (32, 1, float);
+DEFINE_PROCESS_FUNC_FIXED_CHANNELS (64, 1, double);
+
+DEFINE_PROCESS_FUNC_FIXED_CHANNELS (32, 2, float);
+DEFINE_PROCESS_FUNC_FIXED_CHANNELS (64, 2, double);
+
+#undef TIME_DOMAIN_CONVOLUTION_BODY
+#undef DEFINE_PROCESS_FUNC
+#undef DEFINE_PROCESS_FUNC_FIXED_CHANNELS
+
+/* This implements FFT convolution and uses the overlap-save algorithm.
+ * See http://cnx.org/content/m12022/latest/ or your favorite
+ * digital signal processing book for details.
+ *
+ * In every pass the following is calculated:
+ *
+ * y = IFFT (FFT(x) * FFT(h))
+ *
+ * where y is the output in the time domain, x the
+ * input and h the filter kernel. * is the multiplication
+ * of complex numbers.
+ *
+ * Due to the circular convolution theorem this
+ * gives in the time domain:
+ *
+ * y[t] = \sum_{u=0}^{M-1} x[t - u] * h[u]
+ *
+ * where y is the output, M is the kernel length,
+ * x the periodically extended[0] input and h the
+ * filter kernel.
+ *
+ * ([0] Periodically extended means:    )
+ * (    x[t] = x[t+kN] \forall k \in Z  )
+ * (    where N is the length of x      )
+ *
+ * This means:
+ * - Obviously x and h need to be of the same size for the FFT
+ * - The first M-1 output values are useless because they're
+ *   built from 1 up to M-1 values from the end of the input
+ *   (circular convolusion!).
+ * - The last M-1 input values are only used for 1 up to M-1
+ *   output values, i.e. they need to be used again in the
+ *   next pass for the first M-1 input values.
+ *
+ * => The first pass needs M-1 zeroes at the beginning of the
+ * input and the last M-1 input values of every pass need to
+ * be used as the first M-1 input values of the next pass.
+ *
+ * => x must be larger than h to give a useful number of output
+ * samples and h needs to be padded by zeroes at the end to give
+ * it virtually the same size as x (by M we denote the number of
+ * non-padding samples of h). If len(x)==len(h)==M only 1 output
+ * sample would be calculated per pass, len(x)==2*len(h) would
+ * give M+1 output samples, etc. Usually a factor between 4 and 8
+ * gives a low number of operations per output samples (see website
+ * given above).
+ *
+ * Overall this gives a runtime complexity per sample of
+ *
+ *   (  N log N  )
+ * O ( --------- ) compared to O (M) for the direct calculation.
+ *   ( N - M + 1 )
+ */
+#define DEFINE_FFT_PROCESS_FUNC(width,ctype) \
+static guint \
+process_fft_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, \
+    g##ctype * dst, guint input_samples) \
+{ \
+  gint channels = GST_AUDIO_FILTER_CHANNELS (self); \
+  FFT_CONVOLUTION_BODY (channels); \
+}
+
+#define DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS(width,channels,ctype) \
+static guint \
+process_fft_##channels##_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, \
+    g##ctype * dst, guint input_samples) \
+{ \
+  FFT_CONVOLUTION_BODY (channels); \
+}
+
+#define FFT_CONVOLUTION_BODY(channels) G_STMT_START { \
+  gint i, j; \
+  guint pass; \
+  guint kernel_length = self->kernel_length; \
+  guint block_length = self->block_length; \
+  guint buffer_length = self->buffer_length; \
+  guint real_buffer_length = buffer_length + kernel_length - 1; \
+  guint buffer_fill = self->buffer_fill; \
+  GstFFTF64 *fft = self->fft; \
+  GstFFTF64 *ifft = self->ifft; \
+  GstFFTF64Complex *frequency_response = self->frequency_response; \
+  GstFFTF64Complex *fft_buffer = self->fft_buffer; \
+  guint frequency_response_length = self->frequency_response_length; \
+  gdouble *buffer = self->buffer; \
+  guint generated = 0; \
+  gdouble re, im; \
+  \
+  if (!fft_buffer) \
+    self->fft_buffer = fft_buffer = \
+        g_new (GstFFTF64Complex, frequency_response_length); \
+  \
+  /* Buffer contains the time domain samples of input data for one chunk \
+   * plus some more space for the inverse FFT below. \
+   * \
+   * The samples are put at offset kernel_length, the inverse FFT \
+   * overwrites everthing from offset 0 to length-kernel_length+1, keeping \
+   * the last kernel_length-1 samples for copying to the next processing \
+   * step. \
+   */ \
+  if (!buffer) { \
+    self->buffer_length = buffer_length = block_length; \
+    real_buffer_length = buffer_length + kernel_length - 1; \
+    \
+    self->buffer = buffer = g_new0 (gdouble, real_buffer_length * channels); \
+    \
+    /* Beginning has kernel_length-1 zeroes at the beginning */ \
+    self->buffer_fill = buffer_fill = kernel_length - 1; \
+  } \
+  \
+  g_assert (self->buffer_length == block_length); \
+  \
+  while (input_samples) { \
+    pass = MIN (buffer_length - buffer_fill, input_samples); \
+    \
+    /* Deinterleave channels */ \
+    for (i = 0; i < pass; i++) { \
+      for (j = 0; j < channels; j++) { \
+        buffer[real_buffer_length * j + buffer_fill + kernel_length - 1 + i] = \
+            src[i * channels + j]; \
+      } \
+    } \
+    buffer_fill += pass; \
+    src += channels * pass; \
+    input_samples -= pass; \
+    \
+    /* If we don't have a complete buffer go out */ \
+    if (buffer_fill < buffer_length) \
+      break; \
+    \
+    for (j = 0; j < channels; j++) { \
+      /* Calculate FFT of input block */ \
+      gst_fft_f64_fft (fft, \
+          buffer + real_buffer_length * j + kernel_length - 1, fft_buffer); \
+      \
+      /* Complex multiplication of input and filter spectrum */ \
+      for (i = 0; i < frequency_response_length; i++) { \
+	re = fft_buffer[i].r; \
+	im = fft_buffer[i].i; \
+        \
+        fft_buffer[i].r = \
+            re * frequency_response[i].r - \
+            im * frequency_response[i].i; \
+        fft_buffer[i].i = \
+            re * frequency_response[i].i + \
+            im * frequency_response[i].r; \
+      } \
+      \
+      /* Calculate inverse FFT of the result */ \
+      gst_fft_f64_inverse_fft (ifft, fft_buffer, \
+          buffer + real_buffer_length * j); \
+      \
+      /* Copy all except the first kernel_length-1 samples to the output */ \
+      for (i = 0; i < buffer_length - kernel_length + 1; i++) { \
+        dst[i * channels + j] = \
+            buffer[real_buffer_length * j + kernel_length - 1 + i]; \
+      } \
+      \
+      /* Copy the last kernel_length-1 samples to the beginning for the next block */ \
+      for (i = 0; i < kernel_length - 1; i++) { \
+        buffer[real_buffer_length * j + kernel_length - 1 + i] = \
+            buffer[real_buffer_length * j + buffer_length + i]; \
+      } \
+    } \
+    \
+    generated += buffer_length - kernel_length + 1; \
+    dst += channels * (buffer_length - kernel_length + 1); \
+    \
+    /* The the first kernel_length-1 samples are there already */ \
+    buffer_fill = kernel_length - 1; \
+  } \
+  \
+  /* Write back cached buffer_fill value */ \
+  self->buffer_fill = buffer_fill; \
+  \
+  return generated; \
+} G_STMT_END
+
+DEFINE_FFT_PROCESS_FUNC (32, float);
+DEFINE_FFT_PROCESS_FUNC (64, double);
+
+DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (32, 1, float);
+DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (64, 1, double);
+
+DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (32, 2, float);
+DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (64, 2, double);
+
+#undef FFT_CONVOLUTION_BODY
+#undef DEFINE_FFT_PROCESS_FUNC
+#undef DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS
+
+/* Element class */
+static void
+    gst_audio_fx_base_fir_filter_calculate_frequency_response
+    (GstAudioFXBaseFIRFilter * self)
+{
+  gst_fft_f64_free (self->fft);
+  self->fft = NULL;
+  gst_fft_f64_free (self->ifft);
+  self->ifft = NULL;
+  g_free (self->frequency_response);
+  self->frequency_response_length = 0;
+  g_free (self->fft_buffer);
+  self->fft_buffer = NULL;
+
+  if (self->kernel && self->kernel_length >= FFT_THRESHOLD
+      && !self->low_latency) {
+    guint block_length, i;
+    gdouble *kernel_tmp, *kernel = self->kernel;
+
+    /* We process 4 * kernel_length samples per pass in FFT mode */
+    block_length = 4 * self->kernel_length;
+    block_length = gst_fft_next_fast_length (block_length);
+    self->block_length = block_length;
+
+    kernel_tmp = g_new0 (gdouble, block_length);
+    memcpy (kernel_tmp, kernel, self->kernel_length * sizeof (gdouble));
+
+    self->fft = gst_fft_f64_new (block_length, FALSE);
+    self->ifft = gst_fft_f64_new (block_length, TRUE);
+    self->frequency_response_length = block_length / 2 + 1;
+    self->frequency_response =
+        g_new (GstFFTF64Complex, self->frequency_response_length);
+    gst_fft_f64_fft (self->fft, kernel_tmp, self->frequency_response);
+    g_free (kernel_tmp);
+
+    /* Normalize to make sure IFFT(FFT(x)) == x */
+    for (i = 0; i < self->frequency_response_length; i++) {
+      self->frequency_response[i].r /= block_length;
+      self->frequency_response[i].i /= block_length;
+    }
+  }
+}
+
+/* Must be called with base transform lock! */
+static void
+gst_audio_fx_base_fir_filter_select_process_function (GstAudioFXBaseFIRFilter *
+    self, GstAudioFormat format, gint channels)
+{
+  switch (format) {
+    case GST_AUDIO_FORMAT_F32:
+      if (self->fft && !self->low_latency) {
+        if (channels == 1)
+          self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_1_32;
+        else if (channels == 2)
+          self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_2_32;
+        else
+          self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_32;
+      } else {
+        if (channels == 1)
+          self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_1_32;
+        else if (channels == 2)
+          self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_2_32;
+        else
+          self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_32;
+      }
+      break;
+    case GST_AUDIO_FORMAT_F64:
+      if (self->fft && !self->low_latency) {
+        if (channels == 1)
+          self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_1_64;
+        else if (channels == 2)
+          self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_2_64;
+        else
+          self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_64;
+      } else {
+        if (channels == 1)
+          self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_1_64;
+        else if (channels == 2)
+          self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_2_64;
+        else
+          self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_64;
+      }
+      break;
+    default:
+      self->process = NULL;
+      break;
+  }
+}
+
+static void
+gst_audio_fx_base_fir_filter_finalize (GObject * object)
+{
+  GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (object);
+
+  g_free (self->buffer);
+  g_free (self->kernel);
+  gst_fft_f64_free (self->fft);
+  gst_fft_f64_free (self->ifft);
+  g_free (self->frequency_response);
+  g_free (self->fft_buffer);
+  g_mutex_clear (&self->lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_audio_fx_base_fir_filter_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (object);
+
+  switch (prop_id) {
+    case PROP_LOW_LATENCY:{
+      gboolean low_latency;
+
+      if (GST_STATE (self) >= GST_STATE_PAUSED) {
+        g_warning ("Changing the \"low-latency\" property "
+            "is only allowed in states < PAUSED");
+        return;
+      }
+
+
+      g_mutex_lock (&self->lock);
+      low_latency = g_value_get_boolean (value);
+
+      if (self->low_latency != low_latency) {
+        self->low_latency = low_latency;
+        gst_audio_fx_base_fir_filter_calculate_frequency_response (self);
+        gst_audio_fx_base_fir_filter_select_process_function (self,
+            GST_AUDIO_FILTER_FORMAT (self), GST_AUDIO_FILTER_CHANNELS (self));
+      }
+      g_mutex_unlock (&self->lock);
+      break;
+    }
+    case PROP_DRAIN_ON_CHANGES:{
+      g_mutex_lock (&self->lock);
+      self->drain_on_changes = g_value_get_boolean (value);
+      g_mutex_unlock (&self->lock);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_audio_fx_base_fir_filter_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (object);
+
+  switch (prop_id) {
+    case PROP_LOW_LATENCY:
+      g_value_set_boolean (value, self->low_latency);
+      break;
+    case PROP_DRAIN_ON_CHANGES:
+      g_value_set_boolean (value, self->drain_on_changes);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_audio_fx_base_fir_filter_class_init (GstAudioFXBaseFIRFilterClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
+  GstCaps *caps;
+
+  GST_DEBUG_CATEGORY_INIT (gst_audio_fx_base_fir_filter_debug,
+      "audiofxbasefirfilter", 0, "FIR filter base class");
+
+  gobject_class->finalize = gst_audio_fx_base_fir_filter_finalize;
+  gobject_class->set_property = gst_audio_fx_base_fir_filter_set_property;
+  gobject_class->get_property = gst_audio_fx_base_fir_filter_get_property;
+
+  /**
+   * GstAudioFXBaseFIRFilter:low-latency:
+   *
+   * Work in low-latency mode. This mode is much slower for large filter sizes
+   * but the latency is always only the pre-latency of the filter.
+   */
+  g_object_class_install_property (gobject_class, PROP_LOW_LATENCY,
+      g_param_spec_boolean ("low-latency", "Low latency",
+          "Operate in low latency mode. This mode is slower but the "
+          "latency will only be the filter pre-latency. "
+          "Can only be changed in states < PAUSED!", DEFAULT_LOW_LATENCY,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstAudioFXBaseFIRFilter:drain-on-changes:
+   *
+   * Whether the filter should be drained when its coeficients change
+   *
+   * Note: Currently this only works if the kernel size is not changed!
+   * Support for drainless kernel size changes will be added in the future.
+   */
+  g_object_class_install_property (gobject_class, PROP_DRAIN_ON_CHANGES,
+      g_param_spec_boolean ("drain-on-changes", "Drain on changes",
+          "Drains the filter when its coeficients change",
+          DEFAULT_DRAIN_ON_CHANGES,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  caps = gst_caps_from_string (ALLOWED_CAPS);
+  gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass),
+      caps);
+  gst_caps_unref (caps);
+
+  trans_class->transform =
+      GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_transform);
+  trans_class->start = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_start);
+  trans_class->stop = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_stop);
+  trans_class->sink_event =
+      GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_sink_event);
+  trans_class->query = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_query);
+  trans_class->transform_size =
+      GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_transform_size);
+  filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_setup);
+}
+
+static void
+gst_audio_fx_base_fir_filter_init (GstAudioFXBaseFIRFilter * self)
+{
+  self->kernel = NULL;
+  self->buffer = NULL;
+  self->buffer_length = 0;
+
+  self->start_ts = GST_CLOCK_TIME_NONE;
+  self->start_off = GST_BUFFER_OFFSET_NONE;
+  self->nsamples_out = 0;
+  self->nsamples_in = 0;
+
+  self->low_latency = DEFAULT_LOW_LATENCY;
+  self->drain_on_changes = DEFAULT_DRAIN_ON_CHANGES;
+
+  g_mutex_init (&self->lock);
+}
+
+void
+gst_audio_fx_base_fir_filter_push_residue (GstAudioFXBaseFIRFilter * self)
+{
+  GstBuffer *outbuf;
+  GstFlowReturn res;
+  gint rate = GST_AUDIO_FILTER_RATE (self);
+  gint channels = GST_AUDIO_FILTER_CHANNELS (self);
+  gint bps = GST_AUDIO_FILTER_BPS (self);
+  gint outsize, outsamples;
+  GstMapInfo map;
+  guint8 *in, *out;
+
+  if (channels == 0 || rate == 0 || self->nsamples_in == 0) {
+    self->buffer_fill = 0;
+    g_free (self->buffer);
+    self->buffer = NULL;
+    return;
+  }
+
+  /* Calculate the number of samples and their memory size that
+   * should be pushed from the residue */
+  outsamples = self->nsamples_in - (self->nsamples_out - self->latency);
+  if (outsamples <= 0) {
+    self->buffer_fill = 0;
+    g_free (self->buffer);
+    self->buffer = NULL;
+    return;
+  }
+  outsize = outsamples * channels * bps;
+
+  if (!self->fft || self->low_latency) {
+    gint64 diffsize, diffsamples;
+
+    /* Process the difference between latency and residue length samples
+     * to start at the actual data instead of starting at the zeros before
+     * when we only got one buffer smaller than latency */
+    diffsamples =
+        ((gint64) self->latency) - ((gint64) self->buffer_fill) / channels;
+    if (diffsamples > 0) {
+      diffsize = diffsamples * channels * bps;
+      in = g_new0 (guint8, diffsize);
+      out = g_new0 (guint8, diffsize);
+      self->nsamples_out += self->process (self, in, out, diffsamples);
+      g_free (in);
+      g_free (out);
+    }
+
+    outbuf = gst_buffer_new_and_alloc (outsize);
+
+    /* Convolve the residue with zeros to get the actual remaining data */
+    in = g_new0 (guint8, outsize);
+    gst_buffer_map (outbuf, &map, GST_MAP_READWRITE);
+    self->nsamples_out += self->process (self, in, map.data, outsamples);
+    gst_buffer_unmap (outbuf, &map);
+
+    g_free (in);
+  } else {
+    guint gensamples = 0;
+
+    outbuf = gst_buffer_new_and_alloc (outsize);
+    gst_buffer_map (outbuf, &map, GST_MAP_READWRITE);
+
+    while (gensamples < outsamples) {
+      guint step_insamples = self->block_length - self->buffer_fill;
+      guint8 *zeroes = g_new0 (guint8, step_insamples * channels * bps);
+      guint8 *out = g_new (guint8, self->block_length * channels * bps);
+      guint step_gensamples;
+
+      step_gensamples = self->process (self, zeroes, out, step_insamples);
+      g_free (zeroes);
+
+      memcpy (map.data + gensamples * bps, out, MIN (step_gensamples,
+              outsamples - gensamples) * bps);
+      gensamples += MIN (step_gensamples, outsamples - gensamples);
+
+      g_free (out);
+    }
+    self->nsamples_out += gensamples;
+
+    gst_buffer_unmap (outbuf, &map);
+  }
+
+  /* Set timestamp, offset, etc from the values we
+   * saved when processing the regular buffers */
+  if (GST_CLOCK_TIME_IS_VALID (self->start_ts))
+    GST_BUFFER_TIMESTAMP (outbuf) = self->start_ts;
+  else
+    GST_BUFFER_TIMESTAMP (outbuf) = 0;
+  GST_BUFFER_TIMESTAMP (outbuf) +=
+      gst_util_uint64_scale_int (self->nsamples_out - outsamples -
+      self->latency, GST_SECOND, rate);
+
+  GST_BUFFER_DURATION (outbuf) =
+      gst_util_uint64_scale_int (outsamples, GST_SECOND, rate);
+
+  if (self->start_off != GST_BUFFER_OFFSET_NONE) {
+    GST_BUFFER_OFFSET (outbuf) =
+        self->start_off + self->nsamples_out - outsamples - self->latency;
+    GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET (outbuf) + outsamples;
+  }
+
+  GST_DEBUG_OBJECT (self,
+      "Pushing residue buffer of size %" G_GSIZE_FORMAT " with timestamp: %"
+      GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
+      G_GUINT64_FORMAT ", offset_end: %" G_GUINT64_FORMAT ", nsamples_out: %d",
+      gst_buffer_get_size (outbuf),
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
+      GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
+      GST_BUFFER_OFFSET_END (outbuf), outsamples);
+
+  res = gst_pad_push (GST_BASE_TRANSFORM_CAST (self)->srcpad, outbuf);
+
+  if (G_UNLIKELY (res != GST_FLOW_OK)) {
+    GST_WARNING_OBJECT (self, "failed to push residue");
+  }
+
+  self->buffer_fill = 0;
+}
+
+/* GstAudioFilter vmethod implementations */
+
+/* get notified of caps and plug in the correct process function */
+static gboolean
+gst_audio_fx_base_fir_filter_setup (GstAudioFilter * base,
+    const GstAudioInfo * info)
+{
+  GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
+
+  g_mutex_lock (&self->lock);
+  if (self->buffer) {
+    gst_audio_fx_base_fir_filter_push_residue (self);
+    g_free (self->buffer);
+    self->buffer = NULL;
+    self->buffer_fill = 0;
+    self->buffer_length = 0;
+    self->start_ts = GST_CLOCK_TIME_NONE;
+    self->start_off = GST_BUFFER_OFFSET_NONE;
+    self->nsamples_out = 0;
+    self->nsamples_in = 0;
+  }
+
+  gst_audio_fx_base_fir_filter_select_process_function (self,
+      GST_AUDIO_INFO_FORMAT (info), GST_AUDIO_INFO_CHANNELS (info));
+  g_mutex_unlock (&self->lock);
+
+  return (self->process != NULL);
+}
+
+/* GstBaseTransform vmethod implementations */
+
+static gboolean
+gst_audio_fx_base_fir_filter_transform_size (GstBaseTransform * base,
+    GstPadDirection direction, GstCaps * caps, gsize size, GstCaps * othercaps,
+    gsize * othersize)
+{
+  GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
+  guint blocklen;
+  GstAudioInfo info;
+  gint bpf;
+
+  if (!self->fft || self->low_latency || direction == GST_PAD_SRC) {
+    *othersize = size;
+    return TRUE;
+  }
+
+  if (!gst_audio_info_from_caps (&info, caps))
+    return FALSE;
+
+  bpf = GST_AUDIO_INFO_BPF (&info);
+
+  size /= bpf;
+  blocklen = self->block_length - self->kernel_length + 1;
+  *othersize = ((size + blocklen - 1) / blocklen) * blocklen;
+  *othersize *= bpf;
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_audio_fx_base_fir_filter_transform (GstBaseTransform * base,
+    GstBuffer * inbuf, GstBuffer * outbuf)
+{
+  GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
+  GstClockTime timestamp, expected_timestamp;
+  gint channels = GST_AUDIO_FILTER_CHANNELS (self);
+  gint rate = GST_AUDIO_FILTER_RATE (self);
+  gint bps = GST_AUDIO_FILTER_BPS (self);
+  GstMapInfo inmap, outmap;
+  guint input_samples;
+  guint output_samples;
+  guint generated_samples;
+  guint64 output_offset;
+  gint64 diff = 0;
+  GstClockTime stream_time;
+
+  timestamp = GST_BUFFER_TIMESTAMP (outbuf);
+
+  if (!GST_CLOCK_TIME_IS_VALID (timestamp)
+      && !GST_CLOCK_TIME_IS_VALID (self->start_ts)) {
+    GST_ERROR_OBJECT (self, "Invalid timestamp");
+    return GST_FLOW_ERROR;
+  }
+
+  g_mutex_lock (&self->lock);
+  stream_time =
+      gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (self, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (self), stream_time);
+
+  g_return_val_if_fail (self->kernel != NULL, GST_FLOW_ERROR);
+  g_return_val_if_fail (channels != 0, GST_FLOW_ERROR);
+
+  if (GST_CLOCK_TIME_IS_VALID (self->start_ts))
+    expected_timestamp =
+        self->start_ts + gst_util_uint64_scale_int (self->nsamples_in,
+        GST_SECOND, rate);
+  else
+    expected_timestamp = GST_CLOCK_TIME_NONE;
+
+  /* Reset the residue if already existing on discont buffers */
+  if (GST_BUFFER_IS_DISCONT (inbuf)
+      || (GST_CLOCK_TIME_IS_VALID (expected_timestamp)
+          && (ABS (GST_CLOCK_DIFF (timestamp,
+                      expected_timestamp)) > 5 * GST_MSECOND))) {
+    GST_DEBUG_OBJECT (self, "Discontinuity detected - flushing");
+    if (GST_CLOCK_TIME_IS_VALID (expected_timestamp))
+      gst_audio_fx_base_fir_filter_push_residue (self);
+    self->buffer_fill = 0;
+    g_free (self->buffer);
+    self->buffer = NULL;
+    self->start_ts = timestamp;
+    self->start_off = GST_BUFFER_OFFSET (inbuf);
+    self->nsamples_out = 0;
+    self->nsamples_in = 0;
+  } else if (!GST_CLOCK_TIME_IS_VALID (self->start_ts)) {
+    self->start_ts = timestamp;
+    self->start_off = GST_BUFFER_OFFSET (inbuf);
+  }
+
+  gst_buffer_map (inbuf, &inmap, GST_MAP_READ);
+  gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
+
+  input_samples = (inmap.size / bps) / channels;
+  output_samples = (outmap.size / bps) / channels;
+
+  self->nsamples_in += input_samples;
+
+  generated_samples =
+      self->process (self, inmap.data, outmap.data, input_samples);
+
+  gst_buffer_unmap (inbuf, &inmap);
+  gst_buffer_unmap (outbuf, &outmap);
+
+  g_assert (generated_samples <= output_samples);
+  self->nsamples_out += generated_samples;
+  if (generated_samples == 0)
+    goto no_samples;
+
+  /* Calculate the number of samples we can push out now without outputting
+   * latency zeros in the beginning */
+  diff = ((gint64) self->nsamples_out) - ((gint64) self->latency);
+  if (diff < 0)
+    goto no_samples;
+
+  if (diff < generated_samples) {
+    gint64 tmp = diff;
+    diff = generated_samples - diff;
+    generated_samples = tmp;
+  } else {
+    diff = 0;
+  }
+
+  gst_buffer_resize (outbuf, diff * bps * channels,
+      generated_samples * bps * channels);
+
+  output_offset = self->nsamples_out - self->latency - generated_samples;
+  GST_BUFFER_TIMESTAMP (outbuf) =
+      self->start_ts + gst_util_uint64_scale_int (output_offset, GST_SECOND,
+      rate);
+  GST_BUFFER_DURATION (outbuf) =
+      gst_util_uint64_scale_int (output_samples, GST_SECOND, rate);
+  if (self->start_off != GST_BUFFER_OFFSET_NONE) {
+    GST_BUFFER_OFFSET (outbuf) = self->start_off + output_offset;
+    GST_BUFFER_OFFSET_END (outbuf) =
+        GST_BUFFER_OFFSET (outbuf) + generated_samples;
+  } else {
+    GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
+    GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
+  }
+  g_mutex_unlock (&self->lock);
+
+  GST_DEBUG_OBJECT (self,
+      "Pushing buffer of size %" G_GSIZE_FORMAT " with timestamp: %"
+      GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
+      G_GUINT64_FORMAT ", offset_end: %" G_GUINT64_FORMAT ", nsamples_out: %d",
+      gst_buffer_get_size (outbuf),
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
+      GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
+      GST_BUFFER_OFFSET_END (outbuf), generated_samples);
+
+  return GST_FLOW_OK;
+
+no_samples:
+  {
+    g_mutex_unlock (&self->lock);
+    return GST_BASE_TRANSFORM_FLOW_DROPPED;
+  }
+}
+
+static gboolean
+gst_audio_fx_base_fir_filter_start (GstBaseTransform * base)
+{
+  GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
+
+  self->buffer_fill = 0;
+  g_free (self->buffer);
+  self->buffer = NULL;
+  self->start_ts = GST_CLOCK_TIME_NONE;
+  self->start_off = GST_BUFFER_OFFSET_NONE;
+  self->nsamples_out = 0;
+  self->nsamples_in = 0;
+
+  return TRUE;
+}
+
+static gboolean
+gst_audio_fx_base_fir_filter_stop (GstBaseTransform * base)
+{
+  GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
+
+  g_free (self->buffer);
+  self->buffer = NULL;
+  self->buffer_length = 0;
+
+  return TRUE;
+}
+
+static gboolean
+gst_audio_fx_base_fir_filter_query (GstBaseTransform * trans,
+    GstPadDirection direction, GstQuery * query)
+{
+  GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (trans);
+  gboolean res = TRUE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_LATENCY:
+    {
+      GstClockTime min, max;
+      gboolean live;
+      guint64 latency;
+      gint rate = GST_AUDIO_FILTER_RATE (self);
+
+      if (rate == 0) {
+        res = FALSE;
+      } else if ((res =
+              gst_pad_peer_query (GST_BASE_TRANSFORM (self)->sinkpad, query))) {
+        gst_query_parse_latency (query, &live, &min, &max);
+
+        GST_DEBUG_OBJECT (self, "Peer latency: min %"
+            GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (min), GST_TIME_ARGS (max));
+
+        if (self->fft && !self->low_latency)
+          latency = self->block_length - self->kernel_length + 1;
+        else
+          latency = self->latency;
+
+        /* add our own latency */
+        latency = gst_util_uint64_scale_round (latency, GST_SECOND, rate);
+
+        GST_DEBUG_OBJECT (self, "Our latency: %"
+            GST_TIME_FORMAT, GST_TIME_ARGS (latency));
+
+        min += latency;
+        if (max != GST_CLOCK_TIME_NONE)
+          max += latency;
+
+        GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
+            GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (min), GST_TIME_ARGS (max));
+
+        gst_query_set_latency (query, live, min, max);
+      }
+      break;
+    }
+    default:
+      res =
+          GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
+          query);
+      break;
+  }
+  return res;
+}
+
+static gboolean
+gst_audio_fx_base_fir_filter_sink_event (GstBaseTransform * base,
+    GstEvent * event)
+{
+  GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+      gst_audio_fx_base_fir_filter_push_residue (self);
+      self->start_ts = GST_CLOCK_TIME_NONE;
+      self->start_off = GST_BUFFER_OFFSET_NONE;
+      self->nsamples_out = 0;
+      self->nsamples_in = 0;
+      break;
+    default:
+      break;
+  }
+
+  return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (base, event);
+}
+
+void
+gst_audio_fx_base_fir_filter_set_kernel (GstAudioFXBaseFIRFilter * self,
+    gdouble * kernel, guint kernel_length, guint64 latency,
+    const GstAudioInfo * info)
+{
+  gboolean latency_changed;
+  GstAudioFormat format;
+  gint channels;
+
+  g_return_if_fail (kernel != NULL);
+  g_return_if_fail (self != NULL);
+
+  g_mutex_lock (&self->lock);
+
+  latency_changed = (self->latency != latency
+      || (!self->low_latency && self->kernel_length < FFT_THRESHOLD
+          && kernel_length >= FFT_THRESHOLD)
+      || (!self->low_latency && self->kernel_length >= FFT_THRESHOLD
+          && kernel_length < FFT_THRESHOLD));
+
+  /* FIXME: If the latency changes, the buffer size changes too and we
+   * have to drain in any case until this is fixed in the future */
+  if (self->buffer && (!self->drain_on_changes || latency_changed)) {
+    gst_audio_fx_base_fir_filter_push_residue (self);
+    self->start_ts = GST_CLOCK_TIME_NONE;
+    self->start_off = GST_BUFFER_OFFSET_NONE;
+    self->nsamples_out = 0;
+    self->nsamples_in = 0;
+    self->buffer_fill = 0;
+  }
+
+  g_free (self->kernel);
+  if (!self->drain_on_changes || latency_changed) {
+    g_free (self->buffer);
+    self->buffer = NULL;
+    self->buffer_fill = 0;
+    self->buffer_length = 0;
+  }
+
+  self->kernel = kernel;
+  self->kernel_length = kernel_length;
+
+  if (info) {
+    format = GST_AUDIO_INFO_FORMAT (info);
+    channels = GST_AUDIO_INFO_CHANNELS (info);
+  } else {
+    format = GST_AUDIO_FILTER_FORMAT (self);
+    channels = GST_AUDIO_FILTER_CHANNELS (self);
+  }
+
+  gst_audio_fx_base_fir_filter_calculate_frequency_response (self);
+  gst_audio_fx_base_fir_filter_select_process_function (self, format, channels);
+
+  if (latency_changed) {
+    self->latency = latency;
+    gst_element_post_message (GST_ELEMENT (self),
+        gst_message_new_latency (GST_OBJECT (self)));
+  }
+
+  g_mutex_unlock (&self->lock);
+}
diff --git a/gst/audiofx/audiofxbasefirfilter.h b/gst/audiofx/audiofxbasefirfilter.h
new file mode 100644
index 0000000..2bd5561
--- /dev/null
+++ b/gst/audiofx/audiofxbasefirfilter.h
@@ -0,0 +1,102 @@
+/* -*- c-basic-offset: 2 -*-
+ * 
+ * GStreamer
+ * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2006 Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>
+ *               2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * 
+ */
+
+#ifndef __GST_AUDIO_FX_BASE_FIR_FILTER_H__
+#define __GST_AUDIO_FX_BASE_FIR_FILTER_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiofilter.h>
+#include <gst/fft/gstfftf64.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AUDIO_FX_BASE_FIR_FILTER \
+  (gst_audio_fx_base_fir_filter_get_type())
+#define GST_AUDIO_FX_BASE_FIR_FILTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_FX_BASE_FIR_FILTER,GstAudioFXBaseFIRFilter))
+#define GST_AUDIO_FX_BASE_FIR_FILTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_FX_BASE_FIR_FILTER,GstAudioFXBaseFIRFilterClass))
+#define GST_IS_AUDIO_FX_BASE_FIR_FILTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_FX_BASE_FIR_FILTER))
+#define GST_IS_AUDIO_FX_BASE_FIR_FILTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_FX_BASE_FIR_FILTER))
+
+typedef struct _GstAudioFXBaseFIRFilter GstAudioFXBaseFIRFilter;
+typedef struct _GstAudioFXBaseFIRFilterClass GstAudioFXBaseFIRFilterClass;
+
+typedef guint (*GstAudioFXBaseFIRFilterProcessFunc) (GstAudioFXBaseFIRFilter *, const guint8 *, guint8 *, guint);
+
+/**
+ * GstAudioFXBaseFIRFilter:
+ *
+ * Opaque data structure.
+ */
+struct _GstAudioFXBaseFIRFilter {
+  GstAudioFilter element;
+
+  /* properties */
+  gdouble *kernel;              /* filter kernel -- time domain */
+  guint kernel_length;          /* length of the filter kernel -- time domain */
+
+  guint64 latency;              /* pre-latency of the filter kernel */
+  gboolean low_latency;         /* work in slower low latency mode */
+
+  gboolean drain_on_changes;    /* If the filter should be drained when
+                                 * coeficients change */
+
+  /* < private > */
+  GstAudioFXBaseFIRFilterProcessFunc process;
+
+  gdouble *buffer;              /* buffer for storing samples of previous buffers */
+  guint buffer_fill;            /* fill level of buffer */
+  guint buffer_length;          /* length of the buffer -- meaning depends on processing mode */
+
+  /* FFT convolution specific data */
+  GstFFTF64 *fft;
+  GstFFTF64 *ifft;
+  GstFFTF64Complex *frequency_response;  /* filter kernel -- frequency domain */
+  guint frequency_response_length;       /* length of filter kernel -- frequency domain */
+  GstFFTF64Complex *fft_buffer;          /* FFT buffer, has the length of the frequency response */
+  guint block_length;                    /* Length of the processing blocks -- time domain */
+
+  GstClockTime start_ts;        /* start timestamp after a discont */
+  guint64 start_off;            /* start offset after a discont */
+  guint64 nsamples_out;         /* number of output samples since last discont */
+  guint64 nsamples_in;          /* number of input samples since last discont */
+
+  GMutex lock;
+};
+
+struct _GstAudioFXBaseFIRFilterClass {
+  GstAudioFilterClass parent_class;
+};
+
+GType gst_audio_fx_base_fir_filter_get_type (void);
+void gst_audio_fx_base_fir_filter_set_kernel (GstAudioFXBaseFIRFilter *filter, gdouble *kernel,
+                                              guint kernel_length, guint64 latency, const GstAudioInfo * info);
+void gst_audio_fx_base_fir_filter_push_residue (GstAudioFXBaseFIRFilter *filter);
+
+G_END_DECLS
+
+#endif /* __GST_AUDIO_FX_BASE_FIR_FILTER_H__ */
diff --git a/gst/audiofx/audiofxbaseiirfilter.c b/gst/audiofx/audiofxbaseiirfilter.c
new file mode 100644
index 0000000..93553e8
--- /dev/null
+++ b/gst/audiofx/audiofxbaseiirfilter.c
@@ -0,0 +1,416 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include <math.h>
+
+#include "audiofxbaseiirfilter.h"
+
+#define GST_CAT_DEFAULT gst_audio_fx_base_iir_filter_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+#define ALLOWED_CAPS \
+    "audio/x-raw,"                                                \
+    " format=(string){"GST_AUDIO_NE(F32)","GST_AUDIO_NE(F64)"},"  \
+    " rate = (int) [ 1, MAX ],"                                   \
+    " channels = (int) [ 1, MAX ],"                               \
+    " layout=(string) interleaved"
+
+#define gst_audio_fx_base_iir_filter_parent_class parent_class
+G_DEFINE_TYPE (GstAudioFXBaseIIRFilter,
+    gst_audio_fx_base_iir_filter, GST_TYPE_AUDIO_FILTER);
+
+static gboolean gst_audio_fx_base_iir_filter_setup (GstAudioFilter * filter,
+    const GstAudioInfo * info);
+static GstFlowReturn
+gst_audio_fx_base_iir_filter_transform_ip (GstBaseTransform * base,
+    GstBuffer * buf);
+static gboolean gst_audio_fx_base_iir_filter_stop (GstBaseTransform * base);
+
+static void process_64 (GstAudioFXBaseIIRFilter * filter,
+    gdouble * data, guint num_samples);
+static void process_32 (GstAudioFXBaseIIRFilter * filter,
+    gfloat * data, guint num_samples);
+
+/* GObject vmethod implementations */
+
+static void
+gst_audio_fx_base_iir_filter_finalize (GObject * object)
+{
+  GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (object);
+
+  if (filter->a) {
+    g_free (filter->a);
+    filter->a = NULL;
+  }
+
+  if (filter->b) {
+    g_free (filter->b);
+    filter->b = NULL;
+  }
+
+  if (filter->channels) {
+    GstAudioFXBaseIIRFilterChannelCtx *ctx;
+    guint i;
+
+    for (i = 0; i < filter->nchannels; i++) {
+      ctx = &filter->channels[i];
+      g_free (ctx->x);
+      g_free (ctx->y);
+    }
+
+    g_free (filter->channels);
+    filter->channels = NULL;
+  }
+  g_mutex_clear (&filter->lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_audio_fx_base_iir_filter_class_init (GstAudioFXBaseIIRFilterClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
+  GstCaps *caps;
+
+  GST_DEBUG_CATEGORY_INIT (gst_audio_fx_base_iir_filter_debug,
+      "audiofxbaseiirfilter", 0, "Audio IIR Filter Base Class");
+
+  gobject_class->finalize = gst_audio_fx_base_iir_filter_finalize;
+
+  caps = gst_caps_from_string (ALLOWED_CAPS);
+  gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass),
+      caps);
+  gst_caps_unref (caps);
+
+  filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_setup);
+
+  trans_class->transform_ip =
+      GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_transform_ip);
+  trans_class->transform_ip_on_passthrough = FALSE;
+  trans_class->stop = GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_stop);
+}
+
+static void
+gst_audio_fx_base_iir_filter_init (GstAudioFXBaseIIRFilter * filter)
+{
+  gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
+
+  filter->a = NULL;
+  filter->na = 0;
+  filter->b = NULL;
+  filter->nb = 0;
+  filter->channels = NULL;
+  filter->nchannels = 0;
+
+  g_mutex_init (&filter->lock);
+}
+
+/* Evaluate the transfer function that corresponds to the IIR
+ * coefficients at (zr + zi*I)^-1 and return the magnitude */
+gdouble
+gst_audio_fx_base_iir_filter_calculate_gain (gdouble * a, guint na, gdouble * b,
+    guint nb, gdouble zr, gdouble zi)
+{
+  gdouble sum_ar, sum_ai;
+  gdouble sum_br, sum_bi;
+  gdouble gain_r, gain_i;
+
+  gdouble sum_r_old;
+  gdouble sum_i_old;
+
+  gint i;
+
+  sum_ar = a[na - 1];
+  sum_ai = 0.0;
+  for (i = na - 2; i >= 0; i--) {
+    sum_r_old = sum_ar;
+    sum_i_old = sum_ai;
+
+    sum_ar = (sum_r_old * zr - sum_i_old * zi) + a[i];
+    sum_ai = (sum_r_old * zi + sum_i_old * zr) + 0.0;
+  }
+
+  sum_br = b[nb - 1];
+  sum_bi = 0.0;
+  for (i = nb - 2; i >= 0; i--) {
+    sum_r_old = sum_br;
+    sum_i_old = sum_bi;
+
+    sum_br = (sum_r_old * zr - sum_i_old * zi) + b[i];
+    sum_bi = (sum_r_old * zi + sum_i_old * zr) + 0.0;
+  }
+
+  gain_r =
+      (sum_br * sum_ar + sum_bi * sum_ai) / (sum_ar * sum_ar + sum_ai * sum_ai);
+  gain_i =
+      (sum_bi * sum_ar - sum_br * sum_ai) / (sum_ar * sum_ar + sum_ai * sum_ai);
+
+  return (sqrt (gain_r * gain_r + gain_i * gain_i));
+}
+
+void
+gst_audio_fx_base_iir_filter_set_coefficients (GstAudioFXBaseIIRFilter * filter,
+    gdouble * a, guint na, gdouble * b, guint nb)
+{
+  guint i;
+
+  g_return_if_fail (GST_IS_AUDIO_FX_BASE_IIR_FILTER (filter));
+
+  g_mutex_lock (&filter->lock);
+
+  g_free (filter->a);
+  g_free (filter->b);
+
+  filter->a = filter->b = NULL;
+
+  if (filter->channels) {
+    GstAudioFXBaseIIRFilterChannelCtx *ctx;
+    gboolean free = (na != filter->na || nb != filter->nb);
+
+    for (i = 0; i < filter->nchannels; i++) {
+      ctx = &filter->channels[i];
+
+      if (free)
+        g_free (ctx->x);
+      else
+        memset (ctx->x, 0, filter->nb * sizeof (gdouble));
+
+      if (free)
+        g_free (ctx->y);
+      else
+        memset (ctx->y, 0, filter->na * sizeof (gdouble));
+    }
+
+    g_free (filter->channels);
+    filter->channels = NULL;
+  }
+
+  filter->na = na;
+  filter->nb = nb;
+
+  filter->a = a;
+  filter->b = b;
+
+  if (filter->nchannels && !filter->channels) {
+    GstAudioFXBaseIIRFilterChannelCtx *ctx;
+
+    filter->channels =
+        g_new0 (GstAudioFXBaseIIRFilterChannelCtx, filter->nchannels);
+    for (i = 0; i < filter->nchannels; i++) {
+      ctx = &filter->channels[i];
+
+      ctx->x = g_new0 (gdouble, filter->nb);
+      ctx->y = g_new0 (gdouble, filter->na);
+    }
+  }
+
+  g_mutex_unlock (&filter->lock);
+}
+
+/* GstAudioFilter vmethod implementations */
+
+static gboolean
+gst_audio_fx_base_iir_filter_setup (GstAudioFilter * base,
+    const GstAudioInfo * info)
+{
+  GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base);
+  gboolean ret = TRUE;
+  gint channels;
+
+  g_mutex_lock (&filter->lock);
+  switch (GST_AUDIO_INFO_FORMAT (info)) {
+    case GST_AUDIO_FORMAT_F32:
+      filter->process = (GstAudioFXBaseIIRFilterProcessFunc)
+          process_32;
+      break;
+    case GST_AUDIO_FORMAT_F64:
+      filter->process = (GstAudioFXBaseIIRFilterProcessFunc)
+          process_64;
+      break;
+    default:
+      ret = FALSE;
+      break;
+  }
+
+  channels = GST_AUDIO_INFO_CHANNELS (info);
+
+  if (channels != filter->nchannels) {
+    guint i;
+    GstAudioFXBaseIIRFilterChannelCtx *ctx;
+
+    if (filter->channels) {
+      for (i = 0; i < filter->nchannels; i++) {
+        ctx = &filter->channels[i];
+
+        g_free (ctx->x);
+        g_free (ctx->y);
+      }
+      g_free (filter->channels);
+    }
+
+    filter->channels = g_new0 (GstAudioFXBaseIIRFilterChannelCtx, channels);
+    for (i = 0; i < channels; i++) {
+      ctx = &filter->channels[i];
+
+      ctx->x = g_new0 (gdouble, filter->nb);
+      ctx->y = g_new0 (gdouble, filter->na);
+    }
+    filter->nchannels = channels;
+  }
+  g_mutex_unlock (&filter->lock);
+
+  return ret;
+}
+
+static inline gdouble
+process (GstAudioFXBaseIIRFilter * filter,
+    GstAudioFXBaseIIRFilterChannelCtx * ctx, gdouble x0)
+{
+  gdouble val = filter->b[0] * x0;
+  gint i, j;
+
+  for (i = 1, j = ctx->x_pos; i < filter->nb; i++) {
+    val += filter->b[i] * ctx->x[j];
+    j--;
+    if (j < 0)
+      j = filter->nb - 1;
+  }
+
+  for (i = 1, j = ctx->y_pos; i < filter->na; i++) {
+    val -= filter->a[i] * ctx->y[j];
+    j--;
+    if (j < 0)
+      j = filter->na - 1;
+  }
+  val /= filter->a[0];
+
+  if (ctx->x) {
+    ctx->x_pos++;
+    if (ctx->x_pos >= filter->nb)
+      ctx->x_pos = 0;
+    ctx->x[ctx->x_pos] = x0;
+  }
+  if (ctx->y) {
+    ctx->y_pos++;
+    if (ctx->y_pos >= filter->na)
+      ctx->y_pos = 0;
+
+    ctx->y[ctx->y_pos] = val;
+  }
+
+  return val;
+}
+
+#define DEFINE_PROCESS_FUNC(width,ctype) \
+static void \
+process_##width (GstAudioFXBaseIIRFilter * filter, \
+    g##ctype * data, guint num_samples) \
+{ \
+  gint i, j, channels = filter->nchannels; \
+  gdouble val; \
+  \
+  for (i = 0; i < num_samples / channels; i++) { \
+    for (j = 0; j < channels; j++) { \
+      val = process (filter, &filter->channels[j], *data); \
+      *data++ = val; \
+    } \
+  } \
+}
+
+DEFINE_PROCESS_FUNC (32, float);
+DEFINE_PROCESS_FUNC (64, double);
+
+#undef DEFINE_PROCESS_FUNC
+
+/* GstBaseTransform vmethod implementations */
+static GstFlowReturn
+gst_audio_fx_base_iir_filter_transform_ip (GstBaseTransform * base,
+    GstBuffer * buf)
+{
+  GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base);
+  guint num_samples;
+  GstClockTime timestamp, stream_time;
+  GstMapInfo map;
+
+  timestamp = GST_BUFFER_TIMESTAMP (buf);
+  stream_time =
+      gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (filter), stream_time);
+
+  gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+  num_samples = map.size / GST_AUDIO_FILTER_BPS (filter);
+
+  g_mutex_lock (&filter->lock);
+  if (filter->a == NULL || filter->b == NULL) {
+    g_warn_if_fail (filter->a != NULL && filter->b != NULL);
+    gst_buffer_unmap (buf, &map);
+    g_mutex_unlock (&filter->lock);
+    return GST_FLOW_ERROR;
+  }
+  filter->process (filter, map.data, num_samples);
+  g_mutex_unlock (&filter->lock);
+
+  gst_buffer_unmap (buf, &map);
+
+  return GST_FLOW_OK;
+}
+
+
+static gboolean
+gst_audio_fx_base_iir_filter_stop (GstBaseTransform * base)
+{
+  GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base);
+  guint channels = filter->nchannels;
+  GstAudioFXBaseIIRFilterChannelCtx *ctx;
+  guint i;
+
+  /* Reset the history of input and output values if
+   * already existing */
+  if (channels && filter->channels) {
+    for (i = 0; i < channels; i++) {
+      ctx = &filter->channels[i];
+      g_free (ctx->x);
+      g_free (ctx->y);
+    }
+    g_free (filter->channels);
+  }
+  filter->channels = NULL;
+  filter->nchannels = 0;
+
+  return TRUE;
+}
diff --git a/gst/audiofx/audiofxbaseiirfilter.h b/gst/audiofx/audiofxbaseiirfilter.h
new file mode 100644
index 0000000..f78ae31
--- /dev/null
+++ b/gst/audiofx/audiofxbaseiirfilter.h
@@ -0,0 +1,78 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AUDIO_FX_BASE_IIR_FILTER_H__
+#define __GST_AUDIO_FX_BASE_IIR_FILTER_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AUDIO_FX_BASE_IIR_FILTER            (gst_audio_fx_base_iir_filter_get_type())
+#define GST_AUDIO_FX_BASE_IIR_FILTER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_FX_BASE_IIR_FILTER,GstAudioFXBaseIIRFilter))
+#define GST_IS_AUDIO_FX_BASE_IIR_FILTER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_FX_BASE_IIR_FILTER))
+#define GST_AUDIO_FX_BASE_IIR_FILTER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_FX_BASE_IIR_FILTER,GstAudioFXBaseIIRFilterClass))
+#define GST_IS_AUDIO_FX_BASE_IIR_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_FX_BASE_IIR_FILTER))
+#define GST_AUDIO_FX_BASE_IIR_FILTER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_FX_BASE_IIR_FILTER,GstAudioFXBaseIIRFilterClass))
+typedef struct _GstAudioFXBaseIIRFilter GstAudioFXBaseIIRFilter;
+typedef struct _GstAudioFXBaseIIRFilterClass GstAudioFXBaseIIRFilterClass;
+
+typedef void (*GstAudioFXBaseIIRFilterProcessFunc) (GstAudioFXBaseIIRFilter *, guint8 *, guint);
+
+typedef struct
+{
+  gdouble *x;
+  gint x_pos;
+  gdouble *y;
+  gint y_pos;
+} GstAudioFXBaseIIRFilterChannelCtx;
+
+struct _GstAudioFXBaseIIRFilter
+{
+  GstAudioFilter audiofilter;
+
+  /* < private > */
+  GstAudioFXBaseIIRFilterProcessFunc process;
+
+  gdouble *a;
+  guint na;
+  gdouble *b;
+  guint nb;
+  GstAudioFXBaseIIRFilterChannelCtx *channels;
+  guint nchannels;
+
+  GMutex lock;
+};
+
+struct _GstAudioFXBaseIIRFilterClass
+{
+  GstAudioFilterClass parent;
+};
+
+GType gst_audio_fx_base_iir_filter_get_type (void);
+void gst_audio_fx_base_iir_filter_set_coefficients (GstAudioFXBaseIIRFilter *filter, gdouble *a, guint na, gdouble *b, guint nb);
+gdouble gst_audio_fx_base_iir_filter_calculate_gain (gdouble *a, guint na, gdouble *b, guint nb, gdouble zr, gdouble zi);
+
+G_END_DECLS
+
+#endif /* __GST_AUDIO_FX_BASE_IIR_FILTER_H__ */
diff --git a/gst/audiofx/audioiirfilter.c b/gst/audiofx/audioiirfilter.c
new file mode 100644
index 0000000..eb4f20c
--- /dev/null
+++ b/gst/audiofx/audioiirfilter.c
@@ -0,0 +1,281 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * 
+ */
+
+/**
+ * SECTION:element-audioiirfilter
+ *
+ * audioiirfilter implements a generic audio <ulink url="http://en.wikipedia.org/wiki/Infinite_impulse_response">IIR filter</ulink>. Before usage the
+ * "a" and "b" properties have to be set to the filter coefficients that
+ * should be used.
+ *
+ * The filter coefficients describe the numerator and denominator of the
+ * transfer function.
+ *
+ * To change the filter coefficients whenever the sampling rate changes the
+ * "rate-changed" signal can be used. This should be done for most
+ * IIR filters as they're depending on the sampling rate.
+ *
+ * <refsect2>
+ * <title>Example application</title>
+ * <informalexample><programlisting language="C">
+ * <xi:include xmlns:xi="http://www.w3.org/2003/XInclude" parse="text" href="../../../../tests/examples/audiofx/iirfilter-example.c" />
+ * </programlisting></informalexample>
+ * </refsect2>
+ */
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <gst/gst.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audioiirfilter.h"
+
+#include "gst/glib-compat-private.h"
+
+#define GST_CAT_DEFAULT gst_audio_iir_filter_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+enum
+{
+  SIGNAL_RATE_CHANGED,
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_A,
+  PROP_B
+};
+
+static guint gst_audio_iir_filter_signals[LAST_SIGNAL] = { 0, };
+
+#define gst_audio_iir_filter_parent_class parent_class
+G_DEFINE_TYPE (GstAudioIIRFilter, gst_audio_iir_filter,
+    GST_TYPE_AUDIO_FX_BASE_IIR_FILTER);
+
+static void gst_audio_iir_filter_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_audio_iir_filter_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_audio_iir_filter_finalize (GObject * object);
+
+static gboolean gst_audio_iir_filter_setup (GstAudioFilter * base,
+    const GstAudioInfo * info);
+
+static void
+gst_audio_iir_filter_class_init (GstAudioIIRFilterClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (gst_audio_iir_filter_debug, "audioiirfilter", 0,
+      "Generic audio IIR filter plugin");
+
+  gobject_class->set_property = gst_audio_iir_filter_set_property;
+  gobject_class->get_property = gst_audio_iir_filter_get_property;
+  gobject_class->finalize = gst_audio_iir_filter_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_A,
+      g_param_spec_value_array ("a", "A",
+          "Filter coefficients (denominator of transfer function)",
+          g_param_spec_double ("Coefficient", "Filter Coefficient",
+              "Filter coefficient", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_B,
+      g_param_spec_value_array ("b", "B",
+          "Filter coefficients (numerator of transfer function)",
+          g_param_spec_double ("Coefficient", "Filter Coefficient",
+              "Filter coefficient", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_iir_filter_setup);
+
+  /**
+   * GstAudioIIRFilter::rate-changed:
+   * @filter: the filter on which the signal is emitted
+   * @rate: the new sampling rate
+   *
+   * Will be emitted when the sampling rate changes. The callbacks
+   * will be called from the streaming thread and processing will
+   * stop until the event is handled.
+   */
+  gst_audio_iir_filter_signals[SIGNAL_RATE_CHANGED] =
+      g_signal_new ("rate-changed", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstAudioIIRFilterClass, rate_changed),
+      NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Audio IIR filter", "Filter/Effect/Audio",
+      "Generic audio IIR filter with custom filter kernel",
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+}
+
+static void
+gst_audio_iir_filter_update_coefficients (GstAudioIIRFilter * self,
+    GValueArray * va, GValueArray * vb)
+{
+  gdouble *a = NULL, *b = NULL;
+  guint i;
+
+  if (va) {
+    if (self->a)
+      g_value_array_free (self->a);
+
+    self->a = va;
+  }
+  if (vb) {
+    if (self->b)
+      g_value_array_free (self->b);
+
+    self->b = vb;
+  }
+
+  if (self->a && self->a->n_values > 0) {
+    a = g_new (gdouble, self->a->n_values);
+
+    for (i = 0; i < self->a->n_values; i++) {
+      GValue *v = g_value_array_get_nth (self->a, i);
+      a[i] = g_value_get_double (v);
+    }
+  }
+
+  if (self->b && self->b->n_values > 0) {
+    b = g_new (gdouble, self->b->n_values);
+    for (i = 0; i < self->b->n_values; i++) {
+      GValue *v = g_value_array_get_nth (self->b, i);
+      b[i] = g_value_get_double (v);
+    }
+  }
+
+  gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
+      (self), a, (self->a) ? self->a->n_values : 0, b,
+      (self->b) ? self->b->n_values : 0);
+}
+
+static void
+gst_audio_iir_filter_init (GstAudioIIRFilter * self)
+{
+  GValue v = { 0, };
+  GValueArray *a;
+
+  a = g_value_array_new (1);
+
+  g_value_init (&v, G_TYPE_DOUBLE);
+  g_value_set_double (&v, 1.0);
+  g_value_array_append (a, &v);
+  g_value_unset (&v);
+
+  gst_audio_iir_filter_update_coefficients (self, a, g_value_array_copy (a));
+
+  g_mutex_init (&self->lock);
+}
+
+/* GstAudioFilter vmethod implementations */
+
+/* get notified of caps and plug in the correct process function */
+static gboolean
+gst_audio_iir_filter_setup (GstAudioFilter * base, const GstAudioInfo * info)
+{
+  GstAudioIIRFilter *self = GST_AUDIO_IIR_FILTER (base);
+  gint new_rate = GST_AUDIO_INFO_RATE (info);
+
+  if (GST_AUDIO_FILTER_RATE (self) != new_rate) {
+    g_signal_emit (G_OBJECT (self),
+        gst_audio_iir_filter_signals[SIGNAL_RATE_CHANGED], 0, new_rate);
+  }
+
+  return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, info);
+}
+
+static void
+gst_audio_iir_filter_finalize (GObject * object)
+{
+  GstAudioIIRFilter *self = GST_AUDIO_IIR_FILTER (object);
+
+  g_mutex_clear (&self->lock);
+
+  if (self->a)
+    g_value_array_free (self->a);
+  self->a = NULL;
+  if (self->b)
+    g_value_array_free (self->b);
+  self->b = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_audio_iir_filter_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAudioIIRFilter *self = GST_AUDIO_IIR_FILTER (object);
+
+  g_return_if_fail (GST_IS_AUDIO_IIR_FILTER (self));
+
+  switch (prop_id) {
+    case PROP_A:
+      g_mutex_lock (&self->lock);
+      gst_audio_iir_filter_update_coefficients (self, g_value_dup_boxed (value),
+          NULL);
+      g_mutex_unlock (&self->lock);
+      break;
+    case PROP_B:
+      g_mutex_lock (&self->lock);
+      gst_audio_iir_filter_update_coefficients (self, NULL,
+          g_value_dup_boxed (value));
+      g_mutex_unlock (&self->lock);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_audio_iir_filter_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAudioIIRFilter *self = GST_AUDIO_IIR_FILTER (object);
+
+  switch (prop_id) {
+    case PROP_A:
+      g_value_set_boxed (value, self->a);
+      break;
+    case PROP_B:
+      g_value_set_boxed (value, self->b);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/gst/audiofx/audioiirfilter.h b/gst/audiofx/audioiirfilter.h
new file mode 100644
index 0000000..ab39c5b
--- /dev/null
+++ b/gst/audiofx/audioiirfilter.h
@@ -0,0 +1,70 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * 
+ */
+
+#ifndef __GST_AUDIO_IIR_FILTER_H__
+#define __GST_AUDIO_IIR_FILTER_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audiofxbaseiirfilter.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AUDIO_IIR_FILTER \
+  (gst_audio_iir_filter_get_type())
+#define GST_AUDIO_IIR_FILTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_IIR_FILTER,GstAudioIIRFilter))
+#define GST_AUDIO_IIR_FILTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_IIR_FILTER,GstAudioIIRFilterClass))
+#define GST_IS_AUDIO_IIR_FILTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_IIR_FILTER))
+#define GST_IS_AUDIO_IIR_FILTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_IIR_FILTER))
+
+typedef struct _GstAudioIIRFilter GstAudioIIRFilter;
+typedef struct _GstAudioIIRFilterClass GstAudioIIRFilterClass;
+
+/**
+ * GstAudioIIRFilter:
+ *
+ * Opaque data structure.
+ */
+struct _GstAudioIIRFilter {
+  GstAudioFXBaseIIRFilter parent;
+
+  GValueArray *a, *b;
+
+  /* < private > */
+  GMutex lock;
+};
+
+struct _GstAudioIIRFilterClass {
+  GstAudioFXBaseIIRFilterClass parent;
+
+  void (*rate_changed) (GstElement * element, gint rate);
+};
+
+GType gst_audio_iir_filter_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_AUDIO_IIR_FILTER_H__ */
diff --git a/gst/audiofx/audioinvert.c b/gst/audiofx/audioinvert.c
new file mode 100644
index 0000000..a68dd10
--- /dev/null
+++ b/gst/audiofx/audioinvert.c
@@ -0,0 +1,256 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ * Copyright (C) 2006 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-audioinvert
+ *
+ * Swaps upper and lower half of audio samples. Mixing an inverted sample on top of
+ * the original with a slight delay can produce effects that sound like resonance.
+ * Creating a stereo sample from a mono source, with one channel inverted produces wide-stereo sounds.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc wave=saw ! audioinvert degree=0.4 ! alsasink
+ * gst-launch-1.0 filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audioinvert degree=0.4 ! alsasink
+ * gst-launch-1.0 audiotestsrc wave=saw ! audioconvert ! audioinvert degree=0.4 ! audioconvert ! alsasink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audioinvert.h"
+
+#define GST_CAT_DEFAULT gst_audio_invert_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+/* Filter signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_DEGREE
+};
+
+#define ALLOWED_CAPS \
+    "audio/x-raw,"                                                     \
+    " format=(string) {"GST_AUDIO_NE(S16)","GST_AUDIO_NE(F32)"},"      \
+    " rate=(int)[1,MAX],"                                              \
+    " channels=(int)[1,MAX],"                                          \
+    " layout=(string) {interleaved, non-interleaved}"
+
+G_DEFINE_TYPE (GstAudioInvert, gst_audio_invert, GST_TYPE_AUDIO_FILTER);
+
+static void gst_audio_invert_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_audio_invert_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_audio_invert_setup (GstAudioFilter * filter,
+    const GstAudioInfo * info);
+static GstFlowReturn gst_audio_invert_transform_ip (GstBaseTransform * base,
+    GstBuffer * buf);
+
+static void gst_audio_invert_transform_int (GstAudioInvert * filter,
+    gint16 * data, guint num_samples);
+static void gst_audio_invert_transform_float (GstAudioInvert * filter,
+    gfloat * data, guint num_samples);
+
+/* GObject vmethod implementations */
+
+static void
+gst_audio_invert_class_init (GstAudioInvertClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstCaps *caps;
+
+  GST_DEBUG_CATEGORY_INIT (gst_audio_invert_debug, "audioinvert", 0,
+      "audioinvert element");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_audio_invert_set_property;
+  gobject_class->get_property = gst_audio_invert_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_DEGREE,
+      g_param_spec_float ("degree", "Degree",
+          "Degree of inversion", 0.0, 1.0,
+          0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class, "Audio inversion",
+      "Filter/Effect/Audio",
+      "Swaps upper and lower half of audio samples",
+      "Sebastian Dröge <slomo@circular-chaos.org>");
+
+  caps = gst_caps_from_string (ALLOWED_CAPS);
+  gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass),
+      caps);
+  gst_caps_unref (caps);
+
+  GST_BASE_TRANSFORM_CLASS (klass)->transform_ip =
+      GST_DEBUG_FUNCPTR (gst_audio_invert_transform_ip);
+  GST_BASE_TRANSFORM_CLASS (klass)->transform_ip_on_passthrough = FALSE;
+
+  GST_AUDIO_FILTER_CLASS (klass)->setup =
+      GST_DEBUG_FUNCPTR (gst_audio_invert_setup);
+}
+
+static void
+gst_audio_invert_init (GstAudioInvert * filter)
+{
+  filter->degree = 0.0;
+  gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
+  gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE);
+}
+
+static void
+gst_audio_invert_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAudioInvert *filter = GST_AUDIO_INVERT (object);
+
+  switch (prop_id) {
+    case PROP_DEGREE:
+      filter->degree = g_value_get_float (value);
+      gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter),
+          filter->degree == 0.0);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_audio_invert_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAudioInvert *filter = GST_AUDIO_INVERT (object);
+
+  switch (prop_id) {
+    case PROP_DEGREE:
+      g_value_set_float (value, filter->degree);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* GstAudioFilter vmethod implementations */
+
+static gboolean
+gst_audio_invert_setup (GstAudioFilter * base, const GstAudioInfo * info)
+{
+  GstAudioInvert *filter = GST_AUDIO_INVERT (base);
+  gboolean ret = TRUE;
+
+  switch (GST_AUDIO_INFO_FORMAT (info)) {
+    case GST_AUDIO_FORMAT_S16:
+      filter->process = (GstAudioInvertProcessFunc)
+          gst_audio_invert_transform_int;
+      break;
+    case GST_AUDIO_FORMAT_F32:
+      filter->process = (GstAudioInvertProcessFunc)
+          gst_audio_invert_transform_float;
+      break;
+    default:
+      ret = FALSE;
+      break;
+  }
+  return ret;
+}
+
+static void
+gst_audio_invert_transform_int (GstAudioInvert * filter,
+    gint16 * data, guint num_samples)
+{
+  gint i;
+  gfloat dry = 1.0 - filter->degree;
+  glong val;
+
+  for (i = 0; i < num_samples; i++) {
+    val = (*data) * dry + (-1 - (*data)) * filter->degree;
+    *data++ = (gint16) CLAMP (val, G_MININT16, G_MAXINT16);
+  }
+}
+
+static void
+gst_audio_invert_transform_float (GstAudioInvert * filter,
+    gfloat * data, guint num_samples)
+{
+  gint i;
+  gfloat dry = 1.0 - filter->degree;
+  glong val;
+
+  for (i = 0; i < num_samples; i++) {
+    val = (*data) * dry - (*data) * filter->degree;
+    *data++ = val;
+  }
+}
+
+/* GstBaseTransform vmethod implementations */
+static GstFlowReturn
+gst_audio_invert_transform_ip (GstBaseTransform * base, GstBuffer * buf)
+{
+  GstAudioInvert *filter = GST_AUDIO_INVERT (base);
+  guint num_samples;
+  GstClockTime timestamp, stream_time;
+  GstMapInfo map;
+
+  timestamp = GST_BUFFER_TIMESTAMP (buf);
+  stream_time =
+      gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (filter), stream_time);
+
+  if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)))
+    return GST_FLOW_OK;
+
+  gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+  num_samples = map.size / GST_AUDIO_FILTER_BPS (filter);
+
+  filter->process (filter, map.data, num_samples);
+
+  gst_buffer_unmap (buf, &map);
+
+  return GST_FLOW_OK;
+}
diff --git a/gst/audiofx/audioinvert.h b/gst/audiofx/audioinvert.h
new file mode 100644
index 0000000..cbb5b3f
--- /dev/null
+++ b/gst/audiofx/audioinvert.h
@@ -0,0 +1,60 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ * Copyright (C) 2006 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AUDIO_INVERT_H__
+#define __GST_AUDIO_INVERT_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_AUDIO_INVERT            (gst_audio_invert_get_type())
+#define GST_AUDIO_INVERT(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_INVERT,GstAudioInvert))
+#define GST_IS_AUDIO_INVERT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_INVERT))
+#define GST_AUDIO_INVERT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_INVERT,GstAudioInvertClass))
+#define GST_IS_AUDIO_INVERT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_INVERT))
+#define GST_AUDIO_INVERT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_INVERT,GstAudioInvertClass))
+typedef struct _GstAudioInvert GstAudioInvert;
+typedef struct _GstAudioInvertClass GstAudioInvertClass;
+
+typedef void (*GstAudioInvertProcessFunc) (GstAudioInvert *, guint8 *, guint);
+
+struct _GstAudioInvert
+{
+  GstAudioFilter audiofilter;
+
+  gfloat degree;
+
+  /* < private > */
+  GstAudioInvertProcessFunc process;
+};
+
+struct _GstAudioInvertClass
+{
+  GstAudioFilterClass parent;
+};
+
+GType gst_audio_invert_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_AUDIO_INVERT_H__ */
diff --git a/gst/audiofx/audiokaraoke.c b/gst/audiofx/audiokaraoke.c
new file mode 100644
index 0000000..76697ca
--- /dev/null
+++ b/gst/audiofx/audiokaraoke.c
@@ -0,0 +1,363 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2008 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-audiokaraoke
+ *
+ * Remove the voice from audio by filtering the center channel.
+ * This plugin is useful for karaoke applications.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=song.ogg ! oggdemux ! vorbisdec ! audiokaraoke ! audioconvert ! alsasink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audiokaraoke.h"
+
+#define GST_CAT_DEFAULT gst_audio_karaoke_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+/* Filter signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+#define DEFAULT_LEVEL		1.0
+#define DEFAULT_MONO_LEVEL	1.0
+#define DEFAULT_FILTER_BAND	220.0
+#define DEFAULT_FILTER_WIDTH	100.0
+
+enum
+{
+  PROP_0,
+  PROP_LEVEL,
+  PROP_MONO_LEVEL,
+  PROP_FILTER_BAND,
+  PROP_FILTER_WIDTH
+};
+
+#define ALLOWED_CAPS \
+    "audio/x-raw,"                                                \
+    " format=(string){"GST_AUDIO_NE(S16)","GST_AUDIO_NE(F32)"},"  \
+    " rate=(int)[1,MAX],"                                         \
+    " channels=(int)2,"                                           \
+    " channel-mask=(bitmask)0x3,"                                 \
+    " layout=(string) interleaved"
+
+G_DEFINE_TYPE (GstAudioKaraoke, gst_audio_karaoke, GST_TYPE_AUDIO_FILTER);
+
+static void gst_audio_karaoke_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_audio_karaoke_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_audio_karaoke_setup (GstAudioFilter * filter,
+    const GstAudioInfo * info);
+static GstFlowReturn gst_audio_karaoke_transform_ip (GstBaseTransform * base,
+    GstBuffer * buf);
+
+static void gst_audio_karaoke_transform_int (GstAudioKaraoke * filter,
+    gint16 * data, guint num_samples);
+static void gst_audio_karaoke_transform_float (GstAudioKaraoke * filter,
+    gfloat * data, guint num_samples);
+
+/* GObject vmethod implementations */
+
+static void
+gst_audio_karaoke_class_init (GstAudioKaraokeClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstCaps *caps;
+
+  GST_DEBUG_CATEGORY_INIT (gst_audio_karaoke_debug, "audiokaraoke", 0,
+      "audiokaraoke element");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_audio_karaoke_set_property;
+  gobject_class->get_property = gst_audio_karaoke_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_LEVEL,
+      g_param_spec_float ("level", "Level",
+          "Level of the effect (1.0 = full)", 0.0, 1.0, DEFAULT_LEVEL,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MONO_LEVEL,
+      g_param_spec_float ("mono-level", "Mono Level",
+          "Level of the mono channel (1.0 = full)", 0.0, 1.0, DEFAULT_LEVEL,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_FILTER_BAND,
+      g_param_spec_float ("filter-band", "Filter Band",
+          "The Frequency band of the filter", 0.0, 441.0, DEFAULT_FILTER_BAND,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_FILTER_WIDTH,
+      g_param_spec_float ("filter-width", "Filter Width",
+          "The Frequency width of the filter", 0.0, 100.0, DEFAULT_FILTER_WIDTH,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class, "AudioKaraoke",
+      "Filter/Effect/Audio",
+      "Removes voice from sound", "Wim Taymans <wim.taymans@gmail.com>");
+
+  caps = gst_caps_from_string (ALLOWED_CAPS);
+  gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass),
+      caps);
+  gst_caps_unref (caps);
+
+  GST_BASE_TRANSFORM_CLASS (klass)->transform_ip =
+      GST_DEBUG_FUNCPTR (gst_audio_karaoke_transform_ip);
+  GST_BASE_TRANSFORM_CLASS (klass)->transform_ip_on_passthrough = FALSE;
+
+  GST_AUDIO_FILTER_CLASS (klass)->setup =
+      GST_DEBUG_FUNCPTR (gst_audio_karaoke_setup);
+}
+
+static void
+gst_audio_karaoke_init (GstAudioKaraoke * filter)
+{
+  gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
+  gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE);
+
+  filter->level = DEFAULT_LEVEL;
+  filter->mono_level = DEFAULT_MONO_LEVEL;
+  filter->filter_band = DEFAULT_FILTER_BAND;
+  filter->filter_width = DEFAULT_FILTER_WIDTH;
+}
+
+static void
+update_filter (GstAudioKaraoke * filter, const GstAudioInfo * info)
+{
+  gfloat A, B, C;
+  gint rate;
+
+  if (info) {
+    rate = GST_AUDIO_INFO_RATE (info);
+  } else {
+    rate = GST_AUDIO_FILTER_RATE (filter);
+  }
+
+  if (rate == 0)
+    return;
+
+  C = exp (-2 * G_PI * filter->filter_width / rate);
+  B = -4 * C / (1 + C) * cos (2 * G_PI * filter->filter_band / rate);
+  A = sqrt (1 - B * B / (4 * C)) * (1 - C);
+
+  filter->A = A;
+  filter->B = B;
+  filter->C = C;
+  filter->y1 = 0.0;
+  filter->y2 = 0.0;
+}
+
+static void
+gst_audio_karaoke_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAudioKaraoke *filter;
+
+  filter = GST_AUDIO_KARAOKE (object);
+
+  switch (prop_id) {
+    case PROP_LEVEL:
+      filter->level = g_value_get_float (value);
+      break;
+    case PROP_MONO_LEVEL:
+      filter->mono_level = g_value_get_float (value);
+      break;
+    case PROP_FILTER_BAND:
+      filter->filter_band = g_value_get_float (value);
+      update_filter (filter, NULL);
+      break;
+    case PROP_FILTER_WIDTH:
+      filter->filter_width = g_value_get_float (value);
+      update_filter (filter, NULL);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_audio_karaoke_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAudioKaraoke *filter;
+
+  filter = GST_AUDIO_KARAOKE (object);
+
+  switch (prop_id) {
+    case PROP_LEVEL:
+      g_value_set_float (value, filter->level);
+      break;
+    case PROP_MONO_LEVEL:
+      g_value_set_float (value, filter->mono_level);
+      break;
+    case PROP_FILTER_BAND:
+      g_value_set_float (value, filter->filter_band);
+      break;
+    case PROP_FILTER_WIDTH:
+      g_value_set_float (value, filter->filter_width);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* GstAudioFilter vmethod implementations */
+
+static gboolean
+gst_audio_karaoke_setup (GstAudioFilter * base, const GstAudioInfo * info)
+{
+  GstAudioKaraoke *filter = GST_AUDIO_KARAOKE (base);
+  gboolean ret = TRUE;
+
+  switch (GST_AUDIO_INFO_FORMAT (info)) {
+    case GST_AUDIO_FORMAT_S16:
+      filter->process = (GstAudioKaraokeProcessFunc)
+          gst_audio_karaoke_transform_int;
+      break;
+    case GST_AUDIO_FORMAT_F32:
+      filter->process = (GstAudioKaraokeProcessFunc)
+          gst_audio_karaoke_transform_float;
+      break;
+    default:
+      ret = FALSE;
+      break;
+  }
+  update_filter (filter, info);
+
+  return ret;
+}
+
+static void
+gst_audio_karaoke_transform_int (GstAudioKaraoke * filter,
+    gint16 * data, guint num_samples)
+{
+  gint i, l, r, o, x;
+  gint channels;
+  gdouble y;
+  gint level;
+
+  channels = GST_AUDIO_FILTER_CHANNELS (filter);
+  level = filter->level * 256;
+
+  for (i = 0; i < num_samples; i += channels) {
+    /* get left and right inputs */
+    l = data[i];
+    r = data[i + 1];
+    /* do filtering */
+    x = (l + r) / 2;
+    y = (filter->A * x - filter->B * filter->y1) - filter->C * filter->y2;
+    filter->y2 = filter->y1;
+    filter->y1 = y;
+    /* filter mono signal */
+    o = (int) (y * filter->mono_level);
+    o = CLAMP (o, G_MININT16, G_MAXINT16);
+    o = (o * level) >> 8;
+    /* now cut the center */
+    x = l - ((r * level) >> 8) + o;
+    r = r - ((l * level) >> 8) + o;
+    data[i] = CLAMP (x, G_MININT16, G_MAXINT16);
+    data[i + 1] = CLAMP (r, G_MININT16, G_MAXINT16);
+  }
+}
+
+static void
+gst_audio_karaoke_transform_float (GstAudioKaraoke * filter,
+    gfloat * data, guint num_samples)
+{
+  gint i;
+  gint channels;
+  gdouble l, r, o;
+  gdouble y;
+
+  channels = GST_AUDIO_FILTER_CHANNELS (filter);
+
+  for (i = 0; i < num_samples; i += channels) {
+    /* get left and right inputs */
+    l = data[i];
+    r = data[i + 1];
+    /* do filtering */
+    y = (filter->A * ((l + r) / 2.0) - filter->B * filter->y1) -
+        filter->C * filter->y2;
+    filter->y2 = filter->y1;
+    filter->y1 = y;
+    /* filter mono signal */
+    o = y * filter->mono_level * filter->level;
+    /* now cut the center */
+    data[i] = l - (r * filter->level) + o;
+    data[i + 1] = r - (l * filter->level) + o;
+  }
+}
+
+/* GstBaseTransform vmethod implementations */
+static GstFlowReturn
+gst_audio_karaoke_transform_ip (GstBaseTransform * base, GstBuffer * buf)
+{
+  GstAudioKaraoke *filter = GST_AUDIO_KARAOKE (base);
+  guint num_samples;
+  GstClockTime timestamp, stream_time;
+  GstMapInfo map;
+
+  timestamp = GST_BUFFER_TIMESTAMP (buf);
+  stream_time =
+      gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (filter), stream_time);
+
+  if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)))
+    return GST_FLOW_OK;
+
+  gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+  num_samples = map.size / GST_AUDIO_FILTER_BPS (filter);
+
+  filter->process (filter, map.data, num_samples);
+
+  gst_buffer_unmap (buf, &map);
+
+  return GST_FLOW_OK;
+}
diff --git a/gst/audiofx/audiokaraoke.h b/gst/audiofx/audiokaraoke.h
new file mode 100644
index 0000000..1391efc
--- /dev/null
+++ b/gst/audiofx/audiokaraoke.h
@@ -0,0 +1,67 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2008 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AUDIO_KARAOKE_H__
+#define __GST_AUDIO_KARAOKE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_AUDIO_KARAOKE            (gst_audio_karaoke_get_type())
+#define GST_AUDIO_KARAOKE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_KARAOKE,GstAudioKaraoke))
+#define GST_IS_AUDIO_KARAOKE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_KARAOKE))
+#define GST_AUDIO_KARAOKE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_KARAOKE,GstAudioKaraokeClass))
+#define GST_IS_AUDIO_KARAOKE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_KARAOKE))
+#define GST_AUDIO_KARAOKE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_KARAOKE,GstAudioKaraokeClass))
+typedef struct _GstAudioKaraoke GstAudioKaraoke;
+typedef struct _GstAudioKaraokeClass GstAudioKaraokeClass;
+
+typedef void (*GstAudioKaraokeProcessFunc) (GstAudioKaraoke *, guint8 *, guint);
+
+struct _GstAudioKaraoke
+{
+  GstAudioFilter audiofilter;
+
+  /* properties */
+  gfloat level;
+  gfloat mono_level;
+  gfloat filter_band;
+  gfloat filter_width;
+
+  /* filter coef */
+  gfloat A, B, C;
+  gfloat y1, y2;
+
+  /* < private > */
+  GstAudioKaraokeProcessFunc process;
+};
+
+struct _GstAudioKaraokeClass
+{
+  GstAudioFilterClass parent;
+};
+
+GType gst_audio_karaoke_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_AUDIO_KARAOKE_H__ */
diff --git a/gst/audiofx/audiopanorama.c b/gst/audiofx/audiopanorama.c
new file mode 100644
index 0000000..b901464
--- /dev/null
+++ b/gst/audiofx/audiopanorama.c
@@ -0,0 +1,533 @@
+/*
+ * GStreamer
+ * Copyright (C) 2006 Stefan Kost <ensonic@users.sf.net>
+ * Copyright (C) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-audiopanorama
+ *
+ * Stereo panorama effect with controllable pan position. One can choose between the default psychoacoustic panning method,
+ * which keeps the same perceived loudness, and a simple panning method that just controls the volume on one channel.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc wave=saw ! audiopanorama panorama=-1.00 ! alsasink
+ * gst-launch-1.0 filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiopanorama panorama=-1.00 ! alsasink
+ * gst-launch-1.0 audiotestsrc wave=saw ! audioconvert ! audiopanorama panorama=-1.00 ! audioconvert ! alsasink
+ * gst-launch-1.0 audiotestsrc wave=saw ! audioconvert ! audiopanorama method=simple panorama=-0.50 ! audioconvert ! alsasink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+
+#ifdef HAVE_ORC
+#include <orc/orcfunctions.h>
+#else
+#define orc_memset memset
+#endif
+
+#include "audiopanorama.h"
+#include "audiopanoramaorc.h"
+
+#define GST_CAT_DEFAULT gst_audio_panorama_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+/* Filter signals and args */
+enum
+{
+  PROP_0,
+  PROP_PANORAMA,
+  PROP_METHOD
+};
+
+#define GST_TYPE_AUDIO_PANORAMA_METHOD (gst_audio_panorama_method_get_type ())
+static GType
+gst_audio_panorama_method_get_type (void)
+{
+  static GType gtype = 0;
+
+  if (gtype == 0) {
+    static const GEnumValue values[] = {
+      {METHOD_PSYCHOACOUSTIC, "Psychoacoustic Panning (default)",
+          "psychoacoustic"},
+      {METHOD_SIMPLE, "Simple Panning", "simple"},
+      {0, NULL, NULL}
+    };
+
+    gtype = g_enum_register_static ("GstAudioPanoramaMethod", values);
+  }
+  return gtype;
+}
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) { " GST_AUDIO_NE (F32) ", " GST_AUDIO_NE (S16) "}, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ], "
+        "layout = (string) interleaved")
+    );
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) { " GST_AUDIO_NE (F32) ", " GST_AUDIO_NE (S16) "}, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) 2, "
+        "layout = (string) interleaved")
+    );
+
+G_DEFINE_TYPE (GstAudioPanorama, gst_audio_panorama, GST_TYPE_BASE_TRANSFORM);
+
+static void gst_audio_panorama_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_audio_panorama_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_audio_panorama_get_unit_size (GstBaseTransform * base,
+    GstCaps * caps, gsize * size);
+static GstCaps *gst_audio_panorama_transform_caps (GstBaseTransform * base,
+    GstPadDirection direction, GstCaps * caps, GstCaps * filter);
+static gboolean gst_audio_panorama_set_caps (GstBaseTransform * base,
+    GstCaps * incaps, GstCaps * outcaps);
+
+static void gst_audio_panorama_m2s_int (gfloat pan,
+    gint16 * idata, gint16 * odata, guint num_samples);
+static void gst_audio_panorama_s2s_int (gfloat pan,
+    gint16 * idata, gint16 * odata, guint num_samples);
+static void gst_audio_panorama_m2s_float (gfloat pan,
+    gfloat * idata, gfloat * odata, guint num_samples);
+static void gst_audio_panorama_s2s_float (gfloat pan,
+    gfloat * idata, gfloat * odata, guint num_samples);
+
+static void gst_audio_panorama_m2s_int_simple (gfloat pan,
+    gint16 * idata, gint16 * odata, guint num_samples);
+static void gst_audio_panorama_s2s_int_simple (gfloat pan,
+    gint16 * idata, gint16 * odata, guint num_samples);
+static void gst_audio_panorama_m2s_float_simple (gfloat pan,
+    gfloat * idata, gfloat * odata, guint num_samples);
+static void gst_audio_panorama_s2s_float_simple (gfloat pan,
+    gfloat * idata, gfloat * odata, guint num_samples);
+
+static GstFlowReturn gst_audio_panorama_transform (GstBaseTransform * base,
+    GstBuffer * inbuf, GstBuffer * outbuf);
+
+
+/* Table with processing functions: [channels][format][method] */
+static const GstAudioPanoramaProcessFunc panorama_process_functions[2][2][2] = {
+  {
+        {
+              (GstAudioPanoramaProcessFunc) gst_audio_panorama_m2s_int,
+            (GstAudioPanoramaProcessFunc) gst_audio_panorama_m2s_int_simple},
+        {
+              (GstAudioPanoramaProcessFunc) gst_audio_panorama_m2s_float,
+            (GstAudioPanoramaProcessFunc) gst_audio_panorama_m2s_float_simple}
+      },
+  {
+        {
+              (GstAudioPanoramaProcessFunc) gst_audio_panorama_s2s_int,
+            (GstAudioPanoramaProcessFunc) gst_audio_panorama_s2s_int_simple},
+        {
+              (GstAudioPanoramaProcessFunc) gst_audio_panorama_s2s_float,
+            (GstAudioPanoramaProcessFunc) gst_audio_panorama_s2s_float_simple}
+      }
+};
+
+/* GObject vmethod implementations */
+
+static void
+gst_audio_panorama_class_init (GstAudioPanoramaClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  GST_DEBUG_CATEGORY_INIT (gst_audio_panorama_debug, "audiopanorama", 0,
+      "audiopanorama element");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_audio_panorama_set_property;
+  gobject_class->get_property = gst_audio_panorama_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_PANORAMA,
+      g_param_spec_float ("panorama", "Panorama",
+          "Position in stereo panorama (-1.0 left -> 1.0 right)", -1.0, 1.0,
+          0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstAudioPanorama:method:
+   *
+   * Panning method: psychoacoustic mode keeps the same perceived loudness,
+   * while simple mode just controls the volume of one channel. It's merely
+   * a matter of taste which method should be chosen. 
+   */
+  g_object_class_install_property (gobject_class, PROP_METHOD,
+      g_param_spec_enum ("method", "Panning method",
+          "Psychoacoustic mode keeps same perceived loudness, "
+          "simple mode just controls volume of one channel.",
+          GST_TYPE_AUDIO_PANORAMA_METHOD, METHOD_PSYCHOACOUSTIC,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class, "Stereo positioning",
+      "Filter/Effect/Audio",
+      "Positions audio streams in the stereo panorama",
+      "Stefan Kost <ensonic@users.sf.net>");
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_template);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+
+  GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
+      GST_DEBUG_FUNCPTR (gst_audio_panorama_get_unit_size);
+  GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
+      GST_DEBUG_FUNCPTR (gst_audio_panorama_transform_caps);
+  GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
+      GST_DEBUG_FUNCPTR (gst_audio_panorama_set_caps);
+  GST_BASE_TRANSFORM_CLASS (klass)->transform =
+      GST_DEBUG_FUNCPTR (gst_audio_panorama_transform);
+}
+
+static void
+gst_audio_panorama_init (GstAudioPanorama * filter)
+{
+
+  filter->panorama = 0;
+  filter->method = METHOD_PSYCHOACOUSTIC;
+  gst_audio_info_init (&filter->info);
+  filter->process = NULL;
+
+  gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE);
+}
+
+static gboolean
+gst_audio_panorama_set_process_function (GstAudioPanorama * filter,
+    GstAudioInfo * info)
+{
+  gint channel_index, format_index, method_index;
+  const GstAudioFormatInfo *finfo = info->finfo;
+
+  /* set processing function */
+  channel_index = GST_AUDIO_INFO_CHANNELS (info) - 1;
+  if (channel_index > 1 || channel_index < 0) {
+    filter->process = NULL;
+    return FALSE;
+  }
+
+  format_index = GST_AUDIO_FORMAT_INFO_IS_FLOAT (finfo) ? 1 : 0;
+  method_index = filter->method;
+
+  filter->process =
+      panorama_process_functions[channel_index][format_index][method_index];
+  return TRUE;
+}
+
+static void
+gst_audio_panorama_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAudioPanorama *filter = GST_AUDIO_PANORAMA (object);
+
+  switch (prop_id) {
+    case PROP_PANORAMA:
+      filter->panorama = g_value_get_float (value);
+      break;
+    case PROP_METHOD:
+      filter->method = g_value_get_enum (value);
+      gst_audio_panorama_set_process_function (filter, &filter->info);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_audio_panorama_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAudioPanorama *filter = GST_AUDIO_PANORAMA (object);
+
+  switch (prop_id) {
+    case PROP_PANORAMA:
+      g_value_set_float (value, filter->panorama);
+      break;
+    case PROP_METHOD:
+      g_value_set_enum (value, filter->method);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* GstBaseTransform vmethod implementations */
+
+static gboolean
+gst_audio_panorama_get_unit_size (GstBaseTransform * base, GstCaps * caps,
+    gsize * size)
+{
+  GstAudioInfo info;
+
+  g_assert (size);
+
+  if (!gst_audio_info_from_caps (&info, caps))
+    return FALSE;
+
+  *size = GST_AUDIO_INFO_BPF (&info);
+
+  return TRUE;
+}
+
+static GstCaps *
+gst_audio_panorama_transform_caps (GstBaseTransform * base,
+    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
+{
+  GstCaps *res;
+  GstStructure *structure;
+  gint i;
+
+  /* replace the channel property with our range. */
+  res = gst_caps_copy (caps);
+  for (i = 0; i < gst_caps_get_size (res); i++) {
+    structure = gst_caps_get_structure (res, i);
+    if (direction == GST_PAD_SRC) {
+      GST_INFO_OBJECT (base, "[%d] allow 1-2 channels", i);
+      gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
+    } else {
+      GST_INFO_OBJECT (base, "[%d] allow 2 channels", i);
+      gst_structure_set (structure, "channels", G_TYPE_INT, 2, NULL);
+    }
+    gst_structure_remove_field (structure, "channel-mask");
+  }
+  GST_DEBUG_OBJECT (base, "transformed %" GST_PTR_FORMAT, res);
+
+  if (filter) {
+    GstCaps *intersection;
+
+    GST_DEBUG_OBJECT (base, "Using filter caps %" GST_PTR_FORMAT, filter);
+    intersection =
+        gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (res);
+    res = intersection;
+    GST_DEBUG_OBJECT (base, "Intersection %" GST_PTR_FORMAT, res);
+  }
+
+  return res;
+}
+
+static gboolean
+gst_audio_panorama_set_caps (GstBaseTransform * base, GstCaps * incaps,
+    GstCaps * outcaps)
+{
+  GstAudioPanorama *filter = GST_AUDIO_PANORAMA (base);
+  GstAudioInfo info;
+
+  /*GST_INFO ("incaps are %" GST_PTR_FORMAT, incaps); */
+  if (!gst_audio_info_from_caps (&info, incaps))
+    goto no_format;
+
+  GST_DEBUG ("try to process %d input with %d channels",
+      GST_AUDIO_INFO_FORMAT (&info), GST_AUDIO_INFO_CHANNELS (&info));
+
+  if (!gst_audio_panorama_set_process_function (filter, &info))
+    goto no_format;
+
+  filter->info = info;
+
+  return TRUE;
+
+no_format:
+  {
+    GST_DEBUG ("invalid caps");
+    return FALSE;
+  }
+}
+
+/* psychoacoustic processing functions */
+
+/* mono to stereo panning
+ * pan: -1.0  0.0  1.0
+ * l:    1.0  0.5  0.0  
+ * r:    0.0  0.5  1.0
+ *
+ * FIXME: we should use -3db (1/sqtr(2)) for 50:50
+ */
+static void
+gst_audio_panorama_m2s_int (gfloat pan, gint16 * idata, gint16 * odata, guint n)
+{
+  gfloat r = (pan + 1.0) / 2.0;
+  audiopanoramam_orc_process_s16_ch1_psy (odata, idata, 1.0 - r, r, n);
+}
+
+static void
+gst_audio_panorama_m2s_float (gfloat pan, gfloat * idata,
+    gfloat * odata, guint n)
+{
+  gfloat r = (pan + 1.0) / 2.0;
+  audiopanoramam_orc_process_f32_ch1_psy (odata, idata, 1.0 - r, r, n);
+}
+
+/* stereo balance
+ * pan: -1.0  0.0  1.0
+ * ll:   1.0  1.0  0.0
+ * lr:   1.0  0.0  0.0
+ * rr:   0.0  1.0  1.0
+ * rl:   0.0  0.0  1.0
+ */
+static void
+gst_audio_panorama_s2s_int (gfloat pan, gint16 * idata, gint16 * odata, guint n)
+{
+  if (pan == 0.0) {
+    audiopanoramam_orc_process_s16_ch2_none (odata, idata, n);
+  } else if (pan > 0.0) {
+    gfloat rl = pan;
+    gfloat ll = 1.0 - rl;
+    audiopanoramam_orc_process_s16_ch2_psy_right (odata, idata, ll, rl, n);
+  } else {
+    gfloat rr = 1.0 + pan;
+    gfloat lr = 1.0 - rr;
+    audiopanoramam_orc_process_s16_ch2_psy_left (odata, idata, lr, rr, n);
+  }
+}
+
+static void
+gst_audio_panorama_s2s_float (gfloat pan, gfloat * idata,
+    gfloat * odata, guint n)
+{
+  if (pan == 0.0) {
+    audiopanoramam_orc_process_f32_ch2_none (odata, idata, n);
+  } else if (pan > 0.0) {
+    gfloat rl = pan;
+    gfloat ll = 1.0 - rl;
+    audiopanoramam_orc_process_f32_ch2_psy_right (odata, idata, ll, rl, n);
+  } else {
+    gfloat rr = 1.0 + pan;
+    gfloat lr = 1.0 - rr;
+    audiopanoramam_orc_process_f32_ch2_psy_left (odata, idata, lr, rr, n);
+  }
+}
+
+/* simple processing functions */
+
+static void
+gst_audio_panorama_m2s_int_simple (gfloat pan, gint16 * idata,
+    gint16 * odata, guint n)
+{
+  if (pan == 0.0) {
+    audiopanoramam_orc_process_s16_ch1_none (odata, idata, n);
+  } else if (pan > 0.0) {
+    gfloat lpan = 1.0 - pan;
+    audiopanoramam_orc_process_s16_ch1_sim_left (odata, idata, lpan, n);
+  } else {
+    gfloat rpan = 1.0 + pan;
+    audiopanoramam_orc_process_s16_ch1_sim_right (odata, idata, rpan, n);
+  }
+}
+
+static void
+gst_audio_panorama_s2s_int_simple (gfloat pan, gint16 * idata,
+    gint16 * odata, guint n)
+{
+  if (pan == 0.0) {
+    audiopanoramam_orc_process_s16_ch2_none (odata, idata, n);
+  } else if (pan > 0.0) {
+    gfloat lpan = 1.0 - pan;
+    audiopanoramam_orc_process_s16_ch2_sim_left (odata, idata, lpan, n);
+  } else {
+    gfloat rpan = 1.0 + pan;
+    audiopanoramam_orc_process_s16_ch2_sim_right (odata, idata, rpan, n);
+  }
+}
+
+static void
+gst_audio_panorama_m2s_float_simple (gfloat pan, gfloat * idata,
+    gfloat * odata, guint n)
+{
+  if (pan == 0.0) {
+    audiopanoramam_orc_process_f32_ch1_none (odata, idata, n);
+  } else if (pan > 0.0) {
+    gfloat lpan = 1.0 - pan;
+    audiopanoramam_orc_process_f32_ch1_sim_left (odata, idata, lpan, n);
+  } else {
+    gfloat rpan = 1.0 + pan;
+    audiopanoramam_orc_process_f32_ch1_sim_right (odata, idata, rpan, n);
+  }
+}
+
+static void
+gst_audio_panorama_s2s_float_simple (gfloat pan, gfloat * idata,
+    gfloat * odata, guint n)
+{
+  if (pan == 0.0) {
+    audiopanoramam_orc_process_f32_ch2_none (odata, idata, n);
+  } else if (pan > 0.0) {
+    gfloat lpan = 1.0 - pan;
+    audiopanoramam_orc_process_f32_ch2_sim_left (odata, idata, lpan, n);
+  } else {
+    gfloat rpan = 1.0 + pan;
+    audiopanoramam_orc_process_f32_ch2_sim_right (odata, idata, rpan, n);
+  }
+}
+
+/* this function does the actual processing
+ */
+static GstFlowReturn
+gst_audio_panorama_transform (GstBaseTransform * base, GstBuffer * inbuf,
+    GstBuffer * outbuf)
+{
+  GstAudioPanorama *filter = GST_AUDIO_PANORAMA (base);
+  GstClockTime ts;
+  GstMapInfo inmap, outmap;
+
+  ts = gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME,
+      GST_BUFFER_TIMESTAMP (inbuf));
+
+  if (GST_CLOCK_TIME_IS_VALID (ts)) {
+    GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
+    gst_object_sync_values (GST_OBJECT (filter), ts);
+  }
+
+  gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
+
+  if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP))) {
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
+    orc_memset (outmap.data, 0, outmap.size);
+  } else {
+    /* output is always stereo, input is mono or stereo,
+     * and info describes input format */
+    guint num_samples = outmap.size / (2 * GST_AUDIO_INFO_BPS (&filter->info));
+
+    gst_buffer_map (inbuf, &inmap, GST_MAP_READ);
+    filter->process (filter->panorama, inmap.data, outmap.data, num_samples);
+    gst_buffer_unmap (inbuf, &inmap);
+  }
+
+  gst_buffer_unmap (outbuf, &outmap);
+
+  return GST_FLOW_OK;
+}
diff --git a/gst/audiofx/audiopanorama.h b/gst/audiofx/audiopanorama.h
new file mode 100644
index 0000000..44d1cec
--- /dev/null
+++ b/gst/audiofx/audiopanorama.h
@@ -0,0 +1,68 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2006 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+ 
+#ifndef __GST_AUDIO_PANORAMA_H__
+#define __GST_AUDIO_PANORAMA_H__
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/base/gstbasetransform.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AUDIO_PANORAMA            (gst_audio_panorama_get_type())
+#define GST_AUDIO_PANORAMA(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_PANORAMA,GstAudioPanorama))
+#define GST_IS_AUDIO_PANORAMA(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_PANORAMA))
+#define GST_AUDIO_PANORAMA_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_PANORAMA,GstAudioPanoramaClass))
+#define GST_IS_AUDIO_PANORAMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_PANORAMA))
+#define GST_AUDIO_PANORAMA_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_PANORAMA,GstAudioPanoramaClass))
+
+typedef struct _GstAudioPanorama      GstAudioPanorama;
+typedef struct _GstAudioPanoramaClass GstAudioPanoramaClass;
+
+typedef void (*GstAudioPanoramaProcessFunc)(gfloat, guint8*, guint8*, guint);
+
+typedef enum
+{
+  METHOD_PSYCHOACOUSTIC = 0,
+  METHOD_SIMPLE
+} GstAudioPanoramaMethod;
+
+struct _GstAudioPanorama {
+  GstBaseTransform element;
+
+  /* properties */
+  gfloat panorama;
+  GstAudioPanoramaMethod method;
+
+  /* < private > */
+  GstAudioPanoramaProcessFunc process;
+  GstAudioInfo info;
+};
+
+struct _GstAudioPanoramaClass {
+  GstBaseTransformClass parent_class;
+};
+
+GType gst_audio_panorama_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_AUDIO_PANORAMA_H__ */
diff --git a/gst/audiofx/audiopanoramaorc-dist.c b/gst/audiofx/audiopanoramaorc-dist.c
new file mode 100644
index 0000000..86d6861
--- /dev/null
+++ b/gst/audiofx/audiopanoramaorc-dist.c
@@ -0,0 +1,3977 @@
+
+/* autogenerated from audiopanoramaorc.orc */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <glib.h>
+
+#ifndef _ORC_INTEGER_TYPEDEFS_
+#define _ORC_INTEGER_TYPEDEFS_
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+typedef int8_t orc_int8;
+typedef int16_t orc_int16;
+typedef int32_t orc_int32;
+typedef int64_t orc_int64;
+typedef uint8_t orc_uint8;
+typedef uint16_t orc_uint16;
+typedef uint32_t orc_uint32;
+typedef uint64_t orc_uint64;
+#define ORC_UINT64_C(x) UINT64_C(x)
+#elif defined(_MSC_VER)
+typedef signed __int8 orc_int8;
+typedef signed __int16 orc_int16;
+typedef signed __int32 orc_int32;
+typedef signed __int64 orc_int64;
+typedef unsigned __int8 orc_uint8;
+typedef unsigned __int16 orc_uint16;
+typedef unsigned __int32 orc_uint32;
+typedef unsigned __int64 orc_uint64;
+#define ORC_UINT64_C(x) (x##Ui64)
+#define inline __inline
+#else
+#include <limits.h>
+typedef signed char orc_int8;
+typedef short orc_int16;
+typedef int orc_int32;
+typedef unsigned char orc_uint8;
+typedef unsigned short orc_uint16;
+typedef unsigned int orc_uint32;
+#if INT_MAX == LONG_MAX
+typedef long long orc_int64;
+typedef unsigned long long orc_uint64;
+#define ORC_UINT64_C(x) (x##ULL)
+#else
+typedef long orc_int64;
+typedef unsigned long orc_uint64;
+#define ORC_UINT64_C(x) (x##UL)
+#endif
+#endif
+typedef union
+{
+  orc_int16 i;
+  orc_int8 x2[2];
+} orc_union16;
+typedef union
+{
+  orc_int32 i;
+  float f;
+  orc_int16 x2[2];
+  orc_int8 x4[4];
+} orc_union32;
+typedef union
+{
+  orc_int64 i;
+  double f;
+  orc_int32 x2[2];
+  float x2f[2];
+  orc_int16 x4[4];
+} orc_union64;
+#endif
+#ifndef ORC_RESTRICT
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define ORC_RESTRICT restrict
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define ORC_RESTRICT __restrict__
+#else
+#define ORC_RESTRICT
+#endif
+#endif
+
+#ifndef ORC_INTERNAL
+#if defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#define ORC_INTERNAL __hidden
+#elif defined (__GNUC__)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#else
+#define ORC_INTERNAL
+#endif
+#endif
+
+
+#ifndef DISABLE_ORC
+#include <orc/orc.h>
+#endif
+void audiopanoramam_orc_process_s16_ch1_none (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, int n);
+void audiopanoramam_orc_process_f32_ch1_none (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, int n);
+void audiopanoramam_orc_process_s16_ch2_none (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, int n);
+void audiopanoramam_orc_process_f32_ch2_none (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, int n);
+void audiopanoramam_orc_process_s16_ch1_psy (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, float p2, int n);
+void audiopanoramam_orc_process_f32_ch1_psy (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, float p2, int n);
+void audiopanoramam_orc_process_s16_ch2_psy_right (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, float p2, int n);
+void audiopanoramam_orc_process_s16_ch2_psy_left (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, float p2, int n);
+void audiopanoramam_orc_process_f32_ch2_psy_right (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, float p2, int n);
+void audiopanoramam_orc_process_f32_ch2_psy_left (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, float p2, int n);
+void audiopanoramam_orc_process_s16_ch1_sim_right (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, int n);
+void audiopanoramam_orc_process_s16_ch1_sim_left (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, int n);
+void audiopanoramam_orc_process_s16_ch2_sim_right (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, int n);
+void audiopanoramam_orc_process_s16_ch2_sim_left (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, int n);
+void audiopanoramam_orc_process_f32_ch1_sim_right (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, int n);
+void audiopanoramam_orc_process_f32_ch1_sim_left (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, int n);
+void audiopanoramam_orc_process_f32_ch2_sim_right (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, int n);
+void audiopanoramam_orc_process_f32_ch2_sim_left (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, int n);
+
+
+/* begin Orc C target preamble */
+#define ORC_CLAMP(x,a,b) ((x)<(a) ? (a) : ((x)>(b) ? (b) : (x)))
+#define ORC_ABS(a) ((a)<0 ? -(a) : (a))
+#define ORC_MIN(a,b) ((a)<(b) ? (a) : (b))
+#define ORC_MAX(a,b) ((a)>(b) ? (a) : (b))
+#define ORC_SB_MAX 127
+#define ORC_SB_MIN (-1-ORC_SB_MAX)
+#define ORC_UB_MAX (orc_uint8) 255
+#define ORC_UB_MIN 0
+#define ORC_SW_MAX 32767
+#define ORC_SW_MIN (-1-ORC_SW_MAX)
+#define ORC_UW_MAX (orc_uint16)65535
+#define ORC_UW_MIN 0
+#define ORC_SL_MAX 2147483647
+#define ORC_SL_MIN (-1-ORC_SL_MAX)
+#define ORC_UL_MAX 4294967295U
+#define ORC_UL_MIN 0
+#define ORC_CLAMP_SB(x) ORC_CLAMP(x,ORC_SB_MIN,ORC_SB_MAX)
+#define ORC_CLAMP_UB(x) ORC_CLAMP(x,ORC_UB_MIN,ORC_UB_MAX)
+#define ORC_CLAMP_SW(x) ORC_CLAMP(x,ORC_SW_MIN,ORC_SW_MAX)
+#define ORC_CLAMP_UW(x) ORC_CLAMP(x,ORC_UW_MIN,ORC_UW_MAX)
+#define ORC_CLAMP_SL(x) ORC_CLAMP(x,ORC_SL_MIN,ORC_SL_MAX)
+#define ORC_CLAMP_UL(x) ORC_CLAMP(x,ORC_UL_MIN,ORC_UL_MAX)
+#define ORC_SWAP_W(x) ((((x)&0xffU)<<8) | (((x)&0xff00U)>>8))
+#define ORC_SWAP_L(x) ((((x)&0xffU)<<24) | (((x)&0xff00U)<<8) | (((x)&0xff0000U)>>8) | (((x)&0xff000000U)>>24))
+#define ORC_SWAP_Q(x) ((((x)&ORC_UINT64_C(0xff))<<56) | (((x)&ORC_UINT64_C(0xff00))<<40) | (((x)&ORC_UINT64_C(0xff0000))<<24) | (((x)&ORC_UINT64_C(0xff000000))<<8) | (((x)&ORC_UINT64_C(0xff00000000))>>8) | (((x)&ORC_UINT64_C(0xff0000000000))>>24) | (((x)&ORC_UINT64_C(0xff000000000000))>>40) | (((x)&ORC_UINT64_C(0xff00000000000000))>>56))
+#define ORC_PTR_OFFSET(ptr,offset) ((void *)(((unsigned char *)(ptr)) + (offset)))
+#define ORC_DENORMAL(x) ((x) & ((((x)&0x7f800000) == 0) ? 0xff800000 : 0xffffffff))
+#define ORC_ISNAN(x) ((((x)&0x7f800000) == 0x7f800000) && (((x)&0x007fffff) != 0))
+#define ORC_DENORMAL_DOUBLE(x) ((x) & ((((x)&ORC_UINT64_C(0x7ff0000000000000)) == 0) ? ORC_UINT64_C(0xfff0000000000000) : ORC_UINT64_C(0xffffffffffffffff)))
+#define ORC_ISNAN_DOUBLE(x) ((((x)&ORC_UINT64_C(0x7ff0000000000000)) == ORC_UINT64_C(0x7ff0000000000000)) && (((x)&ORC_UINT64_C(0x000fffffffffffff)) != 0))
+#ifndef ORC_RESTRICT
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define ORC_RESTRICT restrict
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define ORC_RESTRICT __restrict__
+#else
+#define ORC_RESTRICT
+#endif
+#endif
+/* end Orc C target preamble */
+
+
+
+/* audiopanoramam_orc_process_s16_ch1_none */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_s16_ch1_none (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, int n)
+{
+  int i;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union16 *ORC_RESTRICT ptr4;
+  orc_union16 var32;
+  orc_union16 var33;
+  orc_union32 var34;
+
+  ptr0 = (orc_union32 *) d1;
+  ptr4 = (orc_union16 *) s1;
+
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadw */
+    var32 = ptr4[i];
+    /* 1: loadw */
+    var33 = ptr4[i];
+    /* 2: mergewl */
+    {
+      orc_union32 _dest;
+      _dest.x2[0] = var32.i;
+      _dest.x2[1] = var33.i;
+      var34.i = _dest.i;
+    }
+    /* 3: storel */
+    ptr0[i] = var34;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_s16_ch1_none (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union16 *ORC_RESTRICT ptr4;
+  orc_union16 var32;
+  orc_union16 var33;
+  orc_union32 var34;
+
+  ptr0 = (orc_union32 *) ex->arrays[0];
+  ptr4 = (orc_union16 *) ex->arrays[4];
+
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadw */
+    var32 = ptr4[i];
+    /* 1: loadw */
+    var33 = ptr4[i];
+    /* 2: mergewl */
+    {
+      orc_union32 _dest;
+      _dest.x2[0] = var32.i;
+      _dest.x2[1] = var33.i;
+      var34.i = _dest.i;
+    }
+    /* 3: storel */
+    ptr0[i] = var34;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_s16_ch1_none (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 39, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 115,
+        49,
+        54, 95, 99, 104, 49, 95, 110, 111, 110, 101, 11, 4, 4, 12, 2, 2,
+        195, 0, 4, 4, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch1_none);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_s16_ch1_none");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch1_none);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_source (p, 2, "s1");
+
+      orc_program_append_2 (p, "mergewl", 0, ORC_VAR_D1, ORC_VAR_S1, ORC_VAR_S1,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_f32_ch1_none */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_f32_ch1_none (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, int n)
+{
+  int i;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var32;
+  orc_union32 var33;
+  orc_union64 var34;
+
+  ptr0 = (orc_union64 *) d1;
+  ptr4 = (orc_union32 *) s1;
+
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var32 = ptr4[i];
+    /* 1: loadl */
+    var33 = ptr4[i];
+    /* 2: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var32.i;
+      _dest.x2[1] = var33.i;
+      var34.i = _dest.i;
+    }
+    /* 3: storeq */
+    ptr0[i] = var34;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_f32_ch1_none (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var32;
+  orc_union32 var33;
+  orc_union64 var34;
+
+  ptr0 = (orc_union64 *) ex->arrays[0];
+  ptr4 = (orc_union32 *) ex->arrays[4];
+
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var32 = ptr4[i];
+    /* 1: loadl */
+    var33 = ptr4[i];
+    /* 2: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var32.i;
+      _dest.x2[1] = var33.i;
+      var34.i = _dest.i;
+    }
+    /* 3: storeq */
+    ptr0[i] = var34;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_f32_ch1_none (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 39, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 102,
+        51,
+        50, 95, 99, 104, 49, 95, 110, 111, 110, 101, 11, 8, 8, 12, 4, 4,
+        194, 0, 4, 4, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch1_none);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_f32_ch1_none");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch1_none);
+      orc_program_add_destination (p, 8, "d1");
+      orc_program_add_source (p, 4, "s1");
+
+      orc_program_append_2 (p, "mergelq", 0, ORC_VAR_D1, ORC_VAR_S1, ORC_VAR_S1,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_s16_ch2_none */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_s16_ch2_none (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, int n)
+{
+  int i;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var32;
+  orc_union32 var33;
+
+  ptr0 = (orc_union32 *) d1;
+  ptr4 = (orc_union32 *) s1;
+
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var32 = ptr4[i];
+    /* 1: copyw */
+    var33.x2[0] = var32.x2[0];
+    var33.x2[1] = var32.x2[1];
+    /* 2: storel */
+    ptr0[i] = var33;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_s16_ch2_none (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var32;
+  orc_union32 var33;
+
+  ptr0 = (orc_union32 *) ex->arrays[0];
+  ptr4 = (orc_union32 *) ex->arrays[4];
+
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var32 = ptr4[i];
+    /* 1: copyw */
+    var33.x2[0] = var32.x2[0];
+    var33.x2[1] = var32.x2[1];
+    /* 2: storel */
+    ptr0[i] = var33;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_s16_ch2_none (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 39, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 115,
+        49,
+        54, 95, 99, 104, 50, 95, 110, 111, 110, 101, 11, 4, 4, 12, 4, 4,
+        21, 1, 79, 0, 4, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch2_none);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_s16_ch2_none");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch2_none);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_source (p, 4, "s1");
+
+      orc_program_append_2 (p, "copyw", 1, ORC_VAR_D1, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_f32_ch2_none */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_f32_ch2_none (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, int n)
+{
+  int i;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union64 *ORC_RESTRICT ptr4;
+  orc_union64 var32;
+  orc_union64 var33;
+
+  ptr0 = (orc_union64 *) d1;
+  ptr4 = (orc_union64 *) s1;
+
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadq */
+    var32 = ptr4[i];
+    /* 1: copyl */
+    var33.x2[0] = var32.x2[0];
+    var33.x2[1] = var32.x2[1];
+    /* 2: storeq */
+    ptr0[i] = var33;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_f32_ch2_none (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union64 *ORC_RESTRICT ptr4;
+  orc_union64 var32;
+  orc_union64 var33;
+
+  ptr0 = (orc_union64 *) ex->arrays[0];
+  ptr4 = (orc_union64 *) ex->arrays[4];
+
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadq */
+    var32 = ptr4[i];
+    /* 1: copyl */
+    var33.x2[0] = var32.x2[0];
+    var33.x2[1] = var32.x2[1];
+    /* 2: storeq */
+    ptr0[i] = var33;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_f32_ch2_none (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 39, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 102,
+        51,
+        50, 95, 99, 104, 50, 95, 110, 111, 110, 101, 11, 8, 8, 12, 8, 8,
+        21, 1, 112, 0, 4, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch2_none);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_f32_ch2_none");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch2_none);
+      orc_program_add_destination (p, 8, "d1");
+      orc_program_add_source (p, 8, "s1");
+
+      orc_program_append_2 (p, "copyl", 1, ORC_VAR_D1, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_s16_ch1_psy */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_s16_ch1_psy (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, float p2, int n)
+{
+  int i;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union16 *ORC_RESTRICT ptr4;
+  orc_union16 var35;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+  orc_union32 var40;
+  orc_union32 var41;
+  orc_union32 var42;
+  orc_union64 var43;
+  orc_union64 var44;
+
+  ptr0 = (orc_union32 *) d1;
+  ptr4 = (orc_union16 *) s1;
+
+  /* 3: loadpl */
+  var36.f = p2;
+  /* 5: loadpl */
+  var37.f = p1;
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadw */
+    var35 = ptr4[i];
+    /* 1: convswl */
+    var39.i = var35.i;
+    /* 2: convlf */
+    var40.f = var39.i;
+    /* 4: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var40.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var41.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 6: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var40.i);
+      _src2.i = ORC_DENORMAL (var37.i);
+      _dest1.f = _src1.f * _src2.f;
+      var42.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 7: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var42.i;
+      _dest.x2[1] = var41.i;
+      var43.i = _dest.i;
+    }
+    /* 8: convfl */
+    {
+      int tmp;
+      tmp = (int) var43.x2f[0];
+      if (tmp == 0x80000000 && !(var43.x2[0] & 0x80000000))
+        tmp = 0x7fffffff;
+      var44.x2[0] = tmp;
+    }
+    {
+      int tmp;
+      tmp = (int) var43.x2f[1];
+      if (tmp == 0x80000000 && !(var43.x2[1] & 0x80000000))
+        tmp = 0x7fffffff;
+      var44.x2[1] = tmp;
+    }
+    /* 9: convssslw */
+    var38.x2[0] = ORC_CLAMP_SW (var44.x2[0]);
+    var38.x2[1] = ORC_CLAMP_SW (var44.x2[1]);
+    /* 10: storel */
+    ptr0[i] = var38;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_s16_ch1_psy (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union16 *ORC_RESTRICT ptr4;
+  orc_union16 var35;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+  orc_union32 var40;
+  orc_union32 var41;
+  orc_union32 var42;
+  orc_union64 var43;
+  orc_union64 var44;
+
+  ptr0 = (orc_union32 *) ex->arrays[0];
+  ptr4 = (orc_union16 *) ex->arrays[4];
+
+  /* 3: loadpl */
+  var36.i = ex->params[25];
+  /* 5: loadpl */
+  var37.i = ex->params[24];
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadw */
+    var35 = ptr4[i];
+    /* 1: convswl */
+    var39.i = var35.i;
+    /* 2: convlf */
+    var40.f = var39.i;
+    /* 4: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var40.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var41.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 6: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var40.i);
+      _src2.i = ORC_DENORMAL (var37.i);
+      _dest1.f = _src1.f * _src2.f;
+      var42.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 7: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var42.i;
+      _dest.x2[1] = var41.i;
+      var43.i = _dest.i;
+    }
+    /* 8: convfl */
+    {
+      int tmp;
+      tmp = (int) var43.x2f[0];
+      if (tmp == 0x80000000 && !(var43.x2[0] & 0x80000000))
+        tmp = 0x7fffffff;
+      var44.x2[0] = tmp;
+    }
+    {
+      int tmp;
+      tmp = (int) var43.x2f[1];
+      if (tmp == 0x80000000 && !(var43.x2[1] & 0x80000000))
+        tmp = 0x7fffffff;
+      var44.x2[1] = tmp;
+    }
+    /* 9: convssslw */
+    var38.x2[0] = ORC_CLAMP_SW (var44.x2[0]);
+    var38.x2[1] = ORC_CLAMP_SW (var44.x2[1]);
+    /* 10: storel */
+    ptr0[i] = var38;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_s16_ch1_psy (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, float p2, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 38, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 115,
+        49,
+        54, 95, 99, 104, 49, 95, 112, 115, 121, 11, 4, 4, 12, 2, 2, 17,
+        4, 17, 4, 20, 8, 20, 4, 20, 4, 153, 33, 4, 211, 33, 33, 202,
+        34, 33, 25, 202, 33, 33, 24, 194, 32, 33, 34, 21, 1, 210, 32, 32,
+        21, 1, 165, 0, 32, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch1_psy);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_s16_ch1_psy");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch1_psy);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_source (p, 2, "s1");
+      orc_program_add_parameter_float (p, 4, "p1");
+      orc_program_add_parameter_float (p, 4, "p2");
+      orc_program_add_temporary (p, 8, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+      orc_program_add_temporary (p, 4, "t3");
+
+      orc_program_append_2 (p, "convswl", 0, ORC_VAR_T2, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convlf", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T3, ORC_VAR_T2, ORC_VAR_P2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mergelq", 0, ORC_VAR_T1, ORC_VAR_T2, ORC_VAR_T3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convfl", 1, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convssslw", 1, ORC_VAR_D1, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  {
+    orc_union32 tmp;
+    tmp.f = p1;
+    ex->params[ORC_VAR_P1] = tmp.i;
+  }
+  {
+    orc_union32 tmp;
+    tmp.f = p2;
+    ex->params[ORC_VAR_P2] = tmp.i;
+  }
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_f32_ch1_psy */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_f32_ch1_psy (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, float p2, int n)
+{
+  int i;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var34;
+  orc_union32 var35;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union64 var38;
+  orc_union32 var39;
+  orc_union32 var40;
+
+  ptr0 = (orc_union64 *) d1;
+  ptr4 = (orc_union32 *) s1;
+
+  /* 1: loadpl */
+  var35.f = p2;
+  /* 4: loadpl */
+  var37.f = p1;
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var34 = ptr4[i];
+    /* 2: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var34.i);
+      _src2.i = ORC_DENORMAL (var35.i);
+      _dest1.f = _src1.f * _src2.f;
+      var39.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 3: loadl */
+    var36 = ptr4[i];
+    /* 5: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var36.i);
+      _src2.i = ORC_DENORMAL (var37.i);
+      _dest1.f = _src1.f * _src2.f;
+      var40.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 6: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var40.i;
+      _dest.x2[1] = var39.i;
+      var38.i = _dest.i;
+    }
+    /* 7: storeq */
+    ptr0[i] = var38;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_f32_ch1_psy (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var34;
+  orc_union32 var35;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union64 var38;
+  orc_union32 var39;
+  orc_union32 var40;
+
+  ptr0 = (orc_union64 *) ex->arrays[0];
+  ptr4 = (orc_union32 *) ex->arrays[4];
+
+  /* 1: loadpl */
+  var35.i = ex->params[25];
+  /* 4: loadpl */
+  var37.i = ex->params[24];
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var34 = ptr4[i];
+    /* 2: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var34.i);
+      _src2.i = ORC_DENORMAL (var35.i);
+      _dest1.f = _src1.f * _src2.f;
+      var39.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 3: loadl */
+    var36 = ptr4[i];
+    /* 5: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var36.i);
+      _src2.i = ORC_DENORMAL (var37.i);
+      _dest1.f = _src1.f * _src2.f;
+      var40.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 6: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var40.i;
+      _dest.x2[1] = var39.i;
+      var38.i = _dest.i;
+    }
+    /* 7: storeq */
+    ptr0[i] = var38;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_f32_ch1_psy (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, float p2, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 38, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 102,
+        51,
+        50, 95, 99, 104, 49, 95, 112, 115, 121, 11, 8, 8, 12, 4, 4, 17,
+        4, 17, 4, 20, 4, 20, 4, 202, 33, 4, 25, 202, 32, 4, 24, 194,
+        0, 32, 33, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch1_psy);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_f32_ch1_psy");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch1_psy);
+      orc_program_add_destination (p, 8, "d1");
+      orc_program_add_source (p, 4, "s1");
+      orc_program_add_parameter_float (p, 4, "p1");
+      orc_program_add_parameter_float (p, 4, "p2");
+      orc_program_add_temporary (p, 4, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T2, ORC_VAR_S1, ORC_VAR_P2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mergelq", 0, ORC_VAR_D1, ORC_VAR_T1, ORC_VAR_T2,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  {
+    orc_union32 tmp;
+    tmp.f = p1;
+    ex->params[ORC_VAR_P1] = tmp.i;
+  }
+  {
+    orc_union32 tmp;
+    tmp.f = p2;
+    ex->params[ORC_VAR_P2] = tmp.i;
+  }
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_s16_ch2_psy_right */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_s16_ch2_psy_right (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, float p2, int n)
+{
+  int i;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+  orc_union64 var40;
+  orc_union64 var41;
+  orc_union32 var42;
+  orc_union32 var43;
+  orc_union32 var44;
+  orc_union32 var45;
+  orc_union32 var46;
+  orc_union64 var47;
+  orc_union64 var48;
+
+  ptr0 = (orc_union32 *) d1;
+  ptr4 = (orc_union32 *) s1;
+
+  /* 5: loadpl */
+  var37.f = p2;
+  /* 7: loadpl */
+  var38.f = p1;
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var36 = ptr4[i];
+    /* 1: convswl */
+    var40.x2[0] = var36.x2[0];
+    var40.x2[1] = var36.x2[1];
+    /* 2: convlf */
+    var41.x2f[0] = var40.x2[0];
+    var41.x2f[1] = var40.x2[1];
+    /* 3: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var41.i;
+      var42.i = _src.x2[0];
+    }
+    /* 4: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var41.i;
+      var43.i = _src.x2[1];
+    }
+    /* 6: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var42.i);
+      _src2.i = ORC_DENORMAL (var37.i);
+      _dest1.f = _src1.f * _src2.f;
+      var44.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 8: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var42.i);
+      _src2.i = ORC_DENORMAL (var38.i);
+      _dest1.f = _src1.f * _src2.f;
+      var45.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 9: addf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var44.i);
+      _src2.i = ORC_DENORMAL (var43.i);
+      _dest1.f = _src1.f + _src2.f;
+      var46.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 10: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var45.i;
+      _dest.x2[1] = var46.i;
+      var47.i = _dest.i;
+    }
+    /* 11: convfl */
+    {
+      int tmp;
+      tmp = (int) var47.x2f[0];
+      if (tmp == 0x80000000 && !(var47.x2[0] & 0x80000000))
+        tmp = 0x7fffffff;
+      var48.x2[0] = tmp;
+    }
+    {
+      int tmp;
+      tmp = (int) var47.x2f[1];
+      if (tmp == 0x80000000 && !(var47.x2[1] & 0x80000000))
+        tmp = 0x7fffffff;
+      var48.x2[1] = tmp;
+    }
+    /* 12: convssslw */
+    var39.x2[0] = ORC_CLAMP_SW (var48.x2[0]);
+    var39.x2[1] = ORC_CLAMP_SW (var48.x2[1]);
+    /* 13: storel */
+    ptr0[i] = var39;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_s16_ch2_psy_right (OrcExecutor *
+    ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+  orc_union64 var40;
+  orc_union64 var41;
+  orc_union32 var42;
+  orc_union32 var43;
+  orc_union32 var44;
+  orc_union32 var45;
+  orc_union32 var46;
+  orc_union64 var47;
+  orc_union64 var48;
+
+  ptr0 = (orc_union32 *) ex->arrays[0];
+  ptr4 = (orc_union32 *) ex->arrays[4];
+
+  /* 5: loadpl */
+  var37.i = ex->params[25];
+  /* 7: loadpl */
+  var38.i = ex->params[24];
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var36 = ptr4[i];
+    /* 1: convswl */
+    var40.x2[0] = var36.x2[0];
+    var40.x2[1] = var36.x2[1];
+    /* 2: convlf */
+    var41.x2f[0] = var40.x2[0];
+    var41.x2f[1] = var40.x2[1];
+    /* 3: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var41.i;
+      var42.i = _src.x2[0];
+    }
+    /* 4: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var41.i;
+      var43.i = _src.x2[1];
+    }
+    /* 6: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var42.i);
+      _src2.i = ORC_DENORMAL (var37.i);
+      _dest1.f = _src1.f * _src2.f;
+      var44.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 8: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var42.i);
+      _src2.i = ORC_DENORMAL (var38.i);
+      _dest1.f = _src1.f * _src2.f;
+      var45.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 9: addf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var44.i);
+      _src2.i = ORC_DENORMAL (var43.i);
+      _dest1.f = _src1.f + _src2.f;
+      var46.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 10: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var45.i;
+      _dest.x2[1] = var46.i;
+      var47.i = _dest.i;
+    }
+    /* 11: convfl */
+    {
+      int tmp;
+      tmp = (int) var47.x2f[0];
+      if (tmp == 0x80000000 && !(var47.x2[0] & 0x80000000))
+        tmp = 0x7fffffff;
+      var48.x2[0] = tmp;
+    }
+    {
+      int tmp;
+      tmp = (int) var47.x2f[1];
+      if (tmp == 0x80000000 && !(var47.x2[1] & 0x80000000))
+        tmp = 0x7fffffff;
+      var48.x2[1] = tmp;
+    }
+    /* 12: convssslw */
+    var39.x2[0] = ORC_CLAMP_SW (var48.x2[0]);
+    var39.x2[1] = ORC_CLAMP_SW (var48.x2[1]);
+    /* 13: storel */
+    ptr0[i] = var39;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_s16_ch2_psy_right (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, float p2, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 44, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 115,
+        49,
+        54, 95, 99, 104, 50, 95, 112, 115, 121, 95, 114, 105, 103, 104, 116, 11,
+        4, 4, 12, 4, 4, 17, 4, 17, 4, 20, 8, 20, 4, 20, 4, 20,
+        4, 21, 1, 153, 32, 4, 21, 1, 211, 32, 32, 192, 33, 32, 193, 34,
+        32, 202, 35, 33, 25, 202, 33, 33, 24, 200, 34, 35, 34, 194, 32, 33,
+        34, 21, 1, 210, 32, 32, 21, 1, 165, 0, 32, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch2_psy_right);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_s16_ch2_psy_right");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch2_psy_right);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_source (p, 4, "s1");
+      orc_program_add_parameter_float (p, 4, "p1");
+      orc_program_add_parameter_float (p, 4, "p2");
+      orc_program_add_temporary (p, 8, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+      orc_program_add_temporary (p, 4, "t3");
+      orc_program_add_temporary (p, 4, "t4");
+
+      orc_program_append_2 (p, "convswl", 1, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convlf", 1, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "select0ql", 0, ORC_VAR_T2, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "select1ql", 0, ORC_VAR_T3, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T4, ORC_VAR_T2, ORC_VAR_P2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addf", 0, ORC_VAR_T3, ORC_VAR_T4, ORC_VAR_T3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mergelq", 0, ORC_VAR_T1, ORC_VAR_T2, ORC_VAR_T3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convfl", 1, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convssslw", 1, ORC_VAR_D1, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  {
+    orc_union32 tmp;
+    tmp.f = p1;
+    ex->params[ORC_VAR_P1] = tmp.i;
+  }
+  {
+    orc_union32 tmp;
+    tmp.f = p2;
+    ex->params[ORC_VAR_P2] = tmp.i;
+  }
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_s16_ch2_psy_left */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_s16_ch2_psy_left (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, float p2, int n)
+{
+  int i;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+  orc_union64 var40;
+  orc_union64 var41;
+  orc_union32 var42;
+  orc_union32 var43;
+  orc_union32 var44;
+  orc_union32 var45;
+  orc_union32 var46;
+  orc_union64 var47;
+  orc_union64 var48;
+
+  ptr0 = (orc_union32 *) d1;
+  ptr4 = (orc_union32 *) s1;
+
+  /* 5: loadpl */
+  var37.f = p1;
+  /* 7: loadpl */
+  var38.f = p2;
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var36 = ptr4[i];
+    /* 1: convswl */
+    var40.x2[0] = var36.x2[0];
+    var40.x2[1] = var36.x2[1];
+    /* 2: convlf */
+    var41.x2f[0] = var40.x2[0];
+    var41.x2f[1] = var40.x2[1];
+    /* 3: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var41.i;
+      var42.i = _src.x2[0];
+    }
+    /* 4: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var41.i;
+      var43.i = _src.x2[1];
+    }
+    /* 6: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var43.i);
+      _src2.i = ORC_DENORMAL (var37.i);
+      _dest1.f = _src1.f * _src2.f;
+      var44.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 8: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var43.i);
+      _src2.i = ORC_DENORMAL (var38.i);
+      _dest1.f = _src1.f * _src2.f;
+      var45.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 9: addf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var44.i);
+      _src2.i = ORC_DENORMAL (var42.i);
+      _dest1.f = _src1.f + _src2.f;
+      var46.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 10: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var46.i;
+      _dest.x2[1] = var45.i;
+      var47.i = _dest.i;
+    }
+    /* 11: convfl */
+    {
+      int tmp;
+      tmp = (int) var47.x2f[0];
+      if (tmp == 0x80000000 && !(var47.x2[0] & 0x80000000))
+        tmp = 0x7fffffff;
+      var48.x2[0] = tmp;
+    }
+    {
+      int tmp;
+      tmp = (int) var47.x2f[1];
+      if (tmp == 0x80000000 && !(var47.x2[1] & 0x80000000))
+        tmp = 0x7fffffff;
+      var48.x2[1] = tmp;
+    }
+    /* 12: convssslw */
+    var39.x2[0] = ORC_CLAMP_SW (var48.x2[0]);
+    var39.x2[1] = ORC_CLAMP_SW (var48.x2[1]);
+    /* 13: storel */
+    ptr0[i] = var39;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_s16_ch2_psy_left (OrcExecutor *
+    ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+  orc_union64 var40;
+  orc_union64 var41;
+  orc_union32 var42;
+  orc_union32 var43;
+  orc_union32 var44;
+  orc_union32 var45;
+  orc_union32 var46;
+  orc_union64 var47;
+  orc_union64 var48;
+
+  ptr0 = (orc_union32 *) ex->arrays[0];
+  ptr4 = (orc_union32 *) ex->arrays[4];
+
+  /* 5: loadpl */
+  var37.i = ex->params[24];
+  /* 7: loadpl */
+  var38.i = ex->params[25];
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var36 = ptr4[i];
+    /* 1: convswl */
+    var40.x2[0] = var36.x2[0];
+    var40.x2[1] = var36.x2[1];
+    /* 2: convlf */
+    var41.x2f[0] = var40.x2[0];
+    var41.x2f[1] = var40.x2[1];
+    /* 3: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var41.i;
+      var42.i = _src.x2[0];
+    }
+    /* 4: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var41.i;
+      var43.i = _src.x2[1];
+    }
+    /* 6: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var43.i);
+      _src2.i = ORC_DENORMAL (var37.i);
+      _dest1.f = _src1.f * _src2.f;
+      var44.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 8: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var43.i);
+      _src2.i = ORC_DENORMAL (var38.i);
+      _dest1.f = _src1.f * _src2.f;
+      var45.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 9: addf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var44.i);
+      _src2.i = ORC_DENORMAL (var42.i);
+      _dest1.f = _src1.f + _src2.f;
+      var46.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 10: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var46.i;
+      _dest.x2[1] = var45.i;
+      var47.i = _dest.i;
+    }
+    /* 11: convfl */
+    {
+      int tmp;
+      tmp = (int) var47.x2f[0];
+      if (tmp == 0x80000000 && !(var47.x2[0] & 0x80000000))
+        tmp = 0x7fffffff;
+      var48.x2[0] = tmp;
+    }
+    {
+      int tmp;
+      tmp = (int) var47.x2f[1];
+      if (tmp == 0x80000000 && !(var47.x2[1] & 0x80000000))
+        tmp = 0x7fffffff;
+      var48.x2[1] = tmp;
+    }
+    /* 12: convssslw */
+    var39.x2[0] = ORC_CLAMP_SW (var48.x2[0]);
+    var39.x2[1] = ORC_CLAMP_SW (var48.x2[1]);
+    /* 13: storel */
+    ptr0[i] = var39;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_s16_ch2_psy_left (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, float p2, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 43, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 115,
+        49,
+        54, 95, 99, 104, 50, 95, 112, 115, 121, 95, 108, 101, 102, 116, 11, 4,
+        4, 12, 4, 4, 17, 4, 17, 4, 20, 8, 20, 4, 20, 4, 20, 4,
+        21, 1, 153, 32, 4, 21, 1, 211, 32, 32, 192, 33, 32, 193, 35, 32,
+        202, 34, 35, 24, 202, 35, 35, 25, 200, 33, 34, 33, 194, 32, 33, 35,
+        21, 1, 210, 32, 32, 21, 1, 165, 0, 32, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch2_psy_left);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_s16_ch2_psy_left");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch2_psy_left);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_source (p, 4, "s1");
+      orc_program_add_parameter_float (p, 4, "p1");
+      orc_program_add_parameter_float (p, 4, "p2");
+      orc_program_add_temporary (p, 8, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+      orc_program_add_temporary (p, 4, "t3");
+      orc_program_add_temporary (p, 4, "t4");
+
+      orc_program_append_2 (p, "convswl", 1, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convlf", 1, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "select0ql", 0, ORC_VAR_T2, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "select1ql", 0, ORC_VAR_T4, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T3, ORC_VAR_T4, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T4, ORC_VAR_T4, ORC_VAR_P2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addf", 0, ORC_VAR_T2, ORC_VAR_T3, ORC_VAR_T2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mergelq", 0, ORC_VAR_T1, ORC_VAR_T2, ORC_VAR_T4,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convfl", 1, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convssslw", 1, ORC_VAR_D1, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  {
+    orc_union32 tmp;
+    tmp.f = p1;
+    ex->params[ORC_VAR_P1] = tmp.i;
+  }
+  {
+    orc_union32 tmp;
+    tmp.f = p2;
+    ex->params[ORC_VAR_P2] = tmp.i;
+  }
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_f32_ch2_psy_right */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_f32_ch2_psy_right (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, float p2, int n)
+{
+  int i;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union64 *ORC_RESTRICT ptr4;
+  orc_union64 var35;
+  orc_union64 var36;
+  orc_union32 var37;
+  orc_union32 var38;
+  orc_union64 var39;
+  orc_union32 var40;
+  orc_union32 var41;
+  orc_union32 var42;
+  orc_union32 var43;
+  orc_union32 var44;
+
+  ptr0 = (orc_union64 *) d1;
+  ptr4 = (orc_union64 *) s1;
+
+  /* 4: loadpl */
+  var37.f = p2;
+  /* 6: loadpl */
+  var38.f = p1;
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadq */
+    var35 = ptr4[i];
+    /* 1: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var35.i;
+      var40.i = _src.x2[0];
+    }
+    /* 2: loadq */
+    var36 = ptr4[i];
+    /* 3: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var36.i;
+      var41.i = _src.x2[1];
+    }
+    /* 5: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var40.i);
+      _src2.i = ORC_DENORMAL (var37.i);
+      _dest1.f = _src1.f * _src2.f;
+      var42.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 7: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var40.i);
+      _src2.i = ORC_DENORMAL (var38.i);
+      _dest1.f = _src1.f * _src2.f;
+      var43.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 8: addf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var42.i);
+      _src2.i = ORC_DENORMAL (var41.i);
+      _dest1.f = _src1.f + _src2.f;
+      var44.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 9: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var43.i;
+      _dest.x2[1] = var44.i;
+      var39.i = _dest.i;
+    }
+    /* 10: storeq */
+    ptr0[i] = var39;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_f32_ch2_psy_right (OrcExecutor *
+    ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union64 *ORC_RESTRICT ptr4;
+  orc_union64 var35;
+  orc_union64 var36;
+  orc_union32 var37;
+  orc_union32 var38;
+  orc_union64 var39;
+  orc_union32 var40;
+  orc_union32 var41;
+  orc_union32 var42;
+  orc_union32 var43;
+  orc_union32 var44;
+
+  ptr0 = (orc_union64 *) ex->arrays[0];
+  ptr4 = (orc_union64 *) ex->arrays[4];
+
+  /* 4: loadpl */
+  var37.i = ex->params[25];
+  /* 6: loadpl */
+  var38.i = ex->params[24];
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadq */
+    var35 = ptr4[i];
+    /* 1: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var35.i;
+      var40.i = _src.x2[0];
+    }
+    /* 2: loadq */
+    var36 = ptr4[i];
+    /* 3: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var36.i;
+      var41.i = _src.x2[1];
+    }
+    /* 5: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var40.i);
+      _src2.i = ORC_DENORMAL (var37.i);
+      _dest1.f = _src1.f * _src2.f;
+      var42.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 7: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var40.i);
+      _src2.i = ORC_DENORMAL (var38.i);
+      _dest1.f = _src1.f * _src2.f;
+      var43.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 8: addf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var42.i);
+      _src2.i = ORC_DENORMAL (var41.i);
+      _dest1.f = _src1.f + _src2.f;
+      var44.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 9: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var43.i;
+      _dest.x2[1] = var44.i;
+      var39.i = _dest.i;
+    }
+    /* 10: storeq */
+    ptr0[i] = var39;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_f32_ch2_psy_right (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, float p2, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 44, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 102,
+        51,
+        50, 95, 99, 104, 50, 95, 112, 115, 121, 95, 114, 105, 103, 104, 116, 11,
+        8, 8, 12, 8, 8, 17, 4, 17, 4, 20, 4, 20, 4, 20, 4, 192,
+        32, 4, 193, 33, 4, 202, 34, 32, 25, 202, 32, 32, 24, 200, 33, 34,
+        33, 194, 0, 32, 33, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch2_psy_right);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_f32_ch2_psy_right");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch2_psy_right);
+      orc_program_add_destination (p, 8, "d1");
+      orc_program_add_source (p, 8, "s1");
+      orc_program_add_parameter_float (p, 4, "p1");
+      orc_program_add_parameter_float (p, 4, "p2");
+      orc_program_add_temporary (p, 4, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+      orc_program_add_temporary (p, 4, "t3");
+
+      orc_program_append_2 (p, "select0ql", 0, ORC_VAR_T1, ORC_VAR_S1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "select1ql", 0, ORC_VAR_T2, ORC_VAR_S1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T3, ORC_VAR_T1, ORC_VAR_P2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addf", 0, ORC_VAR_T2, ORC_VAR_T3, ORC_VAR_T2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mergelq", 0, ORC_VAR_D1, ORC_VAR_T1, ORC_VAR_T2,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  {
+    orc_union32 tmp;
+    tmp.f = p1;
+    ex->params[ORC_VAR_P1] = tmp.i;
+  }
+  {
+    orc_union32 tmp;
+    tmp.f = p2;
+    ex->params[ORC_VAR_P2] = tmp.i;
+  }
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_f32_ch2_psy_left */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_f32_ch2_psy_left (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, float p2, int n)
+{
+  int i;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union64 *ORC_RESTRICT ptr4;
+  orc_union64 var35;
+  orc_union64 var36;
+  orc_union32 var37;
+  orc_union32 var38;
+  orc_union64 var39;
+  orc_union32 var40;
+  orc_union32 var41;
+  orc_union32 var42;
+  orc_union32 var43;
+  orc_union32 var44;
+
+  ptr0 = (orc_union64 *) d1;
+  ptr4 = (orc_union64 *) s1;
+
+  /* 4: loadpl */
+  var37.f = p1;
+  /* 6: loadpl */
+  var38.f = p2;
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadq */
+    var35 = ptr4[i];
+    /* 1: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var35.i;
+      var40.i = _src.x2[0];
+    }
+    /* 2: loadq */
+    var36 = ptr4[i];
+    /* 3: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var36.i;
+      var41.i = _src.x2[1];
+    }
+    /* 5: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var41.i);
+      _src2.i = ORC_DENORMAL (var37.i);
+      _dest1.f = _src1.f * _src2.f;
+      var42.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 7: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var41.i);
+      _src2.i = ORC_DENORMAL (var38.i);
+      _dest1.f = _src1.f * _src2.f;
+      var43.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 8: addf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var42.i);
+      _src2.i = ORC_DENORMAL (var40.i);
+      _dest1.f = _src1.f + _src2.f;
+      var44.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 9: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var44.i;
+      _dest.x2[1] = var43.i;
+      var39.i = _dest.i;
+    }
+    /* 10: storeq */
+    ptr0[i] = var39;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_f32_ch2_psy_left (OrcExecutor *
+    ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union64 *ORC_RESTRICT ptr4;
+  orc_union64 var35;
+  orc_union64 var36;
+  orc_union32 var37;
+  orc_union32 var38;
+  orc_union64 var39;
+  orc_union32 var40;
+  orc_union32 var41;
+  orc_union32 var42;
+  orc_union32 var43;
+  orc_union32 var44;
+
+  ptr0 = (orc_union64 *) ex->arrays[0];
+  ptr4 = (orc_union64 *) ex->arrays[4];
+
+  /* 4: loadpl */
+  var37.i = ex->params[24];
+  /* 6: loadpl */
+  var38.i = ex->params[25];
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadq */
+    var35 = ptr4[i];
+    /* 1: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var35.i;
+      var40.i = _src.x2[0];
+    }
+    /* 2: loadq */
+    var36 = ptr4[i];
+    /* 3: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var36.i;
+      var41.i = _src.x2[1];
+    }
+    /* 5: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var41.i);
+      _src2.i = ORC_DENORMAL (var37.i);
+      _dest1.f = _src1.f * _src2.f;
+      var42.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 7: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var41.i);
+      _src2.i = ORC_DENORMAL (var38.i);
+      _dest1.f = _src1.f * _src2.f;
+      var43.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 8: addf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var42.i);
+      _src2.i = ORC_DENORMAL (var40.i);
+      _dest1.f = _src1.f + _src2.f;
+      var44.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 9: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var44.i;
+      _dest.x2[1] = var43.i;
+      var39.i = _dest.i;
+    }
+    /* 10: storeq */
+    ptr0[i] = var39;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_f32_ch2_psy_left (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, float p2, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 43, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 102,
+        51,
+        50, 95, 99, 104, 50, 95, 112, 115, 121, 95, 108, 101, 102, 116, 11, 8,
+        8, 12, 8, 8, 17, 4, 17, 4, 20, 4, 20, 4, 20, 4, 192, 32,
+        4, 193, 34, 4, 202, 33, 34, 24, 202, 34, 34, 25, 200, 32, 33, 32,
+        194, 0, 32, 34, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch2_psy_left);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_f32_ch2_psy_left");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch2_psy_left);
+      orc_program_add_destination (p, 8, "d1");
+      orc_program_add_source (p, 8, "s1");
+      orc_program_add_parameter_float (p, 4, "p1");
+      orc_program_add_parameter_float (p, 4, "p2");
+      orc_program_add_temporary (p, 4, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+      orc_program_add_temporary (p, 4, "t3");
+
+      orc_program_append_2 (p, "select0ql", 0, ORC_VAR_T1, ORC_VAR_S1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "select1ql", 0, ORC_VAR_T3, ORC_VAR_S1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T2, ORC_VAR_T3, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T3, ORC_VAR_T3, ORC_VAR_P2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addf", 0, ORC_VAR_T1, ORC_VAR_T2, ORC_VAR_T1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mergelq", 0, ORC_VAR_D1, ORC_VAR_T1, ORC_VAR_T3,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  {
+    orc_union32 tmp;
+    tmp.f = p1;
+    ex->params[ORC_VAR_P1] = tmp.i;
+  }
+  {
+    orc_union32 tmp;
+    tmp.f = p2;
+    ex->params[ORC_VAR_P2] = tmp.i;
+  }
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_s16_ch1_sim_right */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_s16_ch1_sim_right (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, int n)
+{
+  int i;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union16 *ORC_RESTRICT ptr4;
+  orc_union16 var35;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+  orc_union32 var40;
+  orc_union64 var41;
+  orc_union64 var42;
+
+  ptr0 = (orc_union32 *) d1;
+  ptr4 = (orc_union16 *) s1;
+
+  /* 3: loadpl */
+  var36.f = p1;
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadw */
+    var35 = ptr4[i];
+    /* 1: convswl */
+    var38.i = var35.i;
+    /* 2: convlf */
+    var39.f = var38.i;
+    /* 4: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var39.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var40.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 5: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var39.i;
+      _dest.x2[1] = var40.i;
+      var41.i = _dest.i;
+    }
+    /* 6: convfl */
+    {
+      int tmp;
+      tmp = (int) var41.x2f[0];
+      if (tmp == 0x80000000 && !(var41.x2[0] & 0x80000000))
+        tmp = 0x7fffffff;
+      var42.x2[0] = tmp;
+    }
+    {
+      int tmp;
+      tmp = (int) var41.x2f[1];
+      if (tmp == 0x80000000 && !(var41.x2[1] & 0x80000000))
+        tmp = 0x7fffffff;
+      var42.x2[1] = tmp;
+    }
+    /* 7: convssslw */
+    var37.x2[0] = ORC_CLAMP_SW (var42.x2[0]);
+    var37.x2[1] = ORC_CLAMP_SW (var42.x2[1]);
+    /* 8: storel */
+    ptr0[i] = var37;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_s16_ch1_sim_right (OrcExecutor *
+    ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union16 *ORC_RESTRICT ptr4;
+  orc_union16 var35;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+  orc_union32 var40;
+  orc_union64 var41;
+  orc_union64 var42;
+
+  ptr0 = (orc_union32 *) ex->arrays[0];
+  ptr4 = (orc_union16 *) ex->arrays[4];
+
+  /* 3: loadpl */
+  var36.i = ex->params[24];
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadw */
+    var35 = ptr4[i];
+    /* 1: convswl */
+    var38.i = var35.i;
+    /* 2: convlf */
+    var39.f = var38.i;
+    /* 4: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var39.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var40.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 5: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var39.i;
+      _dest.x2[1] = var40.i;
+      var41.i = _dest.i;
+    }
+    /* 6: convfl */
+    {
+      int tmp;
+      tmp = (int) var41.x2f[0];
+      if (tmp == 0x80000000 && !(var41.x2[0] & 0x80000000))
+        tmp = 0x7fffffff;
+      var42.x2[0] = tmp;
+    }
+    {
+      int tmp;
+      tmp = (int) var41.x2f[1];
+      if (tmp == 0x80000000 && !(var41.x2[1] & 0x80000000))
+        tmp = 0x7fffffff;
+      var42.x2[1] = tmp;
+    }
+    /* 7: convssslw */
+    var37.x2[0] = ORC_CLAMP_SW (var42.x2[0]);
+    var37.x2[1] = ORC_CLAMP_SW (var42.x2[1]);
+    /* 8: storel */
+    ptr0[i] = var37;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_s16_ch1_sim_right (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 44, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 115,
+        49,
+        54, 95, 99, 104, 49, 95, 115, 105, 109, 95, 114, 105, 103, 104, 116, 11,
+        4, 4, 12, 2, 2, 17, 4, 20, 8, 20, 4, 20, 4, 153, 33, 4,
+        211, 33, 33, 202, 34, 33, 24, 194, 32, 33, 34, 21, 1, 210, 32, 32,
+        21, 1, 165, 0, 32, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch1_sim_right);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_s16_ch1_sim_right");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch1_sim_right);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_source (p, 2, "s1");
+      orc_program_add_parameter_float (p, 4, "p1");
+      orc_program_add_temporary (p, 8, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+      orc_program_add_temporary (p, 4, "t3");
+
+      orc_program_append_2 (p, "convswl", 0, ORC_VAR_T2, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convlf", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T3, ORC_VAR_T2, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mergelq", 0, ORC_VAR_T1, ORC_VAR_T2, ORC_VAR_T3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convfl", 1, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convssslw", 1, ORC_VAR_D1, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  {
+    orc_union32 tmp;
+    tmp.f = p1;
+    ex->params[ORC_VAR_P1] = tmp.i;
+  }
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_s16_ch1_sim_left */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_s16_ch1_sim_left (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, int n)
+{
+  int i;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union16 *ORC_RESTRICT ptr4;
+  orc_union16 var35;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+  orc_union32 var40;
+  orc_union64 var41;
+  orc_union64 var42;
+
+  ptr0 = (orc_union32 *) d1;
+  ptr4 = (orc_union16 *) s1;
+
+  /* 3: loadpl */
+  var36.f = p1;
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadw */
+    var35 = ptr4[i];
+    /* 1: convswl */
+    var38.i = var35.i;
+    /* 2: convlf */
+    var39.f = var38.i;
+    /* 4: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var39.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var40.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 5: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var40.i;
+      _dest.x2[1] = var39.i;
+      var41.i = _dest.i;
+    }
+    /* 6: convfl */
+    {
+      int tmp;
+      tmp = (int) var41.x2f[0];
+      if (tmp == 0x80000000 && !(var41.x2[0] & 0x80000000))
+        tmp = 0x7fffffff;
+      var42.x2[0] = tmp;
+    }
+    {
+      int tmp;
+      tmp = (int) var41.x2f[1];
+      if (tmp == 0x80000000 && !(var41.x2[1] & 0x80000000))
+        tmp = 0x7fffffff;
+      var42.x2[1] = tmp;
+    }
+    /* 7: convssslw */
+    var37.x2[0] = ORC_CLAMP_SW (var42.x2[0]);
+    var37.x2[1] = ORC_CLAMP_SW (var42.x2[1]);
+    /* 8: storel */
+    ptr0[i] = var37;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_s16_ch1_sim_left (OrcExecutor *
+    ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union16 *ORC_RESTRICT ptr4;
+  orc_union16 var35;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+  orc_union32 var40;
+  orc_union64 var41;
+  orc_union64 var42;
+
+  ptr0 = (orc_union32 *) ex->arrays[0];
+  ptr4 = (orc_union16 *) ex->arrays[4];
+
+  /* 3: loadpl */
+  var36.i = ex->params[24];
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadw */
+    var35 = ptr4[i];
+    /* 1: convswl */
+    var38.i = var35.i;
+    /* 2: convlf */
+    var39.f = var38.i;
+    /* 4: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var39.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var40.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 5: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var40.i;
+      _dest.x2[1] = var39.i;
+      var41.i = _dest.i;
+    }
+    /* 6: convfl */
+    {
+      int tmp;
+      tmp = (int) var41.x2f[0];
+      if (tmp == 0x80000000 && !(var41.x2[0] & 0x80000000))
+        tmp = 0x7fffffff;
+      var42.x2[0] = tmp;
+    }
+    {
+      int tmp;
+      tmp = (int) var41.x2f[1];
+      if (tmp == 0x80000000 && !(var41.x2[1] & 0x80000000))
+        tmp = 0x7fffffff;
+      var42.x2[1] = tmp;
+    }
+    /* 7: convssslw */
+    var37.x2[0] = ORC_CLAMP_SW (var42.x2[0]);
+    var37.x2[1] = ORC_CLAMP_SW (var42.x2[1]);
+    /* 8: storel */
+    ptr0[i] = var37;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_s16_ch1_sim_left (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 43, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 115,
+        49,
+        54, 95, 99, 104, 49, 95, 115, 105, 109, 95, 108, 101, 102, 116, 11, 4,
+        4, 12, 2, 2, 17, 4, 20, 8, 20, 4, 20, 4, 153, 34, 4, 211,
+        34, 34, 202, 33, 34, 24, 194, 32, 33, 34, 21, 1, 210, 32, 32, 21,
+        1, 165, 0, 32, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch1_sim_left);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_s16_ch1_sim_left");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch1_sim_left);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_source (p, 2, "s1");
+      orc_program_add_parameter_float (p, 4, "p1");
+      orc_program_add_temporary (p, 8, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+      orc_program_add_temporary (p, 4, "t3");
+
+      orc_program_append_2 (p, "convswl", 0, ORC_VAR_T3, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convlf", 0, ORC_VAR_T3, ORC_VAR_T3, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T2, ORC_VAR_T3, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mergelq", 0, ORC_VAR_T1, ORC_VAR_T2, ORC_VAR_T3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convfl", 1, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convssslw", 1, ORC_VAR_D1, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  {
+    orc_union32 tmp;
+    tmp.f = p1;
+    ex->params[ORC_VAR_P1] = tmp.i;
+  }
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_s16_ch2_sim_right */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_s16_ch2_sim_right (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, int n)
+{
+  int i;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var35;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union64 var38;
+  orc_union64 var39;
+  orc_union32 var40;
+  orc_union32 var41;
+  orc_union32 var42;
+  orc_union64 var43;
+  orc_union64 var44;
+
+  ptr0 = (orc_union32 *) d1;
+  ptr4 = (orc_union32 *) s1;
+
+  /* 5: loadpl */
+  var36.f = p1;
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var35 = ptr4[i];
+    /* 1: convswl */
+    var38.x2[0] = var35.x2[0];
+    var38.x2[1] = var35.x2[1];
+    /* 2: convlf */
+    var39.x2f[0] = var38.x2[0];
+    var39.x2f[1] = var38.x2[1];
+    /* 3: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var39.i;
+      var40.i = _src.x2[0];
+    }
+    /* 4: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var39.i;
+      var41.i = _src.x2[1];
+    }
+    /* 6: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var41.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var42.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 7: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var40.i;
+      _dest.x2[1] = var42.i;
+      var43.i = _dest.i;
+    }
+    /* 8: convfl */
+    {
+      int tmp;
+      tmp = (int) var43.x2f[0];
+      if (tmp == 0x80000000 && !(var43.x2[0] & 0x80000000))
+        tmp = 0x7fffffff;
+      var44.x2[0] = tmp;
+    }
+    {
+      int tmp;
+      tmp = (int) var43.x2f[1];
+      if (tmp == 0x80000000 && !(var43.x2[1] & 0x80000000))
+        tmp = 0x7fffffff;
+      var44.x2[1] = tmp;
+    }
+    /* 9: convssslw */
+    var37.x2[0] = ORC_CLAMP_SW (var44.x2[0]);
+    var37.x2[1] = ORC_CLAMP_SW (var44.x2[1]);
+    /* 10: storel */
+    ptr0[i] = var37;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_s16_ch2_sim_right (OrcExecutor *
+    ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var35;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union64 var38;
+  orc_union64 var39;
+  orc_union32 var40;
+  orc_union32 var41;
+  orc_union32 var42;
+  orc_union64 var43;
+  orc_union64 var44;
+
+  ptr0 = (orc_union32 *) ex->arrays[0];
+  ptr4 = (orc_union32 *) ex->arrays[4];
+
+  /* 5: loadpl */
+  var36.i = ex->params[24];
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var35 = ptr4[i];
+    /* 1: convswl */
+    var38.x2[0] = var35.x2[0];
+    var38.x2[1] = var35.x2[1];
+    /* 2: convlf */
+    var39.x2f[0] = var38.x2[0];
+    var39.x2f[1] = var38.x2[1];
+    /* 3: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var39.i;
+      var40.i = _src.x2[0];
+    }
+    /* 4: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var39.i;
+      var41.i = _src.x2[1];
+    }
+    /* 6: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var41.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var42.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 7: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var40.i;
+      _dest.x2[1] = var42.i;
+      var43.i = _dest.i;
+    }
+    /* 8: convfl */
+    {
+      int tmp;
+      tmp = (int) var43.x2f[0];
+      if (tmp == 0x80000000 && !(var43.x2[0] & 0x80000000))
+        tmp = 0x7fffffff;
+      var44.x2[0] = tmp;
+    }
+    {
+      int tmp;
+      tmp = (int) var43.x2f[1];
+      if (tmp == 0x80000000 && !(var43.x2[1] & 0x80000000))
+        tmp = 0x7fffffff;
+      var44.x2[1] = tmp;
+    }
+    /* 9: convssslw */
+    var37.x2[0] = ORC_CLAMP_SW (var44.x2[0]);
+    var37.x2[1] = ORC_CLAMP_SW (var44.x2[1]);
+    /* 10: storel */
+    ptr0[i] = var37;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_s16_ch2_sim_right (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 44, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 115,
+        49,
+        54, 95, 99, 104, 50, 95, 115, 105, 109, 95, 114, 105, 103, 104, 116, 11,
+        4, 4, 12, 4, 4, 17, 4, 20, 8, 20, 4, 20, 4, 21, 1, 153,
+        32, 4, 21, 1, 211, 32, 32, 192, 33, 32, 193, 34, 32, 202, 34, 34,
+        24, 194, 32, 33, 34, 21, 1, 210, 32, 32, 21, 1, 165, 0, 32, 2,
+        0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch2_sim_right);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_s16_ch2_sim_right");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch2_sim_right);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_source (p, 4, "s1");
+      orc_program_add_parameter_float (p, 4, "p1");
+      orc_program_add_temporary (p, 8, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+      orc_program_add_temporary (p, 4, "t3");
+
+      orc_program_append_2 (p, "convswl", 1, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convlf", 1, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "select0ql", 0, ORC_VAR_T2, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "select1ql", 0, ORC_VAR_T3, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T3, ORC_VAR_T3, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mergelq", 0, ORC_VAR_T1, ORC_VAR_T2, ORC_VAR_T3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convfl", 1, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convssslw", 1, ORC_VAR_D1, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  {
+    orc_union32 tmp;
+    tmp.f = p1;
+    ex->params[ORC_VAR_P1] = tmp.i;
+  }
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_s16_ch2_sim_left */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_s16_ch2_sim_left (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, int n)
+{
+  int i;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var35;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union64 var38;
+  orc_union64 var39;
+  orc_union32 var40;
+  orc_union32 var41;
+  orc_union32 var42;
+  orc_union64 var43;
+  orc_union64 var44;
+
+  ptr0 = (orc_union32 *) d1;
+  ptr4 = (orc_union32 *) s1;
+
+  /* 5: loadpl */
+  var36.f = p1;
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var35 = ptr4[i];
+    /* 1: convswl */
+    var38.x2[0] = var35.x2[0];
+    var38.x2[1] = var35.x2[1];
+    /* 2: convlf */
+    var39.x2f[0] = var38.x2[0];
+    var39.x2f[1] = var38.x2[1];
+    /* 3: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var39.i;
+      var40.i = _src.x2[0];
+    }
+    /* 4: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var39.i;
+      var41.i = _src.x2[1];
+    }
+    /* 6: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var40.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var42.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 7: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var42.i;
+      _dest.x2[1] = var41.i;
+      var43.i = _dest.i;
+    }
+    /* 8: convfl */
+    {
+      int tmp;
+      tmp = (int) var43.x2f[0];
+      if (tmp == 0x80000000 && !(var43.x2[0] & 0x80000000))
+        tmp = 0x7fffffff;
+      var44.x2[0] = tmp;
+    }
+    {
+      int tmp;
+      tmp = (int) var43.x2f[1];
+      if (tmp == 0x80000000 && !(var43.x2[1] & 0x80000000))
+        tmp = 0x7fffffff;
+      var44.x2[1] = tmp;
+    }
+    /* 9: convssslw */
+    var37.x2[0] = ORC_CLAMP_SW (var44.x2[0]);
+    var37.x2[1] = ORC_CLAMP_SW (var44.x2[1]);
+    /* 10: storel */
+    ptr0[i] = var37;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_s16_ch2_sim_left (OrcExecutor *
+    ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var35;
+  orc_union32 var36;
+  orc_union32 var37;
+  orc_union64 var38;
+  orc_union64 var39;
+  orc_union32 var40;
+  orc_union32 var41;
+  orc_union32 var42;
+  orc_union64 var43;
+  orc_union64 var44;
+
+  ptr0 = (orc_union32 *) ex->arrays[0];
+  ptr4 = (orc_union32 *) ex->arrays[4];
+
+  /* 5: loadpl */
+  var36.i = ex->params[24];
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var35 = ptr4[i];
+    /* 1: convswl */
+    var38.x2[0] = var35.x2[0];
+    var38.x2[1] = var35.x2[1];
+    /* 2: convlf */
+    var39.x2f[0] = var38.x2[0];
+    var39.x2f[1] = var38.x2[1];
+    /* 3: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var39.i;
+      var40.i = _src.x2[0];
+    }
+    /* 4: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var39.i;
+      var41.i = _src.x2[1];
+    }
+    /* 6: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var40.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var42.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 7: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var42.i;
+      _dest.x2[1] = var41.i;
+      var43.i = _dest.i;
+    }
+    /* 8: convfl */
+    {
+      int tmp;
+      tmp = (int) var43.x2f[0];
+      if (tmp == 0x80000000 && !(var43.x2[0] & 0x80000000))
+        tmp = 0x7fffffff;
+      var44.x2[0] = tmp;
+    }
+    {
+      int tmp;
+      tmp = (int) var43.x2f[1];
+      if (tmp == 0x80000000 && !(var43.x2[1] & 0x80000000))
+        tmp = 0x7fffffff;
+      var44.x2[1] = tmp;
+    }
+    /* 9: convssslw */
+    var37.x2[0] = ORC_CLAMP_SW (var44.x2[0]);
+    var37.x2[1] = ORC_CLAMP_SW (var44.x2[1]);
+    /* 10: storel */
+    ptr0[i] = var37;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_s16_ch2_sim_left (gint16 * ORC_RESTRICT d1,
+    const gint16 * ORC_RESTRICT s1, float p1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 43, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 115,
+        49,
+        54, 95, 99, 104, 50, 95, 115, 105, 109, 95, 108, 101, 102, 116, 11, 4,
+        4, 12, 4, 4, 17, 4, 20, 8, 20, 4, 20, 4, 21, 1, 153, 32,
+        4, 21, 1, 211, 32, 32, 192, 33, 32, 193, 34, 32, 202, 33, 33, 24,
+        194, 32, 33, 34, 21, 1, 210, 32, 32, 21, 1, 165, 0, 32, 2, 0,
+
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch2_sim_left);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_s16_ch2_sim_left");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_s16_ch2_sim_left);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_source (p, 4, "s1");
+      orc_program_add_parameter_float (p, 4, "p1");
+      orc_program_add_temporary (p, 8, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+      orc_program_add_temporary (p, 4, "t3");
+
+      orc_program_append_2 (p, "convswl", 1, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convlf", 1, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "select0ql", 0, ORC_VAR_T2, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "select1ql", 0, ORC_VAR_T3, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mergelq", 0, ORC_VAR_T1, ORC_VAR_T2, ORC_VAR_T3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convfl", 1, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convssslw", 1, ORC_VAR_D1, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  {
+    orc_union32 tmp;
+    tmp.f = p1;
+    ex->params[ORC_VAR_P1] = tmp.i;
+  }
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_f32_ch1_sim_right */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_f32_ch1_sim_right (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, int n)
+{
+  int i;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var34;
+  orc_union32 var35;
+  orc_union32 var36;
+  orc_union64 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+
+  ptr0 = (orc_union64 *) d1;
+  ptr4 = (orc_union32 *) s1;
+
+  /* 3: loadpl */
+  var36.f = p1;
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var34 = ptr4[i];
+    /* 1: copyl */
+    var38.i = var34.i;
+    /* 2: loadl */
+    var35 = ptr4[i];
+    /* 4: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var35.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var39.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 5: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var38.i;
+      _dest.x2[1] = var39.i;
+      var37.i = _dest.i;
+    }
+    /* 6: storeq */
+    ptr0[i] = var37;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_f32_ch1_sim_right (OrcExecutor *
+    ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var34;
+  orc_union32 var35;
+  orc_union32 var36;
+  orc_union64 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+
+  ptr0 = (orc_union64 *) ex->arrays[0];
+  ptr4 = (orc_union32 *) ex->arrays[4];
+
+  /* 3: loadpl */
+  var36.i = ex->params[24];
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var34 = ptr4[i];
+    /* 1: copyl */
+    var38.i = var34.i;
+    /* 2: loadl */
+    var35 = ptr4[i];
+    /* 4: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var35.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var39.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 5: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var38.i;
+      _dest.x2[1] = var39.i;
+      var37.i = _dest.i;
+    }
+    /* 6: storeq */
+    ptr0[i] = var37;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_f32_ch1_sim_right (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 44, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 102,
+        51,
+        50, 95, 99, 104, 49, 95, 115, 105, 109, 95, 114, 105, 103, 104, 116, 11,
+        8, 8, 12, 4, 4, 17, 4, 20, 4, 20, 4, 112, 32, 4, 202, 33,
+        4, 24, 194, 0, 32, 33, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch1_sim_right);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_f32_ch1_sim_right");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch1_sim_right);
+      orc_program_add_destination (p, 8, "d1");
+      orc_program_add_source (p, 4, "s1");
+      orc_program_add_parameter_float (p, 4, "p1");
+      orc_program_add_temporary (p, 4, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+
+      orc_program_append_2 (p, "copyl", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T2, ORC_VAR_S1, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mergelq", 0, ORC_VAR_D1, ORC_VAR_T1, ORC_VAR_T2,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  {
+    orc_union32 tmp;
+    tmp.f = p1;
+    ex->params[ORC_VAR_P1] = tmp.i;
+  }
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_f32_ch1_sim_left */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_f32_ch1_sim_left (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, int n)
+{
+  int i;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var34;
+  orc_union32 var35;
+  orc_union32 var36;
+  orc_union64 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+
+  ptr0 = (orc_union64 *) d1;
+  ptr4 = (orc_union32 *) s1;
+
+  /* 1: loadpl */
+  var35.f = p1;
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var34 = ptr4[i];
+    /* 2: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var34.i);
+      _src2.i = ORC_DENORMAL (var35.i);
+      _dest1.f = _src1.f * _src2.f;
+      var38.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 3: loadl */
+    var36 = ptr4[i];
+    /* 4: copyl */
+    var39.i = var36.i;
+    /* 5: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var38.i;
+      _dest.x2[1] = var39.i;
+      var37.i = _dest.i;
+    }
+    /* 6: storeq */
+    ptr0[i] = var37;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_f32_ch1_sim_left (OrcExecutor *
+    ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var34;
+  orc_union32 var35;
+  orc_union32 var36;
+  orc_union64 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+
+  ptr0 = (orc_union64 *) ex->arrays[0];
+  ptr4 = (orc_union32 *) ex->arrays[4];
+
+  /* 1: loadpl */
+  var35.i = ex->params[24];
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var34 = ptr4[i];
+    /* 2: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var34.i);
+      _src2.i = ORC_DENORMAL (var35.i);
+      _dest1.f = _src1.f * _src2.f;
+      var38.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 3: loadl */
+    var36 = ptr4[i];
+    /* 4: copyl */
+    var39.i = var36.i;
+    /* 5: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var38.i;
+      _dest.x2[1] = var39.i;
+      var37.i = _dest.i;
+    }
+    /* 6: storeq */
+    ptr0[i] = var37;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_f32_ch1_sim_left (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 43, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 102,
+        51,
+        50, 95, 99, 104, 49, 95, 115, 105, 109, 95, 108, 101, 102, 116, 11, 8,
+        8, 12, 4, 4, 17, 4, 20, 4, 20, 4, 202, 32, 4, 24, 112, 33,
+        4, 194, 0, 32, 33, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch1_sim_left);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_f32_ch1_sim_left");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch1_sim_left);
+      orc_program_add_destination (p, 8, "d1");
+      orc_program_add_source (p, 4, "s1");
+      orc_program_add_parameter_float (p, 4, "p1");
+      orc_program_add_temporary (p, 4, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "copyl", 0, ORC_VAR_T2, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mergelq", 0, ORC_VAR_D1, ORC_VAR_T1, ORC_VAR_T2,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  {
+    orc_union32 tmp;
+    tmp.f = p1;
+    ex->params[ORC_VAR_P1] = tmp.i;
+  }
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_f32_ch2_sim_right */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_f32_ch2_sim_right (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, int n)
+{
+  int i;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union64 *ORC_RESTRICT ptr4;
+  orc_union64 var34;
+  orc_union64 var35;
+  orc_union32 var36;
+  orc_union64 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+  orc_union32 var40;
+
+  ptr0 = (orc_union64 *) d1;
+  ptr4 = (orc_union64 *) s1;
+
+  /* 4: loadpl */
+  var36.f = p1;
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadq */
+    var34 = ptr4[i];
+    /* 1: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var34.i;
+      var38.i = _src.x2[0];
+    }
+    /* 2: loadq */
+    var35 = ptr4[i];
+    /* 3: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var35.i;
+      var39.i = _src.x2[1];
+    }
+    /* 5: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var39.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var40.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 6: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var38.i;
+      _dest.x2[1] = var40.i;
+      var37.i = _dest.i;
+    }
+    /* 7: storeq */
+    ptr0[i] = var37;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_f32_ch2_sim_right (OrcExecutor *
+    ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union64 *ORC_RESTRICT ptr4;
+  orc_union64 var34;
+  orc_union64 var35;
+  orc_union32 var36;
+  orc_union64 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+  orc_union32 var40;
+
+  ptr0 = (orc_union64 *) ex->arrays[0];
+  ptr4 = (orc_union64 *) ex->arrays[4];
+
+  /* 4: loadpl */
+  var36.i = ex->params[24];
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadq */
+    var34 = ptr4[i];
+    /* 1: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var34.i;
+      var38.i = _src.x2[0];
+    }
+    /* 2: loadq */
+    var35 = ptr4[i];
+    /* 3: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var35.i;
+      var39.i = _src.x2[1];
+    }
+    /* 5: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var39.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var40.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 6: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var38.i;
+      _dest.x2[1] = var40.i;
+      var37.i = _dest.i;
+    }
+    /* 7: storeq */
+    ptr0[i] = var37;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_f32_ch2_sim_right (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 44, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 102,
+        51,
+        50, 95, 99, 104, 50, 95, 115, 105, 109, 95, 114, 105, 103, 104, 116, 11,
+        8, 8, 12, 8, 8, 17, 4, 20, 4, 20, 4, 192, 32, 4, 193, 33,
+        4, 202, 33, 33, 24, 194, 0, 32, 33, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch2_sim_right);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_f32_ch2_sim_right");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch2_sim_right);
+      orc_program_add_destination (p, 8, "d1");
+      orc_program_add_source (p, 8, "s1");
+      orc_program_add_parameter_float (p, 4, "p1");
+      orc_program_add_temporary (p, 4, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+
+      orc_program_append_2 (p, "select0ql", 0, ORC_VAR_T1, ORC_VAR_S1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "select1ql", 0, ORC_VAR_T2, ORC_VAR_S1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mergelq", 0, ORC_VAR_D1, ORC_VAR_T1, ORC_VAR_T2,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  {
+    orc_union32 tmp;
+    tmp.f = p1;
+    ex->params[ORC_VAR_P1] = tmp.i;
+  }
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* audiopanoramam_orc_process_f32_ch2_sim_left */
+#ifdef DISABLE_ORC
+void
+audiopanoramam_orc_process_f32_ch2_sim_left (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, int n)
+{
+  int i;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union64 *ORC_RESTRICT ptr4;
+  orc_union64 var34;
+  orc_union64 var35;
+  orc_union32 var36;
+  orc_union64 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+  orc_union32 var40;
+
+  ptr0 = (orc_union64 *) d1;
+  ptr4 = (orc_union64 *) s1;
+
+  /* 4: loadpl */
+  var36.f = p1;
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadq */
+    var34 = ptr4[i];
+    /* 1: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var34.i;
+      var38.i = _src.x2[0];
+    }
+    /* 2: loadq */
+    var35 = ptr4[i];
+    /* 3: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var35.i;
+      var39.i = _src.x2[1];
+    }
+    /* 5: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var38.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var40.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 6: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var40.i;
+      _dest.x2[1] = var39.i;
+      var37.i = _dest.i;
+    }
+    /* 7: storeq */
+    ptr0[i] = var37;
+  }
+
+}
+
+#else
+static void
+_backup_audiopanoramam_orc_process_f32_ch2_sim_left (OrcExecutor *
+    ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union64 *ORC_RESTRICT ptr0;
+  const orc_union64 *ORC_RESTRICT ptr4;
+  orc_union64 var34;
+  orc_union64 var35;
+  orc_union32 var36;
+  orc_union64 var37;
+  orc_union32 var38;
+  orc_union32 var39;
+  orc_union32 var40;
+
+  ptr0 = (orc_union64 *) ex->arrays[0];
+  ptr4 = (orc_union64 *) ex->arrays[4];
+
+  /* 4: loadpl */
+  var36.i = ex->params[24];
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadq */
+    var34 = ptr4[i];
+    /* 1: select0ql */
+    {
+      orc_union64 _src;
+      _src.i = var34.i;
+      var38.i = _src.x2[0];
+    }
+    /* 2: loadq */
+    var35 = ptr4[i];
+    /* 3: select1ql */
+    {
+      orc_union64 _src;
+      _src.i = var35.i;
+      var39.i = _src.x2[1];
+    }
+    /* 5: mulf */
+    {
+      orc_union32 _src1;
+      orc_union32 _src2;
+      orc_union32 _dest1;
+      _src1.i = ORC_DENORMAL (var38.i);
+      _src2.i = ORC_DENORMAL (var36.i);
+      _dest1.f = _src1.f * _src2.f;
+      var40.i = ORC_DENORMAL (_dest1.i);
+    }
+    /* 6: mergelq */
+    {
+      orc_union64 _dest;
+      _dest.x2[0] = var40.i;
+      _dest.x2[1] = var39.i;
+      var37.i = _dest.i;
+    }
+    /* 7: storeq */
+    ptr0[i] = var37;
+  }
+
+}
+
+void
+audiopanoramam_orc_process_f32_ch2_sim_left (gfloat * ORC_RESTRICT d1,
+    const gfloat * ORC_RESTRICT s1, float p1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 43, 97, 117, 100, 105, 111, 112, 97, 110, 111, 114, 97, 109, 97,
+        109, 95, 111, 114, 99, 95, 112, 114, 111, 99, 101, 115, 115, 95, 102,
+        51,
+        50, 95, 99, 104, 50, 95, 115, 105, 109, 95, 108, 101, 102, 116, 11, 8,
+        8, 12, 8, 8, 17, 4, 20, 4, 20, 4, 192, 32, 4, 193, 33, 4,
+        202, 32, 32, 24, 194, 0, 32, 33, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch2_sim_left);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "audiopanoramam_orc_process_f32_ch2_sim_left");
+      orc_program_set_backup_function (p,
+          _backup_audiopanoramam_orc_process_f32_ch2_sim_left);
+      orc_program_add_destination (p, 8, "d1");
+      orc_program_add_source (p, 8, "s1");
+      orc_program_add_parameter_float (p, 4, "p1");
+      orc_program_add_temporary (p, 4, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+
+      orc_program_append_2 (p, "select0ql", 0, ORC_VAR_T1, ORC_VAR_S1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "select1ql", 0, ORC_VAR_T2, ORC_VAR_S1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "mulf", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mergelq", 0, ORC_VAR_D1, ORC_VAR_T1, ORC_VAR_T2,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  {
+    orc_union32 tmp;
+    tmp.f = p1;
+    ex->params[ORC_VAR_P1] = tmp.i;
+  }
+
+  func = c->exec;
+  func (ex);
+}
+#endif
diff --git a/gst/audiofx/audiopanoramaorc-dist.h b/gst/audiofx/audiopanoramaorc-dist.h
new file mode 100644
index 0000000..7611fba
--- /dev/null
+++ b/gst/audiofx/audiopanoramaorc-dist.h
@@ -0,0 +1,107 @@
+
+/* autogenerated from audiopanoramaorc.orc */
+
+#ifndef _AUDIOPANORAMAORC_H_
+#define _AUDIOPANORAMAORC_H_
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#ifndef _ORC_INTEGER_TYPEDEFS_
+#define _ORC_INTEGER_TYPEDEFS_
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+typedef int8_t orc_int8;
+typedef int16_t orc_int16;
+typedef int32_t orc_int32;
+typedef int64_t orc_int64;
+typedef uint8_t orc_uint8;
+typedef uint16_t orc_uint16;
+typedef uint32_t orc_uint32;
+typedef uint64_t orc_uint64;
+#define ORC_UINT64_C(x) UINT64_C(x)
+#elif defined(_MSC_VER)
+typedef signed __int8 orc_int8;
+typedef signed __int16 orc_int16;
+typedef signed __int32 orc_int32;
+typedef signed __int64 orc_int64;
+typedef unsigned __int8 orc_uint8;
+typedef unsigned __int16 orc_uint16;
+typedef unsigned __int32 orc_uint32;
+typedef unsigned __int64 orc_uint64;
+#define ORC_UINT64_C(x) (x##Ui64)
+#define inline __inline
+#else
+#include <limits.h>
+typedef signed char orc_int8;
+typedef short orc_int16;
+typedef int orc_int32;
+typedef unsigned char orc_uint8;
+typedef unsigned short orc_uint16;
+typedef unsigned int orc_uint32;
+#if INT_MAX == LONG_MAX
+typedef long long orc_int64;
+typedef unsigned long long orc_uint64;
+#define ORC_UINT64_C(x) (x##ULL)
+#else
+typedef long orc_int64;
+typedef unsigned long orc_uint64;
+#define ORC_UINT64_C(x) (x##UL)
+#endif
+#endif
+typedef union { orc_int16 i; orc_int8 x2[2]; } orc_union16;
+typedef union { orc_int32 i; float f; orc_int16 x2[2]; orc_int8 x4[4]; } orc_union32;
+typedef union { orc_int64 i; double f; orc_int32 x2[2]; float x2f[2]; orc_int16 x4[4]; } orc_union64;
+#endif
+#ifndef ORC_RESTRICT
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define ORC_RESTRICT restrict
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define ORC_RESTRICT __restrict__
+#else
+#define ORC_RESTRICT
+#endif
+#endif
+
+#ifndef ORC_INTERNAL
+#if defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#define ORC_INTERNAL __hidden
+#elif defined (__GNUC__)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#else
+#define ORC_INTERNAL
+#endif
+#endif
+
+void audiopanoramam_orc_process_s16_ch1_none (gint16 * ORC_RESTRICT d1, const gint16 * ORC_RESTRICT s1, int n);
+void audiopanoramam_orc_process_f32_ch1_none (gfloat * ORC_RESTRICT d1, const gfloat * ORC_RESTRICT s1, int n);
+void audiopanoramam_orc_process_s16_ch2_none (gint16 * ORC_RESTRICT d1, const gint16 * ORC_RESTRICT s1, int n);
+void audiopanoramam_orc_process_f32_ch2_none (gfloat * ORC_RESTRICT d1, const gfloat * ORC_RESTRICT s1, int n);
+void audiopanoramam_orc_process_s16_ch1_psy (gint16 * ORC_RESTRICT d1, const gint16 * ORC_RESTRICT s1, float p1, float p2, int n);
+void audiopanoramam_orc_process_f32_ch1_psy (gfloat * ORC_RESTRICT d1, const gfloat * ORC_RESTRICT s1, float p1, float p2, int n);
+void audiopanoramam_orc_process_s16_ch2_psy_right (gint16 * ORC_RESTRICT d1, const gint16 * ORC_RESTRICT s1, float p1, float p2, int n);
+void audiopanoramam_orc_process_s16_ch2_psy_left (gint16 * ORC_RESTRICT d1, const gint16 * ORC_RESTRICT s1, float p1, float p2, int n);
+void audiopanoramam_orc_process_f32_ch2_psy_right (gfloat * ORC_RESTRICT d1, const gfloat * ORC_RESTRICT s1, float p1, float p2, int n);
+void audiopanoramam_orc_process_f32_ch2_psy_left (gfloat * ORC_RESTRICT d1, const gfloat * ORC_RESTRICT s1, float p1, float p2, int n);
+void audiopanoramam_orc_process_s16_ch1_sim_right (gint16 * ORC_RESTRICT d1, const gint16 * ORC_RESTRICT s1, float p1, int n);
+void audiopanoramam_orc_process_s16_ch1_sim_left (gint16 * ORC_RESTRICT d1, const gint16 * ORC_RESTRICT s1, float p1, int n);
+void audiopanoramam_orc_process_s16_ch2_sim_right (gint16 * ORC_RESTRICT d1, const gint16 * ORC_RESTRICT s1, float p1, int n);
+void audiopanoramam_orc_process_s16_ch2_sim_left (gint16 * ORC_RESTRICT d1, const gint16 * ORC_RESTRICT s1, float p1, int n);
+void audiopanoramam_orc_process_f32_ch1_sim_right (gfloat * ORC_RESTRICT d1, const gfloat * ORC_RESTRICT s1, float p1, int n);
+void audiopanoramam_orc_process_f32_ch1_sim_left (gfloat * ORC_RESTRICT d1, const gfloat * ORC_RESTRICT s1, float p1, int n);
+void audiopanoramam_orc_process_f32_ch2_sim_right (gfloat * ORC_RESTRICT d1, const gfloat * ORC_RESTRICT s1, float p1, int n);
+void audiopanoramam_orc_process_f32_ch2_sim_left (gfloat * ORC_RESTRICT d1, const gfloat * ORC_RESTRICT s1, float p1, int n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/gst/audiofx/audiopanoramaorc.orc b/gst/audiofx/audiopanoramaorc.orc
new file mode 100644
index 0000000..4614011
--- /dev/null
+++ b/gst/audiofx/audiopanoramaorc.orc
@@ -0,0 +1,258 @@
+# pass through functions
+
+.function audiopanoramam_orc_process_s16_ch1_none
+.source 2 s1 gint16
+.dest 4 d1 gint16
+
+mergewl d1 s1 s1
+
+
+.function audiopanoramam_orc_process_f32_ch1_none
+.source 4 s1 gfloat
+.dest 8 d1 gfloat
+
+mergelq d1 s1 s1
+
+
+.function audiopanoramam_orc_process_s16_ch2_none
+.source 4 s1 gint16
+.dest 4 d1 gint16
+
+x2 copyw d1 s1
+
+
+.function audiopanoramam_orc_process_f32_ch2_none
+.source 8 s1 gfloat
+.dest 8 d1 gfloat
+
+x2 copyl d1 s1
+
+
+# psychoacoustic processing function
+
+.function audiopanoramam_orc_process_s16_ch1_psy
+.source 2 s1 gint16
+.dest 4 d1 gint16
+.floatparam 4 lpan
+.floatparam 4 rpan
+.temp 8 t1
+.temp 4 left
+.temp 4 right
+
+convswl left s1
+convlf left left
+mulf right left rpan
+mulf left left lpan
+mergelq t1 left right
+x2 convfl t1 t1
+x2 convssslw d1 t1
+
+
+.function audiopanoramam_orc_process_f32_ch1_psy
+.source 4 s1 gfloat
+.dest 8 d1 gfloat
+.floatparam 4 lpan
+.floatparam 4 rpan
+.temp 4 left
+.temp 4 right
+
+mulf right s1 rpan
+mulf left s1 lpan
+mergelq d1 left right
+
+
+.function audiopanoramam_orc_process_s16_ch2_psy_right
+.source 4 s1 gint16
+.dest 4 d1 gint16
+.floatparam 4 llpan
+.floatparam 4 rlpan
+.temp 8 t1
+.temp 4 left
+.temp 4 right
+.temp 4 right1
+
+x2 convswl t1 s1
+x2 convlf t1 t1
+select0ql left t1
+select1ql right t1
+mulf right1 left rlpan
+mulf left left llpan
+addf right right1 right
+mergelq t1 left right
+x2 convfl t1 t1
+x2 convssslw d1 t1
+
+
+.function audiopanoramam_orc_process_s16_ch2_psy_left
+.source 4 s1 gint16
+.dest 4 d1 gint16
+.floatparam 4 lrpan
+.floatparam 4 rrpan
+.temp 8 t1
+.temp 4 left
+.temp 4 left1
+.temp 4 right
+
+x2 convswl t1 s1
+x2 convlf t1 t1
+select0ql left t1
+select1ql right t1
+mulf left1 right lrpan
+mulf right right rrpan
+addf left left1 left
+mergelq t1 left right
+x2 convfl t1 t1
+x2 convssslw d1 t1
+
+
+.function audiopanoramam_orc_process_f32_ch2_psy_right
+.source 8 s1 gfloat
+.dest 8 d1 gfloat
+.floatparam 4 llpan
+.floatparam 4 rlpan
+.temp 4 left
+.temp 4 right
+.temp 4 right1
+
+select0ql left s1
+select1ql right s1
+mulf right1 left rlpan
+mulf left left llpan
+addf right right1 right
+mergelq d1 left right
+
+
+.function audiopanoramam_orc_process_f32_ch2_psy_left
+.source 8 s1 gfloat
+.dest 8 d1 gfloat
+.floatparam 4 lrpan
+.floatparam 4 rrpan
+.temp 4 left
+.temp 4 left1
+.temp 4 right
+
+select0ql left s1
+select1ql right s1
+mulf left1 right lrpan
+mulf right right rrpan
+addf left left1 left
+mergelq d1 left right
+
+# simple processing functions
+
+.function audiopanoramam_orc_process_s16_ch1_sim_right
+.source 2 s1 gint16
+.dest 4 d1 gint16
+.floatparam 4 rpan
+.temp 8 t1
+.temp 4 left
+.temp 4 right
+
+convswl left s1
+convlf left left
+mulf right left rpan
+mergelq t1 left right
+x2 convfl t1 t1
+x2 convssslw d1 t1
+
+
+.function audiopanoramam_orc_process_s16_ch1_sim_left
+.source 2 s1 gint16
+.dest 4 d1 gint16
+.floatparam 4 lpan
+.temp 8 t1
+.temp 4 left
+.temp 4 right
+
+convswl right s1
+convlf right right
+mulf left right lpan
+mergelq t1 left right
+x2 convfl t1 t1
+x2 convssslw d1 t1
+
+
+.function audiopanoramam_orc_process_s16_ch2_sim_right
+.source 4 s1 gint16
+.dest 4 d1 gint16
+.floatparam 4 rpan
+.temp 8 t1
+.temp 4 left
+.temp 4 right
+
+x2 convswl t1 s1
+x2 convlf t1 t1
+select0ql left t1
+select1ql right t1
+mulf right right rpan
+mergelq t1 left right
+x2 convfl t1 t1
+x2 convssslw d1 t1
+
+
+.function audiopanoramam_orc_process_s16_ch2_sim_left
+.source 4 s1 gint16
+.dest 4 d1 gint16
+.floatparam 4 lpan
+.temp 8 t1
+.temp 4 left
+.temp 4 right
+
+x2 convswl t1 s1
+x2 convlf t1 t1
+select0ql left t1
+select1ql right t1
+mulf left left lpan
+mergelq t1 left right
+x2 convfl t1 t1
+x2 convssslw d1 t1
+
+
+.function audiopanoramam_orc_process_f32_ch1_sim_right
+.source 4 s1 gfloat
+.dest 8 d1 gfloat
+.floatparam 4 rpan
+.temp 4 left
+.temp 4 right
+
+copyl left s1
+mulf right s1 rpan
+mergelq d1 left right
+
+
+.function audiopanoramam_orc_process_f32_ch1_sim_left
+.source 4 s1 gfloat
+.dest 8 d1 gfloat
+.floatparam 4 lpan
+.temp 4 left
+.temp 4 right
+
+mulf left s1 lpan
+copyl right s1
+mergelq d1 left right
+
+
+.function audiopanoramam_orc_process_f32_ch2_sim_right
+.source 8 s1 gfloat
+.dest 8 d1 gfloat
+.floatparam 4 rpan
+.temp 4 left
+.temp 4 right
+
+select0ql left s1
+select1ql right s1
+mulf right right rpan
+mergelq d1 left right
+
+.function audiopanoramam_orc_process_f32_ch2_sim_left
+.source 8 s1 gfloat
+.dest 8 d1 gfloat
+.floatparam 4 lpan
+.temp 4 left
+.temp 4 right
+
+select0ql left s1
+select1ql right s1
+mulf left left lpan
+mergelq d1 left right
+
diff --git a/gst/audiofx/audiowsincband.c b/gst/audiofx/audiowsincband.c
new file mode 100644
index 0000000..3a66d41
--- /dev/null
+++ b/gst/audiofx/audiowsincband.c
@@ -0,0 +1,482 @@
+/* -*- c-basic-offset: 2 -*-
+ * 
+ * GStreamer
+ * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2006 Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>
+ *               2007-2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * 
+ * 
+ * this windowed sinc filter is taken from the freely downloadable DSP book,
+ * "The Scientist and Engineer's Guide to Digital Signal Processing",
+ * chapter 16
+ * available at http://www.dspguide.com/
+ *
+ * For the window functions see
+ * http://en.wikipedia.org/wiki/Window_function
+ */
+
+/**
+ * SECTION:element-audiowsincband
+ *
+ * Attenuates all frequencies outside (bandpass) or inside (bandreject) of a frequency
+ * band. The length parameter controls the rolloff, the window parameter
+ * controls rolloff and stopband attenuation. The Hamming window provides a faster rolloff but a bit
+ * worse stopband attenuation, the other way around for the Blackman window.
+ *
+ * This element has the advantage over the Chebyshev bandpass and bandreject filter that it has
+ * a much better rolloff when using a larger kernel size and almost linear phase. The only
+ * disadvantage is the much slower execution time with larger kernels.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc freq=1500 ! audioconvert ! audiowsincband mode=band-pass lower-frequency=3000 upper-frequency=10000 length=501 window=blackman ! audioconvert ! alsasink
+ * gst-launch-1.0 filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiowsincband mode=band-reject lower-frequency=59 upper-frequency=61 length=10001 window=hamming ! audioconvert ! alsasink
+ * gst-launch-1.0 audiotestsrc wave=white-noise ! audioconvert ! audiowsincband mode=band-pass lower-frequency=1000 upper-frequency=2000 length=31 ! audioconvert ! alsasink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <gst/gst.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audiowsincband.h"
+
+#include "gst/glib-compat-private.h"
+
+#define GST_CAT_DEFAULT gst_gst_audio_wsincband_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+enum
+{
+  PROP_0,
+  PROP_LENGTH,
+  PROP_LOWER_FREQUENCY,
+  PROP_UPPER_FREQUENCY,
+  PROP_MODE,
+  PROP_WINDOW
+};
+
+enum
+{
+  MODE_BAND_PASS = 0,
+  MODE_BAND_REJECT
+};
+
+#define GST_TYPE_AUDIO_WSINC_BAND_MODE (gst_gst_audio_wsincband_mode_get_type ())
+static GType
+gst_gst_audio_wsincband_mode_get_type (void)
+{
+  static GType gtype = 0;
+
+  if (gtype == 0) {
+    static const GEnumValue values[] = {
+      {MODE_BAND_PASS, "Band pass (default)",
+          "band-pass"},
+      {MODE_BAND_REJECT, "Band reject",
+          "band-reject"},
+      {0, NULL, NULL}
+    };
+
+    gtype = g_enum_register_static ("GstAudioWSincBandMode", values);
+  }
+  return gtype;
+}
+
+enum
+{
+  WINDOW_HAMMING = 0,
+  WINDOW_BLACKMAN,
+  WINDOW_GAUSSIAN,
+  WINDOW_COSINE,
+  WINDOW_HANN
+};
+
+#define GST_TYPE_AUDIO_WSINC_BAND_WINDOW (gst_gst_audio_wsincband_window_get_type ())
+static GType
+gst_gst_audio_wsincband_window_get_type (void)
+{
+  static GType gtype = 0;
+
+  if (gtype == 0) {
+    static const GEnumValue values[] = {
+      {WINDOW_HAMMING, "Hamming window (default)",
+          "hamming"},
+      {WINDOW_BLACKMAN, "Blackman window",
+          "blackman"},
+      {WINDOW_GAUSSIAN, "Gaussian window",
+          "gaussian"},
+      {WINDOW_COSINE, "Cosine window",
+          "cosine"},
+      {WINDOW_HANN, "Hann window",
+          "hann"},
+      {0, NULL, NULL}
+    };
+
+    gtype = g_enum_register_static ("GstAudioWSincBandWindow", values);
+  }
+  return gtype;
+}
+
+#define gst_audio_wsincband_parent_class parent_class
+G_DEFINE_TYPE (GstAudioWSincBand, gst_audio_wsincband,
+    GST_TYPE_AUDIO_FX_BASE_FIR_FILTER);
+
+static void gst_audio_wsincband_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_audio_wsincband_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_audio_wsincband_finalize (GObject * object);
+
+static gboolean gst_audio_wsincband_setup (GstAudioFilter * base,
+    const GstAudioInfo * info);
+
+#define POW2(x)  (x)*(x)
+
+static void
+gst_audio_wsincband_class_init (GstAudioWSincBandClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (gst_gst_audio_wsincband_debug, "audiowsincband", 0,
+      "Band-pass and Band-reject Windowed sinc filter plugin");
+
+  gobject_class->set_property = gst_audio_wsincband_set_property;
+  gobject_class->get_property = gst_audio_wsincband_get_property;
+  gobject_class->finalize = gst_audio_wsincband_finalize;
+
+  /* FIXME: Don't use the complete possible range but restrict the upper boundary
+   * so automatically generated UIs can use a slider */
+  g_object_class_install_property (gobject_class, PROP_LOWER_FREQUENCY,
+      g_param_spec_float ("lower-frequency", "Lower Frequency",
+          "Cut-off lower frequency (Hz)", 0.0, 100000.0, 0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_UPPER_FREQUENCY,
+      g_param_spec_float ("upper-frequency", "Upper Frequency",
+          "Cut-off upper frequency (Hz)", 0.0, 100000.0, 0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_LENGTH,
+      g_param_spec_int ("length", "Length",
+          "Filter kernel length, will be rounded to the next odd number", 3,
+          256000, 101,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MODE,
+      g_param_spec_enum ("mode", "Mode",
+          "Band pass or band reject mode", GST_TYPE_AUDIO_WSINC_BAND_MODE,
+          MODE_BAND_PASS,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_WINDOW,
+      g_param_spec_enum ("window", "Window",
+          "Window function to use", GST_TYPE_AUDIO_WSINC_BAND_WINDOW,
+          WINDOW_HAMMING,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Band pass & band reject filter", "Filter/Effect/Audio",
+      "Band pass and band reject windowed sinc filter",
+      "Thomas Vander Stichele <thomas at apestaart dot org>, "
+      "Steven W. Smith, "
+      "Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>, "
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_wsincband_setup);
+}
+
+static void
+gst_audio_wsincband_init (GstAudioWSincBand * self)
+{
+  self->kernel_length = 101;
+  self->lower_frequency = 0.0;
+  self->upper_frequency = 0.0;
+  self->mode = MODE_BAND_PASS;
+  self->window = WINDOW_HAMMING;
+
+  g_mutex_init (&self->lock);
+}
+
+static void
+gst_audio_wsincband_build_kernel (GstAudioWSincBand * self,
+    const GstAudioInfo * info)
+{
+  gint i = 0;
+  gdouble sum = 0.0;
+  gint len = 0;
+  gdouble *kernel_lp, *kernel_hp;
+  gdouble w;
+  gdouble *kernel;
+  gint rate, channels;
+
+  len = self->kernel_length;
+
+  if (info) {
+    rate = GST_AUDIO_INFO_RATE (info);
+    channels = GST_AUDIO_INFO_CHANNELS (info);
+  } else {
+    rate = GST_AUDIO_FILTER_RATE (self);
+    channels = GST_AUDIO_FILTER_CHANNELS (self);
+  }
+
+  if (rate == 0) {
+    GST_DEBUG ("rate not set yet");
+    return;
+  }
+
+  if (channels == 0) {
+    GST_DEBUG ("channels not set yet");
+    return;
+  }
+
+  /* Clamp frequencies */
+  self->lower_frequency = CLAMP (self->lower_frequency, 0.0, rate / 2);
+  self->upper_frequency = CLAMP (self->upper_frequency, 0.0, rate / 2);
+
+  if (self->lower_frequency > self->upper_frequency) {
+    gint tmp = self->lower_frequency;
+
+    self->lower_frequency = self->upper_frequency;
+    self->upper_frequency = tmp;
+  }
+
+  GST_DEBUG ("gst_audio_wsincband: initializing filter kernel of length %d "
+      "with lower frequency %.2lf Hz "
+      ", upper frequency %.2lf Hz for mode %s",
+      len, self->lower_frequency, self->upper_frequency,
+      (self->mode == MODE_BAND_PASS) ? "band-pass" : "band-reject");
+
+  /* fill the lp kernel */
+  w = 2 * G_PI * (self->lower_frequency / rate);
+  kernel_lp = g_new (gdouble, len);
+  for (i = 0; i < len; ++i) {
+    if (i == (len - 1) / 2.0)
+      kernel_lp[i] = w;
+    else
+      kernel_lp[i] = sin (w * (i - (len - 1) / 2.0)) / (i - (len - 1) / 2.0);
+
+    /* windowing */
+    switch (self->window) {
+      case WINDOW_HAMMING:
+        kernel_lp[i] *= (0.54 - 0.46 * cos (2 * G_PI * i / (len - 1)));
+        break;
+      case WINDOW_BLACKMAN:
+        kernel_lp[i] *= (0.42 - 0.5 * cos (2 * G_PI * i / (len - 1)) +
+            0.08 * cos (4 * G_PI * i / (len - 1)));
+        break;
+      case WINDOW_GAUSSIAN:
+        kernel_lp[i] *= exp (-0.5 * POW2 (3.0 / len * (2 * i - (len - 1))));
+        break;
+      case WINDOW_COSINE:
+        kernel_lp[i] *= cos (G_PI * i / (len - 1) - G_PI / 2);
+        break;
+      case WINDOW_HANN:
+        kernel_lp[i] *= 0.5 * (1 - cos (2 * G_PI * i / (len - 1)));
+        break;
+    }
+  }
+
+  /* normalize for unity gain at DC */
+  sum = 0.0;
+  for (i = 0; i < len; ++i)
+    sum += kernel_lp[i];
+  for (i = 0; i < len; ++i)
+    kernel_lp[i] /= sum;
+
+  /* fill the hp kernel */
+  w = 2 * G_PI * (self->upper_frequency / rate);
+  kernel_hp = g_new (gdouble, len);
+  for (i = 0; i < len; ++i) {
+    if (i == (len - 1) / 2.0)
+      kernel_hp[i] = w;
+    else
+      kernel_hp[i] = sin (w * (i - (len - 1) / 2.0)) / (i - (len - 1) / 2.0);
+
+    /* Windowing */
+    switch (self->window) {
+      case WINDOW_HAMMING:
+        kernel_hp[i] *= (0.54 - 0.46 * cos (2 * G_PI * i / (len - 1)));
+        break;
+      case WINDOW_BLACKMAN:
+        kernel_hp[i] *= (0.42 - 0.5 * cos (2 * G_PI * i / (len - 1)) +
+            0.08 * cos (4 * G_PI * i / (len - 1)));
+        break;
+      case WINDOW_GAUSSIAN:
+        kernel_hp[i] *= exp (-0.5 * POW2 (3.0 / len * (2 * i - (len - 1))));
+        break;
+      case WINDOW_COSINE:
+        kernel_hp[i] *= cos (G_PI * i / (len - 1) - G_PI / 2);
+        break;
+      case WINDOW_HANN:
+        kernel_hp[i] *= 0.5 * (1 - cos (2 * G_PI * i / (len - 1)));
+        break;
+    }
+  }
+
+  /* normalize for unity gain at DC */
+  sum = 0.0;
+  for (i = 0; i < len; ++i)
+    sum += kernel_hp[i];
+  for (i = 0; i < len; ++i)
+    kernel_hp[i] /= sum;
+
+  /* do spectral inversion to go from lowpass to highpass */
+  for (i = 0; i < len; ++i)
+    kernel_hp[i] = -kernel_hp[i];
+  if (len % 2 == 1) {
+    kernel_hp[(len - 1) / 2] += 1.0;
+  } else {
+    kernel_hp[len / 2 - 1] += 0.5;
+    kernel_hp[len / 2] += 0.5;
+  }
+
+  /* combine the two kernels */
+  kernel = g_new (gdouble, len);
+
+  for (i = 0; i < len; ++i)
+    kernel[i] = kernel_lp[i] + kernel_hp[i];
+
+  /* free the helper kernels */
+  g_free (kernel_lp);
+  g_free (kernel_hp);
+
+  /* do spectral inversion to go from bandreject to bandpass
+   * if specified */
+  if (self->mode == MODE_BAND_PASS) {
+    for (i = 0; i < len; ++i)
+      kernel[i] = -kernel[i];
+    kernel[len / 2] += 1;
+  }
+
+  gst_audio_fx_base_fir_filter_set_kernel (GST_AUDIO_FX_BASE_FIR_FILTER (self),
+      kernel, self->kernel_length, (len - 1) / 2, info);
+}
+
+/* GstAudioFilter vmethod implementations */
+
+/* get notified of caps and plug in the correct process function */
+static gboolean
+gst_audio_wsincband_setup (GstAudioFilter * base, const GstAudioInfo * info)
+{
+  GstAudioWSincBand *self = GST_AUDIO_WSINC_BAND (base);
+
+  gst_audio_wsincband_build_kernel (self, info);
+
+  return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, info);
+}
+
+static void
+gst_audio_wsincband_finalize (GObject * object)
+{
+  GstAudioWSincBand *self = GST_AUDIO_WSINC_BAND (object);
+
+  g_mutex_clear (&self->lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_audio_wsincband_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAudioWSincBand *self = GST_AUDIO_WSINC_BAND (object);
+
+  g_return_if_fail (GST_IS_AUDIO_WSINC_BAND (self));
+
+  switch (prop_id) {
+    case PROP_LENGTH:{
+      gint val;
+
+      g_mutex_lock (&self->lock);
+      val = g_value_get_int (value);
+      if (val % 2 == 0)
+        val++;
+
+      if (val != self->kernel_length) {
+        gst_audio_fx_base_fir_filter_push_residue (GST_AUDIO_FX_BASE_FIR_FILTER
+            (self));
+        self->kernel_length = val;
+        gst_audio_wsincband_build_kernel (self, NULL);
+      }
+      g_mutex_unlock (&self->lock);
+      break;
+    }
+    case PROP_LOWER_FREQUENCY:
+      g_mutex_lock (&self->lock);
+      self->lower_frequency = g_value_get_float (value);
+      gst_audio_wsincband_build_kernel (self, NULL);
+      g_mutex_unlock (&self->lock);
+      break;
+    case PROP_UPPER_FREQUENCY:
+      g_mutex_lock (&self->lock);
+      self->upper_frequency = g_value_get_float (value);
+      gst_audio_wsincband_build_kernel (self, NULL);
+      g_mutex_unlock (&self->lock);
+      break;
+    case PROP_MODE:
+      g_mutex_lock (&self->lock);
+      self->mode = g_value_get_enum (value);
+      gst_audio_wsincband_build_kernel (self, NULL);
+      g_mutex_unlock (&self->lock);
+      break;
+    case PROP_WINDOW:
+      g_mutex_lock (&self->lock);
+      self->window = g_value_get_enum (value);
+      gst_audio_wsincband_build_kernel (self, NULL);
+      g_mutex_unlock (&self->lock);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_audio_wsincband_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAudioWSincBand *self = GST_AUDIO_WSINC_BAND (object);
+
+  switch (prop_id) {
+    case PROP_LENGTH:
+      g_value_set_int (value, self->kernel_length);
+      break;
+    case PROP_LOWER_FREQUENCY:
+      g_value_set_float (value, self->lower_frequency);
+      break;
+    case PROP_UPPER_FREQUENCY:
+      g_value_set_float (value, self->upper_frequency);
+      break;
+    case PROP_MODE:
+      g_value_set_enum (value, self->mode);
+      break;
+    case PROP_WINDOW:
+      g_value_set_enum (value, self->window);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/gst/audiofx/audiowsincband.h b/gst/audiofx/audiowsincband.h
new file mode 100644
index 0000000..27c2bd4
--- /dev/null
+++ b/gst/audiofx/audiowsincband.h
@@ -0,0 +1,80 @@
+/* -*- c-basic-offset: 2 -*-
+ *
+ * GStreamer
+ * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2006 Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>
+ *               2007-2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *
+ * this windowed sinc filter is taken from the freely downloadable DSP book,
+ * "The Scientist and Engineer's Guide to Digital Signal Processing",
+ * chapter 16
+ * available at http://www.dspguide.com/
+ *
+ */
+
+#ifndef __GST_AUDIO_WSINC_BAND_H__
+#define __GST_AUDIO_WSINC_BAND_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audiofxbasefirfilter.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AUDIO_WSINC_BAND \
+  (gst_audio_wsincband_get_type())
+#define GST_AUDIO_WSINC_BAND(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_WSINC_BAND,GstAudioWSincBand))
+#define GST_AUDIO_WSINC_BAND_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_WSINC_BAND,GstAudioWSincBandClass))
+#define GST_IS_AUDIO_WSINC_BAND(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_WSINC_BAND))
+#define GST_IS_AUDIO_WSINC_BAND_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_WSINC_BAND))
+
+typedef struct _GstAudioWSincBand GstAudioWSincBand;
+typedef struct _GstAudioWSincBandClass GstAudioWSincBandClass;
+
+/**
+ * GstAudioWSincBand:
+ *
+ * Opaque data structure.
+ */
+struct _GstAudioWSincBand {
+  GstAudioFXBaseFIRFilter parent;
+
+  gint mode;
+  gint window;
+  gfloat lower_frequency, upper_frequency;
+  gint kernel_length;           /* length of the filter kernel */
+
+  /* < private > */
+  GMutex lock;
+};
+
+struct _GstAudioWSincBandClass {
+  GstAudioFilterClass parent;
+};
+
+GType gst_audio_wsincband_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_AUDIO_WSINC_BAND_H__ */
diff --git a/gst/audiofx/audiowsinclimit.c b/gst/audiofx/audiowsinclimit.c
new file mode 100644
index 0000000..38eb007
--- /dev/null
+++ b/gst/audiofx/audiowsinclimit.c
@@ -0,0 +1,408 @@
+/* -*- c-basic-offset: 2 -*-
+ * 
+ * GStreamer
+ * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2006 Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>
+ *               2007-2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * 
+ * 
+ * this windowed sinc filter is taken from the freely downloadable DSP book,
+ * "The Scientist and Engineer's Guide to Digital Signal Processing",
+ * chapter 16
+ * available at http://www.dspguide.com/
+ *
+ * For the window functions see
+ * http://en.wikipedia.org/wiki/Window_function
+ */
+
+/**
+ * SECTION:element-audiowsinclimit
+ *
+ * Attenuates all frequencies above the cutoff frequency (low-pass) or all frequencies below the
+ * cutoff frequency (high-pass). The length parameter controls the rolloff, the window parameter
+ * controls rolloff and stopband attenuation. The Hamming window provides a faster rolloff but a bit
+ * worse stopband attenuation, the other way around for the Blackman window.
+ *
+ * This element has the advantage over the Chebyshev lowpass and highpass filter that it has
+ * a much better rolloff when using a larger kernel size and almost linear phase. The only
+ * disadvantage is the much slower execution time with larger kernels.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc freq=1500 ! audioconvert ! audiowsinclimit mode=low-pass cutoff=1000 length=501 ! audioconvert ! alsasink
+ * gst-launch-1.0 filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiowsinclimit mode=high-pass cutoff=15000 length=501 ! audioconvert ! alsasink
+ * gst-launch-1.0 audiotestsrc wave=white-noise ! audioconvert ! audiowsinclimit mode=low-pass cutoff=1000 length=10001 window=blackman ! audioconvert ! alsasink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <gst/gst.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audiowsinclimit.h"
+
+#include "gst/glib-compat-private.h"
+
+#define GST_CAT_DEFAULT gst_audio_wsinclimit_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+enum
+{
+  PROP_0,
+  PROP_LENGTH,
+  PROP_FREQUENCY,
+  PROP_MODE,
+  PROP_WINDOW
+};
+
+enum
+{
+  MODE_LOW_PASS = 0,
+  MODE_HIGH_PASS
+};
+
+#define GST_TYPE_AUDIO_WSINC_LIMIT_MODE (gst_audio_wsinclimit_mode_get_type ())
+static GType
+gst_audio_wsinclimit_mode_get_type (void)
+{
+  static GType gtype = 0;
+
+  if (gtype == 0) {
+    static const GEnumValue values[] = {
+      {MODE_LOW_PASS, "Low pass (default)",
+          "low-pass"},
+      {MODE_HIGH_PASS, "High pass",
+          "high-pass"},
+      {0, NULL, NULL}
+    };
+
+    gtype = g_enum_register_static ("GstAudioWSincLimitMode", values);
+  }
+  return gtype;
+}
+
+enum
+{
+  WINDOW_HAMMING = 0,
+  WINDOW_BLACKMAN,
+  WINDOW_GAUSSIAN,
+  WINDOW_COSINE,
+  WINDOW_HANN
+};
+
+#define GST_TYPE_AUDIO_WSINC_LIMIT_WINDOW (gst_audio_wsinclimit_window_get_type ())
+static GType
+gst_audio_wsinclimit_window_get_type (void)
+{
+  static GType gtype = 0;
+
+  if (gtype == 0) {
+    static const GEnumValue values[] = {
+      {WINDOW_HAMMING, "Hamming window (default)",
+          "hamming"},
+      {WINDOW_BLACKMAN, "Blackman window",
+          "blackman"},
+      {WINDOW_GAUSSIAN, "Gaussian window",
+          "gaussian"},
+      {WINDOW_COSINE, "Cosine window",
+          "cosine"},
+      {WINDOW_HANN, "Hann window",
+          "hann"},
+      {0, NULL, NULL}
+    };
+
+    gtype = g_enum_register_static ("GstAudioWSincLimitWindow", values);
+  }
+  return gtype;
+}
+
+#define gst_audio_wsinclimit_parent_class parent_class
+G_DEFINE_TYPE (GstAudioWSincLimit, gst_audio_wsinclimit,
+    GST_TYPE_AUDIO_FX_BASE_FIR_FILTER);
+
+static void gst_audio_wsinclimit_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_audio_wsinclimit_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_audio_wsinclimit_finalize (GObject * object);
+
+static gboolean gst_audio_wsinclimit_setup (GstAudioFilter * base,
+    const GstAudioInfo * info);
+
+
+#define POW2(x)  (x)*(x)
+
+static void
+gst_audio_wsinclimit_class_init (GstAudioWSincLimitClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (gst_audio_wsinclimit_debug, "audiowsinclimit", 0,
+      "Low-pass and High-pass Windowed sinc filter plugin");
+
+  gobject_class->set_property = gst_audio_wsinclimit_set_property;
+  gobject_class->get_property = gst_audio_wsinclimit_get_property;
+  gobject_class->finalize = gst_audio_wsinclimit_finalize;
+
+  /* FIXME: Don't use the complete possible range but restrict the upper boundary
+   * so automatically generated UIs can use a slider */
+  g_object_class_install_property (gobject_class, PROP_FREQUENCY,
+      g_param_spec_float ("cutoff", "Cutoff",
+          "Cut-off Frequency (Hz)", 0.0, 100000.0, 0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_LENGTH,
+      g_param_spec_int ("length", "Length",
+          "Filter kernel length, will be rounded to the next odd number",
+          3, 256000, 101,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MODE,
+      g_param_spec_enum ("mode", "Mode",
+          "Low pass or high pass mode", GST_TYPE_AUDIO_WSINC_LIMIT_MODE,
+          MODE_LOW_PASS,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_WINDOW,
+      g_param_spec_enum ("window", "Window",
+          "Window function to use", GST_TYPE_AUDIO_WSINC_LIMIT_WINDOW,
+          WINDOW_HAMMING,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Low pass & high pass filter", "Filter/Effect/Audio",
+      "Low pass and high pass windowed sinc filter",
+      "Thomas Vander Stichele <thomas at apestaart dot org>, "
+      "Steven W. Smith, "
+      "Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>, "
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_wsinclimit_setup);
+}
+
+static void
+gst_audio_wsinclimit_init (GstAudioWSincLimit * self)
+{
+  self->mode = MODE_LOW_PASS;
+  self->window = WINDOW_HAMMING;
+  self->kernel_length = 101;
+  self->cutoff = 0.0;
+
+  g_mutex_init (&self->lock);
+}
+
+static void
+gst_audio_wsinclimit_build_kernel (GstAudioWSincLimit * self,
+    const GstAudioInfo * info)
+{
+  gint i = 0;
+  gdouble sum = 0.0;
+  gint len = 0;
+  gdouble w;
+  gdouble *kernel = NULL;
+  gint rate, channels;
+
+  len = self->kernel_length;
+
+  if (info) {
+    rate = GST_AUDIO_INFO_RATE (info);
+    channels = GST_AUDIO_INFO_CHANNELS (info);
+  } else {
+    rate = GST_AUDIO_FILTER_RATE (self);
+    channels = GST_AUDIO_FILTER_CHANNELS (self);
+  }
+
+  if (rate == 0) {
+    GST_DEBUG ("rate not set yet");
+    return;
+  }
+
+  if (channels == 0) {
+    GST_DEBUG ("channels not set yet");
+    return;
+  }
+
+  /* Clamp cutoff frequency between 0 and the nyquist frequency */
+  self->cutoff = CLAMP (self->cutoff, 0.0, rate / 2);
+
+  GST_DEBUG ("gst_audio_wsinclimit_: initializing filter kernel of length %d "
+      "with cutoff %.2lf Hz "
+      "for mode %s",
+      len, self->cutoff,
+      (self->mode == MODE_LOW_PASS) ? "low-pass" : "high-pass");
+
+  /* fill the kernel */
+  w = 2 * G_PI * (self->cutoff / rate);
+
+  kernel = g_new (gdouble, len);
+
+  for (i = 0; i < len; ++i) {
+    if (i == (len - 1) / 2.0)
+      kernel[i] = w;
+    else
+      kernel[i] = sin (w * (i - (len - 1) / 2)) / (i - (len - 1) / 2.0);
+
+    /* windowing */
+    switch (self->window) {
+      case WINDOW_HAMMING:
+        kernel[i] *= (0.54 - 0.46 * cos (2 * G_PI * i / (len - 1)));
+        break;
+      case WINDOW_BLACKMAN:
+        kernel[i] *= (0.42 - 0.5 * cos (2 * G_PI * i / (len - 1)) +
+            0.08 * cos (4 * G_PI * i / (len - 1)));
+        break;
+      case WINDOW_GAUSSIAN:
+        kernel[i] *= exp (-0.5 * POW2 (3.0 / len * (2 * i - (len - 1))));
+        break;
+      case WINDOW_COSINE:
+        kernel[i] *= cos (G_PI * i / (len - 1) - G_PI / 2);
+        break;
+      case WINDOW_HANN:
+        kernel[i] *= 0.5 * (1 - cos (2 * G_PI * i / (len - 1)));
+        break;
+    }
+  }
+
+  /* normalize for unity gain at DC */
+  for (i = 0; i < len; ++i)
+    sum += kernel[i];
+  for (i = 0; i < len; ++i)
+    kernel[i] /= sum;
+
+  /* convert to highpass if specified */
+  if (self->mode == MODE_HIGH_PASS) {
+    for (i = 0; i < len; ++i)
+      kernel[i] = -kernel[i];
+
+    if (len % 2 == 1) {
+      kernel[(len - 1) / 2] += 1.0;
+    } else {
+      kernel[len / 2 - 1] += 0.5;
+      kernel[len / 2] += 0.5;
+    }
+  }
+
+  gst_audio_fx_base_fir_filter_set_kernel (GST_AUDIO_FX_BASE_FIR_FILTER (self),
+      kernel, self->kernel_length, (len - 1) / 2, info);
+}
+
+/* GstAudioFilter vmethod implementations */
+
+/* get notified of caps and plug in the correct process function */
+static gboolean
+gst_audio_wsinclimit_setup (GstAudioFilter * base, const GstAudioInfo * info)
+{
+  GstAudioWSincLimit *self = GST_AUDIO_WSINC_LIMIT (base);
+
+  gst_audio_wsinclimit_build_kernel (self, info);
+
+  return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, info);
+}
+
+static void
+gst_audio_wsinclimit_finalize (GObject * object)
+{
+  GstAudioWSincLimit *self = GST_AUDIO_WSINC_LIMIT (object);
+
+  g_mutex_clear (&self->lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_audio_wsinclimit_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAudioWSincLimit *self = GST_AUDIO_WSINC_LIMIT (object);
+
+  g_return_if_fail (GST_IS_AUDIO_WSINC_LIMIT (self));
+
+  switch (prop_id) {
+    case PROP_LENGTH:{
+      gint val;
+
+      g_mutex_lock (&self->lock);
+      val = g_value_get_int (value);
+      if (val % 2 == 0)
+        val++;
+
+      if (val != self->kernel_length) {
+        gst_audio_fx_base_fir_filter_push_residue (GST_AUDIO_FX_BASE_FIR_FILTER
+            (self));
+        self->kernel_length = val;
+        gst_audio_wsinclimit_build_kernel (self, NULL);
+      }
+      g_mutex_unlock (&self->lock);
+      break;
+    }
+    case PROP_FREQUENCY:
+      g_mutex_lock (&self->lock);
+      self->cutoff = g_value_get_float (value);
+      gst_audio_wsinclimit_build_kernel (self, NULL);
+      g_mutex_unlock (&self->lock);
+      break;
+    case PROP_MODE:
+      g_mutex_lock (&self->lock);
+      self->mode = g_value_get_enum (value);
+      gst_audio_wsinclimit_build_kernel (self, NULL);
+      g_mutex_unlock (&self->lock);
+      break;
+    case PROP_WINDOW:
+      g_mutex_lock (&self->lock);
+      self->window = g_value_get_enum (value);
+      gst_audio_wsinclimit_build_kernel (self, NULL);
+      g_mutex_unlock (&self->lock);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_audio_wsinclimit_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAudioWSincLimit *self = GST_AUDIO_WSINC_LIMIT (object);
+
+  switch (prop_id) {
+    case PROP_LENGTH:
+      g_value_set_int (value, self->kernel_length);
+      break;
+    case PROP_FREQUENCY:
+      g_value_set_float (value, self->cutoff);
+      break;
+    case PROP_MODE:
+      g_value_set_enum (value, self->mode);
+      break;
+    case PROP_WINDOW:
+      g_value_set_enum (value, self->window);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/gst/audiofx/audiowsinclimit.h b/gst/audiofx/audiowsinclimit.h
new file mode 100644
index 0000000..e7fa915
--- /dev/null
+++ b/gst/audiofx/audiowsinclimit.h
@@ -0,0 +1,80 @@
+/* -*- c-basic-offset: 2 -*-
+ * 
+ * GStreamer
+ * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2006 Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>
+ *               2007-2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * 
+ * 
+ * this windowed sinc filter is taken from the freely downloadable DSP book,
+ * "The Scientist and Engineer's Guide to Digital Signal Processing",
+ * chapter 16
+ * available at http://www.dspguide.com/
+ *
+ */
+
+#ifndef __GST_AUDIO_WSINC_LIMIT_H__
+#define __GST_AUDIO_WSINC_LIMIT_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiofilter.h>
+
+#include "audiofxbasefirfilter.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AUDIO_WSINC_LIMIT \
+  (gst_audio_wsinclimit_get_type())
+#define GST_AUDIO_WSINC_LIMIT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_WSINC_LIMIT,GstAudioWSincLimit))
+#define GST_AUDIO_WSINC_LIMIT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_WSINC_LIMIT,GstAudioWSincLimitClass))
+#define GST_IS_AUDIO_WSINC_LIMIT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_WSINC_LIMIT))
+#define GST_IS_AUDIO_WSINC_LIMIT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_WSINC_LIMIT))
+
+typedef struct _GstAudioWSincLimit GstAudioWSincLimit;
+typedef struct _GstAudioWSincLimitClass GstAudioWSincLimitClass;
+
+/**
+ * GstAudioWSincLimit:
+ *
+ * Opaque data structure.
+ */
+struct _GstAudioWSincLimit {
+  GstAudioFXBaseFIRFilter parent;
+
+  gint mode;
+  gint window;
+  gfloat cutoff;
+  gint kernel_length;
+
+  /* < private > */
+  GMutex lock;
+};
+
+struct _GstAudioWSincLimitClass {
+  GstAudioFXBaseFIRFilterClass parent;
+};
+
+GType gst_audio_wsinclimit_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_AUDIO_WSINC_LIMIT_H__ */
diff --git a/gst/audiofx/gstscaletempo.c b/gst/audiofx/gstscaletempo.c
new file mode 100644
index 0000000..6bbc20f
--- /dev/null
+++ b/gst/audiofx/gstscaletempo.c
@@ -0,0 +1,922 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Rov Juvano <rovjuvano@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-scaletempo
+ *
+ * Scale tempo while maintaining pitch
+ * (WSOLA-like technique with cross correlation)
+ * Inspired by SoundTouch library by Olli Parviainen
+ *
+ * Use Sceletempo to apply playback rates without the chipmunk effect.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * <para>
+ * |[
+ * filesrc location=media.ext ! decodebin name=d \
+ *     d. ! queue ! audioconvert ! audioresample ! scaletempo ! audioconvert ! audioresample ! autoaudiosink \
+ *     d. ! queue ! videoconvert ! autovideosink
+ * ]|
+ * OR
+ * |[
+ * playbin uri=... audio_sink="scaletempo ! audioconvert ! audioresample ! autoaudiosink"
+ * ]|
+ * When an application sends a seek event with rate != 1.0, Scaletempo applies
+ * the rate change by scaling the tempo without scaling the pitch.
+ *
+ * Scaletempo works by producing audio in constant sized chunks
+ * (#GstScaletempo:stride) but consuming chunks proportional to the playback
+ * rate.
+ *
+ * Scaletempo then smooths the output by blending the end of one stride with
+ * the next (#GstScaletempo:overlap).
+ *
+ * Scaletempo smooths the overlap further by searching within the input buffer
+ * for the best overlap position.  Scaletempo uses a statistical cross
+ * correlation (roughly a dot-product).  Scaletempo consumes most of its CPU
+ * cycles here. One can use the #GstScaletempo:search propery to tune how far
+ * the algoritm looks.
+ * </para>
+ * </refsect2>
+ */
+
+/*
+ * Note: frame = audio key unit (i.e. one sample for each channel)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <string.h>             /* for memset */
+
+#include "gstscaletempo.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_scaletempo_debug);
+#define GST_CAT_DEFAULT gst_scaletempo_debug
+
+/* Filter signals and args */
+enum
+{
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_RATE,
+  PROP_STRIDE,
+  PROP_OVERLAP,
+  PROP_SEARCH,
+};
+
+#define SUPPORTED_CAPS \
+GST_STATIC_CAPS ( \
+    GST_AUDIO_CAPS_MAKE (GST_AUDIO_NE (F32)) "; " \
+    GST_AUDIO_CAPS_MAKE (GST_AUDIO_NE (F64)) "; " \
+    GST_AUDIO_CAPS_MAKE (GST_AUDIO_NE (S16)) \
+)
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    SUPPORTED_CAPS);
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    SUPPORTED_CAPS);
+
+#define DEBUG_INIT(bla) GST_DEBUG_CATEGORY_INIT (gst_scaletempo_debug, "scaletempo", 0, "scaletempo element");
+
+#define gst_scaletempo_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstScaletempo, gst_scaletempo,
+    GST_TYPE_BASE_TRANSFORM, DEBUG_INIT (0));
+
+#define CREATE_BEST_OVERLAP_OFFSET_FLOAT_FUNC(type) \
+static guint \
+best_overlap_offset_##type (GstScaletempo * st) \
+{ \
+  g##type *pw, *po, *ppc, *search_start; \
+  g##type best_corr = G_MININT; \
+  guint best_off = 0; \
+  gint i, off; \
+  \
+  pw = st->table_window; \
+  po = st->buf_overlap; \
+  po += st->samples_per_frame; \
+  ppc = st->buf_pre_corr; \
+  for (i = st->samples_per_frame; i < st->samples_overlap; i++) { \
+    *ppc++ = *pw++ * *po++; \
+  } \
+  \
+  search_start = (g##type *) st->buf_queue + st->samples_per_frame; \
+  for (off = 0; off < st->frames_search; off++) { \
+    g##type corr = 0; \
+    g##type *ps = search_start; \
+    ppc = st->buf_pre_corr; \
+    for (i = st->samples_per_frame; i < st->samples_overlap; i++) { \
+      corr += *ppc++ * *ps++; \
+    } \
+    if (corr > best_corr) { \
+      best_corr = corr; \
+      best_off = off; \
+    } \
+    search_start += st->samples_per_frame; \
+  } \
+  \
+  return best_off * st->bytes_per_frame; \
+}
+
+CREATE_BEST_OVERLAP_OFFSET_FLOAT_FUNC (float);
+CREATE_BEST_OVERLAP_OFFSET_FLOAT_FUNC (double);
+
+/* buffer padding for loop optimization: sizeof(gint32) * (loop_size - 1) */
+#define UNROLL_PADDING (4*3)
+static guint
+best_overlap_offset_s16 (GstScaletempo * st)
+{
+  gint32 *pw, *ppc;
+  gint16 *po, *search_start;
+  gint64 best_corr = G_MININT64;
+  guint best_off = 0;
+  guint off;
+  glong i;
+
+  pw = st->table_window;
+  po = st->buf_overlap;
+  po += st->samples_per_frame;
+  ppc = st->buf_pre_corr;
+  for (i = st->samples_per_frame; i < st->samples_overlap; i++) {
+    *ppc++ = (*pw++ * *po++) >> 15;
+  }
+
+  search_start = (gint16 *) st->buf_queue + st->samples_per_frame;
+  for (off = 0; off < st->frames_search; off++) {
+    gint64 corr = 0;
+    gint16 *ps = search_start;
+    ppc = st->buf_pre_corr;
+    ppc += st->samples_overlap - st->samples_per_frame;
+    ps += st->samples_overlap - st->samples_per_frame;
+    i = -((glong) st->samples_overlap - (glong) st->samples_per_frame);
+    do {
+      corr += ppc[i + 0] * ps[i + 0];
+      corr += ppc[i + 1] * ps[i + 1];
+      corr += ppc[i + 2] * ps[i + 2];
+      corr += ppc[i + 3] * ps[i + 3];
+      i += 4;
+    } while (i < 0);
+    if (corr > best_corr) {
+      best_corr = corr;
+      best_off = off;
+    }
+    search_start += st->samples_per_frame;
+  }
+
+  return best_off * st->bytes_per_frame;
+}
+
+#define CREATE_OUTPUT_OVERLAP_FLOAT_FUNC(type) \
+static void \
+output_overlap_##type (GstScaletempo * st, gpointer buf_out, guint bytes_off) \
+{ \
+  g##type *pout = buf_out; \
+  g##type *pb = st->table_blend; \
+  g##type *po = st->buf_overlap; \
+  g##type *pin = (g##type *) (st->buf_queue + bytes_off); \
+  gint i; \
+  for (i = 0; i < st->samples_overlap; i++) { \
+    *pout++ = *po - *pb++ * (*po - *pin++); \
+    po++; \
+  } \
+}
+
+CREATE_OUTPUT_OVERLAP_FLOAT_FUNC (float);
+CREATE_OUTPUT_OVERLAP_FLOAT_FUNC (double);
+
+static void
+output_overlap_s16 (GstScaletempo * st, gpointer buf_out, guint bytes_off)
+{
+  gint16 *pout = buf_out;
+  gint32 *pb = st->table_blend;
+  gint16 *po = st->buf_overlap;
+  gint16 *pin = (gint16 *) (st->buf_queue + bytes_off);
+  gint i;
+  for (i = 0; i < st->samples_overlap; i++) {
+    *pout++ = *po - ((*pb++ * (*po - *pin++)) >> 16);
+    po++;
+  }
+}
+
+static guint
+fill_queue (GstScaletempo * st, GstBuffer * buf_in, guint offset)
+{
+  guint bytes_in = gst_buffer_get_size (buf_in) - offset;
+  guint offset_unchanged = offset;
+  GstMapInfo map;
+
+  gst_buffer_map (buf_in, &map, GST_MAP_READ);
+  if (st->bytes_to_slide > 0) {
+    if (st->bytes_to_slide < st->bytes_queued) {
+      guint bytes_in_move = st->bytes_queued - st->bytes_to_slide;
+      memmove (st->buf_queue, st->buf_queue + st->bytes_to_slide,
+          bytes_in_move);
+      st->bytes_to_slide = 0;
+      st->bytes_queued = bytes_in_move;
+    } else {
+      guint bytes_in_skip;
+      st->bytes_to_slide -= st->bytes_queued;
+      bytes_in_skip = MIN (st->bytes_to_slide, bytes_in);
+      st->bytes_queued = 0;
+      st->bytes_to_slide -= bytes_in_skip;
+      offset += bytes_in_skip;
+      bytes_in -= bytes_in_skip;
+    }
+  }
+
+  if (bytes_in > 0) {
+    guint bytes_in_copy =
+        MIN (st->bytes_queue_max - st->bytes_queued, bytes_in);
+    memcpy (st->buf_queue + st->bytes_queued, map.data + offset, bytes_in_copy);
+    st->bytes_queued += bytes_in_copy;
+    offset += bytes_in_copy;
+  }
+  gst_buffer_unmap (buf_in, &map);
+
+  return offset - offset_unchanged;
+}
+
+static void
+reinit_buffers (GstScaletempo * st)
+{
+  gint i, j;
+  guint frames_overlap;
+  guint new_size;
+  GstClockTime latency;
+
+  guint frames_stride = st->ms_stride * st->sample_rate / 1000.0;
+  st->bytes_stride = frames_stride * st->bytes_per_frame;
+
+  /* overlap */
+  frames_overlap = frames_stride * st->percent_overlap;
+  if (frames_overlap < 1) {     /* if no overlap */
+    st->bytes_overlap = 0;
+    st->bytes_standing = st->bytes_stride;
+    st->samples_standing = st->bytes_standing / st->bytes_per_sample;
+    st->output_overlap = NULL;
+  } else {
+    guint prev_overlap = st->bytes_overlap;
+    st->bytes_overlap = frames_overlap * st->bytes_per_frame;
+    st->samples_overlap = frames_overlap * st->samples_per_frame;
+    st->bytes_standing = st->bytes_stride - st->bytes_overlap;
+    st->samples_standing = st->bytes_standing / st->bytes_per_sample;
+    st->buf_overlap = g_realloc (st->buf_overlap, st->bytes_overlap);
+    /* S16 uses gint32 blend table, floats/doubles use their respective type */
+    st->table_blend =
+        g_realloc (st->table_blend,
+        st->samples_overlap * (st->format ==
+            GST_AUDIO_FORMAT_S16 ? 4 : st->bytes_per_sample));
+    if (st->bytes_overlap > prev_overlap) {
+      memset ((guint8 *) st->buf_overlap + prev_overlap, 0,
+          st->bytes_overlap - prev_overlap);
+    }
+    if (st->format == GST_AUDIO_FORMAT_S16) {
+      gint32 *pb = st->table_blend;
+      gint64 blend = 0;
+      for (i = 0; i < frames_overlap; i++) {
+        gint32 v = blend / frames_overlap;
+        for (j = 0; j < st->samples_per_frame; j++) {
+          *pb++ = v;
+        }
+        blend += 65535;         /* 2^16 */
+      }
+      st->output_overlap = output_overlap_s16;
+    } else if (st->format == GST_AUDIO_FORMAT_F32) {
+      gfloat *pb = st->table_blend;
+      gfloat t = (gfloat) frames_overlap;
+      for (i = 0; i < frames_overlap; i++) {
+        gfloat v = i / t;
+        for (j = 0; j < st->samples_per_frame; j++) {
+          *pb++ = v;
+        }
+      }
+      st->output_overlap = output_overlap_float;
+    } else {
+      gdouble *pb = st->table_blend;
+      gdouble t = (gdouble) frames_overlap;
+      for (i = 0; i < frames_overlap; i++) {
+        gdouble v = i / t;
+        for (j = 0; j < st->samples_per_frame; j++) {
+          *pb++ = v;
+        }
+      }
+      st->output_overlap = output_overlap_double;
+    }
+  }
+
+  /* best overlap */
+  st->frames_search =
+      (frames_overlap <= 1) ? 0 : st->ms_search * st->sample_rate / 1000.0;
+  if (st->frames_search < 1) {  /* if no search */
+    st->best_overlap_offset = NULL;
+  } else {
+    /* S16 uses gint32 buffer, floats/doubles use their respective type */
+    guint bytes_pre_corr =
+        (st->samples_overlap - st->samples_per_frame) * (st->format ==
+        GST_AUDIO_FORMAT_S16 ? 4 : st->bytes_per_sample);
+    st->buf_pre_corr =
+        g_realloc (st->buf_pre_corr, bytes_pre_corr + UNROLL_PADDING);
+    st->table_window = g_realloc (st->table_window, bytes_pre_corr);
+    if (st->format == GST_AUDIO_FORMAT_S16) {
+      gint64 t = frames_overlap;
+      gint32 n = 8589934588LL / (t * t);        /* 4 * (2^31 - 1) / t^2 */
+      gint32 *pw;
+
+      memset ((guint8 *) st->buf_pre_corr + bytes_pre_corr, 0, UNROLL_PADDING);
+      pw = st->table_window;
+      for (i = 1; i < frames_overlap; i++) {
+        gint32 v = (i * (t - i) * n) >> 15;
+        for (j = 0; j < st->samples_per_frame; j++) {
+          *pw++ = v;
+        }
+      }
+      st->best_overlap_offset = best_overlap_offset_s16;
+    } else if (st->format == GST_AUDIO_FORMAT_F32) {
+      gfloat *pw = st->table_window;
+      for (i = 1; i < frames_overlap; i++) {
+        gfloat v = i * (frames_overlap - i);
+        for (j = 0; j < st->samples_per_frame; j++) {
+          *pw++ = v;
+        }
+      }
+      st->best_overlap_offset = best_overlap_offset_float;
+    } else {
+      gdouble *pw = st->table_window;
+      for (i = 1; i < frames_overlap; i++) {
+        gdouble v = i * (frames_overlap - i);
+        for (j = 0; j < st->samples_per_frame; j++) {
+          *pw++ = v;
+        }
+      }
+      st->best_overlap_offset = best_overlap_offset_double;
+    }
+  }
+
+  new_size =
+      (st->frames_search + frames_stride +
+      frames_overlap) * st->bytes_per_frame;
+  if (st->bytes_queued > new_size) {
+    if (st->bytes_to_slide > st->bytes_queued) {
+      st->bytes_to_slide -= st->bytes_queued;
+      st->bytes_queued = 0;
+    } else {
+      guint new_queued = MIN (st->bytes_queued - st->bytes_to_slide, new_size);
+      memmove (st->buf_queue,
+          st->buf_queue + st->bytes_queued - new_queued, new_queued);
+      st->bytes_to_slide = 0;
+      st->bytes_queued = new_queued;
+    }
+  }
+
+  st->bytes_queue_max = new_size;
+  st->buf_queue = g_realloc (st->buf_queue, st->bytes_queue_max);
+
+  latency =
+      gst_util_uint64_scale (st->bytes_queue_max, GST_SECOND,
+      st->bytes_per_frame * st->sample_rate);
+  if (st->latency != latency) {
+    st->latency = latency;
+    gst_element_post_message (GST_ELEMENT (st),
+        gst_message_new_latency (GST_OBJECT (st)));
+  }
+
+  st->bytes_stride_scaled = st->bytes_stride * st->scale;
+  st->frames_stride_scaled = st->bytes_stride_scaled / st->bytes_per_frame;
+
+  GST_DEBUG
+      ("%.3f scale, %.3f stride_in, %i stride_out, %i standing, %i overlap, %i search, %i queue, %s mode",
+      st->scale, st->frames_stride_scaled,
+      (gint) (st->bytes_stride / st->bytes_per_frame),
+      (gint) (st->bytes_standing / st->bytes_per_frame),
+      (gint) (st->bytes_overlap / st->bytes_per_frame), st->frames_search,
+      (gint) (st->bytes_queue_max / st->bytes_per_frame),
+      gst_audio_format_to_string (st->format));
+
+  st->reinit_buffers = FALSE;
+}
+
+static GstBuffer *
+reverse_buffer (GstScaletempo * st, GstBuffer * inbuf)
+{
+  GstBuffer *outbuf;
+  GstMapInfo imap, omap;
+
+  gst_buffer_map (inbuf, &imap, GST_MAP_READ);
+  outbuf = gst_buffer_new_and_alloc (imap.size);
+  gst_buffer_map (outbuf, &omap, GST_MAP_WRITE);
+
+  if (st->format == GST_AUDIO_FORMAT_F64) {
+    const gint64 *ip = (const gint64 *) imap.data;
+    gint64 *op = (gint64 *) (omap.data + omap.size - 8 * st->samples_per_frame);
+    guint i, n = imap.size / (8 * st->samples_per_frame);
+    guint j, c = st->samples_per_frame;
+
+    for (i = 0; i < n; i++) {
+      for (j = 0; j < c; j++)
+        op[j] = ip[j];
+      op -= c;
+      ip += c;
+    }
+  } else {
+    const gint32 *ip = (const gint32 *) imap.data;
+    gint32 *op = (gint32 *) (omap.data + omap.size - 4 * st->samples_per_frame);
+    guint i, n = imap.size / (4 * st->samples_per_frame);
+    guint j, c = st->samples_per_frame;
+
+    for (i = 0; i < n; i++) {
+      for (j = 0; j < c; j++)
+        op[j] = ip[j];
+      op -= c;
+      ip += c;
+    }
+  }
+
+  gst_buffer_unmap (inbuf, &imap);
+  gst_buffer_unmap (outbuf, &omap);
+
+  return outbuf;
+}
+
+/* GstBaseTransform vmethod implementations */
+static GstFlowReturn
+gst_scaletempo_transform (GstBaseTransform * trans,
+    GstBuffer * inbuf, GstBuffer * outbuf)
+{
+  GstScaletempo *st = GST_SCALETEMPO (trans);
+  gint8 *pout;
+  guint offset_in, bytes_out;
+  GstMapInfo omap;
+  GstClockTime timestamp;
+  GstBuffer *tmpbuf = NULL;
+
+  if (st->reverse)
+    tmpbuf = reverse_buffer (st, inbuf);
+
+  gst_buffer_map (outbuf, &omap, GST_MAP_WRITE);
+  pout = (gint8 *) omap.data;
+  bytes_out = omap.size;
+
+  offset_in = fill_queue (st, tmpbuf ? tmpbuf : inbuf, 0);
+  bytes_out = 0;
+  while (st->bytes_queued >= st->bytes_queue_max) {
+    guint bytes_off = 0;
+    gdouble frames_to_slide;
+    guint frames_to_stride_whole;
+
+    /* output stride */
+    if (st->output_overlap) {
+      if (st->best_overlap_offset) {
+        bytes_off = st->best_overlap_offset (st);
+      }
+      st->output_overlap (st, pout, bytes_off);
+    }
+    memcpy (pout + st->bytes_overlap,
+        st->buf_queue + bytes_off + st->bytes_overlap, st->bytes_standing);
+    pout += st->bytes_stride;
+    bytes_out += st->bytes_stride;
+
+    /* input stride */
+    memcpy (st->buf_overlap,
+        st->buf_queue + bytes_off + st->bytes_stride, st->bytes_overlap);
+    frames_to_slide = st->frames_stride_scaled + st->frames_stride_error;
+    frames_to_stride_whole = (gint) frames_to_slide;
+    st->bytes_to_slide = frames_to_stride_whole * st->bytes_per_frame;
+    st->frames_stride_error = frames_to_slide - frames_to_stride_whole;
+
+    offset_in += fill_queue (st, tmpbuf ? tmpbuf : inbuf, offset_in);
+  }
+  gst_buffer_unmap (outbuf, &omap);
+
+  if (st->reverse) {
+    timestamp = st->in_segment.stop - GST_BUFFER_TIMESTAMP (inbuf);
+    if (timestamp < st->latency)
+      timestamp = 0;
+    else
+      timestamp -= st->latency;
+  } else {
+    timestamp = GST_BUFFER_TIMESTAMP (inbuf) - st->in_segment.start;
+    if (timestamp < st->latency)
+      timestamp = 0;
+    else
+      timestamp -= st->latency;
+  }
+  GST_BUFFER_TIMESTAMP (outbuf) = timestamp / st->scale + st->in_segment.start;
+  GST_BUFFER_DURATION (outbuf) =
+      gst_util_uint64_scale (bytes_out, GST_SECOND,
+      st->bytes_per_frame * st->sample_rate);
+  gst_buffer_set_size (outbuf, bytes_out);
+
+  if (tmpbuf)
+    gst_buffer_unref (tmpbuf);
+
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_scaletempo_submit_input_buffer (GstBaseTransform * trans,
+    gboolean is_discont, GstBuffer * input)
+{
+  GstScaletempo *scaletempo = GST_SCALETEMPO (trans);
+
+  if (scaletempo->in_segment.format == GST_FORMAT_TIME) {
+    input =
+        gst_audio_buffer_clip (input, &scaletempo->in_segment,
+        scaletempo->sample_rate, scaletempo->bytes_per_frame);
+    if (!input)
+      return GST_FLOW_OK;
+  }
+
+  return GST_BASE_TRANSFORM_CLASS (parent_class)->submit_input_buffer (trans,
+      is_discont, input);
+}
+
+static gboolean
+gst_scaletempo_transform_size (GstBaseTransform * trans,
+    GstPadDirection direction,
+    GstCaps * caps, gsize size, GstCaps * othercaps, gsize * othersize)
+{
+  if (direction == GST_PAD_SINK) {
+    GstScaletempo *scaletempo = GST_SCALETEMPO (trans);
+    gint bytes_to_out;
+
+    if (scaletempo->reinit_buffers)
+      reinit_buffers (scaletempo);
+
+    bytes_to_out = size + scaletempo->bytes_queued - scaletempo->bytes_to_slide;
+    if (bytes_to_out < (gint) scaletempo->bytes_queue_max) {
+      *othersize = 0;
+    } else {
+      /* while (total_buffered - stride_length * n >= queue_max) n++ */
+      *othersize = scaletempo->bytes_stride * ((guint) (
+              (bytes_to_out - scaletempo->bytes_queue_max +
+                  /* rounding protection */ scaletempo->bytes_per_frame)
+              / scaletempo->bytes_stride_scaled) + 1);
+    }
+
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static gboolean
+gst_scaletempo_sink_event (GstBaseTransform * trans, GstEvent * event)
+{
+  GstScaletempo *scaletempo = GST_SCALETEMPO (trans);
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
+    GstSegment segment;
+
+    gst_event_copy_segment (event, &segment);
+
+    if (segment.format != GST_FORMAT_TIME
+        || scaletempo->scale != ABS (segment.rate)
+        || ! !scaletempo->reverse != ! !(segment.rate < 0.0)) {
+      if (segment.format != GST_FORMAT_TIME || ABS (segment.rate - 1.0) < 1e-10) {
+        scaletempo->scale = 1.0;
+        gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (scaletempo),
+            TRUE);
+      } else {
+        gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (scaletempo),
+            FALSE);
+        scaletempo->scale = ABS (segment.rate);
+        scaletempo->reverse = segment.rate < 0.0;
+        scaletempo->bytes_stride_scaled =
+            scaletempo->bytes_stride * scaletempo->scale;
+        scaletempo->frames_stride_scaled =
+            scaletempo->bytes_stride_scaled / scaletempo->bytes_per_frame;
+        GST_DEBUG ("%.3f scale, %.3f stride_in, %i stride_out",
+            scaletempo->scale, scaletempo->frames_stride_scaled,
+            (gint) (scaletempo->bytes_stride / scaletempo->bytes_per_frame));
+
+        scaletempo->bytes_to_slide = 0;
+      }
+    }
+
+    scaletempo->in_segment = segment;
+    scaletempo->out_segment = segment;
+
+    if (scaletempo->scale != 1.0 || scaletempo->reverse) {
+      guint32 seqnum;
+
+      segment.applied_rate = segment.rate;
+      segment.rate = 1.0;
+
+      if (segment.stop != -1) {
+        segment.stop =
+            (segment.stop - segment.start) / ABS (segment.applied_rate) +
+            segment.start;
+      }
+
+      scaletempo->out_segment = segment;
+
+      seqnum = gst_event_get_seqnum (event);
+      gst_event_unref (event);
+
+      event = gst_event_new_segment (&segment);
+      gst_event_set_seqnum (event, seqnum);
+
+      return gst_pad_push_event (GST_BASE_TRANSFORM_SRC_PAD (trans), event);
+    }
+  } else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
+    gst_segment_init (&scaletempo->in_segment, GST_FORMAT_UNDEFINED);
+    gst_segment_init (&scaletempo->out_segment, GST_FORMAT_UNDEFINED);
+  } else if (GST_EVENT_TYPE (event) == GST_EVENT_GAP) {
+    if (scaletempo->scale != 1.0) {
+      GstClockTime gap_ts, gap_duration;
+      gst_event_parse_gap (event, &gap_ts, &gap_duration);
+      if (scaletempo->reverse) {
+        gap_ts = scaletempo->in_segment.stop - gap_ts;
+      } else {
+        gap_ts = gap_ts - scaletempo->in_segment.start;
+      }
+      gap_ts = gap_ts / scaletempo->scale + scaletempo->in_segment.start;
+      if (GST_CLOCK_TIME_IS_VALID (gap_duration)) {
+        gap_duration = gap_duration / ABS (scaletempo->scale);
+      }
+      gst_event_unref (event);
+      event = gst_event_new_gap (gap_ts, gap_duration);
+    }
+  }
+
+  return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
+}
+
+static gboolean
+gst_scaletempo_set_caps (GstBaseTransform * trans,
+    GstCaps * incaps, GstCaps * outcaps)
+{
+  GstScaletempo *scaletempo = GST_SCALETEMPO (trans);
+
+  gint width, bps, nch, rate;
+  GstAudioInfo info;
+  GstAudioFormat format;
+
+  if (!gst_audio_info_from_caps (&info, incaps))
+    return FALSE;
+
+  nch = GST_AUDIO_INFO_CHANNELS (&info);
+  rate = GST_AUDIO_INFO_RATE (&info);
+  width = GST_AUDIO_INFO_WIDTH (&info);
+  format = GST_AUDIO_INFO_FORMAT (&info);
+
+  bps = width / 8;
+
+  GST_DEBUG ("caps: %" GST_PTR_FORMAT ", %d bps", incaps, bps);
+
+  if (rate != scaletempo->sample_rate
+      || nch != scaletempo->samples_per_frame
+      || bps != scaletempo->bytes_per_sample || format != scaletempo->format) {
+    scaletempo->sample_rate = rate;
+    scaletempo->samples_per_frame = nch;
+    scaletempo->bytes_per_sample = bps;
+    scaletempo->bytes_per_frame = nch * bps;
+    scaletempo->format = format;
+    scaletempo->reinit_buffers = TRUE;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_scaletempo_start (GstBaseTransform * trans)
+{
+  GstScaletempo *scaletempo = GST_SCALETEMPO (trans);
+
+  gst_segment_init (&scaletempo->in_segment, GST_FORMAT_UNDEFINED);
+  gst_segment_init (&scaletempo->out_segment, GST_FORMAT_UNDEFINED);
+  scaletempo->reinit_buffers = TRUE;
+
+  return TRUE;
+}
+
+static gboolean
+gst_scaletempo_stop (GstBaseTransform * trans)
+{
+  GstScaletempo *scaletempo = GST_SCALETEMPO (trans);
+
+  g_free (scaletempo->buf_queue);
+  scaletempo->buf_queue = NULL;
+  g_free (scaletempo->buf_overlap);
+  scaletempo->buf_overlap = NULL;
+  g_free (scaletempo->table_blend);
+  scaletempo->table_blend = NULL;
+  g_free (scaletempo->buf_pre_corr);
+  scaletempo->buf_pre_corr = NULL;
+  g_free (scaletempo->table_window);
+  scaletempo->table_window = NULL;
+  scaletempo->reinit_buffers = TRUE;
+
+  return TRUE;
+}
+
+static gboolean
+gst_scaletempo_query (GstBaseTransform * trans, GstPadDirection direction,
+    GstQuery * query)
+{
+  GstScaletempo *scaletempo = GST_SCALETEMPO (trans);
+
+  if (direction == GST_PAD_SRC) {
+    switch (GST_QUERY_TYPE (query)) {
+      case GST_QUERY_LATENCY:{
+        GstPad *peer;
+
+        if ((peer = gst_pad_get_peer (GST_BASE_TRANSFORM_SINK_PAD (trans)))) {
+          if ((gst_pad_query (peer, query))) {
+            GstClockTime min, max;
+            gboolean live;
+
+            gst_query_parse_latency (query, &live, &min, &max);
+
+            GST_DEBUG_OBJECT (scaletempo, "Peer latency: min %"
+                GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
+                GST_TIME_ARGS (min), GST_TIME_ARGS (max));
+
+            /* add our own latency */
+            GST_DEBUG_OBJECT (scaletempo, "Our latency: %" GST_TIME_FORMAT,
+                GST_TIME_ARGS (scaletempo->latency));
+            min += scaletempo->latency;
+            if (max != GST_CLOCK_TIME_NONE)
+              max += scaletempo->latency;
+
+            GST_DEBUG_OBJECT (scaletempo, "Calculated total latency : min %"
+                GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
+                GST_TIME_ARGS (min), GST_TIME_ARGS (max));
+            gst_query_set_latency (query, live, min, max);
+          }
+          gst_object_unref (peer);
+        }
+
+        return TRUE;
+      }
+      default:{
+        return GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
+            query);
+      }
+    }
+  } else {
+    return GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
+        query);
+  }
+}
+
+/* GObject vmethod implementations */
+static void
+gst_scaletempo_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstScaletempo *scaletempo = GST_SCALETEMPO (object);
+
+  switch (prop_id) {
+    case PROP_RATE:
+      g_value_set_double (value, scaletempo->scale);
+      break;
+    case PROP_STRIDE:
+      g_value_set_uint (value, scaletempo->ms_stride);
+      break;
+    case PROP_OVERLAP:
+      g_value_set_double (value, scaletempo->percent_overlap);
+      break;
+    case PROP_SEARCH:
+      g_value_set_uint (value, scaletempo->ms_search);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_scaletempo_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstScaletempo *scaletempo = GST_SCALETEMPO (object);
+
+  switch (prop_id) {
+    case PROP_STRIDE:{
+      guint new_value = g_value_get_uint (value);
+      if (scaletempo->ms_stride != new_value) {
+        scaletempo->ms_stride = new_value;
+        scaletempo->reinit_buffers = TRUE;
+      }
+      break;
+    }
+    case PROP_OVERLAP:{
+      gdouble new_value = g_value_get_double (value);
+      if (scaletempo->percent_overlap != new_value) {
+        scaletempo->percent_overlap = new_value;
+        scaletempo->reinit_buffers = TRUE;
+      }
+      break;
+    }
+    case PROP_SEARCH:{
+      guint new_value = g_value_get_uint (value);
+      if (scaletempo->ms_search != new_value) {
+        scaletempo->ms_search = new_value;
+        scaletempo->reinit_buffers = TRUE;
+      }
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_scaletempo_class_init (GstScaletempoClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  GstBaseTransformClass *basetransform_class = GST_BASE_TRANSFORM_CLASS (klass);
+
+  gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_scaletempo_get_property);
+  gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_scaletempo_set_property);
+
+  g_object_class_install_property (gobject_class, PROP_RATE,
+      g_param_spec_double ("rate", "Playback Rate", "Current playback rate",
+          G_MININT, G_MAXINT, 1.0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_STRIDE,
+      g_param_spec_uint ("stride", "Stride Length",
+          "Length in milliseconds to output each stride", 1, 5000, 30,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_OVERLAP,
+      g_param_spec_double ("overlap", "Overlap Length",
+          "Percentage of stride to overlap", 0, 1, .2,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_SEARCH,
+      g_param_spec_uint ("search", "Search Length",
+          "Length in milliseconds to search for best overlap position", 0, 500,
+          14, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_template);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+  gst_element_class_set_static_metadata (gstelement_class, "Scaletempo",
+      "Filter/Effect/Rate",
+      "Sync audio tempo with playback rate",
+      "Rov Juvano <rovjuvano@users.sourceforge.net>");
+
+  basetransform_class->sink_event =
+      GST_DEBUG_FUNCPTR (gst_scaletempo_sink_event);
+  basetransform_class->set_caps = GST_DEBUG_FUNCPTR (gst_scaletempo_set_caps);
+  basetransform_class->transform_size =
+      GST_DEBUG_FUNCPTR (gst_scaletempo_transform_size);
+  basetransform_class->transform = GST_DEBUG_FUNCPTR (gst_scaletempo_transform);
+  basetransform_class->query = GST_DEBUG_FUNCPTR (gst_scaletempo_query);
+  basetransform_class->start = GST_DEBUG_FUNCPTR (gst_scaletempo_start);
+  basetransform_class->stop = GST_DEBUG_FUNCPTR (gst_scaletempo_stop);
+  basetransform_class->submit_input_buffer =
+      GST_DEBUG_FUNCPTR (gst_scaletempo_submit_input_buffer);
+}
+
+static void
+gst_scaletempo_init (GstScaletempo * scaletempo)
+{
+  /* defaults */
+  scaletempo->ms_stride = 30;
+  scaletempo->percent_overlap = .2;
+  scaletempo->ms_search = 14;
+
+  /* uninitialized */
+  scaletempo->scale = 0;
+  scaletempo->sample_rate = 0;
+  scaletempo->frames_stride_error = 0;
+  scaletempo->bytes_stride = 0;
+  scaletempo->bytes_queued = 0;
+  scaletempo->bytes_to_slide = 0;
+  gst_segment_init (&scaletempo->in_segment, GST_FORMAT_UNDEFINED);
+  gst_segment_init (&scaletempo->out_segment, GST_FORMAT_UNDEFINED);
+}
diff --git a/gst/audiofx/gstscaletempo.h b/gst/audiofx/gstscaletempo.h
new file mode 100644
index 0000000..051881d
--- /dev/null
+++ b/gst/audiofx/gstscaletempo.h
@@ -0,0 +1,99 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Rov Juvano <rovjuvano@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_SCALETEMPO_H__
+#define __GST_SCALETEMPO_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SCALETEMPO            (gst_scaletempo_get_type())
+#define GST_SCALETEMPO(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_SCALETEMPO, GstScaletempo))
+#define GST_SCALETEMPO_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  GST_TYPE_SCALETEMPO, GstScaletempoClass))
+#define GST_IS_SCALETEMPO(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_SCALETEMPO))
+#define GST_IS_SCALETEMPO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),  GST_TYPE_SCALETEMPO))
+
+typedef struct _GstScaletempo GstScaletempo;
+typedef struct _GstScaletempoClass GstScaletempoClass;
+typedef struct _GstScaletempoPrivate GstScaletempoPrivate;
+
+struct _GstScaletempo
+{
+  GstBaseTransform element;
+
+  gdouble scale;
+  gboolean reverse;
+
+  /* parameters */
+  guint ms_stride;
+  gdouble percent_overlap;
+  guint ms_search;
+
+  /* caps */
+  GstAudioFormat format;
+  guint samples_per_frame;      /* AKA number of channels */
+  guint bytes_per_sample;
+  guint bytes_per_frame;
+  guint sample_rate;
+
+  /* stride */
+  gdouble frames_stride_scaled;
+  gdouble frames_stride_error;
+  guint bytes_stride;
+  gdouble bytes_stride_scaled;
+  guint bytes_queue_max;
+  guint bytes_queued;
+  guint bytes_to_slide;
+  gint8 *buf_queue;
+
+  /* overlap */
+  guint samples_overlap;
+  guint samples_standing;
+  guint bytes_overlap;
+  guint bytes_standing;
+  gpointer buf_overlap;
+  gpointer table_blend;
+  void (*output_overlap) (GstScaletempo * scaletempo, gpointer out_buf, guint bytes_off);
+
+  /* best overlap */
+  guint frames_search;
+  gpointer buf_pre_corr;
+  gpointer table_window;
+  guint (*best_overlap_offset) (GstScaletempo * scaletempo);
+
+  /* gstreamer */
+  GstSegment in_segment, out_segment;
+  GstClockTime latency;
+
+  /* threads */
+  gboolean reinit_buffers;
+};
+
+struct _GstScaletempoClass
+{
+  GstBaseTransformClass parent_class;
+};
+
+GType gst_scaletempo_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_SCALETEMPO_H__ */
diff --git a/gst/audiofx/gstscaletempoplugin.c b/gst/audiofx/gstscaletempoplugin.c
new file mode 100644
index 0000000..4c6f1f1
--- /dev/null
+++ b/gst/audiofx/gstscaletempoplugin.c
@@ -0,0 +1,68 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Rov Juvano <rovjuvano@users.sourceforge.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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 <gst/gst.h>
+#include "gstscaletempo.h"
+
+/* entry point to initialize the plug-in
+ * initialize the plug-in itself
+ * register the element factories and pad templates
+ * register the features
+ *
+ * exchange the string 'plugin' with your elemnt name
+ */
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "scaletempo", GST_RANK_NONE,
+      GST_TYPE_SCALETEMPO);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
+    scaletempo, "Scale audio tempo in sync with playback rate",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/audiofx/math_compat.h b/gst/audiofx/math_compat.h
new file mode 100644
index 0000000..da2370c
--- /dev/null
+++ b/gst/audiofx/math_compat.h
@@ -0,0 +1,55 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __MATH_COMPAT_H__
+#define __MATH_COMPAT_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+#include <math.h>
+
+#ifndef HAVE_ASINH
+static inline gdouble
+asinh (gdouble x)
+{
+  return log(x + sqrt (x * x + 1));
+}
+#endif
+
+#ifndef HAVE_SINH
+static inline gdouble
+sinh (gdouble x)
+{
+  return 0.5 * (exp (x) - exp (-x));
+}
+#endif
+
+#ifndef HAVE_COSH
+static inline gdouble
+cosh (gdouble x)
+{
+  return 0.5 * (exp (x) + exp (-x));
+}
+#endif
+
+#endif /* __MATH_COMPAT_H__ */
diff --git a/gst/audiofx/meson.build b/gst/audiofx/meson.build
new file mode 100644
index 0000000..b355044
--- /dev/null
+++ b/gst/audiofx/meson.build
@@ -0,0 +1,46 @@
+audiofx_sources = [
+  'audiofx.c',
+  'audiopanorama.c',
+  'audioinvert.c',
+  'audioamplify.c',
+  'audiodynamic.c',
+  'audiokaraoke.c',
+  'audiofxbaseiirfilter.c',
+  'audiocheblimit.c',
+  'audiochebband.c',
+  'audioiirfilter.c',
+  'audiofxbasefirfilter.c',
+  'audiowsincband.c',
+  'audiowsinclimit.c',
+  'audiofirfilter.c',
+  'audioecho.c',
+  'gstscaletempo.c'
+]
+
+orcsrc = 'audiopanoramaorc'
+if have_orcc
+  orc_h = custom_target(orcsrc + '.h',
+    input : orcsrc + '.orc',
+    output : orcsrc + '.h',
+    command : orcc_args + ['--header', '-o', '@OUTPUT@', '@INPUT@'])
+  orc_c = custom_target(orcsrc + '.c',
+    input : orcsrc + '.orc',
+    output : orcsrc + '.c',
+    command : orcc_args + ['--implementation', '-o', '@OUTPUT@', '@INPUT@'])
+else
+  orc_h = configure_file(input : orcsrc + '-dist.h',
+    output : orcsrc + '.h',
+    configuration : configuration_data())
+  orc_c = configure_file(input : orcsrc + '-dist.c',
+    output : orcsrc + '.c',
+    configuration : configuration_data())
+endif
+
+gstaudiofx = library('gstaudiofx',
+  audiofx_sources, orc_c, orc_h,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc, libsinc],
+  dependencies : [orc_dep, gstaudio_dep, gstfft_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/audioparsers/Makefile.am b/gst/audioparsers/Makefile.am
new file mode 100644
index 0000000..6727688
--- /dev/null
+++ b/gst/audioparsers/Makefile.am
@@ -0,0 +1,19 @@
+plugin_LTLIBRARIES = libgstaudioparsers.la
+
+libgstaudioparsers_la_SOURCES = \
+	gstaacparse.c gstamrparse.c gstac3parse.c \
+	gstdcaparse.c gstflacparse.c gstmpegaudioparse.c \
+	gstsbcparse.c gstwavpackparse.c plugin.c
+
+libgstaudioparsers_la_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstaudioparsers_la_LIBADD = \
+	-lgstpbutils-$(GST_API_VERSION) \
+	$(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_API_VERSION) \
+	-lgstaudio-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) $(GST_LIBS)
+libgstaudioparsers_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstaacparse.h gstamrparse.h gstac3parse.h \
+	gstdcaparse.h gstflacparse.h gstmpegaudioparse.h gstsbcparse.h \
+	gstwavpackparse.h
diff --git a/gst/audioparsers/gstaacparse.c b/gst/audioparsers/gstaacparse.c
new file mode 100644
index 0000000..3c7c716
--- /dev/null
+++ b/gst/audioparsers/gstaacparse.c
@@ -0,0 +1,1671 @@
+/* GStreamer AAC parser plugin
+ * Copyright (C) 2008 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-aacparse
+ * @short_description: AAC parser
+ * @see_also: #GstAmrParse
+ *
+ * This is an AAC parser which handles both ADIF and ADTS stream formats.
+ *
+ * As ADIF format is not framed, it is not seekable and stream duration cannot
+ * be determined either. However, ADTS format AAC clips can be seeked, and parser
+ * can also estimate playback position and clip duration.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=abc.aac ! aacparse ! faad ! audioresample ! audioconvert ! alsasink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/base/gstbitreader.h>
+#include <gst/pbutils/pbutils.h>
+#include "gstaacparse.h"
+
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/mpeg, "
+        "framed = (boolean) true, " "mpegversion = (int) { 2, 4 }, "
+        "stream-format = (string) { raw, adts, adif, loas };"));
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/mpeg, mpegversion = (int) { 2, 4 };"));
+
+GST_DEBUG_CATEGORY_STATIC (aacparse_debug);
+#define GST_CAT_DEFAULT aacparse_debug
+
+
+#define ADIF_MAX_SIZE 40        /* Should be enough */
+#define ADTS_MAX_SIZE 10        /* Should be enough */
+#define LOAS_MAX_SIZE 3         /* Should be enough */
+#define RAW_MAX_SIZE  1         /* Correct framing is required */
+
+#define ADTS_HEADERS_LENGTH 7UL /* Total byte-length of fixed and variable
+                                   headers prepended during raw to ADTS
+                                   conversion */
+
+#define AAC_FRAME_DURATION(parse) (GST_SECOND/parse->frames_per_sec)
+
+static const gint loas_sample_rate_table[16] = {
+  96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+  16000, 12000, 11025, 8000, 7350, 0, 0, 0
+};
+
+static const gint loas_channels_table[16] = {
+  0, 1, 2, 3, 4, 5, 6, 8,
+  0, 0, 0, 7, 8, 0, 8, 0
+};
+
+static gboolean gst_aac_parse_start (GstBaseParse * parse);
+static gboolean gst_aac_parse_stop (GstBaseParse * parse);
+
+static gboolean gst_aac_parse_sink_setcaps (GstBaseParse * parse,
+    GstCaps * caps);
+static GstCaps *gst_aac_parse_sink_getcaps (GstBaseParse * parse,
+    GstCaps * filter);
+
+static GstFlowReturn gst_aac_parse_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize);
+static GstFlowReturn gst_aac_parse_pre_push_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame);
+static gboolean gst_aac_parse_src_event (GstBaseParse * parse,
+    GstEvent * event);
+
+static gboolean gst_aac_parse_read_audio_specific_config (GstAacParse *
+    aacparse, GstBitReader * br, gint * object_type, gint * sample_rate,
+    gint * channels, gint * frame_samples);
+
+
+#define gst_aac_parse_parent_class parent_class
+G_DEFINE_TYPE (GstAacParse, gst_aac_parse, GST_TYPE_BASE_PARSE);
+
+/**
+ * gst_aac_parse_class_init:
+ * @klass: #GstAacParseClass.
+ *
+ */
+static void
+gst_aac_parse_class_init (GstAacParseClass * klass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (aacparse_debug, "aacparse", 0,
+      "AAC audio stream parser");
+
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "AAC audio stream parser", "Codec/Parser/Audio",
+      "Advanced Audio Coding parser", "Stefan Kost <stefan.kost@nokia.com>");
+
+  parse_class->start = GST_DEBUG_FUNCPTR (gst_aac_parse_start);
+  parse_class->stop = GST_DEBUG_FUNCPTR (gst_aac_parse_stop);
+  parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_aac_parse_sink_setcaps);
+  parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_aac_parse_sink_getcaps);
+  parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_aac_parse_handle_frame);
+  parse_class->pre_push_frame =
+      GST_DEBUG_FUNCPTR (gst_aac_parse_pre_push_frame);
+  parse_class->src_event = GST_DEBUG_FUNCPTR (gst_aac_parse_src_event);
+}
+
+
+/**
+ * gst_aac_parse_init:
+ * @aacparse: #GstAacParse.
+ * @klass: #GstAacParseClass.
+ *
+ */
+static void
+gst_aac_parse_init (GstAacParse * aacparse)
+{
+  GST_DEBUG ("initialized");
+  GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (aacparse));
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (aacparse));
+
+  aacparse->last_parsed_sample_rate = 0;
+  aacparse->last_parsed_channels = 0;
+}
+
+
+/**
+ * gst_aac_parse_set_src_caps:
+ * @aacparse: #GstAacParse.
+ * @sink_caps: (proposed) caps of sink pad
+ *
+ * Set source pad caps according to current knowledge about the
+ * audio stream.
+ *
+ * Returns: TRUE if caps were successfully set.
+ */
+static gboolean
+gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps)
+{
+  GstStructure *s;
+  GstCaps *src_caps = NULL, *allowed;
+  gboolean res = FALSE;
+  const gchar *stream_format;
+  guint8 codec_data[2];
+  guint16 codec_data_data;
+  gint sample_rate_idx;
+
+  GST_DEBUG_OBJECT (aacparse, "sink caps: %" GST_PTR_FORMAT, sink_caps);
+  if (sink_caps)
+    src_caps = gst_caps_copy (sink_caps);
+  else
+    src_caps = gst_caps_new_empty_simple ("audio/mpeg");
+
+  gst_caps_set_simple (src_caps, "framed", G_TYPE_BOOLEAN, TRUE,
+      "mpegversion", G_TYPE_INT, aacparse->mpegversion, NULL);
+
+  aacparse->output_header_type = aacparse->header_type;
+  switch (aacparse->header_type) {
+    case DSPAAC_HEADER_NONE:
+      stream_format = "raw";
+      break;
+    case DSPAAC_HEADER_ADTS:
+      stream_format = "adts";
+      break;
+    case DSPAAC_HEADER_ADIF:
+      stream_format = "adif";
+      break;
+    case DSPAAC_HEADER_LOAS:
+      stream_format = "loas";
+      break;
+    default:
+      stream_format = NULL;
+  }
+
+  /* Generate codec data to be able to set profile/level on the caps */
+  sample_rate_idx =
+      gst_codec_utils_aac_get_index_from_sample_rate (aacparse->sample_rate);
+  if (sample_rate_idx < 0)
+    goto not_a_known_rate;
+  codec_data_data =
+      (aacparse->object_type << 11) |
+      (sample_rate_idx << 7) | (aacparse->channels << 3);
+  GST_WRITE_UINT16_BE (codec_data, codec_data_data);
+  gst_codec_utils_aac_caps_set_level_and_profile (src_caps, codec_data, 2);
+
+  s = gst_caps_get_structure (src_caps, 0);
+  if (aacparse->sample_rate > 0)
+    gst_structure_set (s, "rate", G_TYPE_INT, aacparse->sample_rate, NULL);
+  if (aacparse->channels > 0)
+    gst_structure_set (s, "channels", G_TYPE_INT, aacparse->channels, NULL);
+  if (stream_format)
+    gst_structure_set (s, "stream-format", G_TYPE_STRING, stream_format, NULL);
+
+  allowed = gst_pad_get_allowed_caps (GST_BASE_PARSE (aacparse)->srcpad);
+  if (allowed && !gst_caps_can_intersect (src_caps, allowed)) {
+    GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad,
+        "Caps can not intersect");
+    if (aacparse->header_type == DSPAAC_HEADER_ADTS) {
+      GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad,
+          "Input is ADTS, trying raw");
+      gst_caps_set_simple (src_caps, "stream-format", G_TYPE_STRING, "raw",
+          NULL);
+      if (gst_caps_can_intersect (src_caps, allowed)) {
+        GstBuffer *codec_data_buffer;
+
+        GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad,
+            "Caps can intersect, we will drop the ADTS layer");
+        aacparse->output_header_type = DSPAAC_HEADER_NONE;
+
+        /* The codec_data data is according to AudioSpecificConfig,
+           ISO/IEC 14496-3, 1.6.2.1 */
+        codec_data_buffer = gst_buffer_new_and_alloc (2);
+        gst_buffer_fill (codec_data_buffer, 0, codec_data, 2);
+        gst_caps_set_simple (src_caps, "codec_data", GST_TYPE_BUFFER,
+            codec_data_buffer, NULL);
+      }
+    } else if (aacparse->header_type == DSPAAC_HEADER_NONE) {
+      GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad,
+          "Input is raw, trying ADTS");
+      gst_caps_set_simple (src_caps, "stream-format", G_TYPE_STRING, "adts",
+          NULL);
+      if (gst_caps_can_intersect (src_caps, allowed)) {
+        GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad,
+            "Caps can intersect, we will prepend ADTS headers");
+        aacparse->output_header_type = DSPAAC_HEADER_ADTS;
+      }
+    }
+  }
+  if (allowed)
+    gst_caps_unref (allowed);
+
+  aacparse->last_parsed_channels = 0;
+  aacparse->last_parsed_sample_rate = 0;
+
+  GST_DEBUG_OBJECT (aacparse, "setting src caps: %" GST_PTR_FORMAT, src_caps);
+
+  res = gst_pad_set_caps (GST_BASE_PARSE (aacparse)->srcpad, src_caps);
+  gst_caps_unref (src_caps);
+  return res;
+
+not_a_known_rate:
+  GST_ERROR_OBJECT (aacparse, "Not a known sample rate: %d",
+      aacparse->sample_rate);
+  gst_caps_unref (src_caps);
+  return FALSE;
+}
+
+
+/**
+ * gst_aac_parse_sink_setcaps:
+ * @sinkpad: GstPad
+ * @caps: GstCaps
+ *
+ * Implementation of "set_sink_caps" vmethod in #GstBaseParse class.
+ *
+ * Returns: TRUE on success.
+ */
+static gboolean
+gst_aac_parse_sink_setcaps (GstBaseParse * parse, GstCaps * caps)
+{
+  GstAacParse *aacparse;
+  GstStructure *structure;
+  gchar *caps_str;
+  const GValue *value;
+
+  aacparse = GST_AAC_PARSE (parse);
+  structure = gst_caps_get_structure (caps, 0);
+  caps_str = gst_caps_to_string (caps);
+
+  GST_DEBUG_OBJECT (aacparse, "setcaps: %s", caps_str);
+  g_free (caps_str);
+
+  /* This is needed at least in case of RTP
+   * Parses the codec_data information to get ObjectType,
+   * number of channels and samplerate */
+  value = gst_structure_get_value (structure, "codec_data");
+  if (value) {
+    GstBuffer *buf = gst_value_get_buffer (value);
+
+    if (buf && gst_buffer_get_size (buf) >= 2) {
+      GstMapInfo map;
+      GstBitReader br;
+
+      if (!gst_buffer_map (buf, &map, GST_MAP_READ))
+        return FALSE;
+      gst_bit_reader_init (&br, map.data, map.size);
+      gst_aac_parse_read_audio_specific_config (aacparse, &br,
+          &aacparse->object_type, &aacparse->sample_rate, &aacparse->channels,
+          &aacparse->frame_samples);
+
+      aacparse->header_type = DSPAAC_HEADER_NONE;
+      aacparse->mpegversion = 4;
+      gst_buffer_unmap (buf, &map);
+
+      GST_DEBUG ("codec_data: object_type=%d, sample_rate=%d, channels=%d, "
+          "samples=%d", aacparse->object_type, aacparse->sample_rate,
+          aacparse->channels, aacparse->frame_samples);
+
+      /* arrange for metadata and get out of the way */
+      gst_aac_parse_set_src_caps (aacparse, caps);
+      if (aacparse->header_type == aacparse->output_header_type)
+        gst_base_parse_set_passthrough (parse, TRUE);
+
+      /* input is already correctly framed */
+      gst_base_parse_set_min_frame_size (parse, RAW_MAX_SIZE);
+    } else {
+      return FALSE;
+    }
+
+    /* caps info overrides */
+    gst_structure_get_int (structure, "rate", &aacparse->sample_rate);
+    gst_structure_get_int (structure, "channels", &aacparse->channels);
+  } else {
+    const gchar *stream_format =
+        gst_structure_get_string (structure, "stream-format");
+
+    if (g_strcmp0 (stream_format, "raw") == 0) {
+      GST_ERROR_OBJECT (parse, "Need codec_data for raw AAC");
+      return FALSE;
+    } else {
+      aacparse->sample_rate = 0;
+      aacparse->channels = 0;
+      aacparse->header_type = DSPAAC_HEADER_NOT_PARSED;
+      gst_base_parse_set_passthrough (parse, FALSE);
+    }
+  }
+  return TRUE;
+}
+
+
+/**
+ * gst_aac_parse_adts_get_frame_len:
+ * @data: block of data containing an ADTS header.
+ *
+ * This function calculates ADTS frame length from the given header.
+ *
+ * Returns: size of the ADTS frame.
+ */
+static inline guint
+gst_aac_parse_adts_get_frame_len (const guint8 * data)
+{
+  return ((data[3] & 0x03) << 11) | (data[4] << 3) | ((data[5] & 0xe0) >> 5);
+}
+
+
+/**
+ * gst_aac_parse_check_adts_frame:
+ * @aacparse: #GstAacParse.
+ * @data: Data to be checked.
+ * @avail: Amount of data passed.
+ * @framesize: If valid ADTS frame was found, this will be set to tell the
+ *             found frame size in bytes.
+ * @needed_data: If frame was not found, this may be set to tell how much
+ *               more data is needed in the next round to detect the frame
+ *               reliably. This may happen when a frame header candidate
+ *               is found but it cannot be guaranteed to be the header without
+ *               peeking the following data.
+ *
+ * Check if the given data contains contains ADTS frame. The algorithm
+ * will examine ADTS frame header and calculate the frame size. Also, another
+ * consecutive ADTS frame header need to be present after the found frame.
+ * Otherwise the data is not considered as a valid ADTS frame. However, this
+ * "extra check" is omitted when EOS has been received. In this case it is
+ * enough when data[0] contains a valid ADTS header.
+ *
+ * This function may set the #needed_data to indicate that a possible frame
+ * candidate has been found, but more data (#needed_data bytes) is needed to
+ * be absolutely sure. When this situation occurs, FALSE will be returned.
+ *
+ * When a valid frame is detected, this function will use
+ * gst_base_parse_set_min_frame_size() function from #GstBaseParse class
+ * to set the needed bytes for next frame.This way next data chunk is already
+ * of correct size.
+ *
+ * Returns: TRUE if the given data contains a valid ADTS header.
+ */
+static gboolean
+gst_aac_parse_check_adts_frame (GstAacParse * aacparse,
+    const guint8 * data, const guint avail, gboolean drain,
+    guint * framesize, guint * needed_data)
+{
+  guint crc_size;
+
+  *needed_data = 0;
+
+  /* Absolute minimum to perform the ADTS syncword,
+     layer and sampling frequency tests */
+  if (G_UNLIKELY (avail < 3)) {
+    *needed_data = 3;
+    return FALSE;
+  }
+
+  /* Syncword and layer tests */
+  if ((data[0] == 0xff) && ((data[1] & 0xf6) == 0xf0)) {
+
+    /* Sampling frequency test */
+    if (G_UNLIKELY ((data[2] & 0x3C) >> 2 == 15))
+      return FALSE;
+
+    /* This looks like an ADTS frame header but
+       we need at least 6 bytes to proceed */
+    if (G_UNLIKELY (avail < 6)) {
+      *needed_data = 6;
+      return FALSE;
+    }
+
+    *framesize = gst_aac_parse_adts_get_frame_len (data);
+
+    /* If frame has CRC, it needs 2 bytes
+       for it at the end of the header */
+    crc_size = (data[1] & 0x01) ? 0 : 2;
+
+    /* CRC size test */
+    if (*framesize < 7 + crc_size) {
+      *needed_data = 7 + crc_size;
+      return FALSE;
+    }
+
+    /* In EOS mode this is enough. No need to examine the data further.
+       We also relax the check when we have sync, on the assumption that
+       if we're not looking at random data, we have a much higher chance
+       to get the correct sync, and this avoids losing two frames when
+       a single bit corruption happens. */
+    if (drain || !GST_BASE_PARSE_LOST_SYNC (aacparse)) {
+      return TRUE;
+    }
+
+    if (*framesize + ADTS_MAX_SIZE > avail) {
+      /* We have found a possible frame header candidate, but can't be
+         sure since we don't have enough data to check the next frame */
+      GST_DEBUG ("NEED MORE DATA: we need %d, available %d",
+          *framesize + ADTS_MAX_SIZE, avail);
+      *needed_data = *framesize + ADTS_MAX_SIZE;
+      gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
+          *framesize + ADTS_MAX_SIZE);
+      return FALSE;
+    }
+
+    if ((data[*framesize] == 0xff) && ((data[*framesize + 1] & 0xf6) == 0xf0)) {
+      guint nextlen = gst_aac_parse_adts_get_frame_len (data + (*framesize));
+
+      GST_LOG ("ADTS frame found, len: %d bytes", *framesize);
+      gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
+          nextlen + ADTS_MAX_SIZE);
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+static gboolean
+gst_aac_parse_latm_get_value (GstAacParse * aacparse, GstBitReader * br,
+    guint32 * value)
+{
+  guint8 bytes, i, byte;
+
+  *value = 0;
+  if (!gst_bit_reader_get_bits_uint8 (br, &bytes, 2))
+    return FALSE;
+  for (i = 0; i <= bytes; ++i) {
+    *value <<= 8;
+    if (!gst_bit_reader_get_bits_uint8 (br, &byte, 8))
+      return FALSE;
+    *value += byte;
+  }
+  return TRUE;
+}
+
+static gboolean
+gst_aac_parse_get_audio_object_type (GstAacParse * aacparse, GstBitReader * br,
+    guint8 * audio_object_type)
+{
+  if (!gst_bit_reader_get_bits_uint8 (br, audio_object_type, 5))
+    return FALSE;
+  if (*audio_object_type == 31) {
+    if (!gst_bit_reader_get_bits_uint8 (br, audio_object_type, 6))
+      return FALSE;
+    *audio_object_type += 32;
+  }
+  GST_LOG_OBJECT (aacparse, "audio object type %u", *audio_object_type);
+  return TRUE;
+}
+
+static gboolean
+gst_aac_parse_get_audio_sample_rate (GstAacParse * aacparse, GstBitReader * br,
+    gint * sample_rate)
+{
+  guint8 sampling_frequency_index;
+  if (!gst_bit_reader_get_bits_uint8 (br, &sampling_frequency_index, 4))
+    return FALSE;
+  GST_LOG_OBJECT (aacparse, "sampling_frequency_index: %u",
+      sampling_frequency_index);
+  if (sampling_frequency_index == 0xf) {
+    guint32 sampling_rate;
+    if (!gst_bit_reader_get_bits_uint32 (br, &sampling_rate, 24))
+      return FALSE;
+    *sample_rate = sampling_rate;
+  } else {
+    *sample_rate = loas_sample_rate_table[sampling_frequency_index];
+    if (!*sample_rate)
+      return FALSE;
+  }
+  aacparse->last_parsed_sample_rate = *sample_rate;
+  return TRUE;
+}
+
+/* See table 1.13 in ISO/IEC 14496-3 */
+static gboolean
+gst_aac_parse_read_audio_specific_config (GstAacParse * aacparse,
+    GstBitReader * br, gint * object_type, gint * sample_rate, gint * channels,
+    gint * frame_samples)
+{
+  guint8 audio_object_type;
+  guint8 G_GNUC_UNUSED extension_audio_object_type;
+  guint8 channel_configuration, extension_channel_configuration;
+  gboolean G_GNUC_UNUSED sbr = FALSE, ps = FALSE;
+
+  if (!gst_aac_parse_get_audio_object_type (aacparse, br, &audio_object_type))
+    return FALSE;
+  if (object_type)
+    *object_type = audio_object_type;
+
+  if (!gst_aac_parse_get_audio_sample_rate (aacparse, br, sample_rate))
+    return FALSE;
+
+  if (!gst_bit_reader_get_bits_uint8 (br, &channel_configuration, 4))
+    return FALSE;
+  *channels = loas_channels_table[channel_configuration];
+  GST_LOG_OBJECT (aacparse, "channel_configuration: %d", channel_configuration);
+  if (!*channels)
+    return FALSE;
+
+  if (audio_object_type == 5 || audio_object_type == 29) {
+    extension_audio_object_type = 5;
+    sbr = TRUE;
+    if (audio_object_type == 29) {
+      ps = TRUE;
+      /* Parametric stereo. If we have a one-channel configuration, we can
+       * override it to stereo */
+      if (*channels == 1)
+        *channels = 2;
+    }
+
+    GST_LOG_OBJECT (aacparse,
+        "Audio object type 5 or 29, so rereading sampling rate (was %d)...",
+        *sample_rate);
+    if (!gst_aac_parse_get_audio_sample_rate (aacparse, br, sample_rate))
+      return FALSE;
+
+    if (!gst_aac_parse_get_audio_object_type (aacparse, br, &audio_object_type))
+      return FALSE;
+
+    if (audio_object_type == 22) {
+      /* extension channel configuration */
+      if (!gst_bit_reader_get_bits_uint8 (br, &extension_channel_configuration,
+              4))
+        return FALSE;
+      GST_LOG_OBJECT (aacparse, "extension channel_configuration: %d",
+          extension_channel_configuration);
+      *channels = loas_channels_table[extension_channel_configuration];
+      if (!*channels)
+        return FALSE;
+    }
+  } else {
+    extension_audio_object_type = 0;
+  }
+
+  GST_INFO_OBJECT (aacparse, "Parsed AudioSpecificConfig: %d Hz, %d channels",
+      *sample_rate, *channels);
+
+  if (frame_samples && audio_object_type == 23) {
+    guint8 frame_flag;
+    /* Read the Decoder Configuration (GASpecificConfig) if present */
+    /* We only care about the first bit to know what the number of samples
+     * in a frame is */
+    if (!gst_bit_reader_get_bits_uint8 (br, &frame_flag, 1))
+      return FALSE;
+    *frame_samples = frame_flag ? 960 : 1024;
+  }
+
+  /* There's LOTS of stuff next, but we ignore it for now as we have
+     what we want (sample rate and number of channels */
+  GST_DEBUG_OBJECT (aacparse,
+      "Need more code to parse humongous LOAS data, currently ignored");
+  aacparse->last_parsed_channels = *channels;
+  return TRUE;
+}
+
+
+static gboolean
+gst_aac_parse_read_loas_config (GstAacParse * aacparse, const guint8 * data,
+    guint avail, gint * sample_rate, gint * channels, gint * version)
+{
+  GstBitReader br;
+  guint8 u8, v, vA;
+
+  /* No version in the bitstream, but the spec has LOAS in the MPEG-4 section */
+  if (version)
+    *version = 4;
+
+  gst_bit_reader_init (&br, data, avail);
+
+  /* skip sync word (11 bits) and size (13 bits) */
+  if (!gst_bit_reader_skip (&br, 11 + 13))
+    return FALSE;
+
+  /* First bit is "use last config" */
+  if (!gst_bit_reader_get_bits_uint8 (&br, &u8, 1))
+    return FALSE;
+  if (u8) {
+    GST_LOG_OBJECT (aacparse, "Frame uses previous config");
+    if (!aacparse->last_parsed_sample_rate || !aacparse->last_parsed_channels) {
+      GST_DEBUG_OBJECT (aacparse,
+          "No previous config to use. We'll look for more data.");
+      return FALSE;
+    }
+    *sample_rate = aacparse->last_parsed_sample_rate;
+    *channels = aacparse->last_parsed_channels;
+    return TRUE;
+  }
+
+  GST_DEBUG_OBJECT (aacparse, "Frame contains new config");
+
+  /* audioMuxVersion */
+  if (!gst_bit_reader_get_bits_uint8 (&br, &v, 1))
+    return FALSE;
+  if (v) {
+    /* audioMuxVersionA */
+    if (!gst_bit_reader_get_bits_uint8 (&br, &vA, 1))
+      return FALSE;
+  } else
+    vA = 0;
+
+  GST_LOG_OBJECT (aacparse, "v %d, vA %d", v, vA);
+  if (vA == 0) {
+    guint8 same_time, subframes, num_program, prog;
+    if (v == 1) {
+      guint32 value;
+      /* taraBufferFullness */
+      if (!gst_aac_parse_latm_get_value (aacparse, &br, &value))
+        return FALSE;
+    }
+    if (!gst_bit_reader_get_bits_uint8 (&br, &same_time, 1))
+      return FALSE;
+    if (!gst_bit_reader_get_bits_uint8 (&br, &subframes, 6))
+      return FALSE;
+    if (!gst_bit_reader_get_bits_uint8 (&br, &num_program, 4))
+      return FALSE;
+    GST_LOG_OBJECT (aacparse, "same_time %d, subframes %d, num_program %d",
+        same_time, subframes, num_program);
+
+    for (prog = 0; prog <= num_program; ++prog) {
+      guint8 num_layer, layer;
+      if (!gst_bit_reader_get_bits_uint8 (&br, &num_layer, 3))
+        return FALSE;
+      GST_LOG_OBJECT (aacparse, "Program %d: %d layers", prog, num_layer);
+
+      for (layer = 0; layer <= num_layer; ++layer) {
+        guint8 use_same_config;
+        if (prog == 0 && layer == 0) {
+          use_same_config = 0;
+        } else {
+          if (!gst_bit_reader_get_bits_uint8 (&br, &use_same_config, 1))
+            return FALSE;
+        }
+        if (!use_same_config) {
+          if (v == 0) {
+            if (!gst_aac_parse_read_audio_specific_config (aacparse, &br, NULL,
+                    sample_rate, channels, NULL))
+              return FALSE;
+          } else {
+            guint32 asc_len;
+            if (!gst_aac_parse_latm_get_value (aacparse, &br, &asc_len))
+              return FALSE;
+            if (!gst_aac_parse_read_audio_specific_config (aacparse, &br, NULL,
+                    sample_rate, channels, NULL))
+              return FALSE;
+            if (!gst_bit_reader_skip (&br, asc_len))
+              return FALSE;
+          }
+        }
+      }
+    }
+    GST_LOG_OBJECT (aacparse, "More data ignored");
+  } else {
+    GST_WARNING_OBJECT (aacparse, "Spec says \"TBD\"...");
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+ * gst_aac_parse_loas_get_frame_len:
+ * @data: block of data containing a LOAS header.
+ *
+ * This function calculates LOAS frame length from the given header.
+ *
+ * Returns: size of the LOAS frame.
+ */
+static inline guint
+gst_aac_parse_loas_get_frame_len (const guint8 * data)
+{
+  return (((data[1] & 0x1f) << 8) | data[2]) + 3;
+}
+
+
+/**
+ * gst_aac_parse_check_loas_frame:
+ * @aacparse: #GstAacParse.
+ * @data: Data to be checked.
+ * @avail: Amount of data passed.
+ * @framesize: If valid LOAS frame was found, this will be set to tell the
+ *             found frame size in bytes.
+ * @needed_data: If frame was not found, this may be set to tell how much
+ *               more data is needed in the next round to detect the frame
+ *               reliably. This may happen when a frame header candidate
+ *               is found but it cannot be guaranteed to be the header without
+ *               peeking the following data.
+ *
+ * Check if the given data contains contains LOAS frame. The algorithm
+ * will examine LOAS frame header and calculate the frame size. Also, another
+ * consecutive LOAS frame header need to be present after the found frame.
+ * Otherwise the data is not considered as a valid LOAS frame. However, this
+ * "extra check" is omitted when EOS has been received. In this case it is
+ * enough when data[0] contains a valid LOAS header.
+ *
+ * This function may set the #needed_data to indicate that a possible frame
+ * candidate has been found, but more data (#needed_data bytes) is needed to
+ * be absolutely sure. When this situation occurs, FALSE will be returned.
+ *
+ * When a valid frame is detected, this function will use
+ * gst_base_parse_set_min_frame_size() function from #GstBaseParse class
+ * to set the needed bytes for next frame.This way next data chunk is already
+ * of correct size.
+ *
+ * LOAS can have three different formats, if I read the spec correctly. Only
+ * one of them is supported here, as the two samples I have use this one.
+ *
+ * Returns: TRUE if the given data contains a valid LOAS header.
+ */
+static gboolean
+gst_aac_parse_check_loas_frame (GstAacParse * aacparse,
+    const guint8 * data, const guint avail, gboolean drain,
+    guint * framesize, guint * needed_data)
+{
+  *needed_data = 0;
+
+  /* 3 byte header */
+  if (G_UNLIKELY (avail < 3)) {
+    *needed_data = 3;
+    return FALSE;
+  }
+
+  if ((data[0] == 0x56) && ((data[1] & 0xe0) == 0xe0)) {
+    *framesize = gst_aac_parse_loas_get_frame_len (data);
+    GST_DEBUG_OBJECT (aacparse, "Found possible %u byte LOAS frame",
+        *framesize);
+
+    /* In EOS mode this is enough. No need to examine the data further.
+       We also relax the check when we have sync, on the assumption that
+       if we're not looking at random data, we have a much higher chance
+       to get the correct sync, and this avoids losing two frames when
+       a single bit corruption happens. */
+    if (drain || !GST_BASE_PARSE_LOST_SYNC (aacparse)) {
+      return TRUE;
+    }
+
+    if (*framesize + LOAS_MAX_SIZE > avail) {
+      /* We have found a possible frame header candidate, but can't be
+         sure since we don't have enough data to check the next frame */
+      GST_DEBUG ("NEED MORE DATA: we need %d, available %d",
+          *framesize + LOAS_MAX_SIZE, avail);
+      *needed_data = *framesize + LOAS_MAX_SIZE;
+      gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
+          *framesize + LOAS_MAX_SIZE);
+      return FALSE;
+    }
+
+    if ((data[*framesize] == 0x56) && ((data[*framesize + 1] & 0xe0) == 0xe0)) {
+      guint nextlen = gst_aac_parse_loas_get_frame_len (data + (*framesize));
+
+      GST_LOG ("LOAS frame found, len: %d bytes", *framesize);
+      gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
+          nextlen + LOAS_MAX_SIZE);
+      return TRUE;
+    } else {
+      GST_DEBUG_OBJECT (aacparse, "That was a false positive");
+    }
+  }
+  return FALSE;
+}
+
+/* caller ensure sufficient data */
+static inline void
+gst_aac_parse_parse_adts_header (GstAacParse * aacparse, const guint8 * data,
+    gint * rate, gint * channels, gint * object, gint * version)
+{
+
+  if (rate) {
+    gint sr_idx = (data[2] & 0x3c) >> 2;
+
+    *rate = gst_codec_utils_aac_get_sample_rate_from_index (sr_idx);
+  }
+  if (channels) {
+    *channels = ((data[2] & 0x01) << 2) | ((data[3] & 0xc0) >> 6);
+    if (*channels == 7)
+      *channels = 8;
+  }
+
+  if (version)
+    *version = (data[1] & 0x08) ? 2 : 4;
+  if (object)
+    *object = ((data[2] & 0xc0) >> 6) + 1;
+}
+
+/**
+ * gst_aac_parse_detect_stream:
+ * @aacparse: #GstAacParse.
+ * @data: A block of data that needs to be examined for stream characteristics.
+ * @avail: Size of the given datablock.
+ * @framesize: If valid stream was found, this will be set to tell the
+ *             first frame size in bytes.
+ * @skipsize: If valid stream was found, this will be set to tell the first
+ *            audio frame position within the given data.
+ *
+ * Examines the given piece of data and try to detect the format of it. It
+ * checks for "ADIF" header (in the beginning of the clip) and ADTS frame
+ * header. If the stream is detected, TRUE will be returned and #framesize
+ * is set to indicate the found frame size. Additionally, #skipsize might
+ * be set to indicate the number of bytes that need to be skipped, a.k.a. the
+ * position of the frame inside given data chunk.
+ *
+ * Returns: TRUE on success.
+ */
+static gboolean
+gst_aac_parse_detect_stream (GstAacParse * aacparse,
+    const guint8 * data, const guint avail, gboolean drain,
+    guint * framesize, gint * skipsize)
+{
+  gboolean found = FALSE;
+  guint need_data_adts = 0, need_data_loas;
+  guint i = 0;
+
+  GST_DEBUG_OBJECT (aacparse, "Parsing header data");
+
+  /* FIXME: No need to check for ADIF if we are not in the beginning of the
+     stream */
+
+  /* Can we even parse the header? */
+  if (avail < MAX (ADTS_MAX_SIZE, LOAS_MAX_SIZE)) {
+    GST_DEBUG_OBJECT (aacparse, "Not enough data to check");
+    return FALSE;
+  }
+
+  for (i = 0; i < avail - 4; i++) {
+    if (((data[i] == 0xff) && ((data[i + 1] & 0xf6) == 0xf0)) ||
+        ((data[i] == 0x56) && ((data[i + 1] & 0xe0) == 0xe0)) ||
+        strncmp ((char *) data + i, "ADIF", 4) == 0) {
+      GST_DEBUG_OBJECT (aacparse, "Found signature at offset %u", i);
+      found = TRUE;
+
+      if (i) {
+        /* Trick: tell the parent class that we didn't find the frame yet,
+           but make it skip 'i' amount of bytes. Next time we arrive
+           here we have full frame in the beginning of the data. */
+        *skipsize = i;
+        return FALSE;
+      }
+      break;
+    }
+  }
+  if (!found) {
+    if (i)
+      *skipsize = i;
+    return FALSE;
+  }
+
+  if (gst_aac_parse_check_adts_frame (aacparse, data, avail, drain,
+          framesize, &need_data_adts)) {
+    gint rate, channels;
+
+    GST_INFO ("ADTS ID: %d, framesize: %d", (data[1] & 0x08) >> 3, *framesize);
+
+    gst_aac_parse_parse_adts_header (aacparse, data, &rate, &channels,
+        &aacparse->object_type, &aacparse->mpegversion);
+
+    if (!channels || !framesize) {
+      GST_DEBUG_OBJECT (aacparse, "impossible ADTS configuration");
+      return FALSE;
+    }
+
+    aacparse->header_type = DSPAAC_HEADER_ADTS;
+    gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse), rate,
+        aacparse->frame_samples, 2, 2);
+
+    GST_DEBUG ("ADTS: samplerate %d, channels %d, objtype %d, version %d",
+        rate, channels, aacparse->object_type, aacparse->mpegversion);
+
+    gst_base_parse_set_syncable (GST_BASE_PARSE (aacparse), TRUE);
+
+    return TRUE;
+  }
+
+  if (gst_aac_parse_check_loas_frame (aacparse, data, avail, drain,
+          framesize, &need_data_loas)) {
+    gint rate = 0, channels = 0;
+
+    GST_INFO ("LOAS, framesize: %d", *framesize);
+
+    aacparse->header_type = DSPAAC_HEADER_LOAS;
+
+    if (!gst_aac_parse_read_loas_config (aacparse, data, avail, &rate,
+            &channels, &aacparse->mpegversion)) {
+      /* This is pretty normal when skipping data at the start of
+       * random stream (MPEG-TS capture for example) */
+      GST_LOG_OBJECT (aacparse, "Error reading LOAS config");
+      return FALSE;
+    }
+
+    if (rate && channels) {
+      gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse), rate,
+          aacparse->frame_samples, 2, 2);
+
+      /* Don't store the sample rate and channels yet -
+       * this is just format detection. */
+      GST_DEBUG ("LOAS: samplerate %d, channels %d, objtype %d, version %d",
+          rate, channels, aacparse->object_type, aacparse->mpegversion);
+    }
+
+    gst_base_parse_set_syncable (GST_BASE_PARSE (aacparse), TRUE);
+
+    return TRUE;
+  }
+
+  if (need_data_adts || need_data_loas) {
+    /* This tells the parent class not to skip any data */
+    *skipsize = 0;
+    return FALSE;
+  }
+
+  if (avail < ADIF_MAX_SIZE)
+    return FALSE;
+
+  if (memcmp (data + i, "ADIF", 4) == 0) {
+    const guint8 *adif;
+    int skip_size = 0;
+    int bitstream_type;
+    int sr_idx;
+    GstCaps *sinkcaps;
+
+    aacparse->header_type = DSPAAC_HEADER_ADIF;
+    aacparse->mpegversion = 4;
+
+    /* Skip the "ADIF" bytes */
+    adif = data + i + 4;
+
+    /* copyright string */
+    if (adif[0] & 0x80)
+      skip_size += 9;           /* skip 9 bytes */
+
+    bitstream_type = adif[0 + skip_size] & 0x10;
+    aacparse->bitrate =
+        ((unsigned int) (adif[0 + skip_size] & 0x0f) << 19) |
+        ((unsigned int) adif[1 + skip_size] << 11) |
+        ((unsigned int) adif[2 + skip_size] << 3) |
+        ((unsigned int) adif[3 + skip_size] & 0xe0);
+
+    /* CBR */
+    if (bitstream_type == 0) {
+#if 0
+      /* Buffer fullness parsing. Currently not needed... */
+      guint num_elems = 0;
+      guint fullness = 0;
+
+      num_elems = (adif[3 + skip_size] & 0x1e);
+      GST_INFO ("ADIF num_config_elems: %d", num_elems);
+
+      fullness = ((unsigned int) (adif[3 + skip_size] & 0x01) << 19) |
+          ((unsigned int) adif[4 + skip_size] << 11) |
+          ((unsigned int) adif[5 + skip_size] << 3) |
+          ((unsigned int) (adif[6 + skip_size] & 0xe0) >> 5);
+
+      GST_INFO ("ADIF buffer fullness: %d", fullness);
+#endif
+      aacparse->object_type = ((adif[6 + skip_size] & 0x01) << 1) |
+          ((adif[7 + skip_size] & 0x80) >> 7);
+      sr_idx = (adif[7 + skip_size] & 0x78) >> 3;
+    }
+    /* VBR */
+    else {
+      aacparse->object_type = (adif[4 + skip_size] & 0x18) >> 3;
+      sr_idx = ((adif[4 + skip_size] & 0x07) << 1) |
+          ((adif[5 + skip_size] & 0x80) >> 7);
+    }
+
+    /* FIXME: This gives totally wrong results. Duration calculation cannot
+       be based on this */
+    aacparse->sample_rate =
+        gst_codec_utils_aac_get_sample_rate_from_index (sr_idx);
+
+    /* baseparse is not given any fps,
+     * so it will give up on timestamps, seeking, etc */
+
+    /* FIXME: Can we assume this? */
+    aacparse->channels = 2;
+
+    GST_INFO ("ADIF: br=%d, samplerate=%d, objtype=%d",
+        aacparse->bitrate, aacparse->sample_rate, aacparse->object_type);
+
+    gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), 512);
+
+    /* arrange for metadata and get out of the way */
+    sinkcaps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (aacparse));
+    gst_aac_parse_set_src_caps (aacparse, sinkcaps);
+    if (sinkcaps)
+      gst_caps_unref (sinkcaps);
+
+    /* not syncable, not easily seekable (unless we push data from start */
+    gst_base_parse_set_syncable (GST_BASE_PARSE_CAST (aacparse), FALSE);
+    gst_base_parse_set_passthrough (GST_BASE_PARSE_CAST (aacparse), TRUE);
+    gst_base_parse_set_average_bitrate (GST_BASE_PARSE_CAST (aacparse), 0);
+
+    *framesize = avail;
+    return TRUE;
+  }
+
+  /* This should never happen */
+  return FALSE;
+}
+
+/**
+ * gst_aac_parse_get_audio_profile_object_type
+ * @aacparse: #GstAacParse.
+ *
+ * Gets the MPEG-2 profile or the MPEG-4 object type value corresponding to the
+ * mpegversion and profile of @aacparse's src pad caps, according to the
+ * values defined by table 1.A.11 in ISO/IEC 14496-3.
+ *
+ * Returns: the profile or object type value corresponding to @aacparse's src
+ * pad caps, if such a value exists; otherwise G_MAXUINT8.
+ */
+static guint8
+gst_aac_parse_get_audio_profile_object_type (GstAacParse * aacparse)
+{
+  GstCaps *srccaps;
+  GstStructure *srcstruct;
+  const gchar *profile;
+  guint8 ret;
+
+  srccaps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (aacparse));
+  if (G_UNLIKELY (srccaps == NULL)) {
+    return G_MAXUINT8;
+  }
+
+  srcstruct = gst_caps_get_structure (srccaps, 0);
+  profile = gst_structure_get_string (srcstruct, "profile");
+  if (G_UNLIKELY (profile == NULL)) {
+    gst_caps_unref (srccaps);
+    return G_MAXUINT8;
+  }
+
+  if (g_strcmp0 (profile, "main") == 0) {
+    ret = (guint8) 0U;
+  } else if (g_strcmp0 (profile, "lc") == 0) {
+    ret = (guint8) 1U;
+  } else if (g_strcmp0 (profile, "ssr") == 0) {
+    ret = (guint8) 2U;
+  } else if (g_strcmp0 (profile, "ltp") == 0) {
+    if (G_LIKELY (aacparse->mpegversion == 4))
+      ret = (guint8) 3U;
+    else
+      ret = G_MAXUINT8;         /* LTP Object Type allowed only for MPEG-4 */
+  } else {
+    ret = G_MAXUINT8;
+  }
+
+  gst_caps_unref (srccaps);
+  return ret;
+}
+
+/**
+ * gst_aac_parse_get_audio_channel_configuration
+ * @num_channels: number of audio channels.
+ *
+ * Gets the Channel Configuration value, as defined by table 1.19 in ISO/IEC
+ * 14496-3, for a given number of audio channels.
+ *
+ * Returns: the Channel Configuration value corresponding to @num_channels, if
+ * such a value exists; otherwise G_MAXUINT8.
+ */
+static guint8
+gst_aac_parse_get_audio_channel_configuration (gint num_channels)
+{
+  if (num_channels >= 1 && num_channels <= 6)   /* Mono up to & including 5.1 */
+    return (guint8) num_channels;
+  else if (num_channels == 8)   /* 7.1 */
+    return (guint8) 7U;
+  else
+    return G_MAXUINT8;
+
+  /* FIXME: Add support for configurations 11, 12 and 14 from
+   * ISO/IEC 14496-3:2009/PDAM 4 based on the actual channel layout
+   */
+}
+
+/**
+ * gst_aac_parse_get_audio_sampling_frequency_index:
+ * @sample_rate: audio sampling rate.
+ *
+ * Gets the Sampling Frequency Index value, as defined by table 1.18 in ISO/IEC
+ * 14496-3, for a given sampling rate.
+ *
+ * Returns: the Sampling Frequency Index value corresponding to @sample_rate,
+ * if such a value exists; otherwise G_MAXUINT8.
+ */
+static guint8
+gst_aac_parse_get_audio_sampling_frequency_index (gint sample_rate)
+{
+  switch (sample_rate) {
+    case 96000:
+      return 0x0U;
+    case 88200:
+      return 0x1U;
+    case 64000:
+      return 0x2U;
+    case 48000:
+      return 0x3U;
+    case 44100:
+      return 0x4U;
+    case 32000:
+      return 0x5U;
+    case 24000:
+      return 0x6U;
+    case 22050:
+      return 0x7U;
+    case 16000:
+      return 0x8U;
+    case 12000:
+      return 0x9U;
+    case 11025:
+      return 0xAU;
+    case 8000:
+      return 0xBU;
+    case 7350:
+      return 0xCU;
+    default:
+      return G_MAXUINT8;
+  }
+}
+
+/**
+ * gst_aac_parse_prepend_adts_headers:
+ * @aacparse: #GstAacParse.
+ * @frame: raw AAC frame to which ADTS headers shall be prepended.
+ *
+ * Prepends ADTS headers to a raw AAC audio frame.
+ *
+ * Returns: TRUE if ADTS headers were successfully prepended; FALSE otherwise.
+ */
+static gboolean
+gst_aac_parse_prepend_adts_headers (GstAacParse * aacparse,
+    GstBaseParseFrame * frame)
+{
+  GstMemory *mem;
+  guint8 *adts_headers;
+  gsize buf_size;
+  gsize frame_size;
+  guint8 id, profile, channel_configuration, sampling_frequency_index;
+
+  id = (aacparse->mpegversion == 4) ? 0x0U : 0x1U;
+  profile = gst_aac_parse_get_audio_profile_object_type (aacparse);
+  if (profile == G_MAXUINT8) {
+    GST_ERROR_OBJECT (aacparse, "Unsupported audio profile or object type");
+    return FALSE;
+  }
+  channel_configuration =
+      gst_aac_parse_get_audio_channel_configuration (aacparse->channels);
+  if (channel_configuration == G_MAXUINT8) {
+    GST_ERROR_OBJECT (aacparse, "Unsupported number of channels");
+    return FALSE;
+  }
+  sampling_frequency_index =
+      gst_aac_parse_get_audio_sampling_frequency_index (aacparse->sample_rate);
+  if (sampling_frequency_index == G_MAXUINT8) {
+    GST_ERROR_OBJECT (aacparse, "Unsupported sampling frequency");
+    return FALSE;
+  }
+
+  frame->out_buffer = gst_buffer_copy (frame->buffer);
+  buf_size = gst_buffer_get_size (frame->out_buffer);
+  frame_size = buf_size + ADTS_HEADERS_LENGTH;
+
+  if (G_UNLIKELY (frame_size >= 0x4000)) {
+    GST_ERROR_OBJECT (aacparse, "Frame size is too big for ADTS");
+    return FALSE;
+  }
+
+  adts_headers = (guint8 *) g_malloc0 (ADTS_HEADERS_LENGTH);
+
+  /* Note: no error correction bits are added to the resulting ADTS frames */
+  adts_headers[0] = 0xFFU;
+  adts_headers[1] = 0xF0U | (id << 3) | 0x1U;
+  adts_headers[2] = (profile << 6) | (sampling_frequency_index << 2) | 0x2U |
+      (channel_configuration & 0x4U);
+  adts_headers[3] = ((channel_configuration & 0x3U) << 6) | 0x30U |
+      (guint8) (frame_size >> 11);
+  adts_headers[4] = (guint8) ((frame_size >> 3) & 0x00FF);
+  adts_headers[5] = (guint8) (((frame_size & 0x0007) << 5) + 0x1FU);
+  adts_headers[6] = 0xFCU;
+
+  mem = gst_memory_new_wrapped (0, adts_headers, ADTS_HEADERS_LENGTH, 0,
+      ADTS_HEADERS_LENGTH, adts_headers, g_free);
+  gst_buffer_prepend_memory (frame->out_buffer, mem);
+
+  return TRUE;
+}
+
+/**
+ * gst_aac_parse_check_valid_frame:
+ * @parse: #GstBaseParse.
+ * @frame: #GstBaseParseFrame.
+ * @skipsize: How much data parent class should skip in order to find the
+ *            frame header.
+ *
+ * Implementation of "handle_frame" vmethod in #GstBaseParse class.
+ *
+ * Also determines frame overhead.
+ * ADTS streams have a 7 byte header in each frame. MP4 and ADIF streams don't have
+ * a per-frame header. LOAS has 3 bytes.
+ *
+ * We're making a couple of simplifying assumptions:
+ *
+ * 1. We count Program Configuration Elements rather than searching for them
+ *    in the streams to discount them - the overhead is negligible.
+ *
+ * 2. We ignore CRC. This has a worst-case impact of (num_raw_blocks + 1)*16
+ *    bits, which should still not be significant enough to warrant the
+ *    additional parsing through the headers
+ *
+ * Returns: a #GstFlowReturn.
+ */
+static GstFlowReturn
+gst_aac_parse_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize)
+{
+  GstMapInfo map;
+  GstAacParse *aacparse;
+  gboolean ret = FALSE;
+  gboolean lost_sync;
+  GstBuffer *buffer;
+  guint framesize;
+  gint rate = 0, channels = 0;
+
+  aacparse = GST_AAC_PARSE (parse);
+  buffer = frame->buffer;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  *skipsize = -1;
+  lost_sync = GST_BASE_PARSE_LOST_SYNC (parse);
+
+  if (aacparse->header_type == DSPAAC_HEADER_ADIF ||
+      aacparse->header_type == DSPAAC_HEADER_NONE) {
+    /* There is nothing to parse */
+    framesize = map.size;
+    ret = TRUE;
+
+  } else if (aacparse->header_type == DSPAAC_HEADER_NOT_PARSED || lost_sync) {
+
+    ret = gst_aac_parse_detect_stream (aacparse, map.data, map.size,
+        GST_BASE_PARSE_DRAINING (parse), &framesize, skipsize);
+
+  } else if (aacparse->header_type == DSPAAC_HEADER_ADTS) {
+    guint needed_data = 1024;
+
+    ret = gst_aac_parse_check_adts_frame (aacparse, map.data, map.size,
+        GST_BASE_PARSE_DRAINING (parse), &framesize, &needed_data);
+
+    if (!ret && needed_data) {
+      GST_DEBUG ("buffer didn't contain valid frame");
+      *skipsize = 0;
+      gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
+          needed_data);
+    }
+
+  } else if (aacparse->header_type == DSPAAC_HEADER_LOAS) {
+    guint needed_data = 1024;
+
+    ret = gst_aac_parse_check_loas_frame (aacparse, map.data,
+        map.size, GST_BASE_PARSE_DRAINING (parse), &framesize, &needed_data);
+
+    if (!ret && needed_data) {
+      GST_DEBUG ("buffer didn't contain valid frame");
+      *skipsize = 0;
+      gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
+          needed_data);
+    }
+
+  } else {
+    GST_DEBUG ("buffer didn't contain valid frame");
+    gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
+        ADTS_MAX_SIZE);
+  }
+
+  if (G_UNLIKELY (!ret))
+    goto exit;
+
+  if (aacparse->header_type == DSPAAC_HEADER_ADTS) {
+    /* see above */
+    frame->overhead = 7;
+
+    gst_aac_parse_parse_adts_header (aacparse, map.data,
+        &rate, &channels, NULL, NULL);
+
+    GST_LOG_OBJECT (aacparse, "rate: %d, chans: %d", rate, channels);
+
+    if (G_UNLIKELY (rate != aacparse->sample_rate
+            || channels != aacparse->channels)) {
+      aacparse->sample_rate = rate;
+      aacparse->channels = channels;
+
+      if (!gst_aac_parse_set_src_caps (aacparse, NULL)) {
+        /* If linking fails, we need to return appropriate error */
+        ret = GST_FLOW_NOT_LINKED;
+      }
+
+      gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse),
+          aacparse->sample_rate, aacparse->frame_samples, 2, 2);
+    }
+  } else if (aacparse->header_type == DSPAAC_HEADER_LOAS) {
+    gboolean setcaps = FALSE;
+
+    /* see above */
+    frame->overhead = 3;
+
+    if (!gst_aac_parse_read_loas_config (aacparse, map.data, map.size, &rate,
+            &channels, NULL) || !rate || !channels) {
+      /* This is pretty normal when skipping data at the start of
+       * random stream (MPEG-TS capture for example) */
+      GST_DEBUG_OBJECT (aacparse, "Error reading LOAS config. Skipping.");
+      /* Since we don't fully parse the LOAS config, we don't know for sure
+       * how much to skip. Just skip 1 to end up to the next marker and
+       * resume parsing from there */
+      *skipsize = 1;
+      goto exit;
+    }
+
+    if (G_UNLIKELY (rate != aacparse->sample_rate
+            || channels != aacparse->channels)) {
+      aacparse->sample_rate = rate;
+      aacparse->channels = channels;
+      setcaps = TRUE;
+      GST_INFO_OBJECT (aacparse, "New LOAS config: %d Hz, %d channels", rate,
+          channels);
+    }
+
+    /* We want to set caps both at start, and when rate/channels change.
+       Since only some LOAS frames have that info, we may receive frames
+       before knowing about rate/channels. */
+    if (setcaps
+        || !gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (aacparse))) {
+      if (!gst_aac_parse_set_src_caps (aacparse, NULL)) {
+        /* If linking fails, we need to return appropriate error */
+        ret = GST_FLOW_NOT_LINKED;
+      }
+
+      gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse),
+          aacparse->sample_rate, aacparse->frame_samples, 2, 2);
+    }
+  }
+
+  if (aacparse->header_type == DSPAAC_HEADER_NONE
+      && aacparse->output_header_type == DSPAAC_HEADER_ADTS) {
+    if (!gst_aac_parse_prepend_adts_headers (aacparse, frame)) {
+      GST_ERROR_OBJECT (aacparse, "Failed to prepend ADTS headers to frame");
+      ret = GST_FLOW_ERROR;
+    }
+  }
+
+exit:
+  gst_buffer_unmap (buffer, &map);
+
+  if (ret) {
+    /* found, skip if needed */
+    if (*skipsize > 0)
+      return GST_FLOW_OK;
+    *skipsize = 0;
+  } else {
+    if (*skipsize < 0)
+      *skipsize = 1;
+  }
+
+  if (ret && framesize <= map.size) {
+    return gst_base_parse_finish_frame (parse, frame, framesize);
+  }
+
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_aac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
+{
+  GstAacParse *aacparse = GST_AAC_PARSE (parse);
+
+  if (!aacparse->sent_codec_tag) {
+    GstTagList *taglist;
+    GstCaps *caps;
+
+    /* codec tag */
+    caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
+    if (caps == NULL) {
+      if (GST_PAD_IS_FLUSHING (GST_BASE_PARSE_SRC_PAD (parse))) {
+        GST_INFO_OBJECT (parse, "Src pad is flushing");
+        return GST_FLOW_FLUSHING;
+      } else {
+        GST_INFO_OBJECT (parse, "Src pad is not negotiated!");
+        return GST_FLOW_NOT_NEGOTIATED;
+      }
+    }
+
+    taglist = gst_tag_list_new_empty ();
+    gst_pb_utils_add_codec_description_to_tag_list (taglist,
+        GST_TAG_AUDIO_CODEC, caps);
+    gst_caps_unref (caps);
+
+    gst_base_parse_merge_tags (parse, taglist, GST_TAG_MERGE_REPLACE);
+    gst_tag_list_unref (taglist);
+
+    /* also signals the end of first-frame processing */
+    aacparse->sent_codec_tag = TRUE;
+  }
+
+  /* As a special case, we can remove the ADTS framing and output raw AAC. */
+  if (aacparse->header_type == DSPAAC_HEADER_ADTS
+      && aacparse->output_header_type == DSPAAC_HEADER_NONE) {
+    guint header_size;
+    GstMapInfo map;
+    frame->out_buffer = gst_buffer_make_writable (frame->buffer);
+    frame->buffer = NULL;
+    gst_buffer_map (frame->out_buffer, &map, GST_MAP_READ);
+    header_size = (map.data[1] & 1) ? 7 : 9;    /* optional CRC */
+    gst_buffer_unmap (frame->out_buffer, &map);
+    gst_buffer_resize (frame->out_buffer, header_size,
+        gst_buffer_get_size (frame->out_buffer) - header_size);
+  }
+
+  return GST_FLOW_OK;
+}
+
+
+/**
+ * gst_aac_parse_start:
+ * @parse: #GstBaseParse.
+ *
+ * Implementation of "start" vmethod in #GstBaseParse class.
+ *
+ * Returns: TRUE if startup succeeded.
+ */
+static gboolean
+gst_aac_parse_start (GstBaseParse * parse)
+{
+  GstAacParse *aacparse;
+
+  aacparse = GST_AAC_PARSE (parse);
+  GST_DEBUG ("start");
+  aacparse->frame_samples = 1024;
+  gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), ADTS_MAX_SIZE);
+  aacparse->sent_codec_tag = FALSE;
+  aacparse->last_parsed_channels = 0;
+  aacparse->last_parsed_sample_rate = 0;
+  aacparse->object_type = 0;
+  aacparse->bitrate = 0;
+  aacparse->header_type = DSPAAC_HEADER_NOT_PARSED;
+  aacparse->output_header_type = DSPAAC_HEADER_NOT_PARSED;
+  aacparse->channels = 0;
+  aacparse->sample_rate = 0;
+  return TRUE;
+}
+
+
+/**
+ * gst_aac_parse_stop:
+ * @parse: #GstBaseParse.
+ *
+ * Implementation of "stop" vmethod in #GstBaseParse class.
+ *
+ * Returns: TRUE is stopping succeeded.
+ */
+static gboolean
+gst_aac_parse_stop (GstBaseParse * parse)
+{
+  GST_DEBUG ("stop");
+  return TRUE;
+}
+
+static void
+remove_fields (GstCaps * caps)
+{
+  guint i, n;
+
+  n = gst_caps_get_size (caps);
+  for (i = 0; i < n; i++) {
+    GstStructure *s = gst_caps_get_structure (caps, i);
+
+    gst_structure_remove_field (s, "framed");
+  }
+}
+
+static void
+add_conversion_fields (GstCaps * caps)
+{
+  guint i, n;
+
+  n = gst_caps_get_size (caps);
+  for (i = 0; i < n; i++) {
+    GstStructure *s = gst_caps_get_structure (caps, i);
+
+    if (gst_structure_has_field (s, "stream-format")) {
+      const GValue *v = gst_structure_get_value (s, "stream-format");
+
+      if (G_VALUE_HOLDS_STRING (v)) {
+        const gchar *str = g_value_get_string (v);
+
+        if (strcmp (str, "adts") == 0 || strcmp (str, "raw") == 0) {
+          GValue va = G_VALUE_INIT;
+          GValue vs = G_VALUE_INIT;
+
+          g_value_init (&va, GST_TYPE_LIST);
+          g_value_init (&vs, G_TYPE_STRING);
+          g_value_set_string (&vs, "adts");
+          gst_value_list_append_value (&va, &vs);
+          g_value_set_string (&vs, "raw");
+          gst_value_list_append_value (&va, &vs);
+          gst_structure_set_value (s, "stream-format", &va);
+          g_value_unset (&va);
+          g_value_unset (&vs);
+        }
+      } else if (GST_VALUE_HOLDS_LIST (v)) {
+        gboolean contains_raw = FALSE;
+        gboolean contains_adts = FALSE;
+        guint m = gst_value_list_get_size (v), j;
+
+        for (j = 0; j < m; j++) {
+          const GValue *ve = gst_value_list_get_value (v, j);
+          const gchar *str;
+
+          if (G_VALUE_HOLDS_STRING (ve) && (str = g_value_get_string (ve))) {
+            if (strcmp (str, "adts") == 0)
+              contains_adts = TRUE;
+            else if (strcmp (str, "raw") == 0)
+              contains_raw = TRUE;
+          }
+        }
+
+        if (contains_adts || contains_raw) {
+          GValue va = G_VALUE_INIT;
+          GValue vs = G_VALUE_INIT;
+
+          g_value_init (&va, GST_TYPE_LIST);
+          g_value_init (&vs, G_TYPE_STRING);
+          g_value_copy (v, &va);
+
+          if (!contains_raw) {
+            g_value_set_string (&vs, "raw");
+            gst_value_list_append_value (&va, &vs);
+          }
+          if (!contains_adts) {
+            g_value_set_string (&vs, "adts");
+            gst_value_list_append_value (&va, &vs);
+          }
+
+          gst_structure_set_value (s, "stream-format", &va);
+
+          g_value_unset (&vs);
+          g_value_unset (&va);
+        }
+      }
+    }
+  }
+}
+
+static GstCaps *
+gst_aac_parse_sink_getcaps (GstBaseParse * parse, GstCaps * filter)
+{
+  GstCaps *peercaps, *templ;
+  GstCaps *res;
+
+  templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
+
+  if (filter) {
+    GstCaps *fcopy = gst_caps_copy (filter);
+    /* Remove the fields we convert */
+    remove_fields (fcopy);
+    add_conversion_fields (fcopy);
+    peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
+    gst_caps_unref (fcopy);
+  } else
+    peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), NULL);
+
+  if (peercaps) {
+    peercaps = gst_caps_make_writable (peercaps);
+    /* Remove the fields we convert */
+    remove_fields (peercaps);
+    add_conversion_fields (peercaps);
+
+    res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (peercaps);
+    gst_caps_unref (templ);
+  } else {
+    res = templ;
+  }
+
+  if (filter) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (res);
+    res = intersection;
+  }
+
+  return res;
+}
+
+static gboolean
+gst_aac_parse_src_event (GstBaseParse * parse, GstEvent * event)
+{
+  GstAacParse *aacparse = GST_AAC_PARSE (parse);
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
+    aacparse->last_parsed_channels = 0;
+    aacparse->last_parsed_sample_rate = 0;
+  }
+
+  return GST_BASE_PARSE_CLASS (parent_class)->src_event (parse, event);
+}
diff --git a/gst/audioparsers/gstaacparse.h b/gst/audioparsers/gstaacparse.h
new file mode 100644
index 0000000..40c96ff
--- /dev/null
+++ b/gst/audioparsers/gstaacparse.h
@@ -0,0 +1,105 @@
+/* GStreamer AAC parser
+ * Copyright (C) 2008 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AAC_PARSE_H__
+#define __GST_AAC_PARSE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbaseparse.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AAC_PARSE \
+  (gst_aac_parse_get_type())
+#define GST_AAC_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AAC_PARSE, GstAacParse))
+#define GST_AAC_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_AAC_PARSE, GstAacParseClass))
+#define GST_IS_AAC_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_AAC_PARSE))
+#define GST_IS_AAC_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_AAC_PARSE))
+
+
+/**
+ * GstAacHeaderType:
+ * @DSPAAC_HEADER_NOT_PARSED: Header not parsed yet.
+ * @DSPAAC_HEADER_UNKNOWN: Unknown (not recognized) header.
+ * @DSPAAC_HEADER_ADIF: ADIF header found.
+ * @DSPAAC_HEADER_ADTS: ADTS header found.
+ * @DSPAAC_HEADER_LOAS: LOAS header found.
+ * @DSPAAC_HEADER_NONE: Raw stream, no header.
+ *
+ * Type header enumeration set in #header_type.
+ */
+typedef enum {
+  DSPAAC_HEADER_NOT_PARSED,
+  DSPAAC_HEADER_UNKNOWN,
+  DSPAAC_HEADER_ADIF,
+  DSPAAC_HEADER_ADTS,
+  DSPAAC_HEADER_LOAS,
+  DSPAAC_HEADER_NONE
+} GstAacHeaderType;
+
+
+typedef struct _GstAacParse GstAacParse;
+typedef struct _GstAacParseClass GstAacParseClass;
+
+/**
+ * GstAacParse:
+ *
+ * The opaque GstAacParse data structure.
+ */
+struct _GstAacParse {
+  GstBaseParse element;
+
+  /* Stream type -related info */
+  gint           object_type;
+  gint           bitrate;
+  gint           sample_rate;
+  gint           channels;
+  gint           mpegversion;
+  gint           frame_samples;
+
+  GstAacHeaderType header_type;
+  GstAacHeaderType output_header_type;
+
+  gboolean sent_codec_tag;
+
+  gint last_parsed_sample_rate;
+  gint last_parsed_channels;
+};
+
+/**
+ * GstAacParseClass:
+ * @parent_class: Element parent class.
+ *
+ * The opaque GstAacParseClass data structure.
+ */
+struct _GstAacParseClass {
+  GstBaseParseClass parent_class;
+};
+
+GType gst_aac_parse_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_AAC_PARSE_H__ */
diff --git a/gst/audioparsers/gstac3parse.c b/gst/audioparsers/gstac3parse.c
new file mode 100644
index 0000000..afc8770
--- /dev/null
+++ b/gst/audioparsers/gstac3parse.c
@@ -0,0 +1,953 @@
+/* GStreamer AC3 parser
+ * Copyright (C) 2009 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2009 Mark Nauwelaerts <mnauw users sf net>
+ * Copyright (C) 2009 Nokia Corporation. All rights reserved.
+ *   Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-ac3parse
+ * @short_description: AC3 parser
+ * @see_also: #GstAmrParse, #GstAACParse
+ *
+ * This is an AC3 parser.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=abc.ac3 ! ac3parse ! a52dec ! audioresample ! audioconvert ! autoaudiosink
+ * ]|
+ * </refsect2>
+ */
+
+/* TODO:
+ *  - audio/ac3 to audio/x-private1-ac3 is not implemented (done in the muxer)
+ *  - should accept framed and unframed input (needs decodebin fixes first)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstac3parse.h"
+#include <gst/base/base.h>
+#include <gst/pbutils/pbutils.h>
+
+GST_DEBUG_CATEGORY_STATIC (ac3_parse_debug);
+#define GST_CAT_DEFAULT ac3_parse_debug
+
+static const struct
+{
+  const guint bit_rate;         /* nominal bit rate */
+  const guint frame_size[3];    /* frame size for 32kHz, 44kHz, and 48kHz */
+} frmsizcod_table[38] = {
+  {
+    32, {
+  64, 69, 96}}, {
+    32, {
+  64, 70, 96}}, {
+    40, {
+  80, 87, 120}}, {
+    40, {
+  80, 88, 120}}, {
+    48, {
+  96, 104, 144}}, {
+    48, {
+  96, 105, 144}}, {
+    56, {
+  112, 121, 168}}, {
+    56, {
+  112, 122, 168}}, {
+    64, {
+  128, 139, 192}}, {
+    64, {
+  128, 140, 192}}, {
+    80, {
+  160, 174, 240}}, {
+    80, {
+  160, 175, 240}}, {
+    96, {
+  192, 208, 288}}, {
+    96, {
+  192, 209, 288}}, {
+    112, {
+  224, 243, 336}}, {
+    112, {
+  224, 244, 336}}, {
+    128, {
+  256, 278, 384}}, {
+    128, {
+  256, 279, 384}}, {
+    160, {
+  320, 348, 480}}, {
+    160, {
+  320, 349, 480}}, {
+    192, {
+  384, 417, 576}}, {
+    192, {
+  384, 418, 576}}, {
+    224, {
+  448, 487, 672}}, {
+    224, {
+  448, 488, 672}}, {
+    256, {
+  512, 557, 768}}, {
+    256, {
+  512, 558, 768}}, {
+    320, {
+  640, 696, 960}}, {
+    320, {
+  640, 697, 960}}, {
+    384, {
+  768, 835, 1152}}, {
+    384, {
+  768, 836, 1152}}, {
+    448, {
+  896, 975, 1344}}, {
+    448, {
+  896, 976, 1344}}, {
+    512, {
+  1024, 1114, 1536}}, {
+    512, {
+  1024, 1115, 1536}}, {
+    576, {
+  1152, 1253, 1728}}, {
+    576, {
+  1152, 1254, 1728}}, {
+    640, {
+  1280, 1393, 1920}}, {
+    640, {
+  1280, 1394, 1920}}
+};
+
+static const guint fscod_rates[4] = { 48000, 44100, 32000, 0 };
+static const guint acmod_chans[8] = { 2, 1, 2, 3, 3, 4, 4, 5 };
+static const guint numblks[4] = { 1, 2, 3, 6 };
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-ac3, framed = (boolean) true, "
+        " channels = (int) [ 1, 6 ], rate = (int) [ 8000, 48000 ], "
+        " alignment = (string) { iec61937, frame}; "
+        "audio/x-eac3, framed = (boolean) true, "
+        " channels = (int) [ 1, 6 ], rate = (int) [ 8000, 48000 ], "
+        " alignment = (string) { iec61937, frame}; "));
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-ac3; " "audio/x-eac3; " "audio/ac3; "
+        "audio/x-private1-ac3"));
+
+static void gst_ac3_parse_finalize (GObject * object);
+
+static gboolean gst_ac3_parse_start (GstBaseParse * parse);
+static gboolean gst_ac3_parse_stop (GstBaseParse * parse);
+static GstFlowReturn gst_ac3_parse_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize);
+static GstFlowReturn gst_ac3_parse_pre_push_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame);
+static gboolean gst_ac3_parse_src_event (GstBaseParse * parse,
+    GstEvent * event);
+static GstCaps *gst_ac3_parse_get_sink_caps (GstBaseParse * parse,
+    GstCaps * filter);
+static gboolean gst_ac3_parse_set_sink_caps (GstBaseParse * parse,
+    GstCaps * caps);
+
+#define gst_ac3_parse_parent_class parent_class
+G_DEFINE_TYPE (GstAc3Parse, gst_ac3_parse, GST_TYPE_BASE_PARSE);
+
+static void
+gst_ac3_parse_class_init (GstAc3ParseClass * klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (ac3_parse_debug, "ac3parse", 0,
+      "AC3 audio stream parser");
+
+  object_class->finalize = gst_ac3_parse_finalize;
+
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "AC3 audio stream parser", "Codec/Parser/Converter/Audio",
+      "AC3 parser", "Tim-Philipp Müller <tim centricular net>");
+
+  parse_class->start = GST_DEBUG_FUNCPTR (gst_ac3_parse_start);
+  parse_class->stop = GST_DEBUG_FUNCPTR (gst_ac3_parse_stop);
+  parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_ac3_parse_handle_frame);
+  parse_class->pre_push_frame =
+      GST_DEBUG_FUNCPTR (gst_ac3_parse_pre_push_frame);
+  parse_class->src_event = GST_DEBUG_FUNCPTR (gst_ac3_parse_src_event);
+  parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_ac3_parse_get_sink_caps);
+  parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ac3_parse_set_sink_caps);
+}
+
+static void
+gst_ac3_parse_reset (GstAc3Parse * ac3parse)
+{
+  ac3parse->channels = -1;
+  ac3parse->sample_rate = -1;
+  ac3parse->blocks = -1;
+  ac3parse->eac = FALSE;
+  ac3parse->sent_codec_tag = FALSE;
+  g_atomic_int_set (&ac3parse->align, GST_AC3_PARSE_ALIGN_NONE);
+}
+
+static void
+gst_ac3_parse_init (GstAc3Parse * ac3parse)
+{
+  gst_base_parse_set_min_frame_size (GST_BASE_PARSE (ac3parse), 8);
+  gst_ac3_parse_reset (ac3parse);
+  ac3parse->baseparse_chainfunc =
+      GST_BASE_PARSE_SINK_PAD (GST_BASE_PARSE (ac3parse))->chainfunc;
+  GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (ac3parse));
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (ac3parse));
+}
+
+static void
+gst_ac3_parse_finalize (GObject * object)
+{
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_ac3_parse_start (GstBaseParse * parse)
+{
+  GstAc3Parse *ac3parse = GST_AC3_PARSE (parse);
+
+  GST_DEBUG_OBJECT (parse, "starting");
+
+  gst_ac3_parse_reset (ac3parse);
+
+  return TRUE;
+}
+
+static gboolean
+gst_ac3_parse_stop (GstBaseParse * parse)
+{
+  GST_DEBUG_OBJECT (parse, "stopping");
+
+  return TRUE;
+}
+
+static void
+gst_ac3_parse_set_alignment (GstAc3Parse * ac3parse, gboolean eac)
+{
+  GstCaps *caps;
+  GstStructure *st;
+  const gchar *str = NULL;
+  int i;
+
+  if (G_LIKELY (!eac))
+    goto done;
+
+  caps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (ac3parse));
+
+  if (!caps)
+    goto done;
+
+  for (i = 0; i < gst_caps_get_size (caps); i++) {
+    st = gst_caps_get_structure (caps, i);
+
+    if (!g_str_equal (gst_structure_get_name (st), "audio/x-eac3"))
+      continue;
+
+    if ((str = gst_structure_get_string (st, "alignment"))) {
+      if (g_str_equal (str, "iec61937")) {
+        g_atomic_int_set (&ac3parse->align, GST_AC3_PARSE_ALIGN_IEC61937);
+        GST_DEBUG_OBJECT (ac3parse, "picked iec61937 alignment");
+      } else if (g_str_equal (str, "frame") == 0) {
+        g_atomic_int_set (&ac3parse->align, GST_AC3_PARSE_ALIGN_FRAME);
+        GST_DEBUG_OBJECT (ac3parse, "picked frame alignment");
+      } else {
+        g_atomic_int_set (&ac3parse->align, GST_AC3_PARSE_ALIGN_FRAME);
+        GST_WARNING_OBJECT (ac3parse, "unknown alignment: %s", str);
+      }
+      break;
+    }
+  }
+
+  if (caps)
+    gst_caps_unref (caps);
+
+done:
+  /* default */
+  if (ac3parse->align == GST_AC3_PARSE_ALIGN_NONE) {
+    g_atomic_int_set (&ac3parse->align, GST_AC3_PARSE_ALIGN_FRAME);
+    GST_DEBUG_OBJECT (ac3parse, "picked syncframe alignment");
+  }
+}
+
+static gboolean
+gst_ac3_parse_frame_header_ac3 (GstAc3Parse * ac3parse, GstBuffer * buf,
+    gint skip, guint * frame_size, guint * rate, guint * chans, guint * blks,
+    guint * sid)
+{
+  GstBitReader bits;
+  GstMapInfo map;
+  guint8 fscod, frmsizcod, bsid, acmod, lfe_on, rate_scale;
+  gboolean ret = FALSE;
+
+  GST_LOG_OBJECT (ac3parse, "parsing ac3");
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  gst_bit_reader_init (&bits, map.data, map.size);
+  gst_bit_reader_skip_unchecked (&bits, skip * 8);
+
+  gst_bit_reader_skip_unchecked (&bits, 16 + 16);
+  fscod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2);
+  frmsizcod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 6);
+
+  if (G_UNLIKELY (fscod == 3 || frmsizcod >= G_N_ELEMENTS (frmsizcod_table))) {
+    GST_DEBUG_OBJECT (ac3parse, "bad fscod=%d frmsizcod=%d", fscod, frmsizcod);
+    goto cleanup;
+  }
+
+  bsid = gst_bit_reader_get_bits_uint8_unchecked (&bits, 5);
+  gst_bit_reader_skip_unchecked (&bits, 3);     /* bsmod */
+  acmod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 3);
+
+  /* spec not quite clear here: decoder should decode if less than 8,
+   * but seemingly only defines 6 and 8 cases */
+  /* Files with 9 and 10 happen, and seem to comply with the <= 8
+     format, so let them through. The spec says nothing about 9 and 10 */
+  if (bsid > 10) {
+    GST_DEBUG_OBJECT (ac3parse, "unexpected bsid=%d", bsid);
+    goto cleanup;
+  } else if (bsid != 8 && bsid != 6) {
+    GST_DEBUG_OBJECT (ac3parse, "undefined bsid=%d", bsid);
+  }
+
+  if ((acmod & 0x1) && (acmod != 0x1))  /* 3 front channels */
+    gst_bit_reader_skip_unchecked (&bits, 2);
+  if ((acmod & 0x4))            /* if a surround channel exists */
+    gst_bit_reader_skip_unchecked (&bits, 2);
+  if (acmod == 0x2)             /* if in 2/0 mode */
+    gst_bit_reader_skip_unchecked (&bits, 2);
+
+  lfe_on = gst_bit_reader_get_bits_uint8_unchecked (&bits, 1);
+
+  /* 6/8->0, 9->1, 10->2,
+     see http://matroska.org/technical/specs/codecid/index.html */
+  rate_scale = (CLAMP (bsid, 8, 10) - 8);
+
+  if (frame_size)
+    *frame_size = frmsizcod_table[frmsizcod].frame_size[fscod] * 2;
+  if (rate)
+    *rate = fscod_rates[fscod] >> rate_scale;
+  if (chans)
+    *chans = acmod_chans[acmod] + lfe_on;
+  if (blks)
+    *blks = 6;
+  if (sid)
+    *sid = 0;
+
+  ret = TRUE;
+
+cleanup:
+  gst_buffer_unmap (buf, &map);
+
+  return ret;
+}
+
+static gboolean
+gst_ac3_parse_frame_header_eac3 (GstAc3Parse * ac3parse, GstBuffer * buf,
+    gint skip, guint * frame_size, guint * rate, guint * chans, guint * blks,
+    guint * sid)
+{
+  GstBitReader bits;
+  GstMapInfo map;
+  guint16 frmsiz, sample_rate, blocks;
+  guint8 strmtyp, fscod, fscod2, acmod, lfe_on, strmid, numblkscod;
+  gboolean ret = FALSE;
+
+  GST_LOG_OBJECT (ac3parse, "parsing e-ac3");
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  gst_bit_reader_init (&bits, map.data, map.size);
+  gst_bit_reader_skip_unchecked (&bits, skip * 8);
+
+  gst_bit_reader_skip_unchecked (&bits, 16);
+  strmtyp = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2); /* strmtyp     */
+  if (G_UNLIKELY (strmtyp == 3)) {
+    GST_DEBUG_OBJECT (ac3parse, "bad strmtyp %d", strmtyp);
+    goto cleanup;
+  }
+
+  strmid = gst_bit_reader_get_bits_uint8_unchecked (&bits, 3);  /* substreamid */
+  frmsiz = gst_bit_reader_get_bits_uint16_unchecked (&bits, 11);        /* frmsiz      */
+  fscod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2);   /* fscod       */
+  if (fscod == 3) {
+    fscod2 = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2);        /* fscod2      */
+    if (G_UNLIKELY (fscod2 == 3)) {
+      GST_DEBUG_OBJECT (ac3parse, "invalid fscod2");
+      goto cleanup;
+    }
+    sample_rate = fscod_rates[fscod2] / 2;
+    blocks = 6;
+  } else {
+    numblkscod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2);    /* numblkscod  */
+    sample_rate = fscod_rates[fscod];
+    blocks = numblks[numblkscod];
+  }
+
+  acmod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 3);   /* acmod       */
+  lfe_on = gst_bit_reader_get_bits_uint8_unchecked (&bits, 1);  /* lfeon       */
+
+  gst_bit_reader_skip_unchecked (&bits, 5);     /* bsid        */
+
+  if (frame_size)
+    *frame_size = (frmsiz + 1) * 2;
+  if (rate)
+    *rate = sample_rate;
+  if (chans)
+    *chans = acmod_chans[acmod] + lfe_on;
+  if (blks)
+    *blks = blocks;
+  if (sid)
+    *sid = (strmtyp & 0x1) << 3 | strmid;
+
+  ret = TRUE;
+
+cleanup:
+  gst_buffer_unmap (buf, &map);
+
+  return ret;
+}
+
+static gboolean
+gst_ac3_parse_frame_header (GstAc3Parse * parse, GstBuffer * buf, gint skip,
+    guint * framesize, guint * rate, guint * chans, guint * blocks,
+    guint * sid, gboolean * eac)
+{
+  GstBitReader bits;
+  guint16 sync;
+  guint8 bsid;
+  GstMapInfo map;
+  gboolean ret = FALSE;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  gst_bit_reader_init (&bits, map.data, map.size);
+
+  GST_MEMDUMP_OBJECT (parse, "AC3 frame sync", map.data, MIN (map.size, 16));
+
+  gst_bit_reader_skip_unchecked (&bits, skip * 8);
+
+  sync = gst_bit_reader_get_bits_uint16_unchecked (&bits, 16);
+  gst_bit_reader_skip_unchecked (&bits, 16 + 8);
+  bsid = gst_bit_reader_peek_bits_uint8_unchecked (&bits, 5);
+
+  if (G_UNLIKELY (sync != 0x0b77))
+    goto cleanup;
+
+  GST_LOG_OBJECT (parse, "bsid = %d", bsid);
+
+  if (bsid <= 10) {
+    if (eac)
+      *eac = FALSE;
+    ret = gst_ac3_parse_frame_header_ac3 (parse, buf, skip, framesize, rate,
+        chans, blocks, sid);
+    goto cleanup;
+  } else if (bsid <= 16) {
+    if (eac)
+      *eac = TRUE;
+    ret = gst_ac3_parse_frame_header_eac3 (parse, buf, skip, framesize, rate,
+        chans, blocks, sid);
+    goto cleanup;
+  } else {
+    GST_DEBUG_OBJECT (parse, "unexpected bsid %d", bsid);
+    ret = FALSE;
+    goto cleanup;
+  }
+
+  GST_DEBUG_OBJECT (parse, "unexpected bsid %d", bsid);
+
+cleanup:
+  gst_buffer_unmap (buf, &map);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_ac3_parse_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize)
+{
+  GstAc3Parse *ac3parse = GST_AC3_PARSE (parse);
+  GstBuffer *buf = frame->buffer;
+  GstByteReader reader;
+  gint off;
+  gboolean lost_sync, draining, eac, more = FALSE;
+  guint frmsiz, blocks, sid;
+  guint rate, chans;
+  gboolean update_rate = FALSE;
+  gint framesize = 0;
+  gint have_blocks = 0;
+  GstMapInfo map;
+  gboolean ret = FALSE;
+  GstFlowReturn res = GST_FLOW_OK;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  if (G_UNLIKELY (map.size < 8)) {
+    *skipsize = 1;
+    goto cleanup;
+  }
+
+  gst_byte_reader_init (&reader, map.data, map.size);
+  off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffff0000, 0x0b770000,
+      0, map.size);
+
+  GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off);
+
+  /* didn't find anything that looks like a sync word, skip */
+  if (off < 0) {
+    *skipsize = map.size - 3;
+    goto cleanup;
+  }
+
+  /* possible frame header, but not at offset 0? skip bytes before sync */
+  if (off > 0) {
+    *skipsize = off;
+    goto cleanup;
+  }
+
+  /* make sure the values in the frame header look sane */
+  if (!gst_ac3_parse_frame_header (ac3parse, buf, 0, &frmsiz, &rate, &chans,
+          &blocks, &sid, &eac)) {
+    *skipsize = off + 2;
+    goto cleanup;
+  }
+
+  GST_LOG_OBJECT (parse, "size: %u, blocks: %u, rate: %u, chans: %u", frmsiz,
+      blocks, rate, chans);
+
+  framesize = frmsiz;
+
+  if (G_UNLIKELY (g_atomic_int_get (&ac3parse->align) ==
+          GST_AC3_PARSE_ALIGN_NONE))
+    gst_ac3_parse_set_alignment (ac3parse, eac);
+
+  GST_LOG_OBJECT (parse, "got frame");
+
+  lost_sync = GST_BASE_PARSE_LOST_SYNC (parse);
+  draining = GST_BASE_PARSE_DRAINING (parse);
+
+  if (g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_IEC61937) {
+    /* We need 6 audio blocks from each substream, so we keep going forwards
+     * till we have it */
+
+    g_assert (blocks > 0);
+    GST_LOG_OBJECT (ac3parse, "Need %d frames before pushing", 6 / blocks);
+
+    if (sid != 0) {
+      /* We need the first substream to be the one with id 0 */
+      GST_LOG_OBJECT (ac3parse, "Skipping till we find sid 0");
+      *skipsize = off + 2;
+      goto cleanup;
+    }
+
+    framesize = 0;
+
+    /* Loop till we have 6 blocks per substream */
+    for (have_blocks = 0; !more && have_blocks < 6; have_blocks += blocks) {
+      /* Loop till we get one frame from each substream */
+      do {
+        framesize += frmsiz;
+
+        if (!gst_byte_reader_skip (&reader, frmsiz)
+            || map.size < (framesize + 6)) {
+          more = TRUE;
+          break;
+        }
+
+        if (!gst_ac3_parse_frame_header (ac3parse, buf, framesize, &frmsiz,
+                NULL, NULL, NULL, &sid, &eac)) {
+          *skipsize = off + 2;
+          goto cleanup;
+        }
+      } while (sid);
+    }
+
+    /* We're now at the next frame, so no need to skip if resyncing */
+    frmsiz = 0;
+  }
+
+  if (lost_sync && !draining) {
+    guint16 word = 0;
+
+    GST_DEBUG_OBJECT (ac3parse, "resyncing; checking next frame syncword");
+
+    if (more || !gst_byte_reader_skip (&reader, frmsiz) ||
+        !gst_byte_reader_get_uint16_be (&reader, &word)) {
+      GST_DEBUG_OBJECT (ac3parse, "... but not sufficient data");
+      gst_base_parse_set_min_frame_size (parse, framesize + 8);
+      *skipsize = 0;
+      goto cleanup;
+    } else {
+      if (word != 0x0b77) {
+        GST_DEBUG_OBJECT (ac3parse, "0x%x not OK", word);
+        *skipsize = off + 2;
+        goto cleanup;
+      } else {
+        /* ok, got sync now, let's assume constant frame size */
+        gst_base_parse_set_min_frame_size (parse, framesize);
+      }
+    }
+  }
+
+  /* expect to have found a frame here */
+  g_assert (framesize);
+  ret = TRUE;
+
+  /* arrange for metadata setup */
+  if (G_UNLIKELY (sid)) {
+    /* dependent frame, no need to (ac)count for or consider further */
+    GST_LOG_OBJECT (parse, "sid: %d", sid);
+    frame->flags |= GST_BASE_PARSE_FRAME_FLAG_NO_FRAME;
+    /* TODO maybe also mark as DELTA_UNIT,
+     * if that does not surprise baseparse elsewhere */
+    /* occupies same time space as previous base frame */
+    if (G_LIKELY (GST_BUFFER_TIMESTAMP (buf) >= GST_BUFFER_DURATION (buf)))
+      GST_BUFFER_TIMESTAMP (buf) -= GST_BUFFER_DURATION (buf);
+    /* only shortcut if we already arranged for caps */
+    if (G_LIKELY (ac3parse->sample_rate > 0))
+      goto cleanup;
+  }
+
+  if (G_UNLIKELY (ac3parse->sample_rate != rate || ac3parse->channels != chans
+          || ac3parse->eac != eac)) {
+    GstCaps *caps = gst_caps_new_simple (eac ? "audio/x-eac3" : "audio/x-ac3",
+        "framed", G_TYPE_BOOLEAN, TRUE, "rate", G_TYPE_INT, rate,
+        "channels", G_TYPE_INT, chans, NULL);
+    gst_caps_set_simple (caps, "alignment", G_TYPE_STRING,
+        g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_IEC61937 ?
+        "iec61937" : "frame", NULL);
+    gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
+    gst_caps_unref (caps);
+
+    ac3parse->sample_rate = rate;
+    ac3parse->channels = chans;
+    ac3parse->eac = eac;
+
+    update_rate = TRUE;
+  }
+
+  if (G_UNLIKELY (ac3parse->blocks != blocks)) {
+    ac3parse->blocks = blocks;
+
+    update_rate = TRUE;
+  }
+
+  if (G_UNLIKELY (update_rate))
+    gst_base_parse_set_frame_rate (parse, rate, 256 * blocks, 2, 2);
+
+cleanup:
+  gst_buffer_unmap (buf, &map);
+
+  if (ret && framesize <= map.size) {
+    res = gst_base_parse_finish_frame (parse, frame, framesize);
+  }
+
+  return res;
+}
+
+
+/*
+ * MPEG-PS private1 streams add a 2 bytes "Audio Substream Headers" for each
+ * buffer (not each frame) with the offset of the next frame's start.
+ *
+ * Buffer 1:
+ * -------------------------------------------
+ * |firstAccUnit|AC3SyncWord|xxxxxxxxxxxxxxxxx
+ * -------------------------------------------
+ * Buffer 2:
+ * -------------------------------------------
+ * |firstAccUnit|xxxxxx|AC3SyncWord|xxxxxxxxxx
+ * -------------------------------------------
+ *
+ * These 2 bytes can be dropped safely as they do not include any timing
+ * information, only the offset to the start of the next frame.
+ *
+ * From http://stnsoft.com/DVD/ass-hdr.html:
+ * "FirstAccUnit offset to frame which corresponds to PTS value offset 0 is the
+ * last byte of FirstAccUnit, ie add the offset of byte 2 to get the AU's offset
+ * The value 0000 indicates there is no first access unit"
+ * */
+
+static GstFlowReturn
+gst_ac3_parse_chain_priv (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstAc3Parse *ac3parse = GST_AC3_PARSE (parent);
+  GstFlowReturn ret;
+  gsize size;
+  guint8 data[2];
+  gint offset;
+  gint len;
+  GstBuffer *subbuf;
+  gint first_access;
+
+  size = gst_buffer_get_size (buf);
+  if (size < 2)
+    goto not_enough_data;
+
+  gst_buffer_extract (buf, 0, data, 2);
+  first_access = (data[0] << 8) | data[1];
+
+  /* Skip the first_access header */
+  offset = 2;
+
+  if (first_access > 1) {
+    /* Length of data before first_access */
+    len = first_access - 1;
+
+    if (len <= 0 || offset + len > size)
+      goto bad_first_access_parameter;
+
+    subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset, len);
+    GST_BUFFER_DTS (subbuf) = GST_CLOCK_TIME_NONE;
+    GST_BUFFER_PTS (subbuf) = GST_CLOCK_TIME_NONE;
+    ret = ac3parse->baseparse_chainfunc (pad, parent, subbuf);
+    if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
+      gst_buffer_unref (buf);
+      goto done;
+    }
+
+    offset += len;
+    len = size - offset;
+
+    if (len > 0) {
+      subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset, len);
+      GST_BUFFER_PTS (subbuf) = GST_BUFFER_PTS (buf);
+      GST_BUFFER_DTS (subbuf) = GST_BUFFER_DTS (buf);
+
+      ret = ac3parse->baseparse_chainfunc (pad, parent, subbuf);
+    }
+    gst_buffer_unref (buf);
+  } else {
+    /* first_access = 0 or 1, so if there's a timestamp it applies to the first byte */
+    subbuf =
+        gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset,
+        size - offset);
+    GST_BUFFER_PTS (subbuf) = GST_BUFFER_PTS (buf);
+    GST_BUFFER_DTS (subbuf) = GST_BUFFER_DTS (buf);
+    gst_buffer_unref (buf);
+    ret = ac3parse->baseparse_chainfunc (pad, parent, subbuf);
+  }
+
+done:
+  return ret;
+
+/* ERRORS */
+not_enough_data:
+  {
+    GST_ELEMENT_ERROR (GST_ELEMENT (ac3parse), STREAM, FORMAT, (NULL),
+        ("Insufficient data in buffer. Can't determine first_acess"));
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+bad_first_access_parameter:
+  {
+    GST_ELEMENT_ERROR (GST_ELEMENT (ac3parse), STREAM, FORMAT, (NULL),
+        ("Bad first_access parameter (%d) in buffer", first_access));
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstFlowReturn
+gst_ac3_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
+{
+  GstAc3Parse *ac3parse = GST_AC3_PARSE (parse);
+
+  if (!ac3parse->sent_codec_tag) {
+    GstTagList *taglist;
+    GstCaps *caps;
+
+    /* codec tag */
+    caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
+    if (G_UNLIKELY (caps == NULL)) {
+      if (GST_PAD_IS_FLUSHING (GST_BASE_PARSE_SRC_PAD (parse))) {
+        GST_INFO_OBJECT (parse, "Src pad is flushing");
+        return GST_FLOW_FLUSHING;
+      } else {
+        GST_INFO_OBJECT (parse, "Src pad is not negotiated!");
+        return GST_FLOW_NOT_NEGOTIATED;
+      }
+    }
+
+    taglist = gst_tag_list_new_empty ();
+    gst_pb_utils_add_codec_description_to_tag_list (taglist,
+        GST_TAG_AUDIO_CODEC, caps);
+    gst_caps_unref (caps);
+
+    gst_base_parse_merge_tags (parse, taglist, GST_TAG_MERGE_REPLACE);
+    gst_tag_list_unref (taglist);
+
+    /* also signals the end of first-frame processing */
+    ac3parse->sent_codec_tag = TRUE;
+  }
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_ac3_parse_src_event (GstBaseParse * parse, GstEvent * event)
+{
+  GstAc3Parse *ac3parse = GST_AC3_PARSE (parse);
+
+  if (G_UNLIKELY (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM) &&
+      gst_event_has_name (event, "ac3parse-set-alignment")) {
+    const GstStructure *st = gst_event_get_structure (event);
+    const gchar *align = gst_structure_get_string (st, "alignment");
+
+    if (g_str_equal (align, "iec61937")) {
+      GST_DEBUG_OBJECT (ac3parse, "Switching to iec61937 alignment");
+      g_atomic_int_set (&ac3parse->align, GST_AC3_PARSE_ALIGN_IEC61937);
+    } else if (g_str_equal (align, "frame")) {
+      GST_DEBUG_OBJECT (ac3parse, "Switching to frame alignment");
+      g_atomic_int_set (&ac3parse->align, GST_AC3_PARSE_ALIGN_FRAME);
+    } else {
+      g_atomic_int_set (&ac3parse->align, GST_AC3_PARSE_ALIGN_FRAME);
+      GST_WARNING_OBJECT (ac3parse, "Got unknown alignment request (%s) "
+          "reverting to frame alignment.",
+          gst_structure_get_string (st, "alignment"));
+    }
+
+    gst_event_unref (event);
+    return TRUE;
+  }
+
+  return GST_BASE_PARSE_CLASS (parent_class)->src_event (parse, event);
+}
+
+static void
+remove_fields (GstCaps * caps)
+{
+  guint i, n;
+
+  n = gst_caps_get_size (caps);
+  for (i = 0; i < n; i++) {
+    GstStructure *s = gst_caps_get_structure (caps, i);
+
+    gst_structure_remove_field (s, "framed");
+    gst_structure_remove_field (s, "alignment");
+  }
+}
+
+static GstCaps *
+extend_caps (GstCaps * caps, gboolean add_private)
+{
+  guint i, n;
+  GstCaps *ncaps = gst_caps_new_empty ();
+
+  n = gst_caps_get_size (caps);
+  for (i = 0; i < n; i++) {
+    GstStructure *s = gst_caps_get_structure (caps, i);
+
+    if (add_private && !gst_structure_has_name (s, "audio/x-private1-ac3")) {
+      GstStructure *ns = gst_structure_copy (s);
+      gst_structure_set_name (ns, "audio/x-private1-ac3");
+      gst_caps_append_structure (ncaps, ns);
+    } else if (!add_private &&
+        gst_structure_has_name (s, "audio/x-private1-ac3")) {
+      GstStructure *ns = gst_structure_copy (s);
+      gst_structure_set_name (ns, "audio/x-ac3");
+      gst_caps_append_structure (ncaps, ns);
+      ns = gst_structure_copy (s);
+      gst_structure_set_name (ns, "audio/x-eac3");
+      gst_caps_append_structure (ncaps, ns);
+    } else if (!add_private) {
+      gst_caps_append_structure (ncaps, gst_structure_copy (s));
+    }
+  }
+
+  if (add_private) {
+    gst_caps_append (caps, ncaps);
+  } else {
+    gst_caps_unref (caps);
+    caps = ncaps;
+  }
+
+  return caps;
+}
+
+static GstCaps *
+gst_ac3_parse_get_sink_caps (GstBaseParse * parse, GstCaps * filter)
+{
+  GstCaps *peercaps, *templ;
+  GstCaps *res;
+
+  templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
+  if (filter) {
+    GstCaps *fcopy = gst_caps_copy (filter);
+    /* Remove the fields we convert */
+    remove_fields (fcopy);
+    /* we do not ask downstream to handle x-private1-ac3 */
+    fcopy = extend_caps (fcopy, FALSE);
+    peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
+    gst_caps_unref (fcopy);
+  } else
+    peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), NULL);
+
+  if (peercaps) {
+    /* Remove the framed and alignment field. We can convert
+     * between different alignments. */
+    peercaps = gst_caps_make_writable (peercaps);
+    remove_fields (peercaps);
+    /* also allow for x-private1-ac3 input */
+    peercaps = extend_caps (peercaps, TRUE);
+
+    res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (peercaps);
+    gst_caps_unref (templ);
+  } else {
+    res = templ;
+  }
+
+  if (filter) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (res);
+    res = intersection;
+  }
+
+  return res;
+}
+
+static gboolean
+gst_ac3_parse_set_sink_caps (GstBaseParse * parse, GstCaps * caps)
+{
+  GstStructure *s;
+  GstAc3Parse *ac3parse = GST_AC3_PARSE (parse);
+
+  s = gst_caps_get_structure (caps, 0);
+  if (gst_structure_has_name (s, "audio/x-private1-ac3")) {
+    gst_pad_set_chain_function (parse->sinkpad, gst_ac3_parse_chain_priv);
+  } else {
+    gst_pad_set_chain_function (parse->sinkpad, ac3parse->baseparse_chainfunc);
+  }
+  return TRUE;
+}
diff --git a/gst/audioparsers/gstac3parse.h b/gst/audioparsers/gstac3parse.h
new file mode 100644
index 0000000..0e7af5a
--- /dev/null
+++ b/gst/audioparsers/gstac3parse.h
@@ -0,0 +1,83 @@
+/* GStreamer AC3 parser
+ * Copyright (C) 2009 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2009 Mark Nauwelaerts <mnauw users sf net>
+ * Copyright (C) 2009 Nokia Corporation. All rights reserved.
+ *   Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AC3_PARSE_H__
+#define __GST_AC3_PARSE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbaseparse.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AC3_PARSE \
+  (gst_ac3_parse_get_type())
+#define GST_AC3_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AC3_PARSE, GstAc3Parse))
+#define GST_AC3_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_AC3_PARSE, GstAc3ParseClass))
+#define GST_IS_AC3_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_AC3_PARSE))
+#define GST_IS_AC3_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_AC3_PARSE))
+
+typedef struct _GstAc3Parse GstAc3Parse;
+typedef struct _GstAc3ParseClass GstAc3ParseClass;
+
+enum {
+  GST_AC3_PARSE_ALIGN_NONE,
+  GST_AC3_PARSE_ALIGN_FRAME,
+  GST_AC3_PARSE_ALIGN_IEC61937,
+};
+
+/**
+ * GstAc3Parse:
+ *
+ * The opaque GstAc3Parse object
+ */
+struct _GstAc3Parse {
+  GstBaseParse baseparse;
+
+  /*< private >*/
+  gint                  sample_rate;
+  gint                  channels;
+  gint                  blocks;
+  gboolean              eac;
+  gboolean              sent_codec_tag;
+  volatile gint         align;
+  GstPadChainFunction   baseparse_chainfunc;
+};
+
+/**
+ * GstAc3ParseClass:
+ * @parent_class: Element parent class.
+ *
+ * The opaque GstAc3ParseClass data structure.
+ */
+struct _GstAc3ParseClass {
+  GstBaseParseClass baseparse_class;
+};
+
+GType gst_ac3_parse_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_AC3_PARSE_H__ */
diff --git a/gst/audioparsers/gstamrparse.c b/gst/audioparsers/gstamrparse.c
new file mode 100644
index 0000000..ca01359
--- /dev/null
+++ b/gst/audioparsers/gstamrparse.c
@@ -0,0 +1,452 @@
+/* GStreamer Adaptive Multi-Rate parser plugin
+ * Copyright (C) 2006 Edgard Lima <edgard.lima@gmail.com>
+ * Copyright (C) 2008 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-amrparse
+ * @short_description: AMR parser
+ * @see_also: #GstAmrnbDec, #GstAmrnbEnc
+ *
+ * This is an AMR parser capable of handling both narrow-band and wideband
+ * formats.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=abc.amr ! amrparse ! amrdec ! audioresample ! audioconvert ! alsasink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstamrparse.h"
+#include <gst/pbutils/pbutils.h>
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/AMR, " "rate = (int) 8000, " "channels = (int) 1;"
+        "audio/AMR-WB, " "rate = (int) 16000, " "channels = (int) 1;")
+    );
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-amr-nb-sh; audio/x-amr-wb-sh"));
+
+GST_DEBUG_CATEGORY_STATIC (amrparse_debug);
+#define GST_CAT_DEFAULT amrparse_debug
+
+static const gint block_size_nb[16] =
+    { 12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0 };
+
+static const gint block_size_wb[16] =
+    { 17, 23, 32, 36, 40, 46, 50, 58, 60, 5, -1, -1, -1, -1, 0, 0 };
+
+/* AMR has a "hardcoded" framerate of 50fps */
+#define AMR_FRAMES_PER_SECOND 50
+#define AMR_FRAME_DURATION (GST_SECOND/AMR_FRAMES_PER_SECOND)
+#define AMR_MIME_HEADER_SIZE 9
+
+static gboolean gst_amr_parse_start (GstBaseParse * parse);
+static gboolean gst_amr_parse_stop (GstBaseParse * parse);
+
+static gboolean gst_amr_parse_sink_setcaps (GstBaseParse * parse,
+    GstCaps * caps);
+static GstCaps *gst_amr_parse_sink_getcaps (GstBaseParse * parse,
+    GstCaps * filter);
+
+static GstFlowReturn gst_amr_parse_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize);
+static GstFlowReturn gst_amr_parse_pre_push_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame);
+
+G_DEFINE_TYPE (GstAmrParse, gst_amr_parse, GST_TYPE_BASE_PARSE);
+
+/**
+ * gst_amr_parse_class_init:
+ * @klass: GstAmrParseClass.
+ *
+ */
+static void
+gst_amr_parse_class_init (GstAmrParseClass * klass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (amrparse_debug, "amrparse", 0,
+      "AMR-NB audio stream parser");
+
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "AMR audio stream parser", "Codec/Parser/Audio",
+      "Adaptive Multi-Rate audio parser",
+      "Ronald Bultje <rbultje@ronald.bitfreak.net>");
+
+  parse_class->start = GST_DEBUG_FUNCPTR (gst_amr_parse_start);
+  parse_class->stop = GST_DEBUG_FUNCPTR (gst_amr_parse_stop);
+  parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_amr_parse_sink_setcaps);
+  parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_amr_parse_sink_getcaps);
+  parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_amr_parse_handle_frame);
+  parse_class->pre_push_frame =
+      GST_DEBUG_FUNCPTR (gst_amr_parse_pre_push_frame);
+}
+
+
+/**
+ * gst_amr_parse_init:
+ * @amrparse: #GstAmrParse
+ * @klass: #GstAmrParseClass.
+ *
+ */
+static void
+gst_amr_parse_init (GstAmrParse * amrparse)
+{
+  /* init rest */
+  gst_base_parse_set_min_frame_size (GST_BASE_PARSE (amrparse), 62);
+  GST_DEBUG ("initialized");
+  GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (amrparse));
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (amrparse));
+}
+
+
+/**
+ * gst_amr_parse_set_src_caps:
+ * @amrparse: #GstAmrParse.
+ *
+ * Set source pad caps according to current knowledge about the
+ * audio stream.
+ *
+ * Returns: TRUE if caps were successfully set.
+ */
+static gboolean
+gst_amr_parse_set_src_caps (GstAmrParse * amrparse)
+{
+  GstCaps *src_caps = NULL;
+  gboolean res = FALSE;
+
+  if (amrparse->wide) {
+    GST_DEBUG_OBJECT (amrparse, "setting srcpad caps to AMR-WB");
+    src_caps = gst_caps_new_simple ("audio/AMR-WB",
+        "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 16000, NULL);
+  } else {
+    GST_DEBUG_OBJECT (amrparse, "setting srcpad caps to AMR-NB");
+    /* Max. size of NB frame is 31 bytes, so we can set the min. frame
+       size to 32 (+1 for next frame header) */
+    gst_base_parse_set_min_frame_size (GST_BASE_PARSE (amrparse), 32);
+    src_caps = gst_caps_new_simple ("audio/AMR",
+        "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL);
+  }
+  gst_pad_use_fixed_caps (GST_BASE_PARSE (amrparse)->srcpad);
+  res = gst_pad_set_caps (GST_BASE_PARSE (amrparse)->srcpad, src_caps);
+  gst_caps_unref (src_caps);
+  return res;
+}
+
+
+/**
+ * gst_amr_parse_sink_setcaps:
+ * @sinkpad: GstPad
+ * @caps: GstCaps
+ *
+ * Returns: TRUE on success.
+ */
+static gboolean
+gst_amr_parse_sink_setcaps (GstBaseParse * parse, GstCaps * caps)
+{
+  GstAmrParse *amrparse;
+  GstStructure *structure;
+  const gchar *name;
+
+  amrparse = GST_AMR_PARSE (parse);
+  structure = gst_caps_get_structure (caps, 0);
+  name = gst_structure_get_name (structure);
+
+  GST_DEBUG_OBJECT (amrparse, "setcaps: %s", name);
+
+  if (!strncmp (name, "audio/x-amr-wb-sh", 17)) {
+    amrparse->block_size = block_size_wb;
+    amrparse->wide = 1;
+  } else if (!strncmp (name, "audio/x-amr-nb-sh", 17)) {
+    amrparse->block_size = block_size_nb;
+    amrparse->wide = 0;
+  } else {
+    GST_WARNING ("Unknown caps");
+    return FALSE;
+  }
+
+  amrparse->need_header = FALSE;
+  gst_base_parse_set_frame_rate (GST_BASE_PARSE (amrparse), 50, 1, 2, 2);
+  gst_amr_parse_set_src_caps (amrparse);
+  return TRUE;
+}
+
+/**
+ * gst_amr_parse_parse_header:
+ * @amrparse: #GstAmrParse
+ * @data: Header data to be parsed.
+ * @skipsize: Output argument where the frame size will be stored.
+ *
+ * Check if the given data contains an AMR mime header.
+ *
+ * Returns: TRUE on success.
+ */
+static gboolean
+gst_amr_parse_parse_header (GstAmrParse * amrparse,
+    const guint8 * data, gint * skipsize)
+{
+  GST_DEBUG_OBJECT (amrparse, "Parsing header data");
+
+  if (!memcmp (data, "#!AMR-WB\n", 9)) {
+    GST_DEBUG_OBJECT (amrparse, "AMR-WB detected");
+    amrparse->block_size = block_size_wb;
+    amrparse->wide = TRUE;
+    *skipsize = amrparse->header = 9;
+  } else if (!memcmp (data, "#!AMR\n", 6)) {
+    GST_DEBUG_OBJECT (amrparse, "AMR-NB detected");
+    amrparse->block_size = block_size_nb;
+    amrparse->wide = FALSE;
+    *skipsize = amrparse->header = 6;
+  } else
+    return FALSE;
+
+  gst_amr_parse_set_src_caps (amrparse);
+  return TRUE;
+}
+
+
+/**
+ * gst_amr_parse_check_valid_frame:
+ * @parse: #GstBaseParse.
+ * @buffer: #GstBuffer.
+ * @framesize: Output variable where the found frame size is put.
+ * @skipsize: Output variable which tells how much data needs to be skipped
+ *            until a frame header is found.
+ *
+ * Implementation of "check_valid_frame" vmethod in #GstBaseParse class.
+ *
+ * Returns: TRUE if the given data contains valid frame.
+ */
+static GstFlowReturn
+gst_amr_parse_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize)
+{
+  GstBuffer *buffer;
+  GstMapInfo map;
+  gint fsize = 0, mode, dsize;
+  GstAmrParse *amrparse;
+  GstFlowReturn ret = GST_FLOW_OK;
+  gboolean found = FALSE;
+
+  amrparse = GST_AMR_PARSE (parse);
+  buffer = frame->buffer;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  dsize = map.size;
+
+  GST_LOG ("buffer: %d bytes", dsize);
+
+  if (amrparse->need_header) {
+    if (dsize >= AMR_MIME_HEADER_SIZE &&
+        gst_amr_parse_parse_header (amrparse, map.data, skipsize)) {
+      amrparse->need_header = FALSE;
+      gst_base_parse_set_frame_rate (GST_BASE_PARSE (amrparse), 50, 1, 2, 2);
+    } else {
+      GST_WARNING ("media doesn't look like a AMR format");
+    }
+    /* We return FALSE, so this frame won't get pushed forward. Instead,
+       the "skip" value is set, so next time we will receive a valid frame. */
+    goto done;
+  }
+
+  *skipsize = 1;
+  /* Does this look like a possible frame header candidate? */
+  if ((map.data[0] & 0x83) == 0) {
+    /* Yep. Retrieve the frame size */
+    mode = (map.data[0] >> 3) & 0x0F;
+    fsize = amrparse->block_size[mode] + 1;     /* +1 for the header byte */
+
+    /* We recognize this data as a valid frame when:
+     *     - We are in sync. There is no need for extra checks then
+     *     - We are in EOS. There might not be enough data to check next frame
+     *     - Sync is lost, but the following data after this frame seem
+     *       to contain a valid header as well (and there is enough data to
+     *       perform this check)
+     */
+    if (fsize) {
+      *skipsize = 0;
+      /* in sync, no further check */
+      if (!GST_BASE_PARSE_LOST_SYNC (parse)) {
+        found = TRUE;
+      } else if (dsize > fsize) {
+        /* enough data, check for next sync */
+        if ((map.data[fsize] & 0x83) == 0)
+          found = TRUE;
+      } else if (GST_BASE_PARSE_DRAINING (parse)) {
+        /* not enough, but draining, so ok */
+        found = TRUE;
+      }
+    }
+  }
+
+done:
+  gst_buffer_unmap (buffer, &map);
+
+  if (found && fsize <= map.size) {
+    ret = gst_base_parse_finish_frame (parse, frame, fsize);
+  }
+
+  return ret;
+}
+
+/**
+ * gst_amr_parse_start:
+ * @parse: #GstBaseParse.
+ *
+ * Implementation of "start" vmethod in #GstBaseParse class.
+ *
+ * Returns: TRUE on success.
+ */
+static gboolean
+gst_amr_parse_start (GstBaseParse * parse)
+{
+  GstAmrParse *amrparse;
+
+  amrparse = GST_AMR_PARSE (parse);
+  GST_DEBUG ("start");
+  amrparse->need_header = TRUE;
+  amrparse->header = 0;
+  amrparse->sent_codec_tag = FALSE;
+  return TRUE;
+}
+
+
+/**
+ * gst_amr_parse_stop:
+ * @parse: #GstBaseParse.
+ *
+ * Implementation of "stop" vmethod in #GstBaseParse class.
+ *
+ * Returns: TRUE on success.
+ */
+static gboolean
+gst_amr_parse_stop (GstBaseParse * parse)
+{
+  GstAmrParse *amrparse;
+
+  amrparse = GST_AMR_PARSE (parse);
+  GST_DEBUG ("stop");
+  amrparse->need_header = TRUE;
+  amrparse->header = 0;
+  return TRUE;
+}
+
+static GstCaps *
+gst_amr_parse_sink_getcaps (GstBaseParse * parse, GstCaps * filter)
+{
+  GstCaps *peercaps, *templ;
+  GstCaps *res;
+
+
+  templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
+  peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), filter);
+
+  if (peercaps) {
+    guint i, n;
+
+    /* Rename structure names */
+    peercaps = gst_caps_make_writable (peercaps);
+    n = gst_caps_get_size (peercaps);
+    for (i = 0; i < n; i++) {
+      GstStructure *s = gst_caps_get_structure (peercaps, i);
+
+      if (gst_structure_has_name (s, "audio/AMR"))
+        gst_structure_set_name (s, "audio/x-amr-nb-sh");
+      else
+        gst_structure_set_name (s, "audio/x-amr-wb-sh");
+    }
+
+    res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (peercaps);
+    res = gst_caps_make_writable (res);
+    /* Append the template caps because we still want to accept
+     * caps without any fields in the case upstream does not
+     * know anything.
+     */
+    gst_caps_append (res, templ);
+  } else {
+    res = templ;
+  }
+
+  if (filter) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (res);
+    res = intersection;
+  }
+
+  return res;
+}
+
+static GstFlowReturn
+gst_amr_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
+{
+  GstAmrParse *amrparse = GST_AMR_PARSE (parse);
+
+  if (!amrparse->sent_codec_tag) {
+    GstTagList *taglist;
+    GstCaps *caps;
+
+    /* codec tag */
+    caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
+    if (G_UNLIKELY (caps == NULL)) {
+      if (GST_PAD_IS_FLUSHING (GST_BASE_PARSE_SRC_PAD (parse))) {
+        GST_INFO_OBJECT (parse, "Src pad is flushing");
+        return GST_FLOW_FLUSHING;
+      } else {
+        GST_INFO_OBJECT (parse, "Src pad is not negotiated!");
+        return GST_FLOW_NOT_NEGOTIATED;
+      }
+    }
+
+    taglist = gst_tag_list_new_empty ();
+    gst_pb_utils_add_codec_description_to_tag_list (taglist,
+        GST_TAG_AUDIO_CODEC, caps);
+    gst_caps_unref (caps);
+
+    gst_base_parse_merge_tags (parse, taglist, GST_TAG_MERGE_REPLACE);
+    gst_tag_list_unref (taglist);
+
+    /* also signals the end of first-frame processing */
+    amrparse->sent_codec_tag = TRUE;
+  }
+
+  return GST_FLOW_OK;
+}
diff --git a/gst/audioparsers/gstamrparse.h b/gst/audioparsers/gstamrparse.h
new file mode 100644
index 0000000..bba29c0
--- /dev/null
+++ b/gst/audioparsers/gstamrparse.h
@@ -0,0 +1,78 @@
+/* GStreamer Adaptive Multi-Rate parser
+ * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * Copyright (C) 2008 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AMR_PARSE_H__
+#define __GST_AMR_PARSE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbaseparse.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AMR_PARSE \
+  (gst_amr_parse_get_type())
+#define GST_AMR_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AMR_PARSE, GstAmrParse))
+#define GST_AMR_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_AMR_PARSE, GstAmrParseClass))
+#define GST_IS_AMR_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_AMR_PARSE))
+#define GST_IS_AMR_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_AMR_PARSE))
+
+
+typedef struct _GstAmrParse GstAmrParse;
+typedef struct _GstAmrParseClass GstAmrParseClass;
+
+/**
+ * GstAmrParse:
+ * @element: the parent element.
+ * @block_size: Pointer to frame size lookup table.
+ * @need_header: Tells whether the MIME header should be read in the beginning.
+ * @wide: Wideband mode.
+ *
+ * The opaque GstAacParse data structure.
+ */
+struct _GstAmrParse {
+  GstBaseParse element;
+  const gint *block_size;
+  gboolean need_header;
+  gboolean sent_codec_tag;
+  gint header;
+  gboolean wide;
+};
+
+/**
+ * GstAmrParseClass:
+ * @parent_class: Element parent class.
+ *
+ * The opaque GstAmrParseClass data structure.
+ */
+struct _GstAmrParseClass {
+  GstBaseParseClass parent_class;
+};
+
+GType gst_amr_parse_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_AMR_PARSE_H__ */
diff --git a/gst/audioparsers/gstdcaparse.c b/gst/audioparsers/gstdcaparse.c
new file mode 100644
index 0000000..1ea40ac
--- /dev/null
+++ b/gst/audioparsers/gstdcaparse.c
@@ -0,0 +1,617 @@
+/* GStreamer DCA parser
+ * Copyright (C) 2010 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-dcaparse
+ * @short_description: DCA (DTS Coherent Acoustics) parser
+ * @see_also: #GstAmrParse, #GstAACParse, #GstAc3Parse
+ *
+ * This is a DCA (DTS Coherent Acoustics) parser.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=abc.dts ! dcaparse ! dtsdec ! audioresample ! audioconvert ! autoaudiosink
+ * ]|
+ * </refsect2>
+ */
+
+/* TODO:
+ *  - should accept framed and unframed input (needs decodebin fixes first)
+ *  - seeking in raw .dts files doesn't seem to work, but duration estimate ok
+ *
+ *  - if frames have 'odd' durations, the frame durations (plus timestamps)
+ *    aren't adjusted up occasionally to make up for rounding error gaps.
+ *    (e.g. if 512 samples per frame @ 48kHz = 10.666666667 ms/frame)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstdcaparse.h"
+#include <gst/base/base.h>
+#include <gst/pbutils/pbutils.h>
+
+GST_DEBUG_CATEGORY_STATIC (dca_parse_debug);
+#define GST_CAT_DEFAULT dca_parse_debug
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-dts,"
+        " framed = (boolean) true,"
+        " channels = (int) [ 1, 8 ],"
+        " rate = (int) [ 8000, 192000 ],"
+        " depth = (int) { 14, 16 },"
+        " endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
+        " block-size = (int) [ 1, MAX], " " frame-size = (int) [ 1, MAX]"));
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-dts; " "audio/x-private1-dts"));
+
+static void gst_dca_parse_finalize (GObject * object);
+
+static gboolean gst_dca_parse_start (GstBaseParse * parse);
+static gboolean gst_dca_parse_stop (GstBaseParse * parse);
+static GstFlowReturn gst_dca_parse_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize);
+static GstFlowReturn gst_dca_parse_pre_push_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame);
+static GstCaps *gst_dca_parse_get_sink_caps (GstBaseParse * parse,
+    GstCaps * filter);
+static gboolean gst_dca_parse_set_sink_caps (GstBaseParse * parse,
+    GstCaps * caps);
+
+#define gst_dca_parse_parent_class parent_class
+G_DEFINE_TYPE (GstDcaParse, gst_dca_parse, GST_TYPE_BASE_PARSE);
+
+static void
+gst_dca_parse_class_init (GstDcaParseClass * klass)
+{
+  GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (dca_parse_debug, "dcaparse", 0,
+      "DCA audio stream parser");
+
+  object_class->finalize = gst_dca_parse_finalize;
+
+  parse_class->start = GST_DEBUG_FUNCPTR (gst_dca_parse_start);
+  parse_class->stop = GST_DEBUG_FUNCPTR (gst_dca_parse_stop);
+  parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_dca_parse_handle_frame);
+  parse_class->pre_push_frame =
+      GST_DEBUG_FUNCPTR (gst_dca_parse_pre_push_frame);
+  parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_dca_parse_get_sink_caps);
+  parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_dca_parse_set_sink_caps);
+
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "DTS Coherent Acoustics audio stream parser", "Codec/Parser/Audio",
+      "DCA parser", "Tim-Philipp Müller <tim centricular net>");
+}
+
+static void
+gst_dca_parse_reset (GstDcaParse * dcaparse)
+{
+  dcaparse->channels = -1;
+  dcaparse->rate = -1;
+  dcaparse->depth = -1;
+  dcaparse->endianness = -1;
+  dcaparse->block_size = -1;
+  dcaparse->frame_size = -1;
+  dcaparse->last_sync = 0;
+  dcaparse->sent_codec_tag = FALSE;
+}
+
+static void
+gst_dca_parse_init (GstDcaParse * dcaparse)
+{
+  gst_base_parse_set_min_frame_size (GST_BASE_PARSE (dcaparse),
+      DCA_MIN_FRAMESIZE);
+  gst_dca_parse_reset (dcaparse);
+  dcaparse->baseparse_chainfunc =
+      GST_BASE_PARSE_SINK_PAD (GST_BASE_PARSE (dcaparse))->chainfunc;
+
+  GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (dcaparse));
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (dcaparse));
+}
+
+static void
+gst_dca_parse_finalize (GObject * object)
+{
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_dca_parse_start (GstBaseParse * parse)
+{
+  GstDcaParse *dcaparse = GST_DCA_PARSE (parse);
+
+  GST_DEBUG_OBJECT (parse, "starting");
+
+  gst_dca_parse_reset (dcaparse);
+
+  return TRUE;
+}
+
+static gboolean
+gst_dca_parse_stop (GstBaseParse * parse)
+{
+  GST_DEBUG_OBJECT (parse, "stopping");
+
+  return TRUE;
+}
+
+static gboolean
+gst_dca_parse_parse_header (GstDcaParse * dcaparse,
+    const GstByteReader * reader, guint * frame_size,
+    guint * sample_rate, guint * channels, guint * depth,
+    gint * endianness, guint * num_blocks, guint * samples_per_block,
+    gboolean * terminator)
+{
+  static const int sample_rates[16] = { 0, 8000, 16000, 32000, 0, 0, 11025,
+    22050, 44100, 0, 0, 12000, 24000, 48000, 96000, 192000
+  };
+  static const guint8 channels_table[16] = { 1, 2, 2, 2, 2, 3, 3, 4, 4, 5,
+    6, 6, 6, 7, 8, 8
+  };
+  GstByteReader r = *reader;
+  guint16 hdr[8];
+  guint32 marker;
+  guint chans, lfe, i;
+
+  if (gst_byte_reader_get_remaining (&r) < (4 + sizeof (hdr)))
+    return FALSE;
+
+  marker = gst_byte_reader_peek_uint32_be_unchecked (&r);
+
+  /* raw big endian or 14-bit big endian */
+  if (marker == 0x7FFE8001 || marker == 0x1FFFE800) {
+    for (i = 0; i < G_N_ELEMENTS (hdr); ++i)
+      hdr[i] = gst_byte_reader_get_uint16_be_unchecked (&r);
+  } else
+    /* raw little endian or 14-bit little endian */
+  if (marker == 0xFE7F0180 || marker == 0xFF1F00E8) {
+    for (i = 0; i < G_N_ELEMENTS (hdr); ++i)
+      hdr[i] = gst_byte_reader_get_uint16_le_unchecked (&r);
+  } else {
+    return FALSE;
+  }
+
+  GST_LOG_OBJECT (dcaparse, "dts sync marker 0x%08x at offset %u", marker,
+      gst_byte_reader_get_pos (reader));
+
+  /* 14-bit mode */
+  if (marker == 0x1FFFE800 || marker == 0xFF1F00E8) {
+    if ((hdr[2] & 0xFFF0) != 0x07F0)
+      return FALSE;
+    /* discard top 2 bits (2 void), shift in 2 */
+    hdr[0] = (hdr[0] << 2) | ((hdr[1] >> 12) & 0x0003);
+    /* discard top 4 bits (2 void, 2 shifted into hdr[0]), shift in 4 etc. */
+    hdr[1] = (hdr[1] << 4) | ((hdr[2] >> 10) & 0x000F);
+    hdr[2] = (hdr[2] << 6) | ((hdr[3] >> 8) & 0x003F);
+    hdr[3] = (hdr[3] << 8) | ((hdr[4] >> 6) & 0x00FF);
+    hdr[4] = (hdr[4] << 10) | ((hdr[5] >> 4) & 0x03FF);
+    hdr[5] = (hdr[5] << 12) | ((hdr[6] >> 2) & 0x0FFF);
+    hdr[6] = (hdr[6] << 14) | ((hdr[7] >> 0) & 0x3FFF);
+    g_assert (hdr[0] == 0x7FFE && hdr[1] == 0x8001);
+  }
+
+  GST_LOG_OBJECT (dcaparse, "frame header: %04x%04x%04x%04x",
+      hdr[2], hdr[3], hdr[4], hdr[5]);
+
+  *terminator = (hdr[2] & 0x80) ? FALSE : TRUE;
+  *samples_per_block = ((hdr[2] >> 10) & 0x1f) + 1;
+  *num_blocks = ((hdr[2] >> 2) & 0x7F) + 1;
+  *frame_size = (((hdr[2] & 0x03) << 12) | (hdr[3] >> 4)) + 1;
+  chans = ((hdr[3] & 0x0F) << 2) | (hdr[4] >> 14);
+  *sample_rate = sample_rates[(hdr[4] >> 10) & 0x0F];
+  lfe = (hdr[5] >> 9) & 0x03;
+
+  GST_TRACE_OBJECT (dcaparse, "frame size %u, num_blocks %u, rate %u, "
+      "samples per block %u", *frame_size, *num_blocks, *sample_rate,
+      *samples_per_block);
+
+  if (*num_blocks < 6 || *frame_size < 96 || *sample_rate == 0)
+    return FALSE;
+
+  if (marker == 0x1FFFE800 || marker == 0xFF1F00E8)
+    *frame_size = (*frame_size * 16) / 14;      /* FIXME: round up? */
+
+  if (chans < G_N_ELEMENTS (channels_table))
+    *channels = channels_table[chans] + ((lfe) ? 1 : 0);
+  else
+    *channels = 0;
+
+  if (depth)
+    *depth = (marker == 0x1FFFE800 || marker == 0xFF1F00E8) ? 14 : 16;
+  if (endianness)
+    *endianness = (marker == 0xFE7F0180 || marker == 0xFF1F00E8) ?
+        G_LITTLE_ENDIAN : G_BIG_ENDIAN;
+
+  GST_TRACE_OBJECT (dcaparse, "frame size %u, channels %u, rate %u, "
+      "num_blocks %u, samples_per_block %u", *frame_size, *channels,
+      *sample_rate, *num_blocks, *samples_per_block);
+
+  return TRUE;
+}
+
+static gint
+gst_dca_parse_find_sync (GstDcaParse * dcaparse, GstByteReader * reader,
+    gsize bufsize, guint32 * sync)
+{
+  guint32 best_sync = 0;
+  guint best_offset = G_MAXUINT;
+  gint off;
+
+  /* FIXME: verify syncs via _parse_header() here already */
+
+  /* Raw little endian */
+  off = gst_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0xfe7f0180,
+      0, bufsize);
+  if (off >= 0 && off < best_offset) {
+    best_offset = off;
+    best_sync = 0xfe7f0180;
+  }
+
+  /* Raw big endian */
+  off = gst_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0x7ffe8001,
+      0, bufsize);
+  if (off >= 0 && off < best_offset) {
+    best_offset = off;
+    best_sync = 0x7ffe8001;
+  }
+
+  /* FIXME: check next 2 bytes as well for 14-bit formats (but then don't
+   * forget to adjust the *skipsize= in _check_valid_frame() */
+
+  /* 14-bit little endian  */
+  off = gst_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0xff1f00e8,
+      0, bufsize);
+  if (off >= 0 && off < best_offset) {
+    best_offset = off;
+    best_sync = 0xff1f00e8;
+  }
+
+  /* 14-bit big endian  */
+  off = gst_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0x1fffe800,
+      0, bufsize);
+  if (off >= 0 && off < best_offset) {
+    best_offset = off;
+    best_sync = 0x1fffe800;
+  }
+
+  if (best_offset == G_MAXUINT)
+    return -1;
+
+  *sync = best_sync;
+  return best_offset;
+}
+
+static GstFlowReturn
+gst_dca_parse_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize)
+{
+  GstDcaParse *dcaparse = GST_DCA_PARSE (parse);
+  GstBuffer *buf = frame->buffer;
+  GstByteReader r;
+  gboolean parser_in_sync;
+  gboolean terminator;
+  guint32 sync = 0;
+  guint size = 0, rate, chans, num_blocks, samples_per_block, depth;
+  gint block_size;
+  gint endianness;
+  gint off = -1;
+  GstMapInfo map;
+  GstFlowReturn ret = GST_FLOW_EOS;
+  gsize extra_size = 0;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  if (G_UNLIKELY (map.size < 16)) {
+    *skipsize = 1;
+    goto cleanup;
+  }
+
+  parser_in_sync = !GST_BASE_PARSE_LOST_SYNC (parse);
+
+  gst_byte_reader_init (&r, map.data, map.size);
+
+  if (G_LIKELY (parser_in_sync && dcaparse->last_sync != 0)) {
+    off = gst_byte_reader_masked_scan_uint32 (&r, 0xffffffff,
+        dcaparse->last_sync, 0, map.size);
+  }
+
+  if (G_UNLIKELY (off < 0)) {
+    off = gst_dca_parse_find_sync (dcaparse, &r, map.size, &sync);
+  }
+
+  /* didn't find anything that looks like a sync word, skip */
+  if (off < 0) {
+    *skipsize = map.size - 3;
+    GST_DEBUG_OBJECT (dcaparse, "no sync, skipping %d bytes", *skipsize);
+    goto cleanup;
+  }
+
+  GST_LOG_OBJECT (parse, "possible sync %08x at buffer offset %d", sync, off);
+
+  /* possible frame header, but not at offset 0? skip bytes before sync */
+  if (off > 0) {
+    *skipsize = off;
+    goto cleanup;
+  }
+
+  /* make sure the values in the frame header look sane */
+  if (!gst_dca_parse_parse_header (dcaparse, &r, &size, &rate, &chans, &depth,
+          &endianness, &num_blocks, &samples_per_block, &terminator)) {
+    *skipsize = 4;
+    goto cleanup;
+  }
+
+  GST_LOG_OBJECT (parse, "got frame, sync %08x, size %u, rate %d, channels %d",
+      sync, size, rate, chans);
+
+  dcaparse->last_sync = sync;
+
+  /* FIXME: Don't look for a second syncword, there are streams out there
+   * that consistently contain garbage between every frame so we never ever
+   * find a second consecutive syncword.
+   * See https://bugzilla.gnome.org/show_bug.cgi?id=738237
+   */
+#if 0
+  parser_draining = GST_BASE_PARSE_DRAINING (parse);
+
+  if (!parser_in_sync && !parser_draining) {
+    /* check for second frame to be sure */
+    GST_DEBUG_OBJECT (dcaparse, "resyncing; checking next frame syncword");
+    if (map.size >= (size + 16)) {
+      guint s2, r2, c2, n2, s3;
+      gboolean t;
+
+      GST_MEMDUMP ("buf", map.data, size + 16);
+      gst_byte_reader_init (&r, map.data, map.size);
+      gst_byte_reader_skip_unchecked (&r, size);
+
+      if (!gst_dca_parse_parse_header (dcaparse, &r, &s2, &r2, &c2, NULL, NULL,
+              &n2, &s3, &t)) {
+        GST_DEBUG_OBJECT (dcaparse, "didn't find second syncword");
+        *skipsize = 4;
+        goto cleanup;
+      }
+
+      /* ok, got sync now, let's assume constant frame size */
+      gst_base_parse_set_min_frame_size (parse, size);
+    } else {
+      /* wait for some more data */
+      GST_LOG_OBJECT (dcaparse,
+          "next sync out of reach (%" G_GSIZE_FORMAT " < %u)", map.size,
+          size + 16);
+      goto cleanup;
+    }
+  }
+#endif
+
+  /* found frame */
+  ret = GST_FLOW_OK;
+
+  /* metadata handling */
+  block_size = num_blocks * samples_per_block;
+
+  if (G_UNLIKELY (dcaparse->rate != rate || dcaparse->channels != chans
+          || dcaparse->depth != depth || dcaparse->endianness != endianness
+          || (!terminator && dcaparse->block_size != block_size)
+          || (size != dcaparse->frame_size))) {
+    GstCaps *caps;
+
+    caps = gst_caps_new_simple ("audio/x-dts",
+        "framed", G_TYPE_BOOLEAN, TRUE,
+        "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, chans,
+        "endianness", G_TYPE_INT, endianness, "depth", G_TYPE_INT, depth,
+        "block-size", G_TYPE_INT, block_size, "frame-size", G_TYPE_INT, size,
+        NULL);
+    gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
+    gst_caps_unref (caps);
+
+    dcaparse->rate = rate;
+    dcaparse->channels = chans;
+    dcaparse->depth = depth;
+    dcaparse->endianness = endianness;
+    dcaparse->block_size = block_size;
+    dcaparse->frame_size = size;
+
+    gst_base_parse_set_frame_rate (parse, rate, block_size, 0, 0);
+  }
+
+cleanup:
+  /* it is possible that DTS HD substream after DTS core */
+  if (parse->flags & GST_BASE_PARSE_FLAG_DRAINING || map.size >= size + 9) {
+    extra_size = 0;
+    if (map.size >= size + 9) {
+      const guint8 *next = map.data + size;
+      /* Check for DTS_SYNCWORD_SUBSTREAM */
+      if (next[0] == 0x64 && next[1] == 0x58 && next[2] == 0x20
+          && next[3] == 0x25) {
+        /* 7.4.1 Extension Substream Header */
+        GstBitReader reader;
+        gst_bit_reader_init (&reader, next + 4, 5);
+        gst_bit_reader_skip (&reader, 8 + 2);   /* skip UserDefinedBits and nExtSSIndex) */
+        if (gst_bit_reader_get_bits_uint8_unchecked (&reader, 1) == 0) {
+          gst_bit_reader_skip (&reader, 8);
+          extra_size =
+              gst_bit_reader_get_bits_uint32_unchecked (&reader, 16) + 1;
+        } else {
+          gst_bit_reader_skip (&reader, 12);
+          extra_size =
+              gst_bit_reader_get_bits_uint32_unchecked (&reader, 20) + 1;
+        }
+      }
+    }
+    gst_buffer_unmap (buf, &map);
+    if (ret == GST_FLOW_OK && size + extra_size <= map.size) {
+      ret = gst_base_parse_finish_frame (parse, frame, size + extra_size);
+    } else {
+      ret = GST_FLOW_OK;
+    }
+  } else {
+    gst_buffer_unmap (buf, &map);
+  }
+
+  return ret;
+}
+
+/*
+ * MPEG-PS private1 streams add a 2 bytes "Audio Substream Headers" for each
+ * buffer (not each frame) with the offset of the next frame's start.
+ * These 2 bytes can be dropped safely as they do not include any timing
+ * information, only the offset to the start of the next frame.
+ * See gstac3parse.c for a more detailed description.
+ * */
+
+static GstFlowReturn
+gst_dca_parse_chain_priv (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstDcaParse *dcaparse = GST_DCA_PARSE (parent);
+  GstFlowReturn ret;
+  GstBuffer *newbuf;
+  gsize size;
+
+  size = gst_buffer_get_size (buffer);
+  if (size >= 2) {
+    newbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, 2, size - 2);
+    gst_buffer_unref (buffer);
+    ret = dcaparse->baseparse_chainfunc (pad, parent, newbuf);
+  } else {
+    gst_buffer_unref (buffer);
+    ret = GST_FLOW_OK;
+  }
+
+  return ret;
+}
+
+static void
+remove_fields (GstCaps * caps)
+{
+  guint i, n;
+
+  n = gst_caps_get_size (caps);
+  for (i = 0; i < n; i++) {
+    GstStructure *s = gst_caps_get_structure (caps, i);
+
+    gst_structure_remove_field (s, "framed");
+  }
+}
+
+static GstCaps *
+gst_dca_parse_get_sink_caps (GstBaseParse * parse, GstCaps * filter)
+{
+  GstCaps *peercaps, *templ;
+  GstCaps *res;
+
+  templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
+  if (filter) {
+    GstCaps *fcopy = gst_caps_copy (filter);
+    /* Remove the fields we convert */
+    remove_fields (fcopy);
+    peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
+    gst_caps_unref (fcopy);
+  } else
+    peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), NULL);
+
+  if (peercaps) {
+    /* Remove the framed field */
+    peercaps = gst_caps_make_writable (peercaps);
+    remove_fields (peercaps);
+
+    res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (peercaps);
+    gst_caps_unref (templ);
+  } else {
+    res = templ;
+  }
+
+  if (filter) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (res);
+    res = intersection;
+  }
+
+  return res;
+}
+
+static gboolean
+gst_dca_parse_set_sink_caps (GstBaseParse * parse, GstCaps * caps)
+{
+  GstStructure *s;
+  GstDcaParse *dcaparse = GST_DCA_PARSE (parse);
+
+  s = gst_caps_get_structure (caps, 0);
+  if (gst_structure_has_name (s, "audio/x-private1-dts")) {
+    gst_pad_set_chain_function (parse->sinkpad, gst_dca_parse_chain_priv);
+  } else {
+    gst_pad_set_chain_function (parse->sinkpad, dcaparse->baseparse_chainfunc);
+  }
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_dca_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
+{
+  GstDcaParse *dcaparse = GST_DCA_PARSE (parse);
+
+  if (!dcaparse->sent_codec_tag) {
+    GstTagList *taglist;
+    GstCaps *caps;
+
+    /* codec tag */
+    caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
+    if (G_UNLIKELY (caps == NULL)) {
+      if (GST_PAD_IS_FLUSHING (GST_BASE_PARSE_SRC_PAD (parse))) {
+        GST_INFO_OBJECT (parse, "Src pad is flushing");
+        return GST_FLOW_FLUSHING;
+      } else {
+        GST_INFO_OBJECT (parse, "Src pad is not negotiated!");
+        return GST_FLOW_NOT_NEGOTIATED;
+      }
+    }
+
+    taglist = gst_tag_list_new_empty ();
+    gst_pb_utils_add_codec_description_to_tag_list (taglist,
+        GST_TAG_AUDIO_CODEC, caps);
+    gst_caps_unref (caps);
+
+    gst_base_parse_merge_tags (parse, taglist, GST_TAG_MERGE_REPLACE);
+    gst_tag_list_unref (taglist);
+
+    /* also signals the end of first-frame processing */
+    dcaparse->sent_codec_tag = TRUE;
+  }
+
+  return GST_FLOW_OK;
+}
diff --git a/gst/audioparsers/gstdcaparse.h b/gst/audioparsers/gstdcaparse.h
new file mode 100644
index 0000000..9198a06
--- /dev/null
+++ b/gst/audioparsers/gstdcaparse.h
@@ -0,0 +1,82 @@
+/* GStreamer DCA parser
+ * Copyright (C) 2010 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_DCA_PARSE_H__
+#define __GST_DCA_PARSE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbaseparse.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DCA_PARSE \
+  (gst_dca_parse_get_type())
+#define GST_DCA_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_DCA_PARSE, GstDcaParse))
+#define GST_DCA_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_DCA_PARSE, GstDcaParseClass))
+#define GST_IS_DCA_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_DCA_PARSE))
+#define GST_IS_DCA_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_DCA_PARSE))
+
+#define DCA_MIN_FRAMESIZE 96
+#define DCA_MAX_FRAMESIZE 18725 /* 16384*16/14 */
+
+typedef struct _GstDcaParse GstDcaParse;
+typedef struct _GstDcaParseClass GstDcaParseClass;
+
+/**
+ * GstDcaParse:
+ *
+ * The opaque GstDcaParse object
+ */
+struct _GstDcaParse {
+  GstBaseParse baseparse;
+
+  /*< private >*/
+  gint                  rate;
+  gint                  channels;
+  gint                  depth;
+  gint                  endianness;
+  gint                  block_size;
+  gint                  frame_size;
+
+  gboolean              sent_codec_tag;
+
+  guint32               last_sync;
+
+  GstPadChainFunction   baseparse_chainfunc;
+};
+
+/**
+ * GstDcaParseClass:
+ * @parent_class: Element parent class.
+ *
+ * The opaque GstDcaParseClass data structure.
+ */
+struct _GstDcaParseClass {
+  GstBaseParseClass baseparse_class;
+};
+
+GType gst_dca_parse_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_DCA_PARSE_H__ */
diff --git a/gst/audioparsers/gstflacparse.c b/gst/audioparsers/gstflacparse.c
new file mode 100644
index 0000000..69a6928
--- /dev/null
+++ b/gst/audioparsers/gstflacparse.c
@@ -0,0 +1,1877 @@
+/* GStreamer
+ *
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>.
+ * Copyright (C) 2009 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ * Copyright (C) 2009 Nokia Corporation. All rights reserved.
+ *   Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-flacparse
+ * @see_also: flacdec, oggdemux, vorbisparse
+ *
+ * The flacparse element will parse the header packets of the FLAC
+ * stream and put them as the streamheader in the caps. This is used in the
+ * multifdsink case where you want to stream live FLAC streams to multiple
+ * clients, each client has to receive the streamheaders first before they can
+ * consume the FLAC packets.
+ *
+ * This element also makes sure that the buffers that it pushes out are properly
+ * timestamped and that their offset and offset_end are set. The buffers that
+ * flacparse outputs have all of the metadata that oggmux expects to receive,
+ * which allows you to (for example) remux an ogg/flac or convert a native FLAC
+ * format file to an ogg bitstream.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -v filesrc location=sine.flac ! flacparse ! identity \
+ *            ! oggmux ! filesink location=sine-remuxed.ogg
+ * ]| This pipeline converts a native FLAC format file to an ogg bitstream.
+ * It also illustrates that the streamheader is set in the caps, and that each
+ * buffer has the timestamp, duration, offset, and offset_end set.
+ * </refsect2>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstflacparse.h"
+
+#include <string.h>
+#include <gst/tag/tag.h>
+#include <gst/audio/audio.h>
+#include <gst/base/base.h>
+#include <gst/pbutils/pbutils.h>
+
+GST_DEBUG_CATEGORY_STATIC (flacparse_debug);
+#define GST_CAT_DEFAULT flacparse_debug
+
+/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */
+static const guint8 crc8_table[256] = {
+  0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
+  0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
+  0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
+  0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
+  0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
+  0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
+  0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
+  0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
+  0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
+  0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
+  0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
+  0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
+  0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
+  0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
+  0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
+  0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
+  0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
+  0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
+  0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
+  0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
+  0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
+  0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
+  0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
+  0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
+  0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
+  0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
+  0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
+  0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
+  0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
+  0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
+  0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
+  0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
+};
+
+static guint8
+gst_flac_calculate_crc8 (const guint8 * data, guint length)
+{
+  guint8 crc = 0;
+
+  while (length--) {
+    crc = crc8_table[crc ^ *data];
+    ++data;
+  }
+
+  return crc;
+}
+
+/* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */
+static const guint16 crc16_table[256] = {
+  0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
+  0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
+  0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
+  0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
+  0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
+  0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
+  0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
+  0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
+  0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
+  0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
+  0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
+  0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
+  0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
+  0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
+  0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
+  0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
+  0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
+  0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
+  0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
+  0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
+  0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
+  0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
+  0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
+  0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
+  0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
+  0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
+  0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
+  0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
+  0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
+  0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
+  0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
+  0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
+};
+
+static guint16
+gst_flac_calculate_crc16 (const guint8 * data, guint length)
+{
+  guint16 crc = 0;
+
+  while (length--) {
+    crc = ((crc << 8) ^ crc16_table[(crc >> 8) ^ *data]) & 0xffff;
+    data++;
+  }
+
+  return crc;
+}
+
+enum
+{
+  PROP_0,
+  PROP_CHECK_FRAME_CHECKSUMS
+};
+
+#define DEFAULT_CHECK_FRAME_CHECKSUMS FALSE
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-flac, framed = (boolean) true, "
+        "channels = (int) [ 1, 8 ], " "rate = (int) [ 1, 655350 ]")
+    );
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-flac")
+    );
+
+static GstBuffer *gst_flac_parse_generate_vorbiscomment (GstFlacParse *
+    flacparse);
+
+static inline void gst_flac_parse_reset_buffer_time_and_offset (GstBuffer *
+    buffer);
+static void gst_flac_parse_reset (GstFlacParse * parser);
+static gboolean gst_flac_parse_handle_block_type (GstFlacParse * flacparse,
+    guint type, GstBuffer * sbuffer);
+static void gst_flac_parse_finalize (GObject * object);
+static void gst_flac_parse_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_flac_parse_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_flac_parse_start (GstBaseParse * parse);
+static gboolean gst_flac_parse_stop (GstBaseParse * parse);
+static GstFlowReturn gst_flac_parse_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize);
+static GstFlowReturn gst_flac_parse_parse_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint size);
+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);
+static gboolean gst_flac_parse_src_event (GstBaseParse * parse,
+    GstEvent * event);
+static GstCaps *gst_flac_parse_get_sink_caps (GstBaseParse * parse,
+    GstCaps * filter);
+
+#define gst_flac_parse_parent_class parent_class
+G_DEFINE_TYPE (GstFlacParse, gst_flac_parse, GST_TYPE_BASE_PARSE);
+
+static void
+gst_flac_parse_class_init (GstFlacParseClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GstBaseParseClass *baseparse_class = GST_BASE_PARSE_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (flacparse_debug, "flacparse", 0,
+      "Flac parser element");
+
+  gobject_class->finalize = gst_flac_parse_finalize;
+  gobject_class->set_property = gst_flac_parse_set_property;
+  gobject_class->get_property = gst_flac_parse_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_CHECK_FRAME_CHECKSUMS,
+      g_param_spec_boolean ("check-frame-checksums", "Check Frame Checksums",
+          "Check the overall checksums of every frame",
+          DEFAULT_CHECK_FRAME_CHECKSUMS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  baseparse_class->start = GST_DEBUG_FUNCPTR (gst_flac_parse_start);
+  baseparse_class->stop = GST_DEBUG_FUNCPTR (gst_flac_parse_stop);
+  baseparse_class->handle_frame =
+      GST_DEBUG_FUNCPTR (gst_flac_parse_handle_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);
+  baseparse_class->src_event = GST_DEBUG_FUNCPTR (gst_flac_parse_src_event);
+  baseparse_class->get_sink_caps =
+      GST_DEBUG_FUNCPTR (gst_flac_parse_get_sink_caps);
+
+  gst_element_class_add_static_pad_template (element_class, &src_factory);
+  gst_element_class_add_static_pad_template (element_class, &sink_factory);
+
+  gst_element_class_set_static_metadata (element_class, "FLAC audio parser",
+      "Codec/Parser/Audio",
+      "Parses audio with the FLAC lossless audio codec",
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+}
+
+static void
+gst_flac_parse_init (GstFlacParse * flacparse)
+{
+  flacparse->check_frame_checksums = DEFAULT_CHECK_FRAME_CHECKSUMS;
+  GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (flacparse));
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (flacparse));
+}
+
+static void
+gst_flac_parse_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstFlacParse *flacparse = GST_FLAC_PARSE (object);
+
+  switch (prop_id) {
+    case PROP_CHECK_FRAME_CHECKSUMS:
+      flacparse->check_frame_checksums = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_flac_parse_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstFlacParse *flacparse = GST_FLAC_PARSE (object);
+
+  switch (prop_id) {
+    case PROP_CHECK_FRAME_CHECKSUMS:
+      g_value_set_boolean (value, flacparse->check_frame_checksums);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_flac_parse_reset (GstFlacParse * parser)
+{
+  if (parser->tags) {
+    gst_tag_list_unref (parser->tags);
+    parser->tags = NULL;
+  }
+  if (parser->toc) {
+    gst_toc_unref (parser->toc);
+    parser->toc = NULL;
+  }
+  if (parser->seektable) {
+    gst_buffer_unref (parser->seektable);
+    parser->seektable = NULL;
+  }
+
+  g_list_foreach (parser->headers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (parser->headers);
+  parser->headers = NULL;
+}
+
+static void
+gst_flac_parse_finalize (GObject * object)
+{
+  GstFlacParse *flacparse = GST_FLAC_PARSE (object);
+
+  gst_flac_parse_reset (flacparse);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_flac_parse_start (GstBaseParse * parse)
+{
+  GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
+
+  flacparse->state = GST_FLAC_PARSE_STATE_INIT;
+  flacparse->min_blocksize = 0;
+  flacparse->max_blocksize = 0;
+  flacparse->min_framesize = 0;
+  flacparse->max_framesize = 0;
+
+  flacparse->upstream_length = -1;
+
+  flacparse->samplerate = 0;
+  flacparse->channels = 0;
+  flacparse->bps = 0;
+  flacparse->total_samples = 0;
+
+  flacparse->offset = GST_CLOCK_TIME_NONE;
+  flacparse->blocking_strategy = 0;
+  flacparse->block_size = 0;
+  flacparse->sample_number = 0;
+  flacparse->strategy_checked = FALSE;
+
+  flacparse->sent_codec_tag = FALSE;
+
+  /* "fLaC" marker */
+  gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 4);
+
+  /* inform baseclass we can come up with ts, based on counters in packets */
+  gst_base_parse_set_has_timing_info (GST_BASE_PARSE_CAST (flacparse), TRUE);
+  gst_base_parse_set_syncable (GST_BASE_PARSE_CAST (flacparse), TRUE);
+
+  return TRUE;
+}
+
+static gboolean
+gst_flac_parse_stop (GstBaseParse * parse)
+{
+  GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
+
+  gst_flac_parse_reset (flacparse);
+  return TRUE;
+}
+
+static const guint8 sample_size_table[] = { 0, 8, 12, 0, 16, 20, 24, 0 };
+
+static const guint16 blocksize_table[16] = {
+  0, 192, 576 << 0, 576 << 1, 576 << 2, 576 << 3, 0, 0,
+  256 << 0, 256 << 1, 256 << 2, 256 << 3, 256 << 4, 256 << 5, 256 << 6,
+  256 << 7,
+};
+
+static const guint32 sample_rate_table[16] = {
+  0,
+  88200, 176400, 192000,
+  8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000,
+  0, 0, 0, 0,
+};
+
+typedef enum
+{
+  FRAME_HEADER_VALID,
+  FRAME_HEADER_INVALID,
+  FRAME_HEADER_MORE_DATA
+} FrameHeaderCheckReturn;
+
+static FrameHeaderCheckReturn
+gst_flac_parse_frame_header_is_valid (GstFlacParse * flacparse,
+    const guint8 * data, guint size, gboolean set, guint16 * block_size_ret,
+    gboolean * suspect)
+{
+  GstBitReader reader = GST_BIT_READER_INIT (data, size);
+  guint8 blocking_strategy;
+  guint16 block_size;
+  guint32 samplerate = 0;
+  guint64 sample_number;
+  guint8 channels, bps;
+  guint8 tmp = 0;
+  guint8 actual_crc, expected_crc = 0;
+
+  /* Skip 14 bit sync code */
+  gst_bit_reader_skip_unchecked (&reader, 14);
+
+  /* Must be 0 */
+  if (gst_bit_reader_get_bits_uint8_unchecked (&reader, 1) != 0)
+    goto error;
+
+  /* 0 == fixed block size, 1 == variable block size */
+  blocking_strategy = gst_bit_reader_get_bits_uint8_unchecked (&reader, 1);
+  if (flacparse->force_variable_block_size)
+    blocking_strategy = 1;
+
+  /* block size index, calculation of the real blocksize below */
+  block_size = gst_bit_reader_get_bits_uint16_unchecked (&reader, 4);
+  if (block_size == 0)
+    goto error;
+
+  /* sample rate index, calculation of the real samplerate below */
+  samplerate = gst_bit_reader_get_bits_uint16_unchecked (&reader, 4);
+  if (samplerate == 0x0f)
+    goto error;
+
+  /* channel assignment */
+  channels = gst_bit_reader_get_bits_uint8_unchecked (&reader, 4);
+  if (channels < 8) {
+    channels++;
+  } else if (channels <= 10) {
+    channels = 2;
+  } else if (channels > 10) {
+    goto error;
+  }
+  if (flacparse->channels && flacparse->channels != channels)
+    goto error;
+
+  /* bits per sample */
+  bps = gst_bit_reader_get_bits_uint8_unchecked (&reader, 3);
+  if (bps == 0x03 || bps == 0x07) {
+    goto error;
+  } else if (bps == 0 && flacparse->bps == 0) {
+    goto need_streaminfo;
+  }
+  bps = sample_size_table[bps];
+  if (flacparse->bps && bps != flacparse->bps)
+    goto error;
+
+  /* reserved, must be 0 */
+  if (gst_bit_reader_get_bits_uint8_unchecked (&reader, 1) != 0)
+    goto error;
+
+  /* read "utf8" encoded sample/frame number */
+  {
+    gint len = 0;
+
+    len = gst_bit_reader_get_bits_uint8_unchecked (&reader, 8);
+
+    /* This is slightly faster than a loop */
+    if (!(len & 0x80)) {
+      sample_number = len;
+      len = 0;
+    } else if ((len & 0xc0) && !(len & 0x20)) {
+      sample_number = len & 0x1f;
+      len = 1;
+    } else if ((len & 0xe0) && !(len & 0x10)) {
+      sample_number = len & 0x0f;
+      len = 2;
+    } else if ((len & 0xf0) && !(len & 0x08)) {
+      sample_number = len & 0x07;
+      len = 3;
+    } else if ((len & 0xf8) && !(len & 0x04)) {
+      sample_number = len & 0x03;
+      len = 4;
+    } else if ((len & 0xfc) && !(len & 0x02)) {
+      sample_number = len & 0x01;
+      len = 5;
+    } else if ((len & 0xfe) && !(len & 0x01)) {
+      sample_number = len & 0x0;
+      len = 6;
+    } else {
+      goto error;
+    }
+
+    if ((blocking_strategy == 0 && len > 5) ||
+        (blocking_strategy == 1 && len > 6))
+      goto error;
+
+    while (len > 0) {
+      if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 8))
+        goto need_more_data;
+
+      if ((tmp & 0xc0) != 0x80)
+        goto error;
+
+      sample_number <<= 6;
+      sample_number |= (tmp & 0x3f);
+      len--;
+    }
+  }
+
+  /* calculate real blocksize from the blocksize index */
+  if (block_size == 6) {
+    if (!gst_bit_reader_get_bits_uint16 (&reader, &block_size, 8))
+      goto need_more_data;
+    block_size++;
+  } else if (block_size == 7) {
+    if (!gst_bit_reader_get_bits_uint16 (&reader, &block_size, 16))
+      goto need_more_data;
+    block_size++;
+  } else {
+    block_size = blocksize_table[block_size];
+  }
+
+  /* calculate the real samplerate from the samplerate index */
+  if (samplerate == 0 && flacparse->samplerate == 0) {
+    goto need_streaminfo;
+  } else if (samplerate < 12) {
+    samplerate = sample_rate_table[samplerate];
+  } else if (samplerate == 12) {
+    if (!gst_bit_reader_get_bits_uint32 (&reader, &samplerate, 8))
+      goto need_more_data;
+    samplerate *= 1000;
+  } else if (samplerate == 13) {
+    if (!gst_bit_reader_get_bits_uint32 (&reader, &samplerate, 16))
+      goto need_more_data;
+  } else if (samplerate == 14) {
+    if (!gst_bit_reader_get_bits_uint32 (&reader, &samplerate, 16))
+      goto need_more_data;
+    samplerate *= 10;
+  }
+
+  if (flacparse->samplerate && flacparse->samplerate != samplerate)
+    goto error;
+
+  /* check crc-8 for the header */
+  if (!gst_bit_reader_get_bits_uint8 (&reader, &expected_crc, 8))
+    goto need_more_data;
+
+  actual_crc =
+      gst_flac_calculate_crc8 (data,
+      (gst_bit_reader_get_pos (&reader) / 8) - 1);
+  if (actual_crc != expected_crc) {
+    GST_DEBUG_OBJECT (flacparse,
+        "Checksum mismatch. Header CRC was '%d' but frame has '%d'",
+        expected_crc, actual_crc);
+    goto error;
+  }
+
+  /* Sanity check sample number against blocking strategy, as it seems
+     some files claim fixed block size but supply sample numbers,
+     rather than block numbers. */
+  if (blocking_strategy == 0 && flacparse->block_size != 0) {
+    if (!flacparse->strategy_checked) {
+      if (block_size == sample_number) {
+        GST_WARNING_OBJECT (flacparse, "This file claims fixed block size, "
+            "but seems to be lying: assuming variable block size");
+        flacparse->force_variable_block_size = TRUE;
+        blocking_strategy = 1;
+      }
+      flacparse->strategy_checked = TRUE;
+    }
+  }
+
+  /* documentation says:
+   * The "blocking strategy" bit must be the same throughout the entire stream. */
+  if (flacparse->blocking_strategy != blocking_strategy) {
+    if (flacparse->block_size != 0) {
+      GST_WARNING_OBJECT (flacparse, "blocking strategy is not constant");
+      if (suspect)
+        *suspect = TRUE;
+    }
+  }
+
+  /*
+     The FLAC format documentation says:
+     The "blocking strategy" bit determines how to calculate the sample number
+     of the first sample in the frame. If the bit is 0 (fixed-blocksize), the
+     frame header encodes the frame number as above, and the frame's starting
+     sample number will be the frame number times the blocksize. If it is 1
+     (variable-blocksize), the frame header encodes the frame's starting
+     sample number itself. (In the case of a fixed-blocksize stream, only the
+     last block may be shorter than the stream blocksize; its starting sample
+     number will be calculated as the frame number times the previous frame's
+     blocksize, or zero if it is the first frame).
+
+     Therefore, when in fixed block size mode, we only update the block size
+     the first time, then reuse that block size for subsequent calls.
+     This will also fix a timestamp problem with the last block's timestamp
+     being miscalculated by scaling the block number by a "wrong" block size.
+   */
+  if (blocking_strategy == 0) {
+    if (flacparse->block_size != 0) {
+      /* after first block */
+      if (flacparse->block_size != block_size) {
+        /* TODO: can we know we're on the last frame, to avoid warning ? */
+        GST_WARNING_OBJECT (flacparse, "Block size is not constant");
+        block_size = flacparse->block_size;
+        if (suspect)
+          *suspect = TRUE;
+      }
+    }
+  }
+
+  if (set) {
+    flacparse->block_size = block_size;
+    if (!flacparse->samplerate)
+      flacparse->samplerate = samplerate;
+    if (!flacparse->bps)
+      flacparse->bps = bps;
+    if (!flacparse->blocking_strategy)
+      flacparse->blocking_strategy = blocking_strategy;
+    if (!flacparse->channels)
+      flacparse->channels = channels;
+    if (!flacparse->sample_number)
+      flacparse->sample_number = sample_number;
+
+    GST_DEBUG_OBJECT (flacparse,
+        "Parsed frame at offset %" G_GUINT64_FORMAT ":\n" "Block size: %u\n"
+        "Sample/Frame number: %" G_GUINT64_FORMAT, flacparse->offset,
+        flacparse->block_size, flacparse->sample_number);
+  }
+
+  if (block_size_ret)
+    *block_size_ret = block_size;
+
+  return FRAME_HEADER_VALID;
+
+need_streaminfo:
+  GST_ERROR_OBJECT (flacparse, "Need STREAMINFO metadata. Bits per sample "
+      "or sample rate not in frame header");
+error:
+  return FRAME_HEADER_INVALID;
+
+need_more_data:
+  return FRAME_HEADER_MORE_DATA;
+}
+
+static gboolean
+gst_flac_parse_frame_is_valid (GstFlacParse * flacparse,
+    const guint8 * data, gsize size, guint * ret)
+{
+  guint max, remaining;
+  guint i, search_start, search_end;
+  FrameHeaderCheckReturn header_ret;
+  guint16 block_size;
+  gboolean suspect_start = FALSE, suspect_end = FALSE;
+
+  if (size < flacparse->min_framesize)
+    goto need_more;
+
+  header_ret =
+      gst_flac_parse_frame_header_is_valid (flacparse, data, size, TRUE,
+      &block_size, &suspect_start);
+  if (header_ret == FRAME_HEADER_INVALID) {
+    *ret = 0;
+    return FALSE;
+  }
+  if (header_ret == FRAME_HEADER_MORE_DATA)
+    goto need_more;
+
+  /* mind unknown framesize */
+  search_start = MAX (2, flacparse->min_framesize);
+  if (flacparse->max_framesize)
+    search_end = MIN (size, flacparse->max_framesize + 9 + 2);
+  else
+    search_end = size;
+  search_end -= 2;
+
+  remaining = size;
+
+  for (i = search_start; i < search_end; i++, remaining--) {
+
+    if ((GST_READ_UINT16_BE (data + i) & 0xfffe) != 0xfff8)
+      continue;
+
+    GST_LOG_OBJECT (flacparse, "possible frame end at offset %d", i);
+    suspect_end = FALSE;
+    header_ret =
+        gst_flac_parse_frame_header_is_valid (flacparse, data + i,
+        remaining, FALSE, NULL, &suspect_end);
+    if (header_ret == FRAME_HEADER_VALID) {
+      if (flacparse->check_frame_checksums || suspect_start || suspect_end) {
+        guint16 actual_crc = gst_flac_calculate_crc16 (data, i - 2);
+        guint16 expected_crc = GST_READ_UINT16_BE (data + i - 2);
+
+        GST_LOG_OBJECT (flacparse,
+            "Found possible frame (%d, %d). Checking for CRC match",
+            suspect_start, suspect_end);
+        if (actual_crc != expected_crc) {
+          GST_DEBUG_OBJECT (flacparse,
+              "Checksum mismatch. Header CRC was '%d' but frame has '%d'",
+              expected_crc, actual_crc);
+          continue;
+        }
+      }
+      *ret = i;
+      flacparse->block_size = block_size;
+      return TRUE;
+    } else if (header_ret == FRAME_HEADER_MORE_DATA) {
+      goto need_more;
+    }
+  }
+
+  /* For the last frame output everything to the end */
+  if (G_UNLIKELY (GST_BASE_PARSE_DRAINING (flacparse))) {
+    if (flacparse->check_frame_checksums) {
+      guint16 actual_crc = gst_flac_calculate_crc16 (data, size - 2);
+      guint16 expected_crc = GST_READ_UINT16_BE (data + size - 2);
+
+      if (actual_crc == expected_crc) {
+        *ret = size;
+        flacparse->block_size = block_size;
+        return TRUE;
+      }
+    } else {
+      *ret = size;
+      flacparse->block_size = block_size;
+      return TRUE;
+    }
+  }
+
+  /* so we searched to expected end and found nothing,
+   * give up on this frame (start) */
+  if (flacparse->max_framesize && i > 2 * flacparse->max_framesize) {
+    GST_LOG_OBJECT (flacparse,
+        "could not determine valid frame end, discarding frame (start)");
+    *ret = 1;
+    return FALSE;
+  }
+
+need_more:
+  max = flacparse->max_framesize + 16;
+  if (max == 16)
+    max = 1 << 24;
+  *ret = MIN (size + 4096, max);
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_flac_parse_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize)
+{
+  GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
+  GstBuffer *buffer = frame->buffer;
+  GstMapInfo map;
+  gboolean result = TRUE;
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint framesize = 0;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  *skipsize = 1;
+
+  if (G_UNLIKELY (map.size < 4)) {
+    result = FALSE;
+    goto cleanup;
+  }
+
+  if (flacparse->state == GST_FLAC_PARSE_STATE_INIT) {
+    if (memcmp (map.data, "fLaC", 4) == 0) {
+      GST_DEBUG_OBJECT (flacparse, "fLaC marker found");
+      framesize = 4;
+      goto cleanup;
+    }
+    if (map.data[0] == 0xff && (map.data[1] >> 2) == 0x3e) {
+      GST_DEBUG_OBJECT (flacparse, "Found headerless FLAC");
+      /* Minimal size of a frame header */
+      gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 9);
+      flacparse->state = GST_FLAC_PARSE_STATE_GENERATE_HEADERS;
+      *skipsize = 0;
+      result = FALSE;
+      goto cleanup;
+    }
+    GST_DEBUG_OBJECT (flacparse, "fLaC marker not found");
+    result = FALSE;
+    goto cleanup;
+  }
+
+  if (flacparse->state == GST_FLAC_PARSE_STATE_HEADERS) {
+    guint size = 4 + ((map.data[1] << 16) | (map.data[2] << 8) | (map.data[3]));
+
+    GST_DEBUG_OBJECT (flacparse, "Found metadata block of size %u", size);
+    framesize = size;
+    gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), framesize);
+    goto cleanup;
+  }
+
+  if ((GST_READ_UINT16_BE (map.data) & 0xfffe) == 0xfff8) {
+    gboolean ret, is_first = !flacparse->strategy_checked;
+    guint next;
+
+    flacparse->offset = GST_BUFFER_OFFSET (buffer);
+    flacparse->blocking_strategy = 0;
+    flacparse->sample_number = 0;
+
+    GST_DEBUG_OBJECT (flacparse, "Found sync code");
+    ret = gst_flac_parse_frame_is_valid (flacparse, map.data, map.size, &next);
+    if (ret) {
+      if (is_first) {
+        GST_INFO_OBJECT (flacparse, "First sample number is %" G_GUINT64_FORMAT,
+            flacparse->sample_number);
+        flacparse->first_sample_number = flacparse->sample_number;
+      }
+      framesize = next;
+      goto cleanup;
+    }
+
+    /* If we're at EOS and the frame was not valid, drop it! */
+    if (G_UNLIKELY (GST_BASE_PARSE_DRAINING (flacparse))) {
+      GST_WARNING_OBJECT (flacparse, "EOS");
+      result = FALSE;
+      goto cleanup;
+    }
+
+    if (next == 0) {
+    } else if (next > map.size) {
+      GST_DEBUG_OBJECT (flacparse, "Requesting %u bytes", next);
+      *skipsize = 0;
+      gst_base_parse_set_min_frame_size (parse, next);
+      result = FALSE;
+      goto cleanup;
+    } else {
+      GST_ERROR_OBJECT (flacparse,
+          "Giving up on invalid frame (%" G_GSIZE_FORMAT " bytes)", map.size);
+      result = FALSE;
+      goto cleanup;
+    }
+  } else {
+    GstByteReader reader;
+    gint off;
+
+    gst_byte_reader_init (&reader, map.data, map.size);
+    off =
+        gst_byte_reader_masked_scan_uint32 (&reader, 0xfffc0000, 0xfff80000,
+        0, map.size);
+
+    if (off > 0) {
+      GST_DEBUG_OBJECT (parse, "Possible sync at buffer offset %d", off);
+      *skipsize = off;
+      result = FALSE;
+      goto cleanup;
+    }
+
+    GST_DEBUG_OBJECT (flacparse, "Sync code not found");
+    *skipsize = map.size - 3;
+    result = FALSE;
+    goto cleanup;
+  }
+
+  result = FALSE;
+
+cleanup:
+  gst_buffer_unmap (buffer, &map);
+
+  if (result)
+    *skipsize = 0;
+
+  if (result && framesize <= map.size) {
+    ret = gst_flac_parse_parse_frame (parse, frame, framesize);
+    if (ret == GST_BASE_PARSE_FLOW_DROPPED) {
+      frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
+      ret = GST_FLOW_OK;
+    }
+    if (ret == GST_FLOW_OK)
+      ret = gst_base_parse_finish_frame (parse, frame, framesize);
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_flac_parse_handle_streaminfo (GstFlacParse * flacparse, GstBuffer * buffer)
+{
+  GstBitReader reader;
+  GstMapInfo map;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  gst_bit_reader_init (&reader, map.data, map.size);
+
+  if (map.size != 4 + 34) {
+    GST_ERROR_OBJECT (flacparse,
+        "Invalid metablock size for STREAMINFO: %" G_GSIZE_FORMAT "", map.size);
+    goto failure;
+  }
+
+  /* Skip metadata block header */
+  if (!gst_bit_reader_skip (&reader, 32))
+    goto error;
+
+  if (!gst_bit_reader_get_bits_uint16 (&reader, &flacparse->min_blocksize, 16))
+    goto error;
+  if (flacparse->min_blocksize < 16) {
+    GST_WARNING_OBJECT (flacparse, "Invalid minimum block size: %u",
+        flacparse->min_blocksize);
+  }
+
+  if (!gst_bit_reader_get_bits_uint16 (&reader, &flacparse->max_blocksize, 16))
+    goto error;
+  if (flacparse->max_blocksize < 16) {
+    GST_WARNING_OBJECT (flacparse, "Invalid maximum block size: %u",
+        flacparse->max_blocksize);
+  }
+
+  if (!gst_bit_reader_get_bits_uint32 (&reader, &flacparse->min_framesize, 24))
+    goto error;
+  if (!gst_bit_reader_get_bits_uint32 (&reader, &flacparse->max_framesize, 24))
+    goto error;
+
+  if (!gst_bit_reader_get_bits_uint32 (&reader, &flacparse->samplerate, 20))
+    goto error;
+  if (flacparse->samplerate == 0) {
+    GST_ERROR_OBJECT (flacparse, "Invalid sample rate 0");
+    goto failure;
+  }
+
+  if (!gst_bit_reader_get_bits_uint8 (&reader, &flacparse->channels, 3))
+    goto error;
+  flacparse->channels++;
+  if (flacparse->channels > 8) {
+    GST_ERROR_OBJECT (flacparse, "Invalid number of channels %u",
+        flacparse->channels);
+    goto failure;
+  }
+
+  if (!gst_bit_reader_get_bits_uint8 (&reader, &flacparse->bps, 5))
+    goto error;
+  flacparse->bps++;
+
+  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_DEFAULT, flacparse->total_samples, 0);
+  }
+
+  gst_buffer_unmap (buffer, &map);
+
+  GST_DEBUG_OBJECT (flacparse, "STREAMINFO:\n"
+      "\tmin/max blocksize: %u/%u,\n"
+      "\tmin/max framesize: %u/%u,\n"
+      "\tsamplerate: %u,\n"
+      "\tchannels: %u,\n"
+      "\tbits per sample: %u,\n"
+      "\ttotal samples: %" G_GUINT64_FORMAT,
+      flacparse->min_blocksize, flacparse->max_blocksize,
+      flacparse->min_framesize, flacparse->max_framesize,
+      flacparse->samplerate,
+      flacparse->channels, flacparse->bps, flacparse->total_samples);
+
+  return TRUE;
+
+error:
+  GST_ERROR_OBJECT (flacparse, "Failed to read data");
+failure:
+  gst_buffer_unmap (buffer, &map);
+  return FALSE;
+}
+
+static gboolean
+gst_flac_parse_handle_vorbiscomment (GstFlacParse * flacparse,
+    GstBuffer * buffer)
+{
+  GstTagList *tags;
+  GstMapInfo map;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  tags =
+      gst_tag_list_from_vorbiscomment (map.data, map.size, map.data, 4, NULL);
+  gst_buffer_unmap (buffer, &map);
+
+  if (tags == NULL) {
+    GST_ERROR_OBJECT (flacparse, "Invalid vorbiscomment block");
+  } else if (gst_tag_list_is_empty (tags)) {
+    gst_tag_list_unref (tags);
+  } else if (flacparse->tags == NULL) {
+    flacparse->tags = tags;
+  } else {
+    gst_tag_list_insert (flacparse->tags, tags, GST_TAG_MERGE_APPEND);
+    gst_tag_list_unref (tags);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_flac_parse_handle_cuesheet (GstFlacParse * flacparse, GstBuffer * buffer)
+{
+  GstByteReader reader;
+  GstMapInfo map;
+  guint i, j;
+  guint8 n_tracks, track_num, index;
+  guint64 offset;
+  gint64 start, stop;
+  gchar *id;
+  gchar isrc[13];
+  GstTagList *tags;
+  GstToc *toc;
+  GstTocEntry *cur_entry = NULL, *prev_entry = NULL;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  gst_byte_reader_init (&reader, map.data, map.size);
+
+  toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
+
+  /* skip 4 bytes METADATA_BLOCK_HEADER */
+  /* https://xiph.org/flac/format.html#metadata_block_header */
+  if (!gst_byte_reader_skip (&reader, 4))
+    goto error;
+
+  /* skip 395 bytes from METADATA_BLOCK_CUESHEET */
+  /* https://xiph.org/flac/format.html#metadata_block_cuesheet */
+  if (!gst_byte_reader_skip (&reader, 395))
+    goto error;
+
+  if (!gst_byte_reader_get_uint8 (&reader, &n_tracks))
+    goto error;
+
+  /* CUESHEET_TRACK */
+  /* https://xiph.org/flac/format.html#cuesheet_track */
+  for (i = 0; i < n_tracks; i++) {
+    if (!gst_byte_reader_get_uint64_be (&reader, &offset))
+      goto error;
+    if (!gst_byte_reader_get_uint8 (&reader, &track_num))
+      goto error;
+
+    if (gst_byte_reader_get_remaining (&reader) < 12)
+      goto error;
+    memcpy (isrc, map.data + gst_byte_reader_get_pos (&reader), 12);
+    /* \0-terminate the string */
+    isrc[12] = '\0';
+    if (!gst_byte_reader_skip (&reader, 12))
+      goto error;
+
+    /* skip 14 bytes from CUESHEET_TRACK */
+    if (!gst_byte_reader_skip (&reader, 14))
+      goto error;
+    if (!gst_byte_reader_get_uint8 (&reader, &index))
+      goto error;
+    /* add tracks in TOC */
+    /* lead-out tack has number 170 or 255 */
+    if (track_num != 170 && track_num != 255) {
+      prev_entry = cur_entry;
+      /* previous track stop time = current track start time */
+      if (prev_entry != NULL) {
+        gst_toc_entry_get_start_stop_times (prev_entry, &start, NULL);
+        stop =
+            gst_util_uint64_scale_round (offset, GST_SECOND,
+            flacparse->samplerate);
+        gst_toc_entry_set_start_stop_times (prev_entry, start, stop);
+      }
+      id = g_strdup_printf ("%08x", track_num);
+      cur_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_TRACK, id);
+      g_free (id);
+      start =
+          gst_util_uint64_scale_round (offset, GST_SECOND,
+          flacparse->samplerate);
+      gst_toc_entry_set_start_stop_times (cur_entry, start, -1);
+      /* add ISRC as tag in track */
+      if (strlen (isrc) != 0) {
+        tags = gst_tag_list_new_empty ();
+        gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_ISRC, isrc, NULL);
+        gst_toc_entry_set_tags (cur_entry, tags);
+      }
+      gst_toc_append_entry (toc, cur_entry);
+      /* CUESHEET_TRACK_INDEX */
+      /* https://xiph.org/flac/format.html#cuesheet_track_index */
+      for (j = 0; j < index; j++) {
+        if (!gst_byte_reader_skip (&reader, 12))
+          goto error;
+      }
+    } else {
+      /* set stop time in last track */
+      stop =
+          gst_util_uint64_scale_round (offset, GST_SECOND,
+          flacparse->samplerate);
+      gst_toc_entry_set_start_stop_times (cur_entry, start, stop);
+    }
+  }
+
+  /* send data as TOC */
+  if (!flacparse->toc)
+    flacparse->toc = toc;
+
+  gst_buffer_unmap (buffer, &map);
+  return TRUE;
+
+error:
+  GST_ERROR_OBJECT (flacparse, "Error reading data");
+  gst_buffer_unmap (buffer, &map);
+  return FALSE;
+}
+
+static gboolean
+gst_flac_parse_handle_picture (GstFlacParse * flacparse, GstBuffer * buffer)
+{
+  GstByteReader reader;
+  GstMapInfo map;
+  guint32 img_len = 0, img_type = 0;
+  guint32 img_mimetype_len = 0, img_description_len = 0;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  gst_byte_reader_init (&reader, map.data, map.size);
+
+  if (!gst_byte_reader_skip (&reader, 4))
+    goto error;
+
+  if (!gst_byte_reader_get_uint32_be (&reader, &img_type))
+    goto error;
+
+  if (!gst_byte_reader_get_uint32_be (&reader, &img_mimetype_len))
+    goto error;
+  if (!gst_byte_reader_skip (&reader, img_mimetype_len))
+    goto error;
+
+  if (!gst_byte_reader_get_uint32_be (&reader, &img_description_len))
+    goto error;
+  if (!gst_byte_reader_skip (&reader, img_description_len))
+    goto error;
+
+  if (!gst_byte_reader_skip (&reader, 4 * 4))
+    goto error;
+
+  if (!gst_byte_reader_get_uint32_be (&reader, &img_len))
+    goto error;
+
+  if (gst_byte_reader_get_pos (&reader) + img_len > map.size)
+    goto error;
+
+  GST_INFO_OBJECT (flacparse, "Got image of %d bytes", img_len);
+
+  if (img_len > 0) {
+    if (flacparse->tags == NULL)
+      flacparse->tags = gst_tag_list_new_empty ();
+
+    gst_tag_list_add_id3_image (flacparse->tags,
+        map.data + gst_byte_reader_get_pos (&reader), img_len, img_type);
+  }
+
+  gst_buffer_unmap (buffer, &map);
+  return TRUE;
+
+error:
+  GST_ERROR_OBJECT (flacparse, "Error reading data");
+  gst_buffer_unmap (buffer, &map);
+  return FALSE;
+}
+
+static gboolean
+gst_flac_parse_handle_seektable (GstFlacParse * flacparse, GstBuffer * buffer)
+{
+
+  GST_DEBUG_OBJECT (flacparse, "storing seektable");
+  /* only store for now;
+   * offset of the first frame is needed to get real info */
+  if (flacparse->seektable)
+    gst_buffer_unref (flacparse->seektable);
+  flacparse->seektable = gst_buffer_ref (buffer);
+
+  return TRUE;
+}
+
+static void
+gst_flac_parse_process_seektable (GstFlacParse * flacparse, gint64 boffset)
+{
+  GstByteReader br;
+  gint64 offset = 0, samples = 0;
+  GstMapInfo map;
+
+  GST_DEBUG_OBJECT (flacparse,
+      "parsing seektable; base offset %" G_GINT64_FORMAT, boffset);
+
+  if (boffset <= 0)
+    goto exit;
+
+  gst_buffer_map (flacparse->seektable, &map, GST_MAP_READ);
+  gst_byte_reader_init (&br, map.data, map.size);
+
+  /* skip header */
+  if (!gst_byte_reader_skip (&br, 4))
+    goto done;
+
+  /* seekpoints */
+  while (gst_byte_reader_get_remaining (&br)) {
+    if (!gst_byte_reader_get_int64_be (&br, &samples))
+      break;
+    if (!gst_byte_reader_get_int64_be (&br, &offset))
+      break;
+    if (!gst_byte_reader_skip (&br, 2))
+      break;
+
+    GST_LOG_OBJECT (flacparse, "samples %" G_GINT64_FORMAT " -> offset %"
+        G_GINT64_FORMAT, samples, offset);
+
+    /* sanity check */
+    if (G_LIKELY (offset > 0 && samples > 0)) {
+      gst_base_parse_add_index_entry (GST_BASE_PARSE (flacparse),
+          boffset + offset, gst_util_uint64_scale (samples, GST_SECOND,
+              flacparse->samplerate), TRUE, FALSE);
+    }
+  }
+
+done:
+  gst_buffer_unmap (flacparse->seektable, &map);
+exit:
+  gst_buffer_unref (flacparse->seektable);
+  flacparse->seektable = NULL;
+}
+
+static void
+_value_array_append_buffer (GValue * array_val, GstBuffer * buf)
+{
+  GValue value = { 0, };
+
+  g_value_init (&value, GST_TYPE_BUFFER);
+  /* copy buffer to avoid problems with circular refcounts */
+  buf = gst_buffer_copy (buf);
+  /* again, for good measure */
+  GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
+  gst_value_set_buffer (&value, buf);
+  gst_buffer_unref (buf);
+  gst_value_array_append_value (array_val, &value);
+  g_value_unset (&value);
+}
+
+static GstFlowReturn
+gst_flac_parse_handle_headers (GstFlacParse * flacparse)
+{
+  GstBuffer *vorbiscomment = NULL;
+  GstBuffer *streaminfo = NULL;
+  GstBuffer *marker = NULL;
+  GValue array = { 0, };
+  GstCaps *caps;
+  GList *l;
+  GstFlowReturn res = GST_FLOW_OK;
+
+  caps = gst_caps_new_simple ("audio/x-flac",
+      "channels", G_TYPE_INT, flacparse->channels,
+      "framed", G_TYPE_BOOLEAN, TRUE,
+      "rate", G_TYPE_INT, flacparse->samplerate, NULL);
+
+  if (!flacparse->headers)
+    goto push_headers;
+
+  for (l = flacparse->headers; l; l = l->next) {
+    GstBuffer *header = l->data;
+    GstMapInfo map;
+
+    gst_buffer_map (header, &map, GST_MAP_READ);
+
+    GST_BUFFER_FLAG_SET (header, GST_BUFFER_FLAG_HEADER);
+
+    if (map.size == 4 && memcmp (map.data, "fLaC", 4) == 0) {
+      marker = header;
+    } else if (map.size > 1 && (map.data[0] & 0x7f) == 0) {
+      streaminfo = header;
+    } else if (map.size > 1 && (map.data[0] & 0x7f) == 4) {
+      vorbiscomment = header;
+    }
+
+    gst_buffer_unmap (header, &map);
+  }
+
+  /* at least this one we can generate easily
+   * to provide full headers downstream */
+  if (vorbiscomment == NULL && streaminfo != NULL) {
+    GST_DEBUG_OBJECT (flacparse,
+        "missing vorbiscomment header; generating dummy");
+    vorbiscomment = gst_flac_parse_generate_vorbiscomment (flacparse);
+    flacparse->headers = g_list_insert (flacparse->headers, vorbiscomment,
+        g_list_index (flacparse->headers, streaminfo) + 1);
+  }
+
+  if (marker == NULL || streaminfo == NULL || vorbiscomment == NULL) {
+    GST_WARNING_OBJECT (flacparse,
+        "missing header %p %p %p, muxing into container "
+        "formats may be broken", marker, streaminfo, vorbiscomment);
+    goto push_headers;
+  }
+
+  g_value_init (&array, GST_TYPE_ARRAY);
+
+  /* add marker including STREAMINFO header */
+  {
+    GstBuffer *buf;
+    guint16 num;
+    GstMapInfo sinfomap, writemap;
+
+    gst_buffer_map (streaminfo, &sinfomap, GST_MAP_READ);
+
+    /* minus one for the marker that is merged with streaminfo here */
+    num = g_list_length (flacparse->headers) - 1;
+
+    buf = gst_buffer_new_and_alloc (13 + sinfomap.size);
+    gst_buffer_map (buf, &writemap, GST_MAP_WRITE);
+
+    writemap.data[0] = 0x7f;
+    memcpy (writemap.data + 1, "FLAC", 4);
+    writemap.data[5] = 0x01;    /* mapping version major */
+    writemap.data[6] = 0x00;    /* mapping version minor */
+    writemap.data[7] = (num & 0xFF00) >> 8;
+    writemap.data[8] = (num & 0x00FF) >> 0;
+    memcpy (writemap.data + 9, "fLaC", 4);
+    memcpy (writemap.data + 13, sinfomap.data, sinfomap.size);
+    _value_array_append_buffer (&array, buf);
+
+    gst_buffer_unmap (streaminfo, &sinfomap);
+    gst_buffer_unmap (buf, &writemap);
+    gst_buffer_unref (buf);
+  }
+
+  /* add VORBISCOMMENT header */
+  _value_array_append_buffer (&array, vorbiscomment);
+
+  /* add other headers, if there are any */
+  for (l = flacparse->headers; l; l = l->next) {
+    if (GST_BUFFER_CAST (l->data) != marker &&
+        GST_BUFFER_CAST (l->data) != streaminfo &&
+        GST_BUFFER_CAST (l->data) != vorbiscomment) {
+      _value_array_append_buffer (&array, GST_BUFFER_CAST (l->data));
+    }
+  }
+
+  gst_structure_set_value (gst_caps_get_structure (caps, 0),
+      "streamheader", &array);
+  g_value_unset (&array);
+
+push_headers:
+
+  gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (GST_BASE_PARSE (flacparse)), caps);
+  gst_caps_unref (caps);
+
+  /* push header buffers; update caps, so when we push the first buffer the
+   * negotiated caps will change to caps that include the streamheader field */
+  while (flacparse->headers) {
+    GstBuffer *buf = GST_BUFFER (flacparse->headers->data);
+    GstBaseParseFrame frame;
+
+    flacparse->headers =
+        g_list_delete_link (flacparse->headers, flacparse->headers);
+    buf = gst_buffer_make_writable (buf);
+
+    /* init, set and give away frame */
+    gst_base_parse_frame_init (&frame);
+    frame.buffer = buf;
+    frame.overhead = -1;
+    res = gst_base_parse_push_frame (GST_BASE_PARSE (flacparse), &frame);
+    gst_base_parse_frame_free (&frame);
+    if (res != GST_FLOW_OK)
+      break;
+  }
+  g_list_foreach (flacparse->headers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (flacparse->headers);
+  flacparse->headers = NULL;
+
+  return res;
+}
+
+/* empty vorbiscomment */
+static GstBuffer *
+gst_flac_parse_generate_vorbiscomment (GstFlacParse * flacparse)
+{
+  GstTagList *taglist = gst_tag_list_new_empty ();
+  guchar header[4];
+  guint size;
+  GstBuffer *vorbiscomment;
+  GstMapInfo map;
+
+  header[0] = 0x84;             /* is_last = 1; type = 4; */
+
+  vorbiscomment =
+      gst_tag_list_to_vorbiscomment_buffer (taglist, header,
+      sizeof (header), NULL);
+  gst_tag_list_unref (taglist);
+
+  gst_buffer_map (vorbiscomment, &map, GST_MAP_WRITE);
+
+  /* Get rid of framing bit */
+  if (map.data[map.size - 1] == 1) {
+    GstBuffer *sub;
+
+    sub =
+        gst_buffer_copy_region (vorbiscomment, GST_BUFFER_COPY_ALL, 0,
+        map.size - 1);
+    gst_buffer_unmap (vorbiscomment, &map);
+    gst_buffer_unref (vorbiscomment);
+    vorbiscomment = sub;
+    gst_buffer_map (vorbiscomment, &map, GST_MAP_WRITE);
+  }
+
+  size = map.size - 4;
+  map.data[1] = ((size & 0xFF0000) >> 16);
+  map.data[2] = ((size & 0x00FF00) >> 8);
+  map.data[3] = (size & 0x0000FF);
+  gst_buffer_unmap (vorbiscomment, &map);
+  gst_flac_parse_reset_buffer_time_and_offset (vorbiscomment);
+
+  return vorbiscomment;
+}
+
+static gboolean
+gst_flac_parse_generate_headers (GstFlacParse * flacparse)
+{
+  GstBuffer *marker, *streaminfo;
+  GstMapInfo map;
+
+  marker = gst_buffer_new_and_alloc (4);
+  gst_buffer_map (marker, &map, GST_MAP_WRITE);
+  memcpy (map.data, "fLaC", 4);
+  gst_buffer_unmap (marker, &map);
+  gst_flac_parse_reset_buffer_time_and_offset (marker);
+  flacparse->headers = g_list_append (flacparse->headers, marker);
+
+  streaminfo = gst_buffer_new_and_alloc (4 + 34);
+  gst_buffer_map (streaminfo, &map, GST_MAP_WRITE);
+  memset (map.data, 0, 4 + 34);
+
+  /* metadata block header */
+  map.data[0] = 0x00;           /* is_last = 0; type = 0; */
+  map.data[1] = 0x00;           /* length = 34; */
+  map.data[2] = 0x00;
+  map.data[3] = 0x22;
+
+  /* streaminfo */
+
+  map.data[4] = (flacparse->block_size >> 8) & 0xff;    /* min blocksize = blocksize; */
+  map.data[5] = (flacparse->block_size) & 0xff;
+  map.data[6] = (flacparse->block_size >> 8) & 0xff;    /* max blocksize = blocksize; */
+  map.data[7] = (flacparse->block_size) & 0xff;
+
+  map.data[8] = 0x00;           /* min framesize = 0; */
+  map.data[9] = 0x00;
+  map.data[10] = 0x00;
+  map.data[11] = 0x00;          /* max framesize = 0; */
+  map.data[12] = 0x00;
+  map.data[13] = 0x00;
+
+  map.data[14] = (flacparse->samplerate >> 12) & 0xff;
+  map.data[15] = (flacparse->samplerate >> 4) & 0xff;
+  map.data[16] = (flacparse->samplerate >> 0) & 0xf0;
+
+  map.data[16] |= (flacparse->channels - 1) << 1;
+
+  map.data[16] |= ((flacparse->bps - 1) >> 4) & 0x01;
+  map.data[17] = (((flacparse->bps - 1)) & 0x0f) << 4;
+
+  {
+    gint64 duration;
+
+    if (gst_pad_peer_query_duration (GST_BASE_PARSE_SINK_PAD (flacparse),
+            GST_FORMAT_TIME, &duration) && duration != -1) {
+      duration = GST_CLOCK_TIME_TO_FRAMES (duration, flacparse->samplerate);
+
+      map.data[17] |= (duration >> 32) & 0xff;
+      map.data[18] |= (duration >> 24) & 0xff;
+      map.data[19] |= (duration >> 16) & 0xff;
+      map.data[20] |= (duration >> 8) & 0xff;
+      map.data[21] |= (duration >> 0) & 0xff;
+    }
+  }
+  /* MD5 = 0; */
+
+  gst_buffer_unmap (streaminfo, &map);
+  gst_flac_parse_reset_buffer_time_and_offset (streaminfo);
+  flacparse->headers = g_list_append (flacparse->headers, streaminfo);
+
+  flacparse->headers = g_list_append (flacparse->headers,
+      gst_flac_parse_generate_vorbiscomment (flacparse));
+
+  return TRUE;
+}
+
+static inline void
+gst_flac_parse_reset_buffer_time_and_offset (GstBuffer * buffer)
+{
+  GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
+  GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
+  GST_BUFFER_OFFSET (buffer) = 0;
+  GST_BUFFER_OFFSET_END (buffer) = 0;
+}
+
+/* Type 127 is invalid for a metadata block header & should
+ * be discarded _before_ calling this function */
+static gboolean
+gst_flac_parse_handle_block_type (GstFlacParse * flacparse, guint type,
+    GstBuffer * sbuffer)
+{
+  gboolean ret = TRUE;
+
+  switch (type) {
+    case 0:                    /* STREAMINFO */
+      GST_INFO_OBJECT (flacparse, "STREAMINFO header");
+      ret = gst_flac_parse_handle_streaminfo (flacparse, sbuffer);
+      break;
+    case 3:                    /* SEEKTABLE */
+      GST_INFO_OBJECT (flacparse, "SEEKTABLE header");
+      ret = gst_flac_parse_handle_seektable (flacparse, sbuffer);
+      break;
+    case 4:                    /* VORBIS_COMMENT */
+      GST_INFO_OBJECT (flacparse, "VORBISCOMMENT header");
+      ret = gst_flac_parse_handle_vorbiscomment (flacparse, sbuffer);
+      break;
+    case 5:                    /* CUESHEET */
+      GST_INFO_OBJECT (flacparse, "CUESHEET header");
+      ret = gst_flac_parse_handle_cuesheet (flacparse, sbuffer);
+      break;
+    case 6:                    /* PICTURE */
+      GST_INFO_OBJECT (flacparse, "PICTURE header");
+      ret = gst_flac_parse_handle_picture (flacparse, sbuffer);
+      break;
+    case 1:                    /* PADDING */
+      GST_INFO_OBJECT (flacparse, "PADDING header");
+      break;
+    case 2:                    /* APPLICATION */
+      GST_INFO_OBJECT (flacparse, "APPLICATION header");
+      break;
+    default:                   /* RESERVED */
+      GST_INFO_OBJECT (flacparse, "Unhandled metadata header type '%u'", type);
+      GST_FIXME_OBJECT (flacparse, "FLAC version might not be fully supported");
+      break;
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame,
+    gint size)
+{
+  GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
+  GstBuffer *buffer = frame->buffer, *sbuffer;
+  GstMapInfo map;
+  GstFlowReturn res = GST_FLOW_ERROR;
+  guint64 relative_sample_number;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  if (flacparse->state == GST_FLAC_PARSE_STATE_INIT) {
+    sbuffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, 0, size);
+    gst_flac_parse_reset_buffer_time_and_offset (sbuffer);
+
+    /* 32 bits metadata block */
+    gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 4);
+    flacparse->state = GST_FLAC_PARSE_STATE_HEADERS;
+
+    flacparse->headers = g_list_append (flacparse->headers, sbuffer);
+
+    res = GST_BASE_PARSE_FLOW_DROPPED;
+  } else if (flacparse->state == GST_FLAC_PARSE_STATE_HEADERS) {
+    gboolean is_last = map.data[0] >> 7;
+    guint type = (map.data[0] & 0x7F);
+
+    if (type == 127) {
+      GST_WARNING_OBJECT (flacparse, "Invalid metadata block type 127");
+      res = GST_BASE_PARSE_FLOW_DROPPED;
+      goto cleanup;
+    }
+
+    GST_DEBUG_OBJECT (flacparse, "Handling metadata block of type %u", type);
+
+    sbuffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, 0, size);
+
+    if (gst_flac_parse_handle_block_type (flacparse, type, sbuffer)) {
+      gst_flac_parse_reset_buffer_time_and_offset (sbuffer);
+      flacparse->headers = g_list_append (flacparse->headers, sbuffer);
+    } else {
+      GST_WARNING_OBJECT (parse, "failed to parse header of type %u", type);
+      GST_MEMDUMP_OBJECT (parse, "bad header data", map.data, size);
+
+      gst_buffer_unref (sbuffer);
+
+      /* error out unless we have a STREAMINFO header */
+      if (flacparse->samplerate == 0 || flacparse->bps == 0)
+        goto header_parsing_error;
+
+      /* .. in which case just stop header parsing and try to find audio */
+      is_last = TRUE;
+    }
+
+    if (is_last) {
+      res = gst_flac_parse_handle_headers (flacparse);
+
+      /* Minimal size of a frame header */
+      gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), MAX (9,
+              flacparse->min_framesize));
+      flacparse->state = GST_FLAC_PARSE_STATE_DATA;
+
+      if (res != GST_FLOW_OK)
+        goto cleanup;
+    } else {
+      /* Header length */
+      gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 4);
+    }
+
+    /* DROPPED because we pushed already or will push all headers manually */
+    res = GST_BASE_PARSE_FLOW_DROPPED;
+  } else {
+    if (flacparse->offset != GST_BUFFER_OFFSET (buffer)) {
+      FrameHeaderCheckReturn ret;
+
+      flacparse->offset = GST_BUFFER_OFFSET (buffer);
+      ret =
+          gst_flac_parse_frame_header_is_valid (flacparse,
+          map.data, map.size, TRUE, NULL, NULL);
+      if (ret != FRAME_HEADER_VALID) {
+        GST_ERROR_OBJECT (flacparse,
+            "Baseclass didn't provide a complete frame");
+        goto cleanup;
+      }
+    }
+
+    if (flacparse->block_size == 0) {
+      GST_ERROR_OBJECT (flacparse, "Unparsed frame");
+      goto cleanup;
+    }
+
+    if (flacparse->seektable)
+      gst_flac_parse_process_seektable (flacparse, GST_BUFFER_OFFSET (buffer));
+
+    if (flacparse->state == GST_FLAC_PARSE_STATE_GENERATE_HEADERS) {
+      if (flacparse->blocking_strategy == 1) {
+        GST_WARNING_OBJECT (flacparse,
+            "Generating headers for variable blocksize streams not supported");
+
+        res = gst_flac_parse_handle_headers (flacparse);
+      } else {
+        GST_DEBUG_OBJECT (flacparse, "Generating headers");
+
+        if (!gst_flac_parse_generate_headers (flacparse))
+          goto cleanup;
+
+        res = gst_flac_parse_handle_headers (flacparse);
+      }
+      flacparse->state = GST_FLAC_PARSE_STATE_DATA;
+      if (res != GST_FLOW_OK)
+        goto cleanup;
+    }
+
+    /* also cater for oggmux metadata */
+    relative_sample_number =
+        flacparse->sample_number - flacparse->first_sample_number;
+    if (flacparse->blocking_strategy == 0) {
+      GST_BUFFER_PTS (buffer) =
+          gst_util_uint64_scale (relative_sample_number,
+          flacparse->block_size * GST_SECOND, flacparse->samplerate);
+      GST_BUFFER_OFFSET_END (buffer) =
+          relative_sample_number * flacparse->block_size +
+          flacparse->block_size;
+    } else {
+      GST_BUFFER_PTS (buffer) =
+          gst_util_uint64_scale (relative_sample_number, GST_SECOND,
+          flacparse->samplerate);
+      GST_BUFFER_OFFSET_END (buffer) =
+          relative_sample_number + flacparse->block_size;
+    }
+
+    GST_BUFFER_DTS (buffer) = GST_BUFFER_PTS (buffer);
+    GST_BUFFER_OFFSET (buffer) =
+        gst_util_uint64_scale (GST_BUFFER_OFFSET_END (buffer), GST_SECOND,
+        flacparse->samplerate);
+    GST_BUFFER_DURATION (buffer) =
+        GST_BUFFER_OFFSET (buffer) - GST_BUFFER_PTS (buffer);
+
+    /* To simplify, we just assume that it's a fixed size header and ignore
+     * subframe headers. The first could lead us to be off by 88 bits and
+     * the second even less, so the total inaccuracy is negligible. */
+    frame->overhead = 7;
+
+    /* Minimal size of a frame header */
+    gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), MAX (9,
+            flacparse->min_framesize));
+
+    flacparse->offset = -1;
+    flacparse->blocking_strategy = 0;
+    flacparse->sample_number = 0;
+    res = GST_FLOW_OK;
+  }
+
+cleanup:
+  gst_buffer_unmap (buffer, &map);
+  return res;
+
+header_parsing_error:
+  GST_ELEMENT_ERROR (flacparse, STREAM, DECODE, (NULL),
+      ("Failed to parse headers"));
+  goto cleanup;
+}
+
+static GstFlowReturn
+gst_flac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
+{
+  GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
+
+  if (!flacparse->sent_codec_tag) {
+    GstCaps *caps;
+
+    if (flacparse->tags == NULL)
+      flacparse->tags = gst_tag_list_new_empty ();
+
+    /* codec tag */
+    caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
+    if (G_UNLIKELY (caps == NULL)) {
+      if (GST_PAD_IS_FLUSHING (GST_BASE_PARSE_SRC_PAD (parse))) {
+        GST_INFO_OBJECT (parse, "Src pad is flushing");
+        return GST_FLOW_FLUSHING;
+      }
+      GST_INFO_OBJECT (parse, "Src pad is not negotiated!");
+      return GST_FLOW_NOT_NEGOTIATED;
+    }
+    gst_pb_utils_add_codec_description_to_tag_list (flacparse->tags,
+        GST_TAG_AUDIO_CODEC, caps);
+    gst_caps_unref (caps);
+
+    /* Announce our pending tags */
+    gst_base_parse_merge_tags (parse, flacparse->tags, GST_TAG_MERGE_REPLACE);
+
+    /* also signals the end of first-frame processing */
+    flacparse->sent_codec_tag = TRUE;
+  }
+
+  /* Push toc */
+  if (flacparse->toc) {
+    gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (flacparse),
+        gst_event_new_toc (flacparse->toc, FALSE));
+  }
+
+  frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP;
+
+  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);
+}
+
+static gboolean
+gst_flac_parse_src_event (GstBaseParse * parse, GstEvent * event)
+{
+  GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
+  gboolean res = FALSE;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_TOC_SELECT:
+    {
+      GstTocEntry *entry = NULL;
+      GstEvent *seek_event;
+      GstToc *toc = NULL;
+      gint64 start_pos;
+      gchar *uid = NULL;
+
+      /* FIXME: some locking would be good */
+      if (flacparse->toc)
+        toc = gst_toc_ref (flacparse->toc);
+
+      if (toc != NULL) {
+        gst_event_parse_toc_select (event, &uid);
+        if (uid != NULL) {
+          entry = gst_toc_find_entry (toc, uid);
+          if (entry != NULL) {
+            gst_toc_entry_get_start_stop_times (entry, &start_pos, NULL);
+
+            /* FIXME: use segment rate here instead? */
+            seek_event = gst_event_new_seek (1.0,
+                GST_FORMAT_TIME,
+                GST_SEEK_FLAG_FLUSH,
+                GST_SEEK_TYPE_SET, start_pos, GST_SEEK_TYPE_NONE, -1);
+
+            res =
+                GST_BASE_PARSE_CLASS (parent_class)->src_event (parse,
+                seek_event);
+
+          } else {
+            GST_WARNING_OBJECT (parse, "no TOC entry with given UID: %s", uid);
+          }
+          g_free (uid);
+        }
+        gst_toc_unref (toc);
+      } else {
+        GST_DEBUG_OBJECT (flacparse, "no TOC to select");
+      }
+      gst_event_unref (event);
+      break;
+    }
+    default:
+      res = GST_BASE_PARSE_CLASS (parent_class)->src_event (parse, event);
+      break;
+  }
+  return res;
+}
+
+static void
+remove_fields (GstCaps * caps)
+{
+  guint i, n;
+
+  n = gst_caps_get_size (caps);
+  for (i = 0; i < n; i++) {
+    GstStructure *s = gst_caps_get_structure (caps, i);
+
+    gst_structure_remove_field (s, "framed");
+  }
+}
+
+static GstCaps *
+gst_flac_parse_get_sink_caps (GstBaseParse * parse, GstCaps * filter)
+{
+  GstCaps *peercaps, *templ;
+  GstCaps *res;
+
+  templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
+  if (filter) {
+    GstCaps *fcopy = gst_caps_copy (filter);
+    /* Remove the fields we convert */
+    remove_fields (fcopy);
+    peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
+    gst_caps_unref (fcopy);
+  } else
+    peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), NULL);
+
+  if (peercaps) {
+    /* Remove the framed field */
+    peercaps = gst_caps_make_writable (peercaps);
+    remove_fields (peercaps);
+
+    res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (peercaps);
+    gst_caps_unref (templ);
+  } else {
+    res = templ;
+  }
+
+  if (filter) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (res);
+    res = intersection;
+  }
+
+  return res;
+}
diff --git a/gst/audioparsers/gstflacparse.h b/gst/audioparsers/gstflacparse.h
new file mode 100644
index 0000000..55418df
--- /dev/null
+++ b/gst/audioparsers/gstflacparse.h
@@ -0,0 +1,99 @@
+/* GStreamer
+ *
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>.
+ * Copyright (C) 2009 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ * Copyright (C) 2009 Nokia Corporation. All rights reserved.
+ *   Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_FLAC_PARSE_H__
+#define __GST_FLAC_PARSE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbaseparse.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_FLAC_PARSE		   (gst_flac_parse_get_type())
+#define GST_FLAC_PARSE(obj)		   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FLAC_PARSE,GstFlacParse))
+#define GST_FLAC_PARSE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FLAC_PARSE,GstFlacParseClass))
+#define GST_FLAC_PARSE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_FLAC_PARSE,GstFlacParseClass))
+#define GST_IS_FLAC_PARSE(obj)	   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLAC_PARSE))
+#define GST_IS_FLAC_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLAC_PARSE))
+#define GST_FLAC_PARSE_CAST(obj)	((GstFlacParse *)(obj))
+
+typedef struct _GstFlacParse GstFlacParse;
+typedef struct _GstFlacParseClass GstFlacParseClass;
+
+typedef enum {
+  GST_FLAC_PARSE_STATE_INIT,
+  GST_FLAC_PARSE_STATE_HEADERS,
+  GST_FLAC_PARSE_STATE_GENERATE_HEADERS,
+  GST_FLAC_PARSE_STATE_DATA
+} GstFlacParseState;
+
+typedef struct {
+  guint8 type;
+} GstFlacParseSubFrame;
+
+struct _GstFlacParse {
+  GstBaseParse parent;
+
+  /* Properties */
+  gboolean check_frame_checksums;
+
+  GstFlacParseState state;
+
+  gint64 upstream_length;
+
+  /* STREAMINFO content */
+  guint16 min_blocksize, max_blocksize;
+  guint32 min_framesize, max_framesize;
+  guint32 samplerate;
+  guint8 channels;
+  guint8 bps;
+  guint64 total_samples;
+
+  /* Current frame */
+  guint64 offset;
+  guint8 blocking_strategy;
+  guint16 block_size;
+  guint64 sample_number;
+  guint64 first_sample_number;
+  gboolean strategy_checked;
+
+  gboolean sent_codec_tag;
+
+  GstTagList *tags;
+  GstToc *toc;
+
+  GList *headers;
+  GstBuffer *seektable;
+
+  gboolean force_variable_block_size;
+};
+
+struct _GstFlacParseClass {
+  GstBaseParseClass parent_class;
+};
+
+GType gst_flac_parse_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_FLAC_PARSE_H__ */
diff --git a/gst/audioparsers/gstmpegaudioparse.c b/gst/audioparsers/gstmpegaudioparse.c
new file mode 100644
index 0000000..cfad883
--- /dev/null
+++ b/gst/audioparsers/gstmpegaudioparse.c
@@ -0,0 +1,1455 @@
+/* GStreamer MPEG audio parser
+ * Copyright (C) 2006-2007 Jan Schmidt <thaytan@mad.scientist.com>
+ * Copyright (C) 2010 Mark Nauwelaerts <mnauw users sf net>
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ *   Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-mpegaudioparse
+ * @short_description: MPEG audio parser
+ * @see_also: #GstAmrParse, #GstAACParse
+ *
+ * Parses and frames mpeg1 audio streams. Provides seeking.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=test.mp3 ! mpegaudioparse ! mpg123audiodec
+ *  ! audioconvert ! audioresample ! autoaudiosink
+ * ]|
+ * </refsect2>
+ */
+
+/* FIXME: we should make the base class (GstBaseParse) aware of the
+ * XING seek table somehow, so it can use it properly for things like
+ * accurate seeks. Currently it can only do a lookup via the convert function,
+ * but then doesn't know what the result represents exactly. One could either
+ * add a vfunc for index lookup, or just make mpegaudioparse populate the
+ * base class's index via the API provided.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstmpegaudioparse.h"
+#include <gst/base/gstbytereader.h>
+#include <gst/pbutils/pbutils.h>
+
+GST_DEBUG_CATEGORY_STATIC (mpeg_audio_parse_debug);
+#define GST_CAT_DEFAULT mpeg_audio_parse_debug
+
+#define MPEG_AUDIO_CHANNEL_MODE_UNKNOWN -1
+#define MPEG_AUDIO_CHANNEL_MODE_STEREO 0
+#define MPEG_AUDIO_CHANNEL_MODE_JOINT_STEREO 1
+#define MPEG_AUDIO_CHANNEL_MODE_DUAL_CHANNEL 2
+#define MPEG_AUDIO_CHANNEL_MODE_MONO 3
+
+#define CRC_UNKNOWN -1
+#define CRC_PROTECTED 0
+#define CRC_NOT_PROTECTED 1
+
+#define XING_FRAMES_FLAG     0x0001
+#define XING_BYTES_FLAG      0x0002
+#define XING_TOC_FLAG        0x0004
+#define XING_VBR_SCALE_FLAG  0x0008
+
+#define MIN_FRAME_SIZE       6
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/mpeg, "
+        "mpegversion = (int) 1, "
+        "layer = (int) [ 1, 3 ], "
+        "mpegaudioversion = (int) [ 1, 3], "
+        "rate = (int) [ 8000, 48000 ], "
+        "channels = (int) [ 1, 2 ], " "parsed=(boolean) true")
+    );
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/mpeg, mpegversion = (int) 1")
+    );
+
+static void gst_mpeg_audio_parse_finalize (GObject * object);
+
+static gboolean gst_mpeg_audio_parse_start (GstBaseParse * parse);
+static gboolean gst_mpeg_audio_parse_stop (GstBaseParse * parse);
+static GstFlowReturn gst_mpeg_audio_parse_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize);
+static GstFlowReturn gst_mpeg_audio_parse_pre_push_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame);
+static gboolean gst_mpeg_audio_parse_convert (GstBaseParse * parse,
+    GstFormat src_format, gint64 src_value,
+    GstFormat dest_format, gint64 * dest_value);
+static GstCaps *gst_mpeg_audio_parse_get_sink_caps (GstBaseParse * parse,
+    GstCaps * filter);
+
+static void gst_mpeg_audio_parse_handle_first_frame (GstMpegAudioParse *
+    mp3parse, GstBuffer * buf);
+
+#define gst_mpeg_audio_parse_parent_class parent_class
+G_DEFINE_TYPE (GstMpegAudioParse, gst_mpeg_audio_parse, GST_TYPE_BASE_PARSE);
+
+#define GST_TYPE_MPEG_AUDIO_CHANNEL_MODE  \
+    (gst_mpeg_audio_channel_mode_get_type())
+
+static const GEnumValue mpeg_audio_channel_mode[] = {
+  {MPEG_AUDIO_CHANNEL_MODE_UNKNOWN, "Unknown", "unknown"},
+  {MPEG_AUDIO_CHANNEL_MODE_MONO, "Mono", "mono"},
+  {MPEG_AUDIO_CHANNEL_MODE_DUAL_CHANNEL, "Dual Channel", "dual-channel"},
+  {MPEG_AUDIO_CHANNEL_MODE_JOINT_STEREO, "Joint Stereo", "joint-stereo"},
+  {MPEG_AUDIO_CHANNEL_MODE_STEREO, "Stereo", "stereo"},
+  {0, NULL, NULL},
+};
+
+static GType
+gst_mpeg_audio_channel_mode_get_type (void)
+{
+  static GType mpeg_audio_channel_mode_type = 0;
+
+  if (!mpeg_audio_channel_mode_type) {
+    mpeg_audio_channel_mode_type =
+        g_enum_register_static ("GstMpegAudioChannelMode",
+        mpeg_audio_channel_mode);
+  }
+  return mpeg_audio_channel_mode_type;
+}
+
+static const gchar *
+gst_mpeg_audio_channel_mode_get_nick (gint mode)
+{
+  guint i;
+  for (i = 0; i < G_N_ELEMENTS (mpeg_audio_channel_mode); i++) {
+    if (mpeg_audio_channel_mode[i].value == mode)
+      return mpeg_audio_channel_mode[i].value_nick;
+  }
+  return NULL;
+}
+
+static void
+gst_mpeg_audio_parse_class_init (GstMpegAudioParseClass * klass)
+{
+  GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (mpeg_audio_parse_debug, "mpegaudioparse", 0,
+      "MPEG1 audio stream parser");
+
+  object_class->finalize = gst_mpeg_audio_parse_finalize;
+
+  parse_class->start = GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_start);
+  parse_class->stop = GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_stop);
+  parse_class->handle_frame =
+      GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_handle_frame);
+  parse_class->pre_push_frame =
+      GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_pre_push_frame);
+  parse_class->convert = GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_convert);
+  parse_class->get_sink_caps =
+      GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_get_sink_caps);
+
+  /* register tags */
+#define GST_TAG_CRC      "has-crc"
+#define GST_TAG_MODE     "channel-mode"
+
+  gst_tag_register (GST_TAG_CRC, GST_TAG_FLAG_META, G_TYPE_BOOLEAN,
+      "has crc", "Using CRC", NULL);
+  gst_tag_register (GST_TAG_MODE, GST_TAG_FLAG_ENCODED, G_TYPE_STRING,
+      "channel mode", "MPEG audio channel mode", NULL);
+
+  g_type_class_ref (GST_TYPE_MPEG_AUDIO_CHANNEL_MODE);
+
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+
+  gst_element_class_set_static_metadata (element_class, "MPEG1 Audio Parser",
+      "Codec/Parser/Audio",
+      "Parses and frames mpeg1 audio streams (levels 1-3), provides seek",
+      "Jan Schmidt <thaytan@mad.scientist.com>,"
+      "Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>");
+}
+
+static void
+gst_mpeg_audio_parse_reset (GstMpegAudioParse * mp3parse)
+{
+  mp3parse->channels = -1;
+  mp3parse->rate = -1;
+  mp3parse->sent_codec_tag = FALSE;
+  mp3parse->last_posted_crc = CRC_UNKNOWN;
+  mp3parse->last_posted_channel_mode = MPEG_AUDIO_CHANNEL_MODE_UNKNOWN;
+  mp3parse->freerate = 0;
+
+  mp3parse->hdr_bitrate = 0;
+
+  mp3parse->xing_flags = 0;
+  mp3parse->xing_bitrate = 0;
+  mp3parse->xing_frames = 0;
+  mp3parse->xing_total_time = 0;
+  mp3parse->xing_bytes = 0;
+  mp3parse->xing_vbr_scale = 0;
+  memset (mp3parse->xing_seek_table, 0, sizeof (mp3parse->xing_seek_table));
+  memset (mp3parse->xing_seek_table_inverse, 0,
+      sizeof (mp3parse->xing_seek_table_inverse));
+
+  mp3parse->vbri_bitrate = 0;
+  mp3parse->vbri_frames = 0;
+  mp3parse->vbri_total_time = 0;
+  mp3parse->vbri_bytes = 0;
+  mp3parse->vbri_seek_points = 0;
+  g_free (mp3parse->vbri_seek_table);
+  mp3parse->vbri_seek_table = NULL;
+
+  mp3parse->encoder_delay = 0;
+  mp3parse->encoder_padding = 0;
+}
+
+static void
+gst_mpeg_audio_parse_init (GstMpegAudioParse * mp3parse)
+{
+  gst_mpeg_audio_parse_reset (mp3parse);
+  GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (mp3parse));
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (mp3parse));
+}
+
+static void
+gst_mpeg_audio_parse_finalize (GObject * object)
+{
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_mpeg_audio_parse_start (GstBaseParse * parse)
+{
+  GstMpegAudioParse *mp3parse = GST_MPEG_AUDIO_PARSE (parse);
+
+  gst_base_parse_set_min_frame_size (GST_BASE_PARSE (mp3parse), MIN_FRAME_SIZE);
+  GST_DEBUG_OBJECT (parse, "starting");
+
+  gst_mpeg_audio_parse_reset (mp3parse);
+
+  return TRUE;
+}
+
+static gboolean
+gst_mpeg_audio_parse_stop (GstBaseParse * parse)
+{
+  GstMpegAudioParse *mp3parse = GST_MPEG_AUDIO_PARSE (parse);
+
+  GST_DEBUG_OBJECT (parse, "stopping");
+
+  gst_mpeg_audio_parse_reset (mp3parse);
+
+  return TRUE;
+}
+
+static const guint mp3types_bitrates[2][3][16] = {
+  {
+        {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,},
+        {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,},
+        {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,}
+      },
+  {
+        {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,},
+        {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,},
+        {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}
+      },
+};
+
+static const guint mp3types_freqs[3][3] = { {44100, 48000, 32000},
+{22050, 24000, 16000},
+{11025, 12000, 8000}
+};
+
+static inline guint
+mp3_type_frame_length_from_header (GstMpegAudioParse * mp3parse, guint32 header,
+    guint * put_version, guint * put_layer, guint * put_channels,
+    guint * put_bitrate, guint * put_samplerate, guint * put_mode,
+    guint * put_crc)
+{
+  guint length;
+  gulong mode, samplerate, bitrate, layer, channels, padding, crc;
+  gulong version;
+  gint lsf, mpg25;
+
+  if (header & (1 << 20)) {
+    lsf = (header & (1 << 19)) ? 0 : 1;
+    mpg25 = 0;
+  } else {
+    lsf = 1;
+    mpg25 = 1;
+  }
+
+  version = 1 + lsf + mpg25;
+
+  layer = 4 - ((header >> 17) & 0x3);
+
+  crc = (header >> 16) & 0x1;
+
+  bitrate = (header >> 12) & 0xF;
+  bitrate = mp3types_bitrates[lsf][layer - 1][bitrate] * 1000;
+  if (!bitrate) {
+    GST_LOG_OBJECT (mp3parse, "using freeform bitrate");
+    bitrate = mp3parse->freerate;
+  }
+
+  samplerate = (header >> 10) & 0x3;
+  samplerate = mp3types_freqs[lsf + mpg25][samplerate];
+
+  /* force 0 length if 0 bitrate */
+  padding = (bitrate > 0) ? (header >> 9) & 0x1 : 0;
+
+  mode = (header >> 6) & 0x3;
+  channels = (mode == 3) ? 1 : 2;
+
+  switch (layer) {
+    case 1:
+      length = 4 * ((bitrate * 12) / samplerate + padding);
+      break;
+    case 2:
+      length = (bitrate * 144) / samplerate + padding;
+      break;
+    default:
+    case 3:
+      length = (bitrate * 144) / (samplerate << lsf) + padding;
+      break;
+  }
+
+  GST_DEBUG_OBJECT (mp3parse, "Calculated mp3 frame length of %u bytes",
+      length);
+  GST_DEBUG_OBJECT (mp3parse, "samplerate = %lu, bitrate = %lu, version = %lu, "
+      "layer = %lu, channels = %lu, mode = %s", samplerate, bitrate, version,
+      layer, channels, gst_mpeg_audio_channel_mode_get_nick (mode));
+
+  if (put_version)
+    *put_version = version;
+  if (put_layer)
+    *put_layer = layer;
+  if (put_channels)
+    *put_channels = channels;
+  if (put_bitrate)
+    *put_bitrate = bitrate;
+  if (put_samplerate)
+    *put_samplerate = samplerate;
+  if (put_mode)
+    *put_mode = mode;
+  if (put_crc)
+    *put_crc = crc;
+
+  return length;
+}
+
+/* Minimum number of consecutive, valid-looking frames to consider
+ * for resyncing */
+#define MIN_RESYNC_FRAMES 3
+
+/* Perform extended validation to check that subsequent headers match
+ * the first header given here in important characteristics, to avoid
+ * false sync. We look for a minimum of MIN_RESYNC_FRAMES consecutive
+ * frames to match their major characteristics.
+ *
+ * If at_eos is set to TRUE, we just check that we don't find any invalid
+ * frames in whatever data is available, rather than requiring a full
+ * MIN_RESYNC_FRAMES of data.
+ *
+ * Returns TRUE if we've seen enough data to validate or reject the frame.
+ * If TRUE is returned, then *valid contains TRUE if it validated, or false
+ * if we decided it was false sync.
+ * If FALSE is returned, then *valid contains minimum needed data.
+ */
+static gboolean
+gst_mp3parse_validate_extended (GstMpegAudioParse * mp3parse, GstBuffer * buf,
+    guint32 header, int bpf, gboolean at_eos, gint * valid)
+{
+  guint32 next_header;
+  GstMapInfo map;
+  gboolean res = TRUE;
+  int frames_found = 1;
+  int offset = bpf;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  while (frames_found < MIN_RESYNC_FRAMES) {
+    /* Check if we have enough data for all these frames, plus the next
+       frame header. */
+    if (map.size < offset + 4) {
+      if (at_eos) {
+        /* Running out of data at EOS is fine; just accept it */
+        *valid = TRUE;
+        goto cleanup;
+      } else {
+        *valid = offset + 4;
+        res = FALSE;
+        goto cleanup;
+      }
+    }
+
+    next_header = GST_READ_UINT32_BE (map.data + offset);
+    GST_DEBUG_OBJECT (mp3parse, "At %d: header=%08X, header2=%08X, bpf=%d",
+        offset, (unsigned int) header, (unsigned int) next_header, bpf);
+
+/* mask the bits which are allowed to differ between frames */
+#define HDRMASK ~((0xF << 12)  /* bitrate */ | \
+                  (0x1 <<  9)  /* padding */ | \
+                  (0xf <<  4)  /* mode|mode extension */ | \
+                  (0xf))        /* copyright|emphasis */
+
+    if ((next_header & HDRMASK) != (header & HDRMASK)) {
+      /* If any of the unmasked bits don't match, then it's not valid */
+      GST_DEBUG_OBJECT (mp3parse, "next header doesn't match "
+          "(header=%08X (%08X), header2=%08X (%08X), bpf=%d)",
+          (guint) header, (guint) header & HDRMASK, (guint) next_header,
+          (guint) next_header & HDRMASK, bpf);
+      *valid = FALSE;
+      goto cleanup;
+    } else if (((next_header >> 12) & 0xf) == 0xf) {
+      /* The essential parts were the same, but the bitrate held an
+         invalid value - also reject */
+      GST_DEBUG_OBJECT (mp3parse, "next header invalid (bitrate)");
+      *valid = FALSE;
+      goto cleanup;
+    }
+
+    bpf = mp3_type_frame_length_from_header (mp3parse, next_header,
+        NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+
+    /* if no bitrate, and no freeform rate known, then fail */
+    if (G_UNLIKELY (!bpf)) {
+      GST_DEBUG_OBJECT (mp3parse, "next header invalid (bitrate 0)");
+      *valid = FALSE;
+      goto cleanup;
+    }
+
+    offset += bpf;
+    frames_found++;
+  }
+
+  *valid = TRUE;
+
+cleanup:
+  gst_buffer_unmap (buf, &map);
+  return res;
+}
+
+static gboolean
+gst_mpeg_audio_parse_head_check (GstMpegAudioParse * mp3parse,
+    unsigned long head)
+{
+  GST_DEBUG_OBJECT (mp3parse, "checking mp3 header 0x%08lx", head);
+  /* if it's not a valid sync */
+  if ((head & 0xffe00000) != 0xffe00000) {
+    GST_WARNING_OBJECT (mp3parse, "invalid sync");
+    return FALSE;
+  }
+  /* if it's an invalid MPEG version */
+  if (((head >> 19) & 3) == 0x1) {
+    GST_WARNING_OBJECT (mp3parse, "invalid MPEG version: 0x%lx",
+        (head >> 19) & 3);
+    return FALSE;
+  }
+  /* if it's an invalid layer */
+  if (!((head >> 17) & 3)) {
+    GST_WARNING_OBJECT (mp3parse, "invalid layer: 0x%lx", (head >> 17) & 3);
+    return FALSE;
+  }
+  /* if it's an invalid bitrate */
+  if (((head >> 12) & 0xf) == 0xf) {
+    GST_WARNING_OBJECT (mp3parse, "invalid bitrate: 0x%lx", (head >> 12) & 0xf);
+    return FALSE;
+  }
+  /* if it's an invalid samplerate */
+  if (((head >> 10) & 0x3) == 0x3) {
+    GST_WARNING_OBJECT (mp3parse, "invalid samplerate: 0x%lx",
+        (head >> 10) & 0x3);
+    return FALSE;
+  }
+
+  if ((head & 0x3) == 0x2) {
+    /* Ignore this as there are some files with emphasis 0x2 that can
+     * be played fine. See BGO #537235 */
+    GST_WARNING_OBJECT (mp3parse, "invalid emphasis: 0x%lx", head & 0x3);
+  }
+
+  return TRUE;
+}
+
+/* Determines possible freeform frame rate/size by looking for next
+ * header with valid bitrate (0 or otherwise valid) (and sufficiently
+ * matching current header).
+ *
+ * Returns TRUE if we've found such one, and *rate then contains rate
+ * (or *rate contains 0 if decided no freeframe size could be determined).
+ * If not enough data, returns FALSE.
+ */
+static gboolean
+gst_mp3parse_find_freerate (GstMpegAudioParse * mp3parse, GstMapInfo * map,
+    guint32 header, gboolean at_eos, gint * _rate)
+{
+  guint32 next_header;
+  const guint8 *data;
+  guint available;
+  int offset = 4;
+  gulong samplerate, rate, layer, padding;
+  gboolean valid;
+  gint lsf, mpg25;
+
+  available = map->size;
+  data = map->data;
+
+  *_rate = 0;
+
+  /* pick apart header again partially */
+  if (header & (1 << 20)) {
+    lsf = (header & (1 << 19)) ? 0 : 1;
+    mpg25 = 0;
+  } else {
+    lsf = 1;
+    mpg25 = 1;
+  }
+  layer = 4 - ((header >> 17) & 0x3);
+  samplerate = (header >> 10) & 0x3;
+  samplerate = mp3types_freqs[lsf + mpg25][samplerate];
+  padding = (header >> 9) & 0x1;
+
+  for (; offset < available; ++offset) {
+    /* Check if we have enough data for all these frames, plus the next
+       frame header. */
+    if (available < offset + 4) {
+      if (at_eos) {
+        /* Running out of data; failed to determine size */
+        return TRUE;
+      } else {
+        return FALSE;
+      }
+    }
+
+    valid = FALSE;
+    next_header = GST_READ_UINT32_BE (data + offset);
+    if ((next_header & 0xFFE00000) != 0xFFE00000)
+      goto next;
+
+    GST_DEBUG_OBJECT (mp3parse, "At %d: header=%08X, header2=%08X",
+        offset, (unsigned int) header, (unsigned int) next_header);
+
+    if ((next_header & HDRMASK) != (header & HDRMASK)) {
+      /* If any of the unmasked bits don't match, then it's not valid */
+      GST_DEBUG_OBJECT (mp3parse, "next header doesn't match "
+          "(header=%08X (%08X), header2=%08X (%08X))",
+          (guint) header, (guint) header & HDRMASK, (guint) next_header,
+          (guint) next_header & HDRMASK);
+      goto next;
+    } else if (((next_header >> 12) & 0xf) == 0xf) {
+      /* The essential parts were the same, but the bitrate held an
+         invalid value - also reject */
+      GST_DEBUG_OBJECT (mp3parse, "next header invalid (bitrate)");
+      goto next;
+    }
+
+    valid = TRUE;
+
+  next:
+    /* almost accept as free frame */
+    if (layer == 1) {
+      rate = samplerate * (offset - 4 * padding + 4) / 48000;
+    } else {
+      rate = samplerate * (offset - padding + 1) / (144 >> lsf) / 1000;
+    }
+
+    if (valid) {
+      GST_LOG_OBJECT (mp3parse, "calculated rate %lu", rate * 1000);
+      if (rate < 8 || (layer == 3 && rate > 640)) {
+        GST_DEBUG_OBJECT (mp3parse, "rate invalid");
+        if (rate < 8) {
+          /* maybe some hope */
+          continue;
+        } else {
+          GST_DEBUG_OBJECT (mp3parse, "aborting");
+          /* give up */
+          break;
+        }
+      }
+      *_rate = rate * 1000;
+      break;
+    } else {
+      /* avoid indefinite searching */
+      if (rate > 1000) {
+        GST_DEBUG_OBJECT (mp3parse, "exceeded sanity rate; aborting");
+        break;
+      }
+    }
+  }
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_mpeg_audio_parse_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize)
+{
+  GstMpegAudioParse *mp3parse = GST_MPEG_AUDIO_PARSE (parse);
+  GstBuffer *buf = frame->buffer;
+  GstByteReader reader;
+  gint off, bpf = 0;
+  gboolean lost_sync, draining, valid, caps_change;
+  guint32 header;
+  guint bitrate, layer, rate, channels, version, mode, crc;
+  GstMapInfo map;
+  gboolean res = FALSE;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  if (G_UNLIKELY (map.size < 6)) {
+    *skipsize = 1;
+    goto cleanup;
+  }
+
+  gst_byte_reader_init (&reader, map.data, map.size);
+
+  off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffe00000, 0xffe00000,
+      0, map.size);
+
+  GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off);
+
+  /* didn't find anything that looks like a sync word, skip */
+  if (off < 0) {
+    *skipsize = map.size - 3;
+    goto cleanup;
+  }
+
+  /* possible frame header, but not at offset 0? skip bytes before sync */
+  if (off > 0) {
+    *skipsize = off;
+    goto cleanup;
+  }
+
+  /* make sure the values in the frame header look sane */
+  header = GST_READ_UINT32_BE (map.data);
+  if (!gst_mpeg_audio_parse_head_check (mp3parse, header)) {
+    *skipsize = 1;
+    goto cleanup;
+  }
+
+  GST_LOG_OBJECT (parse, "got frame");
+
+  lost_sync = GST_BASE_PARSE_LOST_SYNC (parse);
+  draining = GST_BASE_PARSE_DRAINING (parse);
+
+  if (G_UNLIKELY (lost_sync))
+    mp3parse->freerate = 0;
+
+  bpf = mp3_type_frame_length_from_header (mp3parse, header,
+      &version, &layer, &channels, &bitrate, &rate, &mode, &crc);
+
+  if (channels != mp3parse->channels || rate != mp3parse->rate ||
+      layer != mp3parse->layer || version != mp3parse->version)
+    caps_change = TRUE;
+  else
+    caps_change = FALSE;
+
+  /* maybe free format */
+  if (bpf == 0) {
+    GST_LOG_OBJECT (mp3parse, "possibly free format");
+    if (lost_sync || mp3parse->freerate == 0) {
+      GST_DEBUG_OBJECT (mp3parse, "finding free format rate");
+      if (!gst_mp3parse_find_freerate (mp3parse, &map, header, draining,
+              &valid)) {
+        /* not enough data */
+        gst_base_parse_set_min_frame_size (parse, valid);
+        *skipsize = 0;
+        goto cleanup;
+      } else {
+        GST_DEBUG_OBJECT (parse, "determined freeform size %d", valid);
+        mp3parse->freerate = valid;
+      }
+    }
+    /* try again */
+    bpf = mp3_type_frame_length_from_header (mp3parse, header,
+        &version, &layer, &channels, &bitrate, &rate, &mode, &crc);
+    if (!bpf) {
+      /* did not come up with valid freeform length, reject after all */
+      *skipsize = 1;
+      goto cleanup;
+    }
+  }
+
+  if (!draining && (lost_sync || caps_change)) {
+    if (!gst_mp3parse_validate_extended (mp3parse, buf, header, bpf, draining,
+            &valid)) {
+      /* not enough data */
+      gst_base_parse_set_min_frame_size (parse, valid);
+      *skipsize = 0;
+      goto cleanup;
+    } else {
+      if (!valid) {
+        *skipsize = off + 2;
+        goto cleanup;
+      }
+    }
+  } else if (draining && lost_sync && caps_change && mp3parse->rate > 0) {
+    /* avoid caps jitter that we can't be sure of */
+    *skipsize = off + 2;
+    goto cleanup;
+  }
+
+  /* restore default minimum */
+  gst_base_parse_set_min_frame_size (parse, MIN_FRAME_SIZE);
+
+  res = TRUE;
+
+  /* metadata handling */
+  if (G_UNLIKELY (caps_change)) {
+    GstCaps *caps = gst_caps_new_simple ("audio/mpeg",
+        "mpegversion", G_TYPE_INT, 1,
+        "mpegaudioversion", G_TYPE_INT, version,
+        "layer", G_TYPE_INT, layer,
+        "rate", G_TYPE_INT, rate,
+        "channels", G_TYPE_INT, channels, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
+    gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
+    gst_caps_unref (caps);
+
+    mp3parse->rate = rate;
+    mp3parse->channels = channels;
+    mp3parse->layer = layer;
+    mp3parse->version = version;
+
+    /* see http://www.codeproject.com/audio/MPEGAudioInfo.asp */
+    if (mp3parse->layer == 1)
+      mp3parse->spf = 384;
+    else if (mp3parse->layer == 2)
+      mp3parse->spf = 1152;
+    else if (mp3parse->version == 1) {
+      mp3parse->spf = 1152;
+    } else {
+      /* MPEG-2 or "2.5" */
+      mp3parse->spf = 576;
+    }
+
+    /* lead_in:
+     * We start pushing 9 frames earlier (29 frames for MPEG2) than
+     * segment start to be able to decode the first frame we want.
+     * 9 (29) frames are the theoretical maximum of frames that contain
+     * data for the current frame (bit reservoir).
+     *
+     * lead_out:
+     * Some mp3 streams have an offset in the timestamps, for which we have to
+     * push the frame *after* the end position in order for the decoder to be
+     * able to decode everything up until the segment.stop position. */
+    gst_base_parse_set_frame_rate (parse, mp3parse->rate, mp3parse->spf,
+        (version == 1) ? 10 : 30, 2);
+  }
+
+  mp3parse->hdr_bitrate = bitrate;
+
+  /* For first frame; check for seek tables and output a codec tag */
+  gst_mpeg_audio_parse_handle_first_frame (mp3parse, buf);
+
+  /* store some frame info for later processing */
+  mp3parse->last_crc = crc;
+  mp3parse->last_mode = mode;
+
+cleanup:
+  gst_buffer_unmap (buf, &map);
+
+  if (res && bpf <= map.size) {
+    return gst_base_parse_finish_frame (parse, frame, bpf);
+  }
+
+  return GST_FLOW_OK;
+}
+
+static void
+gst_mpeg_audio_parse_handle_first_frame (GstMpegAudioParse * mp3parse,
+    GstBuffer * buf)
+{
+  const guint32 xing_id = 0x58696e67;   /* 'Xing' in hex */
+  const guint32 info_id = 0x496e666f;   /* 'Info' in hex - found in LAME CBR files */
+  const guint32 vbri_id = 0x56425249;   /* 'VBRI' in hex */
+  const guint32 lame_id = 0x4c414d45;   /* 'LAME' in hex */
+  gint offset_xing, offset_vbri;
+  guint64 avail;
+  gint64 upstream_total_bytes = 0;
+  guint32 read_id_xing = 0, read_id_vbri = 0;
+  GstMapInfo map;
+  guint8 *data;
+  guint bitrate;
+
+  if (mp3parse->sent_codec_tag)
+    return;
+
+  /* Check first frame for Xing info */
+  if (mp3parse->version == 1) { /* MPEG-1 file */
+    if (mp3parse->channels == 1)
+      offset_xing = 0x11;
+    else
+      offset_xing = 0x20;
+  } else {                      /* MPEG-2 header */
+    if (mp3parse->channels == 1)
+      offset_xing = 0x09;
+    else
+      offset_xing = 0x11;
+  }
+
+  /* The VBRI tag is always at offset 0x20 */
+  offset_vbri = 0x20;
+
+  /* Skip the 4 bytes of the MP3 header too */
+  offset_xing += 4;
+  offset_vbri += 4;
+
+  /* Check if we have enough data to read the Xing header */
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  data = map.data;
+  avail = map.size;
+
+  if (avail >= offset_xing + 4) {
+    read_id_xing = GST_READ_UINT32_BE (data + offset_xing);
+  }
+  if (avail >= offset_vbri + 4) {
+    read_id_vbri = GST_READ_UINT32_BE (data + offset_vbri);
+  }
+
+  /* obtain real upstream total bytes */
+  if (!gst_pad_peer_query_duration (GST_BASE_PARSE_SINK_PAD (mp3parse),
+          GST_FORMAT_BYTES, &upstream_total_bytes))
+    upstream_total_bytes = 0;
+
+  if (read_id_xing == xing_id || read_id_xing == info_id) {
+    guint32 xing_flags;
+    guint bytes_needed = offset_xing + 8;
+    gint64 total_bytes;
+    GstClockTime total_time;
+
+    GST_DEBUG_OBJECT (mp3parse, "Found Xing header marker 0x%x", xing_id);
+
+    /* Move data after Xing header */
+    data += offset_xing + 4;
+
+    /* Read 4 base bytes of flags, big-endian */
+    xing_flags = GST_READ_UINT32_BE (data);
+    data += 4;
+    if (xing_flags & XING_FRAMES_FLAG)
+      bytes_needed += 4;
+    if (xing_flags & XING_BYTES_FLAG)
+      bytes_needed += 4;
+    if (xing_flags & XING_TOC_FLAG)
+      bytes_needed += 100;
+    if (xing_flags & XING_VBR_SCALE_FLAG)
+      bytes_needed += 4;
+    if (avail < bytes_needed) {
+      GST_DEBUG_OBJECT (mp3parse,
+          "Not enough data to read Xing header (need %d)", bytes_needed);
+      goto cleanup;
+    }
+
+    GST_DEBUG_OBJECT (mp3parse, "Reading Xing header");
+    mp3parse->xing_flags = xing_flags;
+
+    if (xing_flags & XING_FRAMES_FLAG) {
+      mp3parse->xing_frames = GST_READ_UINT32_BE (data);
+      if (mp3parse->xing_frames == 0) {
+        GST_WARNING_OBJECT (mp3parse,
+            "Invalid number of frames in Xing header");
+        mp3parse->xing_flags &= ~XING_FRAMES_FLAG;
+      } else {
+        mp3parse->xing_total_time = gst_util_uint64_scale (GST_SECOND,
+            (guint64) (mp3parse->xing_frames) * (mp3parse->spf),
+            mp3parse->rate);
+      }
+
+      data += 4;
+    } else {
+      mp3parse->xing_frames = 0;
+      mp3parse->xing_total_time = 0;
+    }
+
+    if (xing_flags & XING_BYTES_FLAG) {
+      mp3parse->xing_bytes = GST_READ_UINT32_BE (data);
+      if (mp3parse->xing_bytes == 0) {
+        GST_WARNING_OBJECT (mp3parse, "Invalid number of bytes in Xing header");
+        mp3parse->xing_flags &= ~XING_BYTES_FLAG;
+      }
+      data += 4;
+    } else {
+      mp3parse->xing_bytes = 0;
+    }
+
+    /* If we know the upstream size and duration, compute the
+     * total bitrate, rounded up to the nearest kbit/sec */
+    if ((total_time = mp3parse->xing_total_time) &&
+        (total_bytes = mp3parse->xing_bytes)) {
+      mp3parse->xing_bitrate = gst_util_uint64_scale (total_bytes,
+          8 * GST_SECOND, total_time);
+      mp3parse->xing_bitrate += 500;
+      mp3parse->xing_bitrate -= mp3parse->xing_bitrate % 1000;
+    }
+
+    if (xing_flags & XING_TOC_FLAG) {
+      int i, percent = 0;
+      guchar *table = mp3parse->xing_seek_table;
+      guchar old = 0, new;
+      guint first;
+
+      first = data[0];
+      GST_DEBUG_OBJECT (mp3parse,
+          "Subtracting initial offset of %d bytes from Xing TOC", first);
+
+      /* xing seek table: percent time -> 1/256 bytepos */
+      for (i = 0; i < 100; i++) {
+        new = data[i] - first;
+        if (old > new) {
+          GST_WARNING_OBJECT (mp3parse, "Skipping broken Xing TOC");
+          mp3parse->xing_flags &= ~XING_TOC_FLAG;
+          goto skip_toc;
+        }
+        mp3parse->xing_seek_table[i] = old = new;
+      }
+
+      /* build inverse table: 1/256 bytepos -> 1/100 percent time */
+      for (i = 0; i < 256; i++) {
+        while (percent < 99 && table[percent + 1] <= i)
+          percent++;
+
+        if (table[percent] == i) {
+          mp3parse->xing_seek_table_inverse[i] = percent * 100;
+        } else if (percent < 99 && table[percent]) {
+          gdouble fa, fb, fx;
+          gint a = percent, b = percent + 1;
+
+          fa = table[a];
+          fb = table[b];
+          fx = (b - a) / (fb - fa) * (i - fa) + a;
+          mp3parse->xing_seek_table_inverse[i] = (guint16) (fx * 100);
+        } else if (percent == 99) {
+          gdouble fa, fb, fx;
+          gint a = percent, b = 100;
+
+          fa = table[a];
+          fb = 256.0;
+          fx = (b - a) / (fb - fa) * (i - fa) + a;
+          mp3parse->xing_seek_table_inverse[i] = (guint16) (fx * 100);
+        }
+      }
+    skip_toc:
+      data += 100;
+    } else {
+      memset (mp3parse->xing_seek_table, 0, sizeof (mp3parse->xing_seek_table));
+      memset (mp3parse->xing_seek_table_inverse, 0,
+          sizeof (mp3parse->xing_seek_table_inverse));
+    }
+
+    if (xing_flags & XING_VBR_SCALE_FLAG) {
+      mp3parse->xing_vbr_scale = GST_READ_UINT32_BE (data);
+      data += 4;
+    } else
+      mp3parse->xing_vbr_scale = 0;
+
+    GST_DEBUG_OBJECT (mp3parse, "Xing header reported %u frames, time %"
+        GST_TIME_FORMAT ", %u bytes, vbr scale %u", mp3parse->xing_frames,
+        GST_TIME_ARGS (mp3parse->xing_total_time), mp3parse->xing_bytes,
+        mp3parse->xing_vbr_scale);
+
+    /* check for truncated file */
+    if (upstream_total_bytes && mp3parse->xing_bytes &&
+        mp3parse->xing_bytes * 0.8 > upstream_total_bytes) {
+      GST_WARNING_OBJECT (mp3parse, "File appears to have been truncated; "
+          "invalidating Xing header duration and size");
+      mp3parse->xing_flags &= ~XING_BYTES_FLAG;
+      mp3parse->xing_flags &= ~XING_FRAMES_FLAG;
+    }
+
+    /* Optional LAME tag? */
+    if (avail - bytes_needed >= 36 && GST_READ_UINT32_BE (data) == lame_id) {
+      gchar lame_version[10] = { 0, };
+      guint tag_rev;
+      guint32 encoder_delay, encoder_padding;
+
+      memcpy (lame_version, data, 9);
+      data += 9;
+      tag_rev = data[0] >> 4;
+      GST_DEBUG_OBJECT (mp3parse, "Found LAME tag revision %d created by '%s'",
+          tag_rev, lame_version);
+
+      /* Skip all the information we're not interested in */
+      data += 12;
+      /* Encoder delay and end padding */
+      encoder_delay = GST_READ_UINT24_BE (data);
+      encoder_delay >>= 12;
+      encoder_padding = GST_READ_UINT24_BE (data);
+      encoder_padding &= 0x000fff;
+
+      mp3parse->encoder_delay = encoder_delay;
+      mp3parse->encoder_padding = encoder_padding;
+
+      GST_DEBUG_OBJECT (mp3parse, "Encoder delay %u, encoder padding %u",
+          encoder_delay, encoder_padding);
+    }
+  } else if (read_id_vbri == vbri_id) {
+    gint64 total_bytes, total_frames;
+    GstClockTime total_time;
+    guint16 nseek_points;
+
+    GST_DEBUG_OBJECT (mp3parse, "Found VBRI header marker 0x%x", vbri_id);
+
+    if (avail < offset_vbri + 26) {
+      GST_DEBUG_OBJECT (mp3parse,
+          "Not enough data to read VBRI header (need %d)", offset_vbri + 26);
+      goto cleanup;
+    }
+
+    GST_DEBUG_OBJECT (mp3parse, "Reading VBRI header");
+
+    /* Move data after VBRI header */
+    data += offset_vbri + 4;
+
+    if (GST_READ_UINT16_BE (data) != 0x0001) {
+      GST_WARNING_OBJECT (mp3parse,
+          "Unsupported VBRI version 0x%x", GST_READ_UINT16_BE (data));
+      goto cleanup;
+    }
+    data += 2;
+
+    /* Skip encoder delay */
+    data += 2;
+
+    /* Skip quality */
+    data += 2;
+
+    total_bytes = GST_READ_UINT32_BE (data);
+    if (total_bytes != 0)
+      mp3parse->vbri_bytes = total_bytes;
+    data += 4;
+
+    total_frames = GST_READ_UINT32_BE (data);
+    if (total_frames != 0) {
+      mp3parse->vbri_frames = total_frames;
+      mp3parse->vbri_total_time = gst_util_uint64_scale (GST_SECOND,
+          (guint64) (mp3parse->vbri_frames) * (mp3parse->spf), mp3parse->rate);
+    }
+    data += 4;
+
+    /* If we know the upstream size and duration, compute the
+     * total bitrate, rounded up to the nearest kbit/sec */
+    if ((total_time = mp3parse->vbri_total_time) &&
+        (total_bytes = mp3parse->vbri_bytes)) {
+      mp3parse->vbri_bitrate = gst_util_uint64_scale (total_bytes,
+          8 * GST_SECOND, total_time);
+      mp3parse->vbri_bitrate += 500;
+      mp3parse->vbri_bitrate -= mp3parse->vbri_bitrate % 1000;
+    }
+
+    nseek_points = GST_READ_UINT16_BE (data);
+    data += 2;
+
+    if (nseek_points > 0) {
+      guint scale, seek_bytes, seek_frames;
+      gint i;
+
+      mp3parse->vbri_seek_points = nseek_points;
+
+      scale = GST_READ_UINT16_BE (data);
+      data += 2;
+
+      seek_bytes = GST_READ_UINT16_BE (data);
+      data += 2;
+
+      seek_frames = GST_READ_UINT16_BE (data);
+
+      if (scale == 0 || seek_bytes == 0 || seek_bytes > 4 || seek_frames == 0) {
+        GST_WARNING_OBJECT (mp3parse, "Unsupported VBRI seek table");
+        goto out_vbri;
+      }
+
+      if (avail < offset_vbri + 26 + nseek_points * seek_bytes) {
+        GST_WARNING_OBJECT (mp3parse,
+            "Not enough data to read VBRI seek table (need %d)",
+            offset_vbri + 26 + nseek_points * seek_bytes);
+        goto out_vbri;
+      }
+
+      if (seek_frames * nseek_points < total_frames - seek_frames ||
+          seek_frames * nseek_points > total_frames + seek_frames) {
+        GST_WARNING_OBJECT (mp3parse,
+            "VBRI seek table doesn't cover the complete file");
+        goto out_vbri;
+      }
+
+      data = map.data;
+      data += offset_vbri + 26;
+
+      /* VBRI seek table: frame/seek_frames -> byte */
+      mp3parse->vbri_seek_table = g_new (guint32, nseek_points);
+      if (seek_bytes == 4)
+        for (i = 0; i < nseek_points; i++) {
+          mp3parse->vbri_seek_table[i] = GST_READ_UINT32_BE (data) * scale;
+          data += 4;
+      } else if (seek_bytes == 3)
+        for (i = 0; i < nseek_points; i++) {
+          mp3parse->vbri_seek_table[i] = GST_READ_UINT24_BE (data) * scale;
+          data += 3;
+      } else if (seek_bytes == 2)
+        for (i = 0; i < nseek_points; i++) {
+          mp3parse->vbri_seek_table[i] = GST_READ_UINT16_BE (data) * scale;
+          data += 2;
+      } else                    /* seek_bytes == 1 */
+        for (i = 0; i < nseek_points; i++) {
+          mp3parse->vbri_seek_table[i] = GST_READ_UINT8 (data) * scale;
+          data += 1;
+        }
+    }
+  out_vbri:
+
+    GST_DEBUG_OBJECT (mp3parse, "VBRI header reported %u frames, time %"
+        GST_TIME_FORMAT ", bytes %u", mp3parse->vbri_frames,
+        GST_TIME_ARGS (mp3parse->vbri_total_time), mp3parse->vbri_bytes);
+
+    /* check for truncated file */
+    if (upstream_total_bytes && mp3parse->vbri_bytes &&
+        mp3parse->vbri_bytes * 0.8 > upstream_total_bytes) {
+      GST_WARNING_OBJECT (mp3parse, "File appears to have been truncated; "
+          "invalidating VBRI header duration and size");
+      mp3parse->vbri_valid = FALSE;
+    } else {
+      mp3parse->vbri_valid = TRUE;
+    }
+  } else {
+    GST_DEBUG_OBJECT (mp3parse,
+        "Xing, LAME or VBRI header not found in first frame");
+  }
+
+  /* set duration if tables provided a valid one */
+  if (mp3parse->xing_flags & XING_FRAMES_FLAG) {
+    gst_base_parse_set_duration (GST_BASE_PARSE (mp3parse), GST_FORMAT_TIME,
+        mp3parse->xing_total_time, 0);
+  }
+  if (mp3parse->vbri_total_time != 0 && mp3parse->vbri_valid) {
+    gst_base_parse_set_duration (GST_BASE_PARSE (mp3parse), GST_FORMAT_TIME,
+        mp3parse->vbri_total_time, 0);
+  }
+
+  /* tell baseclass how nicely we can seek, and a bitrate if one found */
+  /* FIXME: fill index with seek table */
+#if 0
+  seekable = GST_BASE_PARSE_SEEK_DEFAULT;
+  if ((mp3parse->xing_flags & XING_TOC_FLAG) && mp3parse->xing_bytes &&
+      mp3parse->xing_total_time)
+    seekable = GST_BASE_PARSE_SEEK_TABLE;
+
+  if (mp3parse->vbri_seek_table && mp3parse->vbri_bytes &&
+      mp3parse->vbri_total_time)
+    seekable = GST_BASE_PARSE_SEEK_TABLE;
+#endif
+
+  if (mp3parse->xing_bitrate)
+    bitrate = mp3parse->xing_bitrate;
+  else if (mp3parse->vbri_bitrate)
+    bitrate = mp3parse->vbri_bitrate;
+  else
+    bitrate = 0;
+
+  gst_base_parse_set_average_bitrate (GST_BASE_PARSE (mp3parse), bitrate);
+
+cleanup:
+  gst_buffer_unmap (buf, &map);
+}
+
+static gboolean
+gst_mpeg_audio_parse_time_to_bytepos (GstMpegAudioParse * mp3parse,
+    GstClockTime ts, gint64 * bytepos)
+{
+  gint64 total_bytes;
+  GstClockTime total_time;
+
+  /* If XING seek table exists use this for time->byte conversion */
+  if ((mp3parse->xing_flags & XING_TOC_FLAG) &&
+      (total_bytes = mp3parse->xing_bytes) &&
+      (total_time = mp3parse->xing_total_time)) {
+    gdouble fa, fb, fx;
+    gdouble percent =
+        CLAMP ((100.0 * gst_util_guint64_to_gdouble (ts)) /
+        gst_util_guint64_to_gdouble (total_time), 0.0, 100.0);
+    gint index = CLAMP (percent, 0, 99);
+
+    fa = mp3parse->xing_seek_table[index];
+    if (index < 99)
+      fb = mp3parse->xing_seek_table[index + 1];
+    else
+      fb = 256.0;
+
+    fx = fa + (fb - fa) * (percent - index);
+
+    *bytepos = (1.0 / 256.0) * fx * total_bytes;
+
+    return TRUE;
+  }
+
+  if (mp3parse->vbri_seek_table && (total_bytes = mp3parse->vbri_bytes) &&
+      (total_time = mp3parse->vbri_total_time)) {
+    gint i, j;
+    gdouble a, b, fa, fb;
+
+    i = gst_util_uint64_scale (ts, mp3parse->vbri_seek_points - 1, total_time);
+    i = CLAMP (i, 0, mp3parse->vbri_seek_points - 1);
+
+    a = gst_guint64_to_gdouble (gst_util_uint64_scale (i, total_time,
+            mp3parse->vbri_seek_points));
+    fa = 0.0;
+    for (j = i; j >= 0; j--)
+      fa += mp3parse->vbri_seek_table[j];
+
+    if (i + 1 < mp3parse->vbri_seek_points) {
+      b = gst_guint64_to_gdouble (gst_util_uint64_scale (i + 1, total_time,
+              mp3parse->vbri_seek_points));
+      fb = fa + mp3parse->vbri_seek_table[i + 1];
+    } else {
+      b = gst_guint64_to_gdouble (total_time);
+      fb = total_bytes;
+    }
+
+    *bytepos = fa + ((fb - fa) / (b - a)) * (gst_guint64_to_gdouble (ts) - a);
+
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+static gboolean
+gst_mpeg_audio_parse_bytepos_to_time (GstMpegAudioParse * mp3parse,
+    gint64 bytepos, GstClockTime * ts)
+{
+  gint64 total_bytes;
+  GstClockTime total_time;
+
+  /* If XING seek table exists use this for byte->time conversion */
+  if ((mp3parse->xing_flags & XING_TOC_FLAG) &&
+      (total_bytes = mp3parse->xing_bytes) &&
+      (total_time = mp3parse->xing_total_time)) {
+    gdouble fa, fb, fx;
+    gdouble pos;
+    gint index;
+
+    pos = CLAMP ((bytepos * 256.0) / total_bytes, 0.0, 256.0);
+    index = CLAMP (pos, 0, 255);
+    fa = mp3parse->xing_seek_table_inverse[index];
+    if (index < 255)
+      fb = mp3parse->xing_seek_table_inverse[index + 1];
+    else
+      fb = 10000.0;
+
+    fx = fa + (fb - fa) * (pos - index);
+
+    *ts = (1.0 / 10000.0) * fx * gst_util_guint64_to_gdouble (total_time);
+
+    return TRUE;
+  }
+
+  if (mp3parse->vbri_seek_table &&
+      (total_bytes = mp3parse->vbri_bytes) &&
+      (total_time = mp3parse->vbri_total_time)) {
+    gint i = 0;
+    guint64 sum = 0;
+    gdouble a, b, fa, fb;
+
+    do {
+      sum += mp3parse->vbri_seek_table[i];
+      i++;
+    } while (i + 1 < mp3parse->vbri_seek_points
+        && sum + mp3parse->vbri_seek_table[i] < bytepos);
+    i--;
+
+    a = gst_guint64_to_gdouble (sum);
+    fa = gst_guint64_to_gdouble (gst_util_uint64_scale (i, total_time,
+            mp3parse->vbri_seek_points));
+
+    if (i + 1 < mp3parse->vbri_seek_points) {
+      b = a + mp3parse->vbri_seek_table[i + 1];
+      fb = gst_guint64_to_gdouble (gst_util_uint64_scale (i + 1, total_time,
+              mp3parse->vbri_seek_points));
+    } else {
+      b = total_bytes;
+      fb = gst_guint64_to_gdouble (total_time);
+    }
+
+    *ts = gst_gdouble_to_guint64 (fa + ((fb - fa) / (b - a)) * (bytepos - a));
+
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+static gboolean
+gst_mpeg_audio_parse_convert (GstBaseParse * parse, GstFormat src_format,
+    gint64 src_value, GstFormat dest_format, gint64 * dest_value)
+{
+  GstMpegAudioParse *mp3parse = GST_MPEG_AUDIO_PARSE (parse);
+  gboolean res = FALSE;
+
+  if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_BYTES)
+    res =
+        gst_mpeg_audio_parse_time_to_bytepos (mp3parse, src_value, dest_value);
+  else if (src_format == GST_FORMAT_BYTES && dest_format == GST_FORMAT_TIME)
+    res = gst_mpeg_audio_parse_bytepos_to_time (mp3parse, src_value,
+        (GstClockTime *) dest_value);
+
+  /* if no tables, fall back to default estimated rate based conversion */
+  if (!res)
+    return gst_base_parse_convert_default (parse, src_format, src_value,
+        dest_format, dest_value);
+
+  return res;
+}
+
+static GstFlowReturn
+gst_mpeg_audio_parse_pre_push_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame)
+{
+  GstMpegAudioParse *mp3parse = GST_MPEG_AUDIO_PARSE (parse);
+  GstTagList *taglist = NULL;
+
+  /* we will create a taglist (if any of the parameters has changed)
+   * to add the tags that changed */
+  if (mp3parse->last_posted_crc != mp3parse->last_crc) {
+    gboolean using_crc;
+
+    if (!taglist)
+      taglist = gst_tag_list_new_empty ();
+
+    mp3parse->last_posted_crc = mp3parse->last_crc;
+    if (mp3parse->last_posted_crc == CRC_PROTECTED) {
+      using_crc = TRUE;
+    } else {
+      using_crc = FALSE;
+    }
+    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_CRC,
+        using_crc, NULL);
+  }
+
+  if (mp3parse->last_posted_channel_mode != mp3parse->last_mode) {
+    if (!taglist)
+      taglist = gst_tag_list_new_empty ();
+
+    mp3parse->last_posted_channel_mode = mp3parse->last_mode;
+
+    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_MODE,
+        gst_mpeg_audio_channel_mode_get_nick (mp3parse->last_mode), NULL);
+  }
+
+  /* tag sending done late enough in hook to ensure pending events
+   * have already been sent */
+  if (taglist != NULL || !mp3parse->sent_codec_tag) {
+    GstCaps *caps;
+
+    if (taglist == NULL)
+      taglist = gst_tag_list_new_empty ();
+
+    /* codec tag */
+    caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
+    if (G_UNLIKELY (caps == NULL)) {
+      gst_tag_list_unref (taglist);
+
+      if (GST_PAD_IS_FLUSHING (GST_BASE_PARSE_SRC_PAD (parse))) {
+        GST_INFO_OBJECT (parse, "Src pad is flushing");
+        return GST_FLOW_FLUSHING;
+      } else {
+        GST_INFO_OBJECT (parse, "Src pad is not negotiated!");
+        return GST_FLOW_NOT_NEGOTIATED;
+      }
+    }
+    gst_pb_utils_add_codec_description_to_tag_list (taglist,
+        GST_TAG_AUDIO_CODEC, caps);
+    gst_caps_unref (caps);
+
+    if (mp3parse->hdr_bitrate > 0 && mp3parse->xing_bitrate == 0 &&
+        mp3parse->vbri_bitrate == 0) {
+      /* We don't have a VBR bitrate, so post the available bitrate as
+       * nominal and let baseparse calculate the real bitrate */
+      gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
+          GST_TAG_NOMINAL_BITRATE, mp3parse->hdr_bitrate, NULL);
+    }
+
+    /* also signals the end of first-frame processing */
+    mp3parse->sent_codec_tag = TRUE;
+  }
+
+  /* if the taglist exists, we need to update it so it gets sent out */
+  if (taglist) {
+    gst_base_parse_merge_tags (parse, taglist, GST_TAG_MERGE_REPLACE);
+    gst_tag_list_unref (taglist);
+  }
+
+  /* usual clipping applies */
+  frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP;
+
+  return GST_FLOW_OK;
+}
+
+static void
+remove_fields (GstCaps * caps)
+{
+  guint i, n;
+
+  n = gst_caps_get_size (caps);
+  for (i = 0; i < n; i++) {
+    GstStructure *s = gst_caps_get_structure (caps, i);
+
+    gst_structure_remove_field (s, "parsed");
+  }
+}
+
+static GstCaps *
+gst_mpeg_audio_parse_get_sink_caps (GstBaseParse * parse, GstCaps * filter)
+{
+  GstCaps *peercaps, *templ;
+  GstCaps *res;
+
+  templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
+  if (filter) {
+    GstCaps *fcopy = gst_caps_copy (filter);
+    /* Remove the fields we convert */
+    remove_fields (fcopy);
+    peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
+    gst_caps_unref (fcopy);
+  } else
+    peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), NULL);
+
+  if (peercaps) {
+    /* Remove the parsed field */
+    peercaps = gst_caps_make_writable (peercaps);
+    remove_fields (peercaps);
+
+    res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (peercaps);
+    gst_caps_unref (templ);
+  } else {
+    res = templ;
+  }
+
+  if (filter) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (res);
+    res = intersection;
+  }
+
+  return res;
+}
diff --git a/gst/audioparsers/gstmpegaudioparse.h b/gst/audioparsers/gstmpegaudioparse.h
new file mode 100644
index 0000000..5e576be
--- /dev/null
+++ b/gst/audioparsers/gstmpegaudioparse.h
@@ -0,0 +1,113 @@
+/* GStreamer MPEG audio parser
+ * Copyright (C) 2006-2007 Jan Schmidt <thaytan@mad.scientist.com>
+ * Copyright (C) 2010 Mark Nauwelaerts <mnauw users sf net>
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ *   Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MPEG_AUDIO_PARSE_H__
+#define __GST_MPEG_AUDIO_PARSE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbaseparse.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_MPEG_AUDIO_PARSE \
+  (gst_mpeg_audio_parse_get_type())
+#define GST_MPEG_AUDIO_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_MPEG_AUDIO_PARSE, GstMpegAudioParse))
+#define GST_MPEG_AUDIO_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_MPEG_AUDIO_PARSE, GstMpegAudioParseClass))
+#define GST_IS_MPEG_AUDIO_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_MPEG_AUDIO_PARSE))
+#define GST_IS_MPEG_AUDIO_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_MPEG_AUDIO_PARSE))
+
+typedef struct _GstMpegAudioParse GstMpegAudioParse;
+typedef struct _GstMpegAudioParseClass GstMpegAudioParseClass;
+
+/**
+ * GstMpegAudioParse:
+ *
+ * The opaque GstMpegAudioParse object
+ */
+struct _GstMpegAudioParse {
+  GstBaseParse baseparse;
+
+  /*< private >*/
+  gint         rate;
+  gint         channels;
+  gint         layer;
+  gint         version;
+
+  GstClockTime max_bitreservoir;
+  /* samples per frame */
+  gint        spf;
+
+  gint         freerate;
+
+  gboolean     sent_codec_tag;
+  guint        last_posted_bitrate;
+  gint         last_posted_crc, last_crc;
+  guint        last_posted_channel_mode, last_mode;
+
+  /* Bitrate from non-vbr headers */
+  guint32      hdr_bitrate;
+
+  /* Xing info */
+  guint32      xing_flags;
+  guint32      xing_frames;
+  GstClockTime xing_total_time;
+  guint32      xing_bytes;
+  /* percent -> filepos mapping */
+  guchar       xing_seek_table[100];
+  /* filepos -> percent mapping */
+  guint16      xing_seek_table_inverse[256];
+  guint32      xing_vbr_scale;
+  guint        xing_bitrate;
+
+  /* VBRI info */
+  guint32      vbri_frames;
+  GstClockTime vbri_total_time;
+  guint32      vbri_bytes;
+  guint        vbri_bitrate;
+  guint        vbri_seek_points;
+  guint32     *vbri_seek_table;
+  gboolean     vbri_valid;
+
+  /* LAME info */
+  guint32      encoder_delay;
+  guint32      encoder_padding;
+};
+
+/**
+ * GstMpegAudioParseClass:
+ * @parent_class: Element parent class.
+ *
+ * The opaque GstMpegAudioParseClass data structure.
+ */
+struct _GstMpegAudioParseClass {
+  GstBaseParseClass baseparse_class;
+};
+
+GType gst_mpeg_audio_parse_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_MPEG_AUDIO_PARSE_H__ */
diff --git a/gst/audioparsers/gstsbcparse.c b/gst/audioparsers/gstsbcparse.c
new file mode 100644
index 0000000..12c39d9
--- /dev/null
+++ b/gst/audioparsers/gstsbcparse.c
@@ -0,0 +1,533 @@
+/* GStreamer SBC audio parser
+ * Copyright (C) 2012 Collabora Ltd. <tim.muller@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/**
+ * SECTION:element-sbcparse
+ * @see_also: sbcdec, sbcenc
+ *
+ * The sbcparse element will parse a bluetooth SBC audio stream into
+ * frames and timestamp them properly.
+ *
+ * Since: 1.2.0
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstsbcparse.h"
+
+#include <string.h>
+#include <gst/tag/tag.h>
+#include <gst/audio/audio.h>
+#include <gst/base/base.h>
+#include <gst/pbutils/pbutils.h>
+
+#define SBC_SYNCBYTE 0x9C
+
+GST_DEBUG_CATEGORY_STATIC (sbcparse_debug);
+#define GST_CAT_DEFAULT sbcparse_debug
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-sbc, parsed = (boolean) true, "
+        "channels = (int) [ 1, 2 ], "
+        "rate = (int) { 16000, 32000, 44100, 48000 }")
+    );
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-sbc")
+    );
+
+static gboolean gst_sbc_parse_start (GstBaseParse * parse);
+static gboolean gst_sbc_parse_stop (GstBaseParse * parse);
+static GstFlowReturn gst_sbc_parse_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize);
+static GstFlowReturn gst_sbc_parse_pre_push_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame);
+static GstCaps *gst_sbc_parse_get_sink_caps (GstBaseParse * parse,
+    GstCaps * filter);
+
+static guint8 gst_sbc_calculate_crc8 (const guint8 * data, gint bits_crc);
+static gsize gst_sbc_calc_framelen (guint subbands, GstSbcChannelMode ch_mode,
+    guint blocks, guint bitpool);
+static gsize gst_sbc_parse_header (const guint8 * data, guint * rate,
+    guint * n_blocks, GstSbcChannelMode * ch_mode,
+    GstSbcAllocationMethod * alloc_method, guint * n_subbands, guint * bitpool);
+
+#define parent_class gst_sbc_parse_parent_class
+G_DEFINE_TYPE (GstSbcParse, gst_sbc_parse, GST_TYPE_BASE_PARSE);
+
+static void
+gst_sbc_parse_class_init (GstSbcParseClass * klass)
+{
+  GstBaseParseClass *baseparse_class = GST_BASE_PARSE_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (sbcparse_debug, "sbcparse", 0, "SBC audio parser");
+
+  baseparse_class->start = GST_DEBUG_FUNCPTR (gst_sbc_parse_start);
+  baseparse_class->stop = GST_DEBUG_FUNCPTR (gst_sbc_parse_stop);
+  baseparse_class->pre_push_frame =
+      GST_DEBUG_FUNCPTR (gst_sbc_parse_pre_push_frame);
+  baseparse_class->handle_frame =
+      GST_DEBUG_FUNCPTR (gst_sbc_parse_handle_frame);
+  baseparse_class->get_sink_caps =
+      GST_DEBUG_FUNCPTR (gst_sbc_parse_get_sink_caps);
+
+  gst_element_class_add_static_pad_template (element_class, &src_factory);
+  gst_element_class_add_static_pad_template (element_class, &sink_factory);
+
+  gst_element_class_set_static_metadata (element_class, "SBC audio parser",
+      "Codec/Parser/Audio", "Parses an SBC bluetooth audio stream",
+      "Tim-Philipp Müller <tim.muller@collabora.co.uk>");
+}
+
+static void
+gst_sbc_parse_reset (GstSbcParse * sbcparse)
+{
+  sbcparse->alloc_method = GST_SBC_ALLOCATION_METHOD_INVALID;
+  sbcparse->ch_mode = GST_SBC_CHANNEL_MODE_INVALID;
+  sbcparse->rate = -1;
+  sbcparse->n_blocks = -1;
+  sbcparse->n_subbands = -1;
+  sbcparse->bitpool = -1;
+  sbcparse->sent_codec_tag = FALSE;
+}
+
+static void
+gst_sbc_parse_init (GstSbcParse * sbcparse)
+{
+  gst_sbc_parse_reset (sbcparse);
+  GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (sbcparse));
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (sbcparse));
+}
+
+static gboolean
+gst_sbc_parse_start (GstBaseParse * parse)
+{
+  gst_base_parse_set_min_frame_size (parse,
+      gst_sbc_calc_framelen (4, GST_SBC_CHANNEL_MODE_MONO, 4, 2));
+
+  gst_base_parse_set_has_timing_info (parse, FALSE);
+
+  gst_base_parse_set_syncable (parse, TRUE);
+
+  return TRUE;
+}
+
+static gboolean
+gst_sbc_parse_stop (GstBaseParse * parse)
+{
+  gst_sbc_parse_reset (GST_SBC_PARSE (parse));
+  return TRUE;
+}
+
+static const gchar *
+gst_sbc_channel_mode_get_name (GstSbcChannelMode ch_mode)
+{
+  switch (ch_mode) {
+    case GST_SBC_CHANNEL_MODE_MONO:
+      return "mono";
+    case GST_SBC_CHANNEL_MODE_DUAL:
+      return "dual";
+    case GST_SBC_CHANNEL_MODE_STEREO:
+      return "stereo";
+    case GST_SBC_CHANNEL_MODE_JOINT_STEREO:
+      return "joint";
+    default:
+      break;
+  }
+  return "invalid";
+}
+
+static const gchar *
+gst_sbc_allocation_method_get_name (GstSbcAllocationMethod alloc_method)
+{
+  switch (alloc_method) {
+    case GST_SBC_ALLOCATION_METHOD_SNR:
+      return "snr";
+    case GST_SBC_ALLOCATION_METHOD_LOUDNESS:
+      return "loudness";
+    default:
+      break;
+  }
+  return "invalid";
+}
+
+static GstFlowReturn
+gst_sbc_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame,
+    gint * skipsize)
+{
+  GstSbcParse *sbcparse = GST_SBC_PARSE (parse);
+  GstSbcAllocationMethod alloc_method = GST_SBC_ALLOCATION_METHOD_INVALID;
+  GstSbcChannelMode ch_mode = GST_SBC_CHANNEL_MODE_INVALID;
+  GstMapInfo map;
+  guint rate = 0, n_blocks = 0, n_subbands = 0, bitpool = 0;
+  gsize frame_len, next_len;
+  gint i, max_frames;
+
+  gst_buffer_map (frame->buffer, &map, GST_MAP_READ);
+
+  g_assert (map.size >= 6);
+
+  frame_len = gst_sbc_parse_header (map.data, &rate, &n_blocks, &ch_mode,
+      &alloc_method, &n_subbands, &bitpool);
+
+  GST_LOG_OBJECT (parse, "frame_len: %u", (guint) frame_len);
+
+  if (frame_len == 0)
+    goto resync;
+
+  if (sbcparse->alloc_method != alloc_method
+      || sbcparse->ch_mode != ch_mode
+      || sbcparse->rate != rate
+      || sbcparse->n_blocks != n_blocks
+      || sbcparse->n_subbands != n_subbands || sbcparse->bitpool != bitpool) {
+    guint avg_bitrate;
+    GstCaps *caps;
+
+    /* FIXME: do all of these need to be in the caps? */
+    caps = gst_caps_new_simple ("audio/x-sbc", "rate", G_TYPE_INT, rate,
+        "channels", G_TYPE_INT, (ch_mode == GST_SBC_CHANNEL_MODE_MONO) ? 1 : 2,
+        "channel-mode", G_TYPE_STRING, gst_sbc_channel_mode_get_name (ch_mode),
+        "blocks", G_TYPE_INT, n_blocks, "subbands", G_TYPE_INT, n_subbands,
+        "allocation-method", G_TYPE_STRING,
+        gst_sbc_allocation_method_get_name (alloc_method),
+        "bitpool", G_TYPE_INT, bitpool, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
+
+    GST_INFO_OBJECT (sbcparse, "caps changed to %" GST_PTR_FORMAT, caps);
+
+    gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (sbcparse),
+        gst_event_new_caps (caps));
+
+    avg_bitrate = (8 * frame_len * rate) / (n_subbands * n_blocks);
+    gst_base_parse_set_average_bitrate (parse, avg_bitrate);
+
+    gst_base_parse_set_frame_rate (parse, rate, n_subbands * n_blocks, 0, 0);
+
+    sbcparse->alloc_method = alloc_method;
+    sbcparse->ch_mode = ch_mode;
+    sbcparse->rate = rate;
+    sbcparse->n_blocks = n_blocks;
+    sbcparse->n_subbands = n_subbands;
+    sbcparse->bitpool = bitpool;
+
+    gst_caps_unref (caps);
+  }
+
+  if (frame_len > map.size)
+    goto need_more_data;
+
+  GST_BUFFER_OFFSET (frame->buffer) = GST_BUFFER_OFFSET_NONE;
+  GST_BUFFER_OFFSET_END (frame->buffer) = GST_BUFFER_OFFSET_NONE;
+
+  /* completely arbitrary limit, we only process data we already have,
+   * so we aren't introducing latency here */
+  max_frames = MIN (map.size / frame_len, n_blocks * n_subbands * 5);
+  GST_LOG_OBJECT (sbcparse, "parsing up to %d frames", max_frames);
+
+  for (i = 1; i < max_frames; ++i) {
+    next_len = gst_sbc_parse_header (map.data + (i * frame_len), &rate,
+        &n_blocks, &ch_mode, &alloc_method, &n_subbands, &bitpool);
+
+    if (next_len != frame_len || sbcparse->alloc_method != alloc_method ||
+        sbcparse->ch_mode != ch_mode || sbcparse->rate != rate ||
+        sbcparse->n_blocks != n_blocks || sbcparse->n_subbands != n_subbands ||
+        sbcparse->bitpool != bitpool) {
+      break;
+    }
+  }
+  GST_LOG_OBJECT (sbcparse, "packing %d SBC frames into next output buffer", i);
+
+  /* Note: local n_subbands and n_blocks variables might be tainted if we
+   * bailed out of the loop above because of a header configuration mismatch */
+  gst_base_parse_set_frame_rate (parse, rate,
+      sbcparse->n_subbands * sbcparse->n_blocks * i, 0, 0);
+
+  gst_buffer_unmap (frame->buffer, &map);
+  return gst_base_parse_finish_frame (parse, frame, i * frame_len);
+
+resync:
+  {
+    const guint8 *possible_sync;
+
+    GST_DEBUG_OBJECT (parse, "no sync, resyncing");
+
+    possible_sync = memchr (map.data, SBC_SYNCBYTE, map.size);
+
+    if (possible_sync != NULL)
+      *skipsize = (gint) (possible_sync - map.data);
+    else
+      *skipsize = map.size;
+
+    gst_buffer_unmap (frame->buffer, &map);
+
+    /* we could optimise things here by looping over the data and checking
+     * whether the sync is good or not instead of handing control back to
+     * the base class just to be called again */
+    return GST_FLOW_OK;
+  }
+need_more_data:
+  {
+    GST_LOG_OBJECT (parse,
+        "need %" G_GSIZE_FORMAT " bytes, but only have %" G_GSIZE_FORMAT,
+        frame_len, map.size);
+    gst_base_parse_set_min_frame_size (parse, frame_len);
+    gst_buffer_unmap (frame->buffer, &map);
+    return GST_FLOW_OK;
+  }
+}
+
+static void
+remove_fields (GstCaps * caps)
+{
+  guint i, n;
+
+  n = gst_caps_get_size (caps);
+  for (i = 0; i < n; i++) {
+    GstStructure *s = gst_caps_get_structure (caps, i);
+
+    gst_structure_remove_field (s, "parsed");
+  }
+}
+
+static GstCaps *
+gst_sbc_parse_get_sink_caps (GstBaseParse * parse, GstCaps * filter)
+{
+  GstCaps *peercaps, *templ;
+  GstCaps *res;
+
+  templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
+  if (filter) {
+    GstCaps *fcopy = gst_caps_copy (filter);
+    /* Remove the fields we convert */
+    remove_fields (fcopy);
+    peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
+    gst_caps_unref (fcopy);
+  } else
+    peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), NULL);
+
+  if (peercaps) {
+    /* Remove the parsed field */
+    peercaps = gst_caps_make_writable (peercaps);
+    remove_fields (peercaps);
+
+    res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (peercaps);
+    gst_caps_unref (templ);
+  } else {
+    res = templ;
+  }
+
+  if (filter) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (res);
+    res = intersection;
+  }
+
+  return res;
+}
+
+static const guint8 crc_table[256] = {
+  0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53,
+  0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB,
+  0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E,
+  0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76,
+  0x87, 0x9A, 0xBD, 0xA0, 0xF3, 0xEE, 0xC9, 0xD4,
+  0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C,
+  0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19,
+  0xA2, 0xBF, 0x98, 0x85, 0xD6, 0xCB, 0xEC, 0xF1,
+  0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40,
+  0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8,
+  0xDE, 0xC3, 0xE4, 0xF9, 0xAA, 0xB7, 0x90, 0x8D,
+  0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65,
+  0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7,
+  0x7C, 0x61, 0x46, 0x5B, 0x08, 0x15, 0x32, 0x2F,
+  0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A,
+  0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2,
+  0x26, 0x3B, 0x1C, 0x01, 0x52, 0x4F, 0x68, 0x75,
+  0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D,
+  0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8,
+  0x03, 0x1E, 0x39, 0x24, 0x77, 0x6A, 0x4D, 0x50,
+  0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2,
+  0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A,
+  0x6C, 0x71, 0x56, 0x4B, 0x18, 0x05, 0x22, 0x3F,
+  0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7,
+  0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66,
+  0xDD, 0xC0, 0xE7, 0xFA, 0xA9, 0xB4, 0x93, 0x8E,
+  0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB,
+  0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43,
+  0xB2, 0xAF, 0x88, 0x95, 0xC6, 0xDB, 0xFC, 0xE1,
+  0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09,
+  0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C,
+  0x97, 0x8A, 0xAD, 0xB0, 0xE3, 0xFE, 0xD9, 0xC4
+};
+
+static guint8
+gst_sbc_calculate_crc8 (const guint8 * data, gint crc_bits)
+{
+  guint8 crc = 0x0f;
+  guint8 octet;
+
+  while (crc_bits >= 8) {
+    crc = crc_table[crc ^ *data];
+    crc_bits -= 8;
+    ++data;
+  }
+
+  octet = *data;
+  while (crc_bits > 0) {
+    gchar bit = ((octet ^ crc) & 0x80) >> 7;
+
+    crc = ((crc & 0x7f) << 1) ^ (bit ? 0x1d : 0);
+
+    octet = octet << 1;
+    --crc_bits;
+  }
+
+  return crc;
+}
+
+static gsize
+gst_sbc_calc_framelen (guint subbands, GstSbcChannelMode ch_mode,
+    guint blocks, guint bitpool)
+{
+  switch (ch_mode) {
+    case GST_SBC_CHANNEL_MODE_MONO:
+      return 4 + (subbands * 1) / 2 + ((blocks * 1 * bitpool) + 7) / 8;
+    case GST_SBC_CHANNEL_MODE_DUAL:
+      return 4 + (subbands * 2) / 2 + ((blocks * 2 * bitpool) + 7) / 8;
+    case GST_SBC_CHANNEL_MODE_STEREO:
+      return 4 + (subbands * 2) / 2 + ((blocks * bitpool) + 7) / 8;
+    case GST_SBC_CHANNEL_MODE_JOINT_STEREO:
+      return 4 + (subbands * 2) / 2 + ((subbands + blocks * bitpool) + 7) / 8;
+    default:
+      break;
+  }
+
+  g_return_val_if_reached (0);
+}
+
+static gsize
+gst_sbc_parse_header (const guint8 * data, guint * rate, guint * n_blocks,
+    GstSbcChannelMode * ch_mode, GstSbcAllocationMethod * alloc_method,
+    guint * n_subbands, guint * bitpool)
+{
+  static const guint16 sbc_rates[4] = { 16000, 32000, 44100, 48000 };
+  static const guint8 sbc_blocks[4] = { 4, 8, 12, 16 };
+  guint8 crc_data[2 + 1 + 8], crc_bits, i;
+
+  GST_MEMDUMP ("header", data, 8);
+
+  if (data[0] != SBC_SYNCBYTE)
+    return 0;
+
+  *rate = sbc_rates[(data[1] >> 6) & 0x03];
+  *n_blocks = sbc_blocks[(data[1] >> 4) & 0x03];
+  *ch_mode = (GstSbcChannelMode) ((data[1] >> 2) & 0x03);
+  *alloc_method = (data[1] >> 1) & 0x01;
+  *n_subbands = (data[1] & 0x01) ? 8 : 4;
+  *bitpool = data[2];
+
+  GST_TRACE ("rate=%u, n_blocks=%u, ch_mode=%u, alloc_method=%u, "
+      "n_subbands=%u, bitpool=%u", *rate, *n_blocks, *ch_mode, *alloc_method,
+      *n_subbands, *bitpool);
+
+  if (*bitpool < 2)
+    return 0;
+
+  /* check CRC */
+  crc_data[0] = data[1];
+  crc_data[1] = data[2];
+  crc_bits = 16;
+
+  /* joint flags and RFA */
+  if (*ch_mode == GST_SBC_CHANNEL_MODE_JOINT_STEREO)
+    crc_bits += *n_subbands;
+
+  /* scale factors */
+  if (*ch_mode == GST_SBC_CHANNEL_MODE_MONO)
+    crc_bits += *n_subbands * 1 * 4;
+  else
+    crc_bits += *n_subbands * 2 * 4;
+
+  for (i = 16; i < crc_bits; i += 8) {
+    crc_data[i / 8] = data[1 + (i / 8) + 1];
+  }
+
+  if (i > crc_bits) {
+    crc_data[(i / 8) - 1] &= 0xF0;
+  }
+
+  GST_MEMDUMP ("crc bytes", crc_data, GST_ROUND_UP_8 (crc_bits) / 8);
+  if (gst_sbc_calculate_crc8 (crc_data, crc_bits) != data[3]) {
+    GST_LOG ("header CRC check failed, bits=%u, got 0x%02x, expected 0x%02x",
+        crc_bits, gst_sbc_calculate_crc8 (crc_data, crc_bits), data[3]);
+    return 0;
+  }
+
+  return gst_sbc_calc_framelen (*n_subbands, *ch_mode, *n_blocks, *bitpool);
+}
+
+static GstFlowReturn
+gst_sbc_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
+{
+  GstSbcParse *sbcparse = GST_SBC_PARSE (parse);
+
+  if (!sbcparse->sent_codec_tag) {
+    GstTagList *taglist;
+    GstCaps *caps;
+
+    /* codec tag */
+    caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
+    if (G_UNLIKELY (caps == NULL)) {
+      if (GST_PAD_IS_FLUSHING (GST_BASE_PARSE_SRC_PAD (parse))) {
+        GST_INFO_OBJECT (parse, "Src pad is flushing");
+        return GST_FLOW_FLUSHING;
+      } else {
+        GST_INFO_OBJECT (parse, "Src pad is not negotiated!");
+        return GST_FLOW_NOT_NEGOTIATED;
+      }
+    }
+
+    taglist = gst_tag_list_new_empty ();
+    gst_pb_utils_add_codec_description_to_tag_list (taglist,
+        GST_TAG_AUDIO_CODEC, caps);
+    gst_caps_unref (caps);
+
+    gst_base_parse_merge_tags (parse, taglist, GST_TAG_MERGE_REPLACE);
+    gst_tag_list_unref (taglist);
+
+    /* also signals the end of first-frame processing */
+    sbcparse->sent_codec_tag = TRUE;
+  }
+
+  return GST_FLOW_OK;
+}
diff --git a/gst/audioparsers/gstsbcparse.h b/gst/audioparsers/gstsbcparse.h
new file mode 100644
index 0000000..6d204bf
--- /dev/null
+++ b/gst/audioparsers/gstsbcparse.h
@@ -0,0 +1,76 @@
+/* GStreamer SBC audio parser
+ * Copyright (C) 2012 Collabora Ltd. <tim.muller@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_SBC_PARSE_H_INCLUDED__
+#define __GST_SBC_PARSE_H_INCLUDED__
+
+
+#include <gst/gst.h>
+#include <gst/base/gstbaseparse.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SBC_PARSE            (gst_sbc_parse_get_type())
+#define GST_SBC_PARSE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SBC_PARSE,GstSbcParse))
+#define GST_SBC_PARSE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SBC_PARSE,GstSbcParseClass))
+#define GST_SBC_PARSE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_SBC_PARSE,GstSbcParseClass))
+#define GST_IS_SBC_PARSE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SBC_PARSE))
+#define GST_IS_SBC_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SBC_PARSE))
+#define GST_SBC_PARSE_CAST(obj)       ((GstSbcParse *)(obj))
+
+typedef enum {
+  GST_SBC_CHANNEL_MODE_INVALID = -1,
+  GST_SBC_CHANNEL_MODE_MONO = 0,
+  GST_SBC_CHANNEL_MODE_DUAL = 1,
+  GST_SBC_CHANNEL_MODE_STEREO = 2,
+  GST_SBC_CHANNEL_MODE_JOINT_STEREO = 3
+} GstSbcChannelMode;
+
+typedef enum {
+  GST_SBC_ALLOCATION_METHOD_INVALID = -1,
+  GST_SBC_ALLOCATION_METHOD_LOUDNESS = 0,
+  GST_SBC_ALLOCATION_METHOD_SNR = 1
+} GstSbcAllocationMethod;
+
+typedef struct _GstSbcParse GstSbcParse;
+typedef struct _GstSbcParseClass GstSbcParseClass;
+
+struct _GstSbcParse {
+  GstBaseParse baseparse;
+
+  /* current output format */
+  GstSbcAllocationMethod  alloc_method;
+  GstSbcChannelMode       ch_mode;
+  gint                    rate;
+  gint                    n_blocks;
+  gint                    n_subbands;
+  gint                    bitpool;
+
+  gboolean                sent_codec_tag;
+};
+
+struct _GstSbcParseClass {
+  GstBaseParseClass baseparse_class;
+};
+
+GType gst_sbc_parse_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_SBC_PARSE_H_INCLUDED__ */
diff --git a/gst/audioparsers/gstwavpackparse.c b/gst/audioparsers/gstwavpackparse.c
new file mode 100644
index 0000000..3e1d19c
--- /dev/null
+++ b/gst/audioparsers/gstwavpackparse.c
@@ -0,0 +1,706 @@
+/* GStreamer Wavpack parser
+ * Copyright (C) 2012 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ * Copyright (C) 2012 Nokia Corporation. All rights reserved.
+ *   Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-wavpackparse
+ * @short_description: Wavpack parser
+ * @see_also: #GstAmrParse, #GstAACParse
+ *
+ * This is an Wavpack parser.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=abc.wavpack ! wavpackparse ! wavpackdec ! audioresample ! audioconvert ! autoaudiosink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstwavpackparse.h"
+
+#include <gst/base/base.h>
+#include <gst/pbutils/pbutils.h>
+#include <gst/audio/audio.h>
+
+GST_DEBUG_CATEGORY_STATIC (wavpack_parse_debug);
+#define GST_CAT_DEFAULT wavpack_parse_debug
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-wavpack, "
+        "depth = (int) [ 1, 32 ], "
+        "channels = (int) [ 1, 8 ], "
+        "rate = (int) [ 6000, 192000 ], " "framed = (boolean) TRUE; "
+        "audio/x-wavpack-correction, " "framed = (boolean) TRUE")
+    );
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-wavpack"));
+
+static void gst_wavpack_parse_finalize (GObject * object);
+
+static gboolean gst_wavpack_parse_start (GstBaseParse * parse);
+static gboolean gst_wavpack_parse_stop (GstBaseParse * parse);
+static GstFlowReturn gst_wavpack_parse_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize);
+static GstCaps *gst_wavpack_parse_get_sink_caps (GstBaseParse * parse,
+    GstCaps * filter);
+static GstFlowReturn gst_wavpack_parse_pre_push_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame);
+
+#define gst_wavpack_parse_parent_class parent_class
+G_DEFINE_TYPE (GstWavpackParse, gst_wavpack_parse, GST_TYPE_BASE_PARSE);
+
+static void
+gst_wavpack_parse_class_init (GstWavpackParseClass * klass)
+{
+  GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (wavpack_parse_debug, "wavpackparse", 0,
+      "Wavpack audio stream parser");
+
+  object_class->finalize = gst_wavpack_parse_finalize;
+
+  parse_class->start = GST_DEBUG_FUNCPTR (gst_wavpack_parse_start);
+  parse_class->stop = GST_DEBUG_FUNCPTR (gst_wavpack_parse_stop);
+  parse_class->handle_frame =
+      GST_DEBUG_FUNCPTR (gst_wavpack_parse_handle_frame);
+  parse_class->get_sink_caps =
+      GST_DEBUG_FUNCPTR (gst_wavpack_parse_get_sink_caps);
+  parse_class->pre_push_frame =
+      GST_DEBUG_FUNCPTR (gst_wavpack_parse_pre_push_frame);
+
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "Wavpack audio stream parser", "Codec/Parser/Audio",
+      "Wavpack parser", "Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>");
+}
+
+static void
+gst_wavpack_parse_reset (GstWavpackParse * wvparse)
+{
+  wvparse->channels = -1;
+  wvparse->channel_mask = 0;
+  wvparse->sample_rate = -1;
+  wvparse->width = -1;
+  wvparse->total_samples = 0;
+  wvparse->sent_codec_tag = FALSE;
+}
+
+static void
+gst_wavpack_parse_init (GstWavpackParse * wvparse)
+{
+  gst_wavpack_parse_reset (wvparse);
+  GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (wvparse));
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (wvparse));
+}
+
+static void
+gst_wavpack_parse_finalize (GObject * object)
+{
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_wavpack_parse_start (GstBaseParse * parse)
+{
+  GstWavpackParse *wvparse = GST_WAVPACK_PARSE (parse);
+
+  GST_DEBUG_OBJECT (parse, "starting");
+
+  gst_wavpack_parse_reset (wvparse);
+
+  /* need header at least */
+  gst_base_parse_set_min_frame_size (GST_BASE_PARSE (wvparse),
+      sizeof (WavpackHeader));
+
+  /* inform baseclass we can come up with ts, based on counters in packets */
+  gst_base_parse_set_has_timing_info (GST_BASE_PARSE_CAST (wvparse), TRUE);
+  gst_base_parse_set_syncable (GST_BASE_PARSE_CAST (wvparse), TRUE);
+
+  return TRUE;
+}
+
+static gboolean
+gst_wavpack_parse_stop (GstBaseParse * parse)
+{
+  GST_DEBUG_OBJECT (parse, "stopping");
+
+  return TRUE;
+}
+
+static gint
+gst_wavpack_get_default_channel_mask (gint nchannels)
+{
+  gint channel_mask = 0;
+
+  /* Set the default channel mask for the given number of channels.
+   * It's the same as for WAVE_FORMAT_EXTENDED:
+   * http://www.microsoft.com/whdc/device/audio/multichaud.mspx
+   */
+  switch (nchannels) {
+    case 11:
+      channel_mask |= 0x00400;
+      channel_mask |= 0x00200;
+    case 9:
+      channel_mask |= 0x00100;
+    case 8:
+      channel_mask |= 0x00080;
+      channel_mask |= 0x00040;
+    case 6:
+      channel_mask |= 0x00020;
+      channel_mask |= 0x00010;
+    case 4:
+      channel_mask |= 0x00008;
+    case 3:
+      channel_mask |= 0x00004;
+    case 2:
+      channel_mask |= 0x00002;
+      channel_mask |= 0x00001;
+      break;
+    case 1:
+      /* For mono use front center */
+      channel_mask |= 0x00004;
+      break;
+  }
+
+  return channel_mask;
+}
+
+static const struct
+{
+  const guint32 ms_mask;
+  const GstAudioChannelPosition gst_pos;
+} layout_mapping[] = {
+  {
+  0x00001, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT}, {
+  0x00002, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
+  0x00004, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, {
+  0x00008, GST_AUDIO_CHANNEL_POSITION_LFE1}, {
+  0x00010, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT}, {
+  0x00020, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
+  0x00040, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER}, {
+  0x00080, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, {
+  0x00100, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, {
+  0x00200, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT}, {
+  0x00400, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}, {
+  0x00800, GST_AUDIO_CHANNEL_POSITION_TOP_CENTER}, {
+  0x01000, GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT}, {
+  0x02000, GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER}, {
+  0x04000, GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT}, {
+  0x08000, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT}, {
+  0x10000, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER}, {
+  0x20000, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT}
+};
+
+#define MAX_CHANNEL_POSITIONS G_N_ELEMENTS (layout_mapping)
+
+static gboolean
+gst_wavpack_get_channel_positions (gint num_channels, gint layout,
+    GstAudioChannelPosition * pos)
+{
+  gint i, p;
+
+  if (num_channels == 1 && layout == 0x00004) {
+    pos[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
+    return TRUE;
+  }
+
+  p = 0;
+  for (i = 0; i < MAX_CHANNEL_POSITIONS; ++i) {
+    if ((layout & layout_mapping[i].ms_mask) != 0) {
+      if (p >= num_channels) {
+        GST_WARNING ("More bits set in the channel layout map than there "
+            "are channels! Broken file");
+        return FALSE;
+      }
+      if (layout_mapping[i].gst_pos == GST_AUDIO_CHANNEL_POSITION_INVALID) {
+        GST_WARNING ("Unsupported channel position (mask 0x%08x) in channel "
+            "layout map - ignoring those channels", layout_mapping[i].ms_mask);
+        /* what to do? just ignore it and let downstream deal with a channel
+         * layout that has INVALID positions in it for now ... */
+      }
+      pos[p] = layout_mapping[i].gst_pos;
+      ++p;
+    }
+  }
+
+  if (p != num_channels) {
+    GST_WARNING ("Only %d bits set in the channel layout map, but there are "
+        "supposed to be %d channels! Broken file", p, num_channels);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static const guint32 sample_rates[] = {
+  6000, 8000, 9600, 11025, 12000, 16000, 22050,
+  24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000
+};
+
+#define CHECK(call) { \
+  if (!call) \
+    goto read_failed; \
+}
+
+/* caller ensures properly sync'ed with enough data */
+static gboolean
+gst_wavpack_parse_frame_metadata (GstWavpackParse * parse, GstBuffer * buf,
+    gint skip, WavpackHeader * wph, WavpackInfo * wpi)
+{
+  GstByteReader br;
+  gint i;
+  GstMapInfo map;
+
+  g_return_val_if_fail (wph != NULL || wpi != NULL, FALSE);
+  g_return_val_if_fail (gst_buffer_get_size (buf) >=
+      skip + sizeof (WavpackHeader), FALSE);
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  gst_byte_reader_init (&br, map.data + skip, wph->ckSize + 8);
+  /* skip past header */
+  gst_byte_reader_skip_unchecked (&br, sizeof (WavpackHeader));
+
+  /* get some basics from header */
+  i = (wph->flags >> 23) & 0xF;
+  if (!wpi->rate)
+    wpi->rate = (i < G_N_ELEMENTS (sample_rates)) ? sample_rates[i] : 44100;
+  wpi->width = ((wph->flags & 0x3) + 1) * 8;
+  if (!wpi->channels)
+    wpi->channels = (wph->flags & 0x4) ? 1 : 2;
+  if (!wpi->channel_mask)
+    wpi->channel_mask = 5 - wpi->channels;
+
+  /* need to dig metadata blocks for some more */
+  while (gst_byte_reader_get_remaining (&br)) {
+    gint size = 0;
+    guint16 size2 = 0;
+    guint8 c, id;
+    const guint8 *data;
+    GstByteReader mbr;
+
+    CHECK (gst_byte_reader_get_uint8 (&br, &id));
+    CHECK (gst_byte_reader_get_uint8 (&br, &c));
+    if (id & ID_LARGE)
+      CHECK (gst_byte_reader_get_uint16_le (&br, &size2));
+    size = size2;
+    size <<= 8;
+    size += c;
+    size <<= 1;
+    if (id & ID_ODD_SIZE)
+      size--;
+
+    CHECK (gst_byte_reader_get_data (&br, size + (size & 1), &data));
+    gst_byte_reader_init (&mbr, data, size);
+
+    switch (id) {
+      case ID_WVC_BITSTREAM:
+        GST_LOG_OBJECT (parse, "correction bitstream");
+        wpi->correction = TRUE;
+        break;
+      case ID_WV_BITSTREAM:
+      case ID_WVX_BITSTREAM:
+        break;
+      case ID_SAMPLE_RATE:
+        if (size == 3) {
+          CHECK (gst_byte_reader_get_uint24_le (&mbr, &wpi->rate));
+          GST_LOG_OBJECT (parse, "updated with custom rate %d", wpi->rate);
+        } else {
+          GST_DEBUG_OBJECT (parse, "unexpected size for SAMPLE_RATE metadata");
+        }
+        break;
+      case ID_CHANNEL_INFO:
+      {
+        guint16 channels;
+        guint32 mask = 0;
+
+        if (size == 6) {
+          CHECK (gst_byte_reader_get_uint16_le (&mbr, &channels));
+          channels = channels & 0xFFF;
+          CHECK (gst_byte_reader_get_uint24_le (&mbr, &mask));
+        } else if (size) {
+          CHECK (gst_byte_reader_get_uint8 (&mbr, &c));
+          channels = c;
+          while (gst_byte_reader_get_uint8 (&mbr, &c))
+            mask |= (((guint32) c) << 8);
+        } else {
+          GST_DEBUG_OBJECT (parse, "unexpected size for CHANNEL_INFO metadata");
+          break;
+        }
+        wpi->channels = channels;
+        wpi->channel_mask = mask;
+        break;
+      }
+      default:
+        GST_LOG_OBJECT (parse, "unparsed ID 0x%x", id);
+        break;
+    }
+  }
+
+  gst_buffer_unmap (buf, &map);
+
+  return TRUE;
+
+  /* ERRORS */
+read_failed:
+  {
+    gst_buffer_unmap (buf, &map);
+    GST_DEBUG_OBJECT (parse, "short read while parsing metadata");
+    /* let's look the other way anyway */
+    return TRUE;
+  }
+}
+
+/* caller ensures properly sync'ed with enough data */
+static gboolean
+gst_wavpack_parse_frame_header (GstWavpackParse * parse, GstBuffer * buf,
+    gint skip, WavpackHeader * _wph)
+{
+  GstByteReader br;
+  WavpackHeader wph = { {0,}, 0, };
+  GstMapInfo map;
+  gboolean hdl = TRUE;
+
+  g_return_val_if_fail (gst_buffer_get_size (buf) >=
+      skip + sizeof (WavpackHeader), FALSE);
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  gst_byte_reader_init (&br, map.data, map.size);
+
+  /* marker */
+  gst_byte_reader_skip_unchecked (&br, skip + 4);
+
+  /* read */
+  hdl &= gst_byte_reader_get_uint32_le (&br, &wph.ckSize);
+  hdl &= gst_byte_reader_get_uint16_le (&br, &wph.version);
+  hdl &= gst_byte_reader_get_uint8 (&br, &wph.track_no);
+  hdl &= gst_byte_reader_get_uint8 (&br, &wph.index_no);
+  hdl &= gst_byte_reader_get_uint32_le (&br, &wph.total_samples);
+  hdl &= gst_byte_reader_get_uint32_le (&br, &wph.block_index);
+  hdl &= gst_byte_reader_get_uint32_le (&br, &wph.block_samples);
+  hdl &= gst_byte_reader_get_uint32_le (&br, &wph.flags);
+  hdl &= gst_byte_reader_get_uint32_le (&br, &wph.crc);
+
+  if (!hdl)
+    GST_WARNING_OBJECT (parse, "Error reading header");
+
+  /* dump */
+  GST_LOG_OBJECT (parse, "size %d", wph.ckSize);
+  GST_LOG_OBJECT (parse, "version 0x%x", wph.version);
+  GST_LOG_OBJECT (parse, "total samples %d", wph.total_samples);
+  GST_LOG_OBJECT (parse, "block index %d", wph.block_index);
+  GST_LOG_OBJECT (parse, "block samples %d", wph.block_samples);
+  GST_LOG_OBJECT (parse, "flags 0x%x", wph.flags);
+  GST_LOG_OBJECT (parse, "crc 0x%x", wph.flags);
+
+  if (!parse->total_samples && wph.block_index == 0 && wph.total_samples != -1) {
+    GST_DEBUG_OBJECT (parse, "determined duration of %u samples",
+        wph.total_samples);
+    parse->total_samples = wph.total_samples;
+  }
+
+  if (_wph)
+    *_wph = wph;
+
+  gst_buffer_unmap (buf, &map);
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_wavpack_parse_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize)
+{
+  GstWavpackParse *wvparse = GST_WAVPACK_PARSE (parse);
+  GstBuffer *buf = frame->buffer;
+  GstByteReader reader;
+  gint off;
+  guint rate, chans, width, mask;
+  gboolean lost_sync, draining, final;
+  guint frmsize = 0;
+  WavpackHeader wph;
+  WavpackInfo wpi = { 0, };
+  GstMapInfo map;
+
+  if (G_UNLIKELY (gst_buffer_get_size (buf) < sizeof (WavpackHeader)))
+    return FALSE;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  gst_byte_reader_init (&reader, map.data, map.size);
+
+  /* scan for 'wvpk' marker */
+  off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff, 0x7776706b,
+      0, map.size);
+
+  GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off);
+
+  /* didn't find anything that looks like a sync word, skip */
+  if (off < 0) {
+    *skipsize = map.size - 3;
+    goto skip;
+  }
+
+  /* possible frame header, but not at offset 0? skip bytes before sync */
+  if (off > 0) {
+    *skipsize = off;
+    goto skip;
+  }
+
+  /* make sure the values in the frame header look sane */
+  gst_wavpack_parse_frame_header (wvparse, buf, 0, &wph);
+  frmsize = wph.ckSize + 8;
+
+  /* need the entire frame for parsing */
+  if (gst_byte_reader_get_remaining (&reader) < frmsize)
+    goto more;
+
+  /* got a frame, now we can dig for some more metadata */
+  GST_LOG_OBJECT (parse, "got frame");
+  gst_wavpack_parse_frame_metadata (wvparse, buf, 0, &wph, &wpi);
+
+  lost_sync = GST_BASE_PARSE_LOST_SYNC (parse);
+  draining = GST_BASE_PARSE_DRAINING (parse);
+
+  while (!(final = (wph.flags & FLAG_FINAL_BLOCK)) || (lost_sync && !draining)) {
+    guint32 word = 0;
+
+    GST_LOG_OBJECT (wvparse, "checking next frame syncword; "
+        "lost_sync: %d, draining: %d, final: %d", lost_sync, draining, final);
+
+    if (!gst_byte_reader_skip (&reader, wph.ckSize + 8) ||
+        !gst_byte_reader_peek_uint32_be (&reader, &word)) {
+      GST_DEBUG_OBJECT (wvparse, "... but not sufficient data");
+      frmsize += 4;
+      goto more;
+    } else {
+      if (word != 0x7776706b) {
+        GST_DEBUG_OBJECT (wvparse, "0x%x not OK", word);
+        *skipsize = off + 2;
+        goto skip;
+      }
+      /* need to parse each frame/block for metadata if several ones */
+      if (!final) {
+        gint av;
+
+        GST_LOG_OBJECT (wvparse, "checking frame at offset %d (0x%x)",
+            frmsize, frmsize);
+        av = gst_byte_reader_get_remaining (&reader);
+        if (av < sizeof (WavpackHeader)) {
+          frmsize += sizeof (WavpackHeader);
+          goto more;
+        }
+        gst_wavpack_parse_frame_header (wvparse, buf, frmsize, &wph);
+        off = frmsize;
+        frmsize += wph.ckSize + 8;
+        if (av < wph.ckSize + 8)
+          goto more;
+        gst_wavpack_parse_frame_metadata (wvparse, buf, off, &wph, &wpi);
+        /* could also check for matching block_index and block_samples ?? */
+      }
+    }
+
+    /* resynced if we make it here */
+    lost_sync = FALSE;
+  }
+
+  rate = wpi.rate;
+  width = wpi.width;
+  chans = wpi.channels;
+  mask = wpi.channel_mask;
+
+  GST_LOG_OBJECT (parse, "rate: %u, width: %u, chans: %u", rate, width, chans);
+
+  GST_BUFFER_PTS (buf) =
+      gst_util_uint64_scale_int (wph.block_index, GST_SECOND, rate);
+  GST_BUFFER_DTS (buf) = GST_BUFFER_PTS (buf);
+  GST_BUFFER_DURATION (buf) =
+      gst_util_uint64_scale_int (wph.block_index + wph.block_samples,
+      GST_SECOND, rate) - GST_BUFFER_PTS (buf);
+
+  if (G_UNLIKELY (wvparse->sample_rate != rate || wvparse->channels != chans
+          || wvparse->width != width || wvparse->channel_mask != mask)) {
+    GstCaps *caps;
+
+    if (wpi.correction) {
+      caps = gst_caps_new_simple ("audio/x-wavpack-correction",
+          "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+    } else {
+      caps = gst_caps_new_simple ("audio/x-wavpack",
+          "channels", G_TYPE_INT, chans,
+          "rate", G_TYPE_INT, rate,
+          "depth", G_TYPE_INT, width, "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+
+      if (!mask)
+        mask = gst_wavpack_get_default_channel_mask (wvparse->channels);
+      if (mask != 0) {
+        GstAudioChannelPosition pos[64] =
+            { GST_AUDIO_CHANNEL_POSITION_INVALID, };
+        guint64 gmask;
+
+        if (!gst_wavpack_get_channel_positions (chans, mask, pos)) {
+          GST_WARNING_OBJECT (wvparse, "Failed to determine channel layout");
+        } else {
+          gst_audio_channel_positions_to_mask (pos, chans, FALSE, &gmask);
+          if (gmask)
+            gst_caps_set_simple (caps,
+                "channel-mask", GST_TYPE_BITMASK, gmask, NULL);
+        }
+      }
+    }
+
+    gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
+    gst_caps_unref (caps);
+
+    wvparse->sample_rate = rate;
+    wvparse->channels = chans;
+    wvparse->width = width;
+    wvparse->channel_mask = mask;
+
+    if (wvparse->total_samples) {
+      GST_DEBUG_OBJECT (wvparse, "setting duration");
+      gst_base_parse_set_duration (GST_BASE_PARSE (wvparse),
+          GST_FORMAT_TIME, gst_util_uint64_scale_int (wvparse->total_samples,
+              GST_SECOND, wvparse->sample_rate), 0);
+    }
+  }
+
+  /* return to normal size */
+  gst_base_parse_set_min_frame_size (parse, sizeof (WavpackHeader));
+  gst_buffer_unmap (buf, &map);
+
+  return gst_base_parse_finish_frame (parse, frame, frmsize);
+
+skip:
+  gst_buffer_unmap (buf, &map);
+  GST_LOG_OBJECT (wvparse, "skipping %d", *skipsize);
+  return GST_FLOW_OK;
+
+more:
+  gst_buffer_unmap (buf, &map);
+  GST_LOG_OBJECT (wvparse, "need at least %u", frmsize);
+  gst_base_parse_set_min_frame_size (parse, frmsize);
+  *skipsize = 0;
+  return GST_FLOW_OK;
+}
+
+static void
+remove_fields (GstCaps * caps)
+{
+  guint i, n;
+
+  n = gst_caps_get_size (caps);
+  for (i = 0; i < n; i++) {
+    GstStructure *s = gst_caps_get_structure (caps, i);
+
+    gst_structure_remove_field (s, "framed");
+  }
+}
+
+static GstCaps *
+gst_wavpack_parse_get_sink_caps (GstBaseParse * parse, GstCaps * filter)
+{
+  GstCaps *peercaps, *templ;
+  GstCaps *res;
+
+  templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
+  if (filter) {
+    GstCaps *fcopy = gst_caps_copy (filter);
+    /* Remove the fields we convert */
+    remove_fields (fcopy);
+    peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
+    gst_caps_unref (fcopy);
+  } else
+    peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), NULL);
+
+  if (peercaps) {
+    /* Remove the framed field */
+    peercaps = gst_caps_make_writable (peercaps);
+    remove_fields (peercaps);
+
+    res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (peercaps);
+    gst_caps_unref (templ);
+  } else {
+    res = templ;
+  }
+
+  if (filter) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (res);
+    res = intersection;
+  }
+
+  return res;
+}
+
+static GstFlowReturn
+gst_wavpack_parse_pre_push_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame)
+{
+  GstWavpackParse *wavpackparse = GST_WAVPACK_PARSE (parse);
+
+  if (!wavpackparse->sent_codec_tag) {
+    GstTagList *taglist;
+    GstCaps *caps;
+
+    /* codec tag */
+    caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
+    if (G_UNLIKELY (caps == NULL)) {
+      if (GST_PAD_IS_FLUSHING (GST_BASE_PARSE_SRC_PAD (parse))) {
+        GST_INFO_OBJECT (parse, "Src pad is flushing");
+        return GST_FLOW_FLUSHING;
+      } else {
+        GST_INFO_OBJECT (parse, "Src pad is not negotiated!");
+        return GST_FLOW_NOT_NEGOTIATED;
+      }
+    }
+
+    taglist = gst_tag_list_new_empty ();
+    gst_pb_utils_add_codec_description_to_tag_list (taglist,
+        GST_TAG_AUDIO_CODEC, caps);
+    gst_caps_unref (caps);
+
+    gst_base_parse_merge_tags (parse, taglist, GST_TAG_MERGE_REPLACE);
+    gst_tag_list_unref (taglist);
+
+    /* also signals the end of first-frame processing */
+    wavpackparse->sent_codec_tag = TRUE;
+  }
+
+  return GST_FLOW_OK;
+}
diff --git a/gst/audioparsers/gstwavpackparse.h b/gst/audioparsers/gstwavpackparse.h
new file mode 100644
index 0000000..30325aa
--- /dev/null
+++ b/gst/audioparsers/gstwavpackparse.h
@@ -0,0 +1,133 @@
+/* GStreamer Wavpack parser
+ * Copyright (C) 2012 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ * Copyright (C) 2012 Nokia Corporation. All rights reserved.
+ *   Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_WAVPACK_PARSE_H__
+#define __GST_WAVPACK_PARSE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbaseparse.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_WAVPACK_PARSE \
+  (gst_wavpack_parse_get_type())
+#define GST_WAVPACK_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_WAVPACK_PARSE, GstWavpackParse))
+#define GST_WAVPACK_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_WAVPACK_PARSE, GstWavpackParseClass))
+#define GST_IS_WAVPACK_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_WAVPACK_PARSE))
+#define GST_IS_WAVPACK_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_WAVPACK_PARSE))
+
+
+#define ID_UNIQUE               0x3f
+#define ID_OPTIONAL_DATA        0x20
+#define ID_ODD_SIZE             0x40
+#define ID_LARGE                0x80
+
+#define ID_DUMMY                0x0
+#define ID_ENCODER_INFO         0x1
+#define ID_DECORR_TERMS         0x2
+#define ID_DECORR_WEIGHTS       0x3
+#define ID_DECORR_SAMPLES       0x4
+#define ID_ENTROPY_VARS         0x5
+#define ID_HYBRID_PROFILE       0x6
+#define ID_SHAPING_WEIGHTS      0x7
+#define ID_FLOAT_INFO           0x8
+#define ID_INT32_INFO           0x9
+#define ID_WV_BITSTREAM         0xa
+#define ID_WVC_BITSTREAM        0xb
+#define ID_WVX_BITSTREAM        0xc
+#define ID_CHANNEL_INFO         0xd
+
+#define ID_RIFF_HEADER          (ID_OPTIONAL_DATA | 0x1)
+#define ID_RIFF_TRAILER         (ID_OPTIONAL_DATA | 0x2)
+#define ID_REPLAY_GAIN          (ID_OPTIONAL_DATA | 0x3)
+#define ID_CUESHEET             (ID_OPTIONAL_DATA | 0x4)
+#define ID_CONFIG_BLOCK         (ID_OPTIONAL_DATA | 0x5)
+#define ID_MD5_CHECKSUM         (ID_OPTIONAL_DATA | 0x6)
+#define ID_SAMPLE_RATE          (ID_OPTIONAL_DATA | 0x7)
+
+#define FLAG_FINAL_BLOCK        (1 << 12)
+
+typedef struct {
+  char ckID [4];             /* "wvpk" */
+  guint32 ckSize;            /* size of entire block (minus 8, of course) */
+  guint16 version;           /* 0x402 to 0x410 are currently valid for decode */
+  guchar track_no;           /* track number (0 if not used, like now) */
+  guchar index_no;           /* track sub-index (0 if not used, like now) */
+  guint32 total_samples;     /* total samples for entire file, but this is
+                              * only valid if block_index == 0 and a value of
+                              * -1 indicates unknown length */
+  guint32 block_index;       /* index of first sample in block relative to
+                              * beginning of file (normally this would start
+                              * at 0 for the first block) */
+  guint32 block_samples;     /* number of samples in this block (0 = no audio) */
+  guint32 flags;             /* various flags for id and decoding */
+  guint32 crc;               /* crc for actual decoded data */
+} WavpackHeader;
+
+typedef struct {
+  gboolean correction;
+  guint rate;
+  guint width;
+  guint channels;
+  guint channel_mask;
+} WavpackInfo;
+
+typedef struct _GstWavpackParse GstWavpackParse;
+typedef struct _GstWavpackParseClass GstWavpackParseClass;
+
+/**
+ * GstWavpackParse:
+ *
+ * The opaque GstWavpackParse object
+ */
+struct _GstWavpackParse {
+  GstBaseParse baseparse;
+
+  /*< private >*/
+  gint          sample_rate;
+  gint          channels;
+  gint          width;
+  gint          channel_mask;
+
+  guint         total_samples;
+
+  gboolean      sent_codec_tag;
+};
+
+/**
+ * GstWavpackParseClass:
+ * @parent_class: Element parent class.
+ *
+ * The opaque GstWavpackParseClass data structure.
+ */
+struct _GstWavpackParseClass {
+  GstBaseParseClass baseparse_class;
+};
+
+GType gst_wavpack_parse_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_WAVPACK_PARSE_H__ */
diff --git a/gst/audioparsers/meson.build b/gst/audioparsers/meson.build
new file mode 100644
index 0000000..9a5bf87
--- /dev/null
+++ b/gst/audioparsers/meson.build
@@ -0,0 +1,21 @@
+audioparsers_src = [
+  'gstaacparse.c',
+  'gstamrparse.c',
+  'gstac3parse.c',
+  'gstdcaparse.c',
+  'gstflacparse.c',
+  'gstmpegaudioparse.c',
+  'gstsbcparse.c',
+  'gstwavpackparse.c',
+  'plugin.c',
+]
+
+gstaudioparsers = library('gstaudioparsers',
+  audioparsers_src,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gst_dep, gstbase_dep, gstpbutils_dep,
+                  gstaudio_dep, gsttag_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/audioparsers/plugin.c b/gst/audioparsers/plugin.c
new file mode 100644
index 0000000..8cbfe60
--- /dev/null
+++ b/gst/audioparsers/plugin.c
@@ -0,0 +1,63 @@
+/* GStreamer audio parsers
+ * Copyright (C) 2009 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstaacparse.h"
+#include "gstamrparse.h"
+#include "gstac3parse.h"
+#include "gstdcaparse.h"
+#include "gstflacparse.h"
+#include "gstmpegaudioparse.h"
+#include "gstsbcparse.h"
+#include "gstwavpackparse.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  gboolean ret;
+
+  ret = gst_element_register (plugin, "aacparse",
+      GST_RANK_PRIMARY + 1, GST_TYPE_AAC_PARSE);
+  ret &= gst_element_register (plugin, "amrparse",
+      GST_RANK_PRIMARY + 1, GST_TYPE_AMR_PARSE);
+  ret &= gst_element_register (plugin, "ac3parse",
+      GST_RANK_PRIMARY + 1, GST_TYPE_AC3_PARSE);
+  ret &= gst_element_register (plugin, "dcaparse",
+      GST_RANK_PRIMARY + 1, GST_TYPE_DCA_PARSE);
+  ret &= gst_element_register (plugin, "flacparse",
+      GST_RANK_PRIMARY + 1, GST_TYPE_FLAC_PARSE);
+  ret &= gst_element_register (plugin, "mpegaudioparse",
+      GST_RANK_PRIMARY + 2, GST_TYPE_MPEG_AUDIO_PARSE);
+  ret &= gst_element_register (plugin, "sbcparse",
+      GST_RANK_PRIMARY + 1, GST_TYPE_SBC_PARSE);
+  ret &= gst_element_register (plugin, "wavpackparse",
+      GST_RANK_PRIMARY + 1, GST_TYPE_WAVPACK_PARSE);
+
+  return ret;
+}
+
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    audioparsers,
+    "Parsers for various audio formats",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/auparse/.gitignore b/gst/auparse/.gitignore
new file mode 100644
index 0000000..08f5ed3
--- /dev/null
+++ b/gst/auparse/.gitignore
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
diff --git a/gst/auparse/Makefile.am b/gst/auparse/Makefile.am
new file mode 100644
index 0000000..013d0f2
--- /dev/null
+++ b/gst/auparse/Makefile.am
@@ -0,0 +1,8 @@
+plugin_LTLIBRARIES = libgstauparse.la
+
+libgstauparse_la_SOURCES = gstauparse.c
+libgstauparse_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstauparse_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(GST_LIBS) $(GST_BASE_LIBS)
+libgstauparse_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstauparse.h
diff --git a/gst/auparse/gstauparse.c b/gst/auparse/gstauparse.c
new file mode 100644
index 0000000..b814ad8
--- /dev/null
+++ b/gst/auparse/gstauparse.c
@@ -0,0 +1,811 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-auparse
+ *
+ * Parses .au files mostly originating from sun os based computers.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "gstauparse.h"
+#include <gst/audio/audio.h>
+
+GST_DEBUG_CATEGORY_STATIC (auparse_debug);
+#define GST_CAT_DEFAULT (auparse_debug)
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-au")
+    );
+
+#define GST_AU_PARSE_RAW_PAD_TEMPLATE_CAPS \
+    "audio/x-raw, "                         \
+    "format= (string) { S8, S16LE, S16BE, S24LE, S24BE, "  \
+                       "S32LE, S32BE, F32LE, F32BE, "        \
+                       "F64LE, F64BE }, " \
+    "rate = (int) [ 8000, 192000 ], "       \
+    "channels = (int) 1, "                  \
+    "layout = (string) interleaved;"        \
+    "audio/x-raw, "                         \
+    "format= (string) { S8, S16LE, S16BE, S24LE, S24BE, "  \
+                       "S32LE, S32BE, F32LE, F32BE, "        \
+                       "F64LE, F64BE }, " \
+    "rate = (int) [ 8000, 192000 ], "       \
+    "channels = (int) 2, "                  \
+    "channel-mask = (bitmask) 0x3,"         \
+    "layout = (string) interleaved"
+
+#define GST_AU_PARSE_ALAW_PAD_TEMPLATE_CAPS \
+    "audio/x-alaw, "                        \
+    "rate = (int) [ 8000, 192000 ], "       \
+    "channels = (int) [ 1, 2 ]"
+
+#define GST_AU_PARSE_MULAW_PAD_TEMPLATE_CAPS \
+    "audio/x-mulaw, "                        \
+    "rate = (int) [ 8000, 192000 ], "        \
+    "channels = (int) [ 1, 2 ]"
+
+/* Nothing to decode those ADPCM streams for now */
+#define GST_AU_PARSE_ADPCM_PAD_TEMPLATE_CAPS \
+    "audio/x-adpcm, "                        \
+    "layout = (string) { g721, g722, g723_3, g723_5 }"
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_AU_PARSE_RAW_PAD_TEMPLATE_CAPS "; "
+        GST_AU_PARSE_ALAW_PAD_TEMPLATE_CAPS ";"
+        GST_AU_PARSE_MULAW_PAD_TEMPLATE_CAPS ";"
+        GST_AU_PARSE_ADPCM_PAD_TEMPLATE_CAPS));
+
+
+static void gst_au_parse_dispose (GObject * object);
+static GstFlowReturn gst_au_parse_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buf);
+static GstStateChangeReturn gst_au_parse_change_state (GstElement * element,
+    GstStateChange transition);
+static void gst_au_parse_reset (GstAuParse * auparse);
+static gboolean gst_au_parse_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+static gboolean gst_au_parse_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static gboolean gst_au_parse_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static gboolean gst_au_parse_src_convert (GstAuParse * auparse,
+    GstFormat src_format, gint64 srcval, GstFormat dest_format,
+    gint64 * destval);
+
+#define gst_au_parse_parent_class parent_class
+G_DEFINE_TYPE (GstAuParse, gst_au_parse, GST_TYPE_ELEMENT);
+
+static void
+gst_au_parse_class_init (GstAuParseClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  GST_DEBUG_CATEGORY_INIT (auparse_debug, "auparse", 0, ".au parser");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->dispose = gst_au_parse_dispose;
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_au_parse_change_state);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class, &src_template);
+  gst_element_class_set_static_metadata (gstelement_class,
+      "AU audio demuxer",
+      "Codec/Demuxer/Audio",
+      "Parse an .au file into raw audio",
+      "Erik Walthinsen <omega@cse.ogi.edu>");
+}
+
+static void
+gst_au_parse_init (GstAuParse * auparse)
+{
+  auparse->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
+  gst_pad_set_chain_function (auparse->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_au_parse_chain));
+  gst_pad_set_event_function (auparse->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_au_parse_sink_event));
+  gst_element_add_pad (GST_ELEMENT (auparse), auparse->sinkpad);
+
+  auparse->srcpad = gst_pad_new_from_static_template (&src_template, "src");
+  gst_pad_set_query_function (auparse->srcpad,
+      GST_DEBUG_FUNCPTR (gst_au_parse_src_query));
+  gst_pad_set_event_function (auparse->srcpad,
+      GST_DEBUG_FUNCPTR (gst_au_parse_src_event));
+  gst_pad_use_fixed_caps (auparse->srcpad);
+  gst_element_add_pad (GST_ELEMENT (auparse), auparse->srcpad);
+
+  auparse->adapter = gst_adapter_new ();
+  gst_au_parse_reset (auparse);
+}
+
+static void
+gst_au_parse_dispose (GObject * object)
+{
+  GstAuParse *au = GST_AU_PARSE (object);
+
+  if (au->adapter != NULL) {
+    g_object_unref (au->adapter);
+    au->adapter = NULL;
+  }
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_au_parse_reset (GstAuParse * auparse)
+{
+  auparse->offset = 0;
+  auparse->buffer_offset = 0;
+  auparse->encoding = 0;
+  auparse->samplerate = 0;
+  auparse->channels = 0;
+
+  gst_adapter_clear (auparse->adapter);
+
+  gst_caps_replace (&auparse->src_caps, NULL);
+
+  /* gst_segment_init (&auparse->segment, GST_FORMAT_TIME); */
+}
+
+static void
+gst_au_parse_negotiate_srcpad (GstAuParse * auparse, GstCaps * new_caps)
+{
+  if (auparse->src_caps && gst_caps_is_equal (new_caps, auparse->src_caps)) {
+    GST_LOG_OBJECT (auparse, "same caps, nothing to do");
+    return;
+  }
+
+  gst_caps_replace (&auparse->src_caps, new_caps);
+  GST_DEBUG_OBJECT (auparse, "Changing src pad caps to %" GST_PTR_FORMAT,
+      auparse->src_caps);
+  gst_pad_set_caps (auparse->srcpad, auparse->src_caps);
+
+  return;
+}
+
+static GstFlowReturn
+gst_au_parse_parse_header (GstAuParse * auparse)
+{
+  GstCaps *tempcaps;
+  guint32 size;
+  guint8 *head;
+  gchar layout[7] = { 0, };
+  GstAudioFormat format = GST_AUDIO_FORMAT_UNKNOWN;
+  gint law = 0;
+  guint endianness;
+
+  head = (guint8 *) gst_adapter_map (auparse->adapter, 24);
+  g_assert (head != NULL);
+
+  GST_DEBUG_OBJECT (auparse, "[%c%c%c%c]", head[0], head[1], head[2], head[3]);
+
+  switch (GST_READ_UINT32_BE (head)) {
+      /* normal format is big endian (au is a Sparc format) */
+    case 0x2e736e64:{          /* ".snd" */
+      endianness = G_BIG_ENDIAN;
+      break;
+    }
+      /* and of course, someone had to invent a little endian
+       * version.  Used by DEC systems. */
+    case 0x646e732e:           /* dns.                          */
+    case 0x0064732e:{          /* other source say it is "dns." */
+      endianness = G_LITTLE_ENDIAN;
+      break;
+    }
+    default:{
+      goto unknown_header;
+    }
+  }
+
+  auparse->offset = GST_READ_UINT32_BE (head + 4);
+  /* 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);
+  auparse->channels = GST_READ_UINT32_BE (head + 20);
+
+  if (auparse->samplerate < 8000 || auparse->samplerate > 192000)
+    goto unsupported_sample_rate;
+
+  if (auparse->channels < 1 || auparse->channels > 2)
+    goto unsupported_number_of_channels;
+
+  GST_DEBUG_OBJECT (auparse, "offset %" G_GINT64_FORMAT ", size %u, "
+      "encoding %u, frequency %u, channels %u", auparse->offset, size,
+      auparse->encoding, auparse->samplerate, auparse->channels);
+
+  /* Docs:
+   * http://www.opengroup.org/public/pubs/external/auformat.html
+   * http://astronomy.swin.edu.au/~pbourke/dataformats/au/
+   * Solaris headers : /usr/include/audio/au.h
+   * libsndfile : src/au.c
+   *
+   * Samples :
+   * http://www.tsp.ece.mcgill.ca/MMSP/Documents/AudioFormats/AU/Samples.html
+   */
+
+  switch (auparse->encoding) {
+    case 1:                    /* 8-bit ISDN mu-law G.711 */
+      law = 1;
+      break;
+    case 27:                   /* 8-bit ISDN  A-law G.711 */
+      law = 2;
+      break;
+
+    case 2:                    /*  8-bit linear PCM, FIXME signed? */
+      format = GST_AUDIO_FORMAT_S8;
+      auparse->sample_size = auparse->channels;
+      break;
+    case 3:                    /* 16-bit linear PCM */
+      if (endianness == G_LITTLE_ENDIAN)
+        format = GST_AUDIO_FORMAT_S16LE;
+      else
+        format = GST_AUDIO_FORMAT_S16BE;
+      auparse->sample_size = auparse->channels * 2;
+      break;
+    case 4:                    /* 24-bit linear PCM */
+      if (endianness == G_LITTLE_ENDIAN)
+        format = GST_AUDIO_FORMAT_S24LE;
+      else
+        format = GST_AUDIO_FORMAT_S24BE;
+      auparse->sample_size = auparse->channels * 3;
+      break;
+    case 5:                    /* 32-bit linear PCM */
+      if (endianness == G_LITTLE_ENDIAN)
+        format = GST_AUDIO_FORMAT_S32LE;
+      else
+        format = GST_AUDIO_FORMAT_S32BE;
+      auparse->sample_size = auparse->channels * 4;
+      break;
+
+    case 6:                    /* 32-bit IEEE floating point */
+      if (endianness == G_LITTLE_ENDIAN)
+        format = GST_AUDIO_FORMAT_F32LE;
+      else
+        format = GST_AUDIO_FORMAT_F32BE;
+      auparse->sample_size = auparse->channels * 4;
+      break;
+    case 7:                    /* 64-bit IEEE floating point */
+      if (endianness == G_LITTLE_ENDIAN)
+        format = GST_AUDIO_FORMAT_F64LE;
+      else
+        format = GST_AUDIO_FORMAT_F64BE;
+      auparse->sample_size = auparse->channels * 8;
+      break;
+
+    case 23:                   /* 4-bit CCITT G.721   ADPCM 32kbps -> modplug/libsndfile (compressed 8-bit mu-law) */
+      strcpy (layout, "g721");
+      break;
+    case 24:                   /* 8-bit CCITT G.722   ADPCM        -> rtp */
+      strcpy (layout, "g722");
+      break;
+    case 25:                   /* 3-bit CCITT G.723.3 ADPCM 24kbps -> rtp/xine/modplug/libsndfile */
+      strcpy (layout, "g723_3");
+      break;
+    case 26:                   /* 5-bit CCITT G.723.5 ADPCM 40kbps -> rtp/xine/modplug/libsndfile */
+      strcpy (layout, "g723_5");
+      break;
+
+    case 8:                    /* Fragmented sample data */
+    case 9:                    /* AU_ENCODING_NESTED */
+
+    case 10:                   /* DSP program */
+    case 11:                   /* DSP  8-bit fixed point */
+    case 12:                   /* DSP 16-bit fixed point */
+    case 13:                   /* DSP 24-bit fixed point */
+    case 14:                   /* DSP 32-bit fixed point */
+
+    case 16:                   /* AU_ENCODING_DISPLAY : non-audio display data */
+    case 17:                   /* AU_ENCODING_MULAW_SQUELCH */
+
+    case 18:                   /* 16-bit linear with emphasis */
+    case 19:                   /* 16-bit linear compressed (NeXT) */
+    case 20:                   /* 16-bit linear with emphasis and compression */
+
+    case 21:                   /* Music kit DSP commands */
+    case 22:                   /* Music kit DSP commands samples */
+
+    default:
+      goto unknown_format;
+  }
+
+  if (law) {
+    tempcaps =
+        gst_caps_new_simple ((law == 1) ? "audio/x-mulaw" : "audio/x-alaw",
+        "rate", G_TYPE_INT, auparse->samplerate,
+        "channels", G_TYPE_INT, auparse->channels, NULL);
+    auparse->sample_size = auparse->channels;
+  } else if (format != GST_AUDIO_FORMAT_UNKNOWN) {
+    GstCaps *templ_caps = gst_pad_get_pad_template_caps (auparse->srcpad);
+    GstCaps *intersection;
+
+    tempcaps = gst_caps_new_simple ("audio/x-raw",
+        "format", G_TYPE_STRING, gst_audio_format_to_string (format),
+        "rate", G_TYPE_INT, auparse->samplerate,
+        "channels", G_TYPE_INT, auparse->channels, NULL);
+
+    intersection = gst_caps_intersect (tempcaps, templ_caps);
+    gst_caps_unref (tempcaps);
+    gst_caps_unref (templ_caps);
+    tempcaps = intersection;
+  } else if (layout[0]) {
+    tempcaps = gst_caps_new_simple ("audio/x-adpcm",
+        "layout", G_TYPE_STRING, layout, NULL);
+    auparse->sample_size = 0;
+  } else
+    goto unknown_format;
+
+  GST_DEBUG_OBJECT (auparse, "sample_size=%d", auparse->sample_size);
+
+  gst_au_parse_negotiate_srcpad (auparse, tempcaps);
+
+  GST_DEBUG_OBJECT (auparse, "offset=%" G_GINT64_FORMAT, auparse->offset);
+  gst_adapter_unmap (auparse->adapter);
+  gst_adapter_flush (auparse->adapter, auparse->offset);
+
+  gst_caps_unref (tempcaps);
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+unknown_header:
+  {
+    gst_adapter_unmap (auparse->adapter);
+    GST_ELEMENT_ERROR (auparse, STREAM, WRONG_TYPE, (NULL), (NULL));
+    return GST_FLOW_ERROR;
+  }
+unsupported_sample_rate:
+  {
+    gst_adapter_unmap (auparse->adapter);
+    GST_ELEMENT_ERROR (auparse, STREAM, FORMAT, (NULL),
+        ("Unsupported samplerate: %u", auparse->samplerate));
+    return GST_FLOW_ERROR;
+  }
+unsupported_number_of_channels:
+  {
+    gst_adapter_unmap (auparse->adapter);
+    GST_ELEMENT_ERROR (auparse, STREAM, FORMAT, (NULL),
+        ("Unsupported number of channels: %u", auparse->channels));
+    return GST_FLOW_ERROR;
+  }
+unknown_format:
+  {
+    gst_adapter_unmap (auparse->adapter);
+    GST_ELEMENT_ERROR (auparse, STREAM, FORMAT, (NULL),
+        ("Unsupported encoding: %u", auparse->encoding));
+    return GST_FLOW_ERROR;
+  }
+}
+
+#define AU_HEADER_SIZE 24
+
+static GstFlowReturn
+gst_au_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstAuParse *auparse;
+  gint avail, sendnow = 0;
+  gint64 timestamp;
+  gint64 duration;
+  gint64 offset;
+
+  auparse = GST_AU_PARSE (parent);
+
+  GST_LOG_OBJECT (auparse, "got buffer of size %" G_GSIZE_FORMAT,
+      gst_buffer_get_size (buf));
+
+  gst_adapter_push (auparse->adapter, buf);
+  buf = NULL;
+
+  /* if we haven't seen any data yet... */
+  if (!gst_pad_has_current_caps (auparse->srcpad)) {
+    if (gst_adapter_available (auparse->adapter) < AU_HEADER_SIZE) {
+      GST_DEBUG_OBJECT (auparse, "need more data to parse header");
+      ret = GST_FLOW_OK;
+      goto out;
+    }
+
+    ret = gst_au_parse_parse_header (auparse);
+    if (ret != GST_FLOW_OK)
+      goto out;
+
+    if (auparse->need_segment) {
+      gst_pad_push_event (auparse->srcpad,
+          gst_event_new_segment (&auparse->segment));
+      auparse->need_segment = FALSE;
+    }
+  }
+
+  avail = gst_adapter_available (auparse->adapter);
+
+  if (auparse->sample_size > 0) {
+    /* Ensure we push a buffer that's a multiple of the frame size downstream */
+    sendnow = avail - (avail % auparse->sample_size);
+  } else {
+    /* It's something non-trivial (such as ADPCM), we don't understand it, so
+     * just push downstream and assume it will know what to do with it */
+    sendnow = avail;
+  }
+
+  if (sendnow > 0) {
+    GstBuffer *outbuf;
+    gint64 pos;
+
+    outbuf = gst_adapter_take_buffer (auparse->adapter, sendnow);
+    outbuf = gst_buffer_make_writable (outbuf);
+
+    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);
+  }
+
+out:
+
+  return ret;
+}
+
+static gboolean
+gst_au_parse_src_convert (GstAuParse * auparse, GstFormat src_format,
+    gint64 srcval, GstFormat dest_format, gint64 * destval)
+{
+  gboolean ret = TRUE;
+  guint samplesize, rate;
+
+  if (dest_format == src_format) {
+    *destval = srcval;
+    return TRUE;
+  }
+
+  GST_OBJECT_LOCK (auparse);
+  samplesize = auparse->sample_size;
+  rate = auparse->samplerate;
+  GST_OBJECT_UNLOCK (auparse);
+
+  if (samplesize == 0 || rate == 0) {
+    GST_LOG_OBJECT (auparse, "cannot convert, sample_size or rate unknown");
+    return FALSE;
+  }
+
+  switch (src_format) {
+    case GST_FORMAT_BYTES:
+      srcval /= samplesize;
+      /* fallthrough */
+    case GST_FORMAT_DEFAULT:{
+      switch (dest_format) {
+        case GST_FORMAT_DEFAULT:
+          *destval = srcval;
+          break;
+        case GST_FORMAT_BYTES:
+          *destval = srcval * samplesize;
+          break;
+        case GST_FORMAT_TIME:
+          *destval = gst_util_uint64_scale_int (srcval, GST_SECOND, rate);
+          break;
+        default:
+          ret = FALSE;
+          break;
+      }
+      break;
+    }
+    case GST_FORMAT_TIME:{
+      switch (dest_format) {
+        case GST_FORMAT_BYTES:
+          *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);
+          break;
+        default:
+          ret = FALSE;
+          break;
+      }
+      break;
+    }
+    default:{
+      ret = FALSE;
+      break;
+    }
+  }
+
+  if (!ret) {
+    GST_DEBUG_OBJECT (auparse, "could not convert from %s to %s format",
+        gst_format_get_name (src_format), gst_format_get_name (dest_format));
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_au_parse_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  GstAuParse *auparse;
+  gboolean ret = FALSE;
+
+  auparse = GST_AU_PARSE (parent);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_DURATION:{
+      GstFormat format;
+      gint64 len, val;
+
+      gst_query_parse_duration (query, &format, NULL);
+      if (!gst_pad_peer_query_duration (auparse->sinkpad, GST_FORMAT_BYTES,
+              &len)) {
+        GST_DEBUG_OBJECT (auparse, "failed to query upstream length");
+        break;
+      }
+      GST_OBJECT_LOCK (auparse);
+      len -= auparse->offset;
+      GST_OBJECT_UNLOCK (auparse);
+
+      ret =
+          gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, len, format,
+          &val);
+
+      if (ret) {
+        gst_query_set_duration (query, format, val);
+      }
+      break;
+    }
+    case GST_QUERY_POSITION:{
+      GstFormat format;
+      gint64 pos, val;
+
+      gst_query_parse_position (query, &format, NULL);
+      if (!gst_pad_peer_query_position (auparse->sinkpad, GST_FORMAT_BYTES,
+              &pos)) {
+        GST_DEBUG_OBJECT (auparse, "failed to query upstream position");
+        break;
+      }
+      GST_OBJECT_LOCK (auparse);
+      pos -= auparse->offset;
+      GST_OBJECT_UNLOCK (auparse);
+
+      ret = gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, pos,
+          format, &val);
+
+      if (ret) {
+        gst_query_set_position (query, format, val);
+      }
+      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, parent, query);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_au_parse_handle_seek (GstAuParse * auparse, GstEvent * event)
+{
+  GstSeekType start_type, stop_type;
+  GstSeekFlags flags;
+  GstFormat format;
+  gdouble rate;
+  gint64 start, stop;
+  gboolean res;
+
+  gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
+      &stop_type, &stop);
+
+  if (format != GST_FORMAT_TIME) {
+    GST_DEBUG_OBJECT (auparse, "only support seeks in TIME format");
+    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, GstObject * parent, GstEvent * event)
+{
+  GstAuParse *auparse;
+  gboolean ret = TRUE;
+
+  auparse = GST_AU_PARSE (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      /* discard, we'll come up with proper src caps */
+      gst_event_unref (event);
+      break;
+    }
+    case GST_EVENT_SEGMENT:
+    {
+      gint64 start, stop, offset = 0;
+      GstSegment segment;
+
+      /* some debug output */
+      gst_event_copy_segment (event, &segment);
+      GST_DEBUG_OBJECT (auparse, "received newsegment %" GST_SEGMENT_FORMAT,
+          &segment);
+
+      start = segment.start;
+      stop = segment.stop;
+      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);
+      }
+
+      GST_INFO_OBJECT (auparse,
+          "new segment: %" GST_TIME_FORMAT " ... %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
+
+      gst_segment_init (&segment, GST_FORMAT_TIME);
+      segment.start = segment.time = start;
+      segment.stop = stop;
+
+      gst_segment_copy_into (&segment, &auparse->segment);
+
+      if (!gst_pad_has_current_caps (auparse->srcpad)) {
+        auparse->need_segment = TRUE;
+        ret = TRUE;
+      } else {
+        auparse->need_segment = FALSE;
+        ret = gst_pad_push_event (auparse->srcpad,
+            gst_event_new_segment (&segment));
+      }
+
+      auparse->buffer_offset = offset;
+
+      gst_event_unref (event);
+      break;
+    }
+    case GST_EVENT_EOS:
+      if (!auparse->srcpad) {
+        GST_ELEMENT_ERROR (auparse, STREAM, WRONG_TYPE,
+            ("No valid input found before end of stream"), (NULL));
+      }
+      /* fall-through */
+    default:
+      ret = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_au_parse_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstAuParse *auparse;
+  gboolean ret;
+
+  auparse = GST_AU_PARSE (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+      ret = gst_au_parse_handle_seek (auparse, event);
+      gst_event_unref (event);
+      break;
+    default:
+      ret = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return ret;
+}
+
+static GstStateChangeReturn
+gst_au_parse_change_state (GstElement * element, GstStateChange transition)
+{
+  GstAuParse *auparse = GST_AU_PARSE (element);
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_au_parse_reset (auparse);
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "auparse", GST_RANK_SECONDARY,
+          GST_TYPE_AU_PARSE)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    auparse,
+    "parses au streams", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
+    GST_PACKAGE_ORIGIN)
diff --git a/gst/auparse/gstauparse.h b/gst/auparse/gstauparse.h
new file mode 100644
index 0000000..97a0995
--- /dev/null
+++ b/gst/auparse/gstauparse.h
@@ -0,0 +1,75 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_AU_PARSE_H__
+#define __GST_AU_PARSE_H__
+
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AU_PARSE \
+  (gst_au_parse_get_type())
+#define GST_AU_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AU_PARSE,GstAuParse))
+#define GST_AU_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AU_PARSE,GstAuParseClass))
+#define GST_IS_AU_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AU_PARSE))
+#define GST_IS_AU_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AU_PARSE))
+
+typedef struct _GstAuParse GstAuParse;
+typedef struct _GstAuParseClass GstAuParseClass;
+
+struct _GstAuParse {
+  GstElement element;
+
+  GstPad     *sinkpad;
+  GstPad     *srcpad;
+
+  GstCaps    *src_caps;
+
+  GstAdapter *adapter;
+
+  GstSegment  segment;
+  gboolean    need_segment;
+
+  gint64      offset;        /* where sample data starts */
+  gint64      buffer_offset;
+  guint       sample_size;
+  guint       encoding;
+  guint       samplerate;
+  guint       channels;
+};
+
+struct _GstAuParseClass {
+  GstElementClass parent_class;
+};
+
+GType gst_au_parse_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_AU_PARSE_H__ */
diff --git a/gst/auparse/meson.build b/gst/auparse/meson.build
new file mode 100644
index 0000000..5d308d2
--- /dev/null
+++ b/gst/auparse/meson.build
@@ -0,0 +1,8 @@
+gstauparse = library('gstauparse',
+  'gstauparse.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstaudio_dep, gstbase_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/autodetect/Makefile.am b/gst/autodetect/Makefile.am
new file mode 100644
index 0000000..42928a5
--- /dev/null
+++ b/gst/autodetect/Makefile.am
@@ -0,0 +1,18 @@
+plugin_LTLIBRARIES = libgstautodetect.la
+
+libgstautodetect_la_SOURCES = \
+	gstautoaudiosink.c \
+	gstautoaudiosrc.c \
+	gstautodetect.c \
+	gstautovideosink.c \
+	gstautovideosrc.c
+libgstautodetect_la_CFLAGS = $(GST_CFLAGS)
+libgstautodetect_la_LIBADD = $(GST_LIBS)
+libgstautodetect_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = \
+	gstautoaudiosink.h \
+	gstautoaudiosrc.h \
+	gstautodetect.h \
+	gstautovideosink.h \
+	gstautovideosrc.h
diff --git a/gst/autodetect/gstautoaudiosink.c b/gst/autodetect/gstautoaudiosink.c
new file mode 100644
index 0000000..1edf6d8
--- /dev/null
+++ b/gst/autodetect/gstautoaudiosink.c
@@ -0,0 +1,143 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2006 Jan Schmidt <thaytan@noraisin.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-autoaudiosink
+ * @see_also: autovideosink, alsasink, osssink
+ *
+ * autoaudiosink is an audio sink that automatically detects an appropriate
+ * audio sink to use.  It does so by scanning the registry for all elements
+ * that have <quote>Sink</quote> and <quote>Audio</quote> in the class field
+ * of their element information, and also have a non-zero autoplugging rank.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v -m audiotestsrc ! audioconvert ! audioresample ! autoaudiosink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstautoaudiosink.h"
+
+#define DEFAULT_TS_OFFSET           0
+
+/* Properties */
+enum
+{
+  PROP_0,
+  PROP_TS_OFFSET,
+};
+
+static void gst_auto_audio_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_auto_audio_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_auto_audio_sink_configure (GstAutoDetect * autodetect,
+    GstElement * kid);
+
+G_DEFINE_TYPE (GstAutoAudioSink, gst_auto_audio_sink, GST_TYPE_AUTO_DETECT);
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static void
+gst_auto_audio_sink_class_init (GstAutoAudioSinkClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+  GstAutoDetectClass *aklass = GST_AUTO_DETECT_CLASS (klass);
+
+  gobject_class->set_property = gst_auto_audio_sink_set_property;
+  gobject_class->get_property = gst_auto_audio_sink_get_property;
+
+  aklass->configure = gst_auto_audio_sink_configure;
+
+  g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
+      g_param_spec_int64 ("ts-offset", "TS Offset",
+          "Timestamp offset in nanoseconds", G_MININT64, G_MAXINT64,
+          DEFAULT_TS_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (eklass, &sink_template);
+  gst_element_class_set_static_metadata (eklass, "Auto audio sink",
+      "Sink/Audio",
+      "Wrapper audio sink for automatically detected audio sink",
+      "Jan Schmidt <thaytan@noraisin.net>");
+}
+
+static void
+gst_auto_audio_sink_init (GstAutoAudioSink * sink)
+{
+  GstAutoDetect *autodetect = GST_AUTO_DETECT (sink);
+
+  autodetect->media_klass = "Audio";
+  autodetect->flag = GST_ELEMENT_FLAG_SINK;
+
+  sink->ts_offset = DEFAULT_TS_OFFSET;
+}
+
+static void
+gst_auto_audio_sink_configure (GstAutoDetect * autodetect, GstElement * kid)
+{
+  GstAutoAudioSink *self = GST_AUTO_AUDIO_SINK (autodetect);
+
+  g_object_set (G_OBJECT (kid), "ts-offset", self->ts_offset, NULL);
+}
+
+static void
+gst_auto_audio_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAutoAudioSink *sink = GST_AUTO_AUDIO_SINK (object);
+  GstAutoDetect *autodetect = (GstAutoDetect *) sink;
+
+  switch (prop_id) {
+    case PROP_TS_OFFSET:
+      sink->ts_offset = g_value_get_int64 (value);
+      if (autodetect->kid)
+        g_object_set_property (G_OBJECT (autodetect->kid), pspec->name, value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_auto_audio_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAutoAudioSink *sink = GST_AUTO_AUDIO_SINK (object);
+
+  switch (prop_id) {
+    case PROP_TS_OFFSET:
+      g_value_set_int64 (value, sink->ts_offset);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/gst/autodetect/gstautoaudiosink.h b/gst/autodetect/gstautoaudiosink.h
new file mode 100644
index 0000000..24a0b25
--- /dev/null
+++ b/gst/autodetect/gstautoaudiosink.h
@@ -0,0 +1,55 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AUTO_AUDIO_SINK_H__
+#define __GST_AUTO_AUDIO_SINK_H__
+
+#include <gst/gst.h>
+#include "gstautodetect.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AUTO_AUDIO_SINK \
+  (gst_auto_audio_sink_get_type ())
+#define GST_AUTO_AUDIO_SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AUTO_AUDIO_SINK, \
+                               GstAutoAudioSink))
+#define GST_AUTO_AUDIO_SINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_AUTO_AUDIO_SINK, \
+                            GstAutoAudioSinkClass))
+#define GST_IS_AUTO_AUDIO_SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AUTO_AUDIO_SINK))
+#define GST_IS_AUTO_AUDIO_SINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AUTO_AUDIO_SINK))
+
+typedef struct _GstAutoAudioSink {
+  GstAutoDetect parent;
+
+  GstClockTimeDiff ts_offset;
+} GstAutoAudioSink;
+
+typedef struct _GstAutoAudioSinkClass {
+  GstAutoDetectClass parent_class;
+} GstAutoAudioSinkClass;
+
+GType   gst_auto_audio_sink_get_type    (void);
+
+G_END_DECLS
+
+#endif /* __GST_AUTO_AUDIO_SINK_H__ */
diff --git a/gst/autodetect/gstautoaudiosrc.c b/gst/autodetect/gstautoaudiosrc.c
new file mode 100644
index 0000000..8adda00
--- /dev/null
+++ b/gst/autodetect/gstautoaudiosrc.c
@@ -0,0 +1,95 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2006 Jan Schmidt <thaytan@noraisin.net>
+ * (c) 2008 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-autoaudiosrc
+ * @see_also: autovideosrc, alsasrc, osssrc
+ *
+ * autoaudiosrc is an audio source that automatically detects an appropriate
+ * audio source to use.  It does so by scanning the registry for all elements
+ * that have <quote>Source</quote> and <quote>Audio</quote> in the class field
+ * of their element information, and also have a non-zero autoplugging rank.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v -m autoaudiosrc ! audioconvert ! audioresample ! autoaudiosink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstautoaudiosrc.h"
+
+G_DEFINE_TYPE (GstAutoAudioSrc, gst_auto_audio_src, GST_TYPE_AUTO_DETECT);
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static GstElement *
+gst_auto_audio_src_create_fake_element (GstAutoDetect * autodetect)
+{
+  GstElement *fake;
+
+  fake = gst_element_factory_make ("audiotestsrc", "fake-auto-audio-src");
+  if (fake != NULL) {
+    g_object_set (fake, "is-live", TRUE, NULL);
+    gst_util_set_object_arg (G_OBJECT (fake), "wave", "silence");
+  } else {
+    GST_ELEMENT_ERROR (autodetect, RESOURCE, NOT_FOUND,
+        ("Failed to find usable audio source element."),
+        ("Failed to find a usable audio source and couldn't create an audio"
+            "testsrc as fallback either, check your GStreamer installation."));
+    /* This will error out with not-negotiated.. */
+    fake = gst_element_factory_make ("fakesrc", "fake-auto-audio-src");
+  }
+  return fake;
+}
+
+static void
+gst_auto_audio_src_class_init (GstAutoAudioSrcClass * klass)
+{
+  GstAutoDetectClass *autoclass = GST_AUTO_DETECT_CLASS (klass);
+  GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+
+  gst_element_class_add_static_pad_template (eklass, &src_template);
+  gst_element_class_set_static_metadata (eklass, "Auto audio source",
+      "Source/Audio",
+      "Wrapper audio source for automatically detected audio source",
+      "Jan Schmidt <thaytan@noraisin.net>, "
+      "Stefan Kost <ensonic@users.sf.net>");
+
+  autoclass->create_fake_element = gst_auto_audio_src_create_fake_element;
+}
+
+static void
+gst_auto_audio_src_init (GstAutoAudioSrc * src)
+{
+  GstAutoDetect *autodetect = GST_AUTO_DETECT (src);
+
+  autodetect->media_klass = "Audio";
+  autodetect->flag = GST_ELEMENT_FLAG_SOURCE;
+}
diff --git a/gst/autodetect/gstautoaudiosrc.h b/gst/autodetect/gstautoaudiosrc.h
new file mode 100644
index 0000000..427cdae
--- /dev/null
+++ b/gst/autodetect/gstautoaudiosrc.h
@@ -0,0 +1,54 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2008 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AUTO_AUDIO_SRC_H__
+#define __GST_AUTO_AUDIO_SRC_H__
+
+#include <gst/gst.h>
+#include "gstautodetect.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AUTO_AUDIO_SRC \
+  (gst_auto_audio_src_get_type ())
+#define GST_AUTO_AUDIO_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AUTO_AUDIO_SRC, \
+                               GstAutoAudioSrc))
+#define GST_AUTO_AUDIO_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_AUTO_AUDIO_SRC, \
+                            GstAutoAudioSrcClass))
+#define GST_IS_AUTO_AUDIO_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AUTO_AUDIO_SRC))
+#define GST_IS_AUTO_AUDIO_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AUTO_AUDIO_SRC))
+
+typedef struct _GstAutoAudioSrc {
+  GstAutoDetect parent;
+} GstAutoAudioSrc;
+
+typedef struct _GstAutoAudioSrcClass {
+  GstAutoDetectClass parent_class;
+} GstAutoAudioSrcClass;
+
+GType   gst_auto_audio_src_get_type    (void);
+
+G_END_DECLS
+
+#endif /* __GST_AUTO_AUDIO_SRC_H__ */
diff --git a/gst/autodetect/gstautodetect.c b/gst/autodetect/gstautodetect.c
new file mode 100644
index 0000000..3e30241
--- /dev/null
+++ b/gst/autodetect/gstautodetect.c
@@ -0,0 +1,507 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <gst/gst.h>
+
+#include "gstautodetect.h"
+#include "gstautoaudiosink.h"
+#include "gstautoaudiosrc.h"
+#include "gstautovideosink.h"
+#include "gstautovideosrc.h"
+
+GST_DEBUG_CATEGORY (autodetect_debug);
+
+#define DEFAULT_SYNC                TRUE
+
+/* Properties */
+enum
+{
+  PROP_0,
+  PROP_CAPS,
+  PROP_SYNC,
+};
+
+static GstStateChangeReturn gst_auto_detect_change_state (GstElement * element,
+    GstStateChange transition);
+static void gst_auto_detect_constructed (GObject * object);
+static void gst_auto_detect_dispose (GObject * self);
+static void gst_auto_detect_clear_kid (GstAutoDetect * self);
+static void gst_auto_detect_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_auto_detect_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+#define gst_auto_detect_parent_class parent_class
+G_DEFINE_ABSTRACT_TYPE (GstAutoDetect, gst_auto_detect, GST_TYPE_BIN);
+
+static void
+gst_auto_detect_class_init (GstAutoDetectClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *eklass;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  eklass = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->constructed = gst_auto_detect_constructed;
+  gobject_class->dispose = gst_auto_detect_dispose;
+  gobject_class->set_property = gst_auto_detect_set_property;
+  gobject_class->get_property = gst_auto_detect_get_property;
+
+  eklass->change_state = GST_DEBUG_FUNCPTR (gst_auto_detect_change_state);
+
+  /**
+   * GstAutoDetect:filter-caps:
+   *
+   * This property will filter out candidate sinks that can handle the specified
+   * caps. By default only elements that support uncompressed data are selected.
+   *
+   * This property can only be set before the element goes to the READY state.
+   */
+  g_object_class_install_property (gobject_class, PROP_CAPS,
+      g_param_spec_boxed ("filter-caps", "Filter caps",
+          "Filter sink candidates using these caps.", GST_TYPE_CAPS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_SYNC,
+      g_param_spec_boolean ("sync", "Sync",
+          "Sync on the clock", DEFAULT_SYNC,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_auto_detect_dispose (GObject * object)
+{
+  GstAutoDetect *self = GST_AUTO_DETECT (object);
+
+  gst_auto_detect_clear_kid (self);
+
+  if (self->filter_caps)
+    gst_caps_unref (self->filter_caps);
+  self->filter_caps = NULL;
+
+  G_OBJECT_CLASS (parent_class)->dispose ((GObject *) self);
+}
+
+static void
+gst_auto_detect_clear_kid (GstAutoDetect * self)
+{
+  if (self->kid) {
+    gst_element_set_state (self->kid, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN (self), self->kid);
+    self->kid = NULL;
+  }
+}
+
+static GstElement *
+gst_auto_detect_create_fake_element_default (GstAutoDetect * self)
+{
+  GstElement *fake;
+  gchar dummy_factory[10], dummy_name[20];
+
+  sprintf (dummy_factory, "fake%s", self->type_klass_lc);
+  sprintf (dummy_name, "fake-%s-%s", self->media_klass_lc, self->type_klass_lc);
+  fake = gst_element_factory_make (dummy_factory, dummy_name);
+  g_object_set (fake, "sync", self->sync, NULL);
+
+  return fake;
+}
+
+static GstElement *
+gst_auto_detect_create_fake_element (GstAutoDetect * self)
+{
+  GstAutoDetectClass *klass = GST_AUTO_DETECT_GET_CLASS (self);
+  GstElement *fake;
+
+  if (klass->create_fake_element)
+    fake = klass->create_fake_element (self);
+  else
+    fake = gst_auto_detect_create_fake_element_default (self);
+
+  return fake;
+}
+
+static gboolean
+gst_auto_detect_attach_ghost_pad (GstAutoDetect * self)
+{
+  GstPad *target = gst_element_get_static_pad (self->kid, self->type_klass_lc);
+  gboolean res = gst_ghost_pad_set_target (GST_GHOST_PAD (self->pad), target);
+  gst_object_unref (target);
+
+  return res;
+}
+
+/* Hack to make initial linking work; ideally, this'd work even when
+ * no target has been assigned to the ghostpad yet. */
+static void
+gst_auto_detect_reset (GstAutoDetect * self)
+{
+  gst_auto_detect_clear_kid (self);
+
+  /* placeholder element */
+  self->kid = gst_auto_detect_create_fake_element (self);
+  gst_bin_add (GST_BIN (self), self->kid);
+
+  gst_auto_detect_attach_ghost_pad (self);
+}
+
+static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw");
+static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw");
+
+static void
+gst_auto_detect_init (GstAutoDetect * self)
+{
+  self->sync = DEFAULT_SYNC;
+}
+
+static void
+gst_auto_detect_constructed (GObject * object)
+{
+  GstAutoDetect *self = GST_AUTO_DETECT (object);
+  gboolean is_audio;
+
+  if (G_OBJECT_CLASS (parent_class)->constructed)
+    G_OBJECT_CLASS (parent_class)->constructed (object);
+
+  is_audio = !g_strcmp0 (self->media_klass, "Audio");
+  self->type_klass = (self->flag == GST_ELEMENT_FLAG_SINK) ? "Sink" : "Source";
+  self->type_klass_lc = (self->flag == GST_ELEMENT_FLAG_SINK) ? "sink" : "src";
+  self->media_klass_lc = is_audio ? "audio" : "video";
+  /* set the default raw caps */
+  self->filter_caps = gst_static_caps_get (is_audio ? &raw_audio_caps :
+      &raw_video_caps);
+
+  self->pad = gst_ghost_pad_new_no_target (self->type_klass_lc,
+      (self->flag == GST_ELEMENT_FLAG_SINK) ? GST_PAD_SINK : GST_PAD_SRC);
+  gst_element_add_pad (GST_ELEMENT (self), self->pad);
+
+  gst_auto_detect_reset (self);
+
+  /* mark element type */
+  GST_OBJECT_FLAG_SET (self, self->flag);
+  gst_bin_set_suppressed_flags (GST_BIN (self),
+      GST_ELEMENT_FLAG_SOURCE | GST_ELEMENT_FLAG_SINK);
+}
+
+static gboolean
+gst_auto_detect_factory_filter (GstPluginFeature * feature, gpointer data)
+{
+  GstAutoDetect *self = (GstAutoDetect *) data;
+  guint rank;
+  const gchar *klass;
+
+  /* we only care about element factories */
+  if (!GST_IS_ELEMENT_FACTORY (feature))
+    return FALSE;
+
+  /* audio sinks */
+  klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY (feature),
+      GST_ELEMENT_METADATA_KLASS);
+  if (!(strstr (klass, self->type_klass) && strstr (klass, self->media_klass)))
+    return FALSE;
+
+  /* only select elements with autoplugging rank */
+  rank = gst_plugin_feature_get_rank (feature);
+  if (rank < GST_RANK_MARGINAL)
+    return FALSE;
+
+  return TRUE;
+}
+
+static GstElement *
+create_element_with_pretty_name (GstAutoDetect * self,
+    GstElementFactory * factory)
+{
+  GstElement *element;
+  gchar *name, *marker;
+
+  marker = g_strdup (GST_OBJECT_NAME (factory));
+  if (g_str_has_suffix (marker, self->type_klass_lc))
+    marker[strlen (marker) - 4] = '\0';
+  if (g_str_has_prefix (marker, "gst"))
+    memmove (marker, marker + 3, strlen (marker + 3) + 1);
+  name = g_strdup_printf ("%s-actual-%s-%s", GST_OBJECT_NAME (self),
+      self->type_klass_lc, marker);
+  g_free (marker);
+
+  element = gst_element_factory_create (factory, name);
+  g_free (name);
+
+  return element;
+}
+
+static GstElement *
+gst_auto_detect_find_best (GstAutoDetect * self)
+{
+  GList *list, *item;
+  GstElement *choice = NULL;
+  GstMessage *message = NULL;
+  GSList *errors = NULL;
+  GstBus *bus = gst_bus_new ();
+  GstPad *el_pad = NULL;
+  GstCaps *el_caps = NULL;
+  gboolean no_match = TRUE;
+
+  /* We don't treat sound server sinks special. Our policy is that sound
+   * server sinks that have a rank must not auto-spawn a daemon under any
+   * circumstances, so there's nothing for us to worry about here */
+  list = gst_registry_feature_filter (gst_registry_get (),
+      (GstPluginFeatureFilter) gst_auto_detect_factory_filter, FALSE, self);
+  list =
+      g_list_sort (list, (GCompareFunc) gst_plugin_feature_rank_compare_func);
+
+  GST_LOG_OBJECT (self, "Trying to find usable %s elements ...",
+      self->media_klass_lc);
+
+  for (item = list; item != NULL; item = item->next) {
+    GstElementFactory *f = GST_ELEMENT_FACTORY (item->data);
+    GstElement *el;
+
+    if ((el = create_element_with_pretty_name (self, f))) {
+      GstStateChangeReturn ret;
+
+      GST_DEBUG_OBJECT (self, "Testing %s", GST_OBJECT_NAME (f));
+
+      /* If autodetect has been provided with filter caps,
+       * accept only elements that match with the filter caps */
+      if (self->filter_caps) {
+        el_pad = gst_element_get_static_pad (el, self->type_klass_lc);
+        el_caps = gst_pad_query_caps (el_pad, NULL);
+        gst_object_unref (el_pad);
+        GST_DEBUG_OBJECT (self,
+            "Checking caps: %" GST_PTR_FORMAT " vs. %" GST_PTR_FORMAT,
+            self->filter_caps, el_caps);
+        no_match = !gst_caps_can_intersect (self->filter_caps, el_caps);
+        gst_caps_unref (el_caps);
+
+        if (no_match) {
+          GST_DEBUG_OBJECT (self, "Incompatible caps");
+          gst_object_unref (el);
+          continue;
+        } else {
+          GST_DEBUG_OBJECT (self, "Found compatible caps");
+        }
+      }
+
+      gst_element_set_bus (el, bus);
+      ret = gst_element_set_state (el, GST_STATE_READY);
+      if (ret == GST_STATE_CHANGE_SUCCESS) {
+        GST_DEBUG_OBJECT (self, "This worked!");
+        gst_element_set_state (el, GST_STATE_NULL);
+        choice = el;
+        break;
+      }
+
+      /* collect all error messages */
+      while ((message = gst_bus_pop_filtered (bus, GST_MESSAGE_ERROR))) {
+        GST_DEBUG_OBJECT (self, "error message %" GST_PTR_FORMAT, message);
+        errors = g_slist_append (errors, message);
+      }
+
+      gst_element_set_state (el, GST_STATE_NULL);
+      gst_object_unref (el);
+    }
+  }
+
+  GST_DEBUG_OBJECT (self, "done trying");
+  if (!choice) {
+    /* We post a warning and plug a fake-element. This is convenient for running
+     * tests without requiring hardware src/sinks. */
+    if (errors) {
+      GError *err = NULL;
+      gchar *dbg = NULL;
+
+      /* FIXME: we forward the first message for now; but later on it might make
+       * sense to forward all so that apps can actually analyse them. */
+      gst_message_parse_error (GST_MESSAGE (errors->data), &err, &dbg);
+      gst_element_post_message (GST_ELEMENT_CAST (self),
+          gst_message_new_warning (GST_OBJECT_CAST (self), err, dbg));
+      g_error_free (err);
+      g_free (dbg);
+    } else {
+      /* send warning message to application and use a fakesrc */
+      GST_ELEMENT_WARNING (self, RESOURCE, NOT_FOUND, (NULL),
+          ("Failed to find a usable %s %s", self->media_klass_lc,
+              self->type_klass_lc));
+    }
+    choice = gst_auto_detect_create_fake_element (self);
+    gst_element_set_state (choice, GST_STATE_READY);
+  }
+  gst_object_unref (bus);
+  gst_plugin_feature_list_free (list);
+  g_slist_foreach (errors, (GFunc) gst_mini_object_unref, NULL);
+  g_slist_free (errors);
+
+  return choice;
+}
+
+static gboolean
+gst_auto_detect_detect (GstAutoDetect * self)
+{
+  GstElement *kid;
+  GstAutoDetectClass *klass = GST_AUTO_DETECT_GET_CLASS (self);
+
+  gst_auto_detect_clear_kid (self);
+
+  /* find element */
+  GST_DEBUG_OBJECT (self, "Creating new kid");
+  if (!(kid = gst_auto_detect_find_best (self)))
+    goto no_sink;
+
+  self->has_sync =
+      g_object_class_find_property (G_OBJECT_GET_CLASS (kid), "sync") != NULL;
+  if (self->has_sync)
+    g_object_set (G_OBJECT (kid), "sync", self->sync, NULL);
+  if (klass->configure) {
+    klass->configure (self, kid);
+  }
+
+  self->kid = kid;
+
+  gst_bin_add (GST_BIN (self), kid);
+
+  /* Ensure the child is brought up to the right state to match the parent. */
+  if (GST_STATE (self->kid) < GST_STATE (self))
+    gst_element_set_state (self->kid, GST_STATE (self));
+
+  /* attach ghost pad */
+  GST_DEBUG_OBJECT (self, "Re-assigning ghostpad");
+  if (!gst_auto_detect_attach_ghost_pad (self))
+    goto target_failed;
+
+  GST_DEBUG_OBJECT (self, "done changing auto %s %s", self->media_klass_lc,
+      self->type_klass_lc);
+
+  return TRUE;
+
+  /* ERRORS */
+no_sink:
+  {
+    GST_ELEMENT_ERROR (self, LIBRARY, INIT, (NULL),
+        ("Failed to find a supported audio sink"));
+    return FALSE;
+  }
+target_failed:
+  {
+    GST_ELEMENT_ERROR (self, LIBRARY, INIT, (NULL),
+        ("Failed to set target pad"));
+    return FALSE;
+  }
+}
+
+static GstStateChangeReturn
+gst_auto_detect_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+  GstAutoDetect *sink = GST_AUTO_DETECT (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      if (!gst_auto_detect_detect (sink))
+        return GST_STATE_CHANGE_FAILURE;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      gst_auto_detect_reset (sink);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_auto_detect_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAutoDetect *self = GST_AUTO_DETECT (object);
+
+  switch (prop_id) {
+    case PROP_CAPS:
+      if (self->filter_caps)
+        gst_caps_unref (self->filter_caps);
+      self->filter_caps = gst_caps_copy (gst_value_get_caps (value));
+      break;
+    case PROP_SYNC:
+      self->sync = g_value_get_boolean (value);
+      if (self->kid && self->has_sync)
+        g_object_set_property (G_OBJECT (self->kid), pspec->name, value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_auto_detect_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAutoDetect *self = GST_AUTO_DETECT (object);
+
+  switch (prop_id) {
+    case PROP_CAPS:
+      gst_value_set_caps (value, self->filter_caps);
+      break;
+    case PROP_SYNC:
+      g_value_set_boolean (value, self->sync);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (autodetect_debug, "autodetect", 0,
+      "Autodetection audio/video output wrapper elements");
+
+  return gst_element_register (plugin, "autovideosink",
+      GST_RANK_NONE, GST_TYPE_AUTO_VIDEO_SINK) &&
+      gst_element_register (plugin, "autovideosrc",
+      GST_RANK_NONE, GST_TYPE_AUTO_VIDEO_SRC) &&
+      gst_element_register (plugin, "autoaudiosink",
+      GST_RANK_NONE, GST_TYPE_AUTO_AUDIO_SINK) &&
+      gst_element_register (plugin, "autoaudiosrc",
+      GST_RANK_NONE, GST_TYPE_AUTO_AUDIO_SRC);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    autodetect,
+    "Plugin contains auto-detection plugins for video/audio in- and outputs",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/autodetect/gstautodetect.h b/gst/autodetect/gstautodetect.h
new file mode 100644
index 0000000..05ae89f
--- /dev/null
+++ b/gst/autodetect/gstautodetect.h
@@ -0,0 +1,73 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AUTO_DETECT_H__
+#define __GST_AUTO_DETECT_H__
+
+G_BEGIN_DECLS
+
+GST_DEBUG_CATEGORY_EXTERN (autodetect_debug);
+#define GST_CAT_DEFAULT autodetect_debug
+
+#define GST_TYPE_AUTO_DETECT (gst_auto_detect_get_type ())
+#define GST_AUTO_DETECT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AUTO_DETECT, GstAutoDetect))
+#define GST_AUTO_DETECT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_AUTO_DETECT, GstAutoDetectClass))
+#define GST_IS_AUTO_DETECT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AUTO_DETECT))
+#define GST_IS_AUTO_DETECT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AUTO_DETECT))
+#define GST_AUTO_DETECT_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_AUTO_DETECT, GstAutoDetectClass))
+
+typedef struct _GstAutoDetect {
+  GstBin parent;
+  
+  /* configuration for subclasses */
+  const gchar *media_klass; /* Audio/Video/... */
+  GstElementFlags flag; /* GST_ELEMENT_FLAG_{SINK/SOURCE} */
+
+  /* explicit pointers to stuff used */
+  GstPad *pad;
+  GstCaps *filter_caps;
+  gboolean sync;
+
+  /* < private > */ 
+  GstElement *kid;
+  gboolean has_sync;
+  const gchar *type_klass; /* Source/Sink */
+  const gchar *media_klass_lc, *type_klass_lc; /* lower case versions */
+
+} GstAutoDetect;
+
+typedef struct _GstAutoDetectClass {
+  GstBinClass parent_class;
+  
+  /*< private >*/
+  /* virtual methods for subclasses */
+  void (*configure)(GstAutoDetect *self, GstElement *kid);
+  GstElement * (*create_fake_element) (GstAutoDetect * autodetect);
+} GstAutoDetectClass;
+
+GType   gst_auto_detect_get_type    (void);
+
+G_END_DECLS
+
+#endif /* __GST_AUTO_DETECT_H__ */
diff --git a/gst/autodetect/gstautovideosink.c b/gst/autodetect/gstautovideosink.c
new file mode 100644
index 0000000..e4fd91e
--- /dev/null
+++ b/gst/autodetect/gstautovideosink.c
@@ -0,0 +1,143 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2006 Jan Schmidt <thaytan@noraisin.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-autovideosink
+ * @see_also: autoaudiosink, ximagesink, xvimagesink, sdlvideosink
+ *
+ * autovideosink is a video sink that automatically detects an appropriate
+ * video sink to use.  It does so by scanning the registry for all elements
+ * that have <quote>Sink</quote> and <quote>Video</quote> in the class field
+ * of their element information, and also have a non-zero autoplugging rank.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v -m videotestsrc ! autovideosink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstautovideosink.h"
+
+#define DEFAULT_TS_OFFSET           0
+
+/* Properties */
+enum
+{
+  PROP_0,
+  PROP_TS_OFFSET,
+};
+
+static void gst_auto_video_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_auto_video_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_auto_video_sink_configure (GstAutoDetect * autodetect,
+    GstElement * kid);
+
+G_DEFINE_TYPE (GstAutoVideoSink, gst_auto_video_sink, GST_TYPE_AUTO_DETECT);
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static void
+gst_auto_video_sink_class_init (GstAutoVideoSinkClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+  GstAutoDetectClass *aklass = GST_AUTO_DETECT_CLASS (klass);
+
+  gobject_class->set_property = gst_auto_video_sink_set_property;
+  gobject_class->get_property = gst_auto_video_sink_get_property;
+
+  aklass->configure = gst_auto_video_sink_configure;
+
+  g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
+      g_param_spec_int64 ("ts-offset", "TS Offset",
+          "Timestamp offset in nanoseconds", G_MININT64, G_MAXINT64,
+          DEFAULT_TS_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (eklass, &sink_template);
+  gst_element_class_set_static_metadata (eklass, "Auto video sink",
+      "Sink/Video",
+      "Wrapper video sink for automatically detected video sink",
+      "Jan Schmidt <thaytan@noraisin.net>");
+}
+
+static void
+gst_auto_video_sink_init (GstAutoVideoSink * sink)
+{
+  GstAutoDetect *autodetect = GST_AUTO_DETECT (sink);
+
+  autodetect->media_klass = "Video";
+  autodetect->flag = GST_ELEMENT_FLAG_SINK;
+
+  sink->ts_offset = DEFAULT_TS_OFFSET;
+}
+
+static void
+gst_auto_video_sink_configure (GstAutoDetect * autodetect, GstElement * kid)
+{
+  GstAutoVideoSink *self = GST_AUTO_VIDEO_SINK (autodetect);
+
+  g_object_set (G_OBJECT (kid), "ts-offset", self->ts_offset, NULL);
+}
+
+static void
+gst_auto_video_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAutoVideoSink *sink = GST_AUTO_VIDEO_SINK (object);
+  GstAutoDetect *autodetect = (GstAutoDetect *) sink;
+
+  switch (prop_id) {
+    case PROP_TS_OFFSET:
+      sink->ts_offset = g_value_get_int64 (value);
+      if (autodetect->kid)
+        g_object_set_property (G_OBJECT (autodetect->kid), pspec->name, value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_auto_video_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAutoVideoSink *sink = GST_AUTO_VIDEO_SINK (object);
+
+  switch (prop_id) {
+    case PROP_TS_OFFSET:
+      g_value_set_int64 (value, sink->ts_offset);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/gst/autodetect/gstautovideosink.h b/gst/autodetect/gstautovideosink.h
new file mode 100644
index 0000000..5b7db40
--- /dev/null
+++ b/gst/autodetect/gstautovideosink.h
@@ -0,0 +1,55 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AUTO_VIDEO_SINK_H__
+#define __GST_AUTO_VIDEO_SINK_H__
+
+#include <gst/gst.h>
+#include "gstautodetect.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AUTO_VIDEO_SINK \
+  (gst_auto_video_sink_get_type ())
+#define GST_AUTO_VIDEO_SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AUTO_VIDEO_SINK, \
+                               GstAutoVideoSink))
+#define GST_AUTO_VIDEO_SINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_AUTO_VIDEO_SINK, \
+                            GstAutoVideoSinkClass))
+#define GST_IS_AUTO_VIDEO_SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AUTO_VIDEO_SINK))
+#define GST_IS_AUTO_VIDEO_SINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AUTO_VIDEO_SINK))
+
+typedef struct _GstAutoVideoSink {
+  GstAutoDetect parent;
+
+  GstClockTimeDiff ts_offset;
+} GstAutoVideoSink;
+
+typedef struct _GstAutoVideoSinkClass {
+  GstAutoDetectClass parent_class;
+} GstAutoVideoSinkClass;
+
+GType   gst_auto_video_sink_get_type    (void);
+
+G_END_DECLS
+
+#endif /* __GST_AUTO_VIDEO_SINK_H__ */
diff --git a/gst/autodetect/gstautovideosrc.c b/gst/autodetect/gstautovideosrc.c
new file mode 100644
index 0000000..2f43431
--- /dev/null
+++ b/gst/autodetect/gstautovideosrc.c
@@ -0,0 +1,94 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2006 Jan Schmidt <thaytan@noraisin.net>
+ * (c) 2008 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-autovideosrc
+ * @see_also: autoaudiosrc, v4l2src, v4lsrc
+ *
+ * autovideosrc is a video src that automatically detects an appropriate
+ * video source to use.  It does so by scanning the registry for all elements
+ * that have <quote>Source</quote> and <quote>Video</quote> in the class field
+ * of their element information, and also have a non-zero autoplugging rank.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v -m autovideosrc ! xvimagesink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstautovideosrc.h"
+
+G_DEFINE_TYPE (GstAutoVideoSrc, gst_auto_video_src, GST_TYPE_AUTO_DETECT);
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static GstElement *
+gst_auto_video_src_create_fake_element (GstAutoDetect * autodetect)
+{
+  GstElement *fake;
+
+  fake = gst_element_factory_make ("videotestsrc", "fake-auto-video-src");
+  if (fake != NULL) {
+    g_object_set (fake, "is-live", TRUE, NULL);
+  } else {
+    GST_ELEMENT_ERROR (autodetect, RESOURCE, NOT_FOUND,
+        ("Failed to find usable video source element."),
+        ("Failed to find a usable video source and couldn't create a video"
+            "testsrc as fallback either, check your GStreamer installation."));
+    /* This will error out with not-negotiated.. */
+    fake = gst_element_factory_make ("fakesrc", "fake-auto-video-src");
+  }
+  return fake;
+}
+
+static void
+gst_auto_video_src_class_init (GstAutoVideoSrcClass * klass)
+{
+  GstAutoDetectClass *autoclass = GST_AUTO_DETECT_CLASS (klass);
+  GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+
+  gst_element_class_add_static_pad_template (eklass, &src_template);
+  gst_element_class_set_static_metadata (eklass, "Auto video source",
+      "Source/Video",
+      "Wrapper video source for automatically detected video source",
+      "Jan Schmidt <thaytan@noraisin.net>, "
+      "Stefan Kost <ensonic@users.sf.net>");
+
+  autoclass->create_fake_element = gst_auto_video_src_create_fake_element;
+}
+
+static void
+gst_auto_video_src_init (GstAutoVideoSrc * src)
+{
+  GstAutoDetect *autodetect = GST_AUTO_DETECT (src);
+
+  autodetect->media_klass = "Video";
+  autodetect->flag = GST_ELEMENT_FLAG_SOURCE;
+}
diff --git a/gst/autodetect/gstautovideosrc.h b/gst/autodetect/gstautovideosrc.h
new file mode 100644
index 0000000..e76cc72
--- /dev/null
+++ b/gst/autodetect/gstautovideosrc.h
@@ -0,0 +1,54 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2008 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AUTO_VIDEO_SRC_H__
+#define __GST_AUTO_VIDEO_SRC_H__
+
+#include <gst/gst.h>
+#include "gstautodetect.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AUTO_VIDEO_SRC \
+  (gst_auto_video_src_get_type ())
+#define GST_AUTO_VIDEO_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AUTO_VIDEO_SRC, \
+                               GstAutoVideoSrc))
+#define GST_AUTO_VIDEO_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_AUTO_VIDEO_SRC, \
+                            GstAutoVideoSrcClass))
+#define GST_IS_AUTO_VIDEO_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AUTO_VIDEO_SRC))
+#define GST_IS_AUTO_VIDEO_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AUTO_VIDEO_SRC))
+
+typedef struct _GstAutoVideoSrc {
+  GstAutoDetect parent;
+} GstAutoVideoSrc;
+
+typedef struct _GstAutoVideoSrcClass {
+  GstAutoDetectClass parent_class;
+} GstAutoVideoSrcClass;
+
+GType   gst_auto_video_src_get_type    (void);
+
+G_END_DECLS
+
+#endif /* __GST_AUTO_VIDEO_SRC_H__ */
diff --git a/gst/autodetect/meson.build b/gst/autodetect/meson.build
new file mode 100644
index 0000000..4512d2b
--- /dev/null
+++ b/gst/autodetect/meson.build
@@ -0,0 +1,16 @@
+autodetect_sources = [
+  'gstautoaudiosink.c',
+  'gstautoaudiosrc.c',
+  'gstautodetect.c',
+  'gstautovideosink.c',
+  'gstautovideosrc.c',
+]
+
+gstautodetect = library('gstautodetect',
+  autodetect_sources,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gst_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/avi/.gitignore b/gst/avi/.gitignore
new file mode 100644
index 0000000..3df96ad
--- /dev/null
+++ b/gst/avi/.gitignore
@@ -0,0 +1,8 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
+codectest
diff --git a/gst/avi/Makefile.am b/gst/avi/Makefile.am
new file mode 100644
index 0000000..276a327
--- /dev/null
+++ b/gst/avi/Makefile.am
@@ -0,0 +1,27 @@
+plugin_LTLIBRARIES = libgstavi.la
+
+libgstavi_la_SOURCES = \
+	gstavi.c \
+	gstavimux.c \
+	gstavidemux.c \
+	gstavisubtitle.c
+
+noinst_HEADERS = \
+	avi-ids.h \
+	gstavimux.h \
+	gstavidemux.h \
+	gstavisubtitle.h
+
+libgstavi_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstavi_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) \
+	$(GST_BASE_LIBS) \
+	$(GST_LIBS) \
+	-lgstriff-@GST_API_VERSION@ \
+	-lgstaudio-@GST_API_VERSION@ \
+	-lgsttag-@GST_API_VERSION@ \
+	-lgstvideo-@GST_API_VERSION@
+
+libgstavi_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+EXTRA_DIST = README
diff --git a/gst/avi/README b/gst/avi/README
new file mode 100644
index 0000000..69a08a9
--- /dev/null
+++ b/gst/avi/README
@@ -0,0 +1,72 @@
+The avi decoder plugins
+-----------------------
+
+The avi decoder consists of a set of gstreamer plugins:
+
+ - demuxer (avidemux)
+ - avi to gstreamer type converter (avitypes)
+ - windows dlls wrappers.
+
+the avidecoder element uses the above plugins to perform the avi
+decoding. It is constructed as a custom bin which initially only has
+the demuxer element in it. The demuxer has a set of padtemplates for
+raw audio and video.
+
+  (------------------------------------)
+  ! avidecoder                         !
+  !                                 (video/raw)...
+  !     (----------)                   !
+  !     ! demuxer (video/x-msvideo, auds)..
+  !     !          !                   !
+  !   -src         !                   !
+  !  /  !         (video/x-msvideo, vids)..
+ - src  !          !                   !
+  !     (----------)                (audio/raw)...
+  !                                    !
+  (------------------------------------)
+
+the demuxer has a set of padtemplates for the raw avi header properties.
+
+The avi decoder will act on the new_pad signal of the demuxer element
+and will attach an avitype plugin to the new pad. Caps negotiation will
+convert the raw avi caps to the gstreamer caps. If the src pad of the
+avitypes plugin are compatible with the avidecoder padtemplate, the 
+avitype pad is ghosted to the avidecoder bin, this is the case where no
+codec is needed (for raw PCM samples, for example).
+
+When the avitypes caps are not compatible with one of the avidecoder 
+templates, a static autoplugger is used the find an element to connect
+the demuxers pad to the decoders padtemplate.
+
+When no element could be found, an windec plugin is attached to the 
+demuxers pad and the avitypes plugin is removed from the decoder.
+
+
+example:
+--------
+
+ An avidecoder that has a video pad (decoded with windows dlls) and an
+ audio pad (raw PCM).
+
+  (----------------------------------------------------------------)
+  ! avidecoder               (--------)    (------)                !
+  !                          !avitypes!    !windec!       /-- (video/raw)
+  !     (----------)     /-sink      src--sink   src -----         !
+  !     !demuxer (video/x-msvideo,    !    !      !                !
+  !     !          ! auds).. (--------)    (------)                !  
+  !   -sink        !         (--------)                            !
+  !  /  !        (video/x-..,!avitypes!                            !
+ -sink  !          ! vids).. !        !                            !
+  !     (----------)     \-sink      src -------------------- (audio/raw)
+  !                          (--------)                            !
+  (----------------------------------------------------------------)
+
+
+
+TODO
+----
+
+automatically generate the padtemplates from all possible avi types
+found in the registry.
+
+
diff --git a/gst/avi/avi-ids.h b/gst/avi/avi-ids.h
new file mode 100644
index 0000000..9c09803
--- /dev/null
+++ b/gst/avi/avi-ids.h
@@ -0,0 +1,79 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AVI_H__
+#define __GST_AVI_H__
+
+#include <gst/gst.h>
+
+typedef struct _gst_riff_avih {
+  guint32 us_frame;          /* microsec per frame */
+  guint32 max_bps;           /* byte/s overall */
+  guint32 pad_gran;          /* pad_granularity */
+  guint32 flags;
+/* flags values */
+#define GST_RIFF_AVIH_HASINDEX       0x00000010 /* has idx1 chunk */
+#define GST_RIFF_AVIH_MUSTUSEINDEX   0x00000020 /* must use idx1 chunk to determine order */
+#define GST_RIFF_AVIH_ISINTERLEAVED  0x00000100 /* AVI file is interleaved */
+#define GST_RIFF_AVIH_TRUSTCKTYPE    0x00000800 /* Use CKType to find key frames */
+#define GST_RIFF_AVIH_WASCAPTUREFILE 0x00010000 /* specially allocated used for capturing real time video */
+#define GST_RIFF_AVIH_COPYRIGHTED    0x00020000 /* contains copyrighted data */
+  guint32 tot_frames;        /* # of frames (all) */
+  guint32 init_frames;       /* initial frames (???) */
+  guint32 streams;
+  guint32 bufsize;           /* suggested buffer size */
+  guint32 width;
+  guint32 height;
+  guint32 scale;
+  guint32 rate;
+  guint32 start;
+  guint32 length;
+} gst_riff_avih;
+
+/* vprp (video properties) ODML header */
+/* see ODML spec for some/more explanation */
+#define GST_RIFF_TAG_vprp GST_MAKE_FOURCC ('v','p','r','p')
+#define GST_RIFF_DXSB GST_MAKE_FOURCC ('D','X','S','B')
+#define GST_RIFF_VPRP_VIDEO_FIELDS        (2)
+
+typedef struct _gst_riff_vprp_video_field_desc {
+  guint32 compressed_bm_height;
+  guint32 compressed_bm_width;
+  guint32 valid_bm_height;
+  guint32 valid_bm_width;
+  guint32 valid_bm_x_offset;
+  guint32 valid_bm_y_offset;
+  guint32 video_x_t_offset;
+  guint32 video_y_start;
+} gst_riff_vprp_video_field_desc;
+
+typedef struct _gst_riff_vprp {
+  guint32 format_token;      /* whether fields defined by standard */
+  guint32 standard;          /* video display standard, UNKNOWN, PAL, etc */
+  guint32 vert_rate;         /* vertical refresh rate */
+  guint32 hor_t_total;       /* width */
+  guint32 vert_lines;        /* height */
+  guint32 aspect;            /* aspect ratio high word:low word */
+  guint32 width;             /* active width */
+  guint32 height;            /* active height */
+  guint32 fields;            /* field count */
+  gst_riff_vprp_video_field_desc field_info[GST_RIFF_VPRP_VIDEO_FIELDS];
+} gst_riff_vprp;
+
+#endif /* __GST_AVI_H__ */
diff --git a/gst/avi/gstavi.c b/gst/avi/gstavi.c
new file mode 100644
index 0000000..b4cf0ad
--- /dev/null
+++ b/gst/avi/gstavi.c
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
+ *
+ * gstavi.c: plugin registering
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gst/gst-i18n-plugin.h"
+
+#include "gstavidemux.h"
+#include "gstavimux.h"
+#include "gstavisubtitle.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  gst_riff_init ();
+
+#ifdef ENABLE_NLS
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif /* ENABLE_NLS */
+
+  if (!gst_element_register (plugin, "avidemux", GST_RANK_PRIMARY,
+          GST_TYPE_AVI_DEMUX) ||
+      !gst_element_register (plugin, "avimux", GST_RANK_PRIMARY,
+          GST_TYPE_AVI_MUX) ||
+      !gst_element_register (plugin, "avisubtitle", GST_RANK_PRIMARY,
+          GST_TYPE_AVI_SUBTITLE)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    avi,
+    "AVI stream handling",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c
new file mode 100644
index 0000000..c02ee89
--- /dev/null
+++ b/gst/avi/gstavidemux.c
@@ -0,0 +1,6044 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
+ * Copyright (C) <2006> Nokia Corporation (contact <stefan.kost@nokia.com>)
+ * Copyright (C) <2009-2010> STEricsson <benjamin.gaignard@stericsson.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/* Element-Checklist-Version: 5 */
+
+/**
+ * SECTION:element-avidemux
+ *
+ * Demuxes an .avi file into raw or compressed audio and/or video streams.
+ *
+ * This element supports both push and pull-based scheduling, depending on the
+ * capabilities of the upstream elements.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=test.avi ! avidemux name=demux  demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink   demux.video_00 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
+ * ]| Play (parse and decode) an .avi file and try to output it to
+ * an automatically detected soundcard and videosink. If the AVI file contains
+ * compressed audio or video data, this will only work if you have the
+ * right decoder elements/plugins installed.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "gst/riff/riff-media.h"
+#include "gstavidemux.h"
+#include "avi-ids.h"
+#include <gst/gst-i18n-plugin.h>
+#include <gst/base/gstadapter.h>
+#include <gst/tag/tag.h>
+
+#define DIV_ROUND_UP(s,v) (((s) + ((v)-1)) / (v))
+
+#define GST_AVI_KEYFRAME (1 << 0)
+#define ENTRY_IS_KEYFRAME(e) ((e)->flags == GST_AVI_KEYFRAME)
+#define ENTRY_SET_KEYFRAME(e) ((e)->flags = GST_AVI_KEYFRAME)
+#define ENTRY_UNSET_KEYFRAME(e) ((e)->flags = 0)
+
+
+GST_DEBUG_CATEGORY_STATIC (avidemux_debug);
+#define GST_CAT_DEFAULT avidemux_debug
+
+static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-msvideo")
+    );
+
+#ifndef GST_DISABLE_GST_DEBUG
+static const char *const snap_types[2][2] = {
+  {"any", "after"},
+  {"before", "nearest"},
+};
+#endif
+
+static void gst_avi_demux_finalize (GObject * object);
+
+static void gst_avi_demux_reset (GstAviDemux * avi);
+
+#if 0
+static const GstEventMask *gst_avi_demux_get_event_mask (GstPad * pad);
+#endif
+static gboolean gst_avi_demux_handle_src_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static gboolean gst_avi_demux_handle_sink_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static gboolean gst_avi_demux_push_event (GstAviDemux * avi, GstEvent * event);
+
+#if 0
+static const GstFormat *gst_avi_demux_get_src_formats (GstPad * pad);
+#endif
+static gboolean gst_avi_demux_handle_src_query (GstPad * pad,
+    GstObject * parent, GstQuery * query);
+static gboolean gst_avi_demux_src_convert (GstPad * pad, GstFormat src_format,
+    gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
+
+static gboolean gst_avi_demux_do_seek (GstAviDemux * avi, GstSegment * segment,
+    GstSeekFlags flags);
+static gboolean gst_avi_demux_handle_seek (GstAviDemux * avi, GstPad * pad,
+    GstEvent * event);
+static gboolean gst_avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad,
+    GstEvent * event);
+static void gst_avi_demux_loop (GstPad * pad);
+static gboolean gst_avi_demux_sink_activate (GstPad * sinkpad,
+    GstObject * parent);
+static gboolean gst_avi_demux_sink_activate_mode (GstPad * sinkpad,
+    GstObject * parent, GstPadMode mode, gboolean active);
+static GstFlowReturn gst_avi_demux_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buf);
+#if 0
+static void gst_avi_demux_set_index (GstElement * element, GstIndex * index);
+static GstIndex *gst_avi_demux_get_index (GstElement * element);
+#endif
+static GstStateChangeReturn gst_avi_demux_change_state (GstElement * element,
+    GstStateChange transition);
+static void gst_avi_demux_calculate_durations_from_index (GstAviDemux * avi);
+static void gst_avi_demux_get_buffer_info (GstAviDemux * avi,
+    GstAviStream * stream, guint entry_n, GstClockTime * timestamp,
+    GstClockTime * ts_end, guint64 * offset, guint64 * offset_end);
+
+static void gst_avi_demux_parse_idit (GstAviDemux * avi, GstBuffer * buf);
+static void gst_avi_demux_parse_strd (GstAviDemux * avi, GstBuffer * buf);
+
+static void parse_tag_value (GstAviDemux * avi, GstTagList * taglist,
+    const gchar * type, guint8 * ptr, guint tsize);
+
+/* GObject methods */
+
+#define gst_avi_demux_parent_class parent_class
+G_DEFINE_TYPE (GstAviDemux, gst_avi_demux, GST_TYPE_ELEMENT);
+
+static void
+gst_avi_demux_class_init (GstAviDemuxClass * klass)
+{
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstPadTemplate *videosrctempl, *audiosrctempl, *subsrctempl, *subpicsrctempl;
+  GstCaps *audcaps, *vidcaps, *subcaps, *subpiccaps;
+
+  GST_DEBUG_CATEGORY_INIT (avidemux_debug, "avidemux",
+      0, "Demuxer for AVI streams");
+
+  gobject_class->finalize = gst_avi_demux_finalize;
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_avi_demux_change_state);
+#if 0
+  gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_avi_demux_set_index);
+  gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_avi_demux_get_index);
+#endif
+
+  audcaps = gst_riff_create_audio_template_caps ();
+  gst_caps_append (audcaps, gst_caps_new_empty_simple ("audio/x-avi-unknown"));
+  audiosrctempl = gst_pad_template_new ("audio_%u",
+      GST_PAD_SRC, GST_PAD_SOMETIMES, audcaps);
+
+  vidcaps = gst_riff_create_video_template_caps ();
+  gst_caps_append (vidcaps, gst_riff_create_iavs_template_caps ());
+  gst_caps_append (vidcaps, gst_caps_new_empty_simple ("video/x-avi-unknown"));
+  videosrctempl = gst_pad_template_new ("video_%u",
+      GST_PAD_SRC, GST_PAD_SOMETIMES, vidcaps);
+
+  subcaps = gst_caps_new_empty_simple ("application/x-subtitle-avi");
+  subsrctempl = gst_pad_template_new ("subtitle_%u",
+      GST_PAD_SRC, GST_PAD_SOMETIMES, subcaps);
+  subpiccaps = gst_caps_new_empty_simple ("subpicture/x-xsub");
+  subpicsrctempl = gst_pad_template_new ("subpicture_%u",
+      GST_PAD_SRC, GST_PAD_SOMETIMES, subpiccaps);
+  gst_element_class_add_pad_template (gstelement_class, audiosrctempl);
+  gst_element_class_add_pad_template (gstelement_class, videosrctempl);
+  gst_element_class_add_pad_template (gstelement_class, subsrctempl);
+  gst_element_class_add_pad_template (gstelement_class, subpicsrctempl);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_templ);
+
+  gst_caps_unref (audcaps);
+  gst_caps_unref (vidcaps);
+  gst_caps_unref (subcaps);
+  gst_caps_unref (subpiccaps);
+
+  gst_element_class_set_static_metadata (gstelement_class, "Avi demuxer",
+      "Codec/Demuxer",
+      "Demultiplex an avi file into audio and video",
+      "Erik Walthinsen <omega@cse.ogi.edu>, "
+      "Wim Taymans <wim.taymans@chello.be>, "
+      "Thijs Vermeir <thijsvermeir@gmail.com>");
+}
+
+static void
+gst_avi_demux_init (GstAviDemux * avi)
+{
+  avi->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
+  gst_pad_set_activate_function (avi->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_avi_demux_sink_activate));
+  gst_pad_set_activatemode_function (avi->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_avi_demux_sink_activate_mode));
+  gst_pad_set_chain_function (avi->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_avi_demux_chain));
+  gst_pad_set_event_function (avi->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_avi_demux_handle_sink_event));
+  gst_element_add_pad (GST_ELEMENT_CAST (avi), avi->sinkpad);
+
+  avi->adapter = gst_adapter_new ();
+  avi->flowcombiner = gst_flow_combiner_new ();
+
+  gst_avi_demux_reset (avi);
+
+  GST_OBJECT_FLAG_SET (avi, GST_ELEMENT_FLAG_INDEXABLE);
+}
+
+static void
+gst_avi_demux_finalize (GObject * object)
+{
+  GstAviDemux *avi = GST_AVI_DEMUX (object);
+
+  GST_DEBUG ("AVI: finalize");
+
+  g_object_unref (avi->adapter);
+  gst_flow_combiner_free (avi->flowcombiner);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_avi_demux_reset_stream (GstAviDemux * avi, GstAviStream * stream)
+{
+  g_free (stream->strh);
+  g_free (stream->strf.data);
+  g_free (stream->name);
+  g_free (stream->index);
+  g_free (stream->indexes);
+  if (stream->initdata)
+    gst_buffer_unref (stream->initdata);
+  if (stream->extradata)
+    gst_buffer_unref (stream->extradata);
+  if (stream->rgb8_palette)
+    gst_buffer_unref (stream->rgb8_palette);
+  if (stream->pad) {
+    if (stream->exposed) {
+      gst_pad_set_active (stream->pad, FALSE);
+      gst_element_remove_pad (GST_ELEMENT_CAST (avi), stream->pad);
+      gst_flow_combiner_remove_pad (avi->flowcombiner, stream->pad);
+    } else
+      gst_object_unref (stream->pad);
+  }
+  if (stream->taglist) {
+    gst_tag_list_unref (stream->taglist);
+    stream->taglist = NULL;
+  }
+  memset (stream, 0, sizeof (GstAviStream));
+}
+
+static void
+gst_avi_demux_reset (GstAviDemux * avi)
+{
+  gint i;
+
+  GST_DEBUG ("AVI: reset");
+
+  for (i = 0; i < avi->num_streams; i++)
+    gst_avi_demux_reset_stream (avi, &avi->stream[i]);
+
+  avi->header_state = GST_AVI_DEMUX_HEADER_TAG_LIST;
+  avi->num_streams = 0;
+  avi->num_v_streams = 0;
+  avi->num_a_streams = 0;
+  avi->num_t_streams = 0;
+  avi->num_sp_streams = 0;
+  avi->main_stream = -1;
+
+  avi->have_group_id = FALSE;
+  avi->group_id = G_MAXUINT;
+
+  avi->state = GST_AVI_DEMUX_START;
+  avi->offset = 0;
+  avi->building_index = FALSE;
+
+  avi->index_offset = 0;
+  g_free (avi->avih);
+  avi->avih = NULL;
+
+#if 0
+  if (avi->element_index)
+    gst_object_unref (avi->element_index);
+  avi->element_index = NULL;
+#endif
+
+  if (avi->seg_event) {
+    gst_event_unref (avi->seg_event);
+    avi->seg_event = NULL;
+  }
+  if (avi->seek_event) {
+    gst_event_unref (avi->seek_event);
+    avi->seek_event = NULL;
+  }
+
+  if (avi->globaltags)
+    gst_tag_list_unref (avi->globaltags);
+  avi->globaltags = NULL;
+
+  avi->got_tags = TRUE;         /* we always want to push global tags */
+  avi->have_eos = FALSE;
+  avi->seekable = TRUE;
+
+  gst_adapter_clear (avi->adapter);
+
+  gst_segment_init (&avi->segment, GST_FORMAT_TIME);
+  avi->segment_seqnum = 0;
+}
+
+
+/* GstElement methods */
+
+#if 0
+static const GstFormat *
+gst_avi_demux_get_src_formats (GstPad * pad)
+{
+  GstAviStream *stream = gst_pad_get_element_private (pad);
+
+  static const GstFormat src_a_formats[] = {
+    GST_FORMAT_TIME,
+    GST_FORMAT_BYTES,
+    GST_FORMAT_DEFAULT,
+    0
+  };
+  static const GstFormat src_v_formats[] = {
+    GST_FORMAT_TIME,
+    GST_FORMAT_DEFAULT,
+    0
+  };
+
+  return (stream->strh->type == GST_RIFF_FCC_auds ?
+      src_a_formats : src_v_formats);
+}
+#endif
+
+/* assumes stream->strf.auds->av_bps != 0 */
+static inline GstClockTime
+avi_stream_convert_bytes_to_time_unchecked (GstAviStream * stream,
+    guint64 bytes)
+{
+  return gst_util_uint64_scale_int (bytes, GST_SECOND,
+      stream->strf.auds->av_bps);
+}
+
+static inline guint64
+avi_stream_convert_time_to_bytes_unchecked (GstAviStream * stream,
+    GstClockTime time)
+{
+  return gst_util_uint64_scale_int (time, stream->strf.auds->av_bps,
+      GST_SECOND);
+}
+
+/* assumes stream->strh->rate != 0 */
+static inline GstClockTime
+avi_stream_convert_frames_to_time_unchecked (GstAviStream * stream,
+    guint64 frames)
+{
+  return gst_util_uint64_scale (frames, stream->strh->scale * GST_SECOND,
+      stream->strh->rate);
+}
+
+static inline guint64
+avi_stream_convert_time_to_frames_unchecked (GstAviStream * stream,
+    GstClockTime time)
+{
+  return gst_util_uint64_scale (time, stream->strh->rate,
+      stream->strh->scale * GST_SECOND);
+}
+
+static gboolean
+gst_avi_demux_src_convert (GstPad * pad,
+    GstFormat src_format,
+    gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
+{
+  GstAviStream *stream = gst_pad_get_element_private (pad);
+  gboolean res = TRUE;
+
+  GST_LOG_OBJECT (pad,
+      "Received  src_format:%s, src_value:%" G_GUINT64_FORMAT
+      ", dest_format:%s", gst_format_get_name (src_format), src_value,
+      gst_format_get_name (*dest_format));
+
+  if (G_UNLIKELY (src_format == *dest_format)) {
+    *dest_value = src_value;
+    goto done;
+  }
+  if (G_UNLIKELY (!stream->strh || !stream->strf.data)) {
+    res = FALSE;
+    goto done;
+  }
+  if (G_UNLIKELY (stream->strh->type == GST_RIFF_FCC_vids &&
+          (src_format == GST_FORMAT_BYTES
+              || *dest_format == GST_FORMAT_BYTES))) {
+    res = FALSE;
+    goto done;
+  }
+
+  switch (src_format) {
+    case GST_FORMAT_TIME:
+      switch (*dest_format) {
+        case GST_FORMAT_BYTES:
+          *dest_value = gst_util_uint64_scale_int (src_value,
+              stream->strf.auds->av_bps, GST_SECOND);
+          break;
+        case GST_FORMAT_DEFAULT:
+          *dest_value =
+              gst_util_uint64_scale_round (src_value, stream->strh->rate,
+              stream->strh->scale * GST_SECOND);
+          break;
+        default:
+          res = FALSE;
+          break;
+      }
+      break;
+    case GST_FORMAT_BYTES:
+      switch (*dest_format) {
+        case GST_FORMAT_TIME:
+          if (stream->strf.auds->av_bps != 0) {
+            *dest_value = avi_stream_convert_bytes_to_time_unchecked (stream,
+                src_value);
+          } else
+            res = FALSE;
+          break;
+        default:
+          res = FALSE;
+          break;
+      }
+      break;
+    case GST_FORMAT_DEFAULT:
+      switch (*dest_format) {
+        case GST_FORMAT_TIME:
+          *dest_value =
+              avi_stream_convert_frames_to_time_unchecked (stream, src_value);
+          break;
+        default:
+          res = FALSE;
+          break;
+      }
+      break;
+    default:
+      res = FALSE;
+  }
+
+done:
+  GST_LOG_OBJECT (pad,
+      "Returning res:%d dest_format:%s dest_value:%" G_GUINT64_FORMAT, res,
+      gst_format_get_name (*dest_format), *dest_value);
+  return res;
+}
+
+static gboolean
+gst_avi_demux_handle_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  gboolean res = TRUE;
+  GstAviDemux *avi = GST_AVI_DEMUX (parent);
+
+  GstAviStream *stream = gst_pad_get_element_private (pad);
+
+  if (!stream->strh || !stream->strf.data)
+    return gst_pad_query_default (pad, parent, query);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:{
+      gint64 pos = 0;
+
+      GST_DEBUG ("pos query for stream %u: frames %u, bytes %u",
+          stream->num, stream->current_entry, stream->current_total);
+
+      /* FIXME, this looks clumsy */
+      if (stream->strh->type == GST_RIFF_FCC_auds) {
+        if (stream->is_vbr) {
+          /* VBR */
+          pos = avi_stream_convert_frames_to_time_unchecked (stream,
+              stream->current_entry);
+          GST_DEBUG_OBJECT (avi, "VBR convert frame %u, time %"
+              GST_TIME_FORMAT, stream->current_entry, GST_TIME_ARGS (pos));
+        } else if (stream->strf.auds->av_bps != 0) {
+          /* CBR */
+          pos = avi_stream_convert_bytes_to_time_unchecked (stream,
+              stream->current_total);
+          GST_DEBUG_OBJECT (avi,
+              "CBR convert bytes %u, time %" GST_TIME_FORMAT,
+              stream->current_total, GST_TIME_ARGS (pos));
+        } else if (stream->idx_n != 0 && stream->total_bytes != 0) {
+          /* calculate timestamps based on percentage of length */
+          guint64 xlen = avi->avih->us_frame *
+              avi->avih->tot_frames * GST_USECOND;
+
+          pos = gst_util_uint64_scale (xlen, stream->current_total,
+              stream->total_bytes);
+          GST_DEBUG_OBJECT (avi,
+              "CBR perc convert bytes %u, time %" GST_TIME_FORMAT,
+              stream->current_total, GST_TIME_ARGS (pos));
+        } else {
+          /* we don't know */
+          res = FALSE;
+        }
+      } else {
+        if (stream->strh->rate != 0) {
+          pos = gst_util_uint64_scale ((guint64) stream->current_entry *
+              stream->strh->scale, GST_SECOND, (guint64) stream->strh->rate);
+        } else {
+          pos = stream->current_entry * avi->avih->us_frame * GST_USECOND;
+        }
+      }
+      if (res) {
+        GST_DEBUG ("pos query : %" GST_TIME_FORMAT, GST_TIME_ARGS (pos));
+        gst_query_set_position (query, GST_FORMAT_TIME, pos);
+      } else
+        GST_WARNING ("pos query failed");
+      break;
+    }
+    case GST_QUERY_DURATION:
+    {
+      GstFormat fmt;
+      GstClockTime duration;
+
+      /* only act on audio or video streams */
+      if (stream->strh->type != GST_RIFF_FCC_auds &&
+          stream->strh->type != GST_RIFF_FCC_vids &&
+          stream->strh->type != GST_RIFF_FCC_iavs) {
+        res = FALSE;
+        break;
+      }
+
+      /* take stream duration, fall back to avih duration */
+      if ((duration = stream->duration) == -1)
+        if ((duration = stream->hdr_duration) == -1)
+          duration = avi->duration;
+
+      gst_query_parse_duration (query, &fmt, NULL);
+
+      switch (fmt) {
+        case GST_FORMAT_TIME:
+          gst_query_set_duration (query, fmt, duration);
+          break;
+        case GST_FORMAT_DEFAULT:
+        {
+          gint64 dur;
+          GST_DEBUG_OBJECT (query, "total frames is %" G_GUINT32_FORMAT,
+              stream->idx_n);
+
+          if (stream->idx_n > 0)
+            gst_query_set_duration (query, fmt, stream->idx_n);
+          else if (gst_pad_query_convert (pad, GST_FORMAT_TIME,
+                  duration, fmt, &dur))
+            gst_query_set_duration (query, fmt, dur);
+          break;
+        }
+        default:
+          res = FALSE;
+          break;
+      }
+      break;
+    }
+    case GST_QUERY_SEEKING:{
+      GstFormat fmt;
+
+      gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
+      if (fmt == GST_FORMAT_TIME) {
+        gboolean seekable = TRUE;
+
+        if (avi->streaming) {
+          seekable = avi->seekable;
+        }
+
+        gst_query_set_seeking (query, GST_FORMAT_TIME, seekable,
+            0, stream->duration);
+        res = TRUE;
+      }
+      break;
+    }
+    case GST_QUERY_CONVERT:{
+      GstFormat src_fmt, dest_fmt;
+      gint64 src_val, dest_val;
+
+      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
+      if ((res = gst_avi_demux_src_convert (pad, src_fmt, src_val, &dest_fmt,
+                  &dest_val)))
+        gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+      else
+        res = gst_pad_query_default (pad, parent, query);
+      break;
+    }
+    case GST_QUERY_SEGMENT:
+    {
+      GstFormat format;
+      gint64 start, stop;
+
+      format = avi->segment.format;
+
+      start =
+          gst_segment_to_stream_time (&avi->segment, format,
+          avi->segment.start);
+      if ((stop = avi->segment.stop) == -1)
+        stop = avi->segment.duration;
+      else
+        stop = gst_segment_to_stream_time (&avi->segment, format, stop);
+
+      gst_query_set_segment (query, avi->segment.rate, format, start, stop);
+      res = TRUE;
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+
+  return res;
+}
+
+#if 0
+static const GstEventMask *
+gst_avi_demux_get_event_mask (GstPad * pad)
+{
+  static const GstEventMask masks[] = {
+    {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT},
+    {0,}
+  };
+
+  return masks;
+}
+#endif
+
+#if 0
+static guint64
+gst_avi_demux_seek_streams (GstAviDemux * avi, guint64 offset, gboolean before)
+{
+  GstAviStream *stream;
+  GstIndexEntry *entry;
+  gint i;
+  gint64 val, min = offset;
+
+  for (i = 0; i < avi->num_streams; i++) {
+    stream = &avi->stream[i];
+
+    entry = gst_index_get_assoc_entry (avi->element_index, stream->index_id,
+        before ? GST_INDEX_LOOKUP_BEFORE : GST_INDEX_LOOKUP_AFTER,
+        GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, offset);
+
+    if (before) {
+      if (entry) {
+        gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &val);
+        GST_DEBUG_OBJECT (avi, "stream %d, previous entry at %"
+            G_GUINT64_FORMAT, i, val);
+        if (val < min)
+          min = val;
+      }
+      continue;
+    }
+
+    if (!entry) {
+      GST_DEBUG_OBJECT (avi, "no position for stream %d, assuming at start", i);
+      stream->current_entry = 0;
+      stream->current_total = 0;
+      continue;
+    }
+
+    gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &val);
+    GST_DEBUG_OBJECT (avi, "stream %d, next entry at %" G_GUINT64_FORMAT,
+        i, val);
+
+    gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &val);
+    stream->current_total = val;
+    gst_index_entry_assoc_map (entry, GST_FORMAT_DEFAULT, &val);
+    stream->current_entry = val;
+  }
+
+  return min;
+}
+#endif
+
+static gint
+gst_avi_demux_index_entry_offset_search (GstAviIndexEntry * entry,
+    guint64 * offset)
+{
+  if (entry->offset < *offset)
+    return -1;
+  else if (entry->offset > *offset)
+    return 1;
+  return 0;
+}
+
+static guint64
+gst_avi_demux_seek_streams_index (GstAviDemux * avi, guint64 offset,
+    gboolean before)
+{
+  GstAviStream *stream;
+  GstAviIndexEntry *entry;
+  gint i;
+  gint64 val, min = offset;
+  guint index = 0;
+
+  for (i = 0; i < avi->num_streams; i++) {
+    stream = &avi->stream[i];
+
+    /* compensate for chunk header */
+    offset += 8;
+    entry =
+        gst_util_array_binary_search (stream->index, stream->idx_n,
+        sizeof (GstAviIndexEntry),
+        (GCompareDataFunc) gst_avi_demux_index_entry_offset_search,
+        before ? GST_SEARCH_MODE_BEFORE : GST_SEARCH_MODE_AFTER, &offset, NULL);
+    offset -= 8;
+
+    if (entry)
+      index = entry - stream->index;
+
+    if (before) {
+      if (entry) {
+        val = stream->index[index].offset;
+        GST_DEBUG_OBJECT (avi,
+            "stream %d, previous entry at %" G_GUINT64_FORMAT, i, val);
+        if (val < min)
+          min = val;
+      }
+      continue;
+    }
+
+    if (!entry) {
+      GST_DEBUG_OBJECT (avi, "no position for stream %d, assuming at start", i);
+      stream->current_entry = 0;
+      stream->current_total = 0;
+      continue;
+    }
+
+    val = stream->index[index].offset - 8;
+    GST_DEBUG_OBJECT (avi, "stream %d, next entry at %" G_GUINT64_FORMAT, i,
+        val);
+
+    stream->current_total = stream->index[index].total;
+    stream->current_entry = index;
+  }
+
+  return min;
+}
+
+#define GST_AVI_SEEK_PUSH_DISPLACE     (4 * GST_SECOND)
+
+static gboolean
+gst_avi_demux_handle_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  gboolean res = TRUE;
+  GstAviDemux *avi = GST_AVI_DEMUX (parent);
+
+  GST_DEBUG_OBJECT (avi,
+      "have event type %s: %p on sink pad", GST_EVENT_TYPE_NAME (event), event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEGMENT:
+    {
+      gint64 boffset, offset = 0;
+      GstSegment segment;
+      GstEvent *segment_event;
+
+      /* some debug output */
+      gst_event_copy_segment (event, &segment);
+      GST_DEBUG_OBJECT (avi, "received newsegment %" GST_SEGMENT_FORMAT,
+          &segment);
+
+      /* chain will send initial newsegment after pads have been added */
+      if (avi->state != GST_AVI_DEMUX_MOVI) {
+        GST_DEBUG_OBJECT (avi, "still starting, eating event");
+        goto exit;
+      }
+
+      /* we only expect a BYTE segment, e.g. following a seek */
+      if (segment.format != GST_FORMAT_BYTES) {
+        GST_DEBUG_OBJECT (avi, "unsupported segment format, ignoring");
+        goto exit;
+      }
+
+      if (avi->have_index) {
+        GstAviIndexEntry *entry;
+        guint i = 0, index = 0, k = 0;
+        GstAviStream *stream;
+
+        /* compensate chunk header, stored index offset points after header */
+        boffset = segment.start + 8;
+        /* find which stream we're on */
+        do {
+          stream = &avi->stream[i];
+
+          /* find the index for start bytes offset */
+          entry = gst_util_array_binary_search (stream->index,
+              stream->idx_n, sizeof (GstAviIndexEntry),
+              (GCompareDataFunc) gst_avi_demux_index_entry_offset_search,
+              GST_SEARCH_MODE_AFTER, &boffset, NULL);
+
+          if (entry == NULL)
+            continue;
+          index = entry - stream->index;
+
+          /* we are on the stream with a chunk start offset closest to start */
+          if (!offset || stream->index[index].offset < offset) {
+            offset = stream->index[index].offset;
+            k = i;
+          }
+          /* exact match needs no further searching */
+          if (stream->index[index].offset == boffset)
+            break;
+        } while (++i < avi->num_streams);
+        boffset -= 8;
+        offset -= 8;
+        stream = &avi->stream[k];
+
+        /* so we have no idea what is to come, or where we are */
+        if (!offset) {
+          GST_WARNING_OBJECT (avi, "insufficient index data, forcing EOS");
+          goto eos;
+        }
+
+        /* get the ts corresponding to start offset bytes for the stream */
+        gst_avi_demux_get_buffer_info (avi, stream, index,
+            (GstClockTime *) & segment.time, NULL, NULL, NULL);
+#if 0
+      } else if (avi->element_index) {
+        GstIndexEntry *entry;
+
+        /* Let's check if we have an index entry for this position */
+        entry = gst_index_get_assoc_entry (avi->element_index, avi->index_id,
+            GST_INDEX_LOOKUP_AFTER, GST_ASSOCIATION_FLAG_NONE,
+            GST_FORMAT_BYTES, segment.start);
+
+        /* we can not go where we have not yet been before ... */
+        if (!entry) {
+          GST_WARNING_OBJECT (avi, "insufficient index data, forcing EOS");
+          goto eos;
+        }
+
+        gst_index_entry_assoc_map (entry, GST_FORMAT_TIME,
+            (gint64 *) & segment.time);
+        gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &offset);
+#endif
+      } else {
+        GST_WARNING_OBJECT (avi, "no index data, forcing EOS");
+        goto eos;
+      }
+
+      segment.format = GST_FORMAT_TIME;
+      segment.start = segment.time;
+      segment.stop = GST_CLOCK_TIME_NONE;
+      segment.position = segment.start;
+
+      /* rescue duration */
+      segment.duration = avi->segment.duration;
+
+      /* set up segment and send downstream */
+      gst_segment_copy_into (&segment, &avi->segment);
+
+      GST_DEBUG_OBJECT (avi, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
+      avi->segment_seqnum = gst_event_get_seqnum (event);
+      segment_event = gst_event_new_segment (&segment);
+      gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
+      gst_avi_demux_push_event (avi, segment_event);
+
+      GST_DEBUG_OBJECT (avi, "next chunk expected at %" G_GINT64_FORMAT,
+          boffset);
+
+      /* adjust state for streaming thread accordingly */
+      if (avi->have_index)
+        gst_avi_demux_seek_streams_index (avi, offset, FALSE);
+#if 0
+      else
+        gst_avi_demux_seek_streams (avi, offset, FALSE);
+#endif
+
+      /* set up streaming thread */
+      g_assert (offset >= boffset);
+      avi->offset = boffset;
+      avi->todrop = offset - boffset;
+
+    exit:
+      gst_event_unref (event);
+      res = TRUE;
+      break;
+    eos:
+      /* set up for EOS */
+      avi->have_eos = TRUE;
+      goto exit;
+    }
+    case GST_EVENT_EOS:
+    {
+      if (avi->state != GST_AVI_DEMUX_MOVI) {
+        gst_event_unref (event);
+        GST_ELEMENT_ERROR (avi, STREAM, DEMUX,
+            (NULL), ("got eos and didn't receive a complete header object"));
+      } else if (!gst_avi_demux_push_event (avi, event)) {
+        GST_ELEMENT_ERROR (avi, STREAM, DEMUX,
+            (NULL), ("got eos but no streams (yet)"));
+      }
+      break;
+    }
+    case GST_EVENT_FLUSH_STOP:
+    {
+      gint i;
+
+      gst_adapter_clear (avi->adapter);
+      avi->have_eos = FALSE;
+      for (i = 0; i < avi->num_streams; i++) {
+        avi->stream[i].discont = TRUE;
+      }
+      /* fall through to default case so that the event gets passed downstream */
+    }
+    default:
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return res;
+}
+
+static gboolean
+gst_avi_demux_handle_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  gboolean res = TRUE;
+  GstAviDemux *avi = GST_AVI_DEMUX (parent);
+
+  GST_DEBUG_OBJECT (avi,
+      "have event type %s: %p on src pad", GST_EVENT_TYPE_NAME (event), event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+      if (!avi->streaming) {
+        res = gst_avi_demux_handle_seek (avi, pad, event);
+      } else {
+        res = gst_avi_demux_handle_seek_push (avi, pad, event);
+      }
+      gst_event_unref (event);
+      break;
+    default:
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return res;
+}
+
+/* streaming helper (push) */
+
+/*
+ * gst_avi_demux_peek_chunk_info:
+ * @avi: Avi object
+ * @tag: holder for tag
+ * @size: holder for tag size
+ *
+ * Peek next chunk info (tag and size)
+ *
+ * Returns: TRUE when one chunk info has been got
+ */
+static gboolean
+gst_avi_demux_peek_chunk_info (GstAviDemux * avi, guint32 * tag, guint32 * size)
+{
+  const guint8 *data = NULL;
+
+  if (gst_adapter_available (avi->adapter) < 8)
+    return FALSE;
+
+  data = gst_adapter_map (avi->adapter, 8);
+  *tag = GST_READ_UINT32_LE (data);
+  *size = GST_READ_UINT32_LE (data + 4);
+  gst_adapter_unmap (avi->adapter);
+
+  return TRUE;
+}
+
+/*
+ * gst_avi_demux_peek_chunk:
+ * @avi: Avi object
+ * @tag: holder for tag
+ * @size: holder for tag size
+ *
+ * Peek enough data for one full chunk
+ *
+ * Returns: %TRUE when one chunk has been got
+ */
+static gboolean
+gst_avi_demux_peek_chunk (GstAviDemux * avi, guint32 * tag, guint32 * size)
+{
+  guint32 peek_size = 0;
+  gint available;
+
+  if (!gst_avi_demux_peek_chunk_info (avi, tag, size))
+    goto peek_failed;
+
+  /* size 0 -> empty data buffer would surprise most callers,
+   * large size -> do not bother trying to squeeze that into adapter,
+   * so we throw poor man's exception, which can be caught if caller really
+   * wants to handle 0 size chunk */
+  if (!(*size) || (*size) >= (1 << 30))
+    goto strange_size;
+
+  peek_size = (*size + 1) & ~1;
+  available = gst_adapter_available (avi->adapter);
+
+  GST_DEBUG_OBJECT (avi,
+      "Need to peek chunk of %d bytes to read chunk %" GST_FOURCC_FORMAT
+      ", %d bytes available", *size, GST_FOURCC_ARGS (*tag), available);
+
+  if (available < (8 + peek_size))
+    goto need_more;
+
+  return TRUE;
+
+  /* ERRORS */
+peek_failed:
+  {
+    GST_INFO_OBJECT (avi, "Failed to peek");
+    return FALSE;
+  }
+strange_size:
+  {
+    GST_INFO_OBJECT (avi,
+        "Invalid/unexpected chunk size %d for tag %" GST_FOURCC_FORMAT, *size,
+        GST_FOURCC_ARGS (*tag));
+    /* chain should give up */
+    avi->abort_buffering = TRUE;
+    return FALSE;
+  }
+need_more:
+  {
+    GST_INFO_OBJECT (avi, "need more %d < %" G_GUINT32_FORMAT,
+        available, 8 + peek_size);
+    return FALSE;
+  }
+}
+
+/* AVI init */
+
+/*
+ * gst_avi_demux_parse_file_header:
+ * @element: caller element (used for errors/debug).
+ * @buf: input data to be used for parsing.
+ *
+ * "Open" a RIFF/AVI file. The buffer should be at least 12
+ * bytes long. Takes ownership of @buf.
+ *
+ * Returns: TRUE if the file is a RIFF/AVI file, FALSE otherwise.
+ *          Throws an error, caller should error out (fatal).
+ */
+static gboolean
+gst_avi_demux_parse_file_header (GstElement * element, GstBuffer * buf)
+{
+  guint32 doctype;
+  GstClockTime stamp;
+
+  stamp = gst_util_get_timestamp ();
+
+  /* riff_parse posts an error */
+  if (!gst_riff_parse_file_header (element, buf, &doctype))
+    return FALSE;
+
+  if (doctype != GST_RIFF_RIFF_AVI)
+    goto not_avi;
+
+  stamp = gst_util_get_timestamp () - stamp;
+  GST_DEBUG_OBJECT (element, "header parsing took %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (stamp));
+
+  return TRUE;
+
+  /* ERRORS */
+not_avi:
+  {
+    GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
+        ("File is not an AVI file: 0x%" G_GINT32_MODIFIER "x", doctype));
+    return FALSE;
+  }
+}
+
+/*
+ * Read AVI file tag when streaming
+ */
+static GstFlowReturn
+gst_avi_demux_stream_init_push (GstAviDemux * avi)
+{
+  if (gst_adapter_available (avi->adapter) >= 12) {
+    GstBuffer *tmp;
+
+    tmp = gst_adapter_take_buffer (avi->adapter, 12);
+
+    GST_DEBUG ("Parsing avi header");
+    if (!gst_avi_demux_parse_file_header (GST_ELEMENT_CAST (avi), tmp)) {
+      return GST_FLOW_ERROR;
+    }
+    GST_DEBUG ("header ok");
+    avi->offset += 12;
+
+    avi->state = GST_AVI_DEMUX_HEADER;
+  }
+  return GST_FLOW_OK;
+}
+
+/*
+ * Read AVI file tag
+ */
+static GstFlowReturn
+gst_avi_demux_stream_init_pull (GstAviDemux * avi)
+{
+  GstFlowReturn res;
+  GstBuffer *buf = NULL;
+
+  res = gst_pad_pull_range (avi->sinkpad, avi->offset, 12, &buf);
+  if (res != GST_FLOW_OK)
+    return res;
+  else if (!gst_avi_demux_parse_file_header (GST_ELEMENT_CAST (avi), buf))
+    goto wrong_header;
+
+  avi->offset += 12;
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+wrong_header:
+  {
+    GST_DEBUG_OBJECT (avi, "error parsing file header");
+    return GST_FLOW_ERROR;
+  }
+}
+
+/* AVI header handling */
+/*
+ * gst_avi_demux_parse_avih:
+ * @avi: caller element (used for errors/debug).
+ * @buf: input data to be used for parsing.
+ * @avih: pointer to structure (filled in by function) containing
+ *        stream information (such as flags, number of streams, etc.).
+ *
+ * Read 'avih' header. Discards buffer after use.
+ *
+ * Returns: TRUE on success, FALSE otherwise. Throws an error if
+ *          the header is invalid. The caller should error out
+ *          (fatal).
+ */
+static gboolean
+gst_avi_demux_parse_avih (GstAviDemux * avi,
+    GstBuffer * buf, gst_riff_avih ** _avih)
+{
+  gst_riff_avih *avih;
+  gsize size;
+
+  if (buf == NULL)
+    goto no_buffer;
+
+  size = gst_buffer_get_size (buf);
+  if (size < sizeof (gst_riff_avih))
+    goto avih_too_small;
+
+  avih = g_malloc (size);
+  gst_buffer_extract (buf, 0, avih, size);
+
+#if (G_BYTE_ORDER == G_BIG_ENDIAN)
+  avih->us_frame = GUINT32_FROM_LE (avih->us_frame);
+  avih->max_bps = GUINT32_FROM_LE (avih->max_bps);
+  avih->pad_gran = GUINT32_FROM_LE (avih->pad_gran);
+  avih->flags = GUINT32_FROM_LE (avih->flags);
+  avih->tot_frames = GUINT32_FROM_LE (avih->tot_frames);
+  avih->init_frames = GUINT32_FROM_LE (avih->init_frames);
+  avih->streams = GUINT32_FROM_LE (avih->streams);
+  avih->bufsize = GUINT32_FROM_LE (avih->bufsize);
+  avih->width = GUINT32_FROM_LE (avih->width);
+  avih->height = GUINT32_FROM_LE (avih->height);
+  avih->scale = GUINT32_FROM_LE (avih->scale);
+  avih->rate = GUINT32_FROM_LE (avih->rate);
+  avih->start = GUINT32_FROM_LE (avih->start);
+  avih->length = GUINT32_FROM_LE (avih->length);
+#endif
+
+  /* debug stuff */
+  GST_INFO_OBJECT (avi, "avih tag found:");
+  GST_INFO_OBJECT (avi, " us_frame    %u", avih->us_frame);
+  GST_INFO_OBJECT (avi, " max_bps     %u", avih->max_bps);
+  GST_INFO_OBJECT (avi, " pad_gran    %u", avih->pad_gran);
+  GST_INFO_OBJECT (avi, " flags       0x%08x", avih->flags);
+  GST_INFO_OBJECT (avi, " tot_frames  %u", avih->tot_frames);
+  GST_INFO_OBJECT (avi, " init_frames %u", avih->init_frames);
+  GST_INFO_OBJECT (avi, " streams     %u", avih->streams);
+  GST_INFO_OBJECT (avi, " bufsize     %u", avih->bufsize);
+  GST_INFO_OBJECT (avi, " width       %u", avih->width);
+  GST_INFO_OBJECT (avi, " height      %u", avih->height);
+  GST_INFO_OBJECT (avi, " scale       %u", avih->scale);
+  GST_INFO_OBJECT (avi, " rate        %u", avih->rate);
+  GST_INFO_OBJECT (avi, " start       %u", avih->start);
+  GST_INFO_OBJECT (avi, " length      %u", avih->length);
+
+  *_avih = avih;
+  gst_buffer_unref (buf);
+
+  if (avih->us_frame != 0 && avih->tot_frames != 0)
+    avi->duration =
+        (guint64) avih->us_frame * (guint64) avih->tot_frames * 1000;
+  else
+    avi->duration = GST_CLOCK_TIME_NONE;
+
+  GST_INFO_OBJECT (avi, " header duration  %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (avi->duration));
+
+  return TRUE;
+
+  /* ERRORS */
+no_buffer:
+  {
+    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("No buffer"));
+    return FALSE;
+  }
+avih_too_small:
+  {
+    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
+        ("Too small avih (%" G_GSIZE_FORMAT " available, %d needed)",
+            size, (int) sizeof (gst_riff_avih)));
+    gst_buffer_unref (buf);
+    return FALSE;
+  }
+}
+
+/*
+ * gst_avi_demux_parse_superindex:
+ * @avi: caller element (used for debugging/errors).
+ * @buf: input data to use for parsing.
+ * @locations: locations in the file (byte-offsets) that contain
+ *             the actual indexes (see get_avi_demux_parse_subindex()).
+ *             The array ends with GST_BUFFER_OFFSET_NONE.
+ *
+ * Reads superindex (openDML-2 spec stuff) from the provided data.
+ *
+ * Returns: TRUE on success, FALSE otherwise. Indexes should be skipped
+ *          on error, but they are not fatal.
+ */
+static gboolean
+gst_avi_demux_parse_superindex (GstAviDemux * avi,
+    GstBuffer * buf, guint64 ** _indexes)
+{
+  GstMapInfo map;
+  guint8 *data;
+  guint16 bpe = 16;
+  guint32 num, i;
+  guint64 *indexes;
+  gsize size;
+
+  *_indexes = NULL;
+
+  if (buf) {
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    data = map.data;
+    size = map.size;
+  } else {
+    data = NULL;
+    size = 0;
+  }
+
+  if (size < 24)
+    goto too_small;
+
+  /* check type of index. The opendml2 specs state that
+   * there should be 4 dwords per array entry. Type can be
+   * either frame or field (and we don't care). */
+  if (GST_READ_UINT16_LE (data) != 4 ||
+      (data[2] & 0xfe) != 0x0 || data[3] != 0x0) {
+    GST_WARNING_OBJECT (avi,
+        "Superindex for stream has unexpected "
+        "size_entry %d (bytes) or flags 0x%02x/0x%02x",
+        GST_READ_UINT16_LE (data), data[2], data[3]);
+    bpe = GST_READ_UINT16_LE (data) * 4;
+  }
+  num = GST_READ_UINT32_LE (&data[4]);
+
+  GST_DEBUG_OBJECT (avi, "got %d indexes", num);
+
+  /* this can't work out well ... */
+  if (num > G_MAXUINT32 >> 1 || bpe < 8) {
+    goto invalid_params;
+  }
+
+  indexes = g_new (guint64, num + 1);
+  for (i = 0; i < num; i++) {
+    if (size < 24 + bpe * (i + 1))
+      break;
+    indexes[i] = GST_READ_UINT64_LE (&data[24 + bpe * i]);
+    GST_DEBUG_OBJECT (avi, "index %d at %" G_GUINT64_FORMAT, i, indexes[i]);
+  }
+  indexes[i] = GST_BUFFER_OFFSET_NONE;
+  *_indexes = indexes;
+
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+
+  return TRUE;
+
+  /* ERRORS */
+too_small:
+  {
+    GST_ERROR_OBJECT (avi,
+        "Not enough data to parse superindex (%" G_GSIZE_FORMAT
+        " available, 24 needed)", size);
+    if (buf) {
+      gst_buffer_unmap (buf, &map);
+      gst_buffer_unref (buf);
+    }
+    return FALSE;
+  }
+invalid_params:
+  {
+    GST_ERROR_OBJECT (avi, "invalid index parameters (num = %d, bpe = %d)",
+        num, bpe);
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    return FALSE;
+  }
+}
+
+/* add an entry to the index of a stream. @num should be an estimate of the
+ * total amount of index entries for all streams and is used to dynamically
+ * allocate memory for the index entries. */
+static inline gboolean
+gst_avi_demux_add_index (GstAviDemux * avi, GstAviStream * stream,
+    guint num, GstAviIndexEntry * entry)
+{
+  /* ensure index memory */
+  if (G_UNLIKELY (stream->idx_n >= stream->idx_max)) {
+    guint idx_max = stream->idx_max;
+    GstAviIndexEntry *new_idx;
+
+    /* we need to make some more room */
+    if (idx_max == 0) {
+      /* initial size guess, assume each stream has an equal amount of entries,
+       * overshoot with at least 8K */
+      idx_max = (num / avi->num_streams) + (8192 / sizeof (GstAviIndexEntry));
+    } else {
+      idx_max += 8192 / sizeof (GstAviIndexEntry);
+      GST_DEBUG_OBJECT (avi, "expanded index from %u to %u",
+          stream->idx_max, idx_max);
+    }
+    new_idx = g_try_renew (GstAviIndexEntry, stream->index, idx_max);
+    /* out of memory, if this fails stream->index is untouched. */
+    if (G_UNLIKELY (!new_idx))
+      return FALSE;
+    /* use new index */
+    stream->index = new_idx;
+    stream->idx_max = idx_max;
+  }
+
+  /* update entry total and stream stats. The entry total can be converted to
+   * the timestamp of the entry easily. */
+  if (stream->strh->type == GST_RIFF_FCC_auds) {
+    gint blockalign;
+
+    if (stream->is_vbr) {
+      entry->total = stream->total_blocks;
+    } else {
+      entry->total = stream->total_bytes;
+    }
+    blockalign = stream->strf.auds->blockalign;
+    if (blockalign > 0)
+      stream->total_blocks += DIV_ROUND_UP (entry->size, blockalign);
+    else
+      stream->total_blocks++;
+  } else {
+    if (stream->is_vbr) {
+      entry->total = stream->idx_n;
+    } else {
+      entry->total = stream->total_bytes;
+    }
+  }
+  stream->total_bytes += entry->size;
+  if (ENTRY_IS_KEYFRAME (entry))
+    stream->n_keyframes++;
+
+  /* and add */
+  GST_LOG_OBJECT (avi,
+      "Adding stream %u, index entry %d, kf %d, size %u "
+      ", offset %" G_GUINT64_FORMAT ", total %" G_GUINT64_FORMAT, stream->num,
+      stream->idx_n, ENTRY_IS_KEYFRAME (entry), entry->size, entry->offset,
+      entry->total);
+  stream->index[stream->idx_n++] = *entry;
+
+  return TRUE;
+}
+
+/* given @entry_n in @stream, calculate info such as timestamps and
+ * offsets for the entry. */
+static void
+gst_avi_demux_get_buffer_info (GstAviDemux * avi, GstAviStream * stream,
+    guint entry_n, GstClockTime * timestamp, GstClockTime * ts_end,
+    guint64 * offset, guint64 * offset_end)
+{
+  GstAviIndexEntry *entry;
+
+  entry = &stream->index[entry_n];
+
+  if (stream->is_vbr) {
+    /* VBR stream next timestamp */
+    if (stream->strh->type == GST_RIFF_FCC_auds) {
+      if (timestamp)
+        *timestamp =
+            avi_stream_convert_frames_to_time_unchecked (stream, entry->total);
+      if (ts_end) {
+        gint size = 1;
+        if (G_LIKELY (entry_n + 1 < stream->idx_n))
+          size = stream->index[entry_n + 1].total - entry->total;
+        *ts_end = avi_stream_convert_frames_to_time_unchecked (stream,
+            entry->total + size);
+      }
+    } else {
+      if (timestamp)
+        *timestamp =
+            avi_stream_convert_frames_to_time_unchecked (stream, entry_n);
+      if (ts_end)
+        *ts_end = avi_stream_convert_frames_to_time_unchecked (stream,
+            entry_n + 1);
+    }
+  } else if (stream->strh->type == GST_RIFF_FCC_auds) {
+    /* constant rate stream */
+    if (timestamp)
+      *timestamp =
+          avi_stream_convert_bytes_to_time_unchecked (stream, entry->total);
+    if (ts_end)
+      *ts_end = avi_stream_convert_bytes_to_time_unchecked (stream,
+          entry->total + entry->size);
+  }
+  if (stream->strh->type == GST_RIFF_FCC_vids) {
+    /* video offsets are the frame number */
+    if (offset)
+      *offset = entry_n;
+    if (offset_end)
+      *offset_end = entry_n + 1;
+  } else {
+    /* no offsets for audio */
+    if (offset)
+      *offset = -1;
+    if (offset_end)
+      *offset_end = -1;
+  }
+}
+
+/* collect and debug stats about the indexes for all streams.
+ * This method is also responsible for filling in the stream duration
+ * as measured by the amount of index entries.
+ *
+ * Returns TRUE if the index is not empty, else FALSE */
+static gboolean
+gst_avi_demux_do_index_stats (GstAviDemux * avi)
+{
+  guint total_idx = 0;
+  guint i;
+#ifndef GST_DISABLE_GST_DEBUG
+  guint total_max = 0;
+#endif
+
+  /* get stream stats now */
+  for (i = 0; i < avi->num_streams; i++) {
+    GstAviStream *stream;
+
+    if (G_UNLIKELY (!(stream = &avi->stream[i])))
+      continue;
+    if (G_UNLIKELY (!stream->strh))
+      continue;
+    if (G_UNLIKELY (!stream->index || stream->idx_n == 0))
+      continue;
+
+    /* we interested in the end_ts of the last entry, which is the total
+     * duration of this stream */
+    gst_avi_demux_get_buffer_info (avi, stream, stream->idx_n - 1,
+        NULL, &stream->idx_duration, NULL, NULL);
+
+    total_idx += stream->idx_n;
+#ifndef GST_DISABLE_GST_DEBUG
+    total_max += stream->idx_max;
+#endif
+    GST_INFO_OBJECT (avi, "Stream %d, dur %" GST_TIME_FORMAT ", %6u entries, "
+        "%5u keyframes, entry size = %2u, total size = %10u, allocated %10u",
+        i, GST_TIME_ARGS (stream->idx_duration), stream->idx_n,
+        stream->n_keyframes, (guint) sizeof (GstAviIndexEntry),
+        (guint) (stream->idx_n * sizeof (GstAviIndexEntry)),
+        (guint) (stream->idx_max * sizeof (GstAviIndexEntry)));
+
+    /* knowing all that we do, that also includes avg bitrate */
+    if (!stream->taglist) {
+      stream->taglist = gst_tag_list_new_empty ();
+    }
+    if (stream->total_bytes && stream->idx_duration)
+      gst_tag_list_add (stream->taglist, GST_TAG_MERGE_REPLACE,
+          GST_TAG_BITRATE,
+          (guint) gst_util_uint64_scale (stream->total_bytes * 8,
+              GST_SECOND, stream->idx_duration), NULL);
+  }
+  total_idx *= sizeof (GstAviIndexEntry);
+#ifndef GST_DISABLE_GST_DEBUG
+  total_max *= sizeof (GstAviIndexEntry);
+#endif
+  GST_INFO_OBJECT (avi, "%u bytes for index vs %u ideally, %u wasted",
+      total_max, total_idx, total_max - total_idx);
+
+  if (total_idx == 0) {
+    GST_WARNING_OBJECT (avi, "Index is empty !");
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/*
+ * gst_avi_demux_parse_subindex:
+ * @avi: Avi object
+ * @buf: input data to use for parsing.
+ * @stream: stream context.
+ * @entries_list: a list (returned by the function) containing all the
+ *           indexes parsed in this specific subindex. The first
+ *           entry is also a pointer to allocated memory that needs
+ *           to be free´ed. May be NULL if no supported indexes were
+ *           found.
+ *
+ * Reads superindex (openDML-2 spec stuff) from the provided data.
+ * The buffer should contain a GST_RIFF_TAG_ix?? chunk.
+ *
+ * Returns: TRUE on success, FALSE otherwise. Errors are fatal, we
+ *          throw an error, caller should bail out asap.
+ */
+static gboolean
+gst_avi_demux_parse_subindex (GstAviDemux * avi, GstAviStream * stream,
+    GstBuffer * buf)
+{
+  GstMapInfo map;
+  guint8 *data;
+  guint16 bpe;
+  guint32 num, i;
+  guint64 baseoff;
+
+  if (buf == NULL)
+    return TRUE;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  data = map.data;
+
+  /* check size */
+  if (map.size < 24)
+    goto too_small;
+
+  /* We don't support index-data yet */
+  if (data[3] & 0x80)
+    goto not_implemented;
+
+  /* check type of index. The opendml2 specs state that
+   * there should be 4 dwords per array entry. Type can be
+   * either frame or field (and we don't care). */
+  bpe = (data[2] & 0x01) ? 12 : 8;
+  if (GST_READ_UINT16_LE (data) != bpe / 4 ||
+      (data[2] & 0xfe) != 0x0 || data[3] != 0x1) {
+    GST_WARNING_OBJECT (avi,
+        "Superindex for stream %d has unexpected "
+        "size_entry %d (bytes) or flags 0x%02x/0x%02x",
+        stream->num, GST_READ_UINT16_LE (data), data[2], data[3]);
+    bpe = GST_READ_UINT16_LE (data) * 4;
+  }
+  num = GST_READ_UINT32_LE (&data[4]);
+  baseoff = GST_READ_UINT64_LE (&data[12]);
+
+  /* If there's nothing, just return ! */
+  if (num == 0)
+    goto empty_index;
+
+  GST_INFO_OBJECT (avi, "Parsing subindex, nr_entries = %6d", num);
+
+  for (i = 0; i < num; i++) {
+    GstAviIndexEntry entry;
+
+    if (map.size < 24 + bpe * (i + 1))
+      break;
+
+    /* fill in offset and size. offset contains the keyframe flag in the
+     * upper bit*/
+    entry.offset = baseoff + GST_READ_UINT32_LE (&data[24 + bpe * i]);
+    entry.size = GST_READ_UINT32_LE (&data[24 + bpe * i + 4]);
+    /* handle flags */
+    if (stream->strh->type == GST_RIFF_FCC_auds) {
+      /* all audio frames are keyframes */
+      ENTRY_SET_KEYFRAME (&entry);
+    } else {
+      /* else read flags */
+      entry.flags = (entry.size & 0x80000000) ? 0 : GST_AVI_KEYFRAME;
+    }
+    entry.size &= ~0x80000000;
+
+    /* and add */
+    if (G_UNLIKELY (!gst_avi_demux_add_index (avi, stream, num, &entry)))
+      goto out_of_mem;
+  }
+done:
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+
+  return TRUE;
+
+  /* ERRORS */
+too_small:
+  {
+    GST_ERROR_OBJECT (avi,
+        "Not enough data to parse subindex (%" G_GSIZE_FORMAT
+        " available, 24 needed)", map.size);
+    goto done;                  /* continue */
+  }
+not_implemented:
+  {
+    GST_ELEMENT_ERROR (avi, STREAM, NOT_IMPLEMENTED, (NULL),
+        ("Subindex-is-data is not implemented"));
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    return FALSE;
+  }
+empty_index:
+  {
+    GST_DEBUG_OBJECT (avi, "the index is empty");
+    goto done;                  /* continue */
+  }
+out_of_mem:
+  {
+    GST_ELEMENT_ERROR (avi, RESOURCE, NO_SPACE_LEFT, (NULL),
+        ("Cannot allocate memory for %u*%u=%u bytes",
+            (guint) sizeof (GstAviIndexEntry), num,
+            (guint) sizeof (GstAviIndexEntry) * num));
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    return FALSE;
+  }
+}
+
+/*
+ * Create and push a flushing seek event upstream
+ */
+static gboolean
+perform_seek_to_offset (GstAviDemux * demux, guint64 offset, guint32 seqnum)
+{
+  GstEvent *event;
+  gboolean res = 0;
+
+  GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
+
+  event =
+      gst_event_new_seek (1.0, GST_FORMAT_BYTES,
+      GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
+      GST_SEEK_TYPE_NONE, -1);
+  gst_event_set_seqnum (event, seqnum);
+  res = gst_pad_push_event (demux->sinkpad, event);
+
+  if (res)
+    demux->offset = offset;
+  return res;
+}
+
+/*
+ * Read AVI index when streaming
+ */
+static gboolean
+gst_avi_demux_read_subindexes_push (GstAviDemux * avi)
+{
+  guint32 tag = 0, size;
+  GstBuffer *buf = NULL;
+  guint odml_stream;
+
+  GST_DEBUG_OBJECT (avi, "read subindexes for %d streams", avi->num_streams);
+
+  if (avi->odml_subidxs[avi->odml_subidx] != avi->offset)
+    return FALSE;
+
+  if (!gst_avi_demux_peek_chunk (avi, &tag, &size))
+    return TRUE;
+
+  /* this is the ODML chunk we expect */
+  odml_stream = avi->odml_stream;
+
+  if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + odml_stream / 10,
+              '0' + odml_stream % 10)) &&
+      (tag != GST_MAKE_FOURCC ('0' + odml_stream / 10,
+              '0' + odml_stream % 10, 'i', 'x'))) {
+    GST_WARNING_OBJECT (avi, "Not an ix## chunk (%" GST_FOURCC_FORMAT ")",
+        GST_FOURCC_ARGS (tag));
+    return FALSE;
+  }
+
+  avi->offset += 8 + GST_ROUND_UP_2 (size);
+  /* flush chunk header so we get just the 'size' payload data */
+  gst_adapter_flush (avi->adapter, 8);
+  buf = gst_adapter_take_buffer (avi->adapter, size);
+
+  if (!gst_avi_demux_parse_subindex (avi, &avi->stream[odml_stream], buf))
+    return FALSE;
+
+  /* we parsed the index, go to next subindex */
+  avi->odml_subidx++;
+
+  if (avi->odml_subidxs[avi->odml_subidx] == GST_BUFFER_OFFSET_NONE) {
+    /* we reached the end of the indexes for this stream, move to the next
+     * stream to handle the first index */
+    avi->odml_stream++;
+    avi->odml_subidx = 0;
+
+    if (avi->odml_stream < avi->num_streams) {
+      /* there are more indexes */
+      avi->odml_subidxs = avi->stream[avi->odml_stream].indexes;
+    } else {
+      /* we're done, get stream stats now */
+      avi->have_index = gst_avi_demux_do_index_stats (avi);
+
+      return TRUE;
+    }
+  }
+
+  /* seek to next index */
+  return perform_seek_to_offset (avi, avi->odml_subidxs[avi->odml_subidx],
+      avi->segment_seqnum);
+}
+
+/*
+ * Read AVI index
+ */
+static void
+gst_avi_demux_read_subindexes_pull (GstAviDemux * avi)
+{
+  guint32 tag;
+  GstBuffer *buf;
+  gint i, n;
+
+  GST_DEBUG_OBJECT (avi, "read subindexes for %d streams", avi->num_streams);
+
+  for (n = 0; n < avi->num_streams; n++) {
+    GstAviStream *stream = &avi->stream[n];
+
+    if (stream->indexes == NULL)
+      continue;
+
+    for (i = 0; stream->indexes[i] != GST_BUFFER_OFFSET_NONE; i++) {
+      if (gst_riff_read_chunk (GST_ELEMENT_CAST (avi), avi->sinkpad,
+              &stream->indexes[i], &tag, &buf) != GST_FLOW_OK)
+        continue;
+      else if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream->num / 10,
+                  '0' + stream->num % 10)) &&
+          (tag != GST_MAKE_FOURCC ('0' + stream->num / 10,
+                  '0' + stream->num % 10, 'i', 'x'))) {
+        /* Some ODML files (created by god knows what muxer) have a ##ix format
+         * instead of the 'official' ix##. They are still valid though. */
+        GST_WARNING_OBJECT (avi, "Not an ix## chunk (%" GST_FOURCC_FORMAT ")",
+            GST_FOURCC_ARGS (tag));
+        gst_buffer_unref (buf);
+        continue;
+      }
+
+      if (!gst_avi_demux_parse_subindex (avi, stream, buf))
+        continue;
+    }
+
+    g_free (stream->indexes);
+    stream->indexes = NULL;
+  }
+  /* get stream stats now */
+  avi->have_index = gst_avi_demux_do_index_stats (avi);
+}
+
+/*
+ * gst_avi_demux_riff_parse_vprp:
+ * @element: caller element (used for debugging/error).
+ * @buf: input data to be used for parsing, stripped from header.
+ * @vprp: a pointer (returned by this function) to a filled-in vprp
+ *        structure. Caller should free it.
+ *
+ * Parses a video stream´s vprp. This function takes ownership of @buf.
+ *
+ * Returns: TRUE if parsing succeeded, otherwise FALSE. The stream
+ *          should be skipped on error, but it is not fatal.
+ */
+static gboolean
+gst_avi_demux_riff_parse_vprp (GstElement * element,
+    GstBuffer * buf, gst_riff_vprp ** _vprp)
+{
+  gst_riff_vprp *vprp;
+  gint k;
+  gsize size;
+
+  g_return_val_if_fail (buf != NULL, FALSE);
+  g_return_val_if_fail (_vprp != NULL, FALSE);
+
+  size = gst_buffer_get_size (buf);
+
+  if (size < G_STRUCT_OFFSET (gst_riff_vprp, field_info))
+    goto too_small;
+
+  vprp = g_malloc (size);
+  gst_buffer_extract (buf, 0, vprp, size);
+
+#if (G_BYTE_ORDER == G_BIG_ENDIAN)
+  vprp->format_token = GUINT32_FROM_LE (vprp->format_token);
+  vprp->standard = GUINT32_FROM_LE (vprp->standard);
+  vprp->vert_rate = GUINT32_FROM_LE (vprp->vert_rate);
+  vprp->hor_t_total = GUINT32_FROM_LE (vprp->hor_t_total);
+  vprp->vert_lines = GUINT32_FROM_LE (vprp->vert_lines);
+  vprp->aspect = GUINT32_FROM_LE (vprp->aspect);
+  vprp->width = GUINT32_FROM_LE (vprp->width);
+  vprp->height = GUINT32_FROM_LE (vprp->height);
+  vprp->fields = GUINT32_FROM_LE (vprp->fields);
+#endif
+
+  /* size checking */
+  /* calculate fields based on size */
+  k = (size - G_STRUCT_OFFSET (gst_riff_vprp, field_info)) / vprp->fields;
+  if (vprp->fields > k) {
+    GST_WARNING_OBJECT (element,
+        "vprp header indicated %d fields, only %d available", vprp->fields, k);
+    vprp->fields = k;
+  }
+  if (vprp->fields > GST_RIFF_VPRP_VIDEO_FIELDS) {
+    GST_WARNING_OBJECT (element,
+        "vprp header indicated %d fields, at most %d supported", vprp->fields,
+        GST_RIFF_VPRP_VIDEO_FIELDS);
+    vprp->fields = GST_RIFF_VPRP_VIDEO_FIELDS;
+  }
+#if (G_BYTE_ORDER == G_BIG_ENDIAN)
+  for (k = 0; k < vprp->fields; k++) {
+    gst_riff_vprp_video_field_desc *fd;
+
+    fd = &vprp->field_info[k];
+    fd->compressed_bm_height = GUINT32_FROM_LE (fd->compressed_bm_height);
+    fd->compressed_bm_width = GUINT32_FROM_LE (fd->compressed_bm_width);
+    fd->valid_bm_height = GUINT32_FROM_LE (fd->valid_bm_height);
+    fd->valid_bm_width = GUINT16_FROM_LE (fd->valid_bm_width);
+    fd->valid_bm_x_offset = GUINT16_FROM_LE (fd->valid_bm_x_offset);
+    fd->valid_bm_y_offset = GUINT32_FROM_LE (fd->valid_bm_y_offset);
+    fd->video_x_t_offset = GUINT32_FROM_LE (fd->video_x_t_offset);
+    fd->video_y_start = GUINT32_FROM_LE (fd->video_y_start);
+  }
+#endif
+
+  /* debug */
+  GST_INFO_OBJECT (element, "vprp tag found in context vids:");
+  GST_INFO_OBJECT (element, " format_token  %d", vprp->format_token);
+  GST_INFO_OBJECT (element, " standard      %d", vprp->standard);
+  GST_INFO_OBJECT (element, " vert_rate     %d", vprp->vert_rate);
+  GST_INFO_OBJECT (element, " hor_t_total   %d", vprp->hor_t_total);
+  GST_INFO_OBJECT (element, " vert_lines    %d", vprp->vert_lines);
+  GST_INFO_OBJECT (element, " aspect        %d:%d", vprp->aspect >> 16,
+      vprp->aspect & 0xffff);
+  GST_INFO_OBJECT (element, " width         %d", vprp->width);
+  GST_INFO_OBJECT (element, " height        %d", vprp->height);
+  GST_INFO_OBJECT (element, " fields        %d", vprp->fields);
+  for (k = 0; k < vprp->fields; k++) {
+    gst_riff_vprp_video_field_desc *fd;
+
+    fd = &(vprp->field_info[k]);
+    GST_INFO_OBJECT (element, " field %u description:", k);
+    GST_INFO_OBJECT (element, "  compressed_bm_height  %d",
+        fd->compressed_bm_height);
+    GST_INFO_OBJECT (element, "  compressed_bm_width  %d",
+        fd->compressed_bm_width);
+    GST_INFO_OBJECT (element, "  valid_bm_height       %d",
+        fd->valid_bm_height);
+    GST_INFO_OBJECT (element, "  valid_bm_width        %d", fd->valid_bm_width);
+    GST_INFO_OBJECT (element, "  valid_bm_x_offset     %d",
+        fd->valid_bm_x_offset);
+    GST_INFO_OBJECT (element, "  valid_bm_y_offset     %d",
+        fd->valid_bm_y_offset);
+    GST_INFO_OBJECT (element, "  video_x_t_offset      %d",
+        fd->video_x_t_offset);
+    GST_INFO_OBJECT (element, "  video_y_start         %d", fd->video_y_start);
+  }
+
+  gst_buffer_unref (buf);
+
+  *_vprp = vprp;
+
+  return TRUE;
+
+  /* ERRORS */
+too_small:
+  {
+    GST_ERROR_OBJECT (element,
+        "Too small vprp (%" G_GSIZE_FORMAT " available, at least %d needed)",
+        size, (int) G_STRUCT_OFFSET (gst_riff_vprp, field_info));
+    gst_buffer_unref (buf);
+    return FALSE;
+  }
+}
+
+static void
+gst_avi_demux_expose_streams (GstAviDemux * avi, gboolean force)
+{
+  guint i;
+
+  GST_DEBUG_OBJECT (avi, "force : %d", force);
+
+  for (i = 0; i < avi->num_streams; i++) {
+    GstAviStream *stream = &avi->stream[i];
+
+    if (force || stream->idx_n != 0) {
+      GST_LOG_OBJECT (avi, "Adding pad %s", GST_PAD_NAME (stream->pad));
+      gst_element_add_pad ((GstElement *) avi, stream->pad);
+      gst_flow_combiner_add_pad (avi->flowcombiner, stream->pad);
+
+#if 0
+      if (avi->element_index)
+        gst_index_get_writer_id (avi->element_index,
+            GST_OBJECT_CAST (stream->pad), &stream->index_id);
+#endif
+
+      stream->exposed = TRUE;
+      if (avi->main_stream == -1)
+        avi->main_stream = i;
+    } else {
+      GST_WARNING_OBJECT (avi, "Stream #%d doesn't have any entry, removing it",
+          i);
+      gst_avi_demux_reset_stream (avi, stream);
+    }
+  }
+}
+
+/* buf contains LIST chunk data, and will be padded to even size,
+ * since some buggy files do not account for the padding of chunks
+ * within a LIST in the size of the LIST */
+static inline void
+gst_avi_demux_roundup_list (GstAviDemux * avi, GstBuffer ** buf)
+{
+  gsize size;
+
+  size = gst_buffer_get_size (*buf);
+
+  if (G_UNLIKELY (size & 1)) {
+    GstBuffer *obuf;
+    GstMapInfo map;
+
+    GST_DEBUG_OBJECT (avi, "rounding up dubious list size %" G_GSIZE_FORMAT,
+        size);
+    obuf = gst_buffer_new_and_alloc (size + 1);
+
+    gst_buffer_map (obuf, &map, GST_MAP_WRITE);
+    gst_buffer_extract (*buf, 0, map.data, size);
+    /* assume 0 padding, at least makes outcome deterministic */
+    map.data[size] = 0;
+    gst_buffer_unmap (obuf, &map);
+    gst_buffer_replace (buf, obuf);
+  }
+}
+
+static GstCaps *
+gst_avi_demux_check_caps (GstAviDemux * avi, GstAviStream * stream,
+    GstCaps * caps)
+{
+  GstStructure *s;
+  const GValue *val;
+  GstBuffer *buf;
+
+  caps = gst_caps_make_writable (caps);
+
+  s = gst_caps_get_structure (caps, 0);
+  if (gst_structure_has_name (s, "video/x-raw")) {
+    stream->is_raw = TRUE;
+    stream->alignment = 32;
+    if (!gst_structure_has_field (s, "pixel-aspect-ratio"))
+      gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+          1, 1, NULL);
+    if (gst_structure_has_field_typed (s, "palette_data", GST_TYPE_BUFFER)) {
+      gst_structure_get (s, "palette_data", GST_TYPE_BUFFER,
+          &stream->rgb8_palette, NULL);
+      gst_structure_remove_field (s, "palette_data");
+      return caps;
+    }
+  } else if (!gst_structure_has_name (s, "video/x-h264")) {
+    return caps;
+  }
+
+  GST_DEBUG_OBJECT (avi, "checking caps %" GST_PTR_FORMAT, caps);
+
+  /* some muxers put invalid bytestream stuff in h264 extra data */
+  val = gst_structure_get_value (s, "codec_data");
+  if (val && (buf = gst_value_get_buffer (val))) {
+    guint8 *data;
+    gint size;
+    GstMapInfo map;
+
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    data = map.data;
+    size = map.size;
+    if (size >= 4) {
+      guint32 h = GST_READ_UINT32_BE (data);
+      gst_buffer_unmap (buf, &map);
+      if (h == 0x01) {
+        /* can hardly be valid AVC codec data */
+        GST_DEBUG_OBJECT (avi,
+            "discarding invalid codec_data containing byte-stream");
+        /* so do not pretend to downstream that it is packetized avc */
+        gst_structure_remove_field (s, "codec_data");
+        /* ... but rather properly parsed bytestream */
+        gst_structure_set (s, "stream-format", G_TYPE_STRING, "byte-stream",
+            "alignment", G_TYPE_STRING, "au", NULL);
+      }
+    } else {
+      gst_buffer_unmap (buf, &map);
+    }
+  }
+
+  return caps;
+}
+
+/*
+ * gst_avi_demux_parse_stream:
+ * @avi: calling element (used for debugging/errors).
+ * @buf: input buffer used to parse the stream.
+ *
+ * Parses all subchunks in a strl chunk (which defines a single
+ * stream). Discards the buffer after use. This function will
+ * increment the stream counter internally.
+ *
+ * Returns: whether the stream was identified successfully.
+ *          Errors are not fatal. It does indicate the stream
+ *          was skipped.
+ */
+static gboolean
+gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf)
+{
+  GstAviStream *stream;
+  GstElementClass *klass;
+  GstPadTemplate *templ;
+  GstBuffer *sub = NULL;
+  guint offset = 4;
+  guint32 tag = 0;
+  gchar *codec_name = NULL, *padname = NULL;
+  const gchar *tag_name;
+  GstCaps *caps = NULL;
+  GstPad *pad;
+  GstElement *element;
+  gboolean got_strh = FALSE, got_strf = FALSE, got_vprp = FALSE;
+  gst_riff_vprp *vprp = NULL;
+  GstEvent *event;
+  gchar *stream_id;
+  GstMapInfo map;
+  gboolean sparse = FALSE;
+
+  element = GST_ELEMENT_CAST (avi);
+
+  GST_DEBUG_OBJECT (avi, "Parsing stream");
+
+  gst_avi_demux_roundup_list (avi, &buf);
+
+  if (avi->num_streams >= GST_AVI_DEMUX_MAX_STREAMS) {
+    GST_WARNING_OBJECT (avi,
+        "maximum no of streams (%d) exceeded, ignoring stream",
+        GST_AVI_DEMUX_MAX_STREAMS);
+    gst_buffer_unref (buf);
+    /* not a fatal error, let's say */
+    return TRUE;
+  }
+
+  stream = &avi->stream[avi->num_streams];
+
+  /* initial settings */
+  stream->idx_duration = GST_CLOCK_TIME_NONE;
+  stream->hdr_duration = GST_CLOCK_TIME_NONE;
+  stream->duration = GST_CLOCK_TIME_NONE;
+
+  while (gst_riff_parse_chunk (element, buf, &offset, &tag, &sub)) {
+    /* sub can be NULL if the chunk is empty */
+    if (sub == NULL) {
+      GST_DEBUG_OBJECT (avi, "ignoring empty chunk %" GST_FOURCC_FORMAT,
+          GST_FOURCC_ARGS (tag));
+      continue;
+    }
+    switch (tag) {
+      case GST_RIFF_TAG_strh:
+      {
+        gst_riff_strh *strh;
+
+        if (got_strh) {
+          GST_WARNING_OBJECT (avi, "Ignoring additional strh chunk");
+          break;
+        }
+        if (!gst_riff_parse_strh (element, sub, &stream->strh)) {
+          /* ownership given away */
+          sub = NULL;
+          GST_WARNING_OBJECT (avi, "Failed to parse strh chunk");
+          goto fail;
+        }
+        sub = NULL;
+        strh = stream->strh;
+        /* sanity check; stream header frame rate matches global header
+         * frame duration */
+        if (stream->strh->type == GST_RIFF_FCC_vids) {
+          GstClockTime s_dur;
+          GstClockTime h_dur = avi->avih->us_frame * GST_USECOND;
+
+          s_dur = gst_util_uint64_scale (GST_SECOND, strh->scale, strh->rate);
+          GST_DEBUG_OBJECT (avi, "verifying stream framerate %d/%d, "
+              "frame duration = %d ms", strh->rate, strh->scale,
+              (gint) (s_dur / GST_MSECOND));
+          if (h_dur > (10 * GST_MSECOND) && (s_dur > 10 * h_dur)) {
+            strh->rate = GST_SECOND / GST_USECOND;
+            strh->scale = h_dur / GST_USECOND;
+            GST_DEBUG_OBJECT (avi, "correcting stream framerate to %d/%d",
+                strh->rate, strh->scale);
+          }
+        }
+        /* determine duration as indicated by header */
+        stream->hdr_duration = gst_util_uint64_scale ((guint64) strh->length *
+            strh->scale, GST_SECOND, (guint64) strh->rate);
+        GST_INFO ("Stream duration according to header: %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (stream->hdr_duration));
+        if (stream->hdr_duration == 0)
+          stream->hdr_duration = GST_CLOCK_TIME_NONE;
+
+        got_strh = TRUE;
+        break;
+      }
+      case GST_RIFF_TAG_strf:
+      {
+        gboolean res = FALSE;
+
+        if (got_strf) {
+          GST_WARNING_OBJECT (avi, "Ignoring additional strf chunk");
+          break;
+        }
+        if (!got_strh) {
+          GST_ERROR_OBJECT (avi, "Found strf chunk before strh chunk");
+          goto fail;
+        }
+        switch (stream->strh->type) {
+          case GST_RIFF_FCC_vids:
+            stream->is_vbr = TRUE;
+            res = gst_riff_parse_strf_vids (element, sub,
+                &stream->strf.vids, &stream->extradata);
+            sub = NULL;
+            GST_DEBUG_OBJECT (element, "marking video as VBR, res %d", res);
+            break;
+          case GST_RIFF_FCC_auds:
+            res =
+                gst_riff_parse_strf_auds (element, sub, &stream->strf.auds,
+                &stream->extradata);
+            sub = NULL;
+            if (!res)
+              break;
+            stream->is_vbr = (stream->strh->samplesize == 0)
+                && stream->strh->scale > 1
+                && stream->strf.auds->blockalign != 1;
+            GST_DEBUG_OBJECT (element, "marking audio as VBR:%d, res %d",
+                stream->is_vbr, res);
+            /* we need these or we have no way to come up with timestamps */
+            if ((!stream->is_vbr && !stream->strf.auds->av_bps) ||
+                (stream->is_vbr && (!stream->strh->scale ||
+                        !stream->strh->rate))) {
+              GST_WARNING_OBJECT (element,
+                  "invalid audio header, ignoring stream");
+              goto fail;
+            }
+            /* some more sanity checks */
+            if (stream->is_vbr) {
+              if (stream->strf.auds->blockalign <= 4) {
+                /* that would mean (too) many frames per chunk,
+                 * so not likely set as expected */
+                GST_DEBUG_OBJECT (element,
+                    "suspicious blockalign %d for VBR audio; "
+                    "overriding to 1 frame per chunk",
+                    stream->strf.auds->blockalign);
+                /* this should top any likely value */
+                stream->strf.auds->blockalign = (1 << 12);
+              }
+            }
+            break;
+          case GST_RIFF_FCC_iavs:
+            stream->is_vbr = TRUE;
+            res = gst_riff_parse_strf_iavs (element, sub,
+                &stream->strf.iavs, &stream->extradata);
+            sub = NULL;
+            GST_DEBUG_OBJECT (element, "marking iavs as VBR, res %d", res);
+            break;
+          case GST_RIFF_FCC_txts:
+            /* nothing to parse here */
+            stream->is_vbr = (stream->strh->samplesize == 0)
+                && (stream->strh->scale > 1);
+            res = TRUE;
+            break;
+          default:
+            GST_ERROR_OBJECT (avi,
+                "Don´t know how to handle stream type %" GST_FOURCC_FORMAT,
+                GST_FOURCC_ARGS (stream->strh->type));
+            break;
+        }
+        if (sub) {
+          gst_buffer_unref (sub);
+          sub = NULL;
+        }
+        if (!res)
+          goto fail;
+        got_strf = TRUE;
+        break;
+      }
+      case GST_RIFF_TAG_vprp:
+      {
+        if (got_vprp) {
+          GST_WARNING_OBJECT (avi, "Ignoring additional vprp chunk");
+          break;
+        }
+        if (!got_strh) {
+          GST_ERROR_OBJECT (avi, "Found vprp chunk before strh chunk");
+          goto fail;
+        }
+        if (!got_strf) {
+          GST_ERROR_OBJECT (avi, "Found vprp chunk before strf chunk");
+          goto fail;
+        }
+
+        if (!gst_avi_demux_riff_parse_vprp (element, sub, &vprp)) {
+          GST_WARNING_OBJECT (avi, "Failed to parse vprp chunk");
+          /* not considered fatal */
+          g_free (vprp);
+          vprp = NULL;
+        } else
+          got_vprp = TRUE;
+        sub = NULL;
+        break;
+      }
+      case GST_RIFF_TAG_strd:
+        if (stream->initdata)
+          gst_buffer_unref (stream->initdata);
+        stream->initdata = sub;
+        if (sub != NULL) {
+          gst_avi_demux_parse_strd (avi, sub);
+          sub = NULL;
+        }
+        break;
+      case GST_RIFF_TAG_strn:
+        g_free (stream->name);
+
+        gst_buffer_map (sub, &map, GST_MAP_READ);
+
+        if (avi->globaltags == NULL)
+          avi->globaltags = gst_tag_list_new_empty ();
+        parse_tag_value (avi, avi->globaltags, GST_TAG_TITLE,
+            map.data, map.size);
+
+        if (gst_tag_list_get_string (avi->globaltags, GST_TAG_TITLE,
+                &stream->name))
+          GST_DEBUG_OBJECT (avi, "stream name: %s", stream->name);
+
+        gst_buffer_unmap (sub, &map);
+        gst_buffer_unref (sub);
+        sub = NULL;
+        break;
+      case GST_RIFF_IDIT:
+        gst_avi_demux_parse_idit (avi, sub);
+        break;
+      default:
+        if (tag == GST_MAKE_FOURCC ('i', 'n', 'd', 'x') ||
+            tag == GST_MAKE_FOURCC ('i', 'x', '0' + avi->num_streams / 10,
+                '0' + avi->num_streams % 10)) {
+          g_free (stream->indexes);
+          gst_avi_demux_parse_superindex (avi, sub, &stream->indexes);
+          stream->superindex = TRUE;
+          sub = NULL;
+          break;
+        }
+        GST_WARNING_OBJECT (avi,
+            "Unknown stream header tag %" GST_FOURCC_FORMAT ", ignoring",
+            GST_FOURCC_ARGS (tag));
+        /* Only get buffer for debugging if the memdump is needed  */
+        if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= 9) {
+          GstMapInfo map;
+
+          gst_buffer_map (sub, &map, GST_MAP_READ);
+          GST_MEMDUMP_OBJECT (avi, "Unknown stream header tag", map.data,
+              map.size);
+          gst_buffer_unmap (sub, &map);
+        }
+        /* fall-through */
+      case GST_RIFF_TAG_JUNQ:
+      case GST_RIFF_TAG_JUNK:
+        break;
+    }
+    if (sub != NULL) {
+      gst_buffer_unref (sub);
+      sub = NULL;
+    }
+  }
+
+  if (!got_strh) {
+    GST_WARNING_OBJECT (avi, "Failed to find strh chunk");
+    goto fail;
+  }
+
+  if (!got_strf) {
+    GST_WARNING_OBJECT (avi, "Failed to find strf chunk");
+    goto fail;
+  }
+
+  /* get class to figure out the template */
+  klass = GST_ELEMENT_GET_CLASS (avi);
+
+  /* we now have all info, let´s set up a pad and a caps and be done */
+  /* create stream name + pad */
+  switch (stream->strh->type) {
+    case GST_RIFF_FCC_vids:{
+      guint32 fourcc;
+
+      fourcc = (stream->strf.vids->compression) ?
+          stream->strf.vids->compression : stream->strh->fcc_handler;
+      caps = gst_riff_create_video_caps (fourcc, stream->strh,
+          stream->strf.vids, stream->extradata, stream->initdata, &codec_name);
+
+      /* DXSB is XSUB, and it is placed inside a vids */
+      if (!caps || (fourcc != GST_MAKE_FOURCC ('D', 'X', 'S', 'B') &&
+              fourcc != GST_MAKE_FOURCC ('D', 'X', 'S', 'A'))) {
+        padname = g_strdup_printf ("video_%u", avi->num_v_streams);
+        templ = gst_element_class_get_pad_template (klass, "video_%u");
+        if (!caps) {
+          caps = gst_caps_new_simple ("video/x-avi-unknown", "fourcc",
+              G_TYPE_INT, fourcc, NULL);
+        } else if (got_vprp && vprp) {
+          guint32 aspect_n, aspect_d;
+          gint n, d;
+
+          aspect_n = vprp->aspect >> 16;
+          aspect_d = vprp->aspect & 0xffff;
+          /* calculate the pixel aspect ratio using w/h and aspect ratio */
+          n = aspect_n * stream->strf.vids->height;
+          d = aspect_d * stream->strf.vids->width;
+          if (n && d)
+            gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+                n, d, NULL);
+        }
+        caps = gst_avi_demux_check_caps (avi, stream, caps);
+        tag_name = GST_TAG_VIDEO_CODEC;
+        avi->num_v_streams++;
+      } else {
+        padname = g_strdup_printf ("subpicture_%u", avi->num_sp_streams);
+        templ = gst_element_class_get_pad_template (klass, "subpicture_%u");
+        tag_name = NULL;
+        avi->num_sp_streams++;
+        sparse = TRUE;
+      }
+      break;
+    }
+    case GST_RIFF_FCC_auds:{
+      /* FIXME: Do something with the channel reorder map */
+      padname = g_strdup_printf ("audio_%u", avi->num_a_streams);
+      templ = gst_element_class_get_pad_template (klass, "audio_%u");
+      caps = gst_riff_create_audio_caps (stream->strf.auds->format,
+          stream->strh, stream->strf.auds, stream->extradata,
+          stream->initdata, &codec_name, NULL);
+      if (!caps) {
+        caps = gst_caps_new_simple ("audio/x-avi-unknown", "codec_id",
+            G_TYPE_INT, stream->strf.auds->format, NULL);
+      }
+      tag_name = GST_TAG_AUDIO_CODEC;
+      avi->num_a_streams++;
+      break;
+    }
+    case GST_RIFF_FCC_iavs:{
+      guint32 fourcc = stream->strh->fcc_handler;
+
+      padname = g_strdup_printf ("video_%u", avi->num_v_streams);
+      templ = gst_element_class_get_pad_template (klass, "video_%u");
+      caps = gst_riff_create_iavs_caps (fourcc, stream->strh,
+          stream->strf.iavs, stream->extradata, stream->initdata, &codec_name);
+      if (!caps) {
+        caps = gst_caps_new_simple ("video/x-avi-unknown", "fourcc",
+            G_TYPE_INT, fourcc, NULL);
+      }
+      tag_name = GST_TAG_VIDEO_CODEC;
+      avi->num_v_streams++;
+      break;
+    }
+    case GST_RIFF_FCC_txts:{
+      padname = g_strdup_printf ("subtitle_%u", avi->num_t_streams);
+      templ = gst_element_class_get_pad_template (klass, "subtitle_%u");
+      caps = gst_caps_new_empty_simple ("application/x-subtitle-avi");
+      tag_name = NULL;
+      avi->num_t_streams++;
+      sparse = TRUE;
+      break;
+    }
+    default:
+      g_return_val_if_reached (FALSE);
+  }
+
+  /* no caps means no stream */
+  if (!caps) {
+    GST_ERROR_OBJECT (element, "Did not find caps for stream %s", padname);
+    goto fail;
+  }
+
+  GST_DEBUG_OBJECT (element, "codec-name=%s", codec_name ? codec_name : "NULL");
+  GST_DEBUG_OBJECT (element, "caps=%" GST_PTR_FORMAT, caps);
+
+  /* set proper settings and add it */
+  if (stream->pad)
+    gst_object_unref (stream->pad);
+  pad = stream->pad = gst_pad_new_from_template (templ, padname);
+  g_free (padname);
+
+  gst_pad_use_fixed_caps (pad);
+#if 0
+  gst_pad_set_formats_function (pad,
+      GST_DEBUG_FUNCPTR (gst_avi_demux_get_src_formats));
+  gst_pad_set_event_mask_function (pad,
+      GST_DEBUG_FUNCPTR (gst_avi_demux_get_event_mask));
+#endif
+  gst_pad_set_event_function (pad,
+      GST_DEBUG_FUNCPTR (gst_avi_demux_handle_src_event));
+  gst_pad_set_query_function (pad,
+      GST_DEBUG_FUNCPTR (gst_avi_demux_handle_src_query));
+#if 0
+  gst_pad_set_convert_function (pad,
+      GST_DEBUG_FUNCPTR (gst_avi_demux_src_convert));
+#endif
+
+  stream->num = avi->num_streams;
+
+  stream->start_entry = 0;
+  stream->step_entry = 0;
+  stream->stop_entry = 0;
+
+  stream->current_entry = -1;
+  stream->current_total = 0;
+
+  stream->discont = TRUE;
+
+  stream->total_bytes = 0;
+  stream->total_blocks = 0;
+  stream->n_keyframes = 0;
+
+  stream->idx_n = 0;
+  stream->idx_max = 0;
+
+  gst_pad_set_element_private (pad, stream);
+  avi->num_streams++;
+
+  gst_pad_set_active (pad, TRUE);
+  stream_id =
+      gst_pad_create_stream_id_printf (pad, GST_ELEMENT_CAST (avi), "%03u",
+      avi->num_streams);
+
+  event = gst_pad_get_sticky_event (avi->sinkpad, GST_EVENT_STREAM_START, 0);
+  if (event) {
+    if (gst_event_parse_group_id (event, &avi->group_id))
+      avi->have_group_id = TRUE;
+    else
+      avi->have_group_id = FALSE;
+    gst_event_unref (event);
+  } else if (!avi->have_group_id) {
+    avi->have_group_id = TRUE;
+    avi->group_id = gst_util_group_id_next ();
+  }
+
+  event = gst_event_new_stream_start (stream_id);
+  if (avi->have_group_id)
+    gst_event_set_group_id (event, avi->group_id);
+  if (sparse)
+    gst_event_set_stream_flags (event, GST_STREAM_FLAG_SPARSE);
+
+  gst_pad_push_event (pad, event);
+  g_free (stream_id);
+  gst_pad_set_caps (pad, caps);
+  gst_caps_unref (caps);
+
+  /* make tags */
+  if (codec_name && tag_name) {
+    if (!stream->taglist)
+      stream->taglist = gst_tag_list_new_empty ();
+
+    avi->got_tags = TRUE;
+
+    gst_tag_list_add (stream->taglist, GST_TAG_MERGE_APPEND, tag_name,
+        codec_name, NULL);
+  }
+
+  g_free (vprp);
+  g_free (codec_name);
+  gst_buffer_unref (buf);
+
+  return TRUE;
+
+  /* ERRORS */
+fail:
+  {
+    /* unref any mem that may be in use */
+    if (buf)
+      gst_buffer_unref (buf);
+    if (sub)
+      gst_buffer_unref (sub);
+    g_free (vprp);
+    g_free (codec_name);
+    gst_avi_demux_reset_stream (avi, stream);
+    avi->num_streams++;
+    return FALSE;
+  }
+}
+
+/*
+ * gst_avi_demux_parse_odml:
+ * @avi: calling element (used for debug/error).
+ * @buf: input buffer to be used for parsing.
+ *
+ * Read an openDML-2.0 extension header. Fills in the frame number
+ * in the avi demuxer object when reading succeeds.
+ */
+static void
+gst_avi_demux_parse_odml (GstAviDemux * avi, GstBuffer * buf)
+{
+  guint32 tag = 0;
+  guint offset = 4;
+  GstBuffer *sub = NULL;
+
+  while (gst_riff_parse_chunk (GST_ELEMENT_CAST (avi), buf, &offset, &tag,
+          &sub)) {
+    switch (tag) {
+      case GST_RIFF_TAG_dmlh:{
+        gst_riff_dmlh dmlh, *_dmlh;
+        GstMapInfo map;
+
+        /* sub == NULL is possible and means an empty buffer */
+        if (sub == NULL)
+          goto next;
+
+        gst_buffer_map (sub, &map, GST_MAP_READ);
+
+        /* check size */
+        if (map.size < sizeof (gst_riff_dmlh)) {
+          GST_ERROR_OBJECT (avi,
+              "DMLH entry is too small (%" G_GSIZE_FORMAT " bytes, %d needed)",
+              map.size, (int) sizeof (gst_riff_dmlh));
+          gst_buffer_unmap (sub, &map);
+          goto next;
+        }
+        _dmlh = (gst_riff_dmlh *) map.data;
+        dmlh.totalframes = GST_READ_UINT32_LE (&_dmlh->totalframes);
+        gst_buffer_unmap (sub, &map);
+
+        GST_INFO_OBJECT (avi, "dmlh tag found: totalframes: %u",
+            dmlh.totalframes);
+
+        avi->avih->tot_frames = dmlh.totalframes;
+        goto next;
+      }
+
+      default:
+        GST_WARNING_OBJECT (avi,
+            "Unknown tag %" GST_FOURCC_FORMAT " in ODML header",
+            GST_FOURCC_ARGS (tag));
+        /* Only get buffer for debugging if the memdump is needed  */
+        if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= 9) {
+          GstMapInfo map;
+
+          gst_buffer_map (sub, &map, GST_MAP_READ);
+          GST_MEMDUMP_OBJECT (avi, "Unknown ODML tag", map.data, map.size);
+          gst_buffer_unmap (sub, &map);
+        }
+        /* fall-through */
+      case GST_RIFF_TAG_JUNQ:
+      case GST_RIFF_TAG_JUNK:
+      next:
+        /* skip and move to next chunk */
+        if (sub) {
+          gst_buffer_unref (sub);
+          sub = NULL;
+        }
+        break;
+    }
+  }
+  if (buf)
+    gst_buffer_unref (buf);
+}
+
+/* Index helper */
+static guint
+gst_avi_demux_index_last (GstAviDemux * avi, GstAviStream * stream)
+{
+  return stream->idx_n;
+}
+
+/* find a previous entry in the index with the given flags */
+static guint
+gst_avi_demux_index_prev (GstAviDemux * avi, GstAviStream * stream,
+    guint last, gboolean keyframe)
+{
+  GstAviIndexEntry *entry;
+  guint i;
+
+  for (i = last; i > 0; i--) {
+    entry = &stream->index[i - 1];
+    if (!keyframe || ENTRY_IS_KEYFRAME (entry)) {
+      return i - 1;
+    }
+  }
+  return 0;
+}
+
+static guint
+gst_avi_demux_index_next (GstAviDemux * avi, GstAviStream * stream,
+    guint last, gboolean keyframe)
+{
+  GstAviIndexEntry *entry;
+  gint i;
+
+  for (i = last + 1; i < stream->idx_n; i++) {
+    entry = &stream->index[i];
+    if (!keyframe || ENTRY_IS_KEYFRAME (entry)) {
+      return i;
+    }
+  }
+  return stream->idx_n - 1;
+}
+
+static guint
+gst_avi_demux_index_entry_search (GstAviIndexEntry * entry, guint64 * total)
+{
+  if (entry->total < *total)
+    return -1;
+  else if (entry->total > *total)
+    return 1;
+  return 0;
+}
+
+/*
+ * gst_avi_demux_index_for_time:
+ * @avi: Avi object
+ * @stream: the stream
+ * @time: a time position
+ * @next: whether to look for entry before or after @time
+ *
+ * Finds the index entry which time is less/more or equal than the requested time.
+ * Try to avoid binary search when we can convert the time to an index
+ * position directly (for example for video frames with a fixed duration).
+ *
+ * Returns: the found position in the index.
+ */
+static guint
+gst_avi_demux_index_for_time (GstAviDemux * avi,
+    GstAviStream * stream, guint64 time, gboolean next)
+{
+  guint index = -1;
+  guint64 total;
+
+  GST_LOG_OBJECT (avi, "search time:%" GST_TIME_FORMAT, GST_TIME_ARGS (time));
+
+  /* easy (and common) cases */
+  if (time == 0 || stream->idx_n == 0)
+    return 0;
+  if (time >= stream->idx_duration)
+    return stream->idx_n - 1;
+
+  /* figure out where we need to go. For that we convert the time to an
+   * index entry or we convert it to a total and then do a binary search. */
+  if (stream->is_vbr) {
+    /* VBR stream next timestamp */
+    if (stream->strh->type == GST_RIFF_FCC_auds) {
+      total = avi_stream_convert_time_to_frames_unchecked (stream, time);
+    } else {
+      index = avi_stream_convert_time_to_frames_unchecked (stream, time);
+      /* this entry typically undershoots the target time,
+       * so check a bit more if next needed */
+      if (next && index != -1) {
+        GstClockTime itime =
+            avi_stream_convert_frames_to_time_unchecked (stream, index);
+        if (itime < time && index + 1 < stream->idx_n)
+          index++;
+      }
+    }
+  } else if (stream->strh->type == GST_RIFF_FCC_auds) {
+    /* constant rate stream */
+    total = avi_stream_convert_time_to_bytes_unchecked (stream, time);
+  } else
+    return -1;
+
+  if (index == -1) {
+    GstAviIndexEntry *entry;
+
+    /* no index, find index with binary search on total */
+    GST_LOG_OBJECT (avi, "binary search for entry with total %"
+        G_GUINT64_FORMAT, total);
+
+    entry = gst_util_array_binary_search (stream->index,
+        stream->idx_n, sizeof (GstAviIndexEntry),
+        (GCompareDataFunc) gst_avi_demux_index_entry_search,
+        next ? GST_SEARCH_MODE_AFTER : GST_SEARCH_MODE_BEFORE, &total, NULL);
+
+    if (entry == NULL) {
+      GST_LOG_OBJECT (avi, "not found, assume index 0");
+      index = 0;
+    } else {
+      index = entry - stream->index;
+      GST_LOG_OBJECT (avi, "found at %u", index);
+    }
+  } else {
+    GST_LOG_OBJECT (avi, "converted time to index %u", index);
+  }
+
+  return index;
+}
+
+static inline GstAviStream *
+gst_avi_demux_stream_for_id (GstAviDemux * avi, guint32 id)
+{
+  guint stream_nr;
+  GstAviStream *stream;
+
+  /* get the stream for this entry */
+  stream_nr = CHUNKID_TO_STREAMNR (id);
+  if (G_UNLIKELY (stream_nr >= avi->num_streams)) {
+    GST_WARNING_OBJECT (avi,
+        "invalid stream nr %d (0x%08x, %" GST_FOURCC_FORMAT ")", stream_nr, id,
+        GST_FOURCC_ARGS (id));
+    return NULL;
+  }
+  stream = &avi->stream[stream_nr];
+  if (G_UNLIKELY (!stream->strh)) {
+    GST_WARNING_OBJECT (avi, "Unhandled stream %d, skipping", stream_nr);
+    return NULL;
+  }
+  return stream;
+}
+
+/*
+ * gst_avi_demux_parse_index:
+ * @avi: calling element (used for debugging/errors).
+ * @buf: buffer containing the full index.
+ *
+ * Read index entries from the provided buffer.
+ * The buffer should contain a GST_RIFF_TAG_idx1 chunk.
+ */
+static gboolean
+gst_avi_demux_parse_index (GstAviDemux * avi, GstBuffer * buf)
+{
+  GstMapInfo map;
+  guint i, num, n;
+  gst_riff_index_entry *index;
+  GstClockTime stamp;
+  GstAviStream *stream;
+  GstAviIndexEntry entry;
+  guint32 id;
+
+  if (!buf)
+    return FALSE;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  stamp = gst_util_get_timestamp ();
+
+  /* see how many items in the index */
+  num = map.size / sizeof (gst_riff_index_entry);
+  if (num == 0)
+    goto empty_list;
+
+  GST_INFO_OBJECT (avi, "Parsing index, nr_entries = %6d", num);
+
+  index = (gst_riff_index_entry *) map.data;
+
+  /* figure out if the index is 0 based or relative to the MOVI start */
+  entry.offset = GST_READ_UINT32_LE (&index[0].offset);
+  if (entry.offset < avi->offset) {
+    avi->index_offset = avi->offset + 8;
+    GST_DEBUG ("index_offset = %" G_GUINT64_FORMAT, avi->index_offset);
+  } else {
+    avi->index_offset = 0;
+    GST_DEBUG ("index is 0 based");
+  }
+
+  for (i = 0, n = 0; i < num; i++) {
+    id = GST_READ_UINT32_LE (&index[i].id);
+    entry.offset = GST_READ_UINT32_LE (&index[i].offset);
+
+    /* some sanity checks */
+    if (G_UNLIKELY (id == GST_RIFF_rec || id == 0 ||
+            (entry.offset == 0 && n > 0)))
+      continue;
+
+    /* get the stream for this entry */
+    stream = gst_avi_demux_stream_for_id (avi, id);
+    if (G_UNLIKELY (!stream))
+      continue;
+
+    /* handle offset and size */
+    entry.offset += avi->index_offset + 8;
+    entry.size = GST_READ_UINT32_LE (&index[i].size);
+
+    /* handle flags */
+    if (stream->strh->type == GST_RIFF_FCC_auds) {
+      /* all audio frames are keyframes */
+      ENTRY_SET_KEYFRAME (&entry);
+    } else if (stream->strh->type == GST_RIFF_FCC_vids &&
+        stream->strf.vids->compression == GST_RIFF_DXSB) {
+      /* all xsub frames are keyframes */
+      ENTRY_SET_KEYFRAME (&entry);
+    } else {
+      guint32 flags;
+      /* else read flags */
+      flags = GST_READ_UINT32_LE (&index[i].flags);
+      if (flags & GST_RIFF_IF_KEYFRAME) {
+        ENTRY_SET_KEYFRAME (&entry);
+      } else {
+        ENTRY_UNSET_KEYFRAME (&entry);
+      }
+    }
+
+    /* and add */
+    if (G_UNLIKELY (!gst_avi_demux_add_index (avi, stream, num, &entry)))
+      goto out_of_mem;
+
+    n++;
+  }
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+
+  /* get stream stats now */
+  avi->have_index = gst_avi_demux_do_index_stats (avi);
+
+  stamp = gst_util_get_timestamp () - stamp;
+  GST_DEBUG_OBJECT (avi, "index parsing took %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (stamp));
+
+  return TRUE;
+
+  /* ERRORS */
+empty_list:
+  {
+    GST_DEBUG_OBJECT (avi, "empty index");
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    return FALSE;
+  }
+out_of_mem:
+  {
+    GST_ELEMENT_ERROR (avi, RESOURCE, NO_SPACE_LEFT, (NULL),
+        ("Cannot allocate memory for %u*%u=%u bytes",
+            (guint) sizeof (GstAviIndexEntry), num,
+            (guint) sizeof (GstAviIndexEntry) * num));
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    return FALSE;
+  }
+}
+
+/*
+ * gst_avi_demux_stream_index:
+ * @avi: avi demuxer object.
+ *
+ * Seeks to index and reads it.
+ */
+static void
+gst_avi_demux_stream_index (GstAviDemux * avi)
+{
+  GstFlowReturn res;
+  guint64 offset = avi->offset;
+  GstBuffer *buf = NULL;
+  guint32 tag;
+  guint32 size;
+  GstMapInfo map;
+
+  GST_DEBUG ("demux stream index at offset %" G_GUINT64_FORMAT, offset);
+
+  /* get chunk information */
+  res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf);
+  if (res != GST_FLOW_OK)
+    goto pull_failed;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  if (map.size < 8)
+    goto too_small;
+
+  /* check tag first before blindy trying to read 'size' bytes */
+  tag = GST_READ_UINT32_LE (map.data);
+  size = GST_READ_UINT32_LE (map.data + 4);
+  if (tag == GST_RIFF_TAG_LIST) {
+    /* this is the movi tag */
+    GST_DEBUG_OBJECT (avi, "skip LIST chunk, size %" G_GUINT32_FORMAT,
+        (8 + GST_ROUND_UP_2 (size)));
+    offset += 8 + GST_ROUND_UP_2 (size);
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+
+    buf = NULL;
+    res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf);
+    if (res != GST_FLOW_OK)
+      goto pull_failed;
+
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    if (map.size < 8)
+      goto too_small;
+
+    tag = GST_READ_UINT32_LE (map.data);
+    size = GST_READ_UINT32_LE (map.data + 4);
+  }
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+
+  if (tag != GST_RIFF_TAG_idx1)
+    goto no_index;
+  if (!size)
+    goto zero_index;
+
+  GST_DEBUG ("index found at offset %" G_GUINT64_FORMAT, offset);
+
+  /* read chunk, advance offset */
+  if (gst_riff_read_chunk (GST_ELEMENT_CAST (avi),
+          avi->sinkpad, &offset, &tag, &buf) != GST_FLOW_OK)
+    return;
+
+  GST_DEBUG ("will parse index chunk size %" G_GSIZE_FORMAT " for tag %"
+      GST_FOURCC_FORMAT, gst_buffer_get_size (buf), GST_FOURCC_ARGS (tag));
+
+  gst_avi_demux_parse_index (avi, buf);
+
+#ifndef GST_DISABLE_GST_DEBUG
+  /* debug our indexes */
+  {
+    gint i;
+    GstAviStream *stream;
+
+    for (i = 0; i < avi->num_streams; i++) {
+      stream = &avi->stream[i];
+      GST_DEBUG_OBJECT (avi, "stream %u: %u frames, %" G_GINT64_FORMAT " bytes",
+          i, stream->idx_n, stream->total_bytes);
+    }
+  }
+#endif
+  return;
+
+  /* ERRORS */
+pull_failed:
+  {
+    GST_DEBUG_OBJECT (avi,
+        "pull range failed: pos=%" G_GUINT64_FORMAT " size=8", offset);
+    return;
+  }
+too_small:
+  {
+    GST_DEBUG_OBJECT (avi, "Buffer is too small");
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    return;
+  }
+no_index:
+  {
+    GST_WARNING_OBJECT (avi,
+        "No index data (idx1) after movi chunk, but %" GST_FOURCC_FORMAT,
+        GST_FOURCC_ARGS (tag));
+    return;
+  }
+zero_index:
+  {
+    GST_WARNING_OBJECT (avi, "Empty index data (idx1) after movi chunk");
+    return;
+  }
+}
+
+/*
+ * gst_avi_demux_stream_index_push:
+ * @avi: avi demuxer object.
+ *
+ * Read index.
+ */
+static void
+gst_avi_demux_stream_index_push (GstAviDemux * avi)
+{
+  guint64 offset = avi->idx1_offset;
+  GstBuffer *buf;
+  guint32 tag;
+  guint32 size;
+
+  GST_DEBUG ("demux stream index at offset %" G_GUINT64_FORMAT, offset);
+
+  /* get chunk information */
+  if (!gst_avi_demux_peek_chunk (avi, &tag, &size))
+    return;
+
+  /* check tag first before blindly trying to read 'size' bytes */
+  if (tag == GST_RIFF_TAG_LIST) {
+    /* this is the movi tag */
+    GST_DEBUG_OBJECT (avi, "skip LIST chunk, size %" G_GUINT32_FORMAT,
+        (8 + GST_ROUND_UP_2 (size)));
+    avi->idx1_offset = offset + 8 + GST_ROUND_UP_2 (size);
+    /* issue seek to allow chain function to handle it and return! */
+    perform_seek_to_offset (avi, avi->idx1_offset, avi->segment_seqnum);
+    return;
+  }
+
+  if (tag != GST_RIFF_TAG_idx1)
+    goto no_index;
+
+  GST_DEBUG ("index found at offset %" G_GUINT64_FORMAT, offset);
+
+  /* flush chunk header */
+  gst_adapter_flush (avi->adapter, 8);
+  /* read chunk payload */
+  buf = gst_adapter_take_buffer (avi->adapter, size);
+  if (!buf)
+    goto pull_failed;
+  /* advance offset */
+  offset += 8 + GST_ROUND_UP_2 (size);
+
+  GST_DEBUG ("will parse index chunk size %" G_GSIZE_FORMAT " for tag %"
+      GST_FOURCC_FORMAT, gst_buffer_get_size (buf), GST_FOURCC_ARGS (tag));
+
+  avi->offset = avi->first_movi_offset;
+  gst_avi_demux_parse_index (avi, buf);
+
+#ifndef GST_DISABLE_GST_DEBUG
+  /* debug our indexes */
+  {
+    gint i;
+    GstAviStream *stream;
+
+    for (i = 0; i < avi->num_streams; i++) {
+      stream = &avi->stream[i];
+      GST_DEBUG_OBJECT (avi, "stream %u: %u frames, %" G_GINT64_FORMAT " bytes",
+          i, stream->idx_n, stream->total_bytes);
+    }
+  }
+#endif
+  return;
+
+  /* ERRORS */
+pull_failed:
+  {
+    GST_DEBUG_OBJECT (avi,
+        "taking data from adapter failed: pos=%" G_GUINT64_FORMAT " size=%u",
+        offset, size);
+    return;
+  }
+no_index:
+  {
+    GST_WARNING_OBJECT (avi,
+        "No index data (idx1) after movi chunk, but %" GST_FOURCC_FORMAT,
+        GST_FOURCC_ARGS (tag));
+    return;
+  }
+}
+
+/*
+ * gst_avi_demux_peek_tag:
+ *
+ * Returns the tag and size of the next chunk
+ */
+static GstFlowReturn
+gst_avi_demux_peek_tag (GstAviDemux * avi, guint64 offset, guint32 * tag,
+    guint * size)
+{
+  GstFlowReturn res;
+  GstBuffer *buf = NULL;
+  GstMapInfo map;
+
+  res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf);
+  if (res != GST_FLOW_OK)
+    goto pull_failed;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  if (map.size != 8)
+    goto wrong_size;
+
+  *tag = GST_READ_UINT32_LE (map.data);
+  *size = GST_READ_UINT32_LE (map.data + 4);
+
+  GST_LOG_OBJECT (avi, "Tag[%" GST_FOURCC_FORMAT "] (size:%d) %"
+      G_GINT64_FORMAT " -- %" G_GINT64_FORMAT, GST_FOURCC_ARGS (*tag),
+      *size, offset + 8, offset + 8 + (gint64) * size);
+
+done:
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+
+  return res;
+
+  /* ERRORS */
+pull_failed:
+  {
+    GST_DEBUG_OBJECT (avi, "pull_ranged returned %s", gst_flow_get_name (res));
+    return res;
+  }
+wrong_size:
+  {
+    GST_DEBUG_OBJECT (avi, "got %" G_GSIZE_FORMAT " bytes which is <> 8 bytes",
+        map.size);
+    res = GST_FLOW_ERROR;
+    goto done;
+  }
+}
+
+/*
+ * gst_avi_demux_next_data_buffer:
+ *
+ * Returns the offset and size of the next buffer
+ * Position is the position of the buffer (after tag and size)
+ */
+static GstFlowReturn
+gst_avi_demux_next_data_buffer (GstAviDemux * avi, guint64 * offset,
+    guint32 * tag, guint * size)
+{
+  guint64 off = *offset;
+  guint _size = 0;
+  GstFlowReturn res;
+
+  do {
+    res = gst_avi_demux_peek_tag (avi, off, tag, &_size);
+    if (res != GST_FLOW_OK)
+      break;
+    if (*tag == GST_RIFF_TAG_LIST || *tag == GST_RIFF_TAG_RIFF)
+      off += 8 + 4;             /* skip tag + size + subtag */
+    else {
+      *offset = off + 8;
+      *size = _size;
+      break;
+    }
+  } while (TRUE);
+
+  return res;
+}
+
+/*
+ * gst_avi_demux_stream_scan:
+ * @avi: calling element (used for debugging/errors).
+ *
+ * Scan the file for all chunks to "create" a new index.
+ * pull-range based
+ */
+static gboolean
+gst_avi_demux_stream_scan (GstAviDemux * avi)
+{
+  GstFlowReturn res;
+  GstAviStream *stream;
+  guint64 pos = 0;
+  guint64 length;
+  gint64 tmplength;
+  guint32 tag = 0;
+  guint num;
+
+  /* FIXME:
+   * - implement non-seekable source support.
+   */
+  GST_DEBUG_OBJECT (avi, "Creating index");
+
+  /* get the size of the file */
+  if (!gst_pad_peer_query_duration (avi->sinkpad, GST_FORMAT_BYTES, &tmplength))
+    return FALSE;
+  length = tmplength;
+
+  /* guess the total amount of entries we expect */
+  num = 16000;
+
+  while (TRUE) {
+    GstAviIndexEntry entry;
+    guint size = 0;
+
+    /* start reading data buffers to find the id and offset */
+    res = gst_avi_demux_next_data_buffer (avi, &pos, &tag, &size);
+    if (G_UNLIKELY (res != GST_FLOW_OK))
+      break;
+
+    /* get stream */
+    stream = gst_avi_demux_stream_for_id (avi, tag);
+    if (G_UNLIKELY (!stream))
+      goto next;
+
+    /* we can't figure out the keyframes, assume they all are */
+    entry.flags = GST_AVI_KEYFRAME;
+    entry.offset = pos;
+    entry.size = size;
+
+    /* and add to the index of this stream */
+    if (G_UNLIKELY (!gst_avi_demux_add_index (avi, stream, num, &entry)))
+      goto out_of_mem;
+
+  next:
+    /* update position */
+    pos += GST_ROUND_UP_2 (size);
+    if (G_UNLIKELY (pos > length)) {
+      GST_WARNING_OBJECT (avi,
+          "Stopping index lookup since we are further than EOF");
+      break;
+    }
+  }
+
+  /* collect stats */
+  avi->have_index = gst_avi_demux_do_index_stats (avi);
+
+  return TRUE;
+
+  /* ERRORS */
+out_of_mem:
+  {
+    GST_ELEMENT_ERROR (avi, RESOURCE, NO_SPACE_LEFT, (NULL),
+        ("Cannot allocate memory for %u*%u=%u bytes",
+            (guint) sizeof (GstAviIndexEntry), num,
+            (guint) sizeof (GstAviIndexEntry) * num));
+    return FALSE;
+  }
+}
+
+static void
+gst_avi_demux_calculate_durations_from_index (GstAviDemux * avi)
+{
+  guint i;
+  GstClockTime total;
+  GstAviStream *stream;
+
+  total = GST_CLOCK_TIME_NONE;
+
+  /* all streams start at a timestamp 0 */
+  for (i = 0; i < avi->num_streams; i++) {
+    GstClockTime duration, hduration;
+    gst_riff_strh *strh;
+
+    stream = &avi->stream[i];
+    if (G_UNLIKELY (!stream || !stream->idx_n || !(strh = stream->strh)))
+      continue;
+
+    /* get header duration for the stream */
+    hduration = stream->hdr_duration;
+    /* index duration calculated during parsing */
+    duration = stream->idx_duration;
+
+    /* now pick a good duration */
+    if (GST_CLOCK_TIME_IS_VALID (duration)) {
+      /* index gave valid duration, use that */
+      GST_INFO ("Stream %p duration according to index: %" GST_TIME_FORMAT,
+          stream, GST_TIME_ARGS (duration));
+    } else {
+      /* fall back to header info to calculate a duration */
+      duration = hduration;
+    }
+    GST_INFO ("Setting duration of stream #%d to %" GST_TIME_FORMAT,
+        i, GST_TIME_ARGS (duration));
+    /* set duration for the stream */
+    stream->duration = duration;
+
+    /* find total duration */
+    if (total == GST_CLOCK_TIME_NONE ||
+        (GST_CLOCK_TIME_IS_VALID (duration) && duration > total))
+      total = duration;
+  }
+
+  if (GST_CLOCK_TIME_IS_VALID (total) && (total > 0)) {
+    /* now update the duration for those streams where we had none */
+    for (i = 0; i < avi->num_streams; i++) {
+      stream = &avi->stream[i];
+
+      if (!GST_CLOCK_TIME_IS_VALID (stream->duration)
+          || stream->duration == 0) {
+        stream->duration = total;
+
+        GST_INFO ("Stream %p duration according to total: %" GST_TIME_FORMAT,
+            stream, GST_TIME_ARGS (total));
+      }
+    }
+  }
+
+  /* and set the total duration in the segment. */
+  GST_INFO ("Setting total duration to: %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (total));
+
+  avi->segment.duration = total;
+}
+
+/* returns FALSE if there are no pads to deliver event to,
+ * otherwise TRUE (whatever the outcome of event sending),
+ * takes ownership of the event. */
+static gboolean
+gst_avi_demux_push_event (GstAviDemux * avi, GstEvent * event)
+{
+  gboolean result = FALSE;
+  gint i;
+
+  GST_DEBUG_OBJECT (avi, "sending %s event to %d streams",
+      GST_EVENT_TYPE_NAME (event), avi->num_streams);
+
+  for (i = 0; i < avi->num_streams; i++) {
+    GstAviStream *stream = &avi->stream[i];
+
+    if (stream->pad) {
+      result = TRUE;
+      gst_pad_push_event (stream->pad, gst_event_ref (event));
+    }
+  }
+  gst_event_unref (event);
+  return result;
+}
+
+static void
+gst_avi_demux_check_seekability (GstAviDemux * avi)
+{
+  GstQuery *query;
+  gboolean seekable = FALSE;
+  gint64 start = -1, stop = -1;
+
+  query = gst_query_new_seeking (GST_FORMAT_BYTES);
+  if (!gst_pad_peer_query (avi->sinkpad, query)) {
+    GST_DEBUG_OBJECT (avi, "seeking query failed");
+    goto done;
+  }
+
+  gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
+
+  /* try harder to query upstream size if we didn't get it the first time */
+  if (seekable && stop == -1) {
+    GST_DEBUG_OBJECT (avi, "doing duration query to fix up unset stop");
+    gst_pad_peer_query_duration (avi->sinkpad, GST_FORMAT_BYTES, &stop);
+  }
+
+  /* if upstream doesn't know the size, it's likely that it's not seekable in
+   * practice even if it technically may be seekable */
+  if (seekable && (start != 0 || stop <= start)) {
+    GST_DEBUG_OBJECT (avi, "seekable but unknown start/stop -> disable");
+    seekable = FALSE;
+  }
+
+done:
+  GST_INFO_OBJECT (avi, "seekable: %d (%" G_GUINT64_FORMAT " - %"
+      G_GUINT64_FORMAT ")", seekable, start, stop);
+  avi->seekable = seekable;
+
+  gst_query_unref (query);
+}
+
+/*
+ * Read AVI headers when streaming
+ */
+static GstFlowReturn
+gst_avi_demux_stream_header_push (GstAviDemux * avi)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint32 tag = 0;
+  guint32 ltag = 0;
+  guint32 size = 0;
+  const guint8 *data;
+  GstBuffer *buf = NULL, *sub = NULL;
+  guint offset = 4;
+  gint i;
+  GstTagList *tags = NULL;
+  guint8 fourcc[4];
+
+  GST_DEBUG ("Reading and parsing avi headers: %d", avi->header_state);
+
+  switch (avi->header_state) {
+    case GST_AVI_DEMUX_HEADER_TAG_LIST:
+    again:
+      if (gst_avi_demux_peek_chunk (avi, &tag, &size)) {
+        avi->offset += 8 + GST_ROUND_UP_2 (size);
+        if (tag != GST_RIFF_TAG_LIST)
+          goto header_no_list;
+
+        gst_adapter_flush (avi->adapter, 8);
+        /* Find the 'hdrl' LIST tag */
+        GST_DEBUG ("Reading %d bytes", size);
+        buf = gst_adapter_take_buffer (avi->adapter, size);
+
+        gst_buffer_extract (buf, 0, fourcc, 4);
+
+        if (GST_READ_UINT32_LE (fourcc) != GST_RIFF_LIST_hdrl) {
+          GST_WARNING_OBJECT (avi, "Invalid AVI header (no hdrl at start): %"
+              GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag));
+          gst_buffer_unref (buf);
+          goto again;
+        }
+
+        /* mind padding */
+        if (size & 1)
+          gst_adapter_flush (avi->adapter, 1);
+
+        GST_DEBUG ("'hdrl' LIST tag found. Parsing next chunk");
+
+        gst_avi_demux_roundup_list (avi, &buf);
+
+        /* the hdrl starts with a 'avih' header */
+        if (!gst_riff_parse_chunk (GST_ELEMENT_CAST (avi), buf, &offset, &tag,
+                &sub))
+          goto header_no_avih;
+
+        if (tag != GST_RIFF_TAG_avih)
+          goto header_no_avih;
+
+        if (!gst_avi_demux_parse_avih (avi, sub, &avi->avih))
+          goto header_wrong_avih;
+
+        GST_DEBUG_OBJECT (avi, "AVI header ok, reading elemnts from header");
+
+        /* now, read the elements from the header until the end */
+        while (gst_riff_parse_chunk (GST_ELEMENT_CAST (avi), buf, &offset, &tag,
+                &sub)) {
+          /* sub can be NULL on empty tags */
+          if (!sub)
+            continue;
+
+          switch (tag) {
+            case GST_RIFF_TAG_LIST:
+              if (gst_buffer_get_size (sub) < 4)
+                goto next;
+
+              gst_buffer_extract (sub, 0, fourcc, 4);
+
+              switch (GST_READ_UINT32_LE (fourcc)) {
+                case GST_RIFF_LIST_strl:
+                  if (!(gst_avi_demux_parse_stream (avi, sub))) {
+                    sub = NULL;
+                    GST_ELEMENT_WARNING (avi, STREAM, DEMUX, (NULL),
+                        ("failed to parse stream, ignoring"));
+                    goto next;
+                  }
+                  sub = NULL;
+                  goto next;
+                case GST_RIFF_LIST_odml:
+                  gst_avi_demux_parse_odml (avi, sub);
+                  sub = NULL;
+                  break;
+                default:
+                  GST_WARNING_OBJECT (avi,
+                      "Unknown list %" GST_FOURCC_FORMAT " in AVI header",
+                      GST_FOURCC_ARGS (GST_READ_UINT32_LE (fourcc)));
+                  /* fall-through */
+                case GST_RIFF_TAG_JUNQ:
+                case GST_RIFF_TAG_JUNK:
+                  goto next;
+              }
+              break;
+            case GST_RIFF_IDIT:
+              gst_avi_demux_parse_idit (avi, sub);
+              goto next;
+            default:
+              GST_WARNING_OBJECT (avi,
+                  "Unknown tag %" GST_FOURCC_FORMAT " in AVI header",
+                  GST_FOURCC_ARGS (tag));
+              /* Only get buffer for debugging if the memdump is needed  */
+              if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= 9) {
+                GstMapInfo map;
+
+                gst_buffer_map (sub, &map, GST_MAP_READ);
+                GST_MEMDUMP_OBJECT (avi, "Unknown tag", map.data, map.size);
+                gst_buffer_unmap (sub, &map);
+              }
+              /* fall-through */
+            case GST_RIFF_TAG_JUNQ:
+            case GST_RIFF_TAG_JUNK:
+            next:
+              /* move to next chunk */
+              if (sub)
+                gst_buffer_unref (sub);
+              sub = NULL;
+              break;
+          }
+        }
+        gst_buffer_unref (buf);
+        GST_DEBUG ("elements parsed");
+
+        /* check parsed streams */
+        if (avi->num_streams == 0) {
+          goto no_streams;
+        } else if (avi->num_streams != avi->avih->streams) {
+          GST_WARNING_OBJECT (avi,
+              "Stream header mentioned %d streams, but %d available",
+              avi->avih->streams, avi->num_streams);
+        }
+        GST_DEBUG ("Get junk and info next");
+        avi->header_state = GST_AVI_DEMUX_HEADER_INFO;
+      } else {
+        /* Need more data */
+        return ret;
+      }
+      /* fall-though */
+    case GST_AVI_DEMUX_HEADER_INFO:
+      GST_DEBUG_OBJECT (avi, "skipping junk between header and data ...");
+      while (TRUE) {
+        if (gst_adapter_available (avi->adapter) < 12)
+          return GST_FLOW_OK;
+
+        data = gst_adapter_map (avi->adapter, 12);
+        tag = GST_READ_UINT32_LE (data);
+        size = GST_READ_UINT32_LE (data + 4);
+        ltag = GST_READ_UINT32_LE (data + 8);
+        gst_adapter_unmap (avi->adapter);
+
+        if (tag == GST_RIFF_TAG_LIST) {
+          switch (ltag) {
+            case GST_RIFF_LIST_movi:
+              gst_adapter_flush (avi->adapter, 12);
+              if (!avi->first_movi_offset)
+                avi->first_movi_offset = avi->offset;
+              avi->offset += 12;
+              avi->idx1_offset = avi->offset + size - 4;
+              goto skipping_done;
+            case GST_RIFF_LIST_INFO:
+              GST_DEBUG ("Found INFO chunk");
+              if (gst_avi_demux_peek_chunk (avi, &tag, &size)) {
+                GST_DEBUG ("got size %d", size);
+                avi->offset += 12;
+                gst_adapter_flush (avi->adapter, 12);
+                if (size > 4) {
+                  buf = gst_adapter_take_buffer (avi->adapter, size - 4);
+                  /* mind padding */
+                  if (size & 1)
+                    gst_adapter_flush (avi->adapter, 1);
+                  gst_riff_parse_info (GST_ELEMENT_CAST (avi), buf, &tags);
+                  if (tags) {
+                    if (avi->globaltags) {
+                      gst_tag_list_insert (avi->globaltags, tags,
+                          GST_TAG_MERGE_REPLACE);
+                      gst_tag_list_unref (tags);
+                    } else {
+                      avi->globaltags = tags;
+                    }
+                  }
+                  tags = NULL;
+                  gst_buffer_unref (buf);
+
+                  avi->offset += GST_ROUND_UP_2 (size) - 4;
+                } else {
+                  GST_DEBUG ("skipping INFO LIST prefix");
+                }
+              } else {
+                /* Need more data */
+                return GST_FLOW_OK;
+              }
+              break;
+            default:
+              if (gst_avi_demux_peek_chunk (avi, &tag, &size) || size == 0) {
+                /* accept 0 size buffer here */
+                avi->abort_buffering = FALSE;
+                avi->offset += 8 + GST_ROUND_UP_2 (size);
+                gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
+              } else {
+                /* Need more data */
+                return GST_FLOW_OK;
+              }
+              break;
+          }
+        } else {
+          if (gst_avi_demux_peek_chunk (avi, &tag, &size) || size == 0) {
+            /* accept 0 size buffer here */
+            avi->abort_buffering = FALSE;
+            avi->offset += 8 + GST_ROUND_UP_2 (size);
+            gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
+          } else {
+            /* Need more data */
+            return GST_FLOW_OK;
+          }
+        }
+      }
+      break;
+    default:
+      GST_WARNING ("unhandled header state: %d", avi->header_state);
+      break;
+  }
+skipping_done:
+
+  GST_DEBUG_OBJECT (avi, "skipping done ... (streams=%u, stream[0].indexes=%p)",
+      avi->num_streams, avi->stream[0].indexes);
+
+  GST_DEBUG ("Found movi chunk. Starting to stream data");
+  avi->state = GST_AVI_DEMUX_MOVI;
+
+  /* no indexes in push mode, but it still sets some variables */
+  gst_avi_demux_calculate_durations_from_index (avi);
+
+  gst_avi_demux_expose_streams (avi, TRUE);
+
+  /* prepare all streams for index 0 */
+  for (i = 0; i < avi->num_streams; i++)
+    avi->stream[i].current_entry = 0;
+
+  /* create initial NEWSEGMENT event */
+  if (avi->seg_event)
+    gst_event_unref (avi->seg_event);
+  avi->seg_event = gst_event_new_segment (&avi->segment);
+  if (avi->segment_seqnum)
+    gst_event_set_seqnum (avi->seg_event, avi->segment_seqnum);
+
+  gst_avi_demux_check_seekability (avi);
+
+  /* at this point we know all the streams and we can signal the no more
+   * pads signal */
+  GST_DEBUG_OBJECT (avi, "signaling no more pads");
+  gst_element_no_more_pads (GST_ELEMENT_CAST (avi));
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+no_streams:
+  {
+    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("No streams found"));
+    return GST_FLOW_ERROR;
+  }
+header_no_list:
+  {
+    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
+        ("Invalid AVI header (no LIST at start): %"
+            GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
+    return GST_FLOW_ERROR;
+  }
+header_no_avih:
+  {
+    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
+        ("Invalid AVI header (no avih at start): %"
+            GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
+    if (sub)
+      gst_buffer_unref (sub);
+
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+header_wrong_avih:
+  {
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static void
+gst_avi_demux_add_date_tag (GstAviDemux * avi, gint y, gint m, gint d,
+    gint h, gint min, gint s)
+{
+  GDate *date;
+  GstDateTime *dt;
+
+  date = g_date_new_dmy (d, m, y);
+  if (!g_date_valid (date)) {
+    /* bogus date */
+    GST_WARNING_OBJECT (avi, "Refusing to add invalid date %d-%d-%d", y, m, d);
+    g_date_free (date);
+    return;
+  }
+
+  dt = gst_date_time_new_local_time (y, m, d, h, min, s);
+
+  if (avi->globaltags == NULL)
+    avi->globaltags = gst_tag_list_new_empty ();
+
+  gst_tag_list_add (avi->globaltags, GST_TAG_MERGE_REPLACE, GST_TAG_DATE, date,
+      NULL);
+  g_date_free (date);
+  if (dt) {
+    gst_tag_list_add (avi->globaltags, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME,
+        dt, NULL);
+    gst_date_time_unref (dt);
+  }
+}
+
+static void
+gst_avi_demux_parse_idit_nums_only (GstAviDemux * avi, gchar * data)
+{
+  gint y, m, d;
+  gint hr = 0, min = 0, sec = 0;
+  gint ret;
+
+  GST_DEBUG ("data : '%s'", data);
+
+  ret = sscanf (data, "%d:%d:%d %d:%d:%d", &y, &m, &d, &hr, &min, &sec);
+  if (ret < 3) {
+    /* Attempt YYYY/MM/DD/ HH:MM variant (found in CASIO cameras) */
+    ret = sscanf (data, "%04d/%02d/%02d/ %d:%d", &y, &m, &d, &hr, &min);
+    if (ret < 3) {
+      GST_WARNING_OBJECT (avi, "Failed to parse IDIT tag");
+      return;
+    }
+  }
+  gst_avi_demux_add_date_tag (avi, y, m, d, hr, min, sec);
+}
+
+static gint
+get_month_num (gchar * data, guint size)
+{
+  if (g_ascii_strncasecmp (data, "jan", 3) == 0) {
+    return 1;
+  } else if (g_ascii_strncasecmp (data, "feb", 3) == 0) {
+    return 2;
+  } else if (g_ascii_strncasecmp (data, "mar", 3) == 0) {
+    return 3;
+  } else if (g_ascii_strncasecmp (data, "apr", 3) == 0) {
+    return 4;
+  } else if (g_ascii_strncasecmp (data, "may", 3) == 0) {
+    return 5;
+  } else if (g_ascii_strncasecmp (data, "jun", 3) == 0) {
+    return 6;
+  } else if (g_ascii_strncasecmp (data, "jul", 3) == 0) {
+    return 7;
+  } else if (g_ascii_strncasecmp (data, "aug", 3) == 0) {
+    return 8;
+  } else if (g_ascii_strncasecmp (data, "sep", 3) == 0) {
+    return 9;
+  } else if (g_ascii_strncasecmp (data, "oct", 3) == 0) {
+    return 10;
+  } else if (g_ascii_strncasecmp (data, "nov", 3) == 0) {
+    return 11;
+  } else if (g_ascii_strncasecmp (data, "dec", 3) == 0) {
+    return 12;
+  }
+
+  return 0;
+}
+
+static void
+gst_avi_demux_parse_idit_text (GstAviDemux * avi, gchar * data)
+{
+  gint year, month, day;
+  gint hour, min, sec;
+  gint ret;
+  gchar weekday[4];
+  gchar monthstr[4];
+
+  ret = sscanf (data, "%3s %3s %d %d:%d:%d %d", weekday, monthstr, &day, &hour,
+      &min, &sec, &year);
+  if (ret != 7) {
+    GST_WARNING_OBJECT (avi, "Failed to parse IDIT tag");
+    return;
+  }
+  month = get_month_num (monthstr, strlen (monthstr));
+  gst_avi_demux_add_date_tag (avi, year, month, day, hour, min, sec);
+}
+
+static void
+gst_avi_demux_parse_idit (GstAviDemux * avi, GstBuffer * buf)
+{
+  GstMapInfo map;
+  gchar *ptr;
+  gsize left;
+  gchar *safedata = NULL;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  /*
+   * According to:
+   * http://www.eden-foundation.org/products/code/film_date_stamp/index.html
+   *
+   * This tag could be in one of the below formats
+   * 2005:08:17 11:42:43
+   * THU OCT 26 16:46:04 2006
+   * Mon Mar  3 09:44:56 2008
+   *
+   * FIXME: Our date tag doesn't include hours
+   */
+
+  /* skip eventual initial whitespace */
+  ptr = (gchar *) map.data;
+  left = map.size;
+
+  while (left > 0 && g_ascii_isspace (ptr[0])) {
+    ptr++;
+    left--;
+  }
+
+  if (left == 0) {
+    goto non_parsable;
+  }
+
+  /* make a safe copy to add a \0 to the end of the string */
+  safedata = g_strndup (ptr, left);
+
+  /* test if the first char is a alpha or a number */
+  if (g_ascii_isdigit (ptr[0])) {
+    gst_avi_demux_parse_idit_nums_only (avi, safedata);
+    g_free (safedata);
+    gst_buffer_unmap (buf, &map);
+    return;
+  } else if (g_ascii_isalpha (ptr[0])) {
+    gst_avi_demux_parse_idit_text (avi, safedata);
+    g_free (safedata);
+    gst_buffer_unmap (buf, &map);
+    return;
+  }
+
+  g_free (safedata);
+
+non_parsable:
+  GST_WARNING_OBJECT (avi, "IDIT tag has no parsable info");
+  gst_buffer_unmap (buf, &map);
+}
+
+static void
+parse_tag_value (GstAviDemux * avi, GstTagList * taglist, const gchar * type,
+    guint8 * ptr, guint tsize)
+{
+  static const gchar *env_vars[] = { "GST_AVI_TAG_ENCODING",
+    "GST_RIFF_TAG_ENCODING", "GST_TAG_ENCODING", NULL
+  };
+  GType tag_type;
+  gchar *val;
+
+  tag_type = gst_tag_get_type (type);
+  val = gst_tag_freeform_string_to_utf8 ((gchar *) ptr, tsize, env_vars);
+
+  if (val != NULL) {
+    if (tag_type == G_TYPE_STRING) {
+      gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, type, val, NULL);
+    } else {
+      GValue tag_val = { 0, };
+
+      g_value_init (&tag_val, tag_type);
+      if (gst_value_deserialize (&tag_val, val)) {
+        gst_tag_list_add_value (taglist, GST_TAG_MERGE_APPEND, type, &tag_val);
+      } else {
+        GST_WARNING_OBJECT (avi, "could not deserialize '%s' into a "
+            "tag %s of type %s", val, type, g_type_name (tag_type));
+      }
+      g_value_unset (&tag_val);
+    }
+    g_free (val);
+  } else {
+    GST_WARNING_OBJECT (avi, "could not extract %s tag", type);
+  }
+}
+
+static void
+gst_avi_demux_parse_strd (GstAviDemux * avi, GstBuffer * buf)
+{
+  GstMapInfo map;
+  guint32 tag;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  if (map.size > 4) {
+    guint8 *ptr = map.data;
+    gsize left = map.size;
+
+    /* parsing based on
+     * http://www.eden-foundation.org/products/code/film_date_stamp/index.html
+     */
+    tag = GST_READ_UINT32_LE (ptr);
+    if ((tag == GST_MAKE_FOURCC ('A', 'V', 'I', 'F')) && (map.size > 98)) {
+      gsize sub_size;
+
+      ptr += 98;
+      left -= 98;
+      if (!memcmp (ptr, "FUJIFILM", 8)) {
+        GST_MEMDUMP_OBJECT (avi, "fujifim tag", ptr, 48);
+
+        ptr += 10;
+        left -= 10;
+        sub_size = 0;
+        while (ptr[sub_size] && sub_size < left)
+          sub_size++;
+
+        if (avi->globaltags == NULL)
+          avi->globaltags = gst_tag_list_new_empty ();
+
+        gst_tag_list_add (avi->globaltags, GST_TAG_MERGE_APPEND,
+            GST_TAG_DEVICE_MANUFACTURER, "FUJIFILM", NULL);
+        parse_tag_value (avi, avi->globaltags, GST_TAG_DEVICE_MODEL, ptr,
+            sub_size);
+
+        while (ptr[sub_size] == '\0' && sub_size < left)
+          sub_size++;
+
+        ptr += sub_size;
+        left -= sub_size;
+        sub_size = 0;
+        while (ptr[sub_size] && sub_size < left)
+          sub_size++;
+        if (ptr[4] == ':')
+          ptr[4] = '-';
+        if (ptr[7] == ':')
+          ptr[7] = '-';
+
+        parse_tag_value (avi, avi->globaltags, GST_TAG_DATE_TIME, ptr,
+            sub_size);
+      }
+    }
+  }
+  gst_buffer_unmap (buf, &map);
+}
+
+/*
+ * gst_avi_demux_parse_ncdt:
+ * @element: caller element (used for debugging/error).
+ * @buf: input data to be used for parsing, stripped from header.
+ * @taglist: a pointer to a taglist (returned by this function)
+ *           containing information about this stream. May be
+ *           NULL if no supported tags were found.
+ *
+ * Parses Nikon metadata from input data.
+ */
+static void
+gst_avi_demux_parse_ncdt (GstAviDemux * avi, GstBuffer * buf,
+    GstTagList ** _taglist)
+{
+  GstMapInfo info;
+  guint8 *ptr;
+  gsize left;
+  guint tsize;
+  guint32 tag;
+  const gchar *type;
+  GstTagList *taglist;
+
+  g_return_if_fail (_taglist != NULL);
+
+  if (!buf) {
+    *_taglist = NULL;
+    return;
+  }
+  gst_buffer_map (buf, &info, GST_MAP_READ);
+
+  taglist = gst_tag_list_new_empty ();
+
+  ptr = info.data;
+  left = info.size;
+
+  while (left > 8) {
+    tag = GST_READ_UINT32_LE (ptr);
+    tsize = GST_READ_UINT32_LE (ptr + 4);
+
+    GST_MEMDUMP_OBJECT (avi, "tag chunk", ptr, MIN (tsize + 8, left));
+
+    left -= 8;
+    ptr += 8;
+
+    GST_DEBUG_OBJECT (avi, "tag %" GST_FOURCC_FORMAT ", size %u",
+        GST_FOURCC_ARGS (tag), tsize);
+
+    if (tsize > left) {
+      GST_WARNING_OBJECT (avi,
+          "Tagsize %d is larger than available data %" G_GSIZE_FORMAT,
+          tsize, left);
+      tsize = left;
+    }
+
+    /* find out the type of metadata */
+    switch (tag) {
+      case GST_RIFF_LIST_nctg:
+        while (tsize > 4) {
+          guint16 sub_tag = GST_READ_UINT16_LE (ptr);
+          guint16 sub_size = GST_READ_UINT16_LE (ptr + 2);
+
+          tsize -= 4;
+          ptr += 4;
+          left -= 4;
+
+          if (sub_size > tsize)
+            break;
+
+          GST_DEBUG_OBJECT (avi, "sub-tag %u, size %u", sub_tag, sub_size);
+          /* http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
+           * for some reason the sub_tag has a +2 offset
+           */
+          switch (sub_tag) {
+            case 0x03:         /* Make */
+              type = GST_TAG_DEVICE_MANUFACTURER;
+              break;
+            case 0x04:         /* Model */
+              type = GST_TAG_DEVICE_MODEL;
+              break;
+              /* TODO: 0x05: is software version, like V1.0 */
+            case 0x06:         /* Software */
+              type = GST_TAG_ENCODER;
+              break;
+            case 0x13:         /* CreationDate */
+              type = GST_TAG_DATE_TIME;
+              if (left > 7) {
+                if (ptr[4] == ':')
+                  ptr[4] = '-';
+                if (ptr[7] == ':')
+                  ptr[7] = '-';
+              }
+              break;
+            default:
+              type = NULL;
+              break;
+          }
+          if (type != NULL && ptr[0] != '\0') {
+            GST_DEBUG_OBJECT (avi, "mapped tag %u to tag %s", sub_tag, type);
+
+            parse_tag_value (avi, taglist, type, ptr, sub_size);
+          }
+
+          ptr += sub_size;
+          tsize -= sub_size;
+          left -= sub_size;
+        }
+        break;
+      default:
+        type = NULL;
+        GST_WARNING_OBJECT (avi,
+            "Unknown ncdt (metadata) tag entry %" GST_FOURCC_FORMAT,
+            GST_FOURCC_ARGS (tag));
+        GST_MEMDUMP_OBJECT (avi, "Unknown ncdt", ptr, tsize);
+        break;
+    }
+
+    if (tsize & 1) {
+      tsize++;
+      if (tsize > left)
+        tsize = left;
+    }
+
+    ptr += tsize;
+    left -= tsize;
+  }
+
+  if (!gst_tag_list_is_empty (taglist)) {
+    GST_INFO_OBJECT (avi, "extracted tags: %" GST_PTR_FORMAT, taglist);
+    *_taglist = taglist;
+  } else {
+    *_taglist = NULL;
+    gst_tag_list_unref (taglist);
+  }
+  gst_buffer_unmap (buf, &info);
+
+  return;
+}
+
+/*
+ * Read full AVI headers.
+ */
+static GstFlowReturn
+gst_avi_demux_stream_header_pull (GstAviDemux * avi)
+{
+  GstFlowReturn res;
+  GstBuffer *buf, *sub = NULL;
+  guint32 tag;
+  guint offset = 4;
+  GstElement *element = GST_ELEMENT_CAST (avi);
+  GstClockTime stamp;
+  GstTagList *tags = NULL;
+  guint8 fourcc[4];
+
+  stamp = gst_util_get_timestamp ();
+
+  /* the header consists of a 'hdrl' LIST tag */
+  res = gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag, &buf);
+  if (res != GST_FLOW_OK)
+    goto pull_range_failed;
+  else if (tag != GST_RIFF_TAG_LIST)
+    goto no_list;
+  else if (gst_buffer_get_size (buf) < 4)
+    goto no_header;
+
+  GST_DEBUG_OBJECT (avi, "parsing headers");
+
+  /* Find the 'hdrl' LIST tag */
+  gst_buffer_extract (buf, 0, fourcc, 4);
+  while (GST_READ_UINT32_LE (fourcc) != GST_RIFF_LIST_hdrl) {
+    GST_LOG_OBJECT (avi, "buffer contains %" GST_FOURCC_FORMAT,
+        GST_FOURCC_ARGS (GST_READ_UINT32_LE (fourcc)));
+
+    /* Eat up */
+    gst_buffer_unref (buf);
+
+    /* read new chunk */
+    res = gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag, &buf);
+    if (res != GST_FLOW_OK)
+      goto pull_range_failed;
+    else if (tag != GST_RIFF_TAG_LIST)
+      goto no_list;
+    else if (gst_buffer_get_size (buf) < 4)
+      goto no_header;
+    gst_buffer_extract (buf, 0, fourcc, 4);
+  }
+
+  GST_DEBUG_OBJECT (avi, "hdrl LIST tag found");
+
+  gst_avi_demux_roundup_list (avi, &buf);
+
+  /* the hdrl starts with a 'avih' header */
+  if (!gst_riff_parse_chunk (element, buf, &offset, &tag, &sub))
+    goto no_avih;
+  else if (tag != GST_RIFF_TAG_avih)
+    goto no_avih;
+  else if (!gst_avi_demux_parse_avih (avi, sub, &avi->avih))
+    goto invalid_avih;
+
+  GST_DEBUG_OBJECT (avi, "AVI header ok, reading elements from header");
+
+  /* now, read the elements from the header until the end */
+  while (gst_riff_parse_chunk (element, buf, &offset, &tag, &sub)) {
+    GstMapInfo map;
+
+    /* sub can be NULL on empty tags */
+    if (!sub)
+      continue;
+
+    gst_buffer_map (sub, &map, GST_MAP_READ);
+
+    switch (tag) {
+      case GST_RIFF_TAG_LIST:
+        if (map.size < 4)
+          goto next;
+
+        switch (GST_READ_UINT32_LE (map.data)) {
+          case GST_RIFF_LIST_strl:
+            gst_buffer_unmap (sub, &map);
+            if (!(gst_avi_demux_parse_stream (avi, sub))) {
+              GST_ELEMENT_WARNING (avi, STREAM, DEMUX, (NULL),
+                  ("failed to parse stream, ignoring"));
+              sub = NULL;
+            }
+            sub = NULL;
+            goto next;
+          case GST_RIFF_LIST_odml:
+            gst_buffer_unmap (sub, &map);
+            gst_avi_demux_parse_odml (avi, sub);
+            sub = NULL;
+            break;
+          case GST_RIFF_LIST_INFO:
+            gst_buffer_unmap (sub, &map);
+            gst_buffer_resize (sub, 4, -1);
+            gst_riff_parse_info (element, sub, &tags);
+            if (tags) {
+              if (avi->globaltags) {
+                gst_tag_list_insert (avi->globaltags, tags,
+                    GST_TAG_MERGE_REPLACE);
+                gst_tag_list_unref (tags);
+              } else {
+                avi->globaltags = tags;
+              }
+            }
+            tags = NULL;
+            gst_buffer_unref (sub);
+            sub = NULL;
+            break;
+          case GST_RIFF_LIST_ncdt:
+            gst_buffer_unmap (sub, &map);
+            gst_buffer_resize (sub, 4, -1);
+            gst_avi_demux_parse_ncdt (avi, sub, &tags);
+            if (tags) {
+              if (avi->globaltags) {
+                gst_tag_list_insert (avi->globaltags, tags,
+                    GST_TAG_MERGE_REPLACE);
+                gst_tag_list_unref (tags);
+              } else {
+                avi->globaltags = tags;
+              }
+            }
+            tags = NULL;
+            gst_buffer_unref (sub);
+            sub = NULL;
+            break;
+          default:
+            GST_WARNING_OBJECT (avi,
+                "Unknown list %" GST_FOURCC_FORMAT " in AVI header",
+                GST_FOURCC_ARGS (GST_READ_UINT32_LE (map.data)));
+            GST_MEMDUMP_OBJECT (avi, "Unknown list", map.data, map.size);
+            /* fall-through */
+          case GST_RIFF_TAG_JUNQ:
+          case GST_RIFF_TAG_JUNK:
+            goto next;
+        }
+        break;
+      case GST_RIFF_IDIT:
+        gst_avi_demux_parse_idit (avi, sub);
+        goto next;
+      default:
+        GST_WARNING_OBJECT (avi,
+            "Unknown tag %" GST_FOURCC_FORMAT " in AVI header",
+            GST_FOURCC_ARGS (tag));
+        GST_MEMDUMP_OBJECT (avi, "Unknown tag", map.data, map.size);
+        /* fall-through */
+      case GST_RIFF_TAG_JUNQ:
+      case GST_RIFF_TAG_JUNK:
+      next:
+        if (sub) {
+          gst_buffer_unmap (sub, &map);
+          gst_buffer_unref (sub);
+        }
+        sub = NULL;
+        break;
+    }
+  }
+  gst_buffer_unref (buf);
+  GST_DEBUG ("elements parsed");
+
+  /* check parsed streams */
+  if (avi->num_streams == 0)
+    goto no_streams;
+  else if (avi->num_streams != avi->avih->streams) {
+    GST_WARNING_OBJECT (avi,
+        "Stream header mentioned %d streams, but %d available",
+        avi->avih->streams, avi->num_streams);
+  }
+
+  GST_DEBUG_OBJECT (avi, "skipping junk between header and data, offset=%"
+      G_GUINT64_FORMAT, avi->offset);
+
+  /* Now, find the data (i.e. skip all junk between header and data) */
+  do {
+    GstMapInfo map;
+    guint size;
+    guint32 tag, ltag;
+
+    buf = NULL;
+    res = gst_pad_pull_range (avi->sinkpad, avi->offset, 12, &buf);
+    if (res != GST_FLOW_OK) {
+      GST_DEBUG_OBJECT (avi, "pull_range failure while looking for tags");
+      goto pull_range_failed;
+    } else if (gst_buffer_get_size (buf) < 12) {
+      GST_DEBUG_OBJECT (avi,
+          "got %" G_GSIZE_FORMAT " bytes which is less than 12 bytes",
+          gst_buffer_get_size (buf));
+      gst_buffer_unref (buf);
+      return GST_FLOW_ERROR;
+    }
+
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    tag = GST_READ_UINT32_LE (map.data);
+    size = GST_READ_UINT32_LE (map.data + 4);
+    ltag = GST_READ_UINT32_LE (map.data + 8);
+
+    GST_DEBUG ("tag %" GST_FOURCC_FORMAT ", size %u",
+        GST_FOURCC_ARGS (tag), size);
+    GST_MEMDUMP ("Tag content", map.data, map.size);
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+
+    switch (tag) {
+      case GST_RIFF_TAG_LIST:{
+        switch (ltag) {
+          case GST_RIFF_LIST_movi:
+            GST_DEBUG_OBJECT (avi,
+                "Reached the 'movi' tag, we're done with skipping");
+            goto skipping_done;
+          case GST_RIFF_LIST_INFO:
+            res =
+                gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag,
+                &buf);
+            if (res != GST_FLOW_OK) {
+              GST_DEBUG_OBJECT (avi, "couldn't read INFO chunk");
+              goto pull_range_failed;
+            }
+            GST_DEBUG ("got size %" G_GSIZE_FORMAT, gst_buffer_get_size (buf));
+            if (size < 4) {
+              GST_DEBUG ("skipping INFO LIST prefix");
+              avi->offset += (4 - GST_ROUND_UP_2 (size));
+              gst_buffer_unref (buf);
+              continue;
+            }
+
+            sub = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, 4, -1);
+            gst_riff_parse_info (element, sub, &tags);
+            if (tags) {
+              if (avi->globaltags) {
+                gst_tag_list_insert (avi->globaltags, tags,
+                    GST_TAG_MERGE_REPLACE);
+                gst_tag_list_unref (tags);
+              } else {
+                avi->globaltags = tags;
+              }
+            }
+            tags = NULL;
+            if (sub) {
+              gst_buffer_unref (sub);
+              sub = NULL;
+            }
+            gst_buffer_unref (buf);
+            /* gst_riff_read_chunk() has already advanced avi->offset */
+            break;
+          case GST_RIFF_LIST_ncdt:
+            res =
+                gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag,
+                &buf);
+            if (res != GST_FLOW_OK) {
+              GST_DEBUG_OBJECT (avi, "couldn't read ncdt chunk");
+              goto pull_range_failed;
+            }
+            GST_DEBUG ("got size %" G_GSIZE_FORMAT, gst_buffer_get_size (buf));
+            if (size < 4) {
+              GST_DEBUG ("skipping ncdt LIST prefix");
+              avi->offset += (4 - GST_ROUND_UP_2 (size));
+              gst_buffer_unref (buf);
+              continue;
+            }
+
+            sub = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, 4, -1);
+            gst_avi_demux_parse_ncdt (avi, sub, &tags);
+            if (tags) {
+              if (avi->globaltags) {
+                gst_tag_list_insert (avi->globaltags, tags,
+                    GST_TAG_MERGE_REPLACE);
+                gst_tag_list_unref (tags);
+              } else {
+                avi->globaltags = tags;
+              }
+            }
+            tags = NULL;
+            if (sub) {
+              gst_buffer_unref (sub);
+              sub = NULL;
+            }
+            gst_buffer_unref (buf);
+            /* gst_riff_read_chunk() has already advanced avi->offset */
+            break;
+          default:
+            GST_WARNING_OBJECT (avi,
+                "Skipping unknown list tag %" GST_FOURCC_FORMAT,
+                GST_FOURCC_ARGS (ltag));
+            avi->offset += 8 + GST_ROUND_UP_2 (size);
+            break;
+        }
+      }
+        break;
+      default:
+        GST_WARNING_OBJECT (avi, "Skipping unknown tag %" GST_FOURCC_FORMAT,
+            GST_FOURCC_ARGS (tag));
+        /* Fall-through */
+      case GST_MAKE_FOURCC ('J', 'U', 'N', 'Q'):
+      case GST_MAKE_FOURCC ('J', 'U', 'N', 'K'):
+        /* Only get buffer for debugging if the memdump is needed  */
+        if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= 9) {
+          buf = NULL;
+          res = gst_pad_pull_range (avi->sinkpad, avi->offset, size, &buf);
+          if (res != GST_FLOW_OK) {
+            GST_DEBUG_OBJECT (avi, "couldn't read INFO chunk");
+            goto pull_range_failed;
+          }
+          gst_buffer_map (buf, &map, GST_MAP_READ);
+          GST_MEMDUMP ("Junk", map.data, map.size);
+          gst_buffer_unmap (buf, &map);
+          gst_buffer_unref (buf);
+        }
+        avi->offset += 8 + GST_ROUND_UP_2 (size);
+        break;
+    }
+  } while (1);
+skipping_done:
+
+  GST_DEBUG_OBJECT (avi, "skipping done ... (streams=%u, stream[0].indexes=%p)",
+      avi->num_streams, avi->stream[0].indexes);
+
+  /* create or read stream index (for seeking) */
+  if (avi->stream[0].indexes != NULL) {
+    /* we read a super index already (gst_avi_demux_parse_superindex() ) */
+    gst_avi_demux_read_subindexes_pull (avi);
+  }
+  if (!avi->have_index) {
+    if (avi->avih->flags & GST_RIFF_AVIH_HASINDEX)
+      gst_avi_demux_stream_index (avi);
+
+    /* still no index, scan */
+    if (!avi->have_index) {
+      gst_avi_demux_stream_scan (avi);
+
+      /* still no index.. this is a fatal error for now.
+       * FIXME, we should switch to plain push mode without seeking
+       * instead of failing. */
+      if (!avi->have_index)
+        goto no_index;
+    }
+  }
+  /* use the indexes now to construct nice durations */
+  gst_avi_demux_calculate_durations_from_index (avi);
+
+  gst_avi_demux_expose_streams (avi, FALSE);
+
+  /* do initial seek to the default segment values */
+  gst_avi_demux_do_seek (avi, &avi->segment, 0);
+
+  /* create initial NEWSEGMENT event */
+  if (avi->seg_event)
+    gst_event_unref (avi->seg_event);
+  avi->seg_event = gst_event_new_segment (&avi->segment);
+  if (avi->segment_seqnum)
+    gst_event_set_seqnum (avi->seg_event, avi->segment_seqnum);
+
+  stamp = gst_util_get_timestamp () - stamp;
+  GST_DEBUG_OBJECT (avi, "pulling header took %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (stamp));
+
+  /* at this point we know all the streams and we can signal the no more
+   * pads signal */
+  GST_DEBUG_OBJECT (avi, "signaling no more pads");
+  gst_element_no_more_pads (GST_ELEMENT_CAST (avi));
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+no_list:
+  {
+    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
+        ("Invalid AVI header (no LIST at start): %"
+            GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+no_header:
+  {
+    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
+        ("Invalid AVI header (no hdrl at start): %"
+            GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+no_avih:
+  {
+    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
+        ("Invalid AVI header (no avih at start): %"
+            GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
+    if (sub)
+      gst_buffer_unref (sub);
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+invalid_avih:
+  {
+    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
+        ("Invalid AVI header (cannot parse avih at start)"));
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+no_streams:
+  {
+    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("No streams found"));
+    return GST_FLOW_ERROR;
+  }
+no_index:
+  {
+    GST_WARNING ("file without or too big index");
+    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
+        ("Could not get/create index"));
+    return GST_FLOW_ERROR;
+  }
+pull_range_failed:
+  {
+    if (res == GST_FLOW_FLUSHING)
+      return res;
+    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
+        ("pull_range flow reading header: %s", gst_flow_get_name (res)));
+    return res;
+  }
+}
+
+/* move a stream to @index */
+static void
+gst_avi_demux_move_stream (GstAviDemux * avi, GstAviStream * stream,
+    GstSegment * segment, guint index)
+{
+  GST_DEBUG_OBJECT (avi, "Move stream %d to %u", stream->num, index);
+
+  if (segment->rate < 0.0) {
+    guint next_key;
+    /* Because we don't know the frame order we need to push from the prev keyframe
+     * to the next keyframe. If there is a smart decoder downstream he will notice
+     * that there are too many encoded frames send and return EOS when there
+     * are enough decoded frames to fill the segment. */
+    next_key = gst_avi_demux_index_next (avi, stream, index, TRUE);
+
+    /* FIXME, we go back to 0, we should look at segment.start. We will however
+     * stop earlier when the see the timestamp < segment.start */
+    stream->start_entry = 0;
+    stream->step_entry = index;
+    stream->current_entry = index;
+    stream->stop_entry = next_key;
+
+    GST_DEBUG_OBJECT (avi, "reverse seek: start %u, step %u, stop %u",
+        stream->start_entry, stream->step_entry, stream->stop_entry);
+  } else {
+    stream->start_entry = index;
+    stream->step_entry = index;
+    stream->stop_entry = gst_avi_demux_index_last (avi, stream);
+  }
+  if (stream->current_entry != index) {
+    GST_DEBUG_OBJECT (avi, "Move DISCONT from %u to %u",
+        stream->current_entry, index);
+    stream->current_entry = index;
+    stream->discont = TRUE;
+  }
+
+  /* update the buffer info */
+  gst_avi_demux_get_buffer_info (avi, stream, index,
+      &stream->current_timestamp, &stream->current_ts_end,
+      &stream->current_offset, &stream->current_offset_end);
+
+  GST_DEBUG_OBJECT (avi, "Moved to %u, ts %" GST_TIME_FORMAT
+      ", ts_end %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT
+      ", off_end %" G_GUINT64_FORMAT, index,
+      GST_TIME_ARGS (stream->current_timestamp),
+      GST_TIME_ARGS (stream->current_ts_end), stream->current_offset,
+      stream->current_offset_end);
+
+  GST_DEBUG_OBJECT (avi, "Seeking to offset %" G_GUINT64_FORMAT,
+      stream->index[index].offset);
+}
+
+/*
+ * Do the actual seeking.
+ */
+static gboolean
+gst_avi_demux_do_seek (GstAviDemux * avi, GstSegment * segment,
+    GstSeekFlags flags)
+{
+  GstClockTime seek_time;
+  gboolean keyframe, before, after;
+  guint i, index;
+  GstAviStream *stream;
+  gboolean next;
+
+  seek_time = segment->position;
+  keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
+  before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
+  after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
+
+  GST_DEBUG_OBJECT (avi, "seek to: %" GST_TIME_FORMAT
+      " keyframe seeking:%d, %s", GST_TIME_ARGS (seek_time), keyframe,
+      snap_types[before ? 1 : 0][after ? 1 : 0]);
+
+  /* FIXME, this code assumes the main stream with keyframes is stream 0,
+   * which is mostly correct... */
+  stream = &avi->stream[avi->main_stream];
+
+  next = after && !before;
+  if (segment->rate < 0)
+    next = !next;
+
+  /* get the entry index for the requested position */
+  index = gst_avi_demux_index_for_time (avi, stream, seek_time, next);
+  GST_DEBUG_OBJECT (avi, "Got entry %u", index);
+  if (index == -1)
+    return FALSE;
+
+  /* check if we are already on a keyframe */
+  if (!ENTRY_IS_KEYFRAME (&stream->index[index])) {
+    if (next) {
+      GST_DEBUG_OBJECT (avi, "not keyframe, searching forward");
+      /* now go to the next keyframe, this is where we should start
+       * decoding from. */
+      index = gst_avi_demux_index_next (avi, stream, index, TRUE);
+      GST_DEBUG_OBJECT (avi, "next keyframe at %u", index);
+    } else {
+      GST_DEBUG_OBJECT (avi, "not keyframe, searching back");
+      /* now go to the previous keyframe, this is where we should start
+       * decoding from. */
+      index = gst_avi_demux_index_prev (avi, stream, index, TRUE);
+      GST_DEBUG_OBJECT (avi, "previous keyframe at %u", index);
+    }
+  }
+
+  /* move the main stream to this position */
+  gst_avi_demux_move_stream (avi, stream, segment, index);
+
+  if (keyframe) {
+    /* when seeking to a keyframe, we update the result seek time
+     * to the time of the keyframe. */
+    seek_time = stream->current_timestamp;
+    GST_DEBUG_OBJECT (avi, "keyframe adjusted to %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (seek_time));
+    /* the seek time is always the position ... */
+    segment->position = seek_time;
+    /* ... and start and stream time when going forwards,
+     * otherwise only stop time */
+    if (segment->rate > 0.0)
+      segment->start = segment->time = seek_time;
+    else
+      segment->stop = seek_time;
+  }
+
+  /* now set DISCONT and align the other streams */
+  for (i = 0; i < avi->num_streams; i++) {
+    GstAviStream *ostream;
+
+    ostream = &avi->stream[i];
+    if ((ostream == stream) || (ostream->index == NULL))
+      continue;
+
+    /* get the entry index for the requested position */
+    index = gst_avi_demux_index_for_time (avi, ostream, seek_time, FALSE);
+    if (index == -1)
+      continue;
+
+    /* move to previous keyframe */
+    if (!ENTRY_IS_KEYFRAME (&ostream->index[index]))
+      index = gst_avi_demux_index_prev (avi, ostream, index, TRUE);
+
+    gst_avi_demux_move_stream (avi, ostream, segment, index);
+  }
+  GST_DEBUG_OBJECT (avi, "done seek to: %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (seek_time));
+
+  return TRUE;
+}
+
+/*
+ * Handle seek event in pull mode.
+ */
+static gboolean
+gst_avi_demux_handle_seek (GstAviDemux * avi, GstPad * pad, GstEvent * event)
+{
+  gdouble rate;
+  GstFormat format;
+  GstSeekFlags flags;
+  GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
+  gint64 cur, stop;
+  gboolean flush;
+  gboolean update;
+  GstSegment seeksegment = { 0, };
+  gint i;
+  guint32 seqnum = 0;
+
+  if (event) {
+    GST_DEBUG_OBJECT (avi, "doing seek with event");
+
+    gst_event_parse_seek (event, &rate, &format, &flags,
+        &cur_type, &cur, &stop_type, &stop);
+    seqnum = gst_event_get_seqnum (event);
+
+    /* we have to have a format as the segment format. Try to convert
+     * if not. */
+    if (format != GST_FORMAT_TIME) {
+      gboolean res = TRUE;
+
+      if (cur_type != GST_SEEK_TYPE_NONE)
+        res = gst_pad_query_convert (pad, format, cur, GST_FORMAT_TIME, &cur);
+      if (res && stop_type != GST_SEEK_TYPE_NONE)
+        res = gst_pad_query_convert (pad, format, stop, GST_FORMAT_TIME, &stop);
+      if (!res)
+        goto no_format;
+
+      format = GST_FORMAT_TIME;
+    }
+    GST_DEBUG_OBJECT (avi,
+        "seek requested: rate %g cur %" GST_TIME_FORMAT " stop %"
+        GST_TIME_FORMAT, rate, GST_TIME_ARGS (cur), GST_TIME_ARGS (stop));
+    /* FIXME: can we do anything with rate!=1.0 */
+  } else {
+    GST_DEBUG_OBJECT (avi, "doing seek without event");
+    flags = 0;
+    rate = 1.0;
+  }
+
+  /* save flush flag */
+  flush = flags & GST_SEEK_FLAG_FLUSH;
+
+  if (flush) {
+    GstEvent *fevent = gst_event_new_flush_start ();
+
+    if (seqnum)
+      gst_event_set_seqnum (fevent, seqnum);
+    /* for a flushing seek, we send a flush_start on all pads. This will
+     * eventually stop streaming with a WRONG_STATE. We can thus eventually
+     * take the STREAM_LOCK. */
+    GST_DEBUG_OBJECT (avi, "sending flush start");
+    gst_avi_demux_push_event (avi, gst_event_ref (fevent));
+    gst_pad_push_event (avi->sinkpad, fevent);
+  } else {
+    /* a non-flushing seek, we PAUSE the task so that we can take the
+     * STREAM_LOCK */
+    GST_DEBUG_OBJECT (avi, "non flushing seek, pausing task");
+    gst_pad_pause_task (avi->sinkpad);
+  }
+
+  /* wait for streaming to stop */
+  GST_DEBUG_OBJECT (avi, "wait for streaming to stop");
+  GST_PAD_STREAM_LOCK (avi->sinkpad);
+
+  /* copy segment, we need this because we still need the old
+   * segment when we close the current segment. */
+  memcpy (&seeksegment, &avi->segment, sizeof (GstSegment));
+
+  if (event) {
+    GST_DEBUG_OBJECT (avi, "configuring seek");
+    gst_segment_do_seek (&seeksegment, rate, format, flags,
+        cur_type, cur, stop_type, stop, &update);
+  }
+  /* do the seek, seeksegment.position contains the new position, this
+   * actually never fails. */
+  gst_avi_demux_do_seek (avi, &seeksegment, flags);
+
+  if (flush) {
+    GstEvent *fevent = gst_event_new_flush_stop (TRUE);
+
+    if (seqnum)
+      gst_event_set_seqnum (fevent, seqnum);
+
+    GST_DEBUG_OBJECT (avi, "sending flush stop");
+    gst_avi_demux_push_event (avi, gst_event_ref (fevent));
+    gst_pad_push_event (avi->sinkpad, fevent);
+  }
+
+  /* now update the real segment info */
+  memcpy (&avi->segment, &seeksegment, sizeof (GstSegment));
+
+  /* post the SEGMENT_START message when we do segmented playback */
+  if (avi->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+    GstMessage *segment_start_msg =
+        gst_message_new_segment_start (GST_OBJECT_CAST (avi),
+        avi->segment.format, avi->segment.position);
+    if (seqnum)
+      gst_message_set_seqnum (segment_start_msg, seqnum);
+    gst_element_post_message (GST_ELEMENT_CAST (avi), segment_start_msg);
+  }
+
+  /* queue the segment event for the streaming thread. */
+  if (avi->seg_event)
+    gst_event_unref (avi->seg_event);
+  avi->seg_event = gst_event_new_segment (&avi->segment);
+  if (seqnum)
+    gst_event_set_seqnum (avi->seg_event, seqnum);
+  avi->segment_seqnum = seqnum;
+
+  if (!avi->streaming) {
+    gst_pad_start_task (avi->sinkpad, (GstTaskFunction) gst_avi_demux_loop,
+        avi->sinkpad, NULL);
+  }
+  /* reset the last flow and mark discont, seek is always DISCONT */
+  for (i = 0; i < avi->num_streams; i++) {
+    GST_DEBUG_OBJECT (avi, "marking DISCONT");
+    avi->stream[i].discont = TRUE;
+  }
+  /* likewise for the whole new segment */
+  gst_flow_combiner_reset (avi->flowcombiner);
+  GST_PAD_STREAM_UNLOCK (avi->sinkpad);
+
+  return TRUE;
+
+  /* ERRORS */
+no_format:
+  {
+    GST_DEBUG_OBJECT (avi, "unsupported format given, seek aborted.");
+    return FALSE;
+  }
+}
+
+/*
+ * Handle seek event in push mode.
+ */
+static gboolean
+avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad, GstEvent * event)
+{
+  gdouble rate;
+  GstFormat format;
+  GstSeekFlags flags;
+  GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
+  gint64 cur, stop;
+  gboolean keyframe, before, after, next;
+  GstAviStream *stream;
+  guint index;
+  guint n, str_num;
+  guint64 min_offset;
+  GstSegment seeksegment;
+  gboolean update;
+
+  /* check we have the index */
+  if (!avi->have_index) {
+    GST_DEBUG_OBJECT (avi, "no seek index built, seek aborted.");
+    return FALSE;
+  } else {
+    GST_DEBUG_OBJECT (avi, "doing push-based seek with event");
+  }
+
+  gst_event_parse_seek (event, &rate, &format, &flags,
+      &cur_type, &cur, &stop_type, &stop);
+
+  if (format != GST_FORMAT_TIME) {
+    gboolean res = TRUE;
+
+    if (cur_type != GST_SEEK_TYPE_NONE)
+      res = gst_pad_query_convert (pad, format, cur, GST_FORMAT_TIME, &cur);
+    if (res && stop_type != GST_SEEK_TYPE_NONE)
+      res = gst_pad_query_convert (pad, format, stop, GST_FORMAT_TIME, &stop);
+    if (!res) {
+      GST_DEBUG_OBJECT (avi, "unsupported format given, seek aborted.");
+      return FALSE;
+    }
+
+    format = GST_FORMAT_TIME;
+  }
+
+  /* let gst_segment handle any tricky stuff */
+  GST_DEBUG_OBJECT (avi, "configuring seek");
+  memcpy (&seeksegment, &avi->segment, sizeof (GstSegment));
+  gst_segment_do_seek (&seeksegment, rate, format, flags,
+      cur_type, cur, stop_type, stop, &update);
+
+  keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
+  cur = seeksegment.position;
+  before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
+  after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
+
+  GST_DEBUG_OBJECT (avi,
+      "Seek requested: ts %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT
+      ", kf %u, %s, rate %lf", GST_TIME_ARGS (cur), GST_TIME_ARGS (stop),
+      keyframe, snap_types[before ? 1 : 0][after ? 1 : 0], rate);
+
+  if (rate < 0) {
+    GST_DEBUG_OBJECT (avi, "negative rate seek not supported in push mode");
+    return FALSE;
+  }
+
+  /* FIXME, this code assumes the main stream with keyframes is stream 0,
+   * which is mostly correct... */
+  str_num = avi->main_stream;
+  stream = &avi->stream[str_num];
+
+  next = after && !before;
+  if (seeksegment.rate < 0)
+    next = !next;
+
+  /* get the entry index for the requested position */
+  index = gst_avi_demux_index_for_time (avi, stream, cur, next);
+  GST_DEBUG_OBJECT (avi, "str %u: Found entry %u for %" GST_TIME_FORMAT,
+      str_num, index, GST_TIME_ARGS (cur));
+  if (index == -1)
+    return -1;
+
+  /* check if we are already on a keyframe */
+  if (!ENTRY_IS_KEYFRAME (&stream->index[index])) {
+    if (next) {
+      GST_DEBUG_OBJECT (avi, "Entry is not a keyframe - searching forward");
+      /* now go to the next keyframe, this is where we should start
+       * decoding from. */
+      index = gst_avi_demux_index_next (avi, stream, index, TRUE);
+      GST_DEBUG_OBJECT (avi, "Found previous keyframe at %u", index);
+    } else {
+      GST_DEBUG_OBJECT (avi, "Entry is not a keyframe - searching back");
+      /* now go to the previous keyframe, this is where we should start
+       * decoding from. */
+      index = gst_avi_demux_index_prev (avi, stream, index, TRUE);
+      GST_DEBUG_OBJECT (avi, "Found previous keyframe at %u", index);
+    }
+  }
+
+  gst_avi_demux_get_buffer_info (avi, stream, index,
+      &stream->current_timestamp, &stream->current_ts_end,
+      &stream->current_offset, &stream->current_offset_end);
+
+  /* re-use cur to be the timestamp of the seek as it _will_ be */
+  cur = stream->current_timestamp;
+
+  min_offset = stream->index[index].offset;
+  avi->seek_kf_offset = min_offset - 8;
+
+  GST_DEBUG_OBJECT (avi,
+      "Seek to: ts %" GST_TIME_FORMAT " (on str %u, idx %u, offset %"
+      G_GUINT64_FORMAT ")", GST_TIME_ARGS (stream->current_timestamp), str_num,
+      index, min_offset);
+
+  for (n = 0; n < avi->num_streams; n++) {
+    GstAviStream *str = &avi->stream[n];
+    guint idx;
+
+    if (n == avi->main_stream)
+      continue;
+
+    /* get the entry index for the requested position */
+    idx = gst_avi_demux_index_for_time (avi, str, cur, FALSE);
+    GST_DEBUG_OBJECT (avi, "str %u: Found entry %u for %" GST_TIME_FORMAT, n,
+        idx, GST_TIME_ARGS (cur));
+    if (idx == -1)
+      continue;
+
+    /* check if we are already on a keyframe */
+    if (!ENTRY_IS_KEYFRAME (&str->index[idx])) {
+      if (next) {
+        GST_DEBUG_OBJECT (avi, "Entry is not a keyframe - searching forward");
+        /* now go to the next keyframe, this is where we should start
+         * decoding from. */
+        idx = gst_avi_demux_index_next (avi, str, idx, TRUE);
+        GST_DEBUG_OBJECT (avi, "Found next keyframe at %u", idx);
+      } else {
+        GST_DEBUG_OBJECT (avi, "Entry is not a keyframe - searching back");
+        /* now go to the previous keyframe, this is where we should start
+         * decoding from. */
+        idx = gst_avi_demux_index_prev (avi, str, idx, TRUE);
+        GST_DEBUG_OBJECT (avi, "Found previous keyframe at %u", idx);
+      }
+    }
+
+    gst_avi_demux_get_buffer_info (avi, str, idx,
+        &str->current_timestamp, &str->current_ts_end,
+        &str->current_offset, &str->current_offset_end);
+
+    if (str->index[idx].offset < min_offset) {
+      min_offset = str->index[idx].offset;
+      GST_DEBUG_OBJECT (avi,
+          "Found an earlier offset at %" G_GUINT64_FORMAT ", str %u",
+          min_offset, n);
+      str_num = n;
+      stream = str;
+      index = idx;
+    }
+  }
+
+  GST_DEBUG_OBJECT (avi,
+      "Seek performed: str %u, offset %" G_GUINT64_FORMAT ", idx %u, ts %"
+      GST_TIME_FORMAT ", ts_end %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT
+      ", off_end %" G_GUINT64_FORMAT, str_num, min_offset, index,
+      GST_TIME_ARGS (stream->current_timestamp),
+      GST_TIME_ARGS (stream->current_ts_end), stream->current_offset,
+      stream->current_offset_end);
+
+  /* index data refers to data, not chunk header (for pull mode convenience) */
+  min_offset -= 8;
+  GST_DEBUG_OBJECT (avi, "seeking to chunk at offset %" G_GUINT64_FORMAT,
+      min_offset);
+
+  if (!perform_seek_to_offset (avi, min_offset, gst_event_get_seqnum (event))) {
+    GST_DEBUG_OBJECT (avi, "seek event failed!");
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/*
+ * Handle whether we can perform the seek event or if we have to let the chain
+ * function handle seeks to build the seek indexes first.
+ */
+static gboolean
+gst_avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad,
+    GstEvent * event)
+{
+  /* check for having parsed index already */
+  if (!avi->have_index) {
+    guint64 offset = 0;
+    gboolean building_index;
+
+    GST_OBJECT_LOCK (avi);
+    /* handle the seek event in the chain function */
+    avi->state = GST_AVI_DEMUX_SEEK;
+
+    /* copy the event */
+    if (avi->seek_event)
+      gst_event_unref (avi->seek_event);
+    avi->seek_event = gst_event_ref (event);
+
+    /* set the building_index flag so that only one thread can setup the
+     * structures for index seeking. */
+    building_index = avi->building_index;
+    if (!building_index) {
+      avi->building_index = TRUE;
+      if (avi->stream[0].indexes) {
+        avi->odml_stream = 0;
+        avi->odml_subidxs = avi->stream[avi->odml_stream].indexes;
+        offset = avi->odml_subidxs[0];
+      } else {
+        offset = avi->idx1_offset;
+      }
+    }
+    GST_OBJECT_UNLOCK (avi);
+
+    if (!building_index) {
+      /* seek to the first subindex or legacy index */
+      GST_INFO_OBJECT (avi,
+          "Seeking to legacy index/first subindex at %" G_GUINT64_FORMAT,
+          offset);
+      return perform_seek_to_offset (avi, offset, gst_event_get_seqnum (event));
+    }
+
+    /* FIXME: we have to always return true so that we don't block the seek
+     * thread.
+     * Note: maybe it is OK to return true if we're still building the index */
+    return TRUE;
+  }
+
+  return avi_demux_handle_seek_push (avi, pad, event);
+}
+
+/*
+ * Helper for gst_avi_demux_invert()
+ */
+static inline void
+swap_line (guint8 * d1, guint8 * d2, guint8 * tmp, gint bytes)
+{
+  memcpy (tmp, d1, bytes);
+  memcpy (d1, d2, bytes);
+  memcpy (d2, tmp, bytes);
+}
+
+
+#define gst_avi_demux_is_uncompressed(fourcc)		\
+  (fourcc == GST_RIFF_DIB ||				\
+   fourcc == GST_RIFF_rgb ||				\
+   fourcc == GST_RIFF_RGB || fourcc == GST_RIFF_RAW)
+
+/*
+ * Invert DIB buffers... Takes existing buffer and
+ * returns either the buffer or a new one (with old
+ * one dereferenced).
+ * FIXME: can't we preallocate tmp? and remember stride, bpp?
+ */
+static GstBuffer *
+gst_avi_demux_invert (GstAviStream * stream, GstBuffer * buf)
+{
+  gint y, w, h;
+  gint bpp, stride;
+  guint8 *tmp = NULL;
+  GstMapInfo map;
+  guint32 fourcc;
+
+  if (stream->strh->type != GST_RIFF_FCC_vids)
+    return buf;
+
+  if (stream->strf.vids == NULL) {
+    GST_WARNING ("Failed to retrieve vids for stream");
+    return buf;
+  }
+
+  fourcc = (stream->strf.vids->compression) ?
+      stream->strf.vids->compression : stream->strh->fcc_handler;
+  if (!gst_avi_demux_is_uncompressed (fourcc)) {
+    return buf;                 /* Ignore non DIB buffers */
+  }
+
+  /* raw rgb data is stored topdown, but instead of inverting the buffer, */
+  /* some tools just negate the height field in the header (e.g. ffmpeg) */
+  if (((gint32) stream->strf.vids->height) < 0)
+    return buf;
+
+  h = stream->strf.vids->height;
+  w = stream->strf.vids->width;
+  bpp = stream->strf.vids->bit_cnt ? stream->strf.vids->bit_cnt : 8;
+  stride = GST_ROUND_UP_4 (w * (bpp / 8));
+
+  buf = gst_buffer_make_writable (buf);
+
+  gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+  if (map.size < (stride * h)) {
+    GST_WARNING ("Buffer is smaller than reported Width x Height x Depth");
+    gst_buffer_unmap (buf, &map);
+    return buf;
+  }
+
+  tmp = g_malloc (stride);
+
+  for (y = 0; y < h / 2; y++) {
+    swap_line (map.data + stride * y, map.data + stride * (h - 1 - y), tmp,
+        stride);
+  }
+
+  g_free (tmp);
+
+  gst_buffer_unmap (buf, &map);
+
+  /* append palette to paletted RGB8 buffer data */
+  if (stream->rgb8_palette != NULL)
+    buf = gst_buffer_append (buf, gst_buffer_ref (stream->rgb8_palette));
+
+  return buf;
+}
+
+#if 0
+static void
+gst_avi_demux_add_assoc (GstAviDemux * avi, GstAviStream * stream,
+    GstClockTime timestamp, guint64 offset, gboolean keyframe)
+{
+  /* do not add indefinitely for open-ended streaming */
+  if (G_UNLIKELY (avi->element_index && avi->seekable)) {
+    GST_LOG_OBJECT (avi, "adding association %" GST_TIME_FORMAT "-> %"
+        G_GUINT64_FORMAT, GST_TIME_ARGS (timestamp), offset);
+    gst_index_add_association (avi->element_index, avi->index_id,
+        keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
+        GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, timestamp,
+        GST_FORMAT_BYTES, offset, NULL);
+    /* current_entry is DEFAULT (frame #) */
+    gst_index_add_association (avi->element_index, stream->index_id,
+        keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
+        GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, timestamp,
+        GST_FORMAT_BYTES, offset, GST_FORMAT_DEFAULT, stream->current_entry,
+        NULL);
+  }
+}
+#endif
+
+/*
+ * Returns the aggregated GstFlowReturn.
+ */
+static GstFlowReturn
+gst_avi_demux_combine_flows (GstAviDemux * avi, GstAviStream * stream,
+    GstFlowReturn ret)
+{
+  GST_LOG_OBJECT (avi, "Stream %s:%s flow return: %s",
+      GST_DEBUG_PAD_NAME (stream->pad), gst_flow_get_name (ret));
+  ret = gst_flow_combiner_update_pad_flow (avi->flowcombiner, stream->pad, ret);
+  GST_LOG_OBJECT (avi, "combined to return %s", gst_flow_get_name (ret));
+
+  return ret;
+}
+
+/* move @stream to the next position in its index */
+static GstFlowReturn
+gst_avi_demux_advance (GstAviDemux * avi, GstAviStream * stream,
+    GstFlowReturn ret)
+{
+  guint old_entry, new_entry;
+
+  old_entry = stream->current_entry;
+  /* move forwards */
+  new_entry = old_entry + 1;
+
+  /* see if we reached the end */
+  if (new_entry >= stream->stop_entry) {
+    if (avi->segment.rate < 0.0) {
+      if (stream->step_entry == stream->start_entry) {
+        /* we stepped all the way to the start, eos */
+        GST_DEBUG_OBJECT (avi, "reverse reached start %u", stream->start_entry);
+        goto eos;
+      }
+      /* backwards, stop becomes step, find a new step */
+      stream->stop_entry = stream->step_entry;
+      stream->step_entry = gst_avi_demux_index_prev (avi, stream,
+          stream->stop_entry, TRUE);
+
+      GST_DEBUG_OBJECT (avi,
+          "reverse playback jump: start %u, step %u, stop %u",
+          stream->start_entry, stream->step_entry, stream->stop_entry);
+
+      /* and start from the previous keyframe now */
+      new_entry = stream->step_entry;
+    } else {
+      /* EOS */
+      GST_DEBUG_OBJECT (avi, "forward reached stop %u", stream->stop_entry);
+      goto eos;
+    }
+  }
+
+  if (new_entry != old_entry) {
+    stream->current_entry = new_entry;
+    stream->current_total = stream->index[new_entry].total;
+
+    if (new_entry == old_entry + 1) {
+      GST_DEBUG_OBJECT (avi, "moved forwards from %u to %u",
+          old_entry, new_entry);
+      /* we simply moved one step forwards, reuse current info */
+      stream->current_timestamp = stream->current_ts_end;
+      stream->current_offset = stream->current_offset_end;
+      gst_avi_demux_get_buffer_info (avi, stream, new_entry,
+          NULL, &stream->current_ts_end, NULL, &stream->current_offset_end);
+    } else {
+      /* we moved DISCONT, full update */
+      gst_avi_demux_get_buffer_info (avi, stream, new_entry,
+          &stream->current_timestamp, &stream->current_ts_end,
+          &stream->current_offset, &stream->current_offset_end);
+      /* and MARK discont for this stream */
+      stream->discont = TRUE;
+      GST_DEBUG_OBJECT (avi, "Moved from %u to %u, ts %" GST_TIME_FORMAT
+          ", ts_end %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT
+          ", off_end %" G_GUINT64_FORMAT, old_entry, new_entry,
+          GST_TIME_ARGS (stream->current_timestamp),
+          GST_TIME_ARGS (stream->current_ts_end), stream->current_offset,
+          stream->current_offset_end);
+    }
+  }
+  return ret;
+
+  /* ERROR */
+eos:
+  {
+    GST_DEBUG_OBJECT (avi, "we are EOS");
+    /* setting current_timestamp to -1 marks EOS */
+    stream->current_timestamp = -1;
+    return GST_FLOW_EOS;
+  }
+}
+
+/* find the stream with the lowest current position when going forwards or with
+ * the highest position when going backwards, this is the stream
+ * we should push from next */
+static gint
+gst_avi_demux_find_next (GstAviDemux * avi, gfloat rate)
+{
+  guint64 min_time, max_time;
+  guint stream_num, i;
+
+  max_time = 0;
+  min_time = G_MAXUINT64;
+  stream_num = -1;
+
+  for (i = 0; i < avi->num_streams; i++) {
+    guint64 position;
+    GstAviStream *stream;
+
+    stream = &avi->stream[i];
+
+    /* ignore streams that finished */
+    if (stream->pad && GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS)
+      continue;
+
+    position = stream->current_timestamp;
+
+    /* position of -1 is EOS */
+    if (position != -1) {
+      if (rate > 0.0 && position < min_time) {
+        min_time = position;
+        stream_num = i;
+      } else if (rate < 0.0 && position >= max_time) {
+        max_time = position;
+        stream_num = i;
+      }
+    }
+  }
+  return stream_num;
+}
+
+static GstBuffer *
+gst_avi_demux_align_buffer (GstAviDemux * demux,
+    GstBuffer * buffer, gsize alignment)
+{
+  GstMapInfo map;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  if (map.size < sizeof (guintptr)) {
+    gst_buffer_unmap (buffer, &map);
+    return buffer;
+  }
+
+  if (((guintptr) map.data) & (alignment - 1)) {
+    GstBuffer *new_buffer;
+    GstAllocationParams params = { 0, alignment - 1, 0, 0, };
+
+    new_buffer = gst_buffer_new_allocate (NULL,
+        gst_buffer_get_size (buffer), &params);
+
+    /* Copy data "by hand", so ensure alignment is kept: */
+    gst_buffer_fill (new_buffer, 0, map.data, map.size);
+
+    gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
+    GST_DEBUG_OBJECT (demux,
+        "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
+        alignment);
+
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+
+    return new_buffer;
+  }
+
+  gst_buffer_unmap (buffer, &map);
+  return buffer;
+}
+
+static GstFlowReturn
+gst_avi_demux_loop_data (GstAviDemux * avi)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint stream_num;
+  GstAviStream *stream;
+  gboolean processed = FALSE;
+  GstBuffer *buf;
+  guint64 offset, size;
+  GstClockTime timestamp, duration;
+  guint64 out_offset, out_offset_end;
+  gboolean keyframe;
+  GstAviIndexEntry *entry;
+
+  do {
+    stream_num = gst_avi_demux_find_next (avi, avi->segment.rate);
+
+    /* all are EOS */
+    if (G_UNLIKELY (stream_num == -1)) {
+      GST_DEBUG_OBJECT (avi, "all streams are EOS");
+      goto eos;
+    }
+
+    /* we have the stream now */
+    stream = &avi->stream[stream_num];
+
+    /* skip streams without pads */
+    if (!stream->pad) {
+      GST_DEBUG_OBJECT (avi, "skipping entry from stream %d without pad",
+          stream_num);
+      goto next;
+    }
+
+    /* get the timing info for the entry */
+    timestamp = stream->current_timestamp;
+    duration = stream->current_ts_end - timestamp;
+    out_offset = stream->current_offset;
+    out_offset_end = stream->current_offset_end;
+
+    /* get the entry data info */
+    entry = &stream->index[stream->current_entry];
+    offset = entry->offset;
+    size = entry->size;
+    keyframe = ENTRY_IS_KEYFRAME (entry);
+
+    /* skip empty entries */
+    if (size == 0) {
+      GST_DEBUG_OBJECT (avi, "Skipping entry %u (%" G_GUINT64_FORMAT ", %p)",
+          stream->current_entry, size, stream->pad);
+      goto next;
+    }
+
+    if (avi->segment.rate > 0.0) {
+      /* only check this for fowards playback for now */
+      if (keyframe && GST_CLOCK_TIME_IS_VALID (avi->segment.stop)
+          && (timestamp > avi->segment.stop)) {
+        goto eos_stop;
+      }
+    } else {
+      if (keyframe && GST_CLOCK_TIME_IS_VALID (avi->segment.start)
+          && (timestamp < avi->segment.start))
+        goto eos_stop;
+    }
+
+    GST_LOG ("reading buffer (size=%" G_GUINT64_FORMAT "), stream %d, pos %"
+        G_GUINT64_FORMAT " (0x%" G_GINT64_MODIFIER "x), kf %d", size,
+        stream_num, offset, offset, keyframe);
+
+    /* FIXME, check large chunks and cut them up */
+
+    /* pull in the data */
+    buf = NULL;
+    ret = gst_pad_pull_range (avi->sinkpad, offset, size, &buf);
+    if (ret != GST_FLOW_OK)
+      goto pull_failed;
+
+    /* check for short buffers, this is EOS as well */
+    if (gst_buffer_get_size (buf) < size)
+      goto short_buffer;
+
+    /* invert the picture if needed, and append palette for RGB8P */
+    buf = gst_avi_demux_invert (stream, buf);
+
+    /* mark non-keyframes */
+    if (keyframe || stream->is_raw) {
+      GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
+      GST_BUFFER_PTS (buf) = timestamp;
+    } else {
+      GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
+      GST_BUFFER_PTS (buf) = GST_CLOCK_TIME_NONE;
+    }
+
+    GST_BUFFER_DTS (buf) = timestamp;
+
+    GST_BUFFER_DURATION (buf) = duration;
+    GST_BUFFER_OFFSET (buf) = out_offset;
+    GST_BUFFER_OFFSET_END (buf) = out_offset_end;
+
+    /* mark discont when pending */
+    if (stream->discont) {
+      GST_DEBUG_OBJECT (avi, "setting DISCONT flag");
+      GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+      stream->discont = FALSE;
+    } else {
+      GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
+    }
+#if 0
+    gst_avi_demux_add_assoc (avi, stream, timestamp, offset, keyframe);
+#endif
+
+    /* update current position in the segment */
+    avi->segment.position = timestamp;
+
+    GST_DEBUG_OBJECT (avi, "Pushing buffer of size %" G_GSIZE_FORMAT ", ts %"
+        GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT
+        ", off_end %" G_GUINT64_FORMAT,
+        gst_buffer_get_size (buf), GST_TIME_ARGS (timestamp),
+        GST_TIME_ARGS (duration), out_offset, out_offset_end);
+
+    if (stream->alignment > 1)
+      buf = gst_avi_demux_align_buffer (avi, buf, stream->alignment);
+    ret = gst_pad_push (stream->pad, buf);
+
+    /* mark as processed, we increment the frame and byte counters then
+     * leave the while loop and return the GstFlowReturn */
+    processed = TRUE;
+
+    if (avi->segment.rate < 0) {
+      if (timestamp > avi->segment.stop && ret == GST_FLOW_EOS) {
+        /* In reverse playback we can get a GST_FLOW_EOS when
+         * we are at the end of the segment, so we just need to jump
+         * back to the previous section. */
+        GST_DEBUG_OBJECT (avi, "downstream has reached end of segment");
+        ret = GST_FLOW_OK;
+      }
+    }
+  next:
+    /* move to next item */
+    ret = gst_avi_demux_advance (avi, stream, ret);
+
+    /* combine flows */
+    ret = gst_avi_demux_combine_flows (avi, stream, ret);
+  } while (!processed);
+
+beach:
+  return ret;
+
+  /* special cases */
+eos:
+  {
+    GST_DEBUG_OBJECT (avi, "No samples left for any streams - EOS");
+    ret = GST_FLOW_EOS;
+    goto beach;
+  }
+eos_stop:
+  {
+    GST_LOG_OBJECT (avi, "Found keyframe after segment,"
+        " setting EOS (%" GST_TIME_FORMAT " > %" GST_TIME_FORMAT ")",
+        GST_TIME_ARGS (timestamp), GST_TIME_ARGS (avi->segment.stop));
+    ret = GST_FLOW_EOS;
+    /* move to next stream */
+    goto next;
+  }
+pull_failed:
+  {
+    GST_DEBUG_OBJECT (avi, "pull range failed: pos=%" G_GUINT64_FORMAT
+        " size=%" G_GUINT64_FORMAT, offset, size);
+    goto beach;
+  }
+short_buffer:
+  {
+    GST_WARNING_OBJECT (avi, "Short read at offset %" G_GUINT64_FORMAT
+        ", only got %" G_GSIZE_FORMAT "/%" G_GUINT64_FORMAT
+        " bytes (truncated file?)", offset, gst_buffer_get_size (buf), size);
+    gst_buffer_unref (buf);
+    ret = GST_FLOW_EOS;
+    goto beach;
+  }
+}
+
+/*
+ * Read data. If we have an index it delegates to
+ * gst_avi_demux_process_next_entry().
+ */
+static GstFlowReturn
+gst_avi_demux_stream_data (GstAviDemux * avi)
+{
+  guint32 tag = 0;
+  guint32 size = 0;
+  gint stream_nr = 0;
+  GstFlowReturn res = GST_FLOW_OK;
+
+  if (G_UNLIKELY (avi->have_eos)) {
+    /* Clean adapter, we're done */
+    gst_adapter_clear (avi->adapter);
+    return GST_FLOW_EOS;
+  }
+
+  if (G_UNLIKELY (avi->todrop)) {
+    guint drop;
+
+    if ((drop = gst_adapter_available (avi->adapter))) {
+      if (drop > avi->todrop)
+        drop = avi->todrop;
+      GST_DEBUG_OBJECT (avi, "Dropping %d bytes", drop);
+      gst_adapter_flush (avi->adapter, drop);
+      avi->todrop -= drop;
+      avi->offset += drop;
+    }
+  }
+
+  /* Iterate until need more data, so adapter won't grow too much */
+  while (1) {
+    if (G_UNLIKELY (!gst_avi_demux_peek_chunk_info (avi, &tag, &size))) {
+      return GST_FLOW_OK;
+    }
+
+    GST_DEBUG ("Trying chunk (%" GST_FOURCC_FORMAT "), size %d",
+        GST_FOURCC_ARGS (tag), size);
+
+    if (G_LIKELY ((tag & 0xff) >= '0' && (tag & 0xff) <= '9' &&
+            ((tag >> 8) & 0xff) >= '0' && ((tag >> 8) & 0xff) <= '9')) {
+      GST_LOG ("Chunk ok");
+    } else if ((tag & 0xffff) == (('x' << 8) | 'i')) {
+      GST_DEBUG ("Found sub-index tag");
+      if (gst_avi_demux_peek_chunk (avi, &tag, &size) || size == 0) {
+        /* accept 0 size buffer here */
+        avi->abort_buffering = FALSE;
+        GST_DEBUG ("  skipping %d bytes for now", size);
+        gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
+      }
+      return GST_FLOW_OK;
+    } else if (tag == GST_RIFF_TAG_RIFF) {
+      /* RIFF tags can appear in ODML files, just jump over them */
+      if (gst_adapter_available (avi->adapter) >= 12) {
+        GST_DEBUG ("Found RIFF tag, skipping RIFF header");
+        gst_adapter_flush (avi->adapter, 12);
+        continue;
+      }
+      return GST_FLOW_OK;
+    } else if (tag == GST_RIFF_TAG_idx1) {
+      GST_DEBUG ("Found index tag");
+      if (gst_avi_demux_peek_chunk (avi, &tag, &size) || size == 0) {
+        /* accept 0 size buffer here */
+        avi->abort_buffering = FALSE;
+        GST_DEBUG ("  skipping %d bytes for now", size);
+        gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
+      }
+      return GST_FLOW_OK;
+    } else if (tag == GST_RIFF_TAG_LIST) {
+      /* movi chunks might be grouped in rec list */
+      if (gst_adapter_available (avi->adapter) >= 12) {
+        GST_DEBUG ("Found LIST tag, skipping LIST header");
+        gst_adapter_flush (avi->adapter, 12);
+        continue;
+      }
+      return GST_FLOW_OK;
+    } else if (tag == GST_RIFF_TAG_JUNK || tag == GST_RIFF_TAG_JUNQ) {
+      /* rec list might contain JUNK chunks */
+      GST_DEBUG ("Found JUNK tag");
+      if (gst_avi_demux_peek_chunk (avi, &tag, &size) || size == 0) {
+        /* accept 0 size buffer here */
+        avi->abort_buffering = FALSE;
+        GST_DEBUG ("  skipping %d bytes for now", size);
+        gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
+      }
+      return GST_FLOW_OK;
+    } else {
+      GST_DEBUG ("No more stream chunks, send EOS");
+      avi->have_eos = TRUE;
+      return GST_FLOW_EOS;
+    }
+
+    if (G_UNLIKELY (!gst_avi_demux_peek_chunk (avi, &tag, &size))) {
+      /* supposedly one hopes to catch a nicer chunk later on ... */
+      /* FIXME ?? give up here rather than possibly ending up going
+       * through the whole file */
+      if (avi->abort_buffering) {
+        avi->abort_buffering = FALSE;
+        if (size) {
+          gst_adapter_flush (avi->adapter, 8);
+          return GST_FLOW_OK;
+        }
+      } else {
+        return GST_FLOW_OK;
+      }
+    }
+    GST_DEBUG ("chunk ID %" GST_FOURCC_FORMAT ", size %u",
+        GST_FOURCC_ARGS (tag), size);
+
+    stream_nr = CHUNKID_TO_STREAMNR (tag);
+
+    if (G_UNLIKELY (stream_nr < 0 || stream_nr >= avi->num_streams)) {
+      /* recoverable */
+      GST_WARNING ("Invalid stream ID %d (%" GST_FOURCC_FORMAT ")",
+          stream_nr, GST_FOURCC_ARGS (tag));
+      avi->offset += 8 + GST_ROUND_UP_2 (size);
+      gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
+    } else {
+      GstAviStream *stream;
+      GstClockTime next_ts = 0;
+      GstBuffer *buf = NULL;
+#if 0
+      guint64 offset;
+#endif
+      gboolean saw_desired_kf = stream_nr != avi->main_stream
+          || avi->offset >= avi->seek_kf_offset;
+
+      if (stream_nr == avi->main_stream && avi->offset == avi->seek_kf_offset) {
+        GST_DEBUG_OBJECT (avi, "Desired keyframe reached");
+        avi->seek_kf_offset = 0;
+      }
+
+      if (saw_desired_kf) {
+        gst_adapter_flush (avi->adapter, 8);
+        /* get buffer */
+        if (size) {
+          buf = gst_adapter_take_buffer (avi->adapter, GST_ROUND_UP_2 (size));
+          /* patch the size */
+          gst_buffer_resize (buf, 0, size);
+        } else {
+          buf = NULL;
+        }
+      } else {
+        GST_DEBUG_OBJECT (avi,
+            "Desired keyframe not yet reached, flushing chunk");
+        gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
+      }
+
+#if 0
+      offset = avi->offset;
+#endif
+      avi->offset += 8 + GST_ROUND_UP_2 (size);
+
+      stream = &avi->stream[stream_nr];
+
+      /* set delay (if any)
+         if (stream->strh->init_frames == stream->current_frame &&
+         stream->delay == 0)
+         stream->delay = next_ts;
+       */
+
+      /* parsing of corresponding header may have failed */
+      if (G_UNLIKELY (!stream->pad)) {
+        GST_WARNING_OBJECT (avi, "no pad for stream ID %" GST_FOURCC_FORMAT,
+            GST_FOURCC_ARGS (tag));
+        if (buf)
+          gst_buffer_unref (buf);
+      } else {
+        /* get time of this buffer */
+        gst_pad_query_position (stream->pad, GST_FORMAT_TIME,
+            (gint64 *) & next_ts);
+
+#if 0
+        gst_avi_demux_add_assoc (avi, stream, next_ts, offset, FALSE);
+#endif
+
+        /* increment our positions */
+        stream->current_entry++;
+        /* as in pull mode, 'total' is either bytes (CBR) or frames (VBR) */
+        if (stream->strh->type == GST_RIFF_FCC_auds && stream->is_vbr) {
+          gint blockalign = stream->strf.auds->blockalign;
+          if (blockalign > 0)
+            stream->current_total += DIV_ROUND_UP (size, blockalign);
+          else
+            stream->current_total++;
+        } else {
+          stream->current_total += size;
+        }
+        GST_LOG_OBJECT (avi, "current entry %u, total %u",
+            stream->current_entry, stream->current_total);
+
+        /* update current position in the segment */
+        avi->segment.position = next_ts;
+
+        if (saw_desired_kf && buf) {
+          GstClockTime dur_ts = 0;
+
+          /* invert the picture if needed, and append palette for RGB8P */
+          buf = gst_avi_demux_invert (stream, buf);
+
+          gst_pad_query_position (stream->pad, GST_FORMAT_TIME,
+              (gint64 *) & dur_ts);
+
+          GST_BUFFER_DTS (buf) = next_ts;
+          GST_BUFFER_PTS (buf) = GST_CLOCK_TIME_NONE;
+          GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
+          if (stream->strh->type == GST_RIFF_FCC_vids) {
+            GST_BUFFER_OFFSET (buf) = stream->current_entry - 1;
+            GST_BUFFER_OFFSET_END (buf) = stream->current_entry;
+          } else {
+            GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
+            GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
+          }
+
+          GST_DEBUG_OBJECT (avi,
+              "Pushing buffer with time=%" GST_TIME_FORMAT ", duration %"
+              GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
+              " and size %d over pad %s", GST_TIME_ARGS (next_ts),
+              GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
+              GST_BUFFER_OFFSET (buf), size, GST_PAD_NAME (stream->pad));
+
+          /* mark discont when pending */
+          if (G_UNLIKELY (stream->discont)) {
+            GST_DEBUG_OBJECT (avi, "Setting DISCONT");
+            GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+            stream->discont = FALSE;
+          } else {
+            GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
+          }
+
+          if (stream->alignment > 1)
+            buf = gst_avi_demux_align_buffer (avi, buf, stream->alignment);
+          res = gst_pad_push (stream->pad, buf);
+          buf = NULL;
+
+          /* combine flows */
+          res = gst_avi_demux_combine_flows (avi, stream, res);
+          if (G_UNLIKELY (res != GST_FLOW_OK)) {
+            GST_DEBUG ("Push failed; %s", gst_flow_get_name (res));
+            return res;
+          }
+        }
+      }
+    }
+  }
+
+  return res;
+}
+
+/*
+ * Send pending tags.
+ */
+static void
+push_tag_lists (GstAviDemux * avi)
+{
+  guint i;
+  GstTagList *tags;
+
+  if (!avi->got_tags)
+    return;
+
+  GST_DEBUG_OBJECT (avi, "Pushing pending tag lists");
+
+  for (i = 0; i < avi->num_streams; i++) {
+    GstAviStream *stream = &avi->stream[i];
+    GstPad *pad = stream->pad;
+
+    tags = stream->taglist;
+
+    if (pad && tags) {
+      GST_DEBUG_OBJECT (pad, "Tags: %" GST_PTR_FORMAT, tags);
+
+      gst_pad_push_event (pad, gst_event_new_tag (tags));
+      stream->taglist = NULL;
+    }
+  }
+
+  if (!(tags = avi->globaltags))
+    tags = gst_tag_list_new_empty ();
+
+  gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
+      GST_TAG_CONTAINER_FORMAT, "AVI", NULL);
+
+  GST_DEBUG_OBJECT (avi, "Global tags: %" GST_PTR_FORMAT, tags);
+  gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
+  gst_avi_demux_push_event (avi, gst_event_new_tag (tags));
+  avi->globaltags = NULL;
+  avi->got_tags = FALSE;
+}
+
+static void
+gst_avi_demux_loop (GstPad * pad)
+{
+  GstFlowReturn res;
+  GstAviDemux *avi = GST_AVI_DEMUX (GST_PAD_PARENT (pad));
+
+  switch (avi->state) {
+    case GST_AVI_DEMUX_START:
+      res = gst_avi_demux_stream_init_pull (avi);
+      if (G_UNLIKELY (res != GST_FLOW_OK)) {
+        GST_WARNING ("stream_init flow: %s", gst_flow_get_name (res));
+        goto pause;
+      }
+      avi->state = GST_AVI_DEMUX_HEADER;
+      /* fall-through */
+    case GST_AVI_DEMUX_HEADER:
+      res = gst_avi_demux_stream_header_pull (avi);
+      if (G_UNLIKELY (res != GST_FLOW_OK)) {
+        GST_WARNING ("stream_header flow: %s", gst_flow_get_name (res));
+        goto pause;
+      }
+      avi->state = GST_AVI_DEMUX_MOVI;
+      break;
+    case GST_AVI_DEMUX_MOVI:
+      if (G_UNLIKELY (avi->seg_event)) {
+        gst_avi_demux_push_event (avi, avi->seg_event);
+        avi->seg_event = NULL;
+      }
+      if (G_UNLIKELY (avi->got_tags)) {
+        push_tag_lists (avi);
+      }
+      /* process each index entry in turn */
+      res = gst_avi_demux_loop_data (avi);
+
+      /* pause when error */
+      if (G_UNLIKELY (res != GST_FLOW_OK)) {
+        GST_INFO ("stream_movi flow: %s", gst_flow_get_name (res));
+        goto pause;
+      }
+      break;
+    default:
+      GST_ERROR_OBJECT (avi, "unknown state %d", avi->state);
+      res = GST_FLOW_ERROR;
+      goto pause;
+  }
+
+  return;
+
+  /* ERRORS */
+pause:{
+
+    gboolean push_eos = FALSE;
+    GST_LOG_OBJECT (avi, "pausing task, reason %s", gst_flow_get_name (res));
+    gst_pad_pause_task (avi->sinkpad);
+
+    if (res == GST_FLOW_EOS) {
+      /* handle end-of-stream/segment */
+      /* so align our position with the end of it, if there is one
+       * this ensures a subsequent will arrive at correct base/acc time */
+      if (avi->segment.rate > 0.0 &&
+          GST_CLOCK_TIME_IS_VALID (avi->segment.stop))
+        avi->segment.position = avi->segment.stop;
+      else if (avi->segment.rate < 0.0)
+        avi->segment.position = avi->segment.start;
+      if (avi->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+        gint64 stop;
+        GstEvent *event;
+        GstMessage *msg;
+
+        if ((stop = avi->segment.stop) == -1)
+          stop = avi->segment.duration;
+
+        GST_INFO_OBJECT (avi, "sending segment_done");
+
+        msg =
+            gst_message_new_segment_done (GST_OBJECT_CAST (avi),
+            GST_FORMAT_TIME, stop);
+        if (avi->segment_seqnum)
+          gst_message_set_seqnum (msg, avi->segment_seqnum);
+        gst_element_post_message (GST_ELEMENT_CAST (avi), msg);
+
+        event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
+        if (avi->segment_seqnum)
+          gst_event_set_seqnum (event, avi->segment_seqnum);
+        gst_avi_demux_push_event (avi, event);
+      } else {
+        push_eos = TRUE;
+      }
+    } else if (res == GST_FLOW_NOT_LINKED || res < GST_FLOW_EOS) {
+      /* for fatal errors we post an error message, wrong-state is
+       * not fatal because it happens due to flushes and only means
+       * that we should stop now. */
+      GST_ELEMENT_FLOW_ERROR (avi, res);
+      push_eos = TRUE;
+    }
+    if (push_eos) {
+      GstEvent *event;
+
+      GST_INFO_OBJECT (avi, "sending eos");
+      event = gst_event_new_eos ();
+      if (avi->segment_seqnum)
+        gst_event_set_seqnum (event, avi->segment_seqnum);
+      if (!gst_avi_demux_push_event (avi, event) && (res == GST_FLOW_EOS)) {
+        GST_ELEMENT_ERROR (avi, STREAM, DEMUX,
+            (NULL), ("got eos but no streams (yet)"));
+      }
+    }
+  }
+}
+
+
+static GstFlowReturn
+gst_avi_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstFlowReturn res;
+  GstAviDemux *avi = GST_AVI_DEMUX (parent);
+  gint i;
+
+  if (GST_BUFFER_IS_DISCONT (buf)) {
+    GST_DEBUG_OBJECT (avi, "got DISCONT");
+    gst_adapter_clear (avi->adapter);
+    /* mark all streams DISCONT */
+    for (i = 0; i < avi->num_streams; i++)
+      avi->stream[i].discont = TRUE;
+  }
+
+  GST_DEBUG ("Store %" G_GSIZE_FORMAT " bytes in adapter",
+      gst_buffer_get_size (buf));
+  gst_adapter_push (avi->adapter, buf);
+
+  switch (avi->state) {
+    case GST_AVI_DEMUX_START:
+      if ((res = gst_avi_demux_stream_init_push (avi)) != GST_FLOW_OK) {
+        GST_WARNING ("stream_init flow: %s", gst_flow_get_name (res));
+        break;
+      }
+      break;
+    case GST_AVI_DEMUX_HEADER:
+      if ((res = gst_avi_demux_stream_header_push (avi)) != GST_FLOW_OK) {
+        GST_WARNING ("stream_header flow: %s", gst_flow_get_name (res));
+        break;
+      }
+      break;
+    case GST_AVI_DEMUX_MOVI:
+      if (G_UNLIKELY (avi->seg_event)) {
+        gst_avi_demux_push_event (avi, avi->seg_event);
+        avi->seg_event = NULL;
+      }
+      if (G_UNLIKELY (avi->got_tags)) {
+        push_tag_lists (avi);
+      }
+      res = gst_avi_demux_stream_data (avi);
+      break;
+    case GST_AVI_DEMUX_SEEK:
+    {
+      GstEvent *event;
+
+      res = GST_FLOW_OK;
+
+      /* obtain and parse indexes */
+      if (avi->stream[0].indexes && !gst_avi_demux_read_subindexes_push (avi))
+        /* seek in subindex read function failed */
+        goto index_failed;
+
+      if (!avi->stream[0].indexes && !avi->have_index
+          && avi->avih->flags & GST_RIFF_AVIH_HASINDEX)
+        gst_avi_demux_stream_index_push (avi);
+
+      if (avi->have_index) {
+        /* use the indexes now to construct nice durations */
+        gst_avi_demux_calculate_durations_from_index (avi);
+      } else {
+        /* still parsing indexes */
+        break;
+      }
+
+      GST_OBJECT_LOCK (avi);
+      event = avi->seek_event;
+      avi->seek_event = NULL;
+      GST_OBJECT_UNLOCK (avi);
+
+      /* calculate and perform seek */
+      if (!avi_demux_handle_seek_push (avi, avi->sinkpad, event)) {
+        gst_event_unref (event);
+        goto seek_failed;
+      }
+
+      gst_event_unref (event);
+      avi->state = GST_AVI_DEMUX_MOVI;
+      break;
+    }
+    default:
+      GST_ELEMENT_ERROR (avi, STREAM, FAILED, (NULL),
+          ("Illegal internal state"));
+      res = GST_FLOW_ERROR;
+      break;
+  }
+
+  GST_DEBUG_OBJECT (avi, "state: %d res:%s", avi->state,
+      gst_flow_get_name (res));
+
+  if (G_UNLIKELY (avi->abort_buffering))
+    goto abort_buffering;
+
+  return res;
+
+  /* ERRORS */
+index_failed:
+  {
+    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("failed to read indexes"));
+    return GST_FLOW_ERROR;
+  }
+seek_failed:
+  {
+    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("push mode seek failed"));
+    return GST_FLOW_ERROR;
+  }
+abort_buffering:
+  {
+    avi->abort_buffering = FALSE;
+    GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("unhandled buffer size"));
+    return GST_FLOW_ERROR;
+  }
+}
+
+static gboolean
+gst_avi_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
+{
+  GstQuery *query;
+  gboolean pull_mode;
+
+  query = gst_query_new_scheduling ();
+
+  if (!gst_pad_peer_query (sinkpad, query)) {
+    gst_query_unref (query);
+    goto activate_push;
+  }
+
+  pull_mode = gst_query_has_scheduling_mode_with_flags (query,
+      GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
+  gst_query_unref (query);
+
+  if (!pull_mode)
+    goto activate_push;
+
+  GST_DEBUG_OBJECT (sinkpad, "activating pull");
+  return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
+
+activate_push:
+  {
+    GST_DEBUG_OBJECT (sinkpad, "activating push");
+    return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
+  }
+}
+
+static gboolean
+gst_avi_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
+    GstPadMode mode, gboolean active)
+{
+  gboolean res;
+  GstAviDemux *avi = GST_AVI_DEMUX (parent);
+
+  switch (mode) {
+    case GST_PAD_MODE_PULL:
+      if (active) {
+        avi->streaming = FALSE;
+        res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_avi_demux_loop,
+            sinkpad, NULL);
+      } else {
+        res = gst_pad_stop_task (sinkpad);
+      }
+      break;
+    case GST_PAD_MODE_PUSH:
+      if (active) {
+        GST_DEBUG ("avi: activating push/chain function");
+        avi->streaming = TRUE;
+      } else {
+        GST_DEBUG ("avi: deactivating push/chain function");
+      }
+      res = TRUE;
+      break;
+    default:
+      res = FALSE;
+      break;
+  }
+  return res;
+}
+
+#if 0
+static void
+gst_avi_demux_set_index (GstElement * element, GstIndex * index)
+{
+  GstAviDemux *avi = GST_AVI_DEMUX (element);
+
+  GST_OBJECT_LOCK (avi);
+  if (avi->element_index)
+    gst_object_unref (avi->element_index);
+  if (index) {
+    avi->element_index = gst_object_ref (index);
+  } else {
+    avi->element_index = NULL;
+  }
+  GST_OBJECT_UNLOCK (avi);
+  /* object lock might be taken again */
+  if (index)
+    gst_index_get_writer_id (index, GST_OBJECT_CAST (element), &avi->index_id);
+  GST_DEBUG_OBJECT (avi, "Set index %" GST_PTR_FORMAT, avi->element_index);
+}
+
+static GstIndex *
+gst_avi_demux_get_index (GstElement * element)
+{
+  GstIndex *result = NULL;
+  GstAviDemux *avi = GST_AVI_DEMUX (element);
+
+  GST_OBJECT_LOCK (avi);
+  if (avi->element_index)
+    result = gst_object_ref (avi->element_index);
+  GST_OBJECT_UNLOCK (avi);
+
+  GST_DEBUG_OBJECT (avi, "Returning index %" GST_PTR_FORMAT, result);
+
+  return result;
+}
+#endif
+
+static GstStateChangeReturn
+gst_avi_demux_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstAviDemux *avi = GST_AVI_DEMUX (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      avi->streaming = FALSE;
+      gst_segment_init (&avi->segment, GST_FORMAT_TIME);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    goto done;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      avi->have_index = FALSE;
+      gst_avi_demux_reset (avi);
+      break;
+    default:
+      break;
+  }
+
+done:
+  return ret;
+}
diff --git a/gst/avi/gstavidemux.h b/gst/avi/gstavidemux.h
new file mode 100644
index 0000000..22e46a2
--- /dev/null
+++ b/gst/avi/gstavidemux.h
@@ -0,0 +1,221 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2006> Nokia Corporation (contact <stefan.kost@nokia.com>)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AVI_DEMUX_H__
+#define __GST_AVI_DEMUX_H__
+
+#include <gst/gst.h>
+
+#include "avi-ids.h"
+#include "gst/riff/riff-ids.h"
+#include "gst/riff/riff-read.h"
+#include <gst/base/gstadapter.h>
+#include <gst/base/gstflowcombiner.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AVI_DEMUX \
+  (gst_avi_demux_get_type ())
+#define GST_AVI_DEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AVI_DEMUX, GstAviDemux))
+#define GST_AVI_DEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_AVI_DEMUX, GstAviDemuxClass))
+#define GST_IS_AVI_DEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AVI_DEMUX))
+#define GST_IS_AVI_DEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AVI_DEMUX))
+
+#define GST_AVI_DEMUX_MAX_STREAMS       16
+
+#define CHUNKID_TO_STREAMNR(chunkid) \
+  ((((chunkid) & 0xff) - '0') * 10 + \
+   (((chunkid) >> 8) & 0xff) - '0')
+
+
+/* new index entries 24 bytes */
+typedef struct {
+  guint32        flags;
+  guint32        size;    /* bytes of the data */
+  guint64        offset;  /* data offset in file */
+  guint64        total;   /* total bytes before */
+} GstAviIndexEntry;
+
+typedef struct {
+  /* index of this streamcontext */
+  guint          num;
+
+  /* pad*/
+  GstPad        *pad;
+  gboolean       exposed;
+
+  /* stream info and headers */
+  gst_riff_strh *strh;
+  union {
+    gst_riff_strf_vids *vids;
+    gst_riff_strf_auds *auds;
+    gst_riff_strf_iavs *iavs;
+    gpointer     data;
+  } strf;
+  GstBuffer     *extradata, *initdata;
+  GstBuffer     *rgb8_palette;
+  gchar         *name;
+
+  /* the start/step/stop entries */
+  guint          start_entry;
+  guint          step_entry;
+  guint          stop_entry;
+
+  /* current index entry */
+  guint          current_entry;
+  /* position (byte, frame, time) for current_entry */
+  guint          current_total;
+  GstClockTime   current_timestamp;
+  GstClockTime   current_ts_end;
+  guint64        current_offset;
+  guint64        current_offset_end;
+
+  gboolean       discont;
+
+  /* stream length */
+  guint64        total_bytes;
+  guint32        total_blocks;
+  guint          n_keyframes;
+  /* stream length according to index */
+  GstClockTime   idx_duration;
+  /* stream length according to header */
+  GstClockTime   hdr_duration;
+  /* stream length based on header/index */
+  GstClockTime   duration;
+
+  /* VBR indicator */
+  gboolean       is_vbr;
+
+  /* openDML support (for files >4GB) */
+  gboolean       superindex;
+  guint64       *indexes;
+
+  /* new indexes */
+  GstAviIndexEntry *index;     /* array with index entries */
+  guint             idx_n;     /* number of entries */
+  guint             idx_max;   /* max allocated size of entries */
+
+  GstTagList	*taglist;
+
+  gint           index_id;
+  gboolean is_raw;
+  gsize alignment;
+} GstAviStream;
+
+typedef enum {
+  GST_AVI_DEMUX_START,
+  GST_AVI_DEMUX_HEADER,
+  GST_AVI_DEMUX_MOVI,
+  GST_AVI_DEMUX_SEEK,
+} GstAviDemuxState;
+
+typedef enum {
+  GST_AVI_DEMUX_HEADER_TAG_LIST,
+  GST_AVI_DEMUX_HEADER_AVIH,
+  GST_AVI_DEMUX_HEADER_ELEMENTS,
+  GST_AVI_DEMUX_HEADER_INFO,
+  GST_AVI_DEMUX_HEADER_JUNK,
+  GST_AVI_DEMUX_HEADER_DATA
+} GstAviDemuxHeaderState;
+
+typedef struct _GstAviDemux {
+  GstElement     parent;
+
+  /* pads */
+  GstPad        *sinkpad;
+
+  /* AVI decoding state */
+  GstAviDemuxState state;
+  GstAviDemuxHeaderState header_state;
+  guint64        offset;
+  gboolean       abort_buffering;
+
+  /* when we loaded the indexes */
+  gboolean       have_index;
+  /* index offset in the file */
+  guint64        index_offset;
+
+  /* streams */
+  GstAviStream   stream[GST_AVI_DEMUX_MAX_STREAMS];
+  guint          num_streams;
+  guint          num_v_streams;
+  guint          num_a_streams;
+  guint          num_t_streams;   /* subtitle text streams */
+  guint          num_sp_streams;  /* subpicture streams */
+
+  guint          main_stream; /* used for seeking */
+
+  GstFlowCombiner *flowcombiner;
+
+  gboolean       have_group_id;
+  guint          group_id;
+
+  /* for streaming mode */
+  gboolean       streaming;
+  gboolean       have_eos;
+  GstAdapter    *adapter;
+  guint          todrop;
+
+  /* some stream info for length */
+  gst_riff_avih *avih;
+  GstClockTime   duration;
+
+  /* segment in TIME */
+  GstSegment     segment;
+  guint32        segment_seqnum;
+
+  /* pending tags/events */
+  GstEvent      *seg_event;
+  GstTagList	*globaltags;
+  gboolean	 got_tags;
+
+#if 0
+  /* gst index support */
+  GstIndex      *element_index;
+  gint           index_id;
+#endif
+
+  gboolean       seekable;
+
+  guint64        first_movi_offset;
+  guint64        idx1_offset; /* offset in file of list/chunk after movi */
+  GstEvent      *seek_event;
+
+  gboolean       building_index;
+  guint          odml_stream;
+  guint          odml_subidx;
+  guint64       *odml_subidxs;
+
+  guint64        seek_kf_offset; /* offset of the keyframe to which we want to seek */
+} GstAviDemux;
+
+typedef struct _GstAviDemuxClass {
+  GstElementClass parent_class;
+} GstAviDemuxClass;
+
+GType           gst_avi_demux_get_type          (void);
+
+G_END_DECLS
+
+#endif /* __GST_AVI_DEMUX_H__ */
diff --git a/gst/avi/gstavimux.c b/gst/avi/gstavimux.c
new file mode 100644
index 0000000..593ed44
--- /dev/null
+++ b/gst/avi/gstavimux.c
@@ -0,0 +1,2303 @@
+/* AVI muxer plugin for GStreamer
+ * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *           (C) 2006 Mark Nauwelaerts <manauw@skynet.be>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* based on:
+ * - the old avimuxer (by Wim Taymans)
+ * - xawtv's aviwriter (by Gerd Knorr)
+ * - mjpegtools' avilib (by Rainer Johanni)
+ * - openDML large-AVI docs
+ */
+
+/**
+ * SECTION:element-avimux
+ *
+ * Muxes raw or compressed audio and/or video streams into an AVI file.
+ *
+ * <refsect2>
+ * <title>Example launch lines</title>
+ * <para>(write everything in one line, without the backslash characters)</para>
+ * |[
+ * gst-launch-1.0 videotestsrc num-buffers=250 \
+ * ! 'video/x-raw,format=(string)I420,width=320,height=240,framerate=(fraction)25/1' \
+ * ! queue ! mux. \
+ * audiotestsrc num-buffers=440 ! audioconvert \
+ * ! 'audio/x-raw,rate=44100,channels=2' ! queue ! mux. \
+ * avimux name=mux ! filesink location=test.avi
+ * ]| This will create an .AVI file containing an uncompressed video stream
+ * with a test picture and an uncompressed audio stream containing a
+ * test sound.
+ * |[
+ * gst-launch-1.0 videotestsrc num-buffers=250 \
+ * ! 'video/x-raw,format=(string)I420,width=320,height=240,framerate=(fraction)25/1' \
+ * ! xvidenc ! queue ! mux. \
+ * audiotestsrc num-buffers=440 ! audioconvert ! 'audio/x-raw,rate=44100,channels=2' \
+ * ! lame ! queue ! mux. \
+ * avimux name=mux ! filesink location=test.avi
+ * ]| This will create an .AVI file containing the same test video and sound
+ * as above, only that both streams will be compressed this time. This will
+ * only work if you have the necessary encoder elements installed of course.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gst/gst-i18n-plugin.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gst/video/video.h>
+#include <gst/audio/audio.h>
+#include <gst/base/gstbytewriter.h>
+
+#include "gstavimux.h"
+
+GST_DEBUG_CATEGORY_STATIC (avimux_debug);
+#define GST_CAT_DEFAULT avimux_debug
+
+enum
+{
+  PROP_0,
+  PROP_BIGFILE
+};
+
+#define DEFAULT_BIGFILE TRUE
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-msvideo")
+    );
+
+static GstStaticPadTemplate video_sink_factory =
+    GST_STATIC_PAD_TEMPLATE ("video_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("video/x-raw, "
+        "format = (string) { YUY2, I420, BGR, BGRx, BGRA, GRAY8, UYVY }, "
+        "width = (int) [ 16, 4096 ], "
+        "height = (int) [ 16, 4096 ], "
+        "framerate = (fraction) [ 0, MAX ]; "
+        "image/jpeg, "
+        "width = (int) [ 16, 4096 ], "
+        "height = (int) [ 16, 4096 ], "
+        "framerate = (fraction) [ 0, MAX ]; "
+        "video/x-divx, "
+        "width = (int) [ 16, 4096 ], "
+        "height = (int) [ 16, 4096 ], "
+        "framerate = (fraction) [ 0, MAX ], "
+        "divxversion = (int) [ 3, 5 ]; "
+        "video/x-msmpeg, "
+        "width = (int) [ 16, 4096 ], "
+        "height = (int) [ 16, 4096 ], "
+        "framerate = (fraction) [ 0, MAX ], "
+        "msmpegversion = (int) [ 41, 43 ]; "
+        "video/mpeg, "
+        "width = (int) [ 16, 4096 ], "
+        "height = (int) [ 16, 4096 ], "
+        "framerate = (fraction) [ 0, MAX ], "
+        "mpegversion = (int) { 1, 2, 4}, "
+        "systemstream = (boolean) FALSE; "
+        "video/x-h263, "
+        "width = (int) [ 16, 4096 ], "
+        "height = (int) [ 16, 4096 ], "
+        "framerate = (fraction) [ 0, MAX ]; "
+        "video/x-h264, "
+        "stream-format = (string) byte-stream, "
+        "alignment = (string) au, "
+        "width = (int) [ 16, 4096 ], "
+        "height = (int) [ 16, 4096 ], "
+        "framerate = (fraction) [ 0, MAX ]; "
+        "video/x-dv, "
+        "width = (int) 720, "
+        "height = (int) { 576, 480 }, "
+        "framerate = (fraction) [ 0, MAX ], "
+        "systemstream = (boolean) FALSE; "
+        "video/x-huffyuv, "
+        "width = (int) [ 16, 4096 ], "
+        "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0, MAX ];"
+        "video/x-wmv, "
+        "width = (int) [ 16, 4096 ], "
+        "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0, MAX ], "
+        "wmvversion = (int) [ 1, 3];"
+        "image/x-jpc, "
+        "width = (int) [ 1, 2147483647 ], "
+        "height = (int) [ 1, 2147483647 ], "
+        "framerate = (fraction) [ 0, MAX ];"
+        "video/x-vp8, "
+        "width = (int) [ 1, 2147483647 ], "
+        "height = (int) [ 1, 2147483647 ], "
+        "framerate = (fraction) [ 0, MAX ];"
+        "image/png, "
+        "width = (int) [ 16, 4096 ], "
+        "height = (int) [ 16, 4096 ], framerate = (fraction) [ 0, MAX ]")
+    );
+
+static GstStaticPadTemplate audio_sink_factory =
+    GST_STATIC_PAD_TEMPLATE ("audio_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) { U8, S16LE }, "
+        "rate = (int) [ 1000, 96000 ], "
+        "channels = (int) [ 1, 2 ]; "
+        "audio/mpeg, "
+        "mpegversion = (int) 1, "
+        "layer = (int) [ 1, 3 ], "
+        "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]; "
+        "audio/mpeg, "
+        "mpegversion = (int) 4, "
+        "stream-format = (string) raw, "
+        "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]; "
+/*#if 0 VC6 doesn't support #if here ...
+        "audio/x-vorbis, "
+        "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]; "
+#endif*/
+        "audio/x-ac3, "
+        "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 6 ]; "
+        "audio/x-alaw, "
+        "rate = (int) [ 1000, 48000 ], " "channels = (int) [ 1, 2 ]; "
+        "audio/x-mulaw, "
+        "rate = (int) [ 1000, 48000 ], " "channels = (int) [ 1, 2 ]; "
+        "audio/x-wma, "
+        "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ], "
+        "wmaversion = (int) [ 1, 2 ] ")
+    );
+
+static void gst_avi_mux_pad_reset (GstAviPad * avipad, gboolean free);
+
+static GstFlowReturn gst_avi_mux_collect_pads (GstCollectPads * pads,
+    GstAviMux * avimux);
+static gboolean gst_avi_mux_handle_event (GstCollectPads * pad,
+    GstCollectData * data, GstEvent * event, gpointer user_data);
+static GstPad *gst_avi_mux_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
+static void gst_avi_mux_release_pad (GstElement * element, GstPad * pad);
+static void gst_avi_mux_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_avi_mux_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+static GstStateChangeReturn gst_avi_mux_change_state (GstElement * element,
+    GstStateChange transition);
+
+#define gst_avi_mux_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstAviMux, gst_avi_mux, GST_TYPE_ELEMENT,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
+
+static void
+gst_avi_mux_finalize (GObject * object)
+{
+  GstAviMux *mux = GST_AVI_MUX (object);
+  GSList *node;
+
+  /* completely free each sinkpad */
+  node = mux->sinkpads;
+  while (node) {
+    GstAviPad *avipad = (GstAviPad *) node->data;
+
+    node = node->next;
+
+    gst_avi_mux_pad_reset (avipad, TRUE);
+    g_free (avipad);
+  }
+  g_slist_free (mux->sinkpads);
+  mux->sinkpads = NULL;
+
+  g_free (mux->idx);
+  mux->idx = NULL;
+
+  gst_object_unref (mux->collect);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_avi_mux_class_init (GstAviMuxClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (avimux_debug, "avimux", 0, "Muxer for AVI streams");
+
+  gobject_class->get_property = gst_avi_mux_get_property;
+  gobject_class->set_property = gst_avi_mux_set_property;
+  gobject_class->finalize = gst_avi_mux_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_BIGFILE,
+      g_param_spec_boolean ("bigfile", "Bigfile Support (>2GB)",
+          "Support for openDML-2.0 (big) AVI files", DEFAULT_BIGFILE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->request_new_pad =
+      GST_DEBUG_FUNCPTR (gst_avi_mux_request_new_pad);
+  gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_avi_mux_release_pad);
+  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_avi_mux_change_state);
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &audio_sink_factory);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &video_sink_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class, "Avi muxer",
+      "Codec/Muxer",
+      "Muxes audio and video into an avi stream",
+      "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
+}
+
+/* reset pad to initial state
+ * free - if true, release all, not only stream related, data */
+static void
+gst_avi_mux_pad_reset (GstAviPad * avipad, gboolean free)
+{
+  /* generic part */
+  memset (&(avipad->hdr), 0, sizeof (gst_riff_strh));
+
+  memset (&(avipad->idx[0]), 0, sizeof (avipad->idx));
+
+  if (free) {
+    g_free (avipad->tag);
+    avipad->tag = NULL;
+    g_free (avipad->idx_tag);
+    avipad->idx_tag = NULL;
+  }
+
+  if (avipad->is_video) {
+    GstAviVideoPad *vidpad = (GstAviVideoPad *) avipad;
+
+    avipad->hdr.type = GST_MAKE_FOURCC ('v', 'i', 'd', 's');
+    if (vidpad->vids_codec_data) {
+      gst_buffer_unref (vidpad->vids_codec_data);
+      vidpad->vids_codec_data = NULL;
+    }
+
+    if (vidpad->prepend_buffer) {
+      gst_buffer_unref (vidpad->prepend_buffer);
+      vidpad->prepend_buffer = NULL;
+    }
+
+    memset (&(vidpad->vids), 0, sizeof (gst_riff_strf_vids));
+    memset (&(vidpad->vprp), 0, sizeof (gst_riff_vprp));
+  } else {
+    GstAviAudioPad *audpad = (GstAviAudioPad *) avipad;
+
+    audpad->samples = 0;
+
+    avipad->hdr.type = GST_MAKE_FOURCC ('a', 'u', 'd', 's');
+    if (audpad->auds_codec_data) {
+      gst_buffer_unref (audpad->auds_codec_data);
+      audpad->auds_codec_data = NULL;
+    }
+
+    memset (&(audpad->auds), 0, sizeof (gst_riff_strf_auds));
+
+    audpad->audio_size = 0;
+    audpad->audio_time = 0;
+    audpad->max_audio_chunk = 0;
+  }
+}
+
+static void
+gst_avi_mux_reset (GstAviMux * avimux)
+{
+  GSList *node, *newlist = NULL;
+
+  /* free and reset each sinkpad */
+  node = avimux->sinkpads;
+  while (node) {
+    GstAviPad *avipad = (GstAviPad *) node->data;
+
+    node = node->next;
+
+    gst_avi_mux_pad_reset (avipad, FALSE);
+    /* if this pad has collectdata, keep it, otherwise dump it completely */
+    if (avipad->collect)
+      newlist = g_slist_append (newlist, avipad);
+    else {
+      gst_avi_mux_pad_reset (avipad, TRUE);
+      g_free (avipad);
+    }
+  }
+
+  /* free the old list of sinkpads, only keep the real collecting ones */
+  g_slist_free (avimux->sinkpads);
+  avimux->sinkpads = newlist;
+
+  /* avi data */
+  avimux->num_frames = 0;
+  memset (&(avimux->avi_hdr), 0, sizeof (gst_riff_avih));
+  avimux->avi_hdr.max_bps = 10000000;
+  avimux->codec_data_size = 0;
+
+  if (avimux->tags_snap) {
+    gst_tag_list_unref (avimux->tags_snap);
+    avimux->tags_snap = NULL;
+  }
+
+  g_free (avimux->idx);
+  avimux->idx = NULL;
+
+  /* state info */
+  avimux->write_header = TRUE;
+
+  /* tags */
+  gst_tag_setter_reset_tags (GST_TAG_SETTER (avimux));
+}
+
+static void
+gst_avi_mux_init (GstAviMux * avimux)
+{
+  avimux->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
+  gst_pad_use_fixed_caps (avimux->srcpad);
+  gst_element_add_pad (GST_ELEMENT (avimux), avimux->srcpad);
+
+  /* property */
+  avimux->enable_large_avi = DEFAULT_BIGFILE;
+
+  avimux->collect = gst_collect_pads_new ();
+  gst_collect_pads_set_function (avimux->collect,
+      (GstCollectPadsFunction) (GST_DEBUG_FUNCPTR (gst_avi_mux_collect_pads)),
+      avimux);
+  gst_collect_pads_set_event_function (avimux->collect,
+      (GstCollectPadsEventFunction) (GST_DEBUG_FUNCPTR
+          (gst_avi_mux_handle_event)), avimux);
+
+  /* set to clean state */
+  gst_avi_mux_reset (avimux);
+}
+
+static gboolean
+gst_avi_mux_vidsink_set_caps (GstPad * pad, GstCaps * vscaps)
+{
+  GstAviMux *avimux;
+  GstAviVideoPad *avipad;
+  GstAviCollectData *collect_pad;
+  GstStructure *structure;
+  const gchar *mimetype;
+  const GValue *fps, *par;
+  const GValue *codec_data;
+  gint width, height;
+  gint par_n, par_d;
+  gboolean codec_data_in_headers = TRUE;
+  gboolean valid_caps = TRUE;
+
+  avimux = GST_AVI_MUX (gst_pad_get_parent (pad));
+
+  /* find stream data */
+  collect_pad = (GstAviCollectData *) gst_pad_get_element_private (pad);
+  g_assert (collect_pad);
+  avipad = (GstAviVideoPad *) collect_pad->avipad;
+  g_assert (avipad);
+  g_assert (avipad->parent.is_video);
+  g_assert (avipad->parent.hdr.type == GST_MAKE_FOURCC ('v', 'i', 'd', 's'));
+
+  GST_DEBUG_OBJECT (avimux, "%s:%s, caps=%" GST_PTR_FORMAT,
+      GST_DEBUG_PAD_NAME (pad), vscaps);
+
+  structure = gst_caps_get_structure (vscaps, 0);
+  mimetype = gst_structure_get_name (structure);
+
+  /* global */
+  avipad->vids.size = sizeof (gst_riff_strf_vids);
+  avipad->vids.planes = 1;
+  if (!gst_structure_get_int (structure, "width", &width) ||
+      !gst_structure_get_int (structure, "height", &height)) {
+    goto refuse_caps;
+  }
+
+  avipad->vids.width = width;
+  avipad->vids.height = height;
+
+  fps = gst_structure_get_value (structure, "framerate");
+  if (fps == NULL || !GST_VALUE_HOLDS_FRACTION (fps))
+    goto refuse_caps;
+
+  avipad->parent.hdr.rate = gst_value_get_fraction_numerator (fps);
+  avipad->parent.hdr.scale = gst_value_get_fraction_denominator (fps);
+  if (avipad->parent.hdr.rate <= 0 || avipad->parent.hdr.scale <= 0)
+    goto refuse_caps;
+
+  /* (pixel) aspect ratio data, if any */
+  par = gst_structure_get_value (structure, "pixel-aspect-ratio");
+  /* only use video properties header if there is non-trivial aspect info */
+  if (par && GST_VALUE_HOLDS_FRACTION (par) &&
+      ((par_n = gst_value_get_fraction_numerator (par)) !=
+          (par_d = gst_value_get_fraction_denominator (par)))) {
+    GValue to_ratio = { 0, };
+    guint ratio_n, ratio_d;
+
+    /* some fraction voodoo to obtain simplest possible ratio */
+    g_value_init (&to_ratio, GST_TYPE_FRACTION);
+    gst_value_set_fraction (&to_ratio, width * par_n, height * par_d);
+    ratio_n = gst_value_get_fraction_numerator (&to_ratio);
+    ratio_d = gst_value_get_fraction_denominator (&to_ratio);
+    GST_DEBUG_OBJECT (avimux, "generating vprp data with aspect ratio %d/%d",
+        ratio_n, ratio_d);
+    /* simply fill in */
+    avipad->vprp.vert_rate = avipad->parent.hdr.rate / avipad->parent.hdr.scale;
+    avipad->vprp.hor_t_total = width;
+    avipad->vprp.vert_lines = height;
+    avipad->vprp.aspect = (ratio_n) << 16 | (ratio_d & 0xffff);
+    avipad->vprp.width = width;
+    avipad->vprp.height = height;
+    avipad->vprp.fields = 1;
+    avipad->vprp.field_info[0].compressed_bm_height = height;
+    avipad->vprp.field_info[0].compressed_bm_width = width;
+    avipad->vprp.field_info[0].valid_bm_height = height;
+    avipad->vprp.field_info[0].valid_bm_width = width;
+  }
+
+  if (!strcmp (mimetype, "video/x-raw")) {
+    const gchar *format;
+    GstVideoFormat fmt;
+
+    format = gst_structure_get_string (structure, "format");
+    fmt = gst_video_format_from_string (format);
+
+    switch (fmt) {
+      case GST_VIDEO_FORMAT_YUY2:
+        avipad->vids.compression = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
+        avipad->vids.bit_cnt = 16;
+        break;
+      case GST_VIDEO_FORMAT_UYVY:
+        avipad->vids.compression = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
+        avipad->vids.bit_cnt = 16;
+        break;
+      case GST_VIDEO_FORMAT_I420:
+        avipad->vids.compression = GST_MAKE_FOURCC ('I', '4', '2', '0');
+        avipad->vids.bit_cnt = 12;
+        break;
+      case GST_VIDEO_FORMAT_GRAY8:
+        avipad->vids.compression = GST_MAKE_FOURCC ('Y', '8', '0', '0');
+        avipad->vids.bit_cnt = 8;
+        break;
+      case GST_VIDEO_FORMAT_BGR:
+        avipad->vids.compression = GST_MAKE_FOURCC (0x00, 0x00, 0x00, 0x00);
+        avipad->vids.bit_cnt = 24;
+        break;
+      case GST_VIDEO_FORMAT_BGRx:
+      case GST_VIDEO_FORMAT_BGRA:
+        avipad->vids.compression = GST_MAKE_FOURCC (0x00, 0x00, 0x00, 0x00);
+        avipad->vids.bit_cnt = 32;
+        break;
+      default:
+        valid_caps = FALSE;
+        break;
+    }
+  } else {
+    avipad->vids.bit_cnt = 24;
+    avipad->vids.compression = 0;
+
+    /* find format */
+    if (!strcmp (mimetype, "video/x-huffyuv")) {
+      avipad->vids.compression = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
+    } else if (!strcmp (mimetype, "image/jpeg")) {
+      avipad->vids.compression = GST_MAKE_FOURCC ('M', 'J', 'P', 'G');
+    } else if (!strcmp (mimetype, "video/x-divx")) {
+      gint divxversion;
+
+      gst_structure_get_int (structure, "divxversion", &divxversion);
+      switch (divxversion) {
+        case 3:
+          avipad->vids.compression = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
+          break;
+        case 4:
+          avipad->vids.compression = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
+          break;
+        case 5:
+          avipad->vids.compression = GST_MAKE_FOURCC ('D', 'X', '5', '0');
+          break;
+        default:
+          valid_caps = FALSE;
+      }
+    } else if (gst_structure_has_name (structure, "video/x-msmpeg")) {
+      gint msmpegversion;
+
+      gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
+      switch (msmpegversion) {
+        case 41:
+          avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
+          break;
+        case 42:
+          avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', '4', '2');
+          break;
+        case 43:
+          avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', '4', '3');
+          break;
+        default:
+          GST_INFO ("unhandled msmpegversion : %d, fall back to fourcc=MPEG",
+              msmpegversion);
+          avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', 'E', 'G');
+          break;
+      }
+    } else if (!strcmp (mimetype, "video/x-dv")) {
+      avipad->vids.compression = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
+    } else if (!strcmp (mimetype, "video/x-h263")) {
+      avipad->vids.compression = GST_MAKE_FOURCC ('H', '2', '6', '3');
+    } else if (!strcmp (mimetype, "video/x-h264")) {
+      avipad->vids.compression = GST_MAKE_FOURCC ('H', '2', '6', '4');
+    } else if (!strcmp (mimetype, "video/mpeg")) {
+      gint mpegversion;
+
+      gst_structure_get_int (structure, "mpegversion", &mpegversion);
+
+      switch (mpegversion) {
+        case 2:
+          avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', 'G', '2');
+          break;
+        case 4:
+          /* mplayer/ffmpeg might not work with DIVX, but with FMP4 */
+          avipad->vids.compression = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
+
+          /* DIVX/XVID in AVI store the codec_data chunk as part of the
+             first data buffer. So for this case, we prepend the codec_data
+             blob (if any) to that first buffer */
+          codec_data_in_headers = FALSE;
+          break;
+        default:
+          GST_INFO ("unhandled mpegversion : %d, fall back to fourcc=MPEG",
+              mpegversion);
+          avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', 'E', 'G');
+          break;
+      }
+    } else if (!strcmp (mimetype, "video/x-wmv")) {
+      gint wmvversion;
+
+      if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
+        switch (wmvversion) {
+          case 1:
+            avipad->vids.compression = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
+            break;
+          case 2:
+            avipad->vids.compression = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
+            break;
+          case 3:
+            avipad->vids.compression = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
+            break;
+          default:
+            valid_caps = FALSE;
+            break;
+        }
+      }
+    } else if (!strcmp (mimetype, "image/x-jpc")) {
+      avipad->vids.compression = GST_MAKE_FOURCC ('M', 'J', '2', 'C');
+    } else if (!strcmp (mimetype, "video/x-vp8")) {
+      avipad->vids.compression = GST_MAKE_FOURCC ('V', 'P', '8', '0');
+    } else if (!strcmp (mimetype, "image/png")) {
+      avipad->vids.compression = GST_MAKE_FOURCC ('p', 'n', 'g', ' ');
+    } else {
+      valid_caps = FALSE;
+    }
+
+    if (!valid_caps)
+      goto refuse_caps;
+  }
+
+  /* codec initialization data, if any */
+  codec_data = gst_structure_get_value (structure, "codec_data");
+  if (codec_data) {
+    if (codec_data_in_headers) {
+      avipad->vids_codec_data = gst_value_get_buffer (codec_data);
+      gst_buffer_ref (avipad->vids_codec_data);
+      /* keep global track of size */
+      avimux->codec_data_size += gst_buffer_get_size (avipad->vids_codec_data);
+    } else {
+      avipad->prepend_buffer =
+          gst_buffer_ref (gst_value_get_buffer (codec_data));
+    }
+  }
+
+  avipad->parent.hdr.fcc_handler = avipad->vids.compression;
+  avipad->vids.image_size = avipad->vids.height * avipad->vids.width;
+  /* hm, maybe why avi only handles one stream well ... */
+  avimux->avi_hdr.width = avipad->vids.width;
+  avimux->avi_hdr.height = avipad->vids.height;
+  avimux->avi_hdr.us_frame = 1000000. * avipad->parent.hdr.scale /
+      avipad->parent.hdr.rate;
+
+  gst_object_unref (avimux);
+  return TRUE;
+
+refuse_caps:
+  {
+    GST_WARNING_OBJECT (avimux, "refused caps %" GST_PTR_FORMAT, vscaps);
+    gst_object_unref (avimux);
+    return FALSE;
+  }
+}
+
+static void gst_avi_mux_audsink_set_fields (GstAviMux * avimux,
+    GstAviAudioPad * avipad);
+
+static GstFlowReturn
+gst_avi_mux_audsink_scan_mpeg_audio (GstAviMux * avimux, GstAviPad * avipad,
+    GstBuffer * buffer)
+{
+  GstMapInfo map;
+  guint spf;
+  guint32 header;
+  gulong layer;
+  gulong version;
+  gint lsf, mpg25;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  if (map.size < 4)
+    goto not_parsed;
+
+  header = GST_READ_UINT32_BE (map.data);
+
+  if ((header & 0xffe00000) != 0xffe00000)
+    goto not_parsed;
+
+  /* thanks go to mp3parse */
+  if (header & (1 << 20)) {
+    lsf = (header & (1 << 19)) ? 0 : 1;
+    mpg25 = 0;
+  } else {
+    lsf = 1;
+    mpg25 = 1;
+  }
+
+  version = 1 + lsf + mpg25;
+  layer = 4 - ((header >> 17) & 0x3);
+
+  /* see http://www.codeproject.com/audio/MPEGAudioInfo.asp */
+  if (layer == 1)
+    spf = 384;
+  else if (layer == 2)
+    spf = 1152;
+  else if (version == 1) {
+    spf = 1152;
+  } else {
+    /* MPEG-2 or "2.5" */
+    spf = 576;
+  }
+
+  if (G_UNLIKELY (avipad->hdr.scale <= 1)) {
+    avipad->hdr.scale = spf;
+    gst_avi_mux_audsink_set_fields (avimux, (GstAviAudioPad *) avipad);
+  } else if (G_UNLIKELY (avipad->hdr.scale != spf)) {
+    GST_WARNING_OBJECT (avimux, "input mpeg audio has varying frame size");
+    goto cbr_fallback;
+  }
+done:
+  gst_buffer_unmap (buffer, &map);
+
+  return GST_FLOW_OK;
+
+  /* EXITS */
+not_parsed:
+  {
+    GST_WARNING_OBJECT (avimux, "input mpeg audio is not parsed");
+    /* fall-through */
+  }
+cbr_fallback:
+  {
+    GST_WARNING_OBJECT (avimux, "falling back to CBR muxing");
+    avipad->hdr.scale = 1;
+    gst_avi_mux_audsink_set_fields (avimux, (GstAviAudioPad *) avipad);
+    /* no need to check further */
+    avipad->hook = NULL;
+    goto done;
+  }
+}
+
+static void
+gst_avi_mux_audsink_set_fields (GstAviMux * avimux, GstAviAudioPad * avipad)
+{
+  if (avipad->parent.hdr.scale > 1) {
+    /* vbr case: fixed duration per frame/chunk */
+    avipad->parent.hdr.rate = avipad->auds.rate;
+    avipad->parent.hdr.samplesize = 0;
+    /* this triggers determining largest audio chunk size to write at end */
+    avipad->max_audio_chunk = avipad->auds.blockalign =
+        avipad->parent.hdr.scale;
+  } else {
+    /* by spec, hdr.rate is av_bps related, is calculated that way in stop_file,
+     * and reduces to sample rate in PCM like cases */
+    avipad->parent.hdr.rate = avipad->auds.av_bps / avipad->auds.blockalign;
+    avipad->parent.hdr.samplesize = avipad->auds.blockalign;
+    avipad->parent.hdr.scale = 1;
+  }
+}
+
+static gboolean
+gst_avi_mux_audsink_set_caps (GstPad * pad, GstCaps * vscaps)
+{
+  GstAviMux *avimux;
+  GstAviAudioPad *avipad;
+  GstAviCollectData *collect_pad;
+  GstStructure *structure;
+  const gchar *mimetype;
+  const GValue *codec_data;
+  gint channels, rate;
+
+  avimux = GST_AVI_MUX (gst_pad_get_parent (pad));
+
+  /* find stream data */
+  collect_pad = (GstAviCollectData *) gst_pad_get_element_private (pad);
+  g_assert (collect_pad);
+  avipad = (GstAviAudioPad *) collect_pad->avipad;
+  g_assert (avipad);
+  g_assert (!avipad->parent.is_video);
+  g_assert (avipad->parent.hdr.type == GST_MAKE_FOURCC ('a', 'u', 'd', 's'));
+
+  GST_DEBUG_OBJECT (avimux, "%s:%s, caps=%" GST_PTR_FORMAT,
+      GST_DEBUG_PAD_NAME (pad), vscaps);
+
+  structure = gst_caps_get_structure (vscaps, 0);
+  mimetype = gst_structure_get_name (structure);
+
+  /* we want these for all */
+  if (!gst_structure_get_int (structure, "channels", &channels) ||
+      !gst_structure_get_int (structure, "rate", &rate)) {
+    goto refuse_caps;
+  }
+
+  avipad->auds.channels = channels;
+  avipad->auds.rate = rate;
+
+  /* codec initialization data, if any */
+  codec_data = gst_structure_get_value (structure, "codec_data");
+  if (codec_data) {
+    avipad->auds_codec_data = gst_value_get_buffer (codec_data);
+    gst_buffer_ref (avipad->auds_codec_data);
+    /* keep global track of size */
+    avimux->codec_data_size += gst_buffer_get_size (avipad->auds_codec_data);
+  }
+
+  if (!strcmp (mimetype, "audio/x-raw")) {
+    const gchar *format;
+    GstAudioFormat fmt;
+
+    format = gst_structure_get_string (structure, "format");
+    fmt = gst_audio_format_from_string (format);
+
+    switch (fmt) {
+      case GST_AUDIO_FORMAT_U8:
+        avipad->auds.blockalign = 8;
+        avipad->auds.bits_per_sample = 8;
+        break;
+      case GST_AUDIO_FORMAT_S16:
+        avipad->auds.blockalign = 16;
+        avipad->auds.bits_per_sample = 16;
+        break;
+      default:
+        goto refuse_caps;
+    }
+
+    avipad->auds.format = GST_RIFF_WAVE_FORMAT_PCM;
+    /* set some more info straight */
+    avipad->auds.blockalign /= 8;
+    avipad->auds.blockalign *= avipad->auds.channels;
+    avipad->auds.av_bps = avipad->auds.blockalign * avipad->auds.rate;
+  } else {
+    avipad->auds.format = 0;
+    /* set some defaults */
+    avipad->auds.blockalign = 1;
+    avipad->auds.av_bps = 0;
+    avipad->auds.bits_per_sample = 16;
+
+    if (!strcmp (mimetype, "audio/mpeg")) {
+      gint mpegversion;
+
+      gst_structure_get_int (structure, "mpegversion", &mpegversion);
+      switch (mpegversion) {
+        case 1:{
+          gint layer = 3;
+          gboolean parsed = FALSE;
+
+          gst_structure_get_int (structure, "layer", &layer);
+          gst_structure_get_boolean (structure, "parsed", &parsed);
+          switch (layer) {
+            case 3:
+              avipad->auds.format = GST_RIFF_WAVE_FORMAT_MPEGL3;
+              break;
+            case 1:
+            case 2:
+              avipad->auds.format = GST_RIFF_WAVE_FORMAT_MPEGL12;
+              break;
+          }
+          if (parsed) {
+            /* treat as VBR, should also cover CBR case;
+             * setup hook to parse frame header and determine spf */
+            avipad->parent.hook = gst_avi_mux_audsink_scan_mpeg_audio;
+          } else {
+            GST_WARNING_OBJECT (avimux, "unparsed MPEG audio input (?), "
+                "doing CBR muxing");
+          }
+          break;
+        }
+        case 4:
+        {
+          GstBuffer *codec_data_buf = avipad->auds_codec_data;
+          const gchar *stream_format;
+          guint codec;
+          guint8 data[2];
+
+          stream_format = gst_structure_get_string (structure, "stream-format");
+          if (stream_format) {
+            if (strcmp (stream_format, "raw") != 0) {
+              GST_WARNING_OBJECT (avimux, "AAC's stream format '%s' is not "
+                  "supported, please use 'raw'", stream_format);
+              break;
+            }
+          } else {
+            GST_WARNING_OBJECT (avimux, "AAC's stream-format not specified, "
+                "assuming 'raw'");
+          }
+
+          /* vbr case needs some special handling */
+          if (!codec_data_buf || gst_buffer_get_size (codec_data_buf) < 2) {
+            GST_WARNING_OBJECT (avimux, "no (valid) codec_data for AAC audio");
+            break;
+          }
+          avipad->auds.format = GST_RIFF_WAVE_FORMAT_AAC;
+          /* need to determine frame length */
+          gst_buffer_extract (codec_data_buf, 0, data, 2);
+          codec = GST_READ_UINT16_BE (data);
+          avipad->parent.hdr.scale = (codec & 0x4) ? 960 : 1024;
+          break;
+        }
+      }
+    } else if (!strcmp (mimetype, "audio/x-vorbis")) {
+      avipad->auds.format = GST_RIFF_WAVE_FORMAT_VORBIS3;
+    } else if (!strcmp (mimetype, "audio/x-ac3")) {
+      avipad->auds.format = GST_RIFF_WAVE_FORMAT_A52;
+    } else if (!strcmp (mimetype, "audio/x-alaw")) {
+      avipad->auds.format = GST_RIFF_WAVE_FORMAT_ALAW;
+      avipad->auds.bits_per_sample = 8;
+      avipad->auds.blockalign = avipad->auds.channels;
+      avipad->auds.av_bps = avipad->auds.blockalign * avipad->auds.rate;
+    } else if (!strcmp (mimetype, "audio/x-mulaw")) {
+      avipad->auds.format = GST_RIFF_WAVE_FORMAT_MULAW;
+      avipad->auds.bits_per_sample = 8;
+      avipad->auds.blockalign = avipad->auds.channels;
+      avipad->auds.av_bps = avipad->auds.blockalign * avipad->auds.rate;
+    } else if (!strcmp (mimetype, "audio/x-wma")) {
+      gint version;
+      gint bitrate;
+      gint block_align;
+
+      if (gst_structure_get_int (structure, "wmaversion", &version)) {
+        switch (version) {
+          case 1:
+            avipad->auds.format = GST_RIFF_WAVE_FORMAT_WMAV1;
+            break;
+          case 2:
+            avipad->auds.format = GST_RIFF_WAVE_FORMAT_WMAV2;
+            break;
+          default:
+            break;
+        }
+      }
+
+      if (avipad->auds.format != 0) {
+        if (gst_structure_get_int (structure, "block_align", &block_align)) {
+          avipad->auds.blockalign = block_align;
+        }
+        if (gst_structure_get_int (structure, "bitrate", &bitrate)) {
+          avipad->auds.av_bps = bitrate / 8;
+        }
+      }
+    }
+  }
+
+  if (!avipad->auds.format)
+    goto refuse_caps;
+
+  avipad->parent.hdr.fcc_handler = avipad->auds.format;
+  gst_avi_mux_audsink_set_fields (avimux, avipad);
+
+  gst_object_unref (avimux);
+  return TRUE;
+
+refuse_caps:
+  {
+    GST_WARNING_OBJECT (avimux, "refused caps %" GST_PTR_FORMAT, vscaps);
+    gst_object_unref (avimux);
+    return FALSE;
+  }
+}
+
+
+static GstPad *
+gst_avi_mux_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
+{
+  GstAviMux *avimux;
+  GstPad *newpad;
+  GstAviPad *avipad;
+  GstElementClass *klass;
+  gchar *name = NULL;
+  const gchar *pad_name = NULL;
+  gint pad_id;
+
+  g_return_val_if_fail (templ != NULL, NULL);
+
+  if (templ->direction != GST_PAD_SINK)
+    goto wrong_direction;
+
+  g_return_val_if_fail (GST_IS_AVI_MUX (element), NULL);
+  avimux = GST_AVI_MUX (element);
+
+  if (!avimux->write_header)
+    goto too_late;
+
+  klass = GST_ELEMENT_GET_CLASS (element);
+
+  if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
+    /* don't mix named and unnamed pads, if the pad already exists we fail when
+     * trying to add it */
+    if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
+      pad_name = req_name;
+    } else {
+      name = g_strdup_printf ("audio_%u", avimux->audio_pads++);
+      pad_name = name;
+    }
+
+    /* init pad specific data */
+    avipad = g_malloc0 (sizeof (GstAviAudioPad));
+    avipad->is_video = FALSE;
+    avipad->hdr.type = GST_MAKE_FOURCC ('a', 'u', 'd', 's');
+    /* audio goes last */
+    avimux->sinkpads = g_slist_append (avimux->sinkpads, avipad);
+  } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
+    /* though streams are pretty generic and relatively self-contained,
+     * some video info goes in a single avi header -and therefore mux struct-
+     * so video restricted to one stream */
+    if (avimux->video_pads > 0)
+      goto too_many_video_pads;
+
+    /* setup pad */
+    pad_name = "video_0";
+    avimux->video_pads++;
+
+    /* init pad specific data */
+    avipad = g_malloc0 (sizeof (GstAviVideoPad));
+    avipad->is_video = TRUE;
+    avipad->hdr.type = GST_MAKE_FOURCC ('v', 'i', 'd', 's');
+    /* video goes first */
+    avimux->sinkpads = g_slist_prepend (avimux->sinkpads, avipad);
+  } else
+    goto wrong_template;
+
+  newpad = gst_pad_new_from_template (templ, pad_name);
+
+  avipad->collect = gst_collect_pads_add_pad (avimux->collect,
+      newpad, sizeof (GstAviCollectData), NULL, TRUE);
+  ((GstAviCollectData *) (avipad->collect))->avipad = avipad;
+
+  if (!gst_element_add_pad (element, newpad))
+    goto pad_add_failed;
+
+  g_free (name);
+
+  GST_DEBUG_OBJECT (newpad, "Added new request pad");
+
+  return newpad;
+
+  /* ERRORS */
+wrong_direction:
+  {
+    g_warning ("avimux: request pad that is not a SINK pad\n");
+    return NULL;
+  }
+too_late:
+  {
+    g_warning ("avimux: request pad cannot be added after streaming started\n");
+    return NULL;
+  }
+wrong_template:
+  {
+    g_warning ("avimux: this is not our template!\n");
+    return NULL;
+  }
+too_many_video_pads:
+  {
+    GST_WARNING_OBJECT (avimux, "Can only have one video stream");
+    return NULL;
+  }
+pad_add_failed:
+  {
+    GST_WARNING_OBJECT (avimux, "Adding the new pad '%s' failed", pad_name);
+    g_free (name);
+    gst_object_unref (newpad);
+    return NULL;
+  }
+}
+
+static void
+gst_avi_mux_release_pad (GstElement * element, GstPad * pad)
+{
+  GstAviMux *avimux = GST_AVI_MUX (element);
+  GSList *node;
+
+  node = avimux->sinkpads;
+  while (node) {
+    GstAviPad *avipad = (GstAviPad *) node->data;
+
+    if (avipad->collect->pad == pad) {
+      /* pad count should not be adjusted,
+       * as it also represent number of streams present */
+      avipad->collect = NULL;
+      GST_DEBUG_OBJECT (avimux, "removed pad '%s'", GST_PAD_NAME (pad));
+      gst_collect_pads_remove_pad (avimux->collect, pad);
+      gst_element_remove_pad (element, pad);
+      /* if not started yet, we can remove any sign this pad ever existed */
+      /* in this case _start will take care of the real pad count */
+      if (avimux->write_header) {
+        avimux->sinkpads = g_slist_remove (avimux->sinkpads, avipad);
+        gst_avi_mux_pad_reset (avipad, TRUE);
+        g_free (avipad);
+      }
+      return;
+    }
+
+    node = node->next;
+  }
+
+  g_warning ("Unknown pad %s", GST_PAD_NAME (pad));
+}
+
+static inline guint
+gst_avi_mux_start_chunk (GstByteWriter * bw, const gchar * tag, guint32 fourcc)
+{
+  guint chunk_offset;
+
+  if (tag)
+    gst_byte_writer_put_data (bw, (const guint8 *) tag, 4);
+  else
+    gst_byte_writer_put_uint32_le (bw, fourcc);
+
+  chunk_offset = gst_byte_writer_get_pos (bw);
+  /* real chunk size comes later */
+  gst_byte_writer_put_uint32_le (bw, 0);
+
+  return chunk_offset;
+}
+
+static inline void
+gst_avi_mux_end_chunk (GstByteWriter * bw, guint chunk_offset)
+{
+  guint size;
+
+  size = gst_byte_writer_get_pos (bw);
+
+  gst_byte_writer_set_pos (bw, chunk_offset);
+  gst_byte_writer_put_uint32_le (bw, size - chunk_offset - 4);
+  gst_byte_writer_set_pos (bw, size);
+
+  /* arrange for even padding */
+  if (size & 1)
+    gst_byte_writer_put_uint8 (bw, 0);
+}
+
+/* maybe some of these functions should be moved to riff.h? */
+
+static void
+gst_avi_mux_write_tag (const GstTagList * list, const gchar * tag,
+    gpointer data)
+{
+  const struct
+  {
+    guint32 fcc;
+    const gchar *tag;
+  } rifftags[] = {
+    {
+    GST_RIFF_INFO_IARL, GST_TAG_LOCATION}, {
+    GST_RIFF_INFO_IART, GST_TAG_ARTIST}, {
+    GST_RIFF_INFO_ICMT, GST_TAG_COMMENT}, {
+    GST_RIFF_INFO_ICOP, GST_TAG_COPYRIGHT}, {
+    GST_RIFF_INFO_ICRD, GST_TAG_DATE}, {
+    GST_RIFF_INFO_IGNR, GST_TAG_GENRE}, {
+    GST_RIFF_INFO_IKEY, GST_TAG_KEYWORDS}, {
+    GST_RIFF_INFO_INAM, GST_TAG_TITLE}, {
+    GST_RIFF_INFO_ISFT, GST_TAG_ENCODER}, {
+    GST_RIFF_INFO_ISRC, GST_TAG_ISRC}, {
+    0, NULL}
+  };
+  gint n;
+  gchar *str = NULL;
+  GstByteWriter *bw = data;
+  guint chunk;
+
+  for (n = 0; rifftags[n].fcc != 0; n++) {
+    if (!strcmp (rifftags[n].tag, tag)) {
+      if (rifftags[n].fcc == GST_RIFF_INFO_ICRD) {
+        GDate *date;
+        /* special case for the date tag */
+        if (gst_tag_list_get_date (list, tag, &date)) {
+          str =
+              g_strdup_printf ("%04d:%02d:%02d", g_date_get_year (date),
+              g_date_get_month (date), g_date_get_day (date));
+          g_date_free (date);
+        }
+      } else {
+        gst_tag_list_get_string (list, tag, &str);
+      }
+      if (str) {
+        chunk = gst_avi_mux_start_chunk (bw, NULL, rifftags[n].fcc);
+        gst_byte_writer_put_string (bw, str);
+        gst_avi_mux_end_chunk (bw, chunk);
+        g_free (str);
+        str = NULL;
+        break;
+      }
+    }
+  }
+}
+
+static GstBuffer *
+gst_avi_mux_riff_get_avi_header (GstAviMux * avimux)
+{
+  const GstTagList *tags;
+  GstBuffer *buffer = NULL;
+  gint size = 0;
+  GstByteWriter bw;
+  GSList *node;
+  guint avih, riff, hdrl;
+  GstMapInfo map;
+  gboolean hdl = TRUE;
+
+  GST_DEBUG_OBJECT (avimux, "creating avi header, data_size %u, idx_size %u",
+      avimux->data_size, avimux->idx_size);
+
+  if (avimux->tags_snap)
+    tags = avimux->tags_snap;
+  else {
+    /* need to make snapshot of current state of tags to ensure the same set
+     * is used next time around during header rewrite at the end */
+    tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (avimux));
+    if (tags)
+      tags = avimux->tags_snap = gst_tag_list_copy (tags);
+  }
+
+  gst_byte_writer_init_with_size (&bw, 1024, FALSE);
+
+  /* avi header metadata */
+  riff = gst_avi_mux_start_chunk (&bw, "RIFF", 0);
+  hdl &= gst_byte_writer_put_data (&bw, (guint8 *) "AVI ", 4);
+  hdrl = gst_avi_mux_start_chunk (&bw, "LIST", 0);
+  hdl &= gst_byte_writer_put_data (&bw, (guint8 *) "hdrl", 4);
+
+  avih = gst_avi_mux_start_chunk (&bw, "avih", 0);
+  /* the AVI header itself */
+  hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.us_frame);
+  hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.max_bps);
+  hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.pad_gran);
+  hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.flags);
+  hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.tot_frames);
+  hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.init_frames);
+  hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.streams);
+  hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.bufsize);
+  hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.width);
+  hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.height);
+  hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.scale);
+  hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.rate);
+  hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.start);
+  hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->avi_hdr.length);
+  gst_avi_mux_end_chunk (&bw, avih);
+
+  /* stream data */
+  node = avimux->sinkpads;
+  while (node) {
+    GstAviPad *avipad = (GstAviPad *) node->data;
+    GstAviVideoPad *vidpad = (GstAviVideoPad *) avipad;
+    GstAviAudioPad *audpad = (GstAviAudioPad *) avipad;
+    gint codec_size = 0;
+    guint strh, strl, strf, indx;
+
+    /* stream list metadata */
+    strl = gst_avi_mux_start_chunk (&bw, "LIST", 0);
+    hdl &= gst_byte_writer_put_data (&bw, (guint8 *) "strl", 4);
+
+    /* generic header */
+    strh = gst_avi_mux_start_chunk (&bw, "strh", 0);
+    hdl &= gst_byte_writer_put_uint32_le (&bw, avipad->hdr.type);
+    hdl &= gst_byte_writer_put_uint32_le (&bw, avipad->hdr.fcc_handler);
+    hdl &= gst_byte_writer_put_uint32_le (&bw, avipad->hdr.flags);
+    hdl &= gst_byte_writer_put_uint32_le (&bw, avipad->hdr.priority);
+    hdl &= gst_byte_writer_put_uint32_le (&bw, avipad->hdr.init_frames);
+    hdl &= gst_byte_writer_put_uint32_le (&bw, avipad->hdr.scale);
+    hdl &= gst_byte_writer_put_uint32_le (&bw, avipad->hdr.rate);
+    hdl &= gst_byte_writer_put_uint32_le (&bw, avipad->hdr.start);
+    hdl &= gst_byte_writer_put_uint32_le (&bw, avipad->hdr.length);
+    hdl &= gst_byte_writer_put_uint32_le (&bw, avipad->hdr.bufsize);
+    hdl &= gst_byte_writer_put_uint32_le (&bw, avipad->hdr.quality);
+    hdl &= gst_byte_writer_put_uint32_le (&bw, avipad->hdr.samplesize);
+    hdl &= gst_byte_writer_put_uint16_le (&bw, 0);
+    hdl &= gst_byte_writer_put_uint16_le (&bw, 0);
+    hdl &= gst_byte_writer_put_uint16_le (&bw, 0);
+    hdl &= gst_byte_writer_put_uint16_le (&bw, 0);
+    gst_avi_mux_end_chunk (&bw, strh);
+
+    if (avipad->is_video) {
+      codec_size = vidpad->vids_codec_data ?
+          gst_buffer_get_size (vidpad->vids_codec_data) : 0;
+      /* the video header */
+      strf = gst_avi_mux_start_chunk (&bw, "strf", 0);
+      /* the actual header */
+      hdl &=
+          gst_byte_writer_put_uint32_le (&bw, vidpad->vids.size + codec_size);
+      hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vids.width);
+      hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vids.height);
+      hdl &= gst_byte_writer_put_uint16_le (&bw, vidpad->vids.planes);
+      hdl &= gst_byte_writer_put_uint16_le (&bw, vidpad->vids.bit_cnt);
+      hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vids.compression);
+      hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vids.image_size);
+      hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vids.xpels_meter);
+      hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vids.ypels_meter);
+      hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vids.num_colors);
+      hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vids.imp_colors);
+      if (vidpad->vids_codec_data) {
+        gst_buffer_map (vidpad->vids_codec_data, &map, GST_MAP_READ);
+        hdl &= gst_byte_writer_put_data (&bw, map.data, map.size);
+        gst_buffer_unmap (vidpad->vids_codec_data, &map);
+      }
+      gst_avi_mux_end_chunk (&bw, strf);
+
+      /* add video property data, mainly for aspect ratio, if any */
+      if (vidpad->vprp.aspect) {
+        gint f;
+        guint vprp;
+
+        /* let's be on the safe side */
+        vidpad->vprp.fields = MIN (vidpad->vprp.fields,
+            GST_RIFF_VPRP_VIDEO_FIELDS);
+        /* the vprp header */
+        vprp = gst_avi_mux_start_chunk (&bw, "vprp", 0);
+        /* the actual data */
+        hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.format_token);
+        hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.standard);
+        hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.vert_rate);
+        hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.hor_t_total);
+        hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.vert_lines);
+        hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.aspect);
+        hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.width);
+        hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.height);
+        hdl &= gst_byte_writer_put_uint32_le (&bw, vidpad->vprp.fields);
+
+        for (f = 0; f < vidpad->vprp.fields; ++f) {
+          gst_riff_vprp_video_field_desc *fd;
+
+          fd = &(vidpad->vprp.field_info[f]);
+          hdl &= gst_byte_writer_put_uint32_le (&bw, fd->compressed_bm_height);
+          hdl &= gst_byte_writer_put_uint32_le (&bw, fd->compressed_bm_width);
+          hdl &= gst_byte_writer_put_uint32_le (&bw, fd->valid_bm_height);
+          hdl &= gst_byte_writer_put_uint32_le (&bw, fd->valid_bm_width);
+          hdl &= gst_byte_writer_put_uint32_le (&bw, fd->valid_bm_x_offset);
+          hdl &= gst_byte_writer_put_uint32_le (&bw, fd->valid_bm_y_offset);
+          hdl &= gst_byte_writer_put_uint32_le (&bw, fd->video_x_t_offset);
+          hdl &= gst_byte_writer_put_uint32_le (&bw, fd->video_y_start);
+        }
+        gst_avi_mux_end_chunk (&bw, vprp);
+      }
+    } else {
+      codec_size = audpad->auds_codec_data ?
+          gst_buffer_get_size (audpad->auds_codec_data) : 0;
+      /* the audio header */
+      strf = gst_avi_mux_start_chunk (&bw, "strf", 0);
+      /* the actual header */
+      hdl &= gst_byte_writer_put_uint16_le (&bw, audpad->auds.format);
+      hdl &= gst_byte_writer_put_uint16_le (&bw, audpad->auds.channels);
+      hdl &= gst_byte_writer_put_uint32_le (&bw, audpad->auds.rate);
+      hdl &= gst_byte_writer_put_uint32_le (&bw, audpad->auds.av_bps);
+      hdl &= gst_byte_writer_put_uint16_le (&bw, audpad->auds.blockalign);
+      hdl &= gst_byte_writer_put_uint16_le (&bw, audpad->auds.bits_per_sample);
+      hdl &= gst_byte_writer_put_uint16_le (&bw, codec_size);
+      if (audpad->auds_codec_data) {
+        gst_buffer_map (audpad->auds_codec_data, &map, GST_MAP_READ);
+        hdl &= gst_byte_writer_put_data (&bw, map.data, map.size);
+        gst_buffer_unmap (audpad->auds_codec_data, &map);
+      }
+      gst_avi_mux_end_chunk (&bw, strf);
+    }
+
+    /* odml superindex chunk */
+    if (avipad->idx_index > 0)
+      indx = gst_avi_mux_start_chunk (&bw, "indx", 0);
+    else
+      indx = gst_avi_mux_start_chunk (&bw, "JUNK", 0);
+    hdl &= gst_byte_writer_put_uint16_le (&bw, 4);      /* bytes per entry */
+    hdl &= gst_byte_writer_put_uint8 (&bw, 0);  /* index subtype */
+    hdl &= gst_byte_writer_put_uint8 (&bw, GST_AVI_INDEX_OF_INDEXES);   /* index type */
+    hdl &= gst_byte_writer_put_uint32_le (&bw, avipad->idx_index);      /* entries in use */
+    hdl &= gst_byte_writer_put_data (&bw, (guint8 *) avipad->tag, 4);   /* stream id */
+    hdl &= gst_byte_writer_put_uint32_le (&bw, 0);      /* reserved */
+    hdl &= gst_byte_writer_put_uint32_le (&bw, 0);      /* reserved */
+    hdl &= gst_byte_writer_put_uint32_le (&bw, 0);      /* reserved */
+    hdl &= gst_byte_writer_put_data (&bw, (guint8 *) avipad->idx,
+        GST_AVI_SUPERINDEX_COUNT * sizeof (gst_avi_superindex_entry));
+    gst_avi_mux_end_chunk (&bw, indx);
+
+    /* end strl for this stream */
+    gst_avi_mux_end_chunk (&bw, strl);
+
+    node = node->next;
+  }
+
+  if (avimux->video_pads > 0) {
+    guint odml, dmlh;
+    /* odml header */
+    odml = gst_avi_mux_start_chunk (&bw, "LIST", 0);
+    hdl &= gst_byte_writer_put_data (&bw, (guint8 *) "odml", 4);
+    dmlh = gst_avi_mux_start_chunk (&bw, "dmlh", 0);
+    hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->total_frames);
+    gst_avi_mux_end_chunk (&bw, dmlh);
+    gst_avi_mux_end_chunk (&bw, odml);
+  }
+
+  /* end hdrl */
+  gst_avi_mux_end_chunk (&bw, hdrl);
+
+  /* tags */
+  if (tags) {
+    guint info;
+
+    info = gst_avi_mux_start_chunk (&bw, "LIST", 0);
+    hdl &= gst_byte_writer_put_data (&bw, (guint8 *) "INFO", 4);
+
+    gst_tag_list_foreach (tags, gst_avi_mux_write_tag, &bw);
+    if (info + 8 == gst_byte_writer_get_pos (&bw)) {
+      /* no tags writen, remove the empty INFO LIST as it is useless
+       * and prevents playback in vlc */
+      gst_byte_writer_set_pos (&bw, info - 4);
+    } else {
+      gst_avi_mux_end_chunk (&bw, info);
+    }
+  }
+
+  /* pop RIFF */
+  gst_avi_mux_end_chunk (&bw, riff);
+
+  /* avi data header */
+  hdl &= gst_byte_writer_put_data (&bw, (guint8 *) "LIST", 4);
+  hdl &= gst_byte_writer_put_uint32_le (&bw, avimux->data_size);
+  hdl &= gst_byte_writer_put_data (&bw, (guint8 *) "movi", 4);
+
+  if (!hdl)
+    goto beach;
+
+  /* now get the data */
+  buffer = gst_byte_writer_reset_and_get_buffer (&bw);
+
+  /* ... but RIFF includes more than just header */
+  gst_buffer_map (buffer, &map, GST_MAP_READWRITE);
+  size = GST_READ_UINT32_LE (map.data + 4);
+  size += 8 + avimux->data_size + avimux->idx_size;
+  GST_WRITE_UINT32_LE (map.data + 4, size);
+
+  GST_MEMDUMP_OBJECT (avimux, "avi header", map.data, map.size);
+  gst_buffer_unmap (buffer, &map);
+
+beach:
+  return buffer;
+}
+
+static GstBuffer *
+gst_avi_mux_riff_get_avix_header (guint32 datax_size)
+{
+  GstBuffer *buffer;
+  GstMapInfo map;
+
+  buffer = gst_buffer_new_and_alloc (24);
+
+  gst_buffer_map (buffer, &map, GST_MAP_WRITE);
+  memcpy (map.data + 0, "RIFF", 4);
+  GST_WRITE_UINT32_LE (map.data + 4, datax_size + 3 * 4);
+  memcpy (map.data + 8, "AVIX", 4);
+  memcpy (map.data + 12, "LIST", 4);
+  GST_WRITE_UINT32_LE (map.data + 16, datax_size);
+  memcpy (map.data + 20, "movi", 4);
+  gst_buffer_unmap (buffer, &map);
+
+  return buffer;
+}
+
+static inline GstBuffer *
+gst_avi_mux_riff_get_header (GstAviPad * avipad, guint32 video_frame_size)
+{
+  GstBuffer *buffer;
+  GstMapInfo map;
+
+  buffer = gst_buffer_new_and_alloc (8);
+
+  gst_buffer_map (buffer, &map, GST_MAP_WRITE);
+  memcpy (map.data + 0, avipad->tag, 4);
+  GST_WRITE_UINT32_LE (map.data + 4, video_frame_size);
+  gst_buffer_unmap (buffer, &map);
+
+  return buffer;
+}
+
+/* write an odml index chunk in the movi list */
+static GstFlowReturn
+gst_avi_mux_write_avix_index (GstAviMux * avimux, GstAviPad * avipad,
+    gchar * code, gchar * chunk, gst_avi_superindex_entry * super_index,
+    gint * super_index_count)
+{
+  GstFlowReturn res;
+  GstBuffer *buffer;
+  guint8 *data;
+  gst_riff_index_entry *entry;
+  gint i;
+  guint32 size, entry_count;
+  gboolean is_pcm = FALSE;
+  guint32 pcm_samples = 0;
+  GstMapInfo map;
+
+  /* check if it is pcm */
+  if (avipad && !avipad->is_video) {
+    GstAviAudioPad *audiopad = (GstAviAudioPad *) avipad;
+    if (audiopad->auds.format == GST_RIFF_WAVE_FORMAT_PCM) {
+      pcm_samples = audiopad->samples;
+      is_pcm = TRUE;
+    }
+  }
+
+  /* allocate the maximum possible */
+  buffer = gst_buffer_new_and_alloc (32 + 8 * avimux->idx_index);
+
+  gst_buffer_map (buffer, &map, GST_MAP_WRITE);
+  data = map.data;
+
+  /* general index chunk info */
+  memcpy (map.data + 0, chunk, 4);      /* chunk id */
+  GST_WRITE_UINT32_LE (map.data + 4, 0);        /* chunk size; fill later */
+  GST_WRITE_UINT16_LE (map.data + 8, 2);        /* index entry is 2 words */
+  map.data[10] = 0;             /* index subtype */
+  map.data[11] = GST_AVI_INDEX_OF_CHUNKS;       /* index type: AVI_INDEX_OF_CHUNKS */
+  GST_WRITE_UINT32_LE (map.data + 12, 0);       /* entries in use; fill later */
+  memcpy (map.data + 16, code, 4);      /* stream to which index refers */
+  GST_WRITE_UINT64_LE (map.data + 20, avimux->avix_start);      /* base offset */
+  GST_WRITE_UINT32_LE (map.data + 28, 0);       /* reserved */
+  map.data += 32;
+
+  /* now the actual index entries */
+  i = avimux->idx_index;
+  entry = avimux->idx;
+  while (i > 0) {
+    if (memcmp (&entry->id, code, 4) == 0) {
+      /* enter relative offset to the data (!) */
+      GST_WRITE_UINT32_LE (map.data, GUINT32_FROM_LE (entry->offset) + 8);
+      /* msb is set if not (!) keyframe */
+      GST_WRITE_UINT32_LE (map.data + 4, GUINT32_FROM_LE (entry->size)
+          | (GUINT32_FROM_LE (entry->flags)
+              & GST_RIFF_IF_KEYFRAME ? 0 : 1U << 31));
+      map.data += 8;
+    }
+    i--;
+    entry++;
+  }
+
+  /* ok, now we know the size and no of entries, fill in where needed */
+  size = map.data - data;
+  GST_WRITE_UINT32_LE (data + 4, size - 8);
+  entry_count = (size - 32) / 8;
+  GST_WRITE_UINT32_LE (data + 12, entry_count);
+  gst_buffer_unmap (buffer, &map);
+  gst_buffer_resize (buffer, 0, size);
+
+  /* send */
+  if ((res = gst_pad_push (avimux->srcpad, buffer)) != GST_FLOW_OK)
+    return res;
+
+  /* keep track of this in superindex (if room) ... */
+  if (*super_index_count < GST_AVI_SUPERINDEX_COUNT) {
+    i = *super_index_count;
+    super_index[i].offset = GUINT64_TO_LE (avimux->total_data);
+    super_index[i].size = GUINT32_TO_LE (size);
+    if (is_pcm) {
+      super_index[i].duration = GUINT32_TO_LE (pcm_samples);
+    } else {
+      super_index[i].duration = GUINT32_TO_LE (entry_count);
+    }
+    (*super_index_count)++;
+  } else
+    GST_WARNING_OBJECT (avimux, "No more room in superindex of stream %s",
+        code);
+
+  /* ... and in size */
+  avimux->total_data += size;
+  if (avimux->is_bigfile)
+    avimux->datax_size += size;
+  else
+    avimux->data_size += size;
+
+  return GST_FLOW_OK;
+}
+
+/* some other usable functions (thankyou xawtv ;-) ) */
+
+static void
+gst_avi_mux_add_index (GstAviMux * avimux, GstAviPad * avipad, guint32 flags,
+    guint32 size)
+{
+  gchar *code = avipad->tag;
+  if (avimux->idx_index == avimux->idx_count) {
+    avimux->idx_count += 256;
+    avimux->idx =
+        g_realloc (avimux->idx,
+        avimux->idx_count * sizeof (gst_riff_index_entry));
+  }
+
+  /* in case of pcm audio, we need to count the number of samples for
+   * putting in the indx entries */
+  if (!avipad->is_video) {
+    GstAviAudioPad *audiopad = (GstAviAudioPad *) avipad;
+    if (audiopad->auds.format == GST_RIFF_WAVE_FORMAT_PCM) {
+      audiopad->samples += size / audiopad->auds.blockalign;
+    }
+  }
+
+  memcpy (&(avimux->idx[avimux->idx_index].id), code, 4);
+  avimux->idx[avimux->idx_index].flags = GUINT32_TO_LE (flags);
+  avimux->idx[avimux->idx_index].offset = GUINT32_TO_LE (avimux->idx_offset);
+  avimux->idx[avimux->idx_index].size = GUINT32_TO_LE (size);
+  avimux->idx_index++;
+}
+
+static GstFlowReturn
+gst_avi_mux_write_index (GstAviMux * avimux)
+{
+  GstFlowReturn res;
+  GstBuffer *buffer;
+  GstMapInfo map;
+  guint8 *data;
+  gsize size;
+
+  buffer = gst_buffer_new_and_alloc (8);
+
+  gst_buffer_map (buffer, &map, GST_MAP_WRITE);
+  memcpy (map.data + 0, "idx1", 4);
+  GST_WRITE_UINT32_LE (map.data + 4,
+      avimux->idx_index * sizeof (gst_riff_index_entry));
+  gst_buffer_unmap (buffer, &map);
+
+  res = gst_pad_push (avimux->srcpad, buffer);
+  if (res != GST_FLOW_OK)
+    return res;
+
+  buffer = gst_buffer_new ();
+
+  size = avimux->idx_index * sizeof (gst_riff_index_entry);
+  data = (guint8 *) avimux->idx;
+  avimux->idx = NULL;           /* will be free()'ed by gst_buffer_unref() */
+
+  gst_buffer_append_memory (buffer,
+      gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
+
+  avimux->total_data += size + 8;
+
+  res = gst_pad_push (avimux->srcpad, buffer);
+  if (res != GST_FLOW_OK)
+    return res;
+
+  avimux->idx_size += avimux->idx_index * sizeof (gst_riff_index_entry) + 8;
+
+  /* update header */
+  avimux->avi_hdr.flags |= GST_RIFF_AVIH_HASINDEX;
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_avi_mux_bigfile (GstAviMux * avimux, gboolean last)
+{
+  GstFlowReturn res = GST_FLOW_OK;
+  GstBuffer *header;
+  GSList *node;
+
+  /* first some odml standard index chunks in the movi list */
+  node = avimux->sinkpads;
+  while (node) {
+    GstAviPad *avipad = (GstAviPad *) node->data;
+
+    node = node->next;
+
+    res = gst_avi_mux_write_avix_index (avimux, avipad, avipad->tag,
+        avipad->idx_tag, avipad->idx, &avipad->idx_index);
+    if (res != GST_FLOW_OK)
+      return res;
+  }
+
+  if (avimux->is_bigfile) {
+    GstSegment segment;
+
+    gst_segment_init (&segment, GST_FORMAT_BYTES);
+
+    /* search back */
+    segment.start = avimux->avix_start;
+    segment.time = avimux->avix_start;
+    gst_pad_push_event (avimux->srcpad, gst_event_new_segment (&segment));
+
+    /* rewrite AVIX header */
+    header = gst_avi_mux_riff_get_avix_header (avimux->datax_size);
+    res = gst_pad_push (avimux->srcpad, header);
+
+    /* go back to current location, at least try */
+    segment.start = avimux->total_data;
+    segment.time = avimux->total_data;
+    gst_pad_push_event (avimux->srcpad, gst_event_new_segment (&segment));
+
+    if (res != GST_FLOW_OK)
+      return res;
+  } else {                      /* write a standard index in the first riff chunk */
+    res = gst_avi_mux_write_index (avimux);
+    /* the index data/buffer is freed by pushing it */
+    avimux->idx_count = 0;
+    if (res != GST_FLOW_OK)
+      return res;
+  }
+
+  avimux->avix_start = avimux->total_data;
+
+  if (last)
+    return res;
+
+  avimux->is_bigfile = TRUE;
+  avimux->numx_frames = 0;
+  avimux->datax_size = 4;       /* movi tag */
+  avimux->idx_index = 0;
+  node = avimux->sinkpads;
+  while (node) {
+    GstAviPad *avipad = (GstAviPad *) node->data;
+    node = node->next;
+    if (!avipad->is_video) {
+      GstAviAudioPad *audiopad = (GstAviAudioPad *) avipad;
+      audiopad->samples = 0;
+    }
+  }
+
+  header = gst_avi_mux_riff_get_avix_header (0);
+  avimux->total_data += gst_buffer_get_size (header);
+  /* avix_start is used as base offset for the odml index chunk */
+  avimux->idx_offset = avimux->total_data - avimux->avix_start;
+
+  return gst_pad_push (avimux->srcpad, header);
+}
+
+/* enough header blabla now, let's go on to actually writing the headers */
+
+static GstFlowReturn
+gst_avi_mux_start_file (GstAviMux * avimux)
+{
+  GstFlowReturn res;
+  GstBuffer *header;
+  GSList *node;
+  GstCaps *caps;
+  GstSegment segment;
+
+  avimux->total_data = 0;
+  avimux->total_frames = 0;
+  avimux->data_size = 4;        /* movi tag */
+  avimux->datax_size = 0;
+  avimux->num_frames = 0;
+  avimux->numx_frames = 0;
+  avimux->avix_start = 0;
+
+  avimux->idx_index = 0;
+  avimux->idx_offset = 0;       /* see 10 lines below */
+  avimux->idx_size = 0;
+  avimux->idx_count = 0;
+  avimux->idx = NULL;
+
+  /* state */
+  avimux->write_header = FALSE;
+  avimux->restart = FALSE;
+
+  /* init streams, see what we've got */
+  node = avimux->sinkpads;
+  avimux->audio_pads = avimux->video_pads = 0;
+  while (node) {
+    GstAviPad *avipad = (GstAviPad *) node->data;
+
+    node = node->next;
+
+    if (!avipad->is_video) {
+      /* audio stream numbers must start at 1 iff there is a video stream 0;
+       * request_pad inserts video pad at head of list, so this test suffices */
+      if (avimux->video_pads)
+        avimux->audio_pads++;
+      avipad->tag = g_strdup_printf ("%02uwb", avimux->audio_pads);
+      avipad->idx_tag = g_strdup_printf ("ix%02u", avimux->audio_pads);
+      if (!avimux->video_pads)
+        avimux->audio_pads++;
+    } else {
+      avipad->tag = g_strdup_printf ("%02udb", avimux->video_pads);
+      avipad->idx_tag = g_strdup_printf ("ix%02u", avimux->video_pads++);
+    }
+  }
+
+  /* stream-start (FIXME: create id based on input ids) */
+  {
+    gchar s_id[32];
+
+    g_snprintf (s_id, sizeof (s_id), "avimux-%08x", g_random_int ());
+    gst_pad_push_event (avimux->srcpad, gst_event_new_stream_start (s_id));
+  }
+
+  caps = gst_pad_get_pad_template_caps (avimux->srcpad);
+  gst_pad_set_caps (avimux->srcpad, caps);
+  gst_caps_unref (caps);
+
+  /* let downstream know we think in BYTES and expect to do seeking later on */
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  gst_pad_push_event (avimux->srcpad, gst_event_new_segment (&segment));
+
+  /* header */
+  avimux->avi_hdr.streams = g_slist_length (avimux->sinkpads);
+  avimux->is_bigfile = FALSE;
+
+  header = gst_avi_mux_riff_get_avi_header (avimux);
+  avimux->total_data += gst_buffer_get_size (header);
+
+  res = gst_pad_push (avimux->srcpad, header);
+
+  avimux->idx_offset = avimux->total_data;
+
+  return res;
+}
+
+static GstFlowReturn
+gst_avi_mux_stop_file (GstAviMux * avimux)
+{
+  GstFlowReturn res = GST_FLOW_OK;
+  GstBuffer *header;
+  GSList *node;
+  GstSegment segment;
+
+  /* Do not write index and header, if the index has no data */
+  if (avimux->idx == NULL)
+    return GST_FLOW_OK;
+
+  /* if bigfile, rewrite header, else write indexes */
+  /* don't bail out at once if error, still try to re-write header */
+  if (avimux->video_pads > 0) {
+    if (avimux->is_bigfile) {
+      res = gst_avi_mux_bigfile (avimux, TRUE);
+    } else {
+      res = gst_avi_mux_write_index (avimux);
+    }
+  }
+
+  /* we do our best to make it interleaved at least ... */
+  if (avimux->audio_pads > 0 && avimux->video_pads > 0)
+    avimux->avi_hdr.flags |= GST_RIFF_AVIH_ISINTERLEAVED;
+
+  /* set rate and everything having to do with that */
+  avimux->avi_hdr.max_bps = 0;
+  node = avimux->sinkpads;
+  while (node) {
+    GstAviPad *avipad = (GstAviPad *) node->data;
+
+    node = node->next;
+
+    if (!avipad->is_video) {
+      GstAviAudioPad *audpad = (GstAviAudioPad *) avipad;
+
+      /* calculate bps if needed */
+      if (!audpad->auds.av_bps) {
+        if (audpad->audio_time) {
+          audpad->auds.av_bps =
+              (GST_SECOND * audpad->audio_size) / audpad->audio_time;
+          /* round bps to nearest multiple of 8;
+           * which is much more likely to be the (cbr) bitrate in use;
+           * which in turn results in better timestamp calculation on playback */
+          audpad->auds.av_bps = GST_ROUND_UP_8 (audpad->auds.av_bps - 4);
+        } else {
+          GST_ELEMENT_WARNING (avimux, STREAM, MUX,
+              (_("No or invalid input audio, AVI stream will be corrupt.")),
+              (NULL));
+          audpad->auds.av_bps = 0;
+        }
+      }
+      /* housekeeping for vbr case */
+      if (audpad->max_audio_chunk)
+        audpad->auds.blockalign = audpad->max_audio_chunk;
+      if (audpad->auds.blockalign == 0)
+        audpad->auds.blockalign = 1;
+      /* note that hdr.rate is actually used by demux in cbr case */
+      if (avipad->hdr.scale <= 1)
+        avipad->hdr.rate = audpad->auds.av_bps / audpad->auds.blockalign;
+      avimux->avi_hdr.max_bps += audpad->auds.av_bps;
+      avipad->hdr.length = gst_util_uint64_scale (audpad->audio_time,
+          avipad->hdr.rate, avipad->hdr.scale * GST_SECOND);
+    } else {
+      GstAviVideoPad *vidpad = (GstAviVideoPad *) avipad;
+
+      avimux->avi_hdr.max_bps += ((vidpad->vids.bit_cnt + 7) / 8) *
+          (1000000. / avimux->avi_hdr.us_frame) * vidpad->vids.image_size;
+      avipad->hdr.length = avimux->total_frames;
+    }
+  }
+
+  /* statistics/total_frames/... */
+  avimux->avi_hdr.tot_frames = avimux->num_frames;
+
+  /* seek and rewrite the header */
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  gst_pad_push_event (avimux->srcpad, gst_event_new_segment (&segment));
+
+  /* the first error survives */
+  header = gst_avi_mux_riff_get_avi_header (avimux);
+  if (res == GST_FLOW_OK)
+    res = gst_pad_push (avimux->srcpad, header);
+  else
+    gst_pad_push (avimux->srcpad, header);
+
+  segment.start = avimux->total_data;
+  segment.time = avimux->total_data;
+  gst_pad_push_event (avimux->srcpad, gst_event_new_segment (&segment));
+
+  avimux->write_header = TRUE;
+
+  return res;
+}
+
+static GstFlowReturn
+gst_avi_mux_restart_file (GstAviMux * avimux)
+{
+  GstFlowReturn res;
+
+  if ((res = gst_avi_mux_stop_file (avimux)) != GST_FLOW_OK)
+    return res;
+
+  gst_pad_push_event (avimux->srcpad, gst_event_new_eos ());
+
+  return gst_avi_mux_start_file (avimux);
+}
+
+/* handle events (search) */
+static gboolean
+gst_avi_mux_handle_event (GstCollectPads * pads, GstCollectData * data,
+    GstEvent * event, gpointer user_data)
+{
+  GstAviMux *avimux;
+  gboolean ret = TRUE;
+
+  avimux = GST_AVI_MUX (user_data);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+      GstAviCollectData *collect_pad;
+      GstAviVideoPad *avipad;
+
+      gst_event_parse_caps (event, &caps);
+
+      /* find stream data */
+      collect_pad = (GstAviCollectData *) data;
+      g_assert (collect_pad);
+      avipad = (GstAviVideoPad *) collect_pad->avipad;
+      g_assert (avipad);
+
+      if (avipad->parent.is_video) {
+        ret = gst_avi_mux_vidsink_set_caps (data->pad, caps);
+      } else {
+        ret = gst_avi_mux_audsink_set_caps (data->pad, caps);
+      }
+      gst_event_unref (event);
+      event = NULL;
+      break;
+    }
+    case GST_EVENT_TAG:{
+      GstTagList *list;
+      GstTagSetter *setter = GST_TAG_SETTER (avimux);
+      const GstTagMergeMode mode = gst_tag_setter_get_tag_merge_mode (setter);
+
+      gst_event_parse_tag (event, &list);
+      gst_tag_setter_merge_tags (setter, list, mode);
+      gst_event_unref (event);
+      event = NULL;
+      break;
+    }
+    default:
+      break;
+  }
+
+  if (event != NULL)
+    return gst_collect_pads_event_default (pads, data, event, FALSE);
+
+  return ret;
+}
+
+/* send extra 'padding' data */
+static GstFlowReturn
+gst_avi_mux_send_pad_data (GstAviMux * avimux, gulong num_bytes)
+{
+  GstBuffer *buffer;
+
+  buffer = gst_buffer_new_and_alloc (num_bytes);
+  gst_buffer_memset (buffer, 0, 0, num_bytes);
+
+  return gst_pad_push (avimux->srcpad, buffer);
+}
+
+#define gst_avi_mux_is_uncompressed(fourcc)		\
+  (fourcc == GST_RIFF_DIB ||				\
+   fourcc == GST_RIFF_rgb ||				\
+   fourcc == GST_RIFF_RGB || fourcc == GST_RIFF_RAW)
+
+/*
+ * Helper for gst_avi_demux_invert()
+ */
+static inline void
+swap_line (guint8 * d1, guint8 * d2, guint8 * tmp, gint bytes)
+{
+  memcpy (tmp, d1, bytes);
+  memcpy (d1, d2, bytes);
+  memcpy (d2, tmp, bytes);
+}
+
+/*
+ * Invert DIB buffers... Takes existing buffer and
+ * returns either the buffer or a new one (with old
+ * one dereferenced).
+ * FFMPEG does this by simply negating the height in the header. Should we?
+ * FIXME: can't we preallocate tmp? and remember stride, bpp?
+ *        this could be done in do_one_buffer() I suppose
+ */
+static GstBuffer *
+gst_avi_mux_invert (GstAviPad * avipad, GstBuffer * buf)
+{
+  gint y, w, h;
+  gint bpp, stride;
+  guint8 *tmp = NULL;
+  GstMapInfo map;
+
+  GstAviVideoPad *vidpad = (GstAviVideoPad *) avipad;
+
+  h = vidpad->vids.height;
+  w = vidpad->vids.width;
+  bpp = vidpad->vids.bit_cnt ? vidpad->vids.bit_cnt : 8;
+  stride = GST_ROUND_UP_4 (w * (bpp / 8));
+
+  buf = gst_buffer_make_writable (buf);
+
+  gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+  if (map.size < (stride * h)) {
+    GST_WARNING ("Buffer is smaller than reported Width x Height x Depth");
+    gst_buffer_unmap (buf, &map);
+    return buf;
+  }
+
+  tmp = g_malloc (stride);
+
+  for (y = 0; y < h / 2; y++) {
+    swap_line (map.data + stride * y, map.data + stride * (h - 1 - y), tmp,
+        stride);
+  }
+
+  g_free (tmp);
+
+  gst_buffer_unmap (buf, &map);
+
+  return buf;
+}
+
+/* do buffer */
+static GstFlowReturn
+gst_avi_mux_do_buffer (GstAviMux * avimux, GstAviPad * avipad)
+{
+  GstFlowReturn res;
+  GstBuffer *data, *header;
+  gulong total_size, pad_bytes = 0;
+  guint flags;
+  gsize datasize;
+  GstClockTime time;
+
+  data = gst_collect_pads_pop (avimux->collect, avipad->collect);
+  /* arrange downstream running time */
+  time = gst_segment_to_running_time (&avipad->collect->segment,
+      GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (data));
+  if (time != GST_BUFFER_TIMESTAMP (data)) {
+    data = gst_buffer_make_writable (data);
+    GST_BUFFER_TIMESTAMP (data) = time;
+  }
+
+  /* Prepend a special buffer to the first one for some formats */
+  if (avipad->is_video) {
+    GstAviVideoPad *vidpad = (GstAviVideoPad *) avipad;
+
+    if (vidpad->prepend_buffer) {
+      /* Keep a reference to data until we copy the timestamps, then release it */
+      GstBuffer *newdata =
+          gst_buffer_append (vidpad->prepend_buffer, gst_buffer_ref (data));
+      gst_buffer_copy_into (newdata, data, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+      gst_buffer_unref (data);
+
+      data = newdata;
+      vidpad->prepend_buffer = NULL;
+    }
+
+    /* DIB buffers are stored topdown (I don't know why) */
+    if (gst_avi_mux_is_uncompressed (avipad->hdr.fcc_handler)) {
+      data = gst_avi_mux_invert (avipad, data);
+    }
+  }
+
+  if (avimux->restart) {
+    if ((res = gst_avi_mux_restart_file (avimux)) != GST_FLOW_OK)
+      goto done;
+  }
+
+  datasize = gst_buffer_get_size (data);
+
+  /* need to restart or start a next avix chunk ? */
+  if ((avimux->is_bigfile ? avimux->datax_size : avimux->data_size) +
+      datasize > GST_AVI_MAX_SIZE) {
+    if (avimux->enable_large_avi) {
+      if ((res = gst_avi_mux_bigfile (avimux, FALSE)) != GST_FLOW_OK)
+        goto done;
+    } else {
+      if ((res = gst_avi_mux_restart_file (avimux)) != GST_FLOW_OK)
+        goto done;
+    }
+  }
+
+  /* get header and record some stats */
+  if (datasize & 1) {
+    pad_bytes = 2 - (datasize & 1);
+  }
+  header = gst_avi_mux_riff_get_header (avipad, datasize);
+  total_size = gst_buffer_get_size (header) + datasize + pad_bytes;
+
+  if (avimux->is_bigfile) {
+    avimux->datax_size += total_size;
+  } else {
+    avimux->data_size += total_size;
+  }
+
+  if (G_UNLIKELY (avipad->hook)) {
+    gst_buffer_ref (data);
+    avipad->hook (avimux, avipad, data);
+  }
+
+  /* the suggested buffer size is the max frame size */
+  if (avipad->hdr.bufsize < datasize)
+    avipad->hdr.bufsize = datasize;
+
+  if (avipad->is_video) {
+    avimux->total_frames++;
+
+    if (avimux->is_bigfile) {
+      avimux->numx_frames++;
+    } else {
+      avimux->num_frames++;
+    }
+
+    flags = 0x02;
+    if (!GST_BUFFER_FLAG_IS_SET (data, GST_BUFFER_FLAG_DELTA_UNIT))
+      flags |= 0x10;
+  } else {
+    GstAviAudioPad *audpad = (GstAviAudioPad *) avipad;
+
+    flags = 0;
+    audpad->audio_size += datasize;
+    audpad->audio_time += GST_BUFFER_DURATION (data);
+    if (audpad->max_audio_chunk && datasize > audpad->max_audio_chunk)
+      audpad->max_audio_chunk = datasize;
+  }
+
+  gst_avi_mux_add_index (avimux, avipad, flags, datasize);
+
+  /* send buffers */
+  GST_LOG_OBJECT (avimux, "pushing buffers: head, data");
+
+  if ((res = gst_pad_push (avimux->srcpad, header)) != GST_FLOW_OK)
+    goto done;
+
+  gst_buffer_ref (data);
+  if ((res = gst_pad_push (avimux->srcpad, data)) != GST_FLOW_OK)
+    goto done;
+
+  if (pad_bytes) {
+    if ((res = gst_avi_mux_send_pad_data (avimux, pad_bytes)) != GST_FLOW_OK)
+      goto done;
+  }
+
+  /* if any push above fails, we're in trouble with file consistency anyway */
+  avimux->total_data += total_size;
+  avimux->idx_offset += total_size;
+
+done:
+  gst_buffer_unref (data);
+  return res;
+}
+
+/* pick the oldest buffer from the pads and push it */
+static GstFlowReturn
+gst_avi_mux_do_one_buffer (GstAviMux * avimux)
+{
+  GstAviPad *avipad, *best_pad;
+  GSList *node;
+  GstBuffer *buffer;
+  GstClockTime time, best_time, delay;
+
+  node = avimux->sinkpads;
+  best_pad = NULL;
+  best_time = GST_CLOCK_TIME_NONE;
+  for (; node; node = node->next) {
+    avipad = (GstAviPad *) node->data;
+
+    if (!avipad->collect)
+      continue;
+
+    buffer = gst_collect_pads_peek (avimux->collect, avipad->collect);
+    if (!buffer)
+      continue;
+    time = GST_BUFFER_TIMESTAMP (buffer);
+    gst_buffer_unref (buffer);
+
+    /* invalid should pass */
+    if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
+      time = gst_segment_to_running_time (&avipad->collect->segment,
+          GST_FORMAT_TIME, time);
+      if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
+        GST_DEBUG_OBJECT (avimux, "clipping buffer on pad %s outside segment",
+            GST_PAD_NAME (avipad->collect->pad));
+        buffer = gst_collect_pads_pop (avimux->collect, avipad->collect);
+        gst_buffer_unref (buffer);
+        return GST_FLOW_OK;
+      }
+    }
+
+    delay = avipad->is_video ? GST_SECOND / 2 : 0;
+
+    /* invalid timestamp buffers pass first,
+     * these are probably initialization buffers */
+    if (best_pad == NULL || !GST_CLOCK_TIME_IS_VALID (time)
+        || (GST_CLOCK_TIME_IS_VALID (best_time) && time + delay < best_time)) {
+      best_pad = avipad;
+      best_time = time + delay;
+    }
+  }
+
+  if (best_pad) {
+    GST_LOG_OBJECT (avimux, "selected pad %s with time %" GST_TIME_FORMAT,
+        GST_PAD_NAME (best_pad->collect->pad), GST_TIME_ARGS (best_time));
+
+    return gst_avi_mux_do_buffer (avimux, best_pad);
+  } else {
+    /* simply finish off the file and send EOS */
+    gst_avi_mux_stop_file (avimux);
+    gst_pad_push_event (avimux->srcpad, gst_event_new_eos ());
+    return GST_FLOW_EOS;
+  }
+
+}
+
+static GstFlowReturn
+gst_avi_mux_collect_pads (GstCollectPads * pads, GstAviMux * avimux)
+{
+  GstFlowReturn res;
+
+  if (G_UNLIKELY (avimux->write_header)) {
+    if ((res = gst_avi_mux_start_file (avimux)) != GST_FLOW_OK)
+      return res;
+  }
+
+  return gst_avi_mux_do_one_buffer (avimux);
+}
+
+
+static void
+gst_avi_mux_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstAviMux *avimux;
+
+  avimux = GST_AVI_MUX (object);
+
+  switch (prop_id) {
+    case PROP_BIGFILE:
+      g_value_set_boolean (value, avimux->enable_large_avi);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_avi_mux_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstAviMux *avimux;
+
+  avimux = GST_AVI_MUX (object);
+
+  switch (prop_id) {
+    case PROP_BIGFILE:
+      avimux->enable_large_avi = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStateChangeReturn
+gst_avi_mux_change_state (GstElement * element, GstStateChange transition)
+{
+  GstAviMux *avimux;
+  GstStateChangeReturn ret;
+
+  avimux = GST_AVI_MUX (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_collect_pads_start (avimux->collect);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_collect_pads_stop (avimux->collect);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    goto done;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_avi_mux_reset (avimux);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+done:
+  return ret;
+}
diff --git a/gst/avi/gstavimux.h b/gst/avi/gstavimux.h
new file mode 100644
index 0000000..6fd5343
--- /dev/null
+++ b/gst/avi/gstavimux.h
@@ -0,0 +1,198 @@
+/* AVI muxer plugin for GStreamer
+ * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_AVI_MUX_H__
+#define __GST_AVI_MUX_H__
+
+
+#include <gst/gst.h>
+#include <gst/base/gstcollectpads.h>
+#include <gst/riff/riff-ids.h>
+#include "avi-ids.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AVI_MUX \
+  (gst_avi_mux_get_type())
+#define GST_AVI_MUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AVI_MUX,GstAviMux))
+#define GST_AVI_MUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AVI_MUX,GstAviMuxClass))
+#define GST_IS_AVI_MUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AVI_MUX))
+#define GST_IS_AVI_MUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AVI_MUX))
+
+#define GST_AVI_INDEX_OF_INDEXES     0
+#define GST_AVI_INDEX_OF_CHUNKS      1
+
+/* this allows indexing up to 64GB avi file */
+#define GST_AVI_SUPERINDEX_COUNT    32
+
+/* max size */
+#define GST_AVI_MAX_SIZE    0x40000000
+
+typedef struct _gst_avi_superindex_entry {
+  guint64 offset;
+  guint32 size;
+  guint32 duration;
+} gst_avi_superindex_entry;
+
+typedef struct _gst_riff_strh_full {
+  gst_riff_strh  parent;
+  /* rcFrame, RECT structure (struct of 4 shorts) */
+  gint16  left;
+  gint16  top;
+  gint16  right;
+  gint16  bottom;
+} gst_riff_strh_full;
+
+typedef struct _GstAviPad GstAviPad;
+typedef struct _GstAviMux GstAviMux;
+typedef struct _GstAviMuxClass GstAviMuxClass;
+
+typedef GstFlowReturn (*GstAviPadHook) (GstAviMux * avi, GstAviPad * avipad,
+                                        GstBuffer * buffer);
+
+struct _GstAviPad {
+  /* do not extend, link to it */
+  /* is NULL if original sink request pad has been removed */
+  GstCollectData *collect;
+
+  /* type */
+  gboolean is_video;
+  gboolean connected;
+
+  /* chunk tag */
+  gchar *tag;
+
+  /* stream header */
+  gst_riff_strh hdr;
+
+  /* odml super indexes */
+  gst_avi_superindex_entry idx[GST_AVI_SUPERINDEX_COUNT];
+  gint idx_index;
+  gchar *idx_tag;
+
+  /* stream specific hook */
+  GstAviPadHook hook;
+};
+
+typedef struct _GstAviVideoPad {
+  GstAviPad parent;
+
+  /* stream format */
+  gst_riff_strf_vids vids;
+  /* extra data */
+  GstBuffer *vids_codec_data;
+  /* ODML video properties */
+  gst_riff_vprp vprp;
+
+  GstBuffer *prepend_buffer;
+
+} GstAviVideoPad;
+
+typedef struct _GstAviAudioPad {
+  GstAviPad parent;
+
+  /* stream format */
+  gst_riff_strf_auds auds;
+  /* audio info for bps calculation */
+  guint32 audio_size;
+  guint64 audio_time;
+  /* max audio chunk size for vbr */
+  guint32 max_audio_chunk;
+
+  /* counts the number of samples to put in indx chunk
+   * useful for raw audio where usually there are more than
+   * 1 sample in each GstBuffer */
+  gint samples;
+
+  /* extra data */
+  GstBuffer *auds_codec_data;
+} GstAviAudioPad;
+
+typedef struct _GstAviCollectData {
+  /* extend the CollectData */
+  GstCollectData collect;
+
+  GstAviPad      *avipad;
+} GstAviCollectData;
+
+struct _GstAviMux {
+  GstElement element;
+
+  /* pads */
+  GstPad              *srcpad;
+  /* sinkpads, video first */
+  GSList              *sinkpads;
+  /* video restricted to 1 pad */
+  guint               video_pads, audio_pads;
+  GstCollectPads     *collect;
+
+  /* the AVI header */
+  /* still some single stream video data in mux struct */
+  gst_riff_avih avi_hdr;
+  /* total number of (video) frames */
+  guint32 total_frames;
+  /* amount of total data (bytes) */
+  guint64 total_data;
+  /* amount of data (bytes) in the AVI/AVIX block;
+   * actually the movi list, so counted from and including the movi tag */
+  guint32 data_size, datax_size;
+  /* num (video) frames in the AVI/AVIX block */
+  guint32 num_frames, numx_frames;
+  /* size of hdrl list, including tag as usual */
+
+  /* total size of extra codec data */
+  guint32 codec_data_size;
+  /* state info */
+  gboolean write_header;
+  gboolean restart;
+
+  /* tags */
+  GstTagList *tags_snap;
+
+  /* information about the AVI index ('idx') */
+  gst_riff_index_entry *idx;
+  gint idx_index, idx_count;
+  /* offset of *chunk* (relative to a base offset); entered in the index */
+  guint32 idx_offset;
+  /* size of idx1 chunk (including! chunk header and size bytes) */
+  guint32 idx_size;
+
+  /* are we a big file already? */
+  gboolean is_bigfile;
+  guint64 avix_start;
+
+  /* whether to use "large AVI files" or just stick to small indexed files */
+  gboolean enable_large_avi;
+};
+
+struct _GstAviMuxClass {
+  GstElementClass parent_class;
+};
+
+GType gst_avi_mux_get_type(void);
+
+G_END_DECLS
+
+
+#endif /* __GST_AVI_MUX_H__ */
diff --git a/gst/avi/gstavisubtitle.c b/gst/avi/gstavisubtitle.c
new file mode 100644
index 0000000..25c9cca
--- /dev/null
+++ b/gst/avi/gstavisubtitle.c
@@ -0,0 +1,389 @@
+/* GStreamer AVI GAB2 subtitle parser
+ * Copyright (C) <2007> Thijs Vermeir <thijsvermeir@gmail.com>
+ * Copyright (C) <2007> Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-avisubtitle
+ *
+ * <refsect2>
+ * <para>
+ * Parses the subtitle stream from an avi file.
+ * </para>
+ * <title>Example launch line</title>
+ * <para>
+ * <programlisting>
+ * gst-launch-1.0 filesrc location=subtitle.avi ! avidemux name=demux ! queue ! avisubtitle ! subparse ! textoverlay name=overlay ! videoconvert ! autovideosink demux. ! queue ! decodebin ! overlay.
+ * </programlisting>
+ * This plays an avi file with a video and subtitle stream.
+ * </para>
+ * </refsect2>
+ */
+
+/* example of a subtitle chunk in an avi file
+ * 00000000: 47 41 42 32 00 02 00 10 00 00 00 45 00 6e 00 67  GAB2.......E.n.g
+ * 00000010: 00 6c 00 69 00 73 00 68 00 00 00 04 00 8e 00 00  .l.i.s.h........
+ * 00000020: 00 ef bb bf 31 0d 0a 30 30 3a 30 30 3a 30 30 2c  ....1..00:00:00,
+ * 00000030: 31 30 30 20 2d 2d 3e 20 30 30 3a 30 30 3a 30 32  100 --> 00:00:02
+ * 00000040: 2c 30 30 30 0d 0a 3c 62 3e 41 6e 20 55 54 46 38  ,000..<b>An UTF8
+ * 00000050: 20 53 75 62 74 69 74 6c 65 20 77 69 74 68 20 42   Subtitle with B
+ * 00000060: 4f 4d 3c 2f 62 3e 0d 0a 0d 0a 32 0d 0a 30 30 3a  OM</b>....2..00:
+ * 00000070: 30 30 3a 30 32 2c 31 30 30 20 2d 2d 3e 20 30 30  00:02,100 --> 00
+ * 00000080: 3a 30 30 3a 30 34 2c 30 30 30 0d 0a 53 6f 6d 65  :00:04,000..Some
+ * 00000090: 74 68 69 6e 67 20 6e 6f 6e 41 53 43 49 49 20 2d  thing nonASCII -
+ * 000000a0: 20 c2 b5 c3 b6 c3 a4 c3 bc c3 9f 0d 0a 0d 0a      ..............
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstavisubtitle.h"
+
+GST_DEBUG_CATEGORY_STATIC (avisubtitle_debug);
+#define GST_CAT_DEFAULT avisubtitle_debug
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-subtitle-avi")
+    );
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-subtitle")
+    );
+
+static void gst_avi_subtitle_title_tag (GstAviSubtitle * sub, gchar * title);
+static GstFlowReturn gst_avi_subtitle_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer);
+static GstStateChangeReturn gst_avi_subtitle_change_state (GstElement * element,
+    GstStateChange transition);
+static gboolean gst_avi_subtitle_send_event (GstElement * element,
+    GstEvent * event);
+
+#define gst_avi_subtitle_parent_class parent_class
+G_DEFINE_TYPE (GstAviSubtitle, gst_avi_subtitle, GST_TYPE_ELEMENT);
+
+#define IS_BOM_UTF8(data)     ((GST_READ_UINT32_BE(data) >> 8) == 0xEFBBBF)
+#define IS_BOM_UTF16_BE(data) (GST_READ_UINT16_BE(data) == 0xFEFF)
+#define IS_BOM_UTF16_LE(data) (GST_READ_UINT16_LE(data) == 0xFEFF)
+#define IS_BOM_UTF32_BE(data) (GST_READ_UINT32_BE(data) == 0xFEFF)
+#define IS_BOM_UTF32_LE(data) (GST_READ_UINT32_LE(data) == 0xFEFF)
+
+static GstBuffer *
+gst_avi_subtitle_extract_file (GstAviSubtitle * sub, GstBuffer * buffer,
+    guint offset, guint len)
+{
+  const gchar *input_enc = NULL;
+  GstBuffer *ret = NULL;
+  gchar *data;
+  GstMapInfo map;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  data = (gchar *) (map.data + offset);
+
+  if (len >= (3 + 1) && IS_BOM_UTF8 (data) &&
+      g_utf8_validate (data + 3, len - 3, NULL)) {
+    ret =
+        gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset + 3,
+        len - 3);
+  } else if (len >= 2 && IS_BOM_UTF16_BE (data)) {
+    input_enc = "UTF-16BE";
+    data += 2;
+    len -= 2;
+  } else if (len >= 2 && IS_BOM_UTF16_LE (data)) {
+    input_enc = "UTF-16LE";
+    data += 2;
+    len -= 2;
+  } else if (len >= 4 && IS_BOM_UTF32_BE (data)) {
+    input_enc = "UTF-32BE";
+    data += 4;
+    len -= 4;
+  } else if (len >= 4 && IS_BOM_UTF32_LE (data)) {
+    input_enc = "UTF-32LE";
+    data += 4;
+    len -= 4;
+  } else if (g_utf8_validate (data, len, NULL)) {
+    /* not specified, check if it's UTF-8 */
+    ret = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, len);
+  } else {
+    /* we could fall back to gst_tag_freeform_to_utf8() here */
+    GST_WARNING_OBJECT (sub, "unspecified encoding, and not UTF-8");
+    ret = NULL;
+    goto done;
+  }
+
+  g_return_val_if_fail (ret != NULL || input_enc != NULL, NULL);
+
+  if (input_enc) {
+    GError *err = NULL;
+    gchar *utf8;
+    gsize slen;
+
+    GST_DEBUG_OBJECT (sub, "converting subtitles from %s to UTF-8", input_enc);
+    utf8 = g_convert (data, len, "UTF-8", input_enc, NULL, NULL, &err);
+
+    if (err != NULL) {
+      GST_WARNING_OBJECT (sub, "conversion to UTF-8 failed : %s", err->message);
+      g_error_free (err);
+      ret = NULL;
+      goto done;
+    }
+
+    ret = gst_buffer_new ();
+    slen = strlen (utf8);
+    gst_buffer_append_memory (ret,
+        gst_memory_new_wrapped (0, utf8, slen, 0, slen, utf8, g_free));
+
+    GST_BUFFER_OFFSET (ret) = 0;
+  }
+
+done:
+  gst_buffer_unmap (buffer, &map);
+
+  return ret;
+}
+
+/**
+ * gst_avi_subtitle_title_tag:
+ * @sub: subtitle element
+ * @title: the title of this subtitle stream
+ *
+ * Send an event to the srcpad of the @sub element with the title
+ * of the subtitle stream as a GST_TAG_TITLE
+ */
+static void
+gst_avi_subtitle_title_tag (GstAviSubtitle * sub, gchar * title)
+{
+  gst_pad_push_event (sub->src,
+      gst_event_new_tag (gst_tag_list_new (GST_TAG_TITLE, title, NULL)));
+}
+
+static GstFlowReturn
+gst_avi_subtitle_parse_gab2_chunk (GstAviSubtitle * sub, GstBuffer * buf)
+{
+  gchar *name_utf8;
+  guint name_length;
+  guint file_length;
+  GstMapInfo map;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  /* check the magic word "GAB2\0", and the next word must be 2 */
+  if (map.size < 12 || memcmp (map.data, "GAB2\0\2\0", 5 + 2) != 0)
+    goto wrong_magic_word;
+
+  /* read 'name' of subtitle */
+  name_length = GST_READ_UINT32_LE (map.data + 5 + 2);
+  GST_LOG_OBJECT (sub, "length of name: %u", name_length);
+  if (map.size <= 17 + name_length)
+    goto wrong_name_length;
+
+  name_utf8 =
+      g_convert ((gchar *) map.data + 11, name_length, "UTF-8", "UTF-16LE",
+      NULL, NULL, NULL);
+
+  if (name_utf8) {
+    GST_LOG_OBJECT (sub, "subtitle name: %s", name_utf8);
+    gst_avi_subtitle_title_tag (sub, name_utf8);
+    g_free (name_utf8);
+  }
+
+  /* next word must be 4 */
+  if (GST_READ_UINT16_LE (map.data + 11 + name_length) != 0x4)
+    goto wrong_fixed_word_2;
+
+  file_length = GST_READ_UINT32_LE (map.data + 13 + name_length);
+  GST_LOG_OBJECT (sub, "length srt/ssa file: %u", file_length);
+
+  if (map.size < (17 + name_length + file_length))
+    goto wrong_total_length;
+
+  /* store this, so we can send it again after a seek; note that we shouldn't
+   * assume all the remaining data in the chunk is subtitle data, there may
+   * be padding at the end for some reason, so only parse file_length bytes */
+  sub->subfile =
+      gst_avi_subtitle_extract_file (sub, buf, 17 + name_length, file_length);
+
+  if (sub->subfile == NULL)
+    goto extract_failed;
+
+  gst_buffer_unmap (buf, &map);
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+wrong_magic_word:
+  {
+    GST_ELEMENT_ERROR (sub, STREAM, DECODE, (NULL), ("Wrong magic word"));
+    gst_buffer_unmap (buf, &map);
+    return GST_FLOW_ERROR;
+  }
+wrong_name_length:
+  {
+    GST_ELEMENT_ERROR (sub, STREAM, DECODE, (NULL),
+        ("name doesn't fit in buffer (%" G_GSIZE_FORMAT " < %d)", map.size,
+            17 + name_length));
+    gst_buffer_unmap (buf, &map);
+    return GST_FLOW_ERROR;
+  }
+wrong_fixed_word_2:
+  {
+    GST_ELEMENT_ERROR (sub, STREAM, DECODE, (NULL),
+        ("wrong fixed word: expected %u, got %u", 4,
+            GST_READ_UINT16_LE (map.data + 11 + name_length)));
+    gst_buffer_unmap (buf, &map);
+    return GST_FLOW_ERROR;
+  }
+wrong_total_length:
+  {
+    GST_ELEMENT_ERROR (sub, STREAM, DECODE, (NULL),
+        ("buffer size is wrong: need %d bytes, have %" G_GSIZE_FORMAT " bytes",
+            17 + name_length + file_length, map.size));
+    gst_buffer_unmap (buf, &map);
+    return GST_FLOW_ERROR;
+  }
+extract_failed:
+  {
+    GST_ELEMENT_ERROR (sub, STREAM, DECODE, (NULL),
+        ("could not extract subtitles"));
+    gst_buffer_unmap (buf, &map);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstFlowReturn
+gst_avi_subtitle_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstAviSubtitle *sub = GST_AVI_SUBTITLE (parent);
+  GstFlowReturn ret;
+
+  if (sub->subfile != NULL) {
+    GST_WARNING_OBJECT (sub, "Got more buffers than expected, dropping");
+    ret = GST_FLOW_EOS;
+    goto done;
+  }
+
+  /* we expect exactly one buffer with the whole srt/ssa file in it */
+  ret = gst_avi_subtitle_parse_gab2_chunk (sub, buffer);
+  if (ret != GST_FLOW_OK)
+    goto done;
+
+  /* now push the subtitle data downstream */
+  ret = gst_pad_push (sub->src, gst_buffer_ref (sub->subfile));
+
+done:
+
+  gst_buffer_unref (buffer);
+  return ret;
+}
+
+static gboolean
+gst_avi_subtitle_send_event (GstElement * element, GstEvent * event)
+{
+  GstAviSubtitle *avisubtitle = GST_AVI_SUBTITLE (element);
+  gboolean ret = FALSE;
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
+    if (avisubtitle->subfile) {
+      if (gst_pad_push (avisubtitle->src,
+              gst_buffer_ref (avisubtitle->subfile)) == GST_FLOW_OK)
+        ret = TRUE;
+    }
+  }
+  gst_event_unref (event);
+  return ret;
+}
+
+static void
+gst_avi_subtitle_class_init (GstAviSubtitleClass * klass)
+{
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (avisubtitle_debug, "avisubtitle", 0,
+      "parse avi subtitle stream");
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_avi_subtitle_change_state);
+  gstelement_class->send_event =
+      GST_DEBUG_FUNCPTR (gst_avi_subtitle_send_event);
+
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class, &src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Avi subtitle parser", "Codec/Parser/Subtitle",
+      "Parse avi subtitle stream", "Thijs Vermeir <thijsvermeir@gmail.com>");
+}
+
+static void
+gst_avi_subtitle_init (GstAviSubtitle * self)
+{
+  GstCaps *caps;
+
+  self->src = gst_pad_new_from_static_template (&src_template, "src");
+  gst_element_add_pad (GST_ELEMENT (self), self->src);
+
+  self->sink = gst_pad_new_from_static_template (&sink_template, "sink");
+  gst_pad_set_chain_function (self->sink,
+      GST_DEBUG_FUNCPTR (gst_avi_subtitle_chain));
+
+  caps = gst_static_pad_template_get_caps (&src_template);
+  gst_pad_set_caps (self->src, caps);
+  gst_caps_unref (caps);
+
+  gst_pad_use_fixed_caps (self->src);
+  gst_element_add_pad (GST_ELEMENT (self), self->sink);
+
+  self->subfile = NULL;
+}
+
+static GstStateChangeReturn
+gst_avi_subtitle_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstAviSubtitle *sub = GST_AVI_SUBTITLE (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      if (sub->subfile) {
+        gst_buffer_unref (sub->subfile);
+        sub->subfile = NULL;
+      }
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
diff --git a/gst/avi/gstavisubtitle.h b/gst/avi/gstavisubtitle.h
new file mode 100644
index 0000000..0f8048e
--- /dev/null
+++ b/gst/avi/gstavisubtitle.h
@@ -0,0 +1,39 @@
+
+#ifndef __GSTAVISUBTITLE_H__
+#define __GSTAVISUBTITLE_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstAviSubtitle GstAviSubtitle;
+typedef struct _GstAviSubtitleClass GstAviSubtitleClass;
+
+#define GST_TYPE_AVI_SUBTITLE (gst_avi_subtitle_get_type ())
+#define GST_AVI_SUBTITLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AVI_SUBTITLE, GstAviSubtitle))
+#define GST_AVI_SUBTITLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_AVI_SUBTITLE, GstAviSubtitleClass))
+#define GST_IS_AVI_SUBTITLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AVI_SUBTITLE))
+#define GST_IS_AVI_SUBTITLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AVI_SUBTITLE))
+#define GST_AVI_SUBTITLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_AVI_SUBTITLE, GstAviSubtitleClass))
+
+GType gst_avi_subtitle_get_type (void);
+
+struct _GstAviSubtitle
+{
+  GstElement parent;
+
+  GstPad    *src;
+  GstPad    *sink;
+
+  GstBuffer *subfile;  /* the complete subtitle file in one buffer */
+};
+
+struct _GstAviSubtitleClass
+{
+  GstElementClass parent;
+};
+
+G_END_DECLS
+#endif
diff --git a/gst/avi/meson.build b/gst/avi/meson.build
new file mode 100644
index 0000000..64fd1c4
--- /dev/null
+++ b/gst/avi/meson.build
@@ -0,0 +1,15 @@
+avi_sources = [
+  'gstavi.c',
+  'gstavimux.c',
+  'gstavidemux.c',
+  'gstavisubtitle.c'
+]
+
+gstavi = library('gstavi',
+  avi_sources,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc, libsinc],
+  dependencies : [gst_dep, gstriff_dep, gstaudio_dep, gstvideo_dep, gsttag_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/cutter/Makefile.am b/gst/cutter/Makefile.am
new file mode 100644
index 0000000..3d5677e
--- /dev/null
+++ b/gst/cutter/Makefile.am
@@ -0,0 +1,10 @@
+plugin_LTLIBRARIES = libgstcutter.la
+
+libgstcutter_la_SOURCES = gstcutter.c
+libgstcutter_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstcutter_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(GST_BASE_LIBS) $(LIBM)
+libgstcutter_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstcutter.h filter.func
+
+EXTRA_DIST = README
diff --git a/gst/cutter/README b/gst/cutter/README
new file mode 100644
index 0000000..fc0975e
--- /dev/null
+++ b/gst/cutter/README
@@ -0,0 +1,38 @@
+cutter plugin by thomas <thomas@apestaart.org>
+
+SYNOPSIS
+
+This plugin emits signals when RMS level of audio signal crosses a
+threshold for a given amount of time.  
+
+As soon as the buffer's RMS is greater than the threshold value, the plugin fires a CUT_START signal.
+
+When the buffer's RMS level drops below the threshold value for a consecutive run length longer than the given runlength, it sends a CUT_STOP signal.
+
+When a pre-recording buffer is used, the plugin will delay throughput of data when it's in "silent" mode for a maximum length equal to the pre-recording buffer length.  As soon as the input level crosses the threshold level, this pre-recorded buffer is flushed to the src pad (so you can actually record the audio just before the threshold crossing) after sending the signal.
+
+ARGUMENTS
+
+GstCutter::threshold
+	level (between 0 and 1) of threshold
+GstCutter::threshold_dB
+	level of threshold in dB (between -inf and 0)
+GstCutter::runlength
+	minimum length (in seconds) before plugin sends cut_stop signal
+GstCutter::prelength
+        length of pre-recording buffer
+        
+SIGNALS
+
+	CUT_START
+	gets sent when the level of the signal goes above threshold level
+	CUT_STOP
+	gets sent when the level of the signal has been below the
+	threshold level for a number of consecutive iterations of which
+	the cumulative length is more than the runlength
+
+LIMITATIONS
+
+	* RMS value is calculated over the whole data buffer, so
+	  the time resolution is limited to the buffer length
+	* RMS value is calculated over all of the channels combined
diff --git a/gst/cutter/filter.func b/gst/cutter/filter.func
new file mode 100644
index 0000000..bdbe566
--- /dev/null
+++ b/gst/cutter/filter.func
@@ -0,0 +1,16 @@
+{
+  guint j;
+  register double squaresum = 0.0;
+
+  /*
+   * process data here  
+   * input sample data enters in *in_data as 8 or 16 bit data
+   * samples for left and right channel are interleaved
+   */
+
+  for (j = 0; j < num_samples; j++) 
+     squaresum += data[j] * data[j];
+
+  return (squaresum / (float) num_samples);
+}
+
diff --git a/gst/cutter/gstcutter.c b/gst/cutter/gstcutter.c
new file mode 100644
index 0000000..b13ddf6
--- /dev/null
+++ b/gst/cutter/gstcutter.c
@@ -0,0 +1,512 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2002,2003,2005
+ *           Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-cutter
+ *
+ * Analyses the audio signal for periods of silence. The start and end of
+ * silence is signalled by bus messages named
+ * <classname>&quot;cutter&quot;</classname>.
+ * The message's structure contains two fields:
+ * <itemizedlist>
+ * <listitem>
+ *   <para>
+ *   #GstClockTime
+ *   <classname>&quot;timestamp&quot;</classname>:
+ *   the timestamp of the buffer that triggered the message.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   gboolean
+ *   <classname>&quot;above&quot;</classname>:
+ *   %TRUE for begin of silence and %FALSE for end of silence.
+ *   </para>
+ * </listitem>
+ * </itemizedlist>
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -m filesrc location=foo.ogg ! decodebin ! audioconvert ! cutter ! autoaudiosink
+ * ]| Show cut messages.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include "gstcutter.h"
+#include "math.h"
+
+GST_DEBUG_CATEGORY_STATIC (cutter_debug);
+#define GST_CAT_DEFAULT cutter_debug
+
+#define CUTTER_DEFAULT_THRESHOLD_LEVEL    0.1
+#define CUTTER_DEFAULT_THRESHOLD_LENGTH  (500 * GST_MSECOND)
+#define CUTTER_DEFAULT_PRE_LENGTH        (200 * GST_MSECOND)
+
+static GstStaticPadTemplate cutter_src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) { S8," GST_AUDIO_NE (S16) " }, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ], "
+        "layout = (string) interleaved")
+    );
+
+static GstStaticPadTemplate cutter_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) { S8," GST_AUDIO_NE (S16) " }, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ], "
+        "layout = (string) interleaved")
+    );
+
+enum
+{
+  PROP_0,
+  PROP_THRESHOLD,
+  PROP_THRESHOLD_DB,
+  PROP_RUN_LENGTH,
+  PROP_PRE_LENGTH,
+  PROP_LEAKY
+};
+
+#define gst_cutter_parent_class parent_class
+G_DEFINE_TYPE (GstCutter, gst_cutter, GST_TYPE_ELEMENT);
+
+static GstStateChangeReturn
+gst_cutter_change_state (GstElement * element, GstStateChange transition);
+
+static void gst_cutter_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_cutter_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_cutter_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static GstFlowReturn gst_cutter_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer);
+
+static void
+gst_cutter_class_init (GstCutterClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_cutter_set_property;
+  gobject_class->get_property = gst_cutter_get_property;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_THRESHOLD,
+      g_param_spec_double ("threshold", "Threshold",
+          "Volume threshold before trigger",
+          -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_THRESHOLD_DB,
+      g_param_spec_double ("threshold-dB", "Threshold (dB)",
+          "Volume threshold before trigger (in dB)",
+          -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_RUN_LENGTH,
+      g_param_spec_uint64 ("run-length", "Run length",
+          "Length of drop below threshold before cut_stop (in nanoseconds)",
+          0, G_MAXUINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PRE_LENGTH,
+      g_param_spec_uint64 ("pre-length", "Pre-recording buffer length",
+          "Length of pre-recording buffer (in nanoseconds)",
+          0, G_MAXUINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LEAKY,
+      g_param_spec_boolean ("leaky", "Leaky",
+          "do we leak buffers when below threshold ?",
+          FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  GST_DEBUG_CATEGORY_INIT (cutter_debug, "cutter", 0, "Audio cutting");
+
+  gst_element_class_add_static_pad_template (element_class,
+      &cutter_src_factory);
+  gst_element_class_add_static_pad_template (element_class,
+      &cutter_sink_factory);
+  gst_element_class_set_static_metadata (element_class, "Audio cutter",
+      "Filter/Editor/Audio", "Audio Cutter to split audio into non-silent bits",
+      "Thomas Vander Stichele <thomas at apestaart dot org>");
+  element_class->change_state = gst_cutter_change_state;
+}
+
+static void
+gst_cutter_init (GstCutter * filter)
+{
+  filter->sinkpad =
+      gst_pad_new_from_static_template (&cutter_sink_factory, "sink");
+  gst_pad_set_chain_function (filter->sinkpad, gst_cutter_chain);
+  gst_pad_set_event_function (filter->sinkpad, gst_cutter_event);
+  gst_pad_use_fixed_caps (filter->sinkpad);
+  gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
+
+  filter->srcpad =
+      gst_pad_new_from_static_template (&cutter_src_factory, "src");
+  gst_pad_use_fixed_caps (filter->srcpad);
+  gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
+
+  filter->threshold_level = CUTTER_DEFAULT_THRESHOLD_LEVEL;
+  filter->threshold_length = CUTTER_DEFAULT_THRESHOLD_LENGTH;
+  filter->silent_run_length = 0 * GST_SECOND;
+  filter->silent = TRUE;
+  filter->silent_prev = FALSE;  /* previous value of silent */
+
+  filter->pre_length = CUTTER_DEFAULT_PRE_LENGTH;
+  filter->pre_run_length = 0 * GST_SECOND;
+  filter->pre_buffer = NULL;
+  filter->leaky = FALSE;
+}
+
+static GstMessage *
+gst_cutter_message_new (GstCutter * c, gboolean above, GstClockTime timestamp)
+{
+  GstStructure *s;
+
+  s = gst_structure_new ("cutter",
+      "above", G_TYPE_BOOLEAN, above,
+      "timestamp", GST_TYPE_CLOCK_TIME, timestamp, NULL);
+
+  return gst_message_new_element (GST_OBJECT (c), s);
+}
+
+/* Calculate the Normalized Cumulative Square over a buffer of the given type
+ * and over all channels combined */
+
+#define DEFINE_CUTTER_CALCULATOR(TYPE, RESOLUTION)                            \
+static void inline                                                            \
+gst_cutter_calculate_##TYPE (TYPE * in, guint num,                            \
+                            double *NCS)                                      \
+{                                                                             \
+  register int j;                                                             \
+  double squaresum = 0.0;           /* square sum of the integer samples */   \
+  register double square = 0.0;     /* Square */                              \
+  gdouble normalizer;               /* divisor to get a [-1.0, 1.0] range */  \
+                                                                              \
+  *NCS = 0.0;                       /* Normalized Cumulative Square */        \
+                                                                              \
+  normalizer = (double) (1 << (RESOLUTION * 2));                              \
+                                                                              \
+  for (j = 0; j < num; j++)                                                   \
+  {                                                                           \
+    square = ((double) in[j]) * in[j];                                        \
+    squaresum += square;                                                      \
+  }                                                                           \
+                                                                              \
+                                                                              \
+  *NCS = squaresum / normalizer;                                              \
+}
+
+DEFINE_CUTTER_CALCULATOR (gint16, 15);
+DEFINE_CUTTER_CALCULATOR (gint8, 7);
+
+static gboolean
+gst_cutter_setcaps (GstCutter * filter, GstCaps * caps)
+{
+  GstAudioInfo info;
+
+  if (!gst_audio_info_from_caps (&info, caps))
+    return FALSE;
+
+  filter->info = info;
+
+  return gst_pad_set_caps (filter->srcpad, caps);
+}
+
+static GstStateChangeReturn
+gst_cutter_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstCutter *filter = GST_CUTTER (element);
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      g_list_free_full (filter->pre_buffer, (GDestroyNotify) gst_buffer_unref);
+      filter->pre_buffer = NULL;
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+static gboolean
+gst_cutter_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  gboolean ret;
+  GstCutter *filter;
+
+  filter = GST_CUTTER (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      ret = gst_cutter_setcaps (filter, caps);
+      gst_event_unref (event);
+      break;
+    }
+    default:
+      ret = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+  return ret;
+}
+
+static GstFlowReturn
+gst_cutter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstCutter *filter;
+  GstMapInfo map;
+  gint16 *in_data;
+  gint bpf, rate;
+  gsize in_size;
+  guint num_samples;
+  gdouble NCS = 0.0;            /* Normalized Cumulative Square of buffer */
+  gdouble RMS = 0.0;            /* RMS of signal in buffer */
+  gdouble NMS = 0.0;            /* Normalized Mean Square of buffer */
+  GstBuffer *prebuf;            /* pointer to a prebuffer element */
+  GstClockTime duration;
+
+  filter = GST_CUTTER (parent);
+
+  if (GST_AUDIO_INFO_FORMAT (&filter->info) == GST_AUDIO_FORMAT_UNKNOWN)
+    goto not_negotiated;
+
+  bpf = GST_AUDIO_INFO_BPF (&filter->info);
+  rate = GST_AUDIO_INFO_RATE (&filter->info);
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  in_data = (gint16 *) map.data;
+  in_size = map.size;
+
+  GST_LOG_OBJECT (filter, "length of prerec buffer: %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (filter->pre_run_length));
+
+  /* calculate mean square value on buffer */
+  switch (GST_AUDIO_INFO_FORMAT (&filter->info)) {
+    case GST_AUDIO_FORMAT_S16:
+      num_samples = in_size / 2;
+      gst_cutter_calculate_gint16 (in_data, num_samples, &NCS);
+      NMS = NCS / num_samples;
+      break;
+    case GST_AUDIO_FORMAT_S8:
+      num_samples = in_size;
+      gst_cutter_calculate_gint8 ((gint8 *) in_data, num_samples, &NCS);
+      NMS = NCS / num_samples;
+      break;
+    default:
+      /* this shouldn't happen */
+      g_warning ("no mean square function for format");
+      break;
+  }
+
+  gst_buffer_unmap (buf, &map);
+
+  filter->silent_prev = filter->silent;
+
+  duration = gst_util_uint64_scale (in_size / bpf, GST_SECOND, rate);
+
+  RMS = sqrt (NMS);
+  /* if RMS below threshold, add buffer length to silent run length count
+   * if not, reset
+   */
+  GST_LOG_OBJECT (filter, "buffer stats: NMS %f, RMS %f, audio length %f", NMS,
+      RMS, gst_guint64_to_gdouble (duration));
+
+  if (RMS < filter->threshold_level)
+    filter->silent_run_length += gst_guint64_to_gdouble (duration);
+  else {
+    filter->silent_run_length = 0 * GST_SECOND;
+    filter->silent = FALSE;
+  }
+
+  if (filter->silent_run_length > filter->threshold_length)
+    /* it has been silent long enough, flag it */
+    filter->silent = TRUE;
+
+  /* has the silent status changed ? if so, send right signal
+   * and, if from silent -> not silent, flush pre_record buffer
+   */
+  if (filter->silent != filter->silent_prev) {
+    if (filter->silent) {
+      GstMessage *m =
+          gst_cutter_message_new (filter, FALSE, GST_BUFFER_TIMESTAMP (buf));
+      GST_DEBUG_OBJECT (filter, "signaling CUT_STOP");
+      gst_element_post_message (GST_ELEMENT (filter), m);
+    } else {
+      gint count = 0;
+      GstMessage *m =
+          gst_cutter_message_new (filter, TRUE, GST_BUFFER_TIMESTAMP (buf));
+
+      GST_DEBUG_OBJECT (filter, "signaling CUT_START");
+      gst_element_post_message (GST_ELEMENT (filter), m);
+      /* first of all, flush current buffer */
+      GST_DEBUG_OBJECT (filter, "flushing buffer of length %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (filter->pre_run_length));
+
+      while (filter->pre_buffer) {
+        prebuf = (g_list_first (filter->pre_buffer))->data;
+        filter->pre_buffer = g_list_remove (filter->pre_buffer, prebuf);
+        gst_pad_push (filter->srcpad, prebuf);
+        ++count;
+      }
+      GST_DEBUG_OBJECT (filter, "flushed %d buffers", count);
+      filter->pre_run_length = 0 * GST_SECOND;
+    }
+  }
+  /* now check if we have to send the new buffer to the internal buffer cache
+   * or to the srcpad */
+  if (filter->silent) {
+    filter->pre_buffer = g_list_append (filter->pre_buffer, buf);
+    filter->pre_run_length += gst_guint64_to_gdouble (duration);
+
+    while (filter->pre_run_length > filter->pre_length) {
+      GstClockTime pduration;
+      gsize psize;
+
+      prebuf = (g_list_first (filter->pre_buffer))->data;
+      g_assert (GST_IS_BUFFER (prebuf));
+
+      psize = gst_buffer_get_size (prebuf);
+      pduration = gst_util_uint64_scale (psize / bpf, GST_SECOND, rate);
+
+      filter->pre_buffer = g_list_remove (filter->pre_buffer, prebuf);
+      filter->pre_run_length -= gst_guint64_to_gdouble (pduration);
+
+      /* only pass buffers if we don't leak */
+      if (!filter->leaky)
+        ret = gst_pad_push (filter->srcpad, prebuf);
+      else
+        gst_buffer_unref (prebuf);
+    }
+  } else
+    ret = gst_pad_push (filter->srcpad, buf);
+
+  return ret;
+
+  /* ERRORS */
+not_negotiated:
+  {
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+}
+
+static void
+gst_cutter_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstCutter *filter;
+
+  g_return_if_fail (GST_IS_CUTTER (object));
+  filter = GST_CUTTER (object);
+
+  switch (prop_id) {
+    case PROP_THRESHOLD:
+      filter->threshold_level = g_value_get_double (value);
+      GST_DEBUG ("DEBUG: set threshold level to %f", filter->threshold_level);
+      break;
+    case PROP_THRESHOLD_DB:
+      /* set the level given in dB
+       * value in dB = 20 * log (value)
+       * values in dB < 0 result in values between 0 and 1
+       */
+      filter->threshold_level = pow (10, g_value_get_double (value) / 20);
+      GST_DEBUG_OBJECT (filter, "set threshold level to %f",
+          filter->threshold_level);
+      break;
+    case PROP_RUN_LENGTH:
+      /* set the minimum length of the silent run required */
+      filter->threshold_length =
+          gst_guint64_to_gdouble (g_value_get_uint64 (value));
+      break;
+    case PROP_PRE_LENGTH:
+      /* set the length of the pre-record block */
+      filter->pre_length = gst_guint64_to_gdouble (g_value_get_uint64 (value));
+      break;
+    case PROP_LEAKY:
+      /* set if the pre-record buffer is leaky or not */
+      filter->leaky = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_cutter_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstCutter *filter;
+
+  g_return_if_fail (GST_IS_CUTTER (object));
+  filter = GST_CUTTER (object);
+
+  switch (prop_id) {
+    case PROP_RUN_LENGTH:
+      g_value_set_uint64 (value, filter->threshold_length);
+      break;
+    case PROP_THRESHOLD:
+      g_value_set_double (value, filter->threshold_level);
+      break;
+    case PROP_THRESHOLD_DB:
+      g_value_set_double (value, 20 * log (filter->threshold_level));
+      break;
+    case PROP_PRE_LENGTH:
+      g_value_set_uint64 (value, filter->pre_length);
+      break;
+    case PROP_LEAKY:
+      g_value_set_boolean (value, filter->leaky);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "cutter", GST_RANK_NONE, GST_TYPE_CUTTER))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    cutter,
+    "Audio Cutter to split audio into non-silent bits",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/cutter/gstcutter.h b/gst/cutter/gstcutter.h
new file mode 100644
index 0000000..3875f8f
--- /dev/null
+++ b/gst/cutter/gstcutter.h
@@ -0,0 +1,83 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_CUTTER_H__
+#define __GST_CUTTER_H__
+
+
+#include <gst/gst.h>
+/* #include <gst/meta/audioraw.h> */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_CUTTER \
+  (gst_cutter_get_type())
+#define GST_CUTTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CUTTER,GstCutter))
+#define GST_CUTTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CUTTER,GstCutterClass))
+#define GST_IS_CUTTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CUTTER))
+#define GST_IS_CUTTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CUTTER))
+
+typedef struct _GstCutter GstCutter;
+typedef struct _GstCutterClass GstCutterClass;
+
+struct _GstCutter
+{
+  GstElement element;
+
+  GstPad *sinkpad, *srcpad;
+
+  double threshold_level;       /* level below which to cut */
+  double threshold_length;      /* how long signal has to remain
+                                 * below this level before cutting */
+  double silent_run_length;     /* how long has it been below threshold ? */
+  gboolean silent;
+  gboolean silent_prev;
+
+  double pre_length;            /* how long can the pre-record buffer be ? */
+  double pre_run_length;        /* how long is it currently ? */
+  GList *pre_buffer;            /* list of GstBuffers in pre-record buffer */
+  gboolean leaky;               /* do we leak an overflowing prebuffer ? */
+
+  GstAudioInfo info;
+};
+
+struct _GstCutterClass
+{
+  GstElementClass parent_class;
+  void (*cut_start) (GstCutter* filter);
+  void (*cut_stop) (GstCutter* filter);
+};
+
+GType gst_cutter_get_type (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_STEREO_H__ */
diff --git a/gst/cutter/meson.build b/gst/cutter/meson.build
new file mode 100644
index 0000000..3f580bd
--- /dev/null
+++ b/gst/cutter/meson.build
@@ -0,0 +1,7 @@
+gstcutter = library('gstcutter', 'gstcutter.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstbase_dep, gstaudio_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/debugutils/Makefile.am b/gst/debugutils/Makefile.am
new file mode 100644
index 0000000..31e9c8c
--- /dev/null
+++ b/gst/debugutils/Makefile.am
@@ -0,0 +1,39 @@
+
+plugin_LTLIBRARIES = libgstdebug.la libgstnavigationtest.la 
+
+noinst_HEADERS = \
+	cpureport.h \
+	gstcapsdebug.h \
+	gstcapssetter.h \
+	gstnavigationtest.h \
+	gstnavseek.h \
+	gstpushfilesrc.h \
+	gsttaginject.h \
+	progressreport.h \
+	tests.h
+
+libgstnavigationtest_la_SOURCES = gstnavigationtest.c
+libgstnavigationtest_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
+				 $(GST_PLUGINS_BASE_CFLAGS)
+libgstnavigationtest_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) \
+	$(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_API_VERSION@ $(LIBM)
+libgstnavigationtest_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+libgstdebug_la_SOURCES = \
+	gstdebug.c \
+	breakmydata.c \
+	gstcapssetter.c \
+	gstnavseek.c \
+	gstpushfilesrc.c \
+	gsttaginject.c \
+	rndbuffersize.c \
+	progressreport.c \
+	tests.c \
+	cpureport.c \
+	testplugin.c
+
+#	gstcapsdebug.c
+
+libgstdebug_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS)
+libgstdebug_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS)
+libgstdebug_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
diff --git a/gst/debugutils/breakmydata.c b/gst/debugutils/breakmydata.c
new file mode 100644
index 0000000..3722d30
--- /dev/null
+++ b/gst/debugutils/breakmydata.c
@@ -0,0 +1,293 @@
+/* GStreamer
+ * Copyright (C) 2004 Benjamin Otte <otte@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-breakmydata
+ *
+ * This element modifies the contents of the buffer it is passed randomly
+ * according to the parameters set.
+ * It otherwise acts as an identity.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_break_my_data_debug);
+#define GST_CAT_DEFAULT gst_break_my_data_debug
+
+#define GST_TYPE_BREAK_MY_DATA \
+  (gst_break_my_data_get_type())
+#define GST_BREAK_MY_DATA(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BREAK_MY_DATA,GstBreakMyData))
+#define GST_BREAK_MY_DATA_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BREAK_MY_DATA,GstBreakMyDataClass))
+#define GST_IS_BREAK_MY_DATA(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BREAK_MY_DATA))
+#define GST_IS_BREAK_MY_DATA_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BREAK_MY_DATA))
+
+GType gst_break_my_data_get_type (void);
+
+enum
+{
+  PROP_0,
+  PROP_SEED,
+  PROP_SET_TO,
+  PROP_SKIP,
+  PROP_PROBABILITY
+};
+
+typedef struct _GstBreakMyData GstBreakMyData;
+typedef struct _GstBreakMyDataClass GstBreakMyDataClass;
+
+struct _GstBreakMyData
+{
+  GstBaseTransform basetransform;
+
+  GRand *rand;
+  guint skipped;
+
+  guint32 seed;
+  gint set;
+  guint skip;
+  gdouble probability;
+};
+
+struct _GstBreakMyDataClass
+{
+  GstBaseTransformClass parent_class;
+};
+
+static void gst_break_my_data_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_break_my_data_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+static GstFlowReturn gst_break_my_data_transform_ip (GstBaseTransform * trans,
+    GstBuffer * buf);
+static gboolean gst_break_my_data_stop (GstBaseTransform * trans);
+static gboolean gst_break_my_data_start (GstBaseTransform * trans);
+
+GstStaticPadTemplate bmd_src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+GstStaticPadTemplate bmd_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+#define gst_break_my_data_parent_class parent_class
+G_DEFINE_TYPE (GstBreakMyData, gst_break_my_data, GST_TYPE_BASE_TRANSFORM);
+
+
+static void
+gst_break_my_data_class_init (GstBreakMyDataClass * klass)
+{
+  GstBaseTransformClass *gstbasetrans_class;
+  GstElementClass *gstelement_class;
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gstelement_class = GST_ELEMENT_CLASS (klass);
+  gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (gst_break_my_data_debug, "breakmydata", 0,
+      "debugging category for breakmydata element");
+
+  gobject_class->set_property = gst_break_my_data_set_property;
+  gobject_class->get_property = gst_break_my_data_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_SEED,
+      g_param_spec_uint ("seed", "seed",
+          "seed for randomness (initialized when going from READY to PAUSED)",
+          0, G_MAXUINT32, 0,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_SET_TO,
+      g_param_spec_int ("set-to", "set-to",
+          "set changed bytes to this value (-1 means random value",
+          -1, G_MAXUINT8, -1,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_SKIP,
+      g_param_spec_uint ("skip", "skip",
+          "amount of bytes skipped at the beginning of stream",
+          0, G_MAXUINT, 0,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_PROBABILITY,
+      g_param_spec_double ("probability", "probability",
+          "probability for each byte in the buffer to be changed", 0.0, 1.0,
+          0.0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &bmd_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &bmd_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "Break my data",
+      "Testing",
+      "randomly change data in the stream", "Benjamin Otte <otte@gnome>");
+
+  gstbasetrans_class->transform_ip =
+      GST_DEBUG_FUNCPTR (gst_break_my_data_transform_ip);
+  gstbasetrans_class->start = GST_DEBUG_FUNCPTR (gst_break_my_data_start);
+  gstbasetrans_class->stop = GST_DEBUG_FUNCPTR (gst_break_my_data_stop);
+}
+
+static void
+gst_break_my_data_init (GstBreakMyData * bmd)
+{
+  gst_base_transform_set_in_place (GST_BASE_TRANSFORM (bmd), TRUE);
+}
+
+static void
+gst_break_my_data_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstBreakMyData *bmd = GST_BREAK_MY_DATA (object);
+
+  GST_OBJECT_LOCK (bmd);
+
+  switch (prop_id) {
+    case PROP_SEED:
+      bmd->seed = g_value_get_uint (value);
+      break;
+    case PROP_SET_TO:
+      bmd->set = g_value_get_int (value);
+      break;
+    case PROP_SKIP:
+      bmd->skip = g_value_get_uint (value);
+      break;
+    case PROP_PROBABILITY:
+      bmd->probability = g_value_get_double (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  GST_OBJECT_UNLOCK (bmd);
+}
+
+static void
+gst_break_my_data_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstBreakMyData *bmd = GST_BREAK_MY_DATA (object);
+
+  GST_OBJECT_LOCK (bmd);
+
+  switch (prop_id) {
+    case PROP_SEED:
+      g_value_set_uint (value, bmd->seed);
+      break;
+    case PROP_SET_TO:
+      g_value_set_int (value, bmd->set);
+      break;
+    case PROP_SKIP:
+      g_value_set_uint (value, bmd->skip);
+      break;
+    case PROP_PROBABILITY:
+      g_value_set_double (value, bmd->probability);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  GST_OBJECT_UNLOCK (bmd);
+}
+
+static GstFlowReturn
+gst_break_my_data_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
+{
+  GstBreakMyData *bmd = GST_BREAK_MY_DATA (trans);
+  GstMapInfo map;
+  gsize i;
+
+  g_return_val_if_fail (gst_buffer_is_writable (buf), GST_FLOW_ERROR);
+
+  GST_OBJECT_LOCK (bmd);
+
+  if (bmd->skipped < bmd->skip) {
+    i = bmd->skip - bmd->skipped;
+  } else {
+    i = 0;
+  }
+
+  gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+
+  GST_LOG_OBJECT (bmd,
+      "got buffer %p (size %" G_GSIZE_FORMAT ", timestamp %" G_GUINT64_FORMAT
+      ", offset %" G_GUINT64_FORMAT "", buf, map.size,
+      GST_BUFFER_TIMESTAMP (buf), GST_BUFFER_OFFSET (buf));
+
+  for (; i < map.size; i++) {
+    if (g_rand_double_range (bmd->rand, 0, 1.0) <= bmd->probability) {
+      guint8 new;
+
+      if (bmd->set < 0) {
+        new = g_rand_int_range (bmd->rand, 0, 256);
+      } else {
+        new = bmd->set;
+      }
+      GST_INFO_OBJECT (bmd,
+          "changing byte %" G_GSIZE_FORMAT " from 0x%02X to 0x%02X", i,
+          (guint) GST_READ_UINT8 (map.data + i), (guint) ((guint8) new));
+      map.data[i] = new;
+    }
+  }
+  /* don't overflow */
+  bmd->skipped += MIN (G_MAXUINT - bmd->skipped, map.size);
+
+  gst_buffer_unmap (buf, &map);
+
+  GST_OBJECT_UNLOCK (bmd);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_break_my_data_start (GstBaseTransform * trans)
+{
+  GstBreakMyData *bmd = GST_BREAK_MY_DATA (trans);
+
+  GST_OBJECT_LOCK (bmd);
+  bmd->rand = g_rand_new_with_seed (bmd->seed);
+  bmd->skipped = 0;
+  GST_OBJECT_UNLOCK (bmd);
+
+  return TRUE;
+}
+
+static gboolean
+gst_break_my_data_stop (GstBaseTransform * trans)
+{
+  GstBreakMyData *bmd = GST_BREAK_MY_DATA (trans);
+
+  GST_OBJECT_LOCK (bmd);
+  g_rand_free (bmd->rand);
+  bmd->rand = NULL;
+  GST_OBJECT_UNLOCK (bmd);
+
+  return TRUE;
+}
diff --git a/gst/debugutils/cpureport.c b/gst/debugutils/cpureport.c
new file mode 100644
index 0000000..f61c38e
--- /dev/null
+++ b/gst/debugutils/cpureport.c
@@ -0,0 +1,149 @@
+/* GStreamer Cpu Report Element
+ * Copyright (C) <2010> Zaheer Abbas Merali <zaheerabbas merali org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+
+#include "cpureport.h"
+
+
+enum
+{
+  PROP_0,
+};
+
+GstStaticPadTemplate cpu_report_src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+GstStaticPadTemplate cpu_report_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static GstFlowReturn gst_cpu_report_transform_ip (GstBaseTransform * trans,
+    GstBuffer * buf);
+
+static gboolean gst_cpu_report_start (GstBaseTransform * trans);
+static gboolean gst_cpu_report_stop (GstBaseTransform * trans);
+
+#define gst_cpu_report_parent_class parent_class
+G_DEFINE_TYPE (GstCpuReport, gst_cpu_report, GST_TYPE_BASE_TRANSFORM);
+
+static void
+gst_cpu_report_finalize (GObject * obj)
+{
+  G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gst_cpu_report_class_init (GstCpuReportClass * g_class)
+{
+  GstBaseTransformClass *gstbasetrans_class;
+  GstElementClass *element_class;
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (g_class);
+  element_class = GST_ELEMENT_CLASS (g_class);
+  gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (g_class);
+
+  gobject_class->finalize = gst_cpu_report_finalize;
+
+  gst_element_class_add_static_pad_template (element_class,
+      &cpu_report_sink_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &cpu_report_src_template);
+
+  gst_element_class_set_static_metadata (element_class, "CPU report",
+      "Testing",
+      "Post cpu usage information every buffer",
+      "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
+
+  gstbasetrans_class->transform_ip =
+      GST_DEBUG_FUNCPTR (gst_cpu_report_transform_ip);
+  gstbasetrans_class->start = GST_DEBUG_FUNCPTR (gst_cpu_report_start);
+  gstbasetrans_class->stop = GST_DEBUG_FUNCPTR (gst_cpu_report_stop);
+}
+
+static void
+gst_cpu_report_init (GstCpuReport * report)
+{
+  gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (report), TRUE);
+
+}
+
+static GstFlowReturn
+gst_cpu_report_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
+{
+  GstCpuReport *filter;
+  GTimeVal cur_time;
+  clock_t cur_cpu_time;
+  GstMessage *msg;
+  GstStructure *s;
+  gint64 time_taken;
+
+
+  g_get_current_time (&cur_time);
+  cur_cpu_time = clock ();
+
+  filter = GST_CPU_REPORT (trans);
+
+
+  time_taken = GST_TIMEVAL_TO_TIME (cur_time) -
+      GST_TIMEVAL_TO_TIME (filter->last_time);
+
+  s = gst_structure_new ("cpu-report", "cpu-time", G_TYPE_DOUBLE,
+      ((gdouble) (cur_cpu_time - filter->last_cpu_time)),
+      "actual-time", G_TYPE_INT64, time_taken, "buffer-time", G_TYPE_INT64,
+      GST_BUFFER_TIMESTAMP (buf), NULL);
+  msg = gst_message_new_element (GST_OBJECT_CAST (filter), s);
+  gst_element_post_message (GST_ELEMENT_CAST (filter), msg);
+  filter->last_time = cur_time;
+  filter->last_cpu_time = cur_cpu_time;
+
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_cpu_report_start (GstBaseTransform * trans)
+{
+  GstCpuReport *filter;
+
+  filter = GST_CPU_REPORT (trans);
+
+  g_get_current_time (&filter->last_time);
+  filter->start_time = filter->last_time;
+  filter->last_cpu_time = clock ();
+  return TRUE;
+}
+
+static gboolean
+gst_cpu_report_stop (GstBaseTransform * trans)
+{
+  /* anything we should be doing here? */
+  return TRUE;
+}
diff --git a/gst/debugutils/cpureport.h b/gst/debugutils/cpureport.h
new file mode 100644
index 0000000..3505559
--- /dev/null
+++ b/gst/debugutils/cpureport.h
@@ -0,0 +1,58 @@
+/* GStreamer CPU Report Element
+ * Copyright (C) <2010> Zaheer Abbas Merali <zaheerabbas merali org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_CPU_REPORT_H__
+#define __GST_CPU_REPORT_H__
+
+#include <time.h>
+
+#include <gst/base/gstbasetransform.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_CPU_REPORT \
+  (gst_cpu_report_get_type())
+#define GST_CPU_REPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CPU_REPORT,GstCpuReport))
+#define GST_CPU_REPORT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CPU_REPORT,GstCpuReportClass))
+#define GST_IS_CPU_REPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CPU_REPORT))
+#define GST_IS_CPU_REPORT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CPU_REPORT))
+typedef struct _GstCpuReport GstCpuReport;
+typedef struct _GstCpuReportClass GstCpuReportClass;
+
+struct _GstCpuReport
+{
+  GstBaseTransform basetransform;
+
+  GTimeVal start_time;
+  GTimeVal last_time;
+  clock_t last_cpu_time;
+};
+
+struct _GstCpuReportClass
+{
+  GstBaseTransformClass parent_class;
+};
+
+GType gst_cpu_report_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_CPU_REPORT_H__ */
diff --git a/gst/debugutils/gstcapsdebug.c b/gst/debugutils/gstcapsdebug.c
new file mode 100644
index 0000000..c2bc551
--- /dev/null
+++ b/gst/debugutils/gstcapsdebug.c
@@ -0,0 +1,258 @@
+/* GStreamer
+ * Copyright (C) 2010 David Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/gst.h>
+#include "gstcapsdebug.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_caps_debug_debug);
+#define GST_CAT_DEFAULT gst_caps_debug_debug
+
+/* prototypes */
+
+
+static void gst_caps_debug_dispose (GObject * object);
+static void gst_caps_debug_finalize (GObject * object);
+
+static GstFlowReturn gst_caps_debug_sink_chain (GstPad * pad,
+    GstBuffer * buffer);
+static GstCaps *gst_caps_debug_getcaps (GstPad * pad);
+static gboolean gst_caps_debug_acceptcaps (GstPad * pad, GstCaps * caps);
+static GstFlowReturn gst_caps_debug_bufferalloc (GstPad * pad,
+    guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
+
+static GstStateChangeReturn
+gst_caps_debug_change_state (GstElement * element, GstStateChange transition);
+
+/* pad templates */
+
+static GstStaticPadTemplate gst_caps_debug_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate gst_caps_debug_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+/* class initialization */
+
+#define gst_caps_debug_parent_class parent_class
+G_DEFINE_TYPE (GstCapsDebug, gst_caps_debug, GST_TYPE_ELEMENT);
+
+static void
+gst_caps_debug_class_init (GstCapsDebugClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->dispose = gst_caps_debug_dispose;
+  gobject_class->finalize = gst_caps_debug_finalize;
+  element_class->change_state = GST_DEBUG_FUNCPTR (gst_caps_debug_change_state);
+
+  GST_DEBUG_CATEGORY_INIT (gst_caps_debug_debug, "capsdebug", 0,
+      "debug category for capsdebug element");
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_caps_debug_src_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_caps_debug_sink_template);
+
+  gst_element_class_set_static_metadata (element_class, "Caps debug",
+      "Generic", "Debug caps negotiation", "David Schleef <ds@schleef.org>");
+}
+
+static void
+gst_caps_debug_init (GstCapsDebug * capsdebug)
+{
+
+  capsdebug->srcpad =
+      gst_pad_new_from_static_template (&gst_caps_debug_src_template, "src");
+  gst_pad_set_getcaps_function (capsdebug->srcpad,
+      GST_DEBUG_FUNCPTR (gst_caps_debug_getcaps));
+  gst_pad_set_acceptcaps_function (capsdebug->srcpad,
+      GST_DEBUG_FUNCPTR (gst_caps_debug_acceptcaps));
+  gst_element_add_pad (GST_ELEMENT (capsdebug), capsdebug->srcpad);
+
+  capsdebug->sinkpad =
+      gst_pad_new_from_static_template (&gst_caps_debug_sink_template, "sink");
+  gst_pad_set_chain_function (capsdebug->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_caps_debug_sink_chain));
+  gst_pad_set_bufferalloc_function (capsdebug->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_caps_debug_bufferalloc));
+  gst_pad_set_getcaps_function (capsdebug->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_caps_debug_getcaps));
+  gst_pad_set_acceptcaps_function (capsdebug->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_caps_debug_acceptcaps));
+  gst_element_add_pad (GST_ELEMENT (capsdebug), capsdebug->sinkpad);
+
+}
+
+void
+gst_caps_debug_dispose (GObject * object)
+{
+  /* clean up as possible.  may be called multiple times */
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+void
+gst_caps_debug_finalize (GObject * object)
+{
+  /* clean up object here */
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+
+static GstStateChangeReturn
+gst_caps_debug_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  return ret;
+}
+
+
+static GstFlowReturn
+gst_caps_debug_sink_chain (GstPad * pad, GstBuffer * buffer)
+{
+  GstFlowReturn ret;
+  GstCapsDebug *capsdebug;
+
+  capsdebug = GST_CAPS_DEBUG (gst_pad_get_parent (pad));
+
+  ret = gst_pad_push (capsdebug->srcpad, buffer);
+
+  gst_object_unref (capsdebug);
+
+  return ret;
+}
+
+#define THISPAD ((pad == capsdebug->srcpad) ? "downstream" : "upstream")
+#define OTHERPAD ((pad == capsdebug->srcpad) ? "upstream" : "downstream")
+
+static GstCaps *
+gst_caps_debug_getcaps (GstPad * pad)
+{
+  GstCaps *caps;
+  GstCapsDebug *capsdebug;
+  gchar *s;
+  GstPad *otherpad;
+
+  capsdebug = GST_CAPS_DEBUG (gst_pad_get_parent (pad));
+  otherpad =
+      (pad == capsdebug->srcpad) ? capsdebug->sinkpad : capsdebug->srcpad;
+
+  GST_INFO ("%s called getcaps", THISPAD);
+
+  caps = gst_pad_peer_get_caps (otherpad);
+
+  s = gst_caps_to_string (caps);
+  GST_INFO ("%s returned %s", OTHERPAD, s);
+  g_free (s);
+
+  if (caps == NULL)
+    caps = gst_caps_new_any ();
+
+  gst_object_unref (capsdebug);
+
+  return caps;
+}
+
+
+static gboolean
+gst_caps_debug_acceptcaps (GstPad * pad, GstCaps * caps)
+{
+  GstCapsDebug *capsdebug;
+  gchar *s;
+  gboolean ret;
+  GstPad *otherpad;
+
+  capsdebug = GST_CAPS_DEBUG (gst_pad_get_parent (pad));
+  otherpad =
+      (pad == capsdebug->srcpad) ? capsdebug->sinkpad : capsdebug->srcpad;
+
+  s = gst_caps_to_string (caps);
+  GST_INFO ("%s called acceptcaps with %s", THISPAD, s);
+  g_free (s);
+
+  ret = gst_pad_peer_accept_caps (otherpad, caps);
+
+  GST_INFO ("%s returned %s", OTHERPAD, ret ? "TRUE" : "FALSE");
+
+  gst_object_unref (capsdebug);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_caps_debug_bufferalloc (GstPad * pad, guint64 offset, guint size,
+    GstCaps * caps, GstBuffer ** buf)
+{
+  GstCapsDebug *capsdebug;
+  gchar *s;
+  gchar *t;
+  GstFlowReturn ret;
+  GstPad *otherpad;
+  gboolean newcaps;
+
+  capsdebug = GST_CAPS_DEBUG (gst_pad_get_parent (pad));
+  otherpad =
+      (pad == capsdebug->srcpad) ? capsdebug->sinkpad : capsdebug->srcpad;
+
+  newcaps = (caps != GST_PAD_CAPS (pad));
+
+  if (newcaps) {
+    s = gst_caps_to_string (caps);
+    GST_INFO ("%s called bufferalloc with new caps, offset=%" G_GUINT64_FORMAT
+        " size=%d caps=%s", THISPAD, offset, size, s);
+    g_free (s);
+  }
+
+  ret = gst_pad_alloc_buffer_and_set_caps (otherpad, offset, size, caps, buf);
+
+  if (newcaps) {
+    GST_INFO ("%s returned %s", OTHERPAD, gst_flow_get_name (ret));
+  }
+  if (caps != GST_BUFFER_CAPS (*buf)) {
+    s = gst_caps_to_string (caps);
+    t = gst_caps_to_string (GST_BUFFER_CAPS (*buf));
+    GST_INFO
+        ("%s returned from bufferalloc with different caps, requested=%s returned=%s",
+        OTHERPAD, s, t);
+    g_free (s);
+    g_free (t);
+  }
+
+  gst_object_unref (capsdebug);
+
+  return ret;
+}
diff --git a/gst/debugutils/gstcapsdebug.h b/gst/debugutils/gstcapsdebug.h
new file mode 100644
index 0000000..9d0930d
--- /dev/null
+++ b/gst/debugutils/gstcapsdebug.h
@@ -0,0 +1,55 @@
+/* GStreamer
+ * Copyright (C) 2010 FIXME <fixme@example.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GST_CAPS_DEBUG_H_
+#define _GST_CAPS_DEBUG_H_
+
+#include <gst/gst.h>
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CAPS_DEBUG   (gst_caps_debug_get_type())
+#define GST_CAPS_DEBUG(obj)   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAPS_DEBUG,GstCapsDebug))
+#define GST_CAPS_DEBUG_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAPS_DEBUG,GstCapsDebugClass))
+#define GST_IS_CAPS_DEBUG(obj)   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAPS_DEBUG))
+#define GST_IS_CAPS_DEBUG_CLASS(obj)   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAPS_DEBUG))
+
+typedef struct _GstCapsDebug GstCapsDebug;
+typedef struct _GstCapsDebugClass GstCapsDebugClass;
+
+struct _GstCapsDebug
+{
+  GstElement base_capsdebug;
+
+  GstPad *srcpad;
+  GstPad *sinkpad;
+
+};
+
+struct _GstCapsDebugClass
+{
+  GstElementClass base_capsdebug_class;
+};
+
+GType gst_caps_debug_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/gst/debugutils/gstcapssetter.c b/gst/debugutils/gstcapssetter.c
new file mode 100644
index 0000000..6b3db76
--- /dev/null
+++ b/gst/debugutils/gstcapssetter.c
@@ -0,0 +1,331 @@
+/* GStreamer Element
+ * Copyright (C) 2006-2009 Mark Nauwelaerts <mnauw@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1307, USA.
+ */
+
+/**
+ * SECTION:element-capssetter
+ *
+ * Sets or merges caps on a stream's buffers. That is, a buffer's caps are
+ * updated using (fields of) #GstCapsSetter:caps. Note that this may contain
+ * multiple structures (though not likely recommended), but each of these must
+ * be fixed (or will otherwise be rejected).
+ * 
+ * If #GstCapsSetter:join is %TRUE, then the incoming caps' mime-type is
+ * compared to the mime-type(s) of provided caps and only matching structure(s)
+ * are considered for updating.
+ * 
+ * If #GstCapsSetter:replace is %TRUE, then any caps update is preceded by
+ * clearing existing fields, making provided fields (as a whole) replace
+ * incoming ones. Otherwise, no clearing is performed, in which case provided
+ * fields are added/merged onto incoming caps
+ * 
+ * Although this element might mainly serve as debug helper,
+ * it can also practically be used to correct a faulty pixel-aspect-ratio,
+ * or to modify a yuv fourcc value to effectively swap chroma components or such
+ * alike.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstcapssetter.h"
+
+#include <string.h>
+
+
+GST_DEBUG_CATEGORY_STATIC (caps_setter_debug);
+#define GST_CAT_DEFAULT caps_setter_debug
+
+
+/* signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_CAPS,
+  PROP_JOIN,
+  PROP_REPLACE
+      /* FILL ME */
+};
+
+#define DEFAULT_JOIN              TRUE
+#define DEFAULT_REPLACE           FALSE
+
+static GstStaticPadTemplate gst_caps_setter_src_template =
+GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SRC_NAME,
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate gst_caps_setter_sink_template =
+GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SINK_NAME,
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+
+static gboolean gst_caps_setter_transform_size (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * caps, gsize size,
+    GstCaps * othercaps, gsize * othersize);
+static GstCaps *gst_caps_setter_transform_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * cfilter);
+static GstFlowReturn gst_caps_setter_transform_ip (GstBaseTransform * btrans,
+    GstBuffer * in);
+
+static void gst_caps_setter_finalize (GObject * object);
+
+static void gst_caps_setter_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_caps_setter_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+#define gst_caps_setter_parent_class parent_class
+G_DEFINE_TYPE (GstCapsSetter, gst_caps_setter, GST_TYPE_BASE_TRANSFORM);
+
+static void
+gst_caps_setter_class_init (GstCapsSetterClass * g_class)
+{
+  GObjectClass *gobject_class = (GObjectClass *) g_class;
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) g_class;
+
+  GST_DEBUG_CATEGORY_INIT (caps_setter_debug, "capssetter", 0, "capssetter");
+
+  gobject_class->set_property = gst_caps_setter_set_property;
+  gobject_class->get_property = gst_caps_setter_get_property;
+
+  gobject_class->finalize = gst_caps_setter_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_CAPS,
+      g_param_spec_boxed ("caps", "Merge caps",
+          "Merge these caps (thereby overwriting) in the stream",
+          GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_JOIN,
+      g_param_spec_boolean ("join", "Join",
+          "Match incoming caps' mime-type to mime-type of provided caps",
+          DEFAULT_JOIN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_REPLACE,
+      g_param_spec_boolean ("replace", "Replace",
+          "Drop fields of incoming caps", DEFAULT_REPLACE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (element_class, "CapsSetter",
+      "Generic",
+      "Set/merge caps on stream",
+      "Mark Nauwelaerts <mnauw@users.sourceforge.net>");
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_caps_setter_sink_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_caps_setter_src_template);
+
+  trans_class->transform_size =
+      GST_DEBUG_FUNCPTR (gst_caps_setter_transform_size);
+  trans_class->transform_caps =
+      GST_DEBUG_FUNCPTR (gst_caps_setter_transform_caps);
+  /* dummy seems needed */
+  trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_caps_setter_transform_ip);
+}
+
+static void
+gst_caps_setter_init (GstCapsSetter * filter)
+{
+  filter->caps = gst_caps_new_any ();
+  filter->join = DEFAULT_JOIN;
+  filter->replace = DEFAULT_REPLACE;
+}
+
+static void
+gst_caps_setter_finalize (GObject * object)
+{
+  GstCapsSetter *filter = GST_CAPS_SETTER (object);
+
+  gst_caps_replace (&filter->caps, NULL);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_caps_setter_transform_size (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * caps, gsize size,
+    GstCaps * othercaps, gsize * othersize)
+{
+  *othersize = size;
+
+  return TRUE;
+}
+
+static GstCaps *
+gst_caps_setter_transform_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * cfilter)
+{
+  GstCapsSetter *filter = GST_CAPS_SETTER (trans);
+  GstCaps *ret = NULL, *filter_caps = NULL;
+  GstStructure *structure, *merge;
+  const gchar *name;
+  gint i, j, k;
+
+  GST_DEBUG_OBJECT (trans,
+      "receiving caps: %" GST_PTR_FORMAT ", with filter: %" GST_PTR_FORMAT,
+      caps, cfilter);
+
+  /* pass filter caps upstream, or any if no filter */
+  if (direction != GST_PAD_SINK) {
+    if (!cfilter || gst_caps_is_empty (cfilter)) {
+      return gst_caps_ref (GST_CAPS_ANY);
+    } else {
+      return gst_caps_ref (cfilter);
+    }
+  }
+
+  ret = gst_caps_copy (caps);
+
+  GST_OBJECT_LOCK (filter);
+  filter_caps = gst_caps_ref (filter->caps);
+  GST_OBJECT_UNLOCK (filter);
+
+  for (k = 0; k < gst_caps_get_size (ret); k++) {
+    structure = gst_caps_get_structure (ret, k);
+    name = gst_structure_get_name (structure);
+
+    for (i = 0; i < gst_caps_get_size (filter_caps); ++i) {
+      merge = gst_caps_get_structure (filter_caps, i);
+      if (gst_structure_has_name (merge, name) || !filter->join) {
+
+        if (!filter->join)
+          gst_structure_set_name (structure, gst_structure_get_name (merge));
+
+        if (filter->replace)
+          gst_structure_remove_all_fields (structure);
+
+        for (j = 0; j < gst_structure_n_fields (merge); ++j) {
+          const gchar *fname;
+
+          fname = gst_structure_nth_field_name (merge, j);
+          gst_structure_set_value (structure, fname,
+              gst_structure_get_value (merge, fname));
+        }
+      }
+    }
+  }
+
+  GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, ret);
+
+  gst_caps_unref (filter_caps);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_caps_setter_transform_ip (GstBaseTransform * btrans, GstBuffer * in)
+{
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_caps_is_fixed_foreach (GQuark field_id, const GValue * value,
+    gpointer unused)
+{
+  return gst_value_is_fixed (value);
+}
+
+static void
+gst_caps_setter_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstCapsSetter *filter = GST_CAPS_SETTER (object);
+
+  switch (prop_id) {
+    case PROP_CAPS:{
+      GstCaps *new_caps;
+      const GstCaps *new_caps_val = gst_value_get_caps (value);
+      gint i;
+
+      if (new_caps_val == NULL) {
+        new_caps = gst_caps_new_any ();
+      } else {
+        new_caps = gst_caps_copy (new_caps_val);
+      }
+
+      for (i = 0; new_caps && (i < gst_caps_get_size (new_caps)); ++i) {
+        GstStructure *s;
+
+        s = gst_caps_get_structure (new_caps, i);
+        if (!gst_structure_foreach (s, gst_caps_is_fixed_foreach, NULL)) {
+          GST_ERROR_OBJECT (filter, "rejected unfixed caps: %" GST_PTR_FORMAT,
+              new_caps);
+          gst_caps_unref (new_caps);
+          new_caps = NULL;
+          break;
+        }
+      }
+
+      if (new_caps) {
+        GST_OBJECT_LOCK (filter);
+        gst_caps_replace (&filter->caps, new_caps);
+        /* drop extra ref */
+        gst_caps_unref (new_caps);
+        GST_OBJECT_UNLOCK (filter);
+
+        GST_DEBUG_OBJECT (filter, "set new caps %" GST_PTR_FORMAT, new_caps);
+      }
+
+      /* try to activate these new caps next time around */
+      gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (filter));
+      break;
+    }
+    case PROP_JOIN:
+      filter->join = g_value_get_boolean (value);
+      break;
+    case PROP_REPLACE:
+      filter->replace = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_caps_setter_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstCapsSetter *filter = GST_CAPS_SETTER (object);
+
+  switch (prop_id) {
+    case PROP_CAPS:
+      gst_value_set_caps (value, filter->caps);
+      break;
+    case PROP_JOIN:
+      g_value_set_boolean (value, filter->join);
+      break;
+    case PROP_REPLACE:
+      g_value_set_boolean (value, filter->replace);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/gst/debugutils/gstcapssetter.h b/gst/debugutils/gstcapssetter.h
new file mode 100644
index 0000000..246bf19
--- /dev/null
+++ b/gst/debugutils/gstcapssetter.h
@@ -0,0 +1,63 @@
+/* GStreamer Element
+ * Copyright (C) 2006-2009 Mark Nauwelaerts <mnauw@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1307, USA.
+ */
+
+
+#ifndef __GST_CAPS_SETTER_H__
+#define __GST_CAPS_SETTER_H__
+
+#include <gst/base/gstbasetransform.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CAPS_SETTER \
+  (gst_caps_setter_get_type())
+#define GST_CAPS_SETTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAPS_SETTER,GstCapsSetter))
+#define GST_CAPS_SETTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAPS_SETTER,GstCapsSetterClass))
+#define GST_IS_CAPS_SETTER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAPS_SETTER))
+#define GST_IS_CAPS_SETTER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAPS_SETTER))
+
+GType gst_caps_setter_get_type (void);
+
+typedef struct _GstCapsSetter GstCapsSetter;
+typedef struct _GstCapsSetterClass GstCapsSetterClass;
+
+struct _GstCapsSetter
+{
+  GstBaseTransform parent;
+
+  /* < private > */
+  /* properties */
+  GstCaps *caps;
+  gboolean join;
+  gboolean replace;
+};
+
+
+struct _GstCapsSetterClass
+{
+  GstBaseTransformClass parent_class;
+};
+
+G_END_DECLS
+
+#endif /* __GST_CAPS_SETTER_H__ */
diff --git a/gst/debugutils/gstdebug.c b/gst/debugutils/gstdebug.c
new file mode 100644
index 0000000..a56aa9f
--- /dev/null
+++ b/gst/debugutils/gstdebug.c
@@ -0,0 +1,76 @@
+/* GStreamer
+ * Copyright (C) 2004 Benjamin Otte <otte@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+GType gst_break_my_data_get_type (void);
+//GType gst_caps_debug_get_type (void);
+GType gst_caps_setter_get_type (void);
+GType gst_rnd_buffer_size_get_type (void);
+GType gst_navseek_get_type (void);
+GType gst_progress_report_get_type (void);
+GType gst_tag_inject_get_type (void);
+GType gst_test_get_type (void);
+GType gst_push_file_src_get_type (void);
+/*
+GType gst_gst_negotiation_get_type (void);
+*/
+GType gst_cpu_report_get_type (void);
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "breakmydata", GST_RANK_NONE,
+          gst_break_my_data_get_type ())
+      || !gst_element_register (plugin, "capssetter", GST_RANK_NONE,
+          gst_caps_setter_get_type ())
+      || !gst_element_register (plugin, "rndbuffersize", GST_RANK_NONE,
+          gst_rnd_buffer_size_get_type ())
+      || !gst_element_register (plugin, "navseek", GST_RANK_NONE,
+          gst_navseek_get_type ())
+      || !gst_element_register (plugin, "pushfilesrc", GST_RANK_NONE,
+          gst_push_file_src_get_type ()) ||
+/*    !gst_element_register (plugin, "negotiation", GST_RANK_NONE, gst_gst_negotiation_get_type ()) || */
+      !gst_element_register (plugin, "progressreport", GST_RANK_NONE,
+          gst_progress_report_get_type ())
+      || !gst_element_register (plugin, "taginject", GST_RANK_NONE,
+          gst_tag_inject_get_type ())
+      || !gst_element_register (plugin, "testsink", GST_RANK_NONE,
+          gst_test_get_type ())
+#if 0
+      || !gst_element_register (plugin, "capsdebug", GST_RANK_NONE,
+          gst_caps_debug_get_type ())
+#endif
+      || !gst_element_register (plugin, "cpureport", GST_RANK_NONE,
+          gst_cpu_report_get_type ()))
+
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    debug,
+    "elements for testing and debugging",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/debugutils/gstnavigationtest.c b/gst/debugutils/gstnavigationtest.c
new file mode 100644
index 0000000..532fe13
--- /dev/null
+++ b/gst/debugutils/gstnavigationtest.c
@@ -0,0 +1,277 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstnavigationtest.h"
+#include <string.h>
+#include <math.h>
+
+#include <gst/video/video.h>
+
+#ifdef _MSC_VER
+#define rint(x) (floor((x)+0.5))
+#endif
+
+GST_DEBUG_CATEGORY_STATIC (navigationtest_debug);
+#define GST_CAT_DEFAULT navigationtest_debug
+
+static GstStaticPadTemplate gst_navigationtest_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420"))
+    );
+
+static GstStaticPadTemplate gst_navigationtest_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420"))
+    );
+
+#define gst_navigationtest_parent_class parent_class
+G_DEFINE_TYPE (GstNavigationtest, gst_navigationtest, GST_TYPE_VIDEO_FILTER);
+
+static gboolean
+gst_navigationtest_src_event (GstBaseTransform * trans, GstEvent * event)
+{
+  GstVideoInfo *info;
+  GstNavigationtest *navtest;
+  const gchar *type;
+
+  navtest = GST_NAVIGATIONTEST (trans);
+
+  info = &GST_VIDEO_FILTER (trans)->in_info;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_NAVIGATION:
+    {
+      const GstStructure *s = gst_event_get_structure (event);
+      gint fps_n, fps_d;
+
+      fps_n = GST_VIDEO_INFO_FPS_N (info);
+      fps_d = GST_VIDEO_INFO_FPS_D (info);
+
+      type = gst_structure_get_string (s, "event");
+      if (g_str_equal (type, "mouse-move")) {
+        gst_structure_get_double (s, "pointer_x", &navtest->x);
+        gst_structure_get_double (s, "pointer_y", &navtest->y);
+      } else if (g_str_equal (type, "mouse-button-press")) {
+        ButtonClick *click = g_new (ButtonClick, 1);
+
+        gst_structure_get_double (s, "pointer_x", &click->x);
+        gst_structure_get_double (s, "pointer_y", &click->y);
+        click->images_left = (fps_n + fps_d - 1) / fps_d;
+        /* green */
+        click->cy = 150;
+        click->cu = 46;
+        click->cv = 21;
+        navtest->clicks = g_slist_prepend (navtest->clicks, click);
+      } else if (g_str_equal (type, "mouse-button-release")) {
+        ButtonClick *click = g_new (ButtonClick, 1);
+
+        gst_structure_get_double (s, "pointer_x", &click->x);
+        gst_structure_get_double (s, "pointer_y", &click->y);
+        click->images_left = (fps_n + fps_d - 1) / fps_d;
+        /* red */
+        click->cy = 76;
+        click->cu = 85;
+        click->cv = 255;
+        navtest->clicks = g_slist_prepend (navtest->clicks, click);
+      }
+      break;
+    }
+    default:
+      break;
+  }
+  return GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event);
+}
+
+/* Useful macros */
+#define GST_VIDEO_I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
+#define GST_VIDEO_I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
+#define GST_VIDEO_I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(GST_VIDEO_I420_Y_ROWSTRIDE(width)))/2)
+
+#define GST_VIDEO_I420_Y_OFFSET(w,h) (0)
+#define GST_VIDEO_I420_U_OFFSET(w,h) (GST_VIDEO_I420_Y_OFFSET(w,h)+(GST_VIDEO_I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
+#define GST_VIDEO_I420_V_OFFSET(w,h) (GST_VIDEO_I420_U_OFFSET(w,h)+(GST_VIDEO_I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
+
+#define GST_VIDEO_I420_SIZE(w,h)     (GST_VIDEO_I420_V_OFFSET(w,h)+(GST_VIDEO_I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
+
+static void
+draw_box_planar411 (GstVideoFrame * frame, int x, int y,
+    guint8 colory, guint8 coloru, guint8 colorv)
+{
+  gint width, height;
+  int x1, x2, y1, y2;
+  guint8 *d;
+  gint stride;
+
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
+
+  if (x < 0 || y < 0 || x >= width || y >= height)
+    return;
+
+  x1 = MAX (x - 5, 0);
+  x2 = MIN (x + 5, width);
+  y1 = MAX (y - 5, 0);
+  y2 = MIN (y + 5, height);
+
+  d = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+
+  for (y = y1; y < y2; y++) {
+    for (x = x1; x < x2; x++) {
+      d[y * stride + x] = colory;
+    }
+  }
+
+  d = GST_VIDEO_FRAME_PLANE_DATA (frame, 1);
+  stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 1);
+
+  x1 /= 2;
+  x2 /= 2;
+  y1 /= 2;
+  y2 /= 2;
+  for (y = y1; y < y2; y++) {
+    for (x = x1; x < x2; x++) {
+      d[y * stride + x] = coloru;
+    }
+  }
+
+  d = GST_VIDEO_FRAME_PLANE_DATA (frame, 2);
+  stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 2);
+
+  for (y = y1; y < y2; y++) {
+    for (x = x1; x < x2; x++) {
+      d[y * stride + x] = colorv;
+    }
+  }
+}
+
+static GstFlowReturn
+gst_navigationtest_transform_frame (GstVideoFilter * filter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame)
+{
+  GstNavigationtest *navtest = GST_NAVIGATIONTEST (filter);
+  GSList *walk;
+
+  gst_video_frame_copy (out_frame, in_frame);
+
+  walk = navtest->clicks;
+  while (walk) {
+    ButtonClick *click = walk->data;
+
+    walk = g_slist_next (walk);
+    draw_box_planar411 (out_frame,
+        rint (click->x), rint (click->y), click->cy, click->cu, click->cv);
+    if (--click->images_left < 1) {
+      navtest->clicks = g_slist_remove (navtest->clicks, click);
+      g_free (click);
+    }
+  }
+  draw_box_planar411 (out_frame,
+      rint (navtest->x), rint (navtest->y), 0, 128, 128);
+
+  return GST_FLOW_OK;
+}
+
+static GstStateChangeReturn
+gst_navigationtest_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+  GstNavigationtest *navtest = GST_NAVIGATIONTEST (element);
+
+  if (GST_ELEMENT_CLASS (parent_class)->change_state)
+    ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  /* downwards state changes */
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+    {
+      g_slist_foreach (navtest->clicks, (GFunc) g_free, NULL);
+      g_slist_free (navtest->clicks);
+      navtest->clicks = NULL;
+      break;
+    }
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_navigationtest_class_init (GstNavigationtestClass * klass)
+{
+  GstElementClass *element_class;
+  GstBaseTransformClass *trans_class;
+  GstVideoFilterClass *vfilter_class;
+
+  element_class = (GstElementClass *) klass;
+  trans_class = (GstBaseTransformClass *) klass;
+  vfilter_class = (GstVideoFilterClass *) klass;
+
+  element_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_navigationtest_change_state);
+
+  gst_element_class_set_static_metadata (element_class, "Video navigation test",
+      "Filter/Effect/Video",
+      "Handle navigation events showing a black square following mouse pointer",
+      "David Schleef <ds@schleef.org>");
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_navigationtest_sink_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_navigationtest_src_template);
+
+  trans_class->src_event = GST_DEBUG_FUNCPTR (gst_navigationtest_src_event);
+
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_navigationtest_transform_frame);
+}
+
+static void
+gst_navigationtest_init (GstNavigationtest * navtest)
+{
+  navtest->x = -1;
+  navtest->y = -1;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (navigationtest_debug, "navigationtest", 0,
+      "navigationtest");
+
+  return gst_element_register (plugin, "navigationtest", GST_RANK_NONE,
+      GST_TYPE_NAVIGATIONTEST);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    navigationtest,
+    "Template for a video filter",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/debugutils/gstnavigationtest.h b/gst/debugutils/gstnavigationtest.h
new file mode 100644
index 0000000..f1cf458
--- /dev/null
+++ b/gst/debugutils/gstnavigationtest.h
@@ -0,0 +1,65 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_NAVIGATIONTEST_H__
+#define __GST_NAVIGATIONTEST_H__
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_NAVIGATIONTEST \
+  (gst_navigationtest_get_type())
+#define GST_NAVIGATIONTEST(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_NAVIGATIONTEST,GstNavigationtest))
+#define GST_NAVIGATIONTEST_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_NAVIGATIONTEST,GstNavigationtestClass))
+#define GST_IS_NAVIGATIONTEST(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_NAVIGATIONTEST))
+#define GST_IS_NAVIGATIONTEST_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_NAVIGATIONTEST))
+typedef struct _GstNavigationtest GstNavigationtest;
+typedef struct _GstNavigationtestClass GstNavigationtestClass;
+
+typedef struct
+{
+  gdouble x;
+  gdouble y;
+  gint images_left;
+  guint8 cy, cu, cv;
+} ButtonClick;
+
+struct _GstNavigationtest
+{
+  GstVideoFilter videofilter;
+
+  gdouble x, y;
+  GSList *clicks;
+};
+
+struct _GstNavigationtestClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_navigationtest_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_NAVIGATIONTEST_H__ */
diff --git a/gst/debugutils/gstnavseek.c b/gst/debugutils/gstnavseek.c
new file mode 100644
index 0000000..fd9386c
--- /dev/null
+++ b/gst/debugutils/gstnavseek.c
@@ -0,0 +1,390 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * This file was (probably) generated from gstnavseek.c,
+ * gstnavseek.c,v 1.7 2003/11/08 02:48:59 dschleef Exp 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstnavseek.h"
+#include <string.h>
+#include <math.h>
+
+enum
+{
+  PROP_0,
+  PROP_SEEKOFFSET
+};
+
+GstStaticPadTemplate navseek_src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+GstStaticPadTemplate navseek_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static gboolean gst_navseek_sink_event (GstBaseTransform * trans,
+    GstEvent * event);
+static GstFlowReturn gst_navseek_transform_ip (GstBaseTransform * basetrans,
+    GstBuffer * buf);
+static gboolean gst_navseek_src_event (GstBaseTransform * trans,
+    GstEvent * event);
+static gboolean gst_navseek_stop (GstBaseTransform * trans);
+static gboolean gst_navseek_start (GstBaseTransform * trans);
+
+static void gst_navseek_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_navseek_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+GType gst_navseek_get_type (void);
+#define gst_navseek_parent_class parent_class
+G_DEFINE_TYPE (GstNavSeek, gst_navseek, GST_TYPE_BASE_TRANSFORM);
+
+static void
+gst_navseek_class_init (GstNavSeekClass * klass)
+{
+  GstBaseTransformClass *gstbasetrans_class;
+  GstElementClass *element_class;
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  element_class = GST_ELEMENT_CLASS (klass);
+  gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass);
+
+  gobject_class->set_property = gst_navseek_set_property;
+  gobject_class->get_property = gst_navseek_get_property;
+
+  g_object_class_install_property (gobject_class,
+      PROP_SEEKOFFSET, g_param_spec_double ("seek-offset", "Seek Offset",
+          "Time in seconds to seek by", 0.0, G_MAXDOUBLE, 5.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (element_class,
+      &navseek_sink_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &navseek_src_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "Seek based on left-right arrows", "Filter/Video",
+      "Seek based on navigation keys left-right",
+      "Jan Schmidt <thaytan@mad.scientist.com>");
+
+  gstbasetrans_class->src_event = GST_DEBUG_FUNCPTR (gst_navseek_src_event);
+  gstbasetrans_class->sink_event = GST_DEBUG_FUNCPTR (gst_navseek_sink_event);
+  gstbasetrans_class->transform_ip =
+      GST_DEBUG_FUNCPTR (gst_navseek_transform_ip);
+  gstbasetrans_class->start = GST_DEBUG_FUNCPTR (gst_navseek_start);
+  gstbasetrans_class->stop = GST_DEBUG_FUNCPTR (gst_navseek_stop);
+}
+
+static void
+gst_navseek_init (GstNavSeek * navseek)
+{
+  gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (navseek), TRUE);
+
+  navseek->seek_offset = 5.0;
+  navseek->loop = FALSE;
+  navseek->grab_seg_start = FALSE;
+  navseek->grab_seg_end = FALSE;
+  navseek->segment_start = GST_CLOCK_TIME_NONE;
+  navseek->segment_end = GST_CLOCK_TIME_NONE;
+}
+
+static void
+gst_navseek_seek (GstNavSeek * navseek, gint64 offset)
+{
+  gboolean ret;
+  GstPad *peer_pad;
+  gint64 peer_value;
+
+  /* Query for the current time then attempt to set to time + offset */
+  peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
+  ret = gst_pad_query_position (peer_pad, GST_FORMAT_TIME, &peer_value);
+
+  if (ret) {
+    GstEvent *event;
+
+    peer_value += offset;
+    if (peer_value < 0)
+      peer_value = 0;
+
+    event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
+        GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH,
+        GST_SEEK_TYPE_SET, peer_value, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
+
+    gst_pad_send_event (peer_pad, event);
+  }
+
+  gst_object_unref (peer_pad);
+}
+
+static void
+gst_navseek_change_playback_rate (GstNavSeek * navseek, gdouble rate)
+{
+  gboolean ret;
+  GstPad *peer_pad;
+  gint64 current_position;
+
+  peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
+  ret = gst_pad_query_position (peer_pad, GST_FORMAT_TIME, &current_position);
+
+  if (ret) {
+    GstEvent *event;
+    gint64 start;
+    gint64 stop;
+
+    if (rate > 0.0) {
+      start = current_position;
+      stop = -1;
+    } else {
+      /* negative rate: we play from stop to start */
+      start = 0;
+      stop = current_position;
+    }
+
+    event = gst_event_new_seek (rate, GST_FORMAT_TIME,
+        GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP,
+        GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_SET, stop);
+
+    gst_pad_send_event (peer_pad, event);
+  }
+  gst_object_unref (peer_pad);
+}
+
+static void
+gst_navseek_segseek (GstNavSeek * navseek)
+{
+  GstEvent *event;
+  GstPad *peer_pad;
+
+  if ((navseek->segment_start == GST_CLOCK_TIME_NONE) ||
+      (navseek->segment_end == GST_CLOCK_TIME_NONE) ||
+      (!GST_PAD_IS_LINKED (GST_BASE_TRANSFORM (navseek)->sinkpad))) {
+    return;
+  }
+
+  if (navseek->loop) {
+    event =
+        gst_event_new_seek (1.0, GST_FORMAT_TIME,
+        GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT,
+        GST_SEEK_TYPE_SET, navseek->segment_start, GST_SEEK_TYPE_SET,
+        navseek->segment_end);
+  } else {
+    event =
+        gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_ACCURATE,
+        GST_SEEK_TYPE_SET, navseek->segment_start, GST_SEEK_TYPE_SET,
+        navseek->segment_end);
+  }
+
+  peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
+  gst_pad_send_event (peer_pad, event);
+  gst_object_unref (peer_pad);
+}
+
+static void
+gst_navseek_toggle_play_pause (GstNavSeek * navseek)
+{
+  GstStateChangeReturn sret;
+  GstState current, pending, state;
+
+  sret = gst_element_get_state (GST_ELEMENT (navseek), &current, &pending, 0);
+  if (sret == GST_STATE_CHANGE_FAILURE)
+    return;
+
+  state = (pending != GST_STATE_VOID_PENDING) ? pending : current;
+
+  gst_element_post_message (GST_ELEMENT (navseek),
+      gst_message_new_request_state (GST_OBJECT (navseek),
+          (state == GST_STATE_PLAYING) ? GST_STATE_PAUSED : GST_STATE_PLAYING));
+}
+
+static gboolean
+gst_navseek_src_event (GstBaseTransform * trans, GstEvent * event)
+{
+  GstNavSeek *navseek;
+  gboolean ret = TRUE;
+
+  navseek = GST_NAVSEEK (trans);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_NAVIGATION:
+    {
+      /* Check for a keyup and convert left/right to a seek event */
+      const GstStructure *structure;
+      const gchar *event_type;
+
+      structure = gst_event_get_structure (event);
+      g_return_val_if_fail (structure != NULL, FALSE);
+
+      event_type = gst_structure_get_string (structure, "event");
+      g_return_val_if_fail (event_type != NULL, FALSE);
+
+      if (strcmp (event_type, "key-press") == 0) {
+        const gchar *key;
+
+        key = gst_structure_get_string (structure, "key");
+        g_return_val_if_fail (key != NULL, FALSE);
+
+        if (strcmp (key, "Left") == 0) {
+          /* Seek backward by 5 secs */
+          gst_navseek_seek (navseek, -1.0 * navseek->seek_offset * GST_SECOND);
+        } else if (strcmp (key, "Right") == 0) {
+          /* Seek forward */
+          gst_navseek_seek (navseek, navseek->seek_offset * GST_SECOND);
+        } else if (strcmp (key, "s") == 0) {
+          /* Grab the next frame as the start frame of a segment */
+          navseek->grab_seg_start = TRUE;
+        } else if (strcmp (key, "e") == 0) {
+          /* Grab the next frame as the end frame of a segment */
+          navseek->grab_seg_end = TRUE;
+        } else if (strcmp (key, "l") == 0) {
+          /* Toggle the loop flag. If we have both start and end segment times send a seek */
+          navseek->loop = !navseek->loop;
+          gst_navseek_segseek (navseek);
+        } else if (strcmp (key, "f") == 0) {
+          /* fast forward */
+          gst_navseek_change_playback_rate (navseek, 2.0);
+        } else if (strcmp (key, "r") == 0) {
+          /* rewind */
+          gst_navseek_change_playback_rate (navseek, -2.0);
+        } else if (strcmp (key, "n") == 0) {
+          /* normal speed */
+          gst_navseek_change_playback_rate (navseek, 1.0);
+        } else if (strcmp (key, "space") == 0) {
+          gst_navseek_toggle_play_pause (navseek);
+        }
+      } else {
+        break;
+      }
+      gst_event_unref (event);
+      event = NULL;
+      break;
+    }
+    default:
+      break;
+  }
+
+  if (event)
+    ret = GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event);
+
+  return ret;
+}
+
+static void
+gst_navseek_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstNavSeek *navseek = GST_NAVSEEK (object);
+
+  switch (prop_id) {
+    case PROP_SEEKOFFSET:
+      GST_OBJECT_LOCK (navseek);
+      navseek->seek_offset = g_value_get_double (value);
+      GST_OBJECT_UNLOCK (navseek);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_navseek_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstNavSeek *navseek = GST_NAVSEEK (object);
+
+  switch (prop_id) {
+    case PROP_SEEKOFFSET:
+      GST_OBJECT_LOCK (navseek);
+      g_value_set_double (value, navseek->seek_offset);
+      GST_OBJECT_UNLOCK (navseek);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_navseek_sink_event (GstBaseTransform * trans, GstEvent * event)
+{
+  GstNavSeek *navseek = GST_NAVSEEK (trans);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+      GST_OBJECT_LOCK (navseek);
+      if (navseek->loop)
+        gst_navseek_segseek (navseek);
+      GST_OBJECT_UNLOCK (navseek);
+      break;
+    default:
+      break;
+  }
+  return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
+}
+
+static GstFlowReturn
+gst_navseek_transform_ip (GstBaseTransform * basetrans, GstBuffer * buf)
+{
+  GstNavSeek *navseek = GST_NAVSEEK (basetrans);
+
+  GST_OBJECT_LOCK (navseek);
+
+  if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+    if (navseek->grab_seg_start) {
+      navseek->segment_start = GST_BUFFER_TIMESTAMP (buf);
+      navseek->segment_end = GST_CLOCK_TIME_NONE;
+      navseek->grab_seg_start = FALSE;
+    }
+
+    if (navseek->grab_seg_end) {
+      navseek->segment_end = GST_BUFFER_TIMESTAMP (buf);
+      navseek->grab_seg_end = FALSE;
+      gst_navseek_segseek (navseek);
+    }
+  }
+
+  GST_OBJECT_UNLOCK (navseek);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_navseek_start (GstBaseTransform * trans)
+{
+  /* anything we should be doing here? */
+  return TRUE;
+}
+
+static gboolean
+gst_navseek_stop (GstBaseTransform * trans)
+{
+  /* anything we should be doing here? */
+  return TRUE;
+}
diff --git a/gst/debugutils/gstnavseek.h b/gst/debugutils/gstnavseek.h
new file mode 100644
index 0000000..1b9c924
--- /dev/null
+++ b/gst/debugutils/gstnavseek.h
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_NAVSEEK_H__
+#define __GST_NAVSEEK_H__
+
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_NAVSEEK \
+  (gst_navseek_get_type())
+#define GST_NAVSEEK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_NAVSEEK,GstNavSeek))
+#define GST_NAVSEEK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_NAVSEEK,GstNavSeekClass))
+#define GST_IS_NAVSEEK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_NAVSEEK))
+#define GST_IS_NAVSEEK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_NAVSEEK))
+typedef struct _GstNavSeek GstNavSeek;
+typedef struct _GstNavSeekClass GstNavSeekClass;
+
+struct _GstNavSeek
+{
+  GstBaseTransform basetransform;
+
+  gdouble seek_offset;
+  gboolean loop;
+  gboolean grab_seg_start;
+  gboolean grab_seg_end;
+  GstClockTime segment_start;
+  GstClockTime segment_end;
+};
+
+struct _GstNavSeekClass
+{
+  GstBaseTransformClass parent_class;
+};
+
+G_END_DECLS
+#endif /* __GST_NAVSEEK_H__ */
diff --git a/gst/debugutils/gstpushfilesrc.c b/gst/debugutils/gstpushfilesrc.c
new file mode 100644
index 0000000..c60accb
--- /dev/null
+++ b/gst/debugutils/gstpushfilesrc.c
@@ -0,0 +1,421 @@
+/* GStreamer Push File Source
+ * Copyright (C) <2007> Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-pushfilesrc
+ * @see_also: filesrc
+ *
+ * This element is only useful for debugging purposes. It implements an URI
+ * protocol handler for the 'pushfile' protocol and behaves like a file source
+ * element that cannot be activated in pull-mode. This makes it very easy to
+ * debug demuxers or decoders that can operate both pull and push-based in
+ * connection with the playbin element (which creates a source based on the
+ * URI passed).
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -m playbin uri=pushfile:///home/you/some/file.ogg
+ * ]| This plays back the given file using playbin, with the demuxer operating
+ * push-based.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstpushfilesrc.h"
+
+#include <gst/gst.h>
+
+GST_DEBUG_CATEGORY_STATIC (pushfilesrc_debug);
+#define GST_CAT_DEFAULT pushfilesrc_debug
+
+enum
+{
+  PROP_0,
+  PROP_LOCATION,
+  PROP_TIME_SEGMENT,
+  PROP_STREAM_TIME,
+  PROP_START_TIME,
+  PROP_INITIAL_TIMESTAMP,
+  PROP_RATE,
+  PROP_APPLIED_RATE
+};
+
+#define DEFAULT_TIME_SEGMENT FALSE
+#define DEFAULT_STREAM_TIME 0
+#define DEFAULT_START_TIME 0
+#define DEFAULT_INITIAL_TIMESTAMP GST_CLOCK_TIME_NONE
+#define DEFAULT_RATE 1.0
+#define DEFAULT_APPLIED_RATE 1.0
+
+static void gst_push_file_src_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_push_file_src_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static void gst_push_file_src_uri_handler_init (gpointer g_iface,
+    gpointer iface_data);
+
+#define gst_push_file_src_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstPushFileSrc, gst_push_file_src, GST_TYPE_BIN,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
+        gst_push_file_src_uri_handler_init));
+
+static void
+gst_push_file_src_dispose (GObject * obj)
+{
+  GstPushFileSrc *src = GST_PUSH_FILE_SRC (obj);
+
+  if (src->srcpad) {
+    gst_element_remove_pad (GST_ELEMENT (src), src->srcpad);
+    src->srcpad = NULL;
+  }
+  if (src->filesrc) {
+    gst_bin_remove (GST_BIN (src), src->filesrc);
+    src->filesrc = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->dispose (obj);
+}
+
+static void
+gst_push_file_src_class_init (GstPushFileSrcClass * g_class)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = G_OBJECT_CLASS (g_class);
+  element_class = GST_ELEMENT_CLASS (g_class);
+
+  GST_DEBUG_CATEGORY_INIT (pushfilesrc_debug, "pushfilesrc", 0,
+      "pushfilesrc element");
+
+  gobject_class->dispose = gst_push_file_src_dispose;
+  gobject_class->set_property = gst_push_file_src_set_property;
+  gobject_class->get_property = gst_push_file_src_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_LOCATION,
+      g_param_spec_string ("location", "File Location",
+          "Location of the file to read", NULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+          GST_PARAM_MUTABLE_READY));
+
+  g_object_class_install_property (gobject_class, PROP_TIME_SEGMENT,
+      g_param_spec_boolean ("time-segment", "Time Segment",
+          "Emit TIME SEGMENTS", DEFAULT_TIME_SEGMENT, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_STREAM_TIME,
+      g_param_spec_int64 ("stream-time", "Stream Time",
+          "Initial Stream Time (if time-segment TRUE)", 0, G_MAXINT64,
+          DEFAULT_STREAM_TIME, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_START_TIME,
+      g_param_spec_int64 ("start-time", "Start Time",
+          "Initial Start Time (if time-segment TRUE)", 0, G_MAXINT64,
+          DEFAULT_START_TIME, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_INITIAL_TIMESTAMP,
+      g_param_spec_uint64 ("initial-timestamp", "Initial Timestamp",
+          "Initial Buffer Timestamp (if time-segment TRUE)", 0, G_MAXUINT64,
+          DEFAULT_INITIAL_TIMESTAMP, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_RATE,
+      g_param_spec_double ("rate", "Rate", "Rate to use in TIME SEGMENT",
+          G_MINDOUBLE, G_MAXDOUBLE, DEFAULT_RATE, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_APPLIED_RATE,
+      g_param_spec_double ("applied-rate", "Applied Rate",
+          "Applied rate to use in TIME SEGMENT", G_MINDOUBLE, G_MAXDOUBLE,
+          DEFAULT_APPLIED_RATE, G_PARAM_READWRITE));
+
+  gst_element_class_add_static_pad_template (element_class, &srctemplate);
+
+  gst_element_class_set_static_metadata (element_class, "Push File Source",
+      "Testing",
+      "Implements pushfile:// URI-handler for push-based file access",
+      "Tim-Philipp Müller <tim centricular net>");
+}
+
+static void
+gst_push_file_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstPushFileSrc *src = (GstPushFileSrc *) object;
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      g_object_set_property (G_OBJECT (src->filesrc), "location", value);
+      break;
+    case PROP_TIME_SEGMENT:
+      src->time_segment = g_value_get_boolean (value);
+      break;
+    case PROP_STREAM_TIME:
+      src->stream_time = g_value_get_int64 (value);
+      break;
+    case PROP_START_TIME:
+      src->start_time = g_value_get_int64 (value);
+      break;
+    case PROP_INITIAL_TIMESTAMP:
+      src->initial_timestamp = g_value_get_uint64 (value);
+      break;
+    case PROP_RATE:
+      src->rate = g_value_get_double (value);
+      break;
+    case PROP_APPLIED_RATE:
+      src->applied_rate = g_value_get_double (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_push_file_src_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstPushFileSrc *src = (GstPushFileSrc *) object;
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      g_object_get_property (G_OBJECT (src->filesrc), "location", value);
+      break;
+    case PROP_TIME_SEGMENT:
+      g_value_set_boolean (value, src->time_segment);
+      break;
+    case PROP_STREAM_TIME:
+      g_value_set_int64 (value, src->stream_time);
+      break;
+    case PROP_START_TIME:
+      g_value_set_int64 (value, src->start_time);
+      break;
+    case PROP_INITIAL_TIMESTAMP:
+      g_value_set_uint64 (value, src->initial_timestamp);
+      break;
+    case PROP_RATE:
+      g_value_set_double (value, src->rate);
+      break;
+    case PROP_APPLIED_RATE:
+      g_value_set_double (value, src->applied_rate);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstPadProbeReturn
+gst_push_file_src_ghostpad_buffer_probe (GstPad * pad, GstPadProbeInfo * info,
+    GstPushFileSrc * src)
+{
+  GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
+
+  if (src->time_segment && !src->seen_first_buffer) {
+    GST_BUFFER_TIMESTAMP (buffer) = src->initial_timestamp;
+    src->seen_first_buffer = TRUE;
+  }
+  return GST_PAD_PROBE_OK;
+}
+
+static GstPadProbeReturn
+gst_push_file_src_ghostpad_event_probe (GstPad * pad, GstPadProbeInfo * info,
+    GstPushFileSrc * src)
+{
+  GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEGMENT:
+    {
+      if (src->time_segment) {
+        GstSegment segment;
+        GstEvent *replacement;
+        GST_DEBUG_OBJECT (src, "Replacing outgoing segment with TIME SEGMENT");
+        gst_segment_init (&segment, GST_FORMAT_TIME);
+        segment.start = src->start_time;
+        segment.time = src->stream_time;
+        segment.rate = src->rate;
+        segment.applied_rate = src->applied_rate;
+        replacement = gst_event_new_segment (&segment);
+        gst_event_unref (event);
+        GST_PAD_PROBE_INFO_DATA (info) = replacement;
+      }
+    }
+    default:
+      break;
+  }
+  return GST_PAD_PROBE_OK;
+}
+
+static gboolean
+gst_push_file_src_ghostpad_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstPushFileSrc *src = (GstPushFileSrc *) parent;
+  gboolean ret;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+      if (src->time_segment) {
+        /* When working in time we don't allow seeks */
+        GST_DEBUG_OBJECT (src, "Refusing seek event in TIME mode");
+        gst_event_unref (event);
+        ret = FALSE;
+        break;
+      }
+      /* PASSTHROUGH */
+    default:
+      ret = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_push_file_src_ghostpad_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  GstPushFileSrc *src = (GstPushFileSrc *) parent;
+  gboolean res;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_SCHEDULING:
+      /* When working in time we don't allow seeks */
+      if (src->time_segment)
+        gst_query_set_scheduling (query, GST_SCHEDULING_FLAG_SEQUENTIAL, 1, -1,
+            0);
+      else
+        gst_query_set_scheduling (query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1,
+            0);
+      gst_query_add_scheduling_mode (query, GST_PAD_MODE_PUSH);
+      res = TRUE;
+      break;
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+  return res;
+}
+
+static void
+gst_push_file_src_init (GstPushFileSrc * src)
+{
+  src->time_segment = DEFAULT_TIME_SEGMENT;
+  src->stream_time = DEFAULT_STREAM_TIME;
+  src->start_time = DEFAULT_START_TIME;
+  src->initial_timestamp = DEFAULT_INITIAL_TIMESTAMP;
+  src->rate = DEFAULT_RATE;
+  src->applied_rate = DEFAULT_APPLIED_RATE;
+  src->seen_first_buffer = FALSE;
+
+  src->filesrc = gst_element_factory_make ("filesrc", "real-filesrc");
+  if (src->filesrc) {
+    GstPad *pad;
+
+    gst_bin_add (GST_BIN (src), src->filesrc);
+    pad = gst_element_get_static_pad (src->filesrc, "src");
+    g_assert (pad != NULL);
+    src->srcpad = gst_ghost_pad_new ("src", pad);
+    /* FIXME^H^HCORE: try pushfile:///foo/bar.ext ! typefind ! fakesink without
+     * this and watch core bugginess (some pad stays in flushing state) */
+    gst_pad_set_query_function (src->srcpad,
+        GST_DEBUG_FUNCPTR (gst_push_file_src_ghostpad_query));
+    gst_pad_set_event_function (src->srcpad,
+        GST_DEBUG_FUNCPTR (gst_push_file_src_ghostpad_event));
+    /* Add outgoing event probe to replace segment and buffer timestamp */
+    gst_pad_add_probe (src->srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
+        (GstPadProbeCallback) gst_push_file_src_ghostpad_event_probe,
+        src, NULL);
+    gst_pad_add_probe (src->srcpad, GST_PAD_PROBE_TYPE_BUFFER,
+        (GstPadProbeCallback) gst_push_file_src_ghostpad_buffer_probe,
+        src, NULL);
+    gst_element_add_pad (GST_ELEMENT (src), src->srcpad);
+    gst_object_unref (pad);
+  }
+}
+
+/*** GSTURIHANDLER INTERFACE *************************************************/
+
+static GstURIType
+gst_push_file_src_uri_get_type (GType type)
+{
+  return GST_URI_SRC;
+}
+
+static const gchar *const *
+gst_push_file_src_uri_get_protocols (GType type)
+{
+  static const gchar *protocols[] = { "pushfile", NULL };
+
+  return protocols;
+}
+
+static gchar *
+gst_push_file_src_uri_get_uri (GstURIHandler * handler)
+{
+  GstPushFileSrc *src = GST_PUSH_FILE_SRC (handler);
+  gchar *fileuri, *pushfileuri;
+
+  if (src->filesrc == NULL)
+    return NULL;
+
+  fileuri = gst_uri_handler_get_uri (GST_URI_HANDLER (src->filesrc));
+  if (fileuri == NULL)
+    return NULL;
+  pushfileuri = g_strconcat ("push", fileuri, NULL);
+  g_free (fileuri);
+
+  return pushfileuri;
+}
+
+static gboolean
+gst_push_file_src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+    GError ** error)
+{
+  GstPushFileSrc *src = GST_PUSH_FILE_SRC (handler);
+
+  if (src->filesrc == NULL) {
+    g_set_error_literal (error, GST_URI_ERROR, GST_URI_ERROR_BAD_STATE,
+        "Could not create file source element");
+    return FALSE;
+  }
+
+  /* skip 'push' bit */
+  return gst_uri_handler_set_uri (GST_URI_HANDLER (src->filesrc), uri + 4,
+      error);
+}
+
+static void
+gst_push_file_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+  iface->get_type = gst_push_file_src_uri_get_type;
+  iface->get_protocols = gst_push_file_src_uri_get_protocols;
+  iface->get_uri = gst_push_file_src_uri_get_uri;
+  iface->set_uri = gst_push_file_src_uri_set_uri;
+}
diff --git a/gst/debugutils/gstpushfilesrc.h b/gst/debugutils/gstpushfilesrc.h
new file mode 100644
index 0000000..482ae13
--- /dev/null
+++ b/gst/debugutils/gstpushfilesrc.h
@@ -0,0 +1,64 @@
+/* GStreamer Push File Source
+ * Copyright (C) <2007> Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_PUSH_FILE_SRC_H__
+#define __GST_PUSH_FILE_SRC_H__
+
+#include <gst/gstbin.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_PUSH_FILE_SRC \
+  (gst_push_file_src_get_type())
+#define GST_PUSH_FILE_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PUSH_FILE_SRC,GstPushFileSrc))
+#define GST_PUSH_FILE_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PUSH_FILE_SRC,GstPushFileSrcClass))
+#define GST_IS_PUSH_FILE_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PUSH_FILE_SRC))
+#define GST_IS_PUSH_FILE_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PUSH_FILE_SRC))
+typedef struct _GstPushFileSrc GstPushFileSrc;
+typedef struct _GstPushFileSrcClass GstPushFileSrcClass;
+
+struct _GstPushFileSrc
+{
+  GstBin parent;
+
+  /*< private > */
+  GstElement *filesrc;
+  GstPad *srcpad;
+
+  gboolean time_segment;
+  gboolean seen_first_buffer;
+  gint64 stream_time;
+  gint64 start_time;
+  guint64 initial_timestamp;
+  gdouble rate;
+  gdouble applied_rate;
+};
+
+struct _GstPushFileSrcClass
+{
+  GstBinClass parent_class;
+};
+
+GType gst_push_file_src_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_PUSH_FILE_SRC_H__ */
diff --git a/gst/debugutils/gsttaginject.c b/gst/debugutils/gsttaginject.c
new file mode 100644
index 0000000..abdb797
--- /dev/null
+++ b/gst/debugutils/gsttaginject.c
@@ -0,0 +1,203 @@
+/* GStreamer
+ * Copyright (C) 2008 Stefan Kost <ensonic@users.sf.net>
+ *
+ * gsttaginject.c:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-taginject
+ *
+ * Element that injects new metadata tags, but passes incomming data through
+ * unmodified.
+ *
+ * <refsect2>
+ * <title>Example launch lines</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc num-buffers=100 ! taginject tags="title=testsrc,artist=gstreamer" ! vorbisenc ! oggmux ! filesink location=test.ogg
+ * ]| set title and artist
+ * |[
+ * gst-launch-1.0 audiotestsrc num-buffers=100 ! taginject tags="keywords=\{\"testone\",\"audio\"\},title=\"audio\ testtone\"" ! vorbisenc ! oggmux ! filesink location=test.ogg
+ * ]| set keywords and title demonstrating quoting of special chars and handling lists
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "gsttaginject.h"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (gst_tag_inject_debug);
+#define GST_CAT_DEFAULT gst_tag_inject_debug
+
+enum
+{
+  PROP_TAGS = 1
+};
+
+
+#define gst_tag_inject_parent_class parent_class
+G_DEFINE_TYPE (GstTagInject, gst_tag_inject, GST_TYPE_BASE_TRANSFORM);
+
+static void gst_tag_inject_finalize (GObject * object);
+static void gst_tag_inject_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_tag_inject_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstFlowReturn gst_tag_inject_transform_ip (GstBaseTransform * trans,
+    GstBuffer * buf);
+static gboolean gst_tag_inject_start (GstBaseTransform * trans);
+
+
+static void
+gst_tag_inject_finalize (GObject * object)
+{
+  GstTagInject *self = GST_TAG_INJECT (object);
+
+  if (self->tags) {
+    gst_tag_list_unref (self->tags);
+    self->tags = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_tag_inject_class_init (GstTagInjectClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseTransformClass *gstbasetrans_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gstelement_class = GST_ELEMENT_CLASS (klass);
+  gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (gst_tag_inject_debug, "taginject", 0,
+      "tag inject element");
+
+  gobject_class->set_property = gst_tag_inject_set_property;
+  gobject_class->get_property = gst_tag_inject_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_TAGS,
+      g_param_spec_string ("tags", "taglist",
+          "List of tags to inject into the target file",
+          NULL, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+
+  gobject_class->finalize = gst_tag_inject_finalize;
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "TagInject",
+      "Generic", "inject metadata tags", "Stefan Kost <ensonic@users.sf.net>");
+  gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
+  gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
+
+  gstbasetrans_class->transform_ip =
+      GST_DEBUG_FUNCPTR (gst_tag_inject_transform_ip);
+
+  gstbasetrans_class->start = GST_DEBUG_FUNCPTR (gst_tag_inject_start);
+}
+
+static void
+gst_tag_inject_init (GstTagInject * self)
+{
+  GstBaseTransform *trans = GST_BASE_TRANSFORM (self);
+
+  gst_base_transform_set_gap_aware (trans, TRUE);
+
+  self->tags = NULL;
+}
+
+static GstFlowReturn
+gst_tag_inject_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
+{
+  GstTagInject *self = GST_TAG_INJECT (trans);
+
+  if (G_UNLIKELY (!self->tags_sent)) {
+    self->tags_sent = TRUE;
+    /* send tags */
+    if (self->tags && !gst_tag_list_is_empty (self->tags)) {
+      GST_DEBUG ("tag event :%" GST_PTR_FORMAT, self->tags);
+      gst_pad_push_event (GST_BASE_TRANSFORM_SRC_PAD (trans),
+          gst_event_new_tag (gst_tag_list_ref (self->tags)));
+    }
+  }
+
+  return GST_FLOW_OK;
+}
+
+static void
+gst_tag_inject_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstTagInject *self = GST_TAG_INJECT (object);
+
+  switch (prop_id) {
+    case PROP_TAGS:{
+      gchar *structure =
+          g_strdup_printf ("taglist,%s", g_value_get_string (value));
+      if (!(self->tags = gst_tag_list_new_from_string (structure))) {
+        GST_WARNING ("unparsable taglist = '%s'", structure);
+      }
+
+      /* make sure that tags will be send */
+      self->tags_sent = FALSE;
+      g_free (structure);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_tag_inject_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  /*GstTagInject *self = GST_TAG_INJECT (object); */
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_tag_inject_start (GstBaseTransform * trans)
+{
+  GstTagInject *self = GST_TAG_INJECT (trans);
+
+  /* we need to sent tags _transform_ip() once */
+  self->tags_sent = FALSE;
+
+  return TRUE;
+}
diff --git a/gst/debugutils/gsttaginject.h b/gst/debugutils/gsttaginject.h
new file mode 100644
index 0000000..a545927
--- /dev/null
+++ b/gst/debugutils/gsttaginject.h
@@ -0,0 +1,66 @@
+/* GStreamer
+ * Copyright (C) 2008 Stefan Kost <ensonic@users.sf.net>
+ *
+ * gsttaginject.h:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_TAG_INJECT_H__
+#define __GST_TAG_INJECT_H__
+
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_TAG_INJECT \
+  (gst_tag_inject_get_type())
+#define GST_TAG_INJECT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TAG_INJECT,GstTagInject))
+#define GST_TAG_INJECT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TAG_INJECT,GstTagInjectClass))
+#define GST_IS_TAG_INJECT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TAG_INJECT))
+#define GST_IS_TAG_INJECT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TAG_INJECT))
+typedef struct _GstTagInject GstTagInject;
+typedef struct _GstTagInjectClass GstTagInjectClass;
+
+/**
+ * GstTagInject:
+ *
+ * Opaque #GstTagInject data structure
+ */
+struct _GstTagInject
+{
+  GstBaseTransform element;
+
+  /*< private > */
+  GstTagList *tags;
+  gboolean tags_sent;
+};
+
+struct _GstTagInjectClass
+{
+  GstBaseTransformClass parent_class;
+};
+
+GType gst_tag_inject_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_TAG_INJECT_H__ */
diff --git a/gst/debugutils/meson.build b/gst/debugutils/meson.build
new file mode 100644
index 0000000..d180577
--- /dev/null
+++ b/gst/debugutils/meson.build
@@ -0,0 +1,27 @@
+gstnavigationtest = library('gstnavigationtest',
+  'gstnavigationtest.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstbase_dep, gstvideo_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
+
+gstdebug = library('gstdebug',
+  'gstdebug.c',
+  'breakmydata.c',
+  'gstcapssetter.c',
+  'gstnavseek.c',
+  'gstpushfilesrc.c',
+  'gsttaginject.c',
+  'rndbuffersize.c',
+  'progressreport.c',
+  'tests.c',
+  'cpureport.c',
+  'testplugin.c',
+  c_args: gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gst_dep, gstbase_dep, gstvideo_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/debugutils/progressreport.c b/gst/debugutils/progressreport.c
new file mode 100644
index 0000000..906bf0f
--- /dev/null
+++ b/gst/debugutils/progressreport.c
@@ -0,0 +1,521 @@
+/* GStreamer Progress Report Element
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ * Copyright (C) <2004> Jan Schmidt <thaytan@mad.scientist.com>
+ * Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-progressreport
+ *
+ * The progressreport element can be put into a pipeline to report progress,
+ * which is done by doing upstream duration and position queries in regular
+ * (real-time) intervals. Both the interval and the prefered query format
+ * can be specified via the #GstProgressReport:update-freq and the
+ * #GstProgressReport:format property.
+ *
+ * Element messages containing a "progress" structure are posted on the bus
+ * whenever progress has been queried (since gst-plugins-good 0.10.6 only).
+ *
+ * Since the element was originally designed for debugging purposes, it will
+ * by default also print information about the current progress to the
+ * terminal. This can be prevented by setting the #GstProgressReport:silent
+ * property to %TRUE.
+ *
+ * This element is most useful in transcoding pipelines or other situations
+ * where just querying the pipeline might not lead to the wanted result. For
+ * progress in TIME format, the element is best placed in a 'raw stream'
+ * section of the pipeline (or after any demuxers/decoders/parsers).
+ *
+ * Three more things should be pointed out: firstly, the element will only
+ * query progress when data flow happens. If data flow is stalled for some
+ * reason, no progress messages will be posted. Secondly, there are other
+ * elements (like qtdemux, for example) that may also post "progress" element
+ * messages on the bus. Applications should check the source of any element
+ * messages they receive, if needed. Finally, applications should not take
+ * action on receiving notification of progress being 100%, they should only
+ * take action when they receive an EOS message (since the progress reported
+ * is in reference to an internal point of a pipeline and not the pipeline as
+ * a whole).
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -m filesrc location=foo.ogg ! decodebin ! progressreport update-freq=1 ! audioconvert ! audioresample ! autoaudiosink
+ * ]| This shows a progress query where a duration is available.
+ * |[
+ * gst-launch-1.0 -m audiotestsrc ! progressreport update-freq=1 ! audioconvert ! autoaudiosink
+ * ]| This shows a progress query where no duration is available.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+
+#include "progressreport.h"
+
+
+enum
+{
+  PROP_0,
+  PROP_UPDATE_FREQ,
+  PROP_SILENT,
+  PROP_DO_QUERY,
+  PROP_FORMAT
+};
+
+GstStaticPadTemplate progress_report_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+GstStaticPadTemplate progress_report_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+#define DEFAULT_UPDATE_FREQ  5
+#define DEFAULT_SILENT       FALSE
+#define DEFAULT_DO_QUERY     TRUE
+#define DEFAULT_FORMAT       "auto"
+
+static void gst_progress_report_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_progress_report_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_progress_report_sink_event (GstBaseTransform * trans,
+    GstEvent * event);
+static GstFlowReturn gst_progress_report_transform_ip (GstBaseTransform * trans,
+    GstBuffer * buf);
+
+static gboolean gst_progress_report_start (GstBaseTransform * trans);
+static gboolean gst_progress_report_stop (GstBaseTransform * trans);
+
+#define gst_progress_report_parent_class parent_class
+G_DEFINE_TYPE (GstProgressReport, gst_progress_report, GST_TYPE_BASE_TRANSFORM);
+
+static void
+gst_progress_report_finalize (GObject * obj)
+{
+  GstProgressReport *filter = GST_PROGRESS_REPORT (obj);
+
+  g_free (filter->format);
+  filter->format = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gst_progress_report_class_init (GstProgressReportClass * g_class)
+{
+  GstBaseTransformClass *gstbasetrans_class;
+  GstElementClass *element_class;
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (g_class);
+  element_class = GST_ELEMENT_CLASS (g_class);
+  gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (g_class);
+
+  gobject_class->finalize = gst_progress_report_finalize;
+  gobject_class->set_property = gst_progress_report_set_property;
+  gobject_class->get_property = gst_progress_report_get_property;
+
+  g_object_class_install_property (gobject_class,
+      PROP_UPDATE_FREQ, g_param_spec_int ("update-freq", "Update Frequency",
+          "Number of seconds between reports when data is flowing", 1, G_MAXINT,
+          DEFAULT_UPDATE_FREQ, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_SILENT, g_param_spec_boolean ("silent",
+          "Do not print output to stdout", "Do not print output to stdout",
+          DEFAULT_SILENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_DO_QUERY, g_param_spec_boolean ("do-query",
+          "Use a query instead of buffer metadata to determine stream position",
+          "Use a query instead of buffer metadata to determine stream position",
+          DEFAULT_DO_QUERY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_FORMAT, g_param_spec_string ("format", "format",
+          "Format to use for the querying", DEFAULT_FORMAT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (element_class,
+      &progress_report_sink_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &progress_report_src_template);
+
+  gst_element_class_set_static_metadata (element_class, "Progress report",
+      "Testing",
+      "Periodically query and report on processing progress",
+      "Jan Schmidt <thaytan@mad.scientist.com>");
+
+  gstbasetrans_class->sink_event =
+      GST_DEBUG_FUNCPTR (gst_progress_report_sink_event);
+  gstbasetrans_class->transform_ip =
+      GST_DEBUG_FUNCPTR (gst_progress_report_transform_ip);
+  gstbasetrans_class->start = GST_DEBUG_FUNCPTR (gst_progress_report_start);
+  gstbasetrans_class->stop = GST_DEBUG_FUNCPTR (gst_progress_report_stop);
+}
+
+static void
+gst_progress_report_init (GstProgressReport * report)
+{
+  gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (report), TRUE);
+
+  report->update_freq = DEFAULT_UPDATE_FREQ;
+  report->silent = DEFAULT_SILENT;
+  report->do_query = DEFAULT_DO_QUERY;
+  report->format = g_strdup (DEFAULT_FORMAT);
+}
+
+static void
+gst_progress_report_post_progress (GstProgressReport * filter,
+    GstFormat format, gint64 current, gint64 total)
+{
+  GstStructure *s = NULL;
+
+  if (current >= 0 && total > 0) {
+    gdouble perc;
+
+    perc = gst_util_guint64_to_gdouble (current) * 100.0 /
+        gst_util_guint64_to_gdouble (total);
+    perc = CLAMP (perc, 0.0, 100.0);
+
+    /* we provide a "percent" field of integer type to stay compatible
+     * with qtdemux, but add a second "percent-double" field for those who
+     * want more precision and are too lazy to calculate it themselves */
+    s = gst_structure_new ("progress", "percent", G_TYPE_INT, (gint) perc,
+        "percent-double", G_TYPE_DOUBLE, perc, "current", G_TYPE_INT64, current,
+        "total", G_TYPE_INT64, total, NULL);
+  } else if (current >= 0) {
+    s = gst_structure_new ("progress", "current", G_TYPE_INT64, current, NULL);
+  }
+
+  if (s) {
+    GST_LOG_OBJECT (filter, "posting progress message: %" GST_PTR_FORMAT, s);
+    gst_structure_set (s, "format", GST_TYPE_FORMAT, format, NULL);
+    /* can't post it right here because we're holding the object lock */
+    filter->pending_msg = gst_message_new_element (GST_OBJECT_CAST (filter), s);
+  }
+}
+
+static gboolean
+gst_progress_report_do_query (GstProgressReport * filter, GstFormat format,
+    gint hh, gint mm, gint ss, GstBuffer * buf)
+{
+  const gchar *format_name = NULL;
+  GstPad *sink_pad;
+  gint64 cur, total;
+
+  sink_pad = GST_BASE_TRANSFORM (filter)->sinkpad;
+
+  GST_LOG_OBJECT (filter, "querying using format %d (%s)", format,
+      gst_format_get_name (format));
+
+  if (filter->do_query || !buf) {
+    GST_LOG_OBJECT (filter, "using upstream query");
+    if (!gst_pad_peer_query_position (sink_pad, format, &cur) ||
+        !gst_pad_peer_query_duration (sink_pad, format, &total)) {
+      return FALSE;
+    }
+  } else {
+    GstBaseTransform *base = GST_BASE_TRANSFORM (filter);
+
+    GST_LOG_OBJECT (filter, "using buffer metadata");
+    if (format == GST_FORMAT_TIME && base->segment.format == GST_FORMAT_TIME) {
+      cur = gst_segment_to_stream_time (&base->segment, format,
+          GST_BUFFER_TIMESTAMP (buf));
+      total = base->segment.duration;
+    } else if (format == GST_FORMAT_BUFFERS) {
+      cur = filter->buffer_count;
+      total = -1;
+    } else {
+      return FALSE;
+    }
+  }
+
+  switch (format) {
+    case GST_FORMAT_BYTES:
+      format_name = "bytes";
+      break;
+    case GST_FORMAT_BUFFERS:
+      format_name = "buffers";
+      break;
+    case GST_FORMAT_PERCENT:
+      format_name = "percent";
+      break;
+    case GST_FORMAT_TIME:
+      format_name = "seconds";
+      cur /= GST_SECOND;
+      total /= GST_SECOND;
+      break;
+    case GST_FORMAT_DEFAULT:{
+      GstCaps *caps;
+
+      format_name = "bogounits";
+      caps = gst_pad_get_current_caps (GST_BASE_TRANSFORM (filter)->sinkpad);
+      if (caps) {
+        if (gst_caps_is_fixed (caps) && !gst_caps_is_any (caps)) {
+          GstStructure *s = gst_caps_get_structure (caps, 0);
+          const gchar *mime_type = gst_structure_get_name (s);
+
+          if (g_str_has_prefix (mime_type, "video/") ||
+              g_str_has_prefix (mime_type, "image/")) {
+            format_name = "frames";
+          } else if (g_str_has_prefix (mime_type, "audio/")) {
+            format_name = "samples";
+          }
+        }
+        gst_caps_unref (caps);
+      }
+      break;
+    }
+    default:{
+      const GstFormatDefinition *details;
+
+      details = gst_format_get_details (format);
+      if (details) {
+        format_name = details->nick;
+      } else {
+        format_name = "unknown";
+      }
+      break;
+    }
+  }
+
+  if (!filter->silent) {
+    if (total > 0) {
+      g_print ("%s (%02d:%02d:%02d): %" G_GINT64_FORMAT " / %"
+          G_GINT64_FORMAT " %s (%4.1f %%)\n", GST_OBJECT_NAME (filter), hh,
+          mm, ss, cur, total, format_name, (gdouble) cur / total * 100.0);
+    } else {
+      g_print ("%s (%02d:%02d:%02d): %" G_GINT64_FORMAT " %s\n",
+          GST_OBJECT_NAME (filter), hh, mm, ss, cur, format_name);
+    }
+  }
+
+  gst_progress_report_post_progress (filter, format, cur, total);
+  return TRUE;
+}
+
+static void
+gst_progress_report_report (GstProgressReport * filter, GTimeVal cur_time,
+    GstBuffer * buf)
+{
+  GstFormat try_formats[] = { GST_FORMAT_TIME, GST_FORMAT_BYTES,
+    GST_FORMAT_PERCENT, GST_FORMAT_BUFFERS,
+    GST_FORMAT_DEFAULT
+  };
+  GstMessage *msg;
+  GstFormat format = GST_FORMAT_UNDEFINED;
+  gboolean done = FALSE;
+  glong run_time;
+  gint hh, mm, ss;
+
+  run_time = cur_time.tv_sec - filter->start_time.tv_sec;
+
+  hh = (run_time / 3600) % 100;
+  mm = (run_time / 60) % 60;
+  ss = (run_time % 60);
+
+  GST_OBJECT_LOCK (filter);
+
+  if (filter->format != NULL && strcmp (filter->format, "auto") != 0) {
+    format = gst_format_get_by_nick (filter->format);
+  }
+
+  if (format != GST_FORMAT_UNDEFINED) {
+    done = gst_progress_report_do_query (filter, format, hh, mm, ss, buf);
+  } else {
+    gint i;
+
+    for (i = 0; i < G_N_ELEMENTS (try_formats); ++i) {
+      done = gst_progress_report_do_query (filter, try_formats[i], hh, mm, ss,
+          buf);
+      if (done)
+        break;
+    }
+  }
+
+  if (!done && !filter->silent) {
+    g_print ("%s (%2d:%2d:%2d): Could not query position and/or duration\n",
+        GST_OBJECT_NAME (filter), hh, mm, ss);
+  }
+
+  msg = filter->pending_msg;
+  filter->pending_msg = NULL;
+  GST_OBJECT_UNLOCK (filter);
+
+  if (msg) {
+    gst_element_post_message (GST_ELEMENT_CAST (filter), msg);
+  }
+}
+
+static gboolean
+gst_progress_report_sink_event (GstBaseTransform * trans, GstEvent * event)
+{
+  GstProgressReport *filter;
+
+  filter = GST_PROGRESS_REPORT (trans);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+    {
+      GTimeVal cur_time;
+
+      g_get_current_time (&cur_time);
+      gst_progress_report_report (filter, cur_time, NULL);
+      break;
+    }
+    default:
+      break;
+  }
+  return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
+}
+
+static GstFlowReturn
+gst_progress_report_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
+{
+  GstProgressReport *filter;
+  gboolean need_update;
+  GTimeVal cur_time;
+
+  g_get_current_time (&cur_time);
+
+  filter = GST_PROGRESS_REPORT (trans);
+
+  /* Check if update_freq seconds have passed since the last update */
+  GST_OBJECT_LOCK (filter);
+  need_update =
+      ((cur_time.tv_sec - filter->last_report.tv_sec) >= filter->update_freq);
+  filter->buffer_count++;
+  GST_OBJECT_UNLOCK (filter);
+
+  if (need_update) {
+    gst_progress_report_report (filter, cur_time, buf);
+    GST_OBJECT_LOCK (filter);
+    filter->last_report = cur_time;
+    GST_OBJECT_UNLOCK (filter);
+  }
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_progress_report_start (GstBaseTransform * trans)
+{
+  GstProgressReport *filter;
+
+  filter = GST_PROGRESS_REPORT (trans);
+
+  g_get_current_time (&filter->last_report);
+  filter->start_time = filter->last_report;
+  filter->buffer_count = 0;
+
+  return TRUE;
+}
+
+static gboolean
+gst_progress_report_stop (GstBaseTransform * trans)
+{
+  /* anything we should be doing here? */
+  return TRUE;
+}
+
+static void
+gst_progress_report_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstProgressReport *filter;
+
+  filter = GST_PROGRESS_REPORT (object);
+
+  switch (prop_id) {
+    case PROP_UPDATE_FREQ:
+      GST_OBJECT_LOCK (filter);
+      filter->update_freq = g_value_get_int (value);
+      GST_OBJECT_UNLOCK (filter);
+      break;
+    case PROP_SILENT:
+      GST_OBJECT_LOCK (filter);
+      filter->silent = g_value_get_boolean (value);
+      GST_OBJECT_UNLOCK (filter);
+      break;
+    case PROP_DO_QUERY:
+      GST_OBJECT_LOCK (filter);
+      filter->do_query = g_value_get_boolean (value);
+      GST_OBJECT_UNLOCK (filter);
+      break;
+    case PROP_FORMAT:
+      GST_OBJECT_LOCK (filter);
+      g_free (filter->format);
+      filter->format = g_value_dup_string (value);
+      if (filter->format == NULL)
+        filter->format = g_strdup ("auto");
+      GST_OBJECT_UNLOCK (filter);
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_progress_report_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstProgressReport *filter;
+
+  filter = GST_PROGRESS_REPORT (object);
+
+  switch (prop_id) {
+    case PROP_UPDATE_FREQ:
+      GST_OBJECT_LOCK (filter);
+      g_value_set_int (value, filter->update_freq);
+      GST_OBJECT_UNLOCK (filter);
+      break;
+    case PROP_SILENT:
+      GST_OBJECT_LOCK (filter);
+      g_value_set_boolean (value, filter->silent);
+      GST_OBJECT_UNLOCK (filter);
+      break;
+    case PROP_DO_QUERY:
+      GST_OBJECT_LOCK (filter);
+      g_value_set_boolean (value, filter->do_query);
+      GST_OBJECT_UNLOCK (filter);
+      break;
+    case PROP_FORMAT:
+      GST_OBJECT_LOCK (filter);
+      g_value_set_string (value, filter->format);
+      GST_OBJECT_UNLOCK (filter);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/gst/debugutils/progressreport.h b/gst/debugutils/progressreport.h
new file mode 100644
index 0000000..d990937
--- /dev/null
+++ b/gst/debugutils/progressreport.h
@@ -0,0 +1,68 @@
+/* GStreamer Progress Report Element
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ * Copyright (C) <2004> Jan Schmidt <thaytan@mad.scientist.com>
+ * Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_PROGRESS_REPORT_H__
+#define __GST_PROGRESS_REPORT_H__
+
+#include <gst/base/gstbasetransform.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_PROGRESS_REPORT \
+  (gst_progress_report_get_type())
+#define GST_PROGRESS_REPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PROGRESS_REPORT,GstProgressReport))
+#define GST_PROGRESS_REPORT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PROGRESS_REPORT,GstProgressReportClass))
+#define GST_IS_PROGRESS_REPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PROGRESS_REPORT))
+#define GST_IS_PROGRESS_REPORT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PROGRESS_REPORT))
+typedef struct _GstProgressReport GstProgressReport;
+typedef struct _GstProgressReportClass GstProgressReportClass;
+
+struct _GstProgressReport
+{
+  GstBaseTransform basetransform;
+
+  GstMessage *pending_msg;
+
+  gint update_freq;
+  gboolean silent;
+  gboolean do_query;
+  GTimeVal start_time;
+  GTimeVal last_report;
+  gint64 buffer_count;
+
+  /* Format used for querying. Using a string here because the
+   * format might not be registered yet when the property is set */
+  gchar *format;
+};
+
+struct _GstProgressReportClass
+{
+  GstBaseTransformClass parent_class;
+};
+
+GType gst_progress_report_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_PROGRESS_REPORT_H__ */
diff --git a/gst/debugutils/rndbuffersize.c b/gst/debugutils/rndbuffersize.c
new file mode 100644
index 0000000..d33a23c
--- /dev/null
+++ b/gst/debugutils/rndbuffersize.c
@@ -0,0 +1,576 @@
+/* GStreamer
+ * Copyright (C) 2007 Nokia Corporation (contact <stefan.kost@nokia.com>)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-rndbuffersize
+ *
+ * This element pulls buffers with random sizes from the source.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_rnd_buffer_size_debug);
+#define GST_CAT_DEFAULT gst_rnd_buffer_size_debug
+
+#define GST_TYPE_RND_BUFFER_SIZE            (gst_rnd_buffer_size_get_type())
+#define GST_RND_BUFFER_SIZE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RND_BUFFER_SIZE,GstRndBufferSize))
+#define GST_RND_BUFFER_SIZE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RND_BUFFER_SIZE,GstRndBufferSizeClass))
+#define GST_IS_RND_BUFFER_SIZE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RND_BUFFER_SIZE))
+#define GST_IS_RND_BUFFER_SIZE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RND_BUFFER_SIZE))
+
+typedef struct _GstRndBufferSize GstRndBufferSize;
+typedef struct _GstRndBufferSizeClass GstRndBufferSizeClass;
+
+struct _GstRndBufferSize
+{
+  GstElement parent;
+
+  /*< private > */
+  GRand *rand;
+  guint seed;
+  gint min, max;
+
+  GstPad *sinkpad, *srcpad;
+  guint64 offset;
+
+  gboolean need_newsegment;
+
+  GstAdapter *adapter;
+};
+
+struct _GstRndBufferSizeClass
+{
+  GstElementClass parent_class;
+};
+
+enum
+{
+  PROP_SEED = 1,
+  PROP_MINIMUM,
+  PROP_MAXIMUM
+};
+
+#define DEFAULT_SEED 0
+#define DEFAULT_MIN  1
+#define DEFAULT_MAX  (8*1024)
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static void gst_rnd_buffer_size_finalize (GObject * object);
+static void gst_rnd_buffer_size_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rnd_buffer_size_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_rnd_buffer_size_activate (GstPad * pad, GstObject * parent);
+static gboolean gst_rnd_buffer_size_activate_mode (GstPad * pad,
+    GstObject * parent, GstPadMode mode, gboolean active);
+static void gst_rnd_buffer_size_loop (GstRndBufferSize * self);
+static GstStateChangeReturn gst_rnd_buffer_size_change_state (GstElement *
+    element, GstStateChange transition);
+static gboolean gst_rnd_buffer_size_src_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static gboolean gst_rnd_buffer_size_sink_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static GstFlowReturn gst_rnd_buffer_size_chain (GstPad * pad,
+    GstObject * parent, GstBuffer * buffer);
+
+GType gst_rnd_buffer_size_get_type (void);
+#define gst_rnd_buffer_size_parent_class parent_class
+G_DEFINE_TYPE (GstRndBufferSize, gst_rnd_buffer_size, GST_TYPE_ELEMENT);
+
+static void
+gst_rnd_buffer_size_class_init (GstRndBufferSizeClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (gst_rnd_buffer_size_debug, "rndbuffersize", 0,
+      "rndbuffersize element");
+
+  gobject_class->set_property = gst_rnd_buffer_size_set_property;
+  gobject_class->get_property = gst_rnd_buffer_size_get_property;
+  gobject_class->finalize = gst_rnd_buffer_size_finalize;
+
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class, &src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "Random buffer size",
+      "Testing", "pull random sized buffers",
+      "Stefan Kost <stefan.kost@nokia.com>");
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_rnd_buffer_size_change_state);
+
+  g_object_class_install_property (gobject_class, PROP_SEED,
+      g_param_spec_uint ("seed", "random number seed",
+          "seed for randomness (initialized when going from READY to PAUSED)",
+          0, G_MAXUINT32, DEFAULT_SEED,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MINIMUM,
+      g_param_spec_int ("min", "mininum", "mininum buffer size",
+          0, G_MAXINT32, DEFAULT_MIN,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MAXIMUM,
+      g_param_spec_int ("max", "maximum", "maximum buffer size",
+          1, G_MAXINT32, DEFAULT_MAX,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_rnd_buffer_size_init (GstRndBufferSize * self)
+{
+  self->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
+  gst_pad_set_activate_function (self->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rnd_buffer_size_activate));
+  gst_pad_set_activatemode_function (self->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rnd_buffer_size_activate_mode));
+  gst_pad_set_event_function (self->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rnd_buffer_size_sink_event));
+  gst_pad_set_chain_function (self->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rnd_buffer_size_chain));
+  GST_OBJECT_FLAG_SET (self->sinkpad, GST_PAD_FLAG_PROXY_CAPS);
+  GST_OBJECT_FLAG_SET (self->sinkpad, GST_PAD_FLAG_PROXY_ALLOCATION);
+  GST_OBJECT_FLAG_SET (self->sinkpad, GST_PAD_FLAG_PROXY_SCHEDULING);
+  gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
+
+  self->srcpad = gst_pad_new_from_static_template (&src_template, "src");
+  gst_pad_set_event_function (self->srcpad,
+      GST_DEBUG_FUNCPTR (gst_rnd_buffer_size_src_event));
+  GST_OBJECT_FLAG_SET (self->srcpad, GST_PAD_FLAG_PROXY_CAPS);
+  GST_OBJECT_FLAG_SET (self->srcpad, GST_PAD_FLAG_PROXY_ALLOCATION);
+  GST_OBJECT_FLAG_SET (self->srcpad, GST_PAD_FLAG_PROXY_SCHEDULING);
+  gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
+}
+
+
+static void
+gst_rnd_buffer_size_finalize (GObject * object)
+{
+  GstRndBufferSize *self = GST_RND_BUFFER_SIZE (object);
+
+  if (self->rand) {
+    g_rand_free (self->rand);
+    self->rand = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gst_rnd_buffer_size_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRndBufferSize *self = GST_RND_BUFFER_SIZE (object);
+
+  switch (prop_id) {
+    case PROP_SEED:
+      self->seed = g_value_get_uint (value);
+      break;
+    case PROP_MINIMUM:
+      self->min = g_value_get_int (value);
+      break;
+    case PROP_MAXIMUM:
+      self->max = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+
+static void
+gst_rnd_buffer_size_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRndBufferSize *self = GST_RND_BUFFER_SIZE (object);
+
+  switch (prop_id) {
+    case PROP_SEED:
+      g_value_set_uint (value, self->seed);
+      break;
+    case PROP_MINIMUM:
+      g_value_set_int (value, self->min);
+      break;
+    case PROP_MAXIMUM:
+      g_value_set_int (value, self->max);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+
+static gboolean
+gst_rnd_buffer_size_activate (GstPad * pad, GstObject * parent)
+{
+  GstQuery *query;
+  gboolean pull_mode;
+
+  query = gst_query_new_scheduling ();
+
+  if (gst_pad_peer_query (pad, query))
+    pull_mode = gst_query_has_scheduling_mode_with_flags (query,
+        GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
+  else
+    pull_mode = FALSE;
+
+  gst_query_unref (query);
+
+  if (pull_mode) {
+    GST_DEBUG_OBJECT (pad, "activating pull");
+    return gst_pad_activate_mode (pad, GST_PAD_MODE_PULL, TRUE);
+  } else {
+    GST_DEBUG_OBJECT (pad, "activating push");
+    return gst_pad_activate_mode (pad, GST_PAD_MODE_PUSH, TRUE);
+  }
+}
+
+
+static gboolean
+gst_rnd_buffer_size_activate_mode (GstPad * pad, GstObject * parent,
+    GstPadMode mode, gboolean active)
+{
+  gboolean res;
+  GstRndBufferSize *self = GST_RND_BUFFER_SIZE (parent);
+
+  switch (mode) {
+    case GST_PAD_MODE_PULL:
+      if (active) {
+        GST_INFO_OBJECT (self, "starting pull");
+        res =
+            gst_pad_start_task (pad, (GstTaskFunction) gst_rnd_buffer_size_loop,
+            self, NULL);
+        self->need_newsegment = TRUE;
+      } else {
+        GST_INFO_OBJECT (self, "stopping pull");
+        res = gst_pad_stop_task (pad);
+      }
+      break;
+    case GST_PAD_MODE_PUSH:
+      GST_INFO_OBJECT (self, "%sactivating in push mode", (active) ? "" : "de");
+      res = TRUE;
+      break;
+    default:
+      res = FALSE;
+      break;
+  }
+  return res;
+}
+
+static gboolean
+gst_rnd_buffer_size_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstRndBufferSize *self;
+  GstSeekType start_type;
+  GstSeekFlags flags;
+  GstFormat format;
+  gint64 start;
+
+  if (GST_EVENT_TYPE (event) != GST_EVENT_SEEK) {
+    return gst_pad_event_default (pad, parent, event);
+  }
+
+  self = GST_RND_BUFFER_SIZE (parent);
+  gst_event_parse_seek (event, NULL, &format, &flags, &start_type, &start,
+      NULL, NULL);
+
+  if (format != GST_FORMAT_BYTES) {
+    GST_WARNING_OBJECT (pad, "only BYTE format supported");
+    return FALSE;
+  }
+  if (start_type != GST_SEEK_TYPE_SET) {
+    GST_WARNING_OBJECT (pad, "only SEEK_TYPE_SET supported");
+    return FALSE;
+  }
+
+  if ((flags & GST_SEEK_FLAG_FLUSH)) {
+    gst_pad_push_event (self->srcpad, gst_event_new_flush_start ());
+    gst_pad_push_event (self->sinkpad, gst_event_new_flush_start ());
+  } else {
+    gst_pad_pause_task (self->sinkpad);
+  }
+
+  GST_PAD_STREAM_LOCK (self->sinkpad);
+
+  if ((flags & GST_SEEK_FLAG_FLUSH)) {
+    gst_pad_push_event (self->srcpad, gst_event_new_flush_stop (TRUE));
+    gst_pad_push_event (self->sinkpad, gst_event_new_flush_stop (TRUE));
+  }
+
+  GST_INFO_OBJECT (pad, "seeking to offset %" G_GINT64_FORMAT, start);
+
+  self->offset = start;
+  self->need_newsegment = TRUE;
+
+  gst_pad_start_task (self->sinkpad, (GstTaskFunction) gst_rnd_buffer_size_loop,
+      self, NULL);
+
+  GST_PAD_STREAM_UNLOCK (self->sinkpad);
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_rnd_buffer_size_drain_adapter (GstRndBufferSize * self, gboolean eos)
+{
+  GstFlowReturn flow;
+  GstBuffer *buf;
+  guint num_bytes, avail;
+
+  flow = GST_FLOW_OK;
+
+  if (G_UNLIKELY (self->min > self->max))
+    goto bogus_minmax;
+
+  do {
+    if (self->min != self->max) {
+      num_bytes = g_rand_int_range (self->rand, self->min, self->max);
+    } else {
+      num_bytes = self->min;
+    }
+
+    GST_LOG_OBJECT (self, "pulling %u bytes out of adapter", num_bytes);
+
+    buf = gst_adapter_take_buffer (self->adapter, num_bytes);
+
+    if (buf == NULL) {
+      if (!eos) {
+        GST_LOG_OBJECT (self, "not enough bytes in adapter");
+        break;
+      }
+
+      avail = gst_adapter_available (self->adapter);
+
+      if (avail == 0)
+        break;
+
+      if (avail < self->min) {
+        GST_WARNING_OBJECT (self, "discarding %u bytes at end (min=%u)",
+            avail, self->min);
+        gst_adapter_clear (self->adapter);
+        break;
+      }
+      buf = gst_adapter_take_buffer (self->adapter, avail);
+      g_assert (buf != NULL);
+    }
+
+    flow = gst_pad_push (self->srcpad, buf);
+  }
+  while (flow == GST_FLOW_OK);
+
+  return flow;
+
+/* ERRORS */
+bogus_minmax:
+  {
+    GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS,
+        ("The minimum buffer size is smaller than the maximum buffer size."),
+        ("buffer sizes: max=%d, min=%d", self->min, self->max));
+    return GST_FLOW_ERROR;
+  }
+}
+
+static gboolean
+gst_rnd_buffer_size_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstRndBufferSize *rnd = GST_RND_BUFFER_SIZE (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+      gst_rnd_buffer_size_drain_adapter (rnd, TRUE);
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      if (rnd->adapter != NULL)
+        gst_adapter_clear (rnd->adapter);
+      break;
+    default:
+      break;
+  }
+
+  return gst_pad_event_default (pad, parent, event);
+}
+
+static GstFlowReturn
+gst_rnd_buffer_size_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstRndBufferSize *rnd = GST_RND_BUFFER_SIZE (parent);
+  GstFlowReturn flow;
+
+  if (rnd->adapter == NULL)
+    rnd->adapter = gst_adapter_new ();
+
+  gst_adapter_push (rnd->adapter, buf);
+
+  flow = gst_rnd_buffer_size_drain_adapter (rnd, FALSE);
+
+  if (flow != GST_FLOW_OK)
+    GST_INFO_OBJECT (rnd, "flow: %s", gst_flow_get_name (flow));
+
+  return flow;
+}
+
+static void
+gst_rnd_buffer_size_loop (GstRndBufferSize * self)
+{
+  GstBuffer *buf = NULL;
+  GstFlowReturn ret;
+  guint num_bytes, size;
+
+  if (G_UNLIKELY (self->min > self->max))
+    goto bogus_minmax;
+
+  if (G_UNLIKELY (self->min != self->max)) {
+    num_bytes = g_rand_int_range (self->rand, self->min, self->max);
+  } else {
+    num_bytes = self->min;
+  }
+
+  GST_LOG_OBJECT (self, "pulling %u bytes at offset %" G_GUINT64_FORMAT,
+      num_bytes, self->offset);
+
+  ret = gst_pad_pull_range (self->sinkpad, self->offset, num_bytes, &buf);
+
+  if (ret != GST_FLOW_OK)
+    goto pull_failed;
+
+  size = gst_buffer_get_size (buf);
+
+  if (size < num_bytes) {
+    GST_WARNING_OBJECT (self, "short buffer: %u bytes", size);
+  }
+
+  if (self->need_newsegment) {
+    GstSegment segment;
+
+    gst_segment_init (&segment, GST_FORMAT_BYTES);
+    segment.start = self->offset;
+    gst_pad_push_event (self->srcpad, gst_event_new_segment (&segment));
+    self->need_newsegment = FALSE;
+  }
+
+  self->offset += size;
+
+  ret = gst_pad_push (self->srcpad, buf);
+
+  if (ret != GST_FLOW_OK)
+    goto push_failed;
+
+  return;
+
+pause_task:
+  {
+    GST_DEBUG_OBJECT (self, "pausing task");
+    gst_pad_pause_task (self->sinkpad);
+    return;
+  }
+
+pull_failed:
+  {
+    if (ret == GST_FLOW_EOS) {
+      GST_DEBUG_OBJECT (self, "eos");
+      gst_pad_push_event (self->srcpad, gst_event_new_eos ());
+    } else {
+      GST_WARNING_OBJECT (self, "pull_range flow: %s", gst_flow_get_name (ret));
+    }
+    goto pause_task;
+  }
+
+push_failed:
+  {
+    GST_DEBUG_OBJECT (self, "push flow: %s", gst_flow_get_name (ret));
+    if (ret == GST_FLOW_EOS) {
+      GST_DEBUG_OBJECT (self, "eos");
+      gst_pad_push_event (self->srcpad, gst_event_new_eos ());
+    } else if (ret < GST_FLOW_EOS || ret == GST_FLOW_NOT_LINKED) {
+      GST_ELEMENT_FLOW_ERROR (self, ret);
+    }
+    goto pause_task;
+  }
+
+bogus_minmax:
+  {
+    GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS,
+        ("The minimum buffer size is smaller than the maximum buffer size."),
+        ("buffer sizes: max=%d, min=%d", self->min, self->max));
+    goto pause_task;
+  }
+}
+
+static GstStateChangeReturn
+gst_rnd_buffer_size_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRndBufferSize *self = GST_RND_BUFFER_SIZE (element);
+  GstStateChangeReturn ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      self->offset = 0;
+      if (!self->rand) {
+        self->rand = g_rand_new_with_seed (self->seed);
+      }
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      if (self->rand) {
+        g_rand_free (self->rand);
+        self->rand = NULL;
+      }
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      if (self->adapter) {
+        g_object_unref (self->adapter);
+        self->adapter = NULL;
+      }
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
diff --git a/gst/debugutils/testplugin.c b/gst/debugutils/testplugin.c
new file mode 100644
index 0000000..ef9ca0f
--- /dev/null
+++ b/gst/debugutils/testplugin.c
@@ -0,0 +1,304 @@
+/* GStreamer
+ * Copyright (C) 2004 Benjamin Otte <otte@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesink.h>
+#include "tests.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_test_debug);
+#define GST_CAT_DEFAULT gst_test_debug
+
+/* This plugin does all the tests registered in the tests.h file
+ */
+
+#define GST_TYPE_TEST \
+  (gst_test_get_type())
+#define GST_TEST(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TEST,GstTest))
+#define GST_TEST_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TEST,GstTestClass))
+#define GST_TEST_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_TEST,GstTestClass))
+#define GST_IS_TEST(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TEST))
+#define GST_IS_TEST_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TEST))
+
+typedef struct _GstTest GstTest;
+typedef struct _GstTestClass GstTestClass;
+
+struct _GstTest
+{
+  GstBaseSink basesink;
+
+  gpointer tests[TESTS_COUNT];
+  GValue values[TESTS_COUNT];
+};
+
+struct _GstTestClass
+{
+  GstBaseSinkClass parent_class;
+
+  gchar *param_names[2 * TESTS_COUNT];
+};
+
+static void gst_test_finalize (GstTest * test);
+
+static gboolean gst_test_start (GstBaseSink * trans);
+static gboolean gst_test_stop (GstBaseSink * trans);
+static gboolean gst_test_sink_event (GstBaseSink * basesink, GstEvent * event);
+static GstFlowReturn gst_test_render_buffer (GstBaseSink * basesink,
+    GstBuffer * buf);
+
+static void gst_test_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_test_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+GType gst_test_get_type (void);
+#define gst_test_parent_class parent_class
+G_DEFINE_TYPE (GstTest, gst_test, GST_TYPE_BASE_SINK);
+
+
+static void
+gst_test_class_init (GstTestClass * klass)
+{
+  GstBaseSinkClass *basesink_class = GST_BASE_SINK_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  guint i;
+
+  GST_DEBUG_CATEGORY_INIT (gst_test_debug, "testsink", 0,
+      "debugging category for testsink element");
+
+  object_class->set_property = gst_test_set_property;
+  object_class->get_property = gst_test_get_property;
+
+  object_class->finalize = (GObjectFinalizeFunc) gst_test_finalize;
+
+  for (i = 0; i < TESTS_COUNT; i++) {
+    GParamSpec *spec;
+
+    spec = tests[i].get_spec (&tests[i], FALSE);
+    klass->param_names[2 * i] = g_strdup (g_param_spec_get_name (spec));
+    g_object_class_install_property (object_class, 2 * i + 1, spec);
+    spec = tests[i].get_spec (&tests[i], TRUE);
+    klass->param_names[2 * i + 1] = g_strdup (g_param_spec_get_name (spec));
+    g_object_class_install_property (object_class, 2 * i + 2, spec);
+  }
+
+  gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
+
+  gst_element_class_set_static_metadata (gstelement_class, "Test plugin",
+      "Testing", "perform a number of tests", "Benjamin Otte <otte@gnome>");
+
+  basesink_class->render = GST_DEBUG_FUNCPTR (gst_test_render_buffer);
+  basesink_class->event = GST_DEBUG_FUNCPTR (gst_test_sink_event);
+  basesink_class->start = GST_DEBUG_FUNCPTR (gst_test_start);
+  basesink_class->stop = GST_DEBUG_FUNCPTR (gst_test_stop);
+}
+
+static void
+gst_test_init (GstTest * test)
+{
+  GstTestClass *klass;
+  guint i;
+
+  klass = GST_TEST_GET_CLASS (test);
+  for (i = 0; i < TESTS_COUNT; i++) {
+    GParamSpec *spec = g_object_class_find_property (G_OBJECT_CLASS (klass),
+        klass->param_names[2 * i + 1]);
+
+    g_value_init (&test->values[i], G_PARAM_SPEC_VALUE_TYPE (spec));
+  }
+}
+
+static void
+gst_test_finalize (GstTest * test)
+{
+  guint i;
+
+  for (i = 0; i < TESTS_COUNT; i++) {
+    g_value_unset (&test->values[i]);
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize ((GObject *) test);
+}
+
+static void
+tests_unset (GstTest * test)
+{
+  guint i;
+
+  for (i = 0; i < TESTS_COUNT; i++) {
+    if (test->tests[i]) {
+      tests[i].free (test->tests[i]);
+      test->tests[i] = NULL;
+    }
+  }
+}
+
+static void
+tests_set (GstTest * test)
+{
+  guint i;
+
+  for (i = 0; i < TESTS_COUNT; i++) {
+    g_assert (test->tests[i] == NULL);
+    test->tests[i] = tests[i].new (&tests[i]);
+  }
+}
+
+static gboolean
+gst_test_sink_event (GstBaseSink * basesink, GstEvent * event)
+{
+  GstTestClass *klass = GST_TEST_GET_CLASS (basesink);
+  GstTest *test = GST_TEST (basesink);
+
+  switch (GST_EVENT_TYPE (event)) {
+/*
+    case GST_EVENT_NEWSEGMENT:
+      if (GST_EVENT_DISCONT_NEW_MEDIA (event)) {
+        tests_unset (test);
+        tests_set (test);
+      }
+      break;
+*/
+    case GST_EVENT_EOS:{
+      gint i;
+
+      g_object_freeze_notify (G_OBJECT (test));
+      for (i = 0; i < TESTS_COUNT; i++) {
+        if (test->tests[i]) {
+          if (!tests[i].finish (test->tests[i], &test->values[i])) {
+            GValue v = { 0, };
+            gchar *real, *expected;
+
+            expected = gst_value_serialize (&test->values[i]);
+            g_value_init (&v, G_VALUE_TYPE (&test->values[i]));
+            g_object_get_property (G_OBJECT (test), klass->param_names[2 * i],
+                &v);
+            real = gst_value_serialize (&v);
+            g_value_unset (&v);
+            GST_ELEMENT_ERROR (test, STREAM, FORMAT, (NULL),
+                ("test %s returned value \"%s\" and not expected value \"%s\"",
+                    klass->param_names[2 * i], real, expected));
+            g_free (real);
+            g_free (expected);
+          }
+          g_object_notify (G_OBJECT (test), klass->param_names[2 * i]);
+        }
+      }
+      g_object_thaw_notify (G_OBJECT (test));
+      break;
+    }
+    default:
+      break;
+  }
+
+  return GST_BASE_SINK_CLASS (parent_class)->event (basesink, event);
+}
+
+static GstFlowReturn
+gst_test_render_buffer (GstBaseSink * basesink, GstBuffer * buf)
+{
+  GstTest *test = GST_TEST (basesink);
+  guint i;
+
+  for (i = 0; i < TESTS_COUNT; i++) {
+    if (test->tests[i]) {
+      tests[i].add (test->tests[i], buf);
+    }
+  }
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_test_start (GstBaseSink * sink)
+{
+  GstTest *test = GST_TEST (sink);
+
+  tests_set (test);
+  return TRUE;
+}
+
+static gboolean
+gst_test_stop (GstBaseSink * sink)
+{
+  GstTest *test = GST_TEST (sink);
+
+  tests_unset (test);
+  return TRUE;
+}
+
+static void
+gst_test_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstTest *test = GST_TEST (object);
+
+  if (prop_id == 0 || prop_id > 2 * TESTS_COUNT) {
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    return;
+  }
+
+  if (prop_id % 2) {
+    /* real values can't be set */
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  } else {
+    /* expected values */
+    GST_OBJECT_LOCK (test);
+    g_value_copy (value, &test->values[prop_id / 2 - 1]);
+    GST_OBJECT_UNLOCK (test);
+  }
+}
+
+static void
+gst_test_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstTest *test = GST_TEST (object);
+  guint id = (prop_id - 1) / 2;
+
+  if (prop_id == 0 || prop_id > 2 * TESTS_COUNT) {
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    return;
+  }
+
+  GST_OBJECT_LOCK (test);
+
+  if (prop_id % 2) {
+    /* real values */
+    tests[id].get_value (test->tests[id], value);
+  } else {
+    /* expected values */
+    g_value_copy (&test->values[id], value);
+  }
+
+  GST_OBJECT_UNLOCK (test);
+}
diff --git a/gst/debugutils/tests.c b/gst/debugutils/tests.c
new file mode 100644
index 0000000..9ca2af9
--- /dev/null
+++ b/gst/debugutils/tests.c
@@ -0,0 +1,269 @@
+/* GStreamer
+ * Copyright (C) 2004 Benjamin Otte <otte@gnome.org>
+ *
+ * includes code based on glibc 2.2.3's crypt/md5.c,
+ * Copyright (C) 1995, 1996, 1997, 1999, 2000 Free Software Foundation, Inc. 
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tests.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*
+ *** LENGTH ***
+ */
+
+typedef struct
+{
+  gint64 value;
+}
+LengthTest;
+
+static GParamSpec *
+length_get_spec (const GstTestInfo * info, gboolean compare_value)
+{
+  if (compare_value) {
+    return g_param_spec_int64 ("expected-length", "expected length",
+        "expected length of stream", -1, G_MAXINT64, -1,
+        G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+  } else {
+    return g_param_spec_int64 ("length", "length", "length of stream",
+        -1, G_MAXINT64, -1, G_PARAM_READABLE);
+  }
+}
+
+static gpointer
+length_new (const GstTestInfo * info)
+{
+  return g_new0 (LengthTest, 1);
+}
+
+static void
+length_add (gpointer test, GstBuffer * buffer)
+{
+  LengthTest *t = test;
+
+  t->value += gst_buffer_get_size (buffer);
+}
+
+static gboolean
+length_finish (gpointer test, GValue * value)
+{
+  LengthTest *t = test;
+
+  if (g_value_get_int64 (value) == -1)
+    return TRUE;
+
+  return t->value == g_value_get_int64 (value);
+}
+
+static void
+length_get_value (gpointer test, GValue * value)
+{
+  LengthTest *t = test;
+
+  g_value_set_int64 (value, t ? t->value : -1);
+}
+
+/*
+ *** BUFFER COUNT ***
+ */
+
+static GParamSpec *
+buffer_count_get_spec (const GstTestInfo * info, gboolean compare_value)
+{
+  if (compare_value) {
+    return g_param_spec_int64 ("expected-buffer-count", "expected buffer count",
+        "expected number of buffers in stream",
+        -1, G_MAXINT64, -1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+  } else {
+    return g_param_spec_int64 ("buffer-count", "buffer count",
+        "number of buffers in stream", -1, G_MAXINT64, -1, G_PARAM_READABLE);
+  }
+}
+
+static void
+buffer_count_add (gpointer test, GstBuffer * buffer)
+{
+  LengthTest *t = test;
+
+  t->value++;
+}
+
+/*
+ *** TIMESTAMP / DURATION MATCHING ***
+ */
+
+typedef struct
+{
+  guint64 diff;
+  guint count;
+  GstClockTime expected;
+}
+TimeDurTest;
+
+static GParamSpec *
+timedur_get_spec (const GstTestInfo * info, gboolean compare_value)
+{
+  if (compare_value) {
+    return g_param_spec_int64 ("allowed-timestamp-deviation",
+        "allowed timestamp deviation",
+        "allowed average difference in usec between timestamp of next buffer "
+        "and expected timestamp from analyzing last buffer",
+        -1, G_MAXINT64, -1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+  } else {
+    return g_param_spec_int64 ("timestamp-deviation",
+        "timestamp deviation",
+        "average difference in usec between timestamp of next buffer "
+        "and expected timestamp from analyzing last buffer",
+        -1, G_MAXINT64, -1, G_PARAM_READABLE);
+  }
+}
+
+static gpointer
+timedur_new (const GstTestInfo * info)
+{
+  TimeDurTest *ret = g_new0 (TimeDurTest, 1);
+
+  ret->expected = GST_CLOCK_TIME_NONE;
+
+  return ret;
+}
+
+static void
+timedur_add (gpointer test, GstBuffer * buffer)
+{
+  TimeDurTest *t = test;
+
+  if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
+      GST_CLOCK_TIME_IS_VALID (t->expected)) {
+    t->diff +=
+        ABS (GST_CLOCK_DIFF (t->expected, GST_BUFFER_TIMESTAMP (buffer)));
+    t->count++;
+  }
+  if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
+      GST_BUFFER_DURATION_IS_VALID (buffer)) {
+    t->expected = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
+  } else {
+    t->expected = GST_CLOCK_TIME_NONE;
+  }
+}
+
+static gboolean
+timedur_finish (gpointer test, GValue * value)
+{
+  TimeDurTest *t = test;
+
+  if (g_value_get_int64 (value) == -1)
+    return TRUE;
+
+  return (t->diff / MAX (1, t->count)) <= g_value_get_int64 (value);
+}
+
+static void
+timedur_get_value (gpointer test, GValue * value)
+{
+  TimeDurTest *t = test;
+
+  g_value_set_int64 (value, t ? (t->diff / MAX (1, t->count)) : -1);
+}
+
+/*
+ *** MD5 ***
+ */
+
+static GParamSpec *
+md5_get_spec (const GstTestInfo * info, gboolean compare_value)
+{
+  if (compare_value) {
+    return g_param_spec_string ("expected-md5", "expected md5",
+        "expected md5 of processing the whole data",
+        "---", G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+  } else {
+    return g_param_spec_string ("md5", "md5",
+        "md5 of processing the whole data", "---", G_PARAM_READABLE);
+  }
+}
+
+static gpointer
+md5_new (const GstTestInfo * info)
+{
+  return g_checksum_new (G_CHECKSUM_MD5);
+}
+
+static void
+md5_add (gpointer checksum, GstBuffer * buffer)
+{
+  GstMapInfo map;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  g_checksum_update (checksum, map.data, map.size);
+  gst_buffer_unmap (buffer, &map);
+}
+
+static gboolean
+md5_finish (gpointer checksum, GValue * value)
+{
+  const gchar *expected, *result;
+
+  expected = g_value_get_string (value);
+  result = g_checksum_get_string (checksum);
+
+  if (g_str_equal (expected, "---"))
+    return TRUE;
+  if (g_str_equal (expected, result))
+    return TRUE;
+  return FALSE;
+}
+
+static void
+md5_get_value (gpointer checksum, GValue * value)
+{
+  if (!checksum) {
+    g_value_set_string (value, "---");
+  } else {
+    g_value_set_string (value, g_checksum_get_string (checksum));
+  }
+}
+
+static void
+md5_free (gpointer checksum)
+{
+  g_checksum_free (checksum);
+}
+
+/*
+ *** TESTINFO ***
+ */
+
+const GstTestInfo tests[] = {
+  {length_get_spec, length_new, length_add,
+      length_finish, length_get_value, g_free},
+  {buffer_count_get_spec, length_new, buffer_count_add,
+      length_finish, length_get_value, g_free},
+  {timedur_get_spec, timedur_new, timedur_add,
+      timedur_finish, timedur_get_value, g_free},
+  {md5_get_spec, md5_new, md5_add,
+      md5_finish, md5_get_value, md5_free}
+};
diff --git a/gst/debugutils/tests.h b/gst/debugutils/tests.h
new file mode 100644
index 0000000..c8fa088
--- /dev/null
+++ b/gst/debugutils/tests.h
@@ -0,0 +1,43 @@
+/* GStreamer
+ * Copyright (C) 2004 Benjamin Otte <otte@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/gst.h>
+
+#ifndef __GST_TESTS_H__
+#define __GST_TESTS_H__
+
+
+typedef struct _GstTestInfo GstTestInfo;
+
+struct _GstTestInfo
+{
+  GParamSpec *(*get_spec) (const GstTestInfo * info, gboolean compare_value);
+    gpointer (*new) (const GstTestInfo * info);
+  void (*add) (gpointer test, GstBuffer * buffer);
+    gboolean (*finish) (gpointer test, GValue * value);
+  void (*get_value) (gpointer test, GValue * value);
+  void (*free) (gpointer test);
+};
+
+extern const GstTestInfo tests[];
+/* keep up to date! */
+#define TESTS_COUNT (4)
+
+
+#endif /* __GST_TESTS_H__ */
diff --git a/gst/deinterlace/Makefile.am b/gst/deinterlace/Makefile.am
new file mode 100644
index 0000000..61e7ed9
--- /dev/null
+++ b/gst/deinterlace/Makefile.am
@@ -0,0 +1,52 @@
+plugin_LTLIBRARIES = libgstdeinterlace.la
+
+ORC_SOURCE=tvtime
+include $(top_srcdir)/common/orc.mak
+
+libgstdeinterlace_la_SOURCES = \
+	gstdeinterlace.c \
+	gstdeinterlacemethod.c \
+	tvtime/tomsmocomp.c \
+	tvtime/greedy.c \
+	tvtime/greedyh.c \
+	tvtime/vfir.c \
+	tvtime/weavetff.c \
+	tvtime/weavebff.c \
+	tvtime/weave.c \
+	tvtime/linear.c \
+	tvtime/linearblend.c \
+	tvtime/scalerbob.c
+nodist_libgstdeinterlace_la_SOURCES = $(ORC_NODIST_SOURCES)
+
+libgstdeinterlace_la_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(ORC_CFLAGS)
+libgstdeinterlace_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) $(GST_BASE_LIBS) $(GST_LIBS) $(ORC_LIBS)
+libgstdeinterlace_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = \
+	gstdeinterlace.h \
+	gstdeinterlacemethod.h \
+	tvtime/mmx.h \
+	tvtime/sse.h \
+	tvtime/greedyh.asm \
+	tvtime/greedyhmacros.h \
+	tvtime/plugins.h \
+	tvtime/x86-64_macros.inc \
+	tvtime/tomsmocomp/SearchLoop0A.inc \
+	tvtime/tomsmocomp/SearchLoopBottom.inc \
+	tvtime/tomsmocomp/SearchLoopEdgeA8.inc \
+	tvtime/tomsmocomp/SearchLoopEdgeA.inc \
+	tvtime/tomsmocomp/SearchLoopOddA2.inc \
+	tvtime/tomsmocomp/SearchLoopOddA6.inc \
+	tvtime/tomsmocomp/SearchLoopOddAH2.inc \
+	tvtime/tomsmocomp/SearchLoopOddAH.inc \
+	tvtime/tomsmocomp/SearchLoopOddA.inc \
+	tvtime/tomsmocomp/SearchLoopTop.inc \
+	tvtime/tomsmocomp/SearchLoopVAH.inc \
+	tvtime/tomsmocomp/SearchLoopVA.inc \
+	tvtime/tomsmocomp/StrangeBob.inc \
+	tvtime/tomsmocomp/TomsMoCompAll2.inc \
+	tvtime/tomsmocomp/TomsMoCompAll.inc \
+	tvtime/tomsmocomp/tomsmocompmacros.h \
+	tvtime/tomsmocomp/WierdBob.inc
diff --git a/gst/deinterlace/gstdeinterlace.c b/gst/deinterlace/gstdeinterlace.c
new file mode 100644
index 0000000..662a1c4
--- /dev/null
+++ b/gst/deinterlace/gstdeinterlace.c
@@ -0,0 +1,3144 @@
+/*
+ * 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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-deinterlace
+ *
+ * deinterlace deinterlaces interlaced video frames to progressive video frames.
+ * For this different algorithms can be selected which will be described later.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v filesrc location=/path/to/file ! decodebin ! videoconvert ! deinterlace ! videoconvert ! autovideosink
+ * ]| This pipeline deinterlaces a video file with the default deinterlacing options.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstdeinterlace.h"
+#include "tvtime/plugins.h"
+
+#include <string.h>
+
+#if HAVE_ORC
+#include <orc/orc.h>
+#endif
+
+GST_DEBUG_CATEGORY_STATIC (deinterlace_debug);
+#define GST_CAT_DEFAULT (deinterlace_debug)
+
+/* Properties */
+
+#define DEFAULT_MODE            GST_DEINTERLACE_MODE_AUTO
+#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
+{
+  PROP_0,
+  PROP_MODE,
+  PROP_METHOD,
+  PROP_FIELDS,
+  PROP_FIELD_LAYOUT,
+  PROP_LOCKING,
+  PROP_IGNORE_OBSCURE,
+  PROP_DROP_ORPHANS
+};
+
+#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_RFF  (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_RFF (GST_DEINTERLACE_BUFFER_STATE_RFF)
+
+#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-RFF", 4, 4, 5, {GST_PRG, GST_RFF, GST_PRG, GST_RFF,}},
+  {"2:3", 5, 4, 5, {GST_PRG, GST_PRG, GST_ONE, GST_ONE, GST_PRG,}},
+  {"3:2:2:3-RFF", 4, 4, 5, {GST_RFF, GST_PRG, GST_PRG, GST_RFF,}},
+  {"3:2:2:3", 5, 4, 5, {GST_PRG, GST_ONE, GST_INT, GST_ONE, GST_PRG,}},
+  /* fieldanalysis should indicate this using RFF on the second and fourth
+   * buffers and not send the third buffer at all. it will be identified as
+   * 3:2:2:3-RFF */
+  /* {"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,}},
+#if 0
+  /* haven't figured out how fieldanalysis should handle these yet */
+  /* 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,}},
+#endif
+  /* 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"},
+  {GST_DEINTERLACE_GREEDY_H, "Motion Adaptive: Advanced Detection",
+      "greedyh"},
+  {GST_DEINTERLACE_GREEDY_L, "Motion Adaptive: Simple Detection", "greedyl"},
+  {GST_DEINTERLACE_VFIR, "Blur Vertical", "vfir"},
+  {GST_DEINTERLACE_LINEAR, "Linear", "linear"},
+  {GST_DEINTERLACE_LINEAR_BLEND, "Blur: Temporal (Do Not Use)",
+      "linearblend"},
+  {GST_DEINTERLACE_SCALER_BOB, "Double lines", "scalerbob"},
+  {GST_DEINTERLACE_WEAVE, "Weave (Do Not Use)", "weave"},
+  {GST_DEINTERLACE_WEAVE_TFF, "Progressive: Top Field First (Do Not Use)",
+      "weavetff"},
+  {GST_DEINTERLACE_WEAVE_BFF, "Progressive: Bottom Field First (Do Not Use)",
+      "weavebff"},
+  {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
+gst_deinterlace_methods_get_type (void)
+{
+  static GType deinterlace_methods_type = 0;
+
+  if (!deinterlace_methods_type) {
+    deinterlace_methods_type =
+        g_enum_register_static ("GstDeinterlaceMethods", methods_types);
+  }
+  return deinterlace_methods_type;
+}
+
+#define GST_TYPE_DEINTERLACE_FIELDS (gst_deinterlace_fields_get_type ())
+static GType
+gst_deinterlace_fields_get_type (void)
+{
+  static GType deinterlace_fields_type = 0;
+
+  static const GEnumValue fields_types[] = {
+    {GST_DEINTERLACE_ALL, "All fields", "all"},
+    {GST_DEINTERLACE_TF, "Top fields only", "top"},
+    {GST_DEINTERLACE_BF, "Bottom fields only", "bottom"},
+    {GST_DEINTERLACE_FIELDS_AUTO, "Automatically detect", "auto"},
+    {0, NULL, NULL},
+  };
+
+  if (!deinterlace_fields_type) {
+    deinterlace_fields_type =
+        g_enum_register_static ("GstDeinterlaceFields", fields_types);
+  }
+  return deinterlace_fields_type;
+}
+
+#define GST_TYPE_DEINTERLACE_FIELD_LAYOUT (gst_deinterlace_field_layout_get_type ())
+static GType
+gst_deinterlace_field_layout_get_type (void)
+{
+  static GType deinterlace_field_layout_type = 0;
+
+  static const GEnumValue field_layout_types[] = {
+    {GST_DEINTERLACE_LAYOUT_AUTO, "Auto detection", "auto"},
+    {GST_DEINTERLACE_LAYOUT_TFF, "Top field first", "tff"},
+    {GST_DEINTERLACE_LAYOUT_BFF, "Bottom field first", "bff"},
+    {0, NULL, NULL},
+  };
+
+  if (!deinterlace_field_layout_type) {
+    deinterlace_field_layout_type =
+        g_enum_register_static ("GstDeinterlaceFieldLayout",
+        field_layout_types);
+  }
+  return deinterlace_field_layout_type;
+}
+
+#define GST_TYPE_DEINTERLACE_MODES (gst_deinterlace_modes_get_type ())
+static GType
+gst_deinterlace_modes_get_type (void)
+{
+  static GType deinterlace_modes_type = 0;
+
+  static const GEnumValue modes_types[] = {
+    {GST_DEINTERLACE_MODE_AUTO, "Auto detection (best effort)", "auto"},
+    {GST_DEINTERLACE_MODE_INTERLACED, "Force deinterlacing", "interlaced"},
+    {GST_DEINTERLACE_MODE_DISABLED, "Run in passthrough mode", "disabled"},
+    {GST_DEINTERLACE_MODE_AUTO_STRICT, "Auto detection (strict)",
+        "auto-strict"},
+    {0, NULL, NULL},
+  };
+
+  if (!deinterlace_modes_type) {
+    deinterlace_modes_type =
+        g_enum_register_static ("GstDeinterlaceModes", modes_types);
+  }
+  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_VIDEO_FORMATS \
+    "{ AYUV, ARGB, ABGR, RGBA, BGRA, Y444, xRGB, xBGR, RGBx, BGRx, RGB, " \
+    "BGR, YUY2, YVYU, UYVY, Y42B, I420, YV12, Y41B, NV12, NV21 }"
+
+#define DEINTERLACE_CAPS GST_VIDEO_CAPS_MAKE(DEINTERLACE_VIDEO_FORMATS)
+
+#define DEINTERLACE_ALL_CAPS DEINTERLACE_CAPS ";" \
+    GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", GST_VIDEO_FORMATS_ALL)
+
+static GstStaticCaps progressive_caps =
+GST_STATIC_CAPS ("video/x-raw(ANY),interlace-mode=(string)progressive");
+static GstStaticCaps deinterlace_caps = GST_STATIC_CAPS (DEINTERLACE_CAPS);
+
+static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (DEINTERLACE_ALL_CAPS)
+    );
+
+static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (DEINTERLACE_ALL_CAPS)
+    );
+
+static void gst_deinterlace_finalize (GObject * self);
+static void gst_deinterlace_set_property (GObject * self, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_deinterlace_get_property (GObject * self, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_deinterlace_getcaps (GstDeinterlace * self, GstPad * pad,
+    GstCaps * filter);
+static gboolean gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad,
+    GstCaps * caps);
+static gboolean gst_deinterlace_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static gboolean gst_deinterlace_sink_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+static GstFlowReturn gst_deinterlace_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer);
+static GstStateChangeReturn gst_deinterlace_change_state (GstElement * element,
+    GstStateChange transition);
+static gboolean gst_deinterlace_set_allocation (GstDeinterlace * self,
+    GstBufferPool * pool, GstAllocator * allocator,
+    GstAllocationParams * params);
+
+static gboolean gst_deinterlace_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static gboolean gst_deinterlace_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+
+static GstFlowReturn gst_deinterlace_output_frame (GstDeinterlace * self,
+    gboolean flushing);
+static void gst_deinterlace_reset (GstDeinterlace * self);
+static void gst_deinterlace_update_qos (GstDeinterlace * self,
+    gdouble proportion, GstClockTimeDiff diff, GstClockTime time);
+static void gst_deinterlace_reset_qos (GstDeinterlace * self);
+static void gst_deinterlace_read_qos (GstDeinterlace * self,
+    gdouble * proportion, GstClockTime * time);
+
+#define IS_TELECINE(m) ((m) == GST_VIDEO_INTERLACE_MODE_MIXED && self->pattern > 1)
+
+/* FIXME: what's the point of the childproxy interface here? What can you
+ * actually do with it? The method objects seem to have no properties */
+#if 0
+static void gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
+    gpointer iface_data);
+
+static void
+_do_init (GType object_type)
+{
+  const GInterfaceInfo child_proxy_interface_info = {
+    (GInterfaceInitFunc) gst_deinterlace_child_proxy_interface_init,
+    NULL,                       /* interface_finalize */
+    NULL                        /* interface_data */
+  };
+
+  g_type_add_interface_static (object_type, GST_TYPE_CHILD_PROXY,
+      &child_proxy_interface_info);
+}
+#endif
+
+G_DEFINE_TYPE (GstDeinterlace, gst_deinterlace, GST_TYPE_ELEMENT);
+
+#define parent_class gst_deinterlace_parent_class
+
+static const struct
+{
+  GType (*get_type) (void);
+} _method_types[] = {
+  {
+  gst_deinterlace_method_tomsmocomp_get_type}, {
+  gst_deinterlace_method_greedy_h_get_type}, {
+  gst_deinterlace_method_greedy_l_get_type}, {
+  gst_deinterlace_method_vfir_get_type}, {
+  gst_deinterlace_method_linear_get_type}, {
+  gst_deinterlace_method_linear_blend_get_type}, {
+  gst_deinterlace_method_scaler_bob_get_type}, {
+  gst_deinterlace_method_weave_get_type}, {
+  gst_deinterlace_method_weave_tff_get_type}, {
+  gst_deinterlace_method_weave_bff_get_type}
+};
+
+static void
+gst_deinterlace_set_method (GstDeinterlace * self, GstDeinterlaceMethods method)
+{
+  GType method_type;
+  gint width, height;
+  GstVideoFormat format;
+
+  GST_DEBUG_OBJECT (self, "Setting new method %d", method);
+
+  width = GST_VIDEO_INFO_WIDTH (&self->vinfo);
+  height = GST_VIDEO_INFO_HEIGHT (&self->vinfo);
+  format = GST_VIDEO_INFO_FORMAT (&self->vinfo);
+
+  if (self->method) {
+    if (self->method_id == method &&
+        gst_deinterlace_method_supported (G_TYPE_FROM_INSTANCE (self->method),
+            format, width, height)) {
+      GST_DEBUG_OBJECT (self, "Reusing current method");
+      return;
+    }
+#if 0
+    gst_child_proxy_child_removed (GST_OBJECT (self),
+        GST_OBJECT (self->method));
+    gst_object_unparent (GST_OBJECT (self->method));
+    self->method = NULL;
+#endif
+  }
+
+  method_type =
+      _method_types[method].get_type !=
+      NULL ? _method_types[method].get_type () : G_TYPE_INVALID;
+  if (method_type == G_TYPE_INVALID
+      || !gst_deinterlace_method_supported (method_type, format,
+          width, height)) {
+    GType tmp;
+    gint i;
+
+    method_type = G_TYPE_INVALID;
+
+    GST_WARNING_OBJECT (self, "Method doesn't support requested format");
+    for (i = 0; i < G_N_ELEMENTS (_method_types); i++) {
+      if (_method_types[i].get_type == NULL)
+        continue;
+      tmp = _method_types[i].get_type ();
+      if (gst_deinterlace_method_supported (tmp, format, width, height)) {
+        GST_DEBUG_OBJECT (self, "Using method %d", i);
+        method_type = tmp;
+        method = i;
+        break;
+      }
+    }
+    /* If we get here we must have invalid caps! */
+    g_assert (method_type != G_TYPE_INVALID);
+  }
+
+  self->method = g_object_new (method_type, "name", "method", NULL);
+  self->method_id = method;
+
+  gst_object_set_parent (GST_OBJECT (self->method), GST_OBJECT (self));
+#if 0
+  gst_child_proxy_child_added (GST_OBJECT (self), GST_OBJECT (self->method));
+#endif
+
+  if (self->method)
+    gst_deinterlace_method_setup (self->method, &self->vinfo);
+}
+
+static gboolean
+gst_deinterlace_clip_buffer (GstDeinterlace * self, GstBuffer * buffer)
+{
+  gboolean ret = TRUE;
+  GstClockTime start, stop;
+  guint64 cstart, cstop;
+
+  GST_DEBUG_OBJECT (self,
+      "Clipping buffer to the current segment: %" GST_TIME_FORMAT " -- %"
+      GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
+      GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
+  GST_DEBUG_OBJECT (self, "Current segment: %" GST_SEGMENT_FORMAT,
+      &self->segment);
+
+  if (G_UNLIKELY (self->segment.format != GST_FORMAT_TIME))
+    goto beach;
+  if (G_UNLIKELY (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)))
+    goto beach;
+
+  start = GST_BUFFER_TIMESTAMP (buffer);
+  stop = start + GST_BUFFER_DURATION (buffer);
+
+  if (!(ret = gst_segment_clip (&self->segment, GST_FORMAT_TIME,
+              start, stop, &cstart, &cstop)))
+    goto beach;
+
+  GST_BUFFER_TIMESTAMP (buffer) = cstart;
+  if (GST_CLOCK_TIME_IS_VALID (cstop))
+    GST_BUFFER_DURATION (buffer) = cstop - cstart;
+
+beach:
+  if (ret)
+    GST_DEBUG_OBJECT (self,
+        "Clipped buffer to the current segment: %" GST_TIME_FORMAT " -- %"
+        GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
+        GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
+  else
+    GST_DEBUG_OBJECT (self, "Buffer outside the current segment -- dropping");
+
+  return ret;
+}
+
+static void
+gst_deinterlace_class_init (GstDeinterlaceClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+
+  GstElementClass *element_class = (GstElementClass *) klass;
+
+  gst_element_class_add_static_pad_template (element_class, &src_templ);
+  gst_element_class_add_static_pad_template (element_class, &sink_templ);
+
+  gst_element_class_set_static_metadata (element_class,
+      "Deinterlacer",
+      "Filter/Effect/Video/Deinterlace",
+      "Deinterlace Methods ported from DScaler/TvTime",
+      "Martin Eikermann <meiker@upb.de>, "
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  gobject_class->set_property = gst_deinterlace_set_property;
+  gobject_class->get_property = gst_deinterlace_get_property;
+  gobject_class->finalize = gst_deinterlace_finalize;
+
+  /**
+   * GstDeinterlace:mode:
+   *
+   * This selects whether the deinterlacing methods should
+   * always be applied or if they should only be applied
+   * on content that has the "interlaced" flag on the caps.
+   */
+  g_object_class_install_property (gobject_class, PROP_MODE,
+      g_param_spec_enum ("mode",
+          "Mode",
+          "Deinterlace Mode",
+          GST_TYPE_DEINTERLACE_MODES,
+          DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
+  /**
+   * GstDeinterlace:method:
+   *
+   * Selects the different deinterlacing algorithms that can be used.
+   * These provide different quality and CPU usage.
+   *
+   * Some methods provide parameters which can be set by getting
+   * the "method" child via the #GstChildProxy interface and
+   * setting the appropiate properties on it.
+   *
+   * <itemizedlist>
+   * <listitem>
+   * <para>
+   * tomsmocomp
+   * Motion Adaptive: Motion Search
+   * </para>
+   * </listitem>
+   * <listitem>
+   * <para>
+   * greedyh
+   * Motion Adaptive: Advanced Detection
+   * </para>
+   * </listitem>
+   * <listitem>
+   * <para>
+   * greedyl
+   * Motion Adaptive: Simple Detection
+   * </para>
+   * </listitem>
+   * <listitem>
+   * <para>
+   * vfir
+   * Blur vertical
+   * </para>
+   * </listitem>
+   * <listitem>
+   * <para>
+   * linear
+   * Linear interpolation
+   * </para>
+   * </listitem>
+   * <listitem>
+   * <para>
+   * linearblend
+   * Linear interpolation in time domain.  Any motion causes significant
+   * ghosting, so this method should not be used.
+   * </para>
+   * </listitem>
+   * <listitem>
+   * <para>
+   * scalerbob
+   * Double lines
+   * </para>
+   * </listitem>
+   * <listitem>
+   * <para>
+   * weave
+   * Weave.  Bad quality, do not use.
+   * </para>
+   * </listitem>
+   * <listitem>
+   * <para>
+   * weavetff
+   * Progressive: Top Field First.  Bad quality, do not use.
+   * </para>
+   * </listitem>
+   * <listitem>
+   * <para>
+   * weavebff
+   * Progressive: Bottom Field First.  Bad quality, do not use.
+   * </para>
+   * </listitem>
+   * </itemizedlist>
+   */
+  g_object_class_install_property (gobject_class, PROP_METHOD,
+      g_param_spec_enum ("method",
+          "Method",
+          "Deinterlace Method",
+          GST_TYPE_DEINTERLACE_METHODS,
+          DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
+  /**
+   * GstDeinterlace:fields:
+   *
+   * This selects which fields should be output. If "all" is selected
+   * the output framerate will be double.
+   */
+  g_object_class_install_property (gobject_class, PROP_FIELDS,
+      g_param_spec_enum ("fields",
+          "fields",
+          "Fields to use for deinterlacing",
+          GST_TYPE_DEINTERLACE_FIELDS,
+          DEFAULT_FIELDS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
+  /**
+   * GstDeinterlace:layout:
+   *
+   * This selects which fields is the first in time.
+   *
+   */
+  g_object_class_install_property (gobject_class, PROP_FIELD_LAYOUT,
+      g_param_spec_enum ("tff",
+          "tff",
+          "Deinterlace top field first",
+          GST_TYPE_DEINTERLACE_FIELD_LAYOUT,
+          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.
+   */
+  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.
+   */
+  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.
+   */
+  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);
+}
+
+#if 0
+static GstObject *
+gst_deinterlace_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
+    guint index)
+{
+  GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
+
+  g_return_val_if_fail (index == 0, NULL);
+
+  return gst_object_ref (self->method);
+}
+
+static guint
+gst_deinterlace_child_proxy_get_children_count (GstChildProxy * child_proxy)
+{
+  GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
+
+  return ((self->method) ? 1 : 0);
+}
+
+static void
+gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
+    gpointer iface_data)
+{
+  GstChildProxyInterface *iface = g_iface;
+
+  iface->get_child_by_index = gst_deinterlace_child_proxy_get_child_by_index;
+  iface->get_children_count = gst_deinterlace_child_proxy_get_children_count;
+}
+#endif
+
+static void
+gst_deinterlace_init (GstDeinterlace * self)
+{
+  self->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
+  gst_pad_set_chain_function (self->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_deinterlace_chain));
+  gst_pad_set_event_function (self->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_deinterlace_sink_event));
+  gst_pad_set_query_function (self->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_deinterlace_sink_query));
+  gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
+
+  self->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
+  gst_pad_set_event_function (self->srcpad,
+      GST_DEBUG_FUNCPTR (gst_deinterlace_src_event));
+  gst_pad_set_query_function (self->srcpad,
+      GST_DEBUG_FUNCPTR (gst_deinterlace_src_query));
+  gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
+
+  self->mode = DEFAULT_MODE;
+  self->user_set_method_id = DEFAULT_METHOD;
+  gst_video_info_init (&self->vinfo);
+  gst_deinterlace_set_method (self, self->user_set_method_id);
+  self->fields = DEFAULT_FIELDS;
+  self->user_set_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);
+}
+
+static GstVideoFrame *
+gst_video_frame_new_and_map (GstVideoInfo * vinfo, GstBuffer * buffer,
+    GstMapFlags flags)
+{
+  GstVideoFrame *frame = g_malloc0 (sizeof (GstVideoFrame));
+  if (!gst_video_frame_map (frame, vinfo, buffer, flags)) {
+    g_free (frame);
+    g_return_val_if_reached (NULL);
+    return NULL;
+  }
+  return frame;
+}
+
+static void
+gst_video_frame_unmap_and_free (GstVideoFrame * frame)
+{
+  gst_video_frame_unmap (frame);
+  g_free (frame);
+}
+
+static void
+gst_deinterlace_reset_history (GstDeinterlace * self, gboolean drop_all)
+{
+  gint i;
+
+  if (!drop_all) {
+    GST_DEBUG_OBJECT (self, "Flushing history (count %d)", self->history_count);
+    while (self->history_count > 0) {
+      if (gst_deinterlace_output_frame (self, TRUE) != GST_FLOW_OK) {
+        /* Encountered error, or flushing -> skip and drop all remaining */
+        drop_all = TRUE;
+        break;
+      }
+    }
+  }
+  if (drop_all) {
+    GST_DEBUG_OBJECT (self, "Resetting history (count %d)",
+        self->history_count);
+
+    for (i = 0; i < self->history_count; i++) {
+      if (self->field_history[i].frame) {
+        gst_video_frame_unmap_and_free (self->field_history[i].frame);
+        self->field_history[i].frame = NULL;
+      }
+    }
+  }
+  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;
+  self->cur_field_idx = -1;
+
+  if (!self->still_frame_mode && self->last_buffer) {
+    gst_buffer_unref (self->last_buffer);
+    self->last_buffer = NULL;
+  }
+}
+
+static void
+gst_deinterlace_reset (GstDeinterlace * self)
+{
+  GST_DEBUG_OBJECT (self, "Resetting internal state");
+
+  gst_video_info_init (&self->vinfo);
+
+  self->passthrough = FALSE;
+
+  self->reconfigure = FALSE;
+  if ((gint) self->new_mode != -1)
+    self->mode = self->new_mode;
+  if ((gint) self->new_fields != -1)
+    self->user_set_fields = self->new_fields;
+  self->new_mode = -1;
+  self->new_fields = -1;
+
+  gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
+
+  if (self->request_caps)
+    gst_caps_unref (self->request_caps);
+  self->request_caps = NULL;
+
+  gst_deinterlace_reset_history (self, TRUE);
+
+  gst_deinterlace_reset_qos (self);
+
+  self->need_more = FALSE;
+  self->have_eos = FALSE;
+
+  self->discont = TRUE;
+
+  gst_deinterlace_set_allocation (self, NULL, NULL, NULL);
+}
+
+static void
+gst_deinterlace_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstDeinterlace *self;
+
+  self = GST_DEINTERLACE (object);
+
+  switch (prop_id) {
+    case PROP_MODE:{
+      gint new_mode;
+
+      GST_OBJECT_LOCK (self);
+      new_mode = g_value_get_enum (value);
+      if (self->mode != new_mode && gst_pad_has_current_caps (self->srcpad)) {
+        self->reconfigure = TRUE;
+        self->new_mode = new_mode;
+      } else {
+        self->mode = new_mode;
+      }
+      GST_OBJECT_UNLOCK (self);
+      break;
+    }
+    case PROP_METHOD:
+      self->user_set_method_id = g_value_get_enum (value);
+      gst_deinterlace_set_method (self, self->user_set_method_id);
+      break;
+    case PROP_FIELDS:{
+      gint new_fields;
+
+      GST_OBJECT_LOCK (self);
+      new_fields = g_value_get_enum (value);
+      if (self->user_set_fields != new_fields
+          && gst_pad_has_current_caps (self->srcpad)) {
+        self->reconfigure = TRUE;
+        self->new_fields = new_fields;
+      } else {
+        self->user_set_fields = new_fields;
+      }
+      GST_OBJECT_UNLOCK (self);
+      break;
+    }
+    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);
+  }
+
+}
+
+static void
+gst_deinterlace_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstDeinterlace *self;
+
+  self = GST_DEINTERLACE (object);
+
+  switch (prop_id) {
+    case PROP_MODE:
+      g_value_set_enum (value, self->mode);
+      break;
+    case PROP_METHOD:
+      g_value_set_enum (value, self->user_set_method_id);
+      break;
+    case PROP_FIELDS:
+      g_value_set_enum (value, self->user_set_fields);
+      break;
+    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);
+  }
+}
+
+static void
+gst_deinterlace_finalize (GObject * object)
+{
+  GstDeinterlace *self = GST_DEINTERLACE (object);
+
+  gst_deinterlace_reset (self);
+
+  if (self->method) {
+    gst_object_unparent (GST_OBJECT (self->method));
+    self->method = NULL;
+  }
+
+  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;
+  if (self->buf_states[state_idx].state != GST_RFF) {
+    self->pattern_buf_dur =
+        (self->buf_states[state_idx].duration *
+        telecine_patterns[self->pattern].ratio_d) /
+        telecine_patterns[self->pattern].ratio_n;
+  } else {
+    self->pattern_buf_dur =
+        (self->buf_states[state_idx].duration *
+        telecine_patterns[self->pattern].ratio_d * 2) /
+        (telecine_patterns[self->pattern].ratio_n * 3);
+  }
+  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 GstVideoFrame *
+gst_deinterlace_pop_history (GstDeinterlace * self)
+{
+  GstVideoFrame *frame;
+
+  g_return_val_if_fail (self->history_count > 0, NULL);
+
+  GST_DEBUG_OBJECT (self, "Pop last history frame -- current history size %d",
+      self->history_count);
+
+  frame = self->field_history[self->history_count - 1].frame;
+
+  self->history_count--;
+  if (self->locking != GST_DEINTERLACE_LOCKING_NONE && (!self->history_count
+          || GST_VIDEO_FRAME_PLANE_DATA (frame, 0) !=
+          GST_VIDEO_FRAME_PLANE_DATA (self->field_history[self->history_count -
+                  1].frame, 0))) {
+    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_DEBUG_OBJECT (self, "Returning frame: %p %" GST_TIME_FORMAT
+      " with duration %" GST_TIME_FORMAT " and size %" G_GSIZE_FORMAT, frame,
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (frame->buffer)),
+      GST_TIME_ARGS (GST_BUFFER_DURATION (frame->buffer)),
+      GST_VIDEO_FRAME_SIZE (frame));
+
+  return frame;
+}
+
+static void
+gst_deinterlace_get_buffer_state (GstDeinterlace * self, GstVideoFrame * frame,
+    guint8 * state, GstVideoInterlaceMode * i_mode)
+{
+  GstVideoInterlaceMode interlacing_mode;
+
+  if (!(i_mode || state))
+    return;
+
+  interlacing_mode = GST_VIDEO_INFO_INTERLACE_MODE (&frame->info);
+  if (self->mode == GST_DEINTERLACE_MODE_INTERLACED)
+    interlacing_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
+
+  if (state) {
+    if (interlacing_mode == GST_VIDEO_INTERLACE_MODE_MIXED) {
+      if (GST_VIDEO_FRAME_IS_RFF (frame)) {
+        *state = GST_DEINTERLACE_BUFFER_STATE_RFF;
+      } else if (GST_VIDEO_FRAME_IS_ONEFIELD (frame)) {
+        /* tc top if tff, tc bottom otherwise */
+        if (GST_VIDEO_FRAME_IS_TFF (frame)) {
+          *state = GST_DEINTERLACE_BUFFER_STATE_TC_T;
+        } else {
+          *state = GST_DEINTERLACE_BUFFER_STATE_TC_B;
+        }
+      } else if (GST_VIDEO_FRAME_IS_INTERLACED (frame)) {
+        *state = GST_DEINTERLACE_BUFFER_STATE_TC_M;
+      } else {
+        *state = GST_DEINTERLACE_BUFFER_STATE_TC_P;
+      }
+    } else {
+      if (interlacing_mode == GST_VIDEO_INTERLACE_MODE_INTERLEAVED) {
+        *state = GST_DEINTERLACE_BUFFER_STATE_I;
+      } else {
+        *state = GST_DEINTERLACE_BUFFER_STATE_P;
+      }
+    }
+  }
+
+  if (i_mode)
+    *i_mode = interlacing_mode;
+}
+
+#define STATE_TO_STRING(s) ((s) == GST_DEINTERLACE_BUFFER_STATE_P ? "P" : \
+  (s) == GST_DEINTERLACE_BUFFER_STATE_I ? "I" : \
+  (s) == GST_DEINTERLACE_BUFFER_STATE_TC_B ? "B" : \
+  (s) == GST_DEINTERLACE_BUFFER_STATE_TC_T ? "T" : \
+  (s) == GST_DEINTERLACE_BUFFER_STATE_TC_P ? "TCP" : \
+  (s) == GST_DEINTERLACE_BUFFER_STATE_TC_M ? "TCM" : "RFF")
+
+#define MODE_TO_STRING(m) ((m) == GST_VIDEO_INTERLACE_MODE_MIXED ? "MIXED" : \
+  (m) == GST_VIDEO_INTERLACE_MODE_INTERLEAVED ? "I" : \
+  (m) == GST_VIDEO_INTERLACE_MODE_FIELDS ? "FIELDS" : "P")
+
+static void
+gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
+{
+  int i = 1;
+  GstDeinterlaceFieldLayout field_layout = self->field_layout;
+  gboolean tff;
+  gboolean onefield;
+  GstVideoFrame *frame = NULL;
+  GstVideoFrame *field1, *field2 = NULL;
+  guint fields_to_push;
+  guint field1_flags, field2_flags;
+  GstVideoInterlaceMode interlacing_mode;
+  guint8 buf_state;
+
+  /* we will only read from this buffer and write into fresh output buffers
+   * if this is not the case, change the map flags as appropriate
+   */
+  frame = gst_video_frame_new_and_map (&self->vinfo, buffer, GST_MAP_READ);
+  /* we can manage the buffer ref count using the maps from here on */
+  gst_buffer_unref (buffer);
+
+  tff = GST_VIDEO_FRAME_IS_TFF (frame);
+  onefield = GST_VIDEO_FRAME_IS_ONEFIELD (frame);
+  fields_to_push = (onefield) ? 1 : 2;
+
+  g_return_if_fail (self->history_count <
+      GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push);
+
+  gst_deinterlace_get_buffer_state (self, frame, &buf_state, &interlacing_mode);
+
+  GST_DEBUG_OBJECT (self,
+      "Pushing new frame as %d fields to the history (count before %d): ptr %p at %"
+      GST_TIME_FORMAT " with duration %" GST_TIME_FORMAT
+      ", size %" G_GSIZE_FORMAT ", state %s, interlacing mode %s",
+      fields_to_push, self->history_count, frame,
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
+      GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
+      gst_buffer_get_size (buffer),
+      STATE_TO_STRING (buf_state), MODE_TO_STRING (interlacing_mode));
+
+  /* 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++;
+
+  for (i = GST_DEINTERLACE_MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) {
+    self->field_history[i].frame =
+        self->field_history[i - fields_to_push].frame;
+    self->field_history[i].flags =
+        self->field_history[i - fields_to_push].flags;
+  }
+
+  if (field_layout == GST_DEINTERLACE_LAYOUT_AUTO) {
+    if (!GST_VIDEO_INFO_IS_INTERLACED (&self->vinfo)) {
+      GST_WARNING_OBJECT (self, "Can't detect field layout -- assuming TFF");
+      field_layout = GST_DEINTERLACE_LAYOUT_TFF;
+    } else if (tff) {
+      field_layout = GST_DEINTERLACE_LAYOUT_TFF;
+    } else {
+      field_layout = GST_DEINTERLACE_LAYOUT_BFF;
+    }
+  }
+
+  field1 = frame;
+  field2 = gst_video_frame_new_and_map (&self->vinfo, buffer, GST_MAP_READ);
+  if (field_layout == GST_DEINTERLACE_LAYOUT_TFF) {
+    GST_DEBUG_OBJECT (self, "Top field first");
+    field1_flags = PICTURE_INTERLACED_TOP;
+    field2_flags = PICTURE_INTERLACED_BOTTOM;
+  } else {
+    GST_DEBUG_OBJECT (self, "Bottom field first");
+    field1_flags = PICTURE_INTERLACED_BOTTOM;
+    field2_flags = PICTURE_INTERLACED_TOP;
+  }
+
+  /* Swap for reverse playback */
+  if (self->segment.rate < 0) {
+    field1_flags = field1_flags ^ field2_flags;
+    field2_flags = field1_flags ^ field2_flags;
+    field1_flags = field1_flags ^ field2_flags;
+  }
+
+  if (!onefield) {
+    GST_DEBUG_OBJECT (self, "Two fields");
+    self->field_history[1].frame = field1;
+    self->field_history[1].flags = field1_flags;
+
+    self->field_history[0].frame = field2;
+    self->field_history[0].flags = field2_flags;
+  } else {                      /* onefield */
+    GST_DEBUG_OBJECT (self, "One field");
+    self->field_history[0].frame = field1;
+    self->field_history[0].flags = field1_flags;
+    gst_video_frame_unmap_and_free (field2);
+  }
+
+  self->history_count += fields_to_push;
+  self->cur_field_idx += fields_to_push;
+
+  GST_DEBUG_OBJECT (self, "Pushed buffer -- current history size %d, index %d",
+      self->history_count, self->cur_field_idx);
+
+  if (self->last_buffer)
+    gst_buffer_unref (self->last_buffer);
+  self->last_buffer = gst_buffer_ref (buffer);
+}
+
+static void
+gst_deinterlace_update_qos (GstDeinterlace * self, gdouble proportion,
+    GstClockTimeDiff diff, GstClockTime timestamp)
+{
+  GST_DEBUG_OBJECT (self,
+      "Updating QoS: proportion %lf, diff %" GST_STIME_FORMAT ", timestamp %"
+      GST_TIME_FORMAT, proportion, GST_STIME_ARGS (diff),
+      GST_TIME_ARGS (timestamp));
+
+  GST_OBJECT_LOCK (self);
+  self->proportion = proportion;
+  if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) {
+    if (G_UNLIKELY (diff > 0))
+      self->earliest_time =
+          timestamp + 2 * diff + ((self->fields ==
+              GST_DEINTERLACE_ALL) ? self->field_duration : 2 *
+          self->field_duration);
+    else
+      self->earliest_time = timestamp + diff;
+  } else {
+    self->earliest_time = GST_CLOCK_TIME_NONE;
+  }
+  GST_OBJECT_UNLOCK (self);
+}
+
+static void
+gst_deinterlace_reset_qos (GstDeinterlace * self)
+{
+  gst_deinterlace_update_qos (self, 0.5, 0, GST_CLOCK_TIME_NONE);
+  self->processed = 0;
+  self->dropped = 0;
+}
+
+static void
+gst_deinterlace_read_qos (GstDeinterlace * self, gdouble * proportion,
+    GstClockTime * time)
+{
+  GST_OBJECT_LOCK (self);
+  *proportion = self->proportion;
+  *time = self->earliest_time;
+  GST_OBJECT_UNLOCK (self);
+}
+
+/* Perform qos calculations before processing the next frame. Returns TRUE if
+ * the frame should be processed, FALSE if the frame can be dropped entirely */
+static gboolean
+gst_deinterlace_do_qos (GstDeinterlace * self, const GstBuffer * buffer)
+{
+  GstClockTime qostime, earliest_time;
+  GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
+  gdouble proportion;
+
+  /* no timestamp, can't do QoS => process frame */
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
+    GST_LOG_OBJECT (self, "invalid timestamp, can't do QoS, process frame");
+    goto keep_frame;
+  }
+
+  /* get latest QoS observation values */
+  gst_deinterlace_read_qos (self, &proportion, &earliest_time);
+
+  /* skip qos if we have no observation (yet) => process frame */
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
+    GST_LOG_OBJECT (self, "no observation yet, process frame");
+    goto keep_frame;
+  }
+
+  /* qos is done on running time */
+  qostime = gst_segment_to_running_time (&self->segment, GST_FORMAT_TIME,
+      timestamp);
+
+  /* see how our next timestamp relates to the latest qos timestamp */
+  GST_LOG_OBJECT (self, "qostime %" GST_TIME_FORMAT ", earliest %"
+      GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
+
+  if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
+    GstClockTime stream_time, jitter;
+    GstMessage *qos_msg;
+
+    GST_DEBUG_OBJECT (self, "we are late, drop frame");
+    self->dropped++;
+    stream_time =
+        gst_segment_to_stream_time (&self->segment, GST_FORMAT_TIME, timestamp);
+    jitter = GST_CLOCK_DIFF (qostime, earliest_time);
+    qos_msg =
+        gst_message_new_qos (GST_OBJECT (self), FALSE, qostime, stream_time,
+        timestamp, GST_BUFFER_DURATION (buffer));
+    gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
+    gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
+        self->processed, self->dropped);
+    gst_element_post_message (GST_ELEMENT (self), qos_msg);
+    return FALSE;
+  }
+
+  GST_LOG_OBJECT (self, "process frame");
+keep_frame:
+  self->processed++;
+  return TRUE;
+}
+
+static gboolean
+gst_deinterlace_fix_timestamps (GstDeinterlace * self,
+    GstVideoFrame * field1, GstVideoFrame * field2)
+{
+  GstVideoFrame *field3, *field4;
+  GstVideoInterlaceMode interlacing_mode;
+
+  /* FIXME: This is broken for rate < 0 */
+  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->buffer) =
+        self->pattern_base_ts + self->output_count * self->pattern_buf_dur;
+    GST_BUFFER_DURATION (field1->buffer) = self->pattern_buf_dur;
+    self->output_count++;
+  } else {
+    /* naive (but low-latency) timestamp adjustment based on subsequent
+     * fields/buffers */
+    if (field2
+        && GST_VIDEO_FRAME_PLANE_DATA (field1,
+            0) != GST_VIDEO_FRAME_PLANE_DATA (field2, 0)) {
+      if (GST_BUFFER_TIMESTAMP (field1->buffer) +
+          GST_BUFFER_DURATION (field1->buffer) ==
+          GST_BUFFER_TIMESTAMP (field2->buffer)) {
+        GST_BUFFER_TIMESTAMP (field1->buffer) =
+            GST_BUFFER_TIMESTAMP (field2->buffer) =
+            (GST_BUFFER_TIMESTAMP (field1->buffer) +
+            GST_BUFFER_TIMESTAMP (field2->buffer)) / 2;
+      } else {
+        GST_BUFFER_TIMESTAMP (field2->buffer) =
+            GST_BUFFER_TIMESTAMP (field1->buffer);
+      }
+    }
+
+    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].frame;
+    interlacing_mode = GST_VIDEO_INFO_INTERLACE_MODE (&field3->info);
+    if (IS_TELECINE (interlacing_mode)) {
+      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].frame;
+      if (GST_VIDEO_FRAME_PLANE_DATA (field3,
+              0) != GST_VIDEO_FRAME_PLANE_DATA (field4, 0)) {
+        /* telecine fields in separate buffers */
+        GST_BUFFER_TIMESTAMP (field3->buffer) =
+            (GST_BUFFER_TIMESTAMP (field3->buffer) +
+            GST_BUFFER_TIMESTAMP (field4->buffer)) / 2;
+      }
+    }
+
+    GST_BUFFER_DURATION (field1->buffer) =
+        GST_BUFFER_TIMESTAMP (field3->buffer) -
+        GST_BUFFER_TIMESTAMP (field1->buffer);
+  }
+
+  GST_DEBUG_OBJECT (self,
+      "Field 1 adjusted to ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1->buffer)),
+      GST_TIME_ARGS (GST_BUFFER_DURATION (field1->buffer)));
+  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 ? (self->history_count - 1) >> 1 : 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 (pattern < 0) {
+    GST_WARNING_OBJECT (self, "Failed to select a pattern");
+    return;
+  }
+
+  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;
+
+  for (i = 0; i < telecine_patterns[pattern].length; i++) {
+    gint state_idx =
+        self->low_latency ? (self->history_count - 1) >> 1 : self->state_count -
+        1;
+    state_idx -= i;
+    GST_LOG_OBJECT (self, "buf[%d] %s", i,
+        STATE_TO_STRING (self->buf_states[state_idx].state));
+  }
+
+  /* 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++;
+#if 0
+      } else if (!(state & GST_DRP)) {
+#endif
+      } else {
+        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;
+  gint fields_required;
+  GstBuffer *buf, *outbuf;
+  GstVideoFrame *outframe = NULL;
+  GstDeinterlaceField *field1, *field2;
+  GstVideoInterlaceMode interlacing_mode;
+  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;
+
+  memset (&pattern, 0, sizeof (pattern));
+
+restart:
+  ret = GST_FLOW_OK;
+  hl_no_lock = 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;
+  }
+
+  field1 = &self->field_history[self->history_count - 1];
+
+  if (locking != GST_DEINTERLACE_LOCKING_NONE) {
+    GstCaps *sinkcaps;
+
+    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->frame, &buf_state,
+        &interlacing_mode);
+
+    if (self->pattern != -1)
+      pattern = telecine_patterns[self->pattern];
+
+    /* patterns 0 and 1 are interlaced, the rest are telecine */
+    if (self->pattern > 1)
+      interlacing_mode = GST_VIDEO_INTERLACE_MODE_MIXED;
+
+    if (self->pattern == -1 || self->pattern_refresh
+        || !(buf_state & pattern.states[(phase + count) % pattern.length])) {
+      if (self->pattern == -1) {
+        GST_DEBUG_OBJECT (self, "No pattern lock - refresh lock");
+      } else if (self->pattern_refresh) {
+        GST_DEBUG_OBJECT (self, "Pattern refresh - refresh lock");
+      } else {
+        GST_DEBUG_OBJECT (self, "Unexpected buffer state - refresh lock");
+      }
+      /* 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 */
+      sinkcaps = gst_pad_get_current_caps (self->sinkpad);
+      if (!sinkcaps || !gst_deinterlace_setcaps (self, self->sinkpad, sinkcaps)) {
+        if (sinkcaps)
+          gst_caps_unref (sinkcaps);
+        return GST_FLOW_NOT_NEGOTIATED;
+      }
+
+      gst_caps_unref (sinkcaps);
+
+      if (flush_one && self->drop_orphans) {
+        GST_DEBUG_OBJECT (self, "Dropping orphan first field");
+        self->cur_field_idx--;
+        gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+        goto restart;
+      }
+    }
+  } else {
+    gst_deinterlace_get_buffer_state (self, field1->frame, NULL,
+        &interlacing_mode);
+  }
+
+  same_buffer = self->history_count >= 2
+      && (GST_VIDEO_FRAME_PLANE_DATA (field1->frame, 0) ==
+      GST_VIDEO_FRAME_PLANE_DATA (self->field_history[self->history_count -
+              2].frame, 0));
+
+  if ((flushing && self->history_count == 1) || (flush_one
+          && !self->drop_orphans) || (hl_no_lock && (self->history_count == 1
+              || !same_buffer))) {
+    /* This case is for flushing a single field:
+     * - flushing and 1 field in the history
+     * - flush one (due to orphans in the pattern) and do not drop orphans
+     * - high-latency pattern locking with no possible lock given the current
+     *   state and either only one field in the history or the tip two fields
+     *   are in separate buffers */
+    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_mode == GST_VIDEO_INTERLACE_MODE_PROGRESSIVE ||
+      (interlacing_mode == GST_VIDEO_INTERLACE_MODE_MIXED &&
+          !GST_VIDEO_FRAME_IS_INTERLACED (field1->frame))) {
+    /* This case is for processing progressive buffers, telecine or plain
+     * progressive */
+    GstVideoFrame *field1_frame;
+    GstBuffer *field1_buffer;
+
+    /* progressive */
+    fields_required = 2;
+
+    /* Not enough fields in the history */
+    if (!flushing && self->history_count < fields_required) {
+      GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
+          self->history_count, self->cur_field_idx + fields_required);
+      goto need_more;
+    }
+
+    field2 = &self->field_history[self->history_count - 2];
+    if (GST_VIDEO_FRAME_PLANE_DATA (field1->frame,
+            0) != GST_VIDEO_FRAME_PLANE_DATA (field2->frame, 0)) {
+      /* 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!");
+    }
+
+    if (IS_TELECINE (interlacing_mode)
+        && !gst_deinterlace_fix_timestamps (self, field1->frame, field2->frame)
+        && !flushing)
+      goto need_more;
+
+    GST_DEBUG_OBJECT (self,
+        "Frame type: Progressive; pushing buffer as a frame");
+    /* pop and push */
+    self->cur_field_idx--;
+    field1_frame = gst_deinterlace_pop_history (self);
+    field1_buffer = field1_frame->buffer;
+    gst_buffer_ref (field1_buffer);
+    gst_video_frame_unmap_and_free (field1_frame);
+    /* field2 is the same buffer as field1, but we need to remove it from the
+     * history anyway */
+    self->cur_field_idx--;
+    gst_video_frame_unmap_and_free (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_buffer)),
+        GST_TIME_ARGS (GST_BUFFER_DURATION (field1_buffer)),
+        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buffer) +
+            GST_BUFFER_DURATION (field1_buffer)));
+    if (self->discont) {
+      GST_BUFFER_FLAG_SET (field1_buffer, GST_BUFFER_FLAG_DISCONT);
+      self->discont = FALSE;
+    }
+    return gst_pad_push (self->srcpad, field1_buffer);
+  } else if (IS_TELECINE (interlacing_mode)
+      && GST_VIDEO_FRAME_IS_INTERLACED (field1->frame) && !same_buffer) {
+    /* This case needs to identify telecine mixed buffers that require weaving
+     * of two fields in different buffers.
+     * - interlacing mode is mixed
+     * - locked on to a telecine pattern
+     * - frame is interlaced
+     * - fields are in separate buffers
+     * If we don't yet have a pattern lock, we will have to deinterlace as we
+     * don't explicitly know we have a telecine sequence and so we drop through
+     * to the plain deinterlace case */
+    fields_required = 2;
+    if (!flushing && self->history_count < fields_required) {
+      GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
+          self->history_count, self->cur_field_idx + fields_required);
+      goto need_more;
+    }
+
+    field2 = &self->field_history[self->history_count - 2];
+    if (!gst_deinterlace_fix_timestamps (self, field1->frame, field2->frame)
+        && !flushing)
+      goto need_more;
+
+    /* 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 {
+    /* This is the final catch-all case that applies the selected deinterlacing
+     * method. At this point the fields to be processed are either definitely
+     * interlaced or we do not yet know that we have a telecine pattern lock
+     * and so the best we can do is to deinterlace the fields. */
+    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);
+    }
+
+    /* Not enough fields in the history */
+    if (!flushing && self->history_count < fields_required) {
+      GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
+          self->history_count, self->cur_field_idx + fields_required);
+      goto need_more;
+    }
+
+    GST_DEBUG_OBJECT (self,
+        "Frame type: Interlaced; deinterlacing using %s method",
+        methods_types[self->method_id].value_nick);
+  }
+
+  if (!flushing && self->cur_field_idx < 1) {
+    goto need_more;
+  } else if (self->cur_field_idx < 0 && flushing) {
+    self->cur_field_idx++;
+  }
+
+  if (self->fields == GST_DEINTERLACE_ALL || IS_TELECINE (interlacing_mode))
+    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");
+
+  if ((self->field_history[self->cur_field_idx].flags == PICTURE_INTERLACED_TOP
+          && (self->fields == GST_DEINTERLACE_TF
+              || IS_TELECINE (interlacing_mode)))
+      || (self->fields == GST_DEINTERLACE_ALL
+          && !IS_TELECINE (interlacing_mode))) {
+    GST_DEBUG_OBJECT (self, "deinterlacing top field");
+
+    /* create new buffer */
+    ret = gst_buffer_pool_acquire_buffer (self->pool, &outbuf, NULL);
+    if (ret != GST_FLOW_OK)
+      goto no_buffer;
+
+    g_return_val_if_fail (self->history_count >=
+        1 + gst_deinterlace_method_get_latency (self->method), GST_FLOW_ERROR);
+
+    buf =
+        self->field_history[self->history_count - 1 -
+        gst_deinterlace_method_get_latency (self->method)].frame->buffer;
+
+    if (!IS_TELECINE (interlacing_mode)) {
+      timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+      if (self->fields == GST_DEINTERLACE_ALL) {
+        if (self->segment.rate < 0)
+          GST_BUFFER_TIMESTAMP (outbuf) = timestamp + self->field_duration;
+        else
+          GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+        GST_BUFFER_DURATION (outbuf) = self->field_duration;
+      } else {
+        GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+        GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
+      }
+      GST_DEBUG_OBJECT (self,
+          "[ADJUST] 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)));
+    } else {
+      GST_BUFFER_TIMESTAMP (outbuf) =
+          GST_BUFFER_TIMESTAMP (field1->frame->buffer);
+      GST_BUFFER_DURATION (outbuf) =
+          GST_BUFFER_DURATION (field1->frame->buffer);
+    }
+
+    /* Check if we need to drop the frame because of QoS */
+    if (!gst_deinterlace_do_qos (self, buf)) {
+      self->cur_field_idx--;
+      gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+      gst_buffer_unref (outbuf);
+      outbuf = NULL;
+      ret = GST_FLOW_OK;
+    } else {
+      if (self->cur_field_idx < 0 && flushing) {
+        if (self->history_count == 1) {
+          gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+          goto need_more;
+        }
+        self->cur_field_idx++;
+      }
+      if (self->cur_field_idx < 0) {
+        goto need_more;
+      }
+      if (!flushing && self->cur_field_idx < 1) {
+        goto need_more;
+      }
+
+      /* map the frame so the deinterlace methods can write the data to the
+       * correct memory locations */
+      outframe =
+          gst_video_frame_new_and_map (&self->vinfo, outbuf, GST_MAP_WRITE);
+
+      /* do magic calculus */
+      gst_deinterlace_method_deinterlace_frame (self->method,
+          self->field_history, self->history_count, outframe,
+          self->cur_field_idx);
+
+      gst_video_frame_unmap_and_free (outframe);
+
+      self->cur_field_idx--;
+      /* need to remove the field in the telecine weaving case */
+      if ((IS_TELECINE (interlacing_mode)
+              && self->method_id == GST_DEINTERLACE_WEAVE)
+          || self->cur_field_idx + 1 +
+          gst_deinterlace_method_get_latency (self->method) <
+          self->history_count || flushing) {
+        gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+      }
+
+      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)));
+        if (self->discont) {
+          GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+          self->discont = FALSE;
+        }
+        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;
+      if (IS_TELECINE (interlacing_mode)
+          && self->method_id == GST_DEINTERLACE_WEAVE) {
+        /* pop off the second field */
+        GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
+            self->history_count);
+        self->cur_field_idx--;
+        gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+        interlacing_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
+        return ret;
+      }
+    }
+
+    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[self->cur_field_idx].flags ==
+      PICTURE_INTERLACED_TOP && (self->fields == GST_DEINTERLACE_BF
+          && !IS_TELECINE (interlacing_mode))) {
+    GST_DEBUG_OBJECT (self, "Removing unused top field");
+    self->cur_field_idx--;
+    gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+
+    if (flush_one && !self->drop_orphans) {
+      GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
+      goto restart;
+    }
+  }
+
+  if (self->history_count < fields_required)
+    return ret;
+
+  if (self->cur_field_idx < 0)
+    return ret;
+
+  /* deinterlace bottom_field */
+  if ((self->field_history[self->cur_field_idx].flags ==
+          PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_BF
+              || IS_TELECINE (interlacing_mode)))
+      || (self->fields == GST_DEINTERLACE_ALL
+          && !IS_TELECINE (interlacing_mode))) {
+    GST_DEBUG_OBJECT (self, "deinterlacing bottom field");
+
+    /* create new buffer */
+    ret = gst_buffer_pool_acquire_buffer (self->pool, &outbuf, NULL);
+    if (ret != GST_FLOW_OK)
+      goto no_buffer;
+
+    g_return_val_if_fail (self->history_count >=
+        gst_deinterlace_method_get_latency (self->method) + 1, GST_FLOW_ERROR);
+
+    buf =
+        self->field_history[self->history_count - 1 -
+        gst_deinterlace_method_get_latency (self->method)].frame->buffer;
+    if (!IS_TELECINE (interlacing_mode)) {
+      timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+      if (self->fields == GST_DEINTERLACE_ALL) {
+        if (self->segment.rate < 0)
+          GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+        else
+          GST_BUFFER_TIMESTAMP (outbuf) = timestamp + self->field_duration;
+        GST_BUFFER_DURATION (outbuf) = self->field_duration;
+      } else {
+        GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+        GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
+      }
+      GST_DEBUG_OBJECT (self,
+          "[ADJUST] 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)));
+    } else {
+      GST_BUFFER_TIMESTAMP (outbuf) =
+          GST_BUFFER_TIMESTAMP (field1->frame->buffer);
+      GST_BUFFER_DURATION (outbuf) =
+          GST_BUFFER_DURATION (field1->frame->buffer);
+    }
+
+    /* Check if we need to drop the frame because of QoS */
+    if (!gst_deinterlace_do_qos (self, buf)) {
+      self->cur_field_idx--;
+      gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+      gst_buffer_unref (outbuf);
+      outbuf = NULL;
+      ret = GST_FLOW_OK;
+    } else {
+      /* map the frame so the deinterlace methods can write the data to the
+       * correct memory locations */
+      outframe =
+          gst_video_frame_new_and_map (&self->vinfo, outbuf, GST_MAP_WRITE);
+
+      /* do magic calculus */
+      gst_deinterlace_method_deinterlace_frame (self->method,
+          self->field_history, self->history_count, outframe,
+          self->cur_field_idx);
+
+      gst_video_frame_unmap_and_free (outframe);
+
+      self->cur_field_idx--;
+      /* need to remove the field in the telecine weaving case */
+      if ((IS_TELECINE (interlacing_mode)
+              && self->method_id == GST_DEINTERLACE_WEAVE)
+          || self->cur_field_idx + 1 +
+          gst_deinterlace_method_get_latency (self->method) <
+          self->history_count) {
+        gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+      }
+
+      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;
+      if (IS_TELECINE (interlacing_mode)
+          && self->method_id == GST_DEINTERLACE_WEAVE) {
+        /* pop off the second field */
+        GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
+            self->history_count);
+        self->cur_field_idx--;
+        gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+        interlacing_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
+        return ret;
+      }
+    }
+
+    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[self->cur_field_idx].flags ==
+      PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_TF
+          && !IS_TELECINE (interlacing_mode))) {
+    GST_DEBUG_OBJECT (self, "Removing unused bottom field");
+    self->cur_field_idx--;
+    gst_video_frame_unmap_and_free (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;
+  }
+no_buffer:
+  {
+    GST_DEBUG_OBJECT (self, "could not allocate buffer");
+    return ret;
+  }
+}
+
+static gboolean
+gst_deinterlace_get_latency (GstDeinterlace * self)
+{
+  if (self->locking == GST_DEINTERLACE_LOCKING_AUTO) {
+    GstQuery *query;
+
+    query = gst_query_new_latency ();
+    if ((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, GstObject * parent, GstBuffer * buf)
+{
+  GstDeinterlace *self = GST_DEINTERLACE (parent);
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  GST_OBJECT_LOCK (self);
+  if (self->reconfigure || gst_pad_check_reconfigure (self->srcpad)) {
+    GstCaps *caps;
+
+    if ((gint) self->new_fields != -1)
+      self->user_set_fields = self->new_fields;
+    if ((gint) self->new_mode != -1)
+      self->mode = self->new_mode;
+    self->new_mode = -1;
+    self->new_fields = -1;
+
+    self->reconfigure = FALSE;
+    GST_OBJECT_UNLOCK (self);
+    caps = gst_pad_get_current_caps (self->sinkpad);
+    if (caps != NULL) {
+      if (!gst_deinterlace_setcaps (self, self->sinkpad, caps)) {
+        gst_pad_mark_reconfigure (self->srcpad);
+        gst_caps_unref (caps);
+        if (GST_PAD_IS_FLUSHING (self->srcpad))
+          return GST_FLOW_FLUSHING;
+        else
+          return GST_FLOW_NOT_NEGOTIATED;
+      }
+      gst_caps_unref (caps);
+    } else {
+      gst_pad_mark_reconfigure (self->srcpad);
+      return GST_FLOW_FLUSHING;
+    }
+  } else {
+    GST_OBJECT_UNLOCK (self);
+  }
+
+  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");
+    gst_deinterlace_reset_history (self, FALSE);
+    self->discont = TRUE;
+  }
+
+  gst_deinterlace_push_history (self, buf);
+  buf = NULL;
+
+  do {
+    ret = gst_deinterlace_output_frame (self, FALSE);
+  } while (!self->need_more && self->history_count > 0 && ret == GST_FLOW_OK);
+
+  return ret;
+}
+
+static gboolean
+gst_deinterlace_acceptcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps)
+{
+  gboolean ret;
+  GstCaps *ourcaps;
+
+  /* In AUTO/DISABLED mode we accept everything that is compatible with
+   * our template caps. In INTERLACED mode we force deinterlacing, meaning
+   * we can only possibly support the deinterlace caps.
+   * In AUTO_STRICT mode we accept all progressive formats, but only those
+   * interlaced format that we can actually deinterlace */
+  if (self->mode == GST_DEINTERLACE_MODE_DISABLED
+      || self->mode == GST_DEINTERLACE_MODE_AUTO) {
+    ourcaps = gst_pad_get_pad_template_caps (pad);
+    ret = gst_caps_is_subset (caps, ourcaps);
+    gst_caps_unref (ourcaps);
+  } else if (self->mode == GST_DEINTERLACE_MODE_INTERLACED) {
+    ourcaps = gst_static_caps_get (&deinterlace_caps);
+    ret = gst_caps_is_subset (caps, ourcaps);
+    gst_caps_unref (ourcaps);
+  } else if (self->mode == GST_DEINTERLACE_MODE_AUTO_STRICT) {
+    ourcaps = gst_static_caps_get (&progressive_caps);
+    ret = gst_caps_is_subset (caps, ourcaps);
+    gst_caps_unref (ourcaps);
+
+    if (!ret) {
+      ourcaps = gst_static_caps_get (&deinterlace_caps);
+      ret = gst_caps_is_subset (caps, ourcaps);
+      gst_caps_unref (ourcaps);
+    }
+  } else {
+    g_assert_not_reached ();
+  }
+
+  GST_DEBUG_OBJECT (pad, "accept-caps result:%d for caps %" GST_PTR_FORMAT,
+      ret, caps);
+
+  return ret;
+}
+
+static gboolean
+gst_deinterlace_fraction_double (gint * n_out, gint * d_out, gboolean half)
+{
+  gint n, d, gcd;
+
+  n = *n_out;
+  d = *d_out;
+
+  if (d == 0)
+    return FALSE;
+
+  if (n == 0)
+    return TRUE;
+
+  gcd = gst_util_greatest_common_divisor (n, d);
+  n /= gcd;
+  d /= gcd;
+
+  if (half) {
+    if (G_MAXINT / 2 >= ABS (d)) {
+      d *= 2;
+    } else if (n >= 2 && n != G_MAXINT) {
+      n /= 2;
+    } else {
+      d = G_MAXINT;
+    }
+  } else {
+    if (G_MAXINT / 2 >= ABS (n)) {
+      n *= 2;
+    } else if (d >= 2 && d != G_MAXINT) {
+      d /= 2;
+    } else {
+      n = G_MAXINT;
+    }
+  }
+
+  *n_out = n;
+  *d_out = d;
+
+  return TRUE;
+}
+
+static GstCaps *
+gst_deinterlace_caps_double_framerate (GstCaps * caps, gboolean half)
+{
+  guint len;
+
+  for (len = gst_caps_get_size (caps); len > 0; len--) {
+    GstStructure *s = gst_caps_get_structure (caps, len - 1);
+    const GValue *val;
+
+    val = gst_structure_get_value (s, "framerate");
+    if (!val)
+      continue;
+
+    if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION) {
+      gint n, d;
+
+      n = gst_value_get_fraction_numerator (val);
+      d = gst_value_get_fraction_denominator (val);
+
+      if (!gst_deinterlace_fraction_double (&n, &d, half)) {
+        gst_caps_remove_structure (caps, len - 1);
+        continue;
+      }
+
+      gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
+    } else if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION_RANGE) {
+      const GValue *min, *max;
+      GValue nrange = { 0, }, nmin = {
+      0,}, nmax = {
+      0,};
+      gint n, d;
+
+      g_value_init (&nrange, GST_TYPE_FRACTION_RANGE);
+      g_value_init (&nmin, GST_TYPE_FRACTION);
+      g_value_init (&nmax, GST_TYPE_FRACTION);
+
+      min = gst_value_get_fraction_range_min (val);
+      max = gst_value_get_fraction_range_max (val);
+
+      n = gst_value_get_fraction_numerator (min);
+      d = gst_value_get_fraction_denominator (min);
+
+      if (!gst_deinterlace_fraction_double (&n, &d, half)) {
+        g_value_unset (&nrange);
+        g_value_unset (&nmax);
+        g_value_unset (&nmin);
+        gst_caps_remove_structure (caps, len - 1);
+        continue;
+      }
+
+      gst_value_set_fraction (&nmin, n, d);
+
+      n = gst_value_get_fraction_numerator (max);
+      d = gst_value_get_fraction_denominator (max);
+
+      if (!gst_deinterlace_fraction_double (&n, &d, half)) {
+        g_value_unset (&nrange);
+        g_value_unset (&nmax);
+        g_value_unset (&nmin);
+        gst_caps_remove_structure (caps, len - 1);
+        continue;
+      }
+
+      gst_value_set_fraction (&nmax, n, d);
+      gst_value_set_fraction_range (&nrange, &nmin, &nmax);
+
+      gst_structure_take_value (s, "framerate", &nrange);
+
+      g_value_unset (&nmin);
+      g_value_unset (&nmax);
+    } else if (G_VALUE_TYPE (val) == GST_TYPE_LIST) {
+      const GValue *lval;
+      GValue nlist = { 0, };
+      GValue nval = { 0, };
+      gint i;
+
+      g_value_init (&nlist, GST_TYPE_LIST);
+      for (i = gst_value_list_get_size (val); i > 0; i--) {
+        gint n, d;
+
+        lval = gst_value_list_get_value (val, i - 1);
+
+        if (G_VALUE_TYPE (lval) != GST_TYPE_FRACTION)
+          continue;
+
+        n = gst_value_get_fraction_numerator (lval);
+        d = gst_value_get_fraction_denominator (lval);
+
+        /* Double/Half the framerate but if this fails simply
+         * skip this value from the list */
+        if (!gst_deinterlace_fraction_double (&n, &d, half)) {
+          continue;
+        }
+
+        g_value_init (&nval, GST_TYPE_FRACTION);
+
+        gst_value_set_fraction (&nval, n, d);
+        gst_value_list_append_and_take_value (&nlist, &nval);
+      }
+      gst_structure_take_value (s, "framerate", &nlist);
+    }
+  }
+
+  return caps;
+}
+
+static GstCaps *
+gst_deinterlace_getcaps (GstDeinterlace * self, GstPad * pad, GstCaps * filter)
+{
+  GstCaps *ret, *caps;
+  GstPad *otherpad;
+  gint len;
+  GstCaps *ourcaps;
+  GstCaps *peercaps;
+  GstCaps *tmp, *tmp2;
+
+  otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
+
+  ourcaps = gst_pad_get_pad_template_caps (pad);
+  peercaps = gst_pad_peer_query_caps (otherpad, NULL);
+
+  /* Filter any peercaps that are available with our template
+   * to get started with the subset of caps we actually support */
+  if (peercaps) {
+    GST_DEBUG_OBJECT (pad, "Peer has caps %" GST_PTR_FORMAT, peercaps);
+    caps = gst_caps_make_writable (gst_caps_intersect (ourcaps, peercaps));
+    gst_caps_unref (peercaps);
+    gst_caps_unref (ourcaps);
+    peercaps = ourcaps = NULL;
+  } else {
+    caps = gst_caps_make_writable (ourcaps);
+    ourcaps = NULL;
+  }
+
+  GST_DEBUG_OBJECT (pad,
+      "Transforming caps %" GST_PTR_FORMAT " with filter %" GST_PTR_FORMAT,
+      caps, filter);
+
+  /* If deinterlacing is disabled, we just passthrough the
+   * caps and everything */
+  if (self->mode == GST_DEINTERLACE_MODE_DISABLED) {
+    ret = caps;
+    caps = NULL;
+    goto done;
+  }
+
+  /* If deinterlacing is enforced, we can only accept the
+   * caps for which we can actually do deinterlacing */
+  if (self->mode == GST_DEINTERLACE_MODE_INTERLACED) {
+    tmp = gst_static_caps_get (&deinterlace_caps);
+    ret = gst_caps_intersect_full (caps, tmp, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (tmp);
+    tmp = NULL;
+    gst_caps_unref (caps);
+    caps = NULL;
+    goto done;
+  }
+
+  g_assert (self->mode == GST_DEINTERLACE_MODE_AUTO
+      || self->mode == GST_DEINTERLACE_MODE_AUTO_STRICT);
+
+  /* For the auto mode we have to do a bit more than that */
+  ret = gst_caps_new_empty ();
+
+  /* We can accept any structure if
+   * - they are progressive already
+   *
+   */
+  tmp = gst_static_caps_get (&progressive_caps);
+  tmp2 = gst_caps_intersect_full (caps, tmp, GST_CAPS_INTERSECT_FIRST);
+  gst_caps_unref (tmp);
+  tmp = NULL;
+  ret = gst_caps_merge (ret, tmp2);
+  tmp2 = NULL;
+
+  /* or
+   * - they have sysmem caps features and a format for which we support
+   *   deinterlacing
+   * or
+   * - they have ANY caps features, in which case we support it for
+   *   sysmem caps features for formats we support
+   *
+   * NOTE: These are the caps where we actually would do deinterlacing
+   * ourselves. If fields == ALL we would double the framerate so would
+   * have to half the framerate constraints from downstream here
+   */
+  tmp = gst_static_caps_get (&deinterlace_caps);
+  tmp2 = gst_caps_intersect_full (caps, tmp, GST_CAPS_INTERSECT_FIRST);
+  gst_caps_unref (tmp);
+  tmp = NULL;
+
+  for (len = gst_caps_get_size (tmp2); len > 0; len--) {
+    GstStructure *s = gst_caps_get_structure (tmp2, len - 1);
+
+    if (pad == self->sinkpad)
+      gst_structure_remove_field (s, "interlace-mode");
+    else
+      gst_structure_set (s, "interlace-mode", G_TYPE_STRING, "progressive",
+          NULL);
+  }
+
+  if (self->user_set_fields == GST_DEINTERLACE_ALL) {
+    tmp2 = gst_deinterlace_caps_double_framerate (tmp2, (pad == self->sinkpad));
+  }
+  if (self->user_set_fields == GST_DEINTERLACE_FIELDS_AUTO) {
+    tmp = gst_caps_copy (tmp2);
+    tmp = gst_deinterlace_caps_double_framerate (tmp, (pad == self->sinkpad));
+  }
+
+  ret = gst_caps_merge (ret, tmp2);
+  tmp2 = NULL;
+  if (tmp != NULL) {
+    ret = gst_caps_merge (ret, tmp);
+    tmp = NULL;
+  }
+
+  /* or
+   * - anything else in which case we would just passthrough again if we're
+   *   only in AUTO and not AUTO_STRICT mode
+   */
+  if (self->mode == GST_DEINTERLACE_MODE_AUTO)
+    ret = gst_caps_merge (ret, gst_caps_copy (caps));
+
+  gst_caps_unref (caps);
+  caps = NULL;
+
+done:
+
+  if (filter) {
+    GstCaps *tmp;
+
+    GST_LOG_OBJECT (pad, "intersecting with %" GST_PTR_FORMAT, filter);
+    tmp = gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (ret);
+    ret = tmp;
+  }
+
+  GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret);
+
+  return ret;
+}
+
+/* takes ownership of the pool, allocator and query */
+static gboolean
+gst_deinterlace_set_allocation (GstDeinterlace * self,
+    GstBufferPool * pool, GstAllocator * allocator,
+    GstAllocationParams * params)
+{
+  GstAllocator *oldalloc;
+  GstBufferPool *oldpool;
+
+  GST_OBJECT_LOCK (self);
+  oldpool = self->pool;
+  self->pool = pool;
+
+  oldalloc = self->allocator;
+  self->allocator = allocator;
+
+  if (params)
+    self->params = *params;
+  else
+    gst_allocation_params_init (&self->params);
+  GST_OBJECT_UNLOCK (self);
+
+  if (oldpool) {
+    GST_DEBUG_OBJECT (self, "deactivating old pool %p", oldpool);
+    gst_buffer_pool_set_active (oldpool, FALSE);
+    gst_object_unref (oldpool);
+  }
+  if (oldalloc) {
+    gst_object_unref (oldalloc);
+  }
+  if (pool) {
+    GST_DEBUG_OBJECT (self, "activating new pool %p", pool);
+    gst_buffer_pool_set_active (pool, TRUE);
+  }
+  return TRUE;
+}
+
+static gboolean
+gst_deinterlace_do_bufferpool (GstDeinterlace * self, GstCaps * outcaps)
+{
+  GstQuery *query;
+  gboolean result = TRUE;
+  GstBufferPool *pool;
+  GstAllocator *allocator;
+  GstAllocationParams params;
+  GstStructure *config;
+  guint size, min, max;
+
+  if (self->passthrough) {
+    /* we are in passthrough, the input buffer is never copied and always passed
+     * along. We never allocate an output buffer on the srcpad. What we do is
+     * let the upstream element decide if it wants to use a bufferpool and
+     * then we will proxy the downstream pool */
+    GST_DEBUG_OBJECT (self, "we're passthough, delay bufferpool");
+    gst_deinterlace_set_allocation (self, NULL, NULL, NULL);
+    return TRUE;
+  }
+
+  /* not passthrough, we need to allocate */
+  /* find a pool for the negotiated caps now */
+  GST_DEBUG_OBJECT (self, "doing allocation query");
+  query = gst_query_new_allocation (outcaps, TRUE);
+  if (!gst_pad_peer_query (self->srcpad, query)) {
+    /* not a problem, just debug a little */
+    GST_DEBUG_OBJECT (self, "peer ALLOCATION query failed");
+  }
+
+  GST_DEBUG_OBJECT (self, "ALLOCATION (%d) params: %" GST_PTR_FORMAT, result,
+      query);
+
+  /* we got configuration from our peer or the decide_allocation method,
+   * parse them */
+  if (gst_query_get_n_allocation_params (query) > 0) {
+    gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
+  } else {
+    allocator = NULL;
+    gst_allocation_params_init (&params);
+  }
+
+  if (gst_query_get_n_allocation_pools (query) > 0)
+    gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
+  else {
+    pool = NULL;
+    size = GST_VIDEO_INFO_SIZE (&self->vinfo);
+    min =
+        MAX ((gst_deinterlace_method_get_fields_required (self->method) +
+            1) / 2 + 1, 4);
+    max = 0;
+  }
+
+  if (pool == NULL) {
+    /* no pool, we can make our own */
+    GST_DEBUG_OBJECT (self, "no pool, making new pool");
+    pool = gst_video_buffer_pool_new ();
+  }
+
+  /* now configure */
+  config = gst_buffer_pool_get_config (pool);
+  gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
+  gst_buffer_pool_config_set_allocator (config, allocator, &params);
+  gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
+  gst_buffer_pool_set_config (pool, config);
+
+  /* now store */
+  result = gst_deinterlace_set_allocation (self, pool, allocator, &params);
+
+  gst_query_unref (query);
+
+  return result;
+}
+
+
+static gboolean
+gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps)
+{
+  GstCaps *srccaps = NULL;
+  GstVideoInterlaceMode interlacing_mode;
+  gint fps_n, fps_d;
+  GstCaps *peercaps, *current_caps;
+
+  gst_pad_check_reconfigure (self->srcpad);
+
+  if ((current_caps = gst_pad_get_current_caps (pad))) {
+    if (gst_caps_is_equal (caps, current_caps)) {
+      GST_DEBUG_OBJECT (pad, "Got same caps again, returning");
+      gst_caps_unref (current_caps);
+      return TRUE;
+    }
+    gst_deinterlace_reset_history (self, FALSE);
+    gst_caps_unref (current_caps);
+  }
+  peercaps = gst_pad_peer_query_caps (self->srcpad, NULL);
+
+  /* Make sure the peer caps are compatible with the template caps */
+  if (peercaps) {
+    GstCaps *tmp = gst_pad_get_pad_template_caps (self->srcpad);
+    GstCaps *tmp2 = gst_caps_intersect (peercaps, tmp);
+
+    gst_caps_unref (peercaps);
+    peercaps = NULL;
+    gst_caps_unref (tmp);
+
+    if (gst_caps_is_empty (tmp2)) {
+      gst_caps_unref (tmp2);
+      GST_ERROR_OBJECT (self, "Peer caps not compatible with template caps");
+      goto invalid_caps;
+    }
+    peercaps = tmp2;
+  }
+
+  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;
+    }
+  }
+
+  if (!gst_video_info_from_caps (&self->vinfo, caps))
+    goto invalid_caps;
+
+  fps_n = GST_VIDEO_INFO_FPS_N (&self->vinfo);
+  fps_d = GST_VIDEO_INFO_FPS_D (&self->vinfo);
+
+  /* Update passthrough information */
+  if (self->mode == GST_DEINTERLACE_MODE_DISABLED) {
+    self->passthrough = TRUE;
+    GST_DEBUG_OBJECT (self, "Passthrough because mode=disabled");
+  } else if (self->mode == GST_DEINTERLACE_MODE_INTERLACED) {
+    GstCaps *tmp = gst_static_caps_get (&deinterlace_caps);
+
+    if (!gst_caps_can_intersect (caps, tmp)) {
+      gst_caps_unref (tmp);
+      GST_ERROR_OBJECT (self, "Unsupported caps for mode=interlaced");
+      goto invalid_caps;
+    }
+
+    self->passthrough = FALSE;
+    GST_DEBUG_OBJECT (self, "Not passthrough because mode=interlaced");
+  } else if (self->mode == GST_DEINTERLACE_MODE_AUTO
+      || self->mode == GST_DEINTERLACE_MODE_AUTO_STRICT) {
+    GstCaps *tmp = gst_static_caps_get (&deinterlace_caps);
+
+    /* Already progressive? Passthrough */
+    if (!GST_VIDEO_INFO_IS_INTERLACED (&self->vinfo)) {
+      GST_DEBUG_OBJECT (self,
+          "Passthrough because mode=auto and progressive caps");
+      self->passthrough = TRUE;
+    } else if (gst_caps_can_intersect (caps, tmp)) {
+      if (peercaps) {
+        GstCaps *allowed_caps;
+        GstCaps *tmp2;
+        GstStructure *s;
+
+        allowed_caps = gst_caps_intersect (peercaps, tmp);
+
+        tmp2 = gst_caps_copy (caps);
+        s = gst_caps_get_structure (tmp2, 0);
+        gst_structure_set (s, "interlace-mode", G_TYPE_STRING, "progressive",
+            NULL);
+        gst_structure_remove_field (s, "framerate");
+
+        /* Downstream does not support progressive caps but supports
+         * the upstream caps, go passthrough.
+         * TODO: We might want to check the framerate compatibility
+         * of the caps too here
+         */
+        if (gst_caps_can_intersect (allowed_caps, caps)
+            && !gst_caps_can_intersect (allowed_caps, tmp2)) {
+          GST_DEBUG_OBJECT (self,
+              "Passthrough because mode=auto, "
+              "downstream does not support progressive caps and interlaced caps");
+          self->passthrough = TRUE;
+        } else {
+          GST_DEBUG_OBJECT (self, "Not passthrough because mode=auto, "
+              "downstream supports progressive caps and interlaced caps");
+          self->passthrough = FALSE;
+        }
+
+        gst_caps_unref (allowed_caps);
+        gst_caps_unref (tmp2);
+      } else {
+        GST_DEBUG_OBJECT (self,
+            "Not passthrough because mode=auto and interlaced caps");
+        self->passthrough = FALSE;
+      }
+    } else {
+      if (self->mode == GST_DEINTERLACE_MODE_AUTO) {
+        GST_WARNING_OBJECT (self,
+            "Passthrough because mode=auto and unsupported interlaced caps");
+        self->passthrough = TRUE;
+      } else {
+        gst_caps_unref (tmp);
+        GST_ERROR_OBJECT (self,
+            "Unsupported interlaced caps in mode=auto-strict");
+        goto invalid_caps;
+      }
+    }
+
+    gst_caps_unref (tmp);
+  } else {
+    g_assert_not_reached ();
+  }
+
+  interlacing_mode = GST_VIDEO_INFO_INTERLACE_MODE (&self->vinfo);
+
+  if (!self->passthrough) {
+    if (self->pattern_lock) {
+      srccaps = gst_caps_copy (caps);
+      if (self->pattern != -1
+          && G_UNLIKELY (!gst_util_fraction_multiply (fps_n, fps_d,
+                  telecine_patterns[self->pattern].ratio_n,
+                  telecine_patterns[self->pattern].ratio_d, &fps_n, &fps_d)))
+        GST_ERROR_OBJECT (self,
+            "Multiplying the framerate by the telecine pattern ratio overflowed!");
+      gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n,
+          fps_d, NULL);
+    } else if (self->locking == GST_DEINTERLACE_LOCKING_ACTIVE
+        || self->low_latency == 0) {
+      /* 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_copy (caps);
+    } else if (self->low_latency > 0
+        && interlacing_mode == GST_VIDEO_INTERLACE_MODE_MIXED
+        && self->pattern == -1) {
+      /* for initial buffers of a telecine pattern, until there is a lock we
+       * we output naïvely adjusted timestamps in low-latency pattern locking
+       * mode */
+      srccaps = gst_caps_copy (caps);
+      gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
+    } else if (self->user_set_fields == GST_DEINTERLACE_FIELDS_AUTO) {
+      srccaps = gst_caps_copy (caps);
+      if (peercaps) {
+        gboolean can_be_tf = FALSE;
+
+        /* We already know that we are not passthrough: interlace-mode will
+         * be progressive */
+        gst_caps_set_simple (srccaps, "interlace-mode", G_TYPE_STRING,
+            "progressive", NULL);
+
+        if (gst_caps_can_intersect (peercaps, srccaps)) {
+          GST_DEBUG_OBJECT (self, "Can deinterlace top fields");
+          can_be_tf = TRUE;
+        }
+        srccaps = gst_deinterlace_caps_double_framerate (srccaps, FALSE);
+        if (!gst_caps_can_intersect (peercaps, srccaps)) {
+          if (can_be_tf) {
+            GST_DEBUG_OBJECT (self, "Will deinterlace top fields");
+            gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n,
+                fps_d, NULL);
+            self->fields = GST_DEINTERLACE_TF;
+          } else {
+            GST_DEBUG_OBJECT (self,
+                "Can't negotiate upstream and downstream caps");
+            gst_caps_unref (srccaps);
+            goto invalid_caps;
+          }
+        } else {
+          GST_DEBUG_OBJECT (self, "Deinterlacing all fields");
+          self->fields = GST_DEINTERLACE_ALL;
+        }
+      } else {
+        GST_DEBUG_OBJECT (self,
+            "No peer caps yet, falling back to deinterlacing all fields");
+        self->fields = GST_DEINTERLACE_ALL;
+        srccaps = gst_deinterlace_caps_double_framerate (srccaps, FALSE);
+      }
+    } else {
+      self->fields = self->user_set_fields;
+      srccaps = gst_caps_copy (caps);
+      if (self->fields == GST_DEINTERLACE_ALL)
+        srccaps = gst_deinterlace_caps_double_framerate (srccaps, FALSE);
+    }
+
+    /* If not passthrough, we are going to output progressive content */
+    gst_caps_set_simple (srccaps, "interlace-mode", G_TYPE_STRING,
+        "progressive", NULL);
+
+    gst_deinterlace_set_method (self, self->method_id);
+    gst_deinterlace_method_setup (self->method, &self->vinfo);
+  } else {
+    srccaps = gst_caps_ref (caps);
+  }
+
+  if (fps_n != 0) {
+    self->field_duration = gst_util_uint64_scale (GST_SECOND, fps_d, 2 * fps_n);
+  } else {
+    self->field_duration = 0;
+  }
+
+  GST_DEBUG_OBJECT (pad, "Sink caps: %" GST_PTR_FORMAT, caps);
+  GST_DEBUG_OBJECT (pad, "Src  caps: %" GST_PTR_FORMAT, srccaps);
+
+  if (!gst_pad_set_caps (self->srcpad, srccaps))
+    goto set_caps_failed;
+
+  if (!gst_deinterlace_do_bufferpool (self, srccaps))
+    goto no_bufferpool;
+
+  if (peercaps)
+    gst_caps_unref (peercaps);
+  gst_caps_unref (srccaps);
+
+  return TRUE;
+
+invalid_caps:
+  {
+    if (peercaps)
+      gst_caps_unref (peercaps);
+    GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps);
+    gst_pad_mark_reconfigure (self->srcpad);
+    return FALSE;
+  }
+set_caps_failed:
+  {
+    GST_ERROR_OBJECT (pad, "Failed to set caps: %" GST_PTR_FORMAT, srccaps);
+    if (peercaps)
+      gst_caps_unref (peercaps);
+    gst_caps_unref (srccaps);
+    gst_pad_mark_reconfigure (self->srcpad);
+    return FALSE;
+  }
+no_bufferpool:
+  {
+    GST_ERROR_OBJECT (pad, "could not negotiate bufferpool");
+    if (peercaps)
+      gst_caps_unref (peercaps);
+    gst_caps_unref (srccaps);
+    gst_pad_mark_reconfigure (self->srcpad);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_deinterlace_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  gboolean res = TRUE;
+  GstDeinterlace *self = GST_DEINTERLACE (parent);
+
+  GST_LOG_OBJECT (pad, "received %s event: %" GST_PTR_FORMAT,
+      GST_EVENT_TYPE_NAME (event), event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps = NULL;
+
+      gst_event_parse_caps (event, &caps);
+      res = gst_deinterlace_setcaps (self, pad, caps);
+      gst_event_unref (event);
+      break;
+    }
+    case GST_EVENT_SEGMENT:
+    {
+      const GstSegment *segment;
+
+      gst_event_parse_segment (event, &segment);
+
+      gst_deinterlace_reset_qos (self);
+      gst_deinterlace_reset_history (self, FALSE);
+
+      if (segment->format == GST_FORMAT_TIME) {
+        GST_DEBUG_OBJECT (pad,
+            "Got SEGMENT event in TIME format, passing on (%"
+            GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")",
+            GST_TIME_ARGS (segment->start), GST_TIME_ARGS (segment->stop));
+        gst_segment_copy_into (segment, &self->segment);
+      } else {
+        GST_WARNING_OBJECT (pad, "Got SEGMENT event in %s format",
+            gst_format_get_name (segment->format));
+        gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
+      }
+
+      res = gst_pad_push_event (self->srcpad, event);
+      break;
+    }
+    case GST_EVENT_CUSTOM_DOWNSTREAM:{
+      gboolean still_state;
+
+      if (gst_video_event_parse_still_frame (event, &still_state)) {
+        GST_DEBUG_OBJECT (self, "Received still frame event, state %d",
+            still_state);
+
+        if (still_state) {
+          GstFlowReturn ret;
+
+          GST_DEBUG_OBJECT (self, "Handling still frame");
+          self->still_frame_mode = TRUE;
+          gst_deinterlace_reset_history (self, FALSE);
+          if (self->last_buffer) {
+            ret =
+                gst_pad_push (self->srcpad, gst_buffer_ref (self->last_buffer));
+            GST_DEBUG_OBJECT (self, "Pushed still frame, result: %s",
+                gst_flow_get_name (ret));
+          } else {
+            GST_WARNING_OBJECT (self, "No pending buffer!");
+          }
+        } else {
+          GST_DEBUG_OBJECT (self, "Ending still frames");
+          self->still_frame_mode = FALSE;
+        }
+      }
+
+      res = gst_pad_push_event (self->srcpad, event);
+      break;
+    }
+    case GST_EVENT_EOS:
+      self->have_eos = TRUE;
+      gst_deinterlace_reset_history (self, FALSE);
+      res = gst_pad_push_event (self->srcpad, event);
+      break;
+
+    case GST_EVENT_FLUSH_STOP:
+      if (self->still_frame_mode) {
+        GST_DEBUG_OBJECT (self, "Ending still frames");
+        self->still_frame_mode = FALSE;
+      }
+      gst_deinterlace_reset_qos (self);
+      res = gst_pad_push_event (self->srcpad, event);
+      gst_deinterlace_reset_history (self, TRUE);
+      break;
+
+    default:
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return res;
+}
+
+static gboolean
+gst_deinterlace_propose_allocation (GstDeinterlace * self, GstQuery * query)
+{
+  GstBufferPool *pool;
+  GstCaps *caps;
+  GstVideoInfo info;
+  guint size;
+  GstStructure *config;
+
+  gst_query_parse_allocation (query, &caps, NULL);
+
+  if (caps == NULL)
+    return FALSE;
+
+  if (!gst_video_info_from_caps (&info, caps))
+    return FALSE;
+
+  size = GST_VIDEO_INFO_SIZE (&info);
+
+  pool = gst_video_buffer_pool_new ();
+
+  gst_query_add_allocation_pool (query, pool, size, 0, 0);
+
+  config = gst_buffer_pool_get_config (pool);
+  gst_buffer_pool_config_set_params (config, caps, size,
+      (gst_deinterlace_method_get_fields_required (self->method) + 1) / 2 + 1,
+      0);
+  gst_buffer_pool_set_config (pool, config);
+
+  gst_object_unref (pool);
+  gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
+
+  return TRUE;
+}
+
+static gboolean
+gst_deinterlace_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  GstDeinterlace *self = GST_DEINTERLACE (parent);
+  gboolean res = FALSE;
+
+  GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *filter, *caps;
+
+      gst_query_parse_caps (query, &filter);
+      caps = gst_deinterlace_getcaps (self, pad, filter);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+      res = TRUE;
+      break;
+    }
+    case GST_QUERY_ACCEPT_CAPS:
+    {
+      GstCaps *caps;
+      gboolean ret;
+
+      gst_query_parse_accept_caps (query, &caps);
+      ret = gst_deinterlace_acceptcaps (self, pad, caps);
+      gst_query_set_accept_caps_result (query, ret);
+      res = TRUE;
+      break;
+    }
+    case GST_QUERY_ALLOCATION:
+      if (self->passthrough)
+        res = gst_pad_peer_query (self->srcpad, query);
+      else
+        res = gst_deinterlace_propose_allocation (self, query);
+      break;
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+  return res;
+}
+
+static GstStateChangeReturn
+gst_deinterlace_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstDeinterlace *self = GST_DEINTERLACE (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret != GST_STATE_CHANGE_SUCCESS)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_deinterlace_reset (self);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_deinterlace_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstDeinterlace *self = GST_DEINTERLACE (parent);
+  gboolean res;
+
+  GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_QOS:{
+      GstClockTimeDiff diff;
+      GstClockTime timestamp;
+      GstQOSType type;
+      gdouble proportion;
+
+      gst_event_parse_qos (event, &type, &proportion, &diff, &timestamp);
+
+      gst_deinterlace_update_qos (self, proportion, diff, timestamp);
+    }
+      /* fall through */
+    default:
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return res;
+}
+
+static gboolean
+gst_deinterlace_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  GstDeinterlace *self = GST_DEINTERLACE (parent);
+  gboolean res = FALSE;
+
+  GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_LATENCY:
+      if (!self->passthrough) {
+        GstClockTime min, max;
+        gboolean live;
+        GstPad *peer;
+
+        if ((peer = gst_pad_get_peer (self->sinkpad))) {
+          if ((res = gst_pad_query (peer, query))) {
+            GstClockTime latency;
+            gint fields_required = 0;
+            gint method_latency = 0;
+
+            if (self->method) {
+              fields_required =
+                  gst_deinterlace_method_get_fields_required (self->method);
+              method_latency =
+                  gst_deinterlace_method_get_latency (self->method);
+            }
+
+            gst_query_parse_latency (query, &live, &min, &max);
+
+            GST_DEBUG_OBJECT (self, "Peer latency: min %"
+                GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
+                GST_TIME_ARGS (min), GST_TIME_ARGS (max));
+
+            /* add our own latency */
+            latency = (fields_required + method_latency) * self->field_duration;
+
+            GST_DEBUG_OBJECT (self, "Our latency: min %" GST_TIME_FORMAT
+                ", max %" GST_TIME_FORMAT,
+                GST_TIME_ARGS (latency), GST_TIME_ARGS (latency));
+
+            min += latency;
+            if (max != GST_CLOCK_TIME_NONE)
+              max += latency;
+
+            GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
+                GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
+                GST_TIME_ARGS (min), GST_TIME_ARGS (max));
+
+            gst_query_set_latency (query, live, min, max);
+          }
+          gst_object_unref (peer);
+        } else {
+          res = FALSE;
+        }
+        break;
+      }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+
+  return res;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (deinterlace_debug, "deinterlace", 0, "Deinterlacer");
+
+#if HAVE_ORC
+  orc_init ();
+#endif
+
+  if (!gst_element_register (plugin, "deinterlace", GST_RANK_NONE,
+          GST_TYPE_DEINTERLACE)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    deinterlace,
+    "Deinterlacer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
+    GST_PACKAGE_ORIGIN);
diff --git a/gst/deinterlace/gstdeinterlace.h b/gst/deinterlace/gstdeinterlace.h
new file mode 100644
index 0000000..a8cc637
--- /dev/null
+++ b/gst/deinterlace/gstdeinterlace.h
@@ -0,0 +1,208 @@
+/*
+ * GStreamer
+ * Copyright (C) 2005 Martin Eikermann <meiker@upb.de>
+ * Copyright (C) 2008-2010 Sebastian Dröge <slomo@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_DEINTERLACE_H__
+#define __GST_DEINTERLACE_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideopool.h>
+#include <gst/video/gstvideometa.h>
+
+#include "gstdeinterlacemethod.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DEINTERLACE \
+  (gst_deinterlace_get_type())
+#define GST_DEINTERLACE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DEINTERLACE,GstDeinterlace))
+#define GST_DEINTERLACE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DEINTERLACE,GstDeinterlace))
+#define GST_IS_DEINTERLACE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DEINTERLACE))
+#define GST_IS_DEINTERLACE_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DEINTERLACE))
+
+typedef struct _GstDeinterlace GstDeinterlace;
+typedef struct _GstDeinterlaceClass GstDeinterlaceClass;
+
+typedef enum
+{
+  GST_DEINTERLACE_TOMSMOCOMP,
+  GST_DEINTERLACE_GREEDY_H,
+  GST_DEINTERLACE_GREEDY_L,
+  GST_DEINTERLACE_VFIR,
+  GST_DEINTERLACE_LINEAR,
+  GST_DEINTERLACE_LINEAR_BLEND,
+  GST_DEINTERLACE_SCALER_BOB,
+  GST_DEINTERLACE_WEAVE,
+  GST_DEINTERLACE_WEAVE_TFF,
+  GST_DEINTERLACE_WEAVE_BFF
+} GstDeinterlaceMethods;
+
+typedef enum
+{
+  GST_DEINTERLACE_ALL,         /* All (missing data is interp.) */
+  GST_DEINTERLACE_TF,          /* Top Fields Only */
+  GST_DEINTERLACE_BF,          /* Bottom Fields Only */
+  GST_DEINTERLACE_FIELDS_AUTO  /* Automatically detect */
+} GstDeinterlaceFields;
+
+typedef enum
+{
+  GST_DEINTERLACE_LAYOUT_AUTO,
+  GST_DEINTERLACE_LAYOUT_TFF,
+  GST_DEINTERLACE_LAYOUT_BFF
+} GstDeinterlaceFieldLayout;
+
+typedef enum {
+  GST_DEINTERLACE_MODE_AUTO,
+  GST_DEINTERLACE_MODE_INTERLACED,
+  GST_DEINTERLACE_MODE_DISABLED,
+  GST_DEINTERLACE_MODE_AUTO_STRICT
+} 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;
+
+  GstPad *srcpad, *sinkpad;
+
+  /* <private> */
+  GstDeinterlaceMode mode;
+
+  GstDeinterlaceFieldLayout field_layout;
+
+  GstDeinterlaceFields fields;
+
+  GstDeinterlaceFields user_set_fields;
+
+  /* current state (differs when flushing/inverse telecine using weave) */
+  GstDeinterlaceMethods method_id;
+  /* property value */
+  GstDeinterlaceMethods user_set_method_id;
+  GstDeinterlaceMethod *method;
+
+  GstVideoInfo vinfo;
+  GstBufferPool *pool;
+  GstAllocator *allocator;
+  GstAllocationParams params;
+
+  gboolean passthrough;
+  gboolean discont;
+
+  GstClockTime field_duration; /* Duration of one field */
+
+  /* The most recent pictures 
+     PictureHistory[0] is always the most recent.
+     Pointers are NULL if the picture in question isn't valid, e.g. because
+     the program just started or a picture was skipped.
+   */
+  GstDeinterlaceField field_history[GST_DEINTERLACE_MAX_FIELD_HISTORY];
+  guint history_count;
+  int cur_field_idx;
+
+  /* Set to TRUE if we're in still frame mode,
+     i.e. just forward all buffers
+   */
+  gboolean still_frame_mode;
+
+  /* Last buffer that was pushed in */
+  GstBuffer *last_buffer;
+
+  /* Current segment */
+  GstSegment segment;
+
+  /* QoS stuff */
+  gdouble proportion;
+  GstClockTime earliest_time;
+  gint64 processed;
+  gint64 dropped;
+
+  GstCaps *request_caps;
+
+  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
+{
+  GstElementClass parent_class;
+};
+
+GType gst_deinterlace_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_DEINTERLACE_H__ */
diff --git a/gst/deinterlace/gstdeinterlacemethod.c b/gst/deinterlace/gstdeinterlacemethod.c
new file mode 100644
index 0000000..93e77e7
--- /dev/null
+++ b/gst/deinterlace/gstdeinterlacemethod.c
@@ -0,0 +1,802 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008-2010 Sebastian Dröge <slomo@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstdeinterlacemethod.h"
+
+G_DEFINE_ABSTRACT_TYPE (GstDeinterlaceMethod, gst_deinterlace_method,
+    GST_TYPE_OBJECT);
+
+gboolean
+gst_deinterlace_method_supported (GType type, GstVideoFormat format, gint width,
+    gint height)
+{
+  GstDeinterlaceMethodClass *klass =
+      GST_DEINTERLACE_METHOD_CLASS (g_type_class_ref (type));
+  gboolean ret;
+
+  if (format == GST_VIDEO_FORMAT_UNKNOWN)
+    ret = TRUE;
+  else
+    ret = klass->supported (klass, format, width, height);
+  g_type_class_unref (klass);
+
+  return ret;
+}
+
+static gboolean
+gst_deinterlace_method_supported_impl (GstDeinterlaceMethodClass * klass,
+    GstVideoFormat format, gint width, gint height)
+{
+  switch (format) {
+    case GST_VIDEO_FORMAT_YUY2:
+      return (klass->deinterlace_frame_yuy2 != NULL);
+    case GST_VIDEO_FORMAT_YVYU:
+      return (klass->deinterlace_frame_yvyu != NULL);
+    case GST_VIDEO_FORMAT_UYVY:
+      return (klass->deinterlace_frame_uyvy != NULL);
+    case GST_VIDEO_FORMAT_I420:
+      return (klass->deinterlace_frame_i420 != NULL);
+    case GST_VIDEO_FORMAT_YV12:
+      return (klass->deinterlace_frame_yv12 != NULL);
+    case GST_VIDEO_FORMAT_Y444:
+      return (klass->deinterlace_frame_y444 != NULL);
+    case GST_VIDEO_FORMAT_Y42B:
+      return (klass->deinterlace_frame_y42b != NULL);
+    case GST_VIDEO_FORMAT_Y41B:
+      return (klass->deinterlace_frame_y41b != NULL);
+    case GST_VIDEO_FORMAT_AYUV:
+      return (klass->deinterlace_frame_ayuv != NULL);
+    case GST_VIDEO_FORMAT_NV12:
+      return (klass->deinterlace_frame_nv12 != NULL);
+    case GST_VIDEO_FORMAT_NV21:
+      return (klass->deinterlace_frame_nv21 != NULL);
+    case GST_VIDEO_FORMAT_ARGB:
+    case GST_VIDEO_FORMAT_xRGB:
+      return (klass->deinterlace_frame_argb != NULL);
+    case GST_VIDEO_FORMAT_ABGR:
+    case GST_VIDEO_FORMAT_xBGR:
+      return (klass->deinterlace_frame_abgr != NULL);
+    case GST_VIDEO_FORMAT_RGBA:
+    case GST_VIDEO_FORMAT_RGBx:
+      return (klass->deinterlace_frame_rgba != NULL);
+    case GST_VIDEO_FORMAT_BGRA:
+    case GST_VIDEO_FORMAT_BGRx:
+      return (klass->deinterlace_frame_bgra != NULL);
+    case GST_VIDEO_FORMAT_RGB:
+      return (klass->deinterlace_frame_rgb != NULL);
+    case GST_VIDEO_FORMAT_BGR:
+      return (klass->deinterlace_frame_bgr != NULL);
+    default:
+      return FALSE;
+  }
+}
+
+void
+gst_deinterlace_method_setup (GstDeinterlaceMethod * self, GstVideoInfo * vinfo)
+{
+  GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
+
+  klass->setup (self, vinfo);
+}
+
+static void
+gst_deinterlace_method_setup_impl (GstDeinterlaceMethod * self,
+    GstVideoInfo * vinfo)
+{
+  GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
+
+  self->vinfo = vinfo;
+
+  self->deinterlace_frame = NULL;
+
+  if (GST_VIDEO_INFO_FORMAT (self->vinfo) == GST_VIDEO_FORMAT_UNKNOWN)
+    return;
+
+  switch (GST_VIDEO_INFO_FORMAT (self->vinfo)) {
+    case GST_VIDEO_FORMAT_YUY2:
+      self->deinterlace_frame = klass->deinterlace_frame_yuy2;
+      break;
+    case GST_VIDEO_FORMAT_YVYU:
+      self->deinterlace_frame = klass->deinterlace_frame_yvyu;
+      break;
+    case GST_VIDEO_FORMAT_UYVY:
+      self->deinterlace_frame = klass->deinterlace_frame_uyvy;
+      break;
+    case GST_VIDEO_FORMAT_I420:
+      self->deinterlace_frame = klass->deinterlace_frame_i420;
+      break;
+    case GST_VIDEO_FORMAT_YV12:
+      self->deinterlace_frame = klass->deinterlace_frame_yv12;
+      break;
+    case GST_VIDEO_FORMAT_Y444:
+      self->deinterlace_frame = klass->deinterlace_frame_y444;
+      break;
+    case GST_VIDEO_FORMAT_Y42B:
+      self->deinterlace_frame = klass->deinterlace_frame_y42b;
+      break;
+    case GST_VIDEO_FORMAT_Y41B:
+      self->deinterlace_frame = klass->deinterlace_frame_y41b;
+      break;
+    case GST_VIDEO_FORMAT_AYUV:
+      self->deinterlace_frame = klass->deinterlace_frame_ayuv;
+      break;
+    case GST_VIDEO_FORMAT_NV12:
+      self->deinterlace_frame = klass->deinterlace_frame_nv12;
+      break;
+    case GST_VIDEO_FORMAT_NV21:
+      self->deinterlace_frame = klass->deinterlace_frame_nv21;
+      break;
+    case GST_VIDEO_FORMAT_ARGB:
+    case GST_VIDEO_FORMAT_xRGB:
+      self->deinterlace_frame = klass->deinterlace_frame_argb;
+      break;
+    case GST_VIDEO_FORMAT_ABGR:
+    case GST_VIDEO_FORMAT_xBGR:
+      self->deinterlace_frame = klass->deinterlace_frame_abgr;
+      break;
+    case GST_VIDEO_FORMAT_RGBA:
+    case GST_VIDEO_FORMAT_RGBx:
+      self->deinterlace_frame = klass->deinterlace_frame_rgba;
+      break;
+    case GST_VIDEO_FORMAT_BGRA:
+    case GST_VIDEO_FORMAT_BGRx:
+      self->deinterlace_frame = klass->deinterlace_frame_bgra;
+      break;
+    case GST_VIDEO_FORMAT_RGB:
+      self->deinterlace_frame = klass->deinterlace_frame_rgb;
+      break;
+    case GST_VIDEO_FORMAT_BGR:
+      self->deinterlace_frame = klass->deinterlace_frame_bgr;
+      break;
+    default:
+      self->deinterlace_frame = NULL;
+      break;
+  }
+}
+
+static void
+gst_deinterlace_method_class_init (GstDeinterlaceMethodClass * klass)
+{
+  klass->setup = gst_deinterlace_method_setup_impl;
+  klass->supported = gst_deinterlace_method_supported_impl;
+}
+
+static void
+gst_deinterlace_method_init (GstDeinterlaceMethod * self)
+{
+  self->vinfo = NULL;
+}
+
+void
+gst_deinterlace_method_deinterlace_frame (GstDeinterlaceMethod * self,
+    const GstDeinterlaceField * history, guint history_count,
+    GstVideoFrame * outframe, int cur_field_idx)
+{
+  g_assert (self->deinterlace_frame != NULL);
+  self->deinterlace_frame (self, history, history_count, outframe,
+      cur_field_idx);
+}
+
+gint
+gst_deinterlace_method_get_fields_required (GstDeinterlaceMethod * self)
+{
+  GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
+
+  return klass->fields_required;
+}
+
+gint
+gst_deinterlace_method_get_latency (GstDeinterlaceMethod * self)
+{
+  GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
+
+  return klass->latency;
+}
+
+G_DEFINE_ABSTRACT_TYPE (GstDeinterlaceSimpleMethod,
+    gst_deinterlace_simple_method, GST_TYPE_DEINTERLACE_METHOD);
+
+static gboolean
+gst_deinterlace_simple_method_supported (GstDeinterlaceMethodClass * mklass,
+    GstVideoFormat format, gint width, gint height)
+{
+  GstDeinterlaceSimpleMethodClass *klass =
+      GST_DEINTERLACE_SIMPLE_METHOD_CLASS (mklass);
+
+  if (!GST_DEINTERLACE_METHOD_CLASS
+      (gst_deinterlace_simple_method_parent_class)->supported (mklass, format,
+          width, height))
+    return FALSE;
+
+  switch (format) {
+    case GST_VIDEO_FORMAT_ARGB:
+    case GST_VIDEO_FORMAT_xRGB:
+      return (klass->interpolate_scanline_argb != NULL
+          && klass->copy_scanline_argb != NULL);
+    case GST_VIDEO_FORMAT_RGBA:
+    case GST_VIDEO_FORMAT_RGBx:
+      return (klass->interpolate_scanline_rgba != NULL
+          && klass->copy_scanline_rgba != NULL);
+    case GST_VIDEO_FORMAT_ABGR:
+    case GST_VIDEO_FORMAT_xBGR:
+      return (klass->interpolate_scanline_abgr != NULL
+          && klass->copy_scanline_abgr != NULL);
+    case GST_VIDEO_FORMAT_BGRA:
+    case GST_VIDEO_FORMAT_BGRx:
+      return (klass->interpolate_scanline_bgra != NULL
+          && klass->copy_scanline_bgra != NULL);
+    case GST_VIDEO_FORMAT_RGB:
+      return (klass->interpolate_scanline_rgb != NULL
+          && klass->copy_scanline_rgb != NULL);
+    case GST_VIDEO_FORMAT_BGR:
+      return (klass->interpolate_scanline_bgr != NULL
+          && klass->copy_scanline_bgr != NULL);
+    case GST_VIDEO_FORMAT_YUY2:
+      return (klass->interpolate_scanline_yuy2 != NULL
+          && klass->copy_scanline_yuy2 != NULL);
+    case GST_VIDEO_FORMAT_YVYU:
+      return (klass->interpolate_scanline_yvyu != NULL
+          && klass->copy_scanline_yvyu != NULL);
+    case GST_VIDEO_FORMAT_UYVY:
+      return (klass->interpolate_scanline_uyvy != NULL
+          && klass->copy_scanline_uyvy != NULL);
+    case GST_VIDEO_FORMAT_AYUV:
+      return (klass->interpolate_scanline_ayuv != NULL
+          && klass->copy_scanline_ayuv != NULL);
+    case GST_VIDEO_FORMAT_NV12:
+      return (klass->interpolate_scanline_nv12 != NULL
+          && klass->copy_scanline_nv12 != NULL);
+    case GST_VIDEO_FORMAT_NV21:
+      return (klass->interpolate_scanline_nv21 != NULL
+          && klass->copy_scanline_nv21 != NULL);
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+    case GST_VIDEO_FORMAT_Y444:
+    case GST_VIDEO_FORMAT_Y42B:
+    case GST_VIDEO_FORMAT_Y41B:
+      return (klass->interpolate_scanline_planar_y != NULL
+          && klass->copy_scanline_planar_y != NULL &&
+          klass->interpolate_scanline_planar_u != NULL
+          && klass->copy_scanline_planar_u != NULL &&
+          klass->interpolate_scanline_planar_v != NULL
+          && klass->copy_scanline_planar_v != NULL);
+    default:
+      return FALSE;
+  }
+}
+
+static void
+    gst_deinterlace_simple_method_interpolate_scanline_packed
+    (GstDeinterlaceSimpleMethod * self, guint8 * out,
+    const GstDeinterlaceScanlineData * scanlines, guint stride)
+{
+  memcpy (out, scanlines->m1, stride);
+}
+
+static void
+gst_deinterlace_simple_method_copy_scanline_packed (GstDeinterlaceSimpleMethod *
+    self, guint8 * out, const GstDeinterlaceScanlineData * scanlines,
+    guint stride)
+{
+  memcpy (out, scanlines->m0, stride);
+}
+
+static void
+gst_deinterlace_simple_method_deinterlace_frame_packed (GstDeinterlaceMethod *
+    method, const GstDeinterlaceField * history, guint history_count,
+    GstVideoFrame * outframe, gint cur_field_idx)
+{
+  GstDeinterlaceSimpleMethod *self = GST_DEINTERLACE_SIMPLE_METHOD (method);
+#ifndef G_DISABLE_ASSERT
+  GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self);
+#endif
+  GstDeinterlaceScanlineData scanlines;
+  guint cur_field_flags;
+  gint i;
+  gint frame_height, frame_width;
+  GstVideoFrame *framep, *frame0, *frame1, *frame2;
+
+  g_assert (self->interpolate_scanline_packed != NULL);
+  g_assert (self->copy_scanline_packed != NULL);
+
+  frame_height = GST_VIDEO_FRAME_HEIGHT (outframe);
+  frame_width = GST_VIDEO_FRAME_PLANE_STRIDE (outframe, 0);
+
+  frame0 = history[cur_field_idx].frame;
+  frame_width = MIN (frame_width, GST_VIDEO_FRAME_PLANE_STRIDE (frame0, 0));
+  cur_field_flags = history[cur_field_idx].flags;
+
+  framep = (cur_field_idx > 0 ? history[cur_field_idx - 1].frame : NULL);
+  if (framep)
+    frame_width = MIN (frame_width, GST_VIDEO_FRAME_PLANE_STRIDE (framep, 0));
+
+  g_assert (dm_class->fields_required <= 4);
+
+  frame1 =
+      (cur_field_idx + 1 <
+      history_count ? history[cur_field_idx + 1].frame : NULL);
+  if (frame1)
+    frame_width = MIN (frame_width, GST_VIDEO_FRAME_PLANE_STRIDE (frame1, 0));
+
+  frame2 =
+      (cur_field_idx + 2 <
+      history_count ? history[cur_field_idx + 2].frame : NULL);
+  if (frame2)
+    frame_width = MIN (frame_width, GST_VIDEO_FRAME_PLANE_STRIDE (frame2, 0));
+
+#define CLAMP_LOW(i) (((i)<0) ? (i+2) : (i))
+#define CLAMP_HI(i) (((i)>=(frame_height)) ? (i-2) : (i))
+#define LINE(x,i) (((guint8*)GST_VIDEO_FRAME_PLANE_DATA((x),0)) + CLAMP_HI(CLAMP_LOW(i)) * \
+    GST_VIDEO_FRAME_PLANE_STRIDE((x),0))
+#define LINE2(x,i) ((x) ? LINE(x,i) : NULL)
+
+  for (i = 0; i < frame_height; i++) {
+    memset (&scanlines, 0, sizeof (scanlines));
+    scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
+
+    if (!((i & 1) ^ scanlines.bottom_field)) {
+      /* copying */
+      scanlines.tp = LINE2 (framep, i - 1);
+      scanlines.bp = LINE2 (framep, i + 1);
+
+      scanlines.tt0 = LINE2 (frame0, (i - 2 >= 0) ? i - 2 : i);
+      scanlines.m0 = LINE2 (frame0, i);
+      scanlines.bb0 = LINE2 (frame0, (i + 2 < frame_height ? i + 2 : i));
+
+      scanlines.t1 = LINE2 (frame1, i - 1);
+      scanlines.b1 = LINE2 (frame1, i + 1);
+
+      scanlines.tt2 = LINE2 (frame2, (i - 2 >= 0) ? i - 2 : i);
+      scanlines.m2 = LINE2 (frame2, i);
+      scanlines.bb2 = LINE2 (frame2, (i + 2 < frame_height ? i + 2 : i));
+
+      self->copy_scanline_packed (self, LINE (outframe, i), &scanlines,
+          frame_width);
+    } else {
+      /* interpolating */
+      scanlines.ttp = LINE2 (framep, (i - 2 >= 0) ? i - 2 : i);
+      scanlines.mp = LINE2 (framep, i);
+      scanlines.bbp = LINE2 (framep, (i + 2 < frame_height ? i + 2 : i));
+
+      scanlines.t0 = LINE2 (frame0, i - 1);
+      scanlines.b0 = LINE2 (frame0, i + 1);
+
+      scanlines.tt1 = LINE2 (frame1, (i - 2 >= 0) ? i - 2 : i);
+      scanlines.m1 = LINE2 (frame1, i);
+      scanlines.bb1 = LINE2 (frame1, (i + 2 < frame_height ? i + 2 : i));
+
+      scanlines.t2 = LINE2 (frame2, i - 1);
+      scanlines.b2 = LINE2 (frame2, i + 1);
+
+      self->interpolate_scanline_packed (self, LINE (outframe, i), &scanlines,
+          frame_width);
+    }
+#undef LINE
+#undef LINE2
+  }
+}
+
+static void
+    gst_deinterlace_simple_method_interpolate_scanline_planar_y
+    (GstDeinterlaceSimpleMethod * self, guint8 * out,
+    const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m1, size);
+}
+
+static void
+gst_deinterlace_simple_method_copy_scanline_planar_y (GstDeinterlaceSimpleMethod
+    * self, guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint
+    size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+static void
+    gst_deinterlace_simple_method_interpolate_scanline_planar_u
+    (GstDeinterlaceSimpleMethod * self, guint8 * out,
+    const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m1, size);
+}
+
+static void
+gst_deinterlace_simple_method_copy_scanline_planar_u (GstDeinterlaceSimpleMethod
+    * self, guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint
+    size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+static void
+    gst_deinterlace_simple_method_interpolate_scanline_planar_v
+    (GstDeinterlaceSimpleMethod * self, guint8 * out,
+    const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m1, size);
+}
+
+static void
+gst_deinterlace_simple_method_copy_scanline_planar_v (GstDeinterlaceSimpleMethod
+    * self, guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint
+    size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+static void
+    gst_deinterlace_simple_method_deinterlace_frame_planar_plane
+    (GstDeinterlaceSimpleMethod * self, GstVideoFrame * dest,
+    const GstVideoFrame * frame0, const GstVideoFrame * frame1,
+    const GstVideoFrame * frame2, const GstVideoFrame * framep,
+    guint cur_field_flags, gint plane,
+    GstDeinterlaceSimpleMethodFunction copy_scanline,
+    GstDeinterlaceSimpleMethodFunction interpolate_scanline)
+{
+  GstDeinterlaceScanlineData scanlines;
+  gint i;
+  gint frame_height, frame_width;
+
+  frame_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, plane);
+  frame_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, plane) *
+      GST_VIDEO_FRAME_COMP_PSTRIDE (dest, plane);
+
+  g_assert (interpolate_scanline != NULL);
+  g_assert (copy_scanline != NULL);
+
+#define LINE(x,i) (((guint8*)GST_VIDEO_FRAME_PLANE_DATA((x),plane)) + CLAMP_HI(CLAMP_LOW(i)) * \
+    GST_VIDEO_FRAME_PLANE_STRIDE((x),plane))
+#define LINE2(x,i) ((x) ? LINE(x,i) : NULL)
+
+  for (i = 0; i < frame_height; i++) {
+    memset (&scanlines, 0, sizeof (scanlines));
+    scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
+
+    if (!((i & 1) ^ scanlines.bottom_field)) {
+      /* copying */
+      scanlines.tp = LINE2 (framep, i - 1);
+      scanlines.bp = LINE2 (framep, i + 1);
+
+      scanlines.tt0 = LINE2 (frame0, (i - 2 >= 0) ? i - 2 : i);
+      scanlines.m0 = LINE2 (frame0, i);
+      scanlines.bb0 = LINE2 (frame0, (i + 2 < frame_height ? i + 2 : i));
+
+      scanlines.t1 = LINE2 (frame1, i - 1);
+      scanlines.b1 = LINE2 (frame1, i + 1);
+
+      scanlines.tt2 = LINE2 (frame2, (i - 2 >= 0) ? i - 2 : i);
+      scanlines.m2 = LINE2 (frame2, i);
+      scanlines.bb2 = LINE2 (frame2, (i + 2 < frame_height ? i + 2 : i));
+
+      copy_scanline (self, LINE (dest, i), &scanlines, frame_width);
+    } else {
+      /* interpolating */
+      scanlines.ttp = LINE2 (framep, (i - 2 >= 0) ? i - 2 : i);
+      scanlines.mp = LINE2 (framep, i);
+      scanlines.bbp = LINE2 (framep, (i + 2 < frame_height ? i + 2 : i));
+
+      scanlines.t0 = LINE2 (frame0, i - 1);
+      scanlines.b0 = LINE2 (frame0, i + 1);
+
+      scanlines.tt1 = LINE2 (frame1, (i - 2 >= 0) ? i - 2 : i);
+      scanlines.m1 = LINE2 (frame1, i);
+      scanlines.bb1 = LINE2 (frame1, (i + 2 < frame_height ? i + 2 : i));
+
+      scanlines.t2 = LINE2 (frame2, i - 1);
+      scanlines.b2 = LINE2 (frame2, i + 1);
+
+      interpolate_scanline (self, LINE (dest, i), &scanlines, frame_width);
+    }
+#undef LINE
+#undef LINE2
+  }
+}
+
+static void
+gst_deinterlace_simple_method_deinterlace_frame_planar (GstDeinterlaceMethod *
+    method, const GstDeinterlaceField * history, guint history_count,
+    GstVideoFrame * outframe, gint cur_field_idx)
+{
+  GstDeinterlaceSimpleMethod *self = GST_DEINTERLACE_SIMPLE_METHOD (method);
+#ifndef G_DISABLE_ASSERT
+  GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self);
+#endif
+  const GstVideoFrame *frame0, *frame1, *frame2, *framep;
+  guint cur_field_flags = history[cur_field_idx].flags;
+  gint i;
+  GstDeinterlaceSimpleMethodFunction copy_scanline;
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline;
+
+  g_assert (self->interpolate_scanline_planar[0] != NULL);
+  g_assert (self->interpolate_scanline_planar[1] != NULL);
+  g_assert (self->interpolate_scanline_planar[2] != NULL);
+  g_assert (self->copy_scanline_planar[0] != NULL);
+  g_assert (self->copy_scanline_planar[1] != NULL);
+  g_assert (self->copy_scanline_planar[2] != NULL);
+
+  for (i = 0; i < 3; i++) {
+    copy_scanline = self->copy_scanline_planar[i];
+    interpolate_scanline = self->interpolate_scanline_planar[i];
+
+    framep = (cur_field_idx > 0 ? history[cur_field_idx - 1].frame : NULL);
+
+    frame0 = history[cur_field_idx].frame;
+
+    g_assert (dm_class->fields_required <= 4);
+
+    frame1 =
+        (cur_field_idx + 1 <
+        history_count ? history[cur_field_idx + 1].frame : NULL);
+    frame2 =
+        (cur_field_idx + 2 <
+        history_count ? history[cur_field_idx + 2].frame : NULL);
+
+    gst_deinterlace_simple_method_deinterlace_frame_planar_plane (self,
+        outframe, frame0, frame1, frame2, framep, cur_field_flags, i,
+        copy_scanline, interpolate_scanline);
+  }
+}
+
+static void
+gst_deinterlace_simple_method_deinterlace_frame_nv12 (GstDeinterlaceMethod *
+    method, const GstDeinterlaceField * history, guint history_count,
+    GstVideoFrame * outframe, gint cur_field_idx)
+{
+  GstDeinterlaceSimpleMethod *self = GST_DEINTERLACE_SIMPLE_METHOD (method);
+#ifndef G_DISABLE_ASSERT
+  GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self);
+#endif
+  const GstVideoFrame *frame0, *frame1, *frame2, *framep;
+  guint cur_field_flags = history[cur_field_idx].flags;
+  gint i;
+
+  g_assert (self->interpolate_scanline_packed != NULL);
+  g_assert (self->copy_scanline_packed != NULL);
+
+  for (i = 0; i < 2; i++) {
+    framep = (cur_field_idx > 0 ? history[cur_field_idx - 1].frame : NULL);
+
+    frame0 = history[cur_field_idx].frame;
+
+    g_assert (dm_class->fields_required <= 4);
+
+    frame1 =
+        (cur_field_idx + 1 <
+        history_count ? history[cur_field_idx + 1].frame : NULL);
+    frame2 =
+        (cur_field_idx + 2 <
+        history_count ? history[cur_field_idx + 2].frame : NULL);
+
+    gst_deinterlace_simple_method_deinterlace_frame_planar_plane (self,
+        outframe, frame0, frame1, frame2, framep, cur_field_flags, i,
+        self->copy_scanline_packed, self->interpolate_scanline_packed);
+  }
+}
+
+static void
+gst_deinterlace_simple_method_setup (GstDeinterlaceMethod * method,
+    GstVideoInfo * vinfo)
+{
+  GstDeinterlaceSimpleMethod *self = GST_DEINTERLACE_SIMPLE_METHOD (method);
+  GstDeinterlaceSimpleMethodClass *klass =
+      GST_DEINTERLACE_SIMPLE_METHOD_GET_CLASS (self);
+
+  GST_DEINTERLACE_METHOD_CLASS
+      (gst_deinterlace_simple_method_parent_class)->setup (method, vinfo);
+
+  self->interpolate_scanline_packed = NULL;
+  self->copy_scanline_packed = NULL;
+
+  self->interpolate_scanline_planar[0] = NULL;
+  self->interpolate_scanline_planar[1] = NULL;
+  self->interpolate_scanline_planar[2] = NULL;
+  self->copy_scanline_planar[0] = NULL;
+  self->copy_scanline_planar[1] = NULL;
+  self->copy_scanline_planar[2] = NULL;
+
+  if (GST_VIDEO_INFO_FORMAT (vinfo) == GST_VIDEO_FORMAT_UNKNOWN)
+    return;
+
+  switch (GST_VIDEO_INFO_FORMAT (vinfo)) {
+    case GST_VIDEO_FORMAT_YUY2:
+      self->interpolate_scanline_packed = klass->interpolate_scanline_yuy2;
+      self->copy_scanline_packed = klass->copy_scanline_yuy2;
+      break;
+    case GST_VIDEO_FORMAT_YVYU:
+      self->interpolate_scanline_packed = klass->interpolate_scanline_yvyu;
+      self->copy_scanline_packed = klass->copy_scanline_yvyu;
+      break;
+    case GST_VIDEO_FORMAT_UYVY:
+      self->interpolate_scanline_packed = klass->interpolate_scanline_uyvy;
+      self->copy_scanline_packed = klass->copy_scanline_uyvy;
+      break;
+    case GST_VIDEO_FORMAT_AYUV:
+      self->interpolate_scanline_packed = klass->interpolate_scanline_ayuv;
+      self->copy_scanline_packed = klass->copy_scanline_ayuv;
+      break;
+    case GST_VIDEO_FORMAT_ARGB:
+    case GST_VIDEO_FORMAT_xRGB:
+      self->interpolate_scanline_packed = klass->interpolate_scanline_argb;
+      self->copy_scanline_packed = klass->copy_scanline_argb;
+      break;
+    case GST_VIDEO_FORMAT_ABGR:
+    case GST_VIDEO_FORMAT_xBGR:
+      self->interpolate_scanline_packed = klass->interpolate_scanline_abgr;
+      self->copy_scanline_packed = klass->copy_scanline_abgr;
+      break;
+    case GST_VIDEO_FORMAT_RGBA:
+    case GST_VIDEO_FORMAT_RGBx:
+      self->interpolate_scanline_packed = klass->interpolate_scanline_rgba;
+      self->copy_scanline_packed = klass->copy_scanline_rgba;
+      break;
+    case GST_VIDEO_FORMAT_BGRA:
+    case GST_VIDEO_FORMAT_BGRx:
+      self->interpolate_scanline_packed = klass->interpolate_scanline_bgra;
+      self->copy_scanline_packed = klass->copy_scanline_bgra;
+      break;
+    case GST_VIDEO_FORMAT_RGB:
+      self->interpolate_scanline_packed = klass->interpolate_scanline_rgb;
+      self->copy_scanline_packed = klass->copy_scanline_rgb;
+      break;
+    case GST_VIDEO_FORMAT_BGR:
+      self->interpolate_scanline_packed = klass->interpolate_scanline_bgr;
+      self->copy_scanline_packed = klass->copy_scanline_bgr;
+      break;
+    case GST_VIDEO_FORMAT_NV12:
+      self->interpolate_scanline_packed = klass->interpolate_scanline_nv12;
+      self->copy_scanline_packed = klass->copy_scanline_nv12;
+      break;
+    case GST_VIDEO_FORMAT_NV21:
+      self->interpolate_scanline_packed = klass->interpolate_scanline_nv21;
+      self->copy_scanline_packed = klass->copy_scanline_nv21;
+      break;
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+    case GST_VIDEO_FORMAT_Y444:
+    case GST_VIDEO_FORMAT_Y42B:
+    case GST_VIDEO_FORMAT_Y41B:
+      self->interpolate_scanline_planar[0] =
+          klass->interpolate_scanline_planar_y;
+      self->copy_scanline_planar[0] = klass->copy_scanline_planar_y;
+      self->interpolate_scanline_planar[1] =
+          klass->interpolate_scanline_planar_u;
+      self->copy_scanline_planar[1] = klass->copy_scanline_planar_u;
+      self->interpolate_scanline_planar[2] =
+          klass->interpolate_scanline_planar_v;
+      self->copy_scanline_planar[2] = klass->copy_scanline_planar_v;
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_deinterlace_simple_method_class_init (GstDeinterlaceSimpleMethodClass
+    * klass)
+{
+  GstDeinterlaceMethodClass *dm_class = (GstDeinterlaceMethodClass *) klass;
+
+  dm_class->deinterlace_frame_ayuv =
+      gst_deinterlace_simple_method_deinterlace_frame_packed;
+  dm_class->deinterlace_frame_yuy2 =
+      gst_deinterlace_simple_method_deinterlace_frame_packed;
+  dm_class->deinterlace_frame_yvyu =
+      gst_deinterlace_simple_method_deinterlace_frame_packed;
+  dm_class->deinterlace_frame_uyvy =
+      gst_deinterlace_simple_method_deinterlace_frame_packed;
+  dm_class->deinterlace_frame_argb =
+      gst_deinterlace_simple_method_deinterlace_frame_packed;
+  dm_class->deinterlace_frame_abgr =
+      gst_deinterlace_simple_method_deinterlace_frame_packed;
+  dm_class->deinterlace_frame_rgba =
+      gst_deinterlace_simple_method_deinterlace_frame_packed;
+  dm_class->deinterlace_frame_bgra =
+      gst_deinterlace_simple_method_deinterlace_frame_packed;
+  dm_class->deinterlace_frame_rgb =
+      gst_deinterlace_simple_method_deinterlace_frame_packed;
+  dm_class->deinterlace_frame_bgr =
+      gst_deinterlace_simple_method_deinterlace_frame_packed;
+  dm_class->deinterlace_frame_i420 =
+      gst_deinterlace_simple_method_deinterlace_frame_planar;
+  dm_class->deinterlace_frame_yv12 =
+      gst_deinterlace_simple_method_deinterlace_frame_planar;
+  dm_class->deinterlace_frame_y444 =
+      gst_deinterlace_simple_method_deinterlace_frame_planar;
+  dm_class->deinterlace_frame_y42b =
+      gst_deinterlace_simple_method_deinterlace_frame_planar;
+  dm_class->deinterlace_frame_y41b =
+      gst_deinterlace_simple_method_deinterlace_frame_planar;
+  dm_class->deinterlace_frame_nv12 =
+      gst_deinterlace_simple_method_deinterlace_frame_nv12;
+  dm_class->deinterlace_frame_nv21 =
+      gst_deinterlace_simple_method_deinterlace_frame_nv12;
+  dm_class->fields_required = 2;
+  dm_class->setup = gst_deinterlace_simple_method_setup;
+  dm_class->supported = gst_deinterlace_simple_method_supported;
+
+  klass->interpolate_scanline_yuy2 =
+      gst_deinterlace_simple_method_interpolate_scanline_packed;
+  klass->copy_scanline_yuy2 =
+      gst_deinterlace_simple_method_copy_scanline_packed;
+  klass->interpolate_scanline_yvyu =
+      gst_deinterlace_simple_method_interpolate_scanline_packed;
+  klass->copy_scanline_yvyu =
+      gst_deinterlace_simple_method_copy_scanline_packed;
+  klass->interpolate_scanline_ayuv =
+      gst_deinterlace_simple_method_interpolate_scanline_packed;
+  klass->copy_scanline_ayuv =
+      gst_deinterlace_simple_method_copy_scanline_packed;
+  klass->interpolate_scanline_uyvy =
+      gst_deinterlace_simple_method_interpolate_scanline_packed;
+  klass->copy_scanline_uyvy =
+      gst_deinterlace_simple_method_copy_scanline_packed;
+  klass->interpolate_scanline_nv12 =
+      gst_deinterlace_simple_method_interpolate_scanline_packed;
+  klass->copy_scanline_nv12 =
+      gst_deinterlace_simple_method_copy_scanline_packed;
+
+  klass->interpolate_scanline_argb =
+      gst_deinterlace_simple_method_interpolate_scanline_packed;
+  klass->copy_scanline_argb =
+      gst_deinterlace_simple_method_copy_scanline_packed;
+  klass->interpolate_scanline_abgr =
+      gst_deinterlace_simple_method_interpolate_scanline_packed;
+  klass->copy_scanline_abgr =
+      gst_deinterlace_simple_method_copy_scanline_packed;
+
+  klass->interpolate_scanline_rgba =
+      gst_deinterlace_simple_method_interpolate_scanline_packed;
+  klass->copy_scanline_rgba =
+      gst_deinterlace_simple_method_copy_scanline_packed;
+  klass->interpolate_scanline_bgra =
+      gst_deinterlace_simple_method_interpolate_scanline_packed;
+  klass->copy_scanline_bgra =
+      gst_deinterlace_simple_method_copy_scanline_packed;
+  klass->interpolate_scanline_rgb =
+      gst_deinterlace_simple_method_interpolate_scanline_packed;
+  klass->copy_scanline_rgb = gst_deinterlace_simple_method_copy_scanline_packed;
+  klass->interpolate_scanline_bgr =
+      gst_deinterlace_simple_method_interpolate_scanline_packed;
+  klass->copy_scanline_bgr = gst_deinterlace_simple_method_copy_scanline_packed;
+
+  klass->interpolate_scanline_planar_y =
+      gst_deinterlace_simple_method_interpolate_scanline_planar_y;
+  klass->copy_scanline_planar_y =
+      gst_deinterlace_simple_method_copy_scanline_planar_y;
+  klass->interpolate_scanline_planar_u =
+      gst_deinterlace_simple_method_interpolate_scanline_planar_u;
+  klass->copy_scanline_planar_u =
+      gst_deinterlace_simple_method_copy_scanline_planar_u;
+  klass->interpolate_scanline_planar_v =
+      gst_deinterlace_simple_method_interpolate_scanline_planar_v;
+  klass->copy_scanline_planar_v =
+      gst_deinterlace_simple_method_copy_scanline_planar_v;
+}
+
+static void
+gst_deinterlace_simple_method_init (GstDeinterlaceSimpleMethod * self)
+{
+}
diff --git a/gst/deinterlace/gstdeinterlacemethod.h b/gst/deinterlace/gstdeinterlacemethod.h
new file mode 100644
index 0000000..ee64632
--- /dev/null
+++ b/gst/deinterlace/gstdeinterlacemethod.h
@@ -0,0 +1,219 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008-2010 Sebastian Dröge <slomo@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_DEINTERLACE_METHOD_H__
+#define __GST_DEINTERLACE_METHOD_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#if defined(HAVE_GCC_ASM) && defined(HAVE_ORC)
+#if defined(HAVE_CPU_I386) || defined(HAVE_CPU_X86_64)
+#define BUILD_X86_ASM
+#endif
+#endif
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DEINTERLACE_METHOD		(gst_deinterlace_method_get_type ())
+#define GST_IS_DEINTERLACE_METHOD(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD))
+#define GST_IS_DEINTERLACE_METHOD_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD))
+#define GST_DEINTERLACE_METHOD_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD, GstDeinterlaceMethodClass))
+#define GST_DEINTERLACE_METHOD(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD, GstDeinterlaceMethod))
+#define GST_DEINTERLACE_METHOD_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD, GstDeinterlaceMethodClass))
+#define GST_DEINTERLACE_METHOD_CAST(obj)	((GstDeinterlaceMethod*)(obj))
+
+typedef struct _GstDeinterlaceMethod GstDeinterlaceMethod;
+typedef struct _GstDeinterlaceMethodClass GstDeinterlaceMethodClass;
+
+
+#define PICTURE_PROGRESSIVE 0
+#define PICTURE_INTERLACED_BOTTOM 1
+#define PICTURE_INTERLACED_TOP 2
+#define PICTURE_INTERLACED_MASK (PICTURE_INTERLACED_BOTTOM | PICTURE_INTERLACED_TOP)
+
+typedef struct
+{
+  GstVideoFrame *frame;
+  /* see PICTURE_ flags in *.c */
+  guint flags;
+} GstDeinterlaceField;
+
+/*
+ * This structure defines the deinterlacer plugin.
+ */
+
+typedef void (*GstDeinterlaceMethodDeinterlaceFunction) (
+    GstDeinterlaceMethod *self, const GstDeinterlaceField *history,
+    guint history_count, GstVideoFrame *outframe, int cur_field_idx);
+
+struct _GstDeinterlaceMethod {
+  GstObject parent;
+
+  GstVideoInfo *vinfo;
+
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame;
+};
+
+struct _GstDeinterlaceMethodClass {
+  GstObjectClass parent_class;
+  guint fields_required;
+  guint latency;
+
+  gboolean (*supported) (GstDeinterlaceMethodClass *klass, GstVideoFormat format, gint width, gint height);
+
+  void (*setup) (GstDeinterlaceMethod *self, GstVideoInfo * vinfo);
+
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_yuy2;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_yvyu;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_uyvy;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_i420;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_yv12;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_y444;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_y42b;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_y41b;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_ayuv;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_nv12;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_nv21;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_argb;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_abgr;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_rgba;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_bgra;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_rgb;
+  GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_bgr;
+
+  const gchar *name;
+  const gchar *nick;
+};
+
+GType gst_deinterlace_method_get_type (void);
+
+gboolean gst_deinterlace_method_supported (GType type, GstVideoFormat format, gint width, gint height);
+void gst_deinterlace_method_setup (GstDeinterlaceMethod * self, GstVideoInfo * vinfo);
+void gst_deinterlace_method_deinterlace_frame (GstDeinterlaceMethod * self, const GstDeinterlaceField * history, guint history_count, GstVideoFrame * outframe,
+    int cur_field_idx);
+gint gst_deinterlace_method_get_fields_required (GstDeinterlaceMethod * self);
+gint gst_deinterlace_method_get_latency (GstDeinterlaceMethod * self);
+
+#define GST_TYPE_DEINTERLACE_SIMPLE_METHOD		(gst_deinterlace_simple_method_get_type ())
+#define GST_IS_DEINTERLACE_SIMPLE_METHOD(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_SIMPLE_METHOD))
+#define GST_IS_DEINTERLACE_SIMPLE_METHOD_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_SIMPLE_METHOD))
+#define GST_DEINTERLACE_SIMPLE_METHOD_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_SIMPLE_METHOD, GstDeinterlaceSimpleMethodClass))
+#define GST_DEINTERLACE_SIMPLE_METHOD(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_SIMPLE_METHOD, GstDeinterlaceSimpleMethod))
+#define GST_DEINTERLACE_SIMPLE_METHOD_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_SIMPLE_METHOD, GstDeinterlaceSimpleMethodClass))
+#define GST_DEINTERLACE_SIMPLE_METHOD_CAST(obj)	((GstDeinterlaceSimpleMethod*)(obj))
+
+typedef struct _GstDeinterlaceSimpleMethod GstDeinterlaceSimpleMethod;
+typedef struct _GstDeinterlaceSimpleMethodClass GstDeinterlaceSimpleMethodClass;
+typedef struct _GstDeinterlaceScanlineData GstDeinterlaceScanlineData;
+
+/*
+ * This structure defines the simple deinterlacer plugin.
+ */
+
+struct _GstDeinterlaceScanlineData {
+ const guint8 *ttp, *tp, *mp, *bp, *bbp;
+ const guint8 *tt0, *t0, *m0, *b0, *bb0;
+ const guint8 *tt1, *t1, *m1, *b1, *bb1;
+ const guint8 *tt2, *t2, *m2, *b2, *bb2;
+ gboolean bottom_field;
+};
+
+/*
+ * For interpolate_scanline the input is:
+ *
+ * |   t-3       t-2       t-1       t        t+1
+ * | Field 3 | Field 2 | Field 1 | Field 0 | Field -1
+ * |  TT3    |         |   TT1   |         |   TTp
+ * |         |   T2    |         |   T0    |
+ * |   M3    |         |    M1   |         |    Mp
+ * |         |   B2    |         |   B0    |
+ * |  BB3    |         |   BB1   |         |   BBp
+ *
+ * For copy_scanline the input is:
+ *
+ * |   t-3       t-2       t-1       t         t+1
+ * | Field 3 | Field 2 | Field 1 | Field 0 | Field -1
+ * |         |   TT2   |         |  TT0    |
+ * |   T3    |         |   T1    |         |   Tp
+ * |         |    M2   |         |   M0    |
+ * |   B3    |         |   B1    |         |   Bp
+ * |         |   BB2   |         |  BB0    |
+ *
+ * All other values are NULL.
+ */
+
+typedef void (*GstDeinterlaceSimpleMethodFunction) (GstDeinterlaceSimpleMethod *self, guint8 *out, const GstDeinterlaceScanlineData *scanlines, guint size);
+
+struct _GstDeinterlaceSimpleMethod {
+  GstDeinterlaceMethod parent;
+
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_packed;
+  GstDeinterlaceSimpleMethodFunction copy_scanline_packed;
+
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_planar[3];
+  GstDeinterlaceSimpleMethodFunction copy_scanline_planar[3];
+};
+
+struct _GstDeinterlaceSimpleMethodClass {
+  GstDeinterlaceMethodClass parent_class;
+
+  /* Packed formats */
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_yuy2;
+  GstDeinterlaceSimpleMethodFunction copy_scanline_yuy2;
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_yvyu;
+  GstDeinterlaceSimpleMethodFunction copy_scanline_yvyu;
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_uyvy;
+  GstDeinterlaceSimpleMethodFunction copy_scanline_uyvy;
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_ayuv;
+  GstDeinterlaceSimpleMethodFunction copy_scanline_ayuv;
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_argb;
+  GstDeinterlaceSimpleMethodFunction copy_scanline_argb;
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_abgr;
+  GstDeinterlaceSimpleMethodFunction copy_scanline_abgr;
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_rgba;
+  GstDeinterlaceSimpleMethodFunction copy_scanline_rgba;
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_bgra;
+  GstDeinterlaceSimpleMethodFunction copy_scanline_bgra;
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_rgb;
+  GstDeinterlaceSimpleMethodFunction copy_scanline_rgb;
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_bgr;
+  GstDeinterlaceSimpleMethodFunction copy_scanline_bgr;
+
+  /* Semi-planar formats */
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_nv12;
+  GstDeinterlaceSimpleMethodFunction copy_scanline_nv12;
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_nv21;
+  GstDeinterlaceSimpleMethodFunction copy_scanline_nv21;
+
+  /* Planar formats */
+  GstDeinterlaceSimpleMethodFunction copy_scanline_planar_y;
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_planar_y;
+  GstDeinterlaceSimpleMethodFunction copy_scanline_planar_u;
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_planar_u;
+  GstDeinterlaceSimpleMethodFunction copy_scanline_planar_v;
+  GstDeinterlaceSimpleMethodFunction interpolate_scanline_planar_v;
+};
+
+GType gst_deinterlace_simple_method_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_DEINTERLACE_METHOD_H__ */
diff --git a/gst/deinterlace/meson.build b/gst/deinterlace/meson.build
new file mode 100644
index 0000000..11e6c53
--- /dev/null
+++ b/gst/deinterlace/meson.build
@@ -0,0 +1,43 @@
+interlace_sources = [
+  'gstdeinterlace.c',
+  'gstdeinterlacemethod.c',
+  'tvtime/tomsmocomp.c',
+  'tvtime/greedy.c',
+  'tvtime/greedyh.c',
+  'tvtime/vfir.c',
+  'tvtime/weavetff.c',
+  'tvtime/weavebff.c',
+  'tvtime/weave.c',
+  'tvtime/linear.c',
+  'tvtime/linearblend.c',
+  'tvtime/scalerbob.c'
+]
+
+orcsrc = 'tvtime'
+if have_orcc
+  orc_h = custom_target(orcsrc + '.h',
+    input : orcsrc + '.orc',
+    output : orcsrc + '.h',
+    command : orcc_args + ['--header', '-o', '@OUTPUT@', '@INPUT@'])
+  orc_c = custom_target(orcsrc + '.c',
+    input : orcsrc + '.orc',
+    output : orcsrc + '.c',
+    command : orcc_args + ['--implementation', '-o', '@OUTPUT@', '@INPUT@'])
+else
+  orc_h = configure_file(input : orcsrc + '-dist.h',
+    output : orcsrc + '.h',
+    configuration : configuration_data())
+  orc_c = configure_file(input : orcsrc + '-dist.c',
+    output : orcsrc + '.c',
+    configuration : configuration_data())
+endif
+
+gstdeinterlace = library('gstdeinterlace',
+  interlace_sources, orc_c, orc_h,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [orc_dep, gstbase_dep, gstvideo_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
+
diff --git a/gst/deinterlace/tvtime-dist.c b/gst/deinterlace/tvtime-dist.c
new file mode 100644
index 0000000..47c1056
--- /dev/null
+++ b/gst/deinterlace/tvtime-dist.c
@@ -0,0 +1,1119 @@
+
+/* autogenerated from tvtime.orc */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <glib.h>
+
+#ifndef _ORC_INTEGER_TYPEDEFS_
+#define _ORC_INTEGER_TYPEDEFS_
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+typedef int8_t orc_int8;
+typedef int16_t orc_int16;
+typedef int32_t orc_int32;
+typedef int64_t orc_int64;
+typedef uint8_t orc_uint8;
+typedef uint16_t orc_uint16;
+typedef uint32_t orc_uint32;
+typedef uint64_t orc_uint64;
+#define ORC_UINT64_C(x) UINT64_C(x)
+#elif defined(_MSC_VER)
+typedef signed __int8 orc_int8;
+typedef signed __int16 orc_int16;
+typedef signed __int32 orc_int32;
+typedef signed __int64 orc_int64;
+typedef unsigned __int8 orc_uint8;
+typedef unsigned __int16 orc_uint16;
+typedef unsigned __int32 orc_uint32;
+typedef unsigned __int64 orc_uint64;
+#define ORC_UINT64_C(x) (x##Ui64)
+#define inline __inline
+#else
+#include <limits.h>
+typedef signed char orc_int8;
+typedef short orc_int16;
+typedef int orc_int32;
+typedef unsigned char orc_uint8;
+typedef unsigned short orc_uint16;
+typedef unsigned int orc_uint32;
+#if INT_MAX == LONG_MAX
+typedef long long orc_int64;
+typedef unsigned long long orc_uint64;
+#define ORC_UINT64_C(x) (x##ULL)
+#else
+typedef long orc_int64;
+typedef unsigned long orc_uint64;
+#define ORC_UINT64_C(x) (x##UL)
+#endif
+#endif
+typedef union
+{
+  orc_int16 i;
+  orc_int8 x2[2];
+} orc_union16;
+typedef union
+{
+  orc_int32 i;
+  float f;
+  orc_int16 x2[2];
+  orc_int8 x4[4];
+} orc_union32;
+typedef union
+{
+  orc_int64 i;
+  double f;
+  orc_int32 x2[2];
+  float x2f[2];
+  orc_int16 x4[4];
+} orc_union64;
+#endif
+#ifndef ORC_RESTRICT
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define ORC_RESTRICT restrict
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define ORC_RESTRICT __restrict__
+#else
+#define ORC_RESTRICT
+#endif
+#endif
+
+#ifndef ORC_INTERNAL
+#if defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#define ORC_INTERNAL __hidden
+#elif defined (__GNUC__)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#else
+#define ORC_INTERNAL
+#endif
+#endif
+
+
+#ifndef DISABLE_ORC
+#include <orc/orc.h>
+#endif
+void deinterlace_line_vfir (guint8 * ORC_RESTRICT d1,
+    const guint8 * ORC_RESTRICT s1, const guint8 * ORC_RESTRICT s2,
+    const guint8 * ORC_RESTRICT s3, const guint8 * ORC_RESTRICT s4,
+    const guint8 * ORC_RESTRICT s5, int n);
+void deinterlace_line_linear (guint8 * ORC_RESTRICT d1,
+    const guint8 * ORC_RESTRICT s1, const guint8 * ORC_RESTRICT s2, int n);
+void deinterlace_line_linear_blend (guint8 * ORC_RESTRICT d1,
+    const guint8 * ORC_RESTRICT s1, const guint8 * ORC_RESTRICT s2,
+    const guint8 * ORC_RESTRICT s3, int n);
+void deinterlace_line_greedy (orc_uint8 * ORC_RESTRICT d1,
+    const orc_uint8 * ORC_RESTRICT s1, const orc_uint8 * ORC_RESTRICT s2,
+    const orc_uint8 * ORC_RESTRICT s3, const orc_uint8 * ORC_RESTRICT s4,
+    int p1, int n);
+
+
+/* begin Orc C target preamble */
+#define ORC_CLAMP(x,a,b) ((x)<(a) ? (a) : ((x)>(b) ? (b) : (x)))
+#define ORC_ABS(a) ((a)<0 ? -(a) : (a))
+#define ORC_MIN(a,b) ((a)<(b) ? (a) : (b))
+#define ORC_MAX(a,b) ((a)>(b) ? (a) : (b))
+#define ORC_SB_MAX 127
+#define ORC_SB_MIN (-1-ORC_SB_MAX)
+#define ORC_UB_MAX (orc_uint8) 255
+#define ORC_UB_MIN 0
+#define ORC_SW_MAX 32767
+#define ORC_SW_MIN (-1-ORC_SW_MAX)
+#define ORC_UW_MAX (orc_uint16)65535
+#define ORC_UW_MIN 0
+#define ORC_SL_MAX 2147483647
+#define ORC_SL_MIN (-1-ORC_SL_MAX)
+#define ORC_UL_MAX 4294967295U
+#define ORC_UL_MIN 0
+#define ORC_CLAMP_SB(x) ORC_CLAMP(x,ORC_SB_MIN,ORC_SB_MAX)
+#define ORC_CLAMP_UB(x) ORC_CLAMP(x,ORC_UB_MIN,ORC_UB_MAX)
+#define ORC_CLAMP_SW(x) ORC_CLAMP(x,ORC_SW_MIN,ORC_SW_MAX)
+#define ORC_CLAMP_UW(x) ORC_CLAMP(x,ORC_UW_MIN,ORC_UW_MAX)
+#define ORC_CLAMP_SL(x) ORC_CLAMP(x,ORC_SL_MIN,ORC_SL_MAX)
+#define ORC_CLAMP_UL(x) ORC_CLAMP(x,ORC_UL_MIN,ORC_UL_MAX)
+#define ORC_SWAP_W(x) ((((x)&0xffU)<<8) | (((x)&0xff00U)>>8))
+#define ORC_SWAP_L(x) ((((x)&0xffU)<<24) | (((x)&0xff00U)<<8) | (((x)&0xff0000U)>>8) | (((x)&0xff000000U)>>24))
+#define ORC_SWAP_Q(x) ((((x)&ORC_UINT64_C(0xff))<<56) | (((x)&ORC_UINT64_C(0xff00))<<40) | (((x)&ORC_UINT64_C(0xff0000))<<24) | (((x)&ORC_UINT64_C(0xff000000))<<8) | (((x)&ORC_UINT64_C(0xff00000000))>>8) | (((x)&ORC_UINT64_C(0xff0000000000))>>24) | (((x)&ORC_UINT64_C(0xff000000000000))>>40) | (((x)&ORC_UINT64_C(0xff00000000000000))>>56))
+#define ORC_PTR_OFFSET(ptr,offset) ((void *)(((unsigned char *)(ptr)) + (offset)))
+#define ORC_DENORMAL(x) ((x) & ((((x)&0x7f800000) == 0) ? 0xff800000 : 0xffffffff))
+#define ORC_ISNAN(x) ((((x)&0x7f800000) == 0x7f800000) && (((x)&0x007fffff) != 0))
+#define ORC_DENORMAL_DOUBLE(x) ((x) & ((((x)&ORC_UINT64_C(0x7ff0000000000000)) == 0) ? ORC_UINT64_C(0xfff0000000000000) : ORC_UINT64_C(0xffffffffffffffff)))
+#define ORC_ISNAN_DOUBLE(x) ((((x)&ORC_UINT64_C(0x7ff0000000000000)) == ORC_UINT64_C(0x7ff0000000000000)) && (((x)&ORC_UINT64_C(0x000fffffffffffff)) != 0))
+#ifndef ORC_RESTRICT
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define ORC_RESTRICT restrict
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define ORC_RESTRICT __restrict__
+#else
+#define ORC_RESTRICT
+#endif
+#endif
+/* end Orc C target preamble */
+
+
+
+/* deinterlace_line_vfir */
+#ifdef DISABLE_ORC
+void
+deinterlace_line_vfir (guint8 * ORC_RESTRICT d1, const guint8 * ORC_RESTRICT s1,
+    const guint8 * ORC_RESTRICT s2, const guint8 * ORC_RESTRICT s3,
+    const guint8 * ORC_RESTRICT s4, const guint8 * ORC_RESTRICT s5, int n)
+{
+  int i;
+  orc_int8 *ORC_RESTRICT ptr0;
+  const orc_int8 *ORC_RESTRICT ptr4;
+  const orc_int8 *ORC_RESTRICT ptr5;
+  const orc_int8 *ORC_RESTRICT ptr6;
+  const orc_int8 *ORC_RESTRICT ptr7;
+  const orc_int8 *ORC_RESTRICT ptr8;
+  orc_int8 var35;
+  orc_int8 var36;
+  orc_int8 var37;
+  orc_int8 var38;
+  orc_int8 var39;
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union16 var40;
+#else
+  orc_union16 var40;
+#endif
+  orc_int8 var41;
+  orc_union16 var42;
+  orc_union16 var43;
+  orc_union16 var44;
+  orc_union16 var45;
+  orc_union16 var46;
+  orc_union16 var47;
+  orc_union16 var48;
+  orc_union16 var49;
+  orc_union16 var50;
+  orc_union16 var51;
+  orc_union16 var52;
+  orc_union16 var53;
+  orc_union16 var54;
+
+  ptr0 = (orc_int8 *) d1;
+  ptr4 = (orc_int8 *) s1;
+  ptr5 = (orc_int8 *) s2;
+  ptr6 = (orc_int8 *) s3;
+  ptr7 = (orc_int8 *) s4;
+  ptr8 = (orc_int8 *) s5;
+
+  /* 16: loadpw */
+  var40.i = 0x00000004;         /* 4 or 1.97626e-323f */
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadb */
+    var35 = ptr4[i];
+    /* 1: convubw */
+    var42.i = (orc_uint8) var35;
+    /* 2: loadb */
+    var36 = ptr8[i];
+    /* 3: convubw */
+    var43.i = (orc_uint8) var36;
+    /* 4: addw */
+    var44.i = var42.i + var43.i;
+    /* 5: loadb */
+    var37 = ptr5[i];
+    /* 6: convubw */
+    var45.i = (orc_uint8) var37;
+    /* 7: loadb */
+    var38 = ptr7[i];
+    /* 8: convubw */
+    var46.i = (orc_uint8) var38;
+    /* 9: addw */
+    var47.i = var45.i + var46.i;
+    /* 10: shlw */
+    var48.i = ((orc_uint16) var47.i) << 2;
+    /* 11: loadb */
+    var39 = ptr6[i];
+    /* 12: convubw */
+    var49.i = (orc_uint8) var39;
+    /* 13: shlw */
+    var50.i = ((orc_uint16) var49.i) << 1;
+    /* 14: subw */
+    var51.i = var48.i - var44.i;
+    /* 15: addw */
+    var52.i = var51.i + var50.i;
+    /* 17: addw */
+    var53.i = var52.i + var40.i;
+    /* 18: shrsw */
+    var54.i = var53.i >> 3;
+    /* 19: convsuswb */
+    var41 = ORC_CLAMP_UB (var54.i);
+    /* 20: storeb */
+    ptr0[i] = var41;
+  }
+
+}
+
+#else
+static void
+_backup_deinterlace_line_vfir (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_int8 *ORC_RESTRICT ptr0;
+  const orc_int8 *ORC_RESTRICT ptr4;
+  const orc_int8 *ORC_RESTRICT ptr5;
+  const orc_int8 *ORC_RESTRICT ptr6;
+  const orc_int8 *ORC_RESTRICT ptr7;
+  const orc_int8 *ORC_RESTRICT ptr8;
+  orc_int8 var35;
+  orc_int8 var36;
+  orc_int8 var37;
+  orc_int8 var38;
+  orc_int8 var39;
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union16 var40;
+#else
+  orc_union16 var40;
+#endif
+  orc_int8 var41;
+  orc_union16 var42;
+  orc_union16 var43;
+  orc_union16 var44;
+  orc_union16 var45;
+  orc_union16 var46;
+  orc_union16 var47;
+  orc_union16 var48;
+  orc_union16 var49;
+  orc_union16 var50;
+  orc_union16 var51;
+  orc_union16 var52;
+  orc_union16 var53;
+  orc_union16 var54;
+
+  ptr0 = (orc_int8 *) ex->arrays[0];
+  ptr4 = (orc_int8 *) ex->arrays[4];
+  ptr5 = (orc_int8 *) ex->arrays[5];
+  ptr6 = (orc_int8 *) ex->arrays[6];
+  ptr7 = (orc_int8 *) ex->arrays[7];
+  ptr8 = (orc_int8 *) ex->arrays[8];
+
+  /* 16: loadpw */
+  var40.i = 0x00000004;         /* 4 or 1.97626e-323f */
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadb */
+    var35 = ptr4[i];
+    /* 1: convubw */
+    var42.i = (orc_uint8) var35;
+    /* 2: loadb */
+    var36 = ptr8[i];
+    /* 3: convubw */
+    var43.i = (orc_uint8) var36;
+    /* 4: addw */
+    var44.i = var42.i + var43.i;
+    /* 5: loadb */
+    var37 = ptr5[i];
+    /* 6: convubw */
+    var45.i = (orc_uint8) var37;
+    /* 7: loadb */
+    var38 = ptr7[i];
+    /* 8: convubw */
+    var46.i = (orc_uint8) var38;
+    /* 9: addw */
+    var47.i = var45.i + var46.i;
+    /* 10: shlw */
+    var48.i = ((orc_uint16) var47.i) << 2;
+    /* 11: loadb */
+    var39 = ptr6[i];
+    /* 12: convubw */
+    var49.i = (orc_uint8) var39;
+    /* 13: shlw */
+    var50.i = ((orc_uint16) var49.i) << 1;
+    /* 14: subw */
+    var51.i = var48.i - var44.i;
+    /* 15: addw */
+    var52.i = var51.i + var50.i;
+    /* 17: addw */
+    var53.i = var52.i + var40.i;
+    /* 18: shrsw */
+    var54.i = var53.i >> 3;
+    /* 19: convsuswb */
+    var41 = ORC_CLAMP_UB (var54.i);
+    /* 20: storeb */
+    ptr0[i] = var41;
+  }
+
+}
+
+void
+deinterlace_line_vfir (guint8 * ORC_RESTRICT d1, const guint8 * ORC_RESTRICT s1,
+    const guint8 * ORC_RESTRICT s2, const guint8 * ORC_RESTRICT s3,
+    const guint8 * ORC_RESTRICT s4, const guint8 * ORC_RESTRICT s5, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 21, 100, 101, 105, 110, 116, 101, 114, 108, 97, 99, 101, 95, 108,
+        105, 110, 101, 95, 118, 102, 105, 114, 11, 1, 1, 12, 1, 1, 12, 1,
+        1, 12, 1, 1, 12, 1, 1, 12, 1, 1, 14, 2, 2, 0, 0, 0,
+        14, 2, 1, 0, 0, 0, 14, 2, 4, 0, 0, 0, 14, 2, 3, 0,
+        0, 0, 20, 2, 20, 2, 20, 2, 150, 32, 4, 150, 33, 8, 70, 32,
+        32, 33, 150, 33, 5, 150, 34, 7, 70, 33, 33, 34, 93, 33, 33, 16,
+        150, 34, 6, 93, 34, 34, 17, 98, 33, 33, 32, 70, 33, 33, 34, 70,
+        33, 33, 18, 94, 33, 33, 19, 160, 0, 33, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p, _backup_deinterlace_line_vfir);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "deinterlace_line_vfir");
+      orc_program_set_backup_function (p, _backup_deinterlace_line_vfir);
+      orc_program_add_destination (p, 1, "d1");
+      orc_program_add_source (p, 1, "s1");
+      orc_program_add_source (p, 1, "s2");
+      orc_program_add_source (p, 1, "s3");
+      orc_program_add_source (p, 1, "s4");
+      orc_program_add_source (p, 1, "s5");
+      orc_program_add_constant (p, 2, 0x00000002, "c1");
+      orc_program_add_constant (p, 2, 0x00000001, "c2");
+      orc_program_add_constant (p, 2, 0x00000004, "c3");
+      orc_program_add_constant (p, 2, 0x00000003, "c4");
+      orc_program_add_temporary (p, 2, "t1");
+      orc_program_add_temporary (p, 2, "t2");
+      orc_program_add_temporary (p, 2, "t3");
+
+      orc_program_append_2 (p, "convubw", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 0, ORC_VAR_T2, ORC_VAR_S5, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_T2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 0, ORC_VAR_T2, ORC_VAR_S2, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 0, ORC_VAR_T3, ORC_VAR_S4, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addw", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_T3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "shlw", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_C1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 0, ORC_VAR_T3, ORC_VAR_S3, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "shlw", 0, ORC_VAR_T3, ORC_VAR_T3, ORC_VAR_C2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "subw", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_T1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addw", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_T3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addw", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_C3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "shrsw", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_C4,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convsuswb", 0, ORC_VAR_D1, ORC_VAR_T2,
+          ORC_VAR_D1, ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  ex->arrays[ORC_VAR_S2] = (void *) s2;
+  ex->arrays[ORC_VAR_S3] = (void *) s3;
+  ex->arrays[ORC_VAR_S4] = (void *) s4;
+  ex->arrays[ORC_VAR_S5] = (void *) s5;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* deinterlace_line_linear */
+#ifdef DISABLE_ORC
+void
+deinterlace_line_linear (guint8 * ORC_RESTRICT d1,
+    const guint8 * ORC_RESTRICT s1, const guint8 * ORC_RESTRICT s2, int n)
+{
+  int i;
+  orc_int8 *ORC_RESTRICT ptr0;
+  const orc_int8 *ORC_RESTRICT ptr4;
+  const orc_int8 *ORC_RESTRICT ptr5;
+  orc_int8 var32;
+  orc_int8 var33;
+  orc_int8 var34;
+
+  ptr0 = (orc_int8 *) d1;
+  ptr4 = (orc_int8 *) s1;
+  ptr5 = (orc_int8 *) s2;
+
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadb */
+    var32 = ptr4[i];
+    /* 1: loadb */
+    var33 = ptr5[i];
+    /* 2: avgub */
+    var34 = ((orc_uint8) var32 + (orc_uint8) var33 + 1) >> 1;
+    /* 3: storeb */
+    ptr0[i] = var34;
+  }
+
+}
+
+#else
+static void
+_backup_deinterlace_line_linear (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_int8 *ORC_RESTRICT ptr0;
+  const orc_int8 *ORC_RESTRICT ptr4;
+  const orc_int8 *ORC_RESTRICT ptr5;
+  orc_int8 var32;
+  orc_int8 var33;
+  orc_int8 var34;
+
+  ptr0 = (orc_int8 *) ex->arrays[0];
+  ptr4 = (orc_int8 *) ex->arrays[4];
+  ptr5 = (orc_int8 *) ex->arrays[5];
+
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadb */
+    var32 = ptr4[i];
+    /* 1: loadb */
+    var33 = ptr5[i];
+    /* 2: avgub */
+    var34 = ((orc_uint8) var32 + (orc_uint8) var33 + 1) >> 1;
+    /* 3: storeb */
+    ptr0[i] = var34;
+  }
+
+}
+
+void
+deinterlace_line_linear (guint8 * ORC_RESTRICT d1,
+    const guint8 * ORC_RESTRICT s1, const guint8 * ORC_RESTRICT s2, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 23, 100, 101, 105, 110, 116, 101, 114, 108, 97, 99, 101, 95, 108,
+        105, 110, 101, 95, 108, 105, 110, 101, 97, 114, 11, 1, 1, 12, 1, 1,
+        12, 1, 1, 39, 0, 4, 5, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p, _backup_deinterlace_line_linear);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "deinterlace_line_linear");
+      orc_program_set_backup_function (p, _backup_deinterlace_line_linear);
+      orc_program_add_destination (p, 1, "d1");
+      orc_program_add_source (p, 1, "s1");
+      orc_program_add_source (p, 1, "s2");
+
+      orc_program_append_2 (p, "avgub", 0, ORC_VAR_D1, ORC_VAR_S1, ORC_VAR_S2,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  ex->arrays[ORC_VAR_S2] = (void *) s2;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* deinterlace_line_linear_blend */
+#ifdef DISABLE_ORC
+void
+deinterlace_line_linear_blend (guint8 * ORC_RESTRICT d1,
+    const guint8 * ORC_RESTRICT s1, const guint8 * ORC_RESTRICT s2,
+    const guint8 * ORC_RESTRICT s3, int n)
+{
+  int i;
+  orc_int8 *ORC_RESTRICT ptr0;
+  const orc_int8 *ORC_RESTRICT ptr4;
+  const orc_int8 *ORC_RESTRICT ptr5;
+  const orc_int8 *ORC_RESTRICT ptr6;
+  orc_int8 var35;
+  orc_int8 var36;
+  orc_int8 var37;
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union16 var38;
+#else
+  orc_union16 var38;
+#endif
+  orc_int8 var39;
+  orc_union16 var40;
+  orc_union16 var41;
+  orc_union16 var42;
+  orc_union16 var43;
+  orc_union16 var44;
+  orc_union16 var45;
+  orc_union16 var46;
+  orc_union16 var47;
+
+  ptr0 = (orc_int8 *) d1;
+  ptr4 = (orc_int8 *) s1;
+  ptr5 = (orc_int8 *) s2;
+  ptr6 = (orc_int8 *) s3;
+
+  /* 9: loadpw */
+  var38.i = 0x00000002;         /* 2 or 9.88131e-324f */
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadb */
+    var35 = ptr4[i];
+    /* 1: convubw */
+    var40.i = (orc_uint8) var35;
+    /* 2: loadb */
+    var36 = ptr5[i];
+    /* 3: convubw */
+    var41.i = (orc_uint8) var36;
+    /* 4: loadb */
+    var37 = ptr6[i];
+    /* 5: convubw */
+    var42.i = (orc_uint8) var37;
+    /* 6: addw */
+    var43.i = var40.i + var41.i;
+    /* 7: addw */
+    var44.i = var42.i + var42.i;
+    /* 8: addw */
+    var45.i = var43.i + var44.i;
+    /* 10: addw */
+    var46.i = var45.i + var38.i;
+    /* 11: shrsw */
+    var47.i = var46.i >> 2;
+    /* 12: convsuswb */
+    var39 = ORC_CLAMP_UB (var47.i);
+    /* 13: storeb */
+    ptr0[i] = var39;
+  }
+
+}
+
+#else
+static void
+_backup_deinterlace_line_linear_blend (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_int8 *ORC_RESTRICT ptr0;
+  const orc_int8 *ORC_RESTRICT ptr4;
+  const orc_int8 *ORC_RESTRICT ptr5;
+  const orc_int8 *ORC_RESTRICT ptr6;
+  orc_int8 var35;
+  orc_int8 var36;
+  orc_int8 var37;
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union16 var38;
+#else
+  orc_union16 var38;
+#endif
+  orc_int8 var39;
+  orc_union16 var40;
+  orc_union16 var41;
+  orc_union16 var42;
+  orc_union16 var43;
+  orc_union16 var44;
+  orc_union16 var45;
+  orc_union16 var46;
+  orc_union16 var47;
+
+  ptr0 = (orc_int8 *) ex->arrays[0];
+  ptr4 = (orc_int8 *) ex->arrays[4];
+  ptr5 = (orc_int8 *) ex->arrays[5];
+  ptr6 = (orc_int8 *) ex->arrays[6];
+
+  /* 9: loadpw */
+  var38.i = 0x00000002;         /* 2 or 9.88131e-324f */
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadb */
+    var35 = ptr4[i];
+    /* 1: convubw */
+    var40.i = (orc_uint8) var35;
+    /* 2: loadb */
+    var36 = ptr5[i];
+    /* 3: convubw */
+    var41.i = (orc_uint8) var36;
+    /* 4: loadb */
+    var37 = ptr6[i];
+    /* 5: convubw */
+    var42.i = (orc_uint8) var37;
+    /* 6: addw */
+    var43.i = var40.i + var41.i;
+    /* 7: addw */
+    var44.i = var42.i + var42.i;
+    /* 8: addw */
+    var45.i = var43.i + var44.i;
+    /* 10: addw */
+    var46.i = var45.i + var38.i;
+    /* 11: shrsw */
+    var47.i = var46.i >> 2;
+    /* 12: convsuswb */
+    var39 = ORC_CLAMP_UB (var47.i);
+    /* 13: storeb */
+    ptr0[i] = var39;
+  }
+
+}
+
+void
+deinterlace_line_linear_blend (guint8 * ORC_RESTRICT d1,
+    const guint8 * ORC_RESTRICT s1, const guint8 * ORC_RESTRICT s2,
+    const guint8 * ORC_RESTRICT s3, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 29, 100, 101, 105, 110, 116, 101, 114, 108, 97, 99, 101, 95, 108,
+        105, 110, 101, 95, 108, 105, 110, 101, 97, 114, 95, 98, 108, 101, 110,
+        100,
+        11, 1, 1, 12, 1, 1, 12, 1, 1, 12, 1, 1, 14, 2, 2, 0,
+        0, 0, 20, 2, 20, 2, 20, 2, 150, 32, 4, 150, 33, 5, 150, 34,
+        6, 70, 32, 32, 33, 70, 34, 34, 34, 70, 32, 32, 34, 70, 32, 32,
+        16, 94, 32, 32, 16, 160, 0, 32, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p,
+          _backup_deinterlace_line_linear_blend);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "deinterlace_line_linear_blend");
+      orc_program_set_backup_function (p,
+          _backup_deinterlace_line_linear_blend);
+      orc_program_add_destination (p, 1, "d1");
+      orc_program_add_source (p, 1, "s1");
+      orc_program_add_source (p, 1, "s2");
+      orc_program_add_source (p, 1, "s3");
+      orc_program_add_constant (p, 2, 0x00000002, "c1");
+      orc_program_add_temporary (p, 2, "t1");
+      orc_program_add_temporary (p, 2, "t2");
+      orc_program_add_temporary (p, 2, "t3");
+
+      orc_program_append_2 (p, "convubw", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 0, ORC_VAR_T2, ORC_VAR_S2, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 0, ORC_VAR_T3, ORC_VAR_S3, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_T2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addw", 0, ORC_VAR_T3, ORC_VAR_T3, ORC_VAR_T3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_T3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_C1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "shrsw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_C1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convsuswb", 0, ORC_VAR_D1, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  ex->arrays[ORC_VAR_S2] = (void *) s2;
+  ex->arrays[ORC_VAR_S3] = (void *) s3;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* deinterlace_line_greedy */
+#ifdef DISABLE_ORC
+void
+deinterlace_line_greedy (orc_uint8 * ORC_RESTRICT d1,
+    const orc_uint8 * ORC_RESTRICT s1, const orc_uint8 * ORC_RESTRICT s2,
+    const orc_uint8 * ORC_RESTRICT s3, const orc_uint8 * ORC_RESTRICT s4,
+    int p1, int n)
+{
+  int i;
+  orc_int8 *ORC_RESTRICT ptr0;
+  const orc_int8 *ORC_RESTRICT ptr4;
+  const orc_int8 *ORC_RESTRICT ptr5;
+  const orc_int8 *ORC_RESTRICT ptr6;
+  const orc_int8 *ORC_RESTRICT ptr7;
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_int8 var44;
+#else
+  orc_int8 var44;
+#endif
+  orc_int8 var45;
+  orc_int8 var46;
+  orc_int8 var47;
+  orc_int8 var48;
+  orc_int8 var49;
+  orc_int8 var50;
+  orc_int8 var51;
+  orc_int8 var52;
+  orc_int8 var53;
+  orc_int8 var54;
+  orc_int8 var55;
+  orc_int8 var56;
+  orc_int8 var57;
+  orc_int8 var58;
+  orc_int8 var59;
+  orc_int8 var60;
+  orc_int8 var61;
+  orc_int8 var62;
+  orc_int8 var63;
+  orc_int8 var64;
+  orc_int8 var65;
+  orc_int8 var66;
+  orc_int8 var67;
+  orc_int8 var68;
+
+  ptr0 = (orc_int8 *) d1;
+  ptr4 = (orc_int8 *) s1;
+  ptr5 = (orc_int8 *) s2;
+  ptr6 = (orc_int8 *) s3;
+  ptr7 = (orc_int8 *) s4;
+
+  /* 11: loadpb */
+  var44 = 0x00000080;           /* 128 or 6.32404e-322f */
+  /* 20: loadpb */
+  var45 = p1;
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadb */
+    var47 = ptr4[i];
+    /* 1: loadb */
+    var48 = ptr7[i];
+    /* 2: loadb */
+    var49 = ptr6[i];
+    /* 3: loadb */
+    var50 = ptr5[i];
+    /* 4: avgub */
+    var51 = ((orc_uint8) var50 + (orc_uint8) var49 + 1) >> 1;
+    /* 5: maxub */
+    var52 = ORC_MAX ((orc_uint8) var47, (orc_uint8) var51);
+    /* 6: minub */
+    var53 = ORC_MIN ((orc_uint8) var47, (orc_uint8) var51);
+    /* 7: subb */
+    var54 = var52 - var53;
+    /* 8: maxub */
+    var55 = ORC_MAX ((orc_uint8) var48, (orc_uint8) var51);
+    /* 9: minub */
+    var56 = ORC_MIN ((orc_uint8) var48, (orc_uint8) var51);
+    /* 10: subb */
+    var57 = var55 - var56;
+    /* 12: xorb */
+    var58 = var54 ^ var44;
+    /* 13: xorb */
+    var59 = var57 ^ var44;
+    /* 14: cmpgtsb */
+    var60 = (var58 > var59) ? (~0) : 0;
+    /* 15: andb */
+    var61 = var48 & var60;
+    /* 16: andnb */
+    var62 = (~var60) & var47;
+    /* 17: orb */
+    var63 = var61 | var62;
+    /* 18: maxub */
+    var64 = ORC_MAX ((orc_uint8) var50, (orc_uint8) var49);
+    /* 19: minub */
+    var65 = ORC_MIN ((orc_uint8) var50, (orc_uint8) var49);
+    /* 21: addusb */
+    var66 = ORC_CLAMP_UB ((orc_uint8) var64 + (orc_uint8) var45);
+    /* 22: subusb */
+    var67 = ORC_CLAMP_UB ((orc_uint8) var65 - (orc_uint8) var45);
+    /* 23: minub */
+    var68 = ORC_MIN ((orc_uint8) var63, (orc_uint8) var66);
+    /* 24: maxub */
+    var46 = ORC_MAX ((orc_uint8) var68, (orc_uint8) var67);
+    /* 25: storeb */
+    ptr0[i] = var46;
+  }
+
+}
+
+#else
+static void
+_backup_deinterlace_line_greedy (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_int8 *ORC_RESTRICT ptr0;
+  const orc_int8 *ORC_RESTRICT ptr4;
+  const orc_int8 *ORC_RESTRICT ptr5;
+  const orc_int8 *ORC_RESTRICT ptr6;
+  const orc_int8 *ORC_RESTRICT ptr7;
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_int8 var44;
+#else
+  orc_int8 var44;
+#endif
+  orc_int8 var45;
+  orc_int8 var46;
+  orc_int8 var47;
+  orc_int8 var48;
+  orc_int8 var49;
+  orc_int8 var50;
+  orc_int8 var51;
+  orc_int8 var52;
+  orc_int8 var53;
+  orc_int8 var54;
+  orc_int8 var55;
+  orc_int8 var56;
+  orc_int8 var57;
+  orc_int8 var58;
+  orc_int8 var59;
+  orc_int8 var60;
+  orc_int8 var61;
+  orc_int8 var62;
+  orc_int8 var63;
+  orc_int8 var64;
+  orc_int8 var65;
+  orc_int8 var66;
+  orc_int8 var67;
+  orc_int8 var68;
+
+  ptr0 = (orc_int8 *) ex->arrays[0];
+  ptr4 = (orc_int8 *) ex->arrays[4];
+  ptr5 = (orc_int8 *) ex->arrays[5];
+  ptr6 = (orc_int8 *) ex->arrays[6];
+  ptr7 = (orc_int8 *) ex->arrays[7];
+
+  /* 11: loadpb */
+  var44 = 0x00000080;           /* 128 or 6.32404e-322f */
+  /* 20: loadpb */
+  var45 = ex->params[24];
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadb */
+    var47 = ptr4[i];
+    /* 1: loadb */
+    var48 = ptr7[i];
+    /* 2: loadb */
+    var49 = ptr6[i];
+    /* 3: loadb */
+    var50 = ptr5[i];
+    /* 4: avgub */
+    var51 = ((orc_uint8) var50 + (orc_uint8) var49 + 1) >> 1;
+    /* 5: maxub */
+    var52 = ORC_MAX ((orc_uint8) var47, (orc_uint8) var51);
+    /* 6: minub */
+    var53 = ORC_MIN ((orc_uint8) var47, (orc_uint8) var51);
+    /* 7: subb */
+    var54 = var52 - var53;
+    /* 8: maxub */
+    var55 = ORC_MAX ((orc_uint8) var48, (orc_uint8) var51);
+    /* 9: minub */
+    var56 = ORC_MIN ((orc_uint8) var48, (orc_uint8) var51);
+    /* 10: subb */
+    var57 = var55 - var56;
+    /* 12: xorb */
+    var58 = var54 ^ var44;
+    /* 13: xorb */
+    var59 = var57 ^ var44;
+    /* 14: cmpgtsb */
+    var60 = (var58 > var59) ? (~0) : 0;
+    /* 15: andb */
+    var61 = var48 & var60;
+    /* 16: andnb */
+    var62 = (~var60) & var47;
+    /* 17: orb */
+    var63 = var61 | var62;
+    /* 18: maxub */
+    var64 = ORC_MAX ((orc_uint8) var50, (orc_uint8) var49);
+    /* 19: minub */
+    var65 = ORC_MIN ((orc_uint8) var50, (orc_uint8) var49);
+    /* 21: addusb */
+    var66 = ORC_CLAMP_UB ((orc_uint8) var64 + (orc_uint8) var45);
+    /* 22: subusb */
+    var67 = ORC_CLAMP_UB ((orc_uint8) var65 - (orc_uint8) var45);
+    /* 23: minub */
+    var68 = ORC_MIN ((orc_uint8) var63, (orc_uint8) var66);
+    /* 24: maxub */
+    var46 = ORC_MAX ((orc_uint8) var68, (orc_uint8) var67);
+    /* 25: storeb */
+    ptr0[i] = var46;
+  }
+
+}
+
+void
+deinterlace_line_greedy (orc_uint8 * ORC_RESTRICT d1,
+    const orc_uint8 * ORC_RESTRICT s1, const orc_uint8 * ORC_RESTRICT s2,
+    const orc_uint8 * ORC_RESTRICT s3, const orc_uint8 * ORC_RESTRICT s4,
+    int p1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 23, 100, 101, 105, 110, 116, 101, 114, 108, 97, 99, 101, 95, 108,
+        105, 110, 101, 95, 103, 114, 101, 101, 100, 121, 11, 1, 1, 12, 1, 1,
+        12, 1, 1, 12, 1, 1, 12, 1, 1, 14, 1, 128, 0, 0, 0, 16,
+        1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20,
+        1, 20, 1, 20, 1, 20, 1, 20, 1, 43, 32, 4, 43, 33, 7, 43,
+        34, 6, 43, 35, 5, 39, 36, 35, 34, 53, 39, 32, 36, 55, 40, 32,
+        36, 65, 37, 39, 40, 53, 39, 33, 36, 55, 40, 33, 36, 65, 38, 39,
+        40, 68, 37, 37, 16, 68, 38, 38, 16, 41, 40, 37, 38, 36, 39, 33,
+        40, 37, 40, 40, 32, 59, 41, 39, 40, 53, 43, 35, 34, 55, 42, 35,
+        34, 35, 43, 43, 24, 67, 42, 42, 24, 55, 41, 41, 43, 53, 0, 41,
+        42, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p, _backup_deinterlace_line_greedy);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "deinterlace_line_greedy");
+      orc_program_set_backup_function (p, _backup_deinterlace_line_greedy);
+      orc_program_add_destination (p, 1, "d1");
+      orc_program_add_source (p, 1, "s1");
+      orc_program_add_source (p, 1, "s2");
+      orc_program_add_source (p, 1, "s3");
+      orc_program_add_source (p, 1, "s4");
+      orc_program_add_constant (p, 1, 0x00000080, "c1");
+      orc_program_add_parameter (p, 1, "p1");
+      orc_program_add_temporary (p, 1, "t1");
+      orc_program_add_temporary (p, 1, "t2");
+      orc_program_add_temporary (p, 1, "t3");
+      orc_program_add_temporary (p, 1, "t4");
+      orc_program_add_temporary (p, 1, "t5");
+      orc_program_add_temporary (p, 1, "t6");
+      orc_program_add_temporary (p, 1, "t7");
+      orc_program_add_temporary (p, 1, "t8");
+      orc_program_add_temporary (p, 1, "t9");
+      orc_program_add_temporary (p, 1, "t10");
+      orc_program_add_temporary (p, 1, "t11");
+      orc_program_add_temporary (p, 1, "t12");
+
+      orc_program_append_2 (p, "loadb", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "loadb", 0, ORC_VAR_T2, ORC_VAR_S4, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "loadb", 0, ORC_VAR_T3, ORC_VAR_S3, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "loadb", 0, ORC_VAR_T4, ORC_VAR_S2, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "avgub", 0, ORC_VAR_T5, ORC_VAR_T4, ORC_VAR_T3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "maxub", 0, ORC_VAR_T8, ORC_VAR_T1, ORC_VAR_T5,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "minub", 0, ORC_VAR_T9, ORC_VAR_T1, ORC_VAR_T5,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "subb", 0, ORC_VAR_T6, ORC_VAR_T8, ORC_VAR_T9,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "maxub", 0, ORC_VAR_T8, ORC_VAR_T2, ORC_VAR_T5,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "minub", 0, ORC_VAR_T9, ORC_VAR_T2, ORC_VAR_T5,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "subb", 0, ORC_VAR_T7, ORC_VAR_T8, ORC_VAR_T9,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "xorb", 0, ORC_VAR_T6, ORC_VAR_T6, ORC_VAR_C1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "xorb", 0, ORC_VAR_T7, ORC_VAR_T7, ORC_VAR_C1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "cmpgtsb", 0, ORC_VAR_T9, ORC_VAR_T6, ORC_VAR_T7,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "andb", 0, ORC_VAR_T8, ORC_VAR_T2, ORC_VAR_T9,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "andnb", 0, ORC_VAR_T9, ORC_VAR_T9, ORC_VAR_T1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "orb", 0, ORC_VAR_T10, ORC_VAR_T8, ORC_VAR_T9,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "maxub", 0, ORC_VAR_T12, ORC_VAR_T4, ORC_VAR_T3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "minub", 0, ORC_VAR_T11, ORC_VAR_T4, ORC_VAR_T3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addusb", 0, ORC_VAR_T12, ORC_VAR_T12,
+          ORC_VAR_P1, ORC_VAR_D1);
+      orc_program_append_2 (p, "subusb", 0, ORC_VAR_T11, ORC_VAR_T11,
+          ORC_VAR_P1, ORC_VAR_D1);
+      orc_program_append_2 (p, "minub", 0, ORC_VAR_T10, ORC_VAR_T10,
+          ORC_VAR_T12, ORC_VAR_D1);
+      orc_program_append_2 (p, "maxub", 0, ORC_VAR_D1, ORC_VAR_T10, ORC_VAR_T11,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  ex->arrays[ORC_VAR_S2] = (void *) s2;
+  ex->arrays[ORC_VAR_S3] = (void *) s3;
+  ex->arrays[ORC_VAR_S4] = (void *) s4;
+  ex->params[ORC_VAR_P1] = p1;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
diff --git a/gst/deinterlace/tvtime-dist.h b/gst/deinterlace/tvtime-dist.h
new file mode 100644
index 0000000..adbc901
--- /dev/null
+++ b/gst/deinterlace/tvtime-dist.h
@@ -0,0 +1,93 @@
+
+/* autogenerated from tvtime.orc */
+
+#ifndef _TVTIME_H_
+#define _TVTIME_H_
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#ifndef _ORC_INTEGER_TYPEDEFS_
+#define _ORC_INTEGER_TYPEDEFS_
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+typedef int8_t orc_int8;
+typedef int16_t orc_int16;
+typedef int32_t orc_int32;
+typedef int64_t orc_int64;
+typedef uint8_t orc_uint8;
+typedef uint16_t orc_uint16;
+typedef uint32_t orc_uint32;
+typedef uint64_t orc_uint64;
+#define ORC_UINT64_C(x) UINT64_C(x)
+#elif defined(_MSC_VER)
+typedef signed __int8 orc_int8;
+typedef signed __int16 orc_int16;
+typedef signed __int32 orc_int32;
+typedef signed __int64 orc_int64;
+typedef unsigned __int8 orc_uint8;
+typedef unsigned __int16 orc_uint16;
+typedef unsigned __int32 orc_uint32;
+typedef unsigned __int64 orc_uint64;
+#define ORC_UINT64_C(x) (x##Ui64)
+#define inline __inline
+#else
+#include <limits.h>
+typedef signed char orc_int8;
+typedef short orc_int16;
+typedef int orc_int32;
+typedef unsigned char orc_uint8;
+typedef unsigned short orc_uint16;
+typedef unsigned int orc_uint32;
+#if INT_MAX == LONG_MAX
+typedef long long orc_int64;
+typedef unsigned long long orc_uint64;
+#define ORC_UINT64_C(x) (x##ULL)
+#else
+typedef long orc_int64;
+typedef unsigned long orc_uint64;
+#define ORC_UINT64_C(x) (x##UL)
+#endif
+#endif
+typedef union { orc_int16 i; orc_int8 x2[2]; } orc_union16;
+typedef union { orc_int32 i; float f; orc_int16 x2[2]; orc_int8 x4[4]; } orc_union32;
+typedef union { orc_int64 i; double f; orc_int32 x2[2]; float x2f[2]; orc_int16 x4[4]; } orc_union64;
+#endif
+#ifndef ORC_RESTRICT
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define ORC_RESTRICT restrict
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define ORC_RESTRICT __restrict__
+#else
+#define ORC_RESTRICT
+#endif
+#endif
+
+#ifndef ORC_INTERNAL
+#if defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#define ORC_INTERNAL __hidden
+#elif defined (__GNUC__)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#else
+#define ORC_INTERNAL
+#endif
+#endif
+
+void deinterlace_line_vfir (guint8 * ORC_RESTRICT d1, const guint8 * ORC_RESTRICT s1, const guint8 * ORC_RESTRICT s2, const guint8 * ORC_RESTRICT s3, const guint8 * ORC_RESTRICT s4, const guint8 * ORC_RESTRICT s5, int n);
+void deinterlace_line_linear (guint8 * ORC_RESTRICT d1, const guint8 * ORC_RESTRICT s1, const guint8 * ORC_RESTRICT s2, int n);
+void deinterlace_line_linear_blend (guint8 * ORC_RESTRICT d1, const guint8 * ORC_RESTRICT s1, const guint8 * ORC_RESTRICT s2, const guint8 * ORC_RESTRICT s3, int n);
+void deinterlace_line_greedy (orc_uint8 * ORC_RESTRICT d1, const orc_uint8 * ORC_RESTRICT s1, const orc_uint8 * ORC_RESTRICT s2, const orc_uint8 * ORC_RESTRICT s3, const orc_uint8 * ORC_RESTRICT s4, int p1, int n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/gst/deinterlace/tvtime.orc b/gst/deinterlace/tvtime.orc
new file mode 100644
index 0000000..44217e7
--- /dev/null
+++ b/gst/deinterlace/tvtime.orc
@@ -0,0 +1,109 @@
+
+.function deinterlace_line_vfir
+.dest 1 d1 guint8
+.source 1 s1 guint8
+.source 1 s2 guint8
+.source 1 s3 guint8
+.source 1 s4 guint8
+.source 1 s5 guint8
+.temp 2 t1
+.temp 2 t2
+.temp 2 t3
+
+convubw t1, s1
+convubw t2, s5
+addw t1, t1, t2
+convubw t2, s2
+convubw t3, s4
+addw t2, t2, t3
+shlw t2, t2, 2
+convubw t3, s3
+shlw t3, t3, 1
+subw t2, t2, t1
+addw t2, t2, t3
+addw t2, t2, 4
+shrsw t2, t2, 3
+convsuswb d1, t2
+
+
+.function deinterlace_line_linear
+.dest 1 d1 guint8
+.source 1 s1 guint8
+.source 1 s2 guint8
+
+avgub d1, s1, s2
+
+
+.function deinterlace_line_linear_blend
+.dest 1 d1 guint8
+.source 1 s1 guint8
+.source 1 s2 guint8
+.source 1 s3 guint8
+.temp 2 t1
+.temp 2 t2
+.temp 2 t3
+
+convubw t1, s1
+convubw t2, s2
+convubw t3, s3
+addw t1, t1, t2
+addw t3, t3, t3
+addw t1, t1, t3
+addw t1, t1, 2
+shrsw t1, t1, 2
+convsuswb d1, t1
+
+
+.function deinterlace_line_greedy
+.dest 1 d1
+.source 1 m0
+.source 1 t1
+.source 1 b1
+.source 1 m2
+.param 1 max_comb
+.temp 1 tm0
+.temp 1 tm2
+.temp 1 tb1
+.temp 1 tt1
+.temp 1 avg
+.temp 1 l2_diff
+.temp 1 lp2_diff
+.temp 1 t2
+.temp 1 t3
+.temp 1 best
+.temp 1 min
+.temp 1 max
+
+
+loadb tm0, m0
+loadb tm2, m2
+
+loadb tb1, b1
+loadb tt1, t1
+avgub avg, tt1, tb1
+
+maxub t2, tm0, avg
+minub t3, tm0, avg
+subb l2_diff, t2, t3
+
+maxub t2, tm2, avg
+minub t3, tm2, avg
+subb lp2_diff, t2, t3
+
+xorb l2_diff, l2_diff, 0x80
+xorb lp2_diff, lp2_diff, 0x80
+cmpgtsb t3, l2_diff, lp2_diff
+
+andb t2, tm2, t3
+andnb t3, t3, tm0
+orb best, t2, t3
+
+maxub max, tt1, tb1
+minub min, tt1, tb1
+addusb max, max, max_comb
+subusb min, min, max_comb
+minub best, best, max
+maxub d1, best, min
+
+
+
diff --git a/gst/deinterlace/tvtime/greedy.c b/gst/deinterlace/tvtime/greedy.c
new file mode 100644
index 0000000..804ce8b
--- /dev/null
+++ b/gst/deinterlace/tvtime/greedy.c
@@ -0,0 +1,246 @@
+/*
+ *
+ * GStreamer
+ * Copyright (c) 2000 Tom Barry  All rights reserved.
+ * mmx.h port copyright (c) 2002 Billy Biggs <vektor@dumbterm.net>.
+ *
+ * Copyright (C) 2008,2010 Sebastian Dröge <slomo@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Relicensed for GStreamer from GPL to LGPL with permit from Tom Barry
+ * and Billy Biggs.
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstdeinterlacemethod.h"
+#include <string.h>
+#include "tvtime.h"
+
+
+#define GST_TYPE_DEINTERLACE_METHOD_GREEDY_L	(gst_deinterlace_method_greedy_l_get_type ())
+#define GST_IS_DEINTERLACE_METHOD_GREEDY_L(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_L))
+#define GST_IS_DEINTERLACE_METHOD_GREEDY_L_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_GREEDY_L))
+#define GST_DEINTERLACE_METHOD_GREEDY_L_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_L, GstDeinterlaceMethodGreedyLClass))
+#define GST_DEINTERLACE_METHOD_GREEDY_L(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_L, GstDeinterlaceMethodGreedyL))
+#define GST_DEINTERLACE_METHOD_GREEDY_L_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_GREEDY_L, GstDeinterlaceMethodGreedyLClass))
+#define GST_DEINTERLACE_METHOD_GREEDY_L_CAST(obj)	((GstDeinterlaceMethodGreedyL*)(obj))
+
+GType gst_deinterlace_method_greedy_l_get_type (void);
+
+typedef struct
+{
+  GstDeinterlaceSimpleMethod parent;
+
+  guint max_comb;
+} GstDeinterlaceMethodGreedyL;
+
+typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodGreedyLClass;
+
+// This is a simple lightweight DeInterlace method that uses little CPU time
+// but gives very good results for low or intermedite motion.
+// It defers frames by one field, but that does not seem to produce noticeable
+// lip sync problems.
+//
+// The method used is to take either the older or newer weave pixel depending
+// upon which give the smaller comb factor, and then clip to avoid large damage
+// when wrong.
+//
+// I'd intended this to be part of a larger more elaborate method added to 
+// Blended Clip but this give too good results for the CPU to ignore here.
+
+static inline void
+deinterlace_greedy_interpolate_scanline_orc (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  guint max_comb = GST_DEINTERLACE_METHOD_GREEDY_L (self)->max_comb;
+
+  if (scanlines->m1 == NULL || scanlines->mp == NULL) {
+    deinterlace_line_linear (out, scanlines->t0, scanlines->b0, size);
+  } else {
+    deinterlace_line_greedy (out, scanlines->m1, scanlines->t0, scanlines->b0,
+        scanlines->mp ? scanlines->mp : scanlines->m1, max_comb, size);
+  }
+}
+
+static inline void
+deinterlace_greedy_interpolate_scanline_orc_planar_u (GstDeinterlaceSimpleMethod
+    * self, guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint
+    size)
+{
+  guint max_comb = GST_DEINTERLACE_METHOD_GREEDY_L (self)->max_comb;
+
+  if (scanlines->m1 == NULL || scanlines->mp == NULL) {
+    deinterlace_line_linear (out, scanlines->t0, scanlines->b0, size);
+  } else {
+    deinterlace_line_greedy (out, scanlines->m1, scanlines->t0, scanlines->b0,
+        scanlines->mp ? scanlines->mp : scanlines->m1, max_comb, size);
+  }
+}
+
+static inline void
+deinterlace_greedy_interpolate_scanline_orc_planar_v (GstDeinterlaceSimpleMethod
+    * self, guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint
+    size)
+{
+  guint max_comb = GST_DEINTERLACE_METHOD_GREEDY_L (self)->max_comb;
+
+  if (scanlines->m1 == NULL || scanlines->mp == NULL) {
+    deinterlace_line_linear (out, scanlines->t0, scanlines->b0, size);
+  } else {
+    deinterlace_line_greedy (out, scanlines->m1, scanlines->t0, scanlines->b0,
+        scanlines->mp ? scanlines->mp : scanlines->m1, max_comb, size);
+  }
+}
+
+static void
+deinterlace_greedy_copy_scanline (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+static void
+deinterlace_greedy_copy_scanline_planar_u (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+static void
+deinterlace_greedy_copy_scanline_planar_v (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+G_DEFINE_TYPE (GstDeinterlaceMethodGreedyL, gst_deinterlace_method_greedy_l,
+    GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
+
+enum
+{
+  PROP_0,
+  PROP_MAX_COMB
+};
+
+static void
+gst_deinterlace_method_greedy_l_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstDeinterlaceMethodGreedyL *self = GST_DEINTERLACE_METHOD_GREEDY_L (object);
+
+  switch (prop_id) {
+    case PROP_MAX_COMB:
+      self->max_comb = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+gst_deinterlace_method_greedy_l_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstDeinterlaceMethodGreedyL *self = GST_DEINTERLACE_METHOD_GREEDY_L (object);
+
+  switch (prop_id) {
+    case PROP_MAX_COMB:
+      g_value_set_uint (value, self->max_comb);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+gst_deinterlace_method_greedy_l_class_init (GstDeinterlaceMethodGreedyLClass *
+    klass)
+{
+  GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
+  GstDeinterlaceSimpleMethodClass *dism_class =
+      (GstDeinterlaceSimpleMethodClass *) klass;
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+
+  gobject_class->set_property = gst_deinterlace_method_greedy_l_set_property;
+  gobject_class->get_property = gst_deinterlace_method_greedy_l_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_MAX_COMB,
+      g_param_spec_uint ("max-comb",
+          "Max comb",
+          "Max Comb", 0, 255, 15, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
+  dim_class->fields_required = 2;
+  dim_class->name = "Motion Adaptive: Simple Detection";
+  dim_class->nick = "greedyl";
+  dim_class->latency = 1;
+
+  dism_class->interpolate_scanline_ayuv =
+      deinterlace_greedy_interpolate_scanline_orc;
+  dism_class->interpolate_scanline_yuy2 =
+      deinterlace_greedy_interpolate_scanline_orc;
+  dism_class->interpolate_scanline_yvyu =
+      deinterlace_greedy_interpolate_scanline_orc;
+  dism_class->interpolate_scanline_uyvy =
+      deinterlace_greedy_interpolate_scanline_orc;
+  dism_class->interpolate_scanline_argb =
+      deinterlace_greedy_interpolate_scanline_orc;
+  dism_class->interpolate_scanline_abgr =
+      deinterlace_greedy_interpolate_scanline_orc;
+  dism_class->interpolate_scanline_rgba =
+      deinterlace_greedy_interpolate_scanline_orc;
+  dism_class->interpolate_scanline_bgra =
+      deinterlace_greedy_interpolate_scanline_orc;
+  dism_class->interpolate_scanline_rgb =
+      deinterlace_greedy_interpolate_scanline_orc;
+  dism_class->interpolate_scanline_bgr =
+      deinterlace_greedy_interpolate_scanline_orc;
+  dism_class->interpolate_scanline_planar_y =
+      deinterlace_greedy_interpolate_scanline_orc;
+  dism_class->interpolate_scanline_planar_u =
+      deinterlace_greedy_interpolate_scanline_orc_planar_u;
+  dism_class->interpolate_scanline_planar_v =
+      deinterlace_greedy_interpolate_scanline_orc_planar_v;
+
+  dism_class->copy_scanline_ayuv = deinterlace_greedy_copy_scanline;
+  dism_class->copy_scanline_yuy2 = deinterlace_greedy_copy_scanline;
+  dism_class->copy_scanline_yvyu = deinterlace_greedy_copy_scanline;
+  dism_class->copy_scanline_uyvy = deinterlace_greedy_copy_scanline;
+  dism_class->copy_scanline_argb = deinterlace_greedy_copy_scanline;
+  dism_class->copy_scanline_abgr = deinterlace_greedy_copy_scanline;
+  dism_class->copy_scanline_rgba = deinterlace_greedy_copy_scanline;
+  dism_class->copy_scanline_bgra = deinterlace_greedy_copy_scanline;
+  dism_class->copy_scanline_rgb = deinterlace_greedy_copy_scanline;
+  dism_class->copy_scanline_bgr = deinterlace_greedy_copy_scanline;
+  dism_class->copy_scanline_planar_y = deinterlace_greedy_copy_scanline;
+  dism_class->copy_scanline_planar_u =
+      deinterlace_greedy_copy_scanline_planar_u;
+  dism_class->copy_scanline_planar_v =
+      deinterlace_greedy_copy_scanline_planar_v;
+}
+
+static void
+gst_deinterlace_method_greedy_l_init (GstDeinterlaceMethodGreedyL * self)
+{
+  self->max_comb = 15;
+}
diff --git a/gst/deinterlace/tvtime/greedyh.asm b/gst/deinterlace/tvtime/greedyh.asm
new file mode 100644
index 0000000..71a03df
--- /dev/null
+++ b/gst/deinterlace/tvtime/greedyh.asm
@@ -0,0 +1,472 @@
+/*
+ *
+ * GStreamer
+ * Copyright (c) 2001 Tom Barry.  All rights reserved.
+ * Copyright (C) 2008,2010 Sebastian Dröge <slomo@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
+ * 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 aglong with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+/*
+ * Relicensed for GStreamer from GPL to LGPL with permit from Tom Barry.
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
+ */
+
+
+#include "x86-64_macros.inc"
+
+static void
+FUNCT_NAME_YUY2 (GstDeinterlaceMethodGreedyH *self, const guint8 * L1, const guint8 * L2, const guint8 * L3, const guint8 * L2P, guint8 * Dest, gint width)
+{
+
+  // in tight loop some vars are accessed faster in local storage
+  gint64 YMask = 0x00ff00ff00ff00ffull;        // to keep only luma
+  gint64 UVMask = 0xff00ff00ff00ff00ull;       // to keep only chroma
+  gint64 ShiftMask = 0xfefefefefefefefeull;    // to avoid shifting chroma to luma
+  gint64 QW256 = 0x0100010001000100ull;        // 4 256's
+  gint64 MaxComb;
+  gint64 MotionThreshold;
+  gint64 MotionSense;
+  gint64 i;
+  glong LoopCtr;
+  glong oldbx = 0;
+
+  gint64 QW256B;
+  gint64 LastAvg = 0;          //interp value from left qword
+
+  // FIXME: Use C implementation if the width is not a multiple of 4
+  // Do something more optimal later
+  if (width % 4 != 0)
+    C_FUNCT_YUY2 (self, L1, L2, L3, L2P, Dest, width);
+
+  // Set up our two parms that are actually evaluated for each pixel
+  i = self->max_comb;
+  MaxComb =
+      i << 56 | i << 48 | i << 40 | i << 32 | i << 24 | i << 16 | i << 8 | i;
+
+  i = self->motion_threshold;    // scale to range of 0-257
+  MotionThreshold = i << 48 | i << 32 | i << 16 | i | UVMask;
+
+  i = self->motion_sense;        // scale to range of 0-257
+  MotionSense = i << 48 | i << 32 | i << 16 | i;
+
+  i = 0xffffffff - 256;
+  QW256B = i << 48 | i << 32 | i << 16 | i;     // save a couple instr on PMINSW instruct.
+
+  LoopCtr = width / 8 - 1;       // there are LineLength / 4 qwords per line but do 1 less, adj at end of loop
+
+  // For ease of reading, the comments below assume that we're operating on an odd
+  // field (i.e., that InfoIsOdd is true).  Assume the obvious for even lines..
+  __asm__ __volatile__ (
+      // save ebx (-fPIC)
+      MOVX " %%" XBX ", %[oldbx]\n\t"
+      MOVX "  %[L1],          %%" XAX "\n\t"
+      LEAX "  8(%%" XAX "),     %%" XBX "\n\t"   // next qword needed by DJR
+      MOVX "  %[L3],          %%" XCX "\n\t"
+      SUBX "  %%" XAX ",        %%" XCX "\n\t"   // carry L3 addr as an offset
+      MOVX "  %[L2P],         %%" XDX "\n\t"
+      MOVX "  %[L2],          %%" XSI "\n\t"
+      MOVX "  %[Dest],        %%" XDI "\n\t"      // DL1 if Odd or DL2 if Even
+
+      ".align 8\n\t"
+      "1:\n\t"
+      "movq  (%%" XSI "),      %%mm0\n\t"       // L2 - the newest weave pixel value
+      "movq  (%%" XAX "),      %%mm1\n\t"       // L1 - the top pixel
+      "movq  (%%" XDX "),      %%mm2\n\t"       // L2P - the prev weave pixel
+      "movq  (%%" XAX ", %%" XCX "), %%mm3\n\t" // L3, next odd row
+      "movq  %%mm1,          %%mm6\n\t"         // L1 - get simple single pixel interp
+
+      //        pavgb   mm6, mm3                    // use macro below
+      V_PAVGB ("%%mm6", "%%mm3", "%%mm4", "%[ShiftMask]")
+
+      // DJR - Diagonal Jaggie Reduction
+      // In the event that we are going to use an average (Bob) pixel we do not want a jagged
+      // stair step effect.  To combat this we avg in the 2 horizontally adjacen pixels into the
+      // interpolated Bob mix. This will do horizontal smoothing for only the Bob'd pixels.
+
+      "movq  %[LastAvg],     %%mm4\n\t" // the bob value from prev qword in row
+      "movq  %%mm6,          %[LastAvg]\n\t"    // save for next pass
+      "psrlq $48,            %%mm4\n\t" // right justify 1 pixel
+      "movq  %%mm6,          %%mm7\n\t" // copy of simple bob pixel
+      "psllq $16,            %%mm7\n\t" // left justify 3 pixels
+      "por   %%mm7,          %%mm4\n\t" // and combine
+      "movq  (%%" XBX "),      %%mm5\n\t"       // next horiz qword from L1
+      // pavgb   mm5, qword ptr[ebx+ecx] // next horiz qword from L3, use macro below
+
+      V_PAVGB ("%%mm5", "(%%" XBX ",%%" XCX ")", "%%mm7", "%[ShiftMask]")
+      "psllq $48,            %%mm5\n\t" // left just 1 pixel
+      "movq  %%mm6,          %%mm7\n\t" // another copy of simple bob pixel
+      "psrlq $16,            %%mm7\n\t" // right just 3 pixels
+      "por   %%mm7,          %%mm5\n\t" // combine
+      // pavgb        mm4, mm5                        // avg of forward and prev by 1 pixel, use macro
+      V_PAVGB ("%%mm4", "%%mm5", "%%mm5", "%[ShiftMask]")       // mm5 gets modified if MMX
+      //                        pavgb        mm6, mm4                        // avg of center and surround interp vals, use macro
+      V_PAVGB ("%%mm6", "%%mm4", "%%mm7", "%[ShiftMask]")
+
+      // Don't do any more averaging than needed for mmx. It hurts performance and causes rounding errors.
+#ifndef IS_MMX
+      //          pavgb        mm4, mm6                        // 1/4 center, 3/4 adjacent
+      V_PAVGB ("%%mm4", "%%mm6", "%%mm7", "%[ShiftMask]")
+      //                    pavgb        mm6, mm4                        // 3/8 center, 5/8 adjacent
+      V_PAVGB ("%%mm6", "%%mm4", "%%mm7", "%[ShiftMask]")
+#endif
+
+      // get abs value of possible L2 comb
+      "movq    %%mm6,        %%mm4\n\t" // work copy of interp val
+      "movq    %%mm2,        %%mm7\n\t" // L2
+      "psubusb %%mm4,        %%mm7\n\t" // L2 - avg
+      "movq    %%mm4,        %%mm5\n\t" // avg
+      "psubusb %%mm2,        %%mm5\n\t" // avg - L2
+      "por     %%mm7,        %%mm5\n\t" // abs(avg-L2)
+
+      // get abs value of possible L2P comb
+      "movq    %%mm0,        %%mm7\n\t" // L2P
+      "psubusb %%mm4,        %%mm7\n\t" // L2P - avg
+      "psubusb %%mm0,        %%mm4\n\t" // avg - L2P
+      "por     %%mm7,        %%mm4\n\t" // abs(avg-L2P)
+
+      // use L2 or L2P depending upon which makes smaller comb
+      "psubusb %%mm5,        %%mm4\n\t" // see if it goes to zero
+      "psubusb %%mm5,        %%mm5\n\t" // 0
+      "pcmpeqb %%mm5,        %%mm4\n\t" // if (mm4=0) then FF else 0
+      "pcmpeqb %%mm4,        %%mm5\n\t" // opposite of mm4
+
+      // if Comb(L2P) <= Comb(L2) then mm4=ff, mm5=0 else mm4=0, mm5 = 55
+      "pand    %%mm2,        %%mm5\n\t" // use L2 if mm5 == ff, else 0
+      "pand    %%mm0,        %%mm4\n\t" // use L2P if mm4 = ff, else 0
+      "por     %%mm5,        %%mm4\n\t" // may the best win
+
+      // Inventory: at this point we have the following values:
+      // mm0 = L2P (or L2)
+      // mm1 = L1
+      // mm2 = L2 (or L2P)
+      // mm3 = L3
+      // mm4 = the best of L2,L2P weave pixel, base upon comb
+      // mm6 = the avg interpolated value, if we need to use it
+      // Let's measure movement, as how much the weave pixel has changed
+
+      "movq    %%mm2,        %%mm7\n\t"
+      "psubusb %%mm0,        %%mm2\n\t"
+      "psubusb %%mm7,        %%mm0\n\t"
+      "por     %%mm2,        %%mm0\n\t"   // abs value of change, used later
+
+      // Now lets clip our chosen value to be not outside of the range
+      // of the high/low range L1-L3 by more than MaxComb.
+      // This allows some comb but limits the damages and also allows more
+      // detail than a boring oversmoothed clip.
+
+      "movq    %%mm1,        %%mm2\n\t" // copy L1
+      // pmaxub mm2, mm3                     // use macro
+      V_PMAXUB ("%%mm2", "%%mm3")       // now = Max(L1,L3)
+      "movq    %%mm1,        %%mm5\n\t" // copy L1
+      // pminub        mm5, mm3                    // now = Min(L1,L3), use macro
+      V_PMINUB ("%%mm5", "%%mm3", "%%mm7")
+
+      // allow the value to be above the high or below the low by amt of MaxComb
+      "psubusb %[MaxComb],   %%mm5\n\t" // lower min by diff
+      "paddusb %[MaxComb],   %%mm2\n\t" // increase max by diff
+      // pmaxub        mm4, mm5         // now = Max(best,Min(L1,L3) use macro
+      V_PMAXUB ("%%mm4", "%%mm5")
+      // pminub        mm4, mm2         // now = Min( Max(best, Min(L1,L3), L2 )=L2 clipped
+      V_PMINUB ("%%mm4", "%%mm2", "%%mm7")
+
+      // Blend weave pixel with bob pixel, depending on motion val in mm0
+      "psubusb %[MotionThreshold], %%mm0\n\t"   // test Threshold, clear chroma change
+      "pmullw  %[MotionSense], %%mm0\n\t"       // mul by user factor, keep low 16 bits
+      "movq    %[QW256], %%mm7\n\t"
+#ifdef IS_MMXEXT
+      "pminsw  %%mm7,        %%mm0\n\t" // max = 256
+#else
+      "paddusw %[QW256B],    %%mm0\n\t" // add, may sat at fff..
+      "psubusw %[QW256B],    %%mm0\n\t" // now = Min(L1,256)
+#endif
+      "psubusw %%mm0,        %%mm7\n\t" // so the 2 sum to 256, weighted avg
+      "movq    %%mm4,        %%mm2\n\t" // save weave chroma info before trashing
+      "pand    %[YMask],     %%mm4\n\t" // keep only luma from calc'd value
+      "pmullw  %%mm7,        %%mm4\n\t" // use more weave for less motion
+      "pand    %[YMask],     %%mm6\n\t" // keep only luma from calc'd value
+      "pmullw  %%mm0,        %%mm6\n\t" // use more bob for large motion
+      "paddusw %%mm6,        %%mm4\n\t" // combine
+      "psrlw   $8,           %%mm4\n\t" // div by 256 to get weighted avg
+      // chroma comes from weave pixel
+      "pand    %[UVMask],    %%mm2\n\t" // keep chroma
+      "por     %%mm4,        %%mm2\n\t" // and combine
+      V_MOVNTQ ("(%%" XDI ")", "%%mm2") // move in our clipped best, use macro
+      // bump ptrs and loop
+      LEAX "    8(%%" XAX "),   %%" XAX "\n\t"
+      LEAX "    8(%%" XBX "),   %%" XBX "\n\t"
+      LEAX "    8(%%" XDX "),   %%" XDX "\n\t"
+      LEAX "    8(%%" XDI "),   %%" XDI "\n\t"
+      LEAX "    8(%%" XSI "),   %%" XSI "\n\t"
+      DECX "    %[LoopCtr]\n\t"
+      
+      "jg      1b\n\t"   // loop if not to last line
+      // note P-III default assumes backward branches taken
+      "jl      1f\n\t"          // done
+      MOVX "    %%" XAX ",      %%" XBX "\n\t"  // sharpness lookahead 1 byte only, be wrong on 1
+      "jmp     1b\n\t"
+      
+      "1:\n\t"      
+      MOVX " %[oldbx], %%" XBX "\n\t"
+      "emms\n\t":     /* no outputs */
+
+      :[LastAvg] "m" (LastAvg),
+       [L1] "m" (L1),
+       [L3] "m" (L3),
+       [L2P] "m" (L2P),
+       [L2] "m" (L2),
+       [Dest] "m" (Dest),
+       [ShiftMask] "m" (ShiftMask),
+       [MaxComb] "m" (MaxComb),
+       [MotionThreshold] "m" (MotionThreshold),
+       [MotionSense] "m" (MotionSense),
+       [QW256B] "m" (QW256B),
+       [YMask] "m" (YMask),
+       [UVMask] "m" (UVMask),
+       [LoopCtr] "m" (LoopCtr),
+       [QW256] "m" (QW256),
+       [oldbx] "m" (oldbx)
+      : XAX, XCX, XDX, XSI, XDI,
+      "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
+#ifdef __MMX__
+      "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
+#endif
+      "memory", "cc");
+}
+
+static void
+FUNCT_NAME_UYVY (GstDeinterlaceMethodGreedyH *self, const guint8 * L1, const guint8 * L2, const guint8 * L3, const guint8 * L2P, guint8 * Dest, gint width)
+{
+
+  // in tight loop some vars are accessed faster in local storage
+  gint64 YMask = 0xff00ff00ff00ff00ull;       // to keep only luma
+  gint64 UVMask = 0x00ff00ff00ff00ffull;        // to keep only chroma
+  gint64 ShiftMask = 0xfefefefefefefefeull;    // to avoid shifting chroma to luma
+  gint64 QW256 = 0x0100010001000100ull;        // 4 256's
+  gint64 MaxComb;
+  gint64 MotionThreshold;
+  gint64 MotionSense;
+  gint64 i;
+  glong LoopCtr;
+  glong oldbx = 0;
+
+  gint64 QW256B;
+  gint64 LastAvg = 0;          //interp value from left qword
+
+  // FIXME: Use C implementation if the width is not a multiple of 4
+  // Do something more optimal later
+  if (width % 4 != 0)
+    C_FUNCT_UYVY (self, L1, L2, L3, L2P, Dest, width);
+
+  // Set up our two parms that are actually evaluated for each pixel
+  i = self->max_comb;
+  MaxComb =
+      i << 56 | i << 48 | i << 40 | i << 32 | i << 24 | i << 16 | i << 8 | i;
+
+  i = self->motion_threshold;    // scale to range of 0-257
+  MotionThreshold = i << 48 | i << 32 | i << 16 | i | UVMask;
+
+  i = self->motion_sense;        // scale to range of 0-257
+  MotionSense = i << 48 | i << 32 | i << 16 | i;
+
+  i = 0xffffffff - 256;
+  QW256B = i << 48 | i << 32 | i << 16 | i;     // save a couple instr on PMINSW instruct.
+
+  LoopCtr = width / 8 - 1;       // there are LineLength / 4 qwords per line but do 1 less, adj at end of loop
+
+  // For ease of reading, the comments below assume that we're operating on an odd
+  // field (i.e., that InfoIsOdd is true).  Assume the obvious for even lines..
+  __asm__ __volatile__ (
+      // save ebx (-fPIC)
+      MOVX " %%" XBX ", %[oldbx]\n\t"
+      MOVX "  %[L1],          %%" XAX "\n\t"
+      LEAX "  8(%%" XAX "),     %%" XBX "\n\t"   // next qword needed by DJR
+      MOVX "  %[L3],          %%" XCX "\n\t"
+      SUBX "  %%" XAX ",        %%" XCX "\n\t"   // carry L3 addr as an offset
+      MOVX "  %[L2P],         %%" XDX "\n\t"
+      MOVX "  %[L2],          %%" XSI "\n\t"
+      MOVX "  %[Dest],        %%" XDI "\n\t"      // DL1 if Odd or DL2 if Even
+
+      ".align 8\n\t"
+      "1:\n\t"
+      "movq  (%%" XSI "),      %%mm0\n\t"       // L2 - the newest weave pixel value
+      "movq  (%%" XAX "),      %%mm1\n\t"       // L1 - the top pixel
+      "movq  (%%" XDX "),      %%mm2\n\t"       // L2P - the prev weave pixel
+      "movq  (%%" XAX ", %%" XCX "), %%mm3\n\t" // L3, next odd row
+      "movq  %%mm1,          %%mm6\n\t"         // L1 - get simple single pixel interp
+
+      //        pavgb   mm6, mm3                    // use macro below
+      V_PAVGB ("%%mm6", "%%mm3", "%%mm4", "%[ShiftMask]")
+
+      // DJR - Diagonal Jaggie Reduction
+      // In the event that we are going to use an average (Bob) pixel we do not want a jagged
+      // stair step effect.  To combat this we avg in the 2 horizontally adjacen pixels into the
+      // interpolated Bob mix. This will do horizontal smoothing for only the Bob'd pixels.
+
+      "movq  %[LastAvg],     %%mm4\n\t" // the bob value from prev qword in row
+      "movq  %%mm6,          %[LastAvg]\n\t"    // save for next pass
+      "psrlq $48,            %%mm4\n\t" // right justify 1 pixel
+      "movq  %%mm6,          %%mm7\n\t" // copy of simple bob pixel
+      "psllq $16,            %%mm7\n\t" // left justify 3 pixels
+      "por   %%mm7,          %%mm4\n\t" // and combine
+      "movq  (%%" XBX "),      %%mm5\n\t"       // next horiz qword from L1
+      // pavgb   mm5, qword ptr[ebx+ecx] // next horiz qword from L3, use macro below
+
+      V_PAVGB ("%%mm5", "(%%" XBX ",%%" XCX ")", "%%mm7", "%[ShiftMask]")
+      "psllq $48,            %%mm5\n\t" // left just 1 pixel
+      "movq  %%mm6,          %%mm7\n\t" // another copy of simple bob pixel
+      "psrlq $16,            %%mm7\n\t" // right just 3 pixels
+      "por   %%mm7,          %%mm5\n\t" // combine
+      // pavgb        mm4, mm5                        // avg of forward and prev by 1 pixel, use macro
+      V_PAVGB ("%%mm4", "%%mm5", "%%mm5", "%[ShiftMask]")       // mm5 gets modified if MMX
+      //                        pavgb        mm6, mm4                        // avg of center and surround interp vals, use macro
+      V_PAVGB ("%%mm6", "%%mm4", "%%mm7", "%[ShiftMask]")
+
+      // Don't do any more averaging than needed for mmx. It hurts performance and causes rounding errors.
+#ifndef IS_MMX
+      //          pavgb        mm4, mm6                        // 1/4 center, 3/4 adjacent
+      V_PAVGB ("%%mm4", "%%mm6", "%%mm7", "%[ShiftMask]")
+      //                    pavgb        mm6, mm4                        // 3/8 center, 5/8 adjacent
+      V_PAVGB ("%%mm6", "%%mm4", "%%mm7", "%[ShiftMask]")
+#endif
+
+      // get abs value of possible L2 comb
+      "movq    %%mm6,        %%mm4\n\t" // work copy of interp val
+      "movq    %%mm2,        %%mm7\n\t" // L2
+      "psubusb %%mm4,        %%mm7\n\t" // L2 - avg
+      "movq    %%mm4,        %%mm5\n\t" // avg
+      "psubusb %%mm2,        %%mm5\n\t" // avg - L2
+      "por     %%mm7,        %%mm5\n\t" // abs(avg-L2)
+
+      // get abs value of possible L2P comb
+      "movq    %%mm0,        %%mm7\n\t" // L2P
+      "psubusb %%mm4,        %%mm7\n\t" // L2P - avg
+      "psubusb %%mm0,        %%mm4\n\t" // avg - L2P
+      "por     %%mm7,        %%mm4\n\t" // abs(avg-L2P)
+
+      // use L2 or L2P depending upon which makes smaller comb
+      "psubusb %%mm5,        %%mm4\n\t" // see if it goes to zero
+      "psubusb %%mm5,        %%mm5\n\t" // 0
+      "pcmpeqb %%mm5,        %%mm4\n\t" // if (mm4=0) then FF else 0
+      "pcmpeqb %%mm4,        %%mm5\n\t" // opposite of mm4
+
+      // if Comb(L2P) <= Comb(L2) then mm4=ff, mm5=0 else mm4=0, mm5 = 55
+      "pand    %%mm2,        %%mm5\n\t" // use L2 if mm5 == ff, else 0
+      "pand    %%mm0,        %%mm4\n\t" // use L2P if mm4 = ff, else 0
+      "por     %%mm5,        %%mm4\n\t" // may the best win
+
+      // Inventory: at this point we have the following values:
+      // mm0 = L2P (or L2)
+      // mm1 = L1
+      // mm2 = L2 (or L2P)
+      // mm3 = L3
+      // mm4 = the best of L2,L2P weave pixel, base upon comb
+      // mm6 = the avg interpolated value, if we need to use it
+      // Let's measure movement, as how much the weave pixel has changed
+
+      "movq    %%mm2,        %%mm7\n\t"
+      "psubusb %%mm0,        %%mm2\n\t"
+      "psubusb %%mm7,        %%mm0\n\t"
+      "por     %%mm2,        %%mm0\n\t"   // abs value of change, used later
+
+      // Now lets clip our chosen value to be not outside of the range
+      // of the high/low range L1-L3 by more than MaxComb.
+      // This allows some comb but limits the damages and also allows more
+      // detail than a boring oversmoothed clip.
+
+      "movq    %%mm1,        %%mm2\n\t" // copy L1
+      // pmaxub mm2, mm3                     // use macro
+      V_PMAXUB ("%%mm2", "%%mm3")       // now = Max(L1,L3)
+      "movq    %%mm1,        %%mm5\n\t" // copy L1
+      // pminub        mm5, mm3                    // now = Min(L1,L3), use macro
+      V_PMINUB ("%%mm5", "%%mm3", "%%mm7")
+
+      // allow the value to be above the high or below the low by amt of MaxComb
+      "psubusb %[MaxComb],   %%mm5\n\t" // lower min by diff
+      "paddusb %[MaxComb],   %%mm2\n\t" // increase max by diff
+      // pmaxub        mm4, mm5         // now = Max(best,Min(L1,L3) use macro
+      V_PMAXUB ("%%mm4", "%%mm5")
+      // pminub        mm4, mm2         // now = Min( Max(best, Min(L1,L3), L2 )=L2 clipped
+      V_PMINUB ("%%mm4", "%%mm2", "%%mm7")
+
+      // Blend weave pixel with bob pixel, depending on motion val in mm0
+      "psubusb %[MotionThreshold], %%mm0\n\t"   // test Threshold, clear chroma change
+      "psrlw   $8,           %%mm0\n\t" // div by 256 to get weighted avg
+      "pmullw  %[MotionSense], %%mm0\n\t"       // mul by user factor, keep low 16 bits
+      "movq    %[QW256], %%mm7\n\t"
+#ifdef IS_MMXEXT
+      "pminsw  %%mm7,        %%mm0\n\t" // max = 256
+#else
+      "paddusw %[QW256B],    %%mm0\n\t" // add, may sat at fff..
+      "psubusw %[QW256B],    %%mm0\n\t" // now = Min(L1,256)
+#endif
+      "psubusw %%mm0,        %%mm7\n\t" // so the 2 sum to 256, weighted avg
+      "movq    %%mm4,        %%mm2\n\t" // save weave chroma info before trashing
+      "pand    %[YMask],     %%mm4\n\t" // keep only luma from calc'd value
+      "psrlw   $8,           %%mm4\n\t" // div by 256 to get weighted avg
+      "pmullw  %%mm7,        %%mm4\n\t" // use more weave for less motion
+      "pand    %[YMask],     %%mm6\n\t" // keep only luma from calc'd value
+      "psrlw   $8,           %%mm6\n\t" // div by 256 to get weighted avg
+      "pmullw  %%mm0,        %%mm6\n\t" // use more bob for large motion
+      "paddusw %%mm6,        %%mm4\n\t" // combine
+      "pand    %[YMask],     %%mm4\n\t" // keep only luma from calc'd value
+      // chroma comes from weave pixel
+      "pand    %[UVMask],    %%mm2\n\t" // keep chroma
+      "por     %%mm4,        %%mm2\n\t" // and combine
+      V_MOVNTQ ("(%%" XDI ")", "%%mm2") // move in our clipped best, use macro
+      // bump ptrs and loop
+      LEAX "    8(%%" XAX "),   %%" XAX "\n\t"
+      LEAX "    8(%%" XBX "),   %%" XBX "\n\t"
+      LEAX "    8(%%" XDX "),   %%" XDX "\n\t"
+      LEAX "    8(%%" XDI "),   %%" XDI "\n\t"
+      LEAX "    8(%%" XSI "),   %%" XSI "\n\t"
+      DECX "    %[LoopCtr]\n\t"
+      
+      "jg      1b\n\t"   // loop if not to last line
+      // note P-III default assumes backward branches taken
+      "jl      1f\n\t"          // done
+      MOVX "    %%" XAX ",      %%" XBX "\n\t"  // sharpness lookahead 1 byte only, be wrong on 1
+      "jmp     1b\n\t"
+      
+      "1:\n\t"      
+      MOVX " %[oldbx], %%" XBX "\n\t"
+      "emms\n\t":     /* no outputs */
+
+      :[LastAvg] "m" (LastAvg),
+       [L1] "m" (L1),
+       [L3] "m" (L3),
+       [L2P] "m" (L2P),
+       [L2] "m" (L2),
+       [Dest] "m" (Dest),
+       [ShiftMask] "m" (ShiftMask),
+       [MaxComb] "m" (MaxComb),
+       [MotionThreshold] "m" (MotionThreshold),
+       [MotionSense] "m" (MotionSense),
+       [QW256B] "m" (QW256B),
+       [YMask] "m" (YMask),
+       [UVMask] "m" (UVMask),
+       [LoopCtr] "m" (LoopCtr),
+       [QW256] "m" (QW256),
+       [oldbx] "m" (oldbx)
+      : XAX, XCX, XDX, XSI, XDI,
+      "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
+#ifdef __MMX__
+      "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
+#endif
+      "memory", "cc");
+}
+
diff --git a/gst/deinterlace/tvtime/greedyh.c b/gst/deinterlace/tvtime/greedyh.c
new file mode 100644
index 0000000..69f75ee
--- /dev/null
+++ b/gst/deinterlace/tvtime/greedyh.c
@@ -0,0 +1,1076 @@
+/*
+ *
+ * GStreamer
+ * Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
+ * Copyright (C) 2008,2010 Sebastian Dröge <slomo@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "greedyhmacros.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <gst/gst.h>
+#include "plugins.h"
+#include "gstdeinterlacemethod.h"
+#ifdef HAVE_ORC
+#include <orc/orc.h>
+#endif
+
+#define GST_TYPE_DEINTERLACE_METHOD_GREEDY_H	(gst_deinterlace_method_greedy_h_get_type ())
+#define GST_IS_DEINTERLACE_METHOD_GREEDY_H(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H))
+#define GST_IS_DEINTERLACE_METHOD_GREEDY_H_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H))
+#define GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H, GstDeinterlaceMethodGreedyHClass))
+#define GST_DEINTERLACE_METHOD_GREEDY_H(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H, GstDeinterlaceMethodGreedyH))
+#define GST_DEINTERLACE_METHOD_GREEDY_H_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H, GstDeinterlaceMethodGreedyHClass))
+#define GST_DEINTERLACE_METHOD_GREEDY_H_CAST(obj)	((GstDeinterlaceMethodGreedyH*)(obj))
+
+typedef struct
+{
+  GstDeinterlaceMethod parent;
+
+  guint max_comb, motion_threshold, motion_sense;
+} GstDeinterlaceMethodGreedyH;
+
+typedef void (*ScanlineFunction) (GstDeinterlaceMethodGreedyH * self,
+    const guint8 * L2, const guint8 * L1, const guint8 * L3, const guint8 * L2P,
+    guint8 * Dest, gint width);
+
+typedef struct
+{
+  GstDeinterlaceMethodClass parent_class;
+  ScanlineFunction scanline_yuy2;       /* This is for YVYU too */
+  ScanlineFunction scanline_uyvy;
+  ScanlineFunction scanline_ayuv;
+  ScanlineFunction scanline_planar_y;
+  ScanlineFunction scanline_planar_uv;
+} GstDeinterlaceMethodGreedyHClass;
+
+static void
+greedyh_scanline_C_ayuv (GstDeinterlaceMethodGreedyH * self, const guint8 * L1,
+    const guint8 * L2, const guint8 * L3, const guint8 * L2P, guint8 * Dest,
+    gint width)
+{
+  gint Pos, Comp;
+  guint8 l1, l1_1, l3, l3_1;
+  guint8 avg, avg_1;
+  guint8 avg__1[4] = { 0, };
+  guint8 avg_s;
+  guint8 avg_sc;
+  guint8 best;
+  guint16 mov;
+  guint8 out;
+  guint8 l2, lp2;
+  guint8 l2_diff, lp2_diff;
+  guint8 min, max;
+  guint max_comb = self->max_comb;
+  guint motion_sense = self->motion_sense;
+  guint motion_threshold = self->motion_threshold;
+
+  width /= 4;
+  for (Pos = 0; Pos < width; Pos++) {
+    for (Comp = 0; Comp < 4; Comp++) {
+      l1 = L1[0];
+      l3 = L3[0];
+
+      if (Pos == width - 1) {
+        l1_1 = l1;
+        l3_1 = l3;
+      } else {
+        l1_1 = L1[4];
+        l3_1 = L3[4];
+      }
+
+      /* Average of L1 and L3 */
+      avg = (l1 + l3) / 2;
+
+      if (Pos == 0) {
+        avg__1[Comp] = avg;
+      }
+
+      /* Average of next L1 and next L3 */
+      avg_1 = (l1_1 + l3_1) / 2;
+
+      /* Calculate average of one pixel forward and previous */
+      avg_s = (avg__1[Comp] + avg_1) / 2;
+
+      /* Calculate average of center and surrounding pixels */
+      avg_sc = (avg + avg_s) / 2;
+
+      /* move forward */
+      avg__1[Comp] = avg;
+
+      /* Get best L2/L2P, i.e. least diff from above average */
+      l2 = L2[0];
+      lp2 = L2P[0];
+
+      l2_diff = ABS (l2 - avg_sc);
+
+      lp2_diff = ABS (lp2 - avg_sc);
+
+      if (l2_diff > lp2_diff)
+        best = lp2;
+      else
+        best = l2;
+
+      /* Clip this best L2/L2P by L1/L3 and allow to differ by GreedyMaxComb */
+      max = MAX (l1, l3);
+      min = MIN (l1, l3);
+
+      if (max < 256 - max_comb)
+        max += max_comb;
+      else
+        max = 255;
+
+      if (min > max_comb)
+        min -= max_comb;
+      else
+        min = 0;
+
+      out = CLAMP (best, min, max);
+
+      if (Comp < 2) {
+        /* Do motion compensation for luma, i.e. how much
+         * the weave pixel differs */
+        mov = ABS (l2 - lp2);
+        if (mov > motion_threshold)
+          mov -= motion_threshold;
+        else
+          mov = 0;
+
+        mov = mov * motion_sense;
+        if (mov > 256)
+          mov = 256;
+
+        /* Weighted sum on clipped weave pixel and average */
+        out = (out * (256 - mov) + avg_sc * mov) / 256;
+      }
+
+      Dest[0] = out;
+
+      Dest += 1;
+      L1 += 1;
+      L2 += 1;
+      L3 += 1;
+      L2P += 1;
+    }
+  }
+}
+
+static void
+greedyh_scanline_C_yuy2 (GstDeinterlaceMethodGreedyH * self, const guint8 * L1,
+    const guint8 * L2, const guint8 * L3, const guint8 * L2P, guint8 * Dest,
+    gint width)
+{
+  gint Pos;
+  guint8 l1_l, l1_1_l, l3_l, l3_1_l;
+  guint8 l1_c, l1_1_c, l3_c, l3_1_c;
+  guint8 avg_l, avg_c, avg_l_1, avg_c_1;
+  guint8 avg_l__1 = 0, avg_c__1 = 0;
+  guint8 avg_s_l, avg_s_c;
+  guint8 avg_sc_l, avg_sc_c;
+  guint8 best_l, best_c;
+  guint16 mov_l;
+  guint8 out_l, out_c;
+  guint8 l2_l, l2_c, lp2_l, lp2_c;
+  guint8 l2_l_diff, l2_c_diff, lp2_l_diff, lp2_c_diff;
+  guint8 min_l, min_c, max_l, max_c;
+  guint max_comb = self->max_comb;
+  guint motion_sense = self->motion_sense;
+  guint motion_threshold = self->motion_threshold;
+
+  width /= 2;
+  for (Pos = 0; Pos < width; Pos++) {
+    l1_l = L1[0];
+    l1_c = L1[1];
+    l3_l = L3[0];
+    l3_c = L3[1];
+
+    if (Pos == width - 1) {
+      l1_1_l = l1_l;
+      l1_1_c = l1_c;
+      l3_1_l = l3_l;
+      l3_1_c = l3_c;
+    } else {
+      l1_1_l = L1[2];
+      l1_1_c = L1[3];
+      l3_1_l = L3[2];
+      l3_1_c = L3[3];
+    }
+
+    /* Average of L1 and L3 */
+    avg_l = (l1_l + l3_l) / 2;
+    avg_c = (l1_c + l3_c) / 2;
+
+    if (Pos == 0) {
+      avg_l__1 = avg_l;
+      avg_c__1 = avg_c;
+    }
+
+    /* Average of next L1 and next L3 */
+    avg_l_1 = (l1_1_l + l3_1_l) / 2;
+    avg_c_1 = (l1_1_c + l3_1_c) / 2;
+
+    /* Calculate average of one pixel forward and previous */
+    avg_s_l = (avg_l__1 + avg_l_1) / 2;
+    avg_s_c = (avg_c__1 + avg_c_1) / 2;
+
+    /* Calculate average of center and surrounding pixels */
+    avg_sc_l = (avg_l + avg_s_l) / 2;
+    avg_sc_c = (avg_c + avg_s_c) / 2;
+
+    /* move forward */
+    avg_l__1 = avg_l;
+    avg_c__1 = avg_c;
+
+    /* Get best L2/L2P, i.e. least diff from above average */
+    l2_l = L2[0];
+    l2_c = L2[1];
+    lp2_l = L2P[0];
+    lp2_c = L2P[1];
+
+    l2_l_diff = ABS (l2_l - avg_sc_l);
+    l2_c_diff = ABS (l2_c - avg_sc_c);
+
+    lp2_l_diff = ABS (lp2_l - avg_sc_l);
+    lp2_c_diff = ABS (lp2_c - avg_sc_c);
+
+    if (l2_l_diff > lp2_l_diff)
+      best_l = lp2_l;
+    else
+      best_l = l2_l;
+
+    if (l2_c_diff > lp2_c_diff)
+      best_c = lp2_c;
+    else
+      best_c = l2_c;
+
+    /* Clip this best L2/L2P by L1/L3 and allow to differ by GreedyMaxComb */
+    max_l = MAX (l1_l, l3_l);
+    min_l = MIN (l1_l, l3_l);
+
+    if (max_l < 256 - max_comb)
+      max_l += max_comb;
+    else
+      max_l = 255;
+
+    if (min_l > max_comb)
+      min_l -= max_comb;
+    else
+      min_l = 0;
+
+    max_c = MAX (l1_c, l3_c);
+    min_c = MIN (l1_c, l3_c);
+
+    if (max_c < 256 - max_comb)
+      max_c += max_comb;
+    else
+      max_c = 255;
+
+    if (min_c > max_comb)
+      min_c -= max_comb;
+    else
+      min_c = 0;
+
+    out_l = CLAMP (best_l, min_l, max_l);
+    out_c = CLAMP (best_c, min_c, max_c);
+
+    /* Do motion compensation for luma, i.e. how much
+     * the weave pixel differs */
+    mov_l = ABS (l2_l - lp2_l);
+    if (mov_l > motion_threshold)
+      mov_l -= motion_threshold;
+    else
+      mov_l = 0;
+
+    mov_l = mov_l * motion_sense;
+    if (mov_l > 256)
+      mov_l = 256;
+
+    /* Weighted sum on clipped weave pixel and average */
+    out_l = (out_l * (256 - mov_l) + avg_sc_l * mov_l) / 256;
+
+    Dest[0] = out_l;
+    Dest[1] = out_c;
+
+    Dest += 2;
+    L1 += 2;
+    L2 += 2;
+    L3 += 2;
+    L2P += 2;
+  }
+}
+
+static void
+greedyh_scanline_C_uyvy (GstDeinterlaceMethodGreedyH * self, const guint8 * L1,
+    const guint8 * L2, const guint8 * L3, const guint8 * L2P, guint8 * Dest,
+    gint width)
+{
+  gint Pos;
+  guint8 l1_l, l1_1_l, l3_l, l3_1_l;
+  guint8 l1_c, l1_1_c, l3_c, l3_1_c;
+  guint8 avg_l, avg_c, avg_l_1, avg_c_1;
+  guint8 avg_l__1 = 0, avg_c__1 = 0;
+  guint8 avg_s_l, avg_s_c;
+  guint8 avg_sc_l, avg_sc_c;
+  guint8 best_l, best_c;
+  guint16 mov_l;
+  guint8 out_l, out_c;
+  guint8 l2_l, l2_c, lp2_l, lp2_c;
+  guint8 l2_l_diff, l2_c_diff, lp2_l_diff, lp2_c_diff;
+  guint8 min_l, min_c, max_l, max_c;
+  guint max_comb = self->max_comb;
+  guint motion_sense = self->motion_sense;
+  guint motion_threshold = self->motion_threshold;
+
+  width /= 2;
+  for (Pos = 0; Pos < width; Pos++) {
+    l1_l = L1[1];
+    l1_c = L1[0];
+    l3_l = L3[1];
+    l3_c = L3[0];
+
+    if (Pos == width - 1) {
+      l1_1_l = l1_l;
+      l1_1_c = l1_c;
+      l3_1_l = l3_l;
+      l3_1_c = l3_c;
+    } else {
+      l1_1_l = L1[3];
+      l1_1_c = L1[2];
+      l3_1_l = L3[3];
+      l3_1_c = L3[2];
+    }
+
+    /* Average of L1 and L3 */
+    avg_l = (l1_l + l3_l) / 2;
+    avg_c = (l1_c + l3_c) / 2;
+
+    if (Pos == 0) {
+      avg_l__1 = avg_l;
+      avg_c__1 = avg_c;
+    }
+
+    /* Average of next L1 and next L3 */
+    avg_l_1 = (l1_1_l + l3_1_l) / 2;
+    avg_c_1 = (l1_1_c + l3_1_c) / 2;
+
+    /* Calculate average of one pixel forward and previous */
+    avg_s_l = (avg_l__1 + avg_l_1) / 2;
+    avg_s_c = (avg_c__1 + avg_c_1) / 2;
+
+    /* Calculate average of center and surrounding pixels */
+    avg_sc_l = (avg_l + avg_s_l) / 2;
+    avg_sc_c = (avg_c + avg_s_c) / 2;
+
+    /* move forward */
+    avg_l__1 = avg_l;
+    avg_c__1 = avg_c;
+
+    /* Get best L2/L2P, i.e. least diff from above average */
+    l2_l = L2[1];
+    l2_c = L2[0];
+    lp2_l = L2P[1];
+    lp2_c = L2P[0];
+
+    l2_l_diff = ABS (l2_l - avg_sc_l);
+    l2_c_diff = ABS (l2_c - avg_sc_c);
+
+    lp2_l_diff = ABS (lp2_l - avg_sc_l);
+    lp2_c_diff = ABS (lp2_c - avg_sc_c);
+
+    if (l2_l_diff > lp2_l_diff)
+      best_l = lp2_l;
+    else
+      best_l = l2_l;
+
+    if (l2_c_diff > lp2_c_diff)
+      best_c = lp2_c;
+    else
+      best_c = l2_c;
+
+    /* Clip this best L2/L2P by L1/L3 and allow to differ by GreedyMaxComb */
+    max_l = MAX (l1_l, l3_l);
+    min_l = MIN (l1_l, l3_l);
+
+    if (max_l < 256 - max_comb)
+      max_l += max_comb;
+    else
+      max_l = 255;
+
+    if (min_l > max_comb)
+      min_l -= max_comb;
+    else
+      min_l = 0;
+
+    max_c = MAX (l1_c, l3_c);
+    min_c = MIN (l1_c, l3_c);
+
+    if (max_c < 256 - max_comb)
+      max_c += max_comb;
+    else
+      max_c = 255;
+
+    if (min_c > max_comb)
+      min_c -= max_comb;
+    else
+      min_c = 0;
+
+    out_l = CLAMP (best_l, min_l, max_l);
+    out_c = CLAMP (best_c, min_c, max_c);
+
+    /* Do motion compensation for luma, i.e. how much
+     * the weave pixel differs */
+    mov_l = ABS (l2_l - lp2_l);
+    if (mov_l > motion_threshold)
+      mov_l -= motion_threshold;
+    else
+      mov_l = 0;
+
+    mov_l = mov_l * motion_sense;
+    if (mov_l > 256)
+      mov_l = 256;
+
+    /* Weighted sum on clipped weave pixel and average */
+    out_l = (out_l * (256 - mov_l) + avg_sc_l * mov_l) / 256;
+
+    Dest[1] = out_l;
+    Dest[0] = out_c;
+
+    Dest += 2;
+    L1 += 2;
+    L2 += 2;
+    L3 += 2;
+    L2P += 2;
+  }
+}
+
+static void
+greedyh_scanline_C_planar_y (GstDeinterlaceMethodGreedyH * self,
+    const guint8 * L1, const guint8 * L2, const guint8 * L3, const guint8 * L2P,
+    guint8 * Dest, gint width)
+{
+  gint Pos;
+  guint8 l1, l1_1, l3, l3_1;
+  guint8 avg, avg_1;
+  guint8 avg__1 = 0;
+  guint8 avg_s;
+  guint8 avg_sc;
+  guint8 best;
+  guint16 mov;
+  guint8 out;
+  guint8 l2, lp2;
+  guint8 l2_diff, lp2_diff;
+  guint8 min, max;
+  guint max_comb = self->max_comb;
+  guint motion_sense = self->motion_sense;
+  guint motion_threshold = self->motion_threshold;
+
+  for (Pos = 0; Pos < width; Pos++) {
+    l1 = L1[0];
+    l3 = L3[0];
+
+    if (Pos == width - 1) {
+      l1_1 = l1;
+      l3_1 = l3;
+    } else {
+      l1_1 = L1[1];
+      l3_1 = L3[1];
+    }
+
+    /* Average of L1 and L3 */
+    avg = (l1 + l3) / 2;
+
+    if (Pos == 0) {
+      avg__1 = avg;
+    }
+
+    /* Average of next L1 and next L3 */
+    avg_1 = (l1_1 + l3_1) / 2;
+
+    /* Calculate average of one pixel forward and previous */
+    avg_s = (avg__1 + avg_1) / 2;
+
+    /* Calculate average of center and surrounding pixels */
+    avg_sc = (avg + avg_s) / 2;
+
+    /* move forward */
+    avg__1 = avg;
+
+    /* Get best L2/L2P, i.e. least diff from above average */
+    l2 = L2[0];
+    lp2 = L2P[0];
+
+    l2_diff = ABS (l2 - avg_sc);
+
+    lp2_diff = ABS (lp2 - avg_sc);
+
+    if (l2_diff > lp2_diff)
+      best = lp2;
+    else
+      best = l2;
+
+    /* Clip this best L2/L2P by L1/L3 and allow to differ by GreedyMaxComb */
+    max = MAX (l1, l3);
+    min = MIN (l1, l3);
+
+    if (max < 256 - max_comb)
+      max += max_comb;
+    else
+      max = 255;
+
+    if (min > max_comb)
+      min -= max_comb;
+    else
+      min = 0;
+
+    out = CLAMP (best, min, max);
+
+    /* Do motion compensation for luma, i.e. how much
+     * the weave pixel differs */
+    mov = ABS (l2 - lp2);
+    if (mov > motion_threshold)
+      mov -= motion_threshold;
+    else
+      mov = 0;
+
+    mov = mov * motion_sense;
+    if (mov > 256)
+      mov = 256;
+
+    /* Weighted sum on clipped weave pixel and average */
+    out = (out * (256 - mov) + avg_sc * mov) / 256;
+
+    Dest[0] = out;
+
+    Dest += 1;
+    L1 += 1;
+    L2 += 1;
+    L3 += 1;
+    L2P += 1;
+  }
+}
+
+static void
+greedyh_scanline_C_planar_uv (GstDeinterlaceMethodGreedyH * self,
+    const guint8 * L1, const guint8 * L2, const guint8 * L3, const guint8 * L2P,
+    guint8 * Dest, gint width)
+{
+  gint Pos;
+  guint8 l1, l1_1, l3, l3_1;
+  guint8 avg, avg_1;
+  guint8 avg__1 = 0;
+  guint8 avg_s;
+  guint8 avg_sc;
+  guint8 best;
+  guint8 out;
+  guint8 l2, lp2;
+  guint8 l2_diff, lp2_diff;
+  guint8 min, max;
+  guint max_comb = self->max_comb;
+
+  for (Pos = 0; Pos < width; Pos++) {
+    l1 = L1[0];
+    l3 = L3[0];
+
+    if (Pos == width - 1) {
+      l1_1 = l1;
+      l3_1 = l3;
+    } else {
+      l1_1 = L1[1];
+      l3_1 = L3[1];
+    }
+
+    /* Average of L1 and L3 */
+    avg = (l1 + l3) / 2;
+
+    if (Pos == 0) {
+      avg__1 = avg;
+    }
+
+    /* Average of next L1 and next L3 */
+    avg_1 = (l1_1 + l3_1) / 2;
+
+    /* Calculate average of one pixel forward and previous */
+    avg_s = (avg__1 + avg_1) / 2;
+
+    /* Calculate average of center and surrounding pixels */
+    avg_sc = (avg + avg_s) / 2;
+
+    /* move forward */
+    avg__1 = avg;
+
+    /* Get best L2/L2P, i.e. least diff from above average */
+    l2 = L2[0];
+    lp2 = L2P[0];
+
+    l2_diff = ABS (l2 - avg_sc);
+
+    lp2_diff = ABS (lp2 - avg_sc);
+
+    if (l2_diff > lp2_diff)
+      best = lp2;
+    else
+      best = l2;
+
+    /* Clip this best L2/L2P by L1/L3 and allow to differ by GreedyMaxComb */
+    max = MAX (l1, l3);
+    min = MIN (l1, l3);
+
+    if (max < 256 - max_comb)
+      max += max_comb;
+    else
+      max = 255;
+
+    if (min > max_comb)
+      min -= max_comb;
+    else
+      min = 0;
+
+    out = CLAMP (best, min, max);
+
+    Dest[0] = out;
+
+    Dest += 1;
+    L1 += 1;
+    L2 += 1;
+    L3 += 1;
+    L2P += 1;
+  }
+}
+
+#ifdef BUILD_X86_ASM
+
+#define IS_MMXEXT
+#define SIMD_TYPE MMXEXT
+#define C_FUNCT_YUY2 greedyh_scanline_C_yuy2
+#define C_FUNCT_UYVY greedyh_scanline_C_uyvy
+#define C_FUNCT_PLANAR_Y greedyh_scanline_C_planar_y
+#define C_FUNCT_PLANAR_UV greedyh_scanline_C_planar_uv
+#define FUNCT_NAME_YUY2 greedyh_scanline_MMXEXT_yuy2
+#define FUNCT_NAME_UYVY greedyh_scanline_MMXEXT_uyvy
+#define FUNCT_NAME_PLANAR_Y greedyh_scanline_MMXEXT_planar_y
+#define FUNCT_NAME_PLANAR_UV greedyh_scanline_MMXEXT_planar_uv
+#include "greedyh.asm"
+#undef SIMD_TYPE
+#undef IS_MMXEXT
+#undef FUNCT_NAME_YUY2
+#undef FUNCT_NAME_UYVY
+#undef FUNCT_NAME_PLANAR_Y
+#undef FUNCT_NAME_PLANAR_UV
+
+#define IS_3DNOW
+#define SIMD_TYPE 3DNOW
+#define FUNCT_NAME_YUY2 greedyh_scanline_3DNOW_yuy2
+#define FUNCT_NAME_UYVY greedyh_scanline_3DNOW_uyvy
+#define FUNCT_NAME_PLANAR_Y greedyh_scanline_3DNOW_planar_y
+#define FUNCT_NAME_PLANAR_UV greedyh_scanline_3DNOW_planar_uv
+#include "greedyh.asm"
+#undef SIMD_TYPE
+#undef IS_3DNOW
+#undef FUNCT_NAME_YUY2
+#undef FUNCT_NAME_UYVY
+#undef FUNCT_NAME_PLANAR_Y
+#undef FUNCT_NAME_PLANAR_UV
+
+#define IS_MMX
+#define SIMD_TYPE MMX
+#define FUNCT_NAME_YUY2 greedyh_scanline_MMX_yuy2
+#define FUNCT_NAME_UYVY greedyh_scanline_MMX_uyvy
+#define FUNCT_NAME_PLANAR_Y greedyh_scanline_MMX_planar_y
+#define FUNCT_NAME_PLANAR_UV greedyh_scanline_MMX_planar_uv
+#include "greedyh.asm"
+#undef SIMD_TYPE
+#undef IS_MMX
+#undef FUNCT_NAME_YUY2
+#undef FUNCT_NAME_UYVY
+#undef FUNCT_NAME_PLANAR_Y
+#undef FUNCT_NAME_PLANAR_UV
+#undef C_FUNCT_YUY2
+#undef C_FUNCT_PLANAR_Y
+#undef C_FUNCT_PLANAR_UV
+
+#endif
+
+static void
+deinterlace_frame_di_greedyh_packed (GstDeinterlaceMethod * method,
+    const GstDeinterlaceField * history, guint history_count,
+    GstVideoFrame * outframe, int cur_field_idx)
+{
+  GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (method);
+  GstDeinterlaceMethodGreedyHClass *klass =
+      GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS (self);
+  gint InfoIsOdd = 0;
+  gint Line;
+  gint RowStride = GST_VIDEO_FRAME_COMP_STRIDE (outframe, 0);
+  gint FieldHeight = GST_VIDEO_FRAME_HEIGHT (outframe) / 2;
+  gint Pitch = RowStride * 2;
+  const guint8 *L1;             // ptr to Line1, of 3
+  const guint8 *L2;             // ptr to Line2, the weave line
+  const guint8 *L3;             // ptr to Line3
+  const guint8 *L2P;            // ptr to prev Line2
+  guint8 *Dest = GST_VIDEO_FRAME_COMP_DATA (outframe, 0);
+  ScanlineFunction scanline;
+
+  if (cur_field_idx + 2 > history_count || cur_field_idx < 1) {
+    GstDeinterlaceMethod *backup_method;
+
+    backup_method = g_object_new (gst_deinterlace_method_linear_get_type (),
+        NULL);
+
+    gst_deinterlace_method_setup (backup_method, method->vinfo);
+    gst_deinterlace_method_deinterlace_frame (backup_method,
+        history, history_count, outframe, cur_field_idx);
+
+    g_object_unref (backup_method);
+    return;
+  }
+
+  cur_field_idx += 2;
+
+  switch (GST_VIDEO_INFO_FORMAT (method->vinfo)) {
+    case GST_VIDEO_FORMAT_YUY2:
+    case GST_VIDEO_FORMAT_YVYU:
+      scanline = klass->scanline_yuy2;
+      break;
+    case GST_VIDEO_FORMAT_UYVY:
+      scanline = klass->scanline_uyvy;
+      break;
+    case GST_VIDEO_FORMAT_AYUV:
+      scanline = klass->scanline_ayuv;
+      break;
+    default:
+      g_assert_not_reached ();
+      return;
+  }
+
+  // copy first even line no matter what, and the first odd line if we're
+  // processing an EVEN field. (note diff from other deint rtns.)
+
+  if (history[cur_field_idx - 1].flags == PICTURE_INTERLACED_BOTTOM) {
+    InfoIsOdd = 1;
+
+    L1 = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 2].frame, 0);
+    if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM)
+      L1 += RowStride;
+
+    L2 = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 1].frame, 0);
+    if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM)
+      L2 += RowStride;
+
+    L3 = L1 + Pitch;
+    L2P = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 3].frame, 0);
+    if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM)
+      L2P += RowStride;
+
+    // copy first even line
+    memcpy (Dest, L1, RowStride);
+    Dest += RowStride;
+  } else {
+    InfoIsOdd = 0;
+    L1 = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 2].frame, 0);
+    if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM)
+      L1 += RowStride;
+
+    L2 = (guint8 *) GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx -
+            1].frame, 0) + Pitch;
+    if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM)
+      L2 += RowStride;
+
+    L3 = L1 + Pitch;
+    L2P =
+        (guint8 *) GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 3].frame,
+        0) + Pitch;
+    if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM)
+      L2P += RowStride;
+
+    // copy first even line
+    memcpy (Dest, L1, RowStride);
+    Dest += RowStride;
+    // then first odd line
+    memcpy (Dest, L1, RowStride);
+    Dest += RowStride;
+  }
+
+  for (Line = 0; Line < (FieldHeight - 1); ++Line) {
+    scanline (self, L1, L2, L3, L2P, Dest, RowStride);
+    Dest += RowStride;
+    memcpy (Dest, L3, RowStride);
+    Dest += RowStride;
+
+    L1 += Pitch;
+    L2 += Pitch;
+    L3 += Pitch;
+    L2P += Pitch;
+  }
+
+  if (InfoIsOdd) {
+    memcpy (Dest, L2, RowStride);
+  }
+}
+
+static void
+deinterlace_frame_di_greedyh_planar_plane (GstDeinterlaceMethodGreedyH * self,
+    const guint8 * L1, const guint8 * L2, const guint8 * L3, const guint8 * L2P,
+    guint8 * Dest, gint RowStride, gint FieldHeight, gint Pitch, gint InfoIsOdd,
+    ScanlineFunction scanline)
+{
+  gint Line;
+
+  // copy first even line no matter what, and the first odd line if we're
+  // processing an EVEN field. (note diff from other deint rtns.)
+
+  if (InfoIsOdd) {
+    // copy first even line
+    memcpy (Dest, L1, RowStride);
+    Dest += RowStride;
+  } else {
+    // copy first even line
+    memcpy (Dest, L1, RowStride);
+    Dest += RowStride;
+    // then first odd line
+    memcpy (Dest, L1, RowStride);
+    Dest += RowStride;
+  }
+
+  for (Line = 0; Line < (FieldHeight - 1); ++Line) {
+    scanline (self, L1, L2, L3, L2P, Dest, RowStride);
+    Dest += RowStride;
+    memcpy (Dest, L3, RowStride);
+    Dest += RowStride;
+
+    L1 += Pitch;
+    L2 += Pitch;
+    L3 += Pitch;
+    L2P += Pitch;
+  }
+
+  if (InfoIsOdd) {
+    memcpy (Dest, L2, RowStride);
+  }
+}
+
+static void
+deinterlace_frame_di_greedyh_planar (GstDeinterlaceMethod * method,
+    const GstDeinterlaceField * history, guint history_count,
+    GstVideoFrame * outframe, int cur_field_idx)
+{
+  GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (method);
+  GstDeinterlaceMethodGreedyHClass *klass =
+      GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS (self);
+  gint InfoIsOdd;
+  gint RowStride;
+  gint FieldHeight;
+  gint Pitch;
+  const guint8 *L1;             // ptr to Line1, of 3
+  const guint8 *L2;             // ptr to Line2, the weave line
+  const guint8 *L3;             // ptr to Line3
+  const guint8 *L2P;            // ptr to prev Line2
+  guint8 *Dest;
+  gint i;
+  ScanlineFunction scanline;
+
+  if (cur_field_idx + 2 > history_count || cur_field_idx < 1) {
+    GstDeinterlaceMethod *backup_method;
+
+    backup_method = g_object_new (gst_deinterlace_method_linear_get_type (),
+        NULL);
+
+    gst_deinterlace_method_setup (backup_method, method->vinfo);
+    gst_deinterlace_method_deinterlace_frame (backup_method,
+        history, history_count, outframe, cur_field_idx);
+
+    g_object_unref (backup_method);
+    return;
+  }
+
+  cur_field_idx += 2;
+
+  for (i = 0; i < 3; i++) {
+    InfoIsOdd = (history[cur_field_idx - 1].flags == PICTURE_INTERLACED_BOTTOM);
+    RowStride = GST_VIDEO_FRAME_COMP_STRIDE (outframe, i);
+    FieldHeight = GST_VIDEO_FRAME_COMP_HEIGHT (outframe, i) / 2;
+    Pitch = RowStride * 2;
+
+    if (i == 0)
+      scanline = klass->scanline_planar_y;
+    else
+      scanline = klass->scanline_planar_uv;
+
+    Dest = GST_VIDEO_FRAME_COMP_DATA (outframe, i);
+
+    L1 = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 2].frame, i);
+    if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM)
+      L1 += RowStride;
+
+    L2 = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 1].frame, i);
+    if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM)
+      L2 += RowStride;
+
+    L3 = L1 + Pitch;
+    L2P = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 3].frame, i);
+    if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM)
+      L2P += RowStride;
+
+    deinterlace_frame_di_greedyh_planar_plane (self, L1, L2, L3, L2P, Dest,
+        RowStride, FieldHeight, Pitch, InfoIsOdd, scanline);
+  }
+}
+
+G_DEFINE_TYPE (GstDeinterlaceMethodGreedyH, gst_deinterlace_method_greedy_h,
+    GST_TYPE_DEINTERLACE_METHOD);
+
+enum
+{
+  PROP_0,
+  PROP_MAX_COMB,
+  PROP_MOTION_THRESHOLD,
+  PROP_MOTION_SENSE
+};
+
+static void
+gst_deinterlace_method_greedy_h_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object);
+
+  switch (prop_id) {
+    case PROP_MAX_COMB:
+      self->max_comb = g_value_get_uint (value);
+      break;
+    case PROP_MOTION_THRESHOLD:
+      self->motion_threshold = g_value_get_uint (value);
+      break;
+    case PROP_MOTION_SENSE:
+      self->motion_sense = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+gst_deinterlace_method_greedy_h_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object);
+
+  switch (prop_id) {
+    case PROP_MAX_COMB:
+      g_value_set_uint (value, self->max_comb);
+      break;
+    case PROP_MOTION_THRESHOLD:
+      g_value_set_uint (value, self->motion_threshold);
+      break;
+    case PROP_MOTION_SENSE:
+      g_value_set_uint (value, self->motion_sense);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+gst_deinterlace_method_greedy_h_class_init (GstDeinterlaceMethodGreedyHClass *
+    klass)
+{
+  GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+#ifdef BUILD_X86_ASM
+  guint cpu_flags =
+      orc_target_get_default_flags (orc_target_get_by_name ("mmx"));
+#endif
+
+  gobject_class->set_property = gst_deinterlace_method_greedy_h_set_property;
+  gobject_class->get_property = gst_deinterlace_method_greedy_h_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_MAX_COMB,
+      g_param_spec_uint ("max-comb",
+          "Max comb",
+          "Max Comb", 0, 255, 5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
+  g_object_class_install_property (gobject_class, PROP_MOTION_THRESHOLD,
+      g_param_spec_uint ("motion-threshold",
+          "Motion Threshold",
+          "Motion Threshold",
+          0, 255, 25, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
+  g_object_class_install_property (gobject_class, PROP_MOTION_SENSE,
+      g_param_spec_uint ("motion-sense",
+          "Motion Sense",
+          "Motion Sense",
+          0, 255, 30, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
+  dim_class->fields_required = 4;
+  dim_class->name = "Motion Adaptive: Advanced Detection";
+  dim_class->nick = "greedyh";
+  dim_class->latency = 1;
+
+  dim_class->deinterlace_frame_yuy2 = deinterlace_frame_di_greedyh_packed;
+  dim_class->deinterlace_frame_yvyu = deinterlace_frame_di_greedyh_packed;
+  dim_class->deinterlace_frame_uyvy = deinterlace_frame_di_greedyh_packed;
+  dim_class->deinterlace_frame_ayuv = deinterlace_frame_di_greedyh_packed;
+  dim_class->deinterlace_frame_y444 = deinterlace_frame_di_greedyh_planar;
+  dim_class->deinterlace_frame_i420 = deinterlace_frame_di_greedyh_planar;
+  dim_class->deinterlace_frame_yv12 = deinterlace_frame_di_greedyh_planar;
+  dim_class->deinterlace_frame_y42b = deinterlace_frame_di_greedyh_planar;
+  dim_class->deinterlace_frame_y41b = deinterlace_frame_di_greedyh_planar;
+
+#ifdef BUILD_X86_ASM
+  if (cpu_flags & ORC_TARGET_MMX_MMXEXT) {
+    klass->scanline_yuy2 = greedyh_scanline_MMXEXT_yuy2;
+    klass->scanline_uyvy = greedyh_scanline_MMXEXT_uyvy;
+  } else if (cpu_flags & ORC_TARGET_MMX_3DNOW) {
+    klass->scanline_yuy2 = greedyh_scanline_3DNOW_yuy2;
+    klass->scanline_uyvy = greedyh_scanline_3DNOW_uyvy;
+  } else if (cpu_flags & ORC_TARGET_MMX_MMX) {
+    klass->scanline_yuy2 = greedyh_scanline_MMX_yuy2;
+    klass->scanline_uyvy = greedyh_scanline_MMX_uyvy;
+  } else {
+    klass->scanline_yuy2 = greedyh_scanline_C_yuy2;
+    klass->scanline_uyvy = greedyh_scanline_C_uyvy;
+  }
+#else
+  klass->scanline_yuy2 = greedyh_scanline_C_yuy2;
+  klass->scanline_uyvy = greedyh_scanline_C_uyvy;
+#endif
+  /* TODO: MMX implementation of these two */
+  klass->scanline_ayuv = greedyh_scanline_C_ayuv;
+  klass->scanline_planar_y = greedyh_scanline_C_planar_y;
+  klass->scanline_planar_uv = greedyh_scanline_C_planar_uv;
+}
+
+static void
+gst_deinterlace_method_greedy_h_init (GstDeinterlaceMethodGreedyH * self)
+{
+  self->max_comb = 5;
+  self->motion_threshold = 25;
+  self->motion_sense = 30;
+}
diff --git a/gst/deinterlace/tvtime/greedyhmacros.h b/gst/deinterlace/tvtime/greedyhmacros.h
new file mode 100644
index 0000000..cfeaff5
--- /dev/null
+++ b/gst/deinterlace/tvtime/greedyhmacros.h
@@ -0,0 +1,83 @@
+/*
+ * GStreamer
+ * Copyright (c) 2001 Tom Barry  All rights reserved.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Relicensed for GStreamer from GPL to LGPL with permit from Tom Barry.
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
+ */
+
+// Define a few macros for CPU dependent instructions. 
+// I suspect I don't really understand how the C macro preprocessor works but
+// this seems to get the job done.          // TRB 7/01
+
+// BEFORE USING THESE YOU MUST SET:
+
+// #define SIMD_TYPE MMXEXT            (or MMX or 3DNOW)
+
+// some macros for pavgb instruction
+//      V_PAVGB(mmr1, mmr2, mmr work register, smask) mmr2 may = mmrw if you can trash it
+
+#define V_PAVGB_MMX(mmr1, mmr2, mmrw, smask) \
+	"movq    "mmr2",  "mmrw"\n\t"            \
+	"pand    "smask", "mmrw"\n\t"            \
+	"psrlw   $1,      "mmrw"\n\t"            \
+	"pand    "smask", "mmr1"\n\t"            \
+	"psrlw   $1,      "mmr1"\n\t"            \
+	"paddusb "mmrw",  "mmr1"\n\t"
+#define V_PAVGB_MMXEXT(mmr1, mmr2, mmrw, smask)      "pavgb   "mmr2", "mmr1"\n\t"
+#define V_PAVGB_3DNOW(mmr1, mmr2, mmrw, smask)    "pavgusb "mmr2", "mmr1"\n\t"
+#define V_PAVGB(mmr1, mmr2, mmrw, smask)          V_PAVGB2(mmr1, mmr2, mmrw, smask, SIMD_TYPE) 
+#define V_PAVGB2(mmr1, mmr2, mmrw, smask, simd_type) V_PAVGB3(mmr1, mmr2, mmrw, smask, simd_type) 
+#define V_PAVGB3(mmr1, mmr2, mmrw, smask, simd_type) V_PAVGB_##simd_type(mmr1, mmr2, mmrw, smask) 
+
+// some macros for pmaxub instruction
+#define V_PMAXUB_MMX(mmr1, mmr2) \
+    "psubusb "mmr2", "mmr1"\n\t" \
+    "paddusb "mmr2", "mmr1"\n\t"
+#define V_PMAXUB_MMXEXT(mmr1, mmr2)      "pmaxub "mmr2", "mmr1"\n\t"
+#define V_PMAXUB_3DNOW(mmr1, mmr2)    V_PMAXUB_MMX(mmr1, mmr2)  // use MMX version
+#define V_PMAXUB(mmr1, mmr2)          V_PMAXUB2(mmr1, mmr2, SIMD_TYPE) 
+#define V_PMAXUB2(mmr1, mmr2, simd_type) V_PMAXUB3(mmr1, mmr2, simd_type) 
+#define V_PMAXUB3(mmr1, mmr2, simd_type) V_PMAXUB_##simd_type(mmr1, mmr2) 
+
+// some macros for pminub instruction
+//      V_PMINUB(mmr1, mmr2, mmr work register)     mmr2 may NOT = mmrw
+#define V_PMINUB_MMX(mmr1, mmr2, mmrw) \
+    "pcmpeqb "mmrw", "mmrw"\n\t"       \
+    "psubusb "mmr2", "mmrw"\n\t"       \
+    "paddusb "mmrw", "mmr1"\n\t"       \
+    "psubusb "mmrw", "mmr1"\n\t"
+#define V_PMINUB_MMXEXT(mmr1, mmr2, mmrw)      "pminub "mmr2", "mmr1"\n\t"
+#define V_PMINUB_3DNOW(mmr1, mmr2, mmrw)    V_PMINUB_MMX(mmr1, mmr2, mmrw)  // use MMX version
+#define V_PMINUB(mmr1, mmr2, mmrw)          V_PMINUB2(mmr1, mmr2, mmrw, SIMD_TYPE) 
+#define V_PMINUB2(mmr1, mmr2, mmrw, simd_type) V_PMINUB3(mmr1, mmr2, mmrw, simd_type) 
+#define V_PMINUB3(mmr1, mmr2, mmrw, simd_type) V_PMINUB_##simd_type(mmr1, mmr2, mmrw) 
+
+// some macros for movntq instruction
+//      V_MOVNTQ(mmr1, mmr2) 
+#define V_MOVNTQ_MMX(mmr1, mmr2)      "movq   "mmr2", "mmr1"\n\t"
+#define V_MOVNTQ_3DNOW(mmr1, mmr2)    "movq   "mmr2", "mmr1"\n\t"
+#define V_MOVNTQ_MMXEXT(mmr1, mmr2)      "movntq "mmr2", "mmr1"\n\t"
+#define V_MOVNTQ(mmr1, mmr2)          V_MOVNTQ2(mmr1, mmr2, SIMD_TYPE) 
+#define V_MOVNTQ2(mmr1, mmr2, simd_type) V_MOVNTQ3(mmr1, mmr2, simd_type) 
+#define V_MOVNTQ3(mmr1, mmr2, simd_type) V_MOVNTQ_##simd_type(mmr1, mmr2)
+
+// end of macros
+
diff --git a/gst/deinterlace/tvtime/linear.c b/gst/deinterlace/tvtime/linear.c
new file mode 100644
index 0000000..9c45353
--- /dev/null
+++ b/gst/deinterlace/tvtime/linear.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2002 Billy Biggs <vektor@dumbterm.net>.
+ * Copyright (C) 2008,2010 Sebastian Dröge <slomo@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstdeinterlacemethod.h"
+#include <string.h>
+#ifdef HAVE_ORC
+#include <orc/orc.h>
+#endif
+#include "tvtime.h"
+
+#define GST_TYPE_DEINTERLACE_METHOD_LINEAR	(gst_deinterlace_method_linear_get_type ())
+#define GST_IS_DEINTERLACE_METHOD_LINEAR(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR))
+#define GST_IS_DEINTERLACE_METHOD_LINEAR_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_LINEAR))
+#define GST_DEINTERLACE_METHOD_LINEAR_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR, GstDeinterlaceMethodLinearClass))
+#define GST_DEINTERLACE_METHOD_LINEAR(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR, GstDeinterlaceMethodLinear))
+#define GST_DEINTERLACE_METHOD_LINEAR_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_LINEAR, GstDeinterlaceMethodLinearClass))
+#define GST_DEINTERLACE_METHOD_LINEAR_CAST(obj)	((GstDeinterlaceMethodLinear*)(obj))
+
+GType gst_deinterlace_method_linear_get_type (void);
+
+typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodLinear;
+typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodLinearClass;
+
+static void
+deinterlace_scanline_linear_c (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const guint8 * s1, const guint8 * s2, gint size)
+{
+  deinterlace_line_linear (out, s1, s2, size);
+}
+
+static void
+deinterlace_scanline_linear_packed_c (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  deinterlace_scanline_linear_c (self, out, scanlines->t0, scanlines->b0, size);
+}
+
+static void
+deinterlace_scanline_linear_planar_y_c (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  deinterlace_scanline_linear_c (self, out, scanlines->t0, scanlines->b0, size);
+}
+
+static void
+deinterlace_scanline_linear_planar_u_c (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  deinterlace_scanline_linear_c (self, out, scanlines->t0, scanlines->b0, size);
+}
+
+static void
+deinterlace_scanline_linear_planar_v_c (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  deinterlace_scanline_linear_c (self, out, scanlines->t0, scanlines->b0, size);
+}
+
+G_DEFINE_TYPE (GstDeinterlaceMethodLinear, gst_deinterlace_method_linear,
+    GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
+
+static void
+gst_deinterlace_method_linear_class_init (GstDeinterlaceMethodLinearClass *
+    klass)
+{
+  GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
+  GstDeinterlaceSimpleMethodClass *dism_class =
+      (GstDeinterlaceSimpleMethodClass *) klass;
+
+  dim_class->fields_required = 1;
+  dim_class->name = "Television: Full resolution";
+  dim_class->nick = "linear";
+  dim_class->latency = 0;
+
+  dism_class->interpolate_scanline_yuy2 = deinterlace_scanline_linear_packed_c;
+  dism_class->interpolate_scanline_yvyu = deinterlace_scanline_linear_packed_c;
+  dism_class->interpolate_scanline_uyvy = deinterlace_scanline_linear_packed_c;
+  dism_class->interpolate_scanline_ayuv = deinterlace_scanline_linear_packed_c;
+  dism_class->interpolate_scanline_argb = deinterlace_scanline_linear_packed_c;
+  dism_class->interpolate_scanline_abgr = deinterlace_scanline_linear_packed_c;
+  dism_class->interpolate_scanline_rgba = deinterlace_scanline_linear_packed_c;
+  dism_class->interpolate_scanline_bgra = deinterlace_scanline_linear_packed_c;
+  dism_class->interpolate_scanline_rgb = deinterlace_scanline_linear_packed_c;
+  dism_class->interpolate_scanline_bgr = deinterlace_scanline_linear_packed_c;
+  dism_class->interpolate_scanline_nv12 = deinterlace_scanline_linear_packed_c;
+  dism_class->interpolate_scanline_nv21 = deinterlace_scanline_linear_packed_c;
+  dism_class->interpolate_scanline_planar_y =
+      deinterlace_scanline_linear_planar_y_c;
+  dism_class->interpolate_scanline_planar_u =
+      deinterlace_scanline_linear_planar_u_c;
+  dism_class->interpolate_scanline_planar_v =
+      deinterlace_scanline_linear_planar_v_c;
+
+}
+
+static void
+gst_deinterlace_method_linear_init (GstDeinterlaceMethodLinear * self)
+{
+}
diff --git a/gst/deinterlace/tvtime/linearblend.c b/gst/deinterlace/tvtime/linearblend.c
new file mode 100644
index 0000000..c0e4a0b
--- /dev/null
+++ b/gst/deinterlace/tvtime/linearblend.c
@@ -0,0 +1,217 @@
+/*
+ * Linear blend deinterlacing plugin.  The idea for this algorithm came
+ * from the linear blend deinterlacer which originated in the mplayer
+ * sources.
+ *
+ * Copyright (C) 2002 Billy Biggs <vektor@dumbterm.net>.
+ * Copyright (C) 2008,2010 Sebastian Dröge <slomo@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstdeinterlacemethod.h"
+#include <string.h>
+#ifdef HAVE_ORC
+#include <orc/orc.h>
+#endif
+#include "tvtime.h"
+
+#define GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND	(gst_deinterlace_method_linear_blend_get_type ())
+#define GST_IS_DEINTERLACE_METHOD_LINEAR_BLEND(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND))
+#define GST_IS_DEINTERLACE_METHOD_LINEAR_BLEND_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND))
+#define GST_DEINTERLACE_METHOD_LINEAR_BLEND_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND, GstDeinterlaceMethodLinearBlendClass))
+#define GST_DEINTERLACE_METHOD_LINEAR_BLEND(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND, GstDeinterlaceMethodLinearBlend))
+#define GST_DEINTERLACE_METHOD_LINEAR_BLEND_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND, GstDeinterlaceMethodLinearBlendClass))
+#define GST_DEINTERLACE_METHOD_LINEAR_BLEND_CAST(obj)	((GstDeinterlaceMethodLinearBlend*)(obj))
+
+GType gst_deinterlace_method_linear_blend_get_type (void);
+
+typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodLinearBlend;
+typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodLinearBlendClass;
+
+static inline void
+deinterlace_scanline_linear_blend_c (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const guint8 * t0, const guint8 * b0, const guint8 * m1,
+    gint size)
+{
+  if (m1 == NULL) {
+    deinterlace_line_linear (out, t0, b0, size);
+  } else {
+    deinterlace_line_linear_blend (out, t0, b0, m1, size);
+  }
+}
+
+static void
+deinterlace_scanline_linear_blend_packed_c (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  deinterlace_scanline_linear_blend_c (self, out, scanlines->t0, scanlines->b0,
+      scanlines->m1, size);
+}
+
+static void
+deinterlace_scanline_linear_blend_planar_y_c (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  deinterlace_scanline_linear_blend_c (self, out, scanlines->t0, scanlines->b0,
+      scanlines->m1, size);
+}
+
+static void
+deinterlace_scanline_linear_blend_planar_u_c (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  deinterlace_scanline_linear_blend_c (self, out, scanlines->t0, scanlines->b0,
+      scanlines->m1, size);
+}
+
+static void
+deinterlace_scanline_linear_blend_planar_v_c (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  deinterlace_scanline_linear_blend_c (self, out, scanlines->t0, scanlines->b0,
+      scanlines->m1, size);
+}
+
+static inline void
+deinterlace_scanline_linear_blend2_c (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const guint8 * m0, const guint8 * t1, const guint8 * b1,
+    gint size)
+{
+  if (t1 == NULL) {
+    memcpy (out, m0, size);
+  } else {
+    deinterlace_line_linear_blend (out, t1, b1, m0, size);
+  }
+}
+
+static void
+deinterlace_scanline_linear_blend2_packed_c (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  deinterlace_scanline_linear_blend2_c (self, out, scanlines->m0, scanlines->t1,
+      scanlines->b1, size);
+}
+
+static void
+deinterlace_scanline_linear_blend2_planar_y_c (GstDeinterlaceSimpleMethod *
+    self, guint8 * out, const GstDeinterlaceScanlineData * scanlines,
+    guint size)
+{
+  deinterlace_scanline_linear_blend2_c (self, out, scanlines->m0, scanlines->t1,
+      scanlines->b1, size);
+}
+
+static void
+deinterlace_scanline_linear_blend2_planar_u_c (GstDeinterlaceSimpleMethod *
+    self, guint8 * out, const GstDeinterlaceScanlineData * scanlines,
+    guint size)
+{
+  deinterlace_scanline_linear_blend2_c (self, out, scanlines->m0, scanlines->t1,
+      scanlines->b1, size);
+}
+
+static void
+deinterlace_scanline_linear_blend2_planar_v_c (GstDeinterlaceSimpleMethod *
+    self, guint8 * out, const GstDeinterlaceScanlineData * scanlines,
+    guint size)
+{
+  deinterlace_scanline_linear_blend2_c (self, out, scanlines->m0, scanlines->t1,
+      scanlines->b1, size);
+}
+
+G_DEFINE_TYPE (GstDeinterlaceMethodLinearBlend,
+    gst_deinterlace_method_linear_blend, GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
+
+static void
+    gst_deinterlace_method_linear_blend_class_init
+    (GstDeinterlaceMethodLinearBlendClass * klass)
+{
+  GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
+  GstDeinterlaceSimpleMethodClass *dism_class =
+      (GstDeinterlaceSimpleMethodClass *) klass;
+
+  dim_class->fields_required = 2;
+  dim_class->name = "Blur: Temporal";
+  dim_class->nick = "linearblend";
+  dim_class->latency = 1;
+
+  dism_class->interpolate_scanline_yuy2 =
+      deinterlace_scanline_linear_blend_packed_c;
+  dism_class->interpolate_scanline_yvyu =
+      deinterlace_scanline_linear_blend_packed_c;
+  dism_class->interpolate_scanline_uyvy =
+      deinterlace_scanline_linear_blend_packed_c;
+  dism_class->interpolate_scanline_ayuv =
+      deinterlace_scanline_linear_blend_packed_c;
+  dism_class->interpolate_scanline_argb =
+      deinterlace_scanline_linear_blend_packed_c;
+  dism_class->interpolate_scanline_rgba =
+      deinterlace_scanline_linear_blend_packed_c;
+  dism_class->interpolate_scanline_abgr =
+      deinterlace_scanline_linear_blend_packed_c;
+  dism_class->interpolate_scanline_bgra =
+      deinterlace_scanline_linear_blend_packed_c;
+  dism_class->interpolate_scanline_rgb =
+      deinterlace_scanline_linear_blend_packed_c;
+  dism_class->interpolate_scanline_bgr =
+      deinterlace_scanline_linear_blend_packed_c;
+  dism_class->interpolate_scanline_nv12 =
+      deinterlace_scanline_linear_blend_packed_c;
+  dism_class->interpolate_scanline_nv21 =
+      deinterlace_scanline_linear_blend_packed_c;
+
+  dism_class->interpolate_scanline_planar_y =
+      deinterlace_scanline_linear_blend_planar_y_c;
+  dism_class->interpolate_scanline_planar_u =
+      deinterlace_scanline_linear_blend_planar_u_c;
+  dism_class->interpolate_scanline_planar_v =
+      deinterlace_scanline_linear_blend_planar_v_c;
+
+  dism_class->copy_scanline_yuy2 = deinterlace_scanline_linear_blend2_packed_c;
+  dism_class->copy_scanline_yvyu = deinterlace_scanline_linear_blend2_packed_c;
+  dism_class->copy_scanline_uyvy = deinterlace_scanline_linear_blend2_packed_c;
+  dism_class->copy_scanline_ayuv = deinterlace_scanline_linear_blend2_packed_c;
+  dism_class->copy_scanline_argb = deinterlace_scanline_linear_blend2_packed_c;
+  dism_class->copy_scanline_abgr = deinterlace_scanline_linear_blend2_packed_c;
+  dism_class->copy_scanline_rgba = deinterlace_scanline_linear_blend2_packed_c;
+  dism_class->copy_scanline_bgra = deinterlace_scanline_linear_blend2_packed_c;
+  dism_class->copy_scanline_rgb = deinterlace_scanline_linear_blend2_packed_c;
+  dism_class->copy_scanline_bgr = deinterlace_scanline_linear_blend2_packed_c;
+
+  dism_class->copy_scanline_planar_y =
+      deinterlace_scanline_linear_blend2_planar_y_c;
+  dism_class->copy_scanline_planar_u =
+      deinterlace_scanline_linear_blend2_planar_u_c;
+  dism_class->copy_scanline_planar_v =
+      deinterlace_scanline_linear_blend2_planar_v_c;
+
+}
+
+static void
+gst_deinterlace_method_linear_blend_init (GstDeinterlaceMethodLinearBlend *
+    self)
+{
+}
diff --git a/gst/deinterlace/tvtime/mmx.h b/gst/deinterlace/tvtime/mmx.h
new file mode 100644
index 0000000..b0e582b
--- /dev/null
+++ b/gst/deinterlace/tvtime/mmx.h
@@ -0,0 +1,723 @@
+/*	mmx.h
+
+	MultiMedia eXtensions GCC interface library for IA32.
+
+	To use this library, simply include this header file
+	and compile with GCC.  You MUST have inlining enabled
+	in order for mmx_ok() to work; this can be done by
+	simply using -O on the GCC command line.
+
+	Compiling with -DMMX_TRACE will cause detailed trace
+	output to be sent to stderr for each mmx operation.
+	This adds lots of code, and obviously slows execution to
+	a crawl, but can be very useful for debugging.
+
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
+	EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+	LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR ANY PARTICULAR PURPOSE.
+
+	1997-98 by H. Dietz and R. Fisher
+
+ History:
+	97-98*	R.Fisher	Early versions
+	980501	R.Fisher	Original Release
+	980611*	H.Dietz		Rewrite, correctly implementing inlines, and
+		R.Fisher	 including direct register accesses.
+	980616	R.Fisher	Release of 980611 as 980616.
+	980714	R.Fisher	Minor corrections to Makefile, etc.
+	980715	R.Fisher	mmx_ok() now prevents optimizer from using
+				 clobbered values.
+				mmx_ok() now checks if cpuid instruction is
+				 available before trying to use it.
+	980726*	R.Fisher	mm_support() searches for AMD 3DNow, Cyrix
+				 Extended MMX, and standard MMX.  It returns a
+				 value which is positive if any of these are
+				 supported, and can be masked with constants to
+				 see which.  mmx_ok() is now a call to this
+	980726*	R.Fisher	Added i2r support for shift functions
+	980919	R.Fisher	Fixed AMD extended feature recognition bug.
+	980921	R.Fisher	Added definition/check for _MMX_H.
+				Added "float s[2]" to mmx_t for use with
+				  3DNow and EMMX.  So same mmx_t can be used.
+	981013	R.Fisher	Fixed cpuid function 1 bug (looked at wrong reg)
+				Fixed psllq_i2r error in mmxtest.c
+
+	* Unreleased (internal or interim) versions
+
+ Notes:
+	It appears that the latest gas has the pand problem fixed, therefore
+	  I'll undefine BROKEN_PAND by default.
+	String compares may be quicker than the multiple test/jumps in vendor
+	  test sequence in mmx_ok(), but I'm not concerned with that right now.
+
+ Acknowledgments:
+	Jussi Laako for pointing out the errors ultimately found to be
+	  connected to the failure to notify the optimizer of clobbered values.
+	Roger Hardiman for reminding us that CPUID isn't everywhere, and that
+	  someone may actually try to use this on a machine without CPUID.
+	  Also for suggesting code for checking this.
+	Robert Dale for pointing out the AMD recognition bug.
+	Jimmy Mayfield and Carl Witty for pointing out the Intel recognition
+	  bug.
+	Carl Witty for pointing out the psllq_i2r test bug.
+*/
+
+#ifndef _MMX_H
+#define _MMX_H
+
+/*#define MMX_TRACE */
+
+/*	Warning:  at this writing, the version of GAS packaged
+	with most Linux distributions does not handle the
+	parallel AND operation mnemonic correctly.  If the
+	symbol BROKEN_PAND is defined, a slower alternative
+	coding will be used.  If execution of mmxtest results
+	in an illegal instruction fault, define this symbol.
+*/
+#undef	BROKEN_PAND
+
+
+/*	The type of an value that fits in an MMX register
+	(note that long long constant values MUST be suffixed
+	 by LL and unsigned long long values by ULL, lest
+	 they be truncated by the compiler)
+*/
+typedef	union {
+	long long		q;	/* Quadword (64-bit) value */
+	unsigned long long	uq;	/* Unsigned Quadword */
+	int			d[2];	/* 2 Doubleword (32-bit) values */
+	unsigned int		ud[2];	/* 2 Unsigned Doubleword */
+	short			w[4];	/* 4 Word (16-bit) values */
+	unsigned short		uw[4];	/* 4 Unsigned Word */
+	char			b[8];	/* 8 Byte (8-bit) values */
+	unsigned char		ub[8];	/* 8 Unsigned Byte */
+	float			s[2];	/* Single-precision (32-bit) value */
+} mmx_t;
+
+
+/*	Function to test if multimedia instructions are supported...
+*/
+static inline int
+mm_support(void)
+{
+	/* Returns 1 if MMX instructions are supported,
+	   3 if Cyrix MMX and Extended MMX instructions are supported
+	   5 if AMD MMX and 3DNow! instructions are supported
+	   0 if hardware does not support any of these
+	*/
+	register int rval = 0;
+
+	__asm__ __volatile__ (
+		/* See if CPUID instruction is supported ... */
+		/* ... Get copies of EFLAGS into eax and ecx */
+		"pushf\n\t"
+		"popl %%eax\n\t"
+		"movl %%eax, %%ecx\n\t"
+
+		/* ... Toggle the ID bit in one copy and store */
+		/*     to the EFLAGS reg */
+		"xorl $0x200000, %%eax\n\t"
+		"push %%eax\n\t"
+		"popf\n\t"
+
+		/* ... Get the (hopefully modified) EFLAGS */
+		"pushf\n\t"
+		"popl %%eax\n\t"
+
+		/* ... Compare and test result */
+		"xorl %%eax, %%ecx\n\t"
+		"testl $0x200000, %%ecx\n\t"
+		"jz NotSupported1\n\t"		/* Nothing supported */
+
+
+		/* Get standard CPUID information, and
+		       go to a specific vendor section */
+		"movl $0, %%eax\n\t"
+		"cpuid\n\t"
+
+		/* Check for Intel */
+		"cmpl $0x756e6547, %%ebx\n\t"
+		"jne TryAMD\n\t"
+		"cmpl $0x49656e69, %%edx\n\t"
+		"jne TryAMD\n\t"
+		"cmpl $0x6c65746e, %%ecx\n"
+		"jne TryAMD\n\t"
+		"jmp Intel\n\t"
+
+		/* Check for AMD */
+		"\nTryAMD:\n\t"
+		"cmpl $0x68747541, %%ebx\n\t"
+		"jne TryCyrix\n\t"
+		"cmpl $0x69746e65, %%edx\n\t"
+		"jne TryCyrix\n\t"
+		"cmpl $0x444d4163, %%ecx\n"
+		"jne TryCyrix\n\t"
+		"jmp AMD\n\t"
+
+		/* Check for Cyrix */
+		"\nTryCyrix:\n\t"
+		"cmpl $0x69727943, %%ebx\n\t"
+		"jne NotSupported2\n\t"
+		"cmpl $0x736e4978, %%edx\n\t"
+		"jne NotSupported3\n\t"
+		"cmpl $0x64616574, %%ecx\n\t"
+		"jne NotSupported4\n\t"
+		/* Drop through to Cyrix... */
+
+
+		/* Cyrix Section */
+		/* See if extended CPUID is supported */
+		"movl $0x80000000, %%eax\n\t"
+		"cpuid\n\t"
+		"cmpl $0x80000000, %%eax\n\t"
+		"jl MMXtest\n\t"	/* Try standard CPUID instead */
+
+		/* Extended CPUID supported, so get extended features */
+		"movl $0x80000001, %%eax\n\t"
+		"cpuid\n\t"
+		"testl $0x00800000, %%eax\n\t"	/* Test for MMX */
+		"jz NotSupported5\n\t"		/* MMX not supported */
+		"testl $0x01000000, %%eax\n\t"	/* Test for Ext'd MMX */
+		"jnz EMMXSupported\n\t"
+		"movl $1, %0\n\n\t"		/* MMX Supported */
+		"jmp Return\n\n"
+		"EMMXSupported:\n\t"
+		"movl $3, %0\n\n\t"		/* EMMX and MMX Supported */
+		"jmp Return\n\t"
+
+
+		/* AMD Section */
+		"AMD:\n\t"
+
+		/* See if extended CPUID is supported */
+		"movl $0x80000000, %%eax\n\t"
+		"cpuid\n\t"
+		"cmpl $0x80000000, %%eax\n\t"
+		"jl MMXtest\n\t"	/* Try standard CPUID instead */
+
+		/* Extended CPUID supported, so get extended features */
+		"movl $0x80000001, %%eax\n\t"
+		"cpuid\n\t"
+		"testl $0x00800000, %%edx\n\t"	/* Test for MMX */
+		"jz NotSupported6\n\t"		/* MMX not supported */
+		"testl $0x80000000, %%edx\n\t"	/* Test for 3DNow! */
+		"jnz ThreeDNowSupported\n\t"
+		"movl $1, %0\n\n\t"		/* MMX Supported */
+		"jmp Return\n\n"
+		"ThreeDNowSupported:\n\t"
+		"movl $5, %0\n\n\t"		/* 3DNow! and MMX Supported */
+		"jmp Return\n\t"
+
+
+		/* Intel Section */
+		"Intel:\n\t"
+
+		/* Check for MMX */
+		"MMXtest:\n\t"
+		"movl $1, %%eax\n\t"
+		"cpuid\n\t"
+		"testl $0x00800000, %%edx\n\t"	/* Test for MMX */
+		"jz NotSupported7\n\t"		/* MMX Not supported */
+		"movl $1, %0\n\n\t"		/* MMX Supported */
+		"jmp Return\n\t"
+
+		/* Nothing supported */
+		"\nNotSupported1:\n\t"
+		"#movl $101, %0\n\n\t"
+		"\nNotSupported2:\n\t"
+		"#movl $102, %0\n\n\t"
+		"\nNotSupported3:\n\t"
+		"#movl $103, %0\n\n\t"
+		"\nNotSupported4:\n\t"
+		"#movl $104, %0\n\n\t"
+		"\nNotSupported5:\n\t"
+		"#movl $105, %0\n\n\t"
+		"\nNotSupported6:\n\t"
+		"#movl $106, %0\n\n\t"
+		"\nNotSupported7:\n\t"
+		"#movl $107, %0\n\n\t"
+		"movl $0, %0\n\n\t"
+
+		"Return:\n\t"
+		: "=a" (rval)
+		: /* no input */
+		: "eax", "ebx", "ecx", "edx"
+	);
+
+	/* Return */
+	return(rval);
+}
+
+/*	Function to test if mmx instructions are supported...
+*/
+static inline int
+mmx_ok(void)
+{
+	/* Returns 1 if MMX instructions are supported, 0 otherwise */
+	return ( mm_support() & 0x1 );
+}
+
+
+/*	Helper functions for the instruction macros that follow...
+	(note that memory-to-register, m2r, instructions are nearly
+	 as efficient as register-to-register, r2r, instructions;
+	 however, memory-to-memory instructions are really simulated
+	 as a convenience, and are only 1/3 as efficient)
+*/
+#ifdef	MMX_TRACE
+
+/*	Include the stuff for printing a trace to stderr...
+*/
+
+#include <stdio.h>
+
+#define	mmx_i2r(op, imm, reg) \
+	{ \
+		mmx_t mmx_trace; \
+		mmx_trace = (imm); \
+		fprintf(stderr, #op "_i2r(" #imm "=0x%016llx, ", mmx_trace.q); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #reg "=0x%016llx) => ", mmx_trace.q); \
+		__asm__ __volatile__ (#op " %0, %%" #reg \
+				      : /* nothing */ \
+				      : "X" (imm)); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #reg "=0x%016llx\n", mmx_trace.q); \
+	}
+
+#define	mmx_m2r(op, mem, reg) \
+	{ \
+		mmx_t mmx_trace; \
+		mmx_trace = (mem); \
+		fprintf(stderr, #op "_m2r(" #mem "=0x%016llx, ", mmx_trace.q); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #reg "=0x%016llx) => ", mmx_trace.q); \
+		__asm__ __volatile__ (#op " %0, %%" #reg \
+				      : /* nothing */ \
+				      : "X" (mem)); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #reg "=0x%016llx\n", mmx_trace.q); \
+	}
+
+#define	mmx_r2m(op, reg, mem) \
+	{ \
+		mmx_t mmx_trace; \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #op "_r2m(" #reg "=0x%016llx, ", mmx_trace.q); \
+		mmx_trace = (mem); \
+		fprintf(stderr, #mem "=0x%016llx) => ", mmx_trace.q); \
+		__asm__ __volatile__ (#op " %%" #reg ", %0" \
+				      : "=X" (mem) \
+				      : /* nothing */ ); \
+		mmx_trace = (mem); \
+		fprintf(stderr, #mem "=0x%016llx\n", mmx_trace.q); \
+	}
+
+#define	mmx_r2r(op, regs, regd) \
+	{ \
+		mmx_t mmx_trace; \
+		__asm__ __volatile__ ("movq %%" #regs ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #op "_r2r(" #regs "=0x%016llx, ", mmx_trace.q); \
+		__asm__ __volatile__ ("movq %%" #regd ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #regd "=0x%016llx) => ", mmx_trace.q); \
+		__asm__ __volatile__ (#op " %" #regs ", %" #regd); \
+		__asm__ __volatile__ ("movq %%" #regd ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #regd "=0x%016llx\n", mmx_trace.q); \
+	}
+
+#define	mmx_m2m(op, mems, memd) \
+	{ \
+		mmx_t mmx_trace; \
+		mmx_trace = (mems); \
+		fprintf(stderr, #op "_m2m(" #mems "=0x%016llx, ", mmx_trace.q); \
+		mmx_trace = (memd); \
+		fprintf(stderr, #memd "=0x%016llx) => ", mmx_trace.q); \
+		__asm__ __volatile__ ("movq %0, %%mm0\n\t" \
+				      #op " %1, %%mm0\n\t" \
+				      "movq %%mm0, %0" \
+				      : "=X" (memd) \
+				      : "X" (mems)); \
+		mmx_trace = (memd); \
+		fprintf(stderr, #memd "=0x%016llx\n", mmx_trace.q); \
+	}
+
+#else
+
+/*	These macros are a lot simpler without the tracing...
+*/
+
+#define	mmx_i2r(op, imm, reg) \
+	__asm__ __volatile__ (#op " $" #imm ", %%" #reg \
+			      : /* nothing */ \
+			      : /* nothing */);
+
+#define	mmx_m2r(op, mem, reg) \
+	__asm__ __volatile__ (#op " %0, %%" #reg \
+			      : /* nothing */ \
+			      : "m" (mem))
+
+#define	mmx_r2m(op, reg, mem) \
+	__asm__ __volatile__ (#op " %%" #reg ", %0" \
+			      : "=m" (mem) \
+			      : /* nothing */ )
+
+#define	mmx_r2r(op, regs, regd) \
+	__asm__ __volatile__ (#op " %" #regs ", %" #regd)
+
+#define	mmx_m2m(op, mems, memd) \
+	__asm__ __volatile__ ("movq %0, %%mm0\n\t" \
+			      #op " %1, %%mm0\n\t" \
+			      "movq %%mm0, %0" \
+			      : "=m" (memd) \
+			      : "m" (mems))
+
+#endif
+
+
+/*	1x64 MOVe Quadword
+	(this is both a load and a store...
+	 in fact, it is the only way to store)
+*/
+#define	movq_m2r(var, reg)	mmx_m2r(movq, var, reg)
+#define	movq_r2m(reg, var)	mmx_r2m(movq, reg, var)
+#define	movq_r2r(regs, regd)	mmx_r2r(movq, regs, regd)
+#define	movq(vars, vard) \
+	__asm__ __volatile__ ("movq %1, %%mm0\n\t" \
+			      "movq %%mm0, %0" \
+			      : "=X" (vard) \
+			      : "X" (vars))
+
+
+/*	1x32 MOVe Doubleword
+	(like movq, this is both load and store...
+	 but is most useful for moving things between
+	 mmx registers and ordinary registers)
+*/
+#define	movd_m2r(var, reg)	mmx_m2r(movd, var, reg)
+#define	movd_r2m(reg, var)	mmx_r2m(movd, reg, var)
+#define	movd_r2r(regs, regd)	mmx_r2r(movd, regs, regd)
+#define	movd(vars, vard) \
+	__asm__ __volatile__ ("movd %1, %%mm0\n\t" \
+			      "movd %%mm0, %0" \
+			      : "=X" (vard) \
+			      : "X" (vars))
+
+
+/*	2x32, 4x16, and 8x8 Parallel ADDs
+*/
+#define	paddd_m2r(var, reg)	mmx_m2r(paddd, var, reg)
+#define	paddd_r2r(regs, regd)	mmx_r2r(paddd, regs, regd)
+#define	paddd(vars, vard)	mmx_m2m(paddd, vars, vard)
+
+#define	paddw_m2r(var, reg)	mmx_m2r(paddw, var, reg)
+#define	paddw_r2r(regs, regd)	mmx_r2r(paddw, regs, regd)
+#define	paddw(vars, vard)	mmx_m2m(paddw, vars, vard)
+
+#define	paddb_m2r(var, reg)	mmx_m2r(paddb, var, reg)
+#define	paddb_r2r(regs, regd)	mmx_r2r(paddb, regs, regd)
+#define	paddb(vars, vard)	mmx_m2m(paddb, vars, vard)
+
+
+/*	4x16 and 8x8 Parallel ADDs using Saturation arithmetic
+*/
+#define	paddsw_m2r(var, reg)	mmx_m2r(paddsw, var, reg)
+#define	paddsw_r2r(regs, regd)	mmx_r2r(paddsw, regs, regd)
+#define	paddsw(vars, vard)	mmx_m2m(paddsw, vars, vard)
+
+#define	paddsb_m2r(var, reg)	mmx_m2r(paddsb, var, reg)
+#define	paddsb_r2r(regs, regd)	mmx_r2r(paddsb, regs, regd)
+#define	paddsb(vars, vard)	mmx_m2m(paddsb, vars, vard)
+
+
+/*	4x16 and 8x8 Parallel ADDs using Unsigned Saturation arithmetic
+*/
+#define	paddusw_m2r(var, reg)	mmx_m2r(paddusw, var, reg)
+#define	paddusw_r2r(regs, regd)	mmx_r2r(paddusw, regs, regd)
+#define	paddusw(vars, vard)	mmx_m2m(paddusw, vars, vard)
+
+#define	paddusb_m2r(var, reg)	mmx_m2r(paddusb, var, reg)
+#define	paddusb_r2r(regs, regd)	mmx_r2r(paddusb, regs, regd)
+#define	paddusb(vars, vard)	mmx_m2m(paddusb, vars, vard)
+
+
+/*	2x32, 4x16, and 8x8 Parallel SUBs
+*/
+#define	psubd_m2r(var, reg)	mmx_m2r(psubd, var, reg)
+#define	psubd_r2r(regs, regd)	mmx_r2r(psubd, regs, regd)
+#define	psubd(vars, vard)	mmx_m2m(psubd, vars, vard)
+
+#define	psubw_m2r(var, reg)	mmx_m2r(psubw, var, reg)
+#define	psubw_r2r(regs, regd)	mmx_r2r(psubw, regs, regd)
+#define	psubw(vars, vard)	mmx_m2m(psubw, vars, vard)
+
+#define	psubb_m2r(var, reg)	mmx_m2r(psubb, var, reg)
+#define	psubb_r2r(regs, regd)	mmx_r2r(psubb, regs, regd)
+#define	psubb(vars, vard)	mmx_m2m(psubb, vars, vard)
+
+
+/*	4x16 and 8x8 Parallel SUBs using Saturation arithmetic
+*/
+#define	psubsw_m2r(var, reg)	mmx_m2r(psubsw, var, reg)
+#define	psubsw_r2r(regs, regd)	mmx_r2r(psubsw, regs, regd)
+#define	psubsw(vars, vard)	mmx_m2m(psubsw, vars, vard)
+
+#define	psubsb_m2r(var, reg)	mmx_m2r(psubsb, var, reg)
+#define	psubsb_r2r(regs, regd)	mmx_r2r(psubsb, regs, regd)
+#define	psubsb(vars, vard)	mmx_m2m(psubsb, vars, vard)
+
+
+/*	4x16 and 8x8 Parallel SUBs using Unsigned Saturation arithmetic
+*/
+#define	psubusw_m2r(var, reg)	mmx_m2r(psubusw, var, reg)
+#define	psubusw_r2r(regs, regd)	mmx_r2r(psubusw, regs, regd)
+#define	psubusw(vars, vard)	mmx_m2m(psubusw, vars, vard)
+
+#define	psubusb_m2r(var, reg)	mmx_m2r(psubusb, var, reg)
+#define	psubusb_r2r(regs, regd)	mmx_r2r(psubusb, regs, regd)
+#define	psubusb(vars, vard)	mmx_m2m(psubusb, vars, vard)
+
+
+/*	4x16 Parallel MULs giving Low 4x16 portions of results
+*/
+#define	pmullw_m2r(var, reg)	mmx_m2r(pmullw, var, reg)
+#define	pmullw_r2r(regs, regd)	mmx_r2r(pmullw, regs, regd)
+#define	pmullw(vars, vard)	mmx_m2m(pmullw, vars, vard)
+
+
+/*	4x16 Parallel MULs giving High 4x16 portions of results
+*/
+#define	pmulhw_m2r(var, reg)	mmx_m2r(pmulhw, var, reg)
+#define	pmulhw_r2r(regs, regd)	mmx_r2r(pmulhw, regs, regd)
+#define	pmulhw(vars, vard)	mmx_m2m(pmulhw, vars, vard)
+
+
+/*	4x16->2x32 Parallel Mul-ADD
+	(muls like pmullw, then adds adjacent 16-bit fields
+	 in the multiply result to make the final 2x32 result)
+*/
+#define	pmaddwd_m2r(var, reg)	mmx_m2r(pmaddwd, var, reg)
+#define	pmaddwd_r2r(regs, regd)	mmx_r2r(pmaddwd, regs, regd)
+#define	pmaddwd(vars, vard)	mmx_m2m(pmaddwd, vars, vard)
+
+
+/*	1x64 bitwise AND
+*/
+#ifdef	BROKEN_PAND
+#define	pand_m2r(var, reg) \
+	{ \
+		mmx_m2r(pandn, (mmx_t) -1LL, reg); \
+		mmx_m2r(pandn, var, reg); \
+	}
+#define	pand_r2r(regs, regd) \
+	{ \
+		mmx_m2r(pandn, (mmx_t) -1LL, regd); \
+		mmx_r2r(pandn, regs, regd); \
+	}
+#define	pand(vars, vard) \
+	{ \
+		movq_m2r(vard, mm0); \
+		mmx_m2r(pandn, (mmx_t) -1LL, mm0); \
+		mmx_m2r(pandn, vars, mm0); \
+		movq_r2m(mm0, vard); \
+	}
+#else
+#define	pand_m2r(var, reg)	mmx_m2r(pand, var, reg)
+#define	pand_r2r(regs, regd)	mmx_r2r(pand, regs, regd)
+#define	pand(vars, vard)	mmx_m2m(pand, vars, vard)
+#endif
+
+
+/*	1x64 bitwise AND with Not the destination
+*/
+#define	pandn_m2r(var, reg)	mmx_m2r(pandn, var, reg)
+#define	pandn_r2r(regs, regd)	mmx_r2r(pandn, regs, regd)
+#define	pandn(vars, vard)	mmx_m2m(pandn, vars, vard)
+
+
+/*	1x64 bitwise OR
+*/
+#define	por_m2r(var, reg)	mmx_m2r(por, var, reg)
+#define	por_r2r(regs, regd)	mmx_r2r(por, regs, regd)
+#define	por(vars, vard)	mmx_m2m(por, vars, vard)
+
+
+/*	1x64 bitwise eXclusive OR
+*/
+#define	pxor_m2r(var, reg)	mmx_m2r(pxor, var, reg)
+#define	pxor_r2r(regs, regd)	mmx_r2r(pxor, regs, regd)
+#define	pxor(vars, vard)	mmx_m2m(pxor, vars, vard)
+
+
+/*	2x32, 4x16, and 8x8 Parallel CoMPare for EQuality
+	(resulting fields are either 0 or -1)
+*/
+#define	pcmpeqd_m2r(var, reg)	mmx_m2r(pcmpeqd, var, reg)
+#define	pcmpeqd_r2r(regs, regd)	mmx_r2r(pcmpeqd, regs, regd)
+#define	pcmpeqd(vars, vard)	mmx_m2m(pcmpeqd, vars, vard)
+
+#define	pcmpeqw_m2r(var, reg)	mmx_m2r(pcmpeqw, var, reg)
+#define	pcmpeqw_r2r(regs, regd)	mmx_r2r(pcmpeqw, regs, regd)
+#define	pcmpeqw(vars, vard)	mmx_m2m(pcmpeqw, vars, vard)
+
+#define	pcmpeqb_m2r(var, reg)	mmx_m2r(pcmpeqb, var, reg)
+#define	pcmpeqb_r2r(regs, regd)	mmx_r2r(pcmpeqb, regs, regd)
+#define	pcmpeqb(vars, vard)	mmx_m2m(pcmpeqb, vars, vard)
+
+
+/*	2x32, 4x16, and 8x8 Parallel CoMPare for Greater Than
+	(resulting fields are either 0 or -1)
+*/
+#define	pcmpgtd_m2r(var, reg)	mmx_m2r(pcmpgtd, var, reg)
+#define	pcmpgtd_r2r(regs, regd)	mmx_r2r(pcmpgtd, regs, regd)
+#define	pcmpgtd(vars, vard)	mmx_m2m(pcmpgtd, vars, vard)
+
+#define	pcmpgtw_m2r(var, reg)	mmx_m2r(pcmpgtw, var, reg)
+#define	pcmpgtw_r2r(regs, regd)	mmx_r2r(pcmpgtw, regs, regd)
+#define	pcmpgtw(vars, vard)	mmx_m2m(pcmpgtw, vars, vard)
+
+#define	pcmpgtb_m2r(var, reg)	mmx_m2r(pcmpgtb, var, reg)
+#define	pcmpgtb_r2r(regs, regd)	mmx_r2r(pcmpgtb, regs, regd)
+#define	pcmpgtb(vars, vard)	mmx_m2m(pcmpgtb, vars, vard)
+
+
+/*	1x64, 2x32, and 4x16 Parallel Shift Left Logical
+*/
+#define	psllq_i2r(imm, reg)	mmx_i2r(psllq, imm, reg)
+#define	psllq_m2r(var, reg)	mmx_m2r(psllq, var, reg)
+#define	psllq_r2r(regs, regd)	mmx_r2r(psllq, regs, regd)
+#define	psllq(vars, vard)	mmx_m2m(psllq, vars, vard)
+
+#define	pslld_i2r(imm, reg)	mmx_i2r(pslld, imm, reg)
+#define	pslld_m2r(var, reg)	mmx_m2r(pslld, var, reg)
+#define	pslld_r2r(regs, regd)	mmx_r2r(pslld, regs, regd)
+#define	pslld(vars, vard)	mmx_m2m(pslld, vars, vard)
+
+#define	psllw_i2r(imm, reg)	mmx_i2r(psllw, imm, reg)
+#define	psllw_m2r(var, reg)	mmx_m2r(psllw, var, reg)
+#define	psllw_r2r(regs, regd)	mmx_r2r(psllw, regs, regd)
+#define	psllw(vars, vard)	mmx_m2m(psllw, vars, vard)
+
+
+/*	1x64, 2x32, and 4x16 Parallel Shift Right Logical
+*/
+#define	psrlq_i2r(imm, reg)	mmx_i2r(psrlq, imm, reg)
+#define	psrlq_m2r(var, reg)	mmx_m2r(psrlq, var, reg)
+#define	psrlq_r2r(regs, regd)	mmx_r2r(psrlq, regs, regd)
+#define	psrlq(vars, vard)	mmx_m2m(psrlq, vars, vard)
+
+#define	psrld_i2r(imm, reg)	mmx_i2r(psrld, imm, reg)
+#define	psrld_m2r(var, reg)	mmx_m2r(psrld, var, reg)
+#define	psrld_r2r(regs, regd)	mmx_r2r(psrld, regs, regd)
+#define	psrld(vars, vard)	mmx_m2m(psrld, vars, vard)
+
+#define	psrlw_i2r(imm, reg)	mmx_i2r(psrlw, imm, reg)
+#define	psrlw_m2r(var, reg)	mmx_m2r(psrlw, var, reg)
+#define	psrlw_r2r(regs, regd)	mmx_r2r(psrlw, regs, regd)
+#define	psrlw(vars, vard)	mmx_m2m(psrlw, vars, vard)
+
+
+/*	2x32 and 4x16 Parallel Shift Right Arithmetic
+*/
+#define	psrad_i2r(imm, reg)	mmx_i2r(psrad, imm, reg)
+#define	psrad_m2r(var, reg)	mmx_m2r(psrad, var, reg)
+#define	psrad_r2r(regs, regd)	mmx_r2r(psrad, regs, regd)
+#define	psrad(vars, vard)	mmx_m2m(psrad, vars, vard)
+
+#define	psraw_i2r(imm, reg)	mmx_i2r(psraw, imm, reg)
+#define	psraw_m2r(var, reg)	mmx_m2r(psraw, var, reg)
+#define	psraw_r2r(regs, regd)	mmx_r2r(psraw, regs, regd)
+#define	psraw(vars, vard)	mmx_m2m(psraw, vars, vard)
+
+
+/*	2x32->4x16 and 4x16->8x8 PACK and Signed Saturate
+	(packs source and dest fields into dest in that order)
+*/
+#define	packssdw_m2r(var, reg)	mmx_m2r(packssdw, var, reg)
+#define	packssdw_r2r(regs, regd) mmx_r2r(packssdw, regs, regd)
+#define	packssdw(vars, vard)	mmx_m2m(packssdw, vars, vard)
+
+#define	packsswb_m2r(var, reg)	mmx_m2r(packsswb, var, reg)
+#define	packsswb_r2r(regs, regd) mmx_r2r(packsswb, regs, regd)
+#define	packsswb(vars, vard)	mmx_m2m(packsswb, vars, vard)
+
+
+/*	4x16->8x8 PACK and Unsigned Saturate
+	(packs source and dest fields into dest in that order)
+*/
+#define	packuswb_m2r(var, reg)	mmx_m2r(packuswb, var, reg)
+#define	packuswb_r2r(regs, regd) mmx_r2r(packuswb, regs, regd)
+#define	packuswb(vars, vard)	mmx_m2m(packuswb, vars, vard)
+
+
+/*	2x32->1x64, 4x16->2x32, and 8x8->4x16 UNPaCK Low
+	(interleaves low half of dest with low half of source
+	 as padding in each result field)
+*/
+#define	punpckldq_m2r(var, reg)	mmx_m2r(punpckldq, var, reg)
+#define	punpckldq_r2r(regs, regd) mmx_r2r(punpckldq, regs, regd)
+#define	punpckldq(vars, vard)	mmx_m2m(punpckldq, vars, vard)
+
+#define	punpcklwd_m2r(var, reg)	mmx_m2r(punpcklwd, var, reg)
+#define	punpcklwd_r2r(regs, regd) mmx_r2r(punpcklwd, regs, regd)
+#define	punpcklwd(vars, vard)	mmx_m2m(punpcklwd, vars, vard)
+
+#define	punpcklbw_m2r(var, reg)	mmx_m2r(punpcklbw, var, reg)
+#define	punpcklbw_r2r(regs, regd) mmx_r2r(punpcklbw, regs, regd)
+#define	punpcklbw(vars, vard)	mmx_m2m(punpcklbw, vars, vard)
+
+
+/*	2x32->1x64, 4x16->2x32, and 8x8->4x16 UNPaCK High
+	(interleaves high half of dest with high half of source
+	 as padding in each result field)
+*/
+#define	punpckhdq_m2r(var, reg)	mmx_m2r(punpckhdq, var, reg)
+#define	punpckhdq_r2r(regs, regd) mmx_r2r(punpckhdq, regs, regd)
+#define	punpckhdq(vars, vard)	mmx_m2m(punpckhdq, vars, vard)
+
+#define	punpckhwd_m2r(var, reg)	mmx_m2r(punpckhwd, var, reg)
+#define	punpckhwd_r2r(regs, regd) mmx_r2r(punpckhwd, regs, regd)
+#define	punpckhwd(vars, vard)	mmx_m2m(punpckhwd, vars, vard)
+
+#define	punpckhbw_m2r(var, reg)	mmx_m2r(punpckhbw, var, reg)
+#define	punpckhbw_r2r(regs, regd) mmx_r2r(punpckhbw, regs, regd)
+#define	punpckhbw(vars, vard)	mmx_m2m(punpckhbw, vars, vard)
+
+
+/*	Empty MMx State
+	(used to clean-up when going from mmx to float use
+	 of the registers that are shared by both; note that
+	 there is no float-to-mmx operation needed, because
+	 only the float tag word info is corruptible)
+*/
+#ifdef	MMX_TRACE
+
+#define	emms() \
+	{ \
+		fprintf(stderr, "emms()\n"); \
+		__asm__ __volatile__ ("emms"); \
+	}
+
+#else
+
+#define	emms()			__asm__ __volatile__ ("emms")
+
+#endif
+
+#endif
diff --git a/gst/deinterlace/tvtime/plugins.h b/gst/deinterlace/tvtime/plugins.h
new file mode 100644
index 0000000..58085b6
--- /dev/null
+++ b/gst/deinterlace/tvtime/plugins.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * GStreamer
+ * Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
+ * Copyright (C) 2008 Sebastian Dröge <slomo@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
+ */
+
+#ifndef TVTIME_PLUGINS_H_INCLUDED
+#define TVTIME_PLUGINS_H_INCLUDED
+
+#define GST_TYPE_DEINTERLACE_TOMSMOCOMP (gst_deinterlace_method_tomsmocomp_get_type ())
+#define GST_TYPE_DEINTERLACE_GREEDY_H (gst_deinterlace_method_greedy_h_get_type ())
+#define GST_TYPE_DEINTERLACE_GREEDY_L (gst_deinterlace_method_greedy_l_get_type ())
+#define GST_TYPE_DEINTERLACE_VFIR (gst_deinterlace_method_vfir_get_type ())
+#define GST_TYPE_DEINTERLACE_LINEAR (gst_deinterlace_method_linear_get_type ())
+#define GST_TYPE_DEINTERLACE_LINEAR_BLEND (gst_deinterlace_method_linear_blend_get_type ())
+#define GST_TYPE_DEINTERLACE_SCALER_BOB (gst_deinterlace_method_scaler_bob_get_type ())
+#define GST_TYPE_DEINTERLACE_WEAVE (gst_deinterlace_method_weave_get_type ())
+#define GST_TYPE_DEINTERLACE_WEAVE_TFF (gst_deinterlace_method_weave_tff_get_type ())
+#define GST_TYPE_DEINTERLACE_WEAVE_BFF (gst_deinterlace_method_weave_bff_get_type ())
+
+GType gst_deinterlace_method_tomsmocomp_get_type (void);
+GType gst_deinterlace_method_greedy_h_get_type (void);
+GType gst_deinterlace_method_greedy_l_get_type (void);
+GType gst_deinterlace_method_vfir_get_type (void);
+
+GType gst_deinterlace_method_linear_get_type (void);
+GType gst_deinterlace_method_linear_blend_get_type (void);
+GType gst_deinterlace_method_scaler_bob_get_type (void);
+GType gst_deinterlace_method_weave_get_type (void);
+GType gst_deinterlace_method_weave_tff_get_type (void);
+GType gst_deinterlace_method_weave_bff_get_type (void);
+
+#endif /* TVTIME_PLUGINS_H_INCLUDED */
diff --git a/gst/deinterlace/tvtime/scalerbob.c b/gst/deinterlace/tvtime/scalerbob.c
new file mode 100644
index 0000000..ed20bd4
--- /dev/null
+++ b/gst/deinterlace/tvtime/scalerbob.c
@@ -0,0 +1,118 @@
+/*
+ * Double lines
+ * Copyright (C) 2008,2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstdeinterlacemethod.h"
+#include <string.h>
+
+#define GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB	(gst_deinterlace_method_scaler_bob_get_type ())
+#define GST_IS_DEINTERLACE_METHOD_SCALER_BOB(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB))
+#define GST_IS_DEINTERLACE_METHOD_SCALER_BOB_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB))
+#define GST_DEINTERLACE_METHOD_SCALER_BOB_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB, GstDeinterlaceMethodScalerBobClass))
+#define GST_DEINTERLACE_METHOD_SCALER_BOB(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB, GstDeinterlaceMethodScalerBob))
+#define GST_DEINTERLACE_METHOD_SCALER_BOB_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB, GstDeinterlaceMethodScalerBobClass))
+#define GST_DEINTERLACE_METHOD_SCALER_BOB_CAST(obj)	((GstDeinterlaceMethodScalerBob*)(obj))
+
+GType gst_deinterlace_method_scaler_bob_get_type (void);
+
+typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodScalerBob;
+typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodScalerBobClass;
+
+static void
+deinterlace_scanline_scaler_bob_packed (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->t0, size);
+}
+
+static void
+deinterlace_scanline_scaler_bob_planar_y (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->t0, size);
+}
+
+static void
+deinterlace_scanline_scaler_bob_planar_u (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->t0, size);
+}
+
+static void
+deinterlace_scanline_scaler_bob_planar_v (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->t0, size);
+}
+
+G_DEFINE_TYPE (GstDeinterlaceMethodScalerBob, gst_deinterlace_method_scaler_bob,
+    GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
+
+static void
+gst_deinterlace_method_scaler_bob_class_init (GstDeinterlaceMethodScalerBobClass
+    * klass)
+{
+  GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
+  GstDeinterlaceSimpleMethodClass *dism_class =
+      (GstDeinterlaceSimpleMethodClass *) klass;
+
+  dim_class->fields_required = 2;
+  dim_class->name = "Double lines";
+  dim_class->nick = "scalerbob";
+  dim_class->latency = 1;
+
+  dism_class->interpolate_scanline_ayuv =
+      deinterlace_scanline_scaler_bob_packed;
+  dism_class->interpolate_scanline_yuy2 =
+      deinterlace_scanline_scaler_bob_packed;
+  dism_class->interpolate_scanline_yvyu =
+      deinterlace_scanline_scaler_bob_packed;
+  dism_class->interpolate_scanline_uyvy =
+      deinterlace_scanline_scaler_bob_packed;
+  dism_class->interpolate_scanline_nv12 =
+      deinterlace_scanline_scaler_bob_packed;
+  dism_class->interpolate_scanline_nv21 =
+      deinterlace_scanline_scaler_bob_packed;
+  dism_class->interpolate_scanline_argb =
+      deinterlace_scanline_scaler_bob_packed;
+  dism_class->interpolate_scanline_abgr =
+      deinterlace_scanline_scaler_bob_packed;
+  dism_class->interpolate_scanline_rgba =
+      deinterlace_scanline_scaler_bob_packed;
+  dism_class->interpolate_scanline_bgra =
+      deinterlace_scanline_scaler_bob_packed;
+  dism_class->interpolate_scanline_rgb = deinterlace_scanline_scaler_bob_packed;
+  dism_class->interpolate_scanline_bgr = deinterlace_scanline_scaler_bob_packed;
+  dism_class->interpolate_scanline_planar_y =
+      deinterlace_scanline_scaler_bob_planar_y;
+  dism_class->interpolate_scanline_planar_u =
+      deinterlace_scanline_scaler_bob_planar_u;
+  dism_class->interpolate_scanline_planar_v =
+      deinterlace_scanline_scaler_bob_planar_v;
+}
+
+static void
+gst_deinterlace_method_scaler_bob_init (GstDeinterlaceMethodScalerBob * self)
+{
+}
diff --git a/gst/deinterlace/tvtime/sse.h b/gst/deinterlace/tvtime/sse.h
new file mode 100644
index 0000000..2e00ee0
--- /dev/null
+++ b/gst/deinterlace/tvtime/sse.h
@@ -0,0 +1,992 @@
+/*	sse.h
+
+	Streaming SIMD Extenstions (a.k.a. Katmai New Instructions)
+	GCC interface library for IA32.
+
+	To use this library, simply include this header file
+	and compile with GCC.  You MUST have inlining enabled
+	in order for sse_ok() to work; this can be done by
+	simply using -O on the GCC command line.
+
+	Compiling with -DSSE_TRACE will cause detailed trace
+	output to be sent to stderr for each sse operation.
+	This adds lots of code, and obviously slows execution to
+	a crawl, but can be very useful for debugging.
+
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
+	EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+	LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR ANY PARTICULAR PURPOSE.
+
+	1999 by R. Fisher
+	Based on libmmx by H. Dietz and R. Fisher
+
+ Notes:
+	This is still extremely alpha.
+	Because this library depends on an assembler which understands the
+	 SSE opcodes, you probably won't be able to use this yet.
+	For now, do not use TRACE versions.  These both make use
+	 of the MMX registers, not the SSE registers.  This will be resolved
+	 at a later date.
+ ToDo:
+	Rewrite TRACE macros
+	Major Debugging Work
+*/
+
+#ifndef _SSE_H
+#define _SSE_H
+
+
+
+/*	The type of an value that fits in an SSE register
+	(note that long long constant values MUST be suffixed
+	 by LL and unsigned long long values by ULL, lest
+	 they be truncated by the compiler)
+*/
+typedef	union {
+	float			sf[4];	/* Single-precision (32-bit) value */
+} __attribute__ ((aligned (16))) sse_t;	/* On a 16 byte (128-bit) boundary */
+
+
+#if 0
+/*	Function to test if multimedia instructions are supported...
+*/
+inline extern int
+mm_support(void)
+{
+	/* Returns 1 if MMX instructions are supported,
+	   3 if Cyrix MMX and Extended MMX instructions are supported
+	   5 if AMD MMX and 3DNow! instructions are supported
+	   9 if MMX and SSE instructions are supported
+	   0 if hardware does not support any of these
+	*/
+	register int rval = 0;
+
+	__asm__ __volatile__ (
+		/* See if CPUID instruction is supported ... */
+		/* ... Get copies of EFLAGS into eax and ecx */
+		"pushf\n\t"
+		"popl %%eax\n\t"
+		"movl %%eax, %%ecx\n\t"
+
+		/* ... Toggle the ID bit in one copy and store */
+		/*     to the EFLAGS reg */
+		"xorl $0x200000, %%eax\n\t"
+		"push %%eax\n\t"
+		"popf\n\t"
+
+		/* ... Get the (hopefully modified) EFLAGS */
+		"pushf\n\t"
+		"popl %%eax\n\t"
+
+		/* ... Compare and test result */
+		"xorl %%eax, %%ecx\n\t"
+		"testl $0x200000, %%ecx\n\t"
+		"jz NotSupported1\n\t"		/* CPUID not supported */
+
+
+		/* Get standard CPUID information, and
+		       go to a specific vendor section */
+		"movl $0, %%eax\n\t"
+		"cpuid\n\t"
+
+		/* Check for Intel */
+		"cmpl $0x756e6547, %%ebx\n\t"
+		"jne TryAMD\n\t"
+		"cmpl $0x49656e69, %%edx\n\t"
+		"jne TryAMD\n\t"
+		"cmpl $0x6c65746e, %%ecx\n"
+		"jne TryAMD\n\t"
+		"jmp Intel\n\t"
+
+		/* Check for AMD */
+		"\nTryAMD:\n\t"
+		"cmpl $0x68747541, %%ebx\n\t"
+		"jne TryCyrix\n\t"
+		"cmpl $0x69746e65, %%edx\n\t"
+		"jne TryCyrix\n\t"
+		"cmpl $0x444d4163, %%ecx\n"
+		"jne TryCyrix\n\t"
+		"jmp AMD\n\t"
+
+		/* Check for Cyrix */
+		"\nTryCyrix:\n\t"
+		"cmpl $0x69727943, %%ebx\n\t"
+		"jne NotSupported2\n\t"
+		"cmpl $0x736e4978, %%edx\n\t"
+		"jne NotSupported3\n\t"
+		"cmpl $0x64616574, %%ecx\n\t"
+		"jne NotSupported4\n\t"
+		/* Drop through to Cyrix... */
+
+
+		/* Cyrix Section */
+		/* See if extended CPUID level 80000001 is supported */
+		/* The value of CPUID/80000001 for the 6x86MX is undefined
+		   according to the Cyrix CPU Detection Guide (Preliminary
+		   Rev. 1.01 table 1), so we'll check the value of eax for
+		   CPUID/0 to see if standard CPUID level 2 is supported.
+		   According to the table, the only CPU which supports level
+		   2 is also the only one which supports extended CPUID levels.
+		*/
+		"cmpl $0x2, %%eax\n\t"
+		"jne MMXtest\n\t"	/* Use standard CPUID instead */
+
+		/* Extended CPUID supported (in theory), so get extended
+		   features */
+		"movl $0x80000001, %%eax\n\t"
+		"cpuid\n\t"
+		"testl $0x00800000, %%eax\n\t"	/* Test for MMX */
+		"jz NotSupported5\n\t"		/* MMX not supported */
+		"testl $0x01000000, %%eax\n\t"	/* Test for Ext'd MMX */
+		"jnz EMMXSupported\n\t"
+		"movl $1, %0:\n\n\t"		/* MMX Supported */
+		"jmp Return\n\n"
+		"EMMXSupported:\n\t"
+		"movl $3, %0:\n\n\t"		/* EMMX and MMX Supported */
+		"jmp Return\n\t"
+
+
+		/* AMD Section */
+		"AMD:\n\t"
+
+		/* See if extended CPUID is supported */
+		"movl $0x80000000, %%eax\n\t"
+		"cpuid\n\t"
+		"cmpl $0x80000000, %%eax\n\t"
+		"jl MMXtest\n\t"	/* Use standard CPUID instead */
+
+		/* Extended CPUID supported, so get extended features */
+		"movl $0x80000001, %%eax\n\t"
+		"cpuid\n\t"
+		"testl $0x00800000, %%edx\n\t"	/* Test for MMX */
+		"jz NotSupported6\n\t"		/* MMX not supported */
+		"testl $0x80000000, %%edx\n\t"	/* Test for 3DNow! */
+		"jnz ThreeDNowSupported\n\t"
+		"movl $1, %0:\n\n\t"		/* MMX Supported */
+		"jmp Return\n\n"
+		"ThreeDNowSupported:\n\t"
+		"movl $5, %0:\n\n\t"		/* 3DNow! and MMX Supported */
+		"jmp Return\n\t"
+
+
+		/* Intel Section */
+		"Intel:\n\t"
+
+		/* Check for SSE */
+		"SSEtest:\n\t"
+		"movl $1, %%eax\n\t"
+		"cpuid\n\t"
+		"testl $0x02000000, %%edx\n\t"	/* Test for SSE */
+		"jz MMXtest\n\t"		/* SSE Not supported */
+		"movl $9, %0:\n\n\t"		/* SSE Supported */
+		"jmp Return\n\t"
+
+		/* Check for MMX */
+		"MMXtest:\n\t"
+		"movl $1, %%eax\n\t"
+		"cpuid\n\t"
+		"testl $0x00800000, %%edx\n\t"	/* Test for MMX */
+		"jz NotSupported7\n\t"		/* MMX Not supported */
+		"movl $1, %0:\n\n\t"		/* MMX Supported */
+		"jmp Return\n\t"
+
+		/* Nothing supported */
+		"\nNotSupported1:\n\t"
+		"#movl $101, %0:\n\n\t"
+		"\nNotSupported2:\n\t"
+		"#movl $102, %0:\n\n\t"
+		"\nNotSupported3:\n\t"
+		"#movl $103, %0:\n\n\t"
+		"\nNotSupported4:\n\t"
+		"#movl $104, %0:\n\n\t"
+		"\nNotSupported5:\n\t"
+		"#movl $105, %0:\n\n\t"
+		"\nNotSupported6:\n\t"
+		"#movl $106, %0:\n\n\t"
+		"\nNotSupported7:\n\t"
+		"#movl $107, %0:\n\n\t"
+		"movl $0, %0:\n\n\t"
+
+		"Return:\n\t"
+		: "=a" (rval)
+		: /* no input */
+		: "eax", "ebx", "ecx", "edx"
+	);
+
+	/* Return */
+	return(rval);
+}
+
+/*	Function to test if sse instructions are supported...
+*/
+inline extern int
+sse_ok(void)
+{
+	/* Returns 1 if SSE instructions are supported, 0 otherwise */
+	return ( (mm_support() & 0x8) >> 3  );
+}
+#endif
+
+
+
+/*	Helper functions for the instruction macros that follow...
+	(note that memory-to-register, m2r, instructions are nearly
+	 as efficient as register-to-register, r2r, instructions;
+	 however, memory-to-memory instructions are really simulated
+	 as a convenience, and are only 1/3 as efficient)
+*/
+#ifdef	SSE_TRACE
+
+/*	Include the stuff for printing a trace to stderr...
+*/
+
+#include <stdio.h>
+
+#define	sse_i2r(op, imm, reg) \
+	{ \
+		sse_t sse_trace; \
+		sse_trace.uq = (imm); \
+		fprintf(stderr, #op "_i2r(" #imm "=0x%08x%08x, ", \
+			sse_trace.d[1], sse_trace.d[0]); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (sse_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #reg "=0x%08x%08x) => ", \
+			sse_trace.d[1], sse_trace.d[0]); \
+		__asm__ __volatile__ (#op " %0, %%" #reg \
+				      : /* nothing */ \
+				      : "X" (imm)); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (sse_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #reg "=0x%08x%08x\n", \
+			sse_trace.d[1], sse_trace.d[0]); \
+	}
+
+#define	sse_m2r(op, mem, reg) \
+	{ \
+		sse_t sse_trace; \
+		sse_trace = (mem); \
+		fprintf(stderr, #op "_m2r(" #mem "=0x%08x%08x, ", \
+			sse_trace.d[1], sse_trace.d[0]); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (sse_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #reg "=0x%08x%08x) => ", \
+			sse_trace.d[1], sse_trace.d[0]); \
+		__asm__ __volatile__ (#op " %0, %%" #reg \
+				      : /* nothing */ \
+				      : "X" (mem)); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (sse_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #reg "=0x%08x%08x\n", \
+			sse_trace.d[1], sse_trace.d[0]); \
+	}
+
+#define	sse_r2m(op, reg, mem) \
+	{ \
+		sse_t sse_trace; \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (sse_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #op "_r2m(" #reg "=0x%08x%08x, ", \
+			sse_trace.d[1], sse_trace.d[0]); \
+		sse_trace = (mem); \
+		fprintf(stderr, #mem "=0x%08x%08x) => ", \
+			sse_trace.d[1], sse_trace.d[0]); \
+		__asm__ __volatile__ (#op " %%" #reg ", %0" \
+				      : "=X" (mem) \
+				      : /* nothing */ ); \
+		sse_trace = (mem); \
+		fprintf(stderr, #mem "=0x%08x%08x\n", \
+			sse_trace.d[1], sse_trace.d[0]); \
+	}
+
+#define	sse_r2r(op, regs, regd) \
+	{ \
+		sse_t sse_trace; \
+		__asm__ __volatile__ ("movq %%" #regs ", %0" \
+				      : "=X" (sse_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #op "_r2r(" #regs "=0x%08x%08x, ", \
+			sse_trace.d[1], sse_trace.d[0]); \
+		__asm__ __volatile__ ("movq %%" #regd ", %0" \
+				      : "=X" (sse_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #regd "=0x%08x%08x) => ", \
+			sse_trace.d[1], sse_trace.d[0]); \
+		__asm__ __volatile__ (#op " %" #regs ", %" #regd); \
+		__asm__ __volatile__ ("movq %%" #regd ", %0" \
+				      : "=X" (sse_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #regd "=0x%08x%08x\n", \
+			sse_trace.d[1], sse_trace.d[0]); \
+	}
+
+#define	sse_m2m(op, mems, memd) \
+	{ \
+		sse_t sse_trace; \
+		sse_trace = (mems); \
+		fprintf(stderr, #op "_m2m(" #mems "=0x%08x%08x, ", \
+			sse_trace.d[1], sse_trace.d[0]); \
+		sse_trace = (memd); \
+		fprintf(stderr, #memd "=0x%08x%08x) => ", \
+			sse_trace.d[1], sse_trace.d[0]); \
+		__asm__ __volatile__ ("movq %0, %%mm0\n\t" \
+				      #op " %1, %%mm0\n\t" \
+				      "movq %%mm0, %0" \
+				      : "=X" (memd) \
+				      : "X" (mems)); \
+		sse_trace = (memd); \
+		fprintf(stderr, #memd "=0x%08x%08x\n", \
+			sse_trace.d[1], sse_trace.d[0]); \
+	}
+
+#else
+
+/*	These macros are a lot simpler without the tracing...
+*/
+
+#define	sse_i2r(op, imm, reg) \
+	__asm__ __volatile__ (#op " %0, %%" #reg \
+			      : /* nothing */ \
+			      : "X" (imm) )
+
+#define	sse_m2r(op, mem, reg) \
+	__asm__ __volatile__ (#op " %0, %%" #reg \
+			      : /* nothing */ \
+			      : "X" (mem))
+
+#define	sse_r2m(op, reg, mem) \
+	__asm__ __volatile__ (#op " %%" #reg ", %0" \
+			      : "=X" (mem) \
+			      : /* nothing */ )
+
+#define	sse_r2r(op, regs, regd) \
+	__asm__ __volatile__ (#op " %" #regs ", %" #regd)
+
+#define	sse_r2ri(op, regs, regd, imm) \
+	__asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \
+			      : /* nothing */ \
+			      : "X" (imm) )
+
+/* Load data from mems to xmmreg, operate on xmmreg, and store data to memd */
+#define	sse_m2m(op, mems, memd, xmmreg) \
+	__asm__ __volatile__ ("movups %0, %%xmm0\n\t" \
+			      #op " %1, %%xmm0\n\t" \
+			      "movups %%mm0, %0" \
+			      : "=X" (memd) \
+			      : "X" (mems))
+
+#define	sse_m2ri(op, mem, reg, subop) \
+	__asm__ __volatile__ (#op " %0, %%" #reg ", " #subop \
+			      : /* nothing */ \
+			      : "X" (mem))
+
+#define	sse_m2mi(op, mems, memd, xmmreg, subop) \
+	__asm__ __volatile__ ("movups %0, %%xmm0\n\t" \
+			      #op " %1, %%xmm0, " #subop "\n\t" \
+			      "movups %%mm0, %0" \
+			      : "=X" (memd) \
+			      : "X" (mems))
+#endif
+
+
+
+
+/*	1x128 MOVe Aligned four Packed Single-fp
+*/
+#define	movaps_m2r(var, reg)	sse_m2r(movaps, var, reg)
+#define	movaps_r2m(reg, var)	sse_r2m(movaps, reg, var)
+#define	movaps_r2r(regs, regd)	sse_r2r(movaps, regs, regd)
+#define	movaps(vars, vard) \
+	__asm__ __volatile__ ("movaps %1, %%mm0\n\t" \
+			      "movaps %%mm0, %0" \
+			      : "=X" (vard) \
+			      : "X" (vars))
+
+
+/*	1x128 MOVe aligned Non-Temporal four Packed Single-fp
+*/
+#define	movntps_r2m(xmmreg, var)	sse_r2m(movntps, xmmreg, var)
+
+
+/*	1x64 MOVe Non-Temporal Quadword
+*/
+#define	movntq_r2m(mmreg, var)		sse_r2m(movntq, mmreg, var)
+
+
+/*	1x128 MOVe Unaligned four Packed Single-fp
+*/
+#define	movups_m2r(var, reg)	sse_m2r(movups, var, reg)
+#define	movups_r2m(reg, var)	sse_r2m(movups, reg, var)
+#define	movups_r2r(regs, regd)	sse_r2r(movups, regs, regd)
+#define	movups(vars, vard) \
+	__asm__ __volatile__ ("movups %1, %%mm0\n\t" \
+			      "movups %%mm0, %0" \
+			      : "=X" (vard) \
+			      : "X" (vars))
+
+
+/*	MOVe High to Low Packed Single-fp
+	high half of 4x32f (x) -> low half of 4x32f (y)
+*/
+#define	movhlps_r2r(regs, regd)	sse_r2r(movhlps, regs, regd)
+
+
+/*	MOVe Low to High Packed Single-fp
+	low half of 4x32f (x) -> high half of 4x32f (y)
+*/
+#define	movlhps_r2r(regs, regd)	sse_r2r(movlhps, regs, regd)
+
+
+/*	MOVe High Packed Single-fp
+	2x32f -> high half of 4x32f
+*/
+#define	movhps_m2r(var, reg)	sse_m2r(movhps, var, reg)
+#define	movhps_r2m(reg, var)	sse_r2m(movhps, reg, var)
+#define	movhps(vars, vard) \
+	__asm__ __volatile__ ("movhps %1, %%mm0\n\t" \
+			      "movhps %%mm0, %0" \
+			      : "=X" (vard) \
+			      : "X" (vars))
+
+
+/*	MOVe Low Packed Single-fp
+	2x32f -> low half of 4x32f
+*/
+#define	movlps_m2r(var, reg)	sse_m2r(movlps, var, reg)
+#define	movlps_r2m(reg, var)	sse_r2m(movlps, reg, var)
+#define	movlps(vars, vard) \
+	__asm__ __volatile__ ("movlps %1, %%mm0\n\t" \
+			      "movlps %%mm0, %0" \
+			      : "=X" (vard) \
+			      : "X" (vars))
+
+
+/*	MOVe Scalar Single-fp
+	lowest field of 4x32f (x) -> lowest field of 4x32f (y)
+*/
+#define	movss_m2r(var, reg)	sse_m2r(movss, var, reg)
+#define	movss_r2m(reg, var)	sse_r2m(movss, reg, var)
+#define	movss_r2r(regs, regd)	sse_r2r(movss, regs, regd)
+#define	movss(vars, vard) \
+	__asm__ __volatile__ ("movss %1, %%mm0\n\t" \
+			      "movss %%mm0, %0" \
+			      : "=X" (vard) \
+			      : "X" (vars))
+
+
+/*	4x16 Packed SHUFfle Word
+*/
+#define	pshufw_m2r(var, reg, index)	sse_m2ri(pshufw, var, reg, index)
+#define	pshufw_r2r(regs, regd, index)	sse_r2ri(pshufw, regs, regd, index)
+
+
+/*	1x128 SHUFfle Packed Single-fp
+*/
+#define	shufps_m2r(var, reg, index)	sse_m2ri(shufps, var, reg, index)
+#define	shufps_r2r(regs, regd, index)	sse_r2ri(shufps, regs, regd, index)
+
+
+/*	ConVerT Packed signed Int32 to(2) Packed Single-fp
+*/
+#define	cvtpi2ps_m2r(var, xmmreg)	sse_m2r(cvtpi2ps, var, xmmreg)
+#define	cvtpi2ps_r2r(mmreg, xmmreg)	sse_r2r(cvtpi2ps, mmreg, xmmreg)
+
+
+/*	ConVerT Packed Single-fp to(2) Packed signed Int32
+*/
+#define	cvtps2pi_m2r(var, mmreg)	sse_m2r(cvtps2pi, var, mmreg)
+#define	cvtps2pi_r2r(xmmreg, mmreg)	sse_r2r(cvtps2pi, mmreg, xmmreg)
+
+
+/*	ConVerT with Truncate Packed Single-fp to(2) Packed Int32
+*/
+#define	cvttps2pi_m2r(var, mmreg)	sse_m2r(cvttps2pi, var, mmreg)
+#define	cvttps2pi_r2r(xmmreg, mmreg)	sse_r2r(cvttps2pi, mmreg, xmmreg)
+
+
+/*	ConVerT Signed Int32 to(2) Single-fp (Scalar)
+*/
+#define	cvtsi2ss_m2r(var, xmmreg)	sse_m2r(cvtsi2ss, var, xmmreg)
+#define	cvtsi2ss_r2r(reg, xmmreg)	sse_r2r(cvtsi2ss, reg, xmmreg)
+
+
+/*	ConVerT Scalar Single-fp to(2) Signed Int32
+*/
+#define	cvtss2si_m2r(var, reg)		sse_m2r(cvtss2si, var, reg)
+#define	cvtss2si_r2r(xmmreg, reg)	sse_r2r(cvtss2si, xmmreg, reg)
+
+
+/*	ConVerT with Truncate Scalar Single-fp to(2) Signed Int32
+*/
+#define	cvttss2si_m2r(var, reg)		sse_m2r(cvtss2si, var, reg)
+#define	cvttss2si_r2r(xmmreg, reg)	sse_r2r(cvtss2si, xmmreg, reg)
+
+
+/*	Parallel EXTRact Word from 4x16
+*/
+#define	pextrw_r2r(mmreg, reg, field)	sse_r2ri(pextrw, mmreg, reg, field)
+
+
+/*	Parallel INSeRt Word from 4x16
+*/
+#define	pinsrw_r2r(reg, mmreg, field)	sse_r2ri(pinsrw, reg, mmreg, field)
+
+
+
+/*	MOVe MaSK from Packed Single-fp
+*/
+#ifdef	SSE_TRACE
+	#define	movmskps(xmmreg, reg) \
+	{ \
+		fprintf(stderr, "movmskps()\n"); \
+		__asm__ __volatile__ ("movmskps %" #xmmreg ", %" #reg) \
+	}
+#else
+	#define	movmskps(xmmreg, reg) \
+	__asm__ __volatile__ ("movmskps %" #xmmreg ", %" #reg)
+#endif
+
+
+/*	Parallel MOVe MaSK from mmx reg to 32-bit reg
+*/
+#ifdef	SSE_TRACE
+	#define	pmovmskb(mmreg, reg) \
+	{ \
+		fprintf(stderr, "movmskps()\n"); \
+		__asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg) \
+	}
+#else
+	#define	pmovmskb(mmreg, reg) \
+	__asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg)
+#endif
+
+
+/*	MASKed MOVe from 8x8 to memory pointed to by (e)di register
+*/
+#define	maskmovq(mmregs, fieldreg)	sse_r2ri(maskmovq, mmregs, fieldreg)
+
+
+
+
+/*	4x32f Parallel ADDs
+*/
+#define	addps_m2r(var, reg)		sse_m2r(addps, var, reg)
+#define	addps_r2r(regs, regd)		sse_r2r(addps, regs, regd)
+#define	addps(vars, vard, xmmreg)	sse_m2m(addps, vars, vard, xmmreg)
+
+
+/*	Lowest Field of 4x32f Parallel ADDs
+*/
+#define	addss_m2r(var, reg)		sse_m2r(addss, var, reg)
+#define	addss_r2r(regs, regd)		sse_r2r(addss, regs, regd)
+#define	addss(vars, vard, xmmreg)	sse_m2m(addss, vars, vard, xmmreg)
+
+
+/*	4x32f Parallel SUBs
+*/
+#define	subps_m2r(var, reg)		sse_m2r(subps, var, reg)
+#define	subps_r2r(regs, regd)		sse_r2r(subps, regs, regd)
+#define	subps(vars, vard, xmmreg)	sse_m2m(subps, vars, vard, xmmreg)
+
+
+/*	Lowest Field of 4x32f Parallel SUBs
+*/
+#define	subss_m2r(var, reg)		sse_m2r(subss, var, reg)
+#define	subss_r2r(regs, regd)		sse_r2r(subss, regs, regd)
+#define	subss(vars, vard, xmmreg)	sse_m2m(subss, vars, vard, xmmreg)
+
+
+/*	8x8u -> 4x16u Packed Sum of Absolute Differences
+*/
+#define	psadbw_m2r(var, reg)		sse_m2r(psadbw, var, reg)
+#define	psadbw_r2r(regs, regd)		sse_r2r(psadbw, regs, regd)
+#define	psadbw(vars, vard, mmreg)	sse_m2m(psadbw, vars, vard, mmreg)
+
+
+/*	4x16u Parallel MUL High Unsigned
+*/
+#define	pmulhuw_m2r(var, reg)		sse_m2r(pmulhuw, var, reg)
+#define	pmulhuw_r2r(regs, regd)		sse_r2r(pmulhuw, regs, regd)
+#define	pmulhuw(vars, vard, mmreg)	sse_m2m(pmulhuw, vars, vard, mmreg)
+
+
+/*	4x32f Parallel MULs
+*/
+#define	mulps_m2r(var, reg)		sse_m2r(mulps, var, reg)
+#define	mulps_r2r(regs, regd)		sse_r2r(mulps, regs, regd)
+#define	mulps(vars, vard, xmmreg)	sse_m2m(mulps, vars, vard, xmmreg)
+
+
+/*	Lowest Field of 4x32f Parallel MULs
+*/
+#define	mulss_m2r(var, reg)		sse_m2r(mulss, var, reg)
+#define	mulss_r2r(regs, regd)		sse_r2r(mulss, regs, regd)
+#define	mulss(vars, vard, xmmreg)	sse_m2m(mulss, vars, vard, xmmreg)
+
+
+/*	4x32f Parallel DIVs
+*/
+#define	divps_m2r(var, reg)		sse_m2r(divps, var, reg)
+#define	divps_r2r(regs, regd)		sse_r2r(divps, regs, regd)
+#define	divps(vars, vard, xmmreg)	sse_m2m(divps, vars, vard, xmmreg)
+
+
+/*	Lowest Field of 4x32f Parallel DIVs
+*/
+#define	divss_m2r(var, reg)		sse_m2r(divss, var, reg)
+#define	divss_r2r(regs, regd)		sse_r2r(divss, regs, regd)
+#define	divss(vars, vard, xmmreg)	sse_m2m(divss, vars, vard, xmmreg)
+
+
+/*	4x32f Parallel Reciprocals
+*/
+#define	rcpps_m2r(var, reg)		sse_m2r(rcpps, var, reg)
+#define	rcpps_r2r(regs, regd)		sse_r2r(rcpps, regs, regd)
+#define	rcpps(vars, vard, xmmreg)	sse_m2m(rcpps, vars, vard, xmmreg)
+
+
+/*	Lowest Field of 4x32f Parallel Reciprocals
+*/
+#define	rcpss_m2r(var, reg)		sse_m2r(rcpss, var, reg)
+#define	rcpss_r2r(regs, regd)		sse_r2r(rcpss, regs, regd)
+#define	rcpss(vars, vard, xmmreg)	sse_m2m(rcpss, vars, vard, xmmreg)
+
+
+/*	4x32f Parallel Square Root of Reciprocals
+*/
+#define	rsqrtps_m2r(var, reg)		sse_m2r(rsqrtps, var, reg)
+#define	rsqrtps_r2r(regs, regd)		sse_r2r(rsqrtps, regs, regd)
+#define	rsqrtps(vars, vard, xmmreg)	sse_m2m(rsqrtps, vars, vard, xmmreg)
+
+
+/*	Lowest Field of 4x32f Parallel Square Root of Reciprocals
+*/
+#define	rsqrtss_m2r(var, reg)		sse_m2r(rsqrtss, var, reg)
+#define	rsqrtss_r2r(regs, regd)		sse_r2r(rsqrtss, regs, regd)
+#define	rsqrtss(vars, vard, xmmreg)	sse_m2m(rsqrtss, vars, vard, xmmreg)
+
+
+/*	4x32f Parallel Square Roots
+*/
+#define	sqrtps_m2r(var, reg)		sse_m2r(sqrtps, var, reg)
+#define	sqrtps_r2r(regs, regd)		sse_r2r(sqrtps, regs, regd)
+#define	sqrtps(vars, vard, xmmreg)	sse_m2m(sqrtps, vars, vard, xmmreg)
+
+
+/*	Lowest Field of 4x32f Parallel Square Roots
+*/
+#define	sqrtss_m2r(var, reg)		sse_m2r(sqrtss, var, reg)
+#define	sqrtss_r2r(regs, regd)		sse_r2r(sqrtss, regs, regd)
+#define	sqrtss(vars, vard, xmmreg)	sse_m2m(sqrtss, vars, vard, xmmreg)
+
+
+/*	8x8u and 4x16u Parallel AVeraGe
+*/
+#define	pavgb_m2r(var, reg)		sse_m2r(pavgb, var, reg)
+#define	pavgb_r2r(regs, regd)		sse_r2r(pavgb, regs, regd)
+#define	pavgb(vars, vard, mmreg)	sse_m2m(pavgb, vars, vard, mmreg)
+
+#define	pavgw_m2r(var, reg)		sse_m2r(pavgw, var, reg)
+#define	pavgw_r2r(regs, regd)		sse_r2r(pavgw, regs, regd)
+#define	pavgw(vars, vard, mmreg)	sse_m2m(pavgw, vars, vard, mmreg)
+
+
+/*	1x128 bitwise AND
+*/
+#define	andps_m2r(var, reg)		sse_m2r(andps, var, reg)
+#define	andps_r2r(regs, regd)		sse_r2r(andps, regs, regd)
+#define	andps(vars, vard, xmmreg)	sse_m2m(andps, vars, vard, xmmreg)
+
+
+/*	1x128 bitwise AND with Not the destination
+*/
+#define	andnps_m2r(var, reg)		sse_m2r(andnps, var, reg)
+#define	andnps_r2r(regs, regd)		sse_r2r(andnps, regs, regd)
+#define	andnps(vars, vard, xmmreg)	sse_m2m(andnps, vars, vard, xmmreg)
+
+
+/*	1x128 bitwise OR
+*/
+#define	orps_m2r(var, reg)		sse_m2r(orps, var, reg)
+#define	orps_r2r(regs, regd)		sse_r2r(orps, regs, regd)
+#define	orps(vars, vard, xmmreg)	sse_m2m(orps, vars, vard, xmmreg)
+
+
+/*	1x128 bitwise eXclusive OR
+*/
+#define	xorps_m2r(var, reg)		sse_m2r(xorps, var, reg)
+#define	xorps_r2r(regs, regd)		sse_r2r(xorps, regs, regd)
+#define	xorps(vars, vard, xmmreg)	sse_m2m(xorps, vars, vard, xmmreg)
+
+
+/*	8x8u, 4x16, and 4x32f Parallel Maximum
+*/
+#define	pmaxub_m2r(var, reg)		sse_m2r(pmaxub, var, reg)
+#define	pmaxub_r2r(regs, regd)		sse_r2r(pmaxub, regs, regd)
+#define	pmaxub(vars, vard, mmreg)	sse_m2m(pmaxub, vars, vard, mmreg)
+
+#define	pmaxsw_m2r(var, reg)		sse_m2r(pmaxsw, var, reg)
+#define	pmaxsw_r2r(regs, regd)		sse_r2r(pmaxsw, regs, regd)
+#define	pmaxsw(vars, vard, mmreg)	sse_m2m(pmaxsw, vars, vard, mmreg)
+
+#define	maxps_m2r(var, reg)		sse_m2r(maxps, var, reg)
+#define	maxps_r2r(regs, regd)		sse_r2r(maxps, regs, regd)
+#define	maxps(vars, vard, xmmreg)	sse_m2m(maxps, vars, vard, xmmreg)
+
+
+/*	Lowest Field of 4x32f Parallel Maximum
+*/
+#define	maxss_m2r(var, reg)		sse_m2r(maxss, var, reg)
+#define	maxss_r2r(regs, regd)		sse_r2r(maxss, regs, regd)
+#define	maxss(vars, vard, xmmreg)	sse_m2m(maxss, vars, vard, xmmreg)
+
+
+/*	8x8u, 4x16, and 4x32f Parallel Minimum
+*/
+#define	pminub_m2r(var, reg)		sse_m2r(pminub, var, reg)
+#define	pminub_r2r(regs, regd)		sse_r2r(pminub, regs, regd)
+#define	pminub(vars, vard, mmreg)	sse_m2m(pminub, vars, vard, mmreg)
+
+#define	pminsw_m2r(var, reg)		sse_m2r(pminsw, var, reg)
+#define	pminsw_r2r(regs, regd)		sse_r2r(pminsw, regs, regd)
+#define	pminsw(vars, vard, mmreg)	sse_m2m(pminsw, vars, vard, mmreg)
+
+#define	minps_m2r(var, reg)		sse_m2r(minps, var, reg)
+#define	minps_r2r(regs, regd)		sse_r2r(minps, regs, regd)
+#define	minps(vars, vard, xmmreg)	sse_m2m(minps, vars, vard, xmmreg)
+
+
+/*	Lowest Field of 4x32f Parallel Minimum
+*/
+#define	minss_m2r(var, reg)		sse_m2r(minss, var, reg)
+#define	minss_r2r(regs, regd)		sse_r2r(minss, regs, regd)
+#define	minss(vars, vard, xmmreg)	sse_m2m(minss, vars, vard, xmmreg)
+
+
+/*	4x32f Parallel CoMPares
+	(resulting fields are either 0 or -1)
+*/
+#define	cmpps_m2r(var, reg, op)		sse_m2ri(cmpps, var, reg, op)
+#define	cmpps_r2r(regs, regd, op)	sse_r2ri(cmpps, regs, regd, op)
+#define	cmpps(vars, vard, op, xmmreg)	sse_m2mi(cmpps, vars, vard, xmmreg, op)
+
+#define	cmpeqps_m2r(var, reg)		sse_m2ri(cmpps, var, reg, 0)
+#define	cmpeqps_r2r(regs, regd)		sse_r2ri(cmpps, regs, regd, 0)
+#define	cmpeqps(vars, vard, xmmreg)	sse_m2mi(cmpps, vars, vard, xmmreg, 0)
+
+#define	cmpltps_m2r(var, reg)		sse_m2ri(cmpps, var, reg, 1)
+#define	cmpltps_r2r(regs, regd)		sse_r2ri(cmpps, regs, regd, 1)
+#define	cmpltps(vars, vard, xmmreg)	sse_m2mi(cmpps, vars, vard, xmmreg, 1)
+
+#define	cmpleps_m2r(var, reg)		sse_m2ri(cmpps, var, reg, 2)
+#define	cmpleps_r2r(regs, regd)		sse_r2ri(cmpps, regs, regd, 2)
+#define	cmpleps(vars, vard, xmmreg)	sse_m2mi(cmpps, vars, vard, xmmreg, 2)
+
+#define	cmpunordps_m2r(var, reg)	sse_m2ri(cmpps, var, reg, 3)
+#define	cmpunordps_r2r(regs, regd)	sse_r2ri(cmpps, regs, regd, 3)
+#define	cmpunordps(vars, vard, xmmreg)	sse_m2mi(cmpps, vars, vard, xmmreg, 3)
+
+#define	cmpneqps_m2r(var, reg)		sse_m2ri(cmpps, var, reg, 4)
+#define	cmpneqps_r2r(regs, regd)	sse_r2ri(cmpps, regs, regd, 4)
+#define	cmpneqps(vars, vard, xmmreg)	sse_m2mi(cmpps, vars, vard, xmmreg, 4)
+
+#define	cmpnltps_m2r(var, reg)		sse_m2ri(cmpps, var, reg, 5)
+#define	cmpnltps_r2r(regs, regd)	sse_r2ri(cmpps, regs, regd, 5)
+#define	cmpnltps(vars, vard, xmmreg)	sse_m2mi(cmpps, vars, vard, xmmreg, 5)
+
+#define	cmpnleps_m2r(var, reg)		sse_m2ri(cmpps, var, reg, 6)
+#define	cmpnleps_r2r(regs, regd)	sse_r2ri(cmpps, regs, regd, 6)
+#define	cmpnleps(vars, vard, xmmreg)	sse_m2mi(cmpps, vars, vard, xmmreg, 6)
+
+#define	cmpordps_m2r(var, reg)		sse_m2ri(cmpps, var, reg, 7)
+#define	cmpordps_r2r(regs, regd)	sse_r2ri(cmpps, regs, regd, 7)
+#define	cmpordps(vars, vard, xmmreg)	sse_m2mi(cmpps, vars, vard, xmmreg, 7)
+
+
+/*	Lowest Field of 4x32f Parallel CoMPares
+	(resulting fields are either 0 or -1)
+*/
+#define	cmpss_m2r(var, reg, op)		sse_m2ri(cmpss, var, reg, op)
+#define	cmpss_r2r(regs, regd, op)	sse_r2ri(cmpss, regs, regd, op)
+#define	cmpss(vars, vard, op, xmmreg)	sse_m2mi(cmpss, vars, vard, xmmreg, op)
+
+#define	cmpeqss_m2r(var, reg)		sse_m2ri(cmpss, var, reg, 0)
+#define	cmpeqss_r2r(regs, regd)		sse_r2ri(cmpss, regs, regd, 0)
+#define	cmpeqss(vars, vard, xmmreg)	sse_m2mi(cmpss, vars, vard, xmmreg, 0)
+
+#define	cmpltss_m2r(var, reg)		sse_m2ri(cmpss, var, reg, 1)
+#define	cmpltss_r2r(regs, regd)		sse_r2ri(cmpss, regs, regd, 1)
+#define	cmpltss(vars, vard, xmmreg)	sse_m2mi(cmpss, vars, vard, xmmreg, 1)
+
+#define	cmpless_m2r(var, reg)		sse_m2ri(cmpss, var, reg, 2)
+#define	cmpless_r2r(regs, regd)		sse_r2ri(cmpss, regs, regd, 2)
+#define	cmpless(vars, vard, xmmreg)	sse_m2mi(cmpss, vars, vard, xmmreg, 2)
+
+#define	cmpunordss_m2r(var, reg)	sse_m2ri(cmpss, var, reg, 3)
+#define	cmpunordss_r2r(regs, regd)	sse_r2ri(cmpss, regs, regd, 3)
+#define	cmpunordss(vars, vard, xmmreg)	sse_m2mi(cmpss, vars, vard, xmmreg, 3)
+
+#define	cmpneqss_m2r(var, reg)		sse_m2ri(cmpss, var, reg, 4)
+#define	cmpneqss_r2r(regs, regd)	sse_r2ri(cmpss, regs, regd, 4)
+#define	cmpneqss(vars, vard, xmmreg)	sse_m2mi(cmpss, vars, vard, xmmreg, 4)
+
+#define	cmpnltss_m2r(var, reg)		sse_m2ri(cmpss, var, reg, 5)
+#define	cmpnltss_r2r(regs, regd)	sse_r2ri(cmpss, regs, regd, 5)
+#define	cmpnltss(vars, vard, xmmreg)	sse_m2mi(cmpss, vars, vard, xmmreg, 5)
+
+#define	cmpnless_m2r(var, reg)		sse_m2ri(cmpss, var, reg, 6)
+#define	cmpnless_r2r(regs, regd)	sse_r2ri(cmpss, regs, regd, 6)
+#define	cmpnless(vars, vard, xmmreg)	sse_m2mi(cmpss, vars, vard, xmmreg, 6)
+
+#define	cmpordss_m2r(var, reg)		sse_m2ri(cmpss, var, reg, 7)
+#define	cmpordss_r2r(regs, regd)	sse_r2ri(cmpss, regs, regd, 7)
+#define	cmpordss(vars, vard, xmmreg)	sse_m2mi(cmpss, vars, vard, xmmreg, 7)
+
+
+/*	Lowest Field of 4x32f Parallel CoMPares to set EFLAGS
+	(resulting fields are either 0 or -1)
+*/
+#define	comiss_m2r(var, reg)		sse_m2r(comiss, var, reg)
+#define	comiss_r2r(regs, regd)		sse_r2r(comiss, regs, regd)
+#define	comiss(vars, vard, xmmreg)	sse_m2m(comiss, vars, vard, xmmreg)
+
+
+/*	Lowest Field of 4x32f Unordered Parallel CoMPares to set EFLAGS
+	(resulting fields are either 0 or -1)
+*/
+#define	ucomiss_m2r(var, reg)		sse_m2r(ucomiss, var, reg)
+#define	ucomiss_r2r(regs, regd)		sse_r2r(ucomiss, regs, regd)
+#define	ucomiss(vars, vard, xmmreg)	sse_m2m(ucomiss, vars, vard, xmmreg)
+
+
+/*	2-(4x32f) -> 4x32f UNPaCK Low Packed Single-fp
+	(interleaves low half of dest with low half of source
+	 as padding in each result field)
+*/
+#define	unpcklps_m2r(var, reg)		sse_m2r(unpcklps, var, reg)
+#define	unpcklps_r2r(regs, regd)	sse_r2r(unpcklps, regs, regd)
+
+
+/*	2-(4x32f) -> 4x32f UNPaCK High Packed Single-fp
+	(interleaves high half of dest with high half of source
+	 as padding in each result field)
+*/
+#define	unpckhps_m2r(var, reg)		sse_m2r(unpckhps, var, reg)
+#define	unpckhps_r2r(regs, regd)	sse_r2r(unpckhps, regs, regd)
+
+
+
+/*	Fp and mmX ReSTORe state
+*/
+#ifdef	SSE_TRACE
+	#define	fxrstor(mem) \
+	{ \
+		fprintf(stderr, "fxrstor()\n"); \
+		__asm__ __volatile__ ("fxrstor %0" \
+			      : /* nothing */ \
+			      : "X" (mem)) \
+	}
+#else
+	#define	fxrstor(mem) \
+	__asm__ __volatile__ ("fxrstor %0" \
+			      : /* nothing */ \
+			      : "X" (mem))
+#endif
+
+
+/*	Fp and mmX SAVE state
+*/
+#ifdef	SSE_TRACE
+	#define	fxsave(mem) \
+	{ \
+		fprintf(stderr, "fxsave()\n"); \
+		__asm__ __volatile__ ("fxsave %0" \
+			      : /* nothing */ \
+			      : "X" (mem)) \
+	}
+#else
+	#define	fxsave(mem) \
+	__asm__ __volatile__ ("fxsave %0" \
+			      : /* nothing */ \
+			      : "X" (mem))
+#endif
+
+
+/*	STore streaMing simd eXtensions Control/Status Register
+*/
+#ifdef	SSE_TRACE
+	#define	stmxcsr(mem) \
+	{ \
+		fprintf(stderr, "stmxcsr()\n"); \
+		__asm__ __volatile__ ("stmxcsr %0" \
+			      : /* nothing */ \
+			      : "X" (mem)) \
+	}
+#else
+	#define	stmxcsr(mem) \
+	__asm__ __volatile__ ("stmxcsr %0" \
+			      : /* nothing */ \
+			      : "X" (mem))
+#endif
+
+
+/*	LoaD streaMing simd eXtensions Control/Status Register
+*/
+#ifdef	SSE_TRACE
+	#define	ldmxcsr(mem) \
+	{ \
+		fprintf(stderr, "ldmxcsr()\n"); \
+		__asm__ __volatile__ ("ldmxcsr %0" \
+			      : /* nothing */ \
+			      : "X" (mem)) \
+	}
+#else
+	#define	ldmxcsr(mem) \
+	__asm__ __volatile__ ("ldmxcsr %0" \
+			      : /* nothing */ \
+			      : "X" (mem))
+#endif
+
+
+/*	Store FENCE - enforce ordering of stores before fence vs. stores
+	occuring after fence in source code.
+*/
+#ifdef	SSE_TRACE
+	#define	sfence() \
+	{ \
+		fprintf(stderr, "sfence()\n"); \
+		__asm__ __volatile__ ("sfence\n\t") \
+	}
+#else
+	#define	sfence() \
+	__asm__ __volatile__ ("sfence\n\t")
+#endif
+
+
+/*	PREFETCH data using T0, T1, T2, or NTA hint
+		T0  = Prefetch into all cache levels
+		T1  = Prefetch into all cache levels except 0th level
+		T2  = Prefetch into all cache levels except 0th and 1st levels
+		NTA = Prefetch data into non-temporal cache structure
+*/
+#ifdef	SSE_TRACE
+#else
+	#define	prefetch(mem, hint) \
+	__asm__ __volatile__ ("prefetch" #hint " %0" \
+			      : /* nothing */ \
+			      : "X" (mem))
+
+	#define	prefetcht0(mem)		prefetch(mem, t0)
+	#define	prefetcht1(mem)		prefetch(mem, t1)
+	#define	prefetcht2(mem)		prefetch(mem, t2)
+	#define	prefetchnta(mem)	prefetch(mem, nta)
+#endif
+
+
+
+#endif
diff --git a/gst/deinterlace/tvtime/tomsmocomp.c b/gst/deinterlace/tvtime/tomsmocomp.c
new file mode 100644
index 0000000..003e72b
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
+ * Copyright (C) 2008,2010 Sebastian Dröge <slomo@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Relicensed for GStreamer from GPL to LGPL with permit from Tom Barry.
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <gst/gst.h>
+#ifdef HAVE_ORC
+#include <orc/orc.h>
+#endif
+#include "gstdeinterlacemethod.h"
+#include "plugins.h"
+
+#define GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP	(gst_deinterlace_method_tomsmocomp_get_type ())
+#define GST_IS_DEINTERLACE_METHOD_TOMSMOCOMP(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP))
+#define GST_IS_DEINTERLACE_METHOD_TOMSMOCOMP_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP))
+#define GST_DEINTERLACE_METHOD_TOMSMOCOMP_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP, GstDeinterlaceMethodTomsMoCompClass))
+#define GST_DEINTERLACE_METHOD_TOMSMOCOMP(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP, GstDeinterlaceMethodTomsMoComp))
+#define GST_DEINTERLACE_METHOD_TOMSMOCOMP_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP, GstDeinterlaceMethodTomsMoCompClass))
+#define GST_DEINTERLACE_METHOD_TOMSMOCOMP_CAST(obj)	((GstDeinterlaceMethodTomsMoComp*)(obj))
+
+typedef struct
+{
+  GstDeinterlaceMethod parent;
+
+  guint search_effort;
+  gboolean strange_bob;
+} GstDeinterlaceMethodTomsMoComp;
+
+typedef GstDeinterlaceMethodClass GstDeinterlaceMethodTomsMoCompClass;
+
+static void
+Fieldcopy (guint8 * dest, const guint8 * src, gint count,
+    gint rows, gint dst_pitch, gint src_pitch)
+{
+  gint i;
+
+  for (i = 0; i < rows; i++) {
+    memcpy (dest, src, count);
+    src += src_pitch;
+    dest += dst_pitch;
+  }
+}
+
+#define USE_FOR_DSCALER
+
+#define IS_C
+#define SIMD_TYPE C
+#define FUNCT_NAME tomsmocompDScaler_C
+#include "tomsmocomp/TomsMoCompAll.inc"
+#undef  IS_C
+#undef  SIMD_TYPE
+#undef  FUNCT_NAME
+
+#ifdef BUILD_X86_ASM
+
+#include "tomsmocomp/tomsmocompmacros.h"
+#include "x86-64_macros.inc"
+
+#define IS_MMX
+#define SIMD_TYPE MMX
+#define FUNCT_NAME tomsmocompDScaler_MMX
+#include "tomsmocomp/TomsMoCompAll.inc"
+#undef  IS_MMX
+#undef  SIMD_TYPE
+#undef  FUNCT_NAME
+
+#define IS_3DNOW
+#define SIMD_TYPE 3DNOW
+#define FUNCT_NAME tomsmocompDScaler_3DNOW
+#include "tomsmocomp/TomsMoCompAll.inc"
+#undef  IS_3DNOW
+#undef  SIMD_TYPE
+#undef  FUNCT_NAME
+
+#define IS_MMXEXT
+#define SIMD_TYPE MMXEXT
+#define FUNCT_NAME tomsmocompDScaler_MMXEXT
+#include "tomsmocomp/TomsMoCompAll.inc"
+#undef  IS_MMXEXT
+#undef  SIMD_TYPE
+#undef  FUNCT_NAME
+
+#endif
+
+G_DEFINE_TYPE (GstDeinterlaceMethodTomsMoComp,
+    gst_deinterlace_method_tomsmocomp, GST_TYPE_DEINTERLACE_METHOD);
+
+enum
+{
+  PROP_0,
+  PROP_SEARCH_EFFORT,
+  PROP_STRANGE_BOB
+};
+
+static void
+gst_deinterlace_method_tomsmocomp_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstDeinterlaceMethodTomsMoComp *self =
+      GST_DEINTERLACE_METHOD_TOMSMOCOMP (object);
+
+  switch (prop_id) {
+    case PROP_SEARCH_EFFORT:
+      self->search_effort = g_value_get_uint (value);
+      break;
+    case PROP_STRANGE_BOB:
+      self->strange_bob = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+gst_deinterlace_method_tomsmocomp_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstDeinterlaceMethodTomsMoComp *self =
+      GST_DEINTERLACE_METHOD_TOMSMOCOMP (object);
+
+  switch (prop_id) {
+    case PROP_SEARCH_EFFORT:
+      g_value_set_uint (value, self->search_effort);
+      break;
+    case PROP_STRANGE_BOB:
+      g_value_set_boolean (value, self->strange_bob);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+    gst_deinterlace_method_tomsmocomp_class_init
+    (GstDeinterlaceMethodTomsMoCompClass * klass)
+{
+  GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+#ifdef BUILD_X86_ASM
+  guint cpu_flags =
+      orc_target_get_default_flags (orc_target_get_by_name ("mmx"));
+#endif
+
+  gobject_class->set_property = gst_deinterlace_method_tomsmocomp_set_property;
+  gobject_class->get_property = gst_deinterlace_method_tomsmocomp_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_SEARCH_EFFORT,
+      g_param_spec_uint ("search-effort",
+          "Search Effort",
+          "Search Effort", 0, 27, 5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
+  g_object_class_install_property (gobject_class, PROP_STRANGE_BOB,
+      g_param_spec_boolean ("strange-bob",
+          "Strange Bob",
+          "Use strange bob", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
+  dim_class->fields_required = 4;
+  dim_class->name = "Motion Adaptive: Motion Search";
+  dim_class->nick = "tomsmocomp";
+  dim_class->latency = 1;
+
+#ifdef BUILD_X86_ASM
+  if (cpu_flags & ORC_TARGET_MMX_MMXEXT) {
+    dim_class->deinterlace_frame_yuy2 = tomsmocompDScaler_MMXEXT;
+    dim_class->deinterlace_frame_yvyu = tomsmocompDScaler_MMXEXT;
+  } else if (cpu_flags & ORC_TARGET_MMX_3DNOW) {
+    dim_class->deinterlace_frame_yuy2 = tomsmocompDScaler_3DNOW;
+    dim_class->deinterlace_frame_yvyu = tomsmocompDScaler_3DNOW;
+  } else if (cpu_flags & ORC_TARGET_MMX_MMX) {
+    dim_class->deinterlace_frame_yuy2 = tomsmocompDScaler_MMX;
+    dim_class->deinterlace_frame_yvyu = tomsmocompDScaler_MMX;
+  } else {
+    dim_class->deinterlace_frame_yuy2 = tomsmocompDScaler_C;
+    dim_class->deinterlace_frame_yvyu = tomsmocompDScaler_C;
+  }
+#else
+  dim_class->deinterlace_frame_yuy2 = tomsmocompDScaler_C;
+  dim_class->deinterlace_frame_yvyu = tomsmocompDScaler_C;
+#endif
+}
+
+static void
+gst_deinterlace_method_tomsmocomp_init (GstDeinterlaceMethodTomsMoComp * self)
+{
+  self->search_effort = 5;
+  self->strange_bob = FALSE;
+}
diff --git a/gst/deinterlace/tvtime/tomsmocomp/SearchLoop0A.inc b/gst/deinterlace/tvtime/tomsmocomp/SearchLoop0A.inc
new file mode 100644
index 0000000..b1d9aec
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/SearchLoop0A.inc
@@ -0,0 +1,15 @@
+// -*- c++ -*-
+
+// Searches just the center pixel, in both the old
+//  and new fields, but takes averages. This is an even
+// pixel address. Any chroma match will be used. (YUY2)
+// We best like finding 0 motion so we will bias everything we found previously
+// up by a little, and adjust later
+
+#ifdef IS_SSE2
+		"paddusb "_ONES", %%xmm7\n\t"				// bias toward no motion
+#else
+		"paddusb "_ONES", %%mm7\n\t" 				// bias toward no motion
+#endif
+
+        MERGE4PIXavg("(%%"XDI", %%"XCX")", "(%%"XSI", %%"XCX")")  // center, in old and new
diff --git a/gst/deinterlace/tvtime/tomsmocomp/SearchLoopBottom.inc b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopBottom.inc
new file mode 100644
index 0000000..e156035
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopBottom.inc
@@ -0,0 +1,174 @@
+// -*- c++ -*-       
+
+// Version for non-SSE2
+
+#ifndef IS_C
+
+#ifdef SKIP_SEARCH
+            "movq    %%mm6, %%mm0\n\t"            // just use the results of our wierd bob
+#else
+
+
+            // JA 9/Dec/2002
+            // failed experiment
+            // but leave in placeholder for me to play about
+#ifdef DONT_USE_STRANGE_BOB
+            // Use the best weave if diffs less than 10 as that
+            // means the image is still or moving cleanly
+            // if there is motion we will clip which will catch anything
+            "psubusb "_FOURS", %%mm7\n\t"          // sets bits to zero if weave diff < 4
+            "pxor    %%mm0, %%mm0\n\t"
+            "pcmpeqb %%mm0, %%mm7\n\t"            // all ff where weave better, else 00
+            "pcmpeqb %%mm7, %%mm0\n\t"            // all ff where bob better, else 00
+            "pand    %%mm6, %%mm0\n\t"            // use bob for these pixel values
+            "pand    %%mm5, %%mm7\n\t"            // use weave for these
+            "por     %%mm7, %%mm0\n\t"            // combine both
+#else
+            // Use the better of bob or weave
+            //      pminub  mm4, TENS           // the most we care about
+            V_PMINUB ("%%mm4", _TENS, "%%mm0")   // the most we care about
+            
+            "psubusb %%mm4, %%mm7\n\t"            // foregive that much from weave est?
+            "psubusb "_FOURS", %%mm7\n\t"       // bias it a bit toward weave
+            "pxor    %%mm0, %%mm0\n\t"
+            "pcmpeqb %%mm0, %%mm7\n\t"            // all ff where weave better, else 00
+            "pcmpeqb %%mm7, %%mm0\n\t"            // all ff where bob better, else 00
+            "pand    %%mm6, %%mm0\n\t"            // use bob for these pixel values
+            "pand    %%mm5, %%mm7\n\t"            // use weave for these
+            "por     %%mm7, %%mm0\n\t"            // combine both
+#endif
+            
+            
+                //      pminub  mm0, Max_Vals       // but clip to catch the stray error
+                V_PMINUB ("%%mm0", _Max_Vals, "%%mm1") // but clip to catch the stray error
+                //      pmaxub  mm0, Min_Vals
+                V_PMAXUB ("%%mm0", _Min_Vals)
+                
+#endif
+
+
+            MOVX"     "_pDest", %%"XAX"\n\t"
+                
+#ifdef USE_VERTICAL_FILTER
+            "movq    %%mm0, %%mm1\n\t"
+            //      pavgb   mm0, qword ptr["XBX"]
+            V_PAVGB ("%%mm0", "(%%"XBX")", "%%mm2", _ShiftMask)
+            //      movntq  qword ptr["XAX"+"XDX"], mm0
+            V_MOVNTQ ("(%"XAX", %%"XDX")", "%%mm0")
+            //      pavgb   mm1, qword ptr["XBX"+"XCX"]
+            V_PAVGB ("%%mm1", "(%%"XBX", %%"XCX")", "%%mm2", _ShiftMask)
+	    //FIXME: XDX or XAX!!
+            "addq   "_dst_pitchw", %%"XBX
+            //      movntq  qword ptr["XAX"+"XDX"], mm1
+            V_MOVNTQ ("(%%"XAX", %%"XDX")", "%%mm1")
+#else
+                
+            //      movntq  qword ptr["XAX"+"XDX"], mm0
+                V_MOVNTQ ("(%%"XAX", %%"XDX")", "%%mm0")
+#endif
+                
+           LEAX"    8(%%"XDX"), %%"XDX"\n\t"       // bump offset pointer
+           CMPX"    "_Last8", %%"XDX"\n\t"       // done with line?
+           "jb      1b\n\t"                    // y
+
+           MOVX" "_oldbx", %%"XBX"\n\t"
+
+        : /* no outputs */
+
+        : "m"(pBob),
+          "m"(src_pitch2),
+          "m"(ShiftMask),
+          "m"(pDest),
+          "m"(dst_pitchw),
+          "m"(Last8),
+          "m"(pSrc),
+          "m"(pSrcP),
+          "m"(pBobP),
+          "m"(DiffThres),
+          "m"(Min_Vals),
+          "m"(Max_Vals),
+          "m"(FOURS),
+          "m"(TENS),
+          "m"(ONES),
+          "m"(UVMask),
+          "m"(Max_Mov),
+          "m"(YMask),
+          "m"(oldbx)
+
+        : XAX, XCX, XDX, XSI, XDI,
+          "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
+#ifdef __MMX__
+          "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
+#endif
+          "memory", "cc"
+        );
+
+        // adjust for next line
+        pSrc  += src_pitch2;
+        pSrcP += src_pitch2;
+        pDest += dst_pitch2;
+        pBob  += src_pitch2;
+        pBobP += src_pitch2;
+    }
+    
+    return 0;
+#else
+#ifdef SKIP_SEARCH
+            out[0] = best[0];            // just use the results of our wierd bob
+	    out[1] = best[1];
+#else
+            diff[0] = diff[0] - MIN (diff[0], 10) - 4;
+	    diff[1] = diff[1] - MIN (diff[1] - 10) - 4;
+	    if (diff[0] < 0)
+	      out[0] = weave[0];
+	    else
+	      out[0] = best[0];
+	    
+	    if (diff[1] < 0)
+	      out[1] = weave[1];
+	    else
+	      out[1] = best[1];
+
+
+	    out[0] = CLAMP (out[0], MinVals[0], MaxVals[0]);
+	    out[1] = CLAMP (out[1], MinVals[1], MaxVals[1]);
+#endif
+
+#ifdef USE_VERTICAL_FILTER
+            pDest[x] = (out[0] + pBob[0]) / 2;
+	    pDest[x + dst_pitchw] = (pBob[src_pitch2] + out[0]) / 2;
+            pDest[x + 1] = (out[1] + pBob[1]) / 2;
+	    pDest[x + 1 + dst_pitchw] = (pBob[src_pitch2 + 1] + out[1]) / 2;
+#else
+            pDest[x] = out[0];
+	    pDest[x+1] = out[1];
+#endif
+            pBob += 2;
+            pBobP += 2;
+            pSrc += 2;
+            pSrcP += 2;
+	}
+        // adjust for next line
+        pSrc  = src_pitch2 * (y+1) + pWeaveSrc;
+        pSrcP = src_pitch2 * (y+1) + pWeaveSrcP;
+        pDest = dst_pitch2 * (y+1) + pWeaveDest + dst_pitch2;
+
+
+	if (TopFirst)
+	{
+		pBob = pCopySrc + src_pitch2;
+		pBobP = pCopySrcP + src_pitch2;
+	}
+	else
+	{
+		pBob =  pCopySrc;
+		pBobP =  pCopySrcP;
+	}
+
+        pBob  += src_pitch2 * (y+1);
+        pBobP += src_pitch2 * (y+1);
+    }
+    
+    return 0;
+
+#endif
diff --git a/gst/deinterlace/tvtime/tomsmocomp/SearchLoopEdgeA.inc b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopEdgeA.inc
new file mode 100644
index 0000000..6208fe8
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopEdgeA.inc
@@ -0,0 +1,11 @@
+// -*- c++ -*-
+
+// Searches 2 pixel to the left and right, in both the old
+//  and new fields, but takes averages. These are even
+// pixel addresses. Chroma match will be used. (YUY2)
+        MERGE4PIXavg("-4(%%"XDI")", "4(%%"XSI", %%"XCX", 2)")  // up left, down right
+        MERGE4PIXavg("4(%%"XDI")", "-4(%%"XSI", %%"XCX", 2)")  // up right, down left
+        MERGE4PIXavg("-4(%%"XDI", %%"XCX")", "4(%%"XSI", %%"XCX")") // left, right
+        MERGE4PIXavg("4(%%"XDI", %%"XCX")", "-4(%%"XSI", %%"XCX")") // right, left
+        MERGE4PIXavg("-4(%%"XDI", %%"XCX", 2)", "4(%%"XSI")")   // down left, up right
+        MERGE4PIXavg("4(%%"XDI", %%"XCX", 2)", "-4(%%"XSI")")   // down right, up left
diff --git a/gst/deinterlace/tvtime/tomsmocomp/SearchLoopEdgeA8.inc b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopEdgeA8.inc
new file mode 100644
index 0000000..2841c3f
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopEdgeA8.inc
@@ -0,0 +1,12 @@
+// -*- c++ -*-
+
+// Searches 4 pixel to the left and right, in both the old
+//  and new fields, but takes averages. These are even
+// pixel addresses. Chroma match will be used. (YUY2)
+        MERGE4PIXavg("-8(%%"XDI")", "8(%%"XSI", %%"XCX", 2)")  // up left, down right
+        MERGE4PIXavg("8(%%"XDI")", "-8(%%"XSI", %%"XCX", 2)")  // up right, down left
+        MERGE4PIXavg("-8(%%"XDI", %%"XCX")", "8(%%"XSI", %%"XCX")") // left, right
+        MERGE4PIXavg("8(%%"XDI", %%"XCX")", "-8(%%"XSI", %%"XCX")") // right, left
+        MERGE4PIXavg("-8(%%"XDI", %%"XCX", 2)", "8(%%"XSI")")   // down left, up right
+        MERGE4PIXavg("8(%%"XDI", %%"XCX", 2)", "-8(%%"XSI")")   // down right, up left
+
diff --git a/gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddA.inc b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddA.inc
new file mode 100644
index 0000000..ab5375f
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddA.inc
@@ -0,0 +1,10 @@
+// -*- c++ -*-
+
+// Searches 1 pixel to the left and right, in both the old
+//  and new fields, but takes averages. These are odd
+// pixel addresses. Any chroma match will not be used. (YUY2)
+        MERGE4PIXavg("-2(%%"XDI")", "2(%%"XSI", %%"XCX", 2)")  // up left, down right
+        MERGE4PIXavg("2(%%"XDI")", "-2(%%"XSI", %%"XCX", 2)")  // up right, down left
+        MERGE4PIXavg("-2(%%"XDI", %%"XCX", 2)", "2(%%"XSI")")   // down left, up right
+        MERGE4PIXavg("2(%%"XDI", %%"XCX", 2)", "-2(%%"XSI")")   // down right, up left   
+#include "SearchLoopOddA2.inc"
diff --git a/gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddA2.inc b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddA2.inc
new file mode 100644
index 0000000..fd3f6fb
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddA2.inc
@@ -0,0 +1,5 @@
+// Searches 1 pixel to the left and right, in both the old
+// and new fields, but takes averages. These are odd
+// pixel addresses. Any chroma match will not be used. (YUY2)
+        MERGE4PIXavg("-2(%%"XDI", %%"XCX")", "2(%%"XSI", %%"XCX")") // left, right
+        MERGE4PIXavg("2(%%"XDI", %%"XCX")", "-2(%%"XSI", %%"XCX")") // right, left
diff --git a/gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddA6.inc b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddA6.inc
new file mode 100644
index 0000000..cbae014
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddA6.inc
@@ -0,0 +1,11 @@
+// -*- c++ -*-
+
+// Searches 3 pixels to the left and right, in both the old
+//  and new fields, but takes averages. These are odd
+// pixel addresses. Any chroma match will not be used. (YUY2)
+        MERGE4PIXavg("-6(%%"XDI")", "6(%%"XSI", %%"XCX", 2)")  // up left, down right
+        MERGE4PIXavg("6(%%"XDI")", "-6(%%"XSI", %%"XCX", 2)")  // up right, down left
+        MERGE4PIXavg("-6(%%"XDI", %%"XCX")", "6(%%"XSI", %%"XCX")") // left, right
+        MERGE4PIXavg("6(%%"XDI", %%"XCX")", "-6(%%"XSI", %%"XCX")") // right, left
+        MERGE4PIXavg("-6(%%"XDI", %%"XCX", 2)", "6(%%"XSI")")   // down left, up right
+        MERGE4PIXavg("6(%%"XDI", %%"XCX", 2)", "-6(%%"XSI")")   // down right, up left
diff --git a/gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddAH.inc b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddAH.inc
new file mode 100644
index 0000000..e59e3c7
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddAH.inc
@@ -0,0 +1,10 @@
+// Searches 1 pixel to the left and right, in both the old

+//  and new fields, but takes v-half pel averages. These are odd

+// pixel addresses. Any chroma match will not be used. (YUY2)

+		__asm

+		{

+        MERGE4PIXavgH("XDI"-2, "XDI"+"XCX"-2, "XSI"+"XCX"+2, "XSI"+2*"XCX"+2)  // up left, down right

+        MERGE4PIXavgH("XDI"+2, "XDI"+"XCX"+2, "XSI"+"XCX"-2, "XSI"+2*"XCX"-2)   // up right, down left

+        MERGE4PIXavgH("XDI"+2*"XCX"-2, "XDI"+"XCX"-2, "XSI"+"XCX"+2, "XSI"+2)   // down left, up right

+        MERGE4PIXavgH("XDI"+2*"XCX"+2, "XDI"+"XCX"+2, "XSI"+"XCX"-2, "XSI"-2)   // down right, up left   

+		}

diff --git a/gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddAH2.inc b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddAH2.inc
new file mode 100644
index 0000000..cd7d812
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopOddAH2.inc
@@ -0,0 +1,5 @@
+// Searches 1 pixel to the left and right, in both the old
+//  and new fields, but takes vertical averages. These are odd
+// pixel addresses. Any chroma match will not be used. (YUY2)
+     MERGE4PIXavgH("-2(%%"XDI", %%"XCX")", "(%%"XDI", %%"XCX")", "(%%"XSI", %%"XCX")", "2(%%"XSI", %%"XCX")") // left, right
+     MERGE4PIXavgH("2(%%"XDI", %%"XCX")", "(%%"XDI", %%"XCX")", "(%%"XSI", %%"XCX")", "-2(%%"XSI", %%"XCX")") // right, left
diff --git a/gst/deinterlace/tvtime/tomsmocomp/SearchLoopTop.inc b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopTop.inc
new file mode 100644
index 0000000..275c7dd
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopTop.inc
@@ -0,0 +1,254 @@
+// -*- c++ -*-
+
+unsigned char* pDest;
+const unsigned char* pSrcP;
+const unsigned char* pSrc;
+const unsigned char* pBob;
+const unsigned char* pBobP;
+
+// long is int32 on ARCH_368, int64 on ARCH_AMD64. Declaring it this way
+// saves a lot of xor's to delete 64bit garbage.
+
+#if defined(DBL_RESIZE) || defined(USE_FOR_DSCALER)
+long	    src_pitch2 = src_pitch;			// even & odd lines are not interleaved in DScaler
+#else
+long	    src_pitch2 = 2 * src_pitch;		// even & odd lines are interleaved in Avisynth
+#endif
+
+
+long	    dst_pitch2 = 2 * dst_pitch;
+long        y;
+
+long     Last8;
+
+	pSrc  = pWeaveSrc;			// points 1 weave line above
+	pSrcP = pWeaveSrcP;			// " 
+
+#ifdef DBL_RESIZE
+	        
+#ifdef USE_VERTICAL_FILTER
+	pDest = pWeaveDest + dst_pitch2;
+#else
+	pDest = pWeaveDest + 3*dst_pitch;
+#endif
+
+#else
+
+#ifdef USE_VERTICAL_FILTER
+	pDest = pWeaveDest + dst_pitch;
+#else
+	pDest = pWeaveDest + dst_pitch2;
+#endif
+
+#endif
+
+	if (TopFirst)
+	{
+		pBob = pCopySrc + src_pitch2;      // remember one weave line just copied previously
+		pBobP = pCopySrcP + src_pitch2;
+	}
+	else
+	{
+		pBob =  pCopySrc;
+		pBobP =  pCopySrcP;
+	}
+
+#ifndef IS_C
+
+#ifndef _pBob
+#define _pBob       "%0"
+#define _src_pitch2 "%1"
+#define _ShiftMask  "%2"
+#define _pDest      "%3"
+#define _dst_pitchw "%4"
+#define _Last8      "%5"
+#define _pSrc       "%6"
+#define _pSrcP      "%7"
+#define _pBobP      "%8"
+#define _DiffThres  "%9"
+#define _Min_Vals   "%10"
+#define _Max_Vals   "%11"
+#define _FOURS      "%12"
+#define _TENS       "%13"
+#define _ONES       "%14"
+#define _UVMask     "%15"
+#define _Max_Mov    "%16"
+#define _YMask      "%17"
+#define _oldbx      "%18"
+#endif
+        Last8 = (rowsize-8);
+
+	for (y=1; y < FldHeight-1; y++)	
+	{	
+          long	dst_pitchw = dst_pitch; // local stor so asm can ref
+          int64_t Max_Mov   = 0x0404040404040404ull; 
+          int64_t DiffThres = 0x0f0f0f0f0f0f0f0full; 
+          int64_t YMask     = 0x00ff00ff00ff00ffull; // keeps only luma
+          int64_t UVMask    = 0xff00ff00ff00ff00ull; // keeps only chroma
+          int64_t TENS      = 0x0a0a0a0a0a0a0a0aull; 
+          int64_t FOURS     = 0x0404040404040404ull; 
+          int64_t ONES      = 0x0101010101010101ull; 
+          int64_t Min_Vals  = 0x0000000000000000ull;
+          int64_t Max_Vals  = 0x0000000000000000ull;
+          int64_t ShiftMask = 0xfefffefffefffeffull;
+
+          long oldbx = 0;
+
+		// pretend it's indented -->>
+        __asm__ __volatile__
+            (
+             // Loop general reg usage
+             //
+             // XAX - pBobP, then pDest 
+             // XBX - pBob
+             // XCX - src_pitch2
+             // XDX - current offset
+             // XDI - prev weave pixels, 1 line up
+             // XSI - next weave pixels, 1 line up
+
+             // Save "XBX" (-fPIC)
+	     MOVX" %%"XBX", "_oldbx"\n\t"
+             
+             // simple bob first 8 bytes
+             MOVX"	"_pBob",        %%"XBX"\n\t"
+             MOVX"	"_src_pitch2",  %%"XCX"\n\t"
+
+#ifdef USE_VERTICAL_FILTER
+             "movq	    (%%"XBX"),        %%mm0\n\t"
+             "movq	    (%%"XBX", %%"XCX"), %%mm1\n\t" //, qword ptr["XBX"+"XCX"]
+             "movq	    %%mm0,          %%mm2\n\t"
+             V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask)		// halfway between
+             V_PAVGB ("%%mm0", "%%mm2", "%%mm3", _ShiftMask)		// 1/4 way
+             V_PAVGB ("%%mm1", "%%mm2", "%%mm3", _ShiftMask)		// 3/4 way
+             MOVX"		"_pDest",       %%"XDI"\n\t"
+             MOVX"		"_dst_pitchw",  %%"XAX"\n\t"
+             V_MOVNTQ	("(%%"XDI")", "%%mm0")
+             V_MOVNTQ	("(%%"XDI", %%"XAX")", "%%mm1") // qword ptr["XDI"+"XAX"], mm1
+
+             // simple bob last 8 bytes
+             MOVX"		"_Last8", %%"XDX"\n\t"
+             LEAX"		(%%"XBX", %%"XDX"), %%"XSI"\n\t"  // ["XBX"+"XDX"]
+             "movq	    (%%"XSI"), %%mm0\n\t"
+             "movq	    (%%"XSI", %%"XCX"), %%mm1\n\t"    // qword ptr["XSI"+"XCX"]
+             "movq	    %%mm0, %%mm2\n\t"
+             V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask)		// halfway between
+             V_PAVGB ("%%mm0", "%%mm2", "%%mm3", _ShiftMask)		// 1/4 way
+             V_PAVGB ("%%mm1", "%%mm2", "%%mm3", _ShiftMask)		// 3/4 way
+             ADDX"		%%"XDX", %%"XDI"\n\t"						// last 8 bytes of dest
+             V_MOVNTQ	("%%"XDI"", "%%mm0")
+             V_MOVNTQ	("(%%"XDI", %%"XAX")", "%%mm1") // qword ptr["XDI"+"XAX"], mm1)
+
+#else
+             "movq	(%%"XBX"), %%mm0\n\t"
+             //		pavgb	mm0, qword ptr["XBX"+"XCX"]
+             V_PAVGB ("%%mm0", "(%%"XBX", %%"XCX")", "%%mm2", _ShiftMask) // qword ptr["XBX"+"XCX"], mm2, ShiftMask)
+             MOVX"		"_pDest", %%"XDI"\n\t"
+             V_MOVNTQ	("(%%"XDI")", "%%mm0")
+
+             // simple bob last 8 bytes
+             MOVX"		"_Last8", %%"XDX"\n\t"
+             LEAX"		(%%"XBX", %%"XDX"), %%"XSI"\n\t" //"XSI", ["XBX"+"XDX"]
+             "movq	    (%%"XSI"), %%mm0\n\t"
+             //		pavgb	mm0, qword ptr["XSI"+"XCX"]
+             V_PAVGB	("%%mm0", "(%%"XSI", %%"XCX")", "%%mm2", _ShiftMask) // qword ptr["XSI"+"XCX"], mm2, ShiftMask)
+             V_MOVNTQ	("(%%"XDI", %%"XDX")", "%%mm0") // qword ptr["XDI"+"XDX"], mm0)
+#endif
+             // now loop and get the middle qwords
+             MOVX"		"_pSrc", %%"XSI"\n\t"
+             MOVX"		"_pSrcP", %%"XDI"\n\t"
+             MOVX"		$8, %%"XDX"\n\t"				// curr offset longo all lines
+
+             "1:\n\t"	
+             MOVX"		"_pBobP", %%"XAX"\n\t"
+             ADDX"		$8, %%"XDI"\n\t"
+             ADDX"		$8, %%"XSI"\n\t"
+             ADDX"		$8, %%"XBX"\n\t"
+             ADDX"		%%"XDX", %%"XAX"\n\t"
+
+#ifdef USE_STRANGE_BOB
+#include "StrangeBob.inc"
+#else
+#include "WierdBob.inc"
+#endif
+
+             // For non-SSE2:
+             // through out most of the rest of this loop we will maintain
+             //	mm4		our min bob value
+             //	mm5		best weave pixels so far
+             // mm6		our max Bob value 
+             //	mm7		best weighted pixel ratings so far
+             
+             // We will keep a slight bias to using the weave pixels
+             // from the current location, by rating them by the min distance
+             // from the Bob value instead of the avg distance from that value.
+             // our best and only rating so far
+             "pcmpeqb	%%mm7, %%mm7\n\t"			// ffff, say we didn't find anything good yet
+
+#else
+        Last8 = (rowsize - 4);
+
+	for (y=1; y < FldHeight-1; y++)
+	{
+	  #ifdef USE_STRANGE_BOB
+	  long DiffThres = 0x0f;
+	  #endif
+
+	  #ifndef SKIP_SEARCH
+	  long weave[2], MaxVals[2], MinVals[2];
+	  #endif
+
+	  long diff[2], best[2], avg[2], diff2[2], out[2], x;
+
+#ifdef USE_VERTICAL_FILTER
+             pDest[0] = (3 * pBob[0] + pBob[src_pitch2]) / 4;
+             pDest[1] = (3 * pBob[1] + pBob[src_pitch2 + 1]) / 4;
+             pDest[2] = (3 * pBob[2] + pBob[src_pitch2 + 2]) / 4;
+             pDest[3] = (3 * pBob[3] + pBob[src_pitch2 + 3]) / 4;
+	     pDest[dst_pitchw] = (pBob[0] + 3 * pBob[src_pitch2]) / 4;
+	     pDest[dst_pitchw + 1] = (pBob[1] + 3 * pBob[src_pitch2 + 1]) / 4;
+	     pDest[dst_pitchw + 2] = (pBob[2] + 3 * pBob[src_pitch2 + 2]) / 4;
+	     pDest[dst_pitchw + 3] = (pBob[3] + 3 * pBob[src_pitch2 + 3]) / 4;
+
+             // simple bob last byte
+	     pDest[Last8] = (3 * pBob[Last8] + pBob[Last8 + src_pitch2]) / 4;
+	     pDest[Last8 + 1] = (3 * pBob[Last8 + 1] + pBob[Last8 + src_pitch2 + 1]) / 4;
+	     pDest[Last8 + 2] = (3 * pBob[Last8 + 2] + pBob[Last8 + src_pitch2 + 2]) / 4;
+	     pDest[Last8 + 3] = (3 * pBob[Last8 + 3] + pBob[Last8 + src_pitch2 + 3]) / 4;
+	     pDest[Last8 + src_pitch2] = (pBob[Last8] + 3 * pBob[Last8 + src_pitch2]) / 4;
+	     pDest[Last8 + src_pitch2 + 1] = (pBob[Last8 + 1] + 3 * pBob[Last8 + src_pitch2 + 1]) / 4;
+	     pDest[Last8 + src_pitch2 + 2] = (pBob[Last8 + 2] + 3 * pBob[Last8 + src_pitch2 + 2]) / 4;
+	     pDest[Last8 + src_pitch2 + 3] = (pBob[Last8 + 3] + 3 * pBob[Last8 + src_pitch2 + 3]) / 4;
+#else
+             pDest[0] = (pBob[0] + pBob[src_pitch2 + 1]) / 2;
+             pDest[1] = (pBob[1] + pBob[src_pitch2 + 1]) / 2;
+             pDest[2] = (pBob[2] + pBob[src_pitch2 + 2]) / 2;
+             pDest[3] = (pBob[3] + pBob[src_pitch2 + 3]) / 2;
+
+             // simple bob last byte
+	     pDest[Last8] = (pBob[Last8] + pBob[Last8 + src_pitch2]) / 2;
+	     pDest[Last8 + 1] = (pBob[Last8 + 1] + pBob[Last8 + src_pitch2 + 1]) / 2;
+	     pDest[Last8 + 2] = (pBob[Last8 + 2] + pBob[Last8 + src_pitch2 + 2]) / 2;
+	     pDest[Last8 + 3] = (pBob[Last8 + 3] + pBob[Last8 + src_pitch2 + 3]) / 2;
+#endif
+
+             pBob += 4;
+	     pBobP += 4;
+	     pSrc += 4;
+	     pSrcP += 4;
+
+             for (x=4; x < Last8; x += 2) {
+
+#ifdef USE_STRANGE_BOB
+#include "StrangeBob.inc"
+#else
+#include "WierdBob.inc"
+#endif
+
+             // We will keep a slight bias to using the weave pixels
+             // from the current location, by rating them by the min distance
+             // from the Bob value instead of the avg distance from that value.
+             // our best and only rating so far
+             diff[0] = diff[1] = 255;
+
+
+#endif
diff --git a/gst/deinterlace/tvtime/tomsmocomp/SearchLoopVA.inc b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopVA.inc
new file mode 100644
index 0000000..3e3d19b
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopVA.inc
@@ -0,0 +1,6 @@
+// -*- c++ -*-
+
+// Searches the center vertical line above center and below, in both the old 
+// and new fields, but takes averages.  These are even pixel addresses.
+        MERGE4PIXavg("(%%"XDI", %%"XCX", 2)", "(%%"XSI")")	// down, up
+        MERGE4PIXavg("(%%"XDI")", "(%%"XSI", %%"XCX", 2)")	// up, down
diff --git a/gst/deinterlace/tvtime/tomsmocomp/SearchLoopVAH.inc b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopVAH.inc
new file mode 100644
index 0000000..33155bc
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopVAH.inc
@@ -0,0 +1,6 @@
+// -*- c++ -*-
+
+// Searches the center vertical line above center and below, in both the old 
+// and new fields, but takes averages.  These are even pixel addresses.
+        MERGE4PIXavgH("(%%"XDI", %%"XCX", 2)", "(%%"XDI", %%"XCX")", "(%%"XSI", %%"XCX")", "(%%"XSI")")	// down, up
+        MERGE4PIXavgH("(%%"XDI")", "(%%"XDI", %%"XCX")", "(%%"XSI", %%"XCX")", "(%%"XSI", %%"XCX", 2)")	// up, down
diff --git a/gst/deinterlace/tvtime/tomsmocomp/StrangeBob.inc b/gst/deinterlace/tvtime/tomsmocomp/StrangeBob.inc
new file mode 100644
index 0000000..45b4c86
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/StrangeBob.inc
@@ -0,0 +1,435 @@
+// -*- c++ -*-
+		
+		// First, get and save our possible Bob values
+		// Assume our pixels are layed out as follows with x the calc'd bob value
+		// and the other pixels are from the current field
+		//  
+		//	  j a b c k		current field
+		//            x			calculated line
+		//        m d e f n		current field
+		//
+		// we calc the bob value luma value as:
+        // if |j - n| < Thres && |a - m| > Thres 
+        //  avg(j,n)
+        // end if
+        // if |k - m| < Thres && |c - n| > Thres 
+        //  avg(k,m)
+        // end if
+        // if |c - d| < Thres && |b - f| > Thres 
+        //  avg(c,d)
+        // end if
+        // if |a - f| < Thres && |b - d| > Thres 
+        //  avg(a,f)
+        // end if
+        // if |b - e| < Thres
+        //  avg(b,e)
+        // end if
+        // pickup any thing not yet set with avg(b,e)
+
+#ifndef IS_C
+
+		// j, n
+        "pxor %%mm5, %%mm5\n\t"
+        "pxor %%mm6, %%mm6\n\t"
+        "pxor %%mm7, %%mm7\n\t"
+
+		"movq    -2(%%"XBX"), %%mm0\n\t"		// value a from top left		
+		"movq    -4(%%"XBX", %%"XCX"), %%mm1\n\t"	// value m from bottom right			
+        
+		"movq	%%mm0, %%mm3\n\t"
+		"psubusb	%%mm1, %%mm3\n\t"
+		"psubusb %%mm0, %%mm1\n\t"
+		"por		%%mm1, %%mm3\n\t"					// abs(a,m)
+
+		"psubusb "_DiffThres", %%mm3\n\t"		// nonzero where abs(a,m) > Thres else 0
+		"pxor	%%mm4, %%mm4\n\t"
+		"pcmpeqb %%mm4, %%mm3\n\t"			// now ff where abs(a,m) < Thres, else 00	
+		"pcmpeqb	%%mm3, %%mm4\n\t"			// here ff where abs(a,m) > Thres, else 00
+
+
+		"movq    -4(%%"XBX"), %%mm0\n\t"		// value j
+		"movq    4(%%"XBX", %%"XCX"), %%mm1\n\t"	// value n
+		"movq	%%mm0, %%mm2\n\t"					
+		V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask)	// avg(j,n)
+        "movq	%%mm0, %%mm3\n\t"
+		"psubusb	%%mm1, %%mm0\n\t"
+		"psubusb %%mm3, %%mm1\n\t"
+		"por		%%mm1, %%mm0\n\t"					// abs(j,n)
+
+        "movq    %%mm0, %%mm1\n\t"
+		"psubusb "_DiffThres", %%mm1\n\t"		// nonzero where abs(j,n) > Thres else 0
+		"pxor	%%mm3, %%mm3\n\t"
+		"pcmpeqb %%mm3, %%mm1\n\t"			// now ff where abs(j,n) < Thres, else 00	
+
+        "pand    %%mm4, %%mm1\n\t"
+        "pand    %%mm1, %%mm2\n\t"
+        "pand    %%mm1, %%mm0\n\t"
+
+        "movq    %%mm1, %%mm3\n\t"
+        "pxor    %%mm5, %%mm3\n\t"
+        "pand    %%mm3, %%mm6\n\t"
+        "pand    %%mm3, %%mm7\n\t"
+        "pand    %%mm3, %%mm5\n\t"
+
+        "por     %%mm1, %%mm5\n\t"
+        "por     %%mm2, %%mm6\n\t"
+        "por     %%mm0, %%mm7\n\t"
+        
+        // k & m
+		"movq    2(%%"XBX"), %%mm0\n\t"		// value c from top left		
+		"movq    4(%%"XBX", %%"XCX"), %%mm1\n\t"	// value n from bottom right			
+
+		"movq	%%mm0, %%mm3\n\t"
+		"psubusb	%%mm1, %%mm3\n\t"
+		"psubusb %%mm0, %%mm1\n\t"
+		"por		%%mm1, %%mm3\n\t"					// abs(c,n)
+
+		"psubusb "_DiffThres", %%mm3\n\t"		// nonzero where abs(c,n) > Thres else 0
+		"pxor	%%mm4, %%mm4\n\t"
+		"pcmpeqb %%mm4, %%mm3\n\t"			// now ff where abs(c,n) < Thres, else 00	
+		"pcmpeqb	%%mm3, %%mm4\n\t"			// here ff where abs(c,n) > Thres, else 00
+
+
+		"movq    4(%%"XBX"), %%mm0\n\t"		// value k
+		"movq    -4(%%"XBX", %%"XCX"), %%mm1\n\t"	// value m
+		"movq	%%mm0, %%mm2\n\t"					
+		V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask)	// avg(k,m)
+        "movq	%%mm0, %%mm3\n\t"
+		"psubusb	%%mm1, %%mm0\n\t"
+		"psubusb %%mm3, %%mm1\n\t"
+		"por		%%mm1, %%mm0\n\t"					// abs(k,m)
+
+        "movq    %%mm0, %%mm1\n\t"
+		"psubusb "_DiffThres", %%mm1\n\t"		// nonzero where abs(k,m) > Thres else 0
+		"pxor	%%mm3, %%mm3\n\t"
+		"pcmpeqb %%mm3, %%mm1\n\t"			// now ff where abs(k,m) < Thres, else 00	
+
+        "pand    %%mm4, %%mm1\n\t"
+        
+        "pand    %%mm1, %%mm2\n\t"
+        "pand    %%mm1, %%mm0\n\t"
+
+        "movq    %%mm1, %%mm3\n\t"
+        "pxor    %%mm5, %%mm3\n\t"
+        "pand    %%mm3, %%mm6\n\t"
+        "pand    %%mm3, %%mm7\n\t"
+        "pand    %%mm3, %%mm5\n\t"
+
+        "por     %%mm1, %%mm5\n\t"
+        "por     %%mm2, %%mm6\n\t"
+        "por     %%mm0, %%mm7\n\t"
+
+
+        // c & d
+		"movq    (%%"XBX"), %%mm0\n\t"		// value b from top left		
+		"movq    2(%%"XBX", %%"XCX"), %%mm1\n\t"	// value f from bottom right			
+
+		"movq	%%mm0, %%mm3\n\t"
+		"psubusb	%%mm1, %%mm3\n\t"
+		"psubusb %%mm0, %%mm1\n\t"
+		"por		%%mm1, %%mm3\n\t"					// abs(b,f)
+
+		"psubusb "_DiffThres", %%mm3\n\t"		// nonzero where abs(b,f) > Thres else 0
+		"pxor	%%mm4, %%mm4\n\t"
+		"pcmpeqb %%mm4, %%mm3\n\t"			// now ff where abs(b,f) < Thres, else 00	
+		"pcmpeqb	%%mm3, %%mm4\n\t"			// here ff where abs(b,f) > Thres, else 00
+
+		"movq    2(%%"XBX"), %%mm0\n\t"		// value c
+		"movq    -2(%%"XBX", %%"XCX"), %%mm1\n\t"	// value d
+		"movq	%%mm0, %%mm2\n\t"					
+		V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask)	// avg(c,d)
+        "movq	%%mm0, %%mm3\n\t"
+		"psubusb	%%mm1, %%mm0\n\t"
+		"psubusb %%mm3, %%mm1\n\t"
+		"por		%%mm1, %%mm0\n\t"					// abs(c,d)
+
+        "movq    %%mm0, %%mm1\n\t"
+		"psubusb "_DiffThres", %%mm1\n\t"		// nonzero where abs(c,d) > Thres else 0
+		"pxor	%%mm3, %%mm3\n\t"
+        "pcmpeqb %%mm3, %%mm1\n\t"			// now ff where abs(c,d) < Thres, else 00	
+
+        "pand    %%mm4, %%mm1\n\t"
+
+        "pand    %%mm1, %%mm2\n\t"
+        "pand    %%mm1, %%mm0\n\t"
+
+        "movq    %%mm1, %%mm3\n\t"
+        "pxor    %%mm5, %%mm3\n\t"
+        "pand    %%mm3, %%mm6\n\t"
+        "pand    %%mm3, %%mm7\n\t"
+        "pand    %%mm3, %%mm5\n\t"
+
+        "por     %%mm1, %%mm5\n\t"
+        "por     %%mm2, %%mm6\n\t"
+        "por     %%mm0, %%mm7\n\t"
+
+        // a & f
+		"movq    (%%"XBX"), %%mm0\n\t"		// value b from top left		
+		"movq    -2(%%"XBX", %%"XCX"), %%mm1\n\t"	// value d from bottom right			
+
+		"movq	%%mm0, %%mm3\n\t"
+		"psubusb	%%mm1, %%mm3\n\t"
+		"psubusb %%mm0, %%mm1\n\t"
+		"por		%%mm1, %%mm3\n\t"					// abs(b,d)
+
+		"psubusb "_DiffThres", %%mm3\n\t"	// nonzero where abs(b,d) > Thres else 0
+		"pxor	%%mm4, %%mm4\n\t"
+		"pcmpeqb %%mm4, %%mm3\n\t"			// now ff where abs(b,d) < Thres, else 00	
+		"pcmpeqb	%%mm3, %%mm4\n\t"			// here ff where abs(b,d) > Thres, else 00
+
+		"movq    -2(%%"XBX"), %%mm0\n\t"		// value a
+		"movq    2(%%"XBX", %%"XCX"), %%mm1\n\t"	// value f
+		"movq	%%mm0, %%mm2\n\t"					
+		V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask)	// avg(a,f)
+        "movq	%%mm0, %%mm3\n\t"
+        "psubusb	%%mm1, %%mm0\n\t"
+		"psubusb %%mm3, %%mm1\n\t"
+		"por		%%mm1, %%mm0\n\t"					// abs(a,f)
+
+        "movq    %%mm0, %%mm1\n\t"
+		"psubusb "_DiffThres", %%mm1\n\t"		// nonzero where abs(a,f) > Thres else 0
+		"pxor	%%mm3, %%mm3\n\t"
+		"pcmpeqb %%mm3, %%mm1\n\t"			// now ff where abs(a,f) < Thres, else 00	
+
+        "pand    %%mm4, %%mm1\n\t"
+
+        "pand    %%mm1, %%mm2\n\t"
+        "pand    %%mm1, %%mm0\n\t"
+            
+        "movq    %%mm1, %%mm3\n\t"
+        "pxor    %%mm5, %%mm3\n\t"
+        "pand    %%mm3, %%mm6\n\t"
+        "pand    %%mm3, %%mm7\n\t"
+        "pand    %%mm3, %%mm5\n\t"
+
+        "por     %%mm1, %%mm5\n\t"
+        "por     %%mm2, %%mm6\n\t"
+        "por     %%mm0, %%mm7\n\t"
+           
+ 		"pand	"_YMask", %%mm5\n\t"		// mask out chroma from here
+ 		"pand	"_YMask", %%mm6\n\t"			// mask out chroma from here
+ 		"pand	"_YMask", %%mm7\n\t"			// mask out chroma from here
+
+		// b,e
+		"movq    (%%"XBX"), %%mm0\n\t"		// value b from top 		
+		"movq    (%%"XBX", %%"XCX"), %%mm1\n\t"	// value e from bottom 
+		"movq	%%mm0, %%mm2\n\t"					
+		V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask)	// avg(b,e)
+        "movq	%%mm0, %%mm3\n\t"
+        "psubusb	%%mm1, %%mm0\n\t"
+		"psubusb %%mm3, %%mm1\n\t"
+		"por		%%mm1, %%mm0\n\t"					// abs(b,e)
+
+        "movq    %%mm0, %%mm1\n\t"
+		"psubusb "_DiffThres", %%mm1\n\t"		// nonzero where abs(b,e) > Thres else 0
+		"pxor	%%mm3, %%mm3\n\t"
+		"pcmpeqb %%mm3, %%mm1\n\t"		// now ff where abs(b,e) < Thres, else 00	
+
+        "pand    %%mm1, %%mm2\n\t"
+        "pand    %%mm1, %%mm0\n\t"
+
+        "movq    %%mm1, %%mm3\n\t"
+        "pxor    %%mm5, %%mm3\n\t"
+        "pand    %%mm3, %%mm6\n\t"
+        "pand    %%mm3, %%mm7\n\t"
+        "pand    %%mm3, %%mm5\n\t"
+
+        "por     %%mm1, %%mm5\n\t"
+        "por     %%mm2, %%mm6\n\t"
+        "por     %%mm0, %%mm7\n\t"
+
+		// bob in any leftovers
+		"movq    (%%"XBX"), %%mm0\n\t"		// value b from top 		
+		"movq    (%%"XBX", %%"XCX"), %%mm1\n\t"	// value e from bottom 
+
+
+// We will also calc here the max/min values to later limit comb
+// so the max excursion will not exceed the Max_Comb constant
+
+#ifdef SKIP_SEARCH		
+		"movq	%%mm0, %%mm2\n\t"
+//		pminub	%%mm2, %%mm1
+		V_PMINUB ("%%mm2", "%%mm1", "%%mm4")
+
+//		pmaxub	%%mm6, %%mm2			// clip our current results so far to be above this
+		V_PMAXUB ("%%mm6", "%%mm2")
+        "movq	%%mm0, %%mm2\n\t"
+		V_PMAXUB ("%%mm2", "%%mm1")
+//		pminub	%%mm6, %%mm2			// clip our current results so far to be below this
+		V_PMINUB ("%%mm6", "%%mm2", "%%mm4")
+
+#else
+        "movq	%%mm0, %%mm2\n\t"
+		"movq	(%%"XAX"), %%mm4\n\t"
+		"psubusb %%mm4, %%mm2\n\t"
+		"psubusb %%mm0, %%mm4\n\t"
+		"por		%%mm2, %%mm4\n\t"			// abs diff
+		
+		"movq	%%mm1, %%mm2\n\t"
+		"movq	(%%"XAX", %%"XCX"), %%mm3\n\t"
+		"psubusb %%mm3, %%mm2\n\t"
+		"psubusb %%mm1, %%mm3\n\t"
+		"por		%%mm2, %%mm3\n\t"			// abs diff
+//		pmaxub  %%mm3, %%mm4			// top or bottom pixel moved most
+		V_PMAXUB ("%%mm3", "%%mm4")			// top or bottom pixel moved most
+        "psubusb "_DiffThres", %%mm3\n\t"		// moved more than allowed? or goes to 0?
+		"pxor	%%mm4, %%mm4\n\t"
+		"pcmpeqb %%mm4, %%mm3\n\t"			// now ff where low motion, else high motion
+		
+		"movq	%%mm0, %%mm2\n\t"
+//		pminub	%%mm2, %%mm1
+		V_PMINUB ("%%mm2", "%%mm1", "%%mm4")
+
+//		pmaxub	%%mm6, %%mm2			// clip our current results so far to be above this
+		V_PMAXUB ("%%mm6", "%%mm2")
+
+        "psubusb %%mm3, %%mm2\n\t"			// maybe decrease it to 0000.. if no surround motion
+		"movq	%%mm2, "_Min_Vals"\n\t"
+
+		"movq	%%mm0, %%mm2\n\t"
+		V_PMAXUB ("%%mm2", "%%mm1")
+//		pminub	%%mm6, %%mm2			// clip our current results so far to be below this
+		V_PMINUB ("%%mm6", "%%mm2", "%%mm4")
+        "paddusb %%mm3, %%mm2\n\t"			// maybe increase it to ffffff if no surround motion
+		"movq	%%mm2, "_Max_Vals"\n\t"
+#endif
+			
+		"movq	%%mm0, %%mm2\n\t"						
+//		pavgb	%%mm2, %%mm1					// avg(b,e)
+		V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask)	// avg(b,e)
+				
+        "movq	%%mm0, %%mm3\n\t"
+		"psubusb	%%mm1, %%mm3\n\t"
+		"psubusb %%mm0, %%mm1\n\t"
+		"por		%%mm1, %%mm3\n\t"			// abs(b,e)
+		"movq	%%mm3, %%mm1\n\t"			// keep copy of diffs
+            
+		"pxor	%%mm4, %%mm4\n\t"			
+		"psubusb %%mm7, %%mm3\n\t"			// nonzero where new weights bigger, else 0
+		"pcmpeqb %%mm4, %%mm3\n\t"			// now ff where new better, else 00	
+        "pcmpeqb %%mm0, %%mm0\n\t"
+        "pandn   %%mm0, %%mm5\n\t"
+        "por     %%mm5, %%mm3\n\t"
+		"pcmpeqb	%%mm3, %%mm4\n\t"			// here ff where old better, else 00
+
+		"pand	%%mm3, %%mm1\n\t"
+		"pand	%%mm3, %%mm2\n\t"
+        
+		"pand    %%mm4, %%mm6\n\t"
+		"pand    %%mm4, %%mm7\n\t"
+
+		"por		%%mm2, %%mm6\n\t"			// our x2 value
+		"por		%%mm1, %%mm7\n\t"			// our x2 diffs
+		"movq	%%mm7, %%mm4\n\t"			// save as bob uncertainty indicator
+
+#else
+
+        diff[0] = -1;
+        diff[1] = -1;
+	best[0] = 0;
+	best[1] = 0;
+	// j, n
+        if (ABS (pBob[-2] - pBob[src_pitch2 - 4]) < DiffThres &&
+	    ABS (pBob[-4] - pBob[src_pitch2 + 4]) > DiffThres) {
+	   best[0] = (pBob[-2] + pBob[src_pitch2 - 4]) / 2;
+	   diff[0] = ABS (pBob[-2] - pBob[src_pitch2 - 4]);
+	}
+        if (ABS (pBob[-1] - pBob[src_pitch2 - 3]) < DiffThres &&
+	    ABS (pBob[-3] - pBob[src_pitch2 + 5]) > DiffThres) {
+	   best[1] = (pBob[-1] + pBob[src_pitch2 - 3]) / 2;
+	   diff[1] = ABS (pBob[-1] - pBob[src_pitch2 - 3]);
+	}
+
+        // k & m
+        if (ABS (pBob[2] - pBob[src_pitch2 + 4]) < DiffThres &&
+	    ABS (pBob[4] - pBob[src_pitch2 - 4]) > DiffThres) {
+	   best[0] = (pBob[4] + pBob[src_pitch2 - 4]) / 2;
+	   diff[0] = ABS (pBob[4] - pBob[src_pitch2 - 4]);
+	}
+
+        if (ABS (pBob[3] - pBob[src_pitch2 + 5]) < DiffThres &&
+	    ABS (pBob[5] - pBob[src_pitch2 - 3]) > DiffThres) {
+	   best[1] = (pBob[5] + pBob[src_pitch2 - 3]) / 2;
+	   diff[1] = ABS (pBob[5] - pBob[src_pitch2 - 3]);
+	}
+
+        // c & d
+	if (ABS (pBob[0] - pBob[src_pitch2 + 2]) < DiffThres &&
+	    ABS (pBob[2] - pBob[src_pitch2 - 2]) > DiffThres) {
+	   best[0] = (pBob[2] + pBob[src_pitch2 - 2]) / 2;
+	   diff[0] = ABS (pBob[2] - pBob[src_pitch2 - 2]);
+	}
+
+	if (ABS (pBob[1] - pBob[src_pitch2 + 3]) < DiffThres &&
+	    ABS (pBob[3] - pBob[src_pitch2 - 1]) > DiffThres) {
+	   best[1] = (pBob[3] + pBob[src_pitch2 - 1]) / 2;
+	   diff[1] = ABS (pBob[3] - pBob[src_pitch2 - 1]);
+	}
+
+        // a & f
+	if (ABS (pBob[0] - pBob[src_pitch2 - 2]) < DiffThres &&
+	    ABS (pBob[-2] - pBob[src_pitch2 + 2]) > DiffThres) {
+	   best[0] = (pBob[-2] + pBob[src_pitch2 + 2]) / 2;
+	   diff[0] = ABS (pBob[-2] - pBob[src_pitch2 + 2]);
+	}
+
+	if (ABS (pBob[1] - pBob[src_pitch2 - 1]) < DiffThres &&
+	    ABS (pBob[-1] - pBob[src_pitch2 + 3]) > DiffThres) {
+	   best[1] = (pBob[-1] + pBob[src_pitch2 + 3]) / 2;
+	   diff[1] = ABS (pBob[-1] - pBob[src_pitch2 + 3]);
+	}
+
+	// b,e
+	if (ABS (pBob[0] - pBob[src_pitch2]) < DiffThres) {
+	   best[0] = (pBob[0] + pBob[src_pitch2]) / 2;
+	   diff[0] = ABS (pBob[0] - pBob[src_pitch2]);
+	}
+
+	if (ABS (pBob[1] - pBob[src_pitch2 + 1]) < DiffThres) {
+	   best[1] = (pBob[1] + pBob[src_pitch2 + 1]) / 2;
+	   diff[1] = ABS (pBob[1] - pBob[src_pitch2 + 1]);
+	}
+
+
+// We will also calc here the max/min values to later limit comb
+// so the max excursion will not exceed the Max_Comb constant
+
+#ifdef SKIP_SEARCH
+		best[0] = CLAMP (best[0], MIN (pBob[src_pitch2], pBob[0]), MAX (pBob[src_pitch2], pBob[0]));
+		best[1] = CLAMP (best[1], MIN (pBob[src_pitch2 + 1], pBob[1]), MAX (pBob[src_pitch2 + 1], pBob[1]));
+#else
+		mov[0] = MAX (ABS (pBob[0] - pBobP[0]), ABS (pBob[src_pitch2] - pBobP[src_pitch2]));
+		mov[1] = MAX (ABS (pBob[1] - pBobP[1]), ABS (pBob[src_pitch2 + 1] - pBobP[src_pitch2 + 1]));
+
+		MinVals[0] = 0;
+		MinVals[1] = 0;
+		MaxVals[0] = 255;
+		MaxVals[1] = 255;
+		if (mov[0] > DiffThres) {
+		  MinVals[0] = MAX (MIN (pBob[0], pBob[src_pitch2]), best[0]);
+		  MaxVals[0] = MIN (MAX (pBob[0], pBob[src_pitch2]), best[0]);
+		}
+		
+		if (mov[1] > DiffThres) {
+		  MinVals[1] = MAX (MIN (pBob[1], pBob[src_pitch2+1]), best[1]);
+		  MaxVals[1] = MIN (MAX (pBob[1], pBob[src_pitch2+1]), best[1]);
+		}
+
+		best[0] = CLAMP (best[0], MIN (pBob[src_pitch2], pBob[0]), MAX (pBob[src_pitch2], pBob[0]));
+		best[1] = CLAMP (best[1], MIN (pBob[src_pitch2 + 1], pBob[1]), MAX (pBob[src_pitch2 + 1], pBob[1]));
+#endif
+		avg[0] = (pBob[src_pitch2] + pBob[0]) / 2;
+		avg[1] = (pBob[src_pitch2 + 1] + pBob[1]) / 2;
+		diff2[0] = ABS (pBob[src_pitch2 + 1] - pBob[1]);
+		diff2[1] = ABS (pBob[src_pitch2 + 1] - pBob[1]);
+
+		if (diff[0] == -1 || diff2[0] < diff[0]) {
+		  best[0] = avg[0];
+		  diff[0] = diff2[0];
+		}
+
+		if (diff[1] == -1 || diff2[1] < diff[1]) {
+		  best[1] = avg[1];
+		  diff[1] = diff2[1];
+		}
+#endif
diff --git a/gst/deinterlace/tvtime/tomsmocomp/TomsMoCompAll.inc b/gst/deinterlace/tvtime/tomsmocomp/TomsMoCompAll.inc
new file mode 100644
index 0000000..be58bba
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/TomsMoCompAll.inc
@@ -0,0 +1,266 @@
+/*
+ * GStreamer
+ * Copyright (c) 2002 Tom Barry  All rights reserved.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Relicensed for GStreamer from GPL to LGPL with permit from Tom Barry.
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
+ */
+
+
+#ifndef TopFirst
+#define TopFirst IsOdd
+#endif
+
+#ifdef SEFUNC
+#undef SEFUNC
+#endif
+
+#if defined(IS_MMXEXT)
+#define SEFUNC(x) Search_Effort_MMXEXT_##x(int src_pitch, int dst_pitch, int rowsize, const unsigned char *pWeaveSrc, const unsigned char *pWeaveSrcP, unsigned char *pWeaveDest, int IsOdd, const unsigned char *pCopySrc, const unsigned char *pCopySrcP, int FldHeight)
+#elif defined(IS_3DNOW)
+#define SEFUNC(x) Search_Effort_3DNOW_##x(int src_pitch, int dst_pitch, int rowsize, const unsigned char *pWeaveSrc, const unsigned char *pWeaveSrcP, unsigned char *pWeaveDest, int IsOdd, const unsigned char *pCopySrc, const unsigned char *pCopySrcP, int FldHeight)
+#elif defined(IS_MMX)
+#define SEFUNC(x) Search_Effort_MMX_##x(int src_pitch, int dst_pitch, int rowsize, const unsigned char *pWeaveSrc, const unsigned char *pWeaveSrcP, unsigned char *pWeaveDest, int IsOdd, const unsigned char *pCopySrc, const unsigned char *pCopySrcP, int FldHeight)
+#else
+#define SEFUNC(x) Search_Effort_C_##x(int src_pitch, int dst_pitch, int rowsize, const unsigned char *pWeaveSrc, const unsigned char *pWeaveSrcP, unsigned char *pWeaveDest, int IsOdd, const unsigned char *pCopySrc, const unsigned char *pCopySrcP, int FldHeight)
+#endif
+
+#include "TomsMoCompAll2.inc"
+
+#define USE_STRANGE_BOB
+
+#include "TomsMoCompAll2.inc"
+
+#undef USE_STRANGE_BOB
+
+#undef SEFUNC
+#if defined(IS_MMXEXT)
+#define SEFUNC(x) Search_Effort_MMXEXT_##x(src_pitch, dst_pitch, rowsize, pWeaveSrc, pWeaveSrcP, pWeaveDest, IsOdd, pCopySrc, pCopySrcP, FldHeight)
+#elif defined(IS_3DNOW)
+#define SEFUNC(x) Search_Effort_3DNOW_##x(src_pitch, dst_pitch, rowsize, pWeaveSrc, pWeaveSrcP, pWeaveDest, IsOdd, pCopySrc, pCopySrcP, FldHeight)
+#elif defined(IS_MMX)
+#define SEFUNC(x) Search_Effort_MMX_##x(src_pitch, dst_pitch, rowsize, pWeaveSrc, pWeaveSrcP, pWeaveDest, IsOdd, pCopySrc, pCopySrcP, FldHeight)
+#else
+#define SEFUNC(x) Search_Effort_C_##x(src_pitch, dst_pitch, rowsize, pWeaveSrc, pWeaveSrcP, pWeaveDest, IsOdd, pCopySrc, pCopySrcP, FldHeight)
+#endif
+
+static void FUNCT_NAME(GstDeinterlaceMethod *d_method,
+	const GstDeinterlaceField* history, guint history_count,
+	GstVideoFrame *outframe, int cur_field_idx)
+{
+  GstDeinterlaceMethodTomsMoComp *self = GST_DEINTERLACE_METHOD_TOMSMOCOMP (d_method);
+  glong SearchEffort = self->search_effort;
+  gint UseStrangeBob = self->strange_bob;
+  gint IsOdd;
+  const guint8 *pWeaveSrc;
+  const guint8 *pWeaveSrcP;
+  guint8 *pWeaveDest;
+  const guint8 *pCopySrc;
+  const guint8 *pCopySrcP;
+  guint8 *pCopyDest;
+  gint src_pitch;
+  gint dst_pitch;
+  gint rowsize;
+  gint FldHeight;
+
+  if (cur_field_idx + 2 > history_count || cur_field_idx < 1) {
+    GstDeinterlaceMethod *backup_method;
+    
+    backup_method = g_object_new (gst_deinterlace_method_linear_get_type(),
+        NULL);
+
+    gst_deinterlace_method_setup (backup_method, d_method->vinfo);
+    gst_deinterlace_method_deinterlace_frame (backup_method,
+        history, history_count, outframe, cur_field_idx);
+
+    g_object_unref (backup_method);
+    return;
+  }
+
+  /* double stride do address just every odd/even scanline */
+  src_pitch = GST_VIDEO_FRAME_PLANE_STRIDE (outframe, 0) * 2;
+  dst_pitch = GST_VIDEO_FRAME_PLANE_STRIDE (outframe, 0);
+  rowsize = GST_VIDEO_FRAME_PLANE_STRIDE (outframe, 0);
+
+  FldHeight = GST_VIDEO_INFO_HEIGHT (self->parent.vinfo) / 2;
+
+  pCopySrc   = GST_VIDEO_FRAME_PLANE_DATA (history[history_count-1].frame, 0);
+  if (history[history_count - 1].flags & PICTURE_INTERLACED_BOTTOM)
+    pCopySrc += GST_VIDEO_FRAME_PLANE_STRIDE (history[history_count-1].frame, 0);
+  pCopySrcP  = GST_VIDEO_FRAME_PLANE_DATA (history[history_count-3].frame, 0);
+  if (history[history_count - 3].flags & PICTURE_INTERLACED_BOTTOM)
+    pCopySrcP += GST_VIDEO_FRAME_PLANE_STRIDE (history[history_count-3].frame, 0);
+  pWeaveSrc  = GST_VIDEO_FRAME_PLANE_DATA (history[history_count-2].frame, 0);
+  if (history[history_count - 2].flags & PICTURE_INTERLACED_BOTTOM)
+    pWeaveSrc += GST_VIDEO_FRAME_PLANE_STRIDE (history[history_count-2].frame, 0);
+  pWeaveSrcP = GST_VIDEO_FRAME_PLANE_DATA (history[history_count-4].frame, 0);
+  if (history[history_count - 4].flags & PICTURE_INTERLACED_BOTTOM)
+    pWeaveSrcP += GST_VIDEO_FRAME_PLANE_STRIDE (history[history_count-4].frame, 0);
+
+  /* use bottom field and interlace top field */
+  if (history[history_count-2].flags == PICTURE_INTERLACED_BOTTOM) {
+    IsOdd      = 1;
+
+    // if we have an odd field we copy an even field and weave an odd field
+    pCopyDest = GST_VIDEO_FRAME_PLANE_DATA (outframe, 0);
+    pWeaveDest = pCopyDest + dst_pitch;
+  }
+  /* do it vice verca */
+  else {
+
+    IsOdd      = 0;
+    // if we have an even field we copy an odd field and weave an even field
+    pCopyDest = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (outframe, 0) + dst_pitch;
+    pWeaveDest = GST_VIDEO_FRAME_PLANE_DATA (outframe, 0);
+  }
+
+  
+  // copy 1st and last weave lines 
+  Fieldcopy(pWeaveDest, pCopySrc, rowsize,		
+	    1, dst_pitch*2, src_pitch);
+  Fieldcopy(pWeaveDest+(FldHeight-1)*dst_pitch*2,
+	    pCopySrc+(FldHeight-1)*src_pitch, rowsize, 
+	    1, dst_pitch*2, src_pitch);
+  
+#ifdef USE_VERTICAL_FILTER
+  // Vertical Filter currently not implemented for DScaler !!
+  // copy 1st and last lines the copy field
+  Fieldcopy(pCopyDest, pCopySrc, rowsize, 
+	    1, dst_pitch*2, src_pitch);
+  Fieldcopy(pCopyDest+(FldHeight-1)*dst_pitch*2,
+	    pCopySrc+(FldHeight-1)*src_pitch, rowsize, 
+	    1, dst_pitch*2, src_pitch);
+#else
+  
+  // copy all of the copy field
+  Fieldcopy(pCopyDest, pCopySrc, rowsize, 
+	    FldHeight, dst_pitch*2, src_pitch);
+#endif	
+  // then go fill in the hard part, being variously lazy depending upon
+  // SearchEffort
+
+  if(!UseStrangeBob) {
+    if (SearchEffort == 0)
+      {
+	SEFUNC(0);
+      }
+    else if (SearchEffort <= 1)
+      {
+	SEFUNC(1);
+      }
+    /*	else if (SearchEffort <= 2)
+	{
+	SEFUNC(2);
+	}
+    */
+    else if (SearchEffort <= 3)
+      {
+	SEFUNC(3);
+      }
+    else if (SearchEffort <= 5)
+      {
+	SEFUNC(5);
+      }
+    else if (SearchEffort <= 9)
+      {
+	SEFUNC(9);
+      }
+    else if (SearchEffort <= 11)
+      {
+	SEFUNC(11);
+      }
+    else if (SearchEffort <= 13)
+      {
+	SEFUNC(13);
+      }
+    else if (SearchEffort <= 15)
+      {
+	SEFUNC(15);
+      }
+    else if (SearchEffort <= 19)
+      {
+	SEFUNC(19);
+      }
+    else if (SearchEffort <= 21)
+      {
+	SEFUNC(21);
+      }
+    else 
+      {
+	SEFUNC(Max);
+      }
+  }
+  else
+    {
+      if (SearchEffort == 0)
+	{
+	  SEFUNC(0SB);
+	}
+      else if (SearchEffort <= 1)
+	{
+	  SEFUNC(1SB);
+	}
+      /*	else if (SearchEffort <= 2)
+		{
+		SEFUNC(2SB);
+		}
+      */
+      else if (SearchEffort <= 3)
+	{
+	  SEFUNC(3SB);
+	}
+      else if (SearchEffort <= 5)
+	{
+	  SEFUNC(5SB);
+	}
+      else if (SearchEffort <= 9)
+	{
+	  SEFUNC(9SB);
+	}
+      else if (SearchEffort <= 11)
+	{
+	  SEFUNC(11SB);
+	}
+      else if (SearchEffort <= 13)
+	{
+	  SEFUNC(13SB);
+	}
+      else if (SearchEffort <= 15)
+	{
+	  SEFUNC(15SB);
+	}
+      else if (SearchEffort <= 19)
+	{
+	  SEFUNC(19SB);
+	}
+      else if (SearchEffort <= 21)
+	{
+	  SEFUNC(21SB);
+	}
+      else 
+	{
+	  SEFUNC(MaxSB);
+	}
+    }
+
+#if defined(BUILD_X86_ASM) && !defined(IS_C)
+  __asm__ __volatile__("emms");
+#endif
+}
diff --git a/gst/deinterlace/tvtime/tomsmocomp/TomsMoCompAll2.inc b/gst/deinterlace/tvtime/tomsmocomp/TomsMoCompAll2.inc
new file mode 100644
index 0000000..f6344ea
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/TomsMoCompAll2.inc
@@ -0,0 +1,243 @@
+// -*- c++ -*-
+
+#ifdef SEARCH_EFFORT_FUNC
+#undef SEARCH_EFFORT_FUNC
+#endif
+
+#ifdef USE_STRANGE_BOB
+#define SEARCH_EFFORT_FUNC(n) SEFUNC(n##SB)
+#else
+#define SEARCH_EFFORT_FUNC(n) SEFUNC(n)
+#endif
+
+static inline int SEARCH_EFFORT_FUNC(0)		// we don't try at all ;-)
+{
+		//see Search_Effort_Max() for comments
+#define SKIP_SEARCH
+#include "SearchLoopTop.inc"
+#include "SearchLoopBottom.inc"
+#undef SKIP_SEARCH
+}
+
+static inline int SEARCH_EFFORT_FUNC(1)
+{
+#ifdef IS_C
+#define SKIP_SEARCH
+#include "SearchLoopTop.inc"
+#include "SearchLoopBottom.inc"
+#undef SKIP_SEARCH
+#else
+		//see Search_Effort_Max() for comments
+#include "SearchLoopTop.inc"
+	RESET_CHROMA		// pretend chroma diffs was 255 each
+#include "SearchLoop0A.inc"
+#include "SearchLoopBottom.inc"
+#endif
+}
+
+static inline int SEARCH_EFFORT_FUNC(3)
+{
+#ifdef IS_C
+#define SKIP_SEARCH
+#include "SearchLoopTop.inc"
+#include "SearchLoopBottom.inc"
+#undef SKIP_SEARCH
+#else
+		//see Search_Effort_Max() for comments
+#include "SearchLoopTop.inc"
+#include "SearchLoopOddA2.inc"
+	RESET_CHROMA		// pretend chroma diffs was 255 each
+#include "SearchLoop0A.inc"
+#include "SearchLoopBottom.inc"
+#endif
+}
+
+static inline int SEARCH_EFFORT_FUNC(5)
+{
+#ifdef IS_C
+#define SKIP_SEARCH
+#include "SearchLoopTop.inc"
+#include "SearchLoopBottom.inc"
+#undef SKIP_SEARCH
+#else
+		//see Search_Effort_Max() for comments
+#include "SearchLoopTop.inc"
+#include "SearchLoopOddA2.inc"
+#include "SearchLoopOddAH2.inc"
+	RESET_CHROMA		// pretend chroma diffs was 255 each
+#include "SearchLoop0A.inc"
+#include "SearchLoopBottom.inc"
+#endif
+}
+
+// 3x3 search
+static inline int SEARCH_EFFORT_FUNC(9)
+{
+#ifdef IS_C
+#define SKIP_SEARCH
+#include "SearchLoopTop.inc"
+#include "SearchLoopBottom.inc"
+#undef SKIP_SEARCH
+#else
+		//see SearchEffortMax() for comments
+#include "SearchLoopTop.inc"
+#include "SearchLoopOddA.inc"
+	RESET_CHROMA			// pretend chroma diffs was 255 each
+#include "SearchLoopVA.inc"
+#include "SearchLoop0A.inc"
+#include "SearchLoopBottom.inc"
+#endif
+}
+
+// Search 9 with 2 H-half pels added
+static inline int SEARCH_EFFORT_FUNC(11)
+{
+#ifdef IS_C
+#define SKIP_SEARCH
+#include "SearchLoopTop.inc"
+#include "SearchLoopBottom.inc"
+#undef SKIP_SEARCH
+#else
+		//see SearchEffortMax() for comments
+#include "SearchLoopTop.inc"
+#include "SearchLoopOddA.inc"
+#include "SearchLoopOddAH2.inc"
+	RESET_CHROMA			// pretend chroma diffs was 255 each
+#include "SearchLoopVA.inc"
+#include "SearchLoop0A.inc"
+#include "SearchLoopBottom.inc"
+#endif
+}
+
+// Search 11 with 2 V-half pels added
+static inline int SEARCH_EFFORT_FUNC(13)
+{
+#ifdef IS_C
+#define SKIP_SEARCH
+#include "SearchLoopTop.inc"
+#include "SearchLoopBottom.inc"
+#undef SKIP_SEARCH
+#else
+		//see SearchEffortMax() for comments
+#include "SearchLoopTop.inc"
+#include "SearchLoopOddA.inc"
+#include "SearchLoopOddAH2.inc"
+	RESET_CHROMA			// pretend chroma diffs was 255 each
+#include "SearchLoopVAH.inc"
+#include "SearchLoopVA.inc"
+#include "SearchLoop0A.inc"
+#include "SearchLoopBottom.inc"
+#endif
+}
+
+// 5x3
+static inline int SEARCH_EFFORT_FUNC(15)
+{
+#ifdef IS_C
+#define SKIP_SEARCH
+#include "SearchLoopTop.inc"
+#include "SearchLoopBottom.inc"
+#undef SKIP_SEARCH
+#else
+		//see SearchEffortMax() for comments
+#include "SearchLoopTop.inc"
+#include "SearchLoopOddA.inc"
+	RESET_CHROMA			// pretend chroma diffs was 255 each
+#include "SearchLoopEdgeA.inc"
+#include "SearchLoopVA.inc"
+#include "SearchLoop0A.inc"
+#include "SearchLoopBottom.inc"
+#endif
+}
+
+// 5x3 + 4 half pels
+static inline int SEARCH_EFFORT_FUNC(19)
+{
+#ifdef IS_C
+#define SKIP_SEARCH
+#include "SearchLoopTop.inc"
+#include "SearchLoopBottom.inc"
+#undef SKIP_SEARCH
+#else
+		//see SearchEffortMax() for comments
+#include "SearchLoopTop.inc"
+#include "SearchLoopOddA.inc"
+#include "SearchLoopOddAH2.inc"
+	RESET_CHROMA			// pretend chroma diffs was 255 each
+#include "SearchLoopEdgeA.inc"
+#include "SearchLoopVAH.inc"
+#include "SearchLoopVA.inc"
+#include "SearchLoop0A.inc"
+#include "SearchLoopBottom.inc"
+#endif
+}
+
+// Handle one 4x1 block of pixels
+// Search a 7x3 area, no half pels
+
+static inline int SEARCH_EFFORT_FUNC(21)
+{
+#ifdef IS_C
+#define SKIP_SEARCH
+#include "SearchLoopTop.inc"
+#include "SearchLoopBottom.inc"
+#undef SKIP_SEARCH
+#else
+		//see SearchLoopTop.inc for comments
+#include "SearchLoopTop.inc"
+
+		// odd addresses -- the pixels at odd address wouldn't generate
+		// good luma values but we will mask those off
+
+#include "SearchLoopOddA6.inc"  // 4 odd v half pels, 3 to left & right
+#include "SearchLoopOddA.inc"   // 6 odd pels, 1 to left & right
+
+	RESET_CHROMA		// pretend chroma diffs was 255 each
+
+		// even addresses -- use both luma and chroma from these
+		// search averages of 2 pixels left and right
+#include "SearchLoopEdgeA.inc"
+		// search vertical line and averages, -1,0,+1
+#include "SearchLoopVA.inc"
+		// blend our results and loop
+#include "SearchLoop0A.inc"
+#include "SearchLoopBottom.inc"
+#endif
+}
+
+// Handle one 4x1 block of pixels
+// Search a 9x3 area, no half pels
+static inline int SEARCH_EFFORT_FUNC(Max)
+{
+#ifdef IS_C
+#define SKIP_SEARCH
+#include "SearchLoopTop.inc"
+#include "SearchLoopBottom.inc"
+#undef SKIP_SEARCH
+#else
+		//see SearchLoopTop.inc for comments
+#include "SearchLoopTop.inc"
+
+		// odd addresses -- the pixels at odd address wouldn't generate
+		// good luma values but we will mask those off
+
+#include "SearchLoopOddA6.inc"  // 4 odd v half pels, 3 to left & right
+#include "SearchLoopOddA.inc"   // 6 odd pels, 1 to left & right
+
+	RESET_CHROMA		// pretend chroma diffs was 255 each
+
+		// even addresses -- use both luma and chroma from these
+		// search averages of 4 pixels left and right
+#include "SearchLoopEdgeA8.inc"
+		// search averages of 2 pixels left and right
+#include "SearchLoopEdgeA.inc"
+		// search vertical line and averages, -1,0,+1
+#include "SearchLoopVA.inc"
+		// blend our results and loop
+#include "SearchLoop0A.inc"
+#include "SearchLoopBottom.inc"
+#endif
+}
+
+#undef SEARCH_EFFORT_FUNC
+
diff --git a/gst/deinterlace/tvtime/tomsmocomp/WierdBob.inc b/gst/deinterlace/tvtime/tomsmocomp/WierdBob.inc
new file mode 100644
index 0000000..f4bbb83
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/WierdBob.inc
@@ -0,0 +1,286 @@
+// -*- c++ -*-
+
+		// First, get and save our possible Bob values
+		// Assume our pixels are layed out as follows with x the calc'd bob value
+		// and the other pixels are from the current field
+		//  
+		//        j a b c k		current field
+		//            x			calculated line
+		//        m d e f n		current field
+		//
+		// we calc the bob value as:
+		//		x2 = either avg(a,f), avg(c,d), avg(b,e), avg(j,n), or avg(k,m)
+		 
+		// selected for the	smallest of abs(a,f), abs(c,d), or abs(b,e), etc.
+
+#ifndef IS_C
+		// a,f
+		"movq    -2(%%"XBX"), %%mm0\n\t"		// value a from top left		
+		"movq    2(%%"XBX", %%"XCX"), %%mm1\n\t"	// value f from bottom right			
+		"movq	%%mm0, %%mm6\n\t"					
+//		pavgb	%%mm6, %%mm1					// avg(a,f), also best so far
+		V_PAVGB ("%%mm6", "%%mm1", "%%mm7", _ShiftMask)	// avg(a,f), also best so far
+        "movq	%%mm0, %%mm7\n\t"
+		"psubusb	 %%mm1, %%mm7\n\t"
+		"psubusb %%mm0, %%mm1\n\t"
+		"por		%%mm1, %%mm7\n\t"					// abs diff, also best so far
+
+		// c,d
+		"movq    2(%%"XBX"), %%mm0\n\t"		// value a from top left		
+		"movq    -2(%%"XBX", %%"XCX"), %%mm1\n\t"	// value f from bottom right			
+		"movq	%%mm0, %%mm2\n\t"						
+//		pavgb	%%mm2, %%mm1					// avg(c,d)
+		V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask)	// avg(c,d)
+        "movq	%%mm0, %%mm3\n\t"
+		"psubusb	%%mm1, %%mm3\n\t"
+		"psubusb %%mm0, %%mm1\n\t"
+		"por		%%mm1, %%mm3\n\t"					// abs(c,d)
+		"movq	%%mm3, %%mm1\n\t"					// keep copy
+
+		"psubusb %%mm7, %%mm3\n\t"			// nonzero where new weights bigger, else 0
+		"pxor	%%mm4, %%mm4\n\t"
+		"pcmpeqb %%mm4, %%mm3\n\t"			// now ff where new better, else 00	
+		"pcmpeqb	%%mm3, %%mm4\n\t"			// here ff where old better, else 00
+
+		"pand	%%mm3, %%mm1\n\t"			// keep only better new avg and abs
+		"pand	%%mm3, %%mm2\n\t"
+
+		"pand	%%mm4, %%mm6\n\t"
+		"pand    %%mm4, %%mm7\n\t"
+
+		"por		%%mm2, %%mm6\n\t"			// and merge new & old vals keeping best
+		"por		%%mm1, %%mm7\n\t"
+		"por		"_UVMask", %%mm7\n\t"			// but we know chroma is worthless so far
+		"pand	"_YMask", %%mm5\n\t"			// mask out chroma from here also
+
+		// j,n
+		"movq    -4(%%"XBX"), %%mm0\n\t"		// value j from top left		
+		"movq    4(%%"XBX", %%"XCX"), %%mm1\n\t"	// value n from bottom right			
+		"movq	%%mm0, %%mm2\n\t"						
+//		pavgb	%%mm2, %%mm1					// avg(j,n)
+		V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask)	// avg(j,n)
+        "movq	%%mm0, %%mm3\n\t"
+		"psubusb	%%mm1, %%mm3\n\t"
+		"psubusb %%mm0, %%mm1\n\t"
+		"por		%%mm1, %%mm3\n\t"					// abs(j-n)
+		"movq	%%mm3, %%mm1\n\t"					// keep copy
+
+		"psubusb %%mm7, %%mm3\n\t"			// nonzero where new weights bigger, else 0
+		"pxor	%%mm4, %%mm4\n\t"
+		"pcmpeqb %%mm4, %%mm3\n\t"			// now ff where new better, else 00	
+		"pcmpeqb	%%mm3, %%mm4\n\t"			// here ff where old better, else 00
+
+		"pand	%%mm3, %%mm1\n\t"			// keep only better new avg and abs
+		"pand	%%mm2, %%mm3\n\t"
+
+		"pand	%%mm4, %%mm6\n\t"
+		"pand    %%mm4, %%mm7\n\t"
+
+		"por		%%mm3, %%mm6\n\t"			// and merge new & old vals keeping best
+		"por		%%mm1, %%mm7\n\t"			// "
+
+		// k, m
+		"movq    4(%%"XBX"), %%mm0\n\t"		// value k from top right		
+		"movq    -4(%%"XBX", %%"XCX"), %%mm1\n\t"	// value n from bottom left			
+		"movq	%%mm0, %%mm4\n\t"						
+//		pavgb	%%mm4, %%mm1					// avg(k,m)
+		V_PAVGB ("%%mm4", "%%mm1", "%%mm3", _ShiftMask)	// avg(k,m)
+
+        "movq	%%mm0, %%mm3\n\t"
+		"psubusb	%%mm1, %%mm3\n\t"
+		"psubusb %%mm0, %%mm1\n\t"
+		"por		%%mm1, %%mm3\n\t"					// abs(k,m)
+		"movq	%%mm3, %%mm1\n\t"					// keep copy
+            
+		"movq	%%mm4, %%mm2\n\t"			// avg(k,m)
+
+		"psubusb %%mm7, %%mm3\n\t"			// nonzero where new weights bigger, else 0
+		"pxor	%%mm4, %%mm4\n\t"
+		"pcmpeqb %%mm4, %%mm3\n\t"			// now ff where new better, else 00	
+		"pcmpeqb	%%mm3, %%mm4\n\t"			// here ff where old better, else 00
+
+		"pand	%%mm3, %%mm1\n\t"			// keep only better new avg and abs
+		"pand	%%mm2, %%mm3\n\t"
+            
+		"pand	%%mm4, %%mm6\n\t"
+		"pand    %%mm4, %%mm7\n\t"
+
+		"por		%%mm3, %%mm6\n\t"			// and merge new & old vals keeping best
+		"por		%%mm1, %%mm7\n\t"			// "
+
+		// b,e
+		"movq    (%%"XBX"), %%mm0\n\t"		// value b from top 		
+		"movq    (%%"XBX", %%"XCX"), %%mm1\n\t"	// value e from bottom 
+
+// We will also calc here the max/min values to later limit comb
+// so the max excursion will not exceed the Max_Comb constant
+
+#ifdef SKIP_SEARCH		
+		"movq	%%mm0, %%mm2\n\t"
+//		pminub	%%mm2, %%mm1
+		V_PMINUB ("%%mm2", "%%mm1", "%%mm4")
+
+//		pmaxub	%%mm6, %%mm2			// clip our current results so far to be above this
+		V_PMAXUB ("%%mm6", "%%mm2")
+		"movq	%%mm0, %%mm2\n\t"
+		V_PMAXUB ("%%mm2", "%%mm1")
+//		pminub	%%mm6, %%mm2			// clip our current results so far to be below this
+		V_PMINUB ("%%mm6", "%%mm2", "%%mm4")
+
+#else
+        "movq	%%mm0, %%mm2\n\t"
+		"movq	(%%"XAX"), %%mm4\n\t"
+		"psubusb %%mm4, %%mm2\n\t"
+		"psubusb %%mm0, %%mm4\n\t"
+		"por		%%mm2, %%mm4\n\t"			// abs diff
+		
+		"movq	%%mm1, %%mm2\n\t"
+		"movq	(%%"XAX", %%"XCX"), %%mm3\n\t"
+		"psubusb %%mm3, %%mm2\n\t"
+		"psubusb %%mm1, %%mm3\n\t"
+		"por		%%mm2, %%mm3\n\t"			// abs diff
+//		pmaxub  %%mm3, %%mm4			// top or bottom pixel moved most
+		V_PMAXUB ("%%mm3", "%%mm4")			// top or bottom pixel moved most
+        "psubusb "_Max_Mov", %%mm3\n\t"		// moved more than allowed? or goes to 0?
+		"pxor	%%mm4, %%mm4\n\t"
+		"pcmpeqb %%mm4, %%mm3\n\t"			// now ff where low motion, else high motion
+		
+		"movq	%%mm0, %%mm2\n\t"
+//		pminub	%%mm2, %%mm1
+		V_PMINUB ("%%mm2", "%%mm1", "%%mm4")
+
+//		pmaxub	%%mm6, %%mm2			// clip our current results so far to be above this
+		V_PMAXUB ("%%mm6", "%%mm2")
+
+		"psubusb %%mm3, %%mm2\n\t"			// maybe decrease it to 0000.. if no surround motion
+		"movq	%%mm2, "_Min_Vals"\n\t"
+
+		"movq	%%mm0, %%mm2\n\t"
+		V_PMAXUB ("%%mm2", "%%mm1")
+//		pminub	%%mm6, %%mm2			// clip our current results so far to be below this
+		V_PMINUB ("%%mm6", "%%mm2", "%%mm4")
+        "paddusb %%mm3, %%mm2\n\t"			// maybe increase it to ffffff if no surround motion
+		"movq	%%mm2, "_Max_Vals"\n\t"
+#endif
+        
+		"movq	%%mm0, %%mm2\n\t"						
+//		pavgb	%%mm2, %%mm1					// avg(b,e)
+		V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask)	// avg(b,e)
+				
+        "movq	%%mm0, %%mm3\n\t"
+		"psubusb	%%mm1, %%mm3\n\t"
+		"psubusb %%mm0, %%mm1\n\t"
+		"por		%%mm1, %%mm3\n\t"			// abs(c,d)
+		"movq	%%mm3, %%mm1\n\t"			// keep copy of diffs
+
+		"pxor	%%mm4, %%mm4\n\t"			
+		"psubusb %%mm7, %%mm3\n\t"			// nonzero where new weights bigger, else 0
+		"pcmpeqb %%mm4, %%mm3\n\t"			// now ff where new better, else 00	
+
+		"pcmpeqb	%%mm3, %%mm4\n\t"			// here ff where old better, else 00
+
+		"pand	%%mm3, %%mm1\n\t"
+		"pand	%%mm3, %%mm2\n\t"
+
+		"pand    %%mm4, %%mm6\n\t"
+		"pand    %%mm4, %%mm7\n\t"
+
+		"por		%%mm2, %%mm6\n\t"			// our x2 value
+		"por		%%mm1, %%mm7\n\t"			// our x2 diffs
+		"movq	%%mm7, %%mm4\n\t"			// save as bob uncertainty indicator
+
+#else
+
+        // a,f
+        best[0] = (pBob[-2] + pBob[src_pitch2 + 2]) / 2;
+	diff[0] = ABS (pBob[-2] - pBob[src_pitch2 + 2]);
+        best[1] = (pBob[-1] + pBob[src_pitch2 + 3]) / 2;
+	diff[1] = ABS (pBob[-1] - pBob[src_pitch2 + 3]);
+
+        // c,d
+	if (ABS (pBob[2] - pBob[src_pitch2 - 2]) < diff[0]) {
+          best[0] = (pBob[2] + pBob[src_pitch2 - 2]) / 2;
+	  diff[0] = ABS (pBob[2] - pBob[src_pitch2 - 2]);
+	}
+
+	if (ABS (pBob[3] - pBob[src_pitch2 - 1]) < diff[1]) {
+          best[1] = (pBob[3] + pBob[src_pitch2 - 1]) / 2;
+	  diff[1] = ABS (pBob[3] - pBob[src_pitch2 - 1]);
+	}
+
+	// j,n
+	if (ABS (pBob[-4] - pBob[src_pitch2 + 4]) < diff[0]) {
+          best[0] = (pBob[-4] + pBob[src_pitch2 + 4]) / 2;
+	  diff[0] = ABS (pBob[-4] - pBob[src_pitch2 + 4]);
+	}
+
+	if (ABS (pBob[-3] - pBob[src_pitch2 + 5]) < diff[1]) {
+          best[1] = (pBob[-3] + pBob[src_pitch2 + 5]) / 2;
+	  diff[1] = ABS (pBob[-3] - pBob[src_pitch2 + 5]);
+	}
+
+	// k,m
+	if (ABS (pBob[4] - pBob[src_pitch2 - 4]) < diff[0]) {
+          best[0] = (pBob[4] + pBob[src_pitch2 - 4]) / 2;
+	  diff[0] = ABS (pBob[-4] - pBob[src_pitch2 - 4]);
+	}
+
+	if (ABS (pBob[5] - pBob[src_pitch2 - 3]) < diff[1]) {
+          best[1] = (pBob[5] + pBob[src_pitch2 - 3]) / 2;
+	  diff[1] = ABS (pBob[-3] - pBob[src_pitch2 - 3]);
+	}
+	// k,m
+	if (ABS (pBob[4] - pBob[src_pitch2 - 4]) < diff[0]) {
+          best[0] = (pBob[4] + pBob[src_pitch2 - 4]) / 2;
+	  diff[0] = ABS (pBob[-4] - pBob[src_pitch2 - 4]);
+	}
+	
+	if (ABS (pBob[5] - pBob[src_pitch2 - 3]) < diff[1]) {
+          best[1] = (pBob[5] + pBob[src_pitch2 - 3]) / 2;
+	  diff[1] = ABS (pBob[-3] - pBob[src_pitch2 - 3]);
+	}
+
+// We will also calc here the max/min values to later limit comb
+// so the max excursion will not exceed the Max_Comb constant
+
+#ifdef SKIP_SEARCH
+		best[0] = CLAMP (best[0], MIN (pBob[src_pitch2], pBob[0]), MAX (pBob[src_pitch2], pBob[0]));
+		best[1] = CLAMP (best[1], MIN (pBob[src_pitch2 + 1], pBob[1]), MAX (pBob[src_pitch2 + 1], pBob[1]));
+#else
+		mov[0] = MAX (ABS (pBob[0] - pBobP[0]), ABS (pBob[src_pitch2] - pBobP[src_pitch2]));
+		mov[1] = MAX (ABS (pBob[1] - pBobP[1]), ABS (pBob[src_pitch2 + 1] - pBobP[src_pitch2 + 1]));
+
+		MinVals[0] = 0;
+		MinVals[1] = 0;
+		MaxVals[0] = 255;
+		MaxVals[1] = 255;
+
+		if (mov[0] > Max_Mov[0]) {
+		  MinVals[0] = MAX (MIN (pBob[0], pBob[src_pitch2]), best[0]);
+		  MaxVals[0] = MIN (MAX (pBob[0], pBob[src_pitch2]), best[0]);
+		}
+		
+		if (mov[1] > Max_Mov[1]) {
+		  MinVals[1] = MAX (MIN (pBob[1], pBob[src_pitch2 + 1]), best[1]);
+		  MaxVals[1] = MIN (MAX (pBob[1], pBob[src_pitch2 + 1]), best[1]);
+		}
+
+		best[0] = CLAMP (best[0], MIN (pBob[src_pitch2], pBob[0]), MAX (pBob[src_pitch2], pBob[0]));
+		best[1] = CLAMP (best[1], MIN (pBob[src_pitch2 + 1], pBob[1]), MAX (pBob[src_pitch2 + 1], pBob[1]));
+#endif
+
+		avg[0] = (pBob[src_pitch2] + pBob[0]) / 2;
+		avg[1] = (pBob[src_pitch2 + 1] + pBob[1]) / 2;
+		diff2[0] = ABS (pBob[src_pitch2] - pBob[0]);
+		diff2[1] = ABS (pBob[src_pitch2 + 1] - pBob[1]);
+
+		if (diff2[0] < diff[0]) {
+		  best[0] = avg[0];
+		  diff[0] = diff2[0];
+		}
+
+		if (diff2[1] < diff[1]) {
+		  best[1] = avg[1];
+		  diff[1] = diff2[1];
+		}
+#endif
diff --git a/gst/deinterlace/tvtime/tomsmocomp/tomsmocompmacros.h b/gst/deinterlace/tvtime/tomsmocomp/tomsmocompmacros.h
new file mode 100644
index 0000000..7e8147e
--- /dev/null
+++ b/gst/deinterlace/tvtime/tomsmocomp/tomsmocompmacros.h
@@ -0,0 +1,164 @@
+#include <string.h>
+#include <math.h>
+
+// Define a few macros for CPU dependent instructions. 
+// I suspect I don't really understand how the C macro preprocessor works but
+// this seems to get the job done.          // TRB 7/01
+
+// BEFORE USING THESE YOU MUST SET:
+
+// #define SIMD_TYPE MMXEXT            (or MMX or 3DNOW)
+
+// some macros for pavgb instruction
+//      V_PAVGB(mmr1, mmr2, mmr work register, smask) mmr2 may = mmrw if you can trash it
+
+#define V_PAVGB_MMX(mmr1, mmr2, mmrw, smask) \
+	"movq    "mmr2",  "mmrw"\n\t"            \
+	"pand    "smask", "mmrw"\n\t"            \
+	"psrlw   $1,      "mmrw"\n\t"            \
+	"pand    "smask", "mmr1"\n\t"            \
+	"psrlw   $1,      "mmr1"\n\t"            \
+	"paddusb "mmrw",  "mmr1"\n\t"
+#define V_PAVGB_MMXEXT(mmr1, mmr2, mmrw, smask)      "pavgb   "mmr2", "mmr1"\n\t"
+#define V_PAVGB_3DNOW(mmr1, mmr2, mmrw, smask)    "pavgusb "mmr2", "mmr1"\n\t"
+#define V_PAVGB(mmr1, mmr2, mmrw, smask)          V_PAVGB2(mmr1, mmr2, mmrw, smask, SIMD_TYPE) 
+#define V_PAVGB2(mmr1, mmr2, mmrw, smask, simd_type) V_PAVGB3(mmr1, mmr2, mmrw, smask, simd_type) 
+#define V_PAVGB3(mmr1, mmr2, mmrw, smask, simd_type) V_PAVGB_##simd_type(mmr1, mmr2, mmrw, smask) 
+
+// some macros for pmaxub instruction
+#define V_PMAXUB_MMX(mmr1, mmr2) \
+    "psubusb "mmr2", "mmr1"\n\t" \
+    "paddusb "mmr2", "mmr1"\n\t"
+#define V_PMAXUB_MMXEXT(mmr1, mmr2)      "pmaxub "mmr2", "mmr1"\n\t"
+#define V_PMAXUB_3DNOW(mmr1, mmr2)    V_PMAXUB_MMX(mmr1, mmr2)  // use MMX version
+#define V_PMAXUB(mmr1, mmr2)          V_PMAXUB2(mmr1, mmr2, SIMD_TYPE) 
+#define V_PMAXUB2(mmr1, mmr2, simd_type) V_PMAXUB3(mmr1, mmr2, simd_type) 
+#define V_PMAXUB3(mmr1, mmr2, simd_type) V_PMAXUB_##simd_type(mmr1, mmr2) 
+
+// some macros for pminub instruction
+//      V_PMINUB(mmr1, mmr2, mmr work register)     mmr2 may NOT = mmrw
+#define V_PMINUB_MMX(mmr1, mmr2, mmrw) \
+    "pcmpeqb "mmrw", "mmrw"\n\t"       \
+    "psubusb "mmr2", "mmrw"\n\t"       \
+    "paddusb "mmrw", "mmr1"\n\t"       \
+    "psubusb "mmrw", "mmr1"\n\t"
+#define V_PMINUB_MMXEXT(mmr1, mmr2, mmrw)      "pminub "mmr2", "mmr1"\n\t"
+#define V_PMINUB_3DNOW(mmr1, mmr2, mmrw)    V_PMINUB_MMX(mmr1, mmr2, mmrw)  // use MMX version
+#define V_PMINUB(mmr1, mmr2, mmrw)          V_PMINUB2(mmr1, mmr2, mmrw, SIMD_TYPE) 
+#define V_PMINUB2(mmr1, mmr2, mmrw, simd_type) V_PMINUB3(mmr1, mmr2, mmrw, simd_type) 
+#define V_PMINUB3(mmr1, mmr2, mmrw, simd_type) V_PMINUB_##simd_type(mmr1, mmr2, mmrw) 
+
+// some macros for movntq instruction
+//      V_MOVNTQ(mmr1, mmr2) 
+#define V_MOVNTQ_MMX(mmr1, mmr2)      "movq   "mmr2", "mmr1"\n\t"
+#define V_MOVNTQ_3DNOW(mmr1, mmr2)    "movq   "mmr2", "mmr1"\n\t"
+#define V_MOVNTQ_MMXEXT(mmr1, mmr2)      "movntq "mmr2", "mmr1"\n\t"
+#define V_MOVNTQ(mmr1, mmr2)          V_MOVNTQ2(mmr1, mmr2, SIMD_TYPE) 
+#define V_MOVNTQ2(mmr1, mmr2, simd_type) V_MOVNTQ3(mmr1, mmr2, simd_type) 
+#define V_MOVNTQ3(mmr1, mmr2, simd_type) V_MOVNTQ_##simd_type(mmr1, mmr2)
+
+// end of macros
+
+#ifdef IS_SSE2
+
+#define MERGE4PIXavg(PADDR1, PADDR2)                                                     \
+    "movdqu  "PADDR1",   %%xmm0\n\t"       /* our 4 pixels */                            \
+    "movdqu  "PADDR2",   %%xmm1\n\t"       /* our pixel2 value */                        \
+    "movdqa  %%xmm0,     %%xmm2\n\t"       /* another copy of our pixel1 value */        \
+    "movdqa  %%xmm1,     %%xmm3\n\t"       /* another copy of our pixel1 value */        \
+    "psubusb %%xmm1,     %%xmm2\n\t"                                                     \
+    "psubusb %%xmm0,     %%xmm3\n\t"                                                     \
+    "por     %%xmm3,     %%xmm2\n\t"                                                     \
+    "pavgb   %%xmm1,     %%xmm0\n\t"       /* avg of 2 pixels */                         \
+    "movdqa  %%xmm2,     %%xmm3\n\t"       /* another copy of our our weights */         \
+    "pxor    %%xmm1,     %%xmm1\n\t"                                                     \
+    "psubusb %%xmm7,     %%xmm3\n\t"       /* nonzero where old weights lower, else 0 */ \
+    "pcmpeqb %%xmm1,     %%xmm3\n\t"       /* now ff where new better, else 00 */        \
+    "pcmpeqb %%xmm3,     %%xmm1\n\t"       /* here ff where old better, else 00 */       \
+    "pand    %%xmm3,     %%xmm0\n\t"       /* keep only better new pixels */             \
+    "pand    %%xmm3,     %%xmm2\n\t"       /* and weights */                             \
+    "pand    %%xmm1,     %%xmm5\n\t"       /* keep only better old pixels */             \
+    "pand    %%xmm1,     %%xmm7\n\t"                                                     \
+    "por     %%xmm0,     %%xmm5\n\t"       /* and merge new & old vals */                \
+    "por     %%xmm2,     %%xmm7\n\t"
+
+#define MERGE4PIXavgH(PADDR1A, PADDR1B, PADDR2A, PADDR2B)                                \
+    "movdqu  "PADDR1A",   %%xmm0\n\t"      /* our 4 pixels */                            \
+    "movdqu  "PADDR2A",   %%xmm1\n\t"      /* our pixel2 value */                        \
+    "movdqu  "PADDR1B",   %%xmm2\n\t"      /* our 4 pixels */                            \
+    "movdqu  "PADDR2B",   %%xmm3\n\t"      /* our pixel2 value */                        \
+    "pavgb   %%xmm2,      %%xmm0\n\t"                                                    \
+    "pavgb   %%xmm3,      %%xmm1\n\t"                                                    \
+    "movdqa  %%xmm0,      %%xmm2\n\t"      /* another copy of our pixel1 value */        \
+    "movdqa  %%xmm1,      %%xmm3\n\t"      /* another copy of our pixel1 value */        \
+    "psubusb %%xmm1,      %%xmm2\n\t"                                                    \
+    "psubusb %%xmm0,      %%xmm3\n\t"                                                    \
+    "por     %%xmm3,      %%xmm2\n\t"                                                    \
+    "pavgb   %%xmm1,      %%xmm0\n\t"      /* avg of 2 pixels */                         \
+    "movdqa  %%xmm2,      %%xmm3\n\t"      /* another copy of our our weights */         \
+    "pxor    %%xmm1,      %%xmm1\n\t"                                                    \
+    "psubusb %%xmm7,      %%xmm3\n\t"      /* nonzero where old weights lower, else 0 */ \
+    "pcmpeqb %%xmm1,      %%xmm3\n\t"      /* now ff where new better, else 00 */        \
+    "pcmpeqb %%xmm3,      %%xmm1\n\t"      /* here ff where old better, else 00 */       \
+    "pand    %%xmm3,      %%xmm0\n\t"      /* keep only better new pixels */             \
+    "pand    %%xmm3,      %%xmm2\n\t"      /* and weights */                             \
+    "pand    %%xmm1,      %%xmm5\n\t"      /* keep only better old pixels */             \
+    "pand    %%xmm1,      %%xmm7\n\t"                                                    \
+    "por     %%xmm0,      %%xmm5\n\t"      /* and merge new & old vals */                \
+    "por     %%xmm2,      %%xmm7\n\t"
+
+#define RESET_CHROMA "por "_UVMask", %%xmm7\n\t"
+
+#else // ifdef IS_SSE2
+
+#define MERGE4PIXavg(PADDR1, PADDR2)                                                    \
+    "movq    "PADDR1",   %%mm0\n\t"       /* our 4 pixels */                            \
+    "movq    "PADDR2",   %%mm1\n\t"       /* our pixel2 value */                        \
+    "movq    %%mm0,      %%mm2\n\t"       /* another copy of our pixel1 value */        \
+    "movq    %%mm1,      %%mm3\n\t"       /* another copy of our pixel1 value */        \
+    "psubusb %%mm1,      %%mm2\n\t"                                                     \
+    "psubusb %%mm0,      %%mm3\n\t"                                                     \
+    "por     %%mm3,      %%mm2\n\t"                                                     \
+    V_PAVGB ("%%mm0", "%%mm1", "%%mm3", _ShiftMask) /* avg of 2 pixels */               \
+    "movq    %%mm2,      %%mm3\n\t"       /* another copy of our our weights */         \
+    "pxor    %%mm1,      %%mm1\n\t"                                                     \
+    "psubusb %%mm7,      %%mm3\n\t"       /* nonzero where old weights lower, else 0 */ \
+    "pcmpeqb %%mm1,      %%mm3\n\t"       /* now ff where new better, else 00 */        \
+    "pcmpeqb %%mm3,      %%mm1\n\t"       /* here ff where old better, else 00 */       \
+    "pand    %%mm3,      %%mm0\n\t"       /* keep only better new pixels */             \
+    "pand    %%mm3,      %%mm2\n\t"       /* and weights */                             \
+    "pand    %%mm1,      %%mm5\n\t"       /* keep only better old pixels */             \
+    "pand    %%mm1,      %%mm7\n\t"                                                     \
+    "por     %%mm0,      %%mm5\n\t"       /* and merge new & old vals */                \
+    "por     %%mm2,      %%mm7\n\t"
+
+#define MERGE4PIXavgH(PADDR1A, PADDR1B, PADDR2A, PADDR2B)                               \
+    "movq    "PADDR1A",   %%mm0\n\t"      /* our 4 pixels */                            \
+    "movq    "PADDR2A",   %%mm1\n\t"      /* our pixel2 value */                        \
+    "movq    "PADDR1B",   %%mm2\n\t"      /* our 4 pixels */                            \
+    "movq    "PADDR2B",   %%mm3\n\t"      /* our pixel2 value */                        \
+    V_PAVGB("%%mm0", "%%mm2", "%%mm2", _ShiftMask)                                      \
+    V_PAVGB("%%mm1", "%%mm3", "%%mm3", _ShiftMask)                                      \
+    "movq    %%mm0,       %%mm2\n\t"      /* another copy of our pixel1 value */        \
+    "movq    %%mm1,       %%mm3\n\t"      /* another copy of our pixel1 value */        \
+    "psubusb %%mm1,       %%mm2\n\t"                                                    \
+    "psubusb %%mm0,       %%mm3\n\t"                                                    \
+    "por     %%mm3,       %%mm2\n\t"                                                    \
+    V_PAVGB("%%mm0", "%%mm1", "%%mm3", _ShiftMask)   /* avg of 2 pixels */              \
+    "movq    %%mm2,       %%mm3\n\t"      /* another copy of our our weights */         \
+    "pxor    %%mm1,       %%mm1\n\t"                                                    \
+    "psubusb %%mm7,       %%mm3\n\t"      /* nonzero where old weights lower, else 0 */ \
+    "pcmpeqb %%mm1,       %%mm3\n\t"      /* now ff where new better, else 00 */        \
+    "pcmpeqb %%mm3,       %%mm1\n\t"      /* here ff where old better, else 00 */       \
+    "pand    %%mm3,       %%mm0\n\t"      /* keep only better new pixels */             \
+    "pand    %%mm3,       %%mm2\n\t"      /* and weights */                             \
+    "pand    %%mm1,       %%mm5\n\t"      /* keep only better old pixels */             \
+    "pand    %%mm1,       %%mm7\n\t"                                                    \
+    "por     %%mm0,       %%mm5\n\t"      /* and merge new & old vals */                \
+    "por     %%mm2,       %%mm7\n\t"
+
+#define RESET_CHROMA "por "_UVMask", %%mm7\n\t"
+
+#endif
+
+
diff --git a/gst/deinterlace/tvtime/vfir.c b/gst/deinterlace/tvtime/vfir.c
new file mode 100644
index 0000000..a061895
--- /dev/null
+++ b/gst/deinterlace/tvtime/vfir.c
@@ -0,0 +1,314 @@
+/*
+ *
+ * GStreamer
+ * Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
+ * Copyright (c) 2001, 2002, 2003 Fabrice Bellard.
+ * Copyright (C) 2008,2010 Sebastian Dröge <slomo@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * This file contains code from ffmpeg, see http://ffmpeg.org/ (LGPL)
+ * and modifications by Billy Biggs.
+ *
+ * Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstdeinterlacemethod.h"
+#include <string.h>
+#ifdef HAVE_ORC
+#include <orc/orc.h>
+#endif
+#include "tvtime.h"
+
+#define GST_TYPE_DEINTERLACE_METHOD_VFIR	(gst_deinterlace_method_vfir_get_type ())
+#define GST_IS_DEINTERLACE_METHOD_VFIR(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_VFIR))
+#define GST_IS_DEINTERLACE_METHOD_VFIR_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_VFIR))
+#define GST_DEINTERLACE_METHOD_VFIR_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_VFIR, GstDeinterlaceMethodVFIRClass))
+#define GST_DEINTERLACE_METHOD_VFIR(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_VFIR, GstDeinterlaceMethodVFIR))
+#define GST_DEINTERLACE_METHOD_VFIR_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_VFIR, GstDeinterlaceMethodVFIRClass))
+#define GST_DEINTERLACE_METHOD_VFIR_CAST(obj)	((GstDeinterlaceMethodVFIR*)(obj))
+
+GType gst_deinterlace_method_vfir_get_type (void);
+
+typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodVFIR;
+
+typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodVFIRClass;
+
+/*
+ * The MPEG2 spec uses a slightly harsher filter, they specify
+ * [-1 8 2 8 -1].  ffmpeg uses a similar filter but with more of
+ * a tendancy to blur than to use the local information.  The
+ * filter taps here are: [-1 4 2 4 -1].
+ */
+
+ /*
+  * C implementation.
+  */
+static inline void
+deinterlace_c (guint8 * dst, const guint8 * lum_m4, const guint8 * lum_m3,
+    const guint8 * lum_m2, const guint8 * lum_m1, const guint8 * lum, gint size)
+{
+  if (lum_m2 == NULL) {
+    deinterlace_line_linear (dst, lum_m1, lum_m3, size);
+  } else {
+    deinterlace_line_vfir (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
+  }
+}
+
+static void
+deinterlace_line_packed_c (GstDeinterlaceSimpleMethod * self, guint8 * dst,
+    const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  const guint8 *lum_m4 = scanlines->tt1;
+  const guint8 *lum_m3 = scanlines->t0;
+  const guint8 *lum_m2 = scanlines->m1;
+  const guint8 *lum_m1 = scanlines->b0;
+  const guint8 *lum = scanlines->bb1;
+
+  deinterlace_c (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
+}
+
+static void
+deinterlace_line_planar_y_c (GstDeinterlaceSimpleMethod * self, guint8 * dst,
+    const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  const guint8 *lum_m4 = scanlines->tt1;
+  const guint8 *lum_m3 = scanlines->t0;
+  const guint8 *lum_m2 = scanlines->m1;
+  const guint8 *lum_m1 = scanlines->b0;
+  const guint8 *lum = scanlines->bb1;
+
+  deinterlace_c (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
+}
+
+static void
+deinterlace_line_planar_u_c (GstDeinterlaceSimpleMethod * self, guint8 * dst,
+    const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  const guint8 *lum_m4 = scanlines->tt1;
+  const guint8 *lum_m3 = scanlines->t0;
+  const guint8 *lum_m2 = scanlines->m1;
+  const guint8 *lum_m1 = scanlines->b0;
+  const guint8 *lum = scanlines->bb1;
+
+  deinterlace_c (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
+}
+
+static void
+deinterlace_line_planar_v_c (GstDeinterlaceSimpleMethod * self, guint8 * dst,
+    const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  const guint8 *lum_m4 = scanlines->tt1;
+  const guint8 *lum_m3 = scanlines->t0;
+  const guint8 *lum_m2 = scanlines->m1;
+  const guint8 *lum_m1 = scanlines->b0;
+  const guint8 *lum = scanlines->bb1;
+
+  deinterlace_c (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
+}
+
+#undef BUILD_X86_ASM
+
+#ifdef BUILD_X86_ASM
+#include "mmx.h"
+static void
+deinterlace_mmx (guint8 * dst, const guint8 * lum_m4, const guint8 * lum_m3,
+    const guint8 * lum_m2, const guint8 * lum_m1, const guint8 * lum, gint size)
+{
+  mmx_t rounder;
+
+  rounder.uw[0] = 4;
+  rounder.uw[1] = 4;
+  rounder.uw[2] = 4;
+  rounder.uw[3] = 4;
+  pxor_r2r (mm7, mm7);
+  movq_m2r (rounder, mm6);
+
+  for (; size > 3; size -= 4) {
+    movd_m2r (*lum_m4, mm0);
+    movd_m2r (*lum_m3, mm1);
+    movd_m2r (*lum_m2, mm2);
+    movd_m2r (*lum_m1, mm3);
+    movd_m2r (*lum, mm4);
+    punpcklbw_r2r (mm7, mm0);
+    punpcklbw_r2r (mm7, mm1);
+    punpcklbw_r2r (mm7, mm2);
+    punpcklbw_r2r (mm7, mm3);
+    punpcklbw_r2r (mm7, mm4);
+    paddw_r2r (mm3, mm1);
+    psllw_i2r (1, mm2);
+    paddw_r2r (mm4, mm0);
+    psllw_i2r (2, mm1);         // 2
+    paddw_r2r (mm6, mm2);
+    paddw_r2r (mm2, mm1);
+    psubusw_r2r (mm0, mm1);
+    psrlw_i2r (3, mm1);         // 3
+    packuswb_r2r (mm7, mm1);
+    movd_r2m (mm1, *dst);
+    lum_m4 += 4;
+    lum_m3 += 4;
+    lum_m2 += 4;
+    lum_m1 += 4;
+    lum += 4;
+    dst += 4;
+  }
+  emms ();
+
+  /* Handle odd widths */
+  if (size > 0)
+    deinterlace_c (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
+}
+
+static void
+deinterlace_line_packed_mmx (GstDeinterlaceSimpleMethod * self, guint8 * dst,
+    const GstDeinterlaceScanlineData * scanlines)
+{
+  const guint8 *lum_m4 = scanlines->tt1;
+  const guint8 *lum_m3 = scanlines->t0;
+  const guint8 *lum_m2 = scanlines->m1;
+  const guint8 *lum_m1 = scanlines->b0;
+  const guint8 *lum = scanlines->bb1;
+  gint size = self->parent.row_stride[0];
+
+  deinterlace_mmx (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
+}
+
+static void
+deinterlace_line_planar_y_mmx (GstDeinterlaceSimpleMethod * self, guint8 * dst,
+    const GstDeinterlaceScanlineData * scanlines)
+{
+  const guint8 *lum_m4 = scanlines->tt1;
+  const guint8 *lum_m3 = scanlines->t0;
+  const guint8 *lum_m2 = scanlines->m1;
+  const guint8 *lum_m1 = scanlines->b0;
+  const guint8 *lum = scanlines->bb1;
+  gint size = self->parent.row_stride[0];
+
+  deinterlace_mmx (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
+}
+
+static void
+deinterlace_line_planar_u_mmx (GstDeinterlaceSimpleMethod * self, guint8 * dst,
+    const GstDeinterlaceScanlineData * scanlines)
+{
+  const guint8 *lum_m4 = scanlines->tt1;
+  const guint8 *lum_m3 = scanlines->t0;
+  const guint8 *lum_m2 = scanlines->m1;
+  const guint8 *lum_m1 = scanlines->b0;
+  const guint8 *lum = scanlines->bb1;
+  gint size = self->parent.row_stride[1];
+
+  deinterlace_mmx (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
+}
+
+static void
+deinterlace_line_planar_v_mmx (GstDeinterlaceSimpleMethod * self, guint8 * dst,
+    const GstDeinterlaceScanlineData * scanlines)
+{
+  const guint8 *lum_m4 = scanlines->tt1;
+  const guint8 *lum_m3 = scanlines->t0;
+  const guint8 *lum_m2 = scanlines->m1;
+  const guint8 *lum_m1 = scanlines->b0;
+  const guint8 *lum = scanlines->bb1;
+  gint size = self->parent.row_stride[2];
+
+  deinterlace_mmx (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
+}
+#endif
+
+G_DEFINE_TYPE (GstDeinterlaceMethodVFIR, gst_deinterlace_method_vfir,
+    GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
+
+static void
+gst_deinterlace_method_vfir_class_init (GstDeinterlaceMethodVFIRClass * klass)
+{
+  GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
+  GstDeinterlaceSimpleMethodClass *dism_class =
+      (GstDeinterlaceSimpleMethodClass *) klass;
+#ifdef BUILD_X86_ASM
+  guint cpu_flags =
+      orc_target_get_default_flags (orc_target_get_by_name ("mmx"));
+#endif
+
+  dim_class->fields_required = 2;
+  dim_class->name = "Blur Vertical";
+  dim_class->nick = "vfir";
+  dim_class->latency = 1;
+
+#ifdef BUILD_X86_ASM
+  if (cpu_flags & ORC_TARGET_MMX_MMX) {
+    dism_class->interpolate_scanline_ayuv = deinterlace_line_packed_mmx;
+    dism_class->interpolate_scanline_yuy2 = deinterlace_line_packed_mmx;
+    dism_class->interpolate_scanline_yvyu = deinterlace_line_packed_mmx;
+    dism_class->interpolate_scanline_uyvy = deinterlace_line_packed_mmx;
+    dism_class->interpolate_scanline_nv12 = deinterlace_line_packed_mmx;
+    dism_class->interpolate_scanline_nv21 = deinterlace_line_packed_mmx;
+    dism_class->interpolate_scanline_argb = deinterlace_line_packed_mmx;
+    dism_class->interpolate_scanline_abgr = deinterlace_line_packed_mmx;
+    dism_class->interpolate_scanline_rgba = deinterlace_line_packed_mmx;
+    dism_class->interpolate_scanline_bgra = deinterlace_line_packed_mmx;
+    dism_class->interpolate_scanline_rgb = deinterlace_line_packed_mmx;
+    dism_class->interpolate_scanline_bgr = deinterlace_line_packed_mmx;
+    dism_class->interpolate_scanline_planar_y = deinterlace_line_planar_y_mmx;
+    dism_class->interpolate_scanline_planar_u = deinterlace_line_planar_u_mmx;
+    dism_class->interpolate_scanline_planar_v = deinterlace_line_planar_v_mmx;
+  } else {
+    dism_class->interpolate_scanline_yuy2 = deinterlace_line_packed_c;
+    dism_class->interpolate_scanline_yvyu = deinterlace_line_packed_c;
+    dism_class->interpolate_scanline_uyvy = deinterlace_line_packed_c;
+    dism_class->interpolate_scanline_ayuv = deinterlace_line_packed_c;
+    dism_class->interpolate_scanline_nv12 = deinterlace_line_packed_c;
+    dism_class->interpolate_scanline_nv21 = deinterlace_line_packed_c;
+    dism_class->interpolate_scanline_argb = deinterlace_line_packed_c;
+    dism_class->interpolate_scanline_abgr = deinterlace_line_packed_c;
+    dism_class->interpolate_scanline_rgba = deinterlace_line_packed_c;
+    dism_class->interpolate_scanline_bgra = deinterlace_line_packed_c;
+    dism_class->interpolate_scanline_rgb = deinterlace_line_packed_c;
+    dism_class->interpolate_scanline_bgr = deinterlace_line_packed_c;
+    dism_class->interpolate_scanline_planar_y = deinterlace_line_planar_y_c;
+    dism_class->interpolate_scanline_planar_u = deinterlace_line_planar_u_c;
+    dism_class->interpolate_scanline_planar_v = deinterlace_line_planar_v_c;
+  }
+#else
+  dism_class->interpolate_scanline_ayuv = deinterlace_line_packed_c;
+  dism_class->interpolate_scanline_yuy2 = deinterlace_line_packed_c;
+  dism_class->interpolate_scanline_yvyu = deinterlace_line_packed_c;
+  dism_class->interpolate_scanline_uyvy = deinterlace_line_packed_c;
+  dism_class->interpolate_scanline_nv12 = deinterlace_line_packed_c;
+  dism_class->interpolate_scanline_nv21 = deinterlace_line_packed_c;
+  dism_class->interpolate_scanline_argb = deinterlace_line_packed_c;
+  dism_class->interpolate_scanline_abgr = deinterlace_line_packed_c;
+  dism_class->interpolate_scanline_rgba = deinterlace_line_packed_c;
+  dism_class->interpolate_scanline_bgra = deinterlace_line_packed_c;
+  dism_class->interpolate_scanline_rgb = deinterlace_line_packed_c;
+  dism_class->interpolate_scanline_bgr = deinterlace_line_packed_c;
+  dism_class->interpolate_scanline_planar_y = deinterlace_line_planar_y_c;
+  dism_class->interpolate_scanline_planar_u = deinterlace_line_planar_u_c;
+  dism_class->interpolate_scanline_planar_v = deinterlace_line_planar_v_c;
+#endif
+}
+
+static void
+gst_deinterlace_method_vfir_init (GstDeinterlaceMethodVFIR * self)
+{
+}
diff --git a/gst/deinterlace/tvtime/weave.c b/gst/deinterlace/tvtime/weave.c
new file mode 100644
index 0000000..804c889
--- /dev/null
+++ b/gst/deinterlace/tvtime/weave.c
@@ -0,0 +1,173 @@
+/*
+ * Weave frames
+ * Copyright (C) 2002 Billy Biggs <vektor@dumbterm.net>.
+ * Copyright (C) 2008,2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstdeinterlacemethod.h"
+#include <string.h>
+
+#define GST_TYPE_DEINTERLACE_METHOD_WEAVE	(gst_deinterlace_method_weave_get_type ())
+#define GST_IS_DEINTERLACE_METHOD_WEAVE(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE))
+#define GST_IS_DEINTERLACE_METHOD_WEAVE_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE))
+#define GST_DEINTERLACE_METHOD_WEAVE_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE, GstDeinterlaceMethodWeaveClass))
+#define GST_DEINTERLACE_METHOD_WEAVE(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE, GstDeinterlaceMethodWeave))
+#define GST_DEINTERLACE_METHOD_WEAVE_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE, GstDeinterlaceMethodWeaveClass))
+#define GST_DEINTERLACE_METHOD_WEAVE_CAST(obj)	((GstDeinterlaceMethodWeave*)(obj))
+
+GType gst_deinterlace_method_weave_get_type (void);
+
+typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodWeave;
+typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodWeaveClass;
+
+static void
+deinterlace_scanline_weave_packed (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  if (scanlines->m1 == NULL) {
+    memcpy (out, scanlines->t0, size);
+  } else {
+    memcpy (out, scanlines->m1, size);
+  }
+}
+
+static void
+deinterlace_scanline_weave_planar_y (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  if (scanlines->m1 == NULL) {
+    memcpy (out, scanlines->t0, size);
+  } else {
+    memcpy (out, scanlines->m1, size);
+  }
+}
+
+static void
+deinterlace_scanline_weave_planar_u (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  if (scanlines->m1 == NULL) {
+    memcpy (out, scanlines->t0, size);
+  } else {
+    memcpy (out, scanlines->m1, size);
+  }
+}
+
+static void
+deinterlace_scanline_weave_planar_v (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  if (scanlines->m1 == NULL) {
+    memcpy (out, scanlines->t0, size);
+  } else {
+    memcpy (out, scanlines->m1, size);
+  }
+}
+
+static void
+copy_scanline_packed (GstDeinterlaceSimpleMethod * self, guint8 * out,
+    const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+static void
+copy_scanline_planar_y (GstDeinterlaceSimpleMethod * self, guint8 * out,
+    const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+static void
+copy_scanline_planar_u (GstDeinterlaceSimpleMethod * self, guint8 * out,
+    const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+static void
+copy_scanline_planar_v (GstDeinterlaceSimpleMethod * self, guint8 * out,
+    const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+G_DEFINE_TYPE (GstDeinterlaceMethodWeave, gst_deinterlace_method_weave,
+    GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
+
+static void
+gst_deinterlace_method_weave_class_init (GstDeinterlaceMethodWeaveClass * klass)
+{
+  GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
+  GstDeinterlaceSimpleMethodClass *dism_class =
+      (GstDeinterlaceSimpleMethodClass *) klass;
+
+  dim_class->fields_required = 2;
+  dim_class->name = "Weave";
+  dim_class->nick = "weave";
+  dim_class->latency = 1;
+
+  dism_class->interpolate_scanline_ayuv = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_yuy2 = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_yvyu = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_uyvy = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_nv12 = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_nv21 = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_argb = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_abgr = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_rgba = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_bgra = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_rgb = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_bgr = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_planar_y =
+      deinterlace_scanline_weave_planar_y;
+  dism_class->interpolate_scanline_planar_u =
+      deinterlace_scanline_weave_planar_u;
+  dism_class->interpolate_scanline_planar_v =
+      deinterlace_scanline_weave_planar_v;
+
+  dism_class->copy_scanline_ayuv = copy_scanline_packed;
+  dism_class->copy_scanline_yuy2 = copy_scanline_packed;
+  dism_class->copy_scanline_yvyu = copy_scanline_packed;
+  dism_class->copy_scanline_uyvy = copy_scanline_packed;
+  dism_class->copy_scanline_nv12 = copy_scanline_packed;
+  dism_class->copy_scanline_nv21 = copy_scanline_packed;
+  dism_class->copy_scanline_argb = copy_scanline_packed;
+  dism_class->copy_scanline_abgr = copy_scanline_packed;
+  dism_class->copy_scanline_rgba = copy_scanline_packed;
+  dism_class->copy_scanline_bgra = copy_scanline_packed;
+  dism_class->copy_scanline_rgb = copy_scanline_packed;
+  dism_class->copy_scanline_bgr = copy_scanline_packed;
+  dism_class->copy_scanline_planar_y = copy_scanline_planar_y;
+  dism_class->copy_scanline_planar_u = copy_scanline_planar_u;
+  dism_class->copy_scanline_planar_v = copy_scanline_planar_v;
+}
+
+static void
+gst_deinterlace_method_weave_init (GstDeinterlaceMethodWeave * self)
+{
+}
diff --git a/gst/deinterlace/tvtime/weavebff.c b/gst/deinterlace/tvtime/weavebff.c
new file mode 100644
index 0000000..7424e96
--- /dev/null
+++ b/gst/deinterlace/tvtime/weavebff.c
@@ -0,0 +1,174 @@
+/*
+ * Weave frames, bottom-field-first.
+ * Copyright (C) 2003 Billy Biggs <vektor@dumbterm.net>.
+ * Copyright (C) 2008,2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstdeinterlacemethod.h"
+#include <string.h>
+
+#define GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF	(gst_deinterlace_method_weave_bff_get_type ())
+#define GST_IS_DEINTERLACE_METHOD_WEAVE_BFF(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF))
+#define GST_IS_DEINTERLACE_METHOD_WEAVE_BFF_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF))
+#define GST_DEINTERLACE_METHOD_WEAVE_BFF_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF, GstDeinterlaceMethodWeaveBFFClass))
+#define GST_DEINTERLACE_METHOD_WEAVE_BFF(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF, GstDeinterlaceMethodWeaveBFF))
+#define GST_DEINTERLACE_METHOD_WEAVE_BFF_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF, GstDeinterlaceMethodWeaveBFFClass))
+#define GST_DEINTERLACE_METHOD_WEAVE_BFF_CAST(obj)	((GstDeinterlaceMethodWeaveBFF*)(obj))
+
+GType gst_deinterlace_method_weave_bff_get_type (void);
+
+typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodWeaveBFF;
+typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodWeaveBFFClass;
+
+static void
+deinterlace_scanline_weave_packed (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  if (scanlines->m1 == NULL) {
+    memcpy (out, scanlines->b0, size);
+  } else {
+    memcpy (out, scanlines->m1, size);
+  }
+}
+
+static void
+deinterlace_scanline_weave_planar_y (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  if (scanlines->m1 == NULL) {
+    memcpy (out, scanlines->b0, size);
+  } else {
+    memcpy (out, scanlines->m1, size);
+  }
+}
+
+static void
+deinterlace_scanline_weave_planar_u (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  if (scanlines->m1 == NULL) {
+    memcpy (out, scanlines->b0, size);
+  } else {
+    memcpy (out, scanlines->m1, size);
+  }
+}
+
+static void
+deinterlace_scanline_weave_planar_v (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  if (scanlines->m1 == NULL) {
+    memcpy (out, scanlines->b0, size);
+  } else {
+    memcpy (out, scanlines->m1, size);
+  }
+}
+
+static void
+copy_scanline_packed (GstDeinterlaceSimpleMethod * self, guint8 * out,
+    const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+static void
+copy_scanline_planar_y (GstDeinterlaceSimpleMethod * self, guint8 * out,
+    const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+static void
+copy_scanline_planar_u (GstDeinterlaceSimpleMethod * self, guint8 * out,
+    const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+static void
+copy_scanline_planar_v (GstDeinterlaceSimpleMethod * self, guint8 * out,
+    const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+G_DEFINE_TYPE (GstDeinterlaceMethodWeaveBFF, gst_deinterlace_method_weave_bff,
+    GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
+
+static void
+gst_deinterlace_method_weave_bff_class_init (GstDeinterlaceMethodWeaveBFFClass *
+    klass)
+{
+  GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
+  GstDeinterlaceSimpleMethodClass *dism_class =
+      (GstDeinterlaceSimpleMethodClass *) klass;
+
+  dim_class->fields_required = 2;
+  dim_class->name = "Progressive: Bottom Field First";
+  dim_class->nick = "weavebff";
+  dim_class->latency = 1;
+
+  dism_class->interpolate_scanline_ayuv = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_yuy2 = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_yvyu = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_uyvy = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_nv12 = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_nv21 = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_argb = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_abgr = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_rgba = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_bgra = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_rgb = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_bgr = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_planar_y =
+      deinterlace_scanline_weave_planar_y;
+  dism_class->interpolate_scanline_planar_u =
+      deinterlace_scanline_weave_planar_u;
+  dism_class->interpolate_scanline_planar_v =
+      deinterlace_scanline_weave_planar_v;
+
+  dism_class->copy_scanline_ayuv = copy_scanline_packed;
+  dism_class->copy_scanline_yuy2 = copy_scanline_packed;
+  dism_class->copy_scanline_yvyu = copy_scanline_packed;
+  dism_class->copy_scanline_uyvy = copy_scanline_packed;
+  dism_class->copy_scanline_nv12 = copy_scanline_packed;
+  dism_class->copy_scanline_nv21 = copy_scanline_packed;
+  dism_class->copy_scanline_argb = copy_scanline_packed;
+  dism_class->copy_scanline_abgr = copy_scanline_packed;
+  dism_class->copy_scanline_rgba = copy_scanline_packed;
+  dism_class->copy_scanline_bgra = copy_scanline_packed;
+  dism_class->copy_scanline_rgb = copy_scanline_packed;
+  dism_class->copy_scanline_bgr = copy_scanline_packed;
+  dism_class->copy_scanline_planar_y = copy_scanline_planar_y;
+  dism_class->copy_scanline_planar_u = copy_scanline_planar_u;
+  dism_class->copy_scanline_planar_v = copy_scanline_planar_v;
+}
+
+static void
+gst_deinterlace_method_weave_bff_init (GstDeinterlaceMethodWeaveBFF * self)
+{
+}
diff --git a/gst/deinterlace/tvtime/weavetff.c b/gst/deinterlace/tvtime/weavetff.c
new file mode 100644
index 0000000..f33bb2e
--- /dev/null
+++ b/gst/deinterlace/tvtime/weavetff.c
@@ -0,0 +1,175 @@
+/*
+ * Weave frames, top-field-first.
+ * Copyright (C) 2003 Billy Biggs <vektor@dumbterm.net>.
+ * Copyright (C) 2008,2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstdeinterlacemethod.h"
+#include <string.h>
+
+#define GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF	(gst_deinterlace_method_weave_tff_get_type ())
+#define GST_IS_DEINTERLACE_METHOD_WEAVE_TFF(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF))
+#define GST_IS_DEINTERLACE_METHOD_WEAVE_TFF_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF))
+#define GST_DEINTERLACE_METHOD_WEAVE_TFF_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF, GstDeinterlaceMethodWeaveTFFClass))
+#define GST_DEINTERLACE_METHOD_WEAVE_TFF(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF, GstDeinterlaceMethodWeaveTFF))
+#define GST_DEINTERLACE_METHOD_WEAVE_TFF_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF, GstDeinterlaceMethodWeaveTFFClass))
+#define GST_DEINTERLACE_METHOD_WEAVE_TFF_CAST(obj)	((GstDeinterlaceMethodWeaveTFF*)(obj))
+
+GType gst_deinterlace_method_weave_tff_get_type (void);
+
+typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodWeaveTFF;
+typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodWeaveTFFClass;
+
+static void
+deinterlace_scanline_weave_packed (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  if (scanlines->m1 == NULL) {
+    memcpy (out, scanlines->t0, size);
+  } else {
+    memcpy (out, scanlines->m1, size);
+  }
+}
+
+static void
+deinterlace_scanline_weave_planar_y (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  if (scanlines->m1 == NULL) {
+    memcpy (out, scanlines->t0, size);
+  } else {
+    memcpy (out, scanlines->m1, size);
+  }
+}
+
+static void
+deinterlace_scanline_weave_planar_u (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  if (scanlines->m1 == NULL) {
+    memcpy (out, scanlines->t0, size);
+  } else {
+    memcpy (out, scanlines->m1, size);
+  }
+}
+
+static void
+deinterlace_scanline_weave_planar_v (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  if (scanlines->m1 == NULL) {
+    memcpy (out, scanlines->t0, size);
+  } else {
+    memcpy (out, scanlines->m1, size);
+  }
+}
+
+static void
+copy_scanline_packed (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+static void
+copy_scanline_planar_y (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+static void
+copy_scanline_planar_u (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+static void
+copy_scanline_planar_v (GstDeinterlaceSimpleMethod * self,
+    guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size)
+{
+  memcpy (out, scanlines->m0, size);
+}
+
+G_DEFINE_TYPE (GstDeinterlaceMethodWeaveTFF, gst_deinterlace_method_weave_tff,
+    GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
+
+static void
+gst_deinterlace_method_weave_tff_class_init (GstDeinterlaceMethodWeaveTFFClass *
+    klass)
+{
+  GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
+  GstDeinterlaceSimpleMethodClass *dism_class =
+      (GstDeinterlaceSimpleMethodClass *) klass;
+
+  dim_class->fields_required = 2;
+  dim_class->name = "Progressive: Top Field First";
+  dim_class->nick = "weavetff";
+  dim_class->latency = 1;
+
+  dism_class->interpolate_scanline_ayuv = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_yuy2 = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_yvyu = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_uyvy = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_nv12 = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_nv21 = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_argb = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_abgr = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_rgba = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_bgra = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_rgb = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_bgr = deinterlace_scanline_weave_packed;
+  dism_class->interpolate_scanline_planar_y =
+      deinterlace_scanline_weave_planar_y;
+  dism_class->interpolate_scanline_planar_u =
+      deinterlace_scanline_weave_planar_u;
+  dism_class->interpolate_scanline_planar_v =
+      deinterlace_scanline_weave_planar_v;
+
+  dism_class->copy_scanline_ayuv = copy_scanline_packed;
+  dism_class->copy_scanline_yuy2 = copy_scanline_packed;
+  dism_class->copy_scanline_yvyu = copy_scanline_packed;
+  dism_class->copy_scanline_uyvy = copy_scanline_packed;
+  dism_class->copy_scanline_nv12 = copy_scanline_packed;
+  dism_class->copy_scanline_nv21 = copy_scanline_packed;
+  dism_class->copy_scanline_argb = copy_scanline_packed;
+  dism_class->copy_scanline_abgr = copy_scanline_packed;
+  dism_class->copy_scanline_rgba = copy_scanline_packed;
+  dism_class->copy_scanline_bgra = copy_scanline_packed;
+  dism_class->copy_scanline_rgb = copy_scanline_packed;
+  dism_class->copy_scanline_bgr = copy_scanline_packed;
+  dism_class->copy_scanline_planar_y = copy_scanline_planar_y;
+  dism_class->copy_scanline_planar_u = copy_scanline_planar_u;
+  dism_class->copy_scanline_planar_v = copy_scanline_planar_v;
+}
+
+static void
+gst_deinterlace_method_weave_tff_init (GstDeinterlaceMethodWeaveTFF * self)
+{
+}
diff --git a/gst/deinterlace/tvtime/x86-64_macros.inc b/gst/deinterlace/tvtime/x86-64_macros.inc
new file mode 100644
index 0000000..312e3c7
--- /dev/null
+++ b/gst/deinterlace/tvtime/x86-64_macros.inc
@@ -0,0 +1,82 @@
+/*
+ *
+ * GStreamer
+ * Copyright (C) 2004 Dirk Ziegelmeier <dziegel@gmx.de>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * 
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
+ */
+
+/*
+ * This file is copied from TVTIME's sources.
+ * Original author: Achim Schneider <batchall@mordor.ch>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef XAX
+
+#if defined (HAVE_CPU_I386) && !defined(HAVE_CPU_X86_64)
+
+#define XAX   "eax"
+#define XBX   "ebx"
+#define XCX   "ecx"
+#define XDX   "edx"
+#define XSI   "esi"
+#define XDI   "edi"
+#define XSP   "esp"
+#define MOVX  "movl"
+#define LEAX  "leal"
+#define DECX  "decl"
+#define PUSHX "pushl"
+#define POPX  "popl"
+#define CMPX  "cmpl"
+#define ADDX  "addl"
+#define SHLX  "shll"
+#define SHRX  "shrl"
+#define SUBX  "subl"
+
+#elif defined (HAVE_CPU_X86_64)
+
+#define XAX   "rax"
+#define XBX   "rbx"
+#define XCX   "rcx"
+#define XDX   "rdx"
+#define XSI   "rsi"
+#define XDI   "rdi"
+#define XSP   "rsp"
+#define MOVX  "movq"
+#define LEAX  "leaq"
+#define DECX  "decq"
+#define PUSHX "pushq"
+#define POPX  "popq"
+#define CMPX  "cmpq"
+#define ADDX  "addq"
+#define SHLX  "shlq"
+#define SHRX  "shrq"
+#define SUBX  "subq"
+
+#else
+#error Undefined architecture. Define either ARCH_X86 or ARCH_X86_64.
+#endif
+
+#endif
diff --git a/gst/dtmf/Makefile.am b/gst/dtmf/Makefile.am
new file mode 100644
index 0000000..68f8ce8
--- /dev/null
+++ b/gst/dtmf/Makefile.am
@@ -0,0 +1,16 @@
+plugin_LTLIBRARIES = libgstdtmf.la
+
+libgstdtmf_la_SOURCES = gstdtmfsrc.c \
+                        gstrtpdtmfsrc.c \
+                        gstrtpdtmfdepay.c \
+                        gstdtmf.c
+
+noinst_HEADERS = gstdtmfsrc.h \
+                 gstrtpdtmfsrc.h \
+                 gstrtpdtmfdepay.h \
+                 gstdtmfcommon.h
+
+libgstdtmf_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+libgstdtmf_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-@GST_API_VERSION@ \
+	$(GST_BASE_LIBS) $(GST_LIBS) $(LIBM)
+libgstdtmf_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
diff --git a/gst/dtmf/gstdtmf.c b/gst/dtmf/gstdtmf.c
new file mode 100644
index 0000000..1dc4001
--- /dev/null
+++ b/gst/dtmf/gstdtmf.c
@@ -0,0 +1,45 @@
+/* GStreamer DTMF plugin
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstdtmfsrc.h"
+#include "gstrtpdtmfsrc.h"
+#include "gstrtpdtmfdepay.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_dtmf_src_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_dtmf_src_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_dtmf_depay_plugin_init (plugin))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    dtmf, "DTMF plugins",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/dtmf/gstdtmfcommon.h b/gst/dtmf/gstdtmfcommon.h
new file mode 100644
index 0000000..36f26cc
--- /dev/null
+++ b/gst/dtmf/gstdtmfcommon.h
@@ -0,0 +1,52 @@
+/* GStreamer DTMF plugin
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_DTMF_COMMON_H__
+#define __GST_RTP_DTMF_COMMON_H__
+
+#include <gst/math-compat.h>
+
+#define MIN_INTER_DIGIT_INTERVAL 100     /* ms */
+#define MIN_PULSE_DURATION       250     /* ms */
+
+#define MIN_VOLUME               0
+#define MAX_VOLUME               36
+
+#define MIN_EVENT                0
+#define MAX_EVENT                15
+#define MIN_EVENT_STRING         "0"
+#define MAX_EVENT_STRING         "15"
+
+typedef struct
+{
+  unsigned event:8;             /* Current DTMF event */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+  unsigned volume:6;            /* power level of the tone, in dBm0 */
+  unsigned r:1;                 /* Reserved-bit */
+  unsigned e:1;                 /* End-bit */
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+  unsigned e:1;                 /* End-bit */
+  unsigned r:1;                 /* Reserved-bit */
+  unsigned volume:6;            /* power level of the tone, in dBm0 */
+#else
+#error "G_BYTE_ORDER should be big or little endian."
+#endif
+  unsigned duration:16;         /* Duration of digit, in timestamp units */
+} GstRTPDTMFPayload;
+
+#endif /* __GST_RTP_DTMF_COMMON_H__ */
diff --git a/gst/dtmf/gstdtmfsrc.c b/gst/dtmf/gstdtmfsrc.c
new file mode 100644
index 0000000..88f0f08
--- /dev/null
+++ b/gst/dtmf/gstdtmfsrc.c
@@ -0,0 +1,998 @@
+/* GStreamer DTMF source
+ *
+ * gstdtmfsrc.c:
+ *
+ * Copyright (C) <2007> Collabora.
+ *   Contact: Youness Alaoui <youness.alaoui@collabora.co.uk>
+ * Copyright (C) <2007> Nokia Corporation.
+ *   Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2000,2005 Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-dtmfsrc
+ * @see_also: rtpdtmsrc, rtpdtmfmuxx
+ *
+ * The DTMFSrc element generates DTMF (ITU-T Q.23 Specification) tone packets on request
+ * from application. The application communicates the beginning and end of a
+ * DTMF event using custom upstream gstreamer events. To report a DTMF event, an
+ * application must send an event of type GST_EVENT_CUSTOM_UPSTREAM, having a
+ * structure of name "dtmf-event" with fields set according to the following
+ * table:
+ *
+ * <informaltable>
+ * <tgroup cols='4'>
+ * <colspec colname='Name' />
+ * <colspec colname='Type' />
+ * <colspec colname='Possible values' />
+ * <colspec colname='Purpose' />
+ * <thead>
+ * <row>
+ * <entry>Name</entry>
+ * <entry>GType</entry>
+ * <entry>Possible values</entry>
+ * <entry>Purpose</entry>
+ * </row>
+ * </thead>
+ * <tbody>
+ * <row>
+ * <entry>type</entry>
+ * <entry>G_TYPE_INT</entry>
+ * <entry>0-1</entry>
+ * <entry>The application uses this field to specify which of the two methods
+ * specified in RFC 2833 to use. The value should be 0 for tones and 1 for
+ * named events. Tones are specified by their frequencies and events are specied
+ * by their number. This element can only take events as input. Do not confuse
+ * with "method" which specified the output.
+ * </entry>
+ * </row>
+ * <row>
+ * <entry>number</entry>
+ * <entry>G_TYPE_INT</entry>
+ * <entry>0-15</entry>
+ * <entry>The event number.</entry>
+ * </row>
+ * <row>
+ * <entry>volume</entry>
+ * <entry>G_TYPE_INT</entry>
+ * <entry>0-36</entry>
+ * <entry>This field describes the power level of the tone, expressed in dBm0
+ * after dropping the sign. Power levels range from 0 to -63 dBm0. The range of
+ * valid DTMF is from 0 to -36 dBm0. Can be omitted if start is set to FALSE.
+ * </entry>
+ * </row>
+ * <row>
+ * <entry>start</entry>
+ * <entry>G_TYPE_BOOLEAN</entry>
+ * <entry>True or False</entry>
+ * <entry>Whether the event is starting or ending.</entry>
+ * </row>
+ * <row>
+ * <entry>method</entry>
+ * <entry>G_TYPE_INT</entry>
+ * <entry>2</entry>
+ * <entry>The method used for sending event, this element will react if this
+ * field is absent or 2.
+ * </entry>
+ * </row>
+ * </tbody>
+ * </tgroup>
+ * </informaltable>
+ *
+ * For example, the following code informs the pipeline (and in turn, the
+ * DTMFSrc element inside the pipeline) about the start of a DTMF named
+ * event '1' of volume -25 dBm0:
+ *
+ * <programlisting>
+ * structure = gst_structure_new ("dtmf-event",
+ *                    "type", G_TYPE_INT, 1,
+ *                    "number", G_TYPE_INT, 1,
+ *                    "volume", G_TYPE_INT, 25,
+ *                    "start", G_TYPE_BOOLEAN, TRUE, NULL);
+ *
+ * event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, structure);
+ * gst_element_send_event (pipeline, event);
+ * </programlisting>
+ *
+ * When a DTMF tone actually starts or stop, a "dtmf-event-processed"
+ * element #GstMessage with the same fields as the "dtmf-event"
+ * #GstEvent that was used to request the event. Also, if any event
+ * has not been processed when the element goes from the PAUSED to the
+ * READY state, then a "dtmf-event-dropped" message is posted on the
+ * #GstBus in the order that they were received.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <glib.h>
+
+#include "gstdtmfcommon.h"
+
+#include "gstdtmfsrc.h"
+
+#include <gst/audio/audio.h>
+
+#define GST_TONE_DTMF_TYPE_EVENT 1
+#define DEFAULT_PACKET_INTERVAL  50     /* ms */
+#define MIN_PACKET_INTERVAL      10     /* ms */
+#define MAX_PACKET_INTERVAL      50     /* ms */
+#define DEFAULT_SAMPLE_RATE      8000
+#define SAMPLE_SIZE              16
+#define CHANNELS                 1
+#define MIN_DUTY_CYCLE           (MIN_INTER_DIGIT_INTERVAL + MIN_PULSE_DURATION)
+
+
+typedef struct st_dtmf_key
+{
+  const char *event_name;
+  int event_encoding;
+  float low_frequency;
+  float high_frequency;
+} DTMF_KEY;
+
+static const DTMF_KEY DTMF_KEYS[] = {
+  {"DTMF_KEY_EVENT_0", 0, 941, 1336},
+  {"DTMF_KEY_EVENT_1", 1, 697, 1209},
+  {"DTMF_KEY_EVENT_2", 2, 697, 1336},
+  {"DTMF_KEY_EVENT_3", 3, 697, 1477},
+  {"DTMF_KEY_EVENT_4", 4, 770, 1209},
+  {"DTMF_KEY_EVENT_5", 5, 770, 1336},
+  {"DTMF_KEY_EVENT_6", 6, 770, 1477},
+  {"DTMF_KEY_EVENT_7", 7, 852, 1209},
+  {"DTMF_KEY_EVENT_8", 8, 852, 1336},
+  {"DTMF_KEY_EVENT_9", 9, 852, 1477},
+  {"DTMF_KEY_EVENT_S", 10, 941, 1209},
+  {"DTMF_KEY_EVENT_P", 11, 941, 1477},
+  {"DTMF_KEY_EVENT_A", 12, 697, 1633},
+  {"DTMF_KEY_EVENT_B", 13, 770, 1633},
+  {"DTMF_KEY_EVENT_C", 14, 852, 1633},
+  {"DTMF_KEY_EVENT_D", 15, 941, 1633},
+};
+
+#define MAX_DTMF_EVENTS 16
+
+enum
+{
+  DTMF_KEY_EVENT_1 = 1,
+  DTMF_KEY_EVENT_2 = 2,
+  DTMF_KEY_EVENT_3 = 3,
+  DTMF_KEY_EVENT_4 = 4,
+  DTMF_KEY_EVENT_5 = 5,
+  DTMF_KEY_EVENT_6 = 6,
+  DTMF_KEY_EVENT_7 = 7,
+  DTMF_KEY_EVENT_8 = 8,
+  DTMF_KEY_EVENT_9 = 9,
+  DTMF_KEY_EVENT_0 = 0,
+  DTMF_KEY_EVENT_STAR = 10,
+  DTMF_KEY_EVENT_POUND = 11,
+  DTMF_KEY_EVENT_A = 12,
+  DTMF_KEY_EVENT_B = 13,
+  DTMF_KEY_EVENT_C = 14,
+  DTMF_KEY_EVENT_D = 15,
+};
+
+GST_DEBUG_CATEGORY_STATIC (gst_dtmf_src_debug);
+#define GST_CAT_DEFAULT gst_dtmf_src_debug
+
+enum
+{
+  PROP_0,
+  PROP_INTERVAL,
+};
+
+static GstStaticPadTemplate gst_dtmf_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) \"" GST_AUDIO_NE (S16) "\", "
+        "rate = " GST_AUDIO_RATE_RANGE ", " "channels = (int) 1")
+    );
+
+#define parent_class gst_dtmf_src_parent_class
+G_DEFINE_TYPE (GstDTMFSrc, gst_dtmf_src, GST_TYPE_BASE_SRC);
+
+static void gst_dtmf_src_finalize (GObject * object);
+
+static void gst_dtmf_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_dtmf_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static gboolean gst_dtmf_src_handle_event (GstBaseSrc * src, GstEvent * event);
+static gboolean gst_dtmf_src_send_event (GstElement * src, GstEvent * event);
+static GstStateChangeReturn gst_dtmf_src_change_state (GstElement * element,
+    GstStateChange transition);
+static GstFlowReturn gst_dtmf_src_create (GstBaseSrc * basesrc,
+    guint64 offset, guint length, GstBuffer ** buffer);
+static void gst_dtmf_src_add_start_event (GstDTMFSrc * dtmfsrc,
+    gint event_number, gint event_volume);
+static void gst_dtmf_src_add_stop_event (GstDTMFSrc * dtmfsrc);
+
+static gboolean gst_dtmf_src_unlock (GstBaseSrc * src);
+
+static gboolean gst_dtmf_src_unlock_stop (GstBaseSrc * src);
+static gboolean gst_dtmf_src_negotiate (GstBaseSrc * basesrc);
+static gboolean gst_dtmf_src_query (GstBaseSrc * basesrc, GstQuery * query);
+
+
+static void
+gst_dtmf_src_class_init (GstDTMFSrcClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstBaseSrcClass *gstbasesrc_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
+  gstelement_class = GST_ELEMENT_CLASS (klass);
+
+
+  GST_DEBUG_CATEGORY_INIT (gst_dtmf_src_debug, "dtmfsrc", 0, "dtmfsrc element");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_dtmf_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "DTMF tone generator", "Source/Audio", "Generates DTMF tones",
+      "Youness Alaoui <youness.alaoui@collabora.co.uk>");
+
+
+  gobject_class->finalize = gst_dtmf_src_finalize;
+  gobject_class->set_property = gst_dtmf_src_set_property;
+  gobject_class->get_property = gst_dtmf_src_get_property;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_INTERVAL,
+      g_param_spec_uint ("interval", "Interval between tone packets",
+          "Interval in ms between two tone packets", MIN_PACKET_INTERVAL,
+          MAX_PACKET_INTERVAL, DEFAULT_PACKET_INTERVAL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_dtmf_src_change_state);
+  gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_dtmf_src_send_event);
+  gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_dtmf_src_unlock);
+  gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_dtmf_src_unlock_stop);
+
+  gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_dtmf_src_handle_event);
+  gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_dtmf_src_create);
+  gstbasesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_dtmf_src_negotiate);
+  gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_dtmf_src_query);
+}
+
+static void
+event_free (GstDTMFSrcEvent * event)
+{
+  if (event)
+    g_slice_free (GstDTMFSrcEvent, event);
+}
+
+static void
+gst_dtmf_src_init (GstDTMFSrc * dtmfsrc)
+{
+  /* we operate in time */
+  gst_base_src_set_format (GST_BASE_SRC (dtmfsrc), GST_FORMAT_TIME);
+  gst_base_src_set_live (GST_BASE_SRC (dtmfsrc), TRUE);
+
+  dtmfsrc->interval = DEFAULT_PACKET_INTERVAL;
+
+  dtmfsrc->event_queue = g_async_queue_new_full ((GDestroyNotify) event_free);
+  dtmfsrc->last_event = NULL;
+
+  dtmfsrc->sample_rate = DEFAULT_SAMPLE_RATE;
+
+  GST_DEBUG_OBJECT (dtmfsrc, "init done");
+}
+
+static void
+gst_dtmf_src_finalize (GObject * object)
+{
+  GstDTMFSrc *dtmfsrc;
+
+  dtmfsrc = GST_DTMF_SRC (object);
+
+  if (dtmfsrc->event_queue) {
+    g_async_queue_unref (dtmfsrc->event_queue);
+    dtmfsrc->event_queue = NULL;
+  }
+
+  G_OBJECT_CLASS (gst_dtmf_src_parent_class)->finalize (object);
+}
+
+static gboolean
+gst_dtmf_src_handle_dtmf_event (GstDTMFSrc * dtmfsrc, GstEvent * event)
+{
+  const GstStructure *event_structure;
+  GstStateChangeReturn sret;
+  GstState state;
+  gint event_type;
+  gboolean start;
+  gint method;
+  GstClockTime last_stop;
+  gint event_number;
+  gint event_volume;
+  gboolean correct_order;
+
+  sret = gst_element_get_state (GST_ELEMENT (dtmfsrc), &state, NULL, 0);
+  if (sret != GST_STATE_CHANGE_SUCCESS || state != GST_STATE_PLAYING) {
+    GST_DEBUG_OBJECT (dtmfsrc, "dtmf-event, but not in PLAYING state");
+    goto failure;
+  }
+
+  event_structure = gst_event_get_structure (event);
+
+  if (!gst_structure_get_int (event_structure, "type", &event_type) ||
+      !gst_structure_get_boolean (event_structure, "start", &start) ||
+      (start == TRUE && event_type != GST_TONE_DTMF_TYPE_EVENT))
+    goto failure;
+
+  if (gst_structure_get_int (event_structure, "method", &method)) {
+    if (method != 2) {
+      goto failure;
+    }
+  }
+
+  if (start)
+    if (!gst_structure_get_int (event_structure, "number", &event_number) ||
+        !gst_structure_get_int (event_structure, "volume", &event_volume))
+      goto failure;
+
+
+  GST_OBJECT_LOCK (dtmfsrc);
+  if (gst_structure_get_clock_time (event_structure, "last-stop", &last_stop))
+    dtmfsrc->last_stop = last_stop;
+  else
+    dtmfsrc->last_stop = GST_CLOCK_TIME_NONE;
+  correct_order = (start != dtmfsrc->last_event_was_start);
+  dtmfsrc->last_event_was_start = start;
+  GST_OBJECT_UNLOCK (dtmfsrc);
+
+  if (!correct_order)
+    goto failure;
+
+  if (start) {
+    GST_DEBUG_OBJECT (dtmfsrc, "Received start event %d with volume %d",
+        event_number, event_volume);
+    gst_dtmf_src_add_start_event (dtmfsrc, event_number, event_volume);
+  }
+
+  else {
+    GST_DEBUG_OBJECT (dtmfsrc, "Received stop event");
+    gst_dtmf_src_add_stop_event (dtmfsrc);
+  }
+
+  return TRUE;
+failure:
+  return FALSE;
+}
+
+static gboolean
+gst_dtmf_src_handle_event (GstBaseSrc * src, GstEvent * event)
+{
+  GstDTMFSrc *dtmfsrc;
+  gboolean result = FALSE;
+
+  dtmfsrc = GST_DTMF_SRC (src);
+
+  GST_LOG_OBJECT (dtmfsrc, "Received an %s event on the src pad",
+      GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CUSTOM_UPSTREAM:
+      if (gst_event_has_name (event, "dtmf-event")) {
+        result = gst_dtmf_src_handle_dtmf_event (dtmfsrc, event);
+        break;
+      }
+      /* fall through */
+    default:
+      result = GST_BASE_SRC_CLASS (parent_class)->event (src, event);
+      break;
+  }
+
+  return result;
+}
+
+
+static gboolean
+gst_dtmf_src_send_event (GstElement * element, GstEvent * event)
+{
+  GstDTMFSrc *dtmfsrc = GST_DTMF_SRC (element);
+  gboolean ret;
+
+  GST_LOG_OBJECT (dtmfsrc, "Received an %s event via send_event",
+      GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CUSTOM_BOTH:
+    case GST_EVENT_CUSTOM_BOTH_OOB:
+    case GST_EVENT_CUSTOM_UPSTREAM:
+    case GST_EVENT_CUSTOM_DOWNSTREAM:
+    case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:
+      if (gst_event_has_name (event, "dtmf-event")) {
+        ret = gst_dtmf_src_handle_dtmf_event (dtmfsrc, event);
+        break;
+      }
+      /* fall through */
+    default:
+      ret = GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_dtmf_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstDTMFSrc *dtmfsrc;
+
+  dtmfsrc = GST_DTMF_SRC (object);
+
+  switch (prop_id) {
+    case PROP_INTERVAL:
+      dtmfsrc->interval = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_dtmf_src_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstDTMFSrc *dtmfsrc;
+
+  dtmfsrc = GST_DTMF_SRC (object);
+
+  switch (prop_id) {
+    case PROP_INTERVAL:
+      g_value_set_uint (value, dtmfsrc->interval);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_dtmf_prepare_timestamps (GstDTMFSrc * dtmfsrc)
+{
+  GstClockTime last_stop;
+  GstClockTime timestamp;
+
+  GST_OBJECT_LOCK (dtmfsrc);
+  last_stop = dtmfsrc->last_stop;
+  GST_OBJECT_UNLOCK (dtmfsrc);
+
+  if (GST_CLOCK_TIME_IS_VALID (last_stop)) {
+    timestamp = last_stop;
+  } else {
+    GstClock *clock;
+
+    /* If there is no valid start time, lets use now as the start time */
+
+    clock = gst_element_get_clock (GST_ELEMENT (dtmfsrc));
+    if (clock != NULL) {
+      timestamp = gst_clock_get_time (clock)
+          - gst_element_get_base_time (GST_ELEMENT (dtmfsrc));
+      gst_object_unref (clock);
+    } else {
+      gchar *dtmf_name = gst_element_get_name (dtmfsrc);
+      GST_ERROR_OBJECT (dtmfsrc, "No clock set for element %s", dtmf_name);
+      dtmfsrc->timestamp = GST_CLOCK_TIME_NONE;
+      g_free (dtmf_name);
+      return;
+    }
+  }
+
+  /* Make sure the timestamp always goes forward */
+  if (timestamp > dtmfsrc->timestamp)
+    dtmfsrc->timestamp = timestamp;
+}
+
+static void
+gst_dtmf_src_add_start_event (GstDTMFSrc * dtmfsrc, gint event_number,
+    gint event_volume)
+{
+
+  GstDTMFSrcEvent *event = g_slice_new0 (GstDTMFSrcEvent);
+  event->event_type = DTMF_EVENT_TYPE_START;
+  event->sample = 0;
+  event->event_number = CLAMP (event_number, MIN_EVENT, MAX_EVENT);
+  event->volume = CLAMP (event_volume, MIN_VOLUME, MAX_VOLUME);
+
+  g_async_queue_push (dtmfsrc->event_queue, event);
+}
+
+static void
+gst_dtmf_src_add_stop_event (GstDTMFSrc * dtmfsrc)
+{
+
+  GstDTMFSrcEvent *event = g_slice_new0 (GstDTMFSrcEvent);
+  event->event_type = DTMF_EVENT_TYPE_STOP;
+  event->sample = 0;
+  event->event_number = 0;
+  event->volume = 0;
+
+  g_async_queue_push (dtmfsrc->event_queue, event);
+}
+
+static GstBuffer *
+gst_dtmf_src_generate_silence (float duration, gint sample_rate)
+{
+  gint buf_size;
+
+  /* Create a buffer with data set to 0 */
+  buf_size = ((duration / 1000) * sample_rate * SAMPLE_SIZE * CHANNELS) / 8;
+
+  return gst_buffer_new_wrapped (g_malloc0 (buf_size), buf_size);
+}
+
+static GstBuffer *
+gst_dtmf_src_generate_tone (GstDTMFSrcEvent * event, DTMF_KEY key,
+    float duration, gint sample_rate)
+{
+  GstBuffer *buffer;
+  GstMapInfo map;
+  gint16 *p;
+  gint tone_size;
+  double i = 0;
+  double amplitude, f1, f2;
+  double volume_factor;
+  static GstAllocationParams params = { 0, 1, 0, 0, };
+
+  /* Create a buffer for the tone */
+  tone_size = ((duration / 1000) * sample_rate * SAMPLE_SIZE * CHANNELS) / 8;
+
+  buffer = gst_buffer_new_allocate (NULL, tone_size, &params);
+
+  gst_buffer_map (buffer, &map, GST_MAP_READWRITE);
+  p = (gint16 *) map.data;
+
+  volume_factor = pow (10, (-event->volume) / 20);
+
+  /*
+   * For each sample point we calculate 'x' as the
+   * the amplitude value.
+   */
+  for (i = 0; i < (tone_size / (SAMPLE_SIZE / 8)); i++) {
+    /*
+     * We add the fundamental frequencies together.
+     */
+    f1 = sin (2 * M_PI * key.low_frequency * (event->sample / sample_rate));
+    f2 = sin (2 * M_PI * key.high_frequency * (event->sample / sample_rate));
+
+    amplitude = (f1 + f2) / 2;
+
+    /* Adjust the volume */
+    amplitude *= volume_factor;
+
+    /* Make the [-1:1] interval into a [-32767:32767] interval */
+    amplitude *= 32767;
+
+    /* Store it in the data buffer */
+    *(p++) = (gint16) amplitude;
+
+    (event->sample)++;
+  }
+
+  gst_buffer_unmap (buffer, &map);
+
+  return buffer;
+}
+
+
+
+static GstBuffer *
+gst_dtmf_src_create_next_tone_packet (GstDTMFSrc * dtmfsrc,
+    GstDTMFSrcEvent * event)
+{
+  GstBuffer *buf = NULL;
+  gboolean send_silence = FALSE;
+
+  GST_LOG_OBJECT (dtmfsrc, "Creating buffer for tone %s",
+      DTMF_KEYS[event->event_number].event_name);
+
+  if (event->packet_count * dtmfsrc->interval < MIN_INTER_DIGIT_INTERVAL) {
+    send_silence = TRUE;
+  }
+
+  if (send_silence) {
+    GST_LOG_OBJECT (dtmfsrc, "Generating silence");
+    buf = gst_dtmf_src_generate_silence (dtmfsrc->interval,
+        dtmfsrc->sample_rate);
+  } else {
+    GST_LOG_OBJECT (dtmfsrc, "Generating tone");
+    buf = gst_dtmf_src_generate_tone (event, DTMF_KEYS[event->event_number],
+        dtmfsrc->interval, dtmfsrc->sample_rate);
+  }
+  event->packet_count++;
+
+
+  /* timestamp and duration of GstBuffer */
+  GST_BUFFER_DURATION (buf) = dtmfsrc->interval * GST_MSECOND;
+  GST_BUFFER_TIMESTAMP (buf) = dtmfsrc->timestamp;
+
+  GST_LOG_OBJECT (dtmfsrc, "Creating new buffer with event %u duration "
+      " gst: %" GST_TIME_FORMAT " at %" GST_TIME_FORMAT,
+      event->event_number, GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+
+  dtmfsrc->timestamp += GST_BUFFER_DURATION (buf);
+
+  return buf;
+}
+
+static void
+gst_dtmf_src_post_message (GstDTMFSrc * dtmfsrc, const gchar * message_name,
+    GstDTMFSrcEvent * event)
+{
+  GstStructure *s = NULL;
+
+  switch (event->event_type) {
+    case DTMF_EVENT_TYPE_START:
+      s = gst_structure_new (message_name,
+          "type", G_TYPE_INT, 1,
+          "method", G_TYPE_INT, 2,
+          "start", G_TYPE_BOOLEAN, TRUE,
+          "number", G_TYPE_INT, event->event_number,
+          "volume", G_TYPE_INT, event->volume, NULL);
+      break;
+    case DTMF_EVENT_TYPE_STOP:
+      s = gst_structure_new (message_name,
+          "type", G_TYPE_INT, 1, "method", G_TYPE_INT, 2,
+          "start", G_TYPE_BOOLEAN, FALSE, NULL);
+      break;
+    case DTMF_EVENT_TYPE_PAUSE_TASK:
+      return;
+  }
+
+  if (s)
+    gst_element_post_message (GST_ELEMENT (dtmfsrc),
+        gst_message_new_element (GST_OBJECT (dtmfsrc), s));
+}
+
+static GstFlowReturn
+gst_dtmf_src_create (GstBaseSrc * basesrc, guint64 offset,
+    guint length, GstBuffer ** buffer)
+{
+  GstBuffer *buf = NULL;
+  GstDTMFSrcEvent *event;
+  GstDTMFSrc *dtmfsrc;
+  GstClock *clock;
+  GstClockID *clockid;
+  GstClockReturn clockret;
+
+  dtmfsrc = GST_DTMF_SRC (basesrc);
+
+  do {
+
+    if (dtmfsrc->last_event == NULL) {
+      GST_DEBUG_OBJECT (dtmfsrc, "popping");
+      event = g_async_queue_pop (dtmfsrc->event_queue);
+
+      GST_DEBUG_OBJECT (dtmfsrc, "popped %d", event->event_type);
+
+      switch (event->event_type) {
+        case DTMF_EVENT_TYPE_STOP:
+          GST_WARNING_OBJECT (dtmfsrc,
+              "Received a DTMF stop event when already stopped");
+          gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
+          break;
+        case DTMF_EVENT_TYPE_START:
+          gst_dtmf_prepare_timestamps (dtmfsrc);
+
+          event->packet_count = 0;
+          dtmfsrc->last_event = event;
+          event = NULL;
+          gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-processed",
+              dtmfsrc->last_event);
+          break;
+        case DTMF_EVENT_TYPE_PAUSE_TASK:
+          /*
+           * We're pushing it back because it has to stay in there until
+           * the task is really paused (and the queue will then be flushed)
+           */
+          GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task...");
+          GST_OBJECT_LOCK (dtmfsrc);
+          if (dtmfsrc->paused) {
+            g_async_queue_push (dtmfsrc->event_queue, event);
+            goto paused_locked;
+          }
+          GST_OBJECT_UNLOCK (dtmfsrc);
+          break;
+      }
+      if (event)
+        g_slice_free (GstDTMFSrcEvent, event);
+    } else if (dtmfsrc->last_event->packet_count * dtmfsrc->interval >=
+        MIN_DUTY_CYCLE) {
+      event = g_async_queue_try_pop (dtmfsrc->event_queue);
+
+      if (event != NULL) {
+
+        switch (event->event_type) {
+          case DTMF_EVENT_TYPE_START:
+            GST_WARNING_OBJECT (dtmfsrc,
+                "Received two consecutive DTMF start events");
+            gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
+            break;
+          case DTMF_EVENT_TYPE_STOP:
+            g_slice_free (GstDTMFSrcEvent, dtmfsrc->last_event);
+            dtmfsrc->last_event = NULL;
+            gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-processed", event);
+            break;
+          case DTMF_EVENT_TYPE_PAUSE_TASK:
+            /*
+             * We're pushing it back because it has to stay in there until
+             * the task is really paused (and the queue will then be flushed)
+             */
+            GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task...");
+
+            GST_OBJECT_LOCK (dtmfsrc);
+            if (dtmfsrc->paused) {
+              g_async_queue_push (dtmfsrc->event_queue, event);
+              goto paused_locked;
+            }
+            GST_OBJECT_UNLOCK (dtmfsrc);
+
+            break;
+        }
+        g_slice_free (GstDTMFSrcEvent, event);
+      }
+    }
+  } while (dtmfsrc->last_event == NULL);
+
+  GST_LOG_OBJECT (dtmfsrc, "end event check, now wait for the proper time");
+
+  clock = gst_element_get_clock (GST_ELEMENT (basesrc));
+
+  clockid = gst_clock_new_single_shot_id (clock, dtmfsrc->timestamp +
+      gst_element_get_base_time (GST_ELEMENT (dtmfsrc)));
+  gst_object_unref (clock);
+
+  GST_OBJECT_LOCK (dtmfsrc);
+  if (!dtmfsrc->paused) {
+    dtmfsrc->clockid = clockid;
+    GST_OBJECT_UNLOCK (dtmfsrc);
+
+    clockret = gst_clock_id_wait (clockid, NULL);
+
+    GST_OBJECT_LOCK (dtmfsrc);
+    if (dtmfsrc->paused)
+      clockret = GST_CLOCK_UNSCHEDULED;
+  } else {
+    clockret = GST_CLOCK_UNSCHEDULED;
+  }
+  gst_clock_id_unref (clockid);
+  dtmfsrc->clockid = NULL;
+  GST_OBJECT_UNLOCK (dtmfsrc);
+
+  if (clockret == GST_CLOCK_UNSCHEDULED) {
+    goto paused;
+  }
+
+  buf = gst_dtmf_src_create_next_tone_packet (dtmfsrc, dtmfsrc->last_event);
+
+  GST_LOG_OBJECT (dtmfsrc, "Created buffer of size %" G_GSIZE_FORMAT,
+      gst_buffer_get_size (buf));
+  *buffer = buf;
+
+  return GST_FLOW_OK;
+
+paused_locked:
+  GST_OBJECT_UNLOCK (dtmfsrc);
+
+paused:
+
+  if (dtmfsrc->last_event) {
+    GST_DEBUG_OBJECT (dtmfsrc, "Stopping current event");
+    /* Don't forget to release the stream lock */
+    g_slice_free (GstDTMFSrcEvent, dtmfsrc->last_event);
+    dtmfsrc->last_event = NULL;
+  }
+
+  return GST_FLOW_FLUSHING;
+
+}
+
+static gboolean
+gst_dtmf_src_unlock (GstBaseSrc * src)
+{
+  GstDTMFSrc *dtmfsrc = GST_DTMF_SRC (src);
+  GstDTMFSrcEvent *event = NULL;
+
+  GST_DEBUG_OBJECT (dtmfsrc, "Called unlock");
+
+  GST_OBJECT_LOCK (dtmfsrc);
+  dtmfsrc->paused = TRUE;
+  if (dtmfsrc->clockid) {
+    gst_clock_id_unschedule (dtmfsrc->clockid);
+  }
+  GST_OBJECT_UNLOCK (dtmfsrc);
+
+  GST_DEBUG_OBJECT (dtmfsrc, "Pushing the PAUSE_TASK event on unlock request");
+  event = g_slice_new0 (GstDTMFSrcEvent);
+  event->event_type = DTMF_EVENT_TYPE_PAUSE_TASK;
+  g_async_queue_push (dtmfsrc->event_queue, event);
+
+  return TRUE;
+}
+
+
+static gboolean
+gst_dtmf_src_unlock_stop (GstBaseSrc * src)
+{
+  GstDTMFSrc *dtmfsrc = GST_DTMF_SRC (src);
+
+  GST_DEBUG_OBJECT (dtmfsrc, "Unlock stopped");
+
+  GST_OBJECT_LOCK (dtmfsrc);
+  dtmfsrc->paused = FALSE;
+  GST_OBJECT_UNLOCK (dtmfsrc);
+
+  return TRUE;
+}
+
+
+static gboolean
+gst_dtmf_src_negotiate (GstBaseSrc * basesrc)
+{
+  GstDTMFSrc *dtmfsrc = GST_DTMF_SRC (basesrc);
+  GstCaps *caps;
+  GstStructure *s;
+  gboolean ret;
+
+  caps = gst_pad_get_allowed_caps (GST_BASE_SRC_PAD (basesrc));
+
+  if (!caps)
+    caps = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (basesrc));
+
+  if (gst_caps_is_empty (caps)) {
+    gst_caps_unref (caps);
+    return FALSE;
+  }
+
+  caps = gst_caps_truncate (caps);
+
+  caps = gst_caps_make_writable (caps);
+  s = gst_caps_get_structure (caps, 0);
+
+  gst_structure_fixate_field_nearest_int (s, "rate", DEFAULT_SAMPLE_RATE);
+
+  if (!gst_structure_get_int (s, "rate", &dtmfsrc->sample_rate)) {
+    GST_ERROR_OBJECT (dtmfsrc, "Could not get rate");
+    gst_caps_unref (caps);
+    return FALSE;
+  }
+
+  ret = gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps);
+
+  gst_caps_unref (caps);
+
+  return ret;
+}
+
+static gboolean
+gst_dtmf_src_query (GstBaseSrc * basesrc, GstQuery * query)
+{
+  GstDTMFSrc *dtmfsrc = GST_DTMF_SRC (basesrc);
+  gboolean res = FALSE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_LATENCY:
+    {
+      GstClockTime latency;
+
+      latency = dtmfsrc->interval * GST_MSECOND;
+      gst_query_set_latency (query, gst_base_src_is_live (basesrc), latency,
+          GST_CLOCK_TIME_NONE);
+      GST_DEBUG_OBJECT (dtmfsrc, "Reporting latency of %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (latency));
+      res = TRUE;
+    }
+      break;
+    default:
+      res = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
+      break;
+  }
+
+  return res;
+}
+
+static GstStateChangeReturn
+gst_dtmf_src_change_state (GstElement * element, GstStateChange transition)
+{
+  GstDTMFSrc *dtmfsrc;
+  GstStateChangeReturn result;
+  gboolean no_preroll = FALSE;
+  GstDTMFSrcEvent *event = NULL;
+
+  dtmfsrc = GST_DTMF_SRC (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      /* Flushing the event queue */
+      event = g_async_queue_try_pop (dtmfsrc->event_queue);
+
+      while (event != NULL) {
+        gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
+        g_slice_free (GstDTMFSrcEvent, event);
+        event = g_async_queue_try_pop (dtmfsrc->event_queue);
+      }
+      dtmfsrc->last_event_was_start = FALSE;
+      dtmfsrc->timestamp = 0;
+      no_preroll = TRUE;
+      break;
+    default:
+      break;
+  }
+
+  if ((result =
+          GST_ELEMENT_CLASS (gst_dtmf_src_parent_class)->change_state (element,
+              transition)) == GST_STATE_CHANGE_FAILURE)
+    goto failure;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      no_preroll = TRUE;
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      GST_DEBUG_OBJECT (dtmfsrc, "Flushing event queue");
+      /* Flushing the event queue */
+      event = g_async_queue_try_pop (dtmfsrc->event_queue);
+
+      while (event != NULL) {
+        gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
+        g_slice_free (GstDTMFSrcEvent, event);
+        event = g_async_queue_try_pop (dtmfsrc->event_queue);
+      }
+      dtmfsrc->last_event_was_start = FALSE;
+
+      break;
+    default:
+      break;
+  }
+
+  if (no_preroll && result == GST_STATE_CHANGE_SUCCESS)
+    result = GST_STATE_CHANGE_NO_PREROLL;
+
+  return result;
+
+  /* ERRORS */
+failure:
+  {
+    GST_ERROR_OBJECT (dtmfsrc, "parent failed state change");
+    return result;
+  }
+}
+
+gboolean
+gst_dtmf_src_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "dtmfsrc",
+      GST_RANK_NONE, GST_TYPE_DTMF_SRC);
+}
diff --git a/gst/dtmf/gstdtmfsrc.h b/gst/dtmf/gstdtmfsrc.h
new file mode 100644
index 0000000..04440bc
--- /dev/null
+++ b/gst/dtmf/gstdtmfsrc.h
@@ -0,0 +1,101 @@
+/* GStreamer DTMF source
+ *
+ * gstdtmfsrc.h:
+ *
+ * Copyright (C) <2007> Collabora.
+ *   Contact: Youness Alaoui <youness.alaoui@collabora.co.uk>
+ * Copyright (C) <2007> Nokia Corporation.
+ *   Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
+ * Copyright (C) <2005> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_DTMF_SRC_H__
+#define __GST_DTMF_SRC_H__
+
+#include <gst/gst.h>
+#include <gst/gstbuffer.h>
+#include <gst/base/gstbasesrc.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_DTMF_SRC               (gst_dtmf_src_get_type())
+#define GST_DTMF_SRC(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DTMF_SRC,GstDTMFSrc))
+#define GST_DTMF_SRC_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DTMF_SRC,GstDTMFSrcClass))
+#define GST_DTMF_SRC_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DTMF_SRC, GstDTMFSrcClass))
+#define GST_IS_DTMF_SRC(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DTMF_SRC))
+#define GST_IS_DTMF_SRC_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DTMF_SRC))
+#define GST_DTMF_SRC_CAST(obj)          ((GstDTMFSrc *)(obj))
+typedef struct _GstDTMFSrc GstDTMFSrc;
+typedef struct _GstDTMFSrcClass GstDTMFSrcClass;
+
+enum _GstDTMFEventType
+{
+  DTMF_EVENT_TYPE_START,
+  DTMF_EVENT_TYPE_STOP,
+  DTMF_EVENT_TYPE_PAUSE_TASK
+};
+
+typedef enum _GstDTMFEventType GstDTMFEventType;
+
+struct _GstDTMFSrcEvent
+{
+  GstDTMFEventType event_type;
+  double sample;
+  guint16 event_number;
+  guint16 volume;
+  guint32 packet_count;
+};
+
+typedef struct _GstDTMFSrcEvent GstDTMFSrcEvent;
+
+/**
+ * GstDTMFSrc:
+ * @element: the parent element.
+ *
+ * The opaque #GstDTMFSrc data structure.
+ */
+struct _GstDTMFSrc
+{
+  /*< private >*/
+  GstBaseSrc parent;
+  GAsyncQueue *event_queue;
+  GstDTMFSrcEvent *last_event;
+  gboolean last_event_was_start;
+
+  guint16 interval;
+  GstClockTime timestamp;
+
+  gboolean paused;
+  GstClockID clockid;
+
+  GstClockTime last_stop;
+
+  gint sample_rate;
+};
+
+
+struct _GstDTMFSrcClass
+{
+  GstBaseSrcClass parent_class;
+};
+
+GType gst_dtmf_src_get_type (void);
+
+gboolean gst_dtmf_src_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_DTMF_SRC_H__ */
diff --git a/gst/dtmf/gstrtpdtmfdepay.c b/gst/dtmf/gstrtpdtmfdepay.c
new file mode 100644
index 0000000..b7827be
--- /dev/null
+++ b/gst/dtmf/gstrtpdtmfdepay.c
@@ -0,0 +1,534 @@
+/* GstRtpDtmfDepay
+ *
+ * Copyright (C) 2008 Collabora Limited
+ * Copyright (C) 2008 Nokia Corporation
+ *   Contact: Youness Alaoui <youness.alaoui@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-rtpdtmfdepay
+ * @see_also: rtpdtmfsrc, rtpdtmfmux
+ *
+ * This element takes RTP DTMF packets and produces sound. It also emits a
+ * message on the #GstBus.
+ *
+ * The message is called "dtmf-event" and has the following fields
+ * <informaltable>
+ * <tgroup cols='4'>
+ * <colspec colname='Name' />
+ * <colspec colname='Type' />
+ * <colspec colname='Possible values' />
+ * <colspec colname='Purpose' />
+ * <thead>
+ * <row>
+ * <entry>Name</entry>
+ * <entry>GType</entry>
+ * <entry>Possible values</entry>
+ * <entry>Purpose</entry>
+ * </row>
+ * </thead>
+ * <tbody>
+ * <row>
+ * <entry>type</entry>
+ * <entry>G_TYPE_INT</entry>
+ * <entry>0-1</entry>
+ * <entry>Which of the two methods
+ * specified in RFC 2833 to use. The value should be 0 for tones and 1 for
+ * named events. Tones are specified by their frequencies and events are specied
+ * by their number. This element currently only recognizes events.
+ * Do not confuse with "method" which specified the output.
+ * </entry>
+ * </row>
+ * <row>
+ * <entry>number</entry>
+ * <entry>G_TYPE_INT</entry>
+ * <entry>0-16</entry>
+ * <entry>The event number.</entry>
+ * </row>
+ * <row>
+ * <entry>volume</entry>
+ * <entry>G_TYPE_INT</entry>
+ * <entry>0-36</entry>
+ * <entry>This field describes the power level of the tone, expressed in dBm0
+ * after dropping the sign. Power levels range from 0 to -63 dBm0. The range of
+ * valid DTMF is from 0 to -36 dBm0.
+ * </entry>
+ * </row>
+ * <row>
+ * <entry>method</entry>
+ * <entry>G_TYPE_INT</entry>
+ * <entry>1</entry>
+ * <entry>This field will always been 1 (ie RTP event) from this element.
+ * </entry>
+ * </row>
+ * </tbody>
+ * </tgroup>
+ * </informaltable>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstrtpdtmfdepay.h"
+
+#include <string.h>
+#include <math.h>
+
+#include <gst/audio/audio.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#define DEFAULT_PACKET_INTERVAL  50     /* ms */
+#define MIN_PACKET_INTERVAL      10     /* ms */
+#define MAX_PACKET_INTERVAL      50     /* ms */
+#define SAMPLE_RATE              8000
+#define SAMPLE_SIZE              16
+#define CHANNELS                 1
+#define MIN_DUTY_CYCLE           (MIN_INTER_DIGIT_INTERVAL + MIN_PULSE_DURATION)
+
+#define MIN_UNIT_TIME            0
+#define MAX_UNIT_TIME            1000
+#define DEFAULT_UNIT_TIME        0
+
+#define DEFAULT_MAX_DURATION     0
+
+typedef struct st_dtmf_key
+{
+  float low_frequency;
+  float high_frequency;
+} DTMF_KEY;
+
+static const DTMF_KEY DTMF_KEYS[] = {
+  {941, 1336},
+  {697, 1209},
+  {697, 1336},
+  {697, 1477},
+  {770, 1209},
+  {770, 1336},
+  {770, 1477},
+  {852, 1209},
+  {852, 1336},
+  {852, 1477},
+  {941, 1209},
+  {941, 1477},
+  {697, 1633},
+  {770, 1633},
+  {852, 1633},
+  {941, 1633},
+};
+
+#define MAX_DTMF_EVENTS 16
+
+enum
+{
+  DTMF_KEY_EVENT_1 = 1,
+  DTMF_KEY_EVENT_2 = 2,
+  DTMF_KEY_EVENT_3 = 3,
+  DTMF_KEY_EVENT_4 = 4,
+  DTMF_KEY_EVENT_5 = 5,
+  DTMF_KEY_EVENT_6 = 6,
+  DTMF_KEY_EVENT_7 = 7,
+  DTMF_KEY_EVENT_8 = 8,
+  DTMF_KEY_EVENT_9 = 9,
+  DTMF_KEY_EVENT_0 = 0,
+  DTMF_KEY_EVENT_STAR = 10,
+  DTMF_KEY_EVENT_POUND = 11,
+  DTMF_KEY_EVENT_A = 12,
+  DTMF_KEY_EVENT_B = 13,
+  DTMF_KEY_EVENT_C = 14,
+  DTMF_KEY_EVENT_D = 15,
+};
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_dtmf_depay_debug);
+#define GST_CAT_DEFAULT gst_rtp_dtmf_depay_debug
+
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_UNIT_TIME,
+  PROP_MAX_DURATION
+};
+
+static GstStaticPadTemplate gst_rtp_dtmf_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) \"" GST_AUDIO_NE (S16) "\", "
+        "rate = " GST_AUDIO_RATE_RANGE ", " "channels = (int) 1")
+    );
+
+static GstStaticPadTemplate gst_rtp_dtmf_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) [ 0, MAX ], "
+        "encoding-name = (string) \"TELEPHONE-EVENT\"")
+    );
+
+G_DEFINE_TYPE (GstRtpDTMFDepay, gst_rtp_dtmf_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_dtmf_depay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_dtmf_depay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static GstBuffer *gst_rtp_dtmf_depay_process (GstRTPBaseDepayload * depayload,
+    GstBuffer * buf);
+gboolean gst_rtp_dtmf_depay_setcaps (GstRTPBaseDepayload * filter,
+    GstCaps * caps);
+
+static void
+gst_rtp_dtmf_depay_class_init (GstRtpDTMFDepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gstelement_class = GST_ELEMENT_CLASS (klass);
+  gstrtpbasedepayload_class = GST_RTP_BASE_DEPAYLOAD_CLASS (klass);
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_dtmf_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_dtmf_depay_sink_template);
+
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_dtmf_depay_debug,
+      "rtpdtmfdepay", 0, "rtpdtmfdepay element");
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP DTMF packet depayloader", "Codec/Depayloader/Network",
+      "Generates DTMF Sound from telephone-event RTP packets",
+      "Youness Alaoui <youness.alaoui@collabora.co.uk>");
+
+  gobject_class->set_property =
+      GST_DEBUG_FUNCPTR (gst_rtp_dtmf_depay_set_property);
+  gobject_class->get_property =
+      GST_DEBUG_FUNCPTR (gst_rtp_dtmf_depay_get_property);
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_UNIT_TIME,
+      g_param_spec_uint ("unit-time", "Duration unittime",
+          "The smallest unit (ms) the duration must be a multiple of (0 disables it)",
+          MIN_UNIT_TIME, MAX_UNIT_TIME, DEFAULT_UNIT_TIME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_DURATION,
+      g_param_spec_uint ("max-duration", "Maximum duration",
+          "The maxumimum duration (ms) of the outgoing soundpacket. "
+          "(0 = no limit)", 0, G_MAXUINT, DEFAULT_MAX_DURATION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstrtpbasedepayload_class->process =
+      GST_DEBUG_FUNCPTR (gst_rtp_dtmf_depay_process);
+  gstrtpbasedepayload_class->set_caps =
+      GST_DEBUG_FUNCPTR (gst_rtp_dtmf_depay_setcaps);
+
+}
+
+static void
+gst_rtp_dtmf_depay_init (GstRtpDTMFDepay * rtpdtmfdepay)
+{
+  rtpdtmfdepay->unit_time = DEFAULT_UNIT_TIME;
+}
+
+static void
+gst_rtp_dtmf_depay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpDTMFDepay *rtpdtmfdepay;
+
+  rtpdtmfdepay = GST_RTP_DTMF_DEPAY (object);
+
+  switch (prop_id) {
+    case PROP_UNIT_TIME:
+      rtpdtmfdepay->unit_time = g_value_get_uint (value);
+      break;
+    case PROP_MAX_DURATION:
+      rtpdtmfdepay->max_duration = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_dtmf_depay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpDTMFDepay *rtpdtmfdepay;
+
+  rtpdtmfdepay = GST_RTP_DTMF_DEPAY (object);
+
+  switch (prop_id) {
+    case PROP_UNIT_TIME:
+      g_value_set_uint (value, rtpdtmfdepay->unit_time);
+      break;
+    case PROP_MAX_DURATION:
+      g_value_set_uint (value, rtpdtmfdepay->max_duration);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+gboolean
+gst_rtp_dtmf_depay_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps)
+{
+  GstCaps *filtercaps, *srccaps;
+  GstStructure *structure = gst_caps_get_structure (caps, 0);
+  gint clock_rate = 8000;       /* default */
+
+  gst_structure_get_int (structure, "clock-rate", &clock_rate);
+  filter->clock_rate = clock_rate;
+
+  filtercaps =
+      gst_pad_get_pad_template_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (filter));
+
+  filtercaps = gst_caps_make_writable (filtercaps);
+  gst_caps_set_simple (filtercaps, "rate", G_TYPE_INT, clock_rate, NULL);
+
+  srccaps = gst_pad_peer_query_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (filter),
+      filtercaps);
+  gst_caps_unref (filtercaps);
+
+  gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (filter), srccaps);
+  gst_caps_unref (srccaps);
+
+  return TRUE;
+}
+
+static GstBuffer *
+gst_dtmf_src_generate_tone (GstRtpDTMFDepay * rtpdtmfdepay,
+    GstRTPDTMFPayload payload)
+{
+  GstBuffer *buf;
+  GstMapInfo map;
+  gint16 *p;
+  gint tone_size;
+  double i = 0;
+  double amplitude, f1, f2;
+  double volume_factor;
+  DTMF_KEY key = DTMF_KEYS[payload.event];
+  guint32 clock_rate;
+  GstRTPBaseDepayload *depayload = GST_RTP_BASE_DEPAYLOAD (rtpdtmfdepay);
+  gint volume;
+  static GstAllocationParams params = { 0, 1, 0, 0, };
+
+  clock_rate = depayload->clock_rate;
+
+  /* Create a buffer for the tone */
+  tone_size = (payload.duration * SAMPLE_SIZE * CHANNELS) / 8;
+  buf = gst_buffer_new_allocate (NULL, tone_size, &params);
+  GST_BUFFER_DURATION (buf) = payload.duration * GST_SECOND / clock_rate;
+  volume = payload.volume;
+
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  p = (gint16 *) map.data;
+
+  volume_factor = pow (10, (-volume) / 20);
+
+  /*
+   * For each sample point we calculate 'x' as the
+   * the amplitude value.
+   */
+  for (i = 0; i < (tone_size / (SAMPLE_SIZE / 8)); i++) {
+    /*
+     * We add the fundamental frequencies together.
+     */
+    f1 = sin (2 * M_PI * key.low_frequency * (rtpdtmfdepay->sample /
+            clock_rate));
+    f2 = sin (2 * M_PI * key.high_frequency * (rtpdtmfdepay->sample /
+            clock_rate));
+
+    amplitude = (f1 + f2) / 2;
+
+    /* Adjust the volume */
+    amplitude *= volume_factor;
+
+    /* Make the [-1:1] interval into a [-32767:32767] interval */
+    amplitude *= 32767;
+
+    /* Store it in the data buffer */
+    *(p++) = (gint16) amplitude;
+
+    (rtpdtmfdepay->sample)++;
+  }
+
+  gst_buffer_unmap (buf, &map);
+
+  return buf;
+}
+
+
+static GstBuffer *
+gst_rtp_dtmf_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+
+  GstRtpDTMFDepay *rtpdtmfdepay = NULL;
+  GstBuffer *outbuf = NULL;
+  gint payload_len;
+  guint8 *payload = NULL;
+  guint32 timestamp;
+  GstRTPDTMFPayload dtmf_payload;
+  gboolean marker;
+  GstStructure *structure = NULL;
+  GstMessage *dtmf_message = NULL;
+  GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
+
+  rtpdtmfdepay = GST_RTP_DTMF_DEPAY (depayload);
+
+  gst_rtp_buffer_map (buf, GST_MAP_READ, &rtpbuffer);
+
+  payload_len = gst_rtp_buffer_get_payload_len (&rtpbuffer);
+  payload = gst_rtp_buffer_get_payload (&rtpbuffer);
+
+  if (payload_len != sizeof (GstRTPDTMFPayload))
+    goto bad_packet;
+
+  memcpy (&dtmf_payload, payload, sizeof (GstRTPDTMFPayload));
+
+  if (dtmf_payload.event > MAX_EVENT)
+    goto bad_packet;
+
+  marker = gst_rtp_buffer_get_marker (&rtpbuffer);
+
+  timestamp = gst_rtp_buffer_get_timestamp (&rtpbuffer);
+
+  dtmf_payload.duration = g_ntohs (dtmf_payload.duration);
+
+  /* clip to whole units of unit_time */
+  if (rtpdtmfdepay->unit_time) {
+    guint unit_time_clock =
+        (rtpdtmfdepay->unit_time * depayload->clock_rate) / 1000;
+    if (dtmf_payload.duration % unit_time_clock) {
+      /* Make sure we don't overflow the duration */
+      if (dtmf_payload.duration < G_MAXUINT16 - unit_time_clock)
+        dtmf_payload.duration += unit_time_clock -
+            (dtmf_payload.duration % unit_time_clock);
+      else
+        dtmf_payload.duration -= dtmf_payload.duration % unit_time_clock;
+    }
+  }
+
+  /* clip to max duration */
+  if (rtpdtmfdepay->max_duration) {
+    guint max_duration_clock =
+        (rtpdtmfdepay->max_duration * depayload->clock_rate) / 1000;
+
+    if (max_duration_clock < G_MAXUINT16 &&
+        dtmf_payload.duration > max_duration_clock)
+      dtmf_payload.duration = max_duration_clock;
+  }
+
+  GST_DEBUG_OBJECT (depayload, "Received new RTP DTMF packet : "
+      "marker=%d - timestamp=%u - event=%d - duration=%d",
+      marker, timestamp, dtmf_payload.event, dtmf_payload.duration);
+
+  GST_DEBUG_OBJECT (depayload,
+      "Previous information : timestamp=%u - duration=%d",
+      rtpdtmfdepay->previous_ts, rtpdtmfdepay->previous_duration);
+
+  /* First packet */
+  if (marker || rtpdtmfdepay->previous_ts != timestamp) {
+    rtpdtmfdepay->sample = 0;
+    rtpdtmfdepay->previous_ts = timestamp;
+    rtpdtmfdepay->previous_duration = dtmf_payload.duration;
+    rtpdtmfdepay->first_gst_ts = GST_BUFFER_PTS (buf);
+
+    structure = gst_structure_new ("dtmf-event",
+        "number", G_TYPE_INT, dtmf_payload.event,
+        "volume", G_TYPE_INT, dtmf_payload.volume,
+        "type", G_TYPE_INT, 1, "method", G_TYPE_INT, 1, NULL);
+    if (structure) {
+      dtmf_message =
+          gst_message_new_element (GST_OBJECT (depayload), structure);
+      if (dtmf_message) {
+        if (!gst_element_post_message (GST_ELEMENT (depayload), dtmf_message)) {
+          GST_ERROR_OBJECT (depayload,
+              "Unable to send dtmf-event message to bus");
+        }
+      } else {
+        GST_ERROR_OBJECT (depayload, "Unable to create dtmf-event message");
+      }
+    } else {
+      GST_ERROR_OBJECT (depayload, "Unable to create dtmf-event structure");
+    }
+  } else {
+    guint16 duration = dtmf_payload.duration;
+    dtmf_payload.duration -= rtpdtmfdepay->previous_duration;
+    /* If late buffer, ignore */
+    if (duration > rtpdtmfdepay->previous_duration)
+      rtpdtmfdepay->previous_duration = duration;
+  }
+
+  GST_DEBUG_OBJECT (depayload, "new previous duration : %d - new duration : %d"
+      " - diff  : %d - clock rate : %d - timestamp : %" G_GUINT64_FORMAT,
+      rtpdtmfdepay->previous_duration, dtmf_payload.duration,
+      (rtpdtmfdepay->previous_duration - dtmf_payload.duration),
+      depayload->clock_rate, GST_BUFFER_TIMESTAMP (buf));
+
+  /* If late or duplicate packet (like the redundant end packet). Ignore */
+  if (dtmf_payload.duration > 0) {
+    outbuf = gst_dtmf_src_generate_tone (rtpdtmfdepay, dtmf_payload);
+
+
+    GST_BUFFER_PTS (outbuf) = rtpdtmfdepay->first_gst_ts +
+        (rtpdtmfdepay->previous_duration - dtmf_payload.duration) *
+        GST_SECOND / depayload->clock_rate;
+    GST_BUFFER_OFFSET (outbuf) =
+        (rtpdtmfdepay->previous_duration - dtmf_payload.duration) *
+        GST_SECOND / depayload->clock_rate;
+    GST_BUFFER_OFFSET_END (outbuf) = rtpdtmfdepay->previous_duration *
+        GST_SECOND / depayload->clock_rate;
+
+    GST_DEBUG_OBJECT (depayload,
+        "timestamp : %" G_GUINT64_FORMAT " - time %" GST_TIME_FORMAT,
+        GST_BUFFER_TIMESTAMP (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+
+  }
+
+  gst_rtp_buffer_unmap (&rtpbuffer);
+
+  return outbuf;
+
+bad_packet:
+  GST_ELEMENT_WARNING (rtpdtmfdepay, STREAM, DECODE,
+      ("Packet did not validate"), (NULL));
+
+  if (rtpbuffer.buffer != NULL)
+    gst_rtp_buffer_unmap (&rtpbuffer);
+
+  return NULL;
+}
+
+gboolean
+gst_rtp_dtmf_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpdtmfdepay",
+      GST_RANK_MARGINAL, GST_TYPE_RTP_DTMF_DEPAY);
+}
diff --git a/gst/dtmf/gstrtpdtmfdepay.h b/gst/dtmf/gstrtpdtmfdepay.h
new file mode 100644
index 0000000..c5ed189
--- /dev/null
+++ b/gst/dtmf/gstrtpdtmfdepay.h
@@ -0,0 +1,68 @@
+/* GstRtpDtmfDepay
+ *
+ * Copyright (C) 2008 Collabora Limited
+ * Copyright (C) 2008 Nokia Corporation
+ *   Contact: Youness Alaoui <youness.alaoui@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_DTMF_DEPAY_H__
+#define __GST_RTP_DTMF_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+#include "gstdtmfcommon.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_DTMF_DEPAY \
+  (gst_rtp_dtmf_depay_get_type())
+#define GST_RTP_DTMF_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_DTMF_DEPAY,GstRtpDTMFDepay))
+#define GST_RTP_DTMF_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_DTMF_DEPAY,GstRtpDTMFDepayClass))
+#define GST_IS_RTP_DTMF_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_DTMF_DEPAY))
+#define GST_IS_RTP_DTMF_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_DTMF_DEPAY))
+typedef struct _GstRtpDTMFDepay GstRtpDTMFDepay;
+typedef struct _GstRtpDTMFDepayClass GstRtpDTMFDepayClass;
+
+struct _GstRtpDTMFDepay
+{
+  /*< private >*/
+  GstRTPBaseDepayload depayload;
+  double sample;
+  guint32 previous_ts;
+  guint16 previous_duration;
+  GstClockTime first_gst_ts;
+  guint unit_time;
+  guint max_duration;
+};
+
+struct _GstRtpDTMFDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_dtmf_depay_get_type (void);
+
+gboolean gst_rtp_dtmf_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_DTMF_DEPAY_H__ */
diff --git a/gst/dtmf/gstrtpdtmfsrc.c b/gst/dtmf/gstrtpdtmfsrc.c
new file mode 100644
index 0000000..9c783d3
--- /dev/null
+++ b/gst/dtmf/gstrtpdtmfsrc.c
@@ -0,0 +1,1187 @@
+/* GStreamer RTP DTMF source
+ *
+ * gstrtpdtmfsrc.c:
+ *
+ * Copyright (C) <2007> Nokia Corporation.
+ *   Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2000,2005 Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpdtmfsrc
+ * @see_also: dtmfsrc, rtpdtmfdepay, rtpdtmfmux
+ *
+ * The RTPDTMFSrc element generates RTP DTMF (RFC 2833) event packets on request
+ * from application. The application communicates the beginning and end of a
+ * DTMF event using custom upstream gstreamer events. To report a DTMF event, an
+ * application must send an event of type GST_EVENT_CUSTOM_UPSTREAM, having a
+ * structure of name "dtmf-event" with fields set according to the following
+ * table:
+ *
+ * <informaltable>
+ * <tgroup cols='4'>
+ * <colspec colname='Name' />
+ * <colspec colname='Type' />
+ * <colspec colname='Possible values' />
+ * <colspec colname='Purpose' />
+ * <thead>
+ * <row>
+ * <entry>Name</entry>
+ * <entry>GType</entry>
+ * <entry>Possible values</entry>
+ * <entry>Purpose</entry>
+ * </row>
+ * </thead>
+ * <tbody>
+ * <row>
+ * <entry>type</entry>
+ * <entry>G_TYPE_INT</entry>
+ * <entry>0-1</entry>
+ * <entry>The application uses this field to specify which of the two methods
+ * specified in RFC 2833 to use. The value should be 0 for tones and 1 for
+ * named events. Tones are specified by their frequencies and events are specied
+ * by their number. This element can only take events as input. Do not confuse
+ * with "method" which specified the output.
+ * </entry>
+ * </row>
+ * <row>
+ * <entry>number</entry>
+ * <entry>G_TYPE_INT</entry>
+ * <entry>0-15</entry>
+ * <entry>The event number.</entry>
+ * </row>
+ * <row>
+ * <entry>volume</entry>
+ * <entry>G_TYPE_INT</entry>
+ * <entry>0-36</entry>
+ * <entry>This field describes the power level of the tone, expressed in dBm0
+ * after dropping the sign. Power levels range from 0 to -63 dBm0. The range of
+ * valid DTMF is from 0 to -36 dBm0. Can be omitted if start is set to FALSE.
+ * </entry>
+ * </row>
+ * <row>
+ * <entry>start</entry>
+ * <entry>G_TYPE_BOOLEAN</entry>
+ * <entry>True or False</entry>
+ * <entry>Whether the event is starting or ending.</entry>
+ * </row>
+ * <row>
+ * <entry>method</entry>
+ * <entry>G_TYPE_INT</entry>
+ * <entry>1</entry>
+ * <entry>The method used for sending event, this element will react if this
+ * field is absent or 1.
+ * </entry>
+ * </row>
+ * </tbody>
+ * </tgroup>
+ * </informaltable>
+ *
+ * For example, the following code informs the pipeline (and in turn, the
+ * RTPDTMFSrc element inside the pipeline) about the start of an RTP DTMF named
+ * event '1' of volume -25 dBm0:
+ *
+ * <programlisting>
+ * structure = gst_structure_new ("dtmf-event",
+ *                    "type", G_TYPE_INT, 1,
+ *                    "number", G_TYPE_INT, 1,
+ *                    "volume", G_TYPE_INT, 25,
+ *                    "start", G_TYPE_BOOLEAN, TRUE, NULL);
+ *
+ * event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, structure);
+ * gst_element_send_event (pipeline, event);
+ * </programlisting>
+ *
+ * When a DTMF tone actually starts or stop, a "dtmf-event-processed"
+ * element #GstMessage with the same fields as the "dtmf-event"
+ * #GstEvent that was used to request the event. Also, if any event
+ * has not been processed when the element goes from the PAUSED to the
+ * READY state, then a "dtmf-event-dropped" message is posted on the
+ * #GstBus in the order that they were received.
+  */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "gstrtpdtmfsrc.h"
+
+#define GST_RTP_DTMF_TYPE_EVENT  1
+#define DEFAULT_PTIME            40     /* ms */
+#define DEFAULT_SSRC             -1
+#define DEFAULT_PT               96
+#define DEFAULT_TIMESTAMP_OFFSET -1
+#define DEFAULT_SEQNUM_OFFSET    -1
+#define DEFAULT_CLOCK_RATE       8000
+
+#define DEFAULT_PACKET_REDUNDANCY 1
+#define MIN_PACKET_REDUNDANCY 1
+#define MAX_PACKET_REDUNDANCY 5
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_dtmf_src_debug);
+#define GST_CAT_DEFAULT gst_rtp_dtmf_src_debug
+
+/* signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_SSRC,
+  PROP_TIMESTAMP_OFFSET,
+  PROP_SEQNUM_OFFSET,
+  PROP_PT,
+  PROP_CLOCK_RATE,
+  PROP_TIMESTAMP,
+  PROP_SEQNUM,
+  PROP_REDUNDANCY
+};
+
+static GstStaticPadTemplate gst_rtp_dtmf_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) [ 96, 127 ], "
+        "clock-rate = (int) [ 0, MAX ], "
+        "encoding-name = (string) \"TELEPHONE-EVENT\"")
+    /*  "events = (string) \"0-15\" */
+    );
+
+
+G_DEFINE_TYPE (GstRTPDTMFSrc, gst_rtp_dtmf_src, GST_TYPE_BASE_SRC);
+
+static void gst_rtp_dtmf_src_finalize (GObject * object);
+
+static void gst_rtp_dtmf_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_dtmf_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static gboolean gst_rtp_dtmf_src_handle_event (GstBaseSrc * basesrc,
+    GstEvent * event);
+static GstStateChangeReturn gst_rtp_dtmf_src_change_state (GstElement * element,
+    GstStateChange transition);
+static void gst_rtp_dtmf_src_add_start_event (GstRTPDTMFSrc * dtmfsrc,
+    gint event_number, gint event_volume);
+static void gst_rtp_dtmf_src_add_stop_event (GstRTPDTMFSrc * dtmfsrc);
+
+static gboolean gst_rtp_dtmf_src_unlock (GstBaseSrc * src);
+static gboolean gst_rtp_dtmf_src_unlock_stop (GstBaseSrc * src);
+static GstFlowReturn gst_rtp_dtmf_src_create (GstBaseSrc * basesrc,
+    guint64 offset, guint length, GstBuffer ** buffer);
+static gboolean gst_rtp_dtmf_src_negotiate (GstBaseSrc * basesrc);
+static gboolean gst_rtp_dtmf_src_query (GstBaseSrc * basesrc, GstQuery * query);
+
+
+static void
+gst_rtp_dtmf_src_class_init (GstRTPDTMFSrcClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstBaseSrcClass *gstbasesrc_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
+  gstelement_class = GST_ELEMENT_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_dtmf_src_debug,
+      "rtpdtmfsrc", 0, "rtpdtmfsrc element");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_dtmf_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP DTMF packet generator", "Source/Network",
+      "Generates RTP DTMF packets", "Zeeshan Ali <zeeshan.ali@nokia.com>");
+
+  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_finalize);
+  gobject_class->set_property =
+      GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_set_property);
+  gobject_class->get_property =
+      GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_get_property);
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP,
+      g_param_spec_uint ("timestamp", "Timestamp",
+          "The RTP timestamp of the last processed packet",
+          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM,
+      g_param_spec_uint ("seqnum", "Sequence number",
+          "The RTP sequence number of the last processed packet",
+          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_TIMESTAMP_OFFSET, g_param_spec_int ("timestamp-offset",
+          "Timestamp Offset",
+          "Offset to add to all outgoing timestamps (-1 = random)", -1,
+          G_MAXINT, DEFAULT_TIMESTAMP_OFFSET,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET,
+      g_param_spec_int ("seqnum-offset", "Sequence number Offset",
+          "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXINT,
+          DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CLOCK_RATE,
+      g_param_spec_uint ("clock-rate", "clockrate",
+          "The clock-rate at which to generate the dtmf packets",
+          0, G_MAXUINT, DEFAULT_CLOCK_RATE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
+      g_param_spec_uint ("ssrc", "SSRC",
+          "The SSRC of the packets (-1 == random)",
+          0, G_MAXUINT, DEFAULT_SSRC,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
+      g_param_spec_uint ("pt", "payload type",
+          "The payload type of the packets",
+          0, 0x80, DEFAULT_PT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_REDUNDANCY,
+      g_param_spec_uint ("packet-redundancy", "Packet Redundancy",
+          "Number of packets to send to indicate start and stop dtmf events",
+          MIN_PACKET_REDUNDANCY, MAX_PACKET_REDUNDANCY,
+          DEFAULT_PACKET_REDUNDANCY,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_change_state);
+
+  gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_unlock);
+  gstbasesrc_class->unlock_stop =
+      GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_unlock_stop);
+
+  gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_handle_event);
+  gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_create);
+  gstbasesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_negotiate);
+  gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_query);
+}
+
+static void
+gst_rtp_dtmf_src_event_free (GstRTPDTMFSrcEvent * event)
+{
+  if (event) {
+    if (event->payload)
+      g_slice_free (GstRTPDTMFPayload, event->payload);
+    g_slice_free (GstRTPDTMFSrcEvent, event);
+  }
+}
+
+static void
+gst_rtp_dtmf_src_init (GstRTPDTMFSrc * object)
+{
+  gst_base_src_set_format (GST_BASE_SRC (object), GST_FORMAT_TIME);
+  gst_base_src_set_live (GST_BASE_SRC (object), TRUE);
+
+  object->ssrc = DEFAULT_SSRC;
+  object->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
+  object->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
+  object->pt = DEFAULT_PT;
+  object->clock_rate = DEFAULT_CLOCK_RATE;
+  object->ptime = DEFAULT_PTIME;
+  object->packet_redundancy = DEFAULT_PACKET_REDUNDANCY;
+
+  object->event_queue =
+      g_async_queue_new_full ((GDestroyNotify) gst_rtp_dtmf_src_event_free);
+  object->payload = NULL;
+
+  GST_DEBUG_OBJECT (object, "init done");
+}
+
+static void
+gst_rtp_dtmf_src_finalize (GObject * object)
+{
+  GstRTPDTMFSrc *dtmfsrc;
+
+  dtmfsrc = GST_RTP_DTMF_SRC (object);
+
+  if (dtmfsrc->event_queue) {
+    g_async_queue_unref (dtmfsrc->event_queue);
+    dtmfsrc->event_queue = NULL;
+  }
+
+
+  G_OBJECT_CLASS (gst_rtp_dtmf_src_parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_dtmf_src_handle_dtmf_event (GstRTPDTMFSrc * dtmfsrc,
+    const GstStructure * event_structure)
+{
+  gint event_type;
+  gboolean start;
+  gint method;
+  GstClockTime last_stop;
+  gint event_number;
+  gint event_volume;
+  gboolean correct_order;
+
+  if (!gst_structure_get_int (event_structure, "type", &event_type) ||
+      !gst_structure_get_boolean (event_structure, "start", &start) ||
+      event_type != GST_RTP_DTMF_TYPE_EVENT)
+    goto failure;
+
+  if (gst_structure_get_int (event_structure, "method", &method)) {
+    if (method != 1) {
+      goto failure;
+    }
+  }
+
+  if (start)
+    if (!gst_structure_get_int (event_structure, "number", &event_number) ||
+        !gst_structure_get_int (event_structure, "volume", &event_volume))
+      goto failure;
+
+  GST_OBJECT_LOCK (dtmfsrc);
+  if (gst_structure_get_clock_time (event_structure, "last-stop", &last_stop))
+    dtmfsrc->last_stop = last_stop;
+  else
+    dtmfsrc->last_stop = GST_CLOCK_TIME_NONE;
+  correct_order = (start != dtmfsrc->last_event_was_start);
+  dtmfsrc->last_event_was_start = start;
+  GST_OBJECT_UNLOCK (dtmfsrc);
+
+  if (!correct_order)
+    goto failure;
+
+  if (start) {
+    if (!gst_structure_get_int (event_structure, "number", &event_number) ||
+        !gst_structure_get_int (event_structure, "volume", &event_volume))
+      goto failure;
+
+    GST_DEBUG_OBJECT (dtmfsrc, "Received start event %d with volume %d",
+        event_number, event_volume);
+    gst_rtp_dtmf_src_add_start_event (dtmfsrc, event_number, event_volume);
+  }
+
+  else {
+    GST_DEBUG_OBJECT (dtmfsrc, "Received stop event");
+    gst_rtp_dtmf_src_add_stop_event (dtmfsrc);
+  }
+
+  return TRUE;
+failure:
+  return FALSE;
+}
+
+static gboolean
+gst_rtp_dtmf_src_handle_custom_upstream (GstRTPDTMFSrc * dtmfsrc,
+    GstEvent * event)
+{
+  gboolean result = FALSE;
+  gchar *struct_str;
+  const GstStructure *structure;
+
+  GstState state;
+  GstStateChangeReturn ret;
+
+  ret = gst_element_get_state (GST_ELEMENT (dtmfsrc), &state, NULL, 0);
+  if (ret != GST_STATE_CHANGE_SUCCESS || state != GST_STATE_PLAYING) {
+    GST_DEBUG_OBJECT (dtmfsrc, "Received event while not in PLAYING state");
+    goto ret;
+  }
+
+  GST_DEBUG_OBJECT (dtmfsrc, "Received event is of our interest");
+  structure = gst_event_get_structure (event);
+  struct_str = gst_structure_to_string (structure);
+  GST_DEBUG_OBJECT (dtmfsrc, "Event has structure %s", struct_str);
+  g_free (struct_str);
+  if (structure && gst_structure_has_name (structure, "dtmf-event"))
+    result = gst_rtp_dtmf_src_handle_dtmf_event (dtmfsrc, structure);
+
+ret:
+  return result;
+}
+
+static gboolean
+gst_rtp_dtmf_src_handle_event (GstBaseSrc * basesrc, GstEvent * event)
+{
+  GstRTPDTMFSrc *dtmfsrc;
+  gboolean result = FALSE;
+
+  dtmfsrc = GST_RTP_DTMF_SRC (basesrc);
+
+  GST_DEBUG_OBJECT (dtmfsrc, "Received an event on the src pad");
+  if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM) {
+    result = gst_rtp_dtmf_src_handle_custom_upstream (dtmfsrc, event);
+  }
+
+  return result;
+}
+
+static void
+gst_rtp_dtmf_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRTPDTMFSrc *dtmfsrc;
+
+  dtmfsrc = GST_RTP_DTMF_SRC (object);
+
+  switch (prop_id) {
+    case PROP_TIMESTAMP_OFFSET:
+      dtmfsrc->ts_offset = g_value_get_int (value);
+      break;
+    case PROP_SEQNUM_OFFSET:
+      dtmfsrc->seqnum_offset = g_value_get_int (value);
+      break;
+    case PROP_CLOCK_RATE:
+      dtmfsrc->clock_rate = g_value_get_uint (value);
+      dtmfsrc->dirty = TRUE;
+      break;
+    case PROP_SSRC:
+      dtmfsrc->ssrc = g_value_get_uint (value);
+      break;
+    case PROP_PT:
+      dtmfsrc->pt = g_value_get_uint (value);
+      dtmfsrc->dirty = TRUE;
+      break;
+    case PROP_REDUNDANCY:
+      dtmfsrc->packet_redundancy = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_dtmf_src_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstRTPDTMFSrc *dtmfsrc;
+
+  dtmfsrc = GST_RTP_DTMF_SRC (object);
+
+  switch (prop_id) {
+    case PROP_TIMESTAMP_OFFSET:
+      g_value_set_int (value, dtmfsrc->ts_offset);
+      break;
+    case PROP_SEQNUM_OFFSET:
+      g_value_set_int (value, dtmfsrc->seqnum_offset);
+      break;
+    case PROP_CLOCK_RATE:
+      g_value_set_uint (value, dtmfsrc->clock_rate);
+      break;
+    case PROP_SSRC:
+      g_value_set_uint (value, dtmfsrc->ssrc);
+      break;
+    case PROP_PT:
+      g_value_set_uint (value, dtmfsrc->pt);
+      break;
+    case PROP_TIMESTAMP:
+      g_value_set_uint (value, dtmfsrc->rtp_timestamp);
+      break;
+    case PROP_SEQNUM:
+      g_value_set_uint (value, dtmfsrc->seqnum);
+      break;
+    case PROP_REDUNDANCY:
+      g_value_set_uint (value, dtmfsrc->packet_redundancy);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_rtp_dtmf_prepare_timestamps (GstRTPDTMFSrc * dtmfsrc)
+{
+  GstClockTime last_stop;
+
+  GST_OBJECT_LOCK (dtmfsrc);
+  last_stop = dtmfsrc->last_stop;
+  GST_OBJECT_UNLOCK (dtmfsrc);
+
+  if (GST_CLOCK_TIME_IS_VALID (last_stop)) {
+    dtmfsrc->start_timestamp = last_stop;
+  } else {
+    GstClock *clock = gst_element_get_clock (GST_ELEMENT (dtmfsrc));
+
+    if (clock == NULL)
+      return FALSE;
+
+    dtmfsrc->start_timestamp = gst_clock_get_time (clock)
+        - gst_element_get_base_time (GST_ELEMENT (dtmfsrc));
+    gst_object_unref (clock);
+  }
+
+  /* If the last stop was in the past, then lets add the buffers together */
+  if (dtmfsrc->start_timestamp < dtmfsrc->timestamp)
+    dtmfsrc->start_timestamp = dtmfsrc->timestamp;
+
+  dtmfsrc->timestamp = dtmfsrc->start_timestamp;
+
+  dtmfsrc->rtp_timestamp = dtmfsrc->ts_base +
+      gst_util_uint64_scale_int (gst_segment_to_running_time (&GST_BASE_SRC
+          (dtmfsrc)->segment, GST_FORMAT_TIME, dtmfsrc->timestamp),
+      dtmfsrc->clock_rate, GST_SECOND);
+
+  return TRUE;
+}
+
+
+static void
+gst_rtp_dtmf_src_add_start_event (GstRTPDTMFSrc * dtmfsrc, gint event_number,
+    gint event_volume)
+{
+
+  GstRTPDTMFSrcEvent *event = g_slice_new0 (GstRTPDTMFSrcEvent);
+  event->event_type = RTP_DTMF_EVENT_TYPE_START;
+
+  event->payload = g_slice_new0 (GstRTPDTMFPayload);
+  event->payload->event = CLAMP (event_number, MIN_EVENT, MAX_EVENT);
+  event->payload->volume = CLAMP (event_volume, MIN_VOLUME, MAX_VOLUME);
+
+  g_async_queue_push (dtmfsrc->event_queue, event);
+}
+
+static void
+gst_rtp_dtmf_src_add_stop_event (GstRTPDTMFSrc * dtmfsrc)
+{
+
+  GstRTPDTMFSrcEvent *event = g_slice_new0 (GstRTPDTMFSrcEvent);
+  event->event_type = RTP_DTMF_EVENT_TYPE_STOP;
+
+  g_async_queue_push (dtmfsrc->event_queue, event);
+}
+
+
+static void
+gst_rtp_dtmf_prepare_rtp_headers (GstRTPDTMFSrc * dtmfsrc,
+    GstRTPBuffer * rtpbuf)
+{
+  gst_rtp_buffer_set_ssrc (rtpbuf, dtmfsrc->current_ssrc);
+  gst_rtp_buffer_set_payload_type (rtpbuf, dtmfsrc->pt);
+  /* Only the very first packet gets a marker */
+  if (dtmfsrc->first_packet) {
+    gst_rtp_buffer_set_marker (rtpbuf, TRUE);
+  } else if (dtmfsrc->last_packet) {
+    dtmfsrc->payload->e = 1;
+  }
+
+  dtmfsrc->seqnum++;
+  gst_rtp_buffer_set_seq (rtpbuf, dtmfsrc->seqnum);
+
+  /* timestamp of RTP header */
+  gst_rtp_buffer_set_timestamp (rtpbuf, dtmfsrc->rtp_timestamp);
+}
+
+static GstBuffer *
+gst_rtp_dtmf_src_create_next_rtp_packet (GstRTPDTMFSrc * dtmfsrc)
+{
+  GstBuffer *buf;
+  GstRTPDTMFPayload *payload;
+  GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
+
+  buf = gst_rtp_buffer_new_allocate (sizeof (GstRTPDTMFPayload), 0, 0);
+
+  gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtpbuffer);
+
+  gst_rtp_dtmf_prepare_rtp_headers (dtmfsrc, &rtpbuffer);
+
+  /* timestamp and duration of GstBuffer */
+  /* Redundant buffer have no duration ... */
+  if (dtmfsrc->redundancy_count > 1)
+    GST_BUFFER_DURATION (buf) = 0;
+  else
+    GST_BUFFER_DURATION (buf) = dtmfsrc->ptime * GST_MSECOND;
+  GST_BUFFER_PTS (buf) = dtmfsrc->timestamp;
+
+  payload = (GstRTPDTMFPayload *) gst_rtp_buffer_get_payload (&rtpbuffer);
+
+  /* copy payload and convert to network-byte order */
+  memmove (payload, dtmfsrc->payload, sizeof (GstRTPDTMFPayload));
+
+  payload->duration = g_htons (payload->duration);
+
+  if (dtmfsrc->redundancy_count <= 1 && dtmfsrc->last_packet) {
+    GstClockTime inter_digit_interval = MIN_INTER_DIGIT_INTERVAL;
+
+    if (inter_digit_interval % dtmfsrc->ptime != 0)
+      inter_digit_interval += dtmfsrc->ptime -
+          (MIN_INTER_DIGIT_INTERVAL % dtmfsrc->ptime);
+
+    GST_BUFFER_DURATION (buf) += inter_digit_interval * GST_MSECOND;
+  }
+
+  GST_LOG_OBJECT (dtmfsrc, "Creating new buffer with event %u duration "
+      " gst: %" GST_TIME_FORMAT " at %" GST_TIME_FORMAT "(rtp ts:%u dur:%u)",
+      dtmfsrc->payload->event, GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), dtmfsrc->rtp_timestamp,
+      dtmfsrc->payload->duration);
+
+  /* duration of DTMF payloadfor the NEXT packet */
+  /* not updated for redundant packets */
+  if (dtmfsrc->redundancy_count <= 1)
+    dtmfsrc->payload->duration += dtmfsrc->ptime * dtmfsrc->clock_rate / 1000;
+
+  if (GST_CLOCK_TIME_IS_VALID (dtmfsrc->timestamp))
+    dtmfsrc->timestamp += GST_BUFFER_DURATION (buf);
+
+  gst_rtp_buffer_unmap (&rtpbuffer);
+
+  return buf;
+}
+
+static GstMessage *
+gst_dtmf_src_prepare_message (GstRTPDTMFSrc * dtmfsrc,
+    const gchar * message_name, GstRTPDTMFSrcEvent * event)
+{
+  GstStructure *s;
+
+  switch (event->event_type) {
+    case RTP_DTMF_EVENT_TYPE_START:
+      s = gst_structure_new (message_name,
+          "type", G_TYPE_INT, 1,
+          "method", G_TYPE_INT, 1,
+          "start", G_TYPE_BOOLEAN, TRUE,
+          "number", G_TYPE_INT, event->payload->event,
+          "volume", G_TYPE_INT, event->payload->volume, NULL);
+      break;
+    case RTP_DTMF_EVENT_TYPE_STOP:
+      s = gst_structure_new (message_name,
+          "type", G_TYPE_INT, 1, "method", G_TYPE_INT, 1,
+          "start", G_TYPE_BOOLEAN, FALSE, NULL);
+      break;
+    case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
+      return NULL;
+    default:
+      return NULL;
+  }
+
+  return gst_message_new_element (GST_OBJECT (dtmfsrc), s);
+}
+
+static void
+gst_dtmf_src_post_message (GstRTPDTMFSrc * dtmfsrc, const gchar * message_name,
+    GstRTPDTMFSrcEvent * event)
+{
+  GstMessage *m = gst_dtmf_src_prepare_message (dtmfsrc, message_name, event);
+
+
+  if (m)
+    gst_element_post_message (GST_ELEMENT (dtmfsrc), m);
+}
+
+
+static GstFlowReturn
+gst_rtp_dtmf_src_create (GstBaseSrc * basesrc, guint64 offset,
+    guint length, GstBuffer ** buffer)
+{
+  GstRTPDTMFSrcEvent *event;
+  GstRTPDTMFSrc *dtmfsrc;
+  GstClock *clock;
+  GstClockID *clockid;
+  GstClockReturn clockret;
+  GstMessage *message;
+  GQueue messages = G_QUEUE_INIT;
+
+  dtmfsrc = GST_RTP_DTMF_SRC (basesrc);
+
+  do {
+
+    if (dtmfsrc->payload == NULL) {
+      GST_DEBUG_OBJECT (dtmfsrc, "popping");
+      event = g_async_queue_pop (dtmfsrc->event_queue);
+
+      GST_DEBUG_OBJECT (dtmfsrc, "popped %d", event->event_type);
+
+      switch (event->event_type) {
+        case RTP_DTMF_EVENT_TYPE_STOP:
+          GST_WARNING_OBJECT (dtmfsrc,
+              "Received a DTMF stop event when already stopped");
+          gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
+          break;
+
+        case RTP_DTMF_EVENT_TYPE_START:
+          dtmfsrc->first_packet = TRUE;
+          dtmfsrc->last_packet = FALSE;
+          /* Set the redundancy on the first packet */
+          dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
+          if (!gst_rtp_dtmf_prepare_timestamps (dtmfsrc))
+            goto no_clock;
+
+          g_queue_push_tail (&messages,
+              gst_dtmf_src_prepare_message (dtmfsrc, "dtmf-event-processed",
+                  event));
+          dtmfsrc->payload = event->payload;
+          dtmfsrc->payload->duration =
+              dtmfsrc->ptime * dtmfsrc->clock_rate / 1000;
+          event->payload = NULL;
+          break;
+
+        case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
+          /*
+           * We're pushing it back because it has to stay in there until
+           * the task is really paused (and the queue will then be flushed
+           */
+          GST_OBJECT_LOCK (dtmfsrc);
+          if (dtmfsrc->paused) {
+            g_async_queue_push (dtmfsrc->event_queue, event);
+            goto paused_locked;
+          }
+          GST_OBJECT_UNLOCK (dtmfsrc);
+          break;
+      }
+
+      gst_rtp_dtmf_src_event_free (event);
+    } else if (!dtmfsrc->first_packet && !dtmfsrc->last_packet &&
+        (dtmfsrc->timestamp - dtmfsrc->start_timestamp) / GST_MSECOND >=
+        MIN_PULSE_DURATION) {
+      GST_DEBUG_OBJECT (dtmfsrc, "try popping");
+      event = g_async_queue_try_pop (dtmfsrc->event_queue);
+
+
+      if (event != NULL) {
+        GST_DEBUG_OBJECT (dtmfsrc, "try popped %d", event->event_type);
+
+        switch (event->event_type) {
+          case RTP_DTMF_EVENT_TYPE_START:
+            GST_WARNING_OBJECT (dtmfsrc,
+                "Received two consecutive DTMF start events");
+            gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
+            break;
+
+          case RTP_DTMF_EVENT_TYPE_STOP:
+            dtmfsrc->first_packet = FALSE;
+            dtmfsrc->last_packet = TRUE;
+            /* Set the redundancy on the last packet */
+            dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
+            g_queue_push_tail (&messages,
+                gst_dtmf_src_prepare_message (dtmfsrc, "dtmf-event-processed",
+                    event));
+            break;
+
+          case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
+            /*
+             * We're pushing it back because it has to stay in there until
+             * the task is really paused (and the queue will then be flushed)
+             */
+            GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task...");
+            GST_OBJECT_LOCK (dtmfsrc);
+            if (dtmfsrc->paused) {
+              g_async_queue_push (dtmfsrc->event_queue, event);
+              goto paused_locked;
+            }
+            GST_OBJECT_UNLOCK (dtmfsrc);
+            break;
+        }
+        gst_rtp_dtmf_src_event_free (event);
+      }
+    }
+  } while (dtmfsrc->payload == NULL);
+
+
+  GST_DEBUG_OBJECT (dtmfsrc, "Processed events, now lets wait on the clock");
+
+  clock = gst_element_get_clock (GST_ELEMENT (basesrc));
+  if (!clock)
+    goto no_clock;
+  clockid = gst_clock_new_single_shot_id (clock, dtmfsrc->timestamp +
+      gst_element_get_base_time (GST_ELEMENT (dtmfsrc)));
+  gst_object_unref (clock);
+
+  GST_OBJECT_LOCK (dtmfsrc);
+  if (!dtmfsrc->paused) {
+    dtmfsrc->clockid = clockid;
+    GST_OBJECT_UNLOCK (dtmfsrc);
+
+    clockret = gst_clock_id_wait (clockid, NULL);
+
+    GST_OBJECT_LOCK (dtmfsrc);
+    if (dtmfsrc->paused)
+      clockret = GST_CLOCK_UNSCHEDULED;
+  } else {
+    clockret = GST_CLOCK_UNSCHEDULED;
+  }
+  gst_clock_id_unref (clockid);
+  dtmfsrc->clockid = NULL;
+  GST_OBJECT_UNLOCK (dtmfsrc);
+
+  while ((message = g_queue_pop_head (&messages)) != NULL)
+    gst_element_post_message (GST_ELEMENT (dtmfsrc), message);
+
+  if (clockret == GST_CLOCK_UNSCHEDULED) {
+    goto paused;
+  }
+
+send_last:
+
+  if (dtmfsrc->dirty)
+    if (!gst_rtp_dtmf_src_negotiate (basesrc))
+      return GST_FLOW_NOT_NEGOTIATED;
+
+  /* create buffer to hold the payload */
+  *buffer = gst_rtp_dtmf_src_create_next_rtp_packet (dtmfsrc);
+
+  if (dtmfsrc->redundancy_count)
+    dtmfsrc->redundancy_count--;
+
+  /* Only the very first one has a marker */
+  dtmfsrc->first_packet = FALSE;
+
+  /* This is the end of the event */
+  if (dtmfsrc->last_packet == TRUE && dtmfsrc->redundancy_count == 0) {
+
+    g_slice_free (GstRTPDTMFPayload, dtmfsrc->payload);
+    dtmfsrc->payload = NULL;
+
+    dtmfsrc->last_packet = FALSE;
+  }
+
+  return GST_FLOW_OK;
+
+paused_locked:
+
+  GST_OBJECT_UNLOCK (dtmfsrc);
+
+paused:
+
+  if (dtmfsrc->payload) {
+    dtmfsrc->first_packet = FALSE;
+    dtmfsrc->last_packet = TRUE;
+    /* Set the redundanc on the last packet */
+    dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
+    goto send_last;
+  } else {
+    return GST_FLOW_FLUSHING;
+  }
+
+no_clock:
+  GST_ELEMENT_ERROR (dtmfsrc, STREAM, MUX, ("No available clock"),
+      ("No available clock"));
+  gst_pad_pause_task (GST_BASE_SRC_PAD (dtmfsrc));
+  return GST_FLOW_ERROR;
+}
+
+
+static gboolean
+gst_rtp_dtmf_src_negotiate (GstBaseSrc * basesrc)
+{
+  GstCaps *srccaps, *peercaps;
+  GstRTPDTMFSrc *dtmfsrc = GST_RTP_DTMF_SRC (basesrc);
+  gboolean ret;
+
+  /* fill in the defaults, there properties cannot be negotiated. */
+  srccaps = gst_caps_new_simple ("application/x-rtp",
+      "media", G_TYPE_STRING, "audio",
+      "encoding-name", G_TYPE_STRING, "TELEPHONE-EVENT", NULL);
+
+  /* the peer caps can override some of the defaults */
+  peercaps = gst_pad_peer_query_caps (GST_BASE_SRC_PAD (basesrc), NULL);
+  if (peercaps == NULL) {
+    /* no peer caps, just add the other properties */
+    gst_caps_set_simple (srccaps,
+        "payload", G_TYPE_INT, dtmfsrc->pt,
+        "ssrc", G_TYPE_UINT, dtmfsrc->current_ssrc,
+        "timestamp-offset", G_TYPE_UINT, dtmfsrc->ts_base,
+        "clock-rate", G_TYPE_INT, dtmfsrc->clock_rate,
+        "seqnum-offset", G_TYPE_UINT, dtmfsrc->seqnum_base, NULL);
+
+    GST_DEBUG_OBJECT (dtmfsrc, "no peer caps: %" GST_PTR_FORMAT, srccaps);
+  } else {
+    GstCaps *temp;
+    GstStructure *s;
+    const GValue *value;
+    gint pt;
+    gint clock_rate;
+
+    /* peer provides caps we can use to fixate, intersect. This always returns a
+     * writable caps. */
+    temp = gst_caps_intersect (srccaps, peercaps);
+    gst_caps_unref (srccaps);
+    gst_caps_unref (peercaps);
+
+    if (!temp) {
+      GST_DEBUG_OBJECT (dtmfsrc, "Could not get intersection with peer caps");
+      return FALSE;
+    }
+
+    if (gst_caps_is_empty (temp)) {
+      GST_DEBUG_OBJECT (dtmfsrc, "Intersection with peer caps is empty");
+      gst_caps_unref (temp);
+      return FALSE;
+    }
+
+    /* now fixate, start by taking the first caps */
+    temp = gst_caps_truncate (temp);
+    temp = gst_caps_make_writable (temp);
+    srccaps = temp;
+
+    /* get first structure */
+    s = gst_caps_get_structure (srccaps, 0);
+
+    if (gst_structure_get_int (s, "payload", &pt)) {
+      /* use peer pt */
+      dtmfsrc->pt = pt;
+      GST_LOG_OBJECT (dtmfsrc, "using peer pt %d", pt);
+    } else {
+      if (gst_structure_has_field (s, "payload")) {
+        /* can only fixate if there is a field */
+        gst_structure_fixate_field_nearest_int (s, "payload", dtmfsrc->pt);
+        gst_structure_get_int (s, "payload", &pt);
+        GST_LOG_OBJECT (dtmfsrc, "using peer pt %d", pt);
+      } else {
+        /* no pt field, use the internal pt */
+        pt = dtmfsrc->pt;
+        gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
+        GST_LOG_OBJECT (dtmfsrc, "using internal pt %d", pt);
+      }
+    }
+
+    if (gst_structure_get_int (s, "clock-rate", &clock_rate)) {
+      dtmfsrc->clock_rate = clock_rate;
+      GST_LOG_OBJECT (dtmfsrc, "using clock-rate from caps %d",
+          dtmfsrc->clock_rate);
+    } else {
+      GST_LOG_OBJECT (dtmfsrc, "using existing clock-rate %d",
+          dtmfsrc->clock_rate);
+    }
+    gst_structure_set (s, "clock-rate", G_TYPE_INT, dtmfsrc->clock_rate, NULL);
+
+
+    if (gst_structure_has_field_typed (s, "ssrc", G_TYPE_UINT)) {
+      value = gst_structure_get_value (s, "ssrc");
+      dtmfsrc->current_ssrc = g_value_get_uint (value);
+      GST_LOG_OBJECT (dtmfsrc, "using peer ssrc %08x", dtmfsrc->current_ssrc);
+    } else {
+      /* FIXME, fixate_nearest_uint would be even better */
+      gst_structure_set (s, "ssrc", G_TYPE_UINT, dtmfsrc->current_ssrc, NULL);
+      GST_LOG_OBJECT (dtmfsrc, "using internal ssrc %08x",
+          dtmfsrc->current_ssrc);
+    }
+
+    if (gst_structure_has_field_typed (s, "timestamp-offset", G_TYPE_UINT)) {
+      value = gst_structure_get_value (s, "timestamp-offset");
+      dtmfsrc->ts_base = g_value_get_uint (value);
+      GST_LOG_OBJECT (dtmfsrc, "using peer timestamp-offset %u",
+          dtmfsrc->ts_base);
+    } else {
+      /* FIXME, fixate_nearest_uint would be even better */
+      gst_structure_set (s, "timestamp-offset", G_TYPE_UINT, dtmfsrc->ts_base,
+          NULL);
+      GST_LOG_OBJECT (dtmfsrc, "using internal timestamp-offset %u",
+          dtmfsrc->ts_base);
+    }
+    if (gst_structure_has_field_typed (s, "seqnum-offset", G_TYPE_UINT)) {
+      value = gst_structure_get_value (s, "seqnum-offset");
+      dtmfsrc->seqnum_base = g_value_get_uint (value);
+      GST_LOG_OBJECT (dtmfsrc, "using peer seqnum-offset %u",
+          dtmfsrc->seqnum_base);
+    } else {
+      /* FIXME, fixate_nearest_uint would be even better */
+      gst_structure_set (s, "seqnum-offset", G_TYPE_UINT, dtmfsrc->seqnum_base,
+          NULL);
+      GST_LOG_OBJECT (dtmfsrc, "using internal seqnum-offset %u",
+          dtmfsrc->seqnum_base);
+    }
+
+    if (gst_structure_has_field_typed (s, "ptime", G_TYPE_UINT)) {
+      value = gst_structure_get_value (s, "ptime");
+      dtmfsrc->ptime = g_value_get_uint (value);
+      GST_LOG_OBJECT (dtmfsrc, "using peer ptime %u", dtmfsrc->ptime);
+    } else if (gst_structure_has_field_typed (s, "maxptime", G_TYPE_UINT)) {
+      value = gst_structure_get_value (s, "maxptime");
+      dtmfsrc->ptime = g_value_get_uint (value);
+      GST_LOG_OBJECT (dtmfsrc, "using peer maxptime as ptime %u",
+          dtmfsrc->ptime);
+    } else {
+      /* FIXME, fixate_nearest_uint would be even better */
+      gst_structure_set (s, "ptime", G_TYPE_UINT, dtmfsrc->ptime, NULL);
+      GST_LOG_OBJECT (dtmfsrc, "using internal ptime %u", dtmfsrc->ptime);
+    }
+
+
+    GST_DEBUG_OBJECT (dtmfsrc, "with peer caps: %" GST_PTR_FORMAT, srccaps);
+  }
+
+  ret = gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), srccaps);
+  gst_caps_unref (srccaps);
+
+  dtmfsrc->dirty = FALSE;
+
+  return ret;
+
+}
+
+static gboolean
+gst_rtp_dtmf_src_query (GstBaseSrc * basesrc, GstQuery * query)
+{
+  GstRTPDTMFSrc *dtmfsrc = GST_RTP_DTMF_SRC (basesrc);
+  gboolean res = FALSE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_LATENCY:
+    {
+      GstClockTime latency;
+
+      latency = dtmfsrc->ptime * GST_MSECOND;
+      gst_query_set_latency (query, gst_base_src_is_live (basesrc), latency,
+          GST_CLOCK_TIME_NONE);
+      GST_DEBUG_OBJECT (dtmfsrc, "Reporting latency of %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (latency));
+      res = TRUE;
+    }
+      break;
+    default:
+      res = GST_BASE_SRC_CLASS (gst_rtp_dtmf_src_parent_class)->query (basesrc,
+          query);
+      break;
+  }
+
+  return res;
+}
+
+static void
+gst_rtp_dtmf_src_ready_to_paused (GstRTPDTMFSrc * dtmfsrc)
+{
+  if (dtmfsrc->ssrc == -1)
+    dtmfsrc->current_ssrc = g_random_int ();
+  else
+    dtmfsrc->current_ssrc = dtmfsrc->ssrc;
+
+  if (dtmfsrc->seqnum_offset == -1)
+    dtmfsrc->seqnum_base = g_random_int_range (0, G_MAXUINT16);
+  else
+    dtmfsrc->seqnum_base = dtmfsrc->seqnum_offset;
+  dtmfsrc->seqnum = dtmfsrc->seqnum_base;
+
+  if (dtmfsrc->ts_offset == -1)
+    dtmfsrc->ts_base = g_random_int ();
+  else
+    dtmfsrc->ts_base = dtmfsrc->ts_offset;
+
+  dtmfsrc->timestamp = 0;
+}
+
+static GstStateChangeReturn
+gst_rtp_dtmf_src_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRTPDTMFSrc *dtmfsrc;
+  GstStateChangeReturn result;
+  gboolean no_preroll = FALSE;
+  GstRTPDTMFSrcEvent *event = NULL;
+
+  dtmfsrc = GST_RTP_DTMF_SRC (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_dtmf_src_ready_to_paused (dtmfsrc);
+
+      /* Flushing the event queue */
+      while ((event = g_async_queue_try_pop (dtmfsrc->event_queue)) != NULL) {
+        gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
+        gst_rtp_dtmf_src_event_free (event);
+      }
+      dtmfsrc->last_event_was_start = FALSE;
+
+      no_preroll = TRUE;
+      break;
+    default:
+      break;
+  }
+
+  if ((result =
+          GST_ELEMENT_CLASS (gst_rtp_dtmf_src_parent_class)->change_state
+          (element, transition)) == GST_STATE_CHANGE_FAILURE)
+    goto failure;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      no_preroll = TRUE;
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+
+      /* Flushing the event queue */
+      while ((event = g_async_queue_try_pop (dtmfsrc->event_queue)) != NULL) {
+        gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
+        gst_rtp_dtmf_src_event_free (event);
+      }
+      dtmfsrc->last_event_was_start = FALSE;
+
+      /* Indicate that we don't do PRE_ROLL */
+      break;
+
+    default:
+      break;
+  }
+
+  if (no_preroll && result == GST_STATE_CHANGE_SUCCESS)
+    result = GST_STATE_CHANGE_NO_PREROLL;
+
+  return result;
+
+  /* ERRORS */
+failure:
+  {
+    GST_ERROR_OBJECT (dtmfsrc, "parent failed state change");
+    return result;
+  }
+}
+
+
+static gboolean
+gst_rtp_dtmf_src_unlock (GstBaseSrc * src)
+{
+  GstRTPDTMFSrc *dtmfsrc = GST_RTP_DTMF_SRC (src);
+  GstRTPDTMFSrcEvent *event = NULL;
+
+  GST_DEBUG_OBJECT (dtmfsrc, "Called unlock");
+
+  GST_OBJECT_LOCK (dtmfsrc);
+  dtmfsrc->paused = TRUE;
+  if (dtmfsrc->clockid) {
+    gst_clock_id_unschedule (dtmfsrc->clockid);
+  }
+  GST_OBJECT_UNLOCK (dtmfsrc);
+
+  GST_DEBUG_OBJECT (dtmfsrc, "Pushing the PAUSE_TASK event on unlock request");
+  event = g_slice_new0 (GstRTPDTMFSrcEvent);
+  event->event_type = RTP_DTMF_EVENT_TYPE_PAUSE_TASK;
+  g_async_queue_push (dtmfsrc->event_queue, event);
+
+  return TRUE;
+}
+
+
+static gboolean
+gst_rtp_dtmf_src_unlock_stop (GstBaseSrc * src)
+{
+  GstRTPDTMFSrc *dtmfsrc = GST_RTP_DTMF_SRC (src);
+
+  GST_DEBUG_OBJECT (dtmfsrc, "Unlock stopped");
+
+  GST_OBJECT_LOCK (dtmfsrc);
+  dtmfsrc->paused = FALSE;
+  GST_OBJECT_UNLOCK (dtmfsrc);
+
+  return TRUE;
+}
+
+gboolean
+gst_rtp_dtmf_src_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpdtmfsrc",
+      GST_RANK_NONE, GST_TYPE_RTP_DTMF_SRC);
+}
diff --git a/gst/dtmf/gstrtpdtmfsrc.h b/gst/dtmf/gstrtpdtmfsrc.h
new file mode 100644
index 0000000..3e9256c
--- /dev/null
+++ b/gst/dtmf/gstrtpdtmfsrc.h
@@ -0,0 +1,115 @@
+/* GStreamer RTP DTMF source
+ *
+ * gstrtpdtmfsrc.h:
+ *
+ * Copyright (C) <2007> Nokia Corporation.
+ *   Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
+ * Copyright (C) <2005> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_DTMF_SRC_H__
+#define __GST_RTP_DTMF_SRC_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesrc.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstdtmfcommon.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_DTMF_SRC		(gst_rtp_dtmf_src_get_type())
+#define GST_RTP_DTMF_SRC(obj)		(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_DTMF_SRC,GstRTPDTMFSrc))
+#define GST_RTP_DTMF_SRC_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_DTMF_SRC,GstRTPDTMFSrcClass))
+#define GST_RTP_DTMF_SRC_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_DTMF_SRC, GstRTPDTMFSrcClass))
+#define GST_IS_RTP_DTMF_SRC(obj)		(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_DTMF_SRC))
+#define GST_IS_RTP_DTMF_SRC_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_DTMF_SRC))
+#define GST_RTP_DTMF_SRC_CAST(obj)		((GstRTPDTMFSrc *)(obj))
+typedef struct _GstRTPDTMFSrc GstRTPDTMFSrc;
+typedef struct _GstRTPDTMFSrcClass GstRTPDTMFSrcClass;
+
+
+
+enum _GstRTPDTMFEventType
+{
+  RTP_DTMF_EVENT_TYPE_START,
+  RTP_DTMF_EVENT_TYPE_STOP,
+  RTP_DTMF_EVENT_TYPE_PAUSE_TASK
+};
+
+typedef enum _GstRTPDTMFEventType GstRTPDTMFEventType;
+
+struct _GstRTPDTMFSrcEvent
+{
+  GstRTPDTMFEventType event_type;
+  GstRTPDTMFPayload *payload;
+};
+
+typedef struct _GstRTPDTMFSrcEvent GstRTPDTMFSrcEvent;
+
+/**
+ * GstRTPDTMFSrc:
+ * @element: the parent element.
+ *
+ * The opaque #GstRTPDTMFSrc data structure.
+ */
+struct _GstRTPDTMFSrc
+{
+  /*< private >*/
+  GstBaseSrc basesrc;
+
+  GAsyncQueue *event_queue;
+  GstClockID clockid;
+  gboolean paused;
+  GstRTPDTMFPayload *payload;
+
+  GstClockTime timestamp;
+  GstClockTime start_timestamp;
+  gboolean first_packet;
+  gboolean last_packet;
+  guint32 ts_base;
+  guint16 seqnum_base;
+  gint16 seqnum_offset;
+  guint16 seqnum;
+  gint32 ts_offset;
+  guint32 rtp_timestamp;
+  guint pt;
+  guint ssrc;
+  guint current_ssrc;
+  guint16 ptime;
+  guint16 packet_redundancy;
+  guint32 clock_rate;
+  gboolean last_event_was_start;
+
+  GstClockTime last_stop;
+
+  gboolean dirty;
+  guint16 redundancy_count;
+};
+
+struct _GstRTPDTMFSrcClass
+{
+  GstBaseSrcClass parent_class;
+};
+
+GType gst_rtp_dtmf_src_get_type (void);
+
+gboolean gst_rtp_dtmf_src_plugin_init (GstPlugin * plugin);
+
+
+G_END_DECLS
+#endif /* __GST_RTP_DTMF_SRC_H__ */
diff --git a/gst/dtmf/meson.build b/gst/dtmf/meson.build
new file mode 100644
index 0000000..2b7201f
--- /dev/null
+++ b/gst/dtmf/meson.build
@@ -0,0 +1,16 @@
+dtmf_sources = [
+  'gstdtmfsrc.c',
+  'gstrtpdtmfsrc.c',
+  'gstrtpdtmfdepay.c',
+  'gstdtmf.c'
+]
+
+gstdtmf = library('gstdtmf',
+  dtmf_sources,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstbase_dep, gstrtp_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
+
diff --git a/gst/effectv/LICENSE b/gst/effectv/LICENSE
new file mode 100644
index 0000000..91edebf
--- /dev/null
+++ b/gst/effectv/LICENSE
@@ -0,0 +1,14 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * EffecTV:
+ * Copyright (C) 2001 FUKUCHI Kentarou
+ *
+ * EffecTV is free software. We release this product under the terms of the
+ * GNU General Public License version 2. The license is included in the file
+ * COPYING.
+ *
+ * This program 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 General Public License for more details.
+ */
diff --git a/gst/effectv/Makefile.am b/gst/effectv/Makefile.am
new file mode 100644
index 0000000..6bc7076
--- /dev/null
+++ b/gst/effectv/Makefile.am
@@ -0,0 +1,21 @@
+plugin_LTLIBRARIES = libgsteffectv.la
+
+libgsteffectv_la_SOURCES = \
+	gsteffectv.c gstedge.c gstaging.c gstdice.c gstwarp.c \
+	gstshagadelic.c gstvertigo.c gstrev.c gstquark.c gstop.c \
+	gstradioac.c gststreak.c gstripple.c
+libgsteffectv_la_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS) \
+	-I$(top_srcdir)/gst/videofilter
+libgsteffectv_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_API_VERSION@ \
+	$(GST_BASE_LIBS) \
+	$(GST_LIBS) \
+	$(LIBM)
+libgsteffectv_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gsteffectv.h gstaging.h gstdice.h gstedge.h \
+        gstquark.h gstrev.h gstshagadelic.h gstvertigo.h gstwarp.h gstop.h \
+	gstradioac.h gststreak.h gstripple.h
diff --git a/gst/effectv/gstaging.c b/gst/effectv/gstaging.c
new file mode 100644
index 0000000..a91b63b
--- /dev/null
+++ b/gst/effectv/gstaging.c
@@ -0,0 +1,402 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Copyright (C) 2001-2002 FUKUCHI Kentarou
+ *
+ * AgingTV - film-aging effect.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-agingtv
+ *
+ * AgingTV ages a video stream in realtime, changes the colors and adds
+ * scratches and dust.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! agingtv ! videoconvert ! autovideosink
+ * ]| This pipeline shows the effect of agingtv on a test stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <math.h>
+
+#include "gstaging.h"
+#include "gsteffectv.h"
+
+static const gint dx[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
+static const gint dy[8] = { 0, -1, -1, -1, 0, 1, 1, 1 };
+
+enum
+{
+  PROP_0 = 0,
+  PROP_SCRATCH_LINES,
+  PROP_COLOR_AGING,
+  PROP_PITS,
+  PROP_DUSTS
+};
+
+#define DEFAULT_SCRATCH_LINES 7
+#define DEFAULT_COLOR_AGING TRUE
+#define DEFAULT_PITS TRUE
+#define DEFAULT_DUSTS TRUE
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ BGRx, RGBx }")
+#else
+#define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ xRGB, xBGR }")
+#endif
+
+static GstStaticPadTemplate gst_agingtv_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (CAPS_STR)
+    );
+
+static GstStaticPadTemplate gst_agingtv_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (CAPS_STR)
+    );
+
+G_DEFINE_TYPE (GstAgingTV, gst_agingtv, GST_TYPE_VIDEO_FILTER);
+
+static void
+coloraging (guint32 * src, guint32 * dest, gint video_area, gint * c)
+{
+  guint32 a, b;
+  gint i;
+  gint c_tmp = *c;
+
+  c_tmp -= (gint) (fastrand ()) >> 28;
+  if (c_tmp < 0)
+    c_tmp = 0;
+  if (c_tmp > 0x18)
+    c_tmp = 0x18;
+
+  for (i = 0; i < video_area; i++) {
+    a = *src++;
+    b = (a & 0xfcfcfc) >> 2;
+    *dest++ =
+        a - b + (c_tmp | (c_tmp << 8) | (c_tmp << 16)) +
+        ((fastrand () >> 8) & 0x101010);
+  }
+  *c = c_tmp;
+}
+
+
+static void
+scratching (scratch * scratches, gint scratch_lines, guint32 * dest, gint width,
+    gint height)
+{
+  gint i, y, y1, y2;
+  guint32 *p, a, b;
+  scratch *scratch;
+
+  for (i = 0; i < scratch_lines; i++) {
+    scratch = &scratches[i];
+
+    if (scratch->life) {
+      scratch->x = scratch->x + scratch->dx;
+
+      if (scratch->x < 0 || scratch->x > width * 256) {
+        scratch->life = 0;
+        break;
+      }
+      p = dest + (scratch->x >> 8);
+      if (scratch->init) {
+        y1 = scratch->init;
+        scratch->init = 0;
+      } else {
+        y1 = 0;
+      }
+      scratch->life--;
+      if (scratch->life) {
+        y2 = height;
+      } else {
+        y2 = fastrand () % height;
+      }
+      for (y = y1; y < y2; y++) {
+        a = *p & 0xfefeff;
+        a += 0x202020;
+        b = a & 0x1010100;
+        *p = a | (b - (b >> 8));
+        p += width;
+      }
+    } else {
+      if ((fastrand () & 0xf0000000) == 0) {
+        scratch->life = 2 + (fastrand () >> 27);
+        scratch->x = fastrand () % (width * 256);
+        scratch->dx = ((int) fastrand ()) >> 23;
+        scratch->init = (fastrand () % (height - 1)) + 1;
+      }
+    }
+  }
+}
+
+static void
+dusts (guint32 * dest, gint width, gint height, gint * dust_interval,
+    gint area_scale)
+{
+  gint i, j;
+  gint dnum;
+  gint d, len;
+  guint x, y;
+
+  if (*dust_interval == 0) {
+    if ((fastrand () & 0xf0000000) == 0) {
+      *dust_interval = fastrand () >> 29;
+    }
+    return;
+  }
+  dnum = area_scale * 4 + (fastrand () >> 27);
+
+  for (i = 0; i < dnum; i++) {
+    x = fastrand () % width;
+    y = fastrand () % height;
+    d = fastrand () >> 29;
+    len = fastrand () % area_scale + 5;
+    for (j = 0; j < len; j++) {
+      dest[y * width + x] = 0x101010;
+      y += dy[d];
+      x += dx[d];
+
+      if (y >= height || x >= width)
+        break;
+
+      d = (d + fastrand () % 3 - 1) & 7;
+    }
+  }
+  *dust_interval = *dust_interval - 1;
+}
+
+static void
+pits (guint32 * dest, gint width, gint height, gint area_scale,
+    gint * pits_interval)
+{
+  gint i, j;
+  gint pnum, size, pnumscale;
+  guint x, y;
+
+  pnumscale = area_scale * 2;
+  if (*pits_interval) {
+    pnum = pnumscale + (fastrand () % pnumscale);
+
+    *pits_interval = *pits_interval - 1;
+  } else {
+    pnum = fastrand () % pnumscale;
+
+    if ((fastrand () & 0xf8000000) == 0) {
+      *pits_interval = (fastrand () >> 28) + 20;
+    }
+  }
+  for (i = 0; i < pnum; i++) {
+    x = fastrand () % (width - 1);
+    y = fastrand () % (height - 1);
+
+    size = fastrand () >> 28;
+
+    for (j = 0; j < size; j++) {
+      x = x + fastrand () % 3 - 1;
+      y = y + fastrand () % 3 - 1;
+
+      if (y >= height || x >= width)
+        break;
+
+      dest[y * width + x] = 0xc0c0c0;
+    }
+  }
+}
+
+static void
+gst_agingtv_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAgingTV *agingtv = GST_AGINGTV (object);
+
+  GST_OBJECT_LOCK (agingtv);
+  switch (prop_id) {
+    case PROP_SCRATCH_LINES:
+      g_value_set_uint (value, agingtv->scratch_lines);
+      break;
+    case PROP_COLOR_AGING:
+      g_value_set_boolean (value, agingtv->color_aging);
+      break;
+    case PROP_PITS:
+      g_value_set_boolean (value, agingtv->pits);
+      break;
+    case PROP_DUSTS:
+      g_value_set_boolean (value, agingtv->dusts);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+  GST_OBJECT_UNLOCK (agingtv);
+}
+
+static void
+gst_agingtv_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAgingTV *agingtv = GST_AGINGTV (object);
+
+  switch (prop_id) {
+    case PROP_SCRATCH_LINES:
+      agingtv->scratch_lines = g_value_get_uint (value);
+      break;
+    case PROP_COLOR_AGING:
+      agingtv->color_aging = g_value_get_boolean (value);
+      break;
+    case PROP_PITS:
+      agingtv->pits = g_value_get_boolean (value);
+      break;
+    case PROP_DUSTS:
+      agingtv->dusts = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static gboolean
+gst_agingtv_start (GstBaseTransform * trans)
+{
+  GstAgingTV *agingtv = GST_AGINGTV (trans);
+
+  agingtv->coloraging_state = 0x18;
+  agingtv->dust_interval = 0;
+  agingtv->pits_interval = 0;
+
+  memset (agingtv->scratches, 0, sizeof (agingtv->scratches));
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_agingtv_transform_frame (GstVideoFilter * filter, GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame)
+{
+  GstAgingTV *agingtv = GST_AGINGTV (filter);
+  gint area_scale;
+  GstClockTime timestamp, stream_time;
+  gint width, height, stride, video_size;
+  guint32 *src, *dest;
+
+  timestamp = GST_BUFFER_TIMESTAMP (in_frame->buffer);
+  stream_time =
+      gst_segment_to_stream_time (&GST_BASE_TRANSFORM (filter)->segment,
+      GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (agingtv, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (agingtv), stream_time);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+  stride = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0);
+  video_size = stride * height / 4;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  area_scale = width * height / 64 / 480;
+  if (area_scale <= 0)
+    area_scale = 1;
+
+  if (agingtv->color_aging)
+    coloraging (src, dest, video_size, &agingtv->coloraging_state);
+  else
+    memcpy (dest, src, stride * height);
+
+  scratching (agingtv->scratches, agingtv->scratch_lines, dest, width, height);
+  if (agingtv->pits)
+    pits (dest, width, height, area_scale, &agingtv->pits_interval);
+  if (area_scale > 1 && agingtv->dusts)
+    dusts (dest, width, height, &agingtv->dust_interval, area_scale);
+
+  return GST_FLOW_OK;
+}
+
+static void
+gst_agingtv_class_init (GstAgingTVClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->set_property = gst_agingtv_set_property;
+  gobject_class->get_property = gst_agingtv_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_SCRATCH_LINES,
+      g_param_spec_uint ("scratch-lines", "Scratch Lines",
+          "Number of scratch lines", 0, SCRATCH_MAX, DEFAULT_SCRATCH_LINES,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  g_object_class_install_property (gobject_class, PROP_COLOR_AGING,
+      g_param_spec_boolean ("color-aging", "Color Aging",
+          "Color Aging", DEFAULT_COLOR_AGING,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  g_object_class_install_property (gobject_class, PROP_PITS,
+      g_param_spec_boolean ("pits", "Pits",
+          "Pits", DEFAULT_PITS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  g_object_class_install_property (gobject_class, PROP_DUSTS,
+      g_param_spec_boolean ("dusts", "Dusts",
+          "Dusts", DEFAULT_DUSTS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  gst_element_class_set_static_metadata (gstelement_class, "AgingTV effect",
+      "Filter/Effect/Video",
+      "AgingTV adds age to video input using scratches and dust",
+      "Sam Lantinga <slouken@devolution.com>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_agingtv_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_agingtv_src_template);
+
+  trans_class->start = GST_DEBUG_FUNCPTR (gst_agingtv_start);
+
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_agingtv_transform_frame);
+}
+
+static void
+gst_agingtv_init (GstAgingTV * agingtv)
+{
+  agingtv->scratch_lines = DEFAULT_SCRATCH_LINES;
+  agingtv->color_aging = DEFAULT_COLOR_AGING;
+  agingtv->pits = DEFAULT_PITS;
+  agingtv->dusts = DEFAULT_DUSTS;
+}
diff --git a/gst/effectv/gstaging.h b/gst/effectv/gstaging.h
new file mode 100644
index 0000000..52466d1
--- /dev/null
+++ b/gst/effectv/gstaging.h
@@ -0,0 +1,89 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Copyright (C) 2001-2002 FUKUCHI Kentarou
+ *
+ * AgingTV - film-aging effect.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_AGING_H__
+#define __GST_AGING_H__
+
+#include <gst/gst.h>
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AGINGTV \
+  (gst_agingtv_get_type())
+#define GST_AGINGTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AGINGTV,GstAgingTV))
+#define GST_AGINGTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AGINGTV,GstAgingTVClass))
+#define GST_IS_AGINGTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AGINGTV))
+#define GST_IS_AGINGTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AGINGTV))
+
+typedef struct _scratch
+{
+  gint life;
+  gint x;
+  gint dx;
+  gint init;
+} scratch;
+#define SCRATCH_MAX 20
+
+typedef struct _GstAgingTV GstAgingTV;
+typedef struct _GstAgingTVClass GstAgingTVClass;
+
+struct _GstAgingTV
+{
+  GstVideoFilter videofilter;
+
+  /* < private > */
+  gboolean color_aging;
+  gboolean pits;
+  gboolean dusts;
+
+  gint coloraging_state;
+
+  scratch scratches[SCRATCH_MAX];
+  gint scratch_lines;
+
+  gint dust_interval;
+  gint pits_interval;
+
+};
+
+struct _GstAgingTVClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_agingtv_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_AGING_H__ */
+
diff --git a/gst/effectv/gstdice.c b/gst/effectv/gstdice.c
new file mode 100644
index 0000000..5c6e111
--- /dev/null
+++ b/gst/effectv/gstdice.c
@@ -0,0 +1,315 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * dice.c: a 'dicing' effect
+ *  copyright (c) 2001 Sam Mertens.  This code is subject to the provisions of
+ *  the GNU Library Public License.
+ *
+ * I suppose this looks similar to PuzzleTV, but it's not. The screen is
+ * divided into small squares, each of which is rotated either 0, 90, 180 or
+ * 270 degrees.  The amount of rotation for each square is chosen at random.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-dicetv
+ *
+ * DiceTV 'dices' the screen up into many small squares, each defaulting
+ * to a size of 16 pixels by 16 pixels.. Each square is rotated randomly
+ * in one of four directions: up (no change), down (180 degrees, or
+ * upside down), right (90 degrees clockwise), or left (90 degrees
+ * counterclockwise). The direction of each square normally remains
+ * consistent between each frame.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! dicetv ! videoconvert ! autovideosink
+ * ]| This pipeline shows the effect of dicetv on a test stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstdice.h"
+#include "gsteffectv.h"
+
+#define DEFAULT_CUBE_BITS   4
+#define MAX_CUBE_BITS       5
+#define MIN_CUBE_BITS       0
+
+typedef enum _dice_dir
+{
+  DICE_UP = 0,
+  DICE_RIGHT = 1,
+  DICE_DOWN = 2,
+  DICE_LEFT = 3
+} DiceDir;
+
+#define gst_dicetv_parent_class parent_class
+G_DEFINE_TYPE (GstDiceTV, gst_dicetv, GST_TYPE_VIDEO_FILTER);
+
+static void gst_dicetv_create_map (GstDiceTV * filter, GstVideoInfo * info);
+
+static GstStaticPadTemplate gst_dicetv_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBx, xRGB, BGRx, xBGR }"))
+    );
+
+static GstStaticPadTemplate gst_dicetv_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBx, xRGB, BGRx, xBGR }"))
+    );
+
+enum
+{
+  PROP_0,
+  PROP_CUBE_BITS
+};
+
+static gboolean
+gst_dicetv_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstDiceTV *filter = GST_DICETV (vfilter);
+
+  g_free (filter->dicemap);
+  filter->dicemap =
+      (guint8 *) g_malloc (GST_VIDEO_INFO_WIDTH (in_info) *
+      GST_VIDEO_INFO_WIDTH (in_info));
+  gst_dicetv_create_map (filter, in_info);
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_dicetv_transform_frame (GstVideoFilter * vfilter, GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame)
+{
+  GstDiceTV *filter = GST_DICETV (vfilter);
+  guint32 *src, *dest;
+  gint i, map_x, map_y, map_i, base, dx, dy, di;
+  gint video_stride, g_cube_bits, g_cube_size;
+  gint g_map_height, g_map_width;
+  GstClockTime timestamp, stream_time;
+  const guint8 *dicemap;
+
+  timestamp = GST_BUFFER_TIMESTAMP (in_frame->buffer);
+  stream_time =
+      gst_segment_to_stream_time (&GST_BASE_TRANSFORM (vfilter)->segment,
+      GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (filter), stream_time);
+
+  src = (guint32 *) GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = (guint32 *) GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+  video_stride = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0);
+
+  GST_OBJECT_LOCK (filter);
+  g_cube_bits = filter->g_cube_bits;
+  g_cube_size = filter->g_cube_size;
+  g_map_height = filter->g_map_height;
+  g_map_width = filter->g_map_width;
+
+  dicemap = filter->dicemap;
+  video_stride /= 4;
+
+  map_i = 0;
+  for (map_y = 0; map_y < g_map_height; map_y++) {
+    for (map_x = 0; map_x < g_map_width; map_x++) {
+      base = (map_y << g_cube_bits) * video_stride + (map_x << g_cube_bits);
+
+      switch (dicemap[map_i]) {
+        case DICE_UP:
+          for (dy = 0; dy < g_cube_size; dy++) {
+            i = base + dy * video_stride;
+            for (dx = 0; dx < g_cube_size; dx++) {
+              dest[i] = src[i];
+              i++;
+            }
+          }
+          break;
+        case DICE_LEFT:
+          for (dy = 0; dy < g_cube_size; dy++) {
+            i = base + dy * video_stride;
+
+            for (dx = 0; dx < g_cube_size; dx++) {
+              di = base + (dx * video_stride) + (g_cube_size - dy - 1);
+              dest[di] = src[i];
+              i++;
+            }
+          }
+          break;
+        case DICE_DOWN:
+          for (dy = 0; dy < g_cube_size; dy++) {
+            di = base + dy * video_stride;
+            i = base + (g_cube_size - dy - 1) * video_stride + g_cube_size;
+            for (dx = 0; dx < g_cube_size; dx++) {
+              i--;
+              dest[di] = src[i];
+              di++;
+            }
+          }
+          break;
+        case DICE_RIGHT:
+          for (dy = 0; dy < g_cube_size; dy++) {
+            i = base + (dy * video_stride);
+            for (dx = 0; dx < g_cube_size; dx++) {
+              di = base + dy + (g_cube_size - dx - 1) * video_stride;
+              dest[di] = src[i];
+              i++;
+            }
+          }
+          break;
+        default:
+          g_assert_not_reached ();
+          break;
+      }
+      map_i++;
+    }
+  }
+  GST_OBJECT_UNLOCK (filter);
+
+  return GST_FLOW_OK;
+}
+
+static void
+gst_dicetv_create_map (GstDiceTV * filter, GstVideoInfo * info)
+{
+  gint x, y, i;
+  gint width, height;
+
+  width = GST_VIDEO_INFO_WIDTH (info);
+  height = GST_VIDEO_INFO_HEIGHT (info);
+
+  if (width <= 0 || height <= 0)
+    return;
+
+  filter->g_map_height = height >> filter->g_cube_bits;
+  filter->g_map_width = width >> filter->g_cube_bits;
+  filter->g_cube_size = 1 << filter->g_cube_bits;
+
+  i = 0;
+
+  for (y = 0; y < filter->g_map_height; y++) {
+    for (x = 0; x < filter->g_map_width; x++) {
+      // dicemap[i] = ((i + y) & 0x3); /* Up, Down, Left or Right */
+      filter->dicemap[i] = (fastrand () >> 24) & 0x03;
+      i++;
+    }
+  }
+}
+
+static void
+gst_dicetv_set_property (GObject * object, guint prop_id, const GValue * value,
+    GParamSpec * pspec)
+{
+  GstDiceTV *filter = GST_DICETV (object);
+
+  switch (prop_id) {
+    case PROP_CUBE_BITS:
+      GST_OBJECT_LOCK (filter);
+      filter->g_cube_bits = g_value_get_int (value);
+      gst_dicetv_create_map (filter, &GST_VIDEO_FILTER (filter)->in_info);
+      GST_OBJECT_UNLOCK (filter);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_dicetv_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstDiceTV *filter = GST_DICETV (object);
+
+  switch (prop_id) {
+    case PROP_CUBE_BITS:
+      g_value_set_int (value, filter->g_cube_bits);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_dicetv_finalize (GObject * object)
+{
+  GstDiceTV *filter = GST_DICETV (object);
+
+  g_free (filter->dicemap);
+  filter->dicemap = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_dicetv_class_init (GstDiceTVClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->set_property = gst_dicetv_set_property;
+  gobject_class->get_property = gst_dicetv_get_property;
+  gobject_class->finalize = gst_dicetv_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_CUBE_BITS,
+      g_param_spec_int ("square-bits", "Square Bits", "The size of the Squares",
+          MIN_CUBE_BITS, MAX_CUBE_BITS, DEFAULT_CUBE_BITS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  gst_element_class_set_static_metadata (gstelement_class, "DiceTV effect",
+      "Filter/Effect/Video",
+      "'Dices' the screen up into many small squares",
+      "Wim Taymans <wim.taymans@gmail.be>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_dicetv_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_dicetv_src_template);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_dicetv_set_info);
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_dicetv_transform_frame);
+}
+
+static void
+gst_dicetv_init (GstDiceTV * filter)
+{
+  filter->dicemap = NULL;
+  filter->g_cube_bits = DEFAULT_CUBE_BITS;
+  filter->g_cube_size = 0;
+  filter->g_map_height = 0;
+  filter->g_map_width = 0;
+}
diff --git a/gst/effectv/gstdice.h b/gst/effectv/gstdice.h
new file mode 100644
index 0000000..4c14c97
--- /dev/null
+++ b/gst/effectv/gstdice.h
@@ -0,0 +1,75 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * dice.c: a 'dicing' effect
+ *  copyright (c) 2001 Sam Mertens.  This code is subject to the provisions of
+ *  the GNU Library Public License.
+ *
+ * I suppose this looks similar to PuzzleTV, but it's not. The screen is
+ * divided into small squares, each of which is rotated either 0, 90, 180 or
+ * 270 degrees.  The amount of rotation for each square is chosen at random.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_DICE_H__
+#define __GST_DICE_H__
+
+#include <gst/gst.h>
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DICETV \
+  (gst_dicetv_get_type())
+#define GST_DICETV(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DICETV,GstDiceTV))
+#define GST_DICETV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DICETV,GstDiceTVClass))
+#define GST_IS_DICETV(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DICETV))
+#define GST_IS_DICETV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DICETV))
+
+typedef struct _GstDiceTV GstDiceTV;
+typedef struct _GstDiceTVClass GstDiceTVClass;
+
+struct _GstDiceTV
+{
+  GstVideoFilter videofilter;
+
+  /* < private > */
+  guint8 *dicemap;
+
+  gint g_cube_bits;
+  gint g_cube_size;
+  gint g_map_height;
+  gint g_map_width;
+};
+
+struct _GstDiceTVClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_dicetv_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_DICE_H__ */
diff --git a/gst/effectv/gstedge.c b/gst/effectv/gstedge.c
new file mode 100644
index 0000000..07feb99
--- /dev/null
+++ b/gst/effectv/gstedge.c
@@ -0,0 +1,254 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV:
+ * Copyright (C) 2001-2002 FUKUCHI Kentarou
+ *
+ * EdgeTV - detects edge and display it in good old computer way
+ *
+ * EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-edgetv
+ *
+ * EdgeTV detects edges and display it in good old low resolution
+ * computer way.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! edgetv ! videoconvert ! autovideosink
+ * ]| This pipeline shows the effect of edgetv on a test stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstedge.h"
+
+#define gst_edgetv_parent_class parent_class
+G_DEFINE_TYPE (GstEdgeTV, gst_edgetv, GST_TYPE_VIDEO_FILTER);
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define CAPS_STR GST_VIDEO_CAPS_MAKE ("{  BGRx, RGBx }")
+#else
+#define CAPS_STR GST_VIDEO_CAPS_MAKE ("{  xBGR, xRGB }")
+#endif
+
+static GstStaticPadTemplate gst_edgetv_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (CAPS_STR)
+    );
+
+static GstStaticPadTemplate gst_edgetv_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (CAPS_STR)
+    );
+
+static gboolean
+gst_edgetv_set_info (GstVideoFilter * filter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstEdgeTV *edgetv = GST_EDGETV (filter);
+  guint map_size;
+  gint width, height;
+
+  width = GST_VIDEO_INFO_WIDTH (in_info);
+  height = GST_VIDEO_INFO_HEIGHT (in_info);
+
+  edgetv->map_width = width / 4;
+  edgetv->map_height = height / 4;
+  edgetv->video_width_margin = width % 4;
+
+  map_size = edgetv->map_width * edgetv->map_height * sizeof (guint32) * 2;
+
+  g_free (edgetv->map);
+  edgetv->map = (guint32 *) g_malloc0 (map_size);
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_edgetv_transform_frame (GstVideoFilter * vfilter, GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame)
+{
+  GstEdgeTV *filter = GST_EDGETV (vfilter);
+  gint x, y, r, g, b;
+  guint32 *src, *dest;
+  guint32 p, q;
+  guint32 v0, v1, v2, v3;
+  gint width, map_height, map_width;
+  gint video_width_margin;
+  guint32 *map;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  map = filter->map;
+  map_height = filter->map_height;
+  map_width = filter->map_width;
+  video_width_margin = filter->video_width_margin;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+
+  src += width * 4 + 4;
+  dest += width * 4 + 4;
+
+  for (y = 1; y < map_height - 1; y++) {
+    for (x = 1; x < map_width - 1; x++) {
+      p = *src;
+      q = *(src - 4);
+
+      /* difference between the current pixel and left neighbor. */
+      r = ((p & 0xff0000) - (q & 0xff0000)) >> 16;
+      g = ((p & 0xff00) - (q & 0xff00)) >> 8;
+      b = (p & 0xff) - (q & 0xff);
+      r *= r;
+      g *= g;
+      b *= b;
+      r = r >> 5;               /* To lack the lower bit for saturated addition,  */
+      g = g >> 5;               /* devide the value with 32, instead of 16. It is */
+      b = b >> 4;               /* same as `v2 &= 0xfefeff' */
+      if (r > 127)
+        r = 127;
+      if (g > 127)
+        g = 127;
+      if (b > 255)
+        b = 255;
+      v2 = (r << 17) | (g << 9) | b;
+
+      /* difference between the current pixel and upper neighbor. */
+      q = *(src - width * 4);
+      r = ((p & 0xff0000) - (q & 0xff0000)) >> 16;
+      g = ((p & 0xff00) - (q & 0xff00)) >> 8;
+      b = (p & 0xff) - (q & 0xff);
+      r *= r;
+      g *= g;
+      b *= b;
+      r = r >> 5;
+      g = g >> 5;
+      b = b >> 4;
+      if (r > 127)
+        r = 127;
+      if (g > 127)
+        g = 127;
+      if (b > 255)
+        b = 255;
+      v3 = (r << 17) | (g << 9) | b;
+
+      v0 = map[(y - 1) * map_width * 2 + x * 2];
+      v1 = map[y * map_width * 2 + (x - 1) * 2 + 1];
+      map[y * map_width * 2 + x * 2] = v2;
+      map[y * map_width * 2 + x * 2 + 1] = v3;
+      r = v0 + v1;
+      g = r & 0x01010100;
+      dest[0] = r | (g - (g >> 8));
+      r = v0 + v3;
+      g = r & 0x01010100;
+      dest[1] = r | (g - (g >> 8));
+      dest[2] = v3;
+      dest[3] = v3;
+      r = v2 + v1;
+      g = r & 0x01010100;
+      dest[width] = r | (g - (g >> 8));
+      r = v2 + v3;
+      g = r & 0x01010100;
+      dest[width + 1] = r | (g - (g >> 8));
+      dest[width + 2] = v3;
+      dest[width + 3] = v3;
+      dest[width * 2] = v2;
+      dest[width * 2 + 1] = v2;
+      dest[width * 2 + 2] = 0;
+      dest[width * 2 + 3] = 0;
+      dest[width * 3] = v2;
+      dest[width * 3 + 1] = v2;
+      dest[width * 3 + 2] = 0;
+      dest[width * 3 + 3] = 0;
+
+      src += 4;
+      dest += 4;
+    }
+    src += width * 3 + 8 + video_width_margin;
+    dest += width * 3 + 8 + video_width_margin;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_edgetv_start (GstBaseTransform * trans)
+{
+  GstEdgeTV *edgetv = GST_EDGETV (trans);
+
+  if (edgetv->map)
+    memset (edgetv->map, 0,
+        edgetv->map_width * edgetv->map_height * sizeof (guint32) * 2);
+  return TRUE;
+}
+
+static void
+gst_edgetv_finalize (GObject * object)
+{
+  GstEdgeTV *edgetv = GST_EDGETV (object);
+
+  g_free (edgetv->map);
+  edgetv->map = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_edgetv_class_init (GstEdgeTVClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->finalize = gst_edgetv_finalize;
+
+  gst_element_class_set_static_metadata (gstelement_class, "EdgeTV effect",
+      "Filter/Effect/Video",
+      "Apply edge detect on video", "Wim Taymans <wim.taymans@chello.be>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_edgetv_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_edgetv_src_template);
+
+  trans_class->start = GST_DEBUG_FUNCPTR (gst_edgetv_start);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_edgetv_set_info);
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_edgetv_transform_frame);
+}
+
+static void
+gst_edgetv_init (GstEdgeTV * edgetv)
+{
+}
diff --git a/gst/effectv/gstedge.h b/gst/effectv/gstedge.h
new file mode 100644
index 0000000..290c312
--- /dev/null
+++ b/gst/effectv/gstedge.h
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV:
+ * Copyright (C) 2001-2002 FUKUCHI Kentarou
+ *
+ * EdgeTV - detects edge and display it in good old computer way
+ *
+ * EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_EDGE_H__
+#define __GST_EDGE_H__
+
+#include <gst/gst.h>
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_EDGETV \
+  (gst_edgetv_get_type())
+#define GST_EDGETV(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_EDGETV,GstEdgeTV))
+#define GST_EDGETV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_EDGETV,GstEdgeTVClass))
+#define GST_IS_EDGETV(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_EDGETV))
+#define GST_IS_EDGETV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EDGETV))
+
+typedef struct _GstEdgeTV GstEdgeTV;
+typedef struct _GstEdgeTVClass GstEdgeTVClass;
+
+struct _GstEdgeTV
+{
+  GstVideoFilter videofilter;
+
+  /* < private > */
+  gint map_width, map_height;
+  guint32 *map;
+  gint video_width_margin;
+};
+
+struct _GstEdgeTVClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_edgetv_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_EDGE_H__ */
diff --git a/gst/effectv/gsteffectv.c b/gst/effectv/gsteffectv.c
new file mode 100644
index 0000000..0e9ffc0
--- /dev/null
+++ b/gst/effectv/gsteffectv.c
@@ -0,0 +1,83 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * EffecTV:
+ * Copyright (C) 2001 FUKUCHI Kentarou
+ *
+ * EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gsteffectv.h"
+#include "gstaging.h"
+#include "gstdice.h"
+#include "gstedge.h"
+#include "gstquark.h"
+#include "gstrev.h"
+#include "gstshagadelic.h"
+#include "gstvertigo.h"
+#include "gstwarp.h"
+#include "gstop.h"
+#include "gstradioac.h"
+#include "gststreak.h"
+#include "gstripple.h"
+
+struct _elements_entry
+{
+  const gchar *name;
+    GType (*type) (void);
+};
+
+static const struct _elements_entry _elements[] = {
+  {"edgetv", gst_edgetv_get_type},
+  {"agingtv", gst_agingtv_get_type},
+  {"dicetv", gst_dicetv_get_type},
+  {"warptv", gst_warptv_get_type},
+  {"shagadelictv", gst_shagadelictv_get_type},
+  {"vertigotv", gst_vertigotv_get_type},
+  {"revtv", gst_revtv_get_type},
+  {"quarktv", gst_quarktv_get_type},
+  {"optv", gst_optv_get_type},
+  {"radioactv", gst_radioactv_get_type},
+  {"streaktv", gst_streaktv_get_type},
+  {"rippletv", gst_rippletv_get_type},
+  {NULL, 0},
+};
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  gint i = 0;
+
+  while (_elements[i].name) {
+    if (!gst_element_register (plugin, _elements[i].name,
+            GST_RANK_NONE, (_elements[i].type) ()))
+      return FALSE;
+    i++;
+  }
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    effectv,
+    "effect plugins from the effectv project",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/effectv/gsteffectv.h b/gst/effectv/gsteffectv.h
new file mode 100644
index 0000000..0f00799
--- /dev/null
+++ b/gst/effectv/gsteffectv.h
@@ -0,0 +1,33 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * EffecTV:
+ * Copyright (C) 2001 FUKUCHI Kentarou
+ *
+ *  EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/gst.h>
+
+static inline guint
+fastrand (void)
+{
+  static guint fastrand_val;
+
+  return (fastrand_val = fastrand_val * 1103515245 + 12345);
+}
+
diff --git a/gst/effectv/gstop.c b/gst/effectv/gstop.c
new file mode 100644
index 0000000..283878f
--- /dev/null
+++ b/gst/effectv/gstop.c
@@ -0,0 +1,418 @@
+/* GStreamer
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Copyright (C) 2001-2006 FUKUCHI Kentaro
+ *
+ * OpTV - Optical art meets real-time video effect.
+ * Copyright (C) 2004-2005 FUKUCHI Kentaro
+ *
+ * EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-optv
+ *
+ * Traditional black-white optical animation is now resurrected as a
+ * real-time video effect. Input images are binarized and combined with
+ * various optical pattern.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! optv ! videoconvert ! autovideosink
+ * ]| This pipeline shows the effect of optv on a test stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <string.h>
+
+#include "gstop.h"
+#include "gsteffectv.h"
+
+#include <gst/video/video.h>
+
+enum
+{
+  OP_SPIRAL1 = 0,
+  OP_SPIRAL2,
+  OP_PARABOLA,
+  OP_HSTRIPE
+};
+
+#define GST_TYPE_OPTV_MODE (gst_optv_mode_get_type())
+static GType
+gst_optv_mode_get_type (void)
+{
+  static GType type = 0;
+
+  static const GEnumValue enumvalue[] = {
+    {OP_SPIRAL1, "Maelstrom", "maelstrom"},
+    {OP_SPIRAL2, "Radiation", "radiation"},
+    {OP_PARABOLA, "Horizontal Stripes",
+        "horizontal-stripes"},
+    {OP_HSTRIPE, "Vertical Stripes", "vertical-stripes"},
+    {0, NULL, NULL},
+  };
+
+  if (!type) {
+    type = g_enum_register_static ("GstOpTVMode", enumvalue);
+  }
+  return type;
+}
+
+#define DEFAULT_MODE OP_SPIRAL1
+#define DEFAULT_SPEED 16
+#define DEFAULT_THRESHOLD 60
+
+enum
+{
+  PROP_0,
+  PROP_MODE,
+  PROP_SPEED,
+  PROP_THRESHOLD
+};
+
+static guint32 palette[256];
+
+#define gst_optv_parent_class parent_class
+G_DEFINE_TYPE (GstOpTV, gst_optv, GST_TYPE_VIDEO_FILTER);
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ BGRx, RGBx }")
+#else
+#define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ xBGR, xRGB }")
+#endif
+
+static GstStaticPadTemplate gst_optv_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (CAPS_STR)
+    );
+
+static GstStaticPadTemplate gst_optv_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (CAPS_STR)
+    );
+
+static void
+initPalette (void)
+{
+  gint i;
+  guint8 v;
+
+  for (i = 0; i < 112; i++) {
+    palette[i] = 0;
+    palette[i + 128] = 0xffffff;
+  }
+  for (i = 0; i < 16; i++) {
+    v = 16 * (i + 1) - 1;
+    palette[i + 112] = (v << 16) | (v << 8) | v;
+    v = 255 - v;
+    palette[i + 240] = (v << 16) | (v << 8) | v;
+  }
+}
+
+static void
+setOpmap (gint8 * opmap[4], gint width, gint height)
+{
+  gint i, j, x, y;
+#ifndef PS2
+  gdouble xx, yy, r, at, rr;
+#else
+  gfloat xx, yy, r, at, rr;
+#endif
+  gint sci;
+
+  sci = 640 / width;
+  i = 0;
+  for (y = 0; y < height; y++) {
+    yy = (gdouble) (y - height / 2) / width;
+    for (x = 0; x < width; x++) {
+      xx = (gdouble) x / width - 0.5;
+#ifndef PS2
+      r = sqrt (xx * xx + yy * yy);
+      at = atan2 (xx, yy);
+#else
+      r = sqrtf (xx * xx + yy * yy);
+      at = atan2f (xx, yy);
+#endif
+
+      opmap[OP_SPIRAL1][i] = ((guint)
+          ((at / G_PI * 256) + (r * 4000))) & 255;
+
+      j = r * 300 / 32;
+      rr = r * 300 - j * 32;
+      j *= 64;
+      j += (rr > 28) ? (rr - 28) * 16 : 0;
+      opmap[OP_SPIRAL2][i] = ((guint)
+          ((at / G_PI * 4096) + (r * 1600) - j)) & 255;
+
+      opmap[OP_PARABOLA][i] =
+          ((guint) (yy / (xx * xx * 0.3 + 0.1) * 400)) & 255;
+      opmap[OP_HSTRIPE][i] = x * 8 * sci;
+      i++;
+    }
+  }
+}
+
+/* Taken from effectv/image.c */
+/* Y value filters */
+static void
+image_y_over (guint32 * src, guint8 * diff, gint y_threshold, gint video_area)
+{
+  gint i;
+  gint R, G, B, v;
+  guint8 *p = diff;
+
+  for (i = video_area; i > 0; i--) {
+    R = ((*src) & 0xff0000) >> (16 - 1);
+    G = ((*src) & 0xff00) >> (8 - 2);
+    B = (*src) & 0xff;
+    v = y_threshold * 7 - (R + G + B);
+    *p = (guint8) (v >> 24);
+    src++;
+    p++;
+  }
+}
+
+static GstFlowReturn
+gst_optv_transform_frame (GstVideoFilter * vfilter, GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame)
+{
+  GstOpTV *filter = GST_OPTV (vfilter);
+  guint32 *src, *dest;
+  gint8 *p;
+  guint8 *diff;
+  gint x, y, width, height;
+  GstClockTime timestamp, stream_time;
+  guint8 phase;
+
+  timestamp = GST_BUFFER_TIMESTAMP (in_frame->buffer);
+  stream_time =
+      gst_segment_to_stream_time (&GST_BASE_TRANSFORM (vfilter)->segment,
+      GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (filter), stream_time);
+
+  if (G_UNLIKELY (filter->opmap[0] == NULL))
+    return GST_FLOW_NOT_NEGOTIATED;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  GST_OBJECT_LOCK (filter);
+  switch (filter->mode) {
+    default:
+    case 0:
+      p = filter->opmap[OP_SPIRAL1];
+      break;
+    case 1:
+      p = filter->opmap[OP_SPIRAL2];
+      break;
+    case 2:
+      p = filter->opmap[OP_PARABOLA];
+      break;
+    case 3:
+      p = filter->opmap[OP_HSTRIPE];
+      break;
+  }
+
+  filter->phase -= filter->speed;
+
+  diff = filter->diff;
+  image_y_over (src, diff, filter->threshold, width * height);
+  phase = filter->phase;
+
+  for (y = 0; y < height; y++) {
+    for (x = 0; x < width; x++) {
+      *dest++ = palette[(((guint8) (*p + phase)) ^ *diff++) & 255];
+      p++;
+    }
+  }
+  GST_OBJECT_UNLOCK (filter);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_optv_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstOpTV *filter = GST_OPTV (vfilter);
+  gint i, width, height;
+
+  width = GST_VIDEO_INFO_WIDTH (in_info);
+  height = GST_VIDEO_INFO_HEIGHT (in_info);
+
+  for (i = 0; i < 4; i++) {
+    g_free (filter->opmap[i]);
+    filter->opmap[i] = g_new (gint8, width * height);
+  }
+  setOpmap (filter->opmap, width, height);
+
+  g_free (filter->diff);
+  filter->diff = g_new (guint8, width * height);
+
+  return TRUE;
+}
+
+static gboolean
+gst_optv_start (GstBaseTransform * trans)
+{
+  GstOpTV *filter = GST_OPTV (trans);
+
+  filter->phase = 0;
+
+  return TRUE;
+}
+
+static void
+gst_optv_finalize (GObject * object)
+{
+  GstOpTV *filter = GST_OPTV (object);
+
+  if (filter->opmap[0]) {
+    gint i;
+
+    for (i = 0; i < 4; i++) {
+      g_free (filter->opmap[i]);
+      filter->opmap[i] = NULL;
+    }
+  }
+
+  g_free (filter->diff);
+  filter->diff = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_optv_set_property (GObject * object, guint prop_id, const GValue * value,
+    GParamSpec * pspec)
+{
+  GstOpTV *filter = GST_OPTV (object);
+
+  GST_OBJECT_LOCK (filter);
+  switch (prop_id) {
+    case PROP_MODE:
+      filter->mode = g_value_get_enum (value);
+      break;
+    case PROP_SPEED:
+      filter->speed = g_value_get_int (value);
+      break;
+    case PROP_THRESHOLD:
+      filter->threshold = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (filter);
+}
+
+static void
+gst_optv_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstOpTV *filter = GST_OPTV (object);
+
+  switch (prop_id) {
+    case PROP_MODE:
+      g_value_set_enum (value, filter->mode);
+      break;
+    case PROP_SPEED:
+      g_value_set_int (value, filter->speed);
+      break;
+    case PROP_THRESHOLD:
+      g_value_set_uint (value, filter->threshold);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_optv_class_init (GstOpTVClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->set_property = gst_optv_set_property;
+  gobject_class->get_property = gst_optv_get_property;
+
+  gobject_class->finalize = gst_optv_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_MODE,
+      g_param_spec_enum ("mode", "Mode",
+          "Mode", GST_TYPE_OPTV_MODE, DEFAULT_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_SPEED,
+      g_param_spec_int ("speed", "Speed",
+          "Effect speed", G_MININT, G_MAXINT, DEFAULT_SPEED,
+          GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_THRESHOLD,
+      g_param_spec_uint ("threshold", "Threshold",
+          "Luma threshold", 0, G_MAXINT, DEFAULT_THRESHOLD,
+          GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class, "OpTV effect",
+      "Filter/Effect/Video",
+      "Optical art meets real-time video effect",
+      "FUKUCHI, Kentarou <fukuchi@users.sourceforge.net>, "
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_optv_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_optv_src_template);
+
+  trans_class->start = GST_DEBUG_FUNCPTR (gst_optv_start);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_optv_set_info);
+  vfilter_class->transform_frame = GST_DEBUG_FUNCPTR (gst_optv_transform_frame);
+
+  initPalette ();
+}
+
+static void
+gst_optv_init (GstOpTV * filter)
+{
+  filter->speed = DEFAULT_SPEED;
+  filter->mode = DEFAULT_MODE;
+  filter->threshold = DEFAULT_THRESHOLD;
+}
diff --git a/gst/effectv/gstop.h b/gst/effectv/gstop.h
new file mode 100644
index 0000000..5572402
--- /dev/null
+++ b/gst/effectv/gstop.h
@@ -0,0 +1,74 @@
+/* GStreamer
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Copyright (C) 2001-2006 FUKUCHI Kentaro
+ *
+ * OpTV - Optical art meets real-time video effect.
+ * Copyright (C) 2004-2005 FUKUCHI Kentaro
+ *
+ * EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_OP_H__
+#define __GST_OP_H__
+
+#include <gst/gst.h>
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_OPTV \
+  (gst_optv_get_type())
+#define GST_OPTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OPTV,GstOpTV))
+#define GST_OPTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OPTV,GstOpTVClass))
+#define GST_IS_OPTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OPTV))
+#define GST_IS_OPTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OPTV))
+
+typedef struct _GstOpTV GstOpTV;
+typedef struct _GstOpTVClass GstOpTVClass;
+
+struct _GstOpTV
+{
+  GstVideoFilter element;
+
+  /* < private > */
+  gint mode;
+  gint speed;
+  guint threshold;
+
+  gint8 *opmap[4];
+  guint8 *diff;
+  guint8 phase;
+};
+
+struct _GstOpTVClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_optv_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_OP_H__ */
diff --git a/gst/effectv/gstquark.c b/gst/effectv/gstquark.c
new file mode 100644
index 0000000..12ade75
--- /dev/null
+++ b/gst/effectv/gstquark.c
@@ -0,0 +1,299 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV:
+ * Copyright (C) 2001-2002 FUKUCHI Kentarou
+ *
+ * QuarkTV - motion disolver.
+ *
+ *  EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-quarktv
+ *
+ * QuarkTV disolves moving objects. It picks up pixels from
+ * the last frames randomly.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! quarktv ! videoconvert ! autovideosink
+ * ]| This pipeline shows the effect of quarktv on a test stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <string.h>
+
+#include "gstquark.h"
+#include "gsteffectv.h"
+
+/* number of frames of time-buffer. It should be as a configurable paramater */
+/* This number also must be 2^n just for the speed. */
+#define PLANES 16
+
+enum
+{
+  PROP_0,
+  PROP_PLANES
+};
+
+#define gst_quarktv_parent_class parent_class
+G_DEFINE_TYPE (GstQuarkTV, gst_quarktv, GST_TYPE_VIDEO_FILTER);
+
+static void gst_quarktv_planetable_clear (GstQuarkTV * filter);
+
+static GstStaticPadTemplate gst_quarktv_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ xRGB, xBGR, BGRx, RGBx }"))
+    );
+
+static GstStaticPadTemplate gst_quarktv_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ xRGB, xBGR, BGRx, RGBx }"))
+    );
+
+static gboolean
+gst_quarktv_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstQuarkTV *filter = GST_QUARKTV (vfilter);
+  gint width, height;
+
+  width = GST_VIDEO_INFO_WIDTH (in_info);
+  height = GST_VIDEO_INFO_HEIGHT (in_info);
+
+  gst_quarktv_planetable_clear (filter);
+  filter->area = width * height;
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_quarktv_transform_frame (GstVideoFilter * vfilter, GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame)
+{
+  GstQuarkTV *filter = GST_QUARKTV (vfilter);
+  gint area;
+  guint32 *src, *dest;
+  GstClockTime timestamp;
+  GstBuffer **planetable;
+  gint planes, current_plane;
+
+  timestamp = GST_BUFFER_TIMESTAMP (in_frame->buffer);
+  timestamp =
+      gst_segment_to_stream_time (&GST_BASE_TRANSFORM (vfilter)->segment,
+      GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (timestamp))
+    gst_object_sync_values (GST_OBJECT (filter), timestamp);
+
+  if (G_UNLIKELY (filter->planetable == NULL))
+    return GST_FLOW_FLUSHING;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  GST_OBJECT_LOCK (filter);
+  area = filter->area;
+  planetable = filter->planetable;
+  planes = filter->planes;
+  current_plane = filter->current_plane;
+
+  if (planetable[current_plane])
+    gst_buffer_unref (planetable[current_plane]);
+  planetable[current_plane] = gst_buffer_ref (in_frame->buffer);
+
+  /* For each pixel */
+  while (--area) {
+    GstBuffer *rand;
+
+    /* pick a random buffer */
+    rand = planetable[(current_plane + (fastrand () >> 24)) % planes];
+
+    /* Copy the pixel from the random buffer to dest, FIXME, slow */
+    if (rand)
+      gst_buffer_extract (rand, area * 4, &dest[area], 4);
+    else
+      dest[area] = src[area];
+  }
+
+  filter->current_plane--;
+  if (filter->current_plane < 0)
+    filter->current_plane = planes - 1;
+  GST_OBJECT_UNLOCK (filter);
+
+  return GST_FLOW_OK;
+}
+
+static void
+gst_quarktv_planetable_clear (GstQuarkTV * filter)
+{
+  gint i;
+
+  if (filter->planetable == NULL)
+    return;
+
+  for (i = 0; i < filter->planes; i++) {
+    if (GST_IS_BUFFER (filter->planetable[i])) {
+      gst_buffer_unref (filter->planetable[i]);
+    }
+    filter->planetable[i] = NULL;
+  }
+}
+
+static gboolean
+gst_quarktv_start (GstBaseTransform * trans)
+{
+  GstQuarkTV *filter = GST_QUARKTV (trans);
+
+  if (filter->planetable) {
+    gst_quarktv_planetable_clear (filter);
+    g_free (filter->planetable);
+  }
+  filter->planetable =
+      (GstBuffer **) g_malloc0 (filter->planes * sizeof (GstBuffer *));
+
+  return TRUE;
+}
+
+static void
+gst_quarktv_finalize (GObject * object)
+{
+  GstQuarkTV *filter = GST_QUARKTV (object);
+
+  if (filter->planetable) {
+    gst_quarktv_planetable_clear (filter);
+    g_free (filter->planetable);
+    filter->planetable = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_quarktv_set_property (GObject * object, guint prop_id, const GValue * value,
+    GParamSpec * pspec)
+{
+  GstQuarkTV *filter = GST_QUARKTV (object);
+
+  GST_OBJECT_LOCK (filter);
+  switch (prop_id) {
+    case PROP_PLANES:
+    {
+      gint new_n_planes = g_value_get_int (value);
+      GstBuffer **new_planetable;
+      gint i;
+
+      /* If the number of planes changed, copy across any existing planes */
+      if (new_n_planes != filter->planes) {
+        new_planetable =
+            (GstBuffer **) g_malloc0 (new_n_planes * sizeof (GstBuffer *));
+
+        if (filter->planetable) {
+          for (i = 0; (i < new_n_planes) && (i < filter->planes); i++) {
+            new_planetable[i] = filter->planetable[i];
+          }
+          for (; i < filter->planes; i++) {
+            if (filter->planetable[i])
+              gst_buffer_unref (filter->planetable[i]);
+          }
+          g_free (filter->planetable);
+        }
+
+        filter->planetable = new_planetable;
+        filter->planes = new_n_planes;
+        filter->current_plane = filter->planes - 1;
+      }
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (filter);
+}
+
+static void
+gst_quarktv_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstQuarkTV *filter = GST_QUARKTV (object);
+
+  switch (prop_id) {
+    case PROP_PLANES:
+      g_value_set_int (value, filter->planes);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_quarktv_class_init (GstQuarkTVClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->set_property = gst_quarktv_set_property;
+  gobject_class->get_property = gst_quarktv_get_property;
+
+  gobject_class->finalize = gst_quarktv_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_PLANES,
+      g_param_spec_int ("planes", "Planes",
+          "Number of planes", 1, 64, PLANES,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  gst_element_class_set_static_metadata (gstelement_class, "QuarkTV effect",
+      "Filter/Effect/Video",
+      "Motion dissolver", "FUKUCHI, Kentarou <fukuchi@users.sourceforge.net>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_quarktv_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_quarktv_src_template);
+
+  trans_class->start = GST_DEBUG_FUNCPTR (gst_quarktv_start);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_quarktv_set_info);
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_quarktv_transform_frame);
+}
+
+static void
+gst_quarktv_init (GstQuarkTV * filter)
+{
+  filter->planes = PLANES;
+  filter->current_plane = filter->planes - 1;
+}
diff --git a/gst/effectv/gstquark.h b/gst/effectv/gstquark.h
new file mode 100644
index 0000000..5557756
--- /dev/null
+++ b/gst/effectv/gstquark.h
@@ -0,0 +1,71 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV:
+ * Copyright (C) 2001-2002 FUKUCHI Kentarou
+ *
+ * QuarkTV - motion disolver.
+ *
+ *  EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_QUARK_H__
+#define __GST_QUARK_H__
+
+#include <gst/gst.h>
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_QUARKTV \
+  (gst_quarktv_get_type())
+#define GST_QUARKTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_QUARKTV,GstQuarkTV))
+#define GST_QUARKTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_QUARKTV,GstQuarkTVClass))
+#define GST_IS_QUARKTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_QUARKTV))
+#define GST_IS_QUARKTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QUARKTV))
+
+typedef struct _GstQuarkTV GstQuarkTV;
+typedef struct _GstQuarkTVClass GstQuarkTVClass;
+
+struct _GstQuarkTV
+{
+  GstVideoFilter element;
+
+  /* < private > */
+  gint area;
+  gint planes;
+  gint current_plane;
+  GstBuffer **planetable;
+};
+
+struct _GstQuarkTVClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_quarktv_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_QUARK_H__ */
diff --git a/gst/effectv/gstradioac.c b/gst/effectv/gstradioac.c
new file mode 100644
index 0000000..b663684
--- /dev/null
+++ b/gst/effectv/gstradioac.c
@@ -0,0 +1,622 @@
+/* GStreamer
+ * Cradioacyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Cradioacyright (C) 2001-2006 FUKUCHI Kentaro
+ *
+ * RadioacTV - motion-enlightment effect.
+ * Cradioacyright (C) 2001-2002 FUKUCHI Kentaro
+ *
+ * EffecTV is free software. 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 radioaction) any later version.
+ *
+ * This library is distributed in the hradioace 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 cradioacy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-radioactv
+ *
+ * RadioacTV does *NOT* detect a radioactivity. It detects a difference
+ * from previous frame and blurs it.
+ * 
+ * RadioacTV has 4 mode, normal, strobe1, strobe2 and trigger.
+ * In trigger mode, effect appears only when the trigger property is %TRUE.
+ *
+ * strobe1 and strobe2 mode drops some frames. strobe1 mode uses the difference between
+ * current frame and previous frame dropped, while strobe2 mode uses the difference from
+ * previous frame displayed. The effect of strobe2 is stronger than strobe1.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! radioactv ! videoconvert ! autovideosink
+ * ]| This pipeline shows the effect of radioactv on a test stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <string.h>
+
+#include "gstradioac.h"
+#include "gsteffectv.h"
+
+enum
+{
+  RADIOAC_NORMAL = 0,
+  RADIOAC_STROBE,
+  RADIOAC_STROBE2,
+  RADIOAC_TRIGGER
+};
+
+enum
+{
+  COLOR_RED = 0,
+  COLOR_GREEN,
+  COLOR_BLUE,
+  COLOR_WHITE
+};
+
+#define GST_TYPE_RADIOACTV_MODE (gst_radioactv_mode_get_type())
+static GType
+gst_radioactv_mode_get_type (void)
+{
+  static GType type = 0;
+
+  static const GEnumValue enumvalue[] = {
+    {RADIOAC_NORMAL, "Normal", "normal"},
+    {RADIOAC_STROBE, "Strobe 1", "strobe1"},
+    {RADIOAC_STROBE2, "Strobe 2", "strobe2"},
+    {RADIOAC_TRIGGER, "Trigger", "trigger"},
+    {0, NULL, NULL},
+  };
+
+  if (!type) {
+    type = g_enum_register_static ("GstRadioacTVMode", enumvalue);
+  }
+  return type;
+}
+
+#define GST_TYPE_RADIOACTV_COLOR (gst_radioactv_color_get_type())
+static GType
+gst_radioactv_color_get_type (void)
+{
+  static GType type = 0;
+
+  static const GEnumValue enumvalue[] = {
+    {COLOR_RED, "Red", "red"},
+    {COLOR_GREEN, "Green", "green"},
+    {COLOR_BLUE, "Blue", "blue"},
+    {COLOR_WHITE, "White", "white"},
+    {0, NULL, NULL},
+  };
+
+  if (!type) {
+    type = g_enum_register_static ("GstRadioacTVColor", enumvalue);
+  }
+  return type;
+}
+
+#define DEFAULT_MODE RADIOAC_NORMAL
+#define DEFAULT_COLOR COLOR_WHITE
+#define DEFAULT_INTERVAL 3
+#define DEFAULT_TRIGGER FALSE
+
+enum
+{
+  PROP_0,
+  PROP_MODE,
+  PROP_COLOR,
+  PROP_INTERVAL,
+  PROP_TRIGGER
+};
+
+#define COLORS 32
+#define PATTERN 4
+#define MAGIC_THRESHOLD 40
+#define RATIO 0.95
+
+static guint32 palettes[COLORS * PATTERN];
+static const gint swap_tab[] = { 2, 1, 0, 3 };
+
+#define gst_radioactv_parent_class parent_class
+G_DEFINE_TYPE (GstRadioacTV, gst_radioactv, GST_TYPE_VIDEO_FILTER);
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ RGBx, BGRx }")
+#else
+#define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ xBGR, xRGB }")
+#endif
+
+static GstStaticPadTemplate gst_radioactv_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (CAPS_STR)
+    );
+
+static GstStaticPadTemplate gst_radioactv_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (CAPS_STR)
+    );
+
+static void
+makePalette (void)
+{
+  gint i;
+
+#define DELTA (255/(COLORS/2-1))
+
+  /* red, gree, blue */
+  for (i = 0; i < COLORS / 2; i++) {
+    palettes[i] = i * DELTA;
+    palettes[COLORS + i] = (i * DELTA) << 8;
+    palettes[COLORS * 2 + i] = (i * DELTA) << 16;
+  }
+  for (i = 0; i < COLORS / 2; i++) {
+    palettes[i + COLORS / 2] = 255 | (i * DELTA) << 16 | (i * DELTA) << 8;
+    palettes[COLORS + i + COLORS / 2] =
+        (255 << 8) | (i * DELTA) << 16 | i * DELTA;
+    palettes[COLORS * 2 + i + COLORS / 2] =
+        (255 << 16) | (i * DELTA) << 8 | i * DELTA;
+  }
+  /* white */
+  for (i = 0; i < COLORS; i++) {
+    palettes[COLORS * 3 + i] = (255 * i / COLORS) * 0x10101;
+  }
+  for (i = 0; i < COLORS * PATTERN; i++) {
+    palettes[i] = palettes[i] & 0xfefeff;
+  }
+#undef DELTA
+}
+
+#define VIDEO_HWIDTH (filter->buf_width/2)
+#define VIDEO_HHEIGHT (filter->buf_height/2)
+
+/* this table assumes that video_width is times of 32 */
+static void
+setTable (GstRadioacTV * filter)
+{
+  guint bits;
+  gint x, y, tx, ty, xx;
+  gint ptr, prevptr;
+
+  prevptr = (gint) (0.5 + RATIO * (-VIDEO_HWIDTH) + VIDEO_HWIDTH);
+  for (xx = 0; xx < (filter->buf_width_blocks); xx++) {
+    bits = 0;
+    for (x = 0; x < 32; x++) {
+      ptr = (gint) (0.5 + RATIO * (xx * 32 + x - VIDEO_HWIDTH) + VIDEO_HWIDTH);
+      bits = bits >> 1;
+      if (ptr != prevptr)
+        bits |= 0x80000000;
+      prevptr = ptr;
+    }
+    filter->blurzoomx[xx] = bits;
+  }
+
+  ty = (gint) (0.5 + RATIO * (-VIDEO_HHEIGHT) + VIDEO_HHEIGHT);
+  tx = (gint) (0.5 + RATIO * (-VIDEO_HWIDTH) + VIDEO_HWIDTH);
+  xx = (gint) (0.5 + RATIO * (filter->buf_width - 1 - VIDEO_HWIDTH) +
+      VIDEO_HWIDTH);
+  filter->blurzoomy[0] = ty * filter->buf_width + tx;
+  prevptr = ty * filter->buf_width + xx;
+  for (y = 1; y < filter->buf_height; y++) {
+    ty = (gint) (0.5 + RATIO * (y - VIDEO_HHEIGHT) + VIDEO_HHEIGHT);
+    filter->blurzoomy[y] = ty * filter->buf_width + tx - prevptr;
+    prevptr = ty * filter->buf_width + xx;
+  }
+}
+
+#undef VIDEO_HWIDTH
+#undef VIDEO_HHEIGHT
+
+static void
+blur (GstRadioacTV * filter)
+{
+  gint x, y;
+  gint width;
+  guint8 *p, *q;
+  guint8 v;
+  GstVideoInfo *info;
+
+  info = &GST_VIDEO_FILTER (filter)->in_info;
+
+  width = filter->buf_width;
+  p = filter->blurzoombuf + GST_VIDEO_INFO_WIDTH (info) + 1;
+  q = p + filter->buf_area;
+
+  for (y = filter->buf_height - 2; y > 0; y--) {
+    for (x = width - 2; x > 0; x--) {
+      v = (*(p - width) + *(p - 1) + *(p + 1) + *(p + width)) / 4 - 1;
+      if (v == 255)
+        v = 0;
+      *q = v;
+      p++;
+      q++;
+    }
+    p += 2;
+    q += 2;
+  }
+}
+
+static void
+zoom (GstRadioacTV * filter)
+{
+  gint b, x, y;
+  guint8 *p, *q;
+  gint blocks, height;
+  gint dx;
+
+  p = filter->blurzoombuf + filter->buf_area;
+  q = filter->blurzoombuf;
+  height = filter->buf_height;
+  blocks = filter->buf_width_blocks;
+
+  for (y = 0; y < height; y++) {
+    p += filter->blurzoomy[y];
+    for (b = 0; b < blocks; b++) {
+      dx = filter->blurzoomx[b];
+      for (x = 0; x < 32; x++) {
+        p += (dx & 1);
+        *q++ = *p;
+        dx = dx >> 1;
+      }
+    }
+  }
+}
+
+static void
+blurzoomcore (GstRadioacTV * filter)
+{
+  blur (filter);
+  zoom (filter);
+}
+
+/* Background image is refreshed every frame */
+static void
+image_bgsubtract_update_y (guint32 * src, gint16 * background, guint8 * diff,
+    gint video_area, gint y_threshold)
+{
+  gint i;
+  gint R, G, B;
+  guint32 *p;
+  gint16 *q;
+  guint8 *r;
+  gint v;
+
+  p = src;
+  q = background;
+  r = diff;
+  for (i = 0; i < video_area; i++) {
+    R = ((*p) & 0xff0000) >> (16 - 1);
+    G = ((*p) & 0xff00) >> (8 - 2);
+    B = (*p) & 0xff;
+    v = (R + G + B) - (gint) (*q);
+    *q = (gint16) (R + G + B);
+    *r = ((v + y_threshold) >> 24) | ((y_threshold - v) >> 24);
+
+    p++;
+    q++;
+    r++;
+  }
+}
+
+static GstFlowReturn
+gst_radioactv_transform_frame (GstVideoFilter * vfilter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame)
+{
+  GstRadioacTV *filter = GST_RADIOACTV (vfilter);
+  guint32 *src, *dest;
+  GstClockTime timestamp, stream_time;
+  gint x, y, width, height;
+  guint32 a, b;
+  guint8 *diff, *p;
+  guint32 *palette;
+
+  timestamp = GST_BUFFER_TIMESTAMP (in_frame->buffer);
+  stream_time =
+      gst_segment_to_stream_time (&GST_BASE_TRANSFORM (filter)->segment,
+      GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (filter), stream_time);
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  GST_OBJECT_LOCK (filter);
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+  if (GST_VIDEO_FRAME_FORMAT (in_frame) == GST_VIDEO_FORMAT_RGBx) {
+    palette = &palettes[COLORS * filter->color];
+  } else {
+    palette = &palettes[COLORS * swap_tab[filter->color]];
+  }
+#else
+  if (GST_VIDEO_FRAME_FORMAT (in_frame) == GST_VIDEO_FORMAT_xBGR) {
+    palette = &palettes[COLORS * filter->color];
+  } else {
+    palette = &palettes[COLORS * swap_tab[filter->color]];
+  }
+#endif
+  diff = filter->diff;
+
+  if (filter->mode == 3 && filter->trigger)
+    filter->snaptime = 0;
+  else if (filter->mode == 3 && !filter->trigger)
+    filter->snaptime = 1;
+
+  if (filter->mode != 2 || filter->snaptime <= 0) {
+    image_bgsubtract_update_y (src, filter->background, diff,
+        width * height, MAGIC_THRESHOLD * 7);
+    if (filter->mode == 0 || filter->snaptime <= 0) {
+      diff += filter->buf_margin_left;
+      p = filter->blurzoombuf;
+      for (y = 0; y < filter->buf_height; y++) {
+        for (x = 0; x < filter->buf_width; x++) {
+          p[x] |= diff[x] >> 3;
+        }
+        diff += width;
+        p += filter->buf_width;
+      }
+      if (filter->mode == 1 || filter->mode == 2) {
+        memcpy (filter->snapframe, src, width * height * 4);
+      }
+    }
+  }
+  blurzoomcore (filter);
+
+  if (filter->mode == 1 || filter->mode == 2) {
+    src = filter->snapframe;
+  }
+  p = filter->blurzoombuf;
+  for (y = 0; y < height; y++) {
+    for (x = 0; x < filter->buf_margin_left; x++) {
+      *dest++ = *src++;
+    }
+    for (x = 0; x < filter->buf_width; x++) {
+      a = *src++ & 0xfefeff;
+      b = palette[*p++];
+      a += b;
+      b = a & 0x1010100;
+      *dest++ = a | (b - (b >> 8));
+    }
+    for (x = 0; x < filter->buf_margin_right; x++) {
+      *dest++ = *src++;
+    }
+  }
+
+  if (filter->mode == 1 || filter->mode == 2) {
+    filter->snaptime--;
+    if (filter->snaptime < 0) {
+      filter->snaptime = filter->interval;
+    }
+  }
+  GST_OBJECT_UNLOCK (filter);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_radioactv_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstRadioacTV *filter = GST_RADIOACTV (vfilter);
+  gint width, height;
+
+  width = GST_VIDEO_INFO_WIDTH (in_info);
+  height = GST_VIDEO_INFO_HEIGHT (in_info);
+
+  filter->buf_width_blocks = width / 32;
+  if (filter->buf_width_blocks > 255)
+    goto too_wide;
+
+  filter->buf_width = filter->buf_width_blocks * 32;
+  filter->buf_height = height;
+  filter->buf_area = filter->buf_height * filter->buf_width;
+  filter->buf_margin_left = (width - filter->buf_width) / 2;
+  filter->buf_margin_right =
+      height - filter->buf_width - filter->buf_margin_left;
+
+  g_free (filter->blurzoombuf);
+  filter->blurzoombuf = g_new0 (guint8, filter->buf_area * 2);
+
+  g_free (filter->blurzoomx);
+  filter->blurzoomx = g_new0 (gint, filter->buf_width);
+
+  g_free (filter->blurzoomy);
+  filter->blurzoomy = g_new0 (gint, filter->buf_height);
+
+  g_free (filter->snapframe);
+  filter->snapframe = g_new (guint32, width * height);
+
+  g_free (filter->diff);
+  filter->diff = g_new (guint8, width * height);
+
+  g_free (filter->background);
+  filter->background = g_new0 (gint16, width * height);
+
+  setTable (filter);
+
+  return TRUE;
+
+  /* ERRORS */
+too_wide:
+  {
+    GST_DEBUG_OBJECT (filter, "frame too wide");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_radioactv_start (GstBaseTransform * trans)
+{
+  GstRadioacTV *filter = GST_RADIOACTV (trans);
+
+  filter->snaptime = 0;
+
+  return TRUE;
+}
+
+static void
+gst_radioactv_finalize (GObject * object)
+{
+  GstRadioacTV *filter = GST_RADIOACTV (object);
+
+  g_free (filter->snapframe);
+  filter->snapframe = NULL;
+
+  g_free (filter->blurzoombuf);
+  filter->blurzoombuf = NULL;
+
+  g_free (filter->diff);
+  filter->diff = NULL;
+
+  g_free (filter->background);
+  filter->background = NULL;
+
+  g_free (filter->blurzoomx);
+  filter->blurzoomx = NULL;
+
+  g_free (filter->blurzoomy);
+  filter->blurzoomy = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_radioactv_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRadioacTV *filter = GST_RADIOACTV (object);
+
+  GST_OBJECT_LOCK (filter);
+  switch (prop_id) {
+    case PROP_MODE:
+      filter->mode = g_value_get_enum (value);
+      if (filter->mode == 3)
+        filter->snaptime = 1;
+      break;
+    case PROP_COLOR:
+      filter->color = g_value_get_enum (value);
+      break;
+    case PROP_INTERVAL:
+      filter->interval = g_value_get_uint (value);
+      break;
+    case PROP_TRIGGER:
+      filter->trigger = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (filter);
+}
+
+static void
+gst_radioactv_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRadioacTV *filter = GST_RADIOACTV (object);
+
+  switch (prop_id) {
+    case PROP_MODE:
+      g_value_set_enum (value, filter->mode);
+      break;
+    case PROP_COLOR:
+      g_value_set_enum (value, filter->color);
+      break;
+    case PROP_INTERVAL:
+      g_value_set_uint (value, filter->interval);
+      break;
+    case PROP_TRIGGER:
+      g_value_set_boolean (value, filter->trigger);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_radioactv_class_init (GstRadioacTVClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->set_property = gst_radioactv_set_property;
+  gobject_class->get_property = gst_radioactv_get_property;
+
+  gobject_class->finalize = gst_radioactv_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_MODE,
+      g_param_spec_enum ("mode", "Mode",
+          "Mode", GST_TYPE_RADIOACTV_MODE, DEFAULT_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_COLOR,
+      g_param_spec_enum ("color", "Color",
+          "Color", GST_TYPE_RADIOACTV_COLOR, DEFAULT_COLOR,
+          GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_INTERVAL,
+      g_param_spec_uint ("interval", "Interval",
+          "Snapshot interval (in strobe mode)", 0, G_MAXINT, DEFAULT_INTERVAL,
+          GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_TRIGGER,
+      g_param_spec_boolean ("trigger", "Trigger",
+          "Trigger (in trigger mode)", DEFAULT_TRIGGER,
+          GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class, "RadioacTV effect",
+      "Filter/Effect/Video",
+      "motion-enlightment effect",
+      "FUKUCHI, Kentarou <fukuchi@users.sourceforge.net>, "
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_radioactv_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_radioactv_src_template);
+
+  trans_class->start = GST_DEBUG_FUNCPTR (gst_radioactv_start);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_radioactv_set_info);
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_radioactv_transform_frame);
+
+  makePalette ();
+}
+
+static void
+gst_radioactv_init (GstRadioacTV * filter)
+{
+  filter->mode = DEFAULT_MODE;
+  filter->color = DEFAULT_COLOR;
+  filter->interval = DEFAULT_INTERVAL;
+  filter->trigger = DEFAULT_TRIGGER;
+}
diff --git a/gst/effectv/gstradioac.h b/gst/effectv/gstradioac.h
new file mode 100644
index 0000000..c8d7c99
--- /dev/null
+++ b/gst/effectv/gstradioac.h
@@ -0,0 +1,87 @@
+/* GStreamer
+ * Cradioacyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Cradioacyright (C) 2001-2006 FUKUCHI Kentaro
+ *
+ * RadioacTV - motion-enlightment effect.
+ * Copyright (C) 2001-2002 FUKUCHI Kentaro
+ *
+ * EffecTV is free software. 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 radioaction) any later version.
+ *
+ * This library is distributed in the hradioace 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 cradioacy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RADIOAC_H__
+#define __GST_RADIOAC_H__
+
+#include <gst/gst.h>
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RADIOACTV \
+  (gst_radioactv_get_type())
+#define GST_RADIOACTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RADIOACTV,GstRadioacTV))
+#define GST_RADIOACTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RADIOACTV,GstRadioacTVClass))
+#define GST_IS_RADIOACTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RADIOACTV))
+#define GST_IS_RADIOACTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RADIOACTV))
+
+typedef struct _GstRadioacTV GstRadioacTV;
+typedef struct _GstRadioacTVClass GstRadioacTVClass;
+
+struct _GstRadioacTV
+{
+  GstVideoFilter element;
+
+  /* < private > */
+  gint mode;
+  gint color;
+  guint interval;
+  gboolean trigger;
+
+  gint snaptime;
+
+  guint32 *snapframe;
+  guint8 *blurzoombuf;
+  guint8 *diff;
+  gint16 *background;
+  gint *blurzoomx;
+  gint *blurzoomy;
+
+  gint buf_width_blocks;
+  gint buf_width;
+  gint buf_height;
+  gint buf_area;
+  gint buf_margin_right;
+  gint buf_margin_left;
+};
+
+struct _GstRadioacTVClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_radioactv_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_RADIOAC_H__ */
diff --git a/gst/effectv/gstrev.c b/gst/effectv/gstrev.c
new file mode 100644
index 0000000..2f95950
--- /dev/null
+++ b/gst/effectv/gstrev.c
@@ -0,0 +1,249 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * EffecTV:
+ * Copyright (C) 2001 FUKUCHI Kentarou
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Copyright (C) 2001 FUKUCHI Kentarou
+ *
+ * revTV based on Rutt-Etra Video Synthesizer 1974?
+
+ * (c)2002 Ed Tannenbaum
+ *
+ * This effect acts like a waveform monitor on each line.
+ * It was originally done by deflecting the electron beam on a monitor using
+ * additional electromagnets on the yoke of a b/w CRT. 
+ * Here it is emulated digitally.
+
+ * Experimaental tapes were made with this system by Bill and 
+ * Louise Etra and Woody and Steina Vasulka
+
+ * The line spacing can be controlled using the 1 and 2 Keys.
+ * The gain is controlled using the 3 and 4 keys.
+ * The update rate is controlled using the 0 and - keys.
+ 
+ * EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-revtv
+ *
+ * RevTV acts like a video waveform monitor for each line of video
+ * processed. This creates a pseudo 3D effect based on the brightness
+ * of the video along each line.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! revtv ! videoconvert ! autovideosink
+ * ]| This pipeline shows the effect of revtv on a test stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <string.h>
+
+#include "gstrev.h"
+
+#define THE_COLOR 0xffffffff
+
+enum
+{
+  PROP_0,
+  PROP_DELAY,
+  PROP_LINESPACE,
+  PROP_GAIN
+};
+
+#define gst_revtv_parent_class parent_class
+G_DEFINE_TYPE (GstRevTV, gst_revtv, GST_TYPE_VIDEO_FILTER);
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ BGRx, RGBx }")
+#else
+#define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ xBGR, xRGB }")
+#endif
+
+static GstStaticPadTemplate gst_revtv_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (CAPS_STR)
+    );
+
+static GstStaticPadTemplate gst_revtv_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (CAPS_STR)
+    );
+
+static GstFlowReturn
+gst_revtv_transform_frame (GstVideoFilter * vfilter, GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame)
+{
+  GstRevTV *filter = GST_REVTV (vfilter);
+  guint32 *src, *dest;
+  gint width, height, sstride, dstride;
+  guint32 *nsrc;
+  gint y, x, R, G, B, yval;
+  gint linespace, vscale;
+  GstClockTime timestamp, stream_time;
+
+  timestamp = GST_BUFFER_TIMESTAMP (in_frame->buffer);
+  stream_time =
+      gst_segment_to_stream_time (&GST_BASE_TRANSFORM (vfilter)->segment,
+      GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (filter), stream_time);
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  sstride = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+  dstride = GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  /* Clear everything to black */
+  memset (dest, 0, dstride * height);
+
+  GST_OBJECT_LOCK (filter);
+  linespace = filter->linespace;
+  vscale = filter->vscale;
+
+  /* draw the offset lines */
+  for (y = 0; y < height; y += linespace) {
+    for (x = 0; x <= width; x++) {
+      nsrc = src + (y * sstride / 4) + x;
+
+      /* Calc Y Value for curpix */
+      R = ((*nsrc) & 0xff0000) >> (16 - 1);
+      G = ((*nsrc) & 0xff00) >> (8 - 2);
+      B = (*nsrc) & 0xff;
+
+      yval = y - ((short) (R + G + B) / vscale);
+
+      if (yval > 0) {
+        dest[x + (yval * dstride / 4)] = THE_COLOR;
+      }
+    }
+  }
+  GST_OBJECT_UNLOCK (filter);
+
+  return GST_FLOW_OK;
+}
+
+static void
+gst_revtv_set_property (GObject * object, guint prop_id, const GValue * value,
+    GParamSpec * pspec)
+{
+  GstRevTV *filter = GST_REVTV (object);
+
+  GST_OBJECT_LOCK (filter);
+  switch (prop_id) {
+    case PROP_DELAY:
+      filter->vgrabtime = g_value_get_int (value);
+      break;
+    case PROP_LINESPACE:
+      filter->linespace = g_value_get_int (value);
+      break;
+    case PROP_GAIN:
+      filter->vscale = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (filter);
+}
+
+static void
+gst_revtv_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstRevTV *filter = GST_REVTV (object);
+
+  switch (prop_id) {
+    case PROP_DELAY:
+      g_value_set_int (value, filter->vgrabtime);
+      break;
+    case PROP_LINESPACE:
+      g_value_set_int (value, filter->linespace);
+      break;
+    case PROP_GAIN:
+      g_value_set_int (value, filter->vscale);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_revtv_class_init (GstRevTVClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->set_property = gst_revtv_set_property;
+  gobject_class->get_property = gst_revtv_get_property;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DELAY,
+      g_param_spec_int ("delay", "Delay", "Delay in frames between updates",
+          1, 100, 1,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LINESPACE,
+      g_param_spec_int ("linespace", "Linespace", "Control line spacing", 1,
+          100, 6,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_GAIN,
+      g_param_spec_int ("gain", "Gain", "Control gain", 1, 200, 50,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  gst_element_class_set_static_metadata (gstelement_class, "RevTV effect",
+      "Filter/Effect/Video",
+      "A video waveform monitor for each line of video processed",
+      "Wim Taymans <wim.taymans@gmail.be>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_revtv_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_revtv_src_template);
+
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_revtv_transform_frame);
+}
+
+static void
+gst_revtv_init (GstRevTV * restv)
+{
+  restv->vgrabtime = 1;
+  restv->vgrab = 0;
+  restv->linespace = 6;
+  restv->vscale = 50;
+}
diff --git a/gst/effectv/gstrev.h b/gst/effectv/gstrev.h
new file mode 100644
index 0000000..198311b
--- /dev/null
+++ b/gst/effectv/gstrev.h
@@ -0,0 +1,87 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * EffecTV:
+ * Copyright (C) 2001 FUKUCHI Kentarou
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Copyright (C) 2001 FUKUCHI Kentarou
+ *
+ * revTV based on Rutt-Etra Video Synthesizer 1974?
+
+ * (c)2002 Ed Tannenbaum
+ *
+ * This effect acts like a waveform monitor on each line.
+ * It was originally done by deflecting the electron beam on a monitor using
+ * additional electromagnets on the yoke of a b/w CRT. 
+ * Here it is emulated digitally.
+
+ * Experimaental tapes were made with this system by Bill and 
+ * Louise Etra and Woody and Steina Vasulka
+
+ * The line spacing can be controlled using the 1 and 2 Keys.
+ * The gain is controlled using the 3 and 4 keys.
+ * The update rate is controlled using the 0 and - keys.
+ 
+ * EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_REV_H__
+#define __GST_REV_H__
+
+#include <gst/gst.h>
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_REVTV \
+  (gst_revtv_get_type())
+#define GST_REVTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_REVTV,GstRevTV))
+#define GST_REVTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_REVTV,GstRevTVClass))
+#define GST_IS_REVTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_REVTV))
+#define GST_IS_REVTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_REVTV))
+
+typedef struct _GstRevTV GstRevTV;
+typedef struct _GstRevTVClass GstRevTVClass;
+
+struct _GstRevTV
+{
+  GstVideoFilter videofilter;
+
+  /* < private > */
+  gint vgrabtime;
+  gint vgrab;
+  gint linespace;
+  gint vscale;
+};
+
+struct _GstRevTVClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_revtv_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_REV_H__ */
diff --git a/gst/effectv/gstripple.c b/gst/effectv/gstripple.c
new file mode 100644
index 0000000..a4ac6f7
--- /dev/null
+++ b/gst/effectv/gstripple.c
@@ -0,0 +1,611 @@
+/* GStreamer
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Copyright (C) 2001-2006 FUKUCHI Kentaro
+ *
+ * RippleTV - Water ripple effect.
+ * Copyright (C) 2001-2002 FUKUCHI Kentaro
+ *
+ * This combines the RippleTV and BaltanTV effects, which are
+ * very similar. BaltanTV is used if the feedback property is set
+ * to TRUE, otherwise RippleTV is used.
+ *
+ * EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rippletv
+ *
+ * RippleTV does ripple mark effect on the video input. The ripple is caused
+ * by motion or random rain drops.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! rippletv ! videoconvert ! autovideosink
+ * ]| This pipeline shows the effect of rippletv on a test stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <string.h>
+
+#include "gstripple.h"
+#include "gsteffectv.h"
+
+#define DEFAULT_MODE 0
+
+enum
+{
+  PROP_0,
+  PROP_RESET,
+  PROP_MODE
+};
+
+static gint sqrtable[256];
+
+#define GST_TYPE_RIPPLETV_MODE (gst_rippletv_mode_get_type())
+static GType
+gst_rippletv_mode_get_type (void)
+{
+  static GType type = 0;
+
+  static const GEnumValue enumvalue[] = {
+    {0, "Motion Detection", "motion-detection"},
+    {1, "Rain", "rain"},
+    {0, NULL, NULL},
+  };
+
+  if (!type) {
+    type = g_enum_register_static ("GstRippleTVMode", enumvalue);
+  }
+  return type;
+}
+
+#define gst_rippletv_parent_class parent_class
+G_DEFINE_TYPE (GstRippleTV, gst_rippletv, GST_TYPE_VIDEO_FILTER);
+
+static GstStaticPadTemplate gst_rippletv_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ BGRx, RGBx, xBGR, xRGB }"))
+    );
+
+static GstStaticPadTemplate gst_rippletv_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ BGRx, RGBx, xBGR, xRGB }"))
+    );
+
+static const gint point = 16;
+static const gint impact = 2;
+static const gint decay = 8;
+static const gint loopnum = 2;
+
+static void
+setTable (void)
+{
+  gint i;
+
+  for (i = 0; i < 128; i++) {
+    sqrtable[i] = i * i;
+  }
+  for (i = 1; i <= 128; i++) {
+    sqrtable[256 - i] = -i * i;
+  }
+}
+
+static void
+image_bgset_y (guint32 * src, gint16 * background, gint video_area)
+{
+  gint i;
+  gint R, G, B;
+  guint32 *p;
+  gint16 *q;
+
+  p = src;
+  q = background;
+  for (i = 0; i < video_area; i++) {
+    R = ((*p) & 0xff0000) >> (16 - 1);
+    G = ((*p) & 0xff00) >> (8 - 2);
+    B = (*p) & 0xff;
+    *q = (gint16) (R + G + B);
+    p++;
+    q++;
+  }
+}
+
+static gint
+setBackground (GstRippleTV * filter, guint32 * src)
+{
+  GstVideoInfo *info;
+
+  info = &GST_VIDEO_FILTER (filter)->in_info;
+
+  image_bgset_y (src, filter->background,
+      GST_VIDEO_INFO_WIDTH (info) * GST_VIDEO_INFO_HEIGHT (info));
+  filter->bg_is_set = TRUE;
+
+  return 0;
+}
+
+static void
+image_bgsubtract_update_y (guint32 * src, gint16 * background, guint8 * diff,
+    gint video_area)
+{
+  gint i;
+  gint R, G, B;
+  guint32 *p;
+  gint16 *q;
+  guint8 *r;
+  gint v;
+
+  p = src;
+  q = background;
+  r = diff;
+  for (i = 0; i < video_area; i++) {
+    R = ((*p) & 0xff0000) >> (16 - 1);
+    G = ((*p) & 0xff00) >> (8 - 2);
+    B = (*p) & 0xff;
+    v = (R + G + B) - (gint) (*q);
+    *q = (gint16) (R + G + B);
+    *r = ((v + 70 * 7) >> 24) | ((70 * 7 - v) >> 24);
+
+    p++;
+    q++;
+    r++;
+  }
+}
+
+static void
+motiondetect (GstRippleTV * filter, guint32 * src)
+{
+  guint8 *diff = filter->diff;
+  gint width, height;
+  gint *p, *q;
+  gint x, y, h;
+  GstVideoInfo *info;
+
+  info = &GST_VIDEO_FILTER (filter)->in_info;
+
+  width = GST_VIDEO_INFO_WIDTH (info);
+  height = GST_VIDEO_INFO_HEIGHT (info);
+
+  if (!filter->bg_is_set)
+    setBackground (filter, src);
+
+  image_bgsubtract_update_y (src, filter->background, filter->diff,
+      width * height);
+  p = filter->map1 + filter->map_w + 1;
+  q = filter->map2 + filter->map_w + 1;
+  diff += width + 2;
+
+  for (y = filter->map_h - 2; y > 0; y--) {
+    for (x = filter->map_w - 2; x > 0; x--) {
+      h = (gint) * diff + (gint) * (diff + 1) + (gint) * (diff + width) +
+          (gint) * (diff + width + 1);
+      if (h > 0) {
+        *p = h << (point + impact - 8);
+        *q = *p;
+      }
+      p++;
+      q++;
+      diff += 2;
+    }
+    diff += width + 2;
+    p += 2;
+    q += 2;
+  }
+}
+
+static inline void
+drop (gint power, gint * map1, gint * map2, gint map_w, gint map_h)
+{
+  gint x, y;
+  gint *p, *q;
+
+  x = fastrand () % (map_w - 4) + 2;
+  y = fastrand () % (map_h - 4) + 2;
+  p = map1 + y * map_w + x;
+  q = map2 + y * map_w + x;
+  *p = power;
+  *q = power;
+  *(p - map_w) = *(p - 1) = *(p + 1) = *(p + map_w) = power / 2;
+  *(p - map_w - 1) = *(p - map_w + 1) = *(p + map_w - 1) = *(p + map_w + 1) =
+      power / 4;
+  *(q - map_w) = *(q - 1) = *(q + 1) = *(q + map_w) = power / 2;
+  *(q - map_w - 1) = *(q - map_w + 1) = *(q + map_w - 1) = *(p + map_w + 1) =
+      power / 4;
+}
+
+static void
+raindrop (GstRippleTV * filter)
+{
+  gint i;
+
+  if (filter->period == 0) {
+    switch (filter->rain_stat) {
+      case 0:
+        filter->period = (fastrand () >> 23) + 100;
+        filter->drop_prob = 0;
+        filter->drop_prob_increment = 0x00ffffff / filter->period;
+        filter->drop_power = (-(fastrand () >> 28) - 2) << point;
+        filter->drops_per_frame_max = 2 << (fastrand () >> 30); // 2,4,8 or 16
+        filter->rain_stat = 1;
+        break;
+      case 1:
+        filter->drop_prob = 0x00ffffff;
+        filter->drops_per_frame = 1;
+        filter->drop_prob_increment = 1;
+        filter->period = (filter->drops_per_frame_max - 1) * 16;
+        filter->rain_stat = 2;
+        break;
+      case 2:
+        filter->period = (fastrand () >> 22) + 1000;
+        filter->drop_prob_increment = 0;
+        filter->rain_stat = 3;
+        break;
+      case 3:
+        filter->period = (filter->drops_per_frame_max - 1) * 16;
+        filter->drop_prob_increment = -1;
+        filter->rain_stat = 4;
+        break;
+      case 4:
+        filter->period = (fastrand () >> 24) + 60;
+        filter->drop_prob_increment = -(filter->drop_prob / filter->period);
+        filter->rain_stat = 5;
+        break;
+      case 5:
+      default:
+        filter->period = (fastrand () >> 23) + 500;
+        filter->drop_prob = 0;
+        filter->rain_stat = 0;
+        break;
+    }
+  }
+  switch (filter->rain_stat) {
+    default:
+    case 0:
+      break;
+    case 1:
+    case 5:
+      if ((fastrand () >> 8) < filter->drop_prob) {
+        drop (filter->drop_power, filter->map1, filter->map2, filter->map_w,
+            filter->map_h);
+      }
+      filter->drop_prob += filter->drop_prob_increment;
+      break;
+    case 2:
+    case 3:
+    case 4:
+      for (i = filter->drops_per_frame / 16; i > 0; i--) {
+        drop (filter->drop_power, filter->map1, filter->map2, filter->map_w,
+            filter->map_h);
+      }
+      filter->drops_per_frame += filter->drop_prob_increment;
+      break;
+  }
+  filter->period--;
+}
+
+static GstFlowReturn
+gst_rippletv_transform_frame (GstVideoFilter * vfilter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame)
+{
+  GstRippleTV *filter = GST_RIPPLETV (vfilter);
+  guint32 *src, *dest;
+  gint x, y, i;
+  gint dx, dy, o_dx;
+  gint h, v;
+  gint m_w, m_h, v_w, v_h;
+  gint *p, *q, *r;
+  gint8 *vp;
+  GstClockTime timestamp, stream_time;
+
+  timestamp = GST_BUFFER_TIMESTAMP (in_frame->buffer);
+  stream_time =
+      gst_segment_to_stream_time (&GST_BASE_TRANSFORM (vfilter)->segment,
+      GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (filter), stream_time);
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  GST_OBJECT_LOCK (filter);
+  /* impact from the motion or rain drop */
+  if (filter->mode)
+    raindrop (filter);
+  else
+    motiondetect (filter, src);
+
+  m_w = filter->map_w;
+  m_h = filter->map_h;
+  v_w = GST_VIDEO_FRAME_WIDTH (in_frame);
+  v_h = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  /* simulate surface wave */
+
+  /* This function is called only 30 times per second. To increase a speed
+   * of wave, iterates this loop several times. */
+  for (i = loopnum; i > 0; i--) {
+    /* wave simulation */
+    p = filter->map1 + m_w + 1;
+    q = filter->map2 + m_w + 1;
+    r = filter->map3 + m_w + 1;
+    for (y = m_h - 2; y > 0; y--) {
+      for (x = m_w - 2; x > 0; x--) {
+        h = *(p - m_w - 1) + *(p - m_w + 1) + *(p + m_w - 1) + *(p + m_w + 1)
+            + *(p - m_w) + *(p - 1) + *(p + 1) + *(p + m_w) - (*p) * 9;
+        h = h >> 3;
+        v = *p - *q;
+        v += h - (v >> decay);
+        *r = v + *p;
+        p++;
+        q++;
+        r++;
+      }
+      p += 2;
+      q += 2;
+      r += 2;
+    }
+
+    /* low pass filter */
+    p = filter->map3 + m_w + 1;
+    q = filter->map2 + m_w + 1;
+    for (y = m_h - 2; y > 0; y--) {
+      for (x = m_w - 2; x > 0; x--) {
+        h = *(p - m_w) + *(p - 1) + *(p + 1) + *(p + m_w) + (*p) * 60;
+        *q = h >> 6;
+        p++;
+        q++;
+      }
+      p += 2;
+      q += 2;
+    }
+
+    p = filter->map1;
+    filter->map1 = filter->map2;
+    filter->map2 = p;
+  }
+
+  vp = filter->vtable;
+  p = filter->map1;
+  for (y = m_h - 1; y > 0; y--) {
+    for (x = m_w - 1; x > 0; x--) {
+      /* difference of the height between two voxel. They are twiced to
+       * emphasise the wave. */
+      vp[0] = sqrtable[((p[0] - p[1]) >> (point - 1)) & 0xff];
+      vp[1] = sqrtable[((p[0] - p[m_w]) >> (point - 1)) & 0xff];
+      p++;
+      vp += 2;
+    }
+    p++;
+    vp += 2;
+  }
+
+  vp = filter->vtable;
+
+  /* draw refracted image. The vector table is stretched. */
+  for (y = 0; y < v_h; y += 2) {
+    for (x = 0; x < v_w; x += 2) {
+      h = (gint) vp[0];
+      v = (gint) vp[1];
+      dx = x + h;
+      dy = y + v;
+      dx = CLAMP (dx, 0, (v_w - 2));
+      dy = CLAMP (dy, 0, (v_h - 2));
+      dest[0] = src[dy * v_w + dx];
+
+      o_dx = dx;
+
+      dx = x + 1 + (h + (gint) vp[2]) / 2;
+      dx = CLAMP (dx, 0, (v_w - 2));
+      dest[1] = src[dy * v_w + dx];
+
+      dy = y + 1 + (v + (gint) vp[m_w * 2 + 1]) / 2;
+      dy = CLAMP (dy, 0, (v_h - 2));
+      dest[v_w] = src[dy * v_w + o_dx];
+
+      dest[v_w + 1] = src[dy * v_w + dx];
+      dest += 2;
+      vp += 2;
+    }
+    dest += v_w;
+    vp += 2;
+  }
+  GST_OBJECT_UNLOCK (filter);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_rippletv_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstRippleTV *filter = GST_RIPPLETV (vfilter);
+  gint width, height;
+
+  width = GST_VIDEO_INFO_WIDTH (in_info);
+  height = GST_VIDEO_INFO_HEIGHT (in_info);
+
+  GST_OBJECT_LOCK (filter);
+  filter->map_h = height / 2 + 1;
+  filter->map_w = width / 2 + 1;
+
+  /* we over allocate the buffers, as the render code does not handle clipping
+   * very well */
+  g_free (filter->map);
+  filter->map = g_new0 (gint, (1 + filter->map_h) * filter->map_w * 3);
+
+  filter->map1 = filter->map;
+  filter->map2 = filter->map + filter->map_w * filter->map_h;
+  filter->map3 = filter->map + filter->map_w * filter->map_h * 2;
+
+  g_free (filter->vtable);
+  filter->vtable = g_new0 (gint8, (1 + filter->map_h) * filter->map_w * 2);
+
+  g_free (filter->background);
+  filter->background = g_new0 (gint16, width * (height + 1));
+
+  g_free (filter->diff);
+  filter->diff = g_new0 (guint8, width * (height + 1));
+  GST_OBJECT_UNLOCK (filter);
+
+  return TRUE;
+}
+
+static gboolean
+gst_rippletv_start (GstBaseTransform * trans)
+{
+  GstRippleTV *filter = GST_RIPPLETV (trans);
+
+  filter->bg_is_set = FALSE;
+
+  filter->period = 0;
+  filter->rain_stat = 0;
+  filter->drop_prob = 0;
+  filter->drop_prob_increment = 0;
+  filter->drops_per_frame_max = 0;
+  filter->drops_per_frame = 0;
+  filter->drop_power = 0;
+
+  return TRUE;
+}
+
+static void
+gst_rippletv_finalize (GObject * object)
+{
+  GstRippleTV *filter = GST_RIPPLETV (object);
+
+  g_free (filter->map);
+  filter->map = NULL;
+
+  g_free (filter->vtable);
+  filter->vtable = NULL;
+
+  g_free (filter->background);
+  filter->background = NULL;
+
+  g_free (filter->diff);
+  filter->diff = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rippletv_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRippleTV *filter = GST_RIPPLETV (object);
+
+  GST_OBJECT_LOCK (filter);
+  switch (prop_id) {
+    case PROP_RESET:{
+      memset (filter->map, 0,
+          filter->map_h * filter->map_w * 2 * sizeof (gint));
+      break;
+    }
+    case PROP_MODE:
+      filter->mode = g_value_get_enum (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (filter);
+}
+
+static void
+gst_rippletv_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstRippleTV *filter = GST_RIPPLETV (object);
+
+  switch (prop_id) {
+    case PROP_MODE:
+      g_value_set_enum (value, filter->mode);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rippletv_class_init (GstRippleTVClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->set_property = gst_rippletv_set_property;
+  gobject_class->get_property = gst_rippletv_get_property;
+
+  gobject_class->finalize = gst_rippletv_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_RESET,
+      g_param_spec_boolean ("reset", "Reset",
+          "Reset all current ripples", FALSE,
+          G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  g_object_class_install_property (gobject_class, PROP_MODE,
+      g_param_spec_enum ("mode", "Mode",
+          "Mode", GST_TYPE_RIPPLETV_MODE, DEFAULT_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  gst_element_class_set_static_metadata (gstelement_class, "RippleTV effect",
+      "Filter/Effect/Video",
+      "RippleTV does ripple mark effect on the video input",
+      "FUKUCHI, Kentarou <fukuchi@users.sourceforge.net>, "
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rippletv_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rippletv_src_template);
+
+  trans_class->start = GST_DEBUG_FUNCPTR (gst_rippletv_start);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_rippletv_set_info);
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_rippletv_transform_frame);
+
+  setTable ();
+}
+
+static void
+gst_rippletv_init (GstRippleTV * filter)
+{
+  filter->mode = DEFAULT_MODE;
+
+  /* FIXME: remove this when memory corruption after resizes are fixed */
+  gst_pad_use_fixed_caps (GST_BASE_TRANSFORM_SRC_PAD (filter));
+  gst_pad_use_fixed_caps (GST_BASE_TRANSFORM_SINK_PAD (filter));
+}
diff --git a/gst/effectv/gstripple.h b/gst/effectv/gstripple.h
new file mode 100644
index 0000000..329e543
--- /dev/null
+++ b/gst/effectv/gstripple.h
@@ -0,0 +1,86 @@
+/* GStreamer
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Copyright (C) 2001-2006 FUKUCHI Kentaro
+ *
+ * RippleTV - Water ripple effect.
+ * Copyright (C) 2001-2002 FUKUCHI Kentaro
+ *
+ * EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RIPPLE_H__
+#define __GST_RIPPLE_H__
+
+#include <gst/gst.h>
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RIPPLETV \
+  (gst_rippletv_get_type())
+#define GST_RIPPLETV(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RIPPLETV,GstRippleTV))
+#define GST_RIPPLETV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RIPPLETV,GstRippleTVClass))
+#define GST_IS_RIPPLETV(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RIPPLETV))
+#define GST_IS_RIPPLETV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RIPPLETV))
+
+typedef struct _GstRippleTV GstRippleTV;
+typedef struct _GstRippleTVClass GstRippleTVClass;
+
+struct _GstRippleTV
+{
+  GstVideoFilter element;
+
+  /* < private > */
+  gint mode;
+
+  gint16 *background;
+  guint8 *diff;
+
+  gint *map, *map1, *map2, *map3;
+  gint map_h, map_w;
+
+  gint8 *vtable;
+
+  gboolean bg_is_set;
+
+  gint period;
+  gint rain_stat;
+  guint drop_prob;
+  gint drop_prob_increment;
+  gint drops_per_frame_max;
+  gint drops_per_frame;
+  gint drop_power;
+};
+
+struct _GstRippleTVClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_rippletv_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_RIPPLE_H__ */
diff --git a/gst/effectv/gstshagadelic.c b/gst/effectv/gstshagadelic.c
new file mode 100644
index 0000000..721a151
--- /dev/null
+++ b/gst/effectv/gstshagadelic.c
@@ -0,0 +1,256 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * EffecTV:
+ * Copyright (C) 2001 FUKUCHI Kentarou
+ *
+ * Inspired by Adrian Likin's script for the GIMP.
+ * EffecTV is free software.  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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-shagadelictv
+ *
+ * Oh behave, ShagedelicTV makes images shagadelic!
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! shagadelictv ! videoconvert ! autovideosink
+ * ]| This pipeline shows the effect of shagadelictv on a test stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <string.h>
+
+#include "gstshagadelic.h"
+#include "gsteffectv.h"
+
+#ifndef M_PI
+#define M_PI  3.14159265358979323846
+#endif
+
+#define gst_shagadelictv_parent_class parent_class
+G_DEFINE_TYPE (GstShagadelicTV, gst_shagadelictv, GST_TYPE_VIDEO_FILTER);
+
+static void gst_shagadelic_initialize (GstShagadelicTV * filter,
+    GstVideoInfo * in_info);
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define CAPS_STR GST_VIDEO_CAPS_MAKE ("BGRx")
+#else
+#define CAPS_STR GST_VIDEO_CAPS_MAKE ("xRGB")
+#endif
+
+static GstStaticPadTemplate gst_shagadelictv_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (CAPS_STR)
+    );
+
+static GstStaticPadTemplate gst_shagadelictv_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (CAPS_STR)
+    );
+
+static gboolean
+gst_shagadelictv_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstShagadelicTV *filter = GST_SHAGADELICTV (vfilter);
+  gint width, height, area;
+
+  width = GST_VIDEO_INFO_WIDTH (in_info);
+  height = GST_VIDEO_INFO_HEIGHT (in_info);
+
+  area = width * height;
+
+  g_free (filter->ripple);
+  g_free (filter->spiral);
+  filter->ripple = (guint8 *) g_malloc (area * 4);
+  filter->spiral = (guint8 *) g_malloc (area);
+
+  gst_shagadelic_initialize (filter, in_info);
+
+  return TRUE;
+}
+
+static void
+gst_shagadelic_initialize (GstShagadelicTV * filter, GstVideoInfo * info)
+{
+  int i, x, y;
+#ifdef PS2
+  float xx, yy;
+#else
+  double xx, yy;
+#endif
+  gint width, height;
+
+  width = GST_VIDEO_INFO_WIDTH (info);
+  height = GST_VIDEO_INFO_HEIGHT (info);
+
+  i = 0;
+  for (y = 0; y < height * 2; y++) {
+    yy = y - height;
+    yy *= yy;
+
+    for (x = 0; x < width * 2; x++) {
+      xx = x - width;
+#ifdef PS2
+      filter->ripple[i++] = ((unsigned int) (sqrtf (xx * xx + yy) * 8)) & 255;
+#else
+      filter->ripple[i++] = ((unsigned int) (sqrt (xx * xx + yy) * 8)) & 255;
+#endif
+    }
+  }
+
+  i = 0;
+  for (y = 0; y < height; y++) {
+    yy = y - height / 2;
+
+    for (x = 0; x < width; x++) {
+      xx = x - width / 2;
+#ifdef PS2
+      filter->spiral[i++] = ((unsigned int)
+          ((atan2f (xx,
+                      yy) / ((float) M_PI) * 256 * 9) + (sqrtf (xx * xx +
+                      yy * yy) * 5))) & 255;
+#else
+      filter->spiral[i++] = ((unsigned int)
+          ((atan2 (xx, yy) / M_PI * 256 * 9) + (sqrt (xx * xx +
+                      yy * yy) * 5))) & 255;
+#endif
+/* Here is another Swinger!
+ * ((atan2(xx, yy)/M_PI*256) + (sqrt(xx*xx+yy*yy)*10))&255;
+ */
+    }
+  }
+  filter->rx = fastrand () % width;
+  filter->ry = fastrand () % height;
+  filter->bx = fastrand () % width;
+  filter->by = fastrand () % height;
+  filter->rvx = -2;
+  filter->rvy = -2;
+  filter->bvx = 2;
+  filter->bvy = 2;
+  filter->phase = 0;
+}
+
+static GstFlowReturn
+gst_shagadelictv_transform_frame (GstVideoFilter * vfilter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame)
+{
+  GstShagadelicTV *filter = GST_SHAGADELICTV (vfilter);
+  guint32 *src, *dest;
+  gint x, y;
+  guint32 v;
+  guint8 r, g, b;
+  gint width, height;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  for (y = 0; y < height; y++) {
+    for (x = 0; x < width; x++) {
+      v = *src++ | 0x1010100;
+      v = (v - 0x707060) & 0x1010100;
+      v -= v >> 8;
+/* Try another Babe! 
+ * v = *src++;
+ * *dest++ = v & ((r<<16)|(g<<8)|b);
+ */
+      r = ((gint8) (filter->ripple[(filter->ry + y) * width * 2 + filter->rx +
+                  x] + filter->phase * 2)) >> 7;
+      g = ((gint8) (filter->spiral[y * width + x] + filter->phase * 3)) >> 7;
+      b = ((gint8) (filter->ripple[(filter->by + y) * width * 2 + filter->bx +
+                  x] - filter->phase)) >> 7;
+      *dest++ = v & ((r << 16) | (g << 8) | b);
+    }
+  }
+
+  filter->phase -= 8;
+  if ((filter->rx + filter->rvx) < 0 || (filter->rx + filter->rvx) >= width)
+    filter->rvx = -filter->rvx;
+  if ((filter->ry + filter->rvy) < 0 || (filter->ry + filter->rvy) >= height)
+    filter->rvy = -filter->rvy;
+  if ((filter->bx + filter->bvx) < 0 || (filter->bx + filter->bvx) >= width)
+    filter->bvx = -filter->bvx;
+  if ((filter->by + filter->bvy) < 0 || (filter->by + filter->bvy) >= height)
+    filter->bvy = -filter->bvy;
+  filter->rx += filter->rvx;
+  filter->ry += filter->rvy;
+  filter->bx += filter->bvx;
+  filter->by += filter->bvy;
+
+  return GST_FLOW_OK;
+}
+
+static void
+gst_shagadelictv_finalize (GObject * object)
+{
+  GstShagadelicTV *filter = GST_SHAGADELICTV (object);
+
+  g_free (filter->ripple);
+  filter->ripple = NULL;
+
+  g_free (filter->spiral);
+  filter->spiral = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_shagadelictv_class_init (GstShagadelicTVClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->finalize = gst_shagadelictv_finalize;
+
+  gst_element_class_set_static_metadata (gstelement_class, "ShagadelicTV",
+      "Filter/Effect/Video",
+      "Oh behave, ShagedelicTV makes images shagadelic!",
+      "Wim Taymans <wim.taymans@chello.be>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_shagadelictv_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_shagadelictv_src_template);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_shagadelictv_set_info);
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_shagadelictv_transform_frame);
+}
+
+static void
+gst_shagadelictv_init (GstShagadelicTV * filter)
+{
+  filter->ripple = NULL;
+  filter->spiral = NULL;
+}
diff --git a/gst/effectv/gstshagadelic.h b/gst/effectv/gstshagadelic.h
new file mode 100644
index 0000000..a89cbf4
--- /dev/null
+++ b/gst/effectv/gstshagadelic.h
@@ -0,0 +1,72 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * EffecTV:
+ * Copyright (C) 2001 FUKUCHI Kentarou
+ *
+ * Inspired by Adrian Likin's script for the GIMP.
+ * EffecTV is free software.  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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_SHAGADELIC_H__
+#define __GST_SHAGADELIC_H__
+
+#include <gst/gst.h>
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SHAGADELICTV \
+  (gst_shagadelictv_get_type())
+#define GST_SHAGADELICTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SHAGADELICTV,GstShagadelicTV))
+#define GST_SHAGADELICTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SHAGADELICTV,GstShagadelicTVClass))
+#define GST_IS_SHAGADELICTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SHAGADELICTV))
+#define GST_IS_SHAGADELICTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SHAGADELICTV))
+
+typedef struct _GstShagadelicTV GstShagadelicTV;
+typedef struct _GstShagadelicTVClass GstShagadelicTVClass;
+
+struct _GstShagadelicTV
+{
+  GstVideoFilter videofilter;
+
+  /* < private > */
+  guint8 *ripple;
+  guint8 *spiral;
+  guint8 phase;
+  gint rx, ry;
+  gint bx, by;
+  gint rvx, rvy;
+  gint bvx, bvy;
+};
+
+struct _GstShagadelicTVClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_shagadelictv_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_SHAGADELIC_H__ */
diff --git a/gst/effectv/gststreak.c b/gst/effectv/gststreak.c
new file mode 100644
index 0000000..44ed150
--- /dev/null
+++ b/gst/effectv/gststreak.c
@@ -0,0 +1,265 @@
+/* GStreamer
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Copyright (C) 2001-2006 FUKUCHI Kentaro
+ *
+ * StreakTV - afterimage effector.
+ * Copyright (C) 2001-2002 FUKUCHI Kentaro
+ *
+ * This combines the StreakTV and BaltanTV effects, which are
+ * very similar. BaltanTV is used if the feedback property is set
+ * to TRUE, otherwise StreakTV is used.
+ *
+ * EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-streaktv
+ *
+ * StreakTV makes after images of moving objects.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! streaktv ! videoconvert ! autovideosink
+ * ]| This pipeline shows the effect of streaktv on a test stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <string.h>
+
+#include "gststreak.h"
+#include "gsteffectv.h"
+
+#define DEFAULT_FEEDBACK FALSE
+
+enum
+{
+  PROP_0,
+  PROP_FEEDBACK
+};
+
+#define gst_streaktv_parent_class parent_class
+G_DEFINE_TYPE (GstStreakTV, gst_streaktv, GST_TYPE_VIDEO_FILTER);
+
+static GstStaticPadTemplate gst_streaktv_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ BGRx, RGBx, xBGR, xRGB }"))
+    );
+
+static GstStaticPadTemplate gst_streaktv_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ BGRx, RGBx, xBGR, xRGB }"))
+    );
+
+
+static GstFlowReturn
+gst_streaktv_transform_frame (GstVideoFilter * vfilter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame)
+{
+  GstStreakTV *filter = GST_STREAKTV (vfilter);
+  guint32 *src, *dest;
+  gint i, cf;
+  gint video_area, width, height;
+  guint32 **planetable = filter->planetable;
+  gint plane = filter->plane;
+  guint stride_mask, stride_shift, stride;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  video_area = width * height;
+
+  GST_OBJECT_LOCK (filter);
+  if (filter->feedback) {
+    stride_mask = 0xfcfcfcfc;
+    stride = 8;
+    stride_shift = 2;
+  } else {
+    stride_mask = 0xf8f8f8f8;
+    stride = 4;
+    stride_shift = 3;
+  }
+
+  for (i = 0; i < video_area; i++) {
+    planetable[plane][i] = (src[i] & stride_mask) >> stride_shift;
+  }
+
+  cf = plane & (stride - 1);
+  if (filter->feedback) {
+    for (i = 0; i < video_area; i++) {
+      dest[i] = planetable[cf][i]
+          + planetable[cf + stride][i]
+          + planetable[cf + stride * 2][i]
+          + planetable[cf + stride * 3][i];
+      planetable[plane][i] = (dest[i] & stride_mask) >> stride_shift;
+    }
+  } else {
+    for (i = 0; i < video_area; i++) {
+      dest[i] = planetable[cf][i]
+          + planetable[cf + stride][i]
+          + planetable[cf + stride * 2][i]
+          + planetable[cf + stride * 3][i]
+          + planetable[cf + stride * 4][i]
+          + planetable[cf + stride * 5][i]
+          + planetable[cf + stride * 6][i]
+          + planetable[cf + stride * 7][i];
+    }
+  }
+
+  plane++;
+  filter->plane = plane & (PLANES - 1);
+  GST_OBJECT_UNLOCK (filter);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_streaktv_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstStreakTV *filter = GST_STREAKTV (vfilter);
+  gint i, width, height;
+
+  width = GST_VIDEO_INFO_WIDTH (in_info);
+  height = GST_VIDEO_INFO_HEIGHT (in_info);
+
+  g_free (filter->planebuffer);
+
+  filter->planebuffer = g_new0 (guint32, width * height * 4 * PLANES);
+
+  for (i = 0; i < PLANES; i++)
+    filter->planetable[i] = &filter->planebuffer[width * height * i];
+
+  return TRUE;
+}
+
+static gboolean
+gst_streaktv_start (GstBaseTransform * trans)
+{
+  GstStreakTV *filter = GST_STREAKTV (trans);
+
+  filter->plane = 0;
+
+  return TRUE;
+}
+
+static void
+gst_streaktv_finalize (GObject * object)
+{
+  GstStreakTV *filter = GST_STREAKTV (object);
+
+  if (filter->planebuffer) {
+    g_free (filter->planebuffer);
+    filter->planebuffer = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_streaktv_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstStreakTV *filter = GST_STREAKTV (object);
+
+  switch (prop_id) {
+    case PROP_FEEDBACK:
+      if (G_UNLIKELY (GST_STATE (filter) >= GST_STATE_PAUSED)) {
+        g_warning ("Changing the \"feedback\" property only allowed "
+            "in state < PLAYING");
+        return;
+      }
+
+      filter->feedback = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_streaktv_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstStreakTV *filter = GST_STREAKTV (object);
+
+  switch (prop_id) {
+    case PROP_FEEDBACK:
+      g_value_set_boolean (value, filter->feedback);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_streaktv_class_init (GstStreakTVClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->set_property = gst_streaktv_set_property;
+  gobject_class->get_property = gst_streaktv_get_property;
+
+  gobject_class->finalize = gst_streaktv_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_FEEDBACK,
+      g_param_spec_boolean ("feedback", "Feedback",
+          "Feedback", DEFAULT_FEEDBACK,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class, "StreakTV effect",
+      "Filter/Effect/Video",
+      "StreakTV makes after images of moving objects",
+      "FUKUCHI, Kentarou <fukuchi@users.sourceforge.net>, "
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_streaktv_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_streaktv_src_template);
+
+  trans_class->start = GST_DEBUG_FUNCPTR (gst_streaktv_start);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_streaktv_set_info);
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_streaktv_transform_frame);
+}
+
+static void
+gst_streaktv_init (GstStreakTV * filter)
+{
+  filter->feedback = DEFAULT_FEEDBACK;
+}
diff --git a/gst/effectv/gststreak.h b/gst/effectv/gststreak.h
new file mode 100644
index 0000000..5d9362d
--- /dev/null
+++ b/gst/effectv/gststreak.h
@@ -0,0 +1,74 @@
+/* GStreamer
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Copyright (C) 2001-2006 FUKUCHI Kentaro
+ *
+ * StreakTV - afterimage effector.
+ * Copyright (C) 2001-2002 FUKUCHI Kentaro
+ *
+ * EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_STREAK_H__
+#define __GST_STREAK_H__
+
+#include <gst/gst.h>
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_STREAKTV \
+  (gst_streaktv_get_type())
+#define GST_STREAKTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_STREAKTV,GstStreakTV))
+#define GST_STREAKTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_STREAKTV,GstStreakTVClass))
+#define GST_IS_STREAKTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_STREAKTV))
+#define GST_IS_STREAKTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_STREAKTV))
+
+typedef struct _GstStreakTV GstStreakTV;
+typedef struct _GstStreakTVClass GstStreakTVClass;
+
+#define PLANES 32
+
+struct _GstStreakTV
+{
+  GstVideoFilter element;
+
+  /* < private > */
+  gboolean feedback;
+
+  guint32 *planebuffer;
+  guint32 *planetable[PLANES];
+  gint plane;
+};
+
+struct _GstStreakTVClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_streaktv_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_STREAK_H__ */
diff --git a/gst/effectv/gstvertigo.c b/gst/effectv/gstvertigo.c
new file mode 100644
index 0000000..f49a7d2
--- /dev/null
+++ b/gst/effectv/gstvertigo.c
@@ -0,0 +1,327 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * EffecTV:
+ * Copyright (C) 2001 FUKUCHI Kentarou
+ *
+ * EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-vertigotv
+ *
+ * VertigoTV is a loopback alpha blending effector with rotating and scaling.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! vertigotv ! videoconvert ! autovideosink
+ * ]| This pipeline shows the effect of vertigotv on a test stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <string.h>
+
+#include "gstvertigo.h"
+
+#define gst_vertigotv_parent_class parent_class
+G_DEFINE_TYPE (GstVertigoTV, gst_vertigotv, GST_TYPE_VIDEO_FILTER);
+
+/* Filter signals and args */
+enum
+{
+  PROP_0,
+  PROP_SPEED,
+  PROP_ZOOM_SPEED
+};
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ RGBx, BGRx }")
+#else
+#define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ xRGB, xBGR }")
+#endif
+
+static GstStaticPadTemplate gst_vertigotv_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (CAPS_STR)
+    );
+
+static GstStaticPadTemplate gst_vertigotv_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (CAPS_STR)
+    );
+
+static gboolean
+gst_vertigotv_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstVertigoTV *filter = GST_VERTIGOTV (vfilter);
+  gint area, width, height;
+
+  width = GST_VIDEO_INFO_WIDTH (in_info);
+  height = GST_VIDEO_INFO_HEIGHT (in_info);
+
+  area = width * height;
+
+  g_free (filter->buffer);
+  filter->buffer = (guint32 *) g_malloc0 (area * 2 * sizeof (guint32));
+
+  filter->current_buffer = filter->buffer;
+  filter->alt_buffer = filter->buffer + area;
+  filter->phase = 0;
+
+  return TRUE;
+}
+
+static void
+gst_vertigotv_set_parms (GstVertigoTV * filter)
+{
+  double vx, vy;
+  double t;
+  double x, y;
+  double dizz;
+  gint width, height;
+  GstVideoInfo *info;
+
+  dizz = sin (filter->phase) * 10 + sin (filter->phase * 1.9 + 5) * 5;
+
+  info = &GST_VIDEO_FILTER (filter)->in_info;
+
+  width = GST_VIDEO_INFO_WIDTH (info);
+  height = GST_VIDEO_INFO_HEIGHT (info);
+
+  x = width / 2;
+  y = height / 2;
+
+  t = (x * x + y * y) * filter->zoomrate;
+
+  if (width > height) {
+    if (dizz >= 0) {
+      if (dizz > x)
+        dizz = x;
+      vx = (x * (x - dizz) + y * y) / t;
+    } else {
+      if (dizz < -x)
+        dizz = -x;
+      vx = (x * (x + dizz) + y * y) / t;
+    }
+    vy = (dizz * y) / t;
+  } else {
+    if (dizz >= 0) {
+      if (dizz > y)
+        dizz = y;
+      vx = (x * x + y * (y - dizz)) / t;
+    } else {
+      if (dizz < -y)
+        dizz = -y;
+      vx = (x * x + y * (y + dizz)) / t;
+    }
+    vy = (dizz * x) / t;
+  }
+  filter->dx = vx * 65536;
+  filter->dy = vy * 65536;
+  filter->sx = (-vx * x + vy * y + x + cos (filter->phase * 5) * 2) * 65536;
+  filter->sy = (-vx * y - vy * x + y + sin (filter->phase * 6) * 2) * 65536;
+
+  filter->phase += filter->phase_increment;
+  if (filter->phase > 5700000)
+    filter->phase = 0;
+}
+
+static GstFlowReturn
+gst_vertigotv_transform_frame (GstVideoFilter * vfilter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame)
+{
+  GstVertigoTV *filter = GST_VERTIGOTV (vfilter);
+  guint32 *src, *dest, *p;
+  guint32 v;
+  gint x, y, ox, oy, i, width, height, area, sstride, dstride;
+  GstClockTime timestamp, stream_time;
+
+  timestamp = GST_BUFFER_TIMESTAMP (in_frame->buffer);
+  stream_time =
+      gst_segment_to_stream_time (&GST_BASE_TRANSFORM (filter)->segment,
+      GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (filter), stream_time);
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  sstride = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+  dstride = GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  area = width * height;
+
+  sstride /= 4;
+  dstride /= 4;
+
+  gst_vertigotv_set_parms (filter);
+  p = filter->alt_buffer;
+
+  for (y = 0; y < height; y++) {
+    ox = filter->sx;
+    oy = filter->sy;
+
+    for (x = 0; x < width; x++) {
+      i = (oy >> 16) * width + (ox >> 16);
+      if (i < 0)
+        i = 0;
+      if (i >= area)
+        i = area;
+
+      v = filter->current_buffer[i] & 0xfcfcff;
+      v = (v * 3) + (src[x] & 0xfcfcff);
+
+      *p++ = dest[x] = (v >> 2);
+      ox += filter->dx;
+      oy += filter->dy;
+    }
+    filter->sx -= filter->dy;
+    filter->sy += filter->dx;
+
+    src += sstride;
+    dest += dstride;
+  }
+
+  p = filter->current_buffer;
+  filter->current_buffer = filter->alt_buffer;
+  filter->alt_buffer = p;
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_vertigotv_start (GstBaseTransform * trans)
+{
+  GstVertigoTV *filter = GST_VERTIGOTV (trans);
+
+  filter->phase = 0.0;
+
+  return TRUE;
+}
+
+static void
+gst_vertigotv_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVertigoTV *filter = GST_VERTIGOTV (object);
+
+  GST_OBJECT_LOCK (filter);
+  switch (prop_id) {
+    case PROP_SPEED:
+      filter->phase_increment = g_value_get_float (value);
+      break;
+    case PROP_ZOOM_SPEED:
+      filter->zoomrate = g_value_get_float (value);
+      break;
+    default:
+      break;
+  }
+  GST_OBJECT_UNLOCK (filter);
+}
+
+static void
+gst_vertigotv_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstVertigoTV *filter = GST_VERTIGOTV (object);
+
+  switch (prop_id) {
+    case PROP_SPEED:
+      g_value_set_float (value, filter->phase_increment);
+      break;
+    case PROP_ZOOM_SPEED:
+      g_value_set_float (value, filter->zoomrate);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_vertigotv_finalize (GObject * object)
+{
+  GstVertigoTV *filter = GST_VERTIGOTV (object);
+
+  g_free (filter->buffer);
+  filter->buffer = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_vertigotv_class_init (GstVertigoTVClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->set_property = gst_vertigotv_set_property;
+  gobject_class->get_property = gst_vertigotv_get_property;
+  gobject_class->finalize = gst_vertigotv_finalize;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SPEED,
+      g_param_spec_float ("speed", "Speed", "Control the speed of movement",
+          0.01, 100.0, 0.02, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ZOOM_SPEED,
+      g_param_spec_float ("zoom-speed", "Zoom Speed",
+          "Control the rate of zooming", 1.01, 1.1, 1.01,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class, "VertigoTV effect",
+      "Filter/Effect/Video",
+      "A loopback alpha blending effector with rotating and scaling",
+      "Wim Taymans <wim.taymans@gmail.be>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_vertigotv_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_vertigotv_src_template);
+
+  trans_class->start = GST_DEBUG_FUNCPTR (gst_vertigotv_start);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_vertigotv_set_info);
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_vertigotv_transform_frame);
+}
+
+static void
+gst_vertigotv_init (GstVertigoTV * filter)
+{
+  filter->buffer = NULL;
+  filter->phase = 0.0;
+  filter->phase_increment = 0.02;
+  filter->zoomrate = 1.01;
+}
diff --git a/gst/effectv/gstvertigo.h b/gst/effectv/gstvertigo.h
new file mode 100644
index 0000000..39c225b
--- /dev/null
+++ b/gst/effectv/gstvertigo.h
@@ -0,0 +1,71 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * EffecTV:
+ * Copyright (C) 2001 FUKUCHI Kentarou
+ *
+ * EffecTV is free software. 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_VERTIGO_H__
+#define __GST_VERTIGO_H__
+
+#include <gst/gst.h>
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VERTIGOTV \
+  (gst_vertigotv_get_type())
+#define GST_VERTIGOTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VERTIGOTV,GstVertigoTV))
+#define GST_VERTIGOTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VERTIGOTV,GstVertigoTVClass))
+#define GST_IS_VERTIGOTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VERTIGOTV))
+#define GST_IS_VERTIGOTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VERTIGOTV))
+
+typedef struct _GstVertigoTV GstVertigoTV;
+typedef struct _GstVertigoTVClass GstVertigoTVClass;
+
+struct _GstVertigoTV
+{
+  GstVideoFilter videofilter;
+
+  /* < private > */
+  guint32 *buffer;
+  guint32 *current_buffer, *alt_buffer;
+  gint dx, dy;
+  gint sx, sy;
+  gdouble phase;
+  gdouble phase_increment;
+  gdouble zoomrate;
+};
+
+struct _GstVertigoTVClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_vertigotv_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_VERTIGO_H__ */
diff --git a/gst/effectv/gstwarp.c b/gst/effectv/gstwarp.c
new file mode 100644
index 0000000..841ed8c
--- /dev/null
+++ b/gst/effectv/gstwarp.c
@@ -0,0 +1,266 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Copyright (C) 2001 FUKUCHI Kentarou
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * This file was (probably) generated from gstvideotemplate.c,
+ * gstvideotemplate.c,v 1.11 2004/01/07 08:56:45 ds Exp 
+ */
+
+/* From main.c of warp-1.1:
+ *
+ *      Simple DirectMedia Layer demo
+ *      Realtime picture 'gooing'
+ *      by sam lantinga slouken@devolution.com
+ */
+
+/**
+ * SECTION:element-warptv
+ *
+ * WarpTV does realtime goo'ing of the video input.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! warptv ! videoconvert ! autovideosink
+ * ]| This pipeline shows the effect of warptv on a test stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <math.h>
+
+#include "gstwarp.h"
+#include <gst/video/gstvideometa.h>
+#include <gst/video/gstvideopool.h>
+
+#ifndef M_PI
+#define M_PI    3.14159265358979323846
+#endif
+
+#define gst_warptv_parent_class parent_class
+G_DEFINE_TYPE (GstWarpTV, gst_warptv, GST_TYPE_VIDEO_FILTER);
+
+static void initSinTable ();
+static void initDistTable (GstWarpTV * filter, gint width, gint height);
+
+static GstStaticPadTemplate gst_warptv_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBx, xRGB, BGRx, xBGR }"))
+    );
+
+static GstStaticPadTemplate gst_warptv_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBx, xRGB, BGRx, xBGR }"))
+    );
+
+static gboolean
+gst_warptv_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstWarpTV *filter = GST_WARPTV (vfilter);
+  gint width, height;
+
+  width = GST_VIDEO_INFO_WIDTH (in_info);
+  height = GST_VIDEO_INFO_HEIGHT (in_info);
+
+  g_free (filter->disttable);
+  filter->disttable = g_malloc (width * height * sizeof (guint32));
+  initDistTable (filter, width, height);
+
+  return TRUE;
+}
+
+static gint32 sintable[1024 + 256];
+
+static void
+initSinTable (void)
+{
+  gint32 *tptr, *tsinptr;
+  gint i;
+
+  tsinptr = tptr = sintable;
+
+  for (i = 0; i < 1024; i++)
+    *tptr++ = (int) (sin (i * M_PI / 512) * 32767);
+
+  for (i = 0; i < 256; i++)
+    *tptr++ = *tsinptr++;
+}
+
+static void
+initDistTable (GstWarpTV * filter, gint width, gint height)
+{
+  gint32 halfw, halfh, *distptr;
+  gint x, y;
+  float m;
+
+  halfw = width >> 1;
+  halfh = height >> 1;
+
+  distptr = filter->disttable;
+
+  m = sqrt ((double) (halfw * halfw + halfh * halfh));
+
+  for (y = -halfh; y < halfh; y++)
+    for (x = -halfw; x < halfw; x++)
+#ifdef PS2
+      *distptr++ = ((int) ((sqrtf (x * x + y * y) * 511.9999) / m)) << 1;
+#else
+      *distptr++ = ((int) ((sqrt (x * x + y * y) * 511.9999) / m)) << 1;
+#endif
+}
+
+static GstFlowReturn
+gst_warptv_transform_frame (GstVideoFilter * filter, GstVideoFrame * in_frame,
+    GstVideoFrame * out_frame)
+{
+  GstWarpTV *warptv = GST_WARPTV (filter);
+  gint width, height;
+  gint xw, yw, cw;
+  gint32 c, i, x, y, dx, dy, maxx, maxy;
+  gint32 *ctptr, *distptr;
+  gint32 *ctable;
+  guint32 *src, *dest;
+  gint sstride, dstride;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  sstride = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0);
+  dstride = GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0);
+
+  width = GST_VIDEO_FRAME_WIDTH (in_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (in_frame);
+
+  GST_OBJECT_LOCK (warptv);
+  xw = (gint) (sin ((warptv->tval + 100) * M_PI / 128) * 30);
+  yw = (gint) (sin ((warptv->tval) * M_PI / 256) * -35);
+  cw = (gint) (sin ((warptv->tval - 70) * M_PI / 64) * 50);
+  xw += (gint) (sin ((warptv->tval - 10) * M_PI / 512) * 40);
+  yw += (gint) (sin ((warptv->tval + 30) * M_PI / 512) * 40);
+
+  ctptr = warptv->ctable;
+  distptr = warptv->disttable;
+  ctable = warptv->ctable;
+
+  c = 0;
+
+  for (x = 0; x < 512; x++) {
+    i = (c >> 3) & 0x3FE;
+    *ctptr++ = ((sintable[i] * yw) >> 15);
+    *ctptr++ = ((sintable[i + 256] * xw) >> 15);
+    c += cw;
+  }
+  maxx = width - 2;
+  maxy = height - 2;
+
+  for (y = 0; y < height - 1; y++) {
+    for (x = 0; x < width; x++) {
+      i = *distptr++;
+      dx = ctable[i + 1] + x;
+      dy = ctable[i] + y;
+
+      if (dx < 0)
+        dx = 0;
+      else if (dx > maxx)
+        dx = maxx;
+
+      if (dy < 0)
+        dy = 0;
+      else if (dy > maxy)
+        dy = maxy;
+
+      dest[x] = src[dy * sstride / 4 + dx];
+    }
+    dest += dstride / 4;
+  }
+
+  warptv->tval = (warptv->tval + 1) & 511;
+  GST_OBJECT_UNLOCK (warptv);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_warptv_start (GstBaseTransform * trans)
+{
+  GstWarpTV *warptv = GST_WARPTV (trans);
+
+  warptv->tval = 0;
+
+  return TRUE;
+}
+
+static void
+gst_warptv_finalize (GObject * object)
+{
+  GstWarpTV *warptv = GST_WARPTV (object);
+
+  g_free (warptv->disttable);
+  warptv->disttable = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_warptv_class_init (GstWarpTVClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->finalize = gst_warptv_finalize;
+
+  gst_element_class_set_static_metadata (gstelement_class, "WarpTV effect",
+      "Filter/Effect/Video",
+      "WarpTV does realtime goo'ing of the video input",
+      "Sam Lantinga <slouken@devolution.com>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_warptv_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_warptv_src_template);
+
+  trans_class->start = GST_DEBUG_FUNCPTR (gst_warptv_start);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_warptv_set_info);
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_warptv_transform_frame);
+
+  initSinTable ();
+}
+
+static void
+gst_warptv_init (GstWarpTV * warptv)
+{
+  /* nothing to do */
+}
diff --git a/gst/effectv/gstwarp.h b/gst/effectv/gstwarp.h
new file mode 100644
index 0000000..73eeebc
--- /dev/null
+++ b/gst/effectv/gstwarp.h
@@ -0,0 +1,67 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Copyright (C) 2001 FUKUCHI Kentarou
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_WARP_H__
+#define __GST_WARP_H__
+
+#include <gst/gst.h>
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_WARPTV \
+  (gst_warptv_get_type())
+#define GST_WARPTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WARPTV,GstWarpTV))
+#define GST_WARPTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WARPTV,GstWarpTVClass))
+#define GST_IS_WARPTV(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WARPTV))
+#define GST_IS_WARPTV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WARPTV))
+
+typedef struct _GstWarpTV GstWarpTV;
+typedef struct _GstWarpTVClass GstWarpTVClass;
+
+struct _GstWarpTV
+{
+  GstVideoFilter videofilter;
+
+  /* < private > */
+  gint32 *disttable;
+  gint32 ctable[1024];
+  gint tval;
+};
+
+struct _GstWarpTVClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_warptv_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_WARP_H__ */
diff --git a/gst/effectv/meson.build b/gst/effectv/meson.build
new file mode 100644
index 0000000..69d97e0
--- /dev/null
+++ b/gst/effectv/meson.build
@@ -0,0 +1,14 @@
+effect_sources = [
+  'gsteffectv.c', 'gstedge.c', 'gstaging.c', 'gstdice.c', 'gstwarp.c',
+  'gstshagadelic.c', 'gstvertigo.c', 'gstrev.c', 'gstquark.c', 'gstop.c',
+  'gstradioac.c', 'gststreak.c', 'gstripple.c'
+]
+
+gsteffectv = library('gsteffectv',
+  effect_sources,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gst_dep, gstbase_dep, gstvideo_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/equalizer/.gitignore b/gst/equalizer/.gitignore
new file mode 100644
index 0000000..1549b67
--- /dev/null
+++ b/gst/equalizer/.gitignore
@@ -0,0 +1 @@
+demo
diff --git a/gst/equalizer/GstIirEqualizer10Bands.prs b/gst/equalizer/GstIirEqualizer10Bands.prs
new file mode 100644
index 0000000..9b261b8
--- /dev/null
+++ b/gst/equalizer/GstIirEqualizer10Bands.prs
@@ -0,0 +1,174 @@
+[_presets_]
+version=0.10
+element-name=GstIirEqualizer10Bands
+
+[ballad]
+band0=4
+band1=3.75
+band2=2.5
+band3=0
+band4=-4
+band5=-6
+band6=-3
+band7=0
+band8=2.5
+band9=9
+
+[classic]
+band0=0
+band1=0
+band2=0
+band3=0
+band4=0
+band5=0
+band6=-6
+band7=-7
+band8=-7
+band9=-9.5
+
+[club]
+band0=0
+band1=0
+band2=8
+band3=6
+band4=5.5
+band5=5
+band6=3
+band7=0
+band8=0
+band9=0
+
+[dance]
+band0=9.6
+band1=7
+band2=2.5
+band3=0
+band4=0
+band5=-5.6
+band6=-7
+band7=-7
+band8=0
+band9=0
+
+[pop]
+band0=-1.6
+band1=4.5
+band2=7
+band3=8
+band4=5.6
+band5=0
+band6=-2.5
+band7=-2
+band8=-1.6
+band9=-1.5
+
+[reggae]
+band0=0
+band1=0
+band2=0
+band3=-5.5
+band4=0
+band5=6.5
+band6=6.5
+band7=0
+band8=0
+band9=0
+
+[rock]
+band0=8
+band1=5
+band2=-5.5
+band3=-8
+band4=-3
+band5=4
+band6=8
+band7=11
+band8=11
+band9=11.5
+
+[ska]
+band0=-2.5
+band1=-5
+band2=-4
+band3=0
+band4=4
+band5=5.5
+band6=8
+band7=9
+band8=11
+band9=9
+
+[soft]
+band0=5
+band1=1.5
+band2=0
+band3=-2.5
+band4=0
+band5=4
+band6=8
+band7=9
+band8=11
+band9=12
+
+[techno]
+band0=8
+band1=5.5
+band2=0
+band3=-5.5
+band4=-5
+band5=0
+band6=8
+band7=10
+band8=10
+band9=9
+
+
+[party]
+band0=7
+band1=7
+band2=0
+band3=0
+band4=0
+band5=0
+band6=0
+band7=0
+band8=7
+band9=7
+
+
+[more bass]
+band0=-8
+band1=10
+band2=10
+band3=5.5
+band4=1.5
+band5=-4
+band6=-8
+band7=-10
+band8=-11
+band9=-11
+
+[more bass and treble]
+band0=8
+band1=5.5
+band2=0
+band3=-7
+band4=-5
+band5=1.5
+band6=8
+band7=11.2
+band8=12
+band9=12
+
+[more treble]
+band0=-10
+band1=-10
+band2=-10
+band3=-4
+band4=2.5
+band5=11
+band6=16
+band7=16
+band8=16
+band9=18
+
diff --git a/gst/equalizer/GstIirEqualizer3Bands.prs b/gst/equalizer/GstIirEqualizer3Bands.prs
new file mode 100644
index 0000000..fb8ef5a
--- /dev/null
+++ b/gst/equalizer/GstIirEqualizer3Bands.prs
@@ -0,0 +1,14 @@
+[_presets_]
+version=0.10
+element-name=GstIirEqualizer3Bands
+
+[more bass]
+band0=7.75
+band1=0
+band2=0
+
+[more trebble]
+band0=0
+band1=0
+band2=6.0
+
diff --git a/gst/equalizer/Makefile.am b/gst/equalizer/Makefile.am
new file mode 100644
index 0000000..e559f74
--- /dev/null
+++ b/gst/equalizer/Makefile.am
@@ -0,0 +1,21 @@
+plugin_LTLIBRARIES = libgstequalizer.la
+
+libgstequalizer_la_SOURCES = \
+        gstiirequalizer.c gstiirequalizer.h \
+        gstiirequalizernbands.c gstiirequalizernbands.h \
+        gstiirequalizer3bands.c gstiirequalizer3bands.h \
+        gstiirequalizer10bands.c gstiirequalizer10bands.h
+
+libgstequalizer_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS)
+libgstequalizer_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+	-lgstaudio-$(GST_API_VERSION) $(GST_BASE_LIBS) \
+	$(GST_LIBS) $(LIBM)
+libgstequalizer_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstiirequalizer.h
+
+presetdir = $(datadir)/gstreamer-$(GST_API_VERSION)/presets
+preset_DATA = GstIirEqualizer3Bands.prs GstIirEqualizer10Bands.prs
+
+EXTRA_DIST = $(preset_DATA)
diff --git a/gst/equalizer/gstiirequalizer.c b/gst/equalizer/gstiirequalizer.c
new file mode 100644
index 0000000..210296b
--- /dev/null
+++ b/gst/equalizer/gstiirequalizer.c
@@ -0,0 +1,919 @@
+/* GStreamer
+ * Copyright (C) <2004> Benjamin Otte <otte@gnome.org>
+ *               <2007> Stefan Kost <ensonic@users.sf.net>
+ *               <2007> Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "gstiirequalizer.h"
+#include "gstiirequalizernbands.h"
+#include "gstiirequalizer3bands.h"
+#include "gstiirequalizer10bands.h"
+
+#include "gst/glib-compat-private.h"
+
+GST_DEBUG_CATEGORY (equalizer_debug);
+#define GST_CAT_DEFAULT equalizer_debug
+
+#define BANDS_LOCK(equ) g_mutex_lock(&equ->bands_lock)
+#define BANDS_UNLOCK(equ) g_mutex_unlock(&equ->bands_lock)
+
+static void gst_iir_equalizer_child_proxy_interface_init (gpointer g_iface,
+    gpointer iface_data);
+
+static void gst_iir_equalizer_finalize (GObject * object);
+
+static gboolean gst_iir_equalizer_setup (GstAudioFilter * filter,
+    const GstAudioInfo * info);
+static GstFlowReturn gst_iir_equalizer_transform_ip (GstBaseTransform * btrans,
+    GstBuffer * buf);
+static void set_passthrough (GstIirEqualizer * equ);
+
+#define ALLOWED_CAPS \
+    "audio/x-raw,"                                                \
+    " format=(string) {"GST_AUDIO_NE(S16)","GST_AUDIO_NE(F32)","  \
+                        GST_AUDIO_NE(F64)" }, "                   \
+    " rate=(int)[1000,MAX],"                                      \
+    " channels=(int)[1,MAX],"                                     \
+    " layout=(string)interleaved"
+
+#define gst_iir_equalizer_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstIirEqualizer, gst_iir_equalizer,
+    GST_TYPE_AUDIO_FILTER,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
+        gst_iir_equalizer_child_proxy_interface_init)
+    G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
+
+
+/* child object */
+
+enum
+{
+  PROP_GAIN = 1,
+  PROP_FREQ,
+  PROP_BANDWIDTH,
+  PROP_TYPE
+};
+
+typedef enum
+{
+  BAND_TYPE_PEAK = 0,
+  BAND_TYPE_LOW_SHELF,
+  BAND_TYPE_HIGH_SHELF
+} GstIirEqualizerBandType;
+
+#define GST_TYPE_IIR_EQUALIZER_BAND_TYPE (gst_iir_equalizer_band_type_get_type ())
+static GType
+gst_iir_equalizer_band_type_get_type (void)
+{
+  static GType gtype = 0;
+
+  if (gtype == 0) {
+    static const GEnumValue values[] = {
+      {BAND_TYPE_PEAK, "Peak filter (default for inner bands)", "peak"},
+      {BAND_TYPE_LOW_SHELF, "Low shelf filter (default for first band)",
+          "low-shelf"},
+      {BAND_TYPE_HIGH_SHELF, "High shelf filter (default for last band)",
+          "high-shelf"},
+      {0, NULL, NULL}
+    };
+
+    gtype = g_enum_register_static ("GstIirEqualizerBandType", values);
+  }
+  return gtype;
+}
+
+
+typedef struct _GstIirEqualizerBandClass GstIirEqualizerBandClass;
+
+#define GST_TYPE_IIR_EQUALIZER_BAND \
+  (gst_iir_equalizer_band_get_type())
+#define GST_IIR_EQUALIZER_BAND(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_IIR_EQUALIZER_BAND,GstIirEqualizerBand))
+#define GST_IIR_EQUALIZER_BAND_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_IIR_EQUALIZER_BAND,GstIirEqualizerBandClass))
+#define GST_IS_IIR_EQUALIZER_BAND(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_IIR_EQUALIZER_BAND))
+#define GST_IS_IIR_EQUALIZER_BAND_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_IIR_EQUALIZER_BAND))
+
+struct _GstIirEqualizerBand
+{
+  GstObject object;
+
+  /*< private > */
+  /* center frequency and gain */
+  gdouble freq;
+  gdouble gain;
+  gdouble width;
+  GstIirEqualizerBandType type;
+
+  /* second order iir filter */
+  gdouble b1, b2;               /* IIR coefficients for outputs */
+  gdouble a0, a1, a2;           /* IIR coefficients for inputs */
+};
+
+struct _GstIirEqualizerBandClass
+{
+  GstObjectClass parent_class;
+};
+
+static GType gst_iir_equalizer_band_get_type (void);
+
+static void
+gst_iir_equalizer_band_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstIirEqualizerBand *band = GST_IIR_EQUALIZER_BAND (object);
+  GstIirEqualizer *equ =
+      GST_IIR_EQUALIZER (gst_object_get_parent (GST_OBJECT (band)));
+
+  switch (prop_id) {
+    case PROP_GAIN:{
+      gdouble gain;
+
+      gain = g_value_get_double (value);
+      GST_DEBUG_OBJECT (band, "gain = %lf -> %lf", band->gain, gain);
+      if (gain != band->gain) {
+        BANDS_LOCK (equ);
+        equ->need_new_coefficients = TRUE;
+        band->gain = gain;
+        set_passthrough (equ);
+        BANDS_UNLOCK (equ);
+        GST_DEBUG_OBJECT (band, "changed gain = %lf ", band->gain);
+      }
+      break;
+    }
+    case PROP_FREQ:{
+      gdouble freq;
+
+      freq = g_value_get_double (value);
+      GST_DEBUG_OBJECT (band, "freq = %lf -> %lf", band->freq, freq);
+      if (freq != band->freq) {
+        BANDS_LOCK (equ);
+        equ->need_new_coefficients = TRUE;
+        band->freq = freq;
+        BANDS_UNLOCK (equ);
+        GST_DEBUG_OBJECT (band, "changed freq = %lf ", band->freq);
+      }
+      break;
+    }
+    case PROP_BANDWIDTH:{
+      gdouble width;
+
+      width = g_value_get_double (value);
+      GST_DEBUG_OBJECT (band, "width = %lf -> %lf", band->width, width);
+      if (width != band->width) {
+        BANDS_LOCK (equ);
+        equ->need_new_coefficients = TRUE;
+        band->width = width;
+        BANDS_UNLOCK (equ);
+        GST_DEBUG_OBJECT (band, "changed width = %lf ", band->width);
+      }
+      break;
+    }
+    case PROP_TYPE:{
+      GstIirEqualizerBandType type;
+
+      type = g_value_get_enum (value);
+      GST_DEBUG_OBJECT (band, "type = %d -> %d", band->type, type);
+      if (type != band->type) {
+        BANDS_LOCK (equ);
+        equ->need_new_coefficients = TRUE;
+        band->type = type;
+        BANDS_UNLOCK (equ);
+        GST_DEBUG_OBJECT (band, "changed type = %d ", band->type);
+      }
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  gst_object_unref (equ);
+}
+
+static void
+gst_iir_equalizer_band_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstIirEqualizerBand *band = GST_IIR_EQUALIZER_BAND (object);
+
+  switch (prop_id) {
+    case PROP_GAIN:
+      g_value_set_double (value, band->gain);
+      break;
+    case PROP_FREQ:
+      g_value_set_double (value, band->freq);
+      break;
+    case PROP_BANDWIDTH:
+      g_value_set_double (value, band->width);
+      break;
+    case PROP_TYPE:
+      g_value_set_enum (value, band->type);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_iir_equalizer_band_class_init (GstIirEqualizerBandClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = gst_iir_equalizer_band_set_property;
+  gobject_class->get_property = gst_iir_equalizer_band_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_GAIN,
+      g_param_spec_double ("gain", "gain",
+          "gain for the frequency band ranging from -24.0 dB to +12.0 dB",
+          -24.0, 12.0, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  g_object_class_install_property (gobject_class, PROP_FREQ,
+      g_param_spec_double ("freq", "freq",
+          "center frequency of the band",
+          0.0, 100000.0, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  g_object_class_install_property (gobject_class, PROP_BANDWIDTH,
+      g_param_spec_double ("bandwidth", "bandwidth",
+          "difference between bandedges in Hz",
+          0.0, 100000.0, 1.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  g_object_class_install_property (gobject_class, PROP_TYPE,
+      g_param_spec_enum ("type", "Type",
+          "Filter type", GST_TYPE_IIR_EQUALIZER_BAND_TYPE,
+          BAND_TYPE_PEAK,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+}
+
+static void
+gst_iir_equalizer_band_init (GstIirEqualizerBand * band,
+    GstIirEqualizerBandClass * klass)
+{
+  band->freq = 0.0;
+  band->gain = 0.0;
+  band->width = 1.0;
+  band->type = BAND_TYPE_PEAK;
+}
+
+static GType
+gst_iir_equalizer_band_get_type (void)
+{
+  static GType type = 0;
+
+  if (G_UNLIKELY (!type)) {
+    const GTypeInfo type_info = {
+      sizeof (GstIirEqualizerBandClass),
+      NULL,
+      NULL,
+      (GClassInitFunc) gst_iir_equalizer_band_class_init,
+      NULL,
+      NULL,
+      sizeof (GstIirEqualizerBand),
+      0,
+      (GInstanceInitFunc) gst_iir_equalizer_band_init,
+    };
+    type =
+        g_type_register_static (GST_TYPE_OBJECT, "GstIirEqualizerBand",
+        &type_info, 0);
+  }
+  return (type);
+}
+
+
+/* child proxy iface */
+static GObject *
+gst_iir_equalizer_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
+    guint index)
+{
+  GstIirEqualizer *equ = GST_IIR_EQUALIZER (child_proxy);
+  GObject *ret;
+
+  BANDS_LOCK (equ);
+  if (G_UNLIKELY (index >= equ->freq_band_count)) {
+    BANDS_UNLOCK (equ);
+    g_return_val_if_fail (index < equ->freq_band_count, NULL);
+  }
+
+  ret = g_object_ref (G_OBJECT (equ->bands[index]));
+  BANDS_UNLOCK (equ);
+
+  GST_LOG_OBJECT (equ, "return child[%d] %" GST_PTR_FORMAT, index, ret);
+  return ret;
+}
+
+static guint
+gst_iir_equalizer_child_proxy_get_children_count (GstChildProxy * child_proxy)
+{
+  GstIirEqualizer *equ = GST_IIR_EQUALIZER (child_proxy);
+
+  GST_LOG ("we have %d children", equ->freq_band_count);
+  return equ->freq_band_count;
+}
+
+static void
+gst_iir_equalizer_child_proxy_interface_init (gpointer g_iface,
+    gpointer iface_data)
+{
+  GstChildProxyInterface *iface = g_iface;
+
+  GST_DEBUG ("initializing iface");
+
+  iface->get_child_by_index = gst_iir_equalizer_child_proxy_get_child_by_index;
+  iface->get_children_count = gst_iir_equalizer_child_proxy_get_children_count;
+}
+
+/* equalizer implementation */
+
+static void
+gst_iir_equalizer_class_init (GstIirEqualizerClass * klass)
+{
+  GstAudioFilterClass *audio_filter_class = (GstAudioFilterClass *) klass;
+  GstBaseTransformClass *btrans_class = (GstBaseTransformClass *) klass;
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstCaps *caps;
+
+  gobject_class->finalize = gst_iir_equalizer_finalize;
+  audio_filter_class->setup = gst_iir_equalizer_setup;
+  btrans_class->transform_ip = gst_iir_equalizer_transform_ip;
+  btrans_class->transform_ip_on_passthrough = FALSE;
+
+  caps = gst_caps_from_string (ALLOWED_CAPS);
+  gst_audio_filter_class_add_pad_templates (audio_filter_class, caps);
+  gst_caps_unref (caps);
+}
+
+static void
+gst_iir_equalizer_init (GstIirEqualizer * eq)
+{
+  g_mutex_init (&eq->bands_lock);
+  /* Band gains are 0 by default, passthrough until they are changed */
+  gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (eq), TRUE);
+}
+
+static void
+gst_iir_equalizer_finalize (GObject * object)
+{
+  GstIirEqualizer *equ = GST_IIR_EQUALIZER (object);
+  gint i;
+
+  for (i = 0; i < equ->freq_band_count; i++) {
+    if (equ->bands[i])
+      gst_object_unparent (GST_OBJECT (equ->bands[i]));
+    equ->bands[i] = NULL;
+  }
+  equ->freq_band_count = 0;
+
+  g_free (equ->bands);
+  g_free (equ->history);
+
+  g_mutex_clear (&equ->bands_lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* Filter taken from
+ *
+ * The Equivalence of Various Methods of Computing
+ * Biquad Coefficients for Audio Parametric Equalizers
+ *
+ * by Robert Bristow-Johnson
+ *
+ * http://www.aes.org/e-lib/browse.cfm?elib=6326
+ * http://www.musicdsp.org/files/EQ-Coefficients.pdf
+ * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
+ *
+ * The bandwidth method that we use here is the preferred
+ * one from this article transformed from octaves to frequency
+ * in Hz.
+ */
+static inline gdouble
+arg_to_scale (gdouble arg)
+{
+  return (pow (10.0, arg / 40.0));
+}
+
+static gdouble
+calculate_omega (gdouble freq, gint rate)
+{
+  gdouble omega;
+
+  if (freq / rate >= 0.5)
+    omega = G_PI;
+  else if (freq <= 0.0)
+    omega = 0.0;
+  else
+    omega = 2.0 * G_PI * (freq / rate);
+
+  return omega;
+}
+
+static gdouble
+calculate_bw (GstIirEqualizerBand * band, gint rate)
+{
+  gdouble bw = 0.0;
+
+  if (band->width / rate >= 0.5) {
+    /* If bandwidth == 0.5 the calculation below fails as tan(G_PI/2)
+     * is undefined. So set the bandwidth to a slightly smaller value.
+     */
+    bw = G_PI - 0.00000001;
+  } else if (band->width <= 0.0) {
+    /* If bandwidth == 0 this band won't change anything so set
+     * the coefficients accordingly. The coefficient calculation
+     * below would create coefficients that for some reason amplify
+     * the band.
+     */
+    band->a0 = 1.0;
+    band->a1 = 0.0;
+    band->a2 = 0.0;
+    band->b1 = 0.0;
+    band->b2 = 0.0;
+  } else {
+    bw = 2.0 * G_PI * (band->width / rate);
+  }
+  return bw;
+}
+
+static void
+setup_peak_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
+{
+  gint rate = GST_AUDIO_FILTER_RATE (equ);
+
+  g_return_if_fail (rate);
+
+  {
+    gdouble gain, omega, bw;
+    gdouble alpha, alpha1, alpha2, b0;
+
+    gain = arg_to_scale (band->gain);
+    omega = calculate_omega (band->freq, rate);
+    bw = calculate_bw (band, rate);
+    if (bw == 0.0)
+      goto out;
+
+    alpha = tan (bw / 2.0);
+
+    alpha1 = alpha * gain;
+    alpha2 = alpha / gain;
+
+    b0 = (1.0 + alpha2);
+
+    band->a0 = (1.0 + alpha1) / b0;
+    band->a1 = (-2.0 * cos (omega)) / b0;
+    band->a2 = (1.0 - alpha1) / b0;
+    band->b1 = (2.0 * cos (omega)) / b0;
+    band->b2 = -(1.0 - alpha2) / b0;
+
+  out:
+    GST_INFO
+        ("gain = %5.1f, width= %7.2f, freq = %7.2f, a0 = %7.5g, a1 = %7.5g, a2=%7.5g b1 = %7.5g, b2 = %7.5g",
+        band->gain, band->width, band->freq, band->a0, band->a1, band->a2,
+        band->b1, band->b2);
+  }
+}
+
+static void
+setup_low_shelf_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
+{
+  gint rate = GST_AUDIO_FILTER_RATE (equ);
+
+  g_return_if_fail (rate);
+
+  {
+    gdouble gain, omega, bw;
+    gdouble alpha, delta, b0;
+    gdouble egp, egm;
+
+    gain = arg_to_scale (band->gain);
+    omega = calculate_omega (band->freq, rate);
+    bw = calculate_bw (band, rate);
+    if (bw == 0.0)
+      goto out;
+
+    egm = gain - 1.0;
+    egp = gain + 1.0;
+    alpha = tan (bw / 2.0);
+
+    delta = 2.0 * sqrt (gain) * alpha;
+    b0 = egp + egm * cos (omega) + delta;
+
+    band->a0 = ((egp - egm * cos (omega) + delta) * gain) / b0;
+    band->a1 = ((egm - egp * cos (omega)) * 2.0 * gain) / b0;
+    band->a2 = ((egp - egm * cos (omega) - delta) * gain) / b0;
+    band->b1 = ((egm + egp * cos (omega)) * 2.0) / b0;
+    band->b2 = -((egp + egm * cos (omega) - delta)) / b0;
+
+
+  out:
+    GST_INFO
+        ("gain = %5.1f, width= %7.2f, freq = %7.2f, a0 = %7.5g, a1 = %7.5g, a2=%7.5g b1 = %7.5g, b2 = %7.5g",
+        band->gain, band->width, band->freq, band->a0, band->a1, band->a2,
+        band->b1, band->b2);
+  }
+}
+
+static void
+setup_high_shelf_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
+{
+  gint rate = GST_AUDIO_FILTER_RATE (equ);
+
+  g_return_if_fail (rate);
+
+  {
+    gdouble gain, omega, bw;
+    gdouble alpha, delta, b0;
+    gdouble egp, egm;
+
+    gain = arg_to_scale (band->gain);
+    omega = calculate_omega (band->freq, rate);
+    bw = calculate_bw (band, rate);
+    if (bw == 0.0)
+      goto out;
+
+    egm = gain - 1.0;
+    egp = gain + 1.0;
+    alpha = tan (bw / 2.0);
+
+    delta = 2.0 * sqrt (gain) * alpha;
+    b0 = egp - egm * cos (omega) + delta;
+
+    band->a0 = ((egp + egm * cos (omega) + delta) * gain) / b0;
+    band->a1 = ((egm + egp * cos (omega)) * -2.0 * gain) / b0;
+    band->a2 = ((egp + egm * cos (omega) - delta) * gain) / b0;
+    band->b1 = ((egm - egp * cos (omega)) * -2.0) / b0;
+    band->b2 = -((egp - egm * cos (omega) - delta)) / b0;
+
+
+  out:
+    GST_INFO
+        ("gain = %5.1f, width= %7.2f, freq = %7.2f, a0 = %7.5g, a1 = %7.5g, a2=%7.5g b1 = %7.5g, b2 = %7.5g",
+        band->gain, band->width, band->freq, band->a0, band->a1, band->a2,
+        band->b1, band->b2);
+  }
+}
+
+/* Must be called with bands_lock and transform lock! */
+static void
+set_passthrough (GstIirEqualizer * equ)
+{
+  gint i;
+  gboolean passthrough = TRUE;
+
+  for (i = 0; i < equ->freq_band_count; i++) {
+    passthrough = passthrough && (equ->bands[i]->gain == 0.0);
+  }
+
+  gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (equ), passthrough);
+  GST_DEBUG ("Passthrough mode: %d\n", passthrough);
+}
+
+/* Must be called with bands_lock and transform lock! */
+static void
+update_coefficients (GstIirEqualizer * equ)
+{
+  gint i, n = equ->freq_band_count;
+
+  for (i = 0; i < n; i++) {
+    if (equ->bands[i]->type == BAND_TYPE_PEAK)
+      setup_peak_filter (equ, equ->bands[i]);
+    else if (equ->bands[i]->type == BAND_TYPE_LOW_SHELF)
+      setup_low_shelf_filter (equ, equ->bands[i]);
+    else
+      setup_high_shelf_filter (equ, equ->bands[i]);
+  }
+
+  equ->need_new_coefficients = FALSE;
+}
+
+/* Must be called with transform lock! */
+static void
+alloc_history (GstIirEqualizer * equ, const GstAudioInfo * info)
+{
+  /* free + alloc = no memcpy */
+  g_free (equ->history);
+  equ->history =
+      g_malloc0 (equ->history_size * GST_AUDIO_INFO_CHANNELS (info) *
+      equ->freq_band_count);
+}
+
+void
+gst_iir_equalizer_compute_frequencies (GstIirEqualizer * equ, guint new_count)
+{
+  guint old_count, i;
+  gdouble freq0, freq1, step;
+  gchar name[20];
+
+  if (equ->freq_band_count == new_count)
+    return;
+
+  BANDS_LOCK (equ);
+
+  if (G_UNLIKELY (equ->freq_band_count == new_count)) {
+    BANDS_UNLOCK (equ);
+    return;
+  }
+
+  old_count = equ->freq_band_count;
+  equ->freq_band_count = new_count;
+  GST_DEBUG ("bands %u -> %u", old_count, new_count);
+
+  if (old_count < new_count) {
+    /* add new bands */
+    equ->bands = g_realloc (equ->bands, sizeof (GstObject *) * new_count);
+    for (i = old_count; i < new_count; i++) {
+      /* otherwise they get names like 'iirequalizerband5' */
+      sprintf (name, "band%u", i);
+      equ->bands[i] = g_object_new (GST_TYPE_IIR_EQUALIZER_BAND,
+          "name", name, NULL);
+      GST_DEBUG ("adding band[%d]=%p", i, equ->bands[i]);
+
+      gst_object_set_parent (GST_OBJECT (equ->bands[i]), GST_OBJECT (equ));
+      gst_child_proxy_child_added (GST_CHILD_PROXY (equ),
+          G_OBJECT (equ->bands[i]), name);
+    }
+  } else {
+    /* free unused bands */
+    for (i = new_count; i < old_count; i++) {
+      GST_DEBUG ("removing band[%d]=%p", i, equ->bands[i]);
+      gst_child_proxy_child_removed (GST_CHILD_PROXY (equ),
+          G_OBJECT (equ->bands[i]), GST_OBJECT_NAME (equ->bands[i]));
+      gst_object_unparent (GST_OBJECT (equ->bands[i]));
+      equ->bands[i] = NULL;
+    }
+  }
+
+  alloc_history (equ, GST_AUDIO_FILTER_INFO (equ));
+
+  /* set center frequencies and name band objects
+   * FIXME: arg! we can't change the name of parented objects :(
+   *   application should read band->freq to get the name
+   */
+
+  step = pow (HIGHEST_FREQ / LOWEST_FREQ, 1.0 / new_count);
+  freq0 = LOWEST_FREQ;
+  for (i = 0; i < new_count; i++) {
+    freq1 = freq0 * step;
+
+    if (i == 0)
+      equ->bands[i]->type = BAND_TYPE_LOW_SHELF;
+    else if (i == new_count - 1)
+      equ->bands[i]->type = BAND_TYPE_HIGH_SHELF;
+    else
+      equ->bands[i]->type = BAND_TYPE_PEAK;
+
+    equ->bands[i]->freq = freq0 + ((freq1 - freq0) / 2.0);
+    equ->bands[i]->width = freq1 - freq0;
+    GST_DEBUG ("band[%2d] = '%lf'", i, equ->bands[i]->freq);
+
+    g_object_notify (G_OBJECT (equ->bands[i]), "bandwidth");
+    g_object_notify (G_OBJECT (equ->bands[i]), "freq");
+    g_object_notify (G_OBJECT (equ->bands[i]), "type");
+
+    /*
+       if(equ->bands[i]->freq<10000.0)
+       sprintf (name,"%dHz",(gint)equ->bands[i]->freq);
+       else
+       sprintf (name,"%dkHz",(gint)(equ->bands[i]->freq/1000.0));
+       gst_object_set_name( GST_OBJECT (equ->bands[i]), name);
+       GST_DEBUG ("band[%2d] = '%s'",i,name);
+     */
+    freq0 = freq1;
+  }
+
+  equ->need_new_coefficients = TRUE;
+  BANDS_UNLOCK (equ);
+}
+
+/* start of code that is type specific */
+
+#define CREATE_OPTIMIZED_FUNCTIONS_INT(TYPE,BIG_TYPE,MIN_VAL,MAX_VAL)   \
+typedef struct {                                                        \
+  BIG_TYPE x1, x2;          /* history of input values for a filter */  \
+  BIG_TYPE y1, y2;          /* history of output values for a filter */ \
+} SecondOrderHistory ## TYPE;                                           \
+                                                                        \
+static inline BIG_TYPE                                                  \
+one_step_ ## TYPE (GstIirEqualizerBand *filter,                         \
+    SecondOrderHistory ## TYPE *history, BIG_TYPE input)                \
+{                                                                       \
+  /* calculate output */                                                \
+  BIG_TYPE output = filter->a0 * input +                                \
+      filter->a1 * history->x1 + filter->a2 * history->x2 +             \
+      filter->b1 * history->y1 + filter->b2 * history->y2;              \
+  /* update history */                                                  \
+  history->y2 = history->y1;                                            \
+  history->y1 = output;                                                 \
+  history->x2 = history->x1;                                            \
+  history->x1 = input;                                                  \
+                                                                        \
+  return output;                                                        \
+}                                                                       \
+                                                                        \
+static const guint                                                      \
+history_size_ ## TYPE = sizeof (SecondOrderHistory ## TYPE);            \
+                                                                        \
+static void                                                             \
+gst_iir_equ_process_ ## TYPE (GstIirEqualizer *equ, guint8 *data,       \
+guint size, guint channels)                                             \
+{                                                                       \
+  guint frames = size / channels / sizeof (TYPE);                       \
+  guint i, c, f, nf = equ->freq_band_count;                             \
+  BIG_TYPE cur;                                                         \
+  GstIirEqualizerBand **filters = equ->bands;                           \
+                                                                        \
+  for (i = 0; i < frames; i++) {                                        \
+    SecondOrderHistory ## TYPE *history = equ->history;                 \
+    for (c = 0; c < channels; c++) {                                    \
+      cur = *((TYPE *) data);                                           \
+      for (f = 0; f < nf; f++) {                                        \
+        cur = one_step_ ## TYPE (filters[f], history, cur);             \
+        history++;                                                      \
+      }                                                                 \
+      cur = CLAMP (cur, MIN_VAL, MAX_VAL);                              \
+      *((TYPE *) data) = (TYPE) floor (cur);                            \
+      data += sizeof (TYPE);                                            \
+    }                                                                   \
+  }                                                                     \
+}
+
+#define CREATE_OPTIMIZED_FUNCTIONS(TYPE)                                \
+typedef struct {                                                        \
+  TYPE x1, x2;          /* history of input values for a filter */  \
+  TYPE y1, y2;          /* history of output values for a filter */ \
+} SecondOrderHistory ## TYPE;                                           \
+                                                                        \
+static inline TYPE                                                      \
+one_step_ ## TYPE (GstIirEqualizerBand *filter,                         \
+    SecondOrderHistory ## TYPE *history, TYPE input)                    \
+{                                                                       \
+  /* calculate output */                                                \
+  TYPE output = filter->a0 * input + filter->a1 * history->x1 +         \
+      filter->a2 * history->x2 + filter->b1 * history->y1 +             \
+      filter->b2 * history->y2;                                         \
+  /* update history */                                                  \
+  history->y2 = history->y1;                                            \
+  history->y1 = output;                                                 \
+  history->x2 = history->x1;                                            \
+  history->x1 = input;                                                  \
+                                                                        \
+  return output;                                                        \
+}                                                                       \
+                                                                        \
+static const guint                                                      \
+history_size_ ## TYPE = sizeof (SecondOrderHistory ## TYPE);            \
+                                                                        \
+static void                                                             \
+gst_iir_equ_process_ ## TYPE (GstIirEqualizer *equ, guint8 *data,       \
+guint size, guint channels)                                             \
+{                                                                       \
+  guint frames = size / channels / sizeof (TYPE);                       \
+  guint i, c, f, nf = equ->freq_band_count;                             \
+  TYPE cur;                                                             \
+  GstIirEqualizerBand **filters = equ->bands;                           \
+                                                                        \
+  for (i = 0; i < frames; i++) {                                        \
+    SecondOrderHistory ## TYPE *history = equ->history;                 \
+    for (c = 0; c < channels; c++) {                                    \
+      cur = *((TYPE *) data);                                           \
+      for (f = 0; f < nf; f++) {                                        \
+        cur = one_step_ ## TYPE (filters[f], history, cur);             \
+        history++;                                                      \
+      }                                                                 \
+      *((TYPE *) data) = (TYPE) cur;                                    \
+      data += sizeof (TYPE);                                            \
+    }                                                                   \
+  }                                                                     \
+}
+
+CREATE_OPTIMIZED_FUNCTIONS_INT (gint16, gfloat, -32768.0, 32767.0);
+CREATE_OPTIMIZED_FUNCTIONS (gfloat);
+CREATE_OPTIMIZED_FUNCTIONS (gdouble);
+
+static GstFlowReturn
+gst_iir_equalizer_transform_ip (GstBaseTransform * btrans, GstBuffer * buf)
+{
+  GstAudioFilter *filter = GST_AUDIO_FILTER (btrans);
+  GstIirEqualizer *equ = GST_IIR_EQUALIZER (btrans);
+  GstClockTime timestamp;
+  GstMapInfo map;
+  gint channels = GST_AUDIO_FILTER_CHANNELS (filter);
+  gboolean need_new_coefficients;
+
+  if (G_UNLIKELY (channels < 1 || equ->process == NULL))
+    return GST_FLOW_NOT_NEGOTIATED;
+
+  BANDS_LOCK (equ);
+  need_new_coefficients = equ->need_new_coefficients;
+  BANDS_UNLOCK (equ);
+
+  timestamp = GST_BUFFER_TIMESTAMP (buf);
+  timestamp =
+      gst_segment_to_stream_time (&btrans->segment, GST_FORMAT_TIME, timestamp);
+
+  if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+    GstIirEqualizerBand **filters = equ->bands;
+    guint f, nf = equ->freq_band_count;
+
+    gst_object_sync_values (GST_OBJECT (equ), timestamp);
+
+    /* sync values for bands too */
+    /* FIXME: iterating equ->bands is not thread-safe here */
+    for (f = 0; f < nf; f++) {
+      gst_object_sync_values (GST_OBJECT (filters[f]), timestamp);
+    }
+  }
+
+  BANDS_LOCK (equ);
+  if (need_new_coefficients) {
+    update_coefficients (equ);
+  }
+  BANDS_UNLOCK (equ);
+
+  gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+  equ->process (equ, map.data, map.size, channels);
+  gst_buffer_unmap (buf, &map);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_iir_equalizer_setup (GstAudioFilter * audio, const GstAudioInfo * info)
+{
+  GstIirEqualizer *equ = GST_IIR_EQUALIZER (audio);
+
+  switch (GST_AUDIO_INFO_FORMAT (info)) {
+    case GST_AUDIO_FORMAT_S16:
+      equ->history_size = history_size_gint16;
+      equ->process = gst_iir_equ_process_gint16;
+      break;
+    case GST_AUDIO_FORMAT_F32:
+      equ->history_size = history_size_gfloat;
+      equ->process = gst_iir_equ_process_gfloat;
+      break;
+    case GST_AUDIO_FORMAT_F64:
+      equ->history_size = history_size_gdouble;
+      equ->process = gst_iir_equ_process_gdouble;
+      break;
+    default:
+      return FALSE;
+  }
+
+  alloc_history (equ, info);
+  return TRUE;
+}
+
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (equalizer_debug, "equalizer", 0, "equalizer");
+
+  if (!(gst_element_register (plugin, "equalizer-nbands", GST_RANK_NONE,
+              GST_TYPE_IIR_EQUALIZER_NBANDS)))
+    return FALSE;
+
+  if (!(gst_element_register (plugin, "equalizer-3bands", GST_RANK_NONE,
+              GST_TYPE_IIR_EQUALIZER_3BANDS)))
+    return FALSE;
+
+  if (!(gst_element_register (plugin, "equalizer-10bands", GST_RANK_NONE,
+              GST_TYPE_IIR_EQUALIZER_10BANDS)))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    equalizer,
+    "GStreamer audio equalizers",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/equalizer/gstiirequalizer.h b/gst/equalizer/gstiirequalizer.h
new file mode 100644
index 0000000..3ba70eed
--- /dev/null
+++ b/gst/equalizer/gstiirequalizer.h
@@ -0,0 +1,76 @@
+/* GStreamer IIR equalizer
+ * Copyright (C) <2004> Benjamin Otte <otte@gnome.org>
+ *               <2007> Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_IIR_EQUALIZER__
+#define __GST_IIR_EQUALIZER__
+
+#include <gst/audio/gstaudiofilter.h>
+
+typedef struct _GstIirEqualizer GstIirEqualizer;
+typedef struct _GstIirEqualizerClass GstIirEqualizerClass;
+typedef struct _GstIirEqualizerBand GstIirEqualizerBand;
+
+#define GST_TYPE_IIR_EQUALIZER \
+  (gst_iir_equalizer_get_type())
+#define GST_IIR_EQUALIZER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_IIR_EQUALIZER,GstIirEqualizer))
+#define GST_IIR_EQUALIZER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_IIR_EQUALIZER,GstIirEqualizerClass))
+#define GST_IS_IIR_EQUALIZER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_IIR_EQUALIZER))
+#define GST_IS_IIR_EQUALIZER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_IIR_EQUALIZER))
+
+#define LOWEST_FREQ (20.0)
+#define HIGHEST_FREQ (20000.0)
+
+typedef void (*ProcessFunc) (GstIirEqualizer * eq, guint8 * data, guint size,
+    guint channels);
+
+struct _GstIirEqualizer
+{
+  GstAudioFilter audiofilter;
+
+  /*< private >*/
+
+  GMutex bands_lock;
+  GstIirEqualizerBand **bands;
+
+  /* properties */
+  guint freq_band_count;
+  /* for each band and channel */
+  gpointer history;
+  guint history_size;
+
+  gboolean need_new_coefficients;
+
+  ProcessFunc process;
+};
+
+struct _GstIirEqualizerClass
+{
+  GstAudioFilterClass audiofilter_class;
+};
+
+extern void gst_iir_equalizer_compute_frequencies (GstIirEqualizer * equ, guint new_count);
+
+extern GType gst_iir_equalizer_get_type(void);
+
+#endif /* __GST_IIR_EQUALIZER__ */
diff --git a/gst/equalizer/gstiirequalizer10bands.c b/gst/equalizer/gstiirequalizer10bands.c
new file mode 100644
index 0000000..71bbf53
--- /dev/null
+++ b/gst/equalizer/gstiirequalizer10bands.c
@@ -0,0 +1,229 @@
+/* GStreamer
+ * Copyright (C) <2007> Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-equalizer-10bands
+ *
+ * The 10 band equalizer element allows to change the gain of 10 equally distributed
+ * frequency bands between 30 Hz and 15 kHz.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=song.ogg ! oggdemux ! vorbisdec ! audioconvert ! equalizer-10bands band2=3.0 ! alsasink
+ * ]| This raises the volume of the 3rd band which is at 119 Hz by 3 db.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstiirequalizer.h"
+#include "gstiirequalizer10bands.h"
+
+
+enum
+{
+  PROP_BAND0 = 1,
+  PROP_BAND1,
+  PROP_BAND2,
+  PROP_BAND3,
+  PROP_BAND4,
+  PROP_BAND5,
+  PROP_BAND6,
+  PROP_BAND7,
+  PROP_BAND8,
+  PROP_BAND9,
+};
+
+static void gst_iir_equalizer_10bands_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_iir_equalizer_10bands_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+GST_DEBUG_CATEGORY_EXTERN (equalizer_debug);
+#define GST_CAT_DEFAULT equalizer_debug
+
+
+#define gst_iir_equalizer_10bands_parent_class parent_class
+G_DEFINE_TYPE (GstIirEqualizer10Bands, gst_iir_equalizer_10bands,
+    GST_TYPE_IIR_EQUALIZER);
+
+/* equalizer implementation */
+
+static void
+gst_iir_equalizer_10bands_class_init (GstIirEqualizer10BandsClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_iir_equalizer_10bands_set_property;
+  gobject_class->get_property = gst_iir_equalizer_10bands_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_BAND0,
+      g_param_spec_double ("band0", "29 Hz",
+          "gain for the frequency band 29 Hz, ranging from -24 dB to +12 dB",
+          -24.0, 12.0, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (gobject_class, PROP_BAND1,
+      g_param_spec_double ("band1", "59 Hz",
+          "gain for the frequency band 59 Hz, ranging from -24 dB to +12 dB",
+          -24.0, 12.0, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (gobject_class, PROP_BAND2,
+      g_param_spec_double ("band2", "119 Hz",
+          "gain for the frequency band 119 Hz, ranging from -24 dB to +12 dB",
+          -24.0, 12.0, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (gobject_class, PROP_BAND3,
+      g_param_spec_double ("band3", "237 Hz",
+          "gain for the frequency band 237 Hz, ranging from -24 dB to +12 dB",
+          -24.0, 12.0, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (gobject_class, PROP_BAND4,
+      g_param_spec_double ("band4", "474 Hz",
+          "gain for the frequency band 474 Hz, ranging from -24 dB to +12 dB",
+          -24.0, 12.0, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (gobject_class, PROP_BAND5,
+      g_param_spec_double ("band5", "947 Hz",
+          "gain for the frequency band 947 Hz, ranging from -24 dB to +12 dB",
+          -24.0, 12.0, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (gobject_class, PROP_BAND6,
+      g_param_spec_double ("band6", "1889 Hz",
+          "gain for the frequency band 1889 Hz, ranging from -24 dB to +12 dB",
+          -24.0, 12.0, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (gobject_class, PROP_BAND7,
+      g_param_spec_double ("band7", "3770 Hz",
+          "gain for the frequency band 3770 Hz, ranging from -24 dB to +12 dB",
+          -24.0, 12.0, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (gobject_class, PROP_BAND8,
+      g_param_spec_double ("band8", "7523 Hz",
+          "gain for the frequency band 7523 Hz, ranging from -24 dB to +12 dB",
+          -24.0, 12.0, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (gobject_class, PROP_BAND9,
+      g_param_spec_double ("band9", "15011 Hz",
+          "gain for the frequency band 15011 Hz, ranging from -24 dB to +12 dB",
+          -24.0, 12.0, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  gst_element_class_set_static_metadata (gstelement_class, "10 Band Equalizer",
+      "Filter/Effect/Audio",
+      "Direct Form 10 band IIR equalizer",
+      "Stefan Kost <ensonic@users.sf.net>");
+}
+
+static void
+gst_iir_equalizer_10bands_init (GstIirEqualizer10Bands * equ_n)
+{
+  GstIirEqualizer *equ = GST_IIR_EQUALIZER (equ_n);
+
+  gst_iir_equalizer_compute_frequencies (equ, 10);
+}
+
+static void
+gst_iir_equalizer_10bands_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstChildProxy *equ = GST_CHILD_PROXY (object);
+
+  switch (prop_id) {
+    case PROP_BAND0:
+      gst_child_proxy_set_property (equ, "band0::gain", value);
+      break;
+    case PROP_BAND1:
+      gst_child_proxy_set_property (equ, "band1::gain", value);
+      break;
+    case PROP_BAND2:
+      gst_child_proxy_set_property (equ, "band2::gain", value);
+      break;
+    case PROP_BAND3:
+      gst_child_proxy_set_property (equ, "band3::gain", value);
+      break;
+    case PROP_BAND4:
+      gst_child_proxy_set_property (equ, "band4::gain", value);
+      break;
+    case PROP_BAND5:
+      gst_child_proxy_set_property (equ, "band5::gain", value);
+      break;
+    case PROP_BAND6:
+      gst_child_proxy_set_property (equ, "band6::gain", value);
+      break;
+    case PROP_BAND7:
+      gst_child_proxy_set_property (equ, "band7::gain", value);
+      break;
+    case PROP_BAND8:
+      gst_child_proxy_set_property (equ, "band8::gain", value);
+      break;
+    case PROP_BAND9:
+      gst_child_proxy_set_property (equ, "band9::gain", value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_iir_equalizer_10bands_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstChildProxy *equ = GST_CHILD_PROXY (object);
+
+  switch (prop_id) {
+    case PROP_BAND0:
+      gst_child_proxy_get_property (equ, "band0::gain", value);
+      break;
+    case PROP_BAND1:
+      gst_child_proxy_get_property (equ, "band1::gain", value);
+      break;
+    case PROP_BAND2:
+      gst_child_proxy_get_property (equ, "band2::gain", value);
+      break;
+    case PROP_BAND3:
+      gst_child_proxy_get_property (equ, "band3::gain", value);
+      break;
+    case PROP_BAND4:
+      gst_child_proxy_get_property (equ, "band4::gain", value);
+      break;
+    case PROP_BAND5:
+      gst_child_proxy_get_property (equ, "band5::gain", value);
+      break;
+    case PROP_BAND6:
+      gst_child_proxy_get_property (equ, "band6::gain", value);
+      break;
+    case PROP_BAND7:
+      gst_child_proxy_get_property (equ, "band7::gain", value);
+      break;
+    case PROP_BAND8:
+      gst_child_proxy_get_property (equ, "band8::gain", value);
+      break;
+    case PROP_BAND9:
+      gst_child_proxy_get_property (equ, "band9::gain", value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/gst/equalizer/gstiirequalizer10bands.h b/gst/equalizer/gstiirequalizer10bands.h
new file mode 100644
index 0000000..7066721
--- /dev/null
+++ b/gst/equalizer/gstiirequalizer10bands.h
@@ -0,0 +1,51 @@
+/* GStreamer
+ * Copyright (C) <2007> Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_IIR_EQUALIZER_10BANDS__
+#define __GST_IIR_EQUALIZER_10BANDS__
+
+#include "gstiirequalizer.h"
+
+typedef struct _GstIirEqualizer10Bands GstIirEqualizer10Bands;
+typedef struct _GstIirEqualizer10BandsClass GstIirEqualizer10BandsClass;
+
+#define GST_TYPE_IIR_EQUALIZER_10BANDS \
+  (gst_iir_equalizer_10bands_get_type())
+#define GST_IIR_EQUALIZER_10BANDS(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_IIR_EQUALIZER_10BANDS,GstIirEqualizer10Bands))
+#define GST_IIR_EQUALIZER_10BANDS_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_IIR_EQUALIZER_10BANDS,GstIirEqualizer10BandsClass))
+#define GST_IS_IIR_EQUALIZER_10BANDS(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_IIR_EQUALIZER_10BANDS))
+#define GST_IS_IIR_EQUALIZER_10BANDS_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_IIR_EQUALIZER_10BANDS))
+
+struct _GstIirEqualizer10Bands
+{
+  GstIirEqualizer equalizer;
+};
+
+struct _GstIirEqualizer10BandsClass
+{
+  GstIirEqualizerClass equalizer_class;
+};
+
+extern GType gst_iir_equalizer_10bands_get_type(void);
+
+#endif /* __GST_IIR_EQUALIZER_10BANDS__ */
diff --git a/gst/equalizer/gstiirequalizer3bands.c b/gst/equalizer/gstiirequalizer3bands.c
new file mode 100644
index 0000000..02f14ed
--- /dev/null
+++ b/gst/equalizer/gstiirequalizer3bands.c
@@ -0,0 +1,142 @@
+/* GStreamer
+ * Copyright (C) <2007> Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-equalizer-3bands
+ *
+ * The 3-band equalizer element allows to change the gain of a low frequency,
+ * medium frequency and high frequency band.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=song.ogg ! oggdemux ! vorbisdec ! audioconvert ! equalizer-3bands band1=6.0 ! alsasink
+ * ]| This raises the volume of the 2nd band, which is at 1110 Hz, by 6 db.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstiirequalizer.h"
+#include "gstiirequalizer3bands.h"
+
+enum
+{
+  PROP_BAND0 = 1,
+  PROP_BAND1,
+  PROP_BAND2,
+};
+
+static void gst_iir_equalizer_3bands_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_iir_equalizer_3bands_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+GST_DEBUG_CATEGORY_EXTERN (equalizer_debug);
+#define GST_CAT_DEFAULT equalizer_debug
+
+#define gst_iir_equalizer_3bands_parent_class parent_class
+G_DEFINE_TYPE (GstIirEqualizer3Bands, gst_iir_equalizer_3bands,
+    GST_TYPE_IIR_EQUALIZER);
+
+/* equalizer implementation */
+
+static void
+gst_iir_equalizer_3bands_class_init (GstIirEqualizer3BandsClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_iir_equalizer_3bands_set_property;
+  gobject_class->get_property = gst_iir_equalizer_3bands_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_BAND0,
+      g_param_spec_double ("band0", "110 Hz",
+          "gain for the frequency band 100 Hz, ranging from -24.0 to +12.0",
+          -24.0, 12.0, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (gobject_class, PROP_BAND1,
+      g_param_spec_double ("band1", "1100 Hz",
+          "gain for the frequency band 1100 Hz, ranging from -24.0 to +12.0",
+          -24.0, 12.0, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (gobject_class, PROP_BAND2,
+      g_param_spec_double ("band2", "11 kHz",
+          "gain for the frequency band 11 kHz, ranging from -24.0 to +12.0",
+          -24.0, 12.0, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  gst_element_class_set_static_metadata (gstelement_class, "3 Band Equalizer",
+      "Filter/Effect/Audio",
+      "Direct Form 3 band IIR equalizer", "Stefan Kost <ensonic@users.sf.net>");
+}
+
+static void
+gst_iir_equalizer_3bands_init (GstIirEqualizer3Bands * equ_n)
+{
+  GstIirEqualizer *equ = GST_IIR_EQUALIZER (equ_n);
+
+  gst_iir_equalizer_compute_frequencies (equ, 3);
+}
+
+static void
+gst_iir_equalizer_3bands_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstChildProxy *equ = GST_CHILD_PROXY (object);
+
+  switch (prop_id) {
+    case PROP_BAND0:
+      gst_child_proxy_set_property (equ, "band0::gain", value);
+      break;
+    case PROP_BAND1:
+      gst_child_proxy_set_property (equ, "band1::gain", value);
+      break;
+    case PROP_BAND2:
+      gst_child_proxy_set_property (equ, "band2::gain", value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_iir_equalizer_3bands_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstChildProxy *equ = GST_CHILD_PROXY (object);
+
+  switch (prop_id) {
+    case PROP_BAND0:
+      gst_child_proxy_get_property (equ, "band0::gain", value);
+      break;
+    case PROP_BAND1:
+      gst_child_proxy_get_property (equ, "band1::gain", value);
+      break;
+    case PROP_BAND2:
+      gst_child_proxy_get_property (equ, "band2::gain", value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/gst/equalizer/gstiirequalizer3bands.h b/gst/equalizer/gstiirequalizer3bands.h
new file mode 100644
index 0000000..3790fca
--- /dev/null
+++ b/gst/equalizer/gstiirequalizer3bands.h
@@ -0,0 +1,51 @@
+/* GStreamer
+ * Copyright (C) <2007> Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_IIR_EQUALIZER_3BANDS__
+#define __GST_IIR_EQUALIZER_3BANDS__
+
+#include "gstiirequalizer.h"
+
+typedef struct _GstIirEqualizer3Bands GstIirEqualizer3Bands;
+typedef struct _GstIirEqualizer3BandsClass GstIirEqualizer3BandsClass;
+
+#define GST_TYPE_IIR_EQUALIZER_3BANDS \
+  (gst_iir_equalizer_3bands_get_type())
+#define GST_IIR_EQUALIZER_3BANDS(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_IIR_EQUALIZER_3BANDS,GstIirEqualizer3Bands))
+#define GST_IIR_EQUALIZER_3BANDS_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_IIR_EQUALIZER_3BANDS,GstIirEqualizer3BandsClass))
+#define GST_IS_IIR_EQUALIZER_3BANDS(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_IIR_EQUALIZER_3BANDS))
+#define GST_IS_IIR_EQUALIZER_3BANDS_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_IIR_EQUALIZER_3BANDS))
+
+struct _GstIirEqualizer3Bands
+{
+  GstIirEqualizer equalizer;
+};
+
+struct _GstIirEqualizer3BandsClass
+{
+  GstIirEqualizerClass equalizer_class;
+};
+
+extern GType gst_iir_equalizer_3bands_get_type(void);
+
+#endif /* __GST_IIR_EQUALIZER_3BANDS__ */
diff --git a/gst/equalizer/gstiirequalizernbands.c b/gst/equalizer/gstiirequalizernbands.c
new file mode 100644
index 0000000..c8325c6
--- /dev/null
+++ b/gst/equalizer/gstiirequalizernbands.c
@@ -0,0 +1,164 @@
+/* GStreamer
+ * Copyright (C) <2004> Benjamin Otte <otte@gnome.org>
+ *               <2007> Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-equalizer-nbands
+ *
+ * The n-band equalizer element is a fully parametric equalizer. It allows to
+ * select between 1 and 64 bands and has properties on each band to change
+ * the center frequency, band width and gain.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=song.ogg ! oggdemux ! vorbisdec ! audioconvert ! equalizer-nbands num-bands=15 band5::gain=6.0 ! alsasink
+ * ]| This make the equalizer use 15 bands and raises the volume of the 5th band by 6 db.
+ * </refsect2>
+ * <refsect2>
+ * <title>Example code</title>
+ * |[
+ * #include &lt;gst/gst.h&gt;
+ * 
+ * ...
+ * typedef struct {
+ *   gfloat freq;
+ *   gfloat width;
+ *   gfloat gain;
+ * } GstEqualizerBandState;
+ * 
+ * ...
+ * 
+ *   GstElement *equalizer;
+ *   GObject *band;
+ *   gint i;
+ *   GstEqualizerBandState state[] = {
+ *     { 120.0,   50.0, - 3.0},
+ *     { 500.0,   20.0,  12.0},
+ *     {1503.0,    2.0, -20.0},
+ *     {6000.0, 1000.0,   6.0},
+ *     {3000.0,  120.0,   2.0}
+ *   };
+ * 
+ * ...
+ * 
+ *   equalizer = gst_element_factory_make ("equalizer-nbands", "equalizer");
+ *   g_object_set (G_OBJECT (equalizer), "num-bands", 5, NULL);
+ * 
+ * ...
+ * 
+ *   for (i = 0; i &lt; 5; i++) {
+ *     band = gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (equalizer), i);
+ *     g_object_set (G_OBJECT (band), "freq", state[i].freq,
+ *         "bandwidth", state[i].width,
+ * 	"gain", state[i].gain);
+ *     g_object_unref (G_OBJECT (band));
+ *   }
+ * 
+ * ...
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstiirequalizer.h"
+#include "gstiirequalizernbands.h"
+
+
+enum
+{
+  PROP_NUM_BANDS = 1
+};
+
+static void gst_iir_equalizer_nbands_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_iir_equalizer_nbands_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+GST_DEBUG_CATEGORY_EXTERN (equalizer_debug);
+#define GST_CAT_DEFAULT equalizer_debug
+
+#define gst_iir_equalizer_nbands_parent_class parent_class
+G_DEFINE_TYPE (GstIirEqualizerNBands, gst_iir_equalizer_nbands,
+    GST_TYPE_IIR_EQUALIZER);
+
+/* equalizer implementation */
+
+static void
+gst_iir_equalizer_nbands_class_init (GstIirEqualizerNBandsClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_iir_equalizer_nbands_set_property;
+  gobject_class->get_property = gst_iir_equalizer_nbands_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_NUM_BANDS,
+      g_param_spec_uint ("num-bands", "num-bands",
+          "number of different bands to use", 1, 64, 10,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
+
+  gst_element_class_set_static_metadata (gstelement_class, "N Band Equalizer",
+      "Filter/Effect/Audio",
+      "Direct Form IIR equalizer",
+      "Benjamin Otte <otte@gnome.org>," " Stefan Kost <ensonic@users.sf.net>");
+}
+
+static void
+gst_iir_equalizer_nbands_init (GstIirEqualizerNBands * equ_n)
+{
+  GstIirEqualizer *equ = GST_IIR_EQUALIZER (equ_n);
+
+  gst_iir_equalizer_compute_frequencies (equ, 10);
+}
+
+static void
+gst_iir_equalizer_nbands_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstIirEqualizer *equ = GST_IIR_EQUALIZER (object);
+
+  switch (prop_id) {
+    case PROP_NUM_BANDS:
+      gst_iir_equalizer_compute_frequencies (equ, g_value_get_uint (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_iir_equalizer_nbands_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstIirEqualizer *equ = GST_IIR_EQUALIZER (object);
+
+  switch (prop_id) {
+    case PROP_NUM_BANDS:
+      g_value_set_uint (value, equ->freq_band_count);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/gst/equalizer/gstiirequalizernbands.h b/gst/equalizer/gstiirequalizernbands.h
new file mode 100644
index 0000000..c119a1f
--- /dev/null
+++ b/gst/equalizer/gstiirequalizernbands.h
@@ -0,0 +1,52 @@
+/* GStreamer
+ * Copyright (C) <2004> Benjamin Otte <otte@gnome.org>
+ *               <2007> Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_IIR_EQUALIZER_NBANDS__
+#define __GST_IIR_EQUALIZER_NBANDS__
+
+#include "gstiirequalizer.h"
+
+typedef struct _GstIirEqualizerNBands GstIirEqualizerNBands;
+typedef struct _GstIirEqualizerNBandsClass GstIirEqualizerNBandsClass;
+
+#define GST_TYPE_IIR_EQUALIZER_NBANDS \
+  (gst_iir_equalizer_nbands_get_type())
+#define GST_IIR_EQUALIZER_NBANDS(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_IIR_EQUALIZER_NBANDS,GstIirEqualizerNBands))
+#define GST_IIR_EQUALIZER_NBANDS_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_IIR_EQUALIZER_NBANDS,GstIirEqualizerNBandsClass))
+#define GST_IS_IIR_EQUALIZER_NBANDS(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_IIR_EQUALIZER_NBANDS))
+#define GST_IS_IIR_EQUALIZER_NBANDS_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_IIR_EQUALIZER_NBANDS))
+
+struct _GstIirEqualizerNBands
+{
+  GstIirEqualizer equalizer;
+};
+
+struct _GstIirEqualizerNBandsClass
+{
+  GstIirEqualizerClass equalizer_class;
+};
+
+extern GType gst_iir_equalizer_nbands_get_type(void);
+
+#endif /* __GST_IIR_EQUALIZER_NBANDS__ */
diff --git a/gst/equalizer/meson.build b/gst/equalizer/meson.build
new file mode 100644
index 0000000..c7981fb
--- /dev/null
+++ b/gst/equalizer/meson.build
@@ -0,0 +1,18 @@
+eq_sources = [
+  'gstiirequalizer.c',
+  'gstiirequalizernbands.c',
+  'gstiirequalizer3bands.c',
+  'gstiirequalizer10bands.c',
+]
+
+gstequalizer = library('gstequalizer',
+  eq_sources,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc, libsinc],
+  dependencies : [gstbase_dep, gstaudio_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
+
+install_data(sources: ['GstIirEqualizer3Bands.prs',
+  'GstIirEqualizer10Bands.prs'], install_dir: presetdir)
diff --git a/gst/flv/Makefile.am b/gst/flv/Makefile.am
new file mode 100644
index 0000000..60a1015
--- /dev/null
+++ b/gst/flv/Makefile.am
@@ -0,0 +1,12 @@
+plugin_LTLIBRARIES = libgstflv.la
+
+libgstflv_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstflv_la_LIBADD = -lgstpbutils-@GST_API_VERSION@ -lgstaudio-@GST_API_VERSION@ \
+        -lgstvideo-@GST_API_VERSION@ -lgsttag-$(GST_API_VERSION) \
+	$(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS)
+libgstflv_la_LDFLAGS = ${GST_PLUGIN_LDFLAGS}
+libgstflv_la_SOURCES = gstflvdemux.c gstflvmux.c
+
+noinst_HEADERS = gstflvdemux.h gstflvmux.h amfdefs.h gstindex.h
+
+EXTRA_DIST = gstindex.c gstmemindex.c
diff --git a/gst/flv/amfdefs.h b/gst/flv/amfdefs.h
new file mode 100644
index 0000000..d1e7725
--- /dev/null
+++ b/gst/flv/amfdefs.h
@@ -0,0 +1,44 @@
+/* GStreamer
+ *
+ * Copyright (c) 2011 Jan Schmidt <thaytan@noraisin.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __AMFDEFS_H__
+#define __AMFDEFS_H__
+
+#include <glib.h>
+
+#define AMF0_NUMBER_MARKER 0x0
+#define AMF0_BOOLEAN_MARKER 0x1
+#define AMF0_STRING_MARKER 0x2
+#define AMF0_OBJECT_MARKER 0x3
+#define AMF0_MOVIECLIP_MARKER 0x4 /* Reserved, not supported */
+#define AMF0_NULL_MARKER 0x5
+#define AMF0_UNDEFINED_MARKER 0x6
+#define AMF0_REFERENCE_MARKER 0x7
+#define AMF0_ECMA_ARRAY_MARKER 0x8
+#define AMF0_OBJECT_END_MARKER 0x9
+#define AMF0_STRICT_ARRAY_MARKER 0xA
+#define AMF0_DATE_MARKER 0xB
+#define AMF0_LONG_STRING_MARKER 0xC
+#define AMF0_UNSUPPORTED_MARKER 0xD
+#define AMF0_RECORDSET_MARKER 0xE /* Reserved, not supported */
+#define AMF0_XML_DOCUMENT_MARKER 0xF
+#define AMF0_TYPED_OBJECT_MARKER 0x10
+
+#endif
diff --git a/gst/flv/gstflvdemux.c b/gst/flv/gstflvdemux.c
new file mode 100644
index 0000000..2a0fa45
--- /dev/null
+++ b/gst/flv/gstflvdemux.c
@@ -0,0 +1,3667 @@
+/* GStreamer
+ * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-flvdemux
+ *
+ * flvdemux demuxes an FLV file into the different contained streams.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v filesrc location=/path/to/flv ! flvdemux ! audioconvert ! autoaudiosink
+ * ]| This pipeline demuxes an FLV file and outputs the contained raw audio streams.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstflvdemux.h"
+#include "gstflvmux.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <gst/base/gstbytereader.h>
+#include <gst/base/gstbytewriter.h>
+#include <gst/pbutils/descriptions.h>
+#include <gst/pbutils/pbutils.h>
+#include <gst/audio/audio.h>
+#include <gst/video/video.h>
+#include <gst/tag/tag.h>
+
+/* FIXME: don't rely on own GstIndex */
+#include "gstindex.c"
+#include "gstmemindex.c"
+#define GST_ASSOCIATION_FLAG_NONE GST_INDEX_ASSOCIATION_FLAG_NONE
+#define GST_ASSOCIATION_FLAG_KEY_UNIT GST_INDEX_ASSOCIATION_FLAG_KEY_UNIT
+#define GST_ASSOCIATION_FLAG_DELTA_UNIT GST_INDEX_ASSOCIATION_FLAG_DELTA_UNIT
+
+static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-flv")
+    );
+
+static GstStaticPadTemplate audio_src_template =
+    GST_STATIC_PAD_TEMPLATE ("audio",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS
+    ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
+        "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; "
+        "audio/mpeg, mpegversion = (int) 4, stream-format = (string) raw, framed = (boolean) TRUE; "
+        "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
+        "audio/x-raw, format = (string) { U8, S16LE }, layout = (string) interleaved, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
+        "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
+        "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
+        "audio/x-speex, channels = (int) 1, rate = (int) 16000;")
+    );
+
+static GstStaticPadTemplate video_src_template =
+    GST_STATIC_PAD_TEMPLATE ("video",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("video/x-flash-video, flvversion=(int) 1; "
+        "video/x-flash-screen; "
+        "video/x-vp6-flash; " "video/x-vp6-alpha; "
+        "video/x-h264, stream-format=avc;")
+    );
+
+GST_DEBUG_CATEGORY_STATIC (flvdemux_debug);
+#define GST_CAT_DEFAULT flvdemux_debug
+
+#define gst_flv_demux_parent_class parent_class
+G_DEFINE_TYPE (GstFlvDemux, gst_flv_demux, GST_TYPE_ELEMENT);
+
+/* 9 bytes of header + 4 bytes of first previous tag size */
+#define FLV_HEADER_SIZE 13
+/* 1 byte of tag type + 3 bytes of tag data size */
+#define FLV_TAG_TYPE_SIZE 4
+
+/* two seconds - consider dts are resynced to another base if this different */
+#define RESYNC_THRESHOLD 2000
+
+/* how much stream time to wait for audio tags to appear after we have video, or vice versa */
+#define NO_MORE_PADS_THRESHOLD (6 * GST_SECOND)
+
+static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux,
+    GstEvent * event);
+static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux,
+    GstEvent * event, gboolean seeking);
+
+static gboolean gst_flv_demux_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+static gboolean gst_flv_demux_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+
+static GstIndex *gst_flv_demux_get_index (GstElement * element);
+
+static void gst_flv_demux_push_tags (GstFlvDemux * demux);
+
+static void
+gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
+    guint64 pos, gboolean keyframe)
+{
+  GstIndexAssociation associations[2];
+  GstIndex *index;
+  GstIndexEntry *entry;
+
+  GST_LOG_OBJECT (demux,
+      "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
+      keyframe, GST_TIME_ARGS (ts), pos);
+
+  /* if upstream is not seekable there is no point in building an index */
+  if (!demux->upstream_seekable)
+    return;
+
+  index = gst_flv_demux_get_index (GST_ELEMENT (demux));
+
+  if (!index)
+    return;
+
+  /* entry may already have been added before, avoid adding indefinitely */
+  entry = gst_index_get_assoc_entry (index, demux->index_id,
+      GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
+
+  if (entry) {
+#ifndef GST_DISABLE_GST_DEBUG
+    gint64 time = 0;
+    gboolean key;
+
+    gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
+    key = ! !(GST_INDEX_ASSOC_FLAGS (entry) & GST_ASSOCIATION_FLAG_KEY_UNIT);
+    GST_LOG_OBJECT (demux, "position already mapped to time %" GST_TIME_FORMAT
+        ", keyframe %d", GST_TIME_ARGS (time), key);
+    /* there is not really a way to delete the existing one */
+    if (time != ts || key != ! !keyframe)
+      GST_DEBUG_OBJECT (demux, "metadata mismatch");
+#endif
+    gst_object_unref (index);
+    return;
+  }
+
+  associations[0].format = GST_FORMAT_TIME;
+  associations[0].value = ts;
+  associations[1].format = GST_FORMAT_BYTES;
+  associations[1].value = pos;
+
+  gst_index_add_associationv (index, demux->index_id,
+      (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT :
+      GST_ASSOCIATION_FLAG_DELTA_UNIT, 2,
+      (const GstIndexAssociation *) &associations);
+
+  if (pos > demux->index_max_pos)
+    demux->index_max_pos = pos;
+  if (ts > demux->index_max_time)
+    demux->index_max_time = ts;
+
+  gst_object_unref (index);
+}
+
+static gchar *
+FLV_GET_STRING (GstByteReader * reader)
+{
+  guint16 string_size = 0;
+  gchar *string = NULL;
+  const guint8 *str = NULL;
+
+  g_return_val_if_fail (reader != NULL, NULL);
+
+  if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size)))
+    return NULL;
+
+  if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader)))
+    return NULL;
+
+  string = g_try_malloc0 (string_size + 1);
+  if (G_UNLIKELY (!string)) {
+    return NULL;
+  }
+
+  if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) {
+    g_free (string);
+    return NULL;
+  }
+
+  memcpy (string, str, string_size);
+  if (!g_utf8_validate (string, string_size, NULL)) {
+    g_free (string);
+    return NULL;
+  }
+
+  return string;
+}
+
+static void
+gst_flv_demux_check_seekability (GstFlvDemux * demux)
+{
+  GstQuery *query;
+  gint64 start = -1, stop = -1;
+
+  demux->upstream_seekable = FALSE;
+
+  query = gst_query_new_seeking (GST_FORMAT_BYTES);
+  if (!gst_pad_peer_query (demux->sinkpad, query)) {
+    GST_DEBUG_OBJECT (demux, "seeking query failed");
+    gst_query_unref (query);
+    return;
+  }
+
+  gst_query_parse_seeking (query, NULL, &demux->upstream_seekable,
+      &start, &stop);
+
+  gst_query_unref (query);
+
+  /* try harder to query upstream size if we didn't get it the first time */
+  if (demux->upstream_seekable && stop == -1) {
+    GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
+    gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
+  }
+
+  /* if upstream doesn't know the size, it's likely that it's not seekable in
+   * practice even if it technically may be seekable */
+  if (demux->upstream_seekable && (start != 0 || stop <= start)) {
+    GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
+    demux->upstream_seekable = FALSE;
+  }
+
+  GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
+}
+
+static GstDateTime *
+parse_flv_demux_parse_date_string (const gchar * s)
+{
+  static const gchar months[12][4] = {
+    "Jan", "Feb", "Mar", "Apr",
+    "May", "Jun", "Jul", "Aug",
+    "Sep", "Oct", "Nov", "Dec"
+  };
+  GstDateTime *dt = NULL;
+  gchar **tokens;
+  guint64 d;
+  gchar *endptr, *stripped;
+  gint i, hh, mm, ss;
+  gint year = -1, month = -1, day = -1;
+  gint hour = -1, minute = -1, seconds = -1;
+
+  stripped = g_strstrip (g_strdup (s));
+
+  /* "Fri Oct 15 15:13:16 2004" needs to be parsed */
+  tokens = g_strsplit (stripped, " ", -1);
+
+  g_free (stripped);
+
+  if (g_strv_length (tokens) != 5)
+    goto out;
+
+  /* year */
+  d = g_ascii_strtoull (tokens[4], &endptr, 10);
+  if (d == 0 && *endptr != '\0')
+    goto out;
+
+  year = d;
+
+  /* month */
+  if (strlen (tokens[1]) != 3)
+    goto out;
+  for (i = 0; i < 12; i++) {
+    if (!strcmp (tokens[1], months[i])) {
+      break;
+    }
+  }
+  if (i == 12)
+    goto out;
+
+  month = i + 1;
+
+  /* day */
+  d = g_ascii_strtoull (tokens[2], &endptr, 10);
+  if (d == 0 && *endptr != '\0')
+    goto out;
+
+  day = d;
+
+  /* time */
+  hh = mm = ss = 0;
+  if (sscanf (tokens[3], "%d:%d:%d", &hh, &mm, &ss) < 2)
+    goto out;
+  if (hh >= 0 && hh < 24 && mm >= 0 && mm < 60 && ss >= 0 && ss < 60) {
+    hour = hh;
+    minute = mm;
+    seconds = ss;
+  }
+
+out:
+
+  if (tokens)
+    g_strfreev (tokens);
+
+  if (year > 0)
+    dt = gst_date_time_new (0.0, year, month, day, hour, minute, seconds);
+
+  return dt;
+}
+
+static gboolean
+gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader,
+    gboolean * end_marker)
+{
+  gchar *tag_name = NULL;
+  guint8 tag_type = 0;
+
+  /* Initialize the end_marker flag to FALSE */
+  *end_marker = FALSE;
+
+  /* Name of the tag */
+  tag_name = FLV_GET_STRING (reader);
+  if (G_UNLIKELY (!tag_name)) {
+    GST_WARNING_OBJECT (demux, "failed reading tag name");
+    return FALSE;
+  }
+
+  /* What kind of object is that */
+  if (!gst_byte_reader_get_uint8 (reader, &tag_type))
+    goto error;
+
+  GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
+
+  switch (tag_type) {
+    case 0:                    /* Double */
+    {                           /* Use a union to read the uint64 and then as a double */
+      gdouble d = 0;
+
+      if (!gst_byte_reader_get_float64_be (reader, &d))
+        goto error;
+
+      GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d);
+
+      if (!strcmp (tag_name, "duration")) {
+        demux->duration = d * GST_SECOND;
+
+        gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
+            GST_TAG_DURATION, demux->duration, NULL);
+      } else if (!strcmp (tag_name, "AspectRatioX")) {
+        demux->par_x = d;
+        demux->got_par = TRUE;
+      } else if (!strcmp (tag_name, "AspectRatioY")) {
+        demux->par_y = d;
+        demux->got_par = TRUE;
+      } else if (!strcmp (tag_name, "width")) {
+        demux->w = d;
+      } else if (!strcmp (tag_name, "height")) {
+        demux->h = d;
+      } else if (!strcmp (tag_name, "framerate")) {
+        demux->framerate = d;
+      } else if (!strcmp (tag_name, "audiodatarate")) {
+        gst_tag_list_add (demux->audio_tags, GST_TAG_MERGE_REPLACE,
+            GST_TAG_NOMINAL_BITRATE, (guint) (d * 1024), NULL);
+      } else if (!strcmp (tag_name, "videodatarate")) {
+        gst_tag_list_add (demux->video_tags, GST_TAG_MERGE_REPLACE,
+            GST_TAG_NOMINAL_BITRATE, (guint) (d * 1024), NULL);
+      } else {
+        GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
+      }
+
+      break;
+    }
+    case 1:                    /* Boolean */
+    {
+      guint8 b = 0;
+
+      if (!gst_byte_reader_get_uint8 (reader, &b))
+        goto error;
+
+      GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b);
+
+      GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
+
+      break;
+    }
+    case 2:                    /* String */
+    {
+      gchar *s = NULL;
+
+      s = FLV_GET_STRING (reader);
+      if (s == NULL)
+        goto error;
+
+      GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
+
+      if (!strcmp (tag_name, "creationdate")) {
+        GstDateTime *dt;
+
+        dt = parse_flv_demux_parse_date_string (s);
+        if (dt == NULL) {
+          GST_DEBUG_OBJECT (demux, "Failed to parse '%s' into datetime", s);
+        } else {
+          gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
+              GST_TAG_DATE_TIME, dt, NULL);
+          gst_date_time_unref (dt);
+        }
+      } else if (!strcmp (tag_name, "creator")) {
+        gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
+            GST_TAG_ARTIST, s, NULL);
+      } else if (!strcmp (tag_name, "title")) {
+        gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
+            GST_TAG_TITLE, s, NULL);
+      } else if (!strcmp (tag_name, "metadatacreator")) {
+        gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
+            GST_TAG_ENCODER, s, NULL);
+      } else {
+        GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
+      }
+
+      g_free (s);
+
+      break;
+    }
+    case 3:                    /* Object */
+    {
+      gboolean end_of_object_marker = FALSE;
+
+      while (!end_of_object_marker) {
+        gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
+            &end_of_object_marker);
+
+        if (G_UNLIKELY (!ok)) {
+          GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
+          goto error;
+        }
+      }
+
+      break;
+    }
+    case 8:                    /* ECMA array */
+    {
+      guint32 nb_elems = 0;
+      gboolean end_of_object_marker = FALSE;
+
+      if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
+        goto error;
+
+      GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
+          nb_elems);
+
+      while (!end_of_object_marker) {
+        gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
+            &end_of_object_marker);
+
+        if (G_UNLIKELY (!ok)) {
+          GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
+          goto error;
+        }
+      }
+
+      break;
+    }
+    case 9:                    /* End marker */
+    {
+      GST_DEBUG_OBJECT (demux, "end marker ?");
+      if (tag_name[0] == '\0') {
+
+        GST_DEBUG_OBJECT (demux, "end marker detected");
+
+        *end_marker = TRUE;
+      }
+
+      break;
+    }
+    case 10:                   /* Array */
+    {
+      guint32 nb_elems = 0;
+
+      if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
+        goto error;
+
+      GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
+
+      if (!strcmp (tag_name, "times")) {
+        if (demux->times) {
+          g_array_free (demux->times, TRUE);
+        }
+        demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
+      } else if (!strcmp (tag_name, "filepositions")) {
+        if (demux->filepositions) {
+          g_array_free (demux->filepositions, TRUE);
+        }
+        demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
+      }
+
+      while (nb_elems--) {
+        guint8 elem_type = 0;
+
+        if (!gst_byte_reader_get_uint8 (reader, &elem_type))
+          goto error;
+
+        switch (elem_type) {
+          case 0:
+          {
+            gdouble d;
+
+            if (!gst_byte_reader_get_float64_be (reader, &d))
+              goto error;
+
+            GST_DEBUG_OBJECT (demux, "element is a double %f", d);
+
+            if (!strcmp (tag_name, "times") && demux->times) {
+              g_array_append_val (demux->times, d);
+            } else if (!strcmp (tag_name, "filepositions") &&
+                demux->filepositions) {
+              g_array_append_val (demux->filepositions, d);
+            }
+            break;
+          }
+          default:
+            GST_WARNING_OBJECT (demux, "unsupported array element type %d",
+                elem_type);
+        }
+      }
+
+      break;
+    }
+    case 11:                   /* Date */
+    {
+      gdouble d = 0;
+      gint16 i = 0;
+
+      if (!gst_byte_reader_get_float64_be (reader, &d))
+        goto error;
+
+      if (!gst_byte_reader_get_int16_be (reader, &i))
+        goto error;
+
+      GST_DEBUG_OBJECT (demux,
+          "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
+
+      GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
+
+      break;
+    }
+    default:
+      GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
+  }
+
+  g_free (tag_name);
+
+  return TRUE;
+
+error:
+  g_free (tag_name);
+
+  return FALSE;
+}
+
+static void
+gst_flv_demux_clear_tags (GstFlvDemux * demux)
+{
+  GST_DEBUG_OBJECT (demux, "clearing taglist");
+
+  if (demux->taglist) {
+    gst_tag_list_unref (demux->taglist);
+  }
+  demux->taglist = gst_tag_list_new_empty ();
+  gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
+
+  if (demux->audio_tags) {
+    gst_tag_list_unref (demux->audio_tags);
+  }
+  demux->audio_tags = gst_tag_list_new_empty ();
+
+  if (demux->video_tags) {
+    gst_tag_list_unref (demux->video_tags);
+  }
+  demux->video_tags = gst_tag_list_new_empty ();
+}
+
+static GstFlowReturn
+gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstByteReader reader;
+  guint8 type = 0;
+  GstMapInfo map;
+
+  g_return_val_if_fail (gst_buffer_get_size (buffer) >= 7, GST_FLOW_ERROR);
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  gst_byte_reader_init (&reader, map.data, map.size);
+
+  gst_byte_reader_skip_unchecked (&reader, 7);
+
+  GST_LOG_OBJECT (demux, "parsing a script tag");
+
+  if (!gst_byte_reader_get_uint8 (&reader, &type))
+    goto cleanup;
+
+  /* Must be string */
+  if (type == 2) {
+    gchar *function_name;
+    guint i;
+
+    function_name = FLV_GET_STRING (&reader);
+
+    GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
+
+    if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
+      gboolean end_marker = FALSE;
+      GST_DEBUG_OBJECT (demux, "we have a metadata script object");
+
+      gst_flv_demux_clear_tags (demux);
+
+      if (!gst_byte_reader_get_uint8 (&reader, &type)) {
+        g_free (function_name);
+        goto cleanup;
+      }
+
+      switch (type) {
+        case 8:
+        {
+          guint32 nb_elems = 0;
+
+          /* ECMA array */
+          if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
+            g_free (function_name);
+            goto cleanup;
+          }
+
+          /* The number of elements is just a hint, some files have
+             nb_elements == 0 and actually contain items. */
+          GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
+              nb_elems);
+        }
+          /* fallthrough to read data */
+        case 3:
+        {
+          /* Object */
+          while (!end_marker) {
+            gboolean ok =
+                gst_flv_demux_parse_metadata_item (demux, &reader, &end_marker);
+
+            if (G_UNLIKELY (!ok)) {
+              GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
+              break;
+            }
+          }
+        }
+          break;
+        default:
+          GST_DEBUG_OBJECT (demux, "Unhandled script data type : %d", type);
+          g_free (function_name);
+          goto cleanup;
+      }
+
+      gst_flv_demux_push_tags (demux);
+    }
+
+    g_free (function_name);
+
+    if (demux->times && demux->filepositions) {
+      guint num;
+
+      /* If an index was found, insert associations */
+      num = MIN (demux->times->len, demux->filepositions->len);
+      for (i = 0; i < num; i++) {
+        guint64 time, fileposition;
+
+        time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
+        fileposition = g_array_index (demux->filepositions, gdouble, i);
+        gst_flv_demux_parse_and_add_index_entry (demux, time, fileposition,
+            TRUE);
+      }
+      demux->indexed = TRUE;
+    }
+  }
+
+cleanup:
+  gst_buffer_unmap (buffer, &map);
+
+  return ret;
+}
+
+static gboolean
+have_group_id (GstFlvDemux * demux)
+{
+  GstEvent *event;
+
+  event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
+  if (event) {
+    if (gst_event_parse_group_id (event, &demux->group_id))
+      demux->have_group_id = TRUE;
+    else
+      demux->have_group_id = FALSE;
+    gst_event_unref (event);
+  } else if (!demux->have_group_id) {
+    demux->have_group_id = TRUE;
+    demux->group_id = gst_util_group_id_next ();
+  }
+
+  return demux->have_group_id;
+}
+
+static gboolean
+gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
+    guint32 rate, guint32 channels, guint32 width)
+{
+  GstCaps *caps = NULL, *old_caps;
+  gboolean ret = FALSE;
+  guint adjusted_rate = rate;
+  GstEvent *event;
+  gchar *stream_id;
+
+  switch (codec_tag) {
+    case 1:
+      caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
+          "swf", NULL);
+      break;
+    case 2:
+    case 14:
+      caps = gst_caps_new_simple ("audio/mpeg",
+          "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
+          "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
+      break;
+    case 0:
+    case 3:
+    {
+      GstAudioFormat format;
+
+      /* Assuming little endian for 0 (aka endianness of the
+       * system on which the file was created) as most people
+       * are probably using little endian machines */
+      format = gst_audio_format_build_integer ((width == 8) ? FALSE : TRUE,
+          G_LITTLE_ENDIAN, width, width);
+
+      caps = gst_caps_new_simple ("audio/x-raw",
+          "format", G_TYPE_STRING, gst_audio_format_to_string (format),
+          "layout", G_TYPE_STRING, "interleaved", NULL);
+      break;
+    }
+    case 4:
+    case 5:
+    case 6:
+      caps = gst_caps_new_empty_simple ("audio/x-nellymoser");
+      break;
+    case 10:
+    {
+      GstMapInfo map;
+      if (!demux->audio_codec_data) {
+        GST_DEBUG_OBJECT (demux, "don't have AAC codec data yet");
+        ret = TRUE;
+        goto done;
+      }
+
+      gst_buffer_map (demux->audio_codec_data, &map, GST_MAP_READ);
+
+      /* use codec-data to extract and verify samplerate */
+      if (map.size >= 2) {
+        gint freq_index;
+
+        freq_index = GST_READ_UINT16_BE (map.data);
+        freq_index = (freq_index & 0x0780) >> 7;
+        adjusted_rate =
+            gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
+
+        if (adjusted_rate && (rate != adjusted_rate)) {
+          GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
+              adjusted_rate);
+        } else {
+          adjusted_rate = rate;
+        }
+      }
+      gst_buffer_unmap (demux->audio_codec_data, &map);
+
+      caps = gst_caps_new_simple ("audio/mpeg",
+          "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
+          "stream-format", G_TYPE_STRING, "raw", NULL);
+      break;
+    }
+    case 7:
+      caps = gst_caps_new_empty_simple ("audio/x-alaw");
+      break;
+    case 8:
+      caps = gst_caps_new_empty_simple ("audio/x-mulaw");
+      break;
+    case 11:
+    {
+      GValue streamheader = G_VALUE_INIT;
+      GValue value = G_VALUE_INIT;
+      GstByteWriter w;
+      GstStructure *structure;
+      GstBuffer *buf;
+      GstTagList *tags;
+
+      caps = gst_caps_new_empty_simple ("audio/x-speex");
+      structure = gst_caps_get_structure (caps, 0);
+
+      GST_DEBUG_OBJECT (demux, "generating speex header");
+
+      /* Speex decoder expects streamheader to be { [header], [comment] } */
+      g_value_init (&streamheader, GST_TYPE_ARRAY);
+
+      /* header part */
+      gst_byte_writer_init_with_size (&w, 80, TRUE);
+      gst_byte_writer_put_data (&w, (guint8 *) "Speex   ", 8);
+      gst_byte_writer_put_data (&w, (guint8 *) "1.1.12", 7);
+      gst_byte_writer_fill (&w, 0, 13);
+      gst_byte_writer_put_uint32_le (&w, 1);    /* version */
+      gst_byte_writer_put_uint32_le (&w, 80);   /* header_size */
+      gst_byte_writer_put_uint32_le (&w, 16000);        /* rate */
+      gst_byte_writer_put_uint32_le (&w, 1);    /* mode: Wideband */
+      gst_byte_writer_put_uint32_le (&w, 4);    /* mode_bitstream_version */
+      gst_byte_writer_put_uint32_le (&w, 1);    /* nb_channels: 1 */
+      gst_byte_writer_put_uint32_le (&w, -1);   /* bitrate */
+      gst_byte_writer_put_uint32_le (&w, 0x50); /* frame_size */
+      gst_byte_writer_put_uint32_le (&w, 0);    /* VBR */
+      gst_byte_writer_put_uint32_le (&w, 1);    /* frames_per_packet */
+      gst_byte_writer_put_uint32_le (&w, 0);    /* extra_headers */
+      gst_byte_writer_put_uint32_le (&w, 0);    /* reserved1 */
+      gst_byte_writer_put_uint32_le (&w, 0);    /* reserved2 */
+      g_assert (gst_byte_writer_get_size (&w) == 80);
+
+      g_value_init (&value, GST_TYPE_BUFFER);
+      g_value_take_boxed (&value, gst_byte_writer_reset_and_get_buffer (&w));
+      gst_value_array_append_value (&streamheader, &value);
+      g_value_unset (&value);
+
+      /* comment part */
+      g_value_init (&value, GST_TYPE_BUFFER);
+      tags = gst_tag_list_new_empty ();
+      buf = gst_tag_list_to_vorbiscomment_buffer (tags, NULL, 0, "No comments");
+      gst_tag_list_unref (tags);
+      g_value_take_boxed (&value, buf);
+      gst_value_array_append_value (&streamheader, &value);
+      g_value_unset (&value);
+
+      gst_structure_take_value (structure, "streamheader", &streamheader);
+
+      channels = 1;
+      adjusted_rate = 16000;
+      break;
+    }
+    default:
+      GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
+      break;
+  }
+
+  if (G_UNLIKELY (!caps)) {
+    GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
+    goto beach;
+  }
+
+  gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
+      "channels", G_TYPE_INT, channels, NULL);
+
+  if (demux->audio_codec_data) {
+    gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
+        demux->audio_codec_data, NULL);
+  }
+
+  old_caps = gst_pad_get_current_caps (demux->audio_pad);
+  if (!old_caps) {
+    stream_id =
+        gst_pad_create_stream_id (demux->audio_pad, GST_ELEMENT_CAST (demux),
+        "audio");
+
+    event = gst_event_new_stream_start (stream_id);
+    if (have_group_id (demux))
+      gst_event_set_group_id (event, demux->group_id);
+    gst_pad_push_event (demux->audio_pad, event);
+    g_free (stream_id);
+  }
+  if (!old_caps || !gst_caps_is_equal (old_caps, caps))
+    ret = gst_pad_set_caps (demux->audio_pad, caps);
+  else
+    ret = TRUE;
+
+  if (old_caps)
+    gst_caps_unref (old_caps);
+
+done:
+  if (G_LIKELY (ret)) {
+    /* Store the caps we got from tags */
+    demux->audio_codec_tag = codec_tag;
+    demux->rate = rate;
+    demux->channels = channels;
+    demux->width = width;
+
+    if (caps) {
+      GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
+          GST_PTR_FORMAT, caps);
+
+      gst_flv_demux_push_tags (demux);
+    } else {
+      GST_DEBUG_OBJECT (demux->audio_pad, "delayed setting caps");
+    }
+  } else {
+    GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
+        GST_PTR_FORMAT, caps);
+  }
+
+  if (caps)
+    gst_caps_unref (caps);
+
+beach:
+  return ret;
+}
+
+static gboolean
+gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
+{
+  gboolean ret = TRUE;
+
+  if (demux->audio_pad)
+    ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
+
+  if (demux->video_pad)
+    ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
+
+  gst_event_unref (event);
+
+  return ret;
+}
+
+static void
+gst_flv_demux_add_codec_tag (GstFlvDemux * demux, const gchar * tag,
+    GstPad * pad)
+{
+  if (pad) {
+    GstCaps *caps = gst_pad_get_current_caps (pad);
+
+    if (caps) {
+      gchar *codec_name = gst_pb_utils_get_codec_description (caps);
+
+      if (codec_name) {
+        gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
+            tag, codec_name, NULL);
+        g_free (codec_name);
+      }
+
+      gst_caps_unref (caps);
+    }
+  }
+}
+
+static void
+gst_flv_demux_push_tags (GstFlvDemux * demux)
+{
+  gst_flv_demux_add_codec_tag (demux, GST_TAG_AUDIO_CODEC, demux->audio_pad);
+  gst_flv_demux_add_codec_tag (demux, GST_TAG_VIDEO_CODEC, demux->video_pad);
+
+  GST_DEBUG_OBJECT (demux, "pushing %" GST_PTR_FORMAT, demux->taglist);
+
+  gst_flv_demux_push_src_event (demux,
+      gst_event_new_tag (gst_tag_list_copy (demux->taglist)));
+
+  if (demux->audio_pad) {
+    GST_DEBUG_OBJECT (demux->audio_pad, "pushing audio %" GST_PTR_FORMAT,
+        demux->audio_tags);
+    gst_pad_push_event (demux->audio_pad,
+        gst_event_new_tag (gst_tag_list_copy (demux->audio_tags)));
+  }
+
+  if (demux->video_pad) {
+    GST_DEBUG_OBJECT (demux->video_pad, "pushing video %" GST_PTR_FORMAT,
+        demux->video_tags);
+    gst_pad_push_event (demux->video_pad,
+        gst_event_new_tag (gst_tag_list_copy (demux->video_tags)));
+  }
+}
+
+static gboolean
+gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 dts, gboolean discont,
+    guint32 * last, GstClockTime * offset)
+{
+  gboolean ret = FALSE;
+  gint32 ddts = dts - *last;
+  if (!discont && ddts <= -RESYNC_THRESHOLD) {
+    /* Theoretically, we should use substract the duration of the last buffer,
+       but this demuxer sends no durations on buffers, not sure if it cannot
+       know, or just does not care to calculate. */
+    *offset -= ddts * GST_MSECOND;
+    GST_WARNING_OBJECT (demux,
+        "Large dts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
+        GST_TIME_FORMAT "", ddts, GST_TIME_ARGS (*offset));
+
+    ret = TRUE;
+  }
+  *last = dts;
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
+  guint32 codec_data = 0, pts_ext = 0;
+  guint8 flags = 0;
+  GstMapInfo map;
+  GstBuffer *outbuf;
+  guint8 *data;
+
+  GST_LOG_OBJECT (demux, "parsing an audio tag");
+
+  if (G_UNLIKELY (!demux->audio_pad && demux->no_more_pads)) {
+#ifndef GST_DISABLE_DEBUG
+    if (G_UNLIKELY (!demux->no_audio_warned)) {
+      GST_WARNING_OBJECT (demux,
+          "Signaled no-more-pads already but had no audio pad -- ignoring");
+      demux->no_audio_warned = TRUE;
+    }
+#endif
+    return GST_FLOW_OK;
+  }
+
+  g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
+      GST_FLOW_ERROR);
+
+  /* Error out on tags with too small headers */
+  if (gst_buffer_get_size (buffer) < 11) {
+    GST_ERROR_OBJECT (demux, "Too small tag size (%" G_GSIZE_FORMAT ")",
+        gst_buffer_get_size (buffer));
+    return GST_FLOW_ERROR;
+  }
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  data = map.data;
+
+  /* Grab information about audio tag */
+  pts = GST_READ_UINT24_BE (data);
+  /* read the pts extension to 32 bits integer */
+  pts_ext = GST_READ_UINT8 (data + 3);
+  /* Combine them */
+  pts |= pts_ext << 24;
+
+  GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
+      data[2], data[3], pts);
+
+  /* Skip the stream id and go directly to the flags */
+  flags = GST_READ_UINT8 (data + 7);
+
+  /* Silently skip buffers with no data */
+  if (map.size == 11)
+    goto beach;
+
+  /* Channels */
+  if (flags & 0x01) {
+    channels = 2;
+  }
+  /* Width */
+  if (flags & 0x02) {
+    width = 16;
+  }
+  /* Sampling rate */
+  if ((flags & 0x0C) == 0x0C) {
+    rate = 44100;
+  } else if ((flags & 0x0C) == 0x08) {
+    rate = 22050;
+  } else if ((flags & 0x0C) == 0x04) {
+    rate = 11025;
+  }
+  /* Codec tag */
+  codec_tag = flags >> 4;
+  if (codec_tag == 10) {        /* AAC has an extra byte for packet type */
+    codec_data = 2;
+  } else {
+    codec_data = 1;
+  }
+
+  /* codec tags with special rates */
+  if (codec_tag == 5 || codec_tag == 14)
+    rate = 8000;
+  else if ((codec_tag == 4) || (codec_tag == 11))
+    rate = 16000;
+
+  GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
+      "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
+      codec_tag, flags);
+
+  if (codec_tag == 10) {
+    guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
+
+    switch (aac_packet_type) {
+      case 0:
+      {
+        /* AudioSpecificConfig data */
+        GST_LOG_OBJECT (demux, "got an AAC codec data packet");
+        if (demux->audio_codec_data) {
+          gst_buffer_unref (demux->audio_codec_data);
+        }
+        demux->audio_codec_data =
+            gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
+            7 + codec_data, demux->tag_data_size - codec_data);
+
+        /* Use that buffer data in the caps */
+        if (demux->audio_pad)
+          gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
+              width);
+        goto beach;
+      }
+      case 1:
+        if (!demux->audio_codec_data) {
+          GST_ERROR_OBJECT (demux, "got AAC audio packet before codec data");
+          ret = GST_FLOW_OK;
+          goto beach;
+        }
+        /* AAC raw packet */
+        GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
+        break;
+      default:
+        GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
+            aac_packet_type);
+    }
+  }
+
+  /* If we don't have our audio pad created, then create it. */
+  if (G_UNLIKELY (!demux->audio_pad)) {
+    demux->audio_pad =
+        gst_pad_new_from_template (gst_element_class_get_pad_template
+        (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
+    if (G_UNLIKELY (!demux->audio_pad)) {
+      GST_WARNING_OBJECT (demux, "failed creating audio pad");
+      ret = GST_FLOW_ERROR;
+      goto beach;
+    }
+
+    /* Set functions on the pad */
+    gst_pad_set_query_function (demux->audio_pad,
+        GST_DEBUG_FUNCPTR (gst_flv_demux_query));
+    gst_pad_set_event_function (demux->audio_pad,
+        GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
+
+    gst_pad_use_fixed_caps (demux->audio_pad);
+
+    /* Make it active */
+    gst_pad_set_active (demux->audio_pad, TRUE);
+
+    /* Negotiate caps */
+    if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
+            width)) {
+      gst_object_unref (demux->audio_pad);
+      demux->audio_pad = NULL;
+      ret = GST_FLOW_ERROR;
+      goto beach;
+    }
+#ifndef GST_DISABLE_GST_DEBUG
+    {
+      GstCaps *caps;
+
+      caps = gst_pad_get_current_caps (demux->audio_pad);
+      GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
+          caps);
+      if (caps)
+        gst_caps_unref (caps);
+    }
+#endif
+
+    /* We need to set caps before adding */
+    gst_element_add_pad (GST_ELEMENT (demux),
+        gst_object_ref (demux->audio_pad));
+    gst_flow_combiner_add_pad (demux->flowcombiner, demux->audio_pad);
+
+    /* We only emit no more pads when we have audio and video. Indeed we can
+     * not trust the FLV header to tell us if there will be only audio or
+     * only video and we would just break discovery of some files */
+    if (demux->audio_pad && demux->video_pad) {
+      GST_DEBUG_OBJECT (demux, "emitting no more pads");
+      gst_element_no_more_pads (GST_ELEMENT (demux));
+      demux->no_more_pads = TRUE;
+    }
+  }
+
+  /* Check if caps have changed */
+  if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
+          codec_tag != demux->audio_codec_tag || width != demux->width)) {
+    GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
+
+    gst_buffer_replace (&demux->audio_codec_data, NULL);
+
+    /* Negotiate caps */
+    if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
+            width)) {
+      ret = GST_FLOW_ERROR;
+      goto beach;
+    }
+  }
+
+  /* Check if we have anything to push */
+  if (demux->tag_data_size <= codec_data) {
+    GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
+    goto beach;
+  }
+
+  /* Create buffer from pad */
+  outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
+      7 + codec_data, demux->tag_data_size - codec_data);
+
+  /* detect (and deem to be resyncs)  large pts gaps */
+  if (gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
+          &demux->last_audio_pts, &demux->audio_time_offset)) {
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+  }
+
+  /* Fill buffer with data */
+  GST_BUFFER_PTS (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
+  GST_BUFFER_DTS (outbuf) = GST_BUFFER_PTS (outbuf);
+  GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
+  GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
+  GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
+
+  if (demux->duration == GST_CLOCK_TIME_NONE ||
+      demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
+    demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
+
+  /* Only add audio frames to the index if we have no video,
+   * and if the index is not yet complete */
+  if (!demux->has_video && !demux->indexed) {
+    gst_flv_demux_parse_and_add_index_entry (demux,
+        GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
+  }
+
+  if (G_UNLIKELY (demux->audio_need_discont)) {
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+    demux->audio_need_discont = FALSE;
+  }
+
+  demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
+
+  /* Do we need a newsegment event ? */
+  if (G_UNLIKELY (demux->audio_need_segment)) {
+    if (!demux->new_seg_event) {
+      GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
+          GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (demux->segment.position),
+          GST_TIME_ARGS (demux->segment.stop));
+      demux->segment.start = demux->segment.time = demux->segment.position;
+      demux->new_seg_event = gst_event_new_segment (&demux->segment);
+    } else {
+      GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
+    }
+
+    gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
+
+    demux->audio_need_segment = FALSE;
+  }
+
+  GST_LOG_OBJECT (demux,
+      "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
+      " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
+      gst_buffer_get_size (outbuf),
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
+      GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
+
+  if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
+    demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
+  }
+  if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
+    demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
+  }
+
+  if (G_UNLIKELY (!demux->no_more_pads
+          && (GST_CLOCK_DIFF (demux->audio_start,
+                  GST_BUFFER_TIMESTAMP (outbuf)) > NO_MORE_PADS_THRESHOLD))) {
+    GST_DEBUG_OBJECT (demux,
+        "Signalling no-more-pads because no video stream was found"
+        " after 6 seconds of audio");
+    gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
+    demux->no_more_pads = TRUE;
+  }
+
+  /* Push downstream */
+  ret = gst_pad_push (demux->audio_pad, outbuf);
+
+  if (G_UNLIKELY (ret != GST_FLOW_OK) &&
+      demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
+      demux->segment.position > demux->segment.stop) {
+    /* In reverse playback we can get a GST_FLOW_EOS when
+     * we are at the end of the segment, so we just need to jump
+     * back to the previous section. */
+    GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
+    demux->audio_done = TRUE;
+    ret = GST_FLOW_OK;
+    goto beach;
+  }
+
+  ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner,
+      demux->audio_pad, ret);
+
+beach:
+  gst_buffer_unmap (buffer, &map);
+
+  return ret;
+}
+
+static gboolean
+gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
+{
+  gboolean ret = FALSE;
+  GstCaps *caps = NULL, *old_caps;
+  GstEvent *event;
+  gchar *stream_id;
+
+  /* Generate caps for that pad */
+  switch (codec_tag) {
+    case 2:
+      caps =
+          gst_caps_new_simple ("video/x-flash-video", "flvversion", G_TYPE_INT,
+          1, NULL);
+      break;
+    case 3:
+      caps = gst_caps_new_empty_simple ("video/x-flash-screen");
+      break;
+    case 4:
+      caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
+      break;
+    case 5:
+      caps = gst_caps_new_empty_simple ("video/x-vp6-alpha");
+      break;
+    case 7:
+      if (!demux->video_codec_data) {
+        GST_DEBUG_OBJECT (demux, "don't have h264 codec data yet");
+        ret = TRUE;
+        goto done;
+      }
+      caps =
+          gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
+          "avc", NULL);
+      break;
+      /* The following two are non-standard but apparently used, see in ffmpeg
+       * https://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavformat/flvdec.c;h=2bf1e059e1cbeeb79e4af9542da23f4560e1cf59;hb=b18d6c58000beed872d6bb1fe7d0fbe75ae26aef#l254
+       * https://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavformat/flvdec.c;h=2bf1e059e1cbeeb79e4af9542da23f4560e1cf59;hb=b18d6c58000beed872d6bb1fe7d0fbe75ae26aef#l282
+       */
+    case 8:
+      caps = gst_caps_new_empty_simple ("video/x-h263");
+      break;
+    case 9:
+      caps =
+          gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
+          "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+      break;
+    default:
+      GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
+  }
+
+  if (G_UNLIKELY (!caps)) {
+    GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
+    goto beach;
+  }
+
+  if (demux->got_par) {
+    gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+        demux->par_x, demux->par_y, NULL);
+  }
+
+  if (G_LIKELY (demux->w)) {
+    gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
+  }
+
+  if (G_LIKELY (demux->h)) {
+    gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
+  }
+
+  if (G_LIKELY (demux->framerate)) {
+    gint num = 0, den = 0;
+
+    gst_video_guess_framerate (GST_SECOND / demux->framerate, &num, &den);
+    GST_DEBUG_OBJECT (demux->video_pad,
+        "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
+        num, den);
+
+    gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
+  }
+
+  if (demux->video_codec_data) {
+    gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
+        demux->video_codec_data, NULL);
+  }
+
+  old_caps = gst_pad_get_current_caps (demux->video_pad);
+  if (!old_caps) {
+    stream_id =
+        gst_pad_create_stream_id (demux->video_pad, GST_ELEMENT_CAST (demux),
+        "video");
+    event = gst_event_new_stream_start (stream_id);
+    g_free (stream_id);
+
+    if (have_group_id (demux))
+      gst_event_set_group_id (event, demux->group_id);
+    gst_pad_push_event (demux->video_pad, event);
+  }
+
+  if (!old_caps || !gst_caps_is_equal (old_caps, caps))
+    ret = gst_pad_set_caps (demux->video_pad, caps);
+  else
+    ret = TRUE;
+
+  if (old_caps)
+    gst_caps_unref (old_caps);
+
+done:
+  if (G_LIKELY (ret)) {
+    /* Store the caps we have set */
+    demux->video_codec_tag = codec_tag;
+
+    if (caps) {
+      GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
+          GST_PTR_FORMAT, caps);
+
+      gst_flv_demux_push_tags (demux);
+    } else {
+      GST_DEBUG_OBJECT (demux->video_pad, "delayed setting caps");
+    }
+  } else {
+    GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
+        GST_PTR_FORMAT, caps);
+  }
+
+  if (caps)
+    gst_caps_unref (caps);
+
+beach:
+  return ret;
+}
+
+static GstFlowReturn
+gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint32 dts = 0, codec_data = 1, dts_ext = 0;
+  gint32 cts = 0;
+  gboolean keyframe = FALSE;
+  guint8 flags = 0, codec_tag = 0;
+  GstBuffer *outbuf;
+  GstMapInfo map;
+  guint8 *data;
+
+  g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
+      GST_FLOW_ERROR);
+
+  GST_LOG_OBJECT (demux, "parsing a video tag");
+
+  if G_UNLIKELY
+    (!demux->video_pad && demux->no_more_pads) {
+#ifndef GST_DISABLE_DEBUG
+    if G_UNLIKELY
+      (!demux->no_video_warned) {
+      GST_WARNING_OBJECT (demux,
+          "Signaled no-more-pads already but had no video pad -- ignoring");
+      demux->no_video_warned = TRUE;
+      }
+#endif
+    return GST_FLOW_OK;
+    }
+
+  if (gst_buffer_get_size (buffer) < 12) {
+    GST_ERROR_OBJECT (demux, "Too small tag size");
+    return GST_FLOW_ERROR;
+  }
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  data = map.data;
+
+  /* Grab information about video tag */
+  dts = GST_READ_UINT24_BE (data);
+  /* read the dts extension to 32 bits integer */
+  dts_ext = GST_READ_UINT8 (data + 3);
+  /* Combine them */
+  dts |= dts_ext << 24;
+
+  GST_LOG_OBJECT (demux, "dts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
+      data[2], data[3], dts);
+
+  /* Skip the stream id and go directly to the flags */
+  flags = GST_READ_UINT8 (data + 7);
+
+  /* Keyframe */
+  if ((flags >> 4) == 1) {
+    keyframe = TRUE;
+  }
+  /* Codec tag */
+  codec_tag = flags & 0x0F;
+  if (codec_tag == 4 || codec_tag == 5) {
+    codec_data = 2;
+  } else if (codec_tag == 7) {
+    codec_data = 5;
+
+    cts = GST_READ_UINT24_BE (data + 9);
+    cts = (cts + 0xff800000) ^ 0xff800000;
+
+    if (cts < 0 && ABS (cts) > dts) {
+      GST_ERROR_OBJECT (demux, "Detected a negative composition time offset "
+          "'%d' that would lead to negative PTS, fixing", cts);
+      cts += ABS (cts) - dts;
+    }
+
+    GST_LOG_OBJECT (demux, "got cts %d", cts);
+  }
+
+  GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
+      "(flags %02X)", codec_tag, keyframe, flags);
+
+  if (codec_tag == 7) {
+    guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
+
+    switch (avc_packet_type) {
+      case 0:
+      {
+        if (demux->tag_data_size < codec_data) {
+          GST_ERROR_OBJECT (demux, "Got invalid H.264 codec, ignoring.");
+          break;
+        }
+
+        /* AVCDecoderConfigurationRecord data */
+        GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
+        if (demux->video_codec_data) {
+          gst_buffer_unref (demux->video_codec_data);
+        }
+        demux->video_codec_data = gst_buffer_copy_region (buffer,
+            GST_BUFFER_COPY_MEMORY, 7 + codec_data,
+            demux->tag_data_size - codec_data);;
+        /* Use that buffer data in the caps */
+        if (demux->video_pad)
+          gst_flv_demux_video_negotiate (demux, codec_tag);
+        goto beach;
+      }
+      case 1:
+        /* H.264 NALU packet */
+        if (!demux->video_codec_data) {
+          GST_ERROR_OBJECT (demux, "got H.264 video packet before codec data");
+          ret = GST_FLOW_OK;
+          goto beach;
+        }
+        GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
+        break;
+      default:
+        GST_WARNING_OBJECT (demux, "invalid video packet type %u",
+            avc_packet_type);
+    }
+  }
+
+  /* If we don't have our video pad created, then create it. */
+  if (G_UNLIKELY (!demux->video_pad)) {
+    demux->video_pad =
+        gst_pad_new_from_template (gst_element_class_get_pad_template
+        (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
+    if (G_UNLIKELY (!demux->video_pad)) {
+      GST_WARNING_OBJECT (demux, "failed creating video pad");
+      ret = GST_FLOW_ERROR;
+      goto beach;
+    }
+
+    /* Set functions on the pad */
+    gst_pad_set_query_function (demux->video_pad,
+        GST_DEBUG_FUNCPTR (gst_flv_demux_query));
+    gst_pad_set_event_function (demux->video_pad,
+        GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
+
+    gst_pad_use_fixed_caps (demux->video_pad);
+
+    /* Make it active */
+    gst_pad_set_active (demux->video_pad, TRUE);
+
+    /* Needs to be active before setting caps */
+    if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
+      gst_object_unref (demux->video_pad);
+      demux->video_pad = NULL;
+      ret = GST_FLOW_ERROR;
+      goto beach;
+    }
+
+    /* When we ve set pixel-aspect-ratio we use that boolean to detect a
+     * metadata tag that would come later and trigger a caps change */
+    demux->got_par = FALSE;
+
+#ifndef GST_DISABLE_GST_DEBUG
+    {
+      GstCaps *caps;
+
+      caps = gst_pad_get_current_caps (demux->video_pad);
+      GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
+          caps);
+      if (caps)
+        gst_caps_unref (caps);
+    }
+#endif
+
+    /* We need to set caps before adding */
+    gst_element_add_pad (GST_ELEMENT (demux),
+        gst_object_ref (demux->video_pad));
+    gst_flow_combiner_add_pad (demux->flowcombiner, demux->video_pad);
+
+    /* We only emit no more pads when we have audio and video. Indeed we can
+     * not trust the FLV header to tell us if there will be only audio or
+     * only video and we would just break discovery of some files */
+    if (demux->audio_pad && demux->video_pad) {
+      GST_DEBUG_OBJECT (demux, "emitting no more pads");
+      gst_element_no_more_pads (GST_ELEMENT (demux));
+      demux->no_more_pads = TRUE;
+    }
+  }
+
+  /* Check if caps have changed */
+  if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
+    GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
+    gst_buffer_replace (&demux->video_codec_data, NULL);
+
+    if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
+      ret = GST_FLOW_ERROR;
+      goto beach;
+    }
+
+    /* When we ve set pixel-aspect-ratio we use that boolean to detect a
+     * metadata tag that would come later and trigger a caps change */
+    demux->got_par = FALSE;
+  }
+
+  /* Check if we have anything to push */
+  if (demux->tag_data_size <= codec_data) {
+    GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
+    goto beach;
+  }
+
+  /* Create buffer from pad */
+  outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
+      7 + codec_data, demux->tag_data_size - codec_data);
+
+  /* detect (and deem to be resyncs)  large dts gaps */
+  if (gst_flv_demux_update_resync (demux, dts, demux->video_need_discont,
+          &demux->last_video_dts, &demux->video_time_offset)) {
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+  }
+
+  /* Fill buffer with data */
+  GST_LOG_OBJECT (demux, "dts %u pts %u cts %d", dts, dts + cts, cts);
+
+  GST_BUFFER_PTS (outbuf) =
+      (dts + cts) * GST_MSECOND + demux->video_time_offset;
+  GST_BUFFER_DTS (outbuf) = dts * GST_MSECOND + demux->video_time_offset;
+  GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
+  GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
+  GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
+
+  if (demux->duration == GST_CLOCK_TIME_NONE ||
+      demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
+    demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
+
+  if (!keyframe)
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+  if (!demux->indexed) {
+    gst_flv_demux_parse_and_add_index_entry (demux,
+        GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
+  }
+
+  if (G_UNLIKELY (demux->video_need_discont)) {
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+    demux->video_need_discont = FALSE;
+  }
+
+  demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
+
+  /* Do we need a newsegment event ? */
+  if (G_UNLIKELY (demux->video_need_segment)) {
+    if (!demux->new_seg_event) {
+      GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
+          GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (demux->segment.position),
+          GST_TIME_ARGS (demux->segment.stop));
+      demux->segment.start = demux->segment.time = demux->segment.position;
+      demux->new_seg_event = gst_event_new_segment (&demux->segment);
+    } else {
+      GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
+    }
+
+    gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
+
+    demux->video_need_segment = FALSE;
+  }
+
+  GST_LOG_OBJECT (demux,
+      "pushing %" G_GSIZE_FORMAT " bytes buffer at dts %" GST_TIME_FORMAT
+      " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
+      ", keyframe (%d)", gst_buffer_get_size (outbuf),
+      GST_TIME_ARGS (GST_BUFFER_DTS (outbuf)),
+      GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
+      keyframe);
+
+  if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
+    demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
+  }
+  if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
+    demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
+  }
+
+  if (G_UNLIKELY (!demux->no_more_pads
+          && (GST_CLOCK_DIFF (demux->video_start,
+                  GST_BUFFER_TIMESTAMP (outbuf)) > NO_MORE_PADS_THRESHOLD))) {
+    GST_DEBUG_OBJECT (demux,
+        "Signalling no-more-pads because no audio stream was found"
+        " after 6 seconds of video");
+    gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
+    demux->no_more_pads = TRUE;
+  }
+
+  /* Push downstream */
+  ret = gst_pad_push (demux->video_pad, outbuf);
+
+  if (G_UNLIKELY (ret != GST_FLOW_OK) &&
+      demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
+      demux->segment.position > demux->segment.stop) {
+    /* In reverse playback we can get a GST_FLOW_EOS when
+     * we are at the end of the segment, so we just need to jump
+     * back to the previous section. */
+    GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
+    demux->video_done = TRUE;
+    ret = GST_FLOW_OK;
+    goto beach;
+  }
+
+  ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner,
+      demux->video_pad, ret);
+
+beach:
+  gst_buffer_unmap (buffer, &map);
+  return ret;
+}
+
+static GstClockTime
+gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
+    GstBuffer * buffer, size_t * tag_size)
+{
+  guint32 dts = 0, dts_ext = 0;
+  guint32 tag_data_size;
+  guint8 type;
+  gboolean keyframe = TRUE;
+  GstClockTime ret = GST_CLOCK_TIME_NONE;
+  GstMapInfo map;
+  guint8 *data;
+  gsize size;
+
+  g_return_val_if_fail (gst_buffer_get_size (buffer) >= 12,
+      GST_CLOCK_TIME_NONE);
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  data = map.data;
+  size = map.size;
+
+  type = data[0];
+
+  if (type != 9 && type != 8 && type != 18) {
+    GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
+    goto exit;
+  }
+
+  if (type == 9)
+    demux->has_video = TRUE;
+  else if (type == 8)
+    demux->has_audio = TRUE;
+
+  tag_data_size = GST_READ_UINT24_BE (data + 1);
+
+  if (size >= tag_data_size + 11 + 4) {
+    if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
+      GST_WARNING_OBJECT (demux, "Invalid tag size");
+      goto exit;
+    }
+  }
+
+  if (tag_size)
+    *tag_size = tag_data_size + 11 + 4;
+
+  data += 4;
+
+  GST_LOG_OBJECT (demux, "dts bytes %02X %02X %02X %02X", data[0], data[1],
+      data[2], data[3]);
+
+  /* Grab timestamp of tag tag */
+  dts = GST_READ_UINT24_BE (data);
+  /* read the dts extension to 32 bits integer */
+  dts_ext = GST_READ_UINT8 (data + 3);
+  /* Combine them */
+  dts |= dts_ext << 24;
+
+  if (type == 9) {
+    data += 7;
+
+    keyframe = ((data[0] >> 4) == 1);
+  }
+
+  ret = dts * GST_MSECOND;
+  GST_LOG_OBJECT (demux, "dts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
+
+  if (index && !demux->indexed && (type == 9 || (type == 8
+              && !demux->has_video))) {
+    gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
+        keyframe);
+  }
+
+  if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
+    demux->duration = ret;
+
+exit:
+  gst_buffer_unmap (buffer, &map);
+  return ret;
+}
+
+static GstFlowReturn
+gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint8 tag_type = 0;
+  GstMapInfo map;
+
+  g_return_val_if_fail (gst_buffer_get_size (buffer) >= 4, GST_FLOW_ERROR);
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  tag_type = map.data[0];
+
+  /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
+   * 4 bytes of previous tag size */
+  demux->tag_data_size = GST_READ_UINT24_BE (map.data + 1);
+  demux->tag_size = demux->tag_data_size + 11;
+
+  GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
+      demux->tag_data_size);
+
+  gst_buffer_unmap (buffer, &map);
+
+  switch (tag_type) {
+    case 9:
+      demux->state = FLV_STATE_TAG_VIDEO;
+      demux->has_video = TRUE;
+      break;
+    case 8:
+      demux->state = FLV_STATE_TAG_AUDIO;
+      demux->has_audio = TRUE;
+      break;
+    case 18:
+      demux->state = FLV_STATE_TAG_SCRIPT;
+      break;
+    default:
+      GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
+      demux->state = FLV_STATE_SKIP;
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstMapInfo map;
+
+  g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  /* Check for the FLV tag */
+  if (map.data[0] == 'F' && map.data[1] == 'L' && map.data[2] == 'V') {
+    GST_DEBUG_OBJECT (demux, "FLV header detected");
+  } else {
+    if (G_UNLIKELY (demux->strict)) {
+      GST_WARNING_OBJECT (demux, "invalid header tag detected");
+      ret = GST_FLOW_EOS;
+      goto beach;
+    }
+  }
+
+  if (map.data[3] == '1') {
+    GST_DEBUG_OBJECT (demux, "FLV version 1 detected");
+  } else {
+    if (G_UNLIKELY (demux->strict)) {
+      GST_WARNING_OBJECT (demux, "invalid header version detected");
+      ret = GST_FLOW_EOS;
+      goto beach;
+    }
+
+  }
+
+  /* Now look at audio/video flags */
+  {
+    guint8 flags = map.data[4];
+
+    demux->has_video = demux->has_audio = FALSE;
+
+    if (flags & 1) {
+      GST_DEBUG_OBJECT (demux, "there is a video stream");
+      demux->has_video = TRUE;
+    }
+    if (flags & 4) {
+      GST_DEBUG_OBJECT (demux, "there is an audio stream");
+      demux->has_audio = TRUE;
+    }
+  }
+
+  /* do a one-time seekability check */
+  gst_flv_demux_check_seekability (demux);
+
+  /* We don't care about the rest */
+  demux->need_header = FALSE;
+
+beach:
+  gst_buffer_unmap (buffer, &map);
+  return ret;
+}
+
+
+static void
+gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
+{
+  GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
+
+  gst_adapter_clear (demux->adapter);
+
+  demux->audio_need_discont = TRUE;
+  demux->video_need_discont = TRUE;
+
+  demux->flushing = FALSE;
+
+  /* Only in push mode and if we're not during a seek */
+  if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
+    /* After a flush we expect a tag_type */
+    demux->state = FLV_STATE_TAG_TYPE;
+    /* We reset the offset and will get one from first push */
+    demux->offset = 0;
+  }
+}
+
+static void
+gst_flv_demux_cleanup (GstFlvDemux * demux)
+{
+  GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
+
+  demux->state = FLV_STATE_HEADER;
+
+  demux->have_group_id = FALSE;
+  demux->group_id = G_MAXUINT;
+
+  demux->flushing = FALSE;
+  demux->need_header = TRUE;
+  demux->audio_need_segment = TRUE;
+  demux->video_need_segment = TRUE;
+  demux->audio_need_discont = TRUE;
+  demux->video_need_discont = TRUE;
+
+  demux->has_audio = FALSE;
+  demux->has_video = FALSE;
+  demux->got_par = FALSE;
+
+  demux->indexed = FALSE;
+  demux->upstream_seekable = FALSE;
+  demux->file_size = 0;
+
+  demux->index_max_pos = 0;
+  demux->index_max_time = 0;
+
+  demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
+  demux->last_audio_pts = demux->last_video_dts = 0;
+  demux->audio_time_offset = demux->video_time_offset = 0;
+
+  demux->no_more_pads = FALSE;
+
+#ifndef GST_DISABLE_DEBUG
+  demux->no_audio_warned = FALSE;
+  demux->no_video_warned = FALSE;
+#endif
+
+  gst_segment_init (&demux->segment, GST_FORMAT_TIME);
+
+  demux->w = demux->h = 0;
+  demux->framerate = 0.0;
+  demux->par_x = demux->par_y = 1;
+  demux->video_offset = 0;
+  demux->audio_offset = 0;
+  demux->offset = demux->cur_tag_offset = 0;
+  demux->tag_size = demux->tag_data_size = 0;
+  demux->duration = GST_CLOCK_TIME_NONE;
+
+  if (demux->new_seg_event) {
+    gst_event_unref (demux->new_seg_event);
+    demux->new_seg_event = NULL;
+  }
+
+  gst_adapter_clear (demux->adapter);
+
+  if (demux->audio_codec_data) {
+    gst_buffer_unref (demux->audio_codec_data);
+    demux->audio_codec_data = NULL;
+  }
+
+  if (demux->video_codec_data) {
+    gst_buffer_unref (demux->video_codec_data);
+    demux->video_codec_data = NULL;
+  }
+
+  if (demux->audio_pad) {
+    gst_flow_combiner_remove_pad (demux->flowcombiner, demux->audio_pad);
+    gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
+    gst_object_unref (demux->audio_pad);
+    demux->audio_pad = NULL;
+  }
+
+  if (demux->video_pad) {
+    gst_flow_combiner_remove_pad (demux->flowcombiner, demux->video_pad);
+    gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
+    gst_object_unref (demux->video_pad);
+    demux->video_pad = NULL;
+  }
+
+  if (demux->times) {
+    g_array_free (demux->times, TRUE);
+    demux->times = NULL;
+  }
+
+  if (demux->filepositions) {
+    g_array_free (demux->filepositions, TRUE);
+    demux->filepositions = NULL;
+  }
+
+  gst_flv_demux_clear_tags (demux);
+}
+
+/*
+ * Create and push a flushing seek event upstream
+ */
+static gboolean
+flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
+{
+  GstEvent *event;
+  gboolean res = 0;
+
+  GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
+
+  event =
+      gst_event_new_seek (1.0, GST_FORMAT_BYTES,
+      GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
+      GST_SEEK_TYPE_NONE, -1);
+
+  res = gst_pad_push_event (demux->sinkpad, event);
+
+  if (res)
+    demux->offset = offset;
+  return res;
+}
+
+static GstFlowReturn
+gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstFlvDemux *demux = NULL;
+
+  demux = GST_FLV_DEMUX (parent);
+
+  GST_LOG_OBJECT (demux,
+      "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
+      G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
+      GST_BUFFER_OFFSET (buffer));
+
+  if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
+    GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
+    demux->state = FLV_STATE_HEADER;
+    demux->offset = 0;
+  }
+
+  if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
+    GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
+    demux->offset = GST_BUFFER_OFFSET (buffer);
+  }
+
+  if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
+    GST_DEBUG_OBJECT (demux, "Discontinuity");
+    gst_adapter_clear (demux->adapter);
+  }
+
+  gst_adapter_push (demux->adapter, buffer);
+
+  if (demux->seeking) {
+    demux->state = FLV_STATE_SEEK;
+    GST_OBJECT_LOCK (demux);
+    demux->seeking = FALSE;
+    GST_OBJECT_UNLOCK (demux);
+  }
+
+parse:
+  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+    GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
+    goto beach;
+  }
+
+  if (G_UNLIKELY (demux->flushing)) {
+    GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
+    ret = GST_FLOW_FLUSHING;
+    goto beach;
+  }
+
+  switch (demux->state) {
+    case FLV_STATE_HEADER:
+    {
+      if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
+        GstBuffer *buffer;
+
+        buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
+
+        ret = gst_flv_demux_parse_header (demux, buffer);
+
+        gst_buffer_unref (buffer);
+        demux->offset += FLV_HEADER_SIZE;
+
+        demux->state = FLV_STATE_TAG_TYPE;
+        goto parse;
+      } else {
+        goto beach;
+      }
+    }
+    case FLV_STATE_TAG_TYPE:
+    {
+      if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
+        GstBuffer *buffer;
+
+        /* Remember the tag offset in bytes */
+        demux->cur_tag_offset = demux->offset;
+
+        buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
+
+        ret = gst_flv_demux_parse_tag_type (demux, buffer);
+
+        gst_buffer_unref (buffer);
+        demux->offset += FLV_TAG_TYPE_SIZE;
+
+        /* last tag is not an index => no index/don't know where the index is
+         * seek back to the beginning */
+        if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
+          goto no_index;
+
+        goto parse;
+      } else {
+        goto beach;
+      }
+    }
+    case FLV_STATE_TAG_VIDEO:
+    {
+      if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
+        GstBuffer *buffer;
+
+        buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
+
+        ret = gst_flv_demux_parse_tag_video (demux, buffer);
+
+        gst_buffer_unref (buffer);
+        demux->offset += demux->tag_size;
+
+        demux->state = FLV_STATE_TAG_TYPE;
+        goto parse;
+      } else {
+        goto beach;
+      }
+    }
+    case FLV_STATE_TAG_AUDIO:
+    {
+      if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
+        GstBuffer *buffer;
+
+        buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
+
+        ret = gst_flv_demux_parse_tag_audio (demux, buffer);
+
+        gst_buffer_unref (buffer);
+        demux->offset += demux->tag_size;
+
+        demux->state = FLV_STATE_TAG_TYPE;
+        goto parse;
+      } else {
+        goto beach;
+      }
+    }
+    case FLV_STATE_TAG_SCRIPT:
+    {
+      if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
+        GstBuffer *buffer;
+
+        buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
+
+        ret = gst_flv_demux_parse_tag_script (demux, buffer);
+
+        gst_buffer_unref (buffer);
+        demux->offset += demux->tag_size;
+
+        demux->state = FLV_STATE_TAG_TYPE;
+
+        /* if there's a seek event we're here for the index so if we don't have it
+         * we seek back to the beginning */
+        if (demux->seek_event) {
+          if (demux->indexed)
+            demux->state = FLV_STATE_SEEK;
+          else
+            goto no_index;
+        }
+
+        goto parse;
+      } else {
+        goto beach;
+      }
+    }
+    case FLV_STATE_SEEK:
+    {
+      GstEvent *event;
+
+      ret = GST_FLOW_OK;
+
+      if (!demux->indexed) {
+        if (demux->offset == demux->file_size - sizeof (guint32)) {
+          guint64 seek_offset;
+          guint8 *data;
+
+          data = gst_adapter_take (demux->adapter, 4);
+          if (!data)
+            goto no_index;
+
+          seek_offset = demux->file_size - sizeof (guint32) -
+              GST_READ_UINT32_BE (data);
+          g_free (data);
+
+          GST_INFO_OBJECT (demux,
+              "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
+              seek_offset);
+          demux->state = FLV_STATE_TAG_TYPE;
+          flv_demux_seek_to_offset (demux, seek_offset);
+          goto beach;
+        } else
+          goto no_index;
+      }
+
+      GST_OBJECT_LOCK (demux);
+      event = demux->seek_event;
+      demux->seek_event = NULL;
+      GST_OBJECT_UNLOCK (demux);
+
+      /* calculate and perform seek */
+      if (!flv_demux_handle_seek_push (demux, event))
+        goto seek_failed;
+
+      gst_event_unref (event);
+      demux->state = FLV_STATE_TAG_TYPE;
+      goto beach;
+    }
+    case FLV_STATE_SKIP:
+      /* Skip unknown tags (set in _parse_tag_type()) */
+      if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
+        gst_adapter_flush (demux->adapter, demux->tag_size);
+        demux->offset += demux->tag_size;
+        demux->state = FLV_STATE_TAG_TYPE;
+        goto parse;
+      } else {
+        goto beach;
+      }
+    default:
+      GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
+  }
+
+beach:
+  return ret;
+
+/* ERRORS */
+no_index:
+  {
+    GST_OBJECT_LOCK (demux);
+    demux->seeking = FALSE;
+    gst_event_unref (demux->seek_event);
+    demux->seek_event = NULL;
+    GST_OBJECT_UNLOCK (demux);
+    GST_WARNING_OBJECT (demux,
+        "failed to find an index, seeking back to beginning");
+    flv_demux_seek_to_offset (demux, 0);
+    return GST_FLOW_OK;
+  }
+seek_failed:
+  {
+    GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
+    return GST_FLOW_ERROR;
+  }
+
+}
+
+static GstFlowReturn
+gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
+    guint size, GstBuffer ** buffer)
+{
+  GstFlowReturn ret;
+
+  ret = gst_pad_pull_range (pad, offset, size, buffer);
+  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+    GST_WARNING_OBJECT (demux,
+        "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
+        size, offset, gst_flow_get_name (ret));
+    *buffer = NULL;
+    return ret;
+  }
+
+  if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
+    GST_WARNING_OBJECT (demux,
+        "partial pull got %" G_GSIZE_FORMAT " when expecting %d from offset %"
+        G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
+    gst_buffer_unref (*buffer);
+    ret = GST_FLOW_EOS;
+    *buffer = NULL;
+    return ret;
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
+{
+  GstBuffer *buffer = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  /* Store tag offset */
+  demux->cur_tag_offset = demux->offset;
+
+  /* Get the first 4 bytes to identify tag type and size */
+  if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
+                  FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
+    goto beach;
+
+  /* Identify tag type */
+  ret = gst_flv_demux_parse_tag_type (demux, buffer);
+
+  gst_buffer_unref (buffer);
+
+  if (G_UNLIKELY (ret != GST_FLOW_OK))
+    goto beach;
+
+  /* Jump over tag type + size */
+  demux->offset += FLV_TAG_TYPE_SIZE;
+
+  /* Pull the whole tag */
+  buffer = NULL;
+  if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
+                  demux->tag_size, &buffer)) != GST_FLOW_OK))
+    goto beach;
+
+  switch (demux->state) {
+    case FLV_STATE_TAG_VIDEO:
+      ret = gst_flv_demux_parse_tag_video (demux, buffer);
+      break;
+    case FLV_STATE_TAG_AUDIO:
+      ret = gst_flv_demux_parse_tag_audio (demux, buffer);
+      break;
+    case FLV_STATE_TAG_SCRIPT:
+      ret = gst_flv_demux_parse_tag_script (demux, buffer);
+      break;
+    default:
+      GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
+  }
+
+  gst_buffer_unref (buffer);
+
+  /* Jump over that part we've just parsed */
+  demux->offset += demux->tag_size;
+
+  /* Make sure we reinitialize the tag size */
+  demux->tag_size = 0;
+
+  /* Ready for the next tag */
+  demux->state = FLV_STATE_TAG_TYPE;
+
+  if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
+    GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
+        "neither video nor audio are linked");
+  }
+
+beach:
+  return ret;
+}
+
+static GstFlowReturn
+gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
+{
+  GstBuffer *buffer = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  /* Get the first 9 bytes */
+  if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
+                  FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
+    goto beach;
+
+  ret = gst_flv_demux_parse_header (demux, buffer);
+
+  gst_buffer_unref (buffer);
+
+  /* Jump over the header now */
+  demux->offset += FLV_HEADER_SIZE;
+  demux->state = FLV_STATE_TAG_TYPE;
+
+beach:
+  return ret;
+}
+
+static void
+gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
+    gboolean reset)
+{
+  demux->offset = offset;
+
+  /* Tell all the stream we moved to a different position (discont) */
+  demux->audio_need_discont = TRUE;
+  demux->video_need_discont = TRUE;
+
+  /* next section setup */
+  demux->from_offset = -1;
+  demux->audio_done = demux->video_done = FALSE;
+  demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
+
+  if (reset) {
+    demux->from_offset = -1;
+    demux->to_offset = G_MAXINT64;
+  }
+
+  /* If we seeked at the beginning of the file parse the header again */
+  if (G_UNLIKELY (!demux->offset)) {
+    demux->state = FLV_STATE_HEADER;
+  } else {                      /* or parse a tag */
+    demux->state = FLV_STATE_TAG_TYPE;
+  }
+}
+
+static GstFlowReturn
+gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
+{
+  GstFlowReturn ret = GST_FLOW_EOS;
+  GstIndex *index;
+  GstIndexEntry *entry = NULL;
+
+  GST_DEBUG_OBJECT (demux,
+      "terminated section started at offset %" G_GINT64_FORMAT,
+      demux->from_offset);
+
+  /* we are done if we got all audio and video */
+  if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
+          demux->audio_first_ts < demux->segment.start) &&
+      (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
+          demux->video_first_ts < demux->segment.start))
+    goto done;
+
+  if (demux->from_offset <= 0)
+    goto done;
+
+  GST_DEBUG_OBJECT (demux, "locating previous position");
+
+  index = gst_flv_demux_get_index (GST_ELEMENT (demux));
+
+  /* locate index entry before previous start position */
+  if (index) {
+    entry = gst_index_get_assoc_entry (index, demux->index_id,
+        GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
+        GST_FORMAT_BYTES, demux->from_offset - 1);
+
+    if (entry) {
+      gint64 bytes = 0, time = 0;
+
+      gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
+      gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
+
+      GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
+          " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
+          demux->offset - 1, GST_TIME_ARGS (time), bytes);
+
+      /* setup for next section */
+      demux->to_offset = demux->from_offset;
+      gst_flv_demux_move_to_offset (demux, bytes, FALSE);
+      ret = GST_FLOW_OK;
+    }
+
+    gst_object_unref (index);
+  }
+
+done:
+  return ret;
+}
+
+static GstFlowReturn
+gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
+{
+  gint64 size;
+  size_t tag_size;
+  guint64 old_offset;
+  GstBuffer *buffer;
+  GstClockTime tag_time;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
+    return GST_FLOW_OK;
+
+  GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
+      " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
+
+  old_offset = demux->offset;
+  demux->offset = pos;
+
+  buffer = NULL;
+  while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
+              12, &buffer)) == GST_FLOW_OK) {
+    tag_time =
+        gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
+
+    gst_buffer_unref (buffer);
+    buffer = NULL;
+
+    if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
+      goto exit;
+
+    demux->offset += tag_size;
+  }
+
+  if (ret == GST_FLOW_EOS) {
+    /* file ran out, so mark we have complete index */
+    demux->indexed = TRUE;
+    ret = GST_FLOW_OK;
+  }
+
+exit:
+  demux->offset = old_offset;
+
+  return ret;
+}
+
+static gint64
+gst_flv_demux_get_metadata (GstFlvDemux * demux)
+{
+  gint64 ret = 0, offset;
+  size_t tag_size, size;
+  GstBuffer *buffer = NULL;
+  GstMapInfo map;
+
+  if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
+    goto exit;
+
+  ret = offset;
+  GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
+  if (G_UNLIKELY (offset < 4))
+    goto exit;
+
+  offset -= 4;
+  if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
+          4, &buffer))
+    goto exit;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  tag_size = GST_READ_UINT32_BE (map.data);
+  gst_buffer_unmap (buffer, &map);
+  GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
+  gst_buffer_unref (buffer);
+  buffer = NULL;
+
+  if (G_UNLIKELY (offset < tag_size))
+    goto exit;
+
+  offset -= tag_size;
+  if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
+          12, &buffer))
+    goto exit;
+
+  /* a consistency check */
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  size = GST_READ_UINT24_BE (map.data + 1);
+  if (size != tag_size - 11) {
+    gst_buffer_unmap (buffer, &map);
+    GST_DEBUG_OBJECT (demux,
+        "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
+        ", corrupt or truncated file", size, tag_size - 11);
+    goto exit;
+  }
+
+  /* try to update duration with timestamp in any case */
+  gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
+
+  /* maybe get some more metadata */
+  if (map.data[0] == 18) {
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+    buffer = NULL;
+    GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
+    offset += 4;
+    if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
+            tag_size, &buffer))
+      gst_flv_demux_parse_tag_script (demux, buffer);
+  } else {
+    gst_buffer_unmap (buffer, &map);
+  }
+
+exit:
+  if (buffer)
+    gst_buffer_unref (buffer);
+
+  return ret;
+}
+
+static void
+gst_flv_demux_loop (GstPad * pad)
+{
+  GstFlvDemux *demux = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
+
+  /* pull in data */
+  switch (demux->state) {
+    case FLV_STATE_TAG_TYPE:
+      if (demux->from_offset == -1)
+        demux->from_offset = demux->offset;
+      ret = gst_flv_demux_pull_tag (pad, demux);
+      /* if we have seen real data, we probably passed a possible metadata
+       * header located at start.  So if we do not yet have an index,
+       * try to pick up metadata (index, duration) at the end */
+      if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
+              (demux->has_video || demux->has_audio)))
+        demux->file_size = gst_flv_demux_get_metadata (demux);
+      break;
+    case FLV_STATE_DONE:
+      ret = GST_FLOW_EOS;
+      break;
+    case FLV_STATE_SEEK:
+      /* seek issued with insufficient index;
+       * scan for index in task thread from current maximum offset to
+       * desired time and then perform seek */
+      /* TODO maybe some buffering message or so to indicate scan progress */
+      ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
+          demux->seek_time);
+      if (ret != GST_FLOW_OK)
+        goto pause;
+      /* position and state arranged by seek,
+       * also unrefs event */
+      gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
+      demux->seek_event = NULL;
+      break;
+    default:
+      ret = gst_flv_demux_pull_header (pad, demux);
+      /* index scans start after header */
+      demux->index_max_pos = demux->offset;
+      break;
+  }
+
+  if (demux->segment.rate < 0.0) {
+    /* check end of section */
+    if ((gint64) demux->offset >= demux->to_offset ||
+        demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
+        (demux->audio_done && demux->video_done))
+      ret = gst_flv_demux_seek_to_prev_keyframe (demux);
+  } else {
+    /* check EOS condition */
+    if ((demux->segment.stop != -1) &&
+        (demux->segment.position >= demux->segment.stop)) {
+      ret = GST_FLOW_EOS;
+    }
+  }
+
+  /* pause if something went wrong or at end */
+  if (G_UNLIKELY (ret != GST_FLOW_OK))
+    goto pause;
+
+  gst_object_unref (demux);
+
+  return;
+
+pause:
+  {
+    const gchar *reason = gst_flow_get_name (ret);
+
+    GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
+    gst_pad_pause_task (pad);
+
+    if (ret == GST_FLOW_EOS) {
+      /* handle end-of-stream/segment */
+      /* so align our position with the end of it, if there is one
+       * this ensures a subsequent will arrive at correct base/acc time */
+      if (demux->segment.rate > 0.0 &&
+          GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
+        demux->segment.position = demux->segment.stop;
+      else if (demux->segment.rate < 0.0)
+        demux->segment.position = demux->segment.start;
+
+      /* perform EOS logic */
+      if (!demux->no_more_pads) {
+        gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
+        demux->no_more_pads = TRUE;
+      }
+
+      if (demux->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
+        gint64 stop;
+
+        /* for segment playback we need to post when (in stream time)
+         * we stopped, this is either stop (when set) or the duration. */
+        if ((stop = demux->segment.stop) == -1)
+          stop = demux->segment.duration;
+
+        if (demux->segment.rate >= 0) {
+          GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
+          gst_element_post_message (GST_ELEMENT_CAST (demux),
+              gst_message_new_segment_done (GST_OBJECT_CAST (demux),
+                  GST_FORMAT_TIME, stop));
+          gst_flv_demux_push_src_event (demux,
+              gst_event_new_segment_done (GST_FORMAT_TIME, stop));
+        } else {                /* Reverse playback */
+          GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
+              "segment");
+          gst_element_post_message (GST_ELEMENT_CAST (demux),
+              gst_message_new_segment_done (GST_OBJECT_CAST (demux),
+                  GST_FORMAT_TIME, demux->segment.start));
+          gst_flv_demux_push_src_event (demux,
+              gst_event_new_segment_done (GST_FORMAT_TIME,
+                  demux->segment.start));
+        }
+      } else {
+        /* normal playback, send EOS to all linked pads */
+        if (!demux->no_more_pads) {
+          gst_element_no_more_pads (GST_ELEMENT (demux));
+          demux->no_more_pads = TRUE;
+        }
+
+        GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
+        if (!demux->audio_pad && !demux->video_pad)
+          GST_ELEMENT_ERROR (demux, STREAM, FAILED,
+              ("Internal data stream error."), ("Got EOS before any data"));
+        else if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
+          GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
+      }
+    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
+      GST_ELEMENT_FLOW_ERROR (demux, ret);
+      gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
+    }
+    gst_object_unref (demux);
+    return;
+  }
+}
+
+static guint64
+gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment,
+    GstSeekFlags seek_flags)
+{
+  gint64 bytes = 0;
+  gint64 time = 0;
+  GstIndex *index;
+  GstIndexEntry *entry;
+
+  g_return_val_if_fail (segment != NULL, 0);
+
+  time = segment->position;
+
+  index = gst_flv_demux_get_index (GST_ELEMENT (demux));
+
+  if (index) {
+    /* Let's check if we have an index entry for that seek time */
+    entry = gst_index_get_assoc_entry (index, demux->index_id,
+        seek_flags & GST_SEEK_FLAG_SNAP_AFTER ?
+        GST_INDEX_LOOKUP_AFTER : GST_INDEX_LOOKUP_BEFORE,
+        GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, time);
+
+    if (entry) {
+      gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
+      gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
+
+      GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
+          " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
+          GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
+
+      /* Key frame seeking */
+      if (seek_flags & GST_SEEK_FLAG_KEY_UNIT) {
+        /* Adjust the segment so that the keyframe fits in */
+        segment->start = segment->time = time;
+        segment->position = time;
+      }
+    } else {
+      GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (segment->start));
+    }
+
+    gst_object_unref (index);
+  }
+
+  return bytes;
+}
+
+static gboolean
+flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
+{
+  GstFormat format;
+  GstSeekFlags flags;
+  GstSeekType start_type, stop_type;
+  gint64 start, stop;
+  gdouble rate;
+  gboolean update, flush, ret;
+  GstSegment seeksegment;
+
+  gst_event_parse_seek (event, &rate, &format, &flags,
+      &start_type, &start, &stop_type, &stop);
+
+  if (format != GST_FORMAT_TIME)
+    goto wrong_format;
+
+  flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
+
+  /* Work on a copy until we are sure the seek succeeded. */
+  memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
+
+  GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
+      &demux->segment);
+
+  /* Apply the seek to our segment */
+  gst_segment_do_seek (&seeksegment, rate, format, flags,
+      start_type, start, stop_type, stop, &update);
+
+  GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
+      &seeksegment);
+
+  if (flush || seeksegment.position != demux->segment.position) {
+    /* Do the actual seeking */
+    guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment, flags);
+
+    GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
+        G_GUINT64_FORMAT, offset);
+    ret = gst_pad_push_event (demux->sinkpad,
+        gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
+            flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
+            offset, GST_SEEK_TYPE_NONE, 0));
+    if (G_UNLIKELY (!ret)) {
+      GST_WARNING_OBJECT (demux, "upstream seek failed");
+    }
+
+    gst_flow_combiner_reset (demux->flowcombiner);
+    /* Tell all the stream we moved to a different position (discont) */
+    demux->audio_need_discont = TRUE;
+    demux->video_need_discont = TRUE;
+  } else {
+    ret = TRUE;
+  }
+
+  if (ret) {
+    /* Ok seek succeeded, take the newly configured segment */
+    memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
+
+    /* Tell all the stream a new segment is needed */
+    demux->audio_need_segment = TRUE;
+    demux->video_need_segment = TRUE;
+    /* Clean any potential newsegment event kept for the streams. The first
+     * stream needing a new segment will create a new one. */
+    if (G_UNLIKELY (demux->new_seg_event)) {
+      gst_event_unref (demux->new_seg_event);
+      demux->new_seg_event = NULL;
+    }
+    GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
+        GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (demux->segment.start),
+        GST_TIME_ARGS (demux->segment.stop));
+    demux->new_seg_event = gst_event_new_segment (&demux->segment);
+    gst_event_unref (event);
+  } else {
+    ret = gst_pad_push_event (demux->sinkpad, event);
+  }
+
+  return ret;
+
+/* ERRORS */
+wrong_format:
+  {
+    GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
+    gst_event_unref (event);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
+{
+  GstFormat format;
+
+  gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
+
+  if (format != GST_FORMAT_TIME) {
+    GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
+    gst_event_unref (event);
+    return FALSE;
+  }
+
+  /* First try upstream */
+  if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
+    GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
+    gst_event_unref (event);
+    return TRUE;
+  }
+
+  if (!demux->indexed) {
+    guint64 seek_offset = 0;
+    gboolean building_index;
+
+    GST_OBJECT_LOCK (demux);
+    /* handle the seek in the chain function */
+    demux->seeking = TRUE;
+    demux->state = FLV_STATE_SEEK;
+
+    /* copy the event */
+    if (demux->seek_event)
+      gst_event_unref (demux->seek_event);
+    demux->seek_event = gst_event_ref (event);
+
+    /* set the building_index flag so that only one thread can setup the
+     * structures for index seeking. */
+    building_index = demux->building_index;
+    if (!building_index) {
+      demux->building_index = TRUE;
+      if (!demux->file_size
+          && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
+              &demux->file_size)) {
+        GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
+        GST_OBJECT_UNLOCK (demux);
+        return FALSE;
+      }
+
+      /* we hope the last tag is a scriptdataobject containing an index
+       * the size of the last tag is given in the last guint32 bits
+       * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
+      seek_offset = demux->file_size - sizeof (guint32);
+      GST_DEBUG_OBJECT (demux,
+          "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
+    }
+    GST_OBJECT_UNLOCK (demux);
+
+    if (!building_index) {
+      GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
+          seek_offset);
+      return flv_demux_seek_to_offset (demux, seek_offset);
+    }
+
+    /* FIXME: we have to always return true so that we don't block the seek
+     * thread.
+     * Note: maybe it is OK to return true if we're still building the index */
+    return TRUE;
+  }
+
+  return flv_demux_handle_seek_push (demux, event);
+}
+
+static gboolean
+gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
+    gboolean seeking)
+{
+  GstFormat format;
+  GstSeekFlags flags;
+  GstSeekType start_type, stop_type;
+  gint64 start, stop;
+  gdouble rate;
+  gboolean update, flush, ret = FALSE;
+  GstSegment seeksegment;
+
+  gst_event_parse_seek (event, &rate, &format, &flags,
+      &start_type, &start, &stop_type, &stop);
+
+  if (format != GST_FORMAT_TIME)
+    goto wrong_format;
+
+  /* mark seeking thread entering flushing/pausing */
+  GST_OBJECT_LOCK (demux);
+  if (seeking)
+    demux->seeking = seeking;
+  GST_OBJECT_UNLOCK (demux);
+
+  flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
+
+  if (flush) {
+    /* Flush start up and downstream to make sure data flow and loops are
+       idle */
+    gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
+    gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
+  } else {
+    /* Pause the pulling task */
+    gst_pad_pause_task (demux->sinkpad);
+  }
+
+  /* Take the stream lock */
+  GST_PAD_STREAM_LOCK (demux->sinkpad);
+
+  if (flush) {
+    /* Stop flushing upstream we need to pull */
+    gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
+  }
+
+  /* Work on a copy until we are sure the seek succeeded. */
+  memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
+
+  GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
+      &demux->segment);
+
+  /* Apply the seek to our segment */
+  gst_segment_do_seek (&seeksegment, rate, format, flags,
+      start_type, start, stop_type, stop, &update);
+
+  GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
+      &seeksegment);
+
+  if (flush || seeksegment.position != demux->segment.position) {
+    /* Do the actual seeking */
+    /* index is reliable if it is complete or we do not go to far ahead */
+    if (seeking && !demux->indexed &&
+        seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
+      GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
+          " index only up to %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (demux->index_max_time));
+      /* stop flushing for now */
+      if (flush)
+        gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
+      /* delegate scanning and index building to task thread to avoid
+       * occupying main (UI) loop */
+      if (demux->seek_event)
+        gst_event_unref (demux->seek_event);
+      demux->seek_event = gst_event_ref (event);
+      demux->seek_time = seeksegment.position;
+      demux->state = FLV_STATE_SEEK;
+      /* do not know about succes yet, but we did care and handled it */
+      ret = TRUE;
+      goto exit;
+    }
+
+    /* now index should be as reliable as it can be for current purpose */
+    gst_flv_demux_move_to_offset (demux,
+        gst_flv_demux_find_offset (demux, &seeksegment, flags), TRUE);
+    ret = TRUE;
+  } else {
+    ret = TRUE;
+  }
+
+  if (flush) {
+    /* Stop flushing, the sinks are at time 0 now */
+    gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
+  }
+
+  if (ret) {
+    /* Ok seek succeeded, take the newly configured segment */
+    memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
+
+    /* Notify about the start of a new segment */
+    if (demux->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
+      gst_element_post_message (GST_ELEMENT (demux),
+          gst_message_new_segment_start (GST_OBJECT (demux),
+              demux->segment.format, demux->segment.position));
+    }
+
+    gst_flow_combiner_reset (demux->flowcombiner);
+    /* Tell all the stream a new segment is needed */
+    demux->audio_need_segment = TRUE;
+    demux->video_need_segment = TRUE;
+    /* Clean any potential newsegment event kept for the streams. The first
+     * stream needing a new segment will create a new one. */
+    if (G_UNLIKELY (demux->new_seg_event)) {
+      gst_event_unref (demux->new_seg_event);
+      demux->new_seg_event = NULL;
+    }
+    GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
+        GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (demux->segment.start),
+        GST_TIME_ARGS (demux->segment.stop));
+    demux->new_seg_event = gst_event_new_segment (&demux->segment);
+  }
+
+exit:
+  GST_OBJECT_LOCK (demux);
+  seeking = demux->seeking && !seeking;
+  demux->seeking = FALSE;
+  GST_OBJECT_UNLOCK (demux);
+
+  /* if we detect an external seek having started (and possibly already having
+   * flushed), do not restart task to give it a chance.
+   * Otherwise external one's flushing will take care to pause task */
+  if (seeking) {
+    gst_pad_pause_task (demux->sinkpad);
+  } else {
+    gst_pad_start_task (demux->sinkpad,
+        (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad, NULL);
+  }
+
+  GST_PAD_STREAM_UNLOCK (demux->sinkpad);
+
+  gst_event_unref (event);
+  return ret;
+
+  /* ERRORS */
+wrong_format:
+  {
+    GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
+    gst_event_unref (event);
+    return ret;
+  }
+}
+
+/* If we can pull that's prefered */
+static gboolean
+gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
+{
+  GstQuery *query;
+  gboolean pull_mode;
+
+  query = gst_query_new_scheduling ();
+
+  if (!gst_pad_peer_query (sinkpad, query)) {
+    gst_query_unref (query);
+    goto activate_push;
+  }
+
+  pull_mode = gst_query_has_scheduling_mode_with_flags (query,
+      GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
+  gst_query_unref (query);
+
+  if (!pull_mode)
+    goto activate_push;
+
+  GST_DEBUG_OBJECT (sinkpad, "activating pull");
+  return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
+
+activate_push:
+  {
+    GST_DEBUG_OBJECT (sinkpad, "activating push");
+    return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
+  }
+}
+
+static gboolean
+gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
+    GstPadMode mode, gboolean active)
+{
+  gboolean res;
+  GstFlvDemux *demux;
+
+  demux = GST_FLV_DEMUX (parent);
+
+  switch (mode) {
+    case GST_PAD_MODE_PUSH:
+      demux->random_access = FALSE;
+      res = TRUE;
+      break;
+    case GST_PAD_MODE_PULL:
+      if (active) {
+        demux->random_access = TRUE;
+        res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
+            sinkpad, NULL);
+      } else {
+        demux->random_access = FALSE;
+        res = gst_pad_stop_task (sinkpad);
+      }
+      break;
+    default:
+      res = FALSE;
+      break;
+  }
+  return res;
+}
+
+static gboolean
+gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstFlvDemux *demux;
+  gboolean ret = FALSE;
+
+  demux = GST_FLV_DEMUX (parent);
+
+  GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
+      demux->flushing = TRUE;
+      ret = gst_flv_demux_push_src_event (demux, event);
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
+      gst_flv_demux_flush (demux, TRUE);
+      ret = gst_flv_demux_push_src_event (demux, event);
+      break;
+    case GST_EVENT_EOS:
+    {
+      GstIndex *index;
+
+      GST_DEBUG_OBJECT (demux, "received EOS");
+
+      index = gst_flv_demux_get_index (GST_ELEMENT (demux));
+
+      if (index) {
+        GST_DEBUG_OBJECT (demux, "committing index");
+        gst_index_commit (index, demux->index_id);
+        gst_object_unref (index);
+      }
+
+      if (!demux->audio_pad && !demux->video_pad) {
+        GST_ELEMENT_ERROR (demux, STREAM, FAILED,
+            ("Internal data stream error."), ("Got EOS before any data"));
+        gst_event_unref (event);
+      } else {
+        if (!demux->no_more_pads) {
+          gst_element_no_more_pads (GST_ELEMENT (demux));
+          demux->no_more_pads = TRUE;
+        }
+
+        if (!gst_flv_demux_push_src_event (demux, event))
+          GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
+      }
+      ret = TRUE;
+      break;
+    }
+    case GST_EVENT_SEGMENT:
+    {
+      GstSegment in_segment;
+
+      GST_DEBUG_OBJECT (demux, "received new segment");
+
+      gst_event_copy_segment (event, &in_segment);
+
+      if (in_segment.format == GST_FORMAT_TIME) {
+        /* time segment, this is perfect, copy over the values. */
+        memcpy (&demux->segment, &in_segment, sizeof (in_segment));
+
+        GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
+            &demux->segment);
+
+        /* and forward */
+        ret = gst_flv_demux_push_src_event (demux, event);
+      } else {
+        /* non-time format */
+        demux->audio_need_segment = TRUE;
+        demux->video_need_segment = TRUE;
+        ret = TRUE;
+        gst_event_unref (event);
+        if (demux->new_seg_event) {
+          gst_event_unref (demux->new_seg_event);
+          demux->new_seg_event = NULL;
+        }
+      }
+      gst_flow_combiner_reset (demux->flowcombiner);
+      break;
+    }
+    default:
+      ret = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstFlvDemux *demux;
+  gboolean ret = FALSE;
+
+  demux = GST_FLV_DEMUX (parent);
+
+  GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+      /* Try to push upstream first */
+      gst_event_ref (event);
+      ret = gst_pad_push_event (demux->sinkpad, event);
+      if (ret) {
+        gst_event_unref (event);
+        break;
+      }
+      if (demux->random_access) {
+        ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
+      } else {
+        ret = gst_flv_demux_handle_seek_push (demux, event);
+      }
+      break;
+    default:
+      ret = gst_pad_push_event (demux->sinkpad, event);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  gboolean res = TRUE;
+  GstFlvDemux *demux;
+
+  demux = GST_FLV_DEMUX (parent);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_DURATION:
+    {
+      GstFormat format;
+
+      gst_query_parse_duration (query, &format, NULL);
+
+      /* duration is time only */
+      if (format != GST_FORMAT_TIME) {
+        GST_DEBUG_OBJECT (demux, "duration query only supported for time "
+            "format");
+        res = FALSE;
+        goto beach;
+      }
+
+      /* Try to push upstream first */
+      res = gst_pad_peer_query (demux->sinkpad, query);
+      if (res)
+        goto beach;
+
+      GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (demux->duration));
+
+      gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
+      res = TRUE;
+      break;
+    }
+    case GST_QUERY_POSITION:
+    {
+      GstFormat format;
+
+      gst_query_parse_position (query, &format, NULL);
+
+      /* position is time only */
+      if (format != GST_FORMAT_TIME) {
+        GST_DEBUG_OBJECT (demux, "position query only supported for time "
+            "format");
+        res = FALSE;
+        goto beach;
+      }
+
+      GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (demux->segment.position));
+
+      gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
+
+      break;
+    }
+
+    case GST_QUERY_SEEKING:{
+      GstFormat fmt;
+
+      gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
+
+      /* First ask upstream */
+      if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
+        gboolean seekable;
+
+        gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
+        if (seekable) {
+          res = TRUE;
+          break;
+        }
+      }
+      res = TRUE;
+      /* FIXME, check index this way is not thread safe */
+      if (fmt != GST_FORMAT_TIME || !demux->index) {
+        gst_query_set_seeking (query, fmt, FALSE, -1, -1);
+      } else if (demux->random_access) {
+        gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
+            demux->duration);
+      } else {
+        GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
+        gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
+
+        if (seekable)
+          gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
+        gst_query_unref (peerquery);
+
+        if (seekable)
+          gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
+              demux->duration);
+        else
+          gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
+      }
+      break;
+    }
+    case GST_QUERY_SEGMENT:
+    {
+      GstFormat format;
+      gint64 start, stop;
+
+      format = demux->segment.format;
+
+      start =
+          gst_segment_to_stream_time (&demux->segment, format,
+          demux->segment.start);
+      if ((stop = demux->segment.stop) == -1)
+        stop = demux->segment.duration;
+      else
+        stop = gst_segment_to_stream_time (&demux->segment, format, stop);
+
+      gst_query_set_segment (query, demux->segment.rate, format, start, stop);
+      res = TRUE;
+      break;
+    }
+    case GST_QUERY_LATENCY:
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+
+beach:
+
+  return res;
+}
+
+static GstStateChangeReturn
+gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
+{
+  GstFlvDemux *demux;
+  GstStateChangeReturn ret;
+
+  demux = GST_FLV_DEMUX (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      /* If this is our own index destroy it as the
+       * old entries might be wrong for the new stream */
+      if (demux->own_index) {
+        gst_object_unref (demux->index);
+        demux->index = NULL;
+        demux->own_index = FALSE;
+      }
+
+      /* If no index was created, generate one */
+      if (G_UNLIKELY (!demux->index)) {
+        GST_DEBUG_OBJECT (demux, "no index provided creating our own");
+
+        demux->index = g_object_new (gst_mem_index_get_type (), NULL);
+
+        gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
+            &demux->index_id);
+        demux->own_index = TRUE;
+      }
+      gst_flv_demux_cleanup (demux);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_flv_demux_cleanup (demux);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+#if 0
+static void
+gst_flv_demux_set_index (GstElement * element, GstIndex * index)
+{
+  GstFlvDemux *demux = GST_FLV_DEMUX (element);
+  GstIndex *old_index;
+
+  GST_OBJECT_LOCK (demux);
+
+  old_index = demux->index;
+
+  if (index) {
+    demux->index = gst_object_ref (index);
+    demux->own_index = FALSE;
+  } else
+    demux->index = NULL;
+
+  if (old_index)
+    gst_object_unref (demux->index);
+
+  gst_object_ref (index);
+
+  GST_OBJECT_UNLOCK (demux);
+
+  /* object lock might be taken again */
+  if (index)
+    gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
+
+  GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
+
+  gst_object_unref (index);
+}
+#endif
+
+static GstIndex *
+gst_flv_demux_get_index (GstElement * element)
+{
+  GstIndex *result = NULL;
+
+  GstFlvDemux *demux = GST_FLV_DEMUX (element);
+
+  GST_OBJECT_LOCK (demux);
+  if (demux->index)
+    result = gst_object_ref (demux->index);
+  GST_OBJECT_UNLOCK (demux);
+
+  return result;
+}
+
+static void
+gst_flv_demux_dispose (GObject * object)
+{
+  GstFlvDemux *demux = GST_FLV_DEMUX (object);
+
+  GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
+
+  if (demux->adapter) {
+    gst_adapter_clear (demux->adapter);
+    g_object_unref (demux->adapter);
+    demux->adapter = NULL;
+  }
+
+  if (demux->taglist) {
+    gst_tag_list_unref (demux->taglist);
+    demux->taglist = NULL;
+  }
+
+  if (demux->audio_tags) {
+    gst_tag_list_unref (demux->audio_tags);
+    demux->audio_tags = NULL;
+  }
+
+  if (demux->video_tags) {
+    gst_tag_list_unref (demux->video_tags);
+    demux->video_tags = NULL;
+  }
+
+  if (demux->flowcombiner) {
+    gst_flow_combiner_free (demux->flowcombiner);
+    demux->flowcombiner = NULL;
+  }
+
+  if (demux->new_seg_event) {
+    gst_event_unref (demux->new_seg_event);
+    demux->new_seg_event = NULL;
+  }
+
+  if (demux->audio_codec_data) {
+    gst_buffer_unref (demux->audio_codec_data);
+    demux->audio_codec_data = NULL;
+  }
+
+  if (demux->video_codec_data) {
+    gst_buffer_unref (demux->video_codec_data);
+    demux->video_codec_data = NULL;
+  }
+
+  if (demux->audio_pad) {
+    gst_object_unref (demux->audio_pad);
+    demux->audio_pad = NULL;
+  }
+
+  if (demux->video_pad) {
+    gst_object_unref (demux->video_pad);
+    demux->video_pad = NULL;
+  }
+
+  if (demux->index) {
+    gst_object_unref (demux->index);
+    demux->index = NULL;
+  }
+
+  if (demux->times) {
+    g_array_free (demux->times, TRUE);
+    demux->times = NULL;
+  }
+
+  if (demux->filepositions) {
+    g_array_free (demux->filepositions, TRUE);
+    demux->filepositions = NULL;
+  }
+
+  GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
+}
+
+static void
+gst_flv_demux_class_init (GstFlvDemuxClass * klass)
+{
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->dispose = gst_flv_demux_dispose;
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
+
+#if 0
+  gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
+  gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
+#endif
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &flv_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &audio_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &video_src_template);
+  gst_element_class_set_static_metadata (gstelement_class, "FLV Demuxer",
+      "Codec/Demuxer", "Demux FLV feeds into digital streams",
+      "Julien Moutte <julien@moutte.net>");
+}
+
+static void
+gst_flv_demux_init (GstFlvDemux * demux)
+{
+  demux->sinkpad =
+      gst_pad_new_from_static_template (&flv_sink_template, "sink");
+
+  gst_pad_set_event_function (demux->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
+  gst_pad_set_chain_function (demux->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
+  gst_pad_set_activate_function (demux->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
+  gst_pad_set_activatemode_function (demux->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
+
+  gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
+
+  demux->adapter = gst_adapter_new ();
+  demux->flowcombiner = gst_flow_combiner_new ();
+
+  demux->own_index = FALSE;
+
+  GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
+
+  gst_flv_demux_cleanup (demux);
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
+
+  if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
+          gst_flv_demux_get_type ()) ||
+      !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
+          gst_flv_mux_get_type ()))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
+    flv, "FLV muxing and demuxing plugin",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/flv/gstflvdemux.h b/gst/flv/gstflvdemux.h
new file mode 100644
index 0000000..4eb1791
--- /dev/null
+++ b/gst/flv/gstflvdemux.h
@@ -0,0 +1,169 @@
+/* GStreamer
+ * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __FLV_DEMUX_H__
+#define __FLV_DEMUX_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/base/gstflowcombiner.h>
+#include "gstindex.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_FLV_DEMUX \
+  (gst_flv_demux_get_type())
+#define GST_FLV_DEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FLV_DEMUX,GstFlvDemux))
+#define GST_FLV_DEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FLV_DEMUX,GstFlvDemuxClass))
+#define GST_IS_FLV_DEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLV_DEMUX))
+#define GST_IS_FLV_DEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLV_DEMUX))
+typedef struct _GstFlvDemux GstFlvDemux;
+typedef struct _GstFlvDemuxClass GstFlvDemuxClass;
+
+typedef enum
+{
+  FLV_STATE_HEADER,
+  FLV_STATE_TAG_TYPE,
+  FLV_STATE_TAG_VIDEO,
+  FLV_STATE_TAG_AUDIO,
+  FLV_STATE_TAG_SCRIPT,
+  FLV_STATE_SEEK,
+  FLV_STATE_DONE,
+  FLV_STATE_SKIP,
+  FLV_STATE_NONE
+} GstFlvDemuxState;
+
+struct _GstFlvDemux
+{
+  GstElement element;
+
+  GstPad *sinkpad;
+
+  GstPad *audio_pad;
+  GstPad *video_pad;
+
+  gboolean have_group_id;
+  guint group_id;
+
+  /* <private> */
+  
+  GstIndex *index;
+  gint index_id;
+  gboolean own_index;
+  
+  GArray * times;
+  GArray * filepositions;
+
+  GstAdapter *adapter;
+
+  GstFlowCombiner *flowcombiner;
+
+  GstSegment segment;
+
+  GstEvent *new_seg_event;
+
+  GstTagList *taglist;
+  GstTagList *audio_tags;
+  GstTagList *video_tags;
+
+  GstFlvDemuxState state;
+
+  guint64 offset;
+  guint64 cur_tag_offset;
+  GstClockTime duration;
+  guint64 tag_size;
+  guint64 tag_data_size;
+
+  /* Audio infos */
+  guint16 rate;
+  guint16 channels;
+  guint16 width;
+  guint16 audio_codec_tag;
+  guint64 audio_offset;
+  gboolean audio_need_discont;
+  gboolean audio_need_segment;
+  gboolean audio_linked;
+  GstBuffer * audio_codec_data;
+  GstClockTime audio_start;
+  guint32 last_audio_pts;
+  GstClockTime audio_time_offset;
+
+  /* Video infos */
+  guint32 w;
+  guint32 h;
+  guint32 par_x;
+  guint32 par_y;
+  guint16 video_codec_tag;
+  guint64 video_offset;
+  gboolean video_need_discont;
+  gboolean video_need_segment;
+  gboolean video_linked;
+  gboolean got_par;
+  GstBuffer * video_codec_data;
+  GstClockTime video_start;
+  guint32 last_video_dts;
+  GstClockTime video_time_offset;
+  gdouble framerate;
+
+  gboolean random_access;
+  gboolean need_header;
+  gboolean has_audio;
+  gboolean has_video;
+  gboolean strict;
+  gboolean flushing;
+
+  gboolean no_more_pads;
+
+#ifndef GST_DISABLE_DEBUG
+  gboolean no_audio_warned;
+  gboolean no_video_warned;
+#endif
+
+  gboolean seeking;
+  gboolean building_index;
+  gboolean indexed; /* TRUE if index is completely built */
+  gboolean upstream_seekable; /* TRUE if upstream is seekable */
+  gint64 file_size;
+  GstEvent *seek_event;
+  gint64 seek_time;
+
+  GstClockTime index_max_time;
+  gint64 index_max_pos;
+
+  /* reverse playback */
+  GstClockTime video_first_ts;
+  GstClockTime audio_first_ts;
+  gboolean video_done;
+  gboolean audio_done;
+  gint64 from_offset;
+  gint64 to_offset;
+};
+
+struct _GstFlvDemuxClass
+{
+  GstElementClass parent_class;
+};
+
+GType gst_flv_demux_get_type (void);
+
+G_END_DECLS
+#endif /* __FLV_DEMUX_H__ */
diff --git a/gst/flv/gstflvmux.c b/gst/flv/gstflvmux.c
new file mode 100644
index 0000000..ac907e0
--- /dev/null
+++ b/gst/flv/gstflvmux.c
@@ -0,0 +1,1808 @@
+/* GStreamer
+ *
+ * Copyright (c) 2008,2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ * Copyright (c) 2008-2017 Collabora Ltd
+ *  @author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *  @author: Vincent Penquerc'h <vincent.penquerch@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-flvmux
+ *
+ * flvmux muxes different streams into an FLV file.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v flvmux name=mux ! filesink location=test.flv  audiotestsrc samplesperbuffer=44100 num-buffers=10 ! faac ! mux.  videotestsrc num-buffers=250 ! video/x-raw,framerate=25/1 ! x264enc ! mux.
+ * ]| This pipeline encodes a test audio and video stream and muxes both into an FLV file.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <string.h>
+
+#include <gst/audio/audio.h>
+
+#include "gstflvmux.h"
+#include "amfdefs.h"
+
+GST_DEBUG_CATEGORY_STATIC (flvmux_debug);
+#define GST_CAT_DEFAULT flvmux_debug
+
+enum
+{
+  PROP_0,
+  PROP_STREAMABLE,
+  PROP_METADATACREATOR
+};
+
+#define DEFAULT_STREAMABLE FALSE
+#define MAX_INDEX_ENTRIES 128
+#define DEFAULT_METADATACREATOR "GStreamer " PACKAGE_VERSION " FLV muxer"
+
+static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-flv")
+    );
+
+static GstStaticPadTemplate videosink_templ = GST_STATIC_PAD_TEMPLATE ("video",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("video/x-flash-video; "
+        "video/x-flash-screen; "
+        "video/x-vp6-flash; " "video/x-vp6-alpha; "
+        "video/x-h264, stream-format=avc;")
+    );
+
+static GstStaticPadTemplate audiosink_templ = GST_STATIC_PAD_TEMPLATE ("audio",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS
+    ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
+        "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; "
+        "audio/mpeg, mpegversion = (int) { 4, 2 }, stream-format = (string) raw; "
+        "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
+        "audio/x-raw, format = (string) { U8, S16LE}, layout = (string) interleaved, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
+        "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
+        "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
+        "audio/x-speex, channels = (int) 1, rate = (int) 16000;")
+    );
+
+G_DEFINE_TYPE (GstFlvMuxPad, gst_flv_mux_pad, GST_TYPE_AGGREGATOR_PAD);
+
+#define gst_flv_mux_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstFlvMux, gst_flv_mux, GST_TYPE_AGGREGATOR,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
+
+static GstFlowReturn
+gst_flv_mux_aggregate (GstAggregator * aggregator, gboolean timeout);
+static gboolean
+gst_flv_mux_sink_event (GstAggregator * aggregator, GstAggregatorPad * pad,
+    GstEvent * event);
+
+static GstAggregatorPad *gst_flv_mux_create_new_pad (GstAggregator * agg,
+    GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps);
+static void gst_flv_mux_release_pad (GstElement * element, GstPad * pad);
+
+static gboolean gst_flv_mux_video_pad_setcaps (GstFlvMuxPad * pad,
+    GstCaps * caps);
+static gboolean gst_flv_mux_audio_pad_setcaps (GstFlvMuxPad * pad,
+    GstCaps * caps);
+
+static void gst_flv_mux_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+static void gst_flv_mux_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_flv_mux_finalize (GObject * object);
+
+static void gst_flv_mux_reset (GstElement * element);
+static void gst_flv_mux_reset_pad (GstFlvMuxPad * pad);
+
+static void gst_flv_mux_pad_finalize (GObject * object);
+
+static gboolean gst_flv_mux_start (GstAggregator * aggregator);
+static GstFlowReturn gst_flv_mux_flush (GstAggregator * aggregator);
+static GstClockTime gst_flv_mux_get_next_time (GstAggregator * aggregator);
+static GstFlowReturn gst_flv_mux_write_eos (GstFlvMux * mux);
+static GstFlowReturn gst_flv_mux_write_header (GstFlvMux * mux);
+static GstFlowReturn gst_flv_mux_rewrite_header (GstFlvMux * mux);
+static gboolean gst_flv_mux_are_all_pads_eos (GstFlvMux * mux);
+
+
+static GstFlowReturn
+gst_flv_mux_pad_flush (GstAggregatorPad * pad, GstAggregator * aggregator)
+{
+  GstFlvMuxPad *flvpad = GST_FLV_MUX_PAD (pad);
+
+  flvpad->last_timestamp = 0;
+  flvpad->pts = GST_CLOCK_STIME_NONE;
+  flvpad->dts = GST_CLOCK_STIME_NONE;
+
+  return GST_FLOW_OK;
+}
+
+static void
+gst_flv_mux_pad_class_init (GstFlvMuxPadClass * klass)
+{
+  GstAggregatorPadClass *aggregatorpad_class = (GstAggregatorPadClass *) klass;
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+
+  gobject_class->finalize = gst_flv_mux_pad_finalize;
+
+  aggregatorpad_class->flush = GST_DEBUG_FUNCPTR (gst_flv_mux_pad_flush);
+}
+
+static void
+gst_flv_mux_pad_init (GstFlvMuxPad * pad)
+{
+  gst_flv_mux_reset_pad (pad);
+}
+
+typedef struct
+{
+  gdouble position;
+  gdouble time;
+} GstFlvMuxIndexEntry;
+
+static void
+gst_flv_mux_index_entry_free (GstFlvMuxIndexEntry * entry)
+{
+  g_slice_free (GstFlvMuxIndexEntry, entry);
+}
+
+static GstBuffer *
+_gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
+{
+  GstBuffer *buf;
+
+  buf = gst_buffer_new ();
+  gst_buffer_append_memory (buf,
+      gst_memory_new_wrapped (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
+          mem, size, 0, size, mem, free_func));
+
+  return buf;
+}
+
+static void
+_gst_buffer_new_and_alloc (gsize size, GstBuffer ** buffer, guint8 ** data)
+{
+  g_return_if_fail (data != NULL);
+  g_return_if_fail (buffer != NULL);
+
+  *data = g_malloc (size);
+  *buffer = _gst_buffer_new_wrapped (*data, size, g_free);
+}
+
+static void
+gst_flv_mux_class_init (GstFlvMuxClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstAggregatorClass *gstaggregator_class;
+
+  GST_DEBUG_CATEGORY_INIT (flvmux_debug, "flvmux", 0, "FLV muxer");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstaggregator_class = (GstAggregatorClass *) klass;
+
+  gobject_class->get_property = gst_flv_mux_get_property;
+  gobject_class->set_property = gst_flv_mux_set_property;
+  gobject_class->finalize = gst_flv_mux_finalize;
+
+  /* FIXME: ideally the right mode of operation should be detected
+   * automatically using queries when parameter not specified. */
+  /**
+   * GstFlvMux:streamable
+   *
+   * If True, the output will be streaming friendly. (ie without indexes and
+   * duration)
+   */
+  g_object_class_install_property (gobject_class, PROP_STREAMABLE,
+      g_param_spec_boolean ("streamable", "streamable",
+          "If set to true, the output should be as if it is to be streamed "
+          "and hence no indexes written or duration written.",
+          DEFAULT_STREAMABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_METADATACREATOR,
+      g_param_spec_string ("metadatacreator", "metadatacreator",
+          "The value of metadatacreator in the meta packet.",
+          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstaggregator_class->create_new_pad =
+      GST_DEBUG_FUNCPTR (gst_flv_mux_create_new_pad);
+  gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_flv_mux_release_pad);
+
+  gstaggregator_class->start = GST_DEBUG_FUNCPTR (gst_flv_mux_start);
+  gstaggregator_class->aggregate = GST_DEBUG_FUNCPTR (gst_flv_mux_aggregate);
+  gstaggregator_class->sink_event = GST_DEBUG_FUNCPTR (gst_flv_mux_sink_event);
+  gstaggregator_class->flush = GST_DEBUG_FUNCPTR (gst_flv_mux_flush);
+  gstaggregator_class->get_next_time =
+      GST_DEBUG_FUNCPTR (gst_flv_mux_get_next_time);
+
+  gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
+      &videosink_templ, GST_TYPE_FLV_MUX_PAD);
+  gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
+      &audiosink_templ, GST_TYPE_FLV_MUX_PAD);
+  gst_element_class_add_static_pad_template (gstelement_class, &src_templ);
+  gst_element_class_set_static_metadata (gstelement_class, "FLV muxer",
+      "Codec/Muxer",
+      "Muxes video/audio streams into a FLV stream",
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  GST_DEBUG_CATEGORY_INIT (flvmux_debug, "flvmux", 0, "FLV muxer");
+}
+
+static void
+gst_flv_mux_init (GstFlvMux * mux)
+{
+  mux->srcpad = GST_AGGREGATOR_CAST (mux)->srcpad;
+
+  /* property */
+  mux->streamable = DEFAULT_STREAMABLE;
+  mux->metadatacreator = g_strdup (DEFAULT_METADATACREATOR);
+
+  mux->new_tags = FALSE;
+
+  gst_flv_mux_reset (GST_ELEMENT (mux));
+}
+
+static void
+gst_flv_mux_finalize (GObject * object)
+{
+  GstFlvMux *mux = GST_FLV_MUX (object);
+
+  gst_flv_mux_reset (GST_ELEMENT (object));
+  g_free (mux->metadatacreator);
+
+  G_OBJECT_CLASS (gst_flv_mux_parent_class)->finalize (object);
+}
+
+static void
+gst_flv_mux_pad_finalize (GObject * object)
+{
+  GstFlvMuxPad *pad = GST_FLV_MUX_PAD (object);
+
+  gst_flv_mux_reset_pad (pad);
+
+  G_OBJECT_CLASS (gst_flv_mux_pad_parent_class)->finalize (object);
+}
+
+static GstFlowReturn
+gst_flv_mux_flush (GstAggregator * aggregator)
+{
+  /* TODO: What is the right behaviour on flush? Should we just ignore it ?
+   * This still needs to be defined. */
+
+  gst_flv_mux_reset (GST_ELEMENT (aggregator));
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_flv_mux_start (GstAggregator * aggregator)
+{
+  gst_flv_mux_reset (GST_ELEMENT (aggregator));
+  return TRUE;
+}
+
+static void
+gst_flv_mux_reset (GstElement * element)
+{
+  GstFlvMux *mux = GST_FLV_MUX (element);
+
+  g_list_foreach (mux->index, (GFunc) gst_flv_mux_index_entry_free, NULL);
+  g_list_free (mux->index);
+  mux->index = NULL;
+  mux->byte_count = 0;
+
+  mux->duration = GST_CLOCK_TIME_NONE;
+  mux->new_tags = FALSE;
+  mux->first_timestamp = GST_CLOCK_STIME_NONE;
+
+  mux->state = GST_FLV_MUX_STATE_HEADER;
+
+  /* tags */
+  gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
+}
+
+/* Extract per-codec relevant tags for
+ * insertion into the metadata later - ie bitrate,
+ * but maybe others in the future */
+static void
+gst_flv_mux_store_codec_tags (GstFlvMux * mux,
+    GstFlvMuxPad * flvpad, GstTagList * list)
+{
+  /* Look for a bitrate as either nominal or actual bitrate tag */
+  if (gst_tag_list_get_uint (list, GST_TAG_NOMINAL_BITRATE, &flvpad->bitrate)
+      || gst_tag_list_get_uint (list, GST_TAG_BITRATE, &flvpad->bitrate)) {
+    GST_DEBUG_OBJECT (mux, "Stored bitrate for pad %" GST_PTR_FORMAT " = %u",
+        flvpad, flvpad->bitrate);
+  }
+}
+
+static gboolean
+gst_flv_mux_sink_event (GstAggregator * aggregator, GstAggregatorPad * pad,
+    GstEvent * event)
+{
+  GstFlvMux *mux = GST_FLV_MUX (aggregator);
+  GstFlvMuxPad *flvpad = (GstFlvMuxPad *) pad;
+  gboolean ret = TRUE;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+
+      if (mux->video_pad == flvpad) {
+        ret = gst_flv_mux_video_pad_setcaps (flvpad, caps);
+      } else if (mux->audio_pad == flvpad) {
+        ret = gst_flv_mux_audio_pad_setcaps (flvpad, caps);
+      } else {
+        g_assert_not_reached ();
+      }
+      break;
+    }
+    case GST_EVENT_TAG:{
+      GstTagList *list;
+      GstTagSetter *setter = GST_TAG_SETTER (mux);
+      const GstTagMergeMode mode = gst_tag_setter_get_tag_merge_mode (setter);
+
+      gst_event_parse_tag (event, &list);
+      gst_tag_setter_merge_tags (setter, list, mode);
+      gst_flv_mux_store_codec_tags (mux, flvpad, list);
+      mux->new_tags = TRUE;
+      ret = TRUE;
+      break;
+    }
+    default:
+      break;
+  }
+
+  if (!ret)
+    return FALSE;
+
+  return GST_AGGREGATOR_CLASS (parent_class)->sink_event (aggregator, pad,
+      event);;
+}
+
+static gboolean
+gst_flv_mux_video_pad_setcaps (GstFlvMuxPad * pad, GstCaps * caps)
+{
+  GstFlvMux *mux = GST_FLV_MUX (gst_pad_get_parent (pad));
+  gboolean ret = TRUE;
+  GstStructure *s;
+
+  s = gst_caps_get_structure (caps, 0);
+
+  if (strcmp (gst_structure_get_name (s), "video/x-flash-video") == 0) {
+    pad->codec = 2;
+  } else if (strcmp (gst_structure_get_name (s), "video/x-flash-screen") == 0) {
+    pad->codec = 3;
+  } else if (strcmp (gst_structure_get_name (s), "video/x-vp6-flash") == 0) {
+    pad->codec = 4;
+  } else if (strcmp (gst_structure_get_name (s), "video/x-vp6-alpha") == 0) {
+    pad->codec = 5;
+  } else if (strcmp (gst_structure_get_name (s), "video/x-h264") == 0) {
+    pad->codec = 7;
+  } else {
+    ret = FALSE;
+  }
+
+  if (ret && gst_structure_has_field (s, "codec_data")) {
+    const GValue *val = gst_structure_get_value (s, "codec_data");
+
+    if (val)
+      pad->codec_data = gst_buffer_ref (gst_value_get_buffer (val));
+  }
+
+  gst_object_unref (mux);
+
+  return ret;
+}
+
+static gboolean
+gst_flv_mux_audio_pad_setcaps (GstFlvMuxPad * pad, GstCaps * caps)
+{
+  GstFlvMux *mux = GST_FLV_MUX (gst_pad_get_parent (pad));
+  gboolean ret = TRUE;
+  GstStructure *s;
+
+  s = gst_caps_get_structure (caps, 0);
+
+  if (strcmp (gst_structure_get_name (s), "audio/x-adpcm") == 0) {
+    const gchar *layout = gst_structure_get_string (s, "layout");
+    if (layout && strcmp (layout, "swf") == 0) {
+      pad->codec = 1;
+    } else {
+      ret = FALSE;
+    }
+  } else if (strcmp (gst_structure_get_name (s), "audio/mpeg") == 0) {
+    gint mpegversion;
+
+    if (gst_structure_get_int (s, "mpegversion", &mpegversion)) {
+      if (mpegversion == 1) {
+        gint layer;
+
+        if (gst_structure_get_int (s, "layer", &layer) && layer == 3) {
+          gint rate;
+
+          if (gst_structure_get_int (s, "rate", &rate) && rate == 8000)
+            pad->codec = 14;
+          else
+            pad->codec = 2;
+        } else {
+          ret = FALSE;
+        }
+      } else if (mpegversion == 4 || mpegversion == 2) {
+        pad->codec = 10;
+      } else {
+        ret = FALSE;
+      }
+    } else {
+      ret = FALSE;
+    }
+  } else if (strcmp (gst_structure_get_name (s), "audio/x-nellymoser") == 0) {
+    gint rate, channels;
+
+    if (gst_structure_get_int (s, "rate", &rate)
+        && gst_structure_get_int (s, "channels", &channels)) {
+      if (channels == 1 && rate == 16000)
+        pad->codec = 4;
+      else if (channels == 1 && rate == 8000)
+        pad->codec = 5;
+      else
+        pad->codec = 6;
+    } else {
+      pad->codec = 6;
+    }
+  } else if (strcmp (gst_structure_get_name (s), "audio/x-raw") == 0) {
+    GstAudioInfo info;
+
+    if (gst_audio_info_from_caps (&info, caps)) {
+      pad->codec = 3;
+
+      if (GST_AUDIO_INFO_WIDTH (&info) == 8)
+        pad->width = 0;
+      else if (GST_AUDIO_INFO_WIDTH (&info) == 16)
+        pad->width = 1;
+      else
+        ret = FALSE;
+    } else
+      ret = FALSE;
+  } else if (strcmp (gst_structure_get_name (s), "audio/x-alaw") == 0) {
+    pad->codec = 7;
+  } else if (strcmp (gst_structure_get_name (s), "audio/x-mulaw") == 0) {
+    pad->codec = 8;
+  } else if (strcmp (gst_structure_get_name (s), "audio/x-speex") == 0) {
+    pad->codec = 11;
+  } else {
+    ret = FALSE;
+  }
+
+  if (ret) {
+    gint rate, channels;
+
+    if (gst_structure_get_int (s, "rate", &rate)) {
+      if (pad->codec == 10)
+        pad->rate = 3;
+      else if (rate == 5512)
+        pad->rate = 0;
+      else if (rate == 11025)
+        pad->rate = 1;
+      else if (rate == 22050)
+        pad->rate = 2;
+      else if (rate == 44100)
+        pad->rate = 3;
+      else if (rate == 8000 && (pad->codec == 5 || pad->codec == 14))
+        pad->rate = 0;
+      else if (rate == 16000 && (pad->codec == 4 || pad->codec == 11))
+        pad->rate = 0;
+      else
+        ret = FALSE;
+    } else if (pad->codec == 10) {
+      pad->rate = 3;
+    } else {
+      ret = FALSE;
+    }
+
+    if (gst_structure_get_int (s, "channels", &channels)) {
+      if (pad->codec == 4 || pad->codec == 5
+          || pad->codec == 6 || pad->codec == 11)
+        pad->channels = 0;
+      else if (pad->codec == 10)
+        pad->channels = 1;
+      else if (channels == 1)
+        pad->channels = 0;
+      else if (channels == 2)
+        pad->channels = 1;
+      else
+        ret = FALSE;
+    } else if (pad->codec == 4 || pad->codec == 5 || pad->codec == 6) {
+      pad->channels = 0;
+    } else if (pad->codec == 10) {
+      pad->channels = 1;
+    } else {
+      ret = FALSE;
+    }
+
+    if (pad->codec != 3)
+      pad->width = 1;
+  }
+
+  if (ret && gst_structure_has_field (s, "codec_data")) {
+    const GValue *val = gst_structure_get_value (s, "codec_data");
+
+    if (val)
+      pad->codec_data = gst_buffer_ref (gst_value_get_buffer (val));
+  }
+
+  gst_object_unref (mux);
+
+  return ret;
+}
+
+static void
+gst_flv_mux_reset_pad (GstFlvMuxPad * pad)
+{
+  GST_DEBUG_OBJECT (pad, "resetting pad");
+
+  if (pad->codec_data)
+    gst_buffer_unref (pad->codec_data);
+  pad->codec_data = NULL;
+  pad->codec = G_MAXUINT;
+  pad->rate = G_MAXUINT;
+  pad->width = G_MAXUINT;
+  pad->channels = G_MAXUINT;
+
+  gst_flv_mux_pad_flush (GST_AGGREGATOR_PAD_CAST (pad), NULL);
+}
+
+static GstAggregatorPad *
+gst_flv_mux_create_new_pad (GstAggregator * agg,
+    GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (agg);
+  GstAggregatorPad *aggpad;
+  GstFlvMux *mux = GST_FLV_MUX (agg);
+  GstFlvMuxPad *pad = NULL;
+  const gchar *name = NULL;
+  gboolean video;
+
+  if (mux->state != GST_FLV_MUX_STATE_HEADER) {
+    GST_WARNING_OBJECT (mux, "Can't request pads after writing header");
+    return NULL;
+  }
+
+  if (templ == gst_element_class_get_pad_template (klass, "audio")) {
+    if (mux->audio_pad) {
+      GST_WARNING_OBJECT (mux, "Already have an audio pad");
+      return NULL;
+    }
+    name = "audio";
+    video = FALSE;
+  } else if (templ == gst_element_class_get_pad_template (klass, "video")) {
+    if (mux->video_pad) {
+      GST_WARNING_OBJECT (mux, "Already have a video pad");
+      return NULL;
+    }
+    name = "video";
+    video = TRUE;
+  } else {
+    GST_WARNING_OBJECT (mux, "Invalid template");
+    return NULL;
+  }
+
+  aggpad =
+      GST_AGGREGATOR_CLASS (gst_flv_mux_parent_class)->create_new_pad (agg,
+      templ, name, caps);
+  if (aggpad == NULL)
+    return NULL;
+
+  pad = GST_FLV_MUX_PAD (aggpad);
+
+  gst_flv_mux_reset_pad (pad);
+
+  if (video)
+    mux->video_pad = pad;
+  else
+    mux->audio_pad = pad;
+
+  return aggpad;
+}
+
+static void
+gst_flv_mux_release_pad (GstElement * element, GstPad * pad)
+{
+  GstFlvMux *mux = GST_FLV_MUX (element);
+  GstFlvMuxPad *flvpad = GST_FLV_MUX_PAD (pad);
+
+  gst_pad_set_active (pad, FALSE);
+  gst_flv_mux_reset_pad (flvpad);
+
+  if (flvpad == mux->video_pad) {
+    mux->video_pad = NULL;
+  } else if (flvpad == mux->audio_pad) {
+    mux->audio_pad = NULL;
+  } else {
+    GST_WARNING_OBJECT (pad, "Pad is not known audio or video pad");
+  }
+
+  gst_element_remove_pad (element, pad);
+}
+
+static GstFlowReturn
+gst_flv_mux_push (GstFlvMux * mux, GstBuffer * buffer)
+{
+  /* pushing the buffer that rewrites the header will make it no longer be the
+   * total output size in bytes, but it doesn't matter at that point */
+  mux->byte_count += gst_buffer_get_size (buffer);
+
+  return gst_aggregator_finish_buffer (GST_AGGREGATOR_CAST (mux), buffer);
+}
+
+static GstBuffer *
+gst_flv_mux_create_header (GstFlvMux * mux)
+{
+  GstBuffer *header;
+  guint8 *data;
+  gboolean have_audio;
+  gboolean have_video;
+
+  _gst_buffer_new_and_alloc (9 + 4, &header, &data);
+
+  data[0] = 'F';
+  data[1] = 'L';
+  data[2] = 'V';
+  data[3] = 0x01;               /* Version */
+
+  have_audio = (mux->audio_pad && mux->audio_pad->codec != G_MAXUINT);
+  have_video = (mux->video_pad && mux->video_pad->codec != G_MAXUINT);
+
+  data[4] = (have_audio << 2) | have_video;     /* flags */
+  GST_WRITE_UINT32_BE (data + 5, 9);    /* data offset */
+  GST_WRITE_UINT32_BE (data + 9, 0);    /* previous tag size */
+
+  return header;
+}
+
+static GstBuffer *
+gst_flv_mux_preallocate_index (GstFlvMux * mux)
+{
+  GstBuffer *tmp;
+  guint8 *data;
+  gint preallocate_size;
+
+  /* preallocate index of size:
+   *  - 'keyframes' ECMA array key: 2 + 9 = 11 bytes
+   *  - nested ECMA array header, length and end marker: 8 bytes
+   *  - 'times' and 'filepositions' keys: 22 bytes
+   *  - two strict arrays headers and lengths: 10 bytes
+   *  - each index entry: 18 bytes
+   */
+  preallocate_size = 11 + 8 + 22 + 10 + MAX_INDEX_ENTRIES * 18;
+  GST_DEBUG_OBJECT (mux, "preallocating %d bytes for the index",
+      preallocate_size);
+
+  _gst_buffer_new_and_alloc (preallocate_size, &tmp, &data);
+
+  /* prefill the space with a gstfiller: <spaces> script tag variable */
+  GST_WRITE_UINT16_BE (data, 9);        /* 9 characters */
+  memcpy (data + 2, "gstfiller", 9);
+  GST_WRITE_UINT8 (data + 11, AMF0_STRING_MARKER);      /* a string value */
+  GST_WRITE_UINT16_BE (data + 12, preallocate_size - 14);
+  memset (data + 14, ' ', preallocate_size - 14);       /* the rest is spaces */
+  return tmp;
+}
+
+static GstBuffer *
+gst_flv_mux_create_number_script_value (const gchar * name, gdouble value)
+{
+  GstBuffer *tmp;
+  guint8 *data;
+  gsize len = strlen (name);
+
+  _gst_buffer_new_and_alloc (2 + len + 1 + 8, &tmp, &data);
+
+  GST_WRITE_UINT16_BE (data, len);
+  data += 2;                    /* name length */
+  memcpy (data, name, len);
+  data += len;
+  *data++ = AMF0_NUMBER_MARKER; /* double type */
+  GST_WRITE_DOUBLE_BE (data, value);
+
+  return tmp;
+}
+
+static GstBuffer *
+gst_flv_mux_create_metadata (GstFlvMux * mux, gboolean full)
+{
+  const GstTagList *tags;
+  GstBuffer *script_tag, *tmp;
+  GstMapInfo map;
+  guint8 *data;
+  gint i, n_tags, tags_written = 0;
+
+  tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
+
+  GST_DEBUG_OBJECT (mux, "tags = %" GST_PTR_FORMAT, tags);
+
+  /* FIXME perhaps some bytewriter'ing here ... */
+
+  _gst_buffer_new_and_alloc (11, &script_tag, &data);
+
+  data[0] = 18;
+
+  /* Data size, unknown for now */
+  data[1] = 0;
+  data[2] = 0;
+  data[3] = 0;
+
+  /* Timestamp */
+  data[4] = data[5] = data[6] = data[7] = 0;
+
+  /* Stream ID */
+  data[8] = data[9] = data[10] = 0;
+
+  _gst_buffer_new_and_alloc (13, &tmp, &data);
+  data[0] = AMF0_STRING_MARKER; /* string */
+  data[1] = 0;
+  data[2] = 10;                 /* length 10 */
+  memcpy (&data[3], "onMetaData", 10);
+
+  script_tag = gst_buffer_append (script_tag, tmp);
+
+  n_tags = (tags) ? gst_tag_list_n_tags (tags) : 0;
+  _gst_buffer_new_and_alloc (5, &tmp, &data);
+  data[0] = 8;                  /* ECMA array */
+  GST_WRITE_UINT32_BE (data + 1, n_tags);
+  script_tag = gst_buffer_append (script_tag, tmp);
+
+  if (!full)
+    goto tags;
+
+  /* Some players expect the 'duration' to be always set. Fill it out later,
+     after querying the pads or after getting EOS */
+  if (!mux->streamable) {
+    tmp = gst_flv_mux_create_number_script_value ("duration", 86400);
+    script_tag = gst_buffer_append (script_tag, tmp);
+    tags_written++;
+
+    /* Sometimes the information about the total file size is useful for the
+       player. It will be filled later, after getting EOS */
+    tmp = gst_flv_mux_create_number_script_value ("filesize", 0);
+    script_tag = gst_buffer_append (script_tag, tmp);
+    tags_written++;
+
+    /* Preallocate space for the index to be written at EOS */
+    tmp = gst_flv_mux_preallocate_index (mux);
+    script_tag = gst_buffer_append (script_tag, tmp);
+  } else {
+    GST_DEBUG_OBJECT (mux, "not preallocating index, streamable mode");
+  }
+
+tags:
+  for (i = 0; tags && i < n_tags; i++) {
+    const gchar *tag_name = gst_tag_list_nth_tag_name (tags, i);
+    if (!strcmp (tag_name, GST_TAG_DURATION)) {
+      guint64 dur;
+
+      if (!gst_tag_list_get_uint64 (tags, GST_TAG_DURATION, &dur))
+        continue;
+      mux->duration = dur;
+    } else if (!strcmp (tag_name, GST_TAG_ARTIST) ||
+        !strcmp (tag_name, GST_TAG_TITLE)) {
+      gchar *s;
+      const gchar *t = NULL;
+
+      if (!strcmp (tag_name, GST_TAG_ARTIST))
+        t = "creator";
+      else if (!strcmp (tag_name, GST_TAG_TITLE))
+        t = "title";
+
+      if (!gst_tag_list_get_string (tags, tag_name, &s))
+        continue;
+
+      _gst_buffer_new_and_alloc (2 + strlen (t) + 1 + 2 + strlen (s),
+          &tmp, &data);
+      data[0] = 0;              /* tag name length */
+      data[1] = strlen (t);
+      memcpy (&data[2], t, strlen (t));
+      data[2 + strlen (t)] = 2; /* string */
+      data[3 + strlen (t)] = (strlen (s) >> 8) & 0xff;
+      data[4 + strlen (t)] = (strlen (s)) & 0xff;
+      memcpy (&data[5 + strlen (t)], s, strlen (s));
+      script_tag = gst_buffer_append (script_tag, tmp);
+
+      g_free (s);
+      tags_written++;
+    }
+  }
+
+  if (!full)
+    goto end;
+
+  if (mux->duration == GST_CLOCK_TIME_NONE) {
+    GList *l;
+    guint64 dur;
+
+    for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
+      GstFlvMuxPad *pad = GST_FLV_MUX_PAD (l->data);
+
+      if (gst_pad_peer_query_duration (GST_PAD (pad), GST_FORMAT_TIME,
+              (gint64 *) & dur) && dur != GST_CLOCK_TIME_NONE) {
+        if (mux->duration == GST_CLOCK_TIME_NONE)
+          mux->duration = dur;
+        else
+          mux->duration = MAX (dur, mux->duration);
+      }
+    }
+  }
+
+  if (!mux->streamable && mux->duration != GST_CLOCK_TIME_NONE) {
+    gdouble d;
+    GstMapInfo map;
+
+    d = gst_guint64_to_gdouble (mux->duration);
+    d /= (gdouble) GST_SECOND;
+
+    GST_DEBUG_OBJECT (mux, "determined the duration to be %f", d);
+    gst_buffer_map (script_tag, &map, GST_MAP_WRITE);
+    GST_WRITE_DOUBLE_BE (map.data + 29 + 2 + 8 + 1, d);
+    gst_buffer_unmap (script_tag, &map);
+  }
+
+  if (mux->video_pad && mux->video_pad->codec != G_MAXUINT) {
+    GstCaps *caps = NULL;
+
+    if (mux->video_pad)
+      caps = gst_pad_get_current_caps (GST_PAD (mux->video_pad));
+
+    if (caps != NULL) {
+      GstStructure *s;
+      gint size;
+      gint num, den;
+
+      GST_DEBUG_OBJECT (mux, "putting videocodecid %d in the metadata",
+          mux->video_pad->codec);
+
+      tmp = gst_flv_mux_create_number_script_value ("videocodecid",
+          mux->video_pad->codec);
+      script_tag = gst_buffer_append (script_tag, tmp);
+      tags_written++;
+
+      s = gst_caps_get_structure (caps, 0);
+      gst_caps_unref (caps);
+
+      if (gst_structure_get_int (s, "width", &size)) {
+        GST_DEBUG_OBJECT (mux, "putting width %d in the metadata", size);
+
+        tmp = gst_flv_mux_create_number_script_value ("width", size);
+        script_tag = gst_buffer_append (script_tag, tmp);
+        tags_written++;
+      }
+
+      if (gst_structure_get_int (s, "height", &size)) {
+        GST_DEBUG_OBJECT (mux, "putting height %d in the metadata", size);
+
+        tmp = gst_flv_mux_create_number_script_value ("height", size);
+        script_tag = gst_buffer_append (script_tag, tmp);
+        tags_written++;
+      }
+
+      if (gst_structure_get_fraction (s, "pixel-aspect-ratio", &num, &den)) {
+        gdouble d;
+
+        d = num;
+        GST_DEBUG_OBJECT (mux, "putting AspectRatioX %f in the metadata", d);
+
+        tmp = gst_flv_mux_create_number_script_value ("AspectRatioX", d);
+        script_tag = gst_buffer_append (script_tag, tmp);
+        tags_written++;
+
+        d = den;
+        GST_DEBUG_OBJECT (mux, "putting AspectRatioY %f in the metadata", d);
+
+        tmp = gst_flv_mux_create_number_script_value ("AspectRatioY", d);
+        script_tag = gst_buffer_append (script_tag, tmp);
+        tags_written++;
+      }
+
+      if (gst_structure_get_fraction (s, "framerate", &num, &den)) {
+        gdouble d;
+
+        gst_util_fraction_to_double (num, den, &d);
+        GST_DEBUG_OBJECT (mux, "putting framerate %f in the metadata", d);
+
+        tmp = gst_flv_mux_create_number_script_value ("framerate", d);
+        script_tag = gst_buffer_append (script_tag, tmp);
+        tags_written++;
+      }
+
+      GST_DEBUG_OBJECT (mux, "putting videodatarate %u KB/s in the metadata",
+          mux->video_pad->bitrate / 1024);
+      tmp = gst_flv_mux_create_number_script_value ("videodatarate",
+          mux->video_pad->bitrate / 1024);
+      script_tag = gst_buffer_append (script_tag, tmp);
+      tags_written++;
+    }
+  }
+
+  if (mux->audio_pad && mux->audio_pad->codec != G_MAXUINT) {
+    GST_DEBUG_OBJECT (mux, "putting audiocodecid %d in the metadata",
+        mux->audio_pad->codec);
+
+    tmp = gst_flv_mux_create_number_script_value ("audiocodecid",
+        mux->audio_pad->codec);
+    script_tag = gst_buffer_append (script_tag, tmp);
+    tags_written++;
+
+    GST_DEBUG_OBJECT (mux, "putting audiodatarate %u KB/s in the metadata",
+        mux->audio_pad->bitrate / 1024);
+    tmp = gst_flv_mux_create_number_script_value ("audiodatarate",
+        mux->audio_pad->bitrate / 1024);
+    script_tag = gst_buffer_append (script_tag, tmp);
+    tags_written++;
+  }
+
+  _gst_buffer_new_and_alloc (2 + 15 + 1 + 2 + strlen (mux->metadatacreator),
+      &tmp, &data);
+  data[0] = 0;                  /* 15 bytes name */
+  data[1] = 15;
+  memcpy (&data[2], "metadatacreator", 15);
+  data[17] = 2;                 /* string */
+  data[18] = (strlen (mux->metadatacreator) >> 8) & 0xff;
+  data[19] = (strlen (mux->metadatacreator)) & 0xff;
+  memcpy (&data[20], mux->metadatacreator, strlen (mux->metadatacreator));
+  script_tag = gst_buffer_append (script_tag, tmp);
+
+  tags_written++;
+
+  {
+    GTimeVal tv = { 0, };
+    time_t secs;
+    struct tm *tm;
+    gchar *s;
+    static const gchar *weekdays[] = {
+      "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+    };
+    static const gchar *months[] = {
+      "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
+      "Aug", "Sep", "Oct", "Nov", "Dec"
+    };
+
+    g_get_current_time (&tv);
+    secs = tv.tv_sec;
+    tm = gmtime (&secs);
+
+    s = g_strdup_printf ("%s %s %d %02d:%02d:%02d %d", weekdays[tm->tm_wday],
+        months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
+        tm->tm_year + 1900);
+
+    _gst_buffer_new_and_alloc (2 + 12 + 1 + 2 + strlen (s), &tmp, &data);
+    data[0] = 0;                /* 12 bytes name */
+    data[1] = 12;
+    memcpy (&data[2], "creationdate", 12);
+    data[14] = 2;               /* string */
+    data[15] = (strlen (s) >> 8) & 0xff;
+    data[16] = (strlen (s)) & 0xff;
+    memcpy (&data[17], s, strlen (s));
+    script_tag = gst_buffer_append (script_tag, tmp);
+
+    g_free (s);
+    tags_written++;
+  }
+
+end:
+
+  if (!tags_written) {
+    gst_buffer_unref (script_tag);
+    script_tag = NULL;
+    goto exit;
+  }
+
+  _gst_buffer_new_and_alloc (2 + 0 + 1, &tmp, &data);
+  data[0] = 0;                  /* 0 byte size */
+  data[1] = 0;
+  data[2] = 9;                  /* end marker */
+  script_tag = gst_buffer_append (script_tag, tmp);
+
+
+  _gst_buffer_new_and_alloc (4, &tmp, &data);
+  GST_WRITE_UINT32_BE (data, gst_buffer_get_size (script_tag));
+  script_tag = gst_buffer_append (script_tag, tmp);
+
+  gst_buffer_map (script_tag, &map, GST_MAP_WRITE);
+  map.data[1] = ((gst_buffer_get_size (script_tag) - 11 - 4) >> 16) & 0xff;
+  map.data[2] = ((gst_buffer_get_size (script_tag) - 11 - 4) >> 8) & 0xff;
+  map.data[3] = ((gst_buffer_get_size (script_tag) - 11 - 4) >> 0) & 0xff;
+
+  GST_WRITE_UINT32_BE (map.data + 11 + 13 + 1, tags_written);
+  gst_buffer_unmap (script_tag, &map);
+
+exit:
+  return script_tag;
+}
+
+static GstBuffer *
+gst_flv_mux_buffer_to_tag_internal (GstFlvMux * mux, GstBuffer * buffer,
+    GstFlvMuxPad * pad, gboolean is_codec_data)
+{
+  GstBuffer *tag;
+  GstMapInfo map;
+  guint size;
+  guint32 pts, dts, cts;
+  guint8 *data, *bdata = NULL;
+  gsize bsize = 0;
+
+  if (!GST_CLOCK_STIME_IS_VALID (pad->dts)) {
+    pts = dts = pad->last_timestamp / GST_MSECOND;
+  } else {
+    pts = pad->pts / GST_MSECOND;
+    dts = pad->dts / GST_MSECOND;
+  }
+
+  /* Be safe in case TS are buggy */
+  if (pts > dts)
+    cts = pts - dts;
+  else
+    cts = 0;
+
+  /* Timestamp must start at zero */
+  if (GST_CLOCK_STIME_IS_VALID (mux->first_timestamp)) {
+    dts -= mux->first_timestamp / GST_MSECOND;
+    pts = dts + cts;
+  }
+
+  GST_LOG_OBJECT (mux, "got pts %i dts %i cts %i", pts, dts, cts);
+
+  if (buffer != NULL) {
+    gst_buffer_map (buffer, &map, GST_MAP_READ);
+    bdata = map.data;
+    bsize = map.size;
+  }
+
+  size = 11;
+  if (mux->video_pad == pad) {
+    size += 1;
+    if (pad->codec == 7)
+      size += 4 + bsize;
+    else
+      size += bsize;
+  } else {
+    size += 1;
+    if (pad->codec == 10)
+      size += 1 + bsize;
+    else
+      size += bsize;
+  }
+  size += 4;
+
+  _gst_buffer_new_and_alloc (size, &tag, &data);
+  memset (data, 0, size);
+
+  data[0] = (mux->video_pad == pad) ? 9 : 8;
+
+  data[1] = ((size - 11 - 4) >> 16) & 0xff;
+  data[2] = ((size - 11 - 4) >> 8) & 0xff;
+  data[3] = ((size - 11 - 4) >> 0) & 0xff;
+
+  GST_WRITE_UINT24_BE (data + 4, dts);
+  data[7] = (((guint) dts) >> 24) & 0xff;
+
+  data[8] = data[9] = data[10] = 0;
+
+  if (mux->video_pad == pad) {
+    if (buffer && GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT))
+      data[11] |= 2 << 4;
+    else
+      data[11] |= 1 << 4;
+
+    data[11] |= pad->codec & 0x0f;
+
+    if (pad->codec == 7) {
+      if (is_codec_data) {
+        data[12] = 0;
+        GST_WRITE_UINT24_BE (data + 13, 0);
+      } else if (bsize == 0) {
+        /* AVC end of sequence */
+        data[12] = 2;
+        GST_WRITE_UINT24_BE (data + 13, 0);
+      } else {
+        /* ACV NALU */
+        data[12] = 1;
+        GST_WRITE_UINT24_BE (data + 13, cts);
+      }
+      memcpy (data + 11 + 1 + 4, bdata, bsize);
+    } else {
+      memcpy (data + 11 + 1, bdata, bsize);
+    }
+  } else {
+    data[11] |= (pad->codec << 4) & 0xf0;
+    data[11] |= (pad->rate << 2) & 0x0c;
+    data[11] |= (pad->width << 1) & 0x02;
+    data[11] |= (pad->channels << 0) & 0x01;
+
+    GST_DEBUG_OBJECT (mux, "Creating byte %02x with "
+        "codec:%d, rate:%d, width:%d, channels:%d",
+        data[11], pad->codec, pad->rate, pad->width, pad->channels);
+
+    if (pad->codec == 10) {
+      data[12] = is_codec_data ? 0 : 1;
+
+      memcpy (data + 11 + 1 + 1, bdata, bsize);
+    } else {
+      memcpy (data + 11 + 1, bdata, bsize);
+    }
+  }
+
+  if (buffer)
+    gst_buffer_unmap (buffer, &map);
+
+  GST_WRITE_UINT32_BE (data + size - 4, size - 4);
+
+  GST_BUFFER_PTS (tag) = GST_CLOCK_TIME_NONE;
+  GST_BUFFER_DTS (tag) = GST_CLOCK_TIME_NONE;
+  GST_BUFFER_DURATION (tag) = GST_CLOCK_TIME_NONE;
+
+  if (buffer) {
+    /* if we are streamable we copy over timestamps and offsets,
+       if not just copy the offsets */
+    if (mux->streamable) {
+      gst_buffer_copy_into (tag, buffer, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+      GST_BUFFER_OFFSET (tag) = GST_BUFFER_OFFSET_NONE;
+      GST_BUFFER_OFFSET_END (tag) = GST_BUFFER_OFFSET_NONE;
+    } else {
+      GST_BUFFER_OFFSET (tag) = GST_BUFFER_OFFSET (buffer);
+      GST_BUFFER_OFFSET_END (tag) = GST_BUFFER_OFFSET_END (buffer);
+    }
+
+    /* mark the buffer if it's an audio buffer and there's also video being muxed
+     * or it's a video interframe */
+    if (mux->video_pad == pad &&
+        GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT))
+      GST_BUFFER_FLAG_SET (tag, GST_BUFFER_FLAG_DELTA_UNIT);
+  } else {
+    GST_BUFFER_FLAG_SET (tag, GST_BUFFER_FLAG_DELTA_UNIT);
+    GST_BUFFER_OFFSET (tag) = GST_BUFFER_OFFSET_END (tag) =
+        GST_BUFFER_OFFSET_NONE;
+  }
+
+  return tag;
+}
+
+static inline GstBuffer *
+gst_flv_mux_buffer_to_tag (GstFlvMux * mux, GstBuffer * buffer,
+    GstFlvMuxPad * pad)
+{
+  return gst_flv_mux_buffer_to_tag_internal (mux, buffer, pad, FALSE);
+}
+
+static inline GstBuffer *
+gst_flv_mux_codec_data_buffer_to_tag (GstFlvMux * mux, GstBuffer * buffer,
+    GstFlvMuxPad * pad)
+{
+  return gst_flv_mux_buffer_to_tag_internal (mux, buffer, pad, TRUE);
+}
+
+static inline GstBuffer *
+gst_flv_mux_eos_to_tag (GstFlvMux * mux, GstFlvMuxPad * pad)
+{
+  return gst_flv_mux_buffer_to_tag_internal (mux, NULL, pad, FALSE);
+}
+
+static void
+gst_flv_mux_put_buffer_in_streamheader (GValue * streamheader,
+    GstBuffer * buffer)
+{
+  GValue value = { 0 };
+  GstBuffer *buf;
+
+  g_value_init (&value, GST_TYPE_BUFFER);
+  buf = gst_buffer_copy (buffer);
+  gst_value_set_buffer (&value, buf);
+  gst_buffer_unref (buf);
+  gst_value_array_append_value (streamheader, &value);
+  g_value_unset (&value);
+}
+
+static GstFlowReturn
+gst_flv_mux_write_header (GstFlvMux * mux)
+{
+  GstBuffer *header, *metadata;
+  GstBuffer *video_codec_data, *audio_codec_data;
+  GstCaps *caps;
+  GstStructure *structure;
+  GValue streamheader = { 0 };
+  GList *l;
+  GstFlowReturn ret;
+
+  /* if not streaming, check if downstream is seekable */
+  if (!mux->streamable) {
+    gboolean seekable;
+    GstQuery *query;
+
+    query = gst_query_new_seeking (GST_FORMAT_BYTES);
+    if (gst_pad_peer_query (mux->srcpad, query)) {
+      gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
+      GST_INFO_OBJECT (mux, "downstream is %sseekable", seekable ? "" : "not ");
+    } else {
+      /* have to assume seeking is supported if query not handled downstream */
+      GST_WARNING_OBJECT (mux, "downstream did not handle seeking query");
+      seekable = FALSE;
+    }
+    if (!seekable) {
+      mux->streamable = TRUE;
+      g_object_notify (G_OBJECT (mux), "streamable");
+      GST_WARNING_OBJECT (mux, "downstream is not seekable, but "
+          "streamable=false. Will ignore that and create streamable output "
+          "instead");
+    }
+    gst_query_unref (query);
+  }
+
+  header = gst_flv_mux_create_header (mux);
+  metadata = gst_flv_mux_create_metadata (mux, TRUE);
+  video_codec_data = NULL;
+  audio_codec_data = NULL;
+
+  for (l = GST_ELEMENT_CAST (mux)->sinkpads; l != NULL; l = l->next) {
+    GstFlvMuxPad *pad = l->data;
+
+    /* Get H.264 and AAC codec data, if present */
+    if (pad && mux->video_pad == pad && pad->codec == 7) {
+      if (pad->codec_data == NULL)
+        GST_WARNING_OBJECT (mux, "Codec data for video stream not found, "
+            "output might not be playable");
+      else
+        video_codec_data =
+            gst_flv_mux_codec_data_buffer_to_tag (mux, pad->codec_data, pad);
+    } else if (pad && mux->audio_pad == pad && pad->codec == 10) {
+      if (pad->codec_data == NULL)
+        GST_WARNING_OBJECT (mux, "Codec data for audio stream not found, "
+            "output might not be playable");
+      else
+        audio_codec_data =
+            gst_flv_mux_codec_data_buffer_to_tag (mux, pad->codec_data, pad);
+    }
+  }
+
+  /* mark buffers that will go in the streamheader */
+  GST_BUFFER_FLAG_SET (header, GST_BUFFER_FLAG_HEADER);
+  GST_BUFFER_FLAG_SET (metadata, GST_BUFFER_FLAG_HEADER);
+  if (video_codec_data != NULL) {
+    GST_BUFFER_FLAG_SET (video_codec_data, GST_BUFFER_FLAG_HEADER);
+    /* mark as a delta unit, so downstream will not try to synchronize on that
+     * buffer - to actually start playback you need a real video keyframe */
+    GST_BUFFER_FLAG_SET (video_codec_data, GST_BUFFER_FLAG_DELTA_UNIT);
+  }
+  if (audio_codec_data != NULL) {
+    GST_BUFFER_FLAG_SET (audio_codec_data, GST_BUFFER_FLAG_HEADER);
+  }
+
+  /* put buffers in streamheader */
+  g_value_init (&streamheader, GST_TYPE_ARRAY);
+  gst_flv_mux_put_buffer_in_streamheader (&streamheader, header);
+  gst_flv_mux_put_buffer_in_streamheader (&streamheader, metadata);
+  if (video_codec_data != NULL)
+    gst_flv_mux_put_buffer_in_streamheader (&streamheader, video_codec_data);
+  if (audio_codec_data != NULL)
+    gst_flv_mux_put_buffer_in_streamheader (&streamheader, audio_codec_data);
+
+  /* create the caps and put the streamheader in them */
+  caps = gst_caps_new_empty_simple ("video/x-flv");
+  structure = gst_caps_get_structure (caps, 0);
+  gst_structure_set_value (structure, "streamheader", &streamheader);
+  g_value_unset (&streamheader);
+
+  gst_aggregator_set_src_caps (GST_AGGREGATOR_CAST (mux), caps);
+
+  gst_caps_unref (caps);
+
+  /* push the header buffer, the metadata and the codec info, if any */
+  ret = gst_flv_mux_push (mux, header);
+  if (ret != GST_FLOW_OK)
+    goto failure_header;
+  ret = gst_flv_mux_push (mux, metadata);
+  if (ret != GST_FLOW_OK)
+    goto failure_metadata;
+  if (video_codec_data != NULL) {
+    ret = gst_flv_mux_push (mux, video_codec_data);
+    if (ret != GST_FLOW_OK)
+      goto failure_video_codec_data;
+  }
+  if (audio_codec_data != NULL) {
+    ret = gst_flv_mux_push (mux, audio_codec_data);
+    if (ret != GST_FLOW_OK)
+      goto failure_audio_codec_data;
+  }
+  return GST_FLOW_OK;
+
+failure_header:
+  gst_buffer_unref (metadata);
+
+failure_metadata:
+  if (video_codec_data != NULL)
+    gst_buffer_unref (video_codec_data);
+
+failure_video_codec_data:
+  if (audio_codec_data != NULL)
+    gst_buffer_unref (audio_codec_data);
+
+failure_audio_codec_data:
+  return ret;
+}
+
+static GstClockTime
+gst_flv_mux_segment_to_running_time (const GstSegment * segment, GstClockTime t)
+{
+  /* we can get a dts before the segment, if dts < pts and pts is inside
+   * the segment, so we consider early times as 0 */
+  if (t < segment->start)
+    return 0;
+  return gst_segment_to_running_time (segment, GST_FORMAT_TIME, t);
+}
+
+static void
+gst_flv_mux_update_index (GstFlvMux * mux, GstBuffer * buffer,
+    GstFlvMuxPad * pad)
+{
+  /*
+   * Add the tag byte offset and to the index if it's a valid seek point, which
+   * means it's either a video keyframe or if there is no video pad (in that
+   * case every FLV tag is a valid seek point)
+   */
+  if (mux->video_pad == pad &&
+      GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT))
+    return;
+
+  if (GST_BUFFER_PTS_IS_VALID (buffer)) {
+    GstFlvMuxIndexEntry *entry = g_slice_new (GstFlvMuxIndexEntry);
+    GstClockTime pts =
+        gst_flv_mux_segment_to_running_time (&GST_AGGREGATOR_PAD
+        (pad)->segment, GST_BUFFER_PTS (buffer));
+    entry->position = mux->byte_count;
+    entry->time = gst_guint64_to_gdouble (pts) / GST_SECOND;
+    mux->index = g_list_prepend (mux->index, entry);
+  }
+}
+
+static GstFlowReturn
+gst_flv_mux_write_buffer (GstFlvMux * mux, GstFlvMuxPad * pad,
+    GstBuffer * buffer)
+{
+  GstBuffer *tag;
+  GstFlowReturn ret;
+  GstClockTime dts =
+      gst_flv_mux_segment_to_running_time (&GST_AGGREGATOR_PAD (pad)->segment,
+      GST_BUFFER_DTS (buffer));
+
+  /* clipping function arranged for running_time */
+
+  if (!mux->streamable)
+    gst_flv_mux_update_index (mux, buffer, pad);
+
+  tag = gst_flv_mux_buffer_to_tag (mux, buffer, pad);
+
+  gst_buffer_unref (buffer);
+
+  ret = gst_flv_mux_push (mux, tag);
+
+  if (ret == GST_FLOW_OK && GST_CLOCK_TIME_IS_VALID (dts))
+    pad->last_timestamp = dts;
+
+
+  return ret;
+}
+
+static guint64
+gst_flv_mux_determine_duration (GstFlvMux * mux)
+{
+  GList *l;
+  GstClockTime duration = GST_CLOCK_TIME_NONE;
+
+  GST_DEBUG_OBJECT (mux, "trying to determine the duration "
+      "from pad timestamps");
+
+  for (l = GST_ELEMENT_CAST (mux)->sinkpads; l != NULL; l = l->next) {
+    GstFlvMuxPad *pad = GST_FLV_MUX_PAD (l->data);
+
+    if (pad && (pad->last_timestamp != GST_CLOCK_TIME_NONE)) {
+      if (duration == GST_CLOCK_TIME_NONE)
+        duration = pad->last_timestamp;
+      else
+        duration = MAX (duration, pad->last_timestamp);
+    }
+  }
+
+  return duration;
+}
+
+static gboolean
+gst_flv_mux_are_all_pads_eos (GstFlvMux * mux)
+{
+  GList *l;
+
+  for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
+    GstFlvMuxPad *pad = GST_FLV_MUX_PAD (l->data);
+
+    if (!gst_aggregator_pad_is_eos (GST_AGGREGATOR_PAD (pad)))
+      return FALSE;
+  }
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_flv_mux_write_eos (GstFlvMux * mux)
+{
+  GstBuffer *tag;
+
+  if (mux->video_pad == NULL)
+    return GST_FLOW_OK;
+
+  tag = gst_flv_mux_eos_to_tag (mux, mux->video_pad);
+
+  return gst_flv_mux_push (mux, tag);
+}
+
+static GstFlowReturn
+gst_flv_mux_rewrite_header (GstFlvMux * mux)
+{
+  GstBuffer *rewrite, *index, *tmp;
+  GstEvent *event;
+  guint8 *data;
+  gdouble d;
+  GList *l;
+  guint32 index_len, allocate_size;
+  guint32 i, index_skip;
+  GstSegment segment;
+  GstClockTime dur;
+
+  if (mux->streamable)
+    return GST_FLOW_OK;
+
+  /* seek back to the preallocated index space */
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  segment.start = segment.time = 13 + 29;
+  event = gst_event_new_segment (&segment);
+  if (!gst_pad_push_event (mux->srcpad, event)) {
+    GST_WARNING_OBJECT (mux, "Seek to rewrite header failed");
+    return GST_FLOW_OK;
+  }
+
+  /* determine duration now based on our own timestamping,
+   * so that it is likely many times better and consistent
+   * than whatever obtained by some query */
+  dur = gst_flv_mux_determine_duration (mux);
+  if (dur != GST_CLOCK_TIME_NONE)
+    mux->duration = dur;
+
+  /* rewrite the duration tag */
+  d = gst_guint64_to_gdouble (mux->duration);
+  d /= (gdouble) GST_SECOND;
+
+  GST_DEBUG_OBJECT (mux, "determined the final duration to be %f", d);
+
+  rewrite = gst_flv_mux_create_number_script_value ("duration", d);
+
+  /* rewrite the filesize tag */
+  d = gst_guint64_to_gdouble (mux->byte_count);
+
+  GST_DEBUG_OBJECT (mux, "putting total filesize %f in the metadata", d);
+
+  tmp = gst_flv_mux_create_number_script_value ("filesize", d);
+  rewrite = gst_buffer_append (rewrite, tmp);
+
+  if (!mux->index) {
+    /* no index, so push buffer and return */
+    return gst_flv_mux_push (mux, rewrite);
+  }
+
+  /* rewrite the index */
+  mux->index = g_list_reverse (mux->index);
+  index_len = g_list_length (mux->index);
+
+  /* We write at most MAX_INDEX_ENTRIES elements */
+  if (index_len > MAX_INDEX_ENTRIES) {
+    index_skip = 1 + index_len / MAX_INDEX_ENTRIES;
+    index_len = (index_len + index_skip - 1) / index_skip;
+  } else {
+    index_skip = 1;
+  }
+
+  GST_DEBUG_OBJECT (mux, "Index length is %d", index_len);
+  /* see size calculation in gst_flv_mux_preallocate_index */
+  allocate_size = 11 + 8 + 22 + 10 + index_len * 18;
+  GST_DEBUG_OBJECT (mux, "Allocating %d bytes for index", allocate_size);
+  _gst_buffer_new_and_alloc (allocate_size, &index, &data);
+
+  GST_WRITE_UINT16_BE (data, 9);        /* the 'keyframes' key */
+  memcpy (data + 2, "keyframes", 9);
+  GST_WRITE_UINT8 (data + 11, 8);       /* nested ECMA array */
+  GST_WRITE_UINT32_BE (data + 12, 2);   /* two elements */
+  GST_WRITE_UINT16_BE (data + 16, 5);   /* first string key: 'times' */
+  memcpy (data + 18, "times", 5);
+  GST_WRITE_UINT8 (data + 23, 10);      /* strict array */
+  GST_WRITE_UINT32_BE (data + 24, index_len);
+  data += 28;
+
+  /* the keyframes' times */
+  for (i = 0, l = mux->index; l; l = l->next, i++) {
+    GstFlvMuxIndexEntry *entry = l->data;
+
+    if (i % index_skip != 0)
+      continue;
+    GST_WRITE_UINT8 (data, 0);  /* numeric (aka double) */
+    GST_WRITE_DOUBLE_BE (data + 1, entry->time);
+    data += 9;
+  }
+
+  GST_WRITE_UINT16_BE (data, 13);       /* second string key: 'filepositions' */
+  memcpy (data + 2, "filepositions", 13);
+  GST_WRITE_UINT8 (data + 15, 10);      /* strict array */
+  GST_WRITE_UINT32_BE (data + 16, index_len);
+  data += 20;
+
+  /* the keyframes' file positions */
+  for (i = 0, l = mux->index; l; l = l->next, i++) {
+    GstFlvMuxIndexEntry *entry = l->data;
+
+    if (i % index_skip != 0)
+      continue;
+    GST_WRITE_UINT8 (data, 0);
+    GST_WRITE_DOUBLE_BE (data + 1, entry->position);
+    data += 9;
+  }
+
+  GST_WRITE_UINT24_BE (data, 9);        /* finish the ECMA array */
+
+  /* If there is space left in the prefilled area, reinsert the filler.
+     There is at least 18  bytes free, so it will always fit. */
+  if (index_len < MAX_INDEX_ENTRIES) {
+    GstBuffer *tmp;
+    guint8 *data;
+    guint32 remaining_filler_size;
+
+    _gst_buffer_new_and_alloc (14, &tmp, &data);
+    GST_WRITE_UINT16_BE (data, 9);
+    memcpy (data + 2, "gstfiller", 9);
+    GST_WRITE_UINT8 (data + 11, 2);     /* string */
+
+    /* There is 18 bytes per remaining index entry minus what is used for
+     * the'gstfiller' key. The rest is already filled with spaces, so just need
+     * to update length. */
+    remaining_filler_size = (MAX_INDEX_ENTRIES - index_len) * 18 - 14;
+    GST_DEBUG_OBJECT (mux, "Remaining filler size is %d bytes",
+        remaining_filler_size);
+    GST_WRITE_UINT16_BE (data + 12, remaining_filler_size);
+    index = gst_buffer_append (index, tmp);
+  }
+
+  rewrite = gst_buffer_append (rewrite, index);
+
+  return gst_flv_mux_push (mux, rewrite);
+}
+
+static GstFlvMuxPad *
+gst_flv_mux_find_best_pad (GstAggregator * aggregator, GstClockTime * ts)
+{
+  GstAggregatorPad *apad;
+  GstFlvMuxPad *pad, *best = NULL;
+  GList *l;
+  GstBuffer *buffer;
+  GstClockTime best_ts = GST_CLOCK_TIME_NONE;
+
+  for (l = GST_ELEMENT_CAST (aggregator)->sinkpads; l; l = l->next) {
+    apad = GST_AGGREGATOR_PAD (l->data);
+    pad = GST_FLV_MUX_PAD (l->data);
+    buffer = gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (pad));
+    if (!buffer)
+      continue;
+    if (best_ts == GST_CLOCK_TIME_NONE) {
+      best = pad;
+      best_ts = gst_flv_mux_segment_to_running_time (&apad->segment,
+          GST_BUFFER_DTS_OR_PTS (buffer));
+    } else if (GST_BUFFER_DTS_OR_PTS (buffer) != GST_CLOCK_TIME_NONE) {
+      gint64 t = gst_flv_mux_segment_to_running_time (&apad->segment,
+          GST_BUFFER_DTS_OR_PTS (buffer));
+      if (t < best_ts) {
+        best = pad;
+        best_ts = t;
+      }
+    }
+  }
+  GST_DEBUG_OBJECT (aggregator,
+      "Best pad found with %" GST_TIME_FORMAT ": %" GST_PTR_FORMAT,
+      GST_TIME_ARGS (best_ts), best);
+  if (ts)
+    *ts = best_ts;
+  return best;
+}
+
+static GstFlowReturn
+gst_flv_mux_aggregate (GstAggregator * aggregator, gboolean timeout)
+{
+  GstFlvMux *mux = GST_FLV_MUX (aggregator);
+  GstFlvMuxPad *best;
+  gint64 best_time = GST_CLOCK_STIME_NONE;
+  GstFlowReturn ret;
+  GstClockTime ts;
+  GstBuffer *buffer = NULL;
+
+  if (mux->state == GST_FLV_MUX_STATE_HEADER) {
+    if (GST_ELEMENT_CAST (mux)->sinkpads == NULL) {
+      GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
+          ("No input streams configured"));
+      return GST_FLOW_ERROR;
+    }
+
+    ret = gst_flv_mux_write_header (mux);
+    if (ret != GST_FLOW_OK)
+      return ret;
+    mux->state = GST_FLV_MUX_STATE_DATA;
+
+    best = gst_flv_mux_find_best_pad (aggregator, &ts);
+    if (best && GST_CLOCK_STIME_IS_VALID (ts))
+      mux->first_timestamp = ts;
+    else
+      mux->first_timestamp = 0;
+  } else {
+    best = gst_flv_mux_find_best_pad (aggregator, &ts);
+  }
+
+  if (mux->new_tags) {
+    GstBuffer *buf = gst_flv_mux_create_metadata (mux, FALSE);
+    if (buf)
+      gst_flv_mux_push (mux, buf);
+    mux->new_tags = FALSE;
+  }
+
+  if (best) {
+    buffer = gst_aggregator_pad_pop_buffer (GST_AGGREGATOR_PAD (best));
+    g_assert (buffer);
+    best->dts =
+        gst_flv_mux_segment_to_running_time (&GST_AGGREGATOR_PAD
+        (best)->segment, GST_BUFFER_DTS_OR_PTS (buffer));
+
+    if (GST_CLOCK_STIME_IS_VALID (best->dts))
+      best_time = best->dts - mux->first_timestamp;
+
+    if (GST_BUFFER_PTS_IS_VALID (buffer))
+      best->pts =
+          gst_flv_mux_segment_to_running_time (&GST_AGGREGATOR_PAD
+          (best)->segment, GST_BUFFER_PTS (buffer));
+    else
+      best->pts = best->dts;
+
+    GST_LOG_OBJECT (best, "got buffer PTS %" GST_TIME_FORMAT " DTS %"
+        GST_STIME_FORMAT, GST_TIME_ARGS (best->pts),
+        GST_STIME_ARGS (best->dts));
+  } else {
+    best_time = GST_CLOCK_STIME_NONE;
+  }
+
+  /* The FLV timestamp is an int32 field. For non-live streams error out if a
+     bigger timestamp is seen, for live the timestamp will get wrapped in
+     gst_flv_mux_buffer_to_tag */
+  if (!mux->streamable && (GST_CLOCK_STIME_IS_VALID (best_time))
+      && best_time / GST_MSECOND > G_MAXINT32) {
+    GST_WARNING_OBJECT (mux, "Timestamp larger than FLV supports - EOS");
+    if (buffer) {
+      gst_buffer_unref (buffer);
+      buffer = NULL;
+    }
+    best = NULL;
+  }
+
+  if (best) {
+    return gst_flv_mux_write_buffer (mux, best, buffer);
+  } else {
+    if (gst_flv_mux_are_all_pads_eos (mux)) {
+      gst_flv_mux_write_eos (mux);
+      gst_flv_mux_rewrite_header (mux);
+      gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
+    }
+    return GST_FLOW_OK;
+  }
+}
+
+static void
+gst_flv_mux_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstFlvMux *mux = GST_FLV_MUX (object);
+
+  switch (prop_id) {
+    case PROP_STREAMABLE:
+      g_value_set_boolean (value, mux->streamable);
+      break;
+    case PROP_METADATACREATOR:
+      g_value_set_string (value, mux->metadatacreator);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_flv_mux_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstFlvMux *mux = GST_FLV_MUX (object);
+
+  switch (prop_id) {
+    case PROP_STREAMABLE:
+      mux->streamable = g_value_get_boolean (value);
+      if (mux->streamable)
+        gst_tag_setter_set_tag_merge_mode (GST_TAG_SETTER (mux),
+            GST_TAG_MERGE_REPLACE);
+      else
+        gst_tag_setter_set_tag_merge_mode (GST_TAG_SETTER (mux),
+            GST_TAG_MERGE_KEEP);
+      break;
+    case PROP_METADATACREATOR:
+      g_free (mux->metadatacreator);
+      if (!g_value_get_string (value)) {
+        GST_WARNING_OBJECT (mux, "metadatacreator property can not be NULL");
+        mux->metadatacreator = g_strdup (DEFAULT_METADATACREATOR);
+      } else {
+        mux->metadatacreator = g_value_dup_string (value);
+      }
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstClockTime
+gst_flv_mux_get_next_time_for_segment (GstAggregator * aggregator,
+    const GstSegment * segment)
+{
+  GstClockTime next_time;
+
+  GST_OBJECT_LOCK (aggregator);
+  if (segment->position == -1 || segment->position < segment->start)
+    next_time = segment->start;
+  else
+    next_time = segment->position;
+
+  if (segment->stop != -1 && next_time > segment->stop)
+    next_time = segment->stop;
+
+  next_time = gst_segment_to_running_time (segment, GST_FORMAT_TIME, next_time);
+  GST_OBJECT_UNLOCK (aggregator);
+
+  GST_DEBUG_OBJECT (aggregator, "next_time: %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (next_time));
+  return next_time;
+}
+
+static GstClockTime
+gst_flv_mux_get_next_time (GstAggregator * aggregator)
+{
+  return gst_flv_mux_get_next_time_for_segment (aggregator,
+      &aggregator->segment);
+}
diff --git a/gst/flv/gstflvmux.h b/gst/flv/gstflvmux.h
new file mode 100644
index 0000000..4db5093
--- /dev/null
+++ b/gst/flv/gstflvmux.h
@@ -0,0 +1,110 @@
+/* GStreamer
+ *
+ * Copyright (c) 2008,2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ * Copyright (c) 2008-2017 Collabora Ltd
+ *  @author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *  @author: Vincent Penquerc'h <vincent.penquerch@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_FLV_MUX_H__
+#define __GST_FLV_MUX_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstaggregator.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_FLV_MUX_PAD (gst_flv_mux_pad_get_type())
+#define GST_FLV_MUX_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FLV_MUX_PAD, GstFlvMuxPad))
+#define GST_FLV_MUX_PAD_CAST(obj) ((GstFlvMuxPad *)(obj))
+#define GST_FLV_MUX_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FLV_MUX_PAD, GstFlvMuxPad))
+#define GST_IS_FLV_MUX_PAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLV_MUX_PAD))
+#define GST_IS_FLV_MUX_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLV_MUX_PAD))
+
+typedef struct _GstFlvMuxPad GstFlvMuxPad;
+typedef struct _GstFlvMuxPadClass GstFlvMuxPadClass;
+
+#define GST_TYPE_FLV_MUX \
+  (gst_flv_mux_get_type ())
+#define GST_FLV_MUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_FLV_MUX, GstFlvMux))
+#define GST_FLV_MUX_CAST(obj) ((GstFlvMux *)obj)
+#define GST_FLV_MUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_FLV_MUX, GstFlvMuxClass))
+#define GST_IS_FLV_MUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_FLV_MUX))
+#define GST_IS_FLV_MUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_FLV_MUX))
+
+struct _GstFlvMuxPad
+{
+  GstAggregatorPad aggregator_pad;
+
+  guint codec;
+  guint rate;
+  guint width;
+  guint channels;
+  GstBuffer *codec_data;
+
+  guint bitrate;
+
+  GstClockTime last_timestamp;
+  gint64 pts;
+  gint64 dts;
+};
+
+typedef struct _GstFlvMuxPadClass {
+  GstAggregatorPadClass parent;
+} GstFlvMuxPadClass;
+
+typedef enum
+{
+  GST_FLV_MUX_STATE_HEADER,
+  GST_FLV_MUX_STATE_DATA
+} GstFlvMuxState;
+
+typedef struct _GstFlvMux {
+  GstAggregator   aggregator;
+
+  GstPad         *srcpad;
+
+  /* <private> */
+  GstFlvMuxState state;
+  GstFlvMuxPad *audio_pad;
+  GstFlvMuxPad *video_pad;
+  gboolean streamable;
+  gchar *metadatacreator;
+
+  GstTagList *tags;
+  gboolean new_tags;
+  GList *index;
+  guint64 byte_count;
+  guint64 duration;
+  gint64 first_timestamp;
+} GstFlvMux;
+
+typedef struct _GstFlvMuxClass {
+  GstAggregatorClass parent;
+} GstFlvMuxClass;
+
+GType    gst_flv_mux_pad_get_type(void);
+GType    gst_flv_mux_get_type    (void);
+
+G_END_DECLS
+
+#endif /* __GST_FLV_MUX_H__ */
diff --git a/gst/flv/gstindex.c b/gst/flv/gstindex.c
new file mode 100644
index 0000000..26d7fa3
--- /dev/null
+++ b/gst/flv/gstindex.c
@@ -0,0 +1,1019 @@
+/* GStreamer
+ * Copyright (C) 2001 RidgeRun (http://www.ridgerun.com/)
+ * Written by Erik Walthinsen <omega@ridgerun.com>
+ *
+ * gstindex.c: Index for mappings and other data
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:gstindex
+ * @short_description: Generate indexes on objects
+ * @see_also: #GstIndexFactory
+ *
+ * GstIndex is used to generate a stream index of one or more elements
+ * in a pipeline.
+ *
+ * Elements will overload the set_index and get_index virtual methods in
+ * #GstElement. When streaming data, the element will add index entries if it
+ * has an index set.
+ *
+ * Each element that adds to the index will do that using a writer_id. The
+ * writer_id is obtained from gst_index_get_writer_id().
+ *
+ * The application that wants to index the stream will create a new index object
+ * using gst_index_new() or gst_index_factory_make(). The index is assigned to a
+ * specific element, a bin or the whole pipeline. This will cause indexable
+ * elements to add entires to the index while playing.
+ */
+
+/* FIXME: complete gobject annotations */
+/* FIXME-0.11: cleanup API
+ * - no one seems to use GstIndexGroup, GstIndexCertainty
+ *
+ * - the API for application to use the index is mostly missing
+ *   - apps need to get a list of writers
+ *   - apps need to be able to iterate over each writers index entry collection
+ * - gst_index_get_assoc_entry() should pass ownership
+ *   - the GstIndexEntry structure is large and contains repetitive information
+ *   - we want to allow Indexers to implement a saner storage and create
+ *     GstIndexEntries on demand (the app has to free them), might even make
+ *     sense to ask the app to provide a ptr and fill it.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+/* Index signals and args */
+enum
+{
+  ENTRY_ADDED,
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_RESOLVER
+      /* FILL ME */
+};
+
+#if 0
+GST_DEBUG_CATEGORY_STATIC (index_debug);
+#define GST_CAT_DEFAULT index_debug
+#endif
+
+static void gst_index_finalize (GObject * object);
+
+static void gst_index_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_index_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstIndexGroup *gst_index_group_new (guint groupnum);
+static void gst_index_group_free (GstIndexGroup * group);
+
+static gboolean gst_index_path_resolver (GstIndex * index, GstObject * writer,
+    gchar ** writer_string, gpointer data);
+static gboolean gst_index_gtype_resolver (GstIndex * index, GstObject * writer,
+    gchar ** writer_string, gpointer data);
+static void gst_index_add_entry (GstIndex * index, GstIndexEntry * entry);
+
+static guint gst_index_signals[LAST_SIGNAL] = { 0 };
+
+typedef struct
+{
+  GstIndexResolverMethod method;
+  GstIndexResolver resolver;
+  gpointer user_data;
+}
+ResolverEntry;
+
+static const ResolverEntry resolvers[] = {
+  {GST_INDEX_RESOLVER_CUSTOM, NULL, NULL},
+  {GST_INDEX_RESOLVER_GTYPE, gst_index_gtype_resolver, NULL},
+  {GST_INDEX_RESOLVER_PATH, gst_index_path_resolver, NULL},
+};
+
+#define GST_TYPE_INDEX_RESOLVER (gst_index_resolver_get_type())
+static GType
+gst_index_resolver_get_type (void)
+{
+  static GType index_resolver_type = 0;
+  static const GEnumValue index_resolver[] = {
+    {GST_INDEX_RESOLVER_CUSTOM, "GST_INDEX_RESOLVER_CUSTOM", "custom"},
+    {GST_INDEX_RESOLVER_GTYPE, "GST_INDEX_RESOLVER_GTYPE", "gtype"},
+    {GST_INDEX_RESOLVER_PATH, "GST_INDEX_RESOLVER_PATH", "path"},
+    {0, NULL, NULL},
+  };
+
+  if (!index_resolver_type) {
+    index_resolver_type =
+        g_enum_register_static ("GstFlvDemuxIndexResolver", index_resolver);
+  }
+  return index_resolver_type;
+}
+
+GType
+gst_index_entry_get_type (void)
+{
+  static GType index_entry_type = 0;
+
+  if (!index_entry_type) {
+    index_entry_type = g_boxed_type_register_static ("GstFlvDemuxIndexEntry",
+        (GBoxedCopyFunc) gst_index_entry_copy,
+        (GBoxedFreeFunc) gst_index_entry_free);
+  }
+  return index_entry_type;
+}
+
+#if 0
+#define _do_init \
+{ \
+  GST_DEBUG_CATEGORY_INIT (index_debug, "GST_INDEX", GST_DEBUG_BOLD, \
+      "Generic indexing support"); \
+}
+#endif
+
+typedef GstIndex GstFlvDemuxIndex;
+typedef GstIndexClass GstFlvDemuxIndexClass;
+//typedef GstIndexEntry GstFlvDemuxIndexEntry;
+G_DEFINE_TYPE (GstFlvDemuxIndex, gst_index, GST_TYPE_OBJECT);
+
+static void
+gst_index_class_init (GstIndexClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  /**
+   * GstIndex::entry-added
+   * @gstindex: the object which received the signal.
+   * @arg1: The entry added to the index.
+   *
+   * Is emitted when a new entry is added to the index.
+   */
+  gst_index_signals[ENTRY_ADDED] =
+      g_signal_new ("entry-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstIndexClass, entry_added), NULL, NULL,
+      NULL, G_TYPE_NONE, 1, GST_TYPE_INDEX_ENTRY);
+
+  gobject_class->set_property = gst_index_set_property;
+  gobject_class->get_property = gst_index_get_property;
+  gobject_class->finalize = gst_index_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_RESOLVER,
+      g_param_spec_enum ("resolver", "Resolver",
+          "Select a predefined object to string mapper",
+          GST_TYPE_INDEX_RESOLVER, GST_INDEX_RESOLVER_PATH,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_index_init (GstIndex * index)
+{
+  index->curgroup = gst_index_group_new (0);
+  index->maxgroup = 0;
+  index->groups = g_list_prepend (NULL, index->curgroup);
+
+  index->writers = g_hash_table_new (NULL, NULL);
+  index->last_id = 0;
+
+  index->method = GST_INDEX_RESOLVER_PATH;
+  index->resolver = resolvers[index->method].resolver;
+  index->resolver_user_data = resolvers[index->method].user_data;
+
+  GST_OBJECT_FLAG_SET (index, GST_INDEX_WRITABLE);
+  GST_OBJECT_FLAG_SET (index, GST_INDEX_READABLE);
+
+  GST_DEBUG ("created new index");
+}
+
+static void
+gst_index_free_writer (gpointer key, gpointer value, gpointer user_data)
+{
+  GstIndexEntry *entry = (GstIndexEntry *) value;
+
+  if (entry) {
+    gst_index_entry_free (entry);
+  }
+}
+
+static void
+gst_index_finalize (GObject * object)
+{
+  GstIndex *index = GST_INDEX (object);
+
+  if (index->groups) {
+    g_list_foreach (index->groups, (GFunc) gst_index_group_free, NULL);
+    g_list_free (index->groups);
+    index->groups = NULL;
+  }
+
+  if (index->writers) {
+    g_hash_table_foreach (index->writers, gst_index_free_writer, NULL);
+    g_hash_table_destroy (index->writers);
+    index->writers = NULL;
+  }
+
+  if (index->filter_user_data && index->filter_user_data_destroy)
+    index->filter_user_data_destroy (index->filter_user_data);
+
+  if (index->resolver_user_data && index->resolver_user_data_destroy)
+    index->resolver_user_data_destroy (index->resolver_user_data);
+
+  G_OBJECT_CLASS (gst_index_parent_class)->finalize (object);
+}
+
+static void
+gst_index_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstIndex *index;
+
+  index = GST_INDEX (object);
+
+  switch (prop_id) {
+    case PROP_RESOLVER:
+      index->method = (GstIndexResolverMethod) g_value_get_enum (value);
+      index->resolver = resolvers[index->method].resolver;
+      index->resolver_user_data = resolvers[index->method].user_data;
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_index_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstIndex *index;
+
+  index = GST_INDEX (object);
+
+  switch (prop_id) {
+    case PROP_RESOLVER:
+      g_value_set_enum (value, index->method);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstIndexGroup *
+gst_index_group_new (guint groupnum)
+{
+  GstIndexGroup *indexgroup = g_slice_new (GstIndexGroup);
+
+  indexgroup->groupnum = groupnum;
+  indexgroup->entries = NULL;
+  indexgroup->certainty = GST_INDEX_UNKNOWN;
+  indexgroup->peergroup = -1;
+
+  GST_DEBUG ("created new index group %d", groupnum);
+
+  return indexgroup;
+}
+
+static void
+gst_index_group_free (GstIndexGroup * group)
+{
+  g_slice_free (GstIndexGroup, group);
+}
+
+/* do not resurrect this, add a derived dummy index class instead */
+#if 0
+/**
+ * gst_index_new:
+ *
+ * Create a new dummy index object. Use gst_element_set_index() to assign that
+ * to an element or pipeline. This index is not storing anything, but will
+ * still emit e.g. the #GstIndex::entry-added signal.
+ *
+ * Returns: (transfer full): a new index object
+ */
+GstIndex *
+gst_index_new (void)
+{
+  GstIndex *index;
+
+  index = g_object_newv (gst_index_get_type (), 0, NULL);
+
+  return index;
+}
+#endif
+
+/**
+ * gst_index_commit:
+ * @index: the index to commit
+ * @id: the writer that commited the index
+ *
+ * Tell the index that the writer with the given id is done
+ * with this index and is not going to write any more entries
+ * to it.
+ */
+void
+gst_index_commit (GstIndex * index, gint id)
+{
+  GstIndexClass *iclass;
+
+  iclass = GST_INDEX_GET_CLASS (index);
+
+  if (iclass->commit)
+    iclass->commit (index, id);
+}
+
+#if 0
+/**
+ * gst_index_get_group:
+ * @index: the index to get the current group from
+ *
+ * Get the id of the current group.
+ *
+ * Returns: the id of the current group.
+ */
+gint
+gst_index_get_group (GstIndex * index)
+{
+  return index->curgroup->groupnum;
+}
+
+/**
+ * gst_index_new_group:
+ * @index: the index to create the new group in
+ *
+ * Create a new group for the given index. It will be
+ * set as the current group.
+ *
+ * Returns: the id of the newly created group.
+ */
+gint
+gst_index_new_group (GstIndex * index)
+{
+  index->curgroup = gst_index_group_new (++index->maxgroup);
+  index->groups = g_list_append (index->groups, index->curgroup);
+  GST_DEBUG ("created new group %d in index", index->maxgroup);
+  return index->maxgroup;
+}
+
+/**
+ * gst_index_set_group:
+ * @index: the index to set the new group in
+ * @groupnum: the groupnumber to set
+ *
+ * Set the current groupnumber to the given argument.
+ *
+ * Returns: TRUE if the operation succeeded, FALSE if the group
+ * did not exist.
+ */
+gboolean
+gst_index_set_group (GstIndex * index, gint groupnum)
+{
+  GList *list;
+  GstIndexGroup *indexgroup;
+
+  /* first check for null change */
+  if (groupnum == index->curgroup->groupnum)
+    return TRUE;
+
+  /* else search for the proper group */
+  list = index->groups;
+  while (list) {
+    indexgroup = (GstIndexGroup *) (list->data);
+    list = g_list_next (list);
+    if (indexgroup->groupnum == groupnum) {
+      index->curgroup = indexgroup;
+      GST_DEBUG ("switched to index group %d", indexgroup->groupnum);
+      return TRUE;
+    }
+  }
+
+  /* couldn't find the group in question */
+  GST_DEBUG ("couldn't find index group %d", groupnum);
+  return FALSE;
+}
+#endif
+
+#if 0
+/**
+ * gst_index_set_certainty:
+ * @index: the index to set the certainty on
+ * @certainty: the certainty to set
+ *
+ * Set the certainty of the given index.
+ */
+void
+gst_index_set_certainty (GstIndex * index, GstIndexCertainty certainty)
+{
+  index->curgroup->certainty = certainty;
+}
+
+/**
+ * gst_index_get_certainty:
+ * @index: the index to get the certainty of
+ *
+ * Get the certainty of the given index.
+ *
+ * Returns: the certainty of the index.
+ */
+GstIndexCertainty
+gst_index_get_certainty (GstIndex * index)
+{
+  return index->curgroup->certainty;
+}
+#endif
+
+#if 0
+/**
+ * gst_index_set_filter:
+ * @index: the index to register the filter on
+ * @filter: the filter to register
+ * @user_data: data passed to the filter function
+ *
+ * Lets the app register a custom filter function so that
+ * it can select what entries should be stored in the index.
+ */
+void
+gst_index_set_filter (GstIndex * index,
+    GstIndexFilter filter, gpointer user_data)
+{
+  g_return_if_fail (GST_IS_INDEX (index));
+
+  gst_index_set_filter_full (index, filter, user_data, NULL);
+}
+
+/**
+ * gst_index_set_filter_full:
+ * @index: the index to register the filter on
+ * @filter: the filter to register
+ * @user_data: data passed to the filter function
+ * @user_data_destroy: function to call when @user_data is unset
+ *
+ * Lets the app register a custom filter function so that
+ * it can select what entries should be stored in the index.
+ */
+void
+gst_index_set_filter_full (GstIndex * index,
+    GstIndexFilter filter, gpointer user_data, GDestroyNotify user_data_destroy)
+{
+  g_return_if_fail (GST_IS_INDEX (index));
+
+  if (index->filter_user_data && index->filter_user_data_destroy)
+    index->filter_user_data_destroy (index->filter_user_data);
+
+  index->filter = filter;
+  index->filter_user_data = user_data;
+  index->filter_user_data_destroy = user_data_destroy;
+}
+
+/**
+ * gst_index_set_resolver:
+ * @index: the index to register the resolver on
+ * @resolver: the resolver to register
+ * @user_data: data passed to the resolver function
+ *
+ * Lets the app register a custom function to map index
+ * ids to writer descriptions.
+ */
+void
+gst_index_set_resolver (GstIndex * index,
+    GstIndexResolver resolver, gpointer user_data)
+{
+  gst_index_set_resolver_full (index, resolver, user_data, NULL);
+}
+
+/**
+ * gst_index_set_resolver_full:
+ * @index: the index to register the resolver on
+ * @resolver: the resolver to register
+ * @user_data: data passed to the resolver function
+ * @user_data_destroy: destroy function for @user_data
+ *
+ * Lets the app register a custom function to map index
+ * ids to writer descriptions.
+ *
+ * Since: 0.10.18
+ */
+void
+gst_index_set_resolver_full (GstIndex * index, GstIndexResolver resolver,
+    gpointer user_data, GDestroyNotify user_data_destroy)
+{
+  g_return_if_fail (GST_IS_INDEX (index));
+
+  if (index->resolver_user_data && index->resolver_user_data_destroy)
+    index->resolver_user_data_destroy (index->resolver_user_data);
+
+  index->resolver = resolver;
+  index->resolver_user_data = user_data;
+  index->resolver_user_data_destroy = user_data_destroy;
+  index->method = GST_INDEX_RESOLVER_CUSTOM;
+}
+#endif
+
+/**
+ * gst_index_entry_copy:
+ * @entry: the entry to copy
+ *
+ * Copies an entry and returns the result.
+ *
+ * Free-function: gst_index_entry_free
+ *
+ * Returns: (transfer full): a newly allocated #GstIndexEntry.
+ */
+GstIndexEntry *
+gst_index_entry_copy (GstIndexEntry * entry)
+{
+  GstIndexEntry *new_entry = g_slice_new (GstIndexEntry);
+
+  memcpy (new_entry, entry, sizeof (GstIndexEntry));
+  return new_entry;
+}
+
+/**
+ * gst_index_entry_free:
+ * @entry: (transfer full): the entry to free
+ *
+ * Free the memory used by the given entry.
+ */
+void
+gst_index_entry_free (GstIndexEntry * entry)
+{
+  switch (entry->type) {
+    case GST_INDEX_ENTRY_ID:
+      if (entry->data.id.description) {
+        g_free (entry->data.id.description);
+        entry->data.id.description = NULL;
+      }
+      break;
+    case GST_INDEX_ENTRY_ASSOCIATION:
+      if (entry->data.assoc.assocs) {
+        g_free (entry->data.assoc.assocs);
+        entry->data.assoc.assocs = NULL;
+      }
+      break;
+    case GST_INDEX_ENTRY_OBJECT:
+      break;
+    case GST_INDEX_ENTRY_FORMAT:
+      break;
+  }
+
+  g_slice_free (GstIndexEntry, entry);
+}
+
+#if 0
+/**
+ * gst_index_add_format:
+ * @index: the index to add the entry to
+ * @id: the id of the index writer
+ * @format: the format to add to the index
+ *
+ * Adds a format entry into the index. This function is
+ * used to map dynamic GstFormat ids to their original
+ * format key.
+ *
+ * Free-function: gst_index_entry_free
+ *
+ * Returns: (transfer full): a pointer to the newly added entry in the index.
+ */
+GstIndexEntry *
+gst_index_add_format (GstIndex * index, gint id, GstFormat format)
+{
+  GstIndexEntry *entry;
+  const GstFormatDefinition *def;
+
+  g_return_val_if_fail (GST_IS_INDEX (index), NULL);
+  g_return_val_if_fail (format != 0, NULL);
+
+  if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
+    return NULL;
+
+  entry = g_slice_new (GstIndexEntry);
+  entry->type = GST_INDEX_ENTRY_FORMAT;
+  entry->id = id;
+  entry->data.format.format = format;
+
+  def = gst_format_get_details (format);
+  entry->data.format.key = def->nick;
+
+  gst_index_add_entry (index, entry);
+
+  return entry;
+}
+#endif
+
+/**
+ * gst_index_add_id:
+ * @index: the index to add the entry to
+ * @id: the id of the index writer
+ * @description: the description of the index writer
+ *
+ * Add an id entry into the index.
+ *
+ * Returns: a pointer to the newly added entry in the index.
+ */
+GstIndexEntry *
+gst_index_add_id (GstIndex * index, gint id, gchar * description)
+{
+  GstIndexEntry *entry;
+
+  g_return_val_if_fail (GST_IS_INDEX (index), NULL);
+  g_return_val_if_fail (description != NULL, NULL);
+
+  if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
+    return NULL;
+
+  entry = g_slice_new (GstIndexEntry);
+  entry->type = GST_INDEX_ENTRY_ID;
+  entry->id = id;
+  entry->data.id.description = description;
+
+  gst_index_add_entry (index, entry);
+
+  return entry;
+}
+
+static gboolean
+gst_index_path_resolver (GstIndex * index, GstObject * writer,
+    gchar ** writer_string, gpointer data)
+{
+  *writer_string = gst_object_get_path_string (writer);
+
+  return TRUE;
+}
+
+static gboolean
+gst_index_gtype_resolver (GstIndex * index, GstObject * writer,
+    gchar ** writer_string, gpointer data)
+{
+  g_return_val_if_fail (writer != NULL, FALSE);
+
+  if (GST_IS_PAD (writer)) {
+    GstObject *element = gst_object_get_parent (GST_OBJECT (writer));
+    gchar *name;
+
+    name = gst_object_get_name (writer);
+    if (element) {
+      *writer_string = g_strdup_printf ("%s.%s",
+          G_OBJECT_TYPE_NAME (element), name);
+      gst_object_unref (element);
+    } else {
+      *writer_string = name;
+      name = NULL;
+    }
+
+    g_free (name);
+
+  } else {
+    *writer_string = g_strdup (G_OBJECT_TYPE_NAME (writer));
+  }
+
+  return TRUE;
+}
+
+/**
+ * gst_index_get_writer_id:
+ * @index: the index to get a unique write id for
+ * @writer: the GstObject to allocate an id for
+ * @id: a pointer to a gint to hold the id
+ *
+ * Before entries can be added to the index, a writer
+ * should obtain a unique id. The methods to add new entries
+ * to the index require this id as an argument.
+ *
+ * The application can implement a custom function to map the writer object
+ * to a string. That string will be used to register or look up an id
+ * in the index.
+ *
+ * <note>
+ * The caller must not hold @writer's #GST_OBJECT_LOCK, as the default
+ * resolver may call functions that take the object lock as well, and
+ * the lock is not recursive.
+ * </note>
+ *
+ * Returns: TRUE if the writer would be mapped to an id.
+ */
+gboolean
+gst_index_get_writer_id (GstIndex * index, GstObject * writer, gint * id)
+{
+  gchar *writer_string = NULL;
+  GstIndexEntry *entry;
+  GstIndexClass *iclass;
+  gboolean success = FALSE;
+
+  g_return_val_if_fail (GST_IS_INDEX (index), FALSE);
+  g_return_val_if_fail (GST_IS_OBJECT (writer), FALSE);
+  g_return_val_if_fail (id, FALSE);
+
+  *id = -1;
+
+  /* first try to get a previously cached id */
+  entry = g_hash_table_lookup (index->writers, writer);
+  if (entry == NULL) {
+
+    iclass = GST_INDEX_GET_CLASS (index);
+
+    /* let the app make a string */
+    if (index->resolver) {
+      gboolean res;
+
+      res =
+          index->resolver (index, writer, &writer_string,
+          index->resolver_user_data);
+      if (!res)
+        return FALSE;
+    } else {
+      g_warning ("no resolver found");
+      return FALSE;
+    }
+
+    /* if the index has a resolver, make it map this string to an id */
+    if (iclass->get_writer_id) {
+      success = iclass->get_writer_id (index, id, writer_string);
+    }
+    /* if the index could not resolve, we allocate one ourselves */
+    if (!success) {
+      *id = ++index->last_id;
+    }
+
+    entry = gst_index_add_id (index, *id, writer_string);
+    if (!entry) {
+      /* index is probably not writable, make an entry anyway
+       * to keep it in our cache */
+      entry = g_slice_new (GstIndexEntry);
+      entry->type = GST_INDEX_ENTRY_ID;
+      entry->id = *id;
+      entry->data.id.description = writer_string;
+    }
+    g_hash_table_insert (index->writers, writer, entry);
+  } else {
+    *id = entry->id;
+  }
+
+  return TRUE;
+}
+
+static void
+gst_index_add_entry (GstIndex * index, GstIndexEntry * entry)
+{
+  GstIndexClass *iclass;
+
+  iclass = GST_INDEX_GET_CLASS (index);
+
+  if (iclass->add_entry) {
+    iclass->add_entry (index, entry);
+  }
+
+  g_signal_emit (index, gst_index_signals[ENTRY_ADDED], 0, entry);
+}
+
+/**
+ * gst_index_add_associationv:
+ * @index: the index to add the entry to
+ * @id: the id of the index writer
+ * @flags: optinal flags for this entry
+ * @n: number of associations
+ * @list: list of associations
+ *
+ * Associate given format/value pairs with each other.
+ *
+ * Returns: a pointer to the newly added entry in the index.
+ */
+GstIndexEntry *
+gst_index_add_associationv (GstIndex * index, gint id,
+    GstIndexAssociationFlags flags, gint n, const GstIndexAssociation * list)
+{
+  GstIndexEntry *entry;
+
+  g_return_val_if_fail (n > 0, NULL);
+  g_return_val_if_fail (list != NULL, NULL);
+  g_return_val_if_fail (GST_IS_INDEX (index), NULL);
+
+  if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
+    return NULL;
+
+  entry = g_slice_new (GstIndexEntry);
+
+  entry->type = GST_INDEX_ENTRY_ASSOCIATION;
+  entry->id = id;
+  entry->data.assoc.flags = flags;
+  entry->data.assoc.assocs = g_memdup (list, sizeof (GstIndexAssociation) * n);
+  entry->data.assoc.nassocs = n;
+
+  gst_index_add_entry (index, entry);
+
+  return entry;
+}
+
+#if 0
+/**
+ * gst_index_add_association:
+ * @index: the index to add the entry to
+ * @id: the id of the index writer
+ * @flags: optinal flags for this entry
+ * @format: the format of the value
+ * @value: the value
+ * @...: other format/value pairs or 0 to end the list
+ *
+ * Associate given format/value pairs with each other.
+ * Be sure to pass gint64 values to this functions varargs,
+ * you might want to use a gint64 cast to be sure.
+ *
+ * Returns: a pointer to the newly added entry in the index.
+ */
+GstIndexEntry *
+gst_index_add_association (GstIndex * index, gint id,
+    GstIndexAssociationFlags flags, GstFormat format, gint64 value, ...)
+{
+  va_list args;
+  GstIndexEntry *entry;
+  GstIndexAssociation *list;
+  gint n_assocs = 0;
+  GstFormat cur_format;
+  GArray *array;
+
+  g_return_val_if_fail (GST_IS_INDEX (index), NULL);
+  g_return_val_if_fail (format != 0, NULL);
+
+  if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
+    return NULL;
+
+  array = g_array_new (FALSE, FALSE, sizeof (GstIndexAssociation));
+
+  {
+    GstIndexAssociation a;
+
+    a.format = format;
+    a.value = value;
+    n_assocs = 1;
+    g_array_append_val (array, a);
+  }
+
+  va_start (args, value);
+
+  while ((cur_format = va_arg (args, GstFormat))) {
+    GstIndexAssociation a;
+
+    a.format = cur_format;
+    a.value = va_arg (args, gint64);
+    n_assocs++;
+    g_array_append_val (array, a);
+  }
+
+  va_end (args);
+
+  list = (GstIndexAssociation *) g_array_free (array, FALSE);
+
+  entry = gst_index_add_associationv (index, id, flags, n_assocs, list);
+  g_free (list);
+
+  return entry;
+}
+
+/**
+ * gst_index_add_object:
+ * @index: the index to add the object to
+ * @id: the id of the index writer
+ * @key: a key for the object
+ * @type: the GType of the object
+ * @object: a pointer to the object to add
+ *
+ * Add the given object to the index with the given key.
+ *
+ * This function is not yet implemented.
+ *
+ * Returns: a pointer to the newly added entry in the index.
+ */
+GstIndexEntry *
+gst_index_add_object (GstIndex * index, gint id, gchar * key,
+    GType type, gpointer object)
+{
+  if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
+    return NULL;
+
+  return NULL;
+}
+#endif
+
+static gint
+gst_index_compare_func (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+  if (a < b)
+    return -1;
+  if (a > b)
+    return 1;
+  return 0;
+}
+
+/**
+ * gst_index_get_assoc_entry:
+ * @index: the index to search
+ * @id: the id of the index writer
+ * @method: The lookup method to use
+ * @flags: Flags for the entry
+ * @format: the format of the value
+ * @value: the value to find
+ *
+ * Finds the given format/value in the index
+ *
+ * Returns: the entry associated with the value or NULL if the
+ *   value was not found.
+ */
+GstIndexEntry *
+gst_index_get_assoc_entry (GstIndex * index, gint id,
+    GstIndexLookupMethod method, GstIndexAssociationFlags flags,
+    GstFormat format, gint64 value)
+{
+  g_return_val_if_fail (GST_IS_INDEX (index), NULL);
+
+  if (id == -1)
+    return NULL;
+
+  return gst_index_get_assoc_entry_full (index, id, method, flags, format,
+      value, gst_index_compare_func, NULL);
+}
+
+/**
+ * gst_index_get_assoc_entry_full:
+ * @index: the index to search
+ * @id: the id of the index writer
+ * @method: The lookup method to use
+ * @flags: Flags for the entry
+ * @format: the format of the value
+ * @value: the value to find
+ * @func: the function used to compare entries
+ * @user_data: user data passed to the compare function
+ *
+ * Finds the given format/value in the index with the given
+ * compare function and user_data.
+ *
+ * Returns: the entry associated with the value or NULL if the
+ *   value was not found.
+ */
+GstIndexEntry *
+gst_index_get_assoc_entry_full (GstIndex * index, gint id,
+    GstIndexLookupMethod method, GstIndexAssociationFlags flags,
+    GstFormat format, gint64 value, GCompareDataFunc func, gpointer user_data)
+{
+  GstIndexClass *iclass;
+
+  g_return_val_if_fail (GST_IS_INDEX (index), NULL);
+
+  if (id == -1)
+    return NULL;
+
+  iclass = GST_INDEX_GET_CLASS (index);
+
+  if (iclass->get_assoc_entry)
+    return iclass->get_assoc_entry (index, id, method, flags, format, value,
+        func, user_data);
+
+  return NULL;
+}
+
+/**
+ * gst_index_entry_assoc_map:
+ * @entry: the index to search
+ * @format: the format of the value the find
+ * @value: a pointer to store the value
+ *
+ * Gets alternative formats associated with the indexentry.
+ *
+ * Returns: TRUE if there was a value associated with the given
+ * format.
+ */
+gboolean
+gst_index_entry_assoc_map (GstIndexEntry * entry,
+    GstFormat format, gint64 * value)
+{
+  gint i;
+
+  g_return_val_if_fail (entry != NULL, FALSE);
+  g_return_val_if_fail (value != NULL, FALSE);
+
+  for (i = 0; i < GST_INDEX_NASSOCS (entry); i++) {
+    if (GST_INDEX_ASSOC_FORMAT (entry, i) == format) {
+      *value = GST_INDEX_ASSOC_VALUE (entry, i);
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
diff --git a/gst/flv/gstindex.h b/gst/flv/gstindex.h
new file mode 100644
index 0000000..0a51f9c
--- /dev/null
+++ b/gst/flv/gstindex.h
@@ -0,0 +1,448 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wim.taymans@chello.be>
+ *
+ * gstindex.h: Header for GstIndex, base class to handle efficient
+ *             storage or caching of seeking information.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_INDEX_H__
+#define __GST_INDEX_H__
+
+#include <gst/gstobject.h>
+#include <gst/gstformat.h>
+#include <gst/gstpluginfeature.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_INDEX                  (gst_index_get_type ())
+#define GST_INDEX(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_INDEX, GstIndex))
+#define GST_IS_INDEX(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_INDEX))
+#define GST_INDEX_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_INDEX, GstIndexClass))
+#define GST_IS_INDEX_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_INDEX))
+#define GST_INDEX_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_INDEX, GstIndexClass))
+
+#define GST_TYPE_INDEX_ENTRY            (gst_index_entry_get_type())
+
+typedef struct _GstIndexEntry GstIndexEntry;
+typedef struct _GstIndexGroup GstIndexGroup;
+typedef struct _GstIndex GstIndex;
+typedef struct _GstIndexClass GstIndexClass;
+
+/**
+ * GstIndexCertainty:
+ * @GST_INDEX_UNKNOWN: accuracy is not known
+ * @GST_INDEX_CERTAIN: accuracy is perfect
+ * @GST_INDEX_FUZZY: accuracy is fuzzy
+ *
+ * The certainty of a group in the index.
+ */
+typedef enum {
+  GST_INDEX_UNKNOWN,
+  GST_INDEX_CERTAIN,
+  GST_INDEX_FUZZY
+} GstIndexCertainty;
+
+/**
+ * GstIndexEntryType:
+ * @GST_INDEX_ENTRY_ID: This entry is an id that maps an index id to its owner object
+ * @GST_INDEX_ENTRY_ASSOCIATION: This entry is an association between formats
+ * @GST_INDEX_ENTRY_OBJECT: An object
+ * @GST_INDEX_ENTRY_FORMAT: A format definition
+ *
+ * The different types of entries in the index.
+ */
+typedef enum {
+  GST_INDEX_ENTRY_ID,
+  GST_INDEX_ENTRY_ASSOCIATION,
+  GST_INDEX_ENTRY_OBJECT,
+  GST_INDEX_ENTRY_FORMAT
+} GstIndexEntryType;
+
+/**
+ * GstIndexLookupMethod:
+ * @GST_INDEX_LOOKUP_EXACT: There has to be an exact indexentry with the given format/value
+ * @GST_INDEX_LOOKUP_BEFORE: The exact entry or the one before it
+ * @GST_INDEX_LOOKUP_AFTER: The exact entry or the one after it
+ *
+ * Specify the method to find an index entry in the index.
+ */
+typedef enum {
+  GST_INDEX_LOOKUP_EXACT,
+  GST_INDEX_LOOKUP_BEFORE,
+  GST_INDEX_LOOKUP_AFTER
+} GstIndexLookupMethod;
+
+/**
+ * GST_INDEX_NASSOCS:
+ * @entry: The entry to query
+ *
+ * Get the number of associations in the entry.
+ */
+#define GST_INDEX_NASSOCS(entry)                ((entry)->data.assoc.nassocs)
+
+/**
+ * GST_INDEX_ASSOC_FLAGS:
+ * @entry: The entry to query
+ *
+ *  Get the flags for this entry.
+ */
+#define GST_INDEX_ASSOC_FLAGS(entry)            ((entry)->data.assoc.flags)
+
+/**
+ * GST_INDEX_ASSOC_FORMAT:
+ * @entry: The entry to query
+ * @i: The format index
+ *
+ * Get the i-th format of the entry.
+ */
+#define GST_INDEX_ASSOC_FORMAT(entry,i)         ((entry)->data.assoc.assocs[(i)].format)
+
+/**
+ * GST_INDEX_ASSOC_VALUE:
+ * @entry: The entry to query
+ * @i: The value index
+ *
+ * Get the i-th value of the entry.
+ */
+#define GST_INDEX_ASSOC_VALUE(entry,i)          ((entry)->data.assoc.assocs[(i)].value)
+
+typedef struct _GstIndexAssociation GstIndexAssociation;
+
+/**
+ * GstIndexAssociation:
+ * @format: the format of the association
+ * @value: the value of the association
+ *
+ * An association in an entry.
+ */
+struct _GstIndexAssociation {
+  GstFormat     format;
+  gint64        value;
+};
+
+/**
+ * GstIndexAssociationFlags:
+ * @GST_INDEX_ASSOCIATION_FLAG_NONE: no extra flags
+ * @GST_INDEX_ASSOCIATION_FLAG_KEY_UNIT: the entry marks a key unit, a key unit is one
+ *  that marks a place where one can randomly seek to.
+ * @GST_INDEX_ASSOCIATION_FLAG_DELTA_UNIT: the entry marks a delta unit, a delta unit
+ *  is one that marks a place where one can relatively seek to.
+ * @GST_INDEX_ASSOCIATION_FLAG_LAST: extra user defined flags should start here.
+ *
+ * Flags for an association entry.
+ */
+typedef enum {
+  GST_INDEX_ASSOCIATION_FLAG_NONE       = 0,
+  GST_INDEX_ASSOCIATION_FLAG_KEY_UNIT   = (1 << 0),
+  GST_INDEX_ASSOCIATION_FLAG_DELTA_UNIT = (1 << 1),
+
+  /* new flags should start here */
+  GST_INDEX_ASSOCIATION_FLAG_LAST     = (1 << 8)
+} GstIndexAssociationFlags;
+
+/**
+ * GST_INDEX_FORMAT_FORMAT:
+ * @entry: The entry to query
+ *
+ * Get the format of the format entry
+ */
+#define GST_INDEX_FORMAT_FORMAT(entry)          ((entry)->data.format.format)
+
+/**
+ * GST_INDEX_FORMAT_KEY:
+ * @entry: The entry to query
+ *
+ * Get the key of the format entry
+ */
+#define GST_INDEX_FORMAT_KEY(entry)             ((entry)->data.format.key)
+
+/**
+ * GST_INDEX_ID_INVALID:
+ *
+ * Constant for an invalid index id
+ */
+#define GST_INDEX_ID_INVALID                    (-1)
+
+/**
+ * GST_INDEX_ID_DESCRIPTION:
+ * @entry: The entry to query
+ *
+ * Get the description of the id entry
+ */
+#define GST_INDEX_ID_DESCRIPTION(entry)         ((entry)->data.id.description)
+
+/**
+ * GstIndexEntry:
+ *
+ * The basic element of an index.
+ */
+struct _GstIndexEntry {
+  /*< private >*/
+  GstIndexEntryType      type;
+  gint                   id;
+
+  union {
+    struct {
+      gchar             *description;
+    } id;
+    struct {
+      gint               nassocs;
+      GstIndexAssociation
+                        *assocs;
+      GstIndexAssociationFlags      flags;
+    } assoc;
+    struct {
+      gchar             *key;
+      GType              type;
+      gpointer           object;
+    } object;
+    struct {
+      GstFormat          format;
+      const gchar       *key;
+    } format;
+  } data;
+};
+
+/**
+ * GstIndexGroup:
+ *
+ * A group of related entries in an index.
+ */
+
+struct _GstIndexGroup {
+  /*< private >*/
+  /* unique ID of group in index */
+  gint groupnum;
+
+  /* list of entries */
+  GList *entries;
+
+  /* the certainty level of the group */
+  GstIndexCertainty certainty;
+
+  /* peer group that contains more certain entries */
+  gint peergroup;
+};
+
+/**
+ * GstIndexFilter:
+ * @index: The index being queried
+ * @entry: The entry to be added.
+ * @user_data: User data passed to the function.
+ *
+ * Function to filter out entries in the index.
+ *
+ * Returns: This function should return %TRUE if the entry is to be added
+ * to the index, %FALSE otherwise.
+ *
+ */
+typedef gboolean        (*GstIndexFilter)               (GstIndex *index,
+                                                         GstIndexEntry *entry,
+                                                         gpointer user_data);
+/**
+ * GstIndexResolverMethod:
+ * @GST_INDEX_RESOLVER_CUSTOM: Use a custom resolver
+ * @GST_INDEX_RESOLVER_GTYPE: Resolve based on the GType of the object
+ * @GST_INDEX_RESOLVER_PATH: Resolve on the path in graph
+ *
+ * The method used to resolve index writers
+ */
+typedef enum {
+  GST_INDEX_RESOLVER_CUSTOM,
+  GST_INDEX_RESOLVER_GTYPE,
+  GST_INDEX_RESOLVER_PATH
+} GstIndexResolverMethod;
+
+/**
+ * GstIndexResolver:
+ * @index: the index being queried.
+ * @writer: The object that wants to write
+ * @writer_string: A description of the writer.
+ * @user_data: user_data as registered
+ *
+ * Function to resolve ids to writer descriptions.
+ *
+ * Returns: %TRUE if an id could be assigned to the writer.
+ */
+typedef gboolean        (*GstIndexResolver)             (GstIndex *index,
+                                                         GstObject *writer,
+                                                         gchar **writer_string,
+                                                         gpointer user_data);
+
+/**
+ * GstIndexFlags:
+ * @GST_INDEX_WRITABLE: The index is writable
+ * @GST_INDEX_READABLE: The index is readable
+ * @GST_INDEX_FLAG_LAST: First flag that can be used by subclasses
+ *
+ * Flags for this index
+ */
+typedef enum {
+  GST_INDEX_WRITABLE    = (GST_OBJECT_FLAG_LAST << 0),
+  GST_INDEX_READABLE    = (GST_OBJECT_FLAG_LAST << 1),
+
+  GST_INDEX_FLAG_LAST   = (GST_OBJECT_FLAG_LAST << 8)
+} GstIndexFlags;
+
+/**
+ * GST_INDEX_IS_READABLE:
+ * @obj: The index to check
+ *
+ * Check if the index can be read from
+ */
+#define GST_INDEX_IS_READABLE(obj)    (GST_OBJECT_FLAG_IS_SET (obj, GST_INDEX_READABLE))
+
+/**
+ * GST_INDEX_IS_WRITABLE:
+ * @obj: The index to check
+ *
+ * Check if the index can be written to
+ */
+#define GST_INDEX_IS_WRITABLE(obj)    (GST_OBJECT_FLAG_IS_SET (obj, GST_INDEX_WRITABLE))
+
+/**
+ * GstIndex:
+ *
+ * Opaque #GstIndex structure.
+ */
+struct _GstIndex {
+  GstObject              object;
+
+  /*< private >*/
+  GList                 *groups;
+  GstIndexGroup         *curgroup;
+  gint                   maxgroup;
+
+  GstIndexResolverMethod method;
+  GstIndexResolver       resolver;
+  gpointer               resolver_user_data;
+  GDestroyNotify         resolver_user_data_destroy;
+
+  GstIndexFilter         filter;
+  gpointer               filter_user_data;
+  GDestroyNotify         filter_user_data_destroy;
+
+  GHashTable            *writers;
+  gint                   last_id;
+
+  /*< private >*/
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+struct _GstIndexClass {
+  GstObjectClass parent_class;
+
+  /*< protected >*/
+  gboolean      (*get_writer_id)        (GstIndex *index, gint *id, gchar *writer);
+
+  void          (*commit)               (GstIndex *index, gint id);
+
+  /* abstract methods */
+  void          (*add_entry)            (GstIndex *index, GstIndexEntry *entry);
+
+  GstIndexEntry* (*get_assoc_entry)     (GstIndex *index, gint id,
+                                         GstIndexLookupMethod method, GstIndexAssociationFlags flags,
+                                         GstFormat format, gint64 value,
+                                         GCompareDataFunc func,
+                                         gpointer user_data);
+  /* signals */
+  void          (*entry_added)          (GstIndex *index, GstIndexEntry *entry);
+
+  /*< private >*/
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+static
+GType                   gst_index_get_type              (void);
+
+#if 0
+GstIndex*               gst_index_new                   (void);
+#endif
+void                    gst_index_commit                (GstIndex *index, gint id);
+
+#if 0
+gint                    gst_index_get_group             (GstIndex *index);
+gint                    gst_index_new_group             (GstIndex *index);
+gboolean                gst_index_set_group             (GstIndex *index, gint groupnum);
+
+void                    gst_index_set_certainty         (GstIndex *index,
+                                                         GstIndexCertainty certainty);
+GstIndexCertainty       gst_index_get_certainty         (GstIndex *index);
+
+static
+void                    gst_index_set_filter            (GstIndex *index,
+                                                         GstIndexFilter filter, gpointer user_data);
+static
+void                    gst_index_set_filter_full       (GstIndex *index,
+                                                         GstIndexFilter filter, gpointer user_data,
+                                                         GDestroyNotify user_data_destroy);
+
+void                    gst_index_set_resolver          (GstIndex *index,
+                                                         GstIndexResolver resolver, gpointer user_data);
+void                    gst_index_set_resolver_full     (GstIndex *index, GstIndexResolver resolver,
+                                                         gpointer user_data,
+                                                         GDestroyNotify user_data_destroy);
+#endif
+
+static
+gboolean                gst_index_get_writer_id         (GstIndex *index, GstObject *writer, gint *id);
+
+#if 0
+GstIndexEntry*          gst_index_add_format            (GstIndex *index, gint id, GstFormat format);
+#endif
+
+static
+GstIndexEntry*          gst_index_add_associationv      (GstIndex * index, gint id, GstIndexAssociationFlags flags,
+                                                         gint n, const GstIndexAssociation * list);
+#if 0
+GstIndexEntry*          gst_index_add_association       (GstIndex *index, gint id, GstIndexAssociationFlags flags,
+                                                         GstFormat format, gint64 value, ...)
+GstIndexEntry*          gst_index_add_object            (GstIndex *index, gint id, gchar *key,
+                                                         GType type, gpointer object);
+#endif
+
+static
+GstIndexEntry*          gst_index_add_id                (GstIndex *index, gint id,
+                                                         gchar *description);
+
+static
+GstIndexEntry*          gst_index_get_assoc_entry       (GstIndex *index, gint id,
+                                                         GstIndexLookupMethod method, GstIndexAssociationFlags flags,
+                                                         GstFormat format, gint64 value);
+static
+GstIndexEntry*          gst_index_get_assoc_entry_full  (GstIndex *index, gint id,
+                                                         GstIndexLookupMethod method, GstIndexAssociationFlags flags,
+                                                         GstFormat format, gint64 value,
+                                                         GCompareDataFunc func,
+                                                         gpointer user_data);
+
+/* working with index entries */
+static
+GType gst_index_entry_get_type (void);
+static
+GstIndexEntry *         gst_index_entry_copy            (GstIndexEntry *entry);
+static
+void                    gst_index_entry_free            (GstIndexEntry *entry);
+static
+gboolean                gst_index_entry_assoc_map       (GstIndexEntry *entry,
+                                                         GstFormat format, gint64 *value);
+
+G_END_DECLS
+
+#endif /* __GST_INDEX_H__ */
diff --git a/gst/flv/gstmemindex.c b/gst/flv/gstmemindex.c
new file mode 100644
index 0000000..eef99c2
--- /dev/null
+++ b/gst/flv/gstmemindex.c
@@ -0,0 +1,432 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/gst.h>
+
+#define GST_TYPE_MEM_INDEX              \
+  (gst_index_get_type ())
+#define GST_MEM_INDEX(obj)              \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MEM_INDEX, GstMemIndex))
+#define GST_MEM_INDEX_CLASS(klass)      \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MEM_INDEX, GstMemIndexClass))
+#define GST_IS_MEM_INDEX(obj)           \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MEM_INDEX))
+#define GST_IS_MEM_INDEX_CLASS(klass)     \
+  (GST_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MEM_INDEX))
+
+/*
+ * Object model:
+ *
+ * All entries are simply added to a GList first. Then we build
+ * an index to each entry for each id/format
+ *
+ *
+ *  memindex
+ *    -----------------------------...
+ *    !                  !
+ *   id1                 id2
+ *    ------------
+ *    !          !
+ *   format1  format2
+ *    !          !
+ *   GTree      GTree
+ *
+ *
+ * The memindex creates a MemIndexId object for each writer id, a
+ * Hashtable is kept to map the id to the MemIndexId
+ *
+ * The MemIndexId keeps a MemIndexFormatIndex for each format the
+ * specific writer wants indexed.
+ *
+ * The MemIndexFormatIndex keeps all the values of the particular
+ * format in a GTree, The values of the GTree point back to the entry.
+ *
+ * Finding a value for an id/format requires locating the correct GTree,
+ * then do a lookup in the Tree to get the required value.
+ */
+
+typedef struct
+{
+  GstFormat format;
+  gint offset;
+  GTree *tree;
+}
+GstMemIndexFormatIndex;
+
+typedef struct
+{
+  gint id;
+  GHashTable *format_index;
+}
+GstMemIndexId;
+
+typedef struct _GstMemIndex GstMemIndex;
+typedef struct _GstMemIndexClass GstMemIndexClass;
+
+struct _GstMemIndex
+{
+  GstIndex parent;
+
+  GList *associations;
+
+  GHashTable *id_index;
+};
+
+struct _GstMemIndexClass
+{
+  GstIndexClass parent_class;
+};
+
+static void gst_mem_index_finalize (GObject * object);
+
+static void gst_mem_index_add_entry (GstIndex * index, GstIndexEntry * entry);
+static GstIndexEntry *gst_mem_index_get_assoc_entry (GstIndex * index, gint id,
+    GstIndexLookupMethod method, GstIndexAssociationFlags flags,
+    GstFormat format, gint64 value, GCompareDataFunc func, gpointer user_data);
+
+#define CLASS(mem_index)  GST_MEM_INDEX_CLASS (G_OBJECT_GET_CLASS (mem_index))
+
+static GType gst_mem_index_get_type (void);
+
+typedef GstMemIndex GstFlvDemuxMemIndex;
+typedef GstMemIndexClass GstFlvDemuxMemIndexClass;
+G_DEFINE_TYPE (GstFlvDemuxMemIndex, gst_mem_index, GST_TYPE_INDEX);
+
+static void
+gst_mem_index_class_init (GstMemIndexClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstIndexClass *gstindex_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstindex_class = (GstIndexClass *) klass;
+
+  gobject_class->finalize = gst_mem_index_finalize;
+
+  gstindex_class->add_entry = GST_DEBUG_FUNCPTR (gst_mem_index_add_entry);
+  gstindex_class->get_assoc_entry =
+      GST_DEBUG_FUNCPTR (gst_mem_index_get_assoc_entry);
+}
+
+static void
+gst_mem_index_init (GstMemIndex * index)
+{
+  GST_DEBUG ("created new mem index");
+
+  index->associations = NULL;
+  index->id_index = g_hash_table_new (g_int_hash, g_int_equal);
+}
+
+static void
+gst_mem_index_free_format (gpointer key, gpointer value, gpointer user_data)
+{
+  GstMemIndexFormatIndex *index = (GstMemIndexFormatIndex *) value;
+
+  if (index->tree) {
+    g_tree_destroy (index->tree);
+  }
+
+  g_slice_free (GstMemIndexFormatIndex, index);
+}
+
+static void
+gst_mem_index_free_id (gpointer key, gpointer value, gpointer user_data)
+{
+  GstMemIndexId *id_index = (GstMemIndexId *) value;
+
+  if (id_index->format_index) {
+    g_hash_table_foreach (id_index->format_index, gst_mem_index_free_format,
+        NULL);
+    g_hash_table_destroy (id_index->format_index);
+    id_index->format_index = NULL;
+  }
+
+  g_slice_free (GstMemIndexId, id_index);
+}
+
+static void
+gst_mem_index_finalize (GObject * object)
+{
+  GstMemIndex *memindex = GST_MEM_INDEX (object);
+
+  /* Delete the trees referencing the associations first */
+  if (memindex->id_index) {
+    g_hash_table_foreach (memindex->id_index, gst_mem_index_free_id, NULL);
+    g_hash_table_destroy (memindex->id_index);
+    memindex->id_index = NULL;
+  }
+
+  /* Then delete the associations themselves */
+  if (memindex->associations) {
+    g_list_foreach (memindex->associations, (GFunc) gst_index_entry_free, NULL);
+    g_list_free (memindex->associations);
+    memindex->associations = NULL;
+  }
+
+  G_OBJECT_CLASS (gst_mem_index_parent_class)->finalize (object);
+}
+
+static void
+gst_mem_index_add_id (GstIndex * index, GstIndexEntry * entry)
+{
+  GstMemIndex *memindex = GST_MEM_INDEX (index);
+  GstMemIndexId *id_index;
+
+  id_index = g_hash_table_lookup (memindex->id_index, &entry->id);
+
+  if (!id_index) {
+    id_index = g_slice_new0 (GstMemIndexId);
+
+    id_index->id = entry->id;
+    id_index->format_index = g_hash_table_new (g_int_hash, g_int_equal);
+    g_hash_table_insert (memindex->id_index, &id_index->id, id_index);
+  }
+}
+
+static gint
+mem_index_compare (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+  GstMemIndexFormatIndex *index = user_data;
+  gint64 val1, val2;
+  gint64 diff;
+
+  val1 = GST_INDEX_ASSOC_VALUE (((GstIndexEntry *) a), index->offset);
+  val2 = GST_INDEX_ASSOC_VALUE (((GstIndexEntry *) b), index->offset);
+
+  diff = (val2 - val1);
+
+  return (diff == 0 ? 0 : (diff > 0 ? 1 : -1));
+}
+
+static void
+gst_mem_index_index_format (GstMemIndexId * id_index, GstIndexEntry * entry,
+    gint assoc)
+{
+  GstMemIndexFormatIndex *index;
+  GstFormat *format;
+
+  format = &GST_INDEX_ASSOC_FORMAT (entry, assoc);
+
+  index = g_hash_table_lookup (id_index->format_index, format);
+
+  if (!index) {
+    index = g_slice_new0 (GstMemIndexFormatIndex);
+
+    index->format = *format;
+    index->offset = assoc;
+    index->tree = g_tree_new_with_data (mem_index_compare, index);
+
+    g_hash_table_insert (id_index->format_index, &index->format, index);
+  }
+
+  g_tree_insert (index->tree, entry, entry);
+}
+
+static void
+gst_mem_index_add_association (GstIndex * index, GstIndexEntry * entry)
+{
+  GstMemIndex *memindex = GST_MEM_INDEX (index);
+  GstMemIndexId *id_index;
+
+  memindex->associations = g_list_prepend (memindex->associations, entry);
+
+  id_index = g_hash_table_lookup (memindex->id_index, &entry->id);
+  if (id_index) {
+    gint i;
+
+    for (i = 0; i < GST_INDEX_NASSOCS (entry); i++) {
+      gst_mem_index_index_format (id_index, entry, i);
+    }
+  }
+}
+
+static void
+gst_mem_index_add_object (GstIndex * index, GstIndexEntry * entry)
+{
+}
+
+static void
+gst_mem_index_add_format (GstIndex * index, GstIndexEntry * entry)
+{
+}
+
+static void
+gst_mem_index_add_entry (GstIndex * index, GstIndexEntry * entry)
+{
+  GST_LOG_OBJECT (index, "added this entry");
+
+  switch (entry->type) {
+    case GST_INDEX_ENTRY_ID:
+      gst_mem_index_add_id (index, entry);
+      break;
+    case GST_INDEX_ENTRY_ASSOCIATION:
+      gst_mem_index_add_association (index, entry);
+      break;
+    case GST_INDEX_ENTRY_OBJECT:
+      gst_mem_index_add_object (index, entry);
+      break;
+    case GST_INDEX_ENTRY_FORMAT:
+      gst_mem_index_add_format (index, entry);
+      break;
+    default:
+      break;
+  }
+}
+
+typedef struct
+{
+  gint64 value;
+  GstMemIndexFormatIndex *index;
+  gboolean exact;
+  GstIndexEntry *lower;
+  gint64 low_diff;
+  GstIndexEntry *higher;
+  gint64 high_diff;
+}
+GstMemIndexSearchData;
+
+static gint
+mem_index_search (gconstpointer a, gconstpointer b)
+{
+  GstMemIndexSearchData *data = (GstMemIndexSearchData *) b;
+  GstMemIndexFormatIndex *index = data->index;
+  gint64 val1, val2;
+  gint64 diff;
+
+  val1 = GST_INDEX_ASSOC_VALUE (((GstIndexEntry *) a), index->offset);
+  val2 = data->value;
+
+  diff = (val1 - val2);
+  if (diff == 0)
+    return 0;
+
+  /* exact matching, don't update low/high */
+  if (data->exact)
+    return (diff > 0 ? 1 : -1);
+
+  if (diff < 0) {
+    if (diff > data->low_diff) {
+      data->low_diff = diff;
+      data->lower = (GstIndexEntry *) a;
+    }
+    diff = -1;
+  } else {
+    if (diff < data->high_diff) {
+      data->high_diff = diff;
+      data->higher = (GstIndexEntry *) a;
+    }
+    diff = 1;
+  }
+
+  return diff;
+}
+
+static GstIndexEntry *
+gst_mem_index_get_assoc_entry (GstIndex * index, gint id,
+    GstIndexLookupMethod method,
+    GstIndexAssociationFlags flags,
+    GstFormat format, gint64 value, GCompareDataFunc func, gpointer user_data)
+{
+  GstMemIndex *memindex = GST_MEM_INDEX (index);
+  GstMemIndexId *id_index;
+  GstMemIndexFormatIndex *format_index;
+  GstIndexEntry *entry;
+  GstMemIndexSearchData data;
+
+  id_index = g_hash_table_lookup (memindex->id_index, &id);
+  if (!id_index)
+    return NULL;
+
+  format_index = g_hash_table_lookup (id_index->format_index, &format);
+  if (!format_index)
+    return NULL;
+
+  data.value = value;
+  data.index = format_index;
+  data.exact = (method == GST_INDEX_LOOKUP_EXACT);
+
+  /* setup data for low/high checks if we are not looking
+   * for an exact match */
+  if (!data.exact) {
+    data.low_diff = G_MININT64;
+    data.lower = NULL;
+    data.high_diff = G_MAXINT64;
+    data.higher = NULL;
+  }
+
+  entry = g_tree_search (format_index->tree, mem_index_search, &data);
+
+  /* get the low/high values if we're not exact */
+  if (entry == NULL && !data.exact) {
+    if (method == GST_INDEX_LOOKUP_BEFORE)
+      entry = data.lower;
+    else if (method == GST_INDEX_LOOKUP_AFTER) {
+      entry = data.higher;
+    }
+  }
+
+  if (entry && ((GST_INDEX_ASSOC_FLAGS (entry) & flags) != flags)) {
+    if (method != GST_INDEX_LOOKUP_EXACT) {
+      GList *l_entry = g_list_find (memindex->associations, entry);
+
+      entry = NULL;
+
+      while (l_entry) {
+        entry = (GstIndexEntry *) l_entry->data;
+
+        if (entry->id == id && (GST_INDEX_ASSOC_FLAGS (entry) & flags) == flags)
+          break;
+
+        if (method == GST_INDEX_LOOKUP_BEFORE)
+          l_entry = g_list_next (l_entry);
+        else if (method == GST_INDEX_LOOKUP_AFTER) {
+          l_entry = g_list_previous (l_entry);
+        }
+      }
+    } else {
+      entry = NULL;
+    }
+  }
+
+  return entry;
+}
+
+#if 0
+gboolean
+gst_mem_index_plugin_init (GstPlugin * plugin)
+{
+  GstIndexFactory *factory;
+
+  factory = gst_index_factory_new ("memindex",
+      "A index that stores entries in memory", gst_mem_index_get_type ());
+
+  if (factory == NULL) {
+    g_warning ("failed to create memindex factory");
+    return FALSE;
+  }
+
+  GST_PLUGIN_FEATURE (factory)->plugin_name = plugin->desc.name;
+  GST_PLUGIN_FEATURE (factory)->loaded = TRUE;
+
+  gst_registry_add_feature (gst_registry_get_default (),
+      GST_PLUGIN_FEATURE (factory));
+
+  return TRUE;
+}
+#endif
diff --git a/gst/flv/meson.build b/gst/flv/meson.build
new file mode 100644
index 0000000..b9190d3
--- /dev/null
+++ b/gst/flv/meson.build
@@ -0,0 +1,8 @@
+gstflv = library('gstflv',
+  'gstflvdemux.c', 'gstflvmux.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc, libsinc],
+  dependencies : [gstpbutils_dep, gstvideo_dep, gsttag_dep, gstaudio_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/flx/Makefile.am b/gst/flx/Makefile.am
new file mode 100644
index 0000000..58934ea
--- /dev/null
+++ b/gst/flx/Makefile.am
@@ -0,0 +1,8 @@
+plugin_LTLIBRARIES = libgstflxdec.la
+
+libgstflxdec_la_SOURCES = gstflxdec.c flx_color.c
+libgstflxdec_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstflxdec_la_LIBADD = $(GST_BASE_LIBS)  $(GST_LIBS)
+libgstflxdec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = flx_fmt.h flx_color.h gstflxdec.h
diff --git a/gst/flx/flx_color.c b/gst/flx/flx_color.c
new file mode 100644
index 0000000..3a58135
--- /dev/null
+++ b/gst/flx/flx_color.c
@@ -0,0 +1,117 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/gst.h>
+
+#include "flx_color.h"
+
+FlxColorSpaceConverter *
+flx_colorspace_converter_new (gint width, gint height)
+{
+  FlxColorSpaceConverter *new = g_malloc (sizeof (FlxColorSpaceConverter));
+
+  new->width = width;
+  new->height = height;
+
+  memset (new->palvec, 0, sizeof (new->palvec));
+  return new;
+}
+
+void
+flx_colorspace_converter_destroy (FlxColorSpaceConverter * flxpal)
+{
+  g_return_if_fail (flxpal != NULL);
+
+  g_free (flxpal);
+}
+
+void
+flx_colorspace_convert (FlxColorSpaceConverter * flxpal, guchar * src,
+    guchar * dest)
+{
+  guint size, col;
+
+  g_return_if_fail (flxpal != NULL);
+  g_return_if_fail (src != dest);
+
+
+  size = flxpal->width * flxpal->height;
+
+  while (size--) {
+    col = (*src++ * 3);
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+    *dest++ = 0;
+    *dest++ = flxpal->palvec[col];
+    *dest++ = flxpal->palvec[col + 1];
+    *dest++ = flxpal->palvec[col + 2];
+#else
+    *dest++ = flxpal->palvec[col + 2];
+    *dest++ = flxpal->palvec[col + 1];
+    *dest++ = flxpal->palvec[col];
+    *dest++ = 0;
+#endif
+  }
+
+}
+
+
+void
+flx_set_palette_vector (FlxColorSpaceConverter * flxpal, guint start, guint num,
+    guchar * newpal, gint scale)
+{
+  guint grab;
+
+  g_return_if_fail (flxpal != NULL);
+  g_return_if_fail (start < 0x100);
+
+  grab = ((start + num) > 0x100 ? 0x100 - start : num);
+
+  if (scale) {
+    gint i = 0;
+
+    start *= 3;
+    while (grab) {
+      flxpal->palvec[start++] = newpal[i++] << scale;
+      flxpal->palvec[start++] = newpal[i++] << scale;
+      flxpal->palvec[start++] = newpal[i++] << scale;
+      grab--;
+    }
+  } else {
+    memcpy (&flxpal->palvec[start * 3], newpal, grab * 3);
+  }
+}
+
+void
+flx_set_color (FlxColorSpaceConverter * flxpal, guint colr, guint red,
+    guint green, guint blue, gint scale)
+{
+
+  g_return_if_fail (flxpal != NULL);
+  g_return_if_fail (colr < 0x100);
+
+  flxpal->palvec[(colr * 3)] = red << scale;
+  flxpal->palvec[(colr * 3) + 1] = green << scale;
+  flxpal->palvec[(colr * 3) + 2] = blue << scale;
+}
diff --git a/gst/flx/flx_color.h b/gst/flx/flx_color.h
new file mode 100644
index 0000000..fd36ab7
--- /dev/null
+++ b/gst/flx/flx_color.h
@@ -0,0 +1,52 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __FLX_COLOR_H__
+#define __FLX_COLOR_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+  FLX_COLORSPACE_RGB8,
+  FLX_COLORSPACE_RGB32,
+} FlxColorSpaceType;
+
+
+typedef struct _FlxColorSpaceConverter FlxColorSpaceConverter;
+
+struct _FlxColorSpaceConverter {
+  guint      width;
+  guint      height;
+  guchar      palvec[768];
+};
+
+void flx_colorspace_converter_destroy(FlxColorSpaceConverter *flxpal);
+void flx_colorspace_convert(FlxColorSpaceConverter *flxpal, guchar *src, guchar *dest);
+FlxColorSpaceConverter * flx_colorspace_converter_new(gint width, gint height);
+
+void flx_set_palette_vector(FlxColorSpaceConverter *flxpal, guint start, guint num, 
+          guchar *newpal, gint scale);
+void flx_set_color(FlxColorSpaceConverter *flxpal, guint colr, guint red, guint green,
+          guint blue, gint scale);
+
+G_END_DECLS
+
+#endif /* __FLX_COLOR_H__ */
diff --git a/gst/flx/flx_fmt.h b/gst/flx/flx_fmt.h
new file mode 100644
index 0000000..abff200
--- /dev/null
+++ b/gst/flx/flx_fmt.h
@@ -0,0 +1,128 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_FLX_FMT_H__
+#define __GST_FLX_FMT_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+enum Flx_TypeChunk
+{
+	/* frame chunks */
+	FLX_PREFIX_TYPE		= 0xf100,
+	FLX_SCRIPT_CHUNK	= 0xf1e0,
+	FLX_FRAME_TYPE		= 0xf1fa,
+	FLX_SEGMENT_TABLE	= 0xf1fb,
+	FLX_HUFFMAN_TABLE	= 0xf1fc,
+
+	/* sub chunks */
+	FLX_CEL_DATA		= 3,
+	FLX_COLOR256		= 4,
+	FLX_SS2			= 7,
+        FLX_COLOR64		= 11,
+        FLX_LC			= 12,
+        FLX_BLACK		= 13,
+        FLX_BRUN		= 15,
+        FLX_COPY		= 16,
+        FLX_MINI		= 18,
+	FLX_DTA_RUN		= 25,
+	FLX_DTA_COPY		= 26,
+	FLX_DTA_LC		= 27,
+	FLX_LABEL		= 31,
+	FLX_BMP_MASK		= 32,
+	FLX_MLEV_MASK		= 33,
+	FLX_SEGMENT		= 34,
+	FLX_KEY_IMAGE		= 35,
+	FLX_KEY_PAL		= 36,
+	FLX_REGION		= 37,
+	FLX_WAVE		= 38,
+	FLX_USERSTRING		= 39,
+	FLX_RGN_MASK		= 40
+
+};
+
+enum Flx_MagicHdr
+{
+	FLX_MAGICHDR_FLI	= 0xaf11,
+	FLX_MAGICHDR_FLC	= 0xaf12,
+	FLX_MAGICHDR_FLX	= 0xaf44,
+	FLX_MAGICHDR_HUFFBWT	= 0xaf30
+};
+
+typedef struct _FlxHeader 
+{
+	guint32	size;
+	guint16 type;
+	guint16	frames;
+	guint16 width,height,depth,flags;
+	guint32 speed;
+	guint16 reserved1;
+	/* FLC */ 
+	guint32 created,creator,updated,updater;
+	guint16 aspect_dx, aspect_dy;
+	/* EGI */
+	guint16 ext_flags,keyframes,totalframes;
+	guint32 req_memory;
+	guint16 max_regions,transp_num;
+	guchar	reserved2[24];
+	/* FLC */
+	guint32 oframe1,oframe2;
+	guchar	reserved3[40];
+} FlxHeader;
+#define FlxHeaderSize 128
+
+typedef struct _FlxFrameChunk
+{
+	guint32	size;
+	guint16	id;
+} FlxFrameChunk;
+#define FlxFrameChunkSize 6
+
+typedef struct _FlxPrefixChunk
+{
+	guint16 chunks;
+	guchar  reserved[8];
+} FlxPrefixChunk;
+
+typedef struct _FlxSegmentTable
+{
+	guint16 segments;
+} FlxSegmentTable;
+
+typedef struct _FlxHuffmanTable
+{
+	guint16 codelength;
+	guint16 numcodes;
+	guchar	reserved[6];
+} FlxHuffmanTable;
+
+typedef struct _FlxFrameType
+{
+	guint16 chunks;
+	guint16 delay;
+	guchar	reserved[6];
+} FlxFrameType;
+#define FlxFrameTypeSize 10
+
+G_END_DECLS
+
+#endif /* __GST_FLX_FMT_H__ */
diff --git a/gst/flx/gstflxdec.c b/gst/flx/gstflxdec.c
new file mode 100644
index 0000000..37d552a
--- /dev/null
+++ b/gst/flx/gstflxdec.c
@@ -0,0 +1,998 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
+ * Copyright (C) <2016> Matthew Waters <matthew@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-flxdec
+ *
+ * This element decodes fli/flc/flx-video into raw video
+ */
+/*
+ * http://www.coolutils.com/Formats/FLI
+ * http://woodshole.er.usgs.gov/operations/modeling/flc.html
+ * http://www.compuphase.com/flic.htm
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+
+#include "flx_fmt.h"
+#include "gstflxdec.h"
+#include <gst/video/video.h>
+
+#define JIFFIE  (GST_SECOND/70)
+
+GST_DEBUG_CATEGORY_STATIC (flxdec_debug);
+#define GST_CAT_DEFAULT flxdec_debug
+
+/* input */
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-fli")
+    );
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+#define RGB_ORDER "xRGB"
+#else
+#define RGB_ORDER "BGRx"
+#endif
+
+/* output */
+static GstStaticPadTemplate src_video_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (RGB_ORDER))
+    );
+
+static void gst_flxdec_dispose (GstFlxDec * flxdec);
+
+static GstFlowReturn gst_flxdec_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buf);
+static gboolean gst_flxdec_sink_event_handler (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+
+static GstStateChangeReturn gst_flxdec_change_state (GstElement * element,
+    GstStateChange transition);
+
+static gboolean gst_flxdec_src_query_handler (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+
+static gboolean flx_decode_color (GstFlxDec * flxdec, GstByteReader * reader,
+    GstByteWriter * writer, gint scale);
+static gboolean flx_decode_brun (GstFlxDec * flxdec,
+    GstByteReader * reader, GstByteWriter * writer);
+static gboolean flx_decode_delta_fli (GstFlxDec * flxdec,
+    GstByteReader * reader, GstByteWriter * writer);
+static gboolean flx_decode_delta_flc (GstFlxDec * flxdec,
+    GstByteReader * reader, GstByteWriter * writer);
+
+#define rndalign(off) ((off) + ((off) & 1))
+
+#define gst_flxdec_parent_class parent_class
+G_DEFINE_TYPE (GstFlxDec, gst_flxdec, GST_TYPE_ELEMENT);
+
+static void
+gst_flxdec_class_init (GstFlxDecClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->dispose = (GObjectFinalizeFunc) gst_flxdec_dispose;
+
+  GST_DEBUG_CATEGORY_INIT (flxdec_debug, "flxdec", 0, "FLX video decoder");
+
+  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_flxdec_change_state);
+
+  gst_element_class_set_static_metadata (gstelement_class, "FLX video decoder",
+      "Codec/Decoder/Video",
+      "FLC/FLI/FLX video decoder",
+      "Sepp Wijnands <mrrazz@garbage-coderz.net>, Zeeshan Ali <zeenix@gmail.com>");
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&sink_factory));
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&src_video_factory));
+}
+
+static void
+gst_flxdec_init (GstFlxDec * flxdec)
+{
+  flxdec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
+  gst_element_add_pad (GST_ELEMENT (flxdec), flxdec->sinkpad);
+  gst_pad_set_chain_function (flxdec->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_flxdec_chain));
+  gst_pad_set_event_function (flxdec->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_flxdec_sink_event_handler));
+
+  flxdec->srcpad = gst_pad_new_from_static_template (&src_video_factory, "src");
+  gst_element_add_pad (GST_ELEMENT (flxdec), flxdec->srcpad);
+  gst_pad_set_query_function (flxdec->srcpad,
+      GST_DEBUG_FUNCPTR (gst_flxdec_src_query_handler));
+
+  gst_pad_use_fixed_caps (flxdec->srcpad);
+
+  flxdec->adapter = gst_adapter_new ();
+}
+
+static void
+gst_flxdec_dispose (GstFlxDec * flxdec)
+{
+  if (flxdec->adapter) {
+    g_object_unref (flxdec->adapter);
+    flxdec->adapter = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->dispose ((GObject *) flxdec);
+}
+
+static gboolean
+gst_flxdec_src_query_handler (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  GstFlxDec *flxdec = (GstFlxDec *) parent;
+  gboolean ret = FALSE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_DURATION:
+    {
+      GstFormat format;
+
+      gst_query_parse_duration (query, &format, NULL);
+
+      if (format != GST_FORMAT_TIME)
+        goto done;
+
+      gst_query_set_duration (query, format, flxdec->duration);
+
+      ret = TRUE;
+    }
+    default:
+      break;
+  }
+done:
+  if (!ret)
+    ret = gst_pad_query_default (pad, parent, query);
+
+  return ret;
+}
+
+static gboolean
+gst_flxdec_sink_event_handler (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstFlxDec *flxdec;
+  gboolean ret;
+
+  flxdec = GST_FLXDEC (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEGMENT:
+    {
+      gst_event_copy_segment (event, &flxdec->segment);
+      if (flxdec->segment.format != GST_FORMAT_TIME) {
+        GST_DEBUG_OBJECT (flxdec, "generating TIME segment");
+        gst_segment_init (&flxdec->segment, GST_FORMAT_TIME);
+        gst_event_unref (event);
+        event = gst_event_new_segment (&flxdec->segment);
+      }
+
+      if (gst_pad_has_current_caps (flxdec->srcpad)) {
+        ret = gst_pad_event_default (pad, parent, event);
+      } else {
+        flxdec->need_segment = TRUE;
+        gst_event_unref (event);
+        ret = TRUE;
+      }
+      break;
+    }
+    case GST_EVENT_FLUSH_STOP:
+      gst_segment_init (&flxdec->segment, GST_FORMAT_UNDEFINED);
+      ret = gst_pad_event_default (pad, parent, event);
+      break;
+    default:
+      ret = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+flx_decode_chunks (GstFlxDec * flxdec, gulong n_chunks, GstByteReader * reader,
+    GstByteWriter * writer)
+{
+  gboolean ret = TRUE;
+
+  while (n_chunks--) {
+    GstByteReader chunk;
+    guint32 size;
+    guint16 type;
+
+    if (!gst_byte_reader_get_uint32_le (reader, &size))
+      goto parse_error;
+    if (!gst_byte_reader_get_uint16_le (reader, &type))
+      goto parse_error;
+    GST_LOG_OBJECT (flxdec, "chunk has type 0x%02x size %d", type, size);
+
+    if (!gst_byte_reader_get_sub_reader (reader, &chunk,
+            size - FlxFrameChunkSize)) {
+      GST_ERROR_OBJECT (flxdec, "Incorrect size in the chunk header");
+      goto error;
+    }
+
+    switch (type) {
+      case FLX_COLOR64:
+        ret = flx_decode_color (flxdec, &chunk, writer, 2);
+        break;
+
+      case FLX_COLOR256:
+        ret = flx_decode_color (flxdec, &chunk, writer, 0);
+        break;
+
+      case FLX_BRUN:
+        ret = flx_decode_brun (flxdec, &chunk, writer);
+        break;
+
+      case FLX_LC:
+        ret = flx_decode_delta_fli (flxdec, &chunk, writer);
+        break;
+
+      case FLX_SS2:
+        ret = flx_decode_delta_flc (flxdec, &chunk, writer);
+        break;
+
+      case FLX_BLACK:
+        ret = gst_byte_writer_fill (writer, 0, flxdec->size);
+        break;
+
+      case FLX_MINI:
+        break;
+
+      default:
+        GST_WARNING ("Unimplemented chunk type: 0x%02x size: %d - skipping",
+            type, size);
+        break;
+    }
+
+    if (!ret)
+      break;
+  }
+
+  return ret;
+
+parse_error:
+  GST_ERROR_OBJECT (flxdec, "Failed to decode chunk");
+error:
+  return FALSE;
+}
+
+
+static gboolean
+flx_decode_color (GstFlxDec * flxdec, GstByteReader * reader,
+    GstByteWriter * writer, gint scale)
+{
+  guint8 count, indx;
+  guint16 packs;
+
+  if (!gst_byte_reader_get_uint16_le (reader, &packs))
+    goto error;
+  indx = 0;
+
+  GST_LOG ("GstFlxDec: cmap packs: %d", (guint) packs);
+  while (packs--) {
+    const guint8 *data;
+    guint16 actual_count;
+
+    /* color map index + skip count */
+    if (!gst_byte_reader_get_uint8 (reader, &indx))
+      goto error;
+
+    /* number of rgb triplets */
+    if (!gst_byte_reader_get_uint8 (reader, &count))
+      goto error;
+
+    actual_count = count == 0 ? 256 : count;
+
+    if (!gst_byte_reader_get_data (reader, count * 3, &data))
+      goto error;
+
+    GST_LOG_OBJECT (flxdec, "cmap count: %d (indx: %d)", actual_count, indx);
+    flx_set_palette_vector (flxdec->converter, indx, actual_count,
+        (guchar *) data, scale);
+  }
+
+  return TRUE;
+
+error:
+  GST_ERROR_OBJECT (flxdec, "Error decoding color palette");
+  return FALSE;
+}
+
+static gboolean
+flx_decode_brun (GstFlxDec * flxdec, GstByteReader * reader,
+    GstByteWriter * writer)
+{
+  gulong lines, row;
+
+  g_return_val_if_fail (flxdec != NULL, FALSE);
+
+  lines = flxdec->hdr.height;
+  while (lines--) {
+    /* packet count.  
+     * should not be used anymore, since the flc format can
+     * contain more then 255 RLE packets. we use the frame 
+     * width instead. 
+     */
+    if (!gst_byte_reader_skip (reader, 1))
+      goto error;
+
+    row = flxdec->hdr.width;
+    while (row) {
+      gint8 count;
+
+      if (!gst_byte_reader_get_int8 (reader, &count))
+        goto error;
+
+      if (count <= 0) {
+        const guint8 *data;
+
+        /* literal run */
+        count = ABS (count);
+
+        GST_LOG_OBJECT (flxdec, "have literal run of size %d", count);
+
+        if (count > row) {
+          GST_ERROR_OBJECT (flxdec, "Invalid BRUN line detected. "
+              "bytes to write exceeds the end of the row");
+          return FALSE;
+        }
+        row -= count;
+
+        if (!gst_byte_reader_get_data (reader, count, &data))
+          goto error;
+        if (!gst_byte_writer_put_data (writer, data, count))
+          goto error;
+      } else {
+        guint8 x;
+
+        GST_LOG_OBJECT (flxdec, "have replicate run of size %d", count);
+
+        if (count > row) {
+          GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected."
+              "bytes to write exceeds the end of the row");
+          return FALSE;
+        }
+
+        /* replicate run */
+        row -= count;
+
+        if (!gst_byte_reader_get_uint8 (reader, &x))
+          goto error;
+        if (!gst_byte_writer_fill (writer, x, count))
+          goto error;
+      }
+    }
+  }
+
+  return TRUE;
+
+error:
+  GST_ERROR_OBJECT (flxdec, "Failed to decode BRUN packet");
+  return FALSE;
+}
+
+static gboolean
+flx_decode_delta_fli (GstFlxDec * flxdec, GstByteReader * reader,
+    GstByteWriter * writer)
+{
+  guint16 start_line, lines;
+  guint line_start_i;
+
+  g_return_val_if_fail (flxdec != NULL, FALSE);
+  g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);
+
+  /* use last frame for delta */
+  if (!gst_byte_writer_put_data (writer, flxdec->delta_data, flxdec->size))
+    goto error;
+
+  if (!gst_byte_reader_get_uint16_le (reader, &start_line))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &lines))
+    goto error;
+  GST_LOG_OBJECT (flxdec, "height %d start line %d line count %d",
+      flxdec->hdr.height, start_line, lines);
+
+  if (start_line + lines > flxdec->hdr.height) {
+    GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. too many lines.");
+    return FALSE;
+  }
+
+  line_start_i = flxdec->hdr.width * start_line;
+  if (!gst_byte_writer_set_pos (writer, line_start_i))
+    goto error;
+
+  while (lines--) {
+    guint8 packets;
+
+    /* packet count */
+    if (!gst_byte_reader_get_uint8 (reader, &packets))
+      goto error;
+    GST_LOG_OBJECT (flxdec, "have %d packets", packets);
+
+    while (packets--) {
+      /* skip count */
+      guint8 skip;
+      gint8 count;
+      if (!gst_byte_reader_get_uint8 (reader, &skip))
+        goto error;
+
+      /* skip bytes */
+      if (!gst_byte_writer_set_pos (writer,
+              gst_byte_writer_get_pos (writer) + skip))
+        goto error;
+
+      /* RLE count */
+      if (!gst_byte_reader_get_int8 (reader, &count))
+        goto error;
+
+      if (count < 0) {
+        guint8 x;
+
+        /* literal run */
+        count = ABS (count);
+        GST_LOG_OBJECT (flxdec, "have literal run of size %d at offset %d",
+            count, skip);
+
+        if (skip + count > flxdec->hdr.width) {
+          GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
+              "line too long.");
+          return FALSE;
+        }
+
+        if (!gst_byte_reader_get_uint8 (reader, &x))
+          goto error;
+        if (!gst_byte_writer_fill (writer, x, count))
+          goto error;
+      } else {
+        const guint8 *data;
+
+        GST_LOG_OBJECT (flxdec, "have replicate run of size %d at offset %d",
+            count, skip);
+
+        if (skip + count > flxdec->hdr.width) {
+          GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
+              "line too long.");
+          return FALSE;
+        }
+
+        /* replicate run */
+        if (!gst_byte_reader_get_data (reader, count, &data))
+          goto error;
+        if (!gst_byte_writer_put_data (writer, data, count))
+          goto error;
+      }
+    }
+    line_start_i += flxdec->hdr.width;
+    if (!gst_byte_writer_set_pos (writer, line_start_i))
+      goto error;
+  }
+
+  return TRUE;
+
+error:
+  GST_ERROR_OBJECT (flxdec, "Failed to decode FLI packet");
+  return FALSE;
+}
+
+static gboolean
+flx_decode_delta_flc (GstFlxDec * flxdec, GstByteReader * reader,
+    GstByteWriter * writer)
+{
+  guint16 lines, start_l;
+
+  g_return_val_if_fail (flxdec != NULL, FALSE);
+  g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);
+
+  /* use last frame for delta */
+  if (!gst_byte_writer_put_data (writer, flxdec->delta_data, flxdec->size))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &lines))
+    goto error;
+
+  if (lines > flxdec->hdr.height) {
+    GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. too many lines.");
+    return FALSE;
+  }
+
+  start_l = lines;
+
+  while (lines) {
+    guint16 opcode;
+
+    if (!gst_byte_writer_set_pos (writer,
+            flxdec->hdr.width * (start_l - lines)))
+      goto error;
+
+    /* process opcode(s) */
+    while (TRUE) {
+      if (!gst_byte_reader_get_uint16_le (reader, &opcode))
+        goto error;
+      if ((opcode & 0xc000) == 0)
+        break;
+
+      if ((opcode & 0xc000) == 0xc000) {
+        /* line skip count */
+        gulong skip = (0x10000 - opcode);
+        if (skip > flxdec->hdr.height) {
+          GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
+              "skip line count too big.");
+          return FALSE;
+        }
+        start_l += skip;
+        if (!gst_byte_writer_set_pos (writer,
+                gst_byte_writer_get_pos (writer) + flxdec->hdr.width * skip))
+          goto error;
+      } else {
+        /* last pixel */
+        if (!gst_byte_writer_set_pos (writer,
+                gst_byte_writer_get_pos (writer) + flxdec->hdr.width))
+          goto error;
+        if (!gst_byte_writer_put_uint8 (writer, opcode & 0xff))
+          goto error;
+      }
+    }
+
+    /* last opcode is the packet count */
+    GST_LOG_OBJECT (flxdec, "have %d packets", opcode);
+    while (opcode--) {
+      /* skip count */
+      guint8 skip;
+      gint8 count;
+
+      if (!gst_byte_reader_get_uint8 (reader, &skip))
+        goto error;
+      if (!gst_byte_writer_set_pos (writer,
+              gst_byte_writer_get_pos (writer) + skip))
+        goto error;
+
+      /* RLE count */
+      if (!gst_byte_reader_get_int8 (reader, &count))
+        goto error;
+
+      if (count < 0) {
+        guint16 x;
+
+        /* replicate word run */
+        count = ABS (count);
+
+        GST_LOG_OBJECT (flxdec, "have replicate run of size %d at offset %d",
+            count, skip);
+
+        if (skip + count > flxdec->hdr.width) {
+          GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
+              "line too long.");
+          return FALSE;
+        }
+
+        if (!gst_byte_reader_get_uint16_le (reader, &x))
+          goto error;
+
+        while (count--) {
+          if (!gst_byte_writer_put_uint16_le (writer, x)) {
+            goto error;
+          }
+        }
+      } else {
+        GST_LOG_OBJECT (flxdec, "have literal run of size %d at offset %d",
+            count, skip);
+
+        if (skip + count > flxdec->hdr.width) {
+          GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
+              "line too long.");
+          return FALSE;
+        }
+
+        while (count--) {
+          guint16 x;
+
+          if (!gst_byte_reader_get_uint16_le (reader, &x))
+            goto error;
+          if (!gst_byte_writer_put_uint16_le (writer, x))
+            goto error;
+        }
+      }
+    }
+    lines--;
+  }
+
+  return TRUE;
+
+error:
+  GST_ERROR_OBJECT (flxdec, "Failed to decode FLI packet");
+  return FALSE;
+}
+
+static gboolean
+_read_flx_header (GstFlxDec * flxdec, GstByteReader * reader, FlxHeader * flxh)
+{
+  memset (flxh, 0, sizeof (*flxh));
+
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->size))
+    goto error;
+  if (flxh->size < FlxHeaderSize) {
+    GST_ERROR_OBJECT (flxdec, "Invalid file size in the header");
+    return FALSE;
+  }
+
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->type))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->frames))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->width))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->height))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->depth))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->flags))
+    goto error;
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->speed))
+    goto error;
+  if (!gst_byte_reader_skip (reader, 2))        /* reserved */
+    goto error;
+  /* FLC */
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->created))
+    goto error;
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->creator))
+    goto error;
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->updated))
+    goto error;
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->updater))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->aspect_dx))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->aspect_dy))
+    goto error;
+  /* EGI */
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->ext_flags))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->keyframes))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->totalframes))
+    goto error;
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->req_memory))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->max_regions))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->transp_num))
+    goto error;
+  if (!gst_byte_reader_skip (reader, 24))       /* reserved */
+    goto error;
+  /* FLC */
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->oframe1))
+    goto error;
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->oframe2))
+    goto error;
+  if (!gst_byte_reader_skip (reader, 40))       /* reserved */
+    goto error;
+
+  return TRUE;
+
+error:
+  GST_ERROR_OBJECT (flxdec, "Error reading file header");
+  return FALSE;
+}
+
+static GstFlowReturn
+gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstByteReader reader;
+  GstBuffer *input;
+  GstMapInfo map_info;
+  GstCaps *caps;
+  guint available;
+  GstFlowReturn res = GST_FLOW_OK;
+
+  GstFlxDec *flxdec;
+  FlxHeader *flxh;
+
+  g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
+  flxdec = (GstFlxDec *) parent;
+  g_return_val_if_fail (flxdec != NULL, GST_FLOW_ERROR);
+
+  gst_adapter_push (flxdec->adapter, buf);
+  available = gst_adapter_available (flxdec->adapter);
+  input = gst_adapter_get_buffer (flxdec->adapter, available);
+  if (!gst_buffer_map (input, &map_info, GST_MAP_READ)) {
+    GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
+        ("%s", "Failed to map buffer"), (NULL));
+    goto error;
+  }
+  gst_byte_reader_init (&reader, map_info.data, map_info.size);
+
+  if (flxdec->state == GST_FLXDEC_READ_HEADER) {
+    if (available >= FlxHeaderSize) {
+      GstByteReader header;
+      GstCaps *templ;
+
+      if (!gst_byte_reader_get_sub_reader (&reader, &header, FlxHeaderSize)) {
+        GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
+            ("%s", "Could not read header"), (NULL));
+        goto unmap_input_error;
+      }
+      gst_adapter_flush (flxdec->adapter, FlxHeaderSize);
+      available -= FlxHeaderSize;
+
+      if (!_read_flx_header (flxdec, &header, &flxdec->hdr)) {
+        GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
+            ("%s", "Failed to parse header"), (NULL));
+        goto unmap_input_error;
+      }
+
+      flxh = &flxdec->hdr;
+
+      /* check header */
+      if (flxh->type != FLX_MAGICHDR_FLI &&
+          flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX) {
+        GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, (NULL),
+            ("not a flx file (type %x)", flxh->type));
+        goto unmap_input_error;
+      }
+
+      GST_INFO_OBJECT (flxdec, "size      :  %d", flxh->size);
+      GST_INFO_OBJECT (flxdec, "frames    :  %d", flxh->frames);
+      GST_INFO_OBJECT (flxdec, "width     :  %d", flxh->width);
+      GST_INFO_OBJECT (flxdec, "height    :  %d", flxh->height);
+      GST_INFO_OBJECT (flxdec, "depth     :  %d", flxh->depth);
+      GST_INFO_OBJECT (flxdec, "speed     :  %d", flxh->speed);
+
+      flxdec->next_time = 0;
+
+      if (flxh->type == FLX_MAGICHDR_FLI) {
+        flxdec->frame_time = JIFFIE * flxh->speed;
+      } else if (flxh->speed == 0) {
+        flxdec->frame_time = GST_SECOND / 70;
+      } else {
+        flxdec->frame_time = flxh->speed * GST_MSECOND;
+      }
+
+      flxdec->duration = flxh->frames * flxdec->frame_time;
+      GST_LOG ("duration   :  %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (flxdec->duration));
+
+      templ = gst_pad_get_pad_template_caps (flxdec->srcpad);
+      caps = gst_caps_copy (templ);
+      gst_caps_unref (templ);
+      gst_caps_set_simple (caps,
+          "width", G_TYPE_INT, flxh->width,
+          "height", G_TYPE_INT, flxh->height,
+          "framerate", GST_TYPE_FRACTION, (gint) GST_MSECOND,
+          (gint) flxdec->frame_time / 1000, NULL);
+
+      gst_pad_set_caps (flxdec->srcpad, caps);
+      gst_caps_unref (caps);
+
+      if (flxdec->need_segment) {
+        gst_pad_push_event (flxdec->srcpad,
+            gst_event_new_segment (&flxdec->segment));
+        flxdec->need_segment = FALSE;
+      }
+
+      /* zero means 8 */
+      if (flxh->depth == 0)
+        flxh->depth = 8;
+
+      if (flxh->depth != 8) {
+        GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE,
+            ("%s", "Don't know how to decode non 8 bit depth streams"), (NULL));
+        goto unmap_input_error;
+      }
+
+      flxdec->converter =
+          flx_colorspace_converter_new (flxh->width, flxh->height);
+
+      if (flxh->type == FLX_MAGICHDR_FLC || flxh->type == FLX_MAGICHDR_FLX) {
+        GST_INFO_OBJECT (flxdec, "(FLC) aspect_dx :  %d", flxh->aspect_dx);
+        GST_INFO_OBJECT (flxdec, "(FLC) aspect_dy :  %d", flxh->aspect_dy);
+        GST_INFO_OBJECT (flxdec, "(FLC) oframe1   :  0x%08x", flxh->oframe1);
+        GST_INFO_OBJECT (flxdec, "(FLC) oframe2   :  0x%08x", flxh->oframe2);
+      }
+
+      flxdec->size = ((guint) flxh->width * (guint) flxh->height);
+      if (flxdec->size >= G_MAXSIZE / 4) {
+        GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
+            ("%s", "Cannot allocate required memory"), (NULL));
+        goto unmap_input_error;
+      }
+
+      /* create delta and output frame */
+      flxdec->frame_data = g_malloc0 (flxdec->size);
+      flxdec->delta_data = g_malloc0 (flxdec->size);
+
+      flxdec->state = GST_FLXDEC_PLAYING;
+    }
+  } else if (flxdec->state == GST_FLXDEC_PLAYING) {
+    GstBuffer *out;
+
+    /* while we have enough data in the adapter */
+    while (available >= FlxFrameChunkSize && res == GST_FLOW_OK) {
+      guint32 size;
+      guint16 type;
+
+      if (!gst_byte_reader_get_uint32_le (&reader, &size))
+        goto parse_error;
+      if (available < size)
+        goto need_more_data;
+
+      available -= size;
+      gst_adapter_flush (flxdec->adapter, size);
+
+      if (!gst_byte_reader_get_uint16_le (&reader, &type))
+        goto parse_error;
+
+      switch (type) {
+        case FLX_FRAME_TYPE:{
+          GstByteReader chunks;
+          GstByteWriter writer;
+          guint16 n_chunks;
+          GstMapInfo map;
+
+          GST_LOG_OBJECT (flxdec, "Have frame type 0x%02x of size %d", type,
+              size);
+
+          if (!gst_byte_reader_get_sub_reader (&reader, &chunks,
+                  size - FlxFrameChunkSize))
+            goto parse_error;
+
+          if (!gst_byte_reader_get_uint16_le (&chunks, &n_chunks))
+            goto parse_error;
+          GST_LOG_OBJECT (flxdec, "Have %d chunks", n_chunks);
+
+          if (n_chunks == 0)
+            break;
+          if (!gst_byte_reader_skip (&chunks, 8))       /* reserved */
+            goto parse_error;
+
+          gst_byte_writer_init_with_data (&writer, flxdec->frame_data,
+              flxdec->size, TRUE);
+
+          /* decode chunks */
+          if (!flx_decode_chunks (flxdec, n_chunks, &chunks, &writer)) {
+            GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
+                ("%s", "Could not decode chunk"), NULL);
+            goto unmap_input_error;
+          }
+          gst_byte_writer_reset (&writer);
+
+          /* save copy of the current frame for possible delta. */
+          memcpy (flxdec->delta_data, flxdec->frame_data, flxdec->size);
+
+          out = gst_buffer_new_and_alloc (flxdec->size * 4);
+          if (!gst_buffer_map (out, &map, GST_MAP_WRITE)) {
+            GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
+                ("%s", "Could not map output buffer"), NULL);
+            gst_buffer_unref (out);
+            goto unmap_input_error;
+          }
+
+          /* convert current frame. */
+          flx_colorspace_convert (flxdec->converter, flxdec->frame_data,
+              map.data);
+          gst_buffer_unmap (out, &map);
+
+          GST_BUFFER_TIMESTAMP (out) = flxdec->next_time;
+          flxdec->next_time += flxdec->frame_time;
+
+          res = gst_pad_push (flxdec->srcpad, out);
+          break;
+        }
+        default:
+          GST_DEBUG_OBJECT (flxdec, "Unknown frame type 0x%02x, skipping %d",
+              type, size);
+          if (!gst_byte_reader_skip (&reader, size - FlxFrameChunkSize))
+            goto parse_error;
+          break;
+      }
+    }
+  }
+
+need_more_data:
+  gst_buffer_unmap (input, &map_info);
+  gst_buffer_unref (input);
+  return res;
+
+  /* ERRORS */
+parse_error:
+  GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
+      ("%s", "Failed to parse stream"), (NULL));
+unmap_input_error:
+  gst_buffer_unmap (input, &map_info);
+error:
+  gst_buffer_unref (input);
+  return GST_FLOW_ERROR;
+}
+
+static GstStateChangeReturn
+gst_flxdec_change_state (GstElement * element, GstStateChange transition)
+{
+  GstFlxDec *flxdec;
+  GstStateChangeReturn ret;
+
+  flxdec = GST_FLXDEC (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_adapter_clear (flxdec->adapter);
+      flxdec->state = GST_FLXDEC_READ_HEADER;
+      gst_segment_init (&flxdec->segment, GST_FORMAT_UNDEFINED);
+      flxdec->need_segment = TRUE;
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      if (flxdec->frame_data) {
+        g_free (flxdec->frame_data);
+        flxdec->frame_data = NULL;
+      }
+      if (flxdec->delta_data) {
+        g_free (flxdec->delta_data);
+        flxdec->delta_data = NULL;
+      }
+      if (flxdec->converter) {
+        flx_colorspace_converter_destroy (flxdec->converter);
+        flxdec->converter = NULL;
+      }
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "flxdec",
+      GST_RANK_PRIMARY, GST_TYPE_FLXDEC);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    flxdec,
+    "FLC/FLI/FLX video decoder",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/flx/gstflxdec.h b/gst/flx/gstflxdec.h
new file mode 100644
index 0000000..c6486a0
--- /dev/null
+++ b/gst/flx/gstflxdec.h
@@ -0,0 +1,87 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_FLX_DECODER_H__
+#define __GST_FLX_DECODER_H__
+
+#include <gst/gst.h>
+
+#include <gst/base/gstadapter.h>
+#include <gst/base/gstbytereader.h>
+#include <gst/base/gstbytewriter.h>
+#include "flx_color.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+  GST_FLXDEC_READ_HEADER,
+  GST_FLXDEC_PLAYING,
+} GstFlxDecState;
+	
+
+/* Definition of structure storing data for this element. */
+typedef struct _GstFlxDec  GstFlxDec;
+
+struct _GstFlxDec {
+  GstElement element;
+
+  GstPad *sinkpad, *srcpad;
+
+  GstSegment segment;
+  gboolean need_segment;
+
+  gboolean active, new_meta;
+
+  guint8 *delta_data, *frame_data;
+  GstAdapter *adapter;
+  gsize size;
+  GstFlxDecState state;
+  gint64 frame_time;
+  gint64 next_time;
+  gint64 duration;
+
+  FlxColorSpaceConverter *converter;
+
+  FlxHeader hdr;
+};
+
+/* Standard definition defining a class for this element. */
+typedef struct _GstFlxDecClass GstFlxDecClass;
+struct _GstFlxDecClass {
+  GstElementClass parent_class;
+};
+
+/* Standard macros for defining types for this element.  */
+#define GST_TYPE_FLXDEC \
+  (gst_flxdec_get_type())
+#define GST_FLXDEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FLXDEC,GstFlxDec))
+#define GST_FLXDEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FLXDEC,GstFlxDecClass))
+#define GST_IS_FLXDEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLXDEC))
+#define GST_IS_FLXDEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLXDEC))
+
+/* Standard function returning type information. */
+GType gst_flxdec_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_FLX_DECODER_H__ */
diff --git a/gst/flx/meson.build b/gst/flx/meson.build
new file mode 100644
index 0000000..bb7c9f5
--- /dev/null
+++ b/gst/flx/meson.build
@@ -0,0 +1,8 @@
+flxdec = library('gstflxdec',
+  'gstflxdec.c', 'flx_color.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstbase_dep, gstvideo_dep, gst_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/goom/.gitignore b/gst/goom/.gitignore
new file mode 100644
index 0000000..8209050
--- /dev/null
+++ b/gst/goom/.gitignore
@@ -0,0 +1,11 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
+goomsl_lex.c
+goomsl_yacc.c
+goomsl_yacc.h
+
diff --git a/gst/goom/Makefile.am b/gst/goom/Makefile.am
new file mode 100644
index 0000000..7701b10
--- /dev/null
+++ b/gst/goom/Makefile.am
@@ -0,0 +1,46 @@
+
+plugin_LTLIBRARIES = libgstgoom.la
+
+PPC_FILES=ppc_zoom_ultimate.s ppc_drawings.s ppc_drawings.h ppc_zoom_ultimate.h
+MMX_FILES=mmx.c xmmx.c mmx.h xmmx.h
+
+if HAVE_CPU_PPC
+# disable until someone figures out how to build these correctly on ppc
+#ARCH_FILES = $(PPC_FILES)
+ARCH_FILES =
+endif
+if HAVE_CPU_PPC64
+# disable until someone figures out how to build these correctly on ppc
+#ARCH_FILES = $(PPC_FILES)
+ARCH_FILES =
+endif
+if HAVE_CPU_I386
+ARCH_FILES = $(MMX_FILES)
+ARCH_CFLAGS = -DBUILD_MMX
+endif
+				
+libgstgoom_la_SOURCES =						\
+	gstgoom.c gstgoom.h					\
+	drawmethods.c drawmethods.h				\
+	sound_tester.c sound_tester.h				\
+	mathtools.c mathtools.h					\
+	lines.c lines.h ifs.c ifs.h surf3d.c surf3d.h		\
+	tentacle3d.c tentacle3d.h v3d.c v3d.h			\
+	convolve_fx.c flying_stars_fx.c				\
+	goom_fx.h goom_visual_fx.h				\
+	motif_goom1.h motif_goom2.h				\
+	plugin_info.c goom_plugin_info.h			\
+	goom_tools.c						\
+	config_param.c filters.c goom_core.c graphic.c		\
+	goom.h goom_typedefs.h goom_graphic.h			\
+	goom_config_param.h goom_visual_fx.h goom_filters.h	\
+	goom_tools.h goom_tools.h goom_config.h			\
+	$(ARCH_FILES)
+
+libgstgoom_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GOOM_FILTER_CFLAGS) $(ARCH_CFLAGS) $(ORC_CFLAGS)
+libgstgoom_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstpbutils-$(GST_API_VERSION) $(GST_BASE_LIBS) $(GST_LIBS) $(LIBM) $(ORC_LIBS)
+libgstgoom_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+EXTRA_DIST = $(PPC_FILES) $(MMX_FILES)
+
+.NOTPARALLEL:
diff --git a/gst/goom/README b/gst/goom/README
new file mode 100644
index 0000000..08af2ba
--- /dev/null
+++ b/gst/goom/README
@@ -0,0 +1,13 @@
+The Goom plugin is based on the Goom visualization code from
+the Goom homepage found at: 
+http://ios.free.fr/?page=projet&quoi=1 
+
+Like the original library so is the Goom plugin available under the LGPL license
+
+This is based on goom2k4 with changes to plugin_info.c and mmx.h to use Orc for CPU
+detection and GStreamer-specific ifdef's for architecture detection.
+
+These files are not in use right now:
+filters_mmx.s
+goomsl*
+surf3d.s
diff --git a/gst/goom/config_param.c b/gst/goom/config_param.c
new file mode 100644
index 0000000..3a1277f
--- /dev/null
+++ b/gst/goom/config_param.c
@@ -0,0 +1,142 @@
+/* Goom Project
+ * Copyright (C) <2003> Jean-Christophe Hoelt <jeko@free.fr>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "goom_config_param.h"
+#include <string.h>
+
+static void
+empty_fct (PluginParam * dummy)
+{
+}
+
+void
+goom_secure_param (PluginParam * p)
+{
+  p->changed = empty_fct;
+  p->change_listener = empty_fct;
+  p->user_data = 0;
+  p->name = p->desc = 0;
+  p->rw = 1;
+}
+
+void
+goom_secure_f_param (PluginParam * p, const char *name)
+{
+  secure_param (p);
+
+  p->name = name;
+  p->type = PARAM_FLOATVAL;
+  FVAL (*p) = 0.5f;
+  FMIN (*p) = 0.0f;
+  FMAX (*p) = 1.0f;
+  FSTEP (*p) = 0.01f;
+}
+
+void
+goom_secure_f_feedback (PluginParam * p, const char *name)
+{
+  secure_f_param (p, name);
+
+  p->rw = 0;
+}
+
+void
+goom_secure_s_param (PluginParam * p, const char *name)
+{
+  secure_param (p);
+
+  p->name = name;
+  p->type = PARAM_STRVAL;
+  SVAL (*p) = 0;
+}
+
+void
+goom_secure_b_param (PluginParam * p, const char *name, int value)
+{
+  secure_param (p);
+
+  p->name = name;
+  p->type = PARAM_BOOLVAL;
+  BVAL (*p) = value;
+}
+
+void
+goom_secure_i_param (PluginParam * p, const char *name)
+{
+  secure_param (p);
+
+  p->name = name;
+  p->type = PARAM_INTVAL;
+  IVAL (*p) = 50;
+  IMIN (*p) = 0;
+  IMAX (*p) = 100;
+  ISTEP (*p) = 1;
+}
+
+void
+goom_secure_i_feedback (PluginParam * p, const char *name)
+{
+  secure_i_param (p, name);
+
+  p->rw = 0;
+}
+
+void
+goom_plugin_parameters (PluginParameters * p, const char *name, int nb)
+{
+  p->name = name;
+  p->desc = "";
+  p->nbParams = nb;
+  p->params = malloc (nb * sizeof (PluginParam *));
+}
+
+void
+goom_plugin_parameters_free (PluginParameters * p)
+{
+  free (p->params);
+}
+
+/*---------------------------------------------------------------------------*/
+
+void
+goom_set_str_param_value (PluginParam * p, const char *str)
+{
+  int len = strlen (str);
+
+  if (SVAL (*p))
+    SVAL (*p) = (char *) realloc (SVAL (*p), len + 1);
+  else
+    SVAL (*p) = (char *) malloc (len + 1);
+  memcpy (SVAL (*p), str, len + 1);
+}
+
+void
+goom_set_list_param_value (PluginParam * p, const char *str)
+{
+  int len = strlen (str);
+
+#ifdef VERBOSE
+  printf ("%s: %d\n", str, len);
+#endif
+  if (LVAL (*p))
+    LVAL (*p) = (char *) realloc (LVAL (*p), len + 1);
+  else
+    LVAL (*p) = (char *) malloc (len + 1);
+  memcpy (LVAL (*p), str, len + 1);
+}
diff --git a/gst/goom/convolve_fx.c b/gst/goom/convolve_fx.c
new file mode 100644
index 0000000..980e113
--- /dev/null
+++ b/gst/goom/convolve_fx.c
@@ -0,0 +1,368 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "goom_fx.h"
+#include "goom_plugin_info.h"
+#include "goom_config.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+//#define CONV_MOTIF_W 32
+//#define CONV_MOTIF_WMASK 0x1f
+
+/* Define if you like the wacky GOOM logo: */
+#undef DRAW_MOTIF
+
+#define CONV_MOTIF_W 128
+#define CONV_MOTIF_WMASK 0x7f
+
+typedef char Motif[CONV_MOTIF_W][CONV_MOTIF_W];
+
+#include "motif_goom1.h"
+#include "motif_goom2.h"
+
+#define NB_THETA 512
+
+typedef struct _CONV_DATA
+{
+  PluginParam light;
+  PluginParam factor_adj_p;
+  PluginParam factor_p;
+  PluginParameters params;
+
+  /* rotozoom */
+  int theta;
+  float ftheta;
+  int h_sin[NB_THETA];
+  int h_cos[NB_THETA];
+  int h_height;
+  float visibility;
+  Motif conv_motif;
+  int inverse_motif;
+
+} ConvData;
+
+/* init rotozoom tables */
+static void
+compute_tables (VisualFX * _this, PluginInfo * info)
+{
+  ConvData *data = (ConvData *) _this->fx_data;
+  double screen_coef;
+  int i;
+  double h;
+  double radian;
+
+  if (data->h_height == info->screen.height)
+    return;
+
+  screen_coef = 2.0 * 300.0 / (double) info->screen.height;
+  data->h_height = info->screen.height;
+
+  for (i = 0; i < NB_THETA; i++) {
+    radian = 2 * i * G_PI / NB_THETA;
+    h = (0.2 + cos (radian) / 15.0 * sin (radian * 2.0 + 12.123)) * screen_coef;
+    data->h_cos[i] = 0x10000 * (-h * cos (radian) * cos (radian));
+    data->h_sin[i] = 0x10000 * (h * sin (radian + 1.57) * sin (radian));
+  }
+}
+
+static void
+set_motif (ConvData * data, Motif motif)
+{
+  int i, j;
+
+  for (i = 0; i < CONV_MOTIF_W; ++i)
+    for (j = 0; j < CONV_MOTIF_W; ++j)
+      data->conv_motif[i][j] =
+          motif[CONV_MOTIF_W - i - 1][CONV_MOTIF_W - j - 1];
+}
+
+static void
+convolve_init (VisualFX * _this, PluginInfo * info)
+{
+  ConvData *data;
+
+  data = (ConvData *) malloc (sizeof (ConvData));
+  _this->fx_data = (void *) data;
+
+  secure_f_param (&data->light, "Screen Brightness");
+  data->light.param.fval.max = 300.0f;
+  data->light.param.fval.step = 1.0f;
+  data->light.param.fval.value = 100.0f;
+
+  secure_f_param (&data->factor_adj_p, "Flash Intensity");
+  data->factor_adj_p.param.fval.max = 200.0f;
+  data->factor_adj_p.param.fval.step = 1.0f;
+  data->factor_adj_p.param.fval.value = 70.0f;
+
+  secure_f_feedback (&data->factor_p, "Factor");
+
+  plugin_parameters (&data->params, "Bright Flash", 5);
+  data->params.params[0] = &data->light;
+  data->params.params[1] = &data->factor_adj_p;
+  data->params.params[2] = 0;
+  data->params.params[3] = &data->factor_p;
+  data->params.params[4] = 0;
+
+  data->h_height = 0;
+
+  /* init rotozoom tables */
+  compute_tables (_this, info);
+  data->theta = 0;
+  data->ftheta = 0.0;
+  data->visibility = 1.0;
+  set_motif (data, CONV_MOTIF2);
+  data->inverse_motif = 0;
+
+  _this->params = &data->params;
+}
+
+static void
+convolve_free (VisualFX * _this)
+{
+  ConvData *data = (ConvData *) _this->fx_data;
+
+  goom_plugin_parameters_free (&data->params);
+
+  free (_this->fx_data);
+}
+
+#ifdef DRAW_MOTIF
+static void
+create_output_with_brightness (VisualFX * _this, Pixel * src, Pixel * dest,
+    PluginInfo * info, int iff)
+{
+  ConvData *data = (ConvData *) _this->fx_data;
+
+  int x, y;
+  int i = 0;                    //info->screen.height * info->screen.width - 1;
+
+  const int c = data->h_cos[data->theta];
+  const int s = data->h_sin[data->theta];
+
+  const int xi = -(info->screen.width / 2) * c;
+  const int yi = (info->screen.width / 2) * s;
+
+  const int xj = -(info->screen.height / 2) * s;
+  const int yj = -(info->screen.height / 2) * c;
+
+  int xprime = xj;
+  int yprime = yj;
+
+  int ifftab[16];
+
+  if (data->inverse_motif) {
+    int i;
+
+    for (i = 0; i < 16; ++i)
+      ifftab[i] = (double) iff *(1.0 + data->visibility * (15.0 - i) / 15.0);
+  } else {
+    int i;
+
+    for (i = 0; i < 16; ++i)
+      ifftab[i] = (double) iff / (1.0 + data->visibility * (15.0 - i) / 15.0);
+  }
+
+  for (y = info->screen.height; y--;) {
+    int xtex, ytex;
+
+    xtex = xprime + xi + CONV_MOTIF_W * 0x10000 / 2;
+    xprime += s;
+
+    ytex = yprime + yi + CONV_MOTIF_W * 0x10000 / 2;
+    yprime += c;
+
+#ifdef HAVE_MMX
+    __asm__ __volatile__ ("\n\t pxor  %%mm7,  %%mm7"    /* mm7 = 0   */
+        "\n\t movd %[xtex],  %%mm2" "\n\t movd %[ytex],  %%mm3" "\n\t punpckldq %%mm3, %%mm2"   /* mm2 = [ ytex | xtex ] */
+        "\n\t movd %[c],     %%mm4" "\n\t movd %[s],     %%mm6" "\n\t pxor  %%mm5,   %%mm5" "\n\t psubd %%mm6,   %%mm5" "\n\t punpckldq %%mm5, %%mm4"   /* mm4 = [ -s | c ]      */
+        "\n\t movd %[motif], %%mm6"     /* mm6 = motif           */
+        ::[xtex] "g" (xtex),[ytex] "g" (ytex)
+        ,[c] "g" (c),[s] "g" (s)
+        ,[motif] "g" (&data->conv_motif[0][0]));
+
+    for (x = info->screen.width; x--;) {
+      __asm__ __volatile__ ("\n\t movd  %[src], %%mm0"  /* mm0 = src */
+          "\n\t paddd %%mm4, %%mm2"     /* [ ytex | xtex ] += [ -s | s ] */
+          "\n\t movd  %%esi, %%mm5"     /* save esi into mm5 */
+          "\n\t movq  %%mm2, %%mm3" "\n\t psrld  $16,  %%mm3"   /* mm3 = [ (ytex>>16) | (xtex>>16) ] */
+          "\n\t movd  %%mm3, %%eax"     /* eax = xtex' */
+          "\n\t psrlq $25,   %%mm3" "\n\t movd  %%mm3, %%ecx"   /* ecx = ytex' << 7 */
+          "\n\t andl  $127, %%eax" "\n\t andl  $16256, %%ecx" "\n\t addl  %%ecx, %%eax" "\n\t movd  %%mm6, %%esi"       /* esi = motif */
+          "\n\t xorl  %%ecx, %%ecx" "\n\t movb  (%%eax,%%esi), %%cl" "\n\t movl  %[ifftab], %%eax" "\n\t movd  %%mm5, %%esi"    /* restore esi from mm5 */
+          "\n\t movd  (%%eax,%%ecx,4), %%mm1"   /* mm1 = [0|0|0|iff2] */
+          "\n\t punpcklwd %%mm1, %%mm1"
+          "\n\t punpcklbw %%mm7, %%mm0"
+          "\n\t punpckldq %%mm1, %%mm1"
+          "\n\t psrlw     $1,    %%mm0"
+          "\n\t psrlw     $2,    %%mm1"
+          "\n\t pmullw    %%mm1, %%mm0"
+          "\n\t psrlw     $5,    %%mm0"
+          "\n\t packuswb  %%mm7, %%mm0"
+          "\n\t movd      %%mm0, %[dest]":[dest] "=g" (dest[i].val)
+          :[src] "g" (src[i].val)
+          ,[ifftab] "g" (&ifftab[0])
+          :"eax", "ecx");
+
+      i++;
+    }
+#else
+    for (x = info->screen.width; x--;) {
+
+      int iff2;
+      unsigned int f0, f1, f2, f3;
+
+      xtex += c;
+      ytex -= s;
+
+      iff2 =
+          ifftab[(int) data->conv_motif[(ytex >> 16) & CONV_MOTIF_WMASK][(xtex
+                  >> 16) & CONV_MOTIF_WMASK]];
+
+#define sat(a) ((a)>0xFF?0xFF:(a))
+      f0 = src[i].val;
+      f1 = ((f0 >> R_OFFSET) & 0xFF) * iff2 >> 8;
+      f2 = ((f0 >> G_OFFSET) & 0xFF) * iff2 >> 8;
+      f3 = ((f0 >> B_OFFSET) & 0xFF) * iff2 >> 8;
+      dest[i].val =
+          (sat (f1) << R_OFFSET) | (sat (f2) << G_OFFSET) | (sat (f3) <<
+          B_OFFSET);
+/*
+      f0 = (src[i].cop[0] * iff2) >> 8;
+      f1 = (src[i].cop[1] * iff2) >> 8;
+      f2 = (src[i].cop[2] * iff2) >> 8;
+      f3 = (src[i].cop[3] * iff2) >> 8;
+
+      dest[i].cop[0] = (f0 & 0xffffff00) ? 0xff : (unsigned char)f0;
+      dest[i].cop[1] = (f1 & 0xffffff00) ? 0xff : (unsigned char)f1;
+      dest[i].cop[2] = (f2 & 0xffffff00) ? 0xff : (unsigned char)f2;
+      dest[i].cop[3] = (f3 & 0xffffff00) ? 0xff : (unsigned char)f3;
+*/
+      i++;
+    }
+#endif
+  }
+#ifdef HAVE_MMX
+  __asm__ __volatile__ ("\n\t emms");
+#endif
+
+  compute_tables (_this, info);
+}
+#endif
+
+/*#include <stdint.h>
+
+static uint64_t GetTick()
+{
+  uint64_t x;
+  asm volatile ("RDTSC" : "=A" (x));
+  return x;
+}*/
+
+
+static void
+convolve_apply (VisualFX * _this, Pixel * src, Pixel * dest, PluginInfo * info)
+{
+
+  ConvData *data = (ConvData *) _this->fx_data;
+#ifdef DRAW_MOTIF
+  float ff;
+  int iff;
+
+  ff = (FVAL (data->factor_p) * FVAL (data->factor_adj_p) +
+      FVAL (data->light)) / 100.0f;
+  iff = (unsigned int) (ff * 256);
+#endif
+
+  {
+    double fcycle = (double) info->cycle;
+    double rotate_param, rotate_coef;
+    float INCREASE_RATE = 1.5;
+    float DECAY_RATE = 0.955;
+
+    if (FVAL (info->sound.last_goom_p) > 0.8)
+      FVAL (data->factor_p) += FVAL (info->sound.goom_power_p) * INCREASE_RATE;
+    FVAL (data->factor_p) *= DECAY_RATE;
+
+    rotate_param = FVAL (info->sound.last_goom_p);
+    if (rotate_param < 0.0)
+      rotate_param = 0.0;
+    rotate_param += FVAL (info->sound.goom_power_p);
+
+    rotate_coef = 4.0 + FVAL (info->sound.goom_power_p) * 6.0;
+    data->ftheta = (data->ftheta + rotate_coef * sin (rotate_param * 6.3));
+    data->theta = ((unsigned int) data->ftheta) % NB_THETA;
+    data->visibility =
+        (cos (fcycle * 0.001 + 1.5) * sin (fcycle * 0.008) +
+        cos (fcycle * 0.011 + 5.0) - 0.8 + info->sound.speedvar) * 1.5;
+    if (data->visibility < 0.0)
+      data->visibility = 0.0;
+    data->factor_p.change_listener (&data->factor_p);
+  }
+
+  if (data->visibility < 0.01) {
+    switch (goom_irand (info->gRandom, 300)) {
+      case 1:
+        set_motif (data, CONV_MOTIF1);
+        data->inverse_motif = 1;
+        break;
+      case 2:
+        set_motif (data, CONV_MOTIF2);
+        data->inverse_motif = 0;
+        break;
+    }
+  }
+#ifdef DRAW_MOTIF
+  if ((ff > 0.98f) && (ff < 1.02f))
+    memcpy (dest, src, info->screen.size * sizeof (Pixel));
+  else
+    create_output_with_brightness (_this, src, dest, info, iff);
+#else
+  memcpy (dest, src, info->screen.size * sizeof (Pixel));
+#endif
+
+/*
+//   Benching suite...
+   {
+    uint64_t before, after;
+    double   timed;
+    static double stimed = 10000.0;
+    before = GetTick();
+    data->visibility = 1.0;
+    create_output_with_brightness(_this,src,dest,info,iff);
+    after  = GetTick();
+    timed = (double)((after-before) / info->screen.size);
+    if (timed < stimed) {
+      stimed = timed;
+      printf ("CLK = %3.0f CPP\n", stimed);
+    }
+  }
+*/
+}
+
+void
+convolve_create (VisualFX * vfx)
+{
+  vfx->init = convolve_init;
+  vfx->free = convolve_free;
+  vfx->apply = convolve_apply;
+  vfx->fx_data = NULL;
+  vfx->params = NULL;
+}
diff --git a/gst/goom/drawmethods.c b/gst/goom/drawmethods.c
new file mode 100644
index 0000000..97f0cf1
--- /dev/null
+++ b/gst/goom/drawmethods.c
@@ -0,0 +1,222 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "drawmethods.h"
+
+#define DRAWMETHOD_PLUS(_out,_backbuf,_col) \
+{\
+      int tra=0,i=0;\
+      unsigned char *bra = (unsigned char*)&(_backbuf);\
+      unsigned char *dra = (unsigned char*)&(_out);\
+      unsigned char *cra = (unsigned char*)&(_col);\
+      for (;i<4;i++) {\
+				tra = *cra;\
+				tra += *bra;\
+				if (tra>255) tra=255;\
+				*dra = tra;\
+				++dra;++cra;++bra;\
+			}\
+}
+
+#define DRAWMETHOD DRAWMETHOD_PLUS(*p,*p,col)
+
+void
+draw_line (Pixel * data, int x1, int y1, int x2, int y2, int col, int screenx,
+    int screeny)
+{
+  int x, y, dx, dy, yy, xx;
+  Pixel *p;
+
+  if ((y1 < 0) || (y2 < 0) || (x1 < 0) || (x2 < 0) || (y1 >= screeny)
+      || (y2 >= screeny) || (x1 >= screenx) || (x2 >= screenx))
+    return;
+
+  /* clip to top edge 
+     if ((y1 < 0) && (y2 < 0))
+     return;
+
+     if (y1 < 0) {
+     x1 += (y1 * (x1 - x2)) / (y2 - y1);
+     y1 = 0;
+     }
+     if (y2 < 0) {
+     x2 += (y2 * (x1 - x2)) / (y2 - y1);
+     y2 = 0;
+     }
+
+     clip to bottom edge 
+     if ((y1 >= screeny) && (y2 >= screeny))
+     return;
+     if (y1 >= screeny) {
+     x1 -= ((screeny - y1) * (x1 - x2)) / (y2 - y1);
+     y1 = screeny - 1;
+     }
+     if (y2 >= screeny) {
+     x2 -= ((screeny - y2) * (x1 - x2)) / (y2 - y1);
+     y2 = screeny - 1;
+     }
+     clip to left edge 
+     if ((x1 < 0) && (x2 < 0))
+     return;
+     if (x1 < 0) {
+     y1 += (x1 * (y1 - y2)) / (x2 - x1);
+     x1 = 0;
+     }
+     if (x2 < 0) {
+     y2 += (x2 * (y1 - y2)) / (x2 - x1);
+     x2 = 0;
+     }
+     clip to right edge 
+     if ((x1 >= screenx) && (x2 >= screenx))
+     return;
+     if (x1 >= screenx) {
+     y1 -= ((screenx - x1) * (y1 - y2)) / (x2 - x1);
+     x1 = screenx - 1;
+     }
+     if (x2 >= screenx) {
+     y2 -= ((screenx - x2) * (y1 - y2)) / (x2 - x1);
+     x2 = screenx - 1;
+     }
+   */
+
+  dx = x2 - x1;
+  dy = y2 - y1;
+  if (x1 > x2) {
+    int tmp;
+
+    tmp = x1;
+    x1 = x2;
+    x2 = tmp;
+    tmp = y1;
+    y1 = y2;
+    y2 = tmp;
+    dx = x2 - x1;
+    dy = y2 - y1;
+  }
+
+  /* vertical line */
+  if (dx == 0) {
+    if (y1 < y2) {
+      p = &(data[(screenx * y1) + x1]);
+      for (y = y1; y <= y2; y++) {
+        DRAWMETHOD;
+        p += screenx;
+      }
+    } else {
+      p = &(data[(screenx * y2) + x1]);
+      for (y = y2; y <= y1; y++) {
+        DRAWMETHOD;
+        p += screenx;
+      }
+    }
+    return;
+  }
+  /* horizontal line */
+  if (dy == 0) {
+    if (x1 < x2) {
+      p = &(data[(screenx * y1) + x1]);
+      for (x = x1; x <= x2; x++) {
+        DRAWMETHOD;
+        p++;
+      }
+      return;
+    } else {
+      p = &(data[(screenx * y1) + x2]);
+      for (x = x2; x <= x1; x++) {
+        DRAWMETHOD;
+        p++;
+      }
+      return;
+    }
+  }
+  /* 1    */
+  /* \   */
+  /* \  */
+  /* 2 */
+  if (y2 > y1) {
+    /* steep */
+    if (dy > dx) {
+      dx = ((dx << 16) / dy);
+      x = x1 << 16;
+      for (y = y1; y <= y2; y++) {
+        xx = x >> 16;
+        p = &(data[(screenx * y) + xx]);
+        DRAWMETHOD;
+        if (xx < (screenx - 1)) {
+          p++;
+          /* DRAWMETHOD; */
+        }
+        x += dx;
+      }
+      return;
+    }
+    /* shallow */
+    else {
+      dy = ((dy << 16) / dx);
+      y = y1 << 16;
+      for (x = x1; x <= x2; x++) {
+        yy = y >> 16;
+        p = &(data[(screenx * yy) + x]);
+        DRAWMETHOD;
+        if (yy < (screeny - 1)) {
+          p += screeny;
+          /* DRAWMETHOD; */
+        }
+        y += dy;
+      }
+    }
+  }
+  /* 2 */
+  /* /  */
+  /* /   */
+  /* 1    */
+  else {
+    /* steep */
+    if (-dy > dx) {
+      dx = ((dx << 16) / -dy);
+      x = (x1 + 1) << 16;
+      for (y = y1; y >= y2; y--) {
+        xx = x >> 16;
+        p = &(data[(screenx * y) + xx]);
+        DRAWMETHOD;
+        if (xx < (screenx - 1)) {
+          p--;
+          /* DRAWMETHOD; */
+        }
+        x += dx;
+      }
+      return;
+    }
+    /* shallow */
+    else {
+      dy = ((dy << 16) / dx);
+      y = y1 << 16;
+      for (x = x1; x <= x2; x++) {
+        yy = y >> 16;
+        p = &(data[(screenx * yy) + x]);
+        DRAWMETHOD;
+        if (yy < (screeny - 1)) {
+          p += screeny;
+          /* DRAWMETHOD; */
+        }
+        y += dy;
+      }
+      return;
+    }
+  }
+}
diff --git a/gst/goom/drawmethods.h b/gst/goom/drawmethods.h
new file mode 100644
index 0000000..3f86274
--- /dev/null
+++ b/gst/goom/drawmethods.h
@@ -0,0 +1,27 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _DRAWMETHODS_H
+#define _DRAWMETHODS_H
+
+#include "goom_config.h"
+#include "goom_graphic.h"
+
+void draw_line (Pixel *data, int x1, int y1, int x2, int y2, int col, int screenx, int screeny);
+
+#endif /* _DRAWMETHODS_H */
diff --git a/gst/goom/filters.c b/gst/goom/filters.c
new file mode 100644
index 0000000..703d202
--- /dev/null
+++ b/gst/goom/filters.c
@@ -0,0 +1,862 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+// --- CHUI EN TRAIN DE SUPPRIMER LES EXTERN RESOLX ET C_RESOLY ---
+
+/* filter.c version 0.7
+* contient les filtres applicable a un buffer
+* creation : 01/10/2000
+*  -ajout de sinFilter()
+*  -ajout de zoomFilter()
+*  -copie de zoomFilter() en zoomFilterRGB(), gerant les 3 couleurs
+*  -optimisation de sinFilter (utilisant une table de sin)
+*	-asm
+*	-optimisation de la procedure de generation du buffer de transformation
+*		la vitesse est maintenant comprise dans [0..128] au lieu de [0..100]
+*/
+
+/* #define _DEBUG_PIXEL */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "goom_filters.h"
+#include "goom_graphic.h"
+#include "goom_tools.h"
+#include "goom_plugin_info.h"
+#include "goom_fx.h"
+#include "v3d.h"
+
+/* TODO : MOVE THIS AWAY !!! */
+/* jeko: j'ai essayer de le virer, mais si on veut les laisser inline c'est un peu lourdo... */
+static inline void
+setPixelRGB (PluginInfo * goomInfo, Pixel * buffer, Uint x, Uint y, Color c)
+{
+  Pixel i;
+
+  i.channels.b = c.b;
+  i.channels.g = c.v;
+  i.channels.r = c.r;
+  *(buffer + (x + y * goomInfo->screen.width)) = i;
+}
+
+static inline void
+setPixelRGB_ (Pixel * buffer, Uint x, Color c)
+{
+  buffer[x].channels.r = c.r;
+  buffer[x].channels.g = c.v;
+  buffer[x].channels.b = c.b;
+}
+
+static inline void
+getPixelRGB_ (Pixel * buffer, Uint x, Color * c)
+{
+  Pixel i = *(buffer + x);
+
+  c->b = i.channels.b;
+  c->v = i.channels.g;
+  c->r = i.channels.r;
+}
+
+/* END TODO */
+
+
+/* DEPRECATED */
+// retourne x>>s , en testant le signe de x
+//#define ShiftRight(_x,_s) (((_x)<0) ? -(-(_x)>>(_s)) : ((_x)>>(_s)))
+//#define EFFECT_DISTORS 4
+//#define EFFECT_DISTORS_SL 2
+//#define INTERLACE_ADD 9
+//#define INTERLACE_AND 0xf
+/* END DEPRECATED */
+
+#define BUFFPOINTNB 16
+#define BUFFPOINTNBF 16.0f
+#define BUFFPOINTMASK 0xffff
+
+#define sqrtperte 16
+/* faire : a % sqrtperte <=> a & pertemask */
+#define PERTEMASK 0xf
+/* faire : a / sqrtperte <=> a >> PERTEDEC */
+#define PERTEDEC 4
+
+/* pure c version of the zoom filter */
+static void c_zoom (Pixel * expix1, Pixel * expix2, unsigned int prevX,
+    unsigned int prevY, signed int *brutS, signed int *brutD, int buffratio,
+    int precalCoef[BUFFPOINTNB][BUFFPOINTNB]);
+
+/* simple wrapper to give it the same proto than the others */
+void
+zoom_filter_c (int sizeX, int sizeY, Pixel * src, Pixel * dest, int *brutS,
+    int *brutD, int buffratio, int precalCoef[16][16])
+{
+  c_zoom (src, dest, sizeX, sizeY, brutS, brutD, buffratio, precalCoef);
+}
+
+static void generatePrecalCoef (int precalCoef[BUFFPOINTNB][BUFFPOINTNB]);
+
+
+typedef struct _ZOOM_FILTER_FX_WRAPPER_DATA
+{
+
+  PluginParam enabled_bp;
+  PluginParameters params;
+
+  unsigned int *coeffs, *freecoeffs;
+
+  signed int *brutS, *freebrutS;        /* source */
+  signed int *brutD, *freebrutD;        /* dest */
+  signed int *brutT, *freebrutT;        /* temp (en cours de generation) */
+
+  guint32 zoom_width;
+
+  unsigned int prevX, prevY;
+
+  float general_speed;
+  int reverse;                  /* reverse the speed */
+  char theMode;
+  int waveEffect;
+  int hypercosEffect;
+  int vPlaneEffect;
+  int hPlaneEffect;
+  char noisify;
+  int middleX, middleY;
+
+  int mustInitBuffers;
+  int interlace_start;
+
+    /** modif by jeko : fixedpoint : buffration = (16:16) (donc 0<=buffration<=2^16) */
+  int buffratio;
+  int *firedec;
+
+    /** modif d'optim by Jeko : precalcul des 4 coefs resultant des 2 pos */
+  int precalCoef[BUFFPOINTNB][BUFFPOINTNB];
+
+    /** calculatePXandPY statics */
+  int wave;
+  int wavesp;
+
+} ZoomFilterFXWrapperData;
+
+
+
+
+static inline void
+zoomVector (v2g * vecteur, ZoomFilterFXWrapperData * data, float X, float Y)
+{
+  float vx, vy;
+  float sq_dist = X * X + Y * Y;
+
+  /*    sx = (X < 0.0f) ? -1.0f : 1.0f;
+     sy = (Y < 0.0f) ? -1.0f : 1.0f;
+   */
+  float coefVitesse = (1.0f + data->general_speed) / 50.0f;
+
+  // Effects
+
+  /* Centralized FX */
+
+  switch (data->theMode) {
+    case CRYSTAL_BALL_MODE:
+      coefVitesse -= (sq_dist - 0.3f) / 15.0f;
+      break;
+    case AMULETTE_MODE:
+      coefVitesse += sq_dist * 3.5f;
+      break;
+    case WAVE_MODE:
+      coefVitesse += sin (sq_dist * 20.0f) / 100.0f;
+      break;
+    case SCRUNCH_MODE:
+      coefVitesse += sq_dist / 10.0f;
+      break;
+      //case HYPERCOS1_MODE:
+      break;
+      //case HYPERCOS2_MODE:
+      break;
+      //case YONLY_MODE:
+      break;
+    case SPEEDWAY_MODE:
+      coefVitesse *= 4.0f * Y;
+      break;
+    default:
+      break;
+  }
+
+  if (coefVitesse < -2.01f)
+    coefVitesse = -2.01f;
+  if (coefVitesse > 2.01f)
+    coefVitesse = 2.01f;
+
+  vx = coefVitesse * X;
+  vy = coefVitesse * Y;
+
+  /* Amulette 2 */
+  // vx = X * tan(dist);
+  // vy = Y * tan(dist);
+
+  /* Rotate */
+  //vx = (X+Y)*0.1;
+  //vy = (Y-X)*0.1;
+
+
+  // Effects adds-on
+
+  /* Noise */
+  if (data->noisify) {
+    vx += (((float) rand ()) / ((float) RAND_MAX) - 0.5f) / 50.0f;
+    vy += (((float) rand ()) / ((float) RAND_MAX) - 0.5f) / 50.0f;
+  }
+
+  /* Hypercos */
+  if (data->hypercosEffect) {
+    vx += sin (Y * 10.0f) / 120.0f;
+    vy += sin (X * 10.0f) / 120.0f;
+  }
+
+  /* H Plane */
+  if (data->hPlaneEffect)
+    vx += Y * 0.0025f * data->hPlaneEffect;
+
+  /* V Plane */
+  if (data->vPlaneEffect)
+    vy += X * 0.0025f * data->vPlaneEffect;
+
+  /* TODO : Water Mode */
+  //    if (data->waveEffect)
+
+  vecteur->x = vx;
+  vecteur->y = vy;
+}
+
+
+/*
+ * Makes a stripe of a transform buffer (brutT)
+ *
+ * The transform is (in order) :
+ * Translation (-data->middleX, -data->middleY)
+ * Homothetie (Center : 0,0   Coeff : 2/data->prevX)
+ */
+static void
+makeZoomBufferStripe (ZoomFilterFXWrapperData * data, int INTERLACE_INCR)
+{
+  // Position of the pixel to compute in pixmap coordinates
+  Uint x, y;
+
+  // Where (verticaly) to stop generating the buffer stripe
+  int maxEnd;
+
+  // Ratio from pixmap to normalized coordinates
+  float ratio = 2.0f / ((float) data->prevX);
+
+  // Ratio from normalized to virtual pixmap coordinates
+  float inv_ratio = BUFFPOINTNBF / ratio;
+  float min = ratio / BUFFPOINTNBF;
+
+  // Y position of the pixel to compute in normalized coordinates
+  float Y = ((float) (data->interlace_start - data->middleY)) * ratio;
+
+  maxEnd = data->prevY;
+  if (maxEnd > (data->interlace_start + INTERLACE_INCR))
+    maxEnd = (data->interlace_start + INTERLACE_INCR);
+
+  for (y = data->interlace_start;
+      (y < data->prevY) && ((signed int) y < maxEnd); y++) {
+    Uint premul_y_prevX = y * data->prevX * 2;
+    float X = -((float) data->middleX) * ratio;
+
+    for (x = 0; x < data->prevX; x++) {
+      v2g vector;
+
+      zoomVector (&vector, data, X, Y);
+
+      /* Finish and avoid null displacement */
+      if (fabs (vector.x) < min)
+        vector.x = (vector.x < 0.0f) ? -min : min;
+      if (fabs (vector.y) < min)
+        vector.y = (vector.y < 0.0f) ? -min : min;
+
+      data->brutT[premul_y_prevX] =
+          ((int) ((X - vector.x) * inv_ratio) +
+          ((int) (data->middleX * BUFFPOINTNB)));
+      data->brutT[premul_y_prevX + 1] =
+          ((int) ((Y - vector.y) * inv_ratio) +
+          ((int) (data->middleY * BUFFPOINTNB)));
+      premul_y_prevX += 2;
+      X += ratio;
+    }
+    Y += ratio;
+  }
+  data->interlace_start += INTERLACE_INCR;
+  if (y >= data->prevY - 1)
+    data->interlace_start = -1;
+}
+
+
+/*
+ * calculer px et py en fonction de x,y,middleX,middleY et theMode
+ * px et py indique la nouvelle position (en sqrtperte ieme de pixel)
+ * (valeur * 16)
+ 
+ inline void calculatePXandPY (PluginInfo *goomInfo, ZoomFilterFXWrapperData *data, int x, int y, int *px, int *py)
+ {
+     if (data->theMode == WATER_MODE) {
+         int yy;
+         
+         yy = y + goom_irand(goomInfo->gRandom, 4) - goom_irand(goomInfo->gRandom, 4) + data->wave / 10;
+         if (yy < 0)
+             yy = 0;
+         if (yy >= (signed int)goomInfo->screen.height)
+             yy = goomInfo->screen.height - 1;
+         
+         *px = (x << 4) + data->firedec[yy] + (data->wave / 10);
+         *py = (y << 4) + 132 - ((data->vitesse < 131) ? data->vitesse : 130);
+         
+         data->wavesp += goom_irand(goomInfo->gRandom, 3) - goom_irand(goomInfo->gRandom, 3);
+         if (data->wave < -10)
+             data->wavesp += 2;
+         if (data->wave > 10)
+             data->wavesp -= 2;
+         data->wave += (data->wavesp / 10) + goom_irand(goomInfo->gRandom, 3) - goom_irand(goomInfo->gRandom, 3);
+         if (data->wavesp > 100)
+             data->wavesp = (data->wavesp * 9) / 10;
+     }
+     else {
+         int     dist = 0, vx9, vy9;
+         int     vx, vy;
+         int     ppx, ppy;
+         int     fvitesse = data->vitesse << 4;
+         
+         if (data->noisify) {
+             x += goom_irand(goomInfo->gRandom, data->noisify) - goom_irand(goomInfo->gRandom, data->noisify);
+             y += goom_irand(goomInfo->gRandom, data->noisify) - goom_irand(goomInfo->gRandom, data->noisify);
+         }
+         vx = (x - data->middleX) << 9;
+         vy = (y - data->middleY) << 9;
+         
+         if (data->hPlaneEffect)
+             vx += data->hPlaneEffect * (y - data->middleY);
+         
+         if (data->vPlaneEffect)
+             vy += data->vPlaneEffect * (x - data->middleX);
+         
+         if (data->waveEffect) {
+             fvitesse *=
+             1024 +
+             ShiftRight (goomInfo->sintable
+                         [(unsigned short) (dist * 0xffff + EFFECT_DISTORS)], 6);
+             fvitesse /= 1024;
+         }
+         
+         if (data->hypercosEffect) {
+             vx += ShiftRight (goomInfo->sintable[(-vy + dist) & 0xffff], 1);
+             vy += ShiftRight (goomInfo->sintable[(vx + dist) & 0xffff], 1);
+         }
+         
+         vx9 = ShiftRight (vx, 9);
+         vy9 = ShiftRight (vy, 9);
+         dist = vx9 * vx9 + vy9 * vy9;
+         
+         switch (data->theMode) {
+             case WAVE_MODE:
+                 fvitesse *=
+                 1024 +
+                 ShiftRight (goomInfo->sintable
+                             [(unsigned short) (dist * 0xffff * EFFECT_DISTORS)], 6);
+                 fvitesse>>=10;
+                 break;
+             case CRYSTAL_BALL_MODE:
+                 fvitesse += (dist >> (10-EFFECT_DISTORS_SL));
+                 break;
+             case AMULETTE_MODE:
+                 fvitesse -= (dist >> (4 - EFFECT_DISTORS_SL));
+                 break;
+             case SCRUNCH_MODE:
+                 fvitesse -= (dist >> (10 - EFFECT_DISTORS_SL));
+                 break;
+             case HYPERCOS1_MODE:
+                 vx = vx + ShiftRight (goomInfo->sintable[(-vy + dist) & 0xffff], 1);
+                 vy = vy + ShiftRight (goomInfo->sintable[(vx + dist) & 0xffff], 1);
+                 break;
+             case HYPERCOS2_MODE:
+                 vx =
+                 vx + ShiftRight (goomInfo->sintable[(-ShiftRight (vy, 1) + dist) & 0xffff], 0);
+                 vy =
+                     vy + ShiftRight (goomInfo->sintable[(ShiftRight (vx, 1) + dist) & 0xffff], 0);
+                 fvitesse = 128 << 4;
+                 break;
+             case YONLY_MODE:
+                 fvitesse *= 1024 + ShiftRight (goomInfo->sintable[vy & 0xffff], 6);
+                 fvitesse >>= 10;
+                 break;
+             case SPEEDWAY_MODE:
+                 fvitesse -= (ShiftRight(vy,10-EFFECT_DISTORS_SL));
+                 break;
+         }
+         
+         if (fvitesse < -3024)
+             fvitesse = -3024;
+         
+         if (vx < 0)									// pb avec decalage sur nb negatif
+             ppx = -(-(vx * fvitesse) >> 16);
+         // 16 = 9 + 7 (7 = nb chiffre virgule de vitesse * (v = 128 => immobile)
+         //    * * * * * 9 = nb chiffre virgule de vx) 
+         else
+             ppx = ((vx * fvitesse) >> 16);
+         
+         if (vy < 0)
+             ppy = -(-(vy * fvitesse) >> 16);
+         else
+             ppy = ((vy * fvitesse) >> 16);
+         
+         *px = (data->middleX << 4) + ppx;
+         *py = (data->middleY << 4) + ppy;
+     }
+ }
+ */
+
+
+
+static void
+c_zoom (Pixel * expix1, Pixel * expix2, unsigned int prevX, unsigned int prevY,
+    signed int *brutS, signed int *brutD, int buffratio, int precalCoef[16][16])
+{
+  int myPos, myPos2;
+  Color couleur;
+
+  unsigned int ax = (prevX - 1) << PERTEDEC, ay = (prevY - 1) << PERTEDEC;
+
+  int bufsize = prevX * prevY * 2;
+  int bufwidth = prevX;
+
+  expix1[0].val = expix1[prevX - 1].val = expix1[prevX * prevY - 1].val =
+      expix1[prevX * prevY - prevX].val = 0;
+
+  for (myPos = 0; myPos < bufsize; myPos += 2) {
+    Color col1, col2, col3, col4;
+    int c1, c2, c3, c4, px, py;
+    int pos;
+    int coeffs;
+
+    int brutSmypos = brutS[myPos];
+
+    myPos2 = myPos + 1;
+
+    px = brutSmypos + (((brutD[myPos] -
+                brutSmypos) * buffratio) >> BUFFPOINTNB);
+    brutSmypos = brutS[myPos2];
+    py = brutSmypos + (((brutD[myPos2] -
+                brutSmypos) * buffratio) >> BUFFPOINTNB);
+
+    if ((py >= ay) || (px >= ax)) {
+      pos = coeffs = 0;
+    } else {
+      pos = ((px >> PERTEDEC) + prevX * (py >> PERTEDEC));
+      /* coef en modulo 15 */
+      coeffs = precalCoef[px & PERTEMASK][py & PERTEMASK];
+    }
+    getPixelRGB_ (expix1, pos, &col1);
+    getPixelRGB_ (expix1, pos + 1, &col2);
+    getPixelRGB_ (expix1, pos + bufwidth, &col3);
+    getPixelRGB_ (expix1, pos + bufwidth + 1, &col4);
+
+    c1 = coeffs;
+    c2 = (c1 >> 8) & 0xFF;
+    c3 = (c1 >> 16) & 0xFF;
+    c4 = (c1 >> 24) & 0xFF;
+    c1 = c1 & 0xff;
+
+    couleur.r = col1.r * c1 + col2.r * c2 + col3.r * c3 + col4.r * c4;
+    if (couleur.r > 5)
+      couleur.r -= 5;
+    couleur.r >>= 8;
+
+    couleur.v = col1.v * c1 + col2.v * c2 + col3.v * c3 + col4.v * c4;
+    if (couleur.v > 5)
+      couleur.v -= 5;
+    couleur.v >>= 8;
+
+    couleur.b = col1.b * c1 + col2.b * c2 + col3.b * c3 + col4.b * c4;
+    if (couleur.b > 5)
+      couleur.b -= 5;
+    couleur.b >>= 8;
+
+    setPixelRGB_ (expix2, myPos >> 1, couleur);
+  }
+}
+
+/** generate the water fx horizontal direction buffer */
+static void
+generateTheWaterFXHorizontalDirectionBuffer (PluginInfo * goomInfo,
+    ZoomFilterFXWrapperData * data)
+{
+
+  int loopv;
+  int decc = goom_irand (goomInfo->gRandom, 8) - 4;
+  int spdc = goom_irand (goomInfo->gRandom, 8) - 4;
+  int accel = goom_irand (goomInfo->gRandom, 8) - 4;
+
+  for (loopv = data->prevY; loopv != 0;) {
+
+    loopv--;
+    data->firedec[loopv] = decc;
+    decc += spdc / 10;
+    spdc +=
+        goom_irand (goomInfo->gRandom, 3) - goom_irand (goomInfo->gRandom, 3);
+
+    if (decc > 4)
+      spdc -= 1;
+    if (decc < -4)
+      spdc += 1;
+
+    if (spdc > 30)
+      spdc = spdc - goom_irand (goomInfo->gRandom, 3) + accel / 10;
+    if (spdc < -30)
+      spdc = spdc + goom_irand (goomInfo->gRandom, 3) + accel / 10;
+
+    if (decc > 8 && spdc > 1)
+      spdc -= goom_irand (goomInfo->gRandom, 3) - 2;
+
+    if (decc < -8 && spdc < -1)
+      spdc += goom_irand (goomInfo->gRandom, 3) + 2;
+
+    if (decc > 8 || decc < -8)
+      decc = decc * 8 / 9;
+
+    accel +=
+        goom_irand (goomInfo->gRandom, 2) - goom_irand (goomInfo->gRandom, 2);
+    if (accel > 20)
+      accel -= 2;
+    if (accel < -20)
+      accel += 2;
+  }
+}
+
+
+
+/**
+* Main work for the dynamic displacement map.
+ * 
+ * Reads data from pix1, write to pix2.
+ *
+ * Useful datas for this FX are stored in ZoomFilterData.
+ * 
+ * If you think that this is a strange function name, let me say that a long time ago,
+ *  there has been a slow version and a gray-level only one. Then came these function,
+ *  fast and workin in RGB colorspace ! nice but it only was applying a zoom to the image.
+ *  So that is why you have this name, for the nostalgy of the first days of goom
+ *  when it was just a tiny program writen in Turbo Pascal on my i486...
+ */
+void
+zoomFilterFastRGB (PluginInfo * goomInfo, Pixel * pix1, Pixel * pix2,
+    ZoomFilterData * zf, Uint resx, Uint resy, int switchIncr, float switchMult)
+{
+  Uint x, y;
+
+  ZoomFilterFXWrapperData *data =
+      (ZoomFilterFXWrapperData *) goomInfo->zoomFilter_fx.fx_data;
+
+  if (!BVAL (data->enabled_bp))
+    return;
+
+    /** changement de taille **/
+  if ((data->prevX != resx) || (data->prevY != resy)) {
+    data->prevX = resx;
+    data->prevY = resy;
+
+    if (data->brutS)
+      free (data->freebrutS);
+    data->brutS = 0;
+    if (data->brutD)
+      free (data->freebrutD);
+    data->brutD = 0;
+    if (data->brutT)
+      free (data->freebrutT);
+    data->brutT = 0;
+
+    data->middleX = resx / 2;
+    data->middleY = resy / 2;
+    data->mustInitBuffers = 1;
+    if (data->firedec)
+      free (data->firedec);
+    data->firedec = 0;
+  }
+
+  if (data->interlace_start != -2)
+    zf = NULL;
+
+    /** changement de config **/
+  if (zf) {
+    data->reverse = zf->reverse;
+    data->general_speed = (float) (zf->vitesse - 128) / 128.0f;
+    if (data->reverse)
+      data->general_speed = -data->general_speed;
+    data->middleX = zf->middleX;
+    data->middleY = zf->middleY;
+    data->theMode = zf->mode;
+    data->hPlaneEffect = zf->hPlaneEffect;
+    data->vPlaneEffect = zf->vPlaneEffect;
+    data->waveEffect = zf->waveEffect;
+    data->hypercosEffect = zf->hypercosEffect;
+    data->noisify = zf->noisify;
+    data->interlace_start = 0;
+  }
+
+
+  if (data->mustInitBuffers) {
+
+    data->mustInitBuffers = 0;
+    data->freebrutS =
+        (signed int *) calloc (resx * resy * 2 + 128, sizeof (unsigned int));
+    data->brutS =
+        (gint32 *) ((1 + ((uintptr_t) (data->freebrutS)) / 128) * 128);
+
+    data->freebrutD =
+        (signed int *) calloc (resx * resy * 2 + 128, sizeof (unsigned int));
+    data->brutD =
+        (gint32 *) ((1 + ((uintptr_t) (data->freebrutD)) / 128) * 128);
+
+    data->freebrutT =
+        (signed int *) calloc (resx * resy * 2 + 128, sizeof (unsigned int));
+    data->brutT =
+        (gint32 *) ((1 + ((uintptr_t) (data->freebrutT)) / 128) * 128);
+
+    data->buffratio = 0;
+
+    data->firedec = (int *) malloc (data->prevY * sizeof (int));
+    generateTheWaterFXHorizontalDirectionBuffer (goomInfo, data);
+
+    data->interlace_start = 0;
+    makeZoomBufferStripe (data, resy);
+
+    /* Copy the data from temp to dest and source */
+    memcpy (data->brutS, data->brutT, resx * resy * 2 * sizeof (int));
+    memcpy (data->brutD, data->brutT, resx * resy * 2 * sizeof (int));
+  }
+
+  /* generation du buffer de trans */
+  if (data->interlace_start == -1) {
+
+    /* sauvegarde de l'etat actuel dans la nouvelle source
+     * TODO: write that in MMX (has been done in previous version, but did not follow some new fonctionnalities) */
+    y = data->prevX * data->prevY * 2;
+    for (x = 0; x < y; x += 2) {
+      int brutSmypos = data->brutS[x];
+      int x2 = x + 1;
+
+      data->brutS[x] =
+          brutSmypos + (((data->brutD[x] -
+                  brutSmypos) * data->buffratio) >> BUFFPOINTNB);
+      brutSmypos = data->brutS[x2];
+      data->brutS[x2] =
+          brutSmypos + (((data->brutD[x2] -
+                  brutSmypos) * data->buffratio) >> BUFFPOINTNB);
+    }
+    data->buffratio = 0;
+  }
+
+  if (data->interlace_start == -1) {
+    signed int *tmp;
+
+    tmp = data->brutD;
+    data->brutD = data->brutT;
+    data->brutT = tmp;
+    tmp = data->freebrutD;
+    data->freebrutD = data->freebrutT;
+    data->freebrutT = tmp;
+    data->interlace_start = -2;
+  }
+
+  if (data->interlace_start >= 0) {
+    /* creation de la nouvelle destination */
+    makeZoomBufferStripe (data, resy / 16);
+  }
+
+  if (switchIncr != 0) {
+    data->buffratio += switchIncr;
+    if (data->buffratio > BUFFPOINTMASK)
+      data->buffratio = BUFFPOINTMASK;
+  }
+
+  if (switchMult != 1.0f) {
+    data->buffratio = (int) ((float) BUFFPOINTMASK * (1.0f - switchMult) +
+        (float) data->buffratio * switchMult);
+  }
+
+  data->zoom_width = data->prevX;
+
+  goomInfo->methods.zoom_filter (data->prevX, data->prevY, pix1, pix2,
+      data->brutS, data->brutD, data->buffratio, data->precalCoef);
+}
+
+static void
+generatePrecalCoef (int precalCoef[16][16])
+{
+  int coefh, coefv;
+
+  for (coefh = 0; coefh < 16; coefh++) {
+    for (coefv = 0; coefv < 16; coefv++) {
+
+      int i;
+      int diffcoeffh;
+      int diffcoeffv;
+
+      diffcoeffh = sqrtperte - coefh;
+      diffcoeffv = sqrtperte - coefv;
+
+      if (!(coefh || coefv)) {
+        i = 255;
+      } else {
+        Uint i1, i2, i3, i4;
+
+        i1 = diffcoeffh * diffcoeffv;
+        i2 = coefh * diffcoeffv;
+        i3 = diffcoeffh * coefv;
+        i4 = coefh * coefv;
+
+        // TODO: faire mieux...
+        if (i1)
+          i1--;
+        if (i2)
+          i2--;
+        if (i3)
+          i3--;
+        if (i4)
+          i4--;
+
+        i = (i1) | (i2 << 8) | (i3 << 16) | (i4 << 24);
+      }
+      precalCoef[coefh][coefv] = i;
+    }
+  }
+}
+
+/* VisualFX Wrapper */
+
+static void
+zoomFilterVisualFXWrapper_init (struct _VISUAL_FX *_this, PluginInfo * info)
+{
+  ZoomFilterFXWrapperData *data =
+      (ZoomFilterFXWrapperData *) malloc (sizeof (ZoomFilterFXWrapperData));
+
+  data->coeffs = 0;
+  data->freecoeffs = 0;
+  data->brutS = 0;
+  data->freebrutS = 0;
+  data->brutD = 0;
+  data->freebrutD = 0;
+  data->brutT = 0;
+  data->freebrutT = 0;
+  data->prevX = 0;
+  data->prevY = 0;
+
+  data->mustInitBuffers = 1;
+  data->interlace_start = -2;
+
+  data->general_speed = 0.0f;
+  data->reverse = 0;
+  data->theMode = AMULETTE_MODE;
+  data->waveEffect = 0;
+  data->hypercosEffect = 0;
+  data->vPlaneEffect = 0;
+  data->hPlaneEffect = 0;
+  data->noisify = 2;
+
+    /** modif by jeko : fixedpoint : buffration = (16:16) (donc 0<=buffration<=2^16) */
+  data->buffratio = 0;
+  data->firedec = 0;
+
+  data->wave = data->wavesp = 0;
+
+  secure_b_param (&data->enabled_bp, "Enabled", 1);
+
+  plugin_parameters (&data->params, "Zoom Filter", 1);
+  data->params.params[0] = &data->enabled_bp;
+
+  _this->params = &data->params;
+  _this->fx_data = (void *) data;
+
+    /** modif d'optim by Jeko : precalcul des 4 coefs resultant des 2 pos */
+  generatePrecalCoef (data->precalCoef);
+}
+
+static void
+zoomFilterVisualFXWrapper_free (struct _VISUAL_FX *_this)
+{
+  ZoomFilterFXWrapperData *data = (ZoomFilterFXWrapperData *) _this->fx_data;
+
+  if (data->freebrutT)
+    free (data->freebrutT);
+  if (data->freebrutS)
+    free (data->freebrutS);
+  if (data->freebrutD)
+    free (data->freebrutD);
+  if (data->firedec)
+    free (data->firedec);
+
+  goom_plugin_parameters_free (_this->params);
+
+  free (_this->fx_data);
+}
+
+static void
+zoomFilterVisualFXWrapper_apply (struct _VISUAL_FX *_this, Pixel * src,
+    Pixel * dest, PluginInfo * info)
+{
+}
+
+void
+zoomFilterVisualFXWrapper_create (VisualFX * fx)
+{
+  fx->init = zoomFilterVisualFXWrapper_init;
+  fx->free = zoomFilterVisualFXWrapper_free;
+  fx->apply = zoomFilterVisualFXWrapper_apply;
+  fx->params = NULL;
+  fx->fx_data = NULL;
+}
+
+
+/* TODO : MOVE THIS AWAY */
+
+void
+pointFilter (PluginInfo * goomInfo, Pixel * pix1, Color c, float t1, float t2,
+    float t3, float t4, Uint cycle)
+{
+  Uint x = (Uint) ((int) (goomInfo->screen.width / 2)
+      + (int) (t1 * cos ((float) cycle / t3)));
+  Uint y = (Uint) ((int) (goomInfo->screen.height / 2)
+      + (int) (t2 * sin ((float) cycle / t4)));
+
+  if ((x > 1) && (y > 1) && (x < goomInfo->screen.width - 2)
+      && (y < goomInfo->screen.height - 2)) {
+    setPixelRGB (goomInfo, pix1, x + 1, y, c);
+    setPixelRGB (goomInfo, pix1, x, y + 1, c);
+    setPixelRGB (goomInfo, pix1, x + 1, y + 1, WHITE);
+    setPixelRGB (goomInfo, pix1, x + 2, y + 1, c);
+    setPixelRGB (goomInfo, pix1, x + 1, y + 2, c);
+  }
+}
diff --git a/gst/goom/filters_mmx.s b/gst/goom/filters_mmx.s
new file mode 100644
index 0000000..9320d05
--- /dev/null
+++ b/gst/goom/filters_mmx.s
@@ -0,0 +1,216 @@
+; Goom Project
+; Copyright (C) <2001> Jean-Christophe Hoelt <jeko@free.fr>
+;
+; 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., 51 Franklin St, Fifth Floor,
+; Boston, MA 02110-1301, USA.
+;
+;//
+;// history
+;// 07/01/2001 : Changing FEMMS to EMMS : slower... but run on intel machines
+;//	03/01/2001 : WIDTH and HEIGHT are now variable
+;//	28/12/2000 : adding comments to the code, suppress some useless lines
+;//	27/12/2000 : reducing memory access... improving performance by 20%
+;//		coefficients are now on 1 byte
+;//	22/12/2000 : Changing data structure
+;//	16/12/2000 : AT&T version
+;//	14/12/2000 : unrolling loop
+;//	12/12/2000 : 64 bits memory access
+
+
+.data
+
+chaine:
+	.string	"pos = %d\n\0"
+	.long 0x0
+		
+thezero:
+	.long 0x00000000
+	.long 0x00000000
+
+.text
+
+.globl mmx_zoom		;// name of the function to call by C program
+/* .extern coeffs		;// the transformation buffer */
+.extern expix1,expix2 ;// the source and destination buffer
+.extern mmx_zoom_size, zoom_width ;// size of the buffers
+
+.extern brutS,brutD,buffratio,precalCoef,prevX,prevY
+
+#define PERTEMASK 15
+/* faire : a / sqrtperte <=> a >> PERTEDEC*/
+#define PERTEDEC 4
+
+.align 16
+mmx_zoom:
+
+		pushl %ebp
+		movl %esp,%ebp
+		subl $12,%esp
+
+		movl prevX,%eax
+		decl %eax
+		sarl $4,%eax
+		movl %eax,-4(%ebp)
+
+		movl prevY,%eax
+		decl %eax
+		sarl $4,%eax
+		movl %eax,-8(%ebp)
+
+;// initialisation du mm7 � zero
+		movq (thezero), %mm7
+
+movl mmx_zoom_size, %ecx
+decl %ecx
+
+.while:
+	;// esi <- nouvelle position
+	movl brutS, %eax
+	leal (%eax, %ecx, 8),%eax
+
+	movl (%eax),%edx /* = brutS.px (brutSmypos) */
+	movl 4(%eax),%eax /* = brutS.py */
+
+	movl brutD,%ebx
+	leal (%ebx, %ecx, 8),%ebx
+	movl (%ebx),%esi
+	subl %edx, %esi
+	imull buffratio,%esi
+	sarl $16,%esi
+	addl %edx,%esi /* esi = px */
+
+	/* eax contient deja brutS.py = le nouveau brutSmypos*/
+	/* ebx pointe sur brutD[myPos] */
+	movl 4(%ebx),%edi
+	subl %eax,%edi
+	imull buffratio,%edi
+	sarl $16,%edi
+	addl %eax,%edi /* edi = py */
+
+/*		pushl %eax
+		pushl %ebx*/
+/*		popl %ebx
+		popl %eax*/
+		
+	movl %esi,%eax
+	andl $15,%eax /* eax = coefh */
+	movl %edi,%ebx
+	andl $15,%ebx /* ebx = coefv */
+
+	leal 0(,%ebx,4),%ebx
+	sall $6,%eax
+	addl %ebx,%eax
+	movl $precalCoef,%ebx
+/*	movd (%eax,%ebx),%mm6*/ /* mm6 = coeffs */
+
+	cmpl -8(%ebp),%edi
+	jge .then1
+	cmpl -4(%ebp),%esi
+	jge .then1
+
+	sarl $4,%esi
+	sarl $4,%edi
+	imull zoom_width,%edi
+	leal (%esi,%edi),%esi
+	jmp .finsi1
+
+.then1:
+	movl $0,%esi
+.finsi1:
+
+	/** apres ce calcul, %esi = pos, %mm6 = coeffs **/
+/*	pushl %esi
+	pushl $chaine
+	call printf
+	addl $8,%esp*/
+
+	movl expix1,%eax
+
+	;// recuperation des deux premiers pixels dans mm0 et mm1
+/*	movq (%eax,%esi,4), %mm0		/* b1-v1-r1-a1-b2-v2-r2-a2 */
+	movq %mm0, %mm1				/* b1-v1-r1-a1-b2-v2-r2-a2 */
+
+	;// depackage du premier pixel
+	punpcklbw %mm7, %mm0	/* 00-b2-00-v2-00-r2-00-a2 */
+
+	movq %mm6, %mm5			/* ??-??-??-??-c4-c3-c2-c1 */
+	;// depackage du 2ieme pixel
+	punpckhbw %mm7, %mm1	/* 00-b1-00-v1-00-r1-00-a1 */
+
+	;// extraction des coefficients...
+	punpcklbw %mm5, %mm6	/* c4-c4-c3-c3-c2-c2-c1-c1 */
+	movq %mm6, %mm4			/* c4-c4-c3-c3-c2-c2-c1-c1 */
+	movq %mm6, %mm5			/* c4-c4-c3-c3-c2-c2-c1-c1 */
+
+	punpcklbw %mm5, %mm6	/* c2-c2-c2-c2-c1-c1-c1-c1 */
+	punpckhbw %mm5, %mm4	/* c4-c4-c4-c4-c3-c3-c3-c3 */
+
+	movq %mm6, %mm3			/* c2-c2-c2-c2-c1-c1-c1-c1 */
+	punpcklbw %mm7, %mm6	/* 00-c1-00-c1-00-c1-00-c1 */
+	punpckhbw %mm7, %mm3	/* 00-c2-00-c2-00-c2-00-c2 */
+	
+	;// multiplication des pixels par les coefficients
+	pmullw %mm6, %mm0		/* c1*b2-c1*v2-c1*r2-c1*a2 */
+	pmullw %mm3, %mm1		/* c2*b1-c2*v1-c2*r1-c2*a1 */
+	paddw %mm1, %mm0
+	
+	;// ...extraction des 2 derniers coefficients
+	movq %mm4, %mm5			/* c4-c4-c4-c4-c3-c3-c3-c3 */
+	punpcklbw %mm7, %mm4	/* 00-c3-00-c3-00-c3-00-c3 */
+	punpckhbw %mm7, %mm5	/* 00-c4-00-c4-00-c4-00-c4 */
+
+	/* ajouter la longueur de ligne a esi */
+	addl prevX,%esi
+		
+	;// recuperation des 2 derniers pixels
+/*	movq (%eax,%esi,4), %mm1*/
+	movq %mm1, %mm2
+	
+	;// depackage des pixels
+	punpcklbw %mm7, %mm1
+	punpckhbw %mm7, %mm2
+	
+	;// multiplication pas les coeffs
+	pmullw %mm4, %mm1
+	pmullw %mm5, %mm2
+	
+	;// ajout des valeurs obtenues � la valeur finale
+	paddw %mm1, %mm0
+	paddw %mm2, %mm0
+
+	;// division par 256 = 16+16+16+16, puis repackage du pixel final
+	psrlw $8, %mm0
+	packuswb %mm7, %mm0
+	
+	;// passage au suivant
+
+	;// enregistrement du resultat
+	movl expix2,%eax
+/*	movd %mm0,(%eax,%ecx,4)*/
+
+	decl %ecx
+	;// test de fin du tantque
+	cmpl $0, %ecx				;// 400x300
+
+	jz .fin_while
+	jmp .while
+
+.fin_while:
+	emms
+
+	movl %ebp,%esp
+	popl %ebp
+
+	ret                  ;//The End
diff --git a/gst/goom/flying_stars_fx.c b/gst/goom/flying_stars_fx.c
new file mode 100644
index 0000000..de35e72
--- /dev/null
+++ b/gst/goom/flying_stars_fx.c
@@ -0,0 +1,361 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "goom_fx.h"
+#include "goom_plugin_info.h"
+#include "goom_tools.h"
+
+#include "mathtools.h"
+
+/* TODO:-- FAIRE PROPREMENT... BOAH... */
+#define NCOL 15
+
+/*static const int colval[] = {
+0xfdf6f5,
+0xfae4e4,
+0xf7d1d1,
+0xf3b6b5,
+0xefa2a2,
+0xec9190,
+0xea8282,
+0xe87575,
+0xe46060,
+0xe14b4c,
+0xde3b3b,
+0xdc2d2f,
+0xd92726,
+0xd81619,
+0xd50c09,
+0
+};
+*/
+static const int colval[] = {
+  0x1416181a,
+  0x1419181a,
+  0x141f181a,
+  0x1426181a,
+  0x142a181a,
+  0x142f181a,
+  0x1436181a,
+  0x142f1819,
+  0x14261615,
+  0x13201411,
+  0x111a100a,
+  0x0c180508,
+  0x08100304,
+  0x00050101,
+  0x0
+};
+
+
+/* The different modes of the visual FX.
+ * Put this values on fx_mode */
+#define FIREWORKS_FX 0
+#define RAIN_FX 1
+#define FOUNTAIN_FX 2
+#define LAST_FX 3
+
+typedef struct _FS_STAR
+{
+  float x, y;
+  float vx, vy;
+  float ax, ay;
+  float age, vage;
+} Star;
+
+typedef struct _FS_DATA
+{
+
+  int fx_mode;
+  int nbStars;
+
+  int maxStars;
+  Star *stars;
+
+  float min_age;
+  float max_age;
+
+  PluginParam min_age_p;
+  PluginParam max_age_p;
+  PluginParam nbStars_p;
+  PluginParam nbStars_limit_p;
+  PluginParam fx_mode_p;
+
+  PluginParameters params;
+} FSData;
+
+static void
+fs_init (VisualFX * _this, PluginInfo * info)
+{
+
+  FSData *data;
+
+  data = (FSData *) malloc (sizeof (FSData));
+
+  data->fx_mode = FIREWORKS_FX;
+  data->maxStars = 4096;
+  data->stars = (Star *) malloc (data->maxStars * sizeof (Star));
+  data->nbStars = 0;
+
+  secure_i_param (&data->max_age_p, "Fireworks Smallest Bombs");
+  IVAL (data->max_age_p) = 80;
+  IMIN (data->max_age_p) = 0;
+  IMAX (data->max_age_p) = 100;
+  ISTEP (data->max_age_p) = 1;
+
+  secure_i_param (&data->min_age_p, "Fireworks Largest Bombs");
+  IVAL (data->min_age_p) = 99;
+  IMIN (data->min_age_p) = 0;
+  IMAX (data->min_age_p) = 100;
+  ISTEP (data->min_age_p) = 1;
+
+  secure_i_param (&data->nbStars_limit_p, "Max Number of Particules");
+  IVAL (data->nbStars_limit_p) = 512;
+  IMIN (data->nbStars_limit_p) = 0;
+  IMAX (data->nbStars_limit_p) = data->maxStars;
+  ISTEP (data->nbStars_limit_p) = 64;
+
+  secure_i_param (&data->fx_mode_p, "FX Mode");
+  IVAL (data->fx_mode_p) = data->fx_mode;
+  IMIN (data->fx_mode_p) = 1;
+  IMAX (data->fx_mode_p) = 3;
+  ISTEP (data->fx_mode_p) = 1;
+
+  secure_f_feedback (&data->nbStars_p, "Number of Particules (% of Max)");
+
+  plugin_parameters (&data->params, "Particule System", 7);
+  data->params.params[0] = &data->fx_mode_p;
+  data->params.params[1] = &data->nbStars_limit_p;
+  data->params.params[2] = 0;
+  data->params.params[3] = &data->min_age_p;
+  data->params.params[4] = &data->max_age_p;
+  data->params.params[5] = 0;
+  data->params.params[6] = &data->nbStars_p;
+
+  _this->params = &data->params;
+  _this->fx_data = (void *) data;
+}
+
+static void
+fs_free (VisualFX * _this)
+{
+  FSData *data = (FSData *) _this->fx_data;
+
+  goom_plugin_parameters_free (&data->params);
+
+  free (data->stars);
+  free (_this->fx_data);
+}
+
+
+/**
+ * Cree une nouvelle 'bombe', c'est a dire une particule appartenant a une fusee d'artifice.
+ */
+static void
+addABomb (FSData * fs, int mx, int my, float radius, float vage, float gravity,
+    PluginInfo * info)
+{
+
+  int i = fs->nbStars;
+  float ro;
+  int theta;
+
+  if (fs->nbStars >= fs->maxStars)
+    return;
+  fs->nbStars++;
+
+  fs->stars[i].x = mx;
+  fs->stars[i].y = my;
+
+  ro = radius * (float) goom_irand (info->gRandom, 100) / 100.0f;
+  ro *= (float) goom_irand (info->gRandom, 100) / 100.0f + 1.0f;
+  theta = goom_irand (info->gRandom, 256);
+
+  fs->stars[i].vx = ro * cos256[theta];
+  fs->stars[i].vy = -0.2f + ro * sin256[theta];
+
+  fs->stars[i].ax = 0;
+  fs->stars[i].ay = gravity;
+
+  fs->stars[i].age = 0;
+  if (vage < fs->min_age)
+    vage = fs->min_age;
+  fs->stars[i].vage = vage;
+}
+
+
+/**
+ * Met a jour la position et vitesse d'une particule.
+ */
+static void
+updateStar (Star * s)
+{
+  s->x += s->vx;
+  s->y += s->vy;
+  s->vx += s->ax;
+  s->vy += s->ay;
+  s->age += s->vage;
+}
+
+
+/**
+ * Ajoute de nouvelles particules au moment d'un evenement sonore.
+ */
+static void
+fs_sound_event_occured (VisualFX * _this, PluginInfo * info)
+{
+
+  FSData *data = (FSData *) _this->fx_data;
+  int i;
+
+  int max = (int) ((1.0f + info->sound.goomPower) * goom_irand (info->gRandom,
+          150)) + 100;
+  float radius =
+      (1.0f + info->sound.goomPower) * (float) (goom_irand (info->gRandom,
+          150) + 50) / 300;
+  int mx;
+  int my;
+  float vage, gravity = 0.02f;
+
+  switch (data->fx_mode) {
+    case FIREWORKS_FX:
+    {
+      double dx, dy;
+
+      do {
+        mx = goom_irand (info->gRandom, info->screen.width);
+        my = goom_irand (info->gRandom, info->screen.height);
+        dx = (mx - info->screen.width / 2);
+        dy = (my - info->screen.height / 2);
+      } while (dx * dx + dy * dy <
+          (info->screen.height / 2) * (info->screen.height / 2));
+      vage = data->max_age * (1.0f - info->sound.goomPower);
+    }
+      break;
+    case RAIN_FX:
+      mx = goom_irand (info->gRandom, info->screen.width);
+      if (mx > info->screen.width / 2)
+        mx = info->screen.width;
+      else
+        mx = 0;
+      my = -(info->screen.height / 3) - goom_irand (info->gRandom,
+          info->screen.width / 3);
+      radius *= 1.5;
+      vage = 0.002f;
+      break;
+    case FOUNTAIN_FX:
+      my = info->screen.height + 2;
+      vage = 0.001f;
+      radius += 1.0f;
+      mx = info->screen.width / 2;
+      gravity = 0.04f;
+      break;
+    default:
+      return;
+      /* my = i R A N D (info->screen.height); vage = 0.01f; */
+  }
+
+  radius *= info->screen.height / 200.0f;       /* why 200 ? because the FX was developped on 320x200 */
+  max *= info->screen.height / 200.0f;
+
+  if (info->sound.timeSinceLastBigGoom < 1) {
+    radius *= 1.5;
+    max *= 2;
+  }
+  for (i = 0; i < max; ++i)
+    addABomb (data, mx, my, radius, vage, gravity, info);
+}
+
+
+/**
+ * Main methode of the FX.
+ */
+static void
+fs_apply (VisualFX * _this, Pixel * src, Pixel * dest, PluginInfo * info)
+{
+
+  int i;
+  int col;
+  FSData *data = (FSData *) _this->fx_data;
+
+  /* Get the new parameters values */
+  data->min_age = 1.0f - (float) IVAL (data->min_age_p) / 100.0f;
+  data->max_age = 1.0f - (float) IVAL (data->max_age_p) / 100.0f;
+  FVAL (data->nbStars_p) = (float) data->nbStars / (float) data->maxStars;
+  data->nbStars_p.change_listener (&data->nbStars_p);
+  data->maxStars = IVAL (data->nbStars_limit_p);
+  data->fx_mode = IVAL (data->fx_mode_p);
+
+  /* look for events */
+  if (info->sound.timeSinceLastGoom < 1) {
+    fs_sound_event_occured (_this, info);
+    if (goom_irand (info->gRandom, 20) == 1) {
+      IVAL (data->fx_mode_p) = goom_irand (info->gRandom, (LAST_FX * 3));
+      data->fx_mode_p.change_listener (&data->fx_mode_p);
+    }
+  }
+
+  /* update particules */
+  for (i = 0; i < data->nbStars; ++i) {
+    updateStar (&data->stars[i]);
+
+    /* dead particule */
+    if (data->stars[i].age >= NCOL)
+      continue;
+
+    /* choose the color of the particule */
+    col = colval[(int) data->stars[i].age];
+
+    /* draws the particule */
+    info->methods.draw_line (dest, (int) data->stars[i].x,
+        (int) data->stars[i].y,
+        (int) (data->stars[i].x - data->stars[i].vx * 6),
+        (int) (data->stars[i].y - data->stars[i].vy * 6), col,
+        (int) info->screen.width, (int) info->screen.height);
+    info->methods.draw_line (dest, (int) data->stars[i].x,
+        (int) data->stars[i].y,
+        (int) (data->stars[i].x - data->stars[i].vx * 2),
+        (int) (data->stars[i].y - data->stars[i].vy * 2), col,
+        (int) info->screen.width, (int) info->screen.height);
+  }
+
+  /* look for dead particules */
+  for (i = 0; i < data->nbStars;) {
+
+    if ((data->stars[i].x > info->screen.width + 64)
+        || ((data->stars[i].vy >= 0)
+            && (data->stars[i].y - 16 * data->stars[i].vy >
+                info->screen.height))
+        || (data->stars[i].x < -64)
+        || (data->stars[i].age >= NCOL)) {
+      data->stars[i] = data->stars[data->nbStars - 1];
+      data->nbStars--;
+    } else
+      ++i;
+  }
+}
+
+void
+flying_star_create (VisualFX * vfx)
+{
+  vfx->init = fs_init;
+  vfx->free = fs_free;
+  vfx->apply = fs_apply;
+  vfx->fx_data = NULL;
+  vfx->params = NULL;
+}
diff --git a/gst/goom/goom.h b/gst/goom/goom.h
new file mode 100644
index 0000000..02a0936
--- /dev/null
+++ b/gst/goom/goom.h
@@ -0,0 +1,42 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _GOOMCORE_H
+#define _GOOMCORE_H
+
+#include "goom_config.h"
+#include "goom_plugin_info.h"
+
+#define NB_FX 10
+
+PluginInfo *goom_init (guint32 resx, guint32 resy);
+void goom_set_resolution (PluginInfo *goomInfo, guint32 resx, guint32 resy);
+
+/*
+ * forceMode == 0 : do nothing
+ * forceMode == -1 : lock the FX
+ * forceMode == 1..NB_FX : force a switch to FX n# forceMode
+ */
+guint32 *goom_update (PluginInfo *goomInfo, gint16 data[2][512], int forceMode, float fps);
+
+/* returns 0 if the buffer wasn't accepted */
+int goom_set_screenbuffer(PluginInfo *goomInfo, void *buffer);
+
+void goom_close (PluginInfo *goomInfo);
+
+#endif
diff --git a/gst/goom/goom_config.h b/gst/goom/goom_config.h
new file mode 100644
index 0000000..7264bfe
--- /dev/null
+++ b/gst/goom/goom_config.h
@@ -0,0 +1,45 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <glib.h>
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+#define COLOR_ARGB
+#else
+#define COLOR_BGRA
+#endif
+
+#if 1
+/* ndef COLOR_BGRA */
+/** position des composantes **/
+    #define BLEU 0
+    #define VERT 1
+    #define ROUGE 2
+    #define ALPHA 3
+#else
+    #define ROUGE 1
+    #define BLEU 3
+    #define VERT 2
+    #define ALPHA 0
+#endif
+
+#if defined (BUILD_MMX) && defined (HAVE_GCC_ASM)
+
+#define HAVE_MMX
+#endif
+
diff --git a/gst/goom/goom_config_param.h b/gst/goom/goom_config_param.h
new file mode 100644
index 0000000..ba08da9
--- /dev/null
+++ b/gst/goom/goom_config_param.h
@@ -0,0 +1,134 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _CONFIG_PARAM_H
+#define _CONFIG_PARAM_H
+
+#include <stdlib.h>
+
+/*
+ * File created on 2003-05-24 by Jeko.
+ * (c)2003, JC Hoelt for iOS-software.
+ *
+ * LGPL Licence.
+ */
+
+typedef enum {
+  PARAM_INTVAL,
+  PARAM_FLOATVAL,
+  PARAM_BOOLVAL,
+  PARAM_STRVAL,
+  PARAM_LISTVAL,
+} ParamType;
+
+struct IntVal {
+  int value;
+  int min;
+  int max;
+  int step;
+};
+struct FloatVal {
+  float value;
+  float min;
+  float max;
+  float step;
+};
+struct StrVal {
+  char *value;
+};
+struct ListVal {
+  char *value;
+  int nbChoices;
+  char **choices;
+};
+struct BoolVal {
+  int value;
+};
+
+
+typedef struct _PARAM {
+  const char *name;
+  const char *desc;
+  char rw;
+  ParamType type;
+  union {
+    struct IntVal ival;
+    struct FloatVal fval;
+    struct StrVal sval;
+    struct ListVal slist;
+    struct BoolVal bval;
+  } param;
+  
+  /* used by the core to inform the GUI of a change */
+  void (*change_listener)(struct _PARAM *_this);
+
+  /* used by the GUI to inform the core of a change */
+  void (*changed)(struct _PARAM *_this);
+  
+  void *user_data; /* can be used by the GUI */
+} PluginParam;
+
+#define IVAL(p) ((p).param.ival.value)
+#define SVAL(p) ((p).param.sval.value)
+#define FVAL(p) ((p).param.fval.value)
+#define BVAL(p) ((p).param.bval.value)
+#define LVAL(p) ((p).param.slist.value)
+
+#define FMIN(p) ((p).param.fval.min)
+#define FMAX(p) ((p).param.fval.max)
+#define FSTEP(p) ((p).param.fval.step)
+
+#define IMIN(p) ((p).param.ival.min)
+#define IMAX(p) ((p).param.ival.max)
+#define ISTEP(p) ((p).param.ival.step)
+
+void goom_secure_param(PluginParam *p);
+
+void goom_secure_f_param(PluginParam *p, const char *name);
+void goom_secure_i_param(PluginParam *p, const char *name);
+void goom_secure_b_param(PluginParam *p, const char *name, int value);
+void goom_secure_s_param(PluginParam *p, const char *name);
+
+void goom_secure_f_feedback(PluginParam *p, const char *name);
+void goom_secure_i_feedback(PluginParam *p, const char *name);
+
+void goom_set_str_param_value(PluginParam *p, const char *str);
+void goom_set_list_param_value(PluginParam *p, const char *str);
+    
+typedef struct _PARAMETERS {
+  const char *name;
+  const char *desc;
+  int nbParams;
+  PluginParam **params;
+} PluginParameters;
+
+void goom_plugin_parameters(PluginParameters *p, const char *name, int nb);
+void goom_plugin_parameters_free(PluginParameters *p);
+
+#define secure_param goom_secure_param
+#define secure_f_param goom_secure_f_param
+#define secure_i_param goom_secure_i_param
+#define secure_b_param goom_secure_b_param
+#define secure_s_param goom_secure_s_param
+#define secure_f_feedback goom_secure_f_feedback
+#define secure_i_feedback goom_secure_i_feedback
+#define set_list_param_value goom_set_list_param_value
+#define set_str_param_value goom_set_str_param_value
+#define plugin_parameters goom_plugin_parameters
+
+#endif
diff --git a/gst/goom/goom_core.c b/gst/goom/goom_core.c
new file mode 100644
index 0000000..5b1d4f7
--- /dev/null
+++ b/gst/goom/goom_core.c
@@ -0,0 +1,856 @@
+/* Goom Project
+ * Copyright (C) <2003> Jean-Christophe Hoelt <jeko@free.fr>
+ *
+ * goom_core.c:Contains the core of goom's work.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "goom.h"
+#include "goom_tools.h"
+#include "goom_filters.h"
+#include "lines.h"
+#include "ifs.h"
+#include "tentacle3d.h"
+
+#include "sound_tester.h"
+#include "goom_plugin_info.h"
+#include "goom_fx.h"
+
+/* #define VERBOSE */
+
+#define STOP_SPEED 128
+/* TODO: put that as variable in PluginInfo */
+#define TIME_BTW_CHG 300
+
+static void choose_a_goom_line (PluginInfo * goomInfo, float *param1,
+    float *param2, int *couleur, int *mode, float *amplitude, int far);
+
+static void
+init_buffers (PluginInfo * goomInfo, int buffsize)
+{
+  goomInfo->pixel = (guint32 *) malloc (buffsize * sizeof (guint32) + 128);
+  memset (goomInfo->pixel, 0, buffsize * sizeof (guint32) + 128);
+  goomInfo->back = (guint32 *) malloc (buffsize * sizeof (guint32) + 128);
+  memset (goomInfo->back, 0, buffsize * sizeof (guint32) + 128);
+  goomInfo->conv = (Pixel *) malloc (buffsize * sizeof (guint32) + 128);
+  memset (goomInfo->conv, 0, buffsize * sizeof (guint32) + 128);
+
+  goomInfo->outputBuf = goomInfo->conv;
+
+  goomInfo->p1 = (Pixel *) ((1 + ((uintptr_t) (goomInfo->pixel)) / 128) * 128);
+  goomInfo->p2 = (Pixel *) ((1 + ((uintptr_t) (goomInfo->back)) / 128) * 128);
+}
+
+/**************************
+*         INIT           *
+**************************/
+PluginInfo *
+goom_init (guint32 resx, guint32 resy)
+{
+  PluginInfo *goomInfo = (PluginInfo *) malloc (sizeof (PluginInfo));
+
+#ifdef VERBOSE
+  printf ("GOOM: init (%d, %d);\n", resx, resy);
+#endif
+
+  plugin_info_init (goomInfo, 4);
+
+  goomInfo->screen.width = resx;
+  goomInfo->screen.height = resy;
+  goomInfo->screen.size = resx * resy;
+
+  init_buffers (goomInfo, goomInfo->screen.size);
+  goomInfo->gRandom = goom_random_init ((uintptr_t) goomInfo->pixel);
+
+  goomInfo->cycle = 0;
+
+  flying_star_create (&goomInfo->star_fx);
+  goomInfo->star_fx.init (&goomInfo->star_fx, goomInfo);
+
+  zoomFilterVisualFXWrapper_create (&goomInfo->zoomFilter_fx);
+  goomInfo->zoomFilter_fx.init (&goomInfo->zoomFilter_fx, goomInfo);
+
+  tentacle_fx_create (&goomInfo->tentacles_fx);
+  goomInfo->tentacles_fx.init (&goomInfo->tentacles_fx, goomInfo);
+
+  convolve_create (&goomInfo->convolve_fx);
+  goomInfo->convolve_fx.init (&goomInfo->convolve_fx, goomInfo);
+
+  plugin_info_add_visual (goomInfo, 0, &goomInfo->zoomFilter_fx);
+  plugin_info_add_visual (goomInfo, 1, &goomInfo->tentacles_fx);
+  plugin_info_add_visual (goomInfo, 2, &goomInfo->star_fx);
+  plugin_info_add_visual (goomInfo, 3, &goomInfo->convolve_fx);
+
+  ifs_visualfx_create (&goomInfo->ifs_fx);
+  goomInfo->ifs_fx.init (&goomInfo->ifs_fx, goomInfo);
+
+  goomInfo->gmline1 = goom_lines_init (goomInfo, resx, goomInfo->screen.height,
+      GML_HLINE, goomInfo->screen.height, GML_BLACK,
+      GML_CIRCLE, 0.4f * (float) goomInfo->screen.height, GML_VERT);
+  goomInfo->gmline2 = goom_lines_init (goomInfo, resx, goomInfo->screen.height,
+      GML_HLINE, 0, GML_BLACK,
+      GML_CIRCLE, 0.2f * (float) goomInfo->screen.height, GML_RED);
+
+  /* goom_set_main_script(goomInfo, goomInfo->main_script_str); */
+
+  return goomInfo;
+}
+
+
+
+void
+goom_set_resolution (PluginInfo * goomInfo, guint32 resx, guint32 resy)
+{
+  free (goomInfo->pixel);
+  free (goomInfo->back);
+  free (goomInfo->conv);
+
+  goomInfo->screen.width = resx;
+  goomInfo->screen.height = resy;
+  goomInfo->screen.size = resx * resy;
+
+  init_buffers (goomInfo, goomInfo->screen.size);
+
+  /* init_ifs (goomInfo, resx, goomInfo->screen.height); */
+  goomInfo->ifs_fx.free (&goomInfo->ifs_fx);
+  goomInfo->ifs_fx.init (&goomInfo->ifs_fx, goomInfo);
+
+  goom_lines_set_res (goomInfo->gmline1, resx, goomInfo->screen.height);
+  goom_lines_set_res (goomInfo->gmline2, resx, goomInfo->screen.height);
+}
+
+int
+goom_set_screenbuffer (PluginInfo * goomInfo, void *buffer)
+{
+  goomInfo->outputBuf = (Pixel *) buffer;
+  return 1;
+}
+
+/********************************************
+*                  UPDATE                  *
+********************************************
+
+* WARNING: this is a 600 lines function ! (21-11-2003)
+*/
+guint32 *
+goom_update (PluginInfo * goomInfo, gint16 data[2][512], int forceMode,
+    float fps)
+{
+  Pixel *return_val;
+  guint32 pointWidth;
+  guint32 pointHeight;
+  int i;
+  float largfactor;             /* elargissement de l'intervalle d'�volution des points */
+  Pixel *tmp;
+
+  ZoomFilterData *pzfd;
+
+  /* test if the config has changed, update it if so */
+  pointWidth = (goomInfo->screen.width * 2) / 5;
+  pointHeight = ((goomInfo->screen.height) * 2) / 5;
+
+  /* ! etude du signal ... */
+  evaluate_sound (data, &(goomInfo->sound));
+
+  /* goom_execute_main_script(goomInfo); */
+
+  /* ! calcul du deplacement des petits points ... */
+  largfactor =
+      goomInfo->sound.speedvar / 150.0f + goomInfo->sound.volume / 1.5f;
+
+  if (largfactor > 1.5f)
+    largfactor = 1.5f;
+
+  goomInfo->update.decay_ifs--;
+  if (goomInfo->update.decay_ifs > 0)
+    goomInfo->update.ifs_incr += 2;
+  if (goomInfo->update.decay_ifs == 0)
+    goomInfo->update.ifs_incr = 0;
+
+  if (goomInfo->update.recay_ifs) {
+    goomInfo->update.ifs_incr -= 2;
+    goomInfo->update.recay_ifs--;
+    if ((goomInfo->update.recay_ifs == 0) && (goomInfo->update.ifs_incr <= 0))
+      goomInfo->update.ifs_incr = 1;
+  }
+
+  if (goomInfo->update.ifs_incr > 0)
+    goomInfo->ifs_fx.apply (&goomInfo->ifs_fx, goomInfo->p2, goomInfo->p1,
+        goomInfo);
+
+  if (goomInfo->curGState->drawPoints) {
+    for (i = 1; i * 15 <= goomInfo->sound.speedvar * 80.0f + 15; i++) {
+      goomInfo->update.loopvar += goomInfo->sound.speedvar * 50 + 1;
+
+      pointFilter (goomInfo, goomInfo->p1,
+          YELLOW,
+          ((pointWidth - 6.0f) * largfactor + 5.0f),
+          ((pointHeight - 6.0f) * largfactor + 5.0f),
+          i * 152.0f, 128.0f, goomInfo->update.loopvar + i * 2032);
+      pointFilter (goomInfo, goomInfo->p1, ORANGE,
+          ((pointWidth / 2) * largfactor) / i + 10.0f * i,
+          ((pointHeight / 2) * largfactor) / i + 10.0f * i,
+          96.0f, i * 80.0f, goomInfo->update.loopvar / i);
+      pointFilter (goomInfo, goomInfo->p1, VIOLET,
+          ((pointHeight / 3 + 5.0f) * largfactor) / i + 10.0f * i,
+          ((pointHeight / 3 + 5.0f) * largfactor) / i + 10.0f * i,
+          i + 122.0f, 134.0f, goomInfo->update.loopvar / i);
+      pointFilter (goomInfo, goomInfo->p1, BLACK,
+          ((pointHeight / 3) * largfactor + 20.0f),
+          ((pointHeight / 3) * largfactor + 20.0f),
+          58.0f, i * 66.0f, goomInfo->update.loopvar / i);
+      pointFilter (goomInfo, goomInfo->p1, WHITE,
+          (pointHeight * largfactor + 10.0f * i) / i,
+          (pointHeight * largfactor + 10.0f * i) / i,
+          66.0f, 74.0f, goomInfo->update.loopvar + i * 500);
+    }
+  }
+
+  /* par d�faut pas de changement de zoom */
+  pzfd = NULL;
+
+  /* 
+   * Test forceMode
+   */
+#ifdef VERBOSE
+  if (forceMode != 0) {
+    printf ("forcemode = %d\n", forceMode);
+  }
+#endif
+
+
+  /* diminuer de 1 le temps de lockage */
+  /* note pour ceux qui n'ont pas suivis : le lockvar permet d'empecher un */
+  /* changement d'etat du plugin juste apres un autre changement d'etat. oki */
+  if (--goomInfo->update.lockvar < 0)
+    goomInfo->update.lockvar = 0;
+
+  /* on verifie qu'il ne se pas un truc interressant avec le son. */
+  if ((goomInfo->sound.timeSinceLastGoom == 0)
+      || (forceMode > 0)
+      || (goomInfo->update.cyclesSinceLastChange > TIME_BTW_CHG)) {
+
+    /* changement eventuel de mode */
+    if (goom_irand (goomInfo->gRandom, 16) == 0)
+      switch (goom_irand (goomInfo->gRandom, 34)) {
+        case 0:
+        case 10:
+          goomInfo->update.zoomFilterData.hypercosEffect =
+              goom_irand (goomInfo->gRandom, 2);
+        case 13:
+        case 20:
+        case 21:
+          goomInfo->update.zoomFilterData.mode = WAVE_MODE;
+          goomInfo->update.zoomFilterData.reverse = 0;
+          goomInfo->update.zoomFilterData.waveEffect =
+              (goom_irand (goomInfo->gRandom, 3) == 0);
+          if (goom_irand (goomInfo->gRandom, 2))
+            goomInfo->update.zoomFilterData.vitesse =
+                (goomInfo->update.zoomFilterData.vitesse + 127) >> 1;
+          break;
+        case 1:
+        case 11:
+          goomInfo->update.zoomFilterData.mode = CRYSTAL_BALL_MODE;
+          goomInfo->update.zoomFilterData.waveEffect = 0;
+          goomInfo->update.zoomFilterData.hypercosEffect = 0;
+          break;
+        case 2:
+        case 12:
+          goomInfo->update.zoomFilterData.mode = AMULETTE_MODE;
+          goomInfo->update.zoomFilterData.waveEffect = 0;
+          goomInfo->update.zoomFilterData.hypercosEffect = 0;
+          break;
+        case 3:
+          goomInfo->update.zoomFilterData.mode = WATER_MODE;
+          goomInfo->update.zoomFilterData.waveEffect = 0;
+          goomInfo->update.zoomFilterData.hypercosEffect = 0;
+          break;
+        case 4:
+        case 14:
+          goomInfo->update.zoomFilterData.mode = SCRUNCH_MODE;
+          goomInfo->update.zoomFilterData.waveEffect = 0;
+          goomInfo->update.zoomFilterData.hypercosEffect = 0;
+          break;
+        case 5:
+        case 15:
+        case 22:
+          goomInfo->update.zoomFilterData.mode = HYPERCOS1_MODE;
+          goomInfo->update.zoomFilterData.waveEffect = 0;
+          goomInfo->update.zoomFilterData.hypercosEffect =
+              (goom_irand (goomInfo->gRandom, 3) == 0);
+          break;
+        case 6:
+        case 16:
+          goomInfo->update.zoomFilterData.mode = HYPERCOS2_MODE;
+          goomInfo->update.zoomFilterData.waveEffect = 0;
+          goomInfo->update.zoomFilterData.hypercosEffect = 0;
+          break;
+        case 7:
+        case 17:
+          goomInfo->update.zoomFilterData.mode = CRYSTAL_BALL_MODE;
+          goomInfo->update.zoomFilterData.waveEffect =
+              (goom_irand (goomInfo->gRandom, 4) == 0);
+          goomInfo->update.zoomFilterData.hypercosEffect =
+              goom_irand (goomInfo->gRandom, 2);
+          break;
+        case 8:
+        case 18:
+        case 19:
+          goomInfo->update.zoomFilterData.mode = SCRUNCH_MODE;
+          goomInfo->update.zoomFilterData.waveEffect = 1;
+          goomInfo->update.zoomFilterData.hypercosEffect = 1;
+          break;
+        case 29:
+        case 30:
+          goomInfo->update.zoomFilterData.mode = YONLY_MODE;
+          break;
+        case 31:
+        case 32:
+        case 33:
+          goomInfo->update.zoomFilterData.mode = SPEEDWAY_MODE;
+          break;
+        default:
+          goomInfo->update.zoomFilterData.mode = NORMAL_MODE;
+          goomInfo->update.zoomFilterData.waveEffect = 0;
+          goomInfo->update.zoomFilterData.hypercosEffect = 0;
+      }
+  }
+
+  /* tout ceci ne sera fait qu'en cas de non-blocage */
+  if (goomInfo->update.lockvar == 0) {
+    /* reperage de goom (acceleration forte de l'acceleration du volume) */
+    /* -> coup de boost de la vitesse si besoin.. */
+    if (goomInfo->sound.timeSinceLastGoom == 0) {
+
+      int i;
+
+      goomInfo->update.goomvar++;
+
+      /* SELECTION OF THE GOOM STATE */
+      if ((!goomInfo->update.stateSelectionBlocker)
+          && (goom_irand (goomInfo->gRandom, 3))) {
+        goomInfo->update.stateSelectionRnd =
+            goom_irand (goomInfo->gRandom, goomInfo->statesRangeMax);
+        goomInfo->update.stateSelectionBlocker = 3;
+      } else if (goomInfo->update.stateSelectionBlocker)
+        goomInfo->update.stateSelectionBlocker--;
+
+      for (i = 0; i < goomInfo->statesNumber; i++)
+        if ((goomInfo->update.stateSelectionRnd >= goomInfo->states[i].rangemin)
+            && (goomInfo->update.stateSelectionRnd <=
+                goomInfo->states[i].rangemax))
+          goomInfo->curGState = &(goomInfo->states[i]);
+
+      if ((goomInfo->curGState->drawIFS) && (goomInfo->update.ifs_incr <= 0)) {
+        goomInfo->update.recay_ifs = 5;
+        goomInfo->update.ifs_incr = 11;
+      }
+
+      if ((!goomInfo->curGState->drawIFS) && (goomInfo->update.ifs_incr > 0)
+          && (goomInfo->update.decay_ifs <= 0))
+        goomInfo->update.decay_ifs = 100;
+
+      if (!goomInfo->curGState->drawScope)
+        goomInfo->update.stop_lines = 0xf000 & 5;
+
+      if (!goomInfo->curGState->drawScope) {
+        goomInfo->update.stop_lines = 0;
+        goomInfo->update.lineMode = goomInfo->update.drawLinesDuration;
+      }
+
+      /* if (goomInfo->update.goomvar % 1 == 0) */
+      {
+        guint32 vtmp;
+        guint32 newvit;
+
+        goomInfo->update.lockvar = 50;
+        newvit =
+            STOP_SPEED + 1 -
+            ((float) 3.5f * log10 (goomInfo->sound.speedvar * 60 + 1));
+        /* retablir le zoom avant.. */
+        if ((goomInfo->update.zoomFilterData.reverse)
+            && (!(goomInfo->cycle % 13)) && (rand () % 5 == 0)) {
+          goomInfo->update.zoomFilterData.reverse = 0;
+          goomInfo->update.zoomFilterData.vitesse = STOP_SPEED - 2;
+          goomInfo->update.lockvar = 75;
+        }
+        if (goom_irand (goomInfo->gRandom, 10) == 0) {
+          goomInfo->update.zoomFilterData.reverse = 1;
+          goomInfo->update.lockvar = 100;
+        }
+
+        if (goom_irand (goomInfo->gRandom, 10) == 0)
+          goomInfo->update.zoomFilterData.vitesse = STOP_SPEED - 1;
+        if (goom_irand (goomInfo->gRandom, 12) == 0)
+          goomInfo->update.zoomFilterData.vitesse = STOP_SPEED + 1;
+
+        /* changement de milieu.. */
+        switch (goom_irand (goomInfo->gRandom, 25)) {
+          case 0:
+          case 3:
+          case 6:
+            goomInfo->update.zoomFilterData.middleY =
+                goomInfo->screen.height - 1;
+            goomInfo->update.zoomFilterData.middleX =
+                goomInfo->screen.width / 2;
+            break;
+          case 1:
+          case 4:
+            goomInfo->update.zoomFilterData.middleX =
+                goomInfo->screen.width - 1;
+            break;
+          case 2:
+          case 5:
+            goomInfo->update.zoomFilterData.middleX = 1;
+            break;
+          default:
+            goomInfo->update.zoomFilterData.middleY =
+                goomInfo->screen.height / 2;
+            goomInfo->update.zoomFilterData.middleX =
+                goomInfo->screen.width / 2;
+        }
+
+        if ((goomInfo->update.zoomFilterData.mode == WATER_MODE)
+            || (goomInfo->update.zoomFilterData.mode == YONLY_MODE)
+            || (goomInfo->update.zoomFilterData.mode == AMULETTE_MODE)) {
+          goomInfo->update.zoomFilterData.middleX = goomInfo->screen.width / 2;
+          goomInfo->update.zoomFilterData.middleY = goomInfo->screen.height / 2;
+        }
+
+        switch (vtmp = (goom_irand (goomInfo->gRandom, 15))) {
+          case 0:
+            goomInfo->update.zoomFilterData.vPlaneEffect =
+                goom_irand (goomInfo->gRandom, 3)
+                - goom_irand (goomInfo->gRandom, 3);
+            goomInfo->update.zoomFilterData.hPlaneEffect =
+                goom_irand (goomInfo->gRandom, 3)
+                - goom_irand (goomInfo->gRandom, 3);
+            break;
+          case 3:
+            goomInfo->update.zoomFilterData.vPlaneEffect = 0;
+            goomInfo->update.zoomFilterData.hPlaneEffect =
+                goom_irand (goomInfo->gRandom, 8)
+                - goom_irand (goomInfo->gRandom, 8);
+            break;
+          case 4:
+          case 5:
+          case 6:
+          case 7:
+            goomInfo->update.zoomFilterData.vPlaneEffect =
+                goom_irand (goomInfo->gRandom, 5)
+                - goom_irand (goomInfo->gRandom, 5);
+            goomInfo->update.zoomFilterData.hPlaneEffect =
+                -goomInfo->update.zoomFilterData.vPlaneEffect;
+            break;
+          case 8:
+            goomInfo->update.zoomFilterData.hPlaneEffect =
+                5 + goom_irand (goomInfo->gRandom, 8);
+            goomInfo->update.zoomFilterData.vPlaneEffect =
+                -goomInfo->update.zoomFilterData.hPlaneEffect;
+            break;
+          case 9:
+            goomInfo->update.zoomFilterData.vPlaneEffect =
+                5 + goom_irand (goomInfo->gRandom, 8);
+            goomInfo->update.zoomFilterData.hPlaneEffect =
+                -goomInfo->update.zoomFilterData.hPlaneEffect;
+            break;
+          case 13:
+            goomInfo->update.zoomFilterData.hPlaneEffect = 0;
+            goomInfo->update.zoomFilterData.vPlaneEffect =
+                goom_irand (goomInfo->gRandom, 10)
+                - goom_irand (goomInfo->gRandom, 10);
+            break;
+          case 14:
+            goomInfo->update.zoomFilterData.hPlaneEffect =
+                goom_irand (goomInfo->gRandom, 10)
+                - goom_irand (goomInfo->gRandom, 10);
+            goomInfo->update.zoomFilterData.vPlaneEffect =
+                goom_irand (goomInfo->gRandom, 10)
+                - goom_irand (goomInfo->gRandom, 10);
+            break;
+          default:
+            if (vtmp < 10) {
+              goomInfo->update.zoomFilterData.vPlaneEffect = 0;
+              goomInfo->update.zoomFilterData.hPlaneEffect = 0;
+            }
+        }
+
+        if (goom_irand (goomInfo->gRandom, 5) != 0)
+          goomInfo->update.zoomFilterData.noisify = 0;
+        else {
+          goomInfo->update.zoomFilterData.noisify =
+              goom_irand (goomInfo->gRandom, 2) + 1;
+          goomInfo->update.lockvar *= 2;
+        }
+
+        if (goomInfo->update.zoomFilterData.mode == AMULETTE_MODE) {
+          goomInfo->update.zoomFilterData.vPlaneEffect = 0;
+          goomInfo->update.zoomFilterData.hPlaneEffect = 0;
+          goomInfo->update.zoomFilterData.noisify = 0;
+        }
+
+        if ((goomInfo->update.zoomFilterData.middleX == 1)
+            || (goomInfo->update.zoomFilterData.middleX ==
+                (signed int) goomInfo->screen.width - 1)) {
+          goomInfo->update.zoomFilterData.vPlaneEffect = 0;
+          if (goom_irand (goomInfo->gRandom, 2))
+            goomInfo->update.zoomFilterData.hPlaneEffect = 0;
+        }
+
+        if ((signed int) newvit < goomInfo->update.zoomFilterData.vitesse) {    /* on accelere */
+          pzfd = &goomInfo->update.zoomFilterData;
+          if (((newvit < STOP_SPEED - 7) &&
+                  (goomInfo->update.zoomFilterData.vitesse < STOP_SPEED - 6) &&
+                  (goomInfo->cycle % 3 == 0))
+              || (goom_irand (goomInfo->gRandom, 40) == 0)) {
+            goomInfo->update.zoomFilterData.vitesse =
+                STOP_SPEED - goom_irand (goomInfo->gRandom, 2)
+                + goom_irand (goomInfo->gRandom, 2);
+            goomInfo->update.zoomFilterData.reverse =
+                !goomInfo->update.zoomFilterData.reverse;
+          } else {
+            goomInfo->update.zoomFilterData.vitesse =
+                (newvit + goomInfo->update.zoomFilterData.vitesse * 7) / 8;
+          }
+          goomInfo->update.lockvar += 50;
+        }
+      }
+
+      if (goomInfo->update.lockvar > 150) {
+        goomInfo->update.switchIncr = goomInfo->update.switchIncrAmount;
+        goomInfo->update.switchMult = 1.0f;
+      }
+    }
+    /* mode mega-lent */
+    if (goom_irand (goomInfo->gRandom, 700) == 0) {
+      /* 
+       * printf ("coup du sort...\n") ;
+       */
+      pzfd = &goomInfo->update.zoomFilterData;
+      goomInfo->update.zoomFilterData.vitesse = STOP_SPEED - 1;
+      goomInfo->update.zoomFilterData.pertedec = 8;
+      goomInfo->update.zoomFilterData.sqrtperte = 16;
+      goomInfo->update.goomvar = 1;
+      goomInfo->update.lockvar += 50;
+      goomInfo->update.switchIncr = goomInfo->update.switchIncrAmount;
+      goomInfo->update.switchMult = 1.0f;
+    }
+  }
+
+  /*
+   * gros frein si la musique est calme
+   */
+  if ((goomInfo->sound.speedvar < 0.01f)
+      && (goomInfo->update.zoomFilterData.vitesse < STOP_SPEED - 4)
+      && (goomInfo->cycle % 16 == 0)) {
+    pzfd = &goomInfo->update.zoomFilterData;
+    goomInfo->update.zoomFilterData.vitesse += 3;
+    goomInfo->update.zoomFilterData.pertedec = 8;
+    goomInfo->update.zoomFilterData.sqrtperte = 16;
+    goomInfo->update.goomvar = 0;
+  }
+
+  /*
+   * baisser regulierement la vitesse...
+   */
+  if ((goomInfo->cycle % 73 == 0)
+      && (goomInfo->update.zoomFilterData.vitesse < STOP_SPEED - 5)) {
+    pzfd = &goomInfo->update.zoomFilterData;
+    goomInfo->update.zoomFilterData.vitesse++;
+  }
+
+  /*
+   * arreter de decr�menter au bout d'un certain temps
+   */
+  if ((goomInfo->cycle % 101 == 0)
+      && (goomInfo->update.zoomFilterData.pertedec == 7)) {
+    pzfd = &goomInfo->update.zoomFilterData;
+    goomInfo->update.zoomFilterData.pertedec = 8;
+    goomInfo->update.zoomFilterData.sqrtperte = 16;
+  }
+
+  /*
+   * Permet de forcer un effet.
+   */
+  if ((forceMode > 0) && (forceMode <= NB_FX)) {
+    pzfd = &goomInfo->update.zoomFilterData;
+    pzfd->mode = forceMode - 1;
+  }
+
+  if (forceMode == -1) {
+    pzfd = NULL;
+  }
+
+  /*
+   * Changement d'effet de zoom !
+   */
+  if (pzfd != NULL) {
+    int dif;
+
+    goomInfo->update.cyclesSinceLastChange = 0;
+
+    goomInfo->update.switchIncr = goomInfo->update.switchIncrAmount;
+
+    dif =
+        goomInfo->update.zoomFilterData.vitesse -
+        goomInfo->update.previousZoomSpeed;
+    if (dif < 0)
+      dif = -dif;
+
+    if (dif > 2) {
+      goomInfo->update.switchIncr *= (dif + 2) / 2;
+    }
+    goomInfo->update.previousZoomSpeed =
+        goomInfo->update.zoomFilterData.vitesse;
+    goomInfo->update.switchMult = 1.0f;
+
+    if (((goomInfo->sound.timeSinceLastGoom == 0)
+            && (goomInfo->sound.totalgoom < 2)) || (forceMode > 0)) {
+      goomInfo->update.switchIncr = 0;
+      goomInfo->update.switchMult = goomInfo->update.switchMultAmount;
+    }
+  } else {
+    if (goomInfo->update.cyclesSinceLastChange > TIME_BTW_CHG) {
+      pzfd = &goomInfo->update.zoomFilterData;
+      goomInfo->update.cyclesSinceLastChange = 0;
+    } else
+      goomInfo->update.cyclesSinceLastChange++;
+  }
+
+#ifdef VERBOSE
+  if (pzfd) {
+    printf ("GOOM: pzfd->mode = %d\n", pzfd->mode);
+  }
+#endif
+
+  /* Zoom here ! */
+  zoomFilterFastRGB (goomInfo, goomInfo->p1, goomInfo->p2, pzfd,
+      goomInfo->screen.width, goomInfo->screen.height,
+      goomInfo->update.switchIncr, goomInfo->update.switchMult);
+
+  /*
+   * Affichage tentacule
+   */
+
+  goomInfo->tentacles_fx.apply (&goomInfo->tentacles_fx, goomInfo->p1,
+      goomInfo->p2, goomInfo);
+  goomInfo->star_fx.apply (&goomInfo->star_fx, goomInfo->p2, goomInfo->p1,
+      goomInfo);
+
+  /*
+   * Gestion du Scope
+   */
+
+  /*
+   * arret demande
+   */
+  if ((goomInfo->update.stop_lines & 0xf000)
+      || (!goomInfo->curGState->drawScope)) {
+    float param1 = 0, param2 = 0, amplitude;
+    int couleur;
+    int mode;
+
+    choose_a_goom_line (goomInfo, &param1, &param2, &couleur, &mode, &amplitude,
+        1);
+    couleur = GML_BLACK;
+
+    goom_lines_switch_to (goomInfo->gmline1, mode, param1, amplitude, couleur);
+    goom_lines_switch_to (goomInfo->gmline2, mode, param2, amplitude, couleur);
+    goomInfo->update.stop_lines &= 0x0fff;
+  }
+
+  /*
+   * arret aleatore.. changement de mode de ligne..
+   */
+  if (goomInfo->update.lineMode != goomInfo->update.drawLinesDuration) {
+    goomInfo->update.lineMode--;
+    if (goomInfo->update.lineMode == -1)
+      goomInfo->update.lineMode = 0;
+  } else if ((goomInfo->cycle % 80 == 0)
+      && (goom_irand (goomInfo->gRandom, 5) == 0) && goomInfo->update.lineMode)
+    goomInfo->update.lineMode--;
+
+  if ((goomInfo->cycle % 120 == 0)
+      && (goom_irand (goomInfo->gRandom, 4) == 0)
+      && (goomInfo->curGState->drawScope)) {
+    if (goomInfo->update.lineMode == 0)
+      goomInfo->update.lineMode = goomInfo->update.drawLinesDuration;
+    else if (goomInfo->update.lineMode == goomInfo->update.drawLinesDuration) {
+      float param1, param2, amplitude;
+      int couleur1, couleur2;
+      int mode;
+
+      goomInfo->update.lineMode--;
+      choose_a_goom_line (goomInfo, &param1, &param2, &couleur1,
+          &mode, &amplitude, goomInfo->update.stop_lines);
+
+      couleur2 = 5 - couleur1;
+      if (goomInfo->update.stop_lines) {
+        goomInfo->update.stop_lines--;
+        if (goom_irand (goomInfo->gRandom, 2))
+          couleur2 = couleur1 = GML_BLACK;
+      }
+
+      goom_lines_switch_to (goomInfo->gmline1, mode, param1, amplitude,
+          couleur1);
+      goom_lines_switch_to (goomInfo->gmline2, mode, param2, amplitude,
+          couleur2);
+    }
+  }
+
+  /*
+   * si on est dans un goom : afficher les lignes...
+   */
+  if ((goomInfo->update.lineMode != 0)
+      || (goomInfo->sound.timeSinceLastGoom < 5)) {
+    goomInfo->gmline2->power = goomInfo->gmline1->power;
+
+    goom_lines_draw (goomInfo, goomInfo->gmline1, data[0], goomInfo->p2);
+    goom_lines_draw (goomInfo, goomInfo->gmline2, data[1], goomInfo->p2);
+
+    if (((goomInfo->cycle % 121) == 9)
+        && (goom_irand (goomInfo->gRandom, 3) == 1)
+        && ((goomInfo->update.lineMode == 0)
+            || (goomInfo->update.lineMode ==
+                goomInfo->update.drawLinesDuration))) {
+      float param1, param2, amplitude;
+      int couleur1, couleur2;
+      int mode;
+
+      choose_a_goom_line (goomInfo, &param1, &param2, &couleur1,
+          &mode, &amplitude, goomInfo->update.stop_lines);
+      couleur2 = 5 - couleur1;
+
+      if (goomInfo->update.stop_lines) {
+        goomInfo->update.stop_lines--;
+        if (goom_irand (goomInfo->gRandom, 2))
+          couleur2 = couleur1 = GML_BLACK;
+      }
+      goom_lines_switch_to (goomInfo->gmline1, mode, param1, amplitude,
+          couleur1);
+      goom_lines_switch_to (goomInfo->gmline2, mode, param2, amplitude,
+          couleur2);
+    }
+  }
+
+  return_val = goomInfo->p1;
+  tmp = goomInfo->p1;
+  goomInfo->p1 = goomInfo->p2;
+  goomInfo->p2 = tmp;
+
+  /* affichage et swappage des buffers.. */
+  goomInfo->cycle++;
+
+  goomInfo->convolve_fx.apply (&goomInfo->convolve_fx, return_val,
+      goomInfo->outputBuf, goomInfo);
+
+  return (guint32 *) goomInfo->outputBuf;
+}
+
+/****************************************
+*                CLOSE                 *
+****************************************/
+void
+goom_close (PluginInfo * goomInfo)
+{
+  if (goomInfo->pixel != NULL)
+    free (goomInfo->pixel);
+  if (goomInfo->back != NULL)
+    free (goomInfo->back);
+  if (goomInfo->conv != NULL)
+    free (goomInfo->conv);
+
+  goomInfo->pixel = goomInfo->back = NULL;
+  goomInfo->conv = NULL;
+  goom_random_free (goomInfo->gRandom);
+  goom_lines_free (&goomInfo->gmline1);
+  goom_lines_free (&goomInfo->gmline2);
+
+  /* release_ifs (); */
+  goomInfo->ifs_fx.free (&goomInfo->ifs_fx);
+  goomInfo->convolve_fx.free (&goomInfo->convolve_fx);
+  goomInfo->star_fx.free (&goomInfo->star_fx);
+  goomInfo->tentacles_fx.free (&goomInfo->tentacles_fx);
+  goomInfo->zoomFilter_fx.free (&goomInfo->zoomFilter_fx);
+
+  plugin_info_free (goomInfo);
+  free (goomInfo);
+}
+
+
+/* *** */
+void
+choose_a_goom_line (PluginInfo * goomInfo, float *param1, float *param2,
+    int *couleur, int *mode, float *amplitude, int far)
+{
+  *mode = goom_irand (goomInfo->gRandom, 3);
+  *amplitude = 1.0f;
+  switch (*mode) {
+    case GML_CIRCLE:
+      if (far) {
+        *param1 = *param2 = 0.47f;
+        *amplitude = 0.8f;
+        break;
+      }
+      if (goom_irand (goomInfo->gRandom, 3) == 0) {
+        *param1 = *param2 = 0;
+        *amplitude = 3.0f;
+      } else if (goom_irand (goomInfo->gRandom, 2)) {
+        *param1 = 0.40f * goomInfo->screen.height;
+        *param2 = 0.22f * goomInfo->screen.height;
+      } else {
+        *param1 = *param2 = goomInfo->screen.height * 0.35;
+      }
+      break;
+    case GML_HLINE:
+      if (goom_irand (goomInfo->gRandom, 4) || far) {
+        *param1 = goomInfo->screen.height / 7;
+        *param2 = 6.0f * goomInfo->screen.height / 7.0f;
+      } else {
+        *param1 = *param2 = goomInfo->screen.height / 2.0f;
+        *amplitude = 2.0f;
+      }
+      break;
+    case GML_VLINE:
+      if (goom_irand (goomInfo->gRandom, 3) || far) {
+        *param1 = goomInfo->screen.width / 7.0f;
+        *param2 = 6.0f * goomInfo->screen.width / 7.0f;
+      } else {
+        *param1 = *param2 = goomInfo->screen.width / 2.0f;
+        *amplitude = 1.5f;
+      }
+      break;
+    default:
+      *param1 = *param2 = 0;
+      break;
+  }
+
+  *couleur = goom_irand (goomInfo->gRandom, 6);
+}
diff --git a/gst/goom/goom_filters.h b/gst/goom/goom_filters.h
new file mode 100644
index 0000000..13096e2
--- /dev/null
+++ b/gst/goom/goom_filters.h
@@ -0,0 +1,70 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef FILTERS_H
+#define FILTERS_H
+
+#include "goom_config.h"
+#include "goom_typedefs.h"
+#include "goom_visual_fx.h"
+#include "goom_graphic.h"
+
+void zoomFilterVisualFXWrapper_create(VisualFX *fx);
+
+struct _ZOOM_FILTER_DATA
+{
+	int     vitesse;           /* 128 = vitesse nule... * * 256 = en arriere 
+	                            * hyper vite.. * * 0 = en avant hype vite. */
+	unsigned char pertedec;
+	unsigned char sqrtperte;
+	int     middleX, middleY;  /* milieu de l'effet */
+	char    reverse;           /* inverse la vitesse */
+	char    mode;              /* type d'effet � appliquer (cf les #define) */
+	/** @since June 2001 */
+	int     hPlaneEffect;      /* deviation horitontale */
+	int     vPlaneEffect;      /* deviation verticale */
+	/** @since April 2002 */
+	int     waveEffect;        /* applique une "surcouche" de wave effect */
+	int     hypercosEffect;    /* applique une "surcouche de hypercos effect */
+
+	char    noisify;           /* ajoute un bruit a la transformation */
+};
+
+#define NORMAL_MODE 0
+#define WAVE_MODE 1
+#define CRYSTAL_BALL_MODE 2
+#define SCRUNCH_MODE 3
+#define AMULETTE_MODE 4
+#define WATER_MODE 5
+#define HYPERCOS1_MODE 6
+#define HYPERCOS2_MODE 7
+#define YONLY_MODE 8
+#define SPEEDWAY_MODE 9
+
+void pointFilter (PluginInfo *goomInfo, Pixel * pix1, Color c,
+                  float t1, float t2, float t3, float t4, guint32 cycle);
+
+/* filtre de zoom :
+ * le contenu de pix1 est copie dans pix2.
+ * zf : si non NULL, configure l'effet.
+ * resx,resy : taille des buffers.
+ */
+void zoomFilterFastRGB (PluginInfo *goomInfo, Pixel * pix1, Pixel * pix2, ZoomFilterData * zf, guint32 resx,
+                        guint32 resy, int switchIncr, float switchMult);
+
+#endif
diff --git a/gst/goom/goom_fx.h b/gst/goom/goom_fx.h
new file mode 100644
index 0000000..7c82d6c
--- /dev/null
+++ b/gst/goom/goom_fx.h
@@ -0,0 +1,30 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _GOOM_FX_H
+#define _GOOM_FX_H
+
+#include "goom_visual_fx.h"
+#include "goom_plugin_info.h"
+
+void convolve_create (VisualFX *vfx);
+void flying_star_create (VisualFX *vfx);
+
+void zoom_filter_c(int sizeX, int sizeY, Pixel *src, Pixel *dest, int *brutS, int *brutD, int buffratio, int precalCoef[16][16]);
+
+#endif
diff --git a/gst/goom/goom_graphic.h b/gst/goom/goom_graphic.h
new file mode 100644
index 0000000..54dde37
--- /dev/null
+++ b/gst/goom/goom_graphic.h
@@ -0,0 +1,92 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef GRAPHIC_H
+#define GRAPHIC_H
+
+typedef unsigned int Uint;
+
+typedef struct
+{
+  unsigned short r, v, b;
+}
+Color;
+
+extern const Color BLACK;
+extern const Color WHITE;
+extern const Color RED;
+extern const Color BLUE;
+extern const Color GREEN;
+extern const Color YELLOW;
+extern const Color ORANGE;
+extern const Color VIOLET;
+
+
+#ifdef COLOR_BGRA
+
+#define B_CHANNEL 0xFF000000
+#define G_CHANNEL 0x00FF0000
+#define R_CHANNEL 0x0000FF00
+#define A_CHANNEL 0x000000FF
+#define B_OFFSET  24
+#define G_OFFSET  16
+#define R_OFFSET  8
+#define A_OFFSET  0
+
+typedef union _PIXEL {
+  struct {
+    unsigned char b;
+    unsigned char g;
+    unsigned char r;
+    unsigned char a;
+  } channels;
+  unsigned int val;
+  unsigned char cop[4];
+} Pixel;
+
+#else
+
+#define A_CHANNEL 0xFF000000
+#define R_CHANNEL 0x00FF0000
+#define G_CHANNEL 0x0000FF00
+#define B_CHANNEL 0x000000FF
+#define A_OFFSET  24
+#define R_OFFSET  16
+#define G_OFFSET  8
+#define B_OFFSET  0
+
+typedef union _PIXEL {
+  struct {
+    unsigned char a;
+    unsigned char r;
+    unsigned char g;
+    unsigned char b;
+  } channels;
+  unsigned int val;
+  unsigned char cop[4];
+} Pixel;
+
+#endif /* COLOR_BGRA */
+
+/*
+inline void setPixelRGB (Pixel * buffer, Uint x, Uint y, Color c);
+inline void getPixelRGB (Pixel * buffer, Uint x, Uint y, Color * c);
+*/
+
+
+#endif /* GRAPHIC_H */
diff --git a/gst/goom/goom_plugin_info.h b/gst/goom/goom_plugin_info.h
new file mode 100644
index 0000000..da0e96e
--- /dev/null
+++ b/gst/goom/goom_plugin_info.h
@@ -0,0 +1,181 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _PLUGIN_INFO_H
+#define _PLUGIN_INFO_H
+
+#include "goom_typedefs.h"
+
+#include "goom_config.h"
+
+#include "goom_graphic.h"
+#include "goom_config_param.h"
+#include "goom_visual_fx.h"
+#include "goom_filters.h"
+#include "goom_tools.h"
+
+typedef struct {
+	char drawIFS;
+	char drawPoints;
+	char drawTentacle;
+
+	char drawScope;
+	int farScope;
+
+	int rangemin;
+	int rangemax;
+} GoomState;
+
+#define STATES_MAX_NB 128
+
+/**
+ * Gives informations about the sound.
+ */
+struct _SOUND_INFO {
+
+	/* nota : a Goom is just a sound event... */
+
+	int timeSinceLastGoom;   /* >= 0 */
+	float goomPower;         /* power of the last Goom [0..1] */
+
+	int timeSinceLastBigGoom;   /* >= 0 */
+
+	float volume;     /* [0..1] */
+	short samples[2][512];
+
+	/* other "internal" datas for the sound_tester */
+	float goom_limit; /* auto-updated limit of goom_detection */
+	float bigGoomLimit;
+	float accelvar;   /* acceleration of the sound - [0..1] */
+	float speedvar;   /* speed of the sound - [0..100] */
+	int allTimesMax;
+	int totalgoom;    /* number of goom since last reset
+			   * (a reset every 64 cycles) */
+
+	float prov_max;   /* accel max since last reset */
+
+	int cycle;
+
+	/* private */
+	PluginParam volume_p;
+	PluginParam speed_p;
+	PluginParam accel_p;
+	PluginParam goom_limit_p;
+        PluginParam goom_power_p;
+	PluginParam last_goom_p;
+	PluginParam last_biggoom_p;
+	PluginParam biggoom_speed_limit_p;
+	PluginParam biggoom_factor_p;
+
+	PluginParameters params; /* contains the previously defined parameters. */
+};
+
+
+/**
+ * Allows FXs to know the current state of the plugin.
+ */
+struct _PLUGIN_INFO {
+
+	/* public datas */
+
+	int nbParams;
+	PluginParameters *params;
+
+	/* private datas */
+
+	struct _SIZE_TYPE {
+		int width;
+		int height;
+		int size;   /* == screen.height * screen.width. */
+	} screen;
+
+	SoundInfo sound;
+
+	int nbVisuals;
+	VisualFX **visuals; /* pointers on all the visual fx */
+
+	/** The known FX */
+	VisualFX convolve_fx;
+	VisualFX star_fx;
+	VisualFX zoomFilter_fx;
+	VisualFX tentacles_fx;
+	VisualFX ifs_fx;
+
+	/** image buffers */
+	guint32 *pixel;
+	guint32 *back;
+	Pixel *p1, *p2;
+	Pixel *conv;
+  Pixel *outputBuf;
+
+	/** state of goom */
+	guint32 cycle;
+	GoomState states[STATES_MAX_NB];
+	int statesNumber;
+	int statesRangeMax;
+
+	GoomState *curGState;
+
+	/** effet de ligne.. */
+	GMLine *gmline1;
+	GMLine *gmline2;
+
+	/** sinus table */
+	int sintable[0x10000];
+
+	/* INTERNALS */
+	
+	/** goom_update internals.
+	 * I took all static variables from goom_update and put them here.. for the moment.
+	 */
+	struct {
+		int lockvar;               /* pour empecher de nouveaux changements */
+		int goomvar;               /* boucle des gooms */
+		int loopvar;               /* mouvement des points */
+		int stop_lines;
+		int ifs_incr;              /* dessiner l'ifs (0 = non: > = increment) */
+		int decay_ifs;             /* disparition de l'ifs */
+		int recay_ifs;             /* dedisparition de l'ifs */
+		int cyclesSinceLastChange; /* nombre de Cycle Depuis Dernier Changement */
+		int drawLinesDuration;     /* duree de la transition entre afficher les lignes ou pas */
+		int lineMode;              /* l'effet lineaire a dessiner */
+		float switchMultAmount;    /* SWITCHMULT (29.0f/30.0f) */
+		int switchIncrAmount;      /* 0x7f */
+		float switchMult;          /* 1.0f */
+		int switchIncr;            /*  = SWITCHINCR; */
+		int stateSelectionRnd;
+		int stateSelectionBlocker;
+		int previousZoomSpeed;
+		ZoomFilterData zoomFilterData;                
+	} update;
+
+	struct {
+		void (*draw_line) (Pixel *data, int x1, int y1, int x2, int y2, int col, int screenx, int screeny);
+		void (*zoom_filter) (int sizeX, int sizeY, Pixel *src, Pixel *dest, int *brutS, int *brutD, int buffratio, int precalCoef[16][16]);
+	} methods;
+	
+	GoomRandom *gRandom;
+};
+
+void plugin_info_init(PluginInfo *p, int nbVisual); 
+void plugin_info_free(PluginInfo *p);
+
+/* i = [0..p->nbVisual-1] */
+void plugin_info_add_visual(PluginInfo *p, int i, VisualFX *visual);
+
+#endif
diff --git a/gst/goom/goom_tools.c b/gst/goom/goom_tools.c
new file mode 100644
index 0000000..01758fd
--- /dev/null
+++ b/gst/goom/goom_tools.c
@@ -0,0 +1,50 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "goom_tools.h"
+#include <stdlib.h>
+
+GoomRandom *
+goom_random_init (int i)
+{
+  GoomRandom *grandom = (GoomRandom *) malloc (sizeof (GoomRandom));
+
+  srand (i);
+  grandom->pos = 1;
+  goom_random_update_array (grandom, GOOM_NB_RAND);
+  return grandom;
+}
+
+void
+goom_random_free (GoomRandom * grandom)
+{
+  free (grandom);
+}
+
+void
+goom_random_update_array (GoomRandom * grandom, int numberOfValuesToChange)
+{
+  while (numberOfValuesToChange > 0) {
+#if RAND_MAX < 0x10000
+    grandom->array[grandom->pos++] = ((rand () << 16) + rand ()) / 127;
+#else
+    grandom->array[grandom->pos++] = rand () / 127;
+#endif
+    numberOfValuesToChange--;
+  }
+}
diff --git a/gst/goom/goom_tools.h b/gst/goom/goom_tools.h
new file mode 100644
index 0000000..34f5240
--- /dev/null
+++ b/gst/goom/goom_tools.h
@@ -0,0 +1,53 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _GOOMTOOLS_H
+#define _GOOMTOOLS_H
+
+#include "goom_config.h"
+
+/**
+ * Random number generator wrapper for faster random number.
+ */
+
+#define GOOM_NB_RAND 0x10000
+
+typedef struct _GOOM_RANDOM {
+	int array[GOOM_NB_RAND];
+	unsigned short pos;
+} GoomRandom;
+
+GoomRandom *goom_random_init(int i);
+void goom_random_free(GoomRandom *grandom);
+
+inline static int goom_random(GoomRandom *grandom) {
+	
+	grandom->pos++; /* works because pos is an unsigned short */
+	return grandom->array[grandom->pos];
+}
+
+inline static int goom_irand(GoomRandom *grandom, int i) {
+
+	grandom->pos++;
+	return grandom->array[grandom->pos] % i;
+}
+
+/* called to change the specified number of value in the array, so that the array does not remain the same*/
+void goom_random_update_array(GoomRandom *grandom, int numberOfValuesToChange);
+
+#endif
diff --git a/gst/goom/goom_typedefs.h b/gst/goom/goom_typedefs.h
new file mode 100644
index 0000000..d3a33a9
--- /dev/null
+++ b/gst/goom/goom_typedefs.h
@@ -0,0 +1,29 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _GOOM_TYPEDEFS_H
+#define _GOOM_TYPEDEFS_H
+
+typedef struct _PLUGIN_INFO PluginInfo;
+typedef struct _SOUND_INFO SoundInfo;
+typedef struct _GMLINE GMLine;
+typedef struct _GMUNITPOINTER GMUnitPointer;
+typedef struct _ZOOM_FILTER_DATA ZoomFilterData;
+typedef struct _VISUAL_FX VisualFX;
+
+#endif
diff --git a/gst/goom/goom_visual_fx.h b/gst/goom/goom_visual_fx.h
new file mode 100644
index 0000000..0bb5a49
--- /dev/null
+++ b/gst/goom/goom_visual_fx.h
@@ -0,0 +1,35 @@
+/* Goom Project
+ * Copyright (C) <2003> Jean-Christophe Hoelt <jeko@free.fr>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _VISUAL_FX_H
+#define _VISUAL_FX_H
+
+#include "goom_config_param.h"
+#include "goom_graphic.h"
+#include "goom_typedefs.h"
+
+struct _VISUAL_FX {
+  void (*init) (struct _VISUAL_FX *_this, PluginInfo *info);
+  void (*free) (struct _VISUAL_FX *_this);
+  void (*apply) (struct _VISUAL_FX *_this, Pixel *src, Pixel *dest, PluginInfo *info);
+  void *fx_data;
+
+  PluginParameters *params;
+};
+
+#endif
diff --git a/gst/goom/goomsl_lex.l b/gst/goom/goomsl_lex.l
new file mode 100644
index 0000000..7a7de29
--- /dev/null
+++ b/gst/goom/goomsl_lex.l
@@ -0,0 +1,94 @@
+%{
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include "goomsl.h"
+#include "goomsl_private.h"
+#include "goomsl_yacc.h"
+void yyerror(char *);
+void yyparse(void);
+
+GoomSL *currentGoomSL;
+static int  string_size;
+static char string[1024];
+%}
+
+DIGIT    [0-9]
+XDIGIT   [0-9a-f]
+ID       [a-zA-Z_@&][a-zA-Z0-9_\.]*
+
+%S C_COMMENT
+%S LINE_COMMENT
+%S STRING
+
+%%
+
+<LINE_COMMENT,C_COMMENT,INITIAL>^[ \t]*\n           { ++currentGoomSL->num_lines; /* Ignore empty lines */ }
+<LINE_COMMENT,C_COMMENT,INITIAL>^[ \t]*"//"[^\n]*\n { ++currentGoomSL->num_lines; /* Ignore empty lines */ }
+
+<LINE_COMMENT>\n    { ++currentGoomSL->num_lines; yylval.charValue=*yytext; BEGIN INITIAL; return '\n'; }
+<INITIAL>\n         { ++currentGoomSL->num_lines; yylval.charValue=*yytext; return '\n'; }
+
+<C_COMMENT>"*/"                { BEGIN INITIAL; }
+<C_COMMENT>\n                  { ++currentGoomSL->num_lines; }
+<C_COMMENT,LINE_COMMENT>.      { /* eat up comment */ }
+
+<INITIAL>"#RST_LINE#"             { currentGoomSL->num_lines = 0; }
+<INITIAL>"#FILE ".*"#"            { currentGoomSL->num_lines = 0; /* printf("%s\n", yytext); */ }
+<INITIAL>"#"[^\n]*                { /* ignore preprocessor lines */ }
+
+<INITIAL>"/*"                { BEGIN C_COMMENT; }
+<INITIAL>"//"                { BEGIN LINE_COMMENT; }
+<INITIAL>\"                  { BEGIN STRING; string_size=0; }
+
+<STRING>"\\n"                { string[string_size++] = '\n'; }
+<STRING>"\\\""               { string[string_size++] = '\"'; }
+<STRING>\"                   { /* fin de la chaine: on cree le pointeur qui va bien */
+                               unsigned int tmp;
+                               BEGIN INITIAL;
+                               string[string_size]=0;
+                               tmp = gsl_malloc(currentGoomSL, string_size+1);
+                               strcpy((char*)currentGoomSL->ptrArray[tmp],string);
+                               sprintf(yylval.strValue, "0x%08x", tmp);
+                               return LTYPE_PTR;
+                             }
+<STRING>.                    { string[string_size++] = *yytext; }
+
+<INITIAL>"float"                 { return FLOAT_TK; }
+<INITIAL>"int"                   { return INT_TK;   }
+<INITIAL>"boolean"               { return INT_TK;   }
+<INITIAL>"ptr"                   { return PTR_TK;   }
+<INITIAL>"string"                { return PTR_TK;   }
+<INITIAL>"declare"               { return DECLARE;  }
+<INITIAL>"external"              { return EXTERNAL; }
+<INITIAL>"struct"                { return STRUCT;   }
+<INITIAL>"not"                   { return NOT;      }
+<INITIAL>"while"                 { return WHILE;    } 
+<INITIAL>"do"                    { return DO;       }
+<INITIAL>"for"                   { return FOR;      }
+<INITIAL>"in"                    { return IN;       }
+<INITIAL>"true"                  { strncpy(yylval.strValue, "1", 2047);    return LTYPE_INTEGER; }
+<INITIAL>"false"                 { strncpy(yylval.strValue, "0", 2047);    return LTYPE_INTEGER; }
+<INITIAL>{ID}                    { strncpy(yylval.strValue, yytext, 2047); return LTYPE_VAR;     }
+<INITIAL>{DIGIT}+                { strncpy(yylval.strValue, yytext, 2047); return LTYPE_INTEGER; }
+<INITIAL>\'.\'                   { sprintf(yylval.strValue, "%d", (int)yytext[1]); return LTYPE_INTEGER; }
+<INITIAL>"0x"{XDIGIT}+           { strncpy(yylval.strValue, yytext, 2047); return LTYPE_INTEGER; }
+<INITIAL>{DIGIT}+"."{DIGIT}*     { strncpy(yylval.strValue, yytext, 2047); return LTYPE_FLOAT;   }
+<INITIAL>{DIGIT}+"%"             { sprintf(yylval.strValue, "%3.2f", atof(yytext)/100.0f); return LTYPE_FLOAT; }
+<INITIAL>"+="                    { return PLUS_EQ; }
+<INITIAL>"*="                    { return MUL_EQ; }
+<INITIAL>"-="                    { return SUB_EQ; }
+<INITIAL>"/="                    { return DIV_EQ; }
+<INITIAL>"<="                    { return LOW_EQ;  }
+<INITIAL>">="                    { return SUP_EQ;  }
+<INITIAL>"!="                    { return NOT_EQ;  }
+<INITIAL>"<>"                    { return NOT_EQ;  }
+<INITIAL>[ \t]+                  /* eat up whitespace */
+<INITIAL>.                       { yylval.charValue = *yytext; return *yytext;    }
+
+%%
+
+
+int yywrap(void) { return 1; yyunput(0,0); }
+
diff --git a/gst/goom/goomsl_yacc.y b/gst/goom/goomsl_yacc.y
new file mode 100644
index 0000000..078933c
--- /dev/null
+++ b/gst/goom/goomsl_yacc.y
@@ -0,0 +1,1438 @@
+/**
+ * copyright 2004, Jean-Christophe Hoelt <jeko@ios-software.com>
+ *
+ * This program is released under the terms of the GNU Lesser General Public Licence.
+ */
+%{
+    #include <stdio.h>
+    #include <stdlib.h>
+    #include <string.h>
+    #include <glib.h>
+    #include "goomsl.h"
+    #include "goomsl_private.h"
+
+#define STRUCT_ALIGNMENT 16
+/* #define VERBOSE  */
+
+    int yylex(void);
+    void yyerror(char *);
+    extern GoomSL *currentGoomSL;
+
+    static NodeType *nodeNew(const char *str, int type, int line_number);
+    static NodeType *nodeClone(NodeType *node);
+    static void nodeFreeInternals(NodeType *node);
+    static void nodeFree(NodeType *node);
+
+    static void commit_node(NodeType *node, int releaseIfTemp);
+    static void precommit_node(NodeType *node);
+
+    static NodeType *new_constInt(const char *str, int line_number);
+    static NodeType *new_constFloat(const char *str, int line_number);
+    static NodeType *new_constPtr(const char *str, int line_number);
+    static NodeType *new_var(const char *str, int line_number);
+    static NodeType *new_nop(const char *str);
+    static NodeType *new_op(const char *str, int type, int nbOp);
+
+    static int  allocateLabel();
+    static int  allocateTemp();
+    static void releaseTemp(int n);
+    static void releaseAllTemps();
+
+    static int is_tmp_expr(NodeType *node) {
+        if (node->str) {
+            return (!strncmp(node->str,"_i_tmp_",7))
+              || (!strncmp(node->str,"_f_tmp_",7))
+              || (!strncmp(node->str,"_p_tmp",7));
+        }
+        return 0;
+    }
+    /* pre: is_tmp_expr(node); */
+    static int get_tmp_id(NodeType *node)  { return atoi((node->str)+5); }
+
+    static int is_commutative_expr(int itype)
+    { /* {{{ */
+        return (itype == INSTR_ADD)
+            || (itype == INSTR_MUL)
+            || (itype == INSTR_ISEQUAL);
+    } /* }}} */
+
+    static void GSL_PUT_LABEL(char *name, int line_number)
+    { /* {{{ */
+#ifdef VERBOSE
+      printf("label %s\n", name);
+#endif
+      currentGoomSL->instr = gsl_instr_init(currentGoomSL, "label", INSTR_LABEL, 1, line_number);
+      gsl_instr_add_param(currentGoomSL->instr, name, TYPE_LABEL);
+    } /* }}} */
+    static void GSL_PUT_JUMP(char *name, int line_number)
+    { /* {{{ */
+#ifdef VERBOSE
+      printf("jump %s\n", name);
+#endif
+      currentGoomSL->instr = gsl_instr_init(currentGoomSL, "jump", INSTR_JUMP, 1, line_number);
+      gsl_instr_add_param(currentGoomSL->instr, name, TYPE_LABEL);
+    } /* }}} */
+
+    static void GSL_PUT_JXXX(char *name, char *iname, int instr_id, int line_number)
+    { /* {{{ */
+#ifdef VERBOSE
+      printf("%s %s\n", iname, name);
+#endif
+      currentGoomSL->instr = gsl_instr_init(currentGoomSL, iname, instr_id, 1, line_number);
+      gsl_instr_add_param(currentGoomSL->instr, name, TYPE_LABEL);
+    } /* }}} */
+    static void GSL_PUT_JZERO(char *name,int line_number)
+    { /* {{{ */
+      GSL_PUT_JXXX(name,"jzero.i",INSTR_JZERO,line_number);
+    } /* }}} */
+    static void GSL_PUT_JNZERO(char *name, int line_number)
+    { /* {{{ */
+      GSL_PUT_JXXX(name,"jnzero.i",INSTR_JNZERO,line_number);
+    } /* }}} */
+
+    /* Structures Management */
+
+#define ALIGN_ADDR(_addr,_align) {\
+   if (_align>1) {\
+       int _dec = (_addr%_align);\
+       if (_dec != 0) _addr += _align - _dec;\
+   }}
+
+    /* */
+    void gsl_prepare_struct(GSL_Struct *s, int s_align, int i_align, int f_align)
+    {
+      int i;
+      int consumed = 0;
+      int iblk=0, fblk=0;
+
+      s->iBlock[0].size = 0;
+      s->iBlock[0].data = 0;
+      s->fBlock[0].size = 0;
+      s->fBlock[0].data = 0;
+
+      /* Prepare sub-struct and calculate space needed for their storage */
+      for (i = 0; i < s->nbFields; ++i)
+      {
+        if (s->fields[i]->type < FIRST_RESERVED)
+        {
+          int j=0;
+          GSL_Struct *substruct = currentGoomSL->gsl_struct[s->fields[i]->type];
+          consumed += sizeof(int); /* stocke le prefix */
+          ALIGN_ADDR(consumed, s_align);
+          s->fields[i]->offsetInStruct = consumed;
+          gsl_prepare_struct(substruct, s_align, i_align, f_align);
+          for(j=0;substruct->iBlock[j].size>0;++j) {
+            s->iBlock[iblk].data = consumed + substruct->iBlock[j].data;
+            s->iBlock[iblk].size = substruct->iBlock[j].size;
+            iblk++;
+          }
+          for(j=0;substruct->fBlock[j].size>0;++j) {
+            s->fBlock[fblk].data = consumed + substruct->fBlock[j].data;
+            s->fBlock[fblk].size = substruct->fBlock[j].size;
+            fblk++;
+          }
+          consumed += substruct->size;
+        }
+      }
+
+      /* Then prepare integers */
+      ALIGN_ADDR(consumed, i_align);
+      for (i = 0; i < s->nbFields; ++i)
+      {
+        if (s->fields[i]->type == INSTR_INT)
+        {
+          if (s->iBlock[iblk].size == 0) {
+            s->iBlock[iblk].size = 1;
+            s->iBlock[iblk].data = consumed;
+          } else {
+            s->iBlock[iblk].size += 1;
+          }
+          s->fields[i]->offsetInStruct = consumed;
+          consumed += sizeof(int);
+        }
+      }
+
+      iblk++;
+      s->iBlock[iblk].size = 0;
+      s->iBlock[iblk].data = 0;
+
+      /* Then prepare floats */
+      ALIGN_ADDR(consumed, f_align);
+      for (i = 0; i < s->nbFields; ++i)
+      {
+        if (s->fields[i]->type == INSTR_FLOAT)
+        {
+          if (s->fBlock[fblk].size == 0) {
+            s->fBlock[fblk].size = 1;
+            s->fBlock[fblk].data = consumed;
+          } else {
+            s->fBlock[fblk].size += 1;
+          }
+          s->fields[i]->offsetInStruct = consumed;
+          consumed += sizeof(int);
+        }
+      }
+
+      fblk++;
+      s->fBlock[fblk].size = 0;
+      s->fBlock[fblk].data = 0;
+      
+      /* Finally prepare pointers */
+      ALIGN_ADDR(consumed, i_align);
+      for (i = 0; i < s->nbFields; ++i)
+      {
+        if (s->fields[i]->type == INSTR_PTR)
+        {
+          s->fields[i]->offsetInStruct = consumed;
+          consumed += sizeof(int);
+        }
+      }
+      s->size = consumed;
+    }
+
+    /* Returns the ID of a struct from its name */
+    int gsl_get_struct_id(const char *name) /* {{{ */
+    {
+      HashValue *ret = goom_hash_get(currentGoomSL->structIDS, name);
+      if (ret != NULL) return ret->i;
+      return -1;
+    } /* }}} */
+
+    /* Adds the definition of a struct */
+    void gsl_add_struct(const char *name, GSL_Struct *gsl_struct) /* {{{ */
+    {
+      /* Prepare the struct: ie calculate internal storage format */
+      gsl_prepare_struct(gsl_struct, STRUCT_ALIGNMENT, STRUCT_ALIGNMENT, STRUCT_ALIGNMENT);
+      
+      /* If the struct does not already exists */
+      if (gsl_get_struct_id(name) < 0)
+      {
+        /* adds it */
+        int id = currentGoomSL->nbStructID++;
+        goom_hash_put_int(currentGoomSL->structIDS, name, id);
+        if (currentGoomSL->gsl_struct_size <= id) {
+          currentGoomSL->gsl_struct_size *= 2;
+          currentGoomSL->gsl_struct = (GSL_Struct**)realloc(currentGoomSL->gsl_struct,
+                                                            sizeof(GSL_Struct*) * currentGoomSL->gsl_struct_size);
+        }
+        currentGoomSL->gsl_struct[id] = gsl_struct;
+      }
+    } /* }}} */
+    
+    /* Creates a field for a struct */
+    GSL_StructField *gsl_new_struct_field(const char *name, int type)
+    {
+      GSL_StructField *field = (GSL_StructField*)malloc(sizeof(GSL_StructField));
+      strcpy(field->name, name);
+      field->type = type;
+      return field;
+    }
+    
+    /* Create as field for a struct which will be a struct itself */
+    GSL_StructField *gsl_new_struct_field_struct(const char *name, const char *type)
+    {
+      GSL_StructField *field = gsl_new_struct_field(name, gsl_get_struct_id(type));
+      if (field->type < 0) {
+        g_assert_not_reached ();
+#if 0
+        fprintf(stderr, "ERROR: Line %d, Unknown structure: '%s'\n",
+                currentGoomSL->num_lines, type);
+        exit(1);
+#endif
+      }
+      return field;
+    }
+
+    /* Creates a Struct */
+    GSL_Struct *gsl_new_struct(GSL_StructField *field)
+    {
+      GSL_Struct *s = (GSL_Struct*)malloc(sizeof(GSL_Struct));
+      s->nbFields = 1;
+      s->fields[0] = field;
+      return s;
+    }
+
+    /* Adds a field to a struct */
+    void gsl_add_struct_field(GSL_Struct *s, GSL_StructField *field)
+    {
+      s->fields[s->nbFields++] = field;
+    }
+
+    int gsl_type_of_var(GoomHash *ns, const char *name)
+    {
+        char type_of[256];
+        HashValue *hv;
+        sprintf(type_of, "__type_of_%s", name);
+        hv = goom_hash_get(ns, type_of);
+        if (hv != NULL)
+          return hv->i;
+        fprintf(stderr, "ERROR: Unknown variable type: '%s'\n", name);
+        return -1;
+    }
+
+    static void gsl_declare_var(GoomHash *ns, const char *name, int type, void *space)
+    {
+        char type_of[256];
+        if (name[0] == '@') { ns = currentGoomSL->vars; }
+
+        if (space == NULL) {
+          switch (type) {
+            case INSTR_INT:
+            case INSTR_FLOAT:
+            case INSTR_PTR:
+              space = goom_heap_malloc_with_alignment(currentGoomSL->data_heap,
+                  sizeof(int), sizeof(int));
+            break;
+#if 0
+            case -1:
+              fprintf(stderr, "What the fuck!\n");
+              exit(1);
+#endif
+            default: /* On a un struct_id */
+              space = goom_heap_malloc_with_alignment_prefixed(currentGoomSL->data_heap,
+                  currentGoomSL->gsl_struct[type]->size, STRUCT_ALIGNMENT, sizeof(int));
+          }
+        }
+        goom_hash_put_ptr(ns, name, (void*)space);
+        sprintf(type_of, "__type_of_%s", name);
+        goom_hash_put_int(ns, type_of, type);
+
+        /* Ensuite le hack: on ajoute les champs en tant que variables. */
+        if (type < FIRST_RESERVED)
+        {
+          int i;
+          GSL_Struct *gsl_struct = currentGoomSL->gsl_struct[type];
+          ((int*)space)[-1] = type; /* stockage du type dans le prefixe de structure */
+          for (i = 0; i < gsl_struct->nbFields; ++i)
+          {
+            char full_name[256];
+            char *cspace = (char*)space + gsl_struct->fields[i]->offsetInStruct;
+            sprintf(full_name, "%s.%s", name, gsl_struct->fields[i]->name);
+            gsl_declare_var(ns, full_name, gsl_struct->fields[i]->type, cspace);
+          }
+       }
+    }
+    
+    /* Declare a variable which will be a struct */
+    static void gsl_struct_decl(GoomHash *namespace, const char *struct_name, const char *name)
+    {
+        int  struct_id = gsl_get_struct_id(struct_name);
+        gsl_declare_var(namespace, name, struct_id, NULL);
+    }
+
+    static void gsl_float_decl_global(const char *name)
+    {
+        gsl_declare_var(currentGoomSL->vars, name, INSTR_FLOAT, NULL);
+    }
+    static void gsl_int_decl_global(const char *name)
+    {
+        gsl_declare_var(currentGoomSL->vars, name, INSTR_INT, NULL);
+    }
+    static void gsl_ptr_decl_global(const char *name)
+    {
+        gsl_declare_var(currentGoomSL->vars, name, INSTR_PTR, NULL);
+    }
+    static void gsl_struct_decl_global_from_id(const char *name, int id)
+    {
+        gsl_declare_var(currentGoomSL->vars, name, id, NULL);
+    }
+    
+    /* FLOAT */
+    static void gsl_float_decl_local(const char *name)
+    {
+        gsl_declare_var(currentGoomSL->namespaces[currentGoomSL->currentNS], name, INSTR_FLOAT, NULL);
+    }
+    /* INT */
+    static void gsl_int_decl_local(const char *name)
+    {
+        gsl_declare_var(currentGoomSL->namespaces[currentGoomSL->currentNS], name, INSTR_INT, NULL);
+    }
+    /* PTR */
+    static void gsl_ptr_decl_local(const char *name)
+    {
+        gsl_declare_var(currentGoomSL->namespaces[currentGoomSL->currentNS], name, INSTR_PTR, NULL);
+    }
+    /* STRUCT */
+    static void gsl_struct_decl_local(const char *struct_name, const char *name)
+    {
+        gsl_struct_decl(currentGoomSL->namespaces[currentGoomSL->currentNS],struct_name,name);
+    }
+
+
+    static void commit_test2(NodeType *set,const char *type, int instr);
+    static NodeType *new_call(const char *name, NodeType *affect_list);
+
+    /* SETTER */
+    static NodeType *new_set(NodeType *lvalue, NodeType *expression)
+    { /* {{{ */
+        NodeType *set = new_op("set", OPR_SET, 2);
+        set->unode.opr.op[0] = lvalue;
+        set->unode.opr.op[1] = expression;
+        return set;
+    } /* }}} */
+    static void commit_set(NodeType *set)
+    { /* {{{ */
+      commit_test2(set,"set",INSTR_SET);
+    } /* }}} */
+
+    /* PLUS_EQ */
+    static NodeType *new_plus_eq(NodeType *lvalue, NodeType *expression) /* {{{ */
+    {
+        NodeType *set = new_op("plus_eq", OPR_PLUS_EQ, 2);
+        set->unode.opr.op[0] = lvalue;
+        set->unode.opr.op[1] = expression;
+        return set;
+    }
+    static void commit_plus_eq(NodeType *set)
+    {
+        precommit_node(set->unode.opr.op[1]);
+#ifdef VERBOSE
+        printf("add %s %s\n", set->unode.opr.op[0]->str, set->unode.opr.op[1]->str);
+#endif
+        currentGoomSL->instr = gsl_instr_init(currentGoomSL, "add", INSTR_ADD, 2, set->line_number);
+        commit_node(set->unode.opr.op[0],0);
+        commit_node(set->unode.opr.op[1],1);
+    } /* }}} */
+
+    /* SUB_EQ */
+    static NodeType *new_sub_eq(NodeType *lvalue, NodeType *expression) /* {{{ */
+    {
+        NodeType *set = new_op("sub_eq", OPR_SUB_EQ, 2);
+        set->unode.opr.op[0] = lvalue;
+        set->unode.opr.op[1] = expression;
+        return set;
+    }
+    static void commit_sub_eq(NodeType *set)
+    {
+        precommit_node(set->unode.opr.op[1]);
+#ifdef VERBOSE
+        printf("sub %s %s\n", set->unode.opr.op[0]->str, set->unode.opr.op[1]->str);
+#endif
+        currentGoomSL->instr = gsl_instr_init(currentGoomSL, "sub", INSTR_SUB, 2, set->line_number);
+        commit_node(set->unode.opr.op[0],0);
+        commit_node(set->unode.opr.op[1],1);
+    } /* }}} */
+
+    /* MUL_EQ */
+    static NodeType *new_mul_eq(NodeType *lvalue, NodeType *expression) /* {{{ */
+    {
+        NodeType *set = new_op("mul_eq", OPR_MUL_EQ, 2);
+        set->unode.opr.op[0] = lvalue;
+        set->unode.opr.op[1] = expression;
+        return set;
+    }
+    static void commit_mul_eq(NodeType *set)
+    {
+        precommit_node(set->unode.opr.op[1]);
+#ifdef VERBOSE
+        printf("mul %s %s\n", set->unode.opr.op[0]->str, set->unode.opr.op[1]->str);
+#endif
+        currentGoomSL->instr = gsl_instr_init(currentGoomSL, "mul", INSTR_MUL, 2, set->line_number);
+        commit_node(set->unode.opr.op[0],0);
+        commit_node(set->unode.opr.op[1],1);
+    } /* }}} */
+
+    /* DIV_EQ */
+    static NodeType *new_div_eq(NodeType *lvalue, NodeType *expression) /* {{{ */
+    {
+        NodeType *set = new_op("div_eq", OPR_DIV_EQ, 2);
+        set->unode.opr.op[0] = lvalue;
+        set->unode.opr.op[1] = expression;
+        return set;
+    }
+    static void commit_div_eq(NodeType *set)
+    {
+        precommit_node(set->unode.opr.op[1]);
+#ifdef VERBOSE
+        printf("div %s %s\n", set->unode.opr.op[0]->str, set->unode.opr.op[1]->str);
+#endif
+        currentGoomSL->instr = gsl_instr_init(currentGoomSL, "div", INSTR_DIV, 2, set->line_number);
+        commit_node(set->unode.opr.op[0],0);
+        commit_node(set->unode.opr.op[1],1);
+    } /* }}} */
+
+    /* commodity method for add, mult, ... */
+
+    static void precommit_expr(NodeType *expr, const char *type, int instr_id)
+    { /* {{{ */
+        NodeType *tmp, *tmpcpy;
+        int toAdd;
+
+        /* compute "left" and "right" */
+        switch (expr->unode.opr.nbOp) {
+        case 2:
+          precommit_node(expr->unode.opr.op[1]);
+        case 1:
+          precommit_node(expr->unode.opr.op[0]);
+        }
+
+        if (is_tmp_expr(expr->unode.opr.op[0])) {
+            tmp = expr->unode.opr.op[0];
+            toAdd = 1;
+        }
+        else if (is_commutative_expr(instr_id) && (expr->unode.opr.nbOp==2) && is_tmp_expr(expr->unode.opr.op[1])) {
+            tmp = expr->unode.opr.op[1];
+            toAdd = 0;
+        }
+        else {
+            char stmp[256];
+            /* declare a temporary variable to store the result */
+            if (expr->unode.opr.op[0]->type == CONST_INT_NODE) {
+                sprintf(stmp,"_i_tmp_%i",allocateTemp());
+                gsl_int_decl_global(stmp);
+            }
+            else if (expr->unode.opr.op[0]->type == CONST_FLOAT_NODE) {
+                sprintf(stmp,"_f_tmp%i",allocateTemp());
+                gsl_float_decl_global(stmp);
+            }
+            else if (expr->unode.opr.op[0]->type == CONST_PTR_NODE) {
+                sprintf(stmp,"_p_tmp%i",allocateTemp());
+                gsl_ptr_decl_global(stmp);
+            }
+            else {
+                int type = gsl_type_of_var(expr->unode.opr.op[0]->vnamespace, expr->unode.opr.op[0]->str);
+                if (type == INSTR_FLOAT) {
+                    sprintf(stmp,"_f_tmp_%i",allocateTemp());
+                    gsl_float_decl_global(stmp);
+                }
+                else if (type == INSTR_PTR) {
+                    sprintf(stmp,"_p_tmp_%i",allocateTemp());
+                    gsl_ptr_decl_global(stmp);
+                }
+                else if (type == INSTR_INT) {
+                    sprintf(stmp,"_i_tmp_%i",allocateTemp());
+                    gsl_int_decl_global(stmp);
+                }
+                else if (type == -1) {
+                    g_assert_not_reached ();
+#if 0
+                    fprintf(stderr, "ERROR: Line %d, Could not find variable '%s'\n",
+                            expr->line_number, expr->unode.opr.op[0]->str);
+                    exit(1);
+#endif
+                }
+                else { /* type is a struct_id */
+                    sprintf(stmp,"_s_tmp_%i",allocateTemp());
+                    gsl_struct_decl_global_from_id(stmp,type);
+                }
+            }
+            tmp = new_var(stmp,expr->line_number);
+
+            /* set the tmp to the value of "op1" */
+            tmpcpy = nodeClone(tmp);
+            commit_node(new_set(tmp,expr->unode.opr.op[0]),0);
+            toAdd = 1;
+
+            tmp = tmpcpy;
+        }
+
+        /* add op2 to tmp */
+#ifdef VERBOSE
+        if (expr->unode.opr.nbOp == 2)
+          printf("%s %s %s\n", type, tmp->str, expr->unode.opr.op[toAdd]->str);
+        else
+          printf("%s %s\n", type, tmp->str);
+#endif
+        currentGoomSL->instr = gsl_instr_init(currentGoomSL, type, instr_id, expr->unode.opr.nbOp, expr->line_number);
+        tmpcpy = nodeClone(tmp);
+        commit_node(tmp,0);
+        if (expr->unode.opr.nbOp == 2) {
+          commit_node(expr->unode.opr.op[toAdd],1);
+        }
+    
+        /* redefine the ADD node now as the computed variable */
+        nodeFreeInternals(expr);
+        *expr = *tmpcpy;
+        free(tmpcpy);
+    } /* }}} */
+
+    static NodeType *new_expr1(const char *name, int id, NodeType *expr1)
+    { /* {{{ */
+        NodeType *add = new_op(name, id, 1);
+        add->unode.opr.op[0] = expr1;
+        return add;
+    } /* }}} */
+
+    static NodeType *new_expr2(const char *name, int id, NodeType *expr1, NodeType *expr2)
+    { /* {{{ */
+        NodeType *add = new_op(name, id, 2);
+        add->unode.opr.op[0] = expr1;
+        add->unode.opr.op[1] = expr2;
+        return add;
+    } /* }}} */
+
+    /* ADD */
+    static NodeType *new_add(NodeType *expr1, NodeType *expr2) { /* {{{ */
+        return new_expr2("add", OPR_ADD, expr1, expr2);
+    }
+    static void precommit_add(NodeType *add) {
+        precommit_expr(add,"add",INSTR_ADD);
+    } /* }}} */
+
+    /* SUB */
+    static NodeType *new_sub(NodeType *expr1, NodeType *expr2) { /* {{{ */
+        return new_expr2("sub", OPR_SUB, expr1, expr2);
+    }
+    static void precommit_sub(NodeType *sub) {
+        precommit_expr(sub,"sub",INSTR_SUB);
+    } /* }}} */
+
+    /* NEG */
+    static NodeType *new_neg(NodeType *expr) { /* {{{ */
+        NodeType *zeroConst = NULL;
+        if (expr->type == CONST_INT_NODE)
+          zeroConst = new_constInt("0", currentGoomSL->num_lines);
+        else if (expr->type == CONST_FLOAT_NODE)
+          zeroConst = new_constFloat("0.0", currentGoomSL->num_lines);
+        else if (expr->type == CONST_PTR_NODE) {
+          g_assert_not_reached ();
+#if 0
+          fprintf(stderr, "ERROR: Line %d, Could not negate const pointer.\n",
+            currentGoomSL->num_lines);
+          exit(1);
+#endif
+        }
+        else {
+            int type = gsl_type_of_var(expr->vnamespace, expr->str);
+            if (type == INSTR_FLOAT)
+              zeroConst = new_constFloat("0.0", currentGoomSL->num_lines);
+            else if (type == INSTR_PTR) {
+              g_assert_not_reached ();
+#if 0
+              fprintf(stderr, "ERROR: Line %d, Could not negate pointer.\n",
+                currentGoomSL->num_lines);
+              exit(1);
+#endif
+            }
+            else if (type == INSTR_INT)
+              zeroConst = new_constInt("0", currentGoomSL->num_lines);
+            else if (type == -1) {
+                g_assert_not_reached ();
+#if 0
+                fprintf(stderr, "ERROR: Line %d, Could not find variable '%s'\n",
+                        expr->line_number, expr->unode.opr.op[0]->str);
+                exit(1);
+#endif
+            }
+            else { /* type is a struct_id */
+                g_assert_not_reached ();
+#if 0
+                fprintf(stderr, "ERROR: Line %d, Could not negate struct '%s'\n",
+                        expr->line_number, expr->str);
+                exit(1);
+#endif
+            }
+        }
+        return new_expr2("sub", OPR_SUB, zeroConst, expr);
+    }
+    /* }}} */
+
+    /* MUL */
+    static NodeType *new_mul(NodeType *expr1, NodeType *expr2) { /* {{{ */
+        return new_expr2("mul", OPR_MUL, expr1, expr2);
+    }
+    static void precommit_mul(NodeType *mul) {
+        precommit_expr(mul,"mul",INSTR_MUL);
+    } /* }}} */
+    
+    /* DIV */
+    static NodeType *new_div(NodeType *expr1, NodeType *expr2) { /* {{{ */
+        return new_expr2("div", OPR_DIV, expr1, expr2);
+    }
+    static void precommit_div(NodeType *mul) {
+        precommit_expr(mul,"div",INSTR_DIV);
+    } /* }}} */
+
+    /* CALL EXPRESSION */
+    static NodeType *new_call_expr(const char *name, NodeType *affect_list) { /* {{{ */
+        NodeType *call = new_call(name,affect_list);
+        NodeType *node = new_expr1(name, OPR_CALL_EXPR, call);
+        node->vnamespace = gsl_find_namespace(name);
+        if (node->vnamespace == NULL)
+          /* fprintf(stderr, "ERROR: Line %d, No return type for: '%s'\n", currentGoomSL->num_lines, name); */
+        return node;
+    }
+    static void precommit_call_expr(NodeType *call) {
+        char stmp[256];
+        NodeType *tmp,*tmpcpy;
+        int type = gsl_type_of_var(call->vnamespace, call->str);
+        if (type == INSTR_FLOAT) {
+          sprintf(stmp,"_f_tmp_%i",allocateTemp());
+          gsl_float_decl_global(stmp);
+        }
+        else if (type == INSTR_PTR) {
+          sprintf(stmp,"_p_tmp_%i",allocateTemp());
+          gsl_ptr_decl_global(stmp);
+        }
+        else if (type == INSTR_INT) {
+          sprintf(stmp,"_i_tmp_%i",allocateTemp());
+          gsl_int_decl_global(stmp);
+        }
+        else if (type == -1) {
+          g_assert_not_reached ();
+#if 0
+          fprintf(stderr, "ERROR: Line %d, Could not find variable '%s'\n",
+                  call->line_number, call->str);
+          exit(1);
+#endif
+        }
+        else { /* type is a struct_id */
+          sprintf(stmp,"_s_tmp_%i",allocateTemp());
+          gsl_struct_decl_global_from_id(stmp,type);
+        }
+        tmp = new_var(stmp,call->line_number);
+        commit_node(call->unode.opr.op[0],0);
+        tmpcpy = nodeClone(tmp);
+        commit_node(new_set(tmp,new_var(call->str,call->line_number)),0);
+        
+        nodeFreeInternals(call);
+        *call = *tmpcpy;
+        free(tmpcpy);
+    } /* }}} */
+
+    static void commit_test2(NodeType *set,const char *type, int instr)
+    { /* {{{ */
+        NodeType *tmp;
+        char stmp[256];
+        precommit_node(set->unode.opr.op[0]);
+        precommit_node(set->unode.opr.op[1]);
+        tmp = set->unode.opr.op[0];
+        
+        stmp[0] = 0;
+        if (set->unode.opr.op[0]->type == CONST_INT_NODE) {
+            sprintf(stmp,"_i_tmp_%i",allocateTemp());
+            gsl_int_decl_global(stmp);
+        }
+        else if (set->unode.opr.op[0]->type == CONST_FLOAT_NODE) {
+            sprintf(stmp,"_f_tmp%i",allocateTemp());
+            gsl_float_decl_global(stmp);
+        }
+        else if (set->unode.opr.op[0]->type == CONST_PTR_NODE) {
+            sprintf(stmp,"_p_tmp%i",allocateTemp());
+            gsl_ptr_decl_global(stmp);
+        }
+        if (stmp[0]) {
+            NodeType *tmpcpy;
+            tmp = new_var(stmp, set->line_number);
+            tmpcpy = nodeClone(tmp);
+            commit_node(new_set(tmp,set->unode.opr.op[0]),0);
+            tmp = tmpcpy;
+        }
+
+#ifdef VERBOSE
+        printf("%s %s %s\n", type, tmp->str, set->unode.opr.op[1]->str);
+#endif
+        currentGoomSL->instr = gsl_instr_init(currentGoomSL, type, instr, 2, set->line_number);
+        commit_node(tmp,instr!=INSTR_SET);
+        commit_node(set->unode.opr.op[1],1);
+    } /* }}} */
+    
+    /* NOT */
+    static NodeType *new_not(NodeType *expr1) { /* {{{ */
+        return new_expr1("not", OPR_NOT, expr1);
+    }
+    static void commit_not(NodeType *set)
+    {
+        commit_node(set->unode.opr.op[0],0);
+#ifdef VERBOSE
+        printf("not\n");
+#endif
+        currentGoomSL->instr = gsl_instr_init(currentGoomSL, "not", INSTR_NOT, 1, set->line_number);
+        gsl_instr_add_param(currentGoomSL->instr, "|dummy|", TYPE_LABEL);
+    } /* }}} */
+    
+    /* EQU */
+    static NodeType *new_equ(NodeType *expr1, NodeType *expr2) { /* {{{ */
+        return new_expr2("isequal", OPR_EQU, expr1, expr2);
+    }
+    static void commit_equ(NodeType *mul) {
+        commit_test2(mul,"isequal",INSTR_ISEQUAL);
+    } /* }}} */
+    
+    /* INF */
+    static NodeType *new_low(NodeType *expr1, NodeType *expr2) { /* {{{ */
+        return new_expr2("islower", OPR_LOW, expr1, expr2);
+    }
+    static void commit_low(NodeType *mul) {
+        commit_test2(mul,"islower",INSTR_ISLOWER);
+    } /* }}} */
+
+    /* WHILE */
+    static NodeType *new_while(NodeType *expression, NodeType *instr) { /* {{{ */
+        NodeType *node = new_op("while", OPR_WHILE, 2);
+        node->unode.opr.op[0] = expression;
+        node->unode.opr.op[1] = instr;
+        return node;
+    }
+
+    static void commit_while(NodeType *node)
+    {
+        int lbl = allocateLabel();
+        char start_while[1024], test_while[1024];
+        sprintf(start_while, "|start_while_%d|", lbl);
+        sprintf(test_while, "|test_while_%d|", lbl);
+       
+        GSL_PUT_JUMP(test_while,node->line_number);
+        GSL_PUT_LABEL(start_while,node->line_number);
+
+        /* code */
+        commit_node(node->unode.opr.op[1],0);
+
+        GSL_PUT_LABEL(test_while,node->line_number);
+        commit_node(node->unode.opr.op[0],0);
+        GSL_PUT_JNZERO(start_while,node->line_number);
+    } /* }}} */
+
+    /* FOR EACH */
+    static NodeType *new_static_foreach(NodeType *var, NodeType *var_list, NodeType *instr) { /* {{{ */
+        NodeType *node = new_op("for", OPR_FOREACH, 3);
+        node->unode.opr.op[0] = var;
+        node->unode.opr.op[1] = var_list;
+        node->unode.opr.op[2] = instr;
+        node->line_number = currentGoomSL->num_lines;
+        return node;
+    }
+    static void commit_foreach(NodeType *node)
+    {
+        NodeType *cur = node->unode.opr.op[1];
+        char tmp_func[256], tmp_loop[256];
+        int lbl = allocateLabel();
+        sprintf(tmp_func, "|foreach_func_%d|", lbl);
+        sprintf(tmp_loop, "|foreach_loop_%d|", lbl);
+
+        GSL_PUT_JUMP(tmp_loop, node->line_number);
+        GSL_PUT_LABEL(tmp_func, node->line_number);
+
+        precommit_node(node->unode.opr.op[2]);
+        commit_node(node->unode.opr.op[2], 0);
+
+        currentGoomSL->instr = gsl_instr_init(currentGoomSL, "ret", INSTR_RET, 1, node->line_number);
+        gsl_instr_add_param(currentGoomSL->instr, "|dummy|", TYPE_LABEL);
+#ifdef VERBOSE
+        printf("ret\n");
+#endif
+        
+        GSL_PUT_LABEL(tmp_loop, node->line_number);
+        
+        while (cur != NULL)
+        {
+          NodeType *x, *var;
+
+          /* 1: x=var */
+          x   = nodeClone(node->unode.opr.op[0]);
+          var = nodeClone(cur->unode.opr.op[0]);
+          commit_node(new_set(x, var),0);
+          
+          /* 2: instr */
+          currentGoomSL->instr = gsl_instr_init(currentGoomSL, "call", INSTR_CALL, 1, node->line_number);
+          gsl_instr_add_param(currentGoomSL->instr, tmp_func, TYPE_LABEL);
+#ifdef VERBOSE
+          printf("call %s\n", tmp_func);
+#endif
+          
+          /* 3: var=x */
+          x   = nodeClone(node->unode.opr.op[0]);
+          var = cur->unode.opr.op[0];
+          commit_node(new_set(var, x),0);
+          cur = cur->unode.opr.op[1];
+        }
+        nodeFree(node->unode.opr.op[0]);
+    } /* }}} */
+
+    /* IF */
+    static NodeType *new_if(NodeType *expression, NodeType *instr) { /* {{{ */
+        NodeType *node = new_op("if", OPR_IF, 2);
+        node->unode.opr.op[0] = expression;
+        node->unode.opr.op[1] = instr;
+        return node;
+    }
+    static void commit_if(NodeType *node) {
+
+        char slab[1024];
+        sprintf(slab, "|eif%d|", allocateLabel());
+        commit_node(node->unode.opr.op[0],0);
+        GSL_PUT_JZERO(slab,node->line_number);
+        /* code */
+        commit_node(node->unode.opr.op[1],0);
+        GSL_PUT_LABEL(slab,node->line_number);
+    } /* }}} */
+
+    /* BLOCK */
+    static NodeType *new_block(NodeType *lastNode) { /* {{{ */
+        NodeType *blk = new_op("block", OPR_BLOCK, 2);
+        blk->unode.opr.op[0] = new_nop("start_of_block");
+        blk->unode.opr.op[1] = lastNode;        
+        return blk;
+    }
+    static void commit_block(NodeType *node) {
+        commit_node(node->unode.opr.op[0]->unode.opr.next,0);
+    } /* }}} */
+
+    /* FUNCTION INTRO */
+    static NodeType *new_function_intro(const char *name) { /* {{{ */
+        char stmp[256];
+        if (strlen(name) < 200) {
+           sprintf(stmp, "|__func_%s|", name);
+        }
+        return new_op(stmp, OPR_FUNC_INTRO, 0);
+    }
+    static void commit_function_intro(NodeType *node) {
+        currentGoomSL->instr = gsl_instr_init(currentGoomSL, "label", INSTR_LABEL, 1, node->line_number);
+        gsl_instr_add_param(currentGoomSL->instr, node->str, TYPE_LABEL);
+#ifdef VERBOSE
+        printf("label %s\n", node->str);
+#endif
+    } /* }}} */
+
+    /* FUNCTION OUTRO */
+    static NodeType *new_function_outro() { /* {{{ */
+        return new_op("ret", OPR_FUNC_OUTRO, 0);
+    }
+    static void commit_function_outro(NodeType *node) {
+        currentGoomSL->instr = gsl_instr_init(currentGoomSL, "ret", INSTR_RET, 1, node->line_number);
+        gsl_instr_add_param(currentGoomSL->instr, "|dummy|", TYPE_LABEL);
+        releaseAllTemps();
+#ifdef VERBOSE
+        printf("ret\n");
+#endif
+    } /* }}} */
+    
+    /* AFFECTATION LIST */
+    static NodeType *new_affec_list(NodeType *set, NodeType *next) /* {{{ */
+    {
+      NodeType *node = new_op("affect_list", OPR_AFFECT_LIST, 2);
+      node->unode.opr.op[0] = set;
+      node->unode.opr.op[1] = next;
+      return node;
+    }
+    static NodeType *new_affect_list_after(NodeType *affect_list)
+    {
+      NodeType *ret  = NULL;
+      NodeType *cur  =  affect_list;
+      while(cur != NULL) {
+        NodeType *set  = cur->unode.opr.op[0];
+        NodeType *next = cur->unode.opr.op[1];
+        NodeType *lvalue     = set->unode.opr.op[0];
+        NodeType *expression = set->unode.opr.op[1];
+        if ((lvalue->str[0] == '&') && (expression->type == VAR_NODE)) {
+          NodeType *nset = new_set(nodeClone(expression), nodeClone(lvalue));
+          ret  = new_affec_list(nset, ret);
+        }
+        cur = next;
+      }
+      return ret;
+    }
+    static void commit_affect_list(NodeType *node)
+    {
+      NodeType *cur = node;
+      while(cur != NULL) {
+        NodeType *set = cur->unode.opr.op[0];
+        precommit_node(set->unode.opr.op[0]);
+        precommit_node(set->unode.opr.op[1]);
+        cur = cur->unode.opr.op[1];
+      }
+      cur = node;
+      while(cur != NULL) {
+        NodeType *set = cur->unode.opr.op[0];
+        commit_node(set,0);
+        cur = cur->unode.opr.op[1];
+      }
+    } /* }}} */
+
+    /* VAR LIST */
+    static NodeType *new_var_list(NodeType *var, NodeType *next) /* {{{ */
+    {
+      NodeType *node = new_op("var_list", OPR_VAR_LIST, 2);
+      node->unode.opr.op[0] = var;
+      node->unode.opr.op[1] = next;
+      return node;
+    }
+    static void commit_var_list(NodeType *node)
+    {
+    } /* }}} */
+
+    /* FUNCTION CALL */
+    static NodeType *new_call(const char *name, NodeType *affect_list) { /* {{{ */
+        HashValue *fval;
+        fval = goom_hash_get(currentGoomSL->functions, name);
+        if (!fval) {
+            gsl_declare_task(name);
+            fval = goom_hash_get(currentGoomSL->functions, name);
+        }
+        if (!fval) {
+            g_assert_not_reached ();
+#if 0
+            fprintf(stderr, "ERROR: Line %d, Could not find function %s\n", currentGoomSL->num_lines, name);
+            exit(1);
+            return NULL;
+#endif
+        }
+        else {
+            ExternalFunctionStruct *gef = (ExternalFunctionStruct*)fval->ptr;
+            if (gef->is_extern) {
+                NodeType *node =  new_op(name, OPR_EXT_CALL, 1);
+                node->unode.opr.op[0] = affect_list;
+                return node;
+            }
+            else {
+                NodeType *node;
+                char stmp[256];
+                if (strlen(name) < 200) {
+                    sprintf(stmp, "|__func_%s|", name);
+                }
+                node = new_op(stmp, OPR_CALL, 1);
+                node->unode.opr.op[0] = affect_list;
+                return node;
+            }
+        }
+    }
+    static void commit_ext_call(NodeType *node) {
+        NodeType *alafter = new_affect_list_after(node->unode.opr.op[0]);
+        commit_node(node->unode.opr.op[0],0);
+        currentGoomSL->instr = gsl_instr_init(currentGoomSL, "extcall", INSTR_EXT_CALL, 1, node->line_number);
+        gsl_instr_add_param(currentGoomSL->instr, node->str, TYPE_VAR);
+#ifdef VERBOSE
+        printf("extcall %s\n", node->str);
+#endif
+        commit_node(alafter,0);
+    }
+    static void commit_call(NodeType *node) {
+        NodeType *alafter = new_affect_list_after(node->unode.opr.op[0]);
+        commit_node(node->unode.opr.op[0],0);
+        currentGoomSL->instr = gsl_instr_init(currentGoomSL, "call", INSTR_CALL, 1, node->line_number);
+        gsl_instr_add_param(currentGoomSL->instr, node->str, TYPE_LABEL);
+#ifdef VERBOSE
+        printf("call %s\n", node->str);
+#endif
+        commit_node(alafter,0);
+    } /* }}} */
+
+    /** **/
+
+    static NodeType *rootNode = 0; /* TODO: reinitialiser a chaque compilation. */
+    static NodeType *lastNode = 0;
+    static NodeType *gsl_append(NodeType *curNode) {
+        if (curNode == 0) return 0; /* {{{ */
+        if (lastNode)
+            lastNode->unode.opr.next = curNode;
+        lastNode = curNode;
+        while(lastNode->unode.opr.next) lastNode = lastNode->unode.opr.next;
+        if (rootNode == 0)
+            rootNode = curNode;
+        return curNode;
+    } /* }}} */
+
+#if 1
+    int allocateTemp() {
+      return allocateLabel();
+    }
+    void releaseAllTemps() {}
+    void releaseTemp(int n) {}
+#else
+    static int nbTemp = 0;
+    static int *tempArray = 0;
+    static int tempArraySize = 0;
+    int allocateTemp() { /* TODO: allocateITemp, allocateFTemp */
+        int i = 0; /* {{{ */
+        if (tempArray == 0) {
+          tempArraySize = 256;
+          tempArray = (int*)malloc(tempArraySize * sizeof(int));
+        }
+        while (1) {
+          int j;
+          for (j=0;j<nbTemp;++j) {
+            if (tempArray[j] == i) break;
+          }
+          if (j == nbTemp) {
+            if (nbTemp == tempArraySize) {
+              tempArraySize *= 2;
+              tempArray = (int*)realloc(tempArray,tempArraySize * sizeof(int));
+            }
+            tempArray[nbTemp++] = i;
+            return i;
+          }
+          i++;
+        }
+    } /* }}} */
+    void releaseAllTemps() {
+      nbTemp = 0; /* {{{ */
+    } /* }}} */
+    void releaseTemp(int n) {
+      int j; /* {{{ */
+      for (j=0;j<nbTemp;++j) {
+        if (tempArray[j] == n) {
+          tempArray[j] = tempArray[--nbTemp];
+          break;
+        }
+      }
+    } /* }}} */
+#endif
+
+    static int lastLabel = 0;
+    int allocateLabel() {
+        return ++lastLabel; /* {{{ */
+    } /* }}} */
+
+    void gsl_commit_compilation()
+    { /* {{{ */
+        commit_node(rootNode,0);
+        rootNode = 0;
+        lastNode = 0;
+    } /* }}} */
+    
+    void precommit_node(NodeType *node)
+    { /* {{{ */
+        /* do here stuff for expression.. for exemple */
+        if (node->type == OPR_NODE)
+            switch(node->unode.opr.type) {
+                case OPR_ADD: precommit_add(node); break;
+                case OPR_SUB: precommit_sub(node); break;
+                case OPR_MUL: precommit_mul(node); break;
+                case OPR_DIV: precommit_div(node); break;
+                case OPR_CALL_EXPR: precommit_call_expr(node); break;
+            }
+    } /* }}} */
+    
+    void commit_node(NodeType *node, int releaseIfTmp)
+    { /* {{{ */
+        if (node == 0) return;
+        
+        switch(node->type) {
+            case OPR_NODE:
+                switch(node->unode.opr.type) {
+                    case OPR_SET:           commit_set(node); break;
+                    case OPR_PLUS_EQ:       commit_plus_eq(node); break;
+                    case OPR_SUB_EQ:        commit_sub_eq(node); break;
+                    case OPR_MUL_EQ:        commit_mul_eq(node); break;
+                    case OPR_DIV_EQ:        commit_div_eq(node); break;
+                    case OPR_IF:            commit_if(node); break;
+                    case OPR_WHILE:         commit_while(node); break;
+                    case OPR_BLOCK:         commit_block(node); break;
+                    case OPR_FUNC_INTRO:    commit_function_intro(node); break;
+                    case OPR_FUNC_OUTRO:    commit_function_outro(node); break;
+                    case OPR_CALL:          commit_call(node); break;
+                    case OPR_EXT_CALL:      commit_ext_call(node); break;
+                    case OPR_EQU:           commit_equ(node); break;
+                    case OPR_LOW:           commit_low(node); break;
+                    case OPR_NOT:           commit_not(node); break;
+                    case OPR_AFFECT_LIST:   commit_affect_list(node); break;
+                    case OPR_FOREACH:       commit_foreach(node); break;
+                    case OPR_VAR_LIST:      commit_var_list(node); break;
+#ifdef VERBOSE
+                    case EMPTY_NODE:        printf("NOP\n"); break;
+#endif
+                }
+
+                commit_node(node->unode.opr.next,0); /* recursive for the moment, maybe better to do something iterative? */
+                break;
+
+            case VAR_NODE:         gsl_instr_set_namespace(currentGoomSL->instr, node->vnamespace);
+                                   gsl_instr_add_param(currentGoomSL->instr, node->str, TYPE_VAR); break;
+            case CONST_INT_NODE:   gsl_instr_add_param(currentGoomSL->instr, node->str, TYPE_INTEGER); break;
+            case CONST_FLOAT_NODE: gsl_instr_add_param(currentGoomSL->instr, node->str, TYPE_FLOAT); break;
+            case CONST_PTR_NODE:   gsl_instr_add_param(currentGoomSL->instr, node->str, TYPE_PTR); break;
+        }
+        if (releaseIfTmp && is_tmp_expr(node))
+          releaseTemp(get_tmp_id(node));
+        
+        nodeFree(node);
+    } /* }}} */
+
+    NodeType *nodeNew(const char *str, int type, int line_number) {
+        NodeType *node = (NodeType*)malloc(sizeof(NodeType)); /* {{{ */
+        node->type = type;
+        node->str  = (char*)malloc(strlen(str)+1);
+        node->vnamespace = NULL;
+        node->line_number = line_number;
+        strcpy(node->str, str);
+        return node;
+    } /* }}} */
+    static NodeType *nodeClone(NodeType *node) {
+        NodeType *ret = nodeNew(node->str, node->type, node->line_number); /* {{{ */
+        ret->vnamespace = node->vnamespace;
+        ret->unode = node->unode;
+        return ret;
+    } /* }}} */
+
+    void nodeFreeInternals(NodeType *node) {
+        free(node->str); /* {{{ */
+    } /* }}} */
+    
+    void nodeFree(NodeType *node) {
+        nodeFreeInternals(node); /* {{{ */
+        free(node);
+    } /* }}} */
+
+    NodeType *new_constInt(const char *str, int line_number) {
+        NodeType *node = nodeNew(str, CONST_INT_NODE, line_number); /* {{{ */
+        node->unode.constInt.val = atoi(str);
+        return node;
+    } /* }}} */
+
+    NodeType *new_constPtr(const char *str, int line_number) {
+        NodeType *node = nodeNew(str, CONST_PTR_NODE, line_number); /* {{{ */
+        node->unode.constPtr.id = strtol(str,NULL,0);
+        return node;
+    } /* }}} */
+
+    NodeType *new_constFloat(const char *str, int line_number) {
+        NodeType *node = nodeNew(str, CONST_FLOAT_NODE, line_number); /* {{{ */
+        node->unode.constFloat.val = atof(str);
+        return node;
+    } /* }}} */
+
+    NodeType *new_var(const char *str, int line_number) {
+        NodeType *node = nodeNew(str, VAR_NODE, line_number); /* {{{ */
+        node->vnamespace = gsl_find_namespace(str);
+        if (node->vnamespace == 0) {
+            g_assert_not_reached ();
+#if 0
+            fprintf(stderr, "ERROR: Line %d, Variable not found: '%s'\n", line_number, str);
+            exit(1);
+#endif
+        }
+        return node;
+    } /* }}} */
+    
+    NodeType *new_nop(const char *str) {
+        NodeType *node = new_op(str, EMPTY_NODE, 0); /* {{{ */
+        return node;
+    } /* }}} */
+    
+    NodeType *new_op(const char *str, int type, int nbOp) {
+        int i; /* {{{ */
+        NodeType *node = nodeNew(str, OPR_NODE, currentGoomSL->num_lines);
+        node->unode.opr.next = 0;
+        node->unode.opr.type = type;
+        node->unode.opr.nbOp = nbOp;
+        for (i=0;i<nbOp;++i) node->unode.opr.op[i] = 0;
+        return node;
+    } /* }}} */
+
+
+    void gsl_declare_global_variable(int type, char *name) {
+      switch(type){
+        case -1: break;
+        case FLOAT_TK:gsl_float_decl_global(name);break;
+        case INT_TK:  gsl_int_decl_global(name);break;
+        case PTR_TK:  gsl_ptr_decl_global(name);break;
+        default:
+        {
+          int id = type - 1000;
+          gsl_struct_decl_global_from_id(name,id);
+        }
+      }
+    }
+
+%}
+
+%union {
+    int intValue;
+    float floatValue;
+    char charValue;
+    char strValue[2048];
+    NodeType *nPtr;
+    GoomHash *namespace;
+    GSL_Struct *gsl_struct;
+    GSL_StructField *gsl_struct_field;
+  };
+  
+%token <strValue>   LTYPE_INTEGER
+%token <strValue>   LTYPE_FLOAT
+%token <strValue>   LTYPE_VAR
+%token <strValue>   LTYPE_PTR
+
+%token PTR_TK INT_TK FLOAT_TK DECLARE EXTERNAL WHILE DO NOT PLUS_EQ SUB_EQ DIV_EQ MUL_EQ SUP_EQ LOW_EQ NOT_EQ STRUCT FOR IN
+
+%type <intValue> return_type
+%type <nPtr> expression constValue instruction test func_call func_call_expression
+%type <nPtr> start_block affectation_list affectation_in_list affectation declaration
+%type <nPtr> var_list_content var_list
+%type <strValue> task_name ext_task_name 
+%type <namespace> leave_namespace
+%type <gsl_struct> struct_members
+%type <gsl_struct_field> struct_member
+%left '\n'
+%left PLUS_EQ SUB_EQ MUL_EQ DIV_EQ
+%left NOT
+%left '=' '<' '>'
+%left '+' '-'
+%left '/' '*'
+
+%%
+
+/* -------------- Global architechture of a GSL program ------------*/
+
+gsl: gsl_code function_outro gsl_def_functions ;
+
+gsl_code: gsl_code instruction              { gsl_append($2); }
+   | gsl_code EXTERNAL '<' ext_task_name '>' return_type '\n' leave_namespace             { gsl_declare_global_variable($6,$4); }
+   | gsl_code EXTERNAL '<' ext_task_name ':' arglist '>' return_type '\n' leave_namespace { gsl_declare_global_variable($8,$4); }
+   | gsl_code DECLARE '<' task_name '>' return_type  '\n' leave_namespace                 { gsl_declare_global_variable($6,$4); }
+   | gsl_code DECLARE '<' task_name ':' arglist '>' return_type '\n' leave_namespace      { gsl_declare_global_variable($8,$4); }
+   | gsl_code struct_declaration
+   | gsl_code '\n'
+   |
+   ;
+
+/* ------------- Declaration of a structure ------------ */
+
+struct_declaration: STRUCT  '<' LTYPE_VAR  ':' struct_members '>' '\n' { gsl_add_struct($3, $5); }
+                  ;
+
+struct_members: opt_nl struct_member                    { $$ = gsl_new_struct($2);               }
+              | struct_members ',' opt_nl struct_member { $$ = $1; gsl_add_struct_field($1, $4); }
+              ;
+
+struct_member: INT_TK    LTYPE_VAR { $$ = gsl_new_struct_field($2, INSTR_INT); }
+             | FLOAT_TK  LTYPE_VAR { $$ = gsl_new_struct_field($2, INSTR_FLOAT); }
+             | PTR_TK    LTYPE_VAR { $$ = gsl_new_struct_field($2, INSTR_PTR); }
+             | LTYPE_VAR LTYPE_VAR { $$ = gsl_new_struct_field_struct($2, $1); }
+             ;
+
+/* ------------- Fonction declarations -------------- */
+
+ext_task_name: LTYPE_VAR { gsl_declare_external_task($1); gsl_enternamespace($1); strcpy($$,$1); }
+             ;
+task_name:     LTYPE_VAR { gsl_declare_task($1); gsl_enternamespace($1); strcpy($$,$1); strcpy($$,$1); }
+         ;
+
+return_type:      { $$=-1; }
+  | ':' INT_TK    { $$=INT_TK; }
+  | ':' FLOAT_TK  { $$=FLOAT_TK; }
+  | ':' PTR_TK    { $$=PTR_TK; }
+  | ':' LTYPE_VAR { $$= 1000 + gsl_get_struct_id($2); }
+  ;
+
+arglist: empty_declaration
+       | empty_declaration ',' arglist
+       ;
+
+/* ------------- Fonction definition -------------- */
+
+gsl_def_functions: gsl_def_functions function
+                 |
+                 ;
+
+function: function_intro gsl_code function_outro { gsl_leavenamespace(); }
+
+function_intro: '<' task_name '>' return_type '\n'             { gsl_append(new_function_intro($2));
+                                                                 gsl_declare_global_variable($4,$2); }
+              | '<' task_name ':' arglist '>' return_type '\n' { gsl_append(new_function_intro($2));
+                                                                 gsl_declare_global_variable($6,$2); }
+              ;
+function_outro: { gsl_append(new_function_outro()); } ;
+
+leave_namespace:      { $$ = gsl_leavenamespace();   };
+
+/* ------------ Variable declaration ---------------- */
+
+declaration: FLOAT_TK LTYPE_VAR '=' expression { gsl_float_decl_local($2); $$ = new_set(new_var($2,currentGoomSL->num_lines), $4); }
+           | INT_TK   LTYPE_VAR '=' expression { gsl_int_decl_local($2);   $$ = new_set(new_var($2,currentGoomSL->num_lines), $4); }
+           | PTR_TK   LTYPE_VAR '=' expression { gsl_ptr_decl_local($2);   $$ = new_set(new_var($2,currentGoomSL->num_lines), $4); }
+           | LTYPE_VAR LTYPE_VAR '=' expression { gsl_struct_decl_local($1,$2); $$ = new_set(new_var($2,currentGoomSL->num_lines), $4); }
+           | empty_declaration                { $$ = 0; }
+           ;
+
+empty_declaration: FLOAT_TK  LTYPE_VAR { gsl_float_decl_local($2);       }
+                 | INT_TK    LTYPE_VAR { gsl_int_decl_local($2);         }
+                 | PTR_TK    LTYPE_VAR { gsl_ptr_decl_local($2);         }
+                 | LTYPE_VAR LTYPE_VAR { gsl_struct_decl_local($1,$2);   }
+                 ;
+
+/* -------------- Instructions and Expressions ------------------ */
+
+instruction: affectation '\n' { $$ = $1; }
+           | declaration '\n' { $$ = $1; }
+           | '(' test ')' '?' opt_nl instruction     { $$ = new_if($2,$6); }
+           | WHILE test opt_nl DO opt_nl instruction { $$ = new_while($2,$6); }
+           | '{' '\n' start_block gsl_code '}' '\n'  { lastNode = $3->unode.opr.op[1]; $$=$3; }
+           | func_call                               { $$ = $1; }
+           | LTYPE_VAR PLUS_EQ expression { $$ = new_plus_eq(new_var($1,currentGoomSL->num_lines),$3); }
+           | LTYPE_VAR SUB_EQ expression  { $$ = new_sub_eq(new_var($1,currentGoomSL->num_lines),$3); }
+           | LTYPE_VAR MUL_EQ expression  { $$ = new_mul_eq(new_var($1,currentGoomSL->num_lines),$3); }
+           | LTYPE_VAR DIV_EQ expression  { $$ = new_div_eq(new_var($1,currentGoomSL->num_lines),$3); }
+           | FOR LTYPE_VAR IN var_list DO instruction { $$ = new_static_foreach(new_var($2, currentGoomSL->num_lines), $4, $6); }
+           ;
+
+var_list: '(' var_list_content ')'      { $$ = $2; }
+        ;
+var_list_content: LTYPE_VAR             { $$ = new_var_list(new_var($1,currentGoomSL->num_lines), NULL); }
+           | LTYPE_VAR var_list_content { $$ = new_var_list(new_var($1,currentGoomSL->num_lines), $2);   }
+           ;
+
+affectation: LTYPE_VAR '=' expression { $$ = new_set(new_var($1,currentGoomSL->num_lines),$3); } ;
+
+start_block: { $$ = new_block(lastNode); lastNode = $$->unode.opr.op[0]; }
+           ;
+
+expression: LTYPE_VAR   { $$ = new_var($1,currentGoomSL->num_lines); }
+          | constValue  { $$ = $1; }
+          | expression '*' expression { $$ = new_mul($1,$3); } 
+          | expression '/' expression { $$ = new_div($1,$3); } 
+          | expression '+' expression { $$ = new_add($1,$3); } 
+          | expression '-' expression { $$ = new_sub($1,$3); } 
+          | '-' expression            { $$ = new_neg($2);    }
+          | '(' expression ')'        { $$ = $2; }
+          | func_call_expression      { $$ = $1; }
+          ;
+
+test: expression '=' expression { $$ = new_equ($1,$3); } 
+    | expression '<' expression { $$ = new_low($1,$3); } 
+    | expression '>' expression { $$ = new_low($3,$1); }
+    | expression SUP_EQ expression { $$ = new_not(new_low($1,$3)); }
+    | expression LOW_EQ expression { $$ = new_not(new_low($3,$1)); }
+    | expression NOT_EQ expression { $$ = new_not(new_equ($1,$3)); }
+    | NOT test                  { $$ = new_not($2);    }
+    ;
+
+constValue: LTYPE_FLOAT   { $$ = new_constFloat($1,currentGoomSL->num_lines); }
+          | LTYPE_INTEGER { $$ = new_constInt($1,currentGoomSL->num_lines); } 
+          | LTYPE_PTR     { $$ = new_constPtr($1,currentGoomSL->num_lines); } 
+          ;
+
+/* ---------------- Function Calls ------------------ */
+
+func_call:   task_name '\n' leave_namespace                          { $$ = new_call($1,NULL); }
+           | task_name ':' affectation_list '\n' leave_namespace         { $$ = new_call($1,$3); }
+           | '[' task_name ']' '\n' leave_namespace                  { $$ = new_call($2,NULL); }
+           | '[' task_name ':' affectation_list ']' '\n' leave_namespace { $$ = new_call($2,$4); }
+           ;
+
+func_call_expression:
+            '[' task_name leave_namespace ']'                      { $$ = new_call_expr($2,NULL); }
+          | '[' task_name ':' affectation_list ']' leave_namespace { $$ = new_call_expr($2,$4); }
+          ;
+             
+affectation_list: affectation_in_list affectation_list     { $$ = new_affec_list($1,$2);   }
+            | affectation_in_list                          { $$ = new_affec_list($1,NULL); }
+
+affectation_in_list: LTYPE_VAR '=' leave_namespace expression {
+                              gsl_reenternamespace($3);
+                              $$ = new_set(new_var($1,currentGoomSL->num_lines),$4);
+                            }
+                   | ':' leave_namespace expression {
+                              gsl_reenternamespace($2);
+                              $$ = new_set(new_var("&this", currentGoomSL->num_lines),$3);
+                            }
+                   ;
+
+
+/* ------------ Misc ---------- */
+
+opt_nl: '\n' | ;
+           
+
+%%
+
+
+void yyerror(char *str)
+{ /* {{{ */
+    g_assert_not_reached ();
+#if 0
+    fprintf(stderr, "ERROR: Line %d, %s\n", currentGoomSL->num_lines, str);
+    currentGoomSL->compilationOK = 0;
+    exit(1);
+#endif
+} /* }}} */
+
diff --git a/gst/goom/graphic.c b/gst/goom/graphic.c
new file mode 100644
index 0000000..9f30448
--- /dev/null
+++ b/gst/goom/graphic.c
@@ -0,0 +1,28 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "goom_graphic.h"
+
+const Color BLACK = { 0, 0, 0 };
+const Color WHITE = { 0xff, 0xff, 0xff };
+const Color RED = { 0xff, 0x05, 0x05 };
+const Color GREEN = { 0x05, 0xff, 0x05 };
+const Color BLUE = { 0x05, 0x05, 0xff };
+const Color YELLOW = { 0xff, 0xff, 0x33 };
+const Color ORANGE = { 0xff, 0xcc, 0x05 };
+const Color VIOLET = { 0x55, 0x05, 0xff };
diff --git a/gst/goom/gstgoom.c b/gst/goom/gstgoom.c
new file mode 100644
index 0000000..dbbe941
--- /dev/null
+++ b/gst/goom/gstgoom.c
@@ -0,0 +1,210 @@
+/* gstgoom.c: implementation of goom drawing element
+ * Copyright (C) <2001> Richard Boulton <richard@tartarus.org>
+ *           (C) <2006> Wim Taymans <wim at fluendo dot com>
+ *           (C) <2011> Wim Taymans <wim.taymans at gmail dot com>
+ *           (C) <2015> Luis de Bethencourt <luis@debethencourt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-goom
+ * @see_also: synaesthesia
+ *
+ * Goom is an audio visualisation element. It creates warping structures
+ * based on the incoming audio signal.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! goom ! videoconvert ! xvimagesink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include "gstgoom.h"
+#include "goom.h"
+
+#if HAVE_ORC
+#include <orc/orc.h>
+#endif
+
+GST_DEBUG_CATEGORY (goom_debug);
+#define GST_CAT_DEFAULT goom_debug
+
+#define DEFAULT_WIDTH  320
+#define DEFAULT_HEIGHT 240
+
+/* signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  ARG_0
+      /* FILL ME */
+};
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+#define RGB_ORDER "xRGB"
+#else
+#define RGB_ORDER "BGRx"
+#endif
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (RGB_ORDER))
+    );
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",    /* the name of the pads */
+    GST_PAD_SINK,               /* type of the pad */
+    GST_PAD_ALWAYS,             /* ALWAYS/SOMETIMES */
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (S16) ", "
+        "rate = (int) [ 8000, 96000 ], "
+        "channels = (int) 1, "
+        "layout = (string) interleaved; "
+        "audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (S16) ", "
+        "rate = (int) [ 8000, 96000 ], "
+        "channels = (int) 2, "
+        "channel-mask = (bitmask) 0x3, " "layout = (string) interleaved")
+    );
+
+
+static void gst_goom_finalize (GObject * object);
+
+static gboolean gst_goom_setup (GstAudioVisualizer * base);
+static gboolean gst_goom_render (GstAudioVisualizer * base, GstBuffer * audio,
+    GstVideoFrame * video);
+
+G_DEFINE_TYPE (GstGoom, gst_goom, GST_TYPE_AUDIO_VISUALIZER);
+
+static void
+gst_goom_class_init (GstGoomClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstAudioVisualizerClass *visualizer_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  visualizer_class = (GstAudioVisualizerClass *) klass;
+
+  gobject_class->finalize = gst_goom_finalize;
+
+  gst_element_class_set_static_metadata (gstelement_class, "GOOM: what a GOOM!",
+      "Visualization",
+      "Takes frames of data and outputs video frames using the GOOM filter",
+      "Wim Taymans <wim@fluendo.com>");
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class, &src_template);
+
+  visualizer_class->setup = GST_DEBUG_FUNCPTR (gst_goom_setup);
+  visualizer_class->render = GST_DEBUG_FUNCPTR (gst_goom_render);
+}
+
+static void
+gst_goom_init (GstGoom * goom)
+{
+  goom->width = DEFAULT_WIDTH;
+  goom->height = DEFAULT_HEIGHT;
+  goom->channels = 0;
+
+  goom->plugin = goom_init (goom->width, goom->height);
+}
+
+static void
+gst_goom_finalize (GObject * object)
+{
+  GstGoom *goom = GST_GOOM (object);
+
+  goom_close (goom->plugin);
+  goom->plugin = NULL;
+
+  G_OBJECT_CLASS (gst_goom_parent_class)->finalize (object);
+}
+
+static gboolean
+gst_goom_setup (GstAudioVisualizer * base)
+{
+  GstGoom *goom = GST_GOOM (base);
+
+  goom->width = GST_VIDEO_INFO_WIDTH (&base->vinfo);
+  goom->height = GST_VIDEO_INFO_HEIGHT (&base->vinfo);
+  goom_set_resolution (goom->plugin, goom->width, goom->height);
+
+  return TRUE;
+}
+
+static gboolean
+gst_goom_render (GstAudioVisualizer * base, GstBuffer * audio,
+    GstVideoFrame * video)
+{
+  GstGoom *goom = GST_GOOM (base);
+  GstMapInfo amap;
+  gint16 datain[2][GOOM_SAMPLES];
+  gint16 *adata;
+  gint i;
+
+  /* get next GOOM_SAMPLES, we have at least this amount of samples */
+  gst_buffer_map (audio, &amap, GST_MAP_READ);
+  adata = (gint16 *) amap.data;
+
+  if (goom->channels == 2) {
+    for (i = 0; i < GOOM_SAMPLES; i++) {
+      datain[0][i] = *adata++;
+      datain[1][i] = *adata++;
+    }
+  } else {
+    for (i = 0; i < GOOM_SAMPLES; i++) {
+      datain[0][i] = *adata;
+      datain[1][i] = *adata++;
+    }
+  }
+
+  video->data[0] = goom_update (goom->plugin, datain, 0, 0);
+  gst_buffer_unmap (audio, &amap);
+
+  return TRUE;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (goom_debug, "goom", 0, "goom visualisation element");
+
+#if HAVE_ORC
+  orc_init ();
+#endif
+
+  return gst_element_register (plugin, "goom", GST_RANK_NONE, GST_TYPE_GOOM);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    goom,
+    "GOOM visualization filter",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/goom/gstgoom.h b/gst/goom/gstgoom.h
new file mode 100644
index 0000000..25975dd
--- /dev/null
+++ b/gst/goom/gstgoom.h
@@ -0,0 +1,67 @@
+/* gstgoom.c: implementation of goom drawing element
+ * Copyright (C) <2001> Richard Boulton <richard@tartarus.org>
+ * Copyright (C) <2015> Luis de Bethencourt <luis@debethencourt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_GOOM_H__
+#define __GST_GOOM_H__
+
+#include <gst/pbutils/gstaudiovisualizer.h>
+
+#include "goom.h"
+
+G_BEGIN_DECLS
+
+#define GOOM_SAMPLES 512
+
+#define GST_TYPE_GOOM            (gst_goom_get_type())
+#define GST_GOOM(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GOOM,GstGoom))
+#define GST_GOOM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GOOM,GstGoomClass))
+#define GST_IS_GOOM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GOOM))
+#define GST_IS_GOOM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GOOM))
+
+typedef struct _GstGoom GstGoom;
+typedef struct _GstGoomClass GstGoomClass;
+
+struct _GstGoom
+{
+  GstAudioVisualizer parent;
+
+  /* input tracking */
+  gint channels;
+
+  /* video state */
+  gint width;
+  gint height;
+
+  /* goom stuff */
+  PluginInfo *plugin;
+};
+
+struct _GstGoomClass
+{
+  GstAudioVisualizerClass parent_class;
+};
+
+GType gst_goom_get_type (void);
+gboolean gst_goom_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_GOOM_H__ */
+
diff --git a/gst/goom/ifs.c b/gst/goom/ifs.c
new file mode 100644
index 0000000..5438e31
--- /dev/null
+++ b/gst/goom/ifs.c
@@ -0,0 +1,774 @@
+/*-
+ * Copyright (c) 1997 by Massimino Pascal <Pascal.Massimon@ens.fr>
+ *
+ * ifs.c: modified iterated functions system for goom.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * This file is provided AS IS with no warranties of any kind.  The author
+ * shall have no liability with respect to the infringement of copyrights,
+ * trade secrets or any patents by this file or any part thereof.  In no
+ * event will the author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages.
+ *
+ * If this mode is weird and you have an old MetroX server, it is buggy.
+ * There is a free SuSE-enhanced MetroX X server that is fine.
+ *
+ * When shown ifs, Diana Rose (4 years old) said, "It looks like dancing."
+ *
+ * Revision History:
+ * 13-Dec-2003: Added some goom specific stuffs (to make ifs a VisualFX).
+ * 11-Apr-2002: jeko@ios-software.com: Make ifs.c system-indendant. (ifs.h added)
+ * 01-Nov-2000: Allocation checks
+ * 10-May-1997: jwz@jwz.org: turned into a standalone program.
+ *              Made it render into an offscreen bitmap and then copy
+ *              that onto the screen, to reduce flicker.
+ */
+
+/* #ifdef STANDALONE */
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "goom_config.h"
+
+#ifdef HAVE_MMX
+#include "mmx.h"
+#endif
+
+#include "goom_graphic.h"
+#include "ifs.h"
+#include "goom_tools.h"
+
+typedef struct _ifsPoint
+{
+  gint32 x, y;
+}
+IFSPoint;
+
+
+#define MODE_ifs
+
+#define PROGCLASS "IFS"
+
+#define HACK_INIT init_ifs
+#define HACK_DRAW draw_ifs
+
+#define ifs_opts xlockmore_opts
+
+#define DEFAULTS "*delay: 20000 \n" \
+"*ncolors: 100 \n"
+
+#define SMOOTH_COLORS
+
+#define LRAND()            ((long) (goom_random(goomInfo->gRandom) & 0x7fffffff))
+#define NRAND(n)           ((int) (LRAND() % (n)))
+
+#if RAND_MAX < 0x10000
+#define MAXRAND (((float)(RAND_MAX<16)+((float)RAND_MAX)+1.0f)/127.0f)
+#else
+#define MAXRAND            (2147483648.0/127.0) /* unsigned 1<<31 / 127.0 (cf goom_tools) as a float */
+#endif
+
+/*****************************************************/
+
+typedef float DBL;
+typedef int F_PT;
+
+/* typedef float               F_PT; */
+
+/*****************************************************/
+
+#define FIX 12
+#define UNIT   ( 1<<FIX )
+#define MAX_SIMI  6
+
+#define MAX_DEPTH_2  10
+#define MAX_DEPTH_3  6
+#define MAX_DEPTH_4  4
+#define MAX_DEPTH_5  2
+
+/* PREVIOUS VALUE 
+#define MAX_SIMI  6
+
+ * settings for a PC 120Mhz... *
+#define MAX_DEPTH_2  10
+#define MAX_DEPTH_3  6
+#define MAX_DEPTH_4  4
+#define MAX_DEPTH_5  3
+*/
+
+#define DBL_To_F_PT(x)  (F_PT)( (DBL)(UNIT)*(x) )
+
+typedef struct Similitude_Struct SIMI;
+typedef struct Fractal_Struct FRACTAL;
+
+struct Similitude_Struct
+{
+
+  DBL c_x, c_y;
+  DBL r, r2, A, A2;
+  F_PT Ct, St, Ct2, St2;
+  F_PT Cx, Cy;
+  F_PT R, R2;
+};
+
+
+struct Fractal_Struct
+{
+
+  int Nb_Simi;
+  SIMI Components[5 * MAX_SIMI];
+  int Depth, Col;
+  int Count, Speed;
+  int Width, Height, Lx, Ly;
+  DBL r_mean, dr_mean, dr2_mean;
+  int Cur_Pt, Max_Pt;
+
+  IFSPoint *Buffer1, *Buffer2;
+};
+
+typedef struct _IFS_DATA
+{
+  FRACTAL *Root;
+  FRACTAL *Cur_F;
+
+  /* Used by the Trace recursive method */
+  IFSPoint *Buf;
+  int Cur_Pt;
+  int initalized;
+} IfsData;
+
+
+/*****************************************************/
+
+static DBL
+Gauss_Rand (PluginInfo * goomInfo, DBL c, DBL A, DBL S)
+{
+  DBL y;
+
+  y = (DBL) LRAND () / MAXRAND;
+  y = A * (1.0 - exp (-y * y * S)) / (1.0 - exp (-S));
+  if (NRAND (2))
+    return (c + y);
+  return (c - y);
+}
+
+static DBL
+Half_Gauss_Rand (PluginInfo * goomInfo, DBL c, DBL A, DBL S)
+{
+  DBL y;
+
+  y = (DBL) LRAND () / MAXRAND;
+  y = A * (1.0 - exp (-y * y * S)) / (1.0 - exp (-S));
+  return (c + y);
+}
+
+static void
+Random_Simis (PluginInfo * goomInfo, FRACTAL * F, SIMI * Cur, int i)
+{
+  while (i--) {
+    Cur->c_x = Gauss_Rand (goomInfo, 0.0, .8, 4.0);
+    Cur->c_y = Gauss_Rand (goomInfo, 0.0, .8, 4.0);
+    Cur->r = Gauss_Rand (goomInfo, F->r_mean, F->dr_mean, 3.0);
+    Cur->r2 = Half_Gauss_Rand (goomInfo, 0.0, F->dr2_mean, 2.0);
+    Cur->A = Gauss_Rand (goomInfo, 0.0, 360.0, 4.0) * (G_PI / 180.0);
+    Cur->A2 = Gauss_Rand (goomInfo, 0.0, 360.0, 4.0) * (G_PI / 180.0);
+    Cur++;
+  }
+}
+
+static void
+free_ifs_buffers (FRACTAL * Fractal)
+{
+  if (Fractal->Buffer1 != NULL) {
+    (void) free ((void *) Fractal->Buffer1);
+    Fractal->Buffer1 = (IFSPoint *) NULL;
+  }
+  if (Fractal->Buffer2 != NULL) {
+    (void) free ((void *) Fractal->Buffer2);
+    Fractal->Buffer2 = (IFSPoint *) NULL;
+  }
+}
+
+
+static void
+free_ifs (FRACTAL * Fractal)
+{
+  free_ifs_buffers (Fractal);
+}
+
+/***************************************************************/
+
+static void
+init_ifs (PluginInfo * goomInfo, IfsData * data)
+{
+  int i;
+  FRACTAL *Fractal;
+  int width = goomInfo->screen.width;
+  int height = goomInfo->screen.height;
+
+  if (data->Root == NULL) {
+    data->Root = (FRACTAL *) malloc (sizeof (FRACTAL));
+    if (data->Root == NULL)
+      return;
+    data->Root->Buffer1 = (IFSPoint *) NULL;
+    data->Root->Buffer2 = (IFSPoint *) NULL;
+  }
+  Fractal = data->Root;
+
+  free_ifs_buffers (Fractal);
+
+  i = (NRAND (4)) + 2;          /* Number of centers */
+  switch (i) {
+    case 3:
+      Fractal->Depth = MAX_DEPTH_3;
+      Fractal->r_mean = .6;
+      Fractal->dr_mean = .4;
+      Fractal->dr2_mean = .3;
+      break;
+
+    case 4:
+      Fractal->Depth = MAX_DEPTH_4;
+      Fractal->r_mean = .5;
+      Fractal->dr_mean = .4;
+      Fractal->dr2_mean = .3;
+      break;
+
+    case 5:
+      Fractal->Depth = MAX_DEPTH_5;
+      Fractal->r_mean = .5;
+      Fractal->dr_mean = .4;
+      Fractal->dr2_mean = .3;
+      break;
+
+    default:
+    case 2:
+      Fractal->Depth = MAX_DEPTH_2;
+      Fractal->r_mean = .7;
+      Fractal->dr_mean = .3;
+      Fractal->dr2_mean = .4;
+      break;
+  }
+  Fractal->Nb_Simi = i;
+  Fractal->Max_Pt = Fractal->Nb_Simi - 1;
+  for (i = 0; i <= Fractal->Depth + 2; ++i)
+    Fractal->Max_Pt *= Fractal->Nb_Simi;
+
+  if ((Fractal->Buffer1 = (IFSPoint *) calloc (Fractal->Max_Pt,
+              sizeof (IFSPoint))) == NULL) {
+    free_ifs (Fractal);
+    return;
+  }
+  if ((Fractal->Buffer2 = (IFSPoint *) calloc (Fractal->Max_Pt,
+              sizeof (IFSPoint))) == NULL) {
+    free_ifs (Fractal);
+    return;
+  }
+
+  Fractal->Speed = 6;
+  Fractal->Width = width;       /* modif by JeKo */
+  Fractal->Height = height;     /* modif by JeKo */
+  Fractal->Cur_Pt = 0;
+  Fractal->Count = 0;
+  Fractal->Lx = (Fractal->Width - 1) / 2;
+  Fractal->Ly = (Fractal->Height - 1) / 2;
+  Fractal->Col = rand () % (width * height);    /* modif by JeKo */
+
+  Random_Simis (goomInfo, Fractal, Fractal->Components, 5 * MAX_SIMI);
+}
+
+
+/***************************************************************/
+
+static inline void
+Transform (SIMI * Simi, F_PT xo, F_PT yo, F_PT * x, F_PT * y)
+{
+  F_PT xx, yy;
+
+  xo = xo - Simi->Cx;
+  xo = (xo * Simi->R) >> FIX;   /* / UNIT; */
+  yo = yo - Simi->Cy;
+  yo = (yo * Simi->R) >> FIX;   /* / UNIT; */
+
+  xx = xo - Simi->Cx;
+  xx = (xx * Simi->R2) >> FIX;  /* / UNIT; */
+  yy = -yo - Simi->Cy;
+  yy = (yy * Simi->R2) >> FIX;  /* / UNIT; */
+
+  *x = ((xo * Simi->Ct - yo * Simi->St + xx * Simi->Ct2 - yy * Simi->St2)
+      >> FIX /* / UNIT */ ) + Simi->Cx;
+  *y = ((xo * Simi->St + yo * Simi->Ct + xx * Simi->St2 + yy * Simi->Ct2)
+      >> FIX /* / UNIT */ ) + Simi->Cy;
+}
+
+/***************************************************************/
+
+static void
+Trace (FRACTAL * F, F_PT xo, F_PT yo, IfsData * data)
+{
+  F_PT x, y, i;
+  SIMI *Cur;
+
+  Cur = data->Cur_F->Components;
+  for (i = data->Cur_F->Nb_Simi; i; --i, Cur++) {
+    Transform (Cur, xo, yo, &x, &y);
+
+    data->Buf->x = F->Lx + ((x * F->Lx) >> (FIX + 1) /* /(UNIT*2) */ );
+    data->Buf->y = F->Ly - ((y * F->Ly) >> (FIX + 1) /* /(UNIT*2) */ );
+    data->Buf++;
+
+    data->Cur_Pt++;
+
+    if (F->Depth && ((x - xo) >> 4) && ((y - yo) >> 4)) {
+      F->Depth--;
+      Trace (F, x, y, data);
+      F->Depth++;
+    }
+  }
+}
+
+static void
+Draw_Fractal (IfsData * data)
+{
+  FRACTAL *F = data->Root;
+  int i, j;
+  F_PT x, y, xo, yo;
+  SIMI *Cur, *Simi;
+
+  for (Cur = F->Components, i = F->Nb_Simi; i; --i, Cur++) {
+    Cur->Cx = DBL_To_F_PT (Cur->c_x);
+    Cur->Cy = DBL_To_F_PT (Cur->c_y);
+
+    Cur->Ct = DBL_To_F_PT (cos (Cur->A));
+    Cur->St = DBL_To_F_PT (sin (Cur->A));
+    Cur->Ct2 = DBL_To_F_PT (cos (Cur->A2));
+    Cur->St2 = DBL_To_F_PT (sin (Cur->A2));
+
+    Cur->R = DBL_To_F_PT (Cur->r);
+    Cur->R2 = DBL_To_F_PT (Cur->r2);
+  }
+
+
+  data->Cur_Pt = 0;
+  data->Cur_F = F;
+  data->Buf = F->Buffer2;
+  for (Cur = F->Components, i = F->Nb_Simi; i; --i, Cur++) {
+    xo = Cur->Cx;
+    yo = Cur->Cy;
+    for (Simi = F->Components, j = F->Nb_Simi; j; --j, Simi++) {
+      if (Simi == Cur)
+        continue;
+      Transform (Simi, xo, yo, &x, &y);
+      Trace (F, x, y, data);
+    }
+  }
+
+  /* Erase previous */
+
+  F->Cur_Pt = data->Cur_Pt;
+  data->Buf = F->Buffer1;
+  F->Buffer1 = F->Buffer2;
+  F->Buffer2 = data->Buf;
+}
+
+
+static IFSPoint *
+draw_ifs (PluginInfo * goomInfo, int *nbpt, IfsData * data)
+{
+  int i;
+  DBL u, uu, v, vv, u0, u1, u2, u3;
+  SIMI *S, *S1, *S2, *S3, *S4;
+  FRACTAL *F;
+
+  if (data->Root == NULL)
+    return NULL;
+  F = data->Root;
+  if (F->Buffer1 == NULL)
+    return NULL;
+
+  u = (DBL) (F->Count) * (DBL) (F->Speed) / 1000.0;
+  uu = u * u;
+  v = 1.0 - u;
+  vv = v * v;
+  u0 = vv * v;
+  u1 = 3.0 * vv * u;
+  u2 = 3.0 * v * uu;
+  u3 = u * uu;
+
+  S = F->Components;
+  S1 = S + F->Nb_Simi;
+  S2 = S1 + F->Nb_Simi;
+  S3 = S2 + F->Nb_Simi;
+  S4 = S3 + F->Nb_Simi;
+
+  for (i = F->Nb_Simi; i; --i, S++, S1++, S2++, S3++, S4++) {
+    S->c_x = u0 * S1->c_x + u1 * S2->c_x + u2 * S3->c_x + u3 * S4->c_x;
+    S->c_y = u0 * S1->c_y + u1 * S2->c_y + u2 * S3->c_y + u3 * S4->c_y;
+    S->r = u0 * S1->r + u1 * S2->r + u2 * S3->r + u3 * S4->r;
+    S->r2 = u0 * S1->r2 + u1 * S2->r2 + u2 * S3->r2 + u3 * S4->r2;
+    S->A = u0 * S1->A + u1 * S2->A + u2 * S3->A + u3 * S4->A;
+    S->A2 = u0 * S1->A2 + u1 * S2->A2 + u2 * S3->A2 + u3 * S4->A2;
+  }
+
+  Draw_Fractal (data);
+
+  if (F->Count >= 1000 / F->Speed) {
+    S = F->Components;
+    S1 = S + F->Nb_Simi;
+    S2 = S1 + F->Nb_Simi;
+    S3 = S2 + F->Nb_Simi;
+    S4 = S3 + F->Nb_Simi;
+
+    for (i = F->Nb_Simi; i; --i, S++, S1++, S2++, S3++, S4++) {
+      S2->c_x = 2.0 * S4->c_x - S3->c_x;
+      S2->c_y = 2.0 * S4->c_y - S3->c_y;
+      S2->r = 2.0 * S4->r - S3->r;
+      S2->r2 = 2.0 * S4->r2 - S3->r2;
+      S2->A = 2.0 * S4->A - S3->A;
+      S2->A2 = 2.0 * S4->A2 - S3->A2;
+
+      *S1 = *S4;
+    }
+    Random_Simis (goomInfo, F, F->Components + 3 * F->Nb_Simi, F->Nb_Simi);
+
+    Random_Simis (goomInfo, F, F->Components + 4 * F->Nb_Simi, F->Nb_Simi);
+
+    F->Count = 0;
+  } else
+    F->Count++;
+
+  F->Col++;
+
+  (*nbpt) = data->Cur_Pt;
+  return F->Buffer2;
+}
+
+
+/***************************************************************/
+
+static void
+release_ifs (IfsData * data)
+{
+  if (data->Root != NULL) {
+    free_ifs (data->Root);
+    (void) free ((void *) data->Root);
+    data->Root = (FRACTAL *) NULL;
+  }
+}
+
+#define RAND() goom_random(goomInfo->gRandom)
+
+static void
+ifs_update (PluginInfo * goomInfo, Pixel * data, Pixel * back, int increment,
+    IfsData * fx_data)
+{
+  static unsigned int couleur = 0xc0c0c0c0;
+  static int v[4] = { 2, 4, 3, 2 };
+  static int col[4] = { 2, 4, 3, 2 };
+
+#define MOD_MER 0
+#define MOD_FEU 1
+#define MOD_MERVER 2
+  static int mode = MOD_MERVER;
+  static int justChanged = 0;
+  static int cycle = 0;
+  int cycle10;
+
+  int nbpt = 0;
+  IFSPoint *points;
+  int i;
+
+  unsigned int couleursl = couleur;
+  int width = goomInfo->screen.width;
+  int height = goomInfo->screen.height;
+
+  cycle++;
+  if (cycle >= 80)
+    cycle = 0;
+
+  if (cycle < 40)
+    cycle10 = cycle / 10;
+  else
+    cycle10 = 7 - cycle / 10;
+
+  {
+    unsigned char *tmp = (unsigned char *) &couleursl;
+
+    for (i = 0; i < 4; i++) {
+      *tmp = (*tmp) >> cycle10;
+      tmp++;
+    }
+  }
+
+  points = draw_ifs (goomInfo, &nbpt, fx_data);
+  nbpt--;
+
+#ifdef HAVE_MMX
+  movd_m2r (couleursl, mm1);
+  punpckldq_r2r (mm1, mm1);
+  for (i = 0; i < nbpt; i += increment) {
+    int x = points[i].x;
+    int y = points[i].y;
+
+    if ((x < width) && (y < height) && (x > 0) && (y > 0)) {
+      int pos = x + (y * width);
+
+      movd_m2r (back[pos], mm0);
+      paddusb_r2r (mm1, mm0);
+      movd_r2m (mm0, data[pos]);
+    }
+  }
+  emms ();     /*__asm__ __volatile__ ("emms");*/
+#else
+  for (i = 0; i < nbpt; i += increment) {
+    int x = (int) points[i].x & 0x7fffffff;
+    int y = (int) points[i].y & 0x7fffffff;
+
+    if ((x < width) && (y < height)) {
+      int pos = x + (int) (y * width);
+      int tra = 0, i = 0;
+      unsigned char *bra = (unsigned char *) &back[pos];
+      unsigned char *dra = (unsigned char *) &data[pos];
+      unsigned char *cra = (unsigned char *) &couleursl;
+
+      for (; i < 4; i++) {
+        tra = *cra;
+        tra += *bra;
+        if (tra > 255)
+          tra = 255;
+        *dra = tra;
+        ++dra;
+        ++cra;
+        ++bra;
+      }
+    }
+  }
+#endif /*MMX*/
+      justChanged--;
+
+  col[ALPHA] = couleur >> (ALPHA * 8) & 0xff;
+  col[BLEU] = couleur >> (BLEU * 8) & 0xff;
+  col[VERT] = couleur >> (VERT * 8) & 0xff;
+  col[ROUGE] = couleur >> (ROUGE * 8) & 0xff;
+
+  if (mode == MOD_MER) {
+    col[BLEU] += v[BLEU];
+    if (col[BLEU] > 255) {
+      col[BLEU] = 255;
+      v[BLEU] = -(RAND () % 4) - 1;
+    }
+    if (col[BLEU] < 32) {
+      col[BLEU] = 32;
+      v[BLEU] = (RAND () % 4) + 1;
+    }
+
+    col[VERT] += v[VERT];
+    if (col[VERT] > 200) {
+      col[VERT] = 200;
+      v[VERT] = -(RAND () % 3) - 2;
+    }
+    if (col[VERT] > col[BLEU]) {
+      col[VERT] = col[BLEU];
+      v[VERT] = v[BLEU];
+    }
+    if (col[VERT] < 32) {
+      col[VERT] = 32;
+      v[VERT] = (RAND () % 3) + 2;
+    }
+
+    col[ROUGE] += v[ROUGE];
+    if (col[ROUGE] > 64) {
+      col[ROUGE] = 64;
+      v[ROUGE] = -(RAND () % 4) - 1;
+    }
+    if (col[ROUGE] < 0) {
+      col[ROUGE] = 0;
+      v[ROUGE] = (RAND () % 4) + 1;
+    }
+
+    col[ALPHA] += v[ALPHA];
+    if (col[ALPHA] > 0) {
+      col[ALPHA] = 0;
+      v[ALPHA] = -(RAND () % 4) - 1;
+    }
+    if (col[ALPHA] < 0) {
+      col[ALPHA] = 0;
+      v[ALPHA] = (RAND () % 4) + 1;
+    }
+
+    if (((col[VERT] > 32) && (col[ROUGE] < col[VERT] + 40)
+            && (col[VERT] < col[ROUGE] + 20) && (col[BLEU] < 64)
+            && (RAND () % 20 == 0)) && (justChanged < 0)) {
+      mode = (RAND () % 3) ? MOD_FEU : MOD_MERVER;
+      justChanged = 250;
+    }
+  } else if (mode == MOD_MERVER) {
+    col[BLEU] += v[BLEU];
+    if (col[BLEU] > 128) {
+      col[BLEU] = 128;
+      v[BLEU] = -(RAND () % 4) - 1;
+    }
+    if (col[BLEU] < 16) {
+      col[BLEU] = 16;
+      v[BLEU] = (RAND () % 4) + 1;
+    }
+
+    col[VERT] += v[VERT];
+    if (col[VERT] > 200) {
+      col[VERT] = 200;
+      v[VERT] = -(RAND () % 3) - 2;
+    }
+    if (col[VERT] > col[ALPHA]) {
+      col[VERT] = col[ALPHA];
+      v[VERT] = v[ALPHA];
+    }
+    if (col[VERT] < 32) {
+      col[VERT] = 32;
+      v[VERT] = (RAND () % 3) + 2;
+    }
+
+    col[ROUGE] += v[ROUGE];
+    if (col[ROUGE] > 128) {
+      col[ROUGE] = 128;
+      v[ROUGE] = -(RAND () % 4) - 1;
+    }
+    if (col[ROUGE] < 0) {
+      col[ROUGE] = 0;
+      v[ROUGE] = (RAND () % 4) + 1;
+    }
+
+    col[ALPHA] += v[ALPHA];
+    if (col[ALPHA] > 255) {
+      col[ALPHA] = 255;
+      v[ALPHA] = -(RAND () % 4) - 1;
+    }
+    if (col[ALPHA] < 0) {
+      col[ALPHA] = 0;
+      v[ALPHA] = (RAND () % 4) + 1;
+    }
+
+    if (((col[VERT] > 32) && (col[ROUGE] < col[VERT] + 40)
+            && (col[VERT] < col[ROUGE] + 20) && (col[BLEU] < 64)
+            && (RAND () % 20 == 0)) && (justChanged < 0)) {
+      mode = (RAND () % 3) ? MOD_FEU : MOD_MER;
+      justChanged = 250;
+    }
+  } else if (mode == MOD_FEU) {
+
+    col[BLEU] += v[BLEU];
+    if (col[BLEU] > 64) {
+      col[BLEU] = 64;
+      v[BLEU] = -(RAND () % 4) - 1;
+    }
+    if (col[BLEU] < 0) {
+      col[BLEU] = 0;
+      v[BLEU] = (RAND () % 4) + 1;
+    }
+
+    col[VERT] += v[VERT];
+    if (col[VERT] > 200) {
+      col[VERT] = 200;
+      v[VERT] = -(RAND () % 3) - 2;
+    }
+    if (col[VERT] > col[ROUGE] + 20) {
+      col[VERT] = col[ROUGE] + 20;
+      v[VERT] = -(RAND () % 3) - 2;
+      v[ROUGE] = (RAND () % 4) + 1;
+      v[BLEU] = (RAND () % 4) + 1;
+    }
+    if (col[VERT] < 0) {
+      col[VERT] = 0;
+      v[VERT] = (RAND () % 3) + 2;
+    }
+
+    col[ROUGE] += v[ROUGE];
+    if (col[ROUGE] > 255) {
+      col[ROUGE] = 255;
+      v[ROUGE] = -(RAND () % 4) - 1;
+    }
+    if (col[ROUGE] > col[VERT] + 40) {
+      col[ROUGE] = col[VERT] + 40;
+      v[ROUGE] = -(RAND () % 4) - 1;
+    }
+    if (col[ROUGE] < 0) {
+      col[ROUGE] = 0;
+      v[ROUGE] = (RAND () % 4) + 1;
+    }
+
+    col[ALPHA] += v[ALPHA];
+    if (col[ALPHA] > 0) {
+      col[ALPHA] = 0;
+      v[ALPHA] = -(RAND () % 4) - 1;
+    }
+    if (col[ALPHA] < 0) {
+      col[ALPHA] = 0;
+      v[ALPHA] = (RAND () % 4) + 1;
+    }
+
+    if (((col[ROUGE] < 64) && (col[VERT] > 32) && (col[VERT] < col[BLEU])
+            && (col[BLEU] > 32)
+            && (RAND () % 20 == 0)) && (justChanged < 0)) {
+      mode = (RAND () % 2) ? MOD_MER : MOD_MERVER;
+      justChanged = 250;
+    }
+  }
+
+  couleur = (col[ALPHA] << (ALPHA * 8))
+      | (col[BLEU] << (BLEU * 8))
+      | (col[VERT] << (VERT * 8))
+      | (col[ROUGE] << (ROUGE * 8));
+}
+
+/** VISUAL_FX WRAPPER FOR IFS */
+
+static void
+ifs_vfx_apply (VisualFX * _this, Pixel * src, Pixel * dest,
+    PluginInfo * goomInfo)
+{
+
+  IfsData *data = (IfsData *) _this->fx_data;
+
+  if (!data->initalized) {
+    data->initalized = 1;
+    init_ifs (goomInfo, data);
+  }
+  ifs_update (goomInfo, dest, src, goomInfo->update.ifs_incr, data);
+  /*TODO: trouver meilleur soluce pour increment (mettre le code de gestion de l'ifs dans ce fichier: ifs_vfx_apply) */
+}
+
+static void
+ifs_vfx_init (VisualFX * _this, PluginInfo * info)
+{
+
+  IfsData *data = (IfsData *) malloc (sizeof (IfsData));
+
+  data->Root = (FRACTAL *) NULL;
+  data->initalized = 0;
+  _this->fx_data = data;
+}
+
+static void
+ifs_vfx_free (VisualFX * _this)
+{
+  IfsData *data = (IfsData *) _this->fx_data;
+
+  release_ifs (data);
+  free (data);
+}
+
+void
+ifs_visualfx_create (VisualFX * vfx)
+{
+
+  vfx->init = ifs_vfx_init;
+  vfx->free = ifs_vfx_free;
+  vfx->apply = ifs_vfx_apply;
+  vfx->fx_data = NULL;
+  vfx->params = NULL;
+}
diff --git a/gst/goom/ifs.h b/gst/goom/ifs.h
new file mode 100644
index 0000000..4003773
--- /dev/null
+++ b/gst/goom/ifs.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1997 by Massimino Pascal <Pascal.Massimon@ens.fr>
+ *
+ * ifs.h: modified iterated functions system for goom.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * This file is provided AS IS with no warranties of any kind.  The author
+ * shall have no liability with respect to the infringement of copyrights,
+ * trade secrets or any patents by this file or any part thereof.  In no
+ * event will the author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages.
+ *
+ * If this mode is weird and you have an old MetroX server, it is buggy.
+ * There is a free SuSE-enhanced MetroX X server that is fine.
+ *
+ * When shown ifs, Diana Rose (4 years old) said, "It looks like dancing."
+ *
+ * Revision History:
+ * 13-Dec-2003: Added some goom specific stuffs (to make ifs a VisualFX).
+ * 11-Apr-2002: jeko@ios-software.com: Make ifs.c system-indendant. (ifs.h added)
+ * 01-Nov-2000: Allocation checks
+ * 10-May-1997: jwz@jwz.org: turned into a standalone program.
+ *              Made it render into an offscreen bitmap and then copy
+ *              that onto the screen, to reduce flicker.
+ */
+
+#ifndef IFS_H
+#define IFS_H
+
+#include "goom_config.h"
+#include "goom_graphic.h"
+#include "goom_plugin_info.h"
+#include "goom_visual_fx.h"
+
+void ifs_visualfx_create(VisualFX *vfx);
+
+/* init ifs for a (width)x(height) output. * /
+void init_ifs (PluginInfo *goomInfo, int width, int height);
+
+/ * draw an ifs on the buffer (which size is width * height)
+   increment means that we draw 1/increment of the ifs's points * /
+void ifs_update (PluginInfo *goomInfo, Pixel * buffer, Pixel * back, int width, int height, int increment);
+
+/ * free all ifs's data. * /
+void release_ifs (void);
+*/
+
+
+#endif
diff --git a/gst/goom/lines.c b/gst/goom/lines.c
new file mode 100644
index 0000000..a7c1eda
--- /dev/null
+++ b/gst/goom/lines.c
@@ -0,0 +1,257 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "lines.h"
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "goom_tools.h"
+#include "drawmethods.h"
+#include "goom_plugin_info.h"
+
+static inline unsigned char
+lighten (unsigned char value, float power)
+{
+  int val = value;
+  float t = (float) val * log10 (power) / 2.0;
+
+  if (t > 0) {
+    val = (int) t;              /* (32.0f * log (t)); */
+    if (val > 255)
+      val = 255;
+    if (val < 0)
+      val = 0;
+    return val;
+  } else {
+    return 0;
+  }
+}
+
+static void
+lightencolor (guint32 * col, float power)
+{
+  unsigned char *color;
+
+  color = (unsigned char *) col;
+  *color = lighten (*color, power);
+  color++;
+  *color = lighten (*color, power);
+  color++;
+  *color = lighten (*color, power);
+  color++;
+  *color = lighten (*color, power);
+}
+
+
+
+static void
+genline (int id, float param, GMUnitPointer * l, int rx, int ry)
+{
+  int i;
+
+  switch (id) {
+    case GML_HLINE:
+      for (i = 0; i < 512; i++) {
+        l[i].x = ((float) i * rx) / 512.0f;
+        l[i].y = param;
+        l[i].angle = G_PI / 2.0f;
+      }
+      return;
+    case GML_VLINE:
+      for (i = 0; i < 512; i++) {
+        l[i].y = ((float) i * ry) / 512.0f;
+        l[i].x = param;
+        l[i].angle = 0.0f;
+      }
+      return;
+    case GML_CIRCLE:
+      for (i = 0; i < 512; i++) {
+        float cosa, sina;
+
+        l[i].angle = 2.0f * G_PI * (float) i / 512.0f;
+        cosa = param * cos (l[i].angle);
+        sina = param * sin (l[i].angle);
+        l[i].x = ((float) rx / 2.0f) + cosa;
+        l[i].y = (float) ry / 2.0f + sina;
+      }
+      return;
+  }
+}
+
+static guint32
+getcouleur (int mode)
+{
+  switch (mode) {
+    case GML_RED:
+      return (230 << (ROUGE * 8)) | (120 << (VERT * 8)) | (18 << (BLEU * 8));
+    case GML_ORANGE_J:
+      return (120 << (VERT * 8)) | (252 << (ROUGE * 8)) | (18 << (BLEU * 8));
+    case GML_ORANGE_V:
+      return (160 << (VERT * 8)) | (236 << (ROUGE * 8)) | (40 << (BLEU * 8));
+    case GML_BLEUBLANC:
+      return (40 << (BLEU * 8)) | (220 << (ROUGE * 8)) | (140 << (VERT * 8));
+    case GML_VERT:
+      return (200 << (VERT * 8)) | (80 << (ROUGE * 8)) | (18 << (BLEU * 8));
+    case GML_BLEU:
+      return (250 << (BLEU * 8)) | (30 << (VERT * 8)) | (80 << (ROUGE * 8));
+    case GML_BLACK:
+      return (16 << (BLEU * 8)) | (16 << (VERT * 8)) | (16 << (ROUGE * 8));
+  }
+  return 0;
+}
+
+void
+goom_lines_set_res (GMLine * gml, int rx, int ry)
+{
+  if (gml != NULL) {
+    gml->screenX = rx;
+    gml->screenY = ry;
+
+    genline (gml->IDdest, gml->param, gml->points2, rx, ry);
+  }
+}
+
+
+static void
+goom_lines_move (GMLine * l)
+{
+  int i;
+  unsigned char *c1, *c2;
+
+  for (i = 0; i < 512; i++) {
+    l->points[i].x = (l->points2[i].x + 39.0f * l->points[i].x) / 40.0f;
+    l->points[i].y = (l->points2[i].y + 39.0f * l->points[i].y) / 40.0f;
+    l->points[i].angle =
+        (l->points2[i].angle + 39.0f * l->points[i].angle) / 40.0f;
+  }
+
+  c1 = (unsigned char *) &l->color;
+  c2 = (unsigned char *) &l->color2;
+  for (i = 0; i < 4; i++) {
+    int cc1, cc2;
+
+    cc1 = *c1;
+    cc2 = *c2;
+    *c1 = (unsigned char) ((cc1 * 63 + cc2) >> 6);
+    ++c1;
+    ++c2;
+  }
+
+  l->power += l->powinc;
+  if (l->power < 1.1f) {
+    l->power = 1.1f;
+    l->powinc = (float) (goom_irand (l->goomInfo->gRandom, 20) + 10) / 300.0f;
+  }
+  if (l->power > 17.5f) {
+    l->power = 17.5f;
+    l->powinc = -(float) (goom_irand (l->goomInfo->gRandom, 20) + 10) / 300.0f;
+  }
+
+  l->amplitude = (99.0f * l->amplitude + l->amplitudeF) / 100.0f;
+}
+
+void
+goom_lines_switch_to (GMLine * gml, int IDdest,
+    float param, float amplitude, int col)
+{
+  genline (IDdest, param, gml->points2, gml->screenX, gml->screenY);
+  gml->IDdest = IDdest;
+  gml->param = param;
+  gml->amplitudeF = amplitude;
+  gml->color2 = getcouleur (col);
+}
+
+GMLine *
+goom_lines_init (PluginInfo * goomInfo, int rx, int ry,
+    int IDsrc, float paramS, int coulS, int IDdest, float paramD, int coulD)
+{
+  GMLine *l = (GMLine *) malloc (sizeof (GMLine));
+
+  l->goomInfo = goomInfo;
+
+  l->points = (GMUnitPointer *) malloc (512 * sizeof (GMUnitPointer));
+  l->points2 = (GMUnitPointer *) malloc (512 * sizeof (GMUnitPointer));
+  l->nbPoints = 512;
+
+  l->IDdest = IDdest;
+  l->param = paramD;
+
+  l->amplitude = l->amplitudeF = 1.0f;
+
+  genline (IDsrc, paramS, l->points, rx, ry);
+  genline (IDdest, paramD, l->points2, rx, ry);
+
+  l->color = getcouleur (coulS);
+  l->color2 = getcouleur (coulD);
+
+  l->screenX = rx;
+  l->screenY = ry;
+
+  l->power = 0.0f;
+  l->powinc = 0.01f;
+
+  goom_lines_switch_to (l, IDdest, paramD, 1.0f, coulD);
+
+  return l;
+}
+
+void
+goom_lines_free (GMLine ** l)
+{
+  free ((*l)->points2);
+  free ((*l)->points);
+  free (*l);
+  l = NULL;
+}
+
+void
+goom_lines_draw (PluginInfo * plug, GMLine * line, gint16 data[512], Pixel * p)
+{
+  if (line != NULL) {
+    int i, x1, y1;
+    guint32 color = line->color;
+    GMUnitPointer *pt = &(line->points[0]);
+
+    float cosa = cos (pt->angle) / 1000.0f;
+    float sina = sin (pt->angle) / 1000.0f;
+
+    lightencolor (&color, line->power);
+
+    x1 = (int) (pt->x + cosa * line->amplitude * data[0]);
+    y1 = (int) (pt->y + sina * line->amplitude * data[0]);
+
+    for (i = 1; i < 512; i++) {
+      int x2, y2;
+      GMUnitPointer *pt = &(line->points[i]);
+
+      float cosa = cos (pt->angle) / 1000.0f;
+      float sina = sin (pt->angle) / 1000.0f;
+
+      x2 = (int) (pt->x + cosa * line->amplitude * data[i]);
+      y2 = (int) (pt->y + sina * line->amplitude * data[i]);
+
+      plug->methods.draw_line (p, x1, y1, x2, y2, color, line->screenX,
+          line->screenY);
+
+      x1 = x2;
+      y1 = y2;
+    }
+    goom_lines_move (line);
+  }
+}
diff --git a/gst/goom/lines.h b/gst/goom/lines.h
new file mode 100644
index 0000000..4cd50d8
--- /dev/null
+++ b/gst/goom/lines.h
@@ -0,0 +1,94 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINES_H
+#define _LINES_H
+
+#include "goom_typedefs.h"
+#include "goom_graphic.h"
+#include "goom_config.h"
+
+struct _GMUNITPOINTER
+{
+	float   x;
+	float   y;
+	float   angle;
+};
+
+/* tableau de points */
+struct _GMLINE
+{
+
+	GMUnitPointer *points;
+	GMUnitPointer *points2;
+	int     IDdest;
+	float   param;
+	float   amplitudeF;
+	float   amplitude;
+
+	int     nbPoints;
+	guint32 color;     /* pour l'instant je stocke la couleur a terme, on stockera le mode couleur et l'on animera */
+	guint32 color2;
+
+	int     screenX;
+	int     screenY;
+
+	float   power;
+	float   powinc;
+
+	PluginInfo *goomInfo;
+};
+
+/* les ID possibles */
+
+#define GML_CIRCLE 0
+/* (param = radius) */
+
+#define GML_HLINE 1
+/* (param = y) */
+
+#define GML_VLINE 2
+/* (param = x) */
+
+/* les modes couleur possible (si tu mets un autre c'est noir) */
+
+#define GML_BLEUBLANC 0
+#define GML_RED 1
+#define GML_ORANGE_V 2
+#define GML_ORANGE_J 3
+#define GML_VERT 4
+#define GML_BLEU 5
+#define GML_BLACK 6
+
+/* construit un effet de line (une ligne horitontale pour commencer) */
+GMLine *goom_lines_init (PluginInfo *goomInfo, int rx, int ry,
+			 int IDsrc, float paramS, int modeCoulSrc,
+			 int IDdest, float paramD, int modeCoulDest);
+
+void    goom_lines_switch_to (GMLine * gml, int IDdest, float param,
+			float amplitude,
+			int modeCoul);
+
+void    goom_lines_set_res (GMLine * gml, int rx, int ry);
+
+void    goom_lines_free (GMLine ** gml);
+
+void    goom_lines_draw (PluginInfo *plugInfo, GMLine * gml, gint16 data[512], Pixel *p);
+
+#endif /* _LINES_H */
diff --git a/gst/goom/mathtools.c b/gst/goom/mathtools.c
new file mode 100644
index 0000000..dd190bf
--- /dev/null
+++ b/gst/goom/mathtools.c
@@ -0,0 +1,106 @@
+/* Goom Project
+ * Copyright (C) <2003> Jean-Christophe Hoelt <jeko@free.fr>
+ *
+ * goom_core.c:Contains the core of goom's work.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "mathtools.h"
+
+float sin256[256] = {
+  0, 0.0245412, 0.0490677, 0.0735646, 0.0980171, 0.122411, 0.14673, 0.170962,
+  0.19509, 0.219101, 0.24298, 0.266713, 0.290285, 0.313682, 0.33689,
+  0.359895, 0.382683, 0.405241, 0.427555, 0.449611, 0.471397, 0.492898,
+  0.514103, 0.534998, 0.55557, 0.575808, 0.595699, 0.615232, 0.634393,
+  0.653173, 0.671559, 0.689541, 0.707107, 0.724247, 0.740951, 0.757209,
+  0.77301, 0.788346, 0.803208, 0.817585, 0.83147, 0.844854, 0.857729,
+  0.870087, 0.881921, 0.893224, 0.903989, 0.91421, 0.92388, 0.932993,
+  0.941544, 0.949528, 0.95694, 0.963776, 0.970031, 0.975702, 0.980785,
+  0.985278, 0.989177, 0.99248, 0.995185, 0.99729, 0.998795, 0.999699, 1,
+  0.999699, 0.998795, 0.99729, 0.995185, 0.99248, 0.989177, 0.985278,
+  0.980785, 0.975702, 0.970031, 0.963776, 0.95694, 0.949528, 0.941544,
+  0.932993, 0.92388, 0.91421, 0.903989, 0.893224, 0.881921, 0.870087,
+  0.857729, 0.844854, 0.83147, 0.817585, 0.803208, 0.788346, 0.77301,
+  0.757209, 0.740951, 0.724247, 0.707107, 0.689541, 0.671559, 0.653173,
+  0.634393, 0.615232, 0.595699, 0.575808, 0.55557, 0.534998, 0.514103,
+  0.492898, 0.471397, 0.449611, 0.427555, 0.405241, 0.382683, 0.359895,
+  0.33689, 0.313682, 0.290285, 0.266713, 0.24298, 0.219101, 0.19509,
+  0.170962, 0.14673, 0.122411, 0.0980171, 0.0735646, 0.0490677, 0.0245412,
+  1.22465e-16, -0.0245412, -0.0490677, -0.0735646, -0.0980171, -0.122411,
+  -0.14673, -0.170962, -0.19509, -0.219101, -0.24298, -0.266713, -0.290285,
+  -0.313682, -0.33689, -0.359895, -0.382683, -0.405241, -0.427555,
+  -0.449611, -0.471397, -0.492898, -0.514103, -0.534998, -0.55557,
+  -0.575808, -0.595699, -0.615232, -0.634393, -0.653173, -0.671559,
+  -0.689541, -0.707107, -0.724247, -0.740951, -0.757209, -0.77301,
+  -0.788346, -0.803208, -0.817585, -0.83147, -0.844854, -0.857729,
+  -0.870087, -0.881921, -0.893224, -0.903989, -0.91421, -0.92388, -0.932993,
+  -0.941544, -0.949528, -0.95694, -0.963776, -0.970031, -0.975702,
+  -0.980785, -0.985278, -0.989177, -0.99248, -0.995185, -0.99729, -0.998795,
+  -0.999699, -1, -0.999699, -0.998795, -0.99729, -0.995185, -0.99248,
+  -0.989177, -0.985278, -0.980785, -0.975702, -0.970031, -0.963776,
+  -0.95694, -0.949528, -0.941544, -0.932993, -0.92388, -0.91421, -0.903989,
+  -0.893224, -0.881921, -0.870087, -0.857729, -0.844854, -0.83147,
+  -0.817585, -0.803208, -0.788346, -0.77301, -0.757209, -0.740951,
+  -0.724247, -0.707107, -0.689541, -0.671559, -0.653173, -0.634393,
+  -0.615232, -0.595699, -0.575808, -0.55557, -0.534998, -0.514103,
+  -0.492898, -0.471397, -0.449611, -0.427555, -0.405241, -0.382683,
+  -0.359895, -0.33689, -0.313682, -0.290285, -0.266713, -0.24298, -0.219101,
+  -0.19509, -0.170962, -0.14673, -0.122411, -0.0980171, -0.0735646,
+  -0.0490677, -0.0245412
+};
+
+float cos256[256] = {
+  0, 0.999699, 0.998795, 0.99729, 0.995185, 0.99248, 0.989177, 0.985278,
+  0.980785, 0.975702, 0.970031, 0.963776, 0.95694, 0.949528, 0.941544,
+  0.932993, 0.92388, 0.91421, 0.903989, 0.893224, 0.881921, 0.870087,
+  0.857729, 0.844854, 0.83147, 0.817585, 0.803208, 0.788346, 0.77301,
+  0.757209, 0.740951, 0.724247, 0.707107, 0.689541, 0.671559, 0.653173,
+  0.634393, 0.615232, 0.595699, 0.575808, 0.55557, 0.534998, 0.514103,
+  0.492898, 0.471397, 0.449611, 0.427555, 0.405241, 0.382683, 0.359895,
+  0.33689, 0.313682, 0.290285, 0.266713, 0.24298, 0.219101, 0.19509,
+  0.170962, 0.14673, 0.122411, 0.0980171, 0.0735646, 0.0490677, 0.0245412,
+  6.12323e-17, -0.0245412, -0.0490677, -0.0735646, -0.0980171, -0.122411,
+  -0.14673, -0.170962, -0.19509, -0.219101, -0.24298, -0.266713, -0.290285,
+  -0.313682, -0.33689, -0.359895, -0.382683, -0.405241, -0.427555,
+  -0.449611, -0.471397, -0.492898, -0.514103, -0.534998, -0.55557,
+  -0.575808, -0.595699, -0.615232, -0.634393, -0.653173, -0.671559,
+  -0.689541, -0.707107, -0.724247, -0.740951, -0.757209, -0.77301,
+  -0.788346, -0.803208, -0.817585, -0.83147, -0.844854, -0.857729,
+  -0.870087, -0.881921, -0.893224, -0.903989, -0.91421, -0.92388, -0.932993,
+  -0.941544, -0.949528, -0.95694, -0.963776, -0.970031, -0.975702,
+  -0.980785, -0.985278, -0.989177, -0.99248, -0.995185, -0.99729, -0.998795,
+  -0.999699, -1, -0.999699, -0.998795, -0.99729, -0.995185, -0.99248,
+  -0.989177, -0.985278, -0.980785, -0.975702, -0.970031, -0.963776,
+  -0.95694, -0.949528, -0.941544, -0.932993, -0.92388, -0.91421, -0.903989,
+  -0.893224, -0.881921, -0.870087, -0.857729, -0.844854, -0.83147,
+  -0.817585, -0.803208, -0.788346, -0.77301, -0.757209, -0.740951,
+  -0.724247, -0.707107, -0.689541, -0.671559, -0.653173, -0.634393,
+  -0.615232, -0.595699, -0.575808, -0.55557, -0.534998, -0.514103,
+  -0.492898, -0.471397, -0.449611, -0.427555, -0.405241, -0.382683,
+  -0.359895, -0.33689, -0.313682, -0.290285, -0.266713, -0.24298, -0.219101,
+  -0.19509, -0.170962, -0.14673, -0.122411, -0.0980171, -0.0735646,
+  -0.0490677, -0.0245412, -1.83697e-16, 0.0245412, 0.0490677, 0.0735646,
+  0.0980171, 0.122411, 0.14673, 0.170962, 0.19509, 0.219101, 0.24298,
+  0.266713, 0.290285, 0.313682, 0.33689, 0.359895, 0.382683, 0.405241,
+  0.427555, 0.449611, 0.471397, 0.492898, 0.514103, 0.534998, 0.55557,
+  0.575808, 0.595699, 0.615232, 0.634393, 0.653173, 0.671559, 0.689541,
+  0.707107, 0.724247, 0.740951, 0.757209, 0.77301, 0.788346, 0.803208,
+  0.817585, 0.83147, 0.844854, 0.857729, 0.870087, 0.881921, 0.893224,
+  0.903989, 0.91421, 0.92388, 0.932993, 0.941544, 0.949528, 0.95694,
+  0.963776, 0.970031, 0.975702, 0.980785, 0.985278, 0.989177, 0.99248,
+  0.995185, 0.99729, 0.998795, 0.999699
+};
diff --git a/gst/goom/mathtools.h b/gst/goom/mathtools.h
new file mode 100644
index 0000000..5340dab
--- /dev/null
+++ b/gst/goom/mathtools.h
@@ -0,0 +1,58 @@
+/* Goom Project
+ * Copyright (C) <2003> Jean-Christophe Hoelt <jeko@free.fr>
+ *
+ * goom_core.c:Contains the core of goom's work.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+ #ifndef MATHTOOLS_H
+#define MATHTOOLS_H
+
+#include <glib.h>
+
+#define _double2fixmagic (68719476736.0*1.5)
+/* 2^36 * 1.5,  (52-_shiftamt=36) uses limited precisicion to floor */
+#define _shiftamt 16
+/* 16.16 fixed point representation */
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+#define iexp_				0
+#define iman_				1
+#else
+#define iexp_				1
+#define iman_				0
+#endif /* BigEndian_ */
+
+/* TODO: this optimization is very efficient: put it again when all works
+#ifdef HAVE_MMX
+#define F2I(dbl,i) {double d = dbl + _double2fixmagic; i = ((int*)&d)[iman_] >> _shiftamt;}
+#else*/
+#define F2I(dbl,i) i=(int)dbl;
+/*#endif*/
+
+#if 0
+#define SINCOS(f,s,c) \
+  __asm__ __volatile__ ("fsincos" : "=t" (c), "=u" (s) : "0" (f))
+#else
+#define SINCOS(f,s,c) {s=sin(f);c=cos(f);}
+#endif
+
+extern float sin256[256];
+extern float cos256[256];
+
+#endif
+
diff --git a/gst/goom/meson.build b/gst/goom/meson.build
new file mode 100644
index 0000000..07d83a3
--- /dev/null
+++ b/gst/goom/meson.build
@@ -0,0 +1,29 @@
+goom_sources = [
+  'gstgoom.c',
+  'drawmethods.c',
+  'sound_tester.c',
+  'mathtools.c',
+  'lines.c',
+  'ifs.c',
+  'surf3d.c',
+  'tentacle3d.c',
+  'v3d.c',
+  'convolve_fx.c',
+  'flying_stars_fx.c',
+  'plugin_info.c',
+  'goom_tools.c',
+  'config_param.c',
+  'filters.c',
+  'goom_core.c',
+  'graphic.c',
+]
+
+
+gstgoom = library('gstgoom',
+  goom_sources,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gst_dep, gstpbutils_dep, gstbase_dep, orc_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/goom/mmx.c b/gst/goom/mmx.c
new file mode 100644
index 0000000..bc2a6c4
--- /dev/null
+++ b/gst/goom/mmx.c
@@ -0,0 +1,291 @@
+/*	mmx.c
+
+	MultiMedia eXtensions GCC interface library for IA32.
+
+	To use this library, simply include this header file
+	and compile with GCC.  You MUST have inlining enabled
+	in order for mmx_ok() to work; this can be done by
+	simply using -O on the GCC command line.
+
+	Compiling with -DMMX_TRACE will cause detailed trace
+	output to be sent to stderr for each mmx operation.
+	This adds lots of code, and obviously slows execution to
+	a crawl, but can be very useful for debugging.
+
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
+	EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+	LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR ANY PARTICULAR PURPOSE.
+
+	1997-99 by H. Dietz and R. Fisher
+
+ Notes:
+	It appears that the latest gas has the pand problem fixed, therefore
+	  I'll undefine BROKEN_PAND by default.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "goom_config.h"
+
+#ifdef HAVE_MMX
+
+#define BUFFPOINTNB 16
+#define BUFFPOINTMASK 0xffff
+#define BUFFINCR 0xff
+
+#include "mmx.h"
+#include "goom_graphic.h"
+
+#define sqrtperte 16
+// faire : a % sqrtperte <=> a & pertemask
+#define PERTEMASK 0xf
+// faire : a / sqrtperte <=> a >> PERTEDEC
+#define PERTEDEC 4
+
+int
+mmx_supported (void)
+{
+  return (mm_support () & 0x1);
+}
+
+void
+zoom_filter_mmx (int prevX, int prevY,
+    Pixel * expix1, Pixel * expix2,
+    int *brutS, int *brutD, int buffratio, int precalCoef[16][16])
+{
+  unsigned int ax = (prevX - 1) << PERTEDEC, ay = (prevY - 1) << PERTEDEC;
+
+  int bufsize = prevX * prevY;
+  int loop;
+
+  __asm__ __volatile__ ("pxor %mm7,%mm7");
+
+  for (loop = 0; loop < bufsize; loop++) {
+    /*      int couleur; */
+    int px, py;
+    int pos;
+    int coeffs;
+
+    int myPos = loop << 1, myPos2 = myPos + 1;
+    int brutSmypos = brutS[myPos];
+
+    px = brutSmypos + (((brutD[myPos] -
+                brutSmypos) * buffratio) >> BUFFPOINTNB);
+    brutSmypos = brutS[myPos2];
+    py = brutSmypos + (((brutD[myPos2] -
+                brutSmypos) * buffratio) >> BUFFPOINTNB);
+
+    if ((py >= ay) || (px >= ax)) {
+      pos = coeffs = 0;
+    } else {
+      pos = ((px >> PERTEDEC) + prevX * (py >> PERTEDEC));
+      // coef en modulo 15
+      coeffs = precalCoef[px & PERTEMASK][py & PERTEMASK];
+    }
+
+    __asm__ __volatile__ ("movd %2, %%mm6 \n\t"
+        /* recuperation des deux premiers pixels dans mm0 et mm1 */
+        "movq (%3,%1,4), %%mm0 \n\t"    /* b1-v1-r1-a1-b2-v2-r2-a2 */
+        "movq %%mm0, %%mm1 \n\t"        /* b1-v1-r1-a1-b2-v2-r2-a2 */
+        /* depackage du premier pixel */
+        "punpcklbw %%mm7, %%mm0 \n\t"   /* 00-b2-00-v2-00-r2-00-a2 */
+        "movq %%mm6, %%mm5 \n\t"        /* ??-??-??-??-c4-c3-c2-c1 */
+        /* depackage du 2ieme pixel */
+        "punpckhbw %%mm7, %%mm1 \n\t"   /* 00-b1-00-v1-00-r1-00-a1 */
+        /* extraction des coefficients... */
+        "punpcklbw %%mm5, %%mm6 \n\t"   /* c4-c4-c3-c3-c2-c2-c1-c1 */
+        "movq %%mm6, %%mm4 \n\t"        /* c4-c4-c3-c3-c2-c2-c1-c1 */
+        "movq %%mm6, %%mm5 \n\t"        /* c4-c4-c3-c3-c2-c2-c1-c1 */
+        "punpcklbw %%mm5, %%mm6 \n\t"   /* c2-c2-c2-c2-c1-c1-c1-c1 */
+        "punpckhbw %%mm5, %%mm4 \n\t"   /* c4-c4-c4-c4-c3-c3-c3-c3 */
+        "movq %%mm6, %%mm3 \n\t"        /* c2-c2-c2-c2-c1-c1-c1-c1 */
+        "punpcklbw %%mm7, %%mm6 \n\t"   /* 00-c1-00-c1-00-c1-00-c1 */
+        "punpckhbw %%mm7, %%mm3 \n\t"   /* 00-c2-00-c2-00-c2-00-c2 */
+        /* multiplication des pixels par les coefficients */
+        "pmullw %%mm6, %%mm0 \n\t"      /* c1*b2-c1*v2-c1*r2-c1*a2 */
+        "pmullw %%mm3, %%mm1 \n\t"      /* c2*b1-c2*v1-c2*r1-c2*a1 */
+        "paddw %%mm1, %%mm0 \n\t"
+        /* ...extraction des 2 derniers coefficients */
+        "movq %%mm4, %%mm5 \n\t"        /* c4-c4-c4-c4-c3-c3-c3-c3 */
+        "punpcklbw %%mm7, %%mm4 \n\t"   /* 00-c3-00-c3-00-c3-00-c3 */
+        "punpckhbw %%mm7, %%mm5 \n\t"   /* 00-c4-00-c4-00-c4-00-c4 */
+        /* ajouter la longueur de ligne a esi */
+        "addl 8(%%ebp),%1 \n\t"
+        /* recuperation des 2 derniers pixels */
+        "movq (%3,%1,4), %%mm1 \n\t" "movq %%mm1, %%mm2 \n\t"
+        /* depackage des pixels */
+        "punpcklbw %%mm7, %%mm1 \n\t" "punpckhbw %%mm7, %%mm2 \n\t"
+        /* multiplication pas les coeffs */
+        "pmullw %%mm4, %%mm1 \n\t" "pmullw %%mm5, %%mm2 \n\t"
+        /* ajout des valeurs obtenues ? la valeur finale */
+        "paddw %%mm1, %%mm0 \n\t" "paddw %%mm2, %%mm0 \n\t"
+        /* division par 256 = 16+16+16+16, puis repackage du pixel final */
+        "psrlw $8, %%mm0 \n\t"
+        "packuswb %%mm7, %%mm0 \n\t" "movd %%mm0,%0 \n\t":"=g" (expix2[loop])
+        :"r" (pos), "r" (coeffs), "r" (expix1)
+
+        );
+
+    emms ();
+  }
+}
+
+#define DRAWMETHOD_PLUS_MMX(_out,_backbuf,_col) \
+{ \
+	movd_m2r(_backbuf, mm0); \
+	paddusb_m2r(_col, mm0); \
+	movd_r2m(mm0, _out); \
+}
+
+#define DRAWMETHOD DRAWMETHOD_PLUS_MMX(*p,*p,col)
+
+void
+draw_line_mmx (Pixel * data, int x1, int y1, int x2, int y2, int col,
+    int screenx, int screeny)
+{
+  int x, y, dx, dy, yy, xx;
+  Pixel *p;
+
+  if ((y1 < 0) || (y2 < 0) || (x1 < 0) || (x2 < 0) || (y1 >= screeny)
+      || (y2 >= screeny) || (x1 >= screenx) || (x2 >= screenx))
+    goto end_of_line;
+
+  dx = x2 - x1;
+  dy = y2 - y1;
+  if (x1 >= x2) {
+    int tmp;
+
+    tmp = x1;
+    x1 = x2;
+    x2 = tmp;
+    tmp = y1;
+    y1 = y2;
+    y2 = tmp;
+    dx = x2 - x1;
+    dy = y2 - y1;
+  }
+
+  /* vertical line */
+  if (dx == 0) {
+    if (y1 < y2) {
+      p = &(data[(screenx * y1) + x1]);
+      for (y = y1; y <= y2; y++) {
+        DRAWMETHOD;
+        p += screenx;
+      }
+    } else {
+      p = &(data[(screenx * y2) + x1]);
+      for (y = y2; y <= y1; y++) {
+        DRAWMETHOD;
+        p += screenx;
+      }
+    }
+    goto end_of_line;
+  }
+  /* horizontal line */
+  if (dy == 0) {
+    if (x1 < x2) {
+      p = &(data[(screenx * y1) + x1]);
+      for (x = x1; x <= x2; x++) {
+        DRAWMETHOD;
+        p++;
+      }
+      goto end_of_line;
+    } else {
+      p = &(data[(screenx * y1) + x2]);
+      for (x = x2; x <= x1; x++) {
+        DRAWMETHOD;
+        p++;
+      }
+      goto end_of_line;
+    }
+  }
+  /* 1    */
+  /*  \   */
+  /*   \  */
+  /*    2 */
+  if (y2 > y1) {
+    /* steep */
+    if (dy > dx) {
+      dx = ((dx << 16) / dy);
+      x = x1 << 16;
+      for (y = y1; y <= y2; y++) {
+        xx = x >> 16;
+        p = &(data[(screenx * y) + xx]);
+        DRAWMETHOD;
+        if (xx < (screenx - 1)) {
+          p++;
+          /* DRAWMETHOD; */
+        }
+        x += dx;
+      }
+      goto end_of_line;
+    }
+    /* shallow */
+    else {
+      dy = ((dy << 16) / dx);
+      y = y1 << 16;
+      for (x = x1; x <= x2; x++) {
+        yy = y >> 16;
+        p = &(data[(screenx * yy) + x]);
+        DRAWMETHOD;
+        if (yy < (screeny - 1)) {
+          p += screeny;
+          /* DRAWMETHOD; */
+        }
+        y += dy;
+      }
+    }
+  }
+  /*    2 */
+  /*   /  */
+  /*  /   */
+  /* 1    */
+  else {
+    /* steep */
+    if (-dy > dx) {
+      dx = ((dx << 16) / -dy);
+      x = (x1 + 1) << 16;
+      for (y = y1; y >= y2; y--) {
+        xx = x >> 16;
+        p = &(data[(screenx * y) + xx]);
+        DRAWMETHOD;
+        if (xx < (screenx - 1)) {
+          p--;
+          /* DRAWMETHOD; */
+        }
+        x += dx;
+      }
+      goto end_of_line;
+    }
+    /* shallow */
+    else {
+      dy = ((dy << 16) / dx);
+      y = y1 << 16;
+      for (x = x1; x <= x2; x++) {
+        yy = y >> 16;
+        p = &(data[(screenx * yy) + x]);
+        DRAWMETHOD;
+        if (yy < (screeny - 1)) {
+          p += screeny;
+          /* DRAWMETHOD; */
+        }
+        y += dy;
+      }
+      goto end_of_line;
+    }
+  }
+end_of_line:
+  emms ();
+  /* __asm__ __volatile__ ("emms"); */
+}
+#else
+int
+mmx_supported (void)
+{
+  return (0);
+}
+#endif /* HAVE_MMX */
diff --git a/gst/goom/mmx.h b/gst/goom/mmx.h
new file mode 100644
index 0000000..2649e10
--- /dev/null
+++ b/gst/goom/mmx.h
@@ -0,0 +1,741 @@
+/*	mmx.h
+
+	MultiMedia eXtensions GCC interface library for IA32.
+
+	To use this library, simply include this header file
+	and compile with GCC.  You MUST have inlining enabled
+	in order for mmx_ok() to work; this can be done by
+	simply using -O on the GCC command line.
+
+	Compiling with -DMMX_TRACE will cause detailed trace
+	output to be sent to stderr for each mmx operation.
+	This adds lots of code, and obviously slows execution to
+	a crawl, but can be very useful for debugging.
+
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
+	EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+	LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR ANY PARTICULAR PURPOSE.
+
+	1997-99 by H. Dietz and R. Fisher
+
+ Notes:
+	It appears that the latest gas has the pand problem fixed, therefore
+	  I'll undefine BROKEN_PAND by default.
+*/
+
+#ifndef _MMX_H
+#define _MMX_H
+
+#include "goom_graphic.h"
+
+/*	Warning:  at this writing, the version of GAS packaged
+	with most Linux distributions does not handle the
+	parallel AND operation mnemonic correctly.  If the
+	symbol BROKEN_PAND is defined, a slower alternative
+	coding will be used.  If execution of mmxtest results
+	in an illegal instruction fault, define this symbol.
+*/
+#undef	BROKEN_PAND
+
+
+/*	The type of an value that fits in an MMX register
+	(note that long long constant values MUST be suffixed
+	 by LL and unsigned long long values by ULL, lest
+	 they be truncated by the compiler)
+*/
+typedef	union {
+	long long		q;	/* Quadword (64-bit) value */
+	unsigned long long	uq;	/* Unsigned Quadword */
+	int			d[2];	/* 2 Doubleword (32-bit) values */
+	unsigned int		ud[2];	/* 2 Unsigned Doubleword */
+	short			w[4];	/* 4 Word (16-bit) values */
+	unsigned short		uw[4];	/* 4 Unsigned Word */
+	char			b[8];	/* 8 Byte (8-bit) values */
+	unsigned char		ub[8];	/* 8 Unsigned Byte */
+	float			s[2];	/* Single-precision (32-bit) value */
+} __attribute__ ((aligned (8))) mmx_t;	/* On an 8-byte (64-bit) boundary */
+
+
+
+/*	Function to test if multimedia instructions are supported...
+*/
+static int
+mm_support(void)
+{
+	/* Returns 1 if MMX instructions are supported,
+	   3 if Cyrix MMX and Extended MMX instructions are supported
+	   5 if AMD MMX and 3DNow! instructions are supported
+		 13 if AMD Extended MMX, &3dNow supported
+	   0 if hardware does not support any of these
+	*/
+	register int rval = 0;
+
+	__asm__ __volatile__ (
+		/* See if CPUID instruction is supported ... */
+		/* ... Get copies of EFLAGS into eax and ecx */
+    "pushl %%ebx\n\t"
+		"pushf\n\t"
+		"popl %%eax\n\t"
+		"movl %%eax, %%ecx\n\t"
+
+		/* ... Toggle the ID bit in one copy and store */
+		/*     to the EFLAGS reg */
+		"xorl $0x200000, %%eax\n\t"
+		"push %%eax\n\t"
+		"popf\n\t"
+
+		/* ... Get the (hopefully modified) EFLAGS */
+		"pushf\n\t"
+		"popl %%eax\n\t"
+
+		/* ... Compare and test result */
+		"xorl %%eax, %%ecx\n\t"
+		"testl $0x200000, %%ecx\n\t"
+		"jz NotSupported1\n\t"		/* CPUID not supported */
+
+
+		/* Get standard CPUID information, and
+		       go to a specific vendor section */
+		"movl $0, %%eax\n\t"
+		"cpuid\n\t"
+
+		/* Check for Intel */
+		"cmpl $0x756e6547, %%ebx\n\t"
+		"jne TryAMD\n\t"
+		"cmpl $0x49656e69, %%edx\n\t"
+		"jne TryAMD\n\t"
+		"cmpl $0x6c65746e, %%ecx\n"
+		"jne TryAMD\n\t"
+		"jmp Intel\n\t"
+
+		/* Check for AMD */
+		"\nTryAMD:\n\t"
+		"cmpl $0x68747541, %%ebx\n\t"
+		"jne TryCyrix\n\t"
+		"cmpl $0x69746e65, %%edx\n\t"
+		"jne TryCyrix\n\t"
+		"cmpl $0x444d4163, %%ecx\n"
+		"jne TryCyrix\n\t"
+		"jmp AMD\n\t"
+
+		/* Check for Cyrix */
+		"\nTryCyrix:\n\t"
+		"cmpl $0x69727943, %%ebx\n\t"
+		"jne NotSupported2\n\t"
+		"cmpl $0x736e4978, %%edx\n\t"
+		"jne NotSupported3\n\t"
+		"cmpl $0x64616574, %%ecx\n\t"
+		"jne NotSupported4\n\t"
+		/* Drop through to Cyrix... */
+
+
+		/* Cyrix Section */
+		/* See if extended CPUID level 80000001 is supported */
+		/* The value of CPUID/80000001 for the 6x86MX is undefined
+		   according to the Cyrix CPU Detection Guide (Preliminary
+		   Rev. 1.01 table 1), so we'll check the value of eax for
+		   CPUID/0 to see if standard CPUID level 2 is supported.
+		   According to the table, the only CPU which supports level
+		   2 is also the only one which supports extended CPUID levels.
+		*/
+		"cmpl $0x2, %%eax\n\t"
+		"jne MMXtest\n\t"	/* Use standard CPUID instead */
+
+		/* Extended CPUID supported (in theory), so get extended
+		   features */
+		"movl $0x80000001, %%eax\n\t"
+		"cpuid\n\t"
+		"testl $0x00800000, %%eax\n\t"	/* Test for MMX */
+		"jz NotSupported5\n\t"		/* MMX not supported */
+		"testl $0x01000000, %%eax\n\t"	/* Test for Ext'd MMX */
+		"jnz EMMXSupported\n\t"
+		"movl $1, %0\n\n\t"		/* MMX Supported */
+		"jmp Return\n\n"
+		"EMMXSupported:\n\t"
+		"movl $3, %0\n\n\t"		/* EMMX and MMX Supported */
+		"jmp Return\n\t"
+
+
+		/* AMD Section */
+		"AMD:\n\t"
+
+		/* See if extended CPUID is supported */
+		"movl $0x80000000, %%eax\n\t"
+		"cpuid\n\t"
+		"cmpl $0x80000000, %%eax\n\t"
+		"jl MMXtest\n\t"	/* Use standard CPUID instead */
+
+		/* Extended CPUID supported, so get extended features */
+		"movl $0x80000001, %%eax\n\t"
+		"cpuid\n\t"
+		"testl $0x00800000, %%edx\n\t"	/* Test for MMX */
+		"jz NotSupported6\n\t"		/* MMX not supported */
+		"testl $0x80000000, %%edx\n\t"	/* Test for 3DNow! */
+		"jnz ThreeDNowSupported\n\t"
+		"movl $1, %0\n\n\t"		/* MMX Supported */
+		"jmp Return\n\n"
+		"ThreeDNowSupported:\n\t"
+		"testl $0x40000000, %%edx\n\t" /* Test AMD Extended MMX */
+		"jnz AMDXMMXSupported\n\t"
+		"movl $5, %0\n\n\t"		/* 3DNow! and MMX Supported */
+		"jmp Return\n\t"
+		"AMDXMMXSupported:\n\t"
+		"movl $13, %0\n\n\t"		/* XMMX, 3DNow! and MMX Supported */
+		"jmp Return\n\t"
+
+
+		/* Intel Section */
+		"Intel:\n\t"
+
+		/* Check for MMX */
+		"MMXtest:\n\t"
+		"movl $1, %%eax\n\t"
+		"cpuid\n\t"
+		"testl $0x00800000, %%edx\n\t"	/* Test for MMX */
+		"jz NotSupported7\n\t"		/* MMX Not supported */
+		"movl $1, %0\n\n\t"		/* MMX Supported */
+		"jmp Return\n\t"
+
+		/* Nothing supported */
+		"\nNotSupported1:\n\t"
+		"#movl $101, %0\n\n\t"
+		"\nNotSupported2:\n\t"
+		"#movl $102, %0\n\n\t"
+		"\nNotSupported3:\n\t"
+		"#movl $103, %0\n\n\t"
+		"\nNotSupported4:\n\t"
+		"#movl $104, %0\n\n\t"
+		"\nNotSupported5:\n\t"
+		"#movl $105, %0\n\n\t"
+		"\nNotSupported6:\n\t"
+		"#movl $106, %0\n\n\t"
+		"\nNotSupported7:\n\t"
+		"#movl $107, %0\n\n\t"
+		"movl $0, %0\n\n\t"
+
+		"Return:\n\t"
+    "popl %%ebx\n\t"
+		: "=X" (rval)
+		: /* no input */
+		: "eax", "ecx", "edx"
+	);
+
+	/* Return */
+	return(rval);
+}
+
+/*	Function to test if mmx instructions are supported...
+*/
+static inline int
+mmx_ok(void)
+{
+	/* Returns 1 if MMX instructions are supported, 0 otherwise */
+	return ( mm_support() & 0x1 );
+}
+
+int mmx_supported (void);
+int xmmx_supported (void);
+
+
+/* MMX optimized implementations */
+void draw_line_mmx (Pixel *data, int x1, int y1, int x2, int y2, int col, int screenx, int screeny);
+void draw_line_xmmx (Pixel *data, int x1, int y1, int x2, int y2, int col, int screenx, int screeny);
+void zoom_filter_mmx (int prevX, int prevY, Pixel *expix1, Pixel *expix2,
+		      int *brutS, int *brutD, int buffratio, int precalCoef[16][16]);
+void zoom_filter_xmmx (int prevX, int prevY, Pixel *expix1, Pixel *expix2,
+                       int *lbruS, int *lbruD, int buffratio, int precalCoef[16][16]);
+
+
+/*	Helper functions for the instruction macros that follow...
+	(note that memory-to-register, m2r, instructions are nearly
+	 as efficient as register-to-register, r2r, instructions;
+	 however, memory-to-memory instructions are really simulated
+	 as a convenience, and are only 1/3 as efficient)
+*/
+#ifdef	MMX_TRACE
+
+/*	Include the stuff for printing a trace to stderr...
+*/
+
+#include <stdio.h>
+
+#define	mmx_i2r(op, imm, reg) \
+	{ \
+		mmx_t mmx_trace; \
+		mmx_trace.uq = (imm); \
+		printf(#op "_i2r(" #imm "=0x%08x%08x, ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		printf(#reg "=0x%08x%08x) => ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ (#op " %0, %%" #reg \
+				      : /* nothing */ \
+				      : "X" (imm)); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		printf(#reg "=0x%08x%08x\n", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+	}
+
+#define	mmx_m2r(op, mem, reg) \
+	{ \
+		mmx_t mmx_trace; \
+		mmx_trace = (mem); \
+		printf(#op "_m2r(" #mem "=0x%08x%08x, ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		printf(#reg "=0x%08x%08x) => ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ (#op " %0, %%" #reg \
+				      : /* nothing */ \
+				      : "m" (mem)); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		printf(#reg "=0x%08x%08x\n", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+	}
+
+#define	mmx_r2m(op, reg, mem) \
+	{ \
+		mmx_t mmx_trace; \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		printf(#op "_r2m(" #reg "=0x%08x%08x, ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		mmx_trace = (mem); \
+		printf(#mem "=0x%08x%08x) => ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ (#op " %%" #reg ", %0" \
+				      : "=m" (mem) \
+				      : /* nothing */ ); \
+		mmx_trace = (mem); \
+		printf(#mem "=0x%08x%08x\n", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+	}
+
+#define	mmx_r2r(op, regs, regd) \
+	{ \
+		mmx_t mmx_trace; \
+		__asm__ __volatile__ ("movq %%" #regs ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		printf(#op "_r2r(" #regs "=0x%08x%08x, ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ ("movq %%" #regd ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		printf(#regd "=0x%08x%08x) => ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ (#op " %" #regs ", %" #regd); \
+		__asm__ __volatile__ ("movq %%" #regd ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		printf(#regd "=0x%08x%08x\n", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+	}
+
+#define	mmx_m2m(op, mems, memd) \
+	{ \
+		mmx_t mmx_trace; \
+		mmx_trace = (mems); \
+		printf(#op "_m2m(" #mems "=0x%08x%08x, ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		mmx_trace = (memd); \
+		printf(#memd "=0x%08x%08x) => ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ ("movq %0, %%mm0\n\t" \
+				      #op " %1, %%mm0\n\t" \
+				      "movq %%mm0, %0" \
+				      : "=m" (memd) \
+				      : "m" (mems)); \
+		mmx_trace = (memd); \
+		printf(#memd "=0x%08x%08x\n", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+	}
+
+#else
+
+/*	These macros are a lot simpler without the tracing...
+*/
+
+#define	mmx_i2r(op, imm, reg) \
+	__asm__ __volatile__ (#op " %0, %%" #reg \
+			      : /* nothing */ \
+			      : "X" (imm) )
+
+#define	mmx_m2r(op, mem, reg) \
+	__asm__ __volatile__ (#op " %0, %%" #reg \
+			      : /* nothing */ \
+			      : "m" (mem))
+
+#define	mmx_r2m(op, reg, mem) \
+	__asm__ __volatile__ (#op " %%" #reg ", %0" \
+			      : "=m" (mem) \
+			      : /* nothing */ )
+
+#define	mmx_r2r(op, regs, regd) \
+	__asm__ __volatile__ (#op " %" #regs ", %" #regd)
+
+#define	mmx_m2m(op, mems, memd) \
+	__asm__ __volatile__ ("movq %0, %%mm0\n\t" \
+			      #op " %1, %%mm0\n\t" \
+			      "movq %%mm0, %0" \
+			      : "=m" (memd) \
+			      : "m" (mems))
+
+#endif
+
+
+/*	1x64 MOVe Quadword
+	(this is both a load and a store...
+	 in fact, it is the only way to store)
+*/
+#define	movq_m2r(var, reg)	mmx_m2r(movq, var, reg)
+#define	movq_r2m(reg, var)	mmx_r2m(movq, reg, var)
+#define	movq_r2r(regs, regd)	mmx_r2r(movq, regs, regd)
+#define	movq(vars, vard) \
+	__asm__ __volatile__ ("movq %1, %%mm0\n\t" \
+			      "movq %%mm0, %0" \
+			      : "=X" (vard) \
+			      : "X" (vars))
+
+
+/*	1x32 MOVe Doubleword
+	(like movq, this is both load and store...
+	 but is most useful for moving things between
+	 mmx registers and ordinary registers)
+*/
+#define	movd_m2r(var, reg)	mmx_m2r(movd, var, reg)
+#define	movd_r2m(reg, var)	mmx_r2m(movd, reg, var)
+#define	movd_r2r(regs, regd)	mmx_r2r(movd, regs, regd)
+#define	movd(vars, vard) \
+	__asm__ __volatile__ ("movd %1, %%mm0\n\t" \
+			      "movd %%mm0, %0" \
+			      : "=X" (vard) \
+			      : "X" (vars))
+
+
+/*	2x32, 4x16, and 8x8 Parallel ADDs
+*/
+#define	paddd_m2r(var, reg)	mmx_m2r(paddd, var, reg)
+#define	paddd_r2r(regs, regd)	mmx_r2r(paddd, regs, regd)
+#define	paddd(vars, vard)	mmx_m2m(paddd, vars, vard)
+
+#define	paddw_m2r(var, reg)	mmx_m2r(paddw, var, reg)
+#define	paddw_r2r(regs, regd)	mmx_r2r(paddw, regs, regd)
+#define	paddw(vars, vard)	mmx_m2m(paddw, vars, vard)
+
+#define	paddb_m2r(var, reg)	mmx_m2r(paddb, var, reg)
+#define	paddb_r2r(regs, regd)	mmx_r2r(paddb, regs, regd)
+#define	paddb(vars, vard)	mmx_m2m(paddb, vars, vard)
+
+
+/*	4x16 and 8x8 Parallel ADDs using Saturation arithmetic
+*/
+#define	paddsw_m2r(var, reg)	mmx_m2r(paddsw, var, reg)
+#define	paddsw_r2r(regs, regd)	mmx_r2r(paddsw, regs, regd)
+#define	paddsw(vars, vard)	mmx_m2m(paddsw, vars, vard)
+
+#define	paddsb_m2r(var, reg)	mmx_m2r(paddsb, var, reg)
+#define	paddsb_r2r(regs, regd)	mmx_r2r(paddsb, regs, regd)
+#define	paddsb(vars, vard)	mmx_m2m(paddsb, vars, vard)
+
+
+/*	4x16 and 8x8 Parallel ADDs using Unsigned Saturation arithmetic
+*/
+#define	paddusw_m2r(var, reg)	mmx_m2r(paddusw, var, reg)
+#define	paddusw_r2r(regs, regd)	mmx_r2r(paddusw, regs, regd)
+#define	paddusw(vars, vard)	mmx_m2m(paddusw, vars, vard)
+
+#define	paddusb_m2r(var, reg)	mmx_m2r(paddusb, var, reg)
+#define	paddusb_r2r(regs, regd)	mmx_r2r(paddusb, regs, regd)
+#define	paddusb(vars, vard)	mmx_m2m(paddusb, vars, vard)
+
+
+/*	2x32, 4x16, and 8x8 Parallel SUBs
+*/
+#define	psubd_m2r(var, reg)	mmx_m2r(psubd, var, reg)
+#define	psubd_r2r(regs, regd)	mmx_r2r(psubd, regs, regd)
+#define	psubd(vars, vard)	mmx_m2m(psubd, vars, vard)
+
+#define	psubw_m2r(var, reg)	mmx_m2r(psubw, var, reg)
+#define	psubw_r2r(regs, regd)	mmx_r2r(psubw, regs, regd)
+#define	psubw(vars, vard)	mmx_m2m(psubw, vars, vard)
+
+#define	psubb_m2r(var, reg)	mmx_m2r(psubb, var, reg)
+#define	psubb_r2r(regs, regd)	mmx_r2r(psubb, regs, regd)
+#define	psubb(vars, vard)	mmx_m2m(psubb, vars, vard)
+
+
+/*	4x16 and 8x8 Parallel SUBs using Saturation arithmetic
+*/
+#define	psubsw_m2r(var, reg)	mmx_m2r(psubsw, var, reg)
+#define	psubsw_r2r(regs, regd)	mmx_r2r(psubsw, regs, regd)
+#define	psubsw(vars, vard)	mmx_m2m(psubsw, vars, vard)
+
+#define	psubsb_m2r(var, reg)	mmx_m2r(psubsb, var, reg)
+#define	psubsb_r2r(regs, regd)	mmx_r2r(psubsb, regs, regd)
+#define	psubsb(vars, vard)	mmx_m2m(psubsb, vars, vard)
+
+
+/*	4x16 and 8x8 Parallel SUBs using Unsigned Saturation arithmetic
+*/
+#define	psubusw_m2r(var, reg)	mmx_m2r(psubusw, var, reg)
+#define	psubusw_r2r(regs, regd)	mmx_r2r(psubusw, regs, regd)
+#define	psubusw(vars, vard)	mmx_m2m(psubusw, vars, vard)
+
+#define	psubusb_m2r(var, reg)	mmx_m2r(psubusb, var, reg)
+#define	psubusb_r2r(regs, regd)	mmx_r2r(psubusb, regs, regd)
+#define	psubusb(vars, vard)	mmx_m2m(psubusb, vars, vard)
+
+
+/*	4x16 Parallel MULs giving Low 4x16 portions of results
+*/
+#define	pmullw_m2r(var, reg)	mmx_m2r(pmullw, var, reg)
+#define	pmullw_r2r(regs, regd)	mmx_r2r(pmullw, regs, regd)
+#define	pmullw(vars, vard)	mmx_m2m(pmullw, vars, vard)
+
+
+/*	4x16 Parallel MULs giving High 4x16 portions of results
+*/
+#define	pmulhw_m2r(var, reg)	mmx_m2r(pmulhw, var, reg)
+#define	pmulhw_r2r(regs, regd)	mmx_r2r(pmulhw, regs, regd)
+#define	pmulhw(vars, vard)	mmx_m2m(pmulhw, vars, vard)
+
+
+/*	4x16->2x32 Parallel Mul-ADD
+	(muls like pmullw, then adds adjacent 16-bit fields
+	 in the multiply result to make the final 2x32 result)
+*/
+#define	pmaddwd_m2r(var, reg)	mmx_m2r(pmaddwd, var, reg)
+#define	pmaddwd_r2r(regs, regd)	mmx_r2r(pmaddwd, regs, regd)
+#define	pmaddwd(vars, vard)	mmx_m2m(pmaddwd, vars, vard)
+
+
+/*	1x64 bitwise AND
+*/
+#ifdef	BROKEN_PAND
+#define	pand_m2r(var, reg) \
+	{ \
+		mmx_m2r(pandn, (mmx_t) -1LL, reg); \
+		mmx_m2r(pandn, var, reg); \
+	}
+#define	pand_r2r(regs, regd) \
+	{ \
+		mmx_m2r(pandn, (mmx_t) -1LL, regd); \
+		mmx_r2r(pandn, regs, regd) \
+	}
+#define	pand(vars, vard) \
+	{ \
+		movq_m2r(vard, mm0); \
+		mmx_m2r(pandn, (mmx_t) -1LL, mm0); \
+		mmx_m2r(pandn, vars, mm0); \
+		movq_r2m(mm0, vard); \
+	}
+#else
+#define	pand_m2r(var, reg)	mmx_m2r(pand, var, reg)
+#define	pand_r2r(regs, regd)	mmx_r2r(pand, regs, regd)
+#define	pand(vars, vard)	mmx_m2m(pand, vars, vard)
+#endif
+
+
+/*	1x64 bitwise AND with Not the destination
+*/
+#define	pandn_m2r(var, reg)	mmx_m2r(pandn, var, reg)
+#define	pandn_r2r(regs, regd)	mmx_r2r(pandn, regs, regd)
+#define	pandn(vars, vard)	mmx_m2m(pandn, vars, vard)
+
+
+/*	1x64 bitwise OR
+*/
+#define	por_m2r(var, reg)	mmx_m2r(por, var, reg)
+#define	por_r2r(regs, regd)	mmx_r2r(por, regs, regd)
+#define	por(vars, vard)	mmx_m2m(por, vars, vard)
+
+
+/*	1x64 bitwise eXclusive OR
+*/
+#define	pxor_m2r(var, reg)	mmx_m2r(pxor, var, reg)
+#define	pxor_r2r(regs, regd)	mmx_r2r(pxor, regs, regd)
+#define	pxor(vars, vard)	mmx_m2m(pxor, vars, vard)
+
+
+/*	2x32, 4x16, and 8x8 Parallel CoMPare for EQuality
+	(resulting fields are either 0 or -1)
+*/
+#define	pcmpeqd_m2r(var, reg)	mmx_m2r(pcmpeqd, var, reg)
+#define	pcmpeqd_r2r(regs, regd)	mmx_r2r(pcmpeqd, regs, regd)
+#define	pcmpeqd(vars, vard)	mmx_m2m(pcmpeqd, vars, vard)
+
+#define	pcmpeqw_m2r(var, reg)	mmx_m2r(pcmpeqw, var, reg)
+#define	pcmpeqw_r2r(regs, regd)	mmx_r2r(pcmpeqw, regs, regd)
+#define	pcmpeqw(vars, vard)	mmx_m2m(pcmpeqw, vars, vard)
+
+#define	pcmpeqb_m2r(var, reg)	mmx_m2r(pcmpeqb, var, reg)
+#define	pcmpeqb_r2r(regs, regd)	mmx_r2r(pcmpeqb, regs, regd)
+#define	pcmpeqb(vars, vard)	mmx_m2m(pcmpeqb, vars, vard)
+
+
+/*	2x32, 4x16, and 8x8 Parallel CoMPare for Greater Than
+	(resulting fields are either 0 or -1)
+*/
+#define	pcmpgtd_m2r(var, reg)	mmx_m2r(pcmpgtd, var, reg)
+#define	pcmpgtd_r2r(regs, regd)	mmx_r2r(pcmpgtd, regs, regd)
+#define	pcmpgtd(vars, vard)	mmx_m2m(pcmpgtd, vars, vard)
+
+#define	pcmpgtw_m2r(var, reg)	mmx_m2r(pcmpgtw, var, reg)
+#define	pcmpgtw_r2r(regs, regd)	mmx_r2r(pcmpgtw, regs, regd)
+#define	pcmpgtw(vars, vard)	mmx_m2m(pcmpgtw, vars, vard)
+
+#define	pcmpgtb_m2r(var, reg)	mmx_m2r(pcmpgtb, var, reg)
+#define	pcmpgtb_r2r(regs, regd)	mmx_r2r(pcmpgtb, regs, regd)
+#define	pcmpgtb(vars, vard)	mmx_m2m(pcmpgtb, vars, vard)
+
+
+/*	1x64, 2x32, and 4x16 Parallel Shift Left Logical
+*/
+#define	psllq_i2r(imm, reg)	mmx_i2r(psllq, imm, reg)
+#define	psllq_m2r(var, reg)	mmx_m2r(psllq, var, reg)
+#define	psllq_r2r(regs, regd)	mmx_r2r(psllq, regs, regd)
+#define	psllq(vars, vard)	mmx_m2m(psllq, vars, vard)
+
+#define	pslld_i2r(imm, reg)	mmx_i2r(pslld, imm, reg)
+#define	pslld_m2r(var, reg)	mmx_m2r(pslld, var, reg)
+#define	pslld_r2r(regs, regd)	mmx_r2r(pslld, regs, regd)
+#define	pslld(vars, vard)	mmx_m2m(pslld, vars, vard)
+
+#define	psllw_i2r(imm, reg)	mmx_i2r(psllw, imm, reg)
+#define	psllw_m2r(var, reg)	mmx_m2r(psllw, var, reg)
+#define	psllw_r2r(regs, regd)	mmx_r2r(psllw, regs, regd)
+#define	psllw(vars, vard)	mmx_m2m(psllw, vars, vard)
+
+
+/*	1x64, 2x32, and 4x16 Parallel Shift Right Logical
+*/
+#define	psrlq_i2r(imm, reg)	mmx_i2r(psrlq, imm, reg)
+#define	psrlq_m2r(var, reg)	mmx_m2r(psrlq, var, reg)
+#define	psrlq_r2r(regs, regd)	mmx_r2r(psrlq, regs, regd)
+#define	psrlq(vars, vard)	mmx_m2m(psrlq, vars, vard)
+
+#define	psrld_i2r(imm, reg)	mmx_i2r(psrld, imm, reg)
+#define	psrld_m2r(var, reg)	mmx_m2r(psrld, var, reg)
+#define	psrld_r2r(regs, regd)	mmx_r2r(psrld, regs, regd)
+#define	psrld(vars, vard)	mmx_m2m(psrld, vars, vard)
+
+#define	psrlw_i2r(imm, reg)	mmx_i2r(psrlw, imm, reg)
+#define	psrlw_m2r(var, reg)	mmx_m2r(psrlw, var, reg)
+#define	psrlw_r2r(regs, regd)	mmx_r2r(psrlw, regs, regd)
+#define	psrlw(vars, vard)	mmx_m2m(psrlw, vars, vard)
+
+
+/*	2x32 and 4x16 Parallel Shift Right Arithmetic
+*/
+#define	psrad_i2r(imm, reg)	mmx_i2r(psrad, imm, reg)
+#define	psrad_m2r(var, reg)	mmx_m2r(psrad, var, reg)
+#define	psrad_r2r(regs, regd)	mmx_r2r(psrad, regs, regd)
+#define	psrad(vars, vard)	mmx_m2m(psrad, vars, vard)
+
+#define	psraw_i2r(imm, reg)	mmx_i2r(psraw, imm, reg)
+#define	psraw_m2r(var, reg)	mmx_m2r(psraw, var, reg)
+#define	psraw_r2r(regs, regd)	mmx_r2r(psraw, regs, regd)
+#define	psraw(vars, vard)	mmx_m2m(psraw, vars, vard)
+
+
+/*	2x32->4x16 and 4x16->8x8 PACK and Signed Saturate
+	(packs source and dest fields into dest in that order)
+*/
+#define	packssdw_m2r(var, reg)	mmx_m2r(packssdw, var, reg)
+#define	packssdw_r2r(regs, regd) mmx_r2r(packssdw, regs, regd)
+#define	packssdw(vars, vard)	mmx_m2m(packssdw, vars, vard)
+
+#define	packsswb_m2r(var, reg)	mmx_m2r(packsswb, var, reg)
+#define	packsswb_r2r(regs, regd) mmx_r2r(packsswb, regs, regd)
+#define	packsswb(vars, vard)	mmx_m2m(packsswb, vars, vard)
+
+
+/*	4x16->8x8 PACK and Unsigned Saturate
+	(packs source and dest fields into dest in that order)
+*/
+#define	packuswb_m2r(var, reg)	mmx_m2r(packuswb, var, reg)
+#define	packuswb_r2r(regs, regd) mmx_r2r(packuswb, regs, regd)
+#define	packuswb(vars, vard)	mmx_m2m(packuswb, vars, vard)
+
+
+/*	2x32->1x64, 4x16->2x32, and 8x8->4x16 UNPaCK Low
+	(interleaves low half of dest with low half of source
+	 as padding in each result field)
+*/
+#define	punpckldq_m2r(var, reg)	mmx_m2r(punpckldq, var, reg)
+#define	punpckldq_r2r(regs, regd) mmx_r2r(punpckldq, regs, regd)
+#define	punpckldq(vars, vard)	mmx_m2m(punpckldq, vars, vard)
+
+#define	punpcklwd_m2r(var, reg)	mmx_m2r(punpcklwd, var, reg)
+#define	punpcklwd_r2r(regs, regd) mmx_r2r(punpcklwd, regs, regd)
+#define	punpcklwd(vars, vard)	mmx_m2m(punpcklwd, vars, vard)
+
+#define	punpcklbw_m2r(var, reg)	mmx_m2r(punpcklbw, var, reg)
+#define	punpcklbw_r2r(regs, regd) mmx_r2r(punpcklbw, regs, regd)
+#define	punpcklbw(vars, vard)	mmx_m2m(punpcklbw, vars, vard)
+
+
+/*	2x32->1x64, 4x16->2x32, and 8x8->4x16 UNPaCK High
+	(interleaves high half of dest with high half of source
+	 as padding in each result field)
+*/
+#define	punpckhdq_m2r(var, reg)	mmx_m2r(punpckhdq, var, reg)
+#define	punpckhdq_r2r(regs, regd) mmx_r2r(punpckhdq, regs, regd)
+#define	punpckhdq(vars, vard)	mmx_m2m(punpckhdq, vars, vard)
+
+#define	punpckhwd_m2r(var, reg)	mmx_m2r(punpckhwd, var, reg)
+#define	punpckhwd_r2r(regs, regd) mmx_r2r(punpckhwd, regs, regd)
+#define	punpckhwd(vars, vard)	mmx_m2m(punpckhwd, vars, vard)
+
+#define	punpckhbw_m2r(var, reg)	mmx_m2r(punpckhbw, var, reg)
+#define	punpckhbw_r2r(regs, regd) mmx_r2r(punpckhbw, regs, regd)
+#define	punpckhbw(vars, vard)	mmx_m2m(punpckhbw, vars, vard)
+
+
+/*	Empty MMx State
+	(used to clean-up when going from mmx to float use
+	 of the registers that are shared by both; note that
+	 there is no float-to-mmx operation needed, because
+	 only the float tag word info is corruptible)
+*/
+#ifdef	MMX_TRACE
+
+#ifdef __clang__
+#define emms() \
+	{ \
+		printf("emms()\n"); \
+		__asm__ __volatile__ ("emms"); \
+	}
+#else
+#define	emms() \
+	{ \
+		printf("emms()\n"); \
+		__asm__ __volatile__ ("emms" \
+                        "st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)"); \
+	}
+#endif
+
+#else
+
+#ifdef __clang__
+#define	emms() __asm__ __volatile__ ("emms")
+#else
+#define	emms() __asm__ __volatile__ ("emms"::: \
+                      "st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)")
+#endif
+
+#endif
+
+#endif
+
diff --git a/gst/goom/motif_goom1.h b/gst/goom/motif_goom1.h
new file mode 100644
index 0000000..82f381b
--- /dev/null
+++ b/gst/goom/motif_goom1.h
@@ -0,0 +1,1044 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+static Motif CONV_MOTIF1 = {
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,14,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,13,9,9,7,2,2,9,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,11,
+	11,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,12,7,4,0,0,0,2,0,0,3,14,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,12,10,9,9,4,1,0,
+	1,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,10,3,0,0,0,1,1,3,5,0,0,1,14,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,14,6,3,1,1,4,9,1,
+	1,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	10,3,0,0,2,7,13,14,14,14,7,0,0,2,14,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,12,1,9,15,15,15,15,3,
+	0,13,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,12,4,
+	0,0,2,10,15,15,15,15,15,15,1,0,0,10,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,9,0,2,14,15,15,15,7,
+	0,9,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,14,6,0,0,
+	2,9,15,15,15,15,15,15,15,13,0,0,3,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,11,0,0,10,15,15,15,9,
+	0,9,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,13,3,0,1,5,
+	5,4,4,4,6,12,15,15,15,13,0,0,7,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,14,0,0,5,15,15,15,10,
+	0,7,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,11,1,0,3,3,1,
+	0,0,0,0,0,0,5,13,15,12,0,0,13,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,13,14,15,
+	15,15,15,15,15,15,15,15,14,0,0,1,15,15,15,12,
+	0,3,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,10,1,2,4,0,0,1,
+	9,12,12,12,9,3,0,2,14,5,0,7,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,14,7,4,4,1,1,12,
+	15,15,15,15,15,15,15,15,14,1,0,0,12,15,15,15,
+	1,0,12,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,10,0,3,2,0,0,3,12,
+	15,15,15,15,15,14,2,1,13,2,0,12,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,14,3,0,0,0,0,0,2,
+	13,15,15,15,15,15,15,15,14,1,0,0,8,15,15,15,
+	1,0,9,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,12,2,1,0,0,0,9,14,15,
+	15,15,15,15,15,14,1,1,11,0,3,14,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,7,4,11,12,10,1,0,
+	3,12,15,15,15,15,15,15,13,1,1,0,4,15,15,15,
+	2,0,10,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,14,2,1,0,0,3,12,15,15,15,
+	15,15,15,15,15,11,0,5,9,1,12,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,5,1,13,15,15,12,1,
+	0,1,9,15,15,15,15,15,14,2,5,0,1,14,15,15,
+	2,0,7,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,14,3,0,0,0,7,14,15,15,15,15,
+	15,15,15,15,15,9,0,8,7,4,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,7,0,7,8,11,15,13,
+	2,0,0,3,10,15,15,15,15,5,11,0,0,11,15,15,
+	6,0,2,14,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,6,0,0,0,8,15,15,15,15,15,15,
+	15,15,15,15,15,6,0,4,0,6,15,15,15,15,15,15,
+	14,9,14,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,11,0,3,3,0,8,15,
+	14,5,0,0,0,4,12,15,15,5,13,2,0,6,15,15,
+	12,0,0,11,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,10,0,0,0,8,15,15,15,15,15,15,15,
+	15,15,15,15,10,1,7,6,4,13,15,15,15,15,13,11,
+	6,0,8,11,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,1,1,11,2,0,5,
+	14,15,8,0,0,0,0,7,15,5,14,6,0,2,15,15,
+	15,3,0,5,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,13,1,0,0,7,15,15,15,15,15,15,15,15,
+	15,15,15,15,7,9,15,15,15,15,15,15,12,6,2,1,
+	1,1,8,6,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,4,0,6,12,1,0,
+	3,13,15,11,2,0,0,0,8,4,14,10,0,0,13,15,
+	15,7,0,1,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,5,0,0,5,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,13,15,15,15,15,14,8,3,1,2,7,11,
+	5,4,5,6,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,8,0,1,14,11,0,
+	0,1,9,15,14,5,0,0,2,4,14,13,0,0,10,15,
+	15,12,0,0,12,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,10,0,0,1,14,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,14,13,7,2,0,5,9,15,15,15,
+	5,3,6,9,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,13,0,0,9,15,12,
+	2,0,0,4,13,14,4,0,3,2,12,15,1,0,5,15,
+	15,14,1,0,8,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,2,0,0,9,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,12,11,6,1,0,2,3,10,15,15,15,15,7,
+	1,2,4,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,5,0,3,14,15,
+	9,2,0,0,1,6,12,13,13,1,9,12,0,0,2,14,
+	15,15,4,0,4,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,10,0,0,2,14,15,15,15,15,15,15,15,15,15,15,
+	13,9,6,0,1,2,9,10,15,15,15,15,14,7,1,0,
+	6,2,4,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,11,0,0,9,15,
+	4,4,11,6,1,0,0,1,1,0,10,4,0,0,0,12,
+	15,15,9,0,1,14,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,3,0,0,8,15,15,15,15,15,15,15,13,12,4,4,
+	1,1,3,10,12,15,15,15,15,15,9,2,1,0,1,6,
+	6,0,10,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,4,0,3,14,
+	4,3,15,15,14,9,7,9,1,0,0,0,0,1,0,7,
+	15,15,13,0,0,9,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	13,0,0,1,14,15,15,15,15,15,12,9,1,0,1,4,
+	7,15,15,15,15,15,15,14,8,2,0,0,0,2,13,9,
+	0,4,14,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,11,0,0,9,
+	3,0,8,14,15,15,15,15,10,5,4,4,7,4,0,3,
+	15,15,15,4,0,3,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	5,0,0,5,15,15,15,15,14,8,7,8,10,12,14,15,
+	15,15,15,15,15,15,11,1,0,0,0,5,11,15,13,1,
+	1,13,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,3,0,4,
+	4,0,0,2,6,10,15,15,15,15,15,15,15,10,0,0,
+	12,15,15,9,0,0,12,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	1,0,0,10,15,15,15,15,15,13,14,15,15,15,15,15,
+	15,15,15,15,14,7,1,0,0,3,12,15,15,15,6,0,
+	7,15,15,15,12,10,9,10,12,14,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,9,0,0,
+	8,3,1,4,1,0,1,12,15,15,15,15,15,14,2,0,
+	6,15,15,15,2,0,6,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	0,0,1,14,15,15,15,15,14,5,15,15,15,15,15,15,
+	15,15,15,7,2,0,0,1,8,15,15,15,15,12,0,2,
+	14,15,12,4,0,0,0,0,0,1,5,10,14,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,14,0,0,
+	5,4,1,14,15,10,7,13,15,15,15,15,15,15,8,0,
+	1,14,15,15,7,0,1,14,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,13,
+	0,0,4,15,15,15,15,15,13,2,13,15,15,15,15,15,
+	12,7,0,0,0,0,5,12,15,15,15,15,14,3,0,9,
+	11,1,0,0,1,1,0,1,0,0,0,0,2,12,15,15,
+	15,15,15,15,15,15,15,14,15,15,15,15,15,15,2,0,
+	5,2,1,14,15,14,13,15,15,15,15,15,15,15,12,0,
+	0,10,15,15,13,0,0,9,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,12,
+	0,0,4,15,15,15,15,15,12,0,12,15,15,15,12,6,
+	0,0,0,0,6,14,15,15,15,15,15,15,7,0,0,12,
+	1,0,0,2,2,1,1,7,12,8,3,0,0,1,13,15,
+	15,15,15,15,15,8,4,8,12,15,15,15,15,15,8,0,
+	4,2,0,14,15,11,9,15,15,15,15,15,15,15,15,3,
+	0,5,15,15,15,5,0,3,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,12,
+	0,0,4,15,15,15,15,15,12,0,12,15,13,3,1,0,
+	0,0,5,12,15,15,15,15,15,15,15,12,0,0,7,7,
+	0,0,0,0,0,0,0,1,12,15,15,12,3,0,5,15,
+	15,15,15,14,5,0,0,0,0,2,2,3,7,14,9,8,
+	14,2,1,14,15,2,12,13,15,15,15,15,15,15,15,9,
+	0,0,13,15,15,10,0,0,12,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,13,
+	0,0,5,15,15,15,15,15,12,0,11,10,1,0,0,1,
+	5,14,15,15,15,15,15,15,15,15,15,6,0,2,7,0,
+	0,0,0,1,2,7,4,0,3,14,15,15,14,2,0,12,
+	15,15,15,9,0,1,2,1,0,0,0,0,0,1,3,7,
+	15,3,0,14,15,4,12,15,15,15,15,15,15,15,15,14,
+	1,0,8,15,15,14,1,0,8,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,13,
+	0,0,4,15,15,15,15,15,12,0,2,0,0,1,10,15,
+	15,15,15,15,15,15,15,15,15,15,12,0,0,6,0,0,
+	0,1,10,14,15,15,11,1,0,9,15,15,15,8,0,9,
+	15,15,12,4,8,14,15,8,1,0,0,0,0,0,1,9,
+	15,2,0,13,15,1,9,15,15,15,15,15,15,15,15,15,
+	6,0,1,14,15,14,1,0,3,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,14,
+	1,0,1,14,15,15,15,15,12,1,3,7,9,13,15,15,
+	15,15,15,15,15,15,15,15,15,15,3,0,2,3,0,4,
+	0,8,15,15,15,15,15,13,1,2,14,15,15,10,0,6,
+	15,14,2,6,15,15,15,1,3,7,3,0,0,0,0,1,
+	11,1,0,11,12,0,12,15,15,15,15,15,15,15,15,15,
+	11,0,0,9,15,15,4,0,0,12,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	6,0,0,9,15,15,15,15,15,12,14,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,11,0,0,3,0,8,14,
+	2,5,15,15,15,15,15,15,5,0,8,15,15,12,0,4,
+	15,5,2,14,15,15,10,0,13,15,13,2,4,5,5,0,
+	9,1,0,10,9,1,14,15,15,15,15,15,15,15,15,15,
+	13,0,0,3,15,15,9,0,0,8,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	12,0,0,3,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,3,0,1,1,5,14,15,
+	11,0,12,15,15,15,15,15,14,1,1,14,15,12,0,4,
+	10,0,9,15,15,11,1,8,15,15,8,1,14,15,14,2,
+	5,0,0,10,6,2,15,15,15,15,15,15,15,15,15,15,
+	15,3,0,0,12,15,13,0,0,2,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,3,0,0,10,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,10,0,0,1,0,11,15,15,
+	15,2,6,15,15,15,15,15,15,6,0,9,15,13,0,6,
+	3,0,13,15,14,2,6,15,15,13,1,8,15,15,15,4,
+	3,1,0,10,7,2,15,15,15,15,15,15,15,15,15,15,
+	15,9,0,0,6,15,15,3,0,0,13,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,9,0,0,2,14,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,11,10,2,0,3,0,3,15,15,15,
+	15,8,1,14,15,15,15,15,15,13,0,2,15,9,1,10,
+	0,3,15,15,6,2,14,15,14,3,1,14,15,15,15,2,
+	4,0,0,12,5,3,15,15,15,15,15,15,15,15,15,15,
+	15,14,1,0,1,14,15,5,0,0,12,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,4,0,0,6,15,15,15,15,15,15,15,15,14,12,
+	12,9,5,4,4,3,0,0,0,0,4,0,8,15,15,15,
+	15,13,1,10,15,15,15,15,15,15,2,0,11,3,5,10,
+	0,7,15,9,1,11,15,15,8,0,6,15,15,15,10,0,
+	3,0,0,13,3,6,15,15,15,15,15,15,15,15,15,15,
+	15,15,6,0,0,12,15,5,0,0,7,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,13,1,0,0,8,14,15,15,13,6,4,4,1,0,
+	0,0,0,0,0,0,2,0,0,4,3,0,12,15,15,15,
+	15,15,5,3,15,15,15,15,14,8,0,0,1,1,12,9,
+	0,9,10,0,6,15,15,15,2,2,14,15,15,13,2,0,
+	4,0,1,13,0,10,15,15,15,15,15,15,15,15,15,15,
+	15,15,13,1,0,10,15,10,0,0,5,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,9,0,0,0,3,2,2,1,0,0,0,1,4,
+	4,5,10,12,12,12,11,0,0,11,4,0,12,15,15,15,
+	15,15,12,0,7,13,15,15,5,0,0,0,1,6,15,9,
+	0,3,0,0,1,6,14,10,0,12,15,15,11,2,0,2,
+	3,0,3,12,1,11,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,3,0,6,8,7,0,0,5,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,9,1,0,0,0,2,6,10,12,12,14,15,
+	15,15,15,15,11,5,4,0,2,14,4,0,12,15,15,15,
+	15,15,15,4,0,3,13,6,0,0,0,1,2,14,15,12,
+	0,0,0,0,0,0,2,2,6,15,14,8,0,0,0,7,
+	4,0,4,12,0,12,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,12,0,0,0,0,0,0,1,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,12,2,0,0,0,1,6,11,15,15,15,
+	15,15,15,15,2,1,0,0,9,15,6,0,7,15,15,15,
+	15,15,15,13,2,0,0,0,0,0,0,1,12,15,15,15,
+	4,0,0,0,0,0,0,6,13,6,1,0,0,4,13,15,
+	6,0,6,12,0,12,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,14,5,0,0,0,0,0,5,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,14,5,0,0,0,0,0,2,4,5,
+	7,3,6,3,0,2,0,2,15,15,11,0,0,9,15,15,
+	15,15,15,15,11,0,0,0,0,0,2,11,15,15,15,15,
+	12,1,0,0,1,4,6,10,2,0,0,0,7,14,15,15,
+	9,0,9,9,0,12,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,13,9,8,9,7,13,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,12,6,1,0,0,0,0,0,
+	0,0,0,2,8,0,0,9,15,15,14,4,0,0,3,10,
+	14,15,15,15,15,13,3,0,0,4,14,15,15,15,15,15,
+	15,11,2,0,0,1,1,0,0,0,1,11,15,15,15,15,
+	9,0,10,5,3,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,14,12,10,5,4,6,
+	2,4,10,14,8,0,1,14,15,15,15,14,5,0,0,0,
+	1,2,4,4,4,3,1,2,9,14,15,15,15,15,15,15,
+	15,15,15,11,11,13,10,9,9,11,15,15,15,15,15,15,
+	10,0,8,2,4,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	2,7,15,14,1,0,6,15,15,15,15,15,15,10,6,4,
+	2,2,4,4,4,3,9,14,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	11,0,3,1,4,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,11,
+	1,10,15,9,0,0,13,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	11,0,11,11,11,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,2,
+	5,15,14,2,0,5,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	14,1,13,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,10,1,
+	13,15,11,0,0,12,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,5,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,8,1,
+	15,15,5,0,3,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,10,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,12,2,3,
+	15,14,1,0,7,15,15,15,15,15,13,15,15,15,15,14,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,13,12,12,11,9,4,7,14,15,
+	14,13,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,12,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,14,3,0,10,
+	15,9,0,0,8,7,4,2,2,1,0,3,4,3,4,9,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,14,13,11,7,4,2,0,0,0,0,0,0,1,12,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,14,13,11,7,4,2,2,13,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,12,0,3,11,
+	7,1,0,0,0,0,0,1,4,9,11,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,14,12,11,9,7,4,
+	3,1,0,0,0,0,0,0,0,0,0,2,11,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,13,11,8,
+	4,3,1,0,0,0,0,3,8,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,14,11,3,0,0,0,
+	0,0,0,2,6,9,12,14,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,13,9,6,3,1,0,0,0,0,0,0,
+	0,0,0,0,1,4,7,11,12,12,12,14,15,15,15,15,
+	15,15,15,15,15,15,15,14,12,11,7,4,2,0,0,0,
+	0,0,0,1,5,10,13,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,14,12,7,3,1,0,0,0,2,5,
+	2,0,2,14,15,15,15,15,15,15,15,15,15,14,13,12,
+	11,9,6,4,2,0,0,0,0,0,0,0,0,1,2,4,
+	5,9,11,13,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,14,12,11,7,4,3,1,0,0,0,0,0,0,0,1,
+	4,5,10,14,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,13,10,5,1,0,0,0,1,0,0,2,13,14,
+	1,0,8,15,15,14,12,11,9,8,4,3,2,1,0,0,
+	0,0,0,0,1,3,2,3,5,9,10,12,13,14,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,13,11,10,6,4,
+	3,1,0,0,0,0,0,0,0,0,1,4,7,11,13,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,11,4,0,0,0,1,4,9,13,13,1,0,0,1,7,
+	0,0,7,8,5,2,0,0,0,0,0,0,1,2,3,4,
+	5,9,10,12,14,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,14,11,8,4,3,1,0,0,0,0,0,
+	0,0,0,0,1,4,5,9,12,13,15,15,15,15,15,15,
+	15,15,14,12,9,8,8,7,4,2,5,4,5,5,12,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,14,10,5,
+	1,0,1,3,6,11,14,15,15,15,15,13,12,8,3,2,
+	0,0,1,1,3,3,4,5,8,10,12,13,14,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,13,
+	11,9,6,4,2,1,0,0,0,0,0,0,0,1,2,4,
+	6,10,11,13,15,15,15,15,15,15,15,15,13,11,9,7,
+	4,2,1,0,0,0,0,2,4,7,12,14,14,14,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,10,5,1,1,3,
+	8,12,14,15,15,15,15,15,15,15,15,15,15,15,15,9,
+	3,11,14,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,8,6,9,9,9,9,9,8,5,4,4,3,1,0,
+	0,0,0,0,1,2,3,2,4,5,9,11,12,14,15,15,
+	15,15,15,15,15,15,15,14,12,9,5,2,0,0,0,0,
+	0,1,2,4,7,10,14,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,14,9,4,1,3,9,13,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,13,
+	11,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,13,3,1,1,1,1,1,1,1,0,0,0,0,2,3,
+	5,8,10,12,14,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,12,5,2,0,0,0,1,3,4,7,10,
+	12,13,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,13,11,13,13,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,14,12,12,12,13,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,8,1,0,1,4,7,11,13,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,13,7,8,11,14,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15}
+	};
diff --git a/gst/goom/motif_goom2.h b/gst/goom/motif_goom2.h
new file mode 100644
index 0000000..2de92af
--- /dev/null
+++ b/gst/goom/motif_goom2.h
@@ -0,0 +1,1044 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+static Motif CONV_MOTIF2 = {
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,12,5,14,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,12,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,10,1,14,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,10,0,12,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,6,0,12,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,7,0,8,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,13,2,0,10,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,6,0,2,14,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,5,0,0,10,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,9,0,0,12,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,14,9,0,0,1,14,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,8,0,0,8,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,14,8,3,0,0,0,9,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,11,0,0,2,14,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,13,9,5,3,4,1,0,0,0,0,7,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,14,4,0,0,4,11,13,13,15,15,14,12,10,8,5,
+	6,4,1,0,0,0,0,0,0,0,0,0,0,14,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,12,1,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,9,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	13,9,10,13,14,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,12,3,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,2,5,6,0,0,0,0,12,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	5,0,0,0,3,10,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,14,9,2,1,0,0,0,1,4,6,6,1,
+	0,0,0,8,13,15,15,15,12,1,0,2,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,14,
+	2,0,0,0,0,0,4,12,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,3,0,0,10,15,15,15,10,
+	0,0,4,15,15,15,15,15,15,2,0,6,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,5,
+	3,11,5,0,0,0,0,0,4,11,14,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,7,0,0,13,15,15,15,11,
+	0,0,7,15,15,15,15,15,15,1,0,9,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,9,0,
+	13,15,15,12,5,0,0,0,0,0,1,8,14,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,7,0,1,14,15,15,15,11,
+	0,0,7,15,15,15,15,15,14,0,0,9,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,11,1,10,
+	15,15,15,15,15,11,5,0,0,0,0,0,1,6,13,15,
+	15,15,15,15,14,8,11,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,6,0,2,15,15,15,15,11,
+	0,0,6,15,15,15,15,15,13,0,0,11,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,11,1,6,15,
+	15,15,15,15,15,15,15,14,5,0,0,0,0,0,0,6,
+	14,15,15,15,6,0,4,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,7,0,5,15,15,15,15,11,
+	0,0,5,15,15,15,15,15,12,0,0,12,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,13,2,1,13,15,
+	15,15,15,15,15,15,15,15,15,12,2,0,0,0,0,0,
+	1,6,11,7,0,0,4,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,7,0,7,15,15,15,15,11,
+	0,0,6,15,15,15,15,15,12,0,0,12,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,5,0,7,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,11,5,0,0,0,
+	0,0,0,0,0,1,11,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,7,0,10,15,15,15,15,11,
+	0,0,6,15,15,15,15,15,12,0,0,12,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,10,0,4,14,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,13,7,0,
+	0,0,0,0,0,1,6,12,14,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,7,0,10,15,15,15,15,11,
+	0,0,7,15,15,15,15,15,12,0,0,12,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,13,1,1,12,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,13,
+	5,0,0,0,0,0,0,0,3,10,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,7,0,10,15,15,15,15,11,
+	0,0,7,15,15,15,15,15,11,0,0,13,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,14,4,0,8,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	13,0,0,0,1,0,0,0,0,1,13,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,7,0,10,15,15,15,15,11,
+	0,0,8,15,15,15,15,15,8,0,2,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,9,0,4,14,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,14,
+	4,0,0,5,13,12,6,2,0,2,13,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,7,0,10,15,15,15,15,11,
+	0,0,7,15,15,15,15,15,4,0,4,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,13,1,1,13,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,11,
+	0,0,1,13,15,15,15,14,9,13,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,5,0,6,15,15,15,15,11,
+	0,0,8,15,15,15,15,15,2,0,8,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,5,0,9,15,15,15,15,15,15,
+	15,15,15,15,15,15,14,11,15,15,15,15,15,15,15,9,
+	0,0,10,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,4,0,4,15,15,15,15,11,
+	0,0,7,15,15,15,15,13,0,0,11,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,10,0,3,14,15,15,15,15,15,15,
+	15,15,15,15,15,14,3,0,13,15,15,15,15,15,15,14,
+	9,11,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,4,0,4,15,15,15,15,11,
+	0,0,8,15,15,15,15,12,0,0,12,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,14,2,1,12,15,15,15,15,15,15,15,
+	15,15,15,15,14,3,0,0,9,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,6,0,3,15,15,15,15,13,
+	1,0,8,15,15,15,15,12,0,0,12,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,9,0,5,15,15,15,15,15,15,15,15,
+	15,15,15,14,4,0,0,0,10,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,8,0,2,15,15,15,15,15,
+	3,0,13,15,15,15,15,12,0,0,12,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,13,2,1,12,15,15,15,15,15,15,15,15,
+	15,15,15,7,0,0,0,0,8,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,10,0,1,14,15,15,15,15,
+	11,5,15,15,15,15,15,12,0,0,11,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,6,0,7,15,15,15,15,15,15,15,15,15,
+	15,15,8,0,0,0,0,0,0,9,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,12,0,0,12,15,15,15,15,
+	15,14,15,15,15,15,15,10,0,0,12,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,13,1,2,14,15,15,15,15,15,15,15,15,15,
+	15,10,0,0,0,6,6,0,0,0,5,12,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,12,12,
+	15,15,15,15,15,15,15,15,13,0,0,11,15,15,15,15,
+	15,15,15,15,15,15,15,9,0,1,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,7,0,8,15,15,15,15,15,15,15,15,15,15,
+	15,9,0,0,4,15,15,8,0,0,0,1,5,13,15,15,
+	15,15,15,15,15,15,15,15,15,15,12,8,7,6,5,3,
+	3,3,4,12,15,15,15,15,15,15,15,15,15,7,0,6,
+	15,15,15,15,15,15,15,15,14,1,0,10,15,15,15,15,
+	15,15,15,15,15,15,15,6,0,3,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,13,1,0,13,15,15,15,15,15,15,15,15,15,15,
+	15,14,7,8,13,15,15,15,11,2,0,0,0,0,5,11,
+	15,15,15,15,15,15,15,15,13,3,0,0,0,0,0,0,
+	0,0,0,5,15,15,15,15,15,15,15,15,12,1,0,0,
+	3,11,15,15,15,15,15,15,13,1,0,10,15,15,15,15,
+	15,15,15,15,15,15,15,3,0,5,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,9,0,5,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,14,8,1,0,0,0,0,
+	4,12,15,15,15,15,15,15,4,0,0,0,0,0,0,0,
+	0,0,0,2,15,15,15,15,15,15,15,14,4,0,0,0,
+	0,0,9,15,15,15,15,15,14,1,0,10,15,15,15,15,
+	15,15,15,15,15,15,15,2,0,9,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,14,4,0,11,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,14,8,2,0,0,
+	0,0,4,10,14,15,15,15,4,0,0,0,0,0,0,0,
+	0,0,0,3,15,15,15,15,15,15,15,6,0,0,0,2,
+	3,0,0,8,15,15,15,15,14,1,0,10,15,15,15,15,
+	15,15,15,15,15,15,15,1,0,9,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	14,5,0,4,14,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,14,9,3,
+	0,0,0,0,2,5,10,15,5,0,1,11,11,12,13,15,
+	11,0,0,7,15,15,15,15,15,15,8,0,0,0,1,12,
+	14,6,0,0,7,14,15,15,14,1,0,9,15,15,15,15,
+	15,15,15,15,15,15,15,2,0,10,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	9,0,1,13,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,14,
+	10,2,0,0,0,0,1,14,4,0,1,14,15,15,15,15,
+	9,0,0,9,15,15,15,15,15,9,0,0,0,0,9,15,
+	15,15,7,0,0,6,14,15,15,3,0,6,15,15,15,15,
+	15,15,15,15,15,15,15,1,0,9,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,9,
+	0,0,1,10,14,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,13,1,0,0,0,1,14,3,0,0,14,15,15,15,15,
+	5,0,0,11,15,15,15,15,13,1,0,0,0,6,15,15,
+	15,15,15,8,0,0,2,10,15,6,0,3,15,15,15,15,
+	15,15,15,15,15,15,15,2,0,10,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,13,1,
+	0,0,0,0,3,9,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,6,1,0,0,0,8,15,1,0,0,14,15,15,15,15,
+	4,0,0,13,15,15,15,14,4,0,0,0,3,14,15,15,
+	15,15,15,15,5,0,0,1,14,9,0,1,14,15,15,15,
+	15,15,15,15,15,15,15,1,0,9,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,13,1,
+	0,0,0,0,0,0,4,12,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	9,0,0,0,0,7,15,15,1,0,0,14,15,15,15,14,
+	2,0,1,14,15,15,15,12,0,0,0,3,13,15,15,15,
+	15,15,15,9,0,0,0,1,14,12,0,0,12,15,15,15,
+	15,15,15,15,15,15,14,1,0,10,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,12,
+	3,0,0,0,0,0,0,1,8,14,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,9,
+	0,0,0,0,7,15,15,15,1,0,0,14,15,15,15,13,
+	0,0,1,15,15,15,15,12,0,0,0,6,14,15,15,15,
+	15,15,12,0,0,0,0,3,14,12,0,0,12,15,15,15,
+	15,15,15,15,15,15,12,0,0,12,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,13,3,0,0,0,0,0,0,1,6,13,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,12,0,
+	0,0,0,3,15,15,15,12,0,0,0,14,15,15,15,11,
+	0,0,3,15,15,15,15,15,12,7,0,0,4,14,15,15,
+	15,11,1,0,0,0,4,13,15,12,0,0,12,15,15,15,
+	15,15,15,15,15,15,10,0,1,14,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,12,7,0,0,0,0,0,0,0,3,8,12,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,4,0,
+	0,0,1,13,15,15,15,6,0,0,0,14,15,15,15,8,
+	0,0,7,15,15,15,15,15,15,15,8,1,0,2,13,15,
+	14,2,0,0,0,4,14,15,15,13,1,0,10,15,15,15,
+	15,15,15,15,15,15,9,0,2,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,11,6,2,0,0,0,0,0,0,0,1,
+	10,15,15,15,15,15,15,15,15,15,15,15,15,8,0,0,
+	0,0,10,15,15,15,15,4,0,0,1,15,15,15,15,4,
+	0,0,8,15,15,15,15,15,15,15,15,10,1,0,1,8,
+	2,0,0,0,5,15,15,15,15,15,2,0,6,15,15,15,
+	15,15,15,15,15,15,9,0,1,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,9,1,0,0,0,0,0,0,
+	0,1,7,13,14,15,15,15,15,15,15,15,9,0,0,0,
+	0,6,15,15,15,15,15,4,0,0,4,15,15,15,14,1,
+	0,0,9,15,15,15,15,15,15,15,15,15,12,2,0,0,
+	0,0,0,4,14,15,15,15,15,15,4,0,4,15,15,15,
+	15,15,15,15,15,15,7,0,0,14,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,14,11,6,2,0,0,0,
+	0,0,0,0,1,9,12,15,15,15,15,14,3,0,0,0,
+	4,15,15,15,15,15,15,4,0,0,3,6,4,4,2,0,
+	0,0,13,15,15,15,15,15,15,15,15,15,15,12,1,0,
+	0,0,3,14,15,15,15,15,15,15,4,0,4,15,15,15,
+	15,15,15,15,15,15,5,0,0,12,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,8,2,0,
+	0,0,0,0,0,0,0,1,9,15,15,5,0,0,0,0,
+	12,15,15,15,15,15,15,4,0,0,0,0,0,0,0,0,
+	0,3,15,15,15,15,15,15,15,15,15,15,15,14,4,0,
+	0,1,12,15,15,15,15,15,15,15,6,0,1,14,15,15,
+	15,15,15,15,15,15,5,0,0,13,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,12,
+	7,1,0,0,0,0,0,0,0,5,7,0,0,0,0,10,
+	15,15,15,15,15,15,15,7,0,0,0,0,0,0,0,0,
+	1,10,15,15,15,15,15,15,15,15,15,15,15,14,3,0,
+	3,12,15,15,15,15,15,15,15,15,12,0,0,12,15,15,
+	15,15,15,15,15,15,5,0,0,1,1,4,11,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,11,6,1,0,0,0,0,0,0,0,0,0,7,15,
+	15,15,15,15,15,15,15,14,7,4,4,4,5,9,12,13,
+	14,15,15,15,15,15,15,15,15,15,15,15,15,15,11,9,
+	14,15,15,14,12,11,11,11,10,9,7,0,0,5,13,15,
+	15,15,15,15,15,12,1,0,0,0,0,0,0,10,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,14,7,1,0,0,0,0,0,3,14,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,13,2,0,0,0,0,0,0,0,0,0,0,0,8,
+	15,15,15,15,15,11,0,0,0,0,0,0,0,9,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,13,5,0,0,0,0,12,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,8,0,0,0,0,0,0,0,0,0,0,0,0,5,
+	15,15,15,15,15,15,10,5,6,7,7,7,9,14,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,8,3,2,2,2,2,5,14,15,
+	15,15,15,15,15,15,15,15,15,10,3,0,6,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,13,3,1,0,1,0,1,1,2,4,4,3,9,14,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,12,4,0,1,6,7,7,4,1,3,13,
+	15,15,15,15,15,15,15,15,15,15,14,10,13,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,11,11,15,15,15,15,
+	15,15,15,14,14,14,14,14,14,14,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,14,2,0,4,13,15,15,15,15,10,0,12,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,14,13,14,12,12,12,12,12,12,12,
+	12,14,15,15,15,15,15,15,15,15,4,14,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,7,1,5,14,15,15,15,15,15,12,1,11,
+	15,15,15,13,12,13,15,15,14,11,13,15,15,15,15,15,
+	15,15,15,11,6,3,1,1,1,0,0,0,0,0,0,0,
+	0,1,4,7,11,14,15,15,15,14,4,15,13,10,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,14,7,4,5,
+	12,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,13,1,1,14,15,15,14,10,12,15,11,1,12,
+	15,15,11,1,0,4,15,15,6,0,2,14,15,15,15,15,
+	15,15,14,8,6,3,3,2,2,1,0,0,0,0,0,0,
+	0,0,0,0,0,3,11,15,15,11,8,15,12,6,15,9,
+	8,15,15,15,15,15,15,15,15,15,15,15,10,4,4,1,
+	4,15,15,15,15,11,6,2,8,14,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,12,0,4,15,15,15,11,2,10,15,9,1,13,
+	15,13,1,7,6,2,14,14,1,2,1,14,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,13,12,12,12,12,12,12,
+	11,11,11,10,9,10,12,15,15,6,7,15,9,4,15,4,
+	1,14,15,15,15,15,15,15,15,15,15,15,2,11,15,4,
+	4,15,15,15,15,3,9,4,0,9,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,12,0,4,15,15,15,5,0,6,6,1,9,15,
+	15,4,1,13,10,1,13,9,2,7,1,14,14,14,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,3,5,15,3,5,14,1,
+	0,12,13,9,14,15,15,15,15,15,15,15,2,2,4,1,
+	6,15,15,15,14,1,5,6,0,9,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,12,0,4,15,15,15,12,4,2,2,10,15,15,
+	11,0,6,15,12,0,10,7,9,10,1,14,7,14,15,15,
+	15,15,15,15,15,15,13,12,11,11,10,9,9,10,11,13,
+	15,15,15,15,15,15,15,15,15,1,9,15,2,7,14,1,
+	0,10,7,0,8,15,15,15,15,15,15,15,11,4,4,4,
+	13,15,15,15,15,10,2,2,4,14,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,12,0,4,15,15,15,15,15,15,15,15,15,15,
+	4,2,14,15,15,1,9,5,14,9,1,14,8,14,15,15,
+	15,15,15,15,15,10,3,0,1,0,0,0,0,0,0,5,
+	15,15,15,15,15,15,15,15,15,1,9,14,1,8,14,1,
+	0,11,13,6,11,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,14,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,12,0,4,15,15,15,15,15,15,15,15,15,11,
+	0,6,15,15,15,1,5,3,13,10,0,6,8,15,15,15,
+	15,15,15,15,15,15,13,12,12,11,10,9,9,10,11,13,
+	15,15,15,15,15,15,15,15,15,1,9,12,1,11,15,4,
+	1,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	14,10,4,2,12,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,12,1,3,14,15,15,15,15,15,15,15,15,4,
+	3,14,15,15,15,5,1,8,15,14,5,2,9,15,15,15,
+	15,15,15,15,15,15,15,15,15,11,9,13,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,1,9,12,1,12,15,13,
+	11,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	10,2,9,2,3,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,14,4,0,5,14,15,15,15,15,15,15,11,0,
+	6,15,15,15,15,15,14,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,8,1,0,3,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,1,9,15,11,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	7,1,12,6,1,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,11,1,0,3,8,9,9,10,11,9,5,4,
+	13,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,12,9,13,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,5,11,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	10,3,4,1,5,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,12,2,0,0,0,0,0,0,1,8,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,14,12,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,13,8,8,10,9,10,11,14,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
+	{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15}
+	};
diff --git a/gst/goom/plugin_info.c b/gst/goom/plugin_info.c
new file mode 100644
index 0000000..96d570c
--- /dev/null
+++ b/gst/goom/plugin_info.c
@@ -0,0 +1,262 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "goom_config.h"
+
+#include "goom_plugin_info.h"
+#include "goom_fx.h"
+#include "drawmethods.h"
+#include <math.h>
+#include <stdio.h>
+#ifdef HAVE_ORC
+#include <orc/orc.h>
+#endif
+
+
+#if defined (HAVE_CPU_PPC64) || defined (HAVE_CPU_PPC)
+#include "ppc_zoom_ultimate.h"
+#include "ppc_drawings.h"
+#endif /* HAVE_CPU_PPC64 || HAVE_CPU_PPC */
+
+
+#ifdef HAVE_MMX
+#include "mmx.h"
+#endif /* HAVE_MMX */
+
+#include <string.h>
+
+GST_DEBUG_CATEGORY_EXTERN (goom_debug);
+#define GST_CAT_DEFAULT goom_debug
+
+static void
+setOptimizedMethods (PluginInfo * p)
+{
+#ifdef HAVE_ORC
+  unsigned int cpuFlavour =
+      orc_target_get_default_flags (orc_target_get_by_name ("mmx"));
+#else
+  unsigned int cpuFlavour = 0;
+#endif
+
+  /* set default methods */
+  p->methods.draw_line = draw_line;
+  p->methods.zoom_filter = zoom_filter_c;
+/*    p->methods.create_output_with_brightness = create_output_with_brightness;*/
+
+  GST_INFO ("orc cpu flags: 0x%08x", cpuFlavour);
+
+/* FIXME: what about HAVE_CPU_X86_64 ? */
+#ifdef HAVE_CPU_I386
+#ifdef HAVE_MMX
+#ifdef HAVE_ORC
+  GST_INFO ("have an x86");
+  if (cpuFlavour & ORC_TARGET_MMX_MMXEXT) {
+    GST_INFO ("Extended MMX detected. Using the fastest methods!");
+    p->methods.draw_line = draw_line_xmmx;
+    p->methods.zoom_filter = zoom_filter_xmmx;
+  } else if (cpuFlavour & ORC_TARGET_MMX_MMX) {
+    GST_INFO ("MMX detected. Using fast methods!");
+    p->methods.draw_line = draw_line_mmx;
+    p->methods.zoom_filter = zoom_filter_mmx;
+  } else {
+    GST_INFO ("Too bad ! No SIMD optimization available for your CPU.");
+  }
+#endif
+#endif
+#endif /* HAVE_CPU_I386 */
+
+/* disable all PPC stuff until someone finds out what to use here instead of
+ * CPU_OPTION_64_BITS, and until someone fixes the assembly build for ppc */
+#if 0
+#ifdef HAVE_CPU_PPC64
+  if ((cpuFlavour & CPU_OPTION_64_BITS) != 0) {
+/*            p->methods.create_output_with_brightness = ppc_brightness_G5;        */
+    p->methods.zoom_filter = ppc_zoom_generic;
+  }
+#endif /* HAVE_CPU_PPC64 */
+
+#ifdef HAVE_CPU_PPC
+  if ((cpuFlavour & ORC_TARGET_ALTIVEC_ALTIVEC) != 0) {
+/*            p->methods.create_output_with_brightness = ppc_brightness_G4;        */
+    p->methods.zoom_filter = ppc_zoom_G4;
+  } else {
+/*            p->methods.create_output_with_brightness = ppc_brightness_generic;*/
+    p->methods.zoom_filter = ppc_zoom_generic;
+  }
+#endif /* HAVE_CPU_PPC */
+#endif
+}
+
+void
+plugin_info_init (PluginInfo * pp, int nbVisuals)
+{
+
+  int i;
+
+  memset (pp, 0, sizeof (PluginInfo));
+
+  pp->sound.speedvar = pp->sound.accelvar = pp->sound.totalgoom = 0;
+  pp->sound.prov_max = 0;
+  pp->sound.goom_limit = 1;
+  pp->sound.allTimesMax = 1;
+  pp->sound.timeSinceLastGoom = 1;
+  pp->sound.timeSinceLastBigGoom = 1;
+  pp->sound.cycle = 0;
+
+  secure_f_feedback (&pp->sound.volume_p, "Sound Volume");
+  secure_f_feedback (&pp->sound.accel_p, "Sound Acceleration");
+  secure_f_feedback (&pp->sound.speed_p, "Sound Speed");
+  secure_f_feedback (&pp->sound.goom_limit_p, "Goom Limit");
+  secure_f_feedback (&pp->sound.last_goom_p, "Goom Detection");
+  secure_f_feedback (&pp->sound.last_biggoom_p, "Big Goom Detection");
+  secure_f_feedback (&pp->sound.goom_power_p, "Goom Power");
+
+  secure_i_param (&pp->sound.biggoom_speed_limit_p, "Big Goom Speed Limit");
+  IVAL (pp->sound.biggoom_speed_limit_p) = 10;
+  IMIN (pp->sound.biggoom_speed_limit_p) = 0;
+  IMAX (pp->sound.biggoom_speed_limit_p) = 100;
+  ISTEP (pp->sound.biggoom_speed_limit_p) = 1;
+
+  secure_i_param (&pp->sound.biggoom_factor_p, "Big Goom Factor");
+  IVAL (pp->sound.biggoom_factor_p) = 10;
+  IMIN (pp->sound.biggoom_factor_p) = 0;
+  IMAX (pp->sound.biggoom_factor_p) = 100;
+  ISTEP (pp->sound.biggoom_factor_p) = 1;
+
+  plugin_parameters (&pp->sound.params, "Sound", 11);
+
+  pp->nbParams = 0;
+  pp->params = NULL;
+  pp->nbVisuals = nbVisuals;
+  pp->visuals = (VisualFX **) malloc (sizeof (VisualFX *) * nbVisuals);
+
+  pp->sound.params.params[0] = &pp->sound.biggoom_speed_limit_p;
+  pp->sound.params.params[1] = &pp->sound.biggoom_factor_p;
+  pp->sound.params.params[2] = 0;
+  pp->sound.params.params[3] = &pp->sound.volume_p;
+  pp->sound.params.params[4] = &pp->sound.accel_p;
+  pp->sound.params.params[5] = &pp->sound.speed_p;
+  pp->sound.params.params[6] = 0;
+  pp->sound.params.params[7] = &pp->sound.goom_limit_p;
+  pp->sound.params.params[8] = &pp->sound.goom_power_p;
+  pp->sound.params.params[9] = &pp->sound.last_goom_p;
+  pp->sound.params.params[10] = &pp->sound.last_biggoom_p;
+
+  pp->statesNumber = 8;
+  pp->statesRangeMax = 510;
+  {
+    GoomState states[8] = {
+      {1, 0, 0, 1, 4, 0, 100}
+      ,
+      {1, 0, 0, 0, 1, 101, 140}
+      ,
+      {1, 0, 0, 1, 2, 141, 200}
+      ,
+      {0, 1, 0, 1, 2, 201, 260}
+      ,
+      {0, 1, 0, 1, 0, 261, 330}
+      ,
+      {0, 1, 1, 1, 4, 331, 400}
+      ,
+      {0, 0, 1, 0, 5, 401, 450}
+      ,
+      {0, 0, 1, 1, 1, 451, 510}
+    };
+    for (i = 0; i < 8; ++i)
+      pp->states[i] = states[i];
+  }
+  pp->curGState = &(pp->states[6]);
+
+  /* datas for the update loop */
+  pp->update.lockvar = 0;
+  pp->update.goomvar = 0;
+  pp->update.loopvar = 0;
+  pp->update.stop_lines = 0;
+  pp->update.ifs_incr = 1;      /* dessiner l'ifs (0 = non: > = increment) */
+  pp->update.decay_ifs = 0;     /* disparition de l'ifs */
+  pp->update.recay_ifs = 0;     /* dedisparition de l'ifs */
+  pp->update.cyclesSinceLastChange = 0;
+  pp->update.drawLinesDuration = 80;
+  pp->update.lineMode = pp->update.drawLinesDuration;
+
+  pp->update.switchMultAmount = (29.0f / 30.0f);
+  pp->update.switchIncrAmount = 0x7f;
+  pp->update.switchMult = 1.0f;
+  pp->update.switchIncr = pp->update.switchIncrAmount;
+
+  pp->update.stateSelectionRnd = 0;
+  pp->update.stateSelectionBlocker = 0;
+  pp->update.previousZoomSpeed = 128;
+
+  {
+    ZoomFilterData zfd = {
+      127, 8, 16,
+      1, 1, 0, NORMAL_MODE,
+      0, 0, 0, 0, 0
+    };
+    pp->update.zoomFilterData = zfd;
+  }
+
+  setOptimizedMethods (pp);
+
+  for (i = 0; i < 0xffff; i++) {
+    pp->sintable[i] =
+        (int) (1024 * sin ((double) i * 360 / (sizeof (pp->sintable) /
+                sizeof (pp->sintable[0]) - 1) * 3.141592 / 180) + .5);
+    /* sintable [us] = (int)(1024.0f * sin (us*2*3.31415f/0xffff)) ; */
+  }
+}
+
+void
+plugin_info_add_visual (PluginInfo * p, int i, VisualFX * visual)
+{
+  p->visuals[i] = visual;
+  if (i == p->nbVisuals - 1) {
+    ++i;
+    p->nbParams = 1;
+    while (i--) {
+      if (p->visuals[i]->params)
+        p->nbParams++;
+    }
+    p->params =
+        (PluginParameters *) malloc (sizeof (PluginParameters) * p->nbParams);
+    i = p->nbVisuals;
+    p->nbParams = 1;
+    p->params[0] = p->sound.params;
+    while (i--) {
+      if (p->visuals[i]->params)
+        p->params[p->nbParams++] = *(p->visuals[i]->params);
+    }
+  }
+}
+
+void
+plugin_info_free (PluginInfo * p)
+{
+  goom_plugin_parameters_free (&p->sound.params);
+
+  if (p->params)
+    free (p->params);
+  free (p->visuals);
+}
diff --git a/gst/goom/ppc_drawings.h b/gst/goom/ppc_drawings.h
new file mode 100644
index 0000000..d35adf6
--- /dev/null
+++ b/gst/goom/ppc_drawings.h
@@ -0,0 +1,28 @@
+/* Goom Project
+ * Copyright (C) <2003> Guillaume Borios, iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* Generic PowerPC Code */
+void ppc_brightness_generic(Pixel *src, Pixel *dest, int size, int coeff);
+
+/* G4 Specific PowerPC Code (Possible use of Altivec and Data Streams) */
+void ppc_brightness_G4(Pixel *src, Pixel *dest, int size, int coeff);
+
+/* G5 Specific PowerPC Code (Possible use of Altivec) */
+void ppc_brightness_G5(Pixel *src, Pixel *dest, int size, int coeff);
+
diff --git a/gst/goom/ppc_drawings.s b/gst/goom/ppc_drawings.s
new file mode 100644
index 0000000..943cce7
--- /dev/null
+++ b/gst/goom/ppc_drawings.s
@@ -0,0 +1,394 @@
+; PowerPC optimized drawing methods for Goom
+; © 2003 Guillaume Borios
+; 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., 51 Franklin St, Fifth Floor,
+; Boston, MA 02110-1301, USA.
+
+; Change log :
+; 30 May 2003 : File creation
+
+; Section definition : We use a read only code section for the whole file
+.section __TEXT,__text,regular,pure_instructions
+
+
+; --------------------------------------------------------------------------------------
+; Single 32b pixel drawing macros
+; Usage :
+; 	DRAWMETHOD_XXXX_MACRO *pixelIN, *pixelOUT, COLOR, WR1, WR2, WR3, WR4
+;	Only the work registers (WR) can be touched by the macros
+;
+; Available methods :
+;	DRAWMETHOD_DFLT_MACRO : Default drawing method (Actually OVRW)
+;	DRAWMETHOD_PLUS_MACRO : RVB Saturated per channel addition (SLOWEST)
+;	DRAWMETHOD_HALF_MACRO : 50% Transparency color drawing
+;	DRAWMETHOD_OVRW_MACRO : Direct COLOR drawing (FASTEST)
+;	DRAWMETHOD_B_OR_MACRO : Bitwise OR
+;	DRAWMETHOD_BAND_MACRO : Bitwise AND
+;	DRAWMETHOD_BXOR_MACRO : Bitwise XOR
+;	DRAWMETHOD_BNOT_MACRO : Bitwise NOT
+; --------------------------------------------------------------------------------------
+
+.macro DRAWMETHOD_OVRW_MACRO
+    stw		$2,0($1)	;; *$1 <- $2
+.endmacro
+
+.macro DRAWMETHOD_B_OR_MACRO
+    lwz		$3,0($0)	;; $3 <- *$0
+    or		$3,$3,$2	;; $3 <- $3 | $2
+    stw		$3,0($1)	;; *$1 <- $3
+.endmacro
+
+.macro DRAWMETHOD_BAND_MACRO
+    lwz		$3,0($0)	;; $3 <- *$0
+    and		$3,$3,$2	;; $3 <- $3 & $2
+    stw		$3,0($1)	;; *$1 <- $3
+.endmacro
+
+.macro DRAWMETHOD_BXOR_MACRO
+    lwz		$3,0($0)	;; $3 <- *$0
+    xor		$3,$3,$2	;; $3 <- $3 ^ $2
+    stw		$3,0($1)	;; *$1 <- $3
+.endmacro
+
+.macro DRAWMETHOD_BNOT_MACRO
+    lwz		$3,0($0)	;; $3 <- *$0
+    nand	$3,$3,$3	;; $3 <- ~$3
+    stw		$3,0($1)	;; *$1 <- $3
+.endmacro
+
+.macro DRAWMETHOD_PLUS_MACRO
+    lwz		$4,0($0)	;; $4 <- *$0
+    andi.	$3,$4,0xFF00	;; $3 <- $4 & 0x0000FF00
+    andi.	$5,$2,0xFF00	;; $5 <- $2 & 0x0000FF00
+    add		$3,$3,$5	;; $3 <- $3 + $5
+    rlwinm	$5,$3,15,0,0	;; $5 <- 0 | ($3[15] << 15)
+    srawi	$5,$5,23	;; $5 <- $5 >> 23 (algebraic for sign extension)
+    or		$3,$3,$5	;; $3 <- $3 | $5
+    lis		$5,0xFF		;; $5 <- 0x00FF00FF
+    addi	$5,$5,0xFF
+    and		$4,$4,$5	;; $4 <- $4 & $5
+    and		$6,$2,$5	;; $6 <- $2 & $5
+    add		$4,$4,$6	;; $4 <- $4 + $6
+    rlwinm	$6,$4,7,0,0	;; $6 <- 0 | ($4[7] << 7)
+    srawi	$6,$6,15	;; $6 <- $6 >> 15 (algebraic for sign extension)
+    rlwinm	$5,$4,23,0,0	;; $5 <- 0 | ($4[23] << 23)
+    srawi	$5,$5,31	;; $5 <- $5 >> 31 (algebraic for sign extension)
+    rlwimi	$6,$5,0,24,31	;; $6[24..31] <- $5[24..31]
+    or		$4,$4,$6	;; $4 <- $4 | $6
+    rlwimi	$4,$3,0,16,23	;; $4[16..23] <- $3[16..23]
+    stw		$4,0($1)	;; *$1 <- $4
+.endmacro
+
+.macro	DRAWMETHOD_HALF_MACRO
+    lwz		$4,0($0)	;; $4 <- *$0
+    andi.	$3,$4,0xFF00	;; $3 <- $4 & 0x0000FF00
+    andi.	$5,$2,0xFF00	;; $5 <- $2 & 0x0000FF00
+    add		$3,$3,$5	;; $3 <- $3 + $5
+    lis		$5,0xFF		;; $5 <- 0x00FF00FF
+    addi	$5,$5,0xFF
+    and		$4,$4,$5	;; $4 <- $4 & $5
+    and		$5,$2,$5	;; $5 <- $2 & $5
+    add		$4,$4,$5	;; $4 <- $4 + $5
+    srwi	$4,$4,1		;; $4 <- $4 >> 1
+    rlwimi	$4,$3,31,16,23	;; $4[16..23] <- $3[15..22]
+    stw		$4,0($1)	;; *$1 <- $4
+.endmacro
+
+.macro DRAWMETHOD_DFLT_MACRO
+    DRAWMETHOD_PLUS_MACRO
+.endmacro
+
+; --------------------------------------------------------------------------------------
+
+
+
+; **************************************************************************************
+; void DRAWMETHOD_PLUS_PPC(unsigned int * buf, unsigned int _col);
+; void DRAWMETHOD_PLUS_2_PPC(unsigned * in, unsigned int * out, unsigned int _col);
+; **************************************************************************************
+.globl _DRAWMETHOD_PLUS_2_PPC
+.align 3
+_DRAWMETHOD_PLUS_2_PPC:
+    DRAWMETHOD_PLUS_MACRO	r3,r4,r5,r6,r7,r8,r9
+    blr				;; return
+
+.globl _DRAWMETHOD_PLUS_PPC
+.align 3
+_DRAWMETHOD_PLUS_PPC:
+    DRAWMETHOD_PLUS_MACRO	r3,r3,r4,r5,r6,r7,r9
+    blr				;; return
+
+
+; **************************************************************************************
+; void DRAWMETHOD_HALF_PPC(unsigned int * buf, unsigned int _col);
+; void DRAWMETHOD_HALF_2_PPC(unsigned * in, unsigned int * out, unsigned int _col);
+; **************************************************************************************
+.globl _DRAWMETHOD_HALF_2_PPC
+.align 3
+_DRAWMETHOD_HALF_2_PPC:
+    DRAWMETHOD_HALF_MACRO	r3,r4,r5,r6,r7,r8
+    blr				;; return
+
+.globl _DRAWMETHOD_HALF_PPC
+.align 3
+_DRAWMETHOD_HALF_PPC:
+    DRAWMETHOD_HALF_MACRO	r3,r3,r4,r5,r6,r7
+    blr				;; return
+
+
+; **************************************************************************************
+; void DRAW_LINE_PPC(unsigned int *data, int x1, int y1, int x2, int y2, unsigned int col,
+; 			unsigned int screenx, unsigned int screeny)
+; **************************************************************************************
+.globl _DRAW_LINE_PPC
+.align 3
+_DRAW_LINE_PPC:
+    ;; NOT IMPLEMENTED YET
+    blr				;; return
+
+
+; **************************************************************************************
+; void _ppc_brightness(Pixel * src, Pixel * dest, unsigned int size, unsigned int coeff)
+; **************************************************************************************
+
+
+.const
+.align 4
+vectorZERO:
+    .long 0,0,0,0
+    .long 0x10101000, 0x10101001, 0x10101002, 0x10101003
+    .long 0x10101004, 0x10101005, 0x10101006, 0x10101007
+    .long 0x10101008, 0x10101009, 0x1010100A, 0x1010100B
+    .long 0x1010100C, 0x1010100D, 0x1010100E, 0x1010100F
+
+
+.section __TEXT,__text,regular,pure_instructions
+
+.globl _ppc_brightness_G4
+.align 3
+_ppc_brightness_G4:
+
+
+;; PowerPC Altivec code
+    srwi    r5,r5,2
+    mtctr   r5
+
+;;vrsave
+    mfspr   r11,256
+    lis     r12,0xCFFC
+    mtspr   256,r12
+
+        mflr r0
+        bcl 20,31,"L00000000001$pb"
+"L00000000001$pb":
+        mflr r10
+        mtlr r0
+
+    addis   r9,r10,ha16(vectorZERO-"L00000000001$pb")
+    addi    r9,r9,lo16(vectorZERO-"L00000000001$pb")
+    
+    vxor    v0,v0,v0 ;; V0 = NULL vector
+
+    addi    r9,r9,16
+    lvx     v10,0,r9
+    addi    r9,r9,16
+    lvx     v11,0,r9
+    addi    r9,r9,16
+    lvx     v12,0,r9
+    addi    r9,r9,16
+    lvx     v13,0,r9
+
+    addis   r9,r10,ha16(vectortmpwork-"L00000000001$pb")
+    addi    r9,r9,lo16(vectortmpwork-"L00000000001$pb")
+    stw     r6,0(r9)
+    li      r6,8
+    stw     r6,4(r9)
+    lvx     v9,0,r9
+    li      r9,128
+    vspltw  v8,v9,0
+    vspltw  v9,v9,1
+
+;; elt counter
+    li      r9,0
+    lis     r7,0x0F01
+    b L7
+.align 4
+L7:
+    lvx     v1,r9,r3
+
+    vperm   v4,v1,v0,v10
+    ;*********************
+     add r10,r9,r3
+    ;*********************
+    vperm   v5,v1,v0,v11
+    vperm   v6,v1,v0,v12
+    vperm   v7,v1,v0,v13
+
+    vmulouh  v4,v4,v8
+    ;*********************
+     dst     r10,r7,3
+    ;*********************
+    vmulouh  v5,v5,v8
+    vmulouh  v6,v6,v8
+    vmulouh  v7,v7,v8
+    vsrw     v4,v4,v9
+    vsrw     v5,v5,v9
+    vsrw     v6,v6,v9
+    vsrw     v7,v7,v9 
+    
+    vpkuwus v4,v4,v5
+    vpkuwus v6,v6,v7
+    vpkuhus v1,v4,v6
+
+    stvx    v1,r9,r4
+    addi    r9,r9,16
+
+    bdnz L7
+
+    mtspr   256,r11
+    blr
+
+
+.globl _ppc_brightness_G5
+.align 3
+_ppc_brightness_G5:
+
+;; PowerPC Altivec G5 code
+    srwi    r5,r5,2
+    mtctr   r5
+
+;;vrsave
+    mfspr   r11,256
+    lis     r12,0xCFFC
+    mtspr   256,r12
+
+        mflr r0
+        bcl 20,31,"L00000000002$pb"
+"L00000000002$pb":
+        mflr r10
+        mtlr r0
+
+    addis   r9,r10,ha16(vectorZERO-"L00000000002$pb")
+    addi    r9,r9,lo16(vectorZERO-"L00000000002$pb")
+    
+    vxor    v0,v0,v0 ;; V0 = NULL vector
+
+    addi    r9,r9,16
+    lvx     v10,0,r9
+    addi    r9,r9,16
+    lvx     v11,0,r9
+    addi    r9,r9,16
+    lvx     v12,0,r9
+    addi    r9,r9,16
+    lvx     v13,0,r9
+
+    addis   r9,r10,ha16(vectortmpwork-"L00000000002$pb")
+    addi    r9,r9,lo16(vectortmpwork-"L00000000002$pb")
+    stw     r6,0(r9)
+    li      r6,8
+    stw     r6,4(r9)
+    lvx     v9,0,r9
+    li      r9,128
+    vspltw  v8,v9,0
+    vspltw  v9,v9,1
+
+;; elt counter
+    li      r9,0
+    lis     r7,0x0F01
+    b L6
+.align 4
+L6:
+    lvx     v1,r9,r3
+
+    vperm   v4,v1,v0,v10
+    ;*********************
+    add r10,r9,r3
+    ;*********************
+    vperm   v5,v1,v0,v11
+    vperm   v6,v1,v0,v12
+    vperm   v7,v1,v0,v13
+
+    vmulouh  v4,v4,v8
+    vmulouh  v5,v5,v8
+    vmulouh  v6,v6,v8
+    vmulouh  v7,v7,v8
+    vsrw     v4,v4,v9
+    vsrw     v5,v5,v9
+    vsrw     v6,v6,v9
+    vsrw     v7,v7,v9 
+    
+    vpkuwus v4,v4,v5
+    vpkuwus v6,v6,v7
+    vpkuhus v1,v4,v6
+
+    stvx    v1,r9,r4
+    addi    r9,r9,16
+
+    bdnz L6
+
+    mtspr   256,r11
+    blr
+
+
+.globl _ppc_brightness_generic
+.align 3
+_ppc_brightness_generic:
+    lis   r12,0x00FF
+    ori   r12,r12,0x00FF
+    subi  r3,r3,4
+    subi  r4,r4,4
+    mtctr r5
+    b L1
+.align 4
+L1:
+    lwzu  r7,4(r3)
+
+    rlwinm  r8,r7,16,24,31
+    rlwinm  r9,r7,24,24,31
+    mullw   r8,r8,r6
+    rlwinm  r10,r7,0,24,31
+    mullw   r9,r9,r6
+    srwi    r8,r8,8
+    mullw   r10,r10,r6
+    srwi    r9,r9,8
+
+    rlwinm. r11,r8,0,0,23
+    beq     L2
+    li      r8,0xFF
+L2:
+    srwi    r10,r10,8
+    rlwinm. r11,r9,0,0,23
+    beq     L3
+    li      r9,0xFF
+L3:
+    rlwinm  r7,r8,16,8,15
+    rlwinm. r11,r10,0,0,23
+    beq     L4
+    li      r10,0xFF
+L4:
+    rlwimi  r7,r9,8,16,23
+    rlwimi  r7,r10,0,24,31
+
+    stwu    r7,4(r4)
+    bdnz L1
+
+    blr
+
+
+
+.static_data
+.align 4
+vectortmpwork:
+    .long 0,0,0,0
+
diff --git a/gst/goom/ppc_zoom_ultimate.h b/gst/goom/ppc_zoom_ultimate.h
new file mode 100644
index 0000000..cd2c8a2
--- /dev/null
+++ b/gst/goom/ppc_zoom_ultimate.h
@@ -0,0 +1,25 @@
+/* Goom Project
+ * Copyright (C) <2003> Guillaume Borios, iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* Generic PowerPC Code */
+void ppc_zoom_generic (int sizeX, int sizeY, Pixel *src, Pixel *dest, int *brutS, int *brutD, int buffratio, int precalCoef[16][16]);
+
+/* G4 Specific PowerPC Code (Possible use of Altivec and Data Streams) */
+void ppc_zoom_G4 (int sizeX, int sizeY, Pixel *src, Pixel *dest, int *brutS, int *brutD, int buffratio, int precalCoef[16][16]);
+
diff --git a/gst/goom/ppc_zoom_ultimate.s b/gst/goom/ppc_zoom_ultimate.s
new file mode 100644
index 0000000..c37ec50
--- /dev/null
+++ b/gst/goom/ppc_zoom_ultimate.s
@@ -0,0 +1,336 @@
+; PowerPC optimized zoom for Goom
+; © 2001-2003 Guillaume Borios
+; 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., 51 Franklin St, Fifth Floor,
+; Boston, MA 02110-1301, USA.
+
+; Change log :
+; 21 Dec 2003 : Use of altivec is now determined with a parameter
+
+; Section definition : We use a read only section
+.text
+
+; name of the function to call by C program : ppc_zoom
+; We declare this label as a global to extend its scope outside this file
+.globl _ppc_zoom_generic
+.globl _ppc_zoom_G4
+
+; Description :
+; This routine dynamically computes and applies a zoom filter
+
+; parameters :
+; r3  <=> unsigned int sizeX (in pixels)
+; r4  <=> unsigned int sizeY (in pixels)
+; r5  <=> unsigned int * frompixmap
+; r6  <=> unsigned int * topixmap
+; r7  <=> unsigned int * brutS
+; r8  <=> unsigned int * brutD
+; r9  <=> unsigned int buffratio
+; r10 <=> int [16][16] precalccoeffs
+
+; globals after init
+; r5  <=> frompixmap - 1 byte needed for preincremental fetch (replaces r5)
+; r6  <=> topixmap - 1 byte needed for preincremental fetch (replaces r6)
+; r3 <=> ax = x max in 16th of pixels (replaces old r3)
+; r4 <=> ay = y max in 16th of pixels (replaces old r4)
+; r20 <=> row size in bytes
+; r12 <=> 0xFF00FF (mask for parallel 32 bits pixs computing)
+; r30 <=> brutS - 1 byte needed for preincremental fetch (replaces r7)
+; r31 <=> brutD - 1 byte needed for preincremental fetch (replaces r8)
+
+; ABI notes :
+; r1 is the Stack Pointer (SP) => Do not use
+; r13..r31 are non-volatiles => Do not use
+
+_ppc_zoom_generic:
+
+; Saves the used non volatile registers in the Mach-O stack s Red-Zone
+stmw 	r18,-56(r1)
+
+; init
+li      r18,0		; Default value if out of range : 0 (Black)
+mr      r11,r10
+lis     r12,0xFF
+mullw   r2,r3,r4	; Number of pixels to compute
+subi    r30,r8,0
+slwi	r20,r3,2
+srawi   r19,r20,2
+ori     r12,r12,0xFF
+subi    r3,r3,1
+subi    r4,r4,1
+mtspr	ctr,r2		; Init the loop count (one loop per pixel computed)
+subi    r31,r7,0
+subi    r6,r6,4
+slwi	r3,r3,4
+slwi	r4,r4,4
+
+;pre init for loop
+lwz	r2,0(r31)    ; px
+lwz	r29,4(r31)   ; py
+lwz	r8,0(r30)    ; px2
+lwz	r10,4(r30)   ; py2
+
+b       L1
+.align  5
+L1:
+
+; computes dynamically the position to fetch
+sub     r8,r8,r2
+sub     r10,r10,r29
+mullw   r8,r8,r9
+addi    r31,r31,8
+mullw   r10,r10,r9
+addi    r30,r30,8
+
+srawi   r8,r8,16
+srawi   r10,r10,16
+add     r2,r2,r8
+add     r29,r29,r10
+
+; if px>ax or py>ay goto outofrange
+; computes the attenuation coeffs and the original point address
+rlwinm  r10,r2,6,28-6,31-6 ; r10 <- (r2 << 2) & 0x000002D0   (r10=(r2%16)*4*16)
+cmpl    cr4,0,r2,r3
+rlwimi  r10, r29, 2, 28-2, 31-2 ; r10 <- ((r29 << 2) & 0x0000002D) | (r10 & !0x0000002D)      (r10=(r10%16)*4 | r10)
+cmpl    cr7,0,r29,r4
+srawi   r29,r29,4     ; pos computing
+bge-	cr4,L4
+srawi   r2,r2,4       ; pos computing
+mullw   r29, r29,r19  ; pos computing
+bge-	cr7,L4
+
+; Channels notation : 00112233 (AARRVVBB)
+
+add     r2,r2,r29    		; pos computing
+lwzx    r10,r11,r10		; Loads coefs
+slwi    r2,r2,2      		; pos computing
+add	r2,r2,r5     		; pos computing
+rlwinm  r21,r10,0,24,31	        ; Isolates coef1 (??????11 -> 00000011)
+lwz	r25,0(r2)		; Loads col1 -> r25
+lwz	r26,4(r2)		; Loads col2 -> r26
+rlwinm  r22,r10,24,24,31	; Isolates coef2 (????22?? -> 00000022)
+rlwinm  r23,r10,16,24,31	; Isolates coef3 (??33???? -> 00000033)
+add	r2,r2,r20		; Adds one line for future load of col3 and col4
+and	r8, r25,r12		; Masks col1 channels 1 & 3 : 0x00XX00XX
+rlwinm  r24,r10,8,24,31		; Isolates coef4 (44?????? -> 00000044)
+andi.	r25,r25,0xFF00		; Masks col1 channel 2 : 0x0000XX00
+mullw	r8, r8, r21		; Applies coef1 on col1 channels 1 & 3
+
+
+; computes final pixel color
+and	r10,r26,r12		; Masks col2 channels 1 & 3 : 0x00XX00XX
+lwz	r27,0(r2)		; Loads col3 -> r27
+mullw	r10,r10,r22		; Applies coef2 on col2 channels 1 & 3
+mullw	r25,r25,r21		; Applies coef1 on col1 channel 2
+andi.	r29,r26,0xFF00		; Masks col2 channel 2 : 0x0000XX00
+mullw	r29,r29,r22		; Applies coef2 on col2 channel 2
+lwz	r28,4(r2)		; Loads col4 -> r28
+add	r8 ,r8 ,r10		; Adds col1 & col2 channels 1 & 3
+and	r10,r27,r12		; Masks col3 channels 1 & 3 : 0x00XX00XX
+add	r25,r25,r29		; Adds col1 & col2 channel 2
+mullw	r10,r10,r23		; Applies coef3 on col3 channels 1 & 3
+andi.	r29,r27,0xFF00		; Masks col3 channel 2 : 0x0000XX00
+mullw	r29,r29,r23		; Applies coef3 on col3 channel 2
+lwz	r2,0(r31)		; px
+add	r7 ,r8 ,r10		; Adds col3 to (col1 + col2) channels 1 & 3
+and	r10,r28,r12		; Masks col4 channels 1 & 3 : 0x00XX00XX
+mullw	r10,r10,r24		; Applies coef4 on col4 channels 1 & 3
+add	r25,r25,r29		; Adds col 3 to (col1 + col2) channel 2
+lwz 	r8,0(r30)    		; px2
+andi.	r28,r28,0xFF00		; Masks col4 channel 2 : 0x0000XX00
+add	r7 ,r7 ,r10		; Adds col4 to (col1 + col2 + col3) channels 1 & 3
+lwz	r10,4(r30)   		; py2
+mullw	r28,r28,r24		; Applies coef4 on col4 channel 2
+srawi	r7, r7, 8		; (sum of channels 1 & 3) >> 8
+lwz	r29,4(r31)              ; py
+add	r25,r25,r28		; Adds col 4 to (col1 + col2 + col3) channel 2
+rlwimi  r7, r25, 24, 16, 23	; (((sum of channels 2) >> 8 ) & 0x0000FF00) | ((sum of channels 1 and 3) & 0xFFFF00FF)
+stwu	r7,4(r6)		; Stores the computed pixel
+bdnz	L1			; Iterate again if needed
+b       L3	;goto end	; If not, returns from the function
+
+
+; if out of range
+L4:
+stwu	r18,4(r6)
+lwz	r8,0(r30)    ; px2
+lwz	r10,4(r30)   ; py2
+lwz	r2,0(r31)    ; px
+lwz	r29,4(r31)   ; py
+bdnz	L1
+
+
+L3:
+
+; Restore saved registers and return
+lmw	r18,-56(r1)
+blr
+
+
+
+
+
+
+
+
+_ppc_zoom_G4:
+
+; Saves the used non volatile registers in the Mach-O stack s Red-Zone
+stmw 	r17,-60(r1)
+
+; init
+li      r18,0		; Default value if out of range : 0 (Black)
+mr      r11,r10
+lis     r12,0xFF
+mullw   r2,r3,r4	; Number of pixels to compute
+subi    r30,r8,0
+slwi	r20,r3,2
+srawi   r19,r20,2
+ori     r12,r12,0xFF
+subi    r3,r3,1
+subi    r4,r4,1
+mtspr	ctr,r2		; Init the loop count (one loop per pixel computed)
+subi    r31,r7,0
+subi    r6,r6,4
+slwi	r3,r3,4
+slwi	r4,r4,4
+
+;pre init for loop
+lwz	r2,0(r31)    ; px
+lwz	r29,4(r31)   ; py
+lwz	r8,0(r30)    ; px2
+lwz	r10,4(r30)   ; py2
+
+;*********************
+lis     r17,0x0F01
+
+b       L100
+.align  5
+L100:
+
+addi    r6,r6,4
+
+; Optimization to ensure the destination buffer
+; won't be loaded into the data cache
+rlwinm. r0,r6,0,27,31
+bne+    L500
+dcbz    0,r6
+;dcba    0,r6
+L500:
+
+; computes dynamically the position to fetch
+;mullw   r8,r8,r29
+;mullw   r2,r2,r29
+;add     r2,r8,r2
+;srawi   r2,r2,17
+
+sub     r8,r8,r2
+sub     r10,r10,r29
+mullw   r8,r8,r9
+addi    r31,r31,8
+mullw   r10,r10,r9
+addi    r30,r30,8
+
+dst     r30,r17,0
+
+srawi    r8,r8,16
+srawi    r10,r10,16
+add     r2,r2,r8
+add     r29,r29,r10
+
+dst     r31,r17,1
+
+; if px>ax or py>ay goto outofrange
+; computes the attenuation coeffs and the original point address
+rlwinm  r10,r2,6,28-6,31-6 ; r10 <- (r2 << 2) & 0x000002D0   (r10=(r2%16)*4*16)
+cmpl    cr4,0,r2,r3
+rlwimi  r10, r29, 2, 28-2, 31-2 ; r10 <- ((r29 << 2) & 0x0000002D) | (r10 & !0x0000002D)      (r10=(r29%16)*4 | r10)
+cmpl    cr7,0,r29,r4
+srawi   r29,r29,4     ; pos computing
+bge-	cr4,L400
+srawi   r2,r2,4       ; pos computing
+mullw   r29, r29,r19  ; pos computing
+bge-	cr7,L400
+
+; Channels notation : 00112233 (AARRVVBB)
+
+add     r2,r2,r29    		; pos computing
+lwzx    r10,r11,r10		; Loads coefs
+slwi    r2,r2,2      		; pos computing
+add	r2,r2,r5     		; pos computing
+rlwinm  r21,r10,0,24,31	        ; Isolates coef1 (??????11 -> 00000011)
+lwz	r25,0(r2)		; Loads col1 -> r25
+lwz	r26,4(r2)		; Loads col2 -> r26
+rlwinm  r22,r10,24,24,31	; Isolates coef2 (????22?? -> 00000022)
+rlwinm  r23,r10,16,24,31	; Isolates coef3 (??33???? -> 00000033)
+add	r2,r2,r20		; Adds one line for future load of col3 and col4
+and	r8, r25,r12		; Masks col1 channels 1 & 3 : 0x00XX00XX
+rlwinm  r24,r10,8,24,31		; Isolates coef4 (44?????? -> 00000044)
+dst     r2,r17,2
+rlwinm  r25,r25,0,16,23		; Masks col1 channel 2 : 0x0000XX00
+;andi.	r25,r25,0xFF00		; Masks col1 channel 2 : 0x0000XX00
+mullw	r8, r8, r21		; Applies coef1 on col1 channels 1 & 3
+
+
+; computes final pixel color
+and	r10,r26,r12		; Masks col2 channels 1 & 3 : 0x00XX00XX
+lwz	r27,0(r2)		; Loads col3 -> r27
+mullw	r10,r10,r22		; Applies coef2 on col2 channels 1 & 3
+mullw	r25,r25,r21		; Applies coef1 on col1 channel 2
+rlwinm  r29,r26,0,16,23		; Masks col2 channel 2 : 0x0000XX00
+;andi.	r29,r26,0xFF00		; Masks col2 channel 2 : 0x0000XX00
+mullw	r29,r29,r22		; Applies coef2 on col2 channel 2
+lwz	r28,4(r2)		; Loads col4 -> r28
+add	r8 ,r8 ,r10		; Adds col1 & col2 channels 1 & 3
+and	r10,r27,r12		; Masks col3 channels 1 & 3 : 0x00XX00XX
+add	r25,r25,r29		; Adds col1 & col2 channel 2
+mullw	r10,r10,r23		; Applies coef3 on col3 channels 1 & 3
+rlwinm  r29,r27,0,16,23		; Masks col3 channel 2 : 0x0000XX00
+;andi.	r29,r27,0xFF00		; Masks col3 channel 2 : 0x0000XX00
+mullw	r29,r29,r23		; Applies coef3 on col3 channel 2
+lwz	r2,0(r31)		; px
+add	r7 ,r8 ,r10		; Adds col3 to (col1 + col2) channels 1 & 3
+and	r10,r28,r12		; Masks col4 channels 1 & 3 : 0x00XX00XX
+mullw	r10,r10,r24		; Applies coef4 on col4 channels 1 & 3
+add	r25,r25,r29		; Adds col 3 to (col1 + col2) channel 2
+lwz 	r8,0(r30)    		; px2
+rlwinm  r28,r28,0,16,23		; Masks col4 channel 2 : 0x0000XX00
+;andi.	r28,r28,0xFF00		; Masks col4 channel 2 : 0x0000XX00
+add	r7 ,r7 ,r10		; Adds col4 to (col1 + col2 + col3) channels 1 & 3
+lwz	r10,4(r30)   		; py2
+mullw	r28,r28,r24		; Applies coef4 on col4 channel 2
+srawi	r7, r7, 8		; (sum of channels 1 & 3) >> 8
+lwz	r29,4(r31)              ; py
+add	r25,r25,r28		; Adds col 4 to (col1 + col2 + col3) channel 2
+rlwimi  r7, r25, 24, 16, 23	; (((sum of channels 2) >> 8 ) & 0x0000FF00) | ((sum of channels 1 and 3) & 0xFFFF00FF)
+stw	r7,0(r6)		; Stores the computed pixel
+bdnz	L100			; Iterate again if needed
+b       L300	;goto end	; If not, returns from the function
+
+
+; if out of range
+L400:
+stw	r18,0(r6)
+lwz	r8,0(r30)    ; px2
+lwz	r10,4(r30)   ; py2
+lwz	r2,0(r31)    ; px
+lwz	r29,4(r31)   ; py
+bdnz	L100
+
+
+L300:
+
+; Restore saved registers and return
+lmw	r17,-60(r1)
+blr
diff --git a/gst/goom/sound_tester.c b/gst/goom/sound_tester.c
new file mode 100644
index 0000000..d02f0b5
--- /dev/null
+++ b/gst/goom/sound_tester.c
@@ -0,0 +1,161 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "sound_tester.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* some constants */
+#define BIG_GOOM_DURATION 100
+#define BIG_GOOM_SPEED_LIMIT 0.1f
+
+#define ACCEL_MULT 0.95f
+#define SPEED_MULT 0.99f
+
+
+void
+evaluate_sound (gint16 data[2][512], SoundInfo * info)
+{
+
+  int i;
+  float difaccel;
+  float prevspeed;
+
+  /* find the max */
+  int incvar = 0;
+
+  for (i = 0; i < 512; i += 2) {
+    if (incvar < data[0][i])
+      incvar = data[0][i];
+  }
+
+  if (incvar > info->allTimesMax)
+    info->allTimesMax = incvar;
+
+  /* volume sonore */
+  info->volume = (float) incvar / (float) info->allTimesMax;
+  memcpy (info->samples[0], data[0], 512 * sizeof (short));
+  memcpy (info->samples[1], data[1], 512 * sizeof (short));
+
+  difaccel = info->accelvar;
+  info->accelvar = info->volume;        /* accel entre 0 et 1 */
+
+  /* transformations sur la vitesse du son */
+  if (info->speedvar > 1.0f)
+    info->speedvar = 1.0f;
+
+  if (info->speedvar < 0.1f)
+    info->accelvar *= (1.0f - (float) info->speedvar);
+  else if (info->speedvar < 0.3f)
+    info->accelvar *= (0.9f - (float) (info->speedvar - 0.1f) / 2.0f);
+  else
+    info->accelvar *= (0.8f - (float) (info->speedvar - 0.3f) / 4.0f);
+
+  /* adoucissement de l'acceleration */
+  info->accelvar *= ACCEL_MULT;
+  if (info->accelvar < 0)
+    info->accelvar = 0;
+
+  difaccel = info->accelvar - difaccel;
+  if (difaccel < 0)
+    difaccel = -difaccel;
+
+  /* mise a jour de la vitesse */
+  prevspeed = info->speedvar;
+  info->speedvar = (info->speedvar + difaccel * 0.5f) / 2;
+  info->speedvar *= SPEED_MULT;
+  info->speedvar = (info->speedvar + 3.0f * prevspeed) / 4.0f;
+  if (info->speedvar < 0)
+    info->speedvar = 0;
+  if (info->speedvar > 1)
+    info->speedvar = 1;
+
+  /* temps du goom */
+  info->timeSinceLastGoom++;
+  info->timeSinceLastBigGoom++;
+  info->cycle++;
+
+  /* detection des nouveaux gooms */
+  if ((info->speedvar > (float) IVAL (info->biggoom_speed_limit_p) / 100.0f)
+      && (info->accelvar > info->bigGoomLimit)
+      && (info->timeSinceLastBigGoom > BIG_GOOM_DURATION)) {
+    info->timeSinceLastBigGoom = 0;
+  }
+
+  if (info->accelvar > info->goom_limit) {
+    /* TODO: tester && (info->timeSinceLastGoom > 20)) { */
+    info->totalgoom++;
+    info->timeSinceLastGoom = 0;
+    info->goomPower = info->accelvar - info->goom_limit;
+  }
+
+  if (info->accelvar > info->prov_max)
+    info->prov_max = info->accelvar;
+
+  if (info->goom_limit > 1)
+    info->goom_limit = 1;
+
+  /* toute les 2 secondes : v�rifier si le taux de goom est correct
+   * et le modifier sinon.. */
+  if (info->cycle % 64 == 0) {
+    if (info->speedvar < 0.01f)
+      info->goom_limit *= 0.91;
+    if (info->totalgoom > 4) {
+      info->goom_limit += 0.02;
+    }
+    if (info->totalgoom > 7) {
+      info->goom_limit *= 1.03f;
+      info->goom_limit += 0.03;
+    }
+    if (info->totalgoom > 16) {
+      info->goom_limit *= 1.05f;
+      info->goom_limit += 0.04;
+    }
+    if (info->totalgoom == 0) {
+      info->goom_limit = info->prov_max - 0.02;
+    }
+    if ((info->totalgoom == 1) && (info->goom_limit > 0.02))
+      info->goom_limit -= 0.01;
+    info->totalgoom = 0;
+    info->bigGoomLimit =
+        info->goom_limit * (1.0f +
+        (float) IVAL (info->biggoom_factor_p) / 500.0f);
+    info->prov_max = 0;
+  }
+
+  /* mise a jour des parametres pour la GUI */
+  FVAL (info->volume_p) = info->volume;
+  info->volume_p.change_listener (&info->volume_p);
+  FVAL (info->speed_p) = info->speedvar * 4;
+  info->speed_p.change_listener (&info->speed_p);
+  FVAL (info->accel_p) = info->accelvar;
+  info->accel_p.change_listener (&info->accel_p);
+
+  FVAL (info->goom_limit_p) = info->goom_limit;
+  info->goom_limit_p.change_listener (&info->goom_limit_p);
+  FVAL (info->goom_power_p) = info->goomPower;
+  info->goom_power_p.change_listener (&info->goom_power_p);
+  FVAL (info->last_goom_p) = 1.0 - ((float) info->timeSinceLastGoom / 20.0f);
+  info->last_goom_p.change_listener (&info->last_goom_p);
+  FVAL (info->last_biggoom_p) =
+      1.0 - ((float) info->timeSinceLastBigGoom / 40.0f);
+  info->last_biggoom_p.change_listener (&info->last_biggoom_p);
+
+  /* bigGoomLimit ==goomLimit*9/8+7 ? */
+}
diff --git a/gst/goom/sound_tester.h b/gst/goom/sound_tester.h
new file mode 100644
index 0000000..2651d5f
--- /dev/null
+++ b/gst/goom/sound_tester.h
@@ -0,0 +1,29 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _SOUND_TESTER_H
+#define _SOUND_TESTER_H
+
+#include "goom_plugin_info.h"
+#include "goom_config.h"
+
+/** change les donnees du SoundInfo */
+void evaluate_sound(gint16 data[2][512], SoundInfo *sndInfo);
+
+#endif
+
diff --git a/gst/goom/surf3d.c b/gst/goom/surf3d.c
new file mode 100644
index 0000000..847284b
--- /dev/null
+++ b/gst/goom/surf3d.c
@@ -0,0 +1,152 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "surf3d.h"
+#include "goom_plugin_info.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+grid3d *
+grid3d_new (int sizex, int defx, int sizez, int defz, v3d center)
+{
+  int x = defx;
+  int y = defz;
+  grid3d *g = malloc (sizeof (grid3d));
+  surf3d *s = &(g->surf);
+
+  s->nbvertex = x * y;
+  s->vertex = malloc (x * y * sizeof (v3d));
+  s->svertex = malloc (x * y * sizeof (v3d));
+  s->center = center;
+
+  g->defx = defx;
+  g->sizex = sizex;
+  g->defz = defz;
+  g->sizez = sizez;
+  g->mode = 0;
+
+  while (y) {
+    --y;
+    x = defx;
+    while (x) {
+      --x;
+      s->vertex[x + defx * y].x = (float) (x - defx / 2) * sizex / defx;
+      s->vertex[x + defx * y].y = 0;
+      s->vertex[x + defx * y].z = (float) (y - defz / 2) * sizez / defz;
+    }
+  }
+  return g;
+}
+
+void
+grid3d_free (grid3d * g)
+{
+  surf3d *s = &(g->surf);
+
+  free (s->vertex);
+  free (s->svertex);
+
+  free (g);
+}
+
+void
+grid3d_draw (PluginInfo * plug, grid3d * g, int color, int colorlow,
+    int dist, Pixel * buf, Pixel * back, int W, int H)
+{
+
+  int x;
+  v2d v2, v2x;
+
+  v2d *v2_array = malloc (g->surf.nbvertex * sizeof (v2d));
+
+  v3d_to_v2d (g->surf.svertex, g->surf.nbvertex, W, H, dist, v2_array);
+
+  for (x = 0; x < g->defx; x++) {
+    int z;
+
+    v2x = v2_array[x];
+
+    for (z = 1; z < g->defz; z++) {
+      v2 = v2_array[z * g->defx + x];
+      if (((v2.x != -666) || (v2.y != -666))
+          && ((v2x.x != -666) || (v2x.y != -666))) {
+        plug->methods.draw_line (buf, v2x.x, v2x.y, v2.x, v2.y, colorlow, W, H);
+        plug->methods.draw_line (back, v2x.x, v2x.y, v2.x, v2.y, color, W, H);
+      }
+      v2x = v2;
+    }
+  }
+
+  free (v2_array);
+}
+
+void
+surf3d_rotate (surf3d * s, float angle)
+{
+  int i;
+  float cosa;
+  float sina;
+
+  SINCOS (angle, sina, cosa);
+  for (i = 0; i < s->nbvertex; i++) {
+    Y_ROTATE_V3D (s->vertex[i], s->svertex[i], cosa, sina);
+  }
+}
+
+void
+surf3d_translate (surf3d * s)
+{
+  int i;
+
+  for (i = 0; i < s->nbvertex; i++) {
+    TRANSLATE_V3D (s->center, s->svertex[i]);
+  }
+}
+
+void
+grid3d_update (grid3d * g, float angle, float *vals, float dist)
+{
+  int i;
+  float cosa;
+  float sina;
+  surf3d *s = &(g->surf);
+  v3d cam = s->center;
+
+  cam.z += dist;
+
+  SINCOS ((angle / 4.3f), sina, cosa);
+  cam.y += sina * 2.0f;
+  SINCOS (angle, sina, cosa);
+
+  if (g->mode == 0) {
+    if (vals)
+      for (i = 0; i < g->defx; i++)
+        s->vertex[i].y = s->vertex[i].y * 0.2 + vals[i] * 0.8;
+
+    for (i = g->defx; i < s->nbvertex; i++) {
+      s->vertex[i].y *= 0.255f;
+      s->vertex[i].y += (s->vertex[i - g->defx].y * 0.777f);
+    }
+  }
+
+  for (i = 0; i < s->nbvertex; i++) {
+    Y_ROTATE_V3D (s->vertex[i], s->svertex[i], cosa, sina);
+    TRANSLATE_V3D (cam, s->svertex[i]);
+  }
+}
diff --git a/gst/goom/surf3d.h b/gst/goom/surf3d.h
new file mode 100644
index 0000000..f8a2180
--- /dev/null
+++ b/gst/goom/surf3d.h
@@ -0,0 +1,57 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _SURF3D_H
+#define _SURF3D_H
+
+#include "v3d.h"
+#include "goom_graphic.h"
+#include "goom_typedefs.h"
+
+typedef struct {
+	v3d *vertex;
+	v3d *svertex;
+	int nbvertex;
+
+	v3d center;
+} surf3d;
+
+typedef struct {
+	surf3d surf;
+	
+	int defx;
+	int sizex;
+	int defz;
+	int sizez;
+	int mode;
+} grid3d;
+
+/* hi-level */
+
+/* works on grid3d */
+grid3d *grid3d_new (int sizex, int defx, int sizez, int defz, v3d center);
+void grid3d_free (grid3d *g);
+void grid3d_update (grid3d *s, float angle, float *vals, float dist);
+
+/* low level */
+void surf3d_draw (surf3d *s, int color, int dist, int *buf, int *back, int W,int H);
+void grid3d_draw (PluginInfo *plug, grid3d *g, int color, int colorlow, int dist, Pixel *buf, Pixel *back, int W,int H);
+void surf3d_rotate (surf3d *s, float angle);
+void surf3d_translate (surf3d *s);
+
+#endif
diff --git a/gst/goom/surf3d.s b/gst/goom/surf3d.s
new file mode 100644
index 0000000..f8c8c5d
--- /dev/null
+++ b/gst/goom/surf3d.s
@@ -0,0 +1,484 @@
+	.file	"surf3d.c"
+	.version	"01.01"
+gcc2_compiled.:
+.text
+	.align 4
+.globl grid3d_new
+	.type	 grid3d_new,@function
+grid3d_new:
+	pushl %ebp
+	movl %esp,%ebp
+	subl $44,%esp
+	pushl %edi
+	pushl %esi
+	pushl %ebx
+	movl 20(%ebp),%eax
+	movl 12(%ebp),%esi
+	movl %eax,-8(%ebp)
+	addl $-12,%esp
+	pushl $44
+	call malloc
+	movl %esi,%edx
+	imull -8(%ebp),%edx
+	movl %eax,%edi
+	movl %edx,-12(%ebp)
+	leal (%edx,%edx,2),%ebx
+	movl %edx,8(%edi)
+	addl $-12,%esp
+	sall $2,%ebx
+	pushl %ebx
+	call malloc
+	addl $32,%esp
+	movl %eax,(%edi)
+	addl $-12,%esp
+	pushl %ebx
+	call malloc
+	movl %eax,4(%edi)
+	movl 24(%ebp),%eax
+	movl %eax,12(%edi)
+	movl 28(%ebp),%eax
+	movl %eax,16(%edi)
+	movl 32(%ebp),%eax
+	movl %eax,20(%edi)
+	movl 8(%ebp),%eax
+	movl %eax,28(%edi)
+	movl %esi,24(%edi)
+	movl -8(%ebp),%edx
+	movl 16(%ebp),%eax
+	movl %edx,32(%edi)
+	movl %eax,36(%edi)
+	movl $0,40(%edi)
+	testl %edx,%edx
+	je .L480
+	movl %esi,%eax
+	movl %esi,-28(%ebp)
+	shrl $31,%eax
+	addl %eax,%esi
+	movl -8(%ebp),%eax
+	shrl $31,%eax
+	addl -8(%ebp),%eax
+	movl -12(%ebp),%edx
+	sarl $1,%eax
+	movl %edx,-24(%ebp)
+	negl -28(%ebp)
+	movl %esi,-16(%ebp)
+	movl %eax,-20(%ebp)
+	.p2align 4,,7
+.L481:
+	movl -28(%ebp),%eax
+	addl %eax,-24(%ebp)
+	decl -8(%ebp)
+	movl 12(%ebp),%esi
+	testl %esi,%esi
+	je .L479
+	movl -8(%ebp),%eax
+	subl -20(%ebp),%eax
+	movl %eax,-4(%ebp)
+	fildl -4(%ebp)
+	movl %esi,-4(%ebp)
+	movl -24(%ebp),%edx
+	leal (%edx,%esi),%eax
+	movl -16(%ebp),%ebx
+	fildl 16(%ebp)
+	leal (%eax,%eax,2),%eax
+	sarl $1,%ebx
+	leal 0(,%eax,4),%ecx
+	fmulp %st,%st(1)
+	fildl 20(%ebp)
+	fdivrp %st,%st(1)
+	fildl 8(%ebp)
+	fildl -4(%ebp)
+	jmp .L484
+.L487:
+	fxch %st(2)
+	.p2align 4,,7
+.L484:
+	decl %esi
+	movl %esi,%eax
+	movl (%edi),%edx
+	subl %ebx,%eax
+	movl %eax,-4(%ebp)
+	fildl -4(%ebp)
+	addl $-12,%ecx
+	fmul %st(2),%st
+	fdiv %st(1),%st
+	fstps (%edx,%ecx)
+	fxch %st(2)
+	movl (%edi),%eax
+	movl $0,4(%eax,%ecx)
+	movl (%edi),%eax
+	fsts 8(%eax,%ecx)
+	testl %esi,%esi
+	jne .L487
+	fstp %st(0)
+	fstp %st(0)
+	fstp %st(0)
+.L479:
+	cmpl $0,-8(%ebp)
+	jne .L481
+.L480:
+	leal -56(%ebp),%esp
+	popl %ebx
+	movl %edi,%eax
+	popl %esi
+	popl %edi
+	leave
+	ret
+.Lfe1:
+	.size	 grid3d_new,.Lfe1-grid3d_new
+.section	.rodata
+	.align 8
+.LC48:
+	.long 0x0,0x3fe00000
+	.align 4
+.LC49:
+	.long 0x3f19999a
+	.align 4
+.LC50:
+	.long 0x3ee3d70a
+.text
+	.align 4
+.globl grid3d_update
+	.type	 grid3d_update,@function
+grid3d_update:
+	pushl %ebp
+	movl %esp,%ebp
+	subl $32,%esp
+	pushl %esi
+	pushl %ebx
+	flds 12(%ebp)
+	movl 8(%ebp),%ebx
+	movl 16(%ebp),%ecx
+	fld %st(0)
+#APP
+	fsin
+#NO_APP
+	fstps -4(%ebp)
+	flds -4(%ebp)
+	fxch %st(1)
+#APP
+	fcos
+#NO_APP
+	fstps -4(%ebp)
+	flds -4(%ebp)
+	cmpl $0,40(%ebx)
+	jne .L519
+	testl %ecx,%ecx
+	je .L520
+	xorl %esi,%esi
+	cmpl 24(%ebx),%esi
+	jge .L520
+	fldl .LC48
+	xorl %edx,%edx
+	.p2align 4,,7
+.L524:
+	movl (%ebx),%eax
+	fld %st(0)
+	fld %st(1)
+	fxch %st(1)
+	fmuls 4(%eax,%edx)
+	fxch %st(1)
+	fmuls (%ecx,%esi,4)
+	faddp %st,%st(1)
+	incl %esi
+	fstps 4(%eax,%edx)
+	addl $12,%edx
+	cmpl 24(%ebx),%esi
+	jl .L524
+	fstp %st(0)
+.L520:
+	movl 24(%ebx),%esi
+	cmpl 8(%ebx),%esi
+	jge .L519
+	leal (%esi,%esi,2),%eax
+	flds .LC49
+	flds .LC50
+	leal 0(,%eax,4),%ecx
+	.p2align 4,,7
+.L529:
+	movl (%ebx),%eax
+	flds 4(%eax,%ecx)
+	fmul %st(2),%st
+	fstps 4(%eax,%ecx)
+	movl %esi,%eax
+	subl 24(%ebx),%eax
+	movl (%ebx),%edx
+	leal (%eax,%eax,2),%eax
+	flds 4(%edx,%eax,4)
+	fmul %st(1),%st
+	fadds 4(%edx,%ecx)
+	incl %esi
+	fstps 4(%edx,%ecx)
+	addl $12,%ecx
+	cmpl 8(%ebx),%esi
+	jl .L529
+	fstp %st(0)
+	fstp %st(0)
+.L519:
+	xorl %esi,%esi
+	cmpl 8(%ebx),%esi
+	jge .L536
+	xorl %ecx,%ecx
+	.p2align 4,,7
+.L534:
+	movl (%ebx),%eax
+	flds (%eax,%ecx)
+	flds 8(%eax,%ecx)
+	fmul %st(2),%st
+	fxch %st(1)
+	fmul %st(3),%st
+	fsubp %st,%st(1)
+	movl 4(%ebx),%edx
+	incl %esi
+	fstps (%edx,%ecx)
+	movl (%ebx),%eax
+	flds (%eax,%ecx)
+	flds 8(%eax,%ecx)
+	fxch %st(1)
+	fmul %st(2),%st
+	fxch %st(1)
+	fmul %st(3),%st
+	faddp %st,%st(1)
+	movl 4(%ebx),%edx
+	fstps 8(%edx,%ecx)
+	movl (%ebx),%eax
+	flds 4(%eax,%ecx)
+	movl 4(%ebx),%edx
+	fstps 4(%edx,%ecx)
+	movl 4(%ebx),%eax
+	flds (%eax,%ecx)
+	fadds 12(%ebx)
+	fstps (%eax,%ecx)
+	movl 4(%ebx),%eax
+	flds 4(%eax,%ecx)
+	fadds 16(%ebx)
+	fstps 4(%eax,%ecx)
+	movl 4(%ebx),%eax
+	flds 8(%eax,%ecx)
+	fadds 20(%ebx)
+	fstps 8(%eax,%ecx)
+	addl $12,%ecx
+	cmpl 8(%ebx),%esi
+	jl .L534
+.L536:
+	fstp %st(0)
+	fstp %st(0)
+	popl %ebx
+	popl %esi
+	leave
+	ret
+.Lfe2:
+	.size	 grid3d_update,.Lfe2-grid3d_update
+.section	.rodata
+	.align 4
+.LC51:
+	.long 0x40000000
+	.align 8
+.LC52:
+	.long 0x0,0x42380000
+.text
+	.align 4
+.globl surf3d_draw
+	.type	 surf3d_draw,@function
+surf3d_draw:
+	pushl %ebp
+	movl %esp,%ebp
+	subl $60,%esp
+	pushl %edi
+	pushl %esi
+	pushl %ebx
+	movl $0,-20(%ebp)
+	movl -20(%ebp),%edx
+	movl 8(%ebp),%eax
+	cmpl 8(%eax),%edx
+	jge .L493
+	fldl .LC52
+	flds .LC51
+	xorl %edi,%edi
+	.p2align 4,,7
+.L495:
+	movl 8(%ebp),%eax
+	movl 4(%eax),%eax
+	movl %eax,-36(%ebp)
+	fcoms 8(%eax,%edi)
+	fnstsw %ax
+	andb $69,%ah
+	cmpb $1,%ah
+	jne .L496
+	fildl 16(%ebp)
+	movl -36(%ebp),%edx
+	fld %st(0)
+	fmuls (%edx,%edi)
+	fdivs 8(%edx,%edi)
+	fld %st(3)
+	faddp %st,%st(1)
+	fstpl -32(%ebp)
+	movl -32(%ebp),%eax
+	movl -28(%ebp),%edx
+	movl %eax,-40(%ebp)
+	sarl $16,-40(%ebp)
+	movl -36(%ebp),%edx
+	fmuls 4(%edx,%edi)
+	fdivs 8(%edx,%edi)
+	movl -40(%ebp),%ecx
+	fld %st(2)
+	faddp %st,%st(1)
+	fstpl -32(%ebp)
+	movl -32(%ebp),%eax
+	movl -28(%ebp),%edx
+	movl %eax,-44(%ebp)
+	movl 28(%ebp),%eax
+	sarl $1,%eax
+	addl %eax,%ecx
+	movl 32(%ebp),%eax
+	sarl $16,-44(%ebp)
+	sarl $1,%eax
+	movl %ecx,%ebx
+	subl -44(%ebp),%eax
+	movl %eax,%esi
+	cmpl 28(%ebp),%ebx
+	jge .L496
+	testl %ecx,%ecx
+	jl .L496
+	cmpl 32(%ebp),%esi
+	jge .L496
+	testl %eax,%eax
+	jge .L499
+.L496:
+	xorl %esi,%esi
+	xorl %ebx,%ebx
+.L499:
+	movl 20(%ebp),%eax
+	movl %ebx,%edx
+	leal (%eax,%edx,4),%edx
+	movl 28(%ebp),%eax
+	imull %esi,%eax
+	leal (%edx,%eax,4),%eax
+	testl %ebx,%ebx
+	je .L494
+	testl %esi,%esi
+	je .L494
+#APP
+	movd (%eax), %mm0
+	paddusb 12(%ebp), %mm0
+	movd %mm0, (%eax)
+#NO_APP
+.L494:
+	incl -20(%ebp)
+	addl $12,%edi
+	movl -20(%ebp),%eax
+	movl 8(%ebp),%edx
+	cmpl 8(%edx),%eax
+	jl .L495
+	fstp %st(0)
+	fstp %st(0)
+.L493:
+	popl %ebx
+	popl %esi
+	popl %edi
+	leave
+	ret
+.Lfe3:
+	.size	 surf3d_draw,.Lfe3-surf3d_draw
+	.align 4
+.globl surf3d_rotate
+	.type	 surf3d_rotate,@function
+surf3d_rotate:
+	pushl %ebp
+	movl %esp,%ebp
+	subl $32,%esp
+	pushl %esi
+	pushl %ebx
+	flds 12(%ebp)
+	movl 8(%ebp),%ebx
+	fld %st(0)
+#APP
+	fsin
+#NO_APP
+	fstps -4(%ebp)
+	flds -4(%ebp)
+	fxch %st(1)
+#APP
+	fcos
+#NO_APP
+	fstps -4(%ebp)
+	xorl %esi,%esi
+	flds -4(%ebp)
+	cmpl 8(%ebx),%esi
+	jge .L537
+	xorl %ecx,%ecx
+	.p2align 4,,7
+.L508:
+	movl (%ebx),%eax
+	flds (%eax,%ecx)
+	flds 8(%eax,%ecx)
+	fmul %st(2),%st
+	fxch %st(1)
+	fmul %st(3),%st
+	fsubp %st,%st(1)
+	movl 4(%ebx),%edx
+	incl %esi
+	fstps (%edx,%ecx)
+	movl (%ebx),%eax
+	flds (%eax,%ecx)
+	flds 8(%eax,%ecx)
+	fxch %st(1)
+	fmul %st(2),%st
+	fxch %st(1)
+	fmul %st(3),%st
+	faddp %st,%st(1)
+	movl 4(%ebx),%edx
+	fstps 8(%edx,%ecx)
+	movl (%ebx),%eax
+	flds 4(%eax,%ecx)
+	movl 4(%ebx),%edx
+	fstps 4(%edx,%ecx)
+	addl $12,%ecx
+	cmpl 8(%ebx),%esi
+	jl .L508
+.L537:
+	fstp %st(0)
+	fstp %st(0)
+	popl %ebx
+	popl %esi
+	leave
+	ret
+.Lfe4:
+	.size	 surf3d_rotate,.Lfe4-surf3d_rotate
+	.align 4
+.globl surf3d_translate
+	.type	 surf3d_translate,@function
+surf3d_translate:
+	pushl %ebp
+	movl %esp,%ebp
+	pushl %ebx
+	movl 8(%ebp),%ecx
+	xorl %ebx,%ebx
+	cmpl 8(%ecx),%ebx
+	jge .L512
+	xorl %edx,%edx
+	.p2align 4,,7
+.L514:
+	movl 4(%ecx),%eax
+	flds (%eax,%edx)
+	fadds 12(%ecx)
+	incl %ebx
+	fstps (%eax,%edx)
+	movl 4(%ecx),%eax
+	flds 4(%eax,%edx)
+	fadds 16(%ecx)
+	fstps 4(%eax,%edx)
+	movl 4(%ecx),%eax
+	flds 8(%eax,%edx)
+	fadds 20(%ecx)
+	fstps 8(%eax,%edx)
+	addl $12,%edx
+	cmpl 8(%ecx),%ebx
+	jl .L514
+.L512:
+	popl %ebx
+	leave
+	ret
+.Lfe5:
+	.size	 surf3d_translate,.Lfe5-surf3d_translate
+	.ident	"GCC: (GNU) 2.95.3 19991030 (prerelease)"
diff --git a/gst/goom/tentacle3d.c b/gst/goom/tentacle3d.c
new file mode 100644
index 0000000..f82ffba
--- /dev/null
+++ b/gst/goom/tentacle3d.c
@@ -0,0 +1,358 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <stdlib.h>
+
+#include "v3d.h"
+#include "surf3d.h"
+#include "goom_tools.h"
+#include "goom_config.h"
+#include "goom_plugin_info.h"
+#include "tentacle3d.h"
+
+#define D 256.0f
+
+#define nbgrid 6
+#define definitionx 15
+#define definitionz 45
+
+typedef struct _TENTACLE_FX_DATA
+{
+  PluginParam enabled_bp;
+  PluginParameters params;
+
+  float cycle;
+  grid3d *grille[nbgrid];
+  float *vals;
+
+#define NB_TENTACLE_COLORS 4
+  int colors[NB_TENTACLE_COLORS];
+
+  int col;
+  int dstcol;
+  float lig;
+  float ligs;
+
+  /* statics from pretty_move */
+  float distt;
+  float distt2;
+  float rot;                    /* entre 0 et 2 * G_PI */
+  int happens;
+  int rotation;
+  int lock;
+} TentacleFXData;
+
+static void tentacle_new (TentacleFXData * data);
+static void tentacle_update (PluginInfo * goomInfo, Pixel * buf, Pixel * back,
+    int W, int H, short[2][512], float, int drawit, TentacleFXData * data);
+static void tentacle_free (TentacleFXData * data);
+
+/* 
+ * VisualFX wrapper for the tentacles
+ */
+
+static void
+tentacle_fx_init (VisualFX * _this, PluginInfo * info)
+{
+
+  TentacleFXData *data = (TentacleFXData *) malloc (sizeof (TentacleFXData));
+
+  secure_b_param (&data->enabled_bp, "Enabled", 1);
+  plugin_parameters (&data->params, "3D Tentacles", 1);
+  data->params.params[0] = &data->enabled_bp;
+
+  data->cycle = 0.0f;
+  data->col =
+      (0x28 << (ROUGE * 8)) | (0x2c << (VERT * 8)) | (0x5f << (BLEU * 8));
+  data->dstcol = 0;
+  data->lig = 1.15f;
+  data->ligs = 0.1f;
+
+  data->distt = 10.0f;
+  data->distt2 = 0.0f;
+  data->rot = 0.0f;             /* entre 0 et 2 * G_PI */
+  data->happens = 0;
+
+  data->rotation = 0;
+  data->lock = 0;
+  data->colors[0] =
+      (0x18 << (ROUGE * 8)) | (0x4c << (VERT * 8)) | (0x2f << (BLEU * 8));
+  data->colors[1] =
+      (0x48 << (ROUGE * 8)) | (0x2c << (VERT * 8)) | (0x6f << (BLEU * 8));
+  data->colors[2] =
+      (0x58 << (ROUGE * 8)) | (0x3c << (VERT * 8)) | (0x0f << (BLEU * 8));
+  data->colors[3] =
+      (0x87 << (ROUGE * 8)) | (0x55 << (VERT * 8)) | (0x74 << (BLEU * 8));
+  tentacle_new (data);
+
+  _this->params = &data->params;
+  _this->fx_data = (void *) data;
+}
+
+static void
+tentacle_fx_apply (VisualFX * _this, Pixel * src, Pixel * dest,
+    PluginInfo * goomInfo)
+{
+  TentacleFXData *data = (TentacleFXData *) _this->fx_data;
+
+  if (BVAL (data->enabled_bp)) {
+    tentacle_update (goomInfo, dest, src, goomInfo->screen.width,
+        goomInfo->screen.height, goomInfo->sound.samples,
+        (float) goomInfo->sound.accelvar,
+        goomInfo->curGState->drawTentacle, data);
+  }
+}
+
+static void
+tentacle_fx_free (VisualFX * _this)
+{
+  tentacle_free ((TentacleFXData *) _this->fx_data);
+  free (_this->fx_data);
+}
+
+void
+tentacle_fx_create (VisualFX * fx)
+{
+  fx->init = tentacle_fx_init;
+  fx->apply = tentacle_fx_apply;
+  fx->free = tentacle_fx_free;
+  fx->fx_data = NULL;
+  fx->params = NULL;
+}
+
+/* ----- */
+
+static void
+tentacle_free (TentacleFXData * data)
+{
+  int tmp;
+
+  /* FREE GRID */
+  for (tmp = 0; tmp < nbgrid; tmp++)
+    grid3d_free (data->grille[tmp]);
+  free (data->vals);
+
+  goom_plugin_parameters_free (&data->params);
+}
+
+static void
+tentacle_new (TentacleFXData * data)
+{
+  int tmp;
+
+  v3d center = { 0, -17.0, 0 };
+  data->vals = (float *) malloc ((definitionx + 20) * sizeof (float));
+
+  for (tmp = 0; tmp < nbgrid; tmp++) {
+    int x, z;
+
+    z = 45 + rand () % 30;
+    x = 85 + rand () % 5;
+    center.z = z;
+    data->grille[tmp] =
+        grid3d_new (x, definitionx, z, definitionz + rand () % 10, center);
+    center.y += 8;
+  }
+}
+
+static inline unsigned char
+lighten (unsigned char value, float power)
+{
+  int val = value;
+  float t = (float) val * log10 (power) / 2.0;
+
+  if (t > 0) {
+    val = (int) t;              /* (32.0f * log (t)); */
+    if (val > 255)
+      val = 255;
+    if (val < 0)
+      val = 0;
+    return val;
+  } else {
+    return 0;
+  }
+}
+
+static void
+lightencolor (int *col, float power)
+{
+  unsigned char *color;
+
+  color = (unsigned char *) col;
+  *color = lighten (*color, power);
+  color++;
+  *color = lighten (*color, power);
+  color++;
+  *color = lighten (*color, power);
+  color++;
+  *color = lighten (*color, power);
+}
+
+/* retourne x>>s , en testant le signe de x */
+#define ShiftRight(_x,_s) ((_x<0) ? -(-_x>>_s) : (_x>>_s))
+
+static int
+evolutecolor (unsigned int src, unsigned int dest,
+    unsigned int mask, unsigned int incr)
+{
+
+  int color = src & (~mask);
+
+  src &= mask;
+  dest &= mask;
+
+  if ((src != mask)
+      && (src < dest))
+    src += incr;
+
+  if (src > dest)
+    src -= incr;
+  return (src & mask) | color;
+}
+
+static void
+pretty_move (PluginInfo * goomInfo, float cycle, float *dist, float *dist2,
+    float *rotangle, TentacleFXData * fx_data)
+{
+
+  float tmp;
+
+  /* many magic numbers here... I don't really like that. */
+  if (fx_data->happens)
+    fx_data->happens -= 1;
+  else if (fx_data->lock == 0) {
+    fx_data->happens =
+        goom_irand (goomInfo->gRandom,
+        200) ? 0 : 100 + goom_irand (goomInfo->gRandom, 60);
+    fx_data->lock = fx_data->happens * 3 / 2;
+  } else
+    fx_data->lock--;
+
+  tmp = fx_data->happens ? 8.0f : 0;
+  *dist2 = fx_data->distt2 = (tmp + 15.0f * fx_data->distt2) / 16.0f;
+
+  tmp = 30 + D - 90.0f * (1.0f + sin (cycle * 19 / 20));
+  if (fx_data->happens)
+    tmp *= 0.6f;
+
+  *dist = fx_data->distt = (tmp + 3.0f * fx_data->distt) / 4.0f;
+
+  if (!fx_data->happens) {
+    tmp = G_PI * sin (cycle) / 32 + 3 * G_PI / 2;
+  } else {
+    fx_data->rotation =
+        goom_irand (goomInfo->gRandom,
+        500) ? fx_data->rotation : goom_irand (goomInfo->gRandom, 2);
+    if (fx_data->rotation)
+      cycle *= 2.0f * G_PI;
+    else
+      cycle *= -1.0f * G_PI;
+    tmp = cycle - (G_PI * 2.0) * floor (cycle / (G_PI * 2.0));
+  }
+
+  if (fabs (tmp - fx_data->rot) > fabs (tmp - (fx_data->rot + 2.0 * G_PI))) {
+    fx_data->rot = (tmp + 15.0f * (fx_data->rot + 2 * G_PI)) / 16.0f;
+    if (fx_data->rot > 2.0 * G_PI)
+      fx_data->rot -= 2.0 * G_PI;
+    *rotangle = fx_data->rot;
+  } else if (fabs (tmp - fx_data->rot) >
+      fabs (tmp - (fx_data->rot - 2.0 * G_PI))) {
+    fx_data->rot = (tmp + 15.0f * (fx_data->rot - 2.0 * G_PI)) / 16.0f;
+    if (fx_data->rot < 0.0f)
+      fx_data->rot += 2.0 * G_PI;
+    *rotangle = fx_data->rot;
+  } else
+    *rotangle = fx_data->rot = (tmp + 15.0f * fx_data->rot) / 16.0f;
+}
+
+static void
+tentacle_update (PluginInfo * goomInfo, Pixel * buf, Pixel * back, int W, int H,
+    short data[2][512], float rapport, int drawit, TentacleFXData * fx_data)
+{
+
+  int tmp;
+  int tmp2;
+
+  int color;
+  int colorlow;
+
+  float dist, dist2, rotangle;
+
+  if ((!drawit) && (fx_data->ligs > 0.0f))
+    fx_data->ligs = -fx_data->ligs;
+
+  fx_data->lig += fx_data->ligs;
+
+  if (fx_data->lig > 1.01f) {
+    if ((fx_data->lig > 10.0f) | (fx_data->lig < 1.1f))
+      fx_data->ligs = -fx_data->ligs;
+
+    if ((fx_data->lig < 6.3f) && (goom_irand (goomInfo->gRandom, 30) == 0))
+      fx_data->dstcol = goom_irand (goomInfo->gRandom, NB_TENTACLE_COLORS);
+
+    fx_data->col =
+        evolutecolor (fx_data->col, fx_data->colors[fx_data->dstcol], 0xff,
+        0x01);
+    fx_data->col =
+        evolutecolor (fx_data->col, fx_data->colors[fx_data->dstcol], 0xff00,
+        0x0100);
+    fx_data->col =
+        evolutecolor (fx_data->col, fx_data->colors[fx_data->dstcol], 0xff0000,
+        0x010000);
+    fx_data->col =
+        evolutecolor (fx_data->col, fx_data->colors[fx_data->dstcol],
+        0xff000000, 0x01000000);
+
+    color = fx_data->col;
+    colorlow = fx_data->col;
+
+    lightencolor (&color, fx_data->lig * 2.0f + 2.0f);
+    lightencolor (&colorlow, (fx_data->lig / 3.0f) + 0.67f);
+
+    rapport = 1.0f + 2.0f * (rapport - 1.0f);
+    rapport *= 1.2f;
+    if (rapport > 1.12f)
+      rapport = 1.12f;
+
+    pretty_move (goomInfo, fx_data->cycle, &dist, &dist2, &rotangle, fx_data);
+
+    for (tmp = 0; tmp < nbgrid; tmp++) {
+      for (tmp2 = 0; tmp2 < definitionx; tmp2++) {
+        float val =
+            (float) (ShiftRight (data[0][goom_irand (goomInfo->gRandom, 511)],
+                10)) * rapport;
+
+        fx_data->vals[tmp2] = val;
+      }
+
+      grid3d_update (fx_data->grille[tmp], rotangle, fx_data->vals, dist2);
+    }
+    fx_data->cycle += 0.01f;
+    for (tmp = 0; tmp < nbgrid; tmp++)
+      grid3d_draw (goomInfo, fx_data->grille[tmp], color, colorlow, dist, buf,
+          back, W, H);
+  } else {
+    fx_data->lig = 1.05f;
+    if (fx_data->ligs < 0.0f)
+      fx_data->ligs = -fx_data->ligs;
+    pretty_move (goomInfo, fx_data->cycle, &dist, &dist2, &rotangle, fx_data);
+    fx_data->cycle += 0.1f;
+    if (fx_data->cycle > 1000)
+      fx_data->cycle = 0;
+  }
+}
diff --git a/gst/goom/tentacle3d.h b/gst/goom/tentacle3d.h
new file mode 100644
index 0000000..9f3ba92
--- /dev/null
+++ b/gst/goom/tentacle3d.h
@@ -0,0 +1,26 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _TENTACLE3D_H
+#define _TENTACLE3D_H
+
+#include "goom_visual_fx.h"
+
+void tentacle_fx_create(VisualFX *fx);
+
+#endif
diff --git a/gst/goom/v3d.c b/gst/goom/v3d.c
new file mode 100644
index 0000000..7df4f13
--- /dev/null
+++ b/gst/goom/v3d.c
@@ -0,0 +1,38 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "v3d.h"
+
+void
+v3d_to_v2d (v3d * v3, int nbvertex, int width, int height, float distance,
+    v2d * v2)
+{
+  int i;
+
+  for (i = 0; i < nbvertex; ++i) {
+    if (v3[i].z > 2) {
+      int Xp, Yp;
+
+      F2I ((distance * v3[i].x / v3[i].z), Xp);
+      F2I ((distance * v3[i].y / v3[i].z), Yp);
+      v2[i].x = Xp + (width >> 1);
+      v2[i].y = -Yp + (height >> 1);
+    } else
+      v2[i].x = v2[i].y = -666;
+  }
+}
diff --git a/gst/goom/v3d.h b/gst/goom/v3d.h
new file mode 100644
index 0000000..fd5f939
--- /dev/null
+++ b/gst/goom/v3d.h
@@ -0,0 +1,83 @@
+/* Goom Project
+ * Copyright (C) <2003> iOS-Software
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _V3D_H
+#define _V3D_H
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "mathtools.h"
+
+typedef struct {
+    float x,y,z;
+} v3d;
+
+typedef struct {
+    int x,y;
+} v2d;
+
+typedef struct {
+    double x,y;
+} v2g;
+
+/* 
+ * projete le vertex 3D sur le plan d'affichage
+ * retourne (0,0) si le point ne doit pas etre affiche.
+ *
+ * bonne valeur pour distance : 256
+ */
+#define V3D_TO_V2D(v3,v2,width,height,distance) \
+{ \
+  int Xp, Yp; \
+  if (v3.z > 2) { \
+	 F2I((distance * v3.x / v3.z),Xp) ; \
+ 	 F2I((distance * v3.y / v3.z),Yp) ; \
+ 	 v2.x = Xp + (width>>1); \
+	 v2.y = -Yp + (height>>1); \
+  } \
+  else v2.x=v2.y=-666; \
+}
+
+void v3d_to_v2d(v3d *src, int nbvertex, int width, int height, float distance, v2d *v2_array);
+
+/*
+ * rotation selon Y du v3d vi d'angle a (cosa=cos(a), sina=sin(a))
+ * centerz = centre de rotation en z
+ */
+#define Y_ROTATE_V3D(vi,vf,sina,cosa)\
+{\
+ vf.x = vi.x * cosa - vi.z * sina;\
+ vf.z = vi.x * sina + vi.z * cosa;\
+ vf.y = vi.y;\
+}
+
+/*
+ * translation
+ */
+#define TRANSLATE_V3D(vsrc,vdest)\
+{\
+ vdest.x += vsrc.x;\
+ vdest.y += vsrc.y;\
+ vdest.z += vsrc.z;\
+}
+
+#define MUL_V3D(lf,v) {v.x*=lf;v.y*=lf;v.z*=lf;}
+
+#endif
diff --git a/gst/goom/xmmx.c b/gst/goom/xmmx.c
new file mode 100644
index 0000000..ea87cf9
--- /dev/null
+++ b/gst/goom/xmmx.c
@@ -0,0 +1,402 @@
+/*	xmmx.c
+
+	eXtended MultiMedia eXtensions GCC interface library for IA32.
+
+	To use this library, simply include this header file
+	and compile with GCC.  You MUST have inlining enabled
+	in order for xmmx_ok() to work; this can be done by
+	simply using -O on the GCC command line.
+
+	Compiling with -DXMMX_TRACE will cause detailed trace
+	output to be sent to stderr for each mmx operation.
+	This adds lots of code, and obviously slows execution to
+	a crawl, but can be very useful for debugging.
+
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
+	EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+	LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR ANY PARTICULAR PURPOSE.
+
+	1999 by R. Fisher
+	Based on libmmx, 1997-99 by H. Dietz and R. Fisher
+
+ Notes:
+	It appears that the latest gas has the pand problem fixed, therefore
+	  I'll undefine BROKEN_PAND by default.
+*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "goom_config.h"
+
+#ifdef HAVE_MMX
+
+/* a definir pour avoir exactement le meme resultat que la fonction C
+ * (un chouillat plus lent).. mais la difference est assez peu notable.
+ */
+// #define STRICT_COMPAT
+
+#define BUFFPOINTNB 16
+#define BUFFPOINTMASK 0xffff
+#define BUFFINCR 0xff
+
+#define sqrtperte 16
+/* faire : a % sqrtperte <=> a & pertemask*/
+#define PERTEMASK 0xf
+/* faire : a / sqrtperte <=> a >> PERTEDEC*/
+#define PERTEDEC 4
+
+
+/*#define MMX_TRACE*/
+#include "mmx.h"
+/*#include "xmmx.h"*/
+#include "goom_graphic.h"
+
+int
+xmmx_supported (void)
+{
+  return (mm_support () & 0x8) >> 3;
+}
+
+void
+zoom_filter_xmmx (int prevX, int prevY,
+    Pixel * expix1, Pixel * expix2,
+    int *lbruS, int *lbruD, int buffratio, int precalCoef[16][16])
+{
+  int bufsize = prevX * prevY;  /* taille du buffer */
+  volatile int loop;            /* variable de boucle */
+
+  mmx_t *brutS = (mmx_t *) lbruS;       /* buffer de transformation source */
+  mmx_t *brutD = (mmx_t *) lbruD;       /* buffer de transformation dest */
+
+  volatile mmx_t prevXY;
+  volatile mmx_t ratiox;
+
+  /*      volatile mmx_t interpix; */
+
+  expix1[0].val = expix1[prevX - 1].val = expix1[prevX * prevY - 1].val =
+      expix1[prevX * prevY - prevX].val = 0;
+
+  prevXY.ud[0] = (prevX - 1) << PERTEDEC;
+  prevXY.ud[1] = (prevY - 1) << PERTEDEC;
+
+  ratiox.d[0] = buffratio;
+  ratiox.d[1] = buffratio;
+
+  asm volatile ("\n\t movq  %[ratio], %%mm6" "\n\t pslld $16,      %%mm6"       /* mm6 = [rat16=buffratio<<16 | rat16=buffratio<<16] */
+      "\n\t pxor  %%mm7,    %%mm7"      /* mm7 = 0 */
+      ::[ratio] "m" (ratiox));
+
+  loop = 0;
+
+  /*
+   * NOTE : mm6 et mm7 ne sont pas modifies dans la boucle.
+   */
+  while (loop < bufsize) {
+    /* Thread #1
+     * pre :  mm6 = [rat16|rat16]
+     * post : mm0 = S + ((D-S)*rat16 format [X|Y]
+     * modified = mm0,mm1,mm2
+     */
+
+    asm volatile ("#1 \n\t movq 0(%[brutS]), %%mm0" "#1 \n\t movq 0(%[brutD]), %%mm1" "#1 \n\t psubd   %%mm0, %%mm1"    /* mm1 = D - S */
+        "#1 \n\t movq    %%mm1, %%mm2"  /* mm2 = D - S */
+        "#1 \n\t pslld     $16, %%mm1" "#1 \n\t pmullw  %%mm6, %%mm2" "#1 \n\t pmulhuw %%mm6, %%mm1" "#1 \n\t pslld   $16,   %%mm0" "#1 \n\t paddd   %%mm2, %%mm1"      /* mm1 = (D - S) * buffratio >> 16 */
+        "#1 \n\t paddd   %%mm1, %%mm0"  /* mm0 = S + mm1 */
+        "#1 \n\t psrld   $16,   %%mm0"::[brutS] "r" (&brutS[loop]),
+        [brutD] "r" (&brutD[loop])
+        );                      /* mm0 = S */
+
+    /*
+     * pre : mm0 : position vector on screen
+     *       prevXY : coordinate of the lower-right point on screen
+     * post : clipped mm0
+     * modified : mm0,mm1,mm2
+     */
+    asm volatile
+        ("#1 \n\t movq %[prevXY], %%mm1" "#1 \n\t pcmpgtd %%mm0,  %%mm1"
+        /* mm0 en X contient (idem pour Y) :
+         *   1111 si prevXY > px
+         *   0000 si prevXY <= px */
+#ifdef STRICT_COMPAT
+        "#1 \n\t movq      %%mm1, %%mm2"
+        "#1 \n\t punpckhdq %%mm2, %%mm2"
+        "#1 \n\t punpckldq %%mm1, %%mm1" "#1 \n\t pand      %%mm2, %%mm0"
+#endif
+        "#1 \n\t pand %%mm1, %%mm0"     /* on met a zero la partie qui deborde */
+        ::[prevXY] "m" (prevXY));
+
+    /* Thread #2
+     * pre :  mm0 : clipped position on screen
+     *
+     * post : mm3 : coefs for this position
+     *        mm1 : X vector [0|X]
+     *
+     * modif : eax,esi
+     */
+    __asm__ __volatile__ ("#2 \n\t movd %%mm0,%%esi"
+        "#2 \n\t movq %%mm0,%%mm1"
+        "#2 \n\t andl $15,%%esi"
+        "#2 \n\t psrlq $32,%%mm1"
+        "#2 \n\t shll $6,%%esi"
+        "#2 \n\t movd %%mm1,%%eax"
+        "#2 \n\t addl %[precalCoef],%%esi"
+        "#2 \n\t andl $15,%%eax"
+        "#2 \n\t movd (%%esi,%%eax,4),%%mm3"::[precalCoef]
+        "g" (precalCoef):"eax", "esi");
+
+    /*
+     * extraction des coefficients... (Thread #3)
+     *
+     * pre : coef dans mm3
+     *
+     * post : coef extraits dans mm3 (c1 & c2)
+     *                        et mm4 (c3 & c4)
+     *
+     * modif : mm5
+     */
+
+    /* (Thread #4)
+     * pre : mm0 : Y pos [*|Y]
+     *       mm1 : X pos [*|X]
+     *
+     * post : mm0 : expix1[position]
+     *        mm2 : expix1[position+largeur]
+     *
+     * modif : eax, esi
+     */
+    __asm__ __volatile__ ("#2 \n\t psrld $4, %%mm0" "#2 \n\t psrld $4, %%mm1"   /* PERTEDEC = $4 */
+        "#4 \n\t movd %%mm1,%%eax"
+        "#3 \n\t movq %%mm3,%%mm5"
+        "#4 \n\t mull %[prevX]"
+        "#4 \n\t movd %%mm0,%%esi"
+        "#3 \n\t punpcklbw %%mm5, %%mm3"
+        "#4 \n\t addl %%esi, %%eax"
+        "#3 \n\t movq %%mm3, %%mm4"
+        "#3 \n\t movq %%mm3, %%mm5"
+        "#4 \n\t movl %[expix1], %%esi"
+        "#3 \n\t punpcklbw %%mm5, %%mm3"
+        "#4 \n\t movq (%%esi,%%eax,4),%%mm0"
+        "#3 \n\t punpckhbw %%mm5, %%mm4"
+        "#4 \n\t addl %[prevX],%%eax"
+        "#4 \n\t movq (%%esi,%%eax,4),%%mm2"::[expix1] "g" (expix1)
+        ,[prevX] "g" (prevX)
+        :"eax", "esi", "edx");
+
+    /*
+     * pre :       mm0 : expix1[position]
+     *             mm2 : expix1[position+largeur]
+     *       mm3 & mm4 : coefs
+     */
+
+    /* recopie des deux premiers pixels dans mm0 et mm1 */
+    movq_r2r (mm0, mm1);        /* b1-v1-r1-a1-b2-v2-r2-a2 */
+
+    /* depackage du premier pixel */
+    punpcklbw_r2r (mm7, mm0);   /* 00-b2-00-v2-00-r2-00-a2 */
+
+    /* extraction des coefficients... */
+
+    movq_r2r (mm3, mm5);        /* c2-c2-c2-c2-c1-c1-c1-c1 */
+
+    /*^en parrallele^ *//* depackage du 2ieme pixel */
+    /*^ */ punpckhbw_r2r (mm7, mm1);
+    /* 00-b1-00-v1-00-r1-00-a1 */
+
+    punpcklbw_r2r (mm7, mm5);   /* 00-c1-00-c1-00-c1-00-c1 */
+    punpckhbw_r2r (mm7, mm3);   /* 00-c2-00-c2-00-c2-00-c2 */
+
+    /* multiplication des pixels par les coefficients */
+    pmullw_r2r (mm5, mm0);      /* c1*b2-c1*v2-c1*r2-c1*a2 */
+    pmullw_r2r (mm3, mm1);      /* c2*b1-c2*v1-c2*r1-c2*a1 */
+    paddw_r2r (mm1, mm0);
+
+    /* ...extraction des 2 derniers coefficients */
+    movq_r2r (mm4, mm5);        /* c4-c4-c4-c4-c3-c3-c3-c3 */
+    punpcklbw_r2r (mm7, mm4);   /* 00-c3-00-c3-00-c3-00-c3 */
+    punpckhbw_r2r (mm7, mm5);   /* 00-c4-00-c4-00-c4-00-c4 */
+
+    /* recuperation des 2 derniers pixels */
+    movq_r2r (mm2, mm1);
+
+    /* depackage des pixels */
+    punpcklbw_r2r (mm7, mm1);
+    punpckhbw_r2r (mm7, mm2);
+
+    /* multiplication pas les coeffs */
+    pmullw_r2r (mm4, mm1);
+    pmullw_r2r (mm5, mm2);
+
+    /* ajout des valeurs obtenues � la valeur finale */
+    paddw_r2r (mm1, mm0);
+    paddw_r2r (mm2, mm0);
+
+    /* division par 256 = 16+16+16+16, puis repackage du pixel final */
+    psrlw_i2r (8, mm0);
+    packuswb_r2r (mm7, mm0);
+
+    movd_r2m (mm0, expix2[loop]);
+
+    ++loop;
+  }
+  /* this was femms, which is AMD 3dnow */
+  __asm__ __volatile__ ("emms\n");
+}
+
+#define DRAWMETHOD_PLUS_XMMX(_out,_backbuf,_col) \
+{ \
+	movd_m2r(_backbuf, mm0); \
+	paddusb_m2r(_col, mm0); \
+	movd_r2m(mm0, _out); \
+}
+
+#define DRAWMETHOD DRAWMETHOD_PLUS_XMMX(*p,*p,col)
+
+void
+draw_line_xmmx (Pixel * data, int x1, int y1, int x2, int y2, int col,
+    int screenx, int screeny)
+{
+  int x, y, dx, dy, yy, xx;
+  Pixel *p;
+
+  if ((y1 < 0) || (y2 < 0) || (x1 < 0) || (x2 < 0) || (y1 >= screeny)
+      || (y2 >= screeny) || (x1 >= screenx) || (x2 >= screenx))
+    goto end_of_line;
+
+  dx = x2 - x1;
+  dy = y2 - y1;
+  if (x1 >= x2) {
+    int tmp;
+
+    tmp = x1;
+    x1 = x2;
+    x2 = tmp;
+    tmp = y1;
+    y1 = y2;
+    y2 = tmp;
+    dx = x2 - x1;
+    dy = y2 - y1;
+  }
+
+  /* vertical line */
+  if (dx == 0) {
+    if (y1 < y2) {
+      p = &(data[(screenx * y1) + x1]);
+      for (y = y1; y <= y2; y++) {
+        DRAWMETHOD;
+        p += screenx;
+      }
+    } else {
+      p = &(data[(screenx * y2) + x1]);
+      for (y = y2; y <= y1; y++) {
+        DRAWMETHOD;
+        p += screenx;
+      }
+    }
+    goto end_of_line;
+  }
+  /* horizontal line */
+  if (dy == 0) {
+    if (x1 < x2) {
+      p = &(data[(screenx * y1) + x1]);
+      for (x = x1; x <= x2; x++) {
+        DRAWMETHOD;
+        p++;
+      }
+      goto end_of_line;
+    } else {
+      p = &(data[(screenx * y1) + x2]);
+      for (x = x2; x <= x1; x++) {
+        DRAWMETHOD;
+        p++;
+      }
+      goto end_of_line;
+    }
+  }
+  /* 1    */
+  /*  \   */
+  /*   \  */
+  /*    2 */
+  if (y2 > y1) {
+    /* steep */
+    if (dy > dx) {
+      dx = ((dx << 16) / dy);
+      x = x1 << 16;
+      for (y = y1; y <= y2; y++) {
+        xx = x >> 16;
+        p = &(data[(screenx * y) + xx]);
+        DRAWMETHOD;
+        if (xx < (screenx - 1)) {
+          p++;
+          /* DRAWMETHOD; */
+        }
+        x += dx;
+      }
+      goto end_of_line;
+    }
+    /* shallow */
+    else {
+      dy = ((dy << 16) / dx);
+      y = y1 << 16;
+      for (x = x1; x <= x2; x++) {
+        yy = y >> 16;
+        p = &(data[(screenx * yy) + x]);
+        DRAWMETHOD;
+        if (yy < (screeny - 1)) {
+          p += screeny;
+          /* DRAWMETHOD; */
+        }
+        y += dy;
+      }
+    }
+  }
+  /*    2 */
+  /*   /  */
+  /*  /   */
+  /* 1    */
+  else {
+    /* steep */
+    if (-dy > dx) {
+      dx = ((dx << 16) / -dy);
+      x = (x1 + 1) << 16;
+      for (y = y1; y >= y2; y--) {
+        xx = x >> 16;
+        p = &(data[(screenx * y) + xx]);
+        DRAWMETHOD;
+        if (xx < (screenx - 1)) {
+          p--;
+          /* DRAWMETHOD; */
+        }
+        x += dx;
+      }
+      goto end_of_line;
+    }
+    /* shallow */
+    else {
+      dy = ((dy << 16) / dx);
+      y = y1 << 16;
+      for (x = x1; x <= x2; x++) {
+        yy = y >> 16;
+        p = &(data[(screenx * yy) + x]);
+        DRAWMETHOD;
+        if (yy < (screeny - 1)) {
+          p += screeny;
+          /* DRAWMETHOD; */
+        }
+        y += dy;
+      }
+      goto end_of_line;
+    }
+  }
+end_of_line:
+  /* this was femms, which is AMD 3dnow */
+  __asm__ __volatile__ ("emms\n");
+}
+#else
+int
+xmmx_supported (void)
+{
+  return (0);
+}
+#endif
diff --git a/gst/goom/xmmx.h b/gst/goom/xmmx.h
new file mode 100644
index 0000000..70ef361
--- /dev/null
+++ b/gst/goom/xmmx.h
@@ -0,0 +1,537 @@
+/*	xmmx.h
+
+	eXtended MultiMedia eXtensions GCC interface library for IA32.
+
+	To use this library, simply include this header file
+	and compile with GCC.  You MUST have inlining enabled
+	in order for xmmx_ok() to work; this can be done by
+	simply using -O on the GCC command line.
+
+	Compiling with -DXMMX_TRACE will cause detailed trace
+	output to be sent to stderr for each mmx operation.
+	This adds lots of code, and obviously slows execution to
+	a crawl, but can be very useful for debugging.
+
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
+	EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+	LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR ANY PARTICULAR PURPOSE.
+
+	1999 by R. Fisher
+	Based on libmmx, 1997-99 by H. Dietz and R. Fisher
+
+ Notes:
+	It appears that the latest gas has the pand problem fixed, therefore
+	  I'll undefine BROKEN_PAND by default.
+*/
+
+#ifndef _XMMX_H
+#define _XMMX_H
+
+
+/*	Warning:  at this writing, the version of GAS packaged
+	with most Linux distributions does not handle the
+	parallel AND operation mnemonic correctly.  If the
+	symbol BROKEN_PAND is defined, a slower alternative
+	coding will be used.  If execution of mmxtest results
+	in an illegal instruction fault, define this symbol.
+*/
+#undef	BROKEN_PAND
+
+
+/*	The type of an value that fits in an (Extended) MMX register
+	(note that long long constant values MUST be suffixed
+	 by LL and unsigned long long values by ULL, lest
+	 they be truncated by the compiler)
+*/
+#ifndef _MMX_H
+typedef	union {
+	long long		q;	/* Quadword (64-bit) value */
+	unsigned long long	uq;	/* Unsigned Quadword */
+	int			d[2];	/* 2 Doubleword (32-bit) values */
+	unsigned int		ud[2];	/* 2 Unsigned Doubleword */
+	short			w[4];	/* 4 Word (16-bit) values */
+	unsigned short		uw[4];	/* 4 Unsigned Word */
+	char			b[8];	/* 8 Byte (8-bit) values */
+	unsigned char		ub[8];	/* 8 Unsigned Byte */
+	float			s[2];	/* Single-precision (32-bit) value */
+} __attribute__ ((aligned (8))) mmx_t;	/* On an 8-byte (64-bit) boundary */
+#endif
+
+
+
+/*	Function to test if multimedia instructions are supported...
+*/
+static int
+mm_support(void)
+{
+	/* Returns 1 if MMX instructions are supported,
+	   3 if Cyrix MMX and Extended MMX instructions are supported
+	   5 if AMD MMX and 3DNow! instructions are supported
+	   0 if hardware does not support any of these
+	*/
+	register int rval = 0;
+
+	__asm__ __volatile__ (
+		/* See if CPUID instruction is supported ... */
+		/* ... Get copies of EFLAGS into eax and ecx */
+		"pushf\n\t"
+		"popl %%eax\n\t"
+		"movl %%eax, %%ecx\n\t"
+
+		/* ... Toggle the ID bit in one copy and store */
+		/*     to the EFLAGS reg */
+		"xorl $0x200000, %%eax\n\t"
+		"push %%eax\n\t"
+		"popf\n\t"
+
+		/* ... Get the (hopefully modified) EFLAGS */
+		"pushf\n\t"
+		"popl %%eax\n\t"
+
+		/* ... Compare and test result */
+		"xorl %%eax, %%ecx\n\t"
+		"testl $0x200000, %%ecx\n\t"
+		"jz NotSupported1\n\t"		/* CPUID not supported */
+
+
+		/* Get standard CPUID information, and
+		       go to a specific vendor section */
+		"movl $0, %%eax\n\t"
+		"cpuid\n\t"
+
+		/* Check for Intel */
+		"cmpl $0x756e6547, %%ebx\n\t"
+		"jne TryAMD\n\t"
+		"cmpl $0x49656e69, %%edx\n\t"
+		"jne TryAMD\n\t"
+		"cmpl $0x6c65746e, %%ecx\n"
+		"jne TryAMD\n\t"
+		"jmp Intel\n\t"
+
+		/* Check for AMD */
+		"\nTryAMD:\n\t"
+		"cmpl $0x68747541, %%ebx\n\t"
+		"jne TryCyrix\n\t"
+		"cmpl $0x69746e65, %%edx\n\t"
+		"jne TryCyrix\n\t"
+		"cmpl $0x444d4163, %%ecx\n"
+		"jne TryCyrix\n\t"
+		"jmp AMD\n\t"
+
+		/* Check for Cyrix */
+		"\nTryCyrix:\n\t"
+		"cmpl $0x69727943, %%ebx\n\t"
+		"jne NotSupported2\n\t"
+		"cmpl $0x736e4978, %%edx\n\t"
+		"jne NotSupported3\n\t"
+		"cmpl $0x64616574, %%ecx\n\t"
+		"jne NotSupported4\n\t"
+		/* Drop through to Cyrix... */
+
+
+		/* Cyrix Section */
+		/* See if extended CPUID level 80000001 is supported */
+		/* The value of CPUID/80000001 for the 6x86MX is undefined
+		   according to the Cyrix CPU Detection Guide (Preliminary
+		   Rev. 1.01 table 1), so we'll check the value of eax for
+		   CPUID/0 to see if standard CPUID level 2 is supported.
+		   According to the table, the only CPU which supports level
+		   2 is also the only one which supports extended CPUID levels.
+		*/
+		"cmpl $0x2, %%eax\n\t"
+		"jne MMXtest\n\t"	/* Use standard CPUID instead */
+
+		/* Extended CPUID supported (in theory), so get extended
+		   features */
+		"movl $0x80000001, %%eax\n\t"
+		"cpuid\n\t"
+		"testl $0x00800000, %%eax\n\t"	/* Test for MMX */
+		"jz NotSupported5\n\t"		/* MMX not supported */
+		"testl $0x01000000, %%eax\n\t"	/* Test for Ext'd MMX */
+		"jnz EMMXSupported\n\t"
+		"movl $1, %0:\n\n\t"		/* MMX Supported */
+		"jmp Return\n\n"
+		"EMMXSupported:\n\t"
+		"movl $3, %0:\n\n\t"		/* EMMX and MMX Supported */
+		"jmp Return\n\t"
+
+
+		/* AMD Section */
+		"AMD:\n\t"
+
+		/* See if extended CPUID is supported */
+		"movl $0x80000000, %%eax\n\t"
+		"cpuid\n\t"
+		"cmpl $0x80000000, %%eax\n\t"
+		"jl MMXtest\n\t"	/* Use standard CPUID instead */
+
+		/* Extended CPUID supported, so get extended features */
+		"movl $0x80000001, %%eax\n\t"
+		"cpuid\n\t"
+		"testl $0x00800000, %%edx\n\t"	/* Test for MMX */
+		"jz NotSupported6\n\t"		/* MMX not supported */
+		"testl $0x80000000, %%edx\n\t"	/* Test for 3DNow! */
+		"jnz ThreeDNowSupported\n\t"
+		"movl $1, %0:\n\n\t"		/* MMX Supported */
+		"jmp Return\n\n"
+		"ThreeDNowSupported:\n\t"
+		"movl $5, %0:\n\n\t"		/* 3DNow! and MMX Supported */
+		"jmp Return\n\t"
+
+
+		/* Intel Section */
+		"Intel:\n\t"
+
+		/* Check for MMX */
+		"MMXtest:\n\t"
+		"movl $1, %%eax\n\t"
+		"cpuid\n\t"
+		"testl $0x00800000, %%edx\n\t"	/* Test for MMX */
+		"jz NotSupported7\n\t"		/* MMX Not supported */
+		"movl $1, %0:\n\n\t"		/* MMX Supported */
+		"jmp Return\n\t"
+
+		/* Nothing supported */
+		"\nNotSupported1:\n\t"
+		"#movl $101, %0:\n\n\t"
+		"\nNotSupported2:\n\t"
+		"#movl $102, %0:\n\n\t"
+		"\nNotSupported3:\n\t"
+		"#movl $103, %0:\n\n\t"
+		"\nNotSupported4:\n\t"
+		"#movl $104, %0:\n\n\t"
+		"\nNotSupported5:\n\t"
+		"#movl $105, %0:\n\n\t"
+		"\nNotSupported6:\n\t"
+		"#movl $106, %0:\n\n\t"
+		"\nNotSupported7:\n\t"
+		"#movl $107, %0:\n\n\t"
+		"movl $0, %0:\n\n\t"
+
+		"Return:\n\t"
+		: "=a" (rval)
+		: /* no input */
+		: "eax", "ebx", "ecx", "edx"
+	);
+
+	/* Return */
+	return(rval);
+}
+
+/*	Function to test if mmx instructions are supported...
+*/
+#ifndef _XMMX_H
+inline extern int
+mmx_ok(void)
+{
+	/* Returns 1 if MMX instructions are supported, 0 otherwise */
+	return ( mm_support() & 0x1 );
+}
+#endif
+
+/*	Function to test if xmmx instructions are supported...
+*/
+inline extern int
+xmmx_ok(void)
+{
+	/* Returns 1 if Extended MMX instructions are supported, 0 otherwise */
+	return ( (mm_support() & 0x2) >> 1 );
+}
+
+
+/*	Helper functions for the instruction macros that follow...
+	(note that memory-to-register, m2r, instructions are nearly
+	 as efficient as register-to-register, r2r, instructions;
+	 however, memory-to-memory instructions are really simulated
+	 as a convenience, and are only 1/3 as efficient)
+*/
+#ifdef	XMMX_TRACE
+
+/*	Include the stuff for printing a trace to stderr...
+*/
+
+#include <stdio.h>
+
+#define	mmx_i2r(op, imm, reg) \
+	{ \
+		mmx_t mmx_trace; \
+		mmx_trace.uq = (imm); \
+		fprintf(stderr, #op "_i2r(" #imm "=0x%08x%08x, ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #reg "=0x%08x%08x) => ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ (#op " %0, %%" #reg \
+				      : /* nothing */ \
+				      : "X" (imm)); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #reg "=0x%08x%08x\n", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+	}
+
+#define	mmx_m2r(op, mem, reg) \
+	{ \
+		mmx_t mmx_trace; \
+		mmx_trace = (mem); \
+		fprintf(stderr, #op "_m2r(" #mem "=0x%08x%08x, ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #reg "=0x%08x%08x) => ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ (#op " %0, %%" #reg \
+				      : /* nothing */ \
+				      : "X" (mem)); \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #reg "=0x%08x%08x\n", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+	}
+
+#define	mmx_r2m(op, reg, mem) \
+	{ \
+		mmx_t mmx_trace; \
+		__asm__ __volatile__ ("movq %%" #reg ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #op "_r2m(" #reg "=0x%08x%08x, ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		mmx_trace = (mem); \
+		fprintf(stderr, #mem "=0x%08x%08x) => ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ (#op " %%" #reg ", %0" \
+				      : "=X" (mem) \
+				      : /* nothing */ ); \
+		mmx_trace = (mem); \
+		fprintf(stderr, #mem "=0x%08x%08x\n", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+	}
+
+#define	mmx_r2r(op, regs, regd) \
+	{ \
+		mmx_t mmx_trace; \
+		__asm__ __volatile__ ("movq %%" #regs ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #op "_r2r(" #regs "=0x%08x%08x, ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ ("movq %%" #regd ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #regd "=0x%08x%08x) => ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ (#op " %" #regs ", %" #regd); \
+		__asm__ __volatile__ ("movq %%" #regd ", %0" \
+				      : "=X" (mmx_trace) \
+				      : /* nothing */ ); \
+		fprintf(stderr, #regd "=0x%08x%08x\n", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+	}
+
+#define	mmx_m2m(op, mems, memd) \
+	{ \
+		mmx_t mmx_trace; \
+		mmx_trace = (mems); \
+		fprintf(stderr, #op "_m2m(" #mems "=0x%08x%08x, ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		mmx_trace = (memd); \
+		fprintf(stderr, #memd "=0x%08x%08x) => ", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+		__asm__ __volatile__ ("movq %0, %%mm0\n\t" \
+				      #op " %1, %%mm0\n\t" \
+				      "movq %%mm0, %0" \
+				      : "=X" (memd) \
+				      : "X" (mems)); \
+		mmx_trace = (memd); \
+		fprintf(stderr, #memd "=0x%08x%08x\n", \
+			mmx_trace.d[1], mmx_trace.d[0]); \
+	}
+
+#else
+
+/*	These macros are a lot simpler without the tracing...
+*/
+
+#define	mmx_i2r(op, imm, reg) \
+	__asm__ __volatile__ (#op " %0, %%" #reg \
+			      : /* nothing */ \
+			      : "X" (imm) )
+
+#define	mmx_m2r(op, mem, reg) \
+	__asm__ __volatile__ (#op " %0, %%" #reg \
+			      : /* nothing */ \
+			      : "X" (mem))
+
+#define	mmx_m2ir(op, mem, rs) \
+	__asm__ __volatile__ (#op " %0, %%" #rs \
+			      : /* nothing */ \
+			      : "X" (mem) )
+
+#define	mmx_r2m(op, reg, mem) \
+	__asm__ __volatile__ (#op " %%" #reg ", %0" \
+			      : "=X" (mem) \
+			      : /* nothing */ )
+
+#define	mmx_r2r(op, regs, regd) \
+	__asm__ __volatile__ (#op " %" #regs ", %" #regd)
+
+#define	mmx_r2ir(op, rs1, rs2) \
+	__asm__ __volatile__ (#op " %%" #rs1 ", %%" #rs2 \
+			      : /* nothing */ \
+			      : /* nothing */ )
+
+#define	mmx_m2m(op, mems, memd) \
+	__asm__ __volatile__ ("movq %0, %%mm0\n\t" \
+			      #op " %1, %%mm0\n\t" \
+			      "movq %%mm0, %0" \
+			      : "=X" (memd) \
+			      : "X" (mems))
+
+#endif
+
+
+
+/*	1x64 MOVe Quadword
+	(this is both a load and a store...
+	 in fact, it is the only way to store)
+*/
+#define	movq_m2r(var, reg)	mmx_m2r(movq, var, reg)
+#define	movq_r2m(reg, var)	mmx_r2m(movq, reg, var)
+#define	movq_r2r(regs, regd)	mmx_r2r(movq, regs, regd)
+#define	movq(vars, vard) \
+	__asm__ __volatile__ ("movq %1, %%mm0\n\t" \
+			      "movq %%mm0, %0" \
+			      : "=X" (vard) \
+			      : "X" (vars))
+
+
+/*	1x32 MOVe Doubleword
+	(like movq, this is both load and store...
+	 but is most useful for moving things between
+	 mmx registers and ordinary registers)
+*/
+#define	movd_m2r(var, reg)	mmx_m2r(movd, var, reg)
+#define	movd_r2m(reg, var)	mmx_r2m(movd, reg, var)
+#define	movd_r2r(regs, regd)	mmx_r2r(movd, regs, regd)
+#define	movd(vars, vard) \
+	__asm__ __volatile__ ("movd %1, %%mm0\n\t" \
+			      "movd %%mm0, %0" \
+			      : "=X" (vard) \
+			      : "X" (vars))
+
+
+
+/*	4x16 Parallel MAGnitude
+*/
+#define	pmagw_m2r(var, reg)	mmx_m2r(pmagw, var, reg)
+#define	pmagw_r2r(regs, regd)	mmx_r2r(pmagw, regs, regd)
+#define	pmagw(vars, vard)	mmx_m2m(pmagw, vars, vard)
+
+
+/*	4x16 Parallel ADDs using Saturation arithmetic
+	and Implied destination
+*/
+#define	paddsiw_m2ir(var, rs)		mmx_m2ir(paddsiw, var, rs)
+#define	paddsiw_r2ir(rs1, rs2)		mmx_r2ir(paddsiw, rs1, rs2)
+#define	paddsiw(vars, vard)		mmx_m2m(paddsiw, vars, vard)
+
+
+/*	4x16 Parallel SUBs using Saturation arithmetic
+	and Implied destination
+*/
+#define	psubsiw_m2ir(var, rs)		mmx_m2ir(psubsiw, var, rs)
+#define	psubsiw_r2ir(rs1, rs2)		mmx_r2ir(psubsiw, rs1, rs2)
+#define	psubsiw(vars, vard)		mmx_m2m(psubsiw, vars, vard)
+
+
+/*	4x16 Parallel MULs giving High 4x16 portions of results
+	Rounded with 1/2 bit 15.
+*/
+#define	pmulhrw_m2r(var, reg)	mmx_m2r(pmulhrw, var, reg)
+#define	pmulhrw_r2r(regs, regd)	mmx_r2r(pmulhrw, regs, regd)
+#define	pmulhrw(vars, vard)	mmx_m2m(pmulhrw, vars, vard)
+
+
+/*	4x16 Parallel MULs giving High 4x16 portions of results
+	Rounded with 1/2 bit 15, storing to Implied register
+*/
+#define	pmulhriw_m2ir(var, rs)		mmx_m2ir(pmulhriw, var, rs)
+#define	pmulhriw_r2ir(rs1, rs2)		mmx_r2ir(pmulhriw, rs1, rs2)
+#define	pmulhriw(vars, vard)		mmx_m2m(pmulhriw, vars, vard)
+
+
+/*	4x16 Parallel Muls (and ACcumulate) giving High 4x16 portions
+	of results Rounded with 1/2 bit 15, accumulating with Implied register
+*/
+#define	pmachriw_m2ir(var, rs)		mmx_m2ir(pmachriw, var, rs)
+#define	pmachriw_r2ir(rs1, rs2)		mmx_r2ir(pmachriw, rs1, rs2)
+#define	pmachriw(vars, vard)		mmx_m2m(pmachriw, vars, vard)
+
+
+/*	8x8u Parallel AVErage
+*/
+#define	paveb_m2r(var, reg)	mmx_m2r(paveb, var, reg)
+#define	paveb_r2r(regs, regd)	mmx_r2r(paveb, regs, regd)
+#define	paveb(vars, vard)	mmx_m2m(paveb, vars, vard)
+
+
+/*	8x8u Parallel DISTance and accumulate with
+	unsigned saturation to Implied register
+*/
+#define	pdistib_m2ir(var, rs)		mmx_m2ir(pdistib, var, rs)
+#define	pdistib(vars, vard)		mmx_m2m(pdistib, vars, vard)
+
+
+/*	8x8 Parallel conditional MoVe
+	if implied register field is Zero
+*/
+#define	pmvzb_m2ir(var, rs)		mmx_m2ir(pmvzb, var, rs)
+
+
+/*	8x8 Parallel conditional MoVe
+	if implied register field is Not Zero
+*/
+#define	pmvnzb_m2ir(var, rs)		mmx_m2ir(pmvnzb, var, rs)
+
+
+/*	8x8 Parallel conditional MoVe
+	if implied register field is Less than Zero
+*/
+#define	pmvlzb_m2ir(var, rs)		mmx_m2ir(pmvlzb, var, rs)
+
+
+/*	8x8 Parallel conditional MoVe
+	if implied register field is Greater than or Equal to Zero
+*/
+#define	pmvgezb_m2ir(var, rs)		mmx_m2ir(pmvgezb, var, rs)
+
+
+/*	Fast Empty MMx State
+	(used to clean-up when going from mmx to float use
+	 of the registers that are shared by both; note that
+	 there is no float-to-xmmx operation needed, because
+	 only the float tag word info is corruptible)
+*/
+#ifdef	XMMX_TRACE
+
+#define	femms() \
+	{ \
+		fprintf(stderr, "femms()\n"); \
+		__asm__ __volatile__ ("femms"); \
+	}
+
+#else
+
+#define	femms()			__asm__ __volatile__ ("femms")
+
+#endif
+
+#endif
+
diff --git a/gst/goom2k1/.gitignore b/gst/goom2k1/.gitignore
new file mode 100644
index 0000000..041d780
--- /dev/null
+++ b/gst/goom2k1/.gitignore
@@ -0,0 +1,8 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
+
diff --git a/gst/goom2k1/Makefile.am b/gst/goom2k1/Makefile.am
new file mode 100644
index 0000000..e75bb71
--- /dev/null
+++ b/gst/goom2k1/Makefile.am
@@ -0,0 +1,29 @@
+plugin_LTLIBRARIES = libgstgoom2k1.la
+
+GOOM_FILTER_FILES = filters.c
+GOOM_FILTER_CFLAGS = -UMMX -UUSE_ASM
+
+noinst_HEADERS = gstgoom.h filters.h goom_core.h goom_tools.h graphic.h lines.h
+
+libgstgoom2k1_la_SOURCES = gstgoom.c goom_core.c $(GOOM_FILTER_FILES) graphic.c \
+         lines.c
+
+libgstgoom2k1_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GOOM_FILTER_CFLAGS) \
+	-Dgst_goom_get_type=gst_goom2k1_get_type		\
+	-Dgoom_init=goom2k1_init				\
+	-Dgoom_close=goom2k1_close -Dgoom_update=goom2k1_update	\
+	-Dgoom_set_resolution=goom2k1_set_resolution		\
+	-Dgoom_lines=goom2k1_lines				\
+	-DBLACK=GOOM2K1_BLACK -DWHITE=GOOM2K1_WHITE		\
+	-DRED=GOOM2K1_RED -DBLUE=GOOM2K1_BLUE			\
+	-DGREEN=GOOM2K1_GREEN -DYELLOW=GOOM2K1_YELLOW		\
+	-DORANGE=GOOM2K1_ORANGE -DVIOLET=GOOM2K1_VIOLET		\
+	-DzoomFilterFastRGB=zoomFilterFastRGB2k1		\
+	-DpointFilter=pointFilter2k1				\
+	-DzoomFilterDestroy=zoomFilterDestroy2k1		\
+	-DzoomFilterNew=zoomFilterNew2k1
+
+libgstgoom2k1_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstpbutils-$(GST_API_VERSION) $(GST_BASE_LIBS) $(GST_LIBS) $(LIBM)
+libgstgoom2k1_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+EXTRA_DIST = filters.c
diff --git a/gst/goom2k1/README b/gst/goom2k1/README
new file mode 100644
index 0000000..f12cf1b
--- /dev/null
+++ b/gst/goom2k1/README
@@ -0,0 +1,5 @@
+The Goom plugin is based on the Goom visualization code from
+the Goom homepage found at: 
+http://ios.free.fr/?page=projet&quoi=1 
+
+Like the original library so is the Goom plugin available under the LGPL license
diff --git a/gst/goom2k1/filters.c b/gst/goom2k1/filters.c
new file mode 100644
index 0000000..3d1b92c
--- /dev/null
+++ b/gst/goom2k1/filters.c
@@ -0,0 +1,531 @@
+/* filter.c version 0.7
+ * contient les filtres applicable a un buffer
+ * creation : 01/10/2000
+ *  -ajout de sinFilter()
+ *  -ajout de zoomFilter()
+ *  -copie de zoomFilter() en zoomFilterRGB(), gérant les 3 couleurs
+ *  -optimisation de sinFilter (utilisant une table de sin)
+ *      -asm
+ *      -optimisation de la procedure de génération du buffer de transformation
+ *              la vitesse est maintenant comprise dans [0..128] au lieu de [0..100]
+*/
+
+/*#define _DEBUG_PIXEL; */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "filters.h"
+#include "graphic.h"
+#include "goom_tools.h"
+#include "goom_core.h"
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+
+#ifdef MMX
+#define USE_ASM
+#endif
+#ifdef POWERPC
+#define USE_ASM
+#endif
+
+#ifdef USE_ASM
+#define EFFECT_DISTORS 4
+#else
+#define EFFECT_DISTORS 10
+#endif
+
+
+#ifdef USE_ASM
+
+#ifdef MMX
+int mmx_zoom ();
+guint32 mmx_zoom_size;
+#endif /* MMX */
+
+#ifdef POWERPC
+extern unsigned int useAltivec;
+extern void ppc_zoom (void);
+extern void ppc_zoom_altivec (void);
+unsigned int ppcsize4;
+#endif /* PowerPC */
+
+
+unsigned int *coeffs = 0, *freecoeffs = 0;
+guint32 *expix1 = 0;            /* pointeur exporte vers p1 */
+guint32 *expix2 = 0;            /* pointeur exporte vers p2 */
+guint32 zoom_width;
+#endif /* ASM */
+
+
+static int firstTime = 1;
+static int sintable[0xffff];
+
+ZoomFilterData *
+zoomFilterNew (void)
+{
+  ZoomFilterData *zf = malloc (sizeof (ZoomFilterData));
+
+  zf->vitesse = 128;
+  zf->pertedec = 8;
+  zf->sqrtperte = 16;
+  zf->middleX = 1;
+  zf->middleY = 1;
+  zf->reverse = 0;
+  zf->mode = WAVE_MODE;
+  zf->hPlaneEffect = 0;
+  zf->vPlaneEffect = 0;
+  zf->noisify = 0;
+  zf->buffsize = 0;
+  zf->res_x = 0;
+  zf->res_y = 0;
+
+  zf->buffer = NULL;
+  zf->firedec = NULL;
+
+  zf->wave = 0;
+  zf->wavesp = 0;
+
+  return zf;
+}
+
+/* retourne x>>s , en testant le signe de x */
+static inline int
+ShiftRight (int x, const unsigned char s)
+{
+  if (x < 0)
+    return -(-x >> s);
+  else
+    return x >> s;
+}
+
+/*
+  calculer px et py en fonction de x,y,middleX,middleY et theMode
+  px et py indique la nouvelle position (en sqrtperte ieme de pixel)
+  (valeur * 16)
+*/
+static void
+calculatePXandPY (GoomData * gd, int x, int y, int *px, int *py)
+{
+  ZoomFilterData *zf = gd->zfd;
+  int middleX, middleY;
+  guint32 resoly = zf->res_y;
+  int vPlaneEffect = zf->vPlaneEffect;
+  int hPlaneEffect = zf->hPlaneEffect;
+  int vitesse = zf->vitesse;
+  char theMode = zf->mode;
+
+  if (theMode == WATER_MODE) {
+    int wavesp = zf->wavesp;
+    int wave = zf->wave;
+    int yy = y + RAND (gd) % 4 + wave / 10;
+
+    yy -= RAND (gd) % 4;
+    if (yy < 0)
+      yy = 0;
+    if (yy >= resoly)
+      yy = resoly - 1;
+
+    *px = (x << 4) + zf->firedec[yy] + (wave / 10);
+    *py = (y << 4) + 132 - ((vitesse < 132) ? vitesse : 131);
+
+    wavesp += RAND (gd) % 3;
+    wavesp -= RAND (gd) % 3;
+    if (wave < -10)
+      wavesp += 2;
+    if (wave > 10)
+      wavesp -= 2;
+    wave += (wavesp / 10) + RAND (gd) % 3;
+    wave -= RAND (gd) % 3;
+    if (wavesp > 100)
+      wavesp = (wavesp * 9) / 10;
+
+    zf->wavesp = wavesp;
+    zf->wave = wave;
+  } else {
+    int dist;
+    register int vx, vy;
+    int fvitesse = vitesse << 4;
+
+    middleX = zf->middleX;
+    middleY = zf->middleY;
+
+    if (zf->noisify) {
+      x += RAND (gd) % zf->noisify;
+      x -= RAND (gd) % zf->noisify;
+      y += RAND (gd) % zf->noisify;
+      y -= RAND (gd) % zf->noisify;
+    }
+
+    if (hPlaneEffect)
+      vx = ((x - middleX) << 9) + hPlaneEffect * (y - middleY);
+    else
+      vx = (x - middleX) << 9;
+
+    if (vPlaneEffect)
+      vy = ((y - middleY) << 9) + vPlaneEffect * (x - middleX);
+    else
+      vy = (y - middleY) << 9;
+
+    switch (theMode) {
+      case WAVE_MODE:
+        dist =
+            ShiftRight (vx, 9) * ShiftRight (vx, 9) + ShiftRight (vy,
+            9) * ShiftRight (vy, 9);
+        fvitesse *=
+            1024 +
+            ShiftRight (sintable[(unsigned short) (0xffff * dist *
+                    EFFECT_DISTORS)], 6);
+        fvitesse /= 1024;
+        break;
+      case CRYSTAL_BALL_MODE:
+        dist =
+            ShiftRight (vx, 9) * ShiftRight (vx, 9) + ShiftRight (vy,
+            9) * ShiftRight (vy, 9);
+        fvitesse += (dist * EFFECT_DISTORS >> 10);
+        break;
+      case AMULETTE_MODE:
+        dist =
+            ShiftRight (vx, 9) * ShiftRight (vx, 9) + ShiftRight (vy,
+            9) * ShiftRight (vy, 9);
+        fvitesse -= (dist * EFFECT_DISTORS >> 4);
+        break;
+      case SCRUNCH_MODE:
+        dist =
+            ShiftRight (vx, 9) * ShiftRight (vx, 9) + ShiftRight (vy,
+            9) * ShiftRight (vy, 9);
+        fvitesse -= (dist * EFFECT_DISTORS >> 9);
+        break;
+    }
+    if (vx < 0)
+      *px = (middleX << 4) - (-(vx * fvitesse) >> 16);
+    else
+      *px = (middleX << 4) + ((vx * fvitesse) >> 16);
+    if (vy < 0)
+      *py = (middleY << 4) - (-(vy * fvitesse) >> 16);
+    else
+      *py = (middleY << 4) + ((vy * fvitesse) >> 16);
+  }
+}
+
+/*#define _DEBUG */
+
+static inline void
+setPixelRGB (Uint * buffer, Uint x, Uint y, Color c,
+    guint32 resolx, guint32 resoly)
+{
+/*              buffer[ y*WIDTH + x ] = (c.r<<16)|(c.v<<8)|c.b */
+#ifdef _DEBUG_PIXEL
+  if (x + y * resolx >= resolx * resoly) {
+    fprintf (stderr, "setPixel ERROR : hors du tableau... %i, %i\n", x, y);
+    /*exit (1) ; */
+  }
+#endif
+
+#ifdef USE_DGA
+  buffer[y * resolx + x] = (c.b << 16) | (c.v << 8) | c.r;
+#else
+  buffer[y * resolx + x] = (c.r << 16) | (c.v << 8) | c.b;
+#endif
+}
+
+
+static inline void
+setPixelRGB_ (Uint * buffer, Uint x, Color c, guint32 resolx, guint32 resoly)
+{
+#ifdef _DEBUG
+  if (x >= resolx * resoly) {
+    printf ("setPixel ERROR : hors du tableau... %i >= %i*%i (%i)\n", x, resolx,
+        resoly, resolx * resoly);
+    exit (1);
+  }
+#endif
+
+#ifdef USE_DGA
+  buffer[x] = (c.b << 16) | (c.v << 8) | c.r;
+#else
+  buffer[x] = (c.r << 16) | (c.v << 8) | c.b;
+#endif
+}
+
+static inline void
+getPixelRGB_ (Uint * buffer, Uint x, Color * c, guint32 resolx, guint32 resoly)
+{
+  register unsigned char *tmp8;
+
+#ifdef _DEBUG
+  if (x >= resolx * resoly) {
+    printf ("getPixel ERROR : hors du tableau... %i\n", x);
+    exit (1);
+  }
+#endif
+
+#ifdef __BIG_ENDIAN__
+  c->b = *(unsigned char *) (tmp8 = (unsigned char *) (buffer + x));
+  c->r = *(unsigned char *) (++tmp8);
+  c->v = *(unsigned char *) (++tmp8);
+  c->b = *(unsigned char *) (++tmp8);
+
+#else
+  /* ATTENTION AU PETIT INDIEN  */
+  tmp8 = (unsigned char *) (buffer + x);
+  c->b = *(unsigned char *) (tmp8++);
+  c->v = *(unsigned char *) (tmp8++);
+  c->r = *(unsigned char *) (tmp8);
+/*      *c = (Color) buffer[x+y*WIDTH] ; */
+#endif
+}
+
+static void
+zoomFilterSetResolution (GoomData * gd, ZoomFilterData * zf)
+{
+  unsigned short us;
+
+  if (zf->buffsize >= gd->buffsize) {
+    zf->res_x = gd->resolx;
+    zf->res_y = gd->resoly;
+    zf->middleX = gd->resolx / 2;
+    zf->middleY = gd->resoly - 1;
+
+    return;
+  }
+#ifndef USE_ASM
+  if (zf->buffer)
+    free (zf->buffer);
+  zf->buffer = 0;
+#else
+  if (coeffs)
+    free (freecoeffs);
+  coeffs = 0;
+#endif
+  zf->middleX = gd->resolx / 2;
+  zf->middleY = gd->resoly - 1;
+  zf->res_x = gd->resolx;
+  zf->res_y = gd->resoly;
+
+  if (zf->firedec)
+    free (zf->firedec);
+  zf->firedec = 0;
+
+  zf->buffsize = gd->resolx * gd->resoly * sizeof (unsigned int);
+
+#ifdef USE_ASM
+  freecoeffs = (unsigned int *)
+      malloc (resx * resy * 2 * sizeof (unsigned int) + 128);
+  coeffs = (guint32 *) ((1 + ((unsigned int) (freecoeffs)) / 128) * 128);
+
+#else
+  zf->buffer = calloc (sizeof (guint32), zf->buffsize * 5);
+  zf->pos10 = zf->buffer;
+  zf->c[0] = zf->pos10 + zf->buffsize;
+  zf->c[1] = zf->c[0] + zf->buffsize;
+  zf->c[2] = zf->c[1] + zf->buffsize;
+  zf->c[3] = zf->c[2] + zf->buffsize;
+#endif
+  zf->firedec = (int *) malloc (zf->res_y * sizeof (int));
+
+  if (firstTime) {
+    firstTime = 0;
+
+    /* generation d'une table de sinus */
+    for (us = 0; us < 0xffff; us++) {
+      sintable[us] = (int) (1024.0f * sin (us * 2 * 3.31415f / 0xffff));
+    }
+  }
+}
+
+void
+zoomFilterDestroy (ZoomFilterData * zf)
+{
+  if (zf) {
+    if (zf->firedec)
+      free (zf->firedec);
+    if (zf->buffer)
+      free (zf->buffer);
+    free (zf);
+  }
+}
+
+/*===============================================================*/
+void
+zoomFilterFastRGB (GoomData * goomdata, ZoomFilterData * zf, int zfd_update)
+{
+  guint32 prevX = goomdata->resolx;
+  guint32 prevY = goomdata->resoly;
+
+  guint32 *pix1 = goomdata->p1;
+  guint32 *pix2 = goomdata->p2;
+  unsigned int *pos10;
+  unsigned int **c;
+
+  Uint x, y;
+
+/*  static unsigned int prevX = 0, prevY = 0; */
+
+#ifdef USE_ASM
+  expix1 = pix1;
+  expix2 = pix2;
+#else
+  Color couleur;
+  Color col1, col2, col3, col4;
+  Uint position;
+#endif
+
+  if ((goomdata->resolx != zf->res_x) || (goomdata->resoly != zf->res_y)) {
+    zoomFilterSetResolution (goomdata, zf);
+  }
+
+  pos10 = zf->pos10;
+  c = zf->c;
+
+  if (zfd_update) {
+    guchar sqrtperte = zf->sqrtperte;
+    gint start_y = 0;
+
+    if (zf->reverse)
+      zf->vitesse = 256 - zf->vitesse;
+
+    /* generation du buffer */
+    for (y = 0; y < zf->res_y; y++) {
+      gint y_16 = y << 4;
+      gint max_px = (prevX - 1) * sqrtperte;
+      gint max_py = (prevY - 1) * sqrtperte;
+
+      for (x = 0; x < zf->res_x; x++) {
+        gint px, py;
+        guchar coefv, coefh;
+
+        /* calculer px et py en fonction de */
+        /*   x,y,middleX,middleY et theMode */
+        calculatePXandPY (goomdata, x, y, &px, &py);
+
+        if ((px == x << 4) && (py == y_16))
+          py += 8;
+
+        if ((py < 0) || (px < 0) || (py >= max_py) || (px >= max_px)) {
+#ifdef USE_ASM
+          coeffs[(y * prevX + x) * 2] = 0;
+          coeffs[(y * prevX + x) * 2 + 1] = 0;
+#else
+          pos10[start_y + x] = 0;
+          c[0][start_y + x] = 0;
+          c[1][start_y + x] = 0;
+          c[2][start_y + x] = 0;
+          c[3][start_y + x] = 0;
+#endif
+        } else {
+          int npx10;
+          int npy10;
+          int pos;
+
+          npx10 = (px / sqrtperte);
+          npy10 = (py / sqrtperte);
+
+/*                        if (npx10 >= prevX) fprintf(stderr,"error npx:%d",npx10);
+                          if (npy10 >= prevY) fprintf(stderr,"error npy:%d",npy10);
+*/
+          coefh = px % sqrtperte;
+          coefv = py % sqrtperte;
+#ifdef USE_ASM
+          pos = (y * prevX + x) * 2;
+          coeffs[pos] = (npx10 + prevX * npy10) * 4;
+
+          if (!(coefh || coefv))
+            coeffs[pos + 1] = (sqrtperte * sqrtperte - 1);
+          else
+            coeffs[pos + 1] = ((sqrtperte - coefh) * (sqrtperte - coefv));
+
+          coeffs[pos + 1] |= (coefh * (sqrtperte - coefv)) << 8;
+          coeffs[pos + 1] |= ((sqrtperte - coefh) * coefv) << 16;
+          coeffs[pos + 1] |= (coefh * coefv) << 24;
+#else
+          pos = start_y + x;
+          pos10[pos] = npx10 + prevX * npy10;
+
+          if (!(coefh || coefv))
+            c[0][pos] = sqrtperte * sqrtperte - 1;
+          else
+            c[0][pos] = (sqrtperte - coefh) * (sqrtperte - coefv);
+
+          c[1][pos] = coefh * (sqrtperte - coefv);
+          c[2][pos] = (sqrtperte - coefh) * coefv;
+          c[3][pos] = coefh * coefv;
+#endif
+        }
+      }
+      /* Advance start of line index */
+      start_y += prevX;
+    }
+  }
+#ifdef USE_ASM
+#ifdef MMX
+  zoom_width = prevX;
+  mmx_zoom_size = prevX * prevY;
+  mmx_zoom ();
+#endif
+
+#ifdef POWERPC
+  zoom_width = prevX;
+  if (useAltivec) {
+    ppcsize4 = ((unsigned int) (prevX * prevY)) / 4;
+    ppc_zoom_altivec ();
+  } else {
+    ppcsize4 = ((unsigned int) (prevX * prevY));
+    ppc_zoom ();
+  }
+#endif
+#else
+  for (position = 0; position < prevX * prevY; position++) {
+    getPixelRGB_ (pix1, pos10[position], &col1, goomdata->resolx,
+        goomdata->resoly);
+    getPixelRGB_ (pix1, pos10[position] + 1, &col2, goomdata->resolx,
+        goomdata->resoly);
+    getPixelRGB_ (pix1, pos10[position] + prevX, &col3, goomdata->resolx,
+        goomdata->resoly);
+    getPixelRGB_ (pix1, pos10[position] + prevX + 1, &col4, goomdata->resolx,
+        goomdata->resoly);
+
+    couleur.r = col1.r * c[0][position]
+        + col2.r * c[1][position]
+        + col3.r * c[2][position]
+        + col4.r * c[3][position];
+    couleur.r >>= zf->pertedec;
+
+    couleur.v = col1.v * c[0][position]
+        + col2.v * c[1][position]
+        + col3.v * c[2][position]
+        + col4.v * c[3][position];
+    couleur.v >>= zf->pertedec;
+
+    couleur.b = col1.b * c[0][position]
+        + col2.b * c[1][position]
+        + col3.b * c[2][position]
+        + col4.b * c[3][position];
+    couleur.b >>= zf->pertedec;
+
+    setPixelRGB_ (pix2, position, couleur, goomdata->resolx, goomdata->resoly);
+  }
+#endif
+}
+
+
+void
+pointFilter (GoomData * goomdata, Color c,
+    float t1, float t2, float t3, float t4, Uint cycle)
+{
+  Uint *pix1 = goomdata->p1;
+  ZoomFilterData *zf = goomdata->zfd;
+  Uint x = (Uint) (zf->middleX + (int) (t1 * cos ((float) cycle / t3)));
+  Uint y = (Uint) (zf->middleY + (int) (t2 * sin ((float) cycle / t4)));
+
+  if ((x > 1) && (y > 1) && (x < goomdata->resolx - 2)
+      && (y < goomdata->resoly - 2)) {
+    setPixelRGB (pix1, x + 1, y, c, goomdata->resolx, goomdata->resoly);
+    setPixelRGB (pix1, x, y + 1, c, goomdata->resolx, goomdata->resoly);
+    setPixelRGB (pix1, x + 1, y + 1, WHITE, goomdata->resolx, goomdata->resoly);
+    setPixelRGB (pix1, x + 2, y + 1, c, goomdata->resolx, goomdata->resoly);
+    setPixelRGB (pix1, x + 1, y + 2, c, goomdata->resolx, goomdata->resoly);
+  }
+}
diff --git a/gst/goom2k1/filters.h b/gst/goom2k1/filters.h
new file mode 100644
index 0000000..102004b
--- /dev/null
+++ b/gst/goom2k1/filters.h
@@ -0,0 +1,83 @@
+#ifndef FILTERS_H
+#define FILTERS_H
+
+#include <glib.h>
+
+#include "graphic.h"
+#include "goom_core.h"
+
+#define NORMAL_MODE 0
+#define WAVE_MODE 1
+#define CRYSTAL_BALL_MODE 2
+#define SCRUNCH_MODE 3
+#define AMULETTE_MODE 4
+#define WATER_MODE 5
+
+struct ZoomFilterData
+{
+  int vitesse;
+  unsigned char pertedec;
+  unsigned char sqrtperte;
+  int middleX;
+  int middleY;
+  char reverse;
+  char mode;
+        /** @since June 2001 */
+  int hPlaneEffect;
+  int vPlaneEffect;
+  char noisify;
+
+  guint32 res_x;
+  guint32 res_y;
+  guint32 buffsize;
+
+  guint32 *buffer;
+  guint32 *pos10;
+  guint32 *c[4];
+  int     *firedec;
+
+  int     wave;
+  int     wavesp;
+};
+
+void pointFilter(GoomData *goomdata, Color c,
+                                 float t1, float t2, float t3, float t4,
+                                 guint32 cycle);
+
+/* filtre de zoom :
+ le contenu de pix1 est copie dans pix2, avec l'effet appliqué
+ midx et midy represente le centre du zoom
+
+void zoomFilter(Uint *pix1, Uint *pix2, Uint middleX, Uint middleY);
+void zoomFilterRGB(Uint *pix1,
+Uint *pix2,
+Uint middleX,
+Uint middleY);
+*/
+
+ZoomFilterData *zoomFilterNew (void);
+void zoomFilterDestroy (ZoomFilterData *zf);
+void zoomFilterFastRGB (GoomData *goomdata, ZoomFilterData *zf,
+                           int zfd_update);
+
+/* filtre sin :
+ le contenu de pix1 est copie dans pix2, avec l'effet appliqué
+ cycle est la variable de temps.
+ mode vaut SIN_MUL ou SIN_ADD
+ rate est le pourcentage de l'effet appliqué
+ lenght : la longueur d'onde (1..10) [5]
+ speed : la vitesse (1..100) [10]
+*/
+/*
+void sinFilter(Uint *pix1,Uint *pix2,
+                           Uint cycle,
+                           Uint mode,
+                           Uint rate,
+                           char lenght,
+                           Uint speed);
+*/
+
+#define SIN_MUL 1
+#define SIN_ADD 2
+
+#endif
diff --git a/gst/goom2k1/filters_mmx.s b/gst/goom2k1/filters_mmx.s
new file mode 100644
index 0000000..337de56
--- /dev/null
+++ b/gst/goom2k1/filters_mmx.s
@@ -0,0 +1,130 @@
+;// file : mmx_zoom.s
+;// author : JC Hoelt <jeko@free.fr>
+;//
+;// history
+;// 07/01/2001 : Changing FEMMS to EMMS : slower... but run on intel machines
+;//	03/01/2001 : WIDTH and HEIGHT are now variable
+;//	28/12/2000 : adding comments to the code, suppress some useless lines
+;//	27/12/2000 : reducing memory access... improving performance by 20%
+;//		coefficients are now on 1 byte
+;//	22/12/2000 : Changing data structure
+;//	16/12/2000 : AT&T version
+;//	14/12/2000 : unrolling loop
+;//	12/12/2000 : 64 bits memory access
+
+
+.data
+
+thezero:
+	.long 0x00000000
+	.long 0x00000000
+
+
+.text
+
+.globl mmx_zoom		;// name of the function to call by C program
+.extern coeffs		;// the transformation buffer
+.extern expix1,expix2 ;// the source and destination buffer
+.extern mmx_zoom_size, zoom_width ;// size of the buffers
+
+.align 16
+mmx_zoom:
+
+push %ebp
+push %esp
+
+;// initialisation du mm7 à zero
+movq (thezero), %mm7
+
+movl zoom_width, %eax
+movl $4, %ebx
+mull %ebx
+movl %eax, %ebp
+
+movl (coeffs), %eax
+movl (expix1), %edx
+movl (expix2), %ebx
+movl $10, %edi
+movl mmx_zoom_size, %ecx
+
+.while:
+	;// esi <- nouvelle position
+	movl (%eax), %esi
+	leal (%edx, %esi), %esi
+
+	;// recuperation des deux premiers pixels dans mm0 et mm1
+	movq (%esi), %mm0		/* b1-v1-r1-a1-b2-v2-r2-a2 */
+	movq %mm0, %mm1			/* b1-v1-r1-a1-b2-v2-r2-a2 */
+
+	;// recuperation des 4 coefficients
+	movd 4(%eax), %mm6		/* ??-??-??-??-c4-c3-c2-c1 */
+	;// depackage du premier pixel
+	punpcklbw %mm7, %mm0	/* 00-b2-00-v2-00-r2-00-a2 */
+
+	movq %mm6, %mm5			/* ??-??-??-??-c4-c3-c2-c1 */
+	;// depackage du 2ieme pixel
+	punpckhbw %mm7, %mm1	/* 00-b1-00-v1-00-r1-00-a1 */
+
+	;// extraction des coefficients...
+	punpcklbw %mm5, %mm6	/* c4-c4-c3-c3-c2-c2-c1-c1 */
+	movq %mm6, %mm4			/* c4-c4-c3-c3-c2-c2-c1-c1 */
+	movq %mm6, %mm5			/* c4-c4-c3-c3-c2-c2-c1-c1 */
+
+	punpcklbw %mm5, %mm6	/* c2-c2-c2-c2-c1-c1-c1-c1 */
+	punpckhbw %mm5, %mm4	/* c4-c4-c4-c4-c3-c3-c3-c3 */
+
+	movq %mm6, %mm3			/* c2-c2-c2-c2-c1-c1-c1-c1 */
+	punpcklbw %mm7, %mm6	/* 00-c1-00-c1-00-c1-00-c1 */
+	punpckhbw %mm7, %mm3	/* 00-c2-00-c2-00-c2-00-c2 */
+	
+	;// multiplication des pixels par les coefficients
+	pmullw %mm6, %mm0		/* c1*b2-c1*v2-c1*r2-c1*a2 */
+	pmullw %mm3, %mm1		/* c2*b1-c2*v1-c2*r1-c2*a1 */
+	paddw %mm1, %mm0
+	
+	;// ...extraction des 2 derniers coefficients
+	movq %mm4, %mm5			/* c4-c4-c4-c4-c3-c3-c3-c3 */
+	punpcklbw %mm7, %mm4	/* 00-c3-00-c3-00-c3-00-c3 */
+	punpckhbw %mm7, %mm5	/* 00-c4-00-c4-00-c4-00-c4 */
+
+	;// recuperation des 2 derniers pixels
+	movq (%esi,%ebp), %mm1
+	movq %mm1, %mm2
+	
+	;// depackage des pixels
+	punpcklbw %mm7, %mm1
+	punpckhbw %mm7, %mm2
+	
+	;// multiplication pas les coeffs
+	pmullw %mm4, %mm1
+	pmullw %mm5, %mm2
+	
+	;// ajout des valeurs obtenues à la valeur finale
+	paddw %mm1, %mm0
+	paddw %mm2, %mm0
+
+	;// division par 256 = 16+16+16+16, puis repackage du pixel final
+	psrlw $8, %mm0
+	packuswb %mm7, %mm0
+	
+	;// passage au suivant
+	leal 8(%eax), %eax
+
+	decl %ecx
+	;// enregistrement du resultat
+	movd %mm0, (%ebx)
+	leal 4(%ebx), %ebx
+
+	;// test de fin du tantque
+	cmpl $0, %ecx				;// 400x300
+
+jz .fin_while
+jmp .while
+
+.fin_while:
+emms
+
+pop %esp
+pop %ebp
+
+ret                  ;//The End
diff --git a/gst/goom2k1/goom_core.c b/gst/goom2k1/goom_core.c
new file mode 100644
index 0000000..abe6470
--- /dev/null
+++ b/gst/goom2k1/goom_core.c
@@ -0,0 +1,411 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <glib.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include "goom_core.h"
+#include "goom_tools.h"
+#include "filters.h"
+#include "lines.h"
+
+/*#define VERBOSE */
+
+#ifdef VERBOSE
+#include <stdio.h>
+#endif
+
+#define STOP_SPEED 128
+
+void
+goom_init (GoomData * goomdata, guint32 resx, guint32 resy)
+{
+#ifdef VERBOSE
+  printf ("GOOM: init (%d, %d);\n", resx, resy);
+#endif
+  goomdata->resolx = 0;
+  goomdata->resoly = 0;
+  goomdata->buffsize = 0;
+
+  goomdata->pixel = NULL;
+  goomdata->back = NULL;
+  goomdata->p1 = NULL;
+  goomdata->p2 = NULL;
+
+  goom_set_resolution (goomdata, resx, resy);
+  RAND_INIT (goomdata, GPOINTER_TO_INT (goomdata->pixel));
+  goomdata->cycle = 0;
+
+
+  goomdata->goomlimit = 2;      /* sensibilité du goom */
+  goomdata->zfd = zoomFilterNew ();
+  goomdata->lockvar = 0;        /* pour empecher de nouveaux changements */
+  goomdata->goomvar = 0;        /* boucle des gooms */
+  goomdata->totalgoom = 0;      /* nombre de gooms par seconds */
+  goomdata->agoom = 0;          /* un goom a eu lieu..       */
+  goomdata->loopvar = 0;        /* mouvement des points */
+  goomdata->speedvar = 0;       /* vitesse des particules */
+  goomdata->lineMode = 0;       /* l'effet lineaire a dessiner */
+}
+
+void
+goom_set_resolution (GoomData * goomdata, guint32 resx, guint32 resy)
+{
+  guint32 buffsize = resx * resy;
+
+  if ((goomdata->resolx == resx) && (goomdata->resoly == resy))
+    return;
+
+  if (goomdata->buffsize < buffsize) {
+    if (goomdata->pixel)
+      free (goomdata->pixel);
+    if (goomdata->back)
+      free (goomdata->back);
+    goomdata->pixel = (guint32 *) malloc (buffsize * sizeof (guint32) + 128);
+    goomdata->back = (guint32 *) malloc (buffsize * sizeof (guint32) + 128);
+    goomdata->buffsize = buffsize;
+
+    goomdata->p1 = (void *) (((guintptr) goomdata->pixel + 0x7f) & (~0x7f));
+    goomdata->p2 = (void *) (((guintptr) goomdata->back + 0x7f) & (~0x7f));
+  }
+
+  goomdata->resolx = resx;
+  goomdata->resoly = resy;
+
+  memset (goomdata->pixel, 0, buffsize * sizeof (guint32) + 128);
+  memset (goomdata->back, 0, buffsize * sizeof (guint32) + 128);
+}
+
+guint32 *
+goom_update (GoomData * goomdata, gint16 data[2][512])
+{
+  guint32 *return_val;
+  guint32 pointWidth;
+  guint32 pointHeight;
+  int incvar;                   /* volume du son */
+  int accelvar;                 /* acceleration des particules */
+  int i;
+  float largfactor;             /* elargissement de l'intervalle d'évolution des points */
+  int zfd_update = 0;
+  int resolx = goomdata->resolx;
+  int resoly = goomdata->resoly;
+  ZoomFilterData *pzfd = goomdata->zfd;
+  guint32 *tmp;
+
+  /* test if the config has changed, update it if so */
+
+  pointWidth = (resolx * 2) / 5;
+  pointHeight = (resoly * 2) / 5;
+
+  /* ! etude du signal ... */
+  incvar = 0;
+  for (i = 0; i < 512; i++) {
+    if (incvar < data[0][i])
+      incvar = data[0][i];
+  }
+
+  accelvar = incvar / 5000;
+  if (goomdata->speedvar > 5) {
+    accelvar--;
+    if (goomdata->speedvar > 20)
+      accelvar--;
+    if (goomdata->speedvar > 40)
+      goomdata->speedvar = 40;
+  }
+  accelvar--;
+  goomdata->speedvar += accelvar;
+
+  if (goomdata->speedvar < 0)
+    goomdata->speedvar = 0;
+  if (goomdata->speedvar > 40)
+    goomdata->speedvar = 40;
+
+
+  /* ! calcul du deplacement des petits points ... */
+
+  largfactor =
+      ((float) goomdata->speedvar / 40.0f + (float) incvar / 50000.0f) / 1.5f;
+  if (largfactor > 1.5f)
+    largfactor = 1.5f;
+
+  for (i = 1; i * 15 <= goomdata->speedvar + 15; i++) {
+    goomdata->loopvar += goomdata->speedvar + 1;
+
+    pointFilter (goomdata,
+        YELLOW,
+        ((pointWidth - 6.0f) * largfactor + 5.0f),
+        ((pointHeight - 6.0f) * largfactor + 5.0f),
+        i * 152.0f, 128.0f, goomdata->loopvar + i * 2032);
+    pointFilter (goomdata, ORANGE,
+        ((pointWidth / 2) * largfactor) / i + 10.0f * i,
+        ((pointHeight / 2) * largfactor) / i + 10.0f * i,
+        96.0f, i * 80.0f, goomdata->loopvar / i);
+    pointFilter (goomdata, VIOLET,
+        ((pointHeight / 3 + 5.0f) * largfactor) / i + 10.0f * i,
+        ((pointHeight / 3 + 5.0f) * largfactor) / i + 10.0f * i,
+        i + 122.0f, 134.0f, goomdata->loopvar / i);
+    pointFilter (goomdata, BLACK,
+        ((pointHeight / 3) * largfactor + 20.0f),
+        ((pointHeight / 3) * largfactor + 20.0f),
+        58.0f, i * 66.0f, goomdata->loopvar / i);
+    pointFilter (goomdata, WHITE,
+        (pointHeight * largfactor + 10.0f * i) / i,
+        (pointHeight * largfactor + 10.0f * i) / i,
+        66.0f, 74.0f, goomdata->loopvar + i * 500);
+  }
+
+  /* diminuer de 1 le temps de lockage */
+  /* note pour ceux qui n'ont pas suivis : le lockvar permet d'empecher un */
+  /* changement d'etat du plugins juste apres un autre changement d'etat. oki ? */
+  if (--goomdata->lockvar < 0)
+    goomdata->lockvar = 0;
+
+  /* temps du goom */
+  if (--goomdata->agoom < 0)
+    goomdata->agoom = 0;
+
+  /* on verifie qu'il ne se pas un truc interressant avec le son. */
+  if ((accelvar > goomdata->goomlimit) || (accelvar < -goomdata->goomlimit)) {
+    /* UN GOOM !!! YAHOO ! */
+    goomdata->totalgoom++;
+    goomdata->agoom = 20;       /* mais pdt 20 cycles, il n'y en aura plus. */
+    goomdata->lineMode = (goomdata->lineMode + 1) % 20; /* Tous les 10 gooms on change de mode lineaire */
+
+    /* changement eventuel de mode */
+    switch (iRAND (goomdata, 10)) {
+      case 0:
+      case 1:
+      case 2:
+        pzfd->mode = WAVE_MODE;
+        pzfd->vitesse = STOP_SPEED - 1;
+        pzfd->reverse = 0;
+        break;
+      case 3:
+      case 4:
+        pzfd->mode = CRYSTAL_BALL_MODE;
+        break;
+      case 5:
+        pzfd->mode = AMULETTE_MODE;
+        break;
+      case 6:
+        pzfd->mode = WATER_MODE;
+        break;
+      case 7:
+        pzfd->mode = SCRUNCH_MODE;
+        break;
+      default:
+        pzfd->mode = NORMAL_MODE;
+    }
+  }
+
+  /* tout ceci ne sera fait qu'en cas de non-blocage */
+  if (goomdata->lockvar == 0) {
+    /* reperage de goom (acceleration forte de l'acceleration du volume) */
+    /* -> coup de boost de la vitesse si besoin.. */
+    if ((accelvar > goomdata->goomlimit) || (accelvar < -goomdata->goomlimit)) {
+      goomdata->goomvar++;
+      /*if (goomvar % 1 == 0) */
+      {
+        guint32 vtmp;
+        guint32 newvit;
+
+        newvit = STOP_SPEED - goomdata->speedvar / 2;
+        /* retablir le zoom avant.. */
+        if ((pzfd->reverse) && (!(goomdata->cycle % 12)) && (rand () % 3 == 0)) {
+          pzfd->reverse = 0;
+          pzfd->vitesse = STOP_SPEED - 2;
+          goomdata->lockvar = 50;
+        }
+        if (iRAND (goomdata, 10) == 0) {
+          pzfd->reverse = 1;
+          goomdata->lockvar = 100;
+        }
+
+        /* changement de milieu.. */
+        switch (iRAND (goomdata, 20)) {
+          case 0:
+            pzfd->middleY = resoly - 1;
+            pzfd->middleX = resolx / 2;
+            break;
+          case 1:
+            pzfd->middleX = resolx - 1;
+            break;
+          case 2:
+            pzfd->middleX = 1;
+            break;
+          default:
+            pzfd->middleY = resoly / 2;
+            pzfd->middleX = resolx / 2;
+        }
+
+        if (pzfd->mode == WATER_MODE) {
+          pzfd->middleX = resolx / 2;
+          pzfd->middleY = resoly / 2;
+        }
+
+        switch (vtmp = (iRAND (goomdata, 27))) {
+          case 0:
+            pzfd->vPlaneEffect = iRAND (goomdata, 3);
+            pzfd->vPlaneEffect -= iRAND (goomdata, 3);
+            pzfd->hPlaneEffect = iRAND (goomdata, 3);
+            pzfd->hPlaneEffect -= iRAND (goomdata, 3);
+            break;
+          case 3:
+            pzfd->vPlaneEffect = 0;
+            pzfd->hPlaneEffect = iRAND (goomdata, 8);
+            pzfd->hPlaneEffect -= iRAND (goomdata, 8);
+            break;
+          case 4:
+          case 5:
+          case 6:
+          case 7:
+            pzfd->vPlaneEffect = iRAND (goomdata, 5);
+            pzfd->vPlaneEffect -= iRAND (goomdata, 5);
+            pzfd->hPlaneEffect = -pzfd->vPlaneEffect;
+            break;
+          case 8:
+            pzfd->hPlaneEffect = 5 + iRAND (goomdata, 8);
+            pzfd->vPlaneEffect = -pzfd->hPlaneEffect;
+            break;
+          case 9:
+            pzfd->vPlaneEffect = 5 + iRAND (goomdata, 8);
+            pzfd->hPlaneEffect = -pzfd->hPlaneEffect;
+            break;
+          case 13:
+            pzfd->hPlaneEffect = 0;
+            pzfd->vPlaneEffect = iRAND (goomdata, 10);
+            pzfd->vPlaneEffect -= iRAND (goomdata, 10);
+            break;
+          default:
+            if (vtmp < 10) {
+              pzfd->vPlaneEffect = 0;
+              pzfd->hPlaneEffect = 0;
+            }
+        }
+
+        if (iRAND (goomdata, 3) != 0)
+          pzfd->noisify = 0;
+        else {
+          pzfd->noisify = iRAND (goomdata, 3) + 2;
+          goomdata->lockvar *= 3;
+        }
+
+        if (pzfd->mode == AMULETTE_MODE) {
+          pzfd->vPlaneEffect = 0;
+          pzfd->hPlaneEffect = 0;
+          pzfd->noisify = 0;
+        }
+
+        if ((pzfd->middleX == 1) || (pzfd->middleX == resolx - 1)) {
+          pzfd->vPlaneEffect = 0;
+          pzfd->hPlaneEffect = iRAND (goomdata, 2) ? 0 : pzfd->hPlaneEffect;
+        }
+
+        if (newvit < pzfd->vitesse) {   /* on accelere */
+          zfd_update = 1;
+          if (((newvit < STOP_SPEED - 7) &&
+                  (pzfd->vitesse < STOP_SPEED - 6) &&
+                  (goomdata->cycle % 3 == 0)) || (iRAND (goomdata, 40) == 0)) {
+            pzfd->vitesse = STOP_SPEED - 1;
+            pzfd->reverse = !pzfd->reverse;
+          } else {
+            pzfd->vitesse = (newvit + pzfd->vitesse * 4) / 5;
+          }
+          goomdata->lockvar += 50;
+        }
+      }
+    }
+    /* mode mega-lent */
+    if (iRAND (goomdata, 1000) == 0) {
+      /* 
+         printf ("coup du sort...\n") ;
+       */
+      zfd_update = 1;
+      pzfd->vitesse = STOP_SPEED - 1;
+      pzfd->pertedec = 8;
+      pzfd->sqrtperte = 16;
+      goomdata->goomvar = 1;
+      goomdata->lockvar += 70;
+    }
+  }
+
+  /* gros frein si la musique est calme */
+  if ((goomdata->speedvar < 1) && (pzfd->vitesse < STOP_SPEED - 4)
+      && (goomdata->cycle % 16 == 0)) {
+    /*
+       printf ("++slow part... %i\n", zfd.vitesse) ;
+     */
+    zfd_update = 1;
+    pzfd->vitesse += 3;
+    pzfd->pertedec = 8;
+    pzfd->sqrtperte = 16;
+    goomdata->goomvar = 0;
+    /*
+       printf ("--slow part... %i\n", zfd.vitesse) ;
+     */
+  }
+
+  /* baisser regulierement la vitesse... */
+  if ((goomdata->cycle % 73 == 0) && (pzfd->vitesse < STOP_SPEED - 5)) {
+    /*
+       printf ("slow down...\n") ;
+     */
+    zfd_update = 1;
+    pzfd->vitesse++;
+  }
+
+  /* arreter de decrémenter au bout d'un certain temps */
+  if ((goomdata->cycle % 101 == 0) && (pzfd->pertedec == 7)) {
+    zfd_update = 1;
+    pzfd->pertedec = 8;
+    pzfd->sqrtperte = 16;
+  }
+
+  /* Zoom here ! */
+  zoomFilterFastRGB (goomdata, pzfd, zfd_update);
+
+  /* si on est dans un goom : afficher les lignes... */
+  if (goomdata->agoom > 15)
+    goom_lines (goomdata, data, ((pzfd->middleX == resolx / 2)
+            && (pzfd->middleY == resoly / 2)
+            && (pzfd->mode != WATER_MODE))
+        ? (goomdata->lineMode / 10) : 0, goomdata->p2, goomdata->agoom - 15);
+
+  return_val = goomdata->p2;
+  tmp = goomdata->p1;
+  goomdata->p1 = goomdata->p2;
+  goomdata->p2 = tmp;
+
+  /* affichage et swappage des buffers.. */
+  goomdata->cycle++;
+
+  /* tous les 100 cycles : vérifier si le taux de goom est correct */
+  /* et le modifier sinon.. */
+  if (!(goomdata->cycle % 100)) {
+    if (goomdata->totalgoom > 15) {
+      /*  printf ("less gooms\n") ; */
+      goomdata->goomlimit++;
+    } else {
+      if ((goomdata->totalgoom == 0) && (goomdata->goomlimit > 1))
+        goomdata->goomlimit--;
+    }
+    goomdata->totalgoom = 0;
+  }
+  return return_val;
+}
+
+void
+goom_close (GoomData * goomdata)
+{
+  if (goomdata->pixel != NULL)
+    free (goomdata->pixel);
+  if (goomdata->back != NULL)
+    free (goomdata->back);
+  if (goomdata->zfd != NULL) {
+    zoomFilterDestroy (goomdata->zfd);
+    goomdata->zfd = NULL;
+  }
+  goomdata->pixel = goomdata->back = NULL;
+  RAND_CLOSE (goomdata);
+}
diff --git a/gst/goom2k1/goom_core.h b/gst/goom2k1/goom_core.h
new file mode 100644
index 0000000..1fbc0ee
--- /dev/null
+++ b/gst/goom2k1/goom_core.h
@@ -0,0 +1,43 @@
+#ifndef _GOOMCORE_H
+#define _GOOMCORE_H
+
+#include <glib.h>
+
+typedef struct ZoomFilterData ZoomFilterData;
+
+typedef struct
+{
+/**-----------------------------------------------------**
+ **  SHARED DATA                                        **
+ **-----------------------------------------------------**/
+  guint32 *pixel;
+  guint32 *back;
+  guint32 *p1, *p2;
+  guint32 cycle;
+
+  guint32 resolx, resoly, buffsize;
+
+  int lockvar;       /* pour empecher de nouveaux changements */
+  int goomvar;       /* boucle des gooms */
+  int totalgoom;     /* nombre de gooms par seconds */
+  int agoom;         /* un goom a eu lieu..       */
+  int loopvar;       /* mouvement des points */
+  int speedvar;      /* vitesse des particules */
+  int lineMode;      /* l'effet lineaire a dessiner */
+  char goomlimit;    /* sensibilité du goom */
+
+  ZoomFilterData *zfd;
+  
+  /* Random table */
+  gint  *rand_tab;
+  guint  rand_pos;
+} GoomData;
+
+void goom_init (GoomData *goomdata, guint32 resx, guint32 resy);
+void goom_set_resolution (GoomData *goomdata, guint32 resx, guint32 resy);
+
+guint32 *goom_update (GoomData *goomdata, gint16 data [2][512]);
+
+void goom_close (GoomData *goomdata);
+
+#endif
diff --git a/gst/goom2k1/goom_tools.h b/gst/goom2k1/goom_tools.h
new file mode 100644
index 0000000..6178dba
--- /dev/null
+++ b/gst/goom2k1/goom_tools.h
@@ -0,0 +1,24 @@
+#ifndef _GOOMTOOLS_H
+#define _GOOMTOOLS_H
+
+#define NB_RAND 0x10000
+
+#define RAND_INIT(gd,i) \
+        srand (i); \
+        if (gd->rand_tab == NULL) \
+                gd->rand_tab = g_malloc (NB_RAND * sizeof(gint)) ;\
+        gd->rand_pos = 0; \
+        while (gd->rand_pos < NB_RAND) \
+                gd->rand_tab [gd->rand_pos++] = rand ();
+
+#define RAND(gd) \
+        (gd->rand_tab[gd->rand_pos = ((gd->rand_pos + 1) % NB_RAND)])
+
+#define RAND_CLOSE(gd) \
+        g_free (gd->rand_tab); \
+        gd->rand_tab = NULL;
+
+/*#define iRAND(i) ((guint32)((float)i * RAND()/RAND_MAX)) */
+#define iRAND(gd,i) (RAND(gd) % i)
+        
+#endif
diff --git a/gst/goom2k1/graphic.c b/gst/goom2k1/graphic.c
new file mode 100644
index 0000000..c20f987
--- /dev/null
+++ b/gst/goom2k1/graphic.c
@@ -0,0 +1,14 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "graphic.h"
+
+const Color BLACK = { 0, 0, 0 };
+const Color WHITE = { 0xff, 0xff, 0xff };
+const Color RED = { 0xff, 0, 0 };
+const Color GREEN = { 0, 0xff, 0 };
+const Color BLUE = { 0, 0, 0xff };
+const Color YELLOW = { 0xff, 0xff, 0x33 };
+const Color ORANGE = { 0xff, 0xcc, 0x00 };
+const Color VIOLET = { 0x55, 0x00, 0xff };
diff --git a/gst/goom2k1/graphic.h b/gst/goom2k1/graphic.h
new file mode 100644
index 0000000..4154d7f
--- /dev/null
+++ b/gst/goom2k1/graphic.h
@@ -0,0 +1,23 @@
+#ifndef GRAPHIC_H
+#define GRAPHIC_H
+
+#include <glib.h>  /* defines inline for better portability */
+
+typedef unsigned int Uint;
+
+typedef struct
+{
+  unsigned short r,v,b;
+}
+Color;
+
+extern const Color BLACK;
+extern const Color WHITE;
+extern const Color RED;
+extern const Color BLUE;
+extern const Color GREEN;
+extern const Color YELLOW;
+extern const Color ORANGE;
+extern const Color VIOLET;
+
+#endif /*GRAPHIC_H*/
diff --git a/gst/goom2k1/gstgoom.c b/gst/goom2k1/gstgoom.c
new file mode 100644
index 0000000..cfbfcbc
--- /dev/null
+++ b/gst/goom2k1/gstgoom.c
@@ -0,0 +1,193 @@
+/* gstgoom.c: implementation of goom drawing element
+ * Copyright (C) <2001> Richard Boulton <richard@tartarus.org>
+ *           (C) <2006> Wim Taymans <wim at fluendo dot com>
+ *           (C) <2015> Luis de Bethencourt <luis@debethencourt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-goom2k1
+ * @see_also: goom, synaesthesia
+ *
+ * Goom2k1 is an audio visualisation element. It creates warping structures
+ * based on the incomming audio signal. Goom2k1 is the older version of the
+ * visualisation. Also available is goom2k4, with a different look.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! goom2k1 ! videoconvert ! xvimagesink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include "gstgoom.h"
+#include "goom_core.h"
+
+GST_DEBUG_CATEGORY_STATIC (goom2k1_debug);
+#define GST_CAT_DEFAULT goom2k1_debug
+
+#define DEFAULT_WIDTH  320
+#define DEFAULT_HEIGHT 240
+#define DEFAULT_FPS_N  25
+#define DEFAULT_FPS_D  1
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+#define RGB_ORDER "xRGB"
+#else
+#define RGB_ORDER "BGRx"
+#endif
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (RGB_ORDER))
+    );
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",    /* the name of the pads */
+    GST_PAD_SINK,               /* type of the pad */
+    GST_PAD_ALWAYS,             /* ALWAYS/SOMETIMES */
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (S16) ", "
+        "rate = (int) [ 8000, 96000 ], "
+        "channels = (int) 1, "
+        "layout = (string) interleaved; "
+        "audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (S16) ", "
+        "rate = (int) [ 8000, 96000 ], "
+        "channels = (int) 2, "
+        "channel-mask = (bitmask) 0x3, " "layout = (string) interleaved")
+    );
+
+static void gst_goom2k1_finalize (GObject * object);
+
+static gboolean gst_goom2k1_setup (GstAudioVisualizer * base);
+static gboolean gst_goom2k1_render (GstAudioVisualizer * base,
+    GstBuffer * audio, GstVideoFrame * video);
+
+
+G_DEFINE_TYPE (GstGoom2k1, gst_goom2k1, GST_TYPE_AUDIO_VISUALIZER);
+
+static void
+gst_goom2k1_class_init (GstGoom2k1Class * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstAudioVisualizerClass *visualizer_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  visualizer_class = (GstAudioVisualizerClass *) klass;
+
+  gobject_class->finalize = gst_goom2k1_finalize;
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "GOOM: what a GOOM! 2k1 edition", "Visualization",
+      "Takes frames of data and outputs video frames using the GOOM 2k1 filter",
+      "Wim Taymans <wim@fluendo.com>");
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class, &src_template);
+
+  GST_DEBUG_CATEGORY_INIT (goom2k1_debug, "goom2k1", 0,
+      "goom2k1 visualisation element");
+
+  visualizer_class->setup = GST_DEBUG_FUNCPTR (gst_goom2k1_setup);
+  visualizer_class->render = GST_DEBUG_FUNCPTR (gst_goom2k1_render);
+}
+
+static void
+gst_goom2k1_init (GstGoom2k1 * goom)
+{
+  goom->width = DEFAULT_WIDTH;
+  goom->height = DEFAULT_HEIGHT;
+  goom->channels = 0;
+
+  goom_init (&(goom->goomdata), goom->width, goom->height);
+}
+
+static void
+gst_goom2k1_finalize (GObject * object)
+{
+  GstGoom2k1 *goom = GST_GOOM2K1 (object);
+
+  goom_close (&(goom->goomdata));
+
+  G_OBJECT_CLASS (gst_goom2k1_parent_class)->finalize (object);
+}
+
+static gboolean
+gst_goom2k1_setup (GstAudioVisualizer * base)
+{
+  GstGoom2k1 *goom = GST_GOOM2K1 (base);
+
+  goom->width = GST_VIDEO_INFO_WIDTH (&base->vinfo);
+  goom->height = GST_VIDEO_INFO_HEIGHT (&base->vinfo);
+
+  goom_set_resolution (&(goom->goomdata), goom->width, goom->height);
+
+  return TRUE;
+}
+
+static gboolean
+gst_goom2k1_render (GstAudioVisualizer * base, GstBuffer * audio,
+    GstVideoFrame * video)
+{
+  GstGoom2k1 *goom = GST_GOOM2K1 (base);
+  GstMapInfo amap;
+  gint16 datain[2][GOOM2K1_SAMPLES];
+  gint16 *adata;
+  gint i;
+
+  /* get next GOOM2K1_SAMPLES, we have at least this amount of samples */
+  gst_buffer_map (audio, &amap, GST_MAP_READ);
+  adata = (gint16 *) amap.data;
+
+  if (goom->channels == 2) {
+    for (i = 0; i < GOOM2K1_SAMPLES; i++) {
+      datain[0][i] = *adata++;
+      datain[1][i] = *adata++;
+    }
+  } else {
+    for (i = 0; i < GOOM2K1_SAMPLES; i++) {
+      datain[0][i] = *adata;
+      datain[1][i] = *adata++;
+    }
+  }
+
+  video->data[0] = goom_update (&(goom->goomdata), datain);
+  gst_buffer_unmap (audio, &amap);
+
+  return TRUE;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "goom2k1", GST_RANK_NONE,
+      GST_TYPE_GOOM2K1);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    goom2k1,
+    "GOOM 2k1 visualization filter",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/goom2k1/gstgoom.h b/gst/goom2k1/gstgoom.h
new file mode 100644
index 0000000..41b818b
--- /dev/null
+++ b/gst/goom2k1/gstgoom.h
@@ -0,0 +1,68 @@
+/* gstgoom.c: implementation of goom drawing element
+ * Copyright (C) <2001> Richard Boulton <richard@tartarus.org>
+ *           (C) <2006> Wim Taymans <wim at fluendo dot com>
+ * Copyright (C) <2015> Luis de Bethencourt <luis@debethencourt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_GOOM_H__
+#define __GST_GOOM_H__
+
+#include <gst/pbutils/gstaudiovisualizer.h>
+
+#include "goom_core.h"
+
+G_BEGIN_DECLS
+
+#define GOOM2K1_SAMPLES 512
+
+#define GST_TYPE_GOOM2K1            (gst_goom2k1_get_type())
+#define GST_GOOM2K1(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GOOM2K1,GstGoom2k1))
+#define GST_GOOM2K1_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GOOM2K1,GstGoom2k1Class))
+#define GST_IS_GOOM2K1(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GOOM2K1))
+#define GST_IS_GOOM2K1_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GOOM2K1))
+
+typedef struct _GstGoom2k1 GstGoom2k1;
+typedef struct _GstGoom2k1Class GstGoom2k1Class;
+
+struct _GstGoom2k1
+{
+  GstAudioVisualizer parent;
+
+  /* input tracking */
+  gint channels;
+
+  /* video state */
+  gint width;
+  gint height;
+
+  /* goom stuff */
+  GoomData goomdata;
+};
+
+struct _GstGoom2k1Class
+{
+  GstAudioVisualizerClass parent_class;
+};
+
+GType gst_goom2k1_get_type (void);
+gboolean gst_goom2k1_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_GOOM_H__ */
+
diff --git a/gst/goom2k1/lines.c b/gst/goom2k1/lines.c
new file mode 100644
index 0000000..804b68e
--- /dev/null
+++ b/gst/goom2k1/lines.c
@@ -0,0 +1,112 @@
+/*
+ *  lines.c
+ *  iTunesXPlugIn
+ *
+ *  Created by guillaum on Tue Aug 14 2001.
+ *  Copyright (c) 2001 __CompanyName__. All rights reserved.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "lines.h"
+#include <math.h>
+
+static inline unsigned char
+lighten (unsigned char value, unsigned char power)
+{
+  unsigned char i;
+
+  for (i = 0; i < power; i++)
+    value += (255 - value) / 5;
+  return value;
+}
+
+void
+goom_lines (GoomData * goomdata, gint16 data[2][512], unsigned int ID,
+    unsigned int *p, guint32 power)
+{
+  guint32 color1;
+  guint32 color2;
+  guint32 resolx = goomdata->resolx;
+  guint32 resoly = goomdata->resoly;
+  unsigned char *color = 1 + (unsigned char *) &color1;
+
+  switch (ID) {
+    case 0:                    /* Horizontal stereo lines */
+    {
+      color1 = 0x0000AA00;
+      color2 = 0x00AA0000;
+      break;
+    }
+
+    case 1:                    /* Stereo circles */
+    {
+      color1 = 0x00AA33DD;
+      color2 = 0x00AA33DD;
+      break;
+    }
+    default:{
+      color1 = color2 = 0;
+      g_assert_not_reached ();
+      break;
+    }
+  }
+  *color = lighten (*color, power);
+  color++;
+  *color = lighten (*color, power);
+  color++;
+  *color = lighten (*color, power);
+  color = 1 + (unsigned char *) &color2;
+  *color = lighten (*color, power);
+  color++;
+  *color = lighten (*color, power);
+  color++;
+  *color = lighten (*color, power);
+
+  switch (ID) {
+    case 0:                    /* Horizontal stereo lines */
+    {
+      unsigned int i;
+
+      for (i = 0; i < 512; i++) {
+        guint32 plot;
+
+        plot = i * resolx / 512 + (resoly / 4 + data[0][i] / 1600) * resolx;
+        p[plot] = color1;
+        p[plot + 1] = color1;
+        plot = i * resolx / 512 + (resoly * 3 / 4 - data[1][i] / 1600) * resolx;
+        p[plot] = color2;
+        p[plot + 1] = color2;
+      }
+      break;
+    }
+
+    case 1:                    /* Stereo circles */
+    {
+      float z;
+      unsigned int monX = resolx / 2;
+      float monY = (float) resoly / 4;
+      float monY2 = (float) resoly / 2;
+
+      for (z = 0; z < 6.2832f; z += 1.0f / monY) {
+        /* float offset1 = 128+data[1][(unsigned int)(z*81.33f)])/200000; */
+        p[monX + (unsigned int) ((monY + ((float) resoly) * (128 +
+                        data[1][(unsigned int) (z * 81.33f)]) / 200000) *
+                cos (z) + resolx * (unsigned int) (monY2 + (monY +
+                        ((float) resoly) * (128 +
+                            data[1][(unsigned int) (z * 81.33f)]) / 400000) *
+                    sin (z)))] = color1;
+        p[monX + (unsigned int) ((monY - ((float) resoly) * (128 +
+                        data[0][(unsigned int) (z * 81.33f)]) / 200000) *
+                cos (z) + resolx * (unsigned int) (monY2 + (monY -
+                        ((float) resoly) * (128 +
+                            data[0][(unsigned int) (z * 81.33f)]) / 400000) *
+                    sin (z)))] = color2;
+      }
+      break;
+    }
+  }
+}
diff --git a/gst/goom2k1/lines.h b/gst/goom2k1/lines.h
new file mode 100644
index 0000000..548f339
--- /dev/null
+++ b/gst/goom2k1/lines.h
@@ -0,0 +1,16 @@
+/*
+ *  lines.h
+ *  iGoom
+ *
+ *  Created by guillaum on Tue Aug 14 2001.
+ *  Copyright (c) 2001 ios. All rights reserved.
+ *
+ */
+#include <glib.h>
+
+#include "graphic.h"
+#include "goom_core.h"
+
+void goom_lines(GoomData *goomdata, gint16 data [2][512], unsigned int ID,unsigned int* p, guint32 power);
+
+
diff --git a/gst/goom2k1/meson.build b/gst/goom2k1/meson.build
new file mode 100644
index 0000000..6460bd8
--- /dev/null
+++ b/gst/goom2k1/meson.build
@@ -0,0 +1,39 @@
+goom2k1_args = [
+  '-Dgst_goom_get_type=gst_goom2k1_get_type',
+  '-Dgoom_init=goom2k1_init',
+  '-Dgoom_close=goom2k1_close',
+  '-Dgoom_update=goom2k1_update',
+  '-Dgoom_set_resolution=goom2k1_set_resolution',
+  '-Dgoom_lines=goom2k1_lines',
+  '-DBLACK=GOOM2K1_BLACK',
+  '-DWHITE=GOOM2K1_WHITE',
+  '-DRED=GOOM2K1_RED',
+  '-DBLUE=GOOM2K1_BLUE',
+  '-DGREEN=GOOM2K1_GREEN',
+  '-DYELLOW=GOOM2K1_YELLOW',
+  '-DORANGE=GOOM2K1_ORANGE',
+  '-DVIOLET=GOOM2K1_VIOLET',
+  '-DzoomFilterFastRGB=zoomFilterFastRGB2k1',
+  '-DpointFilter=pointFilter2k1',
+  '-DzoomFilterDestroy=zoomFilterDestroy2k1',
+  '-DzoomFilterNew=zoomFilterNew2k1'
+]
+
+filter_args = ['-UMMX', '-UUSE_ASM']
+
+goom2k1_sources = [
+  'gstgoom.c',
+  'goom_core.c',
+  'filters.c',
+  'graphic.c',
+  'lines.c'
+]
+
+gstgoom2k1 = library('gstgoom2k1',
+  goom2k1_sources,
+  c_args : gst_plugins_good_args + goom2k1_args + filter_args,
+  include_directories : [configinc],
+  dependencies : [gstpbutils_dep, gstbase_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/icydemux/Makefile.am b/gst/icydemux/Makefile.am
new file mode 100644
index 0000000..59c021e
--- /dev/null
+++ b/gst/icydemux/Makefile.am
@@ -0,0 +1,8 @@
+plugin_LTLIBRARIES = libgsticydemux.la
+
+libgsticydemux_la_SOURCES = gsticydemux.c
+libgsticydemux_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgsticydemux_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgsttag-@GST_API_VERSION@ $(GST_BASE_LIBS) $(GST_LIBS)
+libgsticydemux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gsticydemux.h
diff --git a/gst/icydemux/gsticydemux.c b/gst/icydemux/gsticydemux.c
new file mode 100644
index 0000000..12fdad2
--- /dev/null
+++ b/gst/icydemux/gsticydemux.c
@@ -0,0 +1,677 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
+/* Copyright 2005 Jan Schmidt <thaytan@mad.scientist.com>
+ *           2006 Michael Smith <msmith@fluendo.com>
+ * Copyright (C) 2003-2004 Benjamin Otte <otte@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-icydemux
+ *
+ * icydemux accepts data streams with ICY metadata at known intervals, as
+ * transmitted from an upstream element (usually read as response headers from
+ * an HTTP stream). The mime type of the data between the tag blocks is
+ * detected using typefind functions, and the appropriate output mime type set
+ * on outgoing buffers. 
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 souphttpsrc location=http://some.server/ iradio-mode=true ! icydemux ! fakesink -t
+ * ]| This pipeline should read any available ICY tag information and output it.
+ * The contents of the stream should be detected, and the appropriate mime
+ * type set on buffers produced from icydemux. (Using gnomevfssrc, neonhttpsrc
+ * or giosrc instead of souphttpsrc should also work.)
+ * </refsect2>
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <gst/gst.h>
+#include <gst/gst-i18n-plugin.h>
+#include <gst/tag/tag.h>
+
+#include "gsticydemux.h"
+
+#include <string.h>
+
+#define ICY_TYPE_FIND_MAX_SIZE (40*1024)
+
+GST_DEBUG_CATEGORY_STATIC (icydemux_debug);
+#define GST_CAT_DEFAULT (icydemux_debug)
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-icy, metadata-interval = (int)[0, MAX]")
+    );
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("ANY")
+    );
+
+static void gst_icydemux_dispose (GObject * object);
+
+static GstFlowReturn gst_icydemux_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buf);
+static gboolean gst_icydemux_handle_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+
+static gboolean gst_icydemux_add_srcpad (GstICYDemux * icydemux,
+    GstCaps * new_caps);
+static gboolean gst_icydemux_remove_srcpad (GstICYDemux * icydemux);
+
+static GstStateChangeReturn gst_icydemux_change_state (GstElement * element,
+    GstStateChange transition);
+static gboolean gst_icydemux_sink_setcaps (GstPad * pad, GstCaps * caps);
+
+static gboolean gst_icydemux_send_tag_event (GstICYDemux * icydemux,
+    GstTagList * taglist);
+
+
+#define gst_icydemux_parent_class parent_class
+G_DEFINE_TYPE (GstICYDemux, gst_icydemux, GST_TYPE_ELEMENT);
+
+static void
+gst_icydemux_class_init (GstICYDemuxClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+
+  gobject_class->dispose = gst_icydemux_dispose;
+
+  gstelement_class->change_state = gst_icydemux_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class, "ICY tag demuxer",
+      "Codec/Demuxer/Metadata",
+      "Read and output ICY tags while demuxing the contents",
+      "Jan Schmidt <thaytan@mad.scientist.com>, "
+      "Michael Smith <msmith@fluendo.com>");
+}
+
+static void
+gst_icydemux_reset (GstICYDemux * icydemux)
+{
+  /* Unknown at the moment (this is a fatal error if don't have a value by the
+   * time we get to our chain function)
+   */
+  icydemux->meta_interval = -1;
+  icydemux->remaining = 0;
+
+  icydemux->typefinding = TRUE;
+
+  gst_caps_replace (&(icydemux->src_caps), NULL);
+
+  gst_icydemux_remove_srcpad (icydemux);
+
+  if (icydemux->cached_tags) {
+    gst_tag_list_unref (icydemux->cached_tags);
+    icydemux->cached_tags = NULL;
+  }
+
+  if (icydemux->cached_events) {
+    g_list_foreach (icydemux->cached_events,
+        (GFunc) gst_mini_object_unref, NULL);
+    g_list_free (icydemux->cached_events);
+    icydemux->cached_events = NULL;
+  }
+
+  if (icydemux->meta_adapter) {
+    gst_adapter_clear (icydemux->meta_adapter);
+    g_object_unref (icydemux->meta_adapter);
+    icydemux->meta_adapter = NULL;
+  }
+
+  if (icydemux->typefind_buf) {
+    gst_buffer_unref (icydemux->typefind_buf);
+    icydemux->typefind_buf = NULL;
+  }
+
+  if (icydemux->content_type) {
+    g_free (icydemux->content_type);
+    icydemux->content_type = NULL;
+  }
+}
+
+static void
+gst_icydemux_init (GstICYDemux * icydemux)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (icydemux);
+
+  icydemux->sinkpad =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "sink"), "sink");
+  gst_pad_set_chain_function (icydemux->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_icydemux_chain));
+  gst_pad_set_event_function (icydemux->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_icydemux_handle_event));
+  gst_element_add_pad (GST_ELEMENT (icydemux), icydemux->sinkpad);
+
+  gst_icydemux_reset (icydemux);
+}
+
+static gboolean
+gst_icydemux_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+  GstICYDemux *icydemux = GST_ICYDEMUX (GST_PAD_PARENT (pad));
+  GstStructure *structure = gst_caps_get_structure (caps, 0);
+  const gchar *tmp;
+
+  if (!gst_structure_get_int (structure, "metadata-interval",
+          &icydemux->meta_interval))
+    return FALSE;
+
+  /* If incoming caps have the HTTP Content-Type, copy that over */
+  if ((tmp = gst_structure_get_string (structure, "content-type")))
+    icydemux->content_type = g_strdup (tmp);
+
+  /* We have a meta interval, so initialise the rest */
+  icydemux->remaining = icydemux->meta_interval;
+  icydemux->meta_remaining = 0;
+  return TRUE;
+}
+
+static void
+gst_icydemux_dispose (GObject * object)
+{
+  GstICYDemux *icydemux = GST_ICYDEMUX (object);
+
+  gst_icydemux_reset (icydemux);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+typedef struct
+{
+  GstCaps *caps;
+  GstPad *pad;
+} CopyStickyEventsData;
+
+static gboolean
+copy_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
+{
+  CopyStickyEventsData *data = user_data;
+
+  if (GST_EVENT_TYPE (*event) >= GST_EVENT_CAPS && data->caps) {
+    gst_pad_set_caps (data->pad, data->caps);
+    data->caps = NULL;
+  }
+
+  if (GST_EVENT_TYPE (*event) != GST_EVENT_CAPS)
+    gst_pad_push_event (data->pad, gst_event_ref (*event));
+
+  return TRUE;
+}
+
+static gboolean
+gst_icydemux_add_srcpad (GstICYDemux * icydemux, GstCaps * new_caps)
+{
+  if (icydemux->src_caps == NULL ||
+      !gst_caps_is_equal (new_caps, icydemux->src_caps)) {
+    gst_caps_replace (&(icydemux->src_caps), new_caps);
+    if (icydemux->srcpad != NULL) {
+      GST_DEBUG_OBJECT (icydemux, "Changing src pad caps to %" GST_PTR_FORMAT,
+          icydemux->src_caps);
+
+      gst_pad_set_caps (icydemux->srcpad, icydemux->src_caps);
+    }
+  } else {
+    /* Caps never changed */
+    gst_caps_unref (new_caps);
+  }
+
+  if (icydemux->srcpad == NULL) {
+    CopyStickyEventsData data;
+
+    icydemux->srcpad =
+        gst_pad_new_from_template (gst_element_class_get_pad_template
+        (GST_ELEMENT_GET_CLASS (icydemux), "src"), "src");
+    g_return_val_if_fail (icydemux->srcpad != NULL, FALSE);
+
+    gst_pad_use_fixed_caps (icydemux->srcpad);
+    gst_pad_set_active (icydemux->srcpad, TRUE);
+
+    data.pad = icydemux->srcpad;
+    data.caps = icydemux->src_caps;
+    gst_pad_sticky_events_foreach (icydemux->sinkpad, copy_sticky_events,
+        &data);
+    if (data.caps)
+      gst_pad_set_caps (data.pad, data.caps);
+
+    GST_DEBUG_OBJECT (icydemux, "Adding src pad with caps %" GST_PTR_FORMAT,
+        icydemux->src_caps);
+
+    if (!(gst_element_add_pad (GST_ELEMENT (icydemux), icydemux->srcpad)))
+      return FALSE;
+    gst_element_no_more_pads (GST_ELEMENT (icydemux));
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_icydemux_remove_srcpad (GstICYDemux * icydemux)
+{
+  gboolean res = TRUE;
+
+  if (icydemux->srcpad != NULL) {
+    res = gst_element_remove_pad (GST_ELEMENT (icydemux), icydemux->srcpad);
+    g_return_val_if_fail (res != FALSE, FALSE);
+    icydemux->srcpad = NULL;
+  }
+
+  return res;
+};
+
+static gchar *
+gst_icydemux_unicodify (const gchar * str)
+{
+  const gchar *env_vars[] = { "GST_ICY_TAG_ENCODING",
+    "GST_TAG_ENCODING", NULL
+  };
+
+  return gst_tag_freeform_string_to_utf8 (str, -1, env_vars);
+}
+
+/* takes ownership of tag list */
+static gboolean
+gst_icydemux_tag_found (GstICYDemux * icydemux, GstTagList * tags)
+{
+  /* send the tag event if we have finished typefinding and have a src pad */
+  if (icydemux->srcpad)
+    return gst_icydemux_send_tag_event (icydemux, tags);
+
+  /* if we haven't a source pad yet, cache the tags */
+  if (!icydemux->cached_tags) {
+    icydemux->cached_tags = tags;
+  } else {
+    gst_tag_list_insert (icydemux->cached_tags, tags,
+        GST_TAG_MERGE_REPLACE_ALL);
+    gst_tag_list_unref (tags);
+  }
+
+  return TRUE;
+}
+
+static void
+gst_icydemux_parse_and_send_tags (GstICYDemux * icydemux)
+{
+  GstTagList *tags;
+  const guint8 *data;
+  int length, i;
+  gboolean tags_found = FALSE;
+  gchar *buffer;
+  gchar **strings;
+
+  length = gst_adapter_available (icydemux->meta_adapter);
+
+  data = gst_adapter_map (icydemux->meta_adapter, length);
+
+  /* Now, copy this to a buffer where we can NULL-terminate it to make things
+   * a bit easier, then do that parsing. */
+  buffer = g_strndup ((const gchar *) data, length);
+
+  tags = gst_tag_list_new_empty ();
+  strings = g_strsplit (buffer, "';", 0);
+
+  for (i = 0; strings[i]; i++) {
+    if (!g_ascii_strncasecmp (strings[i], "StreamTitle=", 12)) {
+      char *title = gst_icydemux_unicodify (strings[i] + 13);
+      tags_found = TRUE;
+
+      if (title && *title) {
+        gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE,
+            title, NULL);
+        g_free (title);
+      }
+    } else if (!g_ascii_strncasecmp (strings[i], "StreamUrl=", 10)) {
+      char *url = gst_icydemux_unicodify (strings[i] + 11);
+      tags_found = TRUE;
+
+      if (url && *url) {
+        gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_HOMEPAGE,
+            url, NULL);
+        g_free (url);
+      }
+    }
+  }
+
+  g_strfreev (strings);
+  g_free (buffer);
+  gst_adapter_unmap (icydemux->meta_adapter);
+  gst_adapter_flush (icydemux->meta_adapter, length);
+
+  if (tags_found)
+    gst_icydemux_tag_found (icydemux, tags);
+  else
+    gst_tag_list_unref (tags);
+}
+
+static gboolean
+gst_icydemux_handle_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstICYDemux *icydemux = GST_ICYDEMUX (parent);
+  gboolean result;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_TAG:
+    {
+      GstTagList *tags;
+
+      gst_event_parse_tag (event, &tags);
+      result = gst_icydemux_tag_found (icydemux, gst_tag_list_copy (tags));
+      gst_event_unref (event);
+      return result;
+    }
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      result = gst_icydemux_sink_setcaps (pad, caps);
+      gst_event_unref (event);
+      return result;
+    }
+    default:
+      break;
+  }
+
+  if (icydemux->typefinding) {
+    switch (GST_EVENT_TYPE (event)) {
+      case GST_EVENT_FLUSH_STOP:
+        g_list_foreach (icydemux->cached_events,
+            (GFunc) gst_mini_object_unref, NULL);
+        g_list_free (icydemux->cached_events);
+        icydemux->cached_events = NULL;
+
+        return gst_pad_event_default (pad, parent, event);
+      default:
+        if (!GST_EVENT_IS_STICKY (event)) {
+          icydemux->cached_events =
+              g_list_append (icydemux->cached_events, event);
+        } else {
+          gst_event_unref (event);
+        }
+        return TRUE;
+    }
+  } else {
+    return gst_pad_event_default (pad, parent, event);
+  }
+}
+
+static void
+gst_icydemux_send_cached_events (GstICYDemux * icydemux)
+{
+  GList *l;
+
+  for (l = icydemux->cached_events; l != NULL; l = l->next) {
+    GstEvent *event = GST_EVENT (l->data);
+
+    gst_pad_push_event (icydemux->srcpad, event);
+  }
+  g_list_free (icydemux->cached_events);
+  icydemux->cached_events = NULL;
+}
+
+static GstFlowReturn
+gst_icydemux_typefind_or_forward (GstICYDemux * icydemux, GstBuffer * buf)
+{
+  if (icydemux->typefinding) {
+    GstBuffer *tf_buf;
+    GstCaps *caps = NULL;
+    GstTypeFindProbability prob;
+
+    /* If we have a content-type from upstream, let's see if we can shortcut
+     * typefinding */
+    if (G_UNLIKELY (icydemux->content_type)) {
+      if (!g_ascii_strcasecmp (icydemux->content_type, "video/nsv")) {
+        GST_DEBUG ("We have a NSV stream");
+        caps = gst_caps_new_empty_simple ("video/x-nsv");
+      } else {
+        GST_DEBUG ("Upstream Content-Type isn't supported");
+        g_free (icydemux->content_type);
+        icydemux->content_type = NULL;
+      }
+    }
+
+    if (icydemux->typefind_buf) {
+      icydemux->typefind_buf = gst_buffer_append (icydemux->typefind_buf, buf);
+    } else {
+      icydemux->typefind_buf = buf;
+    }
+
+    /* Only typefind if we haven't already got some caps */
+    if (caps == NULL) {
+      caps = gst_type_find_helper_for_buffer (GST_OBJECT (icydemux),
+          icydemux->typefind_buf, &prob);
+
+      if (caps == NULL) {
+        if (gst_buffer_get_size (icydemux->typefind_buf) <
+            ICY_TYPE_FIND_MAX_SIZE) {
+          /* Just break for more data */
+          return GST_FLOW_OK;
+        }
+
+        /* We failed typefind */
+        GST_ELEMENT_ERROR (icydemux, STREAM, TYPE_NOT_FOUND, (NULL),
+            ("No caps found for contents within an ICY stream"));
+        gst_buffer_unref (icydemux->typefind_buf);
+        icydemux->typefind_buf = NULL;
+        return GST_FLOW_ERROR;
+      }
+    }
+
+    if (!gst_icydemux_add_srcpad (icydemux, caps)) {
+      GST_DEBUG_OBJECT (icydemux, "Failed to add srcpad");
+      gst_caps_unref (caps);
+      gst_buffer_unref (icydemux->typefind_buf);
+      icydemux->typefind_buf = NULL;
+      return GST_FLOW_ERROR;
+    }
+    gst_caps_unref (caps);
+
+    if (icydemux->cached_events) {
+      gst_icydemux_send_cached_events (icydemux);
+    }
+
+    if (icydemux->cached_tags) {
+      gst_icydemux_send_tag_event (icydemux, icydemux->cached_tags);
+      icydemux->cached_tags = NULL;
+    }
+
+    /* Move onto streaming: call ourselves recursively with the typefind buffer
+     * to get that forwarded. */
+    icydemux->typefinding = FALSE;
+
+    tf_buf = icydemux->typefind_buf;
+    icydemux->typefind_buf = NULL;
+    return gst_icydemux_typefind_or_forward (icydemux, tf_buf);
+  } else {
+    if (G_UNLIKELY (icydemux->srcpad == NULL)) {
+      gst_buffer_unref (buf);
+      return GST_FLOW_ERROR;
+    }
+
+    buf = gst_buffer_make_writable (buf);
+
+    /* Most things don't care, and it's a pain to track (we should preserve a
+     * 0 offset on the first buffer though if it's there, for id3demux etc.) */
+    if (GST_BUFFER_OFFSET (buf) != 0) {
+      GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
+    }
+
+    return gst_pad_push (icydemux->srcpad, buf);
+  }
+}
+
+static void
+gst_icydemux_add_meta (GstICYDemux * icydemux, GstBuffer * buf)
+{
+  if (!icydemux->meta_adapter)
+    icydemux->meta_adapter = gst_adapter_new ();
+
+  gst_adapter_push (icydemux->meta_adapter, buf);
+}
+
+static GstFlowReturn
+gst_icydemux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstICYDemux *icydemux;
+  guint size, chunk, offset;
+  GstBuffer *sub;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  icydemux = GST_ICYDEMUX (parent);
+
+  if (G_UNLIKELY (icydemux->meta_interval < 0))
+    goto not_negotiated;
+
+  if (icydemux->meta_interval == 0) {
+    ret = gst_icydemux_typefind_or_forward (icydemux, buf);
+    buf = NULL;
+    goto done;
+  }
+
+  /* Go through the buffer, chopping it into appropriate chunks. Forward as
+   * tags or buffers, as appropriate
+   */
+  size = gst_buffer_get_size (buf);
+  offset = 0;
+  while (size) {
+    if (icydemux->remaining) {
+      chunk = (size <= icydemux->remaining) ? size : icydemux->remaining;
+      if (offset == 0 && chunk == size) {
+        sub = buf;
+        buf = NULL;
+      } else {
+        sub = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset, chunk);
+      }
+      offset += chunk;
+      icydemux->remaining -= chunk;
+      size -= chunk;
+
+      /* This buffer goes onto typefinding, and/or directly pushed out */
+      ret = gst_icydemux_typefind_or_forward (icydemux, sub);
+      if (ret != GST_FLOW_OK)
+        goto done;
+    } else if (icydemux->meta_remaining) {
+      chunk = (size <= icydemux->meta_remaining) ?
+          size : icydemux->meta_remaining;
+      sub = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset, chunk);
+      gst_icydemux_add_meta (icydemux, sub);
+
+      offset += chunk;
+      icydemux->meta_remaining -= chunk;
+      size -= chunk;
+
+      if (icydemux->meta_remaining == 0) {
+        /* Parse tags from meta_adapter, send off as tag messages */
+        GST_DEBUG_OBJECT (icydemux, "No remaining metadata, parsing for tags");
+        gst_icydemux_parse_and_send_tags (icydemux);
+
+        icydemux->remaining = icydemux->meta_interval;
+      }
+    } else {
+      guint8 byte;
+      /* We need to read a single byte (always safe at this point in the loop)
+       * to figure out how many bytes of metadata exist. 
+       * The 'spec' tells us to read 16 * (byte_value) bytes of metadata after
+       * this (zero is common, and means the metadata hasn't changed).
+       */
+      gst_buffer_extract (buf, offset, &byte, 1);
+      icydemux->meta_remaining = 16 * byte;
+      if (icydemux->meta_remaining == 0)
+        icydemux->remaining = icydemux->meta_interval;
+
+      offset += 1;
+      size -= 1;
+    }
+  }
+
+done:
+  if (buf)
+    gst_buffer_unref (buf);
+
+  return ret;
+
+  /* ERRORS */
+not_negotiated:
+  {
+    GST_WARNING_OBJECT (icydemux, "meta_interval not set, buffer probably had "
+        "no caps set. Try enabling iradio-mode on the http source element");
+    gst_buffer_unref (buf);
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+}
+
+static GstStateChangeReturn
+gst_icydemux_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstICYDemux *icydemux = GST_ICYDEMUX (element);
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_icydemux_reset (icydemux);
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+/* takes ownership of tag list */
+static gboolean
+gst_icydemux_send_tag_event (GstICYDemux * icydemux, GstTagList * tags)
+{
+  GstEvent *event;
+
+  event = gst_event_new_tag (tags);
+  GST_EVENT_TIMESTAMP (event) = 0;
+
+  GST_DEBUG_OBJECT (icydemux, "Sending tag event on src pad");
+  return gst_pad_push_event (icydemux->srcpad, event);
+
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (icydemux_debug, "icydemux", 0,
+      "GStreamer ICY tag demuxer");
+
+  return gst_element_register (plugin, "icydemux",
+      GST_RANK_PRIMARY, GST_TYPE_ICYDEMUX);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    icydemux,
+    "Demux ICY tags from a stream",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/icydemux/gsticydemux.h b/gst/icydemux/gsticydemux.h
new file mode 100644
index 0000000..3f05218
--- /dev/null
+++ b/gst/icydemux/gsticydemux.h
@@ -0,0 +1,87 @@
+/* Copyright 2005 Jan Schmidt <thaytan@mad.scientist.com>
+ *           2006 Michael Smith <msmith@fluendo.com>
+ * Copyright (C) 2003-2004 Benjamin Otte <otte@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_ICYDEMUX_H__
+#define __GST_ICYDEMUX_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/base/gsttypefindhelper.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_ICYDEMUX \
+  (gst_icydemux_get_type())
+#define GST_ICYDEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ICYDEMUX,GstICYDemux))
+#define GST_ICYDEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ICYDEMUX,GstICYDemuxClass))
+#define GST_IS_ICYDEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ICYDEMUX))
+#define GST_IS_ICYDEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ICYDEMUX))
+
+typedef struct _GstICYDemux      GstICYDemux;
+typedef struct _GstICYDemuxClass GstICYDemuxClass;
+
+struct _GstICYDemux
+{
+  GstElement element;
+
+  GstPad *sinkpad, *srcpad;
+
+  /* Interval between metadata updates */
+  gint meta_interval;
+
+  /* Remaining bytes until the next metadata update */
+  gint remaining;
+
+  /* When 'remaining' is zero, this holds the number of bytes of metadata we
+   * still need to read, or zero if we don't yet know (which means we need to
+   * read one byte, after which we can initialise this properly) */
+  gint meta_remaining;
+
+  /* Caps for the data enclosed */
+  GstCaps *src_caps;
+
+  /* True if we're still typefinding */
+  gboolean typefinding;
+
+  GstTagList *cached_tags;
+  GList *cached_events;
+
+  GstAdapter *meta_adapter;
+
+  GstBuffer *typefind_buf;
+
+  /* upstream HTTP Content-Type */
+  gchar *content_type;
+};
+
+struct _GstICYDemuxClass 
+{
+  GstElementClass parent_class;
+};
+
+GType gst_icydemux_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_ICYDEMUX_H__ */
diff --git a/gst/icydemux/meson.build b/gst/icydemux/meson.build
new file mode 100644
index 0000000..5c5f857
--- /dev/null
+++ b/gst/icydemux/meson.build
@@ -0,0 +1,8 @@
+gsticydemux = library('gsticydemux',
+  'gsticydemux.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc, libsinc],
+  dependencies : [gst_dep, gstbase_dep, gsttag_dep, zlib_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/id3demux/Makefile.am b/gst/id3demux/Makefile.am
new file mode 100644
index 0000000..a24a1ac
--- /dev/null
+++ b/gst/id3demux/Makefile.am
@@ -0,0 +1,9 @@
+plugin_LTLIBRARIES = libgstid3demux.la
+
+libgstid3demux_la_SOURCES = gstid3demux.c
+libgstid3demux_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) 
+libgstid3demux_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgsttag-@GST_API_VERSION@ \
+	-lgstpbutils-@GST_API_VERSION@ $(GST_BASE_LIBS)
+libgstid3demux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstid3demux.h
diff --git a/gst/id3demux/gstid3demux.c b/gst/id3demux/gstid3demux.c
new file mode 100644
index 0000000..d491bb8
--- /dev/null
+++ b/gst/id3demux/gstid3demux.c
@@ -0,0 +1,289 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
+/* GStreamer ID3 tag demuxer
+ * Copyright (C) 2005 Jan Schmidt <thaytan@mad.scientist.com>
+ * Copyright (C) 2003-2004 Benjamin Otte <otte@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-id3demux
+ *
+ * id3demux accepts data streams with either (or both) ID3v2 regions at the
+ * start, or ID3v1 at the end. The mime type of the data between the tag blocks
+ * is detected using typefind functions, and the appropriate output mime type
+ * set on outgoing buffers. 
+ *
+ * The element is only able to read ID3v1 tags from a seekable stream, because
+ * they are at the end of the stream. That is, when get_range mode is supported
+ * by the upstream elements. If get_range operation is available, id3demux makes
+ * it available downstream. This means that elements which require get_range
+ * mode, such as wavparse, can operate on files containing ID3 tag information.
+ *
+ * This id3demux element replaced an older element with the same name which
+ * relied on libid3tag from the MAD project.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=file.mp3 ! id3demux ! fakesink -t
+ * ]| This pipeline should read any available ID3 tag information and output it.
+ * The contents of the file inside the ID3 tag regions should be detected, and
+ * the appropriate mime type set on buffers produced from id3demux.
+ * </refsect2>
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <gst/gst.h>
+#include <gst/gst-i18n-plugin.h>
+#include <gst/tag/tag.h>
+#include <gst/pbutils/pbutils.h>
+#include <string.h>
+
+#include "gstid3demux.h"
+
+enum
+{
+  PROP_0,
+  PROP_PREFER_V1
+};
+
+#define DEFAULT_PREFER_V1  FALSE
+
+GST_DEBUG_CATEGORY (id3demux_debug);
+#define GST_CAT_DEFAULT (id3demux_debug)
+
+#define ID3V1_TAG_SIZE 128
+#define ID3V2_HDR_SIZE GST_TAG_ID3V2_HEADER_SIZE
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-id3")
+    );
+
+static gboolean gst_id3demux_identify_tag (GstTagDemux * demux,
+    GstBuffer * buffer, gboolean start_tag, guint * tag_size);
+static GstTagDemuxResult gst_id3demux_parse_tag (GstTagDemux * demux,
+    GstBuffer * buffer, gboolean start_tag, guint * tag_size,
+    GstTagList ** tags);
+static GstTagList *gst_id3demux_merge_tags (GstTagDemux * tagdemux,
+    const GstTagList * start_tags, const GstTagList * end_tags);
+
+static void gst_id3demux_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_id3demux_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+#define gst_id3demux_parent_class parent_class
+G_DEFINE_TYPE (GstID3Demux, gst_id3demux, GST_TYPE_TAG_DEMUX);
+
+static void
+gst_id3demux_class_init (GstID3DemuxClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstTagDemuxClass *tagdemux_class = (GstTagDemuxClass *) klass;
+
+  gobject_class->set_property = gst_id3demux_set_property;
+  gobject_class->get_property = gst_id3demux_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_PREFER_V1,
+      g_param_spec_boolean ("prefer-v1", "Prefer version 1 tag",
+          "Prefer tags from ID3v1 tag at end of file when both ID3v1 "
+          "and ID3v2 tags are present", DEFAULT_PREFER_V1,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class, "ID3 tag demuxer",
+      "Codec/Demuxer/Metadata",
+      "Read and output ID3v1 and ID3v2 tags while demuxing the contents",
+      "Jan Schmidt <thaytan@mad.scientist.com>");
+
+  tagdemux_class->identify_tag = GST_DEBUG_FUNCPTR (gst_id3demux_identify_tag);
+  tagdemux_class->parse_tag = GST_DEBUG_FUNCPTR (gst_id3demux_parse_tag);
+  tagdemux_class->merge_tags = GST_DEBUG_FUNCPTR (gst_id3demux_merge_tags);
+
+  tagdemux_class->min_start_size = ID3V2_HDR_SIZE;
+  tagdemux_class->min_end_size = ID3V1_TAG_SIZE;
+}
+
+static void
+gst_id3demux_init (GstID3Demux * id3demux)
+{
+  id3demux->prefer_v1 = DEFAULT_PREFER_V1;
+}
+
+static gboolean
+gst_id3demux_identify_tag (GstTagDemux * demux, GstBuffer * buf,
+    gboolean start_tag, guint * tag_size)
+{
+  guint8 data[3];
+
+  gst_buffer_extract (buf, 0, data, 3);
+
+  if (start_tag) {
+    if (data[0] != 'I' || data[1] != 'D' || data[2] != '3')
+      goto no_marker;
+
+    *tag_size = gst_tag_get_id3v2_tag_size (buf);
+  } else {
+    if (data[0] != 'T' || data[1] != 'A' || data[2] != 'G')
+      goto no_marker;
+
+    *tag_size = ID3V1_TAG_SIZE;
+  }
+
+  GST_INFO_OBJECT (demux, "Found ID3v%u marker, tag_size = %u",
+      (start_tag) ? 2 : 1, *tag_size);
+
+  return TRUE;
+
+no_marker:
+  {
+    GST_DEBUG_OBJECT (demux, "No ID3v%u marker found", (start_tag) ? 2 : 1);
+    return FALSE;
+  }
+}
+
+static void
+gst_id3demux_add_container_format (GstTagList * tags)
+{
+  GstCaps *sink_caps;
+
+  sink_caps = gst_static_pad_template_get_caps (&sink_factory);
+  gst_pb_utils_add_codec_description_to_tag_list (tags,
+      GST_TAG_CONTAINER_FORMAT, sink_caps);
+  gst_caps_unref (sink_caps);
+}
+
+static GstTagDemuxResult
+gst_id3demux_parse_tag (GstTagDemux * demux, GstBuffer * buffer,
+    gboolean start_tag, guint * tag_size, GstTagList ** tags)
+{
+  if (start_tag) {
+    *tag_size = gst_tag_get_id3v2_tag_size (buffer);
+    *tags = gst_tag_list_from_id3v2_tag (buffer);
+
+    if (G_LIKELY (*tags != NULL)) {
+      gst_id3demux_add_container_format (*tags);
+      return GST_TAG_DEMUX_RESULT_OK;
+    } else {
+      return GST_TAG_DEMUX_RESULT_BROKEN_TAG;
+    }
+  } else {
+    GstMapInfo map;
+
+    gst_buffer_map (buffer, &map, GST_MAP_READ);
+    *tags = gst_tag_list_new_from_id3v1 (map.data);
+    gst_buffer_unmap (buffer, &map);
+
+    if (G_UNLIKELY (*tags == NULL))
+      return GST_TAG_DEMUX_RESULT_BROKEN_TAG;
+
+    gst_id3demux_add_container_format (*tags);
+    *tag_size = ID3V1_TAG_SIZE;
+    return GST_TAG_DEMUX_RESULT_OK;
+  }
+}
+
+static GstTagList *
+gst_id3demux_merge_tags (GstTagDemux * tagdemux, const GstTagList * start_tags,
+    const GstTagList * end_tags)
+{
+  GstID3Demux *id3demux;
+  GstTagList *merged;
+  gboolean prefer_v1;
+
+  id3demux = GST_ID3DEMUX (tagdemux);
+
+  GST_OBJECT_LOCK (id3demux);
+  prefer_v1 = id3demux->prefer_v1;
+  GST_OBJECT_UNLOCK (id3demux);
+
+  /* we merge in REPLACE mode, so put the less important tags first */
+  if (prefer_v1)
+    merged = gst_tag_list_merge (start_tags, end_tags, GST_TAG_MERGE_REPLACE);
+  else
+    merged = gst_tag_list_merge (end_tags, start_tags, GST_TAG_MERGE_REPLACE);
+
+  GST_LOG_OBJECT (id3demux, "start  tags: %" GST_PTR_FORMAT, start_tags);
+  GST_LOG_OBJECT (id3demux, "end    tags: %" GST_PTR_FORMAT, end_tags);
+  GST_LOG_OBJECT (id3demux, "merged tags: %" GST_PTR_FORMAT, merged);
+
+  return merged;
+}
+
+static void
+gst_id3demux_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstID3Demux *id3demux;
+
+  id3demux = GST_ID3DEMUX (object);
+
+  switch (prop_id) {
+    case PROP_PREFER_V1:{
+      GST_OBJECT_LOCK (id3demux);
+      id3demux->prefer_v1 = g_value_get_boolean (value);
+      GST_OBJECT_UNLOCK (id3demux);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_id3demux_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstID3Demux *id3demux;
+
+  id3demux = GST_ID3DEMUX (object);
+
+  switch (prop_id) {
+    case PROP_PREFER_V1:
+      GST_OBJECT_LOCK (id3demux);
+      g_value_set_boolean (value, id3demux->prefer_v1);
+      GST_OBJECT_UNLOCK (id3demux);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (id3demux_debug, "id3demux", 0,
+      "GStreamer ID3 tag demuxer");
+
+  gst_tag_register_musicbrainz_tags ();
+
+  return gst_element_register (plugin, "id3demux",
+      GST_RANK_PRIMARY, GST_TYPE_ID3DEMUX);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    id3demux,
+    "Demux ID3v1 and ID3v2 tags from a file",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/id3demux/gstid3demux.h b/gst/id3demux/gstid3demux.h
new file mode 100644
index 0000000..9561dfd
--- /dev/null
+++ b/gst/id3demux/gstid3demux.h
@@ -0,0 +1,59 @@
+/* GStreamer ID3 tag demuxer
+ * Copyright (C) 2005 Jan Schmidt <thaytan@mad.scientist.com>
+ * Copyright (C) 2003-2004 Benjamin Otte <otte@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_ID3DEMUX_H__
+#define __GST_ID3DEMUX_H__
+
+#include <gst/tag/gsttagdemux.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_ID3DEMUX \
+  (gst_id3demux_get_type())
+#define GST_ID3DEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ID3DEMUX,GstID3Demux))
+#define GST_ID3DEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ID3DEMUX,GstID3DemuxClass))
+#define GST_IS_ID3DEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ID3DEMUX))
+#define GST_IS_ID3DEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ID3DEMUX))
+
+typedef struct _GstID3Demux      GstID3Demux;
+typedef struct _GstID3DemuxClass GstID3DemuxClass;
+
+struct _GstID3Demux
+{
+  GstTagDemux tagdemux;
+
+  gboolean prefer_v1;     /* prefer ID3v1 tags over ID3v2 tags? */
+};
+
+struct _GstID3DemuxClass 
+{
+  GstTagDemuxClass parent_class;
+};
+
+GType gst_id3demux_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_ID3DEMUX_H__ */
+
diff --git a/gst/id3demux/meson.build b/gst/id3demux/meson.build
new file mode 100644
index 0000000..38ea56e
--- /dev/null
+++ b/gst/id3demux/meson.build
@@ -0,0 +1,8 @@
+gstid3demux = library('gstid3demux',
+  'gstid3demux.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc, libsinc],
+  dependencies : [gst_dep, gstbase_dep, gsttag_dep, gstpbutils_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/imagefreeze/Makefile.am b/gst/imagefreeze/Makefile.am
new file mode 100644
index 0000000..056d034
--- /dev/null
+++ b/gst/imagefreeze/Makefile.am
@@ -0,0 +1,9 @@
+plugin_LTLIBRARIES = libgstimagefreeze.la
+
+libgstimagefreeze_la_SOURCES = gstimagefreeze.c
+
+libgstimagefreeze_la_CFLAGS = $(GST_CFLAGS)
+libgstimagefreeze_la_LIBADD = $(GST_LIBS)
+libgstimagefreeze_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstimagefreeze.h
diff --git a/gst/imagefreeze/gstimagefreeze.c b/gst/imagefreeze/gstimagefreeze.c
new file mode 100644
index 0000000..a4e381c
--- /dev/null
+++ b/gst/imagefreeze/gstimagefreeze.c
@@ -0,0 +1,908 @@
+/* GStreamer
+ * Copyright (c) 2005 Edward Hervey <bilboed@bilboed.com>
+ * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-imagefreeze
+ *
+ * The imagefreeze element generates a still frame video stream from
+ * the input. It duplicates the first frame with the framerate requested
+ * by downstream, allows seeking and answers queries.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v filesrc location=some.png ! decodebin ! imagefreeze ! autovideosink
+ * ]| This pipeline shows a still frame stream of a PNG file.
+ * </refsect2>
+ */
+
+/* This is based on the imagefreeze element from PiTiVi:
+ * http://git.gnome.org/browse/pitivi/tree/pitivi/elements/imagefreeze.py
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/glib-compat-private.h>
+
+#include "gstimagefreeze.h"
+
+static void gst_image_freeze_finalize (GObject * object);
+
+static void gst_image_freeze_reset (GstImageFreeze * self);
+
+static GstStateChangeReturn gst_image_freeze_change_state (GstElement * element,
+    GstStateChange transition);
+
+static GstFlowReturn gst_image_freeze_sink_chain (GstPad * pad,
+    GstObject * parent, GstBuffer * buffer);
+static gboolean gst_image_freeze_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static gboolean gst_image_freeze_sink_setcaps (GstImageFreeze * self,
+    GstCaps * caps);
+static GstCaps *gst_image_freeze_sink_getcaps (GstImageFreeze * self,
+    GstCaps * filter);
+static gboolean gst_image_freeze_sink_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+static void gst_image_freeze_src_loop (GstPad * pad);
+static gboolean gst_image_freeze_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static gboolean gst_image_freeze_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+
+static GstStaticPadTemplate sink_pad_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-raw"));
+
+static GstStaticPadTemplate src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-raw"));
+
+GST_DEBUG_CATEGORY_STATIC (gst_image_freeze_debug);
+#define GST_CAT_DEFAULT gst_image_freeze_debug
+
+#define gst_image_freeze_parent_class parent_class
+G_DEFINE_TYPE (GstImageFreeze, gst_image_freeze, GST_TYPE_ELEMENT);
+
+
+static void
+gst_image_freeze_class_init (GstImageFreezeClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->finalize = gst_image_freeze_finalize;
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_image_freeze_change_state);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Still frame stream generator",
+      "Filter/Video",
+      "Generates a still frame stream from an image",
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &sink_pad_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &src_pad_template);
+}
+
+static void
+gst_image_freeze_init (GstImageFreeze * self)
+{
+  self->sinkpad = gst_pad_new_from_static_template (&sink_pad_template, "sink");
+  gst_pad_set_chain_function (self->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_image_freeze_sink_chain));
+  gst_pad_set_event_function (self->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_image_freeze_sink_event));
+  gst_pad_set_query_function (self->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_image_freeze_sink_query));
+  GST_PAD_SET_PROXY_ALLOCATION (self->sinkpad);
+  gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
+
+  self->srcpad = gst_pad_new_from_static_template (&src_pad_template, "src");
+  gst_pad_set_event_function (self->srcpad,
+      GST_DEBUG_FUNCPTR (gst_image_freeze_src_event));
+  gst_pad_set_query_function (self->srcpad,
+      GST_DEBUG_FUNCPTR (gst_image_freeze_src_query));
+  gst_pad_use_fixed_caps (self->srcpad);
+  gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
+
+  g_mutex_init (&self->lock);
+
+  gst_image_freeze_reset (self);
+}
+
+static void
+gst_image_freeze_finalize (GObject * object)
+{
+  GstImageFreeze *self = GST_IMAGE_FREEZE (object);
+
+  gst_image_freeze_reset (self);
+
+  g_mutex_clear (&self->lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_image_freeze_reset (GstImageFreeze * self)
+{
+  GST_DEBUG_OBJECT (self, "Resetting internal state");
+
+  g_mutex_lock (&self->lock);
+  gst_buffer_replace (&self->buffer, NULL);
+
+  gst_segment_init (&self->segment, GST_FORMAT_TIME);
+  self->need_segment = TRUE;
+
+  self->fps_n = self->fps_d = 0;
+  self->offset = 0;
+  self->seqnum = 0;
+  g_mutex_unlock (&self->lock);
+
+  g_atomic_int_set (&self->seeking, 0);
+}
+
+static gboolean
+gst_image_freeze_sink_setcaps (GstImageFreeze * self, GstCaps * caps)
+{
+  gboolean ret = FALSE;
+  GstStructure *s;
+  gint fps_n, fps_d;
+  GstCaps *othercaps, *intersection;
+  guint i, n;
+  GstPad *pad;
+
+  pad = self->sinkpad;
+  caps = gst_caps_copy (caps);
+
+  GST_DEBUG_OBJECT (pad, "Setting caps: %" GST_PTR_FORMAT, caps);
+
+  s = gst_caps_get_structure (caps, 0);
+
+  /* 1. Remove framerate */
+  gst_structure_remove_field (s, "framerate");
+  gst_structure_set (s, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
+      NULL);
+
+  /* 2. Intersect with template caps */
+  othercaps = (GstCaps *) gst_pad_get_pad_template_caps (pad);
+  intersection = gst_caps_intersect (caps, othercaps);
+  GST_DEBUG_OBJECT (pad, "Intersecting: %" GST_PTR_FORMAT, caps);
+  GST_DEBUG_OBJECT (pad, "with: %" GST_PTR_FORMAT, othercaps);
+  GST_DEBUG_OBJECT (pad, "gave: %" GST_PTR_FORMAT, intersection);
+  gst_caps_unref (caps);
+  gst_caps_unref (othercaps);
+  caps = intersection;
+  intersection = othercaps = NULL;
+
+  /* 3. Intersect with downstream peer caps */
+  othercaps = gst_pad_peer_query_caps (self->srcpad, caps);
+  GST_DEBUG_OBJECT (pad, "Peer query resulted: %" GST_PTR_FORMAT, othercaps);
+  gst_caps_unref (caps);
+  caps = othercaps;
+  othercaps = NULL;
+
+  /* 4. For every candidate try to use it downstream with framerate as
+   * near as possible to 25/1 */
+  n = gst_caps_get_size (caps);
+  for (i = 0; i < n; i++) {
+    GstCaps *candidate = gst_caps_new_empty ();
+    GstStructure *s = gst_structure_copy (gst_caps_get_structure (caps, i));
+
+    gst_caps_append_structure (candidate, s);
+    if (gst_structure_has_field_typed (s, "framerate", GST_TYPE_FRACTION) ||
+        gst_structure_fixate_field_nearest_fraction (s, "framerate", 25, 1)) {
+      gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d);
+      if (fps_d != 0) {
+        if (gst_pad_set_caps (self->srcpad, candidate)) {
+          g_mutex_lock (&self->lock);
+          self->fps_n = fps_n;
+          self->fps_d = fps_d;
+          g_mutex_unlock (&self->lock);
+          GST_DEBUG_OBJECT (pad, "Setting caps %" GST_PTR_FORMAT, candidate);
+          ret = TRUE;
+          gst_caps_unref (candidate);
+          break;
+        }
+      } else {
+        GST_WARNING_OBJECT (pad, "Invalid caps with framerate %d/%d", fps_n,
+            fps_d);
+      }
+    }
+    gst_caps_unref (candidate);
+  }
+
+  if (!ret)
+    GST_ERROR_OBJECT (pad, "No usable caps found");
+
+  gst_caps_unref (caps);
+
+  return ret;
+}
+
+/* remove framerate in writable @caps */
+static void
+gst_image_freeze_remove_fps (GstImageFreeze * self, GstCaps * caps)
+{
+  gint i, n;
+
+  n = gst_caps_get_size (caps);
+  for (i = 0; i < n; i++) {
+    GstStructure *s = gst_caps_get_structure (caps, i);
+
+    gst_structure_remove_field (s, "framerate");
+    gst_structure_set (s, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT,
+        1, NULL);
+  }
+}
+
+static GstCaps *
+gst_image_freeze_sink_getcaps (GstImageFreeze * self, GstCaps * filter)
+{
+  GstCaps *ret, *tmp, *templ;
+  GstPad *pad;
+
+  pad = self->sinkpad;
+
+  if (filter) {
+    filter = gst_caps_copy (filter);
+    gst_image_freeze_remove_fps (self, filter);
+  }
+  templ = gst_pad_get_pad_template_caps (pad);
+  tmp = gst_pad_peer_query_caps (self->srcpad, filter);
+  if (tmp) {
+    GST_LOG_OBJECT (self, "peer caps %" GST_PTR_FORMAT, tmp);
+    ret = gst_caps_intersect (tmp, templ);
+    gst_caps_unref (tmp);
+  } else {
+    GST_LOG_OBJECT (self, "going to copy");
+    ret = gst_caps_copy (templ);
+  }
+  if (templ)
+    gst_caps_unref (templ);
+  if (filter)
+    gst_caps_unref (filter);
+
+  ret = gst_caps_make_writable (ret);
+  gst_image_freeze_remove_fps (self, ret);
+
+  GST_LOG_OBJECT (pad, "Returning caps: %" GST_PTR_FORMAT, ret);
+
+  return ret;
+}
+
+static gboolean
+gst_image_freeze_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  GstImageFreeze *self = GST_IMAGE_FREEZE (parent);
+  gboolean ret;
+
+  GST_LOG_OBJECT (pad, "Handling query of type '%s'",
+      gst_query_type_get_name (GST_QUERY_TYPE (query)));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_query_parse_caps (query, &caps);
+      caps = gst_image_freeze_sink_getcaps (self, caps);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+      ret = TRUE;
+      break;
+    }
+    default:
+      ret = gst_pad_query_default (pad, parent, query);
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_image_freeze_convert (GstImageFreeze * self,
+    GstFormat src_format, gint64 src_value,
+    GstFormat * dest_format, gint64 * dest_value)
+{
+  gboolean ret = FALSE;
+
+  if (src_format == *dest_format) {
+    *dest_value = src_value;
+    return TRUE;
+  }
+
+  if (src_value == -1) {
+    *dest_value = -1;
+    return TRUE;
+  }
+
+  switch (src_format) {
+    case GST_FORMAT_DEFAULT:{
+      switch (*dest_format) {
+        case GST_FORMAT_TIME:
+          g_mutex_lock (&self->lock);
+          if (self->fps_n == 0)
+            *dest_value = -1;
+          else
+            *dest_value =
+                gst_util_uint64_scale (src_value, GST_SECOND * self->fps_d,
+                self->fps_n);
+          g_mutex_unlock (&self->lock);
+          ret = TRUE;
+          break;
+        default:
+          break;
+      }
+      break;
+    }
+    case GST_FORMAT_TIME:{
+      switch (*dest_format) {
+        case GST_FORMAT_DEFAULT:
+          g_mutex_lock (&self->lock);
+          *dest_value =
+              gst_util_uint64_scale (src_value, self->fps_n,
+              self->fps_d * GST_SECOND);
+          g_mutex_unlock (&self->lock);
+          ret = TRUE;
+          break;
+        default:
+          break;
+      }
+      break;
+    }
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_image_freeze_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  GstImageFreeze *self = GST_IMAGE_FREEZE (parent);
+  gboolean ret = FALSE;
+
+  GST_LOG_OBJECT (pad, "Handling query of type '%s'",
+      gst_query_type_get_name (GST_QUERY_TYPE (query)));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CONVERT:{
+      GstFormat src_format, dest_format;
+      gint64 src_value, dest_value;
+
+      gst_query_parse_convert (query, &src_format, &src_value, &dest_format,
+          &dest_value);
+      ret =
+          gst_image_freeze_convert (self, src_format, src_value, &dest_format,
+          &dest_value);
+      if (ret)
+        gst_query_set_convert (query, src_format, src_value, dest_format,
+            dest_value);
+      break;
+    }
+    case GST_QUERY_POSITION:{
+      GstFormat format;
+      gint64 position;
+
+      gst_query_parse_position (query, &format, NULL);
+      switch (format) {
+        case GST_FORMAT_DEFAULT:{
+          g_mutex_lock (&self->lock);
+          position = self->offset;
+          g_mutex_unlock (&self->lock);
+          ret = TRUE;
+          break;
+        }
+        case GST_FORMAT_TIME:{
+          g_mutex_lock (&self->lock);
+          position = self->segment.position;
+          g_mutex_unlock (&self->lock);
+          ret = TRUE;
+          break;
+        }
+        default:
+          break;
+      }
+
+      if (ret) {
+        gst_query_set_position (query, format, position);
+        GST_DEBUG_OBJECT (pad,
+            "Returning position %" G_GINT64_FORMAT " in format %s", position,
+            gst_format_get_name (format));
+      } else {
+        GST_DEBUG_OBJECT (pad, "Position query failed");
+      }
+      break;
+    }
+    case GST_QUERY_DURATION:{
+      GstFormat format;
+      gint64 duration;
+
+      gst_query_parse_duration (query, &format, NULL);
+      switch (format) {
+        case GST_FORMAT_TIME:{
+          g_mutex_lock (&self->lock);
+          duration = self->segment.stop;
+          g_mutex_unlock (&self->lock);
+          ret = TRUE;
+          break;
+        }
+        case GST_FORMAT_DEFAULT:{
+          g_mutex_lock (&self->lock);
+          duration = self->segment.stop;
+          if (duration != -1)
+            duration =
+                gst_util_uint64_scale (duration, self->fps_n,
+                GST_SECOND * self->fps_d);
+          g_mutex_unlock (&self->lock);
+          ret = TRUE;
+          break;
+        }
+        default:
+          break;
+      }
+
+      if (ret) {
+        gst_query_set_duration (query, format, duration);
+        GST_DEBUG_OBJECT (pad,
+            "Returning duration %" G_GINT64_FORMAT " in format %s", duration,
+            gst_format_get_name (format));
+      } else {
+        GST_DEBUG_OBJECT (pad, "Duration query failed");
+      }
+      break;
+    }
+    case GST_QUERY_SEEKING:{
+      GstFormat format;
+      gboolean seekable;
+
+      gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
+      seekable = (format == GST_FORMAT_TIME || format == GST_FORMAT_DEFAULT);
+
+      gst_query_set_seeking (query, format, seekable, (seekable ? 0 : -1), -1);
+      ret = TRUE;
+      break;
+    }
+    case GST_QUERY_LATENCY:
+      /* This will only return an accurate latency for the first buffer since
+       * all further buffers outputted by us are just copies of that one, and
+       * the latency is 0 in that case. However, latency changes are not
+       * straightforward, so let's do the conservative fix for now. */
+      ret = gst_pad_query_default (pad, parent, query);
+      break;
+    default:
+      ret = FALSE;
+      break;
+  }
+
+  return ret;
+}
+
+
+static gboolean
+gst_image_freeze_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstImageFreeze *self = GST_IMAGE_FREEZE (parent);
+  gboolean ret;
+
+  GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      gst_image_freeze_sink_setcaps (self, caps);
+      gst_event_unref (event);
+      ret = TRUE;
+      break;
+    }
+    case GST_EVENT_EOS:
+      if (!self->buffer) {
+        /* if we receive EOS before a buffer arrives, then let it pass */
+        GST_DEBUG_OBJECT (self, "EOS without input buffer, passing on");
+        ret = gst_pad_push_event (self->srcpad, event);
+        break;
+      }
+      /* fall-through */
+    case GST_EVENT_SEGMENT:
+      GST_DEBUG_OBJECT (pad, "Dropping event");
+      gst_event_unref (event);
+      ret = TRUE;
+      break;
+    case GST_EVENT_FLUSH_START:
+      gst_image_freeze_reset (self);
+      /* fall through */
+    default:
+      ret = gst_pad_push_event (self->srcpad, event);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_image_freeze_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstImageFreeze *self = GST_IMAGE_FREEZE (parent);
+  gboolean ret;
+
+  GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_NAVIGATION:
+    case GST_EVENT_QOS:
+    case GST_EVENT_LATENCY:
+    case GST_EVENT_STEP:
+      GST_DEBUG_OBJECT (pad, "Dropping event");
+      gst_event_unref (event);
+      ret = TRUE;
+      break;
+    case GST_EVENT_SEEK:{
+      gdouble rate;
+      GstFormat format;
+      GstSeekFlags flags;
+      GstSeekType start_type, stop_type;
+      gint64 start, stop;
+      gint64 last_stop;
+      gboolean start_task;
+      gboolean flush;
+      guint32 seqnum;
+
+      seqnum = gst_event_get_seqnum (event);
+      gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
+          &stop_type, &stop);
+      gst_event_unref (event);
+
+      flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
+
+      if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) {
+        GST_ERROR_OBJECT (pad, "Seek in invalid format: %s",
+            gst_format_get_name (format));
+        ret = FALSE;
+        break;
+      }
+
+      if (format == GST_FORMAT_DEFAULT) {
+        format = GST_FORMAT_TIME;
+        if (!gst_image_freeze_convert (self, GST_FORMAT_DEFAULT, start, &format,
+                &start)
+            || !gst_image_freeze_convert (self, GST_FORMAT_DEFAULT, stop,
+                &format, &stop)
+            || start == -1 || stop == -1) {
+          GST_ERROR_OBJECT (pad,
+              "Failed to convert seek from DEFAULT format into TIME format");
+          ret = FALSE;
+          break;
+        }
+      }
+
+      if (flush) {
+        GstEvent *e;
+
+        g_atomic_int_set (&self->seeking, 1);
+        e = gst_event_new_flush_start ();
+        gst_event_set_seqnum (e, seqnum);
+        gst_pad_push_event (self->srcpad, e);
+      } else {
+        gst_pad_pause_task (self->srcpad);
+      }
+
+      GST_PAD_STREAM_LOCK (self->srcpad);
+
+      g_mutex_lock (&self->lock);
+
+      gst_segment_do_seek (&self->segment, rate, format, flags, start_type,
+          start, stop_type, stop, NULL);
+      self->need_segment = TRUE;
+      last_stop = self->segment.position;
+
+      start_task = self->buffer != NULL;
+      g_mutex_unlock (&self->lock);
+
+      if (flush) {
+        GstEvent *e;
+
+        e = gst_event_new_flush_stop (TRUE);
+        gst_event_set_seqnum (e, seqnum);
+        gst_pad_push_event (self->srcpad, e);
+        g_atomic_int_set (&self->seeking, 0);
+      }
+
+      if (flags & GST_SEEK_FLAG_SEGMENT) {
+        GstMessage *m;
+
+        m = gst_message_new_segment_start (GST_OBJECT (self),
+            format, last_stop);
+        gst_element_post_message (GST_ELEMENT (self), m);
+      }
+
+      self->seqnum = seqnum;
+      GST_PAD_STREAM_UNLOCK (self->srcpad);
+
+      GST_DEBUG_OBJECT (pad, "Seek successful");
+
+      if (start_task) {
+        g_mutex_lock (&self->lock);
+
+        if (self->buffer != NULL)
+          gst_pad_start_task (self->srcpad,
+              (GstTaskFunction) gst_image_freeze_src_loop, self->srcpad, NULL);
+
+        g_mutex_unlock (&self->lock);
+      }
+
+      ret = TRUE;
+      break;
+    }
+    case GST_EVENT_FLUSH_START:
+      gst_image_freeze_reset (self);
+      /* fall through */
+    default:
+      ret = gst_pad_push_event (self->sinkpad, event);
+      break;
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_image_freeze_sink_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer)
+{
+  GstImageFreeze *self = GST_IMAGE_FREEZE (parent);
+
+  g_mutex_lock (&self->lock);
+  if (self->buffer) {
+    GST_DEBUG_OBJECT (pad, "Already have a buffer, dropping");
+    gst_buffer_unref (buffer);
+    g_mutex_unlock (&self->lock);
+    return GST_FLOW_EOS;
+  }
+
+  self->buffer = buffer;
+
+  gst_pad_start_task (self->srcpad, (GstTaskFunction) gst_image_freeze_src_loop,
+      self->srcpad, NULL);
+  g_mutex_unlock (&self->lock);
+  return GST_FLOW_EOS;
+}
+
+static void
+gst_image_freeze_src_loop (GstPad * pad)
+{
+  GstImageFreeze *self = GST_IMAGE_FREEZE (GST_PAD_PARENT (pad));
+  GstBuffer *buffer;
+  guint64 offset;
+  GstClockTime timestamp, timestamp_end;
+  guint64 cstart, cstop;
+  gboolean in_seg, eos;
+  GstFlowReturn flow_ret = GST_FLOW_OK;
+
+  g_mutex_lock (&self->lock);
+  if (!gst_pad_has_current_caps (self->srcpad)) {
+    GST_ERROR_OBJECT (pad, "Not negotiated yet");
+    flow_ret = GST_FLOW_NOT_NEGOTIATED;
+    g_mutex_unlock (&self->lock);
+    goto pause_task;
+  }
+
+  if (!self->buffer) {
+    GST_ERROR_OBJECT (pad, "Have no buffer yet");
+    flow_ret = GST_FLOW_ERROR;
+    g_mutex_unlock (&self->lock);
+    goto pause_task;
+  }
+  buffer = gst_buffer_copy (self->buffer);
+
+  g_mutex_unlock (&self->lock);
+
+  if (self->need_segment) {
+    GstEvent *e;
+
+    GST_DEBUG_OBJECT (pad, "Pushing SEGMENT event: %" GST_SEGMENT_FORMAT,
+        &self->segment);
+    e = gst_event_new_segment (&self->segment);
+
+    if (self->seqnum)
+      gst_event_set_seqnum (e, self->seqnum);
+
+    g_mutex_lock (&self->lock);
+    if (self->segment.rate >= 0) {
+      self->offset =
+          gst_util_uint64_scale (self->segment.start, self->fps_n,
+          self->fps_d * GST_SECOND);
+    } else {
+      self->offset =
+          gst_util_uint64_scale (self->segment.stop, self->fps_n,
+          self->fps_d * GST_SECOND);
+    }
+    g_mutex_unlock (&self->lock);
+
+    self->need_segment = FALSE;
+
+    gst_pad_push_event (self->srcpad, e);
+  }
+
+  g_mutex_lock (&self->lock);
+  offset = self->offset;
+
+  if (self->fps_n != 0) {
+    timestamp =
+        gst_util_uint64_scale (offset, self->fps_d * GST_SECOND, self->fps_n);
+    timestamp_end =
+        gst_util_uint64_scale (offset + 1, self->fps_d * GST_SECOND,
+        self->fps_n);
+  } else {
+    timestamp = self->segment.start;
+    timestamp_end = GST_CLOCK_TIME_NONE;
+  }
+
+  eos = (self->fps_n == 0 && offset > 0) ||
+      (self->segment.rate >= 0 && self->segment.stop != -1
+      && timestamp > self->segment.stop) || (self->segment.rate < 0
+      && offset == 0) || (self->segment.rate < 0
+      && self->segment.start != -1 && timestamp_end < self->segment.start);
+
+  if (self->fps_n == 0 && offset > 0)
+    in_seg = FALSE;
+  else
+    in_seg =
+        gst_segment_clip (&self->segment, GST_FORMAT_TIME, timestamp,
+        timestamp_end, &cstart, &cstop);
+
+  if (in_seg) {
+    self->segment.position = cstart;
+    if (self->segment.rate >= 0)
+      self->segment.position = cstop;
+  }
+
+  if (self->segment.rate >= 0)
+    self->offset++;
+  else
+    self->offset--;
+  g_mutex_unlock (&self->lock);
+
+  GST_DEBUG_OBJECT (pad, "Handling buffer with timestamp %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (in_seg) {
+    GST_BUFFER_DTS (buffer) = GST_CLOCK_TIME_NONE;
+    GST_BUFFER_PTS (buffer) = cstart;
+    GST_BUFFER_DURATION (buffer) = cstop - cstart;
+    GST_BUFFER_OFFSET (buffer) = offset;
+    GST_BUFFER_OFFSET_END (buffer) = offset + 1;
+    flow_ret = gst_pad_push (self->srcpad, buffer);
+    GST_DEBUG_OBJECT (pad, "Pushing buffer resulted in %s",
+        gst_flow_get_name (flow_ret));
+    if (flow_ret != GST_FLOW_OK)
+      goto pause_task;
+  } else {
+    gst_buffer_unref (buffer);
+  }
+
+  if (eos) {
+    flow_ret = GST_FLOW_EOS;
+    goto pause_task;
+  }
+
+  return;
+
+pause_task:
+  {
+    const gchar *reason = gst_flow_get_name (flow_ret);
+
+    GST_LOG_OBJECT (self, "pausing task, reason %s", reason);
+    gst_pad_pause_task (pad);
+
+    if (flow_ret == GST_FLOW_EOS) {
+      if ((self->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
+        GstMessage *m;
+        GstEvent *e;
+
+        GST_DEBUG_OBJECT (pad, "Sending segment done at end of segment");
+        if (self->segment.rate >= 0) {
+          m = gst_message_new_segment_done (GST_OBJECT_CAST (self),
+              GST_FORMAT_TIME, self->segment.stop);
+          e = gst_event_new_segment_done (GST_FORMAT_TIME, self->segment.stop);
+        } else {
+          m = gst_message_new_segment_done (GST_OBJECT_CAST (self),
+              GST_FORMAT_TIME, self->segment.start);
+          e = gst_event_new_segment_done (GST_FORMAT_TIME, self->segment.start);
+        }
+        gst_element_post_message (GST_ELEMENT_CAST (self), m);
+        gst_pad_push_event (self->srcpad, e);
+      } else {
+        GstEvent *e = gst_event_new_eos ();
+
+        GST_DEBUG_OBJECT (pad, "Sending EOS at end of segment");
+
+        if (self->seqnum)
+          gst_event_set_seqnum (e, self->seqnum);
+        gst_pad_push_event (self->srcpad, e);
+      }
+    } else if (flow_ret == GST_FLOW_NOT_LINKED || flow_ret < GST_FLOW_EOS) {
+      GstEvent *e = gst_event_new_eos ();
+
+      GST_ELEMENT_FLOW_ERROR (self, flow_ret);
+
+      if (self->seqnum)
+        gst_event_set_seqnum (e, self->seqnum);
+
+      gst_pad_push_event (self->srcpad, e);
+    }
+    return;
+  }
+}
+
+static GstStateChangeReturn
+gst_image_freeze_change_state (GstElement * element, GstStateChange transition)
+{
+  GstImageFreeze *self = GST_IMAGE_FREEZE (element);
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_image_freeze_reset (self);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_pad_stop_task (self->srcpad);
+      gst_image_freeze_reset (self);
+      break;
+    default:
+      break;
+  }
+
+  if (GST_ELEMENT_CLASS (parent_class)->change_state)
+    ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_image_freeze_debug, "imagefreeze", 0,
+      "imagefreeze element");
+
+  if (!gst_element_register (plugin, "imagefreeze", GST_RANK_NONE,
+          GST_TYPE_IMAGE_FREEZE))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    imagefreeze,
+    "Still frame stream generator",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/imagefreeze/gstimagefreeze.h b/gst/imagefreeze/gstimagefreeze.h
new file mode 100644
index 0000000..19e803b
--- /dev/null
+++ b/gst/imagefreeze/gstimagefreeze.h
@@ -0,0 +1,74 @@
+/* GStreamer
+ * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_IMAGE_FREEZE_H__
+#define __GST_IMAGE_FREEZE_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_IMAGE_FREEZE \
+  (gst_image_freeze_get_type())
+#define GST_IMAGE_FREEZE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_IMAGE_FREEZE,GstImageFreeze))
+#define GST_IMAGE_FREEZE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_IMAGE_FREEZE,GstImageFreezeClass))
+#define GST_IMAGE_FREEZE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_IMAGE_FREEZE,GstImageFreezeClass))
+#define GST_IS_IMAGE_FREEZE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_IMAGE_FREEZE))
+#define GST_IS_IMAGE_FREEZE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_IMAGE_FREEZE))
+
+typedef struct _GstImageFreeze GstImageFreeze;
+typedef struct _GstImageFreezeClass GstImageFreezeClass;
+
+struct _GstImageFreeze
+{
+  GstElement parent;
+
+  /* < private > */
+  GstPad *sinkpad;
+  GstPad *srcpad;
+
+  GMutex lock;
+  GstBuffer *buffer;
+  gint fps_n, fps_d;
+
+  GstSegment segment;
+  gboolean need_segment;
+  guint seqnum;
+
+  guint64 offset;
+
+  /* TRUE if currently doing a flushing seek, protected
+   * by srcpad's stream lock */
+  gint seeking;
+};
+
+struct _GstImageFreezeClass
+{
+  GstElementClass parent_class;
+};
+
+GType gst_image_freeze_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_IMAGE_FREEZE_H__ */
diff --git a/gst/imagefreeze/meson.build b/gst/imagefreeze/meson.build
new file mode 100644
index 0000000..7af6a03
--- /dev/null
+++ b/gst/imagefreeze/meson.build
@@ -0,0 +1,8 @@
+gstimagefreeze = library('gstimagefreeze',
+  'gstimagefreeze.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc, libsinc],
+  dependencies : glib_deps + [gst_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/interleave/Makefile.am b/gst/interleave/Makefile.am
new file mode 100644
index 0000000..2128d3e
--- /dev/null
+++ b/gst/interleave/Makefile.am
@@ -0,0 +1,9 @@
+
+plugin_LTLIBRARIES = libgstinterleave.la
+
+libgstinterleave_la_SOURCES = plugin.c interleave.c deinterleave.c
+libgstinterleave_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstinterleave_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(GST_BASE_LIBS) $(GST_LIBS)
+libgstinterleave_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = plugin.h interleave.h deinterleave.h
diff --git a/gst/interleave/deinterleave.c b/gst/interleave/deinterleave.c
new file mode 100644
index 0000000..4897449
--- /dev/null
+++ b/gst/interleave/deinterleave.c
@@ -0,0 +1,1019 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wtay@chello.be>
+ *                    2005 Wim Taymans <wim@fluendo.com>
+ *                    2007 Andy Wingo <wingo at pobox.com>
+ *                    2008 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * deinterleave.c: deinterleave samples
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* TODO: 
+ *       - handle changes in number of channels
+ *       - handle changes in channel positions
+ *       - better capsnego by using a buffer alloc function
+ *         and passing downstream caps changes upstream there
+ */
+
+/**
+ * SECTION:element-deinterleave
+ * @see_also: interleave
+ *
+ * Splits one interleaved multichannel audio stream into many mono audio streams.
+ * 
+ * This element handles all raw audio formats and supports changing the input caps as long as
+ * all downstream elements can handle the new caps and the number of channels and the channel
+ * positions stay the same. This restriction will be removed in later versions by adding or
+ * removing some source pads as required.
+ * 
+ * In most cases a queue and an audioconvert element should be added after each source pad
+ * before further processing of the audio data.
+ * 
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=/path/to/file.mp3 ! decodebin ! audioconvert ! "audio/x-raw,channels=2 ! deinterleave name=d  d.src_0 ! queue ! audioconvert ! vorbisenc ! oggmux ! filesink location=channel1.ogg  d.src_1 ! queue ! audioconvert ! vorbisenc ! oggmux ! filesink location=channel2.ogg
+ * ]| Decodes an MP3 file and encodes the left and right channel into separate
+ * Ogg Vorbis files.
+ * |[
+ * gst-launch-1.0 filesrc location=file.mp3 ! decodebin ! audioconvert ! "audio/x-raw,channels=2" ! deinterleave name=d  interleave name=i ! audioconvert ! wavenc ! filesink location=test.wav    d.src_0 ! queue ! audioconvert ! i.sink_1    d.src_1 ! queue ! audioconvert ! i.sink_0
+ * ]| Decodes and deinterleaves a Stereo MP3 file into separate channels and
+ * then interleaves the channels again to a WAV file with the channel with the
+ * channels exchanged.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <string.h>
+#include "deinterleave.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_deinterleave_debug);
+#define GST_CAT_DEFAULT gst_deinterleave_debug
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_FORMATS_ALL ", "
+        "rate = (int) [ 1, MAX ], "
+        "channels = (int) 1, layout = (string) {non-interleaved, interleaved}"));
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_FORMATS_ALL ", "
+        "rate = (int) [ 1, MAX ], "
+        "channels = (int) [ 1, MAX ], layout = (string) interleaved"));
+
+#define MAKE_FUNC(type) \
+static void deinterleave_##type (guint##type *out, guint##type *in, \
+    guint stride, guint nframes) \
+{ \
+  gint i; \
+  \
+  for (i = 0; i < nframes; i++) { \
+    out[i] = *in; \
+    in += stride; \
+  } \
+}
+
+MAKE_FUNC (8);
+MAKE_FUNC (16);
+MAKE_FUNC (32);
+MAKE_FUNC (64);
+
+static void
+deinterleave_24 (guint8 * out, guint8 * in, guint stride, guint nframes)
+{
+  gint i;
+
+  for (i = 0; i < nframes; i++) {
+    memcpy (out, in, 3);
+    out += 3;
+    in += stride * 3;
+  }
+}
+
+#define gst_deinterleave_parent_class parent_class
+G_DEFINE_TYPE (GstDeinterleave, gst_deinterleave, GST_TYPE_ELEMENT);
+
+enum
+{
+  PROP_0,
+  PROP_KEEP_POSITIONS
+};
+
+static GstFlowReturn gst_deinterleave_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer);
+
+static gboolean gst_deinterleave_sink_setcaps (GstDeinterleave * self,
+    GstCaps * caps);
+
+static GstStateChangeReturn
+gst_deinterleave_change_state (GstElement * element, GstStateChange transition);
+
+static gboolean gst_deinterleave_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static gboolean gst_deinterleave_sink_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+
+static gboolean gst_deinterleave_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+
+static void gst_deinterleave_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_deinterleave_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+
+static void
+gst_deinterleave_finalize (GObject * obj)
+{
+  GstDeinterleave *self = GST_DEINTERLEAVE (obj);
+
+  if (self->pending_events) {
+    g_list_foreach (self->pending_events, (GFunc) gst_mini_object_unref, NULL);
+    g_list_free (self->pending_events);
+    self->pending_events = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gst_deinterleave_class_init (GstDeinterleaveClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (gst_deinterleave_debug, "deinterleave", 0,
+      "deinterleave element");
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Audio deinterleaver", "Filter/Converter/Audio",
+      "Splits one interleaved multichannel audio stream into many mono audio streams",
+      "Andy Wingo <wingo at pobox.com>, " "Iain <iain@prettypeople.org>, "
+      "Sebastian Dröge <slomo@circular-chaos.org>");
+
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class, &src_template);
+
+  gstelement_class->change_state = gst_deinterleave_change_state;
+
+  gobject_class->finalize = gst_deinterleave_finalize;
+  gobject_class->set_property = gst_deinterleave_set_property;
+  gobject_class->get_property = gst_deinterleave_get_property;
+
+  /**
+   * GstDeinterleave:keep-positions
+   * 
+   * Keep positions: When enable the caps on the output buffers will
+   * contain the original channel positions. This can be used to correctly
+   * interleave the output again later but can also lead to unwanted effects
+   * if the output should be handled as Mono.
+   *
+   */
+  g_object_class_install_property (gobject_class, PROP_KEEP_POSITIONS,
+      g_param_spec_boolean ("keep-positions", "Keep positions",
+          "Keep the original channel positions on the output buffers",
+          FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_deinterleave_init (GstDeinterleave * self)
+{
+  self->keep_positions = FALSE;
+  self->func = NULL;
+  gst_audio_info_init (&self->audio_info);
+
+  /* Add sink pad */
+  self->sink = gst_pad_new_from_static_template (&sink_template, "sink");
+  gst_pad_set_chain_function (self->sink,
+      GST_DEBUG_FUNCPTR (gst_deinterleave_chain));
+  gst_pad_set_event_function (self->sink,
+      GST_DEBUG_FUNCPTR (gst_deinterleave_sink_event));
+  gst_pad_set_query_function (self->sink,
+      GST_DEBUG_FUNCPTR (gst_deinterleave_sink_query));
+  gst_element_add_pad (GST_ELEMENT (self), self->sink);
+}
+
+typedef struct
+{
+  GstCaps *caps;
+  GstPad *pad;
+} CopyStickyEventsData;
+
+static gboolean
+copy_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
+{
+  CopyStickyEventsData *data = user_data;
+
+  if (GST_EVENT_TYPE (*event) >= GST_EVENT_CAPS && data->caps) {
+    gst_pad_set_caps (data->pad, data->caps);
+    data->caps = NULL;
+  }
+
+  if (GST_EVENT_TYPE (*event) != GST_EVENT_CAPS)
+    gst_pad_push_event (data->pad, gst_event_ref (*event));
+
+  return TRUE;
+}
+
+static void
+gst_deinterleave_add_new_pads (GstDeinterleave * self, GstCaps * caps)
+{
+  GstPad *pad;
+  guint i;
+
+  for (i = 0; i < GST_AUDIO_INFO_CHANNELS (&self->audio_info); i++) {
+    gchar *name = g_strdup_printf ("src_%u", i);
+    GstCaps *srccaps;
+    GstAudioInfo info;
+    GstAudioFormat format = GST_AUDIO_INFO_FORMAT (&self->audio_info);
+    gint rate = GST_AUDIO_INFO_RATE (&self->audio_info);
+    GstAudioChannelPosition position = GST_AUDIO_CHANNEL_POSITION_MONO;
+    CopyStickyEventsData data;
+
+    /* Set channel position if we know it */
+    if (self->keep_positions)
+      position = GST_AUDIO_INFO_POSITION (&self->audio_info, i);
+
+    gst_audio_info_init (&info);
+    gst_audio_info_set_format (&info, format, rate, 1, &position);
+
+    srccaps = gst_audio_info_to_caps (&info);
+
+    pad = gst_pad_new_from_static_template (&src_template, name);
+    g_free (name);
+
+    gst_pad_use_fixed_caps (pad);
+    gst_pad_set_query_function (pad,
+        GST_DEBUG_FUNCPTR (gst_deinterleave_src_query));
+    gst_pad_set_active (pad, TRUE);
+
+    data.pad = pad;
+    data.caps = srccaps;
+    gst_pad_sticky_events_foreach (self->sink, copy_sticky_events, &data);
+    if (data.caps)
+      gst_pad_set_caps (pad, data.caps);
+    gst_element_add_pad (GST_ELEMENT (self), pad);
+    self->srcpads = g_list_prepend (self->srcpads, gst_object_ref (pad));
+
+    gst_caps_unref (srccaps);
+  }
+
+  gst_element_no_more_pads (GST_ELEMENT (self));
+  self->srcpads = g_list_reverse (self->srcpads);
+}
+
+static gboolean
+gst_deinterleave_set_pads_caps (GstDeinterleave * self, GstCaps * caps)
+{
+  GList *l;
+  gint i;
+  gboolean ret = TRUE;
+
+  for (l = self->srcpads, i = 0; l; l = l->next, i++) {
+    GstPad *pad = GST_PAD (l->data);
+    GstCaps *srccaps;
+    GstAudioInfo info;
+
+    if (!gst_audio_info_from_caps (&info, caps)) {
+      ret = FALSE;
+      continue;
+    }
+    if (self->keep_positions)
+      GST_AUDIO_INFO_POSITION (&info, 0) =
+          GST_AUDIO_INFO_POSITION (&self->audio_info, i);
+
+    srccaps = gst_audio_info_to_caps (&info);
+
+    gst_pad_set_caps (pad, srccaps);
+    gst_caps_unref (srccaps);
+  }
+  return ret;
+}
+
+static void
+gst_deinterleave_remove_pads (GstDeinterleave * self)
+{
+  GList *l;
+
+  GST_INFO_OBJECT (self, "removing pads");
+
+  for (l = self->srcpads; l; l = l->next) {
+    GstPad *pad = GST_PAD (l->data);
+
+    gst_element_remove_pad (GST_ELEMENT_CAST (self), pad);
+    gst_object_unref (pad);
+  }
+  g_list_free (self->srcpads);
+  self->srcpads = NULL;
+
+  gst_caps_replace (&self->sinkcaps, NULL);
+}
+
+static gboolean
+gst_deinterleave_set_process_function (GstDeinterleave * self)
+{
+  switch (GST_AUDIO_INFO_WIDTH (&self->audio_info)) {
+    case 8:
+      self->func = (GstDeinterleaveFunc) deinterleave_8;
+      break;
+    case 16:
+      self->func = (GstDeinterleaveFunc) deinterleave_16;
+      break;
+    case 24:
+      self->func = (GstDeinterleaveFunc) deinterleave_24;
+      break;
+    case 32:
+      self->func = (GstDeinterleaveFunc) deinterleave_32;
+      break;
+    case 64:
+      self->func = (GstDeinterleaveFunc) deinterleave_64;
+      break;
+    default:
+      return FALSE;
+  }
+  return TRUE;
+}
+
+static gboolean
+gst_deinterleave_check_caps_change (GstDeinterleave * self,
+    GstAudioInfo * old_info, GstAudioInfo * new_info)
+{
+  gint i;
+  gboolean same_layout = TRUE;
+  gboolean was_unpositioned;
+  gboolean is_unpositioned = GST_AUDIO_INFO_IS_UNPOSITIONED (new_info);
+  gint new_channels = GST_AUDIO_INFO_CHANNELS (new_info);
+  gint old_channels;
+
+  was_unpositioned = GST_AUDIO_INFO_IS_UNPOSITIONED (old_info);
+  old_channels = GST_AUDIO_INFO_CHANNELS (old_info);
+
+  /* We allow caps changes as long as the number of channels doesn't change
+   * and the channel positions stay the same. _getcaps() should've cared
+   * for this already but better be safe.
+   */
+  if (new_channels != old_channels)
+    goto cannot_change_caps;
+
+  /* Now check the channel positions. If we had no channel positions
+   * and get them or the other way around things have changed.
+   * If we had channel positions and get different ones things have
+   * changed too of course
+   */
+  if ((!was_unpositioned && is_unpositioned) || (was_unpositioned
+          && !is_unpositioned))
+    goto cannot_change_caps;
+
+  if (!is_unpositioned) {
+    if (GST_AUDIO_INFO_CHANNELS (old_info) !=
+        GST_AUDIO_INFO_CHANNELS (new_info))
+      goto cannot_change_caps;
+    for (i = 0; i < GST_AUDIO_INFO_CHANNELS (old_info); i++) {
+      if (new_info->position[i] != old_info->position[i]) {
+        same_layout = FALSE;
+        break;
+      }
+    }
+    if (!same_layout)
+      goto cannot_change_caps;
+  }
+
+  return TRUE;
+
+cannot_change_caps:
+  return FALSE;
+}
+
+static gboolean
+gst_deinterleave_sink_setcaps (GstDeinterleave * self, GstCaps * caps)
+{
+  GstCaps *srccaps;
+  GstStructure *s;
+
+  GST_DEBUG_OBJECT (self, "got caps: %" GST_PTR_FORMAT, caps);
+
+  if (!gst_audio_info_from_caps (&self->audio_info, caps))
+    goto invalid_caps;
+
+  if (!gst_deinterleave_set_process_function (self))
+    goto unsupported_caps;
+
+  if (self->sinkcaps && !gst_caps_is_equal (caps, self->sinkcaps)) {
+    GstAudioInfo old_info;
+
+    gst_audio_info_init (&old_info);
+    if (!gst_audio_info_from_caps (&old_info, self->sinkcaps))
+      goto info_from_caps_failed;
+
+    if (gst_deinterleave_check_caps_change (self, &old_info, &self->audio_info)) {
+      if (!gst_deinterleave_set_process_function (self))
+        goto cannot_change_caps;
+    } else
+      goto cannot_change_caps;
+
+  }
+
+  gst_caps_replace (&self->sinkcaps, caps);
+
+  /* Get srcpad caps */
+  srccaps = gst_caps_copy (caps);
+  s = gst_caps_get_structure (srccaps, 0);
+  gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
+  gst_structure_remove_field (s, "channel-mask");
+
+  /* If we already have pads, update the caps otherwise
+   * add new pads */
+  if (self->srcpads) {
+    if (!gst_deinterleave_set_pads_caps (self, srccaps))
+      goto set_caps_failed;
+  } else {
+    gst_deinterleave_add_new_pads (self, srccaps);
+  }
+
+  gst_caps_unref (srccaps);
+
+  return TRUE;
+
+cannot_change_caps:
+  {
+    GST_WARNING_OBJECT (self, "caps change from %" GST_PTR_FORMAT
+        " to %" GST_PTR_FORMAT " not supported: channel number or channel "
+        "positions change", self->sinkcaps, caps);
+    return FALSE;
+  }
+unsupported_caps:
+  {
+    GST_ERROR_OBJECT (self, "caps not supported: %" GST_PTR_FORMAT, caps);
+    return FALSE;
+  }
+invalid_caps:
+  {
+    GST_ERROR_OBJECT (self, "invalid caps");
+    return FALSE;
+  }
+set_caps_failed:
+  {
+    GST_ERROR_OBJECT (self, "set_caps failed");
+    gst_caps_unref (srccaps);
+    return FALSE;
+  }
+info_from_caps_failed:
+  {
+    GST_ERROR_OBJECT (self, "coud not get info from caps");
+    return FALSE;
+  }
+}
+
+static void
+__remove_channels (GstCaps * caps)
+{
+  GstStructure *s;
+  gint i, size;
+
+  size = gst_caps_get_size (caps);
+  for (i = 0; i < size; i++) {
+    s = gst_caps_get_structure (caps, i);
+    gst_structure_remove_field (s, "channel-mask");
+    gst_structure_remove_field (s, "channels");
+  }
+}
+
+static void
+__set_channels (GstCaps * caps, gint channels)
+{
+  GstStructure *s;
+  gint i, size;
+
+  size = gst_caps_get_size (caps);
+  for (i = 0; i < size; i++) {
+    s = gst_caps_get_structure (caps, i);
+    if (channels > 0)
+      gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL);
+    else
+      gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
+  }
+}
+
+static gboolean
+gst_deinterleave_sink_acceptcaps (GstPad * pad, GstObject * parent,
+    GstCaps * caps)
+{
+  GstDeinterleave *self = GST_DEINTERLEAVE (parent);
+  GstCaps *templ_caps = gst_pad_get_pad_template_caps (pad);
+  gboolean ret;
+
+  ret = gst_caps_can_intersect (templ_caps, caps);
+  gst_caps_unref (templ_caps);
+  if (ret && self->sinkcaps) {
+    GstAudioInfo new_info;
+
+    gst_audio_info_init (&new_info);
+    if (!gst_audio_info_from_caps (&new_info, caps))
+      goto info_from_caps_failed;
+    ret =
+        gst_deinterleave_check_caps_change (self, &self->audio_info, &new_info);
+  }
+
+  return ret;
+
+info_from_caps_failed:
+  {
+    GST_ERROR_OBJECT (self, "coud not get info from caps");
+    return FALSE;
+  }
+}
+
+static GstCaps *
+gst_deinterleave_getcaps (GstPad * pad, GstObject * parent, GstCaps * filter)
+{
+  GstDeinterleave *self = GST_DEINTERLEAVE (parent);
+  GstCaps *ret;
+  GstIterator *it;
+  GstIteratorResult res;
+  GValue v = G_VALUE_INIT;
+
+  if (pad != self->sink) {
+    ret = gst_pad_get_current_caps (pad);
+    if (ret) {
+      if (filter) {
+        GstCaps *tmp =
+            gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
+        gst_caps_unref (ret);
+        ret = tmp;
+      }
+      return ret;
+    }
+  }
+
+  /* Intersect all of our pad template caps with the peer caps of the pad
+   * to get all formats that are possible up- and downstream.
+   *
+   * For the pad for which the caps are requested we don't remove the channel
+   * informations as they must be in the returned caps and incompatibilities
+   * will be detected here already
+   */
+  ret = gst_caps_new_any ();
+  it = gst_element_iterate_pads (GST_ELEMENT_CAST (self));
+
+  do {
+    res = gst_iterator_next (it, &v);
+    switch (res) {
+      case GST_ITERATOR_OK:{
+        GstPad *ourpad = GST_PAD (g_value_get_object (&v));
+        GstCaps *peercaps = NULL, *ourcaps;
+        GstCaps *templ_caps = gst_pad_get_pad_template_caps (ourpad);
+
+        ourcaps = gst_caps_copy (templ_caps);
+        gst_caps_unref (templ_caps);
+
+        if (pad == ourpad) {
+          if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK)
+            __set_channels (ourcaps,
+                GST_AUDIO_INFO_CHANNELS (&self->audio_info));
+          else
+            __set_channels (ourcaps, 1);
+        } else {
+          __remove_channels (ourcaps);
+          /* Only ask for peer caps for other pads than pad
+           * as otherwise gst_pad_peer_get_caps() might call
+           * back into this function and deadlock
+           */
+          peercaps = gst_pad_peer_query_caps (ourpad, NULL);
+          peercaps = gst_caps_make_writable (peercaps);
+        }
+
+        /* If the peer exists and has caps add them to the intersection,
+         * otherwise assume that the peer accepts everything */
+        if (peercaps) {
+          GstCaps *intersection;
+          GstCaps *oldret = ret;
+
+          __remove_channels (peercaps);
+
+          intersection = gst_caps_intersect (peercaps, ourcaps);
+
+          ret = gst_caps_intersect (ret, intersection);
+          gst_caps_unref (intersection);
+          gst_caps_unref (peercaps);
+          gst_caps_unref (oldret);
+        } else {
+          GstCaps *oldret = ret;
+
+          ret = gst_caps_intersect (ret, ourcaps);
+          gst_caps_unref (oldret);
+        }
+        gst_caps_unref (ourcaps);
+        g_value_reset (&v);
+        break;
+      }
+      case GST_ITERATOR_DONE:
+        break;
+      case GST_ITERATOR_ERROR:
+        gst_caps_unref (ret);
+        ret = gst_caps_new_empty ();
+        break;
+      case GST_ITERATOR_RESYNC:
+        gst_caps_unref (ret);
+        ret = gst_caps_new_any ();
+        gst_iterator_resync (it);
+        break;
+    }
+  } while (res != GST_ITERATOR_DONE && res != GST_ITERATOR_ERROR);
+  g_value_unset (&v);
+  gst_iterator_free (it);
+
+  if (filter) {
+    GstCaps *aux;
+
+    aux = gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (ret);
+    ret = aux;
+  }
+
+  GST_DEBUG_OBJECT (pad, "Intersected caps to %" GST_PTR_FORMAT, ret);
+
+  return ret;
+}
+
+static gboolean
+gst_deinterleave_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstDeinterleave *self = GST_DEINTERLEAVE (parent);
+  gboolean ret;
+
+  GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
+      GST_DEBUG_PAD_NAME (pad));
+
+  /* Send FLUSH_STOP, FLUSH_START and EOS immediately, no matter if
+   * we have src pads already or not. Queue all other events and
+   * push them after we have src pads
+   */
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+    case GST_EVENT_FLUSH_START:
+    case GST_EVENT_EOS:
+      ret = gst_pad_event_default (pad, parent, event);
+      break;
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      ret = gst_deinterleave_sink_setcaps (self, caps);
+      gst_event_unref (event);
+      break;
+    }
+
+    default:
+      if (!self->srcpads && !GST_EVENT_IS_STICKY (event)) {
+        /* Sticky events are copied when creating a new pad */
+        GST_OBJECT_LOCK (self);
+        self->pending_events = g_list_append (self->pending_events, event);
+        GST_OBJECT_UNLOCK (self);
+        ret = TRUE;
+      } else {
+        ret = gst_pad_event_default (pad, parent, event);
+      }
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_deinterleave_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  gboolean res;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:{
+      GstCaps *filter;
+      GstCaps *caps;
+
+      gst_query_parse_caps (query, &filter);
+      caps = gst_deinterleave_getcaps (pad, parent, filter);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+      res = TRUE;
+      break;
+    }
+    case GST_QUERY_ACCEPT_CAPS:{
+      GstCaps *caps;
+      gboolean ret;
+
+      gst_query_parse_accept_caps (query, &caps);
+      ret = gst_deinterleave_sink_acceptcaps (pad, parent, caps);
+      gst_query_set_accept_caps_result (query, ret);
+      res = TRUE;
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+
+  return res;
+}
+
+static gboolean
+gst_deinterleave_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  GstDeinterleave *self = GST_DEINTERLEAVE (parent);
+  gboolean res;
+
+  res = gst_pad_query_default (pad, parent, query);
+
+  if (res && GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
+    GstFormat format;
+    gint64 dur;
+
+    gst_query_parse_duration (query, &format, &dur);
+
+    /* Need to divide by the number of channels in byte format
+     * to get the correct value. All other formats should be fine
+     */
+    if (format == GST_FORMAT_BYTES && dur != -1)
+      gst_query_set_duration (query, format,
+          dur / GST_AUDIO_INFO_CHANNELS (&self->audio_info));
+  } else if (res && GST_QUERY_TYPE (query) == GST_QUERY_POSITION) {
+    GstFormat format;
+    gint64 pos;
+
+    gst_query_parse_position (query, &format, &pos);
+
+    /* Need to divide by the number of channels in byte format
+     * to get the correct value. All other formats should be fine
+     */
+    if (format == GST_FORMAT_BYTES && pos != -1)
+      gst_query_set_position (query, format,
+          pos / GST_AUDIO_INFO_CHANNELS (&self->audio_info));
+  } else if (res && GST_QUERY_TYPE (query) == GST_QUERY_CAPS) {
+    GstCaps *filter, *caps;
+
+    gst_query_parse_caps (query, &filter);
+    caps = gst_deinterleave_getcaps (pad, parent, filter);
+    gst_query_set_caps_result (query, caps);
+    gst_caps_unref (caps);
+  }
+
+  return res;
+}
+
+static void
+gst_deinterleave_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstDeinterleave *self = GST_DEINTERLEAVE (object);
+
+  switch (prop_id) {
+    case PROP_KEEP_POSITIONS:
+      self->keep_positions = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_deinterleave_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstDeinterleave *self = GST_DEINTERLEAVE (object);
+
+  switch (prop_id) {
+    case PROP_KEEP_POSITIONS:
+      g_value_set_boolean (value, self->keep_positions);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstFlowReturn
+gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint channels = GST_AUDIO_INFO_CHANNELS (&self->audio_info);
+  guint pads_pushed = 0, buffers_allocated = 0;
+  guint nframes =
+      gst_buffer_get_size (buf) / channels /
+      (GST_AUDIO_INFO_WIDTH (&self->audio_info) / 8);
+  guint bufsize = nframes * (GST_AUDIO_INFO_WIDTH (&self->audio_info) / 8);
+  guint i;
+  GList *srcs;
+  GstBuffer **buffers_out = g_new0 (GstBuffer *, channels);
+  guint8 *in, *out;
+  GstMapInfo read_info;
+  GList *pending_events, *l;
+
+  /* Send any pending events to all src pads */
+  GST_OBJECT_LOCK (self);
+  pending_events = self->pending_events;
+  self->pending_events = NULL;
+  GST_OBJECT_UNLOCK (self);
+
+  if (pending_events) {
+    GstEvent *event;
+
+    GST_DEBUG_OBJECT (self, "Sending pending events to all src pads");
+    for (l = pending_events; l; l = l->next) {
+      event = l->data;
+      for (srcs = self->srcpads; srcs != NULL; srcs = srcs->next)
+        gst_pad_push_event (GST_PAD (srcs->data), gst_event_ref (event));
+      gst_event_unref (event);
+    }
+    g_list_free (pending_events);
+  }
+
+  gst_buffer_map (buf, &read_info, GST_MAP_READ);
+
+  /* Allocate buffers */
+  for (srcs = self->srcpads, i = 0; srcs; srcs = srcs->next, i++) {
+    buffers_out[i] = gst_buffer_new_allocate (NULL, bufsize, NULL);
+
+    /* Make sure we got a correct buffer. The only other case we allow
+     * here is an unliked pad */
+    if (!buffers_out[i])
+      goto alloc_buffer_failed;
+    else if (buffers_out[i]
+        && gst_buffer_get_size (buffers_out[i]) != bufsize)
+      goto alloc_buffer_bad_size;
+
+    if (buffers_out[i]) {
+      gst_buffer_copy_into (buffers_out[i], buf, GST_BUFFER_COPY_METADATA, 0,
+          -1);
+      buffers_allocated++;
+    }
+  }
+
+  /* Return NOT_LINKED if no pad was linked */
+  if (!buffers_allocated) {
+    GST_WARNING_OBJECT (self,
+        "Couldn't allocate any buffers because no pad was linked");
+    ret = GST_FLOW_NOT_LINKED;
+    goto done;
+  }
+
+  /* deinterleave */
+  for (srcs = self->srcpads, i = 0; srcs; srcs = srcs->next, i++) {
+    GstPad *pad = (GstPad *) srcs->data;
+    GstMapInfo write_info;
+
+    in = (guint8 *) read_info.data;
+    in += i * (GST_AUDIO_INFO_WIDTH (&self->audio_info) / 8);
+    if (buffers_out[i]) {
+      gst_buffer_map (buffers_out[i], &write_info, GST_MAP_WRITE);
+      out = (guint8 *) write_info.data;
+      self->func (out, in, channels, nframes);
+      gst_buffer_unmap (buffers_out[i], &write_info);
+
+      ret = gst_pad_push (pad, buffers_out[i]);
+      buffers_out[i] = NULL;
+      if (ret == GST_FLOW_OK)
+        pads_pushed++;
+      else if (ret == GST_FLOW_NOT_LINKED)
+        ret = GST_FLOW_OK;
+      else
+        goto push_failed;
+    }
+  }
+
+  /* Return NOT_LINKED if no pad was linked */
+  if (!pads_pushed)
+    ret = GST_FLOW_NOT_LINKED;
+
+  GST_DEBUG_OBJECT (self, "Pushed on %d pads", pads_pushed);
+
+done:
+  gst_buffer_unmap (buf, &read_info);
+  gst_buffer_unref (buf);
+  g_free (buffers_out);
+  return ret;
+
+alloc_buffer_failed:
+  {
+    GST_WARNING ("gst_pad_alloc_buffer() returned %s", gst_flow_get_name (ret));
+    goto clean_buffers;
+
+  }
+alloc_buffer_bad_size:
+  {
+    GST_WARNING ("called alloc_buffer(), but didn't get requested bytes");
+    ret = GST_FLOW_NOT_NEGOTIATED;
+    goto clean_buffers;
+  }
+push_failed:
+  {
+    GST_DEBUG ("push() failed, flow = %s", gst_flow_get_name (ret));
+    goto clean_buffers;
+  }
+clean_buffers:
+  {
+    gst_buffer_unmap (buf, &read_info);
+    for (i = 0; i < channels; i++) {
+      if (buffers_out[i])
+        gst_buffer_unref (buffers_out[i]);
+    }
+    gst_buffer_unref (buf);
+    g_free (buffers_out);
+    return ret;
+  }
+}
+
+static GstFlowReturn
+gst_deinterleave_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstDeinterleave *self = GST_DEINTERLEAVE (parent);
+  GstFlowReturn ret;
+
+  g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED);
+  g_return_val_if_fail (GST_AUDIO_INFO_WIDTH (&self->audio_info) > 0,
+      GST_FLOW_NOT_NEGOTIATED);
+  g_return_val_if_fail (GST_AUDIO_INFO_CHANNELS (&self->audio_info) > 0,
+      GST_FLOW_NOT_NEGOTIATED);
+
+  ret = gst_deinterleave_process (self, buffer);
+
+  if (ret != GST_FLOW_OK)
+    GST_DEBUG_OBJECT (self, "flow return: %s", gst_flow_get_name (ret));
+
+  return ret;
+}
+
+static GstStateChangeReturn
+gst_deinterleave_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstDeinterleave *self = GST_DEINTERLEAVE (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_deinterleave_remove_pads (self);
+
+      self->func = NULL;
+
+      if (self->pending_events) {
+        g_list_foreach (self->pending_events, (GFunc) gst_mini_object_unref,
+            NULL);
+        g_list_free (self->pending_events);
+        self->pending_events = NULL;
+      }
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_deinterleave_remove_pads (self);
+
+      self->func = NULL;
+
+      if (self->pending_events) {
+        g_list_foreach (self->pending_events, (GFunc) gst_mini_object_unref,
+            NULL);
+        g_list_free (self->pending_events);
+        self->pending_events = NULL;
+      }
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
diff --git a/gst/interleave/deinterleave.h b/gst/interleave/deinterleave.h
new file mode 100644
index 0000000..07c1885
--- /dev/null
+++ b/gst/interleave/deinterleave.h
@@ -0,0 +1,73 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wtay@chello.be>
+ *                    2005 Wim Taymans <wim@fluendo.com>
+ *                    2007 Andy Wingo <wingo at pobox.com>
+ *                    2008 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * deinterleave.c: deinterleave samples
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __DEINTERLEAVE_H__
+#define __DEINTERLEAVE_H__
+
+G_BEGIN_DECLS
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+
+#define GST_TYPE_DEINTERLEAVE            (gst_deinterleave_get_type())
+#define GST_DEINTERLEAVE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DEINTERLEAVE,GstDeinterleave))
+#define GST_DEINTERLEAVE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DEINTERLEAVE,GstDeinterleaveClass))
+#define GST_DEINTERLEAVE_GET_CLASS(obj) \
+        (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_DEINTERLEAVE,GstDeinterleaveClass))
+#define GST_IS_DEINTERLEAVE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DEINTERLEAVE))
+#define GST_IS_DEINTERLEAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DEINTERLEAVE))
+
+typedef struct _GstDeinterleave GstDeinterleave;
+typedef struct _GstDeinterleaveClass GstDeinterleaveClass;
+
+typedef void (*GstDeinterleaveFunc) (gpointer out, gpointer in, guint stride, guint nframes);
+
+struct _GstDeinterleave
+{
+  GstElement element;
+
+  /*< private > */
+  GList *srcpads;
+  GstCaps *sinkcaps;
+  GstAudioInfo audio_info;
+  gboolean keep_positions;
+
+  GstPad *sink;
+
+  GstDeinterleaveFunc func;
+
+  GList *pending_events;
+};
+
+struct _GstDeinterleaveClass
+{
+  GstElementClass parent_class;
+};
+
+GType gst_deinterleave_get_type (void);
+
+G_END_DECLS
+
+#endif /* __DEINTERLEAVE_H__ */
diff --git a/gst/interleave/interleave.c b/gst/interleave/interleave.c
new file mode 100644
index 0000000..808d0ff
--- /dev/null
+++ b/gst/interleave/interleave.c
@@ -0,0 +1,1338 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wtay@chello.be>
+ *                    2005 Wim Taymans <wim@fluendo.com>
+ *                    2007 Andy Wingo <wingo at pobox.com>
+ *                    2008 Sebastian Dröge <slomo@circular-chaos.rg>
+ *
+ * interleave.c: interleave samples, mostly based on adder.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* TODO:
+ *       - handle caps changes
+ *       - handle more queries/events
+ */
+
+/**
+ * SECTION:element-interleave
+ * @see_also: deinterleave
+ *
+ * Merges separate mono inputs into one interleaved stream.
+ * 
+ * This element handles all raw floating point sample formats and all signed integer sample formats. The first
+ * caps on one of the sinkpads will set the caps of the output so usually an audioconvert element should be
+ * placed before every sinkpad of interleave.
+ * 
+ * It's possible to change the number of channels while the pipeline is running by adding or removing
+ * some of the request pads but this will change the caps of the output buffers. Changing the input
+ * caps is _not_ supported yet.
+ * 
+ * The channel number of every sinkpad in the out can be retrieved from the "channel" property of the pad.
+ * 
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=file.mp3 ! decodebin ! audioconvert ! "audio/x-raw,channels=2" ! deinterleave name=d  interleave name=i ! audioconvert ! wavenc ! filesink location=test.wav    d.src_0 ! queue ! audioconvert ! i.sink_1    d.src_1 ! queue ! audioconvert ! i.sink_0
+ * ]| Decodes and deinterleaves a Stereo MP3 file into separate channels and
+ * then interleaves the channels again to a WAV file with the channels
+ * exchanged.
+ * |[
+ * gst-launch-1.0 interleave name=i ! audioconvert ! wavenc ! filesink location=file.wav  filesrc location=file1.wav ! decodebin ! audioconvert ! "audio/x-raw,channels=1,channel-mask=(bitmask)0x1" ! queue ! i.sink_0   filesrc location=file2.wav ! decodebin ! audioconvert ! "audio/x-raw,channels=1,channel-mask=(bitmask)0x2" ! queue ! i.sink_1
+ * ]| Interleaves two Mono WAV files to a single Stereo WAV file. Having
+ * channel-masks defined in the sink pads ensures a sane mapping of the mono
+ * streams into the stereo stream. NOTE: the proper way to map channels in
+ * code is by using the channel-positions property of the interleave element.
+ * </refsect2>
+ */
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <string.h>
+#include "interleave.h"
+
+#include <gst/audio/audio.h>
+#include <gst/audio/audio-enumtypes.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_interleave_debug);
+#define GST_CAT_DEFAULT gst_interleave_debug
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "rate = (int) [ 1, MAX ], "
+        "channels = (int) 1, "
+        "format = (string) " GST_AUDIO_FORMATS_ALL ", "
+        "layout = (string) {non-interleaved, interleaved}")
+    );
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "rate = (int) [ 1, MAX ], "
+        "channels = (int) [ 1, MAX ], "
+        "format = (string) " GST_AUDIO_FORMATS_ALL ", "
+        "layout = (string) interleaved")
+    );
+
+#define MAKE_FUNC(type) \
+static void interleave_##type (guint##type *out, guint##type *in, \
+    guint stride, guint nframes) \
+{ \
+  gint i; \
+  \
+  for (i = 0; i < nframes; i++) { \
+    *out = in[i]; \
+    out += stride; \
+  } \
+}
+
+MAKE_FUNC (8);
+MAKE_FUNC (16);
+MAKE_FUNC (32);
+MAKE_FUNC (64);
+
+static void
+interleave_24 (guint8 * out, guint8 * in, guint stride, guint nframes)
+{
+  gint i;
+
+  for (i = 0; i < nframes; i++) {
+    memcpy (out, in, 3);
+    out += stride * 3;
+    in += 3;
+  }
+}
+
+typedef struct
+{
+  GstPad parent;
+  guint channel;
+} GstInterleavePad;
+
+enum
+{
+  PROP_PAD_0,
+  PROP_PAD_CHANNEL
+};
+
+static void gst_interleave_pad_class_init (GstPadClass * klass);
+
+#define GST_TYPE_INTERLEAVE_PAD (gst_interleave_pad_get_type())
+#define GST_INTERLEAVE_PAD(pad) (G_TYPE_CHECK_INSTANCE_CAST((pad),GST_TYPE_INTERLEAVE_PAD,GstInterleavePad))
+#define GST_INTERLEAVE_PAD_CAST(pad) ((GstInterleavePad *) pad)
+#define GST_IS_INTERLEAVE_PAD(pad) (G_TYPE_CHECK_INSTANCE_TYPE((pad),GST_TYPE_INTERLEAVE_PAD))
+static GType
+gst_interleave_pad_get_type (void)
+{
+  static GType type = 0;
+
+  if (G_UNLIKELY (type == 0)) {
+    type = g_type_register_static_simple (GST_TYPE_PAD,
+        g_intern_static_string ("GstInterleavePad"), sizeof (GstPadClass),
+        (GClassInitFunc) gst_interleave_pad_class_init,
+        sizeof (GstInterleavePad), NULL, 0);
+  }
+  return type;
+}
+
+static void
+gst_interleave_pad_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstInterleavePad *self = GST_INTERLEAVE_PAD (object);
+
+  switch (prop_id) {
+    case PROP_PAD_CHANNEL:
+      g_value_set_uint (value, self->channel);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_interleave_pad_class_init (GstPadClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+
+  gobject_class->get_property = gst_interleave_pad_get_property;
+
+  g_object_class_install_property (gobject_class,
+      PROP_PAD_CHANNEL,
+      g_param_spec_uint ("channel",
+          "Channel number",
+          "Number of the channel of this pad in the output", 0, G_MAXUINT, 0,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+}
+
+#define gst_interleave_parent_class parent_class
+G_DEFINE_TYPE (GstInterleave, gst_interleave, GST_TYPE_ELEMENT);
+
+enum
+{
+  PROP_0,
+  PROP_CHANNEL_POSITIONS,
+  PROP_CHANNEL_POSITIONS_FROM_INPUT
+};
+
+static void gst_interleave_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_interleave_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+static GstPad *gst_interleave_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
+static void gst_interleave_release_pad (GstElement * element, GstPad * pad);
+
+static GstStateChangeReturn gst_interleave_change_state (GstElement * element,
+    GstStateChange transition);
+
+static gboolean gst_interleave_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+
+static gboolean gst_interleave_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+
+static gboolean gst_interleave_sink_event (GstCollectPads * pads,
+    GstCollectData * data, GstEvent * event, gpointer user_data);
+static gboolean gst_interleave_sink_query (GstCollectPads * pads,
+    GstCollectData * data, GstQuery * query, gpointer user_data);
+
+static gboolean gst_interleave_sink_setcaps (GstInterleave * self,
+    GstPad * pad, const GstCaps * caps, const GstAudioInfo * info);
+
+static GstCaps *gst_interleave_sink_getcaps (GstPad * pad, GstInterleave * self,
+    GstCaps * filter);
+
+static GstFlowReturn gst_interleave_collected (GstCollectPads * pads,
+    GstInterleave * self);
+
+static void
+gst_interleave_finalize (GObject * object)
+{
+  GstInterleave *self = GST_INTERLEAVE (object);
+
+  if (self->collect) {
+    gst_object_unref (self->collect);
+    self->collect = NULL;
+  }
+
+  if (self->channel_positions
+      && self->channel_positions != self->input_channel_positions) {
+    g_value_array_free (self->channel_positions);
+    self->channel_positions = NULL;
+  }
+
+  if (self->input_channel_positions) {
+    g_value_array_free (self->input_channel_positions);
+    self->input_channel_positions = NULL;
+  }
+
+  gst_caps_replace (&self->sinkcaps, NULL);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gint
+compare_positions (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+  const gint i = *(const gint *) a;
+  const gint j = *(const gint *) b;
+  const gint *pos = (const gint *) user_data;
+
+  if (pos[i] < pos[j])
+    return -1;
+  else if (pos[i] > pos[j])
+    return 1;
+  else
+    return 0;
+}
+
+static gboolean
+gst_interleave_channel_positions_to_mask (GValueArray * positions,
+    gint default_ordering_map[64], guint64 * mask)
+{
+  gint i;
+  guint channels;
+  GstAudioChannelPosition *pos;
+  gboolean ret;
+
+  channels = positions->n_values;
+  pos = g_new (GstAudioChannelPosition, channels);
+
+  for (i = 0; i < channels; i++) {
+    GValue *val;
+
+    val = g_value_array_get_nth (positions, i);
+    pos[i] = g_value_get_enum (val);
+  }
+
+  /* sort the default ordering map according to the position order */
+  for (i = 0; i < channels; i++) {
+    default_ordering_map[i] = i;
+  }
+  g_qsort_with_data (default_ordering_map, channels,
+      sizeof (*default_ordering_map), compare_positions, pos);
+
+  ret = gst_audio_channel_positions_to_mask (pos, channels, FALSE, mask);
+  g_free (pos);
+
+  return ret;
+}
+
+static void
+gst_interleave_set_channel_positions (GstInterleave * self, GstStructure * s)
+{
+  if (self->channels <= 64 &&
+      self->channel_positions != NULL &&
+      self->channels == self->channel_positions->n_values) {
+    if (!gst_interleave_channel_positions_to_mask (self->channel_positions,
+            self->default_channels_ordering_map, &self->channel_mask)) {
+      GST_WARNING_OBJECT (self, "Invalid channel positions, using NONE");
+      self->channel_mask = 0;
+    }
+  } else {
+    self->channel_mask = 0;
+    if (self->channels <= 64) {
+      GST_WARNING_OBJECT (self, "Using NONE channel positions");
+    }
+  }
+  gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK, self->channel_mask,
+      NULL);
+}
+
+static void
+gst_interleave_send_stream_start (GstInterleave * self)
+{
+  GST_OBJECT_LOCK (self);
+  if (self->send_stream_start) {
+    gchar s_id[32];
+
+    self->send_stream_start = FALSE;
+    GST_OBJECT_UNLOCK (self);
+
+    /* stream-start (FIXME: create id based on input ids) */
+    g_snprintf (s_id, sizeof (s_id), "interleave-%08x", g_random_int ());
+    gst_pad_push_event (self->src, gst_event_new_stream_start (s_id));
+  } else {
+    GST_OBJECT_UNLOCK (self);
+  }
+}
+
+static void
+gst_interleave_class_init (GstInterleaveClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gstelement_class = GST_ELEMENT_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (gst_interleave_debug, "interleave", 0,
+      "interleave element");
+
+  gst_element_class_set_static_metadata (gstelement_class, "Audio interleaver",
+      "Filter/Converter/Audio",
+      "Folds many mono channels into one interleaved audio stream",
+      "Andy Wingo <wingo at pobox.com>, "
+      "Sebastian Dröge <slomo@circular-chaos.org>");
+
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class, &src_template);
+
+  /* Reference GstInterleavePad class to have the type registered from
+   * a threadsafe context
+   */
+  g_type_class_ref (GST_TYPE_INTERLEAVE_PAD);
+
+  gobject_class->finalize = gst_interleave_finalize;
+  gobject_class->set_property = gst_interleave_set_property;
+  gobject_class->get_property = gst_interleave_get_property;
+
+  /**
+   * GstInterleave:channel-positions
+   * 
+   * Channel positions: This property controls the channel positions
+   * that are used on the src caps. The number of elements should be
+   * the same as the number of sink pads and the array should contain
+   * a valid list of channel positions. The n-th element of the array
+   * is the position of the n-th sink pad.
+   *
+   * These channel positions will only be used if they're valid and the
+   * number of elements is the same as the number of channels. If this
+   * is not given a NONE layout will be used.
+   *
+   */
+  g_object_class_install_property (gobject_class, PROP_CHANNEL_POSITIONS,
+      g_param_spec_value_array ("channel-positions", "Channel positions",
+          "Channel positions used on the output",
+          g_param_spec_enum ("channel-position", "Channel position",
+              "Channel position of the n-th input",
+              GST_TYPE_AUDIO_CHANNEL_POSITION,
+              GST_AUDIO_CHANNEL_POSITION_NONE,
+              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstInterleave:channel-positions-from-input
+   * 
+   * Channel positions from input: If this property is set to %TRUE the channel
+   * positions will be taken from the input caps if valid channel positions for
+   * the output can be constructed from them. If this is set to %TRUE setting the
+   * channel-positions property overwrites this property again.
+   *
+   */
+  g_object_class_install_property (gobject_class,
+      PROP_CHANNEL_POSITIONS_FROM_INPUT,
+      g_param_spec_boolean ("channel-positions-from-input",
+          "Channel positions from input",
+          "Take channel positions from the input", TRUE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->request_new_pad =
+      GST_DEBUG_FUNCPTR (gst_interleave_request_new_pad);
+  gstelement_class->release_pad =
+      GST_DEBUG_FUNCPTR (gst_interleave_release_pad);
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_interleave_change_state);
+}
+
+static void
+gst_interleave_init (GstInterleave * self)
+{
+  self->src = gst_pad_new_from_static_template (&src_template, "src");
+
+  gst_pad_set_query_function (self->src,
+      GST_DEBUG_FUNCPTR (gst_interleave_src_query));
+  gst_pad_set_event_function (self->src,
+      GST_DEBUG_FUNCPTR (gst_interleave_src_event));
+
+  gst_element_add_pad (GST_ELEMENT (self), self->src);
+
+  self->collect = gst_collect_pads_new ();
+  gst_collect_pads_set_function (self->collect,
+      (GstCollectPadsFunction) gst_interleave_collected, self);
+
+  self->input_channel_positions = g_value_array_new (0);
+  self->channel_positions_from_input = TRUE;
+  self->channel_positions = self->input_channel_positions;
+}
+
+static void
+gst_interleave_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstInterleave *self = GST_INTERLEAVE (object);
+
+  switch (prop_id) {
+    case PROP_CHANNEL_POSITIONS:
+      if (self->channel_positions &&
+          self->channel_positions != self->input_channel_positions)
+        g_value_array_free (self->channel_positions);
+
+      self->channel_positions = g_value_dup_boxed (value);
+      self->channel_positions_from_input = FALSE;
+      break;
+    case PROP_CHANNEL_POSITIONS_FROM_INPUT:
+      self->channel_positions_from_input = g_value_get_boolean (value);
+
+      if (self->channel_positions_from_input) {
+        if (self->channel_positions &&
+            self->channel_positions != self->input_channel_positions)
+          g_value_array_free (self->channel_positions);
+        self->channel_positions = self->input_channel_positions;
+      }
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_interleave_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstInterleave *self = GST_INTERLEAVE (object);
+
+  switch (prop_id) {
+    case PROP_CHANNEL_POSITIONS:
+      g_value_set_boxed (value, self->channel_positions);
+      break;
+    case PROP_CHANNEL_POSITIONS_FROM_INPUT:
+      g_value_set_boolean (value, self->channel_positions_from_input);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstPad *
+gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ,
+    const gchar * req_name, const GstCaps * caps)
+{
+  GstInterleave *self = GST_INTERLEAVE (element);
+  GstPad *new_pad;
+  gchar *pad_name;
+  gint channel, padnumber;
+  GValue val = { 0, };
+
+  if (templ->direction != GST_PAD_SINK)
+    goto not_sink_pad;
+
+  padnumber = g_atomic_int_add (&self->padcounter, 1);
+
+  channel = g_atomic_int_add (&self->channels, 1);
+  if (!self->channel_positions_from_input)
+    channel = padnumber;
+
+  pad_name = g_strdup_printf ("sink_%u", padnumber);
+  new_pad = GST_PAD_CAST (g_object_new (GST_TYPE_INTERLEAVE_PAD,
+          "name", pad_name, "direction", templ->direction,
+          "template", templ, NULL));
+  GST_INTERLEAVE_PAD_CAST (new_pad)->channel = channel;
+  GST_DEBUG_OBJECT (self, "requested new pad %s", pad_name);
+  g_free (pad_name);
+
+  gst_pad_use_fixed_caps (new_pad);
+
+  gst_collect_pads_add_pad (self->collect, new_pad, sizeof (GstCollectData),
+      NULL, TRUE);
+
+  gst_collect_pads_set_event_function (self->collect,
+      (GstCollectPadsEventFunction)
+      GST_DEBUG_FUNCPTR (gst_interleave_sink_event), self);
+
+  gst_collect_pads_set_query_function (self->collect,
+      (GstCollectPadsQueryFunction)
+      GST_DEBUG_FUNCPTR (gst_interleave_sink_query), self);
+
+  if (!gst_element_add_pad (element, new_pad))
+    goto could_not_add;
+
+  g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION);
+  g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_NONE);
+  self->input_channel_positions =
+      g_value_array_append (self->input_channel_positions, &val);
+  g_value_unset (&val);
+
+  /* Update the src caps if we already have them */
+  if (self->sinkcaps) {
+    GstCaps *srccaps;
+    GstStructure *s;
+
+    /* Take lock to make sure processing finishes first */
+    GST_OBJECT_LOCK (self->collect);
+
+    srccaps = gst_caps_copy (self->sinkcaps);
+    s = gst_caps_get_structure (srccaps, 0);
+
+    gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
+    gst_interleave_set_channel_positions (self, s);
+
+    gst_interleave_send_stream_start (self);
+    gst_pad_set_caps (self->src, srccaps);
+    gst_caps_unref (srccaps);
+
+    GST_OBJECT_UNLOCK (self->collect);
+  }
+
+  return new_pad;
+
+  /* errors */
+not_sink_pad:
+  {
+    g_warning ("interleave: requested new pad that is not a SINK pad\n");
+    return NULL;
+  }
+could_not_add:
+  {
+    GST_DEBUG_OBJECT (self, "could not add pad %s", GST_PAD_NAME (new_pad));
+    gst_collect_pads_remove_pad (self->collect, new_pad);
+    gst_object_unref (new_pad);
+    return NULL;
+  }
+}
+
+static void
+gst_interleave_release_pad (GstElement * element, GstPad * pad)
+{
+  GstInterleave *self = GST_INTERLEAVE (element);
+  GList *l;
+  GstAudioChannelPosition position;
+
+  g_return_if_fail (GST_IS_INTERLEAVE_PAD (pad));
+
+  /* Take lock to make sure we're not changing this when processing buffers */
+  GST_OBJECT_LOCK (self->collect);
+
+  g_atomic_int_add (&self->channels, -1);
+
+  if (gst_pad_has_current_caps (pad))
+    g_atomic_int_add (&self->configured_sinkpads_counter, -1);
+
+  position = GST_INTERLEAVE_PAD_CAST (pad)->channel;
+  g_value_array_remove (self->input_channel_positions, position);
+
+  /* Update channel numbers */
+  GST_OBJECT_LOCK (self);
+  for (l = GST_ELEMENT_CAST (self)->sinkpads; l != NULL; l = l->next) {
+    GstInterleavePad *ipad = GST_INTERLEAVE_PAD (l->data);
+
+    if (GST_INTERLEAVE_PAD_CAST (pad)->channel < ipad->channel)
+      ipad->channel--;
+  }
+  GST_OBJECT_UNLOCK (self);
+
+  /* Update the src caps if we already have them */
+  if (self->sinkcaps) {
+    if (self->channels > 0) {
+      GstCaps *srccaps;
+      GstStructure *s;
+
+      srccaps = gst_caps_copy (self->sinkcaps);
+      s = gst_caps_get_structure (srccaps, 0);
+
+      gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
+      gst_interleave_set_channel_positions (self, s);
+
+      gst_interleave_send_stream_start (self);
+      gst_pad_set_caps (self->src, srccaps);
+      gst_caps_unref (srccaps);
+    } else {
+      gst_caps_replace (&self->sinkcaps, NULL);
+    }
+  }
+
+  GST_OBJECT_UNLOCK (self->collect);
+
+  gst_collect_pads_remove_pad (self->collect, pad);
+  gst_element_remove_pad (element, pad);
+}
+
+static GstStateChangeReturn
+gst_interleave_change_state (GstElement * element, GstStateChange transition)
+{
+  GstInterleave *self;
+  GstStateChangeReturn ret;
+
+  self = GST_INTERLEAVE (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      self->timestamp = 0;
+      self->offset = 0;
+      gst_event_replace (&self->pending_segment, NULL);
+      self->send_stream_start = TRUE;
+      gst_collect_pads_start (self->collect);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  /* Stop before calling the parent's state change function as
+   * GstCollectPads might take locks and we would deadlock in that
+   * case
+   */
+  if (transition == GST_STATE_CHANGE_PAUSED_TO_READY)
+    gst_collect_pads_stop (self->collect);
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_caps_replace (&self->sinkcaps, NULL);
+      gst_event_replace (&self->pending_segment, NULL);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static void
+__remove_channels (GstCaps * caps)
+{
+  GstStructure *s;
+  gint i, size;
+
+  size = gst_caps_get_size (caps);
+  for (i = 0; i < size; i++) {
+    s = gst_caps_get_structure (caps, i);
+    gst_structure_remove_field (s, "channel-mask");
+    gst_structure_remove_field (s, "channels");
+  }
+}
+
+static void
+__set_channels (GstCaps * caps, gint channels)
+{
+  GstStructure *s;
+  gint i, size;
+
+  size = gst_caps_get_size (caps);
+  for (i = 0; i < size; i++) {
+    s = gst_caps_get_structure (caps, i);
+    if (channels > 0)
+      gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL);
+    else
+      gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
+  }
+}
+
+/* we can only accept caps that we and downstream can handle. */
+static GstCaps *
+gst_interleave_sink_getcaps (GstPad * pad, GstInterleave * self,
+    GstCaps * filter)
+{
+  GstCaps *result, *peercaps, *sinkcaps;
+
+  GST_OBJECT_LOCK (self);
+
+  /* If we already have caps on one of the sink pads return them */
+  if (self->sinkcaps) {
+    result = gst_caps_copy (self->sinkcaps);
+  } else {
+    /* get the downstream possible caps */
+    peercaps = gst_pad_peer_query_caps (self->src, NULL);
+
+    /* get the allowed caps on this sinkpad */
+    sinkcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+    __remove_channels (sinkcaps);
+    if (peercaps) {
+      peercaps = gst_caps_make_writable (peercaps);
+      __remove_channels (peercaps);
+      /* if the peer has caps, intersect */
+      GST_DEBUG_OBJECT (pad, "intersecting peer and template caps");
+      result = gst_caps_intersect (peercaps, sinkcaps);
+      gst_caps_unref (peercaps);
+      gst_caps_unref (sinkcaps);
+    } else {
+      /* the peer has no caps (or there is no peer), just use the allowed caps
+       * of this sinkpad. */
+      GST_DEBUG_OBJECT (pad, "no peer caps, using sinkcaps");
+      result = sinkcaps;
+    }
+    __set_channels (result, 1);
+  }
+
+  GST_OBJECT_UNLOCK (self);
+
+  if (filter != NULL) {
+    GstCaps *caps = result;
+
+    GST_LOG_OBJECT (pad, "intersecting filter caps %" GST_PTR_FORMAT " with "
+        "preliminary result %" GST_PTR_FORMAT, filter, caps);
+
+    result = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+  }
+
+  GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, result);
+
+  return result;
+}
+
+static void
+gst_interleave_set_process_function (GstInterleave * self)
+{
+  switch (self->width) {
+    case 8:
+      self->func = (GstInterleaveFunc) interleave_8;
+      break;
+    case 16:
+      self->func = (GstInterleaveFunc) interleave_16;
+      break;
+    case 24:
+      self->func = (GstInterleaveFunc) interleave_24;
+      break;
+    case 32:
+      self->func = (GstInterleaveFunc) interleave_32;
+      break;
+    case 64:
+      self->func = (GstInterleaveFunc) interleave_64;
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+static gboolean
+gst_interleave_sink_setcaps (GstInterleave * self, GstPad * pad,
+    const GstCaps * caps, const GstAudioInfo * info)
+{
+  g_return_val_if_fail (GST_IS_INTERLEAVE_PAD (pad), FALSE);
+
+  /* TODO: handle caps changes */
+  if (self->sinkcaps && !gst_caps_is_subset (caps, self->sinkcaps)) {
+    goto cannot_change_caps;
+  } else {
+    GstCaps *srccaps;
+    GstStructure *s;
+    gboolean res;
+
+    self->width = GST_AUDIO_INFO_WIDTH (info);
+    self->rate = GST_AUDIO_INFO_RATE (info);
+
+    gst_interleave_set_process_function (self);
+
+    srccaps = gst_caps_copy (caps);
+    s = gst_caps_get_structure (srccaps, 0);
+
+    gst_structure_remove_field (s, "channel-mask");
+
+    gst_structure_set (s, "channels", G_TYPE_INT, self->channels, "layout",
+        G_TYPE_STRING, "interleaved", NULL);
+    gst_interleave_set_channel_positions (self, s);
+
+    gst_interleave_send_stream_start (self);
+    res = gst_pad_set_caps (self->src, srccaps);
+    gst_caps_unref (srccaps);
+
+    if (!res)
+      goto src_did_not_accept;
+  }
+
+  if (!self->sinkcaps) {
+    GstCaps *sinkcaps = gst_caps_copy (caps);
+    GstStructure *s = gst_caps_get_structure (sinkcaps, 0);
+
+    gst_structure_remove_field (s, "channel-mask");
+
+    GST_DEBUG_OBJECT (self, "setting sinkcaps %" GST_PTR_FORMAT, sinkcaps);
+
+    gst_caps_replace (&self->sinkcaps, sinkcaps);
+
+    gst_caps_unref (sinkcaps);
+  }
+
+  return TRUE;
+
+cannot_change_caps:
+  {
+    GST_WARNING_OBJECT (self, "caps of %" GST_PTR_FORMAT " already set, can't "
+        "change", self->sinkcaps);
+    return FALSE;
+  }
+src_did_not_accept:
+  {
+    GST_WARNING_OBJECT (self, "src did not accept setcaps()");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_interleave_sink_event (GstCollectPads * pads, GstCollectData * data,
+    GstEvent * event, gpointer user_data)
+{
+  GstInterleave *self = GST_INTERLEAVE (user_data);
+  gboolean ret = TRUE;
+
+  GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
+      GST_DEBUG_PAD_NAME (data->pad));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      GST_OBJECT_LOCK (self);
+      gst_event_replace (&self->pending_segment, NULL);
+      GST_OBJECT_UNLOCK (self);
+      break;
+    case GST_EVENT_SEGMENT:
+    {
+      GST_OBJECT_LOCK (self);
+      gst_event_replace (&self->pending_segment, event);
+      GST_OBJECT_UNLOCK (self);
+      break;
+    }
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+      GstAudioInfo info;
+      GValue *val;
+      guint channel;
+
+      gst_event_parse_caps (event, &caps);
+
+      if (!gst_audio_info_from_caps (&info, caps)) {
+        GST_WARNING_OBJECT (self, "invalid sink caps");
+        gst_event_unref (event);
+        event = NULL;
+        ret = FALSE;
+        break;
+      }
+
+      if (self->channel_positions_from_input
+          && GST_AUDIO_INFO_CHANNELS (&info) == 1) {
+        channel = GST_INTERLEAVE_PAD_CAST (data->pad)->channel;
+        val = g_value_array_get_nth (self->input_channel_positions, channel);
+        g_value_set_enum (val, GST_AUDIO_INFO_POSITION (&info, 0));
+      }
+
+      if (!gst_pad_has_current_caps (data->pad))
+        g_atomic_int_add (&self->configured_sinkpads_counter, 1);
+
+      /* Last caps that are set on a sink pad are used as output caps */
+      if (g_atomic_int_get (&self->configured_sinkpads_counter) ==
+          self->channels) {
+        ret = gst_interleave_sink_setcaps (self, data->pad, caps, &info);
+        gst_event_unref (event);
+        event = NULL;
+      }
+      break;
+    }
+    case GST_EVENT_TAG:
+      GST_FIXME_OBJECT (self, "FIXME: merge tags and send after stream-start");
+      break;
+    default:
+      break;
+  }
+
+  /* now GstCollectPads can take care of the rest, e.g. EOS */
+  if (event != NULL)
+    return gst_collect_pads_event_default (pads, data, event, FALSE);
+
+  return ret;
+}
+
+static gboolean
+gst_interleave_sink_query (GstCollectPads * pads,
+    GstCollectData * data, GstQuery * query, gpointer user_data)
+{
+  GstInterleave *self = GST_INTERLEAVE (user_data);
+  gboolean ret = TRUE;
+
+  GST_DEBUG ("Got %s query on pad %s:%s", GST_QUERY_TYPE_NAME (query),
+      GST_DEBUG_PAD_NAME (data->pad));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *filter, *caps;
+
+      gst_query_parse_caps (query, &filter);
+      caps = gst_interleave_sink_getcaps (data->pad, self, filter);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+      ret = TRUE;
+      break;
+    }
+    default:
+      ret = gst_collect_pads_query_default (pads, data, query, FALSE);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_interleave_src_query_duration (GstInterleave * self, GstQuery * query)
+{
+  gint64 max;
+  gboolean res;
+  GstFormat format;
+  GstIterator *it;
+  gboolean done;
+
+  /* parse format */
+  gst_query_parse_duration (query, &format, NULL);
+
+  max = -1;
+  res = TRUE;
+  done = FALSE;
+
+  /* Take maximum of all durations */
+  it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
+  while (!done) {
+    GstIteratorResult ires;
+
+    GValue item = { 0, };
+
+    ires = gst_iterator_next (it, &item);
+    switch (ires) {
+      case GST_ITERATOR_DONE:
+        done = TRUE;
+        break;
+      case GST_ITERATOR_OK:
+      {
+        GstPad *pad = GST_PAD_CAST (g_value_dup_object (&item));
+
+        gint64 duration;
+
+        /* ask sink peer for duration */
+        res &= gst_pad_peer_query_duration (pad, format, &duration);
+        /* take max from all valid return values */
+        if (res) {
+          /* valid unknown length, stop searching */
+          if (duration == -1) {
+            max = duration;
+            done = TRUE;
+          }
+          /* else see if bigger than current max */
+          else if (duration > max)
+            max = duration;
+        }
+        gst_object_unref (pad);
+        g_value_unset (&item);
+        break;
+      }
+      case GST_ITERATOR_RESYNC:
+        max = -1;
+        res = TRUE;
+        gst_iterator_resync (it);
+        break;
+      default:
+        res = FALSE;
+        done = TRUE;
+        break;
+    }
+  }
+  gst_iterator_free (it);
+
+  if (res) {
+    /* If in bytes format we have to multiply with the number of channels
+     * to get the correct results. All other formats should be fine */
+    if (format == GST_FORMAT_BYTES && max != -1)
+      max *= self->channels;
+
+    /* and store the max */
+    GST_DEBUG_OBJECT (self, "Total duration in format %s: %"
+        GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max));
+    gst_query_set_duration (query, format, max);
+  }
+
+  return res;
+}
+
+static gboolean
+gst_interleave_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  GstInterleave *self = GST_INTERLEAVE (parent);
+  gboolean res = FALSE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:
+    {
+      GstFormat format;
+
+      gst_query_parse_position (query, &format, NULL);
+
+      switch (format) {
+        case GST_FORMAT_TIME:
+          /* FIXME, bring to stream time, might be tricky */
+          gst_query_set_position (query, format, self->timestamp);
+          res = TRUE;
+          break;
+        case GST_FORMAT_BYTES:
+          gst_query_set_position (query, format,
+              self->offset * self->channels * self->width);
+          res = TRUE;
+          break;
+        case GST_FORMAT_DEFAULT:
+          gst_query_set_position (query, format, self->offset);
+          res = TRUE;
+          break;
+        default:
+          break;
+      }
+      break;
+    }
+    case GST_QUERY_DURATION:
+      res = gst_interleave_src_query_duration (self, query);
+      break;
+    default:
+      /* FIXME, needs a custom query handler because we have multiple
+       * sinkpads */
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+
+  return res;
+}
+
+static gboolean
+forward_event_func (const GValue * item, GValue * ret, GstEvent * event)
+{
+  GstPad *pad = GST_PAD_CAST (g_value_dup_object (item));
+  gst_event_ref (event);
+  GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event));
+  if (!gst_pad_push_event (pad, event)) {
+    g_value_set_boolean (ret, FALSE);
+    GST_WARNING_OBJECT (pad, "Sending event  %p (%s) failed.",
+        event, GST_EVENT_TYPE_NAME (event));
+  } else {
+    GST_LOG_OBJECT (pad, "Sent event  %p (%s).",
+        event, GST_EVENT_TYPE_NAME (event));
+  }
+  gst_object_unref (pad);
+  return TRUE;
+}
+
+static gboolean
+forward_event (GstInterleave * self, GstEvent * event)
+{
+  GstIterator *it;
+  GValue vret = { 0 };
+
+  GST_LOG_OBJECT (self, "Forwarding event %p (%s)", event,
+      GST_EVENT_TYPE_NAME (event));
+
+  g_value_init (&vret, G_TYPE_BOOLEAN);
+  g_value_set_boolean (&vret, TRUE);
+  it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
+  gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret,
+      event);
+  gst_iterator_free (it);
+  gst_event_unref (event);
+
+  return g_value_get_boolean (&vret);
+}
+
+
+static gboolean
+gst_interleave_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstInterleave *self = GST_INTERLEAVE (parent);
+  gboolean result;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_QOS:
+      /* QoS might be tricky */
+      result = FALSE;
+      break;
+    case GST_EVENT_SEEK:
+    {
+      GstSeekFlags flags;
+
+      gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL, NULL);
+
+      /* check if we are flushing */
+      if (flags & GST_SEEK_FLAG_FLUSH) {
+        /* make sure we accept nothing anymore and return WRONG_STATE */
+        gst_collect_pads_set_flushing (self->collect, TRUE);
+
+        /* flushing seek, start flush downstream, the flush will be done
+         * when all pads received a FLUSH_STOP. */
+        gst_pad_push_event (self->src, gst_event_new_flush_start ());
+      }
+      result = forward_event (self, event);
+      break;
+    }
+    case GST_EVENT_NAVIGATION:
+      /* navigation is rather pointless. */
+      result = FALSE;
+      break;
+    default:
+      /* just forward the rest for now */
+      result = forward_event (self, event);
+      break;
+  }
+
+  return result;
+}
+
+static GstFlowReturn
+gst_interleave_collected (GstCollectPads * pads, GstInterleave * self)
+{
+  guint size;
+  GstBuffer *outbuf = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GSList *collected;
+  guint nsamples;
+  guint ncollected = 0;
+  gboolean empty = TRUE;
+  gint width = self->width / 8;
+  GstMapInfo write_info;
+  GstClockTime timestamp = -1;
+
+  size = gst_collect_pads_available (pads);
+  if (size == 0)
+    goto eos;
+
+  g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED);
+  g_return_val_if_fail (self->width > 0, GST_FLOW_NOT_NEGOTIATED);
+  g_return_val_if_fail (self->channels > 0, GST_FLOW_NOT_NEGOTIATED);
+  g_return_val_if_fail (self->rate > 0, GST_FLOW_NOT_NEGOTIATED);
+
+  g_return_val_if_fail (size % width == 0, GST_FLOW_ERROR);
+
+  GST_DEBUG_OBJECT (self, "Starting to collect %u bytes from %d channels", size,
+      self->channels);
+
+  nsamples = size / width;
+
+  outbuf = gst_buffer_new_allocate (NULL, size * self->channels, NULL);
+
+  if (outbuf == NULL || gst_buffer_get_size (outbuf) < size * self->channels) {
+    gst_buffer_unref (outbuf);
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+
+  gst_buffer_map (outbuf, &write_info, GST_MAP_WRITE);
+  memset (write_info.data, 0, size * self->channels);
+
+  for (collected = pads->data; collected != NULL; collected = collected->next) {
+    GstCollectData *cdata;
+    GstBuffer *inbuf;
+    guint8 *outdata;
+    GstMapInfo input_info;
+    gint channel;
+
+    cdata = (GstCollectData *) collected->data;
+
+    inbuf = gst_collect_pads_take_buffer (pads, cdata, size);
+    if (inbuf == NULL) {
+      GST_DEBUG_OBJECT (cdata->pad, "No buffer available");
+      goto next;
+    }
+    ncollected++;
+
+    if (timestamp == -1)
+      timestamp = GST_BUFFER_TIMESTAMP (inbuf);
+
+    if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP))
+      goto next;
+
+    empty = FALSE;
+    channel = GST_INTERLEAVE_PAD_CAST (cdata->pad)->channel;
+    if (self->channels <= 64 && self->channel_mask) {
+      channel = self->default_channels_ordering_map[channel];
+    }
+    outdata = write_info.data + width * channel;
+
+    gst_buffer_map (inbuf, &input_info, GST_MAP_READ);
+    self->func (outdata, input_info.data, self->channels, nsamples);
+    gst_buffer_unmap (inbuf, &input_info);
+
+  next:
+    if (inbuf)
+      gst_buffer_unref (inbuf);
+  }
+
+  if (ncollected == 0) {
+    gst_buffer_unmap (outbuf, &write_info);
+    goto eos;
+  }
+
+  GST_OBJECT_LOCK (self);
+  if (self->pending_segment) {
+    GstEvent *event;
+    GstSegment segment;
+
+    event = self->pending_segment;
+    self->pending_segment = NULL;
+    GST_OBJECT_UNLOCK (self);
+
+    /* convert the input segment to time now */
+    gst_event_copy_segment (event, &segment);
+
+    if (segment.format != GST_FORMAT_TIME) {
+      gst_event_unref (event);
+
+      /* not time, convert */
+      switch (segment.format) {
+        case GST_FORMAT_BYTES:
+          segment.start *= width;
+          if (segment.stop != -1)
+            segment.stop *= width;
+          if (segment.position != -1)
+            segment.position *= width;
+          /* fallthrough for the samples case */
+        case GST_FORMAT_DEFAULT:
+          segment.start =
+              gst_util_uint64_scale_int (segment.start, GST_SECOND, self->rate);
+          if (segment.stop != -1)
+            segment.stop =
+                gst_util_uint64_scale_int (segment.stop, GST_SECOND,
+                self->rate);
+          if (segment.position != -1)
+            segment.position =
+                gst_util_uint64_scale_int (segment.position, GST_SECOND,
+                self->rate);
+          break;
+        default:
+          GST_WARNING ("can't convert segment values");
+          segment.start = 0;
+          segment.stop = -1;
+          segment.position = 0;
+          break;
+      }
+      event = gst_event_new_segment (&segment);
+    }
+    gst_pad_push_event (self->src, event);
+
+    GST_OBJECT_LOCK (self);
+  }
+  GST_OBJECT_UNLOCK (self);
+
+  if (timestamp != -1) {
+    self->offset = gst_util_uint64_scale_int (timestamp, self->rate,
+        GST_SECOND);
+    self->timestamp = timestamp;
+  }
+
+  GST_BUFFER_TIMESTAMP (outbuf) = self->timestamp;
+  GST_BUFFER_OFFSET (outbuf) = self->offset;
+
+  self->offset += nsamples;
+  self->timestamp = gst_util_uint64_scale_int (self->offset,
+      GST_SECOND, self->rate);
+
+  GST_BUFFER_DURATION (outbuf) =
+      self->timestamp - GST_BUFFER_TIMESTAMP (outbuf);
+
+  if (empty)
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
+
+  gst_buffer_unmap (outbuf, &write_info);
+
+  GST_LOG_OBJECT (self, "pushing outbuf, timestamp %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
+  ret = gst_pad_push (self->src, outbuf);
+
+  return ret;
+
+eos:
+  {
+    GST_DEBUG_OBJECT (self, "no data available, must be EOS");
+    if (outbuf)
+      gst_buffer_unref (outbuf);
+    gst_pad_push_event (self->src, gst_event_new_eos ());
+    return GST_FLOW_EOS;
+  }
+}
diff --git a/gst/interleave/interleave.h b/gst/interleave/interleave.h
new file mode 100644
index 0000000..05ebe3b
--- /dev/null
+++ b/gst/interleave/interleave.h
@@ -0,0 +1,90 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wtay@chello.be>
+ *                    2005 Wim Taymans <wim@fluendo.com>
+ *                    2007 Andy Wingo <wingo at pobox.com>
+ *                    2008 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * interleave.c: interleave samples, mostly based on adder
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __INTERLEAVE_H__
+#define __INTERLEAVE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstcollectpads.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_INTERLEAVE            (gst_interleave_get_type())
+#define GST_INTERLEAVE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_INTERLEAVE,GstInterleave))
+#define GST_INTERLEAVE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_INTERLEAVE,GstInterleaveClass))
+#define GST_INTERLEAVE_GET_CLASS(obj) \
+        (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_INTERLEAVE,GstInterleaveClass))
+#define GST_IS_INTERLEAVE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_INTERLEAVE))
+#define GST_IS_INTERLEAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_INTERLEAVE))
+
+typedef struct _GstInterleave GstInterleave;
+typedef struct _GstInterleaveClass GstInterleaveClass;
+
+typedef void (*GstInterleaveFunc) (gpointer out, gpointer in, guint stride, guint nframes);
+
+struct _GstInterleave
+{
+  GstElement element;
+
+  /*< private >*/
+  GstCollectPads *collect;
+
+  gint channels;
+  gint padcounter;
+  gint rate;
+  gint width;
+
+  GValueArray *channel_positions;
+  GValueArray *input_channel_positions;
+  gboolean channel_positions_from_input;
+
+  gint default_channels_ordering_map[64];
+  guint64 channel_mask;
+
+  GstCaps *sinkcaps;
+  gint configured_sinkpads_counter;
+
+  GstClockTime timestamp;
+  guint64 offset;
+
+  GstEvent *pending_segment;
+
+  GstInterleaveFunc func;
+
+  GstPad *src;
+
+  gboolean send_stream_start;
+};
+
+struct _GstInterleaveClass
+{
+  GstElementClass parent_class;
+};
+
+GType gst_interleave_get_type (void);
+
+G_END_DECLS
+
+#endif /* __INTERLEAVE_H__ */
diff --git a/gst/interleave/meson.build b/gst/interleave/meson.build
new file mode 100644
index 0000000..428b36a
--- /dev/null
+++ b/gst/interleave/meson.build
@@ -0,0 +1,8 @@
+gstinterleave = library('gstinterleave',
+  'plugin.c', 'interleave.c', 'deinterleave.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstbase_dep, gstaudio_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/interleave/plugin.c b/gst/interleave/plugin.c
new file mode 100644
index 0000000..9eb7290
--- /dev/null
+++ b/gst/interleave/plugin.c
@@ -0,0 +1,43 @@
+/* GStreamer interleave plugin
+ * Copyright (C) 2004,2007 Andy Wingo <wingo at pobox.com>
+ *
+ * plugin.c: the stubs for the interleave plugin
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "plugin.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "interleave",
+          GST_RANK_NONE, gst_interleave_get_type ()) ||
+      !gst_element_register (plugin, "deinterleave",
+          GST_RANK_NONE, gst_deinterleave_get_type ()))
+    return FALSE;
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    interleave,
+    "Audio interleaver/deinterleaver",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/interleave/plugin.h b/gst/interleave/plugin.h
new file mode 100644
index 0000000..7956827
--- /dev/null
+++ b/gst/interleave/plugin.h
@@ -0,0 +1,31 @@
+/* GStreamer interleave plugin
+ * Copyright (C) 2004,2007 Andy Wingo <wingo at pobox.com>
+ *
+ * plugin.h: the stubs for the interleave plugin
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_PLUGIN_INTERLEAVE_H__
+#define __GST_PLUGIN_INTERLEAVE_H__
+
+
+#include <gst/gst.h>
+#include "interleave.h"
+#include "deinterleave.h"
+
+#endif /* __GST_PLUGIN_INTERLEAVE_H__ */
diff --git a/gst/isomp4/GstQTMux.prs b/gst/isomp4/GstQTMux.prs
new file mode 100644
index 0000000..be1e644
--- /dev/null
+++ b/gst/isomp4/GstQTMux.prs
@@ -0,0 +1,6 @@
+[_presets_]
+version=1.6.0
+element-name=GstQTMux
+
+[Profile YouTube]
+faststart=true
diff --git a/gst/isomp4/LEGAL b/gst/isomp4/LEGAL
new file mode 100644
index 0000000..5af6e8f
--- /dev/null
+++ b/gst/isomp4/LEGAL
@@ -0,0 +1,10 @@
+This is a demuxer supporting a subset of the Quicktime video container
+format developed by Apple. Apple and others have some patents on
+some features of the Quicktime container format in regards to technologies
+such as QuicktimeVR and RTP hinting. Due to that be aware that if ever
+such features are added to this demuxer it would need to be moved to the
+-ugly module or those features need to come as add-in functionality stored in 
+another module.
+
+As the plugin is as of today's date (19th of June 2007) it does not 
+violate any software patents we know of.
diff --git a/gst/isomp4/Makefile.am b/gst/isomp4/Makefile.am
new file mode 100644
index 0000000..d76cb42
--- /dev/null
+++ b/gst/isomp4/Makefile.am
@@ -0,0 +1,45 @@
+
+plugin_LTLIBRARIES = libgstisomp4.la
+
+libgstisomp4_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstisomp4_la_LIBADD = \
+    $(GST_PLUGINS_BASE_LIBS) \
+    -lgstriff-@GST_API_VERSION@ \
+    -lgstaudio-@GST_API_VERSION@ \
+    -lgstvideo-@GST_API_VERSION@ \
+    -lgstrtp-@GST_API_VERSION@ \
+    -lgsttag-@GST_API_VERSION@ \
+    -lgstpbutils-@GST_API_VERSION@ \
+    $(GST_BASE_LIBS) $(GST_LIBS) $(ZLIB_LIBS)
+libgstisomp4_la_LDFLAGS = ${GST_PLUGIN_LDFLAGS}
+libgstisomp4_la_SOURCES = isomp4-plugin.c gstrtpxqtdepay.c \
+	qtdemux.c qtdemux_types.c qtdemux_dump.c qtdemux_lang.c \
+	gstqtmux.c gstqtmoovrecover.c atoms.c atomsrecovery.c descriptors.c \
+	properties.c gstqtmuxmap.c gstisoff.c
+
+presetdir = $(datadir)/gstreamer-$(GST_API_VERSION)/presets
+preset_DATA = GstQTMux.prs
+
+noinst_HEADERS = \
+	qtatomparser.h   \
+	qtdemux.h        \
+	qtdemux_types.h  \
+	qtdemux_debug.h  \
+	qtdemux_dump.h   \
+	qtdemux_lang.h   \
+	qtpalette.h      \
+	gstrtpxqtdepay.h \
+	gstqtmux.h       \
+	gstqtmoovrecover.h \
+	atoms.h          \
+	atomsrecovery.h  \
+	descriptors.h    \
+	properties.h     \
+	fourcc.h         \
+	gstisoff.h       \
+	gstqtmuxmap.h
+
+EXTRA_DIST = \
+	gstqtmux-doc.c \
+	gstqtmux-doc.h \
+	$(preset_DATA)
diff --git a/gst/isomp4/atoms.c b/gst/isomp4/atoms.c
new file mode 100644
index 0000000..4ca6927
--- /dev/null
+++ b/gst/isomp4/atoms.c
@@ -0,0 +1,5595 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008-2010 Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+ * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "atoms.h"
+#include <string.h>
+#include <glib.h>
+
+#include <gst/gst.h>
+#include <gst/base/gstbytewriter.h>
+#include <gst/tag/tag.h>
+#include <gst/video/video.h>
+
+/*
+ * Creates a new AtomsContext for the given flavor.
+ */
+AtomsContext *
+atoms_context_new (AtomsTreeFlavor flavor)
+{
+  AtomsContext *context = g_new0 (AtomsContext, 1);
+  context->flavor = flavor;
+  return context;
+}
+
+/*
+ * Frees an AtomsContext and all memory associated with it
+ */
+void
+atoms_context_free (AtomsContext * context)
+{
+  g_free (context);
+}
+
+/* -- creation, initialization, clear and free functions -- */
+
+#define SECS_PER_DAY (24 * 60 * 60)
+#define LEAP_YEARS_FROM_1904_TO_1970 17
+
+guint64
+atoms_get_current_qt_time (void)
+{
+  GTimeVal timeval;
+
+  g_get_current_time (&timeval);
+  /* FIXME this should use UTC coordinated time */
+  return timeval.tv_sec + (((1970 - 1904) * (guint64) 365) +
+      LEAP_YEARS_FROM_1904_TO_1970) * SECS_PER_DAY;
+}
+
+static void
+common_time_info_init (TimeInfo * ti)
+{
+  ti->creation_time = ti->modification_time = atoms_get_current_qt_time ();
+  ti->timescale = 0;
+  ti->duration = 0;
+}
+
+static void
+atom_header_set (Atom * header, guint32 fourcc, gint32 size, gint64 ext_size)
+{
+  header->type = fourcc;
+  header->size = size;
+  header->extended_size = ext_size;
+}
+
+static void
+atom_clear (Atom * atom)
+{
+}
+
+static void
+atom_full_init (AtomFull * full, guint32 fourcc, gint32 size, gint64 ext_size,
+    guint8 version, guint8 flags[3])
+{
+  atom_header_set (&(full->header), fourcc, size, ext_size);
+  full->version = version;
+  full->flags[0] = flags[0];
+  full->flags[1] = flags[1];
+  full->flags[2] = flags[2];
+}
+
+static void
+atom_full_clear (AtomFull * full)
+{
+  atom_clear (&full->header);
+}
+
+static void
+atom_full_free (AtomFull * full)
+{
+  atom_full_clear (full);
+  g_free (full);
+}
+
+static guint32
+atom_full_get_flags_as_uint (AtomFull * full)
+{
+  return full->flags[0] << 16 | full->flags[1] << 8 | full->flags[2];
+}
+
+static void
+atom_full_set_flags_as_uint (AtomFull * full, guint32 flags_as_uint)
+{
+  full->flags[2] = flags_as_uint & 0xFF;
+  full->flags[1] = (flags_as_uint & 0xFF00) >> 8;
+  full->flags[0] = (flags_as_uint & 0xFF0000) >> 16;
+}
+
+static AtomInfo *
+build_atom_info_wrapper (Atom * atom, gpointer copy_func, gpointer free_func)
+{
+  AtomInfo *info = NULL;
+
+  if (atom) {
+    info = g_new0 (AtomInfo, 1);
+
+    info->atom = atom;
+    info->copy_data_func = copy_func;
+    info->free_func = free_func;
+  }
+
+  return info;
+}
+
+static GList *
+atom_info_list_prepend_atom (GList * ai, Atom * atom,
+    AtomCopyDataFunc copy_func, AtomFreeFunc free_func)
+{
+  if (atom)
+    return g_list_prepend (ai,
+        build_atom_info_wrapper (atom, copy_func, free_func));
+  else
+    return ai;
+}
+
+static void
+atom_info_list_free (GList * ai)
+{
+  while (ai) {
+    AtomInfo *info = (AtomInfo *) ai->data;
+
+    info->free_func (info->atom);
+    g_free (info);
+    ai = g_list_delete_link (ai, ai);
+  }
+}
+
+static AtomData *
+atom_data_new (guint32 fourcc)
+{
+  AtomData *data = g_new0 (AtomData, 1);
+
+  atom_header_set (&data->header, fourcc, 0, 0);
+  return data;
+}
+
+static void
+atom_data_alloc_mem (AtomData * data, guint32 size)
+{
+  g_free (data->data);
+  data->data = g_new0 (guint8, size);
+  data->datalen = size;
+}
+
+static AtomData *
+atom_data_new_from_data (guint32 fourcc, const guint8 * mem, gsize size)
+{
+  AtomData *data = atom_data_new (fourcc);
+
+  atom_data_alloc_mem (data, size);
+  memcpy (data->data, mem, size);
+  return data;
+}
+
+static AtomData *
+atom_data_new_from_gst_buffer (guint32 fourcc, const GstBuffer * buf)
+{
+  AtomData *data = atom_data_new (fourcc);
+  gsize size = gst_buffer_get_size ((GstBuffer *) buf);
+
+  atom_data_alloc_mem (data, size);
+  gst_buffer_extract ((GstBuffer *) buf, 0, data->data, size);
+  return data;
+}
+
+static void
+atom_data_free (AtomData * data)
+{
+  atom_clear (&data->header);
+  g_free (data->data);
+  g_free (data);
+}
+
+static AtomUUID *
+atom_uuid_new (void)
+{
+  AtomUUID *uuid = g_new0 (AtomUUID, 1);
+
+  atom_header_set (&uuid->header, FOURCC_uuid, 0, 0);
+  return uuid;
+}
+
+static void
+atom_uuid_free (AtomUUID * data)
+{
+  atom_clear (&data->header);
+  g_free (data->data);
+  g_free (data);
+}
+
+static void
+atom_ftyp_init (AtomFTYP * ftyp, guint32 major, guint32 version, GList * brands)
+{
+  gint index;
+  GList *it = NULL;
+
+  atom_header_set (&ftyp->header, FOURCC_ftyp, 16, 0);
+  ftyp->major_brand = major;
+  ftyp->version = version;
+
+  /* always include major brand as compatible brand */
+  ftyp->compatible_brands_size = g_list_length (brands) + 1;
+  ftyp->compatible_brands = g_new (guint32, ftyp->compatible_brands_size);
+
+  ftyp->compatible_brands[0] = major;
+  index = 1;
+  for (it = brands; it != NULL; it = g_list_next (it)) {
+    ftyp->compatible_brands[index++] = GPOINTER_TO_UINT (it->data);
+  }
+}
+
+AtomFTYP *
+atom_ftyp_new (AtomsContext * context, guint32 major, guint32 version,
+    GList * brands)
+{
+  AtomFTYP *ftyp = g_new0 (AtomFTYP, 1);
+
+  atom_ftyp_init (ftyp, major, version, brands);
+  return ftyp;
+}
+
+void
+atom_ftyp_free (AtomFTYP * ftyp)
+{
+  atom_clear (&ftyp->header);
+  g_free (ftyp->compatible_brands);
+  ftyp->compatible_brands = NULL;
+  g_free (ftyp);
+}
+
+static void
+atom_esds_init (AtomESDS * esds)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&esds->header, FOURCC_esds, 0, 0, 0, flags);
+  desc_es_init (&esds->es);
+}
+
+static AtomESDS *
+atom_esds_new (void)
+{
+  AtomESDS *esds = g_new0 (AtomESDS, 1);
+
+  atom_esds_init (esds);
+  return esds;
+}
+
+static void
+atom_esds_free (AtomESDS * esds)
+{
+  atom_full_clear (&esds->header);
+  desc_es_descriptor_clear (&esds->es);
+  g_free (esds);
+}
+
+static AtomFRMA *
+atom_frma_new (void)
+{
+  AtomFRMA *frma = g_new0 (AtomFRMA, 1);
+
+  atom_header_set (&frma->header, FOURCC_frma, 0, 0);
+  return frma;
+}
+
+static void
+atom_frma_free (AtomFRMA * frma)
+{
+  atom_clear (&frma->header);
+  g_free (frma);
+}
+
+static AtomWAVE *
+atom_wave_new (void)
+{
+  AtomWAVE *wave = g_new0 (AtomWAVE, 1);
+
+  atom_header_set (&wave->header, FOURCC_wave, 0, 0);
+  return wave;
+}
+
+static void
+atom_wave_free (AtomWAVE * wave)
+{
+  atom_clear (&wave->header);
+  atom_info_list_free (wave->extension_atoms);
+  g_free (wave);
+}
+
+static void
+atom_elst_init (AtomELST * elst)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+  atom_full_init (&elst->header, FOURCC_elst, 0, 0, 0, flags);
+  elst->entries = 0;
+}
+
+static void
+atom_elst_clear (AtomELST * elst)
+{
+  GSList *walker;
+
+  atom_full_clear (&elst->header);
+  walker = elst->entries;
+  while (walker) {
+    g_free ((EditListEntry *) walker->data);
+    walker = g_slist_next (walker);
+  }
+  g_slist_free (elst->entries);
+}
+
+static void
+atom_edts_init (AtomEDTS * edts)
+{
+  atom_header_set (&edts->header, FOURCC_edts, 0, 0);
+  atom_elst_init (&edts->elst);
+}
+
+static void
+atom_edts_clear (AtomEDTS * edts)
+{
+  atom_clear (&edts->header);
+  atom_elst_clear (&edts->elst);
+}
+
+static AtomEDTS *
+atom_edts_new (void)
+{
+  AtomEDTS *edts = g_new0 (AtomEDTS, 1);
+  atom_edts_init (edts);
+  return edts;
+}
+
+static void
+atom_edts_free (AtomEDTS * edts)
+{
+  atom_edts_clear (edts);
+  g_free (edts);
+}
+
+static void
+atom_tcmi_init (AtomTCMI * tcmi)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&tcmi->header, FOURCC_tcmi, 0, 0, 0, flags);
+}
+
+static void
+atom_tcmi_clear (AtomTCMI * tcmi)
+{
+  atom_full_clear (&tcmi->header);
+  tcmi->text_font = 0;
+  tcmi->text_face = 0;
+  tcmi->text_size = 0;
+  tcmi->text_color[0] = 0;
+  tcmi->text_color[1] = 0;
+  tcmi->text_color[2] = 0;
+  tcmi->bg_color[0] = 0;
+  tcmi->bg_color[1] = 0;
+  tcmi->bg_color[2] = 0;
+  g_free (tcmi->font_name);
+  tcmi->font_name = NULL;
+}
+
+static void
+atom_tmcd_init (AtomTMCD * tmcd)
+{
+  atom_header_set (&tmcd->header, FOURCC_tmcd, 0, 0);
+  atom_tcmi_init (&tmcd->tcmi);
+}
+
+static void
+atom_tmcd_clear (AtomTMCD * tmcd)
+{
+  atom_clear (&tmcd->header);
+  atom_tcmi_clear (&tmcd->tcmi);
+}
+
+static void
+atom_gmin_init (AtomGMIN * gmin)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&gmin->header, FOURCC_gmin, 0, 0, 0, flags);
+}
+
+static void
+atom_gmin_clear (AtomGMIN * gmin)
+{
+  atom_full_clear (&gmin->header);
+  gmin->graphics_mode = 0;
+  gmin->opcolor[0] = 0;
+  gmin->opcolor[1] = 0;
+  gmin->opcolor[2] = 0;
+  gmin->balance = 0;
+  gmin->reserved = 0;
+}
+
+static void
+atom_gmhd_init (AtomGMHD * gmhd)
+{
+  atom_header_set (&gmhd->header, FOURCC_gmhd, 0, 0);
+  atom_gmin_init (&gmhd->gmin);
+  atom_tmcd_init (&gmhd->tmcd);
+}
+
+static void
+atom_gmhd_clear (AtomGMHD * gmhd)
+{
+  atom_clear (&gmhd->header);
+  atom_gmin_clear (&gmhd->gmin);
+  atom_tmcd_clear (&gmhd->tmcd);
+}
+
+static AtomGMHD *
+atom_gmhd_new (void)
+{
+  AtomGMHD *gmhd = g_new0 (AtomGMHD, 1);
+  atom_gmhd_init (gmhd);
+  return gmhd;
+}
+
+static void
+atom_gmhd_free (AtomGMHD * gmhd)
+{
+  atom_gmhd_clear (gmhd);
+  g_free (gmhd);
+}
+
+static void
+atom_sample_entry_init (SampleTableEntry * se, guint32 type)
+{
+  atom_header_set (&se->header, type, 0, 0);
+
+  memset (se->reserved, 0, sizeof (guint8) * 6);
+  se->data_reference_index = 0;
+}
+
+static void
+atom_sample_entry_free (SampleTableEntry * se)
+{
+  atom_clear (&se->header);
+}
+
+static void
+sample_entry_mp4a_init (SampleTableEntryMP4A * mp4a)
+{
+  atom_sample_entry_init (&mp4a->se, FOURCC_mp4a);
+
+  mp4a->version = 0;
+  mp4a->revision_level = 0;
+  mp4a->vendor = 0;
+  mp4a->channels = 2;
+  mp4a->sample_size = 16;
+  mp4a->compression_id = 0;
+  mp4a->packet_size = 0;
+  mp4a->sample_rate = 0;
+  /* following only used if version is 1 */
+  mp4a->samples_per_packet = 0;
+  mp4a->bytes_per_packet = 0;
+  mp4a->bytes_per_frame = 0;
+  mp4a->bytes_per_sample = 0;
+
+  mp4a->extension_atoms = NULL;
+}
+
+static SampleTableEntryMP4A *
+sample_entry_mp4a_new (void)
+{
+  SampleTableEntryMP4A *mp4a = g_new0 (SampleTableEntryMP4A, 1);
+
+  sample_entry_mp4a_init (mp4a);
+  return mp4a;
+}
+
+static void
+sample_entry_mp4a_free (SampleTableEntryMP4A * mp4a)
+{
+  atom_sample_entry_free (&mp4a->se);
+  atom_info_list_free (mp4a->extension_atoms);
+  g_free (mp4a);
+}
+
+static void
+sample_entry_tmcd_init (SampleTableEntryTMCD * tmcd)
+{
+  atom_sample_entry_init (&tmcd->se, FOURCC_tmcd);
+
+  tmcd->tc_flags = 0;
+  tmcd->timescale = 0;
+  tmcd->frame_duration = 0;
+  tmcd->n_frames = 0;
+
+  tmcd->name.language_code = 0;
+  g_free (tmcd->name.name);
+  tmcd->name.name = NULL;
+}
+
+static SampleTableEntryTMCD *
+sample_entry_tmcd_new (void)
+{
+  SampleTableEntryTMCD *tmcd = g_new0 (SampleTableEntryTMCD, 1);
+
+  sample_entry_tmcd_init (tmcd);
+  return tmcd;
+}
+
+static void
+sample_entry_tmcd_free (SampleTableEntryTMCD * tmcd)
+{
+  atom_sample_entry_free (&tmcd->se);
+  g_free (tmcd->name.name);
+  g_free (tmcd);
+}
+
+static void
+sample_entry_mp4v_init (SampleTableEntryMP4V * mp4v, AtomsContext * context)
+{
+  atom_sample_entry_init (&mp4v->se, FOURCC_mp4v);
+
+  mp4v->version = 0;
+  mp4v->revision_level = 0;
+  mp4v->vendor = 0;
+
+  mp4v->temporal_quality = 0;
+  mp4v->spatial_quality = 0;
+
+  /* qt and ISO base media do not contradict, and examples agree */
+  mp4v->horizontal_resolution = 0x00480000;
+  mp4v->vertical_resolution = 0x00480000;
+
+  mp4v->datasize = 0;
+  mp4v->frame_count = 1;
+
+  memset (mp4v->compressor, 0, sizeof (guint8) * 32);
+
+  mp4v->depth = 0;
+  mp4v->color_table_id = 0;
+
+  mp4v->extension_atoms = NULL;
+}
+
+static void
+sample_entry_mp4v_free (SampleTableEntryMP4V * mp4v)
+{
+  atom_sample_entry_free (&mp4v->se);
+  atom_info_list_free (mp4v->extension_atoms);
+  g_free (mp4v);
+}
+
+static SampleTableEntryMP4V *
+sample_entry_mp4v_new (AtomsContext * context)
+{
+  SampleTableEntryMP4V *mp4v = g_new0 (SampleTableEntryMP4V, 1);
+
+  sample_entry_mp4v_init (mp4v, context);
+  return mp4v;
+}
+
+static void
+sample_entry_tx3g_init (SampleTableEntryTX3G * tx3g)
+{
+  atom_sample_entry_init (&tx3g->se, FOURCC_tx3g);
+
+  tx3g->display_flags = 0;
+  tx3g->font_id = 1;            /* must be 1 as there is a single font */
+  tx3g->font_face = 0;
+  tx3g->foreground_color_rgba = 0xFFFFFFFF;     /* white, opaque */
+
+  /* can't set this now */
+  tx3g->default_text_box = 0;
+  tx3g->font_size = 0;
+}
+
+static void
+sample_entry_tx3g_free (SampleTableEntryTX3G * tx3g)
+{
+  atom_sample_entry_free (&tx3g->se);
+  g_free (tx3g);
+}
+
+static SampleTableEntryTX3G *
+sample_entry_tx3g_new (void)
+{
+  SampleTableEntryTX3G *tx3g = g_new0 (SampleTableEntryTX3G, 1);
+
+  sample_entry_tx3g_init (tx3g);
+  return tx3g;
+}
+
+
+static void
+atom_stsd_init (AtomSTSD * stsd)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&stsd->header, FOURCC_stsd, 0, 0, 0, flags);
+  stsd->entries = NULL;
+  stsd->n_entries = 0;
+}
+
+static void
+atom_stsd_remove_entries (AtomSTSD * stsd)
+{
+  GList *walker;
+
+  walker = stsd->entries;
+  while (walker) {
+    GList *aux = walker;
+    SampleTableEntry *se = (SampleTableEntry *) aux->data;
+
+    walker = g_list_next (walker);
+    stsd->entries = g_list_remove_link (stsd->entries, aux);
+
+    switch (se->kind) {
+      case AUDIO:
+        sample_entry_mp4a_free ((SampleTableEntryMP4A *) se);
+        break;
+      case VIDEO:
+        sample_entry_mp4v_free ((SampleTableEntryMP4V *) se);
+        break;
+      case SUBTITLE:
+        sample_entry_tx3g_free ((SampleTableEntryTX3G *) se);
+        break;
+      case TIMECODE:
+        sample_entry_tmcd_free ((SampleTableEntryTMCD *) se);
+        break;
+      default:
+        /* best possible cleanup */
+        atom_sample_entry_free (se);
+    }
+    g_list_free (aux);
+  }
+  stsd->n_entries = 0;
+}
+
+static void
+atom_stsd_clear (AtomSTSD * stsd)
+{
+  atom_stsd_remove_entries (stsd);
+  atom_full_clear (&stsd->header);
+}
+
+static void
+atom_ctts_init (AtomCTTS * ctts)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&ctts->header, FOURCC_ctts, 0, 0, 0, flags);
+  atom_array_init (&ctts->entries, 128);
+  ctts->do_pts = FALSE;
+}
+
+static AtomCTTS *
+atom_ctts_new (void)
+{
+  AtomCTTS *ctts = g_new0 (AtomCTTS, 1);
+
+  atom_ctts_init (ctts);
+  return ctts;
+}
+
+static void
+atom_ctts_free (AtomCTTS * ctts)
+{
+  atom_full_clear (&ctts->header);
+  atom_array_clear (&ctts->entries);
+  g_free (ctts);
+}
+
+static void
+atom_svmi_init (AtomSVMI * svmi)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&svmi->header, FOURCC_svmi, 0, 0, 0, flags);
+  svmi->stereoscopic_composition_type = 0x00;
+  svmi->is_left_first = FALSE;
+}
+
+AtomSVMI *
+atom_svmi_new (guint8 stereoscopic_composition_type, gboolean is_left_first)
+{
+  AtomSVMI *svmi = g_new0 (AtomSVMI, 1);
+
+  atom_svmi_init (svmi);
+  svmi->stereoscopic_composition_type = stereoscopic_composition_type;
+  svmi->is_left_first = is_left_first;
+  return svmi;
+}
+
+static void
+atom_svmi_free (AtomSVMI * svmi)
+{
+  g_free (svmi);
+}
+
+static void
+atom_stts_init (AtomSTTS * stts)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&stts->header, FOURCC_stts, 0, 0, 0, flags);
+  atom_array_init (&stts->entries, 512);
+}
+
+static void
+atom_stts_clear (AtomSTTS * stts)
+{
+  atom_full_clear (&stts->header);
+  atom_array_clear (&stts->entries);
+}
+
+static void
+atom_stsz_init (AtomSTSZ * stsz)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&stsz->header, FOURCC_stsz, 0, 0, 0, flags);
+  atom_array_init (&stsz->entries, 1024);
+  stsz->sample_size = 0;
+  stsz->table_size = 0;
+}
+
+static void
+atom_stsz_clear (AtomSTSZ * stsz)
+{
+  atom_full_clear (&stsz->header);
+  atom_array_clear (&stsz->entries);
+  stsz->table_size = 0;
+}
+
+static void
+atom_stsc_init (AtomSTSC * stsc)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&stsc->header, FOURCC_stsc, 0, 0, 0, flags);
+  atom_array_init (&stsc->entries, 128);
+}
+
+static void
+atom_stsc_clear (AtomSTSC * stsc)
+{
+  atom_full_clear (&stsc->header);
+  atom_array_clear (&stsc->entries);
+}
+
+static void
+atom_co64_init (AtomSTCO64 * co64)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&co64->header, FOURCC_stco, 0, 0, 0, flags);
+  atom_array_init (&co64->entries, 256);
+}
+
+static void
+atom_stco64_clear (AtomSTCO64 * stco64)
+{
+  atom_full_clear (&stco64->header);
+  atom_array_clear (&stco64->entries);
+}
+
+static void
+atom_stss_init (AtomSTSS * stss)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&stss->header, FOURCC_stss, 0, 0, 0, flags);
+  atom_array_init (&stss->entries, 128);
+}
+
+static void
+atom_stss_clear (AtomSTSS * stss)
+{
+  atom_full_clear (&stss->header);
+  atom_array_clear (&stss->entries);
+}
+
+void
+atom_stbl_init (AtomSTBL * stbl)
+{
+  atom_header_set (&stbl->header, FOURCC_stbl, 0, 0);
+
+  atom_stts_init (&stbl->stts);
+  atom_stss_init (&stbl->stss);
+  atom_stsd_init (&stbl->stsd);
+  atom_stsz_init (&stbl->stsz);
+  atom_stsc_init (&stbl->stsc);
+  stbl->ctts = NULL;
+  stbl->svmi = NULL;
+
+  atom_co64_init (&stbl->stco64);
+}
+
+void
+atom_stbl_clear (AtomSTBL * stbl)
+{
+  atom_clear (&stbl->header);
+  atom_stsd_clear (&stbl->stsd);
+  atom_stts_clear (&stbl->stts);
+  atom_stss_clear (&stbl->stss);
+  atom_stsc_clear (&stbl->stsc);
+  atom_stsz_clear (&stbl->stsz);
+  if (stbl->ctts) {
+    atom_ctts_free (stbl->ctts);
+  }
+  if (stbl->svmi) {
+    atom_svmi_free (stbl->svmi);
+  }
+  atom_stco64_clear (&stbl->stco64);
+}
+
+static void
+atom_vmhd_init (AtomVMHD * vmhd, AtomsContext * context)
+{
+  guint8 flags[3] = { 0, 0, 1 };
+
+  atom_full_init (&vmhd->header, FOURCC_vmhd, 0, 0, 0, flags);
+  vmhd->graphics_mode = 0x0;
+  memset (vmhd->opcolor, 0, sizeof (guint16) * 3);
+
+  if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
+    vmhd->graphics_mode = 0x40;
+    vmhd->opcolor[0] = 32768;
+    vmhd->opcolor[1] = 32768;
+    vmhd->opcolor[2] = 32768;
+  }
+}
+
+static AtomVMHD *
+atom_vmhd_new (AtomsContext * context)
+{
+  AtomVMHD *vmhd = g_new0 (AtomVMHD, 1);
+
+  atom_vmhd_init (vmhd, context);
+  return vmhd;
+}
+
+static void
+atom_vmhd_free (AtomVMHD * vmhd)
+{
+  atom_full_clear (&vmhd->header);
+  g_free (vmhd);
+}
+
+static void
+atom_smhd_init (AtomSMHD * smhd)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&smhd->header, FOURCC_smhd, 0, 0, 0, flags);
+  smhd->balance = 0;
+  smhd->reserved = 0;
+}
+
+static AtomSMHD *
+atom_smhd_new (void)
+{
+  AtomSMHD *smhd = g_new0 (AtomSMHD, 1);
+
+  atom_smhd_init (smhd);
+  return smhd;
+}
+
+static void
+atom_smhd_free (AtomSMHD * smhd)
+{
+  atom_full_clear (&smhd->header);
+  g_free (smhd);
+}
+
+static void
+atom_hmhd_free (AtomHMHD * hmhd)
+{
+  atom_full_clear (&hmhd->header);
+  g_free (hmhd);
+}
+
+static void
+atom_hdlr_init (AtomHDLR * hdlr, AtomsContext * context)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&hdlr->header, FOURCC_hdlr, 0, 0, 0, flags);
+
+  hdlr->component_type = 0;
+  hdlr->handler_type = 0;
+  hdlr->manufacturer = 0;
+  hdlr->flags = 0;
+  hdlr->flags_mask = 0;
+  hdlr->name = g_strdup ("");
+
+  /* Store the flavor to know how to serialize the 'name' string */
+  hdlr->flavor = context->flavor;
+}
+
+static AtomHDLR *
+atom_hdlr_new (AtomsContext * context)
+{
+  AtomHDLR *hdlr = g_new0 (AtomHDLR, 1);
+
+  atom_hdlr_init (hdlr, context);
+  return hdlr;
+}
+
+static void
+atom_hdlr_clear (AtomHDLR * hdlr)
+{
+  atom_full_clear (&hdlr->header);
+  if (hdlr->name) {
+    g_free (hdlr->name);
+    hdlr->name = NULL;
+  }
+}
+
+static void
+atom_hdlr_free (AtomHDLR * hdlr)
+{
+  atom_hdlr_clear (hdlr);
+  g_free (hdlr);
+}
+
+static void
+atom_url_init (AtomURL * url)
+{
+  guint8 flags[3] = { 0, 0, 1 };
+
+  atom_full_init (&url->header, FOURCC_url_, 0, 0, 0, flags);
+  url->location = NULL;
+}
+
+static void
+atom_url_free (AtomURL * url)
+{
+  atom_full_clear (&url->header);
+  if (url->location) {
+    g_free (url->location);
+    url->location = NULL;
+  }
+  g_free (url);
+}
+
+static AtomURL *
+atom_url_new (void)
+{
+  AtomURL *url = g_new0 (AtomURL, 1);
+
+  atom_url_init (url);
+  return url;
+}
+
+static AtomFull *
+atom_alis_new (void)
+{
+  guint8 flags[3] = { 0, 0, 1 };
+  AtomFull *alis = g_new0 (AtomFull, 1);
+
+  atom_full_init (alis, FOURCC_alis, 0, 0, 0, flags);
+  return alis;
+}
+
+static void
+atom_dref_init (AtomDREF * dref, AtomsContext * context)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&dref->header, FOURCC_dref, 0, 0, 0, flags);
+
+  /* in either case, alis or url init arranges to set self-contained flag */
+  if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
+    /* alis dref for qt */
+    AtomFull *alis = atom_alis_new ();
+    dref->entries = g_list_append (dref->entries, alis);
+  } else {
+    /* url for iso spec, as 'alis' not specified there */
+    AtomURL *url = atom_url_new ();
+    dref->entries = g_list_append (dref->entries, url);
+  }
+}
+
+static void
+atom_dref_clear (AtomDREF * dref)
+{
+  GList *walker;
+
+  atom_full_clear (&dref->header);
+  walker = dref->entries;
+  while (walker) {
+    GList *aux = walker;
+    Atom *atom = (Atom *) aux->data;
+
+    walker = g_list_next (walker);
+    dref->entries = g_list_remove_link (dref->entries, aux);
+    switch (atom->type) {
+      case FOURCC_alis:
+        atom_full_free ((AtomFull *) atom);
+        break;
+      case FOURCC_url_:
+        atom_url_free ((AtomURL *) atom);
+        break;
+      default:
+        /* we do nothing, better leak than crash */
+        break;
+    }
+    g_list_free (aux);
+  }
+}
+
+static void
+atom_dinf_init (AtomDINF * dinf, AtomsContext * context)
+{
+  atom_header_set (&dinf->header, FOURCC_dinf, 0, 0);
+  atom_dref_init (&dinf->dref, context);
+}
+
+static void
+atom_dinf_clear (AtomDINF * dinf)
+{
+  atom_clear (&dinf->header);
+  atom_dref_clear (&dinf->dref);
+}
+
+static void
+atom_minf_init (AtomMINF * minf, AtomsContext * context)
+{
+  atom_header_set (&minf->header, FOURCC_minf, 0, 0);
+
+  minf->vmhd = NULL;
+  minf->smhd = NULL;
+  minf->hmhd = NULL;
+  minf->gmhd = NULL;
+
+  if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
+    minf->hdlr = atom_hdlr_new (context);
+    minf->hdlr->component_type = FOURCC_dhlr;
+    minf->hdlr->handler_type = FOURCC_alis;
+  } else {
+    minf->hdlr = NULL;
+  }
+  atom_dinf_init (&minf->dinf, context);
+  atom_stbl_init (&minf->stbl);
+}
+
+static void
+atom_minf_clear_handlers (AtomMINF * minf)
+{
+  if (minf->vmhd) {
+    atom_vmhd_free (minf->vmhd);
+    minf->vmhd = NULL;
+  }
+  if (minf->smhd) {
+    atom_smhd_free (minf->smhd);
+    minf->smhd = NULL;
+  }
+  if (minf->hmhd) {
+    atom_hmhd_free (minf->hmhd);
+    minf->hmhd = NULL;
+  }
+  if (minf->gmhd) {
+    atom_gmhd_free (minf->gmhd);
+    minf->gmhd = NULL;
+  }
+}
+
+static void
+atom_minf_clear (AtomMINF * minf)
+{
+  atom_clear (&minf->header);
+  atom_minf_clear_handlers (minf);
+  if (minf->hdlr) {
+    atom_hdlr_free (minf->hdlr);
+  }
+  atom_dinf_clear (&minf->dinf);
+  atom_stbl_clear (&minf->stbl);
+}
+
+static void
+atom_mdhd_init (AtomMDHD * mdhd)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&mdhd->header, FOURCC_mdhd, 0, 0, 0, flags);
+  common_time_info_init (&mdhd->time_info);
+  /* tempting as it may be to simply 0-initialize,
+   * that will have the demuxer (correctly) come up with 'eng' as language
+   * so explicitly specify undefined instead */
+  mdhd->language_code =
+      ('u' - 0x60) * 0x400 + ('n' - 0x60) * 0x20 + ('d' - 0x60);
+  mdhd->quality = 0;
+}
+
+static void
+atom_mdhd_clear (AtomMDHD * mdhd)
+{
+  atom_full_clear (&mdhd->header);
+}
+
+static void
+atom_mdia_init (AtomMDIA * mdia, AtomsContext * context)
+{
+  atom_header_set (&mdia->header, FOURCC_mdia, 0, 0);
+
+  atom_mdhd_init (&mdia->mdhd);
+  atom_hdlr_init (&mdia->hdlr, context);
+  atom_minf_init (&mdia->minf, context);
+}
+
+static void
+atom_mdia_clear (AtomMDIA * mdia)
+{
+  atom_clear (&mdia->header);
+  atom_mdhd_clear (&mdia->mdhd);
+  atom_hdlr_clear (&mdia->hdlr);
+  atom_minf_clear (&mdia->minf);
+}
+
+static void
+atom_tkhd_init (AtomTKHD * tkhd, AtomsContext * context)
+{
+  /*
+   * flags info
+   * 1 -> track enabled
+   * 2 -> track in movie
+   * 4 -> track in preview
+   */
+  guint8 flags[3] = { 0, 0, 7 };
+
+  atom_full_init (&tkhd->header, FOURCC_tkhd, 0, 0, 0, flags);
+
+  tkhd->creation_time = tkhd->modification_time = atoms_get_current_qt_time ();
+  tkhd->duration = 0;
+  tkhd->track_ID = 0;
+  tkhd->reserved = 0;
+
+  tkhd->reserved2[0] = tkhd->reserved2[1] = 0;
+  tkhd->layer = 0;
+  tkhd->alternate_group = 0;
+  tkhd->volume = 0;
+  tkhd->reserved3 = 0;
+  memset (tkhd->matrix, 0, sizeof (guint32) * 9);
+  tkhd->matrix[0] = 1 << 16;
+  tkhd->matrix[4] = 1 << 16;
+  tkhd->matrix[8] = 16384 << 16;
+  tkhd->width = 0;
+  tkhd->height = 0;
+}
+
+static void
+atom_tkhd_clear (AtomTKHD * tkhd)
+{
+  atom_full_clear (&tkhd->header);
+}
+
+static void
+atom_ilst_init (AtomILST * ilst)
+{
+  atom_header_set (&ilst->header, FOURCC_ilst, 0, 0);
+  ilst->entries = NULL;
+}
+
+static AtomILST *
+atom_ilst_new (void)
+{
+  AtomILST *ilst = g_new0 (AtomILST, 1);
+
+  atom_ilst_init (ilst);
+  return ilst;
+}
+
+static void
+atom_ilst_free (AtomILST * ilst)
+{
+  if (ilst->entries)
+    atom_info_list_free (ilst->entries);
+  atom_clear (&ilst->header);
+  g_free (ilst);
+}
+
+static void
+atom_meta_init (AtomMETA * meta, AtomsContext * context)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&meta->header, FOURCC_meta, 0, 0, 0, flags);
+  atom_hdlr_init (&meta->hdlr, context);
+  /* FIXME (ISOM says this is always 0) */
+  meta->hdlr.component_type = FOURCC_mhlr;
+  meta->hdlr.handler_type = FOURCC_mdir;
+  meta->ilst = NULL;
+}
+
+static AtomMETA *
+atom_meta_new (AtomsContext * context)
+{
+  AtomMETA *meta = g_new0 (AtomMETA, 1);
+
+  atom_meta_init (meta, context);
+  return meta;
+}
+
+static void
+atom_meta_free (AtomMETA * meta)
+{
+  atom_full_clear (&meta->header);
+  atom_hdlr_clear (&meta->hdlr);
+  if (meta->ilst)
+    atom_ilst_free (meta->ilst);
+  meta->ilst = NULL;
+  g_free (meta);
+}
+
+static void
+atom_udta_init_metatags (AtomUDTA * udta, AtomsContext * context)
+{
+  if (context->flavor != ATOMS_TREE_FLAVOR_3GP) {
+    if (!udta->meta) {
+      udta->meta = atom_meta_new (context);
+    }
+    if (!udta->meta->ilst) {
+      udta->meta->ilst = atom_ilst_new ();
+    }
+  }
+}
+
+static void
+atom_udta_init (AtomUDTA * udta, AtomsContext * context)
+{
+  atom_header_set (&udta->header, FOURCC_udta, 0, 0);
+  udta->meta = NULL;
+  udta->context = context;
+
+  atom_udta_init_metatags (udta, context);
+}
+
+static void
+atom_udta_clear (AtomUDTA * udta)
+{
+  atom_clear (&udta->header);
+  if (udta->meta)
+    atom_meta_free (udta->meta);
+  udta->meta = NULL;
+  if (udta->entries)
+    atom_info_list_free (udta->entries);
+}
+
+static void
+atom_tref_init (AtomTREF * tref, guint32 reftype)
+{
+  atom_header_set (&tref->header, FOURCC_tref, 0, 0);
+  tref->reftype = reftype;
+  atom_array_init (&tref->entries, 128);
+}
+
+static void
+atom_tref_clear (AtomTREF * tref)
+{
+  atom_clear (&tref->header);
+  tref->reftype = 0;
+  atom_array_clear (&tref->entries);
+}
+
+AtomTREF *
+atom_tref_new (guint32 reftype)
+{
+  AtomTREF *tref;
+
+  tref = g_new0 (AtomTREF, 1);
+  atom_tref_init (tref, reftype);
+
+  return tref;
+}
+
+static void
+atom_tref_free (AtomTREF * tref)
+{
+  atom_tref_clear (tref);
+  g_free (tref);
+}
+
+/* Clear added tags, but keep the context/flavor the same */
+void
+atom_udta_clear_tags (AtomUDTA * udta)
+{
+  if (udta->entries) {
+    atom_info_list_free (udta->entries);
+    udta->entries = NULL;
+  }
+  if (udta->meta && udta->meta->ilst->entries) {
+    atom_info_list_free (udta->meta->ilst->entries);
+    udta->meta->ilst->entries = NULL;
+  }
+}
+
+static void
+atom_tag_data_init (AtomTagData * data)
+{
+  guint8 flags[] = { 0, 0, 0 };
+
+  atom_full_init (&data->header, FOURCC_data, 0, 0, 0, flags);
+}
+
+static void
+atom_tag_data_clear (AtomTagData * data)
+{
+  atom_full_clear (&data->header);
+  g_free (data->data);
+  data->datalen = 0;
+}
+
+/*
+ * Fourcc is the tag fourcc
+ * flags will be truncated to 24bits
+ */
+static AtomTag *
+atom_tag_new (guint32 fourcc, guint32 flags_as_uint)
+{
+  AtomTag *tag = g_new0 (AtomTag, 1);
+
+  tag->header.type = fourcc;
+  atom_tag_data_init (&tag->data);
+  atom_full_set_flags_as_uint (&tag->data.header, flags_as_uint);
+  return tag;
+}
+
+static void
+atom_tag_free (AtomTag * tag)
+{
+  atom_clear (&tag->header);
+  atom_tag_data_clear (&tag->data);
+  g_free (tag);
+}
+
+static void
+atom_mvhd_init (AtomMVHD * mvhd)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&(mvhd->header), FOURCC_mvhd, sizeof (AtomMVHD), 0, 0, flags);
+
+  common_time_info_init (&mvhd->time_info);
+
+  mvhd->prefered_rate = 1 << 16;
+  mvhd->volume = 1 << 8;
+  mvhd->reserved3 = 0;
+  memset (mvhd->reserved4, 0, sizeof (guint32[2]));
+
+  memset (mvhd->matrix, 0, sizeof (guint32[9]));
+  mvhd->matrix[0] = 1 << 16;
+  mvhd->matrix[4] = 1 << 16;
+  mvhd->matrix[8] = 16384 << 16;
+
+  mvhd->preview_time = 0;
+  mvhd->preview_duration = 0;
+  mvhd->poster_time = 0;
+  mvhd->selection_time = 0;
+  mvhd->selection_duration = 0;
+  mvhd->current_time = 0;
+
+  mvhd->next_track_id = 1;
+}
+
+static void
+atom_mvhd_clear (AtomMVHD * mvhd)
+{
+  atom_full_clear (&mvhd->header);
+}
+
+static void
+atom_mehd_init (AtomMEHD * mehd)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&mehd->header, FOURCC_mehd, 0, 0, 1, flags);
+  mehd->fragment_duration = 0;
+}
+
+static void
+atom_mvex_init (AtomMVEX * mvex)
+{
+  atom_header_set (&mvex->header, FOURCC_mvex, 0, 0);
+  atom_mehd_init (&mvex->mehd);
+  mvex->trexs = NULL;
+}
+
+static void
+atom_trak_init (AtomTRAK * trak, AtomsContext * context)
+{
+  atom_header_set (&trak->header, FOURCC_trak, 0, 0);
+
+  atom_tkhd_init (&trak->tkhd, context);
+  trak->context = context;
+  atom_udta_init (&trak->udta, context);
+  trak->edts = NULL;
+  atom_mdia_init (&trak->mdia, context);
+  trak->tref = NULL;
+}
+
+AtomTRAK *
+atom_trak_new (AtomsContext * context)
+{
+  AtomTRAK *trak = g_new0 (AtomTRAK, 1);
+
+  atom_trak_init (trak, context);
+  return trak;
+}
+
+static void
+atom_trak_clear (AtomTRAK * trak)
+{
+  atom_clear (&trak->header);
+  atom_tkhd_clear (&trak->tkhd);
+  if (trak->edts)
+    atom_edts_free (trak->edts);
+  atom_udta_clear (&trak->udta);
+  atom_mdia_clear (&trak->mdia);
+  if (trak->tref)
+    atom_tref_free (trak->tref);
+}
+
+static void
+atom_trak_free (AtomTRAK * trak)
+{
+  atom_trak_clear (trak);
+  g_free (trak);
+}
+
+
+static void
+atom_moov_init (AtomMOOV * moov, AtomsContext * context)
+{
+  atom_header_set (&(moov->header), FOURCC_moov, 0, 0);
+  atom_mvhd_init (&(moov->mvhd));
+  atom_mvex_init (&(moov->mvex));
+  atom_udta_init (&moov->udta, context);
+  moov->traks = NULL;
+  moov->context = *context;
+}
+
+AtomMOOV *
+atom_moov_new (AtomsContext * context)
+{
+  AtomMOOV *moov = g_new0 (AtomMOOV, 1);
+
+  atom_moov_init (moov, context);
+  return moov;
+}
+
+static void
+atom_trex_free (AtomTREX * trex)
+{
+  atom_full_clear (&trex->header);
+  g_free (trex);
+}
+
+static void
+atom_mvex_clear (AtomMVEX * mvex)
+{
+  GList *walker;
+
+  atom_clear (&mvex->header);
+  walker = mvex->trexs;
+  while (walker) {
+    atom_trex_free ((AtomTREX *) walker->data);
+    walker = g_list_next (walker);
+  }
+  g_list_free (mvex->trexs);
+  mvex->trexs = NULL;
+}
+
+void
+atom_moov_free (AtomMOOV * moov)
+{
+  GList *walker;
+
+  atom_clear (&moov->header);
+  atom_mvhd_clear (&moov->mvhd);
+
+  walker = moov->traks;
+  while (walker) {
+    atom_trak_free ((AtomTRAK *) walker->data);
+    walker = g_list_next (walker);
+  }
+  g_list_free (moov->traks);
+  moov->traks = NULL;
+
+  atom_udta_clear (&moov->udta);
+  atom_mvex_clear (&moov->mvex);
+
+  g_free (moov);
+}
+
+/* -- end of init / free -- */
+
+/* -- copy data functions -- */
+
+static guint8
+atom_full_get_version (AtomFull * full)
+{
+  return full->version;
+}
+
+static guint64
+common_time_info_copy_data (TimeInfo * ti, gboolean trunc_to_32,
+    guint8 ** buffer, guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (trunc_to_32) {
+    prop_copy_uint32 ((guint32) ti->creation_time, buffer, size, offset);
+    prop_copy_uint32 ((guint32) ti->modification_time, buffer, size, offset);
+    prop_copy_uint32 (ti->timescale, buffer, size, offset);
+    prop_copy_uint32 ((guint32) ti->duration, buffer, size, offset);
+  } else {
+    prop_copy_uint64 (ti->creation_time, buffer, size, offset);
+    prop_copy_uint64 (ti->modification_time, buffer, size, offset);
+    prop_copy_uint32 (ti->timescale, buffer, size, offset);
+    prop_copy_uint64 (ti->duration, buffer, size, offset);
+  }
+  return *offset - original_offset;
+}
+
+static void
+atom_write_size (guint8 ** buffer, guint64 * size, guint64 * offset,
+    guint64 atom_pos)
+{
+  /* this only works for non-extended atom size, which is OK
+   * (though it could be made to do mem_move, etc and write extended size) */
+  prop_copy_uint32 (*offset - atom_pos, buffer, size, &atom_pos);
+}
+
+static guint64
+atom_copy_empty (Atom * atom, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  prop_copy_uint32 (0, buffer, size, offset);
+
+  return *offset - original_offset;
+}
+
+guint64
+atom_copy_data (Atom * atom, guint8 ** buffer, guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  /* copies type and size */
+  prop_copy_uint32 (atom->size, buffer, size, offset);
+  prop_copy_fourcc (atom->type, buffer, size, offset);
+
+  /* extended size needed */
+  if (atom->size == 1) {
+    /* really should not happen other than with mdat atom;
+     * would be a problem for size (re)write code, not to mention memory */
+    g_return_val_if_fail (atom->type == FOURCC_mdat, 0);
+    prop_copy_uint64 (atom->extended_size, buffer, size, offset);
+  }
+
+  return *offset - original_offset;
+}
+
+static guint64
+atom_full_copy_data (AtomFull * atom, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&atom->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint8 (atom->version, buffer, size, offset);
+  prop_copy_uint8_array (atom->flags, 3, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_info_list_copy_data (GList * ai, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  while (ai) {
+    AtomInfo *info = (AtomInfo *) ai->data;
+
+    if (!info->copy_data_func (info->atom, buffer, size, offset)) {
+      return 0;
+    }
+    ai = g_list_next (ai);
+  }
+
+  return *offset - original_offset;
+}
+
+static guint64
+atom_data_copy_data (AtomData * data, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&data->header, buffer, size, offset)) {
+    return 0;
+  }
+  if (data->datalen)
+    prop_copy_uint8_array (data->data, data->datalen, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_uuid_copy_data (AtomUUID * uuid, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&uuid->header, buffer, size, offset)) {
+    return 0;
+  }
+  prop_copy_uint8_array (uuid->uuid, 16, buffer, size, offset);
+  if (uuid->datalen)
+    prop_copy_uint8_array (uuid->data, uuid->datalen, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+guint64
+atom_ftyp_copy_data (AtomFTYP * ftyp, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&ftyp->header, buffer, size, offset)) {
+    return 0;
+  }
+  prop_copy_fourcc (ftyp->major_brand, buffer, size, offset);
+  prop_copy_uint32 (ftyp->version, buffer, size, offset);
+
+  prop_copy_fourcc_array (ftyp->compatible_brands, ftyp->compatible_brands_size,
+      buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+guint64
+atom_mvhd_copy_data (AtomMVHD * atom, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint8 version;
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&(atom->header), buffer, size, offset)) {
+    return 0;
+  }
+
+  version = atom_full_get_version (&(atom->header));
+  if (version == 0) {
+    common_time_info_copy_data (&atom->time_info, TRUE, buffer, size, offset);
+  } else if (version == 1) {
+    common_time_info_copy_data (&atom->time_info, FALSE, buffer, size, offset);
+  } else {
+    *offset = original_offset;
+    return 0;
+  }
+
+  prop_copy_uint32 (atom->prefered_rate, buffer, size, offset);
+  prop_copy_uint16 (atom->volume, buffer, size, offset);
+  prop_copy_uint16 (atom->reserved3, buffer, size, offset);
+  prop_copy_uint32_array (atom->reserved4, 2, buffer, size, offset);
+  prop_copy_uint32_array (atom->matrix, 9, buffer, size, offset);
+  prop_copy_uint32 (atom->preview_time, buffer, size, offset);
+  prop_copy_uint32 (atom->preview_duration, buffer, size, offset);
+  prop_copy_uint32 (atom->poster_time, buffer, size, offset);
+  prop_copy_uint32 (atom->selection_time, buffer, size, offset);
+  prop_copy_uint32 (atom->selection_duration, buffer, size, offset);
+  prop_copy_uint32 (atom->current_time, buffer, size, offset);
+
+  prop_copy_uint32 (atom->next_track_id, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_tkhd_copy_data (AtomTKHD * tkhd, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&tkhd->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  if (atom_full_get_version (&tkhd->header) == 0) {
+    prop_copy_uint32 ((guint32) tkhd->creation_time, buffer, size, offset);
+    prop_copy_uint32 ((guint32) tkhd->modification_time, buffer, size, offset);
+    prop_copy_uint32 (tkhd->track_ID, buffer, size, offset);
+    prop_copy_uint32 (tkhd->reserved, buffer, size, offset);
+    prop_copy_uint32 ((guint32) tkhd->duration, buffer, size, offset);
+  } else {
+    prop_copy_uint64 (tkhd->creation_time, buffer, size, offset);
+    prop_copy_uint64 (tkhd->modification_time, buffer, size, offset);
+    prop_copy_uint32 (tkhd->track_ID, buffer, size, offset);
+    prop_copy_uint32 (tkhd->reserved, buffer, size, offset);
+    prop_copy_uint64 (tkhd->duration, buffer, size, offset);
+  }
+
+  prop_copy_uint32_array (tkhd->reserved2, 2, buffer, size, offset);
+  prop_copy_uint16 (tkhd->layer, buffer, size, offset);
+  prop_copy_uint16 (tkhd->alternate_group, buffer, size, offset);
+  prop_copy_uint16 (tkhd->volume, buffer, size, offset);
+  prop_copy_uint16 (tkhd->reserved3, buffer, size, offset);
+  prop_copy_uint32_array (tkhd->matrix, 9, buffer, size, offset);
+
+  prop_copy_uint32 (tkhd->width, buffer, size, offset);
+  prop_copy_uint32 (tkhd->height, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_hdlr_copy_data (AtomHDLR * hdlr, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&hdlr->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_fourcc (hdlr->component_type, buffer, size, offset);
+  prop_copy_fourcc (hdlr->handler_type, buffer, size, offset);
+  prop_copy_fourcc (hdlr->manufacturer, buffer, size, offset);
+  prop_copy_uint32 (hdlr->flags, buffer, size, offset);
+  prop_copy_uint32 (hdlr->flags_mask, buffer, size, offset);
+
+  if (hdlr->flavor == ATOMS_TREE_FLAVOR_MOV) {
+    prop_copy_size_string ((guint8 *) hdlr->name, strlen (hdlr->name), buffer,
+        size, offset);
+  } else {
+    /* assume isomedia base is more generic and use null terminated */
+    prop_copy_null_terminated_string (hdlr->name, buffer, size, offset);
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_vmhd_copy_data (AtomVMHD * vmhd, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&vmhd->header, buffer, size, offset)) {
+    return 0;
+  }
+  prop_copy_uint16 (vmhd->graphics_mode, buffer, size, offset);
+  prop_copy_uint16_array (vmhd->opcolor, 3, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return original_offset - *offset;
+}
+
+static guint64
+atom_smhd_copy_data (AtomSMHD * smhd, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&smhd->header, buffer, size, offset)) {
+    return 0;
+  }
+  prop_copy_uint16 (smhd->balance, buffer, size, offset);
+  prop_copy_uint16 (smhd->reserved, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return original_offset - *offset;
+}
+
+static guint64
+atom_hmhd_copy_data (AtomHMHD * hmhd, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&hmhd->header, buffer, size, offset)) {
+    return 0;
+  }
+  prop_copy_uint16 (hmhd->max_pdu_size, buffer, size, offset);
+  prop_copy_uint16 (hmhd->avg_pdu_size, buffer, size, offset);
+  prop_copy_uint32 (hmhd->max_bitrate, buffer, size, offset);
+  prop_copy_uint32 (hmhd->avg_bitrate, buffer, size, offset);
+  prop_copy_uint32 (hmhd->sliding_avg_bitrate, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return original_offset - *offset;
+}
+
+static guint64
+atom_tcmi_copy_data (AtomTCMI * tcmi, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&tcmi->header, buffer, size, offset)) {
+    return 0;
+  }
+  prop_copy_uint16 (tcmi->text_font, buffer, size, offset);
+  prop_copy_uint16 (tcmi->text_face, buffer, size, offset);
+  prop_copy_uint16 (tcmi->text_size, buffer, size, offset);
+  prop_copy_uint16 (tcmi->text_color[0], buffer, size, offset);
+  prop_copy_uint16 (tcmi->text_color[1], buffer, size, offset);
+  prop_copy_uint16 (tcmi->text_color[2], buffer, size, offset);
+  prop_copy_uint16 (tcmi->bg_color[0], buffer, size, offset);
+  prop_copy_uint16 (tcmi->bg_color[1], buffer, size, offset);
+  prop_copy_uint16 (tcmi->bg_color[2], buffer, size, offset);
+  /* reserved */
+  prop_copy_uint16 (0, buffer, size, offset);
+  prop_copy_size_string ((guint8 *) tcmi->font_name, strlen (tcmi->font_name),
+      buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return original_offset - *offset;
+}
+
+static guint64
+atom_tmcd_copy_data (AtomTMCD * tmcd, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&tmcd->header, buffer, size, offset)) {
+    return 0;
+  }
+  if (!atom_tcmi_copy_data (&tmcd->tcmi, buffer, size, offset)) {
+    return 0;
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return original_offset - *offset;
+}
+
+static guint64
+atom_gmin_copy_data (AtomGMIN * gmin, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&gmin->header, buffer, size, offset)) {
+    return 0;
+  }
+  prop_copy_uint16 (gmin->graphics_mode, buffer, size, offset);
+  prop_copy_uint16 (gmin->opcolor[0], buffer, size, offset);
+  prop_copy_uint16 (gmin->opcolor[1], buffer, size, offset);
+  prop_copy_uint16 (gmin->opcolor[2], buffer, size, offset);
+  prop_copy_uint8 (gmin->balance, buffer, size, offset);
+  /* reserved */
+  prop_copy_uint8 (0, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return original_offset - *offset;
+}
+
+static guint64
+atom_gmhd_copy_data (AtomGMHD * gmhd, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&gmhd->header, buffer, size, offset)) {
+    return 0;
+  }
+  if (!atom_gmin_copy_data (&gmhd->gmin, buffer, size, offset)) {
+    return 0;
+  }
+  if (!atom_tmcd_copy_data (&gmhd->tmcd, buffer, size, offset)) {
+    return 0;
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return original_offset - *offset;
+}
+
+static gboolean
+atom_url_same_file_flag (AtomURL * url)
+{
+  return (url->header.flags[2] & 0x1) == 1;
+}
+
+static guint64
+atom_url_copy_data (AtomURL * url, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&url->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  if (!atom_url_same_file_flag (url)) {
+    prop_copy_null_terminated_string (url->location, buffer, size, offset);
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return original_offset - *offset;
+}
+
+guint64
+atom_stts_copy_data (AtomSTTS * stts, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  guint i;
+
+  if (!atom_full_copy_data (&stts->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (atom_array_get_len (&stts->entries), buffer, size, offset);
+  /* minimize realloc */
+  prop_copy_ensure_buffer (buffer, size, offset,
+      8 * atom_array_get_len (&stts->entries));
+  for (i = 0; i < atom_array_get_len (&stts->entries); i++) {
+    STTSEntry *entry = &atom_array_index (&stts->entries, i);
+
+    prop_copy_uint32 (entry->sample_count, buffer, size, offset);
+    prop_copy_int32 (entry->sample_delta, buffer, size, offset);
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_sample_entry_copy_data (SampleTableEntry * se, guint8 ** buffer,
+    guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&se->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint8_array (se->reserved, 6, buffer, size, offset);
+  prop_copy_uint16 (se->data_reference_index, buffer, size, offset);
+
+  return *offset - original_offset;
+}
+
+static guint64
+atom_esds_copy_data (AtomESDS * esds, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&esds->header, buffer, size, offset)) {
+    return 0;
+  }
+  if (!desc_es_descriptor_copy_data (&esds->es, buffer, size, offset)) {
+    return 0;
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_frma_copy_data (AtomFRMA * frma, guint8 ** buffer,
+    guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&(frma->header), buffer, size, offset))
+    return 0;
+
+  prop_copy_fourcc (frma->media_type, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_hint_sample_entry_copy_data (AtomHintSampleEntry * hse, guint8 ** buffer,
+    guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_sample_entry_copy_data (&hse->se, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (hse->size, buffer, size, offset);
+  prop_copy_uint8_array (hse->data, hse->size, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+sample_entry_mp4a_copy_data (SampleTableEntryMP4A * mp4a, guint8 ** buffer,
+    guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_sample_entry_copy_data (&mp4a->se, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint16 (mp4a->version, buffer, size, offset);
+  prop_copy_uint16 (mp4a->revision_level, buffer, size, offset);
+  prop_copy_uint32 (mp4a->vendor, buffer, size, offset);
+  prop_copy_uint16 (mp4a->channels, buffer, size, offset);
+  prop_copy_uint16 (mp4a->sample_size, buffer, size, offset);
+  prop_copy_uint16 (mp4a->compression_id, buffer, size, offset);
+  prop_copy_uint16 (mp4a->packet_size, buffer, size, offset);
+  prop_copy_uint32 (mp4a->sample_rate, buffer, size, offset);
+
+  /* this should always be 0 for mp4 flavor */
+  if (mp4a->version == 1) {
+    prop_copy_uint32 (mp4a->samples_per_packet, buffer, size, offset);
+    prop_copy_uint32 (mp4a->bytes_per_packet, buffer, size, offset);
+    prop_copy_uint32 (mp4a->bytes_per_frame, buffer, size, offset);
+    prop_copy_uint32 (mp4a->bytes_per_sample, buffer, size, offset);
+  }
+
+  if (mp4a->extension_atoms) {
+    if (!atom_info_list_copy_data (mp4a->extension_atoms, buffer, size, offset))
+      return 0;
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+sample_entry_mp4v_copy_data (SampleTableEntryMP4V * mp4v, guint8 ** buffer,
+    guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_sample_entry_copy_data (&mp4v->se, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint16 (mp4v->version, buffer, size, offset);
+  prop_copy_uint16 (mp4v->revision_level, buffer, size, offset);
+  prop_copy_fourcc (mp4v->vendor, buffer, size, offset);
+  prop_copy_uint32 (mp4v->temporal_quality, buffer, size, offset);
+  prop_copy_uint32 (mp4v->spatial_quality, buffer, size, offset);
+
+  prop_copy_uint16 (mp4v->width, buffer, size, offset);
+  prop_copy_uint16 (mp4v->height, buffer, size, offset);
+
+  prop_copy_uint32 (mp4v->horizontal_resolution, buffer, size, offset);
+  prop_copy_uint32 (mp4v->vertical_resolution, buffer, size, offset);
+  prop_copy_uint32 (mp4v->datasize, buffer, size, offset);
+
+  prop_copy_uint16 (mp4v->frame_count, buffer, size, offset);
+
+  prop_copy_fixed_size_string ((guint8 *) mp4v->compressor, 32, buffer, size,
+      offset);
+
+  prop_copy_uint16 (mp4v->depth, buffer, size, offset);
+  prop_copy_uint16 (mp4v->color_table_id, buffer, size, offset);
+
+  /* extra atoms */
+  if (mp4v->extension_atoms &&
+      !atom_info_list_copy_data (mp4v->extension_atoms, buffer, size, offset))
+    return 0;
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+sample_entry_tx3g_copy_data (SampleTableEntryTX3G * tx3g, guint8 ** buffer,
+    guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_sample_entry_copy_data (&tx3g->se, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (tx3g->display_flags, buffer, size, offset);
+
+  /* reserved */
+  prop_copy_uint8 (1, buffer, size, offset);
+  prop_copy_uint8 (-1, buffer, size, offset);
+  prop_copy_uint32 (0, buffer, size, offset);
+
+  prop_copy_uint64 (tx3g->default_text_box, buffer, size, offset);
+
+  /* reserved */
+  prop_copy_uint32 (0, buffer, size, offset);
+
+  prop_copy_uint16 (tx3g->font_id, buffer, size, offset);
+  prop_copy_uint8 (tx3g->font_face, buffer, size, offset);
+  prop_copy_uint8 (tx3g->font_size, buffer, size, offset);
+  prop_copy_uint32 (tx3g->foreground_color_rgba, buffer, size, offset);
+
+  /* it must have a fonttable atom */
+  {
+    Atom atom;
+
+    atom_header_set (&atom, FOURCC_ftab, 18, 0);
+    if (!atom_copy_data (&atom, buffer, size, offset))
+      return 0;
+    prop_copy_uint16 (1, buffer, size, offset); /* Count must be 1 */
+    prop_copy_uint16 (1, buffer, size, offset); /* Font id: 1 */
+    prop_copy_size_string ((guint8 *) "Serif", 5, buffer, size, offset);
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+sample_entry_tmcd_copy_data (SampleTableEntryTMCD * tmcd, guint8 ** buffer,
+    guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_sample_entry_copy_data (&tmcd->se, buffer, size, offset)) {
+    return 0;
+  }
+
+  /* reserved */
+  prop_copy_uint32 (0, buffer, size, offset);
+
+  prop_copy_uint32 (tmcd->tc_flags, buffer, size, offset);
+  prop_copy_uint32 (tmcd->timescale, buffer, size, offset);
+  prop_copy_uint32 (tmcd->frame_duration, buffer, size, offset);
+  prop_copy_uint8 (tmcd->n_frames, buffer, size, offset);
+
+  /* reserved */
+  prop_copy_uint8 (0, buffer, size, offset);
+  {
+    Atom atom;
+    guint64 name_offset = *offset;
+
+    atom_header_set (&atom, FOURCC_name, 0, 0);
+    if (!atom_copy_data (&atom, buffer, size, offset))
+      return 0;
+    prop_copy_uint16 (strlen (tmcd->name.name), buffer, size, offset);
+    prop_copy_uint16 (tmcd->name.language_code, buffer, size, offset);
+    prop_copy_fixed_size_string ((guint8 *) tmcd->name.name,
+        strlen (tmcd->name.name), buffer, size, offset);
+
+    atom_write_size (buffer, size, offset, name_offset);
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+guint64
+atom_stsz_copy_data (AtomSTSZ * stsz, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  guint i;
+
+  if (!atom_full_copy_data (&stsz->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (stsz->sample_size, buffer, size, offset);
+  prop_copy_uint32 (stsz->table_size, buffer, size, offset);
+  if (stsz->sample_size == 0) {
+    /* minimize realloc */
+    prop_copy_ensure_buffer (buffer, size, offset, 4 * stsz->table_size);
+    /* entry count must match sample count */
+    g_assert (atom_array_get_len (&stsz->entries) == stsz->table_size);
+    for (i = 0; i < atom_array_get_len (&stsz->entries); i++) {
+      prop_copy_uint32 (atom_array_index (&stsz->entries, i), buffer, size,
+          offset);
+    }
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+guint64
+atom_stsc_copy_data (AtomSTSC * stsc, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  guint i, len;
+  gboolean last_entries_merged = FALSE;
+
+  if (!atom_full_copy_data (&stsc->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  /* Last two entries might be the same size here as we only merge once the
+   * next chunk is started */
+  if ((len = atom_array_get_len (&stsc->entries)) > 1 &&
+      ((atom_array_index (&stsc->entries, len - 1)).samples_per_chunk ==
+          (atom_array_index (&stsc->entries, len - 2)).samples_per_chunk)) {
+    stsc->entries.len--;
+    last_entries_merged = TRUE;
+  }
+
+  prop_copy_uint32 (atom_array_get_len (&stsc->entries), buffer, size, offset);
+  /* minimize realloc */
+  prop_copy_ensure_buffer (buffer, size, offset,
+      12 * atom_array_get_len (&stsc->entries));
+
+  for (i = 0; i < atom_array_get_len (&stsc->entries); i++) {
+    STSCEntry *entry = &atom_array_index (&stsc->entries, i);
+
+    prop_copy_uint32 (entry->first_chunk, buffer, size, offset);
+    prop_copy_uint32 (entry->samples_per_chunk, buffer, size, offset);
+    prop_copy_uint32 (entry->sample_description_index, buffer, size, offset);
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+
+  /* Need to add the last entry again as in "robust" muxing mode we will most
+   * likely add new samples to the last chunk, thus making the
+   * samples_per_chunk in the last one different to the second to last one,
+   * and thus making it wrong to keep them merged
+   */
+  if (last_entries_merged)
+    stsc->entries.len++;
+
+  return *offset - original_offset;
+}
+
+guint64
+atom_ctts_copy_data (AtomCTTS * ctts, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  guint i;
+
+  if (!atom_full_copy_data (&ctts->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (atom_array_get_len (&ctts->entries), buffer, size, offset);
+  /* minimize realloc */
+  prop_copy_ensure_buffer (buffer, size, offset,
+      8 * atom_array_get_len (&ctts->entries));
+  for (i = 0; i < atom_array_get_len (&ctts->entries); i++) {
+    CTTSEntry *entry = &atom_array_index (&ctts->entries, i);
+
+    prop_copy_uint32 (entry->samplecount, buffer, size, offset);
+    prop_copy_uint32 (entry->sampleoffset, buffer, size, offset);
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+guint64
+atom_svmi_copy_data (AtomSVMI * svmi, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&svmi->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint8 (svmi->stereoscopic_composition_type, buffer, size, offset);
+  prop_copy_uint8 (svmi->is_left_first ? 1 : 0, buffer, size, offset);
+  /* stereo-mono change count */
+  prop_copy_uint32 (0, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+guint64
+atom_stco64_copy_data (AtomSTCO64 * stco64, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  guint i;
+  gboolean trunc_to_32 = stco64->header.header.type == FOURCC_stco;
+
+  if (!atom_full_copy_data (&stco64->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (atom_array_get_len (&stco64->entries), buffer, size,
+      offset);
+
+  /* minimize realloc */
+  prop_copy_ensure_buffer (buffer, size, offset,
+      8 * atom_array_get_len (&stco64->entries));
+  for (i = 0; i < atom_array_get_len (&stco64->entries); i++) {
+    guint64 value =
+        atom_array_index (&stco64->entries, i) + stco64->chunk_offset;
+
+    if (trunc_to_32) {
+      prop_copy_uint32 ((guint32) value, buffer, size, offset);
+    } else {
+      prop_copy_uint64 (value, buffer, size, offset);
+    }
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+guint64
+atom_stss_copy_data (AtomSTSS * stss, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  guint i;
+
+  if (atom_array_get_len (&stss->entries) == 0) {
+    /* FIXME not needing this atom might be confused with error while copying */
+    return 0;
+  }
+
+  if (!atom_full_copy_data (&stss->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (atom_array_get_len (&stss->entries), buffer, size, offset);
+  /* minimize realloc */
+  prop_copy_ensure_buffer (buffer, size, offset,
+      4 * atom_array_get_len (&stss->entries));
+  for (i = 0; i < atom_array_get_len (&stss->entries); i++) {
+    prop_copy_uint32 (atom_array_index (&stss->entries, i), buffer, size,
+        offset);
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_stsd_copy_data (AtomSTSD * stsd, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  GList *walker;
+
+  if (!atom_full_copy_data (&stsd->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (stsd->n_entries, buffer, size, offset);
+
+  for (walker = g_list_last (stsd->entries); walker != NULL;
+      walker = g_list_previous (walker)) {
+    SampleTableEntry *se = (SampleTableEntry *) walker->data;
+
+    switch (((Atom *) walker->data)->type) {
+      case FOURCC_mp4a:
+        if (!sample_entry_mp4a_copy_data ((SampleTableEntryMP4A *) walker->data,
+                buffer, size, offset)) {
+          return 0;
+        }
+        break;
+      case FOURCC_mp4v:
+        if (!sample_entry_mp4v_copy_data ((SampleTableEntryMP4V *) walker->data,
+                buffer, size, offset)) {
+          return 0;
+        }
+        break;
+      default:
+        if (se->kind == VIDEO) {
+          if (!sample_entry_mp4v_copy_data ((SampleTableEntryMP4V *)
+                  walker->data, buffer, size, offset)) {
+            return 0;
+          }
+        } else if (se->kind == AUDIO) {
+          if (!sample_entry_mp4a_copy_data ((SampleTableEntryMP4A *)
+                  walker->data, buffer, size, offset)) {
+            return 0;
+          }
+        } else if (se->kind == SUBTITLE) {
+          if (!sample_entry_tx3g_copy_data ((SampleTableEntryTX3G *)
+                  walker->data, buffer, size, offset)) {
+            return 0;
+          }
+        } else if (se->kind == TIMECODE) {
+          if (!sample_entry_tmcd_copy_data ((SampleTableEntryTMCD *)
+                  walker->data, buffer, size, offset)) {
+            return 0;
+          }
+        } else {
+          if (!atom_hint_sample_entry_copy_data (
+                  (AtomHintSampleEntry *) walker->data, buffer, size, offset)) {
+            return 0;
+          }
+        }
+        break;
+    }
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_stbl_copy_data (AtomSTBL * stbl, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&stbl->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  if (!atom_stsd_copy_data (&stbl->stsd, buffer, size, offset)) {
+    return 0;
+  }
+  if (!atom_stts_copy_data (&stbl->stts, buffer, size, offset)) {
+    return 0;
+  }
+  /* this atom is optional, so let's check if we need it
+   * (to avoid false error) */
+  if (atom_array_get_len (&stbl->stss.entries)) {
+    if (!atom_stss_copy_data (&stbl->stss, buffer, size, offset)) {
+      return 0;
+    }
+  }
+
+  if (!atom_stsc_copy_data (&stbl->stsc, buffer, size, offset)) {
+    return 0;
+  }
+  if (!atom_stsz_copy_data (&stbl->stsz, buffer, size, offset)) {
+    return 0;
+  }
+  if (stbl->ctts && stbl->ctts->do_pts) {
+    if (!atom_ctts_copy_data (stbl->ctts, buffer, size, offset)) {
+      return 0;
+    }
+  }
+  if (stbl->svmi) {
+    if (!atom_svmi_copy_data (stbl->svmi, buffer, size, offset)) {
+      return 0;
+    }
+  }
+  if (!atom_stco64_copy_data (&stbl->stco64, buffer, size, offset)) {
+    return 0;
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return original_offset - *offset;
+}
+
+
+static guint64
+atom_dref_copy_data (AtomDREF * dref, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  GList *walker;
+
+  if (!atom_full_copy_data (&dref->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (g_list_length (dref->entries), buffer, size, offset);
+
+  walker = dref->entries;
+  while (walker != NULL) {
+    Atom *atom = (Atom *) walker->data;
+
+    if (atom->type == FOURCC_url_) {
+      if (!atom_url_copy_data ((AtomURL *) atom, buffer, size, offset))
+        return 0;
+    } else if (atom->type == FOURCC_alis) {
+      if (!atom_full_copy_data ((AtomFull *) atom, buffer, size, offset))
+        return 0;
+    } else {
+      g_error ("Unsupported atom used inside dref atom");
+    }
+    walker = g_list_next (walker);
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_dinf_copy_data (AtomDINF * dinf, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&dinf->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  if (!atom_dref_copy_data (&dinf->dref, buffer, size, offset)) {
+    return 0;
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return original_offset - *offset;
+}
+
+static guint64
+atom_minf_copy_data (AtomMINF * minf, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&minf->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  if (minf->vmhd) {
+    if (!atom_vmhd_copy_data (minf->vmhd, buffer, size, offset)) {
+      return 0;
+    }
+  } else if (minf->smhd) {
+    if (!atom_smhd_copy_data (minf->smhd, buffer, size, offset)) {
+      return 0;
+    }
+  } else if (minf->hmhd) {
+    if (!atom_hmhd_copy_data (minf->hmhd, buffer, size, offset)) {
+      return 0;
+    }
+  } else if (minf->gmhd) {
+    if (!atom_gmhd_copy_data (minf->gmhd, buffer, size, offset)) {
+      return 0;
+    }
+  }
+
+  if (minf->hdlr) {
+    if (!atom_hdlr_copy_data (minf->hdlr, buffer, size, offset)) {
+      return 0;
+    }
+  }
+
+  if (!atom_dinf_copy_data (&minf->dinf, buffer, size, offset)) {
+    return 0;
+  }
+  if (!atom_stbl_copy_data (&minf->stbl, buffer, size, offset)) {
+    return 0;
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_mdhd_copy_data (AtomMDHD * mdhd, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&mdhd->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  if (!common_time_info_copy_data (&mdhd->time_info,
+          atom_full_get_version (&mdhd->header) == 0, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint16 (mdhd->language_code, buffer, size, offset);
+  prop_copy_uint16 (mdhd->quality, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_mdia_copy_data (AtomMDIA * mdia, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&mdia->header, buffer, size, offset)) {
+    return 0;
+  }
+  if (!atom_mdhd_copy_data (&mdia->mdhd, buffer, size, offset)) {
+    return 0;
+  }
+  if (!atom_hdlr_copy_data (&mdia->hdlr, buffer, size, offset)) {
+    return 0;
+  }
+
+  if (!atom_minf_copy_data (&mdia->minf, buffer, size, offset)) {
+    return 0;
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_elst_copy_data (AtomELST * elst, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  GSList *walker;
+
+  if (!atom_full_copy_data (&elst->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (g_slist_length (elst->entries), buffer, size, offset);
+
+  for (walker = elst->entries; walker != NULL; walker = g_slist_next (walker)) {
+    EditListEntry *entry = (EditListEntry *) walker->data;
+    prop_copy_uint32 (entry->duration, buffer, size, offset);
+    prop_copy_uint32 (entry->media_time, buffer, size, offset);
+    prop_copy_uint32 (entry->media_rate, buffer, size, offset);
+  }
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_tref_copy_data (AtomTREF * tref, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  guint i;
+
+  g_assert (atom_array_get_len (&tref->entries) > 0);
+
+  if (!atom_copy_data (&tref->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (8 + 4 * atom_array_get_len (&tref->entries), buffer, size,
+      offset);
+  prop_copy_fourcc (tref->reftype, buffer, size, offset);
+  /* minimize realloc */
+  prop_copy_ensure_buffer (buffer, size, offset,
+      4 * atom_array_get_len (&tref->entries));
+  for (i = 0; i < atom_array_get_len (&tref->entries); i++) {
+    prop_copy_uint32 (atom_array_index (&tref->entries, i), buffer, size,
+        offset);
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_edts_copy_data (AtomEDTS * edts, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&(edts->header), buffer, size, offset))
+    return 0;
+
+  if (!atom_elst_copy_data (&(edts->elst), buffer, size, offset))
+    return 0;
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_tag_data_copy_data (AtomTagData * data, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&data->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (data->reserved, buffer, size, offset);
+  prop_copy_uint8_array (data->data, data->datalen, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_tag_copy_data (AtomTag * tag, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&tag->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  if (!atom_tag_data_copy_data (&tag->data, buffer, size, offset)) {
+    return 0;
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_ilst_copy_data (AtomILST * ilst, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&ilst->header, buffer, size, offset)) {
+    return 0;
+  }
+  /* extra atoms */
+  if (ilst->entries &&
+      !atom_info_list_copy_data (ilst->entries, buffer, size, offset))
+    return 0;
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_meta_copy_data (AtomMETA * meta, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&meta->header, buffer, size, offset)) {
+    return 0;
+  }
+  if (!atom_hdlr_copy_data (&meta->hdlr, buffer, size, offset)) {
+    return 0;
+  }
+  if (meta->ilst) {
+    if (!atom_ilst_copy_data (meta->ilst, buffer, size, offset)) {
+      return 0;
+    }
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_udta_copy_data (AtomUDTA * udta, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&udta->header, buffer, size, offset)) {
+    return 0;
+  }
+  if (udta->meta) {
+    if (!atom_meta_copy_data (udta->meta, buffer, size, offset)) {
+      return 0;
+    }
+  }
+  if (udta->entries) {
+    /* extra atoms */
+    if (!atom_info_list_copy_data (udta->entries, buffer, size, offset))
+      return 0;
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_mehd_copy_data (AtomMEHD * mehd, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&mehd->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint64 (mehd->fragment_duration, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_trex_copy_data (AtomTREX * trex, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&trex->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (trex->track_ID, buffer, size, offset);
+  prop_copy_uint32 (trex->default_sample_description_index, buffer, size,
+      offset);
+  prop_copy_uint32 (trex->default_sample_duration, buffer, size, offset);
+  prop_copy_uint32 (trex->default_sample_size, buffer, size, offset);
+  prop_copy_uint32 (trex->default_sample_flags, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_mvex_copy_data (AtomMVEX * mvex, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  GList *walker;
+
+  if (!atom_copy_data (&mvex->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  if (!atom_mehd_copy_data (&mvex->mehd, buffer, size, offset)) {
+    return 0;
+  }
+
+  walker = g_list_first (mvex->trexs);
+  while (walker != NULL) {
+    if (!atom_trex_copy_data ((AtomTREX *) walker->data, buffer, size, offset)) {
+      return 0;
+    }
+    walker = g_list_next (walker);
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+guint64
+atom_trak_copy_data (AtomTRAK * trak, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&trak->header, buffer, size, offset)) {
+    return 0;
+  }
+  if (!atom_tkhd_copy_data (&trak->tkhd, buffer, size, offset)) {
+    return 0;
+  }
+  if (trak->tapt) {
+    if (!trak->tapt->copy_data_func (trak->tapt->atom, buffer, size, offset)) {
+      return 0;
+    }
+  }
+  if (trak->edts) {
+    if (!atom_edts_copy_data (trak->edts, buffer, size, offset)) {
+      return 0;
+    }
+  }
+  if (trak->tref) {
+    /* Make sure we need this atom (there is a referenced track */
+    if (atom_array_get_len (&trak->tref->entries) > 0) {
+      if (!atom_tref_copy_data (trak->tref, buffer, size, offset)) {
+        return 0;
+      }
+    }
+  }
+
+  if (!atom_mdia_copy_data (&trak->mdia, buffer, size, offset)) {
+    return 0;
+  }
+
+  if (!atom_udta_copy_data (&trak->udta, buffer, size, offset)) {
+    return 0;
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+
+guint64
+atom_moov_copy_data (AtomMOOV * atom, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  GList *walker;
+
+  if (!atom_copy_data (&(atom->header), buffer, size, offset))
+    return 0;
+
+  if (!atom_mvhd_copy_data (&(atom->mvhd), buffer, size, offset))
+    return 0;
+
+  walker = g_list_first (atom->traks);
+  while (walker != NULL) {
+    if (!atom_trak_copy_data ((AtomTRAK *) walker->data, buffer, size, offset)) {
+      return 0;
+    }
+    walker = g_list_next (walker);
+  }
+
+  if (!atom_udta_copy_data (&atom->udta, buffer, size, offset)) {
+    return 0;
+  }
+
+  if (atom->fragmented) {
+    if (!atom_mvex_copy_data (&atom->mvex, buffer, size, offset)) {
+      return 0;
+    }
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_wave_copy_data (AtomWAVE * wave, guint8 ** buffer,
+    guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_copy_data (&(wave->header), buffer, size, offset))
+    return 0;
+
+  if (wave->extension_atoms) {
+    if (!atom_info_list_copy_data (wave->extension_atoms, buffer, size, offset))
+      return 0;
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+/* -- end of copy data functions -- */
+
+/* -- general functions, API and support functions */
+
+/* add samples to tables */
+
+void
+atom_stsc_add_new_entry (AtomSTSC * stsc, guint32 first_chunk, guint32 nsamples)
+{
+  gint len;
+
+  if ((len = atom_array_get_len (&stsc->entries)) > 1 &&
+      ((atom_array_index (&stsc->entries, len - 1)).samples_per_chunk ==
+          (atom_array_index (&stsc->entries, len - 2)).samples_per_chunk)) {
+    STSCEntry *nentry;
+
+    /* Merge last two entries as they have the same number of samples per chunk */
+    nentry = &atom_array_index (&stsc->entries, len - 1);
+    nentry->first_chunk = first_chunk;
+    nentry->samples_per_chunk = nsamples;
+    nentry->sample_description_index = 1;
+  } else {
+    STSCEntry nentry;
+
+    nentry.first_chunk = first_chunk;
+    nentry.samples_per_chunk = nsamples;
+    nentry.sample_description_index = 1;
+    atom_array_append (&stsc->entries, nentry, 128);
+  }
+}
+
+static void
+atom_stsc_update_entry (AtomSTSC * stsc, guint32 first_chunk, guint32 nsamples)
+{
+  gint len;
+
+  len = atom_array_get_len (&stsc->entries);
+  g_assert (len != 0);
+  g_assert (atom_array_index (&stsc->entries,
+          len - 1).first_chunk == first_chunk);
+
+  atom_array_index (&stsc->entries, len - 1).samples_per_chunk += nsamples;
+}
+
+static void
+atom_stts_add_entry (AtomSTTS * stts, guint32 sample_count, gint32 sample_delta)
+{
+  STTSEntry *entry = NULL;
+
+  if (G_LIKELY (atom_array_get_len (&stts->entries) != 0))
+    entry = &atom_array_index (&stts->entries,
+        atom_array_get_len (&stts->entries) - 1);
+
+  if (entry && entry->sample_delta == sample_delta) {
+    entry->sample_count += sample_count;
+  } else {
+    STTSEntry nentry;
+
+    nentry.sample_count = sample_count;
+    nentry.sample_delta = sample_delta;
+    atom_array_append (&stts->entries, nentry, 256);
+  }
+}
+
+static void
+atom_stsz_add_entry (AtomSTSZ * stsz, guint32 nsamples, guint32 size)
+{
+  guint32 i;
+
+  stsz->table_size += nsamples;
+  if (stsz->sample_size != 0) {
+    /* it is constant size, we don't need entries */
+    return;
+  }
+  for (i = 0; i < nsamples; i++) {
+    atom_array_append (&stsz->entries, size, 1024);
+  }
+}
+
+static guint32
+atom_stco64_get_entry_count (AtomSTCO64 * stco64)
+{
+  return atom_array_get_len (&stco64->entries);
+}
+
+/* returns TRUE if a new entry was added */
+static gboolean
+atom_stco64_add_entry (AtomSTCO64 * stco64, guint64 entry)
+{
+  guint32 len;
+
+  /* Only add a new entry if the chunk offset changed */
+  if ((len = atom_array_get_len (&stco64->entries)) &&
+      ((atom_array_index (&stco64->entries, len - 1)) == entry))
+    return FALSE;
+
+  atom_array_append (&stco64->entries, entry, 256);
+  if (entry > G_MAXUINT32)
+    stco64->header.header.type = FOURCC_co64;
+
+  return TRUE;
+}
+
+void
+atom_tref_add_entry (AtomTREF * tref, guint32 sample)
+{
+  atom_array_append (&tref->entries, sample, 512);
+}
+
+static void
+atom_stss_add_entry (AtomSTSS * stss, guint32 sample)
+{
+  atom_array_append (&stss->entries, sample, 512);
+}
+
+static void
+atom_stbl_add_stss_entry (AtomSTBL * stbl)
+{
+  guint32 sample_index = stbl->stsz.table_size;
+
+  atom_stss_add_entry (&stbl->stss, sample_index);
+}
+
+static void
+atom_ctts_add_entry (AtomCTTS * ctts, guint32 nsamples, guint32 offset)
+{
+  CTTSEntry *entry = NULL;
+
+  if (G_LIKELY (atom_array_get_len (&ctts->entries) != 0))
+    entry = &atom_array_index (&ctts->entries,
+        atom_array_get_len (&ctts->entries) - 1);
+
+  if (entry == NULL || entry->sampleoffset != offset) {
+    CTTSEntry nentry;
+
+    nentry.samplecount = nsamples;
+    nentry.sampleoffset = offset;
+    atom_array_append (&ctts->entries, nentry, 256);
+    if (offset != 0)
+      ctts->do_pts = TRUE;
+  } else {
+    entry->samplecount += nsamples;
+  }
+}
+
+static void
+atom_stbl_add_ctts_entry (AtomSTBL * stbl, guint32 nsamples, guint32 offset)
+{
+  if (stbl->ctts == NULL) {
+    stbl->ctts = atom_ctts_new ();
+  }
+  atom_ctts_add_entry (stbl->ctts, nsamples, offset);
+}
+
+void
+atom_stbl_add_samples (AtomSTBL * stbl, guint32 nsamples, guint32 delta,
+    guint32 size, guint64 chunk_offset, gboolean sync, gint64 pts_offset)
+{
+  atom_stts_add_entry (&stbl->stts, nsamples, delta);
+  atom_stsz_add_entry (&stbl->stsz, nsamples, size);
+  if (atom_stco64_add_entry (&stbl->stco64, chunk_offset)) {
+    atom_stsc_add_new_entry (&stbl->stsc,
+        atom_stco64_get_entry_count (&stbl->stco64), nsamples);
+  } else {
+    atom_stsc_update_entry (&stbl->stsc,
+        atom_stco64_get_entry_count (&stbl->stco64), nsamples);
+  }
+
+  if (sync)
+    atom_stbl_add_stss_entry (stbl);
+  /* always store to arrange for consistent content */
+  atom_stbl_add_ctts_entry (stbl, nsamples, pts_offset);
+}
+
+void
+atom_trak_add_samples (AtomTRAK * trak, guint32 nsamples, guint32 delta,
+    guint32 size, guint64 chunk_offset, gboolean sync, gint64 pts_offset)
+{
+  AtomSTBL *stbl = &trak->mdia.minf.stbl;
+  atom_stbl_add_samples (stbl, nsamples, delta, size, chunk_offset, sync,
+      pts_offset);
+}
+
+/* trak and moov molding */
+
+guint32
+atom_trak_get_timescale (AtomTRAK * trak)
+{
+  return trak->mdia.mdhd.time_info.timescale;
+}
+
+guint32
+atom_trak_get_id (AtomTRAK * trak)
+{
+  return trak->tkhd.track_ID;
+}
+
+static void
+atom_trak_set_id (AtomTRAK * trak, guint32 id)
+{
+  trak->tkhd.track_ID = id;
+}
+
+static void
+atom_moov_add_trex (AtomMOOV * moov, AtomTREX * trex)
+{
+  moov->mvex.trexs = g_list_append (moov->mvex.trexs, trex);
+}
+
+static AtomTREX *
+atom_trex_new (AtomTRAK * trak)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+  AtomTREX *trex = g_new0 (AtomTREX, 1);
+
+  atom_full_init (&trex->header, FOURCC_trex, 0, 0, 0, flags);
+
+  trex->track_ID = trak->tkhd.track_ID;
+  trex->default_sample_description_index = 1;
+  trex->default_sample_duration = 0;
+  trex->default_sample_size = 0;
+  trex->default_sample_flags = 0;
+
+  return trex;
+}
+
+void
+atom_moov_add_trak (AtomMOOV * moov, AtomTRAK * trak)
+{
+  atom_trak_set_id (trak, moov->mvhd.next_track_id++);
+  moov->traks = g_list_append (moov->traks, trak);
+  /* additional trak means also new trex */
+  atom_moov_add_trex (moov, atom_trex_new (trak));
+}
+
+guint
+atom_moov_get_trak_count (AtomMOOV * moov)
+{
+  return g_list_length (moov->traks);
+}
+
+static guint64
+atom_trak_get_duration (AtomTRAK * trak)
+{
+  return trak->tkhd.duration;
+}
+
+static guint64
+atom_stts_get_total_duration (AtomSTTS * stts)
+{
+  guint i;
+  guint64 sum = 0;
+
+  for (i = 0; i < atom_array_get_len (&stts->entries); i++) {
+    STTSEntry *entry = &atom_array_index (&stts->entries, i);
+
+    sum += (guint64) (entry->sample_count) * entry->sample_delta;
+  }
+  return sum;
+}
+
+static void
+atom_trak_update_duration (AtomTRAK * trak, guint64 moov_timescale)
+{
+  trak->mdia.mdhd.time_info.duration =
+      atom_stts_get_total_duration (&trak->mdia.minf.stbl.stts);
+  if (trak->mdia.mdhd.time_info.timescale != 0) {
+    trak->tkhd.duration =
+        gst_util_uint64_scale (trak->mdia.mdhd.time_info.duration,
+        moov_timescale, trak->mdia.mdhd.time_info.timescale);
+  } else {
+    trak->tkhd.duration = 0;
+  }
+}
+
+static void
+timecode_atom_trak_set_duration (AtomTRAK * trak, guint64 duration,
+    guint64 timescale)
+{
+  STTSEntry *entry;
+  GList *iter;
+
+  /* Sanity checks to ensure we have a timecode */
+  g_assert (trak->mdia.minf.gmhd != NULL);
+  g_assert (atom_array_get_len (&trak->mdia.minf.stbl.stts.entries) == 1);
+
+  for (iter = trak->mdia.minf.stbl.stsd.entries; iter;
+      iter = g_list_next (iter)) {
+    SampleTableEntry *entry = iter->data;
+    if (entry->kind == TIMECODE) {
+      SampleTableEntryTMCD *tmcd = (SampleTableEntryTMCD *) entry;
+
+      duration = duration * tmcd->timescale / timescale;
+      timescale = tmcd->timescale;
+      break;
+    }
+  }
+
+  trak->tkhd.duration = duration;
+  trak->mdia.mdhd.time_info.duration = duration;
+  trak->mdia.mdhd.time_info.timescale = timescale;
+
+  entry = &atom_array_index (&trak->mdia.minf.stbl.stts.entries, 0);
+  entry->sample_delta = duration;
+}
+
+static guint32
+atom_moov_get_timescale (AtomMOOV * moov)
+{
+  return moov->mvhd.time_info.timescale;
+}
+
+void
+atom_moov_update_timescale (AtomMOOV * moov, guint32 timescale)
+{
+  moov->mvhd.time_info.timescale = timescale;
+}
+
+void
+atom_moov_update_duration (AtomMOOV * moov)
+{
+  GList *traks = moov->traks;
+  guint64 dur, duration = 0;
+
+  while (traks) {
+    AtomTRAK *trak = (AtomTRAK *) traks->data;
+
+    /* Skip timecodes for now: they have a placeholder duration */
+    if (trak->mdia.minf.gmhd == NULL) {
+      atom_trak_update_duration (trak, atom_moov_get_timescale (moov));
+      dur = atom_trak_get_duration (trak);
+      if (dur > duration)
+        duration = dur;
+    }
+    traks = g_list_next (traks);
+  }
+  /* Now update the duration of the timecodes */
+  traks = moov->traks;
+  while (traks) {
+    AtomTRAK *trak = (AtomTRAK *) traks->data;
+
+    if (trak->mdia.minf.gmhd != NULL)
+      timecode_atom_trak_set_duration (trak, duration,
+          atom_moov_get_timescale (moov));
+    traks = g_list_next (traks);
+  }
+  moov->mvhd.time_info.duration = duration;
+  moov->mvex.mehd.fragment_duration = duration;
+}
+
+void
+atom_moov_set_fragmented (AtomMOOV * moov, gboolean fragmented)
+{
+  moov->fragmented = fragmented;
+}
+
+void
+atom_stco64_chunks_set_offset (AtomSTCO64 * stco64, guint32 offset)
+{
+  stco64->chunk_offset = offset;
+}
+
+void
+atom_moov_chunks_set_offset (AtomMOOV * moov, guint32 offset)
+{
+  GList *traks = moov->traks;
+
+  if (offset == moov->chunks_offset)
+    return;                     /* Nothing to do */
+
+  while (traks) {
+    AtomTRAK *trak = (AtomTRAK *) traks->data;
+
+    atom_stco64_chunks_set_offset (&trak->mdia.minf.stbl.stco64, offset);
+    traks = g_list_next (traks);
+  }
+
+  moov->chunks_offset = offset;
+}
+
+void
+atom_trak_update_bitrates (AtomTRAK * trak, guint32 avg_bitrate,
+    guint32 max_bitrate)
+{
+  AtomESDS *esds = NULL;
+  AtomData *btrt = NULL;
+  AtomWAVE *wave = NULL;
+  AtomSTSD *stsd;
+  GList *iter;
+  GList *extensioniter = NULL;
+
+  g_return_if_fail (trak != NULL);
+
+  if (avg_bitrate == 0 && max_bitrate == 0)
+    return;
+
+  stsd = &trak->mdia.minf.stbl.stsd;
+  for (iter = stsd->entries; iter; iter = g_list_next (iter)) {
+    SampleTableEntry *entry = iter->data;
+
+    switch (entry->kind) {
+      case AUDIO:{
+        SampleTableEntryMP4A *audioentry = (SampleTableEntryMP4A *) entry;
+        extensioniter = audioentry->extension_atoms;
+        break;
+      }
+      case VIDEO:{
+        SampleTableEntryMP4V *videoentry = (SampleTableEntryMP4V *) entry;
+        extensioniter = videoentry->extension_atoms;
+        break;
+      }
+      default:
+        break;
+    }
+  }
+
+  for (; extensioniter; extensioniter = g_list_next (extensioniter)) {
+    AtomInfo *atominfo = extensioniter->data;
+    if (atominfo->atom->type == FOURCC_esds) {
+      esds = (AtomESDS *) atominfo->atom;
+    } else if (atominfo->atom->type == FOURCC_btrt) {
+      btrt = (AtomData *) atominfo->atom;
+    } else if (atominfo->atom->type == FOURCC_wave) {
+      wave = (AtomWAVE *) atominfo->atom;
+    }
+  }
+
+  /* wave might have an esds internally */
+  if (wave) {
+    for (extensioniter = wave->extension_atoms; extensioniter;
+        extensioniter = g_list_next (extensioniter)) {
+      AtomInfo *atominfo = extensioniter->data;
+      if (atominfo->atom->type == FOURCC_esds) {
+        esds = (AtomESDS *) atominfo->atom;
+        break;
+      }
+    }
+  }
+
+  if (esds) {
+    if (avg_bitrate && esds->es.dec_conf_desc.avg_bitrate == 0)
+      esds->es.dec_conf_desc.avg_bitrate = avg_bitrate;
+    if (max_bitrate && esds->es.dec_conf_desc.max_bitrate == 0)
+      esds->es.dec_conf_desc.max_bitrate = max_bitrate;
+  }
+  if (btrt) {
+    /* type(4bytes) + size(4bytes) + buffersize(4bytes) +
+     * maxbitrate(bytes) + avgbitrate(bytes) */
+    if (max_bitrate && GST_READ_UINT32_BE (btrt->data + 4) == 0)
+      GST_WRITE_UINT32_BE (btrt->data + 4, max_bitrate);
+    if (avg_bitrate && GST_READ_UINT32_BE (btrt->data + 8) == 0)
+      GST_WRITE_UINT32_BE (btrt->data + 8, avg_bitrate);
+  }
+}
+
+void
+atom_trak_tx3g_update_dimension (AtomTRAK * trak, guint32 width, guint32 height)
+{
+  AtomSTSD *stsd;
+  GList *iter;
+  SampleTableEntryTX3G *tx3g = NULL;
+
+  stsd = &trak->mdia.minf.stbl.stsd;
+  for (iter = stsd->entries; iter && tx3g == NULL; iter = g_list_next (iter)) {
+    SampleTableEntry *entry = iter->data;
+
+    switch (entry->kind) {
+      case SUBTITLE:{
+        tx3g = (SampleTableEntryTX3G *) entry;
+        break;
+      }
+      default:
+        break;
+    }
+  }
+
+  /* Currently we never set the vertical placement flag, so we don't
+   * check for it to set the dimensions differently as the spec says.
+   * Always do it for the not set case */
+  if (tx3g) {
+    tx3g->font_size = 0.05 * height;
+
+    height = 0.15 * height;
+    trak->tkhd.width = width << 16;
+    trak->tkhd.height = height << 16;
+    tx3g->default_text_box = width | (height << 16);
+  }
+}
+
+/*
+ * Meta tags functions
+ */
+static void
+atom_tag_data_alloc_data (AtomTagData * data, guint size)
+{
+  g_free (data->data);
+  data->data = g_new0 (guint8, size);
+  data->datalen = size;
+}
+
+static void
+atom_udta_append_tag (AtomUDTA * udta, AtomInfo * tag)
+{
+  GList **entries;
+
+  if (udta->meta)
+    entries = &udta->meta->ilst->entries;
+  else
+    entries = &udta->entries;
+  *entries = g_list_append (*entries, tag);
+}
+
+void
+atom_udta_add_tag (AtomUDTA * udta, guint32 fourcc, guint32 flags,
+    const guint8 * data, guint size)
+{
+  AtomTag *tag;
+  AtomTagData *tdata;
+
+  tag = atom_tag_new (fourcc, flags);
+  tdata = &tag->data;
+  atom_tag_data_alloc_data (tdata, size);
+  memmove (tdata->data, data, size);
+
+  atom_udta_append_tag (udta,
+      build_atom_info_wrapper ((Atom *) tag, atom_tag_copy_data,
+          atom_tag_free));
+}
+
+void
+atom_udta_add_str_tag (AtomUDTA * udta, guint32 fourcc, const gchar * value)
+{
+  gint len = strlen (value);
+
+  if (len > 0)
+    atom_udta_add_tag (udta, fourcc, METADATA_TEXT_FLAG, (guint8 *) value, len);
+}
+
+void
+atom_udta_add_uint_tag (AtomUDTA * udta, guint32 fourcc, guint32 flags,
+    guint32 value)
+{
+  guint8 data[8] = { 0, };
+
+  if (flags) {
+    GST_WRITE_UINT16_BE (data, value);
+    atom_udta_add_tag (udta, fourcc, flags, data, 2);
+  } else {
+    GST_WRITE_UINT32_BE (data + 2, value);
+    atom_udta_add_tag (udta, fourcc, flags, data, 8);
+  }
+}
+
+#define GST_BUFFER_NEW_READONLY(mem, size) \
+    gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, mem, size, \
+    0, size, mem, NULL)
+
+void
+atom_udta_add_blob_tag (AtomUDTA * udta, guint8 * data, guint size)
+{
+  AtomData *data_atom;
+  guint len;
+  guint32 fourcc;
+
+  if (size < 8)
+    return;
+
+  /* blob is unparsed atom;
+   * extract size and fourcc, and wrap remainder in data atom */
+  len = GST_READ_UINT32_BE (data);
+  fourcc = GST_READ_UINT32_LE (data + 4);
+  if (len > size)
+    return;
+
+  data_atom = atom_data_new_from_data (fourcc, data + 8, len - 8);
+
+  atom_udta_append_tag (udta,
+      build_atom_info_wrapper ((Atom *) data_atom, atom_data_copy_data,
+          atom_data_free));
+}
+
+void
+atom_udta_add_3gp_tag (AtomUDTA * udta, guint32 fourcc, guint8 * data,
+    guint size)
+{
+  AtomData *data_atom;
+
+  data_atom = atom_data_new (fourcc);
+
+  /* need full atom */
+  atom_data_alloc_mem (data_atom, size + 4);
+
+  /* full atom: version and flags */
+  GST_WRITE_UINT32_BE (data_atom->data, 0);
+  memcpy (data_atom->data + 4, data, size);
+
+  atom_udta_append_tag (udta,
+      build_atom_info_wrapper ((Atom *) data_atom, atom_data_copy_data,
+          atom_data_free));
+}
+
+guint16
+language_code (const char *lang)
+{
+  g_return_val_if_fail (lang != NULL, 0);
+  g_return_val_if_fail (strlen (lang) == 3, 0);
+
+  return (((lang[0] - 0x60) & 0x1F) << 10) + (((lang[1] - 0x60) & 0x1F) << 5) +
+      ((lang[2] - 0x60) & 0x1F);
+}
+
+void
+atom_udta_add_3gp_str_int_tag (AtomUDTA * udta, guint32 fourcc,
+    const gchar * value, gint16 ivalue)
+{
+  gint len = 0, size = 0;
+  guint8 *data;
+
+  if (value) {
+    len = strlen (value);
+    size = len + 3;
+  }
+
+  if (ivalue >= 0)
+    size += 2;
+
+  data = g_malloc (size + 3);
+  /* language tag and null-terminated UTF-8 string */
+  if (value) {
+    GST_WRITE_UINT16_BE (data, language_code (GST_QT_MUX_DEFAULT_TAG_LANGUAGE));
+    /* include 0 terminator */
+    memcpy (data + 2, value, len + 1);
+  }
+  /* 16-bit unsigned int if standalone, otherwise 8-bit */
+  if (ivalue >= 0) {
+    if (size == 2)
+      GST_WRITE_UINT16_BE (data + size - 2, ivalue);
+    else {
+      GST_WRITE_UINT8 (data + size - 2, ivalue & 0xFF);
+      size--;
+    }
+  }
+
+  atom_udta_add_3gp_tag (udta, fourcc, data, size);
+  g_free (data);
+}
+
+void
+atom_udta_add_3gp_str_tag (AtomUDTA * udta, guint32 fourcc, const gchar * value)
+{
+  atom_udta_add_3gp_str_int_tag (udta, fourcc, value, -1);
+}
+
+void
+atom_udta_add_3gp_uint_tag (AtomUDTA * udta, guint32 fourcc, guint16 value)
+{
+  atom_udta_add_3gp_str_int_tag (udta, fourcc, NULL, value);
+}
+
+void
+atom_udta_add_xmp_tags (AtomUDTA * udta, GstBuffer * xmpbuffer)
+{
+  AtomData *data_atom = NULL;
+
+  if (udta->context->flavor == ATOMS_TREE_FLAVOR_MOV) {
+    if (xmpbuffer) {
+      data_atom = atom_data_new_from_gst_buffer (FOURCC_XMP_, xmpbuffer);
+      udta->entries = g_list_append (udta->entries,
+          build_atom_info_wrapper ((Atom *) data_atom, atom_data_copy_data,
+              atom_data_free));
+    }
+  } else {
+    GST_DEBUG ("Not adding xmp to moov atom, it is only used in 'mov' format");
+  }
+}
+
+/*
+ * Functions for specifying media types
+ */
+
+static void
+atom_minf_set_audio (AtomMINF * minf)
+{
+  atom_minf_clear_handlers (minf);
+  minf->smhd = atom_smhd_new ();
+}
+
+static void
+atom_minf_set_video (AtomMINF * minf, AtomsContext * context)
+{
+  atom_minf_clear_handlers (minf);
+  minf->vmhd = atom_vmhd_new (context);
+}
+
+static void
+atom_minf_set_subtitle (AtomMINF * minf)
+{
+  atom_minf_clear_handlers (minf);
+}
+
+static void
+atom_hdlr_set_type (AtomHDLR * hdlr, AtomsContext * context, guint32 comp_type,
+    guint32 hdlr_type)
+{
+  if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
+    hdlr->component_type = comp_type;
+  }
+  hdlr->handler_type = hdlr_type;
+}
+
+static void
+atom_hdlr_set_name (AtomHDLR * hdlr, const char *name)
+{
+  g_free (hdlr->name);
+  hdlr->name = g_strdup (name);
+}
+
+static void
+atom_mdia_set_hdlr_type_audio (AtomMDIA * mdia, AtomsContext * context)
+{
+  atom_hdlr_set_type (&mdia->hdlr, context, FOURCC_mhlr, FOURCC_soun);
+  /* Some players (low-end hardware) check for this name, which is what
+   * QuickTime itself sets */
+  atom_hdlr_set_name (&mdia->hdlr, "SoundHandler");
+}
+
+static void
+atom_mdia_set_hdlr_type_video (AtomMDIA * mdia, AtomsContext * context)
+{
+  atom_hdlr_set_type (&mdia->hdlr, context, FOURCC_mhlr, FOURCC_vide);
+  /* Some players (low-end hardware) check for this name, which is what
+   * QuickTime itself sets */
+  atom_hdlr_set_name (&mdia->hdlr, "VideoHandler");
+}
+
+static void
+atom_mdia_set_hdlr_type_subtitle (AtomMDIA * mdia, AtomsContext * context)
+{
+  atom_hdlr_set_type (&mdia->hdlr, context, FOURCC_mhlr, FOURCC_sbtl);
+
+  /* Just follows the pattern from video and audio above */
+  atom_hdlr_set_name (&mdia->hdlr, "SubtitleHandler");
+}
+
+static void
+atom_mdia_set_audio (AtomMDIA * mdia, AtomsContext * context)
+{
+  atom_mdia_set_hdlr_type_audio (mdia, context);
+  atom_minf_set_audio (&mdia->minf);
+}
+
+static void
+atom_mdia_set_video (AtomMDIA * mdia, AtomsContext * context)
+{
+  atom_mdia_set_hdlr_type_video (mdia, context);
+  atom_minf_set_video (&mdia->minf, context);
+}
+
+static void
+atom_mdia_set_subtitle (AtomMDIA * mdia, AtomsContext * context)
+{
+  atom_mdia_set_hdlr_type_subtitle (mdia, context);
+  atom_minf_set_subtitle (&mdia->minf);
+}
+
+static void
+atom_tkhd_set_audio (AtomTKHD * tkhd)
+{
+  tkhd->volume = 0x0100;
+  tkhd->width = tkhd->height = 0;
+}
+
+static void
+atom_tkhd_set_video (AtomTKHD * tkhd, AtomsContext * context, guint32 width,
+    guint32 height)
+{
+  tkhd->volume = 0;
+
+  /* qt and ISO base media do not contradict, and examples agree */
+  tkhd->width = width;
+  tkhd->height = height;
+}
+
+static void
+atom_tkhd_set_subtitle (AtomTKHD * tkhd, AtomsContext * context, guint32 width,
+    guint32 height)
+{
+  tkhd->volume = 0;
+
+  /* qt and ISO base media do not contradict, and examples agree */
+  tkhd->width = width;
+  tkhd->height = height;
+}
+
+
+static void
+atom_edts_add_entry (AtomEDTS * edts, gint index, EditListEntry * entry)
+{
+  EditListEntry *e =
+      (EditListEntry *) g_slist_nth_data (edts->elst.entries, index);
+  /* Create a new entry if missing (appends to the list if index is larger) */
+  if (e == NULL) {
+    e = g_new (EditListEntry, 1);
+    edts->elst.entries = g_slist_insert (edts->elst.entries, e, index);
+  }
+
+  /* Update the entry */
+  *e = *entry;
+}
+
+void
+atom_trak_edts_clear (AtomTRAK * trak)
+{
+  if (trak->edts) {
+    atom_edts_free (trak->edts);
+    trak->edts = NULL;
+  }
+}
+
+/*
+ * Update an entry in this trak edits list, creating it if needed.
+ * index is the index of the entry to update, or create if it's past the end.
+ * duration is in the moov's timescale
+ * media_time is the offset in the media time to start from (media's timescale)
+ * rate is a 32 bits fixed-point
+ */
+void
+atom_trak_set_elst_entry (AtomTRAK * trak, gint index,
+    guint32 duration, guint32 media_time, guint32 rate)
+{
+  EditListEntry entry;
+
+  entry.duration = duration;
+  entry.media_time = media_time;
+  entry.media_rate = rate;
+
+  if (trak->edts == NULL)
+    trak->edts = atom_edts_new ();
+
+  atom_edts_add_entry (trak->edts, index, &entry);
+}
+
+/* re-negotiation is prevented at top-level, so only 1 entry expected.
+ * Quite some more care here and elsewhere may be needed to
+ * support several entries */
+static SampleTableEntryMP4A *
+atom_trak_add_audio_entry (AtomTRAK * trak, AtomsContext * context,
+    guint32 type)
+{
+  AtomSTSD *stsd = &trak->mdia.minf.stbl.stsd;
+  SampleTableEntryMP4A *mp4a = sample_entry_mp4a_new ();
+
+  mp4a->se.header.type = type;
+  mp4a->se.kind = AUDIO;
+  mp4a->compression_id = -1;
+  mp4a->se.data_reference_index = 1;
+
+  stsd->entries = g_list_prepend (stsd->entries, mp4a);
+  stsd->n_entries++;
+  return mp4a;
+}
+
+/* return number of centiframes per second */
+guint
+atom_framerate_to_timescale (gint n, gint d)
+{
+  if (n == 0)
+    return 10000;
+
+  if (d != 1 && d != 1001) {
+    /* otherwise there are probably rounding errors and we should rather guess
+     * if it's close enough to a well known framerate */
+    gst_video_guess_framerate (gst_util_uint64_scale (d, GST_SECOND, n), &n,
+        &d);
+  }
+
+  return gst_util_uint64_scale (n, 100, d);
+}
+
+static SampleTableEntryTMCD *
+atom_trak_add_timecode_entry (AtomTRAK * trak, AtomsContext * context,
+    guint32 trak_timescale, GstVideoTimeCode * tc)
+{
+  AtomSTSD *stsd = &trak->mdia.minf.stbl.stsd;
+  SampleTableEntryTMCD *tmcd = sample_entry_tmcd_new ();
+
+  g_assert (trak_timescale != 0);
+
+  trak->mdia.hdlr.component_type = FOURCC_mhlr;
+  trak->mdia.hdlr.handler_type = FOURCC_tmcd;
+  g_free (trak->mdia.hdlr.name);
+  trak->mdia.hdlr.name = g_strdup ("Time Code Media Handler");
+  trak->mdia.mdhd.time_info.timescale = trak_timescale;
+
+  tmcd->se.kind = TIMECODE;
+  tmcd->se.data_reference_index = 1;
+  tmcd->tc_flags = TC_24H_MAX;
+  if (tc->config.flags &= GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME)
+    tmcd->tc_flags |= TC_DROP_FRAME;
+  tmcd->name.language_code = 0;
+  tmcd->name.name = g_strdup ("Tape");
+  tmcd->timescale = trak_timescale;
+  tmcd->frame_duration =
+      gst_util_uint64_scale (tmcd->timescale, tc->config.fps_d,
+      tc->config.fps_n);
+  if (tc->config.fps_d == 1001)
+    tmcd->n_frames = tc->config.fps_n / 1000;
+  else
+    tmcd->n_frames = tc->config.fps_n / tc->config.fps_d;
+
+  stsd->entries = g_list_prepend (stsd->entries, tmcd);
+  stsd->n_entries++;
+  return tmcd;
+}
+
+static SampleTableEntryMP4V *
+atom_trak_add_video_entry (AtomTRAK * trak, AtomsContext * context,
+    guint32 type)
+{
+  SampleTableEntryMP4V *mp4v = sample_entry_mp4v_new (context);
+  AtomSTSD *stsd = &trak->mdia.minf.stbl.stsd;
+
+  mp4v->se.header.type = type;
+  mp4v->se.kind = VIDEO;
+  mp4v->se.data_reference_index = 1;
+  mp4v->horizontal_resolution = 72 << 16;
+  mp4v->vertical_resolution = 72 << 16;
+  if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
+    mp4v->spatial_quality = 512;
+    mp4v->temporal_quality = 512;
+  }
+
+  stsd->entries = g_list_prepend (stsd->entries, mp4v);
+  stsd->n_entries++;
+  return mp4v;
+}
+
+static SampleTableEntryTX3G *
+atom_trak_add_subtitle_entry (AtomTRAK * trak, AtomsContext * context,
+    guint32 type)
+{
+  SampleTableEntryTX3G *tx3g = sample_entry_tx3g_new ();
+  AtomSTSD *stsd = &trak->mdia.minf.stbl.stsd;
+
+  tx3g->se.header.type = type;
+  tx3g->se.kind = SUBTITLE;
+  tx3g->se.data_reference_index = 1;
+
+  stsd->entries = g_list_prepend (stsd->entries, tx3g);
+  stsd->n_entries++;
+  return tx3g;
+}
+
+
+void
+atom_trak_set_constant_size_samples (AtomTRAK * trak, guint32 sample_size)
+{
+  trak->mdia.minf.stbl.stsz.sample_size = sample_size;
+}
+
+static void
+atom_trak_set_audio (AtomTRAK * trak, AtomsContext * context)
+{
+  atom_tkhd_set_audio (&trak->tkhd);
+  atom_mdia_set_audio (&trak->mdia, context);
+}
+
+static void
+atom_trak_set_video (AtomTRAK * trak, AtomsContext * context, guint32 width,
+    guint32 height)
+{
+  atom_tkhd_set_video (&trak->tkhd, context, width, height);
+  atom_mdia_set_video (&trak->mdia, context);
+}
+
+static void
+atom_trak_set_subtitle (AtomTRAK * trak, AtomsContext * context)
+{
+  atom_tkhd_set_subtitle (&trak->tkhd, context, 0, 0);
+  atom_mdia_set_subtitle (&trak->mdia, context);
+}
+
+static void
+atom_trak_set_audio_commons (AtomTRAK * trak, AtomsContext * context,
+    guint32 rate)
+{
+  atom_trak_set_audio (trak, context);
+  trak->mdia.mdhd.time_info.timescale = rate;
+}
+
+static void
+atom_trak_set_video_commons (AtomTRAK * trak, AtomsContext * context,
+    guint32 rate, guint32 width, guint32 height)
+{
+  atom_trak_set_video (trak, context, width, height);
+  trak->mdia.mdhd.time_info.timescale = rate;
+  trak->tkhd.width = width << 16;
+  trak->tkhd.height = height << 16;
+}
+
+static void
+atom_trak_set_subtitle_commons (AtomTRAK * trak, AtomsContext * context)
+{
+  atom_trak_set_subtitle (trak, context);
+  trak->mdia.mdhd.time_info.timescale = 1000;
+
+  trak->tkhd.alternate_group = 2;       /* same for all subtitles */
+  trak->tkhd.layer = -1;        /* above video (layer 0) */
+}
+
+void
+sample_table_entry_add_ext_atom (SampleTableEntry * ste, AtomInfo * ext)
+{
+  GList **list = NULL;
+  if (ste->kind == AUDIO) {
+    list = &(((SampleTableEntryMP4A *) ste)->extension_atoms);
+  } else if (ste->kind == VIDEO) {
+    list = &(((SampleTableEntryMP4V *) ste)->extension_atoms);
+  } else {
+    g_assert_not_reached ();
+    return;
+  }
+
+  *list = g_list_prepend (*list, ext);
+}
+
+SampleTableEntryMP4A *
+atom_trak_set_audio_type (AtomTRAK * trak, AtomsContext * context,
+    AudioSampleEntry * entry, guint32 scale, AtomInfo * ext, gint sample_size)
+{
+  SampleTableEntryMP4A *ste;
+
+  atom_trak_set_audio_commons (trak, context, scale);
+  atom_stsd_remove_entries (&trak->mdia.minf.stbl.stsd);
+  ste = atom_trak_add_audio_entry (trak, context, entry->fourcc);
+
+  trak->is_video = FALSE;
+  trak->is_h264 = FALSE;
+
+  ste->version = entry->version;
+  ste->compression_id = entry->compression_id;
+  ste->sample_size = entry->sample_size;
+  ste->sample_rate = entry->sample_rate << 16;
+  ste->channels = entry->channels;
+
+  ste->samples_per_packet = entry->samples_per_packet;
+  ste->bytes_per_sample = entry->bytes_per_sample;
+  ste->bytes_per_packet = entry->bytes_per_packet;
+  ste->bytes_per_frame = entry->bytes_per_frame;
+
+  if (ext)
+    ste->extension_atoms = g_list_prepend (ste->extension_atoms, ext);
+
+  /* 0 size means variable size */
+  atom_trak_set_constant_size_samples (trak, sample_size);
+
+  return ste;
+}
+
+SampleTableEntryTMCD *
+atom_trak_set_timecode_type (AtomTRAK * trak, AtomsContext * context,
+    guint32 trak_timescale, GstVideoTimeCode * tc)
+{
+  SampleTableEntryTMCD *ste;
+  AtomGMHD *gmhd = trak->mdia.minf.gmhd;
+
+  if (context->flavor != ATOMS_TREE_FLAVOR_MOV) {
+    return NULL;
+  }
+
+  ste = atom_trak_add_timecode_entry (trak, context, trak_timescale, tc);
+
+  gmhd = atom_gmhd_new ();
+  gmhd->gmin.graphics_mode = 0x0040;
+  gmhd->gmin.opcolor[0] = 0x8000;
+  gmhd->gmin.opcolor[1] = 0x8000;
+  gmhd->gmin.opcolor[2] = 0x8000;
+  gmhd->tmcd.tcmi.text_size = 12;
+  gmhd->tmcd.tcmi.font_name = g_strdup ("Chicago");     /* Pascal string */
+
+  trak->mdia.minf.gmhd = gmhd;
+  trak->is_video = FALSE;
+  trak->is_h264 = FALSE;
+
+  return ste;
+}
+
+static AtomInfo *
+build_pasp_extension (gint par_width, gint par_height)
+{
+  AtomData *atom_data = atom_data_new (FOURCC_pasp);
+  guint8 *data;
+
+  atom_data_alloc_mem (atom_data, 8);
+  data = atom_data->data;
+
+  /* ihdr = image header box */
+  GST_WRITE_UINT32_BE (data, par_width);
+  GST_WRITE_UINT32_BE (data + 4, par_height);
+
+  return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
+      atom_data_free);
+}
+
+AtomInfo *
+build_fiel_extension (GstVideoInterlaceMode mode, GstVideoFieldOrder order)
+{
+  AtomData *atom_data = atom_data_new (FOURCC_fiel);
+  guint8 *data;
+  gint field_order;
+  gint interlace;
+
+  atom_data_alloc_mem (atom_data, 2);
+  data = atom_data->data;
+
+  if (mode == GST_VIDEO_INTERLACE_MODE_PROGRESSIVE) {
+    interlace = 1;
+    field_order = 0;
+  } else if (mode == GST_VIDEO_INTERLACE_MODE_INTERLEAVED) {
+    interlace = 2;
+    field_order = order == GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST ? 9 : 14;
+  } else {
+    interlace = 0;
+    field_order = 0;
+  }
+
+  GST_WRITE_UINT8 (data, interlace);
+  GST_WRITE_UINT8 (data + 1, field_order);
+
+  return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
+      atom_data_free);
+}
+
+AtomInfo *
+build_colr_extension (const GstVideoColorimetry * colorimetry, gboolean is_mp4)
+{
+  AtomData *atom_data = atom_data_new (FOURCC_colr);
+  guint8 *data;
+  guint16 primaries;
+  guint16 transfer_function;
+  guint16 matrix;
+
+  switch (colorimetry->primaries) {
+    case GST_VIDEO_COLOR_PRIMARIES_BT709:
+      primaries = 1;
+      break;
+    case GST_VIDEO_COLOR_PRIMARIES_BT470BG:
+      primaries = 5;
+      break;
+    case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M:
+    case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M:
+      primaries = 6;
+      break;
+    case GST_VIDEO_COLOR_PRIMARIES_BT2020:
+      primaries = 9;
+      break;
+    case GST_VIDEO_COLOR_PRIMARIES_UNKNOWN:
+    default:
+      primaries = 2;
+      break;
+  }
+
+  switch (colorimetry->transfer) {
+    case GST_VIDEO_TRANSFER_BT709:
+      transfer_function = 1;
+      break;
+    case GST_VIDEO_TRANSFER_SMPTE240M:
+      transfer_function = 7;
+      break;
+    case GST_VIDEO_TRANSFER_UNKNOWN:
+    default:
+      transfer_function = 2;
+      break;
+  }
+
+  switch (colorimetry->matrix) {
+    case GST_VIDEO_COLOR_MATRIX_BT709:
+      matrix = 1;
+      break;
+    case GST_VIDEO_COLOR_MATRIX_BT601:
+      matrix = 6;
+      break;
+    case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
+      matrix = 7;
+      break;
+    case GST_VIDEO_COLOR_MATRIX_BT2020:
+      matrix = 9;
+      break;
+    case GST_VIDEO_COLOR_MATRIX_UNKNOWN:
+    default:
+      matrix = 2;
+      break;
+  }
+
+  atom_data_alloc_mem (atom_data, 10 + (is_mp4 ? 1 : 0));
+  data = atom_data->data;
+
+  /* colour specification box */
+  if (is_mp4)
+    GST_WRITE_UINT32_LE (data, FOURCC_nclx);
+  else
+    GST_WRITE_UINT32_LE (data, FOURCC_nclc);
+
+  GST_WRITE_UINT16_BE (data + 4, primaries);
+  GST_WRITE_UINT16_BE (data + 6, transfer_function);
+  GST_WRITE_UINT16_BE (data + 8, matrix);
+
+  if (is_mp4) {
+    GST_WRITE_UINT8 (data + 10,
+        colorimetry->range == GST_VIDEO_COLOR_RANGE_0_255 ? 0x80 : 0x00);
+  }
+
+  return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
+      atom_data_free);
+}
+
+AtomInfo *
+build_clap_extension (gint width_n, gint width_d, gint height_n, gint height_d,
+    gint h_off_n, gint h_off_d, gint v_off_n, gint v_off_d)
+{
+  AtomData *atom_data = atom_data_new (FOURCC_clap);
+  guint8 *data;
+
+  atom_data_alloc_mem (atom_data, 32);
+  data = atom_data->data;
+
+  GST_WRITE_UINT32_BE (data, width_n);
+  GST_WRITE_UINT32_BE (data + 4, width_d);
+  GST_WRITE_UINT32_BE (data + 8, height_n);
+  GST_WRITE_UINT32_BE (data + 12, height_d);
+  GST_WRITE_UINT32_BE (data + 16, h_off_n);
+  GST_WRITE_UINT32_BE (data + 20, h_off_d);
+  GST_WRITE_UINT32_BE (data + 24, v_off_n);
+  GST_WRITE_UINT32_BE (data + 28, v_off_d);
+
+  return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
+      atom_data_free);
+}
+
+AtomInfo *
+build_tapt_extension (gint clef_width, gint clef_height, gint prof_width,
+    gint prof_height, gint enof_width, gint enof_height)
+{
+  AtomData *atom_data = atom_data_new (FOURCC_tapt);
+  guint8 *data;
+
+  atom_data_alloc_mem (atom_data, 60);
+  data = atom_data->data;
+
+  GST_WRITE_UINT32_BE (data, 20);
+  GST_WRITE_UINT32_LE (data + 4, FOURCC_clef);
+  GST_WRITE_UINT32_BE (data + 8, 0);
+  GST_WRITE_UINT32_BE (data + 12, clef_width);
+  GST_WRITE_UINT32_BE (data + 16, clef_height);
+
+  GST_WRITE_UINT32_BE (data + 20, 20);
+  GST_WRITE_UINT32_LE (data + 24, FOURCC_prof);
+  GST_WRITE_UINT32_BE (data + 28, 0);
+  GST_WRITE_UINT32_BE (data + 32, prof_width);
+  GST_WRITE_UINT32_BE (data + 36, prof_height);
+
+  GST_WRITE_UINT32_BE (data + 40, 20);
+  GST_WRITE_UINT32_LE (data + 44, FOURCC_enof);
+  GST_WRITE_UINT32_BE (data + 48, 0);
+  GST_WRITE_UINT32_BE (data + 52, enof_width);
+  GST_WRITE_UINT32_BE (data + 56, enof_height);
+
+
+  return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
+      atom_data_free);
+}
+
+static AtomInfo *
+build_mov_video_sample_description_padding_extension (void)
+{
+  AtomData *atom_data = atom_data_new (FOURCC_clap);
+
+  return build_atom_info_wrapper ((Atom *) atom_data, atom_copy_empty,
+      atom_data_free);
+}
+
+SampleTableEntryMP4V *
+atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context,
+    VisualSampleEntry * entry, guint32 scale, GList * ext_atoms_list)
+{
+  SampleTableEntryMP4V *ste;
+  guint dwidth, dheight;
+  gint par_n = 0, par_d = 0;
+
+  par_n = entry->par_n;
+  par_d = entry->par_d;
+
+  dwidth = entry->width;
+  dheight = entry->height;
+  /* ISO file spec says track header w/h indicates track's visual presentation
+   * (so this together with pixels w/h implicitly defines PAR) */
+  if (par_n && (context->flavor != ATOMS_TREE_FLAVOR_MOV)) {
+    /* Assumes square pixels display */
+    if (!gst_video_calculate_display_ratio (&dwidth, &dheight, entry->width,
+            entry->height, par_n, par_d, 1, 1)) {
+      GST_WARNING ("Could not calculate display ratio");
+    }
+  }
+
+  atom_trak_set_video_commons (trak, context, scale, dwidth, dheight);
+  atom_stsd_remove_entries (&trak->mdia.minf.stbl.stsd);
+  ste = atom_trak_add_video_entry (trak, context, entry->fourcc);
+
+  trak->is_video = TRUE;
+  trak->is_h264 = (entry->fourcc == FOURCC_avc1
+      || entry->fourcc == FOURCC_avc3);
+
+  ste->version = entry->version;
+  ste->width = entry->width;
+  ste->height = entry->height;
+  ste->depth = entry->depth;
+  ste->color_table_id = entry->color_table_id;
+  ste->frame_count = entry->frame_count;
+
+  if (ext_atoms_list)
+    ste->extension_atoms = g_list_concat (ste->extension_atoms, ext_atoms_list);
+
+  ste->extension_atoms = g_list_append (ste->extension_atoms,
+      build_pasp_extension (par_n, par_d));
+
+  if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
+    /* append 0 as a terminator "length" to work around some broken software */
+    ste->extension_atoms =
+        g_list_append (ste->extension_atoms,
+        build_mov_video_sample_description_padding_extension ());
+  }
+
+  return ste;
+}
+
+void
+subtitle_sample_entry_init (SubtitleSampleEntry * entry)
+{
+  entry->font_size = 0;
+  entry->font_face = 0;
+  entry->foreground_color_rgba = 0xFFFFFFFF;    /* all white, opaque */
+}
+
+SampleTableEntryTX3G *
+atom_trak_set_subtitle_type (AtomTRAK * trak, AtomsContext * context,
+    SubtitleSampleEntry * entry)
+{
+  SampleTableEntryTX3G *tx3g;
+
+  atom_trak_set_subtitle_commons (trak, context);
+  atom_stsd_remove_entries (&trak->mdia.minf.stbl.stsd);
+  tx3g = atom_trak_add_subtitle_entry (trak, context, entry->fourcc);
+
+  tx3g->font_face = entry->font_face;
+  tx3g->font_size = entry->font_size;
+  tx3g->foreground_color_rgba = entry->foreground_color_rgba;
+
+  trak->is_video = FALSE;
+  trak->is_h264 = FALSE;
+
+  return tx3g;
+}
+
+static void
+atom_mfhd_init (AtomMFHD * mfhd, guint32 sequence_number)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&(mfhd->header), FOURCC_mfhd, 0, 0, 0, flags);
+  mfhd->sequence_number = sequence_number;
+}
+
+static void
+atom_moof_init (AtomMOOF * moof, AtomsContext * context,
+    guint32 sequence_number)
+{
+  atom_header_set (&moof->header, FOURCC_moof, 0, 0);
+  atom_mfhd_init (&moof->mfhd, sequence_number);
+  moof->trafs = NULL;
+}
+
+AtomMOOF *
+atom_moof_new (AtomsContext * context, guint32 sequence_number)
+{
+  AtomMOOF *moof = g_new0 (AtomMOOF, 1);
+
+  atom_moof_init (moof, context, sequence_number);
+  return moof;
+}
+
+static void
+atom_trun_free (AtomTRUN * trun)
+{
+  atom_full_clear (&trun->header);
+  atom_array_clear (&trun->entries);
+  g_free (trun);
+}
+
+static void
+atom_sdtp_free (AtomSDTP * sdtp)
+{
+  atom_full_clear (&sdtp->header);
+  atom_array_clear (&sdtp->entries);
+  g_free (sdtp);
+}
+
+void
+atom_traf_free (AtomTRAF * traf)
+{
+  GList *walker;
+
+  walker = traf->truns;
+  while (walker) {
+    atom_trun_free ((AtomTRUN *) walker->data);
+    walker = g_list_next (walker);
+  }
+  g_list_free (traf->truns);
+  traf->truns = NULL;
+
+  walker = traf->sdtps;
+  while (walker) {
+    atom_sdtp_free ((AtomSDTP *) walker->data);
+    walker = g_list_next (walker);
+  }
+  g_list_free (traf->sdtps);
+  traf->sdtps = NULL;
+
+  g_free (traf);
+}
+
+void
+atom_moof_free (AtomMOOF * moof)
+{
+  GList *walker;
+
+  walker = moof->trafs;
+  while (walker) {
+    atom_traf_free ((AtomTRAF *) walker->data);
+    walker = g_list_next (walker);
+  }
+  g_list_free (moof->trafs);
+  moof->trafs = NULL;
+
+  g_free (moof);
+}
+
+static guint64
+atom_mfhd_copy_data (AtomMFHD * mfhd, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&mfhd->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (mfhd->sequence_number, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_tfhd_copy_data (AtomTFHD * tfhd, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  guint32 flags;
+
+  if (!atom_full_copy_data (&tfhd->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (tfhd->track_ID, buffer, size, offset);
+
+  flags = atom_full_get_flags_as_uint (&tfhd->header);
+
+  if (flags & TF_BASE_DATA_OFFSET)
+    prop_copy_uint64 (tfhd->base_data_offset, buffer, size, offset);
+  if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
+    prop_copy_uint32 (tfhd->sample_description_index, buffer, size, offset);
+  if (flags & TF_DEFAULT_SAMPLE_DURATION)
+    prop_copy_uint32 (tfhd->default_sample_duration, buffer, size, offset);
+  if (flags & TF_DEFAULT_SAMPLE_SIZE)
+    prop_copy_uint32 (tfhd->default_sample_size, buffer, size, offset);
+  if (flags & TF_DEFAULT_SAMPLE_FLAGS)
+    prop_copy_uint32 (tfhd->default_sample_flags, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_tfdt_copy_data (AtomTFDT * tfdt, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&tfdt->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  /* 32-bit time if version == 0 else 64-bit: */
+  if (tfdt->header.version == 0)
+    prop_copy_uint32 (tfdt->base_media_decode_time, buffer, size, offset);
+  else
+    prop_copy_uint64 (tfdt->base_media_decode_time, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_trun_copy_data (AtomTRUN * trun, guint8 ** buffer, guint64 * size,
+    guint64 * offset, guint32 * data_offset)
+{
+  guint64 original_offset = *offset;
+  guint32 flags, i;
+
+  flags = atom_full_get_flags_as_uint (&trun->header);
+
+  /* if first trun in moof, forcibly add data_offset and record
+   * where it must be written later on */
+  if (data_offset && !*data_offset) {
+    flags |= TR_DATA_OFFSET;
+  } else {
+    flags &= ~TR_DATA_OFFSET;
+  }
+
+  atom_full_set_flags_as_uint (&trun->header, flags);
+
+  if (!atom_full_copy_data (&trun->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (trun->sample_count, buffer, size, offset);
+
+  if (flags & TR_DATA_OFFSET) {
+    *data_offset = *offset;
+    prop_copy_int32 (trun->data_offset, buffer, size, offset);
+  }
+  if (flags & TR_FIRST_SAMPLE_FLAGS)
+    prop_copy_uint32 (trun->first_sample_flags, buffer, size, offset);
+
+  for (i = 0; i < atom_array_get_len (&trun->entries); i++) {
+    TRUNSampleEntry *entry = &atom_array_index (&trun->entries, i);
+
+    if (flags & TR_SAMPLE_DURATION)
+      prop_copy_uint32 (entry->sample_duration, buffer, size, offset);
+    if (flags & TR_SAMPLE_SIZE)
+      prop_copy_uint32 (entry->sample_size, buffer, size, offset);
+    if (flags & TR_SAMPLE_FLAGS)
+      prop_copy_uint32 (entry->sample_flags, buffer, size, offset);
+    if (flags & TR_COMPOSITION_TIME_OFFSETS)
+      prop_copy_uint32 (entry->sample_composition_time_offset,
+          buffer, size, offset);
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_sdtp_copy_data (AtomSDTP * sdtp, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&sdtp->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  /* all entries at once */
+  prop_copy_fixed_size_string (&atom_array_index (&sdtp->entries, 0),
+      atom_array_get_len (&sdtp->entries), buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_traf_copy_data (AtomTRAF * traf, guint8 ** buffer, guint64 * size,
+    guint64 * offset, guint32 * data_offset)
+{
+  guint64 original_offset = *offset;
+  GList *walker;
+
+  if (!atom_copy_data (&traf->header, buffer, size, offset)) {
+    return 0;
+  }
+  if (!atom_tfhd_copy_data (&traf->tfhd, buffer, size, offset)) {
+    return 0;
+  }
+  if (!atom_tfdt_copy_data (&traf->tfdt, buffer, size, offset)) {
+    return 0;
+  }
+
+  walker = g_list_first (traf->truns);
+  while (walker != NULL) {
+    if (!atom_trun_copy_data ((AtomTRUN *) walker->data, buffer, size, offset,
+            data_offset)) {
+      return 0;
+    }
+    walker = g_list_next (walker);
+  }
+
+  walker = g_list_first (traf->sdtps);
+  while (walker != NULL) {
+    if (!atom_sdtp_copy_data ((AtomSDTP *) walker->data, buffer, size, offset)) {
+      return 0;
+    }
+    walker = g_list_next (walker);
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+/* creates moof atom; metadata is written expecting actual buffer data
+ * is in mdata directly after moof, and is consecutively written per trak */
+guint64
+atom_moof_copy_data (AtomMOOF * moof, guint8 ** buffer,
+    guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  GList *walker;
+  guint32 data_offset = 0;
+
+  if (!atom_copy_data (&moof->header, buffer, size, offset))
+    return 0;
+
+  if (!atom_mfhd_copy_data (&moof->mfhd, buffer, size, offset))
+    return 0;
+
+  walker = g_list_first (moof->trafs);
+  while (walker != NULL) {
+    if (!atom_traf_copy_data ((AtomTRAF *) walker->data, buffer, size, offset,
+            &data_offset)) {
+      return 0;
+    }
+    walker = g_list_next (walker);
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+
+  if (*buffer && data_offset) {
+    /* first trun needs a data-offset relative to moof start
+     *   = moof size + mdat prefix */
+    GST_WRITE_UINT32_BE (*buffer + data_offset, *offset - original_offset + 8);
+  }
+
+  return *offset - original_offset;
+}
+
+static void
+atom_tfhd_init (AtomTFHD * tfhd, guint32 track_ID)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&tfhd->header, FOURCC_tfhd, 0, 0, 0, flags);
+  tfhd->track_ID = track_ID;
+  tfhd->base_data_offset = 0;
+  tfhd->sample_description_index = 1;
+  tfhd->default_sample_duration = 0;
+  tfhd->default_sample_size = 0;
+  tfhd->default_sample_flags = 0;
+}
+
+static void
+atom_tfdt_init (AtomTFDT * tfdt)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+  atom_full_init (&tfdt->header, FOURCC_tfdt, 0, 0, 0, flags);
+
+  tfdt->base_media_decode_time = 0;
+}
+
+static void
+atom_trun_init (AtomTRUN * trun)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&trun->header, FOURCC_trun, 0, 0, 0, flags);
+  trun->sample_count = 0;
+  trun->data_offset = 0;
+  trun->first_sample_flags = 0;
+  atom_array_init (&trun->entries, 512);
+}
+
+static AtomTRUN *
+atom_trun_new (void)
+{
+  AtomTRUN *trun = g_new0 (AtomTRUN, 1);
+
+  atom_trun_init (trun);
+  return trun;
+}
+
+static void
+atom_sdtp_init (AtomSDTP * sdtp)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&sdtp->header, FOURCC_sdtp, 0, 0, 0, flags);
+  atom_array_init (&sdtp->entries, 512);
+}
+
+static AtomSDTP *
+atom_sdtp_new (AtomsContext * context)
+{
+  AtomSDTP *sdtp = g_new0 (AtomSDTP, 1);
+
+  atom_sdtp_init (sdtp);
+  return sdtp;
+}
+
+static void
+atom_traf_add_sdtp (AtomTRAF * traf, AtomSDTP * sdtp)
+{
+  traf->sdtps = g_list_append (traf->sdtps, sdtp);
+}
+
+static void
+atom_sdtp_add_samples (AtomSDTP * sdtp, guint8 val)
+{
+  /* it does not make much/any sense according to specs,
+   * but that's how MS isml samples seem to do it */
+  atom_array_append (&sdtp->entries, val, 256);
+}
+
+static void
+atom_trun_add_samples (AtomTRUN * trun, guint32 delta, guint32 size,
+    guint32 flags, gint64 pts_offset)
+{
+  TRUNSampleEntry nentry;
+
+  if (pts_offset != 0)
+    trun->header.flags[1] |= (TR_COMPOSITION_TIME_OFFSETS >> 8);
+
+  nentry.sample_duration = delta;
+  nentry.sample_size = size;
+  nentry.sample_flags = flags;
+  nentry.sample_composition_time_offset = pts_offset;
+  atom_array_append (&trun->entries, nentry, 256);
+  trun->sample_count++;
+}
+
+static void
+atom_traf_init (AtomTRAF * traf, AtomsContext * context, guint32 track_ID)
+{
+  atom_header_set (&traf->header, FOURCC_traf, 0, 0);
+  atom_tfdt_init (&traf->tfdt);
+  atom_tfhd_init (&traf->tfhd, track_ID);
+  traf->truns = NULL;
+
+  if (context->flavor == ATOMS_TREE_FLAVOR_ISML)
+    atom_traf_add_sdtp (traf, atom_sdtp_new (context));
+}
+
+AtomTRAF *
+atom_traf_new (AtomsContext * context, guint32 track_ID)
+{
+  AtomTRAF *traf = g_new0 (AtomTRAF, 1);
+
+  atom_traf_init (traf, context, track_ID);
+  return traf;
+}
+
+void
+atom_traf_set_base_decode_time (AtomTRAF * traf, guint64 base_decode_time)
+{
+  traf->tfdt.base_media_decode_time = base_decode_time;
+  /* If we need to write a 64-bit tfdt, set the atom version */
+  if (base_decode_time > G_MAXUINT32)
+    traf->tfdt.header.version = 1;
+}
+
+static void
+atom_traf_add_trun (AtomTRAF * traf, AtomTRUN * trun)
+{
+  traf->truns = g_list_append (traf->truns, trun);
+}
+
+void
+atom_traf_add_samples (AtomTRAF * traf, guint32 delta, guint32 size,
+    gboolean sync, gint64 pts_offset, gboolean sdtp_sync)
+{
+  AtomTRUN *trun;
+  guint32 flags;
+
+  /* 0x10000 is sample-is-difference-sample flag
+   * low byte stuff is what ismv uses */
+  flags = (sync ? 0x0 : 0x10000) | (sdtp_sync ? 0x40 : 0xc0);
+
+  if (G_UNLIKELY (!traf->truns)) {
+    trun = atom_trun_new ();
+    atom_traf_add_trun (traf, trun);
+    /* optimistic; indicate all defaults present in tfhd */
+    traf->tfhd.header.flags[2] = TF_DEFAULT_SAMPLE_DURATION |
+        TF_DEFAULT_SAMPLE_SIZE | TF_DEFAULT_SAMPLE_FLAGS;
+    traf->tfhd.default_sample_duration = delta;
+    traf->tfhd.default_sample_size = size;
+    traf->tfhd.default_sample_flags = flags;
+    trun->first_sample_flags = flags;
+  }
+
+  trun = traf->truns->data;
+
+  /* check if still matching defaults,
+   * if not, abandon default and need entry for each sample */
+  if (traf->tfhd.default_sample_duration != delta) {
+    traf->tfhd.header.flags[2] &= ~TF_DEFAULT_SAMPLE_DURATION;
+    trun->header.flags[1] |= (TR_SAMPLE_DURATION >> 8);
+  }
+  if (traf->tfhd.default_sample_size != size) {
+    traf->tfhd.header.flags[2] &= ~TF_DEFAULT_SAMPLE_SIZE;
+    trun->header.flags[1] |= (TR_SAMPLE_SIZE >> 8);
+  }
+  if (traf->tfhd.default_sample_flags != flags) {
+    if (trun->sample_count == 1) {
+      /* at least will need first sample flag */
+      traf->tfhd.default_sample_flags = flags;
+      trun->header.flags[2] |= TR_FIRST_SAMPLE_FLAGS;
+    } else {
+      /* now we need sample flags for each sample */
+      traf->tfhd.header.flags[2] &= ~TF_DEFAULT_SAMPLE_FLAGS;
+      trun->header.flags[1] |= (TR_SAMPLE_FLAGS >> 8);
+      trun->header.flags[2] &= ~TR_FIRST_SAMPLE_FLAGS;
+    }
+  }
+
+  atom_trun_add_samples (traf->truns->data, delta, size, flags, pts_offset);
+
+  if (traf->sdtps)
+    atom_sdtp_add_samples (traf->sdtps->data, 0x10 | ((flags & 0xff) >> 4));
+}
+
+guint32
+atom_traf_get_sample_num (AtomTRAF * traf)
+{
+  AtomTRUN *trun;
+
+  if (G_UNLIKELY (!traf->truns))
+    return 0;
+
+  trun = traf->truns->data;
+  return atom_array_get_len (&trun->entries);
+}
+
+void
+atom_moof_add_traf (AtomMOOF * moof, AtomTRAF * traf)
+{
+  moof->trafs = g_list_append (moof->trafs, traf);
+}
+
+static void
+atom_tfra_free (AtomTFRA * tfra)
+{
+  atom_full_clear (&tfra->header);
+  atom_array_clear (&tfra->entries);
+  g_free (tfra);
+}
+
+AtomMFRA *
+atom_mfra_new (AtomsContext * context)
+{
+  AtomMFRA *mfra = g_new0 (AtomMFRA, 1);
+
+  atom_header_set (&mfra->header, FOURCC_mfra, 0, 0);
+  return mfra;
+}
+
+void
+atom_mfra_add_tfra (AtomMFRA * mfra, AtomTFRA * tfra)
+{
+  mfra->tfras = g_list_append (mfra->tfras, tfra);
+}
+
+void
+atom_mfra_free (AtomMFRA * mfra)
+{
+  GList *walker;
+
+  walker = mfra->tfras;
+  while (walker) {
+    atom_tfra_free ((AtomTFRA *) walker->data);
+    walker = g_list_next (walker);
+  }
+  g_list_free (mfra->tfras);
+  mfra->tfras = NULL;
+
+  atom_clear (&mfra->header);
+  g_free (mfra);
+}
+
+static void
+atom_tfra_init (AtomTFRA * tfra, guint32 track_ID)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&tfra->header, FOURCC_tfra, 0, 0, 0, flags);
+  tfra->track_ID = track_ID;
+  atom_array_init (&tfra->entries, 512);
+}
+
+AtomTFRA *
+atom_tfra_new (AtomsContext * context, guint32 track_ID)
+{
+  AtomTFRA *tfra = g_new0 (AtomTFRA, 1);
+
+  atom_tfra_init (tfra, track_ID);
+  return tfra;
+
+}
+
+static inline gint
+need_bytes (guint32 num)
+{
+  gint n = 0;
+
+  while (num >>= 8)
+    n++;
+
+  return n;
+}
+
+void
+atom_tfra_add_entry (AtomTFRA * tfra, guint64 dts, guint32 sample_num)
+{
+  TFRAEntry entry;
+
+  entry.time = dts;
+  /* fill in later */
+  entry.moof_offset = 0;
+  /* always write a single trun in a single traf */
+  entry.traf_number = 1;
+  entry.trun_number = 1;
+  entry.sample_number = sample_num;
+
+  /* auto-use 64 bits if needed */
+  if (dts > G_MAXUINT32)
+    tfra->header.version = 1;
+
+  /* 1 byte will always do for traf and trun number,
+   * check how much sample_num needs */
+  tfra->lengths = (tfra->lengths & 0xfc) ||
+      MAX (tfra->lengths, need_bytes (sample_num));
+
+  atom_array_append (&tfra->entries, entry, 256);
+}
+
+void
+atom_tfra_update_offset (AtomTFRA * tfra, guint64 offset)
+{
+  gint i;
+
+  /* auto-use 64 bits if needed */
+  if (offset > G_MAXUINT32)
+    tfra->header.version = 1;
+
+  for (i = atom_array_get_len (&tfra->entries) - 1; i >= 0; i--) {
+    TFRAEntry *entry = &atom_array_index (&tfra->entries, i);
+
+    if (entry->moof_offset)
+      break;
+    entry->moof_offset = offset;
+  }
+}
+
+static guint64
+atom_tfra_copy_data (AtomTFRA * tfra, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  guint32 i;
+  TFRAEntry *entry;
+  guint32 data;
+  guint bytes;
+  guint version;
+
+  if (!atom_full_copy_data (&tfra->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (tfra->track_ID, buffer, size, offset);
+  prop_copy_uint32 (tfra->lengths, buffer, size, offset);
+  prop_copy_uint32 (atom_array_get_len (&tfra->entries), buffer, size, offset);
+
+  version = tfra->header.version;
+  for (i = 0; i < atom_array_get_len (&tfra->entries); ++i) {
+    entry = &atom_array_index (&tfra->entries, i);
+    if (version) {
+      prop_copy_uint64 (entry->time, buffer, size, offset);
+      prop_copy_uint64 (entry->moof_offset, buffer, size, offset);
+    } else {
+      prop_copy_uint32 (entry->time, buffer, size, offset);
+      prop_copy_uint32 (entry->moof_offset, buffer, size, offset);
+    }
+
+    bytes = (tfra->lengths & (0x3 << 4)) + 1;
+    data = GUINT32_TO_BE (entry->traf_number);
+    prop_copy_fixed_size_string (((guint8 *) & data) + 4 - bytes, bytes,
+        buffer, size, offset);
+
+    bytes = (tfra->lengths & (0x3 << 2)) + 1;
+    data = GUINT32_TO_BE (entry->trun_number);
+    prop_copy_fixed_size_string (((guint8 *) & data) + 4 - bytes, bytes,
+        buffer, size, offset);
+
+    bytes = (tfra->lengths & (0x3)) + 1;
+    data = GUINT32_TO_BE (entry->sample_number);
+    prop_copy_fixed_size_string (((guint8 *) & data) + 4 - bytes, bytes,
+        buffer, size, offset);
+
+  }
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+static guint64
+atom_mfro_copy_data (guint32 s, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  guint8 flags[3] = { 0, 0, 0 };
+  AtomFull mfro;
+
+  atom_full_init (&mfro, FOURCC_mfro, 0, 0, 0, flags);
+
+  if (!atom_full_copy_data (&mfro, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint32 (s, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+
+  return *offset - original_offset;
+}
+
+
+guint64
+atom_mfra_copy_data (AtomMFRA * mfra, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  GList *walker;
+
+  if (!atom_copy_data (&mfra->header, buffer, size, offset))
+    return 0;
+
+  walker = g_list_first (mfra->tfras);
+  while (walker != NULL) {
+    if (!atom_tfra_copy_data ((AtomTFRA *) walker->data, buffer, size, offset)) {
+      return 0;
+    }
+    walker = g_list_next (walker);
+  }
+
+  /* 16 is the size of the mfro atom */
+  if (!atom_mfro_copy_data (*offset - original_offset + 16, buffer,
+          size, offset))
+    return 0;
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+/* some sample description construction helpers */
+
+AtomInfo *
+build_esds_extension (AtomTRAK * trak, guint8 object_type, guint8 stream_type,
+    const GstBuffer * codec_data, guint32 avg_bitrate, guint32 max_bitrate)
+{
+  guint32 track_id;
+  AtomESDS *esds;
+
+  track_id = trak->tkhd.track_ID;
+
+  esds = atom_esds_new ();
+  esds->es.id = track_id & 0xFFFF;
+  esds->es.dec_conf_desc.object_type = object_type;
+  esds->es.dec_conf_desc.stream_type = stream_type << 2 | 0x01;
+
+  if (avg_bitrate > 0)
+    esds->es.dec_conf_desc.avg_bitrate = avg_bitrate;
+  if (max_bitrate > 0)
+    esds->es.dec_conf_desc.max_bitrate = max_bitrate;
+
+  /* optional DecoderSpecificInfo */
+  if (codec_data) {
+    DecoderSpecificInfoDescriptor *desc;
+    gsize size;
+
+    esds->es.dec_conf_desc.dec_specific_info = desc =
+        desc_dec_specific_info_new ();
+    size = gst_buffer_get_size ((GstBuffer *) codec_data);
+    desc_dec_specific_info_alloc_data (desc, size);
+    gst_buffer_extract ((GstBuffer *) codec_data, 0, desc->data, size);
+  }
+
+  return build_atom_info_wrapper ((Atom *) esds, atom_esds_copy_data,
+      atom_esds_free);
+}
+
+AtomInfo *
+build_btrt_extension (guint32 buffer_size_db, guint32 avg_bitrate,
+    guint32 max_bitrate)
+{
+  AtomData *atom_data = atom_data_new (FOURCC_btrt);
+  guint8 *data;
+
+  atom_data_alloc_mem (atom_data, 12);
+  data = atom_data->data;
+
+  GST_WRITE_UINT32_BE (data, buffer_size_db);
+  GST_WRITE_UINT32_BE (data + 4, max_bitrate);
+  GST_WRITE_UINT32_BE (data + 8, avg_bitrate);
+
+  return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
+      atom_data_free);
+}
+
+static AtomInfo *
+build_mov_wave_extension (guint32 fourcc, AtomInfo * atom1, AtomInfo * atom2,
+    gboolean terminator)
+{
+  AtomWAVE *wave;
+  AtomFRMA *frma;
+  Atom *ext_atom;
+
+  /* Build WAVE atom for sample table entry */
+  wave = atom_wave_new ();
+
+  /* Prepend Terminator atom to the WAVE list first, so it ends up last */
+  if (terminator) {
+    ext_atom = (Atom *) atom_data_new (FOURCC_null);
+    wave->extension_atoms =
+        atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) ext_atom,
+        (AtomCopyDataFunc) atom_data_copy_data, (AtomFreeFunc) atom_data_free);
+  }
+
+  /* Add supplied atoms to WAVE */
+  if (atom2)
+    wave->extension_atoms = g_list_prepend (wave->extension_atoms, atom2);
+  if (atom1)
+    wave->extension_atoms = g_list_prepend (wave->extension_atoms, atom1);
+
+  /* Add FRMA to the WAVE */
+  frma = atom_frma_new ();
+  frma->media_type = fourcc;
+
+  wave->extension_atoms =
+      atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) frma,
+      (AtomCopyDataFunc) atom_frma_copy_data, (AtomFreeFunc) atom_frma_free);
+
+  return build_atom_info_wrapper ((Atom *) wave, atom_wave_copy_data,
+      atom_wave_free);
+}
+
+AtomInfo *
+build_mov_aac_extension (AtomTRAK * trak, const GstBuffer * codec_data,
+    guint32 avg_bitrate, guint32 max_bitrate)
+{
+  AtomInfo *esds, *mp4a;
+  GstBuffer *buf;
+  guint32 tmp = 0;
+
+  /* Add ESDS atom to WAVE */
+  esds = build_esds_extension (trak, ESDS_OBJECT_TYPE_MPEG4_P3,
+      ESDS_STREAM_TYPE_AUDIO, codec_data, avg_bitrate, max_bitrate);
+
+  /* Add MP4A atom to the WAVE:
+   * not really in spec, but makes offset based players happy */
+  buf = GST_BUFFER_NEW_READONLY (&tmp, 4);
+  mp4a = build_codec_data_extension (FOURCC_mp4a, buf);
+  gst_buffer_unref (buf);
+
+  return build_mov_wave_extension (FOURCC_mp4a, mp4a, esds, TRUE);
+}
+
+AtomInfo *
+build_mov_alac_extension (const GstBuffer * codec_data)
+{
+  AtomInfo *alac;
+
+  alac = build_codec_data_extension (FOURCC_alac, codec_data);
+
+  return build_mov_wave_extension (FOURCC_alac, NULL, alac, TRUE);
+}
+
+AtomInfo *
+build_jp2x_extension (const GstBuffer * prefix)
+{
+  AtomData *atom_data;
+
+  if (!prefix) {
+    return NULL;
+  }
+
+  atom_data = atom_data_new_from_gst_buffer (FOURCC_jp2x, prefix);
+
+  return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
+      atom_data_free);
+}
+
+AtomInfo *
+build_jp2h_extension (gint width, gint height, const gchar * colorspace,
+    gint ncomp, const GValue * cmap_array, const GValue * cdef_array)
+{
+  AtomData *atom_data;
+  GstBuffer *buf;
+  guint8 cenum;
+  gint i;
+  gint idhr_size = 22;
+  gint colr_size = 15;
+  gint cmap_size = 0, cdef_size = 0;
+  gint cmap_array_size = 0;
+  gint cdef_array_size = 0;
+  GstByteWriter writer;
+
+  g_return_val_if_fail (cmap_array == NULL ||
+      GST_VALUE_HOLDS_ARRAY (cmap_array), NULL);
+  g_return_val_if_fail (cdef_array == NULL ||
+      GST_VALUE_HOLDS_ARRAY (cdef_array), NULL);
+
+  if (g_str_equal (colorspace, "sRGB")) {
+    cenum = 0x10;
+    if (ncomp == 0)
+      ncomp = 3;
+  } else if (g_str_equal (colorspace, "GRAY")) {
+    cenum = 0x11;
+    if (ncomp == 0)
+      ncomp = 1;
+  } else if (g_str_equal (colorspace, "sYUV")) {
+    cenum = 0x12;
+    if (ncomp == 0)
+      ncomp = 3;
+  } else
+    return NULL;
+
+  if (cmap_array) {
+    cmap_array_size = gst_value_array_get_size (cmap_array);
+    cmap_size = 8 + cmap_array_size * 4;
+  }
+  if (cdef_array) {
+    cdef_array_size = gst_value_array_get_size (cdef_array);
+    cdef_size = 8 + 2 + cdef_array_size * 6;
+  }
+
+  gst_byte_writer_init_with_size (&writer,
+      idhr_size + colr_size + cmap_size + cdef_size, TRUE);
+
+  /* ihdr = image header box */
+  gst_byte_writer_put_uint32_be_unchecked (&writer, 22);
+  gst_byte_writer_put_uint32_le_unchecked (&writer, FOURCC_ihdr);
+  gst_byte_writer_put_uint32_be_unchecked (&writer, height);
+  gst_byte_writer_put_uint32_be_unchecked (&writer, width);
+  gst_byte_writer_put_uint16_be_unchecked (&writer, ncomp);
+  /* 8 bits per component, unsigned */
+  gst_byte_writer_put_uint8_unchecked (&writer, 0x7);
+  /* compression type; reserved */
+  gst_byte_writer_put_uint8_unchecked (&writer, 0x7);
+  /* colour space (un)known */
+  gst_byte_writer_put_uint8_unchecked (&writer, 0x0);
+  /* intellectual property right (box present) */
+  gst_byte_writer_put_uint8_unchecked (&writer, 0x0);
+
+  /* colour specification box */
+  gst_byte_writer_put_uint32_be_unchecked (&writer, 15);
+  gst_byte_writer_put_uint32_le_unchecked (&writer, FOURCC_colr);
+
+  /* specification method: enumerated */
+  gst_byte_writer_put_uint8_unchecked (&writer, 0x1);
+  /* precedence; reserved */
+  gst_byte_writer_put_uint8_unchecked (&writer, 0x0);
+  /* approximation; reserved */
+  gst_byte_writer_put_uint8_unchecked (&writer, 0x0);
+  /* enumerated colourspace */
+  gst_byte_writer_put_uint32_be_unchecked (&writer, cenum);
+
+  if (cmap_array) {
+    gst_byte_writer_put_uint32_be_unchecked (&writer, cmap_size);
+    gst_byte_writer_put_uint32_le_unchecked (&writer, FOURCC_cmap);
+    for (i = 0; i < cmap_array_size; i++) {
+      const GValue *item;
+      gint value;
+      guint16 cmp;
+      guint8 mtyp;
+      guint8 pcol;
+      item = gst_value_array_get_value (cmap_array, i);
+      value = g_value_get_int (item);
+
+      /* value is '(mtyp << 24) | (pcol << 16) | cmp' */
+      cmp = value & 0xFFFF;
+      mtyp = value >> 24;
+      pcol = (value >> 16) & 0xFF;
+
+      if (mtyp == 1)
+        GST_WARNING ("MTYP of cmap atom signals Pallete Mapping, but we don't "
+            "handle Pallete mapping atoms yet");
+
+      gst_byte_writer_put_uint16_be_unchecked (&writer, cmp);
+      gst_byte_writer_put_uint8_unchecked (&writer, mtyp);
+      gst_byte_writer_put_uint8_unchecked (&writer, pcol);
+    }
+  }
+
+  if (cdef_array) {
+    gst_byte_writer_put_uint32_be_unchecked (&writer, cdef_size);
+    gst_byte_writer_put_uint32_le_unchecked (&writer, FOURCC_cdef);
+    gst_byte_writer_put_uint16_be_unchecked (&writer, cdef_array_size);
+    for (i = 0; i < cdef_array_size; i++) {
+      const GValue *item;
+      gint value;
+      item = gst_value_array_get_value (cdef_array, i);
+      value = g_value_get_int (item);
+
+      gst_byte_writer_put_uint16_be_unchecked (&writer, i);
+      if (value > 0) {
+        gst_byte_writer_put_uint16_be_unchecked (&writer, 0);
+        gst_byte_writer_put_uint16_be_unchecked (&writer, value);
+      } else if (value < 0) {
+        gst_byte_writer_put_uint16_be_unchecked (&writer, -value);
+        gst_byte_writer_put_uint16_be_unchecked (&writer, 0);   /* TODO what here? */
+      } else {
+        gst_byte_writer_put_uint16_be_unchecked (&writer, 1);
+        gst_byte_writer_put_uint16_be_unchecked (&writer, 0);
+      }
+    }
+  }
+
+  g_assert (gst_byte_writer_get_remaining (&writer) == 0);
+  buf = gst_byte_writer_reset_and_get_buffer (&writer);
+
+  atom_data = atom_data_new_from_gst_buffer (FOURCC_jp2h, buf);
+  gst_buffer_unref (buf);
+
+  return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
+      atom_data_free);
+}
+
+AtomInfo *
+build_codec_data_extension (guint32 fourcc, const GstBuffer * codec_data)
+{
+  AtomData *data;
+  AtomInfo *result = NULL;
+
+  if (codec_data) {
+    data = atom_data_new_from_gst_buffer (fourcc, codec_data);
+    result = build_atom_info_wrapper ((Atom *) data, atom_data_copy_data,
+        atom_data_free);
+  }
+
+  return result;
+}
+
+AtomInfo *
+build_amr_extension (void)
+{
+  guint8 ext[9];
+  GstBuffer *buf;
+  AtomInfo *res;
+
+  /* vendor */
+  GST_WRITE_UINT32_LE (ext, 0);
+  /* decoder version */
+  GST_WRITE_UINT8 (ext + 4, 0);
+  /* mode set (all modes) */
+  GST_WRITE_UINT16_BE (ext + 5, 0x81FF);
+  /* mode change period (no restriction) */
+  GST_WRITE_UINT8 (ext + 7, 0);
+  /* frames per sample */
+  GST_WRITE_UINT8 (ext + 8, 1);
+
+  buf = GST_BUFFER_NEW_READONLY (ext, sizeof (ext));
+  res = build_codec_data_extension (FOURCC_damr, buf);
+  gst_buffer_unref (buf);
+  return res;
+}
+
+AtomInfo *
+build_h263_extension (void)
+{
+  guint8 ext[7];
+  GstBuffer *buf;
+  AtomInfo *res;
+
+  /* vendor */
+  GST_WRITE_UINT32_LE (ext, 0);
+  /* decoder version */
+  GST_WRITE_UINT8 (ext + 4, 0);
+  /* level / profile */
+  /* FIXME ? maybe ? obtain somewhere; baseline for now */
+  GST_WRITE_UINT8 (ext + 5, 10);
+  GST_WRITE_UINT8 (ext + 6, 0);
+
+  buf = GST_BUFFER_NEW_READONLY (ext, sizeof (ext));
+  res = build_codec_data_extension (FOURCC_d263, buf);
+  gst_buffer_unref (buf);
+  return res;
+}
+
+AtomInfo *
+build_gama_atom (gdouble gamma)
+{
+  AtomInfo *res;
+  guint32 gamma_fp;
+  GstBuffer *buf;
+
+  /* convert to uint32 from fixed point */
+  gamma_fp = (guint32) 65536 *gamma;
+
+  gamma_fp = GUINT32_TO_BE (gamma_fp);
+  buf = GST_BUFFER_NEW_READONLY (&gamma_fp, 4);
+  res = build_codec_data_extension (FOURCC_gama, buf);
+  gst_buffer_unref (buf);
+  return res;
+}
+
+AtomInfo *
+build_SMI_atom (const GstBuffer * seqh)
+{
+  AtomInfo *res;
+  GstBuffer *buf;
+  gsize size;
+  guint8 *data;
+
+  /* the seqh plus its size and fourcc */
+  size = gst_buffer_get_size ((GstBuffer *) seqh);
+  data = g_malloc (size + 8);
+
+  GST_WRITE_UINT32_LE (data, FOURCC_SEQH);
+  GST_WRITE_UINT32_BE (data + 4, size + 8);
+  gst_buffer_extract ((GstBuffer *) seqh, 0, data + 8, size);
+  buf = gst_buffer_new_wrapped (data, size + 8);
+  res = build_codec_data_extension (FOURCC_SMI_, buf);
+  gst_buffer_unref (buf);
+  return res;
+}
+
+static AtomInfo *
+build_ima_adpcm_atom (gint channels, gint rate, gint blocksize)
+{
+#define IMA_ADPCM_ATOM_SIZE 20
+  AtomData *atom_data;
+  guint8 *data;
+  guint32 fourcc;
+  gint samplesperblock;
+  gint bytespersec;
+
+  /* The FOURCC for WAV codecs in QT is 'ms' followed by the 16 bit wave codec
+     identifier. Note that the identifier here is big-endian, but when used
+     within the WAVE header (below), it's little endian. */
+  fourcc = MS_WAVE_FOURCC (0x11);
+
+  atom_data = atom_data_new (fourcc);
+  atom_data_alloc_mem (atom_data, IMA_ADPCM_ATOM_SIZE);
+  data = atom_data->data;
+
+  /* This atom's content is a WAVE header, including 2 bytes of extra data.
+     Note that all of this is little-endian, unlike most stuff in qt. */
+  /* 4 bytes header per channel (including 1 sample). Then 2 samples per byte
+     for the rest. Simplifies to this. */
+  samplesperblock = 2 * blocksize / channels - 7;
+  bytespersec = rate * blocksize / samplesperblock;
+  GST_WRITE_UINT16_LE (data, 0x11);
+  GST_WRITE_UINT16_LE (data + 2, channels);
+  GST_WRITE_UINT32_LE (data + 4, rate);
+  GST_WRITE_UINT32_LE (data + 8, bytespersec);
+  GST_WRITE_UINT16_LE (data + 12, blocksize);
+  GST_WRITE_UINT16_LE (data + 14, 4);
+  GST_WRITE_UINT16_LE (data + 16, 2);   /* Two extra bytes */
+  GST_WRITE_UINT16_LE (data + 18, samplesperblock);
+
+  return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
+      atom_data_free);
+}
+
+AtomInfo *
+build_ima_adpcm_extension (gint channels, gint rate, gint blocksize)
+{
+  AtomWAVE *wave;
+  AtomFRMA *frma;
+  Atom *ext_atom;
+
+  /* Add WAVE atom */
+  wave = atom_wave_new ();
+
+  /* Prepend Terminator atom to the WAVE list first, so it ends up last */
+  ext_atom = (Atom *) atom_data_new (FOURCC_null);
+  wave->extension_atoms =
+      atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) ext_atom,
+      (AtomCopyDataFunc) atom_data_copy_data, (AtomFreeFunc) atom_data_free);
+
+  /* Add wave ima adpcm atom to WAVE */
+  wave->extension_atoms = g_list_prepend (wave->extension_atoms,
+      build_ima_adpcm_atom (channels, rate, blocksize));
+
+  /* Add FRMA to the WAVE */
+  frma = atom_frma_new ();
+  frma->media_type = MS_WAVE_FOURCC (0x11);
+
+  wave->extension_atoms =
+      atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) frma,
+      (AtomCopyDataFunc) atom_frma_copy_data, (AtomFreeFunc) atom_frma_free);
+
+  return build_atom_info_wrapper ((Atom *) wave, atom_wave_copy_data,
+      atom_wave_free);
+}
+
+AtomInfo *
+build_ac3_extension (guint8 fscod, guint8 bsid, guint8 bsmod, guint8 acmod,
+    guint8 lfe_on, guint8 bitrate_code)
+{
+  AtomData *atom_data = atom_data_new (FOURCC_dac3);
+  guint8 *data;
+
+  atom_data_alloc_mem (atom_data, 3);
+  data = atom_data->data;
+
+  /* Bits from the spec
+   * fscod 2
+   * bsid  5
+   * bsmod 3
+   * acmod 3
+   * lfeon 1
+   * bit_rate_code 5
+   * reserved 5
+   */
+
+  /* Some bit manipulation magic. Need bitwriter */
+  data[0] = (fscod << 6) | (bsid << 1) | ((bsmod >> 2) & 1);
+  data[1] =
+      ((bsmod & 0x3) << 6) | (acmod << 3) | ((lfe_on & 1) << 2) | ((bitrate_code
+          >> 3) & 0x3);
+  data[2] = ((bitrate_code & 0x7) << 5);
+
+  return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
+      atom_data_free);
+}
+
+AtomInfo *
+build_opus_extension (guint32 rate, guint8 channels, guint8 mapping_family,
+    guint8 stream_count, guint8 coupled_count, guint8 channel_mapping[256],
+    guint16 pre_skip, guint16 output_gain)
+{
+  AtomData *atom_data;
+  guint8 *data_block;
+  GstByteWriter bw;
+  gboolean hdl = TRUE;
+  guint data_block_len;
+
+  gst_byte_writer_init (&bw);
+  hdl &= gst_byte_writer_put_uint8 (&bw, 0x00); /* version number */
+  hdl &= gst_byte_writer_put_uint8 (&bw, channels);
+  hdl &= gst_byte_writer_put_uint16_le (&bw, pre_skip);
+  hdl &= gst_byte_writer_put_uint32_le (&bw, rate);
+  hdl &= gst_byte_writer_put_uint16_le (&bw, output_gain);
+  hdl &= gst_byte_writer_put_uint8 (&bw, mapping_family);
+  if (mapping_family > 0) {
+    hdl &= gst_byte_writer_put_uint8 (&bw, stream_count);
+    hdl &= gst_byte_writer_put_uint8 (&bw, coupled_count);
+    hdl &= gst_byte_writer_put_data (&bw, channel_mapping, channels);
+  }
+
+  if (!hdl) {
+    GST_WARNING ("Error creating header");
+    return NULL;
+  }
+
+  data_block_len = gst_byte_writer_get_size (&bw);
+  data_block = gst_byte_writer_reset_and_get_data (&bw);
+  atom_data = atom_data_new_from_data (FOURCC_dops, data_block, data_block_len);
+  g_free (data_block);
+
+  return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
+      atom_data_free);
+}
+
+AtomInfo *
+build_uuid_xmp_atom (GstBuffer * xmp_data)
+{
+  AtomUUID *uuid;
+  gsize size;
+  static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
+    0x97, 0xA9, 0x42, 0xE8,
+    0x9C, 0x71, 0x99, 0x94,
+    0x91, 0xE3, 0xAF, 0xAC
+  };
+
+  if (xmp_data == NULL)
+    return NULL;
+
+  uuid = atom_uuid_new ();
+  memcpy (uuid->uuid, xmp_uuid, 16);
+
+  size = gst_buffer_get_size (xmp_data);
+  uuid->data = g_malloc (size);
+  uuid->datalen = size;
+  gst_buffer_extract (xmp_data, 0, uuid->data, size);
+
+  return build_atom_info_wrapper ((Atom *) uuid, atom_uuid_copy_data,
+      atom_uuid_free);
+}
diff --git a/gst/isomp4/atoms.h b/gst/isomp4/atoms.h
new file mode 100644
index 0000000..27d2494
--- /dev/null
+++ b/gst/isomp4/atoms.h
@@ -0,0 +1,1128 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008-2010 Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __ATOMS_H__
+#define __ATOMS_H__
+
+#include <glib.h>
+#include <string.h>
+#include <gst/video/video.h>
+
+#include "descriptors.h"
+#include "properties.h"
+#include "fourcc.h"
+
+/* helper storage struct */
+#define ATOM_ARRAY(struct_type) \
+struct { \
+  guint size; \
+  guint len; \
+  struct_type *data; \
+}
+
+/* storage helpers */
+
+#define atom_array_init(array, reserve)                                       \
+G_STMT_START {                                                                \
+  (array)->len = 0;                                                           \
+  (array)->size = reserve;                                                    \
+  (array)->data = g_malloc (sizeof (*(array)->data) * reserve);               \
+} G_STMT_END
+
+#define atom_array_append(array, elmt, inc)                                   \
+G_STMT_START {                                                                \
+  g_assert ((array)->data);                                                   \
+  g_assert (inc > 0);                                                         \
+  if (G_UNLIKELY ((array)->len == (array)->size)) {                           \
+    (array)->size += inc;                                                     \
+    (array)->data =                                                           \
+        g_realloc ((array)->data, sizeof (*((array)->data)) * (array)->size); \
+  }                                                                           \
+  (array)->data[(array)->len] = elmt;                                         \
+  (array)->len++;                                                             \
+} G_STMT_END
+
+#define atom_array_get_len(array)                  ((array)->len)
+#define atom_array_index(array, index)             ((array)->data[index])
+
+#define atom_array_clear(array)                                               \
+G_STMT_START {                                                                \
+  (array)->size = (array)->len = 0;                                           \
+  g_free ((array)->data);                                                     \
+  (array)->data = NULL;                                                       \
+} G_STMT_END
+
+/* light-weight context that may influence header atom tree construction */
+typedef enum _AtomsTreeFlavor
+{
+  ATOMS_TREE_FLAVOR_MOV,
+  ATOMS_TREE_FLAVOR_ISOM,
+  ATOMS_TREE_FLAVOR_3GP,
+  ATOMS_TREE_FLAVOR_ISML
+} AtomsTreeFlavor;
+
+typedef struct _AtomsContext
+{
+  AtomsTreeFlavor flavor;
+} AtomsContext;
+
+AtomsContext* atoms_context_new  (AtomsTreeFlavor flavor);
+void          atoms_context_free (AtomsContext *context);
+
+#define METADATA_DATA_FLAG 0x0
+#define METADATA_TEXT_FLAG 0x1
+
+/* atom defs and functions */
+
+typedef struct _AtomInfo AtomInfo;
+
+/*
+ * Used for storing time related values for some atoms.
+ */
+typedef struct _TimeInfo
+{
+  guint64 creation_time;
+  guint64 modification_time;
+  guint32 timescale;
+  guint64 duration;
+} TimeInfo;
+
+typedef struct _Atom
+{
+  guint32 size;
+  guint32 type;
+  guint64 extended_size;
+} Atom;
+
+typedef struct _AtomFull
+{
+  Atom header;
+
+  guint8 version;
+  guint8 flags[3];
+} AtomFull;
+
+/*
+ * Generic extension atom
+ */
+typedef struct _AtomData
+{
+  Atom header;
+
+  /* not written */
+  guint32 datalen;
+
+  guint8 *data;
+} AtomData;
+
+typedef struct _AtomUUID
+{
+  Atom header;
+
+  guint8 uuid[16];
+
+  /* not written */
+  guint32 datalen;
+
+  guint8 *data;
+} AtomUUID;
+
+typedef struct _AtomFTYP
+{
+  Atom header;
+  guint32 major_brand;
+  guint32 version;
+  guint32 *compatible_brands;
+
+  /* not written */
+  guint32 compatible_brands_size;
+} AtomFTYP;
+
+typedef struct _AtomMVHD
+{
+  AtomFull header;
+
+  /* version 0: 32 bits */
+  TimeInfo time_info;
+
+  guint32 prefered_rate;      /* ISO: 0x00010000 */
+  guint16 volume;             /* ISO: 0x0100 */
+  guint16 reserved3;          /* ISO: 0x0 */
+  guint32 reserved4[2];       /* ISO: 0, 0 */
+  /* ISO: identity matrix =
+   * { 0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000 } */
+  guint32 matrix[9];
+
+  /* ISO: all 0 */
+  guint32 preview_time;
+  guint32 preview_duration;
+  guint32 poster_time;
+  guint32 selection_time;
+  guint32 selection_duration;
+  guint32 current_time;
+
+  guint32 next_track_id;
+} AtomMVHD;
+
+typedef struct _AtomTKHD
+{
+  AtomFull header;
+
+  /* version 0: 32 bits */
+  /* like the TimeInfo struct, but it has this track_ID inside */
+  guint64 creation_time;
+  guint64 modification_time;
+  guint32 track_ID;
+  guint32 reserved;
+  guint64 duration;
+
+  guint32 reserved2[2];
+  guint16 layer;
+  guint16 alternate_group;
+  guint16 volume;
+  guint16 reserved3;
+
+  /* ISO: identity matrix =
+   * { 0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000 } */
+  guint32 matrix[9];
+  guint32 width;
+  guint32 height;
+} AtomTKHD;
+
+typedef struct _AtomMDHD
+{
+  AtomFull header;
+
+  /* version 0: 32 bits */
+  TimeInfo time_info;
+
+  /* ISO: packed ISO-639-2/T language code (first bit must be 0) */
+  guint16 language_code;
+  /* ISO: 0 */
+  guint16 quality;
+} AtomMDHD;
+
+typedef struct _AtomHDLR
+{
+  AtomFull header;
+
+  /* ISO: 0 */
+  guint32 component_type;
+  guint32 handler_type;
+  guint32 manufacturer;
+  guint32 flags;
+  guint32 flags_mask;
+  gchar *name;
+
+  AtomsTreeFlavor flavor;
+} AtomHDLR;
+
+typedef struct _AtomVMHD
+{
+  AtomFull header;          /* ISO: flags = 1 */
+
+  guint16 graphics_mode;
+  /* RGB */
+  guint16 opcolor[3];
+} AtomVMHD;
+
+typedef struct _AtomSMHD
+{
+  AtomFull header;
+
+  guint16 balance;
+  guint16 reserved;
+} AtomSMHD;
+
+typedef struct _AtomHMHD
+{
+  AtomFull header;
+
+  guint16 max_pdu_size;
+  guint16 avg_pdu_size;
+  guint32 max_bitrate;
+  guint32 avg_bitrate;
+  guint32 sliding_avg_bitrate;
+} AtomHMHD;
+
+typedef struct _AtomTCMI
+{
+  AtomFull header;
+
+  guint16 text_font;
+  guint16 text_face;
+  guint16 text_size;
+  guint16 text_color[3];
+  guint16 bg_color[3];
+  gchar *font_name;
+} AtomTCMI;
+
+typedef struct _AtomTMCD
+{
+  Atom header;
+
+  AtomTCMI tcmi;
+} AtomTMCD;
+
+typedef struct _AtomGMIN
+{
+  AtomFull header;
+
+  guint16 graphics_mode;
+  guint16 opcolor[3];
+  guint8 balance;
+  guint8 reserved;
+
+} AtomGMIN;
+
+typedef struct _AtomGMHD
+{
+  Atom header;
+
+  AtomGMIN gmin;
+  AtomTMCD tmcd;
+
+} AtomGMHD;
+
+typedef struct _AtomURL
+{
+  AtomFull header;
+
+  gchar *location;
+} AtomURL;
+
+typedef struct _AtomDREF
+{
+  AtomFull header;
+
+  GList *entries;
+} AtomDREF;
+
+typedef struct _AtomDINF
+{
+  Atom header;
+
+  AtomDREF dref;
+} AtomDINF;
+
+typedef struct _STTSEntry
+{
+  guint32 sample_count;
+  gint32 sample_delta;
+} STTSEntry;
+
+typedef struct _AtomSTTS
+{
+  AtomFull header;
+
+  ATOM_ARRAY (STTSEntry) entries;
+} AtomSTTS;
+
+typedef struct _AtomSTSS
+{
+  AtomFull header;
+
+  ATOM_ARRAY (guint32) entries;
+} AtomSTSS;
+
+typedef struct _AtomESDS
+{
+  AtomFull header;
+
+  ESDescriptor es;
+} AtomESDS;
+
+typedef struct _AtomFRMA
+{
+  Atom header;
+
+  guint32 media_type;
+} AtomFRMA;
+
+typedef enum _SampleEntryKind
+{
+  UNKNOWN,
+  AUDIO,
+  VIDEO,
+  SUBTITLE,
+  TIMECODE
+} SampleEntryKind;
+
+typedef struct _SampleTableEntry
+{
+  Atom header;
+
+  guint8 reserved[6];
+  guint16 data_reference_index;
+
+  /* type of entry */
+  SampleEntryKind kind;
+} SampleTableEntry;
+
+typedef struct _AtomHintSampleEntry
+{
+  SampleTableEntry se;
+  guint32 size;
+  guint8 *data;
+} AtomHintSampleEntry;
+
+typedef struct _SampleTableEntryMP4V
+{
+  SampleTableEntry se;
+
+  guint16 version;
+  guint16 revision_level;
+
+  guint32 vendor;                 /* fourcc code */
+  guint32 temporal_quality;
+  guint32 spatial_quality;
+
+  guint16 width;
+  guint16 height;
+
+  guint32 horizontal_resolution;
+  guint32 vertical_resolution;
+  guint32 datasize;
+
+  guint16 frame_count;            /* usually 1 */
+
+  guint8 compressor[32];         /* pascal string, i.e. first byte = length */
+
+  guint16 depth;
+  guint16 color_table_id;
+
+  /* (optional) list of AtomInfo */
+  GList *extension_atoms;
+} SampleTableEntryMP4V;
+
+typedef struct _SampleTableEntryMP4A
+{
+  SampleTableEntry se;
+
+  guint16 version;
+  guint16 revision_level;
+  guint32 vendor;
+
+  guint16 channels;
+  guint16 sample_size;
+  guint16 compression_id;
+  guint16 packet_size;
+
+  guint32 sample_rate;            /* fixed point 16.16 */
+
+  guint32 samples_per_packet;
+  guint32 bytes_per_packet;
+  guint32 bytes_per_frame;
+  guint32 bytes_per_sample;
+
+  /* (optional) list of AtomInfo */
+  GList *extension_atoms;
+} SampleTableEntryMP4A;
+
+typedef struct _AtomNAME
+{
+  Atom header;
+
+  guint8 language_code;
+  gchar *name;
+} AtomNAME;
+
+typedef struct _SampleTableEntryTMCD
+{
+  SampleTableEntry se;
+
+  guint32 tc_flags;
+  guint32 timescale;
+  guint32 frame_duration;
+  guint8 n_frames;
+
+  AtomNAME name;
+
+} SampleTableEntryTMCD;
+
+typedef struct _SampleTableEntryTX3G
+{
+  SampleTableEntry se;
+
+  guint32 display_flags;
+  guint64 default_text_box;
+  guint16 font_id;
+  guint8  font_face; /* bold=0x1, italic=0x2, underline=0x4 */
+  guint8  font_size; /* should always be 0.05 multiplied by the video track header height */
+  guint32 foreground_color_rgba;
+
+} SampleTableEntryTX3G;
+
+typedef struct _AtomSTSD
+{
+  AtomFull header;
+
+  guint n_entries;
+  /* list of subclasses of SampleTableEntry */
+  GList *entries;
+} AtomSTSD;
+
+typedef struct _AtomSTSZ
+{
+  AtomFull header;
+
+  guint32 sample_size;
+
+  /* need the size here because when sample_size is constant,
+   * the list is empty */
+  guint32 table_size;
+  ATOM_ARRAY (guint32) entries;
+} AtomSTSZ;
+
+typedef struct _STSCEntry
+{
+  guint32 first_chunk;
+  guint32 samples_per_chunk;
+  guint32 sample_description_index;
+} STSCEntry;
+
+typedef struct _AtomSTSC
+{
+  AtomFull header;
+
+  ATOM_ARRAY (STSCEntry) entries;
+} AtomSTSC;
+
+/* FIXME: this can support multiple tracks */
+typedef struct _AtomTREF
+{
+  Atom header;
+
+  guint32 reftype;
+  ATOM_ARRAY (guint32) entries;
+} AtomTREF;
+
+/*
+ * used for both STCO and CO64
+ * if used as STCO, entries should be truncated to use only 32bits
+ */
+typedef struct _AtomSTCO64
+{
+  AtomFull header;
+  /* Global offset to add to entries when serialising */
+  guint32 chunk_offset;
+  ATOM_ARRAY (guint64) entries;
+} AtomSTCO64;
+
+typedef struct _CTTSEntry
+{
+  guint32 samplecount;
+  guint32 sampleoffset;
+} CTTSEntry;
+
+typedef struct _AtomCTTS
+{
+  AtomFull header;
+
+  /* also entry count here */
+  ATOM_ARRAY (CTTSEntry) entries;
+  gboolean do_pts;
+} AtomCTTS;
+
+typedef struct _AtomSVMI
+{
+  AtomFull header;
+
+  guint8 stereoscopic_composition_type;
+  gboolean is_left_first;
+} AtomSVMI;
+
+typedef struct _AtomSTBL
+{
+  Atom header;
+
+  AtomSTSD stsd;
+  AtomSTTS stts;
+  AtomSTSS stss;
+  AtomSTSC stsc;
+  AtomSTSZ stsz;
+  /* NULL if not present */
+  AtomCTTS *ctts;
+  /* NULL if not present */
+  AtomSVMI *svmi;
+
+  AtomSTCO64 stco64;
+} AtomSTBL;
+
+typedef struct _AtomMINF
+{
+  Atom header;
+
+  /* only (exactly) one of those must be present */
+  AtomVMHD *vmhd;
+  AtomSMHD *smhd;
+  AtomHMHD *hmhd;
+  AtomGMHD *gmhd;
+
+  AtomHDLR *hdlr;
+  AtomDINF dinf;
+  AtomSTBL stbl;
+} AtomMINF;
+
+typedef struct _EditListEntry
+{
+  /* duration in movie's timescale */
+  guint32 duration;
+  /* start time in media's timescale, -1 for empty */
+  guint32 media_time;
+  guint32 media_rate;  /* fixed point 32 bit */
+} EditListEntry;
+
+typedef struct _AtomELST
+{
+  AtomFull header;
+
+  /* number of entries is implicit */
+  GSList *entries;
+} AtomELST;
+
+typedef struct _AtomEDTS
+{
+  Atom header;
+  AtomELST elst;
+} AtomEDTS;
+
+typedef struct _AtomMDIA
+{
+  Atom header;
+
+  AtomMDHD mdhd;
+  AtomHDLR hdlr;
+  AtomMINF minf;
+} AtomMDIA;
+
+typedef struct _AtomILST
+{
+  Atom header;
+
+  /* list of AtomInfo */
+  GList* entries;
+} AtomILST;
+
+typedef struct _AtomTagData
+{
+  AtomFull header;
+  guint32 reserved;
+
+  guint32 datalen;
+  guint8* data;
+} AtomTagData;
+
+typedef struct _AtomTag
+{
+  Atom header;
+
+  AtomTagData data;
+} AtomTag;
+
+typedef struct _AtomMETA
+{
+  AtomFull header;
+  AtomHDLR hdlr;
+  AtomILST *ilst;
+} AtomMETA;
+
+typedef struct _AtomUDTA
+{
+  Atom header;
+
+  /* list of AtomInfo */
+  GList* entries;
+  /* or list is further down */
+  AtomMETA *meta;
+
+  AtomsContext *context;
+} AtomUDTA;
+
+enum TrFlags
+{
+  TR_DATA_OFFSET              = 0x01,     /* data-offset-present */
+  TR_FIRST_SAMPLE_FLAGS       = 0x04,     /* first-sample-flags-present */
+  TR_SAMPLE_DURATION          = 0x0100,   /* sample-duration-present */
+  TR_SAMPLE_SIZE              = 0x0200,   /* sample-size-present */
+  TR_SAMPLE_FLAGS             = 0x0400,   /* sample-flags-present */
+  TR_COMPOSITION_TIME_OFFSETS = 0x0800    /* sample-composition-time-offsets-presents */
+};
+
+enum TfFlags
+{
+  TF_BASE_DATA_OFFSET         = 0x01,     /* base-data-offset-present */
+  TF_SAMPLE_DESCRIPTION_INDEX = 0x02,     /* sample-description-index-present */
+  TF_DEFAULT_SAMPLE_DURATION  = 0x08,     /* default-sample-duration-present */
+  TF_DEFAULT_SAMPLE_SIZE      = 0x010,    /* default-sample-size-present */
+  TF_DEFAULT_SAMPLE_FLAGS     = 0x020,    /* default-sample-flags-present */
+  TF_DURATION_IS_EMPTY        = 0x010000, /* sample-composition-time-offsets-presents */
+  TF_DEFAULT_BASE_IS_MOOF     = 0x020000  /* default-base-is-moof */
+};
+
+/* Timecode flags */
+enum TcFlags
+{
+  TC_DROP_FRAME = 0x0001,   /* Drop-frame timecode */
+  TC_24H_MAX = 0x0002,      /* Whether the timecode wraps after 24 hours */
+  TC_NEGATIVE_OK = 0x0004,  /* Whether negative time values are OK */
+  TC_COUNTER = 0x0008       /* Whether the time value corresponds to a tape counter value */
+};
+
+typedef struct _AtomTRAK
+{
+  Atom header;
+
+  AtomTKHD tkhd;
+  AtomInfo *tapt;
+  AtomEDTS *edts;
+  AtomMDIA mdia;
+  AtomUDTA udta;
+  AtomTREF *tref;
+
+  /* some helper info for structural conformity checks */
+  gboolean is_video;
+  gboolean is_h264;
+
+  AtomsContext *context;
+} AtomTRAK;
+
+typedef struct _AtomTREX
+{
+  AtomFull header;
+
+  guint32 track_ID;
+  guint32 default_sample_description_index;
+  guint32 default_sample_duration;
+  guint32 default_sample_size;
+  guint32 default_sample_flags;
+} AtomTREX;
+
+typedef struct _AtomMEHD
+{
+  AtomFull header;
+
+  guint64 fragment_duration;
+} AtomMEHD;
+
+
+typedef struct _AtomMVEX
+{
+  Atom header;
+
+  AtomMEHD mehd;
+
+  /* list of AtomTREX */
+  GList *trexs;
+} AtomMVEX;
+
+typedef struct _AtomMFHD
+{
+  AtomFull header;
+
+  guint32 sequence_number;
+} AtomMFHD;
+
+typedef struct _AtomTFHD
+{
+  AtomFull header;
+
+  guint32 track_ID;
+  guint64 base_data_offset;
+  guint32 sample_description_index;
+  guint32 default_sample_duration;
+  guint32 default_sample_size;
+  guint32 default_sample_flags;
+} AtomTFHD;
+
+typedef struct _AtomTFDT
+{
+  AtomFull header;
+
+  guint64 base_media_decode_time;
+} AtomTFDT;
+
+typedef struct _TRUNSampleEntry
+{
+  guint32 sample_duration;
+  guint32 sample_size;
+  guint32 sample_flags;
+  guint32 sample_composition_time_offset;
+} TRUNSampleEntry;
+
+typedef struct _AtomTRUN
+{
+  AtomFull header;
+
+  guint32 sample_count;
+  gint32 data_offset;
+  guint32 first_sample_flags;
+
+  /* array of fields */
+  ATOM_ARRAY (TRUNSampleEntry) entries;
+} AtomTRUN;
+
+typedef struct _AtomSDTP
+{
+  AtomFull header;
+
+  /* not serialized */
+  guint32 sample_count;
+
+  /* array of fields */
+  ATOM_ARRAY (guint8) entries;
+} AtomSDTP;
+
+typedef struct _AtomTRAF
+{
+  Atom header;
+
+  AtomTFHD tfhd;
+
+  AtomTFDT tfdt;
+
+  /* list of AtomTRUN */
+  GList *truns;
+  /* list of AtomSDTP */
+  GList *sdtps;
+} AtomTRAF;
+
+typedef struct _AtomMOOF
+{
+  Atom header;
+
+  AtomMFHD mfhd;
+
+  /* list of AtomTRAF */
+  GList *trafs;
+} AtomMOOF;
+
+
+typedef struct _AtomMOOV
+{
+  /* style */
+  AtomsContext context;
+
+  Atom header;
+
+  AtomMVHD mvhd;
+  AtomMVEX mvex;
+
+  /* list of AtomTRAK */
+  GList *traks;
+  AtomUDTA udta;
+
+  gboolean fragmented;
+  guint32 chunks_offset;
+} AtomMOOV;
+
+typedef struct _AtomWAVE
+{
+  Atom header;
+
+  /* list of AtomInfo */
+  GList *extension_atoms;
+} AtomWAVE;
+
+typedef struct _TFRAEntry
+{
+  guint64 time;
+  guint64 moof_offset;
+  guint32 traf_number;
+  guint32 trun_number;
+  guint32 sample_number;
+} TFRAEntry;
+
+typedef struct _AtomTFRA
+{
+  AtomFull header;
+
+  guint32 track_ID;
+  guint32 lengths;
+  /* array of entries */
+  ATOM_ARRAY (TFRAEntry) entries;
+} AtomTFRA;
+
+typedef struct _AtomMFRA
+{
+  Atom header;
+
+  /* list of tfra */
+  GList *tfras;
+} AtomMFRA;
+
+/*
+ * Function to serialize an atom
+ */
+typedef guint64 (*AtomCopyDataFunc) (Atom *atom, guint8 **buffer, guint64 *size, guint64 *offset);
+
+/*
+ * Releases memory allocated by an atom
+ */
+typedef guint64 (*AtomFreeFunc) (Atom *atom);
+
+/*
+ * Some atoms might have many optional different kinds of child atoms, so this
+ * is useful for enabling generic handling of any atom.
+ * All we need are the two functions (copying it to an array
+ * for serialization and the memory releasing function).
+ */
+struct _AtomInfo
+{
+  Atom *atom;
+  AtomCopyDataFunc copy_data_func;
+  AtomFreeFunc free_func;
+};
+
+guint64    atoms_get_current_qt_time   (void);
+
+guint64    atom_copy_data              (Atom *atom, guint8 **buffer,
+                                        guint64 *size, guint64* offset);
+
+AtomFTYP*  atom_ftyp_new               (AtomsContext *context, guint32 major,
+                                        guint32 version, GList *brands);
+guint64    atom_ftyp_copy_data         (AtomFTYP *ftyp, guint8 **buffer,
+                                        guint64 *size, guint64 *offset);
+void       atom_ftyp_free              (AtomFTYP *ftyp);
+
+AtomTRAK*  atom_trak_new               (AtomsContext *context);
+void       atom_trak_add_samples       (AtomTRAK * trak, guint32 nsamples, guint32 delta,
+                                        guint32 size, guint64 chunk_offset, gboolean sync,
+                                        gint64 pts_offset);
+void       atom_trak_set_elst_entry    (AtomTRAK * trak, gint index, guint32 duration,
+                                        guint32 media_time, guint32 rate);
+void       atom_trak_edts_clear        (AtomTRAK * trak);
+guint32    atom_trak_get_timescale     (AtomTRAK *trak);
+guint32    atom_trak_get_id            (AtomTRAK * trak);
+void       atom_trak_set_constant_size_samples (AtomTRAK * trak, guint32 sample_size);
+void       atom_stbl_add_samples       (AtomSTBL * stbl, guint32 nsamples,
+                                        guint32 delta, guint32 size,
+                                        guint64 chunk_offset, gboolean sync,
+                                        gint64 pts_offset);
+void       atom_stsc_add_new_entry     (AtomSTSC * stsc,
+                                        guint32 first_chunk, guint32 nsamples);
+
+AtomMOOV*  atom_moov_new               (AtomsContext *context);
+void       atom_moov_free              (AtomMOOV *moov);
+guint64    atom_moov_copy_data         (AtomMOOV *atom, guint8 **buffer, guint64 *size, guint64* offset);
+void       atom_moov_update_timescale  (AtomMOOV *moov, guint32 timescale);
+void       atom_moov_update_duration   (AtomMOOV *moov);
+void       atom_moov_set_fragmented    (AtomMOOV *moov, gboolean fragmented);
+void       atom_moov_chunks_set_offset (AtomMOOV *moov, guint32 offset);
+void       atom_moov_add_trak          (AtomMOOV *moov, AtomTRAK *trak);
+guint      atom_moov_get_trak_count    (AtomMOOV *moov);
+
+guint      atom_framerate_to_timescale (gint fps_n, gint fps_d);
+
+guint64    atom_mvhd_copy_data         (AtomMVHD * atom, guint8 ** buffer,
+                                        guint64 * size, guint64 * offset);
+void       atom_stco64_chunks_set_offset (AtomSTCO64 * stco64, guint32 offset);
+guint64    atom_trak_copy_data         (AtomTRAK * atom, guint8 ** buffer,
+                                        guint64 * size, guint64 * offset);
+void       atom_stbl_clear             (AtomSTBL * stbl);
+void       atom_stbl_init              (AtomSTBL * stbl);
+guint64    atom_stss_copy_data         (AtomSTSS *atom, guint8 **buffer,
+                                        guint64 *size, guint64* offset);
+guint64    atom_stts_copy_data         (AtomSTTS *atom, guint8 **buffer,
+                                        guint64 *size, guint64* offset);
+guint64    atom_stsc_copy_data         (AtomSTSC *atom, guint8 **buffer,
+                                        guint64 *size, guint64* offset);
+guint64    atom_stsz_copy_data         (AtomSTSZ *atom, guint8 **buffer,
+                                        guint64 *size, guint64* offset);
+guint64    atom_ctts_copy_data         (AtomCTTS *atom, guint8 **buffer,
+                                        guint64 *size, guint64* offset);
+guint64    atom_svmi_copy_data         (AtomSVMI *atom, guint8 **buffer,
+                                        guint64 *size, guint64* offset);
+AtomSVMI * atom_svmi_new (guint8 stereoscopic_composition_type, gboolean is_left_first);
+guint64    atom_stco64_copy_data       (AtomSTCO64 *atom, guint8 **buffer,
+                                        guint64 *size, guint64* offset);
+AtomMOOF*  atom_moof_new               (AtomsContext *context, guint32 sequence_number);
+void       atom_moof_free              (AtomMOOF *moof);
+guint64    atom_moof_copy_data         (AtomMOOF *moof, guint8 **buffer, guint64 *size, guint64* offset);
+AtomTRAF * atom_traf_new               (AtomsContext * context, guint32 track_ID);
+void       atom_traf_free              (AtomTRAF * traf);
+void       atom_traf_set_base_decode_time (AtomTRAF * traf, guint64 base_decode_time);
+void       atom_traf_add_samples       (AtomTRAF * traf, guint32 delta,
+                                        guint32 size, gboolean sync, gint64 pts_offset,
+                                        gboolean sdtp_sync);
+guint32    atom_traf_get_sample_num    (AtomTRAF * traf);
+void       atom_moof_add_traf          (AtomMOOF *moof, AtomTRAF *traf);
+
+AtomMFRA*  atom_mfra_new               (AtomsContext *context);
+void       atom_mfra_free              (AtomMFRA *mfra);
+AtomTFRA*  atom_tfra_new               (AtomsContext *context, guint32 track_ID);
+void       atom_tfra_add_entry         (AtomTFRA *tfra, guint64 dts, guint32 sample_num);
+void       atom_tfra_update_offset     (AtomTFRA * tfra, guint64 offset);
+void       atom_mfra_add_tfra          (AtomMFRA *mfra, AtomTFRA *tfra);
+guint64    atom_mfra_copy_data         (AtomMFRA *mfra, guint8 **buffer, guint64 *size, guint64* offset);
+
+
+/* media sample description related helpers */
+
+typedef struct
+{
+  guint16 version;
+  guint32 fourcc;
+  guint width;
+  guint height;
+  guint depth;
+  guint frame_count;
+  gint color_table_id;
+  guint par_n;
+  guint par_d;
+
+  GstBuffer *codec_data;
+} VisualSampleEntry;
+
+typedef struct
+{
+  guint32 fourcc;
+  guint version;
+  gint compression_id;
+  guint sample_rate;
+  guint channels;
+  guint sample_size;
+  guint bytes_per_packet;
+  guint samples_per_packet;
+  guint bytes_per_sample;
+  guint bytes_per_frame;
+
+  GstBuffer *codec_data;
+} AudioSampleEntry;
+
+typedef struct
+{
+  guint32 fourcc;
+
+  guint8  font_face; /* bold=0x1, italic=0x2, underline=0x4 */
+  guint8  font_size;
+  guint32 foreground_color_rgba;
+} SubtitleSampleEntry;
+
+void subtitle_sample_entry_init (SubtitleSampleEntry * entry);
+
+SampleTableEntryMP4A * atom_trak_set_audio_type (AtomTRAK * trak, AtomsContext * context,
+                               AudioSampleEntry * entry, guint32 scale,
+                               AtomInfo * ext, gint sample_size);
+
+SampleTableEntryMP4V * atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context,
+                               VisualSampleEntry * entry, guint32 rate,
+                               GList * ext_atoms_list);
+
+SampleTableEntryTX3G * atom_trak_set_subtitle_type (AtomTRAK * trak, AtomsContext * context,
+                               SubtitleSampleEntry * entry);
+
+SampleTableEntryTMCD *
+atom_trak_set_timecode_type (AtomTRAK * trak, AtomsContext * context, guint trak_timescale, GstVideoTimeCode * tc);
+
+void atom_trak_update_bitrates (AtomTRAK * trak, guint32 avg_bitrate,
+                                guint32 max_bitrate);
+
+void atom_trak_tx3g_update_dimension (AtomTRAK * trak, guint32 width,
+                                      guint32 height);
+
+void sample_table_entry_add_ext_atom (SampleTableEntry * ste, AtomInfo * ext);
+
+AtomInfo *   build_codec_data_extension  (guint32 fourcc, const GstBuffer * codec_data);
+AtomInfo *   build_mov_aac_extension     (AtomTRAK * trak, const GstBuffer * codec_data,
+                                          guint32 avg_bitrate, guint32 max_bitrate);
+AtomInfo *   build_mov_alac_extension    (const GstBuffer * codec_data);
+AtomInfo *   build_esds_extension        (AtomTRAK * trak, guint8 object_type,
+                                          guint8 stream_type, const GstBuffer * codec_data,
+                                          guint32 avg_bitrate, guint32 max_bitrate);
+AtomInfo *   build_btrt_extension        (guint32 buffer_size_db, guint32 avg_bitrate,
+                                          guint32 max_bitrate);
+AtomInfo *   build_jp2h_extension        (gint width, gint height, const gchar *colorspace,
+                                          gint ncomp, const GValue * cmap_array,
+                                          const GValue * cdef_array);
+
+AtomInfo *   build_jp2x_extension        (const GstBuffer * prefix);
+AtomInfo *   build_fiel_extension        (GstVideoInterlaceMode mode, GstVideoFieldOrder order);
+AtomInfo *   build_colr_extension        (const GstVideoColorimetry *colorimetry, gboolean is_mp4);
+AtomInfo *   build_clap_extension        (gint width_n, gint width_d, gint height_n, gint height_d, gint h_off_n, gint h_off_d, gint v_off_n, gint v_off_d);
+AtomInfo *   build_tapt_extension        (gint clef_width, gint clef_height, gint prof_width, gint prof_height, gint enof_width, gint enof_height);
+
+
+AtomInfo *   build_ac3_extension         (guint8 fscod, guint8 bsid,
+                                          guint8 bsmod, guint8 acmod,
+                                          guint8 lfe_on, guint8 bitrate_code);
+AtomInfo *   build_opus_extension        (guint32 rate, guint8 channels, guint8 mapping_family,
+                                          guint8 stream_count, guint8 coupled_count,
+                                          guint8 channel_mapping[256], guint16 pre_skip,
+                                          guint16 output_gain);
+
+AtomInfo *   build_amr_extension         (void);
+AtomInfo *   build_h263_extension        (void);
+AtomInfo *   build_gama_atom             (gdouble gamma);
+AtomInfo *   build_SMI_atom              (const GstBuffer *seqh);
+AtomInfo *   build_ima_adpcm_extension   (gint channels, gint rate,
+                                          gint blocksize);
+AtomInfo *   build_uuid_xmp_atom         (GstBuffer * xmp);
+
+
+/*
+ * Meta tags functions
+ */
+void atom_udta_clear_tags (AtomUDTA *udta);
+void atom_udta_add_str_tag    (AtomUDTA *udta, guint32 fourcc, const gchar *value);
+void atom_udta_add_uint_tag   (AtomUDTA *udta, guint32 fourcc, guint32 flags,
+                               guint32 value);
+void atom_udta_add_tag        (AtomUDTA *udta, guint32 fourcc, guint32 flags,
+                               const guint8 * data, guint size);
+void atom_udta_add_blob_tag   (AtomUDTA *udta, guint8 *data, guint size);
+
+void atom_udta_add_3gp_str_tag       (AtomUDTA *udta, guint32 fourcc, const gchar * value);
+void atom_udta_add_3gp_uint_tag      (AtomUDTA *udta, guint32 fourcc, guint16 value);
+void atom_udta_add_3gp_str_int_tag   (AtomUDTA *udta, guint32 fourcc, const gchar * value,
+                                      gint16 ivalue);
+void atom_udta_add_3gp_tag           (AtomUDTA *udta, guint32 fourcc, guint8 * data,
+                                      guint size);
+
+void atom_udta_add_xmp_tags          (AtomUDTA *udta, GstBuffer * xmp);
+
+AtomTREF * atom_tref_new (guint32 reftype);
+void atom_tref_add_entry (AtomTREF * tref, guint32 sample);
+
+#define GST_QT_MUX_DEFAULT_TAG_LANGUAGE   "und" /* undefined/unknown */
+guint16  language_code               (const char * lang);
+
+#endif /* __ATOMS_H__ */
diff --git a/gst/isomp4/atomsrecovery.c b/gst/isomp4/atomsrecovery.c
new file mode 100644
index 0000000..edc4434
--- /dev/null
+++ b/gst/isomp4/atomsrecovery.c
@@ -0,0 +1,1206 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * This module contains functions for serializing partial information from
+ * a mux in progress (by qtmux elements). This enables reconstruction of the
+ * moov box if a crash happens and thus recovering the movie file.
+ *
+ * Usage:
+ * 1) pipeline: ...yourelements ! qtmux moov-recovery-file=path.mrf ! \
+ * filesink location=moovie.mov
+ *
+ * 2) CRASH!
+ *
+ * 3) gst-launch-1.0 qtmoovrecover recovery-input=path.mrf broken-input=moovie.mov \
+        fixed-output=recovered.mov
+ *
+ * 4) (Hopefully) enjoy recovered.mov.
+ *
+ * --- Recovery file layout ---
+ * 1) Version (a guint16)
+ * 2) Prefix atom (if present)
+ * 3) ftyp atom
+ * 4) MVHD atom (without timescale/duration set)
+ * 5) moovie timescale
+ * 6) number of traks
+ * 7) list of trak atoms (stbl data is ignored, except for the stsd atom)
+ * 8) Buffers metadata (metadata that is relevant to the container)
+ *    Buffers metadata are stored in the order they are added to the mdat,
+ *    each entre has a fixed size and is stored in BE. booleans are stored
+ *    as a single byte where 0 means false, otherwise is true.
+ *   Metadata:
+ *   - guint32   track_id;
+ *   - guint32   nsamples;
+ *   - guint32   delta;
+ *   - guint32   size;
+ *   - guint64   chunk_offset;
+ *   - gboolean  sync;
+ *   - gboolean  do_pts;
+ *   - guint64   pts_offset; (always present, ignored if do_pts is false)
+ *
+ * The mdat file might contain ftyp and then mdat, in case this is the faststart
+ * temporary file there is no ftyp and no mdat header, only the buffers data.
+ *
+ * Notes about recovery file layout: We still don't store tags nor EDTS data.
+ *
+ * IMPORTANT: this is still at a experimental state.
+ */
+
+#include "atomsrecovery.h"
+
+#define MAX_CHUNK_SIZE (1024 * 1024)    /* 1MB */
+
+#define ATOMS_RECOV_OUTPUT_WRITE_ERROR(err) \
+    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE, \
+        "Failed to write to output file: %s", g_strerror (errno))
+
+static gboolean
+atoms_recov_write_version (FILE * f)
+{
+  guint8 data[2];
+  GST_WRITE_UINT16_BE (data, ATOMS_RECOV_FILE_VERSION);
+  return fwrite (data, 2, 1, f) == 1;
+}
+
+static gboolean
+atoms_recov_write_ftyp_info (FILE * f, AtomFTYP * ftyp, GstBuffer * prefix)
+{
+  guint8 *data = NULL;
+  guint64 offset = 0;
+  guint64 size = 0;
+
+  if (prefix) {
+    GstMapInfo map;
+
+    if (!gst_buffer_map (prefix, &map, GST_MAP_READ)) {
+      return FALSE;
+    }
+    if (fwrite (map.data, 1, map.size, f) != map.size) {
+      gst_buffer_unmap (prefix, &map);
+      return FALSE;
+    }
+    gst_buffer_unmap (prefix, &map);
+  }
+  if (!atom_ftyp_copy_data (ftyp, &data, &size, &offset)) {
+    return FALSE;
+  }
+  if (fwrite (data, 1, offset, f) != offset) {
+    g_free (data);
+    return FALSE;
+  }
+  g_free (data);
+  return TRUE;
+}
+
+/*
+ * Writes important info on the 'moov' atom (non-trak related)
+ * to be able to recover the moov structure after a crash.
+ *
+ * Currently, it writes the MVHD atom.
+ */
+static gboolean
+atoms_recov_write_moov_info (FILE * f, AtomMOOV * moov)
+{
+  guint8 *data;
+  guint64 size;
+  guint64 offset = 0;
+  guint64 atom_size = 0;
+  gint writen = 0;
+
+  /* likely enough */
+  size = 256;
+  data = g_malloc (size);
+  atom_size = atom_mvhd_copy_data (&moov->mvhd, &data, &size, &offset);
+  if (atom_size > 0)
+    writen = fwrite (data, 1, atom_size, f);
+  g_free (data);
+  return atom_size > 0 && writen == atom_size;
+}
+
+/*
+ * Writes the number of traks to the file.
+ * This simply writes a guint32 in BE.
+ */
+static gboolean
+atoms_recov_write_traks_number (FILE * f, guint32 traks)
+{
+  guint8 data[4];
+  GST_WRITE_UINT32_BE (data, traks);
+  return fwrite (data, 4, 1, f) == 1;
+}
+
+/*
+ * Writes the moov's timescale to the file
+ * This simply writes a guint32 in BE.
+ */
+static gboolean
+atoms_recov_write_moov_timescale (FILE * f, guint32 timescale)
+{
+  guint8 data[4];
+  GST_WRITE_UINT32_BE (data, timescale);
+  return fwrite (data, 4, 1, f) == 1;
+}
+
+/*
+ * Writes the trak atom to the file.
+ */
+gboolean
+atoms_recov_write_trak_info (FILE * f, AtomTRAK * trak)
+{
+  guint8 *data;
+  guint64 size;
+  guint64 offset = 0;
+  guint64 atom_size = 0;
+  gint writen = 0;
+
+  /* buffer is realloced to a larger size if needed */
+  size = 4 * 1024;
+  data = g_malloc (size);
+  atom_size = atom_trak_copy_data (trak, &data, &size, &offset);
+  if (atom_size > 0)
+    writen = fwrite (data, atom_size, 1, f);
+  g_free (data);
+  return atom_size > 0 && writen == atom_size;
+}
+
+gboolean
+atoms_recov_write_trak_samples (FILE * f, AtomTRAK * trak, guint32 nsamples,
+    guint32 delta, guint32 size, guint64 chunk_offset, gboolean sync,
+    gboolean do_pts, gint64 pts_offset)
+{
+  guint8 data[TRAK_BUFFER_ENTRY_INFO_SIZE];
+  /*
+   * We have to write a TrakBufferEntryInfo
+   */
+  GST_WRITE_UINT32_BE (data + 0, trak->tkhd.track_ID);
+  GST_WRITE_UINT32_BE (data + 4, nsamples);
+  GST_WRITE_UINT32_BE (data + 8, delta);
+  GST_WRITE_UINT32_BE (data + 12, size);
+  GST_WRITE_UINT64_BE (data + 16, chunk_offset);
+  if (sync)
+    GST_WRITE_UINT8 (data + 24, 1);
+  else
+    GST_WRITE_UINT8 (data + 24, 0);
+  if (do_pts) {
+    GST_WRITE_UINT8 (data + 25, 1);
+    GST_WRITE_UINT64_BE (data + 26, pts_offset);
+  } else {
+    GST_WRITE_UINT8 (data + 25, 0);
+    GST_WRITE_UINT64_BE (data + 26, 0);
+  }
+
+  return fwrite (data, 1, TRAK_BUFFER_ENTRY_INFO_SIZE, f) ==
+      TRAK_BUFFER_ENTRY_INFO_SIZE;
+}
+
+gboolean
+atoms_recov_write_headers (FILE * f, AtomFTYP * ftyp, GstBuffer * prefix,
+    AtomMOOV * moov, guint32 timescale, guint32 traks_number)
+{
+  if (!atoms_recov_write_version (f)) {
+    return FALSE;
+  }
+
+  if (!atoms_recov_write_ftyp_info (f, ftyp, prefix)) {
+    return FALSE;
+  }
+
+  if (!atoms_recov_write_moov_info (f, moov)) {
+    return FALSE;
+  }
+
+  if (!atoms_recov_write_moov_timescale (f, timescale)) {
+    return FALSE;
+  }
+
+  if (!atoms_recov_write_traks_number (f, traks_number)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+read_atom_header (FILE * f, guint32 * fourcc, guint32 * size)
+{
+  guint8 aux[8];
+
+  if (fread (aux, 1, 8, f) != 8)
+    return FALSE;
+  *size = GST_READ_UINT32_BE (aux);
+  *fourcc = GST_READ_UINT32_LE (aux + 4);
+  return TRUE;
+}
+
+static gboolean
+moov_recov_file_parse_prefix (MoovRecovFile * moovrf)
+{
+  guint32 fourcc;
+  guint32 size;
+  guint32 total_size = 0;
+  if (fseek (moovrf->file, 2, SEEK_SET) != 0)
+    return FALSE;
+  if (!read_atom_header (moovrf->file, &fourcc, &size)) {
+    return FALSE;
+  }
+
+  if (fourcc != FOURCC_ftyp) {
+    /* we might have a prefix here */
+    if (fseek (moovrf->file, size - 8, SEEK_CUR) != 0)
+      return FALSE;
+
+    total_size += size;
+
+    /* now read the ftyp */
+    if (!read_atom_header (moovrf->file, &fourcc, &size))
+      return FALSE;
+  }
+
+  /* this has to be the ftyp */
+  if (fourcc != FOURCC_ftyp)
+    return FALSE;
+  total_size += size;
+  moovrf->prefix_size = total_size;
+  return fseek (moovrf->file, size - 8, SEEK_CUR) == 0;
+}
+
+static gboolean
+moov_recov_file_parse_mvhd (MoovRecovFile * moovrf)
+{
+  guint32 fourcc;
+  guint32 size;
+  if (!read_atom_header (moovrf->file, &fourcc, &size)) {
+    return FALSE;
+  }
+  /* check for sanity */
+  if (fourcc != FOURCC_mvhd)
+    return FALSE;
+
+  moovrf->mvhd_size = size;
+  moovrf->mvhd_pos = ftell (moovrf->file) - 8;
+
+  /* skip the remaining of the mvhd in the file */
+  return fseek (moovrf->file, size - 8, SEEK_CUR) == 0;
+}
+
+static gboolean
+mdat_recov_file_parse_mdat_start (MdatRecovFile * mdatrf)
+{
+  guint32 fourcc, size;
+
+  if (!read_atom_header (mdatrf->file, &fourcc, &size)) {
+    return FALSE;
+  }
+  if (size == 1) {
+    mdatrf->mdat_header_size = 16;
+    mdatrf->mdat_size = 16;
+  } else {
+    mdatrf->mdat_header_size = 8;
+    mdatrf->mdat_size = 8;
+  }
+  mdatrf->mdat_start = ftell (mdatrf->file) - 8;
+
+  return fourcc == FOURCC_mdat;
+}
+
+static gboolean
+mdat_recov_file_find_mdat (FILE * file, GError ** err)
+{
+  guint32 fourcc = 0, size = 0;
+  gboolean failure = FALSE;
+  while (fourcc != FOURCC_mdat && !failure) {
+    if (!read_atom_header (file, &fourcc, &size)) {
+      goto parse_error;
+    }
+    switch (fourcc) {
+        /* skip these atoms */
+      case FOURCC_ftyp:
+      case FOURCC_free:
+      case FOURCC_udta:
+        if (fseek (file, size - 8, SEEK_CUR) != 0) {
+          goto file_seek_error;
+        }
+        break;
+      case FOURCC_mdat:
+        break;
+      default:
+        GST_ERROR ("Unexpected atom in headers %" GST_FOURCC_FORMAT,
+            GST_FOURCC_ARGS (fourcc));
+        failure = TRUE;
+        break;
+    }
+  }
+
+  if (!failure) {
+    /* Reverse to mdat start */
+    if (fseek (file, -8, SEEK_CUR) != 0)
+      goto file_seek_error;
+  }
+
+  return !failure;
+
+parse_error:
+  g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
+      "Failed to parse atom");
+  return FALSE;
+
+file_seek_error:
+  g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
+      "Failed to seek to start of the file");
+  return FALSE;
+
+}
+
+MdatRecovFile *
+mdat_recov_file_create (FILE * file, gboolean datafile, GError ** err)
+{
+  MdatRecovFile *mrf = g_new0 (MdatRecovFile, 1);
+
+  g_return_val_if_fail (file != NULL, NULL);
+
+  mrf->file = file;
+  mrf->rawfile = datafile;
+
+  /* get the file/data length */
+  if (fseek (file, 0, SEEK_END) != 0)
+    goto file_length_error;
+  /* still needs to deduce the mdat header and ftyp size */
+  mrf->data_size = ftell (file);
+  if (mrf->data_size == -1L)
+    goto file_length_error;
+
+  if (fseek (file, 0, SEEK_SET) != 0)
+    goto file_seek_error;
+
+  if (datafile) {
+    /* this file contains no atoms, only raw data to be placed on the mdat
+     * this happens when faststart mode is used */
+    mrf->mdat_start = 0;
+    mrf->mdat_header_size = 16;
+    mrf->mdat_size = 16;
+    return mrf;
+  }
+
+  if (!mdat_recov_file_find_mdat (file, err)) {
+    goto fail;
+  }
+
+  /* we don't parse this if we have a tmpdatafile */
+  if (!mdat_recov_file_parse_mdat_start (mrf)) {
+    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_PARSING,
+        "Error while parsing mdat atom");
+    goto fail;
+  }
+
+  return mrf;
+
+file_seek_error:
+  g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
+      "Failed to seek to start of the file");
+  goto fail;
+
+file_length_error:
+  g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
+      "Failed to determine file size");
+  goto fail;
+
+fail:
+  mdat_recov_file_free (mrf);
+  return NULL;
+}
+
+void
+mdat_recov_file_free (MdatRecovFile * mrf)
+{
+  fclose (mrf->file);
+  g_free (mrf);
+}
+
+static gboolean
+moov_recov_parse_num_traks (MoovRecovFile * moovrf)
+{
+  guint8 traks[4];
+  if (fread (traks, 1, 4, moovrf->file) != 4)
+    return FALSE;
+  moovrf->num_traks = GST_READ_UINT32_BE (traks);
+  return TRUE;
+}
+
+static gboolean
+moov_recov_parse_moov_timescale (MoovRecovFile * moovrf)
+{
+  guint8 ts[4];
+  if (fread (ts, 1, 4, moovrf->file) != 4)
+    return FALSE;
+  moovrf->timescale = GST_READ_UINT32_BE (ts);
+  return TRUE;
+}
+
+static gboolean
+skip_atom (MoovRecovFile * moovrf, guint32 expected_fourcc)
+{
+  guint32 size;
+  guint32 fourcc;
+
+  if (!read_atom_header (moovrf->file, &fourcc, &size))
+    return FALSE;
+  if (fourcc != expected_fourcc)
+    return FALSE;
+
+  return (fseek (moovrf->file, size - 8, SEEK_CUR) == 0);
+}
+
+static gboolean
+moov_recov_parse_tkhd (MoovRecovFile * moovrf, TrakRecovData * trakrd)
+{
+  guint32 size;
+  guint32 fourcc;
+  guint8 data[4];
+
+  /* make sure we are on a tkhd atom */
+  if (!read_atom_header (moovrf->file, &fourcc, &size))
+    return FALSE;
+  if (fourcc != FOURCC_tkhd)
+    return FALSE;
+
+  trakrd->tkhd_file_offset = ftell (moovrf->file) - 8;
+
+  /* move 8 bytes forward to the trak_id pos */
+  if (fseek (moovrf->file, 12, SEEK_CUR) != 0)
+    return FALSE;
+  if (fread (data, 1, 4, moovrf->file) != 4)
+    return FALSE;
+
+  /* advance the rest of tkhd */
+  if (fseek (moovrf->file, 68, SEEK_CUR) != 0)
+    return FALSE;
+
+  trakrd->trak_id = GST_READ_UINT32_BE (data);
+  return TRUE;
+}
+
+static gboolean
+moov_recov_parse_stbl (MoovRecovFile * moovrf, TrakRecovData * trakrd)
+{
+  guint32 size;
+  guint32 fourcc;
+  guint32 auxsize;
+
+  if (!read_atom_header (moovrf->file, &fourcc, &size))
+    return FALSE;
+  if (fourcc != FOURCC_stbl)
+    return FALSE;
+
+  trakrd->stbl_file_offset = ftell (moovrf->file) - 8;
+  trakrd->stbl_size = size;
+
+  /* skip the stsd */
+  if (!read_atom_header (moovrf->file, &fourcc, &auxsize))
+    return FALSE;
+  if (fourcc != FOURCC_stsd)
+    return FALSE;
+  if (fseek (moovrf->file, auxsize - 8, SEEK_CUR) != 0)
+    return FALSE;
+
+  trakrd->stsd_size = auxsize;
+  trakrd->post_stsd_offset = ftell (moovrf->file);
+
+  /* as this is the last atom we parse, we don't skip forward */
+
+  return TRUE;
+}
+
+static gboolean
+moov_recov_parse_minf (MoovRecovFile * moovrf, TrakRecovData * trakrd)
+{
+  guint32 size;
+  guint32 fourcc;
+  guint32 auxsize;
+
+  if (!read_atom_header (moovrf->file, &fourcc, &size))
+    return FALSE;
+  if (fourcc != FOURCC_minf)
+    return FALSE;
+
+  trakrd->minf_file_offset = ftell (moovrf->file) - 8;
+  trakrd->minf_size = size;
+
+  /* skip either of vmhd, smhd, hmhd that might follow */
+  if (!read_atom_header (moovrf->file, &fourcc, &auxsize))
+    return FALSE;
+  if (fourcc != FOURCC_vmhd && fourcc != FOURCC_smhd && fourcc != FOURCC_hmhd &&
+      fourcc != FOURCC_gmhd)
+    return FALSE;
+  if (fseek (moovrf->file, auxsize - 8, SEEK_CUR))
+    return FALSE;
+
+  /* skip a possible hdlr and the following dinf */
+  if (!read_atom_header (moovrf->file, &fourcc, &auxsize))
+    return FALSE;
+  if (fourcc == FOURCC_hdlr) {
+    if (fseek (moovrf->file, auxsize - 8, SEEK_CUR))
+      return FALSE;
+    if (!read_atom_header (moovrf->file, &fourcc, &auxsize))
+      return FALSE;
+  }
+  if (fourcc != FOURCC_dinf)
+    return FALSE;
+  if (fseek (moovrf->file, auxsize - 8, SEEK_CUR))
+    return FALSE;
+
+  /* now we are ready to read the stbl */
+  if (!moov_recov_parse_stbl (moovrf, trakrd))
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+moov_recov_parse_mdhd (MoovRecovFile * moovrf, TrakRecovData * trakrd)
+{
+  guint32 size;
+  guint32 fourcc;
+  guint8 data[4];
+
+  /* make sure we are on a tkhd atom */
+  if (!read_atom_header (moovrf->file, &fourcc, &size))
+    return FALSE;
+  if (fourcc != FOURCC_mdhd)
+    return FALSE;
+
+  trakrd->mdhd_file_offset = ftell (moovrf->file) - 8;
+
+  /* get the timescale */
+  if (fseek (moovrf->file, 12, SEEK_CUR) != 0)
+    return FALSE;
+  if (fread (data, 1, 4, moovrf->file) != 4)
+    return FALSE;
+  trakrd->timescale = GST_READ_UINT32_BE (data);
+  if (fseek (moovrf->file, 8, SEEK_CUR) != 0)
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+moov_recov_parse_mdia (MoovRecovFile * moovrf, TrakRecovData * trakrd)
+{
+  guint32 size;
+  guint32 fourcc;
+
+  /* make sure we are on a tkhd atom */
+  if (!read_atom_header (moovrf->file, &fourcc, &size))
+    return FALSE;
+  if (fourcc != FOURCC_mdia)
+    return FALSE;
+
+  trakrd->mdia_file_offset = ftell (moovrf->file) - 8;
+  trakrd->mdia_size = size;
+
+  if (!moov_recov_parse_mdhd (moovrf, trakrd))
+    return FALSE;
+
+  if (!skip_atom (moovrf, FOURCC_hdlr))
+    return FALSE;
+  if (!moov_recov_parse_minf (moovrf, trakrd))
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+moov_recov_parse_trak (MoovRecovFile * moovrf, TrakRecovData * trakrd)
+{
+  guint64 offset;
+  guint32 size;
+  guint32 fourcc;
+
+  offset = ftell (moovrf->file);
+  if (offset == -1) {
+    return FALSE;
+  }
+
+  /* make sure we are on a trak atom */
+  if (!read_atom_header (moovrf->file, &fourcc, &size)) {
+    return FALSE;
+  }
+  if (fourcc != FOURCC_trak) {
+    return FALSE;
+  }
+  trakrd->trak_size = size;
+
+  /* now we should have a trak header 'tkhd' */
+  if (!moov_recov_parse_tkhd (moovrf, trakrd))
+    return FALSE;
+
+  /* FIXME add edts handling here and in qtmux, as this is only detected
+   * after buffers start flowing */
+
+  if (!moov_recov_parse_mdia (moovrf, trakrd))
+    return FALSE;
+
+  if (fseek (moovrf->file,
+          (long int) trakrd->mdia_file_offset + trakrd->mdia_size,
+          SEEK_SET) != 0)
+    return FALSE;
+
+  trakrd->extra_atoms_offset = ftell (moovrf->file);
+  trakrd->extra_atoms_size = size - (trakrd->extra_atoms_offset - offset);
+
+  trakrd->file_offset = offset;
+  /* position after the trak */
+  return fseek (moovrf->file, (long int) offset + size, SEEK_SET) == 0;
+}
+
+MoovRecovFile *
+moov_recov_file_create (FILE * file, GError ** err)
+{
+  gint i;
+  MoovRecovFile *moovrf = g_new0 (MoovRecovFile, 1);
+
+  g_return_val_if_fail (file != NULL, NULL);
+
+  moovrf->file = file;
+
+  /* look for ftyp and prefix at the start */
+  if (!moov_recov_file_parse_prefix (moovrf)) {
+    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_PARSING,
+        "Error while parsing prefix atoms");
+    goto fail;
+  }
+
+  /* parse the mvhd */
+  if (!moov_recov_file_parse_mvhd (moovrf)) {
+    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_PARSING,
+        "Error while parsing mvhd atom");
+    goto fail;
+  }
+
+  if (!moov_recov_parse_moov_timescale (moovrf)) {
+    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_PARSING,
+        "Error while parsing timescale");
+    goto fail;
+  }
+  if (!moov_recov_parse_num_traks (moovrf)) {
+    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_PARSING,
+        "Error while parsing parsing number of traks");
+    goto fail;
+  }
+
+  /* sanity check */
+  if (moovrf->num_traks > 1024) {
+    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_PARSING,
+        "Unsupported number of traks");
+    goto fail;
+  }
+
+  /* init the traks */
+  moovrf->traks_rd = g_new0 (TrakRecovData, moovrf->num_traks);
+  for (i = 0; i < moovrf->num_traks; i++) {
+    atom_stbl_init (&(moovrf->traks_rd[i].stbl));
+  }
+  for (i = 0; i < moovrf->num_traks; i++) {
+    if (!moov_recov_parse_trak (moovrf, &(moovrf->traks_rd[i]))) {
+      g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_PARSING,
+          "Error while parsing trak atom");
+      goto fail;
+    }
+  }
+
+  return moovrf;
+
+fail:
+  moov_recov_file_free (moovrf);
+  return NULL;
+}
+
+void
+moov_recov_file_free (MoovRecovFile * moovrf)
+{
+  gint i;
+  fclose (moovrf->file);
+  if (moovrf->traks_rd) {
+    for (i = 0; i < moovrf->num_traks; i++) {
+      atom_stbl_clear (&(moovrf->traks_rd[i].stbl));
+    }
+    g_free (moovrf->traks_rd);
+  }
+  g_free (moovrf);
+}
+
+static gboolean
+moov_recov_parse_buffer_entry (MoovRecovFile * moovrf, TrakBufferEntryInfo * b)
+{
+  guint8 data[TRAK_BUFFER_ENTRY_INFO_SIZE];
+  gint read;
+
+  read = fread (data, 1, TRAK_BUFFER_ENTRY_INFO_SIZE, moovrf->file);
+  if (read != TRAK_BUFFER_ENTRY_INFO_SIZE)
+    return FALSE;
+
+  b->track_id = GST_READ_UINT32_BE (data);
+  b->nsamples = GST_READ_UINT32_BE (data + 4);
+  b->delta = GST_READ_UINT32_BE (data + 8);
+  b->size = GST_READ_UINT32_BE (data + 12);
+  b->chunk_offset = GST_READ_UINT64_BE (data + 16);
+  b->sync = data[24] != 0;
+  b->do_pts = data[25] != 0;
+  b->pts_offset = GST_READ_UINT64_BE (data + 26);
+  return TRUE;
+}
+
+static gboolean
+mdat_recov_add_sample (MdatRecovFile * mdatrf, guint32 size)
+{
+  /* test if this data exists */
+  if (mdatrf->mdat_size - mdatrf->mdat_header_size + size > mdatrf->data_size)
+    return FALSE;
+
+  mdatrf->mdat_size += size;
+  return TRUE;
+}
+
+static TrakRecovData *
+moov_recov_get_trak (MoovRecovFile * moovrf, guint32 id)
+{
+  gint i;
+  for (i = 0; i < moovrf->num_traks; i++) {
+    if (moovrf->traks_rd[i].trak_id == id)
+      return &(moovrf->traks_rd[i]);
+  }
+  return NULL;
+}
+
+static void
+trak_recov_data_add_sample (TrakRecovData * trak, TrakBufferEntryInfo * b)
+{
+  trak->duration += b->nsamples * b->delta;
+  atom_stbl_add_samples (&trak->stbl, b->nsamples, b->delta, b->size,
+      b->chunk_offset, b->sync, b->pts_offset);
+}
+
+/*
+ * Parses the buffer entries in the MoovRecovFile and matches the inputs
+ * with the data in the MdatRecovFile. Whenever a buffer entry of that
+ * represents 'x' bytes of data, the same amount of data is 'validated' in
+ * the MdatRecovFile and will be inluded in the generated moovie file.
+ */
+gboolean
+moov_recov_parse_buffers (MoovRecovFile * moovrf, MdatRecovFile * mdatrf,
+    GError ** err)
+{
+  TrakBufferEntryInfo entry;
+  TrakRecovData *trak;
+
+  /* we assume both moovrf and mdatrf are at the starting points of their
+   * data reading */
+  while (moov_recov_parse_buffer_entry (moovrf, &entry)) {
+    /* be sure we still have this data in mdat */
+    trak = moov_recov_get_trak (moovrf, entry.track_id);
+    if (trak == NULL) {
+      g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_PARSING,
+          "Invalid trak id found in buffer entry");
+      return FALSE;
+    }
+    if (!mdat_recov_add_sample (mdatrf, entry.size))
+      break;
+    trak_recov_data_add_sample (trak, &entry);
+  }
+  return TRUE;
+}
+
+static guint32
+trak_recov_data_get_trak_atom_size (TrakRecovData * trak)
+{
+  AtomSTBL *stbl = &trak->stbl;
+  guint64 offset;
+
+  /* write out our stbl child atoms */
+  offset = 0;
+
+  if (!atom_stts_copy_data (&stbl->stts, NULL, NULL, &offset)) {
+    goto fail;
+  }
+  if (atom_array_get_len (&stbl->stss.entries) > 0) {
+    if (!atom_stss_copy_data (&stbl->stss, NULL, NULL, &offset)) {
+      goto fail;
+    }
+  }
+  if (!atom_stsc_copy_data (&stbl->stsc, NULL, NULL, &offset)) {
+    goto fail;
+  }
+  if (!atom_stsz_copy_data (&stbl->stsz, NULL, NULL, &offset)) {
+    goto fail;
+  }
+  if (stbl->ctts) {
+    if (!atom_ctts_copy_data (stbl->ctts, NULL, NULL, &offset)) {
+      goto fail;
+    }
+  }
+  if (!atom_stco64_copy_data (&stbl->stco64, NULL, NULL, &offset)) {
+    goto fail;
+  }
+
+  return trak->trak_size + ((trak->stsd_size + offset + 8) - trak->stbl_size);
+
+fail:
+  return 0;
+}
+
+static guint8 *
+moov_recov_get_stbl_children_data (MoovRecovFile * moovrf, TrakRecovData * trak,
+    guint64 * p_size)
+{
+  AtomSTBL *stbl = &trak->stbl;
+  guint8 *buffer;
+  guint64 size;
+  guint64 offset;
+
+  /* write out our stbl child atoms
+   *
+   * Use 1MB as a starting size, *_copy_data functions
+   * will grow the buffer if needed.
+   */
+  size = 1024 * 1024;
+  buffer = g_malloc0 (size);
+  offset = 0;
+
+  if (!atom_stts_copy_data (&stbl->stts, &buffer, &size, &offset)) {
+    goto fail;
+  }
+  if (atom_array_get_len (&stbl->stss.entries) > 0) {
+    if (!atom_stss_copy_data (&stbl->stss, &buffer, &size, &offset)) {
+      goto fail;
+    }
+  }
+  if (!atom_stsc_copy_data (&stbl->stsc, &buffer, &size, &offset)) {
+    goto fail;
+  }
+  if (!atom_stsz_copy_data (&stbl->stsz, &buffer, &size, &offset)) {
+    goto fail;
+  }
+  if (stbl->ctts) {
+    if (!atom_ctts_copy_data (stbl->ctts, &buffer, &size, &offset)) {
+      goto fail;
+    }
+  }
+  if (!atom_stco64_copy_data (&stbl->stco64, &buffer, &size, &offset)) {
+    goto fail;
+  }
+  *p_size = offset;
+  return buffer;
+
+fail:
+  g_free (buffer);
+  return NULL;
+}
+
+static gboolean
+copy_data_from_file_to_file (FILE * from, guint position, guint size, FILE * to,
+    GError ** err)
+{
+  guint8 *data = NULL;
+
+  if (fseek (from, position, SEEK_SET) != 0)
+    goto fail;
+  data = g_malloc (size);
+  if (fread (data, 1, size, from) != size) {
+    goto fail;
+  }
+  if (fwrite (data, 1, size, to) != size) {
+    ATOMS_RECOV_OUTPUT_WRITE_ERROR (err);
+    goto fail;
+  }
+
+  g_free (data);
+  return TRUE;
+
+fail:
+  g_free (data);
+  return FALSE;
+}
+
+gboolean
+moov_recov_write_file (MoovRecovFile * moovrf, MdatRecovFile * mdatrf,
+    FILE * outf, GError ** err, GError ** warn)
+{
+  guint8 auxdata[16];
+  guint8 *data = NULL;
+  guint8 *prefix_data = NULL;
+  guint8 *mvhd_data = NULL;
+  guint8 *trak_data = NULL;
+  guint32 moov_size = 0;
+  gint i;
+  guint64 stbl_children_size = 0;
+  guint8 *stbl_children = NULL;
+  guint32 longest_duration = 0;
+  guint16 version;
+  guint remaining;
+
+  /* check the version */
+  if (fseek (moovrf->file, 0, SEEK_SET) != 0) {
+    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
+        "Failed to seek to the start of the moov recovery file");
+    goto fail;
+  }
+  if (fread (auxdata, 1, 2, moovrf->file) != 2) {
+    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
+        "Failed to read version from file");
+  }
+
+  version = GST_READ_UINT16_BE (auxdata);
+  if (version != ATOMS_RECOV_FILE_VERSION) {
+    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_VERSION,
+        "Input file version (%u) is not supported in this version (%u)",
+        version, ATOMS_RECOV_FILE_VERSION);
+    return FALSE;
+  }
+
+  /* write the ftyp */
+  prefix_data = g_malloc (moovrf->prefix_size);
+  if (fread (prefix_data, 1, moovrf->prefix_size,
+          moovrf->file) != moovrf->prefix_size) {
+    g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
+        "Failed to read the ftyp atom from file");
+    goto fail;
+  }
+  if (fwrite (prefix_data, 1, moovrf->prefix_size, outf) != moovrf->prefix_size) {
+    ATOMS_RECOV_OUTPUT_WRITE_ERROR (err);
+    goto fail;
+  }
+  g_free (prefix_data);
+  prefix_data = NULL;
+
+  /* need to calculate the moov size beforehand to add the offset to
+   * chunk offset entries */
+  moov_size += moovrf->mvhd_size + 8;   /* mvhd + moov size + fourcc */
+  for (i = 0; i < moovrf->num_traks; i++) {
+    TrakRecovData *trak = &(moovrf->traks_rd[i]);
+    guint32 duration;           /* in moov's timescale */
+    guint32 trak_size;
+
+    /* convert trak duration to moov's duration */
+    duration = gst_util_uint64_scale_round (trak->duration, moovrf->timescale,
+        trak->timescale);
+
+    if (duration > longest_duration)
+      longest_duration = duration;
+    trak_size = trak_recov_data_get_trak_atom_size (trak);
+    if (trak_size == 0) {
+      g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_GENERIC,
+          "Failed to estimate trak atom size");
+      goto fail;
+    }
+    moov_size += trak_size;
+  }
+
+  /* add chunks offsets */
+  for (i = 0; i < moovrf->num_traks; i++) {
+    TrakRecovData *trak = &(moovrf->traks_rd[i]);
+    /* 8 or 16 for the mdat header */
+    gint64 offset = moov_size + ftell (outf) + mdatrf->mdat_header_size;
+    atom_stco64_chunks_set_offset (&trak->stbl.stco64, offset);
+  }
+
+  /* write the moov */
+  GST_WRITE_UINT32_BE (auxdata, moov_size);
+  GST_WRITE_UINT32_LE (auxdata + 4, FOURCC_moov);
+  if (fwrite (auxdata, 1, 8, outf) != 8) {
+    ATOMS_RECOV_OUTPUT_WRITE_ERROR (err);
+    goto fail;
+  }
+
+  /* write the mvhd */
+  mvhd_data = g_malloc (moovrf->mvhd_size);
+  if (fseek (moovrf->file, moovrf->mvhd_pos, SEEK_SET) != 0)
+    goto fail;
+  if (fread (mvhd_data, 1, moovrf->mvhd_size,
+          moovrf->file) != moovrf->mvhd_size)
+    goto fail;
+  GST_WRITE_UINT32_BE (mvhd_data + 20, moovrf->timescale);
+  GST_WRITE_UINT32_BE (mvhd_data + 24, longest_duration);
+  if (fwrite (mvhd_data, 1, moovrf->mvhd_size, outf) != moovrf->mvhd_size) {
+    ATOMS_RECOV_OUTPUT_WRITE_ERROR (err);
+    goto fail;
+  }
+  g_free (mvhd_data);
+  mvhd_data = NULL;
+
+  /* write the traks, this is the tough part because we need to update:
+   * - stbl atom
+   * - sizes of atoms from stbl to trak
+   * - trak duration
+   */
+  for (i = 0; i < moovrf->num_traks; i++) {
+    TrakRecovData *trak = &(moovrf->traks_rd[i]);
+    guint trak_data_size;
+    guint32 stbl_new_size;
+    guint32 minf_new_size;
+    guint32 mdia_new_size;
+    guint32 trak_new_size;
+    guint32 size_diff;
+    guint32 duration;           /* in moov's timescale */
+
+    /* convert trak duration to moov's duration */
+    duration = gst_util_uint64_scale_round (trak->duration, moovrf->timescale,
+        trak->timescale);
+
+    stbl_children = moov_recov_get_stbl_children_data (moovrf, trak,
+        &stbl_children_size);
+    if (stbl_children == NULL)
+      goto fail;
+
+    /* calc the new size of the atoms from stbl to trak in the atoms tree */
+    stbl_new_size = trak->stsd_size + stbl_children_size + 8;
+    size_diff = stbl_new_size - trak->stbl_size;
+    minf_new_size = trak->minf_size + size_diff;
+    mdia_new_size = trak->mdia_size + size_diff;
+    trak_new_size = trak->trak_size + size_diff;
+
+    if (fseek (moovrf->file, trak->file_offset, SEEK_SET) != 0)
+      goto fail;
+    trak_data_size = trak->post_stsd_offset - trak->file_offset;
+    trak_data = g_malloc (trak_data_size);
+    if (fread (trak_data, 1, trak_data_size, moovrf->file) != trak_data_size) {
+      goto fail;
+    }
+    /* update the size values in those read atoms before writing */
+    GST_WRITE_UINT32_BE (trak_data, trak_new_size);
+    GST_WRITE_UINT32_BE (trak_data + (trak->mdia_file_offset -
+            trak->file_offset), mdia_new_size);
+    GST_WRITE_UINT32_BE (trak_data + (trak->minf_file_offset -
+            trak->file_offset), minf_new_size);
+    GST_WRITE_UINT32_BE (trak_data + (trak->stbl_file_offset -
+            trak->file_offset), stbl_new_size);
+
+    /* update duration values in tkhd and mdhd */
+    GST_WRITE_UINT32_BE (trak_data + (trak->tkhd_file_offset -
+            trak->file_offset) + 28, duration);
+    GST_WRITE_UINT32_BE (trak_data + (trak->mdhd_file_offset -
+            trak->file_offset) + 24, trak->duration);
+
+    if (fwrite (trak_data, 1, trak_data_size, outf) != trak_data_size) {
+      ATOMS_RECOV_OUTPUT_WRITE_ERROR (err);
+      goto fail;
+    }
+    if (fwrite (stbl_children, 1, stbl_children_size, outf) !=
+        stbl_children_size) {
+      ATOMS_RECOV_OUTPUT_WRITE_ERROR (err);
+      goto fail;
+    }
+
+    g_free (trak_data);
+    trak_data = NULL;
+    g_free (stbl_children);
+    stbl_children = NULL;
+
+    /* Copy the extra atoms after 'minf' */
+    if (!copy_data_from_file_to_file (moovrf->file, trak->extra_atoms_offset,
+            trak->extra_atoms_size, outf, err))
+      goto fail;
+  }
+
+  /* write the mdat */
+  /* write the header first */
+  if (mdatrf->mdat_header_size == 16) {
+    GST_WRITE_UINT32_BE (auxdata, 1);
+    GST_WRITE_UINT32_LE (auxdata + 4, FOURCC_mdat);
+    GST_WRITE_UINT64_BE (auxdata + 8, mdatrf->mdat_size);
+  } else if (mdatrf->mdat_header_size == 8) {
+    GST_WRITE_UINT32_BE (auxdata, mdatrf->mdat_size);
+    GST_WRITE_UINT32_LE (auxdata + 4, FOURCC_mdat);
+  } else {
+    GST_ERROR ("Unexpected atom size: %u", mdatrf->mdat_header_size);
+    g_assert_not_reached ();
+    goto fail;
+  }
+
+  if (fwrite (auxdata, 1, mdatrf->mdat_header_size,
+          outf) != mdatrf->mdat_header_size) {
+    ATOMS_RECOV_OUTPUT_WRITE_ERROR (err);
+    goto fail;
+  }
+
+  /* now read the mdat data and output to the file */
+  if (fseek (mdatrf->file, mdatrf->mdat_start +
+          (mdatrf->rawfile ? 0 : mdatrf->mdat_header_size), SEEK_SET) != 0)
+    goto fail;
+
+  remaining = mdatrf->mdat_size - mdatrf->mdat_header_size;
+  data = g_malloc (MAX_CHUNK_SIZE);
+  while (!feof (mdatrf->file) && remaining > 0) {
+    gint read, write, readsize;
+
+    readsize = MIN (MAX_CHUNK_SIZE, remaining);
+
+    read = fread (data, 1, readsize, mdatrf->file);
+    write = fwrite (data, 1, read, outf);
+    remaining -= read;
+
+    if (write != read) {
+      g_set_error (err, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
+          "Failed to copy data to output file: %s", g_strerror (errno));
+      goto fail;
+    }
+  }
+  g_free (data);
+
+  if (remaining) {
+    g_set_error (warn, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
+        "Samples in recovery file were not present on headers."
+        " Bytes lost: %u", remaining);
+  } else if (!feof (mdatrf->file)) {
+    g_set_error (warn, ATOMS_RECOV_QUARK, ATOMS_RECOV_ERR_FILE,
+        "Samples in headers were not found in data file.");
+    GST_FIXME ("Rewrite mdat size if we reach this to make the file"
+        " fully correct");
+  }
+
+  return TRUE;
+
+fail:
+  g_free (stbl_children);
+  g_free (mvhd_data);
+  g_free (prefix_data);
+  g_free (trak_data);
+  g_free (data);
+  return FALSE;
+}
diff --git a/gst/isomp4/atomsrecovery.h b/gst/isomp4/atomsrecovery.h
new file mode 100644
index 0000000..f044c9b
--- /dev/null
+++ b/gst/isomp4/atomsrecovery.h
@@ -0,0 +1,162 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __ATOMS_RECOVERY_H__
+#define __ATOMS_RECOVERY_H__
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#include <gst/gst.h>
+
+#include "atoms.h"
+
+/* Version to be incremented each time we decide
+ * to change the file layout */
+#define ATOMS_RECOV_FILE_VERSION          1
+
+#define ATOMS_RECOV_QUARK (g_quark_from_string ("qtmux-atoms-recovery"))
+
+/* gerror error codes */
+#define ATOMS_RECOV_ERR_GENERIC           1
+#define ATOMS_RECOV_ERR_FILE              2
+#define ATOMS_RECOV_ERR_PARSING           3
+#define ATOMS_RECOV_ERR_VERSION           4
+
+/* this struct represents each buffer in a moov file, containing the info
+ * that is placed in the stsd children atoms
+ * Fields should be writen in BE order, and booleans should be writen as
+ * 1byte with 0 for false, anything otherwise */
+#define TRAK_BUFFER_ENTRY_INFO_SIZE 34
+typedef struct
+{
+  guint32   track_id;
+  guint32   nsamples;
+  guint32   delta;
+  guint32   size;
+  guint64   chunk_offset;
+  guint64   pts_offset;
+  gboolean  sync;
+  gboolean  do_pts;
+} TrakBufferEntryInfo;
+
+typedef struct
+{
+  guint32 trak_id;
+  guint32 duration;  /* duration in trak timescale */
+  guint32 timescale; /* trak's timescale */
+
+  guint64 file_offset;
+
+  /* need for later updating duration */
+  guint64 tkhd_file_offset;
+  guint64 mdhd_file_offset;
+
+  /* need these offsets to update size */
+  guint32 trak_size;
+  guint64 mdia_file_offset;
+  guint32 mdia_size;
+  guint64 minf_file_offset;
+  guint32 minf_size;
+  guint64 stbl_file_offset;
+  guint32 stbl_size;
+
+  guint64 post_stsd_offset;
+  guint32 stsd_size;
+
+  guint32 extra_atoms_size;
+  guint32 extra_atoms_offset;
+
+  /* for storing the samples info */
+  AtomSTBL stbl;
+} TrakRecovData;
+
+typedef struct
+{
+  FILE * file;
+  gboolean rawfile;
+
+  /* results from parsing the input file */
+  guint64   data_size;
+  guint32   mdat_header_size;
+  guint     mdat_start;
+
+  guint64   mdat_size;
+} MdatRecovFile;
+
+typedef struct
+{
+  FILE * file;
+  guint32 timescale;
+
+  guint32 mvhd_pos;
+  guint32 mvhd_size;
+  guint32 prefix_size; /* prefix + ftyp total size */
+
+  gint num_traks;
+  TrakRecovData *traks_rd;
+} MoovRecovFile;
+
+gboolean atoms_recov_write_trak_info      (FILE * f, AtomTRAK * trak);
+gboolean atoms_recov_write_headers        (FILE * f, AtomFTYP * ftyp,
+                                           GstBuffer * prefix, AtomMOOV * moov,
+                                           guint32 timescale,
+                                           guint32 traks_number);
+gboolean atoms_recov_write_trak_samples   (FILE * f, AtomTRAK * trak,
+                                           guint32 nsamples, guint32 delta,
+                                           guint32 size, guint64 chunk_offset,
+                                           gboolean sync, gboolean do_pts,
+                                           gint64 pts_offset);
+
+MdatRecovFile * mdat_recov_file_create   (FILE * file, gboolean datafile,
+                                          GError ** err);
+void            mdat_recov_file_free     (MdatRecovFile * mrf);
+MoovRecovFile * moov_recov_file_create   (FILE * file, GError ** err);
+void            moov_recov_file_free     (MoovRecovFile * moovrf);
+gboolean        moov_recov_parse_buffers (MoovRecovFile * moovrf,
+                                          MdatRecovFile * mdatrf,
+                                          GError ** err);
+gboolean        moov_recov_write_file    (MoovRecovFile * moovrf,
+                                          MdatRecovFile * mdatrf, FILE * outf,
+                                          GError ** err, GError ** warn);
+
+#endif /* __ATOMS_RECOVERY_H__ */
diff --git a/gst/isomp4/descriptors.c b/gst/isomp4/descriptors.c
new file mode 100644
index 0000000..713ffdc
--- /dev/null
+++ b/gst/isomp4/descriptors.c
@@ -0,0 +1,457 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "descriptors.h"
+
+/*
+ * Some mp4 structures (descriptors) use a coding scheme for
+ * representing its size.
+ * It is grouped in bytes. The 1st bit set to 1 means we need another byte,
+ * 0 otherwise. The remaining 7 bits are the useful values.
+ *
+ * The next set of functions handle those values
+ */
+
+/*
+ * Gets an unsigned integer and packs it into a 'expandable size' format
+ * (as used by mp4 descriptors)
+ * @size: the integer to be parsed
+ * @ptr: the array to place the result
+ * @array_size: the size of ptr array
+ */
+static void
+expandable_size_parse (guint64 size, guint8 * ptr, guint32 array_size)
+{
+  int index = 0;
+
+  memset (ptr, 0, sizeof (array_size));
+  while (size > 0 && index < array_size) {
+    ptr[index++] = (size > 0x7F ? 0x80 : 0x0) | (size & 0x7F);
+    size = size >> 7;
+  }
+}
+
+/*
+ * Gets how many positions in an array holding an 'expandable size'
+ * are really used
+ *
+ * @ptr: the array with the 'expandable size'
+ * @array_size: the size of ptr array
+ *
+ * Returns: the number of really used positions
+ */
+static guint64
+expandable_size_get_length (guint8 * ptr, guint32 array_size)
+{
+  gboolean next = TRUE;
+  guint32 index = 0;
+
+  while (next && index < array_size) {
+    next = (ptr[index] & 0x80);
+    index++;
+  }
+  return index;
+}
+
+/*
+ * Initializers below
+ */
+
+static void
+desc_base_descriptor_init (BaseDescriptor * bd, guint8 tag, guint32 size)
+{
+  bd->tag = tag;
+  expandable_size_parse (size, bd->size, 4);
+}
+
+static void
+desc_dec_specific_info_init (DecoderSpecificInfoDescriptor * dsid)
+{
+  desc_base_descriptor_init (&dsid->base, DECODER_SPECIFIC_INFO_TAG, 0);
+  dsid->length = 0;
+  dsid->data = NULL;
+}
+
+DecoderSpecificInfoDescriptor *
+desc_dec_specific_info_new (void)
+{
+  DecoderSpecificInfoDescriptor *desc =
+      g_new0 (DecoderSpecificInfoDescriptor, 1);
+  desc_dec_specific_info_init (desc);
+  return desc;
+}
+
+static void
+desc_dec_conf_desc_init (DecoderConfigDescriptor * dcd)
+{
+  desc_base_descriptor_init (&dcd->base, DECODER_CONFIG_DESC_TAG, 0);
+  dcd->dec_specific_info = NULL;
+}
+
+static void
+desc_sl_conf_desc_init (SLConfigDescriptor * sl)
+{
+  desc_base_descriptor_init (&sl->base, SL_CONFIG_DESC_TAG, 0);
+  sl->predefined = 0x2;
+}
+
+void
+desc_es_init (ESDescriptor * es)
+{
+  desc_base_descriptor_init (&es->base, ES_DESCRIPTOR_TAG, 0);
+
+  es->id = 0;
+  es->flags = 0;
+  es->depends_on_es_id = 0;
+  es->ocr_es_id = 0;
+  es->url_length = 0;
+  es->url_string = NULL;
+
+  desc_dec_conf_desc_init (&es->dec_conf_desc);
+  desc_sl_conf_desc_init (&es->sl_conf_desc);
+}
+
+ESDescriptor *
+desc_es_descriptor_new (void)
+{
+  ESDescriptor *es = g_new0 (ESDescriptor, 1);
+
+  desc_es_init (es);
+  return es;
+}
+
+/*
+ * Deinitializers/Destructors below
+ */
+
+static void
+desc_base_descriptor_clear (BaseDescriptor * base)
+{
+}
+
+void
+desc_dec_specific_info_free (DecoderSpecificInfoDescriptor * dsid)
+{
+  desc_base_descriptor_clear (&dsid->base);
+  if (dsid->data) {
+    g_free (dsid->data);
+    dsid->data = NULL;
+  }
+  g_free (dsid);
+}
+
+static void
+desc_dec_conf_desc_clear (DecoderConfigDescriptor * dec)
+{
+  desc_base_descriptor_clear (&dec->base);
+  if (dec->dec_specific_info) {
+    desc_dec_specific_info_free (dec->dec_specific_info);
+  }
+}
+
+static void
+desc_sl_config_descriptor_clear (SLConfigDescriptor * sl)
+{
+  desc_base_descriptor_clear (&sl->base);
+}
+
+void
+desc_es_descriptor_clear (ESDescriptor * es)
+{
+  desc_base_descriptor_clear (&es->base);
+  if (es->url_string) {
+    g_free (es->url_string);
+    es->url_string = NULL;
+  }
+  desc_dec_conf_desc_clear (&es->dec_conf_desc);
+  desc_sl_config_descriptor_clear (&es->sl_conf_desc);
+}
+
+/*
+ * Size handling functions below
+ */
+
+void
+desc_dec_specific_info_alloc_data (DecoderSpecificInfoDescriptor * dsid,
+    guint32 size)
+{
+  if (dsid->data) {
+    g_free (dsid->data);
+  }
+  dsid->data = g_new0 (guint8, size);
+  dsid->length = size;
+}
+
+static void
+desc_base_descriptor_set_size (BaseDescriptor * bd, guint32 size)
+{
+  expandable_size_parse (size, bd->size, 4);
+}
+
+static guint64
+desc_base_descriptor_get_size (BaseDescriptor * bd)
+{
+  guint64 size = 0;
+
+  size += sizeof (guint8);
+  size += expandable_size_get_length (bd->size, 4) * sizeof (guint8);
+  return size;
+}
+
+static guint64
+desc_sl_config_descriptor_get_size (SLConfigDescriptor * sl_desc)
+{
+  guint64 size = 0;
+  guint64 extra_size = 0;
+
+  size += desc_base_descriptor_get_size (&sl_desc->base);
+  /* predefined */
+  extra_size += sizeof (guint8);
+
+  desc_base_descriptor_set_size (&sl_desc->base, extra_size);
+
+  return size + extra_size;
+}
+
+static guint64
+desc_dec_specific_info_get_size (DecoderSpecificInfoDescriptor * dsid)
+{
+  guint64 size = 0;
+  guint64 extra_size = 0;
+
+  size += desc_base_descriptor_get_size (&dsid->base);
+  extra_size += sizeof (guint8) * dsid->length;
+  desc_base_descriptor_set_size (&dsid->base, extra_size);
+  return size + extra_size;
+}
+
+static guint64
+desc_dec_config_descriptor_get_size (DecoderConfigDescriptor * dec_desc)
+{
+  guint64 size = 0;
+  guint64 extra_size = 0;
+
+  size += desc_base_descriptor_get_size (&dec_desc->base);
+  /* object type */
+  extra_size += sizeof (guint8);
+  /* stream type */
+  extra_size += sizeof (guint8);
+  /* buffer size */
+  extra_size += sizeof (guint8) * 3;
+  /* max bitrate */
+  extra_size += sizeof (guint32);
+  /* avg bitrate */
+  extra_size += sizeof (guint32);
+  if (dec_desc->dec_specific_info) {
+    extra_size += desc_dec_specific_info_get_size (dec_desc->dec_specific_info);
+  }
+
+  desc_base_descriptor_set_size (&dec_desc->base, extra_size);
+  return size + extra_size;
+}
+
+static guint64
+desc_es_descriptor_get_size (ESDescriptor * es)
+{
+  guint64 size = 0;
+  guint64 extra_size = 0;
+
+  size += desc_base_descriptor_get_size (&es->base);
+  /* id */
+  extra_size += sizeof (guint16);
+  /* flags */
+  extra_size += sizeof (guint8);
+  /* depends_on_es_id */
+  if (es->flags & 0x80) {
+    extra_size += sizeof (guint16);
+  }
+  if (es->flags & 0x40) {
+    /* url_length */
+    extra_size += sizeof (guint8);
+    /* url */
+    extra_size += sizeof (gchar) * es->url_length;
+  }
+  if (es->flags & 0x20) {
+    /* ocr_es_id */
+    extra_size += sizeof (guint16);
+  }
+
+  extra_size += desc_dec_config_descriptor_get_size (&es->dec_conf_desc);
+  extra_size += desc_sl_config_descriptor_get_size (&es->sl_conf_desc);
+
+  desc_base_descriptor_set_size (&es->base, extra_size);
+
+  return size + extra_size;
+}
+
+static gboolean
+desc_es_descriptor_check_stream_dependency (ESDescriptor * es)
+{
+  return es->flags & 0x80;
+}
+
+static gboolean
+desc_es_descriptor_check_url_flag (ESDescriptor * es)
+{
+  return es->flags & 0x40;
+}
+
+static gboolean
+desc_es_descriptor_check_ocr (ESDescriptor * es)
+{
+  return es->flags & 0x20;
+}
+
+/* Copy/Serializations Functions below */
+
+static guint64
+desc_base_descriptor_copy_data (BaseDescriptor * desc, guint8 ** buffer,
+    guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  prop_copy_uint8 (desc->tag, buffer, size, offset);
+  prop_copy_uint8_array (desc->size, expandable_size_get_length (desc->size, 4),
+      buffer, size, offset);
+  return original_offset - *offset;
+}
+
+static guint64
+desc_sl_config_descriptor_copy_data (SLConfigDescriptor * desc,
+    guint8 ** buffer, guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!desc_base_descriptor_copy_data (&desc->base, buffer, size, offset)) {
+    return 0;
+  }
+  /* predefined attribute */
+  prop_copy_uint8 (desc->predefined, buffer, size, offset);
+
+  return *offset - original_offset;
+}
+
+static guint64
+desc_dec_specific_info_copy_data (DecoderSpecificInfoDescriptor * desc,
+    guint8 ** buffer, guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!desc_base_descriptor_copy_data (&desc->base, buffer, size, offset)) {
+    return 0;
+  }
+  prop_copy_uint8_array (desc->data, desc->length, buffer, size, offset);
+
+  return *offset - original_offset;
+}
+
+static guint64
+desc_dec_config_descriptor_copy_data (DecoderConfigDescriptor * desc,
+    guint8 ** buffer, guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!desc_base_descriptor_copy_data (&desc->base, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint8 (desc->object_type, buffer, size, offset);
+
+  prop_copy_uint8 (desc->stream_type, buffer, size, offset);
+  prop_copy_uint8_array (desc->buffer_size_DB, 3, buffer, size, offset);
+
+  prop_copy_uint32 (desc->max_bitrate, buffer, size, offset);
+  prop_copy_uint32 (desc->avg_bitrate, buffer, size, offset);
+
+  if (desc->dec_specific_info) {
+    if (!desc_dec_specific_info_copy_data (desc->dec_specific_info, buffer,
+            size, offset)) {
+      return 0;
+    }
+  }
+
+  return *offset - original_offset;
+}
+
+guint64
+desc_es_descriptor_copy_data (ESDescriptor * desc, guint8 ** buffer,
+    guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  /* must call this twice to have size fields of all contained descriptors set
+   * correctly, and to have the size of the size fields taken into account */
+  desc_es_descriptor_get_size (desc);
+  desc_es_descriptor_get_size (desc);
+
+  if (!desc_base_descriptor_copy_data (&desc->base, buffer, size, offset)) {
+    return 0;
+  }
+  /* id and flags */
+  prop_copy_uint16 (desc->id, buffer, size, offset);
+  prop_copy_uint8 (desc->flags, buffer, size, offset);
+
+  if (desc_es_descriptor_check_stream_dependency (desc)) {
+    prop_copy_uint16 (desc->depends_on_es_id, buffer, size, offset);
+  }
+
+  if (desc_es_descriptor_check_url_flag (desc)) {
+    prop_copy_size_string (desc->url_string, desc->url_length, buffer, size,
+        offset);
+  }
+
+  if (desc_es_descriptor_check_ocr (desc)) {
+    prop_copy_uint16 (desc->ocr_es_id, buffer, size, offset);
+  }
+
+  if (!desc_dec_config_descriptor_copy_data (&desc->dec_conf_desc, buffer, size,
+          offset)) {
+    return 0;
+  }
+
+  if (!desc_sl_config_descriptor_copy_data (&desc->sl_conf_desc, buffer, size,
+          offset)) {
+    return 0;
+  }
+
+  return *offset - original_offset;
+}
diff --git a/gst/isomp4/descriptors.h b/gst/isomp4/descriptors.h
new file mode 100644
index 0000000..b472523
--- /dev/null
+++ b/gst/isomp4/descriptors.h
@@ -0,0 +1,151 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __DESCRIPTORS_H__
+#define __DESCRIPTORS_H__
+
+#include <glib.h>
+#include <string.h>
+#include "properties.h"
+
+/*
+ * Tags for descriptor (each kind is represented by a number, instead of fourcc as in atoms)
+ */
+#define OBJECT_DESC_TAG            0x01
+#define INIT_OBJECT_DESC_TAG       0x02
+#define ES_DESCRIPTOR_TAG          0x03
+#define DECODER_CONFIG_DESC_TAG    0x04
+#define DECODER_SPECIFIC_INFO_TAG  0x05
+#define SL_CONFIG_DESC_TAG         0x06
+#define ES_ID_INC_TAG              0x0E
+#define MP4_INIT_OBJECT_DESC_TAG   0x10
+
+#define ESDS_OBJECT_TYPE_MPEG1_P3       0x6B
+#define ESDS_OBJECT_TYPE_MPEG2_P7_MAIN  0x66
+#define ESDS_OBJECT_TYPE_MPEG4_P7_LC    0x67
+#define ESDS_OBJECT_TYPE_MPEG4_P7_SSR   0x68
+#define ESDS_OBJECT_TYPE_MPEG4_P2       0x20
+#define ESDS_OBJECT_TYPE_MPEG4_P3       0x40
+
+#define ESDS_STREAM_TYPE_VISUAL         0x04
+#define ESDS_STREAM_TYPE_AUDIO          0x05
+
+
+typedef struct _BaseDescriptor
+{
+  guint8 tag;
+  /* the first bit of each byte indicates if the next byte should be used */
+  guint8 size[4];
+} BaseDescriptor;
+
+typedef struct _SLConfigDescriptor
+{
+  BaseDescriptor base;
+
+  guint8 predefined;              /* everything is supposed predefined */
+} SLConfigDescriptor;
+
+typedef struct _DecoderSpecificInfoDescriptor
+{
+  BaseDescriptor base;
+  guint32 length;
+  guint8 *data;
+} DecoderSpecificInfoDescriptor;
+
+typedef struct _DecoderConfigDescriptor {
+  BaseDescriptor base;
+
+  guint8 object_type;
+
+  /* following are condensed into streamType:
+   * bit(6) streamType;
+   * bit(1) upStream;
+   * const bit(1) reserved=1;
+  */
+  guint8 stream_type;
+
+  guint8 buffer_size_DB[3];
+  guint32 max_bitrate;
+  guint32 avg_bitrate;
+
+  DecoderSpecificInfoDescriptor *dec_specific_info;
+} DecoderConfigDescriptor;
+
+typedef struct _ESDescriptor
+{
+  BaseDescriptor base;
+
+  guint16 id;
+
+  /* flags contains the following:
+   * bit(1) streamDependenceFlag;
+   * bit(1) URL_Flag;
+   * bit(1) OCRstreamFlag;
+   * bit(5) streamPriority;
+   */
+  guint8 flags;
+
+  guint16 depends_on_es_id;
+  guint8 url_length;              /* only if URL_flag is set */
+  guint8 *url_string;             /* size is url_length */
+
+  guint16 ocr_es_id;              /* only if OCRstreamFlag is set */
+
+  DecoderConfigDescriptor dec_conf_desc;
+  SLConfigDescriptor sl_conf_desc;
+
+  /* optional remainder of ESDescriptor is not used */
+} ESDescriptor;
+
+/* --- FUNCTIONS --- */
+void    desc_es_init                               (ESDescriptor *es);
+ESDescriptor *desc_es_descriptor_new               (void);
+guint64 desc_es_descriptor_copy_data               (ESDescriptor *es, guint8 **buffer,
+                                                    guint64 *size, guint64 *offset);
+void    desc_es_descriptor_clear                   (ESDescriptor *es);
+
+DecoderSpecificInfoDescriptor *desc_dec_specific_info_new(void);
+void    desc_dec_specific_info_free                (DecoderSpecificInfoDescriptor *dsid);
+void    desc_dec_specific_info_alloc_data          (DecoderSpecificInfoDescriptor *dsid,
+                                                    guint32 size);
+
+#endif /* __DESCRIPTORS_H__ */
diff --git a/gst/isomp4/fourcc.h b/gst/isomp4/fourcc.h
new file mode 100644
index 0000000..be5c7c0
--- /dev/null
+++ b/gst/isomp4/fourcc.h
@@ -0,0 +1,384 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+ /*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#ifndef __FOURCC_H__
+#define __FOURCC_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define FOURCC_null     0x0
+
+#define FOURCC_2vuy     GST_MAKE_FOURCC('2','v','u','y')
+#define FOURCC_FMP4     GST_MAKE_FOURCC('F','M','P','4')
+#define FOURCC_H264     GST_MAKE_FOURCC('H','2','6','4')
+#define FOURCC_H265     GST_MAKE_FOURCC('H','2','6','5')
+#define FOURCC_MAC3     GST_MAKE_FOURCC('M','A','C','3')
+#define FOURCC_MAC6     GST_MAKE_FOURCC('M','A','C','6')
+#define FOURCC_MP4V     GST_MAKE_FOURCC('M','P','4','V')
+#define FOURCC_PICT     GST_MAKE_FOURCC('P','I','C','T')
+#define FOURCC_QDM2     GST_MAKE_FOURCC('Q','D','M','2')
+#define FOURCC_SVQ3     GST_MAKE_FOURCC('S','V','Q','3')
+#define FOURCC_VP31     GST_MAKE_FOURCC('V','P','3','1')
+#define FOURCC_VP80     GST_MAKE_FOURCC('V','P','8','0')
+#define FOURCC_WRLE     GST_MAKE_FOURCC('W','R','L','E')
+#define FOURCC_XMP_     GST_MAKE_FOURCC('X','M','P','_')
+#define FOURCC_XVID     GST_MAKE_FOURCC('X','V','I','D')
+#define FOURCC__ART     GST_MAKE_FOURCC(0xa9,'A','R','T')
+#define FOURCC_____     GST_MAKE_FOURCC('-','-','-','-')
+#define FOURCC___in     GST_MAKE_FOURCC(' ',' ','i','n')
+#define FOURCC___ty     GST_MAKE_FOURCC(' ',' ','t','y')
+#define FOURCC__alb     GST_MAKE_FOURCC(0xa9,'a','l','b')
+#define FOURCC__cpy     GST_MAKE_FOURCC(0xa9,'c','p','y')
+#define FOURCC__day     GST_MAKE_FOURCC(0xa9,'d','a','y')
+#define FOURCC__des     GST_MAKE_FOURCC(0xa9,'d','e','s')
+#define FOURCC__enc     GST_MAKE_FOURCC(0xa9,'e','n','c')
+#define FOURCC__gen     GST_MAKE_FOURCC(0xa9, 'g', 'e', 'n')
+#define FOURCC__grp     GST_MAKE_FOURCC(0xa9,'g','r','p')
+#define FOURCC__inf     GST_MAKE_FOURCC(0xa9,'i','n','f')
+#define FOURCC__lyr     GST_MAKE_FOURCC(0xa9,'l','y','r')
+#define FOURCC__mp3     GST_MAKE_FOURCC('.','m','p','3')
+#define FOURCC__nam     GST_MAKE_FOURCC(0xa9,'n','a','m')
+#define FOURCC__req     GST_MAKE_FOURCC(0xa9,'r','e','q')
+#define FOURCC__too     GST_MAKE_FOURCC(0xa9,'t','o','o')
+#define FOURCC__wrt     GST_MAKE_FOURCC(0xa9,'w','r','t')
+#define FOURCC_aART     GST_MAKE_FOURCC('a','A','R','T')
+#define FOURCC_ac_3     GST_MAKE_FOURCC('a','c','-','3')
+#define FOURCC_agsm     GST_MAKE_FOURCC('a','g','s','m')
+#define FOURCC_alac     GST_MAKE_FOURCC('a','l','a','c')
+#define FOURCC_fLaC     GST_MAKE_FOURCC('f','L','a','C')
+#define FOURCC_dfLa     GST_MAKE_FOURCC('d','f','L','a')
+#define FOURCC_alaw     GST_MAKE_FOURCC('a','l','a','w')
+#define FOURCC_alis     GST_MAKE_FOURCC('a','l','i','s')
+#define FOURCC_appl     GST_MAKE_FOURCC('a','p','p','l')
+#define FOURCC_avc1     GST_MAKE_FOURCC('a','v','c','1')
+#define FOURCC_avc3     GST_MAKE_FOURCC('a','v','c','3')
+#define FOURCC_avcC     GST_MAKE_FOURCC('a','v','c','C')
+#define FOURCC_clip     GST_MAKE_FOURCC('c','l','i','p')
+#define FOURCC_cmov     GST_MAKE_FOURCC('c','m','o','v')
+#define FOURCC_cmvd     GST_MAKE_FOURCC('c','m','v','d')
+#define FOURCC_co64     GST_MAKE_FOURCC('c','o','6','4')
+#define FOURCC_covr     GST_MAKE_FOURCC('c','o','v','r')
+#define FOURCC_cpil     GST_MAKE_FOURCC('c','p','i','l')
+#define FOURCC_cprt     GST_MAKE_FOURCC('c','p','r','t')
+#define FOURCC_crgn     GST_MAKE_FOURCC('c','r','g','n')
+#define FOURCC_ctab     GST_MAKE_FOURCC('c','t','a','b')
+#define FOURCC_ctts     GST_MAKE_FOURCC('c','t','t','s')
+#define FOURCC_cslg     GST_MAKE_FOURCC('c','s','l','g')
+#define FOURCC_d263     GST_MAKE_FOURCC('d','2','6','3')
+#define FOURCC_dac3     GST_MAKE_FOURCC('d','a','c','3')
+#define FOURCC_damr     GST_MAKE_FOURCC('d','a','m','r')
+#define FOURCC_data     GST_MAKE_FOURCC('d','a','t','a')
+#define FOURCC_dcom     GST_MAKE_FOURCC('d','c','o','m')
+#define FOURCC_desc     GST_MAKE_FOURCC('d','e','s','c')
+#define FOURCC_dhlr     GST_MAKE_FOURCC('d','h','l','r')
+#define FOURCC_dinf     GST_MAKE_FOURCC('d','i','n','f')
+#define FOURCC_disc     GST_MAKE_FOURCC('d','i','s','c')
+#define FOURCC_disk     GST_MAKE_FOURCC('d','i','s','k')
+#define FOURCC_drac     GST_MAKE_FOURCC('d','r','a','c')
+#define FOURCC_dref     GST_MAKE_FOURCC('d','r','e','f')
+#define FOURCC_drmi     GST_MAKE_FOURCC('d','r','m','i')
+#define FOURCC_drms     GST_MAKE_FOURCC('d','r','m','s')
+#define FOURCC_dvcp     GST_MAKE_FOURCC('d','v','c','p')
+#define FOURCC_dvc_     GST_MAKE_FOURCC('d','v','c',' ')
+#define FOURCC_dv5p     GST_MAKE_FOURCC('d','v','5','p')
+#define FOURCC_dv5n     GST_MAKE_FOURCC('d','v','5','n')
+#define FOURCC_edts     GST_MAKE_FOURCC('e','d','t','s')
+#define FOURCC_elst     GST_MAKE_FOURCC('e','l','s','t')
+#define FOURCC_enda     GST_MAKE_FOURCC('e','n','d','a')
+#define FOURCC_esds     GST_MAKE_FOURCC('e','s','d','s')
+#define FOURCC_fmp4     GST_MAKE_FOURCC('f','m','p','4')
+#define FOURCC_free     GST_MAKE_FOURCC('f','r','e','e')
+#define FOURCC_frma     GST_MAKE_FOURCC('f','r','m','a')
+#define FOURCC_ftyp     GST_MAKE_FOURCC('f','t','y','p')
+#define FOURCC_ftab     GST_MAKE_FOURCC('f','t','a','b')
+#define FOURCC_gama     GST_MAKE_FOURCC('g','a','m','a')
+#define FOURCC_glbl     GST_MAKE_FOURCC('g','l','b','l')
+#define FOURCC_gmhd     GST_MAKE_FOURCC('g','m','h','d')
+#define FOURCC_gmin     GST_MAKE_FOURCC('g','m','i','n')
+#define FOURCC_gnre     GST_MAKE_FOURCC('g','n','r','e')
+#define FOURCC_h263     GST_MAKE_FOURCC('h','2','6','3')
+#define FOURCC_hdlr     GST_MAKE_FOURCC('h','d','l','r')
+#define FOURCC_hev1     GST_MAKE_FOURCC('h','e','v','1')
+#define FOURCC_hint     GST_MAKE_FOURCC('h','i','n','t')
+#define FOURCC_hmhd     GST_MAKE_FOURCC('h','m','h','d')
+#define FOURCC_hndl     GST_MAKE_FOURCC('h','n','d','l')
+#define FOURCC_hnti     GST_MAKE_FOURCC('h','n','t','i')
+#define FOURCC_hvc1     GST_MAKE_FOURCC('h','v','c','1')
+#define FOURCC_hvcC     GST_MAKE_FOURCC('h','v','c','C')
+#define FOURCC_ilst     GST_MAKE_FOURCC('i','l','s','t')
+#define FOURCC_ima4     GST_MAKE_FOURCC('i','m','a','4')
+#define FOURCC_imap     GST_MAKE_FOURCC('i','m','a','p')
+#define FOURCC_in24     GST_MAKE_FOURCC('i','n','2','4')
+#define FOURCC_jp2c     GST_MAKE_FOURCC('j','p','2','c')
+#define FOURCC_jpeg     GST_MAKE_FOURCC('j','p','e','g')
+#define FOURCC_keyw     GST_MAKE_FOURCC('k','e','y','w')
+#define FOURCC_kmat     GST_MAKE_FOURCC('k','m','a','t')
+#define FOURCC_kywd     GST_MAKE_FOURCC('k','y','w','d')
+#define FOURCC_load     GST_MAKE_FOURCC('l','o','a','d')
+#define FOURCC_matt     GST_MAKE_FOURCC('m','a','t','t')
+#define FOURCC_mdat     GST_MAKE_FOURCC('m','d','a','t')
+#define FOURCC_mdhd     GST_MAKE_FOURCC('m','d','h','d')
+#define FOURCC_mdia     GST_MAKE_FOURCC('m','d','i','a')
+#define FOURCC_mdir     GST_MAKE_FOURCC('m','d','i','r')
+#define FOURCC_mean     GST_MAKE_FOURCC('m','e','a','n')
+#define FOURCC_meta     GST_MAKE_FOURCC('m','e','t','a')
+#define FOURCC_mhlr     GST_MAKE_FOURCC('m','h','l','r')
+#define FOURCC_minf     GST_MAKE_FOURCC('m','i','n','f')
+#define FOURCC_moov     GST_MAKE_FOURCC('m','o','o','v')
+#define FOURCC_mp4a     GST_MAKE_FOURCC('m','p','4','a')
+#define FOURCC_mp4s     GST_MAKE_FOURCC('m','p','4','s')
+#define FOURCC_mp4s     GST_MAKE_FOURCC('m','p','4','s')
+#define FOURCC_mp4v     GST_MAKE_FOURCC('m','p','4','v')
+#define FOURCC_name     GST_MAKE_FOURCC('n','a','m','e')
+#define FOURCC_nclc     GST_MAKE_FOURCC('n','c','l','c')
+#define FOURCC_nclx     GST_MAKE_FOURCC('n','c','l','x')
+#define FOURCC_opus     GST_MAKE_FOURCC('O','p','u','s')
+#define FOURCC_dops     GST_MAKE_FOURCC('d','O','p','s')
+#define FOURCC_pasp     GST_MAKE_FOURCC('p','a','s','p')
+#define FOURCC_colr     GST_MAKE_FOURCC('c','o','l','r')
+#define FOURCC_clap     GST_MAKE_FOURCC('c','l','a','p')
+#define FOURCC_tapt     GST_MAKE_FOURCC('t','a','p','t')
+#define FOURCC_clef     GST_MAKE_FOURCC('c','l','e','f')
+#define FOURCC_prof     GST_MAKE_FOURCC('p','r','o','f')
+#define FOURCC_enof     GST_MAKE_FOURCC('e','n','o','f')
+#define FOURCC_fiel     GST_MAKE_FOURCC('f','i','e','l')
+#define FOURCC_pcst     GST_MAKE_FOURCC('p','c','s','t')
+#define FOURCC_pgap     GST_MAKE_FOURCC('p','g','a','p')
+#define FOURCC_png      GST_MAKE_FOURCC('p','n','g',' ')
+#define FOURCC_pnot     GST_MAKE_FOURCC('p','n','o','t')
+#define FOURCC_qt__     GST_MAKE_FOURCC('q','t',' ',' ')
+#define FOURCC_qtim     GST_MAKE_FOURCC('q','t','i','m')
+#define FOURCC_raw_     GST_MAKE_FOURCC('r','a','w',' ')
+#define FOURCC_rdrf     GST_MAKE_FOURCC('r','d','r','f')
+#define FOURCC_rle_     GST_MAKE_FOURCC('r','l','e',' ')
+#define FOURCC_rmda     GST_MAKE_FOURCC('r','m','d','a')
+#define FOURCC_rmdr     GST_MAKE_FOURCC('r','m','d','r')
+#define FOURCC_rmra     GST_MAKE_FOURCC('r','m','r','a')
+#define FOURCC_rmvc     GST_MAKE_FOURCC('r','m','v','c')
+#define FOURCC_rtp_     GST_MAKE_FOURCC('r','t','p',' ')
+#define FOURCC_rtsp     GST_MAKE_FOURCC('r','t','s','p')
+#define FOURCC_s263     GST_MAKE_FOURCC('s','2','6','3')
+#define FOURCC_samr     GST_MAKE_FOURCC('s','a','m','r')
+#define FOURCC_sawb     GST_MAKE_FOURCC('s','a','w','b')
+#define FOURCC_sbtl     GST_MAKE_FOURCC('s','b','t','l')
+#define FOURCC_sdp_     GST_MAKE_FOURCC('s','d','p',' ')
+#define FOURCC_sidx     GST_MAKE_FOURCC('s','i','d','x')
+#define FOURCC_skip     GST_MAKE_FOURCC('s','k','i','p')
+#define FOURCC_smhd     GST_MAKE_FOURCC('s','m','h','d')
+#define FOURCC_soaa     GST_MAKE_FOURCC('s','o','a','a')
+#define FOURCC_soal     GST_MAKE_FOURCC('s','o','a','l')
+#define FOURCC_soar     GST_MAKE_FOURCC('s','o','a','r')
+#define FOURCC_soco     GST_MAKE_FOURCC('s','o','c','o')
+#define FOURCC_sonm     GST_MAKE_FOURCC('s','o','n','m')
+#define FOURCC_sosn     GST_MAKE_FOURCC('s','o','s','n')
+#define FOURCC_soun     GST_MAKE_FOURCC('s','o','u','n')
+#define FOURCC_sowt     GST_MAKE_FOURCC('s','o','w','t')
+#define FOURCC_stbl     GST_MAKE_FOURCC('s','t','b','l')
+#define FOURCC_stco     GST_MAKE_FOURCC('s','t','c','o')
+#define FOURCC_stpp     GST_MAKE_FOURCC('s','t','p','p')
+#define FOURCC_stps     GST_MAKE_FOURCC('s','t','p','s')
+#define FOURCC_strf     GST_MAKE_FOURCC('s','t','r','f')
+#define FOURCC_strm     GST_MAKE_FOURCC('s','t','r','m')
+#define FOURCC_stsc     GST_MAKE_FOURCC('s','t','s','c')
+#define FOURCC_stsd     GST_MAKE_FOURCC('s','t','s','d')
+#define FOURCC_stss     GST_MAKE_FOURCC('s','t','s','s')
+#define FOURCC_stsz     GST_MAKE_FOURCC('s','t','s','z')
+#define FOURCC_stts     GST_MAKE_FOURCC('s','t','t','s')
+#define FOURCC_styp     GST_MAKE_FOURCC('s','t','y','p')
+#define FOURCC_subp     GST_MAKE_FOURCC('s','u','b','p')
+#define FOURCC_subt     GST_MAKE_FOURCC('s','u','b','t')
+#define FOURCC_text     GST_MAKE_FOURCC('t','e','x','t')
+#define FOURCC_tcmi     GST_MAKE_FOURCC('t','c','m','i')
+#define FOURCC_tkhd     GST_MAKE_FOURCC('t','k','h','d')
+#define FOURCC_tmcd     GST_MAKE_FOURCC('t','m','c','d')
+#define FOURCC_tmpo     GST_MAKE_FOURCC('t','m','p','o')
+#define FOURCC_trak     GST_MAKE_FOURCC('t','r','a','k')
+#define FOURCC_tref     GST_MAKE_FOURCC('t','r','e','f')
+#define FOURCC_trkn     GST_MAKE_FOURCC('t','r','k','n')
+#define FOURCC_tven     GST_MAKE_FOURCC('t','v','e','n')
+#define FOURCC_tves     GST_MAKE_FOURCC('t','v','e','s')
+#define FOURCC_tvsh     GST_MAKE_FOURCC('t','v','s','h')
+#define FOURCC_tvsn     GST_MAKE_FOURCC('t','v','s','n')
+#define FOURCC_twos     GST_MAKE_FOURCC('t','w','o','s')
+#define FOURCC_tx3g     GST_MAKE_FOURCC('t','x','3','g')
+#define FOURCC_udta     GST_MAKE_FOURCC('u','d','t','a')
+#define FOURCC_ulaw     GST_MAKE_FOURCC('u','l','a','w')
+#define FOURCC_url_     GST_MAKE_FOURCC('u','r','l',' ')
+#define FOURCC_uuid     GST_MAKE_FOURCC('u','u','i','d')
+#define FOURCC_v210     GST_MAKE_FOURCC('v','2','1','0')
+#define FOURCC_vc_1     GST_MAKE_FOURCC('v','c','-','1')
+#define FOURCC_vide     GST_MAKE_FOURCC('v','i','d','e')
+#define FOURCC_vmhd     GST_MAKE_FOURCC('v','m','h','d')
+#define FOURCC_vp08     GST_MAKE_FOURCC('v','p','0','8')
+#define FOURCC_vp09     GST_MAKE_FOURCC('v','p','0','9')
+#define FOURCC_xvid     GST_MAKE_FOURCC('x','v','i','d')
+#define FOURCC_wave     GST_MAKE_FOURCC('w','a','v','e')
+#define FOURCC_wide     GST_MAKE_FOURCC('w','i','d','e')
+#define FOURCC_zlib     GST_MAKE_FOURCC('z','l','i','b')
+#define FOURCC_lpcm     GST_MAKE_FOURCC('l','p','c','m')
+
+#define FOURCC_cfhd     GST_MAKE_FOURCC('C','F','H','D')
+#define FOURCC_ap4x     GST_MAKE_FOURCC('a','p','4','x')
+#define FOURCC_ap4h     GST_MAKE_FOURCC('a','p','4','h')
+#define FOURCC_apch     GST_MAKE_FOURCC('a','p','c','h')
+#define FOURCC_apcn     GST_MAKE_FOURCC('a','p','c','n')
+#define FOURCC_apco     GST_MAKE_FOURCC('a','p','c','o')
+#define FOURCC_apcs     GST_MAKE_FOURCC('a','p','c','s')
+#define FOURCC_m1v      GST_MAKE_FOURCC('m','1','v',' ')
+#define FOURCC_vivo     GST_MAKE_FOURCC('v','i','v','o')
+#define FOURCC_saiz     GST_MAKE_FOURCC('s','a','i','z')
+#define FOURCC_saio     GST_MAKE_FOURCC('s','a','i','o')
+
+#define FOURCC_3gg6     GST_MAKE_FOURCC('3','g','g','6')
+#define FOURCC_3gg7     GST_MAKE_FOURCC('3','g','g','7')
+#define FOURCC_3gp4     GST_MAKE_FOURCC('3','g','p','4')
+#define FOURCC_3gp6     GST_MAKE_FOURCC('3','g','p','6')
+#define FOURCC_3gr6     GST_MAKE_FOURCC('3','g','r','6')
+#define FOURCC_3g__     GST_MAKE_FOURCC('3','g',0,0)
+#define FOURCC_isml     GST_MAKE_FOURCC('i','s','m','l')
+#define FOURCC_iso2     GST_MAKE_FOURCC('i','s','o','2')
+#define FOURCC_isom     GST_MAKE_FOURCC('i','s','o','m')
+#define FOURCC_mp41     GST_MAKE_FOURCC('m','p','4','1')
+#define FOURCC_mp42     GST_MAKE_FOURCC('m','p','4','2')
+#define FOURCC_piff     GST_MAKE_FOURCC('p','i','f','f')
+#define FOURCC_titl     GST_MAKE_FOURCC('t','i','t','l')
+
+/* SVQ3 fourcc */
+#define FOURCC_SEQH     GST_MAKE_FOURCC('S','E','Q','H')
+#define FOURCC_SMI_     GST_MAKE_FOURCC('S','M','I',' ')
+
+/* 3gpp asset meta data fourcc */
+#define FOURCC_albm     GST_MAKE_FOURCC('a','l','b','m')
+#define FOURCC_auth     GST_MAKE_FOURCC('a','u','t','h')
+#define FOURCC_clsf     GST_MAKE_FOURCC('c','l','s','f')
+#define FOURCC_dscp     GST_MAKE_FOURCC('d','s','c','p')
+#define FOURCC_loci     GST_MAKE_FOURCC('l','o','c','i')
+#define FOURCC_perf     GST_MAKE_FOURCC('p','e','r','f')
+#define FOURCC_rtng     GST_MAKE_FOURCC('r','t','n','g')
+#define FOURCC_yrrc     GST_MAKE_FOURCC('y','r','r','c')
+
+/* misc tag stuff */
+#define FOURCC_ID32     GST_MAKE_FOURCC('I', 'D','3','2')
+
+/* ISO Motion JPEG 2000 fourcc */
+#define FOURCC_cdef     GST_MAKE_FOURCC('c','d','e','f')
+#define FOURCC_cmap     GST_MAKE_FOURCC('c','m','a','p')
+#define FOURCC_ihdr     GST_MAKE_FOURCC('i','h','d','r')
+#define FOURCC_jp2h     GST_MAKE_FOURCC('j','p','2','h')
+#define FOURCC_jp2x     GST_MAKE_FOURCC('j','p','2','x')
+#define FOURCC_mjp2     GST_MAKE_FOURCC('m','j','p','2')
+
+/* some buggy hardware's notion of mdhd */
+#define FOURCC_mhdr     GST_MAKE_FOURCC('m','h','d','r')
+
+/* Fragmented MP4 */
+#define FOURCC_btrt     GST_MAKE_FOURCC('b','t','r','t')
+#define FOURCC_mehd     GST_MAKE_FOURCC('m','e','h','d')
+#define FOURCC_mfhd     GST_MAKE_FOURCC('m','f','h','d')
+#define FOURCC_mfra     GST_MAKE_FOURCC('m','f','r','a')
+#define FOURCC_mfro     GST_MAKE_FOURCC('m','f','r','o')
+#define FOURCC_moof     GST_MAKE_FOURCC('m','o','o','f')
+#define FOURCC_mvex     GST_MAKE_FOURCC('m','v','e','x')
+#define FOURCC_mvhd     GST_MAKE_FOURCC('m','v','h','d')
+#define FOURCC_ovc1     GST_MAKE_FOURCC('o','v','c','1')
+#define FOURCC_owma     GST_MAKE_FOURCC('o','w','m','a')
+#define FOURCC_sdtp     GST_MAKE_FOURCC('s','d','t','p')
+#define FOURCC_tfhd     GST_MAKE_FOURCC('t','f','h','d')
+#define FOURCC_tfra     GST_MAKE_FOURCC('t','f','r','a')
+#define FOURCC_traf     GST_MAKE_FOURCC('t','r','a','f')
+#define FOURCC_trex     GST_MAKE_FOURCC('t','r','e','x')
+#define FOURCC_trun     GST_MAKE_FOURCC('t','r','u','n')
+#define FOURCC_wma_     GST_MAKE_FOURCC('w','m','a',' ')
+
+/* MPEG DASH */
+#define FOURCC_tfdt     GST_MAKE_FOURCC('t','f','d','t')
+
+/* Xiph fourcc */
+#define FOURCC_XdxT     GST_MAKE_FOURCC('X','d','x','T')
+#define FOURCC_XiTh     GST_MAKE_FOURCC('X','i','T','h')
+#define FOURCC_tCtC     GST_MAKE_FOURCC('t','C','t','C')
+#define FOURCC_tCtH     GST_MAKE_FOURCC('t','C','t','H')
+#define FOURCC_tCt_     GST_MAKE_FOURCC('t','C','t','#')
+
+/* ilst metatags */
+#define FOURCC__cmt     GST_MAKE_FOURCC(0xa9, 'c','m','t')
+
+/* apple tags */
+#define FOURCC__mak     GST_MAKE_FOURCC(0xa9, 'm','a','k')
+#define FOURCC__mod     GST_MAKE_FOURCC(0xa9, 'm','o','d')
+#define FOURCC__swr     GST_MAKE_FOURCC(0xa9, 's','w','r')
+
+/* Chapters reference */
+#define FOURCC_chap     GST_MAKE_FOURCC('c','h','a','p')
+
+/* For Microsoft Wave formats embedded in quicktime, the FOURCC is
+   'm', 's', then the 16 bit wave codec id */
+#define MS_WAVE_FOURCC(codecid)  GST_MAKE_FOURCC( \
+        'm', 's', ((codecid)>>8)&0xff, ((codecid)&0xff))
+
+/* MPEG Application Format , Stereo Video */
+#define FOURCC_ss01     GST_MAKE_FOURCC('s','s','0','1')
+#define FOURCC_ss02     GST_MAKE_FOURCC('s','s','0','2')
+#define FOURCC_svmi     GST_MAKE_FOURCC('s','v','m','i')
+#define FOURCC_scdi     GST_MAKE_FOURCC('s','c','d','i')
+
+/* Protected streams */
+#define FOURCC_encv     GST_MAKE_FOURCC('e','n','c','v')
+#define FOURCC_enca     GST_MAKE_FOURCC('e','n','c','a')
+#define FOURCC_enct     GST_MAKE_FOURCC('e','n','c','t')
+#define FOURCC_encs     GST_MAKE_FOURCC('e','n','c','s')
+#define FOURCC_sinf     GST_MAKE_FOURCC('s','i','n','f')
+#define FOURCC_frma     GST_MAKE_FOURCC('f','r','m','a')
+#define FOURCC_schm     GST_MAKE_FOURCC('s','c','h','m')
+#define FOURCC_schi     GST_MAKE_FOURCC('s','c','h','i')
+
+/* Common Encryption */
+#define FOURCC_pssh     GST_MAKE_FOURCC('p','s','s','h')
+#define FOURCC_tenc     GST_MAKE_FOURCC('t','e','n','c')
+#define FOURCC_cenc     GST_MAKE_FOURCC('c','e','n','c')
+
+G_END_DECLS
+
+#endif /* __FOURCC_H__ */
diff --git a/gst/isomp4/gstisoff.c b/gst/isomp4/gstisoff.c
new file mode 100644
index 0000000..829a73a
--- /dev/null
+++ b/gst/isomp4/gstisoff.c
@@ -0,0 +1,203 @@
+/*
+ * ISO File Format parsing library
+ *
+ * gstisoff.h
+ *
+ * Copyright (C) 2015 Samsung Electronics. All rights reserved.
+ *   Author: Thiago Santos <thiagoss@osg.samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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 (COPYING); if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "qtdemux_debug.h"
+#include "gstisoff.h"
+#include <gst/base/gstbytereader.h>
+
+#define GST_CAT_DEFAULT qtdemux_debug
+
+void
+gst_isoff_qt_sidx_parser_init (GstSidxParser * parser)
+{
+  parser->status = GST_ISOFF_QT_SIDX_PARSER_INIT;
+  parser->cumulative_entry_size = 0;
+  parser->sidx.entries = NULL;
+  parser->sidx.entries_count = 0;
+}
+
+void
+gst_isoff_qt_sidx_parser_clear (GstSidxParser * parser)
+{
+  g_free (parser->sidx.entries);
+  parser->sidx.entries = NULL;
+}
+
+static void
+gst_isoff_qt_parse_sidx_entry (GstSidxBoxEntry * entry, GstByteReader * reader)
+{
+  guint32 aux;
+
+  aux = gst_byte_reader_get_uint32_be_unchecked (reader);
+  entry->ref_type = aux >> 31;
+  entry->size = aux & 0x7FFFFFFF;
+  entry->duration = gst_byte_reader_get_uint32_be_unchecked (reader);
+  aux = gst_byte_reader_get_uint32_be_unchecked (reader);
+  entry->starts_with_sap = aux >> 31;
+  entry->sap_type = ((aux >> 28) & 0x7);
+  entry->sap_delta_time = aux & 0xFFFFFFF;
+}
+
+GstIsoffParserResult
+gst_isoff_qt_sidx_parser_add_data (GstSidxParser * parser,
+    const guint8 * buffer, gint length, guint * consumed)
+{
+  GstIsoffParserResult res = GST_ISOFF_QT_PARSER_OK;
+  GstByteReader reader;
+  gsize remaining;
+  guint32 fourcc;
+
+  gst_byte_reader_init (&reader, buffer, length);
+
+  switch (parser->status) {
+    case GST_ISOFF_QT_SIDX_PARSER_INIT:
+      if (gst_byte_reader_get_remaining (&reader) < GST_ISOFF_QT_FULL_BOX_SIZE) {
+        break;
+      }
+
+      parser->size = gst_byte_reader_get_uint32_be_unchecked (&reader);
+      fourcc = gst_byte_reader_get_uint32_le_unchecked (&reader);
+      if (fourcc != GST_ISOFF_QT_FOURCC_SIDX) {
+        res = GST_ISOFF_QT_PARSER_UNEXPECTED;
+        gst_byte_reader_set_pos (&reader, 0);
+        break;
+      }
+      if (parser->size == 1) {
+        if (gst_byte_reader_get_remaining (&reader) < 12) {
+          gst_byte_reader_set_pos (&reader, 0);
+          break;
+        }
+
+        parser->size = gst_byte_reader_get_uint64_be_unchecked (&reader);
+      }
+      if (parser->size == 0) {
+        res = GST_ISOFF_QT_PARSER_ERROR;
+        gst_byte_reader_set_pos (&reader, 0);
+        break;
+      }
+      parser->sidx.version = gst_byte_reader_get_uint8_unchecked (&reader);
+      parser->sidx.flags = gst_byte_reader_get_uint24_le_unchecked (&reader);
+
+      parser->status = GST_ISOFF_QT_SIDX_PARSER_HEADER;
+
+    case GST_ISOFF_QT_SIDX_PARSER_HEADER:
+      remaining = gst_byte_reader_get_remaining (&reader);
+      if (remaining < 12 + (parser->sidx.version == 0 ? 8 : 16)) {
+        break;
+      }
+
+      parser->sidx.ref_id = gst_byte_reader_get_uint32_be_unchecked (&reader);
+      parser->sidx.timescale =
+          gst_byte_reader_get_uint32_be_unchecked (&reader);
+      if (parser->sidx.version == 0) {
+        parser->sidx.earliest_pts =
+            gst_byte_reader_get_uint32_be_unchecked (&reader);
+        parser->sidx.first_offset = parser->sidx.earliest_pts =
+            gst_byte_reader_get_uint32_be_unchecked (&reader);
+      } else {
+        parser->sidx.earliest_pts =
+            gst_byte_reader_get_uint64_be_unchecked (&reader);
+        parser->sidx.first_offset =
+            gst_byte_reader_get_uint64_be_unchecked (&reader);
+      }
+      /* skip 2 reserved bytes */
+      gst_byte_reader_skip_unchecked (&reader, 2);
+      parser->sidx.entries_count =
+          gst_byte_reader_get_uint16_be_unchecked (&reader);
+
+      GST_LOG ("Timescale: %" G_GUINT32_FORMAT, parser->sidx.timescale);
+      GST_LOG ("Earliest pts: %" G_GUINT64_FORMAT, parser->sidx.earliest_pts);
+      GST_LOG ("First offset: %" G_GUINT64_FORMAT, parser->sidx.first_offset);
+
+      parser->cumulative_pts =
+          gst_util_uint64_scale_int_round (parser->sidx.earliest_pts,
+          GST_SECOND, parser->sidx.timescale);
+
+      if (parser->sidx.entries_count) {
+        parser->sidx.entries =
+            g_malloc (sizeof (GstSidxBoxEntry) * parser->sidx.entries_count);
+      }
+      parser->sidx.entry_index = 0;
+
+      parser->status = GST_ISOFF_QT_SIDX_PARSER_DATA;
+
+    case GST_ISOFF_QT_SIDX_PARSER_DATA:
+      while (parser->sidx.entry_index < parser->sidx.entries_count) {
+        GstSidxBoxEntry *entry =
+            &parser->sidx.entries[parser->sidx.entry_index];
+
+        remaining = gst_byte_reader_get_remaining (&reader);
+        if (remaining < 12)
+          break;
+
+        entry->offset = parser->cumulative_entry_size;
+        entry->pts = parser->cumulative_pts;
+        gst_isoff_qt_parse_sidx_entry (entry, &reader);
+        entry->duration = gst_util_uint64_scale_int_round (entry->duration,
+            GST_SECOND, parser->sidx.timescale);
+        parser->cumulative_entry_size += entry->size;
+        parser->cumulative_pts += entry->duration;
+
+        GST_LOG ("Sidx entry %d) offset: %" G_GUINT64_FORMAT ", pts: %"
+            GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT " - size %"
+            G_GUINT32_FORMAT, parser->sidx.entry_index, entry->offset,
+            GST_TIME_ARGS (entry->pts), GST_TIME_ARGS (entry->duration),
+            entry->size);
+
+        parser->sidx.entry_index++;
+      }
+
+      if (parser->sidx.entry_index == parser->sidx.entries_count)
+        parser->status = GST_ISOFF_QT_SIDX_PARSER_FINISHED;
+      else
+        break;
+    case GST_ISOFF_QT_SIDX_PARSER_FINISHED:
+      parser->sidx.entry_index = 0;
+      res = GST_ISOFF_QT_PARSER_DONE;
+      break;
+  }
+
+  *consumed = gst_byte_reader_get_pos (&reader);
+  return res;
+}
+
+GstIsoffParserResult
+gst_isoff_qt_sidx_parser_add_buffer (GstSidxParser * parser, GstBuffer * buffer,
+    guint * consumed)
+{
+  GstIsoffParserResult res = GST_ISOFF_QT_PARSER_OK;
+  GstMapInfo info;
+
+  if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {
+    *consumed = 0;
+    return GST_ISOFF_QT_PARSER_ERROR;
+  }
+
+  res =
+      gst_isoff_qt_sidx_parser_add_data (parser, info.data, info.size,
+      consumed);
+
+  gst_buffer_unmap (buffer, &info);
+  return res;
+}
diff --git a/gst/isomp4/gstisoff.h b/gst/isomp4/gstisoff.h
new file mode 100644
index 0000000..c6fbf33
--- /dev/null
+++ b/gst/isomp4/gstisoff.h
@@ -0,0 +1,100 @@
+/*
+ * ISO File Format parsing library
+ *
+ * gstisoff.h
+ *
+ * Copyright (C) 2015 Samsung Electronics. All rights reserved.
+ *   Author: Thiago Santos <thiagoss@osg.samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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 (COPYING); if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_ISOFF_QT_H__
+#define __GST_ISOFF_QT_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+  GST_ISOFF_QT_PARSER_OK,
+  GST_ISOFF_QT_PARSER_DONE,
+  GST_ISOFF_QT_PARSER_UNEXPECTED,
+  GST_ISOFF_QT_PARSER_ERROR
+} GstIsoffParserResult;
+
+/* this is the minimum size, it can be larger if it
+ * uses extended size or type */
+#define GST_ISOFF_QT_FULL_BOX_SIZE 12
+
+#define GST_ISOFF_QT_FOURCC_SIDX GST_MAKE_FOURCC('s','i','d','x')
+typedef struct _GstSidxBoxEntry
+{
+  gboolean ref_type;
+  guint32 size;
+  GstClockTime duration;
+  gboolean starts_with_sap;
+  guint8 sap_type;
+  guint32 sap_delta_time;
+
+  guint64 offset;
+  GstClockTime pts;
+} GstSidxBoxEntry;
+
+typedef struct _GstSidxBox
+{
+  guint8 version;
+  guint32 flags;
+
+  guint32 ref_id;
+  guint32 timescale;
+  guint64 earliest_pts;
+  guint64 first_offset;
+
+  gint entry_index;
+  gint entries_count;
+
+  GstSidxBoxEntry *entries;
+} GstSidxBox;
+
+typedef enum _GstSidxParserStatus
+{
+  GST_ISOFF_QT_SIDX_PARSER_INIT,
+  GST_ISOFF_QT_SIDX_PARSER_HEADER,
+  GST_ISOFF_QT_SIDX_PARSER_DATA,
+  GST_ISOFF_QT_SIDX_PARSER_FINISHED
+} GstSidxParserStatus;
+
+typedef struct _GstSidxParser
+{
+  GstSidxParserStatus status;
+
+  guint64 size;
+  guint64 cumulative_entry_size;
+  guint64 cumulative_pts;
+
+  GstSidxBox sidx;
+} GstSidxParser;
+
+void gst_isoff_qt_sidx_parser_init (GstSidxParser * parser);
+void gst_isoff_qt_sidx_parser_clear (GstSidxParser * parser);
+GstIsoffParserResult gst_isoff_qt_sidx_parser_add_data (GstSidxParser * parser, const guint8 * buffer, gint length, guint * consumed);
+GstIsoffParserResult gst_isoff_qt_sidx_parser_add_buffer (GstSidxParser * parser, GstBuffer * buf, guint * consumed);
+
+G_END_DECLS
+
+#endif /* __GST_ISOFF_QT_H__ */
+
diff --git a/gst/isomp4/gstqtmoovrecover.c b/gst/isomp4/gstqtmoovrecover.c
new file mode 100644
index 0000000..f5d2b91
--- /dev/null
+++ b/gst/isomp4/gstqtmoovrecover.c
@@ -0,0 +1,387 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+/**
+ * SECTION:element-qtmoovrecover
+ * @short_description: Utility element for recovering unfinished quicktime files
+ *
+ * <refsect2>
+ * <para>
+ * This element recovers quicktime files created with qtmux using the moov
+ * recovery feature.
+ * </para>
+ * <title>Example pipelines</title>
+ * <para>
+ * <programlisting>
+ * TODO
+ * </programlisting>
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib/gstdio.h>
+#include <gst/gst.h>
+
+#include "gstqtmoovrecover.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_qt_moov_recover_debug);
+#define GST_CAT_DEFAULT gst_qt_moov_recover_debug
+
+/* QTMoovRecover signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_RECOVERY_INPUT,
+  PROP_BROKEN_INPUT,
+  PROP_FIXED_OUTPUT,
+  PROP_FAST_START_MODE
+};
+
+#define gst_qt_moov_recover_parent_class parent_class
+G_DEFINE_TYPE (GstQTMoovRecover, gst_qt_moov_recover, GST_TYPE_PIPELINE);
+
+/* property functions */
+static void gst_qt_moov_recover_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_qt_moov_recover_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn gst_qt_moov_recover_change_state (GstElement *
+    element, GstStateChange transition);
+
+static void gst_qt_moov_recover_finalize (GObject * object);
+
+static void
+gst_qt_moov_recover_class_init (GstQTMoovRecoverClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gst_qt_moov_recover_finalize;
+  gobject_class->get_property = gst_qt_moov_recover_get_property;
+  gobject_class->set_property = gst_qt_moov_recover_set_property;
+
+  gstelement_class->change_state = gst_qt_moov_recover_change_state;
+
+  g_object_class_install_property (gobject_class, PROP_FIXED_OUTPUT,
+      g_param_spec_string ("fixed-output",
+          "Path to write the fixed file",
+          "Path to write the fixed file to (used as output)",
+          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_BROKEN_INPUT,
+      g_param_spec_string ("broken-input",
+          "Path to broken input file",
+          "Path to broken input file. (If qtmux was on faststart mode, this "
+          "file is the faststart file)", NULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_RECOVERY_INPUT,
+      g_param_spec_string ("recovery-input",
+          "Path to recovery file",
+          "Path to recovery file (used as input)", NULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_FAST_START_MODE,
+      g_param_spec_boolean ("faststart-mode",
+          "If the broken input is from faststart mode",
+          "If the broken input is from faststart mode",
+          FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  GST_DEBUG_CATEGORY_INIT (gst_qt_moov_recover_debug, "qtmoovrecover", 0,
+      "QT Moovie Recover");
+
+  gst_element_class_set_static_metadata (gstelement_class, "QT Moov Recover",
+      "Util", "Recovers unfinished qtmux files",
+      "Thiago Santos <thiago.sousa.santos@collabora.co.uk>");
+}
+
+static void
+gst_qt_moov_recover_init (GstQTMoovRecover * qtmr)
+{
+}
+
+static void
+gst_qt_moov_recover_finalize (GObject * object)
+{
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_qt_moov_recover_run (void *data)
+{
+  FILE *moovrec = NULL;
+  FILE *mdatinput = NULL;
+  FILE *output = NULL;
+  MdatRecovFile *mdat_recov = NULL;
+  MoovRecovFile *moov_recov = NULL;
+  GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (data);
+  GError *err = NULL;
+  GError *warn = NULL;
+
+  GST_LOG_OBJECT (qtmr, "Starting task");
+
+  GST_DEBUG_OBJECT (qtmr, "Validating properties");
+  GST_OBJECT_LOCK (qtmr);
+  /* validate properties */
+  if (qtmr->broken_input == NULL) {
+    GST_OBJECT_UNLOCK (qtmr);
+    GST_ELEMENT_ERROR (qtmr, RESOURCE, SETTINGS,
+        ("Please set broken-input property"), (NULL));
+    goto end;
+  }
+  if (qtmr->recovery_input == NULL) {
+    GST_OBJECT_UNLOCK (qtmr);
+    GST_ELEMENT_ERROR (qtmr, RESOURCE, SETTINGS,
+        ("Please set recovery-input property"), (NULL));
+    goto end;
+  }
+  if (qtmr->fixed_output == NULL) {
+    GST_OBJECT_UNLOCK (qtmr);
+    GST_ELEMENT_ERROR (qtmr, RESOURCE, SETTINGS,
+        ("Please set fixed-output property"), (NULL));
+    goto end;
+  }
+
+  GST_DEBUG_OBJECT (qtmr, "Opening input/output files");
+  /* open files */
+  moovrec = g_fopen (qtmr->recovery_input, "rb");
+  if (moovrec == NULL) {
+    GST_OBJECT_UNLOCK (qtmr);
+    GST_ELEMENT_ERROR (qtmr, RESOURCE, OPEN_READ,
+        ("Failed to open recovery-input file"), (NULL));
+    goto end;
+  }
+
+  mdatinput = g_fopen (qtmr->broken_input, "rb");
+  if (mdatinput == NULL) {
+    GST_OBJECT_UNLOCK (qtmr);
+    GST_ELEMENT_ERROR (qtmr, RESOURCE, OPEN_READ,
+        ("Failed to open broken-input file"), (NULL));
+    goto end;
+  }
+  output = g_fopen (qtmr->fixed_output, "wb+");
+  if (output == NULL) {
+    GST_OBJECT_UNLOCK (qtmr);
+    GST_ELEMENT_ERROR (qtmr, RESOURCE, OPEN_READ_WRITE,
+        ("Failed to open fixed-output file"), (NULL));
+    goto end;
+  }
+  GST_OBJECT_UNLOCK (qtmr);
+
+  GST_DEBUG_OBJECT (qtmr, "Parsing input files");
+  /* now create our structures */
+  mdat_recov = mdat_recov_file_create (mdatinput, qtmr->faststart_mode, &err);
+  mdatinput = NULL;
+  if (mdat_recov == NULL) {
+    GST_ELEMENT_ERROR (qtmr, RESOURCE, FAILED,
+        ("Broken file could not be parsed correctly"), (NULL));
+    goto end;
+  }
+  moov_recov = moov_recov_file_create (moovrec, &err);
+  moovrec = NULL;
+  if (moov_recov == NULL) {
+    GST_ELEMENT_ERROR (qtmr, RESOURCE, FAILED,
+        ("Recovery file could not be parsed correctly"), (NULL));
+    goto end;
+  }
+
+  /* now parse the buffers data from moovrec */
+  if (!moov_recov_parse_buffers (moov_recov, mdat_recov, &err)) {
+    goto end;
+  }
+
+  GST_DEBUG_OBJECT (qtmr, "Writing fixed file to output");
+  if (!moov_recov_write_file (moov_recov, mdat_recov, output, &err, &warn)) {
+    goto end;
+  }
+
+  if (warn) {
+    GST_ELEMENT_WARNING (qtmr, RESOURCE, FAILED, ("%s", warn->message), (NULL));
+    g_error_free (warn);
+  }
+
+  /* here means success */
+  GST_DEBUG_OBJECT (qtmr, "Finished successfully, posting EOS");
+  gst_element_post_message (GST_ELEMENT_CAST (qtmr),
+      gst_message_new_eos (GST_OBJECT_CAST (qtmr)));
+
+end:
+  GST_LOG_OBJECT (qtmr, "Finalizing task");
+  if (err) {
+    GST_ELEMENT_ERROR (qtmr, RESOURCE, FAILED, ("%s", err->message), (NULL));
+    g_error_free (err);
+  }
+
+  if (moov_recov)
+    moov_recov_file_free (moov_recov);
+  if (moovrec)
+    fclose (moovrec);
+
+  if (mdat_recov)
+    mdat_recov_file_free (mdat_recov);
+  if (mdatinput)
+    fclose (mdatinput);
+
+  if (output)
+    fclose (output);
+  GST_LOG_OBJECT (qtmr, "Leaving task");
+  gst_task_stop (qtmr->task);
+}
+
+static void
+gst_qt_moov_recover_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (object);
+
+  GST_OBJECT_LOCK (qtmr);
+  switch (prop_id) {
+    case PROP_FAST_START_MODE:
+      g_value_set_boolean (value, qtmr->faststart_mode);
+      break;
+    case PROP_BROKEN_INPUT:
+      g_value_set_string (value, qtmr->broken_input);
+      break;
+    case PROP_RECOVERY_INPUT:
+      g_value_set_string (value, qtmr->recovery_input);
+      break;
+    case PROP_FIXED_OUTPUT:
+      g_value_set_string (value, qtmr->fixed_output);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (qtmr);
+}
+
+static void
+gst_qt_moov_recover_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (object);
+
+  GST_OBJECT_LOCK (qtmr);
+  switch (prop_id) {
+    case PROP_FAST_START_MODE:
+      qtmr->faststart_mode = g_value_get_boolean (value);
+      break;
+    case PROP_BROKEN_INPUT:
+      g_free (qtmr->broken_input);
+      qtmr->broken_input = g_value_dup_string (value);
+      break;
+    case PROP_RECOVERY_INPUT:
+      g_free (qtmr->recovery_input);
+      qtmr->recovery_input = g_value_dup_string (value);
+      break;
+    case PROP_FIXED_OUTPUT:
+      g_free (qtmr->fixed_output);
+      qtmr->fixed_output = g_value_dup_string (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (qtmr);
+}
+
+static GstStateChangeReturn
+gst_qt_moov_recover_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      qtmr->task = gst_task_new (gst_qt_moov_recover_run, qtmr, NULL);
+      g_rec_mutex_init (&qtmr->task_mutex);
+      gst_task_set_lock (qtmr->task, &qtmr->task_mutex);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      gst_task_start (qtmr->task);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      gst_task_stop (qtmr->task);
+      gst_task_join (qtmr->task);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      if (gst_task_get_state (qtmr->task) != GST_TASK_STOPPED)
+        GST_ERROR ("task %p should be stopped by now", qtmr->task);
+      gst_object_unref (qtmr->task);
+      qtmr->task = NULL;
+      g_rec_mutex_clear (&qtmr->task_mutex);
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+
+gboolean
+gst_qt_moov_recover_register (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "qtmoovrecover", GST_RANK_NONE,
+      GST_TYPE_QT_MOOV_RECOVER);
+}
diff --git a/gst/isomp4/gstqtmoovrecover.h b/gst/isomp4/gstqtmoovrecover.h
new file mode 100644
index 0000000..b86c223
--- /dev/null
+++ b/gst/isomp4/gstqtmoovrecover.h
@@ -0,0 +1,88 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_QT_MOOV_RECOVER_H__
+#define __GST_QT_MOOV_RECOVER_H__
+
+#include <gst/gst.h>
+
+#include "atoms.h"
+#include "atomsrecovery.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_QT_MOOV_RECOVER (gst_qt_moov_recover_get_type())
+#define GST_QT_MOOV_RECOVER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_QT_MOOV_RECOVER, GstQTMoovRecover))
+#define GST_QT_MOOV_RECOVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_QT_MOOV_RECOVER, GstQTMoovRecover))
+#define GST_IS_QT_MOOV_RECOVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_QT_MOOV_RECOVER))
+#define GST_IS_QT_MOOV_RECOVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QT_MOOV_RECOVER))
+#define GST_QT_MOOV_RECOVER_CAST(obj) ((GstQTMoovRecover*)(obj))
+
+
+typedef struct _GstQTMoovRecover GstQTMoovRecover;
+typedef struct _GstQTMoovRecoverClass GstQTMoovRecoverClass;
+
+struct _GstQTMoovRecover
+{
+  GstPipeline pipeline;
+
+  GstTask *task;
+  GRecMutex task_mutex;
+
+  /* properties */
+  gboolean  faststart_mode;
+  gchar    *recovery_input;
+  gchar    *fixed_output;
+  gchar    *broken_input;
+};
+
+struct _GstQTMoovRecoverClass
+{
+  GstPipelineClass parent_class;
+};
+
+GType gst_qt_moov_recover_get_type (void);
+gboolean gst_qt_moov_recover_register (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_QT_MOOV_RECOVER_H__ */
diff --git a/gst/isomp4/gstqtmux-doc.c b/gst/isomp4/gstqtmux-doc.c
new file mode 100644
index 0000000..3b857d8
--- /dev/null
+++ b/gst/isomp4/gstqtmux-doc.c
@@ -0,0 +1,242 @@
+/* Quicktime muxer documentation
+ * Copyright (C) 2008-2010 Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+ * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ * Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* ============================= mp4mux ==================================== */
+
+/**
+ * SECTION:element-mp4mux
+ * @short_description: Muxer for ISO MPEG-4 (.mp4) files
+ *
+ * This element merges streams (audio and video) into ISO MPEG-4 (.mp4) files.
+ *
+ * The following background intends to explain why various similar muxers
+ * are present in this plugin.
+ *
+ * The <ulink url="http://www.apple.com/quicktime/resources/qtfileformat.pdf">
+ * QuickTime file format specification</ulink> served as basis for the MP4 file
+ * format specification (mp4mux), and as such the QuickTime file structure is
+ * nearly identical to the so-called ISO Base Media file format defined in
+ * ISO 14496-12 (except for some media specific parts).
+ * In turn, the latter ISO Base Media format was further specialized as a
+ * Motion JPEG-2000 file format in ISO 15444-3 (mj2mux)
+ * and in various 3GPP(2) specs (3gppmux).
+ * The fragmented file features defined (only) in ISO Base Media are used by
+ * ISMV files making up (a.o.) Smooth Streaming (ismlmux).
+ *
+ * A few properties (#GstMp4Mux:movie-timescale, #GstMp4Mux:trak-timescale)
+ * allow adjusting some technical parameters, which might be useful in (rare)
+ * cases to resolve compatibility issues in some situations.
+ *
+ * Some other properties influence the result more fundamentally.
+ * A typical mov/mp4 file's metadata (aka moov) is located at the end of the
+ * file, somewhat contrary to this usually being called "the header".
+ * However, a #GstMp4Mux:faststart file will (with some effort) arrange this to
+ * be located near start of the file, which then allows it e.g. to be played
+ * while downloading. Alternatively, rather than having one chunk of metadata at
+ * start (or end), there can be some metadata at start and most of the other
+ * data can be spread out into fragments of #GstMp4Mux:fragment-duration.
+ * If such fragmented layout is intended for streaming purposes, then
+ * #GstMp4Mux:streamable allows foregoing to add index metadata (at the end of
+ * file).
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 gst-launch-1.0 v4l2src num-buffers=50 ! queue ! x264enc ! mp4mux ! filesink location=video.mp4
+ * ]|
+ * Records a video stream captured from a v4l2 device, encodes it into H.264
+ * and muxes it into an mp4 file.
+ * </refsect2>
+ */
+
+/* ============================= 3gppmux ==================================== */
+
+/**
+ * SECTION:element-3gppmux
+ * @short_description: Muxer for 3GPP (.3gp) files
+ *
+ * This element merges streams (audio and video) into 3GPP (.3gp) files.
+ *
+ * The following background intends to explain why various similar muxers
+ * are present in this plugin.
+ *
+ * The <ulink url="http://www.apple.com/quicktime/resources/qtfileformat.pdf">
+ * QuickTime file format specification</ulink> served as basis for the MP4 file
+ * format specification (mp4mux), and as such the QuickTime file structure is
+ * nearly identical to the so-called ISO Base Media file format defined in
+ * ISO 14496-12 (except for some media specific parts).
+ * In turn, the latter ISO Base Media format was further specialized as a
+ * Motion JPEG-2000 file format in ISO 15444-3 (mj2mux)
+ * and in various 3GPP(2) specs (3gppmux).
+ * The fragmented file features defined (only) in ISO Base Media are used by
+ * ISMV files making up (a.o.) Smooth Streaming (ismlmux).
+ *
+ * A few properties (#Gst3GPPMux:movie-timescale, #Gst3GPPMux:trak-timescale)
+ * allow adjusting some technical parameters, which might be useful in (rare)
+ * cases to resolve compatibility issues in some situations.
+ *
+ * Some other properties influence the result more fundamentally.
+ * A typical mov/mp4 file's metadata (aka moov) is located at the end of the file,
+ * somewhat contrary to this usually being called "the header". However, a
+ * #Gst3GPPMux:faststart file will (with some effort) arrange this to be located
+ * near start of the file, which then allows it e.g. to be played while
+ * downloading. Alternatively, rather than having one chunk of metadata at start
+ * (or end), there can be some metadata at start and most of the other data can
+ * be spread out into fragments of #Gst3GPPMux:fragment-duration. If such
+ * fragmented layout is intended for streaming purposes, then
+ * #Gst3GPPMux:streamable allows foregoing to add index metadata (at the end of
+ * file).
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 v4l2src num-buffers=50 ! queue ! ffenc_h263 ! 3gppmux ! filesink location=video.3gp
+ * ]|
+ * Records a video stream captured from a v4l2 device, encodes it into H.263
+ * and muxes it into an 3gp file.
+ * </refsect2>
+ *
+ * Documentation last reviewed on 2011-04-21
+ */
+
+/* ============================= mj2pmux ==================================== */
+
+/**
+ * SECTION:element-mj2mux
+ * @short_description: Muxer for Motion JPEG-2000 (.mj2) files
+ *
+ * This element merges streams (audio and video) into MJ2 (.mj2) files.
+ *
+ * The following background intends to explain why various similar muxers
+ * are present in this plugin.
+ *
+ * The <ulink url="http://www.apple.com/quicktime/resources/qtfileformat.pdf">
+ * QuickTime file format specification</ulink> served as basis for the MP4 file
+ * format specification (mp4mux), and as such the QuickTime file structure is
+ * nearly identical to the so-called ISO Base Media file format defined in
+ * ISO 14496-12 (except for some media specific parts).
+ * In turn, the latter ISO Base Media format was further specialized as a
+ * Motion JPEG-2000 file format in ISO 15444-3 (mj2mux)
+ * and in various 3GPP(2) specs (3gppmux).
+ * The fragmented file features defined (only) in ISO Base Media are used by
+ * ISMV files making up (a.o.) Smooth Streaming (ismlmux).
+ *
+ * A few properties (#GstMJ2Mux:movie-timescale, #GstMJ2Mux:trak-timescale)
+ * allow adjusting some technical parameters, which might be useful in (rare)
+ * cases to resolve compatibility issues in some situations.
+ *
+ * Some other properties influence the result more fundamentally.
+ * A typical mov/mp4 file's metadata (aka moov) is located at the end of the file,
+ * somewhat contrary to this usually being called "the header". However, a
+ * #GstMJ2Mux:faststart file will (with some effort) arrange this to be located
+ * near start of the file, which then allows it e.g. to be played while
+ * downloading. Alternatively, rather than having one chunk of metadata at start
+ * (or end), there can be some metadata at start and most of the other data can
+ * be spread out into fragments of #GstMJ2Mux:fragment-duration. If such
+ * fragmented layout is intended for streaming purposes, then
+ * #GstMJ2Mux:streamable allows foregoing to add index metadata (at the end of
+ * file).
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 v4l2src num-buffers=50 ! queue ! jp2kenc ! mj2mux ! filesink location=video.mj2
+ * ]|
+ * Records a video stream captured from a v4l2 device, encodes it into JPEG-2000
+ * and muxes it into an mj2 file.
+ * </refsect2>
+ *
+ * Documentation last reviewed on 2011-04-21
+ */
+
+/* ============================= ismlmux ==================================== */
+
+/**
+ * SECTION:element-ismlmux
+ * @short_description: Muxer for ISML smooth streaming (.isml) files
+ *
+ * This element merges streams (audio and video) into MJ2 (.mj2) files.
+ *
+ * The following background intends to explain why various similar muxers
+ * are present in this plugin.
+ *
+ * The <ulink url="http://www.apple.com/quicktime/resources/qtfileformat.pdf">
+ * QuickTime file format specification</ulink> served as basis for the MP4 file
+ * format specification (mp4mux), and as such the QuickTime file structure is
+ * nearly identical to the so-called ISO Base Media file format defined in
+ * ISO 14496-12 (except for some media specific parts).
+ * In turn, the latter ISO Base Media format was further specialized as a
+ * Motion JPEG-2000 file format in ISO 15444-3 (mj2mux)
+ * and in various 3GPP(2) specs (3gppmux).
+ * The fragmented file features defined (only) in ISO Base Media are used by
+ * ISMV files making up (a.o.) Smooth Streaming (ismlmux).
+ *
+ * A few properties (#GstISMLMux:movie-timescale, #GstISMLMux:trak-timescale)
+ * allow adjusting some technical parameters, which might be useful in (rare)
+ * cases to resolve compatibility issues in some situations.
+ *
+ * Some other properties influence the result more fundamentally.
+ * A typical mov/mp4 file's metadata (aka moov) is located at the end of the file,
+ * somewhat contrary to this usually being called "the header". However, a
+ * #GstISMLMux:faststart file will (with some effort) arrange this to be located
+ * near start of the file, which then allows it e.g. to be played while
+ * downloading. Alternatively, rather than having one chunk of metadata at start
+ * (or end), there can be some metadata at start and most of the other data can
+ * be spread out into fragments of #GstISMLMux:fragment-duration. If such
+ * fragmented layout is intended for streaming purposes, then
+ * #GstISMLMux:streamable allows foregoing to add index metadata (at the end of
+ * file).
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 v4l2src num-buffers=50 ! queue ! jp2kenc ! mj2mux ! filesink location=video.mj2
+ * ]|
+ * Records a video stream captured from a v4l2 device, encodes it into JPEG-2000
+ * and muxes it into an mj2 file.
+ * </refsect2>
+ *
+ * Documentation last reviewed on 2011-04-21
+ */
diff --git a/gst/isomp4/gstqtmux-doc.h b/gst/isomp4/gstqtmux-doc.h
new file mode 100644
index 0000000..9d12164
--- /dev/null
+++ b/gst/isomp4/gstqtmux-doc.h
@@ -0,0 +1,52 @@
+/* Quicktime muxer documentation
+ * Copyright (C) 2008-2010 Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+ * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ * Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#error "This header is for gtk-doc only and not supposed to be included"
+
+typedef struct _GstMP4Mux GstMP4Mux;
+typedef struct _Gst3GPPMux Gst3GPPMux;
+typedef struct _GstISMLMux GstISMLMux;
+typedef struct _GstMJ2Mux GstMJ2Mux;
+
diff --git a/gst/isomp4/gstqtmux.c b/gst/isomp4/gstqtmux.c
new file mode 100644
index 0000000..74e177c
--- /dev/null
+++ b/gst/isomp4/gstqtmux.c
@@ -0,0 +1,6322 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008-2010 Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+ * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ * Copyright (C) 2014 Jan Schmidt <jan@centricular.com>
+ * Contact: Stefan Kost <stefan.kost@nokia.com>
+
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+/**
+ * SECTION:element-qtmux
+ * @short_description: Muxer for quicktime(.mov) files
+ *
+ * This element merges streams (audio and video) into QuickTime(.mov) files.
+ *
+ * The following background intends to explain why various similar muxers
+ * are present in this plugin.
+ *
+ * The <ulink url="http://www.apple.com/quicktime/resources/qtfileformat.pdf">
+ * QuickTime file format specification</ulink> served as basis for the MP4 file
+ * format specification (mp4mux), and as such the QuickTime file structure is
+ * nearly identical to the so-called ISO Base Media file format defined in
+ * ISO 14496-12 (except for some media specific parts).
+ * In turn, the latter ISO Base Media format was further specialized as a
+ * Motion JPEG-2000 file format in ISO 15444-3 (mj2mux)
+ * and in various 3GPP(2) specs (gppmux).
+ * The fragmented file features defined (only) in ISO Base Media are used by
+ * ISMV files making up (a.o.) Smooth Streaming (ismlmux).
+ *
+ * A few properties (#GstQTMux:movie-timescale, #GstQTMux:trak-timescale,
+ * #GstQTMuxPad:trak-timescale) allow adjusting some technical parameters,
+ * which might be useful in (rare) cases to resolve compatibility issues in
+ * some situations.
+ *
+ * Some other properties influence the result more fundamentally.
+ * A typical mov/mp4 file's metadata (aka moov) is located at the end of the
+ * file, somewhat contrary to this usually being called "the header".
+ * However, a #GstQTMux:faststart file will (with some effort) arrange this to
+ * be located near start of the file, which then allows it e.g. to be played
+ * while downloading. Alternatively, rather than having one chunk of metadata at
+ * start (or end), there can be some metadata at start and most of the other
+ * data can be spread out into fragments of #GstQTMux:fragment-duration.
+ * If such fragmented layout is intended for streaming purposes, then
+ * #GstQTMux:streamable allows foregoing to add index metadata (at the end of
+ * file).
+ *
+ * When the maximum duration to be recorded can be known in advance, #GstQTMux
+ * also supports a 'Robust Muxing' mode. In robust muxing mode,  space for the
+ * headers are reserved at the start of muxing, and rewritten at a configurable
+ * interval, so that the output file is always playable, even if the recording
+ * is interrupted uncleanly by a crash. Robust muxing mode requires a seekable
+ * output, such as filesink, because it needs to rewrite the start of the file.
+ *
+ * To enable robust muxing mode, set the #GstQTMux::reserved-moov-update-period
+ * and #GstQTMux::reserved-max-duration property. Also present is the
+ * #GstQTMux::reserved-bytes-per-sec property, which can be increased if
+ * for some reason the default is not large enough and the initial reserved
+ * space for headers is too small. Applications can monitor the
+ * #GstQTMux::reserved-duration-remaining property to see how close to full
+ * the reserved space is becoming.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 v4l2src num-buffers=500 ! video/x-raw,width=320,height=240 ! videoconvert ! qtmux ! filesink location=video.mov
+ * ]|
+ * Records a video stream captured from a v4l2 device and muxes it into a qt file.
+ * </refsect2>
+ */
+
+/*
+ * Based on avimux
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib/gstdio.h>
+
+#include <gst/gst.h>
+#include <gst/base/gstcollectpads.h>
+#include <gst/base/gstbytereader.h>
+#include <gst/base/gstbitreader.h>
+#include <gst/audio/audio.h>
+#include <gst/video/video.h>
+#include <gst/tag/tag.h>
+#include <gst/pbutils/pbutils.h>
+
+#include <sys/types.h>
+#ifdef G_OS_WIN32
+#include <io.h>                 /* lseek, open, close, read */
+#undef lseek
+#define lseek _lseeki64
+#undef off_t
+#define off_t guint64
+#endif
+
+#ifdef _MSC_VER
+#define ftruncate g_win32_ftruncate
+#endif
+
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
+
+#include "gstqtmux.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_qt_mux_debug);
+#define GST_CAT_DEFAULT gst_qt_mux_debug
+
+#ifndef ABSDIFF
+#define ABSDIFF(a, b) ((a) > (b) ? (a) - (b) : (b) - (a))
+#endif
+
+/* Hacker notes.
+ *
+ * The basic building blocks of MP4 files are:
+ *  - an 'ftyp' box at the very start
+ *  - an 'mdat' box which contains the raw audio/video/subtitle data;
+ *    this is just a bunch of bytes, completely unframed and possibly
+ *    unordered with no additional meta-information
+ *  - a 'moov' box that contains information about the different streams
+ *    and what they contain, as well as sample tables for each stream
+ *    that tell the demuxer where in the mdat box each buffer/sample is
+ *    and what its duration/timestamp etc. is, and whether it's a
+ *    keyframe etc.
+ * Additionally, fragmented MP4 works by writing chunks of data in
+ * pairs of 'moof' and 'mdat' boxes:
+ *  - 'moof' boxes, header preceding each mdat fragment describing the
+ *    contents, like a moov but only for that fragment.
+ *  - a 'mfra' box for Fragmented MP4, which is written at the end and
+ *    contains a summary of all fragments and seek tables.
+ *
+ * Currently mp4mux can work in 4 different modes / generate 4 types
+ * of output files/streams:
+ *
+ * - Normal mp4: mp4mux will write a little ftyp identifier at the
+ *   beginning, then start an mdat box into which it will write all the
+ *   sample data. At EOS it will then write the moov header with track
+ *   headers and sample tables at the end of the file, and rewrite the
+ *   start of the file to fix up the mdat box size at the beginning.
+ *   It has to wait for EOS to write the moov (which includes the
+ *   sample tables) because it doesn't know how much space those
+ *   tables will be. The output downstream must be seekable to rewrite
+ *   the mdat box at EOS.
+ *
+ * - Fragmented mp4: moov header with track headers at start
+ *   but no sample table, followed by N fragments, each containing
+ *   track headers with sample tables followed by some data. Downstream
+ *   does not need to be seekable if the 'streamable' flag is TRUE,
+ *   as the final mfra and total duration will be omitted.
+ *
+ * - Fast-start mp4: the goal here is to create a file where the moov
+ *   headers are at the beginning; what mp4mux will do is write all
+ *   sample data into a temp file and build moov header plus sample
+ *   tables in memory and then when EOS comes, it will push out the
+ *   moov header plus sample tables at the beginning, followed by the
+ *   mdat sample data at the end which is read in from the temp file
+ *   Files created in this mode are better for streaming over the
+ *   network, since the client doesn't have to seek to the end of the
+ *   file to get the headers, but it requires copying all sample data
+ *   out of the temp file at EOS, which can be expensive. Downstream does
+ *   not need to be seekable, because of the use of the temp file.
+ *
+ * - Robust Muxing mode: In this mode, qtmux uses the reserved-max-duration
+ *   and reserved-moov-update-period properties to reserve free space
+ *   at the start of the file and periodically write the MOOV atom out
+ *   to it. That means that killing the muxing at any point still
+ *   results in a playable file, at the cost of wasting some amount of
+ *   free space at the start of file. The approximate recording duration
+ *   has to be known in advance to estimate how much free space to reserve
+ *   for the moov, and the downstream must be seekable.
+ *   If the moov header grows larger than the reserved space, an error
+ *   is generated - so it's better to over-estimate the amount of space
+ *   to reserve. To ensure the file is playable at any point, the moov
+ *   is updated using a 'ping-pong' strategy, so the output is never in
+ *   an invalid state.
+ */
+
+#ifndef GST_REMOVE_DEPRECATED
+enum
+{
+  DTS_METHOD_DD,
+  DTS_METHOD_REORDER,
+  DTS_METHOD_ASC
+};
+
+static GType
+gst_qt_mux_dts_method_get_type (void)
+{
+  static GType gst_qt_mux_dts_method = 0;
+
+  if (!gst_qt_mux_dts_method) {
+    static const GEnumValue dts_methods[] = {
+      {DTS_METHOD_DD, "delta/duration", "dd"},
+      {DTS_METHOD_REORDER, "reorder", "reorder"},
+      {DTS_METHOD_ASC, "ascending", "asc"},
+      {0, NULL, NULL},
+    };
+
+    gst_qt_mux_dts_method =
+        g_enum_register_static ("GstQTMuxDtsMethods", dts_methods);
+  }
+
+  return gst_qt_mux_dts_method;
+}
+
+#define GST_TYPE_QT_MUX_DTS_METHOD \
+  (gst_qt_mux_dts_method_get_type ())
+#endif
+
+enum
+{
+  PROP_PAD_0,
+  PROP_PAD_TRAK_TIMESCALE,
+};
+
+#define DEFAULT_PAD_TRAK_TIMESCALE          0
+
+GType gst_qt_mux_pad_get_type (void);
+
+#define GST_TYPE_QT_MUX_PAD \
+  (gst_qt_mux_pad_get_type())
+#define GST_QT_MUX_PAD(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QT_MUX_PAD, GstQTMuxPad))
+#define GST_QT_MUX_PAD_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QT_MUX_PAD, GstQTMuxPadClass))
+#define GST_IS_QT_MUX_PAD(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QT_MUX_PAD))
+#define GST_IS_QT_MUX_PAD_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QT_MUX_PAD))
+#define GST_QT_MUX_PAD_CAST(obj) \
+  ((GstQTMuxPad *)(obj))
+
+typedef struct _GstQTMuxPad GstQTMuxPad;
+typedef struct _GstQTMuxPadClass GstQTMuxPadClass;
+
+struct _GstQTMuxPad
+{
+  GstPad parent;
+
+  guint32 trak_timescale;
+};
+
+struct _GstQTMuxPadClass
+{
+  GstPadClass parent;
+};
+
+G_DEFINE_TYPE (GstQTMuxPad, gst_qt_mux_pad, GST_TYPE_PAD);
+
+static void
+gst_qt_mux_pad_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstQTMuxPad *pad = GST_QT_MUX_PAD_CAST (object);
+
+  GST_OBJECT_LOCK (pad);
+  switch (prop_id) {
+    case PROP_PAD_TRAK_TIMESCALE:
+      pad->trak_timescale = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (pad);
+}
+
+static void
+gst_qt_mux_pad_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstQTMuxPad *pad = GST_QT_MUX_PAD_CAST (object);
+
+  GST_OBJECT_LOCK (pad);
+  switch (prop_id) {
+    case PROP_PAD_TRAK_TIMESCALE:
+      g_value_set_uint (value, pad->trak_timescale);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (pad);
+}
+
+static void
+gst_qt_mux_pad_class_init (GstQTMuxPadClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+
+  gobject_class->get_property = gst_qt_mux_pad_get_property;
+  gobject_class->set_property = gst_qt_mux_pad_set_property;
+
+  g_object_class_install_property (gobject_class, PROP_PAD_TRAK_TIMESCALE,
+      g_param_spec_uint ("trak-timescale", "Track timescale",
+          "Timescale to use for this pad's trak (units per second, 0 is automatic)",
+          0, G_MAXUINT32, DEFAULT_PAD_TRAK_TIMESCALE,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_qt_mux_pad_init (GstQTMuxPad * pad)
+{
+  pad->trak_timescale = DEFAULT_PAD_TRAK_TIMESCALE;
+}
+
+static guint32
+gst_qt_mux_pad_get_timescale (GstQTMuxPad * pad)
+{
+  guint32 timescale;
+
+  GST_OBJECT_LOCK (pad);
+  timescale = pad->trak_timescale;
+  GST_OBJECT_UNLOCK (pad);
+
+  return timescale;
+}
+
+/* QTMux signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_MOVIE_TIMESCALE,
+  PROP_TRAK_TIMESCALE,
+  PROP_FAST_START,
+  PROP_FAST_START_TEMP_FILE,
+  PROP_MOOV_RECOV_FILE,
+  PROP_FRAGMENT_DURATION,
+  PROP_STREAMABLE,
+  PROP_RESERVED_MAX_DURATION,
+  PROP_RESERVED_DURATION_REMAINING,
+  PROP_RESERVED_MOOV_UPDATE_PERIOD,
+  PROP_RESERVED_BYTES_PER_SEC,
+  PROP_RESERVED_PREFILL,
+#ifndef GST_REMOVE_DEPRECATED
+  PROP_DTS_METHOD,
+#endif
+  PROP_DO_CTTS,
+  PROP_INTERLEAVE_BYTES,
+  PROP_INTERLEAVE_TIME,
+  PROP_MAX_RAW_AUDIO_DRIFT,
+};
+
+/* some spare for header size as well */
+#define MDAT_LARGE_FILE_LIMIT           ((guint64) 1024 * 1024 * 1024 * 2)
+
+#define DEFAULT_MOVIE_TIMESCALE         0
+#define DEFAULT_TRAK_TIMESCALE          0
+#define DEFAULT_DO_CTTS                 TRUE
+#define DEFAULT_FAST_START              FALSE
+#define DEFAULT_FAST_START_TEMP_FILE    NULL
+#define DEFAULT_MOOV_RECOV_FILE         NULL
+#define DEFAULT_FRAGMENT_DURATION       0
+#define DEFAULT_STREAMABLE              TRUE
+#ifndef GST_REMOVE_DEPRECATED
+#define DEFAULT_DTS_METHOD              DTS_METHOD_REORDER
+#endif
+#define DEFAULT_RESERVED_MAX_DURATION   GST_CLOCK_TIME_NONE
+#define DEFAULT_RESERVED_MOOV_UPDATE_PERIOD   GST_CLOCK_TIME_NONE
+#define DEFAULT_RESERVED_BYTES_PER_SEC_PER_TRAK 550
+#define DEFAULT_RESERVED_PREFILL FALSE
+#define DEFAULT_INTERLEAVE_BYTES 0
+#define DEFAULT_INTERLEAVE_TIME 250*GST_MSECOND
+#define DEFAULT_MAX_RAW_AUDIO_DRIFT 40 * GST_MSECOND
+
+static void gst_qt_mux_finalize (GObject * object);
+
+static GstStateChangeReturn gst_qt_mux_change_state (GstElement * element,
+    GstStateChange transition);
+
+/* property functions */
+static void gst_qt_mux_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_qt_mux_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+/* pad functions */
+static GstPad *gst_qt_mux_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
+static void gst_qt_mux_release_pad (GstElement * element, GstPad * pad);
+
+/* event */
+static gboolean gst_qt_mux_sink_event (GstCollectPads * pads,
+    GstCollectData * data, GstEvent * event, gpointer user_data);
+
+static GstFlowReturn gst_qt_mux_collected (GstCollectPads * pads,
+    gpointer user_data);
+static GstFlowReturn gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad,
+    GstBuffer * buf);
+
+static GstFlowReturn
+gst_qt_mux_robust_recording_rewrite_moov (GstQTMux * qtmux);
+
+static void gst_qt_mux_update_global_statistics (GstQTMux * qtmux);
+static void gst_qt_mux_update_edit_lists (GstQTMux * qtmux);
+
+static GstElementClass *parent_class = NULL;
+
+static void
+gst_qt_mux_base_init (gpointer g_class)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+  GstQTMuxClass *klass = (GstQTMuxClass *) g_class;
+  GstQTMuxClassParams *params;
+  GstPadTemplate *videosinktempl, *audiosinktempl, *subtitlesinktempl;
+  GstPadTemplate *srctempl;
+  gchar *longname, *description;
+
+  params =
+      (GstQTMuxClassParams *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (g_class),
+      GST_QT_MUX_PARAMS_QDATA);
+  g_assert (params != NULL);
+
+  /* construct the element details struct */
+  longname = g_strdup_printf ("%s Muxer", params->prop->long_name);
+  description = g_strdup_printf ("Multiplex audio and video into a %s file",
+      params->prop->long_name);
+  gst_element_class_set_static_metadata (element_class, longname,
+      "Codec/Muxer", description,
+      "Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>");
+  g_free (longname);
+  g_free (description);
+
+  /* pad templates */
+  srctempl = gst_pad_template_new ("src", GST_PAD_SRC,
+      GST_PAD_ALWAYS, params->src_caps);
+  gst_element_class_add_pad_template (element_class, srctempl);
+
+  if (params->audio_sink_caps) {
+    audiosinktempl = gst_pad_template_new_with_gtype ("audio_%u",
+        GST_PAD_SINK, GST_PAD_REQUEST, params->audio_sink_caps,
+        GST_TYPE_QT_MUX_PAD);
+    gst_element_class_add_pad_template (element_class, audiosinktempl);
+  }
+
+  if (params->video_sink_caps) {
+    videosinktempl = gst_pad_template_new_with_gtype ("video_%u",
+        GST_PAD_SINK, GST_PAD_REQUEST, params->video_sink_caps,
+        GST_TYPE_QT_MUX_PAD);
+    gst_element_class_add_pad_template (element_class, videosinktempl);
+  }
+
+  if (params->subtitle_sink_caps) {
+    subtitlesinktempl = gst_pad_template_new_with_gtype ("subtitle_%u",
+        GST_PAD_SINK, GST_PAD_REQUEST, params->subtitle_sink_caps,
+        GST_TYPE_QT_MUX_PAD);
+    gst_element_class_add_pad_template (element_class, subtitlesinktempl);
+  }
+
+  klass->format = params->prop->format;
+}
+
+static void
+gst_qt_mux_class_init (GstQTMuxClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GParamFlags streamable_flags;
+  const gchar *streamable_desc;
+  gboolean streamable;
+#define STREAMABLE_DESC "If set to true, the output should be as if it is to "\
+  "be streamed and hence no indexes written or duration written."
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gst_qt_mux_finalize;
+  gobject_class->get_property = gst_qt_mux_get_property;
+  gobject_class->set_property = gst_qt_mux_set_property;
+
+  streamable_flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
+  if (klass->format == GST_QT_MUX_FORMAT_ISML) {
+    streamable_desc = STREAMABLE_DESC;
+    streamable = DEFAULT_STREAMABLE;
+  } else {
+    streamable_desc =
+        STREAMABLE_DESC " (DEPRECATED, only valid for fragmented MP4)";
+    streamable_flags |= G_PARAM_DEPRECATED;
+    streamable = FALSE;
+  }
+
+  g_object_class_install_property (gobject_class, PROP_MOVIE_TIMESCALE,
+      g_param_spec_uint ("movie-timescale", "Movie timescale",
+          "Timescale to use in the movie (units per second, 0 == default)",
+          0, G_MAXUINT32, DEFAULT_MOVIE_TIMESCALE,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_TRAK_TIMESCALE,
+      g_param_spec_uint ("trak-timescale", "Track timescale",
+          "Timescale to use for the tracks (units per second, 0 is automatic)",
+          0, G_MAXUINT32, DEFAULT_TRAK_TIMESCALE,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_DO_CTTS,
+      g_param_spec_boolean ("presentation-time",
+          "Include presentation-time info",
+          "Calculate and include presentation/composition time "
+          "(in addition to decoding time)", DEFAULT_DO_CTTS,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+#ifndef GST_REMOVE_DEPRECATED
+  g_object_class_install_property (gobject_class, PROP_DTS_METHOD,
+      g_param_spec_enum ("dts-method", "dts-method",
+          "Method to determine DTS time (DEPRECATED)",
+          GST_TYPE_QT_MUX_DTS_METHOD, DEFAULT_DTS_METHOD,
+          G_PARAM_DEPRECATED | G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
+          G_PARAM_STATIC_STRINGS));
+#endif
+  g_object_class_install_property (gobject_class, PROP_FAST_START,
+      g_param_spec_boolean ("faststart", "Format file to faststart",
+          "If the file should be formatted for faststart (headers first)",
+          DEFAULT_FAST_START, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_FAST_START_TEMP_FILE,
+      g_param_spec_string ("faststart-file", "File to use for storing buffers",
+          "File that will be used temporarily to store data from the stream "
+          "when creating a faststart file. If null a filepath will be "
+          "created automatically", DEFAULT_FAST_START_TEMP_FILE,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MOOV_RECOV_FILE,
+      g_param_spec_string ("moov-recovery-file",
+          "File to store data for posterior moov atom recovery",
+          "File to be used to store "
+          "data for moov atom making movie file recovery possible in case "
+          "of a crash during muxing. Null for disabled. (Experimental)",
+          DEFAULT_MOOV_RECOV_FILE,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_FRAGMENT_DURATION,
+      g_param_spec_uint ("fragment-duration", "Fragment duration",
+          "Fragment durations in ms (produce a fragmented file if > 0)",
+          0, G_MAXUINT32, klass->format == GST_QT_MUX_FORMAT_ISML ?
+          2000 : DEFAULT_FRAGMENT_DURATION,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_STREAMABLE,
+      g_param_spec_boolean ("streamable", "Streamable", streamable_desc,
+          streamable, streamable_flags | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_RESERVED_MAX_DURATION,
+      g_param_spec_uint64 ("reserved-max-duration",
+          "Reserved maximum file duration (ns)",
+          "When set to a value > 0, reserves space for index tables at the "
+          "beginning of the file.",
+          0, G_MAXUINT64, DEFAULT_RESERVED_MAX_DURATION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_RESERVED_DURATION_REMAINING,
+      g_param_spec_uint64 ("reserved-duration-remaining",
+          "Report the approximate amount of remaining recording space (ns)",
+          "Reports the approximate amount of remaining moov header space "
+          "reserved using reserved-max-duration", 0, G_MAXUINT64, 0,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_RESERVED_MOOV_UPDATE_PERIOD,
+      g_param_spec_uint64 ("reserved-moov-update-period",
+          "Interval at which to update index tables (ns)",
+          "When used with reserved-max-duration, periodically updates the "
+          "index tables with information muxed so far.", 0, G_MAXUINT64,
+          DEFAULT_RESERVED_MOOV_UPDATE_PERIOD,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_RESERVED_BYTES_PER_SEC,
+      g_param_spec_uint ("reserved-bytes-per-sec",
+          "Reserved MOOV bytes per second, per track",
+          "Multiplier for converting reserved-max-duration into bytes of header to reserve, per second, per track",
+          0, 10000, DEFAULT_RESERVED_BYTES_PER_SEC_PER_TRAK,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_RESERVED_PREFILL,
+      g_param_spec_boolean ("reserved-prefill",
+          "Reserved Prefill Samples Table",
+          "Prefill samples table of reserved duration",
+          DEFAULT_RESERVED_PREFILL,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_INTERLEAVE_BYTES,
+      g_param_spec_uint64 ("interleave-bytes", "Interleave (bytes)",
+          "Interleave between streams in bytes",
+          0, G_MAXUINT64, DEFAULT_INTERLEAVE_BYTES,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_INTERLEAVE_TIME,
+      g_param_spec_uint64 ("interleave-time", "Interleave (time)",
+          "Interleave between streams in nanoseconds",
+          0, G_MAXUINT64, DEFAULT_INTERLEAVE_TIME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MAX_RAW_AUDIO_DRIFT,
+      g_param_spec_uint64 ("max-raw-audio-drift", "Max Raw Audio Drift",
+          "Maximum allowed drift of raw audio samples vs. timestamps in nanoseconds",
+          0, G_MAXUINT64, DEFAULT_MAX_RAW_AUDIO_DRIFT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->request_new_pad =
+      GST_DEBUG_FUNCPTR (gst_qt_mux_request_new_pad);
+  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qt_mux_change_state);
+  gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_qt_mux_release_pad);
+}
+
+static void
+gst_qt_mux_pad_reset (GstQTPad * qtpad)
+{
+  qtpad->fourcc = 0;
+  qtpad->is_out_of_order = FALSE;
+  qtpad->sample_size = 0;
+  qtpad->sync = FALSE;
+  qtpad->last_dts = 0;
+  qtpad->sample_offset = 0;
+  qtpad->dts_adjustment = GST_CLOCK_TIME_NONE;
+  qtpad->first_ts = GST_CLOCK_TIME_NONE;
+  qtpad->first_dts = GST_CLOCK_TIME_NONE;
+  qtpad->prepare_buf_func = NULL;
+  qtpad->create_empty_buffer = NULL;
+  qtpad->avg_bitrate = 0;
+  qtpad->max_bitrate = 0;
+  qtpad->total_duration = 0;
+  qtpad->total_bytes = 0;
+  qtpad->sparse = FALSE;
+
+  gst_buffer_replace (&qtpad->last_buf, NULL);
+
+  if (qtpad->tags) {
+    gst_tag_list_unref (qtpad->tags);
+    qtpad->tags = NULL;
+  }
+
+  /* reference owned elsewhere */
+  qtpad->trak = NULL;
+  qtpad->tc_trak = NULL;
+
+  if (qtpad->traf) {
+    atom_traf_free (qtpad->traf);
+    qtpad->traf = NULL;
+  }
+  atom_array_clear (&qtpad->fragment_buffers);
+  if (qtpad->samples)
+    g_array_unref (qtpad->samples);
+  qtpad->samples = NULL;
+
+  /* reference owned elsewhere */
+  qtpad->tfra = NULL;
+
+  qtpad->first_pts = GST_CLOCK_TIME_NONE;
+  qtpad->tc_pos = -1;
+  if (qtpad->first_tc)
+    gst_video_time_code_free (qtpad->first_tc);
+  qtpad->first_tc = NULL;
+
+  if (qtpad->raw_audio_adapter)
+    gst_object_unref (qtpad->raw_audio_adapter);
+  qtpad->raw_audio_adapter = NULL;
+}
+
+/*
+ * Takes GstQTMux back to its initial state
+ */
+static void
+gst_qt_mux_reset (GstQTMux * qtmux, gboolean alloc)
+{
+  GSList *walk;
+
+  qtmux->state = GST_QT_MUX_STATE_NONE;
+  qtmux->header_size = 0;
+  qtmux->mdat_size = 0;
+  qtmux->moov_pos = 0;
+  qtmux->mdat_pos = 0;
+  qtmux->longest_chunk = GST_CLOCK_TIME_NONE;
+  qtmux->fragment_sequence = 0;
+
+  if (qtmux->ftyp) {
+    atom_ftyp_free (qtmux->ftyp);
+    qtmux->ftyp = NULL;
+  }
+  if (qtmux->moov) {
+    atom_moov_free (qtmux->moov);
+    qtmux->moov = NULL;
+  }
+  if (qtmux->mfra) {
+    atom_mfra_free (qtmux->mfra);
+    qtmux->mfra = NULL;
+  }
+  if (qtmux->fast_start_file) {
+    fclose (qtmux->fast_start_file);
+    g_remove (qtmux->fast_start_file_path);
+    qtmux->fast_start_file = NULL;
+  }
+  if (qtmux->moov_recov_file) {
+    fclose (qtmux->moov_recov_file);
+    qtmux->moov_recov_file = NULL;
+  }
+  for (walk = qtmux->extra_atoms; walk; walk = g_slist_next (walk)) {
+    AtomInfo *ainfo = (AtomInfo *) walk->data;
+    ainfo->free_func (ainfo->atom);
+    g_free (ainfo);
+  }
+  g_slist_free (qtmux->extra_atoms);
+  qtmux->extra_atoms = NULL;
+
+  GST_OBJECT_LOCK (qtmux);
+  gst_tag_setter_reset_tags (GST_TAG_SETTER (qtmux));
+  GST_OBJECT_UNLOCK (qtmux);
+
+  /* reset pad data */
+  for (walk = qtmux->sinkpads; walk; walk = g_slist_next (walk)) {
+    GstQTPad *qtpad = (GstQTPad *) walk->data;
+    gst_qt_mux_pad_reset (qtpad);
+
+    /* hm, moov_free above yanked the traks away from us,
+     * so do not free, but do clear */
+    qtpad->trak = NULL;
+  }
+
+  if (alloc) {
+    qtmux->moov = atom_moov_new (qtmux->context);
+    /* ensure all is as nice and fresh as request_new_pad would provide it */
+    for (walk = qtmux->sinkpads; walk; walk = g_slist_next (walk)) {
+      GstQTPad *qtpad = (GstQTPad *) walk->data;
+
+      qtpad->trak = atom_trak_new (qtmux->context);
+      atom_moov_add_trak (qtmux->moov, qtpad->trak);
+    }
+  }
+
+  qtmux->current_pad = NULL;
+  qtmux->current_chunk_size = 0;
+  qtmux->current_chunk_duration = 0;
+  qtmux->current_chunk_offset = -1;
+
+  qtmux->reserved_moov_size = 0;
+  qtmux->last_moov_update = GST_CLOCK_TIME_NONE;
+  qtmux->muxed_since_last_update = 0;
+  qtmux->reserved_duration_remaining = GST_CLOCK_TIME_NONE;
+}
+
+static void
+gst_qt_mux_init (GstQTMux * qtmux, GstQTMuxClass * qtmux_klass)
+{
+  GstElementClass *klass = GST_ELEMENT_CLASS (qtmux_klass);
+  GstPadTemplate *templ;
+
+  templ = gst_element_class_get_pad_template (klass, "src");
+  qtmux->srcpad = gst_pad_new_from_template (templ, "src");
+  gst_pad_use_fixed_caps (qtmux->srcpad);
+  gst_element_add_pad (GST_ELEMENT (qtmux), qtmux->srcpad);
+
+  qtmux->sinkpads = NULL;
+  qtmux->collect = gst_collect_pads_new ();
+  gst_collect_pads_set_event_function (qtmux->collect,
+      GST_DEBUG_FUNCPTR (gst_qt_mux_sink_event), qtmux);
+  gst_collect_pads_set_clip_function (qtmux->collect,
+      GST_DEBUG_FUNCPTR (gst_collect_pads_clip_running_time), qtmux);
+  gst_collect_pads_set_function (qtmux->collect,
+      GST_DEBUG_FUNCPTR (gst_qt_mux_collected), qtmux);
+
+  /* properties set to default upon construction */
+
+  qtmux->reserved_max_duration = DEFAULT_RESERVED_MAX_DURATION;
+  qtmux->reserved_moov_update_period = DEFAULT_RESERVED_MOOV_UPDATE_PERIOD;
+  qtmux->reserved_bytes_per_sec_per_trak =
+      DEFAULT_RESERVED_BYTES_PER_SEC_PER_TRAK;
+  qtmux->interleave_bytes = DEFAULT_INTERLEAVE_BYTES;
+  qtmux->interleave_time = DEFAULT_INTERLEAVE_TIME;
+  qtmux->max_raw_audio_drift = DEFAULT_MAX_RAW_AUDIO_DRIFT;
+
+  /* always need this */
+  qtmux->context =
+      atoms_context_new (gst_qt_mux_map_format_to_flavor (qtmux_klass->format));
+
+  /* internals to initial state */
+  gst_qt_mux_reset (qtmux, TRUE);
+}
+
+
+static void
+gst_qt_mux_finalize (GObject * object)
+{
+  GstQTMux *qtmux = GST_QT_MUX_CAST (object);
+
+  gst_qt_mux_reset (qtmux, FALSE);
+
+  g_free (qtmux->fast_start_file_path);
+  g_free (qtmux->moov_recov_file_path);
+
+  atoms_context_free (qtmux->context);
+  gst_object_unref (qtmux->collect);
+
+  g_slist_free (qtmux->sinkpads);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstBuffer *
+gst_qt_mux_prepare_jpc_buffer (GstQTPad * qtpad, GstBuffer * buf,
+    GstQTMux * qtmux)
+{
+  GstBuffer *newbuf;
+  GstMapInfo map;
+  gsize size;
+
+  GST_LOG_OBJECT (qtmux, "Preparing jpc buffer");
+
+  if (buf == NULL)
+    return NULL;
+
+  size = gst_buffer_get_size (buf);
+  newbuf = gst_buffer_new_and_alloc (size + 8);
+  gst_buffer_copy_into (newbuf, buf, GST_BUFFER_COPY_ALL, 8, size);
+
+  gst_buffer_map (newbuf, &map, GST_MAP_WRITE);
+  GST_WRITE_UINT32_BE (map.data, map.size);
+  GST_WRITE_UINT32_LE (map.data + 4, FOURCC_jp2c);
+
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+
+  return newbuf;
+}
+
+static GstBuffer *
+gst_qt_mux_prepare_tx3g_buffer (GstQTPad * qtpad, GstBuffer * buf,
+    GstQTMux * qtmux)
+{
+  GstBuffer *newbuf;
+  GstMapInfo frommap;
+  GstMapInfo tomap;
+  gsize size;
+  const guint8 *dataend;
+
+  GST_LOG_OBJECT (qtmux, "Preparing tx3g buffer %" GST_PTR_FORMAT, buf);
+
+  if (buf == NULL)
+    return NULL;
+
+  gst_buffer_map (buf, &frommap, GST_MAP_READ);
+
+  dataend = memchr (frommap.data, 0, frommap.size);
+  size = dataend ? dataend - frommap.data : frommap.size;
+  newbuf = gst_buffer_new_and_alloc (size + 2);
+
+  gst_buffer_map (newbuf, &tomap, GST_MAP_WRITE);
+
+  GST_WRITE_UINT16_BE (tomap.data, size);
+  memcpy (tomap.data + 2, frommap.data, size);
+
+  gst_buffer_unmap (newbuf, &tomap);
+  gst_buffer_unmap (buf, &frommap);
+
+  gst_buffer_copy_into (newbuf, buf, GST_BUFFER_COPY_METADATA, 0, size);
+
+  /* gst_buffer_copy_into is trying to be too clever and
+   * won't copy duration when size is different */
+  GST_BUFFER_DURATION (newbuf) = GST_BUFFER_DURATION (buf);
+
+  gst_buffer_unref (buf);
+
+  return newbuf;
+}
+
+static void
+gst_qt_mux_pad_add_ac3_extension (GstQTMux * qtmux, GstQTPad * qtpad,
+    guint8 fscod, guint8 frmsizcod, guint8 bsid, guint8 bsmod, guint8 acmod,
+    guint8 lfe_on)
+{
+  AtomInfo *ext;
+
+  g_return_if_fail (qtpad->trak_ste);
+
+  ext = build_ac3_extension (fscod, bsid, bsmod, acmod, lfe_on, frmsizcod >> 1);        /* bitrate_code is inside frmsizcod */
+
+  sample_table_entry_add_ext_atom (qtpad->trak_ste, ext);
+}
+
+static GstBuffer *
+gst_qt_mux_prepare_parse_ac3_frame (GstQTPad * qtpad, GstBuffer * buf,
+    GstQTMux * qtmux)
+{
+  GstMapInfo map;
+  GstByteReader reader;
+  guint off;
+
+  if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
+    GST_WARNING_OBJECT (qtpad->collect.pad, "Failed to map buffer");
+    return buf;
+  }
+
+  if (G_UNLIKELY (map.size < 8))
+    goto done;
+
+  gst_byte_reader_init (&reader, map.data, map.size);
+  off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffff0000, 0x0b770000,
+      0, map.size);
+
+  if (off != -1) {
+    GstBitReader bits;
+    guint8 fscod, frmsizcod, bsid, bsmod, acmod, lfe_on;
+
+    GST_DEBUG_OBJECT (qtpad->collect.pad, "Found ac3 sync point at offset: %u",
+        off);
+
+    gst_bit_reader_init (&bits, map.data, map.size);
+
+    /* off + sync + crc */
+    gst_bit_reader_skip_unchecked (&bits, off * 8 + 16 + 16);
+
+    fscod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2);
+    frmsizcod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 6);
+    bsid = gst_bit_reader_get_bits_uint8_unchecked (&bits, 5);
+    bsmod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 3);
+    acmod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 3);
+
+    if ((acmod & 0x1) && (acmod != 0x1))        /* 3 front channels */
+      gst_bit_reader_skip_unchecked (&bits, 2);
+    if ((acmod & 0x4))          /* if a surround channel exists */
+      gst_bit_reader_skip_unchecked (&bits, 2);
+    if (acmod == 0x2)           /* if in 2/0 mode */
+      gst_bit_reader_skip_unchecked (&bits, 2);
+
+    lfe_on = gst_bit_reader_get_bits_uint8_unchecked (&bits, 1);
+
+    gst_qt_mux_pad_add_ac3_extension (qtmux, qtpad, fscod, frmsizcod, bsid,
+        bsmod, acmod, lfe_on);
+
+    /* AC-3 spec says that those values should be constant for the
+     * whole stream when muxed in mp4. We trust the input follows it */
+    GST_DEBUG_OBJECT (qtpad->collect.pad, "Data parsed, removing "
+        "prepare buffer function");
+    qtpad->prepare_buf_func = NULL;
+  }
+
+done:
+  gst_buffer_unmap (buf, &map);
+  return buf;
+}
+
+static GstBuffer *
+gst_qt_mux_create_empty_tx3g_buffer (GstQTPad * qtpad, gint64 duration)
+{
+  guint8 *data;
+
+  data = g_malloc (2);
+  GST_WRITE_UINT16_BE (data, 0);
+
+  return gst_buffer_new_wrapped (data, 2);
+}
+
+static void
+gst_qt_mux_add_mp4_tag (GstQTMux * qtmux, const GstTagList * list,
+    AtomUDTA * udta, const char *tag, const char *tag2, guint32 fourcc)
+{
+  switch (gst_tag_get_type (tag)) {
+      /* strings */
+    case G_TYPE_STRING:
+    {
+      gchar *str = NULL;
+
+      if (!gst_tag_list_get_string (list, tag, &str) || !str)
+        break;
+      GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
+          GST_FOURCC_ARGS (fourcc), str);
+      atom_udta_add_str_tag (udta, fourcc, str);
+      g_free (str);
+      break;
+    }
+      /* double */
+    case G_TYPE_DOUBLE:
+    {
+      gdouble value;
+
+      if (!gst_tag_list_get_double (list, tag, &value))
+        break;
+      GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %u",
+          GST_FOURCC_ARGS (fourcc), (gint) value);
+      atom_udta_add_uint_tag (udta, fourcc, 21, (gint) value);
+      break;
+    }
+    case G_TYPE_UINT:
+    {
+      guint value = 0;
+      if (tag2) {
+        /* paired unsigned integers */
+        guint count = 0;
+        gboolean got_tag;
+
+        got_tag = gst_tag_list_get_uint (list, tag, &value);
+        got_tag = gst_tag_list_get_uint (list, tag2, &count) || got_tag;
+        if (!got_tag)
+          break;
+        GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %u/%u",
+            GST_FOURCC_ARGS (fourcc), value, count);
+        atom_udta_add_uint_tag (udta, fourcc, 0,
+            value << 16 | (count & 0xFFFF));
+      } else {
+        /* unpaired unsigned integers */
+        if (!gst_tag_list_get_uint (list, tag, &value))
+          break;
+        GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %u",
+            GST_FOURCC_ARGS (fourcc), value);
+        atom_udta_add_uint_tag (udta, fourcc, 1, value);
+      }
+      break;
+    }
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+static void
+gst_qt_mux_add_mp4_date (GstQTMux * qtmux, const GstTagList * list,
+    AtomUDTA * udta, const char *tag, const char *tag2, guint32 fourcc)
+{
+  GDate *date = NULL;
+  GDateYear year;
+  GDateMonth month;
+  GDateDay day;
+  gchar *str;
+
+  g_return_if_fail (gst_tag_get_type (tag) == G_TYPE_DATE);
+
+  if (!gst_tag_list_get_date (list, tag, &date) || !date)
+    return;
+
+  year = g_date_get_year (date);
+  month = g_date_get_month (date);
+  day = g_date_get_day (date);
+
+  g_date_free (date);
+
+  if (year == G_DATE_BAD_YEAR && month == G_DATE_BAD_MONTH &&
+      day == G_DATE_BAD_DAY) {
+    GST_WARNING_OBJECT (qtmux, "invalid date in tag");
+    return;
+  }
+
+  str = g_strdup_printf ("%u-%u-%u", year, month, day);
+  GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
+      GST_FOURCC_ARGS (fourcc), str);
+  atom_udta_add_str_tag (udta, fourcc, str);
+  g_free (str);
+}
+
+static void
+gst_qt_mux_add_mp4_cover (GstQTMux * qtmux, const GstTagList * list,
+    AtomUDTA * udta, const char *tag, const char *tag2, guint32 fourcc)
+{
+  GValue value = { 0, };
+  GstBuffer *buf;
+  GstSample *sample;
+  GstCaps *caps;
+  GstStructure *structure;
+  gint flags = 0;
+  GstMapInfo map;
+
+  g_return_if_fail (gst_tag_get_type (tag) == GST_TYPE_SAMPLE);
+
+  if (!gst_tag_list_copy_value (&value, list, tag))
+    return;
+
+  sample = gst_value_get_sample (&value);
+
+  if (!sample)
+    goto done;
+
+  buf = gst_sample_get_buffer (sample);
+  if (!buf)
+    goto done;
+
+  caps = gst_sample_get_caps (sample);
+  if (!caps) {
+    GST_WARNING_OBJECT (qtmux, "preview image without caps");
+    goto done;
+  }
+
+  GST_DEBUG_OBJECT (qtmux, "preview image caps %" GST_PTR_FORMAT, caps);
+
+  structure = gst_caps_get_structure (caps, 0);
+  if (gst_structure_has_name (structure, "image/jpeg"))
+    flags = 13;
+  else if (gst_structure_has_name (structure, "image/png"))
+    flags = 14;
+
+  if (!flags) {
+    GST_WARNING_OBJECT (qtmux, "preview image format not supported");
+    goto done;
+  }
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT
+      " -> image size %" G_GSIZE_FORMAT "", GST_FOURCC_ARGS (fourcc), map.size);
+  atom_udta_add_tag (udta, fourcc, flags, map.data, map.size);
+  gst_buffer_unmap (buf, &map);
+done:
+  g_value_unset (&value);
+}
+
+static void
+gst_qt_mux_add_3gp_str (GstQTMux * qtmux, const GstTagList * list,
+    AtomUDTA * udta, const char *tag, const char *tag2, guint32 fourcc)
+{
+  gchar *str = NULL;
+  guint number;
+
+  g_return_if_fail (gst_tag_get_type (tag) == G_TYPE_STRING);
+  g_return_if_fail (!tag2 || gst_tag_get_type (tag2) == G_TYPE_UINT);
+
+  if (!gst_tag_list_get_string (list, tag, &str) || !str)
+    return;
+
+  if (tag2)
+    if (!gst_tag_list_get_uint (list, tag2, &number))
+      tag2 = NULL;
+
+  if (!tag2) {
+    GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
+        GST_FOURCC_ARGS (fourcc), str);
+    atom_udta_add_3gp_str_tag (udta, fourcc, str);
+  } else {
+    GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s/%d",
+        GST_FOURCC_ARGS (fourcc), str, number);
+    atom_udta_add_3gp_str_int_tag (udta, fourcc, str, number);
+  }
+
+  g_free (str);
+}
+
+static void
+gst_qt_mux_add_3gp_date (GstQTMux * qtmux, const GstTagList * list,
+    AtomUDTA * udta, const char *tag, const char *tag2, guint32 fourcc)
+{
+  GDate *date = NULL;
+  GDateYear year;
+
+  g_return_if_fail (gst_tag_get_type (tag) == G_TYPE_DATE);
+
+  if (!gst_tag_list_get_date (list, tag, &date) || !date)
+    return;
+
+  year = g_date_get_year (date);
+  g_date_free (date);
+
+  if (year == G_DATE_BAD_YEAR) {
+    GST_WARNING_OBJECT (qtmux, "invalid date in tag");
+    return;
+  }
+
+  GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %d",
+      GST_FOURCC_ARGS (fourcc), year);
+  atom_udta_add_3gp_uint_tag (udta, fourcc, year);
+}
+
+static void
+gst_qt_mux_add_3gp_location (GstQTMux * qtmux, const GstTagList * list,
+    AtomUDTA * udta, const char *tag, const char *tag2, guint32 fourcc)
+{
+  gdouble latitude = -360, longitude = -360, altitude = 0;
+  gchar *location = NULL;
+  guint8 *data, *ddata;
+  gint size = 0, len = 0;
+  gboolean ret = FALSE;
+
+  g_return_if_fail (strcmp (tag, GST_TAG_GEO_LOCATION_NAME) == 0);
+
+  ret = gst_tag_list_get_string (list, tag, &location);
+  ret |= gst_tag_list_get_double (list, GST_TAG_GEO_LOCATION_LONGITUDE,
+      &longitude);
+  ret |= gst_tag_list_get_double (list, GST_TAG_GEO_LOCATION_LATITUDE,
+      &latitude);
+  ret |= gst_tag_list_get_double (list, GST_TAG_GEO_LOCATION_ELEVATION,
+      &altitude);
+
+  if (!ret)
+    return;
+
+  if (location)
+    len = strlen (location);
+  size += len + 1 + 2;
+
+  /* role + (long, lat, alt) + body + notes */
+  size += 1 + 3 * 4 + 1 + 1;
+
+  data = ddata = g_malloc (size);
+
+  /* language tag */
+  GST_WRITE_UINT16_BE (data, language_code (GST_QT_MUX_DEFAULT_TAG_LANGUAGE));
+  /* location */
+  if (location)
+    memcpy (data + 2, location, len);
+  GST_WRITE_UINT8 (data + 2 + len, 0);
+  data += len + 1 + 2;
+  /* role */
+  GST_WRITE_UINT8 (data, 0);
+  /* long, lat, alt */
+#define QT_WRITE_SFP32(data, fp) GST_WRITE_UINT32_BE(data, (guint32) ((gint) (fp * 65536.0)))
+  QT_WRITE_SFP32 (data + 1, longitude);
+  QT_WRITE_SFP32 (data + 5, latitude);
+  QT_WRITE_SFP32 (data + 9, altitude);
+  /* neither astronomical body nor notes */
+  GST_WRITE_UINT16_BE (data + 13, 0);
+
+  GST_DEBUG_OBJECT (qtmux, "Adding tag 'loci'");
+  atom_udta_add_3gp_tag (udta, fourcc, ddata, size);
+  g_free (ddata);
+}
+
+static void
+gst_qt_mux_add_3gp_keywords (GstQTMux * qtmux, const GstTagList * list,
+    AtomUDTA * udta, const char *tag, const char *tag2, guint32 fourcc)
+{
+  gchar *keywords = NULL;
+  guint8 *data, *ddata;
+  gint size = 0, i;
+  gchar **kwds;
+
+  g_return_if_fail (strcmp (tag, GST_TAG_KEYWORDS) == 0);
+
+  if (!gst_tag_list_get_string (list, tag, &keywords) || !keywords)
+    return;
+
+  kwds = g_strsplit (keywords, ",", 0);
+  g_free (keywords);
+
+  size = 0;
+  for (i = 0; kwds[i]; i++) {
+    /* size byte + null-terminator */
+    size += strlen (kwds[i]) + 1 + 1;
+  }
+
+  /* language tag + count + keywords */
+  size += 2 + 1;
+
+  data = ddata = g_malloc (size);
+
+  /* language tag */
+  GST_WRITE_UINT16_BE (data, language_code (GST_QT_MUX_DEFAULT_TAG_LANGUAGE));
+  /* count */
+  GST_WRITE_UINT8 (data + 2, i);
+  data += 3;
+  /* keywords */
+  for (i = 0; kwds[i]; ++i) {
+    gint len = strlen (kwds[i]);
+
+    GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
+        GST_FOURCC_ARGS (fourcc), kwds[i]);
+    /* size */
+    GST_WRITE_UINT8 (data, len + 1);
+    memcpy (data + 1, kwds[i], len + 1);
+    data += len + 2;
+  }
+
+  g_strfreev (kwds);
+
+  atom_udta_add_3gp_tag (udta, fourcc, ddata, size);
+  g_free (ddata);
+}
+
+static gboolean
+gst_qt_mux_parse_classification_string (GstQTMux * qtmux, const gchar * input,
+    guint32 * p_fourcc, guint16 * p_table, gchar ** p_content)
+{
+  guint32 fourcc;
+  gint table;
+  gint size;
+  const gchar *data;
+
+  data = input;
+  size = strlen (input);
+
+  if (size < 4 + 3 + 1 + 1 + 1) {
+    /* at least the minimum xxxx://y/z */
+    GST_WARNING_OBJECT (qtmux, "Classification tag input (%s) too short, "
+        "ignoring", input);
+    return FALSE;
+  }
+
+  /* read the fourcc */
+  memcpy (&fourcc, data, 4);
+  size -= 4;
+  data += 4;
+
+  if (strncmp (data, "://", 3) != 0) {
+    goto mismatch;
+  }
+  data += 3;
+  size -= 3;
+
+  /* read the table number */
+  if (sscanf (data, "%d", &table) != 1) {
+    goto mismatch;
+  }
+  if (table < 0) {
+    GST_WARNING_OBJECT (qtmux, "Invalid table number in classification tag (%d)"
+        ", table numbers should be positive, ignoring tag", table);
+    return FALSE;
+  }
+
+  /* find the next / */
+  while (size > 0 && data[0] != '/') {
+    data += 1;
+    size -= 1;
+  }
+  if (size == 0) {
+    goto mismatch;
+  }
+  g_assert (data[0] == '/');
+
+  /* skip the '/' */
+  data += 1;
+  size -= 1;
+  if (size == 0) {
+    goto mismatch;
+  }
+
+  /* read up the rest of the string */
+  *p_content = g_strdup (data);
+  *p_table = (guint16) table;
+  *p_fourcc = fourcc;
+  return TRUE;
+
+mismatch:
+  {
+    GST_WARNING_OBJECT (qtmux, "Ignoring classification tag as "
+        "input (%s) didn't match the expected entitycode://table/content",
+        input);
+    return FALSE;
+  }
+}
+
+static void
+gst_qt_mux_add_3gp_classification (GstQTMux * qtmux, const GstTagList * list,
+    AtomUDTA * udta, const char *tag, const char *tag2, guint32 fourcc)
+{
+  gchar *clsf_data = NULL;
+  gint size = 0;
+  guint32 entity = 0;
+  guint16 table = 0;
+  gchar *content = NULL;
+  guint8 *data;
+
+  g_return_if_fail (strcmp (tag, GST_TAG_3GP_CLASSIFICATION) == 0);
+
+  if (!gst_tag_list_get_string (list, tag, &clsf_data) || !clsf_data)
+    return;
+
+  GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
+      GST_FOURCC_ARGS (fourcc), clsf_data);
+
+  /* parse the string, format is:
+   * entityfourcc://table/content
+   */
+  gst_qt_mux_parse_classification_string (qtmux, clsf_data, &entity, &table,
+      &content);
+  g_free (clsf_data);
+  /* +1 for the \0 */
+  size = strlen (content) + 1;
+
+  /* now we have everything, build the atom
+   * atom description is at 3GPP TS 26.244 V8.2.0 (2009-09) */
+  data = g_malloc (4 + 2 + 2 + size);
+  GST_WRITE_UINT32_LE (data, entity);
+  GST_WRITE_UINT16_BE (data + 4, (guint16) table);
+  GST_WRITE_UINT16_BE (data + 6, 0);
+  memcpy (data + 8, content, size);
+  g_free (content);
+
+  atom_udta_add_3gp_tag (udta, fourcc, data, 4 + 2 + 2 + size);
+  g_free (data);
+}
+
+typedef void (*GstQTMuxAddUdtaTagFunc) (GstQTMux * mux,
+    const GstTagList * list, AtomUDTA * udta, const char *tag,
+    const char *tag2, guint32 fourcc);
+
+/*
+ * Struct to record mappings from gstreamer tags to fourcc codes
+ */
+typedef struct _GstTagToFourcc
+{
+  guint32 fourcc;
+  const gchar *gsttag;
+  const gchar *gsttag2;
+  const GstQTMuxAddUdtaTagFunc func;
+} GstTagToFourcc;
+
+/* tag list tags to fourcc matching */
+static const GstTagToFourcc tag_matches_mp4[] = {
+  {FOURCC__alb, GST_TAG_ALBUM, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__ART, GST_TAG_ARTIST, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__cmt, GST_TAG_COMMENT, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__wrt, GST_TAG_COMPOSER, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__gen, GST_TAG_GENRE, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__nam, GST_TAG_TITLE, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_perf, GST_TAG_PERFORMER, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__grp, GST_TAG_GROUPING, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__des, GST_TAG_DESCRIPTION, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__lyr, GST_TAG_LYRICS, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__too, GST_TAG_ENCODER, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_keyw, GST_TAG_KEYWORDS, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__day, GST_TAG_DATE, NULL, gst_qt_mux_add_mp4_date},
+  {FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT,
+      gst_qt_mux_add_mp4_tag},
+  {FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
+      gst_qt_mux_add_mp4_tag},
+  {FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, gst_qt_mux_add_mp4_cover},
+  {FOURCC_covr, GST_TAG_IMAGE, NULL, gst_qt_mux_add_mp4_cover},
+  {0, NULL,}
+};
+
+static const GstTagToFourcc tag_matches_3gp[] = {
+  {FOURCC_titl, GST_TAG_TITLE, NULL, gst_qt_mux_add_3gp_str},
+  {FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, gst_qt_mux_add_3gp_str},
+  {FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, gst_qt_mux_add_3gp_str},
+  {FOURCC_perf, GST_TAG_ARTIST, NULL, gst_qt_mux_add_3gp_str},
+  {FOURCC_auth, GST_TAG_COMPOSER, NULL, gst_qt_mux_add_3gp_str},
+  {FOURCC_gnre, GST_TAG_GENRE, NULL, gst_qt_mux_add_3gp_str},
+  {FOURCC_kywd, GST_TAG_KEYWORDS, NULL, gst_qt_mux_add_3gp_keywords},
+  {FOURCC_yrrc, GST_TAG_DATE, NULL, gst_qt_mux_add_3gp_date},
+  {FOURCC_albm, GST_TAG_ALBUM, GST_TAG_TRACK_NUMBER, gst_qt_mux_add_3gp_str},
+  {FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, gst_qt_mux_add_3gp_location},
+  {FOURCC_clsf, GST_TAG_3GP_CLASSIFICATION, NULL,
+      gst_qt_mux_add_3gp_classification},
+  {0, NULL,}
+};
+
+/* qtdemux produces these for atoms it cannot parse */
+#define GST_QT_DEMUX_PRIVATE_TAG "private-qt-tag"
+
+static void
+gst_qt_mux_add_xmp_tags (GstQTMux * qtmux, const GstTagList * list)
+{
+  GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
+  GstBuffer *xmp = NULL;
+
+  /* adobe specs only have 'quicktime' and 'mp4',
+   * but I guess we can extrapolate to gpp.
+   * Keep mj2 out for now as we don't add any tags for it yet.
+   * If you have further info about xmp on these formats, please share */
+  if (qtmux_klass->format == GST_QT_MUX_FORMAT_MJ2)
+    return;
+
+  GST_DEBUG_OBJECT (qtmux, "Adding xmp tags");
+
+  if (qtmux_klass->format == GST_QT_MUX_FORMAT_QT) {
+    xmp = gst_tag_xmp_writer_tag_list_to_xmp_buffer (GST_TAG_XMP_WRITER (qtmux),
+        list, TRUE);
+    if (xmp)
+      atom_udta_add_xmp_tags (&qtmux->moov->udta, xmp);
+  } else {
+    AtomInfo *ainfo;
+    /* for isom/mp4, it is a top level uuid atom */
+    xmp = gst_tag_xmp_writer_tag_list_to_xmp_buffer (GST_TAG_XMP_WRITER (qtmux),
+        list, TRUE);
+    if (xmp) {
+      ainfo = build_uuid_xmp_atom (xmp);
+      if (ainfo) {
+        qtmux->extra_atoms = g_slist_prepend (qtmux->extra_atoms, ainfo);
+      }
+    }
+  }
+  if (xmp)
+    gst_buffer_unref (xmp);
+}
+
+static void
+gst_qt_mux_add_metadata_tags (GstQTMux * qtmux, const GstTagList * list,
+    AtomUDTA * udta)
+{
+  GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
+  guint32 fourcc;
+  gint i;
+  const gchar *tag, *tag2;
+  const GstTagToFourcc *tag_matches;
+
+  switch (qtmux_klass->format) {
+    case GST_QT_MUX_FORMAT_3GP:
+      tag_matches = tag_matches_3gp;
+      break;
+    case GST_QT_MUX_FORMAT_MJ2:
+      tag_matches = NULL;
+      break;
+    default:
+      /* sort of iTunes style for mp4 and QT (?) */
+      tag_matches = tag_matches_mp4;
+      break;
+  }
+
+  if (!tag_matches)
+    return;
+
+  /* Clear existing tags so we don't add them over and over */
+  atom_udta_clear_tags (udta);
+
+  for (i = 0; tag_matches[i].fourcc; i++) {
+    fourcc = tag_matches[i].fourcc;
+    tag = tag_matches[i].gsttag;
+    tag2 = tag_matches[i].gsttag2;
+
+    g_assert (tag_matches[i].func);
+    tag_matches[i].func (qtmux, list, udta, tag, tag2, fourcc);
+  }
+
+  /* add unparsed blobs if present */
+  if (gst_tag_exists (GST_QT_DEMUX_PRIVATE_TAG)) {
+    guint num_tags;
+
+    num_tags = gst_tag_list_get_tag_size (list, GST_QT_DEMUX_PRIVATE_TAG);
+    for (i = 0; i < num_tags; ++i) {
+      GstSample *sample = NULL;
+      GstBuffer *buf;
+      const GstStructure *s;
+
+      if (!gst_tag_list_get_sample_index (list, GST_QT_DEMUX_PRIVATE_TAG, i,
+              &sample))
+        continue;
+      buf = gst_sample_get_buffer (sample);
+
+      if (buf && (s = gst_sample_get_info (sample))) {
+        const gchar *style = NULL;
+        GstMapInfo map;
+
+        gst_buffer_map (buf, &map, GST_MAP_READ);
+        GST_DEBUG_OBJECT (qtmux,
+            "Found private tag %d/%d; size %" G_GSIZE_FORMAT ", info %"
+            GST_PTR_FORMAT, i, num_tags, map.size, s);
+        if (s && (style = gst_structure_get_string (s, "style"))) {
+          /* try to prevent some style tag ending up into another variant
+           * (todo: make into a list if more cases) */
+          if ((strcmp (style, "itunes") == 0 &&
+                  qtmux_klass->format == GST_QT_MUX_FORMAT_MP4) ||
+              (strcmp (style, "iso") == 0 &&
+                  qtmux_klass->format == GST_QT_MUX_FORMAT_3GP)) {
+            GST_DEBUG_OBJECT (qtmux, "Adding private tag");
+            atom_udta_add_blob_tag (udta, map.data, map.size);
+          }
+        }
+        gst_buffer_unmap (buf, &map);
+      }
+      gst_sample_unref (sample);
+    }
+  }
+
+  return;
+}
+
+/*
+ * Gets the tagsetter iface taglist and puts the known tags
+ * into the output stream
+ */
+static void
+gst_qt_mux_setup_metadata (GstQTMux * qtmux)
+{
+  const GstTagList *tags = NULL;
+  GSList *walk;
+
+  GST_OBJECT_LOCK (qtmux);
+  if (qtmux->tags_changed) {
+    tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (qtmux));
+    qtmux->tags_changed = FALSE;
+  }
+  GST_OBJECT_UNLOCK (qtmux);
+
+  GST_LOG_OBJECT (qtmux, "tags: %" GST_PTR_FORMAT, tags);
+
+  if (tags && !gst_tag_list_is_empty (tags)) {
+    GstTagList *copy = gst_tag_list_copy (tags);
+
+    GST_DEBUG_OBJECT (qtmux, "Removing bogus tags");
+    gst_tag_list_remove_tag (copy, GST_TAG_VIDEO_CODEC);
+    gst_tag_list_remove_tag (copy, GST_TAG_AUDIO_CODEC);
+    gst_tag_list_remove_tag (copy, GST_TAG_CONTAINER_FORMAT);
+
+    GST_DEBUG_OBJECT (qtmux, "Formatting tags");
+    gst_qt_mux_add_metadata_tags (qtmux, copy, &qtmux->moov->udta);
+    gst_qt_mux_add_xmp_tags (qtmux, copy);
+    gst_tag_list_unref (copy);
+  } else {
+    GST_DEBUG_OBJECT (qtmux, "No new tags received");
+  }
+
+  for (walk = qtmux->sinkpads; walk; walk = g_slist_next (walk)) {
+    GstCollectData *cdata = (GstCollectData *) walk->data;
+    GstQTPad *qpad = (GstQTPad *) cdata;
+    GstPad *pad = qpad->collect.pad;
+
+    if (qpad->tags_changed && qpad->tags) {
+      GST_DEBUG_OBJECT (pad, "Adding tags");
+      gst_tag_list_remove_tag (qpad->tags, GST_TAG_CONTAINER_FORMAT);
+      gst_qt_mux_add_metadata_tags (qtmux, qpad->tags, &qpad->trak->udta);
+      qpad->tags_changed = FALSE;
+      GST_DEBUG_OBJECT (pad, "Tags added");
+    } else {
+      GST_DEBUG_OBJECT (pad, "No new tags received");
+    }
+  }
+}
+
+static inline GstBuffer *
+_gst_buffer_new_take_data (guint8 * data, guint size)
+{
+  GstBuffer *buf;
+
+  buf = gst_buffer_new ();
+  gst_buffer_append_memory (buf,
+      gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
+
+  return buf;
+}
+
+static GstFlowReturn
+gst_qt_mux_send_buffer (GstQTMux * qtmux, GstBuffer * buf, guint64 * offset,
+    gboolean mind_fast)
+{
+  GstFlowReturn res;
+  gsize size;
+
+  g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
+
+  size = gst_buffer_get_size (buf);
+  GST_LOG_OBJECT (qtmux, "sending buffer size %" G_GSIZE_FORMAT, size);
+
+  if (mind_fast && qtmux->fast_start_file) {
+    GstMapInfo map;
+    gint ret;
+
+    GST_LOG_OBJECT (qtmux, "to temporary file");
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    ret = fwrite (map.data, sizeof (guint8), map.size, qtmux->fast_start_file);
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    if (ret != size)
+      goto write_error;
+    else
+      res = GST_FLOW_OK;
+  } else {
+    GST_LOG_OBJECT (qtmux, "downstream");
+    res = gst_pad_push (qtmux->srcpad, buf);
+  }
+
+  if (G_LIKELY (offset))
+    *offset += size;
+
+  return res;
+
+  /* ERRORS */
+write_error:
+  {
+    GST_ELEMENT_ERROR (qtmux, RESOURCE, WRITE,
+        ("Failed to write to temporary file"), GST_ERROR_SYSTEM);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static gboolean
+gst_qt_mux_seek_to_beginning (FILE * f)
+{
+#ifdef HAVE_FSEEKO
+  if (fseeko (f, (off_t) 0, SEEK_SET) != 0)
+    return FALSE;
+#elif defined (G_OS_UNIX) || defined (G_OS_WIN32)
+  if (lseek (fileno (f), (off_t) 0, SEEK_SET) == (off_t) - 1)
+    return FALSE;
+#else
+  if (fseek (f, (long) 0, SEEK_SET) != 0)
+    return FALSE;
+#endif
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_qt_mux_send_buffered_data (GstQTMux * qtmux, guint64 * offset)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBuffer *buf = NULL;
+
+  if (fflush (qtmux->fast_start_file))
+    goto flush_failed;
+
+  if (!gst_qt_mux_seek_to_beginning (qtmux->fast_start_file))
+    goto seek_failed;
+
+  /* hm, this could all take a really really long time,
+   * but there may not be another way to get moov atom first
+   * (somehow optimize copy?) */
+  GST_DEBUG_OBJECT (qtmux, "Sending buffered data");
+  while (ret == GST_FLOW_OK) {
+    const int bufsize = 4096;
+    GstMapInfo map;
+    gsize size;
+
+    buf = gst_buffer_new_and_alloc (bufsize);
+    gst_buffer_map (buf, &map, GST_MAP_WRITE);
+    size = fread (map.data, sizeof (guint8), bufsize, qtmux->fast_start_file);
+    if (size == 0) {
+      gst_buffer_unmap (buf, &map);
+      break;
+    }
+    GST_LOG_OBJECT (qtmux, "Pushing buffered buffer of size %d", (gint) size);
+    gst_buffer_unmap (buf, &map);
+    if (size != bufsize)
+      gst_buffer_set_size (buf, size);
+    ret = gst_qt_mux_send_buffer (qtmux, buf, offset, FALSE);
+    buf = NULL;
+  }
+  if (buf)
+    gst_buffer_unref (buf);
+
+  if (ftruncate (fileno (qtmux->fast_start_file), 0))
+    goto seek_failed;
+  if (!gst_qt_mux_seek_to_beginning (qtmux->fast_start_file))
+    goto seek_failed;
+
+  return ret;
+
+  /* ERRORS */
+flush_failed:
+  {
+    GST_ELEMENT_ERROR (qtmux, RESOURCE, WRITE,
+        ("Failed to flush temporary file"), GST_ERROR_SYSTEM);
+    ret = GST_FLOW_ERROR;
+    goto fail;
+  }
+seek_failed:
+  {
+    GST_ELEMENT_ERROR (qtmux, RESOURCE, SEEK,
+        ("Failed to seek temporary file"), GST_ERROR_SYSTEM);
+    ret = GST_FLOW_ERROR;
+    goto fail;
+  }
+fail:
+  {
+    /* clear descriptor so we don't remove temp file later on,
+     * might be possible to recover */
+    fclose (qtmux->fast_start_file);
+    qtmux->fast_start_file = NULL;
+    return ret;
+  }
+}
+
+/*
+ * Sends the initial mdat atom fields (size fields and fourcc type),
+ * the subsequent buffers are considered part of it's data.
+ * As we can't predict the amount of data that we are going to place in mdat
+ * we need to record the position of the size field in the stream so we can
+ * seek back to it later and update when the streams have finished.
+ */
+static GstFlowReturn
+gst_qt_mux_send_mdat_header (GstQTMux * qtmux, guint64 * off, guint64 size,
+    gboolean extended, gboolean fsync_after)
+{
+  GstBuffer *buf;
+  GstMapInfo map;
+
+  GST_DEBUG_OBJECT (qtmux, "Sending mdat's atom header, "
+      "size %" G_GUINT64_FORMAT, size);
+
+  /* if the qtmux state is EOS, really write the mdat, otherwise
+   * allow size == 0 for a placeholder atom */
+  if (qtmux->state == GST_QT_MUX_STATE_EOS || size > 0)
+    size += 8;
+
+  if (extended) {
+    gboolean large_file = (size > MDAT_LARGE_FILE_LIMIT);
+    /* Always write 16-bytes, but put a free atom first
+     * if the size is < 4GB. */
+    buf = gst_buffer_new_and_alloc (16);
+    gst_buffer_map (buf, &map, GST_MAP_WRITE);
+
+    if (large_file) {
+      /* Write extended mdat header and large_size field */
+      GST_WRITE_UINT32_BE (map.data, 1);
+      GST_WRITE_UINT32_LE (map.data + 4, FOURCC_mdat);
+      GST_WRITE_UINT64_BE (map.data + 8, size + 8);
+    } else {
+      /* Write an empty free atom, then standard 32-bit mdat */
+      GST_WRITE_UINT32_BE (map.data, 8);
+      GST_WRITE_UINT32_LE (map.data + 4, FOURCC_free);
+      GST_WRITE_UINT32_BE (map.data + 8, size);
+      GST_WRITE_UINT32_LE (map.data + 12, FOURCC_mdat);
+    }
+    gst_buffer_unmap (buf, &map);
+  } else {
+    buf = gst_buffer_new_and_alloc (8);
+    gst_buffer_map (buf, &map, GST_MAP_WRITE);
+
+    /* Vanilla 32-bit mdat */
+    GST_WRITE_UINT32_BE (map.data, size);
+    GST_WRITE_UINT32_LE (map.data + 4, FOURCC_mdat);
+    gst_buffer_unmap (buf, &map);
+  }
+
+  GST_LOG_OBJECT (qtmux, "Pushing mdat header");
+  if (fsync_after)
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_SYNC_AFTER);
+
+  return gst_qt_mux_send_buffer (qtmux, buf, off, FALSE);
+
+}
+
+/*
+ * We get the position of the mdat size field, seek back to it
+ * and overwrite with the real value
+ */
+static GstFlowReturn
+gst_qt_mux_update_mdat_size (GstQTMux * qtmux, guint64 mdat_pos,
+    guint64 mdat_size, guint64 * offset, gboolean fsync_after)
+{
+  GstSegment segment;
+
+  /* We must have recorded the mdat position for this to work */
+  g_assert (mdat_pos != 0);
+
+  /* seek and rewrite the header */
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  segment.start = mdat_pos;
+  gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
+
+  return gst_qt_mux_send_mdat_header (qtmux, offset, mdat_size, TRUE,
+      fsync_after);
+}
+
+static GstFlowReturn
+gst_qt_mux_send_ftyp (GstQTMux * qtmux, guint64 * off)
+{
+  GstBuffer *buf;
+  guint64 size = 0, offset = 0;
+  guint8 *data = NULL;
+
+  GST_DEBUG_OBJECT (qtmux, "Sending ftyp atom");
+
+  if (!atom_ftyp_copy_data (qtmux->ftyp, &data, &size, &offset))
+    goto serialize_error;
+
+  buf = _gst_buffer_new_take_data (data, offset);
+
+  GST_LOG_OBJECT (qtmux, "Pushing ftyp");
+  return gst_qt_mux_send_buffer (qtmux, buf, off, FALSE);
+
+  /* ERRORS */
+serialize_error:
+  {
+    GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
+        ("Failed to serialize ftyp"));
+    return GST_FLOW_ERROR;
+  }
+}
+
+static void
+gst_qt_mux_prepare_ftyp (GstQTMux * qtmux, AtomFTYP ** p_ftyp,
+    GstBuffer ** p_prefix)
+{
+  GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
+  guint32 major, version;
+  GList *comp;
+  GstBuffer *prefix = NULL;
+  AtomFTYP *ftyp = NULL;
+
+  GST_DEBUG_OBJECT (qtmux, "Preparing ftyp and possible prefix atom");
+
+  /* init and send context and ftyp based on current property state */
+  gst_qt_mux_map_format_to_header (qtmux_klass->format, &prefix, &major,
+      &version, &comp, qtmux->moov, qtmux->longest_chunk,
+      qtmux->fast_start_file != NULL);
+  ftyp = atom_ftyp_new (qtmux->context, major, version, comp);
+  if (comp)
+    g_list_free (comp);
+  if (prefix) {
+    if (p_prefix)
+      *p_prefix = prefix;
+    else
+      gst_buffer_unref (prefix);
+  }
+  *p_ftyp = ftyp;
+}
+
+static GstFlowReturn
+gst_qt_mux_prepare_and_send_ftyp (GstQTMux * qtmux)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBuffer *prefix = NULL;
+
+  GST_DEBUG_OBJECT (qtmux, "Preparing to send ftyp atom");
+
+  /* init and send context and ftyp based on current property state */
+  if (qtmux->ftyp) {
+    atom_ftyp_free (qtmux->ftyp);
+    qtmux->ftyp = NULL;
+  }
+  gst_qt_mux_prepare_ftyp (qtmux, &qtmux->ftyp, &prefix);
+  if (prefix) {
+    ret = gst_qt_mux_send_buffer (qtmux, prefix, &qtmux->header_size, FALSE);
+    if (ret != GST_FLOW_OK)
+      return ret;
+  }
+  return gst_qt_mux_send_ftyp (qtmux, &qtmux->header_size);
+}
+
+static void
+gst_qt_mux_set_header_on_caps (GstQTMux * mux, GstBuffer * buf)
+{
+  GstStructure *structure;
+  GValue array = { 0 };
+  GValue value = { 0 };
+  GstCaps *caps, *tcaps;
+
+  tcaps = gst_pad_get_current_caps (mux->srcpad);
+  caps = gst_caps_copy (tcaps);
+  gst_caps_unref (tcaps);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  g_value_init (&array, GST_TYPE_ARRAY);
+
+  GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
+  g_value_init (&value, GST_TYPE_BUFFER);
+  gst_value_take_buffer (&value, gst_buffer_ref (buf));
+  gst_value_array_append_value (&array, &value);
+  g_value_unset (&value);
+
+  gst_structure_set_value (structure, "streamheader", &array);
+  g_value_unset (&array);
+  gst_pad_set_caps (mux->srcpad, caps);
+  gst_caps_unref (caps);
+}
+
+/*
+ * Write out a free space atom. The offset is adjusted by the full
+ * size, but a smaller buffer is sent
+ */
+static GstFlowReturn
+gst_qt_mux_send_free_atom (GstQTMux * qtmux, guint64 * off, guint32 size,
+    gboolean fsync_after)
+{
+  Atom *node_header;
+  GstBuffer *buf;
+  guint8 *data = NULL;
+  guint64 offset = 0, bsize = 0;
+  GstFlowReturn ret;
+
+  GST_DEBUG_OBJECT (qtmux, "Sending free atom header of size %u", size);
+
+  /* We can't make a free space atom smaller than the header */
+  if (size < 8)
+    goto too_small;
+
+  node_header = g_malloc0 (sizeof (Atom));
+  node_header->type = FOURCC_free;
+  node_header->size = size;
+
+  bsize = offset = 0;
+  if (atom_copy_data (node_header, &data, &bsize, &offset) == 0)
+    goto serialize_error;
+
+  buf = _gst_buffer_new_take_data (data, offset);
+  g_free (node_header);
+
+  if (fsync_after)
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_SYNC_AFTER);
+
+  GST_LOG_OBJECT (qtmux, "Pushing free atom");
+  ret = gst_qt_mux_send_buffer (qtmux, buf, off, FALSE);
+
+  if (off) {
+    GstSegment segment;
+
+    *off += size - 8;
+
+    /* Make sure downstream position ends up at the end of this free box */
+    gst_segment_init (&segment, GST_FORMAT_BYTES);
+    segment.start = *off;
+    gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
+  }
+
+  return ret;
+
+  /* ERRORS */
+too_small:
+  {
+    GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
+        ("Not enough free reserved space"));
+    return GST_FLOW_ERROR;
+  }
+serialize_error:
+  {
+    GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
+        ("Failed to serialize mdat"));
+    g_free (node_header);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static void
+gst_qt_mux_configure_moov (GstQTMux * qtmux)
+{
+  gboolean fragmented = FALSE;
+  guint32 timescale;
+
+  GST_OBJECT_LOCK (qtmux);
+  timescale = qtmux->timescale;
+  if (qtmux->mux_mode == GST_QT_MUX_MODE_FRAGMENTED ||
+      qtmux->mux_mode == GST_QT_MUX_MODE_FRAGMENTED_STREAMABLE)
+    fragmented = TRUE;
+  GST_OBJECT_UNLOCK (qtmux);
+
+  /* inform lower layers of our property wishes, and determine duration.
+   * Let moov take care of this using its list of traks;
+   * so that released pads are also included */
+  GST_DEBUG_OBJECT (qtmux, "Updating timescale to %" G_GUINT32_FORMAT,
+      timescale);
+  atom_moov_update_timescale (qtmux->moov, timescale);
+  atom_moov_set_fragmented (qtmux->moov, fragmented);
+
+  atom_moov_update_duration (qtmux->moov);
+}
+
+static GstFlowReturn
+gst_qt_mux_send_moov (GstQTMux * qtmux, guint64 * _offset,
+    guint64 padded_moov_size, gboolean mind_fast, gboolean fsync_after)
+{
+  guint64 offset = 0, size = 0;
+  guint8 *data;
+  GstBuffer *buf;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GSList *walk;
+  guint64 current_time = atoms_get_current_qt_time ();
+
+  /* update modification times */
+  qtmux->moov->mvhd.time_info.modification_time = current_time;
+  for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
+    GstCollectData *cdata = (GstCollectData *) walk->data;
+    GstQTPad *qtpad = (GstQTPad *) cdata;
+
+    qtpad->trak->mdia.mdhd.time_info.modification_time = current_time;
+    qtpad->trak->tkhd.modification_time = current_time;
+  }
+
+  /* serialize moov */
+  offset = size = 0;
+  data = NULL;
+  GST_LOG_OBJECT (qtmux, "Copying movie header into buffer");
+  if (!atom_moov_copy_data (qtmux->moov, &data, &size, &offset))
+    goto serialize_error;
+  qtmux->last_moov_size = offset;
+
+  /* Check we have enough reserved space for this and a Free atom */
+  if (padded_moov_size > 0 && offset + 8 > padded_moov_size)
+    goto too_small_reserved;
+  buf = _gst_buffer_new_take_data (data, offset);
+  GST_DEBUG_OBJECT (qtmux, "Pushing moov atoms");
+
+  /* If at EOS, this is the final moov, put in the streamheader
+   * (apparently used by a flumotion util) */
+  if (qtmux->state == GST_QT_MUX_STATE_EOS)
+    gst_qt_mux_set_header_on_caps (qtmux, buf);
+
+  if (fsync_after)
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_SYNC_AFTER);
+  ret = gst_qt_mux_send_buffer (qtmux, buf, _offset, mind_fast);
+
+  /* Write out a free atom if needed */
+  if (ret == GST_FLOW_OK && offset < padded_moov_size) {
+    GST_LOG_OBJECT (qtmux, "Writing out free atom of size %u",
+        (guint32) (padded_moov_size - offset));
+    ret =
+        gst_qt_mux_send_free_atom (qtmux, _offset, padded_moov_size - offset,
+        fsync_after);
+  }
+
+  return ret;
+too_small_reserved:
+  {
+    GST_ELEMENT_ERROR (qtmux, STREAM, MUX,
+        ("Not enough free reserved header space"),
+        ("Needed %" G_GUINT64_FORMAT " bytes, reserved %" G_GUINT64_FORMAT,
+            offset, padded_moov_size));
+    return GST_FLOW_ERROR;
+  }
+serialize_error:
+  {
+    g_free (data);
+    return GST_FLOW_ERROR;
+  }
+}
+
+/* either calculates size of extra atoms or pushes them */
+static GstFlowReturn
+gst_qt_mux_send_extra_atoms (GstQTMux * qtmux, gboolean send, guint64 * offset,
+    gboolean mind_fast)
+{
+  GSList *walk;
+  guint64 loffset = 0, size = 0;
+  guint8 *data;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  for (walk = qtmux->extra_atoms; walk; walk = g_slist_next (walk)) {
+    AtomInfo *ainfo = (AtomInfo *) walk->data;
+
+    loffset = size = 0;
+    data = NULL;
+    if (!ainfo->copy_data_func (ainfo->atom,
+            send ? &data : NULL, &size, &loffset))
+      goto serialize_error;
+
+    if (send) {
+      GstBuffer *buf;
+
+      GST_DEBUG_OBJECT (qtmux,
+          "Pushing extra top-level atom %" GST_FOURCC_FORMAT,
+          GST_FOURCC_ARGS (ainfo->atom->type));
+      buf = _gst_buffer_new_take_data (data, loffset);
+      ret = gst_qt_mux_send_buffer (qtmux, buf, offset, FALSE);
+      if (ret != GST_FLOW_OK)
+        break;
+    } else {
+      if (offset)
+        *offset += loffset;
+    }
+  }
+
+  return ret;
+
+serialize_error:
+  {
+    g_free (data);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static gboolean
+gst_qt_mux_downstream_is_seekable (GstQTMux * qtmux)
+{
+  gboolean seekable = FALSE;
+  GstQuery *query = gst_query_new_seeking (GST_FORMAT_BYTES);
+
+  if (gst_pad_peer_query (qtmux->srcpad, query)) {
+    gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
+    GST_INFO_OBJECT (qtmux, "downstream is %sseekable", seekable ? "" : "not ");
+  } else {
+    /* have to assume seeking is not supported if query not handled downstream */
+    GST_WARNING_OBJECT (qtmux, "downstream did not handle seeking query");
+    seekable = FALSE;
+  }
+  gst_query_unref (query);
+
+  return seekable;
+}
+
+static void
+gst_qt_mux_prepare_moov_recovery (GstQTMux * qtmux)
+{
+  GSList *walk;
+  gboolean fail = FALSE;
+  AtomFTYP *ftyp = NULL;
+  GstBuffer *prefix = NULL;
+
+  GST_DEBUG_OBJECT (qtmux, "Opening moov recovery file: %s",
+      qtmux->moov_recov_file_path);
+
+  qtmux->moov_recov_file = g_fopen (qtmux->moov_recov_file_path, "wb+");
+  if (qtmux->moov_recov_file == NULL) {
+    GST_WARNING_OBJECT (qtmux, "Failed to open moov recovery file in %s",
+        qtmux->moov_recov_file_path);
+    return;
+  }
+
+  gst_qt_mux_prepare_ftyp (qtmux, &ftyp, &prefix);
+
+  if (!atoms_recov_write_headers (qtmux->moov_recov_file, ftyp, prefix,
+          qtmux->moov, qtmux->timescale, g_slist_length (qtmux->sinkpads))) {
+    GST_WARNING_OBJECT (qtmux, "Failed to write moov recovery file " "headers");
+    goto fail;
+  }
+
+  atom_ftyp_free (ftyp);
+  if (prefix)
+    gst_buffer_unref (prefix);
+
+  for (walk = qtmux->sinkpads; walk && !fail; walk = g_slist_next (walk)) {
+    GstCollectData *cdata = (GstCollectData *) walk->data;
+    GstQTPad *qpad = (GstQTPad *) cdata;
+    /* write info for each stream */
+    fail = atoms_recov_write_trak_info (qtmux->moov_recov_file, qpad->trak);
+    if (fail) {
+      GST_WARNING_OBJECT (qtmux, "Failed to write trak info to recovery "
+          "file");
+      break;
+    }
+  }
+
+  return;
+
+fail:
+  /* cleanup */
+  fclose (qtmux->moov_recov_file);
+  qtmux->moov_recov_file = NULL;
+}
+
+static guint64
+prefill_get_block_index (GstQTMux * qtmux, GstQTPad * qpad)
+{
+  switch (qpad->fourcc) {
+    case FOURCC_apch:
+    case FOURCC_apcn:
+    case FOURCC_apcs:
+    case FOURCC_apco:
+    case FOURCC_ap4h:
+    case FOURCC_ap4x:
+      return qpad->sample_offset;
+    case FOURCC_sowt:
+    case FOURCC_twos:
+      return gst_util_uint64_scale_ceil (qpad->sample_offset,
+          qpad->expected_sample_duration_n,
+          qpad->expected_sample_duration_d *
+          atom_trak_get_timescale (qpad->trak));
+    default:
+      return -1;
+  }
+}
+
+static guint
+prefill_get_sample_size (GstQTMux * qtmux, GstQTPad * qpad)
+{
+  switch (qpad->fourcc) {
+    case FOURCC_apch:
+      if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 480) {
+        return 300000;
+      } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 576) {
+        return 350000;
+      } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 720) {
+        return 525000;
+      } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 1080) {
+        return 1050000;
+      } else {
+        return 4150000;
+      }
+      break;
+    case FOURCC_apcn:
+      if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 480) {
+        return 200000;
+      } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 576) {
+        return 250000;
+      } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 720) {
+        return 350000;
+      } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 1080) {
+        return 700000;
+      } else {
+        return 2800000;
+      }
+      break;
+    case FOURCC_apcs:
+      if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 480) {
+        return 150000;
+      } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 576) {
+        return 200000;
+      } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 720) {
+        return 250000;
+      } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 1080) {
+        return 500000;
+      } else {
+        return 2800000;
+      }
+      break;
+    case FOURCC_apco:
+      if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 480) {
+        return 80000;
+      } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 576) {
+        return 100000;
+      } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 720) {
+        return 150000;
+      } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 1080) {
+        return 250000;
+      } else {
+        return 900000;
+      }
+      break;
+    case FOURCC_sowt:
+    case FOURCC_twos:{
+      guint64 block_idx;
+      guint64 next_sample_offset;
+
+      block_idx = prefill_get_block_index (qtmux, qpad);
+      next_sample_offset =
+          gst_util_uint64_scale (block_idx + 1,
+          qpad->expected_sample_duration_d *
+          atom_trak_get_timescale (qpad->trak),
+          qpad->expected_sample_duration_n);
+
+      return (next_sample_offset - qpad->sample_offset) * qpad->sample_size;
+    }
+    case FOURCC_ap4h:
+    case FOURCC_ap4x:
+    default:
+      GST_ERROR_OBJECT (qtmux, "unsupported codec for pre-filling");
+      return -1;
+  }
+
+  return -1;
+}
+
+static GstClockTime
+prefill_get_next_timestamp (GstQTMux * qtmux, GstQTPad * qpad)
+{
+  switch (qpad->fourcc) {
+    case FOURCC_apch:
+    case FOURCC_apcn:
+    case FOURCC_apcs:
+    case FOURCC_apco:
+    case FOURCC_ap4h:
+    case FOURCC_ap4x:
+      return gst_util_uint64_scale (qpad->sample_offset + 1,
+          qpad->expected_sample_duration_d * GST_SECOND,
+          qpad->expected_sample_duration_n);
+    case FOURCC_sowt:
+    case FOURCC_twos:{
+      guint64 block_idx;
+      guint64 next_sample_offset;
+
+      block_idx = prefill_get_block_index (qtmux, qpad);
+      next_sample_offset =
+          gst_util_uint64_scale (block_idx + 1,
+          qpad->expected_sample_duration_d *
+          atom_trak_get_timescale (qpad->trak),
+          qpad->expected_sample_duration_n);
+
+      return gst_util_uint64_scale (next_sample_offset, GST_SECOND,
+          atom_trak_get_timescale (qpad->trak));
+    }
+    default:
+      GST_ERROR_OBJECT (qtmux, "unsupported codec for pre-filling");
+      return -1;
+  }
+
+  return -1;
+}
+
+static GstBuffer *
+prefill_raw_audio_prepare_buf_func (GstQTPad * qtpad, GstBuffer * buf,
+    GstQTMux * qtmux)
+{
+  guint64 block_idx;
+  guint64 nsamples;
+  GstClockTime input_timestamp;
+  guint64 input_timestamp_distance;
+
+  if (buf)
+    gst_adapter_push (qtpad->raw_audio_adapter, buf);
+
+  block_idx = gst_util_uint64_scale_ceil (qtpad->raw_audio_adapter_offset,
+      qtpad->expected_sample_duration_n,
+      qtpad->expected_sample_duration_d *
+      atom_trak_get_timescale (qtpad->trak));
+  nsamples =
+      gst_util_uint64_scale (block_idx + 1,
+      qtpad->expected_sample_duration_d * atom_trak_get_timescale (qtpad->trak),
+      qtpad->expected_sample_duration_n) - qtpad->raw_audio_adapter_offset;
+
+  if ((!GST_COLLECT_PADS_STATE_IS_SET (&qtpad->collect,
+              GST_COLLECT_PADS_STATE_EOS)
+          && gst_adapter_available (qtpad->raw_audio_adapter) <
+          nsamples * qtpad->sample_size)
+      || gst_adapter_available (qtpad->raw_audio_adapter) == 0) {
+    return NULL;
+  }
+
+  input_timestamp =
+      gst_adapter_prev_pts (qtpad->raw_audio_adapter,
+      &input_timestamp_distance);
+  if (input_timestamp != GST_CLOCK_TIME_NONE)
+    input_timestamp +=
+        gst_util_uint64_scale (input_timestamp_distance, GST_SECOND,
+        qtpad->sample_size * atom_trak_get_timescale (qtpad->trak));
+
+  buf =
+      gst_adapter_take_buffer (qtpad->raw_audio_adapter,
+      !GST_COLLECT_PADS_STATE_IS_SET (&qtpad->collect,
+          GST_COLLECT_PADS_STATE_EOS) ? nsamples *
+      qtpad->sample_size : gst_adapter_available (qtpad->raw_audio_adapter));
+  GST_BUFFER_PTS (buf) = input_timestamp;
+  GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
+  GST_BUFFER_DURATION (buf) = GST_CLOCK_TIME_NONE;
+
+  qtpad->raw_audio_adapter_offset += nsamples;
+
+  /* Check if we have yet another block of raw audio in the adapter */
+  nsamples =
+      gst_util_uint64_scale (block_idx + 2,
+      qtpad->expected_sample_duration_d * atom_trak_get_timescale (qtpad->trak),
+      qtpad->expected_sample_duration_n) - qtpad->raw_audio_adapter_offset;
+  if (gst_adapter_available (qtpad->raw_audio_adapter) >=
+      nsamples * qtpad->sample_size) {
+    input_timestamp =
+        gst_adapter_prev_pts (qtpad->raw_audio_adapter,
+        &input_timestamp_distance);
+    if (input_timestamp != GST_CLOCK_TIME_NONE)
+      input_timestamp +=
+          gst_util_uint64_scale (input_timestamp_distance, GST_SECOND,
+          qtpad->sample_size * atom_trak_get_timescale (qtpad->trak));
+    qtpad->raw_audio_adapter_pts = input_timestamp;
+  } else {
+    qtpad->raw_audio_adapter_pts = GST_CLOCK_TIME_NONE;
+  }
+
+  return buf;
+}
+
+static gboolean
+prefill_update_sample_size (GstQTMux * qtmux, GstQTPad * qpad)
+{
+  switch (qpad->fourcc) {
+    case FOURCC_apch:
+    case FOURCC_apcn:
+    case FOURCC_apcs:
+    case FOURCC_apco:
+    case FOURCC_ap4h:
+    case FOURCC_ap4x:{
+      guint sample_size = prefill_get_sample_size (qtmux, qpad);
+      atom_trak_set_constant_size_samples (qpad->trak, sample_size);
+      return TRUE;
+    }
+    case FOURCC_sowt:
+    case FOURCC_twos:{
+      GSList *walk;
+
+      /* Find the (first) video track and assume that we have to output
+       * in that size */
+      for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
+        GstCollectData *cdata = (GstCollectData *) walk->data;
+        GstQTPad *tmp_qpad = (GstQTPad *) cdata;
+
+        if (tmp_qpad->trak->is_video) {
+          qpad->expected_sample_duration_n =
+              tmp_qpad->expected_sample_duration_n;
+          qpad->expected_sample_duration_d =
+              tmp_qpad->expected_sample_duration_d;
+          break;
+        }
+      }
+
+      if (walk == NULL) {
+        GST_INFO_OBJECT (qpad->collect.pad,
+            "Found no video framerate, using 40ms audio buffers");
+        qpad->expected_sample_duration_n = 25;
+        qpad->expected_sample_duration_d = 1;
+      }
+
+      /* Set a prepare_buf_func that ensures this */
+      qpad->prepare_buf_func = prefill_raw_audio_prepare_buf_func;
+      qpad->raw_audio_adapter = gst_adapter_new ();
+      qpad->raw_audio_adapter_offset = 0;
+      qpad->raw_audio_adapter_pts = GST_CLOCK_TIME_NONE;
+
+      return TRUE;
+    }
+    default:
+      return TRUE;
+  }
+}
+
+static GstQTPad *
+find_best_pad_prefill (GstQTMux * qtmux)
+{
+  GSList *walk;
+  GstQTPad *best_pad = NULL;
+
+  if (qtmux->current_pad &&
+      (qtmux->interleave_bytes != 0 || qtmux->interleave_time != 0) &&
+      (qtmux->interleave_bytes == 0
+          || qtmux->current_chunk_size <= qtmux->interleave_bytes)
+      && (qtmux->interleave_time == 0
+          || qtmux->current_chunk_duration <= qtmux->interleave_time)
+      && qtmux->mux_mode != GST_QT_MUX_MODE_FRAGMENTED
+      && qtmux->mux_mode != GST_QT_MUX_MODE_FRAGMENTED_STREAMABLE) {
+
+    if (qtmux->current_pad->total_duration < qtmux->reserved_max_duration) {
+      best_pad = qtmux->current_pad;
+    }
+  } else if (qtmux->collect->data->next) {
+    best_pad = qtmux->current_pad = NULL;
+  }
+
+  if (!best_pad) {
+    GstClockTime best_time = GST_CLOCK_TIME_NONE;
+
+    for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
+      GstCollectData *cdata = (GstCollectData *) walk->data;
+      GstQTPad *qtpad = (GstQTPad *) cdata;
+      GstClockTime timestamp;
+
+      if (qtpad->total_duration >= qtmux->reserved_max_duration)
+        continue;
+
+      timestamp = qtpad->total_duration;
+
+      if (best_pad == NULL ||
+          !GST_CLOCK_TIME_IS_VALID (best_time) || timestamp < best_time) {
+        best_pad = qtpad;
+        best_time = timestamp;
+      }
+    }
+  }
+
+  return best_pad;
+}
+
+static gboolean
+gst_qt_mux_prefill_samples (GstQTMux * qtmux)
+{
+  GstQTPad *qpad;
+  GSList *walk;
+  GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
+
+  /* Update expected sample sizes/durations as needed, this is for raw
+   * audio where samples are actual audio samples. */
+  for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
+    GstCollectData *cdata = (GstCollectData *) walk->data;
+    GstQTPad *qpad = (GstQTPad *) cdata;
+
+    if (!prefill_update_sample_size (qtmux, qpad))
+      return FALSE;
+  }
+
+  if (qtmux_klass->format == GST_QT_MUX_FORMAT_QT) {
+    /* For the first sample check/update timecode as needed. We do that before
+     * all actual samples as the code in gst_qt_mux_add_buffer() does it with
+     * initial buffer directly, not with last_buf */
+    for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
+      GstCollectData *cdata = (GstCollectData *) walk->data;
+      GstQTPad *qpad = (GstQTPad *) cdata;
+      GstBuffer *buffer =
+          gst_collect_pads_peek (qtmux->collect, (GstCollectData *) qpad);
+      GstVideoTimeCodeMeta *tc_meta;
+
+      if (buffer && (tc_meta = gst_buffer_get_video_time_code_meta (buffer))) {
+        GstVideoTimeCode *tc = &tc_meta->tc;
+
+        qpad->tc_trak = atom_trak_new (qtmux->context);
+        atom_moov_add_trak (qtmux->moov, qpad->tc_trak);
+
+        qpad->trak->tref = atom_tref_new (FOURCC_tmcd);
+        atom_tref_add_entry (qpad->trak->tref, qpad->tc_trak->tkhd.track_ID);
+
+        atom_trak_set_timecode_type (qpad->tc_trak, qtmux->context,
+            qpad->trak->mdia.mdhd.time_info.timescale, tc);
+
+        atom_trak_add_samples (qpad->tc_trak, 1, 1, 4,
+            qtmux->mdat_size, FALSE, 0);
+
+        qpad->tc_pos = qtmux->mdat_size;
+        qpad->first_tc = gst_video_time_code_copy (tc);
+        qpad->first_pts = GST_BUFFER_PTS (buffer);
+
+        qtmux->current_chunk_offset = -1;
+        qtmux->current_chunk_size = 0;
+        qtmux->current_chunk_duration = 0;
+        qtmux->mdat_size += 4;
+      }
+      if (buffer)
+        gst_buffer_unref (buffer);
+    }
+  }
+
+  while ((qpad = find_best_pad_prefill (qtmux))) {
+    GstClockTime timestamp, next_timestamp, duration;
+    guint nsamples, sample_size;
+    guint64 chunk_offset;
+    gint64 scaled_duration;
+    gint64 pts_offset = 0;
+    gboolean sync = FALSE;
+    TrakBufferEntryInfo sample_entry;
+
+    sample_size = prefill_get_sample_size (qtmux, qpad);
+
+    if (sample_size == -1) {
+      return FALSE;
+    }
+
+    if (!qpad->samples)
+      qpad->samples = g_array_new (FALSE, FALSE, sizeof (TrakBufferEntryInfo));
+
+    timestamp = qpad->total_duration;
+    next_timestamp = prefill_get_next_timestamp (qtmux, qpad);
+    duration = next_timestamp - timestamp;
+
+    if (qpad->first_ts == GST_CLOCK_TIME_NONE)
+      qpad->first_ts = timestamp;
+    if (qpad->first_dts == GST_CLOCK_TIME_NONE)
+      qpad->first_dts = timestamp;
+
+    if (qtmux->current_pad != qpad || qtmux->current_chunk_offset == -1) {
+      qtmux->current_pad = qpad;
+      if (qtmux->current_chunk_offset == -1)
+        qtmux->current_chunk_offset = qtmux->mdat_size;
+      else
+        qtmux->current_chunk_offset += qtmux->current_chunk_size;
+      qtmux->current_chunk_size = 0;
+      qtmux->current_chunk_duration = 0;
+    }
+    if (qpad->sample_size)
+      nsamples = sample_size / qpad->sample_size;
+    else
+      nsamples = 1;
+    qpad->last_dts = timestamp;
+    scaled_duration = gst_util_uint64_scale_round (timestamp + duration,
+        atom_trak_get_timescale (qpad->trak),
+        GST_SECOND) - gst_util_uint64_scale_round (timestamp,
+        atom_trak_get_timescale (qpad->trak), GST_SECOND);
+
+    qtmux->current_chunk_size += sample_size;
+    qtmux->current_chunk_duration += duration;
+    qpad->total_bytes += sample_size;
+
+    chunk_offset = qtmux->current_chunk_offset;
+
+    /* I-frame only, no frame reordering */
+    sync = FALSE;
+    pts_offset = 0;
+
+    if (qtmux->current_chunk_duration > qtmux->longest_chunk
+        || !GST_CLOCK_TIME_IS_VALID (qtmux->longest_chunk)) {
+      qtmux->longest_chunk = qtmux->current_chunk_duration;
+    }
+
+    sample_entry.track_id = qpad->trak->tkhd.track_ID;
+    sample_entry.nsamples = nsamples;
+    sample_entry.delta = scaled_duration / nsamples;
+    sample_entry.size = sample_size / nsamples;
+    sample_entry.chunk_offset = chunk_offset;
+    sample_entry.pts_offset = pts_offset;
+    sample_entry.sync = sync;
+    sample_entry.do_pts = TRUE;
+    g_array_append_val (qpad->samples, sample_entry);
+    atom_trak_add_samples (qpad->trak, nsamples, scaled_duration / nsamples,
+        sample_size / nsamples, chunk_offset, sync, pts_offset);
+
+    qpad->total_duration = next_timestamp;
+    qtmux->mdat_size += sample_size;
+    qpad->sample_offset += nsamples;
+  }
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_qt_mux_start_file (GstQTMux * qtmux)
+{
+  GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstCaps *caps;
+  GstSegment segment;
+  gchar s_id[32];
+  GstClockTime reserved_max_duration;
+  guint reserved_bytes_per_sec_per_trak;
+  GSList *walk;
+
+  GST_DEBUG_OBJECT (qtmux, "starting file");
+
+  GST_OBJECT_LOCK (qtmux);
+  reserved_max_duration = qtmux->reserved_max_duration;
+  reserved_bytes_per_sec_per_trak = qtmux->reserved_bytes_per_sec_per_trak;
+  GST_OBJECT_UNLOCK (qtmux);
+
+  /* stream-start (FIXME: create id based on input ids) */
+  g_snprintf (s_id, sizeof (s_id), "qtmux-%08x", g_random_int ());
+  gst_pad_push_event (qtmux->srcpad, gst_event_new_stream_start (s_id));
+
+  caps = gst_caps_copy (gst_pad_get_pad_template_caps (qtmux->srcpad));
+  /* qtmux has structure with and without variant, remove all but the first */
+  while (gst_caps_get_size (caps) > 1)
+    gst_caps_remove_structure (caps, 1);
+  gst_pad_set_caps (qtmux->srcpad, caps);
+  gst_caps_unref (caps);
+
+  /* Default is 'normal' mode */
+  qtmux->mux_mode = GST_QT_MUX_MODE_MOOV_AT_END;
+
+  /* Require a sensible fragment duration when muxing
+   * using the ISML muxer */
+  if (qtmux_klass->format == GST_QT_MUX_FORMAT_ISML &&
+      qtmux->fragment_duration == 0)
+    goto invalid_isml;
+
+  if (qtmux->fragment_duration > 0) {
+    if (qtmux->streamable)
+      qtmux->mux_mode = GST_QT_MUX_MODE_FRAGMENTED_STREAMABLE;
+    else
+      qtmux->mux_mode = GST_QT_MUX_MODE_FRAGMENTED;
+  } else if (qtmux->fast_start) {
+    qtmux->mux_mode = GST_QT_MUX_MODE_FAST_START;
+  } else if (reserved_max_duration != GST_CLOCK_TIME_NONE) {
+    if (qtmux->reserved_prefill)
+      qtmux->mux_mode = GST_QT_MUX_MODE_ROBUST_RECORDING_PREFILL;
+    else
+      qtmux->mux_mode = GST_QT_MUX_MODE_ROBUST_RECORDING;
+  }
+
+  switch (qtmux->mux_mode) {
+    case GST_QT_MUX_MODE_MOOV_AT_END:
+    case GST_QT_MUX_MODE_ROBUST_RECORDING:
+      /* We have to be able to seek to rewrite the mdat header, or any
+       * moov atom we write will not be visible in the file, because an
+       * MDAT with 0 as the size covers the rest of the file. A file
+       * with no moov is not playable, so error out now. */
+      if (!gst_qt_mux_downstream_is_seekable (qtmux)) {
+        GST_ELEMENT_ERROR (qtmux, STREAM, MUX,
+            ("Downstream is not seekable - will not be able to create a playable file"),
+            (NULL));
+        return GST_FLOW_ERROR;
+      }
+      break;
+    case GST_QT_MUX_MODE_FAST_START:
+    case GST_QT_MUX_MODE_FRAGMENTED_STREAMABLE:
+      break;                    /* Don't need seekability, ignore */
+    case GST_QT_MUX_MODE_FRAGMENTED:
+      if (!gst_qt_mux_downstream_is_seekable (qtmux)) {
+        GST_WARNING_OBJECT (qtmux, "downstream is not seekable, but "
+            "streamable=false. Will ignore that and create streamable output "
+            "instead");
+        qtmux->streamable = TRUE;
+        g_object_notify (G_OBJECT (qtmux), "streamable");
+      }
+      break;
+    case GST_QT_MUX_MODE_ROBUST_RECORDING_PREFILL:
+      if (!gst_qt_mux_downstream_is_seekable (qtmux)) {
+        GST_WARNING_OBJECT (qtmux,
+            "downstream is not seekable, will not be able "
+            "to trim samples table at the end if less than reserved-duration is "
+            "recorded");
+      }
+      break;
+  }
+
+  /* let downstream know we think in BYTES and expect to do seeking later on */
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
+
+  GST_OBJECT_LOCK (qtmux);
+
+  if (qtmux->timescale == 0) {
+    guint32 suggested_timescale = 0;
+    GSList *walk;
+
+    /* Calculate a reasonable timescale for the moov:
+     * If there is video, it is the biggest video track timescale or an even
+     * multiple of it if it's smaller than 1800.
+     * Otherwise it is 1800 */
+    for (walk = qtmux->sinkpads; walk; walk = g_slist_next (walk)) {
+      GstCollectData *cdata = (GstCollectData *) walk->data;
+      GstQTPad *qpad = (GstQTPad *) cdata;
+
+      if (!qpad->trak)
+        continue;
+
+      /* not video */
+      if (!qpad->trak->mdia.minf.vmhd)
+        continue;
+
+      suggested_timescale =
+          MAX (qpad->trak->mdia.mdhd.time_info.timescale, suggested_timescale);
+    }
+
+    if (suggested_timescale == 0)
+      suggested_timescale = 1800;
+
+    while (suggested_timescale < 1800)
+      suggested_timescale *= 2;
+
+    qtmux->timescale = suggested_timescale;
+  }
+
+  /* initialize our moov recovery file */
+  if (qtmux->moov_recov_file_path) {
+    gst_qt_mux_prepare_moov_recovery (qtmux);
+  }
+
+  /* Make sure the first time we update the moov, we'll
+   * include any tagsetter tags */
+  qtmux->tags_changed = TRUE;
+
+  GST_OBJECT_UNLOCK (qtmux);
+
+  /*
+   * send mdat header if already needed, and mark position for later update.
+   * We don't send ftyp now if we are on fast start mode, because we can
+   * better fine tune using the information we gather to create the whole moov
+   * atom.
+   */
+  switch (qtmux->mux_mode) {
+    case GST_QT_MUX_MODE_MOOV_AT_END:
+      ret = gst_qt_mux_prepare_and_send_ftyp (qtmux);
+      if (ret != GST_FLOW_OK)
+        break;
+
+      /* Store this as the mdat offset for later updating
+       * when we write the moov */
+      qtmux->mdat_pos = qtmux->header_size;
+      /* extended atom in case we go over 4GB while writing and need
+       * the full 64-bit atom */
+      ret =
+          gst_qt_mux_send_mdat_header (qtmux, &qtmux->header_size, 0, TRUE,
+          FALSE);
+      break;
+    case GST_QT_MUX_MODE_ROBUST_RECORDING:
+      ret = gst_qt_mux_prepare_and_send_ftyp (qtmux);
+      if (ret != GST_FLOW_OK)
+        break;
+
+      /* Pad ftyp out to an 8-byte boundary before starting the moov
+       * ping pong region. It should be well less than 1 disk sector,
+       * unless there's a bajillion compatible types listed,
+       * but let's be sure the free atom doesn't cross a sector
+       * boundary anyway */
+      if (qtmux->header_size % 8) {
+        /* Extra 8 bytes for the padding free atom header */
+        guint padding = (guint) (16 - (qtmux->header_size % 8));
+        GST_LOG_OBJECT (qtmux, "Rounding ftyp by %u bytes", padding);
+        ret =
+            gst_qt_mux_send_free_atom (qtmux, &qtmux->header_size, padding,
+            FALSE);
+        if (ret != GST_FLOW_OK)
+          return ret;
+      }
+
+      /* Store this as the moov offset for later updating.
+       * We record mdat position below */
+      qtmux->moov_pos = qtmux->header_size;
+
+      /* Set up the initial 'ping' state of the ping-pong buffers */
+      qtmux->reserved_moov_first_active = TRUE;
+
+      gst_qt_mux_configure_moov (qtmux);
+      gst_qt_mux_setup_metadata (qtmux);
+      /* Empty free atom to begin, starting on an 8-byte boundary */
+      ret = gst_qt_mux_send_free_atom (qtmux, &qtmux->header_size, 8, FALSE);
+      if (ret != GST_FLOW_OK)
+        return ret;
+      /* Moov header, not padded yet */
+      ret = gst_qt_mux_send_moov (qtmux, &qtmux->header_size, 0, FALSE, FALSE);
+      if (ret != GST_FLOW_OK)
+        return ret;
+      /* The moov we just sent contains the 'base' size of the moov, before
+       * we put in any time-dependent per-trak data. Use that to make
+       * a good estimate of how much extra to reserve */
+      /* Calculate how much space to reserve for our MOOV atom.
+       * We actually reserve twice that, for ping-pong buffers */
+      qtmux->base_moov_size = qtmux->last_moov_size;
+      GST_LOG_OBJECT (qtmux, "Base moov size is %u before any indexes",
+          qtmux->base_moov_size);
+      qtmux->reserved_moov_size = qtmux->base_moov_size +
+          gst_util_uint64_scale (reserved_max_duration,
+          reserved_bytes_per_sec_per_trak *
+          atom_moov_get_trak_count (qtmux->moov), GST_SECOND);
+
+      /* Need space for at least 4 atom headers. More really, but
+       * this as an absolute minimum */
+      if (qtmux->reserved_moov_size < 4 * 8)
+        goto reserved_moov_too_small;
+
+      GST_DEBUG_OBJECT (qtmux, "reserving header area of size %u",
+          2 * qtmux->reserved_moov_size + 16);
+
+      GST_OBJECT_LOCK (qtmux);
+      qtmux->reserved_duration_remaining =
+          gst_util_uint64_scale (qtmux->reserved_moov_size -
+          qtmux->base_moov_size, GST_SECOND,
+          reserved_bytes_per_sec_per_trak *
+          atom_moov_get_trak_count (qtmux->moov));
+      GST_OBJECT_UNLOCK (qtmux);
+
+      /* Now that we know how much reserved space is targetted,
+       * output a free atom to fill the extra reserved */
+      ret = gst_qt_mux_send_free_atom (qtmux, &qtmux->header_size,
+          qtmux->reserved_moov_size - qtmux->base_moov_size, FALSE);
+      if (ret != GST_FLOW_OK)
+        return ret;
+
+      /* Then a free atom containing 'pong' buffer, with an
+       * extra 8 bytes to account for the free atom header itself */
+      ret = gst_qt_mux_send_free_atom (qtmux, &qtmux->header_size,
+          qtmux->reserved_moov_size + 8, FALSE);
+      if (ret != GST_FLOW_OK)
+        return ret;
+
+      /* extra atoms go after the free/moov(s), before the mdat */
+      ret =
+          gst_qt_mux_send_extra_atoms (qtmux, TRUE, &qtmux->header_size, FALSE);
+      if (ret != GST_FLOW_OK)
+        return ret;
+
+      qtmux->mdat_pos = qtmux->header_size;
+      /* extended atom in case we go over 4GB while writing and need
+       * the full 64-bit atom */
+      ret =
+          gst_qt_mux_send_mdat_header (qtmux, &qtmux->header_size, 0, TRUE,
+          FALSE);
+      break;
+    case GST_QT_MUX_MODE_ROBUST_RECORDING_PREFILL:
+      ret = gst_qt_mux_prepare_and_send_ftyp (qtmux);
+      if (ret != GST_FLOW_OK)
+        break;
+
+      /* Store this as the moov offset for later updating.
+       * We record mdat position below */
+      qtmux->moov_pos = qtmux->header_size;
+
+      if (!gst_qt_mux_prefill_samples (qtmux)) {
+        GST_ELEMENT_ERROR (qtmux, STREAM, MUX,
+            ("Unsupported codecs or configuration for prefill mode"), (NULL));
+
+        return GST_FLOW_ERROR;
+      }
+
+      gst_qt_mux_update_global_statistics (qtmux);
+      gst_qt_mux_configure_moov (qtmux);
+      gst_qt_mux_update_edit_lists (qtmux);
+      gst_qt_mux_setup_metadata (qtmux);
+
+      /* Moov header with pre-filled samples */
+      ret = gst_qt_mux_send_moov (qtmux, &qtmux->header_size, 0, FALSE, FALSE);
+      if (ret != GST_FLOW_OK)
+        return ret;
+
+      /* last_moov_size now contains the full size of the moov, moov_pos the
+       * position. This allows us to rewrite it in the very end as needed */
+      qtmux->reserved_moov_size =
+          qtmux->last_moov_size + 12 * g_slist_length (qtmux->sinkpads) + 8;
+
+      /* Send an additional free atom at the end so we definitely have space
+       * to rewrite the moov header at the end and remove the samples that
+       * were not actually written */
+      ret =
+          gst_qt_mux_send_free_atom (qtmux, &qtmux->header_size,
+          12 * g_slist_length (qtmux->sinkpads) + 8, FALSE);
+      if (ret != GST_FLOW_OK)
+        return ret;
+
+      /* extra atoms go after the free/moov(s), before the mdat */
+      ret =
+          gst_qt_mux_send_extra_atoms (qtmux, TRUE, &qtmux->header_size, FALSE);
+      if (ret != GST_FLOW_OK)
+        return ret;
+
+      qtmux->mdat_pos = qtmux->header_size;
+
+      /* And now send the mdat header */
+      ret =
+          gst_qt_mux_send_mdat_header (qtmux, &qtmux->header_size,
+          qtmux->mdat_size, TRUE, FALSE);
+
+      /* chunks position is set relative to the first byte of the
+       * MDAT atom payload. Set the overall offset into the file */
+      atom_moov_chunks_set_offset (qtmux->moov, qtmux->header_size);
+
+      {
+        GstSegment segment;
+
+        gst_segment_init (&segment, GST_FORMAT_BYTES);
+        segment.start = qtmux->moov_pos;
+        gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
+
+        ret = gst_qt_mux_send_moov (qtmux, NULL, 0, FALSE, FALSE);
+        if (ret != GST_FLOW_OK)
+          return ret;
+
+        segment.start = qtmux->header_size;
+        gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
+      }
+
+      qtmux->current_chunk_size = 0;
+      qtmux->current_chunk_duration = 0;
+      qtmux->current_chunk_offset = -1;
+      qtmux->mdat_size = 0;
+      qtmux->current_pad = NULL;
+      qtmux->longest_chunk = GST_CLOCK_TIME_NONE;
+
+      for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
+        GstCollectData *cdata = (GstCollectData *) walk->data;
+        GstQTPad *qtpad = (GstQTPad *) cdata;
+
+        qtpad->total_bytes = 0;
+        qtpad->total_duration = 0;
+        qtpad->first_dts = qtpad->first_ts = GST_CLOCK_TIME_NONE;
+        qtpad->last_dts = GST_CLOCK_TIME_NONE;
+        qtpad->sample_offset = 0;
+      }
+
+      break;
+    case GST_QT_MUX_MODE_FAST_START:
+      GST_OBJECT_LOCK (qtmux);
+      qtmux->fast_start_file = g_fopen (qtmux->fast_start_file_path, "wb+");
+      if (!qtmux->fast_start_file)
+        goto open_failed;
+      GST_OBJECT_UNLOCK (qtmux);
+      /* send a dummy buffer for preroll */
+      ret = gst_qt_mux_send_buffer (qtmux, gst_buffer_new (), NULL, FALSE);
+      break;
+    case GST_QT_MUX_MODE_FRAGMENTED:
+    case GST_QT_MUX_MODE_FRAGMENTED_STREAMABLE:
+      ret = gst_qt_mux_prepare_and_send_ftyp (qtmux);
+      if (ret != GST_FLOW_OK)
+        break;
+      /* store the moov pos so we can update the duration later
+       * in non-streamable mode */
+      qtmux->moov_pos = qtmux->header_size;
+
+      GST_DEBUG_OBJECT (qtmux, "fragment duration %d ms, writing headers",
+          qtmux->fragment_duration);
+      /* also used as snapshot marker to indicate fragmented file */
+      qtmux->fragment_sequence = 1;
+      /* prepare moov and/or tags */
+      gst_qt_mux_configure_moov (qtmux);
+      gst_qt_mux_setup_metadata (qtmux);
+      ret = gst_qt_mux_send_moov (qtmux, &qtmux->header_size, 0, FALSE, FALSE);
+      if (ret != GST_FLOW_OK)
+        return ret;
+      /* extra atoms */
+      ret =
+          gst_qt_mux_send_extra_atoms (qtmux, TRUE, &qtmux->header_size, FALSE);
+      if (ret != GST_FLOW_OK)
+        break;
+      /* prepare index if not streamable */
+      if (qtmux->mux_mode == GST_QT_MUX_MODE_FRAGMENTED)
+        qtmux->mfra = atom_mfra_new (qtmux->context);
+      break;
+  }
+
+  return ret;
+  /* ERRORS */
+invalid_isml:
+  {
+    GST_ELEMENT_ERROR (qtmux, STREAM, MUX,
+        ("Cannot create an ISML file with 0 fragment duration"), (NULL));
+    return GST_FLOW_ERROR;
+  }
+reserved_moov_too_small:
+  {
+    GST_ELEMENT_ERROR (qtmux, STREAM, MUX,
+        ("Not enough reserved space for creating headers"), (NULL));
+    return GST_FLOW_ERROR;
+  }
+open_failed:
+  {
+    GST_ELEMENT_ERROR (qtmux, RESOURCE, OPEN_READ_WRITE,
+        (("Could not open temporary file \"%s\""),
+            qtmux->fast_start_file_path), GST_ERROR_SYSTEM);
+    GST_OBJECT_UNLOCK (qtmux);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstFlowReturn
+gst_qt_mux_send_last_buffers (GstQTMux * qtmux)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GSList *walk;
+
+  for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
+    GstCollectData *cdata = (GstCollectData *) walk->data;
+    GstQTPad *qtpad = (GstQTPad *) cdata;
+
+    /* avoid add_buffer complaining if not negotiated
+     * in which case no buffers either, so skipping */
+    if (!qtpad->fourcc) {
+      GST_DEBUG_OBJECT (qtmux, "Pad %s has never had buffers",
+          GST_PAD_NAME (qtpad->collect.pad));
+      continue;
+    }
+
+    /* send last buffer; also flushes possibly queued buffers/ts */
+    GST_DEBUG_OBJECT (qtmux, "Sending the last buffer for pad %s",
+        GST_PAD_NAME (qtpad->collect.pad));
+    ret = gst_qt_mux_add_buffer (qtmux, qtpad, NULL);
+    if (ret != GST_FLOW_OK) {
+      GST_WARNING_OBJECT (qtmux, "Failed to send last buffer for %s, "
+          "flow return: %s", GST_PAD_NAME (qtpad->collect.pad),
+          gst_flow_get_name (ret));
+    }
+  }
+
+  return ret;
+}
+
+static void
+gst_qt_mux_update_global_statistics (GstQTMux * qtmux)
+{
+  GSList *walk;
+
+  /* for setting some subtitles fields */
+  guint max_width = 0;
+  guint max_height = 0;
+
+  qtmux->first_ts = qtmux->last_dts = GST_CLOCK_TIME_NONE;
+
+  for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
+    GstCollectData *cdata = (GstCollectData *) walk->data;
+    GstQTPad *qtpad = (GstQTPad *) cdata;
+
+    if (!qtpad->fourcc) {
+      GST_DEBUG_OBJECT (qtmux, "Pad %s has never had buffers",
+          GST_PAD_NAME (qtpad->collect.pad));
+      continue;
+    }
+
+    /* having flushed above, can check for buffers now */
+    if (GST_CLOCK_TIME_IS_VALID (qtpad->first_ts)) {
+      GstClockTime first_pts_in = qtpad->first_ts;
+      /* it should be, since we got first_ts by adding adjustment
+       * to a positive incoming PTS */
+      if (qtpad->dts_adjustment <= first_pts_in)
+        first_pts_in -= qtpad->dts_adjustment;
+      /* determine max stream duration */
+      if (!GST_CLOCK_TIME_IS_VALID (qtmux->last_dts)
+          || qtpad->last_dts > qtmux->last_dts) {
+        qtmux->last_dts = qtpad->last_dts;
+      }
+      if (!GST_CLOCK_TIME_IS_VALID (qtmux->first_ts)
+          || first_pts_in < qtmux->first_ts) {
+        /* we need the original incoming PTS here, as this first_ts
+         * is used in update_edit_lists to construct the edit list that arrange
+         * for sync'ed streams.  The first_ts is most likely obtained from
+         * some (audio) stream with 0 dts_adjustment and initial 0 PTS,
+         * so it makes no difference, though it matters in other cases */
+        qtmux->first_ts = first_pts_in;
+      }
+    }
+
+    /* subtitles need to know the video width/height,
+     * it is stored shifted 16 bits to the left according to the
+     * spec */
+    max_width = MAX (max_width, (qtpad->trak->tkhd.width >> 16));
+    max_height = MAX (max_height, (qtpad->trak->tkhd.height >> 16));
+
+    /* update average bitrate of streams if needed */
+    {
+      guint32 avgbitrate = 0;
+      guint32 maxbitrate = qtpad->max_bitrate;
+
+      if (qtpad->avg_bitrate)
+        avgbitrate = qtpad->avg_bitrate;
+      else if (qtpad->total_duration > 0)
+        avgbitrate = (guint32) gst_util_uint64_scale_round (qtpad->total_bytes,
+            8 * GST_SECOND, qtpad->total_duration);
+
+      atom_trak_update_bitrates (qtpad->trak, avgbitrate, maxbitrate);
+    }
+  }
+
+  /* need to update values on subtitle traks now that we know the
+   * max width and height */
+  for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
+    GstCollectData *cdata = (GstCollectData *) walk->data;
+    GstQTPad *qtpad = (GstQTPad *) cdata;
+
+    if (!qtpad->fourcc) {
+      GST_DEBUG_OBJECT (qtmux, "Pad %s has never had buffers",
+          GST_PAD_NAME (qtpad->collect.pad));
+      continue;
+    }
+
+    if (qtpad->fourcc == FOURCC_tx3g) {
+      atom_trak_tx3g_update_dimension (qtpad->trak, max_width, max_height);
+    }
+  }
+}
+
+/* Called after gst_qt_mux_update_global_statistics() updates the
+ * first_ts tracking, to create/set edit lists for delayed streams */
+static void
+gst_qt_mux_update_edit_lists (GstQTMux * qtmux)
+{
+  GSList *walk;
+
+  GST_DEBUG_OBJECT (qtmux, "Media first ts selected: %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (qtmux->first_ts));
+  /* add/update EDTSs for late streams. configure_moov will have
+   * set the trak durations above by summing the sample tables,
+   * here we extend that if needing to insert an empty segment */
+  for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
+    GstCollectData *cdata = (GstCollectData *) walk->data;
+    GstQTPad *qtpad = (GstQTPad *) cdata;
+
+    atom_trak_edts_clear (qtpad->trak);
+
+    if (GST_CLOCK_TIME_IS_VALID (qtpad->first_ts)) {
+      guint32 lateness = 0;
+      guint32 duration = qtpad->trak->tkhd.duration;
+      gboolean has_gap;
+
+      has_gap = (qtpad->first_ts > (qtmux->first_ts + qtpad->dts_adjustment));
+
+      if (has_gap) {
+        GstClockTime diff;
+
+        diff = qtpad->first_ts - (qtmux->first_ts + qtpad->dts_adjustment);
+        lateness = gst_util_uint64_scale_round (diff,
+            qtmux->timescale, GST_SECOND);
+
+        if (lateness > 0) {
+          GST_DEBUG_OBJECT (qtmux,
+              "Pad %s is a late stream by %" GST_TIME_FORMAT,
+              GST_PAD_NAME (qtpad->collect.pad), GST_TIME_ARGS (diff));
+
+          atom_trak_set_elst_entry (qtpad->trak, 0, lateness, (guint32) - 1,
+              (guint32) (1 * 65536.0));
+        }
+      }
+
+      /* Always write an edit list for the whole track. In general this is not
+       * necessary except for the case of having a gap or DTS adjustment but
+       * it allows to give the whole track's duration in the usually more
+       * accurate media timescale
+       */
+      {
+        GstClockTime ctts = 0;
+        guint32 media_start;
+
+        if (qtpad->first_ts > qtpad->first_dts)
+          ctts = qtpad->first_ts - qtpad->first_dts;
+
+        media_start = gst_util_uint64_scale_round (ctts,
+            atom_trak_get_timescale (qtpad->trak), GST_SECOND);
+
+        /* atom_trak_set_elst_entry() has a quirk - if the edit list
+         * is empty because there's no gap added above, this call
+         * will not replace index 1, it will create the entry at index 0.
+         * Luckily, that's exactly what we want here */
+        atom_trak_set_elst_entry (qtpad->trak, 1, duration, media_start,
+            (guint32) (1 * 65536.0));
+      }
+
+      /* need to add the empty time to the trak duration */
+      duration += lateness;
+      qtpad->trak->tkhd.duration = duration;
+      if (qtpad->tc_trak) {
+        qtpad->tc_trak->tkhd.duration = duration;
+        qtpad->tc_trak->mdia.mdhd.time_info.duration = duration;
+      }
+
+      /* And possibly grow the moov duration */
+      if (duration > qtmux->moov->mvhd.time_info.duration) {
+        qtmux->moov->mvhd.time_info.duration = duration;
+        qtmux->moov->mvex.mehd.fragment_duration = duration;
+      }
+    }
+  }
+}
+
+static GstFlowReturn
+gst_qt_mux_update_timecode (GstQTMux * qtmux, GstQTPad * qtpad)
+{
+  GstSegment segment;
+  GstBuffer *buf;
+  GstMapInfo map;
+  guint64 offset = qtpad->tc_pos;
+  GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
+
+  if (qtmux_klass->format != GST_QT_MUX_FORMAT_QT)
+    return GST_FLOW_OK;
+
+  g_assert (qtpad->tc_pos != -1);
+
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  segment.start = offset;
+  gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
+
+  buf = gst_buffer_new_and_alloc (4);
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+
+  GST_WRITE_UINT32_BE (map.data,
+      gst_video_time_code_frames_since_daily_jam (qtpad->first_tc));
+  gst_buffer_unmap (buf, &map);
+
+  /* Reset this value, so the timecode won't be re-rewritten */
+  qtpad->tc_pos = -1;
+
+  return gst_qt_mux_send_buffer (qtmux, buf, &offset, FALSE);
+}
+
+static GstFlowReturn
+gst_qt_mux_stop_file (GstQTMux * qtmux)
+{
+  gboolean ret = GST_FLOW_OK;
+  guint64 offset = 0, size = 0;
+  gboolean large_file;
+  GSList *walk;
+
+  GST_DEBUG_OBJECT (qtmux, "Updating remaining values and sending last data");
+
+  /* pushing last buffers for each pad */
+  if ((ret = gst_qt_mux_send_last_buffers (qtmux)) != GST_FLOW_OK)
+    return ret;
+
+  if (qtmux->mux_mode == GST_QT_MUX_MODE_FRAGMENTED_STREAMABLE) {
+    /* Streamable mode; no need to write duration or MFRA */
+    GST_DEBUG_OBJECT (qtmux, "streamable file; nothing to stop");
+    return GST_FLOW_OK;
+  }
+
+  gst_qt_mux_update_global_statistics (qtmux);
+  for (walk = qtmux->collect->data; walk; walk = walk->next) {
+    GstQTPad *qtpad = (GstQTPad *) walk->data;
+
+    if (qtpad->tc_pos != -1) {
+      /* File is being stopped and timecode hasn't been updated. Update it now
+       * with whatever we have */
+      ret = gst_qt_mux_update_timecode (qtmux, qtpad);
+      if (ret != GST_FLOW_OK)
+        return ret;
+    }
+  }
+
+  switch (qtmux->mux_mode) {
+    case GST_QT_MUX_MODE_FRAGMENTED:{
+      GstSegment segment;
+      guint8 *data = NULL;
+      GstBuffer *buf;
+
+      size = offset = 0;
+      GST_DEBUG_OBJECT (qtmux, "adding mfra");
+      if (!atom_mfra_copy_data (qtmux->mfra, &data, &size, &offset))
+        goto serialize_error;
+      buf = _gst_buffer_new_take_data (data, offset);
+      ret = gst_qt_mux_send_buffer (qtmux, buf, NULL, FALSE);
+      if (ret != GST_FLOW_OK)
+        return ret;
+
+      /* only mvex duration is updated,
+       * mvhd should be consistent with empty moov
+       * (but TODO maybe some clients do not handle that well ?) */
+      qtmux->moov->mvex.mehd.fragment_duration =
+          gst_util_uint64_scale (qtmux->last_dts, qtmux->timescale, GST_SECOND);
+      GST_DEBUG_OBJECT (qtmux, "rewriting moov with mvex duration %"
+          GST_TIME_FORMAT, GST_TIME_ARGS (qtmux->last_dts));
+      /* seek and rewrite the header */
+      gst_segment_init (&segment, GST_FORMAT_BYTES);
+      segment.start = qtmux->moov_pos;
+      gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
+      /* no need to seek back */
+      return gst_qt_mux_send_moov (qtmux, NULL, 0, FALSE, FALSE);
+    }
+    case GST_QT_MUX_MODE_ROBUST_RECORDING:{
+      ret = gst_qt_mux_robust_recording_rewrite_moov (qtmux);
+      if (G_UNLIKELY (ret != GST_FLOW_OK))
+        return ret;
+      /* Finalise by writing the final size into the mdat. Up until now
+       * it's been 0, which means 'rest of the file'
+       * No need to seek back after this, we won't write any more */
+      return gst_qt_mux_update_mdat_size (qtmux, qtmux->mdat_pos,
+          qtmux->mdat_size, NULL, TRUE);
+    }
+    case GST_QT_MUX_MODE_ROBUST_RECORDING_PREFILL:{
+      GSList *walk;
+      guint32 next_track_id = qtmux->moov->mvhd.next_track_id;
+
+      for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
+        GstCollectData *cdata = (GstCollectData *) walk->data;
+        GstQTPad *qpad = (GstQTPad *) cdata;
+        const TrakBufferEntryInfo *sample_entry;
+        guint64 block_idx;
+        AtomSTBL *stbl = &qpad->trak->mdia.minf.stbl;
+
+        /* Get the block index of the last sample we wrote, not of the next
+         * sample we would write */
+        block_idx = prefill_get_block_index (qtmux, qpad);
+        g_assert (block_idx > 0);
+        block_idx--;
+
+        sample_entry =
+            &g_array_index (qpad->samples, TrakBufferEntryInfo, block_idx);
+
+        /* stts */
+        {
+          STTSEntry *entry;
+          guint64 nsamples = 0;
+          gint i, n;
+
+          n = atom_array_get_len (&stbl->stts.entries);
+          for (i = 0; i < n; i++) {
+            entry = &atom_array_index (&stbl->stts.entries, i);
+            if (nsamples + entry->sample_count >= qpad->sample_offset) {
+              entry->sample_count = qpad->sample_offset - nsamples;
+              stbl->stts.entries.len = i + 1;
+              break;
+            }
+            nsamples += entry->sample_count;
+          }
+          g_assert (i < n);
+        }
+
+        /* stsz */
+        {
+          g_assert (stbl->stsz.entries.len == 0);
+          stbl->stsz.table_size = qpad->sample_offset;
+        }
+
+        /* stco/stsc */
+        {
+          gint i, n;
+          guint64 nsamples = 0;
+          gint chunk_index = 0;
+
+          n = stbl->stco64.entries.len;
+          for (i = 0; i < n; i++) {
+            guint64 *entry = &atom_array_index (&stbl->stco64.entries, i);
+
+            if (*entry == sample_entry->chunk_offset) {
+              stbl->stco64.entries.len = i + 1;
+              chunk_index = i + 1;
+              break;
+            }
+          }
+          g_assert (i < n);
+          g_assert (chunk_index > 0);
+
+          n = stbl->stsc.entries.len;
+          for (i = 0; i < n; i++) {
+            STSCEntry *entry = &atom_array_index (&stbl->stsc.entries, i);
+
+            if (entry->first_chunk >= chunk_index)
+              break;
+
+            if (i > 0) {
+              nsamples +=
+                  (entry->first_chunk - atom_array_index (&stbl->stsc.entries,
+                      i -
+                      1).first_chunk) * atom_array_index (&stbl->stsc.entries,
+                  i - 1).samples_per_chunk;
+            }
+          }
+          g_assert (i <= n);
+
+          if (i > 0) {
+            STSCEntry *prev_entry =
+                &atom_array_index (&stbl->stsc.entries, i - 1);
+            nsamples +=
+                (chunk_index -
+                prev_entry->first_chunk) * prev_entry->samples_per_chunk;
+            if (qpad->sample_offset - nsamples > 0) {
+              stbl->stsc.entries.len = i;
+              atom_stsc_add_new_entry (&stbl->stsc, chunk_index,
+                  qpad->sample_offset - nsamples);
+            } else {
+              stbl->stsc.entries.len = i;
+              stbl->stco64.entries.len--;
+            }
+          } else {
+            /* Everything in a single chunk */
+            stbl->stsc.entries.len = 0;
+            atom_stsc_add_new_entry (&stbl->stsc, chunk_index,
+                qpad->sample_offset);
+          }
+        }
+
+        {
+          GList *walk2;
+
+          for (walk2 = qtmux->moov->mvex.trexs; walk2; walk2 = walk2->next) {
+            AtomTREX *trex = walk2->data;
+
+            if (trex->track_ID == qpad->trak->tkhd.track_ID) {
+              trex->track_ID = next_track_id;
+              break;
+            }
+          }
+
+          qpad->trak->tkhd.track_ID = next_track_id++;
+        }
+      }
+      qtmux->moov->mvhd.next_track_id = next_track_id;
+
+      gst_qt_mux_update_global_statistics (qtmux);
+      gst_qt_mux_configure_moov (qtmux);
+
+      gst_qt_mux_update_edit_lists (qtmux);
+
+      /* Check if any gap edit lists were added. We don't have any space
+       * reserved for this in the moov and the pre-finalized moov would have
+       * broken A/V synchronization. Error out here now
+       */
+      for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
+        GstCollectData *cdata = (GstCollectData *) walk->data;
+        GstQTPad *qpad = (GstQTPad *) cdata;
+
+        if (qpad->trak->edts
+            && g_slist_length (qpad->trak->edts->elst.entries) > 1) {
+          GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
+              ("Can't support gaps in prefill mode"));
+
+          return GST_FLOW_ERROR;
+        }
+      }
+
+      gst_qt_mux_setup_metadata (qtmux);
+      atom_moov_chunks_set_offset (qtmux->moov, qtmux->header_size);
+
+      {
+        GstSegment segment;
+
+        gst_segment_init (&segment, GST_FORMAT_BYTES);
+        segment.start = qtmux->moov_pos;
+        gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
+
+        ret =
+            gst_qt_mux_send_moov (qtmux, NULL, qtmux->reserved_moov_size, FALSE,
+            FALSE);
+        if (ret != GST_FLOW_OK)
+          return ret;
+
+        if (qtmux->reserved_moov_size > qtmux->last_moov_size) {
+          ret =
+              gst_qt_mux_send_free_atom (qtmux, NULL,
+              qtmux->reserved_moov_size - qtmux->last_moov_size, TRUE);
+        }
+
+        if (ret != GST_FLOW_OK)
+          return ret;
+      }
+
+      ret = gst_qt_mux_update_mdat_size (qtmux, qtmux->mdat_pos,
+          qtmux->mdat_size, NULL, FALSE);
+      return ret;
+    }
+    default:
+      break;
+  }
+
+  /* Moov-at-end or fast-start mode from here down */
+  gst_qt_mux_configure_moov (qtmux);
+
+  gst_qt_mux_update_edit_lists (qtmux);
+
+  /* tags into file metadata */
+  gst_qt_mux_setup_metadata (qtmux);
+
+  large_file = (qtmux->mdat_size > MDAT_LARGE_FILE_LIMIT);
+
+  switch (qtmux->mux_mode) {
+    case GST_QT_MUX_MODE_FAST_START:{
+      /* if faststart, update the offset of the atoms in the movie with the offset
+       * that the movie headers before mdat will cause.
+       * Also, send the ftyp */
+      offset = size = 0;
+
+      ret = gst_qt_mux_prepare_and_send_ftyp (qtmux);
+      if (ret != GST_FLOW_OK) {
+        goto ftyp_error;
+      }
+      /* copy into NULL to obtain size */
+      if (!atom_moov_copy_data (qtmux->moov, NULL, &size, &offset))
+        goto serialize_error;
+      GST_DEBUG_OBJECT (qtmux, "calculated moov atom size %" G_GUINT64_FORMAT,
+          offset);
+      offset += qtmux->header_size + (large_file ? 16 : 8);
+
+      /* sum up with the extra atoms size */
+      ret = gst_qt_mux_send_extra_atoms (qtmux, FALSE, &offset, FALSE);
+      if (ret != GST_FLOW_OK)
+        return ret;
+      break;
+    }
+    default:
+      offset = qtmux->header_size;
+      break;
+  }
+
+  /* Now that we know the size of moov + extra atoms, we can adjust
+   * the chunk offsets stored into the moov */
+  atom_moov_chunks_set_offset (qtmux->moov, offset);
+
+  /* write out moov and extra atoms */
+  /* note: as of this point, we no longer care about tracking written data size,
+   * since there is no more use for it anyway */
+  ret = gst_qt_mux_send_moov (qtmux, NULL, 0, FALSE, FALSE);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  /* extra atoms */
+  ret = gst_qt_mux_send_extra_atoms (qtmux, TRUE, NULL, FALSE);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  switch (qtmux->mux_mode) {
+    case GST_QT_MUX_MODE_MOOV_AT_END:
+    {
+      /* mdat needs update iff not using faststart */
+      GST_DEBUG_OBJECT (qtmux, "updating mdat size");
+      ret = gst_qt_mux_update_mdat_size (qtmux, qtmux->mdat_pos,
+          qtmux->mdat_size, NULL, FALSE);
+      /* note; no seeking back to the end of file is done,
+       * since we no longer write anything anyway */
+      break;
+    }
+    case GST_QT_MUX_MODE_FAST_START:
+    {
+      /* send mdat atom and move buffered data into it */
+      /* mdat_size = accumulated (buffered data) */
+      ret = gst_qt_mux_send_mdat_header (qtmux, NULL, qtmux->mdat_size,
+          large_file, FALSE);
+      if (ret != GST_FLOW_OK)
+        return ret;
+      ret = gst_qt_mux_send_buffered_data (qtmux, NULL);
+      if (ret != GST_FLOW_OK)
+        return ret;
+      break;
+    }
+    default:
+      g_assert_not_reached ();
+  }
+
+  return ret;
+
+  /* ERRORS */
+serialize_error:
+  {
+    GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
+        ("Failed to serialize moov"));
+    return GST_FLOW_ERROR;
+  }
+ftyp_error:
+  {
+    GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL), ("Failed to send ftyp"));
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstFlowReturn
+gst_qt_mux_pad_fragment_add_buffer (GstQTMux * qtmux, GstQTPad * pad,
+    GstBuffer * buf, gboolean force, guint32 nsamples, gint64 dts,
+    guint32 delta, guint32 size, gboolean sync, gint64 pts_offset)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  /* setup if needed */
+  if (G_UNLIKELY (!pad->traf || force))
+    goto init;
+
+flush:
+  /* flush pad fragment if threshold reached,
+   * or at new keyframe if we should be minding those in the first place */
+  if (G_UNLIKELY (force || (sync && pad->sync) ||
+          pad->fragment_duration < (gint64) delta)) {
+    AtomMOOF *moof;
+    guint64 size = 0, offset = 0;
+    guint8 *data = NULL;
+    GstBuffer *buffer;
+    guint i, total_size;
+
+    /* now we know where moof ends up, update offset in tfra */
+    if (pad->tfra)
+      atom_tfra_update_offset (pad->tfra, qtmux->header_size);
+
+    moof = atom_moof_new (qtmux->context, qtmux->fragment_sequence);
+    /* takes ownership */
+    atom_moof_add_traf (moof, pad->traf);
+    pad->traf = NULL;
+    atom_moof_copy_data (moof, &data, &size, &offset);
+    buffer = _gst_buffer_new_take_data (data, offset);
+    GST_LOG_OBJECT (qtmux, "writing moof size %" G_GSIZE_FORMAT,
+        gst_buffer_get_size (buffer));
+    ret = gst_qt_mux_send_buffer (qtmux, buffer, &qtmux->header_size, FALSE);
+
+    /* and actual data */
+    total_size = 0;
+    for (i = 0; i < atom_array_get_len (&pad->fragment_buffers); i++) {
+      total_size +=
+          gst_buffer_get_size (atom_array_index (&pad->fragment_buffers, i));
+    }
+
+    GST_LOG_OBJECT (qtmux, "writing %d buffers, total_size %d",
+        atom_array_get_len (&pad->fragment_buffers), total_size);
+    if (ret == GST_FLOW_OK)
+      ret = gst_qt_mux_send_mdat_header (qtmux, &qtmux->header_size, total_size,
+          FALSE, FALSE);
+    for (i = 0; i < atom_array_get_len (&pad->fragment_buffers); i++) {
+      if (G_LIKELY (ret == GST_FLOW_OK))
+        ret = gst_qt_mux_send_buffer (qtmux,
+            atom_array_index (&pad->fragment_buffers, i), &qtmux->header_size,
+            FALSE);
+      else
+        gst_buffer_unref (atom_array_index (&pad->fragment_buffers, i));
+    }
+
+    atom_array_clear (&pad->fragment_buffers);
+    atom_moof_free (moof);
+    qtmux->fragment_sequence++;
+    force = FALSE;
+  }
+
+init:
+  if (G_UNLIKELY (!pad->traf)) {
+    GST_LOG_OBJECT (qtmux, "setting up new fragment");
+    pad->traf = atom_traf_new (qtmux->context, atom_trak_get_id (pad->trak));
+    atom_array_init (&pad->fragment_buffers, 512);
+    pad->fragment_duration = gst_util_uint64_scale (qtmux->fragment_duration,
+        atom_trak_get_timescale (pad->trak), 1000);
+
+    if (G_UNLIKELY (qtmux->mfra && !pad->tfra)) {
+      pad->tfra = atom_tfra_new (qtmux->context, atom_trak_get_id (pad->trak));
+      atom_mfra_add_tfra (qtmux->mfra, pad->tfra);
+    }
+    atom_traf_set_base_decode_time (pad->traf, dts);
+  }
+
+  /* add buffer and metadata */
+  atom_traf_add_samples (pad->traf, delta, size, sync, pts_offset,
+      pad->sync && sync);
+  atom_array_append (&pad->fragment_buffers, buf, 256);
+  pad->fragment_duration -= delta;
+
+  if (pad->tfra) {
+    guint32 sn = atom_traf_get_sample_num (pad->traf);
+
+    if ((sync && pad->sync) || (sn == 1 && !pad->sync))
+      atom_tfra_add_entry (pad->tfra, dts, sn);
+  }
+
+  if (G_UNLIKELY (force))
+    goto flush;
+
+  return ret;
+}
+
+/* Here's the clever bit of robust recording: Updating the moov
+ * header is done using a ping-pong scheme inside 2 blocks of size
+ * 'reserved_moov_size' at the start of the file, in such a way that the
+ * file on-disk is always valid if interrupted.
+ * Inside the reserved space, we have 2 pairs of free + moov atoms
+ * (in that order), free-A + moov-A @ offset 0 and free-B + moov-B at
+ * at offset "reserved_moov_size".
+ *
+ * 1. Free-A has 0 size payload, moov-A immediately after is
+ *    active/current, and is padded with an internal Free atom to
+ *    end at reserved_space/2. Free-B is at reserved_space/2, sized
+ *    to cover the remaining free space (including moov-B).
+ * 2. We write moov-B (which is invisible inside free-B), and pad it to
+ *    end at the end of free space. Then, we update free-A to size
+ *    reserved_space/2 + sizeof(free-B), which hides moov-A and the
+ *    free-B header, and makes moov-B active.
+ * 3. Rewrite moov-A inside free-A, with padding out to free-B.
+ *    Change the size of free-A to make moov-A active again.
+ * 4. Rinse and repeat.
+ *
+ */
+static GstFlowReturn
+gst_qt_mux_robust_recording_rewrite_moov (GstQTMux * qtmux)
+{
+  GstSegment segment;
+  GstFlowReturn ret;
+  guint64 freeA_offset;
+  guint32 new_freeA_size;
+  guint64 new_moov_offset;
+
+  /* Update moov info, then seek and rewrite the MOOV atom */
+  gst_qt_mux_update_global_statistics (qtmux);
+  gst_qt_mux_configure_moov (qtmux);
+
+  gst_qt_mux_update_edit_lists (qtmux);
+
+  /* tags into file metadata */
+  gst_qt_mux_setup_metadata (qtmux);
+
+  /* chunks position is set relative to the first byte of the
+   * MDAT atom payload. Set the overall offset into the file */
+  atom_moov_chunks_set_offset (qtmux->moov, qtmux->header_size);
+
+  /* Calculate which moov to rewrite. qtmux->moov_pos points to
+   * the start of the free-A header */
+  freeA_offset = qtmux->moov_pos;
+  if (qtmux->reserved_moov_first_active) {
+    GST_DEBUG_OBJECT (qtmux, "Updating pong moov header");
+    /* After this, freeA will include itself, moovA, plus the freeB
+     * header */
+    new_freeA_size = qtmux->reserved_moov_size + 16;
+  } else {
+    GST_DEBUG_OBJECT (qtmux, "Updating ping moov header");
+    new_freeA_size = 8;
+  }
+  /* the moov we update is after free-A, calculate its offset */
+  new_moov_offset = freeA_offset + new_freeA_size;
+
+  /* Swap ping-pong cadence marker */
+  qtmux->reserved_moov_first_active = !qtmux->reserved_moov_first_active;
+
+  /* seek and rewrite the MOOV atom */
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  segment.start = new_moov_offset;
+  gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
+
+  ret =
+      gst_qt_mux_send_moov (qtmux, NULL, qtmux->reserved_moov_size, FALSE,
+      TRUE);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  /* Update the estimated recording space remaining, based on amount used so
+   * far and duration muxed so far */
+  if (qtmux->last_moov_size > qtmux->base_moov_size && qtmux->last_dts > 0) {
+    GstClockTime remain;
+    GstClockTime time_muxed = qtmux->last_dts;
+
+    remain =
+        gst_util_uint64_scale (qtmux->reserved_moov_size -
+        qtmux->last_moov_size, time_muxed,
+        qtmux->last_moov_size - qtmux->base_moov_size);
+    /* Always under-estimate slightly, so users
+     * have time to stop muxing before we run out */
+    if (remain < GST_SECOND / 2)
+      remain = 0;
+    else
+      remain -= GST_SECOND / 2;
+
+    GST_INFO_OBJECT (qtmux,
+        "Reserved %u header bytes. Used %u in %" GST_TIME_FORMAT
+        ". Remaining now %u or approx %" G_GUINT64_FORMAT " ns\n",
+        qtmux->reserved_moov_size, qtmux->last_moov_size,
+        GST_TIME_ARGS (qtmux->last_dts),
+        qtmux->reserved_moov_size - qtmux->last_moov_size, remain);
+
+    GST_OBJECT_LOCK (qtmux);
+    qtmux->reserved_duration_remaining = remain;
+    qtmux->muxed_since_last_update = 0;
+    GST_DEBUG_OBJECT (qtmux, "reserved remaining duration now %"
+        G_GUINT64_FORMAT, qtmux->reserved_duration_remaining);
+    GST_OBJECT_UNLOCK (qtmux);
+  }
+
+
+  /* Now update the moov-A size. Don't pass offset, since we don't need
+   * send_free_atom() to seek for us - all our callers seek back to
+   * where they need after this, or they don't need it */
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  segment.start = freeA_offset;
+  gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
+
+  ret = gst_qt_mux_send_free_atom (qtmux, NULL, new_freeA_size, TRUE);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_qt_mux_robust_recording_update (GstQTMux * qtmux, GstClockTime position)
+{
+  GstSegment segment;
+  GstFlowReturn flow_ret;
+
+  guint64 mdat_offset = qtmux->mdat_pos + 16 + qtmux->mdat_size;
+
+  GST_OBJECT_LOCK (qtmux);
+
+  /* Update the offset of how much we've muxed, so the
+   * report of remaining space keeps counting down */
+  if (position > qtmux->last_moov_update &&
+      position - qtmux->last_moov_update > qtmux->muxed_since_last_update) {
+    GST_LOG_OBJECT (qtmux,
+        "Muxed time %" G_GUINT64_FORMAT " since last moov update",
+        qtmux->muxed_since_last_update);
+    qtmux->muxed_since_last_update = position - qtmux->last_moov_update;
+  }
+
+  /* Next, check if we're supposed to send periodic moov updates downstream */
+  if (qtmux->reserved_moov_update_period == GST_CLOCK_TIME_NONE) {
+    GST_OBJECT_UNLOCK (qtmux);
+    return GST_FLOW_OK;
+  }
+
+  /* Update if position is > the threshold or there's been no update yet */
+  if (qtmux->last_moov_update != GST_CLOCK_TIME_NONE &&
+      (position <= qtmux->last_moov_update ||
+          (position - qtmux->last_moov_update) <
+          qtmux->reserved_moov_update_period)) {
+    GST_OBJECT_UNLOCK (qtmux);
+    return GST_FLOW_OK;         /* No update needed yet */
+  }
+
+  qtmux->last_moov_update = position;
+  GST_OBJECT_UNLOCK (qtmux);
+
+  GST_DEBUG_OBJECT (qtmux, "Update moov atom, position %" GST_TIME_FORMAT
+      " mdat starts @ %" G_GUINT64_FORMAT " we were a %" G_GUINT64_FORMAT,
+      GST_TIME_ARGS (position), qtmux->mdat_pos, mdat_offset);
+
+  flow_ret = gst_qt_mux_robust_recording_rewrite_moov (qtmux);
+  if (G_UNLIKELY (flow_ret != GST_FLOW_OK))
+    return flow_ret;
+
+  /* Seek back to previous position */
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  segment.start = mdat_offset;
+  gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
+
+  return flow_ret;
+}
+
+static GstFlowReturn
+gst_qt_mux_register_and_push_sample (GstQTMux * qtmux, GstQTPad * pad,
+    GstBuffer * buffer, gboolean is_last_buffer, guint nsamples,
+    gint64 last_dts, gint64 scaled_duration, guint sample_size,
+    guint64 chunk_offset, gboolean sync, gboolean do_pts, gint64 pts_offset)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  /* note that a new chunk is started each time (not fancy but works) */
+  if (qtmux->moov_recov_file) {
+    if (!atoms_recov_write_trak_samples (qtmux->moov_recov_file, pad->trak,
+            nsamples, (gint32) scaled_duration, sample_size, chunk_offset, sync,
+            do_pts, pts_offset)) {
+      GST_WARNING_OBJECT (qtmux, "Failed to write sample information to "
+          "recovery file, disabling recovery");
+      fclose (qtmux->moov_recov_file);
+      qtmux->moov_recov_file = NULL;
+    }
+  }
+
+  switch (qtmux->mux_mode) {
+    case GST_QT_MUX_MODE_ROBUST_RECORDING_PREFILL:{
+      const TrakBufferEntryInfo *sample_entry;
+      guint64 block_idx = prefill_get_block_index (qtmux, pad);
+
+      if (block_idx >= pad->samples->len) {
+        GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
+            ("Unexpected sample %" G_GUINT64_FORMAT ", expected up to %u",
+                block_idx, pad->samples->len));
+        gst_buffer_unref (buffer);
+        return GST_FLOW_ERROR;
+      }
+
+      /* Check if all values are as expected */
+      sample_entry =
+          &g_array_index (pad->samples, TrakBufferEntryInfo, block_idx);
+
+      /* Allow +/- 1 difference for the scaled_duration to allow
+       * for some rounding errors
+       */
+      if (sample_entry->nsamples != nsamples
+          || ABSDIFF (sample_entry->delta, scaled_duration) > 1
+          || sample_entry->size != sample_size
+          || sample_entry->chunk_offset != chunk_offset
+          || sample_entry->pts_offset != pts_offset
+          || sample_entry->sync != sync) {
+        GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
+            ("Unexpected values in sample %" G_GUINT64_FORMAT,
+                pad->sample_offset + 1));
+        gst_buffer_unref (buffer);
+        return GST_FLOW_ERROR;
+      }
+
+      ret = gst_qt_mux_send_buffer (qtmux, buffer, &qtmux->mdat_size, TRUE);
+      break;
+    }
+    case GST_QT_MUX_MODE_MOOV_AT_END:
+    case GST_QT_MUX_MODE_FAST_START:
+    case GST_QT_MUX_MODE_ROBUST_RECORDING:
+      atom_trak_add_samples (pad->trak, nsamples, (gint32) scaled_duration,
+          sample_size, chunk_offset, sync, pts_offset);
+      ret = gst_qt_mux_send_buffer (qtmux, buffer, &qtmux->mdat_size, TRUE);
+      /* Check if it's time to re-write the headers in robust-recording mode */
+      if (ret == GST_FLOW_OK
+          && qtmux->mux_mode == GST_QT_MUX_MODE_ROBUST_RECORDING)
+        ret = gst_qt_mux_robust_recording_update (qtmux, pad->total_duration);
+      break;
+    case GST_QT_MUX_MODE_FRAGMENTED:
+    case GST_QT_MUX_MODE_FRAGMENTED_STREAMABLE:
+      /* ensure that always sync samples are marked as such */
+      ret = gst_qt_mux_pad_fragment_add_buffer (qtmux, pad, buffer,
+          is_last_buffer, nsamples, last_dts, (gint32) scaled_duration,
+          sample_size, !pad->sync || sync, pts_offset);
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_qt_mux_register_buffer_in_chunk (GstQTMux * qtmux, GstQTPad * pad,
+    guint buffer_size, GstClockTime duration)
+{
+  /* not that much happens here,
+   * but updating any of this very likely needs to happen all in sync,
+   * unless there is a very good reason not to */
+
+  /* for computing the avg bitrate */
+  pad->total_bytes += buffer_size;
+  pad->total_duration += duration;
+  /* for keeping track of where we are in chunk;
+   * ensures that data really is located as recorded in atoms */
+  qtmux->current_chunk_size += buffer_size;
+  qtmux->current_chunk_duration += duration;
+}
+
+static GstFlowReturn
+gst_qt_mux_check_and_update_timecode (GstQTMux * qtmux, GstQTPad * pad,
+    GstBuffer * buf, GstFlowReturn ret)
+{
+  GstVideoTimeCodeMeta *tc_meta;
+  GstVideoTimeCode *tc;
+  GstBuffer *tc_buf;
+  gsize szret;
+  guint32 frames_since_daily_jam;
+  GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
+
+  if (qtmux_klass->format != GST_QT_MUX_FORMAT_QT)
+    return ret;
+
+  if (buf == NULL || (pad->tc_trak != NULL && pad->tc_pos == -1))
+    return ret;
+
+  tc_meta = gst_buffer_get_video_time_code_meta (buf);
+  if (!tc_meta)
+    return ret;
+
+  tc = &tc_meta->tc;
+
+  /* This means we never got a timecode before */
+  if (pad->first_tc == NULL) {
+#ifndef GST_DISABLE_GST_DEBUG
+    gchar *tc_str = gst_video_time_code_to_string (tc);
+    GST_DEBUG_OBJECT (qtmux, "Found first timecode %s", tc_str);
+    g_free (tc_str);
+#endif
+    g_assert (pad->tc_trak == NULL);
+    pad->first_tc = gst_video_time_code_copy (tc);
+    /* If frames are out of order, the frame we're currently getting might
+     * not be the first one. Just write a 0 timecode for now and wait
+     * until we receive a timecode that's lower than the current one */
+    if (pad->is_out_of_order) {
+      pad->first_pts = GST_BUFFER_PTS (buf);
+      frames_since_daily_jam = 0;
+      /* Position to rewrite */
+      pad->tc_pos = qtmux->mdat_size;
+    } else {
+      frames_since_daily_jam =
+          gst_video_time_code_frames_since_daily_jam (pad->first_tc);
+      frames_since_daily_jam = GUINT32_TO_BE (frames_since_daily_jam);
+    }
+    /* Write the timecode trak now */
+    pad->tc_trak = atom_trak_new (qtmux->context);
+    atom_moov_add_trak (qtmux->moov, pad->tc_trak);
+
+    pad->trak->tref = atom_tref_new (FOURCC_tmcd);
+    atom_tref_add_entry (pad->trak->tref, pad->tc_trak->tkhd.track_ID);
+
+    atom_trak_set_timecode_type (pad->tc_trak, qtmux->context,
+        pad->trak->mdia.mdhd.time_info.timescale, pad->first_tc);
+
+    tc_buf = gst_buffer_new_allocate (NULL, 4, NULL);
+    szret = gst_buffer_fill (tc_buf, 0, &frames_since_daily_jam, 4);
+    g_assert (szret == 4);
+
+    atom_trak_add_samples (pad->tc_trak, 1, 1, 4, qtmux->mdat_size, FALSE, 0);
+    ret = gst_qt_mux_send_buffer (qtmux, tc_buf, &qtmux->mdat_size, TRUE);
+
+    /* Need to reset the current chunk (of the previous pad) here because
+     * some other data was written now above, and the pad has to start a
+     * new chunk now */
+    qtmux->current_chunk_offset = -1;
+    qtmux->current_chunk_size = 0;
+    qtmux->current_chunk_duration = 0;
+  } else if (qtmux->mux_mode == GST_QT_MUX_MODE_ROBUST_RECORDING_PREFILL) {
+    frames_since_daily_jam =
+        gst_video_time_code_frames_since_daily_jam (pad->first_tc);
+    frames_since_daily_jam = GUINT32_TO_BE (frames_since_daily_jam);
+
+    tc_buf = gst_buffer_new_allocate (NULL, 4, NULL);
+    szret = gst_buffer_fill (tc_buf, 0, &frames_since_daily_jam, 4);
+    g_assert (szret == 4);
+
+    ret = gst_qt_mux_send_buffer (qtmux, tc_buf, &qtmux->mdat_size, TRUE);
+    pad->tc_pos = -1;
+
+    qtmux->current_chunk_offset = -1;
+    qtmux->current_chunk_size = 0;
+    qtmux->current_chunk_duration = 0;
+  } else if (pad->is_out_of_order) {
+    /* Check for a lower timecode than the one stored */
+    g_assert (pad->tc_trak != NULL);
+    if (GST_BUFFER_DTS (buf) <= pad->first_pts) {
+      if (gst_video_time_code_compare (tc, pad->first_tc) == -1) {
+        gst_video_time_code_free (pad->first_tc);
+        pad->first_tc = gst_video_time_code_copy (tc);
+      }
+    } else {
+      guint64 bk_size = qtmux->mdat_size;
+      GstSegment segment;
+      /* If this frame's DTS is after the first PTS received, it means
+       * we've already received the first frame to be presented. Otherwise
+       * the decoder would need to go back in time */
+      gst_qt_mux_update_timecode (qtmux, pad);
+
+      /* Reset writing position */
+      gst_segment_init (&segment, GST_FORMAT_BYTES);
+      segment.start = bk_size;
+      gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
+    }
+  }
+
+  return ret;
+}
+
+/*
+ * Here we push the buffer and update the tables in the track atoms
+ */
+static GstFlowReturn
+gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf)
+{
+  GstBuffer *last_buf = NULL;
+  GstClockTime duration;
+  guint nsamples, sample_size;
+  guint64 chunk_offset;
+  gint64 last_dts, scaled_duration;
+  gint64 pts_offset = 0;
+  gboolean sync = FALSE;
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint buffer_size;
+
+  if (!pad->fourcc)
+    goto not_negotiated;
+
+  /* if this pad has a prepare function, call it */
+  if (pad->prepare_buf_func != NULL) {
+    GstBuffer *new_buf;
+
+    new_buf = pad->prepare_buf_func (pad, buf, qtmux);
+    if (buf && !new_buf)
+      return GST_FLOW_OK;
+    buf = new_buf;
+  }
+
+  ret = gst_qt_mux_check_and_update_timecode (qtmux, pad, buf, ret);
+  if (ret != GST_FLOW_OK) {
+    if (buf)
+      gst_buffer_unref (buf);
+    return ret;
+  }
+
+  last_buf = pad->last_buf;
+  pad->last_buf = buf;
+
+  if (last_buf == NULL) {
+#ifndef GST_DISABLE_GST_DEBUG
+    if (buf == NULL) {
+      GST_DEBUG_OBJECT (qtmux, "Pad %s has no previous buffer stored and "
+          "received NULL buffer, doing nothing",
+          GST_PAD_NAME (pad->collect.pad));
+    } else {
+      GST_LOG_OBJECT (qtmux,
+          "Pad %s has no previous buffer stored, storing now",
+          GST_PAD_NAME (pad->collect.pad));
+    }
+#endif
+    goto exit;
+  }
+
+  if (!GST_BUFFER_PTS_IS_VALID (last_buf))
+    goto no_pts;
+
+  /* if this is the first buffer, store the timestamp */
+  if (G_UNLIKELY (pad->first_ts == GST_CLOCK_TIME_NONE)) {
+    if (GST_BUFFER_PTS_IS_VALID (last_buf)) {
+      pad->first_ts = GST_BUFFER_PTS (last_buf);
+    } else if (GST_BUFFER_DTS_IS_VALID (last_buf)) {
+      pad->first_ts = GST_BUFFER_DTS (last_buf);
+    }
+
+    if (GST_BUFFER_DTS_IS_VALID (last_buf)) {
+      pad->first_dts = pad->last_dts = GST_BUFFER_DTS (last_buf);
+    } else if (GST_BUFFER_PTS_IS_VALID (last_buf)) {
+      pad->first_dts = pad->last_dts = GST_BUFFER_PTS (last_buf);
+    }
+
+    if (GST_CLOCK_TIME_IS_VALID (pad->first_ts)) {
+      GST_DEBUG ("setting first_ts to %" G_GUINT64_FORMAT, pad->first_ts);
+    } else {
+      GST_WARNING_OBJECT (qtmux, "First buffer for pad %s has no timestamp, "
+          "using 0 as first timestamp", GST_PAD_NAME (pad->collect.pad));
+      pad->first_ts = pad->first_dts = 0;
+    }
+    GST_DEBUG_OBJECT (qtmux, "Stored first timestamp for pad %s %"
+        GST_TIME_FORMAT, GST_PAD_NAME (pad->collect.pad),
+        GST_TIME_ARGS (pad->first_ts));
+  }
+
+  if (buf && GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (buf)) &&
+      GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (last_buf)) &&
+      GST_BUFFER_DTS (buf) < GST_BUFFER_DTS (last_buf)) {
+    GST_ERROR ("decreasing DTS value %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
+        GST_TIME_ARGS (GST_BUFFER_DTS (last_buf)));
+    pad->last_buf = buf = gst_buffer_make_writable (buf);
+    GST_BUFFER_DTS (buf) = GST_BUFFER_DTS (last_buf);
+  }
+
+  buffer_size = gst_buffer_get_size (last_buf);
+
+  if (qtmux->mux_mode == GST_QT_MUX_MODE_ROBUST_RECORDING_PREFILL) {
+    guint required_buffer_size = prefill_get_sample_size (qtmux, pad);
+    guint fill_size = required_buffer_size - buffer_size;
+    GstMemory *mem;
+    GstMapInfo map;
+
+    if (required_buffer_size < buffer_size) {
+      GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
+          ("Sample size %u bigger than expected maximum %u", buffer_size,
+              required_buffer_size));
+      goto bail;
+    }
+
+    if (fill_size > 0) {
+      GST_DEBUG_OBJECT (qtmux,
+          "Padding buffer by %u bytes to reach required %u bytes", fill_size,
+          required_buffer_size);
+      mem = gst_allocator_alloc (NULL, fill_size, NULL);
+      gst_memory_map (mem, &map, GST_MAP_WRITE);
+      memset (map.data, 0, map.size);
+      gst_memory_unmap (mem, &map);
+      last_buf = gst_buffer_make_writable (last_buf);
+      gst_buffer_append_memory (last_buf, mem);
+      buffer_size = required_buffer_size;
+    }
+  }
+
+  /* duration actually means time delta between samples, so we calculate
+   * the duration based on the difference in DTS or PTS, falling back
+   * to DURATION if the other two don't exist, such as with the last
+   * sample before EOS. Or use 0 if nothing else is available */
+  if (GST_BUFFER_DURATION_IS_VALID (last_buf))
+    duration = GST_BUFFER_DURATION (last_buf);
+  else
+    duration = 0;
+  if (!pad->sparse) {
+    if (buf && GST_BUFFER_DTS_IS_VALID (buf)
+        && GST_BUFFER_DTS_IS_VALID (last_buf))
+      duration = GST_BUFFER_DTS (buf) - GST_BUFFER_DTS (last_buf);
+    else if (buf && GST_BUFFER_PTS_IS_VALID (buf)
+        && GST_BUFFER_PTS_IS_VALID (last_buf))
+      duration = GST_BUFFER_PTS (buf) - GST_BUFFER_PTS (last_buf);
+  }
+
+  if (qtmux->current_pad != pad || qtmux->current_chunk_offset == -1) {
+    GST_DEBUG_OBJECT (qtmux,
+        "Switching to next chunk for pad %s:%s: offset %" G_GUINT64_FORMAT
+        ", size %" G_GUINT64_FORMAT ", duration %" GST_TIME_FORMAT,
+        GST_DEBUG_PAD_NAME (pad->collect.pad), qtmux->current_chunk_offset,
+        qtmux->current_chunk_size,
+        GST_TIME_ARGS (qtmux->current_chunk_duration));
+    qtmux->current_pad = pad;
+    if (qtmux->current_chunk_offset == -1)
+      qtmux->current_chunk_offset = qtmux->mdat_size;
+    else
+      qtmux->current_chunk_offset += qtmux->current_chunk_size;
+    qtmux->current_chunk_size = 0;
+    qtmux->current_chunk_duration = 0;
+  }
+
+  last_dts = gst_util_uint64_scale_round (pad->last_dts,
+      atom_trak_get_timescale (pad->trak), GST_SECOND);
+
+  /* fragments only deal with 1 buffer == 1 chunk (== 1 sample) */
+  if (pad->sample_size && !qtmux->fragment_sequence) {
+    GstClockTime expected_timestamp;
+
+    /* Constant size packets: usually raw audio (with many samples per
+       buffer (= chunk)), but can also be fixed-packet-size codecs like ADPCM
+     */
+    sample_size = pad->sample_size;
+    if (buffer_size % sample_size != 0)
+      goto fragmented_sample;
+
+    /* note: qt raw audio storage warps it implicitly into a timewise
+     * perfect stream, discarding buffer times.
+     * If the difference between the current PTS and the expected one
+     * becomes too big, we error out: there was a gap and we have no way to
+     * represent that, causing A/V sync to be off */
+    expected_timestamp =
+        gst_util_uint64_scale (pad->sample_offset, GST_SECOND,
+        atom_trak_get_timescale (pad->trak)) + pad->first_ts;
+    if (ABSDIFF (GST_BUFFER_DTS_OR_PTS (last_buf),
+            expected_timestamp) > qtmux->max_raw_audio_drift)
+      goto raw_audio_timestamp_drift;
+
+    if (GST_BUFFER_DURATION (last_buf) != GST_CLOCK_TIME_NONE) {
+      nsamples = gst_util_uint64_scale_round (GST_BUFFER_DURATION (last_buf),
+          atom_trak_get_timescale (pad->trak), GST_SECOND);
+      duration = GST_BUFFER_DURATION (last_buf);
+    } else {
+      nsamples = buffer_size / sample_size;
+      duration =
+          gst_util_uint64_scale_round (nsamples, GST_SECOND,
+          atom_trak_get_timescale (pad->trak));
+    }
+
+    /* timescale = samplerate */
+    scaled_duration = 1;
+    pad->last_dts =
+        pad->first_dts + gst_util_uint64_scale_round (pad->sample_offset +
+        nsamples, GST_SECOND, atom_trak_get_timescale (pad->trak));
+  } else {
+    nsamples = 1;
+    sample_size = buffer_size;
+    if (!pad->sparse && ((buf && GST_BUFFER_DTS_IS_VALID (buf))
+            || GST_BUFFER_DTS_IS_VALID (last_buf))) {
+      gint64 scaled_dts;
+      if (buf && GST_BUFFER_DTS_IS_VALID (buf)) {
+        pad->last_dts = GST_BUFFER_DTS (buf);
+      } else {
+        pad->last_dts = GST_BUFFER_DTS (last_buf) + duration;
+      }
+      if ((gint64) (pad->last_dts) < 0) {
+        scaled_dts = -gst_util_uint64_scale_round (-pad->last_dts,
+            atom_trak_get_timescale (pad->trak), GST_SECOND);
+      } else {
+        scaled_dts = gst_util_uint64_scale_round (pad->last_dts,
+            atom_trak_get_timescale (pad->trak), GST_SECOND);
+      }
+      scaled_duration = scaled_dts - last_dts;
+      last_dts = scaled_dts;
+    } else {
+      /* first convert intended timestamp (in GstClockTime resolution) to
+       * trak timescale, then derive delta;
+       * this ensures sums of (scale)delta add up to converted timestamp,
+       * which only deviates at most 1/scale from timestamp itself */
+      scaled_duration = gst_util_uint64_scale_round (pad->last_dts + duration,
+          atom_trak_get_timescale (pad->trak), GST_SECOND) - last_dts;
+      pad->last_dts += duration;
+    }
+  }
+
+  gst_qt_mux_register_buffer_in_chunk (qtmux, pad, buffer_size, duration);
+
+  chunk_offset = qtmux->current_chunk_offset;
+
+  GST_LOG_OBJECT (qtmux,
+      "Pad (%s) dts updated to %" GST_TIME_FORMAT,
+      GST_PAD_NAME (pad->collect.pad), GST_TIME_ARGS (pad->last_dts));
+  GST_LOG_OBJECT (qtmux,
+      "Adding %d samples to track, duration: %" G_GUINT64_FORMAT
+      " size: %" G_GUINT32_FORMAT " chunk offset: %" G_GUINT64_FORMAT,
+      nsamples, scaled_duration, sample_size, chunk_offset);
+
+  /* might be a sync sample */
+  if (pad->sync &&
+      !GST_BUFFER_FLAG_IS_SET (last_buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
+    GST_LOG_OBJECT (qtmux, "Adding new sync sample entry for track of pad %s",
+        GST_PAD_NAME (pad->collect.pad));
+    sync = TRUE;
+  }
+
+  if (GST_BUFFER_DTS_IS_VALID (last_buf)) {
+    last_dts = gst_util_uint64_scale_round (GST_BUFFER_DTS (last_buf),
+        atom_trak_get_timescale (pad->trak), GST_SECOND);
+    pts_offset =
+        (gint64) (gst_util_uint64_scale_round (GST_BUFFER_PTS (last_buf),
+            atom_trak_get_timescale (pad->trak), GST_SECOND) - last_dts);
+  } else {
+    pts_offset = 0;
+    last_dts = gst_util_uint64_scale_round (GST_BUFFER_PTS (last_buf),
+        atom_trak_get_timescale (pad->trak), GST_SECOND);
+  }
+  GST_DEBUG ("dts: %" GST_TIME_FORMAT " pts: %" GST_TIME_FORMAT
+      " timebase_dts: %d pts_offset: %d",
+      GST_TIME_ARGS (GST_BUFFER_DTS (last_buf)),
+      GST_TIME_ARGS (GST_BUFFER_PTS (last_buf)),
+      (int) (last_dts), (int) (pts_offset));
+
+  if (GST_CLOCK_TIME_IS_VALID (duration)
+      && (qtmux->current_chunk_duration > qtmux->longest_chunk
+          || !GST_CLOCK_TIME_IS_VALID (qtmux->longest_chunk))) {
+    GST_DEBUG_OBJECT (qtmux,
+        "New longest chunk found: %" GST_TIME_FORMAT ", pad %s",
+        GST_TIME_ARGS (qtmux->current_chunk_duration),
+        GST_PAD_NAME (pad->collect.pad));
+    qtmux->longest_chunk = qtmux->current_chunk_duration;
+  }
+
+  if (qtmux->mux_mode == GST_QT_MUX_MODE_ROBUST_RECORDING_PREFILL) {
+    const TrakBufferEntryInfo *sample_entry;
+    guint64 block_idx = prefill_get_block_index (qtmux, pad);
+
+    if (block_idx >= pad->samples->len) {
+      GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
+          ("Unexpected sample %" G_GUINT64_FORMAT ", expected up to %u",
+              block_idx, pad->samples->len));
+      goto bail;
+    }
+
+    /* Check if all values are as expected */
+    sample_entry =
+        &g_array_index (pad->samples, TrakBufferEntryInfo, block_idx);
+
+    if (chunk_offset < sample_entry->chunk_offset) {
+      guint fill_size = sample_entry->chunk_offset - chunk_offset;
+      GstBuffer *fill_buf;
+
+      fill_buf = gst_buffer_new_allocate (NULL, fill_size, NULL);
+      gst_buffer_memset (fill_buf, 0, 0, fill_size);
+
+      ret = gst_qt_mux_send_buffer (qtmux, fill_buf, &qtmux->mdat_size, TRUE);
+      if (ret != GST_FLOW_OK)
+        goto bail;
+      qtmux->current_chunk_offset = chunk_offset = sample_entry->chunk_offset;
+      qtmux->current_chunk_size = buffer_size;
+      qtmux->current_chunk_duration = duration;
+    } else if (chunk_offset != sample_entry->chunk_offset) {
+      GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
+          ("Unexpected chunk offset %" G_GUINT64_FORMAT ", expected up to %"
+              G_GUINT64_FORMAT, chunk_offset, sample_entry->chunk_offset));
+      goto bail;
+    }
+  }
+
+  /* now we go and register this buffer/sample all over */
+  ret = gst_qt_mux_register_and_push_sample (qtmux, pad, last_buf,
+      buf == NULL, nsamples, last_dts, scaled_duration, sample_size,
+      chunk_offset, sync, TRUE, pts_offset);
+  pad->sample_offset += nsamples;
+
+  /* if this is sparse and we have a next buffer, check if there is any gap
+   * between them to insert an empty sample */
+  if (pad->sparse && buf) {
+    if (pad->create_empty_buffer) {
+      GstBuffer *empty_buf;
+      gint64 empty_duration =
+          GST_BUFFER_PTS (buf) - (GST_BUFFER_PTS (last_buf) + duration);
+      gint64 empty_duration_scaled;
+      guint empty_size;
+
+      empty_buf = pad->create_empty_buffer (pad, empty_duration);
+
+      pad->last_dts = GST_BUFFER_PTS (buf);
+      empty_duration_scaled = gst_util_uint64_scale_round (pad->last_dts,
+          atom_trak_get_timescale (pad->trak), GST_SECOND)
+          - (last_dts + scaled_duration);
+      empty_size = gst_buffer_get_size (empty_buf);
+
+      gst_qt_mux_register_buffer_in_chunk (qtmux, pad, empty_size,
+          empty_duration);
+
+      ret =
+          gst_qt_mux_register_and_push_sample (qtmux, pad, empty_buf, FALSE, 1,
+          last_dts + scaled_duration, empty_duration_scaled,
+          empty_size, chunk_offset, sync, TRUE, 0);
+    } else {
+      /* our only case currently is tx3g subtitles, so there is no reason to fill this yet */
+      g_assert_not_reached ();
+      GST_WARNING_OBJECT (qtmux,
+          "no empty buffer creation function found for pad %s",
+          GST_PAD_NAME (pad->collect.pad));
+    }
+  }
+
+exit:
+
+  return ret;
+
+  /* ERRORS */
+bail:
+  {
+    gst_buffer_unref (last_buf);
+    return GST_FLOW_ERROR;
+  }
+fragmented_sample:
+  {
+    GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
+        ("Audio buffer contains fragmented sample."));
+    goto bail;
+  }
+raw_audio_timestamp_drift:
+  {
+    /* TODO: Could in theory be implemented with edit lists */
+    GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
+        ("Audio stream timestamps are drifting (got %" GST_TIME_FORMAT
+            ", expected %" GST_TIME_FORMAT "). This is not supported yet!",
+            GST_TIME_ARGS (GST_BUFFER_DTS_OR_PTS (last_buf)),
+            GST_TIME_ARGS (gst_util_uint64_scale (pad->sample_offset,
+                    GST_SECOND,
+                    atom_trak_get_timescale (pad->trak)) + pad->first_ts)));
+    goto bail;
+  }
+no_pts:
+  {
+    GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL), ("Buffer has no PTS."));
+    goto bail;
+  }
+not_negotiated:
+  {
+    GST_ELEMENT_ERROR (qtmux, CORE, NEGOTIATION, (NULL),
+        ("format wasn't negotiated before buffer flow on pad %s",
+            GST_PAD_NAME (pad->collect.pad)));
+    if (buf)
+      gst_buffer_unref (buf);
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+}
+
+/*
+ * DTS running time can be negative. There is no way to represent that in
+ * MP4 however, thus we need to offset DTS so that it starts from 0.
+ */
+static void
+gst_qt_pad_adjust_buffer_dts (GstQTMux * qtmux, GstQTPad * pad,
+    GstCollectData * cdata, GstBuffer ** buf)
+{
+  GstClockTime pts;
+  gint64 dts;
+
+  pts = GST_BUFFER_PTS (*buf);
+  dts = GST_COLLECT_PADS_DTS (cdata);
+
+  GST_LOG_OBJECT (qtmux, "selected pad %s with PTS %" GST_TIME_FORMAT
+      " and DTS %" GST_STIME_FORMAT, GST_PAD_NAME (cdata->pad),
+      GST_TIME_ARGS (pts), GST_STIME_ARGS (dts));
+
+  if (!GST_CLOCK_TIME_IS_VALID (pad->dts_adjustment)) {
+    if (GST_CLOCK_STIME_IS_VALID (dts) && dts < 0)
+      pad->dts_adjustment = -dts;
+    else
+      pad->dts_adjustment = 0;
+  }
+
+  if (pad->dts_adjustment > 0) {
+    *buf = gst_buffer_make_writable (*buf);
+
+    dts += pad->dts_adjustment;
+
+    if (GST_CLOCK_TIME_IS_VALID (pts))
+      pts += pad->dts_adjustment;
+
+    if (GST_CLOCK_STIME_IS_VALID (dts) && dts < 0) {
+      GST_WARNING_OBJECT (pad, "Decreasing DTS.");
+      dts = 0;
+    }
+
+    if (pts < dts) {
+      GST_WARNING_OBJECT (pad, "DTS is bigger then PTS");
+      pts = dts;
+    }
+
+    GST_BUFFER_PTS (*buf) = pts;
+    GST_BUFFER_DTS (*buf) = dts;
+
+    GST_LOG_OBJECT (qtmux, "time adjusted to PTS %" GST_TIME_FORMAT
+        " and DTS %" GST_TIME_FORMAT, GST_TIME_ARGS (pts), GST_TIME_ARGS (dts));
+  }
+}
+
+static GstQTPad *
+find_best_pad (GstQTMux * qtmux, GstCollectPads * pads)
+{
+  GSList *walk;
+  GstQTPad *best_pad = NULL;
+
+  if (qtmux->mux_mode == GST_QT_MUX_MODE_ROBUST_RECORDING_PREFILL) {
+    guint64 smallest_offset = G_MAXUINT64;
+    guint64 chunk_offset = 0;
+
+    for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
+      GstCollectData *cdata = (GstCollectData *) walk->data;
+      GstQTPad *qtpad = (GstQTPad *) cdata;
+      const TrakBufferEntryInfo *sample_entry;
+      guint64 block_idx, current_block_idx;
+      guint64 chunk_offset_offset = 0;
+      GstBuffer *tmp_buf =
+          gst_collect_pads_peek (pads, (GstCollectData *) qtpad);
+
+      /* Check for EOS pads and just skip them */
+      if (!tmp_buf && !qtpad->last_buf && (!qtpad->raw_audio_adapter
+              || gst_adapter_available (qtpad->raw_audio_adapter) == 0))
+        continue;
+      if (tmp_buf)
+        gst_buffer_unref (tmp_buf);
+
+      /* Find the exact offset where the next sample of this track is supposed
+       * to be written at */
+      block_idx = current_block_idx = prefill_get_block_index (qtmux, qtpad);
+      sample_entry =
+          &g_array_index (qtpad->samples, TrakBufferEntryInfo, block_idx);
+      while (block_idx > 0) {
+        const TrakBufferEntryInfo *tmp =
+            &g_array_index (qtpad->samples, TrakBufferEntryInfo, block_idx - 1);
+
+        if (tmp->chunk_offset != sample_entry->chunk_offset)
+          break;
+        chunk_offset_offset += tmp->size * tmp->nsamples;
+        block_idx--;
+      }
+
+      /* Except for the previously selected pad being EOS we always have
+       *  qtmux->current_chunk_offset + qtmux->current_chunk_size
+       *    ==
+       *  sample_entry->chunk_offset + chunk_offset_offset
+       * for the best pad. Instead of checking that, we just return the
+       * pad that has the smallest offset for the next to-be-written sample.
+       */
+      if (sample_entry->chunk_offset + chunk_offset_offset < smallest_offset) {
+        smallest_offset = sample_entry->chunk_offset + chunk_offset_offset;
+        best_pad = qtpad;
+        chunk_offset = sample_entry->chunk_offset;
+      }
+    }
+
+    if (chunk_offset != qtmux->current_chunk_offset) {
+      qtmux->current_pad = NULL;
+    }
+
+    return best_pad;
+  }
+
+  if (qtmux->current_pad && (qtmux->interleave_bytes != 0
+          || qtmux->interleave_time != 0) && (qtmux->interleave_bytes == 0
+          || qtmux->current_chunk_size <= qtmux->interleave_bytes)
+      && (qtmux->interleave_time == 0
+          || qtmux->current_chunk_duration <= qtmux->interleave_time)
+      && qtmux->mux_mode != GST_QT_MUX_MODE_FRAGMENTED
+      && qtmux->mux_mode != GST_QT_MUX_MODE_FRAGMENTED_STREAMABLE) {
+    GstBuffer *tmp_buf =
+        gst_collect_pads_peek (pads, (GstCollectData *) qtmux->current_pad);
+
+    if (tmp_buf || qtmux->current_pad->last_buf) {
+      best_pad = qtmux->current_pad;
+      if (tmp_buf)
+        gst_buffer_unref (tmp_buf);
+      GST_DEBUG_OBJECT (qtmux, "Reusing pad %s:%s",
+          GST_DEBUG_PAD_NAME (best_pad->collect.pad));
+    }
+  } else if (qtmux->collect->data->next) {
+    /* Only switch pads if we have more than one, otherwise
+     * we can just put everything into a single chunk and save
+     * a few bytes of offsets
+     */
+    if (qtmux->current_pad)
+      GST_DEBUG_OBJECT (qtmux, "Switching from pad %s:%s",
+          GST_DEBUG_PAD_NAME (qtmux->current_pad->collect.pad));
+    best_pad = qtmux->current_pad = NULL;
+  }
+
+  if (!best_pad) {
+    GstClockTime best_time = GST_CLOCK_TIME_NONE;
+
+    for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
+      GstCollectData *cdata = (GstCollectData *) walk->data;
+      GstQTPad *qtpad = (GstQTPad *) cdata;
+      GstBuffer *tmp_buf;
+      GstClockTime timestamp;
+
+      tmp_buf = gst_collect_pads_peek (pads, cdata);
+      if (!tmp_buf) {
+        /* This one is newly EOS now, finish it for real */
+        if (qtpad->last_buf) {
+          timestamp = GST_BUFFER_DTS_OR_PTS (qtpad->last_buf);
+        } else {
+          continue;
+        }
+      } else {
+        if (qtpad->last_buf)
+          timestamp = GST_BUFFER_DTS_OR_PTS (qtpad->last_buf);
+        else
+          timestamp = GST_BUFFER_DTS_OR_PTS (tmp_buf);
+      }
+
+      if (best_pad == NULL ||
+          !GST_CLOCK_TIME_IS_VALID (best_time) || timestamp < best_time) {
+        best_pad = qtpad;
+        best_time = timestamp;
+      }
+
+      if (tmp_buf)
+        gst_buffer_unref (tmp_buf);
+    }
+
+    if (best_pad) {
+      GST_DEBUG_OBJECT (qtmux, "Choosing pad %s:%s",
+          GST_DEBUG_PAD_NAME (best_pad->collect.pad));
+    } else {
+      GST_DEBUG_OBJECT (qtmux, "No best pad: EOS");
+    }
+  }
+
+  return best_pad;
+}
+
+static GstFlowReturn
+gst_qt_mux_collected (GstCollectPads * pads, gpointer user_data)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstQTMux *qtmux = GST_QT_MUX_CAST (user_data);
+  GstQTPad *best_pad = NULL;
+
+  if (G_UNLIKELY (qtmux->state == GST_QT_MUX_STATE_STARTED)) {
+    if ((ret = gst_qt_mux_start_file (qtmux)) != GST_FLOW_OK)
+      return ret;
+
+    qtmux->state = GST_QT_MUX_STATE_DATA;
+  }
+
+  if (G_UNLIKELY (qtmux->state == GST_QT_MUX_STATE_EOS))
+    return GST_FLOW_EOS;
+
+  best_pad = find_best_pad (qtmux, pads);
+
+  /* clipping already converted to running time */
+  if (best_pad != NULL) {
+    GstBuffer *buf = NULL;
+
+    if (qtmux->mux_mode != GST_QT_MUX_MODE_ROBUST_RECORDING_PREFILL ||
+        best_pad->raw_audio_adapter == NULL ||
+        best_pad->raw_audio_adapter_pts == GST_CLOCK_TIME_NONE)
+      buf = gst_collect_pads_pop (pads, (GstCollectData *) best_pad);
+
+    g_assert (buf || best_pad->last_buf || (best_pad->raw_audio_adapter
+            && gst_adapter_available (best_pad->raw_audio_adapter) > 0));
+
+    if (buf)
+      gst_qt_pad_adjust_buffer_dts (qtmux, best_pad,
+          (GstCollectData *) best_pad, &buf);
+
+    ret = gst_qt_mux_add_buffer (qtmux, best_pad, buf);
+  } else {
+    qtmux->state = GST_QT_MUX_STATE_EOS;
+    ret = gst_qt_mux_stop_file (qtmux);
+    if (ret == GST_FLOW_OK) {
+      GST_DEBUG_OBJECT (qtmux, "Pushing eos");
+      gst_pad_push_event (qtmux->srcpad, gst_event_new_eos ());
+      ret = GST_FLOW_EOS;
+    } else {
+      GST_WARNING_OBJECT (qtmux, "Failed to stop file: %s",
+          gst_flow_get_name (ret));
+    }
+  }
+
+  return ret;
+}
+
+static gboolean
+check_field (GQuark field_id, const GValue * value, gpointer user_data)
+{
+  GstStructure *structure = (GstStructure *) user_data;
+  const GValue *other = gst_structure_id_get_value (structure, field_id);
+  if (other == NULL)
+    return FALSE;
+  return gst_value_compare (value, other) == GST_VALUE_EQUAL;
+}
+
+static gboolean
+gst_qtmux_caps_is_subset_full (GstQTMux * qtmux, GstCaps * subset,
+    GstCaps * superset)
+{
+  GstStructure *sub_s = gst_caps_get_structure (subset, 0);
+  GstStructure *sup_s = gst_caps_get_structure (superset, 0);
+
+  return gst_structure_foreach (sub_s, check_field, sup_s);
+}
+
+static gboolean
+gst_qt_mux_audio_sink_set_caps (GstQTPad * qtpad, GstCaps * caps)
+{
+  GstPad *pad = qtpad->collect.pad;
+  GstQTMux *qtmux = GST_QT_MUX_CAST (gst_pad_get_parent (pad));
+  GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
+  GstStructure *structure;
+  const gchar *mimetype;
+  gint rate, channels;
+  const GValue *value = NULL;
+  const GstBuffer *codec_data = NULL;
+  GstQTMuxFormat format;
+  AudioSampleEntry entry = { 0, };
+  AtomInfo *ext_atom = NULL;
+  gint constant_size = 0;
+  const gchar *stream_format;
+  guint32 timescale;
+
+  /* does not go well to renegotiate stream mid-way, unless
+   * the old caps are a subset of the new one (this means upstream
+   * added more info to the caps, as both should be 'fixed' caps) */
+  if (qtpad->fourcc) {
+    GstCaps *current_caps;
+
+    current_caps = gst_pad_get_current_caps (pad);
+    g_assert (caps != NULL);
+
+    if (!gst_qtmux_caps_is_subset_full (qtmux, current_caps, caps)) {
+      gst_caps_unref (current_caps);
+      goto refuse_renegotiation;
+    }
+    GST_DEBUG_OBJECT (qtmux,
+        "pad %s accepted renegotiation to %" GST_PTR_FORMAT " from %"
+        GST_PTR_FORMAT, GST_PAD_NAME (pad), caps, current_caps);
+    gst_caps_unref (current_caps);
+
+    return TRUE;
+  }
+
+  GST_DEBUG_OBJECT (qtmux, "%s:%s, caps=%" GST_PTR_FORMAT,
+      GST_DEBUG_PAD_NAME (pad), caps);
+
+  qtpad->prepare_buf_func = NULL;
+
+  format = qtmux_klass->format;
+  structure = gst_caps_get_structure (caps, 0);
+  mimetype = gst_structure_get_name (structure);
+
+  /* common info */
+  if (!gst_structure_get_int (structure, "channels", &channels) ||
+      !gst_structure_get_int (structure, "rate", &rate)) {
+    goto refuse_caps;
+  }
+
+  /* optional */
+  value = gst_structure_get_value (structure, "codec_data");
+  if (value != NULL)
+    codec_data = gst_value_get_buffer (value);
+
+  qtpad->is_out_of_order = FALSE;
+
+  /* set common properties */
+  entry.sample_rate = rate;
+  entry.channels = channels;
+  /* default */
+  entry.sample_size = 16;
+  /* this is the typical compressed case */
+  if (format == GST_QT_MUX_FORMAT_QT) {
+    entry.version = 1;
+    entry.compression_id = -2;
+  }
+
+  /* now map onto a fourcc, and some extra properties */
+  if (strcmp (mimetype, "audio/mpeg") == 0) {
+    gint mpegversion = 0, mpegaudioversion = 0;
+    gint layer = -1;
+
+    gst_structure_get_int (structure, "mpegversion", &mpegversion);
+    switch (mpegversion) {
+      case 1:
+        gst_structure_get_int (structure, "layer", &layer);
+        gst_structure_get_int (structure, "mpegaudioversion",
+            &mpegaudioversion);
+
+        /* mp1/2/3 */
+        /* note: QuickTime player does not like mp3 either way in iso/mp4 */
+        if (format == GST_QT_MUX_FORMAT_QT)
+          entry.fourcc = FOURCC__mp3;
+        else {
+          entry.fourcc = FOURCC_mp4a;
+          ext_atom =
+              build_esds_extension (qtpad->trak, ESDS_OBJECT_TYPE_MPEG1_P3,
+              ESDS_STREAM_TYPE_AUDIO, codec_data, qtpad->avg_bitrate,
+              qtpad->max_bitrate);
+        }
+        if (layer == 1) {
+          g_warn_if_fail (format == GST_QT_MUX_FORMAT_MP4
+              || format == GST_QT_MUX_FORMAT_QT);
+          entry.samples_per_packet = 384;
+        } else if (layer == 2) {
+          g_warn_if_fail (format == GST_QT_MUX_FORMAT_MP4
+              || format == GST_QT_MUX_FORMAT_QT);
+          entry.samples_per_packet = 1152;
+        } else {
+          g_warn_if_fail (layer == 3);
+          entry.samples_per_packet = (mpegaudioversion <= 1) ? 1152 : 576;
+        }
+        entry.bytes_per_sample = 2;
+        break;
+      case 4:
+
+        /* check stream-format */
+        stream_format = gst_structure_get_string (structure, "stream-format");
+        if (stream_format) {
+          if (strcmp (stream_format, "raw") != 0) {
+            GST_WARNING_OBJECT (qtmux, "Unsupported AAC stream-format %s, "
+                "please use 'raw'", stream_format);
+            goto refuse_caps;
+          }
+        } else {
+          GST_WARNING_OBJECT (qtmux, "No stream-format present in caps, "
+              "assuming 'raw'");
+        }
+
+        if (!codec_data || gst_buffer_get_size ((GstBuffer *) codec_data) < 2) {
+          GST_WARNING_OBJECT (qtmux, "no (valid) codec_data for AAC audio");
+          goto refuse_caps;
+        } else {
+          guint8 profile;
+
+          gst_buffer_extract ((GstBuffer *) codec_data, 0, &profile, 1);
+          /* warn if not Low Complexity profile */
+          profile >>= 3;
+          if (profile != 2)
+            GST_WARNING_OBJECT (qtmux,
+                "non-LC AAC may not run well on (Apple) QuickTime/iTunes");
+        }
+
+        /* AAC */
+        entry.fourcc = FOURCC_mp4a;
+
+        if (format == GST_QT_MUX_FORMAT_QT)
+          ext_atom = build_mov_aac_extension (qtpad->trak, codec_data,
+              qtpad->avg_bitrate, qtpad->max_bitrate);
+        else
+          ext_atom =
+              build_esds_extension (qtpad->trak, ESDS_OBJECT_TYPE_MPEG4_P3,
+              ESDS_STREAM_TYPE_AUDIO, codec_data, qtpad->avg_bitrate,
+              qtpad->max_bitrate);
+        break;
+      default:
+        break;
+    }
+  } else if (strcmp (mimetype, "audio/AMR") == 0) {
+    entry.fourcc = FOURCC_samr;
+    entry.sample_size = 16;
+    entry.samples_per_packet = 160;
+    entry.bytes_per_sample = 2;
+    ext_atom = build_amr_extension ();
+  } else if (strcmp (mimetype, "audio/AMR-WB") == 0) {
+    entry.fourcc = FOURCC_sawb;
+    entry.sample_size = 16;
+    entry.samples_per_packet = 320;
+    entry.bytes_per_sample = 2;
+    ext_atom = build_amr_extension ();
+  } else if (strcmp (mimetype, "audio/x-raw") == 0) {
+    GstAudioInfo info;
+
+    gst_audio_info_init (&info);
+    if (!gst_audio_info_from_caps (&info, caps))
+      goto refuse_caps;
+
+    /* spec has no place for a distinction in these */
+    if (info.finfo->width != info.finfo->depth) {
+      GST_DEBUG_OBJECT (qtmux, "width must be same as depth!");
+      goto refuse_caps;
+    }
+
+    if ((info.finfo->flags & GST_AUDIO_FORMAT_FLAG_SIGNED)) {
+      if (info.finfo->endianness == G_LITTLE_ENDIAN)
+        entry.fourcc = FOURCC_sowt;
+      else if (info.finfo->endianness == G_BIG_ENDIAN)
+        entry.fourcc = FOURCC_twos;
+      else
+        entry.fourcc = FOURCC_sowt;
+      /* maximum backward compatibility; only new version for > 16 bit */
+      if (info.finfo->depth <= 16)
+        entry.version = 0;
+      /* not compressed in any case */
+      entry.compression_id = 0;
+      /* QT spec says: max at 16 bit even if sample size were actually larger,
+       * however, most players (e.g. QuickTime!) seem to disagree, so ... */
+      entry.sample_size = info.finfo->depth;
+      entry.bytes_per_sample = info.finfo->depth / 8;
+      entry.samples_per_packet = 1;
+      entry.bytes_per_packet = info.finfo->depth / 8;
+      entry.bytes_per_frame = entry.bytes_per_packet * info.channels;
+    } else {
+      if (info.finfo->width == 8 && info.finfo->depth == 8) {
+        /* fall back to old 8-bit version */
+        entry.fourcc = FOURCC_raw_;
+        entry.version = 0;
+        entry.compression_id = 0;
+        entry.sample_size = 8;
+      } else {
+        GST_DEBUG_OBJECT (qtmux, "non 8-bit PCM must be signed");
+        goto refuse_caps;
+      }
+    }
+    constant_size = (info.finfo->depth / 8) * info.channels;
+  } else if (strcmp (mimetype, "audio/x-alaw") == 0) {
+    entry.fourcc = FOURCC_alaw;
+    entry.samples_per_packet = 1023;
+    entry.bytes_per_sample = 2;
+  } else if (strcmp (mimetype, "audio/x-mulaw") == 0) {
+    entry.fourcc = FOURCC_ulaw;
+    entry.samples_per_packet = 1023;
+    entry.bytes_per_sample = 2;
+  } else if (strcmp (mimetype, "audio/x-adpcm") == 0) {
+    gint blocksize;
+    if (!gst_structure_get_int (structure, "block_align", &blocksize)) {
+      GST_DEBUG_OBJECT (qtmux, "broken caps, block_align missing");
+      goto refuse_caps;
+    }
+    /* Currently only supports WAV-style IMA ADPCM, for which the codec id is
+       0x11 */
+    entry.fourcc = MS_WAVE_FOURCC (0x11);
+    /* 4 byte header per channel (including one sample). 2 samples per byte
+       remaining. Simplifying gives the following (samples per block per
+       channel) */
+    entry.samples_per_packet = 2 * blocksize / channels - 7;
+    entry.bytes_per_sample = 2;
+
+    entry.bytes_per_frame = blocksize;
+    entry.bytes_per_packet = blocksize / channels;
+    /* ADPCM has constant size packets */
+    constant_size = 1;
+    /* TODO: I don't really understand why this helps, but it does! Constant
+     * size and compression_id of -2 seem to be incompatible, and other files
+     * in the wild use this too. */
+    entry.compression_id = -1;
+
+    ext_atom = build_ima_adpcm_extension (channels, rate, blocksize);
+  } else if (strcmp (mimetype, "audio/x-alac") == 0) {
+    GstBuffer *codec_config;
+    gint len;
+    GstMapInfo map;
+
+    entry.fourcc = FOURCC_alac;
+    gst_buffer_map ((GstBuffer *) codec_data, &map, GST_MAP_READ);
+    /* let's check if codec data already comes with 'alac' atom prefix */
+    if (!codec_data || (len = map.size) < 28) {
+      GST_DEBUG_OBJECT (qtmux, "broken caps, codec data missing");
+      gst_buffer_unmap ((GstBuffer *) codec_data, &map);
+      goto refuse_caps;
+    }
+    if (GST_READ_UINT32_LE (map.data + 4) == FOURCC_alac) {
+      len -= 8;
+      codec_config =
+          gst_buffer_copy_region ((GstBuffer *) codec_data,
+          GST_BUFFER_COPY_MEMORY, 8, len);
+    } else {
+      codec_config = gst_buffer_ref ((GstBuffer *) codec_data);
+    }
+    gst_buffer_unmap ((GstBuffer *) codec_data, &map);
+    if (len != 28) {
+      /* does not look good, but perhaps some trailing unneeded stuff */
+      GST_WARNING_OBJECT (qtmux, "unexpected codec-data size, possibly broken");
+    }
+    if (format == GST_QT_MUX_FORMAT_QT)
+      ext_atom = build_mov_alac_extension (codec_config);
+    else
+      ext_atom = build_codec_data_extension (FOURCC_alac, codec_config);
+    /* set some more info */
+    gst_buffer_map (codec_config, &map, GST_MAP_READ);
+    entry.bytes_per_sample = 2;
+    entry.samples_per_packet = GST_READ_UINT32_BE (map.data + 4);
+    gst_buffer_unmap (codec_config, &map);
+    gst_buffer_unref (codec_config);
+  } else if (strcmp (mimetype, "audio/x-ac3") == 0) {
+    entry.fourcc = FOURCC_ac_3;
+
+    /* Fixed values according to TS 102 366 but it also mentions that
+     * they should be ignored */
+    entry.channels = 2;
+    entry.sample_size = 16;
+
+    /* AC-3 needs an extension atom but its data can only be obtained from
+     * the stream itself. Abuse the prepare_buf_func so we parse a frame
+     * and get the needed data */
+    qtpad->prepare_buf_func = gst_qt_mux_prepare_parse_ac3_frame;
+  } else if (strcmp (mimetype, "audio/x-opus") == 0) {
+    /* Based on the specification defined in:
+     * https://www.opus-codec.org/docs/opus_in_isobmff.html */
+    guint8 channels, mapping_family, stream_count, coupled_count;
+    guint16 pre_skip;
+    gint16 output_gain;
+    guint32 rate;
+    guint8 channel_mapping[256];
+    const GValue *streamheader;
+    const GValue *first_element;
+    GstBuffer *header;
+
+    entry.fourcc = FOURCC_opus;
+    entry.sample_size = 16;
+
+    streamheader = gst_structure_get_value (structure, "streamheader");
+    if (streamheader && GST_VALUE_HOLDS_ARRAY (streamheader) &&
+        gst_value_array_get_size (streamheader) != 0) {
+      first_element = gst_value_array_get_value (streamheader, 0);
+      header = gst_value_get_buffer (first_element);
+      if (!gst_codec_utils_opus_parse_header (header, &rate, &channels,
+              &mapping_family, &stream_count, &coupled_count, channel_mapping,
+              &pre_skip, &output_gain)) {
+        GST_ERROR_OBJECT (qtmux, "Incomplete OpusHead");
+        goto refuse_caps;
+      }
+    } else {
+      GST_WARNING_OBJECT (qtmux,
+          "no streamheader field in caps %" GST_PTR_FORMAT, caps);
+
+      if (!gst_codec_utils_opus_parse_caps (caps, &rate, &channels,
+              &mapping_family, &stream_count, &coupled_count,
+              channel_mapping)) {
+        GST_ERROR_OBJECT (qtmux, "Incomplete Opus caps");
+        goto refuse_caps;
+      }
+      pre_skip = 0;
+      output_gain = 0;
+    }
+
+    entry.channels = channels;
+    ext_atom = build_opus_extension (rate, channels, mapping_family,
+        stream_count, coupled_count, channel_mapping, pre_skip, output_gain);
+  }
+
+  if (!entry.fourcc)
+    goto refuse_caps;
+
+  timescale = gst_qt_mux_pad_get_timescale (GST_QT_MUX_PAD_CAST (pad));
+  if (!timescale && qtmux->trak_timescale)
+    timescale = qtmux->trak_timescale;
+  else if (!timescale)
+    timescale = entry.sample_rate;
+
+  /* ok, set the pad info accordingly */
+  qtpad->fourcc = entry.fourcc;
+  qtpad->sample_size = constant_size;
+  qtpad->trak_ste =
+      (SampleTableEntry *) atom_trak_set_audio_type (qtpad->trak,
+      qtmux->context, &entry, timescale, ext_atom, constant_size);
+
+  gst_object_unref (qtmux);
+  return TRUE;
+
+  /* ERRORS */
+refuse_caps:
+  {
+    GST_WARNING_OBJECT (qtmux, "pad %s refused caps %" GST_PTR_FORMAT,
+        GST_PAD_NAME (pad), caps);
+    gst_object_unref (qtmux);
+    return FALSE;
+  }
+refuse_renegotiation:
+  {
+    GST_WARNING_OBJECT (qtmux,
+        "pad %s refused renegotiation to %" GST_PTR_FORMAT,
+        GST_PAD_NAME (pad), caps);
+    gst_object_unref (qtmux);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_qt_mux_video_sink_set_caps (GstQTPad * qtpad, GstCaps * caps)
+{
+  GstPad *pad = qtpad->collect.pad;
+  GstQTMux *qtmux = GST_QT_MUX_CAST (gst_pad_get_parent (pad));
+  GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
+  GstStructure *structure;
+  const gchar *mimetype;
+  gint width, height, depth = -1;
+  gint framerate_num, framerate_den;
+  guint32 rate;
+  const GValue *value = NULL;
+  const GstBuffer *codec_data = NULL;
+  VisualSampleEntry entry = { 0, };
+  GstQTMuxFormat format;
+  AtomInfo *ext_atom = NULL;
+  GList *ext_atom_list = NULL;
+  gboolean sync = FALSE;
+  int par_num, par_den;
+  const gchar *multiview_mode;
+
+  /* does not go well to renegotiate stream mid-way, unless
+   * the old caps are a subset of the new one (this means upstream
+   * added more info to the caps, as both should be 'fixed' caps) */
+  if (qtpad->fourcc) {
+    GstCaps *current_caps;
+
+    current_caps = gst_pad_get_current_caps (pad);
+    g_assert (caps != NULL);
+
+    if (!gst_qtmux_caps_is_subset_full (qtmux, current_caps, caps)) {
+      gst_caps_unref (current_caps);
+      goto refuse_renegotiation;
+    }
+    GST_DEBUG_OBJECT (qtmux,
+        "pad %s accepted renegotiation to %" GST_PTR_FORMAT " from %"
+        GST_PTR_FORMAT, GST_PAD_NAME (pad), caps, current_caps);
+    gst_caps_unref (current_caps);
+
+    return TRUE;
+  }
+
+  GST_DEBUG_OBJECT (qtmux, "%s:%s, caps=%" GST_PTR_FORMAT,
+      GST_DEBUG_PAD_NAME (pad), caps);
+
+  qtpad->prepare_buf_func = NULL;
+
+  format = qtmux_klass->format;
+  structure = gst_caps_get_structure (caps, 0);
+  mimetype = gst_structure_get_name (structure);
+
+  /* required parts */
+  if (!gst_structure_get_int (structure, "width", &width) ||
+      !gst_structure_get_int (structure, "height", &height))
+    goto refuse_caps;
+
+  /* optional */
+  depth = -1;
+  /* works as a default timebase */
+  framerate_num = 10000;
+  framerate_den = 1;
+  gst_structure_get_fraction (structure, "framerate", &framerate_num,
+      &framerate_den);
+  gst_structure_get_int (structure, "depth", &depth);
+  value = gst_structure_get_value (structure, "codec_data");
+  if (value != NULL)
+    codec_data = gst_value_get_buffer (value);
+
+  par_num = 1;
+  par_den = 1;
+  gst_structure_get_fraction (structure, "pixel-aspect-ratio", &par_num,
+      &par_den);
+
+  qtpad->is_out_of_order = FALSE;
+
+  /* bring frame numerator into a range that ensures both reasonable resolution
+   * as well as a fair duration */
+  qtpad->expected_sample_duration_n = framerate_num;
+  qtpad->expected_sample_duration_d = framerate_den;
+
+  rate = gst_qt_mux_pad_get_timescale (GST_QT_MUX_PAD_CAST (pad));
+  if (!rate && qtmux->trak_timescale)
+    rate = qtmux->trak_timescale;
+  else if (!rate)
+    rate = atom_framerate_to_timescale (framerate_num, framerate_den);
+
+  GST_DEBUG_OBJECT (qtmux, "Rate of video track selected: %" G_GUINT32_FORMAT,
+      rate);
+
+  multiview_mode = gst_structure_get_string (structure, "multiview-mode");
+  if (multiview_mode && !qtpad->trak->mdia.minf.stbl.svmi) {
+    GstVideoMultiviewMode mode;
+    GstVideoMultiviewFlags flags = 0;
+
+    mode = gst_video_multiview_mode_from_caps_string (multiview_mode);
+    gst_structure_get_flagset (structure, "multiview-flags", &flags, NULL);
+    switch (mode) {
+      case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
+        qtpad->trak->mdia.minf.stbl.svmi =
+            atom_svmi_new (0,
+            flags & GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST);
+        break;
+      case GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED:
+        qtpad->trak->mdia.minf.stbl.svmi =
+            atom_svmi_new (1,
+            flags & GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST);
+        break;
+      case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
+        qtpad->trak->mdia.minf.stbl.svmi =
+            atom_svmi_new (2,
+            flags & GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST);
+        break;
+      default:
+        GST_DEBUG_OBJECT (qtmux, "Unsupported multiview-mode %s",
+            multiview_mode);
+        break;
+    }
+  }
+
+  /* set common properties */
+  entry.width = width;
+  entry.height = height;
+  entry.par_n = par_num;
+  entry.par_d = par_den;
+  /* should be OK according to qt and iso spec, override if really needed */
+  entry.color_table_id = -1;
+  entry.frame_count = 1;
+  entry.depth = 24;
+
+  /* sync entries by default */
+  sync = TRUE;
+
+  /* now map onto a fourcc, and some extra properties */
+  if (strcmp (mimetype, "video/x-raw") == 0) {
+    const gchar *format;
+    GstVideoFormat fmt;
+    const GstVideoFormatInfo *vinfo;
+
+    format = gst_structure_get_string (structure, "format");
+    fmt = gst_video_format_from_string (format);
+    vinfo = gst_video_format_get_info (fmt);
+
+    switch (fmt) {
+      case GST_VIDEO_FORMAT_UYVY:
+        if (depth == -1)
+          depth = 24;
+        entry.fourcc = FOURCC_2vuy;
+        entry.depth = depth;
+        sync = FALSE;
+        break;
+      case GST_VIDEO_FORMAT_v210:
+        if (depth == -1)
+          depth = 24;
+        entry.fourcc = FOURCC_v210;
+        entry.depth = depth;
+        sync = FALSE;
+        break;
+      default:
+        if (GST_VIDEO_FORMAT_INFO_FLAGS (vinfo) & GST_VIDEO_FORMAT_FLAG_RGB) {
+          entry.fourcc = FOURCC_raw_;
+          entry.depth = GST_VIDEO_FORMAT_INFO_PSTRIDE (vinfo, 0) * 8;
+          sync = FALSE;
+        }
+        break;
+    }
+  } else if (strcmp (mimetype, "video/x-h263") == 0) {
+    ext_atom = NULL;
+    if (format == GST_QT_MUX_FORMAT_QT)
+      entry.fourcc = FOURCC_h263;
+    else
+      entry.fourcc = FOURCC_s263;
+    ext_atom = build_h263_extension ();
+    if (ext_atom != NULL)
+      ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
+  } else if (strcmp (mimetype, "video/x-divx") == 0 ||
+      strcmp (mimetype, "video/mpeg") == 0) {
+    gint version = 0;
+
+    if (strcmp (mimetype, "video/x-divx") == 0) {
+      gst_structure_get_int (structure, "divxversion", &version);
+      version = version == 5 ? 1 : 0;
+    } else {
+      gst_structure_get_int (structure, "mpegversion", &version);
+      version = version == 4 ? 1 : 0;
+    }
+    if (version) {
+      entry.fourcc = FOURCC_mp4v;
+      ext_atom =
+          build_esds_extension (qtpad->trak, ESDS_OBJECT_TYPE_MPEG4_P2,
+          ESDS_STREAM_TYPE_VISUAL, codec_data, qtpad->avg_bitrate,
+          qtpad->max_bitrate);
+      if (ext_atom != NULL)
+        ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
+      if (!codec_data)
+        GST_WARNING_OBJECT (qtmux, "no codec_data for MPEG4 video; "
+            "output might not play in Apple QuickTime (try global-headers?)");
+    }
+  } else if (strcmp (mimetype, "video/x-h264") == 0) {
+    if (!codec_data) {
+      GST_WARNING_OBJECT (qtmux, "no codec_data in h264 caps");
+      goto refuse_caps;
+    }
+
+    entry.fourcc = FOURCC_avc1;
+
+    ext_atom = build_btrt_extension (0, qtpad->avg_bitrate, qtpad->max_bitrate);
+    if (ext_atom != NULL)
+      ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
+    ext_atom = build_codec_data_extension (FOURCC_avcC, codec_data);
+    if (ext_atom != NULL)
+      ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
+  } else if (strcmp (mimetype, "video/x-h265") == 0) {
+    const gchar *format;
+
+    if (!codec_data) {
+      GST_WARNING_OBJECT (qtmux, "no codec_data in h265 caps");
+      goto refuse_caps;
+    }
+
+    format = gst_structure_get_string (structure, "stream-format");
+    if (strcmp (format, "hvc1") == 0)
+      entry.fourcc = FOURCC_hvc1;
+    else if (strcmp (format, "hev1") == 0)
+      entry.fourcc = FOURCC_hev1;
+
+    ext_atom = build_btrt_extension (0, qtpad->avg_bitrate, qtpad->max_bitrate);
+    if (ext_atom != NULL)
+      ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
+
+    ext_atom = build_codec_data_extension (FOURCC_hvcC, codec_data);
+    if (ext_atom != NULL)
+      ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
+
+  } else if (strcmp (mimetype, "video/x-svq") == 0) {
+    gint version = 0;
+    const GstBuffer *seqh = NULL;
+    const GValue *seqh_value;
+    gdouble gamma = 0;
+
+    gst_structure_get_int (structure, "svqversion", &version);
+    if (version == 3) {
+      entry.fourcc = FOURCC_SVQ3;
+      entry.version = 3;
+      entry.depth = 32;
+
+      seqh_value = gst_structure_get_value (structure, "seqh");
+      if (seqh_value) {
+        seqh = gst_value_get_buffer (seqh_value);
+        ext_atom = build_SMI_atom (seqh);
+        if (ext_atom)
+          ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
+      }
+
+      /* we need to add the gamma anyway because quicktime might crash
+       * when it doesn't find it */
+      if (!gst_structure_get_double (structure, "applied-gamma", &gamma)) {
+        /* it seems that using 0 here makes it ignored */
+        gamma = 0.0;
+      }
+      ext_atom = build_gama_atom (gamma);
+      if (ext_atom)
+        ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
+    } else {
+      GST_WARNING_OBJECT (qtmux, "SVQ version %d not supported. Please file "
+          "a bug at http://bugzilla.gnome.org", version);
+    }
+  } else if (strcmp (mimetype, "video/x-dv") == 0) {
+    gint version = 0;
+    gboolean pal = TRUE;
+
+    sync = FALSE;
+    if (framerate_num != 25 || framerate_den != 1)
+      pal = FALSE;
+    gst_structure_get_int (structure, "dvversion", &version);
+    /* fall back to typical one */
+    if (!version)
+      version = 25;
+    switch (version) {
+      case 25:
+        if (pal)
+          entry.fourcc = FOURCC_dvcp;
+        else
+          entry.fourcc = FOURCC_dvc_;
+        break;
+      case 50:
+        if (pal)
+          entry.fourcc = FOURCC_dv5p;
+        else
+          entry.fourcc = FOURCC_dv5n;
+        break;
+      default:
+        GST_WARNING_OBJECT (qtmux, "unrecognized dv version");
+        break;
+    }
+  } else if (strcmp (mimetype, "image/jpeg") == 0) {
+    entry.fourcc = FOURCC_jpeg;
+    sync = FALSE;
+  } else if (strcmp (mimetype, "image/png") == 0) {
+    entry.fourcc = FOURCC_png;
+    sync = FALSE;
+  } else if (strcmp (mimetype, "image/x-j2c") == 0 ||
+      strcmp (mimetype, "image/x-jpc") == 0) {
+    const gchar *colorspace;
+    const GValue *cmap_array;
+    const GValue *cdef_array;
+    gint ncomp = 0;
+
+    if (strcmp (mimetype, "image/x-jpc") == 0) {
+      qtpad->prepare_buf_func = gst_qt_mux_prepare_jpc_buffer;
+    }
+
+    gst_structure_get_int (structure, "num-components", &ncomp);
+    cmap_array = gst_structure_get_value (structure, "component-map");
+    cdef_array = gst_structure_get_value (structure, "channel-definitions");
+
+    ext_atom = NULL;
+    entry.fourcc = FOURCC_mjp2;
+    sync = FALSE;
+
+    colorspace = gst_structure_get_string (structure, "colorspace");
+    if (colorspace &&
+        (ext_atom =
+            build_jp2h_extension (width, height, colorspace, ncomp, cmap_array,
+                cdef_array)) != NULL) {
+      ext_atom_list = g_list_append (ext_atom_list, ext_atom);
+
+      ext_atom = build_jp2x_extension (codec_data);
+      if (ext_atom)
+        ext_atom_list = g_list_append (ext_atom_list, ext_atom);
+    } else {
+      GST_DEBUG_OBJECT (qtmux, "missing or invalid fourcc in jp2 caps");
+      goto refuse_caps;
+    }
+  } else if (strcmp (mimetype, "video/x-vp8") == 0) {
+    entry.fourcc = FOURCC_vp08;
+  } else if (strcmp (mimetype, "video/x-vp9") == 0) {
+    entry.fourcc = FOURCC_vp09;
+  } else if (strcmp (mimetype, "video/x-dirac") == 0) {
+    entry.fourcc = FOURCC_drac;
+  } else if (strcmp (mimetype, "video/x-qt-part") == 0) {
+    guint32 fourcc = 0;
+
+    gst_structure_get_uint (structure, "format", &fourcc);
+    entry.fourcc = fourcc;
+  } else if (strcmp (mimetype, "video/x-mp4-part") == 0) {
+    guint32 fourcc = 0;
+
+    gst_structure_get_uint (structure, "format", &fourcc);
+    entry.fourcc = fourcc;
+  } else if (strcmp (mimetype, "video/x-prores") == 0) {
+    const gchar *variant;
+
+    variant = gst_structure_get_string (structure, "variant");
+    if (!variant || !g_strcmp0 (variant, "standard"))
+      entry.fourcc = FOURCC_apcn;
+    else if (!g_strcmp0 (variant, "lt"))
+      entry.fourcc = FOURCC_apcs;
+    else if (!g_strcmp0 (variant, "hq"))
+      entry.fourcc = FOURCC_apch;
+    else if (!g_strcmp0 (variant, "proxy"))
+      entry.fourcc = FOURCC_apco;
+    else if (!g_strcmp0 (variant, "4444"))
+      entry.fourcc = FOURCC_ap4h;
+    else if (!g_strcmp0 (variant, "4444xq"))
+      entry.fourcc = FOURCC_ap4x;
+
+    sync = FALSE;
+
+    if (!qtmux->interleave_time_set)
+      qtmux->interleave_time = 500 * GST_MSECOND;
+    if (!qtmux->interleave_bytes_set)
+      qtmux->interleave_bytes = width > 720 ? 4 * 1024 * 1024 : 2 * 1024 * 1024;
+  } else if (strcmp (mimetype, "video/x-cineform") == 0) {
+    entry.fourcc = FOURCC_cfhd;
+    sync = FALSE;
+  }
+
+  if (!entry.fourcc)
+    goto refuse_caps;
+
+  if (qtmux_klass->format == GST_QT_MUX_FORMAT_QT ||
+      qtmux_klass->format == GST_QT_MUX_FORMAT_MP4) {
+    const gchar *s;
+    GstVideoColorimetry colorimetry;
+
+    s = gst_structure_get_string (structure, "colorimetry");
+    if (s && gst_video_colorimetry_from_string (&colorimetry, s)) {
+      ext_atom =
+          build_colr_extension (&colorimetry,
+          qtmux_klass->format == GST_QT_MUX_FORMAT_MP4);
+      if (ext_atom)
+        ext_atom_list = g_list_append (ext_atom_list, ext_atom);
+    }
+  }
+
+  if (qtmux_klass->format == GST_QT_MUX_FORMAT_QT
+      || strcmp (mimetype, "image/x-j2c") == 0
+      || strcmp (mimetype, "image/x-jpc") == 0) {
+    const gchar *s;
+    GstVideoInterlaceMode interlace_mode;
+    GstVideoFieldOrder field_order;
+    gint fields = -1;
+
+    if (strcmp (mimetype, "image/x-j2c") == 0 ||
+        strcmp (mimetype, "image/x-jpc") == 0) {
+
+      fields = 1;
+      gst_structure_get_int (structure, "fields", &fields);
+    }
+
+    s = gst_structure_get_string (structure, "interlace-mode");
+    if (s)
+      interlace_mode = gst_video_interlace_mode_from_string (s);
+    else
+      interlace_mode =
+          (fields <=
+          1) ? GST_VIDEO_INTERLACE_MODE_PROGRESSIVE :
+          GST_VIDEO_INTERLACE_MODE_MIXED;
+
+    field_order = GST_VIDEO_FIELD_ORDER_UNKNOWN;
+    if (interlace_mode == GST_VIDEO_INTERLACE_MODE_INTERLEAVED) {
+      s = gst_structure_get_string (structure, "field-order");
+      if (s)
+        field_order = gst_video_field_order_from_string (s);
+    }
+
+    ext_atom = build_fiel_extension (interlace_mode, field_order);
+    if (ext_atom)
+      ext_atom_list = g_list_append (ext_atom_list, ext_atom);
+  }
+
+
+  if (qtmux_klass->format == GST_QT_MUX_FORMAT_QT &&
+      width > 640 && width <= 1052 && height >= 480 && height <= 576) {
+    /* The 'clap' extension is also defined for MP4 but inventing values in
+     * general seems a bit tricky for this one. We only write it for
+     * SD resolution in MOV, where it is a requirement.
+     * The same goes for the 'tapt' extension, just that it is not defined for
+     * MP4 and only for MOV
+     */
+    gint dar_num, dar_den;
+    gint clef_width, clef_height, prof_width;
+    gint clap_width_n, clap_width_d, clap_height;
+    gint cdiv;
+    double approx_dar;
+
+    /* First, guess display aspect ratio based on pixel aspect ratio,
+     * width and height. We assume that display aspect ratio is either
+     * 4:3 or 16:9
+     */
+    approx_dar = (gdouble) (width * par_num) / (height * par_den);
+    if (approx_dar > 11.0 / 9 && approx_dar < 14.0 / 9) {
+      dar_num = 4;
+      dar_den = 3;
+    } else if (approx_dar > 15.0 / 9 && approx_dar < 18.0 / 9) {
+      dar_num = 16;
+      dar_den = 9;
+    } else {
+      dar_num = width * par_num;
+      dar_den = height * par_den;
+      cdiv = gst_util_greatest_common_divisor (dar_num, dar_den);
+      dar_num /= cdiv;
+      dar_den /= cdiv;
+    }
+
+    /* Then, calculate clean-aperture values (clap and clef)
+     * using the guessed DAR.
+     */
+    clef_height = clap_height = (height == 486 ? 480 : height);
+    clef_width = gst_util_uint64_scale (clef_height,
+        dar_num * G_GUINT64_CONSTANT (65536), dar_den);
+    prof_width = gst_util_uint64_scale (width,
+        par_num * G_GUINT64_CONSTANT (65536), par_den);
+    clap_width_n = clap_height * dar_num * par_den;
+    clap_width_d = dar_den * par_num;
+    cdiv = gst_util_greatest_common_divisor (clap_width_n, clap_width_d);
+    clap_width_n /= cdiv;
+    clap_width_d /= cdiv;
+
+    ext_atom = build_tapt_extension (clef_width, clef_height << 16, prof_width,
+        height << 16, width << 16, height << 16);
+    qtpad->trak->tapt = ext_atom;
+
+    ext_atom = build_clap_extension (clap_width_n, clap_width_d,
+        clap_height, 1, 0, 1, 0, 1);
+    if (ext_atom)
+      ext_atom_list = g_list_append (ext_atom_list, ext_atom);
+  }
+
+  /* ok, set the pad info accordingly */
+  qtpad->fourcc = entry.fourcc;
+  qtpad->sync = sync;
+  qtpad->trak_ste =
+      (SampleTableEntry *) atom_trak_set_video_type (qtpad->trak,
+      qtmux->context, &entry, rate, ext_atom_list);
+  if (strcmp (mimetype, "video/x-prores") == 0) {
+    SampleTableEntryMP4V *mp4v = (SampleTableEntryMP4V *) qtpad->trak_ste;
+    const gchar *compressor = NULL;
+    mp4v->spatial_quality = 0x3FF;
+    mp4v->temporal_quality = 0;
+    mp4v->vendor = FOURCC_appl;
+    mp4v->horizontal_resolution = 72 << 16;
+    mp4v->vertical_resolution = 72 << 16;
+    mp4v->depth = (entry.fourcc == FOURCC_ap4h
+        || entry.fourcc == FOURCC_ap4x) ? 32 : 24;
+
+    /* Set compressor name, required by some software */
+    switch (entry.fourcc) {
+      case FOURCC_apcn:
+        compressor = "Apple ProRes 422";
+        break;
+      case FOURCC_apcs:
+        compressor = "Apple ProRes 422 LT";
+        break;
+      case FOURCC_apch:
+        compressor = "Apple ProRes 422 HQ";
+        break;
+      case FOURCC_apco:
+        compressor = "Apple ProRes 422 Proxy";
+        break;
+      case FOURCC_ap4h:
+        compressor = "Apple ProRes 4444";
+        break;
+      case FOURCC_ap4x:
+        compressor = "Apple ProRes 4444 XQ";
+        break;
+    }
+    if (compressor) {
+      strcpy ((gchar *) mp4v->compressor + 1, compressor);
+      mp4v->compressor[0] = strlen (compressor);
+    }
+  }
+
+  gst_object_unref (qtmux);
+  return TRUE;
+
+  /* ERRORS */
+refuse_caps:
+  {
+    GST_WARNING_OBJECT (qtmux, "pad %s refused caps %" GST_PTR_FORMAT,
+        GST_PAD_NAME (pad), caps);
+    gst_object_unref (qtmux);
+    return FALSE;
+  }
+refuse_renegotiation:
+  {
+    GST_ELEMENT_WARNING (qtmux, STREAM, FORMAT,
+        ("Can't change input format at runtime."),
+        ("pad %s refused renegotiation to %" GST_PTR_FORMAT, GST_PAD_NAME (pad),
+            caps));
+    gst_object_unref (qtmux);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_qt_mux_subtitle_sink_set_caps (GstQTPad * qtpad, GstCaps * caps)
+{
+  GstPad *pad = qtpad->collect.pad;
+  GstQTMux *qtmux = GST_QT_MUX_CAST (gst_pad_get_parent (pad));
+  GstStructure *structure;
+  SubtitleSampleEntry entry = { 0, };
+
+  /* does not go well to renegotiate stream mid-way, unless
+   * the old caps are a subset of the new one (this means upstream
+   * added more info to the caps, as both should be 'fixed' caps) */
+  if (qtpad->fourcc) {
+    GstCaps *current_caps;
+
+    current_caps = gst_pad_get_current_caps (pad);
+    g_assert (caps != NULL);
+
+    if (!gst_qtmux_caps_is_subset_full (qtmux, current_caps, caps)) {
+      gst_caps_unref (current_caps);
+      goto refuse_renegotiation;
+    }
+    GST_DEBUG_OBJECT (qtmux,
+        "pad %s accepted renegotiation to %" GST_PTR_FORMAT " from %"
+        GST_PTR_FORMAT, GST_PAD_NAME (pad), caps, current_caps);
+    gst_caps_unref (current_caps);
+
+    return TRUE;
+  }
+
+  GST_DEBUG_OBJECT (qtmux, "%s:%s, caps=%" GST_PTR_FORMAT,
+      GST_DEBUG_PAD_NAME (pad), caps);
+
+  /* subtitles default */
+  subtitle_sample_entry_init (&entry);
+  qtpad->is_out_of_order = FALSE;
+  qtpad->sync = FALSE;
+  qtpad->sparse = TRUE;
+  qtpad->prepare_buf_func = NULL;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (gst_structure_has_name (structure, "text/x-raw")) {
+    const gchar *format = gst_structure_get_string (structure, "format");
+    if (format && strcmp (format, "utf8") == 0) {
+      entry.fourcc = FOURCC_tx3g;
+      qtpad->prepare_buf_func = gst_qt_mux_prepare_tx3g_buffer;
+      qtpad->create_empty_buffer = gst_qt_mux_create_empty_tx3g_buffer;
+    }
+  }
+
+  if (!entry.fourcc)
+    goto refuse_caps;
+
+  qtpad->fourcc = entry.fourcc;
+  qtpad->trak_ste =
+      (SampleTableEntry *) atom_trak_set_subtitle_type (qtpad->trak,
+      qtmux->context, &entry);
+
+  gst_object_unref (qtmux);
+  return TRUE;
+
+  /* ERRORS */
+refuse_caps:
+  {
+    GST_WARNING_OBJECT (qtmux, "pad %s refused caps %" GST_PTR_FORMAT,
+        GST_PAD_NAME (pad), caps);
+    gst_object_unref (qtmux);
+    return FALSE;
+  }
+refuse_renegotiation:
+  {
+    GST_WARNING_OBJECT (qtmux,
+        "pad %s refused renegotiation to %" GST_PTR_FORMAT, GST_PAD_NAME (pad),
+        caps);
+    gst_object_unref (qtmux);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_qt_mux_sink_event (GstCollectPads * pads, GstCollectData * data,
+    GstEvent * event, gpointer user_data)
+{
+  GstQTMux *qtmux;
+  guint32 avg_bitrate = 0, max_bitrate = 0;
+  GstPad *pad = data->pad;
+  gboolean ret = TRUE;
+
+  qtmux = GST_QT_MUX_CAST (user_data);
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+      GstQTPad *collect_pad;
+
+      gst_event_parse_caps (event, &caps);
+
+      /* find stream data */
+      collect_pad = (GstQTPad *) gst_pad_get_element_private (pad);
+      g_assert (collect_pad);
+      g_assert (collect_pad->set_caps);
+
+      ret = collect_pad->set_caps (collect_pad, caps);
+      gst_event_unref (event);
+      event = NULL;
+      break;
+    }
+    case GST_EVENT_TAG:{
+      GstTagList *list;
+      GstTagSetter *setter = GST_TAG_SETTER (qtmux);
+      GstTagMergeMode mode;
+      gchar *code;
+      GstQTPad *collect_pad;
+
+      GST_OBJECT_LOCK (qtmux);
+      mode = gst_tag_setter_get_tag_merge_mode (setter);
+      collect_pad = (GstQTPad *) gst_pad_get_element_private (pad);
+
+      gst_event_parse_tag (event, &list);
+      GST_DEBUG_OBJECT (qtmux, "received tag event on pad %s:%s : %"
+          GST_PTR_FORMAT, GST_DEBUG_PAD_NAME (pad), list);
+
+      if (gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL) {
+        gst_tag_setter_merge_tags (setter, list, mode);
+        qtmux->tags_changed = TRUE;
+      } else {
+        if (!collect_pad->tags)
+          collect_pad->tags = gst_tag_list_new_empty ();
+        gst_tag_list_insert (collect_pad->tags, list, mode);
+        collect_pad->tags_changed = TRUE;
+      }
+      GST_OBJECT_UNLOCK (qtmux);
+
+      if (gst_tag_list_get_uint (list, GST_TAG_BITRATE, &avg_bitrate) |
+          gst_tag_list_get_uint (list, GST_TAG_MAXIMUM_BITRATE, &max_bitrate)) {
+        GstQTPad *qtpad = gst_pad_get_element_private (pad);
+        g_assert (qtpad);
+
+        if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32)
+          qtpad->avg_bitrate = avg_bitrate;
+        if (max_bitrate > 0 && max_bitrate < G_MAXUINT32)
+          qtpad->max_bitrate = max_bitrate;
+      }
+
+      if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &code)) {
+        const char *iso_code = gst_tag_get_language_code_iso_639_2T (code);
+        if (iso_code) {
+          GstQTPad *qtpad = gst_pad_get_element_private (pad);
+          g_assert (qtpad);
+          if (qtpad->trak) {
+            /* https://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap4/qtff4.html */
+            qtpad->trak->mdia.mdhd.language_code =
+                (iso_code[0] - 0x60) * 0x400 + (iso_code[1] - 0x60) * 0x20 +
+                (iso_code[2] - 0x60);
+          }
+        }
+        g_free (code);
+      }
+
+      gst_event_unref (event);
+      event = NULL;
+      ret = TRUE;
+      break;
+    }
+    default:
+      break;
+  }
+
+  if (event != NULL)
+    return gst_collect_pads_event_default (pads, data, event, FALSE);
+
+  return ret;
+}
+
+static void
+gst_qt_mux_release_pad (GstElement * element, GstPad * pad)
+{
+  GstQTMux *mux = GST_QT_MUX_CAST (element);
+  GSList *walk;
+
+  GST_DEBUG_OBJECT (element, "Releasing %s:%s", GST_DEBUG_PAD_NAME (pad));
+
+  for (walk = mux->sinkpads; walk; walk = g_slist_next (walk)) {
+    GstQTPad *qtpad = (GstQTPad *) walk->data;
+    GST_DEBUG ("Checking %s:%s", GST_DEBUG_PAD_NAME (qtpad->collect.pad));
+    if (qtpad->collect.pad == pad) {
+      /* this is it, remove */
+      mux->sinkpads = g_slist_delete_link (mux->sinkpads, walk);
+      gst_element_remove_pad (element, pad);
+      break;
+    }
+  }
+
+  if (mux->current_pad && mux->current_pad->collect.pad == pad) {
+    mux->current_pad = NULL;
+    mux->current_chunk_size = 0;
+    mux->current_chunk_duration = 0;
+  }
+
+  gst_collect_pads_remove_pad (mux->collect, pad);
+
+  if (mux->sinkpads == NULL) {
+    /* No more outstanding request pads, reset our counters */
+    mux->video_pads = 0;
+    mux->audio_pads = 0;
+    mux->subtitle_pads = 0;
+  }
+}
+
+static GstPad *
+gst_qt_mux_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
+  GstQTMux *qtmux = GST_QT_MUX_CAST (element);
+  GstQTPad *collect_pad;
+  GstPad *newpad;
+  GstQTPadSetCapsFunc setcaps_func;
+  gchar *name;
+  gint pad_id;
+  gboolean lock = TRUE;
+
+  if (templ->direction != GST_PAD_SINK)
+    goto wrong_direction;
+
+  if (qtmux->state > GST_QT_MUX_STATE_STARTED)
+    goto too_late;
+
+  if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
+    setcaps_func = gst_qt_mux_audio_sink_set_caps;
+    if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
+      name = g_strdup (req_name);
+    } else {
+      name = g_strdup_printf ("audio_%u", qtmux->audio_pads++);
+    }
+  } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
+    setcaps_func = gst_qt_mux_video_sink_set_caps;
+    if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) {
+      name = g_strdup (req_name);
+    } else {
+      name = g_strdup_printf ("video_%u", qtmux->video_pads++);
+    }
+  } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%u")) {
+    setcaps_func = gst_qt_mux_subtitle_sink_set_caps;
+    if (req_name != NULL && sscanf (req_name, "subtitle_%u", &pad_id) == 1) {
+      name = g_strdup (req_name);
+    } else {
+      name = g_strdup_printf ("subtitle_%u", qtmux->subtitle_pads++);
+    }
+    lock = FALSE;
+  } else
+    goto wrong_template;
+
+  GST_DEBUG_OBJECT (qtmux, "Requested pad: %s", name);
+
+  /* create pad and add to collections */
+  newpad =
+      g_object_new (GST_TYPE_QT_MUX_PAD, "name", name, "direction",
+      templ->direction, "template", templ, NULL);
+  g_free (name);
+  collect_pad = (GstQTPad *)
+      gst_collect_pads_add_pad (qtmux->collect, newpad, sizeof (GstQTPad),
+      (GstCollectDataDestroyNotify) (gst_qt_mux_pad_reset), lock);
+  /* set up pad */
+  gst_qt_mux_pad_reset (collect_pad);
+  collect_pad->trak = atom_trak_new (qtmux->context);
+  atom_moov_add_trak (qtmux->moov, collect_pad->trak);
+
+  qtmux->sinkpads = g_slist_append (qtmux->sinkpads, collect_pad);
+
+  /* set up pad functions */
+  collect_pad->set_caps = setcaps_func;
+
+  gst_pad_set_active (newpad, TRUE);
+  gst_element_add_pad (element, newpad);
+
+  return newpad;
+
+  /* ERRORS */
+wrong_direction:
+  {
+    GST_WARNING_OBJECT (qtmux, "Request pad that is not a SINK pad.");
+    return NULL;
+  }
+too_late:
+  {
+    GST_WARNING_OBJECT (qtmux, "Not providing request pad after stream start.");
+    return NULL;
+  }
+wrong_template:
+  {
+    GST_WARNING_OBJECT (qtmux, "This is not our template!");
+    return NULL;
+  }
+}
+
+static void
+gst_qt_mux_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstQTMux *qtmux = GST_QT_MUX_CAST (object);
+
+  GST_OBJECT_LOCK (qtmux);
+  switch (prop_id) {
+    case PROP_MOVIE_TIMESCALE:
+      g_value_set_uint (value, qtmux->timescale);
+      break;
+    case PROP_TRAK_TIMESCALE:
+      g_value_set_uint (value, qtmux->trak_timescale);
+      break;
+    case PROP_DO_CTTS:
+      g_value_set_boolean (value, qtmux->guess_pts);
+      break;
+#ifndef GST_REMOVE_DEPRECATED
+    case PROP_DTS_METHOD:
+      g_value_set_enum (value, qtmux->dts_method);
+      break;
+#endif
+    case PROP_FAST_START:
+      g_value_set_boolean (value, qtmux->fast_start);
+      break;
+    case PROP_FAST_START_TEMP_FILE:
+      g_value_set_string (value, qtmux->fast_start_file_path);
+      break;
+    case PROP_MOOV_RECOV_FILE:
+      g_value_set_string (value, qtmux->moov_recov_file_path);
+      break;
+    case PROP_FRAGMENT_DURATION:
+      g_value_set_uint (value, qtmux->fragment_duration);
+      break;
+    case PROP_STREAMABLE:
+      g_value_set_boolean (value, qtmux->streamable);
+      break;
+    case PROP_RESERVED_MAX_DURATION:
+      g_value_set_uint64 (value, qtmux->reserved_max_duration);
+      break;
+    case PROP_RESERVED_DURATION_REMAINING:
+      if (qtmux->reserved_duration_remaining == GST_CLOCK_TIME_NONE)
+        g_value_set_uint64 (value, qtmux->reserved_max_duration);
+      else {
+        GstClockTime remaining = qtmux->reserved_duration_remaining;
+
+        /* Report the remaining space as the calculated remaining, minus
+         * however much we've muxed since the last update */
+        if (remaining > qtmux->muxed_since_last_update)
+          remaining -= qtmux->muxed_since_last_update;
+        else
+          remaining = 0;
+        GST_LOG_OBJECT (qtmux, "reserved duration remaining - reporting %"
+            G_GUINT64_FORMAT "(%" G_GUINT64_FORMAT " - %" G_GUINT64_FORMAT,
+            remaining, qtmux->reserved_duration_remaining,
+            qtmux->muxed_since_last_update);
+        g_value_set_uint64 (value, remaining);
+      }
+      break;
+    case PROP_RESERVED_MOOV_UPDATE_PERIOD:
+      g_value_set_uint64 (value, qtmux->reserved_moov_update_period);
+      break;
+    case PROP_RESERVED_BYTES_PER_SEC:
+      g_value_set_uint (value, qtmux->reserved_bytes_per_sec_per_trak);
+      break;
+    case PROP_RESERVED_PREFILL:
+      g_value_set_boolean (value, qtmux->reserved_prefill);
+      break;
+    case PROP_INTERLEAVE_BYTES:
+      g_value_set_uint64 (value, qtmux->interleave_bytes);
+      break;
+    case PROP_INTERLEAVE_TIME:
+      g_value_set_uint64 (value, qtmux->interleave_time);
+      break;
+    case PROP_MAX_RAW_AUDIO_DRIFT:
+      g_value_set_uint64 (value, qtmux->max_raw_audio_drift);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (qtmux);
+}
+
+static void
+gst_qt_mux_generate_fast_start_file_path (GstQTMux * qtmux)
+{
+  gchar *tmp;
+
+  g_free (qtmux->fast_start_file_path);
+  qtmux->fast_start_file_path = NULL;
+
+  tmp = g_strdup_printf ("%s%d", "qtmux", g_random_int ());
+  qtmux->fast_start_file_path = g_build_filename (g_get_tmp_dir (), tmp, NULL);
+  g_free (tmp);
+}
+
+static void
+gst_qt_mux_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstQTMux *qtmux = GST_QT_MUX_CAST (object);
+
+  GST_OBJECT_LOCK (qtmux);
+  switch (prop_id) {
+    case PROP_MOVIE_TIMESCALE:
+      qtmux->timescale = g_value_get_uint (value);
+      break;
+    case PROP_TRAK_TIMESCALE:
+      qtmux->trak_timescale = g_value_get_uint (value);
+      break;
+    case PROP_DO_CTTS:
+      qtmux->guess_pts = g_value_get_boolean (value);
+      break;
+#ifndef GST_REMOVE_DEPRECATED
+    case PROP_DTS_METHOD:
+      qtmux->dts_method = g_value_get_enum (value);
+      break;
+#endif
+    case PROP_FAST_START:
+      qtmux->fast_start = g_value_get_boolean (value);
+      break;
+    case PROP_FAST_START_TEMP_FILE:
+      g_free (qtmux->fast_start_file_path);
+      qtmux->fast_start_file_path = g_value_dup_string (value);
+      /* NULL means to generate a random one */
+      if (!qtmux->fast_start_file_path) {
+        gst_qt_mux_generate_fast_start_file_path (qtmux);
+      }
+      break;
+    case PROP_MOOV_RECOV_FILE:
+      g_free (qtmux->moov_recov_file_path);
+      qtmux->moov_recov_file_path = g_value_dup_string (value);
+      break;
+    case PROP_FRAGMENT_DURATION:
+      qtmux->fragment_duration = g_value_get_uint (value);
+      break;
+    case PROP_STREAMABLE:{
+      GstQTMuxClass *qtmux_klass =
+          (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
+      if (qtmux_klass->format == GST_QT_MUX_FORMAT_ISML) {
+        qtmux->streamable = g_value_get_boolean (value);
+      }
+      break;
+    }
+    case PROP_RESERVED_MAX_DURATION:
+      qtmux->reserved_max_duration = g_value_get_uint64 (value);
+      break;
+    case PROP_RESERVED_MOOV_UPDATE_PERIOD:
+      qtmux->reserved_moov_update_period = g_value_get_uint64 (value);
+      break;
+    case PROP_RESERVED_BYTES_PER_SEC:
+      qtmux->reserved_bytes_per_sec_per_trak = g_value_get_uint (value);
+      break;
+    case PROP_RESERVED_PREFILL:
+      qtmux->reserved_prefill = g_value_get_boolean (value);
+      break;
+    case PROP_INTERLEAVE_BYTES:
+      qtmux->interleave_bytes = g_value_get_uint64 (value);
+      qtmux->interleave_bytes_set = TRUE;
+      break;
+    case PROP_INTERLEAVE_TIME:
+      qtmux->interleave_time = g_value_get_uint64 (value);
+      qtmux->interleave_time_set = TRUE;
+      break;
+    case PROP_MAX_RAW_AUDIO_DRIFT:
+      qtmux->max_raw_audio_drift = g_value_get_uint64 (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (qtmux);
+}
+
+static GstStateChangeReturn
+gst_qt_mux_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstQTMux *qtmux = GST_QT_MUX_CAST (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_collect_pads_start (qtmux->collect);
+      qtmux->state = GST_QT_MUX_STATE_STARTED;
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_collect_pads_stop (qtmux->collect);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_qt_mux_reset (qtmux, TRUE);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+gboolean
+gst_qt_mux_register (GstPlugin * plugin)
+{
+  GTypeInfo typeinfo = {
+    sizeof (GstQTMuxClass),
+    (GBaseInitFunc) gst_qt_mux_base_init,
+    NULL,
+    (GClassInitFunc) gst_qt_mux_class_init,
+    NULL,
+    NULL,
+    sizeof (GstQTMux),
+    0,
+    (GInstanceInitFunc) gst_qt_mux_init,
+  };
+  static const GInterfaceInfo tag_setter_info = {
+    NULL, NULL, NULL
+  };
+  static const GInterfaceInfo tag_xmp_writer_info = {
+    NULL, NULL, NULL
+  };
+  static const GInterfaceInfo preset_info = {
+    NULL, NULL, NULL
+  };
+  GType type;
+  GstQTMuxFormat format;
+  GstQTMuxClassParams *params;
+  guint i = 0;
+
+  GST_DEBUG_CATEGORY_INIT (gst_qt_mux_debug, "qtmux", 0, "QT Muxer");
+
+  GST_LOG ("Registering muxers");
+
+  while (TRUE) {
+    GstQTMuxFormatProp *prop;
+    GstCaps *subtitle_caps;
+
+    prop = &gst_qt_mux_format_list[i];
+    format = prop->format;
+    if (format == GST_QT_MUX_FORMAT_NONE)
+      break;
+
+    /* create a cache for these properties */
+    params = g_new0 (GstQTMuxClassParams, 1);
+    params->prop = prop;
+    params->src_caps = gst_static_caps_get (&prop->src_caps);
+    params->video_sink_caps = gst_static_caps_get (&prop->video_sink_caps);
+    params->audio_sink_caps = gst_static_caps_get (&prop->audio_sink_caps);
+    subtitle_caps = gst_static_caps_get (&prop->subtitle_sink_caps);
+    if (!gst_caps_is_equal (subtitle_caps, GST_CAPS_NONE)) {
+      params->subtitle_sink_caps = subtitle_caps;
+    } else {
+      gst_caps_unref (subtitle_caps);
+    }
+
+    /* create the type now */
+    type = g_type_register_static (GST_TYPE_ELEMENT, prop->type_name, &typeinfo,
+        0);
+    g_type_set_qdata (type, GST_QT_MUX_PARAMS_QDATA, (gpointer) params);
+    g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, &tag_setter_info);
+    g_type_add_interface_static (type, GST_TYPE_TAG_XMP_WRITER,
+        &tag_xmp_writer_info);
+    g_type_add_interface_static (type, GST_TYPE_PRESET, &preset_info);
+
+    if (!gst_element_register (plugin, prop->name, prop->rank, type))
+      return FALSE;
+
+    i++;
+  }
+
+  GST_LOG ("Finished registering muxers");
+
+  /* FIXME: ideally classification tag should be added and
+     registered in gstreamer core gsttaglist
+   */
+
+  GST_LOG ("Registering tags");
+
+  gst_tag_register (GST_TAG_3GP_CLASSIFICATION, GST_TAG_FLAG_META,
+      G_TYPE_STRING, GST_TAG_3GP_CLASSIFICATION, "content classification",
+      gst_tag_merge_use_first);
+
+  GST_LOG ("Finished registering tags");
+
+  return TRUE;
+}
diff --git a/gst/isomp4/gstqtmux.h b/gst/isomp4/gstqtmux.h
new file mode 100644
index 0000000..c9ef21d
--- /dev/null
+++ b/gst/isomp4/gstqtmux.h
@@ -0,0 +1,328 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008-2010 Thiago Santos <thiagoss@embedded.ufcg.edu.br>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_QT_MUX_H__
+#define __GST_QT_MUX_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstcollectpads.h>
+
+#include "fourcc.h"
+#include "atoms.h"
+#include "atomsrecovery.h"
+#include "gstqtmuxmap.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_QT_MUX (gst_qt_mux_get_type())
+#define GST_QT_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_QT_MUX, GstQTMux))
+#define GST_QT_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_QT_MUX, GstQTMux))
+#define GST_IS_QT_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_QT_MUX))
+#define GST_IS_QT_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QT_MUX))
+#define GST_QT_MUX_CAST(obj) ((GstQTMux*)(obj))
+
+
+typedef struct _GstQTMux GstQTMux;
+typedef struct _GstQTMuxClass GstQTMuxClass;
+typedef struct _GstQTPad GstQTPad;
+
+/*
+ * GstQTPadPrepareBufferFunc
+ *
+ * Receives a buffer (takes ref) and returns a new buffer that should
+ * replace the passed one.
+ *
+ * Useful for when the pad/datatype needs some manipulation before
+ * being muxed. (Originally added for image/x-jpc support, for which buffers
+ * need to be wrapped into a isom box)
+ */
+typedef GstBuffer * (*GstQTPadPrepareBufferFunc) (GstQTPad * pad,
+    GstBuffer * buf, GstQTMux * qtmux);
+
+typedef gboolean (*GstQTPadSetCapsFunc) (GstQTPad * pad, GstCaps * caps);
+typedef GstBuffer * (*GstQTPadCreateEmptyBufferFunc) (GstQTPad * pad, gint64 duration);
+
+#define QTMUX_NO_OF_TS   10
+
+struct _GstQTPad
+{
+  GstCollectData collect;       /* we extend the CollectData */
+
+  /* fourcc id of stream */
+  guint32 fourcc;
+  /* whether using format that have out of order buffers */
+  gboolean is_out_of_order;
+  /* if not 0, track with constant sized samples, e.g. raw audio */
+  guint sample_size;
+  /* make sync table entry */
+  gboolean sync;
+  /* if it is a sparse stream
+   * (meaning we can't use PTS differences to compute duration) */
+  gboolean sparse;
+  /* bitrates */
+  guint32 avg_bitrate, max_bitrate;
+  /* expected sample duration */
+  guint expected_sample_duration_n;
+  guint expected_sample_duration_d;
+
+  /* for avg bitrate calculation */
+  guint64 total_bytes;
+  guint64 total_duration;
+
+  GstBuffer *last_buf;
+  /* dts of last_buf */
+  GstClockTime last_dts;
+  guint64 sample_offset;
+
+  /* This is compensate for CTTS */
+  GstClockTime dts_adjustment;
+
+  /* store the first timestamp for comparing with other streams and
+   * know if there are late streams */
+  /* subjected to dts adjustment */
+  GstClockTime first_ts;
+  GstClockTime first_dts;
+
+  /* all the atom and chunk book-keeping is delegated here
+   * unowned/uncounted reference, parent MOOV owns */
+  AtomTRAK *trak;
+  AtomTRAK *tc_trak;
+  SampleTableEntry *trak_ste;
+  /* fragmented support */
+  /* meta data book-keeping delegated here */
+  AtomTRAF *traf;
+  /* fragment buffers */
+  ATOM_ARRAY (GstBuffer *) fragment_buffers;
+  /* running fragment duration */
+  gint64 fragment_duration;
+  /* optional fragment index book-keeping */
+  AtomTFRA *tfra;
+
+  /* Set when tags are received, cleared when written to moov */
+  gboolean tags_changed;
+
+  GstTagList *tags;
+
+  /* if nothing is set, it won't be called */
+  GstQTPadPrepareBufferFunc prepare_buf_func;
+  GstQTPadSetCapsFunc set_caps;
+  GstQTPadCreateEmptyBufferFunc create_empty_buffer;
+
+  /* SMPTE timecode */
+  GstVideoTimeCode *first_tc;
+  GstClockTime first_pts;
+  guint64 tc_pos;
+
+  /* for keeping track in pre-fill mode */
+  GArray *samples;
+  /* current sample */
+  GstAdapter *raw_audio_adapter;
+  guint64 raw_audio_adapter_offset;
+  GstClockTime raw_audio_adapter_pts;
+};
+
+typedef enum _GstQTMuxState
+{
+  GST_QT_MUX_STATE_NONE,
+  GST_QT_MUX_STATE_STARTED,
+  GST_QT_MUX_STATE_DATA,
+  GST_QT_MUX_STATE_EOS
+} GstQTMuxState;
+
+typedef enum _GstQtMuxMode {
+    GST_QT_MUX_MODE_MOOV_AT_END,
+    GST_QT_MUX_MODE_FRAGMENTED,
+    GST_QT_MUX_MODE_FRAGMENTED_STREAMABLE,
+    GST_QT_MUX_MODE_FAST_START,
+    GST_QT_MUX_MODE_ROBUST_RECORDING,
+    GST_QT_MUX_MODE_ROBUST_RECORDING_PREFILL,
+} GstQtMuxMode;
+
+struct _GstQTMux
+{
+  GstElement element;
+
+  GstPad *srcpad;
+  GstCollectPads *collect;
+  GSList *sinkpads;
+
+  /* state */
+  GstQTMuxState state;
+
+  /* Mux mode, inferred from property
+   * set in gst_qt_mux_start_file() */
+  GstQtMuxMode mux_mode;
+
+  /* size of header (prefix, atoms (ftyp, possibly moov, mdat header)) */
+  guint64 header_size;
+  /* accumulated size of raw media data (not including mdat header) */
+  guint64 mdat_size;
+  /* position of the moov (for fragmented mode) or reserved moov atom
+   * area (for robust-muxing mode) */
+  guint64 moov_pos;
+  /* position of mdat atom header (for later updating of size) in
+   * moov-at-end, fragmented and robust-muxing modes */
+  guint64 mdat_pos;
+
+  /* keep track of the largest chunk to fine-tune brands */
+  GstClockTime longest_chunk;
+
+  /* Earliest timestamp across all pads/traks
+   * (unadjusted incoming PTS) */
+  GstClockTime first_ts;
+  /* Last DTS across all pads (= duration) */
+  GstClockTime last_dts;
+
+  /* Last pad we used for writing the current chunk */
+  GstQTPad *current_pad;
+  guint64 current_chunk_size;
+  GstClockTime current_chunk_duration;
+  guint64 current_chunk_offset;
+
+  /* atom helper objects */
+  AtomsContext *context;
+  AtomFTYP *ftyp;
+  AtomMOOV *moov;
+  GSList *extra_atoms; /* list of extra top-level atoms (e.g. UUID for xmp)
+                        * Stored as AtomInfo structs */
+
+  /* Set when tags are received, cleared when written to moov */
+  gboolean tags_changed;
+
+  /* fragmented file index */
+  AtomMFRA *mfra;
+
+  /* fast start */
+  FILE *fast_start_file;
+
+  /* moov recovery */
+  FILE *moov_recov_file;
+
+  /* fragment sequence */
+  guint32 fragment_sequence;
+
+  /* properties */
+  guint32 timescale;
+  guint32 trak_timescale;
+  AtomsTreeFlavor flavor;
+  gboolean fast_start;
+  gboolean guess_pts;
+#ifndef GST_REMOVE_DEPRECATED
+  gint dts_method;
+#endif
+  gchar *fast_start_file_path;
+  gchar *moov_recov_file_path;
+  guint32 fragment_duration;
+  /* Whether or not to work in 'streamable' mode and not
+   * seek to rewrite headers - only valid for fragmented
+   * mode. */
+  gboolean streamable;
+
+  /* Requested target maximum duration */
+  GstClockTime reserved_max_duration;
+  /* Estimate of remaining reserved header space (in ns of recording) */
+  GstClockTime reserved_duration_remaining;
+  /* Multiplier for conversion from reserved_max_duration to bytes */
+  guint reserved_bytes_per_sec_per_trak;
+
+  guint64 interleave_bytes;
+  GstClockTime interleave_time;
+  gboolean interleave_bytes_set, interleave_time_set;
+
+  GstClockTime max_raw_audio_drift;
+
+  /* Reserved minimum MOOV size in bytes
+   * This is converted from reserved_max_duration
+   * using the bytes/trak/sec estimate */
+  guint32 reserved_moov_size;
+  /* Basic size of the moov (static headers + tags) */
+  guint32 base_moov_size;
+  /* Size of the most recently generated moov header */
+  guint32 last_moov_size;
+  /* True if the first moov in the ping-pong buffers
+   * is the active one. See gst_qt_mux_robust_recording_rewrite_moov() */
+  gboolean reserved_moov_first_active;
+
+  /* Tracking of periodic MOOV updates */
+  GstClockTime last_moov_update;
+  GstClockTime reserved_moov_update_period;
+  GstClockTime muxed_since_last_update;
+
+  gboolean reserved_prefill;
+
+  /* for request pad naming */
+  guint video_pads, audio_pads, subtitle_pads;
+};
+
+struct _GstQTMuxClass
+{
+  GstElementClass parent_class;
+
+  GstQTMuxFormat format;
+};
+
+/* type register helper struct */
+typedef struct _GstQTMuxClassParams
+{
+  GstQTMuxFormatProp *prop;
+  GstCaps *src_caps;
+  GstCaps *video_sink_caps;
+  GstCaps *audio_sink_caps;
+  GstCaps *subtitle_sink_caps;
+} GstQTMuxClassParams;
+
+#define GST_QT_MUX_PARAMS_QDATA g_quark_from_static_string("qt-mux-params")
+
+GType gst_qt_mux_get_type (void);
+gboolean gst_qt_mux_register (GstPlugin * plugin);
+
+/* FIXME: ideally classification tag should be added and
+ * registered in gstreamer core gsttaglist
+ *
+ * this tag is a string in the format: entityfourcc://table_num/content
+ * FIXME Shouldn't we add a field for 'language'?
+ */
+#define GST_TAG_3GP_CLASSIFICATION "classification"
+
+G_END_DECLS
+
+#endif /* __GST_QT_MUX_H__ */
diff --git a/gst/isomp4/gstqtmuxmap.c b/gst/isomp4/gstqtmuxmap.c
new file mode 100644
index 0000000..4e34e13
--- /dev/null
+++ b/gst/isomp4/gstqtmuxmap.c
@@ -0,0 +1,412 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+ * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "gstqtmuxmap.h"
+#include "fourcc.h"
+
+/* static info related to various format */
+
+#define COMMON_VIDEO_CAPS \
+  "width = (int) [ 16, MAX ], " \
+  "height = (int) [ 16, MAX ]"
+
+#define COMMON_VIDEO_CAPS_NO_FRAMERATE \
+  "width = (int) [ 16, MAX ], " \
+  "height = (int) [ 16, MAX ] "
+
+#define H263_CAPS \
+  "video/x-h263, " \
+  COMMON_VIDEO_CAPS
+
+#define H264_CAPS \
+  "video/x-h264, " \
+  "stream-format = (string) avc, " \
+  "alignment = (string) au, " \
+  COMMON_VIDEO_CAPS
+
+#define H265_CAPS \
+  "video/x-h265, " \
+  "stream-format = (string) { hvc1, hev1 }, " \
+  "alignment = (string) au, " \
+  COMMON_VIDEO_CAPS
+
+#define MPEG4V_CAPS \
+  "video/mpeg, " \
+  "mpegversion = (int) 4, "\
+  "systemstream = (boolean) false, " \
+  COMMON_VIDEO_CAPS "; " \
+  "video/x-divx, " \
+  "divxversion = (int) 5, "\
+  COMMON_VIDEO_CAPS
+
+#define PRORES_CAPS \
+  "video/x-prores, " \
+  "variant = (string) {standard, lt, hq, proxy, 4444, 4444xq}, " \
+  COMMON_VIDEO_CAPS
+
+#define CINEFORM_CAPS \
+  "video/x-cineform, " \
+  COMMON_VIDEO_CAPS
+
+#define SVQ_CAPS \
+  "video/x-svq, " \
+  "svqversion = (int) 3, " \
+  COMMON_VIDEO_CAPS
+
+#define COMMON_AUDIO_CAPS(c, r) \
+  "channels = (int) [ 1, " G_STRINGIFY (c) " ], " \
+  "rate = (int) [ 1, " G_STRINGIFY (r) " ]"
+
+#define PCM_CAPS \
+  "audio/x-raw, " \
+  "format = (string) { S16LE, S16BE, S8, U8 }, " \
+  "layout = (string) interleaved, " \
+  COMMON_AUDIO_CAPS (2, MAX)
+
+#define PCM_CAPS_FULL \
+  "audio/x-raw, " \
+  "format = (string) { S32LE, S32BE, S24LE, S24BE, S16LE, S16BE, S8, U8 }, " \
+  "layout = (string) interleaved, " \
+  COMMON_AUDIO_CAPS (2, MAX)
+
+#define PCM_CAPS_UNPOSITIONED \
+  "audio/x-raw, " \
+  "format = (string) { S32LE, S32BE, S24LE, S24BE, S16LE, S16BE, S8, U8 }, " \
+  "layout = (string) interleaved, " \
+  "channel-mask = (bitmask) 0, " \
+  COMMON_AUDIO_CAPS (16, MAX)
+
+#define MP3_CAPS \
+  "audio/mpeg, " \
+  "mpegversion = (int) 1, " \
+  "layer = (int) 3, " \
+  COMMON_AUDIO_CAPS (2, MAX)
+
+#define MP123_CAPS \
+  "audio/mpeg, " \
+  "mpegversion = (int) 1, " \
+  "layer = (int) [1, 3], " \
+  COMMON_AUDIO_CAPS (2, MAX)
+
+#define AAC_CAPS \
+  "audio/mpeg, " \
+  "mpegversion = (int) 4, " \
+  "stream-format = (string) raw, " \
+  COMMON_AUDIO_CAPS (8, MAX)
+
+#define AC3_CAPS \
+  "audio/x-ac3, " \
+  COMMON_AUDIO_CAPS (6, MAX)
+
+#define AMR_CAPS \
+  "audio/AMR, " \
+  "rate = (int) 8000, " \
+  "channels = [ 1, 2 ]; " \
+  "audio/AMR-WB, " \
+  "rate = (int) 16000, " \
+  "channels = [ 1, 2 ] "
+
+#define ADPCM_CAPS  \
+  "audio/x-adpcm, " \
+  "layout = (string)dvi, " \
+  "block_align = (int)[64, 8096], " \
+  COMMON_AUDIO_CAPS(2, MAX)
+
+#define ALAC_CAPS \
+  "audio/x-alac, " \
+  COMMON_AUDIO_CAPS(2, MAX)
+
+#define OPUS_CAPS \
+  "audio/x-opus, " \
+  "channel-mapping-family = (int) [0, 255], " \
+  COMMON_AUDIO_CAPS(8, MAX)
+
+
+#define TEXT_UTF8 \
+  "text/x-raw, " \
+  "format=(string)utf8"
+
+/* FIXME 0.11 - take a look at bugs #580005 and #340375 */
+GstQTMuxFormatProp gst_qt_mux_format_list[] = {
+  /* original QuickTime format; see Apple site (e.g. qtff.pdf) */
+  {
+        GST_QT_MUX_FORMAT_QT,
+        GST_RANK_PRIMARY,
+        "qtmux",
+        "QuickTime",
+        "GstQTMux",
+        GST_STATIC_CAPS ("video/quicktime, variant = (string) apple; "
+            "video/quicktime"),
+        GST_STATIC_CAPS ("video/x-raw, "
+            "format = (string) { RGB, UYVY, v210 }, "
+            COMMON_VIDEO_CAPS "; "
+            MPEG4V_CAPS "; "
+            PRORES_CAPS "; "
+            CINEFORM_CAPS "; "
+            H263_CAPS "; "
+            H264_CAPS "; "
+            H265_CAPS "; "
+            SVQ_CAPS "; "
+            "video/x-dv, "
+            "systemstream = (boolean) false, "
+            COMMON_VIDEO_CAPS "; "
+            "image/jpeg, "
+            COMMON_VIDEO_CAPS_NO_FRAMERATE "; "
+            "image/png, "
+            COMMON_VIDEO_CAPS_NO_FRAMERATE "; "
+            "video/x-vp8, "
+            COMMON_VIDEO_CAPS "; "
+            "video/x-vp9, "
+            COMMON_VIDEO_CAPS "; "
+            "video/x-dirac, "
+            COMMON_VIDEO_CAPS "; " "video/x-qt-part, " COMMON_VIDEO_CAPS),
+        GST_STATIC_CAPS (PCM_CAPS_FULL "; "
+            PCM_CAPS_UNPOSITIONED " ; "
+            MP123_CAPS " ; "
+            AAC_CAPS " ; "
+            AC3_CAPS " ; "
+            ADPCM_CAPS " ; "
+            "audio/x-alaw, " COMMON_AUDIO_CAPS (2, MAX) "; "
+            "audio/x-mulaw, " COMMON_AUDIO_CAPS (2, MAX) "; "
+            AMR_CAPS " ; " ALAC_CAPS " ; " OPUS_CAPS),
+      GST_STATIC_CAPS (TEXT_UTF8)}
+  ,
+  /* ISO 14496-14: mp42 as ISO base media extension
+   * (supersedes original ISO 144996-1 mp41) */
+  {
+        GST_QT_MUX_FORMAT_MP4,
+        GST_RANK_PRIMARY,
+        "mp4mux",
+        "MP4",
+        "GstMP4Mux",
+        GST_STATIC_CAPS ("video/quicktime, variant = (string) iso"),
+        GST_STATIC_CAPS (MPEG4V_CAPS "; " H264_CAPS ";" H265_CAPS ";"
+            "video/x-mp4-part," COMMON_VIDEO_CAPS),
+        GST_STATIC_CAPS (MP123_CAPS "; "
+            AAC_CAPS " ; " AC3_CAPS " ; " ALAC_CAPS " ; " OPUS_CAPS),
+      GST_STATIC_CAPS (TEXT_UTF8)}
+  ,
+  /* Microsoft Smooth Streaming fmp4/isml */
+  /* TODO add WMV/WMA support */
+  {
+        GST_QT_MUX_FORMAT_ISML,
+        GST_RANK_PRIMARY,
+        "ismlmux",
+        "ISML",
+        "GstISMLMux",
+        GST_STATIC_CAPS ("video/quicktime, variant = (string) iso-fragmented"),
+        GST_STATIC_CAPS (MPEG4V_CAPS "; " H264_CAPS),
+        GST_STATIC_CAPS (MP3_CAPS "; " AAC_CAPS),
+      GST_STATIC_CAPS_NONE}
+  ,
+  /* 3GPP Technical Specification 26.244 V7.3.0
+   * (extended in 3GPP2 File Formats for Multimedia Services) */
+  {
+        GST_QT_MUX_FORMAT_3GP,
+        GST_RANK_PRIMARY,
+        "3gppmux",
+        "3GPP",
+        "Gst3GPPMux",
+        GST_STATIC_CAPS ("video/quicktime, variant = (string) 3gpp"),
+        GST_STATIC_CAPS (H263_CAPS "; " MPEG4V_CAPS "; " H264_CAPS),
+        GST_STATIC_CAPS (AMR_CAPS "; " MP3_CAPS "; " AAC_CAPS "; " AC3_CAPS),
+      GST_STATIC_CAPS (TEXT_UTF8)}
+  ,
+  /* ISO 15444-3: Motion-JPEG-2000 (also ISO base media extension) */
+  {
+        GST_QT_MUX_FORMAT_MJ2,
+        GST_RANK_PRIMARY,
+        "mj2mux",
+        "MJ2",
+        "GstMJ2Mux",
+        GST_STATIC_CAPS ("video/mj2"),
+        GST_STATIC_CAPS ("image/x-j2c, " COMMON_VIDEO_CAPS "; "
+            "image/x-jpc, " COMMON_VIDEO_CAPS),
+        GST_STATIC_CAPS (PCM_CAPS),
+      GST_STATIC_CAPS_NONE}
+  ,
+  {
+        GST_QT_MUX_FORMAT_NONE,
+      }
+};
+
+/* pretty static, but may turn out needed a few times */
+AtomsTreeFlavor
+gst_qt_mux_map_format_to_flavor (GstQTMuxFormat format)
+{
+  if (format == GST_QT_MUX_FORMAT_QT)
+    return ATOMS_TREE_FLAVOR_MOV;
+  else if (format == GST_QT_MUX_FORMAT_3GP)
+    return ATOMS_TREE_FLAVOR_3GP;
+  else if (format == GST_QT_MUX_FORMAT_ISML)
+    return ATOMS_TREE_FLAVOR_ISML;
+  else
+    return ATOMS_TREE_FLAVOR_ISOM;
+}
+
+static void
+gst_qt_mux_map_check_tracks (AtomMOOV * moov, gint * _video, gint * _audio,
+    gboolean * _has_h264)
+{
+  GList *it;
+  gint video = 0, audio = 0;
+  gboolean has_h264 = FALSE;
+
+  for (it = moov->traks; it != NULL; it = g_list_next (it)) {
+    AtomTRAK *track = it->data;
+
+    if (track->is_video) {
+      video++;
+      if (track->is_h264)
+        has_h264 = TRUE;
+    } else
+      audio++;
+  }
+
+  if (_video)
+    *_video = video;
+  if (_audio)
+    *_audio = audio;
+  if (_has_h264)
+    *_has_h264 = has_h264;
+}
+
+/* pretty static, but possibly dynamic format info */
+
+/* notes:
+ * - avc1 brand is not used, since the specific extensions indicated by it
+ *   are not used (e.g. sample groupings, etc)
+ * - TODO: maybe even more 3GPP brand fine-tuning ??
+ *   (but that might need ftyp rewriting at the end) */
+void
+gst_qt_mux_map_format_to_header (GstQTMuxFormat format, GstBuffer ** _prefix,
+    guint32 * _major, guint32 * _version, GList ** _compatible, AtomMOOV * moov,
+    GstClockTime longest_chunk, gboolean faststart)
+{
+  static const guint32 qt_brands[] = { 0 };
+  static const guint32 mp4_brands[] =
+      { FOURCC_mp41, FOURCC_isom, FOURCC_iso2, 0 };
+  static const guint32 isml_brands[] = { FOURCC_iso2, 0 };
+  static const guint32 gpp_brands[] = { FOURCC_isom, FOURCC_iso2, 0 };
+  static const guint32 mjp2_brands[] = { FOURCC_isom, FOURCC_iso2, 0 };
+  static const guint8 mjp2_prefix[] =
+      { 0, 0, 0, 12, 'j', 'P', ' ', ' ', 0x0D, 0x0A, 0x87, 0x0A };
+  const guint32 *comp = NULL;
+  guint32 major = 0, version = 0;
+  GstBuffer *prefix = NULL;
+  GList *result = NULL;
+
+  g_return_if_fail (_prefix != NULL);
+  g_return_if_fail (_major != NULL);
+  g_return_if_fail (_version != NULL);
+  g_return_if_fail (_compatible != NULL);
+
+  switch (format) {
+    case GST_QT_MUX_FORMAT_QT:
+      major = FOURCC_qt__;
+      comp = qt_brands;
+      version = 0x20050300;
+      break;
+    case GST_QT_MUX_FORMAT_MP4:
+      major = FOURCC_mp42;
+      comp = mp4_brands;
+      break;
+    case GST_QT_MUX_FORMAT_ISML:
+      major = FOURCC_isml;
+      comp = isml_brands;
+      break;
+    case GST_QT_MUX_FORMAT_3GP:
+    {
+      gint video, audio;
+      gboolean has_h264;
+
+      gst_qt_mux_map_check_tracks (moov, &video, &audio, &has_h264);
+      /* only track restriction really matters for Basic Profile */
+      if (video <= 1 && audio <= 1) {
+        /* it seems only newer spec knows about H264 */
+        major = has_h264 ? FOURCC_3gp6 : FOURCC_3gp4;
+        version = has_h264 ? 0x100 : 0x200;
+      } else {
+        major = FOURCC_3gg6;
+        version = 0x100;
+      }
+      comp = gpp_brands;
+
+      /*
+       * We assume that we have chunks in dts order
+       */
+      if (faststart && longest_chunk <= GST_SECOND) {
+        /* add progressive download profile */
+        result = g_list_append (result, GUINT_TO_POINTER (FOURCC_3gr6));
+      }
+      break;
+    }
+    case GST_QT_MUX_FORMAT_MJ2:
+    {
+      major = FOURCC_mjp2;
+      comp = mjp2_brands;
+      version = 0;
+      prefix = gst_buffer_new_and_alloc (sizeof (mjp2_prefix));
+      gst_buffer_fill (prefix, 0, mjp2_prefix, sizeof (mjp2_prefix));
+      break;
+    }
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+
+  /* convert list to list, hm */
+  while (comp && *comp != 0) {
+    /* order matters over efficiency */
+    result = g_list_append (result, GUINT_TO_POINTER (*comp));
+    comp++;
+  }
+
+  *_major = major;
+  *_version = version;
+  *_prefix = prefix;
+  *_compatible = result;
+
+  /* TODO 3GPP may include mp42 as compatible if applicable */
+  /* TODO 3GPP major brand 3gp7 if at most 1 video and audio track */
+}
diff --git a/gst/isomp4/gstqtmuxmap.h b/gst/isomp4/gstqtmuxmap.h
new file mode 100644
index 0000000..e578a36
--- /dev/null
+++ b/gst/isomp4/gstqtmuxmap.h
@@ -0,0 +1,85 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+ * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_QT_MUX_MAP_H__
+#define __GST_QT_MUX_MAP_H__
+
+#include "atoms.h"
+
+#include <glib.h>
+#include <gst/gst.h>
+
+typedef enum _GstQTMuxFormat
+{
+  GST_QT_MUX_FORMAT_NONE = 0,
+  GST_QT_MUX_FORMAT_QT,
+  GST_QT_MUX_FORMAT_MP4,
+  GST_QT_MUX_FORMAT_3GP,
+  GST_QT_MUX_FORMAT_MJ2,
+  GST_QT_MUX_FORMAT_ISML
+} GstQTMuxFormat;
+
+typedef struct _GstQTMuxFormatProp
+{
+  GstQTMuxFormat format;
+  GstRank rank;
+  const gchar *name;
+  const gchar *long_name;
+  const gchar *type_name;
+  GstStaticCaps src_caps;
+  GstStaticCaps video_sink_caps;
+  GstStaticCaps audio_sink_caps;
+  GstStaticCaps subtitle_sink_caps;
+} GstQTMuxFormatProp;
+
+extern GstQTMuxFormatProp gst_qt_mux_format_list[];
+
+void            gst_qt_mux_map_format_to_header      (GstQTMuxFormat format, GstBuffer ** _prefix,
+                                                      guint32 * _major, guint32 * verson,
+                                                      GList ** _compatible, AtomMOOV * moov,
+                                                      GstClockTime longest_chunk,
+                                                      gboolean faststart);
+
+AtomsTreeFlavor gst_qt_mux_map_format_to_flavor      (GstQTMuxFormat format);
+
+#endif /* __GST_QT_MUX_MAP_H__ */
diff --git a/gst/isomp4/gstrtpxqtdepay.c b/gst/isomp4/gstrtpxqtdepay.c
new file mode 100644
index 0000000..8a3c60e
--- /dev/null
+++ b/gst/isomp4/gstrtpxqtdepay.c
@@ -0,0 +1,687 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * based on http://developer.apple.com/quicktime/icefloe/dispatch026.html
+ */
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <string.h>
+#include "gstrtpxqtdepay.h"
+
+#define MAKE_TLV(a,b)  (((a)<<8)|(b))
+
+#define TLV_sd	MAKE_TLV ('s','d')
+#define TLV_qt	MAKE_TLV ('q','t')
+#define TLV_ti	MAKE_TLV ('t','i')
+#define TLV_ly	MAKE_TLV ('l','y')
+#define TLV_vo	MAKE_TLV ('v','o')
+#define TLV_mx	MAKE_TLV ('m','x')
+#define TLV_tr	MAKE_TLV ('t','r')
+#define TLV_tw	MAKE_TLV ('t','w')
+#define TLV_th	MAKE_TLV ('t','h')
+#define TLV_la	MAKE_TLV ('l','a')
+#define TLV_rt	MAKE_TLV ('r','t')
+#define TLV_gm	MAKE_TLV ('g','m')
+#define TLV_oc	MAKE_TLV ('o','c')
+#define TLV_cr	MAKE_TLV ('c','r')
+#define TLV_du	MAKE_TLV ('d','u')
+#define TLV_po	MAKE_TLV ('p','o')
+
+#define QT_UINT32(a)  (GST_READ_UINT32_BE(a))
+#define QT_UINT24(a)  (GST_READ_UINT32_BE(a) >> 8)
+#define QT_UINT16(a)  (GST_READ_UINT16_BE(a))
+#define QT_UINT8(a)   (GST_READ_UINT8(a))
+#define QT_FP32(a)    ((GST_READ_UINT32_BE(a))/65536.0)
+#define QT_FP16(a)    ((GST_READ_UINT16_BE(a))/256.0)
+#define QT_FOURCC(a)  (GST_READ_UINT32_LE(a))
+#define QT_UINT64(a)  ((((guint64)QT_UINT32(a))<<32)|QT_UINT32(((guint8 *)a)+4))
+
+#define FOURCC_avc1     GST_MAKE_FOURCC('a','v','c','1')
+#define FOURCC_avc3     GST_MAKE_FOURCC('a','v','c','3')
+#define FOURCC_avcC     GST_MAKE_FOURCC('a','v','c','C')
+
+GST_DEBUG_CATEGORY_STATIC (rtpxqtdepay_debug);
+#define GST_CAT_DEFAULT (rtpxqtdepay_debug)
+
+/* RtpXQTDepay signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+};
+
+static GstStaticPadTemplate gst_rtp_xqt_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate gst_rtp_xqt_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "media = (string) { \"audio\", \"video\" }, clock-rate = (int) [1, MAX], "
+        "encoding-name = (string) { \"X-QT\", \"X-QUICKTIME\" }")
+    );
+
+#define gst_rtp_xqt_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpXQTDepay, gst_rtp_xqt_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_xqt_depay_finalize (GObject * object);
+
+static gboolean gst_rtp_xqt_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_xqt_depay_process (GstRTPBaseDepayload * depayload,
+    GstBuffer * buf);
+
+static GstStateChangeReturn gst_rtp_xqt_depay_change_state (GstElement *
+    element, GstStateChange transition);
+
+
+static void
+gst_rtp_xqt_depay_class_init (GstRtpXQTDepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gst_rtp_xqt_depay_finalize;
+
+  gstelement_class->change_state = gst_rtp_xqt_depay_change_state;
+
+  gstrtpbasedepayload_class->set_caps = gst_rtp_xqt_depay_setcaps;
+  gstrtpbasedepayload_class->process = gst_rtp_xqt_depay_process;
+
+  GST_DEBUG_CATEGORY_INIT (rtpxqtdepay_debug, "rtpxqtdepay", 0,
+      "QT Media RTP Depayloader");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_xqt_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_xqt_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP packet depayloader", "Codec/Depayloader/Network",
+      "Extracts Quicktime audio/video from RTP packets",
+      "Wim Taymans <wim@fluendo.com>");
+}
+
+static void
+gst_rtp_xqt_depay_init (GstRtpXQTDepay * rtpxqtdepay)
+{
+  rtpxqtdepay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_xqt_depay_finalize (GObject * object)
+{
+  GstRtpXQTDepay *rtpxqtdepay;
+
+  rtpxqtdepay = GST_RTP_XQT_DEPAY (object);
+
+  g_object_unref (rtpxqtdepay->adapter);
+  rtpxqtdepay->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_quicktime_parse_sd (GstRtpXQTDepay * rtpxqtdepay, guint8 * data,
+    guint data_len)
+{
+  gint len;
+  guint32 fourcc;
+
+  if (data_len < 8)
+    goto too_short;
+
+  len = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
+  if (len > data_len)
+    goto too_short;
+
+  fourcc = QT_FOURCC (data + 4);
+
+  GST_DEBUG_OBJECT (rtpxqtdepay, "parsing %" GST_FOURCC_FORMAT,
+      GST_FOURCC_ARGS (fourcc));
+
+  switch (fourcc) {
+    case FOURCC_avc1:
+    case FOURCC_avc3:
+    {
+      guint32 chlen;
+
+      if (len < 0x56)
+        goto too_short;
+      len -= 0x56;
+      data += 0x56;
+
+      /* find avcC */
+      while (len >= 8) {
+        chlen = QT_UINT32 (data);
+        fourcc = QT_FOURCC (data + 4);
+        if (fourcc == FOURCC_avcC) {
+          GstBuffer *buf;
+          gint size;
+          GstCaps *caps;
+
+          GST_DEBUG_OBJECT (rtpxqtdepay, "found avcC codec_data in sd, %u",
+              chlen);
+
+          /* parse, if found */
+          if (chlen < len)
+            size = chlen - 8;
+          else
+            size = len - 8;
+
+          buf = gst_buffer_new_and_alloc (size);
+          gst_buffer_fill (buf, 0, data + 8, size);
+          caps = gst_caps_new_simple ("video/x-h264",
+              "codec_data", GST_TYPE_BUFFER, buf, NULL);
+          gst_buffer_unref (buf);
+          gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD (rtpxqtdepay)->srcpad, caps);
+          gst_caps_unref (caps);
+          break;
+        }
+        len -= chlen;
+        data += chlen;
+      }
+      break;
+    }
+    default:
+      break;
+  }
+  return TRUE;
+
+  /* ERRORS */
+too_short:
+  {
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_rtp_xqt_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  gint clock_rate = 90000;      /* default */
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  gst_structure_get_int (structure, "clock-rate", &clock_rate);
+  depayload->clock_rate = clock_rate;
+
+  return TRUE;
+}
+
+static GstBuffer *
+gst_rtp_xqt_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+  GstRtpXQTDepay *rtpxqtdepay;
+  GstBuffer *outbuf = NULL;
+  gboolean m;
+  GstRTPBuffer rtp = { NULL };
+
+  rtpxqtdepay = GST_RTP_XQT_DEPAY (depayload);
+
+  gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+  if (GST_BUFFER_IS_DISCONT (buf)) {
+    /* discont, clear adapter and try to find a new packet start */
+    gst_adapter_clear (rtpxqtdepay->adapter);
+    rtpxqtdepay->need_resync = TRUE;
+    GST_DEBUG_OBJECT (rtpxqtdepay, "we need resync");
+  }
+
+  m = gst_rtp_buffer_get_marker (&rtp);
+  GST_LOG_OBJECT (rtpxqtdepay, "marker: %d", m);
+
+  {
+    gint payload_len;
+    guint avail;
+    guint8 *payload;
+    guint8 ver, pck;
+    gboolean s, q, l, d;
+
+    payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+    payload = gst_rtp_buffer_get_payload (&rtp);
+
+    /*                      1                   2                   3 
+     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * | VER   |PCK|S|Q|L| RES         |D| QuickTime Payload ID        |
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     */
+    if (payload_len <= 4)
+      goto wrong_length;
+
+    ver = (payload[0] & 0xf0) >> 4;
+    if (ver > 1)
+      goto wrong_version;
+
+    pck = (payload[0] & 0x0c) >> 2;
+    if (pck == 0)
+      goto pck_reserved;
+
+    s = (payload[0] & 0x02) != 0;       /* contains sync sample */
+    q = (payload[0] & 0x01) != 0;       /* has payload description */
+    l = (payload[1] & 0x80) != 0;       /* has packet specific information description */
+    d = (payload[2] & 0x80) != 0;       /* don't cache info for payload id */
+    /* id used for caching info */
+    rtpxqtdepay->current_id = ((payload[2] & 0x7f) << 8) | payload[3];
+
+    GST_LOG_OBJECT (rtpxqtdepay,
+        "VER: %d, PCK: %d, S: %d, Q: %d, L: %d, D: %d, ID: %d", ver, pck, s, q,
+        l, d, rtpxqtdepay->current_id);
+
+    if (rtpxqtdepay->need_resync) {
+      /* we need to find the boundary of a new packet after a DISCONT */
+      if (pck != 3 || q) {
+        /* non-fragmented packet or payload description present, packet starts
+         * here. */
+        rtpxqtdepay->need_resync = FALSE;
+      } else {
+        /* fragmented packet without description */
+        if (m) {
+          /* marker bit set, next packet is start of new one */
+          rtpxqtdepay->need_resync = FALSE;
+        }
+        goto need_resync;
+      }
+    }
+
+    payload += 4;
+    payload_len -= 4;
+
+    if (q) {
+      gboolean k, f, a, z;
+      guint pdlen, pdpadded;
+      gint padding;
+      /* media_type only used for printing */
+      guint32 G_GNUC_UNUSED media_type;
+      guint32 timescale;
+
+      /*                      1                   2                   3
+       *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       * |K|F|A|Z| RES                   | QuickTime Payload Desc Length |
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       * . QuickTime Payload Desc Data ... . 
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       */
+      if (payload_len <= 4)
+        goto wrong_length;
+
+      k = (payload[0] & 0x80) != 0;     /* keyframe */
+      f = (payload[0] & 0x40) != 0;     /* sparse */
+      a = (payload[0] & 0x20) != 0;     /* start of payload */
+      z = (payload[0] & 0x10) != 0;     /* end of payload */
+      pdlen = (payload[2] << 8) | payload[3];
+
+      if (pdlen < 12)
+        goto wrong_length;
+
+      /* calc padding */
+      pdpadded = pdlen + 3;
+      pdpadded -= pdpadded % 4;
+      if (payload_len < pdpadded)
+        goto wrong_length;
+
+      padding = pdpadded - pdlen;
+      GST_LOG_OBJECT (rtpxqtdepay,
+          "K: %d, F: %d, A: %d, Z: %d, len: %d, padding %d", k, f, a, z, pdlen,
+          padding);
+
+      payload += 4;
+      payload_len -= 4;
+      /*                      1                   2                   3
+       *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       * | QuickTime Media Type                                          |
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       * | Timescale                                                     |
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       * . QuickTime TLVs ... .
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       */
+      media_type =
+          (payload[0] << 24) | (payload[1] << 16) | (payload[2] << 8) |
+          payload[3];
+      timescale =
+          (payload[4] << 24) | (payload[5] << 16) | (payload[6] << 8) |
+          payload[7];
+
+      GST_LOG_OBJECT (rtpxqtdepay, "media_type: %c%c%c%c, timescale %u",
+          payload[0], payload[1], payload[2], payload[3], timescale);
+
+      payload += 8;
+      payload_len -= 8;
+      pdlen -= 12;
+
+      /* parse TLV (type-length-value triplets */
+      while (pdlen > 3) {
+        guint16 tlv_len, tlv_type;
+
+        /*                      1                   2                   3
+         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         * | QuickTime TLV Length          | QuickTime TLV Type            |
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         * . QuickTime TLV Value ... .
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         */
+        tlv_len = (payload[0] << 8) | payload[1];
+        tlv_type = (payload[2] << 8) | payload[3];
+        pdlen -= 4;
+        if (tlv_len > pdlen)
+          goto wrong_length;
+
+        GST_LOG_OBJECT (rtpxqtdepay, "TLV '%c%c', len %d", payload[2],
+            payload[3], tlv_len);
+
+        payload += 4;
+        payload_len -= 4;
+
+        switch (tlv_type) {
+          case TLV_sd:
+            /* Session description */
+            if (!gst_rtp_quicktime_parse_sd (rtpxqtdepay, payload, tlv_len))
+              goto unknown_format;
+            rtpxqtdepay->have_sd = TRUE;
+            break;
+          case TLV_qt:
+          case TLV_ti:
+          case TLV_ly:
+          case TLV_vo:
+          case TLV_mx:
+          case TLV_tr:
+          case TLV_tw:
+          case TLV_th:
+          case TLV_la:
+          case TLV_rt:
+          case TLV_gm:
+          case TLV_oc:
+          case TLV_cr:
+          case TLV_du:
+          case TLV_po:
+          default:
+            break;
+        }
+
+        pdlen -= tlv_len;
+        payload += tlv_len;
+        payload_len -= tlv_len;
+      }
+      payload += padding;
+      payload_len -= padding;
+    }
+
+    if (l) {
+      guint ssilen, ssipadded;
+      gint padding;
+
+      /*                      1                   2                   3
+       *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       * | RES                           | Sample-Specific Info Length   |
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       * . QuickTime TLVs ... 
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       */
+      if (payload_len <= 4)
+        goto wrong_length;
+
+      ssilen = (payload[2] << 8) | payload[3];
+      if (ssilen < 4)
+        goto wrong_length;
+
+      /* calc padding */
+      ssipadded = ssilen + 3;
+      ssipadded -= ssipadded % 4;
+      if (payload_len < ssipadded)
+        goto wrong_length;
+
+      padding = ssipadded - ssilen;
+      GST_LOG_OBJECT (rtpxqtdepay, "len: %d, padding %d", ssilen, padding);
+
+      payload += 4;
+      payload_len -= 4;
+      ssilen -= 4;
+
+      /* parse TLV (type-length-value triplets */
+      while (ssilen > 3) {
+        guint16 tlv_len, tlv_type;
+
+        /*                      1                   2                   3
+         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         * | QuickTime TLV Length          | QuickTime TLV Type            |
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         * . QuickTime TLV Value ... .
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         */
+        tlv_len = (payload[0] << 8) | payload[1];
+        tlv_type = (payload[2] << 8) | payload[3];
+        ssilen -= 4;
+        if (tlv_len > ssilen)
+          goto wrong_length;
+
+        GST_LOG_OBJECT (rtpxqtdepay, "TLV '%c%c', len %d", payload[2],
+            payload[3], tlv_len);
+
+        payload += 4;
+        payload_len -= 4;
+
+        switch (tlv_type) {
+          case TLV_sd:
+          case TLV_qt:
+          case TLV_ti:
+          case TLV_ly:
+          case TLV_vo:
+          case TLV_mx:
+          case TLV_tr:
+          case TLV_tw:
+          case TLV_th:
+          case TLV_la:
+          case TLV_rt:
+          case TLV_gm:
+          case TLV_oc:
+          case TLV_cr:
+          case TLV_du:
+          case TLV_po:
+          default:
+            break;
+        }
+
+        ssilen -= tlv_len;
+        payload += tlv_len;
+        payload_len -= tlv_len;
+      }
+      payload += padding;
+      payload_len -= padding;
+    }
+
+    rtpxqtdepay->previous_id = rtpxqtdepay->current_id;
+
+    switch (pck) {
+      case 1:
+      {
+        /* multiple samples per packet. */
+        outbuf = gst_buffer_new_and_alloc (payload_len);
+        gst_buffer_fill (outbuf, 0, payload, payload_len);
+
+        goto done;
+      }
+      case 2:
+      {
+        guint slen;
+
+        /* multiple samples per packet. 
+         *                      1                   2                   3
+         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         * |S| Reserved                    | Sample Length                 |
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         * | Sample Timestamp                                              |
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         * . Sample Data ...                                               .
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         * |S| Reserved                    | Sample Length                 |
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         * | Sample Timestamp                                              |
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         * . Sample Data ...                                               .
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         * . ......                                                        .
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         */
+        while (payload_len > 8) {
+          s = (payload[0] & 0x80) != 0; /* contains sync sample */
+          slen = (payload[2] << 8) | payload[3];
+          /* timestamp =
+           *    (payload[4] << 24) | (payload[5] << 16) | (payload[6] << 8) |
+           *    payload[7];
+           */
+
+          payload += 8;
+          payload_len -= 8;
+
+          if (slen > payload_len)
+            slen = payload_len;
+
+          outbuf = gst_buffer_new_and_alloc (slen);
+          gst_buffer_fill (outbuf, 0, payload, slen);
+          if (!s)
+            GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+          gst_rtp_base_depayload_push (depayload, outbuf);
+
+          /* aligned on 32 bit boundary */
+          slen = GST_ROUND_UP_4 (slen);
+
+          payload += slen;
+          payload_len -= slen;
+        }
+        break;
+      }
+      case 3:
+      {
+        /* one sample per packet, use adapter to combine based on marker bit. */
+        outbuf = gst_buffer_new_and_alloc (payload_len);
+        gst_buffer_fill (outbuf, 0, payload, payload_len);
+
+        gst_adapter_push (rtpxqtdepay->adapter, outbuf);
+        outbuf = NULL;
+
+        if (!m)
+          goto done;
+
+        avail = gst_adapter_available (rtpxqtdepay->adapter);
+        outbuf = gst_adapter_take_buffer (rtpxqtdepay->adapter, avail);
+
+        GST_DEBUG_OBJECT (rtpxqtdepay,
+            "gst_rtp_xqt_depay_chain: pushing buffer of size %u", avail);
+
+        goto done;
+      }
+    }
+  }
+
+done:
+  gst_rtp_buffer_unmap (&rtp);
+  return outbuf;
+
+need_resync:
+  {
+    GST_DEBUG_OBJECT (rtpxqtdepay, "waiting for marker");
+    goto done;
+  }
+wrong_version:
+  {
+    GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE,
+        ("Unknown payload version."), (NULL));
+    goto done;
+  }
+pck_reserved:
+  {
+    GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE,
+        ("PCK reserved 0."), (NULL));
+    goto done;
+  }
+wrong_length:
+  {
+    GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE,
+        ("Wrong payload length."), (NULL));
+    goto done;
+  }
+unknown_format:
+  {
+    GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE,
+        ("Unknown payload format."), (NULL));
+    goto done;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_xqt_depay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRtpXQTDepay *rtpxqtdepay;
+  GstStateChangeReturn ret;
+
+  rtpxqtdepay = GST_RTP_XQT_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_adapter_clear (rtpxqtdepay->adapter);
+      rtpxqtdepay->previous_id = -1;
+      rtpxqtdepay->current_id = -1;
+      rtpxqtdepay->need_resync = TRUE;
+      rtpxqtdepay->have_sd = FALSE;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_adapter_clear (rtpxqtdepay->adapter);
+    default:
+      break;
+  }
+  return ret;
+}
diff --git a/gst/isomp4/gstrtpxqtdepay.h b/gst/isomp4/gstrtpxqtdepay.h
new file mode 100644
index 0000000..ca4e41a
--- /dev/null
+++ b/gst/isomp4/gstrtpxqtdepay.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_XQT_DEPAY_H__
+#define __GST_RTP_XQT_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_XQT_DEPAY \
+  (gst_rtp_xqt_depay_get_type())
+#define GST_RTP_XQT_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_XQT_DEPAY,GstRtpXQTDepay))
+#define GST_RTP_XQT_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_XQT_DEPAY,GstRtpXQTDepayClass))
+#define GST_IS_RTP_XQT_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_XQT_DEPAY))
+#define GST_IS_RTP_XQT_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_XQT_DEPAY))
+
+typedef struct _GstRtpXQTDepay GstRtpXQTDepay;
+typedef struct _GstRtpXQTDepayClass GstRtpXQTDepayClass;
+
+struct _GstRtpXQTDepay
+{
+  GstRTPBaseDepayload depayload;
+
+  GstAdapter *adapter;
+
+  gboolean need_resync;
+  guint16 previous_id;
+  guint16 current_id;
+  gboolean have_sd;
+};
+
+struct _GstRtpXQTDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_xqt_depay_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_XQT_DEPAY_H__ */
diff --git a/gst/isomp4/isomp4-plugin.c b/gst/isomp4/isomp4-plugin.c
new file mode 100644
index 0000000..7ff78ce
--- /dev/null
+++ b/gst/isomp4/isomp4-plugin.c
@@ -0,0 +1,73 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
+ * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "gst/gst-i18n-plugin.h"
+
+#include "qtdemux.h"
+#include "gstrtpxqtdepay.h"
+#include "gstqtmux.h"
+#include "gstqtmoovrecover.h"
+
+#include <gst/pbutils/pbutils.h>
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+#ifdef ENABLE_NLS
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif /* ENABLE_NLS */
+
+  gst_pb_utils_init ();
+
+  /* ensure private tag is registered */
+  gst_tag_register (GST_QT_DEMUX_PRIVATE_TAG, GST_TAG_FLAG_META,
+      GST_TYPE_SAMPLE, "QT atom", "unparsed QT tag atom",
+      gst_tag_merge_use_first);
+
+  gst_tag_register (GST_QT_DEMUX_CLASSIFICATION_TAG, GST_TAG_FLAG_META,
+      G_TYPE_STRING, GST_QT_DEMUX_CLASSIFICATION_TAG, "content classification",
+      gst_tag_merge_use_first);
+
+  if (!gst_element_register (plugin, "qtdemux",
+          GST_RANK_PRIMARY, GST_TYPE_QTDEMUX))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "rtpxqtdepay",
+          GST_RANK_MARGINAL, GST_TYPE_RTP_XQT_DEPAY))
+    return FALSE;
+
+  if (!gst_qt_mux_register (plugin))
+    return FALSE;
+  if (!gst_qt_moov_recover_register (plugin))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    isomp4,
+    "ISO base media file format support (mp4, 3gpp, qt, mj2)",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/isomp4/meson.build b/gst/isomp4/meson.build
new file mode 100644
index 0000000..bda2d64
--- /dev/null
+++ b/gst/isomp4/meson.build
@@ -0,0 +1,29 @@
+mp4_sources = [
+  'isomp4-plugin.c',
+  'gstrtpxqtdepay.c',
+  'qtdemux.c',
+  'qtdemux_types.c',
+  'qtdemux_dump.c',
+  'qtdemux_lang.c',
+  'gstisoff.c',
+  'gstqtmux.c',
+  'gstqtmoovrecover.c',
+  'atoms.c',
+  'atomsrecovery.c',
+  'descriptors.c',
+  'properties.c',
+  'gstqtmuxmap.c'
+]
+
+gstisomp4 = library('gstisomp4',
+  mp4_sources,
+  c_args : gst_plugins_good_args,
+  link_args : noseh_link_args,
+  include_directories : [configinc, libsinc],
+  dependencies : [gst_dep, gstriff_dep, gstaudio_dep, gstvideo_dep,
+                  gstrtp_dep, gsttag_dep, gstpbutils_dep, zlib_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
+
+install_data(sources: 'GstQTMux.prs', install_dir: presetdir)
diff --git a/gst/isomp4/properties.c b/gst/isomp4/properties.c
new file mode 100644
index 0000000..cb43e29
--- /dev/null
+++ b/gst/isomp4/properties.c
@@ -0,0 +1,210 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "properties.h"
+
+/* if needed, re-allocate buffer to ensure size bytes can be written into it
+ * at offset */
+void
+prop_copy_ensure_buffer (guint8 ** buffer, guint64 * bsize, guint64 * offset,
+    guint64 size)
+{
+  if (buffer && *bsize - *offset < size) {
+    *bsize += size + 10 * 1024;
+    *buffer = g_realloc (*buffer, *bsize);
+  }
+}
+
+static guint64
+copy_func (void *prop, guint size, guint8 ** buffer, guint64 * bsize,
+    guint64 * offset)
+{
+  if (buffer) {
+    prop_copy_ensure_buffer (buffer, bsize, offset, size);
+    memcpy (*buffer + *offset, prop, size);
+  }
+  *offset += size;
+  return size;
+}
+
+#define INT_ARRAY_COPY_FUNC_FAST(name, datatype) 			\
+guint64 prop_copy_ ## name ## _array (datatype *prop, guint size,	\
+    guint8 ** buffer, guint64 * bsize, guint64 * offset) { 		\
+  return copy_func (prop, sizeof (datatype) * size, buffer, bsize, offset);\
+}
+
+#define INT_ARRAY_COPY_FUNC(name, datatype) 				\
+guint64 prop_copy_ ## name ## _array (datatype *prop, guint size,	\
+    guint8 ** buffer, guint64 * bsize, guint64 * offset) { 		\
+  guint i;								\
+									\
+  for (i = 0; i < size; i++) {						\
+    prop_copy_ ## name (prop[i], buffer, bsize, offset);		\
+  }									\
+  return sizeof (datatype) * size;					\
+}
+
+/* INTEGERS */
+guint64
+prop_copy_uint8 (guint8 prop, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  return copy_func (&prop, sizeof (guint8), buffer, size, offset);
+}
+
+guint64
+prop_copy_uint16 (guint16 prop, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  prop = GUINT16_TO_BE (prop);
+  return copy_func (&prop, sizeof (guint16), buffer, size, offset);
+}
+
+guint64
+prop_copy_uint32 (guint32 prop, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  prop = GUINT32_TO_BE (prop);
+  return copy_func (&prop, sizeof (guint32), buffer, size, offset);
+}
+
+guint64
+prop_copy_uint64 (guint64 prop, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  prop = GUINT64_TO_BE (prop);
+  return copy_func (&prop, sizeof (guint64), buffer, size, offset);
+}
+
+guint64
+prop_copy_int32 (gint32 prop, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  prop = GINT32_TO_BE (prop);
+  return copy_func (&prop, sizeof (guint32), buffer, size, offset);
+}
+
+/* uint8 can use direct copy in any case, and may be used for large quantity */
+INT_ARRAY_COPY_FUNC_FAST (uint8, guint8);
+/* not used in large quantity anyway */
+INT_ARRAY_COPY_FUNC (uint16, guint16);
+INT_ARRAY_COPY_FUNC (uint32, guint32);
+INT_ARRAY_COPY_FUNC (uint64, guint64);
+
+/* FOURCC */
+guint64
+prop_copy_fourcc (guint32 prop, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  prop = GINT32_TO_LE (prop);
+  return copy_func (&prop, sizeof (guint32), buffer, size, offset);
+}
+
+INT_ARRAY_COPY_FUNC (fourcc, guint32);
+
+/**
+ * prop_copy_fixed_size_string:
+ * @string: the string to be copied
+ * @str_size: size of the string
+ * @buffer: the array to copy the string to
+ * @offset: the position in the buffer array.
+ * This value is updated to the point right after the copied string.
+ *
+ * Copies a string of bytes without placing its size at the beginning.
+ *
+ * Returns: the number of bytes copied
+ */
+guint64
+prop_copy_fixed_size_string (guint8 * string, guint str_size, guint8 ** buffer,
+    guint64 * size, guint64 * offset)
+{
+  return copy_func (string, str_size * sizeof (guint8), buffer, size, offset);
+}
+
+/**
+ * prop_copy_size_string:
+ *
+ * @string: the string to be copied
+ * @str_size: size of the string
+ * @buffer: the array to copy the string to
+ * @offset: the position in the buffer array.
+ * This value is updated to the point right after the copied string.
+ *
+ * Copies a string and its size to an array. Example:
+ * string = 'abc\0'
+ * result in the array: [3][a][b][c]  (each [x] represents a position)
+ *
+ * Returns: the number of bytes copied
+ */
+guint64
+prop_copy_size_string (guint8 * string, guint str_size, guint8 ** buffer,
+    guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  prop_copy_uint8 (str_size, buffer, size, offset);
+  prop_copy_fixed_size_string (string, str_size, buffer, size, offset);
+  return *offset - original_offset;
+}
+
+/**
+ * prop_copy_null_terminated_string:
+ * @string: the string to be copied
+ * @buffer: the array to copy the string to
+ * @offset: the position in the buffer array.
+ * This value is updated to the point right after the copied string.
+ *
+ * Copies a string including its null terminating char to an array.
+ *
+ * Returns: the number of bytes copied
+ */
+guint64
+prop_copy_null_terminated_string (gchar * string, guint8 ** buffer,
+    guint64 * size, guint64 * offset)
+{
+  guint64 original_offset = *offset;
+  guint len = strlen (string);
+
+  prop_copy_fixed_size_string ((guint8 *) string, len, buffer, size, offset);
+  prop_copy_uint8 ('\0', buffer, size, offset);
+  return *offset - original_offset;
+}
diff --git a/gst/isomp4/properties.h b/gst/isomp4/properties.h
new file mode 100644
index 0000000..c36fe48
--- /dev/null
+++ b/gst/isomp4/properties.h
@@ -0,0 +1,87 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __PROPERTIES_H__
+#define __PROPERTIES_H__
+
+#include <glib.h>
+#include <string.h>
+
+/*
+ * Functions for copying atoms properties.
+ *
+ * All of them receive, as the input, the property to be copied, the destination
+ * buffer, and a pointer to an offset in the destination buffer to copy to the right place.
+ * This offset will be updated to the new value (offset + copied_size)
+ * The functions return the size of the property that has been copied or 0
+ * if it couldn't copy.
+ */
+
+void    prop_copy_ensure_buffer          (guint8 ** buffer, guint64 * bsize, guint64 * offset, guint64 size);
+
+guint64 prop_copy_uint8                  (guint8 prop, guint8 **buffer, guint64 *size, guint64 *offset);
+guint64 prop_copy_uint16                 (guint16 prop, guint8 **buffer, guint64 *size, guint64 *offset);
+guint64 prop_copy_uint32                 (guint32 prop, guint8 **buffer, guint64 *size, guint64 *offset);
+guint64 prop_copy_uint64                 (guint64 prop, guint8 **buffer, guint64 *size, guint64 *offset);
+
+guint64 prop_copy_int32                  (gint32 prop, guint8 **buffer, guint64 *size, guint64 *offset);
+
+guint64 prop_copy_uint8_array            (guint8 *prop, guint size,
+                                          guint8 **buffer, guint64 *bsize, guint64 *offset);
+guint64 prop_copy_uint16_array           (guint16 *prop, guint size,
+                                          guint8 **buffer, guint64 *bsize, guint64 *offset);
+guint64 prop_copy_uint32_array           (guint32 *prop, guint size,
+                                          guint8 **buffer, guint64 *bsize, guint64 *offset);
+guint64 prop_copy_uint64_array           (guint64 *prop, guint size,
+                                          guint8 **buffer, guint64 *bsize, guint64 *offset);
+
+guint64 prop_copy_fourcc                 (guint32 prop, guint8 **buffer, guint64 *size, guint64 *offset);
+guint64 prop_copy_fourcc_array           (guint32 *prop, guint size,
+                                          guint8 **buffer, guint64 *bsize, guint64 *offset);
+guint64 prop_copy_fixed_size_string      (guint8 *string, guint str_size,
+                                          guint8 **buffer, guint64 *size, guint64 *offset);
+guint64 prop_copy_size_string            (guint8 *string, guint str_size,
+                                          guint8 **buffer, guint64 *size, guint64 *offset);
+guint64 prop_copy_null_terminated_string (gchar *string,
+                                          guint8 **buffer, guint64 *size, guint64 *offset);
+
+#endif /* __PROPERTIES_H__ */
diff --git a/gst/isomp4/qtatomparser.h b/gst/isomp4/qtatomparser.h
new file mode 100644
index 0000000..89bab50
--- /dev/null
+++ b/gst/isomp4/qtatomparser.h
@@ -0,0 +1,139 @@
+/* GStreamer QuickTime atom parser
+ * Copyright (C) 2009 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef QT_ATOM_PARSER_H
+#define QT_ATOM_PARSER_H
+
+#include <gst/base/gstbytereader.h>
+
+/* our inlined version of GstByteReader */
+
+static inline gboolean
+qt_atom_parser_has_remaining (GstByteReader * parser, guint64 bytes_needed)
+{
+  return G_LIKELY (parser->size >= bytes_needed) &&
+      G_LIKELY ((parser->size - bytes_needed) >= parser->byte);
+}
+
+static inline gboolean
+qt_atom_parser_has_chunks (GstByteReader * parser, guint32 n_chunks,
+    guint32 chunk_size)
+{
+  /* assumption: n_chunks and chunk_size are 32-bit, we cast to 64-bit here
+   * to avoid overflows, to handle e.g. (guint32)-1 * size correctly */
+  return qt_atom_parser_has_remaining (parser, (guint64) n_chunks * chunk_size);
+}
+
+static inline gboolean
+qt_atom_parser_peek_sub (GstByteReader * parser, guint offset, guint size,
+    GstByteReader * sub)
+{
+  *sub = *parser;
+
+  if (G_UNLIKELY (!gst_byte_reader_skip (sub, offset)))
+    return FALSE;
+
+  return (gst_byte_reader_get_remaining (sub) >= size);
+}
+
+static inline gboolean
+qt_atom_parser_skipn_and_get_uint32 (GstByteReader * parser,
+    guint bytes_to_skip, guint32 * val)
+{
+  if (G_UNLIKELY (gst_byte_reader_get_remaining (parser) < (bytes_to_skip + 4)))
+    return FALSE;
+
+  gst_byte_reader_skip_unchecked (parser, bytes_to_skip);
+  *val = gst_byte_reader_get_uint32_be_unchecked (parser);
+  return TRUE;
+}
+
+/* off_size must be either 4 or 8 */
+static inline gboolean
+qt_atom_parser_get_offset (GstByteReader * parser, guint off_size,
+    guint64 * val)
+{
+  if (G_UNLIKELY (gst_byte_reader_get_remaining (parser) < off_size))
+    return FALSE;
+
+  if (off_size == sizeof (guint64)) {
+    *val = gst_byte_reader_get_uint64_be_unchecked (parser);
+  } else {
+    *val = gst_byte_reader_get_uint32_be_unchecked (parser);
+  }
+  return TRUE;
+}
+
+/* off_size must be either 4 or 8 */
+static inline guint64
+qt_atom_parser_get_offset_unchecked (GstByteReader * parser, guint off_size)
+{
+  if (off_size == sizeof (guint64)) {
+    return gst_byte_reader_get_uint64_be_unchecked (parser);
+  } else {
+    return gst_byte_reader_get_uint32_be_unchecked (parser);
+  }
+}
+
+/* size must be from 1 to 4 */
+static inline guint32
+qt_atom_parser_get_uint_with_size_unchecked (GstByteReader * parser,
+    guint size)
+{
+  switch (size) {
+  case 1:
+    return gst_byte_reader_get_uint8_unchecked (parser);
+  case 2:
+    return gst_byte_reader_get_uint16_be_unchecked (parser);
+  case 3:
+    return gst_byte_reader_get_uint24_be_unchecked (parser);
+  case 4:
+    return gst_byte_reader_get_uint32_be_unchecked (parser);
+  default:
+    g_assert_not_reached ();
+    gst_byte_reader_skip_unchecked (parser, size);
+    break;
+  }
+  return 0;
+}
+
+static inline gboolean
+qt_atom_parser_get_fourcc (GstByteReader * parser, guint32 * fourcc)
+{
+  guint32 f_be;
+
+  if (G_UNLIKELY (gst_byte_reader_get_remaining (parser) < 4))
+    return FALSE;
+
+  f_be = gst_byte_reader_get_uint32_be_unchecked (parser);
+  *fourcc = GUINT32_SWAP_LE_BE (f_be);
+  return TRUE;
+}
+
+static inline guint32
+qt_atom_parser_get_fourcc_unchecked (GstByteReader * parser)
+{
+  guint32 fourcc;
+
+  fourcc = gst_byte_reader_get_uint32_be_unchecked (parser);
+  return GUINT32_SWAP_LE_BE (fourcc);
+}
+
+#endif /* QT_ATOM_PARSER_H */
diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c
new file mode 100644
index 0000000..a6f870f
--- /dev/null
+++ b/gst/isomp4/qtdemux.c
@@ -0,0 +1,14475 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
+ * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
+ * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
+ * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
+ * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ * Copyright (C) <2013> Intel Corporation
+ * Copyright (C) <2014> Centricular Ltd
+ * Copyright (C) <2015> YouView TV Ltd.
+ * Copyright (C) <2016> British Broadcasting Corporation
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-qtdemux
+ *
+ * Demuxes a .mov file into raw or compressed audio and/or video streams.
+ *
+ * This element supports both push and pull-based scheduling, depending on the
+ * capabilities of the upstream elements.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux  demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink   demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
+ * ]| Play (parse and decode) a .mov file and try to output it to
+ * an automatically detected soundcard and videosink. If the MOV file contains
+ * compressed audio or video data, this will only work if you have the
+ * right decoder elements/plugins installed.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gst/gst-i18n-plugin.h"
+
+#include <glib/gprintf.h>
+#include <gst/tag/tag.h>
+#include <gst/audio/audio.h>
+#include <gst/video/video.h>
+
+#include "qtatomparser.h"
+#include "qtdemux_types.h"
+#include "qtdemux_dump.h"
+#include "fourcc.h"
+#include "descriptors.h"
+#include "qtdemux_lang.h"
+#include "qtdemux.h"
+#include "qtpalette.h"
+
+#include "gst/riff/riff-media.h"
+#include "gst/riff/riff-read.h"
+
+#include <gst/pbutils/pbutils.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <math.h>
+#include <gst/math-compat.h>
+
+#ifdef HAVE_ZLIB
+# include <zlib.h>
+#endif
+
+/* max. size considered 'sane' for non-mdat atoms */
+#define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
+
+/* if the sample index is larger than this, something is likely wrong */
+#define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
+
+/* For converting qt creation times to unix epoch times */
+#define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
+#define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
+#define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
+    QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
+
+#define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
+
+#define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
+
+#define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
+
+GST_DEBUG_CATEGORY (qtdemux_debug);
+#define GST_CAT_DEFAULT qtdemux_debug
+
+typedef struct _QtDemuxSegment QtDemuxSegment;
+typedef struct _QtDemuxSample QtDemuxSample;
+
+typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
+
+struct _QtDemuxSample
+{
+  guint32 size;
+  gint32 pts_offset;            /* Add this value to timestamp to get the pts */
+  guint64 offset;
+  guint64 timestamp;            /* DTS In mov time */
+  guint32 duration;             /* In mov time */
+  gboolean keyframe;            /* TRUE when this packet is a keyframe */
+};
+
+/* Macros for converting to/from timescale */
+#define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
+#define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
+
+#define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
+#define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
+
+/* timestamp is the DTS */
+#define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
+/* timestamp + offset + cslg_shift is the outgoing PTS */
+#define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
+/* timestamp + offset is the PTS used for internal seek calcuations */
+#define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
+/* timestamp + duration - dts is the duration */
+#define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
+
+#define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
+
+/*
+ * Quicktime has tracks and segments. A track is a continuous piece of
+ * multimedia content. The track is not always played from start to finish but
+ * instead, pieces of the track are 'cut out' and played in sequence. This is
+ * what the segments do.
+ *
+ * Inside the track we have keyframes (K) and delta frames. The track has its
+ * own timing, which starts from 0 and extends to end. The position in the track
+ * is called the media_time.
+ *
+ * The segments now describe the pieces that should be played from this track
+ * and are basically tuples of media_time/duration/rate entries. We can have
+ * multiple segments and they are all played after one another. An example:
+ *
+ * segment 1: media_time: 1 second, duration: 1 second, rate 1
+ * segment 2: media_time: 3 second, duration: 2 second, rate 2
+ *
+ * To correctly play back this track, one must play: 1 second of media starting
+ * from media_time 1 followed by 2 seconds of media starting from media_time 3
+ * at a rate of 2.
+ *
+ * Each of the segments will be played at a specific time, the first segment at
+ * time 0, the second one after the duration of the first one, etc.. Note that
+ * the time in resulting playback is not identical to the media_time of the
+ * track anymore.
+ *
+ * Visually, assuming the track has 4 second of media_time:
+ *
+ *                (a)                   (b)          (c)              (d)
+ *         .-----------------------------------------------------------.
+ * track:  | K.....K.........K........K.......K.......K...........K... |
+ *         '-----------------------------------------------------------'
+ *         0              1              2              3              4
+ *           .------------^              ^   .----------^              ^
+ *          /              .-------------'  /       .------------------'
+ *         /              /          .-----'       /
+ *         .--------------.         .--------------.
+ *         | segment 1    |         | segment 2    |
+ *         '--------------'         '--------------'
+ *
+ * The challenge here is to cut out the right pieces of the track for each of
+ * the playback segments. This fortunately can easily be done with the SEGMENT
+ * events of GStreamer.
+ *
+ * For playback of segment 1, we need to provide the decoder with the keyframe
+ * (a), in the above figure, but we must instruct it only to output the decoded
+ * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
+ * position set to the time of the segment: 0.
+ *
+ * We then proceed to push data from keyframe (a) to frame (b). The decoder
+ * decodes but clips all before media_time 1.
+ *
+ * After finishing a segment, we push out a new SEGMENT event with the clipping
+ * boundaries of the new data.
+ *
+ * This is a good usecase for the GStreamer accumulated SEGMENT events.
+ */
+
+struct _QtDemuxSegment
+{
+  /* global time and duration, all gst time */
+  GstClockTime time;
+  GstClockTime stop_time;
+  GstClockTime duration;
+  /* media time of trak, all gst time */
+  GstClockTime media_start;
+  GstClockTime media_stop;
+  gdouble rate;
+  /* Media start time in trak timescale units */
+  guint32 trak_media_start;
+};
+
+#define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
+
+/* Used with fragmented MP4 files (mfra atom) */
+typedef struct
+{
+  GstClockTime ts;
+  guint64 moof_offset;
+} QtDemuxRandomAccessEntry;
+
+typedef struct _QtDemuxStreamStsdEntry
+{
+  GstCaps *caps;
+  guint32 fourcc;
+  gboolean sparse;
+
+  /* video info */
+  gint width;
+  gint height;
+  gint par_w;
+  gint par_h;
+  /* Numerator/denominator framerate */
+  gint fps_n;
+  gint fps_d;
+  GstVideoColorimetry colorimetry;
+  guint16 bits_per_sample;
+  guint16 color_table_id;
+  GstMemory *rgb8_palette;
+  guint interlace_mode;
+  guint field_order;
+
+  /* audio info */
+  gdouble rate;
+  gint n_channels;
+  guint samples_per_packet;
+  guint samples_per_frame;
+  guint bytes_per_packet;
+  guint bytes_per_sample;
+  guint bytes_per_frame;
+  guint compression;
+
+  /* if we use chunks or samples */
+  gboolean sampled;
+  guint padding;
+
+} QtDemuxStreamStsdEntry;
+
+#define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
+
+struct _QtDemuxStream
+{
+  GstPad *pad;
+
+  QtDemuxStreamStsdEntry *stsd_entries;
+  guint stsd_entries_length;
+  guint cur_stsd_entry_index;
+
+  /* stream type */
+  guint32 subtype;
+
+  gboolean new_caps;            /* If TRUE, caps need to be generated (by
+                                 * calling _configure_stream()) This happens
+                                 * for MSS and fragmented streams */
+
+  gboolean new_stream;          /* signals that a stream_start is required */
+  gboolean on_keyframe;         /* if this stream last pushed buffer was a
+                                 * keyframe. This is important to identify
+                                 * where to stop pushing buffers after a
+                                 * segment stop time */
+
+  /* if the stream has a redirect URI in its headers, we store it here */
+  gchar *redirect_uri;
+
+  /* track id */
+  guint track_id;
+
+  /* duration/scale */
+  guint64 duration;             /* in timescale units */
+  guint32 timescale;
+
+  /* language */
+  gchar lang_id[4];             /* ISO 639-2T language code */
+
+  /* our samples */
+  guint32 n_samples;
+  QtDemuxSample *samples;
+  gboolean all_keyframe;        /* TRUE when all samples are keyframes (no stss) */
+  guint32 first_duration;       /* duration in timescale of first sample, used for figuring out
+                                   the framerate */
+  guint32 n_samples_moof;       /* sample count in a moof */
+  guint64 duration_moof;        /* duration in timescale of a moof, used for figure out
+                                 * the framerate of fragmented format stream */
+  guint64 duration_last_moof;
+
+  guint32 offset_in_sample;     /* Offset in the current sample, used for
+                                 * streams which have got exceedingly big
+                                 * sample size (such as 24s of raw audio).
+                                 * Only used when max_buffer_size is non-NULL */
+  guint32 max_buffer_size;      /* Maximum allowed size for output buffers.
+                                 * Currently only set for raw audio streams*/
+
+  /* video info */
+  /* aspect ratio */
+  gint display_width;
+  gint display_height;
+
+  /* allocation */
+  gboolean use_allocator;
+  GstAllocator *allocator;
+  GstAllocationParams params;
+
+  gsize alignment;
+
+  /* when a discontinuity is pending */
+  gboolean discont;
+
+  /* list of buffers to push first */
+  GSList *buffers;
+
+  /* if we need to clip this buffer. This is only needed for uncompressed
+   * data */
+  gboolean need_clip;
+
+  /* buffer needs some custom processing, e.g. subtitles */
+  gboolean need_process;
+
+  /* current position */
+  guint32 segment_index;
+  guint32 sample_index;
+  GstClockTime time_position;   /* in gst time */
+  guint64 accumulated_base;
+
+  /* the Gst segment we are processing out, used for clipping */
+  GstSegment segment;
+
+  /* quicktime segments */
+  guint32 n_segments;
+  QtDemuxSegment *segments;
+  gboolean dummy_segment;
+  guint32 from_sample;
+  guint32 to_sample;
+
+  gboolean sent_eos;
+  GstTagList *stream_tags;
+  gboolean send_global_tags;
+
+  GstEvent *pending_event;
+
+  GstByteReader stco;
+  GstByteReader stsz;
+  GstByteReader stsc;
+  GstByteReader stts;
+  GstByteReader stss;
+  GstByteReader stps;
+  GstByteReader ctts;
+
+  gboolean chunks_are_samples;  /* TRUE means treat chunks as samples */
+  gint64 stbl_index;
+  /* stco */
+  guint co_size;
+  GstByteReader co_chunk;
+  guint32 first_chunk;
+  guint32 current_chunk;
+  guint32 last_chunk;
+  guint32 samples_per_chunk;
+  guint32 stsd_sample_description_id;
+  guint32 stco_sample_index;
+  /* stsz */
+  guint32 sample_size;          /* 0 means variable sizes are stored in stsz */
+  /* stsc */
+  guint32 stsc_index;
+  guint32 n_samples_per_chunk;
+  guint32 stsc_chunk_index;
+  guint32 stsc_sample_index;
+  guint64 chunk_offset;
+  /* stts */
+  guint32 stts_index;
+  guint32 stts_samples;
+  guint32 n_sample_times;
+  guint32 stts_sample_index;
+  guint64 stts_time;
+  guint32 stts_duration;
+  /* stss */
+  gboolean stss_present;
+  guint32 n_sample_syncs;
+  guint32 stss_index;
+  /* stps */
+  gboolean stps_present;
+  guint32 n_sample_partial_syncs;
+  guint32 stps_index;
+  QtDemuxRandomAccessEntry *ra_entries;
+  guint n_ra_entries;
+
+  const QtDemuxRandomAccessEntry *pending_seek;
+
+  /* ctts */
+  gboolean ctts_present;
+  guint32 n_composition_times;
+  guint32 ctts_index;
+  guint32 ctts_sample_index;
+  guint32 ctts_count;
+  gint32 ctts_soffset;
+
+  /* cslg */
+  guint32 cslg_shift;
+
+  /* fragmented */
+  gboolean parsed_trex;
+  guint32 def_sample_description_index; /* index is 1-based */
+  guint32 def_sample_duration;
+  guint32 def_sample_size;
+  guint32 def_sample_flags;
+
+  gboolean disabled;
+
+  /* stereoscopic video streams */
+  GstVideoMultiviewMode multiview_mode;
+  GstVideoMultiviewFlags multiview_flags;
+
+  /* protected streams */
+  gboolean protected;
+  guint32 protection_scheme_type;
+  guint32 protection_scheme_version;
+  gpointer protection_scheme_info;      /* specific to the protection scheme */
+  GQueue protection_scheme_event_queue;
+};
+
+/* Contains properties and cryptographic info for a set of samples from a
+ * track protected using Common Encryption (cenc) */
+struct _QtDemuxCencSampleSetInfo
+{
+  GstStructure *default_properties;
+
+  /* @crypto_info holds one GstStructure per sample */
+  GPtrArray *crypto_info;
+};
+
+static const gchar *
+qt_demux_state_string (enum QtDemuxState state)
+{
+  switch (state) {
+    case QTDEMUX_STATE_INITIAL:
+      return "<INITIAL>";
+    case QTDEMUX_STATE_HEADER:
+      return "<HEADER>";
+    case QTDEMUX_STATE_MOVIE:
+      return "<MOVIE>";
+    case QTDEMUX_STATE_BUFFER_MDAT:
+      return "<BUFFER_MDAT>";
+    default:
+      return "<UNKNOWN>";
+  }
+}
+
+static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
+static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
+    guint32 fourcc, GstByteReader * parser);
+static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
+static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
+    guint32 fourcc, GstByteReader * parser);
+
+static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
+
+static GstStaticPadTemplate gst_qtdemux_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
+        "application/x-3gp")
+    );
+
+static GstStaticPadTemplate gst_qtdemux_videosrc_template =
+GST_STATIC_PAD_TEMPLATE ("video_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
+GST_STATIC_PAD_TEMPLATE ("audio_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate gst_qtdemux_subsrc_template =
+GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS_ANY);
+
+#define gst_qtdemux_parent_class parent_class
+G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
+
+static void gst_qtdemux_dispose (GObject * object);
+
+static guint32
+gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
+    GstClockTime media_time);
+static guint32
+gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
+    QtDemuxStream * str, gint64 media_offset);
+
+#if 0
+static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
+static GstIndex *gst_qtdemux_get_index (GstElement * element);
+#endif
+static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
+    GstStateChange transition);
+static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
+static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
+    GstObject * parent, GstPadMode mode, gboolean active);
+
+static void gst_qtdemux_loop (GstPad * pad);
+static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
+    GstBuffer * inbuf);
+static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
+static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
+    QtDemuxStream * stream);
+static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
+    QtDemuxStream * stream);
+static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
+    gboolean force);
+
+static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
+    const guint8 * buffer, guint length);
+static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
+    const guint8 * buffer, guint length);
+static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
+static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
+    GNode * udta);
+
+static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
+    GstTagList * list);
+static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
+    const guint8 * stsd_entry_data, gchar ** codec_name);
+static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
+    const guint8 * data, int len, gchar ** codec_name);
+static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
+    gchar ** codec_name);
+static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
+    const guint8 * stsd_entry_data, gchar ** codec_name);
+
+static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, guint32 n);
+static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
+static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
+    QtDemuxStream * stream);
+static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
+    QtDemuxStream * stream);
+static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
+static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
+static void qtdemux_do_allocation (GstQTDemux * qtdemux,
+    QtDemuxStream * stream);
+static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
+static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
+    GstClockTime * _start, GstClockTime * _stop);
+static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
+    QtDemuxStream * stream, gint segment_index, GstClockTime pos);
+
+static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
+static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
+
+static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
+
+static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, guint sample_index);
+static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
+    const gchar * id);
+static void qtdemux_gst_structure_free (GstStructure * gststructure);
+
+static void
+gst_qtdemux_class_init (GstQTDemuxClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->dispose = gst_qtdemux_dispose;
+
+  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
+#if 0
+  gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
+  gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
+#endif
+
+  gst_tag_register_musicbrainz_tags ();
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_qtdemux_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_qtdemux_videosrc_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_qtdemux_audiosrc_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_qtdemux_subsrc_template);
+  gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
+      "Codec/Demuxer",
+      "Demultiplex a QuickTime file into audio and video streams",
+      "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
+
+  GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
+
+}
+
+static void
+gst_qtdemux_init (GstQTDemux * qtdemux)
+{
+  qtdemux->sinkpad =
+      gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
+  gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
+  gst_pad_set_activatemode_function (qtdemux->sinkpad,
+      qtdemux_sink_activate_mode);
+  gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
+  gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
+  gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
+
+  qtdemux->state = QTDEMUX_STATE_INITIAL;
+  qtdemux->pullbased = FALSE;
+  qtdemux->posted_redirect = FALSE;
+  qtdemux->neededbytes = 16;
+  qtdemux->todrop = 0;
+  qtdemux->adapter = gst_adapter_new ();
+  qtdemux->offset = 0;
+  qtdemux->first_mdat = -1;
+  qtdemux->got_moov = FALSE;
+  qtdemux->mdatoffset = -1;
+  qtdemux->mdatbuffer = NULL;
+  qtdemux->restoredata_buffer = NULL;
+  qtdemux->restoredata_offset = -1;
+  qtdemux->fragment_start = -1;
+  qtdemux->fragment_start_offset = -1;
+  qtdemux->media_caps = NULL;
+  qtdemux->exposed = FALSE;
+  qtdemux->mss_mode = FALSE;
+  qtdemux->pending_newsegment = NULL;
+  qtdemux->upstream_format_is_time = FALSE;
+  qtdemux->have_group_id = FALSE;
+  qtdemux->group_id = G_MAXUINT;
+  qtdemux->cenc_aux_info_offset = 0;
+  qtdemux->cenc_aux_info_sizes = NULL;
+  qtdemux->cenc_aux_sample_count = 0;
+  qtdemux->protection_system_ids = NULL;
+  g_queue_init (&qtdemux->protection_event_queue);
+  gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
+  qtdemux->tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
+  qtdemux->flowcombiner = gst_flow_combiner_new ();
+
+  GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
+}
+
+static void
+gst_qtdemux_dispose (GObject * object)
+{
+  GstQTDemux *qtdemux = GST_QTDEMUX (object);
+
+  if (qtdemux->adapter) {
+    g_object_unref (G_OBJECT (qtdemux->adapter));
+    qtdemux->adapter = NULL;
+  }
+  gst_tag_list_unref (qtdemux->tag_list);
+  gst_flow_combiner_free (qtdemux->flowcombiner);
+  g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
+      NULL);
+  g_queue_clear (&qtdemux->protection_event_queue);
+
+  g_free (qtdemux->cenc_aux_info_sizes);
+  qtdemux->cenc_aux_info_sizes = NULL;
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
+{
+  if (qtdemux->posted_redirect) {
+    GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
+        (_("This file contains no playable streams.")),
+        ("no known streams found, a redirect message has been posted"));
+  } else {
+    GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
+        (_("This file contains no playable streams.")),
+        ("no known streams found"));
+  }
+}
+
+static GstBuffer *
+_gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
+{
+  return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
+      mem, size, 0, size, mem, free_func);
+}
+
+static GstFlowReturn
+gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
+    GstBuffer ** buf)
+{
+  GstFlowReturn flow;
+  GstMapInfo map;
+  gsize bsize;
+
+  if (G_UNLIKELY (size == 0)) {
+    GstFlowReturn ret;
+    GstBuffer *tmp = NULL;
+
+    ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
+    if (ret != GST_FLOW_OK)
+      return ret;
+
+    gst_buffer_map (tmp, &map, GST_MAP_READ);
+    size = QT_UINT32 (map.data);
+    GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
+
+    gst_buffer_unmap (tmp, &map);
+    gst_buffer_unref (tmp);
+  }
+
+  /* Sanity check: catch bogus sizes (fuzzed/broken files) */
+  if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
+    if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
+      /* we're pulling header but already got most interesting bits,
+       * so never mind the rest (e.g. tags) (that much) */
+      GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
+          size);
+      return GST_FLOW_EOS;
+    } else {
+      GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
+          (_("This file is invalid and cannot be played.")),
+          ("atom has bogus size %" G_GUINT64_FORMAT, size));
+      return GST_FLOW_ERROR;
+    }
+  }
+
+  flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
+
+  if (G_UNLIKELY (flow != GST_FLOW_OK))
+    return flow;
+
+  bsize = gst_buffer_get_size (*buf);
+  /* Catch short reads - we don't want any partial atoms */
+  if (G_UNLIKELY (bsize < size)) {
+    GST_WARNING_OBJECT (qtdemux,
+        "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
+    gst_buffer_unref (*buf);
+    *buf = NULL;
+    return GST_FLOW_EOS;
+  }
+
+  return flow;
+}
+
+#if 1
+static gboolean
+gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
+    GstFormat src_format, gint64 src_value, GstFormat dest_format,
+    gint64 * dest_value)
+{
+  gboolean res = TRUE;
+  QtDemuxStream *stream = gst_pad_get_element_private (pad);
+  gint32 index;
+
+  if (stream->subtype != FOURCC_vide) {
+    res = FALSE;
+    goto done;
+  }
+
+  switch (src_format) {
+    case GST_FORMAT_TIME:
+      switch (dest_format) {
+        case GST_FORMAT_BYTES:{
+          index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
+          if (-1 == index) {
+            res = FALSE;
+            goto done;
+          }
+
+          *dest_value = stream->samples[index].offset;
+
+          GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
+              GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
+              GST_TIME_ARGS (src_value), *dest_value);
+          break;
+        }
+        default:
+          res = FALSE;
+          break;
+      }
+      break;
+    case GST_FORMAT_BYTES:
+      switch (dest_format) {
+        case GST_FORMAT_TIME:{
+          index =
+              gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
+              stream, src_value);
+
+          if (-1 == index) {
+            res = FALSE;
+            goto done;
+          }
+
+          *dest_value =
+              QTSTREAMTIME_TO_GSTTIME (stream,
+              stream->samples[index].timestamp);
+          GST_DEBUG_OBJECT (qtdemux,
+              "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
+              GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
+          break;
+        }
+        default:
+          res = FALSE;
+          break;
+      }
+      break;
+    default:
+      res = FALSE;
+      break;
+  }
+
+done:
+  return res;
+}
+#endif
+
+static gboolean
+gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
+{
+  gboolean res = FALSE;
+
+  *duration = GST_CLOCK_TIME_NONE;
+
+  if (qtdemux->duration != 0 &&
+      qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
+    *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
+    res = TRUE;
+  } else {
+    *duration = GST_CLOCK_TIME_NONE;
+  }
+
+  return res;
+}
+
+static gboolean
+gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  gboolean res = FALSE;
+  GstQTDemux *qtdemux = GST_QTDEMUX (parent);
+
+  GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:{
+      GstFormat fmt;
+
+      gst_query_parse_position (query, &fmt, NULL);
+      if (fmt == GST_FORMAT_TIME
+          && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
+        gst_query_set_position (query, GST_FORMAT_TIME,
+            qtdemux->segment.position);
+        res = TRUE;
+      }
+    }
+      break;
+    case GST_QUERY_DURATION:{
+      GstFormat fmt;
+
+      gst_query_parse_duration (query, &fmt, NULL);
+      if (fmt == GST_FORMAT_TIME) {
+        /* First try to query upstream */
+        res = gst_pad_query_default (pad, parent, query);
+        if (!res) {
+          GstClockTime duration;
+          if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
+            gst_query_set_duration (query, GST_FORMAT_TIME, duration);
+            res = TRUE;
+          }
+        }
+      }
+      break;
+    }
+    case GST_QUERY_CONVERT:{
+      GstFormat src_fmt, dest_fmt;
+      gint64 src_value, dest_value = 0;
+
+      gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
+
+      res = gst_qtdemux_src_convert (qtdemux, pad,
+          src_fmt, src_value, dest_fmt, &dest_value);
+      if (res)
+        gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
+
+      break;
+    }
+    case GST_QUERY_FORMATS:
+      gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
+      res = TRUE;
+      break;
+    case GST_QUERY_SEEKING:{
+      GstFormat fmt;
+      gboolean seekable;
+
+      /* try upstream first */
+      res = gst_pad_query_default (pad, parent, query);
+
+      if (!res) {
+        gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
+        if (fmt == GST_FORMAT_TIME) {
+          GstClockTime duration;
+
+          gst_qtdemux_get_duration (qtdemux, &duration);
+          seekable = TRUE;
+          if (!qtdemux->pullbased) {
+            GstQuery *q;
+
+            /* we might be able with help from upstream */
+            seekable = FALSE;
+            q = gst_query_new_seeking (GST_FORMAT_BYTES);
+            if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
+              gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
+              GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
+            }
+            gst_query_unref (q);
+          }
+          gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
+          res = TRUE;
+        }
+      }
+      break;
+    }
+    case GST_QUERY_SEGMENT:
+    {
+      GstFormat format;
+      gint64 start, stop;
+
+      format = qtdemux->segment.format;
+
+      start =
+          gst_segment_to_stream_time (&qtdemux->segment, format,
+          qtdemux->segment.start);
+      if ((stop = qtdemux->segment.stop) == -1)
+        stop = qtdemux->segment.duration;
+      else
+        stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
+
+      gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
+      res = TRUE;
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+
+  return res;
+}
+
+static void
+gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
+{
+  if (G_LIKELY (stream->pad)) {
+    GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
+        GST_DEBUG_PAD_NAME (stream->pad));
+
+    if (!gst_tag_list_is_empty (stream->stream_tags)) {
+      GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
+          stream->stream_tags);
+      gst_pad_push_event (stream->pad,
+          gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
+    }
+
+    if (G_UNLIKELY (stream->send_global_tags)) {
+      GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
+          qtdemux->tag_list);
+      gst_pad_push_event (stream->pad,
+          gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
+      stream->send_global_tags = FALSE;
+    }
+  }
+}
+
+/* push event on all source pads; takes ownership of the event */
+static void
+gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
+{
+  guint n;
+  gboolean has_valid_stream = FALSE;
+  GstEventType etype = GST_EVENT_TYPE (event);
+
+  GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
+      GST_EVENT_TYPE_NAME (event));
+
+  for (n = 0; n < qtdemux->n_streams; n++) {
+    GstPad *pad;
+    QtDemuxStream *stream = qtdemux->streams[n];
+    GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
+
+    if ((pad = stream->pad)) {
+      has_valid_stream = TRUE;
+
+      if (etype == GST_EVENT_EOS) {
+        /* let's not send twice */
+        if (stream->sent_eos)
+          continue;
+        stream->sent_eos = TRUE;
+      }
+
+      gst_pad_push_event (pad, gst_event_ref (event));
+    }
+  }
+
+  gst_event_unref (event);
+
+  /* if it is EOS and there are no pads, post an error */
+  if (!has_valid_stream && etype == GST_EVENT_EOS) {
+    gst_qtdemux_post_no_playable_stream_error (qtdemux);
+  }
+}
+
+/* push a pending newsegment event, if any from the streaming thread */
+static void
+gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
+{
+  if (qtdemux->pending_newsegment) {
+    gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
+    qtdemux->pending_newsegment = NULL;
+  }
+}
+
+typedef struct
+{
+  guint64 media_time;
+} FindData;
+
+static gint
+find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
+{
+  if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
+    return 1;
+  if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
+    return 0;
+
+  return -1;
+}
+
+/* find the index of the sample that includes the data for @media_time using a
+ * binary search.  Only to be called in optimized cases of linear search below.
+ *
+ * Returns the index of the sample.
+ */
+static guint32
+gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
+    guint64 media_time)
+{
+  QtDemuxSample *result;
+  guint32 index;
+
+  /* convert media_time to mov format */
+  media_time =
+      gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
+
+  result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
+      sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
+      GST_SEARCH_MODE_BEFORE, &media_time, NULL);
+
+  if (G_LIKELY (result))
+    index = result - str->samples;
+  else
+    index = 0;
+
+  return index;
+}
+
+
+
+/* find the index of the sample that includes the data for @media_offset using a
+ * linear search
+ *
+ * Returns the index of the sample.
+ */
+static guint32
+gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
+    QtDemuxStream * str, gint64 media_offset)
+{
+  QtDemuxSample *result = str->samples;
+  guint32 index = 0;
+
+  if (result == NULL || str->n_samples == 0)
+    return -1;
+
+  if (media_offset == result->offset)
+    return index;
+
+  result++;
+  while (index < str->n_samples - 1) {
+    if (!qtdemux_parse_samples (qtdemux, str, index + 1))
+      goto parse_failed;
+
+    if (media_offset < result->offset)
+      break;
+
+    index++;
+    result++;
+  }
+  return index;
+
+  /* ERRORS */
+parse_failed:
+  {
+    GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
+    return -1;
+  }
+}
+
+/* find the index of the sample that includes the data for @media_time using a
+ * linear search, and keeping in mind that not all samples may have been parsed
+ * yet.  If possible, it will delegate to binary search.
+ *
+ * Returns the index of the sample.
+ */
+static guint32
+gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
+    GstClockTime media_time)
+{
+  guint32 index = 0;
+  guint64 mov_time;
+  QtDemuxSample *sample;
+
+  /* convert media_time to mov format */
+  mov_time =
+      gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
+
+  sample = str->samples;
+  if (mov_time == sample->timestamp + sample->pts_offset)
+    return index;
+
+  /* use faster search if requested time in already parsed range */
+  sample = str->samples + str->stbl_index;
+  if (str->stbl_index >= 0 &&
+      mov_time <= (sample->timestamp + sample->pts_offset))
+    return gst_qtdemux_find_index (qtdemux, str, media_time);
+
+  while (index < str->n_samples - 1) {
+    if (!qtdemux_parse_samples (qtdemux, str, index + 1))
+      goto parse_failed;
+
+    sample = str->samples + index + 1;
+    if (mov_time < (sample->timestamp + sample->pts_offset))
+      break;
+
+    index++;
+  }
+  return index;
+
+  /* ERRORS */
+parse_failed:
+  {
+    GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
+    return -1;
+  }
+}
+
+/* find the index of the keyframe needed to decode the sample at @index
+ * of stream @str, or of a subsequent keyframe (depending on @next)
+ *
+ * Returns the index of the keyframe.
+ */
+static guint32
+gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
+    guint32 index, gboolean next)
+{
+  guint32 new_index = index;
+
+  if (index >= str->n_samples) {
+    new_index = str->n_samples;
+    goto beach;
+  }
+
+  /* all keyframes, return index */
+  if (str->all_keyframe) {
+    new_index = index;
+    goto beach;
+  }
+
+  /* else search until we have a keyframe */
+  while (new_index < str->n_samples) {
+    if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
+      goto parse_failed;
+
+    if (str->samples[new_index].keyframe)
+      break;
+
+    if (new_index == 0)
+      break;
+
+    if (next)
+      new_index++;
+    else
+      new_index--;
+  }
+
+  if (new_index == str->n_samples) {
+    GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
+    new_index = -1;
+  }
+
+beach:
+  GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
+      "gave %u", next ? "after" : "before", index, new_index);
+
+  return new_index;
+
+  /* ERRORS */
+parse_failed:
+  {
+    GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
+    return -1;
+  }
+}
+
+/* find the segment for @time_position for @stream
+ *
+ * Returns the index of the segment containing @time_position.
+ * Returns the last segment and sets the @eos variable to TRUE
+ * if the time is beyond the end. @eos may be NULL
+ */
+static guint32
+gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    GstClockTime time_position)
+{
+  gint i;
+  guint32 seg_idx;
+
+  GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (time_position));
+
+  seg_idx = -1;
+  for (i = 0; i < stream->n_segments; i++) {
+    QtDemuxSegment *segment = &stream->segments[i];
+
+    GST_LOG_OBJECT (stream->pad,
+        "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
+        GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
+
+    /* For the last segment we include stop_time in the last segment */
+    if (i < stream->n_segments - 1) {
+      if (segment->time <= time_position && time_position < segment->stop_time) {
+        GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
+        seg_idx = i;
+        break;
+      }
+    } else {
+      /* Last segment always matches */
+      seg_idx = i;
+      break;
+    }
+  }
+  return seg_idx;
+}
+
+/* move the stream @str to the sample position @index.
+ *
+ * Updates @str->sample_index and marks discontinuity if needed.
+ */
+static void
+gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
+    guint32 index)
+{
+  /* no change needed */
+  if (index == str->sample_index)
+    return;
+
+  GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
+      str->n_samples);
+
+  /* position changed, we have a discont */
+  str->sample_index = index;
+  str->offset_in_sample = 0;
+  /* Each time we move in the stream we store the position where we are
+   * starting from */
+  str->from_sample = index;
+  str->discont = TRUE;
+}
+
+static void
+gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
+    gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
+{
+  guint64 min_offset;
+  gint64 min_byte_offset = -1;
+  gint n;
+
+  min_offset = desired_time;
+
+  /* for each stream, find the index of the sample in the segment
+   * and move back to the previous keyframe. */
+  for (n = 0; n < qtdemux->n_streams; n++) {
+    QtDemuxStream *str;
+    guint32 index, kindex;
+    guint32 seg_idx;
+    GstClockTime media_start;
+    GstClockTime media_time;
+    GstClockTime seg_time;
+    QtDemuxSegment *seg;
+    gboolean empty_segment = FALSE;
+
+    str = qtdemux->streams[n];
+
+    if (CUR_STREAM (str)->sparse && !use_sparse)
+      continue;
+
+    seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
+    GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
+
+    /* get segment and time in the segment */
+    seg = &str->segments[seg_idx];
+    seg_time = (desired_time - seg->time) * seg->rate;
+
+    while (QTSEGMENT_IS_EMPTY (seg)) {
+      seg_time = 0;
+      empty_segment = TRUE;
+      GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
+          seg_idx);
+      seg_idx++;
+      if (seg_idx == str->n_segments)
+        break;
+      seg = &str->segments[seg_idx];
+    }
+
+    if (seg_idx == str->n_segments) {
+      /* FIXME track shouldn't have the last segment as empty, but if it
+       * happens we better handle it */
+      continue;
+    }
+
+    /* get the media time in the segment */
+    media_start = seg->media_start + seg_time;
+
+    /* get the index of the sample with media time */
+    index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
+    GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
+        " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
+        GST_TIME_ARGS (media_start), index, str->samples[index].offset,
+        empty_segment);
+
+    /* shift to next frame if we are looking for next keyframe */
+    if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
+        && index < str->stbl_index)
+      index++;
+
+    if (!empty_segment) {
+      /* find previous keyframe */
+      kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
+
+      /* we will settle for one before if none found after */
+      if (next && kindex == -1)
+        kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
+
+      /* if the keyframe is at a different position, we need to update the
+       * requested seek time */
+      if (index != kindex) {
+        index = kindex;
+
+        /* get timestamp of keyframe */
+        media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
+        GST_DEBUG_OBJECT (qtdemux,
+            "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
+            G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
+            str->samples[kindex].offset);
+
+        /* keyframes in the segment get a chance to change the
+         * desired_offset. keyframes out of the segment are
+         * ignored. */
+        if (media_time >= seg->media_start) {
+          GstClockTime seg_time;
+
+          /* this keyframe is inside the segment, convert back to
+           * segment time */
+          seg_time = (media_time - seg->media_start) + seg->time;
+          if ((!next && (seg_time < min_offset)) ||
+              (next && (seg_time > min_offset)))
+            min_offset = seg_time;
+        }
+      }
+    }
+
+    if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
+      min_byte_offset = str->samples[index].offset;
+  }
+
+  if (key_time)
+    *key_time = min_offset;
+  if (key_offset)
+    *key_offset = min_byte_offset;
+}
+
+static gboolean
+gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
+    GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
+{
+  gboolean res;
+
+  g_return_val_if_fail (format != NULL, FALSE);
+  g_return_val_if_fail (cur != NULL, FALSE);
+  g_return_val_if_fail (stop != NULL, FALSE);
+
+  if (*format == GST_FORMAT_TIME)
+    return TRUE;
+
+  res = TRUE;
+  if (cur_type != GST_SEEK_TYPE_NONE)
+    res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
+  if (res && stop_type != GST_SEEK_TYPE_NONE)
+    res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
+
+  if (res)
+    *format = GST_FORMAT_TIME;
+
+  return res;
+}
+
+/* perform seek in push based mode:
+   find BYTE position to move to based on time and delegate to upstream
+*/
+static gboolean
+gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
+{
+  gdouble rate;
+  GstFormat format;
+  GstSeekFlags flags;
+  GstSeekType cur_type, stop_type;
+  gint64 cur, stop, key_cur;
+  gboolean res;
+  gint64 byte_cur;
+  gint64 original_stop;
+  guint32 seqnum;
+
+  GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
+
+  gst_event_parse_seek (event, &rate, &format, &flags,
+      &cur_type, &cur, &stop_type, &stop);
+  seqnum = gst_event_get_seqnum (event);
+
+  /* only forward streaming and seeking is possible */
+  if (rate <= 0)
+    goto unsupported_seek;
+
+  /* convert to TIME if needed and possible */
+  if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
+          stop_type, &stop))
+    goto no_format;
+
+  /* Upstream seek in bytes will have undefined stop, but qtdemux stores
+   * the original stop position to use when upstream pushes the new segment
+   * for this seek */
+  original_stop = stop;
+  stop = -1;
+
+  /* find reasonable corresponding BYTE position,
+   * also try to mind about keyframes, since we can not go back a bit for them
+   * later on */
+  /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
+   * mostly just work, but let's not yet boldly go there  ... */
+  gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
+
+  if (byte_cur == -1)
+    goto abort_seek;
+
+  GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
+      "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
+      stop);
+
+  GST_OBJECT_LOCK (qtdemux);
+  qtdemux->seek_offset = byte_cur;
+  if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
+    qtdemux->push_seek_start = cur;
+  } else {
+    qtdemux->push_seek_start = key_cur;
+  }
+
+  if (stop_type == GST_SEEK_TYPE_NONE) {
+    qtdemux->push_seek_stop = qtdemux->segment.stop;
+  } else {
+    qtdemux->push_seek_stop = original_stop;
+  }
+  GST_OBJECT_UNLOCK (qtdemux);
+
+  /* BYTE seek event */
+  event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
+      stop_type, stop);
+  gst_event_set_seqnum (event, seqnum);
+  res = gst_pad_push_event (qtdemux->sinkpad, event);
+
+  return res;
+
+  /* ERRORS */
+abort_seek:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
+        "seek aborted.");
+    return FALSE;
+  }
+unsupported_seek:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
+    return FALSE;
+  }
+no_format:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
+    return FALSE;
+  }
+}
+
+/* perform the seek.
+ *
+ * We set all segment_indexes in the streams to unknown and
+ * adjust the time_position to the desired position. this is enough
+ * to trigger a segment switch in the streaming thread to start
+ * streaming from the desired position.
+ *
+ * Keyframe seeking is a little more complicated when dealing with
+ * segments. Ideally we want to move to the previous keyframe in
+ * the segment but there might not be a keyframe in the segment. In
+ * fact, none of the segments could contain a keyframe. We take a
+ * practical approach: seek to the previous keyframe in the segment,
+ * if there is none, seek to the beginning of the segment.
+ *
+ * Called with STREAM_LOCK
+ */
+static gboolean
+gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
+    guint32 seqnum, GstSeekFlags flags)
+{
+  gint64 desired_offset;
+  gint n;
+
+  desired_offset = segment->position;
+
+  GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (desired_offset));
+
+  /* may not have enough fragmented info to do this adjustment,
+   * and we can't scan (and probably should not) at this time with
+   * possibly flushing upstream */
+  if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
+    gint64 min_offset;
+    gboolean next, before, after;
+
+    before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
+    after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
+    next = after && !before;
+    if (segment->rate < 0)
+      next = !next;
+
+    gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
+        NULL);
+    GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
+        GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
+    desired_offset = min_offset;
+  }
+
+  /* and set all streams to the final position */
+  gst_flow_combiner_reset (qtdemux->flowcombiner);
+  qtdemux->segment_seqnum = seqnum;
+  for (n = 0; n < qtdemux->n_streams; n++) {
+    QtDemuxStream *stream = qtdemux->streams[n];
+
+    stream->time_position = desired_offset;
+    stream->accumulated_base = 0;
+    stream->sample_index = -1;
+    stream->offset_in_sample = 0;
+    stream->segment_index = -1;
+    stream->sent_eos = FALSE;
+
+    if (segment->flags & GST_SEEK_FLAG_FLUSH)
+      gst_segment_init (&stream->segment, GST_FORMAT_TIME);
+  }
+  segment->position = desired_offset;
+  segment->time = desired_offset;
+  if (segment->rate >= 0) {
+    segment->start = desired_offset;
+
+    /* we stop at the end */
+    if (segment->stop == -1)
+      segment->stop = segment->duration;
+  } else {
+    segment->stop = desired_offset;
+  }
+
+  if (qtdemux->fragmented)
+    qtdemux->fragmented_seek_pending = TRUE;
+
+  return TRUE;
+}
+
+/* do a seek in pull based mode */
+static gboolean
+gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
+{
+  gdouble rate;
+  GstFormat format;
+  GstSeekFlags flags;
+  GstSeekType cur_type, stop_type;
+  gint64 cur, stop;
+  gboolean flush;
+  gboolean update;
+  GstSegment seeksegment;
+  guint32 seqnum = GST_SEQNUM_INVALID;
+  GstEvent *flush_event;
+  gboolean ret;
+
+  if (event) {
+    GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
+
+    gst_event_parse_seek (event, &rate, &format, &flags,
+        &cur_type, &cur, &stop_type, &stop);
+    seqnum = gst_event_get_seqnum (event);
+
+    /* we have to have a format as the segment format. Try to convert
+     * if not. */
+    if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
+            stop_type, &stop))
+      goto no_format;
+
+    GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
+  } else {
+    GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
+    flags = 0;
+  }
+
+  flush = flags & GST_SEEK_FLAG_FLUSH;
+
+  /* stop streaming, either by flushing or by pausing the task */
+  if (flush) {
+    flush_event = gst_event_new_flush_start ();
+    if (seqnum != GST_SEQNUM_INVALID)
+      gst_event_set_seqnum (flush_event, seqnum);
+    /* unlock upstream pull_range */
+    gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
+    /* make sure out loop function exits */
+    gst_qtdemux_push_event (qtdemux, flush_event);
+  } else {
+    /* non flushing seek, pause the task */
+    gst_pad_pause_task (qtdemux->sinkpad);
+  }
+
+  /* wait for streaming to finish */
+  GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
+
+  /* copy segment, we need this because we still need the old
+   * segment when we close the current segment. */
+  memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
+
+  if (event) {
+    /* configure the segment with the seek variables */
+    GST_DEBUG_OBJECT (qtdemux, "configuring seek");
+    if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
+            cur_type, cur, stop_type, stop, &update)) {
+      ret = FALSE;
+      GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
+    } else {
+      /* now do the seek */
+      ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
+    }
+  } else {
+    /* now do the seek */
+    ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
+  }
+
+  /* prepare for streaming again */
+  if (flush) {
+    flush_event = gst_event_new_flush_stop (TRUE);
+    if (seqnum != GST_SEQNUM_INVALID)
+      gst_event_set_seqnum (flush_event, seqnum);
+
+    gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
+    gst_qtdemux_push_event (qtdemux, flush_event);
+  }
+
+  /* commit the new segment */
+  memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
+
+  if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+    GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
+        qtdemux->segment.format, qtdemux->segment.position);
+    if (seqnum != GST_SEQNUM_INVALID)
+      gst_message_set_seqnum (msg, seqnum);
+    gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
+  }
+
+  /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
+  gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
+      qtdemux->sinkpad, NULL);
+
+  GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
+
+  return ret;
+
+  /* ERRORS */
+no_format:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
+    return FALSE;
+  }
+}
+
+static gboolean
+qtdemux_ensure_index (GstQTDemux * qtdemux)
+{
+  guint i;
+
+  GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
+
+  /* Build complete index */
+  for (i = 0; i < qtdemux->n_streams; i++) {
+    QtDemuxStream *stream = qtdemux->streams[i];
+
+    if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
+      goto parse_error;
+  }
+  return TRUE;
+
+  /* ERRORS */
+parse_error:
+  {
+    GST_LOG_OBJECT (qtdemux,
+        "Building complete index of stream %u for seeking failed!", i);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  gboolean res = TRUE;
+  GstQTDemux *qtdemux = GST_QTDEMUX (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+    {
+#ifndef GST_DISABLE_GST_DEBUG
+      GstClockTime ts = gst_util_get_timestamp ();
+#endif
+      guint32 seqnum = gst_event_get_seqnum (event);
+
+      if (seqnum == qtdemux->segment_seqnum) {
+        GST_LOG_OBJECT (pad,
+            "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
+        gst_event_unref (event);
+        return TRUE;
+      }
+
+      if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
+        /* seek should be handled by upstream, we might need to re-download fragments */
+        GST_DEBUG_OBJECT (qtdemux,
+            "let upstream handle seek for fragmented playback");
+        goto upstream;
+      }
+
+      /* Build complete index for seeking;
+       * if not a fragmented file at least */
+      if (!qtdemux->fragmented)
+        if (!qtdemux_ensure_index (qtdemux))
+          goto index_failed;
+#ifndef GST_DISABLE_GST_DEBUG
+      ts = gst_util_get_timestamp () - ts;
+      GST_INFO_OBJECT (qtdemux,
+          "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
+#endif
+    }
+      if (qtdemux->pullbased) {
+        res = gst_qtdemux_do_seek (qtdemux, pad, event);
+      } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
+        GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
+        res = TRUE;
+      } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
+          && !qtdemux->fragmented) {
+        res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
+      } else {
+        GST_DEBUG_OBJECT (qtdemux,
+            "ignoring seek in push mode in current state");
+        res = FALSE;
+      }
+      gst_event_unref (event);
+      break;
+    default:
+    upstream:
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+done:
+  return res;
+
+  /* ERRORS */
+index_failed:
+  {
+    GST_ERROR_OBJECT (qtdemux, "Index failed");
+    gst_event_unref (event);
+    res = FALSE;
+    goto done;
+  }
+}
+
+/* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
+ *
+ * If @fw is false, the coding order is explored backwards.
+ *
+ * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
+ * sample is found for that track.
+ *
+ * The stream and sample index of the sample with the minimum offset in the direction explored
+ * (see @fw) is returned in the output parameters @_stream and @_index respectively.
+ *
+ * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
+ * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
+ * @_stream and @_index. */
+static void
+gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
+    gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
+{
+  gint i, n, index;
+  gint64 time, min_time;
+  QtDemuxStream *stream;
+
+  min_time = -1;
+  stream = NULL;
+  index = -1;
+
+  for (n = 0; n < qtdemux->n_streams; ++n) {
+    QtDemuxStream *str;
+    gint inc;
+    gboolean set_sample;
+
+    str = qtdemux->streams[n];
+    set_sample = !set;
+
+    if (fw) {
+      i = 0;
+      inc = 1;
+    } else {
+      i = str->n_samples - 1;
+      inc = -1;
+    }
+
+    for (; (i >= 0) && (i < str->n_samples); i += inc) {
+      if (str->samples[i].size == 0)
+        continue;
+
+      if (fw && (str->samples[i].offset < byte_pos))
+        continue;
+
+      if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
+        continue;
+
+      /* move stream to first available sample */
+      if (set) {
+        gst_qtdemux_move_stream (qtdemux, str, i);
+        set_sample = TRUE;
+      }
+
+      /* avoid index from sparse streams since they might be far away */
+      if (!CUR_STREAM (str)->sparse) {
+        /* determine min/max time */
+        time = QTSAMPLE_PTS (str, &str->samples[i]);
+        if (min_time == -1 || (!fw && time > min_time) ||
+            (fw && time < min_time)) {
+          min_time = time;
+        }
+
+        /* determine stream with leading sample, to get its position */
+        if (!stream ||
+            (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
+            (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
+          stream = str;
+          index = i;
+        }
+      }
+      break;
+    }
+
+    /* no sample for this stream, mark eos */
+    if (!set_sample)
+      gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
+  }
+
+  if (_time)
+    *_time = min_time;
+  if (_stream)
+    *_stream = stream;
+  if (_index)
+    *_index = index;
+}
+
+static QtDemuxStream *
+_create_stream (void)
+{
+  QtDemuxStream *stream;
+
+  stream = g_new0 (QtDemuxStream, 1);
+  /* new streams always need a discont */
+  stream->discont = TRUE;
+  /* we enable clipping for raw audio/video streams */
+  stream->need_clip = FALSE;
+  stream->need_process = FALSE;
+  stream->segment_index = -1;
+  stream->time_position = 0;
+  stream->sample_index = -1;
+  stream->offset_in_sample = 0;
+  stream->new_stream = TRUE;
+  stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
+  stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
+  stream->protected = FALSE;
+  stream->protection_scheme_type = 0;
+  stream->protection_scheme_version = 0;
+  stream->protection_scheme_info = NULL;
+  stream->n_samples_moof = 0;
+  stream->duration_moof = 0;
+  stream->duration_last_moof = 0;
+  stream->alignment = 1;
+  stream->stream_tags = gst_tag_list_new_empty ();
+  gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
+  g_queue_init (&stream->protection_scheme_event_queue);
+  return stream;
+}
+
+static gboolean
+gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
+{
+  GstStructure *structure;
+  const gchar *variant;
+  const GstCaps *mediacaps = NULL;
+
+  GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
+
+  structure = gst_caps_get_structure (caps, 0);
+  variant = gst_structure_get_string (structure, "variant");
+
+  if (variant && strcmp (variant, "mss-fragmented") == 0) {
+    QtDemuxStream *stream;
+    const GValue *value;
+
+    demux->fragmented = TRUE;
+    demux->mss_mode = TRUE;
+
+    if (demux->n_streams > 1) {
+      /* can't do this, we can only renegotiate for another mss format */
+      return FALSE;
+    }
+
+    value = gst_structure_get_value (structure, "media-caps");
+    /* create stream */
+    if (value) {
+      const GValue *timescale_v;
+
+      /* TODO update when stream changes during playback */
+
+      if (demux->n_streams == 0) {
+        stream = _create_stream ();
+        demux->streams[demux->n_streams] = stream;
+        demux->n_streams = 1;
+        /* mss has no stsd/stsd entry, use id 0 as default */
+        stream->stsd_entries_length = 1;
+        stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
+        stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
+      } else {
+        stream = demux->streams[0];
+      }
+
+      timescale_v = gst_structure_get_value (structure, "timescale");
+      if (timescale_v) {
+        stream->timescale = g_value_get_uint64 (timescale_v);
+      } else {
+        /* default mss timescale */
+        stream->timescale = 10000000;
+      }
+      demux->timescale = stream->timescale;
+
+      mediacaps = gst_value_get_caps (value);
+      if (!CUR_STREAM (stream)->caps
+          || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
+        GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
+            mediacaps);
+        stream->new_caps = TRUE;
+      }
+      gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
+      structure = gst_caps_get_structure (mediacaps, 0);
+      if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
+        stream->subtype = FOURCC_vide;
+
+        gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
+        gst_structure_get_int (structure, "height",
+            &CUR_STREAM (stream)->height);
+        gst_structure_get_fraction (structure, "framerate",
+            &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
+      } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
+        gint rate = 0;
+        stream->subtype = FOURCC_soun;
+        gst_structure_get_int (structure, "channels",
+            &CUR_STREAM (stream)->n_channels);
+        gst_structure_get_int (structure, "rate", &rate);
+        CUR_STREAM (stream)->rate = rate;
+      }
+    }
+    gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
+  } else {
+    demux->mss_mode = FALSE;
+  }
+
+  return TRUE;
+}
+
+static void
+gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
+{
+  gint n;
+
+  GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
+  gst_pad_stop_task (qtdemux->sinkpad);
+
+  if (hard || qtdemux->upstream_format_is_time) {
+    qtdemux->state = QTDEMUX_STATE_INITIAL;
+    qtdemux->neededbytes = 16;
+    qtdemux->todrop = 0;
+    qtdemux->pullbased = FALSE;
+    qtdemux->posted_redirect = FALSE;
+    qtdemux->first_mdat = -1;
+    qtdemux->header_size = 0;
+    qtdemux->mdatoffset = -1;
+    qtdemux->restoredata_offset = -1;
+    if (qtdemux->mdatbuffer)
+      gst_buffer_unref (qtdemux->mdatbuffer);
+    if (qtdemux->restoredata_buffer)
+      gst_buffer_unref (qtdemux->restoredata_buffer);
+    qtdemux->mdatbuffer = NULL;
+    qtdemux->restoredata_buffer = NULL;
+    qtdemux->mdatleft = 0;
+    qtdemux->mdatsize = 0;
+    if (qtdemux->comp_brands)
+      gst_buffer_unref (qtdemux->comp_brands);
+    qtdemux->comp_brands = NULL;
+    qtdemux->last_moov_offset = -1;
+    if (qtdemux->moov_node_compressed) {
+      g_node_destroy (qtdemux->moov_node_compressed);
+      if (qtdemux->moov_node)
+        g_free (qtdemux->moov_node->data);
+    }
+    qtdemux->moov_node_compressed = NULL;
+    if (qtdemux->moov_node)
+      g_node_destroy (qtdemux->moov_node);
+    qtdemux->moov_node = NULL;
+    if (qtdemux->tag_list)
+      gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
+    qtdemux->tag_list = gst_tag_list_new_empty ();
+    gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
+#if 0
+    if (qtdemux->element_index)
+      gst_object_unref (qtdemux->element_index);
+    qtdemux->element_index = NULL;
+#endif
+    qtdemux->major_brand = 0;
+    if (qtdemux->pending_newsegment)
+      gst_event_unref (qtdemux->pending_newsegment);
+    qtdemux->pending_newsegment = NULL;
+    qtdemux->upstream_format_is_time = FALSE;
+    qtdemux->upstream_seekable = FALSE;
+    qtdemux->upstream_size = 0;
+
+    qtdemux->fragment_start = -1;
+    qtdemux->fragment_start_offset = -1;
+    qtdemux->duration = 0;
+    qtdemux->moof_offset = 0;
+    qtdemux->chapters_track_id = 0;
+    qtdemux->have_group_id = FALSE;
+    qtdemux->group_id = G_MAXUINT;
+
+    g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
+        NULL);
+    g_queue_clear (&qtdemux->protection_event_queue);
+  }
+  qtdemux->offset = 0;
+  gst_adapter_clear (qtdemux->adapter);
+  gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
+  qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
+
+  if (hard) {
+    for (n = 0; n < qtdemux->n_streams; n++) {
+      gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
+      qtdemux->streams[n] = NULL;
+    }
+    qtdemux->n_streams = 0;
+    qtdemux->n_video_streams = 0;
+    qtdemux->n_audio_streams = 0;
+    qtdemux->n_sub_streams = 0;
+    qtdemux->exposed = FALSE;
+    qtdemux->fragmented = FALSE;
+    qtdemux->mss_mode = FALSE;
+    gst_caps_replace (&qtdemux->media_caps, NULL);
+    qtdemux->timescale = 0;
+    qtdemux->got_moov = FALSE;
+    if (qtdemux->protection_system_ids) {
+      g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
+      qtdemux->protection_system_ids = NULL;
+    }
+  } else if (qtdemux->mss_mode) {
+    gst_flow_combiner_reset (qtdemux->flowcombiner);
+    for (n = 0; n < qtdemux->n_streams; n++)
+      gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
+  } else {
+    gst_flow_combiner_reset (qtdemux->flowcombiner);
+    for (n = 0; n < qtdemux->n_streams; n++) {
+      qtdemux->streams[n]->sent_eos = FALSE;
+      qtdemux->streams[n]->time_position = 0;
+      qtdemux->streams[n]->accumulated_base = 0;
+    }
+    if (!qtdemux->pending_newsegment) {
+      qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
+      if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
+        gst_event_set_seqnum (qtdemux->pending_newsegment,
+            qtdemux->segment_seqnum);
+    }
+  }
+}
+
+
+/* Maps the @segment to the qt edts internal segments and pushes
+ * the correspnding segment event.
+ *
+ * If it ends up being at a empty segment, a gap will be pushed and the next
+ * edts segment will be activated in sequence.
+ *
+ * To be used in push-mode only */
+static void
+gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
+{
+  gint n, i;
+
+  for (n = 0; n < qtdemux->n_streams; n++) {
+    QtDemuxStream *stream = qtdemux->streams[n];
+
+    stream->time_position = segment->start;
+
+    /* in push mode we should be guaranteed that we will have empty segments
+     * at the beginning and then one segment after, other scenarios are not
+     * supported and are discarded when parsing the edts */
+    for (i = 0; i < stream->n_segments; i++) {
+      if (stream->segments[i].stop_time > segment->start) {
+        gst_qtdemux_activate_segment (qtdemux, stream, i,
+            stream->time_position);
+        if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
+          /* push the empty segment and move to the next one */
+          gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
+              stream->time_position);
+          continue;
+        }
+
+        g_assert (i == stream->n_segments - 1);
+      }
+    }
+  }
+}
+
+static gboolean
+gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
+    GstEvent * event)
+{
+  GstQTDemux *demux = GST_QTDEMUX (parent);
+  gboolean res = TRUE;
+
+  GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEGMENT:
+    {
+      gint64 offset = 0;
+      QtDemuxStream *stream;
+      gint idx;
+      GstSegment segment;
+
+      /* some debug output */
+      gst_event_copy_segment (event, &segment);
+      GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
+          &segment);
+
+      /* erase any previously set segment */
+      gst_event_replace (&demux->pending_newsegment, NULL);
+
+      if (segment.format == GST_FORMAT_TIME) {
+        GST_DEBUG_OBJECT (demux, "new pending_newsegment");
+        gst_event_replace (&demux->pending_newsegment, event);
+        demux->upstream_format_is_time = TRUE;
+      } else {
+        GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
+            "not in time format");
+
+        /* chain will send initial newsegment after pads have been added */
+        if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
+          GST_DEBUG_OBJECT (demux, "still starting, eating event");
+          goto exit;
+        }
+      }
+
+      /* check if this matches a time seek we received previously
+       * FIXME for backwards compatibility reasons we use the
+       * seek_offset here to compare. In the future we might want to
+       * change this to use the seqnum as it uniquely should identify
+       * the segment that corresponds to the seek. */
+      GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
+          ", received segment offset %" G_GINT64_FORMAT,
+          demux->seek_offset, segment.start);
+      if (segment.format == GST_FORMAT_BYTES
+          && demux->seek_offset == segment.start) {
+        GST_OBJECT_LOCK (demux);
+        offset = segment.start;
+
+        segment.format = GST_FORMAT_TIME;
+        segment.start = demux->push_seek_start;
+        segment.stop = demux->push_seek_stop;
+        GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
+            "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
+        GST_OBJECT_UNLOCK (demux);
+      }
+
+      /* we only expect a BYTE segment, e.g. following a seek */
+      if (segment.format == GST_FORMAT_BYTES) {
+        if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
+          offset = segment.start;
+
+          gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
+              NULL, (gint64 *) & segment.start);
+          if ((gint64) segment.start < 0)
+            segment.start = 0;
+        }
+        if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
+          gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
+              NULL, (gint64 *) & segment.stop);
+          /* keyframe seeking should already arrange for start >= stop,
+           * but make sure in other rare cases */
+          segment.stop = MAX (segment.stop, segment.start);
+        }
+      } else if (segment.format == GST_FORMAT_TIME) {
+        /* push all data on the adapter before starting this
+         * new segment */
+        gst_qtdemux_process_adapter (demux, TRUE);
+      } else {
+        GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
+        goto exit;
+      }
+
+      /* We shouldn't modify upstream driven TIME FORMAT segment */
+      if (!demux->upstream_format_is_time) {
+        /* accept upstream's notion of segment and distribute along */
+        segment.format = GST_FORMAT_TIME;
+        segment.position = segment.time = segment.start;
+        segment.duration = demux->segment.duration;
+        segment.base = gst_segment_to_running_time (&demux->segment,
+            GST_FORMAT_TIME, demux->segment.position);
+      }
+
+      gst_segment_copy_into (&segment, &demux->segment);
+      GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
+
+      /* map segment to internal qt segments and push on each stream */
+      if (demux->n_streams) {
+        if (demux->fragmented) {
+          GstEvent *segment_event = gst_event_new_segment (&segment);
+
+          gst_event_replace (&demux->pending_newsegment, NULL);
+          gst_event_set_seqnum (segment_event, demux->segment_seqnum);
+          gst_qtdemux_push_event (demux, segment_event);
+        } else {
+          gst_event_replace (&demux->pending_newsegment, NULL);
+          gst_qtdemux_map_and_push_segments (demux, &segment);
+        }
+      }
+
+      /* clear leftover in current segment, if any */
+      gst_adapter_clear (demux->adapter);
+
+      /* set up streaming thread */
+      demux->offset = offset;
+      if (demux->upstream_format_is_time) {
+        GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
+            "set values to restart reading from a new atom");
+        demux->neededbytes = 16;
+        demux->todrop = 0;
+      } else {
+        gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
+            NULL);
+        if (stream) {
+          demux->todrop = stream->samples[idx].offset - offset;
+          demux->neededbytes = demux->todrop + stream->samples[idx].size;
+        } else {
+          /* set up for EOS */
+          demux->neededbytes = -1;
+          demux->todrop = 0;
+        }
+      }
+    exit:
+      gst_event_unref (event);
+      res = TRUE;
+      goto drop;
+    }
+    case GST_EVENT_FLUSH_START:
+    {
+      if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
+        gst_event_unref (event);
+        goto drop;
+      }
+      break;
+    }
+    case GST_EVENT_FLUSH_STOP:
+    {
+      guint64 dur;
+
+      dur = demux->segment.duration;
+      gst_qtdemux_reset (demux, FALSE);
+      demux->segment.duration = dur;
+
+      if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
+        gst_event_unref (event);
+        goto drop;
+      }
+      break;
+    }
+    case GST_EVENT_EOS:
+      /* If we are in push mode, and get an EOS before we've seen any streams,
+       * then error out - we have nowhere to send the EOS */
+      if (!demux->pullbased) {
+        gint i;
+        gboolean has_valid_stream = FALSE;
+        for (i = 0; i < demux->n_streams; i++) {
+          if (demux->streams[i]->pad != NULL) {
+            has_valid_stream = TRUE;
+            break;
+          }
+        }
+        if (!has_valid_stream)
+          gst_qtdemux_post_no_playable_stream_error (demux);
+        else {
+          GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
+              (guint) gst_adapter_available (demux->adapter));
+          if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
+            res = FALSE;
+          }
+        }
+      }
+      break;
+    case GST_EVENT_CAPS:{
+      GstCaps *caps = NULL;
+
+      gst_event_parse_caps (event, &caps);
+      gst_qtdemux_setcaps (demux, caps);
+      res = TRUE;
+      gst_event_unref (event);
+      goto drop;
+    }
+    case GST_EVENT_PROTECTION:
+    {
+      const gchar *system_id = NULL;
+
+      gst_event_parse_protection (event, &system_id, NULL, NULL);
+      GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
+          system_id);
+      gst_qtdemux_append_protection_system_id (demux, system_id);
+      /* save the event for later, for source pads that have not been created */
+      g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
+      /* send it to all pads that already exist */
+      gst_qtdemux_push_event (demux, event);
+      res = TRUE;
+      goto drop;
+    }
+    default:
+      break;
+  }
+
+  res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
+
+drop:
+  return res;
+}
+
+#if 0
+static void
+gst_qtdemux_set_index (GstElement * element, GstIndex * index)
+{
+  GstQTDemux *demux = GST_QTDEMUX (element);
+
+  GST_OBJECT_LOCK (demux);
+  if (demux->element_index)
+    gst_object_unref (demux->element_index);
+  if (index) {
+    demux->element_index = gst_object_ref (index);
+  } else {
+    demux->element_index = NULL;
+  }
+  GST_OBJECT_UNLOCK (demux);
+  /* object lock might be taken again */
+  if (index)
+    gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
+  GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
+      demux->element_index, demux->index_id);
+}
+
+static GstIndex *
+gst_qtdemux_get_index (GstElement * element)
+{
+  GstIndex *result = NULL;
+  GstQTDemux *demux = GST_QTDEMUX (element);
+
+  GST_OBJECT_LOCK (demux);
+  if (demux->element_index)
+    result = gst_object_ref (demux->element_index);
+  GST_OBJECT_UNLOCK (demux);
+
+  GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
+
+  return result;
+}
+#endif
+
+static void
+gst_qtdemux_stbl_free (QtDemuxStream * stream)
+{
+  g_free ((gpointer) stream->stco.data);
+  stream->stco.data = NULL;
+  g_free ((gpointer) stream->stsz.data);
+  stream->stsz.data = NULL;
+  g_free ((gpointer) stream->stsc.data);
+  stream->stsc.data = NULL;
+  g_free ((gpointer) stream->stts.data);
+  stream->stts.data = NULL;
+  g_free ((gpointer) stream->stss.data);
+  stream->stss.data = NULL;
+  g_free ((gpointer) stream->stps.data);
+  stream->stps.data = NULL;
+  g_free ((gpointer) stream->ctts.data);
+  stream->ctts.data = NULL;
+}
+
+static void
+gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
+    QtDemuxStream * stream)
+{
+  g_free (stream->segments);
+  stream->segments = NULL;
+  stream->segment_index = -1;
+  stream->accumulated_base = 0;
+}
+
+static void
+gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
+    QtDemuxStream * stream)
+{
+  g_free (stream->samples);
+  stream->samples = NULL;
+  gst_qtdemux_stbl_free (stream);
+
+  /* fragments */
+  g_free (stream->ra_entries);
+  stream->ra_entries = NULL;
+  stream->n_ra_entries = 0;
+
+  stream->sample_index = -1;
+  stream->stbl_index = -1;
+  stream->n_samples = 0;
+  stream->time_position = 0;
+
+  stream->n_samples_moof = 0;
+  stream->duration_moof = 0;
+  stream->duration_last_moof = 0;
+}
+
+static void
+gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
+{
+  gint i;
+  if (stream->allocator)
+    gst_object_unref (stream->allocator);
+  while (stream->buffers) {
+    gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
+    stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
+  }
+  for (i = 0; i < stream->stsd_entries_length; i++) {
+    QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
+    if (entry->rgb8_palette) {
+      gst_memory_unref (entry->rgb8_palette);
+      entry->rgb8_palette = NULL;
+    }
+    entry->sparse = FALSE;
+  }
+
+  gst_tag_list_unref (stream->stream_tags);
+  stream->stream_tags = gst_tag_list_new_empty ();
+  gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
+  g_free (stream->redirect_uri);
+  stream->redirect_uri = NULL;
+  stream->sent_eos = FALSE;
+  stream->protected = FALSE;
+  if (stream->protection_scheme_info) {
+    if (stream->protection_scheme_type == FOURCC_cenc) {
+      QtDemuxCencSampleSetInfo *info =
+          (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
+      if (info->default_properties)
+        gst_structure_free (info->default_properties);
+      if (info->crypto_info)
+        g_ptr_array_free (info->crypto_info, TRUE);
+    }
+    g_free (stream->protection_scheme_info);
+    stream->protection_scheme_info = NULL;
+  }
+  stream->protection_scheme_type = 0;
+  stream->protection_scheme_version = 0;
+  g_queue_foreach (&stream->protection_scheme_event_queue,
+      (GFunc) gst_event_unref, NULL);
+  g_queue_clear (&stream->protection_scheme_event_queue);
+  gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
+  gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
+}
+
+static void
+gst_qtdemux_stream_reset (GstQTDemux * qtdemux, QtDemuxStream * stream)
+{
+  gint i;
+  gst_qtdemux_stream_clear (qtdemux, stream);
+  for (i = 0; i < stream->stsd_entries_length; i++) {
+    QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
+    if (entry->caps) {
+      gst_caps_unref (entry->caps);
+      entry->caps = NULL;
+    }
+  }
+  g_free (stream->stsd_entries);
+  stream->stsd_entries = NULL;
+  stream->stsd_entries_length = 0;
+}
+
+
+static void
+gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
+{
+  gst_qtdemux_stream_reset (qtdemux, stream);
+  gst_tag_list_unref (stream->stream_tags);
+  if (stream->pad) {
+    gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
+    gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
+  }
+  g_free (stream);
+}
+
+static void
+gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
+{
+  g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
+
+  gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
+  qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
+  qtdemux->streams[qtdemux->n_streams - 1] = NULL;
+  qtdemux->n_streams--;
+}
+
+static GstStateChangeReturn
+gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
+{
+  GstQTDemux *qtdemux = GST_QTDEMUX (element);
+  GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      break;
+    default:
+      break;
+  }
+
+  result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:{
+      gst_qtdemux_reset (qtdemux, TRUE);
+      break;
+    }
+    default:
+      break;
+  }
+
+  return result;
+}
+
+static void
+qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
+{
+  /* counts as header data */
+  qtdemux->header_size += length;
+
+  /* only consider at least a sufficiently complete ftyp atom */
+  if (length >= 20) {
+    GstBuffer *buf;
+
+    qtdemux->major_brand = QT_FOURCC (buffer + 8);
+    GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
+        GST_FOURCC_ARGS (qtdemux->major_brand));
+    if (qtdemux->comp_brands)
+      gst_buffer_unref (qtdemux->comp_brands);
+    buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
+    gst_buffer_fill (buf, 0, buffer + 16, length - 16);
+  }
+}
+
+static void
+qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
+    GstTagList * xmptaglist)
+{
+  /* Strip out bogus fields */
+  if (xmptaglist) {
+    if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
+      gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
+      gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
+    } else {
+      gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
+    }
+
+    GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
+
+    /* prioritize native tags using _KEEP mode */
+    gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
+    gst_tag_list_unref (xmptaglist);
+  }
+}
+
+static void
+qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
+    guint offset)
+{
+  GstByteReader br;
+  guint8 version;
+  guint32 flags = 0;
+  guint i;
+  guint8 iv_size = 8;
+  QtDemuxStream *stream;
+  GstStructure *structure;
+  QtDemuxCencSampleSetInfo *ss_info = NULL;
+  const gchar *system_id;
+  gboolean uses_sub_sample_encryption = FALSE;
+
+  if (qtdemux->n_streams == 0)
+    return;
+
+  stream = qtdemux->streams[0];
+
+  structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
+  if (!gst_structure_has_name (structure, "application/x-cenc")) {
+    GST_WARNING_OBJECT (qtdemux,
+        "Attempting PIFF box parsing on an unencrypted stream.");
+    return;
+  }
+
+  gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
+      G_TYPE_STRING, &system_id, NULL);
+  gst_qtdemux_append_protection_system_id (qtdemux, system_id);
+
+  stream->protected = TRUE;
+  stream->protection_scheme_type = FOURCC_cenc;
+
+  if (!stream->protection_scheme_info)
+    stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
+
+  ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
+
+  if (ss_info->default_properties)
+    gst_structure_free (ss_info->default_properties);
+
+  ss_info->default_properties =
+      gst_structure_new ("application/x-cenc",
+      "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
+
+  if (ss_info->crypto_info) {
+    GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
+    g_ptr_array_free (ss_info->crypto_info, TRUE);
+    ss_info->crypto_info = NULL;
+  }
+
+  /* skip UUID */
+  gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
+
+  if (!gst_byte_reader_get_uint8 (&br, &version)) {
+    GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
+    return;
+  }
+
+  if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
+    GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
+    return;
+  }
+
+  if ((flags & 0x000001)) {
+    guint32 algorithm_id = 0;
+    const guint8 *kid;
+    GstBuffer *kid_buf;
+    gboolean is_encrypted = TRUE;
+
+    if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
+      GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
+      return;
+    }
+
+    algorithm_id >>= 8;
+    if (algorithm_id == 0) {
+      is_encrypted = FALSE;
+    } else if (algorithm_id == 1) {
+      /* FIXME: maybe store this in properties? */
+      GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
+    } else if (algorithm_id == 2) {
+      /* FIXME: maybe store this in properties? */
+      GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
+    }
+
+    if (!gst_byte_reader_get_uint8 (&br, &iv_size))
+      return;
+
+    if (!gst_byte_reader_get_data (&br, 16, &kid))
+      return;
+
+    kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
+    gst_buffer_fill (kid_buf, 0, kid, 16);
+    if (ss_info->default_properties)
+      gst_structure_free (ss_info->default_properties);
+    ss_info->default_properties =
+        gst_structure_new ("application/x-cenc",
+        "iv_size", G_TYPE_UINT, iv_size,
+        "encrypted", G_TYPE_BOOLEAN, is_encrypted,
+        "kid", GST_TYPE_BUFFER, kid_buf, NULL);
+    GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
+        "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
+    gst_buffer_unref (kid_buf);
+  } else if ((flags & 0x000002)) {
+    uses_sub_sample_encryption = TRUE;
+  }
+
+  if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
+    GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
+    return;
+  }
+
+  ss_info->crypto_info =
+      g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
+      (GDestroyNotify) qtdemux_gst_structure_free);
+
+  for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
+    GstStructure *properties;
+    guint8 *data;
+    GstBuffer *buf;
+
+    properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
+    if (properties == NULL) {
+      GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
+      return;
+    }
+
+    if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
+      GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
+      gst_structure_free (properties);
+      return;
+    }
+    buf = gst_buffer_new_wrapped (data, iv_size);
+    gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
+    gst_buffer_unref (buf);
+
+    if (uses_sub_sample_encryption) {
+      guint16 n_subsamples;
+
+      if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
+          || n_subsamples == 0) {
+        GST_ERROR_OBJECT (qtdemux,
+            "failed to get subsample count for sample %u", i);
+        gst_structure_free (properties);
+        return;
+      }
+      GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
+      if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
+        GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
+            i);
+        gst_structure_free (properties);
+        return;
+      }
+      buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
+      gst_structure_set (properties,
+          "subsample_count", G_TYPE_UINT, n_subsamples,
+          "subsamples", GST_TYPE_BUFFER, buf, NULL);
+      gst_buffer_unref (buf);
+    } else {
+      gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
+    }
+
+    g_ptr_array_add (ss_info->crypto_info, properties);
+  }
+}
+
+static void
+qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
+{
+  static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
+    0x97, 0xA9, 0x42, 0xE8,
+    0x9C, 0x71, 0x99, 0x94,
+    0x91, 0xE3, 0xAF, 0xAC
+  };
+  static const guint8 playready_uuid[] = {
+    0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
+    0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
+  };
+
+  static const guint8 piff_sample_encryption_uuid[] = {
+    0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
+    0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
+  };
+
+  guint offset;
+
+  /* counts as header data */
+  qtdemux->header_size += length;
+
+  offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
+
+  if (length <= offset + 16) {
+    GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
+    return;
+  }
+
+  if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
+    GstBuffer *buf;
+    GstTagList *taglist;
+
+    buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
+        length - offset - 16, NULL);
+    taglist = gst_tag_list_from_xmp_buffer (buf);
+    gst_buffer_unref (buf);
+
+    /* make sure we have a usable taglist */
+    qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
+
+    qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
+
+  } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
+    int len;
+    const gunichar2 *s_utf16;
+    char *contents;
+
+    len = GST_READ_UINT16_LE (buffer + offset + 0x30);
+    s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
+    contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
+    GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
+
+    g_free (contents);
+
+    GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
+        (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
+        (NULL));
+  } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
+    qtdemux_parse_piff (qtdemux, buffer, length, offset);
+  } else {
+    GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
+        GST_READ_UINT32_LE (buffer + offset),
+        GST_READ_UINT32_LE (buffer + offset + 4),
+        GST_READ_UINT32_LE (buffer + offset + 8),
+        GST_READ_UINT32_LE (buffer + offset + 12));
+  }
+}
+
+static void
+qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
+{
+  GstSidxParser sidx_parser;
+  GstIsoffParserResult res;
+  guint consumed;
+
+  gst_isoff_qt_sidx_parser_init (&sidx_parser);
+
+  res =
+      gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
+      &consumed);
+  GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
+  if (res == GST_ISOFF_QT_PARSER_DONE) {
+    check_update_duration (qtdemux, sidx_parser.cumulative_pts);
+  }
+  gst_isoff_qt_sidx_parser_clear (&sidx_parser);
+}
+
+/* caller verifies at least 8 bytes in buf */
+static void
+extract_initial_length_and_fourcc (const guint8 * data, guint size,
+    guint64 * plength, guint32 * pfourcc)
+{
+  guint64 length;
+  guint32 fourcc;
+
+  length = QT_UINT32 (data);
+  GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
+  fourcc = QT_FOURCC (data + 4);
+  GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
+
+  if (length == 0) {
+    length = G_MAXUINT64;
+  } else if (length == 1 && size >= 16) {
+    /* this means we have an extended size, which is the 64 bit value of
+     * the next 8 bytes */
+    length = QT_UINT64 (data + 8);
+    GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
+  }
+
+  if (plength)
+    *plength = length;
+  if (pfourcc)
+    *pfourcc = fourcc;
+}
+
+static gboolean
+qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
+{
+  guint32 version = 0;
+  GstClockTime duration = 0;
+
+  if (!gst_byte_reader_get_uint32_be (br, &version))
+    goto failed;
+
+  version >>= 24;
+  if (version == 1) {
+    if (!gst_byte_reader_get_uint64_be (br, &duration))
+      goto failed;
+  } else {
+    guint32 dur = 0;
+
+    if (!gst_byte_reader_get_uint32_be (br, &dur))
+      goto failed;
+    duration = dur;
+  }
+
+  GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
+  qtdemux->duration = duration;
+
+  return TRUE;
+
+failed:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
+    return FALSE;
+  }
+}
+
+static gboolean
+qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
+{
+  if (!stream->parsed_trex && qtdemux->moov_node) {
+    GNode *mvex, *trex;
+    GstByteReader trex_data;
+
+    mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
+    if (mvex) {
+      trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
+          &trex_data);
+      while (trex) {
+        guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
+
+        /* skip version/flags */
+        if (!gst_byte_reader_skip (&trex_data, 4))
+          goto next;
+        if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
+          goto next;
+        if (id != stream->track_id)
+          goto next;
+        if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
+          goto next;
+        if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
+          goto next;
+        if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
+          goto next;
+        if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
+          goto next;
+
+        GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
+            "duration %d,  size %d, flags 0x%x", stream->track_id,
+            dur, size, flags);
+
+        stream->parsed_trex = TRUE;
+        stream->def_sample_description_index = sdi;
+        stream->def_sample_duration = dur;
+        stream->def_sample_size = size;
+        stream->def_sample_flags = flags;
+
+      next:
+        /* iterate all siblings */
+        trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
+            &trex_data);
+      }
+    }
+  }
+
+  *ds_duration = stream->def_sample_duration;
+  *ds_size = stream->def_sample_size;
+  *ds_flags = stream->def_sample_flags;
+
+  /* even then, above values are better than random ... */
+  if (G_UNLIKELY (!stream->parsed_trex)) {
+    GST_WARNING_OBJECT (qtdemux,
+        "failed to find fragment defaults for stream %d", stream->track_id);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/* This method should be called whenever a more accurate duration might
+ * have been found. It will update all relevant variables if/where needed
+ */
+static void
+check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
+{
+  guint i;
+  guint64 movdur;
+  GstClockTime prevdur;
+
+  movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
+
+  if (movdur > qtdemux->duration) {
+    prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
+    GST_DEBUG_OBJECT (qtdemux,
+        "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
+    qtdemux->duration = movdur;
+    GST_DEBUG_OBJECT (qtdemux,
+        "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
+        GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
+        GST_TIME_ARGS (qtdemux->segment.stop));
+    if (qtdemux->segment.duration == prevdur) {
+      /* If the current segment has duration/stop identical to previous duration
+       * update them also (because they were set at that point in time with
+       * the wrong duration */
+      /* We convert the value *from* the timescale version to avoid rounding errors */
+      GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
+      GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
+      qtdemux->segment.duration = fixeddur;
+      qtdemux->segment.stop = fixeddur;
+    }
+  }
+  for (i = 0; i < qtdemux->n_streams; i++) {
+    QtDemuxStream *stream = qtdemux->streams[i];
+    if (stream) {
+      movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
+      if (movdur > stream->duration) {
+        GST_DEBUG_OBJECT (qtdemux,
+            "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
+            GST_TIME_ARGS (duration));
+        stream->duration = movdur;
+        /* internal duration tracking state has been updated above, so */
+        /* preserve an open-ended dummy segment rather than repeatedly updating
+         * it and spamming downstream accordingly with segment events */
+        if (stream->dummy_segment &&
+            GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
+          /* Update all dummy values to new duration */
+          stream->segments[0].stop_time = duration;
+          stream->segments[0].duration = duration;
+          stream->segments[0].media_stop = duration;
+
+          /* let downstream know we possibly have a new stop time */
+          if (stream->segment_index != -1) {
+            GstClockTime pos;
+
+            if (qtdemux->segment.rate >= 0) {
+              pos = stream->segment.start;
+            } else {
+              pos = stream->segment.stop;
+            }
+
+            gst_qtdemux_stream_update_segment (qtdemux, stream,
+                stream->segment_index, pos, NULL, NULL);
+          }
+        }
+      }
+    }
+  }
+}
+
+static gboolean
+qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
+    QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
+    guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
+    gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
+    gboolean has_tfdt)
+{
+  GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
+  guint64 timestamp;
+  gint32 data_offset = 0;
+  guint32 flags = 0, first_flags = 0, samples_count = 0;
+  gint i;
+  guint8 *data;
+  guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
+  QtDemuxSample *sample;
+  gboolean ismv = FALSE;
+  gint64 initial_offset;
+
+  GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
+      "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
+      "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
+      d_sample_size, d_sample_flags, *base_offset, decode_ts);
+
+  if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
+    GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
+    return TRUE;
+  }
+
+  /* presence of stss or not can't really tell us much,
+   * and flags and so on tend to be marginally reliable in these files */
+  if (stream->subtype == FOURCC_soun) {
+    GST_DEBUG_OBJECT (qtdemux,
+        "sound track in fragmented file; marking all keyframes");
+    stream->all_keyframe = TRUE;
+  }
+
+  if (!gst_byte_reader_skip (trun, 1) ||
+      !gst_byte_reader_get_uint24_be (trun, &flags))
+    goto fail;
+
+  if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
+    goto fail;
+
+  if (flags & TR_DATA_OFFSET) {
+    /* note this is really signed */
+    if (!gst_byte_reader_get_int32_be (trun, &data_offset))
+      goto fail;
+    GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
+    /* default base offset = first byte of moof */
+    if (*base_offset == -1) {
+      GST_LOG_OBJECT (qtdemux, "base_offset at moof");
+      *base_offset = moof_offset;
+    }
+    *running_offset = *base_offset + data_offset;
+  } else {
+    /* if no offset at all, that would mean data starts at moof start,
+     * which is a bit wrong and is ismv crappy way, so compensate
+     * assuming data is in mdat following moof */
+    if (*base_offset == -1) {
+      *base_offset = moof_offset + moof_length + 8;
+      GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
+      ismv = TRUE;
+    }
+    if (*running_offset == -1)
+      *running_offset = *base_offset;
+  }
+
+  GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
+      *running_offset);
+  GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
+      data_offset, flags, samples_count);
+
+  if (flags & TR_FIRST_SAMPLE_FLAGS) {
+    if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
+      GST_DEBUG_OBJECT (qtdemux,
+          "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
+      flags ^= TR_FIRST_SAMPLE_FLAGS;
+    } else {
+      if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
+        goto fail;
+      GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
+    }
+  }
+
+  /* FIXME ? spec says other bits should also be checked to determine
+   * entry size (and prefix size for that matter) */
+  entry_size = 0;
+  dur_offset = size_offset = 0;
+  if (flags & TR_SAMPLE_DURATION) {
+    GST_LOG_OBJECT (qtdemux, "entry duration present");
+    dur_offset = entry_size;
+    entry_size += 4;
+  }
+  if (flags & TR_SAMPLE_SIZE) {
+    GST_LOG_OBJECT (qtdemux, "entry size present");
+    size_offset = entry_size;
+    entry_size += 4;
+  }
+  if (flags & TR_SAMPLE_FLAGS) {
+    GST_LOG_OBJECT (qtdemux, "entry flags present");
+    flags_offset = entry_size;
+    entry_size += 4;
+  }
+  if (flags & TR_COMPOSITION_TIME_OFFSETS) {
+    GST_LOG_OBJECT (qtdemux, "entry ct offset present");
+    ct_offset = entry_size;
+    entry_size += 4;
+  }
+
+  if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
+    goto fail;
+  data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
+
+  if (stream->n_samples + samples_count >=
+      QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
+    goto index_too_big;
+
+  GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
+      stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
+      (stream->n_samples + samples_count) *
+      sizeof (QtDemuxSample) / (1024.0 * 1024.0));
+
+  /* create a new array of samples if it's the first sample parsed */
+  if (stream->n_samples == 0) {
+    g_assert (stream->samples == NULL);
+    stream->samples = g_try_new0 (QtDemuxSample, samples_count);
+    /* or try to reallocate it with space enough to insert the new samples */
+  } else
+    stream->samples = g_try_renew (QtDemuxSample, stream->samples,
+        stream->n_samples + samples_count);
+  if (stream->samples == NULL)
+    goto out_of_memory;
+
+  if (qtdemux->fragment_start != -1) {
+    timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
+    qtdemux->fragment_start = -1;
+  } else {
+    if (stream->n_samples == 0) {
+      if (decode_ts > 0) {
+        timestamp = decode_ts;
+      } else if (stream->pending_seek != NULL) {
+        /* if we don't have a timestamp from a tfdt box, we'll use the one
+         * from the mfra seek table */
+        GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (stream->pending_seek->ts));
+
+        /* FIXME: this is not fully correct, the timestamp refers to the random
+         * access sample refered to in the tfra entry, which may not necessarily
+         * be the first sample in the tfrag/trun (but hopefully/usually is) */
+        timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
+      } else {
+        timestamp = 0;
+      }
+
+      gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
+      GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (gst_ts));
+    } else {
+      /* subsequent fragments extend stream */
+      timestamp =
+          stream->samples[stream->n_samples - 1].timestamp +
+          stream->samples[stream->n_samples - 1].duration;
+
+      /* If this is a GST_FORMAT_BYTES stream and there's a significant
+       * difference (1 sec.) between decode_ts and timestamp, prefer the
+       * former */
+      if (has_tfdt && !qtdemux->upstream_format_is_time
+          && ABSDIFF (decode_ts, timestamp) >
+          MAX (stream->duration_last_moof / 2,
+              GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
+        GST_INFO_OBJECT (qtdemux,
+            "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
+            ") are significantly different (more than %" GST_TIME_FORMAT
+            "), using decode_ts",
+            GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
+            GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
+            GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
+                    MAX (stream->duration_last_moof / 2,
+                        GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
+        timestamp = decode_ts;
+      }
+
+      gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
+      GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
+          " (extends previous samples)", GST_TIME_ARGS (gst_ts));
+    }
+  }
+
+  initial_offset = *running_offset;
+
+  sample = stream->samples + stream->n_samples;
+  for (i = 0; i < samples_count; i++) {
+    guint32 dur, size, sflags, ct;
+
+    /* first read sample data */
+    if (flags & TR_SAMPLE_DURATION) {
+      dur = QT_UINT32 (data + dur_offset);
+    } else {
+      dur = d_sample_duration;
+    }
+    if (flags & TR_SAMPLE_SIZE) {
+      size = QT_UINT32 (data + size_offset);
+    } else {
+      size = d_sample_size;
+    }
+    if (flags & TR_FIRST_SAMPLE_FLAGS) {
+      if (i == 0) {
+        sflags = first_flags;
+      } else {
+        sflags = d_sample_flags;
+      }
+    } else if (flags & TR_SAMPLE_FLAGS) {
+      sflags = QT_UINT32 (data + flags_offset);
+    } else {
+      sflags = d_sample_flags;
+    }
+    if (flags & TR_COMPOSITION_TIME_OFFSETS) {
+      ct = QT_UINT32 (data + ct_offset);
+    } else {
+      ct = 0;
+    }
+    data += entry_size;
+
+    /* fill the sample information */
+    sample->offset = *running_offset;
+    sample->pts_offset = ct;
+    sample->size = size;
+    sample->timestamp = timestamp;
+    sample->duration = dur;
+    /* sample-is-difference-sample */
+    /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
+     * now idea how it relates to bitfield other than massive LE/BE confusion */
+    sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
+    *running_offset += size;
+    timestamp += dur;
+    stream->duration_moof += dur;
+    sample++;
+  }
+
+  /* Update total duration if needed */
+  check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
+
+  /* Pre-emptively figure out size of mdat based on trun information.
+   * If the [mdat] atom is effectivelly read, it will be replaced by the actual
+   * size, else we will still be able to use this when dealing with gap'ed
+   * input */
+  qtdemux->mdatleft = *running_offset - initial_offset;
+  qtdemux->mdatoffset = initial_offset;
+  qtdemux->mdatsize = qtdemux->mdatleft;
+
+  stream->n_samples += samples_count;
+  stream->n_samples_moof += samples_count;
+
+  if (stream->pending_seek != NULL)
+    stream->pending_seek = NULL;
+
+  return TRUE;
+
+fail:
+  {
+    GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
+    return FALSE;
+  }
+out_of_memory:
+  {
+    GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
+        stream->n_samples);
+    return FALSE;
+  }
+index_too_big:
+  {
+    GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
+        "be larger than %uMB (broken file?)", stream->n_samples,
+        QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
+    return FALSE;
+  }
+}
+
+/* find stream with @id */
+static inline QtDemuxStream *
+qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
+{
+  QtDemuxStream *stream;
+  gint i;
+
+  /* check */
+  if (G_UNLIKELY (!id)) {
+    GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
+    return NULL;
+  }
+
+  /* try to get it fast and simple */
+  if (G_LIKELY (id <= qtdemux->n_streams)) {
+    stream = qtdemux->streams[id - 1];
+    if (G_LIKELY (stream->track_id == id))
+      return stream;
+  }
+
+  /* linear search otherwise */
+  for (i = 0; i < qtdemux->n_streams; i++) {
+    stream = qtdemux->streams[i];
+    if (stream->track_id == id)
+      return stream;
+  }
+  if (qtdemux->mss_mode) {
+    /* mss should have only 1 stream anyway */
+    return qtdemux->streams[0];
+  }
+
+  return NULL;
+}
+
+static gboolean
+qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
+    guint32 * fragment_number)
+{
+  if (!gst_byte_reader_skip (mfhd, 4))
+    goto fail;
+  if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
+    goto fail;
+  return TRUE;
+fail:
+  {
+    GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
+    return FALSE;
+  }
+}
+
+static gboolean
+qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
+    QtDemuxStream ** stream, guint32 * default_sample_duration,
+    guint32 * default_sample_size, guint32 * default_sample_flags,
+    gint64 * base_offset)
+{
+  guint32 flags = 0;
+  guint32 track_id = 0;
+
+  if (!gst_byte_reader_skip (tfhd, 1) ||
+      !gst_byte_reader_get_uint24_be (tfhd, &flags))
+    goto invalid_track;
+
+  if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
+    goto invalid_track;
+
+  *stream = qtdemux_find_stream (qtdemux, track_id);
+  if (G_UNLIKELY (!*stream))
+    goto unknown_stream;
+
+  if (flags & TF_DEFAULT_BASE_IS_MOOF)
+    *base_offset = qtdemux->moof_offset;
+
+  if (flags & TF_BASE_DATA_OFFSET)
+    if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
+      goto invalid_track;
+
+  /* obtain stream defaults */
+  qtdemux_parse_trex (qtdemux, *stream,
+      default_sample_duration, default_sample_size, default_sample_flags);
+
+  (*stream)->stsd_sample_description_id =
+      (*stream)->def_sample_description_index - 1;
+
+  if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
+    guint32 sample_description_index;
+    if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
+      goto invalid_track;
+    (*stream)->stsd_sample_description_id = sample_description_index - 1;
+  }
+
+  if (qtdemux->mss_mode) {
+    /* mss has no stsd entry */
+    (*stream)->stsd_sample_description_id = 0;
+  }
+
+  if (flags & TF_DEFAULT_SAMPLE_DURATION)
+    if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
+      goto invalid_track;
+
+  if (flags & TF_DEFAULT_SAMPLE_SIZE)
+    if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
+      goto invalid_track;
+
+  if (flags & TF_DEFAULT_SAMPLE_FLAGS)
+    if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
+      goto invalid_track;
+
+  return TRUE;
+
+invalid_track:
+  {
+    GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
+    return FALSE;
+  }
+unknown_stream:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
+    return TRUE;
+  }
+}
+
+static gboolean
+qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
+    guint64 * decode_time)
+{
+  guint32 version = 0;
+
+  if (!gst_byte_reader_get_uint32_be (br, &version))
+    return FALSE;
+
+  version >>= 24;
+  if (version == 1) {
+    if (!gst_byte_reader_get_uint64_be (br, decode_time))
+      goto failed;
+  } else {
+    guint32 dec_time = 0;
+    if (!gst_byte_reader_get_uint32_be (br, &dec_time))
+      goto failed;
+    *decode_time = dec_time;
+  }
+
+  GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
+      *decode_time);
+
+  return TRUE;
+
+failed:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
+    return FALSE;
+  }
+}
+
+/* Returns a pointer to a GstStructure containing the properties of
+ * the stream sample identified by @sample_index. The caller must unref
+ * the returned object after use. Returns NULL if unsuccessful. */
+static GstStructure *
+qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, guint sample_index)
+{
+  QtDemuxCencSampleSetInfo *info = NULL;
+
+  g_return_val_if_fail (stream != NULL, NULL);
+  g_return_val_if_fail (stream->protected, NULL);
+  g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
+
+  info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
+
+  /* Currently, cenc properties for groups of samples are not supported, so
+   * simply return a copy of the default sample properties */
+  return gst_structure_copy (info->default_properties);
+}
+
+/* Parses the sizes of sample auxiliary information contained within a stream,
+ * as given in a saiz box. Returns array of sample_count guint8 size values,
+ * or NULL on failure */
+static guint8 *
+qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    GstByteReader * br, guint32 * sample_count)
+{
+  guint32 flags = 0;
+  guint8 *info_sizes;
+  guint8 default_info_size;
+
+  g_return_val_if_fail (qtdemux != NULL, NULL);
+  g_return_val_if_fail (stream != NULL, NULL);
+  g_return_val_if_fail (br != NULL, NULL);
+  g_return_val_if_fail (sample_count != NULL, NULL);
+
+  if (!gst_byte_reader_get_uint32_be (br, &flags))
+    return NULL;
+
+  if (flags & 0x1) {
+    /* aux_info_type and aux_info_type_parameter are ignored */
+    if (!gst_byte_reader_skip (br, 8))
+      return NULL;
+  }
+
+  if (!gst_byte_reader_get_uint8 (br, &default_info_size))
+    return NULL;
+  GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
+
+  if (!gst_byte_reader_get_uint32_be (br, sample_count))
+    return NULL;
+  GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
+
+
+  if (default_info_size == 0) {
+    if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
+      return NULL;
+    }
+  } else {
+    info_sizes = g_new (guint8, *sample_count);
+    memset (info_sizes, default_info_size, *sample_count);
+  }
+
+  return info_sizes;
+}
+
+/* Parses the offset of sample auxiliary information contained within a stream,
+ * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
+static gboolean
+qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
+    guint64 * offset)
+{
+  guint8 version = 0;
+  guint32 flags = 0;
+  guint32 aux_info_type = 0;
+  guint32 aux_info_type_parameter = 0;
+  guint32 entry_count;
+  guint32 off_32;
+  guint64 off_64;
+  const guint8 *aux_info_type_data = NULL;
+
+  g_return_val_if_fail (qtdemux != NULL, FALSE);
+  g_return_val_if_fail (stream != NULL, FALSE);
+  g_return_val_if_fail (br != NULL, FALSE);
+  g_return_val_if_fail (offset != NULL, FALSE);
+
+  if (!gst_byte_reader_get_uint8 (br, &version))
+    return FALSE;
+
+  if (!gst_byte_reader_get_uint24_be (br, &flags))
+    return FALSE;
+
+  if (flags & 0x1) {
+
+    if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
+      return FALSE;
+    aux_info_type = QT_FOURCC (aux_info_type_data);
+
+    if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
+      return FALSE;
+  } else if (stream->protected) {
+    aux_info_type = stream->protection_scheme_type;
+  } else {
+    aux_info_type = CUR_STREAM (stream)->fourcc;
+  }
+
+  if (info_type)
+    *info_type = aux_info_type;
+  if (info_type_parameter)
+    *info_type_parameter = aux_info_type_parameter;
+
+  GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
+      "aux_info_type_parameter:  %#06x",
+      GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
+
+  if (!gst_byte_reader_get_uint32_be (br, &entry_count))
+    return FALSE;
+
+  if (entry_count != 1) {
+    GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
+    return FALSE;
+  }
+
+  if (version == 0) {
+    if (!gst_byte_reader_get_uint32_be (br, &off_32))
+      return FALSE;
+    *offset = (guint64) off_32;
+  } else {
+    if (!gst_byte_reader_get_uint64_be (br, &off_64))
+      return FALSE;
+    *offset = off_64;
+  }
+
+  GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
+  return TRUE;
+}
+
+static void
+qtdemux_gst_structure_free (GstStructure * gststructure)
+{
+  if (gststructure) {
+    gst_structure_free (gststructure);
+  }
+}
+
+/* Parses auxiliary information relating to samples protected using Common
+ * Encryption (cenc); the format of this information is defined in
+ * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
+static gboolean
+qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
+{
+  QtDemuxCencSampleSetInfo *ss_info = NULL;
+  guint8 size;
+  gint i;
+  GPtrArray *old_crypto_info = NULL;
+  guint old_entries = 0;
+
+  g_return_val_if_fail (qtdemux != NULL, FALSE);
+  g_return_val_if_fail (stream != NULL, FALSE);
+  g_return_val_if_fail (br != NULL, FALSE);
+  g_return_val_if_fail (stream->protected, FALSE);
+  g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
+
+  ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
+
+  if (ss_info->crypto_info) {
+    old_crypto_info = ss_info->crypto_info;
+    /* Count number of non-null entries remaining at the tail end */
+    for (i = old_crypto_info->len - 1; i >= 0; i--) {
+      if (g_ptr_array_index (old_crypto_info, i) == NULL)
+        break;
+      old_entries++;
+    }
+  }
+
+  ss_info->crypto_info =
+      g_ptr_array_new_full (sample_count + old_entries,
+      (GDestroyNotify) qtdemux_gst_structure_free);
+
+  /* We preserve old entries because we parse the next moof in advance
+   * of consuming all samples from the previous moof, and otherwise
+   * we'd discard the corresponding crypto info for the samples
+   * from the previous fragment. */
+  if (old_entries) {
+    GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
+        old_entries);
+    for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
+      g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
+              i));
+      g_ptr_array_index (old_crypto_info, i) = NULL;
+    }
+  }
+
+  if (old_crypto_info) {
+    /* Everything now belongs to the new array */
+    g_ptr_array_free (old_crypto_info, TRUE);
+  }
+
+  for (i = 0; i < sample_count; ++i) {
+    GstStructure *properties;
+    guint16 n_subsamples = 0;
+    guint8 *data;
+    guint iv_size;
+    GstBuffer *buf;
+
+    properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
+    if (properties == NULL) {
+      GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
+      return FALSE;
+    }
+    if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
+      GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
+      gst_structure_free (properties);
+      return FALSE;
+    }
+    if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
+      GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
+      gst_structure_free (properties);
+      return FALSE;
+    }
+    buf = gst_buffer_new_wrapped (data, iv_size);
+    gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
+    gst_buffer_unref (buf);
+    size = info_sizes[i];
+    if (size > iv_size) {
+      if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
+          || !(n_subsamples > 0)) {
+        gst_structure_free (properties);
+        GST_ERROR_OBJECT (qtdemux,
+            "failed to get subsample count for sample %u", i);
+        return FALSE;
+      }
+      GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
+      if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
+        GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
+            i);
+        gst_structure_free (properties);
+        return FALSE;
+      }
+      buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
+      if (!buf) {
+        gst_structure_free (properties);
+        return FALSE;
+      }
+      gst_structure_set (properties,
+          "subsample_count", G_TYPE_UINT, n_subsamples,
+          "subsamples", GST_TYPE_BUFFER, buf, NULL);
+      gst_buffer_unref (buf);
+    } else {
+      gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
+    }
+    g_ptr_array_add (ss_info->crypto_info, properties);
+  }
+  return TRUE;
+}
+
+/* Converts a UUID in raw byte form to a string representation, as defined in
+ * RFC 4122. The caller takes ownership of the returned string and is
+ * responsible for freeing it after use. */
+static gchar *
+qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
+{
+  const guint8 *uuid = (const guint8 *) uuid_bytes;
+
+  return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+      "%02x%02x-%02x%02x%02x%02x%02x%02x",
+      uuid[0], uuid[1], uuid[2], uuid[3],
+      uuid[4], uuid[5], uuid[6], uuid[7],
+      uuid[8], uuid[9], uuid[10], uuid[11],
+      uuid[12], uuid[13], uuid[14], uuid[15]);
+}
+
+/* Parses a Protection System Specific Header box (pssh), as defined in the
+ * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
+ * information needed by a specific content protection system in order to
+ * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
+ * otherwise. */
+static gboolean
+qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
+{
+  gchar *sysid_string;
+  guint32 pssh_size = QT_UINT32 (node->data);
+  GstBuffer *pssh = NULL;
+  GstEvent *event = NULL;
+  guint32 parent_box_type;
+  gint i;
+
+  if (G_UNLIKELY (pssh_size < 32U)) {
+    GST_ERROR_OBJECT (qtdemux, "invalid box size");
+    return FALSE;
+  }
+
+  sysid_string =
+      qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
+
+  gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
+
+  pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
+  GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
+      gst_buffer_get_size (pssh));
+
+  parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
+
+  /* Push an event containing the pssh box onto the queues of all streams. */
+  event = gst_event_new_protection (sysid_string, pssh,
+      (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
+  for (i = 0; i < qtdemux->n_streams; ++i) {
+    g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
+        gst_event_ref (event));
+  }
+  g_free (sysid_string);
+  gst_event_unref (event);
+  gst_buffer_unref (pssh);
+  return TRUE;
+}
+
+static gboolean
+qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
+    guint64 moof_offset, QtDemuxStream * stream)
+{
+  GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
+  GNode *uuid_node;
+  GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
+  GNode *saiz_node, *saio_node, *pssh_node;
+  GstByteReader saiz_data, saio_data;
+  guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
+  gint64 base_offset, running_offset;
+  guint32 frag_num;
+
+  /* NOTE @stream ignored */
+
+  moof_node = g_node_new ((guint8 *) buffer);
+  qtdemux_parse_node (qtdemux, moof_node, buffer, length);
+  qtdemux_node_dump (qtdemux, moof_node);
+
+  /* Get fragment number from mfhd and check it's valid */
+  mfhd_node =
+      qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
+  if (mfhd_node == NULL)
+    goto missing_mfhd;
+  if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
+    goto fail;
+  GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
+
+  /* unknown base_offset to start with */
+  base_offset = running_offset = -1;
+  traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
+  while (traf_node) {
+    guint64 decode_time = 0;
+
+    /* Fragment Header node */
+    tfhd_node =
+        qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
+        &tfhd_data);
+    if (!tfhd_node)
+      goto missing_tfhd;
+    if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
+            &ds_size, &ds_flags, &base_offset))
+      goto missing_tfhd;
+
+    /* The following code assumes at most a single set of sample auxiliary
+     * data in the fragment (consisting of a saiz box and a corresponding saio
+     * box); in theory, however, there could be multiple sets of sample
+     * auxiliary data in a fragment. */
+    saiz_node =
+        qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
+        &saiz_data);
+    if (saiz_node) {
+      guint32 info_type = 0;
+      guint64 offset = 0;
+      guint32 info_type_parameter = 0;
+
+      g_free (qtdemux->cenc_aux_info_sizes);
+
+      qtdemux->cenc_aux_info_sizes =
+          qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
+          &qtdemux->cenc_aux_sample_count);
+      if (qtdemux->cenc_aux_info_sizes == NULL) {
+        GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
+        goto fail;
+      }
+      saio_node =
+          qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
+          &saio_data);
+      if (!saio_node) {
+        GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
+        g_free (qtdemux->cenc_aux_info_sizes);
+        qtdemux->cenc_aux_info_sizes = NULL;
+        goto fail;
+      }
+
+      if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
+                  &info_type, &info_type_parameter, &offset))) {
+        GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
+        g_free (qtdemux->cenc_aux_info_sizes);
+        qtdemux->cenc_aux_info_sizes = NULL;
+        goto fail;
+      }
+      if (base_offset > -1 && base_offset > qtdemux->moof_offset)
+        offset += (guint64) (base_offset - qtdemux->moof_offset);
+      if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
+        GstByteReader br;
+        if (offset > length) {
+          GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
+          qtdemux->cenc_aux_info_offset = offset;
+        } else {
+          gst_byte_reader_init (&br, buffer + offset, length - offset);
+          if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
+                  qtdemux->cenc_aux_info_sizes,
+                  qtdemux->cenc_aux_sample_count)) {
+            GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
+            g_free (qtdemux->cenc_aux_info_sizes);
+            qtdemux->cenc_aux_info_sizes = NULL;
+            goto fail;
+          }
+        }
+      }
+    }
+
+    tfdt_node =
+        qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
+        &tfdt_data);
+    if (tfdt_node) {
+      /* We'll use decode_time to interpolate timestamps
+       * in case the input timestamps are missing */
+      qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
+
+      GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
+          " (%" GST_TIME_FORMAT ")", decode_time,
+          GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
+                  decode_time) : GST_CLOCK_TIME_NONE));
+
+      /* Discard the fragment buffer timestamp info to avoid using it.
+       * Rely on tfdt instead as it is more accurate than the timestamp
+       * that is fetched from a manifest/playlist and is usually
+       * less accurate. */
+      qtdemux->fragment_start = -1;
+    }
+
+    if (G_UNLIKELY (!stream)) {
+      /* we lost track of offset, we'll need to regain it,
+       * but can delay complaining until later or avoid doing so altogether */
+      base_offset = -2;
+      goto next;
+    }
+    if (G_UNLIKELY (base_offset < -1))
+      goto lost_offset;
+
+    if (qtdemux->upstream_format_is_time)
+      gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
+
+    /* initialise moof sample data */
+    stream->n_samples_moof = 0;
+    stream->duration_last_moof = stream->duration_moof;
+    stream->duration_moof = 0;
+
+    /* Track Run node */
+    trun_node =
+        qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
+        &trun_data);
+    while (trun_node) {
+      qtdemux_parse_trun (qtdemux, &trun_data, stream,
+          ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
+          &running_offset, decode_time, (tfdt_node != NULL));
+      /* iterate all siblings */
+      trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
+          &trun_data);
+    }
+
+    uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
+    if (uuid_node) {
+      guint8 *uuid_buffer = (guint8 *) uuid_node->data;
+      guint32 box_length = QT_UINT32 (uuid_buffer);
+
+      qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
+    }
+
+    /* if no new base_offset provided for next traf,
+     * base is end of current traf */
+    base_offset = running_offset;
+    running_offset = -1;
+
+    if (stream->n_samples_moof && stream->duration_moof)
+      stream->new_caps = TRUE;
+
+  next:
+    /* iterate all siblings */
+    traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
+  }
+
+  /* parse any protection system info */
+  pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
+  while (pssh_node) {
+    GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
+    qtdemux_parse_pssh (qtdemux, pssh_node);
+    pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
+  }
+
+  g_node_destroy (moof_node);
+  return TRUE;
+
+missing_tfhd:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
+    goto fail;
+  }
+missing_mfhd:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
+    goto fail;
+  }
+lost_offset:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "lost offset");
+    goto fail;
+  }
+fail:
+  {
+    g_node_destroy (moof_node);
+    GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
+        (_("This file is corrupt and cannot be played.")), (NULL));
+    return FALSE;
+  }
+}
+
+#if 0
+/* might be used if some day we actually use mfra & co
+ * for random access to fragments,
+ * but that will require quite some modifications and much less relying
+ * on a sample array */
+#endif
+
+static gboolean
+qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
+{
+  QtDemuxStream *stream;
+  guint32 ver_flags, track_id, len, num_entries, i;
+  guint value_size, traf_size, trun_size, sample_size;
+  guint64 time = 0, moof_offset = 0;
+#if 0
+  GstBuffer *buf = NULL;
+  GstFlowReturn ret;
+#endif
+  GstByteReader tfra;
+
+  gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
+
+  if (!gst_byte_reader_skip (&tfra, 8))
+    return FALSE;
+
+  if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
+    return FALSE;
+
+  if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
+      || !gst_byte_reader_get_uint32_be (&tfra, &len)
+      || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
+    return FALSE;
+
+  GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
+
+  stream = qtdemux_find_stream (qtdemux, track_id);
+  if (stream == NULL)
+    goto unknown_trackid;
+
+  value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
+  sample_size = (len & 3) + 1;
+  trun_size = ((len & 12) >> 2) + 1;
+  traf_size = ((len & 48) >> 4) + 1;
+
+  GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
+      "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
+
+  if (num_entries == 0)
+    goto no_samples;
+
+  if (!qt_atom_parser_has_chunks (&tfra, num_entries,
+          value_size + value_size + traf_size + trun_size + sample_size))
+    goto corrupt_file;
+
+  g_free (stream->ra_entries);
+  stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
+  stream->n_ra_entries = num_entries;
+
+  for (i = 0; i < num_entries; i++) {
+    qt_atom_parser_get_offset (&tfra, value_size, &time);
+    qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
+    qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
+    qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
+    qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
+
+    time = QTSTREAMTIME_TO_GSTTIME (stream, time);
+
+    GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
+        " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
+
+    stream->ra_entries[i].ts = time;
+    stream->ra_entries[i].moof_offset = moof_offset;
+
+    /* don't want to go through the entire file and read all moofs at startup */
+#if 0
+    ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
+    if (ret != GST_FLOW_OK)
+      goto corrupt_file;
+    qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
+        moof_offset, stream);
+    gst_buffer_unref (buf);
+#endif
+  }
+
+  check_update_duration (qtdemux, time);
+
+  return TRUE;
+
+/* ERRORS */
+unknown_trackid:
+  {
+    GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
+    return FALSE;
+  }
+corrupt_file:
+  {
+    GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
+    return FALSE;
+  }
+no_samples:
+  {
+    GST_WARNING_OBJECT (qtdemux, "stream has no samples");
+    return FALSE;
+  }
+}
+
+static gboolean
+qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
+{
+  GstMapInfo mfro_map = GST_MAP_INFO_INIT;
+  GstMapInfo mfra_map = GST_MAP_INFO_INIT;
+  GstBuffer *mfro = NULL, *mfra = NULL;
+  GstFlowReturn flow;
+  gboolean ret = FALSE;
+  GNode *mfra_node, *tfra_node;
+  guint64 mfra_offset = 0;
+  guint32 fourcc, mfra_size;
+  gint64 len;
+
+  /* query upstream size in bytes */
+  if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
+    goto size_query_failed;
+
+  /* mfro box should be at the very end of the file */
+  flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
+  if (flow != GST_FLOW_OK)
+    goto exit;
+
+  gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
+
+  fourcc = QT_FOURCC (mfro_map.data + 4);
+  if (fourcc != FOURCC_mfro)
+    goto exit;
+
+  GST_INFO_OBJECT (qtdemux, "Found mfro box");
+  if (mfro_map.size < 16)
+    goto invalid_mfro_size;
+
+  mfra_size = QT_UINT32 (mfro_map.data + 12);
+  if (mfra_size >= len)
+    goto invalid_mfra_size;
+
+  mfra_offset = len - mfra_size;
+
+  GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
+      mfra_offset, mfra_size);
+
+  /* now get and parse mfra box */
+  flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
+  if (flow != GST_FLOW_OK)
+    goto broken_file;
+
+  gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
+
+  mfra_node = g_node_new ((guint8 *) mfra_map.data);
+  qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
+
+  tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
+
+  while (tfra_node) {
+    qtdemux_parse_tfra (qtdemux, tfra_node);
+    /* iterate all siblings */
+    tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
+  }
+  g_node_destroy (mfra_node);
+
+  GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
+  ret = TRUE;
+
+exit:
+
+  if (mfro) {
+    if (mfro_map.memory != NULL)
+      gst_buffer_unmap (mfro, &mfro_map);
+    gst_buffer_unref (mfro);
+  }
+  if (mfra) {
+    if (mfra_map.memory != NULL)
+      gst_buffer_unmap (mfra, &mfra_map);
+    gst_buffer_unref (mfra);
+  }
+  return ret;
+
+/* ERRORS */
+size_query_failed:
+  {
+    GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
+    goto exit;
+  }
+invalid_mfro_size:
+  {
+    GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
+    goto exit;
+  }
+invalid_mfra_size:
+  {
+    GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
+    goto exit;
+  }
+broken_file:
+  {
+    GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
+    goto exit;
+  }
+}
+
+static guint64
+add_offset (guint64 offset, guint64 advance)
+{
+  /* Avoid 64-bit overflow by clamping */
+  if (offset > G_MAXUINT64 - advance)
+    return G_MAXUINT64;
+  return offset + advance;
+}
+
+static GstFlowReturn
+gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
+{
+  guint64 length = 0;
+  guint32 fourcc = 0;
+  GstBuffer *buf = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint64 cur_offset = qtdemux->offset;
+  GstMapInfo map;
+
+  ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
+  if (G_UNLIKELY (ret != GST_FLOW_OK))
+    goto beach;
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  if (G_LIKELY (map.size >= 8))
+    extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+
+  /* maybe we already got most we needed, so only consider this eof */
+  if (G_UNLIKELY (length == 0)) {
+    GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
+        (_("Invalid atom size.")),
+        ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
+            GST_FOURCC_ARGS (fourcc)));
+    ret = GST_FLOW_EOS;
+    goto beach;
+  }
+
+  switch (fourcc) {
+    case FOURCC_moof:
+      /* record for later parsing when needed */
+      if (!qtdemux->moof_offset) {
+        qtdemux->moof_offset = qtdemux->offset;
+      }
+      if (qtdemux_pull_mfro_mfra (qtdemux)) {
+        /* FIXME */
+      } else {
+        qtdemux->offset += length;      /* skip moof and keep going */
+      }
+      if (qtdemux->got_moov) {
+        GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
+        ret = GST_FLOW_EOS;
+        goto beach;
+      }
+      break;
+    case FOURCC_mdat:
+    case FOURCC_free:
+    case FOURCC_skip:
+    case FOURCC_wide:
+    case FOURCC_PICT:
+    case FOURCC_pnot:
+    {
+      GST_LOG_OBJECT (qtdemux,
+          "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
+          GST_FOURCC_ARGS (fourcc), cur_offset);
+      qtdemux->offset = add_offset (qtdemux->offset, length);
+      break;
+    }
+    case FOURCC_moov:
+    {
+      GstBuffer *moov = NULL;
+
+      if (qtdemux->got_moov) {
+        GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
+        qtdemux->offset = add_offset (qtdemux->offset, length);
+        goto beach;
+      }
+
+      ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
+      if (ret != GST_FLOW_OK)
+        goto beach;
+      gst_buffer_map (moov, &map, GST_MAP_READ);
+
+      if (length != map.size) {
+        /* Some files have a 'moov' atom at the end of the file which contains
+         * a terminal 'free' atom where the body of the atom is missing.
+         * Check for, and permit, this special case.
+         */
+        if (map.size >= 8) {
+          guint8 *final_data = map.data + (map.size - 8);
+          guint32 final_length = QT_UINT32 (final_data);
+          guint32 final_fourcc = QT_FOURCC (final_data + 4);
+
+          if (final_fourcc == FOURCC_free
+              && map.size + final_length - 8 == length) {
+            /* Ok, we've found that special case. Allocate a new buffer with
+             * that free atom actually present. */
+            GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
+            gst_buffer_fill (newmoov, 0, map.data, map.size);
+            gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
+            gst_buffer_unmap (moov, &map);
+            gst_buffer_unref (moov);
+            moov = newmoov;
+            gst_buffer_map (moov, &map, GST_MAP_READ);
+          }
+        }
+      }
+
+      if (length != map.size) {
+        GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
+            (_("This file is incomplete and cannot be played.")),
+            ("We got less than expected (received %" G_GSIZE_FORMAT
+                ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
+                (guint) length, cur_offset));
+        gst_buffer_unmap (moov, &map);
+        gst_buffer_unref (moov);
+        ret = GST_FLOW_ERROR;
+        goto beach;
+      }
+      qtdemux->offset += length;
+
+      qtdemux_parse_moov (qtdemux, map.data, length);
+      qtdemux_node_dump (qtdemux, qtdemux->moov_node);
+
+      qtdemux_parse_tree (qtdemux);
+      if (qtdemux->moov_node_compressed) {
+        g_node_destroy (qtdemux->moov_node_compressed);
+        g_free (qtdemux->moov_node->data);
+      }
+      qtdemux->moov_node_compressed = NULL;
+      g_node_destroy (qtdemux->moov_node);
+      qtdemux->moov_node = NULL;
+      gst_buffer_unmap (moov, &map);
+      gst_buffer_unref (moov);
+      qtdemux->got_moov = TRUE;
+
+      break;
+    }
+    case FOURCC_ftyp:
+    {
+      GstBuffer *ftyp = NULL;
+
+      /* extract major brand; might come in handy for ISO vs QT issues */
+      ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
+      if (ret != GST_FLOW_OK)
+        goto beach;
+      qtdemux->offset += length;
+      gst_buffer_map (ftyp, &map, GST_MAP_READ);
+      qtdemux_parse_ftyp (qtdemux, map.data, map.size);
+      gst_buffer_unmap (ftyp, &map);
+      gst_buffer_unref (ftyp);
+      break;
+    }
+    case FOURCC_uuid:
+    {
+      GstBuffer *uuid = NULL;
+
+      /* uuid are extension atoms */
+      ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
+      if (ret != GST_FLOW_OK)
+        goto beach;
+      qtdemux->offset += length;
+      gst_buffer_map (uuid, &map, GST_MAP_READ);
+      qtdemux_parse_uuid (qtdemux, map.data, map.size);
+      gst_buffer_unmap (uuid, &map);
+      gst_buffer_unref (uuid);
+      break;
+    }
+    case FOURCC_sidx:
+    {
+      GstBuffer *sidx = NULL;
+      ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
+      if (ret != GST_FLOW_OK)
+        goto beach;
+      qtdemux->offset += length;
+      gst_buffer_map (sidx, &map, GST_MAP_READ);
+      qtdemux_parse_sidx (qtdemux, map.data, map.size);
+      gst_buffer_unmap (sidx, &map);
+      gst_buffer_unref (sidx);
+      break;
+    }
+    default:
+    {
+      GstBuffer *unknown = NULL;
+
+      GST_LOG_OBJECT (qtdemux,
+          "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
+          " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
+          cur_offset);
+      ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
+      if (ret != GST_FLOW_OK)
+        goto beach;
+      gst_buffer_map (unknown, &map, GST_MAP_READ);
+      GST_MEMDUMP ("Unknown tag", map.data, map.size);
+      gst_buffer_unmap (unknown, &map);
+      gst_buffer_unref (unknown);
+      qtdemux->offset += length;
+      break;
+    }
+  }
+
+beach:
+  if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
+    /* digested all data, show what we have */
+    qtdemux_prepare_streams (qtdemux);
+    ret = qtdemux_expose_streams (qtdemux);
+
+    qtdemux->state = QTDEMUX_STATE_MOVIE;
+    GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
+        qtdemux->state);
+    return ret;
+  }
+  return ret;
+}
+
+/* Seeks to the previous keyframe of the indexed stream and
+ * aligns other streams with respect to the keyframe timestamp
+ * of indexed stream. Only called in case of Reverse Playback
+ */
+static GstFlowReturn
+gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
+{
+  guint8 n = 0;
+  guint32 seg_idx = 0, k_index = 0;
+  guint32 ref_seg_idx, ref_k_index;
+  GstClockTime k_pos = 0, last_stop = 0;
+  QtDemuxSegment *seg = NULL;
+  QtDemuxStream *ref_str = NULL;
+  guint64 seg_media_start_mov;  /* segment media start time in mov format */
+  guint64 target_ts;
+
+  /* Now we choose an arbitrary stream, get the previous keyframe timestamp
+   * and finally align all the other streams on that timestamp with their
+   * respective keyframes */
+  for (n = 0; n < qtdemux->n_streams; n++) {
+    QtDemuxStream *str = qtdemux->streams[n];
+
+    /* No candidate yet, take the first stream */
+    if (!ref_str) {
+      ref_str = str;
+      continue;
+    }
+
+    /* So that stream has a segment, we prefer video streams */
+    if (str->subtype == FOURCC_vide) {
+      ref_str = str;
+      break;
+    }
+  }
+
+  if (G_UNLIKELY (!ref_str)) {
+    GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
+    goto eos;
+  }
+
+  if (G_UNLIKELY (!ref_str->from_sample)) {
+    GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
+    goto eos;
+  }
+
+  /* So that stream has been playing from from_sample to to_sample. We will
+   * get the timestamp of the previous sample and search for a keyframe before
+   * that. For audio streams we do an arbitrary jump in the past (10 samples) */
+  if (ref_str->subtype == FOURCC_vide) {
+    k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
+        ref_str->from_sample - 1, FALSE);
+  } else {
+    if (ref_str->from_sample >= 10)
+      k_index = ref_str->from_sample - 10;
+    else
+      k_index = 0;
+  }
+
+  target_ts =
+      ref_str->samples[k_index].timestamp +
+      ref_str->samples[k_index].pts_offset;
+
+  /* get current segment for that stream */
+  seg = &ref_str->segments[ref_str->segment_index];
+  /* Use segment start in original timescale for comparisons */
+  seg_media_start_mov = seg->trak_media_start;
+
+  GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
+      " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
+      k_index, target_ts, seg_media_start_mov,
+      GST_TIME_ARGS (seg->media_start));
+
+  /* Crawl back through segments to find the one containing this I frame */
+  while (target_ts < seg_media_start_mov) {
+    GST_DEBUG_OBJECT (qtdemux,
+        "keyframe position (sample %u) is out of segment %u " " target %"
+        G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
+        ref_str->segment_index, target_ts, seg_media_start_mov);
+
+    if (G_UNLIKELY (!ref_str->segment_index)) {
+      /* Reached first segment, let's consider it's EOS */
+      goto eos;
+    }
+    ref_str->segment_index--;
+    seg = &ref_str->segments[ref_str->segment_index];
+    /* Use segment start in original timescale for comparisons */
+    seg_media_start_mov = seg->trak_media_start;
+  }
+  /* Calculate time position of the keyframe and where we should stop */
+  k_pos =
+      QTSTREAMTIME_TO_GSTTIME (ref_str,
+      target_ts - seg->trak_media_start) + seg->time;
+  last_stop =
+      QTSTREAMTIME_TO_GSTTIME (ref_str,
+      ref_str->samples[ref_str->from_sample].timestamp -
+      seg->trak_media_start) + seg->time;
+
+  GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
+      "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
+      k_index, GST_TIME_ARGS (k_pos));
+
+  /* Set last_stop with the keyframe timestamp we pushed of that stream */
+  qtdemux->segment.position = last_stop;
+  GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (last_stop));
+
+  if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
+    GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
+    goto eos;
+  }
+
+  ref_seg_idx = ref_str->segment_index;
+  ref_k_index = k_index;
+
+  /* Align them all on this */
+  for (n = 0; n < qtdemux->n_streams; n++) {
+    guint32 index = 0;
+    GstClockTime seg_time = 0;
+    QtDemuxStream *str = qtdemux->streams[n];
+
+    /* aligning reference stream again might lead to backing up to yet another
+     * keyframe (due to timestamp rounding issues),
+     * potentially putting more load on downstream; so let's try to avoid */
+    if (str == ref_str) {
+      seg_idx = ref_seg_idx;
+      seg = &str->segments[seg_idx];
+      k_index = ref_k_index;
+      GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
+          "sample at index %d", n, ref_str->segment_index, k_index);
+    } else {
+      seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
+      GST_DEBUG_OBJECT (qtdemux,
+          "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
+          seg_idx, GST_TIME_ARGS (k_pos));
+
+      /* get segment and time in the segment */
+      seg = &str->segments[seg_idx];
+      seg_time = k_pos - seg->time;
+
+      /* get the media time in the segment.
+       * No adjustment for empty "filler" segments */
+      if (seg->media_start != GST_CLOCK_TIME_NONE)
+        seg_time += seg->media_start;
+
+      /* get the index of the sample with media time */
+      index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
+      GST_DEBUG_OBJECT (qtdemux,
+          "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
+          GST_TIME_ARGS (seg_time), index);
+
+      /* find previous keyframe */
+      k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
+    }
+
+    /* Remember until where we want to go */
+    str->to_sample = str->from_sample - 1;
+    /* Define our time position */
+    target_ts =
+        str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
+    str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
+    if (seg->media_start != GST_CLOCK_TIME_NONE)
+      str->time_position -= seg->media_start;
+
+    /* Now seek back in time */
+    gst_qtdemux_move_stream (qtdemux, str, k_index);
+    GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
+        GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
+        GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
+  }
+
+  return GST_FLOW_OK;
+
+eos:
+  return GST_FLOW_EOS;
+}
+
+/*
+ * Gets the current qt segment start, stop and position for the
+ * given time offset. This is used in update_segment()
+ */
+static void
+gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, GstClockTime offset,
+    GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
+{
+  GstClockTime seg_time;
+  GstClockTime start, stop, time;
+  QtDemuxSegment *segment;
+
+  segment = &stream->segments[stream->segment_index];
+
+  /* get time in this segment */
+  seg_time = (offset - segment->time) * segment->rate;
+
+  GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (seg_time));
+
+  if (G_UNLIKELY (seg_time > segment->duration)) {
+    GST_LOG_OBJECT (stream->pad,
+        "seg_time > segment->duration %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (segment->duration));
+    seg_time = segment->duration;
+  }
+
+  /* qtdemux->segment.stop is in outside-time-realm, whereas
+   * segment->media_stop is in track-time-realm.
+   *
+   * In order to compare the two, we need to bring segment.stop
+   * into the track-time-realm
+   *
+   * FIXME - does this comment still hold? Don't see any conversion here */
+
+  stop = qtdemux->segment.stop;
+  if (stop == GST_CLOCK_TIME_NONE)
+    stop = qtdemux->segment.duration;
+  if (stop == GST_CLOCK_TIME_NONE)
+    stop = segment->media_stop;
+  else
+    stop =
+        MIN (segment->media_stop, stop - segment->time + segment->media_start);
+
+  if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
+    start = segment->time + seg_time;
+    time = offset;
+    stop = start - seg_time + segment->duration;
+  } else if (qtdemux->segment.rate >= 0) {
+    start = MIN (segment->media_start + seg_time, stop);
+    time = offset;
+  } else {
+    if (segment->media_start >= qtdemux->segment.start) {
+      time = segment->time;
+    } else {
+      time = segment->time + (qtdemux->segment.start - segment->media_start);
+    }
+
+    start = MAX (segment->media_start, qtdemux->segment.start);
+    stop = MIN (segment->media_start + seg_time, stop);
+  }
+
+  *_start = start;
+  *_stop = stop;
+  *_time = time;
+}
+
+/*
+ * Updates the qt segment used for the stream and pushes a new segment event
+ * downstream on this stream's pad.
+ */
+static gboolean
+gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    gint seg_idx, GstClockTime offset, GstClockTime * _start,
+    GstClockTime * _stop)
+{
+  QtDemuxSegment *segment;
+  GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
+  gdouble rate;
+  GstEvent *event;
+
+  /* update the current segment */
+  stream->segment_index = seg_idx;
+
+  /* get the segment */
+  segment = &stream->segments[seg_idx];
+
+  if (G_UNLIKELY (offset < segment->time)) {
+    GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (segment->time));
+    return FALSE;
+  }
+
+  /* segment lies beyond total indicated duration */
+  if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
+          segment->time > qtdemux->segment.duration)) {
+    GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
+        " < segment->time %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (qtdemux->segment.duration),
+        GST_TIME_ARGS (segment->time));
+    return FALSE;
+  }
+
+  gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
+      &start, &stop, &time);
+
+  GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
+      " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
+      GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
+
+  /* combine global rate with that of the segment */
+  rate = segment->rate * qtdemux->segment.rate;
+
+  /* Copy flags from main segment */
+  stream->segment.flags = qtdemux->segment.flags;
+
+  /* update the segment values used for clipping */
+  stream->segment.offset = qtdemux->segment.offset;
+  stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
+  stream->segment.applied_rate = qtdemux->segment.applied_rate;
+  stream->segment.rate = rate;
+  stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
+      stream->cslg_shift);
+  stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
+      stream->cslg_shift);
+  stream->segment.time = time;
+  stream->segment.position = stream->segment.start;
+
+  GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
+      &stream->segment);
+
+  /* now prepare and send the segment */
+  if (stream->pad) {
+    event = gst_event_new_segment (&stream->segment);
+    if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
+      gst_event_set_seqnum (event, qtdemux->segment_seqnum);
+    }
+    gst_pad_push_event (stream->pad, event);
+    /* assume we can send more data now */
+    GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
+    /* clear to send tags on this pad now */
+    gst_qtdemux_push_tags (qtdemux, stream);
+  }
+
+  if (_start)
+    *_start = start;
+  if (_stop)
+    *_stop = stop;
+
+  return TRUE;
+}
+
+/* activate the given segment number @seg_idx of @stream at time @offset.
+ * @offset is an absolute global position over all the segments.
+ *
+ * This will push out a NEWSEGMENT event with the right values and
+ * position the stream index to the first decodable sample before
+ * @offset.
+ */
+static gboolean
+gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    guint32 seg_idx, GstClockTime offset)
+{
+  QtDemuxSegment *segment;
+  guint32 index, kf_index;
+  GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
+
+  GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
+      seg_idx, GST_TIME_ARGS (offset));
+
+  if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
+          &start, &stop))
+    return FALSE;
+
+  segment = &stream->segments[stream->segment_index];
+
+  /* in the fragmented case, we pick a fragment that starts before our
+   * desired position and rely on downstream to wait for a keyframe
+   * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
+   * tfra entries tells us which trun/sample the key unit is in, but we don't
+   * make use of this additional information at the moment) */
+  if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
+    stream->to_sample = G_MAXUINT32;
+    return TRUE;
+  } else {
+    /* well, it will be taken care of below */
+    qtdemux->fragmented_seek_pending = FALSE;
+    /* FIXME ideally the do_fragmented_seek can be done right here,
+     * rather than at loop level
+     * (which might even allow handling edit lists in a fragmented file) */
+  }
+
+  /* We don't need to look for a sample in push-based */
+  if (!qtdemux->pullbased)
+    return TRUE;
+
+  /* and move to the keyframe before the indicated media time of the
+   * segment */
+  if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
+    if (qtdemux->segment.rate >= 0) {
+      index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
+      stream->to_sample = G_MAXUINT32;
+      GST_DEBUG_OBJECT (stream->pad,
+          "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
+          GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
+          GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
+    } else {
+      index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
+      stream->to_sample = index;
+      GST_DEBUG_OBJECT (stream->pad,
+          "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
+          GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
+          GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
+    }
+  } else {
+    GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
+        "this is an empty segment");
+    return TRUE;
+  }
+
+  /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
+   * encountered an error and printed a message so we return appropriately */
+  if (index == -1)
+    return FALSE;
+
+  /* we're at the right spot */
+  if (index == stream->sample_index) {
+    GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
+    return TRUE;
+  }
+
+  /* find keyframe of the target index */
+  kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
+
+/* *INDENT-OFF* */
+/* indent does stupid stuff with stream->samples[].timestamp */
+
+  /* if we move forwards, we don't have to go back to the previous
+   * keyframe since we already sent that. We can also just jump to
+   * the keyframe right before the target index if there is one. */
+  if (index > stream->sample_index) {
+    /* moving forwards check if we move past a keyframe */
+    if (kf_index > stream->sample_index) {
+      GST_DEBUG_OBJECT (stream->pad,
+           "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
+           GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
+           GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
+      gst_qtdemux_move_stream (qtdemux, stream, kf_index);
+    } else {
+      GST_DEBUG_OBJECT (stream->pad,
+          "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
+          GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
+          GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
+    }
+  } else {
+    GST_DEBUG_OBJECT (stream->pad,
+        "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
+        GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
+        GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
+    gst_qtdemux_move_stream (qtdemux, stream, kf_index);
+  }
+
+/* *INDENT-ON* */
+
+  return TRUE;
+}
+
+/* prepare to get the current sample of @stream, getting essential values.
+ *
+ * This function will also prepare and send the segment when needed.
+ *
+ * Return FALSE if the stream is EOS.
+ *
+ * PULL-BASED
+ */
+static gboolean
+gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
+    GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
+    gboolean * keyframe)
+{
+  QtDemuxSample *sample;
+  GstClockTime time_position;
+  guint32 seg_idx;
+
+  g_return_val_if_fail (stream != NULL, FALSE);
+
+  time_position = stream->time_position;
+  if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
+    goto eos;
+
+  seg_idx = stream->segment_index;
+  if (G_UNLIKELY (seg_idx == -1)) {
+    /* find segment corresponding to time_position if we are looking
+     * for a segment. */
+    seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
+  }
+
+  /* different segment, activate it, sample_index will be set. */
+  if (G_UNLIKELY (stream->segment_index != seg_idx))
+    gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
+
+  if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
+                  segment_index]))) {
+    QtDemuxSegment *seg = &stream->segments[stream->segment_index];
+
+    GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
+        " prepare empty sample");
+
+    *empty = TRUE;
+    *pts = *dts = time_position;
+    *duration = seg->duration - (time_position - seg->time);
+
+    return TRUE;
+  }
+
+  *empty = FALSE;
+
+  if (stream->sample_index == -1)
+    stream->sample_index = 0;
+
+  GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
+      stream->sample_index, stream->n_samples);
+
+  if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
+    if (!qtdemux->fragmented)
+      goto eos;
+
+    GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
+    do {
+      GstFlowReturn flow;
+
+      GST_OBJECT_LOCK (qtdemux);
+      flow = qtdemux_add_fragmented_samples (qtdemux);
+      GST_OBJECT_UNLOCK (qtdemux);
+
+      if (flow != GST_FLOW_OK)
+        goto eos;
+    }
+    while (stream->sample_index >= stream->n_samples);
+  }
+
+  if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
+    GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
+        stream->sample_index);
+    return FALSE;
+  }
+
+  /* now get the info for the sample we're at */
+  sample = &stream->samples[stream->sample_index];
+
+  *dts = QTSAMPLE_DTS (stream, sample);
+  *pts = QTSAMPLE_PTS (stream, sample);
+  *offset = sample->offset;
+  *size = sample->size;
+  *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
+  *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
+
+  return TRUE;
+
+  /* special cases */
+eos:
+  {
+    stream->time_position = GST_CLOCK_TIME_NONE;
+    return FALSE;
+  }
+}
+
+/* move to the next sample in @stream.
+ *
+ * Moves to the next segment when needed.
+ */
+static void
+gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
+{
+  QtDemuxSample *sample;
+  QtDemuxSegment *segment;
+
+  /* get current segment */
+  segment = &stream->segments[stream->segment_index];
+
+  if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
+    GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
+    goto next_segment;
+  }
+
+  if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
+    /* Mark the stream as EOS */
+    GST_DEBUG_OBJECT (qtdemux,
+        "reached max allowed sample %u, mark EOS", stream->to_sample);
+    stream->time_position = GST_CLOCK_TIME_NONE;
+    return;
+  }
+
+  /* move to next sample */
+  stream->sample_index++;
+  stream->offset_in_sample = 0;
+
+  /* reached the last sample, we need the next segment */
+  if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
+    goto next_segment;
+
+  if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
+    GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
+        stream->sample_index);
+    return;
+  }
+
+  /* get next sample */
+  sample = &stream->samples[stream->sample_index];
+
+  /* see if we are past the segment */
+  if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
+    goto next_segment;
+
+  if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
+    /* inside the segment, update time_position, looks very familiar to
+     * GStreamer segments, doesn't it? */
+    stream->time_position =
+        QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
+  } else {
+    /* not yet in segment, time does not yet increment. This means
+     * that we are still prerolling keyframes to the decoder so it can
+     * decode the first sample of the segment. */
+    stream->time_position = segment->time;
+  }
+  return;
+
+  /* move to the next segment */
+next_segment:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
+
+    if (stream->segment_index == stream->n_segments - 1) {
+      /* are we at the end of the last segment, we're EOS */
+      stream->time_position = GST_CLOCK_TIME_NONE;
+    } else {
+      /* else we're only at the end of the current segment */
+      stream->time_position = segment->stop_time;
+    }
+    /* make sure we select a new segment */
+
+    /* accumulate previous segments */
+    if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
+      stream->accumulated_base +=
+          (stream->segment.stop -
+          stream->segment.start) / ABS (stream->segment.rate);
+
+    stream->segment_index = -1;
+  }
+}
+
+static void
+gst_qtdemux_sync_streams (GstQTDemux * demux)
+{
+  gint i;
+
+  if (demux->n_streams <= 1)
+    return;
+
+  for (i = 0; i < demux->n_streams; i++) {
+    QtDemuxStream *stream;
+    GstClockTime end_time;
+
+    stream = demux->streams[i];
+
+    if (!stream->pad)
+      continue;
+
+    /* TODO advance time on subtitle streams here, if any some day */
+
+    /* some clips/trailers may have unbalanced streams at the end,
+     * so send EOS on shorter stream to prevent stalling others */
+
+    /* do not mess with EOS if SEGMENT seeking */
+    if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
+      continue;
+
+    if (demux->pullbased) {
+      /* loop mode is sample time based */
+      if (!STREAM_IS_EOS (stream))
+        continue;
+    } else {
+      /* push mode is byte position based */
+      if (stream->n_samples &&
+          stream->samples[stream->n_samples - 1].offset >= demux->offset)
+        continue;
+    }
+
+    if (stream->sent_eos)
+      continue;
+
+    /* only act if some gap */
+    end_time = stream->segments[stream->n_segments - 1].stop_time;
+    GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
+        ", stream end: %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
+    if (GST_CLOCK_TIME_IS_VALID (end_time)
+        && (end_time + 2 * GST_SECOND < demux->segment.position)) {
+      GstEvent *event;
+
+      GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
+          GST_PAD_NAME (stream->pad));
+      stream->sent_eos = TRUE;
+      event = gst_event_new_eos ();
+      if (demux->segment_seqnum != GST_SEQNUM_INVALID)
+        gst_event_set_seqnum (event, demux->segment_seqnum);
+      gst_pad_push_event (stream->pad, event);
+    }
+  }
+}
+
+/* EOS and NOT_LINKED need to be combined. This means that we return:
+ *
+ *  GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
+ *  GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
+ */
+static GstFlowReturn
+gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
+    GstFlowReturn ret)
+{
+  GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
+
+  if (stream->pad)
+    ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
+        ret);
+  else
+    ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
+
+  GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
+  return ret;
+}
+
+/* the input buffer metadata must be writable. Returns NULL when the buffer is
+ * completely clipped
+ *
+ * Should be used only with raw buffers */
+static GstBuffer *
+gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    GstBuffer * buf)
+{
+  guint64 start, stop, cstart, cstop, diff;
+  GstClockTime pts, duration;
+  gsize size, osize;
+  gint num_rate, denom_rate;
+  gint frame_size;
+  gboolean clip_data;
+  guint offset;
+
+  osize = size = gst_buffer_get_size (buf);
+  offset = 0;
+
+  /* depending on the type, setup the clip parameters */
+  if (stream->subtype == FOURCC_soun) {
+    frame_size = CUR_STREAM (stream)->bytes_per_frame;
+    num_rate = GST_SECOND;
+    denom_rate = (gint) CUR_STREAM (stream)->rate;
+    clip_data = TRUE;
+  } else if (stream->subtype == FOURCC_vide) {
+    frame_size = size;
+    num_rate = CUR_STREAM (stream)->fps_n;
+    denom_rate = CUR_STREAM (stream)->fps_d;
+    clip_data = FALSE;
+  } else
+    goto wrong_type;
+
+  if (frame_size <= 0)
+    goto bad_frame_size;
+
+  /* we can only clip if we have a valid pts */
+  pts = GST_BUFFER_PTS (buf);
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
+    goto no_pts;
+
+  duration = GST_BUFFER_DURATION (buf);
+
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
+    duration =
+        gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
+  }
+
+  start = pts;
+  stop = start + duration;
+
+  if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
+              GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
+    goto clipped;
+
+  /* see if some clipping happened */
+  diff = cstart - start;
+  if (diff > 0) {
+    pts += diff;
+    duration -= diff;
+
+    if (clip_data) {
+      /* bring clipped time to samples and to bytes */
+      diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
+      diff *= frame_size;
+
+      GST_DEBUG_OBJECT (qtdemux,
+          "clipping start to %" GST_TIME_FORMAT " %"
+          G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
+
+      offset = diff;
+      size -= diff;
+    }
+  }
+  diff = stop - cstop;
+  if (diff > 0) {
+    duration -= diff;
+
+    if (clip_data) {
+      /* bring clipped time to samples and then to bytes */
+      diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
+      diff *= frame_size;
+      GST_DEBUG_OBJECT (qtdemux,
+          "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
+          " bytes", GST_TIME_ARGS (cstop), diff);
+      size -= diff;
+    }
+  }
+
+  if (offset != 0 || size != osize)
+    gst_buffer_resize (buf, offset, size);
+
+  GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
+  GST_BUFFER_PTS (buf) = pts;
+  GST_BUFFER_DURATION (buf) = duration;
+
+  return buf;
+
+  /* dropped buffer */
+wrong_type:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
+    return buf;
+  }
+bad_frame_size:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "bad frame size");
+    return buf;
+  }
+no_pts:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
+    return buf;
+  }
+clipped:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
+    gst_buffer_unref (buf);
+    return NULL;
+  }
+}
+
+static GstBuffer *
+gst_qtdemux_align_buffer (GstQTDemux * demux,
+    GstBuffer * buffer, gsize alignment)
+{
+  GstMapInfo map;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  if (map.size < sizeof (guintptr)) {
+    gst_buffer_unmap (buffer, &map);
+    return buffer;
+  }
+
+  if (((guintptr) map.data) & (alignment - 1)) {
+    GstBuffer *new_buffer;
+    GstAllocationParams params = { 0, alignment - 1, 0, 0, };
+
+    new_buffer = gst_buffer_new_allocate (NULL,
+        gst_buffer_get_size (buffer), &params);
+
+    /* Copy data "by hand", so ensure alignment is kept: */
+    gst_buffer_fill (new_buffer, 0, map.data, map.size);
+
+    gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
+    GST_DEBUG_OBJECT (demux,
+        "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
+        alignment);
+
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+
+    return new_buffer;
+  }
+
+  gst_buffer_unmap (buffer, &map);
+  return buffer;
+}
+
+/* the input buffer metadata must be writable,
+ * but time/duration etc not yet set and need not be preserved */
+static GstBuffer *
+gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    GstBuffer * buf)
+{
+  GstMapInfo map;
+  guint nsize = 0;
+  gchar *str;
+
+  /* not many cases for now */
+  if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
+    /* send a one time dvd clut event */
+    if (stream->pending_event && stream->pad)
+      gst_pad_push_event (stream->pad, stream->pending_event);
+    stream->pending_event = NULL;
+  }
+
+  if (G_UNLIKELY (stream->subtype != FOURCC_text
+          && stream->subtype != FOURCC_sbtl &&
+          stream->subtype != FOURCC_subp)) {
+    return buf;
+  }
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  /* empty buffer is sent to terminate previous subtitle */
+  if (map.size <= 2) {
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    return NULL;
+  }
+  if (stream->subtype == FOURCC_subp) {
+    /* That's all the processing needed for subpictures */
+    gst_buffer_unmap (buf, &map);
+    return buf;
+  }
+
+  nsize = GST_READ_UINT16_BE (map.data);
+  nsize = MIN (nsize, map.size - 2);
+
+  GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
+      nsize, map.size);
+
+  /* takes care of UTF-8 validation or UTF-16 recognition,
+   * no other encoding expected */
+  str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
+  gst_buffer_unmap (buf, &map);
+  if (str) {
+    gst_buffer_unref (buf);
+    buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
+  } else {
+    /* this should not really happen unless the subtitle is corrupted */
+    gst_buffer_unref (buf);
+    buf = NULL;
+  }
+
+  /* FIXME ? convert optional subsequent style info to markup */
+
+  return buf;
+}
+
+/* Sets a buffer's attributes properly and pushes it downstream.
+ * Also checks for additional actions and custom processing that may
+ * need to be done first.
+ */
+static GstFlowReturn
+gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, GstBuffer * buf,
+    GstClockTime dts, GstClockTime pts, GstClockTime duration,
+    gboolean keyframe, GstClockTime position, guint64 byte_position)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  /* offset the timestamps according to the edit list */
+
+  if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
+    gchar *url;
+    GstMapInfo map;
+
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    url = g_strndup ((gchar *) map.data, map.size);
+    gst_buffer_unmap (buf, &map);
+    if (url != NULL && strlen (url) != 0) {
+      /* we have RTSP redirect now */
+      gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
+          gst_message_new_element (GST_OBJECT_CAST (qtdemux),
+              gst_structure_new ("redirect",
+                  "new-location", G_TYPE_STRING, url, NULL)));
+      qtdemux->posted_redirect = TRUE;
+    } else {
+      GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
+          "posting");
+    }
+    g_free (url);
+  }
+
+  /* position reporting */
+  if (qtdemux->segment.rate >= 0) {
+    qtdemux->segment.position = position;
+    gst_qtdemux_sync_streams (qtdemux);
+  }
+
+  if (G_UNLIKELY (!stream->pad)) {
+    GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
+    gst_buffer_unref (buf);
+    goto exit;
+  }
+
+  /* send out pending buffers */
+  while (stream->buffers) {
+    GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
+
+    if (G_UNLIKELY (stream->discont)) {
+      GST_LOG_OBJECT (qtdemux, "marking discont buffer");
+      GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
+      stream->discont = FALSE;
+    } else {
+      GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
+    }
+
+    if (stream->alignment > 1)
+      buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
+    gst_pad_push (stream->pad, buffer);
+
+    stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
+  }
+
+  /* we're going to modify the metadata */
+  buf = gst_buffer_make_writable (buf);
+
+  if (G_UNLIKELY (stream->need_process))
+    buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
+
+  if (!buf) {
+    goto exit;
+  }
+
+  GST_BUFFER_DTS (buf) = dts;
+  GST_BUFFER_PTS (buf) = pts;
+  GST_BUFFER_DURATION (buf) = duration;
+  GST_BUFFER_OFFSET (buf) = -1;
+  GST_BUFFER_OFFSET_END (buf) = -1;
+
+  if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
+    gst_buffer_append_memory (buf,
+        gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
+
+  if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
+    gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
+  }
+#if 0
+  if (G_UNLIKELY (qtdemux->element_index)) {
+    GstClockTime stream_time;
+
+    stream_time =
+        gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
+        timestamp);
+    if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
+      GST_LOG_OBJECT (qtdemux,
+          "adding association %" GST_TIME_FORMAT "-> %"
+          G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
+      gst_index_add_association (qtdemux->element_index,
+          qtdemux->index_id,
+          keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
+          GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
+          GST_FORMAT_BYTES, byte_position, NULL);
+    }
+  }
+#endif
+
+  if (stream->need_clip)
+    buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
+
+  if (G_UNLIKELY (buf == NULL))
+    goto exit;
+
+  if (G_UNLIKELY (stream->discont)) {
+    GST_LOG_OBJECT (qtdemux, "marking discont buffer");
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+    stream->discont = FALSE;
+  } else {
+    GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
+  }
+
+  if (!keyframe) {
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
+    stream->on_keyframe = FALSE;
+  } else {
+    stream->on_keyframe = TRUE;
+  }
+
+
+  GST_LOG_OBJECT (qtdemux,
+      "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
+      ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
+      GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
+      GST_PAD_NAME (stream->pad));
+
+  if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
+    GstStructure *crypto_info;
+    QtDemuxCencSampleSetInfo *info =
+        (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
+    gint index;
+    GstEvent *event;
+
+    while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
+      gst_pad_push_event (stream->pad, event);
+    }
+
+    if (info->crypto_info == NULL) {
+      GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
+      gst_buffer_unref (buf);
+      goto exit;
+    }
+
+    /* The end of the crypto_info array matches our n_samples position,
+     * so count backward from there */
+    index = stream->sample_index - stream->n_samples + info->crypto_info->len;
+    if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
+      /* steal structure from array */
+      crypto_info = g_ptr_array_index (info->crypto_info, index);
+      g_ptr_array_index (info->crypto_info, index) = NULL;
+      GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
+          info->crypto_info->len);
+      if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
+        GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
+    } else {
+      GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
+          index, stream->sample_index);
+    }
+  }
+
+  if (stream->alignment > 1)
+    buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
+
+  ret = gst_pad_push (stream->pad, buf);
+
+  if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
+    /* mark position in stream, we'll need this to know when to send GAP event */
+    stream->segment.position = pts + duration;
+  }
+
+exit:
+  return ret;
+}
+
+static const QtDemuxRandomAccessEntry *
+gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    GstClockTime pos, gboolean after)
+{
+  QtDemuxRandomAccessEntry *entries = stream->ra_entries;
+  guint n_entries = stream->n_ra_entries;
+  guint i;
+
+  /* we assume the table is sorted */
+  for (i = 0; i < n_entries; ++i) {
+    if (entries[i].ts > pos)
+      break;
+  }
+
+  /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
+   * probably okay to assume that the index lists the very first fragment */
+  if (i == 0)
+    return &entries[0];
+
+  if (after)
+    return &entries[i];
+  else
+    return &entries[i - 1];
+}
+
+static gboolean
+gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
+{
+  const QtDemuxRandomAccessEntry *best_entry = NULL;
+  guint i;
+
+  GST_OBJECT_LOCK (qtdemux);
+
+  g_assert (qtdemux->n_streams > 0);
+
+  /* first see if we can determine where to go to using mfra,
+   * before we start clearing things */
+  for (i = 0; i < qtdemux->n_streams; i++) {
+    const QtDemuxRandomAccessEntry *entry;
+    QtDemuxStream *stream;
+    gboolean is_audio_or_video;
+
+    stream = qtdemux->streams[i];
+
+    if (stream->ra_entries == NULL)
+      continue;
+
+    if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
+      is_audio_or_video = TRUE;
+    else
+      is_audio_or_video = FALSE;
+
+    entry =
+        gst_qtdemux_stream_seek_fragment (qtdemux, stream,
+        stream->time_position, !is_audio_or_video);
+
+    GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
+        "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
+
+    stream->pending_seek = entry;
+
+    /* decide position to jump to just based on audio/video tracks, not subs */
+    if (!is_audio_or_video)
+      continue;
+
+    if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
+      best_entry = entry;
+  }
+
+  /* no luck, will handle seek otherwise */
+  if (best_entry == NULL) {
+    GST_OBJECT_UNLOCK (qtdemux);
+    return FALSE;
+  }
+
+  /* ok, now we can prepare for processing as of located moof */
+  for (i = 0; i < qtdemux->n_streams; i++) {
+    QtDemuxStream *stream;
+
+    stream = qtdemux->streams[i];
+
+    g_free (stream->samples);
+    stream->samples = NULL;
+    stream->n_samples = 0;
+    stream->stbl_index = -1;    /* no samples have yet been parsed */
+    stream->sample_index = -1;
+
+    if (stream->protection_scheme_info) {
+      /* Clear out any old cenc crypto info entries as we'll move to a new moof */
+      if (stream->protection_scheme_type == FOURCC_cenc) {
+        QtDemuxCencSampleSetInfo *info =
+            (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
+        if (info->crypto_info) {
+          g_ptr_array_free (info->crypto_info, TRUE);
+          info->crypto_info = NULL;
+        }
+      }
+    }
+  }
+
+  GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
+      "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (qtdemux->streams[0]->time_position),
+      best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
+
+  qtdemux->moof_offset = best_entry->moof_offset;
+
+  qtdemux_add_fragmented_samples (qtdemux);
+
+  GST_OBJECT_UNLOCK (qtdemux);
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBuffer *buf = NULL;
+  QtDemuxStream *stream;
+  GstClockTime min_time;
+  guint64 offset = 0;
+  GstClockTime dts = GST_CLOCK_TIME_NONE;
+  GstClockTime pts = GST_CLOCK_TIME_NONE;
+  GstClockTime duration = 0;
+  gboolean keyframe = FALSE;
+  guint sample_size = 0;
+  gboolean empty = 0;
+  guint size;
+  gint index;
+  gint i;
+
+  gst_qtdemux_push_pending_newsegment (qtdemux);
+
+  if (qtdemux->fragmented_seek_pending) {
+    GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
+    if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
+      GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
+      qtdemux->fragmented_seek_pending = FALSE;
+    } else {
+      GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
+    }
+  }
+
+  /* Figure out the next stream sample to output, min_time is expressed in
+   * global time and runs over the edit list segments. */
+  min_time = G_MAXUINT64;
+  index = -1;
+  for (i = 0; i < qtdemux->n_streams; i++) {
+    GstClockTime position;
+
+    stream = qtdemux->streams[i];
+    position = stream->time_position;
+
+    /* position of -1 is EOS */
+    if (position != GST_CLOCK_TIME_NONE && position < min_time) {
+      min_time = position;
+      index = i;
+    }
+  }
+  /* all are EOS */
+  if (G_UNLIKELY (index == -1)) {
+    GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
+    goto eos;
+  }
+
+  /* check for segment end */
+  if (G_UNLIKELY (qtdemux->segment.stop != -1
+          && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
+              || (qtdemux->segment.rate < 0
+                  && qtdemux->segment.start > min_time))
+          && qtdemux->streams[index]->on_keyframe)) {
+    GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
+    qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
+    goto eos_stream;
+  }
+
+  /* gap events for subtitle streams */
+  for (i = 0; i < qtdemux->n_streams; i++) {
+    stream = qtdemux->streams[i];
+    if (stream->pad && (stream->subtype == FOURCC_subp
+            || stream->subtype == FOURCC_text
+            || stream->subtype == FOURCC_sbtl)) {
+      /* send one second gap events until the stream catches up */
+      /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
+      while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
+          GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
+          stream->segment.position + GST_SECOND < min_time) {
+        GstEvent *gap =
+            gst_event_new_gap (stream->segment.position, GST_SECOND);
+        gst_pad_push_event (stream->pad, gap);
+        stream->segment.position += GST_SECOND;
+      }
+    }
+  }
+
+  stream = qtdemux->streams[index];
+  /* fetch info for the current sample of this stream */
+  if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
+              &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
+    goto eos_stream;
+
+  gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
+  if (stream->new_caps) {
+    gst_qtdemux_configure_stream (qtdemux, stream);
+    qtdemux_do_allocation (qtdemux, stream);
+  }
+
+  /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
+  if (G_UNLIKELY (qtdemux->
+          segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
+    if (stream->subtype == FOURCC_vide && !keyframe) {
+      GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
+      goto next;
+    }
+  }
+
+  GST_DEBUG_OBJECT (qtdemux,
+      "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
+      ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
+      ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
+      GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
+
+  if (G_UNLIKELY (empty)) {
+    /* empty segment, push a gap if there's a second or more
+     * difference and move to the next one */
+    if ((pts + duration - stream->segment.position) >= GST_SECOND)
+      gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
+    stream->segment.position = pts + duration;
+    goto next;
+  }
+
+  /* hmm, empty sample, skip and move to next sample */
+  if (G_UNLIKELY (sample_size <= 0))
+    goto next;
+
+  /* last pushed sample was out of boundary, goto next sample */
+  if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
+    goto next;
+
+  if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
+    size = sample_size;
+  } else {
+    GST_DEBUG_OBJECT (qtdemux,
+        "size %d larger than stream max_buffer_size %d, trimming",
+        sample_size, stream->max_buffer_size);
+    size =
+        MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
+  }
+
+  if (qtdemux->cenc_aux_info_offset > 0) {
+    GstMapInfo map;
+    GstByteReader br;
+    GstBuffer *aux_info = NULL;
+
+    /* pull the data stored before the sample */
+    ret =
+        gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
+        offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
+    if (G_UNLIKELY (ret != GST_FLOW_OK))
+      goto beach;
+    gst_buffer_map (aux_info, &map, GST_MAP_READ);
+    GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
+    gst_byte_reader_init (&br, map.data + 8, map.size);
+    if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
+            qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
+      GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
+      gst_buffer_unmap (aux_info, &map);
+      gst_buffer_unref (aux_info);
+      ret = GST_FLOW_ERROR;
+      goto beach;
+    }
+    gst_buffer_unmap (aux_info, &map);
+    gst_buffer_unref (aux_info);
+  }
+
+  GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
+      offset);
+
+  if (stream->use_allocator) {
+    /* if we have a per-stream allocator, use it */
+    buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
+  }
+
+  ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
+      size, &buf);
+  if (G_UNLIKELY (ret != GST_FLOW_OK))
+    goto beach;
+
+  if (size != sample_size) {
+    pts += gst_util_uint64_scale_int (GST_SECOND,
+        stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
+        stream->timescale);
+    dts +=
+        gst_util_uint64_scale_int (GST_SECOND,
+        stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
+        stream->timescale);
+    duration =
+        gst_util_uint64_scale_int (GST_SECOND,
+        size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
+  }
+
+  ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
+      dts, pts, duration, keyframe, min_time, offset);
+
+  if (size != sample_size) {
+    QtDemuxSample *sample = &stream->samples[stream->sample_index];
+    QtDemuxSegment *segment = &stream->segments[stream->segment_index];
+
+    GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
+        sample->timestamp +
+        stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
+    if (time_position >= segment->media_start) {
+      /* inside the segment, update time_position, looks very familiar to
+       * GStreamer segments, doesn't it? */
+      stream->time_position = (time_position - segment->media_start) +
+          segment->time;
+    } else {
+      /* not yet in segment, time does not yet increment. This means
+       * that we are still prerolling keyframes to the decoder so it can
+       * decode the first sample of the segment. */
+      stream->time_position = segment->time;
+    }
+  }
+
+  /* combine flows */
+  ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
+  /* ignore unlinked, we will not push on the pad anymore and we will EOS when
+   * we have no more data for the pad to push */
+  if (ret == GST_FLOW_EOS)
+    ret = GST_FLOW_OK;
+
+  stream->offset_in_sample += size;
+  if (stream->offset_in_sample >= sample_size) {
+    gst_qtdemux_advance_sample (qtdemux, stream);
+  }
+  goto beach;
+
+next:
+  gst_qtdemux_advance_sample (qtdemux, stream);
+
+beach:
+  return ret;
+
+  /* special cases */
+eos:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
+    ret = GST_FLOW_EOS;
+    goto beach;
+  }
+eos_stream:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
+    /* EOS will be raised if all are EOS */
+    ret = GST_FLOW_OK;
+    goto beach;
+  }
+}
+
+static void
+gst_qtdemux_loop (GstPad * pad)
+{
+  GstQTDemux *qtdemux;
+  guint64 cur_offset;
+  GstFlowReturn ret;
+
+  qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
+
+  cur_offset = qtdemux->offset;
+  GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
+      cur_offset, qt_demux_state_string (qtdemux->state));
+
+  switch (qtdemux->state) {
+    case QTDEMUX_STATE_INITIAL:
+    case QTDEMUX_STATE_HEADER:
+      ret = gst_qtdemux_loop_state_header (qtdemux);
+      break;
+    case QTDEMUX_STATE_MOVIE:
+      ret = gst_qtdemux_loop_state_movie (qtdemux);
+      if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
+        ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
+      }
+      break;
+    default:
+      /* ouch */
+      goto invalid_state;
+  }
+
+  /* if something went wrong, pause */
+  if (ret != GST_FLOW_OK)
+    goto pause;
+
+done:
+  gst_object_unref (qtdemux);
+  return;
+
+  /* ERRORS */
+invalid_state:
+  {
+    GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
+        (NULL), ("streaming stopped, invalid state"));
+    gst_pad_pause_task (pad);
+    gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
+    goto done;
+  }
+pause:
+  {
+    const gchar *reason = gst_flow_get_name (ret);
+
+    GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
+
+    gst_pad_pause_task (pad);
+
+    /* fatal errors need special actions */
+    /* check EOS */
+    if (ret == GST_FLOW_EOS) {
+      if (qtdemux->n_streams == 0) {
+        /* we have no streams, post an error */
+        gst_qtdemux_post_no_playable_stream_error (qtdemux);
+      }
+      if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+        gint64 stop;
+
+        if ((stop = qtdemux->segment.stop) == -1)
+          stop = qtdemux->segment.duration;
+
+        if (qtdemux->segment.rate >= 0) {
+          GstMessage *message;
+          GstEvent *event;
+
+          GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
+          message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
+              GST_FORMAT_TIME, stop);
+          event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
+          if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
+            gst_message_set_seqnum (message, qtdemux->segment_seqnum);
+            gst_event_set_seqnum (event, qtdemux->segment_seqnum);
+          }
+          gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
+          gst_qtdemux_push_event (qtdemux, event);
+        } else {
+          GstMessage *message;
+          GstEvent *event;
+
+          /*  For Reverse Playback */
+          GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
+          message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
+              GST_FORMAT_TIME, qtdemux->segment.start);
+          event = gst_event_new_segment_done (GST_FORMAT_TIME,
+              qtdemux->segment.start);
+          if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
+            gst_message_set_seqnum (message, qtdemux->segment_seqnum);
+            gst_event_set_seqnum (event, qtdemux->segment_seqnum);
+          }
+          gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
+          gst_qtdemux_push_event (qtdemux, event);
+        }
+      } else {
+        GstEvent *event;
+
+        GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
+        event = gst_event_new_eos ();
+        if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
+          gst_event_set_seqnum (event, qtdemux->segment_seqnum);
+        gst_qtdemux_push_event (qtdemux, event);
+      }
+    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
+      GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
+      gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
+    }
+    goto done;
+  }
+}
+
+/*
+ * has_next_entry
+ *
+ * Returns if there are samples to be played.
+ */
+static gboolean
+has_next_entry (GstQTDemux * demux)
+{
+  QtDemuxStream *stream;
+  int i;
+
+  GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
+
+  for (i = 0; i < demux->n_streams; i++) {
+    stream = demux->streams[i];
+
+    if (stream->sample_index == -1) {
+      stream->sample_index = 0;
+      stream->offset_in_sample = 0;
+    }
+
+    if (stream->sample_index >= stream->n_samples) {
+      GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
+      continue;
+    }
+    GST_DEBUG_OBJECT (demux, "Found a sample");
+    return TRUE;
+  }
+
+  GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
+  return FALSE;
+}
+
+/*
+ * next_entry_size
+ *
+ * Returns the size of the first entry at the current offset.
+ * If -1, there are none (which means EOS or empty file).
+ */
+static guint64
+next_entry_size (GstQTDemux * demux)
+{
+  QtDemuxStream *stream;
+  int i;
+  int smallidx = -1;
+  guint64 smalloffs = (guint64) - 1;
+  QtDemuxSample *sample;
+
+  GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
+      demux->offset);
+
+  for (i = 0; i < demux->n_streams; i++) {
+    stream = demux->streams[i];
+
+    if (stream->sample_index == -1) {
+      stream->sample_index = 0;
+      stream->offset_in_sample = 0;
+    }
+
+    if (stream->sample_index >= stream->n_samples) {
+      GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
+      continue;
+    }
+
+    if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
+      GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
+          stream->sample_index);
+      return -1;
+    }
+
+    sample = &stream->samples[stream->sample_index];
+
+    GST_LOG_OBJECT (demux,
+        "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
+        " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
+        sample->offset, sample->size);
+
+    if (((smalloffs == -1)
+            || (sample->offset < smalloffs)) && (sample->size)) {
+      smallidx = i;
+      smalloffs = sample->offset;
+    }
+  }
+
+  GST_LOG_OBJECT (demux,
+      "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
+      G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
+
+  if (smallidx == -1)
+    return -1;
+
+  stream = demux->streams[smallidx];
+  sample = &stream->samples[stream->sample_index];
+
+  if (sample->offset >= demux->offset) {
+    demux->todrop = sample->offset - demux->offset;
+    return sample->size + demux->todrop;
+  }
+
+  GST_DEBUG_OBJECT (demux,
+      "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
+  return -1;
+}
+
+static void
+gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
+{
+  gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
+
+  gst_element_post_message (GST_ELEMENT_CAST (demux),
+      gst_message_new_element (GST_OBJECT_CAST (demux),
+          gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
+}
+
+static gboolean
+qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
+{
+  GstEvent *event;
+  gboolean res = 0;
+
+  GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
+
+  event =
+      gst_event_new_seek (1.0, GST_FORMAT_BYTES,
+      GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
+      GST_SEEK_TYPE_NONE, -1);
+
+  /* store seqnum to drop flush events, they don't need to reach downstream */
+  demux->offset_seek_seqnum = gst_event_get_seqnum (event);
+  res = gst_pad_push_event (demux->sinkpad, event);
+  demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
+
+  return res;
+}
+
+/* check for seekable upstream, above and beyond a mere query */
+static void
+gst_qtdemux_check_seekability (GstQTDemux * demux)
+{
+  GstQuery *query;
+  gboolean seekable = FALSE;
+  gint64 start = -1, stop = -1;
+
+  if (demux->upstream_size)
+    return;
+
+  if (demux->upstream_format_is_time)
+    return;
+
+  query = gst_query_new_seeking (GST_FORMAT_BYTES);
+  if (!gst_pad_peer_query (demux->sinkpad, query)) {
+    GST_DEBUG_OBJECT (demux, "seeking query failed");
+    goto done;
+  }
+
+  gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
+
+  /* try harder to query upstream size if we didn't get it the first time */
+  if (seekable && stop == -1) {
+    GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
+    gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
+  }
+
+  /* if upstream doesn't know the size, it's likely that it's not seekable in
+   * practice even if it technically may be seekable */
+  if (seekable && (start != 0 || stop <= start)) {
+    GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
+    seekable = FALSE;
+  }
+
+done:
+  gst_query_unref (query);
+
+  GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
+      G_GUINT64_FORMAT ")", seekable, start, stop);
+  demux->upstream_seekable = seekable;
+  demux->upstream_size = seekable ? stop : -1;
+}
+
+static void
+gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
+{
+  g_return_if_fail (bytes <= demux->todrop);
+
+  GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
+  gst_adapter_flush (demux->adapter, bytes);
+  demux->neededbytes -= bytes;
+  demux->offset += bytes;
+  demux->todrop -= bytes;
+}
+
+static void
+gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
+{
+  if (G_UNLIKELY (demux->pending_newsegment)) {
+    gint i;
+
+    gst_qtdemux_push_pending_newsegment (demux);
+    /* clear to send tags on all streams */
+    for (i = 0; i < demux->n_streams; i++) {
+      QtDemuxStream *stream;
+      stream = demux->streams[i];
+      gst_qtdemux_push_tags (demux, stream);
+      if (CUR_STREAM (stream)->sparse) {
+        GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
+        gst_pad_push_event (stream->pad,
+            gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
+      }
+    }
+  }
+}
+
+static void
+gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
+    QtDemuxStream * stream, gint segment_index, GstClockTime pos)
+{
+  GstClockTime ts, dur;
+  GstEvent *gap;
+
+  ts = pos;
+  dur =
+      stream->segments[segment_index].duration - (pos -
+      stream->segments[segment_index].time);
+  gap = gst_event_new_gap (ts, dur);
+  stream->time_position += dur;
+
+  GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
+      "segment: %" GST_PTR_FORMAT, gap);
+  gst_pad_push_event (stream->pad, gap);
+}
+
+static void
+gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
+    QtDemuxStream * stream)
+{
+  gint i;
+
+  /* Push any initial gap segments before proceeding to the
+   * 'real' data */
+  for (i = 0; i < stream->n_segments; i++) {
+    gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
+
+    if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
+      gst_qtdemux_send_gap_for_segment (demux, stream, i,
+          stream->time_position);
+    } else {
+      /* Only support empty segment at the beginning followed by
+       * one non-empty segment, this was checked when parsing the
+       * edts atom, arriving here is unexpected */
+      g_assert (i + 1 == stream->n_segments);
+      break;
+    }
+  }
+}
+
+static GstFlowReturn
+gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
+{
+  GstQTDemux *demux;
+
+  demux = GST_QTDEMUX (parent);
+
+  GST_DEBUG_OBJECT (demux,
+      "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
+      " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
+      G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
+      GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
+      gst_buffer_get_size (inbuf), demux->offset);
+
+  if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
+    gboolean is_gap_input = FALSE;
+    gint i;
+
+    GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
+
+    for (i = 0; i < demux->n_streams; i++) {
+      demux->streams[i]->discont = TRUE;
+    }
+
+    /* Check if we can land back on our feet in the case where upstream is
+     * handling the seeking/pushing of samples with gaps in between (like
+     * in the case of trick-mode DASH for example) */
+    if (demux->upstream_format_is_time
+        && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
+      gint i;
+      for (i = 0; i < demux->n_streams; i++) {
+        guint32 res;
+        GST_LOG_OBJECT (demux,
+            "Stream #%d , checking if offset %" G_GUINT64_FORMAT
+            " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
+        res =
+            gst_qtdemux_find_index_for_given_media_offset_linear (demux,
+            demux->streams[i], GST_BUFFER_OFFSET (inbuf));
+        if (res != -1) {
+          QtDemuxSample *sample = &demux->streams[i]->samples[res];
+          GST_LOG_OBJECT (demux,
+              "Checking if sample %d from stream %d is valid (offset:%"
+              G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
+              sample->offset, sample->size);
+          if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
+            GST_LOG_OBJECT (demux,
+                "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
+                res);
+            is_gap_input = TRUE;
+            /* We can go back to standard playback mode */
+            demux->state = QTDEMUX_STATE_MOVIE;
+            /* Remember which sample this stream is at */
+            demux->streams[i]->sample_index = res;
+            /* Finally update all push-based values to the expected values */
+            demux->neededbytes = demux->streams[i]->samples[res].size;
+            demux->offset = GST_BUFFER_OFFSET (inbuf);
+            demux->mdatleft =
+                demux->mdatsize - demux->offset + demux->mdatoffset;
+            demux->todrop = 0;
+          }
+        }
+      }
+      if (!is_gap_input) {
+        GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
+        /* Reset state if it's a real discont */
+        demux->neededbytes = 16;
+        demux->state = QTDEMUX_STATE_INITIAL;
+        demux->offset = GST_BUFFER_OFFSET (inbuf);
+        gst_adapter_clear (demux->adapter);
+      }
+    }
+    /* Reverse fragmented playback, need to flush all we have before
+     * consuming a new fragment.
+     * The samples array have the timestamps calculated by accumulating the
+     * durations but this won't work for reverse playback of fragments as
+     * the timestamps of a subsequent fragment should be smaller than the
+     * previously received one. */
+    if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
+      gst_qtdemux_process_adapter (demux, TRUE);
+      for (i = 0; i < demux->n_streams; i++)
+        gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
+    }
+  }
+
+  gst_adapter_push (demux->adapter, inbuf);
+
+  GST_DEBUG_OBJECT (demux,
+      "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
+      demux->neededbytes, gst_adapter_available (demux->adapter));
+
+  return gst_qtdemux_process_adapter (demux, FALSE);
+}
+
+static GstFlowReturn
+gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  /* we never really mean to buffer that much */
+  if (demux->neededbytes == -1) {
+    goto eos;
+  }
+
+  while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
+      (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
+
+#ifndef GST_DISABLE_GST_DEBUG
+    {
+      guint64 discont_offset, distance_from_discont;
+
+      discont_offset = gst_adapter_offset_at_discont (demux->adapter);
+      distance_from_discont =
+          gst_adapter_distance_from_discont (demux->adapter);
+
+      GST_DEBUG_OBJECT (demux,
+          "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
+          " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
+          " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
+          demux->offset, discont_offset, distance_from_discont);
+    }
+#endif
+
+    switch (demux->state) {
+      case QTDEMUX_STATE_INITIAL:{
+        const guint8 *data;
+        guint32 fourcc;
+        guint64 size;
+
+        gst_qtdemux_check_seekability (demux);
+
+        data = gst_adapter_map (demux->adapter, demux->neededbytes);
+
+        /* get fourcc/length, set neededbytes */
+        extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
+            &size, &fourcc);
+        gst_adapter_unmap (demux->adapter);
+        data = NULL;
+        GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
+            "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
+        if (size == 0) {
+          GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
+              (_("This file is invalid and cannot be played.")),
+              ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
+                  GST_FOURCC_ARGS (fourcc)));
+          ret = GST_FLOW_ERROR;
+          break;
+        }
+        if (fourcc == FOURCC_mdat) {
+          gint next_entry = next_entry_size (demux);
+          if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
+            /* we have the headers, start playback */
+            demux->state = QTDEMUX_STATE_MOVIE;
+            demux->neededbytes = next_entry;
+            demux->mdatleft = size;
+            demux->mdatsize = demux->mdatleft;
+          } else {
+            /* no headers yet, try to get them */
+            guint bs;
+            gboolean res;
+            guint64 old, target;
+
+          buffer_data:
+            old = demux->offset;
+            target = old + size;
+
+            /* try to jump over the atom with a seek */
+            /* only bother if it seems worth doing so,
+             * and avoids possible upstream/server problems */
+            if (demux->upstream_seekable &&
+                demux->upstream_size > 4 * (1 << 20)) {
+              res = qtdemux_seek_offset (demux, target);
+            } else {
+              GST_DEBUG_OBJECT (demux, "skipping seek");
+              res = FALSE;
+            }
+
+            if (res) {
+              GST_DEBUG_OBJECT (demux, "seek success");
+              /* remember the offset fo the first mdat so we can seek back to it
+               * after we have the headers */
+              if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
+                demux->first_mdat = old;
+                GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
+                    demux->first_mdat);
+              }
+              /* seek worked, continue reading */
+              demux->offset = target;
+              demux->neededbytes = 16;
+              demux->state = QTDEMUX_STATE_INITIAL;
+            } else {
+              /* seek failed, need to buffer */
+              demux->offset = old;
+              GST_DEBUG_OBJECT (demux, "seek failed/skipped");
+              /* there may be multiple mdat (or alike) buffers */
+              /* sanity check */
+              if (demux->mdatbuffer)
+                bs = gst_buffer_get_size (demux->mdatbuffer);
+              else
+                bs = 0;
+              if (size + bs > 10 * (1 << 20))
+                goto no_moov;
+              demux->state = QTDEMUX_STATE_BUFFER_MDAT;
+              demux->neededbytes = size;
+              if (!demux->mdatbuffer)
+                demux->mdatoffset = demux->offset;
+            }
+          }
+        } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
+          GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
+              (_("This file is invalid and cannot be played.")),
+              ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
+                  GST_FOURCC_ARGS (fourcc), size));
+          ret = GST_FLOW_ERROR;
+          break;
+        } else {
+          /* this means we already started buffering and still no moov header,
+           * let's continue buffering everything till we get moov */
+          if (demux->mdatbuffer && !(fourcc == FOURCC_moov
+                  || fourcc == FOURCC_moof))
+            goto buffer_data;
+          demux->neededbytes = size;
+          demux->state = QTDEMUX_STATE_HEADER;
+        }
+        break;
+      }
+      case QTDEMUX_STATE_HEADER:{
+        const guint8 *data;
+        guint32 fourcc;
+
+        GST_DEBUG_OBJECT (demux, "In header");
+
+        data = gst_adapter_map (demux->adapter, demux->neededbytes);
+
+        /* parse the header */
+        extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
+            &fourcc);
+        if (fourcc == FOURCC_moov) {
+          gint n;
+
+          /* in usual fragmented setup we could try to scan for more
+           * and end up at the the moov (after mdat) again */
+          if (demux->got_moov && demux->n_streams > 0 &&
+              (!demux->fragmented
+                  || demux->last_moov_offset == demux->offset)) {
+            GST_DEBUG_OBJECT (demux,
+                "Skipping moov atom as we have (this) one already");
+          } else {
+            GST_DEBUG_OBJECT (demux, "Parsing [moov]");
+
+            if (demux->got_moov && demux->fragmented) {
+              GST_DEBUG_OBJECT (demux,
+                  "Got a second moov, clean up data from old one");
+              if (demux->moov_node_compressed) {
+                g_node_destroy (demux->moov_node_compressed);
+                if (demux->moov_node)
+                  g_free (demux->moov_node->data);
+              }
+              demux->moov_node_compressed = NULL;
+              if (demux->moov_node)
+                g_node_destroy (demux->moov_node);
+              demux->moov_node = NULL;
+            } else {
+              /* prepare newsegment to send when streaming actually starts */
+              if (!demux->pending_newsegment) {
+                demux->pending_newsegment =
+                    gst_event_new_segment (&demux->segment);
+                if (demux->segment_seqnum != GST_SEQNUM_INVALID)
+                  gst_event_set_seqnum (demux->pending_newsegment,
+                      demux->segment_seqnum);
+              }
+            }
+
+            demux->last_moov_offset = demux->offset;
+
+            qtdemux_parse_moov (demux, data, demux->neededbytes);
+            qtdemux_node_dump (demux, demux->moov_node);
+            qtdemux_parse_tree (demux);
+            qtdemux_prepare_streams (demux);
+            if (!demux->got_moov)
+              qtdemux_expose_streams (demux);
+            else {
+
+              for (n = 0; n < demux->n_streams; n++) {
+                QtDemuxStream *stream = demux->streams[n];
+
+                gst_qtdemux_configure_stream (demux, stream);
+              }
+            }
+
+            demux->got_moov = TRUE;
+            gst_qtdemux_check_send_pending_segment (demux);
+
+            /* fragmented streams headers shouldn't contain edts atoms */
+            if (!demux->fragmented) {
+              for (n = 0; n < demux->n_streams; n++) {
+                gst_qtdemux_stream_send_initial_gap_segments (demux,
+                    demux->streams[n]);
+              }
+            }
+
+            if (demux->moov_node_compressed) {
+              g_node_destroy (demux->moov_node_compressed);
+              g_free (demux->moov_node->data);
+            }
+            demux->moov_node_compressed = NULL;
+            g_node_destroy (demux->moov_node);
+            demux->moov_node = NULL;
+            GST_DEBUG_OBJECT (demux, "Finished parsing the header");
+          }
+        } else if (fourcc == FOURCC_moof) {
+          if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
+            guint64 dist = 0;
+            GstClockTime prev_pts;
+            guint64 prev_offset;
+            guint64 adapter_discont_offset, adapter_discont_dist;
+
+            GST_DEBUG_OBJECT (demux, "Parsing [moof]");
+
+            /*
+             * The timestamp of the moof buffer is relevant as some scenarios
+             * won't have the initial timestamp in the atoms. Whenever a new
+             * buffer has started, we get that buffer's PTS and use it as a base
+             * timestamp for the trun entries.
+             *
+             * To keep track of the current buffer timestamp and starting point
+             * we use gst_adapter_prev_pts that gives us the PTS and the distance
+             * from the beggining of the buffer, with the distance and demux->offset
+             * we know if it is still the same buffer or not.
+             */
+            prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
+            prev_offset = demux->offset - dist;
+            if (demux->fragment_start_offset == -1
+                || prev_offset > demux->fragment_start_offset) {
+              demux->fragment_start_offset = prev_offset;
+              demux->fragment_start = prev_pts;
+              GST_DEBUG_OBJECT (demux,
+                  "New fragment start found at: %" G_GUINT64_FORMAT " : %"
+                  GST_TIME_FORMAT, demux->fragment_start_offset,
+                  GST_TIME_ARGS (demux->fragment_start));
+            }
+
+            /* We can't use prev_offset() here because this would require
+             * upstream to set consistent and correct offsets on all buffers
+             * since the discont. Nothing ever did that in the past and we
+             * would break backwards compatibility here then.
+             * Instead take the offset we had at the last discont and count
+             * the bytes from there. This works with old code as there would
+             * be no discont between moov and moof, and also works with
+             * adaptivedemux which correctly sets offset and will set the
+             * DISCONT flag accordingly when needed.
+             *
+             * We also only do this for upstream TIME segments as otherwise
+             * there are potential backwards compatibility problems with
+             * seeking in PUSH mode and upstream providing inconsistent
+             * timestamps. */
+            adapter_discont_offset =
+                gst_adapter_offset_at_discont (demux->adapter);
+            adapter_discont_dist =
+                gst_adapter_distance_from_discont (demux->adapter);
+
+            GST_DEBUG_OBJECT (demux,
+                "demux offset %" G_GUINT64_FORMAT " adapter offset %"
+                G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
+                demux->offset, adapter_discont_offset, adapter_discont_dist);
+
+            if (demux->upstream_format_is_time) {
+              demux->moof_offset = adapter_discont_offset;
+              if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
+                demux->moof_offset += adapter_discont_dist;
+              if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
+                demux->moof_offset = demux->offset;
+            } else {
+              demux->moof_offset = demux->offset;
+            }
+
+            if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
+                    demux->moof_offset, NULL)) {
+              gst_adapter_unmap (demux->adapter);
+              ret = GST_FLOW_ERROR;
+              goto done;
+            }
+            /* in MSS we need to expose the pads after the first moof as we won't get a moov */
+            if (demux->mss_mode && !demux->exposed) {
+              if (!demux->pending_newsegment) {
+                GST_DEBUG_OBJECT (demux, "new pending_newsegment");
+                demux->pending_newsegment =
+                    gst_event_new_segment (&demux->segment);
+                if (demux->segment_seqnum != GST_SEQNUM_INVALID)
+                  gst_event_set_seqnum (demux->pending_newsegment,
+                      demux->segment_seqnum);
+              }
+              qtdemux_expose_streams (demux);
+            }
+          } else {
+            GST_DEBUG_OBJECT (demux, "Discarding [moof]");
+          }
+        } else if (fourcc == FOURCC_ftyp) {
+          GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
+          qtdemux_parse_ftyp (demux, data, demux->neededbytes);
+        } else if (fourcc == FOURCC_uuid) {
+          GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
+          qtdemux_parse_uuid (demux, data, demux->neededbytes);
+        } else if (fourcc == FOURCC_sidx) {
+          GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
+          qtdemux_parse_sidx (demux, data, demux->neededbytes);
+        } else {
+          switch (fourcc) {
+            case FOURCC_styp:
+              /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
+               * FALLTHROUGH */
+            case FOURCC_skip:
+            case FOURCC_free:
+              /* [free] and [skip] are padding atoms */
+              GST_DEBUG_OBJECT (demux,
+                  "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
+                  GST_FOURCC_ARGS (fourcc));
+              break;
+            default:
+              GST_WARNING_OBJECT (demux,
+                  "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
+                  GST_FOURCC_ARGS (fourcc));
+              /* Let's jump that one and go back to initial state */
+              break;
+          }
+        }
+        gst_adapter_unmap (demux->adapter);
+        data = NULL;
+
+        if (demux->mdatbuffer && demux->n_streams) {
+          gsize remaining_data_size = 0;
+
+          /* the mdat was before the header */
+          GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
+              demux->n_streams, demux->mdatbuffer);
+          /* restore our adapter/offset view of things with upstream;
+           * put preceding buffered data ahead of current moov data.
+           * This should also handle evil mdat, moov, mdat cases and alike */
+          gst_adapter_flush (demux->adapter, demux->neededbytes);
+
+          /* Store any remaining data after the mdat for later usage */
+          remaining_data_size = gst_adapter_available (demux->adapter);
+          if (remaining_data_size > 0) {
+            g_assert (demux->restoredata_buffer == NULL);
+            demux->restoredata_buffer =
+                gst_adapter_take_buffer (demux->adapter, remaining_data_size);
+            demux->restoredata_offset = demux->offset + demux->neededbytes;
+            GST_DEBUG_OBJECT (demux,
+                "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
+                G_GUINT64_FORMAT, remaining_data_size,
+                demux->restoredata_offset);
+          }
+
+          gst_adapter_push (demux->adapter, demux->mdatbuffer);
+          demux->mdatbuffer = NULL;
+          demux->offset = demux->mdatoffset;
+          demux->neededbytes = next_entry_size (demux);
+          demux->state = QTDEMUX_STATE_MOVIE;
+          demux->mdatleft = gst_adapter_available (demux->adapter);
+          demux->mdatsize = demux->mdatleft;
+        } else {
+          GST_DEBUG_OBJECT (demux, "Carrying on normally");
+          gst_adapter_flush (demux->adapter, demux->neededbytes);
+
+          /* only go back to the mdat if there are samples to play */
+          if (demux->got_moov && demux->first_mdat != -1
+              && has_next_entry (demux)) {
+            gboolean res;
+
+            /* we need to seek back */
+            res = qtdemux_seek_offset (demux, demux->first_mdat);
+            if (res) {
+              demux->offset = demux->first_mdat;
+            } else {
+              GST_DEBUG_OBJECT (demux, "Seek back failed");
+            }
+          } else {
+            demux->offset += demux->neededbytes;
+          }
+          demux->neededbytes = 16;
+          demux->state = QTDEMUX_STATE_INITIAL;
+        }
+
+        break;
+      }
+      case QTDEMUX_STATE_BUFFER_MDAT:{
+        GstBuffer *buf;
+        guint8 fourcc[4];
+
+        GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
+            demux->offset);
+        buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
+        gst_buffer_extract (buf, 0, fourcc, 4);
+        GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
+            GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
+        if (demux->mdatbuffer)
+          demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
+        else
+          demux->mdatbuffer = buf;
+        demux->offset += demux->neededbytes;
+        demux->neededbytes = 16;
+        demux->state = QTDEMUX_STATE_INITIAL;
+        gst_qtdemux_post_progress (demux, 1, 1);
+
+        break;
+      }
+      case QTDEMUX_STATE_MOVIE:{
+        QtDemuxStream *stream = NULL;
+        QtDemuxSample *sample;
+        int i = -1;
+        GstClockTime dts, pts, duration;
+        gboolean keyframe;
+
+        GST_DEBUG_OBJECT (demux,
+            "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
+
+        if (demux->fragmented) {
+          GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
+              demux->mdatleft);
+          if (G_LIKELY (demux->todrop < demux->mdatleft)) {
+            /* if needed data starts within this atom,
+             * then it should not exceed this atom */
+            if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
+              GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
+                  (_("This file is invalid and cannot be played.")),
+                  ("sample data crosses atom boundary"));
+              ret = GST_FLOW_ERROR;
+              break;
+            }
+            demux->mdatleft -= demux->neededbytes;
+          } else {
+            GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
+            /* so we are dropping more than left in this atom */
+            gst_qtdemux_drop_data (demux, demux->mdatleft);
+            demux->mdatleft = 0;
+
+            /* need to resume atom parsing so we do not miss any other pieces */
+            demux->state = QTDEMUX_STATE_INITIAL;
+            demux->neededbytes = 16;
+
+            /* check if there was any stored post mdat data from previous buffers */
+            if (demux->restoredata_buffer) {
+              g_assert (gst_adapter_available (demux->adapter) == 0);
+
+              gst_adapter_push (demux->adapter, demux->restoredata_buffer);
+              demux->restoredata_buffer = NULL;
+              demux->offset = demux->restoredata_offset;
+            }
+
+            break;
+          }
+        }
+
+        if (demux->todrop) {
+          if (demux->cenc_aux_info_offset > 0) {
+            GstByteReader br;
+            const guint8 *data;
+
+            GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
+            data = gst_adapter_map (demux->adapter, demux->todrop);
+            gst_byte_reader_init (&br, data + 8, demux->todrop);
+            if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
+                    demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
+              GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
+              ret = GST_FLOW_ERROR;
+              gst_adapter_unmap (demux->adapter);
+              g_free (demux->cenc_aux_info_sizes);
+              demux->cenc_aux_info_sizes = NULL;
+              goto done;
+            }
+            demux->cenc_aux_info_offset = 0;
+            g_free (demux->cenc_aux_info_sizes);
+            demux->cenc_aux_info_sizes = NULL;
+            gst_adapter_unmap (demux->adapter);
+          }
+          gst_qtdemux_drop_data (demux, demux->todrop);
+        }
+
+        /* first buffer? */
+        /* initial newsegment sent here after having added pads,
+         * possible others in sink_event */
+        gst_qtdemux_check_send_pending_segment (demux);
+
+        /* Figure out which stream this packet belongs to */
+        for (i = 0; i < demux->n_streams; i++) {
+          stream = demux->streams[i];
+          if (stream->sample_index >= stream->n_samples)
+            continue;
+          GST_LOG_OBJECT (demux,
+              "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
+              " / size:%d)", i, stream->sample_index,
+              stream->samples[stream->sample_index].offset,
+              stream->samples[stream->sample_index].size);
+
+          if (stream->samples[stream->sample_index].offset == demux->offset)
+            break;
+        }
+
+        if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
+          goto unknown_stream;
+
+        gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
+
+        if (stream->new_caps) {
+          gst_qtdemux_configure_stream (demux, stream);
+        }
+
+        /* Put data in a buffer, set timestamps, caps, ... */
+        sample = &stream->samples[stream->sample_index];
+
+        if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
+          GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
+              GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
+
+          dts = QTSAMPLE_DTS (stream, sample);
+          pts = QTSAMPLE_PTS (stream, sample);
+          duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
+          keyframe = QTSAMPLE_KEYFRAME (stream, sample);
+
+          /* check for segment end */
+          if (G_UNLIKELY (demux->segment.stop != -1
+                  && demux->segment.stop <= pts && stream->on_keyframe)) {
+            GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
+            stream->time_position = GST_CLOCK_TIME_NONE;        /* this means EOS */
+
+            /* skip this data, stream is EOS */
+            gst_adapter_flush (demux->adapter, demux->neededbytes);
+            demux->offset += demux->neededbytes;
+
+            /* check if all streams are eos */
+            ret = GST_FLOW_EOS;
+            for (i = 0; i < demux->n_streams; i++) {
+              if (!STREAM_IS_EOS (demux->streams[i])) {
+                ret = GST_FLOW_OK;
+                break;
+              }
+            }
+          } else {
+            GstBuffer *outbuf;
+
+            outbuf =
+                gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
+
+            /* FIXME: should either be an assert or a plain check */
+            g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
+
+            ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
+                dts, pts, duration, keyframe, dts, demux->offset);
+          }
+
+          /* combine flows */
+          ret = gst_qtdemux_combine_flows (demux, stream, ret);
+        } else {
+          /* skip this data, stream is EOS */
+          gst_adapter_flush (demux->adapter, demux->neededbytes);
+        }
+
+        stream->sample_index++;
+        stream->offset_in_sample = 0;
+
+        /* update current offset and figure out size of next buffer */
+        GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
+            demux->offset, demux->neededbytes);
+        demux->offset += demux->neededbytes;
+        GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
+            demux->offset);
+
+
+        if (ret == GST_FLOW_EOS) {
+          GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
+          demux->neededbytes = -1;
+          goto eos;
+        }
+
+        if ((demux->neededbytes = next_entry_size (demux)) == -1) {
+          if (demux->fragmented) {
+            GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
+            /* there may be more to follow, only finish this atom */
+            demux->todrop = demux->mdatleft;
+            demux->neededbytes = demux->todrop;
+            break;
+          }
+          goto eos;
+        }
+        if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
+          goto non_ok_unlinked_flow;
+        }
+        break;
+      }
+      default:
+        goto invalid_state;
+    }
+  }
+
+  /* when buffering movie data, at least show user something is happening */
+  if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
+      gst_adapter_available (demux->adapter) <= demux->neededbytes) {
+    gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
+        demux->neededbytes);
+  }
+done:
+
+  return ret;
+
+  /* ERRORS */
+non_ok_unlinked_flow:
+  {
+    GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
+        gst_flow_get_name (ret));
+    return ret;
+  }
+unknown_stream:
+  {
+    GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+eos:
+  {
+    GST_DEBUG_OBJECT (demux, "no next entry, EOS");
+    ret = GST_FLOW_EOS;
+    goto done;
+  }
+invalid_state:
+  {
+    GST_ELEMENT_ERROR (demux, STREAM, FAILED,
+        (NULL), ("qtdemuxer invalid state %d", demux->state));
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+no_moov:
+  {
+    GST_ELEMENT_ERROR (demux, STREAM, FAILED,
+        (NULL), ("no 'moov' atom within the first 10 MB"));
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+}
+
+static gboolean
+qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
+{
+  GstQuery *query;
+  gboolean pull_mode;
+
+  query = gst_query_new_scheduling ();
+
+  if (!gst_pad_peer_query (sinkpad, query)) {
+    gst_query_unref (query);
+    goto activate_push;
+  }
+
+  pull_mode = gst_query_has_scheduling_mode_with_flags (query,
+      GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
+  gst_query_unref (query);
+
+  if (!pull_mode)
+    goto activate_push;
+
+  GST_DEBUG_OBJECT (sinkpad, "activating pull");
+  return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
+
+activate_push:
+  {
+    GST_DEBUG_OBJECT (sinkpad, "activating push");
+    return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
+  }
+}
+
+static gboolean
+qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
+    GstPadMode mode, gboolean active)
+{
+  gboolean res;
+  GstQTDemux *demux = GST_QTDEMUX (parent);
+
+  switch (mode) {
+    case GST_PAD_MODE_PUSH:
+      demux->pullbased = FALSE;
+      res = TRUE;
+      break;
+    case GST_PAD_MODE_PULL:
+      if (active) {
+        demux->pullbased = TRUE;
+        res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
+            sinkpad, NULL);
+      } else {
+        res = gst_pad_stop_task (sinkpad);
+      }
+      break;
+    default:
+      res = FALSE;
+      break;
+  }
+  return res;
+}
+
+#ifdef HAVE_ZLIB
+static void *
+qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
+{
+  guint8 *buffer;
+  z_stream z;
+  int ret;
+
+  memset (&z, 0, sizeof (z));
+  z.zalloc = NULL;
+  z.zfree = NULL;
+  z.opaque = NULL;
+
+  if ((ret = inflateInit (&z)) != Z_OK) {
+    GST_ERROR ("inflateInit() returned %d", ret);
+    return NULL;
+  }
+
+  z.next_in = z_buffer;
+  z.avail_in = z_length;
+
+  buffer = (guint8 *) g_malloc (*length);
+  z.avail_out = *length;
+  z.next_out = (Bytef *) buffer;
+  do {
+    ret = inflate (&z, Z_NO_FLUSH);
+    if (ret == Z_STREAM_END) {
+      break;
+    } else if (ret != Z_OK) {
+      GST_WARNING ("inflate() returned %d", ret);
+      break;
+    }
+
+    *length += 4096;
+    buffer = (guint8 *) g_realloc (buffer, *length);
+    z.next_out = (Bytef *) (buffer + z.total_out);
+    z.avail_out += 4096;
+  } while (z.avail_in > 0);
+
+  if (ret != Z_STREAM_END) {
+    g_free (buffer);
+    buffer = NULL;
+    *length = 0;
+  } else {
+    *length = z.total_out;
+  }
+
+  inflateEnd (&z);
+
+  return buffer;
+}
+#endif /* HAVE_ZLIB */
+
+static gboolean
+qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
+{
+  GNode *cmov;
+
+  qtdemux->moov_node = g_node_new ((guint8 *) buffer);
+
+  /* counts as header data */
+  qtdemux->header_size += length;
+
+  GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
+  qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
+
+  cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
+  if (cmov) {
+    guint32 method;
+    GNode *dcom;
+    GNode *cmvd;
+    guint32 dcom_len;
+
+    dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
+    cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
+    if (dcom == NULL || cmvd == NULL)
+      goto invalid_compression;
+
+    dcom_len = QT_UINT32 (dcom->data);
+    if (dcom_len < 12)
+      goto invalid_compression;
+
+    method = QT_FOURCC ((guint8 *) dcom->data + 8);
+    switch (method) {
+#ifdef HAVE_ZLIB
+      case FOURCC_zlib:{
+        guint uncompressed_length;
+        guint compressed_length;
+        guint8 *buf;
+        guint32 cmvd_len;
+
+        cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
+        if (cmvd_len < 12)
+          goto invalid_compression;
+
+        uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
+        compressed_length = cmvd_len - 12;
+        GST_LOG ("length = %u", uncompressed_length);
+
+        buf =
+            (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
+            compressed_length, &uncompressed_length);
+
+        if (buf) {
+          qtdemux->moov_node_compressed = qtdemux->moov_node;
+          qtdemux->moov_node = g_node_new (buf);
+
+          qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
+              uncompressed_length);
+        }
+        break;
+      }
+#endif /* HAVE_ZLIB */
+      default:
+        GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
+            "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
+        break;
+    }
+  }
+  return TRUE;
+
+  /* ERRORS */
+invalid_compression:
+  {
+    GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
+    return FALSE;
+  }
+}
+
+static gboolean
+qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
+    const guint8 * end)
+{
+  while (G_UNLIKELY (buf < end)) {
+    GNode *child;
+    guint32 len;
+
+    if (G_UNLIKELY (buf + 4 > end)) {
+      GST_LOG_OBJECT (qtdemux, "buffer overrun");
+      break;
+    }
+    len = QT_UINT32 (buf);
+    if (G_UNLIKELY (len == 0)) {
+      GST_LOG_OBJECT (qtdemux, "empty container");
+      break;
+    }
+    if (G_UNLIKELY (len < 8)) {
+      GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
+      break;
+    }
+    if (G_UNLIKELY (len > (end - buf))) {
+      GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
+          (gint) (end - buf));
+      break;
+    }
+
+    child = g_node_new ((guint8 *) buf);
+    g_node_append (node, child);
+    GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
+    qtdemux_parse_node (qtdemux, child, buf, len);
+
+    buf += len;
+  }
+  return TRUE;
+}
+
+static gboolean
+qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    GNode * xdxt)
+{
+  int len = QT_UINT32 (xdxt->data);
+  guint8 *buf = xdxt->data;
+  guint8 *end = buf + len;
+  GstBuffer *buffer;
+
+  /* skip size and type */
+  buf += 8;
+  end -= 8;
+
+  while (buf < end) {
+    gint size;
+    guint32 type;
+
+    size = QT_UINT32 (buf);
+    type = QT_FOURCC (buf + 4);
+
+    GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
+
+    if (buf + size > end || size <= 0)
+      break;
+
+    buf += 8;
+    size -= 8;
+
+    GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
+        GST_FOURCC_ARGS (type));
+
+    switch (type) {
+      case FOURCC_tCtH:
+        buffer = gst_buffer_new_and_alloc (size);
+        gst_buffer_fill (buffer, 0, buf, size);
+        stream->buffers = g_slist_append (stream->buffers, buffer);
+        GST_LOG_OBJECT (qtdemux, "parsing theora header");
+        break;
+      case FOURCC_tCt_:
+        buffer = gst_buffer_new_and_alloc (size);
+        gst_buffer_fill (buffer, 0, buf, size);
+        stream->buffers = g_slist_append (stream->buffers, buffer);
+        GST_LOG_OBJECT (qtdemux, "parsing theora comment");
+        break;
+      case FOURCC_tCtC:
+        buffer = gst_buffer_new_and_alloc (size);
+        gst_buffer_fill (buffer, 0, buf, size);
+        stream->buffers = g_slist_append (stream->buffers, buffer);
+        GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
+        break;
+      default:
+        GST_WARNING_OBJECT (qtdemux,
+            "unknown theora cookie %" GST_FOURCC_FORMAT,
+            GST_FOURCC_ARGS (type));
+        break;
+    }
+    buf += size;
+  }
+  return TRUE;
+}
+
+static gboolean
+qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
+    guint length)
+{
+  guint32 fourcc = 0;
+  guint32 node_length = 0;
+  const QtNodeType *type;
+  const guint8 *end;
+
+  GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
+
+  if (G_UNLIKELY (length < 8))
+    goto not_enough_data;
+
+  node_length = QT_UINT32 (buffer);
+  fourcc = QT_FOURCC (buffer + 4);
+
+  /* ignore empty nodes */
+  if (G_UNLIKELY (fourcc == 0 || node_length == 8))
+    return TRUE;
+
+  type = qtdemux_type_get (fourcc);
+
+  end = buffer + length;
+
+  GST_LOG_OBJECT (qtdemux,
+      "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
+      GST_FOURCC_ARGS (fourcc), node_length, type->name);
+
+  if (node_length > length)
+    goto broken_atom_size;
+
+  if (type->flags & QT_FLAG_CONTAINER) {
+    qtdemux_parse_container (qtdemux, node, buffer + 8, end);
+  } else {
+    switch (fourcc) {
+      case FOURCC_stsd:
+      {
+        if (node_length < 20) {
+          GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
+          break;
+        }
+        GST_DEBUG_OBJECT (qtdemux,
+            "parsing stsd (sample table, sample description) atom");
+        /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
+        qtdemux_parse_container (qtdemux, node, buffer + 16, end);
+        break;
+      }
+      case FOURCC_mp4a:
+      case FOURCC_alac:
+      case FOURCC_fLaC:
+      {
+        guint32 version;
+        guint32 offset;
+        guint min_size;
+
+        /* also read alac (or whatever) in stead of mp4a in the following,
+         * since a similar layout is used in other cases as well */
+        if (fourcc == FOURCC_mp4a)
+          min_size = 20;
+        else if (fourcc == FOURCC_fLaC)
+          min_size = 86;
+        else
+          min_size = 40;
+
+        /* There are two things we might encounter here: a true mp4a atom, and
+           an mp4a entry in an stsd atom. The latter is what we're interested
+           in, and it looks like an atom, but isn't really one. The true mp4a
+           atom is short, so we detect it based on length here. */
+        if (length < min_size) {
+          GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
+              GST_FOURCC_ARGS (fourcc));
+          break;
+        }
+
+        /* 'version' here is the sound sample description version. Types 0 and
+           1 are documented in the QTFF reference, but type 2 is not: it's
+           described in Apple header files instead (struct SoundDescriptionV2
+           in Movies.h) */
+        version = QT_UINT16 (buffer + 16);
+
+        GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
+            GST_FOURCC_ARGS (fourcc), version);
+
+        /* parse any esds descriptors */
+        switch (version) {
+          case 0:
+            offset = 0x24;
+            break;
+          case 1:
+            offset = 0x34;
+            break;
+          case 2:
+            offset = 0x48;
+            break;
+          default:
+            GST_WARNING_OBJECT (qtdemux,
+                "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
+                GST_FOURCC_ARGS (fourcc), version);
+            offset = 0;
+            break;
+        }
+        if (offset)
+          qtdemux_parse_container (qtdemux, node, buffer + offset, end);
+        break;
+      }
+      case FOURCC_mp4v:
+      case FOURCC_MP4V:
+      case FOURCC_fmp4:
+      case FOURCC_FMP4:
+      case FOURCC_apcs:
+      case FOURCC_apch:
+      case FOURCC_apcn:
+      case FOURCC_apco:
+      case FOURCC_ap4h:
+      case FOURCC_xvid:
+      case FOURCC_XVID:
+      case FOURCC_H264:
+      case FOURCC_avc1:
+      case FOURCC_avc3:
+      case FOURCC_H265:
+      case FOURCC_hvc1:
+      case FOURCC_hev1:
+      case FOURCC_mjp2:
+      case FOURCC_encv:
+      {
+        guint32 version;
+        guint32 str_len;
+
+        /* codec_data is contained inside these atoms, which all have
+         * the same format. */
+        /* video sample description size is 86 bytes without extension.
+         * node_length have to be bigger than 86 bytes because video sample
+         * description can include extenstions such as esds, fiel, glbl, etc. */
+        if (node_length < 86) {
+          GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
+              " sample description length too short (%u < 86)",
+              GST_FOURCC_ARGS (fourcc), node_length);
+          break;
+        }
+
+        GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
+            GST_FOURCC_ARGS (fourcc));
+
+        /* version (2 bytes) : this is set to 0, unless a compressor has changed
+         *              its data format.
+         * revision level (2 bytes) : must be set to 0. */
+        version = QT_UINT32 (buffer + 16);
+        GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
+
+        /* compressor name : PASCAL string and informative purposes
+         * first byte : the number of bytes to be displayed.
+         *              it has to be less than 32 because it is reserved
+         *              space of 32 bytes total including itself. */
+        str_len = QT_UINT8 (buffer + 50);
+        if (str_len < 32)
+          GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
+              (char *) buffer + 51);
+        else
+          GST_WARNING_OBJECT (qtdemux,
+              "compressorname length too big (%u > 31)", str_len);
+
+        GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
+            end - buffer);
+        qtdemux_parse_container (qtdemux, node, buffer + 86, end);
+        break;
+      }
+      case FOURCC_meta:
+      {
+        GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
+
+        /* You are reading this correctly. QTFF specifies that the
+         * metadata atom is a short atom, whereas ISO BMFF specifies
+         * it's a full atom. But since so many people are doing things
+         * differently, we actually peek into the atom to see which
+         * variant it is */
+        if (length < 16) {
+          GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
+              GST_FOURCC_ARGS (fourcc));
+          break;
+        }
+        if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
+          /* Variant 1: What QTFF specifies. 'meta' is a short header which
+           * starts with a 'hdlr' atom */
+          qtdemux_parse_container (qtdemux, node, buffer + 8, end);
+        } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
+          /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
+           * with version/flags both set to zero */
+          qtdemux_parse_container (qtdemux, node, buffer + 12, end);
+        } else
+          GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
+        break;
+      }
+      case FOURCC_mp4s:
+      {
+        GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
+        /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
+        qtdemux_parse_container (qtdemux, node, buffer + 16, end);
+        break;
+      }
+      case FOURCC_XiTh:
+      {
+        guint32 version;
+        guint32 offset;
+
+        if (length < 16) {
+          GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
+              GST_FOURCC_ARGS (fourcc));
+          break;
+        }
+
+        version = QT_UINT32 (buffer + 12);
+        GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
+
+        switch (version) {
+          case 0x00000001:
+            offset = 0x62;
+            break;
+          default:
+            GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
+            offset = 0;
+            break;
+        }
+        if (offset) {
+          if (length < offset) {
+            GST_WARNING_OBJECT (qtdemux,
+                "skipping too small %" GST_FOURCC_FORMAT " box",
+                GST_FOURCC_ARGS (fourcc));
+            break;
+          }
+          qtdemux_parse_container (qtdemux, node, buffer + offset, end);
+        }
+        break;
+      }
+      case FOURCC_in24:
+      {
+        qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
+        break;
+      }
+      case FOURCC_uuid:
+      {
+        qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
+        break;
+      }
+      case FOURCC_enca:
+      {
+        qtdemux_parse_container (qtdemux, node, buffer + 36, end);
+        break;
+      }
+      default:
+        if (!strcmp (type->name, "unknown"))
+          GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
+        break;
+    }
+  }
+  GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
+      GST_FOURCC_ARGS (fourcc));
+  return TRUE;
+
+/* ERRORS */
+not_enough_data:
+  {
+    GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
+        (_("This file is corrupt and cannot be played.")),
+        ("Not enough data for an atom header, got only %u bytes", length));
+    return FALSE;
+  }
+broken_atom_size:
+  {
+    GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
+        (_("This file is corrupt and cannot be played.")),
+        ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
+            "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
+            length));
+    return FALSE;
+  }
+}
+
+static GNode *
+qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
+{
+  GNode *child;
+  guint8 *buffer;
+  guint32 child_fourcc;
+
+  for (child = g_node_first_child (node); child;
+      child = g_node_next_sibling (child)) {
+    buffer = (guint8 *) child->data;
+
+    child_fourcc = QT_FOURCC (buffer + 4);
+
+    if (G_UNLIKELY (child_fourcc == fourcc)) {
+      return child;
+    }
+  }
+  return NULL;
+}
+
+static GNode *
+qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
+    GstByteReader * parser)
+{
+  GNode *child;
+  guint8 *buffer;
+  guint32 child_fourcc, child_len;
+
+  for (child = g_node_first_child (node); child;
+      child = g_node_next_sibling (child)) {
+    buffer = (guint8 *) child->data;
+
+    child_len = QT_UINT32 (buffer);
+    child_fourcc = QT_FOURCC (buffer + 4);
+
+    if (G_UNLIKELY (child_fourcc == fourcc)) {
+      if (G_UNLIKELY (child_len < (4 + 4)))
+        return NULL;
+      /* FIXME: must verify if atom length < parent atom length */
+      gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
+      return child;
+    }
+  }
+  return NULL;
+}
+
+static GNode *
+qtdemux_tree_get_child_by_index (GNode * node, guint index)
+{
+  return g_node_nth_child (node, index);
+}
+
+static GNode *
+qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
+    GstByteReader * parser)
+{
+  GNode *child;
+  guint8 *buffer;
+  guint32 child_fourcc, child_len;
+
+  for (child = g_node_next_sibling (node); child;
+      child = g_node_next_sibling (child)) {
+    buffer = (guint8 *) child->data;
+
+    child_fourcc = QT_FOURCC (buffer + 4);
+
+    if (child_fourcc == fourcc) {
+      if (parser) {
+        child_len = QT_UINT32 (buffer);
+        if (G_UNLIKELY (child_len < (4 + 4)))
+          return NULL;
+        /* FIXME: must verify if atom length < parent atom length */
+        gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
+      }
+      return child;
+    }
+  }
+  return NULL;
+}
+
+static GNode *
+qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
+{
+  return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
+}
+
+static void
+qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
+{
+/* FIXME: This can only reliably work if demuxers have a
+ * separate streaming thread per srcpad. This should be
+ * done in a demuxer base class, which integrates parts
+ * of multiqueue
+ *
+ * https://bugzilla.gnome.org/show_bug.cgi?id=701856
+ */
+#if 0
+  GstQuery *query;
+
+  query = gst_query_new_allocation (stream->caps, FALSE);
+
+  if (!gst_pad_peer_query (stream->pad, query)) {
+    /* not a problem, just debug a little */
+    GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
+  }
+
+  if (stream->allocator)
+    gst_object_unref (stream->allocator);
+
+  if (gst_query_get_n_allocation_params (query) > 0) {
+    /* try the allocator */
+    gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
+        &stream->params);
+    stream->use_allocator = TRUE;
+  } else {
+    stream->allocator = NULL;
+    gst_allocation_params_init (&stream->params);
+    stream->use_allocator = FALSE;
+  }
+  gst_query_unref (query);
+#endif
+}
+
+static gboolean
+gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
+    QtDemuxStream * stream)
+{
+  GstStructure *s;
+  const gchar *selected_system;
+
+  g_return_val_if_fail (qtdemux != NULL, FALSE);
+  g_return_val_if_fail (stream != NULL, FALSE);
+  g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
+      FALSE);
+
+  if (stream->protection_scheme_type != FOURCC_cenc) {
+    GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
+    return FALSE;
+  }
+  if (qtdemux->protection_system_ids == NULL) {
+    GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
+        "cenc protection system information has been found");
+    return FALSE;
+  }
+  g_ptr_array_add (qtdemux->protection_system_ids, NULL);
+  selected_system = gst_protection_select_system ((const gchar **)
+      qtdemux->protection_system_ids->pdata);
+  g_ptr_array_remove_index (qtdemux->protection_system_ids,
+      qtdemux->protection_system_ids->len - 1);
+  if (!selected_system) {
+    GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
+        "suitable decryptor element has been found");
+    return FALSE;
+  }
+
+  s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
+  if (!gst_structure_has_name (s, "application/x-cenc")) {
+    gst_structure_set (s,
+        "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
+        GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
+        NULL);
+    gst_structure_set_name (s, "application/x-cenc");
+  }
+  return TRUE;
+}
+
+static gboolean
+gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
+{
+  if (stream->subtype == FOURCC_vide) {
+    /* fps is calculated base on the duration of the average framerate since
+     * qt does not have a fixed framerate. */
+    gboolean fps_available = TRUE;
+
+    if ((stream->n_samples == 1 && stream->first_duration == 0)
+        || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
+      /* still frame */
+      CUR_STREAM (stream)->fps_n = 0;
+      CUR_STREAM (stream)->fps_d = 1;
+    } else {
+      if (stream->duration == 0 || stream->n_samples < 2) {
+        CUR_STREAM (stream)->fps_n = stream->timescale;
+        CUR_STREAM (stream)->fps_d = 1;
+        fps_available = FALSE;
+      } else {
+        GstClockTime avg_duration;
+        guint64 duration;
+        guint32 n_samples;
+
+        /* duration and n_samples can be updated for fragmented format
+         * so, framerate of fragmented format is calculated using data in a moof */
+        if (qtdemux->fragmented && stream->n_samples_moof > 0
+            && stream->duration_moof > 0) {
+          n_samples = stream->n_samples_moof;
+          duration = stream->duration_moof;
+        } else {
+          n_samples = stream->n_samples;
+          duration = stream->duration;
+        }
+
+        /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
+        /* stream->duration is guint64, timescale, n_samples are guint32 */
+        avg_duration =
+            gst_util_uint64_scale_round (duration -
+            stream->first_duration, GST_SECOND,
+            (guint64) (stream->timescale) * (n_samples - 1));
+
+        GST_LOG_OBJECT (qtdemux,
+            "Calculating avg sample duration based on stream (or moof) duration %"
+            G_GUINT64_FORMAT
+            " minus first sample %u, leaving %d samples gives %"
+            GST_TIME_FORMAT, duration, stream->first_duration,
+            n_samples - 1, GST_TIME_ARGS (avg_duration));
+
+        gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
+            &CUR_STREAM (stream)->fps_d);
+
+        GST_DEBUG_OBJECT (qtdemux,
+            "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
+            stream->timescale, CUR_STREAM (stream)->fps_n,
+            CUR_STREAM (stream)->fps_d);
+      }
+    }
+
+    if (CUR_STREAM (stream)->caps) {
+      CUR_STREAM (stream)->caps =
+          gst_caps_make_writable (CUR_STREAM (stream)->caps);
+
+      gst_caps_set_simple (CUR_STREAM (stream)->caps,
+          "width", G_TYPE_INT, CUR_STREAM (stream)->width,
+          "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
+
+      /* set framerate if calculated framerate is reliable */
+      if (fps_available) {
+        gst_caps_set_simple (CUR_STREAM (stream)->caps,
+            "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
+            CUR_STREAM (stream)->fps_d, NULL);
+      }
+
+      /* calculate pixel-aspect-ratio using display width and height */
+      GST_DEBUG_OBJECT (qtdemux,
+          "video size %dx%d, target display size %dx%d",
+          CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
+          stream->display_width, stream->display_height);
+      /* qt file might have pasp atom */
+      if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
+        GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
+            CUR_STREAM (stream)->par_h);
+        gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
+            GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
+            CUR_STREAM (stream)->par_h, NULL);
+      } else if (stream->display_width > 0 && stream->display_height > 0
+          && CUR_STREAM (stream)->width > 0
+          && CUR_STREAM (stream)->height > 0) {
+        gint n, d;
+
+        /* calculate the pixel aspect ratio using the display and pixel w/h */
+        n = stream->display_width * CUR_STREAM (stream)->height;
+        d = stream->display_height * CUR_STREAM (stream)->width;
+        if (n == d)
+          n = d = 1;
+        GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
+        CUR_STREAM (stream)->par_w = n;
+        CUR_STREAM (stream)->par_h = d;
+        gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
+            GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
+            CUR_STREAM (stream)->par_h, NULL);
+      }
+
+      if (CUR_STREAM (stream)->interlace_mode > 0) {
+        if (CUR_STREAM (stream)->interlace_mode == 1) {
+          gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
+              G_TYPE_STRING, "progressive", NULL);
+        } else if (CUR_STREAM (stream)->interlace_mode == 2) {
+          gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
+              G_TYPE_STRING, "interleaved", NULL);
+          if (CUR_STREAM (stream)->field_order == 9) {
+            gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
+                G_TYPE_STRING, "top-field-first", NULL);
+          } else if (CUR_STREAM (stream)->field_order == 14) {
+            gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
+                G_TYPE_STRING, "bottom-field-first", NULL);
+          }
+        }
+      }
+
+      /* Create incomplete colorimetry here if needed */
+      if (CUR_STREAM (stream)->colorimetry.range ||
+          CUR_STREAM (stream)->colorimetry.matrix ||
+          CUR_STREAM (stream)->colorimetry.transfer
+          || CUR_STREAM (stream)->colorimetry.primaries) {
+        gchar *colorimetry =
+            gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
+        gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
+            G_TYPE_STRING, colorimetry, NULL);
+        g_free (colorimetry);
+      }
+
+      if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
+        guint par_w = 1, par_h = 1;
+
+        if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
+          par_w = CUR_STREAM (stream)->par_w;
+          par_h = CUR_STREAM (stream)->par_h;
+        }
+
+        if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
+                CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
+                par_h)) {
+          stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
+        }
+
+        gst_caps_set_simple (CUR_STREAM (stream)->caps,
+            "multiview-mode", G_TYPE_STRING,
+            gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
+            "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
+            stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
+      }
+    }
+  }
+
+  else if (stream->subtype == FOURCC_soun) {
+    if (CUR_STREAM (stream)->caps) {
+      CUR_STREAM (stream)->caps =
+          gst_caps_make_writable (CUR_STREAM (stream)->caps);
+      if (CUR_STREAM (stream)->rate > 0)
+        gst_caps_set_simple (CUR_STREAM (stream)->caps,
+            "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
+      if (CUR_STREAM (stream)->n_channels > 0)
+        gst_caps_set_simple (CUR_STREAM (stream)->caps,
+            "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
+      if (CUR_STREAM (stream)->n_channels > 2) {
+        /* FIXME: Need to parse the 'chan' atom to get channel layouts
+         * correctly; this is just the minimum we can do - assume
+         * we don't actually have any channel positions. */
+        gst_caps_set_simple (CUR_STREAM (stream)->caps,
+            "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
+      }
+    }
+  }
+
+  if (stream->pad) {
+    GstCaps *prev_caps = NULL;
+
+    GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
+    gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
+    gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
+    gst_pad_set_active (stream->pad, TRUE);
+
+    gst_pad_use_fixed_caps (stream->pad);
+
+    if (stream->protected) {
+      if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
+        GST_ERROR_OBJECT (qtdemux,
+            "Failed to configure protected stream caps.");
+        return FALSE;
+      }
+    }
+
+    GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
+        CUR_STREAM (stream)->caps);
+    if (stream->new_stream) {
+      gchar *stream_id;
+      GstEvent *event;
+      GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
+
+      event =
+          gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
+          0);
+      if (event) {
+        gst_event_parse_stream_flags (event, &stream_flags);
+        if (gst_event_parse_group_id (event, &qtdemux->group_id))
+          qtdemux->have_group_id = TRUE;
+        else
+          qtdemux->have_group_id = FALSE;
+        gst_event_unref (event);
+      } else if (!qtdemux->have_group_id) {
+        qtdemux->have_group_id = TRUE;
+        qtdemux->group_id = gst_util_group_id_next ();
+      }
+
+      stream->new_stream = FALSE;
+      stream_id =
+          gst_pad_create_stream_id_printf (stream->pad,
+          GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
+      event = gst_event_new_stream_start (stream_id);
+      if (qtdemux->have_group_id)
+        gst_event_set_group_id (event, qtdemux->group_id);
+      if (stream->disabled)
+        stream_flags |= GST_STREAM_FLAG_UNSELECT;
+      if (CUR_STREAM (stream)->sparse) {
+        stream_flags |= GST_STREAM_FLAG_SPARSE;
+      } else {
+        stream_flags &= ~GST_STREAM_FLAG_SPARSE;
+      }
+      gst_event_set_stream_flags (event, stream_flags);
+      gst_pad_push_event (stream->pad, event);
+      g_free (stream_id);
+    }
+
+    prev_caps = gst_pad_get_current_caps (stream->pad);
+
+    if (CUR_STREAM (stream)->caps) {
+      if (!prev_caps
+          || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
+        GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
+            CUR_STREAM (stream)->caps);
+        gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
+      } else {
+        GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
+      }
+    } else {
+      GST_WARNING_OBJECT (qtdemux, "stream without caps");
+    }
+
+    if (prev_caps)
+      gst_caps_unref (prev_caps);
+    stream->new_caps = FALSE;
+  }
+  return TRUE;
+}
+
+static void
+gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
+    QtDemuxStream * stream)
+{
+  if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
+    return;
+
+  GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
+      stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
+  if (G_UNLIKELY (stream->stsd_sample_description_id >=
+          stream->stsd_entries_length)) {
+    GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
+        (_("This file is invalid and cannot be played.")),
+        ("New sample description id is out of bounds (%d >= %d)",
+            stream->stsd_sample_description_id, stream->stsd_entries_length));
+  } else {
+    stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
+    stream->new_caps = TRUE;
+  }
+}
+
+static gboolean
+gst_qtdemux_add_stream (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, GstTagList * list)
+{
+  gboolean ret = TRUE;
+  /* consistent default for push based mode */
+  gst_segment_init (&stream->segment, GST_FORMAT_TIME);
+
+  if (stream->subtype == FOURCC_vide) {
+    gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
+
+    stream->pad =
+        gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
+    g_free (name);
+
+    if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
+      gst_object_unref (stream->pad);
+      stream->pad = NULL;
+      ret = FALSE;
+      goto done;
+    }
+
+    qtdemux->n_video_streams++;
+  } else if (stream->subtype == FOURCC_soun) {
+    gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
+
+    stream->pad =
+        gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
+    g_free (name);
+    if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
+      gst_object_unref (stream->pad);
+      stream->pad = NULL;
+      ret = FALSE;
+      goto done;
+    }
+    qtdemux->n_audio_streams++;
+  } else if (stream->subtype == FOURCC_strm) {
+    GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
+  } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
+      || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
+    gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
+
+    stream->pad =
+        gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
+    g_free (name);
+    if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
+      gst_object_unref (stream->pad);
+      stream->pad = NULL;
+      ret = FALSE;
+      goto done;
+    }
+    qtdemux->n_sub_streams++;
+  } else if (CUR_STREAM (stream)->caps) {
+    gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
+
+    stream->pad =
+        gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
+    g_free (name);
+    if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
+      gst_object_unref (stream->pad);
+      stream->pad = NULL;
+      ret = FALSE;
+      goto done;
+    }
+    qtdemux->n_video_streams++;
+  } else {
+    GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
+    goto done;
+  }
+
+  if (stream->pad) {
+    GList *l;
+
+    GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
+        GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
+    gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
+    gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
+
+    if (stream->stream_tags)
+      gst_tag_list_unref (stream->stream_tags);
+    stream->stream_tags = list;
+    list = NULL;
+    /* global tags go on each pad anyway */
+    stream->send_global_tags = TRUE;
+    /* send upstream GST_EVENT_PROTECTION events that were received before
+       this source pad was created */
+    for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
+      gst_pad_push_event (stream->pad, gst_event_ref (l->data));
+  }
+done:
+  if (list)
+    gst_tag_list_unref (list);
+  return ret;
+}
+
+/* find next atom with @fourcc starting at @offset */
+static GstFlowReturn
+qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
+    guint64 * length, guint32 fourcc)
+{
+  GstFlowReturn ret;
+  guint32 lfourcc;
+  GstBuffer *buf;
+
+  GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
+      G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
+
+  while (TRUE) {
+    GstMapInfo map;
+
+    buf = NULL;
+    ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
+    if (G_UNLIKELY (ret != GST_FLOW_OK))
+      goto locate_failed;
+    if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
+      /* likely EOF */
+      ret = GST_FLOW_EOS;
+      gst_buffer_unref (buf);
+      goto locate_failed;
+    }
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+
+    if (G_UNLIKELY (*length == 0)) {
+      GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
+      ret = GST_FLOW_ERROR;
+      goto locate_failed;
+    }
+
+    if (lfourcc == fourcc) {
+      GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
+          *offset);
+      break;
+    } else {
+      GST_LOG_OBJECT (qtdemux,
+          "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
+          GST_FOURCC_ARGS (fourcc), *offset);
+      *offset += *length;
+    }
+  }
+
+  return GST_FLOW_OK;
+
+locate_failed:
+  {
+    /* might simply have had last one */
+    GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
+    return ret;
+  }
+}
+
+/* should only do something in pull mode */
+/* call with OBJECT lock */
+static GstFlowReturn
+qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
+{
+  guint64 length, offset;
+  GstBuffer *buf = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstFlowReturn res = GST_FLOW_OK;
+  GstMapInfo map;
+
+  offset = qtdemux->moof_offset;
+  GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
+
+  if (!offset) {
+    GST_DEBUG_OBJECT (qtdemux, "no next moof");
+    return GST_FLOW_EOS;
+  }
+
+  /* best not do pull etc with lock held */
+  GST_OBJECT_UNLOCK (qtdemux);
+
+  ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
+  if (ret != GST_FLOW_OK)
+    goto flow_failed;
+
+  ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
+  if (G_UNLIKELY (ret != GST_FLOW_OK))
+    goto flow_failed;
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    buf = NULL;
+    goto parse_failed;
+  }
+
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+  buf = NULL;
+
+  offset += length;
+  /* look for next moof */
+  ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
+  if (G_UNLIKELY (ret != GST_FLOW_OK))
+    goto flow_failed;
+
+exit:
+  GST_OBJECT_LOCK (qtdemux);
+
+  qtdemux->moof_offset = offset;
+
+  return res;
+
+parse_failed:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
+    offset = 0;
+    res = GST_FLOW_ERROR;
+    goto exit;
+  }
+flow_failed:
+  {
+    /* maybe upstream temporarily flushing */
+    if (ret != GST_FLOW_FLUSHING) {
+      GST_DEBUG_OBJECT (qtdemux, "no next moof");
+      offset = 0;
+    } else {
+      GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
+      /* resume at current position next time */
+    }
+    res = ret;
+    goto exit;
+  }
+}
+
+/* initialise bytereaders for stbl sub-atoms */
+static gboolean
+qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
+{
+  stream->stbl_index = -1;      /* no samples have yet been parsed */
+  stream->sample_index = -1;
+
+  /* time-to-sample atom */
+  if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
+    goto corrupt_file;
+
+  /* copy atom data into a new buffer for later use */
+  stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
+
+  /* skip version + flags */
+  if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
+      !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
+    goto corrupt_file;
+  GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
+
+  /* make sure there's enough data */
+  if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
+    stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
+    GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
+        stream->n_sample_times);
+    if (!stream->n_sample_times)
+      goto corrupt_file;
+  }
+
+  /* sync sample atom */
+  stream->stps_present = FALSE;
+  if ((stream->stss_present =
+          ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
+              &stream->stss) ? TRUE : FALSE) == TRUE) {
+    /* copy atom data into a new buffer for later use */
+    stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
+
+    /* skip version + flags */
+    if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
+        !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
+      goto corrupt_file;
+
+    if (stream->n_sample_syncs) {
+      /* make sure there's enough data */
+      if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
+        goto corrupt_file;
+    }
+
+    /* partial sync sample atom */
+    if ((stream->stps_present =
+            ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
+                &stream->stps) ? TRUE : FALSE) == TRUE) {
+      /* copy atom data into a new buffer for later use */
+      stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
+
+      /* skip version + flags */
+      if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
+          !gst_byte_reader_get_uint32_be (&stream->stps,
+              &stream->n_sample_partial_syncs))
+        goto corrupt_file;
+
+      /* if there are no entries, the stss table contains the real
+       * sync samples */
+      if (stream->n_sample_partial_syncs) {
+        /* make sure there's enough data */
+        if (!qt_atom_parser_has_chunks (&stream->stps,
+                stream->n_sample_partial_syncs, 4))
+          goto corrupt_file;
+      }
+    }
+  }
+
+  /* sample size */
+  if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
+    goto no_samples;
+
+  /* copy atom data into a new buffer for later use */
+  stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
+
+  /* skip version + flags */
+  if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
+      !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
+    goto corrupt_file;
+
+  if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
+    goto corrupt_file;
+
+  if (!stream->n_samples)
+    goto no_samples;
+
+  /* sample-to-chunk atom */
+  if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
+    goto corrupt_file;
+
+  /* copy atom data into a new buffer for later use */
+  stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
+
+  /* skip version + flags */
+  if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
+      !gst_byte_reader_get_uint32_be (&stream->stsc,
+          &stream->n_samples_per_chunk))
+    goto corrupt_file;
+
+  GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
+      stream->n_samples_per_chunk);
+
+  /* make sure there's enough data */
+  if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
+          12))
+    goto corrupt_file;
+
+
+  /* chunk offset */
+  if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
+    stream->co_size = sizeof (guint32);
+  else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
+          &stream->stco))
+    stream->co_size = sizeof (guint64);
+  else
+    goto corrupt_file;
+
+  /* copy atom data into a new buffer for later use */
+  stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
+
+  /* skip version + flags */
+  if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
+    goto corrupt_file;
+
+  /* chunks_are_samples == TRUE means treat chunks as samples */
+  stream->chunks_are_samples = stream->sample_size
+      && !CUR_STREAM (stream)->sampled;
+  if (stream->chunks_are_samples) {
+    /* treat chunks as samples */
+    if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
+      goto corrupt_file;
+  } else {
+    /* skip number of entries */
+    if (!gst_byte_reader_skip (&stream->stco, 4))
+      goto corrupt_file;
+
+    /* make sure there are enough data in the stsz atom */
+    if (!stream->sample_size) {
+      /* different sizes for each sample */
+      if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
+        goto corrupt_file;
+    }
+  }
+
+  GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
+      stream->n_samples, (guint) sizeof (QtDemuxSample),
+      stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
+
+  if (stream->n_samples >=
+      QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
+    GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
+        "be larger than %uMB (broken file?)", stream->n_samples,
+        QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
+    return FALSE;
+  }
+
+  g_assert (stream->samples == NULL);
+  stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
+  if (!stream->samples) {
+    GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
+        stream->n_samples);
+    return FALSE;
+  }
+
+  /* composition time-to-sample */
+  if ((stream->ctts_present =
+          ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
+              &stream->ctts) ? TRUE : FALSE) == TRUE) {
+    GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
+
+    /* copy atom data into a new buffer for later use */
+    stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
+
+    /* skip version + flags */
+    if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
+        || !gst_byte_reader_get_uint32_be (&stream->ctts,
+            &stream->n_composition_times))
+      goto corrupt_file;
+
+    /* make sure there's enough data */
+    if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
+            4 + 4))
+      goto corrupt_file;
+
+    /* This is optional, if missing we iterate the ctts */
+    if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
+      if (!gst_byte_reader_skip (&cslg, 1 + 3)
+          || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
+        g_free ((gpointer) cslg.data);
+        goto corrupt_file;
+      }
+    } else {
+      gint32 cslg_least = 0;
+      guint num_entries, pos;
+      gint i;
+
+      pos = gst_byte_reader_get_pos (&stream->ctts);
+      num_entries = stream->n_composition_times;
+
+      stream->cslg_shift = 0;
+
+      for (i = 0; i < num_entries; i++) {
+        gint32 offset;
+
+        gst_byte_reader_skip_unchecked (&stream->ctts, 4);
+        offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
+
+        if (offset < cslg_least)
+          cslg_least = offset;
+      }
+
+      if (cslg_least < 0)
+        stream->cslg_shift = ABS (cslg_least);
+      else
+        stream->cslg_shift = 0;
+
+      /* reset the reader so we can generate sample table */
+      gst_byte_reader_set_pos (&stream->ctts, pos);
+    }
+  } else {
+    /* Ensure the cslg_shift value is consistent so we can use it
+     * unconditionnally to produce TS and Segment */
+    stream->cslg_shift = 0;
+  }
+
+  return TRUE;
+
+corrupt_file:
+  {
+    GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
+        (_("This file is corrupt and cannot be played.")), (NULL));
+    return FALSE;
+  }
+no_samples:
+  {
+    gst_qtdemux_stbl_free (stream);
+    if (!qtdemux->fragmented) {
+      /* not quite good */
+      GST_WARNING_OBJECT (qtdemux, "stream has no samples");
+      return FALSE;
+    } else {
+      /* may pick up samples elsewhere */
+      return TRUE;
+    }
+  }
+}
+
+/* collect samples from the next sample to be parsed up to sample @n for @stream
+ * by reading the info from @stbl
+ *
+ * This code can be executed from both the streaming thread and the seeking
+ * thread so it takes the object lock to protect itself
+ */
+static gboolean
+qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
+{
+  gint i, j, k;
+  QtDemuxSample *samples, *first, *cur, *last;
+  guint32 n_samples_per_chunk;
+  guint32 n_samples;
+
+  GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
+      GST_FOURCC_FORMAT ", pad %s",
+      GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
+      stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
+
+  n_samples = stream->n_samples;
+
+  if (n >= n_samples)
+    goto out_of_samples;
+
+  GST_OBJECT_LOCK (qtdemux);
+  if (n <= stream->stbl_index)
+    goto already_parsed;
+
+  GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
+
+  if (!stream->stsz.data) {
+    /* so we already parsed and passed all the moov samples;
+     * onto fragmented ones */
+    g_assert (qtdemux->fragmented);
+    goto done;
+  }
+
+  /* pointer to the sample table */
+  samples = stream->samples;
+
+  /* starts from -1, moves to the next sample index to parse */
+  stream->stbl_index++;
+
+  /* keep track of the first and last sample to fill */
+  first = &samples[stream->stbl_index];
+  last = &samples[n];
+
+  if (!stream->chunks_are_samples) {
+    /* set the sample sizes */
+    if (stream->sample_size == 0) {
+      /* different sizes for each sample */
+      for (cur = first; cur <= last; cur++) {
+        cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
+        GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
+            (guint) (cur - samples), cur->size);
+      }
+    } else {
+      /* samples have the same size */
+      GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
+      for (cur = first; cur <= last; cur++)
+        cur->size = stream->sample_size;
+    }
+  }
+
+  n_samples_per_chunk = stream->n_samples_per_chunk;
+  cur = first;
+
+  for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
+    guint32 last_chunk;
+
+    if (stream->stsc_chunk_index >= stream->last_chunk
+        || stream->stsc_chunk_index < stream->first_chunk) {
+      stream->first_chunk =
+          gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
+      stream->samples_per_chunk =
+          gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
+      /* starts from 1 */
+      stream->stsd_sample_description_id =
+          gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
+
+      /* chunk numbers are counted from 1 it seems */
+      if (G_UNLIKELY (stream->first_chunk == 0))
+        goto corrupt_file;
+
+      --stream->first_chunk;
+
+      /* the last chunk of each entry is calculated by taking the first chunk
+       * of the next entry; except if there is no next, where we fake it with
+       * INT_MAX */
+      if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
+        stream->last_chunk = G_MAXUINT32;
+      } else {
+        stream->last_chunk =
+            gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
+        if (G_UNLIKELY (stream->last_chunk == 0))
+          goto corrupt_file;
+
+        --stream->last_chunk;
+      }
+
+      GST_LOG_OBJECT (qtdemux,
+          "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
+          "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
+          stream->samples_per_chunk, stream->stsd_sample_description_id);
+
+      if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
+        goto corrupt_file;
+
+      if (stream->last_chunk != G_MAXUINT32) {
+        if (!qt_atom_parser_peek_sub (&stream->stco,
+                stream->first_chunk * stream->co_size,
+                (stream->last_chunk - stream->first_chunk) * stream->co_size,
+                &stream->co_chunk))
+          goto corrupt_file;
+
+      } else {
+        stream->co_chunk = stream->stco;
+        if (!gst_byte_reader_skip (&stream->co_chunk,
+                stream->first_chunk * stream->co_size))
+          goto corrupt_file;
+      }
+
+      stream->stsc_chunk_index = stream->first_chunk;
+    }
+
+    last_chunk = stream->last_chunk;
+
+    if (stream->chunks_are_samples) {
+      cur = &samples[stream->stsc_chunk_index];
+
+      for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
+        if (j > n) {
+          /* save state */
+          stream->stsc_chunk_index = j;
+          goto done;
+        }
+
+        cur->offset =
+            qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
+            stream->co_size);
+
+        GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
+            "%" G_GUINT64_FORMAT, j, cur->offset);
+
+        if (CUR_STREAM (stream)->samples_per_frame > 0 &&
+            CUR_STREAM (stream)->bytes_per_frame > 0) {
+          cur->size =
+              (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
+              CUR_STREAM (stream)->samples_per_frame *
+              CUR_STREAM (stream)->bytes_per_frame;
+        } else {
+          cur->size = stream->samples_per_chunk;
+        }
+
+        GST_DEBUG_OBJECT (qtdemux,
+            "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
+            j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
+                    stream->stco_sample_index)), cur->size);
+
+        cur->timestamp = stream->stco_sample_index;
+        cur->duration = stream->samples_per_chunk;
+        cur->keyframe = TRUE;
+        cur++;
+
+        stream->stco_sample_index += stream->samples_per_chunk;
+      }
+      stream->stsc_chunk_index = j;
+    } else {
+      for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
+        guint32 samples_per_chunk;
+        guint64 chunk_offset;
+
+        if (!stream->stsc_sample_index
+            && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
+                &stream->chunk_offset))
+          goto corrupt_file;
+
+        samples_per_chunk = stream->samples_per_chunk;
+        chunk_offset = stream->chunk_offset;
+
+        for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
+          GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
+              G_GUINT64_FORMAT " and size %d",
+              (guint) (cur - samples), chunk_offset, cur->size);
+
+          cur->offset = chunk_offset;
+          chunk_offset += cur->size;
+          cur++;
+
+          if (G_UNLIKELY (cur > last)) {
+            /* save state */
+            stream->stsc_sample_index = k + 1;
+            stream->chunk_offset = chunk_offset;
+            stream->stsc_chunk_index = j;
+            goto done2;
+          }
+        }
+        stream->stsc_sample_index = 0;
+      }
+      stream->stsc_chunk_index = j;
+    }
+    stream->stsc_index++;
+  }
+
+  if (stream->chunks_are_samples)
+    goto ctts;
+done2:
+  {
+    guint32 n_sample_times;
+
+    n_sample_times = stream->n_sample_times;
+    cur = first;
+
+    for (i = stream->stts_index; i < n_sample_times; i++) {
+      guint32 stts_samples;
+      gint32 stts_duration;
+      gint64 stts_time;
+
+      if (stream->stts_sample_index >= stream->stts_samples
+          || !stream->stts_sample_index) {
+
+        stream->stts_samples =
+            gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
+        stream->stts_duration =
+            gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
+
+        GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
+            i, stream->stts_samples, stream->stts_duration);
+
+        stream->stts_sample_index = 0;
+      }
+
+      stts_samples = stream->stts_samples;
+      stts_duration = stream->stts_duration;
+      stts_time = stream->stts_time;
+
+      for (j = stream->stts_sample_index; j < stts_samples; j++) {
+        GST_DEBUG_OBJECT (qtdemux,
+            "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
+            (guint) (cur - samples), j,
+            GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
+
+        cur->timestamp = stts_time;
+        cur->duration = stts_duration;
+
+        /* avoid 32-bit wrap-around,
+         * but still mind possible 'negative' duration */
+        stts_time += (gint64) stts_duration;
+        cur++;
+
+        if (G_UNLIKELY (cur > last)) {
+          /* save values */
+          stream->stts_time = stts_time;
+          stream->stts_sample_index = j + 1;
+          if (stream->stts_sample_index >= stream->stts_samples)
+            stream->stts_index++;
+          goto done3;
+        }
+      }
+      stream->stts_sample_index = 0;
+      stream->stts_time = stts_time;
+      stream->stts_index++;
+    }
+    /* fill up empty timestamps with the last timestamp, this can happen when
+     * the last samples do not decode and so we don't have timestamps for them.
+     * We however look at the last timestamp to estimate the track length so we
+     * need something in here. */
+    for (; cur < last; cur++) {
+      GST_DEBUG_OBJECT (qtdemux,
+          "fill sample %d: timestamp %" GST_TIME_FORMAT,
+          (guint) (cur - samples),
+          GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
+      cur->timestamp = stream->stts_time;
+      cur->duration = -1;
+    }
+  }
+done3:
+  {
+    /* sample sync, can be NULL */
+    if (stream->stss_present == TRUE) {
+      guint32 n_sample_syncs;
+
+      n_sample_syncs = stream->n_sample_syncs;
+
+      if (!n_sample_syncs) {
+        GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
+        stream->all_keyframe = TRUE;
+      } else {
+        for (i = stream->stss_index; i < n_sample_syncs; i++) {
+          /* note that the first sample is index 1, not 0 */
+          guint32 index;
+
+          index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
+
+          if (G_LIKELY (index > 0 && index <= n_samples)) {
+            index -= 1;
+            samples[index].keyframe = TRUE;
+            GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
+            /* and exit if we have enough samples */
+            if (G_UNLIKELY (index >= n)) {
+              i++;
+              break;
+            }
+          }
+        }
+        /* save state */
+        stream->stss_index = i;
+      }
+
+      /* stps marks partial sync frames like open GOP I-Frames */
+      if (stream->stps_present == TRUE) {
+        guint32 n_sample_partial_syncs;
+
+        n_sample_partial_syncs = stream->n_sample_partial_syncs;
+
+        /* if there are no entries, the stss table contains the real
+         * sync samples */
+        if (n_sample_partial_syncs) {
+          for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
+            /* note that the first sample is index 1, not 0 */
+            guint32 index;
+
+            index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
+
+            if (G_LIKELY (index > 0 && index <= n_samples)) {
+              index -= 1;
+              samples[index].keyframe = TRUE;
+              GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
+              /* and exit if we have enough samples */
+              if (G_UNLIKELY (index >= n)) {
+                i++;
+                break;
+              }
+            }
+          }
+          /* save state */
+          stream->stps_index = i;
+        }
+      }
+    } else {
+      /* no stss, all samples are keyframes */
+      stream->all_keyframe = TRUE;
+      GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
+    }
+  }
+
+ctts:
+  /* composition time to sample */
+  if (stream->ctts_present == TRUE) {
+    guint32 n_composition_times;
+    guint32 ctts_count;
+    gint32 ctts_soffset;
+
+    /* Fill in the pts_offsets */
+    cur = first;
+    n_composition_times = stream->n_composition_times;
+
+    for (i = stream->ctts_index; i < n_composition_times; i++) {
+      if (stream->ctts_sample_index >= stream->ctts_count
+          || !stream->ctts_sample_index) {
+        stream->ctts_count =
+            gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
+        stream->ctts_soffset =
+            gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
+        stream->ctts_sample_index = 0;
+      }
+
+      ctts_count = stream->ctts_count;
+      ctts_soffset = stream->ctts_soffset;
+
+      for (j = stream->ctts_sample_index; j < ctts_count; j++) {
+        cur->pts_offset = ctts_soffset;
+        cur++;
+
+        if (G_UNLIKELY (cur > last)) {
+          /* save state */
+          stream->ctts_sample_index = j + 1;
+          goto done;
+        }
+      }
+      stream->ctts_sample_index = 0;
+      stream->ctts_index++;
+    }
+  }
+done:
+  stream->stbl_index = n;
+  /* if index has been completely parsed, free data that is no-longer needed */
+  if (n + 1 == stream->n_samples) {
+    gst_qtdemux_stbl_free (stream);
+    GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
+    if (qtdemux->pullbased) {
+      GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
+      while (n + 1 == stream->n_samples)
+        if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
+          break;
+    }
+  }
+  GST_OBJECT_UNLOCK (qtdemux);
+
+  return TRUE;
+
+  /* SUCCESS */
+already_parsed:
+  {
+    GST_LOG_OBJECT (qtdemux,
+        "Tried to parse up to sample %u but this sample has already been parsed",
+        n);
+    /* if fragmented, there may be more */
+    if (qtdemux->fragmented && n == stream->stbl_index)
+      goto done;
+    GST_OBJECT_UNLOCK (qtdemux);
+    return TRUE;
+  }
+  /* ERRORS */
+out_of_samples:
+  {
+    GST_LOG_OBJECT (qtdemux,
+        "Tried to parse up to sample %u but there are only %u samples", n + 1,
+        stream->n_samples);
+    GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
+        (_("This file is corrupt and cannot be played.")), (NULL));
+    return FALSE;
+  }
+corrupt_file:
+  {
+    GST_OBJECT_UNLOCK (qtdemux);
+    GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
+        (_("This file is corrupt and cannot be played.")), (NULL));
+    return FALSE;
+  }
+}
+
+/* collect all segment info for @stream.
+ */
+static gboolean
+qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    GNode * trak)
+{
+  GNode *edts;
+  /* accept edts if they contain gaps at start and there is only
+   * one media segment */
+  gboolean allow_pushbased_edts = TRUE;
+  gint media_segments_count = 0;
+
+  /* parse and prepare segment info from the edit list */
+  GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
+  stream->n_segments = 0;
+  stream->segments = NULL;
+  if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
+    GNode *elst;
+    gint n_segments;
+    gint i, count, entry_size;
+    guint64 time;
+    GstClockTime stime;
+    const guint8 *buffer;
+    guint8 version;
+    guint32 size;
+
+    GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
+    if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
+      goto done;
+
+    buffer = elst->data;
+
+    size = QT_UINT32 (buffer);
+    /* version, flags, n_segments */
+    if (size < 16) {
+      GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
+      goto done;
+    }
+    version = QT_UINT8 (buffer + 8);
+    entry_size = (version == 1) ? 20 : 12;
+
+    n_segments = QT_UINT32 (buffer + 12);
+
+    if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
+      GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
+      goto done;
+    }
+
+    /* we might allocate a bit too much, at least allocate 1 segment */
+    stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
+
+    /* segments always start from 0 */
+    time = 0;
+    stime = 0;
+    count = 0;
+    buffer += 16;
+    for (i = 0; i < n_segments; i++) {
+      guint64 duration;
+      guint64 media_time;
+      gboolean time_valid = TRUE;
+      QtDemuxSegment *segment;
+      guint32 rate_int;
+      GstClockTime media_start = GST_CLOCK_TIME_NONE;
+
+      if (version == 1) {
+        media_time = QT_UINT64 (buffer + 8);
+        duration = QT_UINT64 (buffer);
+        if (media_time == G_MAXUINT64)
+          time_valid = FALSE;
+      } else {
+        media_time = QT_UINT32 (buffer + 4);
+        duration = QT_UINT32 (buffer);
+        if (media_time == G_MAXUINT32)
+          time_valid = FALSE;
+      }
+
+      if (time_valid)
+        media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
+
+      segment = &stream->segments[count++];
+
+      /* time and duration expressed in global timescale */
+      segment->time = stime;
+      /* add non scaled values so we don't cause roundoff errors */
+      if (duration || media_start == GST_CLOCK_TIME_NONE) {
+        time += duration;
+        stime = QTTIME_TO_GSTTIME (qtdemux, time);
+        segment->duration = stime - segment->time;
+      } else {
+        /* zero duration does not imply media_start == media_stop
+         * but, only specify media_start.*/
+        stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
+        if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
+            && stime >= media_start) {
+          segment->duration = stime - media_start;
+        } else {
+          segment->duration = GST_CLOCK_TIME_NONE;
+        }
+      }
+      segment->stop_time = stime;
+
+      segment->trak_media_start = media_time;
+      /* media_time expressed in stream timescale */
+      if (time_valid) {
+        segment->media_start = media_start;
+        segment->media_stop = segment->media_start + segment->duration;
+        media_segments_count++;
+      } else {
+        segment->media_start = GST_CLOCK_TIME_NONE;
+        segment->media_stop = GST_CLOCK_TIME_NONE;
+      }
+      rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
+
+      if (rate_int <= 1) {
+        /* 0 is not allowed, some programs write 1 instead of the floating point
+         * value */
+        GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
+            rate_int);
+        segment->rate = 1;
+      } else {
+        segment->rate = rate_int / 65536.0;
+      }
+
+      GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
+          ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
+          " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
+          " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
+          i, GST_TIME_ARGS (segment->time),
+          GST_TIME_ARGS (segment->duration),
+          GST_TIME_ARGS (segment->media_start), media_time,
+          GST_TIME_ARGS (segment->media_stop),
+          GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
+          stream->timescale);
+      if (segment->stop_time > qtdemux->segment.stop) {
+        GST_WARNING_OBJECT (qtdemux, "Segment %d "
+            " extends to %" GST_TIME_FORMAT
+            " past the end of the file duration %" GST_TIME_FORMAT
+            " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
+            GST_TIME_ARGS (qtdemux->segment.stop));
+        qtdemux->segment.stop = segment->stop_time;
+      }
+
+      buffer += entry_size;
+    }
+    GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
+    stream->n_segments = count;
+    if (media_segments_count != 1)
+      allow_pushbased_edts = FALSE;
+  }
+done:
+
+  /* push based does not handle segments, so act accordingly here,
+   * and warn if applicable */
+  if (!qtdemux->pullbased && !allow_pushbased_edts) {
+    GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
+    /* remove and use default one below, we stream like it anyway */
+    g_free (stream->segments);
+    stream->segments = NULL;
+    stream->n_segments = 0;
+  }
+
+  /* no segments, create one to play the complete trak */
+  if (stream->n_segments == 0) {
+    GstClockTime stream_duration =
+        QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
+
+    if (stream->segments == NULL)
+      stream->segments = g_new (QtDemuxSegment, 1);
+
+    /* represent unknown our way */
+    if (stream_duration == 0)
+      stream_duration = GST_CLOCK_TIME_NONE;
+
+    stream->segments[0].time = 0;
+    stream->segments[0].stop_time = stream_duration;
+    stream->segments[0].duration = stream_duration;
+    stream->segments[0].media_start = 0;
+    stream->segments[0].media_stop = stream_duration;
+    stream->segments[0].rate = 1.0;
+    stream->segments[0].trak_media_start = 0;
+
+    GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (stream_duration));
+    stream->n_segments = 1;
+    stream->dummy_segment = TRUE;
+  }
+  GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
+
+  return TRUE;
+}
+
+/*
+ * Parses the stsd atom of a svq3 trak looking for
+ * the SMI and gama atoms.
+ */
+static void
+qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
+    const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
+{
+  const guint8 *_gamma = NULL;
+  GstBuffer *_seqh = NULL;
+  const guint8 *stsd_data = stsd_entry_data;
+  guint32 length = QT_UINT32 (stsd_data);
+  guint16 version;
+
+  if (length < 32) {
+    GST_WARNING_OBJECT (qtdemux, "stsd too short");
+    goto end;
+  }
+
+  stsd_data += 16;
+  length -= 16;
+  version = QT_UINT16 (stsd_data);
+  if (version == 3) {
+    if (length >= 70) {
+      length -= 70;
+      stsd_data += 70;
+      while (length > 8) {
+        guint32 fourcc, size;
+        const guint8 *data;
+        size = QT_UINT32 (stsd_data);
+        fourcc = QT_FOURCC (stsd_data + 4);
+        data = stsd_data + 8;
+
+        if (size == 0) {
+          GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
+              "svq3 atom parsing");
+          goto end;
+        }
+
+        switch (fourcc) {
+          case FOURCC_gama:{
+            if (size == 12) {
+              _gamma = data;
+            } else {
+              GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
+                  " for gama atom, expected 12", size);
+            }
+            break;
+          }
+          case FOURCC_SMI_:{
+            if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
+              guint32 seqh_size;
+              if (_seqh != NULL) {
+                GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
+                    " found, ignoring");
+              } else {
+                seqh_size = QT_UINT32 (data + 4);
+                if (seqh_size > 0) {
+                  _seqh = gst_buffer_new_and_alloc (seqh_size);
+                  gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
+                }
+              }
+            }
+            break;
+          }
+          default:{
+            GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
+                " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
+          }
+        }
+
+        if (size <= length) {
+          length -= size;
+          stsd_data += size;
+        }
+      }
+    } else {
+      GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
+    }
+  } else {
+    GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
+        G_GUINT16_FORMAT, version);
+    goto end;
+  }
+
+end:
+  if (gamma) {
+    *gamma = _gamma;
+  }
+  if (seqh) {
+    *seqh = _seqh;
+  } else if (_seqh) {
+    gst_buffer_unref (_seqh);
+  }
+}
+
+static gchar *
+qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
+{
+  GNode *dinf;
+  GstByteReader dref;
+  gchar *uri = NULL;
+
+  /*
+   * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
+   * atom that might contain a 'data' atom with the rtsp uri.
+   * This case was reported in bug #597497, some info about
+   * the hndl atom can be found in TN1195
+   */
+  dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
+  GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
+
+  if (dinf) {
+    guint32 dref_num_entries = 0;
+    if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
+        gst_byte_reader_skip (&dref, 4) &&
+        gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
+      gint i;
+
+      /* search dref entries for hndl atom */
+      for (i = 0; i < dref_num_entries; i++) {
+        guint32 size = 0, type;
+        guint8 string_len = 0;
+        if (gst_byte_reader_get_uint32_be (&dref, &size) &&
+            qt_atom_parser_get_fourcc (&dref, &type)) {
+          if (type == FOURCC_hndl) {
+            GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
+
+            /* skip data reference handle bytes and the
+             * following pascal string and some extra 4
+             * bytes I have no idea what are */
+            if (!gst_byte_reader_skip (&dref, 4) ||
+                !gst_byte_reader_get_uint8 (&dref, &string_len) ||
+                !gst_byte_reader_skip (&dref, string_len + 4)) {
+              GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
+              break;
+            }
+
+            /* iterate over the atoms to find the data atom */
+            while (gst_byte_reader_get_remaining (&dref) >= 8) {
+              guint32 atom_size;
+              guint32 atom_type;
+
+              if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
+                  qt_atom_parser_get_fourcc (&dref, &atom_type)) {
+                if (atom_type == FOURCC_data) {
+                  const guint8 *uri_aux = NULL;
+
+                  /* found the data atom that might contain the rtsp uri */
+                  GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
+                      "hndl atom, interpreting it as an URI");
+                  if (gst_byte_reader_peek_data (&dref, atom_size - 8,
+                          &uri_aux)) {
+                    if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
+                      uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
+                    else
+                      GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
+                          "didn't contain a rtsp address");
+                  } else {
+                    GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
+                        "atom contents");
+                  }
+                  break;
+                }
+                /* skipping to the next entry */
+                if (!gst_byte_reader_skip (&dref, atom_size - 8))
+                  break;
+              } else {
+                GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
+                    "atom header");
+                break;
+              }
+            }
+            break;
+          }
+          /* skip to the next entry */
+          if (!gst_byte_reader_skip (&dref, size - 8))
+            break;
+        } else {
+          GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
+        }
+      }
+      GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
+    }
+  }
+  return uri;
+}
+
+#define AMR_NB_ALL_MODES        0x81ff
+#define AMR_WB_ALL_MODES        0x83ff
+static guint
+qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
+{
+  /* The 'damr' atom is of the form:
+   *
+   * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
+   *    32 b       8 b          16 b           8 b                 8 b
+   *
+   * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
+   * represents the highest mode used in the stream (and thus the maximum
+   * bitrate), with a couple of special cases as seen below.
+   */
+
+  /* Map of frame type ID -> bitrate */
+  static const guint nb_bitrates[] = {
+    4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
+  };
+  static const guint wb_bitrates[] = {
+    6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
+  };
+  GstMapInfo map;
+  gsize max_mode;
+  guint16 mode_set;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  if (map.size != 0x11) {
+    GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
+    goto bad_data;
+  }
+
+  if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
+    GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
+        GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
+    goto bad_data;
+  }
+
+  mode_set = QT_UINT16 (map.data + 13);
+
+  if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
+    max_mode = 7 + (wb ? 1 : 0);
+  else
+    /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
+    max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
+
+  if (max_mode == -1) {
+    GST_DEBUG ("No mode indication was found (mode set) = %x",
+        (guint) mode_set);
+    goto bad_data;
+  }
+
+  gst_buffer_unmap (buf, &map);
+  return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
+
+bad_data:
+  gst_buffer_unmap (buf, &map);
+  return 0;
+}
+
+static gboolean
+qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
+    GstByteReader * reader, guint32 * matrix, const gchar * atom)
+{
+  /*
+   * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
+   * [0 1 2]
+   * [3 4 5]
+   * [6 7 8]
+   */
+
+  if (gst_byte_reader_get_remaining (reader) < 36)
+    return FALSE;
+
+  matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
+  matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
+  matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
+  matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
+  matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
+  matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
+  matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
+  matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
+  matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
+
+  GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
+  GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
+      matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
+      matrix[2] & 0xFF);
+  GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
+      matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
+      matrix[5] & 0xFF);
+  GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
+      matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
+      matrix[8] & 0xFF);
+
+  return TRUE;
+}
+
+static void
+qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
+{
+
+/* [a b c]
+ * [d e f]
+ * [g h i]
+ *
+ * This macro will only compare value abdegh, it expects cfi to have already
+ * been checked
+ */
+#define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
+                                   (m)[3] == (d << 16) && (m)[4] == (e << 16))
+
+  /* only handle the cases where the last column has standard values */
+  if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
+    const gchar *rotation_tag = NULL;
+
+    /* no rotation needed */
+    if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
+      /* NOP */
+    } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
+      rotation_tag = "rotate-90";
+    } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
+      rotation_tag = "rotate-180";
+    } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
+      rotation_tag = "rotate-270";
+    } else {
+      GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
+    }
+
+    GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
+        rotation_tag);
+    if (rotation_tag != NULL) {
+      if (*taglist == NULL)
+        *taglist = gst_tag_list_new_empty ();
+      gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
+          GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
+    }
+  } else {
+    GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
+  }
+}
+
+/* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
+ * protected streams (sinf, frma, schm and schi); if the protection scheme is
+ * Common Encryption (cenc), the function will also parse the tenc box (defined
+ * in ISO/IEC 23001-7). @container points to the node that contains these boxes
+ * (typically an enc[v|a|t|s] sample entry); the function will set
+ * @original_fmt to the fourcc of the original unencrypted stream format.
+ * Returns TRUE if successful; FALSE otherwise. */
+static gboolean
+qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
+{
+  GNode *sinf;
+  GNode *frma;
+  GNode *schm;
+  GNode *schi;
+
+  g_return_val_if_fail (qtdemux != NULL, FALSE);
+  g_return_val_if_fail (stream != NULL, FALSE);
+  g_return_val_if_fail (container != NULL, FALSE);
+  g_return_val_if_fail (original_fmt != NULL, FALSE);
+
+  sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
+  if (G_UNLIKELY (!sinf)) {
+    if (stream->protection_scheme_type == FOURCC_cenc) {
+      GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
+          "mandatory for Common Encryption");
+      return FALSE;
+    }
+    return TRUE;
+  }
+
+  frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
+  if (G_UNLIKELY (!frma)) {
+    GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
+    return FALSE;
+  }
+
+  *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
+  GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
+      GST_FOURCC_ARGS (*original_fmt));
+
+  schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
+  if (!schm) {
+    GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
+    return FALSE;
+  }
+  stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
+  stream->protection_scheme_version =
+      QT_UINT32 ((const guint8 *) schm->data + 16);
+
+  GST_DEBUG_OBJECT (qtdemux,
+      "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
+      "protection_scheme_version: %#010x",
+      GST_FOURCC_ARGS (stream->protection_scheme_type),
+      stream->protection_scheme_version);
+
+  schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
+  if (!schi) {
+    GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
+    return FALSE;
+  }
+  if (stream->protection_scheme_type == FOURCC_cenc) {
+    QtDemuxCencSampleSetInfo *info;
+    GNode *tenc;
+    const guint8 *tenc_data;
+    guint32 isEncrypted;
+    guint8 iv_size;
+    const guint8 *default_kid;
+    GstBuffer *kid_buf;
+
+    if (G_UNLIKELY (!stream->protection_scheme_info))
+      stream->protection_scheme_info =
+          g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
+
+    info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
+
+    tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
+    if (!tenc) {
+      GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
+          "which is mandatory for Common Encryption");
+      return FALSE;
+    }
+    tenc_data = (const guint8 *) tenc->data + 12;
+    isEncrypted = QT_UINT24 (tenc_data);
+    iv_size = QT_UINT8 (tenc_data + 3);
+    default_kid = (tenc_data + 4);
+    kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
+    gst_buffer_fill (kid_buf, 0, default_kid, 16);
+    if (info->default_properties)
+      gst_structure_free (info->default_properties);
+    info->default_properties =
+        gst_structure_new ("application/x-cenc",
+        "iv_size", G_TYPE_UINT, iv_size,
+        "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
+        "kid", GST_TYPE_BUFFER, kid_buf, NULL);
+    GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
+        "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
+    gst_buffer_unref (kid_buf);
+  }
+  return TRUE;
+}
+
+/* parse the traks.
+ * With each track we associate a new QtDemuxStream that contains all the info
+ * about the trak.
+ * traks that do not decode to something (like strm traks) will not have a pad.
+ */
+static gboolean
+qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
+{
+  GstByteReader tkhd;
+  int offset;
+  GNode *mdia;
+  GNode *mdhd;
+  GNode *hdlr;
+  GNode *minf;
+  GNode *stbl;
+  GNode *stsd;
+  GNode *mp4a;
+  GNode *mp4v;
+  GNode *esds;
+  GNode *tref;
+  GNode *udta;
+  GNode *svmi;
+
+  QtDemuxStream *stream = NULL;
+  gboolean new_stream = FALSE;
+  const guint8 *stsd_data;
+  const guint8 *stsd_entry_data;
+  guint remaining_stsd_len;
+  guint stsd_entry_count;
+  guint stsd_index;
+  guint16 lang_code;            /* quicktime lang code or packed iso code */
+  guint32 version;
+  guint32 tkhd_flags = 0;
+  guint8 tkhd_version = 0;
+  guint32 w = 0, h = 0;
+  guint value_size, stsd_len, len;
+  guint32 track_id;
+  guint32 dummy;
+
+  GST_DEBUG_OBJECT (qtdemux, "parse_trak");
+
+  if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
+      || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
+      || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
+    goto corrupt_file;
+
+  /* pick between 64 or 32 bits */
+  value_size = tkhd_version == 1 ? 8 : 4;
+  if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
+      !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
+    goto corrupt_file;
+
+  if (!qtdemux->got_moov) {
+    if (qtdemux_find_stream (qtdemux, track_id))
+      goto existing_stream;
+    stream = _create_stream ();
+    stream->track_id = track_id;
+    new_stream = TRUE;
+  } else {
+    stream = qtdemux_find_stream (qtdemux, track_id);
+    if (!stream) {
+      GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
+      goto skip_track;
+    }
+
+    /* reset reused stream */
+    gst_qtdemux_stream_reset (qtdemux, stream);
+  }
+  /* need defaults for fragments */
+  qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
+
+  if ((tkhd_flags & 1) == 0)
+    stream->disabled = TRUE;
+
+  GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
+      tkhd_version, tkhd_flags, stream->track_id);
+
+  if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
+    goto corrupt_file;
+
+  if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
+    /* be nice for some crooked mjp2 files that use mhdr for mdhd */
+    if (qtdemux->major_brand != FOURCC_mjp2 ||
+        !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
+      goto corrupt_file;
+  }
+
+  len = QT_UINT32 ((guint8 *) mdhd->data);
+  version = QT_UINT32 ((guint8 *) mdhd->data + 8);
+  GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
+  if (version == 0x01000000) {
+    if (len < 38)
+      goto corrupt_file;
+    stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
+    stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
+    lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
+  } else {
+    if (len < 30)
+      goto corrupt_file;
+    stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
+    stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
+    lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
+  }
+
+  if (lang_code < 0x400) {
+    qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
+  } else if (lang_code == 0x7fff) {
+    stream->lang_id[0] = 0;     /* unspecified */
+  } else {
+    stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
+    stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
+    stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
+    stream->lang_id[3] = 0;
+  }
+
+  GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
+      stream->timescale);
+  GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
+      stream->duration);
+  GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
+      lang_code, stream->lang_id);
+
+  if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
+    goto corrupt_file;
+
+  if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
+    /* chapters track reference */
+    GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
+    if (chap) {
+      gsize length = GST_READ_UINT32_BE (chap->data);
+      if (qtdemux->chapters_track_id)
+        GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
+
+      if (length >= 12) {
+        qtdemux->chapters_track_id =
+            GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
+      }
+    }
+  }
+
+  /* fragmented files may have bogus duration in moov */
+  if (!qtdemux->fragmented &&
+      qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
+    guint64 tdur1, tdur2;
+
+    /* don't overflow */
+    tdur1 = stream->timescale * (guint64) qtdemux->duration;
+    tdur2 = qtdemux->timescale * (guint64) stream->duration;
+
+    /* HACK:
+     * some of those trailers, nowadays, have prologue images that are
+     * themselves video tracks as well. I haven't really found a way to
+     * identify those yet, except for just looking at their duration. */
+    if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
+      GST_WARNING_OBJECT (qtdemux,
+          "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
+          " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
+          "found, assuming preview image or something; skipping track",
+          stream->duration, stream->timescale, qtdemux->duration,
+          qtdemux->timescale);
+      if (new_stream)
+        gst_qtdemux_stream_free (qtdemux, stream);
+      return TRUE;
+    }
+  }
+
+  if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
+    goto corrupt_file;
+
+  GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
+      GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
+
+  len = QT_UINT32 ((guint8 *) hdlr->data);
+  if (len >= 20)
+    stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
+  GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
+      GST_FOURCC_ARGS (stream->subtype));
+
+  if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
+    goto corrupt_file;
+
+  if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
+    goto corrupt_file;
+
+  /*parse svmi header if existing */
+  svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
+  if (svmi) {
+    len = QT_UINT32 ((guint8 *) svmi->data);
+    version = QT_UINT32 ((guint8 *) svmi->data + 8);
+    if (!version) {
+      GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
+      GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
+      guint8 frame_type, frame_layout;
+
+      /* MPEG-A stereo video */
+      if (qtdemux->major_brand == FOURCC_ss02)
+        flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
+
+      frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
+      frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
+      switch (frame_type) {
+        case 0:
+          mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
+          break;
+        case 1:
+          mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
+          break;
+        case 2:
+          mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
+          break;
+        case 3:
+          /* mode 3 is primary/secondary view sequence, ie
+           * left/right views in separate tracks. See section 7.2
+           * of ISO/IEC 23000-11:2009 */
+          GST_FIXME_OBJECT (qtdemux,
+              "Implement stereo video in separate streams");
+      }
+
+      if ((frame_layout & 0x1) == 0)
+        flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
+
+      GST_LOG_OBJECT (qtdemux,
+          "StereoVideo: composition type: %u, is_left_first: %u",
+          frame_type, frame_layout);
+      stream->multiview_mode = mode;
+      stream->multiview_flags = flags;
+    }
+  }
+
+  /* parse rest of tkhd */
+  if (stream->subtype == FOURCC_vide) {
+    guint32 matrix[9];
+
+    /* version 1 uses some 64-bit ints */
+    if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
+      goto corrupt_file;
+
+    if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
+      goto corrupt_file;
+
+    if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
+        || !gst_byte_reader_get_uint32_be (&tkhd, &h))
+      goto corrupt_file;
+
+    qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
+        &stream->stream_tags);
+  }
+
+  /* parse stsd */
+  if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
+    goto corrupt_file;
+  stsd_data = (const guint8 *) stsd->data;
+
+  /* stsd should at least have one entry */
+  stsd_len = QT_UINT32 (stsd_data);
+  if (stsd_len < 24) {
+    /* .. but skip stream with empty stsd produced by some Vivotek cameras */
+    if (stream->subtype == FOURCC_vivo) {
+      if (new_stream)
+        gst_qtdemux_stream_free (qtdemux, stream);
+      return TRUE;
+    } else {
+      goto corrupt_file;
+    }
+  }
+
+  stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
+  stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
+  GST_LOG_OBJECT (qtdemux, "stsd len:           %d", stsd_len);
+  GST_LOG_OBJECT (qtdemux, "stsd entry count:   %u", stsd_entry_count);
+
+  stsd_entry_data = stsd_data + 16;
+  remaining_stsd_len = stsd_len - 16;
+  for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
+    guint32 fourcc;
+    gchar *codec = NULL;
+    QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
+
+    /* and that entry should fit within stsd */
+    len = QT_UINT32 (stsd_entry_data);
+    if (len > remaining_stsd_len)
+      goto corrupt_file;
+
+    entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
+    GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
+        GST_FOURCC_ARGS (entry->fourcc));
+    GST_LOG_OBJECT (qtdemux, "stsd type len:      %d", len);
+
+    if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
+      goto error_encrypted;
+
+    if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
+      /* FIXME this looks wrong, there might be multiple children
+       * with the same type */
+      GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
+      stream->protected = TRUE;
+      if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
+        GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
+    }
+
+    if (stream->subtype == FOURCC_vide) {
+      GNode *colr;
+      GNode *fiel;
+      GNode *pasp;
+      gboolean gray;
+      gint depth, palette_size, palette_count;
+      guint32 *palette_data = NULL;
+
+      entry->sampled = TRUE;
+
+      stream->display_width = w >> 16;
+      stream->display_height = h >> 16;
+
+      offset = 16;
+      if (len < 86)             /* TODO verify */
+        goto corrupt_file;
+
+      entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
+      entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
+      entry->fps_n = 0;         /* this is filled in later */
+      entry->fps_d = 0;         /* this is filled in later */
+      entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
+      entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
+
+      /* if color_table_id is 0, ctab atom must follow; however some files
+       * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
+       * if color table is not present we'll correct the value */
+      if (entry->color_table_id == 0 &&
+          (len < 90
+              || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
+        entry->color_table_id = -1;
+      }
+
+      GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
+          entry->width, entry->height, entry->bits_per_sample,
+          entry->color_table_id);
+
+      depth = entry->bits_per_sample;
+
+      /* more than 32 bits means grayscale */
+      gray = (depth > 32);
+      /* low 32 bits specify the depth  */
+      depth &= 0x1F;
+
+      /* different number of palette entries is determined by depth. */
+      palette_count = 0;
+      if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
+        palette_count = (1 << depth);
+      palette_size = palette_count * 4;
+
+      if (entry->color_table_id) {
+        switch (palette_count) {
+          case 0:
+            break;
+          case 2:
+            palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
+            break;
+          case 4:
+            palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
+            break;
+          case 16:
+            if (gray)
+              palette_data =
+                  g_memdup (ff_qt_grayscale_palette_16, palette_size);
+            else
+              palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
+            break;
+          case 256:
+            if (gray)
+              palette_data =
+                  g_memdup (ff_qt_grayscale_palette_256, palette_size);
+            else
+              palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
+            break;
+          default:
+            GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
+                (_("The video in this file might not play correctly.")),
+                ("unsupported palette depth %d", depth));
+            break;
+        }
+      } else {
+        gint i, j, start, end;
+
+        if (len < 94)
+          goto corrupt_file;
+
+        /* read table */
+        start = QT_UINT32 (stsd_entry_data + offset + 70);
+        palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
+        end = QT_UINT16 (stsd_entry_data + offset + 76);
+
+        GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
+            start, end, palette_count);
+
+        if (end > 255)
+          end = 255;
+        if (start > end)
+          start = end;
+
+        if (len < 94 + (end - start) * 8)
+          goto corrupt_file;
+
+        /* palette is always the same size */
+        palette_data = g_malloc0 (256 * 4);
+        palette_size = 256 * 4;
+
+        for (j = 0, i = start; i <= end; j++, i++) {
+          guint32 a, r, g, b;
+
+          a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
+          r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
+          g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
+          b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
+
+          palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
+              (g & 0xff00) | (b >> 8);
+        }
+      }
+
+      if (entry->caps)
+        gst_caps_unref (entry->caps);
+
+      entry->caps =
+          qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
+          &codec);
+      if (G_UNLIKELY (!entry->caps)) {
+        g_free (palette_data);
+        goto unknown_stream;
+      }
+
+      if (codec) {
+        gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
+            GST_TAG_VIDEO_CODEC, codec, NULL);
+        g_free (codec);
+        codec = NULL;
+      }
+
+      if (palette_data) {
+        GstStructure *s;
+
+        if (entry->rgb8_palette)
+          gst_memory_unref (entry->rgb8_palette);
+        entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+            palette_data, palette_size, 0, palette_size, palette_data, g_free);
+
+        s = gst_caps_get_structure (entry->caps, 0);
+
+        /* non-raw video has a palette_data property. raw video has the palette as
+         * an extra plane that we append to the output buffers before we push
+         * them*/
+        if (!gst_structure_has_name (s, "video/x-raw")) {
+          GstBuffer *palette;
+
+          palette = gst_buffer_new ();
+          gst_buffer_append_memory (palette, entry->rgb8_palette);
+          entry->rgb8_palette = NULL;
+
+          gst_caps_set_simple (entry->caps, "palette_data",
+              GST_TYPE_BUFFER, palette, NULL);
+          gst_buffer_unref (palette);
+        }
+      } else if (palette_count != 0) {
+        GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
+            (NULL), ("Unsupported palette depth %d", depth));
+      }
+
+      GST_LOG_OBJECT (qtdemux, "frame count:   %u",
+          QT_UINT16 (stsd_entry_data + offset + 32));
+
+      esds = NULL;
+      pasp = NULL;
+      colr = NULL;
+      fiel = NULL;
+      /* pick 'the' stsd child */
+      mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
+      if (!stream->protected) {
+        if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
+          mp4v = NULL;
+        }
+      } else {
+        if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
+          mp4v = NULL;
+        }
+      }
+
+      if (mp4v) {
+        esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
+        pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
+        colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
+        fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
+      }
+
+      if (pasp) {
+        const guint8 *pasp_data = (const guint8 *) pasp->data;
+        gint len = QT_UINT32 (pasp_data);
+
+        if (len == 16) {
+          CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
+          CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
+        } else {
+          CUR_STREAM (stream)->par_w = 0;
+          CUR_STREAM (stream)->par_h = 0;
+        }
+      } else {
+        CUR_STREAM (stream)->par_w = 0;
+        CUR_STREAM (stream)->par_h = 0;
+      }
+
+      if (fiel) {
+        const guint8 *fiel_data = (const guint8 *) fiel->data;
+        gint len = QT_UINT32 (fiel_data);
+
+        if (len == 10) {
+          CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
+          CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
+        }
+      }
+
+      if (colr) {
+        const guint8 *colr_data = (const guint8 *) colr->data;
+        gint len = QT_UINT32 (colr_data);
+
+        if (len == 19 || len == 18) {
+          guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
+
+          if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
+            guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
+            guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
+            guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
+            gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
+
+            switch (primaries) {
+              case 1:
+                CUR_STREAM (stream)->colorimetry.primaries =
+                    GST_VIDEO_COLOR_PRIMARIES_BT709;
+                break;
+              case 5:
+                CUR_STREAM (stream)->colorimetry.primaries =
+                    GST_VIDEO_COLOR_PRIMARIES_BT470BG;
+                break;
+              case 6:
+                CUR_STREAM (stream)->colorimetry.primaries =
+                    GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
+                break;
+              case 9:
+                CUR_STREAM (stream)->colorimetry.primaries =
+                    GST_VIDEO_COLOR_PRIMARIES_BT2020;
+                break;
+              default:
+                break;
+            }
+
+            switch (transfer_function) {
+              case 1:
+                CUR_STREAM (stream)->colorimetry.transfer =
+                    GST_VIDEO_TRANSFER_BT709;
+                break;
+              case 7:
+                CUR_STREAM (stream)->colorimetry.transfer =
+                    GST_VIDEO_TRANSFER_SMPTE240M;
+                break;
+              default:
+                break;
+            }
+
+            switch (matrix) {
+              case 1:
+                CUR_STREAM (stream)->colorimetry.matrix =
+                    GST_VIDEO_COLOR_MATRIX_BT709;
+                break;
+              case 6:
+                CUR_STREAM (stream)->colorimetry.matrix =
+                    GST_VIDEO_COLOR_MATRIX_BT601;
+                break;
+              case 7:
+                CUR_STREAM (stream)->colorimetry.matrix =
+                    GST_VIDEO_COLOR_MATRIX_SMPTE240M;
+                break;
+              case 9:
+                CUR_STREAM (stream)->colorimetry.matrix =
+                    GST_VIDEO_COLOR_MATRIX_BT2020;
+                break;
+              default:
+                break;
+            }
+
+            CUR_STREAM (stream)->colorimetry.range =
+                full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
+                GST_VIDEO_COLOR_RANGE_16_235;
+          } else {
+            GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
+          }
+        } else {
+          GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
+        }
+      }
+
+      if (esds) {
+        gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
+            stream->stream_tags);
+      } else {
+        switch (fourcc) {
+          case FOURCC_H264:
+          case FOURCC_avc1:
+          case FOURCC_avc3:
+          {
+            gint len = QT_UINT32 (stsd_entry_data) - 0x56;
+            const guint8 *avc_data = stsd_entry_data + 0x56;
+
+            /* find avcC */
+            while (len >= 0x8) {
+              gint size;
+
+              if (QT_UINT32 (avc_data) <= len)
+                size = QT_UINT32 (avc_data) - 0x8;
+              else
+                size = len - 0x8;
+
+              if (size < 1)
+                /* No real data, so break out */
+                break;
+
+              switch (QT_FOURCC (avc_data + 0x4)) {
+                case FOURCC_avcC:
+                {
+                  /* parse, if found */
+                  GstBuffer *buf;
+
+                  GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
+
+                  /* First 4 bytes are the length of the atom, the next 4 bytes
+                   * are the fourcc, the next 1 byte is the version, and the
+                   * subsequent bytes are profile_tier_level structure like data. */
+                  gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
+                      avc_data + 8 + 1, size - 1);
+                  buf = gst_buffer_new_and_alloc (size);
+                  gst_buffer_fill (buf, 0, avc_data + 0x8, size);
+                  gst_caps_set_simple (entry->caps,
+                      "codec_data", GST_TYPE_BUFFER, buf, NULL);
+                  gst_buffer_unref (buf);
+
+                  break;
+                }
+                case FOURCC_strf:
+                {
+                  GstBuffer *buf;
+
+                  GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
+
+                  /* First 4 bytes are the length of the atom, the next 4 bytes
+                   * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
+                   * next 1 byte is the version, and the
+                   * subsequent bytes are sequence parameter set like data. */
+
+                  size -= 40;   /* we'll be skipping BITMAPINFOHEADER */
+                  if (size > 1) {
+                    gst_codec_utils_h264_caps_set_level_and_profile
+                        (entry->caps, avc_data + 8 + 40 + 1, size - 1);
+
+                    buf = gst_buffer_new_and_alloc (size);
+                    gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
+                    gst_caps_set_simple (entry->caps,
+                        "codec_data", GST_TYPE_BUFFER, buf, NULL);
+                    gst_buffer_unref (buf);
+                  }
+                  break;
+                }
+                case FOURCC_btrt:
+                {
+                  guint avg_bitrate, max_bitrate;
+
+                  /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
+                  if (size < 12)
+                    break;
+
+                  max_bitrate = QT_UINT32 (avc_data + 0xc);
+                  avg_bitrate = QT_UINT32 (avc_data + 0x10);
+
+                  if (!max_bitrate && !avg_bitrate)
+                    break;
+
+                  /* Some muxers seem to swap the average and maximum bitrates
+                   * (I'm looking at you, YouTube), so we swap for sanity. */
+                  if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
+                    guint temp = avg_bitrate;
+
+                    avg_bitrate = max_bitrate;
+                    max_bitrate = temp;
+                  }
+
+                  if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
+                    gst_tag_list_add (stream->stream_tags,
+                        GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
+                        max_bitrate, NULL);
+                  }
+                  if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
+                    gst_tag_list_add (stream->stream_tags,
+                        GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
+                        NULL);
+                  }
+
+                  break;
+                }
+
+                default:
+                  break;
+              }
+
+              len -= size + 8;
+              avc_data += size + 8;
+            }
+
+            break;
+          }
+          case FOURCC_H265:
+          case FOURCC_hvc1:
+          case FOURCC_hev1:
+          {
+            gint len = QT_UINT32 (stsd_entry_data) - 0x56;
+            const guint8 *hevc_data = stsd_entry_data + 0x56;
+
+            /* find hevc */
+            while (len >= 0x8) {
+              gint size;
+
+              if (QT_UINT32 (hevc_data) <= len)
+                size = QT_UINT32 (hevc_data) - 0x8;
+              else
+                size = len - 0x8;
+
+              if (size < 1)
+                /* No real data, so break out */
+                break;
+
+              switch (QT_FOURCC (hevc_data + 0x4)) {
+                case FOURCC_hvcC:
+                {
+                  /* parse, if found */
+                  GstBuffer *buf;
+
+                  GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
+
+                  /* First 4 bytes are the length of the atom, the next 4 bytes
+                   * are the fourcc, the next 1 byte is the version, and the
+                   * subsequent bytes are sequence parameter set like data. */
+                  gst_codec_utils_h265_caps_set_level_tier_and_profile
+                      (entry->caps, hevc_data + 8 + 1, size - 1);
+
+                  buf = gst_buffer_new_and_alloc (size);
+                  gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
+                  gst_caps_set_simple (entry->caps,
+                      "codec_data", GST_TYPE_BUFFER, buf, NULL);
+                  gst_buffer_unref (buf);
+                  break;
+                }
+                default:
+                  break;
+              }
+              len -= size + 8;
+              hevc_data += size + 8;
+            }
+            break;
+          }
+          case FOURCC_mp4v:
+          case FOURCC_MP4V:
+          case FOURCC_fmp4:
+          case FOURCC_FMP4:
+          case FOURCC_xvid:
+          case FOURCC_XVID:
+          {
+            GNode *glbl;
+
+            GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
+                GST_FOURCC_ARGS (fourcc));
+
+            /* codec data might be in glbl extension atom */
+            glbl = mp4v ?
+                qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
+            if (glbl) {
+              guint8 *data;
+              GstBuffer *buf;
+              gint len;
+
+              GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
+              data = glbl->data;
+              len = QT_UINT32 (data);
+              if (len > 0x8) {
+                len -= 0x8;
+                buf = gst_buffer_new_and_alloc (len);
+                gst_buffer_fill (buf, 0, data + 8, len);
+                gst_caps_set_simple (entry->caps,
+                    "codec_data", GST_TYPE_BUFFER, buf, NULL);
+                gst_buffer_unref (buf);
+              }
+            }
+            break;
+          }
+          case FOURCC_mjp2:
+          {
+            /* see annex I of the jpeg2000 spec */
+            GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
+            const guint8 *data;
+            const gchar *colorspace = NULL;
+            gint ncomp = 0;
+            guint32 ncomp_map = 0;
+            gint32 *comp_map = NULL;
+            guint32 nchan_def = 0;
+            gint32 *chan_def = NULL;
+
+            GST_DEBUG_OBJECT (qtdemux, "found mjp2");
+            /* some required atoms */
+            mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
+            if (!mjp2)
+              break;
+            jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
+            if (!jp2h)
+              break;
+
+            /* number of components; redundant with info in codestream, but useful
+               to a muxer */
+            ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
+            if (!ihdr || QT_UINT32 (ihdr->data) != 22)
+              break;
+            ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
+
+            colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
+            if (!colr)
+              break;
+            GST_DEBUG_OBJECT (qtdemux, "found colr");
+            /* extract colour space info */
+            if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
+              switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
+                case 16:
+                  colorspace = "sRGB";
+                  break;
+                case 17:
+                  colorspace = "GRAY";
+                  break;
+                case 18:
+                  colorspace = "sYUV";
+                  break;
+                default:
+                  colorspace = NULL;
+                  break;
+              }
+            }
+            if (!colorspace)
+              /* colr is required, and only values 16, 17, and 18 are specified,
+                 so error if we have no colorspace */
+              break;
+
+            /* extract component mapping */
+            cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
+            if (cmap) {
+              guint32 cmap_len = 0;
+              int i;
+              cmap_len = QT_UINT32 (cmap->data);
+              if (cmap_len >= 8) {
+                /* normal box, subtract off header */
+                cmap_len -= 8;
+                /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
+                if (cmap_len % 4 == 0) {
+                  ncomp_map = (cmap_len / 4);
+                  comp_map = g_new0 (gint32, ncomp_map);
+                  for (i = 0; i < ncomp_map; i++) {
+                    guint16 cmp;
+                    guint8 mtyp, pcol;
+                    cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
+                    mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
+                    pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
+                    comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
+                  }
+                }
+              }
+            }
+            /* extract channel definitions */
+            cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
+            if (cdef) {
+              guint32 cdef_len = 0;
+              int i;
+              cdef_len = QT_UINT32 (cdef->data);
+              if (cdef_len >= 10) {
+                /* normal box, subtract off header and len */
+                cdef_len -= 10;
+                /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
+                if (cdef_len % 6 == 0) {
+                  nchan_def = (cdef_len / 6);
+                  chan_def = g_new0 (gint32, nchan_def);
+                  for (i = 0; i < nchan_def; i++)
+                    chan_def[i] = -1;
+                  for (i = 0; i < nchan_def; i++) {
+                    guint16 cn, typ, asoc;
+                    cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
+                    typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
+                    asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
+                    if (cn < nchan_def) {
+                      switch (typ) {
+                        case 0:
+                          chan_def[cn] = asoc;
+                          break;
+                        case 1:
+                          chan_def[cn] = 0;     /* alpha */
+                          break;
+                        default:
+                          chan_def[cn] = -typ;
+                      }
+                    }
+                  }
+                }
+              }
+            }
+
+            gst_caps_set_simple (entry->caps,
+                "num-components", G_TYPE_INT, ncomp, NULL);
+            gst_caps_set_simple (entry->caps,
+                "colorspace", G_TYPE_STRING, colorspace, NULL);
+
+            if (comp_map) {
+              GValue arr = { 0, };
+              GValue elt = { 0, };
+              int i;
+              g_value_init (&arr, GST_TYPE_ARRAY);
+              g_value_init (&elt, G_TYPE_INT);
+              for (i = 0; i < ncomp_map; i++) {
+                g_value_set_int (&elt, comp_map[i]);
+                gst_value_array_append_value (&arr, &elt);
+              }
+              gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
+                  "component-map", &arr);
+              g_value_unset (&elt);
+              g_value_unset (&arr);
+              g_free (comp_map);
+            }
+
+            if (chan_def) {
+              GValue arr = { 0, };
+              GValue elt = { 0, };
+              int i;
+              g_value_init (&arr, GST_TYPE_ARRAY);
+              g_value_init (&elt, G_TYPE_INT);
+              for (i = 0; i < nchan_def; i++) {
+                g_value_set_int (&elt, chan_def[i]);
+                gst_value_array_append_value (&arr, &elt);
+              }
+              gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
+                  "channel-definitions", &arr);
+              g_value_unset (&elt);
+              g_value_unset (&arr);
+              g_free (chan_def);
+            }
+
+            /* some optional atoms */
+            field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
+            prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
+
+            /* indicate possible fields in caps */
+            if (field) {
+              data = (guint8 *) field->data + 8;
+              if (*data != 1)
+                gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
+                    (gint) * data, NULL);
+            }
+            /* add codec_data if provided */
+            if (prefix) {
+              GstBuffer *buf;
+              gint len;
+
+              GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
+              data = prefix->data;
+              len = QT_UINT32 (data);
+              if (len > 0x8) {
+                len -= 0x8;
+                buf = gst_buffer_new_and_alloc (len);
+                gst_buffer_fill (buf, 0, data + 8, len);
+                gst_caps_set_simple (entry->caps,
+                    "codec_data", GST_TYPE_BUFFER, buf, NULL);
+                gst_buffer_unref (buf);
+              }
+            }
+            break;
+          }
+          case FOURCC_SVQ3:
+          case FOURCC_VP31:
+          {
+            GstBuffer *buf;
+            GstBuffer *seqh = NULL;
+            const guint8 *gamma_data = NULL;
+            gint len = QT_UINT32 (stsd_data);   /* FIXME review - why put the whole stsd in codec data? */
+
+            qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
+                &seqh);
+            if (gamma_data) {
+              gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
+                  QT_FP32 (gamma_data), NULL);
+            }
+            if (seqh) {
+              /* sorry for the bad name, but we don't know what this is, other
+               * than its own fourcc */
+              gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
+                  NULL);
+              gst_buffer_unref (seqh);
+            }
+
+            GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
+            buf = gst_buffer_new_and_alloc (len);
+            gst_buffer_fill (buf, 0, stsd_data, len);
+            gst_caps_set_simple (entry->caps,
+                "codec_data", GST_TYPE_BUFFER, buf, NULL);
+            gst_buffer_unref (buf);
+            break;
+          }
+          case FOURCC_jpeg:
+          {
+            /* https://developer.apple.com/standards/qtff-2001.pdf,
+             * page 92, "Video Sample Description", under table 3.1 */
+            GstByteReader br;
+
+            const gint compressor_offset =
+                16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
+            const gint min_size = compressor_offset + 32 + 2 + 2;
+            GNode *jpeg;
+            guint32 len;
+            guint16 color_table_id = 0;
+            gboolean ok;
+
+            GST_DEBUG_OBJECT (qtdemux, "found jpeg");
+
+            /* recover information on interlaced/progressive */
+            jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
+            if (!jpeg)
+              break;
+
+            len = QT_UINT32 (jpeg->data);
+            GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
+                min_size);
+            if (len >= min_size) {
+              gst_byte_reader_init (&br, jpeg->data, len);
+
+              gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
+              gst_byte_reader_get_uint16_le (&br, &color_table_id);
+              if (color_table_id != 0) {
+                /* the spec says there can be concatenated chunks in the data, and we want
+                 * to find one called field. Walk through them. */
+                gint offset = min_size;
+                while (offset + 8 < len) {
+                  guint32 size = 0, tag;
+                  ok = gst_byte_reader_get_uint32_le (&br, &size);
+                  ok &= gst_byte_reader_get_uint32_le (&br, &tag);
+                  if (!ok || size < 8) {
+                    GST_WARNING_OBJECT (qtdemux,
+                        "Failed to walk optional chunk list");
+                    break;
+                  }
+                  GST_DEBUG_OBJECT (qtdemux,
+                      "Found optional %4.4s chunk, size %u",
+                      (const char *) &tag, size);
+                  if (tag == FOURCC_fiel) {
+                    guint8 n_fields = 0, ordering = 0;
+                    gst_byte_reader_get_uint8 (&br, &n_fields);
+                    gst_byte_reader_get_uint8 (&br, &ordering);
+                    if (n_fields == 1 || n_fields == 2) {
+                      GST_DEBUG_OBJECT (qtdemux,
+                          "Found fiel tag with %u fields, ordering %u",
+                          n_fields, ordering);
+                      if (n_fields == 2)
+                        gst_caps_set_simple (CUR_STREAM (stream)->caps,
+                            "interlace-mode", G_TYPE_STRING, "interleaved",
+                            NULL);
+                    } else {
+                      GST_WARNING_OBJECT (qtdemux,
+                          "Found fiel tag with invalid fields (%u)", n_fields);
+                    }
+                  }
+                  offset += size;
+                }
+              } else {
+                GST_DEBUG_OBJECT (qtdemux,
+                    "Color table ID is 0, not trying to get interlacedness");
+              }
+            } else {
+              GST_WARNING_OBJECT (qtdemux,
+                  "Length of jpeg chunk is too small, not trying to get interlacedness");
+            }
+
+            break;
+          }
+          case FOURCC_rle_:
+          case FOURCC_WRLE:
+          {
+            gst_caps_set_simple (entry->caps,
+                "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
+                NULL);
+            break;
+          }
+          case FOURCC_XiTh:
+          {
+            GNode *xith, *xdxt;
+
+            GST_DEBUG_OBJECT (qtdemux, "found XiTh");
+            xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
+            if (!xith)
+              break;
+
+            xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
+            if (!xdxt)
+              break;
+
+            GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
+            /* collect the headers and store them in a stream list so that we can
+             * send them out first */
+            qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
+            break;
+          }
+          case FOURCC_ovc1:
+          {
+            GNode *ovc1;
+            guint8 *ovc1_data;
+            guint ovc1_len;
+            GstBuffer *buf;
+
+            GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
+            ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
+            if (!ovc1)
+              break;
+            ovc1_data = ovc1->data;
+            ovc1_len = QT_UINT32 (ovc1_data);
+            if (ovc1_len <= 198) {
+              GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
+              break;
+            }
+            buf = gst_buffer_new_and_alloc (ovc1_len - 198);
+            gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
+            gst_caps_set_simple (entry->caps,
+                "codec_data", GST_TYPE_BUFFER, buf, NULL);
+            gst_buffer_unref (buf);
+            break;
+          }
+          case FOURCC_vc_1:
+          {
+            gint len = QT_UINT32 (stsd_entry_data) - 0x56;
+            const guint8 *vc1_data = stsd_entry_data + 0x56;
+
+            /* find dvc1 */
+            while (len >= 8) {
+              gint size;
+
+              if (QT_UINT32 (vc1_data) <= len)
+                size = QT_UINT32 (vc1_data) - 8;
+              else
+                size = len - 8;
+
+              if (size < 1)
+                /* No real data, so break out */
+                break;
+
+              switch (QT_FOURCC (vc1_data + 0x4)) {
+                case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
+                {
+                  GstBuffer *buf;
+
+                  GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
+                  buf = gst_buffer_new_and_alloc (size);
+                  gst_buffer_fill (buf, 0, vc1_data + 8, size);
+                  gst_caps_set_simple (entry->caps,
+                      "codec_data", GST_TYPE_BUFFER, buf, NULL);
+                  gst_buffer_unref (buf);
+                  break;
+                }
+                default:
+                  break;
+              }
+              len -= size + 8;
+              vc1_data += size + 8;
+            }
+            break;
+          }
+          default:
+            break;
+        }
+      }
+
+      GST_INFO_OBJECT (qtdemux,
+          "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
+          GST_FOURCC_ARGS (fourcc), entry->caps);
+
+    } else if (stream->subtype == FOURCC_soun) {
+      GNode *wave;
+      int version, samplesize;
+      guint16 compression_id;
+      gboolean amrwb = FALSE;
+
+      offset = 16;
+      /* sample description entry (16) + sound sample description v0 (20) */
+      if (len < 36)
+        goto corrupt_file;
+
+      version = QT_UINT32 (stsd_entry_data + offset);
+      entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
+      samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
+      compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
+      entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
+
+      GST_LOG_OBJECT (qtdemux, "version/rev:      %08x", version);
+      GST_LOG_OBJECT (qtdemux, "vendor:           %08x",
+          QT_UINT32 (stsd_entry_data + offset + 4));
+      GST_LOG_OBJECT (qtdemux, "n_channels:       %d", entry->n_channels);
+      GST_LOG_OBJECT (qtdemux, "sample_size:      %d", samplesize);
+      GST_LOG_OBJECT (qtdemux, "compression_id:   %d", compression_id);
+      GST_LOG_OBJECT (qtdemux, "packet size:      %d",
+          QT_UINT16 (stsd_entry_data + offset + 14));
+      GST_LOG_OBJECT (qtdemux, "sample rate:      %g", entry->rate);
+
+      if (compression_id == 0xfffe)
+        entry->sampled = TRUE;
+
+      /* first assume uncompressed audio */
+      entry->bytes_per_sample = samplesize / 8;
+      entry->samples_per_frame = entry->n_channels;
+      entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
+      entry->samples_per_packet = entry->samples_per_frame;
+      entry->bytes_per_packet = entry->bytes_per_sample;
+
+      offset = 36;
+      switch (fourcc) {
+          /* Yes, these have to be hard-coded */
+        case FOURCC_MAC6:
+        {
+          entry->samples_per_packet = 6;
+          entry->bytes_per_packet = 1;
+          entry->bytes_per_frame = 1 * entry->n_channels;
+          entry->bytes_per_sample = 1;
+          entry->samples_per_frame = 6 * entry->n_channels;
+          break;
+        }
+        case FOURCC_MAC3:
+        {
+          entry->samples_per_packet = 3;
+          entry->bytes_per_packet = 1;
+          entry->bytes_per_frame = 1 * entry->n_channels;
+          entry->bytes_per_sample = 1;
+          entry->samples_per_frame = 3 * entry->n_channels;
+          break;
+        }
+        case FOURCC_ima4:
+        {
+          entry->samples_per_packet = 64;
+          entry->bytes_per_packet = 34;
+          entry->bytes_per_frame = 34 * entry->n_channels;
+          entry->bytes_per_sample = 2;
+          entry->samples_per_frame = 64 * entry->n_channels;
+          break;
+        }
+        case FOURCC_ulaw:
+        case FOURCC_alaw:
+        {
+          entry->samples_per_packet = 1;
+          entry->bytes_per_packet = 1;
+          entry->bytes_per_frame = 1 * entry->n_channels;
+          entry->bytes_per_sample = 1;
+          entry->samples_per_frame = 1 * entry->n_channels;
+          break;
+        }
+        case FOURCC_agsm:
+        {
+          entry->samples_per_packet = 160;
+          entry->bytes_per_packet = 33;
+          entry->bytes_per_frame = 33 * entry->n_channels;
+          entry->bytes_per_sample = 2;
+          entry->samples_per_frame = 160 * entry->n_channels;
+          break;
+        }
+        default:
+          break;
+      }
+
+      if (version == 0x00010000) {
+        /* sample description entry (16) + sound sample description v1 (20+16) */
+        if (len < 52)
+          goto corrupt_file;
+
+        switch (fourcc) {
+          case FOURCC_twos:
+          case FOURCC_sowt:
+          case FOURCC_raw_:
+          case FOURCC_lpcm:
+            break;
+          default:
+          {
+            /* only parse extra decoding config for non-pcm audio */
+            entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
+            entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
+            entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
+            entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
+
+            GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
+                entry->samples_per_packet);
+            GST_LOG_OBJECT (qtdemux, "bytes/packet:     %d",
+                entry->bytes_per_packet);
+            GST_LOG_OBJECT (qtdemux, "bytes/frame:      %d",
+                entry->bytes_per_frame);
+            GST_LOG_OBJECT (qtdemux, "bytes/sample:     %d",
+                entry->bytes_per_sample);
+
+            if (!entry->sampled && entry->bytes_per_packet) {
+              entry->samples_per_frame = (entry->bytes_per_frame /
+                  entry->bytes_per_packet) * entry->samples_per_packet;
+              GST_LOG_OBJECT (qtdemux, "samples/frame:    %d",
+                  entry->samples_per_frame);
+            }
+            break;
+          }
+        }
+      } else if (version == 0x00020000) {
+        union
+        {
+          gdouble fp;
+          guint64 val;
+        } qtfp;
+
+        /* sample description entry (16) + sound sample description v2 (56) */
+        if (len < 72)
+          goto corrupt_file;
+
+        qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
+        entry->rate = qtfp.fp;
+        entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
+
+        GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
+        GST_LOG_OBJECT (qtdemux, "sample rate:        %g", entry->rate);
+        GST_LOG_OBJECT (qtdemux, "n_channels:         %d", entry->n_channels);
+        GST_LOG_OBJECT (qtdemux, "bits/channel:       %d",
+            QT_UINT32 (stsd_entry_data + offset + 20));
+        GST_LOG_OBJECT (qtdemux, "format flags:       %X",
+            QT_UINT32 (stsd_entry_data + offset + 24));
+        GST_LOG_OBJECT (qtdemux, "bytes/packet:       %d",
+            QT_UINT32 (stsd_entry_data + offset + 28));
+        GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
+            QT_UINT32 (stsd_entry_data + offset + 32));
+      } else if (version != 0x00000) {
+        GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
+            version);
+      }
+
+      if (entry->caps)
+        gst_caps_unref (entry->caps);
+
+      entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
+          stsd_entry_data + 32, len - 16, &codec);
+
+      switch (fourcc) {
+        case FOURCC_in24:
+        {
+          GNode *enda;
+          GNode *in24;
+
+          in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
+
+          enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
+          if (!enda) {
+            wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
+            if (wave)
+              enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
+          }
+          if (enda) {
+            int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
+            gst_caps_set_simple (entry->caps,
+                "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
+                NULL);
+          }
+          break;
+        }
+        case FOURCC_owma:
+        {
+          const guint8 *owma_data;
+          const gchar *codec_name = NULL;
+          guint owma_len;
+          GstBuffer *buf;
+          gint version = 1;
+          /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
+          /* FIXME this should also be gst_riff_strf_auds,
+           * but the latter one is actually missing bits-per-sample :( */
+          typedef struct
+          {
+            gint16 wFormatTag;
+            gint16 nChannels;
+            gint32 nSamplesPerSec;
+            gint32 nAvgBytesPerSec;
+            gint16 nBlockAlign;
+            gint16 wBitsPerSample;
+            gint16 cbSize;
+          } WAVEFORMATEX;
+          WAVEFORMATEX *wfex;
+
+          GST_DEBUG_OBJECT (qtdemux, "parse owma");
+          owma_data = stsd_entry_data;
+          owma_len = QT_UINT32 (owma_data);
+          if (owma_len <= 54) {
+            GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
+            break;
+          }
+          wfex = (WAVEFORMATEX *) (owma_data + 36);
+          buf = gst_buffer_new_and_alloc (owma_len - 54);
+          gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
+          if (wfex->wFormatTag == 0x0161) {
+            codec_name = "Windows Media Audio";
+            version = 2;
+          } else if (wfex->wFormatTag == 0x0162) {
+            codec_name = "Windows Media Audio 9 Pro";
+            version = 3;
+          } else if (wfex->wFormatTag == 0x0163) {
+            codec_name = "Windows Media Audio 9 Lossless";
+            /* is that correct? gstffmpegcodecmap.c is missing it, but
+             * fluendo codec seems to support it */
+            version = 4;
+          }
+
+          gst_caps_set_simple (entry->caps,
+              "codec_data", GST_TYPE_BUFFER, buf,
+              "wmaversion", G_TYPE_INT, version,
+              "block_align", G_TYPE_INT,
+              GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
+              GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
+              GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
+              GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
+          gst_buffer_unref (buf);
+
+          if (codec_name) {
+            g_free (codec);
+            codec = g_strdup (codec_name);
+          }
+          break;
+        }
+        case FOURCC_wma_:
+        {
+          gint len = QT_UINT32 (stsd_entry_data) - offset;
+          const guint8 *wfex_data = stsd_entry_data + offset;
+          const gchar *codec_name = NULL;
+          gint version = 1;
+          /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
+          /* FIXME this should also be gst_riff_strf_auds,
+           * but the latter one is actually missing bits-per-sample :( */
+          typedef struct
+          {
+            gint16 wFormatTag;
+            gint16 nChannels;
+            gint32 nSamplesPerSec;
+            gint32 nAvgBytesPerSec;
+            gint16 nBlockAlign;
+            gint16 wBitsPerSample;
+            gint16 cbSize;
+          } WAVEFORMATEX;
+          WAVEFORMATEX wfex;
+
+          /* FIXME: unify with similar wavformatex parsing code above */
+          GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
+
+          /* find wfex */
+          while (len >= 8) {
+            gint size;
+
+            if (QT_UINT32 (wfex_data) <= len)
+              size = QT_UINT32 (wfex_data) - 8;
+            else
+              size = len - 8;
+
+            if (size < 1)
+              /* No real data, so break out */
+              break;
+
+            switch (QT_FOURCC (wfex_data + 4)) {
+              case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
+              {
+                GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
+
+                if (size < 8 + 18)
+                  break;
+
+                wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
+                wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
+                wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
+                wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
+                wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
+                wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
+                wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
+
+                GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
+                GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
+                    "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
+                    "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
+                    wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
+                    wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
+
+                if (wfex.wFormatTag == 0x0161) {
+                  codec_name = "Windows Media Audio";
+                  version = 2;
+                } else if (wfex.wFormatTag == 0x0162) {
+                  codec_name = "Windows Media Audio 9 Pro";
+                  version = 3;
+                } else if (wfex.wFormatTag == 0x0163) {
+                  codec_name = "Windows Media Audio 9 Lossless";
+                  /* is that correct? gstffmpegcodecmap.c is missing it, but
+                   * fluendo codec seems to support it */
+                  version = 4;
+                }
+
+                gst_caps_set_simple (entry->caps,
+                    "wmaversion", G_TYPE_INT, version,
+                    "block_align", G_TYPE_INT, wfex.nBlockAlign,
+                    "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
+                    "width", G_TYPE_INT, wfex.wBitsPerSample,
+                    "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
+
+                if (size > wfex.cbSize) {
+                  GstBuffer *buf;
+
+                  buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
+                  gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
+                      size - wfex.cbSize);
+                  gst_caps_set_simple (entry->caps,
+                      "codec_data", GST_TYPE_BUFFER, buf, NULL);
+                  gst_buffer_unref (buf);
+                } else {
+                  GST_WARNING_OBJECT (qtdemux, "no codec data");
+                }
+
+                if (codec_name) {
+                  g_free (codec);
+                  codec = g_strdup (codec_name);
+                }
+                break;
+              }
+              default:
+                break;
+            }
+            len -= size + 8;
+            wfex_data += size + 8;
+          }
+          break;
+        }
+        case FOURCC_opus:
+        {
+          const guint8 *opus_data;
+          guint8 *channel_mapping = NULL;
+          guint32 rate;
+          guint8 channels;
+          guint8 channel_mapping_family;
+          guint8 stream_count;
+          guint8 coupled_count;
+          guint8 i;
+
+          opus_data = stsd_entry_data;
+
+          channels = GST_READ_UINT8 (opus_data + 45);
+          rate = GST_READ_UINT32_LE (opus_data + 48);
+          channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
+          stream_count = GST_READ_UINT8 (opus_data + 55);
+          coupled_count = GST_READ_UINT8 (opus_data + 56);
+
+          if (channels > 0) {
+            channel_mapping = g_malloc (channels * sizeof (guint8));
+            for (i = 0; i < channels; i++)
+              channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
+          }
+
+          entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
+              channel_mapping_family, stream_count, coupled_count,
+              channel_mapping);
+          break;
+        }
+        default:
+          break;
+      }
+
+      if (codec) {
+        GstStructure *s;
+        gint bitrate = 0;
+
+        gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
+            GST_TAG_AUDIO_CODEC, codec, NULL);
+        g_free (codec);
+        codec = NULL;
+
+        /* some bitrate info may have ended up in caps */
+        s = gst_caps_get_structure (entry->caps, 0);
+        gst_structure_get_int (s, "bitrate", &bitrate);
+        if (bitrate > 0)
+          gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
+              GST_TAG_BITRATE, bitrate, NULL);
+      }
+
+      mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
+      if (!stream->protected) {
+      } else {
+        if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
+          mp4v = NULL;
+        }
+      }
+      if (stream->protected && fourcc == FOURCC_mp4a) {
+        if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
+          mp4a = NULL;
+        }
+      } else {
+        if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
+          mp4a = NULL;
+        }
+      }
+
+      wave = NULL;
+      esds = NULL;
+      if (mp4a) {
+        wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
+        if (wave)
+          esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
+        if (!esds)
+          esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
+      }
+
+
+      /* If the fourcc's bottom 16 bits gives 'sm', then the top
+         16 bits is a byte-swapped wave-style codec identifier,
+         and we can find a WAVE header internally to a 'wave' atom here.
+         This can more clearly be thought of as 'ms' as the top 16 bits, and a
+         codec id as the bottom 16 bits - but byte-swapped to store in QT (which
+         is big-endian).
+       */
+      if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
+        if (len < offset + 20) {
+          GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
+        } else {
+          guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
+          const guint8 *data = stsd_entry_data + offset + 16;
+          GNode *wavenode;
+          GNode *waveheadernode;
+
+          wavenode = g_node_new ((guint8 *) data);
+          if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
+            const guint8 *waveheader;
+            guint32 headerlen;
+
+            waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
+            if (waveheadernode) {
+              waveheader = (const guint8 *) waveheadernode->data;
+              headerlen = QT_UINT32 (waveheader);
+
+              if (headerlen > 8) {
+                gst_riff_strf_auds *header = NULL;
+                GstBuffer *headerbuf;
+                GstBuffer *extra;
+
+                waveheader += 8;
+                headerlen -= 8;
+
+                headerbuf = gst_buffer_new_and_alloc (headerlen);
+                gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
+
+                if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
+                        headerbuf, &header, &extra)) {
+                  gst_caps_unref (entry->caps);
+                  /* FIXME: Need to do something with the channel reorder map */
+                  entry->caps =
+                      gst_riff_create_audio_caps (header->format, NULL, header,
+                      extra, NULL, NULL, NULL);
+
+                  if (extra)
+                    gst_buffer_unref (extra);
+                  g_free (header);
+                }
+              }
+            } else
+              GST_DEBUG ("Didn't find waveheadernode for this codec");
+          }
+          g_node_destroy (wavenode);
+        }
+      } else if (esds) {
+        gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
+            stream->stream_tags);
+      } else {
+        switch (fourcc) {
+#if 0
+            /* FIXME: what is in the chunk? */
+          case FOURCC_QDMC:
+          {
+            gint len = QT_UINT32 (stsd_data);
+
+            /* seems to be always = 116 = 0x74 */
+            break;
+          }
+#endif
+          case FOURCC_QDM2:
+          {
+            gint len = QT_UINT32 (stsd_entry_data);
+
+            if (len > 0x3C) {
+              GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
+
+              gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
+              gst_caps_set_simple (entry->caps,
+                  "codec_data", GST_TYPE_BUFFER, buf, NULL);
+              gst_buffer_unref (buf);
+            }
+            gst_caps_set_simple (entry->caps,
+                "samplesize", G_TYPE_INT, samplesize, NULL);
+            break;
+          }
+          case FOURCC_alac:
+          {
+            GNode *alac, *wave = NULL;
+
+            /* apparently, m4a has this atom appended directly in the stsd entry,
+             * while mov has it in a wave atom */
+            alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
+            if (alac) {
+              /* alac now refers to stsd entry atom */
+              wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
+              if (wave)
+                alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
+              else
+                alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
+            }
+            if (alac) {
+              const guint8 *alac_data = alac->data;
+              gint len = QT_UINT32 (alac->data);
+              GstBuffer *buf;
+
+              if (len < 36) {
+                GST_DEBUG_OBJECT (qtdemux,
+                    "discarding alac atom with unexpected len %d", len);
+              } else {
+                /* codec-data contains alac atom size and prefix,
+                 * ffmpeg likes it that way, not quite gst-ish though ...*/
+                buf = gst_buffer_new_and_alloc (len);
+                gst_buffer_fill (buf, 0, alac->data, len);
+                gst_caps_set_simple (entry->caps,
+                    "codec_data", GST_TYPE_BUFFER, buf, NULL);
+                gst_buffer_unref (buf);
+
+                entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
+                entry->n_channels = QT_UINT8 (alac_data + 21);
+                entry->rate = QT_UINT32 (alac_data + 32);
+              }
+            }
+            gst_caps_set_simple (entry->caps,
+                "samplesize", G_TYPE_INT, samplesize, NULL);
+            break;
+          }
+          case FOURCC_fLaC:
+          {
+            /* The codingname of the sample entry is 'fLaC' */
+            GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
+
+            if (flac) {
+              /* The 'dfLa' box is added to the sample entry to convey
+                 initializing information for the decoder. */
+              const GNode *dfla =
+                  qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
+
+              if (dfla) {
+                const guint32 len = QT_UINT32 (dfla->data);
+
+                /* Must contain at least dfLa box header (12),
+                 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
+                if (len < 50) {
+                  GST_DEBUG_OBJECT (qtdemux,
+                      "discarding dfla atom with unexpected len %d", len);
+                } else {
+                  /* skip dfLa header to get the METADATA_BLOCKs */
+                  const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
+                  const guint32 metadata_blocks_len = len - 12;
+
+                  gchar *stream_marker = g_strdup ("fLaC");
+                  GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
+                      strlen (stream_marker));
+
+                  guint32 index = 0;
+                  guint32 remainder = 0;
+                  guint32 block_size = 0;
+                  gboolean is_last = FALSE;
+
+                  GValue array = G_VALUE_INIT;
+                  GValue value = G_VALUE_INIT;
+
+                  g_value_init (&array, GST_TYPE_ARRAY);
+                  g_value_init (&value, GST_TYPE_BUFFER);
+
+                  gst_value_set_buffer (&value, block);
+                  gst_value_array_append_value (&array, &value);
+                  g_value_reset (&value);
+
+                  gst_buffer_unref (block);
+
+                  /* check there's at least one METADATA_BLOCK_HEADER's worth
+                   * of data, and we haven't already finished parsing */
+                  while (!is_last && ((index + 3) < metadata_blocks_len)) {
+                    remainder = metadata_blocks_len - index;
+
+                    /* add the METADATA_BLOCK_HEADER size to the signalled size */
+                    block_size = 4 +
+                        (metadata_blocks[index + 1] << 16) +
+                        (metadata_blocks[index + 2] << 8) +
+                        metadata_blocks[index + 3];
+
+                    /* be careful not to read off end of box */
+                    if (block_size > remainder) {
+                      break;
+                    }
+
+                    is_last = metadata_blocks[index] >> 7;
+
+                    block = gst_buffer_new_and_alloc (block_size);
+
+                    gst_buffer_fill (block, 0, &metadata_blocks[index],
+                        block_size);
+
+                    gst_value_set_buffer (&value, block);
+                    gst_value_array_append_value (&array, &value);
+                    g_value_reset (&value);
+
+                    gst_buffer_unref (block);
+
+                    index += block_size;
+                  }
+
+                  /* only append the metadata if we successfully read all of it */
+                  if (is_last) {
+                    gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
+                            (stream)->caps, 0), "streamheader", &array);
+                  } else {
+                    GST_WARNING_OBJECT (qtdemux,
+                        "discarding all METADATA_BLOCKs due to invalid "
+                        "block_size %d at idx %d, rem %d", block_size, index,
+                        remainder);
+                  }
+
+                  g_value_unset (&value);
+                  g_value_unset (&array);
+
+                  /* The sample rate obtained from the stsd may not be accurate
+                   * since it cannot represent rates greater than 65535Hz, so
+                   * override that value with the sample rate from the
+                   * METADATA_BLOCK_STREAMINFO block */
+                  CUR_STREAM (stream)->rate =
+                      (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
+                }
+              }
+            }
+            break;
+          }
+          case FOURCC_sawb:
+            /* Fallthrough! */
+            amrwb = TRUE;
+          case FOURCC_samr:
+          {
+            gint len = QT_UINT32 (stsd_entry_data);
+
+            if (len > 0x24) {
+              GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
+              guint bitrate;
+
+              gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
+
+              /* If we have enough data, let's try to get the 'damr' atom. See
+               * the 3GPP container spec (26.244) for more details. */
+              if ((len - 0x34) > 8 &&
+                  (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
+                gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
+                    GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
+              }
+
+              gst_caps_set_simple (entry->caps,
+                  "codec_data", GST_TYPE_BUFFER, buf, NULL);
+              gst_buffer_unref (buf);
+            }
+            break;
+          }
+          case FOURCC_mp4a:
+          {
+            /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
+            gint len = QT_UINT32 (stsd_entry_data);
+
+            if (len >= 34) {
+              guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
+
+              if (sound_version == 1) {
+                guint16 channels = QT_UINT16 (stsd_entry_data + 24);
+                guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
+                guint8 codec_data[2];
+                GstBuffer *buf;
+                gint profile = 2;       /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
+
+                gint sample_rate_index =
+                    gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
+
+                /* build AAC codec data */
+                codec_data[0] = profile << 3;
+                codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
+                codec_data[1] = (sample_rate_index & 0x01) << 7;
+                codec_data[1] |= (channels & 0xF) << 3;
+
+                buf = gst_buffer_new_and_alloc (2);
+                gst_buffer_fill (buf, 0, codec_data, 2);
+                gst_caps_set_simple (entry->caps,
+                    "codec_data", GST_TYPE_BUFFER, buf, NULL);
+                gst_buffer_unref (buf);
+              }
+            }
+            break;
+          }
+          case FOURCC_lpcm:
+            /* Fully handled elsewhere */
+            break;
+          default:
+            GST_INFO_OBJECT (qtdemux,
+                "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
+            break;
+        }
+      }
+      GST_INFO_OBJECT (qtdemux,
+          "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
+          GST_FOURCC_ARGS (fourcc), entry->caps);
+
+    } else if (stream->subtype == FOURCC_strm) {
+      if (fourcc == FOURCC_rtsp) {
+        stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
+      } else {
+        GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
+            GST_FOURCC_ARGS (fourcc));
+        goto unknown_stream;
+      }
+      entry->sampled = TRUE;
+    } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
+        || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
+
+      entry->sampled = TRUE;
+      entry->sparse = TRUE;
+
+      entry->caps =
+          qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
+          &codec);
+      if (codec) {
+        gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
+            GST_TAG_SUBTITLE_CODEC, codec, NULL);
+        g_free (codec);
+        codec = NULL;
+      }
+
+      /* hunt for sort-of codec data */
+      switch (fourcc) {
+        case FOURCC_mp4s:
+        {
+          GNode *mp4s = NULL;
+          GNode *esds = NULL;
+
+          /* look for palette in a stsd->mp4s->esds sub-atom */
+          mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
+          if (mp4s)
+            esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
+          if (esds == NULL) {
+            /* Invalid STSD */
+            GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
+            break;
+          }
+
+          gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
+              stream->stream_tags);
+          break;
+        }
+        default:
+          GST_INFO_OBJECT (qtdemux,
+              "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
+          break;
+      }
+      GST_INFO_OBJECT (qtdemux,
+          "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
+          GST_FOURCC_ARGS (fourcc), entry->caps);
+    } else {
+      /* everything in 1 sample */
+      entry->sampled = TRUE;
+
+      entry->caps =
+          qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
+          &codec);
+
+      if (entry->caps == NULL)
+        goto unknown_stream;
+
+      if (codec) {
+        gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
+            GST_TAG_SUBTITLE_CODEC, codec, NULL);
+        g_free (codec);
+        codec = NULL;
+      }
+    }
+
+    /* promote to sampled format */
+    if (entry->fourcc == FOURCC_samr) {
+      /* force mono 8000 Hz for AMR */
+      entry->sampled = TRUE;
+      entry->n_channels = 1;
+      entry->rate = 8000;
+    } else if (entry->fourcc == FOURCC_sawb) {
+      /* force mono 16000 Hz for AMR-WB */
+      entry->sampled = TRUE;
+      entry->n_channels = 1;
+      entry->rate = 16000;
+    } else if (entry->fourcc == FOURCC_mp4a) {
+      entry->sampled = TRUE;
+    }
+
+
+    stsd_entry_data += len;
+    remaining_stsd_len -= len;
+
+  }
+
+  /* collect sample information */
+  if (!qtdemux_stbl_init (qtdemux, stream, stbl))
+    goto samples_failed;
+
+  if (qtdemux->fragmented) {
+    guint64 offset;
+
+    /* need all moov samples as basis; probably not many if any at all */
+    /* prevent moof parsing taking of at this time */
+    offset = qtdemux->moof_offset;
+    qtdemux->moof_offset = 0;
+    if (stream->n_samples &&
+        !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
+      qtdemux->moof_offset = offset;
+      goto samples_failed;
+    }
+    qtdemux->moof_offset = 0;
+    /* movie duration more reliable in this case (e.g. mehd) */
+    if (qtdemux->segment.duration &&
+        GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
+      stream->duration =
+          GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
+  }
+
+  /* configure segments */
+  if (!qtdemux_parse_segments (qtdemux, stream, trak))
+    goto segments_failed;
+
+  /* add some language tag, if useful */
+  if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
+      strcmp (stream->lang_id, "und")) {
+    const gchar *lang_code;
+
+    /* convert ISO 639-2 code to ISO 639-1 */
+    lang_code = gst_tag_get_language_code (stream->lang_id);
+    gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
+        GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
+  }
+
+  /* Check for UDTA tags */
+  if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
+    qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
+  }
+
+  /* now we are ready to add the stream */
+  if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
+    goto too_many_streams;
+
+  if (!qtdemux->got_moov) {
+    qtdemux->streams[qtdemux->n_streams] = stream;
+    qtdemux->n_streams++;
+    GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
+  }
+
+  return TRUE;
+
+/* ERRORS */
+skip_track:
+  {
+    GST_INFO_OBJECT (qtdemux, "skip disabled track");
+    if (new_stream)
+      gst_qtdemux_stream_free (qtdemux, stream);
+    return TRUE;
+  }
+corrupt_file:
+  {
+    GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
+        (_("This file is corrupt and cannot be played.")), (NULL));
+    if (new_stream)
+      gst_qtdemux_stream_free (qtdemux, stream);
+    return FALSE;
+  }
+error_encrypted:
+  {
+    GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
+    if (new_stream)
+      gst_qtdemux_stream_free (qtdemux, stream);
+    return FALSE;
+  }
+samples_failed:
+segments_failed:
+  {
+    /* we posted an error already */
+    /* free stbl sub-atoms */
+    gst_qtdemux_stbl_free (stream);
+    if (new_stream)
+      gst_qtdemux_stream_free (qtdemux, stream);
+    return FALSE;
+  }
+existing_stream:
+  {
+    GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
+        track_id);
+    if (new_stream)
+      gst_qtdemux_stream_free (qtdemux, stream);
+    return TRUE;
+  }
+unknown_stream:
+  {
+    GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
+        GST_FOURCC_ARGS (stream->subtype));
+    if (new_stream)
+      gst_qtdemux_stream_free (qtdemux, stream);
+    return TRUE;
+  }
+too_many_streams:
+  {
+    GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
+        (_("This file contains too many streams. Only playing first %d"),
+            GST_QTDEMUX_MAX_STREAMS), (NULL));
+    return TRUE;
+  }
+}
+
+/* If we can estimate the overall bitrate, and don't have information about the
+ * stream bitrate for exactly one stream, this guesses the stream bitrate as
+ * the overall bitrate minus the sum of the bitrates of all other streams. This
+ * should be useful for the common case where we have one audio and one video
+ * stream and can estimate the bitrate of one, but not the other. */
+static void
+gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
+{
+  QtDemuxStream *stream = NULL;
+  gint64 size, sys_bitrate, sum_bitrate = 0;
+  GstClockTime duration;
+  gint i;
+  guint bitrate;
+
+  if (qtdemux->fragmented)
+    return;
+
+  GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
+
+  if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
+      || size <= 0) {
+    GST_DEBUG_OBJECT (qtdemux,
+        "Size in bytes of the stream not known - bailing");
+    return;
+  }
+
+  /* Subtract the header size */
+  GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
+      size, qtdemux->header_size);
+
+  if (size < qtdemux->header_size)
+    return;
+
+  size = size - qtdemux->header_size;
+
+  if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
+    GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
+    return;
+  }
+
+  for (i = 0; i < qtdemux->n_streams; i++) {
+    switch (qtdemux->streams[i]->subtype) {
+      case FOURCC_soun:
+      case FOURCC_vide:
+        GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
+            CUR_STREAM (qtdemux->streams[i])->caps);
+        /* retrieve bitrate, prefer avg then max */
+        bitrate = 0;
+        if (qtdemux->streams[i]->stream_tags) {
+          if (gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
+                  GST_TAG_MAXIMUM_BITRATE, &bitrate))
+            GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
+          if (gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
+                  GST_TAG_NOMINAL_BITRATE, &bitrate))
+            GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
+          if (gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
+                  GST_TAG_BITRATE, &bitrate))
+            GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
+        }
+        if (bitrate)
+          sum_bitrate += bitrate;
+        else {
+          if (stream) {
+            GST_DEBUG_OBJECT (qtdemux,
+                ">1 stream with unknown bitrate - bailing");
+            return;
+          } else
+            stream = qtdemux->streams[i];
+        }
+
+      default:
+        /* For other subtypes, we assume no significant impact on bitrate */
+        break;
+    }
+  }
+
+  if (!stream) {
+    GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
+    return;
+  }
+
+  sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
+
+  if (sys_bitrate < sum_bitrate) {
+    /* This can happen, since sum_bitrate might be derived from maximum
+     * bitrates and not average bitrates */
+    GST_DEBUG_OBJECT (qtdemux,
+        "System bitrate less than sum bitrate - bailing");
+    return;
+  }
+
+  bitrate = sys_bitrate - sum_bitrate;
+  GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
+      ", Stream bitrate = %u", sys_bitrate, bitrate);
+
+  if (!stream->stream_tags)
+    stream->stream_tags = gst_tag_list_new_empty ();
+  else
+    stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
+
+  gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
+      GST_TAG_BITRATE, bitrate, NULL);
+}
+
+static GstFlowReturn
+qtdemux_prepare_streams (GstQTDemux * qtdemux)
+{
+  gint i;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  GST_DEBUG_OBJECT (qtdemux, "prepare streams");
+
+  for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
+    QtDemuxStream *stream = qtdemux->streams[i];
+    guint32 sample_num = 0;
+
+    GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
+        i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
+
+    if (qtdemux->fragmented) {
+      /* need all moov samples first */
+      GST_OBJECT_LOCK (qtdemux);
+      while (stream->n_samples == 0)
+        if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
+          break;
+      GST_OBJECT_UNLOCK (qtdemux);
+    } else {
+      /* discard any stray moof */
+      qtdemux->moof_offset = 0;
+    }
+
+    /* prepare braking */
+    if (ret != GST_FLOW_ERROR)
+      ret = GST_FLOW_OK;
+
+    /* in pull mode, we should have parsed some sample info by now;
+     * and quite some code will not handle no samples.
+     * in push mode, we'll just have to deal with it */
+    if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
+      GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
+      gst_qtdemux_remove_stream (qtdemux, i);
+      i--;
+      continue;
+    }
+
+    /* parse the initial sample for use in setting the frame rate cap */
+    while (sample_num == 0 && sample_num < stream->n_samples) {
+      if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
+        break;
+      ++sample_num;
+    }
+    if (stream->n_samples > 0 && stream->stbl_index >= 0) {
+      stream->first_duration = stream->samples[0].duration;
+      GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
+          stream->track_id, stream->first_duration);
+    }
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+qtdemux_expose_streams (GstQTDemux * qtdemux)
+{
+  gint i;
+  GSList *oldpads = NULL;
+  GSList *iter;
+
+  GST_DEBUG_OBJECT (qtdemux, "exposing streams");
+
+  for (i = 0; i < qtdemux->n_streams; i++) {
+    QtDemuxStream *stream = qtdemux->streams[i];
+    GstPad *oldpad = stream->pad;
+    GstTagList *list;
+
+    GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
+        i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
+
+    if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
+        stream->track_id == qtdemux->chapters_track_id) {
+      /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
+         so that it doesn't look like a subtitle track */
+      gst_qtdemux_remove_stream (qtdemux, i);
+      i--;
+      continue;
+    }
+
+    /* now we have all info and can expose */
+    list = stream->stream_tags;
+    stream->stream_tags = NULL;
+    if (oldpad)
+      oldpads = g_slist_prepend (oldpads, oldpad);
+    if (!gst_qtdemux_add_stream (qtdemux, stream, list))
+      return GST_FLOW_ERROR;
+  }
+
+  gst_qtdemux_guess_bitrate (qtdemux);
+
+  gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
+
+  for (iter = oldpads; iter; iter = g_slist_next (iter)) {
+    GstPad *oldpad = iter->data;
+    GstEvent *event;
+
+    event = gst_event_new_eos ();
+    if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
+      gst_event_set_seqnum (event, qtdemux->segment_seqnum);
+
+    gst_pad_push_event (oldpad, event);
+    gst_pad_set_active (oldpad, FALSE);
+    gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
+    gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
+    gst_object_unref (oldpad);
+  }
+
+  /* check if we should post a redirect in case there is a single trak
+   * and it is a redirecting trak */
+  if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
+    GstMessage *m;
+
+    GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
+        "an external content");
+    m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
+        gst_structure_new ("redirect",
+            "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
+            NULL));
+    gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
+    qtdemux->posted_redirect = TRUE;
+  }
+
+  for (i = 0; i < qtdemux->n_streams; i++) {
+    QtDemuxStream *stream = qtdemux->streams[i];
+
+    qtdemux_do_allocation (qtdemux, stream);
+  }
+
+  qtdemux->exposed = TRUE;
+  return GST_FLOW_OK;
+}
+
+/* check if major or compatible brand is 3GP */
+static inline gboolean
+qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
+{
+  if (major) {
+    return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
+        FOURCC_3g__);
+  } else if (qtdemux->comp_brands != NULL) {
+    GstMapInfo map;
+    guint8 *data;
+    gsize size;
+    gboolean res = FALSE;
+
+    gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
+    data = map.data;
+    size = map.size;
+    while (size >= 4) {
+      res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
+          FOURCC_3g__);
+      data += 4;
+      size -= 4;
+    }
+    gst_buffer_unmap (qtdemux->comp_brands, &map);
+    return res;
+  } else {
+    return FALSE;
+  }
+}
+
+/* check if tag is a spec'ed 3GP tag keyword storing a string */
+static inline gboolean
+qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
+{
+  return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
+      || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
+      || fourcc == FOURCC_albm;
+}
+
+static void
+qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
+    const char *tag, const char *dummy, GNode * node)
+{
+  const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
+  int offset;
+  char *name;
+  gchar *data;
+  gdouble longitude, latitude, altitude;
+  gint len;
+
+  len = QT_UINT32 (node->data);
+  if (len <= 14)
+    goto short_read;
+
+  data = node->data;
+  offset = 14;
+
+  /* TODO: language code skipped */
+
+  name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
+
+  if (!name) {
+    /* do not alarm in trivial case, but bail out otherwise */
+    if (*(data + offset) != 0) {
+      GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
+          "giving up", tag);
+    }
+  } else {
+    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
+        GST_TAG_GEO_LOCATION_NAME, name, NULL);
+    offset += strlen (name);
+    g_free (name);
+  }
+
+  if (len < offset + 2 + 4 + 4 + 4)
+    goto short_read;
+
+  /* +1 +1 = skip null-terminator and location role byte */
+  offset += 1 + 1;
+  /* table in spec says unsigned, semantics say negative has meaning ... */
+  longitude = QT_SFP32 (data + offset);
+
+  offset += 4;
+  latitude = QT_SFP32 (data + offset);
+
+  offset += 4;
+  altitude = QT_SFP32 (data + offset);
+
+  /* one invalid means all are invalid */
+  if (longitude >= -180.0 && longitude <= 180.0 &&
+      latitude >= -90.0 && latitude <= 90.0) {
+    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
+        GST_TAG_GEO_LOCATION_LATITUDE, latitude,
+        GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
+        GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
+  }
+
+  /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
+
+  return;
+
+  /* ERRORS */
+short_read:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
+    return;
+  }
+}
+
+
+static void
+qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
+    const char *tag, const char *dummy, GNode * node)
+{
+  guint16 y;
+  GDate *date;
+  gint len;
+
+  len = QT_UINT32 (node->data);
+  if (len < 14)
+    return;
+
+  y = QT_UINT16 ((guint8 *) node->data + 12);
+  if (y == 0) {
+    GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
+    return;
+  }
+  GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
+
+  date = g_date_new_dmy (1, 1, y);
+  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
+  g_date_free (date);
+}
+
+static void
+qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
+    const char *tag, const char *dummy, GNode * node)
+{
+  int offset;
+  char *tag_str = NULL;
+  guint8 *entity;
+  guint16 table;
+  gint len;
+
+  len = QT_UINT32 (node->data);
+  if (len <= 20)
+    goto short_read;
+
+  offset = 12;
+  entity = (guint8 *) node->data + offset;
+  if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
+    GST_DEBUG_OBJECT (qtdemux,
+        "classification info: %c%c%c%c invalid classification entity",
+        entity[0], entity[1], entity[2], entity[3]);
+    return;
+  }
+
+  offset += 4;
+  table = QT_UINT16 ((guint8 *) node->data + offset);
+
+  /* Language code skipped */
+
+  offset += 4;
+
+  /* Tag format: "XXXX://Y[YYYY]/classification info string"
+   * XXXX: classification entity, fixed length 4 chars.
+   * Y[YYYY]: classification table, max 5 chars.
+   */
+  tag_str = g_strdup_printf ("----://%u/%s",
+      table, (char *) node->data + offset);
+
+  /* memcpy To be sure we're preserving byte order */
+  memcpy (tag_str, entity, 4);
+  GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
+
+  gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
+
+  g_free (tag_str);
+
+  return;
+
+  /* ERRORS */
+short_read:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
+    return;
+  }
+}
+
+static gboolean
+qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
+    const char *tag, const char *dummy, GNode * node)
+{
+  const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
+  GNode *data;
+  char *s;
+  int len;
+  guint32 type;
+  int offset;
+  gboolean ret = TRUE;
+  const gchar *charset = NULL;
+
+  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
+  if (data) {
+    len = QT_UINT32 (data->data);
+    type = QT_UINT32 ((guint8 *) data->data + 8);
+    if (type == 0x00000001 && len > 16) {
+      s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
+          env_vars);
+      if (s) {
+        GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
+        gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
+        g_free (s);
+      } else {
+        GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
+      }
+    }
+  } else {
+    len = QT_UINT32 (node->data);
+    type = QT_UINT32 ((guint8 *) node->data + 4);
+    if ((type >> 24) == 0xa9 && len > 8 + 4) {
+      gint str_len;
+      gint lang_code;
+
+      /* Type starts with the (C) symbol, so the next data is a list
+       * of (string size(16), language code(16), string) */
+
+      str_len = QT_UINT16 ((guint8 *) node->data + 8);
+      lang_code = QT_UINT16 ((guint8 *) node->data + 10);
+
+      /* the string + fourcc + size + 2 16bit fields,
+       * means that there are more tags in this atom */
+      if (len > str_len + 8 + 4) {
+        /* TODO how to represent the same tag in different languages? */
+        GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
+            "text alternatives, reading only first one");
+      }
+
+      offset = 12;
+      len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
+      GST_DEBUG_OBJECT (qtdemux, "found international text tag");
+
+      if (lang_code < 0x800) {  /* MAC encoded string */
+        charset = "mac";
+      }
+    } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
+            QT_FOURCC ((guint8 *) node->data + 4))) {
+      guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
+
+      /* we go for 3GP style encoding if major brands claims so,
+       * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
+      if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
+          (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
+              ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
+        offset = 14;
+        /* 16-bit Language code is ignored here as well */
+        GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
+      } else {
+        goto normal;
+      }
+    } else {
+    normal:
+      offset = 8;
+      GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
+      ret = FALSE;              /* may have to fallback */
+    }
+    if (charset) {
+      GError *err = NULL;
+
+      s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
+          charset, NULL, NULL, &err);
+      if (err) {
+        GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
+            " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
+            err->message);
+        g_error_free (err);
+      }
+    } else {
+      s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
+          len - offset, env_vars);
+    }
+    if (s) {
+      GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
+      gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
+      g_free (s);
+      ret = TRUE;
+    } else {
+      GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
+    }
+  }
+  return ret;
+}
+
+static void
+qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
+    const char *tag, const char *dummy, GNode * node)
+{
+  qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
+}
+
+static void
+qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
+    const char *tag, const char *dummy, GNode * node)
+{
+  const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
+  guint8 *data;
+  char *s, *t, *k = NULL;
+  int len;
+  int offset;
+  int count;
+
+  /* first try normal string tag if major brand not 3GP */
+  if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
+    if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
+      /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
+       * let's try it 3gpp way after minor safety check */
+      data = node->data;
+      if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
+        return;
+    } else
+      return;
+  }
+
+  GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
+
+  data = node->data;
+
+  len = QT_UINT32 (data);
+  if (len < 15)
+    goto short_read;
+
+  count = QT_UINT8 (data + 14);
+  offset = 15;
+  for (; count; count--) {
+    gint slen;
+
+    if (offset + 1 > len)
+      goto short_read;
+    slen = QT_UINT8 (data + offset);
+    offset += 1;
+    if (offset + slen > len)
+      goto short_read;
+    s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
+        slen, env_vars);
+    if (s) {
+      GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
+      if (k) {
+        t = g_strjoin (",", k, s, NULL);
+        g_free (s);
+        g_free (k);
+        k = t;
+      } else {
+        k = s;
+      }
+    } else {
+      GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
+    }
+    offset += slen;
+  }
+
+done:
+  if (k) {
+    GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
+    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
+  }
+  g_free (k);
+
+  return;
+
+  /* ERRORS */
+short_read:
+  {
+    GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
+    goto done;
+  }
+}
+
+static void
+qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
+    const char *tag1, const char *tag2, GNode * node)
+{
+  GNode *data;
+  int len;
+  int type;
+  int n1, n2;
+
+  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
+  if (data) {
+    len = QT_UINT32 (data->data);
+    type = QT_UINT32 ((guint8 *) data->data + 8);
+    if (type == 0x00000000 && len >= 22) {
+      n1 = QT_UINT16 ((guint8 *) data->data + 18);
+      n2 = QT_UINT16 ((guint8 *) data->data + 20);
+      if (n1 > 0) {
+        GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
+        gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
+      }
+      if (n2 > 0) {
+        GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
+        gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
+      }
+    }
+  }
+}
+
+static void
+qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
+    const char *tag1, const char *dummy, GNode * node)
+{
+  GNode *data;
+  int len;
+  int type;
+  int n1;
+
+  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
+  if (data) {
+    len = QT_UINT32 (data->data);
+    type = QT_UINT32 ((guint8 *) data->data + 8);
+    GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
+    /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
+    if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
+      n1 = QT_UINT16 ((guint8 *) data->data + 16);
+      if (n1) {
+        /* do not add bpm=0 */
+        GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
+        gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
+            NULL);
+      }
+    }
+  }
+}
+
+static void
+qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
+    const char *tag1, const char *dummy, GNode * node)
+{
+  GNode *data;
+  int len;
+  int type;
+  guint32 num;
+
+  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
+  if (data) {
+    len = QT_UINT32 (data->data);
+    type = QT_UINT32 ((guint8 *) data->data + 8);
+    GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
+    /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
+    if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
+      num = QT_UINT32 ((guint8 *) data->data + 16);
+      if (num) {
+        /* do not add num=0 */
+        GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
+        gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
+      }
+    }
+  }
+}
+
+static void
+qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
+    const char *tag1, const char *dummy, GNode * node)
+{
+  GNode *data;
+  int len;
+  int type;
+  GstSample *sample;
+
+  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
+  if (data) {
+    len = QT_UINT32 (data->data);
+    type = QT_UINT32 ((guint8 *) data->data + 8);
+    GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
+    if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
+      GstTagImageType image_type;
+
+      if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
+        image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
+      else
+        image_type = GST_TAG_IMAGE_TYPE_NONE;
+
+      if ((sample =
+              gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
+                  len - 16, image_type))) {
+        GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
+        gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
+        gst_sample_unref (sample);
+      }
+    }
+  }
+}
+
+static void
+qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
+    const char *tag, const char *dummy, GNode * node)
+{
+  GNode *data;
+  char *s;
+  int len;
+  int type;
+
+  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
+  if (data) {
+    len = QT_UINT32 (data->data);
+    type = QT_UINT32 ((guint8 *) data->data + 8);
+    if (type == 0x00000001 && len > 16) {
+      guint y, m = 1, d = 1;
+      gint ret;
+
+      s = g_strndup ((char *) data->data + 16, len - 16);
+      GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
+      ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
+      if (ret >= 1 && y > 1500 && y < 3000) {
+        GDate *date;
+
+        date = g_date_new_dmy (d, m, y);
+        gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
+        g_date_free (date);
+      } else {
+        GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
+      }
+      g_free (s);
+    }
+  }
+}
+
+static void
+qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
+    const char *tag, const char *dummy, GNode * node)
+{
+  GNode *data;
+
+  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
+
+  /* re-route to normal string tag if major brand says so
+   * or no data atom and compatible brand suggests so */
+  if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
+      (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
+    qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
+    return;
+  }
+
+  if (data) {
+    guint len, type, n;
+
+    len = QT_UINT32 (data->data);
+    type = QT_UINT32 ((guint8 *) data->data + 8);
+    if (type == 0x00000000 && len >= 18) {
+      n = QT_UINT16 ((guint8 *) data->data + 16);
+      if (n > 0) {
+        const gchar *genre;
+
+        genre = gst_tag_id3_genre_get (n - 1);
+        if (genre != NULL) {
+          GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
+          gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
+        }
+      }
+    }
+  }
+}
+
+static void
+qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
+    const gchar * tag, guint8 * data, guint32 datasize)
+{
+  gdouble value;
+  gchar *datacopy;
+
+  /* make a copy to have \0 at the end */
+  datacopy = g_strndup ((gchar *) data, datasize);
+
+  /* convert the str to double */
+  if (sscanf (datacopy, "%lf", &value) == 1) {
+    GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
+    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
+  } else {
+    GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
+        datacopy);
+  }
+  g_free (datacopy);
+}
+
+
+static void
+qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
+    const char *tag, const char *tag_bis, GNode * node)
+{
+  GNode *mean;
+  GNode *name;
+  GNode *data;
+  guint32 meansize;
+  guint32 namesize;
+  guint32 datatype;
+  guint32 datasize;
+  const gchar *meanstr;
+  const gchar *namestr;
+
+  /* checking the whole ---- atom size for consistency */
+  if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
+    GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
+    return;
+  }
+
+  mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
+  if (!mean) {
+    GST_WARNING_OBJECT (demux, "No 'mean' atom found");
+    return;
+  }
+
+  meansize = QT_UINT32 (mean->data);
+  if (meansize <= 12) {
+    GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
+    return;
+  }
+  meanstr = ((gchar *) mean->data) + 12;
+  meansize -= 12;
+
+  name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
+  if (!name) {
+    GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
+    return;
+  }
+
+  namesize = QT_UINT32 (name->data);
+  if (namesize <= 12) {
+    GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
+    return;
+  }
+  namestr = ((gchar *) name->data) + 12;
+  namesize -= 12;
+
+  /*
+   * Data atom is:
+   * uint32 - size
+   * uint32 - name
+   * uint8  - version
+   * uint24 - data type
+   * uint32 - all 0
+   * rest   - the data
+   */
+  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
+  if (!data) {
+    GST_WARNING_OBJECT (demux, "No data atom in this tag");
+    return;
+  }
+  datasize = QT_UINT32 (data->data);
+  if (datasize <= 16) {
+    GST_WARNING_OBJECT (demux, "Data atom too small");
+    return;
+  }
+  datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
+
+  if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
+      (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
+    static const struct
+    {
+      const gchar name[28];
+      const gchar tag[28];
+    } tags[] = {
+      {
+      "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
+      "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
+      "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
+      "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
+      "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
+      "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
+      "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
+      "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
+    };
+    int i;
+
+    for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
+      if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
+        switch (gst_tag_get_type (tags[i].tag)) {
+          case G_TYPE_DOUBLE:
+            qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
+                ((guint8 *) data->data) + 16, datasize - 16);
+            break;
+          case G_TYPE_STRING:
+            qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
+            break;
+          default:
+            /* not reached */
+            break;
+        }
+        break;
+      }
+    }
+    if (i == G_N_ELEMENTS (tags))
+      goto unknown_tag;
+  } else {
+    goto unknown_tag;
+  }
+
+  return;
+
+/* errors */
+unknown_tag:
+#ifndef GST_DISABLE_GST_DEBUG
+  {
+    gchar *namestr_dbg;
+    gchar *meanstr_dbg;
+
+    meanstr_dbg = g_strndup (meanstr, meansize);
+    namestr_dbg = g_strndup (namestr, namesize);
+
+    GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
+        "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
+
+    g_free (namestr_dbg);
+    g_free (meanstr_dbg);
+  }
+#endif
+  return;
+}
+
+static void
+qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
+    const char *tag_bis, GNode * node)
+{
+  guint8 *data;
+  GstBuffer *buf;
+  guint len;
+  GstTagList *id32_taglist = NULL;
+
+  GST_LOG_OBJECT (demux, "parsing ID32");
+
+  data = node->data;
+  len = GST_READ_UINT32_BE (data);
+
+  /* need at least full box and language tag */
+  if (len < 12 + 2)
+    return;
+
+  buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
+  gst_buffer_fill (buf, 0, data + 14, len - 14);
+
+  id32_taglist = gst_tag_list_from_id3v2_tag (buf);
+  if (id32_taglist) {
+    GST_LOG_OBJECT (demux, "parsing ok");
+    gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
+    gst_tag_list_unref (id32_taglist);
+  } else {
+    GST_LOG_OBJECT (demux, "parsing failed");
+  }
+
+  gst_buffer_unref (buf);
+}
+
+typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
+    const char *tag, const char *tag_bis, GNode * node);
+
+/* unmapped tags
+FOURCC_pcst -> if media is a podcast -> bool
+FOURCC_cpil -> if media is part of a compilation -> bool
+FOURCC_pgap -> if media is part of a gapless context -> bool
+FOURCC_tven -> the tv episode id e.g. S01E23 -> str
+*/
+
+static const struct
+{
+  guint32 fourcc;
+  const gchar *gst_tag;
+  const gchar *gst_tag_bis;
+  const GstQTDemuxAddTagFunc func;
+} add_funcs[] = {
+  {
+  FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
+  FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
+  FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
+  FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
+  FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
+  FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
+  FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
+  FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
+  FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
+  FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
+  FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
+  FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
+  FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
+  FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
+  FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
+  FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
+  FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
+  FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
+  FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
+  FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
+  FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
+  FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
+  FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
+        qtdemux_tag_add_num}, {
+  FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
+        qtdemux_tag_add_num}, {
+  FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
+  FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
+  FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
+  FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
+  FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
+  FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
+  FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
+  FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
+  FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
+  FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
+  FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
+  FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
+  FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
+  FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
+  FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
+  FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
+  FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
+  FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
+        qtdemux_tag_add_classification}, {
+  FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
+  FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
+  FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
+
+    /* This is a special case, some tags are stored in this
+     * 'reverse dns naming', according to:
+     * http://atomicparsley.sourceforge.net/mpeg-4files.html and
+     * bug #614471
+     */
+  FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
+    /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
+  FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
+};
+
+struct _GstQtDemuxTagList
+{
+  GstQTDemux *demux;
+  GstTagList *taglist;
+};
+typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
+
+static void
+qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
+{
+  gint len;
+  guint8 *data;
+  GstBuffer *buf;
+  gchar *media_type;
+  const gchar *style;
+  GstSample *sample;
+  GstStructure *s;
+  guint i;
+  guint8 ndata[4];
+  GstQTDemux *demux = qtdemuxtaglist->demux;
+  GstTagList *taglist = qtdemuxtaglist->taglist;
+
+  data = node->data;
+  len = QT_UINT32 (data);
+  buf = gst_buffer_new_and_alloc (len);
+  gst_buffer_fill (buf, 0, data, len);
+
+  /* heuristic to determine style of tag */
+  if (QT_FOURCC (data + 4) == FOURCC_____ ||
+      (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
+    style = "itunes";
+  else if (demux->major_brand == FOURCC_qt__)
+    style = "quicktime";
+  /* fall back to assuming iso/3gp tag style */
+  else
+    style = "iso";
+
+  /* santize the name for the caps. */
+  for (i = 0; i < 4; i++) {
+    guint8 d = data[4 + i];
+    if (g_ascii_isalnum (d))
+      ndata[i] = g_ascii_tolower (d);
+    else
+      ndata[i] = '_';
+  }
+
+  media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
+      ndata[0], ndata[1], ndata[2], ndata[3]);
+  GST_DEBUG_OBJECT (demux, "media type %s", media_type);
+
+  s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
+  sample = gst_sample_new (buf, NULL, NULL, s);
+  gst_buffer_unref (buf);
+  g_free (media_type);
+
+  GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
+      len, s);
+
+  gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
+      GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
+
+  gst_sample_unref (sample);
+}
+
+static void
+qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
+{
+  GNode *meta;
+  GNode *ilst;
+  GNode *xmp_;
+  GNode *node;
+  gint i;
+  GstQtDemuxTagList demuxtaglist;
+
+  demuxtaglist.demux = qtdemux;
+  demuxtaglist.taglist = taglist;
+
+  meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
+  if (meta != NULL) {
+    ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
+    if (ilst == NULL) {
+      GST_LOG_OBJECT (qtdemux, "no ilst");
+      return;
+    }
+  } else {
+    ilst = udta;
+    GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
+  }
+
+  i = 0;
+  while (i < G_N_ELEMENTS (add_funcs)) {
+    node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
+    if (node) {
+      gint len;
+
+      len = QT_UINT32 (node->data);
+      if (len < 12) {
+        GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
+            GST_FOURCC_ARGS (add_funcs[i].fourcc));
+      } else {
+        add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
+            add_funcs[i].gst_tag_bis, node);
+      }
+      g_node_destroy (node);
+    } else {
+      i++;
+    }
+  }
+
+  /* parsed nodes have been removed, pass along remainder as blob */
+  g_node_children_foreach (ilst, G_TRAVERSE_ALL,
+      (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
+
+  /* parse up XMP_ node if existing */
+  xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
+  if (xmp_ != NULL) {
+    GstBuffer *buf;
+    GstTagList *xmptaglist;
+
+    buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
+        QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
+    xmptaglist = gst_tag_list_from_xmp_buffer (buf);
+    gst_buffer_unref (buf);
+
+    qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
+  } else {
+    GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
+  }
+}
+
+typedef struct
+{
+  GstStructure *structure;      /* helper for sort function */
+  gchar *location;
+  guint min_req_bitrate;
+  guint min_req_qt_version;
+} GstQtReference;
+
+static gint
+qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
+{
+  GstQtReference *ref_a = (GstQtReference *) a;
+  GstQtReference *ref_b = (GstQtReference *) b;
+
+  if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
+    return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
+
+  /* known bitrates go before unknown; higher bitrates go first */
+  return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
+}
+
+/* sort the redirects and post a message for the application.
+ */
+static void
+qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
+{
+  GstQtReference *best;
+  GstStructure *s;
+  GstMessage *msg;
+  GValue list_val = { 0, };
+  GList *l;
+
+  g_assert (references != NULL);
+
+  references = g_list_sort (references, qtdemux_redirects_sort_func);
+
+  best = (GstQtReference *) references->data;
+
+  g_value_init (&list_val, GST_TYPE_LIST);
+
+  for (l = references; l != NULL; l = l->next) {
+    GstQtReference *ref = (GstQtReference *) l->data;
+    GValue struct_val = { 0, };
+
+    ref->structure = gst_structure_new ("redirect",
+        "new-location", G_TYPE_STRING, ref->location, NULL);
+
+    if (ref->min_req_bitrate > 0) {
+      gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
+          ref->min_req_bitrate, NULL);
+    }
+
+    g_value_init (&struct_val, GST_TYPE_STRUCTURE);
+    g_value_set_boxed (&struct_val, ref->structure);
+    gst_value_list_append_value (&list_val, &struct_val);
+    g_value_unset (&struct_val);
+    /* don't free anything here yet, since we need best->structure below */
+  }
+
+  g_assert (best != NULL);
+  s = gst_structure_copy (best->structure);
+
+  if (g_list_length (references) > 1) {
+    gst_structure_set_value (s, "locations", &list_val);
+  }
+
+  g_value_unset (&list_val);
+
+  for (l = references; l != NULL; l = l->next) {
+    GstQtReference *ref = (GstQtReference *) l->data;
+
+    gst_structure_free (ref->structure);
+    g_free (ref->location);
+    g_free (ref);
+  }
+  g_list_free (references);
+
+  GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
+  msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
+  gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
+  qtdemux->posted_redirect = TRUE;
+}
+
+/* look for redirect nodes, collect all redirect information and
+ * process it.
+ */
+static gboolean
+qtdemux_parse_redirects (GstQTDemux * qtdemux)
+{
+  GNode *rmra, *rmda, *rdrf;
+
+  rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
+  if (rmra) {
+    GList *redirects = NULL;
+
+    rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
+    while (rmda) {
+      GstQtReference ref = { NULL, NULL, 0, 0 };
+      GNode *rmdr, *rmvc;
+
+      if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
+        ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
+        GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
+            ref.min_req_bitrate);
+      }
+
+      if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
+        guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
+        guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
+
+#ifndef GST_DISABLE_GST_DEBUG
+        guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
+#endif
+        guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
+
+        GST_LOG_OBJECT (qtdemux,
+            "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
+            ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
+            bitmask, check_type);
+        if (package == FOURCC_qtim && check_type == 0) {
+          ref.min_req_qt_version = version;
+        }
+      }
+
+      rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
+      if (rdrf) {
+        guint32 ref_type;
+        guint8 *ref_data;
+        guint ref_len;
+
+        ref_len = QT_UINT32 ((guint8 *) rdrf->data);
+        if (ref_len > 20) {
+          ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
+          ref_data = (guint8 *) rdrf->data + 20;
+          if (ref_type == FOURCC_alis) {
+            guint record_len, record_version, fn_len;
+
+            if (ref_len > 70) {
+              /* MacOSX alias record, google for alias-layout.txt */
+              record_len = QT_UINT16 (ref_data + 4);
+              record_version = QT_UINT16 (ref_data + 4 + 2);
+              fn_len = QT_UINT8 (ref_data + 50);
+              if (record_len > 50 && record_version == 2 && fn_len > 0) {
+                ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
+              }
+            } else {
+              GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
+                  ref_len);
+            }
+          } else if (ref_type == FOURCC_url_) {
+            ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
+          } else {
+            GST_DEBUG_OBJECT (qtdemux,
+                "unknown rdrf reference type %" GST_FOURCC_FORMAT,
+                GST_FOURCC_ARGS (ref_type));
+          }
+          if (ref.location != NULL) {
+            GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
+            redirects =
+                g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
+          } else {
+            GST_WARNING_OBJECT (qtdemux,
+                "Failed to extract redirect location from rdrf atom");
+          }
+        } else {
+          GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
+        }
+      }
+
+      /* look for others */
+      rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
+    }
+
+    if (redirects != NULL) {
+      qtdemux_process_redirects (qtdemux, redirects);
+    }
+  }
+  return TRUE;
+}
+
+static GstTagList *
+qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
+{
+  const gchar *fmt;
+
+  if (tags == NULL) {
+    tags = gst_tag_list_new_empty ();
+    gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
+  }
+
+  if (qtdemux->major_brand == FOURCC_mjp2)
+    fmt = "Motion JPEG 2000";
+  else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
+    fmt = "3GP";
+  else if (qtdemux->major_brand == FOURCC_qt__)
+    fmt = "Quicktime";
+  else if (qtdemux->fragmented)
+    fmt = "ISO fMP4";
+  else
+    fmt = "ISO MP4/M4A";
+
+  GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
+      GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
+
+  gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
+      fmt, NULL);
+
+  return tags;
+}
+
+/* we have read the complete moov node now.
+ * This function parses all of the relevant info, creates the traks and
+ * prepares all data structures for playback
+ */
+static gboolean
+qtdemux_parse_tree (GstQTDemux * qtdemux)
+{
+  GNode *mvhd;
+  GNode *trak;
+  GNode *udta;
+  GNode *mvex;
+  GstClockTime duration;
+  GNode *pssh;
+  guint64 creation_time;
+  GstDateTime *datetime = NULL;
+  gint version;
+
+  /* make sure we have a usable taglist */
+  qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
+
+  mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
+  if (mvhd == NULL) {
+    GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
+    return qtdemux_parse_redirects (qtdemux);
+  }
+
+  version = QT_UINT8 ((guint8 *) mvhd->data + 8);
+  if (version == 1) {
+    creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
+    qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
+    qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
+  } else if (version == 0) {
+    creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
+    qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
+    qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
+  } else {
+    GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
+    return FALSE;
+  }
+
+  /* Moving qt creation time (secs since 1904) to unix time */
+  if (creation_time != 0) {
+    /* Try to use epoch first as it should be faster and more commonly found */
+    if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
+      GTimeVal now;
+
+      creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
+      /* some data cleansing sanity */
+      g_get_current_time (&now);
+      if (now.tv_sec + 24 * 3600 < creation_time) {
+        GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
+      } else {
+        datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
+      }
+    } else {
+      GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
+      GDateTime *dt, *dt_local;
+
+      dt = g_date_time_add_seconds (base_dt, creation_time);
+      dt_local = g_date_time_to_local (dt);
+      datetime = gst_date_time_new_from_g_date_time (dt_local);
+
+      g_date_time_unref (base_dt);
+      g_date_time_unref (dt);
+    }
+  }
+  if (datetime) {
+    /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
+    gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
+        datetime, NULL);
+    gst_date_time_unref (datetime);
+  }
+
+  GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
+  GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
+
+  /* check for fragmented file and get some (default) data */
+  mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
+  if (mvex) {
+    GNode *mehd;
+    GstByteReader mehd_data;
+
+    /* let track parsing or anyone know weird stuff might happen ... */
+    qtdemux->fragmented = TRUE;
+
+    /* compensate for total duration */
+    mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
+    if (mehd)
+      qtdemux_parse_mehd (qtdemux, &mehd_data);
+  }
+
+  /* set duration in the segment info */
+  gst_qtdemux_get_duration (qtdemux, &duration);
+  if (duration) {
+    qtdemux->segment.duration = duration;
+    /* also do not exceed duration; stop is set that way post seek anyway,
+     * and segment activation falls back to duration,
+     * whereas loop only checks stop, so let's align this here as well */
+    qtdemux->segment.stop = duration;
+  }
+
+  /* parse all traks */
+  trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
+  while (trak) {
+    qtdemux_parse_trak (qtdemux, trak);
+    /* iterate all siblings */
+    trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
+  }
+
+  qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
+
+  /* find tags */
+  udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
+  if (udta) {
+    qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
+  } else {
+    GST_LOG_OBJECT (qtdemux, "No udta node found.");
+  }
+
+  /* maybe also some tags in meta box */
+  udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
+  if (udta) {
+    GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
+    qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
+  } else {
+    GST_LOG_OBJECT (qtdemux, "No meta node found.");
+  }
+
+  /* parse any protection system info */
+  pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
+  while (pssh) {
+    GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
+    qtdemux_parse_pssh (qtdemux, pssh);
+    pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
+  }
+
+  qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
+
+  return TRUE;
+}
+
+/* taken from ffmpeg */
+static int
+read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
+{
+  int count = 4;
+  int len = 0;
+
+  while (count--) {
+    int c;
+
+    if (ptr >= end)
+      return -1;
+
+    c = *ptr++;
+    len = (len << 7) | (c & 0x7f);
+    if (!(c & 0x80))
+      break;
+  }
+  *end_out = ptr;
+  return len;
+}
+
+/* this can change the codec originally present in @list */
+static void
+gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
+{
+  int len = QT_UINT32 (esds->data);
+  guint8 *ptr = esds->data;
+  guint8 *end = ptr + len;
+  int tag;
+  guint8 *data_ptr = NULL;
+  int data_len = 0;
+  guint8 object_type_id = 0;
+  const char *codec_name = NULL;
+  GstCaps *caps = NULL;
+
+  GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
+  ptr += 8;
+  GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
+  ptr += 4;
+  while (ptr + 1 < end) {
+    tag = QT_UINT8 (ptr);
+    GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
+    ptr++;
+    len = read_descr_size (ptr, end, &ptr);
+    GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
+
+    /* Check the stated amount of data is available for reading */
+    if (len < 0 || ptr + len > end)
+      break;
+
+    switch (tag) {
+      case ES_DESCRIPTOR_TAG:
+        GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
+        GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
+        ptr += 3;
+        break;
+      case DECODER_CONFIG_DESC_TAG:{
+        guint max_bitrate, avg_bitrate;
+
+        object_type_id = QT_UINT8 (ptr);
+        max_bitrate = QT_UINT32 (ptr + 5);
+        avg_bitrate = QT_UINT32 (ptr + 9);
+        GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
+        GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
+        GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
+        GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
+        GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
+        if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
+          gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+              GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
+        }
+        if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
+          gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
+              avg_bitrate, NULL);
+        }
+        ptr += 13;
+        break;
+      }
+      case DECODER_SPECIFIC_INFO_TAG:
+        GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
+        if (object_type_id == 0xe0 && len == 0x40) {
+          guint8 *data;
+          GstStructure *s;
+          guint32 clut[16];
+          gint i;
+
+          GST_DEBUG_OBJECT (qtdemux,
+              "Have VOBSUB palette. Creating palette event");
+          /* move to decConfigDescr data and read palette */
+          data = ptr;
+          for (i = 0; i < 16; i++) {
+            clut[i] = QT_UINT32 (data);
+            data += 4;
+          }
+
+          s = gst_structure_new ("application/x-gst-dvd", "event",
+              G_TYPE_STRING, "dvd-spu-clut-change",
+              "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
+              "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
+              "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
+              "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
+              "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
+              "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
+              "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
+              "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
+              NULL);
+
+          /* store event and trigger custom processing */
+          stream->pending_event =
+              gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
+        } else {
+          /* Generic codec_data handler puts it on the caps */
+          data_ptr = ptr;
+          data_len = len;
+        }
+
+        ptr += len;
+        break;
+      case SL_CONFIG_DESC_TAG:
+        GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
+        ptr += 1;
+        break;
+      default:
+        GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
+            tag);
+        GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
+        ptr += len;
+        break;
+    }
+  }
+
+  /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
+   * in use, and should also be used to override some other parameters for some
+   * codecs. */
+  switch (object_type_id) {
+    case 0x20:                 /* MPEG-4 */
+      /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
+       * profile_and_level_indication */
+      if (data_ptr != NULL && data_len >= 5 &&
+          GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
+        gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
+            data_ptr + 4, data_len - 4);
+      }
+      break;                    /* Nothing special needed here */
+    case 0x21:                 /* H.264 */
+      codec_name = "H.264 / AVC";
+      caps = gst_caps_new_simple ("video/x-h264",
+          "stream-format", G_TYPE_STRING, "avc",
+          "alignment", G_TYPE_STRING, "au", NULL);
+      break;
+    case 0x40:                 /* AAC (any) */
+    case 0x66:                 /* AAC Main */
+    case 0x67:                 /* AAC LC */
+    case 0x68:                 /* AAC SSR */
+      /* Override channels and rate based on the codec_data, as it's often
+       * wrong. */
+      /* Only do so for basic setup without HE-AAC extension */
+      if (data_ptr && data_len == 2) {
+        guint channels, rate;
+
+        channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
+        if (channels > 0)
+          entry->n_channels = channels;
+
+        rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
+        if (rate > 0)
+          entry->rate = rate;
+      }
+
+      /* Set level and profile if possible */
+      if (data_ptr != NULL && data_len >= 2) {
+        gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
+            data_ptr, data_len);
+      } else {
+        const gchar *profile_str = NULL;
+        GstBuffer *buffer;
+        GstMapInfo map;
+        guint8 *codec_data;
+        gint rate_idx, profile;
+
+        /* No codec_data, let's invent something.
+         * FIXME: This is wrong for SBR! */
+
+        GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
+
+        buffer = gst_buffer_new_and_alloc (2);
+        gst_buffer_map (buffer, &map, GST_MAP_WRITE);
+        codec_data = map.data;
+
+        rate_idx =
+            gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
+            (stream)->rate);
+
+        switch (object_type_id) {
+          case 0x66:
+            profile_str = "main";
+            profile = 0;
+            break;
+          case 0x67:
+            profile_str = "lc";
+            profile = 1;
+            break;
+          case 0x68:
+            profile_str = "ssr";
+            profile = 2;
+            break;
+          default:
+            profile = 3;
+            break;
+        }
+
+        codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
+        codec_data[1] =
+            ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
+
+        gst_buffer_unmap (buffer, &map);
+        gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
+            GST_TYPE_BUFFER, buffer, NULL);
+        gst_buffer_unref (buffer);
+
+        if (profile_str) {
+          gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
+              G_TYPE_STRING, profile_str, NULL);
+        }
+      }
+      break;
+    case 0x60:                 /* MPEG-2, various profiles */
+    case 0x61:
+    case 0x62:
+    case 0x63:
+    case 0x64:
+    case 0x65:
+      codec_name = "MPEG-2 video";
+      caps = gst_caps_new_simple ("video/mpeg",
+          "mpegversion", G_TYPE_INT, 2,
+          "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+      break;
+    case 0x69:                 /* MPEG-2 BC audio */
+    case 0x6B:                 /* MPEG-1 audio */
+      caps = gst_caps_new_simple ("audio/mpeg",
+          "mpegversion", G_TYPE_INT, 1, NULL);
+      codec_name = "MPEG-1 audio";
+      break;
+    case 0x6A:                 /* MPEG-1 */
+      codec_name = "MPEG-1 video";
+      caps = gst_caps_new_simple ("video/mpeg",
+          "mpegversion", G_TYPE_INT, 1,
+          "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+      break;
+    case 0x6C:                 /* MJPEG */
+      caps =
+          gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
+          NULL);
+      codec_name = "Motion-JPEG";
+      break;
+    case 0x6D:                 /* PNG */
+      caps =
+          gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
+          NULL);
+      codec_name = "PNG still images";
+      break;
+    case 0x6E:                 /* JPEG2000 */
+      codec_name = "JPEG-2000";
+      caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
+      break;
+    case 0xA4:                 /* Dirac */
+      codec_name = "Dirac";
+      caps = gst_caps_new_empty_simple ("video/x-dirac");
+      break;
+    case 0xA5:                 /* AC3 */
+      codec_name = "AC-3 audio";
+      caps = gst_caps_new_simple ("audio/x-ac3",
+          "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+      break;
+    case 0xA9:                 /* AC3 */
+      codec_name = "DTS audio";
+      caps = gst_caps_new_simple ("audio/x-dts",
+          "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+      break;
+    case 0xE1:                 /* QCELP */
+      /* QCELP, the codec_data is a riff tag (little endian) with
+       * more info (http://ftp.3gpp2.org/TSGC/Working/2003/2003-05-SanDiego/TSG-C-2003-05-San%20Diego/WG1/SWG12/C12-20030512-006%20=%20C12-20030217-015_Draft_Baseline%20Text%20of%20FFMS_R2.doc). */
+      caps = gst_caps_new_empty_simple ("audio/qcelp");
+      codec_name = "QCELP";
+      break;
+    default:
+      break;
+  }
+
+  /* If we have a replacement caps, then change our caps for this stream */
+  if (caps) {
+    gst_caps_unref (entry->caps);
+    entry->caps = caps;
+  }
+
+  if (codec_name && list)
+    gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+        GST_TAG_AUDIO_CODEC, codec_name, NULL);
+
+  /* Add the codec_data attribute to caps, if we have it */
+  if (data_ptr) {
+    GstBuffer *buffer;
+
+    buffer = gst_buffer_new_and_alloc (data_len);
+    gst_buffer_fill (buffer, 0, data_ptr, data_len);
+
+    GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
+    GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
+
+    gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
+        buffer, NULL);
+    gst_buffer_unref (buffer);
+  }
+
+}
+
+static inline GstCaps *
+_get_unknown_codec_name (const gchar * type, guint32 fourcc)
+{
+  GstCaps *caps;
+  guint i;
+  char *s, fourstr[5];
+
+  g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
+  for (i = 0; i < 4; i++) {
+    if (!g_ascii_isalnum (fourstr[i]))
+      fourstr[i] = '_';
+  }
+  s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
+  caps = gst_caps_new_empty_simple (s);
+  g_free (s);
+  return caps;
+}
+
+#define _codec(name) \
+  do { \
+    if (codec_name) { \
+      *codec_name = g_strdup (name); \
+    } \
+  } while (0)
+
+static GstCaps *
+qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    QtDemuxStreamStsdEntry * entry, guint32 fourcc,
+    const guint8 * stsd_entry_data, gchar ** codec_name)
+{
+  GstCaps *caps = NULL;
+  GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
+
+  switch (fourcc) {
+    case FOURCC_png:
+      _codec ("PNG still images");
+      caps = gst_caps_new_empty_simple ("image/png");
+      break;
+    case FOURCC_jpeg:
+      _codec ("JPEG still images");
+      caps =
+          gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
+          NULL);
+      break;
+    case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
+    case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
+    case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
+    case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
+      _codec ("Motion-JPEG");
+      caps =
+          gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
+          NULL);
+      break;
+    case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
+      _codec ("Motion-JPEG format B");
+      caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
+      break;
+    case FOURCC_mjp2:
+      _codec ("JPEG-2000");
+      /* override to what it should be according to spec, avoid palette_data */
+      entry->bits_per_sample = 24;
+      caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
+      break;
+    case FOURCC_SVQ3:
+      _codec ("Sorensen video v.3");
+      caps = gst_caps_new_simple ("video/x-svq",
+          "svqversion", G_TYPE_INT, 3, NULL);
+      break;
+    case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
+    case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
+      _codec ("Sorensen video v.1");
+      caps = gst_caps_new_simple ("video/x-svq",
+          "svqversion", G_TYPE_INT, 1, NULL);
+      break;
+    case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
+      caps = gst_caps_new_empty_simple ("video/x-raw");
+      gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
+      _codec ("Windows Raw RGB");
+      stream->alignment = 32;
+      break;
+    case FOURCC_raw_:
+    {
+      guint16 bps;
+
+      bps = QT_UINT16 (stsd_entry_data + 82);
+      switch (bps) {
+        case 15:
+          format = GST_VIDEO_FORMAT_RGB15;
+          break;
+        case 16:
+          format = GST_VIDEO_FORMAT_RGB16;
+          break;
+        case 24:
+          format = GST_VIDEO_FORMAT_RGB;
+          break;
+        case 32:
+          format = GST_VIDEO_FORMAT_ARGB;
+          break;
+        default:
+          /* unknown */
+          break;
+      }
+      break;
+    }
+    case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
+      format = GST_VIDEO_FORMAT_I420;
+      break;
+    case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
+    case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
+      format = GST_VIDEO_FORMAT_I420;
+      break;
+    case FOURCC_2vuy:
+    case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
+      format = GST_VIDEO_FORMAT_UYVY;
+      break;
+    case GST_MAKE_FOURCC ('v', '3', '0', '8'):
+      format = GST_VIDEO_FORMAT_v308;
+      break;
+    case GST_MAKE_FOURCC ('v', '2', '1', '6'):
+      format = GST_VIDEO_FORMAT_v216;
+      break;
+    case FOURCC_v210:
+      format = GST_VIDEO_FORMAT_v210;
+      break;
+    case GST_MAKE_FOURCC ('r', '2', '1', '0'):
+      format = GST_VIDEO_FORMAT_r210;
+      break;
+      /* Packed YUV 4:4:4 10 bit in 32 bits, complex
+         case GST_MAKE_FOURCC ('v', '4', '1', '0'):
+         format = GST_VIDEO_FORMAT_v410;
+         break;
+       */
+      /* Packed YUV 4:4:4:4 8 bit in 32 bits
+       * but different order than AYUV
+       case GST_MAKE_FOURCC ('v', '4', '0', '8'):
+       format = GST_VIDEO_FORMAT_v408;
+       break;
+       */
+    case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
+    case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
+      _codec ("MPEG-1 video");
+      caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
+          "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+      break;
+    case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
+    case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
+    case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
+    case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
+    case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
+    case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
+    case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
+    case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
+    case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
+    case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
+    case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
+    case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
+    case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
+    case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
+    case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
+    case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
+    case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
+    case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
+    case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
+    case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
+    case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
+    case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
+    case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
+    case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
+    case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
+    case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
+    case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
+    case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
+    case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
+    case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
+    case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
+    case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
+    case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
+    case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
+    case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
+    case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
+    case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
+    case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
+    case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
+    case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
+    case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
+    case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
+    case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
+    case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
+    case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
+    case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
+    case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
+      _codec ("MPEG-2 video");
+      caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
+          "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+      break;
+    case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
+      _codec ("GIF still images");
+      caps = gst_caps_new_empty_simple ("image/gif");
+      break;
+    case FOURCC_h263:
+    case GST_MAKE_FOURCC ('H', '2', '6', '3'):
+    case FOURCC_s263:
+    case GST_MAKE_FOURCC ('U', '2', '6', '3'):
+      _codec ("H.263");
+      /* ffmpeg uses the height/width props, don't know why */
+      caps = gst_caps_new_simple ("video/x-h263",
+          "variant", G_TYPE_STRING, "itu", NULL);
+      break;
+    case FOURCC_mp4v:
+    case FOURCC_MP4V:
+      _codec ("MPEG-4 video");
+      caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
+          "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+      break;
+    case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
+    case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
+      _codec ("Microsoft MPEG-4 4.3");  /* FIXME? */
+      caps = gst_caps_new_simple ("video/x-msmpeg",
+          "msmpegversion", G_TYPE_INT, 43, NULL);
+      break;
+    case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
+      _codec ("DivX 3");
+      caps = gst_caps_new_simple ("video/x-divx",
+          "divxversion", G_TYPE_INT, 3, NULL);
+      break;
+    case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
+    case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
+      _codec ("DivX 4");
+      caps = gst_caps_new_simple ("video/x-divx",
+          "divxversion", G_TYPE_INT, 4, NULL);
+      break;
+    case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
+      _codec ("DivX 5");
+      caps = gst_caps_new_simple ("video/x-divx",
+          "divxversion", G_TYPE_INT, 5, NULL);
+      break;
+
+    case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
+      _codec ("FFV1");
+      caps = gst_caps_new_simple ("video/x-ffv",
+          "ffvversion", G_TYPE_INT, 1, NULL);
+      break;
+
+    case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
+    case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
+    case FOURCC_XVID:
+    case FOURCC_xvid:
+    case FOURCC_FMP4:
+    case FOURCC_fmp4:
+    case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
+      caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
+          "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+      _codec ("MPEG-4");
+      break;
+
+    case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
+      _codec ("Cinepak");
+      caps = gst_caps_new_empty_simple ("video/x-cinepak");
+      break;
+    case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
+      _codec ("Apple QuickDraw");
+      caps = gst_caps_new_empty_simple ("video/x-qdrw");
+      break;
+    case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
+      _codec ("Apple video");
+      caps = gst_caps_new_empty_simple ("video/x-apple-video");
+      break;
+    case FOURCC_H264:
+    case FOURCC_avc1:
+      _codec ("H.264 / AVC");
+      caps = gst_caps_new_simple ("video/x-h264",
+          "stream-format", G_TYPE_STRING, "avc",
+          "alignment", G_TYPE_STRING, "au", NULL);
+      break;
+    case FOURCC_avc3:
+      _codec ("H.264 / AVC");
+      caps = gst_caps_new_simple ("video/x-h264",
+          "stream-format", G_TYPE_STRING, "avc3",
+          "alignment", G_TYPE_STRING, "au", NULL);
+      break;
+    case FOURCC_H265:
+    case FOURCC_hvc1:
+      _codec ("H.265 / HEVC");
+      caps = gst_caps_new_simple ("video/x-h265",
+          "stream-format", G_TYPE_STRING, "hvc1",
+          "alignment", G_TYPE_STRING, "au", NULL);
+      break;
+    case FOURCC_hev1:
+      _codec ("H.265 / HEVC");
+      caps = gst_caps_new_simple ("video/x-h265",
+          "stream-format", G_TYPE_STRING, "hev1",
+          "alignment", G_TYPE_STRING, "au", NULL);
+      break;
+    case FOURCC_rle_:
+      _codec ("Run-length encoding");
+      caps = gst_caps_new_simple ("video/x-rle",
+          "layout", G_TYPE_STRING, "quicktime", NULL);
+      break;
+    case FOURCC_WRLE:
+      _codec ("Run-length encoding");
+      caps = gst_caps_new_simple ("video/x-rle",
+          "layout", G_TYPE_STRING, "microsoft", NULL);
+      break;
+    case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
+    case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
+      _codec ("Indeo Video 3");
+      caps = gst_caps_new_simple ("video/x-indeo",
+          "indeoversion", G_TYPE_INT, 3, NULL);
+      break;
+    case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
+    case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
+      _codec ("Intel Video 4");
+      caps = gst_caps_new_simple ("video/x-indeo",
+          "indeoversion", G_TYPE_INT, 4, NULL);
+      break;
+    case FOURCC_dvcp:
+    case FOURCC_dvc_:
+    case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
+    case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
+    case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
+    case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
+    case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
+    case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
+      _codec ("DV Video");
+      caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
+          "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+      break;
+    case FOURCC_dv5n:          /* DVCPRO50 NTSC */
+    case FOURCC_dv5p:          /* DVCPRO50 PAL */
+      _codec ("DVCPro50 Video");
+      caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
+          "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+      break;
+    case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
+    case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
+      _codec ("DVCProHD Video");
+      caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
+          "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+      break;
+    case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
+      _codec ("Apple Graphics (SMC)");
+      caps = gst_caps_new_empty_simple ("video/x-smc");
+      break;
+    case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
+      _codec ("VP3");
+      caps = gst_caps_new_empty_simple ("video/x-vp3");
+      break;
+    case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
+      _codec ("VP6 Flash");
+      caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
+      break;
+    case FOURCC_XiTh:
+      _codec ("Theora");
+      caps = gst_caps_new_empty_simple ("video/x-theora");
+      /* theora uses one byte of padding in the data stream because it does not
+       * allow 0 sized packets while theora does */
+      entry->padding = 1;
+      break;
+    case FOURCC_drac:
+      _codec ("Dirac");
+      caps = gst_caps_new_empty_simple ("video/x-dirac");
+      break;
+    case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
+      _codec ("TIFF still images");
+      caps = gst_caps_new_empty_simple ("image/tiff");
+      break;
+    case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
+      _codec ("Apple Intermediate Codec");
+      caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
+      break;
+    case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
+      _codec ("AVID DNxHD");
+      caps = gst_caps_from_string ("video/x-dnxhd");
+      break;
+    case FOURCC_VP80:
+    case FOURCC_vp08:
+      _codec ("On2 VP8");
+      caps = gst_caps_from_string ("video/x-vp8");
+      break;
+    case FOURCC_vp09:
+      _codec ("Google VP9");
+      caps = gst_caps_from_string ("video/x-vp9");
+      break;
+    case FOURCC_apcs:
+      _codec ("Apple ProRes LT");
+      caps =
+          gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
+          NULL);
+      break;
+    case FOURCC_apch:
+      _codec ("Apple ProRes HQ");
+      caps =
+          gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
+          NULL);
+      break;
+    case FOURCC_apcn:
+      _codec ("Apple ProRes");
+      caps =
+          gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
+          "standard", NULL);
+      break;
+    case FOURCC_apco:
+      _codec ("Apple ProRes Proxy");
+      caps =
+          gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
+          "proxy", NULL);
+      break;
+    case FOURCC_ap4h:
+      _codec ("Apple ProRes 4444");
+      caps =
+          gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
+          "4444", NULL);
+      break;
+    case FOURCC_ap4x:
+      _codec ("Apple ProRes 4444 XQ");
+      caps =
+          gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
+          "4444xq", NULL);
+      break;
+    case FOURCC_cfhd:
+      _codec ("GoPro CineForm");
+      caps = gst_caps_from_string ("video/x-cineform");
+      break;
+    case FOURCC_vc_1:
+    case FOURCC_ovc1:
+      _codec ("VC-1");
+      caps = gst_caps_new_simple ("video/x-wmv",
+          "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
+      break;
+    case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
+    default:
+    {
+      caps = _get_unknown_codec_name ("video", fourcc);
+      break;
+    }
+  }
+
+  if (format != GST_VIDEO_FORMAT_UNKNOWN) {
+    GstVideoInfo info;
+
+    gst_video_info_init (&info);
+    gst_video_info_set_format (&info, format, entry->width, entry->height);
+
+    caps = gst_video_info_to_caps (&info);
+    *codec_name = gst_pb_utils_get_codec_description (caps);
+
+    /* enable clipping for raw video streams */
+    stream->need_clip = TRUE;
+    stream->alignment = 32;
+  }
+
+  return caps;
+}
+
+static guint
+round_up_pow2 (guint n)
+{
+  n = n - 1;
+  n = n | (n >> 1);
+  n = n | (n >> 2);
+  n = n | (n >> 4);
+  n = n | (n >> 8);
+  n = n | (n >> 16);
+  return n + 1;
+}
+
+static GstCaps *
+qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
+    int len, gchar ** codec_name)
+{
+  GstCaps *caps;
+  const GstStructure *s;
+  const gchar *name;
+  gint endian = 0;
+  GstAudioFormat format = 0;
+  gint depth;
+
+  GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
+
+  depth = entry->bytes_per_packet * 8;
+
+  switch (fourcc) {
+    case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
+    case FOURCC_raw_:
+      /* 8-bit audio is unsigned */
+      if (depth == 8)
+        format = GST_AUDIO_FORMAT_U8;
+      /* otherwise it's signed and big-endian just like 'twos' */
+    case FOURCC_twos:
+      endian = G_BIG_ENDIAN;
+      /* fall-through */
+    case FOURCC_sowt:
+    {
+      gchar *str;
+
+      if (!endian)
+        endian = G_LITTLE_ENDIAN;
+
+      if (!format)
+        format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
+
+      str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
+      _codec (str);
+      g_free (str);
+
+      caps = gst_caps_new_simple ("audio/x-raw",
+          "format", G_TYPE_STRING, gst_audio_format_to_string (format),
+          "layout", G_TYPE_STRING, "interleaved", NULL);
+      stream->alignment = GST_ROUND_UP_8 (depth);
+      stream->alignment = round_up_pow2 (stream->alignment);
+      break;
+    }
+    case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
+      _codec ("Raw 64-bit floating-point audio");
+      caps = gst_caps_new_simple ("audio/x-raw",
+          "format", G_TYPE_STRING, "F64BE",
+          "layout", G_TYPE_STRING, "interleaved", NULL);
+      stream->alignment = 8;
+      break;
+    case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
+      _codec ("Raw 32-bit floating-point audio");
+      caps = gst_caps_new_simple ("audio/x-raw",
+          "format", G_TYPE_STRING, "F32BE",
+          "layout", G_TYPE_STRING, "interleaved", NULL);
+      stream->alignment = 4;
+      break;
+    case FOURCC_in24:
+      _codec ("Raw 24-bit PCM audio");
+      /* we assume BIG ENDIAN, an enda box will tell us to change this to little
+       * endian later */
+      caps = gst_caps_new_simple ("audio/x-raw",
+          "format", G_TYPE_STRING, "S24BE",
+          "layout", G_TYPE_STRING, "interleaved", NULL);
+      stream->alignment = 4;
+      break;
+    case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
+      _codec ("Raw 32-bit PCM audio");
+      caps = gst_caps_new_simple ("audio/x-raw",
+          "format", G_TYPE_STRING, "S32BE",
+          "layout", G_TYPE_STRING, "interleaved", NULL);
+      stream->alignment = 4;
+      break;
+    case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
+      _codec ("Raw 16-bit PCM audio");
+      caps = gst_caps_new_simple ("audio/x-raw",
+          "format", G_TYPE_STRING, "S16LE",
+          "layout", G_TYPE_STRING, "interleaved", NULL);
+      stream->alignment = 2;
+      break;
+    case FOURCC_ulaw:
+      _codec ("Mu-law audio");
+      caps = gst_caps_new_empty_simple ("audio/x-mulaw");
+      break;
+    case FOURCC_alaw:
+      _codec ("A-law audio");
+      caps = gst_caps_new_empty_simple ("audio/x-alaw");
+      break;
+    case 0x0200736d:
+    case 0x6d730002:
+      _codec ("Microsoft ADPCM");
+      /* Microsoft ADPCM-ACM code 2 */
+      caps = gst_caps_new_simple ("audio/x-adpcm",
+          "layout", G_TYPE_STRING, "microsoft", NULL);
+      break;
+    case 0x1100736d:
+    case 0x6d730011:
+      _codec ("DVI/IMA ADPCM");
+      caps = gst_caps_new_simple ("audio/x-adpcm",
+          "layout", G_TYPE_STRING, "dvi", NULL);
+      break;
+    case 0x1700736d:
+    case 0x6d730017:
+      _codec ("DVI/Intel IMA ADPCM");
+      /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
+      caps = gst_caps_new_simple ("audio/x-adpcm",
+          "layout", G_TYPE_STRING, "quicktime", NULL);
+      break;
+    case 0x5500736d:
+    case 0x6d730055:
+      /* MPEG layer 3, CBR only (pre QT4.1) */
+    case FOURCC__mp3:
+      _codec ("MPEG-1 layer 3");
+      /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
+      caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
+          "mpegversion", G_TYPE_INT, 1, NULL);
+      break;
+    case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
+      _codec ("MPEG-1 layer 2");
+      /* MPEG layer 2 */
+      caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
+          "mpegversion", G_TYPE_INT, 1, NULL);
+      break;
+    case 0x20736d:
+    case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
+      _codec ("EAC-3 audio");
+      caps = gst_caps_new_simple ("audio/x-eac3",
+          "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+      entry->sampled = TRUE;
+      break;
+    case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
+    case FOURCC_ac_3:
+      _codec ("AC-3 audio");
+      caps = gst_caps_new_simple ("audio/x-ac3",
+          "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+      entry->sampled = TRUE;
+      break;
+    case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
+    case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
+      _codec ("DTS audio");
+      caps = gst_caps_new_simple ("audio/x-dts",
+          "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+      entry->sampled = TRUE;
+      break;
+    case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
+    case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
+      _codec ("DTS-HD audio");
+      caps = gst_caps_new_simple ("audio/x-dts",
+          "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+      entry->sampled = TRUE;
+      break;
+    case FOURCC_MAC3:
+      _codec ("MACE-3");
+      caps = gst_caps_new_simple ("audio/x-mace",
+          "maceversion", G_TYPE_INT, 3, NULL);
+      break;
+    case FOURCC_MAC6:
+      _codec ("MACE-6");
+      caps = gst_caps_new_simple ("audio/x-mace",
+          "maceversion", G_TYPE_INT, 6, NULL);
+      break;
+    case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
+      /* ogg/vorbis */
+      caps = gst_caps_new_empty_simple ("application/ogg");
+      break;
+    case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
+      _codec ("DV audio");
+      caps = gst_caps_new_empty_simple ("audio/x-dv");
+      break;
+    case FOURCC_mp4a:
+      _codec ("MPEG-4 AAC audio");
+      caps = gst_caps_new_simple ("audio/mpeg",
+          "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
+          "stream-format", G_TYPE_STRING, "raw", NULL);
+      break;
+    case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
+      _codec ("QDesign Music");
+      caps = gst_caps_new_empty_simple ("audio/x-qdm");
+      break;
+    case FOURCC_QDM2:
+      _codec ("QDesign Music v.2");
+      /* FIXME: QDesign music version 2 (no constant) */
+      if (FALSE && data) {
+        caps = gst_caps_new_simple ("audio/x-qdm2",
+            "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
+            "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
+            "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
+      } else {
+        caps = gst_caps_new_empty_simple ("audio/x-qdm2");
+      }
+      break;
+    case FOURCC_agsm:
+      _codec ("GSM audio");
+      caps = gst_caps_new_empty_simple ("audio/x-gsm");
+      break;
+    case FOURCC_samr:
+      _codec ("AMR audio");
+      caps = gst_caps_new_empty_simple ("audio/AMR");
+      break;
+    case FOURCC_sawb:
+      _codec ("AMR-WB audio");
+      caps = gst_caps_new_empty_simple ("audio/AMR-WB");
+      break;
+    case FOURCC_ima4:
+      _codec ("Quicktime IMA ADPCM");
+      caps = gst_caps_new_simple ("audio/x-adpcm",
+          "layout", G_TYPE_STRING, "quicktime", NULL);
+      break;
+    case FOURCC_alac:
+      _codec ("Apple lossless audio");
+      caps = gst_caps_new_empty_simple ("audio/x-alac");
+      break;
+    case FOURCC_fLaC:
+      _codec ("Free Lossless Audio Codec");
+      caps = gst_caps_new_simple ("audio/x-flac",
+          "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+      break;
+    case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
+      _codec ("QualComm PureVoice");
+      caps = gst_caps_from_string ("audio/qcelp");
+      break;
+    case FOURCC_wma_:
+    case FOURCC_owma:
+      _codec ("WMA");
+      caps = gst_caps_new_empty_simple ("audio/x-wma");
+      break;
+    case FOURCC_opus:
+      _codec ("Opus");
+      caps = gst_caps_new_empty_simple ("audio/x-opus");
+      break;
+    case FOURCC_lpcm:
+    {
+      guint32 flags = 0;
+      guint32 depth = 0;
+      guint32 width = 0;
+      GstAudioFormat format;
+      enum
+      {
+        FLAG_IS_FLOAT = 0x1,
+        FLAG_IS_BIG_ENDIAN = 0x2,
+        FLAG_IS_SIGNED = 0x4,
+        FLAG_IS_PACKED = 0x8,
+        FLAG_IS_ALIGNED_HIGH = 0x10,
+        FLAG_IS_NON_INTERLEAVED = 0x20
+      };
+      _codec ("Raw LPCM audio");
+
+      if (data && len >= 36) {
+        depth = QT_UINT32 (data + 24);
+        flags = QT_UINT32 (data + 28);
+        width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
+      }
+      if ((flags & FLAG_IS_FLOAT) == 0) {
+        if (depth == 0)
+          depth = 16;
+        if (width == 0)
+          width = 16;
+        if ((flags & FLAG_IS_ALIGNED_HIGH))
+          depth = width;
+
+        format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
+            TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
+            G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
+        caps = gst_caps_new_simple ("audio/x-raw",
+            "format", G_TYPE_STRING,
+            format !=
+            GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
+            "UNKNOWN", "layout", G_TYPE_STRING,
+            (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
+            "interleaved", NULL);
+        stream->alignment = GST_ROUND_UP_8 (depth);
+        stream->alignment = round_up_pow2 (stream->alignment);
+      } else {
+        if (width == 0)
+          width = 32;
+        if (width == 64) {
+          if (flags & FLAG_IS_BIG_ENDIAN)
+            format = GST_AUDIO_FORMAT_F64BE;
+          else
+            format = GST_AUDIO_FORMAT_F64LE;
+        } else {
+          if (flags & FLAG_IS_BIG_ENDIAN)
+            format = GST_AUDIO_FORMAT_F32BE;
+          else
+            format = GST_AUDIO_FORMAT_F32LE;
+        }
+        caps = gst_caps_new_simple ("audio/x-raw",
+            "format", G_TYPE_STRING, gst_audio_format_to_string (format),
+            "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
+            "non-interleaved" : "interleaved", NULL);
+        stream->alignment = width / 8;
+      }
+      break;
+    }
+    case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
+      /* ? */
+    default:
+    {
+      caps = _get_unknown_codec_name ("audio", fourcc);
+      break;
+    }
+  }
+
+  if (caps) {
+    GstCaps *templ_caps =
+        gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
+    GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
+    gst_caps_unref (caps);
+    gst_caps_unref (templ_caps);
+    caps = intersection;
+  }
+
+  /* enable clipping for raw audio streams */
+  s = gst_caps_get_structure (caps, 0);
+  name = gst_structure_get_name (s);
+  if (g_str_has_prefix (name, "audio/x-raw")) {
+    stream->need_clip = TRUE;
+    stream->max_buffer_size = 4096 * entry->bytes_per_frame;
+    GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
+  }
+  return caps;
+}
+
+static GstCaps *
+qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    QtDemuxStreamStsdEntry * entry, guint32 fourcc,
+    const guint8 * stsd_entry_data, gchar ** codec_name)
+{
+  GstCaps *caps;
+
+  GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
+
+  switch (fourcc) {
+    case FOURCC_mp4s:
+      _codec ("DVD subtitle");
+      caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
+      stream->need_process = TRUE;
+      break;
+    case FOURCC_text:
+      _codec ("Quicktime timed text");
+      goto text;
+    case FOURCC_tx3g:
+      _codec ("3GPP timed text");
+    text:
+      caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
+          "utf8", NULL);
+      /* actual text piece needs to be extracted */
+      stream->need_process = TRUE;
+      break;
+    case FOURCC_stpp:
+      _codec ("XML subtitles");
+      caps = gst_caps_new_empty_simple ("application/ttml+xml");
+      break;
+    default:
+    {
+      caps = _get_unknown_codec_name ("text", fourcc);
+      break;
+    }
+  }
+  return caps;
+}
+
+static GstCaps *
+qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    QtDemuxStreamStsdEntry * entry, guint32 fourcc,
+    const guint8 * stsd_entry_data, gchar ** codec_name)
+{
+  GstCaps *caps;
+
+  switch (fourcc) {
+    case FOURCC_m1v:
+      _codec ("MPEG 1 video");
+      caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
+          "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+      break;
+    default:
+      caps = NULL;
+      break;
+  }
+  return caps;
+}
+
+static void
+gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
+    const gchar * system_id)
+{
+  gint i;
+
+  if (!qtdemux->protection_system_ids)
+    qtdemux->protection_system_ids =
+        g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
+  /* Check whether we already have an entry for this system ID. */
+  for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
+    const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
+    if (g_ascii_strcasecmp (system_id, id) == 0) {
+      return;
+    }
+  }
+  GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
+  g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,
+          -1));
+}
diff --git a/gst/isomp4/qtdemux.h b/gst/isomp4/qtdemux.h
new file mode 100644
index 0000000..ad4da3e
--- /dev/null
+++ b/gst/isomp4/qtdemux.h
@@ -0,0 +1,242 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_QTDEMUX_H__
+#define __GST_QTDEMUX_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/base/gstflowcombiner.h>
+#include "gstisoff.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_QTDEMUX \
+  (gst_qtdemux_get_type())
+#define GST_QTDEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_QTDEMUX,GstQTDemux))
+#define GST_QTDEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_QTDEMUX,GstQTDemuxClass))
+#define GST_IS_QTDEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_QTDEMUX))
+#define GST_IS_QTDEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QTDEMUX))
+
+#define GST_QTDEMUX_CAST(obj) ((GstQTDemux *)(obj))
+
+/* qtdemux produces these for atoms it cannot parse */
+#define GST_QT_DEMUX_PRIVATE_TAG "private-qt-tag"
+#define GST_QT_DEMUX_CLASSIFICATION_TAG "classification"
+
+#define GST_QTDEMUX_MAX_STREAMS         32
+
+typedef struct _GstQTDemux GstQTDemux;
+typedef struct _GstQTDemuxClass GstQTDemuxClass;
+typedef struct _QtDemuxStream QtDemuxStream;
+
+enum QtDemuxState
+{
+  QTDEMUX_STATE_INITIAL,        /* Initial state (haven't got the header yet) */
+  QTDEMUX_STATE_HEADER,         /* Parsing the header */
+  QTDEMUX_STATE_MOVIE,          /* Parsing/Playing the media data */
+  QTDEMUX_STATE_BUFFER_MDAT     /* Buffering the mdat atom */
+};
+
+struct _GstQTDemux {
+  GstElement element;
+
+  /* Global state */
+  enum QtDemuxState state;
+
+  /* static sink pad */
+  GstPad *sinkpad;
+
+  /* TRUE if pull-based */
+  gboolean pullbased;
+
+  gboolean posted_redirect;
+
+  QtDemuxStream *streams[GST_QTDEMUX_MAX_STREAMS];
+  gint     n_streams;
+  gint     n_video_streams;
+  gint     n_audio_streams;
+  gint     n_sub_streams;
+
+  GstFlowCombiner *flowcombiner;
+
+  /* Incoming stream group-id to set on downstream STREAM_START events.
+   * If upstream doesn't contain one, a global one will be generated */
+  gboolean have_group_id;
+  guint group_id;
+
+  guint  major_brand;
+  GstBuffer *comp_brands;
+
+  /* [moov] header.
+   * FIXME : This is discarded just after it's created. Just move it
+   * to a temporary variable ? */
+  GNode *moov_node;
+
+  /* FIXME : This is never freed. It is only assigned once. memleak ? */
+  GNode *moov_node_compressed;
+
+  /* Set to TRUE when the [moov] header has been fully parsed */
+  gboolean got_moov;
+
+  /* Global timescale for the incoming stream. Use the QTTIME macros
+   * to convert values to/from GstClockTime */
+  guint32 timescale;
+
+  /* Global duration (in global timescale). Use QTTIME macros to get GstClockTime */
+  guint64 duration;
+
+  /* Total size of header atoms. Used to calculate fallback overall bitrate */
+  guint header_size;
+
+  GstTagList *tag_list;
+
+  /* configured playback region */
+  GstSegment segment;
+
+  /* The SEGMENT_EVENT from upstream *OR* generated from segment (above) */
+  GstEvent *pending_newsegment;
+
+  guint32 segment_seqnum;
+
+  /* flag to indicate that we're working with a smoothstreaming fragment
+   * Mss doesn't have 'moov' or any information about the streams format,
+   * requiring qtdemux to expose and create the streams */
+  gboolean mss_mode;
+
+  /* Set to TRUE if the incoming stream is either a MSS stream or
+   * a Fragmented MP4 (containing the [mvex] atom in the header) */
+  gboolean fragmented;
+
+  /* PULL-BASED only : If TRUE there is a pending seek */
+  gboolean fragmented_seek_pending;
+
+  /* PULL-BASED : offset of first [moof] or of fragment to seek to
+   * PUSH-BASED : offset of latest [moof] */
+  guint64 moof_offset;
+
+  /* MSS streams have a single media that is unspecified at the atoms, so
+   * upstream provides it at the caps */
+  GstCaps *media_caps;
+
+  /* Set to TRUE when all streams have been exposed */
+  gboolean exposed;
+
+  gint64 chapters_track_id;
+
+  /* protection support */
+  GPtrArray *protection_system_ids; /* Holds identifiers of all content protection systems for all tracks */
+  GQueue protection_event_queue; /* holds copy of upstream protection events */
+  guint64 cenc_aux_info_offset;
+  guint8 *cenc_aux_info_sizes;
+  guint32 cenc_aux_sample_count;
+
+
+  /*
+   * ALL VARIABLES BELOW ARE ONLY USED IN PUSH-BASED MODE
+   */
+  GstAdapter *adapter;
+  guint neededbytes;
+  guint todrop;
+  /* Used to store data if [mdat] is before the headers */
+  GstBuffer *mdatbuffer;
+  /* Amount of bytes left to read in the current [mdat] */
+  guint64 mdatleft, mdatsize;
+
+  /* When restoring the mdat to the adapter, this buffer stores any
+   * trailing data that was after the last atom parsed as it has to be
+   * restored later along with the correct offset. Used in fragmented
+   * scenario where mdat/moof are one after the other in any order.
+   *
+   * Check https://bugzilla.gnome.org/show_bug.cgi?id=710623 */
+  GstBuffer *restoredata_buffer;
+  guint64 restoredata_offset;
+
+  /* The current offset in bytes from upstream.
+   * Note: While it makes complete sense when we are PULL-BASED (pulling
+   * in BYTES from upstream) and PUSH-BASED with a BYTE SEGMENT (receiving
+   * buffers with actual offsets), it is undefined in PUSH-BASED with a
+   * TIME SEGMENT */
+  guint64 offset;
+
+  /* offset of the mdat atom */
+  guint64 mdatoffset;
+  /* Offset of the first mdat */
+  guint64 first_mdat;
+  /* offset of last [moov] seen */
+  guint64 last_moov_offset;
+
+  /* If TRUE, qtdemux received upstream newsegment in TIME format
+   * which likely means that upstream is driving the pipeline (such as
+   * adaptive demuxers or dlna sources) */
+  gboolean upstream_format_is_time;
+
+  /* Seqnum of the seek event sent upstream.  Will be used to
+   * detect incoming FLUSH events corresponding to that */
+  guint32 offset_seek_seqnum;
+
+  /* UPSTREAM BYTE: Requested upstream byte seek offset.
+   * Currently it is only used to check if an incoming BYTE SEGMENT
+   * corresponds to a seek event that was sent upstream */
+  gint64 seek_offset;
+
+  /* UPSTREAM BYTE: Requested start/stop TIME values from
+   * downstream.
+   * Used to set on the downstream segment once the corresponding upstream
+   * BYTE SEEK has succeeded */
+  gint64 push_seek_start;
+  gint64 push_seek_stop;
+
+#if 0
+  /* gst index support */
+  GstIndex *element_index;
+  gint index_id;
+#endif
+
+  /* Whether upstream is seekable in BYTES */
+  gboolean upstream_seekable;
+  /* UPSTREAM BYTE: Size of upstream content.
+   * Note : This is only computed once ! If upstream grows in the meantime
+   * it will not be updated */
+  gint64 upstream_size;
+
+  /* UPSTREAM TIME : Contains the PTS (if any) of the
+   * buffer that contains a [moof] header. Will be used to establish
+   * the actual PTS of the samples contained within that fragment. */
+  guint64 fragment_start;
+  /* UPSTREAM TIME : The offset in bytes of the [moof]
+   * header start.
+   * Note : This is not computed from the GST_BUFFER_OFFSET field */
+  guint64 fragment_start_offset;
+};
+
+struct _GstQTDemuxClass {
+  GstElementClass parent_class;
+};
+
+GType gst_qtdemux_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_QTDEMUX_H__ */
diff --git a/gst/isomp4/qtdemux_debug.h b/gst/isomp4/qtdemux_debug.h
new file mode 100644
index 0000000..26da268
--- /dev/null
+++ b/gst/isomp4/qtdemux_debug.h
@@ -0,0 +1,12 @@
+#ifndef __GST_QTDEMUX_DEBUG_H__
+#define __GST_QTDEMUX_DEBUG_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+GST_DEBUG_CATEGORY_EXTERN (qtdemux_debug);
+
+G_END_DECLS
+
+#endif /* __GST_QTDEMUX_DEBUG_H__ */
diff --git a/gst/isomp4/qtdemux_dump.c b/gst/isomp4/qtdemux_dump.c
new file mode 100644
index 0000000..5ff2e92
--- /dev/null
+++ b/gst/isomp4/qtdemux_dump.c
@@ -0,0 +1,1048 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2009 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "qtdemux_debug.h"
+#include "qtdemux_types.h"
+#include "qtdemux_dump.h"
+#include "fourcc.h"
+
+#include "qtatomparser.h"
+
+#include <string.h>
+
+#define GST_CAT_DEFAULT qtdemux_debug
+
+#define GET_UINT8(data)   gst_byte_reader_get_uint8_unchecked(data)
+#define GET_UINT16(data)  gst_byte_reader_get_uint16_be_unchecked(data)
+#define GET_UINT32(data)  gst_byte_reader_get_uint32_be_unchecked(data)
+#define GET_UINT64(data)  gst_byte_reader_get_uint64_be_unchecked(data)
+#define GET_FP32(data)   (gst_byte_reader_get_uint32_be_unchecked(data)/65536.0)
+#define GET_FP16(data)   (gst_byte_reader_get_uint16_be_unchecked(data)/256.0)
+#define GET_FOURCC(data)  qt_atom_parser_get_fourcc_unchecked(data)
+
+gboolean
+qtdemux_dump_mvhd (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 version = 0;
+
+  if (!qt_atom_parser_has_remaining (data, 100))
+    return FALSE;
+
+  version = GET_UINT32 (data);
+  GST_LOG ("%*s  version/flags: %08x", depth, "", version);
+
+  version = version >> 24;
+  if (version == 0) {
+    GST_LOG ("%*s  creation time: %u", depth, "", GET_UINT32 (data));
+    GST_LOG ("%*s  modify time:   %u", depth, "", GET_UINT32 (data));
+    GST_LOG ("%*s  time scale:    1/%u sec", depth, "", GET_UINT32 (data));
+    GST_LOG ("%*s  duration:      %u", depth, "", GET_UINT32 (data));
+  } else if (version == 1) {
+    GST_LOG ("%*s  creation time: %" G_GUINT64_FORMAT,
+        depth, "", GET_UINT64 (data));
+    GST_LOG ("%*s  modify time:   %" G_GUINT64_FORMAT,
+        depth, "", GET_UINT64 (data));
+    GST_LOG ("%*s  time scale:    1/%u sec", depth, "", GET_UINT32 (data));
+    GST_LOG ("%*s  duration:      %" G_GUINT64_FORMAT,
+        depth, "", GET_UINT64 (data));
+  } else
+    return FALSE;
+
+  GST_LOG ("%*s  pref. rate:    %g", depth, "", GET_FP32 (data));
+  GST_LOG ("%*s  pref. volume:  %g", depth, "", GET_FP16 (data));
+  gst_byte_reader_skip_unchecked (data, 46);
+  GST_LOG ("%*s  preview time:  %u", depth, "", GET_UINT32 (data));
+  GST_LOG ("%*s  preview dur.:  %u", depth, "", GET_UINT32 (data));
+  GST_LOG ("%*s  poster time:   %u", depth, "", GET_UINT32 (data));
+  GST_LOG ("%*s  select time:   %u", depth, "", GET_UINT32 (data));
+  GST_LOG ("%*s  select dur.:   %u", depth, "", GET_UINT32 (data));
+  GST_LOG ("%*s  current time:  %u", depth, "", GET_UINT32 (data));
+  GST_LOG ("%*s  next track ID: %d", depth, "", GET_UINT32 (data));
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_tkhd (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint64 duration, ctime, mtime;
+  guint32 version = 0, track_id = 0, iwidth = 0, iheight = 0;
+  guint16 layer = 0, alt_group = 0, ivol = 0;
+  guint value_size;
+
+  if (!gst_byte_reader_get_uint32_be (data, &version))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", version);
+
+  value_size = ((version >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
+
+  if (qt_atom_parser_get_offset (data, value_size, &ctime) &&
+      qt_atom_parser_get_offset (data, value_size, &mtime) &&
+      gst_byte_reader_get_uint32_be (data, &track_id) &&
+      gst_byte_reader_skip (data, 4) &&
+      qt_atom_parser_get_offset (data, value_size, &duration) &&
+      gst_byte_reader_skip (data, 4) &&
+      gst_byte_reader_get_uint16_be (data, &layer) &&
+      gst_byte_reader_get_uint16_be (data, &alt_group) &&
+      gst_byte_reader_skip (data, 4) &&
+      gst_byte_reader_get_uint16_be (data, &ivol) &&
+      gst_byte_reader_skip (data, 2 + (9 * 4)) &&
+      gst_byte_reader_get_uint32_be (data, &iwidth) &&
+      gst_byte_reader_get_uint32_be (data, &iheight)) {
+    GST_LOG ("%*s  creation time: %" G_GUINT64_FORMAT, depth, "", ctime);
+    GST_LOG ("%*s  modify time:   %" G_GUINT64_FORMAT, depth, "", mtime);
+    GST_LOG ("%*s  track ID:      %u", depth, "", track_id);
+    GST_LOG ("%*s  duration:      %" G_GUINT64_FORMAT, depth, "", duration);
+    GST_LOG ("%*s  layer:         %u", depth, "", layer);
+    GST_LOG ("%*s  alt group:     %u", depth, "", alt_group);
+    GST_LOG ("%*s  volume:        %g", depth, "", ivol / 256.0);
+    GST_LOG ("%*s  track width:   %g", depth, "", iwidth / 65536.0);
+    GST_LOG ("%*s  track height:  %g", depth, "", iheight / 65536.0);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+gboolean
+qtdemux_dump_elst (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 ver_flags = 0, num_entries = 0, i;
+
+  if (!gst_byte_reader_get_uint32_be (data, &ver_flags) ||
+      !gst_byte_reader_get_uint32_be (data, &num_entries))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", ver_flags);
+  GST_LOG ("%*s  n entries:     %d", depth, "", num_entries);
+
+  if (!qt_atom_parser_has_chunks (data, num_entries, 4 + 4 + 4))
+    return FALSE;
+
+  for (i = 0; i < num_entries; i++) {
+    GST_LOG ("%*s    track dur:     %u", depth, "", GET_UINT32 (data));
+    GST_LOG ("%*s    media time:    %u", depth, "", GET_UINT32 (data));
+    GST_LOG ("%*s    media rate:    %g", depth, "", GET_FP32 (data));
+  }
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_mdhd (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 version = 0;
+  guint64 duration, ctime, mtime;
+  guint32 time_scale = 0;
+  guint16 language = 0, quality = 0;
+  guint value_size;
+
+  if (!gst_byte_reader_get_uint32_be (data, &version))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", version);
+
+  value_size = ((version >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
+
+  if (qt_atom_parser_get_offset (data, value_size, &ctime) &&
+      qt_atom_parser_get_offset (data, value_size, &mtime) &&
+      gst_byte_reader_get_uint32_be (data, &time_scale) &&
+      qt_atom_parser_get_offset (data, value_size, &duration) &&
+      gst_byte_reader_get_uint16_be (data, &language) &&
+      gst_byte_reader_get_uint16_be (data, &quality)) {
+    GST_LOG ("%*s  creation time: %" G_GUINT64_FORMAT, depth, "", ctime);
+    GST_LOG ("%*s  modify time:   %" G_GUINT64_FORMAT, depth, "", mtime);
+    GST_LOG ("%*s  time scale:    1/%u sec", depth, "", time_scale);
+    GST_LOG ("%*s  duration:      %" G_GUINT64_FORMAT, depth, "", duration);
+    GST_LOG ("%*s  language:      %u", depth, "", language);
+    GST_LOG ("%*s  quality:       %u", depth, "", quality);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+gboolean
+qtdemux_dump_hdlr (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 version, type, subtype, manufacturer;
+  const gchar *name;
+
+  if (!qt_atom_parser_has_remaining (data, 4 + 4 + 4 + 4 + 4 + 4))
+    return FALSE;
+
+  version = GET_UINT32 (data);
+  type = GET_FOURCC (data);
+  subtype = GET_FOURCC (data);
+  manufacturer = GET_FOURCC (data);
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", version);
+  GST_LOG ("%*s  type:          %" GST_FOURCC_FORMAT, depth, "",
+      GST_FOURCC_ARGS (type));
+  GST_LOG ("%*s  subtype:       %" GST_FOURCC_FORMAT, depth, "",
+      GST_FOURCC_ARGS (subtype));
+  GST_LOG ("%*s  manufacturer:  %" GST_FOURCC_FORMAT, depth, "",
+      GST_FOURCC_ARGS (manufacturer));
+  GST_LOG ("%*s  flags:         %08x", depth, "", GET_UINT32 (data));
+  GST_LOG ("%*s  flags mask:    %08x", depth, "", GET_UINT32 (data));
+
+  /* quicktime uses pascal string, mp4 zero-terminated string */
+  if (gst_byte_reader_peek_string (data, &name)) {
+    GST_LOG ("%*s  name:          %s", depth, "", name);
+  } else {
+    gchar buf[256];
+    guint8 len;
+
+    if (gst_byte_reader_get_uint8 (data, &len)
+        && qt_atom_parser_has_remaining (data, len)) {
+      memcpy (buf, gst_byte_reader_peek_data_unchecked (data), len);
+      buf[len] = '\0';
+      GST_LOG ("%*s  name:          %s", depth, "", buf);
+    }
+  }
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_vmhd (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  if (!qt_atom_parser_has_remaining (data, 4 + 4))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", GET_UINT32 (data));
+  GST_LOG ("%*s  mode/color:    %08x", depth, "", GET_UINT32 (data));
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_dref (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 ver_flags = 0, num_entries = 0, i;
+
+  if (!gst_byte_reader_get_uint32_be (data, &ver_flags) ||
+      !gst_byte_reader_get_uint32_be (data, &num_entries))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", ver_flags);
+  GST_LOG ("%*s  n entries:     %u", depth, "", num_entries);
+  for (i = 0; i < num_entries; i++) {
+    guint32 size = 0, fourcc;
+
+    if (!gst_byte_reader_get_uint32_be (data, &size) ||
+        !qt_atom_parser_get_fourcc (data, &fourcc) || size < 8 ||
+        !gst_byte_reader_skip (data, size - 8))
+      return FALSE;
+
+    GST_LOG ("%*s    size:          %u", depth, "", size);
+    GST_LOG ("%*s    type:          %" GST_FOURCC_FORMAT, depth, "",
+        GST_FOURCC_ARGS (fourcc));
+  }
+  return TRUE;
+}
+
+static gboolean
+qtdemux_dump_stsd_avc1 (GstQTDemux * qtdemux, GstByteReader * data, guint size,
+    int depth)
+{
+  guint32 fourcc;
+
+  /* Size of avc1 = 78 bytes */
+  if (size < (6 + 2 + 4 + 4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 2 + 1 + 31 + 2 + 2))
+    return FALSE;
+
+  gst_byte_reader_skip_unchecked (data, 6);
+  GST_LOG_OBJECT (qtdemux, "%*s    data reference:%d", depth, "",
+      GET_UINT16 (data));
+  GST_LOG_OBJECT (qtdemux, "%*s    version/rev.:  %08x", depth, "",
+      GET_UINT32 (data));
+  fourcc = GET_FOURCC (data);
+  GST_LOG_OBJECT (qtdemux, "%*s    vendor:        %" GST_FOURCC_FORMAT, depth,
+      "", GST_FOURCC_ARGS (fourcc));
+  GST_LOG_OBJECT (qtdemux, "%*s    temporal qual: %u", depth, "",
+      GET_UINT32 (data));
+  GST_LOG_OBJECT (qtdemux, "%*s    spatial qual:  %u", depth, "",
+      GET_UINT32 (data));
+  GST_LOG_OBJECT (qtdemux, "%*s    width:         %u", depth, "",
+      GET_UINT16 (data));
+  GST_LOG_OBJECT (qtdemux, "%*s    height:        %u", depth, "",
+      GET_UINT16 (data));
+  GST_LOG_OBJECT (qtdemux, "%*s    horiz. resol:  %g", depth, "",
+      GET_FP32 (data));
+  GST_LOG_OBJECT (qtdemux, "%*s    vert. resol.:  %g", depth, "",
+      GET_FP32 (data));
+  GST_LOG_OBJECT (qtdemux, "%*s    data size:     %u", depth, "",
+      GET_UINT32 (data));
+  GST_LOG_OBJECT (qtdemux, "%*s    frame count:   %u", depth, "",
+      GET_UINT16 (data));
+  /* something is not right with this, it's supposed to be a string but it's
+   * not apparently, so just skip this for now */
+  gst_byte_reader_skip_unchecked (data, 1 + 31);
+  GST_LOG_OBJECT (qtdemux, "%*s    compressor:    (skipped)", depth, "");
+  GST_LOG_OBJECT (qtdemux, "%*s    depth:         %u", depth, "",
+      GET_UINT16 (data));
+  GST_LOG_OBJECT (qtdemux, "%*s    color table ID:%u", depth, "",
+      GET_UINT16 (data));
+
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_stsd (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 ver_flags = 0, num_entries = 0, i;
+
+  if (!gst_byte_reader_get_uint32_be (data, &ver_flags) ||
+      !gst_byte_reader_get_uint32_be (data, &num_entries))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", ver_flags);
+  GST_LOG ("%*s  n entries:     %d", depth, "", num_entries);
+
+  for (i = 0; i < num_entries; i++) {
+    GstByteReader sub;
+    guint32 size, remain;
+    guint32 fourcc;
+
+    if (!gst_byte_reader_get_uint32_be (data, &size) ||
+        !qt_atom_parser_get_fourcc (data, &fourcc))
+      return FALSE;
+
+    GST_LOG_OBJECT (qtdemux, "%*s    size:          %u", depth, "", size);
+    GST_LOG_OBJECT (qtdemux, "%*s    type:          %" GST_FOURCC_FORMAT, depth,
+        "", GST_FOURCC_ARGS (fourcc));
+
+    remain = gst_byte_reader_get_remaining (data);
+    /* Size includes the 8 bytes we just read: len & fourcc, then 8 bytes
+     * version, flags, entries_count */
+    if (size > remain + 8) {
+      GST_LOG_OBJECT (qtdemux,
+          "Not enough data left for this atom (have %u need %u)", remain, size);
+      return FALSE;
+    }
+
+    qt_atom_parser_peek_sub (data, 0, size, &sub);
+    switch (fourcc) {
+      case FOURCC_avc1:
+        if (!qtdemux_dump_stsd_avc1 (qtdemux, &sub, size, depth + 1))
+          return FALSE;
+        break;
+      case FOURCC_fLaC:
+        /* will be dumped by node_dump_foreach */
+        break;
+      case FOURCC_mp4s:
+        if (!gst_byte_reader_get_uint32_be (&sub, &ver_flags) ||
+            !gst_byte_reader_get_uint32_be (&sub, &num_entries))
+          return FALSE;
+        if (!qtdemux_dump_unknown (qtdemux, &sub, depth + 1))
+          return FALSE;
+        break;
+      default:
+        /* Unknown stsd data, dump the bytes */
+        if (!qtdemux_dump_unknown (qtdemux, &sub, depth + 1))
+          return FALSE;
+        break;
+    }
+
+    if (!gst_byte_reader_skip (data, size - (4 + 4)))
+      return FALSE;
+  }
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_stts (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 ver_flags = 0, num_entries = 0, i;
+
+  if (!gst_byte_reader_get_uint32_be (data, &ver_flags) ||
+      !gst_byte_reader_get_uint32_be (data, &num_entries))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", ver_flags);
+  GST_LOG ("%*s  n entries:     %d", depth, "", num_entries);
+
+  if (!qt_atom_parser_has_chunks (data, num_entries, 4 + 4))
+    return FALSE;
+
+  for (i = 0; i < num_entries; i++) {
+    GST_LOG ("%*s    count:         %u", depth, "", GET_UINT32 (data));
+    GST_LOG ("%*s    duration:      %u", depth, "", GET_UINT32 (data));
+  }
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_stps (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 ver_flags = 0, num_entries = 0, i;
+
+  if (!gst_byte_reader_get_uint32_be (data, &ver_flags) ||
+      !gst_byte_reader_get_uint32_be (data, &num_entries))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", ver_flags);
+  GST_LOG ("%*s  n entries:     %d", depth, "", num_entries);
+
+  if (!qt_atom_parser_has_chunks (data, num_entries, 4))
+    return FALSE;
+
+  for (i = 0; i < num_entries; i++) {
+    GST_LOG ("%*s    sample:        %u", depth, "", GET_UINT32 (data));
+  }
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_stss (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 ver_flags = 0, num_entries = 0, i;
+
+  if (!gst_byte_reader_get_uint32_be (data, &ver_flags) ||
+      !gst_byte_reader_get_uint32_be (data, &num_entries))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", ver_flags);
+  GST_LOG ("%*s  n entries:     %d", depth, "", num_entries);
+
+  if (!qt_atom_parser_has_chunks (data, num_entries, 4))
+    return FALSE;
+
+  for (i = 0; i < num_entries; i++) {
+    GST_LOG ("%*s    sample:        %u", depth, "", GET_UINT32 (data));
+  }
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_stsc (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 ver_flags = 0, num_entries = 0, i;
+
+  if (!gst_byte_reader_get_uint32_be (data, &ver_flags) ||
+      !gst_byte_reader_get_uint32_be (data, &num_entries))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", ver_flags);
+  GST_LOG ("%*s  n entries:     %d", depth, "", num_entries);
+
+  if (!qt_atom_parser_has_chunks (data, num_entries, 4 + 4 + 4))
+    return FALSE;
+
+  for (i = 0; i < num_entries; i++) {
+    GST_LOG ("%*s    first chunk:   %u", depth, "", GET_UINT32 (data));
+    GST_LOG ("%*s    sample per ch: %u", depth, "", GET_UINT32 (data));
+    GST_LOG ("%*s    sample desc id:%08x", depth, "", GET_UINT32 (data));
+  }
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_stsz (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 ver_flags = 0, sample_size = 0, num_entries = 0, i;
+
+  if (!gst_byte_reader_get_uint32_be (data, &ver_flags) ||
+      !gst_byte_reader_get_uint32_be (data, &sample_size))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", ver_flags);
+  GST_LOG ("%*s  sample size:   %d", depth, "", sample_size);
+
+  if (sample_size == 0) {
+    if (!gst_byte_reader_get_uint32_be (data, &num_entries))
+      return FALSE;
+
+    GST_LOG ("%*s  n entries:     %d", depth, "", num_entries);
+    if (!qt_atom_parser_has_chunks (data, num_entries, 4))
+      return FALSE;
+    for (i = 0; i < num_entries; i++) {
+      GST_TRACE ("%*s    sample size:   %u", depth, "", GET_UINT32 (data));
+    }
+  }
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_stco (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 ver_flags = 0, num_entries = 0, i;
+
+  if (!gst_byte_reader_get_uint32_be (data, &ver_flags) ||
+      !gst_byte_reader_get_uint32_be (data, &num_entries))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", ver_flags);
+  GST_LOG ("%*s  n entries:     %d", depth, "", num_entries);
+
+  if (!qt_atom_parser_has_chunks (data, num_entries, 4))
+    return FALSE;
+
+  for (i = 0; i < num_entries; i++) {
+    GST_LOG ("%*s    chunk offset:  %u", depth, "", GET_UINT32 (data));
+  }
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_ctts (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 ver_flags = 0, num_entries = 0, i, count;
+  gint32 offset;
+
+
+  if (!gst_byte_reader_get_uint32_be (data, &ver_flags) ||
+      !gst_byte_reader_get_uint32_be (data, &num_entries))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", ver_flags);
+  GST_LOG ("%*s  n entries:     %u", depth, "", num_entries);
+
+  if (!qt_atom_parser_has_chunks (data, num_entries, 4 + 4))
+    return FALSE;
+
+  for (i = 0; i < num_entries; i++) {
+    count = GET_UINT32 (data);
+    offset = GET_UINT32 (data);
+    GST_LOG ("%*s    sample count :%8d offset: %8d", depth, "", count, offset);
+  }
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_cslg (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 ver_flags = 0, shift = 0;
+  gint32 least_offset = 0, start_time = 0, end_time = 0;
+
+  if (!gst_byte_reader_get_uint32_be (data, &ver_flags) ||
+      !gst_byte_reader_get_uint32_be (data, &shift) ||
+      !gst_byte_reader_get_int32_be (data, &least_offset) ||
+      !gst_byte_reader_get_int32_be (data, &start_time) ||
+      !gst_byte_reader_get_int32_be (data, &end_time))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", ver_flags);
+  GST_LOG ("%*s  shift:         %u", depth, "", shift);
+  GST_LOG ("%*s  least offset:  %d", depth, "", least_offset);
+  GST_LOG ("%*s  start time:    %d", depth, "", start_time);
+  GST_LOG ("%*s  end time:      %d", depth, "", end_time);
+
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_co64 (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 ver_flags = 0, num_entries = 0, i;
+
+  if (!gst_byte_reader_get_uint32_be (data, &ver_flags) ||
+      !gst_byte_reader_get_uint32_be (data, &num_entries))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", ver_flags);
+  GST_LOG ("%*s  n entries:     %d", depth, "", num_entries);
+
+  if (!qt_atom_parser_has_chunks (data, num_entries, 8))
+    return FALSE;
+
+  for (i = 0; i < num_entries; i++) {
+    GST_LOG ("%*s    chunk offset:  %" G_GUINT64_FORMAT, depth, "",
+        GET_UINT64 (data));
+  }
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_dcom (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  if (!qt_atom_parser_has_remaining (data, 4))
+    return FALSE;
+
+  GST_LOG ("%*s  compression type: %" GST_FOURCC_FORMAT, depth, "",
+      GST_FOURCC_ARGS (GET_FOURCC (data)));
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_cmvd (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  if (!qt_atom_parser_has_remaining (data, 4))
+    return FALSE;
+
+  GST_LOG ("%*s  length: %d", depth, "", GET_UINT32 (data));
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_mfro (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  if (!qt_atom_parser_has_remaining (data, 4))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", GET_UINT32 (data));
+  GST_LOG ("%*s  size: %d", depth, "", GET_UINT32 (data));
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_mfhd (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  if (!qt_atom_parser_has_remaining (data, 4))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", GET_UINT32 (data));
+  GST_LOG ("%*s  sequence_number: %d", depth, "", GET_UINT32 (data));
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_tfra (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint64 time = 0, moof_offset = 0;
+  guint32 len = 0, num_entries = 0, ver_flags = 0, track_id = 0, i;
+  guint value_size, traf_size, trun_size, sample_size;
+
+  if (!gst_byte_reader_get_uint32_be (data, &ver_flags))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", ver_flags);
+
+  if (!gst_byte_reader_get_uint32_be (data, &track_id) ||
+      !gst_byte_reader_get_uint32_be (data, &len) ||
+      !gst_byte_reader_get_uint32_be (data, &num_entries))
+    return FALSE;
+
+  GST_LOG ("%*s  track ID:      %u", depth, "", track_id);
+  GST_LOG ("%*s  length:        0x%x", depth, "", len);
+  GST_LOG ("%*s  n entries:     %u", depth, "", num_entries);
+
+  value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
+  sample_size = (len & 3) + 1;
+  trun_size = ((len & 12) >> 2) + 1;
+  traf_size = ((len & 48) >> 4) + 1;
+
+  if (!qt_atom_parser_has_chunks (data, num_entries,
+          value_size + value_size + traf_size + trun_size + sample_size))
+    return FALSE;
+
+  for (i = 0; i < num_entries; i++) {
+    qt_atom_parser_get_offset (data, value_size, &time);
+    qt_atom_parser_get_offset (data, value_size, &moof_offset);
+    GST_LOG ("%*s    time:          %" G_GUINT64_FORMAT, depth, "", time);
+    GST_LOG ("%*s    moof_offset:   %" G_GUINT64_FORMAT,
+        depth, "", moof_offset);
+    GST_LOG ("%*s    traf_number:   %u", depth, "",
+        qt_atom_parser_get_uint_with_size_unchecked (data, traf_size));
+    GST_LOG ("%*s    trun_number:   %u", depth, "",
+        qt_atom_parser_get_uint_with_size_unchecked (data, trun_size));
+    GST_LOG ("%*s    sample_number: %u", depth, "",
+        qt_atom_parser_get_uint_with_size_unchecked (data, sample_size));
+  }
+
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_tfhd (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 flags = 0, n = 0, track_id = 0;
+  guint64 base_data_offset = 0;
+
+  if (!gst_byte_reader_skip (data, 1) ||
+      !gst_byte_reader_get_uint24_be (data, &flags))
+    return FALSE;
+  GST_LOG ("%*s  flags: %08x", depth, "", flags);
+
+  if (!gst_byte_reader_get_uint32_be (data, &track_id))
+    return FALSE;
+  GST_LOG ("%*s  track_id: %u", depth, "", track_id);
+
+  if (flags & TF_BASE_DATA_OFFSET) {
+    if (!gst_byte_reader_get_uint64_be (data, &base_data_offset))
+      return FALSE;
+    GST_LOG ("%*s    base-data-offset: %" G_GUINT64_FORMAT,
+        depth, "", base_data_offset);
+  }
+
+  if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
+    if (!gst_byte_reader_get_uint32_be (data, &n))
+      return FALSE;
+    GST_LOG ("%*s    sample-description-index: %u", depth, "", n);
+  }
+
+  if (flags & TF_DEFAULT_SAMPLE_DURATION) {
+    if (!gst_byte_reader_get_uint32_be (data, &n))
+      return FALSE;
+    GST_LOG ("%*s    default-sample-duration:  %u", depth, "", n);
+  }
+
+  if (flags & TF_DEFAULT_SAMPLE_SIZE) {
+    if (!gst_byte_reader_get_uint32_be (data, &n))
+      return FALSE;
+    GST_LOG ("%*s    default-sample-size:  %u", depth, "", n);
+  }
+
+  if (flags & TF_DEFAULT_SAMPLE_FLAGS) {
+    if (!gst_byte_reader_get_uint32_be (data, &n))
+      return FALSE;
+    GST_LOG ("%*s    default-sample-flags:  %u", depth, "", n);
+  }
+
+  GST_LOG ("%*s    duration-is-empty:     %s", depth, "",
+      flags & TF_DURATION_IS_EMPTY ? "yes" : "no");
+
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_trun (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 flags = 0, samples_count = 0, data_offset = 0, first_sample_flags = 0;
+  guint32 sample_duration = 0, sample_size = 0, sample_flags =
+      0, composition_time_offsets = 0;
+  int i = 0;
+
+  if (!gst_byte_reader_skip (data, 1) ||
+      !gst_byte_reader_get_uint24_be (data, &flags))
+    return FALSE;
+
+  GST_LOG ("%*s  flags: %08x", depth, "", flags);
+
+  if (!gst_byte_reader_get_uint32_be (data, &samples_count))
+    return FALSE;
+  GST_LOG ("%*s  samples_count: %u", depth, "", samples_count);
+
+  if (flags & TR_DATA_OFFSET) {
+    if (!gst_byte_reader_get_uint32_be (data, &data_offset))
+      return FALSE;
+    GST_LOG ("%*s    data-offset: %u", depth, "", data_offset);
+  }
+
+  if (flags & TR_FIRST_SAMPLE_FLAGS) {
+    if (!gst_byte_reader_get_uint32_be (data, &first_sample_flags))
+      return FALSE;
+    GST_LOG ("%*s    first-sample-flags: %u", depth, "", first_sample_flags);
+  }
+
+  for (i = 0; i < samples_count; i++) {
+    if (flags & TR_SAMPLE_DURATION) {
+      if (!gst_byte_reader_get_uint32_be (data, &sample_duration))
+        return FALSE;
+      GST_TRACE ("%*s    sample-duration:  %u", depth, "", sample_duration);
+    }
+
+    if (flags & TR_SAMPLE_SIZE) {
+      if (!gst_byte_reader_get_uint32_be (data, &sample_size))
+        return FALSE;
+      GST_TRACE ("%*s    sample-size:  %u", depth, "", sample_size);
+    }
+
+    if (flags & TR_SAMPLE_FLAGS) {
+      if (!gst_byte_reader_get_uint32_be (data, &sample_flags))
+        return FALSE;
+      GST_TRACE ("%*s    sample-flags:  %u", depth, "", sample_flags);
+    }
+
+    if (flags & TR_COMPOSITION_TIME_OFFSETS) {
+      if (!gst_byte_reader_get_uint32_be (data, &composition_time_offsets))
+        return FALSE;
+      GST_TRACE ("%*s    composition_time_offsets:  %u", depth, "",
+          composition_time_offsets);
+    }
+  }
+
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_trex (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  if (!qt_atom_parser_has_remaining (data, 4 + 4 + 4 + 4 + 4 + 4))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", GET_UINT32 (data));
+  GST_LOG ("%*s  track ID:      %08x", depth, "", GET_UINT32 (data));
+  GST_LOG ("%*s  default sample desc. index: %08x", depth, "",
+      GET_UINT32 (data));
+  GST_LOG ("%*s  default sample duration:    %08x", depth, "",
+      GET_UINT32 (data));
+  GST_LOG ("%*s  default sample size:        %08x", depth, "",
+      GET_UINT32 (data));
+  GST_LOG ("%*s  default sample flags:       %08x", depth, "",
+      GET_UINT32 (data));
+
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_mehd (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 version = 0;
+  guint64 fragment_duration;
+  guint value_size;
+
+  if (!gst_byte_reader_get_uint32_be (data, &version))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", version);
+
+  value_size = ((version >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
+  if (qt_atom_parser_get_offset (data, value_size, &fragment_duration)) {
+    GST_LOG ("%*s  fragment duration: %" G_GUINT64_FORMAT,
+        depth, "", fragment_duration);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+gboolean
+qtdemux_dump_tfdt (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 version = 0;
+  guint64 decode_time;
+  guint value_size;
+
+  if (!gst_byte_reader_get_uint32_be (data, &version))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", version);
+
+  value_size = ((version >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
+  if (qt_atom_parser_get_offset (data, value_size, &decode_time)) {
+    GST_LOG ("%*s  Track fragment decode time: %" G_GUINT64_FORMAT,
+        depth, "", decode_time);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+gboolean
+qtdemux_dump_sdtp (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 version;
+  guint8 val;
+  guint i = 1;
+
+  version = GET_UINT32 (data);
+  GST_LOG ("%*s  version/flags: %08x", depth, "", version);
+
+  /* the sample_count is specified in the stsz or stz2 box.
+   * the information for a sample is stored in a single byte,
+   * so we read until there are no remaining bytes */
+  while (qt_atom_parser_has_remaining (data, 1)) {
+    val = GET_UINT8 (data);
+    GST_LOG ("%*s     sample number: %d", depth, "", i);
+    GST_LOG ("%*s     sample_depends_on: %d", depth, "",
+        ((guint16) (val)) & 0x3);
+    GST_LOG ("%*s     sample_is_depended_on: %d", depth, "",
+        ((guint16) (val >> 2)) & 0x3);
+    GST_LOG ("%*s     sample_has_redundancy: %d", depth, "",
+        ((guint16) (val >> 4)) & 0x3);
+    GST_LOG ("%*s     early display: %d", depth, "",
+        ((guint16) (val >> 6)) & 0x1);
+    ++i;
+  }
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_svmi (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 version;
+  guint stereo_mono_change_count;
+  guint i;
+
+  version = GET_UINT32 (data);
+  GST_LOG ("%*s  version/flags: %08x", depth, "", version);
+
+  if (!version) {
+    /* stereoscopic visual type information */
+    GST_LOG ("%*s     stereo_composition_type: %d", depth, "",
+        GET_UINT8 (data));
+    GST_LOG ("%*s     is_left_first: %d", depth, "",
+        ((guint8) GET_UINT8 (data)) & 0x01);
+
+    /* stereo_mono_change information */
+    stereo_mono_change_count = GET_UINT32 (data);
+    GST_LOG ("%*s     stereo_mono_change_count: %d", depth, "",
+        stereo_mono_change_count);
+    for (i = 1; i <= stereo_mono_change_count; i++) {
+      GST_LOG ("%*s     sample_count: %d", depth, "", GET_UINT32 (data));
+      GST_LOG ("%*s     stereo_flag: %d", depth, "",
+          ((guint8) GET_UINT8 (data)) & 0x01);
+    }
+  }
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_dfLa (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  const gchar *block_types[] = {
+    "STREAMINFO", "PADDING", "APPLICATION", "SEEKTABLE", "VORBIS_COMMENT",
+    "CUESHEET", "PICTURE", "UNKNOWN", "INVALID"
+  };
+
+  guint32 ver_flags, block_header, block_size;
+  gint8 block_type;
+  gboolean isLast = FALSE;
+
+  if (!gst_byte_reader_get_uint32_be (data, &ver_flags))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", ver_flags);
+
+  do {
+    if (!gst_byte_reader_get_uint32_be (data, &block_header))
+      break;
+
+    isLast = (block_header >> 31) & 1;
+    block_type = (block_header >> 24) & 0x7F;
+    block_size = block_header & 0xFFFFFF;
+
+    if (block_type == 127)
+      block_type = 8;
+    else if (block_type > 6)
+      block_type = 7;
+
+    GST_LOG ("%*s  block_type:      %s", depth, "", block_types[block_type]);
+    GST_LOG ("%*s  last-block-flag: %s", depth, "", isLast ? "true" : "false");
+    GST_LOG ("%*s  length:          %d", depth, "", block_size);
+
+    if (!gst_byte_reader_skip (data, block_size))
+      break;
+  } while (!isLast);
+
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_fLaC (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint16 data_ref_id, n_channels, sample_size;
+  guint32 sample_rate;
+
+  if (!gst_byte_reader_skip (data, 6) ||
+      !gst_byte_reader_get_uint16_be (data, &data_ref_id) ||
+      !gst_byte_reader_skip (data, 8) ||
+      !gst_byte_reader_get_uint16_be (data, &n_channels) ||
+      !gst_byte_reader_get_uint16_be (data, &sample_size) ||
+      !gst_byte_reader_skip (data, 4) ||
+      !gst_byte_reader_get_uint32_be (data, &sample_rate))
+    return FALSE;
+
+  GST_LOG ("%*s  data reference: %d", depth, "", data_ref_id);
+  GST_LOG ("%*s  channel count:  %d", depth, "", n_channels);
+  GST_LOG ("%*s  sample size:    %d", depth, "", sample_size);
+  GST_LOG ("%*s  sample rate:    %d", depth, "", (sample_rate >> 16));
+
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_gmin (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  guint32 ver_flags;
+  guint16 graphics_mode, opc_r, opc_g, opc_b, balance;
+
+  if (!gst_byte_reader_get_uint32_be (data, &ver_flags))
+    return FALSE;
+
+  GST_LOG ("%*s  version/flags : %08x", depth, "", ver_flags);
+  if (!gst_byte_reader_get_uint16_be (data, &graphics_mode) ||
+      !gst_byte_reader_get_uint16_be (data, &opc_r) ||
+      !gst_byte_reader_get_uint16_be (data, &opc_g) ||
+      !gst_byte_reader_get_uint16_be (data, &opc_b) ||
+      !gst_byte_reader_get_uint16_be (data, &balance))
+    return FALSE;
+
+  GST_LOG ("%*s  graphics mode : 0x%x", depth, "", graphics_mode);
+  GST_LOG ("%*s  opcolor :       r:0x%x g:0x%x b:0x%x", depth, "", opc_r, opc_g,
+      opc_b);
+  GST_LOG ("%*s  balance :       %d", depth, "", balance);
+
+  return TRUE;
+}
+
+gboolean
+qtdemux_dump_unknown (GstQTDemux * qtdemux, GstByteReader * data, int depth)
+{
+  int len;
+
+  len = gst_byte_reader_get_remaining (data);
+  GST_LOG ("%*s  length: %d", depth, "", len);
+
+  GST_MEMDUMP_OBJECT (qtdemux, "unknown atom data",
+      gst_byte_reader_peek_data_unchecked (data), len);
+  return TRUE;
+}
+
+static gboolean
+qtdemux_node_dump_foreach (GNode * node, gpointer qtdemux)
+{
+  GstByteReader parser;
+  guint8 *buffer = (guint8 *) node->data;       /* FIXME: move to byte reader */
+  guint32 node_length;
+  guint32 fourcc;
+  const QtNodeType *type;
+  int depth;
+
+  node_length = GST_READ_UINT32_BE (buffer);
+  fourcc = GST_READ_UINT32_LE (buffer + 4);
+
+  g_warn_if_fail (node_length >= 8);
+
+  gst_byte_reader_init (&parser, buffer + 8, node_length - 8);
+
+  type = qtdemux_type_get (fourcc);
+
+  depth = (g_node_depth (node) - 1) * 2;
+  GST_LOG ("%*s'%" GST_FOURCC_FORMAT "', [%d], %s",
+      depth, "", GST_FOURCC_ARGS (fourcc), node_length, type->name);
+
+  if (type->dump) {
+    gboolean ret;
+
+    ret = type->dump (GST_QTDEMUX_CAST (qtdemux), &parser, depth);
+
+    if (!ret) {
+      GST_WARNING ("%*s  not enough data parsing atom %" GST_FOURCC_FORMAT,
+          depth, "", GST_FOURCC_ARGS (fourcc));
+    }
+  }
+
+  return FALSE;
+}
+
+gboolean
+qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node)
+{
+#ifndef GST_DISABLE_GST_DEBUG
+  /* Only traverse/dump if we know it will be outputted in the end */
+  if (qtdemux_debug->threshold < GST_LEVEL_LOG)
+    return TRUE;
+
+  g_node_traverse (node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+      qtdemux_node_dump_foreach, qtdemux);
+#endif
+  return TRUE;
+}
diff --git a/gst/isomp4/qtdemux_dump.h b/gst/isomp4/qtdemux_dump.h
new file mode 100644
index 0000000..45dcd3f
--- /dev/null
+++ b/gst/isomp4/qtdemux_dump.h
@@ -0,0 +1,98 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_QTDEMUX_DUMP_H__
+#define __GST_QTDEMUX_DUMP_H__
+
+#include <gst/gst.h>
+#include <qtdemux.h>
+
+G_BEGIN_DECLS
+    gboolean qtdemux_dump_mvhd (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_tkhd (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_elst (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_mdhd (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_hdlr (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_vmhd (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_dref (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_stsd (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_stts (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_stss (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_stps (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_stsc (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_stsz (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_stco (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_co64 (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_dcom (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_cmvd (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_ctts (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_cslg (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_mfro (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_mfhd (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_tfra (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_tfhd (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_trun (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_trex (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_mehd (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_sdtp (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_tfdt (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_unknown (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_svmi (GstQTDemux *qtdemux, GstByteReader *data,
+    int depth);
+gboolean qtdemux_dump_dfLa (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_fLaC (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+gboolean qtdemux_dump_gmin (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+
+gboolean qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node);
+
+G_END_DECLS
+#endif /* __GST_QTDEMUX_DUMP_H__ */
diff --git a/gst/isomp4/qtdemux_lang.c b/gst/isomp4/qtdemux_lang.c
new file mode 100644
index 0000000..c9646b2
--- /dev/null
+++ b/gst/isomp4/qtdemux_lang.c
@@ -0,0 +1,207 @@
+/* GStreamer Quicktime/ISO demuxer language utility functions
+ * Copyright (C) 2010 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "qtdemux_debug.h"
+#include "qtdemux_lang.h"
+
+#include <string.h>
+
+#define GST_CAT_DEFAULT qtdemux_debug
+
+/* http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap4/qtff4.html */
+
+static const gchar qt_lang_map[][4] = {
+
+/* 000 English
+ * 001 French
+ * 002 German
+ * 003 Italian
+ * 004 Dutch
+ * 005 Swedish
+ * 006 Spanish
+ * 007 Danish
+ * 008 Portuguese
+ * 009 Norwegian
+ */
+  "eng", "fre", "deu", "ita", "nld", "swe", "spa", "dan", "por", "nor",
+
+/* 010 Hebrew
+ * 011 Japanese
+ * 012 Arabic
+ * 013 Finnish
+ * 014 Greek
+ * 015 Icelandic
+ * 016 Maltese
+ * 017 Turkish
+ * 018 Croatian
+ * 019 Traditional Chinese (ISO 639-2 can't express script differences, so zho)
+ */
+  "heb", "jpn", "ara", "fin", "ell", "isl", "mlt", "tur", "hrv", "zho",
+
+/* 020 Urdu
+ * 021 Hindi
+ * 022 Thai
+ * 023 Korean
+ * 024 Lithuanian
+ * 025 Polish
+ * 026 Hungarian
+ * 027 Estonian
+ * 028 Latvian / Lettish
+ * 029 Lappish / Saamish (used code for Nothern Sami)
+ */
+  "urd", "hin", "tha", "kor", "lit", "pol", "hun", "est", "lav", "sme",
+
+/* 030 Faeroese
+ * 031 Farsi
+ * 032 Russian
+ * 033 Simplified Chinese (ISO 639-2 can't express script differences, so zho)
+ * 034 Flemish (no ISO 639-2 code, used Dutch code)
+ * 035 Irish
+ * 036 Albanian
+ * 037 Romanian
+ * 038 Czech
+ * 039 Slovak
+ */
+  "fao", "fas", "rus", "zho", "nld", "gle", "sqi", "ron", "ces", "slk",
+
+/* 040 Slovenian
+ * 041 Yiddish
+ * 042 Serbian
+ * 043 Macedonian
+ * 044 Bulgarian
+ * 045 Ukrainian
+ * 046 Byelorussian
+ * 047 Uzbek
+ * 048 Kazakh
+ * 049 Azerbaijani
+ */
+  "slv", "yid", "srp", "mkd", "bul", "ukr", "bel", "uzb", "kaz", "aze",
+
+/* 050 AzerbaijanAr (presumably script difference? used aze here)
+ * 051 Armenian
+ * 052 Georgian
+ * 053 Moldavian
+ * 054 Kirghiz
+ * 055 Tajiki
+ * 056 Turkmen
+ * 057 Mongolian
+ * 058 MongolianCyr (presumably script difference? used mon here)
+ * 059 Pashto
+ */
+
+  "aze", "hye", "kat", "mol", "kir", "tgk", "tuk", "mon", "mon", "pus",
+
+
+/* 060 Kurdish
+ * 061 Kashmiri
+ * 062 Sindhi
+ * 063 Tibetan
+ * 064 Nepali
+ * 065 Sanskrit
+ * 066 Marathi
+ * 067 Bengali
+ * 068 Assamese
+ * 069 Gujarati
+ */
+  "kur", "kas", "snd", "bod", "nep", "san", "mar", "ben", "asm", "guj",
+
+/* 070 Punjabi
+ * 071 Oriya
+ * 072 Malayalam
+ * 073 Kannada
+ * 074 Tamil
+ * 075 Telugu
+ * 076 Sinhalese
+ * 077 Burmese
+ * 078 Khmer
+ * 079 Lao
+ */
+  "pan", "ori", "mal", "kan", "tam", "tel", "sin", "mya", "khm", "lao",
+
+/* 080 Vietnamese
+ * 081 Indonesian
+ * 082 Tagalog
+ * 083 MalayRoman
+ * 084 MalayArabic
+ * 085 Amharic
+ * 087 Galla (same as Oromo?)
+ * 087 Oromo
+ * 088 Somali
+ * 089 Swahili
+ */
+  "vie", "ind", "tgl", "msa", "msa", "amh", "orm", "orm", "som", "swa",
+
+/* 090 Ruanda
+ * 091 Rundi
+ * 092 Chewa
+ * 093 Malagasy
+ * 094 Esperanto
+ * 095 ---
+ * 096 ---
+ * 097 ---
+ * 098 ---
+ * 099 ---
+ */
+  "kin", "run", "nya", "mlg", "ep", "und", "und", "und", "und", "und",
+
+/* 100-109 ---
+ * 110-119 ---
+ */
+  "und", "und", "und", "und", "und", "und", "und", "und", "und", "und",
+  "und", "und", "und", "und", "und", "und", "und", "und", "und", "und",
+
+/* 120-127 ---
+ * 128 Welsh
+ * 129 Basque
+ */
+  "und", "und", "und", "und", "und", "und", "und", "und", "cym", "eus",
+
+/* 130 Catalan
+ * 131 Latin
+ * 132 Quechua
+ * 133 Guarani
+ * 134 Aymara
+ * 135 Tatar
+ * 136 Uighur
+ * 137 Dzongkha
+ * 138 JavaneseRom
+ */
+  "cat", "lat", "que", "grn", "aym", "tat", "uig", "dzo", "jav"
+};
+
+/* map quicktime language code to ISO-639-2T id, returns "und" if unknown */
+void
+qtdemux_lang_map_qt_code_to_iso (gchar id[4], guint16 qt_lang_code)
+{
+  const gchar *iso_code;
+
+  g_assert (qt_lang_code < 0x400);
+
+  if (qt_lang_code < G_N_ELEMENTS (qt_lang_map))
+    iso_code = qt_lang_map[qt_lang_code];
+  else
+    iso_code = "und";
+
+  GST_DEBUG ("mapped quicktime language code %u to ISO 639-2T code '%s'",
+      qt_lang_code, iso_code);
+
+  memcpy (id, iso_code, 4);
+
+  g_assert (id[3] == '\0');
+}
diff --git a/gst/isomp4/qtdemux_lang.h b/gst/isomp4/qtdemux_lang.h
new file mode 100644
index 0000000..707c5f7
--- /dev/null
+++ b/gst/isomp4/qtdemux_lang.h
@@ -0,0 +1,31 @@
+/* GStreamer Quicktime/ISO demuxer language utility functions
+ * Copyright (C) 2010 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_QTDEMUX_LANG_H__
+#define __GST_QTDEMUX_LANG_H__
+
+G_BEGIN_DECLS
+
+#include <glib.h>
+
+void qtdemux_lang_map_qt_code_to_iso (gchar id[4], guint16 qt_lang_code);
+
+G_END_DECLS
+
+#endif /* __GST_QTDEMUX_LANG_H__ */
diff --git a/gst/isomp4/qtdemux_types.c b/gst/isomp4/qtdemux_types.c
new file mode 100644
index 0000000..88db8c2
--- /dev/null
+++ b/gst/isomp4/qtdemux_types.c
@@ -0,0 +1,236 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "qtdemux_debug.h"
+#include "qtdemux_types.h"
+#include "qtdemux_dump.h"
+#include "fourcc.h"
+
+#define GST_CAT_DEFAULT qtdemux_debug
+
+static const QtNodeType qt_node_types[] = {
+  {FOURCC_moov, "movie", QT_FLAG_CONTAINER,},
+  {FOURCC_mvhd, "movie header", 0,
+      qtdemux_dump_mvhd},
+  {FOURCC_clip, "clipping", QT_FLAG_CONTAINER,},
+  {FOURCC_trak, "track", QT_FLAG_CONTAINER,},
+  {FOURCC_udta, "user data", QT_FLAG_CONTAINER,},       /* special container */
+  {FOURCC_ctab, "color table", 0,},
+  {FOURCC_tkhd, "track header", 0,
+      qtdemux_dump_tkhd},
+  {FOURCC_crgn, "clipping region", 0,},
+  {FOURCC_matt, "track matte", QT_FLAG_CONTAINER,},
+  {FOURCC_kmat, "compressed matte", 0,},
+  {FOURCC_edts, "edit", QT_FLAG_CONTAINER,},
+  {FOURCC_elst, "edit list", 0,
+      qtdemux_dump_elst},
+  {FOURCC_load, "track load settings", 0,},
+  {FOURCC_tref, "track reference", QT_FLAG_CONTAINER,},
+  {FOURCC_imap, "track input map", QT_FLAG_CONTAINER,},
+  {FOURCC___in, "track input", 0,},     /* special container */
+  {FOURCC___ty, "input type", 0,},
+  {FOURCC_mdia, "media", QT_FLAG_CONTAINER},
+  {FOURCC_mdhd, "media header", 0,
+      qtdemux_dump_mdhd},
+  {FOURCC_hdlr, "handler reference", 0,
+      qtdemux_dump_hdlr},
+  {FOURCC_minf, "media information", QT_FLAG_CONTAINER},
+  {FOURCC_vmhd, "video media information", 0,
+      qtdemux_dump_vmhd},
+  {FOURCC_smhd, "sound media information", 0},
+  {FOURCC_gmhd, "base media information header", QT_FLAG_CONTAINER},
+  {FOURCC_gmin, "base media info", 0, qtdemux_dump_gmin},
+  {FOURCC_dinf, "data information", QT_FLAG_CONTAINER},
+  {FOURCC_dref, "data reference", 0,
+      qtdemux_dump_dref},
+  {FOURCC_stbl, "sample table", QT_FLAG_CONTAINER},
+  {FOURCC_stsd, "sample description", 0,
+      qtdemux_dump_stsd},
+  {FOURCC_stts, "time-to-sample", 0,
+      qtdemux_dump_stts},
+  {FOURCC_stps, "partial sync sample", 0,
+      qtdemux_dump_stps},
+  {FOURCC_stss, "sync sample", 0,
+      qtdemux_dump_stss},
+  {FOURCC_stsc, "sample-to-chunk", 0,
+      qtdemux_dump_stsc},
+  {FOURCC_stsz, "sample size", 0,
+      qtdemux_dump_stsz},
+  {FOURCC_stco, "chunk offset", 0,
+      qtdemux_dump_stco},
+  {FOURCC_co64, "64-bit chunk offset", 0,
+      qtdemux_dump_co64},
+  {FOURCC_vide, "video media", 0},
+  {FOURCC_cmov, "compressed movie", QT_FLAG_CONTAINER},
+  {FOURCC_dcom, "compressed data", 0, qtdemux_dump_dcom},
+  {FOURCC_cmvd, "compressed movie data", 0, qtdemux_dump_cmvd},
+  {FOURCC_hint, "hint", 0,},
+  {FOURCC_mp4a, "mp4a", 0,},
+  {FOURCC_mp4v, "mp4v", 0,},
+  {FOURCC_mjp2, "mjp2", 0,},
+  {FOURCC_mhdr, "mhdr", QT_FLAG_CONTAINER,},
+  {FOURCC_jp2h, "jp2h", QT_FLAG_CONTAINER,},
+  {FOURCC_colr, "colr", 0,},
+  {FOURCC_clap, "clap", 0,},
+  {FOURCC_tapt, "tapt", 0,},
+  {FOURCC_ihdr, "ihdr", 0,},
+  {FOURCC_fiel, "fiel", 0,},
+  {FOURCC_jp2x, "jp2x", 0,},
+  {FOURCC_alac, "alac", 0,},
+  {FOURCC_fLaC, "fLaC", 0, qtdemux_dump_fLaC},
+  {FOURCC_dfLa, "dfLa", 0, qtdemux_dump_dfLa},
+  {FOURCC_wave, "wave", QT_FLAG_CONTAINER},
+  {FOURCC_appl, "appl", QT_FLAG_CONTAINER},
+  {FOURCC_cfhd, "cfhd", QT_FLAG_CONTAINER},
+  {FOURCC_esds, "esds", 0},
+  {FOURCC_hnti, "hnti", QT_FLAG_CONTAINER},
+  {FOURCC_rtp_, "rtp ", 0, qtdemux_dump_unknown},
+  {FOURCC_sdp_, "sdp ", 0, qtdemux_dump_unknown},
+  {FOURCC_meta, "meta", 0, qtdemux_dump_unknown},
+  {FOURCC_ilst, "ilst", QT_FLAG_CONTAINER,},
+  {FOURCC__nam, "Name", QT_FLAG_CONTAINER,},
+  {FOURCC_titl, "Title", QT_FLAG_CONTAINER,},
+  {FOURCC__ART, "Artist", QT_FLAG_CONTAINER,},
+  {FOURCC_aART, "Album Artist", QT_FLAG_CONTAINER,},
+  {FOURCC_auth, "Author", QT_FLAG_CONTAINER,},
+  {FOURCC_perf, "Performer", QT_FLAG_CONTAINER,},
+  {FOURCC__wrt, "Writer", QT_FLAG_CONTAINER,},
+  {FOURCC__grp, "Grouping", QT_FLAG_CONTAINER,},
+  {FOURCC__alb, "Album", QT_FLAG_CONTAINER,},
+  {FOURCC_albm, "Album", QT_FLAG_CONTAINER,},
+  {FOURCC__day, "Date", QT_FLAG_CONTAINER,},
+  {FOURCC__cpy, "Copyright", QT_FLAG_CONTAINER,},
+  {FOURCC__cmt, "Comment", QT_FLAG_CONTAINER,},
+  {FOURCC__des, "Description", QT_FLAG_CONTAINER,},
+  {FOURCC_desc, "Description", QT_FLAG_CONTAINER,},
+  {FOURCC_dscp, "Description", QT_FLAG_CONTAINER,},
+  {FOURCC__lyr, "Lyrics", QT_FLAG_CONTAINER,},
+  {FOURCC__req, "Requirement", QT_FLAG_CONTAINER,},
+  {FOURCC__enc, "Encoder", QT_FLAG_CONTAINER,},
+  {FOURCC_gnre, "Genre", QT_FLAG_CONTAINER,},
+  {FOURCC_trkn, "Track Number", QT_FLAG_CONTAINER,},
+  {FOURCC_disc, "Disc Number", QT_FLAG_CONTAINER,},
+  {FOURCC_disk, "Disc Number", QT_FLAG_CONTAINER,},
+  {FOURCC_cprt, "Copyright", QT_FLAG_CONTAINER,},
+  {FOURCC_cpil, "Compilation", QT_FLAG_CONTAINER,},
+  {FOURCC_pgap, "Gapless", QT_FLAG_CONTAINER,},
+  {FOURCC_pcst, "Podcast", QT_FLAG_CONTAINER,},
+  {FOURCC_tmpo, "Tempo", QT_FLAG_CONTAINER,},
+  {FOURCC_covr, "Cover", QT_FLAG_CONTAINER,},
+  {FOURCC_sonm, "Sort Title", QT_FLAG_CONTAINER,},
+  {FOURCC_soal, "Sort Album", QT_FLAG_CONTAINER,},
+  {FOURCC_soar, "Sort Artist", QT_FLAG_CONTAINER,},
+  {FOURCC_soaa, "Sort Album Artist", QT_FLAG_CONTAINER,},
+  {FOURCC_soco, "Sort Composer", QT_FLAG_CONTAINER,},
+  {FOURCC_sosn, "Sort TV Show", QT_FLAG_CONTAINER,},
+  {FOURCC_tvsh, "TV Show", QT_FLAG_CONTAINER,},
+  {FOURCC_tven, "TV Episode ID", QT_FLAG_CONTAINER,},
+  {FOURCC_tvsn, "TV Season Number", QT_FLAG_CONTAINER,},
+  {FOURCC_tves, "TV Episode Number", QT_FLAG_CONTAINER,},
+  {FOURCC_keyw, "Keywords", QT_FLAG_CONTAINER,},
+  {FOURCC_kywd, "Keywords", QT_FLAG_CONTAINER,},
+  {FOURCC__too, "Encoder", QT_FLAG_CONTAINER,},
+  {FOURCC__swr, "Application Name", QT_FLAG_CONTAINER,},
+  {FOURCC_____, "----", QT_FLAG_CONTAINER,},
+  {FOURCC_data, "data", 0, qtdemux_dump_unknown},
+  {FOURCC_free, "free", 0,},
+  {FOURCC_skip, "skip", 0,},
+  {FOURCC_SVQ3, "SVQ3", 0,},
+  {FOURCC_rmra, "rmra", QT_FLAG_CONTAINER,},
+  {FOURCC_rmda, "rmda", QT_FLAG_CONTAINER,},
+  {FOURCC_rdrf, "rdrf", 0,},
+  {FOURCC__gen, "Custom Genre", QT_FLAG_CONTAINER,},
+  {FOURCC_ctts, "Composition time to sample", 0, qtdemux_dump_ctts},
+  {FOURCC_cslg, "Composition Shift Least Greatest", 0, qtdemux_dump_cslg},
+  {FOURCC_XiTh, "XiTh", 0},
+  {FOURCC_XdxT, "XdxT", 0},
+  {FOURCC_loci, "loci", 0},
+  {FOURCC_clsf, "clsf", 0},
+  {FOURCC_mfra, "movie fragment random access",
+      QT_FLAG_CONTAINER,},
+  {FOURCC_tfra, "track fragment random access", 0,
+      qtdemux_dump_tfra},
+  {FOURCC_mfro, "movie fragment random access offset", 0,
+      qtdemux_dump_mfro},
+  {FOURCC_moof, "movie fragment", QT_FLAG_CONTAINER,},
+  {FOURCC_mfhd, "movie fragment header", 0, qtdemux_dump_mfhd},
+  {FOURCC_traf, "track fragment", QT_FLAG_CONTAINER,},
+  {FOURCC_tfhd, "track fragment header", 0,
+      qtdemux_dump_tfhd},
+  {FOURCC_sdtp, "independent and disposable samples", 0,
+      qtdemux_dump_sdtp},
+  {FOURCC_trun, "track fragment run", 0, qtdemux_dump_trun},
+  {FOURCC_mdat, "moovie data", 0, qtdemux_dump_unknown},
+  {FOURCC_trex, "moovie data", 0, qtdemux_dump_trex},
+  {FOURCC_mvex, "mvex", QT_FLAG_CONTAINER,},
+  {FOURCC_mehd, "movie extends header", 0,
+      qtdemux_dump_mehd},
+  {FOURCC_ovc1, "ovc1", 0},
+  {FOURCC_owma, "owma", 0},
+  {FOURCC_avcC, "AV codec configuration container", 0},
+  {FOURCC_avc1, "AV codec configuration v1", 0},
+  {FOURCC_avc3, "AV codec configuration v3", 0},
+  {FOURCC_mp4s, "VOBSUB codec configuration", 0},
+  {FOURCC_hvc1, "HEVC codec configuration", 0},
+  {FOURCC_hev1, "HEVC codec configuration", 0},
+  {FOURCC_hvcC, "HEVC codec configuration container", 0},
+  {FOURCC_tfdt, "Track fragment decode time", 0, qtdemux_dump_tfdt},
+  {FOURCC_chap, "Chapter Reference"},
+  {FOURCC_btrt, "Bitrate information", 0},
+  {FOURCC_frma, "Audio codec format", 0},
+  {FOURCC_name, "name", 0},
+  {FOURCC_mean, "mean", 0},
+  {FOURCC_svmi, "Stereoscopic Video Media Information", 0,
+      qtdemux_dump_svmi},
+  {FOURCC_scdi, "Stereoscopic Camera and Display Information", 0,
+      qtdemux_dump_unknown},
+  {FOURCC_saiz, "sample auxiliary information sizes", 0},
+  {FOURCC_saio, "sample auxiliary information offsets", 0},
+  {FOURCC_encv, "encrypted visual sample entry", 0},
+  {FOURCC_enca, "encrypted audio sample entry", 0},
+  {FOURCC_enct, "encrypted text sample entry", 0},
+  {FOURCC_encs, "encrypted system sample entry", 0},
+  {FOURCC_sinf, "protection scheme information", QT_FLAG_CONTAINER},
+  {FOURCC_frma, "original format", 0},
+  {FOURCC_schm, "scheme type", 0},
+  {FOURCC_schi, "scheme information", QT_FLAG_CONTAINER},
+  {FOURCC_pssh, "protection system specific header", 0},
+  {FOURCC_tenc, "track encryption", 0},
+  {FOURCC_stpp, "XML subtitle sample entry", 0},
+  {0, "unknown", 0,},
+};
+
+static const int n_qt_node_types =
+    sizeof (qt_node_types) / sizeof (qt_node_types[0]);
+
+const QtNodeType *
+qtdemux_type_get (guint32 fourcc)
+{
+  int i;
+
+  for (i = 0; i < n_qt_node_types; i++) {
+    if (G_UNLIKELY (qt_node_types[i].fourcc == fourcc))
+      return qt_node_types + i;
+  }
+
+  GST_WARNING ("unknown QuickTime node type %" GST_FOURCC_FORMAT,
+      GST_FOURCC_ARGS (fourcc));
+
+  return qt_node_types + n_qt_node_types - 1;
+}
diff --git a/gst/isomp4/qtdemux_types.h b/gst/isomp4/qtdemux_types.h
new file mode 100644
index 0000000..43ef77c
--- /dev/null
+++ b/gst/isomp4/qtdemux_types.h
@@ -0,0 +1,83 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_QTDEMUX_TYPES_H__
+#define __GST_QTDEMUX_TYPES_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbytereader.h>
+
+#include "qtdemux.h"
+
+G_BEGIN_DECLS
+
+typedef gboolean (*QtDumpFunc) (GstQTDemux * qtdemux, GstByteReader * data,
+    int depth);
+
+typedef struct _QtNodeType QtNodeType;
+
+#define QT_UINT32(a)  (GST_READ_UINT32_BE(a))
+#define QT_UINT24(a)  (GST_READ_UINT32_BE(a) >> 8)
+#define QT_UINT16(a)  (GST_READ_UINT16_BE(a))
+#define QT_UINT8(a)   (GST_READ_UINT8(a))
+#define QT_FP32(a)    ((GST_READ_UINT32_BE(a))/65536.0)
+#define QT_SFP32(a)   (((gint)(GST_READ_UINT32_BE(a)))/65536.0)
+#define QT_FP16(a)    ((GST_READ_UINT16_BE(a))/256.0)
+#define QT_FOURCC(a)  (GST_READ_UINT32_LE(a))
+#define QT_UINT64(a)  ((((guint64)QT_UINT32(a))<<32)|QT_UINT32(((guint8 *)a)+4))
+
+typedef enum {
+  QT_FLAG_NONE      = (0),
+  QT_FLAG_CONTAINER = (1 << 0)
+} QtFlags;
+
+struct _QtNodeType {
+  guint32      fourcc;
+  const gchar *name;
+  QtFlags      flags;
+  QtDumpFunc   dump;
+};
+
+enum TfFlags
+{
+  TF_BASE_DATA_OFFSET         = 0x000001,   /* base-data-offset-present */
+  TF_SAMPLE_DESCRIPTION_INDEX = 0x000002,   /* sample-description-index-present */
+  TF_DEFAULT_SAMPLE_DURATION  = 0x000008,   /* default-sample-duration-present */
+  TF_DEFAULT_SAMPLE_SIZE      = 0x000010,   /* default-sample-size-present */
+  TF_DEFAULT_SAMPLE_FLAGS     = 0x000020,   /* default-sample-flags-present */
+  TF_DURATION_IS_EMPTY        = 0x010000,   /* duration-is-empty */
+  TF_DEFAULT_BASE_IS_MOOF     = 0x020000    /* default-base-is-moof */
+};
+
+enum TrFlags
+{
+  TR_DATA_OFFSET              = 0x000001,   /* data-offset-present */
+  TR_FIRST_SAMPLE_FLAGS       = 0x000004,   /* first-sample-flags-present */
+  TR_SAMPLE_DURATION          = 0x000100,   /* sample-duration-present */
+  TR_SAMPLE_SIZE              = 0x000200,   /* sample-size-present */
+  TR_SAMPLE_FLAGS             = 0x000400,   /* sample-flags-present */
+  TR_COMPOSITION_TIME_OFFSETS = 0x000800    /* sample-composition-time-offsets-presents */
+};
+
+const QtNodeType *qtdemux_type_get (guint32 fourcc);
+
+G_END_DECLS
+
+#endif /* __GST_QTDEMUX_TYPES_H__ */
diff --git a/gst/isomp4/qtpalette.h b/gst/isomp4/qtpalette.h
new file mode 100644
index 0000000..a41e991
--- /dev/null
+++ b/gst/isomp4/qtpalette.h
@@ -0,0 +1,137 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_QTPALLETE_H__
+#define __GST_QTPALLETE_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+static const guint32 ff_qt_default_palette_2[2] = {
+  0xffffff, 0x000000
+};
+
+static const guint32 ff_qt_default_palette_4[4] = {
+  0x93655e, 0xffffff, 0xdfd0ab, 0x000000
+};
+
+static const guint32 ff_qt_default_palette_16[16] = {
+  0xfffbff, 0xefd9bb, 0xe8c9b1, 0x93655e,
+  0xfcdee8, 0x9d8891, 0xffffff, 0xffffff,
+  0xffffff, 0x474837, 0x7a5e55, 0xdfd0ab,
+  0xfffbf9, 0xe8cac5, 0x8a7c77, 0x000000
+};
+static const guint32 ff_qt_default_palette_256[256] = {
+  0xFFFFFF, 0xFFFFCC, 0xFFFF99, 0xFFFF66, 0xFFFF33, 0xFFFF00,
+  0xFFCCFF, 0xFFCCCC, 0xFFCC99, 0xFFCC66, 0xFFCC33, 0xFFCC00,
+  0xFF99FF, 0xFF99CC, 0xFF9999, 0xFF9966, 0xFF9933, 0xFF9900,
+  0xFF66FF, 0xFF66CC, 0xFF6699, 0xFF6666, 0xFF6633, 0xFF6600,
+  0xFF33FF, 0xFF33CC, 0xFF3399, 0xFF3366, 0xFF3333, 0xFF3300,
+  0xFF00FF, 0xFF00CC, 0xFF0099, 0xFF0066, 0xFF0033, 0xFF0000,
+  0xCCFFFF, 0xCCFFCC, 0xCCFF99, 0xCCFF66, 0xCCFF33, 0xCCFF00,
+  0xCCCCFF, 0xCCCCCC, 0xCCCC99, 0xCCCC66, 0xCCCC33, 0xCCCC00,
+  0xCC99FF, 0xCC99CC, 0xCC9999, 0xCC9966, 0xCC9933, 0xCC9900,
+  0xCC66FF, 0xCC66CC, 0xCC6699, 0xCC6666, 0xCC6633, 0xCC6600,
+  0xCC33FF, 0xCC33CC, 0xCC3399, 0xCC3366, 0xCC3333, 0xCC3300,
+  0xCC00FF, 0xCC00CC, 0xCC0099, 0xCC0066, 0xCC0033, 0xCC0000,
+  0x99FFFF, 0x99FFCC, 0x99FF99, 0x99FF66, 0x99FF33, 0x99FF00,
+  0x99CCFF, 0x99CCCC, 0x99CC99, 0x99CC66, 0x99CC33, 0x99CC00,
+  0x9999FF, 0x9999CC, 0x999999, 0x999966, 0x999933, 0x999900,
+  0x9966FF, 0x9966CC, 0x996699, 0x996666, 0x996633, 0x996600,
+  0x9933FF, 0x9933CC, 0x993399, 0x993366, 0x993333, 0x993300,
+  0x9900FF, 0x9900CC, 0x990099, 0x990066, 0x990033, 0x990000,
+  0x66FFFF, 0x66FFCC, 0x66FF99, 0x66FF66, 0x66FF33, 0x66FF00,
+  0x66CCFF, 0x66CCCC, 0x66CC99, 0x66CC66, 0x66CC33, 0x66CC00,
+  0x6699FF, 0x6699CC, 0x669999, 0x669966, 0x669933, 0x669900,
+  0x6666FF, 0x6666CC, 0x666699, 0x666666, 0x666633, 0x666600,
+  0x6633FF, 0x6633CC, 0x663399, 0x663366, 0x663333, 0x663300,
+  0x6600FF, 0x6600CC, 0x660099, 0x660066, 0x660033, 0x660000,
+  0x33FFFF, 0x33FFCC, 0x33FF99, 0x33FF66, 0x33FF33, 0x33FF00,
+  0x33CCFF, 0x33CCCC, 0x33CC99, 0x33CC66, 0x33CC33, 0x33CC00,
+  0x3399FF, 0x3399CC, 0x339999, 0x339966, 0x339933, 0x339900,
+  0x3366FF, 0x3366CC, 0x336699, 0x336666, 0x336633, 0x336600,
+  0x3333FF, 0x3333CC, 0x333399, 0x333366, 0x333333, 0x333300,
+  0x3300FF, 0x3300CC, 0x330099, 0x330066, 0x330033, 0x330000,
+  0x00FFFF, 0x00FFCC, 0x00FF99, 0x00FF66, 0x00FF33, 0x00FF00,
+  0x00CCFF, 0x00CCCC, 0x00CC99, 0x00CC66, 0x00CC33, 0x00CC00,
+  0x0099FF, 0x0099CC, 0x009999, 0x009966, 0x009933, 0x009900,
+  0x0066FF, 0x0066CC, 0x006699, 0x006666, 0x006633, 0x006600,
+  0x0033FF, 0x0033CC, 0x003399, 0x003366, 0x003333, 0x003300,
+  0x0000FF, 0x0000CC, 0x000099, 0x000066, 0x000033, 0xEE0000,
+  0xDD0000, 0xBB0000, 0xAA0000, 0x880000, 0x770000, 0x550000,
+  0x440000, 0x220000, 0x110000, 0x00EE00, 0x00DD00, 0x00BB00,
+  0x00AA00, 0x008800, 0x007700, 0x005500, 0x004400, 0x002200,
+  0x001100, 0x0000EE, 0x0000DD, 0x0000BB, 0x0000AA, 0x000088,
+  0x000077, 0x000055, 0x000044, 0x000022, 0x000011, 0xEEEEEE,
+  0xDDDDDD, 0xBBBBBB, 0xAAAAAA, 0x888888, 0x777777, 0x555555,
+  0x444444, 0x222222, 0x111111, 0x000000
+};
+
+static const guint32 ff_qt_grayscale_palette_16[16] = {
+  0xffffff, 0xeeeeee, 0xdddddd, 0xcccccc,
+  0xbbbbbb, 0xaaaaaa, 0x999999, 0x888888,
+  0x777777, 0x666666, 0x555555, 0x444444,
+  0x333333, 0x222222, 0x111111, 0x000000
+};
+
+static const guint32 ff_qt_grayscale_palette_256[256] = {
+  0xffffff, 0xfefefe, 0xfdfdfd, 0xfcfcfc, 0xfbfbfb, 0xfafafa, 0xf9f9f9,
+  0xf8f8f8, 0xf7f7f7, 0xf6f6f6, 0xf5f5f5, 0xf4f4f4, 0xf3f3f3, 0xf2f2f2,
+  0xf1f1f1, 0xf0f0f0, 0xefefef, 0xeeeeee, 0xededed, 0xececec, 0xebebeb,
+  0xeaeaea, 0xe9e9e9, 0xe8e8e8, 0xe7e7e7, 0xe6e6e6, 0xe5e5e5, 0xe4e4e4,
+  0xe3e3e3, 0xe2e2e2, 0xe1e1e1, 0xe0e0e0, 0xdfdfdf, 0xdedede, 0xdddddd,
+  0xdcdcdc, 0xdbdbdb, 0xdadada, 0xd9d9d9, 0xd8d8d8, 0xd7d7d7, 0xd6d6d6,
+  0xd5d5d5, 0xd4d4d4, 0xd3d3d3, 0xd2d2d2, 0xd1d1d1, 0xd0d0d0, 0xcfcfcf,
+  0xcecece, 0xcdcdcd, 0xcccccc, 0xcbcbcb, 0xcacaca, 0xc9c9c9, 0xc8c8c8,
+  0xc7c7c7, 0xc6c6c6, 0xc5c5c5, 0xc4c4c4, 0xc3c3c3, 0xc2c2c2, 0xc1c1c1,
+  0xc0c0c0, 0xbfbfbf, 0xbebebe, 0xbdbdbd, 0xbcbcbc, 0xbbbbbb, 0xbababa,
+  0xb9b9b9, 0xb8b8b8, 0xb7b7b7, 0xb6b6b6, 0xb5b5b5, 0xb4b4b4, 0xb3b3b3,
+  0xb2b2b2, 0xb1b1b1, 0xb0b0b0, 0xafafaf, 0xaeaeae, 0xadadad, 0xacacac,
+  0xababab, 0xaaaaaa, 0xa9a9a9, 0xa8a8a8, 0xa7a7a7, 0xa6a6a6, 0xa5a5a5,
+  0xa4a4a4, 0xa3a3a3, 0xa2a2a2, 0xa1a1a1, 0xa0a0a0, 0x9f9f9f, 0x9e9e9e,
+  0x9d9d9d, 0x9c9c9c, 0x9b9b9b, 0x9a9a9a, 0x999999, 0x989898, 0x979797,
+  0x969696, 0x959595, 0x949494, 0x939393, 0x929292, 0x919191, 0x909090,
+  0x8f8f8f, 0x8e8e8e, 0x8d8d8d, 0x8c8c8c, 0x8b8b8b, 0x8a8a8a, 0x898989,
+  0x888888, 0x878787, 0x868686, 0x858585, 0x848484, 0x838383, 0x828282,
+  0x818181, 0x808080, 0x7f7f7f, 0x7e7e7e, 0x7d7d7d, 0x7c7c7c, 0x7b7b7b,
+  0x7a7a7a, 0x797979, 0x787878, 0x777777, 0x767676, 0x757575, 0x747474,
+  0x737373, 0x727272, 0x717171, 0x707070, 0x6f6f6f, 0x6e6e6e, 0x6d6d6d,
+  0x6c6c6c, 0x6b6b6b, 0x6a6a6a, 0x696969, 0x686868, 0x676767, 0x666666,
+  0x656565, 0x646464, 0x636363, 0x626262, 0x616161, 0x606060, 0x5f5f5f,
+  0x5e5e5e, 0x5d5d5d, 0x5c5c5c, 0x5b5b5b, 0x5a5a5a, 0x595959, 0x585858,
+  0x575757, 0x565656, 0x555555, 0x545454, 0x535353, 0x525252, 0x515151,
+  0x505050, 0x4f4f4f, 0x4e4e4e, 0x4d4d4d, 0x4c4c4c, 0x4b4b4b, 0x4a4a4a,
+  0x494949, 0x484848, 0x474747, 0x464646, 0x454545, 0x444444, 0x434343,
+  0x424242, 0x414141, 0x404040, 0x3f3f3f, 0x3e3e3e, 0x3d3d3d, 0x3c3c3c,
+  0x3b3b3b, 0x3a3a3a, 0x393939, 0x383838, 0x373737, 0x363636, 0x353535,
+  0x343434, 0x333333, 0x323232, 0x313131, 0x303030, 0x2f2f2f, 0x2e2e2e,
+  0x2d2d2d, 0x2c2c2c, 0x2b2b2b, 0x2a2a2a, 0x292929, 0x282828, 0x272727,
+  0x262626, 0x252525, 0x242424, 0x232323, 0x222222, 0x212121, 0x202020,
+  0x1f1f1f, 0x1e1e1e, 0x1d1d1d, 0x1c1c1c, 0x1b1b1b, 0x1a1a1a, 0x191919,
+  0x181818, 0x171717, 0x161616, 0x151515, 0x141414, 0x131313, 0x121212,
+  0x111111, 0x101010, 0x0f0f0f, 0x0e0e0e, 0x0d0d0d, 0x0c0c0c, 0x0b0b0b,
+  0x0a0a0a, 0x090909, 0x080808, 0x070707, 0x060606, 0x050505, 0x040404,
+  0x030303, 0x020202, 0x010101, 0x000000
+};
+
+G_END_DECLS
+
+#endif /* __GST_QTPALETTE_H__ */
diff --git a/gst/law/Makefile.am b/gst/law/Makefile.am
new file mode 100644
index 0000000..9ed94ba
--- /dev/null
+++ b/gst/law/Makefile.am
@@ -0,0 +1,15 @@
+plugin_LTLIBRARIES = libgstalaw.la libgstmulaw.la
+
+libgstalaw_la_SOURCES = alaw-encode.c alaw-decode.c alaw.c
+libgstalaw_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+libgstalaw_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) $(GST_LIBS)
+libgstalaw_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+libgstmulaw_la_SOURCES = mulaw-encode.c mulaw-conversion.c mulaw-decode.c mulaw.c
+libgstmulaw_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+libgstmulaw_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) $(GST_LIBS)
+libgstmulaw_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = mulaw-conversion.h alaw-encode.h alaw-decode.h mulaw-encode.h mulaw-decode.h
diff --git a/gst/law/alaw-decode.c b/gst/law/alaw-decode.c
new file mode 100644
index 0000000..eea23e5
--- /dev/null
+++ b/gst/law/alaw-decode.c
@@ -0,0 +1,231 @@
+/* GStreamer A-Law to PCM conversion
+ * Copyright (C) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-alawdec
+ *
+ * This element decodes alaw audio. Alaw coding is also known as G.711.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "alaw-decode.h"
+
+extern GstStaticPadTemplate alaw_dec_src_factory;
+extern GstStaticPadTemplate alaw_dec_sink_factory;
+
+GST_DEBUG_CATEGORY_STATIC (alaw_dec_debug);
+#define GST_CAT_DEFAULT alaw_dec_debug
+
+static gboolean gst_alaw_dec_set_format (GstAudioDecoder * dec, GstCaps * caps);
+static GstFlowReturn gst_alaw_dec_handle_frame (GstAudioDecoder * dec,
+    GstBuffer * buffer);
+
+#define gst_alaw_dec_parent_class parent_class
+G_DEFINE_TYPE (GstALawDec, gst_alaw_dec, GST_TYPE_AUDIO_DECODER);
+
+/* some day we might have defines in gstconfig.h that tell us about the
+ * desired cpu/memory/binary size trade-offs */
+#define GST_ALAW_DEC_USE_TABLE
+
+#ifdef GST_ALAW_DEC_USE_TABLE
+
+static const gint alaw_to_s16_table[256] = {
+  -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
+  -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
+  -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
+  -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
+  -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
+  -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
+  -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
+  -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
+  -344, -328, -376, -360, -280, -264, -312, -296,
+  -472, -456, -504, -488, -408, -392, -440, -424,
+  -88, -72, -120, -104, -24, -8, -56, -40,
+  -216, -200, -248, -232, -152, -136, -184, -168,
+  -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
+  -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
+  -688, -656, -752, -720, -560, -528, -624, -592,
+  -944, -912, -1008, -976, -816, -784, -880, -848,
+  5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
+  7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
+  2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
+  3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
+  22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
+  30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
+  11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
+  15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
+  344, 328, 376, 360, 280, 264, 312, 296,
+  472, 456, 504, 488, 408, 392, 440, 424,
+  88, 72, 120, 104, 24, 8, 56, 40,
+  216, 200, 248, 232, 152, 136, 184, 168,
+  1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
+  1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
+  688, 656, 752, 720, 560, 528, 624, 592,
+  944, 912, 1008, 976, 816, 784, 880, 848
+};
+
+static inline gint
+alaw_to_s16 (guint8 a_val)
+{
+  return alaw_to_s16_table[a_val];
+}
+
+#else /* GST_ALAW_DEC_USE_TABLE */
+
+static inline gint
+alaw_to_s16 (guint8 a_val)
+{
+  gint t;
+  gint seg;
+
+  a_val ^= 0x55;
+  t = a_val & 0x7f;
+  if (t < 16)
+    t = (t << 4) + 8;
+  else {
+    seg = (t >> 4) & 0x07;
+    t = ((t & 0x0f) << 4) + 0x108;
+    t <<= seg - 1;
+  }
+  return ((a_val & 0x80) ? t : -t);
+}
+
+#endif /* GST_ALAW_DEC_USE_TABLE */
+
+static gboolean
+gst_alaw_dec_set_format (GstAudioDecoder * dec, GstCaps * caps)
+{
+  GstALawDec *alawdec = GST_ALAW_DEC (dec);
+  GstStructure *structure;
+  int rate, channels;
+  GstAudioInfo info;
+
+  structure = gst_caps_get_structure (caps, 0);
+  if (!structure) {
+    GST_ERROR_OBJECT (dec, "failed to get structure from caps");
+    return FALSE;
+  }
+
+  if (!gst_structure_get_int (structure, "rate", &rate)) {
+    GST_ERROR_OBJECT (dec, "failed to find field rate in input caps");
+    return FALSE;
+  }
+
+  if (!gst_structure_get_int (structure, "channels", &channels)) {
+    GST_ERROR_OBJECT (dec, "failed to find field channels in input caps");
+    return FALSE;
+  }
+
+  gst_audio_info_init (&info);
+  gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, rate, channels, NULL);
+
+  GST_DEBUG_OBJECT (alawdec, "rate=%d, channels=%d", rate, channels);
+
+  return gst_audio_decoder_set_output_format (dec, &info);
+}
+
+static GstFlowReturn
+gst_alaw_dec_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer)
+{
+  GstMapInfo inmap, outmap;
+  gint16 *linear_data;
+  guint8 *alaw_data;
+  gsize alaw_size, linear_size;
+  GstBuffer *outbuf;
+  gint i;
+
+  if (!buffer) {
+    return GST_FLOW_OK;
+  }
+
+  if (!gst_buffer_map (buffer, &inmap, GST_MAP_READ)) {
+    GST_ERROR_OBJECT (dec, "failed to map input buffer");
+    goto error_failed_map_input_buffer;
+  }
+
+  alaw_data = inmap.data;
+  alaw_size = inmap.size;
+
+  linear_size = alaw_size * 2;
+
+  outbuf = gst_audio_decoder_allocate_output_buffer (dec, linear_size);
+  if (!gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE)) {
+    GST_ERROR_OBJECT (dec, "failed to map input buffer");
+    goto error_failed_map_output_buffer;
+  }
+
+  linear_data = (gint16 *) outmap.data;
+  for (i = 0; i < alaw_size; i++) {
+    linear_data[i] = alaw_to_s16 (alaw_data[i]);
+  }
+
+  gst_buffer_unmap (outbuf, &outmap);
+  gst_buffer_unmap (buffer, &inmap);
+
+  return gst_audio_decoder_finish_frame (dec, outbuf, -1);
+
+error_failed_map_output_buffer:
+  gst_buffer_unref (outbuf);
+  gst_buffer_unmap (buffer, &inmap);
+
+error_failed_map_input_buffer:
+  return GST_FLOW_ERROR;
+}
+
+static gboolean
+gst_alaw_dec_start (GstAudioDecoder * dec)
+{
+  gst_audio_decoder_set_estimate_rate (dec, TRUE);
+
+  return TRUE;
+}
+
+static void
+gst_alaw_dec_class_init (GstALawDecClass * klass)
+{
+  GstElementClass *element_class = (GstElementClass *) klass;
+  GstAudioDecoderClass *audiodec_class = GST_AUDIO_DECODER_CLASS (klass);
+
+  gst_element_class_add_static_pad_template (element_class,
+      &alaw_dec_src_factory);
+  gst_element_class_add_static_pad_template (element_class,
+      &alaw_dec_sink_factory);
+
+  audiodec_class->start = GST_DEBUG_FUNCPTR (gst_alaw_dec_start);
+  audiodec_class->set_format = GST_DEBUG_FUNCPTR (gst_alaw_dec_set_format);
+  audiodec_class->handle_frame = GST_DEBUG_FUNCPTR (gst_alaw_dec_handle_frame);
+
+  gst_element_class_set_static_metadata (element_class, "A Law audio decoder",
+      "Codec/Decoder/Audio",
+      "Convert 8bit A law to 16bit PCM",
+      "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
+
+  GST_DEBUG_CATEGORY_INIT (alaw_dec_debug, "alawdec", 0, "A Law audio decoder");
+}
+
+static void
+gst_alaw_dec_init (GstALawDec * alawdec)
+{
+  gst_audio_decoder_set_needs_format (GST_AUDIO_DECODER (alawdec), TRUE);
+  gst_audio_decoder_set_use_default_pad_acceptcaps (GST_AUDIO_DECODER_CAST
+      (alawdec), TRUE);
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_DECODER_SINK_PAD (alawdec));
+}
diff --git a/gst/law/alaw-decode.h b/gst/law/alaw-decode.h
new file mode 100644
index 0000000..58647dc
--- /dev/null
+++ b/gst/law/alaw-decode.h
@@ -0,0 +1,55 @@
+/* GStreamer A-Law to PCM conversion
+ * Copyright (C) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_ALAW_DECODE_H__
+#define __GST_ALAW_DECODE_H__
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_ALAW_DEC \
+  (gst_alaw_dec_get_type())
+#define GST_ALAW_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALAW_DEC,GstALawDec))
+#define GST_ALAW_DEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALAW_DEC,GstALawDecClass))
+#define GST_IS_ALAW_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALAW_DEC))
+#define GST_IS_ALAW_DEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALAW_DEC))
+
+typedef struct _GstALawDec GstALawDec;
+typedef struct _GstALawDecClass GstALawDecClass;
+
+struct _GstALawDec {
+  GstAudioDecoder element;
+};
+
+struct _GstALawDecClass {
+  GstAudioDecoderClass parent_class;
+};
+
+GType gst_alaw_dec_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_ALAW_DECODE_H__ */
+
diff --git a/gst/law/alaw-encode.c b/gst/law/alaw-encode.c
new file mode 100644
index 0000000..ff17000
--- /dev/null
+++ b/gst/law/alaw-encode.c
@@ -0,0 +1,427 @@
+/* GStreamer PCM to A-Law conversion
+ * Copyright (C) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-alawenc
+ *
+ * This element encode alaw audio. Alaw coding is also known as G.711.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/audio/audio.h>
+#include "alaw-encode.h"
+
+GST_DEBUG_CATEGORY_STATIC (alaw_enc_debug);
+#define GST_CAT_DEFAULT alaw_enc_debug
+
+extern GstStaticPadTemplate alaw_enc_src_factory;
+extern GstStaticPadTemplate alaw_enc_sink_factory;
+
+G_DEFINE_TYPE (GstALawEnc, gst_alaw_enc, GST_TYPE_AUDIO_ENCODER);
+
+static gboolean gst_alaw_enc_start (GstAudioEncoder * audioenc);
+static gboolean gst_alaw_enc_set_format (GstAudioEncoder * enc,
+    GstAudioInfo * info);
+static GstFlowReturn gst_alaw_enc_handle_frame (GstAudioEncoder * enc,
+    GstBuffer * buffer);
+
+/* some day we might have defines in gstconfig.h that tell us about the
+ * desired cpu/memory/binary size trade-offs */
+#define GST_ALAW_ENC_USE_TABLE
+
+#ifdef GST_ALAW_ENC_USE_TABLE
+
+static const guint8 alaw_encode[2048 + 1] = {
+  0xd5, 0xd4, 0xd7, 0xd6, 0xd1, 0xd0, 0xd3, 0xd2, 0xdd, 0xdc, 0xdf, 0xde,
+  0xd9, 0xd8, 0xdb, 0xda, 0xc5, 0xc4, 0xc7, 0xc6, 0xc1, 0xc0, 0xc3, 0xc2,
+  0xcd, 0xcc, 0xcf, 0xce, 0xc9, 0xc8, 0xcb, 0xca, 0xf5, 0xf5, 0xf4, 0xf4,
+  0xf7, 0xf7, 0xf6, 0xf6, 0xf1, 0xf1, 0xf0, 0xf0, 0xf3, 0xf3, 0xf2, 0xf2,
+  0xfd, 0xfd, 0xfc, 0xfc, 0xff, 0xff, 0xfe, 0xfe, 0xf9, 0xf9, 0xf8, 0xf8,
+  0xfb, 0xfb, 0xfa, 0xfa, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4,
+  0xe7, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe1, 0xe1, 0xe1, 0xe1,
+  0xe0, 0xe0, 0xe0, 0xe0, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2,
+  0xed, 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xef, 0xef, 0xef, 0xef,
+  0xee, 0xee, 0xee, 0xee, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8,
+  0xeb, 0xeb, 0xeb, 0xeb, 0xea, 0xea, 0xea, 0xea, 0x95, 0x95, 0x95, 0x95,
+  0x95, 0x95, 0x95, 0x95, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+  0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96,
+  0x96, 0x96, 0x96, 0x96, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+  0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x93, 0x93, 0x93, 0x93,
+  0x93, 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+  0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c,
+  0x9c, 0x9c, 0x9c, 0x9c, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+  0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x99, 0x99, 0x99, 0x99,
+  0x99, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+  0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a,
+  0x9a, 0x9a, 0x9a, 0x9a, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+  0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84,
+  0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+  0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+  0x87, 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+  0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x81, 0x81, 0x81, 0x81,
+  0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+  0x80, 0x80, 0x80, 0x80, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+  0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82,
+  0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+  0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+  0x8d, 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+  0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8f, 0x8f, 0x8f, 0x8f,
+  0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+  0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+  0x8e, 0x8e, 0x8e, 0x8e, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+  0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88,
+  0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+  0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+  0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+  0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0xb5, 0xb5, 0xb5, 0xb5,
+  0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
+  0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
+  0xb5, 0xb5, 0xb5, 0xb5, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+  0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+  0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+  0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
+  0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
+  0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6,
+  0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
+  0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
+  0xb6, 0xb6, 0xb6, 0xb6, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
+  0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
+  0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
+  0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
+  0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
+  0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb3, 0xb3, 0xb3, 0xb3,
+  0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
+  0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
+  0xb3, 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
+  0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
+  0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
+  0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
+  0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
+  0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc,
+  0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
+  0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
+  0xbc, 0xbc, 0xbc, 0xbc, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+  0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+  0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+  0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+  0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+  0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xb9, 0xb9, 0xb9, 0xb9,
+  0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
+  0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
+  0xb9, 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
+  0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
+  0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
+  0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+  0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+  0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba,
+  0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
+  0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
+  0xba, 0xba, 0xba, 0xba, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+  0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+  0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+  0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+  0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+  0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4,
+  0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+  0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+  0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+  0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+  0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+  0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+  0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+  0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+  0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+  0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+  0xa7, 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+  0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+  0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+  0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+  0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+  0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa1, 0xa1, 0xa1, 0xa1,
+  0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+  0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+  0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+  0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+  0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+  0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+  0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+  0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+  0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+  0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+  0xa0, 0xa0, 0xa0, 0xa0, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+  0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+  0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+  0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+  0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+  0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2,
+  0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+  0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+  0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+  0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+  0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+  0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+  0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+  0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+  0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+  0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+  0xad, 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+  0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+  0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+  0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+  0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+  0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xaf, 0xaf, 0xaf, 0xaf,
+  0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+  0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+  0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+  0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+  0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+  0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+  0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+  0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+  0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+  0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+  0xae, 0xae, 0xae, 0xae, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+  0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+  0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+  0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+  0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+  0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8,
+  0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+  0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+  0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+  0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+  0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+  0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+  0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+  0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+  0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+  0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+  0xab, 0xab, 0xab, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a
+};
+
+static inline guint8
+s16_to_alaw (gint16 pcm_val)
+{
+  if (pcm_val >= 0)
+    return alaw_encode[pcm_val / 16];
+  else
+    return (0x7F & alaw_encode[pcm_val / -16]);
+}
+
+#else /* GST_ALAW_ENC_USE_TABLE */
+
+/*
+ * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
+ *
+ * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data.
+ *
+ *              Linear Input Code       Compressed Code
+ *      ------------------------        ---------------
+ *      0000000wxyza                    000wxyz
+ *      0000001wxyza                    001wxyz
+ *      000001wxyzab                    010wxyz
+ *      00001wxyzabc                    011wxyz
+ *      0001wxyzabcd                    100wxyz
+ *      001wxyzabcde                    101wxyz
+ *      01wxyzabcdef                    110wxyz
+ *      1wxyzabcdefg                    111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+static inline gint
+val_seg (gint val)
+{
+  gint r = 1;
+
+  val >>= 8;
+  if (val & 0xf0) {
+    val >>= 4;
+    r += 4;
+  }
+  if (val & 0x0c) {
+    val >>= 2;
+    r += 2;
+  }
+  if (val & 0x02)
+    r += 1;
+  return r;
+}
+
+static inline guint8
+s16_to_alaw (gint pcm_val)
+{
+  gint seg;
+  guint8 mask;
+  guint8 aval;
+
+  if (pcm_val >= 0) {
+    mask = 0xD5;
+  } else {
+    mask = 0x55;
+    pcm_val = -pcm_val;
+    if (pcm_val > 0x7fff)
+      pcm_val = 0x7fff;
+  }
+
+  if (pcm_val < 256)
+    aval = pcm_val >> 4;
+  else {
+    /* Convert the scaled magnitude to segment number. */
+    seg = val_seg (pcm_val);
+    aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
+  }
+  return aval ^ mask;
+}
+
+#endif /* GST_ALAW_ENC_USE_TABLE */
+
+static gboolean
+gst_alaw_enc_start (GstAudioEncoder * audioenc)
+{
+  GstALawEnc *alawenc = GST_ALAW_ENC (audioenc);
+
+  alawenc->channels = 0;
+  alawenc->rate = 0;
+
+  return TRUE;
+}
+
+static gboolean
+gst_alaw_enc_set_format (GstAudioEncoder * audioenc, GstAudioInfo * info)
+{
+  GstCaps *base_caps;
+  GstStructure *structure;
+  GstALawEnc *alawenc = GST_ALAW_ENC (audioenc);
+  gboolean ret;
+
+  alawenc->rate = info->rate;
+  alawenc->channels = info->channels;
+
+  base_caps =
+      gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SRC_PAD (audioenc));
+  g_assert (base_caps);
+  base_caps = gst_caps_make_writable (base_caps);
+  g_assert (base_caps);
+
+  structure = gst_caps_get_structure (base_caps, 0);
+  g_assert (structure);
+  gst_structure_set (structure, "rate", G_TYPE_INT, alawenc->rate, NULL);
+  gst_structure_set (structure, "channels", G_TYPE_INT, alawenc->channels,
+      NULL);
+
+  ret = gst_audio_encoder_set_output_format (audioenc, base_caps);
+  gst_caps_unref (base_caps);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_alaw_enc_handle_frame (GstAudioEncoder * audioenc, GstBuffer * buffer)
+{
+  GstALawEnc *alawenc;
+  GstMapInfo inmap, outmap;
+  gint16 *linear_data;
+  gsize linear_size;
+  guint8 *alaw_data;
+  guint alaw_size;
+  GstBuffer *outbuf;
+  GstFlowReturn ret;
+  gint i;
+
+  if (!buffer) {
+    ret = GST_FLOW_OK;
+    goto done;
+  }
+
+  alawenc = GST_ALAW_ENC (audioenc);
+
+  if (!alawenc->rate || !alawenc->channels)
+    goto not_negotiated;
+
+  gst_buffer_map (buffer, &inmap, GST_MAP_READ);
+  linear_data = (gint16 *) inmap.data;
+  linear_size = inmap.size;
+
+  alaw_size = linear_size / 2;
+
+  outbuf = gst_audio_encoder_allocate_output_buffer (audioenc, alaw_size);
+
+  g_assert (outbuf);
+
+  gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
+  alaw_data = outmap.data;
+
+  for (i = 0; i < alaw_size; i++) {
+    alaw_data[i] = s16_to_alaw (linear_data[i]);
+  }
+
+  gst_buffer_unmap (outbuf, &outmap);
+  gst_buffer_unmap (buffer, &inmap);
+
+  ret = gst_audio_encoder_finish_frame (audioenc, outbuf, -1);
+
+done:
+  return ret;
+
+not_negotiated:
+  {
+    GST_DEBUG_OBJECT (alawenc, "no format negotiated");
+    ret = GST_FLOW_NOT_NEGOTIATED;
+    goto done;
+  }
+}
+
+static void
+gst_alaw_enc_class_init (GstALawEncClass * klass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GstAudioEncoderClass *audio_encoder_class = GST_AUDIO_ENCODER_CLASS (klass);
+
+  audio_encoder_class->start = GST_DEBUG_FUNCPTR (gst_alaw_enc_start);
+  audio_encoder_class->set_format = GST_DEBUG_FUNCPTR (gst_alaw_enc_set_format);
+  audio_encoder_class->handle_frame =
+      GST_DEBUG_FUNCPTR (gst_alaw_enc_handle_frame);
+
+  gst_element_class_add_static_pad_template (element_class,
+      &alaw_enc_src_factory);
+  gst_element_class_add_static_pad_template (element_class,
+      &alaw_enc_sink_factory);
+
+  gst_element_class_set_static_metadata (element_class,
+      "A Law audio encoder", "Codec/Encoder/Audio",
+      "Convert 16bit PCM to 8bit A law",
+      "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
+  GST_DEBUG_CATEGORY_INIT (alaw_enc_debug, "alawenc", 0, "A Law audio encoder");
+}
+
+static void
+gst_alaw_enc_init (GstALawEnc * alawenc)
+{
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (alawenc));
+}
diff --git a/gst/law/alaw-encode.h b/gst/law/alaw-encode.h
new file mode 100644
index 0000000..7b08f48
--- /dev/null
+++ b/gst/law/alaw-encode.h
@@ -0,0 +1,57 @@
+/* GStreamer PCM to A-Law conversion
+ * Copyright (C) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_ALAW_ENCODE_H__
+#define __GST_ALAW_ENCODE_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_ALAW_ENC \
+  (gst_alaw_enc_get_type())
+#define GST_ALAW_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALAW_ENC,GstALawEnc))
+#define GST_ALAW_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALAW_ENC,GstALawEncClass))
+#define GST_IS_ALAW_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALAW_ENC))
+#define GST_IS_ALAW_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALAW_ENC))
+
+typedef struct _GstALawEnc GstALawEnc;
+typedef struct _GstALawEncClass GstALawEncClass;
+
+struct _GstALawEnc {
+  GstAudioEncoder encoder;
+
+  gint channels;
+  gint rate;
+};
+
+struct _GstALawEncClass {
+  GstAudioEncoderClass parent_class;
+};
+
+GType gst_alaw_enc_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_ALAW_ENCODE_H__ */
diff --git a/gst/law/alaw.c b/gst/law/alaw.c
new file mode 100644
index 0000000..64f7e06
--- /dev/null
+++ b/gst/law/alaw.c
@@ -0,0 +1,77 @@
+/* GStreamer PCM/A-Law conversions
+ *
+ * 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.1 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/audio/audio.h>
+
+#include "alaw-encode.h"
+#include "alaw-decode.h"
+
+GstStaticPadTemplate alaw_dec_src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (S16) ", "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 8000, 192000 ], " "channels = (int) [ 1, 2 ]")
+    );
+
+GstStaticPadTemplate alaw_dec_sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-alaw, "
+        "rate = [ 8000 , 192000 ], " "channels = [ 1 , 2 ]")
+    );
+
+GstStaticPadTemplate alaw_enc_sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (S16) ", "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 8000, 192000 ], " "channels = (int) [ 1, 2 ]")
+    );
+
+GstStaticPadTemplate alaw_enc_src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-alaw, "
+        "rate = [ 8000 , 192000 ], " "channels = [ 1 , 2 ]")
+    );
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "alawenc",
+          GST_RANK_PRIMARY, GST_TYPE_ALAW_ENC) ||
+      !gst_element_register (plugin, "alawdec",
+          GST_RANK_PRIMARY, GST_TYPE_ALAW_DEC))
+    return FALSE;
+
+  return TRUE;
+}
+
+/* FIXME 0.11: merge alaw and mulaw into one plugin? */
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    alaw,
+    "ALaw audio conversion routines",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/law/meson.build b/gst/law/meson.build
new file mode 100644
index 0000000..661810d
--- /dev/null
+++ b/gst/law/meson.build
@@ -0,0 +1,17 @@
+gstalaw = library('gstalaw',
+  'alaw-encode.c', 'alaw-decode.c', 'alaw.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstbase_dep, gstaudio_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
+
+gstmulaw = library('gstmulaw',
+  'mulaw-encode.c', 'mulaw-conversion.c', 'mulaw-decode.c', 'mulaw.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstbase_dep, gstaudio_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/law/mulaw-conversion.c b/gst/law/mulaw-conversion.c
new file mode 100644
index 0000000..15cde17
--- /dev/null
+++ b/gst/law/mulaw-conversion.c
@@ -0,0 +1,122 @@
+/*
+ * This routine converts from linear to ulaw
+ * 29 September 1989
+ *
+ * Craig Reese: IDA/Supercomputing Research Center
+ * Joe Campbell: Department of Defense
+ *
+ * References:
+ * 1) CCITT Recommendation G.711  (very difficult to follow)
+ * 2) "A New Digital Technique for Implementation of Any 
+ *     Continuous PCM Companding Law," Villeret, Michel,
+ *     et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
+ *     1973, pg. 11.12-11.17
+ * 3) MIL-STD-188-113,"Interoperability and Performance Standards
+ *     for Analog-to_Digital Conversion Techniques,"
+ *     17 February 1987
+ *
+ * Input: Signed 16 bit linear sample
+ * Output: 8 bit ulaw sample
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+
+#include "mulaw-conversion.h"
+
+#undef ZEROTRAP                 /* turn on the trap as per the MIL-STD */
+#define BIAS 0x84               /* define the add-in bias for 16 bit samples */
+#define CLIP 32635
+
+void
+mulaw_encode (gint16 * in, guint8 * out, gint numsamples)
+{
+  static const gint16 exp_lut[256] = {
+    0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+  };
+  gint16 sign, exponent, mantissa;
+  gint16 sample;
+  guint8 ulawbyte;
+  gint i;
+
+  for (i = 0; i < numsamples; i++) {
+    sample = in[i];
+      /** get the sample into sign-magnitude **/
+    sign = (sample >> 8) & 0x80;        /* set aside the sign */
+    if (sign != 0) {
+      sample = -sample;         /* get magnitude */
+    }
+    /* sample can be zero because we can overflow in the inversion,
+     * checking against the unsigned version solves this */
+    if (((guint16) sample) > CLIP)
+      sample = CLIP;            /* clip the magnitude */
+
+      /** convert from 16 bit linear to ulaw **/
+    sample = sample + BIAS;
+    exponent = exp_lut[(sample >> 7) & 0xFF];
+    mantissa = (sample >> (exponent + 3)) & 0x0F;
+    ulawbyte = ~(sign | (exponent << 4) | mantissa);
+#ifdef ZEROTRAP
+    if (ulawbyte == 0)
+      ulawbyte = 0x02;          /* optional CCITT trap */
+#endif
+    out[i] = ulawbyte;
+  }
+}
+
+/*
+ * This routine converts from ulaw to 16 bit linear
+ * 29 September 1989
+ *
+ * Craig Reese: IDA/Supercomputing Research Center
+ *
+ * References:
+ * 1) CCITT Recommendation G.711  (very difficult to follow)
+ * 2) MIL-STD-188-113,"Interoperability and Performance Standards
+ *     for Analog-to_Digital Conversion Techniques,"
+ *     17 February 1987
+ *
+ * Input: 8 bit ulaw sample
+ * Output: signed 16 bit linear sample
+ */
+
+void
+mulaw_decode (guint8 * in, gint16 * out, gint numsamples)
+{
+  static const gint16 exp_lut[8] =
+      { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
+  gint16 sign, exponent, mantissa;
+  guint8 ulawbyte;
+  gint16 linear;
+  gint i;
+
+  for (i = 0; i < numsamples; i++) {
+    ulawbyte = in[i];
+    ulawbyte = ~ulawbyte;
+    sign = (ulawbyte & 0x80);
+    exponent = (ulawbyte >> 4) & 0x07;
+    mantissa = ulawbyte & 0x0F;
+    linear = exp_lut[exponent] + (mantissa << (exponent + 3));
+    if (sign != 0)
+      linear = -linear;
+    out[i] = linear;
+  }
+}
diff --git a/gst/law/mulaw-conversion.h b/gst/law/mulaw-conversion.h
new file mode 100644
index 0000000..38367ad
--- /dev/null
+++ b/gst/law/mulaw-conversion.h
@@ -0,0 +1,12 @@
+#ifndef _GST_ULAW_CONVERSION_H
+#define _GST_ULAW_CONVERSION_H
+
+#include <glib.h>
+
+void
+mulaw_encode(gint16* in, guint8* out, gint numsamples);
+void
+mulaw_decode(guint8* in,gint16* out,gint numsamples);
+
+#endif /* _GST_ULAW_CONVERSION_H */
+
diff --git a/gst/law/mulaw-decode.c b/gst/law/mulaw-decode.c
new file mode 100644
index 0000000..1a70d0b
--- /dev/null
+++ b/gst/law/mulaw-decode.c
@@ -0,0 +1,176 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-mulawdec
+ *
+ * This element decodes mulaw audio. Mulaw coding is also known as G.711.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <gst/gst.h>
+
+#include "mulaw-decode.h"
+#include "mulaw-conversion.h"
+
+extern GstStaticPadTemplate mulaw_dec_src_factory;
+extern GstStaticPadTemplate mulaw_dec_sink_factory;
+
+static gboolean gst_mulawdec_set_format (GstAudioDecoder * dec, GstCaps * caps);
+static GstFlowReturn gst_mulawdec_handle_frame (GstAudioDecoder * dec,
+    GstBuffer * buffer);
+
+
+/* Stereo signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0
+};
+
+#define gst_mulawdec_parent_class parent_class
+G_DEFINE_TYPE (GstMuLawDec, gst_mulawdec, GST_TYPE_AUDIO_DECODER);
+
+static gboolean
+gst_mulawdec_set_format (GstAudioDecoder * dec, GstCaps * caps)
+{
+  GstMuLawDec *mulawdec = GST_MULAWDEC (dec);
+  GstStructure *structure;
+  int rate, channels;
+  GstAudioInfo info;
+
+  structure = gst_caps_get_structure (caps, 0);
+  if (!structure) {
+    GST_ERROR ("failed to get structure from caps");
+    goto error_failed_get_structure;
+  }
+
+  if (!gst_structure_get_int (structure, "rate", &rate)) {
+    GST_ERROR ("failed to find field rate in input caps");
+    goto error_failed_find_rate;
+  }
+
+  if (!gst_structure_get_int (structure, "channels", &channels)) {
+    GST_ERROR ("failed to find field channels in input caps");
+    goto error_failed_find_channel;
+  }
+
+  gst_audio_info_init (&info);
+  gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, rate, channels, NULL);
+
+  GST_DEBUG_OBJECT (mulawdec, "rate=%d, channels=%d", rate, channels);
+
+  return gst_audio_decoder_set_output_format (dec, &info);
+
+error_failed_find_channel:
+error_failed_find_rate:
+error_failed_get_structure:
+  return FALSE;
+}
+
+static GstFlowReturn
+gst_mulawdec_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer)
+{
+  GstMapInfo inmap, outmap;
+  gint16 *linear_data;
+  guint8 *mulaw_data;
+  gsize mulaw_size, linear_size;
+  GstBuffer *outbuf;
+
+  if (!buffer) {
+    return GST_FLOW_OK;
+  }
+
+  if (!gst_buffer_map (buffer, &inmap, GST_MAP_READ)) {
+    GST_ERROR ("failed to map input buffer");
+    goto error_failed_map_input_buffer;
+  }
+
+  mulaw_data = inmap.data;
+  mulaw_size = inmap.size;
+
+  linear_size = mulaw_size * 2;
+
+  outbuf = gst_audio_decoder_allocate_output_buffer (dec, linear_size);
+  if (!gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE)) {
+    GST_ERROR ("failed to map input buffer");
+    goto error_failed_map_output_buffer;
+  }
+
+  linear_data = (gint16 *) outmap.data;
+
+  mulaw_decode (mulaw_data, linear_data, mulaw_size);
+
+  gst_buffer_unmap (outbuf, &outmap);
+  gst_buffer_unmap (buffer, &inmap);
+
+  return gst_audio_decoder_finish_frame (dec, outbuf, -1);
+
+error_failed_map_output_buffer:
+  gst_buffer_unref (outbuf);
+  gst_buffer_unmap (buffer, &inmap);
+
+error_failed_map_input_buffer:
+  return GST_FLOW_ERROR;
+}
+
+static gboolean
+gst_mulawdec_start (GstAudioDecoder * dec)
+{
+  gst_audio_decoder_set_estimate_rate (dec, TRUE);
+
+  return TRUE;
+}
+
+static void
+gst_mulawdec_class_init (GstMuLawDecClass * klass)
+{
+  GstElementClass *element_class = (GstElementClass *) klass;
+  GstAudioDecoderClass *audiodec_class = GST_AUDIO_DECODER_CLASS (klass);
+
+  gst_element_class_add_static_pad_template (element_class,
+      &mulaw_dec_src_factory);
+  gst_element_class_add_static_pad_template (element_class,
+      &mulaw_dec_sink_factory);
+
+
+  audiodec_class->start = GST_DEBUG_FUNCPTR (gst_mulawdec_start);
+  audiodec_class->set_format = GST_DEBUG_FUNCPTR (gst_mulawdec_set_format);
+  audiodec_class->handle_frame = GST_DEBUG_FUNCPTR (gst_mulawdec_handle_frame);
+
+  gst_element_class_set_static_metadata (element_class, "Mu Law audio decoder",
+      "Codec/Decoder/Audio",
+      "Convert 8bit mu law to 16bit PCM",
+      "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
+}
+
+static void
+gst_mulawdec_init (GstMuLawDec * mulawdec)
+{
+  gst_audio_decoder_set_needs_format (GST_AUDIO_DECODER (mulawdec), TRUE);
+  gst_audio_decoder_set_use_default_pad_acceptcaps (GST_AUDIO_DECODER_CAST
+      (mulawdec), TRUE);
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_DECODER_SINK_PAD (mulawdec));
+}
diff --git a/gst/law/mulaw-decode.h b/gst/law/mulaw-decode.h
new file mode 100644
index 0000000..bed62fa
--- /dev/null
+++ b/gst/law/mulaw-decode.h
@@ -0,0 +1,54 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MULAWDECODE_H__
+#define __GST_MULAWDECODE_H__
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiodecoder.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_MULAWDEC \
+  (gst_mulawdec_get_type())
+#define GST_MULAWDEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULAWDEC,GstMuLawDec))
+#define GST_MULAWDEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULAWDEC,GstMuLawDecClass))
+#define GST_IS_MULAWDEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULAWDEC))
+#define GST_IS_MULAWDEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULAWDEC))
+typedef struct _GstMuLawDec GstMuLawDec;
+typedef struct _GstMuLawDecClass GstMuLawDecClass;
+
+struct _GstMuLawDec
+{
+  GstAudioDecoder element;
+};
+
+struct _GstMuLawDecClass
+{
+  GstAudioDecoderClass parent_class;
+};
+
+GType gst_mulawdec_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_STEREO_H__ */
diff --git a/gst/law/mulaw-encode.c b/gst/law/mulaw-encode.c
new file mode 100644
index 0000000..b22ce0d
--- /dev/null
+++ b/gst/law/mulaw-encode.c
@@ -0,0 +1,211 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-mulawenc
+ *
+ * This element encode mulaw audio. Mulaw coding is also known as G.711.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+
+#include "mulaw-encode.h"
+#include "mulaw-conversion.h"
+
+extern GstStaticPadTemplate mulaw_enc_src_factory;
+extern GstStaticPadTemplate mulaw_enc_sink_factory;
+
+/* Stereo signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0
+};
+
+static gboolean gst_mulawenc_start (GstAudioEncoder * audioenc);
+static gboolean gst_mulawenc_set_format (GstAudioEncoder * enc,
+    GstAudioInfo * info);
+static GstFlowReturn gst_mulawenc_handle_frame (GstAudioEncoder * enc,
+    GstBuffer * buffer);
+static void gst_mulawenc_set_tags (GstMuLawEnc * mulawenc);
+
+
+#define gst_mulawenc_parent_class parent_class
+G_DEFINE_TYPE (GstMuLawEnc, gst_mulawenc, GST_TYPE_AUDIO_ENCODER);
+
+/*static guint gst_stereo_signals[LAST_SIGNAL] = { 0 }; */
+
+static gboolean
+gst_mulawenc_start (GstAudioEncoder * audioenc)
+{
+  GstMuLawEnc *mulawenc = GST_MULAWENC (audioenc);
+
+  mulawenc->channels = 0;
+  mulawenc->rate = 0;
+
+  return TRUE;
+}
+
+
+static void
+gst_mulawenc_set_tags (GstMuLawEnc * mulawenc)
+{
+  GstTagList *taglist;
+  guint bitrate;
+
+  /* bitrate of mulaw is 8 bits/sample * sample rate * number of channels */
+  bitrate = 8 * mulawenc->rate * mulawenc->channels;
+
+  taglist = gst_tag_list_new_empty ();
+  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
+      GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
+  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
+      GST_TAG_MINIMUM_BITRATE, bitrate, NULL);
+  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
+      GST_TAG_BITRATE, bitrate, NULL);
+
+  gst_audio_encoder_merge_tags (GST_AUDIO_ENCODER (mulawenc),
+      taglist, GST_TAG_MERGE_REPLACE);
+
+  gst_tag_list_unref (taglist);
+}
+
+
+static gboolean
+gst_mulawenc_set_format (GstAudioEncoder * audioenc, GstAudioInfo * info)
+{
+  GstCaps *base_caps;
+  GstStructure *structure;
+  GstMuLawEnc *mulawenc = GST_MULAWENC (audioenc);
+  gboolean ret;
+
+  mulawenc->rate = info->rate;
+  mulawenc->channels = info->channels;
+
+  base_caps =
+      gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SRC_PAD (audioenc));
+  g_assert (base_caps);
+  base_caps = gst_caps_make_writable (base_caps);
+  g_assert (base_caps);
+
+  structure = gst_caps_get_structure (base_caps, 0);
+  g_assert (structure);
+  gst_structure_set (structure, "rate", G_TYPE_INT, mulawenc->rate, NULL);
+  gst_structure_set (structure, "channels", G_TYPE_INT, mulawenc->channels,
+      NULL);
+
+  gst_mulawenc_set_tags (mulawenc);
+
+  ret = gst_audio_encoder_set_output_format (audioenc, base_caps);
+  gst_caps_unref (base_caps);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_mulawenc_handle_frame (GstAudioEncoder * audioenc, GstBuffer * buffer)
+{
+  GstMuLawEnc *mulawenc;
+  GstMapInfo inmap, outmap;
+  gint16 *linear_data;
+  gsize linear_size;
+  guint8 *mulaw_data;
+  guint mulaw_size;
+  GstBuffer *outbuf;
+  GstFlowReturn ret;
+
+  if (!buffer) {
+    ret = GST_FLOW_OK;
+    goto done;
+  }
+
+  mulawenc = GST_MULAWENC (audioenc);
+
+  if (!mulawenc->rate || !mulawenc->channels)
+    goto not_negotiated;
+
+  gst_buffer_map (buffer, &inmap, GST_MAP_READ);
+  linear_data = (gint16 *) inmap.data;
+  linear_size = inmap.size;
+
+  mulaw_size = linear_size / 2;
+
+  outbuf = gst_audio_encoder_allocate_output_buffer (audioenc, mulaw_size);
+
+  g_assert (outbuf);
+
+  gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
+  mulaw_data = outmap.data;
+
+  mulaw_encode (linear_data, mulaw_data, mulaw_size);
+
+  gst_buffer_unmap (outbuf, &outmap);
+  gst_buffer_unmap (buffer, &inmap);
+
+  ret = gst_audio_encoder_finish_frame (audioenc, outbuf, -1);
+
+done:
+
+  return ret;
+
+not_negotiated:
+  {
+    GST_DEBUG_OBJECT (mulawenc, "no format negotiated");
+    ret = GST_FLOW_NOT_NEGOTIATED;
+    goto done;
+  }
+}
+
+
+
+static void
+gst_mulawenc_class_init (GstMuLawEncClass * klass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GstAudioEncoderClass *audio_encoder_class = GST_AUDIO_ENCODER_CLASS (klass);
+
+  audio_encoder_class->start = GST_DEBUG_FUNCPTR (gst_mulawenc_start);
+  audio_encoder_class->set_format = GST_DEBUG_FUNCPTR (gst_mulawenc_set_format);
+  audio_encoder_class->handle_frame =
+      GST_DEBUG_FUNCPTR (gst_mulawenc_handle_frame);
+
+  gst_element_class_add_static_pad_template (element_class,
+      &mulaw_enc_src_factory);
+  gst_element_class_add_static_pad_template (element_class,
+      &mulaw_enc_sink_factory);
+
+  gst_element_class_set_static_metadata (element_class, "Mu Law audio encoder",
+      "Codec/Encoder/Audio",
+      "Convert 16bit PCM to 8bit mu law",
+      "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
+}
+
+static void
+gst_mulawenc_init (GstMuLawEnc * mulawenc)
+{
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (mulawenc));
+}
diff --git a/gst/law/mulaw-encode.h b/gst/law/mulaw-encode.h
new file mode 100644
index 0000000..c5ade39
--- /dev/null
+++ b/gst/law/mulaw-encode.h
@@ -0,0 +1,57 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_MULAWENCODE_H__
+#define __GST_MULAWENCODE_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudioencoder.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_MULAWENC \
+  (gst_mulawenc_get_type())
+#define GST_MULAWENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULAWENC,GstMuLawEnc))
+#define GST_MULAWENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULAWENC,GstMuLawEncClass))
+#define GST_IS_MULAWENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULAWENC))
+#define GST_IS_MULAWENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULAWENC))
+typedef struct _GstMuLawEnc GstMuLawEnc;
+typedef struct _GstMuLawEncClass GstMuLawEncClass;
+
+struct _GstMuLawEnc
+{
+  GstAudioEncoder element;
+
+  gint channels;
+  gint rate;
+};
+
+struct _GstMuLawEncClass
+{
+  GstAudioEncoderClass parent_class;
+};
+
+GType gst_mulawenc_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_STEREO_H__ */
diff --git a/gst/law/mulaw.c b/gst/law/mulaw.c
new file mode 100644
index 0000000..a2e614d
--- /dev/null
+++ b/gst/law/mulaw.c
@@ -0,0 +1,79 @@
+/* GStreamer PCM/A-Law conversions
+ *
+ * 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.1 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "mulaw-encode.h"
+#include "mulaw-decode.h"
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define INT_FORMAT "S16LE"
+#else
+#define INT_FORMAT "S16BE"
+#endif
+
+GstStaticPadTemplate mulaw_dec_src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " INT_FORMAT ", "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 8000, 192000 ], " "channels = (int) [ 1, 2 ]")
+    );
+
+GstStaticPadTemplate mulaw_dec_sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-mulaw, "
+        "rate = [ 8000 , 192000 ], " "channels = [ 1 , 2 ]")
+    );
+
+GstStaticPadTemplate mulaw_enc_sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " INT_FORMAT ", "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 8000, 192000 ], " "channels = (int) [ 1, 2 ]")
+    );
+
+GstStaticPadTemplate mulaw_enc_src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-mulaw, "
+        "rate = [ 8000 , 192000 ], " "channels = [ 1 , 2 ]")
+    );
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "mulawenc",
+          GST_RANK_PRIMARY, GST_TYPE_MULAWENC) ||
+      !gst_element_register (plugin, "mulawdec",
+          GST_RANK_PRIMARY, GST_TYPE_MULAWDEC))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    mulaw,
+    "MuLaw audio conversion routines",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/level/.gitignore b/gst/level/.gitignore
new file mode 100644
index 0000000..11efff7
--- /dev/null
+++ b/gst/level/.gitignore
@@ -0,0 +1 @@
+level-example
diff --git a/gst/level/Makefile.am b/gst/level/Makefile.am
new file mode 100644
index 0000000..49c7b28
--- /dev/null
+++ b/gst/level/Makefile.am
@@ -0,0 +1,8 @@
+plugin_LTLIBRARIES = libgstlevel.la
+
+libgstlevel_la_SOURCES = gstlevel.c
+libgstlevel_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstlevel_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(GST_BASE_LIBS) $(LIBM)
+libgstlevel_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstlevel.h
diff --git a/gst/level/gstlevel.c b/gst/level/gstlevel.c
new file mode 100644
index 0000000..bcf290e
--- /dev/null
+++ b/gst/level/gstlevel.c
@@ -0,0 +1,805 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2000,2001,2002,2003,2005
+ *           Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-level
+ *
+ * Level analyses incoming audio buffers and, if the #GstLevel:message property
+ * is %TRUE, generates an element message named
+ * <classname>&quot;level&quot;</classname>:
+ * after each interval of time given by the #GstLevel:interval property.
+ * The message's structure contains these fields:
+ * <itemizedlist>
+ * <listitem>
+ *   <para>
+ *   #GstClockTime
+ *   <classname>&quot;timestamp&quot;</classname>:
+ *   the timestamp of the buffer that triggered the message.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GstClockTime
+ *   <classname>&quot;stream-time&quot;</classname>:
+ *   the stream time of the buffer.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GstClockTime
+ *   <classname>&quot;running-time&quot;</classname>:
+ *   the running_time of the buffer.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GstClockTime
+ *   <classname>&quot;duration&quot;</classname>:
+ *   the duration of the buffer.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GstClockTime
+ *   <classname>&quot;endtime&quot;</classname>:
+ *   the end time of the buffer that triggered the message as stream time (this
+ *   is deprecated, as it can be calculated from stream-time + duration)
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GValueArray of #gdouble
+ *   <classname>&quot;peak&quot;</classname>:
+ *   the peak power level in dB for each channel
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GValueArray of #gdouble
+ *   <classname>&quot;decay&quot;</classname>:
+ *   the decaying peak power level in dB for each channel
+ *   The decaying peak level follows the peak level, but starts dropping if no
+ *   new peak is reached after the time given by the #GstLevel:peak-ttl.
+ *   When the decaying peak level drops, it does so at the decay rate as
+ *   specified by the #GstLevel:peak-falloff.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GValueArray of #gdouble
+ *   <classname>&quot;rms&quot;</classname>:
+ *   the Root Mean Square (or average power) level in dB for each channel
+ *   </para>
+ * </listitem>
+ * </itemizedlist>
+ *
+ * <refsect2>
+ * <title>Example application</title>
+ * <informalexample><programlisting language="C">
+ * <xi:include xmlns:xi="http://www.w3.org/2003/XInclude" parse="text" href="../../../../tests/examples/level/level-example.c" />
+ * </programlisting></informalexample>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <string.h>
+#include <math.h>
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+
+#include "gstlevel.h"
+
+GST_DEBUG_CATEGORY_STATIC (level_debug);
+#define GST_CAT_DEFAULT level_debug
+
+#define EPSILON 1e-35f
+
+static GstStaticPadTemplate sink_template_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) { S8, " GST_AUDIO_NE (S16) ", " GST_AUDIO_NE (S32)
+        ", " GST_AUDIO_NE (F32) "," GST_AUDIO_NE (F64) " },"
+        "layout = (string) interleaved, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+    );
+
+static GstStaticPadTemplate src_template_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) { S8, " GST_AUDIO_NE (S16) ", " GST_AUDIO_NE (S32)
+        ", " GST_AUDIO_NE (F32) "," GST_AUDIO_NE (F64) " },"
+        "layout = (string) interleaved, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+    );
+
+enum
+{
+  PROP_0,
+  PROP_POST_MESSAGES,
+  PROP_MESSAGE,
+  PROP_INTERVAL,
+  PROP_PEAK_TTL,
+  PROP_PEAK_FALLOFF
+};
+
+#define gst_level_parent_class parent_class
+G_DEFINE_TYPE (GstLevel, gst_level, GST_TYPE_BASE_TRANSFORM);
+
+static void gst_level_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_level_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_level_finalize (GObject * obj);
+
+static gboolean gst_level_set_caps (GstBaseTransform * trans, GstCaps * in,
+    GstCaps * out);
+static gboolean gst_level_start (GstBaseTransform * trans);
+static GstFlowReturn gst_level_transform_ip (GstBaseTransform * trans,
+    GstBuffer * in);
+static void gst_level_post_message (GstLevel * filter);
+static gboolean gst_level_sink_event (GstBaseTransform * trans,
+    GstEvent * event);
+static void gst_level_recalc_interval_frames (GstLevel * level);
+
+static void
+gst_level_class_init (GstLevelClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GstBaseTransformClass *trans_class = GST_BASE_TRANSFORM_CLASS (klass);
+
+  gobject_class->set_property = gst_level_set_property;
+  gobject_class->get_property = gst_level_get_property;
+  gobject_class->finalize = gst_level_finalize;
+
+  /**
+   * GstLevel:post-messages
+   *
+   * Post messages on the bus with level information.
+   *
+   * Since: 1.1.0
+   */
+  g_object_class_install_property (gobject_class, PROP_POST_MESSAGES,
+      g_param_spec_boolean ("post-messages", "Post Messages",
+          "Whether to post a 'level' element message on the bus for each "
+          "passed interval", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /* FIXME(2.0): remove this property */
+  /**
+   * GstLevel:post-messages
+   *
+   * Post messages on the bus with level information.
+   *
+   * Deprecated: use the #GstLevel:post-messages property
+   */
+#ifndef GST_REMOVE_DEPRECATED
+  g_object_class_install_property (gobject_class, PROP_MESSAGE,
+      g_param_spec_boolean ("message", "message",
+          "Post a 'level' message for each passed interval "
+          "(deprecated, use the post-messages property instead)", TRUE,
+          G_PARAM_READWRITE | G_PARAM_DEPRECATED | G_PARAM_STATIC_STRINGS));
+#endif
+  g_object_class_install_property (gobject_class, PROP_INTERVAL,
+      g_param_spec_uint64 ("interval", "Interval",
+          "Interval of time between message posts (in nanoseconds)",
+          1, G_MAXUINT64, GST_SECOND / 10,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_PEAK_TTL,
+      g_param_spec_uint64 ("peak-ttl", "Peak TTL",
+          "Time To Live of decay peak before it falls back (in nanoseconds)",
+          0, G_MAXUINT64, GST_SECOND / 10 * 3,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_PEAK_FALLOFF,
+      g_param_spec_double ("peak-falloff", "Peak Falloff",
+          "Decay rate of decay peak after TTL (in dB/sec)",
+          0.0, G_MAXDOUBLE, 10.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  GST_DEBUG_CATEGORY_INIT (level_debug, "level", 0, "Level calculation");
+
+  gst_element_class_add_static_pad_template (element_class,
+      &sink_template_factory);
+  gst_element_class_add_static_pad_template (element_class,
+      &src_template_factory);
+  gst_element_class_set_static_metadata (element_class, "Level",
+      "Filter/Analyzer/Audio",
+      "RMS/Peak/Decaying Peak Level messager for audio/raw",
+      "Thomas Vander Stichele <thomas at apestaart dot org>");
+
+  trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_level_set_caps);
+  trans_class->start = GST_DEBUG_FUNCPTR (gst_level_start);
+  trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_level_transform_ip);
+  trans_class->sink_event = GST_DEBUG_FUNCPTR (gst_level_sink_event);
+  trans_class->passthrough_on_same_caps = TRUE;
+}
+
+static void
+gst_level_init (GstLevel * filter)
+{
+  filter->CS = NULL;
+  filter->peak = NULL;
+  filter->last_peak = NULL;
+  filter->decay_peak = NULL;
+  filter->decay_peak_base = NULL;
+  filter->decay_peak_age = NULL;
+
+  gst_audio_info_init (&filter->info);
+
+  filter->interval = GST_SECOND / 10;
+  filter->decay_peak_ttl = GST_SECOND / 10 * 3;
+  filter->decay_peak_falloff = 10.0;    /* dB falloff (/sec) */
+
+  filter->post_messages = TRUE;
+
+  filter->process = NULL;
+
+  gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE);
+}
+
+static void
+gst_level_finalize (GObject * obj)
+{
+  GstLevel *filter = GST_LEVEL (obj);
+
+  g_free (filter->CS);
+  g_free (filter->peak);
+  g_free (filter->last_peak);
+  g_free (filter->decay_peak);
+  g_free (filter->decay_peak_base);
+  g_free (filter->decay_peak_age);
+
+  filter->CS = NULL;
+  filter->peak = NULL;
+  filter->last_peak = NULL;
+  filter->decay_peak = NULL;
+  filter->decay_peak_base = NULL;
+  filter->decay_peak_age = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gst_level_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstLevel *filter = GST_LEVEL (object);
+
+  switch (prop_id) {
+    case PROP_POST_MESSAGES:
+      /* fall-through */
+    case PROP_MESSAGE:
+      filter->post_messages = g_value_get_boolean (value);
+      break;
+    case PROP_INTERVAL:
+      filter->interval = g_value_get_uint64 (value);
+      /* Not exactly thread-safe, but property does not advertise that it
+       * can be changed at runtime anyway */
+      if (GST_AUDIO_INFO_RATE (&filter->info)) {
+        gst_level_recalc_interval_frames (filter);
+      }
+      break;
+    case PROP_PEAK_TTL:
+      filter->decay_peak_ttl =
+          gst_guint64_to_gdouble (g_value_get_uint64 (value));
+      break;
+    case PROP_PEAK_FALLOFF:
+      filter->decay_peak_falloff = g_value_get_double (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_level_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstLevel *filter = GST_LEVEL (object);
+
+  switch (prop_id) {
+    case PROP_POST_MESSAGES:
+      /* fall-through */
+    case PROP_MESSAGE:
+      g_value_set_boolean (value, filter->post_messages);
+      break;
+    case PROP_INTERVAL:
+      g_value_set_uint64 (value, filter->interval);
+      break;
+    case PROP_PEAK_TTL:
+      g_value_set_uint64 (value, filter->decay_peak_ttl);
+      break;
+    case PROP_PEAK_FALLOFF:
+      g_value_set_double (value, filter->decay_peak_falloff);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+
+/* process one (interleaved) channel of incoming samples
+ * calculate square sum of samples
+ * normalize and average over number of samples
+ * returns a normalized cumulative square value, which can be averaged
+ * to return the average power as a double between 0 and 1
+ * also returns the normalized peak power (square of the highest amplitude)
+ *
+ * caller must assure num is a multiple of channels
+ * samples for multiple channels are interleaved
+ * input sample data enters in *in_data and is not modified
+ * this filter only accepts signed audio data, so mid level is always 0
+ *
+ * for integers, this code considers the non-existant positive max value to be
+ * full-scale; so max-1 will not map to 1.0
+ */
+
+#define DEFINE_INT_LEVEL_CALCULATOR(TYPE, RESOLUTION)                         \
+static void inline                                                            \
+gst_level_calculate_##TYPE (gpointer data, guint num, guint channels,         \
+                            gdouble *NCS, gdouble *NPS)                       \
+{                                                                             \
+  TYPE * in = (TYPE *)data;                                                   \
+  register guint j;                                                           \
+  gdouble squaresum = 0.0;           /* square sum of the input samples */    \
+  register gdouble square = 0.0;     /* Square */                             \
+  register gdouble peaksquare = 0.0; /* Peak Square Sample */                 \
+  gdouble normalizer;                /* divisor to get a [-1.0, 1.0] range */ \
+                                                                              \
+  /* *NCS = 0.0; Normalized Cumulative Square */                              \
+  /* *NPS = 0.0; Normalized Peak Square */                                    \
+                                                                              \
+  for (j = 0; j < num; j += channels) {                                       \
+    square = ((gdouble) in[j]) * in[j];                                       \
+    if (square > peaksquare) peaksquare = square;                             \
+    squaresum += square;                                                      \
+  }                                                                           \
+                                                                              \
+  normalizer = (gdouble) (G_GINT64_CONSTANT(1) << (RESOLUTION * 2));          \
+  *NCS = squaresum / normalizer;                                              \
+  *NPS = peaksquare / normalizer;                                             \
+}
+
+DEFINE_INT_LEVEL_CALCULATOR (gint32, 31);
+DEFINE_INT_LEVEL_CALCULATOR (gint16, 15);
+DEFINE_INT_LEVEL_CALCULATOR (gint8, 7);
+
+/* FIXME: use orc to calculate squaresums? */
+#define DEFINE_FLOAT_LEVEL_CALCULATOR(TYPE)                                   \
+static void inline                                                            \
+gst_level_calculate_##TYPE (gpointer data, guint num, guint channels,         \
+                            gdouble *NCS, gdouble *NPS)                       \
+{                                                                             \
+  TYPE * in = (TYPE *)data;                                                   \
+  register guint j;                                                           \
+  gdouble squaresum = 0.0;           /* square sum of the input samples */    \
+  register gdouble square = 0.0;     /* Square */                             \
+  register gdouble peaksquare = 0.0; /* Peak Square Sample */                 \
+                                                                              \
+  /* *NCS = 0.0; Normalized Cumulative Square */                              \
+  /* *NPS = 0.0; Normalized Peak Square */                                    \
+                                                                              \
+  /* orc_level_squaresum_f64(&squaresum,in,num); */                           \
+  for (j = 0; j < num; j += channels) {                                       \
+    square = ((gdouble) in[j]) * in[j];                                       \
+    if (square > peaksquare) peaksquare = square;                             \
+    squaresum += square;                                                      \
+  }                                                                           \
+                                                                              \
+  *NCS = squaresum;                                                           \
+  *NPS = peaksquare;                                                          \
+}
+
+DEFINE_FLOAT_LEVEL_CALCULATOR (gfloat);
+DEFINE_FLOAT_LEVEL_CALCULATOR (gdouble);
+
+/* we would need stride to deinterleave also
+static void inline
+gst_level_calculate_gdouble (gpointer data, guint num, guint channels,
+                            gdouble *NCS, gdouble *NPS)
+{
+  orc_level_squaresum_f64(NCS,(gdouble *)data,num);
+  *NPS = 0.0;
+}
+*/
+
+static void
+gst_level_recalc_interval_frames (GstLevel * level)
+{
+  GstClockTime interval = level->interval;
+  guint sample_rate = GST_AUDIO_INFO_RATE (&level->info);
+  guint interval_frames;
+
+  interval_frames = GST_CLOCK_TIME_TO_FRAMES (interval, sample_rate);
+
+  if (interval_frames == 0) {
+    GST_WARNING_OBJECT (level, "interval %" GST_TIME_FORMAT " is too small, "
+        "should be at least %" GST_TIME_FORMAT " for sample rate %u",
+        GST_TIME_ARGS (interval),
+        GST_TIME_ARGS (GST_FRAMES_TO_CLOCK_TIME (1, sample_rate)), sample_rate);
+    interval_frames = 1;
+  }
+
+  level->interval_frames = interval_frames;
+
+  GST_INFO_OBJECT (level, "interval_frames now %u for interval "
+      "%" GST_TIME_FORMAT " and sample rate %u", interval_frames,
+      GST_TIME_ARGS (interval), sample_rate);
+}
+
+static gboolean
+gst_level_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
+{
+  GstLevel *filter = GST_LEVEL (trans);
+  GstAudioInfo info;
+  gint i, channels;
+
+  if (!gst_audio_info_from_caps (&info, in))
+    return FALSE;
+
+  switch (GST_AUDIO_INFO_FORMAT (&info)) {
+    case GST_AUDIO_FORMAT_S8:
+      filter->process = gst_level_calculate_gint8;
+      break;
+    case GST_AUDIO_FORMAT_S16:
+      filter->process = gst_level_calculate_gint16;
+      break;
+    case GST_AUDIO_FORMAT_S32:
+      filter->process = gst_level_calculate_gint32;
+      break;
+    case GST_AUDIO_FORMAT_F32:
+      filter->process = gst_level_calculate_gfloat;
+      break;
+    case GST_AUDIO_FORMAT_F64:
+      filter->process = gst_level_calculate_gdouble;
+      break;
+    default:
+      filter->process = NULL;
+      break;
+  }
+
+  filter->info = info;
+
+  channels = GST_AUDIO_INFO_CHANNELS (&info);
+
+  /* allocate channel variable arrays */
+  g_free (filter->CS);
+  g_free (filter->peak);
+  g_free (filter->last_peak);
+  g_free (filter->decay_peak);
+  g_free (filter->decay_peak_base);
+  g_free (filter->decay_peak_age);
+  filter->CS = g_new (gdouble, channels);
+  filter->peak = g_new (gdouble, channels);
+  filter->last_peak = g_new (gdouble, channels);
+  filter->decay_peak = g_new (gdouble, channels);
+  filter->decay_peak_base = g_new (gdouble, channels);
+
+  filter->decay_peak_age = g_new (GstClockTime, channels);
+
+  for (i = 0; i < channels; ++i) {
+    filter->CS[i] = filter->peak[i] = filter->last_peak[i] =
+        filter->decay_peak[i] = filter->decay_peak_base[i] = 0.0;
+    filter->decay_peak_age[i] = G_GUINT64_CONSTANT (0);
+  }
+
+  gst_level_recalc_interval_frames (filter);
+
+  return TRUE;
+}
+
+static gboolean
+gst_level_start (GstBaseTransform * trans)
+{
+  GstLevel *filter = GST_LEVEL (trans);
+
+  filter->num_frames = 0;
+  filter->message_ts = GST_CLOCK_TIME_NONE;
+
+  return TRUE;
+}
+
+static GstMessage *
+gst_level_message_new (GstLevel * level, GstClockTime timestamp,
+    GstClockTime duration)
+{
+  GstBaseTransform *trans = GST_BASE_TRANSFORM_CAST (level);
+  GstStructure *s;
+  GValue v = { 0, };
+  GstClockTime endtime, running_time, stream_time;
+
+  running_time = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
+      timestamp);
+  stream_time = gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
+      timestamp);
+  /* endtime is for backwards compatibility */
+  endtime = stream_time + duration;
+
+  s = gst_structure_new ("level",
+      "endtime", GST_TYPE_CLOCK_TIME, endtime,
+      "timestamp", G_TYPE_UINT64, timestamp,
+      "stream-time", G_TYPE_UINT64, stream_time,
+      "running-time", G_TYPE_UINT64, running_time,
+      "duration", G_TYPE_UINT64, duration, NULL);
+
+  g_value_init (&v, G_TYPE_VALUE_ARRAY);
+  g_value_take_boxed (&v, g_value_array_new (0));
+  gst_structure_take_value (s, "rms", &v);
+
+  g_value_init (&v, G_TYPE_VALUE_ARRAY);
+  g_value_take_boxed (&v, g_value_array_new (0));
+  gst_structure_take_value (s, "peak", &v);
+
+  g_value_init (&v, G_TYPE_VALUE_ARRAY);
+  g_value_take_boxed (&v, g_value_array_new (0));
+  gst_structure_take_value (s, "decay", &v);
+
+  return gst_message_new_element (GST_OBJECT (level), s);
+}
+
+static void
+gst_level_message_append_channel (GstMessage * m, gdouble rms, gdouble peak,
+    gdouble decay)
+{
+  const GValue *array_val;
+  GstStructure *s;
+  GValueArray *arr;
+  GValue v = { 0, };
+
+  g_value_init (&v, G_TYPE_DOUBLE);
+
+  s = (GstStructure *) gst_message_get_structure (m);
+
+  array_val = gst_structure_get_value (s, "rms");
+  arr = (GValueArray *) g_value_get_boxed (array_val);
+  g_value_set_double (&v, rms);
+  g_value_array_append (arr, &v);       /* copies by value */
+
+  array_val = gst_structure_get_value (s, "peak");
+  arr = (GValueArray *) g_value_get_boxed (array_val);
+  g_value_set_double (&v, peak);
+  g_value_array_append (arr, &v);       /* copies by value */
+
+  array_val = gst_structure_get_value (s, "decay");
+  arr = (GValueArray *) g_value_get_boxed (array_val);
+  g_value_set_double (&v, decay);
+  g_value_array_append (arr, &v);       /* copies by value */
+
+  g_value_unset (&v);
+}
+
+static GstFlowReturn
+gst_level_transform_ip (GstBaseTransform * trans, GstBuffer * in)
+{
+  GstLevel *filter;
+  GstMapInfo map;
+  guint8 *in_data;
+  gsize in_size;
+  gdouble CS;
+  guint i;
+  guint num_frames;
+  guint num_int_samples = 0;    /* number of interleaved samples
+                                 * ie. total count for all channels combined */
+  guint block_size, block_int_size;     /* we subdivide buffers to not skip message
+                                         * intervals */
+  GstClockTimeDiff falloff_time;
+  gint channels, rate, bps;
+
+  filter = GST_LEVEL (trans);
+
+  channels = GST_AUDIO_INFO_CHANNELS (&filter->info);
+  bps = GST_AUDIO_INFO_BPS (&filter->info);
+  rate = GST_AUDIO_INFO_RATE (&filter->info);
+
+  gst_buffer_map (in, &map, GST_MAP_READ);
+  in_data = map.data;
+  in_size = map.size;
+
+  num_int_samples = in_size / bps;
+
+  GST_LOG_OBJECT (filter, "analyzing %u sample frames at ts %" GST_TIME_FORMAT,
+      num_int_samples, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (in)));
+
+  g_return_val_if_fail (num_int_samples % channels == 0, GST_FLOW_ERROR);
+
+  if (GST_BUFFER_FLAG_IS_SET (in, GST_BUFFER_FLAG_DISCONT)) {
+    filter->message_ts = GST_BUFFER_TIMESTAMP (in);
+    filter->num_frames = 0;
+  }
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (filter->message_ts))) {
+    filter->message_ts = GST_BUFFER_TIMESTAMP (in);
+  }
+
+  num_frames = num_int_samples / channels;
+  while (num_frames > 0) {
+    block_size = filter->interval_frames - filter->num_frames;
+    block_size = MIN (block_size, num_frames);
+    block_int_size = block_size * channels;
+
+    for (i = 0; i < channels; ++i) {
+      if (!GST_BUFFER_FLAG_IS_SET (in, GST_BUFFER_FLAG_GAP)) {
+        filter->process (in_data + (bps * i), block_int_size, channels, &CS,
+            &filter->peak[i]);
+        GST_LOG_OBJECT (filter,
+            "[%d]: cumulative squares %lf, over %d samples/%d channels",
+            i, CS, block_int_size, channels);
+        filter->CS[i] += CS;
+      } else {
+        filter->peak[i] = 0.0;
+      }
+
+      filter->decay_peak_age[i] += GST_FRAMES_TO_CLOCK_TIME (num_frames, rate);
+      GST_LOG_OBJECT (filter,
+          "[%d]: peak %f, last peak %f, decay peak %f, age %" GST_TIME_FORMAT,
+          i, filter->peak[i], filter->last_peak[i], filter->decay_peak[i],
+          GST_TIME_ARGS (filter->decay_peak_age[i]));
+
+      /* update running peak */
+      if (filter->peak[i] > filter->last_peak[i])
+        filter->last_peak[i] = filter->peak[i];
+
+      /* make decay peak fall off if too old */
+      falloff_time =
+          GST_CLOCK_DIFF (gst_gdouble_to_guint64 (filter->decay_peak_ttl),
+          filter->decay_peak_age[i]);
+      if (falloff_time > 0) {
+        gdouble falloff_dB;
+        gdouble falloff;
+        gdouble length;         /* length of falloff time in seconds */
+
+        length = (gdouble) falloff_time / (gdouble) GST_SECOND;
+        falloff_dB = filter->decay_peak_falloff * length;
+        falloff = pow (10, falloff_dB / -20.0);
+
+        GST_LOG_OBJECT (filter,
+            "falloff: current %f, base %f, interval %" GST_TIME_FORMAT
+            ", dB falloff %f, factor %e",
+            filter->decay_peak[i], filter->decay_peak_base[i],
+            GST_TIME_ARGS (falloff_time), falloff_dB, falloff);
+        filter->decay_peak[i] = filter->decay_peak_base[i] * falloff;
+        GST_LOG_OBJECT (filter,
+            "peak is %" GST_TIME_FORMAT " old, decayed with factor %e to %f",
+            GST_TIME_ARGS (filter->decay_peak_age[i]), falloff,
+            filter->decay_peak[i]);
+      } else {
+        GST_LOG_OBJECT (filter, "peak not old enough, not decaying");
+      }
+
+      /* if the peak of this run is higher, the decay peak gets reset */
+      if (filter->peak[i] >= filter->decay_peak[i]) {
+        GST_LOG_OBJECT (filter, "new peak, %f", filter->peak[i]);
+        filter->decay_peak[i] = filter->peak[i];
+        filter->decay_peak_base[i] = filter->peak[i];
+        filter->decay_peak_age[i] = G_GINT64_CONSTANT (0);
+      }
+    }
+    in_data += block_size * bps * channels;
+
+    filter->num_frames += block_size;
+    num_frames -= block_size;
+
+    /* do we need to message ? */
+    if (filter->num_frames >= filter->interval_frames) {
+      gst_level_post_message (filter);
+    }
+  }
+
+  gst_buffer_unmap (in, &map);
+
+  return GST_FLOW_OK;
+}
+
+static void
+gst_level_post_message (GstLevel * filter)
+{
+  guint i;
+  gint channels, rate, frames = filter->num_frames;
+  GstClockTime duration;
+
+  channels = GST_AUDIO_INFO_CHANNELS (&filter->info);
+  rate = GST_AUDIO_INFO_RATE (&filter->info);
+  duration = GST_FRAMES_TO_CLOCK_TIME (frames, rate);
+
+  if (filter->post_messages) {
+    GstMessage *m =
+        gst_level_message_new (filter, filter->message_ts, duration);
+
+    GST_LOG_OBJECT (filter,
+        "message: ts %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT
+        ", num_frames %d", GST_TIME_ARGS (filter->message_ts),
+        GST_TIME_ARGS (duration), frames);
+
+    for (i = 0; i < channels; ++i) {
+      gdouble RMS;
+      gdouble RMSdB, peakdB, decaydB;
+
+      RMS = sqrt (filter->CS[i] / frames);
+      GST_LOG_OBJECT (filter,
+          "message: channel %d, CS %f, RMS %f", i, filter->CS[i], RMS);
+      GST_LOG_OBJECT (filter,
+          "message: last_peak: %f, decay_peak: %f",
+          filter->last_peak[i], filter->decay_peak[i]);
+      /* RMS values are calculated in amplitude, so 20 * log 10 */
+      RMSdB = 20 * log10 (RMS + EPSILON);
+      /* peak values are square sums, ie. power, so 10 * log 10 */
+      peakdB = 10 * log10 (filter->last_peak[i] + EPSILON);
+      decaydB = 10 * log10 (filter->decay_peak[i] + EPSILON);
+
+      if (filter->decay_peak[i] < filter->last_peak[i]) {
+        /* this can happen in certain cases, for example when
+         * the last peak is between decay_peak and decay_peak_base */
+        GST_DEBUG_OBJECT (filter,
+            "message: decay peak dB %f smaller than last peak dB %f, copying",
+            decaydB, peakdB);
+        filter->decay_peak[i] = filter->last_peak[i];
+      }
+      GST_LOG_OBJECT (filter,
+          "message: RMS %f dB, peak %f dB, decay %f dB",
+          RMSdB, peakdB, decaydB);
+
+      gst_level_message_append_channel (m, RMSdB, peakdB, decaydB);
+
+      /* reset cumulative and normal peak */
+      filter->CS[i] = 0.0;
+      filter->last_peak[i] = 0.0;
+    }
+
+    gst_element_post_message (GST_ELEMENT (filter), m);
+
+  }
+  filter->num_frames -= frames;
+  filter->message_ts += duration;
+}
+
+
+static gboolean
+gst_level_sink_event (GstBaseTransform * trans, GstEvent * event)
+{
+  if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
+    GstLevel *filter = GST_LEVEL (trans);
+
+    gst_level_post_message (filter);
+  }
+
+  return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "level", GST_RANK_NONE, GST_TYPE_LEVEL);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    level,
+    "Audio level plugin",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/level/gstlevel.h b/gst/level/gstlevel.h
new file mode 100644
index 0000000..e6d927a
--- /dev/null
+++ b/gst/level/gstlevel.h
@@ -0,0 +1,92 @@
+/* GStreamer
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2000,2001,2002,2003,2005
+ *           Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_LEVEL_H__
+#define __GST_LEVEL_H__
+
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+
+G_BEGIN_DECLS
+
+
+#define GST_TYPE_LEVEL \
+  (gst_level_get_type())
+#define GST_LEVEL(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_LEVEL,GstLevel))
+#define GST_LEVEL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_LEVEL,GstLevelClass))
+#define GST_LEVEL_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_LEVEL,GstLevelClass))
+#define GST_IS_LEVEL(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_LEVEL))
+#define GST_IS_LEVEL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_LEVEL))
+
+
+typedef struct _GstLevel GstLevel;
+typedef struct _GstLevelClass GstLevelClass;
+
+/**
+ * GstLevel:
+ *
+ * Opaque data structure.
+ */
+struct _GstLevel {
+  GstBaseTransform element;
+
+  /* properties */
+  gboolean post_messages;       /* whether or not to post messages */
+  guint64 interval;             /* how many nanoseconds between emits */
+  gdouble decay_peak_ttl;       /* time to live for peak in nanoseconds */
+  gdouble decay_peak_falloff;   /* falloff in dB/sec */
+
+  GstAudioInfo info;
+  gint num_frames;              /* frame count (1 sample per channel)
+                                 * since last emit */
+  gint interval_frames;         /* after how many frame to sent a message */
+  GstClockTime message_ts;      /* starttime for next message */
+
+  /* per-channel arrays for intermediate values */
+  gdouble *CS;                  /* normalized Cumulative Square */
+  gdouble *peak;                /* normalized Peak value over buffer */
+  gdouble *last_peak;           /* last normalized Peak value over interval */
+  gdouble *decay_peak;          /* running decaying normalized Peak */
+  gdouble *decay_peak_base;     /* value of last peak we are decaying from */
+  GstClockTime *decay_peak_age; /* age of last peak */
+
+  void (*process)(gpointer, guint, guint, gdouble*, gdouble*);
+};
+
+struct _GstLevelClass {
+  GstBaseTransformClass parent_class;
+};
+
+GType gst_level_get_type (void);
+
+
+G_END_DECLS
+
+
+#endif /* __GST_LEVEL_H__ */
diff --git a/gst/level/meson.build b/gst/level/meson.build
new file mode 100644
index 0000000..24ac4c9
--- /dev/null
+++ b/gst/level/meson.build
@@ -0,0 +1,8 @@
+gstlevel = library('gstlevel',
+  'gstlevel.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstbase_dep, gstaudio_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/matroska/Makefile.am b/gst/matroska/Makefile.am
new file mode 100644
index 0000000..ade9865
--- /dev/null
+++ b/gst/matroska/Makefile.am
@@ -0,0 +1,43 @@
+plugin_LTLIBRARIES = libgstmatroska.la
+
+libgstmatroska_la_SOURCES = \
+	ebml-read.c \
+	ebml-write.c \
+	matroska.c \
+	matroska-demux.c \
+	matroska-parse.c \
+	matroska-ids.c \
+	matroska-mux.c \
+	matroska-read-common.c \
+	webm-mux.c \
+	lzo.c
+
+noinst_HEADERS = \
+	ebml-ids.h \
+	ebml-read.h \
+	ebml-write.h \
+	matroska-demux.h \
+	matroska-parse.h \
+	matroska-ids.h \
+	matroska-mux.h \
+	matroska-read-common.h \
+	webm-mux.h \
+	lzo.h
+
+libgstmatroska_la_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS)
+libgstmatroska_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) \
+	-lgstriff-@GST_API_VERSION@ \
+	-lgstaudio-@GST_API_VERSION@ \
+	-lgstvideo-@GST_API_VERSION@ \
+	-lgsttag-@GST_API_VERSION@ \
+	-lgstpbutils-@GST_API_VERSION@ \
+	$(GST_BASE_LIBS) \
+	$(GST_LIBS) \
+	$(ZLIB_LIBS) \
+	$(BZ2_LIBS) \
+	$(LIBM)
+libgstmatroska_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
diff --git a/gst/matroska/ebml-ids.h b/gst/matroska/ebml-ids.h
new file mode 100644
index 0000000..ef2e6cb
--- /dev/null
+++ b/gst/matroska/ebml-ids.h
@@ -0,0 +1,54 @@
+/* GStreamer EBML I/O
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * ebml-ids.h: definition of EBML data IDs
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_EBML_IDS_H__
+#define __GST_EBML_IDS_H__
+
+G_BEGIN_DECLS
+
+/* EBML version supported */
+#define GST_EBML_VERSION 1
+
+/* Unknown size (all bits set to 1) */
+#define GST_EBML_SIZE_UNKNOWN          G_GINT64_CONSTANT(0x00ffffffffffffff)
+
+/* top-level master-IDs */
+#define GST_EBML_ID_HEADER             0x1A45DFA3
+
+/* IDs in the HEADER master */
+#define GST_EBML_ID_EBMLVERSION        0x4286
+#define GST_EBML_ID_EBMLREADVERSION    0x42F7
+#define GST_EBML_ID_EBMLMAXIDLENGTH    0x42F2
+#define GST_EBML_ID_EBMLMAXSIZELENGTH  0x42F3
+#define GST_EBML_ID_DOCTYPE            0x4282
+#define GST_EBML_ID_DOCTYPEVERSION     0x4287
+#define GST_EBML_ID_DOCTYPEREADVERSION 0x4285
+
+/* general EBML types */
+#define GST_EBML_ID_VOID               0xEC
+#define GST_EBML_ID_CRC32              0xBF
+
+/* EbmlDate offset from the unix epoch in seconds, 2001/01/01 00:00:00 UTC */
+#define GST_EBML_DATE_OFFSET           978307200
+
+G_END_DECLS
+
+#endif /* __GST_EBML_IDS_H__ */
diff --git a/gst/matroska/ebml-read.c b/gst/matroska/ebml-read.c
new file mode 100644
index 0000000..64893f1
--- /dev/null
+++ b/gst/matroska/ebml-read.c
@@ -0,0 +1,669 @@
+/* GStreamer EBML I/O
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * ebml-read.c: read EBML data from file/stream
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "ebml-read.h"
+#include "ebml-ids.h"
+
+#include <gst/math-compat.h>
+
+GST_DEBUG_CATEGORY (ebmlread_debug);
+#define GST_CAT_DEFAULT ebmlread_debug
+
+/* Peeks following element id and element length in datastream provided
+ * by @peek with @ctx as user data.
+ * Returns GST_FLOW_EOS if not enough data to read id and length.
+ * Otherwise, @needed provides the prefix length (id + length), and
+ * @length provides element length.
+ *
+ * @object and @offset are provided for informative messaging/debug purposes.
+ */
+GstFlowReturn
+gst_ebml_peek_id_length (guint32 * _id, guint64 * _length, guint * _needed,
+    GstPeekData peek, gpointer * ctx, GstElement * el, guint64 offset)
+{
+  guint needed;
+  const guint8 *buf;
+  gint len_mask = 0x80, read = 1, n = 1, num_ffs = 0;
+  guint64 total;
+  guint8 b;
+  GstFlowReturn ret;
+
+  g_return_val_if_fail (_id != NULL, GST_FLOW_ERROR);
+  g_return_val_if_fail (_length != NULL, GST_FLOW_ERROR);
+  g_return_val_if_fail (_needed != NULL, GST_FLOW_ERROR);
+
+  /* well ... */
+  *_id = (guint32) GST_EBML_SIZE_UNKNOWN;
+  *_length = GST_EBML_SIZE_UNKNOWN;
+
+  /* read element id */
+  needed = 2;
+  ret = peek (ctx, needed, &buf);
+  if (ret != GST_FLOW_OK)
+    goto peek_error;
+  b = GST_READ_UINT8 (buf);
+  total = (guint64) b;
+  while (read <= 4 && !(total & len_mask)) {
+    read++;
+    len_mask >>= 1;
+  }
+  if (G_UNLIKELY (read > 4))
+    goto invalid_id;
+
+  /* need id and at least something for subsequent length */
+  needed = read + 1;
+  ret = peek (ctx, needed, &buf);
+  if (ret != GST_FLOW_OK)
+    goto peek_error;
+  while (n < read) {
+    b = GST_READ_UINT8 (buf + n);
+    total = (total << 8) | b;
+    ++n;
+  }
+  *_id = (guint32) total;
+
+  /* read element length */
+  b = GST_READ_UINT8 (buf + n);
+  total = (guint64) b;
+  len_mask = 0x80;
+  read = 1;
+  while (read <= 8 && !(total & len_mask)) {
+    read++;
+    len_mask >>= 1;
+  }
+  if (G_UNLIKELY (read > 8))
+    goto invalid_length;
+  if ((total &= (len_mask - 1)) == len_mask - 1)
+    num_ffs++;
+
+  needed += read - 1;
+  ret = peek (ctx, needed, &buf);
+  if (ret != GST_FLOW_OK)
+    goto peek_error;
+  buf += (needed - read);
+  n = 1;
+  while (n < read) {
+    guint8 b = GST_READ_UINT8 (buf + n);
+
+    if (G_UNLIKELY (b == 0xff))
+      num_ffs++;
+    total = (total << 8) | b;
+    ++n;
+  }
+
+  if (G_UNLIKELY (read == num_ffs))
+    *_length = G_MAXUINT64;
+  else
+    *_length = total;
+
+  *_needed = needed;
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+peek_error:
+  {
+    if (ret != GST_FLOW_FLUSHING && ret != GST_FLOW_EOS)
+      GST_WARNING_OBJECT (el, "peek failed, ret = %s", gst_flow_get_name (ret));
+    else
+      GST_DEBUG_OBJECT (el, "peek failed, ret = %s", gst_flow_get_name (ret));
+    *_needed = needed;
+    return ret;
+  }
+invalid_id:
+  {
+    GST_ERROR_OBJECT (el,
+        "Invalid EBML ID size tag (0x%x) at position %" G_GUINT64_FORMAT " (0x%"
+        G_GINT64_MODIFIER "x)", (guint) b, offset, offset);
+    return GST_FLOW_ERROR;
+  }
+invalid_length:
+  {
+    GST_ERROR_OBJECT (el,
+        "Invalid EBML length size tag (0x%x) at position %" G_GUINT64_FORMAT
+        " (0x%" G_GINT64_MODIFIER "x)", (guint) b, offset, offset);
+    return GST_FLOW_ERROR;
+  }
+}
+
+/* setup for parsing @buf at position @offset on behalf of @el.
+ * Takes ownership of @buf. */
+void
+gst_ebml_read_init (GstEbmlRead * ebml, GstElement * el, GstBuffer * buf,
+    guint64 offset)
+{
+  GstEbmlMaster m;
+
+  g_return_if_fail (el);
+  g_return_if_fail (buf);
+
+  ebml->el = el;
+  ebml->offset = offset;
+  ebml->buf = buf;
+  gst_buffer_map (buf, &ebml->map, GST_MAP_READ);
+  ebml->readers = g_array_sized_new (FALSE, FALSE, sizeof (GstEbmlMaster), 10);
+  m.offset = ebml->offset;
+  gst_byte_reader_init (&m.br, ebml->map.data, ebml->map.size);
+  g_array_append_val (ebml->readers, m);
+}
+
+void
+gst_ebml_read_clear (GstEbmlRead * ebml)
+{
+  if (ebml->readers)
+    g_array_free (ebml->readers, TRUE);
+  ebml->readers = NULL;
+  if (ebml->buf) {
+    gst_buffer_unmap (ebml->buf, &ebml->map);
+    gst_buffer_unref (ebml->buf);
+  }
+  ebml->buf = NULL;
+  ebml->el = NULL;
+}
+
+static GstFlowReturn
+gst_ebml_read_peek (GstByteReader * br, guint peek, const guint8 ** data)
+{
+  if (G_LIKELY (gst_byte_reader_peek_data (br, peek, data)))
+    return GST_FLOW_OK;
+  else
+    return GST_FLOW_EOS;
+}
+
+static GstFlowReturn
+gst_ebml_peek_id_full (GstEbmlRead * ebml, guint32 * id, guint64 * length,
+    guint * prefix)
+{
+  GstFlowReturn ret;
+
+  ret = gst_ebml_peek_id_length (id, length, prefix,
+      (GstPeekData) gst_ebml_read_peek, (gpointer) gst_ebml_read_br (ebml),
+      ebml->el, gst_ebml_read_get_pos (ebml));
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  GST_LOG_OBJECT (ebml->el, "id 0x%x at offset 0x%" G_GINT64_MODIFIER "x"
+      " of length %" G_GUINT64_FORMAT ", prefix %d", *id,
+      gst_ebml_read_get_pos (ebml), *length, *prefix);
+
+#ifndef GST_DISABLE_GST_DEBUG
+  if (ebmlread_debug->threshold >= GST_LEVEL_LOG) {
+    const guint8 *data = NULL;
+    GstByteReader *br = gst_ebml_read_br (ebml);
+    guint size = gst_byte_reader_get_remaining (br);
+
+    if (gst_byte_reader_peek_data (br, size, &data)) {
+
+      GST_LOG_OBJECT (ebml->el, "current br %p; remaining %d", br, size);
+      if (data)
+        GST_MEMDUMP_OBJECT (ebml->el, "element", data, MIN (size, *length));
+    }
+  }
+#endif
+
+  return ret;
+}
+
+GstFlowReturn
+gst_ebml_peek_id (GstEbmlRead * ebml, guint32 * id)
+{
+  guint64 length;
+  guint needed;
+
+  return gst_ebml_peek_id_full (ebml, id, &length, &needed);
+}
+
+/*
+ * Read the next element, the contents are supposed to be sub-elements which
+ * can be read separately.  A new bytereader is setup for doing so.
+ */
+GstFlowReturn
+gst_ebml_read_master (GstEbmlRead * ebml, guint32 * id)
+{
+  guint64 length;
+  guint prefix;
+  const guint8 *data = NULL;
+  GstFlowReturn ret;
+  GstEbmlMaster m;
+
+  ret = gst_ebml_peek_id_full (ebml, id, &length, &prefix);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  /* we just at least peeked the id */
+  if (!gst_byte_reader_skip (gst_ebml_read_br (ebml), prefix))
+    return GST_FLOW_ERROR;      /* FIXME: do proper error handling */
+
+  m.offset = gst_ebml_read_get_pos (ebml);
+  if (!gst_byte_reader_get_data (gst_ebml_read_br (ebml), length, &data))
+    return GST_FLOW_PARSE;
+
+  GST_LOG_OBJECT (ebml->el, "pushing level %d at offset %" G_GUINT64_FORMAT,
+      ebml->readers->len, m.offset);
+  gst_byte_reader_init (&m.br, data, length);
+  g_array_append_val (ebml->readers, m);
+
+  return GST_FLOW_OK;
+}
+
+/* explicitly pop a bytereader from stack.  Usually invoked automagically. */
+GstFlowReturn
+gst_ebml_read_pop_master (GstEbmlRead * ebml)
+{
+  g_return_val_if_fail (ebml->readers, GST_FLOW_ERROR);
+
+  /* never remove initial bytereader */
+  if (ebml->readers->len > 1) {
+    GST_LOG_OBJECT (ebml->el, "popping level %d", ebml->readers->len - 1);
+    g_array_remove_index (ebml->readers, ebml->readers->len - 1);
+  }
+
+  return GST_FLOW_OK;
+}
+
+/*
+ * Skip the next element.
+ */
+
+GstFlowReturn
+gst_ebml_read_skip (GstEbmlRead * ebml)
+{
+  guint64 length;
+  guint32 id;
+  guint prefix;
+  GstFlowReturn ret;
+
+  ret = gst_ebml_peek_id_full (ebml, &id, &length, &prefix);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  if (!gst_byte_reader_skip (gst_ebml_read_br (ebml), length + prefix))
+    return GST_FLOW_PARSE;
+
+  return ret;
+}
+
+/*
+ * Read the next element as a GstBuffer (binary).
+ */
+
+GstFlowReturn
+gst_ebml_read_buffer (GstEbmlRead * ebml, guint32 * id, GstBuffer ** buf)
+{
+  guint64 length;
+  guint prefix;
+  GstFlowReturn ret;
+
+  ret = gst_ebml_peek_id_full (ebml, id, &length, &prefix);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  /* we just at least peeked the id */
+  if (!gst_byte_reader_skip (gst_ebml_read_br (ebml), prefix))
+    return GST_FLOW_ERROR;      /* FIXME: do proper error handling */
+
+  if (G_LIKELY (length > 0)) {
+    guint offset;
+
+    offset = gst_ebml_read_get_pos (ebml) - ebml->offset;
+    if (G_LIKELY (gst_byte_reader_skip (gst_ebml_read_br (ebml), length))) {
+      *buf = gst_buffer_copy_region (ebml->buf, GST_BUFFER_COPY_ALL,
+          offset, length);
+    } else {
+      *buf = NULL;
+      return GST_FLOW_PARSE;
+    }
+  } else {
+    *buf = gst_buffer_new ();
+  }
+
+  return ret;
+}
+
+/*
+ * Read the next element, return a pointer to it and its size.
+ */
+
+static GstFlowReturn
+gst_ebml_read_bytes (GstEbmlRead * ebml, guint32 * id, const guint8 ** data,
+    guint * size)
+{
+  guint64 length;
+  guint prefix;
+  GstFlowReturn ret;
+
+  *size = 0;
+
+  ret = gst_ebml_peek_id_full (ebml, id, &length, &prefix);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  /* we just at least peeked the id */
+  if (!gst_byte_reader_skip (gst_ebml_read_br (ebml), prefix))
+    return GST_FLOW_ERROR;      /* FIXME: do proper error handling */
+
+  *data = NULL;
+  if (G_LIKELY (length > 0)) {
+    if (!gst_byte_reader_get_data (gst_ebml_read_br (ebml), length, data))
+      return GST_FLOW_PARSE;
+  }
+
+  *size = length;
+
+  return ret;
+}
+
+/*
+ * Read the next element as an unsigned int.
+ */
+
+GstFlowReturn
+gst_ebml_read_uint (GstEbmlRead * ebml, guint32 * id, guint64 * num)
+{
+  const guint8 *data;
+  guint size;
+  GstFlowReturn ret;
+
+  ret = gst_ebml_read_bytes (ebml, id, &data, &size);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  if (size > 8) {
+    GST_ERROR_OBJECT (ebml->el,
+        "Invalid integer element size %d at position %" G_GUINT64_FORMAT " (0x%"
+        G_GINT64_MODIFIER "x)", size, gst_ebml_read_get_pos (ebml) - size,
+        gst_ebml_read_get_pos (ebml) - size);
+    return GST_FLOW_ERROR;
+  }
+
+  if (size == 0) {
+    *num = 0;
+    return ret;
+  }
+
+  *num = 0;
+  while (size > 0) {
+    *num = (*num << 8) | *data;
+    size--;
+    data++;
+  }
+
+  return ret;
+}
+
+/*
+ * Read the next element as a signed int.
+ */
+
+GstFlowReturn
+gst_ebml_read_sint (GstEbmlRead * ebml, guint32 * id, gint64 * num)
+{
+  const guint8 *data;
+  guint size;
+  gboolean negative = 0;
+  GstFlowReturn ret;
+
+  ret = gst_ebml_read_bytes (ebml, id, &data, &size);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  if (size > 8) {
+    GST_ERROR_OBJECT (ebml->el,
+        "Invalid integer element size %d at position %" G_GUINT64_FORMAT " (0x%"
+        G_GINT64_MODIFIER "x)", size, gst_ebml_read_get_pos (ebml) - size,
+        gst_ebml_read_get_pos (ebml) - size);
+    return GST_FLOW_ERROR;
+  }
+
+  if (size == 0) {
+    *num = 0;
+    return ret;
+  }
+
+  *num = 0;
+  if (*data & 0x80) {
+    negative = 1;
+    *num = *data & ~0x80;
+    size--;
+    data++;
+  }
+
+  while (size > 0) {
+    *num = (*num << 8) | *data;
+    size--;
+    data++;
+  }
+
+  /* make signed */
+  if (negative) {
+    *num = 0 - *num;
+  }
+
+  return ret;
+}
+
+/* Convert 80 bit extended precision float in big endian format to double.
+ * Code taken from libavutil/intfloat_readwrite.c from ffmpeg,
+ * licensed under LGPL */
+
+struct _ext_float
+{
+  guint8 exponent[2];
+  guint8 mantissa[8];
+};
+
+static gdouble
+_ext2dbl (const guint8 * data)
+{
+  struct _ext_float ext;
+  guint64 m = 0;
+  gint e, i;
+
+  memcpy (&ext.exponent, data, 2);
+  memcpy (&ext.mantissa, data + 2, 8);
+
+  for (i = 0; i < 8; i++)
+    m = (m << 8) + ext.mantissa[i];
+  e = (((gint) ext.exponent[0] & 0x7f) << 8) | ext.exponent[1];
+  if (e == 0x7fff && m)
+    return NAN;
+  e -= 16383 + 63;              /* In IEEE 80 bits, the whole (i.e. 1.xxxx)
+                                 * mantissa bit is written as opposed to the
+                                 * single and double precision formats */
+  if (ext.exponent[0] & 0x80)
+    m = -m;
+  return ldexp (m, e);
+}
+
+/*
+ * Read the next element as a float.
+ */
+
+GstFlowReturn
+gst_ebml_read_float (GstEbmlRead * ebml, guint32 * id, gdouble * num)
+{
+  const guint8 *data;
+  guint size;
+  GstFlowReturn ret;
+
+  ret = gst_ebml_read_bytes (ebml, id, &data, &size);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  if (size != 0 && size != 4 && size != 8 && size != 10) {
+    GST_ERROR_OBJECT (ebml->el,
+        "Invalid float element size %d at position %" G_GUINT64_FORMAT " (0x%"
+        G_GINT64_MODIFIER "x)", size, gst_ebml_read_get_pos (ebml) - size,
+        gst_ebml_read_get_pos (ebml) - size);
+    return GST_FLOW_ERROR;
+  }
+
+  if (size == 4) {
+    gfloat f;
+
+    memcpy (&f, data, 4);
+    f = GFLOAT_FROM_BE (f);
+
+    *num = f;
+  } else if (size == 8) {
+    gdouble d;
+
+    memcpy (&d, data, 8);
+    d = GDOUBLE_FROM_BE (d);
+
+    *num = d;
+  } else if (size == 10) {
+    *num = _ext2dbl (data);
+  } else {
+    /* size == 0 means a value of 0.0 */
+    *num = 0.0;
+  }
+
+  return ret;
+}
+
+/*
+ * Read the next element as a C string.
+ */
+
+static GstFlowReturn
+gst_ebml_read_string (GstEbmlRead * ebml, guint32 * id, gchar ** str)
+{
+  const guint8 *data;
+  guint size;
+  GstFlowReturn ret;
+
+  ret = gst_ebml_read_bytes (ebml, id, &data, &size);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  *str = g_malloc (size + 1);
+  memcpy (*str, data, size);
+  (*str)[size] = '\0';
+
+  return ret;
+}
+
+/*
+ * Read the next element as an ASCII string.
+ */
+
+GstFlowReturn
+gst_ebml_read_ascii (GstEbmlRead * ebml, guint32 * id, gchar ** str_out)
+{
+  GstFlowReturn ret;
+  gchar *str;
+  gchar *iter;
+
+#ifndef GST_DISABLE_GST_DEBUG
+  guint64 oldoff = ebml->offset;
+#endif
+
+  ret = gst_ebml_read_string (ebml, id, &str);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  for (iter = str; *iter != '\0'; iter++) {
+    if (G_UNLIKELY (*iter & 0x80)) {
+      GST_ERROR_OBJECT (ebml,
+          "Invalid ASCII string at offset %" G_GUINT64_FORMAT, oldoff);
+      g_free (str);
+      return GST_FLOW_ERROR;
+    }
+  }
+
+  *str_out = str;
+  return ret;
+}
+
+/*
+ * Read the next element as a UTF-8 string.
+ */
+
+GstFlowReturn
+gst_ebml_read_utf8 (GstEbmlRead * ebml, guint32 * id, gchar ** str)
+{
+  GstFlowReturn ret;
+
+#ifndef GST_DISABLE_GST_DEBUG
+  guint64 oldoff = gst_ebml_read_get_pos (ebml);
+#endif
+
+  ret = gst_ebml_read_string (ebml, id, str);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  if (str != NULL && *str != NULL && **str != '\0' &&
+      !g_utf8_validate (*str, -1, NULL)) {
+    GST_WARNING_OBJECT (ebml->el,
+        "Invalid UTF-8 string at offset %" G_GUINT64_FORMAT, oldoff);
+  }
+
+  return ret;
+}
+
+/*
+ * Read the next element as a date.
+ * Returns the seconds since the unix epoch.
+ */
+
+GstFlowReturn
+gst_ebml_read_date (GstEbmlRead * ebml, guint32 * id, gint64 * date)
+{
+  gint64 ebml_date;
+  GstFlowReturn ret;
+
+  ret = gst_ebml_read_sint (ebml, id, &ebml_date);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  *date = (ebml_date / GST_SECOND) + GST_EBML_DATE_OFFSET;
+
+  return ret;
+}
+
+/*
+ * Read the next element as binary data.
+ */
+
+GstFlowReturn
+gst_ebml_read_binary (GstEbmlRead * ebml,
+    guint32 * id, guint8 ** binary, guint64 * length)
+{
+  const guint8 *data;
+  guint size;
+  GstFlowReturn ret;
+
+  ret = gst_ebml_read_bytes (ebml, id, &data, &size);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  *length = size;
+  *binary = g_memdup (data, size);
+
+  return GST_FLOW_OK;
+}
diff --git a/gst/matroska/ebml-read.h b/gst/matroska/ebml-read.h
new file mode 100644
index 0000000..ce894da
--- /dev/null
+++ b/gst/matroska/ebml-read.h
@@ -0,0 +1,171 @@
+/* GStreamer EBML I/O
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * ebml-read.c: read EBML data from file/stream
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_EBML_READ_H__
+#define __GST_EBML_READ_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbytereader.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_EBML_READ \
+  (gst_ebml_read_get_type ())
+#define GST_EBML_READ(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_EBML_READ, GstEbmlRead))
+#define GST_EBML_READ_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_EBML_READ, GstEbmlReadClass))
+#define GST_IS_EBML_READ(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_EBML_READ))
+#define GST_IS_EBML_READ_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_EBML_READ))
+#define GST_EBML_READ_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_EBML_READ, GstEbmlReadClass))
+
+GST_DEBUG_CATEGORY_EXTERN (ebmlread_debug);
+
+/* custom flow return code */
+#define  GST_FLOW_PARSE  GST_FLOW_CUSTOM_ERROR
+
+typedef struct _GstEbmlMaster {
+  guint64       offset;
+  GstByteReader br;
+} GstEbmlMaster;
+
+typedef struct _GstEbmlRead {
+  GstElement *el;
+
+  GstBuffer *buf;
+  guint64 offset;
+  GstMapInfo map;
+
+  GArray *readers;
+} GstEbmlRead;
+
+typedef GstFlowReturn (*GstPeekData) (gpointer * context, guint peek, const guint8 ** data);
+
+/* returns UNEXPECTED if not enough data */
+GstFlowReturn gst_ebml_peek_id_length    (guint32 * _id, guint64 * _length,
+                                          guint * _needed,
+                                          GstPeekData peek, gpointer * ctx,
+                                          GstElement * el, guint64 offset);
+
+void          gst_ebml_read_init         (GstEbmlRead * ebml,
+                                          GstElement * el, GstBuffer * buf,
+                                          guint64 offset);
+
+void          gst_ebml_read_clear        (GstEbmlRead * ebml);
+
+GstFlowReturn gst_ebml_peek_id           (GstEbmlRead * ebml, guint32 * id);
+
+/* return _PARSE if not enough data to read what is needed, _ERROR or _OK */
+GstFlowReturn gst_ebml_read_skip         (GstEbmlRead *ebml);
+
+GstFlowReturn gst_ebml_read_buffer       (GstEbmlRead *ebml,
+                                          guint32     *id,
+                                          GstBuffer  **buf);
+
+GstFlowReturn gst_ebml_read_uint         (GstEbmlRead *ebml,
+                                          guint32     *id,
+                                          guint64     *num);
+
+GstFlowReturn gst_ebml_read_sint         (GstEbmlRead *ebml,
+                                          guint32     *id,
+                                          gint64      *num);
+
+GstFlowReturn gst_ebml_read_float        (GstEbmlRead *ebml,
+                                          guint32     *id,
+                                          gdouble     *num);
+
+GstFlowReturn gst_ebml_read_ascii        (GstEbmlRead *ebml,
+                                          guint32     *id,
+                                          gchar      **str);
+
+GstFlowReturn gst_ebml_read_utf8         (GstEbmlRead *ebml,
+                                          guint32     *id,
+                                          gchar      **str);
+
+GstFlowReturn gst_ebml_read_date         (GstEbmlRead *ebml,
+                                          guint32     *id,
+                                          gint64      *date);
+
+GstFlowReturn gst_ebml_read_master       (GstEbmlRead *ebml,
+                                          guint32     *id);
+
+GstFlowReturn gst_ebml_read_pop_master   (GstEbmlRead *ebml);
+
+GstFlowReturn gst_ebml_read_binary       (GstEbmlRead *ebml,
+                                          guint32     *id,
+                                          guint8     **binary,
+                                          guint64     *length);
+
+GstFlowReturn gst_ebml_read_header       (GstEbmlRead *read,
+                                          gchar      **doctype,
+                                          guint       *version);
+
+/* Returns current (absolute) position of Ebml parser,
+ * i.e. taking into account offset provided at init */
+static inline guint64
+gst_ebml_read_get_pos (GstEbmlRead * ebml)
+{
+  GstEbmlMaster *m;
+
+  g_return_val_if_fail (ebml->readers, 0);
+  g_return_val_if_fail (ebml->readers->len, 0);
+
+  m = &(g_array_index (ebml->readers, GstEbmlMaster, ebml->readers->len - 1));
+  return m->offset + gst_byte_reader_get_pos (&m->br);
+}
+
+/* Returns starting offset of Ebml parser */
+static inline guint64
+gst_ebml_read_get_offset (GstEbmlRead * ebml)
+{
+  return ebml->offset;
+}
+
+static inline GstByteReader *
+gst_ebml_read_br (GstEbmlRead * ebml)
+{
+  g_return_val_if_fail (ebml->readers, NULL);
+  g_return_val_if_fail (ebml->readers->len, NULL);
+
+  return &(g_array_index (ebml->readers,
+          GstEbmlMaster, ebml->readers->len - 1).br);
+}
+
+static inline gboolean
+gst_ebml_read_has_remaining (GstEbmlRead * ebml, guint64 bytes_needed,
+    gboolean auto_pop)
+{
+  gboolean res;
+
+  res = (gst_byte_reader_get_remaining (gst_ebml_read_br (ebml)) >= bytes_needed);
+  if (G_LIKELY (!res && auto_pop)) {
+    gst_ebml_read_pop_master (ebml);
+  }
+
+  return G_LIKELY (res);
+}
+
+G_END_DECLS
+
+#endif /* __GST_EBML_READ_H__ */
diff --git a/gst/matroska/ebml-write.c b/gst/matroska/ebml-write.c
new file mode 100644
index 0000000..08e93bc
--- /dev/null
+++ b/gst/matroska/ebml-write.c
@@ -0,0 +1,941 @@
+/* GStreamer EBML I/O
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2005 Michal Benes <michal.benes@xeris.cz>
+ *
+ * ebml-write.c: write EBML data to file/stream
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "ebml-write.h"
+#include "ebml-ids.h"
+
+
+GST_DEBUG_CATEGORY_STATIC (gst_ebml_write_debug);
+#define GST_CAT_DEFAULT gst_ebml_write_debug
+
+#define _do_init \
+      GST_DEBUG_CATEGORY_INIT (gst_ebml_write_debug, "ebmlwrite", 0, "Write EBML structured data")
+#define parent_class gst_ebml_write_parent_class
+G_DEFINE_TYPE_WITH_CODE (GstEbmlWrite, gst_ebml_write, GST_TYPE_OBJECT,
+    _do_init);
+
+static void gst_ebml_write_finalize (GObject * object);
+
+static void
+gst_ebml_write_class_init (GstEbmlWriteClass * klass)
+{
+  GObjectClass *object = G_OBJECT_CLASS (klass);
+
+  object->finalize = gst_ebml_write_finalize;
+}
+
+static void
+gst_ebml_write_init (GstEbmlWrite * ebml)
+{
+  ebml->srcpad = NULL;
+  ebml->pos = 0;
+  ebml->last_pos = G_MAXUINT64; /* force segment event */
+
+  ebml->cache = NULL;
+  ebml->streamheader = NULL;
+  ebml->streamheader_pos = 0;
+  ebml->writing_streamheader = FALSE;
+  ebml->caps = NULL;
+}
+
+static void
+gst_ebml_write_finalize (GObject * object)
+{
+  GstEbmlWrite *ebml = GST_EBML_WRITE (object);
+
+  gst_object_unref (ebml->srcpad);
+
+  if (ebml->cache) {
+    gst_byte_writer_free (ebml->cache);
+    ebml->cache = NULL;
+  }
+
+  if (ebml->streamheader) {
+    gst_byte_writer_free (ebml->streamheader);
+    ebml->streamheader = NULL;
+  }
+
+  if (ebml->caps) {
+    gst_caps_unref (ebml->caps);
+    ebml->caps = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+/**
+ * gst_ebml_write_new:
+ * @srcpad: Source pad to which the output will be pushed.
+ *
+ * Creates a new #GstEbmlWrite.
+ *
+ * Returns: a new #GstEbmlWrite
+ */
+GstEbmlWrite *
+gst_ebml_write_new (GstPad * srcpad)
+{
+  GstEbmlWrite *ebml =
+      GST_EBML_WRITE (g_object_new (GST_TYPE_EBML_WRITE, NULL));
+
+  ebml->srcpad = gst_object_ref (srcpad);
+  ebml->timestamp = GST_CLOCK_TIME_NONE;
+
+  gst_ebml_write_reset (ebml);
+
+  return ebml;
+}
+
+
+/**
+ * gst_ebml_write_reset:
+ * @ebml: a #GstEbmlWrite.
+ *
+ * Reset internal state of #GstEbmlWrite.
+ */
+void
+gst_ebml_write_reset (GstEbmlWrite * ebml)
+{
+  ebml->pos = 0;
+  ebml->last_pos = G_MAXUINT64; /* force segment event */
+
+  if (ebml->cache) {
+    gst_byte_writer_free (ebml->cache);
+    ebml->cache = NULL;
+  }
+
+  if (ebml->caps) {
+    gst_caps_unref (ebml->caps);
+    ebml->caps = NULL;
+  }
+
+  ebml->last_write_result = GST_FLOW_OK;
+  ebml->timestamp = GST_CLOCK_TIME_NONE;
+}
+
+
+/**
+ * gst_ebml_last_write_result:
+ * @ebml: a #GstEbmlWrite.
+ *
+ * Returns: GST_FLOW_OK if there was not write error since the last call of
+ *          gst_ebml_last_write_result or code of the error.
+ */
+GstFlowReturn
+gst_ebml_last_write_result (GstEbmlWrite * ebml)
+{
+  GstFlowReturn res = ebml->last_write_result;
+
+  ebml->last_write_result = GST_FLOW_OK;
+
+  return res;
+}
+
+
+void
+gst_ebml_start_streamheader (GstEbmlWrite * ebml)
+{
+  g_return_if_fail (ebml->streamheader == NULL);
+
+  GST_DEBUG ("Starting streamheader at %" G_GUINT64_FORMAT, ebml->pos);
+  ebml->streamheader = gst_byte_writer_new_with_size (1000, FALSE);
+  ebml->streamheader_pos = ebml->pos;
+  ebml->writing_streamheader = TRUE;
+}
+
+GstBuffer *
+gst_ebml_stop_streamheader (GstEbmlWrite * ebml)
+{
+  GstBuffer *buffer;
+
+  if (!ebml->streamheader)
+    return NULL;
+
+  buffer = gst_byte_writer_free_and_get_buffer (ebml->streamheader);
+  ebml->streamheader = NULL;
+  GST_DEBUG ("Streamheader was size %" G_GSIZE_FORMAT,
+      gst_buffer_get_size (buffer));
+
+  ebml->writing_streamheader = FALSE;
+  return buffer;
+}
+
+/**
+ * gst_ebml_write_set_cache:
+ * @ebml: a #GstEbmlWrite.
+ * @size: size of the cache.
+ * Create a cache.
+ *
+ * The idea is that you use this for writing a lot
+ * of small elements. This will just "queue" all of
+ * them and they'll be pushed to the next element all
+ * at once. This saves memory and time for buffer
+ * allocation and init, and it looks better.
+ */
+void
+gst_ebml_write_set_cache (GstEbmlWrite * ebml, guint size)
+{
+  g_return_if_fail (ebml->cache == NULL);
+
+  GST_DEBUG ("Starting cache at %" G_GUINT64_FORMAT, ebml->pos);
+  ebml->cache = gst_byte_writer_new_with_size (size, FALSE);
+  ebml->cache_pos = ebml->pos;
+}
+
+static gboolean
+gst_ebml_writer_send_segment_event (GstEbmlWrite * ebml, guint64 new_pos)
+{
+  GstSegment segment;
+  gboolean res;
+
+  GST_INFO ("seeking to %" G_GUINT64_FORMAT, new_pos);
+
+  gst_segment_init (&segment,
+      ebml->streamable ? GST_FORMAT_TIME : GST_FORMAT_BYTES);
+  segment.start = new_pos;
+  segment.stop = -1;
+  segment.position = 0;
+
+  res = gst_pad_push_event (ebml->srcpad, gst_event_new_segment (&segment));
+
+  if (!res)
+    GST_WARNING ("seek to %" G_GUINT64_FORMAT "failed", new_pos);
+
+  return res;
+}
+
+/**
+ * gst_ebml_write_flush_cache:
+ * @ebml:      a #GstEbmlWrite.
+ * @timestamp: timestamp of the buffer.
+ *
+ * Flush the cache.
+ */
+void
+gst_ebml_write_flush_cache (GstEbmlWrite * ebml, gboolean is_keyframe,
+    GstClockTime timestamp)
+{
+  GstBuffer *buffer;
+
+  if (!ebml->cache)
+    return;
+
+  buffer = gst_byte_writer_free_and_get_buffer (ebml->cache);
+  ebml->cache = NULL;
+  GST_DEBUG ("Flushing cache of size %" G_GSIZE_FORMAT,
+      gst_buffer_get_size (buffer));
+  GST_BUFFER_TIMESTAMP (buffer) = timestamp;
+  GST_BUFFER_OFFSET (buffer) = ebml->pos - gst_buffer_get_size (buffer);
+  GST_BUFFER_OFFSET_END (buffer) = ebml->pos;
+  if (ebml->last_write_result == GST_FLOW_OK) {
+    if (GST_BUFFER_OFFSET (buffer) != ebml->last_pos) {
+      gst_ebml_writer_send_segment_event (ebml, GST_BUFFER_OFFSET (buffer));
+      GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
+    } else {
+      GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
+    }
+    if (ebml->writing_streamheader) {
+      GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_HEADER);
+    } else {
+      GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_HEADER);
+    }
+    if (!is_keyframe) {
+      GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
+    }
+    ebml->last_pos = ebml->pos;
+    ebml->last_write_result = gst_pad_push (ebml->srcpad, buffer);
+  } else {
+    gst_buffer_unref (buffer);
+  }
+}
+
+
+/**
+ * gst_ebml_write_element_new:
+ * @ebml: a #GstEbmlWrite.
+ * @size: size of the requested buffer.
+ *
+ * Create a buffer for one element. If there is
+ * a cache, use that instead.
+ *
+ * Returns: A new #GstBuffer.
+ */
+static GstBuffer *
+gst_ebml_write_element_new (GstEbmlWrite * ebml, GstMapInfo * map, guint size)
+{
+  /* Create new buffer of size + ID + length */
+  GstBuffer *buf;
+
+  /* length, ID */
+  size += 12;
+
+  buf = gst_buffer_new_and_alloc (size);
+  GST_BUFFER_TIMESTAMP (buf) = ebml->timestamp;
+
+  /* FIXME unmap not possible */
+  gst_buffer_map (buf, map, GST_MAP_WRITE);
+
+  return buf;
+}
+
+
+/**
+ * gst_ebml_write_element_id:
+ * @data_inout: Pointer to data pointer
+ * @id: Element ID that should be written.
+ * 
+ * Write element ID into a buffer.
+ */
+static void
+gst_ebml_write_element_id (guint8 ** data_inout, guint32 id)
+{
+  guint8 *data = *data_inout;
+  guint bytes = 4, mask = 0x10;
+
+  /* get ID length */
+  while (!(id & (mask << ((bytes - 1) * 8))) && bytes > 0) {
+    mask <<= 1;
+    bytes--;
+  }
+
+  /* if invalid ID, use dummy */
+  if (bytes == 0) {
+    GST_WARNING ("Invalid ID, voiding");
+    bytes = 1;
+    id = GST_EBML_ID_VOID;
+  }
+
+  /* write out, BE */
+  *data_inout += bytes;
+  while (bytes--) {
+    data[bytes] = id & 0xff;
+    id >>= 8;
+  }
+}
+
+
+/**
+ * gst_ebml_write_element_size:
+ * @data_inout: Pointer to data pointer
+ * @size: Element length.
+ *
+ * Write element length into a buffer.
+ */
+static void
+gst_ebml_write_element_size (guint8 ** data_inout, guint64 size)
+{
+  guint8 *data = *data_inout;
+  guint bytes = 1, mask = 0x80;
+
+  if (size != GST_EBML_SIZE_UNKNOWN) {
+    /* how many bytes? - use mask-1 because an all-1 bitset is not allowed */
+    while (bytes <= 8 && (size >> ((bytes - 1) * 8)) >= (mask - 1)) {
+      mask >>= 1;
+      bytes++;
+    }
+
+    /* if invalid size, use max. */
+    if (bytes > 8) {
+      GST_WARNING ("Invalid size, writing size unknown");
+      mask = 0x01;
+      bytes = 8;
+      /* Now here's a real FIXME: we cannot read those yet! */
+      size = GST_EBML_SIZE_UNKNOWN;
+    }
+  } else {
+    mask = 0x01;
+    bytes = 8;
+  }
+
+  /* write out, BE, with length size marker */
+  *data_inout += bytes;
+  while (bytes-- > 0) {
+    data[bytes] = size & 0xff;
+    size >>= 8;
+    if (!bytes)
+      *data |= mask;
+  }
+}
+
+
+/**
+ * gst_ebml_write_element_data:
+ * @data_inout: Pointer to data pointer
+ * @write: Data that should be written.
+ * @length: Length of the data.
+ *
+ * Write element data into a buffer.
+ */
+static void
+gst_ebml_write_element_data (guint8 ** data_inout, guint8 * write,
+    guint64 length)
+{
+  memcpy (*data_inout, write, length);
+  *data_inout += length;
+}
+
+
+/**
+ * gst_ebml_write_element_push:
+ * @ebml: #GstEbmlWrite
+ * @buf: #GstBuffer to be written.
+ * @buf_data: Start of data to push from @buf (or NULL for whole buffer).
+ * @buf_data_end: Data pointer positioned after the last byte in @buf_data (or
+ * NULL for whole buffer).
+ * 
+ * Write out buffer by moving it to the next element.
+ */
+static void
+gst_ebml_write_element_push (GstEbmlWrite * ebml, GstBuffer * buf,
+    guint8 * buf_data, guint8 * buf_data_end)
+{
+  GstMapInfo map;
+  guint data_size;
+
+  map.data = NULL;
+
+  if (buf_data_end)
+    data_size = buf_data_end - buf_data;
+  else
+    data_size = gst_buffer_get_size (buf);
+
+  ebml->pos += data_size;
+
+  /* if there's no cache, then don't push it! */
+  if (ebml->writing_streamheader) {
+    if (!buf_data) {
+      gst_buffer_map (buf, &map, GST_MAP_READ);
+      buf_data = map.data;
+    }
+    if (!buf_data)
+      GST_WARNING ("Failed to map buffer");
+    else if (!gst_byte_writer_put_data (ebml->streamheader, buf_data,
+            data_size))
+      GST_WARNING ("Error writing data to streamheader");
+  }
+  if (ebml->cache) {
+    if (!buf_data) {
+      gst_buffer_map (buf, &map, GST_MAP_READ);
+      buf_data = map.data;
+    }
+    if (!buf_data)
+      GST_WARNING ("Failed to map buffer");
+    else if (!gst_byte_writer_put_data (ebml->cache, buf_data, data_size))
+      GST_WARNING ("Error writing data to cache");
+    if (map.data)
+      gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    return;
+  }
+
+  if (buf_data && map.data)
+    gst_buffer_unmap (buf, &map);
+
+  if (ebml->last_write_result == GST_FLOW_OK) {
+    buf = gst_buffer_make_writable (buf);
+    GST_BUFFER_OFFSET (buf) = ebml->pos - data_size;
+    GST_BUFFER_OFFSET_END (buf) = ebml->pos;
+    if (ebml->writing_streamheader) {
+      GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
+    } else {
+      GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_HEADER);
+    }
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+    if (GST_BUFFER_OFFSET (buf) != ebml->last_pos) {
+      gst_ebml_writer_send_segment_event (ebml, GST_BUFFER_OFFSET (buf));
+      GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+    } else {
+      GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
+    }
+    ebml->last_pos = ebml->pos;
+    ebml->last_write_result = gst_pad_push (ebml->srcpad, buf);
+  } else {
+    gst_buffer_unref (buf);
+  }
+}
+
+
+/**
+ * gst_ebml_write_seek:
+ * @ebml: #GstEbmlWrite
+ * @pos: Seek position.
+ * 
+ * Seek.
+ */
+void
+gst_ebml_write_seek (GstEbmlWrite * ebml, guint64 pos)
+{
+  if (ebml->writing_streamheader) {
+    GST_DEBUG ("wanting to seek to pos %" G_GUINT64_FORMAT, pos);
+    if (pos >= ebml->streamheader_pos &&
+        pos <= ebml->streamheader_pos + ebml->streamheader->parent.size) {
+      gst_byte_writer_set_pos (ebml->streamheader,
+          pos - ebml->streamheader_pos);
+      GST_DEBUG ("seeked in streamheader to position %" G_GUINT64_FORMAT,
+          pos - ebml->streamheader_pos);
+    } else {
+      GST_WARNING
+          ("we are writing streamheader still and seek is out of bounds");
+    }
+  }
+  /* Cache seeking. A bit dangerous, we assume the client writer
+   * knows what he's doing... */
+  if (ebml->cache) {
+    /* within bounds? */
+    if (pos >= ebml->cache_pos &&
+        pos <= ebml->cache_pos + ebml->cache->parent.size) {
+      GST_DEBUG ("seeking in cache to %" G_GUINT64_FORMAT, pos);
+      ebml->pos = pos;
+      gst_byte_writer_set_pos (ebml->cache, ebml->pos - ebml->cache_pos);
+      return;
+    } else {
+      GST_LOG ("Seek outside cache range. Clearing...");
+      gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
+    }
+  }
+
+  GST_INFO ("scheduling seek to %" G_GUINT64_FORMAT, pos);
+  ebml->pos = pos;
+}
+
+
+/**
+ * gst_ebml_write_get_uint_size:
+ * @num: Number to be encoded.
+ * 
+ * Get number of bytes needed to write a uint.
+ *
+ * Returns: Encoded uint length.
+ */
+static guint
+gst_ebml_write_get_uint_size (guint64 num)
+{
+  guint size = 1;
+
+  /* get size */
+  while (size < 8 && num >= (G_GINT64_CONSTANT (1) << (size * 8))) {
+    size++;
+  }
+
+  return size;
+}
+
+
+/**
+ * gst_ebml_write_set_uint:
+ * @data_inout: Pointer to data pointer
+ * @num: Number to be written.
+ * @size: Encoded number length.
+ *
+ * Write an uint into a buffer.
+ */
+static void
+gst_ebml_write_set_uint (guint8 ** data_inout, guint64 num, guint size)
+{
+  guint8 *data = *data_inout;
+
+  *data_inout += size;
+
+  while (size-- > 0) {
+    data[size] = num & 0xff;
+    num >>= 8;
+  }
+}
+
+
+/**
+ * gst_ebml_write_uint:
+ * @ebml: #GstEbmlWrite
+ * @id: Element ID.
+ * @num: Number to be written.
+ *
+ * Write uint element.
+ */
+void
+gst_ebml_write_uint (GstEbmlWrite * ebml, guint32 id, guint64 num)
+{
+  GstBuffer *buf;
+  guint8 *data_start, *data_end;
+  guint size = gst_ebml_write_get_uint_size (num);
+  GstMapInfo map;
+
+  buf = gst_ebml_write_element_new (ebml, &map, sizeof (num));
+  data_end = data_start = map.data;
+
+  /* write */
+  gst_ebml_write_element_id (&data_end, id);
+  gst_ebml_write_element_size (&data_end, size);
+  gst_ebml_write_set_uint (&data_end, num, size);
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_set_size (buf, (data_end - data_start));
+
+  gst_ebml_write_element_push (ebml, buf, data_start, data_end);
+}
+
+
+/**
+ * gst_ebml_write_sint:
+ * @ebml: #GstEbmlWrite
+ * @id: Element ID.
+ * @num: Number to be written.
+ *
+ * Write sint element.
+ */
+void
+gst_ebml_write_sint (GstEbmlWrite * ebml, guint32 id, gint64 num)
+{
+  GstBuffer *buf;
+  guint8 *data_start, *data_end;
+  GstMapInfo map;
+
+  /* if the signed number is on the edge of a extra-byte,
+   * then we'll fall over when detecting it. Example: if I
+   * have a number (-)0x8000 (G_MINSHORT), then my abs()<<1
+   * will be 0x10000; this is G_MAXUSHORT+1! So: if (<0) -1. */
+  guint64 unum = (num < 0 ? (-num - 1) << 1 : num << 1);
+  guint size = gst_ebml_write_get_uint_size (unum);
+
+  buf = gst_ebml_write_element_new (ebml, &map, sizeof (num));
+  data_end = data_start = map.data;
+
+  /* make unsigned */
+  if (num >= 0) {
+    unum = num;
+  } else {
+    unum = ((guint64) 0x80) << ((size - 1) * 8);
+    unum += num;
+    unum |= ((guint64) 0x80) << ((size - 1) * 8);
+  }
+
+  /* write */
+  gst_ebml_write_element_id (&data_end, id);
+  gst_ebml_write_element_size (&data_end, size);
+  gst_ebml_write_set_uint (&data_end, unum, size);
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_set_size (buf, (data_end - data_start));
+
+  gst_ebml_write_element_push (ebml, buf, data_start, data_end);
+}
+
+
+/**
+ * gst_ebml_write_float:
+ * @ebml: #GstEbmlWrite
+ * @id: Element ID.
+ * @num: Number to be written.
+ *
+ * Write float element.
+ */
+void
+gst_ebml_write_float (GstEbmlWrite * ebml, guint32 id, gdouble num)
+{
+  GstBuffer *buf;
+  GstMapInfo map;
+  guint8 *data_start, *data_end;
+
+  buf = gst_ebml_write_element_new (ebml, &map, sizeof (num));
+  data_end = data_start = map.data;
+
+  gst_ebml_write_element_id (&data_end, id);
+  gst_ebml_write_element_size (&data_end, 8);
+  num = GDOUBLE_TO_BE (num);
+  gst_ebml_write_element_data (&data_end, (guint8 *) & num, 8);
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_set_size (buf, (data_end - data_start));
+
+  gst_ebml_write_element_push (ebml, buf, data_start, data_end);
+}
+
+
+/**
+ * gst_ebml_write_ascii:
+ * @ebml: #GstEbmlWrite
+ * @id: Element ID.
+ * @str: String to be written.
+ *
+ * Write string element.
+ */
+void
+gst_ebml_write_ascii (GstEbmlWrite * ebml, guint32 id, const gchar * str)
+{
+  gint len = strlen (str) + 1;  /* add trailing '\0' */
+  GstBuffer *buf;
+  GstMapInfo map;
+  guint8 *data_start, *data_end;
+
+  buf = gst_ebml_write_element_new (ebml, &map, len);
+  data_end = data_start = map.data;
+
+  gst_ebml_write_element_id (&data_end, id);
+  gst_ebml_write_element_size (&data_end, len);
+  gst_ebml_write_element_data (&data_end, (guint8 *) str, len);
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_set_size (buf, (data_end - data_start));
+
+  gst_ebml_write_element_push (ebml, buf, data_start, data_end);
+}
+
+
+/**
+ * gst_ebml_write_utf8:
+ * @ebml: #GstEbmlWrite
+ * @id: Element ID.
+ * @str: String to be written.
+ *
+ * Write utf8 encoded string element.
+ */
+void
+gst_ebml_write_utf8 (GstEbmlWrite * ebml, guint32 id, const gchar * str)
+{
+  gst_ebml_write_ascii (ebml, id, str);
+}
+
+
+/**
+ * gst_ebml_write_date:
+ * @ebml: #GstEbmlWrite
+ * @id: Element ID.
+ * @date: Date in seconds since the unix epoch.
+ *
+ * Write date element.
+ */
+void
+gst_ebml_write_date (GstEbmlWrite * ebml, guint32 id, gint64 date)
+{
+  gst_ebml_write_sint (ebml, id, (date - GST_EBML_DATE_OFFSET) * GST_SECOND);
+}
+
+/**
+ * gst_ebml_write_master_start:
+ * @ebml: #GstEbmlWrite
+ * @id: Element ID.
+ *
+ * Start wiriting mater element.
+ *
+ * Master writing is annoying. We use a size marker of
+ * the max. allowed length, so that we can later fill it
+ * in validly. 
+ *
+ * Returns: Master starting position.
+ */
+guint64
+gst_ebml_write_master_start (GstEbmlWrite * ebml, guint32 id)
+{
+  guint64 pos = ebml->pos;
+  GstBuffer *buf;
+  GstMapInfo map;
+  guint8 *data_start, *data_end;
+
+  buf = gst_ebml_write_element_new (ebml, &map, 0);
+  data_end = data_start = map.data;
+
+  gst_ebml_write_element_id (&data_end, id);
+  pos += data_end - data_start;
+  gst_ebml_write_element_size (&data_end, GST_EBML_SIZE_UNKNOWN);
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_set_size (buf, (data_end - data_start));
+
+  gst_ebml_write_element_push (ebml, buf, data_start, data_end);
+
+  return pos;
+}
+
+
+/**
+ * gst_ebml_write_master_finish_full:
+ * @ebml: #GstEbmlWrite
+ * @startpos: Master starting position.
+ *
+ * Finish writing master element.  Size of master element is difference between
+ * current position and the element start, and @extra_size added to this.
+ */
+void
+gst_ebml_write_master_finish_full (GstEbmlWrite * ebml, guint64 startpos,
+    guint64 extra_size)
+{
+  guint64 pos = ebml->pos;
+  guint8 *data = g_malloc (8);
+  GstBuffer *buf = gst_buffer_new_wrapped (data, 8);
+
+  gst_ebml_write_seek (ebml, startpos);
+
+  GST_WRITE_UINT64_BE (data,
+      (G_GINT64_CONSTANT (1) << 56) | (pos - startpos - 8 + extra_size));
+
+  gst_ebml_write_element_push (ebml, buf, NULL, NULL);
+  gst_ebml_write_seek (ebml, pos);
+}
+
+void
+gst_ebml_write_master_finish (GstEbmlWrite * ebml, guint64 startpos)
+{
+  gst_ebml_write_master_finish_full (ebml, startpos, 0);
+}
+
+/**
+ * gst_ebml_write_binary:
+ * @ebml: #GstEbmlWrite
+ * @id: Element ID.
+ * @binary: Data to be written.
+ * @length: Length of the data
+ *
+ * Write an element with binary data.
+ */
+void
+gst_ebml_write_binary (GstEbmlWrite * ebml,
+    guint32 id, guint8 * binary, guint64 length)
+{
+  GstBuffer *buf;
+  GstMapInfo map;
+  guint8 *data_start, *data_end;
+
+  buf = gst_ebml_write_element_new (ebml, &map, length);
+  data_end = data_start = map.data;
+
+  gst_ebml_write_element_id (&data_end, id);
+  gst_ebml_write_element_size (&data_end, length);
+  gst_ebml_write_element_data (&data_end, binary, length);
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_set_size (buf, (data_end - data_start));
+
+  gst_ebml_write_element_push (ebml, buf, data_start, data_end);
+}
+
+
+/**
+ * gst_ebml_write_buffer_header:
+ * @ebml: #GstEbmlWrite
+ * @id: Element ID.
+ * @length: Length of the data
+ * 
+ * Write header of the binary element (use with gst_ebml_write_buffer function).
+ * 
+ * For things like video frames and audio samples,
+ * you want to use this function, as it doesn't have
+ * the overhead of memcpy() that other functions
+ * such as write_binary() do have.
+ */
+void
+gst_ebml_write_buffer_header (GstEbmlWrite * ebml, guint32 id, guint64 length)
+{
+  GstBuffer *buf;
+  GstMapInfo map;
+  guint8 *data_start, *data_end;
+
+  buf = gst_ebml_write_element_new (ebml, &map, 0);
+  data_end = data_start = map.data;
+
+  gst_ebml_write_element_id (&data_end, id);
+  gst_ebml_write_element_size (&data_end, length);
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_set_size (buf, (data_end - data_start));
+
+  gst_ebml_write_element_push (ebml, buf, data_start, data_end);
+}
+
+
+/**
+ * gst_ebml_write_buffer:
+ * @ebml: #GstEbmlWrite
+ * @buf: #GstBuffer cointaining the data.
+ *
+ * Write  binary element (see gst_ebml_write_buffer_header).
+ */
+void
+gst_ebml_write_buffer (GstEbmlWrite * ebml, GstBuffer * buf)
+{
+  gst_ebml_write_element_push (ebml, buf, NULL, NULL);
+}
+
+
+/**
+ * gst_ebml_replace_uint:
+ * @ebml: #GstEbmlWrite
+ * @pos: Position of the uint that should be replaced.
+ * @num: New value.
+ *
+ * Replace uint with a new value.
+ * 
+ * When replacing a uint, we assume that it is *always*
+ * 8-byte, since that's the safest guess we can do. This
+ * is just for simplicity.
+ *
+ * FIXME: this function needs to be replaced with something
+ * proper. This is a crude hack.
+ */
+void
+gst_ebml_replace_uint (GstEbmlWrite * ebml, guint64 pos, guint64 num)
+{
+  guint64 oldpos = ebml->pos;
+  guint8 *data_start, *data_end;
+  GstBuffer *buf;
+
+  data_start = g_malloc (8);
+  data_end = data_start;
+  buf = gst_buffer_new_wrapped (data_start, 8);
+
+  gst_ebml_write_seek (ebml, pos);
+  gst_ebml_write_set_uint (&data_end, num, 8);
+
+  gst_ebml_write_element_push (ebml, buf, data_start, data_end);
+  gst_ebml_write_seek (ebml, oldpos);
+}
+
+/**
+ * gst_ebml_write_header:
+ * @ebml: #GstEbmlWrite
+ * @doctype: Document type.
+ * @version: Document type version.
+ * 
+ * Write EBML header.
+ */
+void
+gst_ebml_write_header (GstEbmlWrite * ebml, const gchar * doctype,
+    guint version)
+{
+  guint64 pos;
+
+  /* write the basic EBML header */
+  gst_ebml_write_set_cache (ebml, 0x40);
+  pos = gst_ebml_write_master_start (ebml, GST_EBML_ID_HEADER);
+#if (GST_EBML_VERSION != 1)
+  gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLVERSION, GST_EBML_VERSION);
+  gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLREADVERSION, GST_EBML_VERSION);
+#endif
+#if 0
+  /* we don't write these until they're "non-default" (never!) */
+  gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLMAXIDLENGTH, sizeof (guint32));
+  gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLMAXSIZELENGTH, sizeof (guint64));
+#endif
+  gst_ebml_write_ascii (ebml, GST_EBML_ID_DOCTYPE, doctype);
+  gst_ebml_write_uint (ebml, GST_EBML_ID_DOCTYPEVERSION, version);
+  gst_ebml_write_uint (ebml, GST_EBML_ID_DOCTYPEREADVERSION, version);
+  gst_ebml_write_master_finish (ebml, pos);
+  gst_ebml_write_flush_cache (ebml, FALSE, 0);
+}
diff --git a/gst/matroska/ebml-write.h b/gst/matroska/ebml-write.h
new file mode 100644
index 0000000..c7143fe
--- /dev/null
+++ b/gst/matroska/ebml-write.h
@@ -0,0 +1,154 @@
+/* GStreamer EBML I/O
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2005 Michal Benes <michal.benes@xeris.cz>
+ *
+ * ebml-write.c: write EBML data to file/stream
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_EBML_WRITE_H__
+#define __GST_EBML_WRITE_H__
+
+#include <glib.h>
+#include <gst/gst.h>
+#include <gst/base/gstbytewriter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_EBML_WRITE \
+  (gst_ebml_write_get_type ())
+#define GST_EBML_WRITE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_EBML_WRITE, GstEbmlWrite))
+#define GST_EBML_WRITE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_EBML_WRITE, GstEbmlWriteClass))
+#define GST_IS_EBML_WRITE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_EBML_WRITE))
+#define GST_IS_EBML_WRITE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_EBML_WRITE))
+#define GST_EBML_WRITE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_EBML_WRITE, GstEbmlWriteClass))
+
+typedef struct _GstEbmlWrite {
+  GstObject object;
+
+  GstPad *srcpad;
+  guint64 pos;
+  guint64 last_pos;
+  GstClockTime timestamp;
+
+  GstByteWriter *cache;
+  guint64 cache_pos;
+
+  GstFlowReturn last_write_result;
+
+  gboolean writing_streamheader;
+  GstByteWriter *streamheader;
+  guint64 streamheader_pos;
+
+  GstCaps *caps;
+
+  gboolean streamable;
+} GstEbmlWrite;
+
+typedef struct _GstEbmlWriteClass {
+  GstObjectClass parent;
+} GstEbmlWriteClass;
+
+GType   gst_ebml_write_get_type      (void);
+
+GstEbmlWrite *gst_ebml_write_new     (GstPad *srcpad);
+void    gst_ebml_write_reset         (GstEbmlWrite *ebml);
+
+GstFlowReturn gst_ebml_last_write_result (GstEbmlWrite *ebml);
+
+/* Used to create streamheaders */
+void    gst_ebml_start_streamheader  (GstEbmlWrite *ebml);
+GstBuffer*    gst_ebml_stop_streamheader   (GstEbmlWrite *ebml);
+
+/*
+ * Caching means that we do not push one buffer for
+ * each element, but fill this one until a flush.
+ */
+void    gst_ebml_write_set_cache     (GstEbmlWrite *ebml,
+                                      guint         size);
+void    gst_ebml_write_flush_cache   (GstEbmlWrite *ebml,
+                                      gboolean is_keyframe,
+                                      GstClockTime timestamp);
+
+/*
+ * Seeking.
+ */
+void    gst_ebml_write_seek          (GstEbmlWrite *ebml,
+                                      guint64       pos);
+
+/*
+ * Data writing. 
+ */
+void    gst_ebml_write_uint          (GstEbmlWrite *ebml,
+                                      guint32       id,
+                                      guint64       num);
+void    gst_ebml_write_sint          (GstEbmlWrite *ebml,
+                                      guint32       id,
+                                      gint64        num);
+void    gst_ebml_write_float         (GstEbmlWrite *ebml,
+                                      guint32       id,
+                                      gdouble       num);
+void    gst_ebml_write_ascii         (GstEbmlWrite *ebml,
+                                      guint32       id,
+                                      const gchar  *str);
+void    gst_ebml_write_utf8          (GstEbmlWrite *ebml,
+                                      guint32       id,
+                                      const gchar  *str);
+void    gst_ebml_write_date          (GstEbmlWrite *ebml,
+                                      guint32       id,
+                                      gint64        date);
+guint64 gst_ebml_write_master_start  (GstEbmlWrite *ebml,
+                                      guint32       id);
+void    gst_ebml_write_master_finish (GstEbmlWrite *ebml,
+                                      guint64       startpos);
+void    gst_ebml_write_master_finish_full (GstEbmlWrite * ebml,
+                                      guint64 startpos,
+                                      guint64 extra_size);
+void    gst_ebml_write_binary        (GstEbmlWrite *ebml,
+                                      guint32       id,
+                                      guchar       *binary,
+                                      guint64       length);
+void    gst_ebml_write_header        (GstEbmlWrite *ebml,
+                                      const gchar  *doctype,
+                                      guint         version);
+
+/*
+ * Note: this is supposed to be used only for media data.
+ */
+void    gst_ebml_write_buffer_header (GstEbmlWrite *ebml,
+                                      guint32       id,
+                                      guint64       length);
+void    gst_ebml_write_buffer        (GstEbmlWrite *ebml,
+                                      GstBuffer    *data);
+
+/*
+ * A hack, basically... See matroska-mux.c. I should actually
+ * make a nice _replace_element_with_size() or so, but this
+ * works for now.
+ */
+void    gst_ebml_replace_uint        (GstEbmlWrite *ebml,
+                                      guint64       pos,
+                                      guint64       num);
+
+G_END_DECLS
+
+#endif /* __GST_EBML_WRITE_H__ */
diff --git a/gst/matroska/lzo.c b/gst/matroska/lzo.c
new file mode 100644
index 0000000..9d1e848
--- /dev/null
+++ b/gst/matroska/lzo.c
@@ -0,0 +1,292 @@
+/*
+ * LZO 1x decompression
+ * Copyright (c) 2006 Reimar Doeffinger
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <stdlib.h>
+#include <string.h>
+#include "lzo.h"
+
+/*! define if we may write up to 12 bytes beyond the output buffer */
+/* #define OUTBUF_PADDED 1 */
+/*! define if we may read up to 8 bytes beyond the input buffer */
+/* #define INBUF_PADDED 1 */
+typedef struct LZOContext
+{
+  const guint8 *in, *in_end;
+  guint8 *out_start, *out, *out_end;
+  int error;
+} LZOContext;
+
+/*
+ * \brief read one byte from input buffer, avoiding overrun
+ * \return byte read
+ */
+static inline int
+get_byte (LZOContext * c)
+{
+  if (c->in < c->in_end)
+    return *c->in++;
+  c->error |= LZO_INPUT_DEPLETED;
+  return 1;
+}
+
+#ifdef INBUF_PADDED
+#define GETB(c) (*(c).in++)
+#else
+#define GETB(c) get_byte(&(c))
+#endif
+
+/*
+ * \brief decode a length value in the coding used by lzo
+ * \param x previous byte value
+ * \param mask bits used from x
+ * \return decoded length value
+ */
+static inline int
+get_len (LZOContext * c, int x, int mask)
+{
+  int cnt = x & mask;
+  if (!cnt) {
+    while (!(x = get_byte (c)))
+      cnt += 255;
+    cnt += mask + x;
+  }
+  return cnt;
+}
+
+/*#define UNALIGNED_LOADSTORE */
+#define BUILTIN_MEMCPY
+#ifdef UNALIGNED_LOADSTORE
+#define COPY2(d, s) *(guint16 *)(d) = *(guint16 *)(s);
+#define COPY4(d, s) *(guint32 *)(d) = *(guint32 *)(s);
+#elif defined(BUILTIN_MEMCPY)
+#define COPY2(d, s) memcpy(d, s, 2);
+#define COPY4(d, s) memcpy(d, s, 4);
+#else
+#define COPY2(d, s) (d)[0] = (s)[0]; (d)[1] = (s)[1];
+#define COPY4(d, s) (d)[0] = (s)[0]; (d)[1] = (s)[1]; (d)[2] = (s)[2]; (d)[3] = (s)[3];
+#endif
+
+/*
+ * \brief copy bytes from input to output buffer with checking
+ * \param cnt number of bytes to copy, must be >= 0
+ */
+static inline void
+copy (LZOContext * c, int cnt)
+{
+  register const guint8 *src = c->in;
+  register guint8 *dst = c->out;
+  if (cnt > c->in_end - src) {
+    cnt = MAX (c->in_end - src, 0);
+    c->error |= LZO_INPUT_DEPLETED;
+  }
+  if (cnt > c->out_end - dst) {
+    cnt = MAX (c->out_end - dst, 0);
+    c->error |= LZO_OUTPUT_FULL;
+  }
+#if defined(INBUF_PADDED) && defined(OUTBUF_PADDED)
+  COPY4 (dst, src);
+  src += 4;
+  dst += 4;
+  cnt -= 4;
+  if (cnt > 0)
+#endif
+    memcpy (dst, src, cnt);
+  c->in = src + cnt;
+  c->out = dst + cnt;
+}
+
+/*
+ * \brief copy previously decoded bytes to current position
+ * \param back how many bytes back we start
+ * \param cnt number of bytes to copy, must be >= 0
+ *
+ * cnt > back is valid, this will copy the bytes we just copied,
+ * thus creating a repeating pattern with a period length of back.
+ */
+static inline void
+copy_backptr (LZOContext * c, int back, int cnt)
+{
+  register const guint8 *src = &c->out[-back];
+  register guint8 *dst = c->out;
+  if (src < c->out_start || src > dst) {
+    c->error |= LZO_INVALID_BACKPTR;
+    return;
+  }
+  if (cnt > c->out_end - dst) {
+    cnt = MAX (c->out_end - dst, 0);
+    c->error |= LZO_OUTPUT_FULL;
+  }
+  if (back == 1) {
+    memset (dst, *src, cnt);
+    dst += cnt;
+  } else {
+#ifdef OUTBUF_PADDED
+    COPY2 (dst, src);
+    COPY2 (dst + 2, src + 2);
+    src += 4;
+    dst += 4;
+    cnt -= 4;
+    if (cnt > 0) {
+      COPY2 (dst, src);
+      COPY2 (dst + 2, src + 2);
+      COPY2 (dst + 4, src + 4);
+      COPY2 (dst + 6, src + 6);
+      src += 8;
+      dst += 8;
+      cnt -= 8;
+    }
+#endif
+    if (cnt > 0) {
+      int blocklen = back;
+      while (cnt > blocklen) {
+        memcpy (dst, src, blocklen);
+        dst += blocklen;
+        cnt -= blocklen;
+        blocklen <<= 1;
+      }
+      memcpy (dst, src, cnt);
+    }
+    dst += cnt;
+  }
+  c->out = dst;
+}
+
+/*
+ * \brief decode LZO 1x compressed data
+ * \param out output buffer
+ * \param outlen size of output buffer, number of bytes left are returned here
+ * \param in input buffer
+ * \param inlen size of input buffer, number of bytes left are returned here
+ * \return 0 on success, otherwise error flags, see lzo.h
+ *
+ * make sure all buffers are appropriately padded, in must provide
+ * LZO_INPUT_PADDING, out must provide LZO_OUTPUT_PADDING additional bytes
+ */
+int
+lzo1x_decode (void *out, int *outlen, const void *in, int *inlen)
+{
+  int state = 0;
+  int x;
+  LZOContext c;
+  c.in = in;
+  c.in_end = (const guint8 *) in + *inlen;
+  c.out = c.out_start = out;
+  c.out_end = (guint8 *) out + *outlen;
+  c.error = 0;
+  x = GETB (c);
+  if (x > 17) {
+    copy (&c, x - 17);
+    x = GETB (c);
+    if (x < 16)
+      c.error |= LZO_ERROR;
+  }
+  if (c.in > c.in_end)
+    c.error |= LZO_INPUT_DEPLETED;
+  while (!c.error) {
+    int cnt, back;
+    if (x > 15) {
+      if (x > 63) {
+        cnt = (x >> 5) - 1;
+        back = (GETB (c) << 3) + ((x >> 2) & 7) + 1;
+      } else if (x > 31) {
+        cnt = get_len (&c, x, 31);
+        x = GETB (c);
+        back = (GETB (c) << 6) + (x >> 2) + 1;
+      } else {
+        cnt = get_len (&c, x, 7);
+        back = (1 << 14) + ((x & 8) << 11);
+        x = GETB (c);
+        back += (GETB (c) << 6) + (x >> 2);
+        if (back == (1 << 14)) {
+          if (cnt != 1)
+            c.error |= LZO_ERROR;
+          break;
+        }
+      }
+    } else if (!state) {
+      cnt = get_len (&c, x, 15);
+      copy (&c, cnt + 3);
+      x = GETB (c);
+      if (x > 15)
+        continue;
+      cnt = 1;
+      back = (1 << 11) + (GETB (c) << 2) + (x >> 2) + 1;
+    } else {
+      cnt = 0;
+      back = (GETB (c) << 2) + (x >> 2) + 1;
+    }
+    copy_backptr (&c, back, cnt + 2);
+    state = cnt = x & 3;
+    copy (&c, cnt);
+    x = GETB (c);
+  }
+  *inlen = c.in_end - c.in;
+  if (c.in > c.in_end)
+    *inlen = 0;
+  *outlen = c.out_end - c.out;
+  return c.error;
+}
+
+#ifdef TEST
+#include <stdio.h>
+#include <lzo/lzo1x.h>
+#include "log.h"
+#define MAXSZ (10*1024*1024)
+int
+main (int argc, char *argv[])
+{
+  FILE *in = fopen (argv[1], "rb");
+  guint8 *orig = av_malloc (MAXSZ + 16);
+  guint8 *comp = av_malloc (2 * MAXSZ + 16);
+  guint8 *decomp = av_malloc (MAXSZ + 16);
+  gsize s = fread (orig, 1, MAXSZ, in);
+  lzo_uint clen = 0;
+  long tmp[LZO1X_MEM_COMPRESS];
+  int inlen, outlen;
+  int i;
+  av_log_level = AV_LOG_DEBUG;
+  lzo1x_999_compress (orig, s, comp, &clen, tmp);
+  for (i = 0; i < 300; i++) {
+    START_TIMER inlen = clen;
+    outlen = MAXSZ;
+#ifdef LIBLZO
+    if (lzo1x_decompress_safe (comp, inlen, decomp, &outlen, NULL))
+#elif defined(LIBLZO_UNSAFE)
+    if (lzo1x_decompress (comp, inlen, decomp, &outlen, NULL))
+#else
+    if (lzo1x_decode (decomp, &outlen, comp, &inlen))
+#endif
+      av_log (NULL, AV_LOG_ERROR, "decompression error\n");
+    STOP_TIMER ("lzod")
+  }
+  if (memcmp (orig, decomp, s))
+    av_log (NULL, AV_LOG_ERROR, "decompression incorrect\n");
+  else
+    av_log (NULL, AV_LOG_ERROR, "decompression ok\n");
+
+  fclose (in);
+  return 0;
+}
+#endif
diff --git a/gst/matroska/lzo.h b/gst/matroska/lzo.h
new file mode 100644
index 0000000..e7795f7
--- /dev/null
+++ b/gst/matroska/lzo.h
@@ -0,0 +1,35 @@
+/*
+ * LZO 1x decompression
+ * copyright (c) 2006 Reimar Doeffinger
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FFMPEG_LZO_H
+#define FFMPEG_LZO_H
+
+#define LZO_INPUT_DEPLETED 1
+#define LZO_OUTPUT_FULL 2
+#define LZO_INVALID_BACKPTR 4
+#define LZO_ERROR 8
+
+#define LZO_INPUT_PADDING 8
+#define LZO_OUTPUT_PADDING 12
+
+int lzo1x_decode(void *out, int *outlen, const void *in, int *inlen);
+
+#endif /* FFMPEG_LZO_H */
diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c
new file mode 100644
index 0000000..f3bf763
--- /dev/null
+++ b/gst/matroska/matroska-demux.c
@@ -0,0 +1,6407 @@
+/* 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-demux.c: matroska file/stream demuxer
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* TODO: check CRC32 if present
+ * TODO: there can be a segment after the first segment. Handle like
+ *       chained oggs. Fixes #334082
+ * TODO: Test samples: http://www.matroska.org/samples/matrix/index.html
+ *                     http://samples.mplayerhq.hu/Matroska/
+ * TODO: check if demuxing is done correct for all codecs according to spec
+ * TODO: seeking with incomplete or without CUE
+ */
+
+/**
+ * SECTION:element-matroskademux
+ *
+ * matroskademux demuxes a Matroska file into the different contained streams.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v filesrc location=/path/to/mkv ! matroskademux ! vorbisdec ! audioconvert ! audioresample ! autoaudiosink
+ * ]| This pipeline demuxes a Matroska file and outputs the contained Vorbis audio.
+ * </refsect2>
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <string.h>
+#include <glib/gprintf.h>
+
+/* For AVI compatibility mode
+   and for fourcc stuff */
+#include <gst/riff/riff-read.h>
+#include <gst/riff/riff-ids.h>
+#include <gst/riff/riff-media.h>
+
+#include <gst/audio/audio.h>
+#include <gst/tag/tag.h>
+#include <gst/pbutils/pbutils.h>
+#include <gst/video/video.h>
+
+#include "matroska-demux.h"
+#include "matroska-ids.h"
+
+GST_DEBUG_CATEGORY_STATIC (matroskademux_debug);
+#define GST_CAT_DEFAULT matroskademux_debug
+
+#define DEBUG_ELEMENT_START(demux, ebml, element) \
+    GST_DEBUG_OBJECT (demux, "Parsing " element " element at offset %" \
+        G_GUINT64_FORMAT, gst_ebml_read_get_pos (ebml))
+
+#define DEBUG_ELEMENT_STOP(demux, ebml, element, ret) \
+    GST_DEBUG_OBJECT (demux, "Parsing " element " element " \
+        " finished with '%s'", gst_flow_get_name (ret))
+
+enum
+{
+  PROP_0,
+  PROP_METADATA,
+  PROP_STREAMINFO,
+  PROP_MAX_GAP_TIME
+};
+
+#define  DEFAULT_MAX_GAP_TIME      (2 * GST_SECOND)
+#define  INVALID_DATA_THRESHOLD    (2 * 1024 * 1024)
+
+static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-matroska; video/x-matroska; "
+        "video/x-matroska-3d; audio/webm; video/webm")
+    );
+
+/* TODO: fill in caps! */
+
+static GstStaticPadTemplate audio_src_templ =
+GST_STATIC_PAD_TEMPLATE ("audio_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("ANY")
+    );
+
+static GstStaticPadTemplate video_src_templ =
+GST_STATIC_PAD_TEMPLATE ("video_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("ANY")
+    );
+
+static GstStaticPadTemplate subtitle_src_templ =
+    GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("text/x-raw, format=pango-markup; application/x-ssa; "
+        "application/x-ass;application/x-usf; subpicture/x-dvd; "
+        "subpicture/x-pgs; subtitle/x-kate; " "application/x-subtitle-unknown")
+    );
+
+static GstFlowReturn gst_matroska_demux_parse_id (GstMatroskaDemux * demux,
+    guint32 id, guint64 length, guint needed);
+
+/* element functions */
+static void gst_matroska_demux_loop (GstPad * pad);
+
+static gboolean gst_matroska_demux_element_send_event (GstElement * element,
+    GstEvent * event);
+static gboolean gst_matroska_demux_element_query (GstElement * element,
+    GstQuery * query);
+
+/* pad functions */
+static gboolean gst_matroska_demux_sink_activate (GstPad * sinkpad,
+    GstObject * parent);
+static gboolean gst_matroska_demux_sink_activate_mode (GstPad * sinkpad,
+    GstObject * parent, GstPadMode mode, gboolean active);
+
+static gboolean gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
+    GstPad * pad, GstEvent * event);
+static gboolean gst_matroska_demux_handle_src_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static gboolean gst_matroska_demux_handle_src_query (GstPad * pad,
+    GstObject * parent, GstQuery * query);
+
+static gboolean gst_matroska_demux_handle_sink_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static GstFlowReturn gst_matroska_demux_chain (GstPad * pad,
+    GstObject * object, GstBuffer * buffer);
+
+static GstStateChangeReturn
+gst_matroska_demux_change_state (GstElement * element,
+    GstStateChange transition);
+#if 0
+static void
+gst_matroska_demux_set_index (GstElement * element, GstIndex * index);
+static GstIndex *gst_matroska_demux_get_index (GstElement * element);
+#endif
+
+/* caps functions */
+static GstCaps *gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext
+    * videocontext, const gchar * codec_id, guint8 * data, guint size,
+    gchar ** codec_name, guint32 * riff_fourcc);
+static GstCaps *gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext
+    * audiocontext, const gchar * codec_id, guint8 * data, guint size,
+    gchar ** codec_name, guint16 * riff_audio_fmt);
+static GstCaps
+    * gst_matroska_demux_subtitle_caps (GstMatroskaTrackSubtitleContext *
+    subtitlecontext, const gchar * codec_id, gpointer data, guint size);
+
+/* stream methods */
+static void gst_matroska_demux_reset (GstElement * element);
+static gboolean perform_seek_to_offset (GstMatroskaDemux * demux,
+    gdouble rate, guint64 offset, guint32 seqnum, GstSeekFlags flags);
+
+/* gobject functions */
+static void gst_matroska_demux_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_matroska_demux_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+GType gst_matroska_demux_get_type (void);
+#define parent_class gst_matroska_demux_parent_class
+G_DEFINE_TYPE (GstMatroskaDemux, gst_matroska_demux, GST_TYPE_ELEMENT);
+
+static void
+gst_matroska_demux_finalize (GObject * object)
+{
+  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (object);
+
+  gst_matroska_read_common_finalize (&demux->common);
+  gst_flow_combiner_free (demux->flowcombiner);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_matroska_demux_class_init (GstMatroskaDemuxClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (matroskademux_debug, "matroskademux", 0,
+      "Matroska demuxer");
+
+  gobject_class->finalize = gst_matroska_demux_finalize;
+
+  gobject_class->get_property = gst_matroska_demux_get_property;
+  gobject_class->set_property = gst_matroska_demux_set_property;
+
+  g_object_class_install_property (gobject_class, PROP_MAX_GAP_TIME,
+      g_param_spec_uint64 ("max-gap-time", "Maximum gap time",
+          "The demuxer sends out segment events for skipping "
+          "gaps longer than this (0 = disabled).", 0, G_MAXUINT64,
+          DEFAULT_MAX_GAP_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_matroska_demux_change_state);
+  gstelement_class->send_event =
+      GST_DEBUG_FUNCPTR (gst_matroska_demux_element_send_event);
+  gstelement_class->query =
+      GST_DEBUG_FUNCPTR (gst_matroska_demux_element_query);
+#if 0
+  gstelement_class->set_index =
+      GST_DEBUG_FUNCPTR (gst_matroska_demux_set_index);
+  gstelement_class->get_index =
+      GST_DEBUG_FUNCPTR (gst_matroska_demux_get_index);
+#endif
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &video_src_templ);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &audio_src_templ);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &subtitle_src_templ);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_templ);
+
+  gst_element_class_set_static_metadata (gstelement_class, "Matroska demuxer",
+      "Codec/Demuxer",
+      "Demuxes Matroska/WebM streams into video/audio/subtitles",
+      "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
+}
+
+static void
+gst_matroska_demux_init (GstMatroskaDemux * demux)
+{
+  demux->common.sinkpad = gst_pad_new_from_static_template (&sink_templ,
+      "sink");
+  gst_pad_set_activate_function (demux->common.sinkpad,
+      GST_DEBUG_FUNCPTR (gst_matroska_demux_sink_activate));
+  gst_pad_set_activatemode_function (demux->common.sinkpad,
+      GST_DEBUG_FUNCPTR (gst_matroska_demux_sink_activate_mode));
+  gst_pad_set_chain_function (demux->common.sinkpad,
+      GST_DEBUG_FUNCPTR (gst_matroska_demux_chain));
+  gst_pad_set_event_function (demux->common.sinkpad,
+      GST_DEBUG_FUNCPTR (gst_matroska_demux_handle_sink_event));
+  gst_element_add_pad (GST_ELEMENT (demux), demux->common.sinkpad);
+
+  /* init defaults for common read context */
+  gst_matroska_read_common_init (&demux->common);
+
+  /* property defaults */
+  demux->max_gap_time = DEFAULT_MAX_GAP_TIME;
+
+  GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
+
+  demux->flowcombiner = gst_flow_combiner_new ();
+
+  /* finish off */
+  gst_matroska_demux_reset (GST_ELEMENT (demux));
+}
+
+static void
+gst_matroska_demux_reset (GstElement * element)
+{
+  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
+
+  GST_DEBUG_OBJECT (demux, "Resetting state");
+
+  gst_matroska_read_common_reset (GST_ELEMENT (demux), &demux->common);
+
+  demux->num_a_streams = 0;
+  demux->num_t_streams = 0;
+  demux->num_v_streams = 0;
+
+  demux->have_group_id = FALSE;
+  demux->group_id = G_MAXUINT;
+
+  demux->clock = NULL;
+  demux->tracks_parsed = FALSE;
+
+  if (demux->clusters) {
+    g_array_free (demux->clusters, TRUE);
+    demux->clusters = NULL;
+  }
+
+  g_list_foreach (demux->seek_parsed,
+      (GFunc) gst_matroska_read_common_free_parsed_el, NULL);
+  g_list_free (demux->seek_parsed);
+  demux->seek_parsed = NULL;
+
+  demux->last_stop_end = GST_CLOCK_TIME_NONE;
+  demux->seek_block = 0;
+  demux->stream_start_time = GST_CLOCK_TIME_NONE;
+  demux->to_time = GST_CLOCK_TIME_NONE;
+  demux->cluster_time = GST_CLOCK_TIME_NONE;
+  demux->cluster_offset = 0;
+  demux->next_cluster_offset = 0;
+  demux->stream_last_time = GST_CLOCK_TIME_NONE;
+  demux->last_cluster_offset = 0;
+  demux->index_offset = 0;
+  demux->seekable = FALSE;
+  demux->need_segment = FALSE;
+  demux->segment_seqnum = 0;
+  demux->requested_seek_time = GST_CLOCK_TIME_NONE;
+  demux->seek_offset = -1;
+  demux->building_index = FALSE;
+  if (demux->seek_event) {
+    gst_event_unref (demux->seek_event);
+    demux->seek_event = NULL;
+  }
+
+  demux->seek_index = NULL;
+  demux->seek_entry = 0;
+
+  if (demux->new_segment) {
+    gst_event_unref (demux->new_segment);
+    demux->new_segment = NULL;
+  }
+
+  demux->invalid_duration = FALSE;
+
+  demux->cached_length = G_MAXUINT64;
+
+  gst_flow_combiner_clear (demux->flowcombiner);
+}
+
+static GstBuffer *
+gst_matroska_decode_buffer (GstMatroskaTrackContext * context, GstBuffer * buf)
+{
+  GstMapInfo map;
+  gpointer data;
+  gsize size;
+
+  g_return_val_if_fail (GST_IS_BUFFER (buf), NULL);
+
+  GST_DEBUG ("decoding buffer %p", buf);
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  data = map.data;
+  size = map.size;
+
+  g_return_val_if_fail (size > 0, buf);
+
+  if (gst_matroska_decode_data (context->encodings, &data, &size,
+          GST_MATROSKA_TRACK_ENCODING_SCOPE_FRAME, FALSE)) {
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    return gst_buffer_new_wrapped (data, size);
+  } else {
+    GST_DEBUG ("decode data failed");
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    return NULL;
+  }
+}
+
+static void
+gst_matroska_demux_add_stream_headers_to_caps (GstMatroskaDemux * demux,
+    GstBufferList * list, GstCaps * caps)
+{
+  GstStructure *s;
+  GValue arr_val = G_VALUE_INIT;
+  GValue buf_val = G_VALUE_INIT;
+  gint i, num;
+
+  g_assert (gst_caps_is_writable (caps));
+
+  g_value_init (&arr_val, GST_TYPE_ARRAY);
+  g_value_init (&buf_val, GST_TYPE_BUFFER);
+
+  num = gst_buffer_list_length (list);
+  for (i = 0; i < num; ++i) {
+    g_value_set_boxed (&buf_val, gst_buffer_list_get (list, i));
+    gst_value_array_append_value (&arr_val, &buf_val);
+  }
+
+  s = gst_caps_get_structure (caps, 0);
+  gst_structure_take_value (s, "streamheader", &arr_val);
+  g_value_unset (&buf_val);
+}
+
+static GstFlowReturn
+gst_matroska_demux_parse_colour (GstMatroskaDemux * demux, GstEbmlRead * ebml,
+    GstMatroskaTrackVideoContext * video_context)
+{
+  GstFlowReturn ret;
+  GstVideoColorimetry colorimetry;
+  guint32 id;
+  guint64 num;
+
+  colorimetry.range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
+  colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
+  colorimetry.transfer = GST_VIDEO_TRANSFER_UNKNOWN;
+  colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
+
+  DEBUG_ELEMENT_START (demux, ebml, "TrackVideoColour");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
+    goto beach;
+
+  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
+    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
+      goto beach;
+
+    switch (id) {
+      case GST_MATROSKA_ID_VIDEOMATRIXCOEFFICIENTS:{
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          goto beach;
+
+        switch (num) {
+          case 0:
+            colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
+            break;
+          case 1:
+            colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
+            break;
+          case 2:
+            colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
+            break;
+          case 4:
+            colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_FCC;
+            break;
+            /* FIXME: "5: BT470BG" is undefined in GstVideoColorMatrix
+             * but it's functionally same as "6: BT601" */
+          case 5:
+          case 6:
+            colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
+            break;
+          case 7:
+            colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
+            break;
+          case 9:
+            colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
+            break;
+          default:
+            GST_FIXME_OBJECT (demux, "Unsupported color matrix coefficients  %"
+                G_GUINT64_FORMAT, num);
+            break;
+        }
+        break;
+      }
+
+      case GST_MATROSKA_ID_VIDEORANGE:{
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          goto beach;
+
+        switch (num) {
+          case 0:
+            colorimetry.range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
+            break;
+          case 1:
+            colorimetry.range = GST_VIDEO_COLOR_RANGE_16_235;
+            break;
+          case 2:
+            colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
+            break;
+          default:
+            GST_FIXME_OBJECT (demux, "Unsupported color range  %"
+                G_GUINT64_FORMAT, num);
+            break;
+        }
+        break;
+      }
+
+      case GST_MATROSKA_ID_VIDEOTRANSFERCHARACTERISTICS:{
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          goto beach;
+
+        switch (num) {
+            /* FIXME: "6: BT601" and "14: BT2020_10" are undefined in
+             * GstVideoTransferFunction, but functionally same as "1: BT709" */
+          case 1:
+          case 6:
+          case 14:
+            colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
+            break;
+          case 2:
+            colorimetry.transfer = GST_VIDEO_TRANSFER_UNKNOWN;
+            break;
+          case 4:
+            colorimetry.transfer = GST_VIDEO_TRANSFER_GAMMA22;
+            break;
+          case 5:
+            colorimetry.transfer = GST_VIDEO_TRANSFER_GAMMA28;
+            break;
+          case 7:
+            colorimetry.transfer = GST_VIDEO_TRANSFER_SMPTE240M;
+            break;
+          case 8:
+            colorimetry.transfer = GST_VIDEO_TRANSFER_GAMMA10;
+            break;
+          case 9:
+            colorimetry.transfer = GST_VIDEO_TRANSFER_LOG100;
+            break;
+          case 10:
+            colorimetry.transfer = GST_VIDEO_TRANSFER_LOG316;
+            break;
+          case 13:
+            colorimetry.transfer = GST_VIDEO_TRANSFER_SRGB;
+            break;
+          case 15:
+            colorimetry.transfer = GST_VIDEO_TRANSFER_BT2020_12;
+            break;
+          default:
+            GST_FIXME_OBJECT (demux,
+                "Unsupported color transfer characteristics  %"
+                G_GUINT64_FORMAT, num);
+            break;
+        }
+        break;
+      }
+
+      case GST_MATROSKA_ID_VIDEOPRIMARIES:{
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          goto beach;
+
+        switch (num) {
+          case 1:
+            colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
+            break;
+          case 2:
+            colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
+            break;
+          case 4:
+            colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470M;
+            break;
+          case 5:
+            colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
+            break;
+          case 6:
+            colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
+            break;
+          case 7:
+            colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE240M;
+            break;
+          case 8:
+            colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_FILM;
+            break;
+          case 9:
+            colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
+            break;
+          default:
+            GST_FIXME_OBJECT (demux, "Unsupported color primaries  %"
+                G_GUINT64_FORMAT, num);
+            break;
+        }
+        break;
+      }
+
+      default:
+        GST_FIXME_OBJECT (demux, "Unsupported subelement 0x%x in Colour", id);
+        ret = gst_ebml_read_skip (ebml);
+        break;
+    }
+  }
+
+  memcpy (&video_context->colorimetry, &colorimetry,
+      sizeof (GstVideoColorimetry));
+
+beach:
+  DEBUG_ELEMENT_STOP (demux, ebml, "TrackVideoColour", ret);
+  return ret;
+}
+
+static GstFlowReturn
+gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (demux);
+  GstMatroskaTrackContext *context;
+  GstPadTemplate *templ = NULL;
+  GstStreamFlags stream_flags;
+  GstCaps *caps = NULL;
+  GstTagList *cached_taglist;
+  gchar *padname = NULL;
+  GstFlowReturn ret;
+  guint32 id, riff_fourcc = 0;
+  guint16 riff_audio_fmt = 0;
+  GstEvent *stream_start;
+  gchar *codec = NULL;
+  gchar *stream_id;
+
+  DEBUG_ELEMENT_START (demux, ebml, "TrackEntry");
+
+  /* start with the master */
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (demux, ebml, "TrackEntry", ret);
+    return ret;
+  }
+
+  /* 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->common.src, context);
+  context->index = demux->common.num_streams;
+  context->index_writer_id = -1;
+  context->type = 0;            /* no type yet */
+  context->default_duration = 0;
+  context->pos = 0;
+  context->set_discont = TRUE;
+  context->timecodescale = 1.0;
+  context->flags =
+      GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT |
+      GST_MATROSKA_TRACK_LACING;
+  context->from_time = GST_CLOCK_TIME_NONE;
+  context->from_offset = -1;
+  context->to_offset = G_MAXINT64;
+  context->alignment = 1;
+  context->dts_only = FALSE;
+  context->intra_only = FALSE;
+  context->tags = gst_tag_list_new_empty ();
+  demux->common.num_streams++;
+  g_assert (demux->common.src->len == demux->common.num_streams);
+
+  GST_DEBUG_OBJECT (demux, "Stream number %d", context->index);
+
+  /* try reading the trackentry headers */
+  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 (unique stream ID) */
+      case GST_MATROSKA_ID_TRACKNUMBER:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num == 0) {
+          GST_ERROR_OBJECT (demux, "Invalid TrackNumber 0");
+          ret = GST_FLOW_ERROR;
+          break;
+        } else if (!gst_matroska_read_common_tracknumber_unique (&demux->common,
+                num)) {
+          GST_ERROR_OBJECT (demux, "TrackNumber %" G_GUINT64_FORMAT
+              " is not unique", num);
+          ret = GST_FLOW_ERROR;
+          break;
+        }
+
+        GST_DEBUG_OBJECT (demux, "TrackNumber: %" G_GUINT64_FORMAT, num);
+        context->num = num;
+        break;
+      }
+        /* track UID (unique identifier) */
+      case GST_MATROSKA_ID_TRACKUID:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num == 0) {
+          GST_ERROR_OBJECT (demux, "Invalid TrackUID 0");
+          ret = GST_FLOW_ERROR;
+          break;
+        }
+
+        GST_DEBUG_OBJECT (demux, "TrackUID: %" G_GUINT64_FORMAT, num);
+        context->uid = num;
+        break;
+      }
+
+        /* track type (video, audio, combined, subtitle, etc.) */
+      case GST_MATROSKA_ID_TRACKTYPE:{
+        guint64 track_type;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &track_type)) != GST_FLOW_OK) {
+          break;
+        }
+
+        if (context->type != 0 && context->type != track_type) {
+          GST_WARNING_OBJECT (demux,
+              "More than one tracktype defined in a TrackEntry - skipping");
+          break;
+        } else if (track_type < 1 || track_type > 254) {
+          GST_WARNING_OBJECT (demux, "Invalid TrackType %" G_GUINT64_FORMAT,
+              track_type);
+          break;
+        }
+
+        GST_DEBUG_OBJECT (demux, "TrackType: %" G_GUINT64_FORMAT, track_type);
+
+        /* ok, so we're actually going to reallocate this thing */
+        switch (track_type) {
+          case GST_MATROSKA_TRACK_TYPE_VIDEO:
+            gst_matroska_track_init_video_context (&context);
+            break;
+          case GST_MATROSKA_TRACK_TYPE_AUDIO:
+            gst_matroska_track_init_audio_context (&context);
+            break;
+          case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
+            gst_matroska_track_init_subtitle_context (&context);
+            break;
+          case GST_MATROSKA_TRACK_TYPE_COMPLEX:
+          case GST_MATROSKA_TRACK_TYPE_LOGO:
+          case GST_MATROSKA_TRACK_TYPE_BUTTONS:
+          case GST_MATROSKA_TRACK_TYPE_CONTROL:
+          default:
+            GST_WARNING_OBJECT (demux,
+                "Unknown or unsupported TrackType %" G_GUINT64_FORMAT,
+                track_type);
+            context->type = 0;
+            break;
+        }
+        g_ptr_array_index (demux->common.src, demux->common.num_streams - 1)
+            = context;
+        break;
+      }
+
+        /* tracktype specific stuff for video */
+      case GST_MATROSKA_ID_TRACKVIDEO:{
+        GstMatroskaTrackVideoContext *videocontext;
+
+        DEBUG_ELEMENT_START (demux, ebml, "TrackVideo");
+
+        if (!gst_matroska_track_init_video_context (&context)) {
+          GST_WARNING_OBJECT (demux,
+              "TrackVideo element in non-video track - ignoring track");
+          ret = GST_FLOW_ERROR;
+          break;
+        } else if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+          break;
+        }
+        videocontext = (GstMatroskaTrackVideoContext *) 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)) {
+          if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
+            break;
+
+          switch (id) {
+              /* Should be one level up but some broken muxers write it here. */
+            case GST_MATROSKA_ID_TRACKDEFAULTDURATION:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num == 0) {
+                GST_WARNING_OBJECT (demux, "Invalid TrackDefaultDuration 0");
+                break;
+              }
+
+              GST_DEBUG_OBJECT (demux,
+                  "TrackDefaultDuration: %" G_GUINT64_FORMAT, num);
+              context->default_duration = num;
+              break;
+            }
+
+              /* video framerate */
+              /* NOTE: This one is here only for backward compatibility.
+               * Use _TRACKDEFAULDURATION one level up. */
+            case GST_MATROSKA_ID_VIDEOFRAMERATE:{
+              gdouble num;
+
+              if ((ret = gst_ebml_read_float (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num <= 0.0) {
+                GST_WARNING_OBJECT (demux, "Invalid TrackVideoFPS %lf", num);
+                break;
+              }
+
+              GST_DEBUG_OBJECT (demux, "TrackVideoFrameRate: %lf", num);
+              if (context->default_duration == 0)
+                context->default_duration =
+                    gst_gdouble_to_guint64 ((gdouble) GST_SECOND * (1.0 / num));
+              videocontext->default_fps = num;
+              break;
+            }
+
+              /* width of the size to display the video at */
+            case GST_MATROSKA_ID_VIDEODISPLAYWIDTH:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num == 0) {
+                GST_WARNING_OBJECT (demux, "Invalid TrackVideoDisplayWidth 0");
+                break;
+              }
+
+              GST_DEBUG_OBJECT (demux,
+                  "TrackVideoDisplayWidth: %" G_GUINT64_FORMAT, num);
+              videocontext->display_width = num;
+              break;
+            }
+
+              /* height of the size to display the video at */
+            case GST_MATROSKA_ID_VIDEODISPLAYHEIGHT:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num == 0) {
+                GST_WARNING_OBJECT (demux, "Invalid TrackVideoDisplayHeight 0");
+                break;
+              }
+
+              GST_DEBUG_OBJECT (demux,
+                  "TrackVideoDisplayHeight: %" G_GUINT64_FORMAT, num);
+              videocontext->display_height = num;
+              break;
+            }
+
+              /* width of the video in the file */
+            case GST_MATROSKA_ID_VIDEOPIXELWIDTH:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num == 0) {
+                GST_WARNING_OBJECT (demux, "Invalid TrackVideoPixelWidth 0");
+                break;
+              }
+
+              GST_DEBUG_OBJECT (demux,
+                  "TrackVideoPixelWidth: %" G_GUINT64_FORMAT, num);
+              videocontext->pixel_width = num;
+              break;
+            }
+
+              /* height of the video in the file */
+            case GST_MATROSKA_ID_VIDEOPIXELHEIGHT:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num == 0) {
+                GST_WARNING_OBJECT (demux, "Invalid TrackVideoPixelHeight 0");
+                break;
+              }
+
+              GST_DEBUG_OBJECT (demux,
+                  "TrackVideoPixelHeight: %" G_GUINT64_FORMAT, num);
+              videocontext->pixel_height = num;
+              break;
+            }
+
+              /* whether the video is interlaced */
+            case GST_MATROSKA_ID_VIDEOFLAGINTERLACED:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num)
+                context->flags |= GST_MATROSKA_VIDEOTRACK_INTERLACED;
+              else
+                context->flags &= ~GST_MATROSKA_VIDEOTRACK_INTERLACED;
+              GST_DEBUG_OBJECT (demux, "TrackVideoInterlaced: %d",
+                  (context->flags & GST_MATROSKA_VIDEOTRACK_INTERLACED) ? 1 :
+                  0);
+              break;
+            }
+
+              /* aspect ratio behaviour */
+            case GST_MATROSKA_ID_VIDEOASPECTRATIOTYPE:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num != GST_MATROSKA_ASPECT_RATIO_MODE_FREE &&
+                  num != GST_MATROSKA_ASPECT_RATIO_MODE_KEEP &&
+                  num != GST_MATROSKA_ASPECT_RATIO_MODE_FIXED) {
+                GST_WARNING_OBJECT (demux,
+                    "Unknown TrackVideoAspectRatioType 0x%x", (guint) num);
+                break;
+              }
+              GST_DEBUG_OBJECT (demux,
+                  "TrackVideoAspectRatioType: %" G_GUINT64_FORMAT, num);
+              videocontext->asr_mode = num;
+              break;
+            }
+
+              /* colourspace (only matters for raw video) fourcc */
+            case GST_MATROSKA_ID_VIDEOCOLOURSPACE:{
+              guint8 *data;
+              guint64 datalen;
+
+              if ((ret =
+                      gst_ebml_read_binary (ebml, &id, &data,
+                          &datalen)) != GST_FLOW_OK)
+                break;
+
+              if (datalen != 4) {
+                g_free (data);
+                GST_WARNING_OBJECT (demux,
+                    "Invalid TrackVideoColourSpace length %" G_GUINT64_FORMAT,
+                    datalen);
+                break;
+              }
+
+              memcpy (&videocontext->fourcc, data, 4);
+              GST_DEBUG_OBJECT (demux,
+                  "TrackVideoColourSpace: %" GST_FOURCC_FORMAT,
+                  GST_FOURCC_ARGS (videocontext->fourcc));
+              g_free (data);
+              break;
+            }
+
+              /* color info */
+            case GST_MATROSKA_ID_VIDEOCOLOUR:{
+              ret = gst_matroska_demux_parse_colour (demux, ebml, videocontext);
+              break;
+            }
+
+            case GST_MATROSKA_ID_VIDEOSTEREOMODE:
+            {
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              GST_DEBUG_OBJECT (demux, "StereoMode: %" G_GUINT64_FORMAT, num);
+
+              switch (num) {
+                case GST_MATROSKA_STEREO_MODE_SBS_RL:
+                  videocontext->multiview_flags =
+                      GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
+                  /* fall through */
+                case GST_MATROSKA_STEREO_MODE_SBS_LR:
+                  videocontext->multiview_mode =
+                      GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
+                  break;
+                case GST_MATROSKA_STEREO_MODE_TB_RL:
+                  videocontext->multiview_flags =
+                      GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
+                  /* fall through */
+                case GST_MATROSKA_STEREO_MODE_TB_LR:
+                  videocontext->multiview_mode =
+                      GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
+                  break;
+                case GST_MATROSKA_STEREO_MODE_CHECKER_RL:
+                  videocontext->multiview_flags =
+                      GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
+                  /* fall through */
+                case GST_MATROSKA_STEREO_MODE_CHECKER_LR:
+                  videocontext->multiview_mode =
+                      GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD;
+                  break;
+                case GST_MATROSKA_STEREO_MODE_FBF_RL:
+                  videocontext->multiview_flags =
+                      GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
+                  /* fall through */
+                case GST_MATROSKA_STEREO_MODE_FBF_LR:
+                  videocontext->multiview_mode =
+                      GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
+                  /* FIXME: In frame-by-frame mode, left/right frame buffers are
+                   * laced within one block, and we'll need to apply FIRST_IN_BUNDLE
+                   * accordingly. See http://www.matroska.org/technical/specs/index.html#StereoMode */
+                  GST_FIXME_OBJECT (demux,
+                      "Frame-by-frame stereoscopic mode not fully implemented");
+                  break;
+              }
+              break;
+            }
+
+            default:
+              GST_WARNING_OBJECT (demux,
+                  "Unknown TrackVideo subelement 0x%x - ignoring", id);
+              /* fall through */
+            case GST_MATROSKA_ID_VIDEODISPLAYUNIT:
+            case GST_MATROSKA_ID_VIDEOPIXELCROPBOTTOM:
+            case GST_MATROSKA_ID_VIDEOPIXELCROPTOP:
+            case GST_MATROSKA_ID_VIDEOPIXELCROPLEFT:
+            case GST_MATROSKA_ID_VIDEOPIXELCROPRIGHT:
+            case GST_MATROSKA_ID_VIDEOGAMMAVALUE:
+              ret = gst_ebml_read_skip (ebml);
+              break;
+          }
+        }
+
+        DEBUG_ELEMENT_STOP (demux, ebml, "TrackVideo", ret);
+        break;
+      }
+
+        /* tracktype specific stuff for audio */
+      case GST_MATROSKA_ID_TRACKAUDIO:{
+        GstMatroskaTrackAudioContext *audiocontext;
+
+        DEBUG_ELEMENT_START (demux, ebml, "TrackAudio");
+
+        if (!gst_matroska_track_init_audio_context (&context)) {
+          GST_WARNING_OBJECT (demux,
+              "TrackAudio element in non-audio track - ignoring track");
+          ret = GST_FLOW_ERROR;
+          break;
+        }
+
+        if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
+          break;
+
+        audiocontext = (GstMatroskaTrackAudioContext *) 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)) {
+          if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
+            break;
+
+          switch (id) {
+              /* samplerate */
+            case GST_MATROSKA_ID_AUDIOSAMPLINGFREQ:{
+              gdouble num;
+
+              if ((ret = gst_ebml_read_float (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+
+              if (num <= 0.0) {
+                GST_WARNING_OBJECT (demux,
+                    "Invalid TrackAudioSamplingFrequency %lf", num);
+                break;
+              }
+
+              GST_DEBUG_OBJECT (demux, "TrackAudioSamplingFrequency: %lf", num);
+              audiocontext->samplerate = num;
+              break;
+            }
+
+              /* bitdepth */
+            case GST_MATROSKA_ID_AUDIOBITDEPTH:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num == 0) {
+                GST_WARNING_OBJECT (demux, "Invalid TrackAudioBitDepth 0");
+                break;
+              }
+
+              GST_DEBUG_OBJECT (demux, "TrackAudioBitDepth: %" G_GUINT64_FORMAT,
+                  num);
+              audiocontext->bitdepth = num;
+              break;
+            }
+
+              /* channels */
+            case GST_MATROSKA_ID_AUDIOCHANNELS:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num == 0) {
+                GST_WARNING_OBJECT (demux, "Invalid TrackAudioChannels 0");
+                break;
+              }
+
+              GST_DEBUG_OBJECT (demux, "TrackAudioChannels: %" G_GUINT64_FORMAT,
+                  num);
+              audiocontext->channels = num;
+              break;
+            }
+
+            default:
+              GST_WARNING_OBJECT (demux,
+                  "Unknown TrackAudio subelement 0x%x - ignoring", id);
+              /* fall through */
+            case GST_MATROSKA_ID_AUDIOCHANNELPOSITIONS:
+            case GST_MATROSKA_ID_AUDIOOUTPUTSAMPLINGFREQ:
+              ret = gst_ebml_read_skip (ebml);
+              break;
+          }
+        }
+
+        DEBUG_ELEMENT_STOP (demux, ebml, "TrackAudio", ret);
+
+        break;
+      }
+
+        /* codec identifier */
+      case GST_MATROSKA_ID_CODECID:{
+        gchar *text;
+
+        if ((ret = gst_ebml_read_ascii (ebml, &id, &text)) != GST_FLOW_OK)
+          break;
+
+        GST_DEBUG_OBJECT (demux, "CodecID: %s", GST_STR_NULL (text));
+        context->codec_id = text;
+        break;
+      }
+
+        /* codec private data */
+      case GST_MATROSKA_ID_CODECPRIVATE:{
+        guint8 *data;
+        guint64 size;
+
+        if ((ret =
+                gst_ebml_read_binary (ebml, &id, &data, &size)) != GST_FLOW_OK)
+          break;
+
+        context->codec_priv = data;
+        context->codec_priv_size = size;
+
+        GST_DEBUG_OBJECT (demux, "CodecPrivate of size %" G_GUINT64_FORMAT,
+            size);
+        break;
+      }
+
+        /* name of the codec */
+      case GST_MATROSKA_ID_CODECNAME:{
+        gchar *text;
+
+        if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
+          break;
+
+        GST_DEBUG_OBJECT (demux, "CodecName: %s", GST_STR_NULL (text));
+        context->codec_name = text;
+        break;
+      }
+
+        /* codec delay */
+      case GST_MATROSKA_ID_CODECDELAY:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        context->codec_delay = num;
+
+        GST_DEBUG_OBJECT (demux, "CodecDelay: %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (num));
+        break;
+      }
+
+        /* codec delay */
+      case GST_MATROSKA_ID_SEEKPREROLL:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        context->seek_preroll = num;
+
+        GST_DEBUG_OBJECT (demux, "SeekPreroll: %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (num));
+        break;
+      }
+
+        /* name of this track */
+      case GST_MATROSKA_ID_TRACKNAME:{
+        gchar *text;
+
+        if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
+          break;
+
+        context->name = text;
+        GST_DEBUG_OBJECT (demux, "TrackName: %s", GST_STR_NULL (text));
+        break;
+      }
+
+        /* language (matters for audio/subtitles, mostly) */
+      case GST_MATROSKA_ID_TRACKLANGUAGE:{
+        gchar *text;
+
+        if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
+          break;
+
+
+        context->language = text;
+
+        /* fre-ca => fre */
+        if (strlen (context->language) >= 4 && context->language[3] == '-')
+          context->language[3] = '\0';
+
+        GST_DEBUG_OBJECT (demux, "TrackLanguage: %s",
+            GST_STR_NULL (context->language));
+        break;
+      }
+
+        /* whether this is actually used */
+      case GST_MATROSKA_ID_TRACKFLAGENABLED:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num)
+          context->flags |= GST_MATROSKA_TRACK_ENABLED;
+        else
+          context->flags &= ~GST_MATROSKA_TRACK_ENABLED;
+
+        GST_DEBUG_OBJECT (demux, "TrackEnabled: %d",
+            (context->flags & GST_MATROSKA_TRACK_ENABLED) ? 1 : 0);
+        break;
+      }
+
+        /* whether it's the default for this track type */
+      case GST_MATROSKA_ID_TRACKFLAGDEFAULT:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num)
+          context->flags |= GST_MATROSKA_TRACK_DEFAULT;
+        else
+          context->flags &= ~GST_MATROSKA_TRACK_DEFAULT;
+
+        GST_DEBUG_OBJECT (demux, "TrackDefault: %d",
+            (context->flags & GST_MATROSKA_TRACK_DEFAULT) ? 1 : 0);
+        break;
+      }
+
+        /* whether the track must be used during playback */
+      case GST_MATROSKA_ID_TRACKFLAGFORCED:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num)
+          context->flags |= GST_MATROSKA_TRACK_FORCED;
+        else
+          context->flags &= ~GST_MATROSKA_TRACK_FORCED;
+
+        GST_DEBUG_OBJECT (demux, "TrackForced: %d",
+            (context->flags & GST_MATROSKA_TRACK_FORCED) ? 1 : 0);
+        break;
+      }
+
+        /* lacing (like MPEG, where blocks don't end/start on frame
+         * boundaries) */
+      case GST_MATROSKA_ID_TRACKFLAGLACING:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num)
+          context->flags |= GST_MATROSKA_TRACK_LACING;
+        else
+          context->flags &= ~GST_MATROSKA_TRACK_LACING;
+
+        GST_DEBUG_OBJECT (demux, "TrackLacing: %d",
+            (context->flags & GST_MATROSKA_TRACK_LACING) ? 1 : 0);
+        break;
+      }
+
+        /* default length (in time) of one data block in this track */
+      case GST_MATROSKA_ID_TRACKDEFAULTDURATION:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+
+        if (num == 0) {
+          GST_WARNING_OBJECT (demux, "Invalid TrackDefaultDuration 0");
+          break;
+        }
+
+        GST_DEBUG_OBJECT (demux, "TrackDefaultDuration: %" G_GUINT64_FORMAT,
+            num);
+        context->default_duration = num;
+        break;
+      }
+
+      case GST_MATROSKA_ID_CONTENTENCODINGS:{
+        ret = gst_matroska_read_common_read_track_encodings (&demux->common,
+            ebml, context);
+        break;
+      }
+
+      case GST_MATROSKA_ID_TRACKTIMECODESCALE:{
+        gdouble num;
+
+        if ((ret = gst_ebml_read_float (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num <= 0.0) {
+          GST_WARNING_OBJECT (demux, "Invalid TrackTimeCodeScale %lf", num);
+          break;
+        }
+
+        GST_DEBUG_OBJECT (demux, "TrackTimeCodeScale: %lf", num);
+        context->timecodescale = num;
+        break;
+      }
+
+      default:
+        GST_WARNING ("Unknown TrackEntry subelement 0x%x - ignoring", id);
+        /* pass-through */
+
+        /* we ignore these because they're nothing useful (i.e. crap)
+         * or simply not implemented yet. */
+      case GST_MATROSKA_ID_TRACKMINCACHE:
+      case GST_MATROSKA_ID_TRACKMAXCACHE:
+      case GST_MATROSKA_ID_MAXBLOCKADDITIONID:
+      case GST_MATROSKA_ID_TRACKATTACHMENTLINK:
+      case GST_MATROSKA_ID_TRACKOVERLAY:
+      case GST_MATROSKA_ID_TRACKTRANSLATE:
+      case GST_MATROSKA_ID_TRACKOFFSET:
+      case GST_MATROSKA_ID_CODECSETTINGS:
+      case GST_MATROSKA_ID_CODECINFOURL:
+      case GST_MATROSKA_ID_CODECDOWNLOADURL:
+      case GST_MATROSKA_ID_CODECDECODEALL:
+        ret = gst_ebml_read_skip (ebml);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (demux, ebml, "TrackEntry", ret);
+
+  /* Decode codec private data if necessary */
+  if (context->encodings && context->encodings->len > 0 && context->codec_priv
+      && context->codec_priv_size > 0) {
+    if (!gst_matroska_decode_data (context->encodings,
+            &context->codec_priv, &context->codec_priv_size,
+            GST_MATROSKA_TRACK_ENCODING_SCOPE_CODEC_DATA, TRUE)) {
+      GST_WARNING_OBJECT (demux, "Decoding codec private data failed");
+      ret = GST_FLOW_ERROR;
+    }
+  }
+
+  if (context->type == 0 || context->codec_id == NULL || (ret != GST_FLOW_OK
+          && ret != GST_FLOW_EOS)) {
+    if (ret == GST_FLOW_OK || ret == GST_FLOW_EOS)
+      GST_WARNING_OBJECT (ebml, "Unknown stream/codec in track entry header");
+
+    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);
+    gst_matroska_track_free (context);
+
+    return ret;
+  }
+
+  /* check for a cached track taglist  */
+  cached_taglist =
+      (GstTagList *) g_hash_table_lookup (demux->common.cached_track_taglists,
+      GUINT_TO_POINTER (context->uid));
+  if (cached_taglist)
+    gst_tag_list_insert (context->tags, cached_taglist, GST_TAG_MERGE_APPEND);
+
+  /* now create the GStreamer connectivity */
+  switch (context->type) {
+    case GST_MATROSKA_TRACK_TYPE_VIDEO:{
+      GstMatroskaTrackVideoContext *videocontext =
+          (GstMatroskaTrackVideoContext *) context;
+
+      padname = g_strdup_printf ("video_%u", demux->num_v_streams++);
+      templ = gst_element_class_get_pad_template (klass, "video_%u");
+      caps = gst_matroska_demux_video_caps (videocontext,
+          context->codec_id, context->codec_priv,
+          context->codec_priv_size, &codec, &riff_fourcc);
+
+      if (codec) {
+        gst_tag_list_add (context->tags, GST_TAG_MERGE_REPLACE,
+            GST_TAG_VIDEO_CODEC, codec, NULL);
+        context->tags_changed = TRUE;
+        g_free (codec);
+      }
+      break;
+    }
+
+    case GST_MATROSKA_TRACK_TYPE_AUDIO:{
+      GstMatroskaTrackAudioContext *audiocontext =
+          (GstMatroskaTrackAudioContext *) context;
+
+      padname = g_strdup_printf ("audio_%u", demux->num_a_streams++);
+      templ = gst_element_class_get_pad_template (klass, "audio_%u");
+      caps = gst_matroska_demux_audio_caps (audiocontext,
+          context->codec_id, context->codec_priv, context->codec_priv_size,
+          &codec, &riff_audio_fmt);
+
+      if (codec) {
+        gst_tag_list_add (context->tags, GST_TAG_MERGE_REPLACE,
+            GST_TAG_AUDIO_CODEC, codec, NULL);
+        context->tags_changed = TRUE;
+        g_free (codec);
+      }
+      break;
+    }
+
+    case GST_MATROSKA_TRACK_TYPE_SUBTITLE:{
+      GstMatroskaTrackSubtitleContext *subtitlecontext =
+          (GstMatroskaTrackSubtitleContext *) context;
+
+      padname = g_strdup_printf ("subtitle_%u", demux->num_t_streams++);
+      templ = gst_element_class_get_pad_template (klass, "subtitle_%u");
+      caps = gst_matroska_demux_subtitle_caps (subtitlecontext,
+          context->codec_id, context->codec_priv, context->codec_priv_size);
+      break;
+    }
+
+    case GST_MATROSKA_TRACK_TYPE_COMPLEX:
+    case GST_MATROSKA_TRACK_TYPE_LOGO:
+    case GST_MATROSKA_TRACK_TYPE_BUTTONS:
+    case GST_MATROSKA_TRACK_TYPE_CONTROL:
+    default:
+      /* we should already have quit by now */
+      g_assert_not_reached ();
+  }
+
+  if ((context->language == NULL || *context->language == '\0') &&
+      (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO ||
+          context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE)) {
+    GST_LOG ("stream %d: language=eng (assuming default)", context->index);
+    context->language = g_strdup ("eng");
+  }
+
+  if (context->language) {
+    const gchar *lang;
+
+    /* Matroska contains ISO 639-2B codes, we want ISO 639-1 */
+    lang = gst_tag_get_language_code (context->language);
+    gst_tag_list_add (context->tags, GST_TAG_MERGE_REPLACE,
+        GST_TAG_LANGUAGE_CODE, (lang) ? lang : context->language, NULL);
+    context->tags_changed = TRUE;
+  }
+
+  if (caps == NULL) {
+    GST_WARNING_OBJECT (demux, "could not determine caps for stream with "
+        "codec_id='%s'", context->codec_id);
+    switch (context->type) {
+      case GST_MATROSKA_TRACK_TYPE_VIDEO:
+        caps = gst_caps_new_empty_simple ("video/x-unknown");
+        break;
+      case GST_MATROSKA_TRACK_TYPE_AUDIO:
+        caps = gst_caps_new_empty_simple ("audio/x-unknown");
+        break;
+      case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
+        caps = gst_caps_new_empty_simple ("application/x-subtitle-unknown");
+        break;
+      case GST_MATROSKA_TRACK_TYPE_COMPLEX:
+      default:
+        caps = gst_caps_new_empty_simple ("application/x-matroska-unknown");
+        break;
+    }
+    gst_caps_set_simple (caps, "codec-id", G_TYPE_STRING, context->codec_id,
+        NULL);
+
+    /* add any unrecognised riff fourcc / audio format, but after codec-id */
+    if (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO && riff_audio_fmt != 0)
+      gst_caps_set_simple (caps, "format", G_TYPE_INT, riff_audio_fmt, NULL);
+    else if (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO && riff_fourcc != 0) {
+      gchar *fstr = g_strdup_printf ("%" GST_FOURCC_FORMAT,
+          GST_FOURCC_ARGS (riff_fourcc));
+      gst_caps_set_simple (caps, "fourcc", G_TYPE_STRING, fstr, NULL);
+      g_free (fstr);
+    }
+  } else if (context->stream_headers != NULL) {
+    gst_matroska_demux_add_stream_headers_to_caps (demux,
+        context->stream_headers, caps);
+  }
+
+  /* the pad in here */
+  context->pad = gst_pad_new_from_template (templ, padname);
+  context->caps = caps;
+
+  gst_pad_set_event_function (context->pad,
+      GST_DEBUG_FUNCPTR (gst_matroska_demux_handle_src_event));
+  gst_pad_set_query_function (context->pad,
+      GST_DEBUG_FUNCPTR (gst_matroska_demux_handle_src_query));
+
+  GST_INFO_OBJECT (demux, "Adding pad '%s' with caps %" GST_PTR_FORMAT,
+      padname, caps);
+
+  gst_pad_set_element_private (context->pad, context);
+
+  gst_pad_use_fixed_caps (context->pad);
+  gst_pad_set_active (context->pad, TRUE);
+
+  stream_id =
+      gst_pad_create_stream_id_printf (context->pad, GST_ELEMENT_CAST (demux),
+      "%03" G_GUINT64_FORMAT ":%03" G_GUINT64_FORMAT,
+      context->num, context->uid);
+  stream_start =
+      gst_pad_get_sticky_event (demux->common.sinkpad, GST_EVENT_STREAM_START,
+      0);
+  if (stream_start) {
+    if (gst_event_parse_group_id (stream_start, &demux->group_id))
+      demux->have_group_id = TRUE;
+    else
+      demux->have_group_id = FALSE;
+    gst_event_unref (stream_start);
+  } else if (!demux->have_group_id) {
+    demux->have_group_id = TRUE;
+    demux->group_id = gst_util_group_id_next ();
+  }
+
+  stream_start = gst_event_new_stream_start (stream_id);
+  g_free (stream_id);
+  if (demux->have_group_id)
+    gst_event_set_group_id (stream_start, demux->group_id);
+  stream_flags = GST_STREAM_FLAG_NONE;
+  if (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE)
+    stream_flags |= GST_STREAM_FLAG_SPARSE;
+  if (context->flags & GST_MATROSKA_TRACK_DEFAULT)
+    stream_flags |= GST_STREAM_FLAG_SELECT;
+  gst_event_set_stream_flags (stream_start, stream_flags);
+  gst_pad_push_event (context->pad, stream_start);
+  gst_pad_set_caps (context->pad, context->caps);
+
+
+  if (demux->common.global_tags) {
+    GstEvent *tag_event;
+
+    gst_tag_list_add (demux->common.global_tags, GST_TAG_MERGE_REPLACE,
+        GST_TAG_CONTAINER_FORMAT, "Matroska", NULL);
+    GST_DEBUG_OBJECT (context->pad, "Sending global_tags %p: %" GST_PTR_FORMAT,
+        demux->common.global_tags, demux->common.global_tags);
+
+    tag_event =
+        gst_event_new_tag (gst_tag_list_copy (demux->common.global_tags));
+
+    gst_pad_push_event (context->pad, tag_event);
+  }
+
+  if (G_UNLIKELY (context->tags_changed)) {
+    GST_DEBUG_OBJECT (context->pad, "Sending tags %p: %"
+        GST_PTR_FORMAT, context->tags, context->tags);
+    gst_pad_push_event (context->pad,
+        gst_event_new_tag (gst_tag_list_copy (context->tags)));
+    context->tags_changed = FALSE;
+  }
+
+  gst_element_add_pad (GST_ELEMENT (demux), context->pad);
+  gst_flow_combiner_add_pad (demux->flowcombiner, context->pad);
+
+  g_free (padname);
+
+  /* tadaah! */
+  return ret;
+}
+
+static gboolean
+gst_matroska_demux_query (GstMatroskaDemux * demux, GstPad * pad,
+    GstQuery * query)
+{
+  gboolean res = FALSE;
+  GstMatroskaTrackContext *context = NULL;
+
+  if (pad) {
+    context = gst_pad_get_element_private (pad);
+  }
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:
+    {
+      GstFormat format;
+
+      gst_query_parse_position (query, &format, NULL);
+
+      res = TRUE;
+      if (format == GST_FORMAT_TIME) {
+        GST_OBJECT_LOCK (demux);
+        if (context)
+          gst_query_set_position (query, GST_FORMAT_TIME,
+              MAX (context->pos, demux->stream_start_time) -
+              demux->stream_start_time);
+        else
+          gst_query_set_position (query, GST_FORMAT_TIME,
+              MAX (demux->common.segment.position, demux->stream_start_time) -
+              demux->stream_start_time);
+        GST_OBJECT_UNLOCK (demux);
+      } else if (format == GST_FORMAT_DEFAULT && context
+          && context->default_duration) {
+        GST_OBJECT_LOCK (demux);
+        gst_query_set_position (query, GST_FORMAT_DEFAULT,
+            context->pos / context->default_duration);
+        GST_OBJECT_UNLOCK (demux);
+      } else {
+        GST_DEBUG_OBJECT (demux,
+            "only position query in TIME and DEFAULT format is supported");
+        res = FALSE;
+      }
+
+      break;
+    }
+    case GST_QUERY_DURATION:
+    {
+      GstFormat format;
+
+      gst_query_parse_duration (query, &format, NULL);
+
+      res = TRUE;
+      if (format == GST_FORMAT_TIME) {
+        GST_OBJECT_LOCK (demux);
+        gst_query_set_duration (query, GST_FORMAT_TIME,
+            demux->common.segment.duration);
+        GST_OBJECT_UNLOCK (demux);
+      } else if (format == GST_FORMAT_DEFAULT && context
+          && context->default_duration) {
+        GST_OBJECT_LOCK (demux);
+        gst_query_set_duration (query, GST_FORMAT_DEFAULT,
+            demux->common.segment.duration / context->default_duration);
+        GST_OBJECT_UNLOCK (demux);
+      } else {
+        GST_DEBUG_OBJECT (demux,
+            "only duration query in TIME and DEFAULT format is supported");
+        res = FALSE;
+      }
+      break;
+    }
+
+    case GST_QUERY_SEEKING:
+    {
+      GstFormat fmt;
+
+      gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
+      GST_OBJECT_LOCK (demux);
+      if (fmt == GST_FORMAT_TIME) {
+        gboolean seekable;
+
+        if (demux->streaming) {
+          /* assuming we'll be able to get an index ... */
+          seekable = demux->seekable;
+        } else {
+          seekable = TRUE;
+        }
+
+        gst_query_set_seeking (query, GST_FORMAT_TIME, seekable,
+            0, demux->common.segment.duration);
+        res = TRUE;
+      }
+      GST_OBJECT_UNLOCK (demux);
+      break;
+    }
+    case GST_QUERY_SEGMENT:
+    {
+      GstFormat format;
+      gint64 start, stop;
+
+      format = demux->common.segment.format;
+
+      start =
+          gst_segment_to_stream_time (&demux->common.segment, format,
+          demux->common.segment.start);
+      if ((stop = demux->common.segment.stop) == -1)
+        stop = demux->common.segment.duration;
+      else
+        stop =
+            gst_segment_to_stream_time (&demux->common.segment, format, stop);
+
+      gst_query_set_segment (query, demux->common.segment.rate, format, start,
+          stop);
+      res = TRUE;
+      break;
+    }
+    default:
+      if (pad)
+        res = gst_pad_query_default (pad, (GstObject *) demux, query);
+      else
+        res =
+            GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (demux),
+            query);
+      break;
+  }
+
+  return res;
+}
+
+static gboolean
+gst_matroska_demux_element_query (GstElement * element, GstQuery * query)
+{
+  return gst_matroska_demux_query (GST_MATROSKA_DEMUX (element), NULL, query);
+}
+
+static gboolean
+gst_matroska_demux_handle_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (parent);
+
+  return gst_matroska_demux_query (demux, pad, query);
+}
+
+/* returns FALSE if there are no pads to deliver event to,
+ * otherwise TRUE (whatever the outcome of event sending),
+ * takes ownership of the passed event! */
+static gboolean
+gst_matroska_demux_send_event (GstMatroskaDemux * demux, GstEvent * event)
+{
+  gboolean ret = FALSE;
+  gint i;
+
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  GST_DEBUG_OBJECT (demux, "Sending event of type %s to all source pads",
+      GST_EVENT_TYPE_NAME (event));
+
+  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->common.src, i);
+    gst_event_ref (event);
+    gst_pad_push_event (stream->pad, event);
+    ret = TRUE;
+  }
+
+  gst_event_unref (event);
+  return ret;
+}
+
+static void
+gst_matroska_demux_send_tags (GstMatroskaDemux * demux)
+{
+  gint i;
+
+  if (G_UNLIKELY (demux->common.global_tags_changed)) {
+    GstEvent *tag_event;
+    gst_tag_list_add (demux->common.global_tags, GST_TAG_MERGE_REPLACE,
+        GST_TAG_CONTAINER_FORMAT, "Matroska", NULL);
+    GST_DEBUG_OBJECT (demux, "Sending global_tags %p : %" GST_PTR_FORMAT,
+        demux->common.global_tags, demux->common.global_tags);
+
+    tag_event =
+        gst_event_new_tag (gst_tag_list_copy (demux->common.global_tags));
+
+    for (i = 0; i < demux->common.src->len; i++) {
+      GstMatroskaTrackContext *stream;
+
+      stream = g_ptr_array_index (demux->common.src, i);
+      gst_pad_push_event (stream->pad, gst_event_ref (tag_event));
+    }
+
+    gst_event_unref (tag_event);
+    demux->common.global_tags_changed = FALSE;
+  }
+
+  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->common.src, i);
+
+    if (G_UNLIKELY (stream->tags_changed)) {
+      GST_DEBUG_OBJECT (demux, "Sending tags %p for pad %s:%s : %"
+          GST_PTR_FORMAT, stream->tags,
+          GST_DEBUG_PAD_NAME (stream->pad), stream->tags);
+      gst_pad_push_event (stream->pad,
+          gst_event_new_tag (gst_tag_list_copy (stream->tags)));
+      stream->tags_changed = FALSE;
+    }
+  }
+}
+
+static gboolean
+gst_matroska_demux_element_send_event (GstElement * element, GstEvent * event)
+{
+  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
+  gboolean res;
+
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
+    /* no seeking until we are (safely) ready */
+    if (demux->common.state != GST_MATROSKA_READ_STATE_DATA) {
+      GST_DEBUG_OBJECT (demux, "not ready for seeking yet");
+      gst_event_unref (event);
+      return FALSE;
+    }
+    res = gst_matroska_demux_handle_seek_event (demux, NULL, event);
+  } else {
+    GST_WARNING_OBJECT (demux, "Unhandled event of type %s",
+        GST_EVENT_TYPE_NAME (event));
+    res = FALSE;
+  }
+  gst_event_unref (event);
+  return res;
+}
+
+static gboolean
+gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux,
+    GstMatroskaIndex * entry, gboolean reset, gboolean update)
+{
+  gint i;
+
+  GST_OBJECT_LOCK (demux);
+
+  if (update) {
+    /* seek (relative to matroska segment) */
+    /* position might be invalid; will error when streaming resumes ... */
+    demux->common.offset = entry->pos + demux->common.ebml_segment_start;
+    demux->next_cluster_offset = 0;
+
+    GST_DEBUG_OBJECT (demux,
+        "Seeked to offset %" G_GUINT64_FORMAT ", block %d, " "time %"
+        GST_TIME_FORMAT, entry->pos + demux->common.ebml_segment_start,
+        entry->block, GST_TIME_ARGS (entry->time));
+
+    /* update the time */
+    gst_matroska_read_common_reset_streams (&demux->common, entry->time, TRUE);
+    gst_flow_combiner_reset (demux->flowcombiner);
+    demux->common.segment.position = entry->time;
+    demux->seek_block = entry->block;
+    demux->seek_first = TRUE;
+    demux->last_stop_end = GST_CLOCK_TIME_NONE;
+  }
+
+  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;
+    } else {
+      if (stream->from_offset != -1)
+        stream->to_offset = stream->from_offset;
+    }
+    stream->from_offset = -1;
+    stream->from_time = GST_CLOCK_TIME_NONE;
+  }
+
+  GST_OBJECT_UNLOCK (demux);
+
+  return TRUE;
+}
+
+static gint
+gst_matroska_cluster_compare (gint64 * i1, gint64 * i2)
+{
+  if (*i1 < *i2)
+    return -1;
+  else if (*i1 > *i2)
+    return 1;
+  else
+    return 0;
+}
+
+/* searches for a cluster start from @pos,
+ * return GST_FLOW_OK and cluster position in @pos if found */
+static GstFlowReturn
+gst_matroska_demux_search_cluster (GstMatroskaDemux * demux, gint64 * pos,
+    gboolean forward)
+{
+  gint64 newpos = *pos;
+  gint64 orig_offset;
+  GstFlowReturn ret = GST_FLOW_OK;
+  const guint chunk = 128 * 1024;
+  GstBuffer *buf = NULL;
+  GstMapInfo map;
+  gpointer data = NULL;
+  gsize size;
+  guint64 length;
+  guint32 id;
+  guint needed;
+  gint64 oldpos, oldlength;
+
+  orig_offset = demux->common.offset;
+
+  GST_LOG_OBJECT (demux, "searching cluster %s offset %" G_GINT64_FORMAT,
+      forward ? "following" : "preceding", *pos);
+
+  if (demux->clusters) {
+    gint64 *cpos;
+
+    cpos = gst_util_array_binary_search (demux->clusters->data,
+        demux->clusters->len, sizeof (gint64),
+        (GCompareDataFunc) gst_matroska_cluster_compare,
+        forward ? GST_SEARCH_MODE_AFTER : GST_SEARCH_MODE_BEFORE, pos, NULL);
+    /* sanity check */
+    if (cpos) {
+      GST_DEBUG_OBJECT (demux,
+          "cluster reported at offset %" G_GINT64_FORMAT, *cpos);
+      demux->common.offset = *cpos;
+      ret = gst_matroska_read_common_peek_id_length_pull (&demux->common,
+          GST_ELEMENT_CAST (demux), &id, &length, &needed);
+      if (ret == GST_FLOW_OK && id == GST_MATROSKA_ID_CLUSTER) {
+        newpos = *cpos;
+        goto exit;
+      }
+    }
+  }
+
+  /* read in at newpos and scan for ebml cluster id */
+  oldpos = oldlength = -1;
+  while (1) {
+    GstByteReader reader;
+    gint cluster_pos;
+    guint toread = chunk;
+
+    if (!forward) {
+      /* never read beyond the requested target */
+      if (G_UNLIKELY (newpos < chunk)) {
+        toread = newpos;
+        newpos = 0;
+      } else {
+        newpos -= chunk;
+      }
+    }
+    if (buf != NULL) {
+      gst_buffer_unmap (buf, &map);
+      gst_buffer_unref (buf);
+      buf = NULL;
+    }
+    ret = gst_pad_pull_range (demux->common.sinkpad, newpos, toread, &buf);
+    if (ret != GST_FLOW_OK)
+      break;
+    GST_DEBUG_OBJECT (demux,
+        "read buffer size %" G_GSIZE_FORMAT " at offset %" G_GINT64_FORMAT,
+        gst_buffer_get_size (buf), newpos);
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    data = map.data;
+    size = map.size;
+    if (oldpos == newpos && oldlength == map.size) {
+      GST_ERROR_OBJECT (demux, "Stuck at same position");
+      ret = GST_FLOW_ERROR;
+      goto exit;
+    } else {
+      oldpos = newpos;
+      oldlength = map.size;
+    }
+
+    gst_byte_reader_init (&reader, data, size);
+    cluster_pos = -1;
+    while (1) {
+      gint found = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff,
+          GST_MATROSKA_ID_CLUSTER, 0, gst_byte_reader_get_remaining (&reader));
+      if (forward) {
+        cluster_pos = found;
+        break;
+      }
+      /* need last occurrence when searching backwards */
+      if (found >= 0) {
+        cluster_pos = gst_byte_reader_get_pos (&reader) + found;
+        gst_byte_reader_skip (&reader, found + 4);
+      } else {
+        break;
+      }
+    }
+
+    if (cluster_pos >= 0) {
+      newpos += cluster_pos;
+      GST_DEBUG_OBJECT (demux,
+          "found cluster ebml id at offset %" G_GINT64_FORMAT, newpos);
+      /* extra checks whether we really sync'ed to a cluster:
+       * - either it is the first and only cluster
+       * - either there is a cluster after this one
+       * - either cluster length is undefined
+       */
+      /* ok if first cluster (there may not a subsequent one) */
+      if (newpos == demux->first_cluster_offset) {
+        GST_DEBUG_OBJECT (demux, "cluster is first cluster -> OK");
+        break;
+      }
+      demux->common.offset = newpos;
+      ret = gst_matroska_read_common_peek_id_length_pull (&demux->common,
+          GST_ELEMENT_CAST (demux), &id, &length, &needed);
+      if (ret != GST_FLOW_OK) {
+        GST_DEBUG_OBJECT (demux, "need more data -> continue");
+        goto next;
+      }
+      g_assert (id == GST_MATROSKA_ID_CLUSTER);
+      GST_DEBUG_OBJECT (demux, "cluster size %" G_GUINT64_FORMAT ", prefix %d",
+          length, needed);
+      /* ok if undefined length or first cluster */
+      if (length == GST_EBML_SIZE_UNKNOWN || length == G_MAXUINT64) {
+        GST_DEBUG_OBJECT (demux, "cluster has undefined length -> OK");
+        break;
+      }
+      /* skip cluster */
+      demux->common.offset += length + needed;
+      ret = gst_matroska_read_common_peek_id_length_pull (&demux->common,
+          GST_ELEMENT_CAST (demux), &id, &length, &needed);
+      if (ret != GST_FLOW_OK)
+        goto next;
+      GST_DEBUG_OBJECT (demux, "next element is %scluster",
+          id == GST_MATROSKA_ID_CLUSTER ? "" : "not ");
+      if (id == GST_MATROSKA_ID_CLUSTER)
+        break;
+    next:
+      if (forward)
+        newpos += 1;
+    } else {
+      /* partial cluster id may have been in tail of buffer */
+      newpos +=
+          forward ? MAX (gst_byte_reader_get_remaining (&reader), 4) - 3 : 3;
+    }
+  }
+
+  if (buf) {
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    buf = NULL;
+  }
+
+exit:
+  demux->common.offset = orig_offset;
+  *pos = newpos;
+  return ret;
+}
+
+/* bisect and scan through file for cluster starting before @time,
+ * returns fake index entry with corresponding info on cluster */
+static GstMatroskaIndex *
+gst_matroska_demux_search_pos (GstMatroskaDemux * demux, GstClockTime time)
+{
+  GstMatroskaIndex *entry = NULL;
+  GstMatroskaReadState current_state;
+  GstClockTime otime, prev_cluster_time, current_cluster_time, cluster_time;
+  GstClockTime atime;
+  gint64 opos, newpos, current_offset;
+  gint64 prev_cluster_offset = -1, current_cluster_offset, cluster_offset;
+  gint64 apos, maxpos;
+  guint64 cluster_size = 0;
+  GstFlowReturn ret;
+  guint64 length;
+  guint32 id;
+  guint needed;
+
+  /* estimate new position, resync using cluster ebml id,
+   * and bisect further or scan forward to appropriate cluster */
+
+  /* store some current state */
+  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->common.offset;
+
+  demux->common.state = GST_MATROSKA_READ_STATE_SCANNING;
+
+  /* estimate using start and last known cluster */
+  GST_OBJECT_LOCK (demux);
+  apos = demux->first_cluster_offset;
+  atime = demux->stream_start_time;
+  opos = demux->last_cluster_offset;
+  otime = demux->stream_last_time;
+  GST_OBJECT_UNLOCK (demux);
+
+  /* sanitize */
+  time = MAX (time, atime);
+  otime = MAX (otime, atime);
+  opos = MAX (opos, apos);
+
+  maxpos = gst_matroska_read_common_get_length (&demux->common);
+
+  /* invariants;
+   * apos <= opos
+   * atime <= otime
+   * apos always refer to a cluster before target time;
+   * opos may or may not be after target time, but if it is once so,
+   * then also in next iteration
+   * */
+
+retry:
+  GST_LOG_OBJECT (demux,
+      "apos: %" G_GUINT64_FORMAT ", atime: %" GST_TIME_FORMAT ", %"
+      GST_TIME_FORMAT " in stream time, "
+      "opos: %" G_GUINT64_FORMAT ", otime: %" GST_TIME_FORMAT ", %"
+      GST_TIME_FORMAT " in stream time (start %" GST_TIME_FORMAT "), time %"
+      GST_TIME_FORMAT, apos, GST_TIME_ARGS (atime),
+      GST_TIME_ARGS (atime - demux->stream_start_time), opos,
+      GST_TIME_ARGS (otime), GST_TIME_ARGS (otime - demux->stream_start_time),
+      GST_TIME_ARGS (demux->stream_start_time), GST_TIME_ARGS (time));
+
+  g_assert (atime <= otime);
+  g_assert (apos <= opos);
+  if (time == GST_CLOCK_TIME_NONE) {
+    GST_DEBUG_OBJECT (demux, "searching last cluster");
+    newpos = maxpos;
+    if (newpos == -1) {
+      GST_DEBUG_OBJECT (demux, "unknown file size; bailing out");
+      goto exit;
+    }
+  } else if (otime <= atime) {
+    newpos = apos;
+  } else {
+    newpos = apos +
+        gst_util_uint64_scale (opos - apos, time - atime, otime - atime);
+    if (maxpos != -1 && newpos > maxpos)
+      newpos = maxpos;
+  }
+
+  GST_DEBUG_OBJECT (demux,
+      "estimated offset for %" GST_TIME_FORMAT ": %" G_GINT64_FORMAT,
+      GST_TIME_ARGS (time), newpos);
+
+  /* search backwards */
+  if (newpos > apos) {
+    ret = gst_matroska_demux_search_cluster (demux, &newpos, FALSE);
+    if (ret != GST_FLOW_OK)
+      goto exit;
+  }
+
+  /* then start scanning and parsing for cluster time,
+   * re-estimate if possible, otherwise next cluster and so on */
+  /* note that each re-estimate is entered with a change in apos or opos,
+   * avoiding infinite loop */
+  demux->common.offset = newpos;
+  demux->cluster_time = cluster_time = GST_CLOCK_TIME_NONE;
+  cluster_size = 0;
+  prev_cluster_time = GST_CLOCK_TIME_NONE;
+  while (1) {
+    /* peek and parse some elements */
+    ret = gst_matroska_read_common_peek_id_length_pull (&demux->common,
+        GST_ELEMENT_CAST (demux), &id, &length, &needed);
+    if (ret != GST_FLOW_OK)
+      goto error;
+    GST_LOG_OBJECT (demux, "Offset %" G_GUINT64_FORMAT ", Element id 0x%x, "
+        "size %" G_GUINT64_FORMAT ", needed %d", demux->common.offset, id,
+        length, needed);
+    ret = gst_matroska_demux_parse_id (demux, id, length, needed);
+    if (ret != GST_FLOW_OK)
+      goto error;
+
+    if (id == GST_MATROSKA_ID_CLUSTER) {
+      cluster_time = GST_CLOCK_TIME_NONE;
+      if (length == G_MAXUINT64)
+        cluster_size = 0;
+      else
+        cluster_size = length + needed;
+    }
+    if (demux->cluster_time != GST_CLOCK_TIME_NONE &&
+        cluster_time == GST_CLOCK_TIME_NONE) {
+      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,
+          GST_TIME_ARGS (cluster_time));
+      if (time == GST_CLOCK_TIME_NONE) {
+        GST_DEBUG_OBJECT (demux, "found last cluster");
+        prev_cluster_time = cluster_time;
+        prev_cluster_offset = cluster_offset;
+        break;
+      }
+      if (cluster_time > time) {
+        GST_DEBUG_OBJECT (demux, "overshot target");
+        /* cluster overshoots */
+        if (cluster_offset == demux->first_cluster_offset) {
+          /* but no prev one */
+          GST_DEBUG_OBJECT (demux, "but using first cluster anyway");
+          prev_cluster_time = cluster_time;
+          prev_cluster_offset = cluster_offset;
+          break;
+        }
+        if (prev_cluster_time != GST_CLOCK_TIME_NONE) {
+          /* prev cluster did not overshoot, so prev cluster is target */
+          break;
+        } else {
+          /* re-estimate using this new position info */
+          opos = cluster_offset;
+          otime = cluster_time;
+          goto retry;
+        }
+      } else {
+        /* cluster undershoots */
+        GST_DEBUG_OBJECT (demux, "undershot target");
+        /* ok if close enough */
+        if (GST_CLOCK_DIFF (cluster_time, time) < 5 * GST_SECOND) {
+          GST_DEBUG_OBJECT (demux, "target close enough");
+          prev_cluster_time = cluster_time;
+          prev_cluster_offset = cluster_offset;
+          break;
+        }
+        if (otime > time) {
+          /* we are in between atime and otime => can bisect if worthwhile */
+          if (prev_cluster_time != GST_CLOCK_TIME_NONE &&
+              cluster_time > prev_cluster_time &&
+              (GST_CLOCK_DIFF (prev_cluster_time, cluster_time) * 10 <
+                  GST_CLOCK_DIFF (cluster_time, time))) {
+            /* we moved at least one cluster forward,
+             * and it looks like target is still far away,
+             * let's estimate again */
+            GST_DEBUG_OBJECT (demux, "bisecting with new apos");
+            apos = cluster_offset;
+            atime = cluster_time;
+            goto retry;
+          }
+        }
+        /* cluster undershoots, goto next one */
+        prev_cluster_time = cluster_time;
+        prev_cluster_offset = cluster_offset;
+        /* skip cluster if length is defined,
+         * otherwise will be skippingly parsed into */
+        if (cluster_size) {
+          GST_DEBUG_OBJECT (demux, "skipping to next cluster");
+          demux->common.offset = cluster_offset + cluster_size;
+          demux->cluster_time = GST_CLOCK_TIME_NONE;
+        } else {
+          GST_DEBUG_OBJECT (demux, "parsing/skipping cluster elements");
+        }
+      }
+    }
+    continue;
+
+  error:
+    if (ret == GST_FLOW_EOS) {
+      if (prev_cluster_time != GST_CLOCK_TIME_NONE)
+        break;
+    }
+    goto exit;
+  }
+
+  entry = g_new0 (GstMatroskaIndex, 1);
+  entry->time = prev_cluster_time;
+  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);
+
+exit:
+
+  /* restore some state */
+  demux->cluster_offset = current_cluster_offset;
+  demux->cluster_time = current_cluster_time;
+  demux->common.offset = current_offset;
+  demux->common.state = current_state;
+
+  return entry;
+}
+
+static gboolean
+gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
+    GstPad * pad, GstEvent * event)
+{
+  GstMatroskaIndex *entry = NULL;
+  GstMatroskaIndex scan_entry;
+  GstSeekFlags flags;
+  GstSeekType cur_type, stop_type;
+  GstFormat format;
+  gboolean flush, keyunit, before, after, snap_next;
+  gdouble rate;
+  gint64 cur, stop;
+  GstMatroskaTrackContext *track = NULL;
+  GstSegment seeksegment = { 0, };
+  gboolean update = TRUE;
+  gboolean pad_locked = FALSE;
+  guint32 seqnum;
+  GstSearchMode snap_dir;
+
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  if (pad)
+    track = gst_pad_get_element_private (pad);
+
+  GST_DEBUG_OBJECT (demux, "Have seek %" GST_PTR_FORMAT, event);
+
+  gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
+      &stop_type, &stop);
+  seqnum = gst_event_get_seqnum (event);
+
+  /* we can only seek on time */
+  if (format != GST_FORMAT_TIME) {
+    GST_DEBUG_OBJECT (demux, "Can only seek on TIME");
+    return FALSE;
+  }
+
+  /* copy segment, we need this because we still need the old
+   * segment when we close the current segment. */
+  memcpy (&seeksegment, &demux->common.segment, sizeof (GstSegment));
+
+  /* pull mode without index means that the actual duration is not known,
+   * we might be playing a file that's still being recorded
+   * so, invalidate our current duration, which is only a moving target,
+   * and should not be used to clamp anything */
+  if (!demux->streaming && !demux->common.index && demux->invalid_duration) {
+    seeksegment.duration = GST_CLOCK_TIME_NONE;
+  }
+
+  GST_DEBUG_OBJECT (demux, "configuring seek");
+  /* Subtract stream_start_time so we always seek on a segment
+   * in stream time */
+  if (GST_CLOCK_TIME_IS_VALID (demux->stream_start_time)) {
+    seeksegment.start -= demux->stream_start_time;
+    seeksegment.position -= demux->stream_start_time;
+    if (GST_CLOCK_TIME_IS_VALID (seeksegment.stop))
+      seeksegment.stop -= demux->stream_start_time;
+    else
+      seeksegment.stop = seeksegment.duration;
+  }
+
+  gst_segment_do_seek (&seeksegment, rate, format, flags,
+      cur_type, cur, stop_type, stop, &update);
+
+  /* Restore the clip timestamp offset */
+  if (GST_CLOCK_TIME_IS_VALID (demux->stream_start_time)) {
+    seeksegment.position += demux->stream_start_time;
+    seeksegment.start += demux->stream_start_time;
+    if (!GST_CLOCK_TIME_IS_VALID (seeksegment.stop))
+      seeksegment.stop = seeksegment.duration;
+    if (GST_CLOCK_TIME_IS_VALID (seeksegment.stop))
+      seeksegment.stop += demux->stream_start_time;
+  }
+
+  /* restore segment duration (if any effect),
+   * would be determined again when parsing, but anyway ... */
+  seeksegment.duration = demux->common.segment.duration;
+
+  flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
+  keyunit = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
+  after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
+  before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
+
+  /* always do full update if flushing,
+   * otherwise problems might arise downstream with missing keyframes etc */
+  update = update || flush;
+
+  GST_DEBUG_OBJECT (demux, "New segment %" GST_SEGMENT_FORMAT, &seeksegment);
+
+  /* check sanity before we start flushing and all that */
+  snap_next = after && !before;
+  if (seeksegment.rate < 0)
+    snap_dir = snap_next ? GST_SEARCH_MODE_BEFORE : GST_SEARCH_MODE_AFTER;
+  else
+    snap_dir = snap_next ? GST_SEARCH_MODE_AFTER : GST_SEARCH_MODE_BEFORE;
+
+  GST_OBJECT_LOCK (demux);
+  track = gst_matroska_read_common_get_seek_track (&demux->common, track);
+  if ((entry = gst_matroska_read_common_do_index_seek (&demux->common, track,
+              seeksegment.position, &demux->seek_index, &demux->seek_entry,
+              snap_dir)) == NULL) {
+    /* pull mode without index can scan later on */
+    if (demux->streaming) {
+      GST_DEBUG_OBJECT (demux, "No matching seek entry in index");
+      GST_OBJECT_UNLOCK (demux);
+      return FALSE;
+    } else if (rate < 0.0) {
+      /* FIXME: We should build an index during playback or when scanning
+       * that can be used here. The reverse playback code requires seek_index
+       * and seek_entry to be set!
+       */
+      GST_DEBUG_OBJECT (demux,
+          "No matching seek entry in index, needed for reverse playback");
+      GST_OBJECT_UNLOCK (demux);
+      return FALSE;
+    }
+  }
+  GST_DEBUG_OBJECT (demux, "Seek position looks sane");
+  GST_OBJECT_UNLOCK (demux);
+
+  if (!update) {
+    /* only have to update some segment,
+     * but also still have to honour flush and so on */
+    GST_DEBUG_OBJECT (demux, "... no update");
+    /* bad goto, bad ... */
+    goto next;
+  }
+
+  if (demux->streaming)
+    goto finish;
+
+next:
+  if (flush) {
+    GstEvent *flush_event = gst_event_new_flush_start ();
+    gst_event_set_seqnum (flush_event, seqnum);
+    GST_DEBUG_OBJECT (demux, "Starting flush");
+    gst_pad_push_event (demux->common.sinkpad, gst_event_ref (flush_event));
+    gst_matroska_demux_send_event (demux, flush_event);
+  } else {
+    GST_DEBUG_OBJECT (demux, "Non-flushing seek, pausing task");
+    gst_pad_pause_task (demux->common.sinkpad);
+  }
+  /* ouch */
+  if (!update) {
+    GST_PAD_STREAM_LOCK (demux->common.sinkpad);
+    pad_locked = TRUE;
+    goto exit;
+  }
+
+  /* now grab the stream lock so that streaming cannot continue, for
+   * non flushing seeks when the element is in PAUSED this could block
+   * forever. */
+  GST_DEBUG_OBJECT (demux, "Waiting for streaming to stop");
+  GST_PAD_STREAM_LOCK (demux->common.sinkpad);
+  pad_locked = TRUE;
+
+  /* pull mode without index can do some scanning */
+  if (!demux->streaming && !entry) {
+    GstEvent *flush_event;
+
+    /* need to stop flushing upstream as we need it next */
+    if (flush) {
+      flush_event = gst_event_new_flush_stop (TRUE);
+      gst_event_set_seqnum (flush_event, seqnum);
+      gst_pad_push_event (demux->common.sinkpad, flush_event);
+    }
+    entry = gst_matroska_demux_search_pos (demux, seeksegment.position);
+    /* keep local copy */
+    if (entry) {
+      scan_entry = *entry;
+      g_free (entry);
+      entry = &scan_entry;
+    } else {
+      GST_DEBUG_OBJECT (demux, "Scan failed to find matching position");
+      if (flush) {
+        flush_event = gst_event_new_flush_stop (TRUE);
+        gst_event_set_seqnum (flush_event, seqnum);
+        gst_matroska_demux_send_event (demux, flush_event);
+      }
+      goto seek_error;
+    }
+  }
+
+finish:
+  if (keyunit && seeksegment.rate > 0) {
+    GST_DEBUG_OBJECT (demux, "seek to key unit, adjusting segment start from %"
+        GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (seeksegment.start), GST_TIME_ARGS (entry->time));
+    seeksegment.start = MAX (entry->time, demux->stream_start_time);
+    seeksegment.position = seeksegment.start;
+    seeksegment.time = seeksegment.start - demux->stream_start_time;
+  } else if (keyunit) {
+    GST_DEBUG_OBJECT (demux, "seek to key unit, adjusting segment stop from %"
+        GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (seeksegment.stop), GST_TIME_ARGS (entry->time));
+    seeksegment.stop = MAX (entry->time, demux->stream_start_time);
+    seeksegment.position = seeksegment.stop;
+  }
+
+  if (demux->streaming) {
+    GST_OBJECT_LOCK (demux);
+    /* track real position we should start at */
+    GST_DEBUG_OBJECT (demux, "storing segment start");
+    demux->requested_seek_time = seeksegment.position;
+    demux->seek_offset = entry->pos + demux->common.ebml_segment_start;
+    GST_OBJECT_UNLOCK (demux);
+    /* 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 (demux, rate,
+        entry->pos + demux->common.ebml_segment_start, seqnum, flags);
+  }
+
+exit:
+  if (flush) {
+    GstEvent *flush_event = gst_event_new_flush_stop (TRUE);
+    gst_event_set_seqnum (flush_event, seqnum);
+    GST_DEBUG_OBJECT (demux, "Stopping flush");
+    gst_pad_push_event (demux->common.sinkpad, gst_event_ref (flush_event));
+    gst_matroska_demux_send_event (demux, flush_event);
+  }
+
+  GST_OBJECT_LOCK (demux);
+  /* now update the real segment info */
+  GST_DEBUG_OBJECT (demux, "Committing new seek segment");
+  memcpy (&demux->common.segment, &seeksegment, sizeof (GstSegment));
+  GST_OBJECT_UNLOCK (demux);
+
+  /* update some (segment) state */
+  if (!gst_matroska_demux_move_to_entry (demux, entry, TRUE, update))
+    goto seek_error;
+
+  /* notify start of new segment */
+  if (demux->common.segment.flags & GST_SEEK_FLAG_SEGMENT) {
+    GstMessage *msg;
+
+    msg = gst_message_new_segment_start (GST_OBJECT (demux),
+        GST_FORMAT_TIME, demux->common.segment.start);
+    gst_message_set_seqnum (msg, seqnum);
+    gst_element_post_message (GST_ELEMENT (demux), msg);
+  }
+
+  GST_OBJECT_LOCK (demux);
+  if (demux->new_segment)
+    gst_event_unref (demux->new_segment);
+
+  /* On port from 0.10, discarded !update (for segment.update) here, FIXME? */
+  demux->new_segment = gst_event_new_segment (&demux->common.segment);
+  gst_event_set_seqnum (demux->new_segment, seqnum);
+  if (demux->common.segment.rate < 0 && demux->common.segment.stop == -1)
+    demux->to_time = demux->common.segment.position;
+  else
+    demux->to_time = GST_CLOCK_TIME_NONE;
+  demux->segment_seqnum = seqnum;
+  GST_OBJECT_UNLOCK (demux);
+
+  /* restart our task since it might have been stopped when we did the
+   * flush. */
+  gst_pad_start_task (demux->common.sinkpad,
+      (GstTaskFunction) gst_matroska_demux_loop, demux->common.sinkpad, NULL);
+
+  /* streaming can continue now */
+  if (pad_locked) {
+    GST_PAD_STREAM_UNLOCK (demux->common.sinkpad);
+  }
+
+  return TRUE;
+
+seek_error:
+  {
+    if (pad_locked) {
+      GST_PAD_STREAM_UNLOCK (demux->common.sinkpad);
+    }
+    GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("Got a seek error"));
+    return FALSE;
+  }
+}
+
+/*
+ * Handle whether we can perform the seek event or if we have to let the chain
+ * function handle seeks to build the seek indexes first.
+ */
+static gboolean
+gst_matroska_demux_handle_seek_push (GstMatroskaDemux * demux, GstPad * pad,
+    GstEvent * event)
+{
+  GstSeekFlags flags;
+  GstSeekType cur_type, stop_type;
+  GstFormat format;
+  gdouble rate;
+  gint64 cur, stop;
+
+  gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
+      &stop_type, &stop);
+
+  /* sanity checks */
+
+  /* we can only seek on time */
+  if (format != GST_FORMAT_TIME) {
+    GST_DEBUG_OBJECT (demux, "Can only seek on TIME");
+    return FALSE;
+  }
+
+  if (stop_type != GST_SEEK_TYPE_NONE && stop != GST_CLOCK_TIME_NONE) {
+    GST_DEBUG_OBJECT (demux, "Seek end-time not supported in streaming mode");
+    return FALSE;
+  }
+
+  if (!(flags & GST_SEEK_FLAG_FLUSH)) {
+    GST_DEBUG_OBJECT (demux,
+        "Non-flushing seek not supported in streaming mode");
+    return FALSE;
+  }
+
+  if (flags & GST_SEEK_FLAG_SEGMENT) {
+    GST_DEBUG_OBJECT (demux, "Segment seek not supported in streaming mode");
+    return FALSE;
+  }
+
+  /* check for having parsed index already */
+  if (!demux->common.index_parsed) {
+    gboolean building_index;
+    guint64 offset = 0;
+
+    if (!demux->index_offset) {
+      GST_DEBUG_OBJECT (demux, "no index (location); no seek in push mode");
+      return FALSE;
+    }
+
+    GST_OBJECT_LOCK (demux);
+    /* handle the seek event in the chain function */
+    demux->common.state = GST_MATROSKA_READ_STATE_SEEK;
+    /* no more seek can be issued until state reset to _DATA */
+
+    /* copy the event */
+    if (demux->seek_event)
+      gst_event_unref (demux->seek_event);
+    demux->seek_event = gst_event_ref (event);
+
+    /* set the building_index flag so that only one thread can setup the
+     * structures for index seeking. */
+    building_index = demux->building_index;
+    if (!building_index) {
+      demux->building_index = TRUE;
+      offset = demux->index_offset;
+    }
+    GST_OBJECT_UNLOCK (demux);
+
+    if (!building_index) {
+      /* seek to the first subindex or legacy index */
+      GST_INFO_OBJECT (demux, "Seeking to Cues at %" G_GUINT64_FORMAT, offset);
+      return perform_seek_to_offset (demux, rate, offset,
+          gst_event_get_seqnum (event), GST_SEEK_FLAG_NONE);
+    }
+
+    /* well, we are handling it already */
+    return TRUE;
+  }
+
+  /* delegate to tweaked regular seek */
+  return gst_matroska_demux_handle_seek_event (demux, pad, event);
+}
+
+static gboolean
+gst_matroska_demux_handle_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (parent);
+  gboolean res = TRUE;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+      /* no seeking until we are (safely) ready */
+      if (demux->common.state != GST_MATROSKA_READ_STATE_DATA) {
+        GST_DEBUG_OBJECT (demux, "not ready for seeking yet");
+        gst_event_unref (event);
+        return FALSE;
+      }
+
+      {
+        guint32 seqnum = gst_event_get_seqnum (event);
+        if (seqnum == demux->segment_seqnum) {
+          GST_LOG_OBJECT (pad,
+              "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
+          gst_event_unref (event);
+          return TRUE;
+        }
+      }
+
+      if (!demux->streaming)
+        res = gst_matroska_demux_handle_seek_event (demux, pad, event);
+      else
+        res = gst_matroska_demux_handle_seek_push (demux, pad, event);
+      gst_event_unref (event);
+      break;
+
+    case GST_EVENT_QOS:
+    {
+      GstMatroskaTrackContext *context = gst_pad_get_element_private (pad);
+      if (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
+        GstMatroskaTrackVideoContext *videocontext =
+            (GstMatroskaTrackVideoContext *) context;
+        gdouble proportion;
+        GstClockTimeDiff diff;
+        GstClockTime timestamp;
+
+        gst_event_parse_qos (event, NULL, &proportion, &diff, &timestamp);
+
+        GST_OBJECT_LOCK (demux);
+        videocontext->earliest_time = timestamp + diff;
+        GST_OBJECT_UNLOCK (demux);
+      }
+      res = TRUE;
+      gst_event_unref (event);
+      break;
+    }
+
+    case GST_EVENT_TOC_SELECT:
+    {
+      char *uid = NULL;
+      GstTocEntry *entry = NULL;
+      GstEvent *seek_event;
+      gint64 start_pos;
+
+      if (!demux->common.toc) {
+        GST_DEBUG_OBJECT (demux, "no TOC to select");
+        return FALSE;
+      } else {
+        gst_event_parse_toc_select (event, &uid);
+        if (uid != NULL) {
+          GST_OBJECT_LOCK (demux);
+          entry = gst_toc_find_entry (demux->common.toc, uid);
+          if (entry == NULL) {
+            GST_OBJECT_UNLOCK (demux);
+            GST_WARNING_OBJECT (demux, "no TOC entry with given UID: %s", uid);
+            res = FALSE;
+          } else {
+            gst_toc_entry_get_start_stop_times (entry, &start_pos, NULL);
+            GST_OBJECT_UNLOCK (demux);
+            seek_event = gst_event_new_seek (1.0,
+                GST_FORMAT_TIME,
+                GST_SEEK_FLAG_FLUSH,
+                GST_SEEK_TYPE_SET, start_pos, GST_SEEK_TYPE_SET, -1);
+            res = gst_matroska_demux_handle_seek_event (demux, pad, seek_event);
+            gst_event_unref (seek_event);
+          }
+          g_free (uid);
+        } else {
+          GST_WARNING_OBJECT (demux, "received empty TOC select event");
+          res = FALSE;
+        }
+      }
+      gst_event_unref (event);
+      break;
+    }
+
+      /* events we don't need to handle */
+    case GST_EVENT_NAVIGATION:
+      gst_event_unref (event);
+      res = FALSE;
+      break;
+
+    case GST_EVENT_LATENCY:
+    default:
+      res = gst_pad_push_event (demux->common.sinkpad, event);
+      break;
+  }
+
+  return res;
+}
+
+static GstFlowReturn
+gst_matroska_demux_seek_to_previous_keyframe (GstMatroskaDemux * demux)
+{
+  GstFlowReturn ret = GST_FLOW_EOS;
+  gboolean done = TRUE;
+  gint i;
+
+  g_return_val_if_fail (demux->seek_index, GST_FLOW_EOS);
+  g_return_val_if_fail (demux->seek_entry < demux->seek_index->len,
+      GST_FLOW_EOS);
+
+  GST_DEBUG_OBJECT (demux, "locating previous keyframe");
+
+  if (!demux->seek_entry) {
+    GST_DEBUG_OBJECT (demux, "no earlier index entry");
+    goto exit;
+  }
+
+  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,
+        GST_TIME_ARGS (demux->common.segment.start), stream->index,
+        GST_TIME_ARGS (stream->from_time));
+    if (GST_CLOCK_TIME_IS_VALID (stream->from_time)) {
+      if (stream->from_time > demux->common.segment.start) {
+        GST_DEBUG_OBJECT (demux, "stream %d not finished yet", stream->index);
+        done = FALSE;
+      }
+    } else {
+      /* nothing pushed for this stream;
+       * likely seek entry did not start at keyframe, so all was skipped.
+       * So we need an earlier entry */
+      done = FALSE;
+    }
+  }
+
+  if (!done) {
+    GstMatroskaIndex *entry;
+
+    entry = &g_array_index (demux->seek_index, GstMatroskaIndex,
+        --demux->seek_entry);
+    if (!gst_matroska_demux_move_to_entry (demux, entry, FALSE, TRUE))
+      goto exit;
+
+    ret = GST_FLOW_OK;
+  }
+
+exit:
+  return ret;
+}
+
+static GstFlowReturn
+gst_matroska_demux_parse_tracks (GstMatroskaDemux * demux, GstEbmlRead * ebml)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint32 id;
+
+  DEBUG_ELEMENT_START (demux, ebml, "Tracks");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (demux, ebml, "Tracks", 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 track within the "all-tracks" header */
+      case GST_MATROSKA_ID_TRACKENTRY:
+        ret = gst_matroska_demux_add_stream (demux, ebml);
+        break;
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "Track", id);
+        break;
+    }
+  }
+  DEBUG_ELEMENT_STOP (demux, ebml, "Tracks", ret);
+
+  demux->tracks_parsed = TRUE;
+
+  return ret;
+}
+
+/*
+ * Read signed/unsigned "EBML" numbers.
+ * Return: number of bytes processed.
+ */
+
+static gint
+gst_matroska_ebmlnum_uint (guint8 * data, guint size, guint64 * num)
+{
+  gint len_mask = 0x80, read = 1, n = 1, num_ffs = 0;
+  guint64 total;
+
+  if (size <= 0) {
+    return -1;
+  }
+
+  total = data[0];
+  while (read <= 8 && !(total & len_mask)) {
+    read++;
+    len_mask >>= 1;
+  }
+  if (read > 8)
+    return -1;
+
+  if ((total &= (len_mask - 1)) == len_mask - 1)
+    num_ffs++;
+  if (size < read)
+    return -1;
+  while (n < read) {
+    if (data[n] == 0xff)
+      num_ffs++;
+    total = (total << 8) | data[n];
+    n++;
+  }
+
+  if (read == num_ffs && total != 0)
+    *num = G_MAXUINT64;
+  else
+    *num = total;
+
+  return read;
+}
+
+static gint
+gst_matroska_ebmlnum_sint (guint8 * data, guint size, gint64 * num)
+{
+  guint64 unum;
+  gint res;
+
+  /* read as unsigned number first */
+  if ((res = gst_matroska_ebmlnum_uint (data, size, &unum)) < 0)
+    return -1;
+
+  /* make signed */
+  if (unum == G_MAXUINT64)
+    *num = G_MAXINT64;
+  else
+    *num = unum - ((1 << ((7 * res) - 1)) - 1);
+
+  return res;
+}
+
+/*
+ * Mostly used for subtitles. We add void filler data for each
+ * lagging stream to make sure we don't deadlock.
+ */
+
+static void
+gst_matroska_demux_sync_streams (GstMatroskaDemux * demux)
+{
+  GstClockTime gap_threshold;
+  gint stream_nr;
+
+  GST_OBJECT_LOCK (demux);
+
+  GST_LOG_OBJECT (demux, "Sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (demux->common.segment.position));
+
+  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->common.src, stream_nr);
+
+    GST_LOG_OBJECT (demux,
+        "Checking for resync on stream %d (%" GST_TIME_FORMAT ")", stream_nr,
+        GST_TIME_ARGS (context->pos));
+
+    /* Only send gap events on non-subtitle streams if lagging way behind.
+     * The 0.5 second threshold for subtitle streams is also quite random. */
+    if (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE)
+      gap_threshold = GST_SECOND / 2;
+    else
+      gap_threshold = 3 * GST_SECOND;
+
+    /* Lag need only be considered if we have advanced into requested segment */
+    if (GST_CLOCK_TIME_IS_VALID (context->pos) &&
+        GST_CLOCK_TIME_IS_VALID (demux->common.segment.position) &&
+        demux->common.segment.position > demux->common.segment.start &&
+        context->pos + gap_threshold < demux->common.segment.position) {
+
+      GstEvent *event;
+      guint64 start = context->pos;
+      guint64 stop = demux->common.segment.position - gap_threshold;
+
+      GST_DEBUG_OBJECT (demux,
+          "Synchronizing stream %d with other by advancing time from %"
+          GST_TIME_FORMAT " to %" GST_TIME_FORMAT, stream_nr,
+          GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
+
+      context->pos = stop;
+
+      event = gst_event_new_gap (start, stop - start);
+      GST_OBJECT_UNLOCK (demux);
+      gst_pad_push_event (context->pad, event);
+      GST_OBJECT_LOCK (demux);
+    }
+  }
+
+  GST_OBJECT_UNLOCK (demux);
+}
+
+static GstFlowReturn
+gst_matroska_demux_push_stream_headers (GstMatroskaDemux * demux,
+    GstMatroskaTrackContext * stream)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  gint i, num;
+
+  num = gst_buffer_list_length (stream->stream_headers);
+  for (i = 0; i < num; ++i) {
+    GstBuffer *buf;
+
+    buf = gst_buffer_list_get (stream->stream_headers, i);
+    buf = gst_buffer_copy (buf);
+
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
+
+    if (stream->set_discont) {
+      GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+      stream->set_discont = FALSE;
+    } else {
+      GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
+    }
+
+    /* push out all headers in one go and use last flow return */
+    ret = gst_pad_push (stream->pad, buf);
+  }
+
+  /* don't need these any  longer */
+  gst_buffer_list_unref (stream->stream_headers);
+  stream->stream_headers = NULL;
+
+  /* combine flows */
+  ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
+
+  return ret;
+}
+
+static void
+gst_matroska_demux_push_dvd_clut_change_event (GstMatroskaDemux * demux,
+    GstMatroskaTrackContext * stream)
+{
+  gchar *buf, *start;
+
+  g_assert (!strcmp (stream->codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB));
+
+  if (!stream->codec_priv)
+    return;
+
+  /* ideally, VobSub private data should be parsed and stored more convenient
+   * elsewhere, but for now, only interested in a small part */
+
+  /* make sure we have terminating 0 */
+  buf = g_strndup (stream->codec_priv, stream->codec_priv_size);
+
+  /* just locate and parse palette part */
+  start = strstr (buf, "palette:");
+  if (start) {
+    gint i;
+    guint32 clut[16];
+    guint32 col;
+    guint8 r, g, b, y, u, v;
+
+    start += 8;
+    while (g_ascii_isspace (*start))
+      start++;
+    for (i = 0; i < 16; i++) {
+      if (sscanf (start, "%06x", &col) != 1)
+        break;
+      start += 6;
+      while ((*start == ',') || g_ascii_isspace (*start))
+        start++;
+      /* sigh, need to convert this from vobsub pseudo-RGB to YUV */
+      r = (col >> 16) & 0xff;
+      g = (col >> 8) & 0xff;
+      b = col & 0xff;
+      y = CLAMP ((0.1494 * r + 0.6061 * g + 0.2445 * b) * 219 / 255 + 16, 0,
+          255);
+      u = CLAMP (0.6066 * r - 0.4322 * g - 0.1744 * b + 128, 0, 255);
+      v = CLAMP (-0.08435 * r - 0.3422 * g + 0.4266 * b + 128, 0, 255);
+      clut[i] = (y << 16) | (u << 8) | v;
+    }
+
+    /* got them all without problems; build and send event */
+    if (i == 16) {
+      GstStructure *s;
+
+      s = gst_structure_new ("application/x-gst-dvd", "event", G_TYPE_STRING,
+          "dvd-spu-clut-change", "clut00", G_TYPE_INT, clut[0], "clut01",
+          G_TYPE_INT, clut[1], "clut02", G_TYPE_INT, clut[2], "clut03",
+          G_TYPE_INT, clut[3], "clut04", G_TYPE_INT, clut[4], "clut05",
+          G_TYPE_INT, clut[5], "clut06", G_TYPE_INT, clut[6], "clut07",
+          G_TYPE_INT, clut[7], "clut08", G_TYPE_INT, clut[8], "clut09",
+          G_TYPE_INT, clut[9], "clut10", G_TYPE_INT, clut[10], "clut11",
+          G_TYPE_INT, clut[11], "clut12", G_TYPE_INT, clut[12], "clut13",
+          G_TYPE_INT, clut[13], "clut14", G_TYPE_INT, clut[14], "clut15",
+          G_TYPE_INT, clut[15], NULL);
+
+      gst_pad_push_event (stream->pad,
+          gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_STICKY, s));
+    }
+  }
+  g_free (buf);
+}
+
+static void
+gst_matroska_demux_push_codec_data_all (GstMatroskaDemux * demux)
+{
+  gint 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 *stream;
+
+    stream = g_ptr_array_index (demux->common.src, stream_nr);
+
+    if (stream->send_stream_headers) {
+      if (stream->stream_headers != NULL) {
+        gst_matroska_demux_push_stream_headers (demux, stream);
+      } else {
+        /* FIXME: perhaps we can just disable and skip this stream then */
+        GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
+            ("Failed to extract stream headers from codec private data"));
+      }
+      stream->send_stream_headers = FALSE;
+    }
+
+    if (stream->send_dvd_event) {
+      gst_matroska_demux_push_dvd_clut_change_event (demux, stream);
+      /* FIXME: should we send this event again after (flushing) seek ? */
+      stream->send_dvd_event = FALSE;
+    }
+  }
+
+}
+
+static GstFlowReturn
+gst_matroska_demux_add_mpeg_seq_header (GstElement * element,
+    GstMatroskaTrackContext * stream, GstBuffer ** buf)
+{
+  guint8 *seq_header;
+  guint seq_header_len;
+  guint32 header, tmp;
+
+  if (stream->codec_state) {
+    seq_header = stream->codec_state;
+    seq_header_len = stream->codec_state_size;
+  } else if (stream->codec_priv) {
+    seq_header = stream->codec_priv;
+    seq_header_len = stream->codec_priv_size;
+  } else {
+    return GST_FLOW_OK;
+  }
+
+  /* Sequence header only needed for keyframes */
+  if (GST_BUFFER_FLAG_IS_SET (*buf, GST_BUFFER_FLAG_DELTA_UNIT))
+    return GST_FLOW_OK;
+
+  if (gst_buffer_get_size (*buf) < 4)
+    return GST_FLOW_OK;
+
+  gst_buffer_extract (*buf, 0, &tmp, sizeof (guint32));
+  header = GUINT32_FROM_BE (tmp);
+
+  /* Sequence start code, if not found prepend */
+  if (header != 0x000001b3) {
+    GstBuffer *newbuf;
+
+    GST_DEBUG_OBJECT (element, "Prepending MPEG sequence header");
+
+    newbuf = gst_buffer_new_wrapped (g_memdup (seq_header, seq_header_len),
+        seq_header_len);
+
+    gst_buffer_copy_into (newbuf, *buf, GST_BUFFER_COPY_TIMESTAMPS |
+        GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_MEMORY, 0,
+        gst_buffer_get_size (*buf));
+
+    gst_buffer_unref (*buf);
+    *buf = newbuf;
+  }
+
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_matroska_demux_add_wvpk_header (GstElement * element,
+    GstMatroskaTrackContext * stream, GstBuffer ** buf)
+{
+  GstMatroskaTrackAudioContext *audiocontext =
+      (GstMatroskaTrackAudioContext *) stream;
+  GstBuffer *newbuf = NULL;
+  GstMapInfo map, outmap;
+  guint8 *buf_data, *data;
+  Wavpack4Header wvh;
+
+  wvh.ck_id[0] = 'w';
+  wvh.ck_id[1] = 'v';
+  wvh.ck_id[2] = 'p';
+  wvh.ck_id[3] = 'k';
+
+  wvh.version = GST_READ_UINT16_LE (stream->codec_priv);
+  wvh.track_no = 0;
+  wvh.index_no = 0;
+  wvh.total_samples = -1;
+  wvh.block_index = audiocontext->wvpk_block_index;
+
+  if (audiocontext->channels <= 2) {
+    guint32 block_samples, tmp;
+    gsize size = gst_buffer_get_size (*buf);
+
+    gst_buffer_extract (*buf, 0, &tmp, sizeof (guint32));
+    block_samples = GUINT32_FROM_LE (tmp);
+    /* we need to reconstruct the header of the wavpack block */
+
+    /* -20 because ck_size is the size of the wavpack block -8
+     * and lace_size is the size of the wavpack block + 12
+     * (the three guint32 of the header that already are in the buffer) */
+    wvh.ck_size = size + sizeof (Wavpack4Header) - 20;
+
+    /* block_samples, flags and crc are already in the buffer */
+    newbuf = gst_buffer_new_allocate (NULL, sizeof (Wavpack4Header) - 12, NULL);
+
+    gst_buffer_map (newbuf, &outmap, GST_MAP_WRITE);
+    data = outmap.data;
+    data[0] = 'w';
+    data[1] = 'v';
+    data[2] = 'p';
+    data[3] = 'k';
+    GST_WRITE_UINT32_LE (data + 4, wvh.ck_size);
+    GST_WRITE_UINT16_LE (data + 8, wvh.version);
+    GST_WRITE_UINT8 (data + 10, wvh.track_no);
+    GST_WRITE_UINT8 (data + 11, wvh.index_no);
+    GST_WRITE_UINT32_LE (data + 12, wvh.total_samples);
+    GST_WRITE_UINT32_LE (data + 16, wvh.block_index);
+    gst_buffer_unmap (newbuf, &outmap);
+
+    /* Append data from buf: */
+    gst_buffer_copy_into (newbuf, *buf, GST_BUFFER_COPY_TIMESTAMPS |
+        GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_MEMORY, 0, size);
+
+    gst_buffer_unref (*buf);
+    *buf = newbuf;
+    audiocontext->wvpk_block_index += block_samples;
+  } else {
+    guint8 *outdata = NULL;
+    guint outpos = 0;
+    gsize buf_size, size, out_size = 0;
+    guint32 block_samples, flags, crc, blocksize;
+
+    gst_buffer_map (*buf, &map, GST_MAP_READ);
+    buf_data = map.data;
+    buf_size = map.size;
+
+    if (buf_size < 4) {
+      GST_ERROR_OBJECT (element, "Too small wavpack buffer");
+      gst_buffer_unmap (*buf, &map);
+      return GST_FLOW_ERROR;
+    }
+
+    data = buf_data;
+    size = buf_size;
+
+    block_samples = GST_READ_UINT32_LE (data);
+    data += 4;
+    size -= 4;
+
+    while (size > 12) {
+      flags = GST_READ_UINT32_LE (data);
+      data += 4;
+      size -= 4;
+      crc = GST_READ_UINT32_LE (data);
+      data += 4;
+      size -= 4;
+      blocksize = GST_READ_UINT32_LE (data);
+      data += 4;
+      size -= 4;
+
+      if (blocksize == 0 || size < blocksize)
+        break;
+
+      g_assert ((newbuf == NULL) == (outdata == NULL));
+
+      if (newbuf == NULL) {
+        out_size = sizeof (Wavpack4Header) + blocksize;
+        newbuf = gst_buffer_new_allocate (NULL, out_size, NULL);
+
+        gst_buffer_copy_into (newbuf, *buf,
+            GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS, 0, -1);
+
+        outpos = 0;
+        gst_buffer_map (newbuf, &outmap, GST_MAP_WRITE);
+        outdata = outmap.data;
+      } else {
+        gst_buffer_unmap (newbuf, &outmap);
+        out_size += sizeof (Wavpack4Header) + blocksize;
+        gst_buffer_set_size (newbuf, out_size);
+        gst_buffer_map (newbuf, &outmap, GST_MAP_WRITE);
+        outdata = outmap.data;
+      }
+
+      outdata[outpos] = 'w';
+      outdata[outpos + 1] = 'v';
+      outdata[outpos + 2] = 'p';
+      outdata[outpos + 3] = 'k';
+      outpos += 4;
+
+      GST_WRITE_UINT32_LE (outdata + outpos,
+          blocksize + sizeof (Wavpack4Header) - 8);
+      GST_WRITE_UINT16_LE (outdata + outpos + 4, wvh.version);
+      GST_WRITE_UINT8 (outdata + outpos + 6, wvh.track_no);
+      GST_WRITE_UINT8 (outdata + outpos + 7, wvh.index_no);
+      GST_WRITE_UINT32_LE (outdata + outpos + 8, wvh.total_samples);
+      GST_WRITE_UINT32_LE (outdata + outpos + 12, wvh.block_index);
+      GST_WRITE_UINT32_LE (outdata + outpos + 16, block_samples);
+      GST_WRITE_UINT32_LE (outdata + outpos + 20, flags);
+      GST_WRITE_UINT32_LE (outdata + outpos + 24, crc);
+      outpos += 28;
+
+      memmove (outdata + outpos, data, blocksize);
+      outpos += blocksize;
+      data += blocksize;
+      size -= blocksize;
+    }
+    gst_buffer_unmap (*buf, &map);
+    gst_buffer_unref (*buf);
+
+    if (newbuf)
+      gst_buffer_unmap (newbuf, &outmap);
+
+    *buf = newbuf;
+    audiocontext->wvpk_block_index += block_samples;
+  }
+
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_matroska_demux_add_prores_header (GstElement * element,
+    GstMatroskaTrackContext * stream, GstBuffer ** buf)
+{
+  GstBuffer *newbuf = gst_buffer_new_allocate (NULL, 8, NULL);
+  GstMapInfo map;
+  guint32 frame_size;
+
+  if (!gst_buffer_map (newbuf, &map, GST_MAP_WRITE)) {
+    GST_ERROR ("Failed to map newly allocated buffer");
+    return GST_FLOW_ERROR;
+  }
+
+  frame_size = gst_buffer_get_size (*buf);
+
+  GST_WRITE_UINT32_BE (map.data, frame_size);
+  map.data[4] = 'i';
+  map.data[5] = 'c';
+  map.data[6] = 'p';
+  map.data[7] = 'f';
+
+  gst_buffer_unmap (newbuf, &map);
+  *buf = gst_buffer_append (newbuf, *buf);
+
+  return GST_FLOW_OK;
+}
+
+/* @text must be null-terminated */
+static gboolean
+gst_matroska_demux_subtitle_chunk_has_tag (GstElement * element,
+    const gchar * text)
+{
+  gchar *tag;
+
+  g_return_val_if_fail (text != NULL, FALSE);
+
+  /* yes, this might all lead to false positives ... */
+  tag = (gchar *) text;
+  while ((tag = strchr (tag, '<'))) {
+    tag++;
+    if (*tag != '\0' && *(tag + 1) == '>') {
+      /* some common convenience ones */
+      /* maybe any character will do here ? */
+      switch (*tag) {
+        case 'b':
+        case 'i':
+        case 'u':
+        case 's':
+          return TRUE;
+        default:
+          return FALSE;
+      }
+    }
+  }
+
+  if (strstr (text, "<span"))
+    return TRUE;
+
+  return FALSE;
+}
+
+static GstFlowReturn
+gst_matroska_demux_check_subtitle_buffer (GstElement * element,
+    GstMatroskaTrackContext * stream, GstBuffer ** buf)
+{
+  GstMatroskaTrackSubtitleContext *sub_stream;
+  const gchar *encoding;
+  GError *err = NULL;
+  GstBuffer *newbuf;
+  gchar *utf8;
+  GstMapInfo map;
+  gboolean needs_unmap = TRUE;
+
+  sub_stream = (GstMatroskaTrackSubtitleContext *) stream;
+
+  if (!gst_buffer_get_size (*buf) || !gst_buffer_map (*buf, &map, GST_MAP_READ))
+    return GST_FLOW_OK;
+
+  /* The subtitle buffer we push out should not include a NUL terminator as
+   * part of the data. */
+  if (map.data[map.size - 1] == '\0') {
+    gst_buffer_set_size (*buf, map.size - 1);
+    gst_buffer_unmap (*buf, &map);
+    gst_buffer_map (*buf, &map, GST_MAP_READ);
+  }
+
+  if (!sub_stream->invalid_utf8) {
+    if (g_utf8_validate ((gchar *) map.data, map.size, NULL)) {
+      goto next;
+    }
+    GST_WARNING_OBJECT (element, "subtitle stream %" G_GUINT64_FORMAT
+        " is not valid UTF-8, this is broken according to the matroska"
+        " specification", stream->num);
+    sub_stream->invalid_utf8 = TRUE;
+  }
+
+  /* file with broken non-UTF8 subtitle, do the best we can do to fix it */
+  encoding = g_getenv ("GST_SUBTITLE_ENCODING");
+  if (encoding == NULL || *encoding == '\0') {
+    /* if local encoding is UTF-8 and no encoding specified
+     * via the environment variable, assume ISO-8859-15 */
+    if (g_get_charset (&encoding)) {
+      encoding = "ISO-8859-15";
+    }
+  }
+
+  utf8 =
+      g_convert_with_fallback ((gchar *) map.data, map.size, "UTF-8", encoding,
+      (char *) "*", NULL, NULL, &err);
+
+  if (err) {
+    GST_LOG_OBJECT (element, "could not convert string from '%s' to UTF-8: %s",
+        encoding, err->message);
+    g_error_free (err);
+    g_free (utf8);
+
+    /* invalid input encoding, fall back to ISO-8859-15 (always succeeds) */
+    encoding = "ISO-8859-15";
+    utf8 =
+        g_convert_with_fallback ((gchar *) map.data, map.size, "UTF-8",
+        encoding, (char *) "*", NULL, NULL, NULL);
+  }
+
+  GST_LOG_OBJECT (element, "converted subtitle text from %s to UTF-8 %s",
+      encoding, (err) ? "(using ISO-8859-15 as fallback)" : "");
+
+  if (utf8 == NULL)
+    utf8 = g_strdup ("invalid subtitle");
+
+  newbuf = gst_buffer_new_wrapped (utf8, strlen (utf8));
+  gst_buffer_unmap (*buf, &map);
+  gst_buffer_copy_into (newbuf, *buf,
+      GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_META,
+      0, -1);
+  gst_buffer_unref (*buf);
+
+  *buf = newbuf;
+  gst_buffer_map (*buf, &map, GST_MAP_READ);
+
+next:
+
+  if (sub_stream->check_markup) {
+    /* caps claim markup text, so we need to escape text,
+     * except if text is already markup and then needs no further escaping */
+    sub_stream->seen_markup_tag = sub_stream->seen_markup_tag ||
+        gst_matroska_demux_subtitle_chunk_has_tag (element, (gchar *) map.data);
+
+    if (!sub_stream->seen_markup_tag) {
+      utf8 = g_markup_escape_text ((gchar *) map.data, map.size);
+
+      newbuf = gst_buffer_new_wrapped (utf8, strlen (utf8));
+      gst_buffer_unmap (*buf, &map);
+      gst_buffer_copy_into (newbuf, *buf,
+          GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS |
+          GST_BUFFER_COPY_META, 0, -1);
+      gst_buffer_unref (*buf);
+
+      *buf = newbuf;
+      needs_unmap = FALSE;
+    }
+  }
+
+  if (needs_unmap)
+    gst_buffer_unmap (*buf, &map);
+
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_matroska_demux_check_aac (GstElement * element,
+    GstMatroskaTrackContext * stream, GstBuffer ** buf)
+{
+  guint8 data[2];
+  guint size;
+
+  gst_buffer_extract (*buf, 0, data, 2);
+  size = gst_buffer_get_size (*buf);
+
+  if (size > 2 && data[0] == 0xff && (data[1] >> 4 == 0x0f)) {
+    GstStructure *s;
+
+    /* tss, ADTS data, remove codec_data
+     * still assume it is at least parsed */
+    stream->caps = gst_caps_make_writable (stream->caps);
+    s = gst_caps_get_structure (stream->caps, 0);
+    g_assert (s);
+    gst_structure_remove_field (s, "codec_data");
+    gst_pad_set_caps (stream->pad, stream->caps);
+    GST_DEBUG_OBJECT (element, "ADTS AAC audio data; removing codec-data, "
+        "new caps: %" GST_PTR_FORMAT, stream->caps);
+  }
+
+  /* disable subsequent checking */
+  stream->postprocess_frame = NULL;
+
+  return GST_FLOW_OK;
+}
+
+static GstBuffer *
+gst_matroska_demux_align_buffer (GstMatroskaDemux * demux,
+    GstBuffer * buffer, gsize alignment)
+{
+  GstMapInfo map;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  if (map.size < sizeof (guintptr)) {
+    gst_buffer_unmap (buffer, &map);
+    return buffer;
+  }
+
+  if (((guintptr) map.data) & (alignment - 1)) {
+    GstBuffer *new_buffer;
+    GstAllocationParams params = { 0, alignment - 1, 0, 0, };
+
+    new_buffer = gst_buffer_new_allocate (NULL,
+        gst_buffer_get_size (buffer), &params);
+
+    /* Copy data "by hand", so ensure alignment is kept: */
+    gst_buffer_fill (new_buffer, 0, map.data, map.size);
+
+    gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
+    GST_DEBUG_OBJECT (demux,
+        "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
+        alignment);
+
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+
+    return new_buffer;
+  }
+
+  gst_buffer_unmap (buffer, &map);
+  return buffer;
+}
+
+static GstFlowReturn
+gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
+    GstEbmlRead * ebml, guint64 cluster_time, guint64 cluster_offset,
+    gboolean is_simpleblock)
+{
+  GstMatroskaTrackContext *stream = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+  gboolean readblock = FALSE;
+  guint32 id;
+  guint64 block_duration = -1;
+  gint64 block_discardpadding = 0;
+  GstBuffer *buf = NULL;
+  GstMapInfo map;
+  gint stream_num = -1, n, laces = 0;
+  guint size = 0;
+  gint *lace_size = NULL;
+  gint64 time = 0;
+  gint flags = 0;
+  gint64 referenceblock = 0;
+  gint64 offset;
+  GstClockTime buffer_timestamp;
+
+  offset = gst_ebml_read_get_offset (ebml);
+
+  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
+    if (!is_simpleblock) {
+      if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) {
+        goto data_error;
+      }
+    } else {
+      id = GST_MATROSKA_ID_SIMPLEBLOCK;
+    }
+
+    switch (id) {
+        /* one block inside the group. Note, block parsing is one
+         * of the harder things, so this code is a bit complicated.
+         * See http://www.matroska.org/ for documentation. */
+      case GST_MATROSKA_ID_SIMPLEBLOCK:
+      case GST_MATROSKA_ID_BLOCK:
+      {
+        guint64 num;
+        guint8 *data;
+
+        if (buf) {
+          gst_buffer_unmap (buf, &map);
+          gst_buffer_unref (buf);
+          buf = NULL;
+        }
+        if ((ret = gst_ebml_read_buffer (ebml, &id, &buf)) != GST_FLOW_OK)
+          break;
+
+        gst_buffer_map (buf, &map, GST_MAP_READ);
+        data = map.data;
+        size = map.size;
+
+        /* first byte(s): blocknum */
+        if ((n = gst_matroska_ebmlnum_uint (data, size, &num)) < 0)
+          goto data_error;
+        data += n;
+        size -= n;
+
+        /* fetch stream from 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->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
+              "; ignoring block", stream_num, num);
+          goto done;
+        }
+
+        stream = g_ptr_array_index (demux->common.src, stream_num);
+
+        /* time (relative to cluster time) */
+        time = ((gint16) GST_READ_UINT16_BE (data));
+        data += 2;
+        size -= 2;
+        flags = GST_READ_UINT8 (data);
+        data += 1;
+        size -= 1;
+
+        GST_LOG_OBJECT (demux, "time %" G_GUINT64_FORMAT ", flags %d", time,
+            flags);
+
+        switch ((flags & 0x06) >> 1) {
+          case 0x0:            /* no lacing */
+            laces = 1;
+            lace_size = g_new (gint, 1);
+            lace_size[0] = size;
+            break;
+
+          case 0x1:            /* xiph lacing */
+          case 0x2:            /* fixed-size lacing */
+          case 0x3:            /* EBML lacing */
+            if (size == 0)
+              goto invalid_lacing;
+            laces = GST_READ_UINT8 (data) + 1;
+            data += 1;
+            size -= 1;
+            lace_size = g_new0 (gint, laces);
+
+            switch ((flags & 0x06) >> 1) {
+              case 0x1:        /* xiph lacing */  {
+                guint temp, total = 0;
+
+                for (n = 0; ret == GST_FLOW_OK && n < laces - 1; n++) {
+                  while (1) {
+                    if (size == 0)
+                      goto invalid_lacing;
+                    temp = GST_READ_UINT8 (data);
+                    lace_size[n] += temp;
+                    data += 1;
+                    size -= 1;
+                    if (temp != 0xff)
+                      break;
+                  }
+                  total += lace_size[n];
+                }
+                lace_size[n] = size - total;
+                break;
+              }
+
+              case 0x2:        /* fixed-size lacing */
+                for (n = 0; n < laces; n++)
+                  lace_size[n] = size / laces;
+                break;
+
+              case 0x3:        /* EBML lacing */  {
+                guint total;
+
+                if ((n = gst_matroska_ebmlnum_uint (data, size, &num)) < 0)
+                  goto data_error;
+                data += n;
+                size -= n;
+                total = lace_size[0] = num;
+                for (n = 1; ret == GST_FLOW_OK && n < laces - 1; n++) {
+                  gint64 snum;
+                  gint r;
+
+                  if ((r = gst_matroska_ebmlnum_sint (data, size, &snum)) < 0)
+                    goto data_error;
+                  data += r;
+                  size -= r;
+                  lace_size[n] = lace_size[n - 1] + snum;
+                  total += lace_size[n];
+                }
+                if (n < laces)
+                  lace_size[n] = size - total;
+                break;
+              }
+            }
+            break;
+        }
+
+        if (ret != GST_FLOW_OK)
+          break;
+
+        readblock = TRUE;
+        break;
+      }
+
+      case GST_MATROSKA_ID_BLOCKDURATION:{
+        ret = gst_ebml_read_uint (ebml, &id, &block_duration);
+        GST_DEBUG_OBJECT (demux, "BlockDuration: %" G_GUINT64_FORMAT,
+            block_duration);
+        break;
+      }
+
+      case GST_MATROSKA_ID_DISCARDPADDING:{
+        ret = gst_ebml_read_sint (ebml, &id, &block_discardpadding);
+        GST_DEBUG_OBJECT (demux, "DiscardPadding: %" GST_STIME_FORMAT,
+            GST_STIME_ARGS (block_discardpadding));
+        break;
+      }
+
+      case GST_MATROSKA_ID_REFERENCEBLOCK:{
+        ret = gst_ebml_read_sint (ebml, &id, &referenceblock);
+        GST_DEBUG_OBJECT (demux, "ReferenceBlock: %" G_GINT64_FORMAT,
+            referenceblock);
+        break;
+      }
+
+      case GST_MATROSKA_ID_CODECSTATE:{
+        guint8 *data;
+        guint64 data_len = 0;
+
+        if ((ret =
+                gst_ebml_read_binary (ebml, &id, &data,
+                    &data_len)) != GST_FLOW_OK)
+          break;
+
+        if (G_UNLIKELY (stream == NULL)) {
+          GST_WARNING_OBJECT (demux,
+              "Unexpected CodecState subelement - ignoring");
+          break;
+        }
+
+        g_free (stream->codec_state);
+        stream->codec_state = data;
+        stream->codec_state_size = data_len;
+
+        /* Decode if necessary */
+        if (stream->encodings && stream->encodings->len > 0
+            && stream->codec_state && stream->codec_state_size > 0) {
+          if (!gst_matroska_decode_data (stream->encodings,
+                  &stream->codec_state, &stream->codec_state_size,
+                  GST_MATROSKA_TRACK_ENCODING_SCOPE_CODEC_DATA, TRUE)) {
+            GST_WARNING_OBJECT (demux, "Decoding codec state failed");
+          }
+        }
+
+        GST_DEBUG_OBJECT (demux, "CodecState of %" G_GSIZE_FORMAT " bytes",
+            stream->codec_state_size);
+        break;
+      }
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "BlockGroup", id);
+        break;
+
+      case GST_MATROSKA_ID_BLOCKVIRTUAL:
+      case GST_MATROSKA_ID_BLOCKADDITIONS:
+      case GST_MATROSKA_ID_REFERENCEPRIORITY:
+      case GST_MATROSKA_ID_REFERENCEVIRTUAL:
+      case GST_MATROSKA_ID_SLICES:
+        GST_DEBUG_OBJECT (demux,
+            "Skipping BlockGroup subelement 0x%x - ignoring", id);
+        ret = gst_ebml_read_skip (ebml);
+        break;
+    }
+
+    if (is_simpleblock)
+      break;
+  }
+
+  /* reading a number or so could have failed */
+  if (ret != GST_FLOW_OK)
+    goto data_error;
+
+  if (ret == GST_FLOW_OK && readblock) {
+    gboolean invisible_frame = FALSE;
+    gboolean delta_unit = FALSE;
+    guint64 duration = 0;
+    gint64 lace_time = 0;
+
+    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?
+       * Drop unless the lace contains timestamp 0? */
+      if (time < 0 && (-time) > cluster_time) {
+        lace_time = 0;
+      } else {
+        if (stream->timecodescale == 1.0)
+          lace_time = (cluster_time + time) * demux->common.time_scale;
+        else
+          lace_time =
+              gst_util_guint64_to_gdouble ((cluster_time + time) *
+              demux->common.time_scale) * stream->timecodescale;
+      }
+    } else {
+      lace_time = GST_CLOCK_TIME_NONE;
+    }
+
+    /* need to refresh segment info ASAP */
+    if (GST_CLOCK_TIME_IS_VALID (lace_time) && demux->need_segment) {
+      GstSegment *segment = &demux->common.segment;
+      guint64 clace_time;
+      GstEvent *segment_event;
+
+      if (!GST_CLOCK_TIME_IS_VALID (demux->stream_start_time)) {
+        demux->stream_start_time = lace_time;
+        GST_DEBUG_OBJECT (demux,
+            "Setting stream start time to %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (lace_time));
+      }
+      clace_time = MAX (lace_time, demux->stream_start_time);
+      if (GST_CLOCK_TIME_IS_VALID (demux->common.segment.position) &&
+          demux->common.segment.position != 0) {
+        GST_DEBUG_OBJECT (demux,
+            "using stored seek position %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (demux->common.segment.position));
+        clace_time = demux->common.segment.position;
+        segment->position = GST_CLOCK_TIME_NONE;
+      }
+      segment->start = clace_time;
+      segment->stop = GST_CLOCK_TIME_NONE;
+      segment->time = segment->start - demux->stream_start_time;
+      segment->position = segment->start - demux->stream_start_time;
+      GST_DEBUG_OBJECT (demux,
+          "generated segment starting at %" GST_TIME_FORMAT ": %"
+          GST_SEGMENT_FORMAT, GST_TIME_ARGS (lace_time), segment);
+      /* now convey our segment notion downstream */
+      segment_event = gst_event_new_segment (segment);
+      if (demux->segment_seqnum)
+        gst_event_set_seqnum (segment_event, demux->segment_seqnum);
+      gst_matroska_demux_send_event (demux, segment_event);
+      demux->need_segment = FALSE;
+      demux->segment_seqnum = 0;
+    }
+
+    /* send pending codec data headers for all streams,
+     * before we perform sync across all streams */
+    gst_matroska_demux_push_codec_data_all (demux);
+
+    if (block_duration != -1) {
+      if (stream->timecodescale == 1.0)
+        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->common.time_scale,
+                    1)) * stream->timecodescale);
+    } else if (stream->default_duration) {
+      duration = stream->default_duration * laces;
+    }
+    /* else duration is diff between timecode of this and next block */
+
+    if (stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
+      /* For SimpleBlock, look at the keyframe bit in flags. Otherwise,
+         a ReferenceBlock implies that this is not a keyframe. In either
+         case, it only makes sense for video streams. */
+      if ((is_simpleblock && !(flags & 0x80)) || referenceblock) {
+        delta_unit = TRUE;
+        invisible_frame = ((flags & 0x08)) &&
+            (!strcmp (stream->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VP8) ||
+            !strcmp (stream->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VP9) ||
+            !strcmp (stream->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_AV1));
+      }
+
+      /* If we're doing a keyframe-only trickmode, only push keyframes on video
+       * streams */
+      if (delta_unit
+          && demux->common.
+          segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS) {
+        GST_LOG_OBJECT (demux, "Skipping non-keyframe on stream %d",
+            stream->index);
+        ret = GST_FLOW_OK;
+        goto done;
+      }
+    }
+
+    for (n = 0; n < laces; n++) {
+      GstBuffer *sub;
+
+      if (G_UNLIKELY (lace_size[n] > size)) {
+        GST_WARNING_OBJECT (demux, "Invalid lace size");
+        break;
+      }
+
+      /* QoS for video track with an index. the assumption is that
+         index entries point to keyframes, but if that is not true we
+         will instad skip until the next keyframe. */
+      if (GST_CLOCK_TIME_IS_VALID (lace_time) &&
+          stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
+          stream->index_table && demux->common.segment.rate > 0.0) {
+        GstMatroskaTrackVideoContext *videocontext =
+            (GstMatroskaTrackVideoContext *) stream;
+        GstClockTime earliest_time;
+        GstClockTime earliest_stream_time;
+
+        GST_OBJECT_LOCK (demux);
+        earliest_time = videocontext->earliest_time;
+        GST_OBJECT_UNLOCK (demux);
+        earliest_stream_time =
+            gst_segment_position_from_running_time (&demux->common.segment,
+            GST_FORMAT_TIME, earliest_time);
+
+        if (GST_CLOCK_TIME_IS_VALID (lace_time) &&
+            GST_CLOCK_TIME_IS_VALID (earliest_stream_time) &&
+            lace_time <= earliest_stream_time) {
+          /* find index entry (keyframe) <= earliest_stream_time */
+          GstMatroskaIndex *entry =
+              gst_util_array_binary_search (stream->index_table->data,
+              stream->index_table->len, sizeof (GstMatroskaIndex),
+              (GCompareDataFunc) gst_matroska_index_seek_find,
+              GST_SEARCH_MODE_BEFORE, &earliest_stream_time, NULL);
+
+          /* if that entry (keyframe) is after the current the current
+             buffer, we can skip pushing (and thus decoding) all
+             buffers until that keyframe. */
+          if (entry && GST_CLOCK_TIME_IS_VALID (entry->time) &&
+              entry->time > lace_time) {
+            GST_LOG_OBJECT (demux, "Skipping lace before late keyframe");
+            stream->set_discont = TRUE;
+            goto next_lace;
+          }
+        }
+      }
+
+      sub = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
+          gst_buffer_get_size (buf) - size, lace_size[n]);
+      GST_DEBUG_OBJECT (demux, "created subbuffer %p", sub);
+
+      if (delta_unit)
+        GST_BUFFER_FLAG_SET (sub, GST_BUFFER_FLAG_DELTA_UNIT);
+      else
+        GST_BUFFER_FLAG_UNSET (sub, GST_BUFFER_FLAG_DELTA_UNIT);
+
+      if (invisible_frame)
+        GST_BUFFER_FLAG_SET (sub, GST_BUFFER_FLAG_DECODE_ONLY);
+
+      if (stream->encodings != NULL && stream->encodings->len > 0)
+        sub = gst_matroska_decode_buffer (stream, sub);
+
+      if (sub == NULL) {
+        GST_WARNING_OBJECT (demux, "Decoding buffer failed");
+        goto next_lace;
+      }
+
+      if (!stream->dts_only) {
+        GST_BUFFER_PTS (sub) = lace_time;
+      } else {
+        GST_BUFFER_DTS (sub) = lace_time;
+        if (stream->intra_only)
+          GST_BUFFER_PTS (sub) = lace_time;
+      }
+
+      buffer_timestamp = gst_matroska_track_get_buffer_timestamp (stream, sub);
+
+      if (GST_CLOCK_TIME_IS_VALID (lace_time)) {
+        GstClockTime last_stop_end;
+
+        /* Check if this stream is after segment stop */
+        if (GST_CLOCK_TIME_IS_VALID (demux->common.segment.stop) &&
+            lace_time >= demux->common.segment.stop) {
+          GST_DEBUG_OBJECT (demux,
+              "Stream %d after segment stop %" GST_TIME_FORMAT, stream->index,
+              GST_TIME_ARGS (demux->common.segment.stop));
+          gst_buffer_unref (sub);
+          goto eos;
+        }
+        if (offset >= stream->to_offset
+            || (GST_CLOCK_TIME_IS_VALID (demux->to_time)
+                && lace_time > demux->to_time)) {
+          GST_DEBUG_OBJECT (demux, "Stream %d after playback section",
+              stream->index);
+          gst_buffer_unref (sub);
+          goto eos;
+        }
+
+        /* handle gaps, e.g. non-zero start-time, or an cue index entry
+         * that landed us with timestamps not quite intended */
+        GST_OBJECT_LOCK (demux);
+        if (demux->max_gap_time &&
+            GST_CLOCK_TIME_IS_VALID (demux->last_stop_end) &&
+            demux->common.segment.rate > 0.0) {
+          GstClockTimeDiff diff;
+
+          /* only send segments with increasing start times,
+           * otherwise if these go back and forth downstream (sinks) increase
+           * accumulated time and running_time */
+          diff = GST_CLOCK_DIFF (demux->last_stop_end, lace_time);
+          if (diff > 0 && diff > demux->max_gap_time
+              && lace_time > demux->common.segment.start
+              && (!GST_CLOCK_TIME_IS_VALID (demux->common.segment.stop)
+                  || lace_time < demux->common.segment.stop)) {
+            GstEvent *event;
+            GST_DEBUG_OBJECT (demux,
+                "Gap of %" G_GINT64_FORMAT " ns detected in"
+                "stream %d (%" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "). "
+                "Sending updated SEGMENT events", diff,
+                stream->index, GST_TIME_ARGS (stream->pos),
+                GST_TIME_ARGS (lace_time));
+
+            event = gst_event_new_gap (demux->last_stop_end, diff);
+            GST_OBJECT_UNLOCK (demux);
+            gst_pad_push_event (stream->pad, event);
+            GST_OBJECT_LOCK (demux);
+          }
+        }
+
+        if (!GST_CLOCK_TIME_IS_VALID (demux->common.segment.position)
+            || demux->common.segment.position < lace_time) {
+          demux->common.segment.position = lace_time;
+        }
+        GST_OBJECT_UNLOCK (demux);
+
+        last_stop_end = lace_time;
+        if (duration) {
+          GST_BUFFER_DURATION (sub) = duration / laces;
+          last_stop_end += GST_BUFFER_DURATION (sub);
+        }
+
+        if (!GST_CLOCK_TIME_IS_VALID (demux->last_stop_end) ||
+            demux->last_stop_end < last_stop_end)
+          demux->last_stop_end = last_stop_end;
+
+        GST_OBJECT_LOCK (demux);
+        if (demux->common.segment.duration == -1 ||
+            demux->stream_start_time + demux->common.segment.duration <
+            last_stop_end) {
+          demux->common.segment.duration =
+              last_stop_end - demux->stream_start_time;
+          GST_OBJECT_UNLOCK (demux);
+          if (!demux->invalid_duration) {
+            gst_element_post_message (GST_ELEMENT_CAST (demux),
+                gst_message_new_duration_changed (GST_OBJECT_CAST (demux)));
+            demux->invalid_duration = TRUE;
+          }
+        } else {
+          GST_OBJECT_UNLOCK (demux);
+        }
+      }
+
+      stream->pos = lace_time;
+
+      gst_matroska_demux_sync_streams (demux);
+
+      if (stream->set_discont) {
+        GST_DEBUG_OBJECT (demux, "marking DISCONT");
+        GST_BUFFER_FLAG_SET (sub, GST_BUFFER_FLAG_DISCONT);
+        stream->set_discont = FALSE;
+      } else {
+        GST_BUFFER_FLAG_UNSET (sub, GST_BUFFER_FLAG_DISCONT);
+      }
+
+      /* reverse playback book-keeping */
+      if (!GST_CLOCK_TIME_IS_VALID (stream->from_time))
+        stream->from_time = lace_time;
+      if (stream->from_offset == -1)
+        stream->from_offset = offset;
+
+      GST_DEBUG_OBJECT (demux,
+          "Pushing lace %d, data of size %" G_GSIZE_FORMAT
+          " for stream %d, time=%" GST_TIME_FORMAT " and duration=%"
+          GST_TIME_FORMAT, n, gst_buffer_get_size (sub), stream_num,
+          GST_TIME_ARGS (buffer_timestamp),
+          GST_TIME_ARGS (GST_BUFFER_DURATION (sub)));
+
+#if 0
+      if (demux->common.element_index) {
+        if (stream->index_writer_id == -1)
+          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 (buffer_timestamp), cluster_offset,
+            stream->index_writer_id);
+        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, buffer_timestamp, GST_FORMAT_BYTES, cluster_offset,
+            NULL);
+      }
+#endif
+
+      /* Postprocess the buffers depending on the codec used */
+      if (stream->postprocess_frame) {
+        GST_LOG_OBJECT (demux, "running post process");
+        ret = stream->postprocess_frame (GST_ELEMENT (demux), stream, &sub);
+      }
+
+      /* At this point, we have a sub-buffer pointing at data within a larger
+         buffer. This data might not be aligned with anything. If the data is
+         raw samples though, we want it aligned to the raw type (eg, 4 bytes
+         for 32 bit samples, etc), or bad things will happen downstream as
+         elements typically assume minimal alignment.
+         Therefore, create an aligned copy if necessary. */
+      sub = gst_matroska_demux_align_buffer (demux, sub, stream->alignment);
+
+      if (!strcmp (stream->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)) {
+        guint64 start_clip = 0, end_clip = 0;
+
+        /* Codec delay is part of the timestamps */
+        if (GST_BUFFER_PTS_IS_VALID (sub) && stream->codec_delay) {
+          if (GST_BUFFER_PTS (sub) > stream->codec_delay) {
+            GST_BUFFER_PTS (sub) -= stream->codec_delay;
+          } else {
+            GST_BUFFER_PTS (sub) = 0;
+            start_clip =
+                gst_util_uint64_scale_round (stream->codec_delay, 48000,
+                GST_SECOND);
+
+            if (GST_BUFFER_DURATION_IS_VALID (sub)) {
+              if (GST_BUFFER_DURATION (sub) > stream->codec_delay)
+                GST_BUFFER_DURATION (sub) -= stream->codec_delay;
+              else
+                GST_BUFFER_DURATION (sub) = 0;
+            }
+          }
+        }
+
+        if (block_discardpadding) {
+          end_clip =
+              gst_util_uint64_scale_round (block_discardpadding, 48000,
+              GST_SECOND);
+        }
+
+        if (start_clip || end_clip) {
+          gst_buffer_add_audio_clipping_meta (sub, GST_FORMAT_DEFAULT,
+              start_clip, end_clip);
+        }
+      }
+
+      if (GST_BUFFER_PTS_IS_VALID (sub)) {
+        stream->pos = GST_BUFFER_PTS (sub);
+        if (GST_BUFFER_DURATION_IS_VALID (sub))
+          stream->pos += GST_BUFFER_DURATION (sub);
+      } else if (GST_BUFFER_DTS_IS_VALID (sub)) {
+        stream->pos = GST_BUFFER_DTS (sub);
+        if (GST_BUFFER_DURATION_IS_VALID (sub))
+          stream->pos += GST_BUFFER_DURATION (sub);
+      }
+
+      ret = gst_pad_push (stream->pad, sub);
+
+      if (demux->common.segment.rate < 0) {
+        if (lace_time > demux->common.segment.stop && ret == GST_FLOW_EOS) {
+          /* In reverse playback we can get a GST_FLOW_EOS when
+           * we are at the end of the segment, so we just need to jump
+           * back to the previous section. */
+          GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
+          ret = GST_FLOW_OK;
+        }
+      }
+      /* combine flows */
+      ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner,
+          stream->pad, ret);
+
+    next_lace:
+      size -= lace_size[n];
+      if (lace_time != GST_CLOCK_TIME_NONE && duration)
+        lace_time += duration / laces;
+      else
+        lace_time = GST_CLOCK_TIME_NONE;
+    }
+  }
+
+done:
+  if (buf) {
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+  }
+  g_free (lace_size);
+
+  return ret;
+
+  /* EXITS */
+eos:
+  {
+    stream->eos = TRUE;
+    ret = GST_FLOW_OK;
+    /* combine flows */
+    ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
+        ret);
+    goto done;
+  }
+invalid_lacing:
+  {
+    GST_ELEMENT_WARNING (demux, STREAM, DEMUX, (NULL), ("Invalid lacing size"));
+    /* non-fatal, try next block(group) */
+    ret = GST_FLOW_OK;
+    goto done;
+  }
+data_error:
+  {
+    GST_ELEMENT_WARNING (demux, STREAM, DEMUX, (NULL), ("Data error"));
+    /* non-fatal, try next block(group) */
+    ret = GST_FLOW_OK;
+    goto done;
+  }
+}
+
+/* return FALSE if block(group) should be skipped (due to a seek) */
+static inline gboolean
+gst_matroska_demux_seek_block (GstMatroskaDemux * demux)
+{
+  if (G_UNLIKELY (demux->seek_block)) {
+    if (!(--demux->seek_block)) {
+      return TRUE;
+    } else {
+      GST_LOG_OBJECT (demux, "should skip block due to seek");
+      return FALSE;
+    }
+  } else {
+    return TRUE;
+  }
+}
+
+static GstFlowReturn
+gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
+    GstEbmlRead * ebml)
+{
+  GstFlowReturn ret;
+  guint64 seek_pos = (guint64) - 1;
+  guint32 seek_id = 0;
+  guint32 id;
+
+  DEBUG_ELEMENT_START (demux, ebml, "Seek");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (demux, ebml, "Seek", 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) {
+      case GST_MATROSKA_ID_SEEKID:
+      {
+        guint64 t;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &t)) != GST_FLOW_OK)
+          break;
+
+        GST_DEBUG_OBJECT (demux, "SeekID: %" G_GUINT64_FORMAT, t);
+        seek_id = t;
+        break;
+      }
+
+      case GST_MATROSKA_ID_SEEKPOSITION:
+      {
+        guint64 t;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &t)) != GST_FLOW_OK)
+          break;
+
+        if (t > G_MAXINT64) {
+          GST_WARNING_OBJECT (demux,
+              "Too large SeekPosition %" G_GUINT64_FORMAT, t);
+          break;
+        }
+
+        GST_DEBUG_OBJECT (demux, "SeekPosition: %" G_GUINT64_FORMAT, t);
+        seek_pos = t;
+        break;
+      }
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "SeekHead", id);
+        break;
+    }
+  }
+
+  if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS)
+    return ret;
+
+  if (!seek_id || seek_pos == (guint64) - 1) {
+    GST_WARNING_OBJECT (demux, "Incomplete seekhead entry (0x%x/%"
+        G_GUINT64_FORMAT ")", seek_id, seek_pos);
+    return GST_FLOW_OK;
+  }
+
+  switch (seek_id) {
+    case GST_MATROSKA_ID_SEEKHEAD:
+    {
+    }
+    case GST_MATROSKA_ID_CUES:
+    case GST_MATROSKA_ID_TAGS:
+    case GST_MATROSKA_ID_TRACKS:
+    case GST_MATROSKA_ID_SEGMENTINFO:
+    case GST_MATROSKA_ID_ATTACHMENTS:
+    case GST_MATROSKA_ID_CHAPTERS:
+    {
+      guint64 before_pos, length;
+      guint needed;
+
+      /* remember */
+      length = gst_matroska_read_common_get_length (&demux->common);
+      before_pos = demux->common.offset;
+
+      if (length == (guint64) - 1) {
+        GST_DEBUG_OBJECT (demux, "no upstream length, skipping SeakHead entry");
+        break;
+      }
+
+      /* check for validity */
+      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->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->common.ebml_segment_start;
+          GST_DEBUG_OBJECT (demux, "Cues located at offset %" G_GUINT64_FORMAT,
+              demux->index_offset);
+        }
+        break;
+      }
+
+      /* seek */
+      demux->common.offset = seek_pos + demux->common.ebml_segment_start;
+
+      /* check ID */
+      if ((ret = gst_matroska_read_common_peek_id_length_pull (&demux->common,
+                  GST_ELEMENT_CAST (demux), &id, &length, &needed)) !=
+          GST_FLOW_OK)
+        goto finish;
+
+      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->common.ebml_segment_start);
+      } else {
+        /* now parse */
+        ret = gst_matroska_demux_parse_id (demux, id, length, needed);
+      }
+
+    finish:
+      /* seek back */
+      demux->common.offset = before_pos;
+      break;
+    }
+
+    case GST_MATROSKA_ID_CLUSTER:
+    {
+      guint64 pos = seek_pos + demux->common.ebml_segment_start;
+
+      GST_LOG_OBJECT (demux, "Cluster position");
+      if (G_UNLIKELY (!demux->clusters))
+        demux->clusters = g_array_sized_new (TRUE, TRUE, sizeof (guint64), 100);
+      g_array_append_val (demux->clusters, pos);
+      break;
+    }
+
+    default:
+      GST_DEBUG_OBJECT (demux, "Ignoring Seek entry for ID=0x%x", seek_id);
+      break;
+  }
+  DEBUG_ELEMENT_STOP (demux, ebml, "Seek", ret);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_matroska_demux_parse_contents (GstMatroskaDemux * demux, GstEbmlRead * ebml)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint32 id;
+
+  DEBUG_ELEMENT_START (demux, ebml, "SeekHead");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (demux, ebml, "SeekHead", 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) {
+      case GST_MATROSKA_ID_SEEKENTRY:
+      {
+        ret = gst_matroska_demux_parse_contents_seekentry (demux, ebml);
+        /* Ignore EOS and errors here */
+        if (ret != GST_FLOW_OK) {
+          GST_DEBUG_OBJECT (demux, "Ignoring %s", gst_flow_get_name (ret));
+          ret = GST_FLOW_OK;
+        }
+        break;
+      }
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (&demux->common,
+            ebml, "SeekHead", id);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (demux, ebml, "SeekHead", ret);
+
+  /* Sort clusters by position for easier searching */
+  if (demux->clusters)
+    g_array_sort (demux->clusters, (GCompareFunc) gst_matroska_cluster_compare);
+
+  return ret;
+}
+
+#define GST_FLOW_OVERFLOW   GST_FLOW_CUSTOM_ERROR
+
+#define MAX_BLOCK_SIZE (15 * 1024 * 1024)
+
+static inline GstFlowReturn
+gst_matroska_demux_check_read_size (GstMatroskaDemux * demux, guint64 bytes)
+{
+  if (G_UNLIKELY (bytes > MAX_BLOCK_SIZE)) {
+    /* only a few blocks are expected/allowed to be large,
+     * and will be recursed into, whereas others will be read and must fit */
+    if (demux->streaming) {
+      /* fatal in streaming case, as we can't step over easily */
+      GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
+          ("reading large block of size %" G_GUINT64_FORMAT " not supported; "
+              "file might be corrupt.", bytes));
+      return GST_FLOW_ERROR;
+    } else {
+      /* indicate higher level to quietly give up */
+      GST_DEBUG_OBJECT (demux,
+          "too large block of size %" G_GUINT64_FORMAT, bytes);
+      return GST_FLOW_ERROR;
+    }
+  } else {
+    return GST_FLOW_OK;
+  }
+}
+
+/* returns TRUE if we truely are in error state, and should give up */
+static inline GstFlowReturn
+gst_matroska_demux_check_parse_error (GstMatroskaDemux * demux)
+{
+  if (!demux->streaming && demux->next_cluster_offset > 0) {
+    /* just repositioning to where next cluster should be and try from there */
+    GST_WARNING_OBJECT (demux, "parse error, trying next cluster expected at %"
+        G_GUINT64_FORMAT, demux->next_cluster_offset);
+    demux->common.offset = demux->next_cluster_offset;
+    demux->next_cluster_offset = 0;
+    return GST_FLOW_OK;
+  } else {
+    gint64 pos;
+    GstFlowReturn ret;
+
+    /* sigh, one last attempt above and beyond call of duty ...;
+     * search for cluster mark following current pos */
+    pos = demux->common.offset;
+    GST_WARNING_OBJECT (demux, "parse error, looking for next cluster");
+    if ((ret = gst_matroska_demux_search_cluster (demux, &pos, TRUE)) !=
+        GST_FLOW_OK) {
+      /* did not work, give up */
+      return ret;
+    } else {
+      GST_DEBUG_OBJECT (demux, "... found at  %" G_GUINT64_FORMAT, pos);
+      /* try that position */
+      demux->common.offset = pos;
+      return GST_FLOW_OK;
+    }
+  }
+}
+
+static inline GstFlowReturn
+gst_matroska_demux_flush (GstMatroskaDemux * demux, guint flush)
+{
+  GST_LOG_OBJECT (demux, "skipping %d bytes", flush);
+  demux->common.offset += flush;
+  if (demux->streaming) {
+    GstFlowReturn ret;
+
+    /* hard to skip large blocks when streaming */
+    ret = gst_matroska_demux_check_read_size (demux, flush);
+    if (ret != GST_FLOW_OK)
+      return ret;
+    if (flush <= gst_adapter_available (demux->common.adapter))
+      gst_adapter_flush (demux->common.adapter, flush);
+    else
+      return GST_FLOW_EOS;
+  }
+  return GST_FLOW_OK;
+}
+
+/* initializes @ebml with @bytes from input stream at current offset.
+ * Returns EOS if insufficient available,
+ * ERROR if too much was attempted to read. */
+static inline GstFlowReturn
+gst_matroska_demux_take (GstMatroskaDemux * demux, guint64 bytes,
+    GstEbmlRead * ebml)
+{
+  GstBuffer *buffer = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  GST_LOG_OBJECT (demux, "taking %" G_GUINT64_FORMAT " bytes for parsing",
+      bytes);
+  ret = gst_matroska_demux_check_read_size (demux, bytes);
+  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+    if (!demux->streaming) {
+      /* in pull mode, we can skip */
+      if ((ret = gst_matroska_demux_flush (demux, bytes)) == GST_FLOW_OK)
+        ret = GST_FLOW_OVERFLOW;
+    } else {
+      /* otherwise fatal */
+      ret = GST_FLOW_ERROR;
+    }
+    goto exit;
+  }
+  if (demux->streaming) {
+    if (gst_adapter_available (demux->common.adapter) >= bytes)
+      buffer = gst_adapter_take_buffer (demux->common.adapter, bytes);
+    else
+      ret = GST_FLOW_EOS;
+  } else
+    ret = gst_matroska_read_common_peek_bytes (&demux->common,
+        demux->common.offset, bytes, &buffer, NULL);
+  if (G_LIKELY (buffer)) {
+    gst_ebml_read_init (ebml, GST_ELEMENT_CAST (demux), buffer,
+        demux->common.offset);
+    demux->common.offset += bytes;
+  }
+exit:
+  return ret;
+}
+
+static void
+gst_matroska_demux_check_seekability (GstMatroskaDemux * demux)
+{
+  GstQuery *query;
+  gboolean seekable = FALSE;
+  gint64 start = -1, stop = -1;
+
+  query = gst_query_new_seeking (GST_FORMAT_BYTES);
+  if (!gst_pad_peer_query (demux->common.sinkpad, query)) {
+    GST_DEBUG_OBJECT (demux, "seeking query failed");
+    goto done;
+  }
+
+  gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
+
+  /* try harder to query upstream size if we didn't get it the first time */
+  if (seekable && stop == -1) {
+    GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
+    gst_pad_peer_query_duration (demux->common.sinkpad, GST_FORMAT_BYTES,
+        &stop);
+  }
+
+  /* if upstream doesn't know the size, it's likely that it's not seekable in
+   * practice even if it technically may be seekable */
+  if (seekable && (start != 0 || stop <= start)) {
+    GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
+    seekable = FALSE;
+  }
+
+done:
+  GST_INFO_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
+      G_GUINT64_FORMAT ")", seekable, start, stop);
+  demux->seekable = seekable;
+
+  gst_query_unref (query);
+}
+
+static GstFlowReturn
+gst_matroska_demux_find_tracks (GstMatroskaDemux * demux)
+{
+  guint32 id;
+  guint64 before_pos;
+  guint64 length;
+  guint needed;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  GST_WARNING_OBJECT (demux,
+      "Found Cluster element before Tracks, searching Tracks");
+
+  /* remember */
+  before_pos = demux->common.offset;
+
+  /* Search Tracks element */
+  while (TRUE) {
+    ret = gst_matroska_read_common_peek_id_length_pull (&demux->common,
+        GST_ELEMENT_CAST (demux), &id, &length, &needed);
+    if (ret != GST_FLOW_OK)
+      break;
+
+    if (id != GST_MATROSKA_ID_TRACKS) {
+      /* we may be skipping large cluster here, so forego size check etc */
+      /* ... but we can't skip undefined size; force error */
+      if (length == G_MAXUINT64) {
+        ret = gst_matroska_demux_check_read_size (demux, length);
+        break;
+      } else {
+        demux->common.offset += needed;
+        demux->common.offset += length;
+      }
+      continue;
+    }
+
+    /* will lead to track parsing ... */
+    ret = gst_matroska_demux_parse_id (demux, id, length, needed);
+    break;
+  }
+
+  /* seek back */
+  demux->common.offset = before_pos;
+
+  return ret;
+}
+
+#define GST_READ_CHECK(stmt)  \
+G_STMT_START { \
+  if (G_UNLIKELY ((ret = (stmt)) != GST_FLOW_OK)) { \
+    if (ret == GST_FLOW_OVERFLOW) { \
+      ret = GST_FLOW_OK; \
+    } \
+    goto read_error; \
+  } \
+} G_STMT_END
+
+static GstFlowReturn
+gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
+    guint64 length, guint needed)
+{
+  GstEbmlRead ebml = { 0, };
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint64 read;
+
+  GST_LOG_OBJECT (demux, "Parsing Element id 0x%x, "
+      "size %" G_GUINT64_FORMAT ", prefix %d", id, length, needed);
+
+  /* if we plan to read and parse this element, we need prefix (id + length)
+   * and the contents */
+  /* mind about overflow wrap-around when dealing with undefined size */
+  read = length;
+  if (G_LIKELY (length != G_MAXUINT64))
+    read += needed;
+
+  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_read_common_parse_header (&demux->common, &ebml);
+          if (ret != GST_FLOW_OK)
+            goto parse_failed;
+          demux->common.state = GST_MATROSKA_READ_STATE_SEGMENT;
+          gst_matroska_demux_check_seekability (demux);
+          break;
+        default:
+          goto invalid_header;
+          break;
+      }
+      break;
+    case GST_MATROSKA_READ_STATE_SEGMENT:
+      switch (id) {
+        case GST_MATROSKA_ID_SEGMENT:
+          /* eat segment prefix */
+          GST_READ_CHECK (gst_matroska_demux_flush (demux, needed));
+          GST_DEBUG_OBJECT (demux,
+              "Found Segment start at offset %" G_GUINT64_FORMAT " with size %"
+              G_GUINT64_FORMAT, demux->common.offset, length);
+          /* seeks are from the beginning of the segment,
+           * after the segment ID/length */
+          demux->common.ebml_segment_start = demux->common.offset;
+          if (length == 0)
+            length = G_MAXUINT64;
+          demux->common.ebml_segment_length = length;
+          demux->common.state = GST_MATROSKA_READ_STATE_HEADER;
+          break;
+        default:
+          GST_WARNING_OBJECT (demux,
+              "Expected a Segment ID (0x%x), but received 0x%x!",
+              GST_MATROSKA_ID_SEGMENT, id);
+          GST_READ_CHECK (gst_matroska_demux_flush (demux, read));
+          break;
+      }
+      break;
+    case GST_MATROSKA_READ_STATE_SCANNING:
+      if (id != GST_MATROSKA_ID_CLUSTER &&
+          id != GST_MATROSKA_ID_CLUSTERTIMECODE) {
+        if (demux->common.start_resync_offset != -1) {
+          /* we need to skip byte per byte if we are scanning for a new cluster
+           * after invalid data is found
+           */
+          read = 1;
+        }
+        goto skip;
+      } else {
+        if (demux->common.start_resync_offset != -1) {
+          GST_LOG_OBJECT (demux, "Resync done, new cluster found!");
+          demux->common.start_resync_offset = -1;
+          demux->common.state = demux->common.state_to_restore;
+        }
+      }
+      /* fall-through */
+    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->common.segmentinfo_parsed) {
+            GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
+            ret = gst_matroska_read_common_parse_info (&demux->common,
+                GST_ELEMENT_CAST (demux), &ebml);
+            if (ret == GST_FLOW_OK)
+              gst_matroska_demux_send_tags (demux);
+          } else {
+            GST_READ_CHECK (gst_matroska_demux_flush (demux, read));
+          }
+          break;
+        case GST_MATROSKA_ID_TRACKS:
+          if (!demux->tracks_parsed) {
+            GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
+            ret = gst_matroska_demux_parse_tracks (demux, &ebml);
+          } else {
+            GST_READ_CHECK (gst_matroska_demux_flush (demux, read));
+          }
+          break;
+        case GST_MATROSKA_ID_CLUSTER:
+          if (G_UNLIKELY (!demux->tracks_parsed)) {
+            if (demux->streaming) {
+              GST_DEBUG_OBJECT (demux, "Cluster before Track");
+              goto not_streamable;
+            } else {
+              ret = gst_matroska_demux_find_tracks (demux);
+              if (!demux->tracks_parsed)
+                goto no_tracks;
+            }
+          }
+          if (G_UNLIKELY (demux->common.state
+                  == GST_MATROSKA_READ_STATE_HEADER)) {
+            demux->common.state = GST_MATROSKA_READ_STATE_DATA;
+            demux->first_cluster_offset = demux->common.offset;
+            if (!demux->streaming &&
+                !GST_CLOCK_TIME_IS_VALID (demux->common.segment.duration)) {
+              GstMatroskaIndex *last = NULL;
+
+              GST_DEBUG_OBJECT (demux,
+                  "estimating duration using last cluster");
+              if ((last = gst_matroska_demux_search_pos (demux,
+                          GST_CLOCK_TIME_NONE)) != NULL) {
+                demux->last_cluster_offset =
+                    last->pos + demux->common.ebml_segment_start;
+                demux->stream_last_time = last->time;
+                demux->common.segment.duration =
+                    demux->stream_last_time - demux->stream_start_time;
+                /* above estimate should not be taken all too strongly */
+                demux->invalid_duration = TRUE;
+                GST_DEBUG_OBJECT (demux,
+                    "estimated duration as %" GST_TIME_FORMAT,
+                    GST_TIME_ARGS (demux->common.segment.duration));
+              }
+            }
+            GST_DEBUG_OBJECT (demux, "signaling no more pads");
+            gst_element_no_more_pads (GST_ELEMENT (demux));
+            /* send initial segment - we wait till we know the first
+               incoming timestamp, so we can properly set the start of
+               the segment. */
+            demux->need_segment = TRUE;
+          }
+          demux->cluster_time = GST_CLOCK_TIME_NONE;
+          demux->cluster_offset = demux->common.offset;
+          if (G_UNLIKELY (!demux->seek_first && demux->seek_block)) {
+            GST_DEBUG_OBJECT (demux, "seek target block %" G_GUINT64_FORMAT
+                " not found in Cluster, trying next Cluster's first block instead",
+                demux->seek_block);
+            demux->seek_block = 0;
+          }
+          demux->seek_first = FALSE;
+          /* record next cluster for recovery */
+          if (read != G_MAXUINT64)
+            demux->next_cluster_offset = demux->cluster_offset + read;
+          /* eat cluster prefix */
+          gst_matroska_demux_flush (demux, needed);
+          break;
+        case GST_MATROSKA_ID_CLUSTERTIMECODE:
+        {
+          guint64 num;
+
+          GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
+          if ((ret = gst_ebml_read_uint (&ebml, &id, &num)) != GST_FLOW_OK)
+            goto parse_failed;
+          GST_DEBUG_OBJECT (demux, "ClusterTimeCode: %" G_GUINT64_FORMAT, num);
+          demux->cluster_time = num;
+          /* track last cluster */
+          if (demux->cluster_offset > demux->last_cluster_offset) {
+            demux->last_cluster_offset = demux->cluster_offset;
+            demux->stream_last_time =
+                demux->cluster_time * demux->common.time_scale;
+          }
+#if 0
+          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->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);
+          }
+#endif
+          break;
+        }
+        case GST_MATROSKA_ID_BLOCKGROUP:
+          if (!gst_matroska_demux_seek_block (demux))
+            goto skip;
+          GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
+          DEBUG_ELEMENT_START (demux, &ebml, "BlockGroup");
+          if ((ret = gst_ebml_read_master (&ebml, &id)) == GST_FLOW_OK) {
+            ret = gst_matroska_demux_parse_blockgroup_or_simpleblock (demux,
+                &ebml, demux->cluster_time, demux->cluster_offset, FALSE);
+          }
+          DEBUG_ELEMENT_STOP (demux, &ebml, "BlockGroup", ret);
+          break;
+        case GST_MATROSKA_ID_SIMPLEBLOCK:
+          if (!gst_matroska_demux_seek_block (demux))
+            goto skip;
+          GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
+          DEBUG_ELEMENT_START (demux, &ebml, "SimpleBlock");
+          ret = gst_matroska_demux_parse_blockgroup_or_simpleblock (demux,
+              &ebml, demux->cluster_time, demux->cluster_offset, TRUE);
+          DEBUG_ELEMENT_STOP (demux, &ebml, "SimpleBlock", ret);
+          break;
+        case GST_MATROSKA_ID_ATTACHMENTS:
+          if (!demux->common.attachments_parsed) {
+            GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
+            ret = gst_matroska_read_common_parse_attachments (&demux->common,
+                GST_ELEMENT_CAST (demux), &ebml);
+            if (ret == GST_FLOW_OK)
+              gst_matroska_demux_send_tags (demux);
+          } else {
+            GST_READ_CHECK (gst_matroska_demux_flush (demux, read));
+          }
+          break;
+        case GST_MATROSKA_ID_TAGS:
+          GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
+          ret = gst_matroska_read_common_parse_metadata (&demux->common,
+              GST_ELEMENT_CAST (demux), &ebml);
+          if (ret == GST_FLOW_OK)
+            gst_matroska_demux_send_tags (demux);
+          break;
+        case GST_MATROSKA_ID_CHAPTERS:
+          if (!demux->common.chapters_parsed) {
+            GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
+            ret =
+                gst_matroska_read_common_parse_chapters (&demux->common, &ebml);
+
+            if (demux->common.toc) {
+              gst_matroska_demux_send_event (demux,
+                  gst_event_new_toc (demux->common.toc, FALSE));
+            }
+          } else
+            GST_READ_CHECK (gst_matroska_demux_flush (demux, read));
+          break;
+        case GST_MATROSKA_ID_SEEKHEAD:
+          GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
+          ret = gst_matroska_demux_parse_contents (demux, &ebml);
+          break;
+        case GST_MATROSKA_ID_CUES:
+          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_read_common_parse_index (&demux->common, &ebml);
+          /* only push based; delayed index building */
+          if (ret == GST_FLOW_OK
+              && demux->common.state == GST_MATROSKA_READ_STATE_SEEK) {
+            GstEvent *event;
+
+            GST_OBJECT_LOCK (demux);
+            event = demux->seek_event;
+            demux->seek_event = NULL;
+            GST_OBJECT_UNLOCK (demux);
+
+            g_assert (event);
+            /* unlikely to fail, since we managed to seek to this point */
+            if (!gst_matroska_demux_handle_seek_event (demux, NULL, event)) {
+              gst_event_unref (event);
+              goto seek_failed;
+            }
+            gst_event_unref (event);
+            /* resume data handling, main thread clear to seek again */
+            GST_OBJECT_LOCK (demux);
+            demux->common.state = GST_MATROSKA_READ_STATE_DATA;
+            GST_OBJECT_UNLOCK (demux);
+          }
+          break;
+        case GST_MATROSKA_ID_POSITION:
+        case GST_MATROSKA_ID_PREVSIZE:
+        case GST_MATROSKA_ID_ENCRYPTEDBLOCK:
+        case GST_MATROSKA_ID_SILENTTRACKS:
+          GST_DEBUG_OBJECT (demux,
+              "Skipping Cluster subelement 0x%x - ignoring", id);
+          /* fall-through */
+        default:
+        skip:
+          GST_DEBUG_OBJECT (demux, "skipping Element 0x%x", id);
+          GST_READ_CHECK (gst_matroska_demux_flush (demux, read));
+          break;
+      }
+      break;
+  }
+
+  if (ret == GST_FLOW_PARSE)
+    goto parse_failed;
+
+exit:
+  gst_ebml_read_clear (&ebml);
+  return ret;
+
+  /* ERRORS */
+read_error:
+  {
+    /* simply exit, maybe not enough data yet */
+    /* no ebml to clear if read error */
+    return ret;
+  }
+parse_failed:
+  {
+    GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
+        ("Failed to parse Element 0x%x", id));
+    ret = GST_FLOW_ERROR;
+    goto exit;
+  }
+not_streamable:
+  {
+    GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
+        ("File layout does not permit streaming"));
+    ret = GST_FLOW_ERROR;
+    goto exit;
+  }
+no_tracks:
+  {
+    GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
+        ("No Tracks element found"));
+    ret = GST_FLOW_ERROR;
+    goto exit;
+  }
+invalid_header:
+  {
+    GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("Invalid header"));
+    ret = GST_FLOW_ERROR;
+    goto exit;
+  }
+seek_failed:
+  {
+    GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("Failed to seek"));
+    ret = GST_FLOW_ERROR;
+    goto exit;
+  }
+}
+
+static void
+gst_matroska_demux_loop (GstPad * pad)
+{
+  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (GST_PAD_PARENT (pad));
+  GstFlowReturn ret;
+  guint32 id;
+  guint64 length;
+  guint needed;
+
+  /* If we have to close a segment, send a new segment to do this now */
+  if (G_LIKELY (demux->common.state == GST_MATROSKA_READ_STATE_DATA)) {
+    if (G_UNLIKELY (demux->new_segment)) {
+      gst_matroska_demux_send_event (demux, demux->new_segment);
+      demux->new_segment = NULL;
+    }
+  }
+
+  ret = gst_matroska_read_common_peek_id_length_pull (&demux->common,
+      GST_ELEMENT_CAST (demux), &id, &length, &needed);
+  if (ret == GST_FLOW_EOS) {
+    goto eos;
+  } else if (ret == GST_FLOW_FLUSHING) {
+    goto pause;
+  } else if (ret != GST_FLOW_OK) {
+    ret = gst_matroska_demux_check_parse_error (demux);
+
+    /* Only handle EOS as no error if we're outside the segment already */
+    if (ret == GST_FLOW_EOS && (demux->common.ebml_segment_length != G_MAXUINT64
+            && demux->common.offset >=
+            demux->common.ebml_segment_start +
+            demux->common.ebml_segment_length))
+      goto eos;
+    else if (ret != GST_FLOW_OK)
+      goto pause;
+    else
+      return;
+  }
+
+  GST_LOG_OBJECT (demux, "Offset %" G_GUINT64_FORMAT ", Element id 0x%x, "
+      "size %" G_GUINT64_FORMAT ", needed %d", demux->common.offset, id,
+      length, needed);
+
+  ret = gst_matroska_demux_parse_id (demux, id, length, needed);
+  if (ret == GST_FLOW_EOS)
+    goto eos;
+  if (ret != GST_FLOW_OK)
+    goto pause;
+
+  /* check if we're at the end of a configured segment */
+  if (G_LIKELY (demux->common.src->len)) {
+    guint 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)
+        goto next;
+    }
+
+    GST_INFO_OBJECT (demux, "All streams are EOS");
+    ret = GST_FLOW_EOS;
+    goto eos;
+  }
+
+next:
+  if (G_UNLIKELY (demux->cached_length == G_MAXUINT64 ||
+          demux->common.offset >= demux->cached_length)) {
+    demux->cached_length = gst_matroska_read_common_get_length (&demux->common);
+    if (demux->common.offset == demux->cached_length) {
+      GST_LOG_OBJECT (demux, "Reached end of stream");
+      ret = GST_FLOW_EOS;
+      goto eos;
+    }
+  }
+
+  return;
+
+  /* ERRORS */
+eos:
+  {
+    if (demux->common.segment.rate < 0.0) {
+      ret = gst_matroska_demux_seek_to_previous_keyframe (demux);
+      if (ret == GST_FLOW_OK)
+        return;
+    }
+    /* fall-through */
+  }
+pause:
+  {
+    const gchar *reason = gst_flow_get_name (ret);
+    gboolean push_eos = FALSE;
+
+    GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
+    gst_pad_pause_task (demux->common.sinkpad);
+
+    if (ret == GST_FLOW_EOS) {
+      /* perform EOS logic */
+
+      /* If we were in the headers, make sure we send no-more-pads.
+         This will ensure decodebin does not get stuck thinking
+         the chain is not complete yet, and waiting indefinitely. */
+      if (G_UNLIKELY (demux->common.state == GST_MATROSKA_READ_STATE_HEADER)) {
+        if (demux->common.src->len == 0) {
+          GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL),
+              ("No pads created"));
+        } else {
+          GST_ELEMENT_WARNING (demux, STREAM, DEMUX, (NULL),
+              ("Failed to finish reading headers"));
+        }
+        gst_element_no_more_pads (GST_ELEMENT (demux));
+      }
+
+      if (demux->common.segment.flags & GST_SEEK_FLAG_SEGMENT) {
+        GstEvent *event;
+        GstMessage *msg;
+        gint64 stop;
+
+        /* for segment playback we need to post when (in stream time)
+         * we stopped, this is either stop (when set) or the duration. */
+        if ((stop = demux->common.segment.stop) == -1)
+          stop = demux->last_stop_end;
+
+        GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
+        msg = gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
+            stop);
+        if (demux->segment_seqnum)
+          gst_message_set_seqnum (msg, demux->segment_seqnum);
+        gst_element_post_message (GST_ELEMENT (demux), msg);
+
+        event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
+        if (demux->segment_seqnum)
+          gst_event_set_seqnum (event, demux->segment_seqnum);
+        gst_matroska_demux_send_event (demux, event);
+      } else {
+        push_eos = TRUE;
+      }
+    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
+      /* for fatal errors we post an error message */
+      GST_ELEMENT_FLOW_ERROR (demux, ret);
+      push_eos = TRUE;
+    }
+    if (push_eos) {
+      GstEvent *event;
+
+      /* send EOS, and prevent hanging if no streams yet */
+      GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
+      event = gst_event_new_eos ();
+      if (demux->segment_seqnum)
+        gst_event_set_seqnum (event, demux->segment_seqnum);
+      if (!gst_matroska_demux_send_event (demux, event) &&
+          (ret == GST_FLOW_EOS)) {
+        GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
+            (NULL), ("got eos but no streams (yet)"));
+      }
+    }
+    return;
+  }
+}
+
+/*
+ * Create and push a flushing seek event upstream
+ */
+static gboolean
+perform_seek_to_offset (GstMatroskaDemux * demux, gdouble rate, guint64 offset,
+    guint32 seqnum, GstSeekFlags flags)
+{
+  GstEvent *event;
+  gboolean res = 0;
+
+  GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
+
+  event =
+      gst_event_new_seek (rate, GST_FORMAT_BYTES,
+      flags | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
+      GST_SEEK_TYPE_SET, offset, GST_SEEK_TYPE_NONE, -1);
+  gst_event_set_seqnum (event, seqnum);
+
+  res = gst_pad_push_event (demux->common.sinkpad, event);
+
+  /* segment event will update offset */
+  return res;
+}
+
+static GstFlowReturn
+gst_matroska_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (parent);
+  guint available;
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint needed = 0;
+  guint32 id;
+  guint64 length;
+
+  if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buffer))) {
+    GST_DEBUG_OBJECT (demux, "got DISCONT");
+    gst_adapter_clear (demux->common.adapter);
+    GST_OBJECT_LOCK (demux);
+    gst_matroska_read_common_reset_streams (&demux->common,
+        GST_CLOCK_TIME_NONE, FALSE);
+    GST_OBJECT_UNLOCK (demux);
+  }
+
+  gst_adapter_push (demux->common.adapter, buffer);
+  buffer = NULL;
+
+next:
+  available = gst_adapter_available (demux->common.adapter);
+
+  ret = gst_matroska_read_common_peek_id_length_push (&demux->common,
+      GST_ELEMENT_CAST (demux), &id, &length, &needed);
+  if (G_UNLIKELY (ret != GST_FLOW_OK && ret != GST_FLOW_EOS)) {
+    if (demux->common.ebml_segment_length != G_MAXUINT64
+        && demux->common.offset >=
+        demux->common.ebml_segment_start + demux->common.ebml_segment_length) {
+      return GST_FLOW_OK;
+    } else {
+      gint64 bytes_scanned;
+      if (demux->common.start_resync_offset == -1) {
+        demux->common.start_resync_offset = demux->common.offset;
+        demux->common.state_to_restore = demux->common.state;
+      }
+      bytes_scanned = demux->common.offset - demux->common.start_resync_offset;
+      if (bytes_scanned <= INVALID_DATA_THRESHOLD) {
+        GST_WARNING_OBJECT (demux,
+            "parse error, looking for next cluster, actual offset %"
+            G_GUINT64_FORMAT ", start resync offset %" G_GUINT64_FORMAT,
+            demux->common.offset, demux->common.start_resync_offset);
+        demux->common.state = GST_MATROSKA_READ_STATE_SCANNING;
+        ret = GST_FLOW_OK;
+      } else {
+        GST_WARNING_OBJECT (demux,
+            "unrecoverable parse error, next cluster not found and threshold "
+            "exceeded, bytes scanned %" G_GINT64_FORMAT, bytes_scanned);
+        return ret;
+      }
+    }
+  }
+
+  GST_LOG_OBJECT (demux, "Offset %" G_GUINT64_FORMAT ", Element id 0x%x, "
+      "size %" G_GUINT64_FORMAT ", needed %d, available %d",
+      demux->common.offset, id, length, needed, available);
+
+  if (needed > available)
+    return GST_FLOW_OK;
+
+  ret = gst_matroska_demux_parse_id (demux, id, length, needed);
+  if (ret == GST_FLOW_EOS) {
+    /* need more data */
+    return GST_FLOW_OK;
+  } else if (ret != GST_FLOW_OK) {
+    return ret;
+  } else
+    goto next;
+}
+
+static gboolean
+gst_matroska_demux_handle_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  gboolean res = TRUE;
+  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (parent);
+
+  GST_DEBUG_OBJECT (demux,
+      "have event type %s: %p on sink pad", GST_EVENT_TYPE_NAME (event), event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEGMENT:
+    {
+      const GstSegment *segment;
+
+      /* some debug output */
+      gst_event_parse_segment (event, &segment);
+      /* FIXME: do we need to update segment base here (like accum in 0.10)? */
+      GST_DEBUG_OBJECT (demux,
+          "received format %d segment %" GST_SEGMENT_FORMAT, segment->format,
+          segment);
+
+      if (demux->common.state < GST_MATROSKA_READ_STATE_DATA) {
+        GST_DEBUG_OBJECT (demux, "still starting");
+        goto exit;
+      }
+
+      /* we only expect a BYTE segment, e.g. following a seek */
+      if (segment->format != GST_FORMAT_BYTES) {
+        GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
+        goto exit;
+      }
+
+      GST_DEBUG_OBJECT (demux, "clearing segment state");
+      GST_OBJECT_LOCK (demux);
+      /* clear current segment leftover */
+      gst_adapter_clear (demux->common.adapter);
+      /* and some streaming setup */
+      demux->common.offset = segment->start;
+      /* accumulate base based on current position */
+      if (GST_CLOCK_TIME_IS_VALID (demux->common.segment.position))
+        demux->common.segment.base +=
+            (MAX (demux->common.segment.position, demux->stream_start_time)
+            - demux->stream_start_time) / fabs (demux->common.segment.rate);
+      /* do not know where we are;
+       * need to come across a cluster and generate segment */
+      demux->common.segment.position = GST_CLOCK_TIME_NONE;
+      demux->cluster_time = GST_CLOCK_TIME_NONE;
+      demux->cluster_offset = 0;
+      demux->need_segment = TRUE;
+      demux->segment_seqnum = gst_event_get_seqnum (event);
+      /* but keep some of the upstream segment */
+      demux->common.segment.rate = segment->rate;
+      demux->common.segment.flags = segment->flags;
+      /* also check if need to keep some of the requested seek position */
+      if (demux->seek_offset == segment->start) {
+        GST_DEBUG_OBJECT (demux, "position matches requested seek");
+        demux->common.segment.position = demux->requested_seek_time;
+      } else {
+        GST_DEBUG_OBJECT (demux, "unexpected segment position");
+      }
+      demux->requested_seek_time = GST_CLOCK_TIME_NONE;
+      demux->seek_offset = -1;
+      GST_OBJECT_UNLOCK (demux);
+    exit:
+      /* chain will send initial segment after pads have been added,
+       * or otherwise come up with one */
+      GST_DEBUG_OBJECT (demux, "eating event");
+      gst_event_unref (event);
+      res = TRUE;
+      break;
+    }
+    case GST_EVENT_EOS:
+    {
+      if (demux->common.state != GST_MATROSKA_READ_STATE_DATA
+          && demux->common.state != GST_MATROSKA_READ_STATE_SCANNING) {
+        gst_event_unref (event);
+        GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
+            (NULL), ("got eos and didn't receive a complete header object"));
+      } else if (demux->common.num_streams == 0) {
+        GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
+            (NULL), ("got eos but no streams (yet)"));
+      } else {
+        gst_matroska_demux_send_event (demux, event);
+      }
+      break;
+    }
+    case GST_EVENT_FLUSH_STOP:
+    {
+      guint64 dur;
+
+      gst_adapter_clear (demux->common.adapter);
+      GST_OBJECT_LOCK (demux);
+      gst_matroska_read_common_reset_streams (&demux->common,
+          GST_CLOCK_TIME_NONE, TRUE);
+      gst_flow_combiner_reset (demux->flowcombiner);
+      dur = demux->common.segment.duration;
+      gst_segment_init (&demux->common.segment, GST_FORMAT_TIME);
+      demux->common.segment.duration = dur;
+      demux->cluster_time = GST_CLOCK_TIME_NONE;
+      demux->cluster_offset = 0;
+      GST_OBJECT_UNLOCK (demux);
+      /* fall-through */
+    }
+    default:
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return res;
+}
+
+static gboolean
+gst_matroska_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
+{
+  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (parent);
+  GstQuery *query;
+  gboolean pull_mode = FALSE;
+
+  query = gst_query_new_scheduling ();
+
+  if (gst_pad_peer_query (sinkpad, query))
+    pull_mode = gst_query_has_scheduling_mode_with_flags (query,
+        GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
+
+  gst_query_unref (query);
+
+  if (pull_mode) {
+    GST_DEBUG ("going to pull mode");
+    demux->streaming = FALSE;
+    return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
+  } else {
+    GST_DEBUG ("going to push (streaming) mode");
+    demux->streaming = TRUE;
+    return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
+  }
+}
+
+static gboolean
+gst_matroska_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
+    GstPadMode mode, gboolean active)
+{
+  switch (mode) {
+    case GST_PAD_MODE_PULL:
+      if (active) {
+        /* if we have a scheduler we can start the task */
+        gst_pad_start_task (sinkpad, (GstTaskFunction) gst_matroska_demux_loop,
+            sinkpad, NULL);
+      } else {
+        gst_pad_stop_task (sinkpad);
+      }
+      return TRUE;
+    case GST_PAD_MODE_PUSH:
+      return TRUE;
+    default:
+      return FALSE;
+  }
+}
+
+static GstCaps *
+gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *
+    videocontext, const gchar * codec_id, guint8 * data, guint size,
+    gchar ** codec_name, guint32 * riff_fourcc)
+{
+  GstMatroskaTrackContext *context = (GstMatroskaTrackContext *) videocontext;
+  GstCaps *caps = NULL;
+
+  g_assert (videocontext != NULL);
+  g_assert (codec_name != NULL);
+
+  if (riff_fourcc)
+    *riff_fourcc = 0;
+
+  /* TODO: check if we have all codec types from matroska-ids.h
+   *       check if we have to do more special things with codec_private
+   *
+   * Add support for
+   *  GST_MATROSKA_CODEC_ID_VIDEO_QUICKTIME
+   *  GST_MATROSKA_CODEC_ID_VIDEO_SNOW
+   */
+
+  if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC)) {
+    gst_riff_strf_vids *vids = NULL;
+
+    if (data) {
+      GstBuffer *buf = NULL;
+
+      vids = (gst_riff_strf_vids *) data;
+
+      /* assure size is big enough */
+      if (size < 24) {
+        GST_WARNING ("Too small BITMAPINFOHEADER (%d bytes)", size);
+        return NULL;
+      }
+      if (size < sizeof (gst_riff_strf_vids)) {
+        vids = g_new (gst_riff_strf_vids, 1);
+        memcpy (vids, data, size);
+      }
+
+      context->dts_only = TRUE; /* VFW files only store DTS */
+
+      /* little-endian -> byte-order */
+      vids->size = GUINT32_FROM_LE (vids->size);
+      vids->width = GUINT32_FROM_LE (vids->width);
+      vids->height = GUINT32_FROM_LE (vids->height);
+      vids->planes = GUINT16_FROM_LE (vids->planes);
+      vids->bit_cnt = GUINT16_FROM_LE (vids->bit_cnt);
+      vids->compression = GUINT32_FROM_LE (vids->compression);
+      vids->image_size = GUINT32_FROM_LE (vids->image_size);
+      vids->xpels_meter = GUINT32_FROM_LE (vids->xpels_meter);
+      vids->ypels_meter = GUINT32_FROM_LE (vids->ypels_meter);
+      vids->num_colors = GUINT32_FROM_LE (vids->num_colors);
+      vids->imp_colors = GUINT32_FROM_LE (vids->imp_colors);
+
+      if (size > sizeof (gst_riff_strf_vids)) { /* some extra_data */
+        gsize offset = sizeof (gst_riff_strf_vids);
+
+        buf =
+            gst_buffer_new_wrapped (g_memdup ((guint8 *) vids + offset,
+                size - offset), size - offset);
+      }
+
+      if (riff_fourcc)
+        *riff_fourcc = vids->compression;
+
+      caps = gst_riff_create_video_caps (vids->compression, NULL, vids,
+          buf, NULL, codec_name);
+
+      if (caps == NULL) {
+        GST_WARNING ("Unhandled RIFF fourcc %" GST_FOURCC_FORMAT,
+            GST_FOURCC_ARGS (vids->compression));
+      } else {
+        static GstStaticCaps intra_caps = GST_STATIC_CAPS ("image/jpeg; "
+            "video/x-raw; image/png; video/x-dv; video/x-huffyuv; video/x-ffv; "
+            "video/x-compressed-yuv");
+        context->intra_only =
+            gst_caps_can_intersect (gst_static_caps_get (&intra_caps), caps);
+      }
+
+      if (buf)
+        gst_buffer_unref (buf);
+
+      if (vids != (gst_riff_strf_vids *) data)
+        g_free (vids);
+    }
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED)) {
+    GstVideoInfo info;
+    GstVideoFormat format;
+
+    gst_video_info_init (&info);
+    switch (videocontext->fourcc) {
+      case GST_MAKE_FOURCC ('I', '4', '2', '0'):
+        format = GST_VIDEO_FORMAT_I420;
+        break;
+      case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
+        format = GST_VIDEO_FORMAT_YUY2;
+        break;
+      case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
+        format = GST_VIDEO_FORMAT_YV12;
+        break;
+      case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
+        format = GST_VIDEO_FORMAT_UYVY;
+        break;
+      case GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'):
+        format = GST_VIDEO_FORMAT_AYUV;
+        break;
+      case GST_MAKE_FOURCC ('Y', '8', '0', '0'):
+      case GST_MAKE_FOURCC ('Y', '8', ' ', ' '):
+        format = GST_VIDEO_FORMAT_GRAY8;
+        break;
+      case GST_MAKE_FOURCC ('R', 'G', 'B', 24):
+        format = GST_VIDEO_FORMAT_RGB;
+        break;
+      case GST_MAKE_FOURCC ('B', 'G', 'R', 24):
+        format = GST_VIDEO_FORMAT_BGR;
+        break;
+      default:
+        GST_DEBUG ("Unknown fourcc %" GST_FOURCC_FORMAT,
+            GST_FOURCC_ARGS (videocontext->fourcc));
+        return NULL;
+    }
+
+    context->intra_only = TRUE;
+
+    gst_video_info_set_format (&info, format, videocontext->pixel_width,
+        videocontext->pixel_height);
+    caps = gst_video_info_to_caps (&info);
+    *codec_name = gst_pb_utils_get_codec_description (caps);
+    context->alignment = 32;
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_SP)) {
+    caps = gst_caps_new_simple ("video/x-divx",
+        "divxversion", G_TYPE_INT, 4, NULL);
+    *codec_name = g_strdup ("MPEG-4 simple profile");
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP) ||
+      !strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AP)) {
+    caps = gst_caps_new_simple ("video/mpeg",
+        "mpegversion", G_TYPE_INT, 4,
+        "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+    if (data) {
+      GstBuffer *priv;
+
+      priv = gst_buffer_new_wrapped (g_memdup (data, size), size);
+      gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, priv, NULL);
+      gst_buffer_unref (priv);
+
+      gst_codec_utils_mpeg4video_caps_set_level_and_profile (caps, data, size);
+    }
+    if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP))
+      *codec_name = g_strdup ("MPEG-4 advanced simple profile");
+    else
+      *codec_name = g_strdup ("MPEG-4 advanced profile");
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3)) {
+#if 0
+    caps = gst_caps_new_full (gst_structure_new ("video/x-divx",
+            "divxversion", G_TYPE_INT, 3, NULL),
+        gst_structure_new ("video/x-msmpeg",
+            "msmpegversion", G_TYPE_INT, 43, NULL), NULL);
+#endif
+    caps = gst_caps_new_simple ("video/x-msmpeg",
+        "msmpegversion", G_TYPE_INT, 43, NULL);
+    *codec_name = g_strdup ("Microsoft MPEG-4 v.3");
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_MPEG1) ||
+      !strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_MPEG2)) {
+    gint mpegversion;
+
+    if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_MPEG1))
+      mpegversion = 1;
+    else
+      mpegversion = 2;
+
+    caps = gst_caps_new_simple ("video/mpeg",
+        "systemstream", G_TYPE_BOOLEAN, FALSE,
+        "mpegversion", G_TYPE_INT, mpegversion, NULL);
+    *codec_name = g_strdup_printf ("MPEG-%d video", mpegversion);
+    context->postprocess_frame = gst_matroska_demux_add_mpeg_seq_header;
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_MJPEG)) {
+    caps = gst_caps_new_empty_simple ("image/jpeg");
+    *codec_name = g_strdup ("Motion-JPEG");
+    context->intra_only = TRUE;
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC)) {
+    caps = gst_caps_new_empty_simple ("video/x-h264");
+    if (data) {
+      GstBuffer *priv;
+
+      /* First byte is the version, second is the profile indication, and third
+       * is the 5 contraint_set_flags and 3 reserved bits. Fourth byte is the
+       * level indication. */
+      gst_codec_utils_h264_caps_set_level_and_profile (caps, data + 1,
+          size - 1);
+
+      priv = gst_buffer_new_wrapped (g_memdup (data, size), size);
+      gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, priv, NULL);
+      gst_buffer_unref (priv);
+
+      gst_caps_set_simple (caps, "stream-format", G_TYPE_STRING, "avc",
+          "alignment", G_TYPE_STRING, "au", NULL);
+    } else {
+      GST_WARNING ("No codec data found, assuming output is byte-stream");
+      gst_caps_set_simple (caps, "stream-format", G_TYPE_STRING, "byte-stream",
+          NULL);
+    }
+    *codec_name = g_strdup ("H264");
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_MPEGH_HEVC)) {
+    caps = gst_caps_new_empty_simple ("video/x-h265");
+    if (data) {
+      GstBuffer *priv;
+
+      gst_codec_utils_h265_caps_set_level_tier_and_profile (caps, data + 1,
+          size - 1);
+
+      priv = gst_buffer_new_wrapped (g_memdup (data, size), size);
+      gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, priv, NULL);
+      gst_buffer_unref (priv);
+
+      gst_caps_set_simple (caps, "stream-format", G_TYPE_STRING, "hvc1",
+          "alignment", G_TYPE_STRING, "au", NULL);
+    } else {
+      GST_WARNING ("No codec data found, assuming output is byte-stream");
+      gst_caps_set_simple (caps, "stream-format", G_TYPE_STRING, "byte-stream",
+          NULL);
+    }
+    *codec_name = g_strdup ("HEVC");
+  } else if ((!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1)) ||
+      (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2)) ||
+      (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3)) ||
+      (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4))) {
+    gint rmversion = -1;
+
+    if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1))
+      rmversion = 1;
+    else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2))
+      rmversion = 2;
+    else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3))
+      rmversion = 3;
+    else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4))
+      rmversion = 4;
+
+    caps = gst_caps_new_simple ("video/x-pn-realvideo",
+        "rmversion", G_TYPE_INT, rmversion, NULL);
+    GST_DEBUG ("data:%p, size:0x%x", data, size);
+    /* We need to extract the extradata ! */
+    if (data && (size >= 0x22)) {
+      GstBuffer *priv;
+      guint rformat;
+      guint subformat;
+
+      subformat = GST_READ_UINT32_BE (data + 0x1a);
+      rformat = GST_READ_UINT32_BE (data + 0x1e);
+
+      priv =
+          gst_buffer_new_wrapped (g_memdup (data + 0x1a, size - 0x1a),
+          size - 0x1a);
+      gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, priv, "format",
+          G_TYPE_INT, rformat, "subformat", G_TYPE_INT, subformat, NULL);
+      gst_buffer_unref (priv);
+
+    }
+    *codec_name = g_strdup_printf ("RealVideo %d.0", rmversion);
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_THEORA)) {
+    caps = gst_caps_new_empty_simple ("video/x-theora");
+    context->stream_headers =
+        gst_matroska_parse_xiph_stream_headers (context->codec_priv,
+        context->codec_priv_size);
+    /* FIXME: mark stream as broken and skip if there are no stream headers */
+    context->send_stream_headers = TRUE;
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC)) {
+    caps = gst_caps_new_empty_simple ("video/x-dirac");
+    *codec_name = g_strdup_printf ("Dirac");
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VP8)) {
+    caps = gst_caps_new_empty_simple ("video/x-vp8");
+    *codec_name = g_strdup_printf ("On2 VP8");
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VP9)) {
+    caps = gst_caps_new_empty_simple ("video/x-vp9");
+    *codec_name = g_strdup_printf ("On2 VP9");
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_AV1)) {
+    caps = gst_caps_new_empty_simple ("video/x-av1");
+    *codec_name = g_strdup_printf ("AOM AV1");
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_PRORES)) {
+    guint32 fourcc;
+    const gchar *variant, *variant_descr = "";
+
+    /* Expect a fourcc in the codec private data */
+    if (!data || size < 4) {
+      GST_WARNING ("No or too small PRORESS fourcc (%d bytes)", size);
+      return NULL;
+    }
+
+    fourcc = GST_STR_FOURCC (data);
+    switch (fourcc) {
+      case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
+        variant_descr = " 4:2:2 LT";
+        variant = "lt";
+        break;
+      case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
+        variant = "hq";
+        variant_descr = " 4:2:2 HQ";
+        break;
+      case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
+        variant = "4444";
+        variant_descr = " 4:4:4:4";
+        break;
+      case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
+        variant = "proxy";
+        variant_descr = " 4:2:2 Proxy";
+        break;
+      case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
+      default:
+        variant = "standard";
+        variant_descr = " 4:2:2 SD";
+        break;
+    }
+
+    GST_LOG ("Prores video, codec fourcc %" GST_FOURCC_FORMAT,
+        GST_FOURCC_ARGS (fourcc));
+
+    caps = gst_caps_new_simple ("video/x-prores",
+        "format", G_TYPE_STRING, variant, NULL);
+    *codec_name = g_strdup_printf ("Apple ProRes%s", variant_descr);
+    context->postprocess_frame = gst_matroska_demux_add_prores_header;
+  } else {
+    GST_WARNING ("Unknown codec '%s', cannot build Caps", codec_id);
+    return NULL;
+  }
+
+  if (caps != NULL) {
+    int i;
+    GstStructure *structure;
+
+    for (i = 0; i < gst_caps_get_size (caps); i++) {
+      structure = gst_caps_get_structure (caps, i);
+
+      /* FIXME: use the real unit here! */
+      GST_DEBUG ("video size %dx%d, target display size %dx%d (any unit)",
+          videocontext->pixel_width,
+          videocontext->pixel_height,
+          videocontext->display_width, videocontext->display_height);
+
+      /* pixel width and height are the w and h of the video in pixels */
+      if (videocontext->pixel_width > 0 && videocontext->pixel_height > 0) {
+        gint w = videocontext->pixel_width;
+        gint h = videocontext->pixel_height;
+
+        gst_structure_set (structure,
+            "width", G_TYPE_INT, w, "height", G_TYPE_INT, h, NULL);
+      }
+
+      if (videocontext->display_width > 0 || videocontext->display_height > 0) {
+        int n, d;
+
+        if (videocontext->display_width <= 0)
+          videocontext->display_width = videocontext->pixel_width;
+        if (videocontext->display_height <= 0)
+          videocontext->display_height = videocontext->pixel_height;
+
+        /* calculate the pixel aspect ratio using the display and pixel w/h */
+        n = videocontext->display_width * videocontext->pixel_height;
+        d = videocontext->display_height * videocontext->pixel_width;
+        GST_DEBUG ("setting PAR to %d/%d", n, d);
+        gst_structure_set (structure, "pixel-aspect-ratio",
+            GST_TYPE_FRACTION,
+            videocontext->display_width * videocontext->pixel_height,
+            videocontext->display_height * videocontext->pixel_width, NULL);
+      }
+
+      if (videocontext->default_fps > 0.0) {
+        gint fps_n, fps_d;
+
+        gst_util_double_to_fraction (videocontext->default_fps, &fps_n, &fps_d);
+
+        GST_DEBUG ("using default fps %d/%d", fps_n, fps_d);
+
+        gst_structure_set (structure, "framerate", GST_TYPE_FRACTION, fps_n,
+            fps_d, NULL);
+      } else if (context->default_duration > 0) {
+        int fps_n, fps_d;
+
+        gst_video_guess_framerate (context->default_duration, &fps_n, &fps_d);
+
+        GST_INFO ("using default duration %" G_GUINT64_FORMAT
+            " framerate %d/%d", context->default_duration, fps_n, fps_d);
+
+        gst_structure_set (structure, "framerate", GST_TYPE_FRACTION,
+            fps_n, fps_d, NULL);
+      } else {
+        gst_structure_set (structure, "framerate", GST_TYPE_FRACTION,
+            0, 1, NULL);
+      }
+
+      if (videocontext->parent.flags & GST_MATROSKA_VIDEOTRACK_INTERLACED)
+        gst_structure_set (structure, "interlace-mode", G_TYPE_STRING,
+            "mixed", NULL);
+    }
+    if (videocontext->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
+      if (gst_video_multiview_guess_half_aspect (videocontext->multiview_mode,
+              videocontext->pixel_width, videocontext->pixel_height,
+              videocontext->display_width * videocontext->pixel_height,
+              videocontext->display_height * videocontext->pixel_width)) {
+        videocontext->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
+      }
+      gst_caps_set_simple (caps,
+          "multiview-mode", G_TYPE_STRING,
+          gst_video_multiview_mode_to_caps_string
+          (videocontext->multiview_mode), "multiview-flags",
+          GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, videocontext->multiview_flags,
+          GST_FLAG_SET_MASK_EXACT, NULL);
+    }
+
+    if (videocontext->colorimetry.range != GST_VIDEO_COLOR_RANGE_UNKNOWN ||
+        videocontext->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN ||
+        videocontext->colorimetry.transfer != GST_VIDEO_TRANSFER_UNKNOWN ||
+        videocontext->colorimetry.primaries !=
+        GST_VIDEO_COLOR_PRIMARIES_UNKNOWN) {
+      gchar *colorimetry =
+          gst_video_colorimetry_to_string (&videocontext->colorimetry);
+      gst_caps_set_simple (caps, "colorimetry", G_TYPE_STRING, colorimetry,
+          NULL);
+      GST_DEBUG ("setting colorimetry to %s", colorimetry);
+      g_free (colorimetry);
+    }
+
+    caps = gst_caps_simplify (caps);
+  }
+
+  return caps;
+}
+
+/*
+ * Some AAC specific code... *sigh*
+ * FIXME: maybe we should use '15' and code the sample rate explicitly
+ * if the sample rate doesn't match the predefined rates exactly? (tpm)
+ */
+
+static gint
+aac_rate_idx (gint rate)
+{
+  if (92017 <= rate)
+    return 0;
+  else if (75132 <= rate)
+    return 1;
+  else if (55426 <= rate)
+    return 2;
+  else if (46009 <= rate)
+    return 3;
+  else if (37566 <= rate)
+    return 4;
+  else if (27713 <= rate)
+    return 5;
+  else if (23004 <= rate)
+    return 6;
+  else if (18783 <= rate)
+    return 7;
+  else if (13856 <= rate)
+    return 8;
+  else if (11502 <= rate)
+    return 9;
+  else if (9391 <= rate)
+    return 10;
+  else
+    return 11;
+}
+
+static gint
+aac_profile_idx (const gchar * codec_id)
+{
+  gint profile;
+
+  if (strlen (codec_id) <= 12)
+    profile = 3;
+  else if (!strncmp (&codec_id[12], "MAIN", 4))
+    profile = 0;
+  else if (!strncmp (&codec_id[12], "LC", 2))
+    profile = 1;
+  else if (!strncmp (&codec_id[12], "SSR", 3))
+    profile = 2;
+  else
+    profile = 3;
+
+  return profile;
+}
+
+static guint
+round_up_pow2 (guint n)
+{
+  n = n - 1;
+  n = n | (n >> 1);
+  n = n | (n >> 2);
+  n = n | (n >> 4);
+  n = n | (n >> 8);
+  n = n | (n >> 16);
+  return n + 1;
+}
+
+#define AAC_SYNC_EXTENSION_TYPE 0x02b7
+
+static GstCaps *
+gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext *
+    audiocontext, const gchar * codec_id, guint8 * data, guint size,
+    gchar ** codec_name, guint16 * riff_audio_fmt)
+{
+  GstMatroskaTrackContext *context = (GstMatroskaTrackContext *) audiocontext;
+  GstCaps *caps = NULL;
+
+  g_assert (audiocontext != NULL);
+  g_assert (codec_name != NULL);
+
+  if (riff_audio_fmt)
+    *riff_audio_fmt = 0;
+
+  /* TODO: check if we have all codec types from matroska-ids.h
+   *       check if we have to do more special things with codec_private
+   *       check if we need bitdepth in different places too
+   *       implement channel position magic
+   * Add support for:
+   *  GST_MATROSKA_CODEC_ID_AUDIO_AC3_BSID9
+   *  GST_MATROSKA_CODEC_ID_AUDIO_AC3_BSID10
+   *  GST_MATROSKA_CODEC_ID_AUDIO_QUICKTIME_QDMC
+   *  GST_MATROSKA_CODEC_ID_AUDIO_QUICKTIME_QDM2
+   */
+
+  if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1) ||
+      !strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2) ||
+      !strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3)) {
+    gint layer;
+
+    if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1))
+      layer = 1;
+    else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2))
+      layer = 2;
+    else
+      layer = 3;
+
+    caps = gst_caps_new_simple ("audio/mpeg",
+        "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, layer, NULL);
+    *codec_name = g_strdup_printf ("MPEG-1 layer %d", layer);
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE) ||
+      !strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE)) {
+    gboolean sign;
+    gint endianness;
+    GstAudioFormat format;
+
+    sign = (audiocontext->bitdepth != 8);
+    if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE))
+      endianness = G_BIG_ENDIAN;
+    else
+      endianness = G_LITTLE_ENDIAN;
+
+    format = gst_audio_format_build_integer (sign, endianness,
+        audiocontext->bitdepth, audiocontext->bitdepth);
+
+    /* FIXME: Channel mask and reordering */
+    caps = gst_caps_new_simple ("audio/x-raw",
+        "format", G_TYPE_STRING, gst_audio_format_to_string (format),
+        "layout", G_TYPE_STRING, "interleaved",
+        "channel-mask", GST_TYPE_BITMASK,
+        gst_audio_channel_get_fallback_mask (audiocontext->channels), NULL);
+
+    *codec_name = g_strdup_printf ("Raw %d-bit PCM audio",
+        audiocontext->bitdepth);
+    context->alignment = GST_ROUND_UP_8 (audiocontext->bitdepth) / 8;
+    context->alignment = round_up_pow2 (context->alignment);
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT)) {
+    const gchar *format;
+    if (audiocontext->bitdepth == 32)
+      format = "F32LE";
+    else
+      format = "F64LE";
+    /* FIXME: Channel mask and reordering */
+    caps = gst_caps_new_simple ("audio/x-raw",
+        "format", G_TYPE_STRING, format,
+        "layout", G_TYPE_STRING, "interleaved",
+        "channel-mask", GST_TYPE_BITMASK,
+        gst_audio_channel_get_fallback_mask (audiocontext->channels), NULL);
+    *codec_name = g_strdup_printf ("Raw %d-bit floating-point audio",
+        audiocontext->bitdepth);
+    context->alignment = audiocontext->bitdepth / 8;
+    context->alignment = round_up_pow2 (context->alignment);
+  } else if (!strncmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_AC3,
+          strlen (GST_MATROSKA_CODEC_ID_AUDIO_AC3))) {
+    caps = gst_caps_new_simple ("audio/x-ac3",
+        "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+    *codec_name = g_strdup ("AC-3 audio");
+  } else if (!strncmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_EAC3,
+          strlen (GST_MATROSKA_CODEC_ID_AUDIO_EAC3))) {
+    caps = gst_caps_new_simple ("audio/x-eac3",
+        "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+    *codec_name = g_strdup ("E-AC-3 audio");
+  } else if (!strncmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_TRUEHD,
+          strlen (GST_MATROSKA_CODEC_ID_AUDIO_TRUEHD))) {
+    caps = gst_caps_new_empty_simple ("audio/x-true-hd");
+    *codec_name = g_strdup ("Dolby TrueHD");
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_DTS)) {
+    caps = gst_caps_new_empty_simple ("audio/x-dts");
+    *codec_name = g_strdup ("DTS audio");
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_VORBIS)) {
+    caps = gst_caps_new_empty_simple ("audio/x-vorbis");
+    context->stream_headers =
+        gst_matroska_parse_xiph_stream_headers (context->codec_priv,
+        context->codec_priv_size);
+    /* FIXME: mark stream as broken and skip if there are no stream headers */
+    context->send_stream_headers = TRUE;
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_FLAC)) {
+    caps = gst_caps_new_empty_simple ("audio/x-flac");
+    context->stream_headers =
+        gst_matroska_parse_flac_stream_headers (context->codec_priv,
+        context->codec_priv_size);
+    /* FIXME: mark stream as broken and skip if there are no stream headers */
+    context->send_stream_headers = TRUE;
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_SPEEX)) {
+    caps = gst_caps_new_empty_simple ("audio/x-speex");
+    context->stream_headers =
+        gst_matroska_parse_speex_stream_headers (context->codec_priv,
+        context->codec_priv_size);
+    /* FIXME: mark stream as broken and skip if there are no stream headers */
+    context->send_stream_headers = TRUE;
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)) {
+    GstBuffer *tmp;
+
+    if (context->codec_priv_size >= 19) {
+      if (audiocontext->samplerate)
+        GST_WRITE_UINT32_LE ((guint8 *) context->codec_priv + 12,
+            audiocontext->samplerate);
+      if (context->codec_delay) {
+        guint64 delay =
+            gst_util_uint64_scale_round (context->codec_delay, 48000,
+            GST_SECOND);
+        GST_WRITE_UINT16_LE ((guint8 *) context->codec_priv + 10, delay);
+      }
+
+      tmp =
+          gst_buffer_new_wrapped (g_memdup (context->codec_priv,
+              context->codec_priv_size), context->codec_priv_size);
+      caps = gst_codec_utils_opus_create_caps_from_header (tmp, NULL);
+      gst_buffer_unref (tmp);
+      *codec_name = g_strdup ("Opus");
+    } else if (context->codec_priv_size == 0) {
+      GST_WARNING ("No Opus codec data found, trying to create one");
+      if (audiocontext->channels <= 2) {
+        guint8 streams, coupled, channels;
+        guint32 samplerate;
+
+        samplerate =
+            audiocontext->samplerate == 0 ? 48000 : audiocontext->samplerate;
+        channels = audiocontext->channels == 0 ? 2 : audiocontext->channels;
+        if (channels == 1) {
+          streams = 1;
+          coupled = 0;
+        } else {
+          streams = 1;
+          coupled = 1;
+        }
+
+        caps =
+            gst_codec_utils_opus_create_caps (samplerate, channels, 0, streams,
+            coupled, NULL);
+        if (caps) {
+          *codec_name = g_strdup ("Opus");
+        } else {
+          GST_WARNING ("Failed to create Opus caps from audio context");
+        }
+      } else {
+        GST_WARNING ("No Opus codec data, and not enough info to create one");
+      }
+    } else {
+      GST_WARNING ("Invalid Opus codec data size (got %" G_GSIZE_FORMAT
+          ", expected 19)", context->codec_priv_size);
+    }
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_ACM)) {
+    gst_riff_strf_auds auds;
+
+    if (data && size >= 18) {
+      GstBuffer *codec_data = NULL;
+
+      /* little-endian -> byte-order */
+      auds.format = GST_READ_UINT16_LE (data);
+      auds.channels = GST_READ_UINT16_LE (data + 2);
+      auds.rate = GST_READ_UINT32_LE (data + 4);
+      auds.av_bps = GST_READ_UINT32_LE (data + 8);
+      auds.blockalign = GST_READ_UINT16_LE (data + 12);
+      auds.bits_per_sample = GST_READ_UINT16_LE (data + 16);
+
+      /* 18 is the waveformatex size */
+      if (size > 18) {
+        codec_data = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+            data + 18, size - 18, 0, size - 18, NULL, NULL);
+      }
+
+      if (riff_audio_fmt)
+        *riff_audio_fmt = auds.format;
+
+      /* FIXME: Handle reorder map */
+      caps = gst_riff_create_audio_caps (auds.format, NULL, &auds, NULL,
+          codec_data, codec_name, NULL);
+      if (codec_data)
+        gst_buffer_unref (codec_data);
+
+      if (caps == NULL) {
+        GST_WARNING ("Unhandled RIFF audio format 0x%02x", auds.format);
+      }
+    } else {
+      GST_WARNING ("Invalid codec data size (%d expected, got %d)", 18, size);
+    }
+  } else if (g_str_has_prefix (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_AAC)) {
+    GstBuffer *priv = NULL;
+    gint mpegversion;
+    gint rate_idx, profile;
+    guint8 *data = NULL;
+
+    /* unspecified AAC profile with opaque private codec data */
+    if (strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_AAC) == 0) {
+      if (context->codec_priv_size >= 2) {
+        guint obj_type, freq_index, explicit_freq_bytes = 0;
+
+        codec_id = GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4;
+        mpegversion = 4;
+        freq_index = (GST_READ_UINT16_BE (context->codec_priv) & 0x780) >> 7;
+        obj_type = (GST_READ_UINT16_BE (context->codec_priv) & 0xF800) >> 11;
+        if (freq_index == 15)
+          explicit_freq_bytes = 3;
+        GST_DEBUG ("obj_type = %u, freq_index = %u", obj_type, freq_index);
+        priv = gst_buffer_new_wrapped (g_memdup (context->codec_priv,
+                context->codec_priv_size), context->codec_priv_size);
+        /* assume SBR if samplerate <= 24kHz */
+        if (obj_type == 5 || (freq_index >= 6 && freq_index != 15) ||
+            (context->codec_priv_size == (5 + explicit_freq_bytes))) {
+          audiocontext->samplerate *= 2;
+        }
+      } else {
+        GST_WARNING ("Opaque A_AAC codec ID, but no codec private data");
+        /* this is pretty broken;
+         * maybe we need to make up some default private,
+         * or maybe ADTS data got dumped in.
+         * Let's set up some private data now, and check actual data later */
+        /* just try this and see what happens ... */
+        codec_id = GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4;
+        context->postprocess_frame = gst_matroska_demux_check_aac;
+      }
+    }
+
+    /* make up decoder-specific data if it is not supplied */
+    if (priv == NULL) {
+      GstMapInfo map;
+
+      priv = gst_buffer_new_allocate (NULL, 5, NULL);
+      gst_buffer_map (priv, &map, GST_MAP_WRITE);
+      data = map.data;
+      rate_idx = aac_rate_idx (audiocontext->samplerate);
+      profile = aac_profile_idx (codec_id);
+
+      data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
+      data[1] = ((rate_idx & 0x1) << 7) | (audiocontext->channels << 3);
+
+      if (!strncmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2,
+              strlen (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2))) {
+        mpegversion = 2;
+        gst_buffer_unmap (priv, &map);
+        gst_buffer_set_size (priv, 2);
+      } else if (!strncmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4,
+              strlen (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4))) {
+        mpegversion = 4;
+
+        if (g_strrstr (codec_id, "SBR")) {
+          /* HE-AAC (aka SBR AAC) */
+          audiocontext->samplerate *= 2;
+          rate_idx = aac_rate_idx (audiocontext->samplerate);
+          data[2] = AAC_SYNC_EXTENSION_TYPE >> 3;
+          data[3] = ((AAC_SYNC_EXTENSION_TYPE & 0x07) << 5) | 5;
+          data[4] = (1 << 7) | (rate_idx << 3);
+          gst_buffer_unmap (priv, &map);
+        } else {
+          gst_buffer_unmap (priv, &map);
+          gst_buffer_set_size (priv, 2);
+        }
+      } else {
+        gst_buffer_unmap (priv, &map);
+        gst_buffer_unref (priv);
+        priv = NULL;
+        GST_ERROR ("Unknown AAC profile and no codec private data");
+      }
+    }
+
+    if (priv) {
+      caps = gst_caps_new_simple ("audio/mpeg",
+          "mpegversion", G_TYPE_INT, mpegversion,
+          "framed", G_TYPE_BOOLEAN, TRUE,
+          "stream-format", G_TYPE_STRING, "raw", NULL);
+      gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, priv, NULL);
+      if (context->codec_priv && context->codec_priv_size > 0)
+        gst_codec_utils_aac_caps_set_level_and_profile (caps,
+            context->codec_priv, context->codec_priv_size);
+      *codec_name = g_strdup_printf ("MPEG-%d AAC audio", mpegversion);
+      gst_buffer_unref (priv);
+    }
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_TTA)) {
+    caps = gst_caps_new_simple ("audio/x-tta",
+        "width", G_TYPE_INT, audiocontext->bitdepth, NULL);
+    *codec_name = g_strdup ("TTA audio");
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_WAVPACK4)) {
+    caps = gst_caps_new_simple ("audio/x-wavpack",
+        "width", G_TYPE_INT, audiocontext->bitdepth,
+        "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+    *codec_name = g_strdup ("Wavpack audio");
+    context->postprocess_frame = gst_matroska_demux_add_wvpk_header;
+    audiocontext->wvpk_block_index = 0;
+  } else if ((!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4)) ||
+      (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8)) ||
+      (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK))) {
+    gint raversion = -1;
+
+    if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4))
+      raversion = 1;
+    else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK))
+      raversion = 8;
+    else
+      raversion = 2;
+
+    caps = gst_caps_new_simple ("audio/x-pn-realaudio",
+        "raversion", G_TYPE_INT, raversion, NULL);
+    /* Extract extra information from caps, mapping varies based on codec */
+    if (data && (size >= 0x50)) {
+      GstBuffer *priv;
+      guint flavor;
+      guint packet_size;
+      guint height;
+      guint leaf_size;
+      guint sample_width;
+      guint extra_data_size;
+
+      GST_DEBUG ("real audio raversion:%d", raversion);
+      if (raversion == 8) {
+        /* COOK */
+        flavor = GST_READ_UINT16_BE (data + 22);
+        packet_size = GST_READ_UINT32_BE (data + 24);
+        height = GST_READ_UINT16_BE (data + 40);
+        leaf_size = GST_READ_UINT16_BE (data + 44);
+        sample_width = GST_READ_UINT16_BE (data + 58);
+        extra_data_size = GST_READ_UINT32_BE (data + 74);
+
+        GST_DEBUG
+            ("flavor:%d, packet_size:%d, height:%d, leaf_size:%d, sample_width:%d, extra_data_size:%d",
+            flavor, packet_size, height, leaf_size, sample_width,
+            extra_data_size);
+        gst_caps_set_simple (caps, "flavor", G_TYPE_INT, flavor, "packet_size",
+            G_TYPE_INT, packet_size, "height", G_TYPE_INT, height, "leaf_size",
+            G_TYPE_INT, leaf_size, "width", G_TYPE_INT, sample_width, NULL);
+
+        if ((size - 78) >= extra_data_size) {
+          priv = gst_buffer_new_wrapped (g_memdup (data + 78, extra_data_size),
+              extra_data_size);
+          gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, priv, NULL);
+          gst_buffer_unref (priv);
+        }
+      }
+    }
+
+    *codec_name = g_strdup_printf ("RealAudio %d.0", raversion);
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_REAL_SIPR)) {
+    caps = gst_caps_new_empty_simple ("audio/x-sipro");
+    *codec_name = g_strdup ("Sipro/ACELP.NET Voice Codec");
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_REAL_RALF)) {
+    caps = gst_caps_new_empty_simple ("audio/x-ralf-mpeg4-generic");
+    *codec_name = g_strdup ("Real Audio Lossless");
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_REAL_ATRC)) {
+    caps = gst_caps_new_empty_simple ("audio/x-vnd.sony.atrac3");
+    *codec_name = g_strdup ("Sony ATRAC3");
+  } else {
+    GST_WARNING ("Unknown codec '%s', cannot build Caps", codec_id);
+    return NULL;
+  }
+
+  if (caps != NULL) {
+    if (audiocontext->samplerate > 0 && audiocontext->channels > 0) {
+      gint i;
+
+      for (i = 0; i < gst_caps_get_size (caps); i++) {
+        gst_structure_set (gst_caps_get_structure (caps, i),
+            "channels", G_TYPE_INT, audiocontext->channels,
+            "rate", G_TYPE_INT, audiocontext->samplerate, NULL);
+      }
+    }
+
+    caps = gst_caps_simplify (caps);
+  }
+
+  return caps;
+}
+
+static GstCaps *
+gst_matroska_demux_subtitle_caps (GstMatroskaTrackSubtitleContext *
+    subtitlecontext, const gchar * codec_id, gpointer data, guint size)
+{
+  GstCaps *caps = NULL;
+  GstMatroskaTrackContext *context =
+      (GstMatroskaTrackContext *) subtitlecontext;
+
+  /* for backwards compatibility */
+  if (!g_ascii_strcasecmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_ASCII))
+    codec_id = GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8;
+  else if (!g_ascii_strcasecmp (codec_id, "S_SSA"))
+    codec_id = GST_MATROSKA_CODEC_ID_SUBTITLE_SSA;
+  else if (!g_ascii_strcasecmp (codec_id, "S_ASS"))
+    codec_id = GST_MATROSKA_CODEC_ID_SUBTITLE_ASS;
+  else if (!g_ascii_strcasecmp (codec_id, "S_USF"))
+    codec_id = GST_MATROSKA_CODEC_ID_SUBTITLE_USF;
+
+  /* TODO: Add GST_MATROSKA_CODEC_ID_SUBTITLE_BMP support
+   * Check if we have to do something with codec_private */
+  if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8)) {
+    /* well, plain text simply does not have a lot of markup ... */
+    caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
+        "pango-markup", NULL);
+    context->postprocess_frame = gst_matroska_demux_check_subtitle_buffer;
+    subtitlecontext->check_markup = TRUE;
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_SSA)) {
+    caps = gst_caps_new_empty_simple ("application/x-ssa");
+    context->postprocess_frame = gst_matroska_demux_check_subtitle_buffer;
+    subtitlecontext->check_markup = FALSE;
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_ASS)) {
+    caps = gst_caps_new_empty_simple ("application/x-ass");
+    context->postprocess_frame = gst_matroska_demux_check_subtitle_buffer;
+    subtitlecontext->check_markup = FALSE;
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_USF)) {
+    caps = gst_caps_new_empty_simple ("application/x-usf");
+    context->postprocess_frame = gst_matroska_demux_check_subtitle_buffer;
+    subtitlecontext->check_markup = FALSE;
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB)) {
+    caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
+    ((GstMatroskaTrackContext *) subtitlecontext)->send_dvd_event = TRUE;
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_HDMVPGS)) {
+    caps = gst_caps_new_empty_simple ("subpicture/x-pgs");
+  } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_KATE)) {
+    caps = gst_caps_new_empty_simple ("subtitle/x-kate");
+    context->stream_headers =
+        gst_matroska_parse_xiph_stream_headers (context->codec_priv,
+        context->codec_priv_size);
+    /* FIXME: mark stream as broken and skip if there are no stream headers */
+    context->send_stream_headers = TRUE;
+  } else {
+    GST_DEBUG ("Unknown subtitle stream: codec_id='%s'", codec_id);
+    caps = gst_caps_new_empty_simple ("application/x-subtitle-unknown");
+  }
+
+  if (data != NULL && size > 0) {
+    GstBuffer *buf;
+
+    buf = gst_buffer_new_wrapped (g_memdup (data, size), size);
+    gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buf, NULL);
+    gst_buffer_unref (buf);
+  }
+
+  return caps;
+}
+
+#if 0
+static void
+gst_matroska_demux_set_index (GstElement * element, GstIndex * index)
+{
+  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
+
+  GST_OBJECT_LOCK (demux);
+  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->common.element_index);
+}
+
+static GstIndex *
+gst_matroska_demux_get_index (GstElement * element)
+{
+  GstIndex *result = NULL;
+  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
+
+  GST_OBJECT_LOCK (demux);
+  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);
+
+  return result;
+}
+#endif
+
+static GstStateChangeReturn
+gst_matroska_demux_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+  /* handle upwards state changes here */
+  switch (transition) {
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  /* handle downwards state changes */
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_matroska_demux_reset (GST_ELEMENT (demux));
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_matroska_demux_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstMatroskaDemux *demux;
+
+  g_return_if_fail (GST_IS_MATROSKA_DEMUX (object));
+  demux = GST_MATROSKA_DEMUX (object);
+
+  switch (prop_id) {
+    case PROP_MAX_GAP_TIME:
+      GST_OBJECT_LOCK (demux);
+      demux->max_gap_time = g_value_get_uint64 (value);
+      GST_OBJECT_UNLOCK (demux);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_matroska_demux_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstMatroskaDemux *demux;
+
+  g_return_if_fail (GST_IS_MATROSKA_DEMUX (object));
+  demux = GST_MATROSKA_DEMUX (object);
+
+  switch (prop_id) {
+    case PROP_MAX_GAP_TIME:
+      GST_OBJECT_LOCK (demux);
+      g_value_set_uint64 (value, demux->max_gap_time);
+      GST_OBJECT_UNLOCK (demux);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+gboolean
+gst_matroska_demux_plugin_init (GstPlugin * plugin)
+{
+  gst_riff_init ();
+
+  /* parser helper separate debug */
+  GST_DEBUG_CATEGORY_INIT (ebmlread_debug, "ebmlread",
+      0, "EBML stream helper class");
+
+  /* create an elementfactory for the matroska_demux element */
+  if (!gst_element_register (plugin, "matroskademux",
+          GST_RANK_PRIMARY, GST_TYPE_MATROSKA_DEMUX))
+    return FALSE;
+
+  return TRUE;
+}
diff --git a/gst/matroska/matroska-demux.h b/gst/matroska/matroska-demux.h
new file mode 100644
index 0000000..2fe248b
--- /dev/null
+++ b/gst/matroska/matroska-demux.h
@@ -0,0 +1,126 @@
+/* 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
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MATROSKA_DEMUX_H__
+#define __GST_MATROSKA_DEMUX_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstflowcombiner.h>
+
+#include "ebml-read.h"
+#include "matroska-ids.h"
+#include "matroska-read-common.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_MATROSKA_DEMUX \
+  (gst_matroska_demux_get_type ())
+#define GST_MATROSKA_DEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MATROSKA_DEMUX, GstMatroskaDemux))
+#define GST_MATROSKA_DEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MATROSKA_DEMUX, GstMatroskaDemuxClass))
+#define GST_IS_MATROSKA_DEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MATROSKA_DEMUX))
+#define GST_IS_MATROSKA_DEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MATROSKA_DEMUX))
+
+typedef struct _GstMatroskaDemux {
+  GstElement              parent;
+
+  /* < private > */
+
+  GstMatroskaReadCommon    common;
+
+  /* pads */
+  GstClock                *clock;
+  guint                    num_v_streams;
+  guint                    num_a_streams;
+  guint                    num_t_streams;
+
+  guint                    group_id;
+  gboolean                 have_group_id;
+
+  GstFlowCombiner         *flowcombiner;
+
+  /* state */
+  gboolean                 streaming;
+  guint64                  seek_block;
+  gboolean                 seek_first;
+
+  /* did we parse cues/tracks/segmentinfo already? */
+  gboolean                 tracks_parsed;
+  GList                   *seek_parsed;
+
+  /* cluster positions (optional) */
+  GArray                  *clusters;
+
+  /* keeping track of playback position */
+  GstClockTime             last_stop_end;
+  GstClockTime             stream_start_time;
+
+  /* Stop time for reverse playback */
+  GstClockTime             to_time;
+  GstEvent                *new_segment;
+
+  /* some state saving */
+  GstClockTime             cluster_time;
+  guint64                  cluster_offset;
+  guint64                  first_cluster_offset;
+  guint64                  next_cluster_offset;
+  GstClockTime             requested_seek_time;
+  guint64                  seek_offset;
+
+  /* alternative duration; optionally obtained from last cluster */
+  guint64                  last_cluster_offset;
+  GstClockTime             stream_last_time;
+
+  /* index stuff */
+  gboolean                 seekable;
+  gboolean                 building_index;
+  guint64                  index_offset;
+  GstEvent                *seek_event;
+  gboolean                 need_segment;
+  guint32                  segment_seqnum;
+
+  /* reverse playback */
+  GArray                  *seek_index;
+  gint                     seek_entry;
+
+  /* gap handling */
+  guint64                  max_gap_time;
+
+  /* for non-finalized files, with invalid segment duration */
+  gboolean                 invalid_duration;
+
+  /* Cached upstream length (default G_MAXUINT64) */
+  guint64	           cached_length;
+} GstMatroskaDemux;
+
+typedef struct _GstMatroskaDemuxClass {
+  GstElementClass parent;
+} GstMatroskaDemuxClass;
+
+gboolean gst_matroska_demux_plugin_init (GstPlugin *plugin);
+
+G_END_DECLS
+
+#endif /* __GST_MATROSKA_DEMUX_H__ */
diff --git a/gst/matroska/matroska-ids.c b/gst/matroska/matroska-ids.c
new file mode 100644
index 0000000..3be3d27
--- /dev/null
+++ b/gst/matroska/matroska-ids.c
@@ -0,0 +1,355 @@
+/* GStreamer Matroska muxer/demuxer
+ * (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * matroska-ids.c: matroska track context utility functions
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "matroska-ids.h"
+
+#include <string.h>
+
+gboolean
+gst_matroska_track_init_video_context (GstMatroskaTrackContext ** p_context)
+{
+  GstMatroskaTrackVideoContext *video_context;
+
+  g_assert (p_context != NULL && *p_context != NULL);
+
+  /* already set up? (track info might come before track type) */
+  if ((*p_context)->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
+    GST_LOG ("video context already set up");
+    return TRUE;
+  }
+
+  /* it better not have been set up as some other track type ... */
+  if ((*p_context)->type != 0) {
+    g_return_val_if_reached (FALSE);
+  }
+
+  video_context = g_renew (GstMatroskaTrackVideoContext, *p_context, 1);
+  *p_context = (GstMatroskaTrackContext *) video_context;
+
+  /* defaults */
+  (*p_context)->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
+  video_context->display_width = 0;
+  video_context->display_height = 0;
+  video_context->pixel_width = 0;
+  video_context->pixel_height = 0;
+  video_context->asr_mode = 0;
+  video_context->fourcc = 0;
+  video_context->default_fps = 0.0;
+  video_context->earliest_time = GST_CLOCK_TIME_NONE;
+  video_context->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
+  video_context->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
+  video_context->colorimetry.range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
+  video_context->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
+  video_context->colorimetry.transfer = GST_VIDEO_TRANSFER_UNKNOWN;
+  video_context->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
+
+
+  return TRUE;
+}
+
+gboolean
+gst_matroska_track_init_audio_context (GstMatroskaTrackContext ** p_context)
+{
+  GstMatroskaTrackAudioContext *audio_context;
+
+  g_assert (p_context != NULL && *p_context != NULL);
+
+  /* already set up? (track info might come before track type) */
+  if ((*p_context)->type == GST_MATROSKA_TRACK_TYPE_AUDIO)
+    return TRUE;
+
+  /* it better not have been set up as some other track type ... */
+  if ((*p_context)->type != 0) {
+    g_return_val_if_reached (FALSE);
+  }
+
+  audio_context = g_renew (GstMatroskaTrackAudioContext, *p_context, 1);
+  *p_context = (GstMatroskaTrackContext *) audio_context;
+
+  /* defaults */
+  (*p_context)->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
+  audio_context->channels = 1;
+  audio_context->samplerate = 8000;
+  return TRUE;
+}
+
+gboolean
+gst_matroska_track_init_subtitle_context (GstMatroskaTrackContext ** p_context)
+{
+  GstMatroskaTrackSubtitleContext *subtitle_context;
+
+  g_assert (p_context != NULL && *p_context != NULL);
+
+  /* already set up? (track info might come before track type) */
+  if ((*p_context)->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE)
+    return TRUE;
+
+  /* it better not have been set up as some other track type ... */
+  if ((*p_context)->type != 0) {
+    g_return_val_if_reached (FALSE);
+  }
+
+  subtitle_context = g_renew (GstMatroskaTrackSubtitleContext, *p_context, 1);
+  *p_context = (GstMatroskaTrackContext *) subtitle_context;
+
+  (*p_context)->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
+  subtitle_context->invalid_utf8 = FALSE;
+  subtitle_context->seen_markup_tag = FALSE;
+  return TRUE;
+}
+
+void
+gst_matroska_register_tags (void)
+{
+  /* TODO: register other custom tags */
+}
+
+GstBufferList *
+gst_matroska_parse_xiph_stream_headers (gpointer codec_data,
+    gsize codec_data_size)
+{
+  GstBufferList *list = NULL;
+  guint8 *p = codec_data;
+  gint i, offset, num_packets;
+  guint *length, last;
+
+  GST_MEMDUMP ("xiph codec data", codec_data, codec_data_size);
+
+  if (codec_data == NULL || codec_data_size == 0)
+    goto error;
+
+  /* start of the stream and vorbis audio or theora video, need to
+   * send the codec_priv data as first three packets */
+  num_packets = p[0] + 1;
+  GST_DEBUG ("%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
+      (guint) num_packets, codec_data_size);
+
+  length = g_alloca (num_packets * sizeof (guint));
+  last = 0;
+  offset = 1;
+
+  /* first packets, read length values */
+  for (i = 0; i < num_packets - 1; i++) {
+    length[i] = 0;
+    while (offset < codec_data_size) {
+      length[i] += p[offset];
+      if (p[offset++] != 0xff)
+        break;
+    }
+    last += length[i];
+  }
+  if (offset + last > codec_data_size)
+    goto error;
+
+  /* last packet is the remaining size */
+  length[i] = codec_data_size - offset - last;
+
+  list = gst_buffer_list_new ();
+
+  for (i = 0; i < num_packets; i++) {
+    GstBuffer *hdr;
+
+    GST_DEBUG ("buffer %d: %u bytes", i, (guint) length[i]);
+
+    if (offset + length[i] > codec_data_size)
+      goto error;
+
+    hdr = gst_buffer_new_wrapped (g_memdup (p + offset, length[i]), length[i]);
+    gst_buffer_list_add (list, hdr);
+
+    offset += length[i];
+  }
+
+  return list;
+
+/* ERRORS */
+error:
+  {
+    if (list != NULL)
+      gst_buffer_list_unref (list);
+    return NULL;
+  }
+}
+
+GstBufferList *
+gst_matroska_parse_speex_stream_headers (gpointer codec_data,
+    gsize codec_data_size)
+{
+  GstBufferList *list = NULL;
+  GstBuffer *hdr;
+  guint8 *pdata = codec_data;
+
+  GST_MEMDUMP ("speex codec data", codec_data, codec_data_size);
+
+  if (codec_data == NULL || codec_data_size < 80) {
+    GST_WARNING ("not enough codec priv data for speex headers");
+    return NULL;
+  }
+
+  if (memcmp (pdata, "Speex   ", 8) != 0) {
+    GST_WARNING ("no Speex marker at start of stream headers");
+    return NULL;
+  }
+
+  list = gst_buffer_list_new ();
+
+  hdr = gst_buffer_new_wrapped (g_memdup (pdata, 80), 80);
+  gst_buffer_list_add (list, hdr);
+
+  if (codec_data_size > 80) {
+    hdr = gst_buffer_new_wrapped (g_memdup (pdata + 80, codec_data_size - 80),
+        codec_data_size - 80);
+    gst_buffer_list_add (list, hdr);
+  }
+
+  return list;
+}
+
+GstBufferList *
+gst_matroska_parse_opus_stream_headers (gpointer codec_data,
+    gsize codec_data_size)
+{
+  GstBufferList *list = NULL;
+  GstBuffer *hdr;
+  guint8 *pdata = codec_data;
+
+  GST_MEMDUMP ("opus codec data", codec_data, codec_data_size);
+
+  if (codec_data == NULL || codec_data_size < 19) {
+    GST_WARNING ("not enough codec priv data for opus headers");
+    return NULL;
+  }
+
+  if (memcmp (pdata, "OpusHead", 8) != 0) {
+    GST_WARNING ("no OpusHead marker at start of stream headers");
+    return NULL;
+  }
+
+  list = gst_buffer_list_new ();
+
+  hdr =
+      gst_buffer_new_wrapped (g_memdup (pdata, codec_data_size),
+      codec_data_size);
+  gst_buffer_list_add (list, hdr);
+
+  return list;
+}
+
+GstBufferList *
+gst_matroska_parse_flac_stream_headers (gpointer codec_data,
+    gsize codec_data_size)
+{
+  GstBufferList *list = NULL;
+  GstBuffer *hdr;
+  guint8 *pdata = codec_data;
+  guint len, off;
+
+  GST_MEMDUMP ("flac codec data", codec_data, codec_data_size);
+
+  /* need at least 'fLaC' marker + STREAMINFO metadata block */
+  if (codec_data == NULL || codec_data_size < ((4) + (4 + 34))) {
+    GST_WARNING ("not enough codec priv data for flac headers");
+    return NULL;
+  }
+
+  if (memcmp (pdata, "fLaC", 4) != 0) {
+    GST_WARNING ("no flac marker at start of stream headers");
+    return NULL;
+  }
+
+  list = gst_buffer_list_new ();
+
+  hdr = gst_buffer_new_wrapped (g_memdup (pdata, 4), 4);
+  gst_buffer_list_add (list, hdr);
+
+  /* skip fLaC marker */
+  off = 4;
+
+  while (off < codec_data_size - 3) {
+    len = GST_READ_UINT8 (pdata + off + 1) << 16;
+    len |= GST_READ_UINT8 (pdata + off + 2) << 8;
+    len |= GST_READ_UINT8 (pdata + off + 3);
+
+    GST_DEBUG ("header packet: len=%u bytes, flags=0x%02x", len, pdata[off]);
+
+    if (off + len > codec_data_size) {
+      gst_buffer_list_unref (list);
+      return NULL;
+    }
+
+    hdr = gst_buffer_new_wrapped (g_memdup (pdata + off, len + 4), len + 4);
+    gst_buffer_list_add (list, hdr);
+
+    off += 4 + len;
+  }
+  return list;
+}
+
+GstClockTime
+gst_matroska_track_get_buffer_timestamp (GstMatroskaTrackContext * track,
+    GstBuffer * buf)
+{
+  if (track->dts_only) {
+    return GST_BUFFER_DTS_OR_PTS (buf);
+  } else {
+    return GST_BUFFER_PTS (buf);
+  }
+}
+
+void
+gst_matroska_track_free (GstMatroskaTrackContext * track)
+{
+  g_free (track->codec_id);
+  g_free (track->codec_name);
+  g_free (track->name);
+  g_free (track->language);
+  g_free (track->codec_priv);
+  g_free (track->codec_state);
+
+  if (track->encodings != NULL) {
+    int i;
+
+    for (i = 0; i < track->encodings->len; ++i) {
+      GstMatroskaTrackEncoding *enc = &g_array_index (track->encodings,
+          GstMatroskaTrackEncoding,
+          i);
+
+      g_free (enc->comp_settings);
+    }
+    g_array_free (track->encodings, TRUE);
+  }
+
+  if (track->tags)
+    gst_tag_list_unref (track->tags);
+
+  if (track->index_table)
+    g_array_free (track->index_table, TRUE);
+
+  if (track->stream_headers)
+    gst_buffer_list_unref (track->stream_headers);
+
+  g_free (track);
+}
diff --git a/gst/matroska/matroska-ids.h b/gst/matroska/matroska-ids.h
new file mode 100644
index 0000000..9a88010
--- /dev/null
+++ b/gst/matroska/matroska-ids.h
@@ -0,0 +1,689 @@
+/* GStreamer Matroska muxer/demuxer
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * matroska-ids.h: matroska file/stream data IDs
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MATROSKA_IDS_H__
+#define __GST_MATROSKA_IDS_H__
+
+#include <gst/gst.h>
+#include <gst/video/video-info.h>
+
+#include "ebml-ids.h"
+
+/*
+ * EBML DocType.
+ */
+
+#define GST_MATROSKA_DOCTYPE_MATROSKA              "matroska"
+#define GST_MATROSKA_DOCTYPE_WEBM                  "webm"
+
+/*
+ * Matroska element IDs. max. 32-bit.
+ */
+
+/* toplevel Segment */
+#define GST_MATROSKA_ID_SEGMENT                    0x18538067
+
+/* matroska top-level master IDs, childs of Segment */
+#define GST_MATROSKA_ID_SEGMENTINFO                0x1549A966
+#define GST_MATROSKA_ID_TRACKS                     0x1654AE6B
+#define GST_MATROSKA_ID_CUES                       0x1C53BB6B
+#define GST_MATROSKA_ID_TAGS                       0x1254C367
+#define GST_MATROSKA_ID_SEEKHEAD                   0x114D9B74
+#define GST_MATROSKA_ID_CLUSTER                    0x1F43B675
+#define GST_MATROSKA_ID_ATTACHMENTS                0x1941A469
+#define GST_MATROSKA_ID_CHAPTERS                   0x1043A770
+
+/* IDs in the SegmentInfo master */
+#define GST_MATROSKA_ID_TIMECODESCALE              0x2AD7B1
+#define GST_MATROSKA_ID_DURATION                   0x4489
+#define GST_MATROSKA_ID_WRITINGAPP                 0x5741
+#define GST_MATROSKA_ID_MUXINGAPP                  0x4D80
+#define GST_MATROSKA_ID_DATEUTC                    0x4461
+#define GST_MATROSKA_ID_SEGMENTUID                 0x73A4
+#define GST_MATROSKA_ID_SEGMENTFILENAME            0x7384
+#define GST_MATROSKA_ID_PREVUID                    0x3CB923
+#define GST_MATROSKA_ID_PREVFILENAME               0x3C83AB
+#define GST_MATROSKA_ID_NEXTUID                    0x3EB923
+#define GST_MATROSKA_ID_NEXTFILENAME               0x3E83BB
+#define GST_MATROSKA_ID_TITLE                      0x7BA9
+#define GST_MATROSKA_ID_SEGMENTFAMILY              0x4444
+#define GST_MATROSKA_ID_CHAPTERTRANSLATE           0x6924
+
+/* IDs in the ChapterTranslate master */
+#define GST_MATROSKA_ID_CHAPTERTRANSLATEEDITIONUID 0x69FC
+#define GST_MATROSKA_ID_CHAPTERTRANSLATECODEC      0x69BF
+#define GST_MATROSKA_ID_CHAPTERTRANSLATEID         0x69A5
+
+/* ID in the Tracks master */
+#define GST_MATROSKA_ID_TRACKENTRY                 0xAE
+
+/* IDs in the TrackEntry master */
+#define GST_MATROSKA_ID_TRACKNUMBER                0xD7
+#define GST_MATROSKA_ID_TRACKUID                   0x73C5
+#define GST_MATROSKA_ID_TRACKTYPE                  0x83
+#define GST_MATROSKA_ID_TRACKAUDIO                 0xE1
+#define GST_MATROSKA_ID_TRACKVIDEO                 0xE0
+#define GST_MATROSKA_ID_CONTENTENCODINGS           0x6D80
+#define GST_MATROSKA_ID_CODECID                    0x86
+#define GST_MATROSKA_ID_CODECPRIVATE               0x63A2
+#define GST_MATROSKA_ID_CODECNAME                  0x258688
+#define GST_MATROSKA_ID_TRACKNAME                  0x536E
+#define GST_MATROSKA_ID_TRACKLANGUAGE              0x22B59C
+#define GST_MATROSKA_ID_TRACKFLAGENABLED           0xB9
+#define GST_MATROSKA_ID_TRACKFLAGDEFAULT           0x88
+#define GST_MATROSKA_ID_TRACKFLAGFORCED            0x55AA
+#define GST_MATROSKA_ID_TRACKFLAGLACING            0x9C
+#define GST_MATROSKA_ID_TRACKMINCACHE              0x6DE7
+#define GST_MATROSKA_ID_TRACKMAXCACHE              0x6DF8
+#define GST_MATROSKA_ID_TRACKDEFAULTDURATION       0x23E383
+#define GST_MATROSKA_ID_TRACKTIMECODESCALE         0x23314F
+#define GST_MATROSKA_ID_MAXBLOCKADDITIONID         0x55EE
+#define GST_MATROSKA_ID_TRACKATTACHMENTLINK        0x7446
+#define GST_MATROSKA_ID_TRACKOVERLAY               0x6FAB
+#define GST_MATROSKA_ID_TRACKTRANSLATE             0x6624
+/* semi-draft */
+#define GST_MATROSKA_ID_TRACKOFFSET                0x537F
+/* semi-draft */
+#define GST_MATROSKA_ID_CODECSETTINGS              0x3A9697
+/* semi-draft */
+#define GST_MATROSKA_ID_CODECINFOURL               0x3B4040
+/* semi-draft */
+#define GST_MATROSKA_ID_CODECDOWNLOADURL           0x26B240
+/* semi-draft */
+#define GST_MATROSKA_ID_CODECDECODEALL             0xAA
+#define GST_MATROSKA_ID_SEEKPREROLL                0x56BB
+#define GST_MATROSKA_ID_CODECDELAY                 0x56AA
+
+/* IDs in the TrackTranslate master */
+#define GST_MATROSKA_ID_TRACKTRANSLATEEDITIONUID   0x66FC
+#define GST_MATROSKA_ID_TRACKTRANSLATECODEC        0x66BF
+#define GST_MATROSKA_ID_TRACKTRANSLATETRACKID      0x66A5
+
+
+/* IDs in the TrackVideo master */
+/* NOTE: This one is here only for backward compatibility.
+ * Use _TRACKDEFAULDURATION */
+#define GST_MATROSKA_ID_VIDEOFRAMERATE             0x2383E3
+#define GST_MATROSKA_ID_VIDEODISPLAYWIDTH          0x54B0
+#define GST_MATROSKA_ID_VIDEODISPLAYHEIGHT         0x54BA
+#define GST_MATROSKA_ID_VIDEODISPLAYUNIT           0x54B2
+#define GST_MATROSKA_ID_VIDEOPIXELWIDTH            0xB0
+#define GST_MATROSKA_ID_VIDEOPIXELHEIGHT           0xBA
+#define GST_MATROSKA_ID_VIDEOPIXELCROPBOTTOM       0x54AA
+#define GST_MATROSKA_ID_VIDEOPIXELCROPTOP          0x54BB
+#define GST_MATROSKA_ID_VIDEOPIXELCROPLEFT         0x54CC
+#define GST_MATROSKA_ID_VIDEOPIXELCROPRIGHT        0x54DD
+#define GST_MATROSKA_ID_VIDEOFLAGINTERLACED        0x9A
+/* semi-draft */
+#define GST_MATROSKA_ID_VIDEOSTEREOMODE            0x53B8
+#define GST_MATROSKA_ID_VIDEOASPECTRATIOTYPE       0x54B3
+#define GST_MATROSKA_ID_VIDEOCOLOURSPACE           0x2EB524
+/* semi-draft */
+#define GST_MATROSKA_ID_VIDEOGAMMAVALUE            0x2FB523
+
+#define GST_MATROSKA_ID_VIDEOCOLOUR                0x55B0
+/* IDs in the Colour master*/
+#define GST_MATROSKA_ID_VIDEOMATRIXCOEFFICIENTS    0x55B1
+#define GST_MATROSKA_ID_VIDEORANGE                 0x55B9
+#define GST_MATROSKA_ID_VIDEOTRANSFERCHARACTERISTICS  0x55BA
+#define GST_MATROSKA_ID_VIDEOPRIMARIES             0x55BB
+
+/* IDs in the TrackAudio master */
+#define GST_MATROSKA_ID_AUDIOSAMPLINGFREQ          0xB5
+#define GST_MATROSKA_ID_AUDIOBITDEPTH              0x6264
+#define GST_MATROSKA_ID_AUDIOCHANNELS              0x9F
+/* semi-draft */
+#define GST_MATROSKA_ID_AUDIOCHANNELPOSITIONS      0x7D7B
+#define GST_MATROSKA_ID_AUDIOOUTPUTSAMPLINGFREQ    0x78B5
+
+/* IDs in the TrackContentEncoding master */
+#define GST_MATROSKA_ID_CONTENTENCODING            0x6240
+
+/* IDs in the ContentEncoding master */
+#define GST_MATROSKA_ID_CONTENTENCODINGORDER       0x5031
+#define GST_MATROSKA_ID_CONTENTENCODINGSCOPE       0x5032
+#define GST_MATROSKA_ID_CONTENTENCODINGTYPE        0x5033
+#define GST_MATROSKA_ID_CONTENTCOMPRESSION         0x5034
+#define GST_MATROSKA_ID_CONTENTENCRYPTION          0x5035
+
+/* IDs in the ContentCompression master */
+#define GST_MATROSKA_ID_CONTENTCOMPALGO            0x4254
+#define GST_MATROSKA_ID_CONTENTCOMPSETTINGS        0x4255
+
+/* IDs in the ContentEncryption master */
+#define GST_MATROSKA_ID_CONTENTENCALGO             0x47E1
+#define GST_MATROSKA_ID_CONTENTENCKEYID            0x47E2
+#define GST_MATROSKA_ID_CONTENTSIGNATURE           0x47E3
+#define GST_MATROSKA_ID_CONTENTSIGKEYID            0x47E4
+#define GST_MATROSKA_ID_CONTENTSIGALGO             0x47E5
+#define GST_MATROSKA_ID_CONTENTSIGHASHALGO         0x47E6
+
+/* ID in the CUEs master */
+#define GST_MATROSKA_ID_POINTENTRY                 0xBB
+
+/* IDs in the pointentry master */
+#define GST_MATROSKA_ID_CUETIME                    0xB3
+#define GST_MATROSKA_ID_CUETRACKPOSITIONS          0xB7
+
+/* IDs in the CueTrackPositions master */
+#define GST_MATROSKA_ID_CUETRACK                   0xF7
+#define GST_MATROSKA_ID_CUECLUSTERPOSITION         0xF1
+#define GST_MATROSKA_ID_CUEBLOCKNUMBER             0x5378
+/* semi-draft */
+#define GST_MATROSKA_ID_CUECODECSTATE              0xEA
+/* semi-draft */
+#define GST_MATROSKA_ID_CUEREFERENCE               0xDB
+
+/* IDs in the CueReference master */
+/* semi-draft */
+#define GST_MATROSKA_ID_CUEREFTIME                 0x96
+/* semi-draft */
+#define GST_MATROSKA_ID_CUEREFCLUSTER              0x97
+/* semi-draft */
+#define GST_MATROSKA_ID_CUEREFNUMBER               0x535F
+/* semi-draft */
+#define GST_MATROSKA_ID_CUEREFCODECSTATE           0xEB
+
+/* IDs in the Tags master */
+#define GST_MATROSKA_ID_TAG                        0x7373
+
+/* in the Tag master */
+#define GST_MATROSKA_ID_SIMPLETAG                  0x67C8
+#define GST_MATROSKA_ID_TARGETS                    0x63C0
+
+/* in the SimpleTag master */
+#define GST_MATROSKA_ID_TAGNAME                    0x45A3
+#define GST_MATROSKA_ID_TAGSTRING                  0x4487
+#define GST_MATROSKA_ID_TAGLANGUAGE                0x447A
+#define GST_MATROSKA_ID_TAGDEFAULT                 0x4484
+#define GST_MATROSKA_ID_TAGBINARY                  0x4485
+
+/* in the Targets master */
+#define GST_MATROSKA_ID_TARGETTYPEVALUE            0x68CA
+#define GST_MATROSKA_ID_TARGETTYPE                 0x63CA
+#define GST_MATROSKA_ID_TARGETTRACKUID             0x63C5
+#define GST_MATROSKA_ID_TARGETEDITIONUID           0x63C9
+#define GST_MATROSKA_ID_TARGETCHAPTERUID           0x63C4
+#define GST_MATROSKA_ID_TARGETATTACHMENTUID        0x63C6
+
+/* IDs in the SeekHead master */
+#define GST_MATROSKA_ID_SEEKENTRY                  0x4DBB
+
+/* IDs in the SeekEntry master */
+#define GST_MATROSKA_ID_SEEKID                     0x53AB
+#define GST_MATROSKA_ID_SEEKPOSITION               0x53AC
+
+/* IDs in the Cluster master */
+#define GST_MATROSKA_ID_CLUSTERTIMECODE            0xE7
+#define GST_MATROSKA_ID_BLOCKGROUP                 0xA0
+#define GST_MATROSKA_ID_SIMPLEBLOCK                0xA3
+#define GST_MATROSKA_ID_REFERENCEBLOCK             0xFB
+#define GST_MATROSKA_ID_POSITION                   0xA7
+#define GST_MATROSKA_ID_PREVSIZE                   0xAB
+/* semi-draft */
+#define GST_MATROSKA_ID_ENCRYPTEDBLOCK             0xAF
+#define GST_MATROSKA_ID_SILENTTRACKS               0x5854
+
+/* IDs in the SilentTracks master */
+#define GST_MATROSKA_ID_SILENTTRACKNUMBER          0x58D7
+
+/* IDs in the BlockGroup master */
+#define GST_MATROSKA_ID_BLOCK                      0xA1
+#define GST_MATROSKA_ID_BLOCKDURATION              0x9B
+/* semi-draft */
+#define GST_MATROSKA_ID_BLOCKVIRTUAL               0xA2
+#define GST_MATROSKA_ID_REFERENCEBLOCK             0xFB
+#define GST_MATROSKA_ID_BLOCKADDITIONS             0x75A1
+#define GST_MATROSKA_ID_REFERENCEPRIORITY          0xFA
+/* semi-draft */
+#define GST_MATROSKA_ID_REFERENCEVIRTUAL           0xFD
+/* semi-draft */
+#define GST_MATROSKA_ID_CODECSTATE                 0xA4
+#define GST_MATROSKA_ID_SLICES                     0x8E
+#define GST_MATROSKA_ID_DISCARDPADDING             0x75A2
+
+/* IDs in the BlockAdditions master */
+#define GST_MATROSKA_ID_BLOCKMORE                  0xA6
+
+/* IDs in the BlockMore master */
+#define GST_MATROSKA_ID_BLOCKADDID                 0xEE
+#define GST_MATROSKA_ID_BLOCKADDITIONAL            0xA5
+
+/* IDs in the Slices master */
+#define GST_MATROSKA_ID_TIMESLICE                  0xE8
+
+/* IDs in the TimeSlice master */
+#define GST_MATROSKA_ID_LACENUMBER                 0xCC
+/* semi-draft */
+#define GST_MATROSKA_ID_FRAMENUMBER                0xCD
+/* semi-draft */
+#define GST_MATROSKA_ID_BLOCKADDITIONID            0xCB
+/* semi-draft */
+#define GST_MATROSKA_ID_TIMESLICEDELAY             0xCE
+#define GST_MATROSKA_ID_TIMESLICEDURATION          0xCF
+
+/* IDs in the Attachments master */
+#define GST_MATROSKA_ID_ATTACHEDFILE               0x61A7
+
+/* IDs in the AttachedFile master */
+#define GST_MATROSKA_ID_FILEDESCRIPTION            0x467E
+#define GST_MATROSKA_ID_FILENAME                   0x466E
+#define GST_MATROSKA_ID_FILEMIMETYPE               0x4660
+#define GST_MATROSKA_ID_FILEDATA                   0x465C
+#define GST_MATROSKA_ID_FILEUID                    0x46AE
+/* semi-draft */
+#define GST_MATROSKA_ID_FILEREFERRAL               0x4675
+
+/* IDs in the Chapters master */
+#define GST_MATROSKA_ID_EDITIONENTRY               0x45B9
+
+/* IDs in the EditionEntry master */
+#define GST_MATROSKA_ID_EDITIONUID                 0x45BC
+#define GST_MATROSKA_ID_EDITIONFLAGHIDDEN          0x45BD
+#define GST_MATROSKA_ID_EDITIONFLAGDEFAULT         0x45DB
+#define GST_MATROSKA_ID_EDITIONFLAGORDERED         0x45DD
+#define GST_MATROSKA_ID_CHAPTERATOM                0xB6
+
+/* IDs in the ChapterAtom master */
+#define GST_MATROSKA_ID_CHAPTERUID                 0x73C4
+#define GST_MATROSKA_ID_CHAPTERSTRINGUID           0x5654
+#define GST_MATROSKA_ID_CHAPTERTIMESTART           0x91
+#define GST_MATROSKA_ID_CHAPTERTIMESTOP            0x92
+#define GST_MATROSKA_ID_CHAPTERFLAGHIDDEN          0x98
+#define GST_MATROSKA_ID_CHAPTERFLAGENABLED         0x4598
+#define GST_MATROSKA_ID_CHAPTERSEGMENTUID          0x6E67
+#define GST_MATROSKA_ID_CHAPTERSEGMENTEDITIONUID   0x6EBC
+#define GST_MATROSKA_ID_CHAPTERPHYSICALEQUIV       0x63C3
+#define GST_MATROSKA_ID_CHAPTERTRACK               0x8F
+#define GST_MATROSKA_ID_CHAPTERDISPLAY             0x80
+#define GST_MATROSKA_ID_CHAPPROCESS                0x6944
+
+/* IDs in the ChapProcess master */
+#define GST_MATROSKA_ID_CHAPPROCESSCODECID         0x6955
+#define GST_MATROSKA_ID_CHAPPROCESSPRIVATE         0x450D
+#define GST_MATROSKA_ID_CHAPPROCESSCOMMAND         0x6911
+
+/* IDs in the ChapProcessCommand master */
+#define GST_MATROSKA_ID_CHAPPROCESSTIME            0x6922
+#define GST_MATROSKA_ID_CHAPPROCESSDATA            0x6933
+
+/* IDs in the ChapterDisplay master */
+#define GST_MATROSKA_ID_CHAPSTRING                 0x85
+#define GST_MATROSKA_ID_CHAPLANGUAGE               0x437C
+#define GST_MATROSKA_ID_CHAPCOUNTRY                0x437E
+
+/* IDs in the ChapterTrack master */
+#define GST_MATROSKA_ID_CHAPTERTRACKNUMBER         0x89
+
+/*
+ * Matroska Codec IDs. Strings.
+ */
+
+#define GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC   "V_MS/VFW/FOURCC"
+#define GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED "V_UNCOMPRESSED"
+#define GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_SP     "V_MPEG4/ISO/SP"
+#define GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP    "V_MPEG4/ISO/ASP"
+#define GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AP     "V_MPEG4/ISO/AP"
+#define GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC    "V_MPEG4/ISO/AVC"
+#define GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3    "V_MPEG4/MS/V3"
+#define GST_MATROSKA_CODEC_ID_VIDEO_MPEG1        "V_MPEG1"
+#define GST_MATROSKA_CODEC_ID_VIDEO_MPEG2        "V_MPEG2"
+/* FIXME: not (yet) in the spec! */
+#define GST_MATROSKA_CODEC_ID_VIDEO_MJPEG        "V_MJPEG"
+#define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1   "V_REAL/RV10"
+#define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2   "V_REAL/RV20"
+#define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3   "V_REAL/RV30"
+#define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4   "V_REAL/RV40"
+#define GST_MATROSKA_CODEC_ID_VIDEO_THEORA       "V_THEORA"
+#define GST_MATROSKA_CODEC_ID_VIDEO_QUICKTIME    "V_QUICKTIME"
+#define GST_MATROSKA_CODEC_ID_VIDEO_SNOW         "V_SNOW"
+#define GST_MATROSKA_CODEC_ID_VIDEO_DIRAC        "V_DIRAC"
+#define GST_MATROSKA_CODEC_ID_VIDEO_VP8          "V_VP8"
+#define GST_MATROSKA_CODEC_ID_VIDEO_VP9          "V_VP9"
+#define GST_MATROSKA_CODEC_ID_VIDEO_AV1          "V_AV1"
+#define GST_MATROSKA_CODEC_ID_VIDEO_MPEGH_HEVC   "V_MPEGH/ISO/HEVC"
+#define GST_MATROSKA_CODEC_ID_VIDEO_PRORES       "V_PRORES"
+
+#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1       "A_MPEG/L1"
+#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2       "A_MPEG/L2"
+#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3       "A_MPEG/L3"
+#define GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE     "A_PCM/INT/BIG"
+#define GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE     "A_PCM/INT/LIT"
+#define GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT      "A_PCM/FLOAT/IEEE"
+#define GST_MATROSKA_CODEC_ID_AUDIO_AC3            "A_AC3"
+#define GST_MATROSKA_CODEC_ID_AUDIO_AC3_BSID9      "A_AC3/BSID9"
+#define GST_MATROSKA_CODEC_ID_AUDIO_AC3_BSID10     "A_AC3/BSID10"
+#define GST_MATROSKA_CODEC_ID_AUDIO_EAC3           "A_EAC3"
+#define GST_MATROSKA_CODEC_ID_AUDIO_TRUEHD         "A_TRUEHD"
+#define GST_MATROSKA_CODEC_ID_AUDIO_DTS            "A_DTS"
+#define GST_MATROSKA_CODEC_ID_AUDIO_VORBIS         "A_VORBIS"
+#define GST_MATROSKA_CODEC_ID_AUDIO_FLAC           "A_FLAC"
+/* FIXME: not yet in the spec */
+#define GST_MATROSKA_CODEC_ID_AUDIO_SPEEX          "A_SPEEX"
+#define GST_MATROSKA_CODEC_ID_AUDIO_ACM            "A_MS/ACM"
+#define GST_MATROSKA_CODEC_ID_AUDIO_TTA            "A_TTA1"
+#define GST_MATROSKA_CODEC_ID_AUDIO_WAVPACK4       "A_WAVPACK4"
+#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4      "A_REAL/14_4"
+#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8      "A_REAL/28_8"
+#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK      "A_REAL/COOK"
+#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_SIPR      "A_REAL/SIPR"
+#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_RALF      "A_REAL/RALF"
+#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_ATRC      "A_REAL/ATRC"
+#define GST_MATROSKA_CODEC_ID_AUDIO_AAC            "A_AAC"
+#define GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2      "A_AAC/MPEG2/"
+#define GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4      "A_AAC/MPEG4/"
+#define GST_MATROSKA_CODEC_ID_AUDIO_QUICKTIME_QDMC "A_QUICKTIME/QDMC"
+#define GST_MATROSKA_CODEC_ID_AUDIO_QUICKTIME_QDM2 "A_QUICKTIME/QDM2"
+#define GST_MATROSKA_CODEC_ID_AUDIO_OPUS           "A_OPUS"
+/* Undefined for now:
+#define GST_MATROSKA_CODEC_ID_AUDIO_MPC            "A_MPC"
+*/
+
+#define GST_MATROSKA_CODEC_ID_SUBTITLE_ASCII     "S_TEXT/ASCII"
+#define GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8      "S_TEXT/UTF8"
+#define GST_MATROSKA_CODEC_ID_SUBTITLE_SSA       "S_TEXT/SSA"
+#define GST_MATROSKA_CODEC_ID_SUBTITLE_ASS       "S_TEXT/ASS" 
+#define GST_MATROSKA_CODEC_ID_SUBTITLE_USF       "S_TEXT/USF"
+#define GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB    "S_VOBSUB"
+#define GST_MATROSKA_CODEC_ID_SUBTITLE_HDMVPGS   "S_HDMV/PGS"
+#define GST_MATROSKA_CODEC_ID_SUBTITLE_BMP       "S_IMAGE/BMP"
+#define GST_MATROSKA_CODEC_ID_SUBTITLE_KATE      "S_KATE"
+
+/*
+ * Matroska tags. Strings.
+ */
+
+#define GST_MATROSKA_TAG_ID_TITLE    "TITLE"
+#define GST_MATROSKA_TAG_ID_AUTHOR   "AUTHOR"
+#define GST_MATROSKA_TAG_ID_ARTIST   "ARTIST"
+#define GST_MATROSKA_TAG_ID_ALBUM    "ALBUM"
+#define GST_MATROSKA_TAG_ID_COMMENTS "COMMENTS"
+#define GST_MATROSKA_TAG_ID_COMMENT  "COMMENT"
+#define GST_MATROSKA_TAG_ID_BITSPS   "BITSPS"
+#define GST_MATROSKA_TAG_ID_BPS      "BPS"
+#define GST_MATROSKA_TAG_ID_ENCODER  "ENCODER"
+#define GST_MATROSKA_TAG_ID_ISRC     "ISRC"
+#define GST_MATROSKA_TAG_ID_COPYRIGHT "COPYRIGHT"
+#define GST_MATROSKA_TAG_ID_BPM       "BPM"
+#define GST_MATROSKA_TAG_ID_TERMS_OF_USE "TERMS_OF_USE"
+#define GST_MATROSKA_TAG_ID_DATE      "DATE"
+#define GST_MATROSKA_TAG_ID_COMPOSER  "COMPOSER"
+#define GST_MATROSKA_TAG_ID_LEAD_PERFORMER  "LEAD_PERFOMER"
+#define GST_MATROSKA_TAG_ID_GENRE     "GENRE"
+#define GST_MATROSKA_TAG_ID_TOTAL_PARTS "TOTAL_PARTS"
+#define GST_MATROSKA_TAG_ID_PART_NUMBER "PART_NUMBER"
+#define GST_MATROSKA_TAG_ID_SUBTITLE "SUBTITLE"
+#define GST_MATROSKA_TAG_ID_ACCOMPANIMENT "ACCOMPANIMENT"
+#define GST_MATROSKA_TAG_ID_LYRICS "LYRICS"
+#define GST_MATROSKA_TAG_ID_CONDUCTOR "CONDUCTOR"
+#define GST_MATROSKA_TAG_ID_ENCODED_BY "ENCODED_BY"
+#define GST_MATROSKA_TAG_ID_DESCRIPTION "DESCRIPTION"
+#define GST_MATROSKA_TAG_ID_KEYWORDS "KEYWORDS"
+#define GST_MATROSKA_TAG_ID_DATE_RELEASED "DATE_RELEASED"
+#define GST_MATROSKA_TAG_ID_DATE_RECORDED "DATE_RECORDED"
+#define GST_MATROSKA_TAG_ID_DATE_ENCODED "DATE_ENCODED"
+#define GST_MATROSKA_TAG_ID_DATE_TAGGED "DATE_TAGGED"
+#define GST_MATROSKA_TAG_ID_DATE_DIGITIZED "DATE_DIGITIZED"
+#define GST_MATROSKA_TAG_ID_DATE_WRITTEN "DATE_WRITTEN"
+#define GST_MATROSKA_TAG_ID_DATE_PURCHASED "DATE_PURCHASED"
+#define GST_MATROSKA_TAG_ID_RECORDING_LOCATION "RECORDING_LOCATION"
+#define GST_MATROSKA_TAG_ID_PRODUCTION_COPYRIGHT "PRODUCTION_COPYRIGHT"
+#define GST_MATROSKA_TAG_ID_LICENSE "LICENSE"
+
+/*
+ * TODO: add this tag & mappings
+ * "REPLAYGAIN_GAIN" -> GST_TAG_*_GAIN   see http://replaygain.hydrogenaudio.org/rg_data_format.html
+ * "REPLAYGAIN_PEAK" -> GST_TAG_*_PEAK   see http://replaygain.hydrogenaudio.org/peak_data_format.html
+ * both are depending on the target (track, album?)
+ *
+ * "TOTAL_PARTS" -> GST_TAG_TRACK_COUNT    depending on target
+ * "PART_NUMBER" -> GST_TAG_TRACK_NUMBER   depending on target
+ *
+ * "SORT_WITH" -> nested in other elements, GST_TAG_TITLE_SORTNAME, etc
+ *
+ * TODO: maybe add custom gstreamer tags for other standard matroska tags,
+ * see http://matroska.org/technical/specs/tagging/index.html
+ *
+ * TODO: handle tag targets and nesting correctly
+ */
+
+/*
+ * Enumerations for various types (mapping from binary
+ * value to what it actually means).
+ */
+
+typedef enum {
+  GST_MATROSKA_TRACK_TYPE_VIDEO    = 0x1,
+  GST_MATROSKA_TRACK_TYPE_AUDIO    = 0x2,
+  GST_MATROSKA_TRACK_TYPE_COMPLEX  = 0x3,
+  GST_MATROSKA_TRACK_TYPE_LOGO     = 0x10,
+  GST_MATROSKA_TRACK_TYPE_SUBTITLE = 0x11,
+  GST_MATROSKA_TRACK_TYPE_BUTTONS  = 0x12,
+  GST_MATROSKA_TRACK_TYPE_CONTROL  = 0x20,
+} GstMatroskaTrackType;
+
+typedef enum {
+  GST_MATROSKA_ASPECT_RATIO_MODE_FREE  = 0x0,
+  GST_MATROSKA_ASPECT_RATIO_MODE_KEEP  = 0x1,
+  GST_MATROSKA_ASPECT_RATIO_MODE_FIXED = 0x2,
+} GstMatroskaAspectRatioMode;
+
+/*
+ * These aren't in any way "matroska-form" things,
+ * it's just something I use in the muxer/demuxer.
+ */
+
+typedef enum {
+  GST_MATROSKA_TRACK_ENABLED = (1<<0),
+  GST_MATROSKA_TRACK_DEFAULT = (1<<1),
+  GST_MATROSKA_TRACK_LACING  = (1<<2),
+  GST_MATROSKA_TRACK_FORCED  = (1<<3),
+  GST_MATROSKA_TRACK_SHIFT   = (1<<16)
+} GstMatroskaTrackFlags;
+
+typedef enum {
+  GST_MATROSKA_VIDEOTRACK_INTERLACED = (GST_MATROSKA_TRACK_SHIFT<<0)
+} GstMatroskaVideoTrackFlags;
+
+typedef enum {
+  GST_MATROSKA_STEREO_MODE_SBS_LR      = 0x1,
+  GST_MATROSKA_STEREO_MODE_TB_RL       = 0x2,
+  GST_MATROSKA_STEREO_MODE_TB_LR       = 0x3,
+  GST_MATROSKA_STEREO_MODE_CHECKER_RL  = 0x4,
+  GST_MATROSKA_STEREO_MODE_CHECKER_LR  = 0x5,
+  GST_MATROSKA_STEREO_MODE_SBS_RL      = 0x9,
+  GST_MATROSKA_STEREO_MODE_FBF_LR      = 0xD,
+  GST_MATROSKA_STEREO_MODE_FBF_RL      = 0xE
+} GstMatroskaStereoMode;
+
+typedef struct _GstMatroskaTrackContext GstMatroskaTrackContext;
+
+/* TODO: check if all fields are used */
+struct _GstMatroskaTrackContext {
+  GstPad       *pad;
+  GstCaps      *caps;
+  guint         index;
+  /* reverse playback */
+  GstClockTime  from_time;
+  gint64                   from_offset;
+  gint64                   to_offset;
+
+  GArray       *index_table;
+
+  gint          index_writer_id;
+
+  /* some often-used info */
+  gchar        *codec_id, *codec_name, *name, *language;
+  gpointer      codec_priv;
+  gsize         codec_priv_size;
+  gpointer      codec_state;
+  gsize         codec_state_size;
+  GstMatroskaTrackType type;
+  guint64       uid, num;
+  GstMatroskaTrackFlags flags;
+  guint64       default_duration;
+  guint64       pos;
+  gdouble       timecodescale;
+  guint64       seek_preroll;
+  guint64       codec_delay;
+
+  gboolean      set_discont; /* TRUE = set DISCONT flag on next buffer */
+
+  /* Stream header buffer, to put into caps and send before any other buffers */
+  GstBufferList * stream_headers;
+  gboolean        send_stream_headers;
+
+  /* Special flag for VobSub, for which we have to send colour table info
+   * (if available) first before sending any data, and just testing
+   * for time == 0 is not enough to detect that. Used by demuxer */
+  gboolean      send_dvd_event;
+
+  /* Special counter for muxer to skip the first N vorbis/theora headers -
+   * they are put into codec private data, not muxed into the stream */
+  guint         xiph_headers_to_skip;
+
+  /* Used for postprocessing a frame before it is pushed from the demuxer */
+  GstFlowReturn (*postprocess_frame) (GstElement *element,
+                                      GstMatroskaTrackContext *context,
+				      GstBuffer **buffer);
+
+  /* List of tags for this stream */
+  GstTagList   *tags;
+  /* Tags changed and should be pushed again */
+  gboolean      tags_changed;
+
+  /* A GArray of GstMatroskaTrackEncoding structures which contain the
+   * encoding (compression/encryption) settings for this track, if any */
+  GArray       *encodings;
+
+  /* Whether the stream is EOS */
+  gboolean      eos;
+
+  /* any alignment we need our output buffers to have */
+  gint          alignment;
+  
+  /* for compatibility with VFW files, where timestamp represents DTS */
+  gboolean      dts_only;
+  
+  /* indicate that the track is raw (jpeg,raw variants) and so pts=dts */
+  gboolean		intra_only;
+};
+
+typedef struct _GstMatroskaTrackVideoContext {
+  GstMatroskaTrackContext parent;
+
+  guint         pixel_width, pixel_height;
+  guint         display_width, display_height;
+  gdouble       default_fps;
+  GstMatroskaAspectRatioMode asr_mode;
+  guint32       fourcc;
+
+  GstVideoMultiviewMode multiview_mode;
+  GstVideoMultiviewFlags multiview_flags;
+
+  /* QoS */
+  GstClockTime  earliest_time;
+
+  GstBuffer     *dirac_unit;
+  GstVideoColorimetry colorimetry;
+} GstMatroskaTrackVideoContext;
+
+typedef struct _GstMatroskaTrackAudioContext {
+  GstMatroskaTrackContext parent;
+
+  guint         samplerate, channels, bitdepth;
+
+  guint32       wvpk_block_index;
+} GstMatroskaTrackAudioContext;
+
+typedef struct _GstMatroskaTrackSubtitleContext {
+  GstMatroskaTrackContext parent;
+
+  gboolean    check_utf8;     /* buffers should be valid UTF-8 */
+  gboolean    check_markup;   /* check if buffers contain markup
+                               * or plaintext and escape characters */
+  gboolean    invalid_utf8;   /* work around broken files      */
+  gboolean    seen_markup_tag;  /* markup found in text */
+} GstMatroskaTrackSubtitleContext;
+
+typedef struct _GstMatroskaIndex {
+  guint64        pos;      /* of the corresponding *cluster*! */
+  GstClockTime   time;     /* in nanoseconds */
+  guint32        block;    /* number of the block in the cluster */
+  guint16        track;    /* reference to 'num' */
+} GstMatroskaIndex;
+
+typedef struct _Wavpack4Header {
+  guchar  ck_id [4];     /* "wvpk"                                         */
+  guint32 ck_size;       /* size of entire frame (minus 8, of course)      */
+  guint16 version;       /* 0x403 for now                                  */
+  guint8  track_no;      /* track number (0 if not used, like now)         */
+  guint8  index_no;      /* remember these? (0 if not used, like now)      */
+  guint32 total_samples; /* for entire file (-1 if unknown)                */
+  guint32 block_index;   /* index of first sample in block (to file begin) */
+  guint32 block_samples; /* # samples in this block                        */
+  guint32 flags;         /* various flags for id and decoding              */
+  guint32 crc;           /* crc for actual decoded data                    */
+} Wavpack4Header;
+
+typedef enum {
+  GST_MATROSKA_TRACK_ENCODING_SCOPE_FRAME = (1<<0),
+  GST_MATROSKA_TRACK_ENCODING_SCOPE_CODEC_DATA = (1<<1),
+  GST_MATROSKA_TRACK_ENCODING_SCOPE_NEXT_CONTENT_ENCODING = (1<<2)
+} GstMatroskaTrackEncodingScope;
+
+typedef enum {
+  GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_ZLIB = 0,
+  GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_BZLIB = 1,
+  GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_LZO1X = 2,
+  GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_HEADERSTRIP = 3
+} GstMatroskaTrackCompressionAlgorithm;
+
+typedef struct _GstMatroskaTrackEncoding {
+  guint   order;
+  guint   scope     : 3;
+  guint   type      : 1;
+  guint   comp_algo : 2;
+  guint8 *comp_settings;
+  guint   comp_settings_length;
+} GstMatroskaTrackEncoding;
+
+gboolean gst_matroska_track_init_video_context    (GstMatroskaTrackContext ** p_context);
+gboolean gst_matroska_track_init_audio_context    (GstMatroskaTrackContext ** p_context);
+gboolean gst_matroska_track_init_subtitle_context (GstMatroskaTrackContext ** p_context);
+
+void gst_matroska_register_tags (void);
+
+GstBufferList * gst_matroska_parse_xiph_stream_headers  (gpointer codec_data,
+                                                         gsize codec_data_size);
+
+GstBufferList * gst_matroska_parse_speex_stream_headers (gpointer codec_data,
+                                                         gsize codec_data_size);
+
+GstBufferList * gst_matroska_parse_opus_stream_headers  (gpointer codec_data,
+                                                         gsize codec_data_size);
+
+GstBufferList * gst_matroska_parse_flac_stream_headers  (gpointer codec_data,
+                                                         gsize codec_data_size);
+void gst_matroska_track_free (GstMatroskaTrackContext * track);
+GstClockTime gst_matroska_track_get_buffer_timestamp (GstMatroskaTrackContext * track, GstBuffer *buf);
+
+#endif /* __GST_MATROSKA_IDS_H__ */
diff --git a/gst/matroska/matroska-mux.c b/gst/matroska/matroska-mux.c
new file mode 100644
index 0000000..fd09e2e
--- /dev/null
+++ b/gst/matroska/matroska-mux.c
@@ -0,0 +1,4067 @@
+/* GStreamer Matroska muxer/demuxer
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2005 Michal Benes <michal.benes@xeris.cz>
+ * (c) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ * (c) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ *
+ * matroska-mux.c: matroska file/stream muxer
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* TODO: - check everywhere that we don't write invalid values
+ *       - make sure timestamps are correctly scaled everywhere
+ */
+
+/**
+ * SECTION:element-matroskamux
+ *
+ * matroskamux muxes different input streams into a Matroska file.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v filesrc location=/path/to/mp3 ! mpegaudioparse ! matroskamux name=mux ! filesink location=test.mkv  filesrc location=/path/to/theora.ogg ! oggdemux ! theoraparse ! mux.
+ * ]| This pipeline muxes an MP3 file and a Ogg Theora video into a Matroska file.
+ * |[
+ * gst-launch-1.0 -v audiotestsrc num-buffers=100 ! audioconvert ! vorbisenc ! matroskamux ! filesink location=test.mka
+ * ]| This pipeline muxes a 440Hz sine wave encoded with the Vorbis codec into a Matroska file.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gst/audio/audio.h>
+#include <gst/riff/riff-media.h>
+#include <gst/tag/tag.h>
+#include <gst/pbutils/codec-utils.h>
+
+#include "matroska-mux.h"
+#include "matroska-ids.h"
+
+#define GST_MATROSKA_MUX_CHAPLANG "und"
+
+GST_DEBUG_CATEGORY_STATIC (matroskamux_debug);
+#define GST_CAT_DEFAULT matroskamux_debug
+
+enum
+{
+  PROP_0,
+  PROP_WRITING_APP,
+  PROP_DOCTYPE_VERSION,
+  PROP_MIN_INDEX_INTERVAL,
+  PROP_STREAMABLE,
+  PROP_TIMECODESCALE,
+  PROP_MIN_CLUSTER_DURATION,
+  PROP_MAX_CLUSTER_DURATION
+};
+
+#define  DEFAULT_DOCTYPE_VERSION         2
+#define  DEFAULT_WRITING_APP             "GStreamer Matroska muxer"
+#define  DEFAULT_MIN_INDEX_INTERVAL      0
+#define  DEFAULT_STREAMABLE              FALSE
+#define  DEFAULT_TIMECODESCALE           GST_MSECOND
+#define  DEFAULT_MIN_CLUSTER_DURATION    500 * GST_MSECOND
+#define  DEFAULT_MAX_CLUSTER_DURATION    65535 * GST_MSECOND
+
+/* WAVEFORMATEX is gst_riff_strf_auds + an extra guint16 extension size */
+#define WAVEFORMATEX_SIZE  (2 + sizeof (gst_riff_strf_auds))
+
+static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-matroska; video/x-matroska-3d; audio/x-matroska")
+    );
+
+#define COMMON_VIDEO_CAPS \
+  "width = (int) [ 16, MAX ], " \
+  "height = (int) [ 16, MAX ] "
+
+/* FIXME:
+ * * require codec data, etc as needed
+ */
+
+static GstStaticPadTemplate videosink_templ =
+    GST_STATIC_PAD_TEMPLATE ("video_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("video/mpeg, "
+        "mpegversion = (int) { 1, 2, 4 }, "
+        "systemstream = (boolean) false, "
+        COMMON_VIDEO_CAPS "; "
+        "video/x-h264, stream-format=avc, alignment=au, "
+        COMMON_VIDEO_CAPS "; "
+        "video/x-h265, stream-format=hvc1, alignment=au, "
+        COMMON_VIDEO_CAPS "; "
+        "video/x-divx, "
+        COMMON_VIDEO_CAPS "; "
+        "video/x-huffyuv, "
+        COMMON_VIDEO_CAPS "; "
+        "video/x-dv, "
+        COMMON_VIDEO_CAPS "; "
+        "video/x-h263, "
+        COMMON_VIDEO_CAPS "; "
+        "video/x-msmpeg, "
+        COMMON_VIDEO_CAPS "; "
+        "image/jpeg, "
+        COMMON_VIDEO_CAPS "; "
+        "video/x-theora; "
+        "video/x-dirac, "
+        COMMON_VIDEO_CAPS "; "
+        "video/x-pn-realvideo, "
+        "rmversion = (int) [1, 4], "
+        COMMON_VIDEO_CAPS "; "
+        "video/x-vp8, "
+        COMMON_VIDEO_CAPS "; "
+        "video/x-vp9, "
+        COMMON_VIDEO_CAPS "; "
+        "video/x-raw, "
+        "format = (string) { YUY2, I420, YV12, UYVY, AYUV, GRAY8, BGR, RGB }, "
+        COMMON_VIDEO_CAPS "; "
+        "video/x-prores, "
+        COMMON_VIDEO_CAPS "; "
+        "video/x-wmv, " "wmvversion = (int) [ 1, 3 ], " COMMON_VIDEO_CAPS)
+    );
+
+#define COMMON_AUDIO_CAPS \
+  "channels = (int) [ 1, MAX ], " \
+  "rate = (int) [ 1, MAX ]"
+
+/* FIXME:
+ * * require codec data, etc as needed
+ */
+static GstStaticPadTemplate audiosink_templ =
+    GST_STATIC_PAD_TEMPLATE ("audio_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("audio/mpeg, "
+        "mpegversion = (int) 1, "
+        "layer = (int) [ 1, 3 ], "
+        COMMON_AUDIO_CAPS "; "
+        "audio/mpeg, "
+        "mpegversion = (int) { 2, 4 }, "
+        "stream-format = (string) raw, "
+        COMMON_AUDIO_CAPS "; "
+        "audio/x-ac3, "
+        COMMON_AUDIO_CAPS "; "
+        "audio/x-eac3, "
+        COMMON_AUDIO_CAPS "; "
+        "audio/x-dts, "
+        COMMON_AUDIO_CAPS "; "
+        "audio/x-vorbis, "
+        COMMON_AUDIO_CAPS "; "
+        "audio/x-flac, "
+        COMMON_AUDIO_CAPS "; "
+        "audio/x-opus; "
+        "audio/x-speex, "
+        COMMON_AUDIO_CAPS "; "
+        "audio/x-raw, "
+        "format = (string) { U8, S16BE, S16LE, S24BE, S24LE, S32BE, S32LE, F32LE, F64LE }, "
+        "layout = (string) interleaved, "
+        COMMON_AUDIO_CAPS ";"
+        "audio/x-tta, "
+        "width = (int) { 8, 16, 24 }, "
+        "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
+        "audio/x-pn-realaudio, "
+        "raversion = (int) { 1, 2, 8 }, " COMMON_AUDIO_CAPS "; "
+        "audio/x-wma, " "wmaversion = (int) [ 1, 3 ], "
+        "block_align = (int) [ 0, 65535 ], bitrate = (int) [ 0, 524288 ], "
+        COMMON_AUDIO_CAPS ";"
+        "audio/x-alaw, "
+        "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
+        "audio/x-mulaw, "
+        "channels = (int) {1, 2}, " "rate = (int) [ 8000, 192000 ]; "
+        "audio/x-adpcm, "
+        "layout = (string)dvi, "
+        "block_align = (int)[64, 8192], "
+        "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
+        "audio/G722, "
+        "channels = (int)1," "rate = (int)16000; "
+        "audio/x-adpcm, "
+        "layout = (string)g726, " "channels = (int)1," "rate = (int)8000; ")
+    );
+
+static GstStaticPadTemplate subtitlesink_templ =
+    GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("subtitle/x-kate; "
+        "text/x-raw, format=utf8; application/x-ssa; application/x-ass; "
+        "application/x-usf; subpicture/x-dvd; "
+        "application/x-subtitle-unknown")
+    );
+
+static gpointer parent_class;   /* NULL */
+
+/* Matroska muxer destructor */
+static void gst_matroska_mux_class_init (GstMatroskaMuxClass * klass);
+static void gst_matroska_mux_init (GstMatroskaMux * mux, gpointer g_class);
+static void gst_matroska_mux_finalize (GObject * object);
+
+/* Pads collected callback */
+static GstFlowReturn gst_matroska_mux_handle_buffer (GstCollectPads * pads,
+    GstCollectData * data, GstBuffer * buf, gpointer user_data);
+static gboolean gst_matroska_mux_handle_sink_event (GstCollectPads * pads,
+    GstCollectData * data, GstEvent * event, gpointer user_data);
+
+/* pad functions */
+static gboolean gst_matroska_mux_handle_src_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static GstPad *gst_matroska_mux_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
+static void gst_matroska_mux_release_pad (GstElement * element, GstPad * pad);
+
+/* gst internal change state handler */
+static GstStateChangeReturn
+gst_matroska_mux_change_state (GstElement * element, GstStateChange transition);
+
+/* gobject bla bla */
+static void gst_matroska_mux_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_matroska_mux_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+/* reset muxer */
+static void gst_matroska_mux_reset (GstElement * element);
+
+/* uid generation */
+static guint64 gst_matroska_mux_create_uid (GstMatroskaMux * mux);
+
+static gboolean theora_streamheader_to_codecdata (const GValue * streamheader,
+    GstMatroskaTrackContext * context);
+static gboolean vorbis_streamheader_to_codecdata (const GValue * streamheader,
+    GstMatroskaTrackContext * context);
+static gboolean speex_streamheader_to_codecdata (const GValue * streamheader,
+    GstMatroskaTrackContext * context);
+static gboolean kate_streamheader_to_codecdata (const GValue * streamheader,
+    GstMatroskaTrackContext * context);
+static gboolean flac_streamheader_to_codecdata (const GValue * streamheader,
+    GstMatroskaTrackContext * context);
+static void
+gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
+    gpointer data);
+static gboolean gst_matroska_mux_tag_list_is_empty (const GstTagList * list);
+static void gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux);
+static gboolean gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux);
+
+/* Cannot use boilerplate macros here because we need the full init function
+ * signature with the additional class argument, so we use the right template
+ * for the sink caps */
+GType
+gst_matroska_mux_get_type (void)
+{
+  static GType object_type;     /* 0 */
+
+  if (object_type == 0) {
+    static const GTypeInfo object_info = {
+      sizeof (GstMatroskaMuxClass),
+      NULL,                     /* base_init */
+      NULL,                     /* base_finalize */
+      (GClassInitFunc) gst_matroska_mux_class_init,
+      NULL,                     /* class_finalize */
+      NULL,                     /* class_data */
+      sizeof (GstMatroskaMux),
+      0,                        /* n_preallocs */
+      (GInstanceInitFunc) gst_matroska_mux_init
+    };
+    const GInterfaceInfo iface_info = { NULL };
+
+    object_type = g_type_register_static (GST_TYPE_ELEMENT,
+        "GstMatroskaMux", &object_info, (GTypeFlags) 0);
+
+    g_type_add_interface_static (object_type, GST_TYPE_TAG_SETTER, &iface_info);
+    g_type_add_interface_static (object_type, GST_TYPE_TOC_SETTER, &iface_info);
+  }
+
+  return object_type;
+}
+
+static void
+gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &videosink_templ);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &audiosink_templ);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &subtitlesink_templ);
+  gst_element_class_add_static_pad_template (gstelement_class, &src_templ);
+  gst_element_class_set_static_metadata (gstelement_class, "Matroska muxer",
+      "Codec/Muxer",
+      "Muxes video/audio/subtitle streams into a matroska stream",
+      "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
+
+  GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
+      "Matroska muxer");
+
+  gobject_class->finalize = gst_matroska_mux_finalize;
+
+  gobject_class->get_property = gst_matroska_mux_get_property;
+  gobject_class->set_property = gst_matroska_mux_set_property;
+
+  g_object_class_install_property (gobject_class, PROP_WRITING_APP,
+      g_param_spec_string ("writing-app", "Writing application.",
+          "The name the application that creates the matroska file.",
+          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_DOCTYPE_VERSION,
+      g_param_spec_int ("version", "DocType version",
+          "This parameter determines what Matroska features can be used.",
+          1, 2, DEFAULT_DOCTYPE_VERSION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MIN_INDEX_INTERVAL,
+      g_param_spec_int64 ("min-index-interval", "Minimum time between index "
+          "entries", "An index entry is created every so many nanoseconds.",
+          0, G_MAXINT64, DEFAULT_MIN_INDEX_INTERVAL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_STREAMABLE,
+      g_param_spec_boolean ("streamable", "Determines whether output should "
+          "be streamable", "If set to true, the output should be as if it is "
+          "to be streamed and hence no indexes written or duration written.",
+          DEFAULT_STREAMABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_TIMECODESCALE,
+      g_param_spec_int64 ("timecodescale", "Timecode Scale",
+          "TimecodeScale used to calculate the Raw Timecode of a Block", 1,
+          GST_SECOND, DEFAULT_TIMECODESCALE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MIN_CLUSTER_DURATION,
+      g_param_spec_int64 ("min-cluster-duration", "Minimum cluster duration",
+          "Desidered cluster duration as nanoseconds. A new cluster will be "
+          "created irrespective of this property if a force key unit event "
+          "is received. 0 means create a new cluster for each video keyframe "
+          "or for each audio buffer in audio only streams.", 0,
+          G_MAXINT64, DEFAULT_MIN_CLUSTER_DURATION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MAX_CLUSTER_DURATION,
+      g_param_spec_int64 ("max-cluster-duration", "Maximum cluster duration",
+          "A new cluster will be created if its duration exceeds this value. "
+          "0 means no maximum duration.", 0,
+          G_MAXINT64, DEFAULT_MAX_CLUSTER_DURATION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_matroska_mux_change_state);
+  gstelement_class->request_new_pad =
+      GST_DEBUG_FUNCPTR (gst_matroska_mux_request_new_pad);
+  gstelement_class->release_pad =
+      GST_DEBUG_FUNCPTR (gst_matroska_mux_release_pad);
+
+  parent_class = g_type_class_peek_parent (klass);
+}
+
+/*
+ * Start of pad option handler code
+ */
+#define DEFAULT_PAD_FRAME_DURATION TRUE
+
+enum
+{
+  PROP_PAD_0,
+  PROP_PAD_FRAME_DURATION
+};
+
+typedef struct
+{
+  GstPad parent;
+  gboolean frame_duration;
+  gboolean frame_duration_user;
+} GstMatroskamuxPad;
+
+typedef GstPadClass GstMatroskamuxPadClass;
+
+GType gst_matroskamux_pad_get_type (void);
+G_DEFINE_TYPE (GstMatroskamuxPad, gst_matroskamux_pad, GST_TYPE_PAD);
+
+#define GST_TYPE_MATROSKAMUX_PAD (gst_matroskamux_pad_get_type())
+#define GST_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_CAST((pad),GST_TYPE_MATROSKAMUX_PAD,GstMatroskamuxPad))
+#define GST_MATROSKAMUX_PAD_CAST(pad) ((GstMatroskamuxPad *) pad)
+#define GST_IS_MATROSKAMUX_PAD(pad) (G_TYPE_CHECK_INSTANCE_TYPE((pad),GST_TYPE_MATROSKAMUX_PAD))
+
+static void
+gst_matroskamux_pad_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
+
+  switch (prop_id) {
+    case PROP_PAD_FRAME_DURATION:
+      g_value_set_boolean (value, pad->frame_duration);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_matroskamux_pad_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstMatroskamuxPad *pad = GST_MATROSKAMUX_PAD (object);
+
+  switch (prop_id) {
+    case PROP_PAD_FRAME_DURATION:
+      pad->frame_duration = g_value_get_boolean (value);
+      pad->frame_duration_user = TRUE;
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_matroskamux_pad_class_init (GstMatroskamuxPadClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+
+  gobject_class->set_property = gst_matroskamux_pad_set_property;
+  gobject_class->get_property = gst_matroskamux_pad_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_PAD_FRAME_DURATION,
+      g_param_spec_boolean ("frame-duration", "Frame duration",
+          "Default frame duration", DEFAULT_PAD_FRAME_DURATION,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_matroskamux_pad_init (GstMatroskamuxPad * pad)
+{
+  pad->frame_duration = DEFAULT_PAD_FRAME_DURATION;
+  pad->frame_duration_user = FALSE;
+}
+
+/*
+ * End of pad option handler code
+ **/
+
+static void
+gst_matroska_mux_init (GstMatroskaMux * mux, gpointer g_class)
+{
+  GstPadTemplate *templ;
+
+  templ =
+      gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
+  mux->srcpad = gst_pad_new_from_template (templ, "src");
+
+  gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
+  gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
+  gst_pad_use_fixed_caps (mux->srcpad);
+
+  mux->collect = gst_collect_pads_new ();
+  gst_collect_pads_set_clip_function (mux->collect,
+      GST_DEBUG_FUNCPTR (gst_collect_pads_clip_running_time), mux);
+  gst_collect_pads_set_buffer_function (mux->collect,
+      GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_buffer), mux);
+  gst_collect_pads_set_event_function (mux->collect,
+      GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event), mux);
+
+  mux->ebml_write = gst_ebml_write_new (mux->srcpad);
+  mux->doctype = GST_MATROSKA_DOCTYPE_MATROSKA;
+
+  /* property defaults */
+  mux->doctype_version = DEFAULT_DOCTYPE_VERSION;
+  mux->writing_app = g_strdup (DEFAULT_WRITING_APP);
+  mux->min_index_interval = DEFAULT_MIN_INDEX_INTERVAL;
+  mux->ebml_write->streamable = DEFAULT_STREAMABLE;
+  mux->time_scale = DEFAULT_TIMECODESCALE;
+  mux->min_cluster_duration = DEFAULT_MIN_CLUSTER_DURATION;
+  mux->max_cluster_duration = DEFAULT_MAX_CLUSTER_DURATION;
+
+  /* initialize internal variables */
+  mux->index = NULL;
+  mux->num_streams = 0;
+  mux->num_a_streams = 0;
+  mux->num_t_streams = 0;
+  mux->num_v_streams = 0;
+  mux->internal_toc = NULL;
+
+  /* create used uid list */
+  mux->used_uids = g_array_sized_new (FALSE, FALSE, sizeof (guint64), 10);
+
+  /* initialize remaining variables */
+  gst_matroska_mux_reset (GST_ELEMENT (mux));
+}
+
+
+/**
+ * gst_matroska_mux_finalize:
+ * @object: #GstMatroskaMux that should be finalized.
+ *
+ * Finalize matroska muxer.
+ */
+static void
+gst_matroska_mux_finalize (GObject * object)
+{
+  GstMatroskaMux *mux = GST_MATROSKA_MUX (object);
+
+  gst_event_replace (&mux->force_key_unit_event, NULL);
+
+  gst_object_unref (mux->collect);
+  gst_object_unref (mux->ebml_write);
+  g_free (mux->writing_app);
+
+  g_array_free (mux->used_uids, TRUE);
+
+  if (mux->internal_toc) {
+    gst_toc_unref (mux->internal_toc);
+    mux->internal_toc = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+/**
+ * gst_matroska_mux_create_uid:
+ * @mux: #GstMatroskaMux to generate UID for.
+ *
+ * Generate new unused track UID.
+ *
+ * Returns: New track UID.
+ */
+static guint64
+gst_matroska_mux_create_uid (GstMatroskaMux * mux)
+{
+  guint64 uid = 0;
+
+  while (!uid) {
+    guint i;
+
+    uid = (((guint64) g_random_int ()) << 32) | g_random_int ();
+    for (i = 0; i < mux->used_uids->len; i++) {
+      if (g_array_index (mux->used_uids, guint64, i) == uid) {
+        uid = 0;
+        break;
+      }
+    }
+    g_array_append_val (mux->used_uids, uid);
+  }
+
+  return uid;
+}
+
+
+/**
+ * gst_matroska_pad_reset:
+ * @collect_pad: the #GstMatroskaPad
+ *
+ * Reset and/or release resources of a matroska collect pad.
+ */
+static void
+gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
+{
+  gchar *name = NULL;
+  GstMatroskaTrackType type = 0;
+
+  /* free track information */
+  if (collect_pad->track != NULL) {
+    /* retrieve for optional later use */
+    name = collect_pad->track->name;
+    type = collect_pad->track->type;
+    /* extra for video */
+    if (type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
+      GstMatroskaTrackVideoContext *ctx =
+          (GstMatroskaTrackVideoContext *) collect_pad->track;
+
+      if (ctx->dirac_unit) {
+        gst_buffer_unref (ctx->dirac_unit);
+        ctx->dirac_unit = NULL;
+      }
+    }
+    g_free (collect_pad->track->codec_id);
+    g_free (collect_pad->track->codec_name);
+    if (full)
+      g_free (collect_pad->track->name);
+    g_free (collect_pad->track->language);
+    g_free (collect_pad->track->codec_priv);
+    g_free (collect_pad->track);
+    collect_pad->track = NULL;
+    if (collect_pad->tags) {
+      gst_tag_list_unref (collect_pad->tags);
+      collect_pad->tags = NULL;
+    }
+  }
+
+  if (!full && type != 0) {
+    GstMatroskaTrackContext *context;
+
+    /* create a fresh context */
+    switch (type) {
+      case GST_MATROSKA_TRACK_TYPE_VIDEO:
+        context = (GstMatroskaTrackContext *)
+            g_new0 (GstMatroskaTrackVideoContext, 1);
+        break;
+      case GST_MATROSKA_TRACK_TYPE_AUDIO:
+        context = (GstMatroskaTrackContext *)
+            g_new0 (GstMatroskaTrackAudioContext, 1);
+        break;
+      case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
+        context = (GstMatroskaTrackContext *)
+            g_new0 (GstMatroskaTrackSubtitleContext, 1);
+        break;
+      default:
+        g_assert_not_reached ();
+        return;
+    }
+
+    context->type = type;
+    context->name = name;
+    context->uid = gst_matroska_mux_create_uid (collect_pad->mux);
+    /* TODO: check default values for the context */
+    context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
+    collect_pad->track = context;
+    collect_pad->start_ts = GST_CLOCK_TIME_NONE;
+    collect_pad->end_ts = GST_CLOCK_TIME_NONE;
+    collect_pad->tags = gst_tag_list_new_empty ();
+    gst_tag_list_set_scope (collect_pad->tags, GST_TAG_SCOPE_STREAM);
+  }
+}
+
+/**
+ * gst_matroska_pad_free:
+ * @collect_pad: the #GstMatroskaPad
+ *
+ * Release resources of a matroska collect pad.
+ */
+static void
+gst_matroska_pad_free (GstPad * collect_pad)
+{
+  gst_matroska_pad_reset ((GstMatroskaPad *) collect_pad, TRUE);
+}
+
+
+/**
+ * gst_matroska_mux_reset:
+ * @element: #GstMatroskaMux that should be reseted.
+ *
+ * Reset matroska muxer back to initial state.
+ */
+static void
+gst_matroska_mux_reset (GstElement * element)
+{
+  GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
+  GSList *walk;
+
+  /* reset EBML write */
+  gst_ebml_write_reset (mux->ebml_write);
+
+  /* reset input */
+  mux->state = GST_MATROSKA_MUX_STATE_START;
+
+  /* clean up existing streams */
+
+  for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
+    GstMatroskaPad *collect_pad;
+
+    collect_pad = (GstMatroskaPad *) walk->data;
+
+    /* reset collect pad to pristine state */
+    gst_matroska_pad_reset (collect_pad, FALSE);
+  }
+
+  /* reset indexes */
+  mux->num_indexes = 0;
+  g_free (mux->index);
+  mux->index = NULL;
+
+  /* reset timers */
+  mux->duration = 0;
+
+  /* reset cluster */
+  mux->cluster = 0;
+  mux->cluster_time = 0;
+  mux->cluster_pos = 0;
+  mux->prev_cluster_size = 0;
+
+  /* reset tags */
+  gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
+
+  mux->tags_pos = 0;
+
+  /* reset chapters */
+  gst_toc_setter_reset (GST_TOC_SETTER (mux));
+  if (mux->internal_toc) {
+    gst_toc_unref (mux->internal_toc);
+    mux->internal_toc = NULL;
+  }
+
+  mux->chapters_pos = 0;
+
+  /* clear used uids */
+  if (mux->used_uids->len > 0) {
+    g_array_remove_range (mux->used_uids, 0, mux->used_uids->len);
+  }
+}
+
+/**
+ * gst_matroska_mux_handle_src_event:
+ * @pad: Pad which received the event.
+ * @event: Received event.
+ *
+ * handle events - copied from oggmux without understanding
+ *
+ * Returns: %TRUE on success.
+ */
+static gboolean
+gst_matroska_mux_handle_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstEventType type;
+
+  type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
+
+  switch (type) {
+    case GST_EVENT_SEEK:
+      /* disable seeking for now */
+      return FALSE;
+    default:
+      break;
+  }
+
+  return gst_pad_event_default (pad, parent, event);
+}
+
+
+static void
+gst_matroska_mux_free_codec_priv (GstMatroskaTrackContext * context)
+{
+  if (context->codec_priv != NULL) {
+    g_free (context->codec_priv);
+    context->codec_priv = NULL;
+    context->codec_priv_size = 0;
+  }
+}
+
+static void
+gst_matroska_mux_build_vobsub_private (GstMatroskaTrackContext * context,
+    const guint * clut)
+{
+  gchar *clutv[17];
+  gchar *sclut;
+  gint i;
+  guint32 col;
+  gdouble y, u, v;
+  guint8 r, g, b;
+
+  /* produce comma-separated list in hex format */
+  for (i = 0; i < 16; ++i) {
+    col = clut[i];
+    /* replicate vobsub's slightly off RGB conversion calculation */
+    y = (((col >> 16) & 0xff) - 16) * 255 / 219;
+    u = ((col >> 8) & 0xff) - 128;
+    v = (col & 0xff) - 128;
+    r = CLAMP (1.0 * y + 1.4022 * u, 0, 255);
+    g = CLAMP (1.0 * y - 0.3456 * u - 0.7145 * v, 0, 255);
+    b = CLAMP (1.0 * y + 1.7710 * v, 0, 255);
+    clutv[i] = g_strdup_printf ("%02x%02x%02x", r, g, b);
+  }
+  clutv[i] = NULL;
+  sclut = g_strjoinv (",", clutv);
+
+  /* build codec private; only palette for now */
+  gst_matroska_mux_free_codec_priv (context);
+  context->codec_priv = (guint8 *) g_strdup_printf ("palette: %s", sclut);
+  /* include terminating 0 */
+  context->codec_priv_size = strlen ((gchar *) context->codec_priv) + 1;
+  g_free (sclut);
+  for (i = 0; i < 16; ++i) {
+    g_free (clutv[i]);
+  }
+}
+
+
+/**
+ * gst_matroska_mux_handle_sink_event:
+ * @pad: Pad which received the event.
+ * @event: Received event.
+ *
+ * handle events - informational ones like tags
+ *
+ * Returns: %TRUE on success.
+ */
+static gboolean
+gst_matroska_mux_handle_sink_event (GstCollectPads * pads,
+    GstCollectData * data, GstEvent * event, gpointer user_data)
+{
+  GstMatroskaPad *collect_pad;
+  GstMatroskaTrackContext *context;
+  GstMatroskaMux *mux;
+  GstPad *pad;
+  GstTagList *list;
+  gboolean ret = TRUE;
+
+  mux = GST_MATROSKA_MUX (user_data);
+  collect_pad = (GstMatroskaPad *) data;
+  pad = data->pad;
+  context = collect_pad->track;
+  g_assert (context);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:{
+      GstCaps *caps;
+
+      collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
+      gst_event_parse_caps (event, &caps);
+
+      ret = collect_pad->capsfunc (pad, caps);
+      gst_event_unref (event);
+      event = NULL;
+      break;
+    }
+    case GST_EVENT_TAG:{
+      gchar *lang = NULL;
+
+      GST_DEBUG_OBJECT (mux, "received tag event");
+      gst_event_parse_tag (event, &list);
+
+      /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
+      if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
+        const gchar *lang_code;
+
+        lang_code = gst_tag_get_language_code_iso_639_2B (lang);
+        if (lang_code) {
+          GST_INFO_OBJECT (pad, "Setting language to '%s'", lang_code);
+          g_free (context->language);
+          context->language = g_strdup (lang_code);
+        } else {
+          GST_WARNING_OBJECT (pad, "Did not get language code for '%s'", lang);
+        }
+        g_free (lang);
+      }
+
+      /* FIXME: what about stream-specific tags? */
+      if (gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL) {
+        gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
+            gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
+      } else {
+        gst_tag_list_insert (collect_pad->tags, list, GST_TAG_MERGE_REPLACE);
+      }
+
+      gst_event_unref (event);
+      /* handled this, don't want collectpads to forward it downstream */
+      event = NULL;
+      ret = TRUE;
+      break;
+    }
+    case GST_EVENT_TOC:{
+      GstToc *toc, *old_toc;
+
+      if (mux->chapters_pos > 0)
+        break;
+
+      GST_DEBUG_OBJECT (mux, "received toc event");
+      gst_event_parse_toc (event, &toc, NULL);
+
+      if (toc != NULL) {
+        old_toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
+        if (old_toc != NULL) {
+          if (old_toc != toc)
+            GST_INFO_OBJECT (pad, "Replacing TOC with a new one");
+          gst_toc_unref (old_toc);
+        }
+
+        gst_toc_setter_set_toc (GST_TOC_SETTER (mux), toc);
+        gst_toc_unref (toc);
+      }
+
+      gst_event_unref (event);
+      /* handled this, don't want collectpads to forward it downstream */
+      event = NULL;
+      break;
+    }
+    case GST_EVENT_CUSTOM_DOWNSTREAM:
+    case GST_EVENT_CUSTOM_DOWNSTREAM_STICKY:{
+      const GstStructure *structure;
+
+      structure = gst_event_get_structure (event);
+      if (gst_structure_has_name (structure, "GstForceKeyUnit")) {
+        gst_event_replace (&mux->force_key_unit_event, NULL);
+        mux->force_key_unit_event = event;
+        event = NULL;
+      } else if (gst_structure_has_name (structure, "application/x-gst-dvd") &&
+          !strcmp ("dvd-spu-clut-change",
+              gst_structure_get_string (structure, "event"))) {
+        gchar name[16];
+        gint i, value;
+        guint clut[16];
+
+        GST_DEBUG_OBJECT (pad, "New DVD colour table received");
+        if (context->type != GST_MATROSKA_TRACK_TYPE_SUBTITLE) {
+          GST_DEBUG_OBJECT (pad, "... discarding");
+          break;
+        }
+        /* first transform event data into table form */
+        for (i = 0; i < 16; i++) {
+          g_snprintf (name, sizeof (name), "clut%02d", i);
+          if (!gst_structure_get_int (structure, name, &value)) {
+            GST_ERROR_OBJECT (mux, "dvd-spu-clut-change event did not "
+                "contain %s field", name);
+            goto break_hard;
+          }
+          clut[i] = value;
+        }
+
+        /* transform into private data for stream; text form */
+        gst_matroska_mux_build_vobsub_private (context, clut);
+      }
+    }
+      /* fall through */
+    default:
+      break;
+  }
+
+break_hard:
+  if (event != NULL)
+    return gst_collect_pads_event_default (pads, data, event, FALSE);
+
+  return ret;
+}
+
+static void
+gst_matroska_mux_set_codec_id (GstMatroskaTrackContext * context,
+    const char *id)
+{
+  g_assert (context && id);
+  g_free (context->codec_id);
+  context->codec_id = g_strdup (id);
+}
+
+/**
+ * gst_matroska_mux_video_pad_setcaps:
+ * @pad: Pad which got the caps.
+ * @caps: New caps.
+ *
+ * Setcaps function for video sink pad.
+ *
+ * Returns: %TRUE on success.
+ */
+static gboolean
+gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
+{
+  GstMatroskaTrackContext *context = NULL;
+  GstMatroskaTrackVideoContext *videocontext;
+  GstMatroskaMux *mux;
+  GstMatroskaPad *collect_pad;
+  GstStructure *structure;
+  const gchar *mimetype;
+  const gchar *interlace_mode, *s;
+  const GValue *value = NULL;
+  GstBuffer *codec_buf = NULL;
+  gint width, height, pixel_width, pixel_height;
+  gint fps_d, fps_n;
+  guint multiview_flags;
+
+  mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
+
+  /* find context */
+  collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
+  g_assert (collect_pad);
+  context = collect_pad->track;
+  g_assert (context);
+  g_assert (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO);
+  videocontext = (GstMatroskaTrackVideoContext *) context;
+
+  /* gst -> matroska ID'ing */
+  structure = gst_caps_get_structure (caps, 0);
+
+  mimetype = gst_structure_get_name (structure);
+
+  interlace_mode = gst_structure_get_string (structure, "interlace-mode");
+  if (interlace_mode != NULL && strcmp (interlace_mode, "progressive") != 0)
+    context->flags |= GST_MATROSKA_VIDEOTRACK_INTERLACED;
+
+  if (!strcmp (mimetype, "video/x-theora")) {
+    /* we'll extract the details later from the theora identification header */
+    goto skip_details;
+  }
+
+  /* get general properties */
+  /* spec says it is mandatory */
+  if (!gst_structure_get_int (structure, "width", &width) ||
+      !gst_structure_get_int (structure, "height", &height))
+    goto refuse_caps;
+
+  videocontext->pixel_width = width;
+  videocontext->pixel_height = height;
+
+  if (GST_MATROSKAMUX_PAD_CAST (pad)->frame_duration
+      && gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
+      && fps_n > 0) {
+    context->default_duration =
+        gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
+    GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (context->default_duration));
+  } else {
+    context->default_duration = 0;
+  }
+  if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
+          &pixel_width, &pixel_height)) {
+    if (pixel_width > pixel_height) {
+      videocontext->display_width = width * pixel_width / pixel_height;
+      videocontext->display_height = height;
+    } else if (pixel_width < pixel_height) {
+      videocontext->display_width = width;
+      videocontext->display_height = height * pixel_height / pixel_width;
+    } else {
+      videocontext->display_width = 0;
+      videocontext->display_height = 0;
+    }
+  } else {
+    videocontext->display_width = 0;
+    videocontext->display_height = 0;
+  }
+
+  /* Collect stereoscopic info, if any */
+  if ((s = gst_structure_get_string (structure, "multiview-mode")))
+    videocontext->multiview_mode =
+        gst_video_multiview_mode_from_caps_string (s);
+  gst_structure_get_flagset (structure, "multiview-flags", &multiview_flags,
+      NULL);
+  videocontext->multiview_flags = multiview_flags;
+
+
+skip_details:
+
+  videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
+  videocontext->fourcc = 0;
+
+  /* TODO: - check if we handle all codecs by the spec, i.e. codec private
+   *         data and other settings
+   *       - add new formats
+   */
+
+  /* extract codec_data, may turn out needed */
+  value = gst_structure_get_value (structure, "codec_data");
+  if (value)
+    codec_buf = (GstBuffer *) gst_value_get_buffer (value);
+
+  /* find type */
+  if (!strcmp (mimetype, "video/x-raw")) {
+    const gchar *fstr;
+    gst_matroska_mux_set_codec_id (context,
+        GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
+    fstr = gst_structure_get_string (structure, "format");
+    if (fstr) {
+      if (strlen (fstr) == 4)
+        videocontext->fourcc = GST_STR_FOURCC (fstr);
+      else if (!strcmp (fstr, "GRAY8"))
+        videocontext->fourcc = GST_MAKE_FOURCC ('Y', '8', '0', '0');
+      else if (!strcmp (fstr, "BGR"))
+        videocontext->fourcc = GST_MAKE_FOURCC ('B', 'G', 'R', 24);
+      else if (!strcmp (fstr, "RGB"))
+        videocontext->fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', 24);
+    }
+  } else if (!strcmp (mimetype, "video/x-huffyuv")      /* MS/VfW compatibility cases */
+      ||!strcmp (mimetype, "video/x-divx")
+      || !strcmp (mimetype, "video/x-dv")
+      || !strcmp (mimetype, "video/x-h263")
+      || !strcmp (mimetype, "video/x-msmpeg")
+      || !strcmp (mimetype, "video/x-wmv")
+      || !strcmp (mimetype, "image/jpeg")) {
+    gst_riff_strf_vids *bih;
+    gint size = sizeof (gst_riff_strf_vids);
+    guint32 fourcc = 0;
+
+    if (!strcmp (mimetype, "video/x-huffyuv"))
+      fourcc = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
+    else if (!strcmp (mimetype, "video/x-dv"))
+      fourcc = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
+    else if (!strcmp (mimetype, "video/x-h263"))
+      fourcc = GST_MAKE_FOURCC ('H', '2', '6', '3');
+    else if (!strcmp (mimetype, "video/x-divx")) {
+      gint divxversion;
+
+      gst_structure_get_int (structure, "divxversion", &divxversion);
+      switch (divxversion) {
+        case 3:
+          fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
+          break;
+        case 4:
+          fourcc = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
+          break;
+        case 5:
+          fourcc = GST_MAKE_FOURCC ('D', 'X', '5', '0');
+          break;
+      }
+    } else if (!strcmp (mimetype, "video/x-msmpeg")) {
+      gint msmpegversion;
+
+      gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
+      switch (msmpegversion) {
+        case 41:
+          fourcc = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
+          break;
+        case 42:
+          fourcc = GST_MAKE_FOURCC ('M', 'P', '4', '2');
+          break;
+        case 43:
+          goto msmpeg43;
+          break;
+      }
+    } else if (!strcmp (mimetype, "video/x-wmv")) {
+      gint wmvversion;
+      const gchar *fstr;
+
+      fstr = gst_structure_get_string (structure, "format");
+      if (fstr && strlen (fstr) == 4) {
+        fourcc = GST_STR_FOURCC (fstr);
+      } else if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
+        if (wmvversion == 2) {
+          fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
+        } else if (wmvversion == 1) {
+          fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
+        } else if (wmvversion == 3) {
+          fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
+        }
+      }
+    } else if (!strcmp (mimetype, "image/jpeg")) {
+      fourcc = GST_MAKE_FOURCC ('M', 'J', 'P', 'G');
+    }
+
+    if (!fourcc)
+      goto refuse_caps;
+
+    bih = g_new0 (gst_riff_strf_vids, 1);
+    GST_WRITE_UINT32_LE (&bih->size, size);
+    GST_WRITE_UINT32_LE (&bih->width, videocontext->pixel_width);
+    GST_WRITE_UINT32_LE (&bih->height, videocontext->pixel_height);
+    GST_WRITE_UINT32_LE (&bih->compression, fourcc);
+    GST_WRITE_UINT16_LE (&bih->planes, (guint16) 1);
+    GST_WRITE_UINT16_LE (&bih->bit_cnt, (guint16) 24);
+    GST_WRITE_UINT32_LE (&bih->image_size, videocontext->pixel_width *
+        videocontext->pixel_height * 3);
+
+    /* process codec private/initialization data, if any */
+    if (codec_buf) {
+      size += gst_buffer_get_size (codec_buf);
+      bih = g_realloc (bih, size);
+      GST_WRITE_UINT32_LE (&bih->size, size);
+      gst_buffer_extract (codec_buf, 0,
+          (guint8 *) bih + sizeof (gst_riff_strf_vids), -1);
+    }
+
+    gst_matroska_mux_set_codec_id (context,
+        GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
+    gst_matroska_mux_free_codec_priv (context);
+    context->codec_priv = (gpointer) bih;
+    context->codec_priv_size = size;
+    context->dts_only = TRUE;
+  } else if (!strcmp (mimetype, "video/x-h264")) {
+    gst_matroska_mux_set_codec_id (context,
+        GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
+    gst_matroska_mux_free_codec_priv (context);
+    /* Create avcC header */
+    if (codec_buf != NULL) {
+      context->codec_priv_size = gst_buffer_get_size (codec_buf);
+      context->codec_priv = g_malloc0 (context->codec_priv_size);
+      gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
+    }
+  } else if (!strcmp (mimetype, "video/x-h265")) {
+    gst_matroska_mux_set_codec_id (context,
+        GST_MATROSKA_CODEC_ID_VIDEO_MPEGH_HEVC);
+    gst_matroska_mux_free_codec_priv (context);
+    /* Create hvcC header */
+    if (codec_buf != NULL) {
+      context->codec_priv_size = gst_buffer_get_size (codec_buf);
+      context->codec_priv = g_malloc0 (context->codec_priv_size);
+      gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
+    }
+  } else if (!strcmp (mimetype, "video/x-theora")) {
+    const GValue *streamheader;
+
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
+
+    gst_matroska_mux_free_codec_priv (context);
+
+    streamheader = gst_structure_get_value (structure, "streamheader");
+    if (!theora_streamheader_to_codecdata (streamheader, context)) {
+      GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
+          ("theora stream headers missing or malformed"));
+      goto refuse_caps;
+    }
+  } else if (!strcmp (mimetype, "video/x-dirac")) {
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
+  } else if (!strcmp (mimetype, "video/x-vp8")) {
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP8);
+  } else if (!strcmp (mimetype, "video/x-vp9")) {
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP9);
+  } else if (!strcmp (mimetype, "video/x-av1")) {
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_AV1);
+  } else if (!strcmp (mimetype, "video/mpeg")) {
+    gint mpegversion;
+
+    gst_structure_get_int (structure, "mpegversion", &mpegversion);
+    switch (mpegversion) {
+      case 1:
+        gst_matroska_mux_set_codec_id (context,
+            GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
+        break;
+      case 2:
+        gst_matroska_mux_set_codec_id (context,
+            GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
+        break;
+      case 4:
+        gst_matroska_mux_set_codec_id (context,
+            GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
+        break;
+      default:
+        goto refuse_caps;
+    }
+
+    /* global headers may be in codec data */
+    if (codec_buf != NULL) {
+      gst_matroska_mux_free_codec_priv (context);
+      context->codec_priv_size = gst_buffer_get_size (codec_buf);
+      context->codec_priv = g_malloc0 (context->codec_priv_size);
+      gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
+    }
+  } else if (!strcmp (mimetype, "video/x-msmpeg")) {
+  msmpeg43:
+    /* can only make it here if preceding case verified it was version 3 */
+    gst_matroska_mux_set_codec_id (context,
+        GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
+  } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
+    gint rmversion;
+    const GValue *mdpr_data;
+
+    gst_structure_get_int (structure, "rmversion", &rmversion);
+    switch (rmversion) {
+      case 1:
+        gst_matroska_mux_set_codec_id (context,
+            GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
+        break;
+      case 2:
+        gst_matroska_mux_set_codec_id (context,
+            GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
+        break;
+      case 3:
+        gst_matroska_mux_set_codec_id (context,
+            GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
+        break;
+      case 4:
+        gst_matroska_mux_set_codec_id (context,
+            GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
+        break;
+      default:
+        goto refuse_caps;
+    }
+
+    mdpr_data = gst_structure_get_value (structure, "mdpr_data");
+    if (mdpr_data != NULL) {
+      guint8 *priv_data = NULL;
+      guint priv_data_size = 0;
+
+      GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
+
+      priv_data_size = gst_buffer_get_size (codec_data_buf);
+      priv_data = g_malloc0 (priv_data_size);
+
+      gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
+
+      gst_matroska_mux_free_codec_priv (context);
+      context->codec_priv = priv_data;
+      context->codec_priv_size = priv_data_size;
+    }
+  } else if (strcmp (mimetype, "video/x-prores") == 0) {
+    const gchar *variant;
+
+    gst_matroska_mux_free_codec_priv (context);
+
+    variant = gst_structure_get_string (structure, "format");
+    if (!variant || !g_strcmp0 (variant, "standard"))
+      context->codec_priv = g_strdup ("apcn");
+    else if (!g_strcmp0 (variant, "hq"))
+      context->codec_priv = g_strdup ("apch");
+    else if (!g_strcmp0 (variant, "lt"))
+      context->codec_priv = g_strdup ("apcs");
+    else if (!g_strcmp0 (variant, "proxy"))
+      context->codec_priv = g_strdup ("apco");
+    else if (!g_strcmp0 (variant, "4444"))
+      context->codec_priv = g_strdup ("ap4h");
+    else {
+      GST_WARNING_OBJECT (mux, "Unhandled prores format: %s", variant);
+
+      goto refuse_caps;
+    }
+
+    context->codec_priv_size = sizeof (guint32);
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_PRORES);
+  }
+
+  return TRUE;
+
+  /* ERRORS */
+refuse_caps:
+  {
+    GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
+        GST_PAD_NAME (pad), caps);
+    return FALSE;
+  }
+}
+
+/* N > 0 to expect a particular number of headers, negative if the
+   number of headers is variable */
+static gboolean
+xiphN_streamheader_to_codecdata (const GValue * streamheader,
+    GstMatroskaTrackContext * context, GstBuffer ** p_buf0, int N)
+{
+  GstBuffer **buf = NULL;
+  GArray *bufarr;
+  guint8 *priv_data;
+  guint bufi, i, offset, priv_data_size;
+
+  if (streamheader == NULL)
+    goto no_stream_headers;
+
+  if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
+    goto wrong_type;
+
+  bufarr = g_value_peek_pointer (streamheader);
+  if (bufarr->len <= 0 || bufarr->len > 255)    /* at least one header, and count stored in a byte */
+    goto wrong_count;
+  if (N > 0 && bufarr->len != N)
+    goto wrong_count;
+
+  context->xiph_headers_to_skip = bufarr->len;
+
+  buf = (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * bufarr->len);
+  for (i = 0; i < bufarr->len; i++) {
+    GValue *bufval = &g_array_index (bufarr, GValue, i);
+
+    if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
+      g_free (buf);
+      goto wrong_content_type;
+    }
+
+    buf[i] = g_value_peek_pointer (bufval);
+  }
+
+  priv_data_size = 1;
+  if (bufarr->len > 0) {
+    for (i = 0; i < bufarr->len - 1; i++) {
+      priv_data_size += gst_buffer_get_size (buf[i]) / 0xff + 1;
+    }
+  }
+
+  for (i = 0; i < bufarr->len; ++i) {
+    priv_data_size += gst_buffer_get_size (buf[i]);
+  }
+
+  priv_data = g_malloc0 (priv_data_size);
+
+  priv_data[0] = bufarr->len - 1;
+  offset = 1;
+
+  if (bufarr->len > 0) {
+    for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
+      for (i = 0; i < gst_buffer_get_size (buf[bufi]) / 0xff; ++i) {
+        priv_data[offset++] = 0xff;
+      }
+      priv_data[offset++] = gst_buffer_get_size (buf[bufi]) % 0xff;
+    }
+  }
+
+  for (i = 0; i < bufarr->len; ++i) {
+    gst_buffer_extract (buf[i], 0, priv_data + offset, -1);
+    offset += gst_buffer_get_size (buf[i]);
+  }
+
+  gst_matroska_mux_free_codec_priv (context);
+  context->codec_priv = priv_data;
+  context->codec_priv_size = priv_data_size;
+
+  if (p_buf0)
+    *p_buf0 = gst_buffer_ref (buf[0]);
+
+  g_free (buf);
+
+  return TRUE;
+
+/* ERRORS */
+no_stream_headers:
+  {
+    GST_WARNING ("required streamheaders missing in sink caps!");
+    return FALSE;
+  }
+wrong_type:
+  {
+    GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
+        G_VALUE_TYPE_NAME (streamheader));
+    return FALSE;
+  }
+wrong_count:
+  {
+    GST_WARNING ("got %u streamheaders, not %d as expected", bufarr->len, N);
+    return FALSE;
+  }
+wrong_content_type:
+  {
+    GST_WARNING ("streamheaders array does not contain GstBuffers");
+    return FALSE;
+  }
+}
+
+static gboolean
+vorbis_streamheader_to_codecdata (const GValue * streamheader,
+    GstMatroskaTrackContext * context)
+{
+  GstBuffer *buf0 = NULL;
+
+  if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
+    return FALSE;
+
+  if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 4) {
+    GST_WARNING ("First vorbis header too small, ignoring");
+  } else {
+    if (gst_buffer_memcmp (buf0, 1, "vorbis", 6) == 0) {
+      GstMatroskaTrackAudioContext *audiocontext;
+      GstMapInfo map;
+      guint8 *hdr;
+
+      gst_buffer_map (buf0, &map, GST_MAP_READ);
+      hdr = map.data + 1 + 6 + 4;
+      audiocontext = (GstMatroskaTrackAudioContext *) context;
+      audiocontext->channels = GST_READ_UINT8 (hdr);
+      audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
+      gst_buffer_unmap (buf0, &map);
+    }
+  }
+
+  if (buf0)
+    gst_buffer_unref (buf0);
+
+  return TRUE;
+}
+
+static gboolean
+theora_streamheader_to_codecdata (const GValue * streamheader,
+    GstMatroskaTrackContext * context)
+{
+  GstBuffer *buf0 = NULL;
+
+  if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
+    return FALSE;
+
+  if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 26) {
+    GST_WARNING ("First theora header too small, ignoring");
+  } else if (gst_buffer_memcmp (buf0, 0, "\200theora\003\002", 9) != 0) {
+    GST_WARNING ("First header not a theora identification header, ignoring");
+  } else {
+    GstMatroskaTrackVideoContext *videocontext;
+    guint fps_num, fps_denom, par_num, par_denom;
+    GstMapInfo map;
+    guint8 *hdr;
+
+    gst_buffer_map (buf0, &map, GST_MAP_READ);
+    hdr = map.data + 1 + 6 + 3 + 2 + 2;
+
+    videocontext = (GstMatroskaTrackVideoContext *) context;
+    videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
+    videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
+    hdr += 3 + 3 + 1 + 1;
+    fps_num = GST_READ_UINT32_BE (hdr);
+    fps_denom = GST_READ_UINT32_BE (hdr + 4);
+    context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
+        fps_denom, fps_num);
+    hdr += 4 + 4;
+    par_num = GST_READ_UINT32_BE (hdr) >> 8;
+    par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
+    if (par_num > 0 && par_denom > 0) {
+      if (par_num > par_denom) {
+        videocontext->display_width =
+            videocontext->pixel_width * par_num / par_denom;
+        videocontext->display_height = videocontext->pixel_height;
+      } else if (par_num < par_denom) {
+        videocontext->display_width = videocontext->pixel_width;
+        videocontext->display_height =
+            videocontext->pixel_height * par_denom / par_num;
+      } else {
+        videocontext->display_width = 0;
+        videocontext->display_height = 0;
+      }
+    } else {
+      videocontext->display_width = 0;
+      videocontext->display_height = 0;
+    }
+
+    gst_buffer_unmap (buf0, &map);
+  }
+
+  if (buf0)
+    gst_buffer_unref (buf0);
+
+  return TRUE;
+}
+
+static gboolean
+kate_streamheader_to_codecdata (const GValue * streamheader,
+    GstMatroskaTrackContext * context)
+{
+  GstBuffer *buf0 = NULL;
+
+  if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
+    return FALSE;
+
+  if (buf0 == NULL || gst_buffer_get_size (buf0) < 64) {        /* Kate ID header is 64 bytes */
+    GST_WARNING ("First kate header too small, ignoring");
+  } else if (gst_buffer_memcmp (buf0, 0, "\200kate\0\0\0", 8) != 0) {
+    GST_WARNING ("First header not a kate identification header, ignoring");
+  }
+
+  if (buf0)
+    gst_buffer_unref (buf0);
+
+  return TRUE;
+}
+
+static gboolean
+flac_streamheader_to_codecdata (const GValue * streamheader,
+    GstMatroskaTrackContext * context)
+{
+  GArray *bufarr;
+  gint i;
+  GValue *bufval;
+  GstBuffer *buffer;
+
+  if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
+    GST_WARNING ("No or invalid streamheader field in the caps");
+    return FALSE;
+  }
+
+  bufarr = g_value_peek_pointer (streamheader);
+  if (bufarr->len < 2) {
+    GST_WARNING ("Too few headers in streamheader field");
+    return FALSE;
+  }
+
+  context->xiph_headers_to_skip = bufarr->len + 1;
+
+  bufval = &g_array_index (bufarr, GValue, 0);
+  if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
+    GST_WARNING ("streamheaders array does not contain GstBuffers");
+    return FALSE;
+  }
+
+  buffer = g_value_peek_pointer (bufval);
+
+  /* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
+  if (gst_buffer_get_size (buffer) < 9 + 4 + 4 + 34
+      || gst_buffer_memcmp (buffer, 1, "FLAC", 4) != 0
+      || gst_buffer_memcmp (buffer, 9, "fLaC", 4) != 0) {
+    GST_WARNING ("Invalid streamheader for FLAC");
+    return FALSE;
+  }
+
+  gst_matroska_mux_free_codec_priv (context);
+  context->codec_priv_size = gst_buffer_get_size (buffer) - 9;
+  context->codec_priv = g_malloc (context->codec_priv_size);
+  gst_buffer_extract (buffer, 9, context->codec_priv, -1);
+
+  for (i = 1; i < bufarr->len; i++) {
+    guint old_size;
+    bufval = &g_array_index (bufarr, GValue, i);
+
+    if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
+      gst_matroska_mux_free_codec_priv (context);
+      GST_WARNING ("streamheaders array does not contain GstBuffers");
+      return FALSE;
+    }
+
+    buffer = g_value_peek_pointer (bufval);
+
+    old_size = context->codec_priv_size;
+    context->codec_priv_size += gst_buffer_get_size (buffer);
+
+    context->codec_priv = g_realloc (context->codec_priv,
+        context->codec_priv_size);
+    gst_buffer_extract (buffer, 0,
+        (guint8 *) context->codec_priv + old_size, -1);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+speex_streamheader_to_codecdata (const GValue * streamheader,
+    GstMatroskaTrackContext * context)
+{
+  GArray *bufarr;
+  GValue *bufval;
+  GstBuffer *buffer;
+  guint old_size;
+
+  if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
+    GST_WARNING ("No or invalid streamheader field in the caps");
+    return FALSE;
+  }
+
+  bufarr = g_value_peek_pointer (streamheader);
+  if (bufarr->len != 2) {
+    GST_WARNING ("Too few headers in streamheader field");
+    return FALSE;
+  }
+
+  context->xiph_headers_to_skip = bufarr->len + 1;
+
+  bufval = &g_array_index (bufarr, GValue, 0);
+  if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
+    GST_WARNING ("streamheaders array does not contain GstBuffers");
+    return FALSE;
+  }
+
+  buffer = g_value_peek_pointer (bufval);
+
+  if (gst_buffer_get_size (buffer) < 80
+      || gst_buffer_memcmp (buffer, 0, "Speex   ", 8) != 0) {
+    GST_WARNING ("Invalid streamheader for Speex");
+    return FALSE;
+  }
+
+  gst_matroska_mux_free_codec_priv (context);
+  context->codec_priv_size = gst_buffer_get_size (buffer);
+  context->codec_priv = g_malloc (context->codec_priv_size);
+  gst_buffer_extract (buffer, 0, context->codec_priv, -1);
+
+  bufval = &g_array_index (bufarr, GValue, 1);
+
+  if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
+    gst_matroska_mux_free_codec_priv (context);
+    GST_WARNING ("streamheaders array does not contain GstBuffers");
+    return FALSE;
+  }
+
+  buffer = g_value_peek_pointer (bufval);
+
+  old_size = context->codec_priv_size;
+  context->codec_priv_size += gst_buffer_get_size (buffer);
+  context->codec_priv = g_realloc (context->codec_priv,
+      context->codec_priv_size);
+  gst_buffer_extract (buffer, 0, (guint8 *) context->codec_priv + old_size, -1);
+
+  return TRUE;
+}
+
+static gboolean
+opus_streamheader_to_codecdata (const GValue * streamheader,
+    GstMatroskaTrackContext * context)
+{
+  GArray *bufarr;
+  GValue *bufval;
+  GstBuffer *buf;
+
+  if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
+    goto wrong_type;
+
+  bufarr = g_value_peek_pointer (streamheader);
+  if (bufarr->len != 1 && bufarr->len != 2)     /* one header, and count stored in a byte */
+    goto wrong_count;
+
+  /* Opus headers are not in-band */
+  context->xiph_headers_to_skip = 0;
+
+  bufval = &g_array_index (bufarr, GValue, 0);
+  if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
+    goto wrong_content_type;
+  }
+  buf = g_value_peek_pointer (bufval);
+
+  gst_matroska_mux_free_codec_priv (context);
+
+  context->codec_priv_size = gst_buffer_get_size (buf);
+  context->codec_priv = g_malloc0 (context->codec_priv_size);
+  gst_buffer_extract (buf, 0, context->codec_priv, -1);
+
+  context->codec_delay =
+      GST_READ_UINT16_LE ((guint8 *) context->codec_priv + 10);
+  context->codec_delay =
+      gst_util_uint64_scale_round (context->codec_delay, GST_SECOND, 48000);
+  context->seek_preroll = 80 * GST_MSECOND;
+
+  return TRUE;
+
+/* ERRORS */
+wrong_type:
+  {
+    GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
+        G_VALUE_TYPE_NAME (streamheader));
+    return FALSE;
+  }
+wrong_count:
+  {
+    GST_WARNING ("got %u streamheaders, not 1 or 2 as expected", bufarr->len);
+    return FALSE;
+  }
+wrong_content_type:
+  {
+    GST_WARNING ("streamheaders array does not contain GstBuffers");
+    return FALSE;
+  }
+}
+
+static gboolean
+opus_make_codecdata (GstMatroskaTrackContext * context, GstCaps * caps)
+{
+  guint32 rate;
+  guint8 channels;
+  guint8 channel_mapping_family;
+  guint8 stream_count, coupled_count, channel_mapping[256];
+  GstBuffer *buffer;
+  GstMapInfo map;
+
+  /* Opus headers are not in-band */
+  context->xiph_headers_to_skip = 0;
+
+  context->codec_delay = 0;
+  context->seek_preroll = 80 * GST_MSECOND;
+
+  if (!gst_codec_utils_opus_parse_caps (caps, &rate, &channels,
+          &channel_mapping_family, &stream_count, &coupled_count,
+          channel_mapping)) {
+    GST_WARNING ("Failed to parse caps for Opus");
+    return FALSE;
+  }
+
+  buffer =
+      gst_codec_utils_opus_create_header (rate, channels,
+      channel_mapping_family, stream_count, coupled_count, channel_mapping, 0,
+      0);
+  if (!buffer) {
+    GST_WARNING ("Failed to create Opus header from caps");
+    return FALSE;
+  }
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  context->codec_priv_size = map.size;
+  context->codec_priv = g_malloc (context->codec_priv_size);
+  memcpy (context->codec_priv, map.data, map.size);
+  gst_buffer_unmap (buffer, &map);
+  gst_buffer_unref (buffer);
+
+  return TRUE;
+}
+
+/**
+ * gst_matroska_mux_audio_pad_setcaps:
+ * @pad: Pad which got the caps.
+ * @caps: New caps.
+ *
+ * Setcaps function for audio sink pad.
+ *
+ * Returns: %TRUE on success.
+ */
+static gboolean
+gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
+{
+  GstMatroskaTrackContext *context = NULL;
+  GstMatroskaTrackAudioContext *audiocontext;
+  GstMatroskaMux *mux;
+  GstMatroskaPad *collect_pad;
+  const gchar *mimetype;
+  gint samplerate = 0, channels = 0;
+  GstStructure *structure;
+  const GValue *codec_data = NULL;
+  GstBuffer *buf = NULL;
+  const gchar *stream_format = NULL;
+
+  mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
+
+  /* find context */
+  collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
+  g_assert (collect_pad);
+  context = collect_pad->track;
+  g_assert (context);
+  g_assert (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO);
+  audiocontext = (GstMatroskaTrackAudioContext *) context;
+
+  structure = gst_caps_get_structure (caps, 0);
+  mimetype = gst_structure_get_name (structure);
+
+  /* general setup */
+  gst_structure_get_int (structure, "rate", &samplerate);
+  gst_structure_get_int (structure, "channels", &channels);
+
+  audiocontext->samplerate = samplerate;
+  audiocontext->channels = channels;
+  audiocontext->bitdepth = 0;
+  context->default_duration = 0;
+
+  codec_data = gst_structure_get_value (structure, "codec_data");
+  if (codec_data)
+    buf = gst_value_get_buffer (codec_data);
+
+  /* TODO: - check if we handle all codecs by the spec, i.e. codec private
+   *         data and other settings
+   *       - add new formats
+   */
+
+  if (!strcmp (mimetype, "audio/mpeg")) {
+    gint mpegversion = 0;
+
+    gst_structure_get_int (structure, "mpegversion", &mpegversion);
+    switch (mpegversion) {
+      case 1:{
+        gint layer;
+        gint version = 1;
+        gint spf;
+
+        gst_structure_get_int (structure, "layer", &layer);
+
+        if (!gst_structure_get_int (structure, "mpegaudioversion", &version)) {
+          GST_WARNING_OBJECT (mux,
+              "Unable to determine MPEG audio version, assuming 1");
+          version = 1;
+        }
+
+        if (layer == 1)
+          spf = 384;
+        else if (layer == 2)
+          spf = 1152;
+        else if (version == 2)
+          spf = 576;
+        else
+          spf = 1152;
+
+        context->default_duration =
+            gst_util_uint64_scale (GST_SECOND, spf, audiocontext->samplerate);
+
+        switch (layer) {
+          case 1:
+            gst_matroska_mux_set_codec_id (context,
+                GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
+            break;
+          case 2:
+            gst_matroska_mux_set_codec_id (context,
+                GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
+            break;
+          case 3:
+            gst_matroska_mux_set_codec_id (context,
+                GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
+            break;
+          default:
+            goto refuse_caps;
+        }
+        break;
+      }
+      case 2:
+      case 4:
+        stream_format = gst_structure_get_string (structure, "stream-format");
+        /* check this is raw aac */
+        if (stream_format) {
+          if (strcmp (stream_format, "raw") != 0) {
+            GST_WARNING_OBJECT (mux, "AAC stream-format must be 'raw', not %s",
+                stream_format);
+          }
+        } else {
+          GST_WARNING_OBJECT (mux, "AAC stream-format not specified, "
+              "assuming 'raw'");
+        }
+
+        if (buf) {
+          gst_matroska_mux_set_codec_id (context,
+              GST_MATROSKA_CODEC_ID_AUDIO_AAC);
+          context->codec_priv_size = gst_buffer_get_size (buf);
+          context->codec_priv = g_malloc (context->codec_priv_size);
+          gst_buffer_extract (buf, 0, context->codec_priv,
+              context->codec_priv_size);
+        } else {
+          GST_DEBUG_OBJECT (mux, "no AAC codec_data; not packetized");
+          goto refuse_caps;
+        }
+        break;
+      default:
+        goto refuse_caps;
+    }
+  } else if (!strcmp (mimetype, "audio/x-raw")) {
+    GstAudioInfo info;
+
+    gst_audio_info_init (&info);
+    if (!gst_audio_info_from_caps (&info, caps)) {
+      GST_DEBUG_OBJECT (mux,
+          "broken caps, rejected by gst_audio_info_from_caps");
+      goto refuse_caps;
+    }
+
+    switch (GST_AUDIO_INFO_FORMAT (&info)) {
+      case GST_AUDIO_FORMAT_U8:
+      case GST_AUDIO_FORMAT_S16BE:
+      case GST_AUDIO_FORMAT_S16LE:
+      case GST_AUDIO_FORMAT_S24BE:
+      case GST_AUDIO_FORMAT_S24LE:
+      case GST_AUDIO_FORMAT_S32BE:
+      case GST_AUDIO_FORMAT_S32LE:
+        if (GST_AUDIO_INFO_WIDTH (&info) != GST_AUDIO_INFO_DEPTH (&info)) {
+          GST_DEBUG_OBJECT (mux, "width must be same as depth!");
+          goto refuse_caps;
+        }
+        if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&info))
+          gst_matroska_mux_set_codec_id (context,
+              GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
+        else
+          gst_matroska_mux_set_codec_id (context,
+              GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
+        break;
+      case GST_AUDIO_FORMAT_F32LE:
+      case GST_AUDIO_FORMAT_F64LE:
+        gst_matroska_mux_set_codec_id (context,
+            GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
+        break;
+
+      default:
+        GST_DEBUG_OBJECT (mux, "wrong format in raw audio caps");
+        goto refuse_caps;
+    }
+
+    audiocontext->bitdepth = GST_AUDIO_INFO_WIDTH (&info);
+  } else if (!strcmp (mimetype, "audio/x-vorbis")) {
+    const GValue *streamheader;
+
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
+
+    gst_matroska_mux_free_codec_priv (context);
+
+    streamheader = gst_structure_get_value (structure, "streamheader");
+    if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
+      GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
+          ("vorbis stream headers missing or malformed"));
+      goto refuse_caps;
+    }
+  } else if (!strcmp (mimetype, "audio/x-flac")) {
+    const GValue *streamheader;
+
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
+
+    gst_matroska_mux_free_codec_priv (context);
+
+    streamheader = gst_structure_get_value (structure, "streamheader");
+    if (!flac_streamheader_to_codecdata (streamheader, context)) {
+      GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
+          ("flac stream headers missing or malformed"));
+      goto refuse_caps;
+    }
+  } else if (!strcmp (mimetype, "audio/x-speex")) {
+    const GValue *streamheader;
+
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
+    gst_matroska_mux_free_codec_priv (context);
+
+    streamheader = gst_structure_get_value (structure, "streamheader");
+    if (!speex_streamheader_to_codecdata (streamheader, context)) {
+      GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
+          ("speex stream headers missing or malformed"));
+      goto refuse_caps;
+    }
+  } else if (!strcmp (mimetype, "audio/x-opus")) {
+    const GValue *streamheader;
+
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_OPUS);
+
+    streamheader = gst_structure_get_value (structure, "streamheader");
+    if (streamheader) {
+      gst_matroska_mux_free_codec_priv (context);
+      if (!opus_streamheader_to_codecdata (streamheader, context)) {
+        GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
+            ("opus stream headers missing or malformed"));
+        goto refuse_caps;
+      }
+    } else {
+      /* no streamheader, but we need to have one, so we make one up
+         based on caps */
+      gst_matroska_mux_free_codec_priv (context);
+      if (!opus_make_codecdata (context, caps)) {
+        GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
+            ("opus stream headers missing or malformed"));
+        goto refuse_caps;
+      }
+    }
+  } else if (!strcmp (mimetype, "audio/x-ac3")) {
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_AC3);
+  } else if (!strcmp (mimetype, "audio/x-eac3")) {
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
+  } else if (!strcmp (mimetype, "audio/x-dts")) {
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_DTS);
+  } else if (!strcmp (mimetype, "audio/x-tta")) {
+    gint width;
+
+    /* TTA frame duration */
+    context->default_duration = 1.04489795918367346939 * GST_SECOND;
+
+    gst_structure_get_int (structure, "width", &width);
+    audiocontext->bitdepth = width;
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_TTA);
+
+  } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
+    gint raversion;
+    const GValue *mdpr_data;
+
+    gst_structure_get_int (structure, "raversion", &raversion);
+    switch (raversion) {
+      case 1:
+        gst_matroska_mux_set_codec_id (context,
+            GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
+        break;
+      case 2:
+        gst_matroska_mux_set_codec_id (context,
+            GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
+        break;
+      case 8:
+        gst_matroska_mux_set_codec_id (context,
+            GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
+        break;
+      default:
+        goto refuse_caps;
+    }
+
+    mdpr_data = gst_structure_get_value (structure, "mdpr_data");
+    if (mdpr_data != NULL) {
+      guint8 *priv_data = NULL;
+      guint priv_data_size = 0;
+
+      GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
+
+      priv_data_size = gst_buffer_get_size (codec_data_buf);
+      priv_data = g_malloc0 (priv_data_size);
+
+      gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
+
+      gst_matroska_mux_free_codec_priv (context);
+
+      context->codec_priv = priv_data;
+      context->codec_priv_size = priv_data_size;
+    }
+
+  } else if (!strcmp (mimetype, "audio/x-wma")
+      || !strcmp (mimetype, "audio/x-alaw")
+      || !strcmp (mimetype, "audio/x-mulaw")
+      || !strcmp (mimetype, "audio/x-adpcm")
+      || !strcmp (mimetype, "audio/G722")) {
+    guint8 *codec_priv;
+    guint codec_priv_size;
+    guint16 format = 0;
+    gint block_align = 0;
+    gint bitrate = 0;
+
+    if (samplerate == 0 || channels == 0) {
+      GST_WARNING_OBJECT (mux, "Missing channels/samplerate on caps");
+      goto refuse_caps;
+    }
+
+    if (!strcmp (mimetype, "audio/x-wma")) {
+      gint wmaversion;
+      gint depth;
+
+      if (!gst_structure_get_int (structure, "wmaversion", &wmaversion)
+          || !gst_structure_get_int (structure, "block_align", &block_align)
+          || !gst_structure_get_int (structure, "bitrate", &bitrate)) {
+        GST_WARNING_OBJECT (mux, "Missing wmaversion/block_align/bitrate"
+            " on WMA caps");
+        goto refuse_caps;
+      }
+
+      switch (wmaversion) {
+        case 1:
+          format = GST_RIFF_WAVE_FORMAT_WMAV1;
+          break;
+        case 2:
+          format = GST_RIFF_WAVE_FORMAT_WMAV2;
+          break;
+        case 3:
+          format = GST_RIFF_WAVE_FORMAT_WMAV3;
+          break;
+        default:
+          GST_WARNING_OBJECT (mux, "Unexpected WMA version: %d", wmaversion);
+          goto refuse_caps;
+      }
+
+      if (gst_structure_get_int (structure, "depth", &depth))
+        audiocontext->bitdepth = depth;
+    } else if (!strcmp (mimetype, "audio/x-alaw")
+        || !strcmp (mimetype, "audio/x-mulaw")) {
+      audiocontext->bitdepth = 8;
+      if (!strcmp (mimetype, "audio/x-alaw"))
+        format = GST_RIFF_WAVE_FORMAT_ALAW;
+      else
+        format = GST_RIFF_WAVE_FORMAT_MULAW;
+
+      block_align = channels;
+      bitrate = block_align * samplerate;
+    } else if (!strcmp (mimetype, "audio/x-adpcm")) {
+      const char *layout;
+
+      layout = gst_structure_get_string (structure, "layout");
+      if (!layout) {
+        GST_WARNING_OBJECT (mux, "Missing layout on adpcm caps");
+        goto refuse_caps;
+      }
+
+      if (!gst_structure_get_int (structure, "block_align", &block_align)) {
+        GST_WARNING_OBJECT (mux, "Missing block_align on adpcm caps");
+        goto refuse_caps;
+      }
+
+      if (!strcmp (layout, "dvi")) {
+        format = GST_RIFF_WAVE_FORMAT_DVI_ADPCM;
+      } else if (!strcmp (layout, "g726")) {
+        format = GST_RIFF_WAVE_FORMAT_ITU_G726_ADPCM;
+        if (!gst_structure_get_int (structure, "bitrate", &bitrate)) {
+          GST_WARNING_OBJECT (mux, "Missing bitrate on adpcm g726 caps");
+          goto refuse_caps;
+        }
+      } else {
+        GST_WARNING_OBJECT (mux, "Unknown layout on adpcm caps");
+        goto refuse_caps;
+      }
+
+    } else if (!strcmp (mimetype, "audio/G722")) {
+      format = GST_RIFF_WAVE_FORMAT_ADPCM_G722;
+    }
+    g_assert (format != 0);
+
+    codec_priv_size = WAVEFORMATEX_SIZE;
+    if (buf)
+      codec_priv_size += gst_buffer_get_size (buf);
+
+    /* serialize waveformatex structure */
+    codec_priv = g_malloc0 (codec_priv_size);
+    GST_WRITE_UINT16_LE (codec_priv, format);
+    GST_WRITE_UINT16_LE (codec_priv + 2, channels);
+    GST_WRITE_UINT32_LE (codec_priv + 4, samplerate);
+    GST_WRITE_UINT32_LE (codec_priv + 8, bitrate / 8);
+    GST_WRITE_UINT16_LE (codec_priv + 12, block_align);
+    GST_WRITE_UINT16_LE (codec_priv + 14, 0);
+    if (buf)
+      GST_WRITE_UINT16_LE (codec_priv + 16, gst_buffer_get_size (buf));
+    else
+      GST_WRITE_UINT16_LE (codec_priv + 16, 0);
+
+    /* process codec private/initialization data, if any */
+    if (buf) {
+      gst_buffer_extract (buf, 0,
+          (guint8 *) codec_priv + WAVEFORMATEX_SIZE, -1);
+    }
+
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_ACM);
+    gst_matroska_mux_free_codec_priv (context);
+    context->codec_priv = (gpointer) codec_priv;
+    context->codec_priv_size = codec_priv_size;
+  }
+
+  return TRUE;
+
+  /* ERRORS */
+refuse_caps:
+  {
+    GST_WARNING_OBJECT (mux, "pad %s refused caps %" GST_PTR_FORMAT,
+        GST_PAD_NAME (pad), caps);
+    return FALSE;
+  }
+}
+
+/* we probably don't have the data at start,
+ * so have to reserve (a maximum) space to write this at the end.
+ * bit spacy, but some formats can hold quite some */
+#define SUBTITLE_MAX_CODEC_PRIVATE   2048       /* must be > 128 */
+
+/**
+ * gst_matroska_mux_subtitle_pad_setcaps:
+ * @pad: Pad which got the caps.
+ * @caps: New caps.
+ *
+ * Setcaps function for subtitle sink pad.
+ *
+ * Returns: %TRUE on success.
+ */
+static gboolean
+gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
+{
+  /* There is now (at least) one such alement (kateenc), and I'm going
+     to handle it here and claim it works when it can be piped back
+     through GStreamer and VLC */
+
+  GstMatroskaTrackContext *context = NULL;
+  GstMatroskaTrackSubtitleContext *scontext;
+  GstMatroskaMux *mux;
+  GstMatroskaPad *collect_pad;
+  const gchar *mimetype;
+  GstStructure *structure;
+  const GValue *value = NULL;
+  GstBuffer *buf = NULL;
+  gboolean ret = TRUE;
+
+  mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
+
+  /* find context */
+  collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
+  g_assert (collect_pad);
+  context = collect_pad->track;
+  g_assert (context);
+  g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
+  scontext = (GstMatroskaTrackSubtitleContext *) context;
+
+  structure = gst_caps_get_structure (caps, 0);
+  mimetype = gst_structure_get_name (structure);
+
+  /* general setup */
+  scontext->check_utf8 = 1;
+  scontext->invalid_utf8 = 0;
+  context->default_duration = 0;
+
+  if (!strcmp (mimetype, "subtitle/x-kate")) {
+    const GValue *streamheader;
+
+    gst_matroska_mux_set_codec_id (context,
+        GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
+
+    gst_matroska_mux_free_codec_priv (context);
+
+    streamheader = gst_structure_get_value (structure, "streamheader");
+    if (!kate_streamheader_to_codecdata (streamheader, context)) {
+      GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
+          ("kate stream headers missing or malformed"));
+      ret = FALSE;
+      goto exit;
+    }
+  } else if (!strcmp (mimetype, "text/x-raw")) {
+    gst_matroska_mux_set_codec_id (context,
+        GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8);
+  } else if (!strcmp (mimetype, "application/x-ssa")) {
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_SSA);
+  } else if (!strcmp (mimetype, "application/x-ass")) {
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_ASS);
+  } else if (!strcmp (mimetype, "application/x-usf")) {
+    gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_USF);
+  } else if (!strcmp (mimetype, "subpicture/x-dvd")) {
+    gst_matroska_mux_set_codec_id (context,
+        GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB);
+  } else {
+    ret = FALSE;
+    goto exit;
+  }
+
+  /* maybe some private data, e.g. vobsub */
+  value = gst_structure_get_value (structure, "codec_data");
+  if (value)
+    buf = gst_value_get_buffer (value);
+  if (buf != NULL) {
+    GstMapInfo map;
+    guint8 *priv_data = NULL;
+
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+
+    if (map.size > SUBTITLE_MAX_CODEC_PRIVATE) {
+      GST_WARNING_OBJECT (mux, "pad %" GST_PTR_FORMAT " subtitle private data"
+          " exceeded maximum (%d); discarding", pad,
+          SUBTITLE_MAX_CODEC_PRIVATE);
+      gst_buffer_unmap (buf, &map);
+      return TRUE;
+    }
+
+    gst_matroska_mux_free_codec_priv (context);
+
+    priv_data = g_malloc0 (map.size);
+    memcpy (priv_data, map.data, map.size);
+    context->codec_priv = priv_data;
+    context->codec_priv_size = map.size;
+    gst_buffer_unmap (buf, &map);
+  }
+
+  GST_DEBUG_OBJECT (pad, "codec_id %s, codec data size %" G_GSIZE_FORMAT,
+      GST_STR_NULL (context->codec_id), context->codec_priv_size);
+
+exit:
+
+  return ret;
+}
+
+
+/**
+ * gst_matroska_mux_request_new_pad:
+ * @element: #GstMatroskaMux.
+ * @templ: #GstPadTemplate.
+ * @pad_name: New pad name.
+ *
+ * Request pad function for sink templates.
+ *
+ * Returns: New #GstPad.
+ */
+static GstPad *
+gst_matroska_mux_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
+  GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
+  GstMatroskaPad *collect_pad;
+  GstMatroskamuxPad *newpad;
+  gchar *name = NULL;
+  const gchar *pad_name = NULL;
+  GstMatroskaCapsFunc capsfunc = NULL;
+  GstMatroskaTrackContext *context = NULL;
+  gint pad_id;
+  gboolean locked = TRUE;
+  const gchar *id = NULL;
+
+  if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
+    /* don't mix named and unnamed pads, if the pad already exists we fail when
+     * trying to add it */
+    if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
+      pad_name = req_name;
+    } else {
+      name = g_strdup_printf ("audio_%u", mux->num_a_streams++);
+      pad_name = name;
+    }
+    capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
+    context = (GstMatroskaTrackContext *)
+        g_new0 (GstMatroskaTrackAudioContext, 1);
+    context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
+    context->name = g_strdup ("Audio");
+  } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
+    /* don't mix named and unnamed pads, if the pad already exists we fail when
+     * trying to add it */
+    if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) {
+      pad_name = req_name;
+    } else {
+      name = g_strdup_printf ("video_%u", mux->num_v_streams++);
+      pad_name = name;
+    }
+    capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
+    context = (GstMatroskaTrackContext *)
+        g_new0 (GstMatroskaTrackVideoContext, 1);
+    context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
+    context->name = g_strdup ("Video");
+  } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%u")) {
+    /* don't mix named and unnamed pads, if the pad already exists we fail when
+     * trying to add it */
+    if (req_name != NULL && sscanf (req_name, "subtitle_%u", &pad_id) == 1) {
+      pad_name = req_name;
+    } else {
+      name = g_strdup_printf ("subtitle_%u", mux->num_t_streams++);
+      pad_name = name;
+    }
+    capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
+    context = (GstMatroskaTrackContext *)
+        g_new0 (GstMatroskaTrackSubtitleContext, 1);
+    context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
+    context->name = g_strdup ("Subtitle");
+    /* setcaps may only provide proper one a lot later */
+    id = "S_SUB_UNKNOWN";
+    locked = FALSE;
+  } else {
+    GST_WARNING_OBJECT (mux, "This is not our template!");
+    return NULL;
+  }
+
+  newpad = g_object_new (GST_TYPE_MATROSKAMUX_PAD,
+      "name", pad_name, "direction", templ->direction, "template", templ, NULL);
+
+  gst_matroskamux_pad_init (newpad);
+  collect_pad = (GstMatroskaPad *)
+      gst_collect_pads_add_pad (mux->collect, GST_PAD (newpad),
+      sizeof (GstMatroskamuxPad),
+      (GstCollectDataDestroyNotify) gst_matroska_pad_free, locked);
+
+  collect_pad->mux = mux;
+  collect_pad->track = context;
+  gst_matroska_pad_reset (collect_pad, FALSE);
+  if (id)
+    gst_matroska_mux_set_codec_id (collect_pad->track, id);
+  collect_pad->track->dts_only = FALSE;
+
+  collect_pad->capsfunc = capsfunc;
+  gst_pad_set_active (GST_PAD (newpad), TRUE);
+  if (!gst_element_add_pad (element, GST_PAD (newpad)))
+    goto pad_add_failed;
+
+  g_free (name);
+
+  mux->num_streams++;
+
+  GST_DEBUG_OBJECT (newpad, "Added new request pad");
+
+  return GST_PAD (newpad);
+
+  /* ERROR cases */
+pad_add_failed:
+  {
+    GST_WARNING_OBJECT (mux, "Adding the new pad '%s' failed", pad_name);
+    g_free (name);
+    gst_object_unref (newpad);
+    return NULL;
+  }
+}
+
+/**
+ * gst_matroska_mux_release_pad:
+ * @element: #GstMatroskaMux.
+ * @pad: Pad to release.
+ *
+ * Release a previously requested pad.
+*/
+static void
+gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
+{
+  GstMatroskaMux *mux;
+  GSList *walk;
+
+  mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
+
+  for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
+    GstCollectData *cdata = (GstCollectData *) walk->data;
+    GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
+
+    if (cdata->pad == pad) {
+      /*
+       * observed duration, this will remain GST_CLOCK_TIME_NONE
+       * only if the pad is resetted 
+       */
+      GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
+
+      if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
+          GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
+        collected_duration =
+            GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
+      }
+
+      if (GST_CLOCK_TIME_IS_VALID (collected_duration)
+          && mux->duration < collected_duration)
+        mux->duration = collected_duration;
+
+      break;
+    }
+  }
+
+  gst_collect_pads_remove_pad (mux->collect, pad);
+  if (gst_element_remove_pad (element, pad))
+    mux->num_streams--;
+}
+
+
+/**
+ * gst_matroska_mux_track_header:
+ * @mux: #GstMatroskaMux
+ * @context: Tack context.
+ *
+ * Write a track header.
+ */
+static void
+gst_matroska_mux_track_header (GstMatroskaMux * mux,
+    GstMatroskaTrackContext * context)
+{
+  GstEbmlWrite *ebml = mux->ebml_write;
+  guint64 master;
+
+  /* TODO: check if everything necessary is written and check default values */
+
+  /* track type goes before the type-specific stuff */
+  gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num);
+  gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
+
+  gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID, context->uid);
+  if (context->default_duration) {
+    gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
+        context->default_duration);
+  }
+  if (context->language) {
+    gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
+        context->language);
+  }
+
+  /* FIXME: until we have a nice way of getting the codecname
+   * out of the caps, I'm not going to enable this. Too much
+   * (useless, double, boring) work... */
+  /* TODO: Use value from tags if any */
+  /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
+     context->codec_name); */
+  gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
+
+  /* type-specific stuff */
+  switch (context->type) {
+    case GST_MATROSKA_TRACK_TYPE_VIDEO:{
+      GstMatroskaTrackVideoContext *videocontext =
+          (GstMatroskaTrackVideoContext *) context;
+
+      master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKVIDEO);
+      gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELWIDTH,
+          videocontext->pixel_width);
+      gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPIXELHEIGHT,
+          videocontext->pixel_height);
+      if (videocontext->display_width && videocontext->display_height) {
+        gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYWIDTH,
+            videocontext->display_width);
+        gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEODISPLAYHEIGHT,
+            videocontext->display_height);
+      }
+      if (context->flags & GST_MATROSKA_VIDEOTRACK_INTERLACED)
+        gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOFLAGINTERLACED, 1);
+      if (videocontext->fourcc) {
+        guint32 fcc_le = GUINT32_TO_LE (videocontext->fourcc);
+
+        gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
+            (gpointer) & fcc_le, 4);
+      }
+      if (videocontext->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
+        guint64 stereo_mode = 0;
+
+        switch (videocontext->multiview_mode) {
+          case GST_VIDEO_MULTIVIEW_MODE_MONO:
+            break;
+          case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
+            if (videocontext->multiview_flags &
+                GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
+              stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_RL;
+            else
+              stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_LR;
+            break;
+          case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
+            if (videocontext->multiview_flags &
+                GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
+              stereo_mode = GST_MATROSKA_STEREO_MODE_TB_RL;
+            else
+              stereo_mode = GST_MATROSKA_STEREO_MODE_TB_LR;
+            break;
+          case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
+            if (videocontext->multiview_flags &
+                GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
+              stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_RL;
+            else
+              stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_LR;
+            break;
+          case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
+            if (videocontext->multiview_flags &
+                GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
+              stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_RL;
+            else
+              stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_LR;
+            /* FIXME: In frame-by-frame mode, left/right frame buffers need to be
+             * laced within one block. See http://www.matroska.org/technical/specs/index.html#StereoMode */
+            GST_FIXME_OBJECT (mux,
+                "Frame-by-frame stereoscopic mode not fully implemented");
+            break;
+          default:
+            GST_WARNING_OBJECT (mux,
+                "Multiview mode %d not supported in Matroska/WebM",
+                videocontext->multiview_mode);
+            break;
+        }
+
+        if (stereo_mode != 0)
+          gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOSTEREOMODE,
+              stereo_mode);
+      }
+      gst_ebml_write_master_finish (ebml, master);
+
+      break;
+    }
+
+    case GST_MATROSKA_TRACK_TYPE_AUDIO:{
+      GstMatroskaTrackAudioContext *audiocontext =
+          (GstMatroskaTrackAudioContext *) context;
+
+      master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKAUDIO);
+      if (audiocontext->samplerate != 8000)
+        gst_ebml_write_float (ebml, GST_MATROSKA_ID_AUDIOSAMPLINGFREQ,
+            audiocontext->samplerate);
+      if (audiocontext->channels != 1)
+        gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOCHANNELS,
+            audiocontext->channels);
+      if (audiocontext->bitdepth) {
+        gst_ebml_write_uint (ebml, GST_MATROSKA_ID_AUDIOBITDEPTH,
+            audiocontext->bitdepth);
+      }
+
+      gst_ebml_write_master_finish (ebml, master);
+
+      break;
+    }
+
+    case GST_MATROSKA_TRACK_TYPE_SUBTITLE:{
+      break;
+    }
+    default:
+      /* doesn't need type-specific data */
+      break;
+  }
+
+  gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id);
+  if (context->codec_priv)
+    gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
+        context->codec_priv, context->codec_priv_size);
+
+  if (context->seek_preroll) {
+    gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPREROLL,
+        context->seek_preroll);
+  }
+
+  if (context->codec_delay) {
+    gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CODECDELAY,
+        context->codec_delay);
+  }
+}
+
+static void
+gst_matroska_mux_write_chapter_title (const gchar * title, GstEbmlWrite * ebml)
+{
+  guint64 title_master;
+
+  title_master =
+      gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERDISPLAY);
+
+  gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPSTRING, title);
+  gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CHAPLANGUAGE,
+      GST_MATROSKA_MUX_CHAPLANG);
+
+  gst_ebml_write_master_finish (ebml, title_master);
+}
+
+static GstTocEntry *
+gst_matroska_mux_write_chapter (GstMatroskaMux * mux, GstTocEntry * edition,
+    GstTocEntry * entry, GstEbmlWrite * ebml, guint64 * master_chapters,
+    guint64 * master_edition)
+{
+  guint64 master_chapteratom;
+  GList *cur;
+  guint count, i;
+  gchar *title;
+  gint64 start, stop;
+  guint64 uid;
+  gchar s_uid[32];
+  GstTocEntry *internal_chapter, *internal_nested;
+  GstTagList *tags;
+
+  if (G_UNLIKELY (master_chapters != NULL && *master_chapters == 0))
+    *master_chapters =
+        gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERS);
+
+  if (G_UNLIKELY (master_edition != NULL && *master_edition == 0)) {
+    /* create uid for the parent */
+    *master_edition =
+        gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_EDITIONENTRY);
+
+    gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONUID,
+        g_ascii_strtoull (gst_toc_entry_get_uid (edition), NULL, 10));
+    gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGHIDDEN, 0);
+    gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGDEFAULT, 0);
+    gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGORDERED, 0);
+  }
+
+  gst_toc_entry_get_start_stop_times (entry, &start, &stop);
+  tags = gst_toc_entry_get_tags (entry);
+  if (tags != NULL) {
+    tags = gst_tag_list_copy (tags);
+  }
+
+  /* build internal chapter */
+  uid = gst_matroska_mux_create_uid (mux);
+  g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT, uid);
+  internal_chapter = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, s_uid);
+
+  /* Write the chapter entry */
+  master_chapteratom =
+      gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERATOM);
+
+  gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERUID, uid);
+  /* Store the user provided UID in the ChapterStringUID */
+  gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPTERSTRINGUID,
+      gst_toc_entry_get_uid (entry));
+  gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTART, start);
+  gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTOP, stop);
+  gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGHIDDEN, 0);
+  gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGENABLED, 1);
+
+  /* write current ChapterDisplays before the nested chapters */
+  if (G_LIKELY (tags != NULL)) {
+    count = gst_tag_list_get_tag_size (tags, GST_TAG_TITLE);
+
+    for (i = 0; i < count; ++i) {
+      gst_tag_list_get_string_index (tags, GST_TAG_TITLE, i, &title);
+      /* FIXME: handle ChapterLanguage entries */
+      gst_matroska_mux_write_chapter_title (title, ebml);
+      g_free (title);
+    }
+
+    /* remove title tag */
+    if (G_LIKELY (count > 0))
+      gst_tag_list_remove_tag (tags, GST_TAG_TITLE);
+
+    gst_toc_entry_set_tags (internal_chapter, tags);
+  }
+
+  /* Write nested chapters */
+  for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
+      cur = cur->next) {
+    internal_nested = gst_matroska_mux_write_chapter (mux, NULL, cur->data,
+        ebml, NULL, NULL);
+
+    gst_toc_entry_append_sub_entry (internal_chapter, internal_nested);
+  }
+
+  gst_ebml_write_master_finish (ebml, master_chapteratom);
+
+  return internal_chapter;
+}
+
+static GstTocEntry *
+gst_matroska_mux_write_chapter_edition (GstMatroskaMux * mux,
+    GstTocEntry * edition, GList * chapters, GstEbmlWrite * ebml,
+    guint64 * master_chapters)
+{
+  guint64 master_edition = 0;
+  gchar s_uid[32];
+  GList *cur;
+  GstTocEntry *internal_edition, *internal_chapter;
+  GstTagList *tags = NULL;
+
+  g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT,
+      gst_matroska_mux_create_uid (mux));
+
+  if (edition != NULL) {
+    /* Edition entry defined, get its tags */
+    tags = gst_toc_entry_get_tags (edition);
+    if (tags != NULL) {
+      tags = gst_tag_list_copy (tags);
+    }
+  }
+
+  internal_edition = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, s_uid);
+  if (tags != NULL) {
+    gst_toc_entry_set_tags (internal_edition, tags);
+  }
+
+  for (cur = g_list_first (chapters); cur != NULL; cur = cur->next) {
+    internal_chapter = gst_matroska_mux_write_chapter (mux, internal_edition,
+        cur->data, ebml, master_chapters, &master_edition);
+
+    gst_toc_entry_append_sub_entry (internal_edition, internal_chapter);
+  }
+
+  if (G_LIKELY (master_edition != 0))
+    gst_ebml_write_master_finish (ebml, master_edition);
+
+  return internal_edition;
+}
+
+/**
+ * gst_matroska_mux_start:
+ * @mux: #GstMatroskaMux
+ *
+ * Start a new matroska file (write headers etc...)
+ */
+static void
+gst_matroska_mux_start (GstMatroskaMux * mux, GstMatroskaPad * first_pad,
+    GstBuffer * first_pad_buf)
+{
+  GstEbmlWrite *ebml = mux->ebml_write;
+  const gchar *doctype;
+  guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
+    GST_MATROSKA_ID_TRACKS,
+    GST_MATROSKA_ID_CHAPTERS,
+    GST_MATROSKA_ID_CUES,
+    GST_MATROSKA_ID_TAGS,
+    0
+  };
+  const gchar *media_type;
+  gboolean audio_only;
+  guint64 master, child;
+  GSList *collected;
+  int i;
+  guint tracknum = 1;
+  GstClockTime duration = 0;
+  guint32 segment_uid[4];
+  GTimeVal time = { 0, 0 };
+  gchar s_id[32];
+  GstToc *toc;
+
+  /* if not streaming, check if downstream is seekable */
+  if (!mux->ebml_write->streamable) {
+    gboolean seekable;
+    GstQuery *query;
+
+    query = gst_query_new_seeking (GST_FORMAT_BYTES);
+    if (gst_pad_peer_query (mux->srcpad, query)) {
+      gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
+      GST_INFO_OBJECT (mux, "downstream is %sseekable", seekable ? "" : "not ");
+    } else {
+      /* assume seeking is not supported if query not handled downstream */
+      GST_WARNING_OBJECT (mux, "downstream did not handle seeking query");
+      seekable = FALSE;
+    }
+    if (!seekable) {
+      mux->ebml_write->streamable = TRUE;
+      g_object_notify (G_OBJECT (mux), "streamable");
+      GST_WARNING_OBJECT (mux, "downstream is not seekable, but "
+          "streamable=false. Will ignore that and create streamable output "
+          "instead");
+    }
+    gst_query_unref (query);
+  }
+
+  /* stream-start (FIXME: create id based on input ids) */
+  g_snprintf (s_id, sizeof (s_id), "matroskamux-%08x", g_random_int ());
+  gst_pad_push_event (mux->srcpad, gst_event_new_stream_start (s_id));
+
+  /* output caps */
+  audio_only = mux->num_v_streams == 0 && mux->num_a_streams > 0;
+  if (mux->is_webm) {
+    media_type = (audio_only) ? "audio/webm" : "video/webm";
+  } else {
+    media_type = (audio_only) ? "audio/x-matroska" : "video/x-matroska";
+  }
+  ebml->caps = gst_caps_new_empty_simple (media_type);
+  gst_pad_set_caps (mux->srcpad, ebml->caps);
+  /* we start with a EBML header */
+  doctype = mux->doctype;
+  GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d",
+      doctype, mux->doctype_version);
+  gst_ebml_write_header (ebml, doctype, mux->doctype_version);
+
+  /* the rest of the header is cached */
+  gst_ebml_write_set_cache (ebml, 0x1000);
+
+  /* start a segment */
+  mux->segment_pos =
+      gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
+  mux->segment_master = ebml->pos;
+
+  if (!mux->ebml_write->streamable) {
+    /* seekhead (table of contents) - we set the positions later */
+    mux->seekhead_pos = ebml->pos;
+    master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
+    for (i = 0; seekhead_id[i] != 0; i++) {
+      child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKENTRY);
+      gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKID, seekhead_id[i]);
+      gst_ebml_write_uint (ebml, GST_MATROSKA_ID_SEEKPOSITION, -1);
+      gst_ebml_write_master_finish (ebml, child);
+    }
+    gst_ebml_write_master_finish (ebml, master);
+  }
+
+  if (mux->ebml_write->streamable) {
+    const GstTagList *tags;
+    gboolean has_main_tags;
+
+    /* tags */
+    tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
+    has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
+
+    if (has_main_tags || gst_matroska_mux_streams_have_tags (mux)) {
+      guint64 master_tags, master_tag;
+
+      GST_DEBUG_OBJECT (mux, "Writing tags");
+
+      mux->tags_pos = ebml->pos;
+      master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
+      if (has_main_tags) {
+        master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
+        gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
+        gst_ebml_write_master_finish (ebml, master_tag);
+      }
+      gst_matroska_mux_write_streams_tags (mux);
+      gst_ebml_write_master_finish (ebml, master_tags);
+    }
+  }
+
+  /* segment info */
+  mux->info_pos = ebml->pos;
+  master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO);
+
+  /* WebM does not support SegmentUID field on SegmentInfo */
+  if (!mux->is_webm) {
+    for (i = 0; i < 4; i++) {
+      segment_uid[i] = g_random_int ();
+    }
+    gst_ebml_write_binary (ebml, GST_MATROSKA_ID_SEGMENTUID,
+        (guint8 *) segment_uid, 16);
+  }
+
+  gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale);
+  mux->duration_pos = ebml->pos;
+  /* get duration */
+  if (!mux->ebml_write->streamable) {
+    for (collected = mux->collect->data; collected;
+        collected = g_slist_next (collected)) {
+      GstMatroskaPad *collect_pad;
+      GstPad *thepad;
+      gint64 trackduration;
+
+      collect_pad = (GstMatroskaPad *) collected->data;
+      thepad = collect_pad->collect.pad;
+
+      /* Query the total length of the track. */
+      GST_DEBUG_OBJECT (thepad, "querying peer duration");
+      if (gst_pad_peer_query_duration (thepad, GST_FORMAT_TIME, &trackduration)) {
+        GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (trackduration));
+        if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
+          duration = (GstClockTime) trackduration;
+        }
+      }
+    }
+    gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
+        gst_guint64_to_gdouble (duration) /
+        gst_guint64_to_gdouble (mux->time_scale));
+  }
+  gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP,
+      "GStreamer matroskamux version " PACKAGE_VERSION);
+  if (mux->writing_app && mux->writing_app[0]) {
+    gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_WRITINGAPP, mux->writing_app);
+  }
+  g_get_current_time (&time);
+  gst_ebml_write_date (ebml, GST_MATROSKA_ID_DATEUTC, time.tv_sec);
+  gst_ebml_write_master_finish (ebml, master);
+
+  /* tracks */
+  mux->tracks_pos = ebml->pos;
+  master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKS);
+
+  for (collected = mux->collect->data; collected;
+      collected = g_slist_next (collected)) {
+    GstMatroskaPad *collect_pad;
+    GstBuffer *buf;
+
+    collect_pad = (GstMatroskaPad *) collected->data;
+
+    /* This will cause an error at a later time */
+    if (collect_pad->track->codec_id == NULL)
+      continue;
+
+    /* For audio tracks, use the first buffers duration as the default
+     * duration if we didn't get any better idea from the caps event already
+     */
+    if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO &&
+        collect_pad->track->default_duration == 0) {
+      if (collect_pad == first_pad)
+        buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
+      else
+        buf = gst_collect_pads_peek (mux->collect, collected->data);
+
+      if (buf && GST_BUFFER_DURATION_IS_VALID (buf))
+        collect_pad->track->default_duration =
+            GST_BUFFER_DURATION (buf) + collect_pad->track->codec_delay;
+      if (buf)
+        gst_buffer_unref (buf);
+    }
+
+    collect_pad->track->num = tracknum++;
+    child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
+    gst_matroska_mux_track_header (mux, collect_pad->track);
+    gst_ebml_write_master_finish (ebml, child);
+    /* some remaining pad/track setup */
+    collect_pad->default_duration_scaled =
+        gst_util_uint64_scale (collect_pad->track->default_duration,
+        1, mux->time_scale);
+  }
+  gst_ebml_write_master_finish (ebml, master);
+
+  /* chapters */
+  toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
+  if (toc != NULL && !mux->ebml_write->streamable) {
+    guint64 master_chapters = 0;
+    GstTocEntry *internal_edition;
+    GList *cur, *chapters;
+
+    GST_DEBUG ("Writing chapters");
+
+    /* There are two UIDs for Chapters:
+     * - The ChapterUID is a mandatory unsigned integer which internally
+     * refers to a given chapter. Except for the title & language which use
+     * dedicated fields, this UID can also be used to add tags to the Chapter.
+     * The tags come in a separate section of the container.
+     * - The ChapterStringUID is an optional UTF-8 string which also uniquely
+     * refers to a chapter but from an external perspective. It can act as a
+     * "WebVTT cue identifier" which "can be used to reference a specific cue,
+     * for example from script or CSS".
+     *
+     * The ChapterUID will be generated and checked for unicity, while the
+     * ChapterStringUID will receive the user defined UID.
+     *
+     * In order to be able to refer to chapters from the tags section,
+     * we must maintain an internal Toc tree with the generated ChapterUID
+     * (see gst_matroska_mux_write_toc_entry_tags) */
+
+    /* Check whether we have editions or chapters at the root level. */
+    cur = gst_toc_get_entries (toc);
+    if (cur != NULL) {
+      mux->chapters_pos = ebml->pos;
+
+      mux->internal_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
+
+      if (gst_toc_entry_get_entry_type (cur->data) ==
+          GST_TOC_ENTRY_TYPE_EDITION) {
+        /* Editions at the root level */
+        for (; cur != NULL; cur = cur->next) {
+          chapters = gst_toc_entry_get_sub_entries (cur->data);
+          internal_edition = gst_matroska_mux_write_chapter_edition (mux,
+              cur->data, chapters, ebml, &master_chapters);
+          gst_toc_append_entry (mux->internal_toc, internal_edition);
+        }
+      } else {
+        /* Chapters at the root level */
+        internal_edition = gst_matroska_mux_write_chapter_edition (mux,
+            NULL, cur, ebml, &master_chapters);
+        gst_toc_append_entry (mux->internal_toc, internal_edition);
+      }
+
+      /* close master element if any edition was written */
+      if (G_LIKELY (master_chapters != 0))
+        gst_ebml_write_master_finish (ebml, master_chapters);
+    }
+  }
+
+  /* lastly, flush the cache */
+  gst_ebml_write_flush_cache (ebml, FALSE, 0);
+
+  if (toc != NULL)
+    gst_toc_unref (toc);
+}
+
+/* TODO: more sensible tag mappings */
+static const struct
+{
+  const gchar *matroska_tagname;
+  const gchar *gstreamer_tagname;
+}
+gst_matroska_tag_conv[] = {
+  {
+  GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
+  GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
+  GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
+  GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
+  GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
+  GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
+  GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
+  GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
+  GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
+  GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
+  GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
+  GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
+  GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
+  GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
+  GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
+};
+
+/* Every stagefright implementation on android up to and including 6.0.1 is using
+ libwebm with bug in matroska parsing, where it will choke on empty tag elements;
+ so before outputting tags and tag elements we better make sure that there are
+ actually tags we are going to write */
+static gboolean
+gst_matroska_mux_tag_list_is_empty (const GstTagList * list)
+{
+  int i;
+  for (i = 0; i < gst_tag_list_n_tags (list); i++) {
+    const gchar *tag = gst_tag_list_nth_tag_name (list, i);
+    int i;
+    for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
+      const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
+      if (strcmp (tagname_gst, tag) == 0) {
+        GValue src = { 0, };
+        gchar *dest;
+
+        if (!gst_tag_list_copy_value (&src, list, tag))
+          break;
+        dest = gst_value_serialize (&src);
+
+        g_value_unset (&src);
+        if (dest) {
+          g_free (dest);
+          return FALSE;
+        }
+      }
+    }
+  }
+  return TRUE;
+}
+
+static void
+gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
+    gpointer data)
+{
+  GstEbmlWrite *ebml = (GstEbmlWrite *) data;
+  guint i;
+  guint64 simpletag_master;
+
+  for (i = 0; i < G_N_ELEMENTS (gst_matroska_tag_conv); i++) {
+    const gchar *tagname_gst = gst_matroska_tag_conv[i].gstreamer_tagname;
+    const gchar *tagname_mkv = gst_matroska_tag_conv[i].matroska_tagname;
+
+    if (strcmp (tagname_gst, tag) == 0) {
+      GValue src = { 0, };
+      gchar *dest;
+
+      if (!gst_tag_list_copy_value (&src, list, tag))
+        break;
+      if ((dest = gst_value_serialize (&src))) {
+
+        simpletag_master = gst_ebml_write_master_start (ebml,
+            GST_MATROSKA_ID_SIMPLETAG);
+        gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_TAGNAME, tagname_mkv);
+        gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TAGSTRING, dest);
+        gst_ebml_write_master_finish (ebml, simpletag_master);
+        g_free (dest);
+      } else {
+        GST_WARNING ("Can't transform tag '%s' to string", tagname_mkv);
+      }
+      g_value_unset (&src);
+      break;
+    }
+  }
+}
+
+static void
+gst_matroska_mux_write_stream_tags (GstMatroskaMux * mux, GstMatroskaPad * mpad)
+{
+  guint64 master_tag, master_targets;
+  GstEbmlWrite *ebml;
+
+  ebml = mux->ebml_write;
+
+  if (G_UNLIKELY (mpad->tags == NULL
+          || gst_matroska_mux_tag_list_is_empty (mpad->tags)))
+    return;
+
+  master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
+  master_targets = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
+
+  gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETTRACKUID, mpad->track->uid);
+
+  gst_ebml_write_master_finish (ebml, master_targets);
+  gst_tag_list_foreach (mpad->tags, gst_matroska_mux_write_simple_tag, ebml);
+  gst_ebml_write_master_finish (ebml, master_tag);
+}
+
+static void
+gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux)
+{
+  GSList *walk;
+
+  for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
+    GstMatroskaPad *collect_pad;
+
+    collect_pad = (GstMatroskaPad *) walk->data;
+
+    gst_matroska_mux_write_stream_tags (mux, collect_pad);
+  }
+}
+
+static gboolean
+gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux)
+{
+  GSList *walk;
+
+  for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
+    GstMatroskaPad *collect_pad;
+
+    collect_pad = (GstMatroskaPad *) walk->data;
+    if (!gst_matroska_mux_tag_list_is_empty (collect_pad->tags))
+      return TRUE;
+  }
+  return FALSE;
+}
+
+static void
+gst_matroska_mux_write_toc_entry_tags (GstMatroskaMux * mux,
+    const GstTocEntry * entry, guint64 * master_tags, gboolean * has_tags)
+{
+  guint64 master_tag, master_targets;
+  GstEbmlWrite *ebml;
+  GList *cur;
+  const GstTagList *tags;
+
+  ebml = mux->ebml_write;
+
+  tags = gst_toc_entry_get_tags (entry);
+  if (G_UNLIKELY (tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags))) {
+    *has_tags = TRUE;
+
+    if (*master_tags == 0) {
+      mux->tags_pos = ebml->pos;
+      *master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
+    }
+
+    master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
+    master_targets =
+        gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
+
+    if (gst_toc_entry_get_entry_type (entry) == GST_TOC_ENTRY_TYPE_EDITION)
+      gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETEDITIONUID,
+          g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
+    else
+      gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETCHAPTERUID,
+          g_ascii_strtoull (gst_toc_entry_get_uid (entry), NULL, 10));
+
+    gst_ebml_write_master_finish (ebml, master_targets);
+    gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
+    gst_ebml_write_master_finish (ebml, master_tag);
+  }
+
+  for (cur = gst_toc_entry_get_sub_entries (entry); cur != NULL;
+      cur = cur->next) {
+    gst_matroska_mux_write_toc_entry_tags (mux, cur->data, master_tags,
+        has_tags);
+  }
+}
+
+/**
+ * gst_matroska_mux_finish:
+ * @mux: #GstMatroskaMux
+ *
+ * Finish a new matroska file (write index etc...)
+ */
+static void
+gst_matroska_mux_finish (GstMatroskaMux * mux)
+{
+  GstEbmlWrite *ebml = mux->ebml_write;
+  guint64 pos;
+  guint64 duration = 0;
+  GSList *collected;
+  const GstTagList *tags, *toc_tags;
+  const GstToc *toc;
+  gboolean has_main_tags, toc_has_tags = FALSE;
+  GList *cur;
+
+  /* finish last cluster */
+  if (mux->cluster) {
+    gst_ebml_write_master_finish (ebml, mux->cluster);
+  }
+
+  /* cues */
+  if (mux->index != NULL) {
+    guint n;
+    guint64 master, pointentry_master, trackpos_master;
+
+    mux->cues_pos = ebml->pos;
+    gst_ebml_write_set_cache (ebml, 12 + 41 * mux->num_indexes);
+    master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CUES);
+
+    for (n = 0; n < mux->num_indexes; n++) {
+      GstMatroskaIndex *idx = &mux->index[n];
+
+      pointentry_master = gst_ebml_write_master_start (ebml,
+          GST_MATROSKA_ID_POINTENTRY);
+      gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME,
+          idx->time / mux->time_scale);
+      trackpos_master = gst_ebml_write_master_start (ebml,
+          GST_MATROSKA_ID_CUETRACKPOSITIONS);
+      gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track);
+      gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION,
+          idx->pos - mux->segment_master);
+      gst_ebml_write_master_finish (ebml, trackpos_master);
+      gst_ebml_write_master_finish (ebml, pointentry_master);
+    }
+
+    gst_ebml_write_master_finish (ebml, master);
+    gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
+  }
+
+  /* tags */
+  tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
+  has_main_tags = tags != NULL && !gst_matroska_mux_tag_list_is_empty (tags);
+  toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
+
+  if (has_main_tags || gst_matroska_mux_streams_have_tags (mux) || toc != NULL) {
+    guint64 master_tags = 0, master_tag;
+
+    GST_DEBUG_OBJECT (mux, "Writing tags");
+
+    if (has_main_tags) {
+      /* TODO: maybe limit via the TARGETS id by looking at the source pad */
+      mux->tags_pos = ebml->pos;
+      master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
+      master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
+
+      if (tags != NULL)
+        gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
+      if (mux->internal_toc != NULL) {
+        toc_tags = gst_toc_get_tags (mux->internal_toc);
+        toc_has_tags = (toc_tags != NULL);
+        gst_tag_list_foreach (toc_tags, gst_matroska_mux_write_simple_tag,
+            ebml);
+      }
+
+      gst_ebml_write_master_finish (ebml, master_tag);
+    }
+
+    if (mux->internal_toc != NULL) {
+      for (cur = gst_toc_get_entries (mux->internal_toc); cur != NULL;
+          cur = cur->next) {
+        gst_matroska_mux_write_toc_entry_tags (mux, cur->data, &master_tags,
+            &toc_has_tags);
+      }
+    }
+
+    if (master_tags == 0 && gst_matroska_mux_streams_have_tags (mux)) {
+      mux->tags_pos = ebml->pos;
+      master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
+    }
+    gst_matroska_mux_write_streams_tags (mux);
+
+    if (master_tags != 0)
+      gst_ebml_write_master_finish (ebml, master_tags);
+  }
+
+  /* update seekhead. We know that:
+   * - a seekhead contains 5 entries.
+   * - order of entries is as above.
+   * - a seekhead has a 4-byte header + 8-byte length
+   * - each entry is 2-byte master, 2-byte ID pointer,
+   *     2-byte length pointer, all 8/1-byte length, 4-
+   *     byte ID and 8-byte length pointer, where the
+   *     length pointer starts at 20.
+   * - all entries are local to the segment (so pos - segment_master).
+   * - so each entry is at 12 + 20 + num * 28. */
+  gst_ebml_replace_uint (ebml, mux->seekhead_pos + 32,
+      mux->info_pos - mux->segment_master);
+  gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
+      mux->tracks_pos - mux->segment_master);
+  if (toc != NULL && mux->chapters_pos > 0) {
+    gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
+        mux->chapters_pos - mux->segment_master);
+  } else {
+    /* void'ify */
+    guint64 my_pos = ebml->pos;
+
+    gst_ebml_write_seek (ebml, mux->seekhead_pos + 68);
+    gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
+    gst_ebml_write_seek (ebml, my_pos);
+  }
+  if (mux->index != NULL) {
+    gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
+        mux->cues_pos - mux->segment_master);
+  } else {
+    /* void'ify */
+    guint64 my_pos = ebml->pos;
+
+    gst_ebml_write_seek (ebml, mux->seekhead_pos + 96);
+    gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
+    gst_ebml_write_seek (ebml, my_pos);
+  }
+
+  if (tags != NULL || toc_has_tags) {
+    gst_ebml_replace_uint (ebml, mux->seekhead_pos + 144,
+        mux->tags_pos - mux->segment_master);
+  } else {
+    /* void'ify */
+    guint64 my_pos = ebml->pos;
+
+    gst_ebml_write_seek (ebml, mux->seekhead_pos + 124);
+    gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
+    gst_ebml_write_seek (ebml, my_pos);
+  }
+
+  if (toc != NULL) {
+    gst_toc_unref (toc);
+  }
+
+  /* loop tracks:
+   * - first get the overall duration
+   *   (a released track may have left a duration in here)
+   * - write some track header data for subtitles
+   */
+  duration = mux->duration;
+  pos = ebml->pos;
+  for (collected = mux->collect->data; collected;
+      collected = g_slist_next (collected)) {
+    GstMatroskaPad *collect_pad;
+    /*
+     * observed duration, this will never remain GST_CLOCK_TIME_NONE
+     * since this means buffer without timestamps that is not possibile
+     */
+    GstClockTime collected_duration = GST_CLOCK_TIME_NONE;
+
+    collect_pad = (GstMatroskaPad *) collected->data;
+
+    GST_DEBUG_OBJECT (mux,
+        "Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
+        " end ts %" GST_TIME_FORMAT, collect_pad,
+        GST_TIME_ARGS (collect_pad->start_ts),
+        GST_TIME_ARGS (collect_pad->end_ts));
+
+    if (GST_CLOCK_TIME_IS_VALID (collect_pad->start_ts) &&
+        GST_CLOCK_TIME_IS_VALID (collect_pad->end_ts)) {
+      collected_duration =
+          GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
+      GST_DEBUG_OBJECT (collect_pad,
+          "final track duration: %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (collected_duration));
+    } else {
+      GST_WARNING_OBJECT (collect_pad, "unable to get final track duration");
+    }
+    if (GST_CLOCK_TIME_IS_VALID (collected_duration) &&
+        duration < collected_duration)
+      duration = collected_duration;
+
+  }
+
+  /* seek back (optional, but do anyway) */
+  gst_ebml_write_seek (ebml, pos);
+
+  /* update duration */
+  if (duration != 0) {
+    GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (duration));
+    pos = mux->ebml_write->pos;
+    gst_ebml_write_seek (ebml, mux->duration_pos);
+    gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
+        gst_guint64_to_gdouble (duration) /
+        gst_guint64_to_gdouble (mux->time_scale));
+    gst_ebml_write_seek (ebml, pos);
+  } else {
+    /* void'ify */
+    guint64 my_pos = ebml->pos;
+
+    gst_ebml_write_seek (ebml, mux->duration_pos);
+    gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8);
+    gst_ebml_write_seek (ebml, my_pos);
+  }
+  GST_DEBUG_OBJECT (mux, "finishing segment");
+  /* finish segment - this also writes element length */
+  gst_ebml_write_master_finish (ebml, mux->segment_pos);
+}
+
+/**
+ * gst_matroska_mux_buffer_header:
+ * @track: Track context.
+ * @relative_timestamp: relative timestamp of the buffer
+ * @flags: Buffer flags.
+ *
+ * Create a buffer containing buffer header.
+ *
+ * Returns: New buffer.
+ */
+static GstBuffer *
+gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
+    gint16 relative_timestamp, int flags)
+{
+  GstBuffer *hdr;
+  guint8 *data = g_malloc (4);
+
+  hdr = gst_buffer_new_wrapped (data, 4);
+  /* track num - FIXME: what if num >= 0x80 (unlikely)? */
+  data[0] = track->num | 0x80;
+  /* time relative to clustertime */
+  GST_WRITE_UINT16_BE (data + 1, relative_timestamp);
+
+  /* flags */
+  data[3] = flags;
+
+  return hdr;
+}
+
+#define DIRAC_PARSE_CODE_SEQUENCE_HEADER 0x00
+#define DIRAC_PARSE_CODE_END_OF_SEQUENCE 0x10
+#define DIRAC_PARSE_CODE_IS_PICTURE(x) ((x & 0x08) != 0)
+
+static GstBuffer *
+gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
+    GstMatroskaPad * collect_pad, GstBuffer * buf)
+{
+  GstMatroskaTrackVideoContext *ctx =
+      (GstMatroskaTrackVideoContext *) collect_pad->track;
+  GstMapInfo map;
+  guint8 *data;
+  gsize size;
+  guint8 parse_code;
+  guint32 next_parse_offset;
+  GstBuffer *ret = NULL;
+  gboolean is_muxing_unit = FALSE;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  data = map.data;
+  size = map.size;
+
+  if (size < 13) {
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    return ret;
+  }
+
+  /* Check if this buffer contains a picture or end-of-sequence packet */
+  while (size >= 13) {
+    if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
+      gst_buffer_unmap (buf, &map);
+      gst_buffer_unref (buf);
+      return ret;
+    }
+
+    parse_code = GST_READ_UINT8 (data + 4);
+    if (parse_code == DIRAC_PARSE_CODE_SEQUENCE_HEADER) {
+      if (ctx->dirac_unit) {
+        gst_buffer_unref (ctx->dirac_unit);
+        ctx->dirac_unit = NULL;
+      }
+    } else if (DIRAC_PARSE_CODE_IS_PICTURE (parse_code) ||
+        parse_code == DIRAC_PARSE_CODE_END_OF_SEQUENCE) {
+      is_muxing_unit = TRUE;
+      break;
+    }
+
+    next_parse_offset = GST_READ_UINT32_BE (data + 5);
+
+    if (G_UNLIKELY (next_parse_offset == 0 || next_parse_offset > size))
+      break;
+
+    data += next_parse_offset;
+    size -= next_parse_offset;
+  }
+
+  if (ctx->dirac_unit)
+    ctx->dirac_unit = gst_buffer_append (ctx->dirac_unit, gst_buffer_ref (buf));
+  else
+    ctx->dirac_unit = gst_buffer_ref (buf);
+
+  gst_buffer_unmap (buf, &map);
+
+  if (is_muxing_unit) {
+    ret = gst_buffer_make_writable (ctx->dirac_unit);
+    ctx->dirac_unit = NULL;
+    gst_buffer_copy_into (ret, buf,
+        GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+    gst_buffer_unref (buf);
+  } else {
+    gst_buffer_unref (buf);
+    ret = NULL;
+  }
+
+  return ret;
+}
+
+static void
+gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
+{
+  GstCaps *caps;
+  GstStructure *s;
+  GValue streamheader = { 0 };
+  GValue bufval = { 0 };
+  GstBuffer *streamheader_buffer;
+  GstEbmlWrite *ebml = mux->ebml_write;
+
+  streamheader_buffer = gst_ebml_stop_streamheader (ebml);
+  caps = gst_caps_copy (mux->ebml_write->caps);
+  s = gst_caps_get_structure (caps, 0);
+  g_value_init (&streamheader, GST_TYPE_ARRAY);
+  g_value_init (&bufval, GST_TYPE_BUFFER);
+  GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_HEADER);
+  gst_value_set_buffer (&bufval, streamheader_buffer);
+  gst_value_array_append_value (&streamheader, &bufval);
+  g_value_unset (&bufval);
+  gst_structure_set_value (s, "streamheader", &streamheader);
+  g_value_unset (&streamheader);
+  gst_caps_replace (&ebml->caps, caps);
+  gst_buffer_unref (streamheader_buffer);
+  gst_pad_set_caps (mux->srcpad, caps);
+  gst_caps_unref (caps);
+}
+
+/**
+ * gst_matroska_mux_write_data:
+ * @mux: #GstMatroskaMux
+ * @collect_pad: #GstMatroskaPad with the data
+ *
+ * Write collected data (called from gst_matroska_mux_collected).
+ *
+ * Returns: Result of the gst_pad_push issued to write the data.
+ */
+static GstFlowReturn
+gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad,
+    GstBuffer * buf)
+{
+  GstEbmlWrite *ebml = mux->ebml_write;
+  GstBuffer *hdr;
+  guint64 blockgroup;
+  gboolean write_duration;
+  gint16 relative_timestamp;
+  gint64 relative_timestamp64;
+  guint64 block_duration, duration_diff = 0;
+  gboolean is_video_keyframe = FALSE;
+  gboolean is_video_invisible = FALSE;
+  gboolean is_audio_only = FALSE;
+  gboolean is_min_duration_reached = FALSE;
+  gboolean is_max_duration_exceeded = FALSE;
+  GstMatroskamuxPad *pad;
+  gint flags = 0;
+  GstClockTime buffer_timestamp;
+  GstAudioClippingMeta *cmeta = NULL;
+
+  /* write data */
+  pad = GST_MATROSKAMUX_PAD_CAST (collect_pad->collect.pad);
+
+  /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
+  if (collect_pad->track->xiph_headers_to_skip > 0) {
+    --collect_pad->track->xiph_headers_to_skip;
+    if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER)) {
+      GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
+      gst_buffer_unref (buf);
+      return GST_FLOW_OK;
+    }
+  }
+
+  /* for dirac we have to queue up everything up to a picture unit */
+  if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC)) {
+    buf = gst_matroska_mux_handle_dirac_packet (mux, collect_pad, buf);
+    if (!buf)
+      return GST_FLOW_OK;
+  } else if (!strcmp (collect_pad->track->codec_id,
+          GST_MATROSKA_CODEC_ID_VIDEO_PRORES)) {
+    /* Remove the 'Frame container atom' header' */
+    buf = gst_buffer_make_writable (buf);
+    gst_buffer_resize (buf, 8, gst_buffer_get_size (buf) - 8);
+  }
+
+  buffer_timestamp =
+      gst_matroska_track_get_buffer_timestamp (collect_pad->track, buf);
+
+  /* hm, invalid timestamp (due to --to be fixed--- element upstream);
+   * this would wreak havoc with time stored in matroska file */
+  /* TODO: maybe calculate a timestamp by using the previous timestamp
+   * and default duration */
+  if (!GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
+    GST_WARNING_OBJECT (collect_pad->collect.pad,
+        "Invalid buffer timestamp; dropping buffer");
+    gst_buffer_unref (buf);
+    return GST_FLOW_OK;
+  }
+
+  if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
+      && collect_pad->track->codec_delay) {
+    /* All timestamps should include the codec delay */
+    if (buffer_timestamp > collect_pad->track->codec_delay) {
+      buffer_timestamp += collect_pad->track->codec_delay;
+    } else {
+      buffer_timestamp = 0;
+      duration_diff = collect_pad->track->codec_delay - buffer_timestamp;
+    }
+  }
+
+  /* set the timestamp for outgoing buffers */
+  ebml->timestamp = buffer_timestamp;
+
+  if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
+    if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
+      GST_LOG_OBJECT (mux, "have video keyframe, ts=%" GST_TIME_FORMAT,
+          GST_TIME_ARGS (buffer_timestamp));
+      is_video_keyframe = TRUE;
+    } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DECODE_ONLY) &&
+        (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VP8)
+            || !strcmp (collect_pad->track->codec_id,
+                GST_MATROSKA_CODEC_ID_VIDEO_VP9))) {
+      GST_LOG_OBJECT (mux,
+          "have VP8 video invisible frame, " "ts=%" GST_TIME_FORMAT,
+          GST_TIME_ARGS (buffer_timestamp));
+      is_video_invisible = TRUE;
+    }
+  }
+
+  is_audio_only = (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
+      (mux->num_streams == 1);
+  is_min_duration_reached = (mux->min_cluster_duration == 0
+      || (buffer_timestamp > mux->cluster_time
+          && (buffer_timestamp - mux->cluster_time) >=
+          mux->min_cluster_duration));
+  is_max_duration_exceeded = (mux->max_cluster_duration > 0
+      && buffer_timestamp > mux->cluster_time
+      && (buffer_timestamp - mux->cluster_time) >= mux->max_cluster_duration);
+
+  if (mux->cluster) {
+    /* start a new cluster at every keyframe, at every GstForceKeyUnit event,
+     * or when we may be reaching the limit of the relative timestamp */
+    if (is_max_duration_exceeded || (is_video_keyframe
+            && is_min_duration_reached) || mux->force_key_unit_event
+        || (is_audio_only && is_min_duration_reached)) {
+      if (!mux->ebml_write->streamable)
+        gst_ebml_write_master_finish (ebml, mux->cluster);
+
+      /* Forward the GstForceKeyUnit event after finishing the cluster */
+      if (mux->force_key_unit_event) {
+        gst_pad_push_event (mux->srcpad, mux->force_key_unit_event);
+        mux->force_key_unit_event = NULL;
+      }
+
+      mux->prev_cluster_size = ebml->pos - mux->cluster_pos;
+      mux->cluster_pos = ebml->pos;
+      gst_ebml_write_set_cache (ebml, 0x20);
+      mux->cluster =
+          gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
+      gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
+          gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale));
+      GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT,
+          gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale));
+      gst_ebml_write_flush_cache (ebml, TRUE, buffer_timestamp);
+      mux->cluster_time = buffer_timestamp;
+      gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE,
+          mux->prev_cluster_size);
+    }
+  } else {
+    /* first cluster */
+
+    mux->cluster_pos = ebml->pos;
+    gst_ebml_write_set_cache (ebml, 0x20);
+    mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER);
+    gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE,
+        gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale));
+    gst_ebml_write_flush_cache (ebml, TRUE, buffer_timestamp);
+    mux->cluster_time = buffer_timestamp;
+  }
+
+  /* We currently write index entries for all video tracks or for the audio
+   * track in a single-track audio file.  This could be improved by keeping the
+   * index only for the *first* video track. */
+
+  /* TODO: index is useful for every track, should contain the number of
+   * the block in the cluster which contains the timestamp, should also work
+   * for files with multiple audio tracks.
+   */
+  if (!mux->ebml_write->streamable && (is_video_keyframe || is_audio_only)) {
+    gint last_idx = -1;
+
+    if (mux->min_index_interval != 0) {
+      for (last_idx = mux->num_indexes - 1; last_idx >= 0; last_idx--) {
+        if (mux->index[last_idx].track == collect_pad->track->num)
+          break;
+      }
+    }
+
+    if (last_idx < 0 || mux->min_index_interval == 0 ||
+        (GST_CLOCK_DIFF (mux->index[last_idx].time, buffer_timestamp)
+            >= mux->min_index_interval)) {
+      GstMatroskaIndex *idx;
+
+      if (mux->num_indexes % 32 == 0) {
+        mux->index = g_renew (GstMatroskaIndex, mux->index,
+            mux->num_indexes + 32);
+      }
+      idx = &mux->index[mux->num_indexes++];
+
+      idx->pos = mux->cluster_pos;
+      idx->time = buffer_timestamp;
+      idx->track = collect_pad->track->num;
+    }
+  }
+
+  /* Check if the duration differs from the default duration. */
+  write_duration = FALSE;
+  block_duration = 0;
+  if (pad->frame_duration && GST_BUFFER_DURATION_IS_VALID (buf)) {
+    block_duration = GST_BUFFER_DURATION (buf) + duration_diff;
+    block_duration = gst_util_uint64_scale (block_duration, 1, mux->time_scale);
+
+    /* small difference should be ok. */
+    if (block_duration > collect_pad->default_duration_scaled + 1 ||
+        block_duration < collect_pad->default_duration_scaled - 1) {
+      write_duration = TRUE;
+    }
+  }
+
+  /* write the block, for doctype v2 use SimpleBlock if possible
+   * one slice (*breath*).
+   * FIXME: Need to do correct lacing! */
+  relative_timestamp64 = buffer_timestamp - mux->cluster_time;
+  if (relative_timestamp64 >= 0) {
+    /* round the timestamp */
+    relative_timestamp64 += gst_util_uint64_scale (mux->time_scale, 1, 2);
+    relative_timestamp = gst_util_uint64_scale (relative_timestamp64, 1,
+        mux->time_scale);
+  } else {
+    /* round the timestamp */
+    relative_timestamp64 -= gst_util_uint64_scale (mux->time_scale, 1, 2);
+    relative_timestamp =
+        -((gint16) gst_util_uint64_scale (-relative_timestamp64, 1,
+            mux->time_scale));
+  }
+
+  if (is_video_invisible)
+    flags |= 0x08;
+
+  if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)) {
+    cmeta = gst_buffer_get_audio_clipping_meta (buf);
+    g_assert (!cmeta || cmeta->format == GST_FORMAT_DEFAULT);
+
+    /* Start clipping is done via header and CodecDelay */
+    if (cmeta && !cmeta->end)
+      cmeta = NULL;
+  }
+
+  if (mux->doctype_version > 1 && !write_duration && !cmeta) {
+    if (is_video_keyframe)
+      flags |= 0x80;
+
+    hdr =
+        gst_matroska_mux_create_buffer_header (collect_pad->track,
+        relative_timestamp, flags);
+    gst_ebml_write_set_cache (ebml, 0x40);
+    gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
+        gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
+    gst_ebml_write_buffer (ebml, hdr);
+    gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
+    gst_ebml_write_buffer (ebml, buf);
+
+    return gst_ebml_last_write_result (ebml);
+  } else {
+    gst_ebml_write_set_cache (ebml, gst_buffer_get_size (buf) * 2);
+    /* write and call order slightly unnatural,
+     * but avoids seek and minizes pushing */
+    blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
+    hdr =
+        gst_matroska_mux_create_buffer_header (collect_pad->track,
+        relative_timestamp, flags);
+    if (write_duration)
+      gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION, block_duration);
+
+    if (!strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)
+        && cmeta) {
+      /* Start clipping is done via header and CodecDelay */
+      if (cmeta->end) {
+        guint64 end =
+            gst_util_uint64_scale_round (cmeta->end, GST_SECOND, 48000);
+        gst_ebml_write_sint (ebml, GST_MATROSKA_ID_DISCARDPADDING, end);
+      }
+    }
+
+    gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
+        gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
+    gst_ebml_write_buffer (ebml, hdr);
+    gst_ebml_write_master_finish_full (ebml, blockgroup,
+        gst_buffer_get_size (buf));
+    gst_ebml_write_flush_cache (ebml, FALSE, buffer_timestamp);
+    gst_ebml_write_buffer (ebml, buf);
+
+    return gst_ebml_last_write_result (ebml);
+  }
+}
+
+/**
+ * gst_matroska_mux_handle_buffer:
+ * @pads: #GstCollectPads
+ * @uuser_data: #GstMatroskaMux
+ *
+ * Collectpads callback.
+ *
+ * Returns: #GstFlowReturn
+ */
+static GstFlowReturn
+gst_matroska_mux_handle_buffer (GstCollectPads * pads, GstCollectData * data,
+    GstBuffer * buf, gpointer user_data)
+{
+  GstClockTime buffer_timestamp;
+  GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
+  GstEbmlWrite *ebml = mux->ebml_write;
+  GstMatroskaPad *best = (GstMatroskaPad *) data;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GST_DEBUG_OBJECT (mux, "Collected pads");
+
+  /* start with a header */
+  if (mux->state == GST_MATROSKA_MUX_STATE_START) {
+    if (mux->collect->data == NULL) {
+      GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
+          ("No input streams configured"));
+      return GST_FLOW_ERROR;
+    }
+    mux->state = GST_MATROSKA_MUX_STATE_HEADER;
+    gst_ebml_start_streamheader (ebml);
+    gst_matroska_mux_start (mux, best, buf);
+    gst_matroska_mux_stop_streamheader (mux);
+    mux->state = GST_MATROSKA_MUX_STATE_DATA;
+  }
+
+  /* if there is no best pad, we have reached EOS */
+  if (best == NULL) {
+    GST_DEBUG_OBJECT (mux, "No best pad. Finishing...");
+    if (!mux->ebml_write->streamable) {
+      gst_matroska_mux_finish (mux);
+    } else {
+      GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
+    }
+    gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
+    ret = GST_FLOW_EOS;
+    goto exit;
+  }
+
+  if (best->track->codec_id == NULL) {
+    GST_ERROR_OBJECT (best->collect.pad, "No codec-id for pad");
+    ret = GST_FLOW_NOT_NEGOTIATED;
+    goto exit;
+  }
+
+  /* if we have a best stream, should also have a buffer */
+  g_assert (buf);
+
+  buffer_timestamp = gst_matroska_track_get_buffer_timestamp (best->track, buf);
+
+  GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
+      GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (buffer_timestamp),
+      GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
+
+  /* make note of first and last encountered timestamps, so we can calculate
+   * the actual duration later when we send an updated header on eos */
+  if (GST_CLOCK_TIME_IS_VALID (buffer_timestamp)) {
+    GstClockTime start_ts = buffer_timestamp;
+    GstClockTime end_ts = start_ts;
+
+    if (GST_BUFFER_DURATION_IS_VALID (buf))
+      end_ts += GST_BUFFER_DURATION (buf);
+    else if (best->track->default_duration)
+      end_ts += best->track->default_duration;
+
+    if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
+      best->end_ts = end_ts;
+
+    if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
+            start_ts < best->start_ts))
+      best->start_ts = start_ts;
+  }
+
+  /* write one buffer */
+  ret = gst_matroska_mux_write_data (mux, best, buf);
+
+exit:
+  return ret;
+}
+
+
+/**
+ * gst_matroska_mux_change_state:
+ * @element: #GstMatroskaMux
+ * @transition: State change transition.
+ *
+ * Change the muxer state.
+ *
+ * Returns: #GstStateChangeReturn
+ */
+static GstStateChangeReturn
+gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_collect_pads_start (mux->collect);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_collect_pads_stop (mux->collect);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_matroska_mux_reset (GST_ELEMENT (mux));
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_matroska_mux_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstMatroskaMux *mux;
+
+  g_return_if_fail (GST_IS_MATROSKA_MUX (object));
+  mux = GST_MATROSKA_MUX (object);
+
+  switch (prop_id) {
+    case PROP_WRITING_APP:
+      if (!g_value_get_string (value)) {
+        GST_WARNING_OBJECT (mux, "writing-app property can not be NULL");
+        break;
+      }
+      g_free (mux->writing_app);
+      mux->writing_app = g_value_dup_string (value);
+      break;
+    case PROP_DOCTYPE_VERSION:
+      mux->doctype_version = g_value_get_int (value);
+      break;
+    case PROP_MIN_INDEX_INTERVAL:
+      mux->min_index_interval = g_value_get_int64 (value);
+      break;
+    case PROP_STREAMABLE:
+      mux->ebml_write->streamable = g_value_get_boolean (value);
+      break;
+    case PROP_TIMECODESCALE:
+      mux->time_scale = g_value_get_int64 (value);
+      break;
+    case PROP_MIN_CLUSTER_DURATION:
+      mux->min_cluster_duration = g_value_get_int64 (value);
+      break;
+    case PROP_MAX_CLUSTER_DURATION:
+      mux->max_cluster_duration = g_value_get_int64 (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_matroska_mux_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstMatroskaMux *mux;
+
+  g_return_if_fail (GST_IS_MATROSKA_MUX (object));
+  mux = GST_MATROSKA_MUX (object);
+
+  switch (prop_id) {
+    case PROP_WRITING_APP:
+      g_value_set_string (value, mux->writing_app);
+      break;
+    case PROP_DOCTYPE_VERSION:
+      g_value_set_int (value, mux->doctype_version);
+      break;
+    case PROP_MIN_INDEX_INTERVAL:
+      g_value_set_int64 (value, mux->min_index_interval);
+      break;
+    case PROP_STREAMABLE:
+      g_value_set_boolean (value, mux->ebml_write->streamable);
+      break;
+    case PROP_TIMECODESCALE:
+      g_value_set_int64 (value, mux->time_scale);
+      break;
+    case PROP_MIN_CLUSTER_DURATION:
+      g_value_set_int64 (value, mux->min_cluster_duration);
+      break;
+    case PROP_MAX_CLUSTER_DURATION:
+      g_value_set_int64 (value, mux->max_cluster_duration);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/gst/matroska/matroska-mux.h b/gst/matroska/matroska-mux.h
new file mode 100644
index 0000000..7283840
--- /dev/null
+++ b/gst/matroska/matroska-mux.h
@@ -0,0 +1,156 @@
+/* GStreamer Matroska muxer/demuxer
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2005 Michal Benes <michal.benes@xeris.cz>
+ *
+ * matroska-mux.h: matroska file/stream muxer object types
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MATROSKA_MUX_H__
+#define __GST_MATROSKA_MUX_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstcollectpads.h>
+
+#include "ebml-write.h"
+#include "matroska-ids.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_MATROSKA_MUX \
+  (gst_matroska_mux_get_type ())
+#define GST_MATROSKA_MUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MATROSKA_MUX, GstMatroskaMux))
+#define GST_MATROSKA_MUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MATROSKA_MUX, GstMatroskaMuxClass))
+#define GST_IS_MATROSKA_MUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MATROSKA_MUX))
+#define GST_IS_MATROSKA_MUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MATROSKA_MUX))
+
+typedef enum {
+  GST_MATROSKA_MUX_STATE_START,
+  GST_MATROSKA_MUX_STATE_HEADER,
+  GST_MATROSKA_MUX_STATE_DATA,
+} GstMatroskaMuxState;
+
+typedef struct _GstMatroskaMetaSeekIndex {
+  guint32  id;
+  guint64  pos;
+} GstMatroskaMetaSeekIndex;
+
+typedef gboolean (*GstMatroskaCapsFunc) (GstPad *pad, GstCaps *caps);
+
+typedef struct _GstMatroskaMux GstMatroskaMux;
+
+/* all information needed for one matroska stream */
+typedef struct
+{
+  GstCollectData collect;       /* we extend the CollectData */
+  GstMatroskaCapsFunc capsfunc;
+  GstMatroskaTrackContext *track;
+
+  GstMatroskaMux *mux;
+
+  GstTagList *tags;
+
+  GstClockTime start_ts;
+  GstClockTime end_ts;    /* last timestamp + (if available) duration */
+  guint64 default_duration_scaled;
+}
+GstMatroskaPad;
+
+
+struct _GstMatroskaMux {
+  GstElement     element;
+  
+  /* < private > */
+
+  /* pads */
+  GstPad        *srcpad;
+  GstCollectPads *collect;
+  GstEbmlWrite *ebml_write;
+
+  guint          num_streams,
+                 num_v_streams, num_a_streams, num_t_streams;
+
+  /* Application name (for the writing application header element) */
+  gchar          *writing_app;
+
+  /* EBML DocType. */
+  const gchar    *doctype;
+
+  /* DocType version. */
+  guint          doctype_version;
+
+  /* state */
+  GstMatroskaMuxState state;
+
+  /* a cue (index) table */
+  GstMatroskaIndex *index;
+  guint          num_indexes;
+  GstClockTimeDiff min_index_interval;
+ 
+  /* timescale in the file */
+  guint64        time_scale;
+  /* minimum and maximum limit of nanoseconds you can have in a cluster */
+  guint64        max_cluster_duration;
+  guint64        min_cluster_duration;
+
+  /* length, position (time, ns) */
+  guint64        duration;
+
+  /* byte-positions of master-elements (for replacing contents) */
+  guint64        segment_pos,
+                 seekhead_pos,
+                 cues_pos,
+                 chapters_pos,
+                 tags_pos,
+                 info_pos,
+                 tracks_pos,
+                 duration_pos,
+                 meta_pos;
+  guint64        segment_master;
+
+  /* current cluster */
+  guint64        cluster,
+                 cluster_time,
+                 cluster_pos,
+		 prev_cluster_size;
+
+  /* GstForceKeyUnit event */
+  GstEvent       *force_key_unit_event;
+
+  /* Internal Toc (adjusted UIDs and title tags removed when processed) */
+  GstToc         *internal_toc;
+
+  /* Flag to ease handling of WebM specifics */
+  gboolean is_webm;
+
+  /* used uids */
+  GArray *used_uids;
+};
+
+typedef struct _GstMatroskaMuxClass {
+  GstElementClass parent;
+} GstMatroskaMuxClass;
+
+GType   gst_matroska_mux_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_MATROSKA_MUX_H__ */
diff --git a/gst/matroska/matroska-parse.c b/gst/matroska/matroska-parse.c
new file mode 100644
index 0000000..006a46d
--- /dev/null
+++ b/gst/matroska/matroska-parse.c
@@ -0,0 +1,3236 @@
+/* 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-parse.c: matroska file/stream 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* TODO: check CRC32 if present
+ * TODO: there can be a segment after the first segment. Handle like
+ *       chained oggs. Fixes #334082
+ * TODO: Test samples: http://www.matroska.org/samples/matrix/index.html
+ *                     http://samples.mplayerhq.hu/Matroska/
+ * TODO: check if parseing is done correct for all codecs according to spec
+ * TODO: seeking with incomplete or without CUE
+ */
+
+/**
+ * SECTION:element-matroskaparse
+ *
+ * matroskaparse parsees a Matroska file into the different contained streams.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v filesrc location=/path/to/mkv ! matroskaparse ! vorbisdec ! audioconvert ! audioresample ! autoaudiosink
+ * ]| This pipeline parsees a Matroska file and outputs the contained Vorbis audio.
+ * </refsect2>
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <string.h>
+#include <glib/gprintf.h>
+
+/* For AVI compatibility mode
+   and for fourcc stuff */
+#include <gst/riff/riff-read.h>
+#include <gst/riff/riff-ids.h>
+#include <gst/riff/riff-media.h>
+
+#include <gst/tag/tag.h>
+
+#include <gst/pbutils/pbutils.h>
+
+#include "matroska-parse.h"
+#include "matroska-ids.h"
+
+GST_DEBUG_CATEGORY_STATIC (matroskaparse_debug);
+#define GST_CAT_DEFAULT matroskaparse_debug
+
+#define DEBUG_ELEMENT_START(parse, ebml, element) \
+    GST_DEBUG_OBJECT (parse, "Parsing " element " element at offset %" \
+        G_GUINT64_FORMAT, gst_ebml_read_get_pos (ebml))
+
+#define DEBUG_ELEMENT_STOP(parse, ebml, element, ret) \
+    GST_DEBUG_OBJECT (parse, "Parsing " element " element " \
+        " finished with '%s'", gst_flow_get_name (ret))
+
+#define INVALID_DATA_THRESHOLD (2 * 1024 * 1024)
+
+enum
+{
+  PROP_0
+};
+
+static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-matroska; video/x-matroska; "
+        "video/x-matroska-3d; audio/webm; video/webm")
+    );
+
+static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-matroska; video/x-matroska; "
+        "video/x-matroska-3d; audio/webm; video/webm")
+    );
+
+static GstFlowReturn gst_matroska_parse_parse_id (GstMatroskaParse * parse,
+    guint32 id, guint64 length, guint needed);
+
+/* element functions */
+//static void gst_matroska_parse_loop (GstPad * pad);
+
+static gboolean gst_matroska_parse_element_send_event (GstElement * element,
+    GstEvent * event);
+static gboolean gst_matroska_parse_element_query (GstElement * element,
+    GstQuery * query);
+
+/* pad functions */
+static gboolean gst_matroska_parse_handle_seek_event (GstMatroskaParse * parse,
+    GstPad * pad, GstEvent * event);
+static gboolean gst_matroska_parse_handle_src_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static gboolean gst_matroska_parse_handle_src_query (GstPad * pad,
+    GstObject * parent, GstQuery * query);
+
+static gboolean gst_matroska_parse_handle_sink_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static GstFlowReturn gst_matroska_parse_chain (GstPad * pad,
+    GstObject * parent, GstBuffer * buffer);
+
+static GstStateChangeReturn
+gst_matroska_parse_change_state (GstElement * element,
+    GstStateChange transition);
+#if 0
+static void
+gst_matroska_parse_set_index (GstElement * element, GstIndex * index);
+static GstIndex *gst_matroska_parse_get_index (GstElement * element);
+#endif
+
+/* stream methods */
+static void gst_matroska_parse_reset (GstElement * element);
+static gboolean perform_seek_to_offset (GstMatroskaParse * parse,
+    guint64 offset);
+static GstCaps *gst_matroska_parse_forge_caps (gboolean is_webm,
+    gboolean has_video);
+
+GType gst_matroska_parse_get_type (void);
+#define parent_class gst_matroska_parse_parent_class
+G_DEFINE_TYPE (GstMatroskaParse, gst_matroska_parse, GST_TYPE_ELEMENT);
+
+static void
+gst_matroska_parse_finalize (GObject * object)
+{
+  GstMatroskaParse *parse = GST_MATROSKA_PARSE (object);
+
+  gst_matroska_read_common_finalize (&parse->common);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_matroska_parse_class_init (GstMatroskaParseClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (matroskaparse_debug, "matroskaparse", 0,
+      "Matroska parser");
+
+  gobject_class->finalize = gst_matroska_parse_finalize;
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_matroska_parse_change_state);
+  gstelement_class->send_event =
+      GST_DEBUG_FUNCPTR (gst_matroska_parse_element_send_event);
+  gstelement_class->query =
+      GST_DEBUG_FUNCPTR (gst_matroska_parse_element_query);
+
+#if 0
+  gstelement_class->set_index =
+      GST_DEBUG_FUNCPTR (gst_matroska_parse_set_index);
+  gstelement_class->get_index =
+      GST_DEBUG_FUNCPTR (gst_matroska_parse_get_index);
+#endif
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_templ);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_templ);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Matroska parser", "Codec/Parser",
+      "Parses Matroska/WebM streams into video/audio/subtitles",
+      "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
+}
+
+static void
+gst_matroska_parse_init (GstMatroskaParse * parse)
+{
+  parse->common.sinkpad = gst_pad_new_from_static_template (&sink_templ,
+      "sink");
+  gst_pad_set_chain_function (parse->common.sinkpad,
+      GST_DEBUG_FUNCPTR (gst_matroska_parse_chain));
+  gst_pad_set_event_function (parse->common.sinkpad,
+      GST_DEBUG_FUNCPTR (gst_matroska_parse_handle_sink_event));
+  gst_element_add_pad (GST_ELEMENT (parse), parse->common.sinkpad);
+
+  parse->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
+  gst_pad_set_event_function (parse->srcpad,
+      GST_DEBUG_FUNCPTR (gst_matroska_parse_handle_src_event));
+  gst_pad_set_query_function (parse->srcpad,
+      GST_DEBUG_FUNCPTR (gst_matroska_parse_handle_src_query));
+  gst_pad_use_fixed_caps (parse->srcpad);
+
+  gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad);
+
+  /* init defaults for common read context */
+  gst_matroska_read_common_init (&parse->common);
+
+  GST_OBJECT_FLAG_SET (parse, GST_ELEMENT_FLAG_INDEXABLE);
+
+  /* finish off */
+  gst_matroska_parse_reset (GST_ELEMENT (parse));
+}
+
+static void
+gst_matroska_parse_reset (GstElement * element)
+{
+  GstMatroskaParse *parse = GST_MATROSKA_PARSE (element);
+
+  GST_DEBUG_OBJECT (parse, "Resetting state");
+
+  gst_matroska_read_common_reset (GST_ELEMENT (parse), &parse->common);
+
+  parse->num_a_streams = 0;
+  parse->num_t_streams = 0;
+  parse->num_v_streams = 0;
+
+  parse->clock = NULL;
+  parse->tracks_parsed = FALSE;
+
+  g_list_foreach (parse->seek_parsed,
+      (GFunc) gst_matroska_read_common_free_parsed_el, NULL);
+  g_list_free (parse->seek_parsed);
+  parse->seek_parsed = NULL;
+
+  parse->last_stop_end = GST_CLOCK_TIME_NONE;
+  parse->seek_block = 0;
+  parse->cluster_time = GST_CLOCK_TIME_NONE;
+  parse->cluster_offset = 0;
+  parse->next_cluster_offset = 0;
+  parse->index_offset = 0;
+  parse->seekable = FALSE;
+  parse->need_newsegment = TRUE;
+  parse->building_index = FALSE;
+  if (parse->seek_event) {
+    gst_event_unref (parse->seek_event);
+    parse->seek_event = NULL;
+  }
+
+  parse->seek_index = NULL;
+  parse->seek_entry = 0;
+
+  if (parse->close_segment) {
+    gst_event_unref (parse->close_segment);
+    parse->close_segment = NULL;
+  }
+
+  if (parse->new_segment) {
+    gst_event_unref (parse->new_segment);
+    parse->new_segment = NULL;
+  }
+
+  if (parse->streamheader != NULL) {
+    gst_buffer_unref (parse->streamheader);
+    parse->streamheader = NULL;
+  }
+}
+
+static GstFlowReturn
+gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
+{
+  GstMatroskaTrackContext *context;
+  GstFlowReturn ret;
+  guint32 id;
+
+  DEBUG_ELEMENT_START (parse, ebml, "TrackEntry");
+
+  /* start with the master */
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (parse, ebml, "TrackEntry", ret);
+    return ret;
+  }
+
+  /* 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->common.src, context);
+  context->index = parse->common.num_streams;
+  context->index_writer_id = -1;
+  context->type = 0;            /* no type yet */
+  context->default_duration = 0;
+  context->pos = 0;
+  context->set_discont = TRUE;
+  context->timecodescale = 1.0;
+  context->flags =
+      GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT |
+      GST_MATROSKA_TRACK_LACING;
+  context->to_offset = G_MAXINT64;
+  context->alignment = 1;
+  parse->common.num_streams++;
+  g_assert (parse->common.src->len == parse->common.num_streams);
+
+  GST_DEBUG_OBJECT (parse, "Stream number %d", context->index);
+
+  /* try reading the trackentry headers */
+  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 (unique stream ID) */
+      case GST_MATROSKA_ID_TRACKNUMBER:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num == 0) {
+          GST_ERROR_OBJECT (parse, "Invalid TrackNumber 0");
+          ret = GST_FLOW_ERROR;
+          break;
+        } else if (!gst_matroska_read_common_tracknumber_unique (&parse->common,
+                num)) {
+          GST_ERROR_OBJECT (parse, "TrackNumber %" G_GUINT64_FORMAT
+              " is not unique", num);
+          ret = GST_FLOW_ERROR;
+          break;
+        }
+
+        GST_DEBUG_OBJECT (parse, "TrackNumber: %" G_GUINT64_FORMAT, num);
+        context->num = num;
+        break;
+      }
+        /* track UID (unique identifier) */
+      case GST_MATROSKA_ID_TRACKUID:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num == 0) {
+          GST_ERROR_OBJECT (parse, "Invalid TrackUID 0");
+          ret = GST_FLOW_ERROR;
+          break;
+        }
+
+        GST_DEBUG_OBJECT (parse, "TrackUID: %" G_GUINT64_FORMAT, num);
+        context->uid = num;
+        break;
+      }
+
+        /* track type (video, audio, combined, subtitle, etc.) */
+      case GST_MATROSKA_ID_TRACKTYPE:{
+        guint64 track_type;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &track_type)) != GST_FLOW_OK) {
+          break;
+        }
+
+        if (context->type != 0 && context->type != track_type) {
+          GST_WARNING_OBJECT (parse,
+              "More than one tracktype defined in a TrackEntry - skipping");
+          break;
+        } else if (track_type < 1 || track_type > 254) {
+          GST_WARNING_OBJECT (parse, "Invalid TrackType %" G_GUINT64_FORMAT,
+              track_type);
+          break;
+        }
+
+        GST_DEBUG_OBJECT (parse, "TrackType: %" G_GUINT64_FORMAT, track_type);
+
+        /* ok, so we're actually going to reallocate this thing */
+        switch (track_type) {
+          case GST_MATROSKA_TRACK_TYPE_VIDEO:
+            gst_matroska_track_init_video_context (&context);
+            parse->common.has_video = TRUE;
+            break;
+          case GST_MATROSKA_TRACK_TYPE_AUDIO:
+            gst_matroska_track_init_audio_context (&context);
+            break;
+          case GST_MATROSKA_TRACK_TYPE_SUBTITLE:
+            gst_matroska_track_init_subtitle_context (&context);
+            break;
+          case GST_MATROSKA_TRACK_TYPE_COMPLEX:
+          case GST_MATROSKA_TRACK_TYPE_LOGO:
+          case GST_MATROSKA_TRACK_TYPE_BUTTONS:
+          case GST_MATROSKA_TRACK_TYPE_CONTROL:
+          default:
+            GST_WARNING_OBJECT (parse,
+                "Unknown or unsupported TrackType %" G_GUINT64_FORMAT,
+                track_type);
+            context->type = 0;
+            break;
+        }
+        g_ptr_array_index (parse->common.src, parse->common.num_streams - 1)
+            = context;
+        break;
+      }
+
+        /* tracktype specific stuff for video */
+      case GST_MATROSKA_ID_TRACKVIDEO:{
+        GstMatroskaTrackVideoContext *videocontext;
+
+        DEBUG_ELEMENT_START (parse, ebml, "TrackVideo");
+
+        if (!gst_matroska_track_init_video_context (&context)) {
+          GST_WARNING_OBJECT (parse,
+              "TrackVideo element in non-video track - ignoring track");
+          ret = GST_FLOW_ERROR;
+          break;
+        } else if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+          break;
+        }
+        videocontext = (GstMatroskaTrackVideoContext *) 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)) {
+          if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
+            break;
+
+          switch (id) {
+              /* Should be one level up but some broken muxers write it here. */
+            case GST_MATROSKA_ID_TRACKDEFAULTDURATION:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num == 0) {
+                GST_WARNING_OBJECT (parse, "Invalid TrackDefaultDuration 0");
+                break;
+              }
+
+              GST_DEBUG_OBJECT (parse,
+                  "TrackDefaultDuration: %" G_GUINT64_FORMAT, num);
+              context->default_duration = num;
+              break;
+            }
+
+              /* video framerate */
+              /* NOTE: This one is here only for backward compatibility.
+               * Use _TRACKDEFAULDURATION one level up. */
+            case GST_MATROSKA_ID_VIDEOFRAMERATE:{
+              gdouble num;
+
+              if ((ret = gst_ebml_read_float (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num <= 0.0) {
+                GST_WARNING_OBJECT (parse, "Invalid TrackVideoFPS %lf", num);
+                break;
+              }
+
+              GST_DEBUG_OBJECT (parse, "TrackVideoFrameRate: %lf", num);
+              if (context->default_duration == 0)
+                context->default_duration =
+                    gst_gdouble_to_guint64 ((gdouble) GST_SECOND * (1.0 / num));
+              videocontext->default_fps = num;
+              break;
+            }
+
+              /* width of the size to display the video at */
+            case GST_MATROSKA_ID_VIDEODISPLAYWIDTH:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num == 0) {
+                GST_WARNING_OBJECT (parse, "Invalid TrackVideoDisplayWidth 0");
+                break;
+              }
+
+              GST_DEBUG_OBJECT (parse,
+                  "TrackVideoDisplayWidth: %" G_GUINT64_FORMAT, num);
+              videocontext->display_width = num;
+              break;
+            }
+
+              /* height of the size to display the video at */
+            case GST_MATROSKA_ID_VIDEODISPLAYHEIGHT:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num == 0) {
+                GST_WARNING_OBJECT (parse, "Invalid TrackVideoDisplayHeight 0");
+                break;
+              }
+
+              GST_DEBUG_OBJECT (parse,
+                  "TrackVideoDisplayHeight: %" G_GUINT64_FORMAT, num);
+              videocontext->display_height = num;
+              break;
+            }
+
+              /* width of the video in the file */
+            case GST_MATROSKA_ID_VIDEOPIXELWIDTH:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num == 0) {
+                GST_WARNING_OBJECT (parse, "Invalid TrackVideoPixelWidth 0");
+                break;
+              }
+
+              GST_DEBUG_OBJECT (parse,
+                  "TrackVideoPixelWidth: %" G_GUINT64_FORMAT, num);
+              videocontext->pixel_width = num;
+              break;
+            }
+
+              /* height of the video in the file */
+            case GST_MATROSKA_ID_VIDEOPIXELHEIGHT:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num == 0) {
+                GST_WARNING_OBJECT (parse, "Invalid TrackVideoPixelHeight 0");
+                break;
+              }
+
+              GST_DEBUG_OBJECT (parse,
+                  "TrackVideoPixelHeight: %" G_GUINT64_FORMAT, num);
+              videocontext->pixel_height = num;
+              break;
+            }
+
+              /* whether the video is interlaced */
+            case GST_MATROSKA_ID_VIDEOFLAGINTERLACED:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num)
+                context->flags |= GST_MATROSKA_VIDEOTRACK_INTERLACED;
+              else
+                context->flags &= ~GST_MATROSKA_VIDEOTRACK_INTERLACED;
+              GST_DEBUG_OBJECT (parse, "TrackVideoInterlaced: %d",
+                  (context->flags & GST_MATROSKA_VIDEOTRACK_INTERLACED) ? 1 :
+                  0);
+              break;
+            }
+
+              /* aspect ratio behaviour */
+            case GST_MATROSKA_ID_VIDEOASPECTRATIOTYPE:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num != GST_MATROSKA_ASPECT_RATIO_MODE_FREE &&
+                  num != GST_MATROSKA_ASPECT_RATIO_MODE_KEEP &&
+                  num != GST_MATROSKA_ASPECT_RATIO_MODE_FIXED) {
+                GST_WARNING_OBJECT (parse,
+                    "Unknown TrackVideoAspectRatioType 0x%x", (guint) num);
+                break;
+              }
+              GST_DEBUG_OBJECT (parse,
+                  "TrackVideoAspectRatioType: %" G_GUINT64_FORMAT, num);
+              videocontext->asr_mode = num;
+              break;
+            }
+
+              /* colourspace (only matters for raw video) fourcc */
+            case GST_MATROSKA_ID_VIDEOCOLOURSPACE:{
+              guint8 *data;
+              guint64 datalen;
+
+              if ((ret =
+                      gst_ebml_read_binary (ebml, &id, &data,
+                          &datalen)) != GST_FLOW_OK)
+                break;
+
+              if (datalen != 4) {
+                g_free (data);
+                GST_WARNING_OBJECT (parse,
+                    "Invalid TrackVideoColourSpace length %" G_GUINT64_FORMAT,
+                    datalen);
+                break;
+              }
+
+              memcpy (&videocontext->fourcc, data, 4);
+              GST_DEBUG_OBJECT (parse,
+                  "TrackVideoColourSpace: %" GST_FOURCC_FORMAT,
+                  GST_FOURCC_ARGS (videocontext->fourcc));
+              g_free (data);
+              break;
+            }
+
+            default:
+              GST_WARNING_OBJECT (parse,
+                  "Unknown TrackVideo subelement 0x%x - ignoring", id);
+              /* fall through */
+            case GST_MATROSKA_ID_VIDEOSTEREOMODE:
+            case GST_MATROSKA_ID_VIDEODISPLAYUNIT:
+            case GST_MATROSKA_ID_VIDEOPIXELCROPBOTTOM:
+            case GST_MATROSKA_ID_VIDEOPIXELCROPTOP:
+            case GST_MATROSKA_ID_VIDEOPIXELCROPLEFT:
+            case GST_MATROSKA_ID_VIDEOPIXELCROPRIGHT:
+            case GST_MATROSKA_ID_VIDEOGAMMAVALUE:
+              ret = gst_ebml_read_skip (ebml);
+              break;
+          }
+        }
+
+        DEBUG_ELEMENT_STOP (parse, ebml, "TrackVideo", ret);
+        break;
+      }
+
+        /* tracktype specific stuff for audio */
+      case GST_MATROSKA_ID_TRACKAUDIO:{
+        GstMatroskaTrackAudioContext *audiocontext;
+
+        DEBUG_ELEMENT_START (parse, ebml, "TrackAudio");
+
+        if (!gst_matroska_track_init_audio_context (&context)) {
+          GST_WARNING_OBJECT (parse,
+              "TrackAudio element in non-audio track - ignoring track");
+          ret = GST_FLOW_ERROR;
+          break;
+        }
+
+        if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
+          break;
+
+        audiocontext = (GstMatroskaTrackAudioContext *) 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)) {
+          if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
+            break;
+
+          switch (id) {
+              /* samplerate */
+            case GST_MATROSKA_ID_AUDIOSAMPLINGFREQ:{
+              gdouble num;
+
+              if ((ret = gst_ebml_read_float (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+
+              if (num <= 0.0) {
+                GST_WARNING_OBJECT (parse,
+                    "Invalid TrackAudioSamplingFrequency %lf", num);
+                break;
+              }
+
+              GST_DEBUG_OBJECT (parse, "TrackAudioSamplingFrequency: %lf", num);
+              audiocontext->samplerate = num;
+              break;
+            }
+
+              /* bitdepth */
+            case GST_MATROSKA_ID_AUDIOBITDEPTH:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num == 0) {
+                GST_WARNING_OBJECT (parse, "Invalid TrackAudioBitDepth 0");
+                break;
+              }
+
+              GST_DEBUG_OBJECT (parse, "TrackAudioBitDepth: %" G_GUINT64_FORMAT,
+                  num);
+              audiocontext->bitdepth = num;
+              break;
+            }
+
+              /* channels */
+            case GST_MATROSKA_ID_AUDIOCHANNELS:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              if (num == 0) {
+                GST_WARNING_OBJECT (parse, "Invalid TrackAudioChannels 0");
+                break;
+              }
+
+              GST_DEBUG_OBJECT (parse, "TrackAudioChannels: %" G_GUINT64_FORMAT,
+                  num);
+              audiocontext->channels = num;
+              break;
+            }
+
+            default:
+              GST_WARNING_OBJECT (parse,
+                  "Unknown TrackAudio subelement 0x%x - ignoring", id);
+              /* fall through */
+            case GST_MATROSKA_ID_AUDIOCHANNELPOSITIONS:
+            case GST_MATROSKA_ID_AUDIOOUTPUTSAMPLINGFREQ:
+              ret = gst_ebml_read_skip (ebml);
+              break;
+          }
+        }
+
+        DEBUG_ELEMENT_STOP (parse, ebml, "TrackAudio", ret);
+
+        break;
+      }
+
+        /* codec identifier */
+      case GST_MATROSKA_ID_CODECID:{
+        gchar *text;
+
+        if ((ret = gst_ebml_read_ascii (ebml, &id, &text)) != GST_FLOW_OK)
+          break;
+
+        GST_DEBUG_OBJECT (parse, "CodecID: %s", GST_STR_NULL (text));
+        context->codec_id = text;
+        break;
+      }
+
+        /* codec private data */
+      case GST_MATROSKA_ID_CODECPRIVATE:{
+        guint8 *data;
+        guint64 size;
+
+        if ((ret =
+                gst_ebml_read_binary (ebml, &id, &data, &size)) != GST_FLOW_OK)
+          break;
+
+        context->codec_priv = data;
+        context->codec_priv_size = size;
+
+        GST_DEBUG_OBJECT (parse, "CodecPrivate of size %" G_GUINT64_FORMAT,
+            size);
+        break;
+      }
+
+        /* name of the codec */
+      case GST_MATROSKA_ID_CODECNAME:{
+        gchar *text;
+
+        if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
+          break;
+
+        GST_DEBUG_OBJECT (parse, "CodecName: %s", GST_STR_NULL (text));
+        context->codec_name = text;
+        break;
+      }
+
+        /* name of this track */
+      case GST_MATROSKA_ID_TRACKNAME:{
+        gchar *text;
+
+        if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
+          break;
+
+        context->name = text;
+        GST_DEBUG_OBJECT (parse, "TrackName: %s", GST_STR_NULL (text));
+        break;
+      }
+
+        /* language (matters for audio/subtitles, mostly) */
+      case GST_MATROSKA_ID_TRACKLANGUAGE:{
+        gchar *text;
+
+        if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
+          break;
+
+
+        context->language = text;
+
+        /* fre-ca => fre */
+        if (strlen (context->language) >= 4 && context->language[3] == '-')
+          context->language[3] = '\0';
+
+        GST_DEBUG_OBJECT (parse, "TrackLanguage: %s",
+            GST_STR_NULL (context->language));
+        break;
+      }
+
+        /* whether this is actually used */
+      case GST_MATROSKA_ID_TRACKFLAGENABLED:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num)
+          context->flags |= GST_MATROSKA_TRACK_ENABLED;
+        else
+          context->flags &= ~GST_MATROSKA_TRACK_ENABLED;
+
+        GST_DEBUG_OBJECT (parse, "TrackEnabled: %d",
+            (context->flags & GST_MATROSKA_TRACK_ENABLED) ? 1 : 0);
+        break;
+      }
+
+        /* whether it's the default for this track type */
+      case GST_MATROSKA_ID_TRACKFLAGDEFAULT:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num)
+          context->flags |= GST_MATROSKA_TRACK_DEFAULT;
+        else
+          context->flags &= ~GST_MATROSKA_TRACK_DEFAULT;
+
+        GST_DEBUG_OBJECT (parse, "TrackDefault: %d",
+            (context->flags & GST_MATROSKA_TRACK_ENABLED) ? 1 : 0);
+        break;
+      }
+
+        /* whether the track must be used during playback */
+      case GST_MATROSKA_ID_TRACKFLAGFORCED:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num)
+          context->flags |= GST_MATROSKA_TRACK_FORCED;
+        else
+          context->flags &= ~GST_MATROSKA_TRACK_FORCED;
+
+        GST_DEBUG_OBJECT (parse, "TrackForced: %d",
+            (context->flags & GST_MATROSKA_TRACK_ENABLED) ? 1 : 0);
+        break;
+      }
+
+        /* lacing (like MPEG, where blocks don't end/start on frame
+         * boundaries) */
+      case GST_MATROSKA_ID_TRACKFLAGLACING:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num)
+          context->flags |= GST_MATROSKA_TRACK_LACING;
+        else
+          context->flags &= ~GST_MATROSKA_TRACK_LACING;
+
+        GST_DEBUG_OBJECT (parse, "TrackLacing: %d",
+            (context->flags & GST_MATROSKA_TRACK_ENABLED) ? 1 : 0);
+        break;
+      }
+
+        /* default length (in time) of one data block in this track */
+      case GST_MATROSKA_ID_TRACKDEFAULTDURATION:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+
+        if (num == 0) {
+          GST_WARNING_OBJECT (parse, "Invalid TrackDefaultDuration 0");
+          break;
+        }
+
+        GST_DEBUG_OBJECT (parse, "TrackDefaultDuration: %" G_GUINT64_FORMAT,
+            num);
+        context->default_duration = num;
+        break;
+      }
+
+      case GST_MATROSKA_ID_CONTENTENCODINGS:{
+        ret = gst_matroska_read_common_read_track_encodings (&parse->common,
+            ebml, context);
+        break;
+      }
+
+      case GST_MATROSKA_ID_TRACKTIMECODESCALE:{
+        gdouble num;
+
+        if ((ret = gst_ebml_read_float (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num <= 0.0) {
+          GST_WARNING_OBJECT (parse, "Invalid TrackTimeCodeScale %lf", num);
+          break;
+        }
+
+        GST_DEBUG_OBJECT (parse, "TrackTimeCodeScale: %lf", num);
+        context->timecodescale = num;
+        break;
+      }
+
+      default:
+        GST_WARNING ("Unknown TrackEntry subelement 0x%x - ignoring", id);
+        /* pass-through */
+
+        /* we ignore these because they're nothing useful (i.e. crap)
+         * or simply not implemented yet. */
+      case GST_MATROSKA_ID_TRACKMINCACHE:
+      case GST_MATROSKA_ID_TRACKMAXCACHE:
+      case GST_MATROSKA_ID_MAXBLOCKADDITIONID:
+      case GST_MATROSKA_ID_TRACKATTACHMENTLINK:
+      case GST_MATROSKA_ID_TRACKOVERLAY:
+      case GST_MATROSKA_ID_TRACKTRANSLATE:
+      case GST_MATROSKA_ID_TRACKOFFSET:
+      case GST_MATROSKA_ID_CODECSETTINGS:
+      case GST_MATROSKA_ID_CODECINFOURL:
+      case GST_MATROSKA_ID_CODECDOWNLOADURL:
+      case GST_MATROSKA_ID_CODECDECODEALL:
+        ret = gst_ebml_read_skip (ebml);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (parse, ebml, "TrackEntry", ret);
+
+  /* Decode codec private data if necessary */
+  if (context->encodings && context->encodings->len > 0 && context->codec_priv
+      && context->codec_priv_size > 0) {
+    if (!gst_matroska_decode_data (context->encodings,
+            &context->codec_priv, &context->codec_priv_size,
+            GST_MATROSKA_TRACK_ENCODING_SCOPE_CODEC_DATA, TRUE)) {
+      GST_WARNING_OBJECT (parse, "Decoding codec private data failed");
+      ret = GST_FLOW_ERROR;
+    }
+  }
+
+  if (context->type == 0 || context->codec_id == NULL || (ret != GST_FLOW_OK
+          && ret != GST_FLOW_EOS)) {
+    if (ret == GST_FLOW_OK || ret == GST_FLOW_EOS)
+      GST_WARNING_OBJECT (ebml, "Unknown stream/codec in track entry header");
+
+    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);
+    gst_matroska_track_free (context);
+
+    return ret;
+  }
+
+  if ((context->language == NULL || *context->language == '\0') &&
+      (context->type == GST_MATROSKA_TRACK_TYPE_AUDIO ||
+          context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE)) {
+    GST_LOG ("stream %d: language=eng (assuming default)", context->index);
+    context->language = g_strdup ("eng");
+  }
+
+
+  /* tadaah! */
+  return ret;
+}
+
+static gboolean
+gst_matroska_parse_query (GstMatroskaParse * parse, GstPad * pad,
+    GstQuery * query)
+{
+  gboolean res = FALSE;
+  GstMatroskaTrackContext *context = NULL;
+
+  if (pad) {
+    context = gst_pad_get_element_private (pad);
+  }
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:
+    {
+      GstFormat format;
+
+      gst_query_parse_position (query, &format, NULL);
+
+      if (format == GST_FORMAT_TIME) {
+        GST_OBJECT_LOCK (parse);
+        if (context)
+          gst_query_set_position (query, GST_FORMAT_TIME, context->pos);
+        else
+          gst_query_set_position (query, GST_FORMAT_TIME,
+              parse->common.segment.position);
+        GST_OBJECT_UNLOCK (parse);
+      } else if (format == GST_FORMAT_DEFAULT && context
+          && context->default_duration) {
+        GST_OBJECT_LOCK (parse);
+        gst_query_set_position (query, GST_FORMAT_DEFAULT,
+            context->pos / context->default_duration);
+        GST_OBJECT_UNLOCK (parse);
+      } else {
+        GST_DEBUG_OBJECT (parse,
+            "only position query in TIME and DEFAULT format is supported");
+      }
+
+      res = TRUE;
+      break;
+    }
+    case GST_QUERY_DURATION:
+    {
+      GstFormat format;
+
+      gst_query_parse_duration (query, &format, NULL);
+
+      if (format == GST_FORMAT_TIME) {
+        GST_OBJECT_LOCK (parse);
+        gst_query_set_duration (query, GST_FORMAT_TIME,
+            parse->common.segment.duration);
+        GST_OBJECT_UNLOCK (parse);
+      } else if (format == GST_FORMAT_DEFAULT && context
+          && context->default_duration) {
+        GST_OBJECT_LOCK (parse);
+        gst_query_set_duration (query, GST_FORMAT_DEFAULT,
+            parse->common.segment.duration / context->default_duration);
+        GST_OBJECT_UNLOCK (parse);
+      } else {
+        GST_DEBUG_OBJECT (parse,
+            "only duration query in TIME and DEFAULT format is supported");
+      }
+
+      res = TRUE;
+      break;
+    }
+
+    case GST_QUERY_SEEKING:
+    {
+      GstFormat fmt;
+
+      gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
+      if (fmt == GST_FORMAT_TIME) {
+        gboolean seekable;
+
+        /* assuming we'll be able to get an index ... */
+        seekable = parse->seekable;
+
+        gst_query_set_seeking (query, GST_FORMAT_TIME, seekable,
+            0, parse->common.segment.duration);
+        res = TRUE;
+      }
+      break;
+    }
+    default:
+      if (pad)
+        res = gst_pad_query_default (pad, (GstObject *) parse, query);
+      break;
+  }
+
+  return res;
+}
+
+static gboolean
+gst_matroska_parse_element_query (GstElement * element, GstQuery * query)
+{
+  return gst_matroska_parse_query (GST_MATROSKA_PARSE (element), NULL, query);
+}
+
+static gboolean
+gst_matroska_parse_handle_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  gboolean ret;
+  GstMatroskaParse *parse = GST_MATROSKA_PARSE (parent);
+
+  ret = gst_matroska_parse_query (parse, pad, query);
+
+  return ret;
+}
+
+static void
+gst_matroska_parse_send_tags (GstMatroskaParse * parse)
+{
+  if (G_UNLIKELY (parse->common.global_tags_changed)) {
+    GstEvent *tag_event;
+    gst_tag_list_add (parse->common.global_tags, GST_TAG_MERGE_REPLACE,
+        GST_TAG_CONTAINER_FORMAT, "Matroska", NULL);
+    GST_DEBUG_OBJECT (parse, "Sending global_tags %p : %" GST_PTR_FORMAT,
+        parse->common.global_tags, parse->common.global_tags);
+
+    /* Send a copy as we want to keep our local ref writable to add more tags
+     * if any are found */
+    tag_event =
+        gst_event_new_tag (gst_tag_list_copy (parse->common.global_tags));
+
+    gst_pad_push_event (parse->srcpad, tag_event);
+
+    parse->common.global_tags_changed = FALSE;
+  }
+}
+
+/* returns FALSE if there are no pads to deliver event to,
+ * otherwise TRUE (whatever the outcome of event sending),
+ * takes ownership of the passed event! */
+static gboolean
+gst_matroska_parse_send_event (GstMatroskaParse * parse, GstEvent * event)
+{
+  gboolean ret = FALSE;
+
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  GST_DEBUG_OBJECT (parse, "Sending event of type %s to all source pads",
+      GST_EVENT_TYPE_NAME (event));
+
+  gst_pad_push_event (parse->srcpad, event);
+
+  return ret;
+}
+
+static gboolean
+gst_matroska_parse_element_send_event (GstElement * element, GstEvent * event)
+{
+  GstMatroskaParse *parse = GST_MATROSKA_PARSE (element);
+  gboolean res;
+
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
+    res = gst_matroska_parse_handle_seek_event (parse, NULL, event);
+  } else {
+    GST_WARNING_OBJECT (parse, "Unhandled event of type %s",
+        GST_EVENT_TYPE_NAME (event));
+    res = FALSE;
+  }
+  gst_event_unref (event);
+  return res;
+}
+
+#if 0
+/* searches for a cluster start from @pos,
+ * return GST_FLOW_OK and cluster position in @pos if found */
+static GstFlowReturn
+gst_matroska_parse_search_cluster (GstMatroskaParse * parse, gint64 * pos)
+{
+  gint64 newpos = *pos;
+  gint64 orig_offset;
+  GstFlowReturn ret = GST_FLOW_OK;
+  const guint chunk = 64 * 1024;
+  GstBuffer *buf;
+  GstMapInfo map;
+  gpointer data;
+  gsize size;
+  guint64 length;
+  guint32 id;
+  guint needed;
+
+  orig_offset = parse->common.offset;
+
+  /* read in at newpos and scan for ebml cluster id */
+  while (1) {
+    GstByteReader reader;
+    gint cluster_pos;
+
+    buf = NULL;
+    ret = gst_pad_pull_range (parse->common.sinkpad, newpos, chunk, &buf);
+    if (ret != GST_FLOW_OK)
+      break;
+    GST_DEBUG_OBJECT (parse,
+        "read buffer size %" G_GSIZE_FORMAT " at offset %" G_GINT64_FORMAT,
+        gst_buffer_get_size (buf), newpos);
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    data = map.data;
+    size = map.size;
+    gst_byte_reader_init (&reader, data, size);
+    cluster_pos = 0;
+  resume:
+    cluster_pos = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff,
+        GST_MATROSKA_ID_CLUSTER, cluster_pos, size - cluster_pos);
+    if (cluster_pos >= 0) {
+      newpos += cluster_pos;
+      GST_DEBUG_OBJECT (parse,
+          "found cluster ebml id at offset %" G_GINT64_FORMAT, newpos);
+      /* extra checks whether we really sync'ed to a cluster:
+       * - either it is the first and only cluster
+       * - either there is a cluster after this one
+       * - either cluster length is undefined
+       */
+      /* ok if first cluster (there may not a subsequent one) */
+      if (newpos == parse->first_cluster_offset) {
+        GST_DEBUG_OBJECT (parse, "cluster is first cluster -> OK");
+        break;
+      }
+      parse->common.offset = newpos;
+      ret = gst_matroska_read_common_peek_id_length_pull (&parse->common,
+          GST_ELEMENT_CAST (parse), &id, &length, &needed);
+      if (ret != GST_FLOW_OK)
+        goto resume;
+      g_assert (id == GST_MATROSKA_ID_CLUSTER);
+      GST_DEBUG_OBJECT (parse, "cluster size %" G_GUINT64_FORMAT ", prefix %d",
+          length, needed);
+      /* ok if undefined length or first cluster */
+      if (length == G_MAXUINT64) {
+        GST_DEBUG_OBJECT (parse, "cluster has undefined length -> OK");
+        break;
+      }
+      /* skip cluster */
+      parse->common.offset += length + needed;
+      ret = gst_matroska_read_common_peek_id_length_pull (&parse->common,
+          GST_ELEMENT_CAST (parse), &id, &length, &needed);
+      if (ret != GST_FLOW_OK)
+        goto resume;
+      GST_DEBUG_OBJECT (parse, "next element is %scluster",
+          id == GST_MATROSKA_ID_CLUSTER ? "" : "not ");
+      if (id == GST_MATROSKA_ID_CLUSTER)
+        break;
+      /* not ok, resume */
+      goto resume;
+    } else {
+      /* partial cluster id may have been in tail of buffer */
+      newpos += MAX (size, 4) - 3;
+      gst_buffer_unmap (buf, &map);
+      gst_buffer_unref (buf);
+      buf = NULL;
+    }
+  }
+
+  if (buf) {
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    buf = NULL;
+  }
+
+  parse->common.offset = orig_offset;
+  *pos = newpos;
+  return ret;
+}
+#endif
+
+static gboolean
+gst_matroska_parse_handle_seek_event (GstMatroskaParse * parse,
+    GstPad * pad, GstEvent * event)
+{
+  GstMatroskaIndex *entry = NULL;
+  GstSeekFlags flags;
+  GstSeekType cur_type, stop_type;
+  GstFormat format;
+  gdouble rate;
+  gint64 cur, stop;
+  GstMatroskaTrackContext *track = NULL;
+  GstSegment seeksegment = { 0, };
+  gboolean update;
+  GstSearchMode snap_dir;
+
+  if (pad)
+    track = gst_pad_get_element_private (pad);
+
+  track = gst_matroska_read_common_get_seek_track (&parse->common, track);
+
+  gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
+      &stop_type, &stop);
+
+  /* we can only seek on time */
+  if (format != GST_FORMAT_TIME) {
+    GST_DEBUG_OBJECT (parse, "Can only seek on TIME");
+    return FALSE;
+  }
+
+  /* copy segment, we need this because we still need the old
+   * segment when we close the current segment. */
+  memcpy (&seeksegment, &parse->common.segment, sizeof (GstSegment));
+
+  if (event) {
+    GST_DEBUG_OBJECT (parse, "configuring seek");
+    gst_segment_do_seek (&seeksegment, rate, format, flags,
+        cur_type, cur, stop_type, stop, &update);
+  }
+
+  GST_DEBUG_OBJECT (parse, "New segment %" GST_SEGMENT_FORMAT, &seeksegment);
+
+  if (seeksegment.rate < 0)
+    snap_dir = GST_SEARCH_MODE_AFTER;
+  else
+    snap_dir = GST_SEARCH_MODE_BEFORE;
+
+  /* check sanity before we start flushing and all that */
+  GST_OBJECT_LOCK (parse);
+  if ((entry = gst_matroska_read_common_do_index_seek (&parse->common, track,
+              seeksegment.position, &parse->seek_index, &parse->seek_entry,
+              snap_dir)) == NULL) {
+    /* pull mode without index can scan later on */
+    GST_DEBUG_OBJECT (parse, "No matching seek entry in index");
+    GST_OBJECT_UNLOCK (parse);
+    return FALSE;
+  }
+  GST_DEBUG_OBJECT (parse, "Seek position looks sane");
+  GST_OBJECT_UNLOCK (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->common.ebml_segment_start);
+}
+
+/*
+ * Handle whether we can perform the seek event or if we have to let the chain
+ * function handle seeks to build the seek indexes first.
+ */
+static gboolean
+gst_matroska_parse_handle_seek_push (GstMatroskaParse * parse, GstPad * pad,
+    GstEvent * event)
+{
+  GstSeekFlags flags;
+  GstSeekType cur_type, stop_type;
+  GstFormat format;
+  gdouble rate;
+  gint64 cur, stop;
+
+  gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
+      &stop_type, &stop);
+
+  /* sanity checks */
+
+  /* we can only seek on time */
+  if (format != GST_FORMAT_TIME) {
+    GST_DEBUG_OBJECT (parse, "Can only seek on TIME");
+    return FALSE;
+  }
+
+  if (stop_type != GST_SEEK_TYPE_NONE && stop != GST_CLOCK_TIME_NONE) {
+    GST_DEBUG_OBJECT (parse, "Seek end-time not supported in streaming mode");
+    return FALSE;
+  }
+
+  if (!(flags & GST_SEEK_FLAG_FLUSH)) {
+    GST_DEBUG_OBJECT (parse,
+        "Non-flushing seek not supported in streaming mode");
+    return FALSE;
+  }
+
+  if (flags & GST_SEEK_FLAG_SEGMENT) {
+    GST_DEBUG_OBJECT (parse, "Segment seek not supported in streaming mode");
+    return FALSE;
+  }
+
+  /* check for having parsed index already */
+  if (!parse->common.index_parsed) {
+    gboolean building_index;
+    guint64 offset = 0;
+
+    if (!parse->index_offset) {
+      GST_DEBUG_OBJECT (parse, "no index (location); no seek in push mode");
+      return FALSE;
+    }
+
+    GST_OBJECT_LOCK (parse);
+    /* handle the seek event in the chain function */
+    parse->common.state = GST_MATROSKA_READ_STATE_SEEK;
+    /* no more seek can be issued until state reset to _DATA */
+
+    /* copy the event */
+    if (parse->seek_event)
+      gst_event_unref (parse->seek_event);
+    parse->seek_event = gst_event_ref (event);
+
+    /* set the building_index flag so that only one thread can setup the
+     * structures for index seeking. */
+    building_index = parse->building_index;
+    if (!building_index) {
+      parse->building_index = TRUE;
+      offset = parse->index_offset;
+    }
+    GST_OBJECT_UNLOCK (parse);
+
+    if (!building_index) {
+      /* seek to the first subindex or legacy index */
+      GST_INFO_OBJECT (parse, "Seeking to Cues at %" G_GUINT64_FORMAT, offset);
+      return perform_seek_to_offset (parse, offset);
+    }
+
+    /* well, we are handling it already */
+    return TRUE;
+  }
+
+  /* delegate to tweaked regular seek */
+  return gst_matroska_parse_handle_seek_event (parse, pad, event);
+}
+
+static gboolean
+gst_matroska_parse_handle_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstMatroskaParse *parse = GST_MATROSKA_PARSE (parent);
+  gboolean res = TRUE;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+      /* no seeking until we are (safely) ready */
+      if (parse->common.state != GST_MATROSKA_READ_STATE_DATA) {
+        GST_DEBUG_OBJECT (parse, "not ready for seeking yet");
+        return FALSE;
+      }
+      res = gst_matroska_parse_handle_seek_push (parse, pad, event);
+      gst_event_unref (event);
+      break;
+
+    case GST_EVENT_QOS:
+    {
+      GstMatroskaTrackContext *context = gst_pad_get_element_private (pad);
+      if (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
+        GstMatroskaTrackVideoContext *videocontext =
+            (GstMatroskaTrackVideoContext *) context;
+        gdouble proportion;
+        GstClockTimeDiff diff;
+        GstClockTime timestamp;
+
+        gst_event_parse_qos (event, NULL, &proportion, &diff, &timestamp);
+
+        GST_OBJECT_LOCK (parse);
+        videocontext->earliest_time = timestamp + diff;
+        GST_OBJECT_UNLOCK (parse);
+      }
+      res = TRUE;
+      gst_event_unref (event);
+      break;
+    }
+
+      /* events we don't need to handle */
+    case GST_EVENT_NAVIGATION:
+      gst_event_unref (event);
+      res = FALSE;
+      break;
+
+    case GST_EVENT_LATENCY:
+    default:
+      res = gst_pad_push_event (parse->common.sinkpad, event);
+      break;
+  }
+
+  return res;
+}
+
+static GstFlowReturn
+gst_matroska_parse_parse_tracks (GstMatroskaParse * parse, GstEbmlRead * ebml)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint32 id;
+
+  DEBUG_ELEMENT_START (parse, ebml, "Tracks");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (parse, ebml, "Tracks", 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 track within the "all-tracks" header */
+      case GST_MATROSKA_ID_TRACKENTRY:
+        ret = gst_matroska_parse_add_stream (parse, ebml);
+        break;
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "Track", id);
+        break;
+    }
+  }
+  DEBUG_ELEMENT_STOP (parse, ebml, "Tracks", ret);
+
+  parse->tracks_parsed = TRUE;
+
+  return ret;
+}
+
+/*
+ * Read signed/unsigned "EBML" numbers.
+ * Return: number of bytes processed.
+ */
+
+static gint
+gst_matroska_ebmlnum_uint (guint8 * data, guint size, guint64 * num)
+{
+  gint len_mask = 0x80, read = 1, n = 1, num_ffs = 0;
+  guint64 total;
+
+  if (size <= 0) {
+    return -1;
+  }
+
+  total = data[0];
+  while (read <= 8 && !(total & len_mask)) {
+    read++;
+    len_mask >>= 1;
+  }
+  if (read > 8)
+    return -1;
+
+  if ((total &= (len_mask - 1)) == len_mask - 1)
+    num_ffs++;
+  if (size < read)
+    return -1;
+  while (n < read) {
+    if (data[n] == 0xff)
+      num_ffs++;
+    total = (total << 8) | data[n];
+    n++;
+  }
+
+  if (read == num_ffs && total != 0)
+    *num = G_MAXUINT64;
+  else
+    *num = total;
+
+  return read;
+}
+
+static gint
+gst_matroska_ebmlnum_sint (guint8 * data, guint size, gint64 * num)
+{
+  guint64 unum;
+  gint res;
+
+  /* read as unsigned number first */
+  if ((res = gst_matroska_ebmlnum_uint (data, size, &unum)) < 0)
+    return -1;
+
+  /* make signed */
+  if (unum == G_MAXUINT64)
+    *num = G_MAXINT64;
+  else
+    *num = unum - ((1 << ((7 * res) - 1)) - 1);
+
+  return res;
+}
+
+static GstFlowReturn
+gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
+    GstEbmlRead * ebml, guint64 cluster_time, guint64 cluster_offset,
+    gboolean is_simpleblock)
+{
+  GstMatroskaTrackContext *stream = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+  gboolean readblock = FALSE;
+  guint32 id;
+  guint64 block_duration = 0;
+  GstBuffer *buf = NULL;
+  GstMapInfo map;
+  gint stream_num = -1, n, laces = 0;
+  guint size = 0;
+  gint *lace_size = NULL;
+  gint64 time = 0;
+  gint flags = 0;
+  gint64 referenceblock = 0;
+
+  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
+    if (!is_simpleblock) {
+      if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) {
+        goto data_error;
+      }
+    } else {
+      id = GST_MATROSKA_ID_SIMPLEBLOCK;
+    }
+
+    switch (id) {
+        /* one block inside the group. Note, block parsing is one
+         * of the harder things, so this code is a bit complicated.
+         * See http://www.matroska.org/ for documentation. */
+      case GST_MATROSKA_ID_SIMPLEBLOCK:
+      case GST_MATROSKA_ID_BLOCK:
+      {
+        guint64 num;
+        guint8 *data;
+
+        if (buf) {
+          gst_buffer_unref (buf);
+          buf = NULL;
+        }
+        if ((ret = gst_ebml_read_buffer (ebml, &id, &buf)) != GST_FLOW_OK)
+          break;
+
+        gst_buffer_map (buf, &map, GST_MAP_READ);
+        data = map.data;
+        size = map.size;
+
+        /* first byte(s): blocknum */
+        if ((n = gst_matroska_ebmlnum_uint (data, size, &num)) < 0)
+          goto data_error;
+        data += n;
+        size -= n;
+
+        /* fetch stream from 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->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
+              "; ignoring block", stream_num, num);
+          goto done;
+        }
+
+        stream = g_ptr_array_index (parse->common.src, stream_num);
+
+        /* time (relative to cluster time) */
+        time = ((gint16) GST_READ_UINT16_BE (data));
+        data += 2;
+        size -= 2;
+        flags = GST_READ_UINT8 (data);
+        data += 1;
+        size -= 1;
+
+        GST_LOG_OBJECT (parse, "time %" G_GUINT64_FORMAT ", flags %d", time,
+            flags);
+
+        switch ((flags & 0x06) >> 1) {
+          case 0x0:            /* no lacing */
+            laces = 1;
+            lace_size = g_new (gint, 1);
+            lace_size[0] = size;
+            break;
+
+          case 0x1:            /* xiph lacing */
+          case 0x2:            /* fixed-size lacing */
+          case 0x3:            /* EBML lacing */
+            if (size == 0)
+              goto invalid_lacing;
+            laces = GST_READ_UINT8 (data) + 1;
+            data += 1;
+            size -= 1;
+            lace_size = g_new0 (gint, laces);
+
+            switch ((flags & 0x06) >> 1) {
+              case 0x1:        /* xiph lacing */  {
+                guint temp, total = 0;
+
+                for (n = 0; ret == GST_FLOW_OK && n < laces - 1; n++) {
+                  while (1) {
+                    if (size == 0)
+                      goto invalid_lacing;
+                    temp = GST_READ_UINT8 (data);
+                    lace_size[n] += temp;
+                    data += 1;
+                    size -= 1;
+                    if (temp != 0xff)
+                      break;
+                  }
+                  total += lace_size[n];
+                }
+                lace_size[n] = size - total;
+                break;
+              }
+
+              case 0x2:        /* fixed-size lacing */
+                for (n = 0; n < laces; n++)
+                  lace_size[n] = size / laces;
+                break;
+
+              case 0x3:        /* EBML lacing */  {
+                guint total;
+
+                if ((n = gst_matroska_ebmlnum_uint (data, size, &num)) < 0)
+                  goto data_error;
+                data += n;
+                size -= n;
+                total = lace_size[0] = num;
+                for (n = 1; ret == GST_FLOW_OK && n < laces - 1; n++) {
+                  gint64 snum;
+                  gint r;
+
+                  if ((r = gst_matroska_ebmlnum_sint (data, size, &snum)) < 0)
+                    goto data_error;
+                  data += r;
+                  size -= r;
+                  lace_size[n] = lace_size[n - 1] + snum;
+                  total += lace_size[n];
+                }
+                if (n < laces)
+                  lace_size[n] = size - total;
+                break;
+              }
+            }
+            break;
+        }
+
+        if (ret != GST_FLOW_OK)
+          break;
+
+        readblock = TRUE;
+        break;
+      }
+
+      case GST_MATROSKA_ID_BLOCKDURATION:{
+        ret = gst_ebml_read_uint (ebml, &id, &block_duration);
+        GST_DEBUG_OBJECT (parse, "BlockDuration: %" G_GUINT64_FORMAT,
+            block_duration);
+        break;
+      }
+
+      case GST_MATROSKA_ID_REFERENCEBLOCK:{
+        ret = gst_ebml_read_sint (ebml, &id, &referenceblock);
+        GST_DEBUG_OBJECT (parse, "ReferenceBlock: %" G_GINT64_FORMAT,
+            referenceblock);
+        break;
+      }
+
+      case GST_MATROSKA_ID_CODECSTATE:{
+        guint8 *data;
+        guint64 data_len = 0;
+
+        if ((ret =
+                gst_ebml_read_binary (ebml, &id, &data,
+                    &data_len)) != GST_FLOW_OK)
+          break;
+
+        if (G_UNLIKELY (stream == NULL)) {
+          GST_WARNING_OBJECT (parse,
+              "Unexpected CodecState subelement - ignoring");
+          break;
+        }
+
+        g_free (stream->codec_state);
+        stream->codec_state = data;
+        stream->codec_state_size = data_len;
+
+        break;
+      }
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "BlockGroup", id);
+        break;
+
+      case GST_MATROSKA_ID_BLOCKVIRTUAL:
+      case GST_MATROSKA_ID_BLOCKADDITIONS:
+      case GST_MATROSKA_ID_REFERENCEPRIORITY:
+      case GST_MATROSKA_ID_REFERENCEVIRTUAL:
+      case GST_MATROSKA_ID_SLICES:
+        GST_DEBUG_OBJECT (parse,
+            "Skipping BlockGroup subelement 0x%x - ignoring", id);
+        ret = gst_ebml_read_skip (ebml);
+        break;
+    }
+
+    if (is_simpleblock)
+      break;
+  }
+
+  /* reading a number or so could have failed */
+  if (ret != GST_FLOW_OK)
+    goto data_error;
+
+  if (ret == GST_FLOW_OK && readblock) {
+    guint64 duration = 0;
+    gint64 lace_time = 0;
+    gboolean delta_unit;
+
+    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?
+       * Drop unless the lace contains timestamp 0? */
+      if (time < 0 && (-time) > cluster_time) {
+        lace_time = 0;
+      } else {
+        if (stream->timecodescale == 1.0)
+          lace_time = (cluster_time + time) * parse->common.time_scale;
+        else
+          lace_time =
+              gst_util_guint64_to_gdouble ((cluster_time + time) *
+              parse->common.time_scale) * stream->timecodescale;
+      }
+    } else {
+      lace_time = GST_CLOCK_TIME_NONE;
+    }
+
+    if (lace_time != GST_CLOCK_TIME_NONE) {
+      parse->last_timestamp = lace_time;
+    }
+    /* need to refresh segment info ASAP */
+    if (GST_CLOCK_TIME_IS_VALID (lace_time) && parse->need_newsegment) {
+      GstSegment segment;
+      GST_DEBUG_OBJECT (parse,
+          "generating segment starting at %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (lace_time));
+      /* pretend we seeked here */
+      gst_segment_do_seek (&parse->common.segment, parse->common.segment.rate,
+          GST_FORMAT_TIME, 0, GST_SEEK_TYPE_SET, lace_time,
+          GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE, NULL);
+      /* now convey our segment notion downstream */
+      segment = parse->common.segment;
+      segment.position = segment.start;
+      gst_matroska_parse_send_event (parse, gst_event_new_segment (&segment));
+      parse->need_newsegment = FALSE;
+    }
+
+    if (block_duration) {
+      if (stream->timecodescale == 1.0)
+        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->common.time_scale,
+                    1)) * stream->timecodescale);
+    } else if (stream->default_duration) {
+      duration = stream->default_duration * laces;
+    }
+    /* else duration is diff between timecode of this and next block */
+
+    /* For SimpleBlock, look at the keyframe bit in flags. Otherwise,
+       a ReferenceBlock implies that this is not a keyframe. In either
+       case, it only makes sense for video streams. */
+    delta_unit = stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
+        ((is_simpleblock && !(flags & 0x80)) || referenceblock);
+
+    if (delta_unit && stream->set_discont) {
+      /* When doing seeks or such, we need to restart on key frames or
+       * decoders might choke. */
+      GST_DEBUG_OBJECT (parse, "skipping delta unit");
+      goto done;
+    }
+
+    for (n = 0; n < laces; n++) {
+      if (G_UNLIKELY (lace_size[n] > size)) {
+        GST_WARNING_OBJECT (parse, "Invalid lace size");
+        break;
+      }
+
+      /* QoS for video track with an index. the assumption is that
+         index entries point to keyframes, but if that is not true we
+         will instad skip until the next keyframe. */
+      if (GST_CLOCK_TIME_IS_VALID (lace_time) &&
+          stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
+          stream->index_table && parse->common.segment.rate > 0.0) {
+        GstMatroskaTrackVideoContext *videocontext =
+            (GstMatroskaTrackVideoContext *) stream;
+        GstClockTime earliest_time;
+        GstClockTime earliest_stream_time;
+
+        GST_OBJECT_LOCK (parse);
+        earliest_time = videocontext->earliest_time;
+        GST_OBJECT_UNLOCK (parse);
+        earliest_stream_time =
+            gst_segment_position_from_running_time (&parse->common.segment,
+            GST_FORMAT_TIME, earliest_time);
+
+        if (GST_CLOCK_TIME_IS_VALID (lace_time) &&
+            GST_CLOCK_TIME_IS_VALID (earliest_stream_time) &&
+            lace_time <= earliest_stream_time) {
+          /* find index entry (keyframe) <= earliest_stream_time */
+          GstMatroskaIndex *entry =
+              gst_util_array_binary_search (stream->index_table->data,
+              stream->index_table->len, sizeof (GstMatroskaIndex),
+              (GCompareDataFunc) gst_matroska_index_seek_find,
+              GST_SEARCH_MODE_BEFORE, &earliest_stream_time, NULL);
+
+          /* if that entry (keyframe) is after the current the current
+             buffer, we can skip pushing (and thus decoding) all
+             buffers until that keyframe. */
+          if (entry && GST_CLOCK_TIME_IS_VALID (entry->time) &&
+              entry->time > lace_time) {
+            GST_LOG_OBJECT (parse, "Skipping lace before late keyframe");
+            stream->set_discont = TRUE;
+            goto next_lace;
+          }
+        }
+      }
+#if 0
+      sub = gst_buffer_create_sub (buf,
+          GST_BUFFER_SIZE (buf) - size, lace_size[n]);
+      GST_DEBUG_OBJECT (parse, "created subbuffer %p", sub);
+
+      if (delta_unit)
+        GST_BUFFER_FLAG_SET (sub, GST_BUFFER_FLAG_DELTA_UNIT);
+      else
+        GST_BUFFER_FLAG_UNSET (sub, GST_BUFFER_FLAG_DELTA_UNIT);
+
+      if (stream->encodings != NULL && stream->encodings->len > 0)
+        sub = gst_matroska_decode_buffer (stream, sub);
+
+      if (sub == NULL) {
+        GST_WARNING_OBJECT (parse, "Decoding buffer failed");
+        goto next_lace;
+      }
+
+      GST_BUFFER_TIMESTAMP (sub) = lace_time;
+
+      if (GST_CLOCK_TIME_IS_VALID (lace_time)) {
+        GstClockTime last_stop_end;
+
+        /* Check if this stream is after segment stop */
+        if (GST_CLOCK_TIME_IS_VALID (parse->common.segment.stop) &&
+            lace_time >= parse->common.segment.stop) {
+          GST_DEBUG_OBJECT (parse,
+              "Stream %d after segment stop %" GST_TIME_FORMAT, stream->index,
+              GST_TIME_ARGS (parse->common.segment.stop));
+          gst_buffer_unref (sub);
+          goto eos;
+        }
+        if (offset >= stream->to_offset) {
+          GST_DEBUG_OBJECT (parse, "Stream %d after playback section",
+              stream->index);
+          gst_buffer_unref (sub);
+          goto eos;
+        }
+
+        /* handle gaps, e.g. non-zero start-time, or an cue index entry
+         * that landed us with timestamps not quite intended */
+        if (GST_CLOCK_TIME_IS_VALID (parse->segment.last_stop) &&
+            parse->segment.rate > 0.0) {
+          GstClockTimeDiff diff;
+
+          /* only send newsegments with increasing start times,
+           * otherwise if these go back and forth downstream (sinks) increase
+           * accumulated time and running_time */
+          diff = GST_CLOCK_DIFF (parse->segment.last_stop, lace_time);
+          if (diff > 2 * GST_SECOND && lace_time > parse->segment.start &&
+              (!GST_CLOCK_TIME_IS_VALID (parse->segment.stop) ||
+                  lace_time < parse->segment.stop)) {
+            GST_DEBUG_OBJECT (parse,
+                "Gap of %" G_GINT64_FORMAT " ns detected in"
+                "stream %d (%" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "). "
+                "Sending updated NEWSEGMENT events", diff,
+                stream->index, GST_TIME_ARGS (stream->pos),
+                GST_TIME_ARGS (lace_time));
+            /* send newsegment events such that the gap is not accounted in
+             * accum time, hence running_time */
+            /* close ahead of gap */
+            gst_matroska_parse_send_event (parse,
+                gst_event_new_new_segment (TRUE, parse->segment.rate,
+                    parse->segment.format, parse->segment.last_stop,
+                    parse->segment.last_stop, parse->segment.last_stop));
+            /* skip gap */
+            gst_matroska_parse_send_event (parse,
+                gst_event_new_new_segment (FALSE, parse->segment.rate,
+                    parse->segment.format, lace_time, parse->segment.stop,
+                    lace_time));
+            /* align segment view with downstream,
+             * prevents double-counting accum when closing segment */
+            gst_segment_set_newsegment (&parse->segment, FALSE,
+                parse->segment.rate, parse->segment.format, lace_time,
+                parse->segment.stop, lace_time);
+            parse->segment.last_stop = lace_time;
+          }
+        }
+
+        if (!GST_CLOCK_TIME_IS_VALID (parse->segment.last_stop)
+            || parse->segment.last_stop < lace_time) {
+          parse->segment.last_stop = lace_time;
+        }
+
+        last_stop_end = lace_time;
+        if (duration) {
+          GST_BUFFER_DURATION (sub) = duration / laces;
+          last_stop_end += GST_BUFFER_DURATION (sub);
+        }
+
+        if (!GST_CLOCK_TIME_IS_VALID (parse->last_stop_end) ||
+            parse->last_stop_end < last_stop_end)
+          parse->last_stop_end = last_stop_end;
+
+        if (parse->segment.duration == -1 ||
+            parse->segment.duration < lace_time) {
+          gst_segment_set_duration (&parse->segment, GST_FORMAT_TIME,
+              last_stop_end);
+          gst_element_post_message (GST_ELEMENT_CAST (parse),
+              gst_message_new_duration (GST_OBJECT_CAST (parse),
+                  GST_FORMAT_TIME, GST_CLOCK_TIME_NONE));
+        }
+      }
+
+      stream->pos = lace_time;
+
+      gst_matroska_parse_sync_streams (parse);
+
+      if (stream->set_discont) {
+        GST_DEBUG_OBJECT (parse, "marking DISCONT");
+        GST_BUFFER_FLAG_SET (sub, GST_BUFFER_FLAG_DISCONT);
+        stream->set_discont = FALSE;
+      }
+
+      /* reverse playback book-keeping */
+      if (!GST_CLOCK_TIME_IS_VALID (stream->from_time))
+        stream->from_time = lace_time;
+      if (stream->from_offset == -1)
+        stream->from_offset = offset;
+
+      GST_DEBUG_OBJECT (parse,
+          "Pushing lace %d, data of size %d for stream %d, time=%"
+          GST_TIME_FORMAT " and duration=%" GST_TIME_FORMAT, n,
+          GST_BUFFER_SIZE (sub), stream_num,
+          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (sub)),
+          GST_TIME_ARGS (GST_BUFFER_DURATION (sub)));
+
+      if (parse->element_index) {
+        if (stream->index_writer_id == -1)
+          gst_index_get_writer_id (parse->element_index,
+              GST_OBJECT (stream->pad), &stream->index_writer_id);
+
+        GST_LOG_OBJECT (parse, "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 (parse->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,
+            cluster_offset, NULL);
+      }
+
+      gst_buffer_set_caps (sub, GST_PAD_CAPS (parse->srcpad));
+
+      /* Postprocess the buffers depending on the codec used */
+      if (stream->postprocess_frame) {
+        GST_LOG_OBJECT (parse, "running post process");
+        ret = stream->postprocess_frame (GST_ELEMENT (parse), stream, &sub);
+      }
+
+      ret = gst_pad_push (stream->pad, sub);
+      if (parse->segment.rate < 0) {
+        if (lace_time > parse->segment.stop && ret == GST_FLOW_EOS) {
+          /* In reverse playback we can get a GST_FLOW_EOS when
+           * we are at the end of the segment, so we just need to jump
+           * back to the previous section. */
+          GST_DEBUG_OBJECT (parse, "downstream has reached end of segment");
+          ret = GST_FLOW_OK;
+        }
+      }
+      /* combine flows */
+      ret = gst_matroska_parse_combine_flows (parse, stream, ret);
+#endif
+
+    next_lace:
+      size -= lace_size[n];
+      if (lace_time != GST_CLOCK_TIME_NONE && duration)
+        lace_time += duration / laces;
+      else
+        lace_time = GST_CLOCK_TIME_NONE;
+    }
+  }
+
+done:
+  if (buf) {
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+  }
+  g_free (lace_size);
+
+  return ret;
+
+  /* EXITS */
+invalid_lacing:
+  {
+    GST_ELEMENT_WARNING (parse, STREAM, DEMUX, (NULL), ("Invalid lacing size"));
+    /* non-fatal, try next block(group) */
+    ret = GST_FLOW_OK;
+    goto done;
+  }
+data_error:
+  {
+    GST_ELEMENT_WARNING (parse, STREAM, DEMUX, (NULL), ("Data error"));
+    /* non-fatal, try next block(group) */
+    ret = GST_FLOW_OK;
+    goto done;
+  }
+}
+
+/* return FALSE if block(group) should be skipped (due to a seek) */
+static inline gboolean
+gst_matroska_parse_seek_block (GstMatroskaParse * parse)
+{
+  if (G_UNLIKELY (parse->seek_block)) {
+    if (!(--parse->seek_block)) {
+      return TRUE;
+    } else {
+      GST_LOG_OBJECT (parse, "should skip block due to seek");
+      return FALSE;
+    }
+  } else {
+    return TRUE;
+  }
+}
+
+static GstFlowReturn
+gst_matroska_parse_parse_contents_seekentry (GstMatroskaParse * parse,
+    GstEbmlRead * ebml)
+{
+  GstFlowReturn ret;
+  guint64 seek_pos = (guint64) - 1;
+  guint32 seek_id = 0;
+  guint32 id;
+
+  DEBUG_ELEMENT_START (parse, ebml, "Seek");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (parse, ebml, "Seek", 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) {
+      case GST_MATROSKA_ID_SEEKID:
+      {
+        guint64 t;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &t)) != GST_FLOW_OK)
+          break;
+
+        GST_DEBUG_OBJECT (parse, "SeekID: %" G_GUINT64_FORMAT, t);
+        seek_id = t;
+        break;
+      }
+
+      case GST_MATROSKA_ID_SEEKPOSITION:
+      {
+        guint64 t;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &t)) != GST_FLOW_OK)
+          break;
+
+        if (t > G_MAXINT64) {
+          GST_WARNING_OBJECT (parse,
+              "Too large SeekPosition %" G_GUINT64_FORMAT, t);
+          break;
+        }
+
+        GST_DEBUG_OBJECT (parse, "SeekPosition: %" G_GUINT64_FORMAT, t);
+        seek_pos = t;
+        break;
+      }
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "SeekHead", id);
+        break;
+    }
+  }
+
+  if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS)
+    return ret;
+
+  if (!seek_id || seek_pos == (guint64) - 1) {
+    GST_WARNING_OBJECT (parse, "Incomplete seekhead entry (0x%x/%"
+        G_GUINT64_FORMAT ")", seek_id, seek_pos);
+    return GST_FLOW_OK;
+  }
+
+  switch (seek_id) {
+    case GST_MATROSKA_ID_SEEKHEAD:
+    {
+    }
+    case GST_MATROSKA_ID_CUES:
+    case GST_MATROSKA_ID_TAGS:
+    case GST_MATROSKA_ID_TRACKS:
+    case GST_MATROSKA_ID_SEGMENTINFO:
+    case GST_MATROSKA_ID_ATTACHMENTS:
+    case GST_MATROSKA_ID_CHAPTERS:
+    {
+      guint64 length;
+
+      /* remember */
+      length = gst_matroska_read_common_get_length (&parse->common);
+
+      if (length == (guint64) - 1) {
+        GST_DEBUG_OBJECT (parse, "no upstream length, skipping SeakHead entry");
+        break;
+      }
+
+      /* check for validity */
+      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->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->common.ebml_segment_start;
+        GST_DEBUG_OBJECT (parse, "Cues located at offset %" G_GUINT64_FORMAT,
+            parse->index_offset);
+      }
+      break;
+    }
+
+    default:
+      GST_DEBUG_OBJECT (parse, "Ignoring Seek entry for ID=0x%x", seek_id);
+      break;
+  }
+  DEBUG_ELEMENT_STOP (parse, ebml, "Seek", ret);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_matroska_parse_parse_contents (GstMatroskaParse * parse, GstEbmlRead * ebml)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint32 id;
+
+  DEBUG_ELEMENT_START (parse, ebml, "SeekHead");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (parse, ebml, "SeekHead", 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) {
+      case GST_MATROSKA_ID_SEEKENTRY:
+      {
+        ret = gst_matroska_parse_parse_contents_seekentry (parse, ebml);
+        /* Ignore EOS and errors here */
+        if (ret != GST_FLOW_OK) {
+          GST_DEBUG_OBJECT (parse, "Ignoring %s", gst_flow_get_name (ret));
+          ret = GST_FLOW_OK;
+        }
+        break;
+      }
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "SeekHead", id);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (parse, ebml, "SeekHead", ret);
+
+  return ret;
+}
+
+#define GST_FLOW_OVERFLOW   GST_FLOW_CUSTOM_ERROR
+
+#define MAX_BLOCK_SIZE (15 * 1024 * 1024)
+
+static inline GstFlowReturn
+gst_matroska_parse_check_read_size (GstMatroskaParse * parse, guint64 bytes)
+{
+  if (G_UNLIKELY (bytes > MAX_BLOCK_SIZE)) {
+    /* only a few blocks are expected/allowed to be large,
+     * and will be recursed into, whereas others will be read and must fit */
+    /* fatal in streaming case, as we can't step over easily */
+    GST_ELEMENT_ERROR (parse, STREAM, DEMUX, (NULL),
+        ("reading large block of size %" G_GUINT64_FORMAT " not supported; "
+            "file might be corrupt.", bytes));
+    return GST_FLOW_ERROR;
+  } else {
+    return GST_FLOW_OK;
+  }
+}
+
+#if 0
+/* returns TRUE if we truely are in error state, and should give up */
+static inline gboolean
+gst_matroska_parse_check_parse_error (GstMatroskaParse * parse)
+{
+  gint64 pos;
+
+  /* sigh, one last attempt above and beyond call of duty ...;
+   * search for cluster mark following current pos */
+  pos = parse->common.offset;
+  GST_WARNING_OBJECT (parse, "parse error, looking for next cluster");
+  if (gst_matroska_parse_search_cluster (parse, &pos) != GST_FLOW_OK) {
+    /* did not work, give up */
+    return TRUE;
+  } else {
+    GST_DEBUG_OBJECT (parse, "... found at  %" G_GUINT64_FORMAT, pos);
+    /* try that position */
+    parse->common.offset = pos;
+    return FALSE;
+  }
+}
+#endif
+
+/* initializes @ebml with @bytes from input stream at current offset.
+ * Returns EOS if insufficient available,
+ * ERROR if too much was attempted to read. */
+static inline GstFlowReturn
+gst_matroska_parse_take (GstMatroskaParse * parse, guint64 bytes,
+    GstEbmlRead * ebml)
+{
+  GstBuffer *buffer = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  GST_LOG_OBJECT (parse, "taking %" G_GUINT64_FORMAT " bytes for parsing",
+      bytes);
+  ret = gst_matroska_parse_check_read_size (parse, bytes);
+  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+    /* otherwise fatal */
+    ret = GST_FLOW_ERROR;
+    goto exit;
+  }
+  if (gst_adapter_available (parse->common.adapter) < bytes)
+    return GST_FLOW_EOS;
+
+  buffer = gst_adapter_take_buffer (parse->common.adapter, bytes);
+  if (G_LIKELY (buffer)) {
+    gst_ebml_read_init (ebml, GST_ELEMENT_CAST (parse), buffer,
+        parse->common.offset);
+    parse->common.offset += bytes;
+  } else {
+    ret = GST_FLOW_ERROR;
+  }
+exit:
+
+  return ret;
+}
+
+static void
+gst_matroska_parse_check_seekability (GstMatroskaParse * parse)
+{
+  GstQuery *query;
+  gboolean seekable = FALSE;
+  gint64 start = -1, stop = -1;
+
+  query = gst_query_new_seeking (GST_FORMAT_BYTES);
+  if (!gst_pad_peer_query (parse->common.sinkpad, query)) {
+    GST_DEBUG_OBJECT (parse, "seeking query failed");
+    goto done;
+  }
+
+  gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
+
+  /* try harder to query upstream size if we didn't get it the first time */
+  if (seekable && stop == -1) {
+    GST_DEBUG_OBJECT (parse, "doing duration query to fix up unset stop");
+    gst_pad_peer_query_duration (parse->common.sinkpad, GST_FORMAT_BYTES,
+        &stop);
+  }
+
+  /* if upstream doesn't know the size, it's likely that it's not seekable in
+   * practice even if it technically may be seekable */
+  if (seekable && (start != 0 || stop <= start)) {
+    GST_DEBUG_OBJECT (parse, "seekable but unknown start/stop -> disable");
+    seekable = FALSE;
+  }
+
+done:
+  GST_INFO_OBJECT (parse, "seekable: %d (%" G_GUINT64_FORMAT " - %"
+      G_GUINT64_FORMAT ")", seekable, start, stop);
+  parse->seekable = seekable;
+
+  gst_query_unref (query);
+}
+
+#if 0
+static GstFlowReturn
+gst_matroska_parse_find_tracks (GstMatroskaParse * parse)
+{
+  guint32 id;
+  guint64 before_pos;
+  guint64 length;
+  guint needed;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  GST_WARNING_OBJECT (parse,
+      "Found Cluster element before Tracks, searching Tracks");
+
+  /* remember */
+  before_pos = parse->common.offset;
+
+  /* Search Tracks element */
+  while (TRUE) {
+    ret = gst_matroska_read_common_peek_id_length_pull (&parse->common,
+        GST_ELEMENT_CAST (parse), &id, &length, &needed);
+    if (ret != GST_FLOW_OK)
+      break;
+
+    if (id != GST_MATROSKA_ID_TRACKS) {
+      /* we may be skipping large cluster here, so forego size check etc */
+      /* ... but we can't skip undefined size; force error */
+      if (length == G_MAXUINT64) {
+        ret = gst_matroska_parse_check_read_size (parse, length);
+        break;
+      } else {
+        parse->common.offset += needed;
+        parse->offset += length;
+      }
+      continue;
+    }
+
+    /* will lead to track parsing ... */
+    ret = gst_matroska_parse_parse_id (parse, id, length, needed);
+    break;
+  }
+
+  /* seek back */
+  parse->offset = before_pos;
+
+  return ret;
+}
+#endif
+
+#define GST_READ_CHECK(stmt)  \
+G_STMT_START { \
+  if (G_UNLIKELY ((ret = (stmt)) != GST_FLOW_OK)) { \
+    if (ret == GST_FLOW_OVERFLOW) { \
+      ret = GST_FLOW_OK; \
+    } \
+    goto read_error; \
+  } \
+} G_STMT_END
+
+static void
+gst_matroska_parse_accumulate_streamheader (GstMatroskaParse * parse,
+    GstBuffer * buffer)
+{
+  if (parse->pushed_headers) {
+    GST_WARNING_OBJECT (parse,
+        "Accumulating headers, but headers are already pushed");
+  }
+
+  if (parse->streamheader) {
+    parse->streamheader = gst_buffer_append (parse->streamheader,
+        gst_buffer_ref (buffer));
+  } else {
+    parse->streamheader = gst_buffer_ref (buffer);
+  }
+
+  GST_DEBUG ("%" G_GSIZE_FORMAT, gst_buffer_get_size (parse->streamheader));
+}
+
+static GstFlowReturn
+gst_matroska_parse_output (GstMatroskaParse * parse, GstBuffer * buffer,
+    gboolean keyframe)
+{
+  GstFlowReturn ret;
+
+  if (!parse->pushed_headers) {
+    GstCaps *caps;
+    GstStructure *s;
+    GValue streamheader = { 0 };
+    GValue bufval = { 0 };
+    GstBuffer *buf;
+
+    caps = gst_pad_get_current_caps (parse->common.sinkpad);
+    if (caps == NULL) {
+      caps = gst_matroska_parse_forge_caps (parse->common.is_webm,
+          parse->common.has_video);
+    } else
+      caps = gst_caps_make_writable (caps);
+
+    s = gst_caps_get_structure (caps, 0);
+    g_value_init (&streamheader, GST_TYPE_ARRAY);
+    g_value_init (&bufval, GST_TYPE_BUFFER);
+    buf = gst_buffer_copy (parse->streamheader);
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
+    gst_value_set_buffer (&bufval, buf);
+    gst_buffer_unref (buf);
+    gst_value_array_append_value (&streamheader, &bufval);
+    g_value_unset (&bufval);
+    gst_structure_set_value (s, "streamheader", &streamheader);
+    g_value_unset (&streamheader);
+    //gst_caps_replace (parse->caps, caps);
+    gst_pad_set_caps (parse->srcpad, caps);
+
+    if (parse->need_newsegment) {
+      gst_pad_push_event (parse->srcpad,
+          gst_event_new_segment (&parse->common.segment));
+      parse->need_newsegment = FALSE;
+    }
+
+    buf = gst_buffer_copy (parse->streamheader);
+    gst_caps_unref (caps);
+
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+    ret = gst_pad_push (parse->srcpad, buf);
+    if (ret != GST_FLOW_OK) {
+      GST_WARNING_OBJECT (parse, "Failed to push buffer");
+      return ret;
+    }
+
+    parse->pushed_headers = TRUE;
+  }
+
+  if (!keyframe) {
+    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
+  } else {
+    GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
+  }
+  if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE) {
+    parse->last_timestamp = GST_BUFFER_TIMESTAMP (buffer);
+  } else {
+    GST_BUFFER_TIMESTAMP (buffer) = parse->last_timestamp;
+  }
+
+  return gst_pad_push (parse->srcpad, gst_buffer_ref (buffer));
+}
+
+static GstFlowReturn
+gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
+    guint64 length, guint needed)
+{
+  GstEbmlRead ebml = { 0, };
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint64 read;
+  //GstBuffer *buffer;
+
+  GST_DEBUG_OBJECT (parse, "Parsing Element id 0x%x, "
+      "size %" G_GUINT64_FORMAT ", prefix %d", id, length, needed);
+
+#if 0
+  if (gst_adapter_available (parse->adapter) >= length + needed) {
+    buffer = gst_adapter_take_buffer (parse->adapter, length + needed);
+    gst_pad_push (parse->srcpad, buffer);
+  } else {
+    ret = GST_FLOW_EOS;
+  }
+  //GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
+
+  return ret;
+#endif
+
+
+
+  /* if we plan to read and parse this element, we need prefix (id + length)
+   * and the contents */
+  /* mind about overflow wrap-around when dealing with undefined size */
+  read = length;
+  if (G_LIKELY (length != G_MAXUINT64))
+    read += needed;
+
+  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_read_common_parse_header (&parse->common, &ebml);
+          if (ret != GST_FLOW_OK)
+            goto parse_failed;
+          parse->common.state = GST_MATROSKA_READ_STATE_SEGMENT;
+          gst_matroska_parse_check_seekability (parse);
+          gst_matroska_parse_accumulate_streamheader (parse, ebml.buf);
+          break;
+        default:
+          goto invalid_header;
+          break;
+      }
+      break;
+    case GST_MATROSKA_READ_STATE_SEGMENT:
+      switch (id) {
+        case GST_MATROSKA_ID_SEGMENT:
+          /* eat segment prefix */
+          GST_READ_CHECK (gst_matroska_parse_take (parse, needed, &ebml));
+          GST_DEBUG_OBJECT (parse,
+              "Found Segment start at offset %" G_GUINT64_FORMAT " with size %"
+              G_GUINT64_FORMAT, parse->common.offset, length);
+          /* seeks are from the beginning of the segment,
+           * after the segment ID/length */
+          parse->common.ebml_segment_start = parse->common.offset;
+          if (length == 0)
+            length = G_MAXUINT64;
+          parse->common.ebml_segment_length = length;
+          parse->common.state = GST_MATROSKA_READ_STATE_HEADER;
+          gst_matroska_parse_accumulate_streamheader (parse, ebml.buf);
+          break;
+        default:
+          GST_WARNING_OBJECT (parse,
+              "Expected a Segment ID (0x%x), but received 0x%x!",
+              GST_MATROSKA_ID_SEGMENT, id);
+          GST_READ_CHECK (gst_matroska_parse_take (parse, needed, &ebml));
+          gst_matroska_parse_accumulate_streamheader (parse, ebml.buf);
+          break;
+      }
+      break;
+    case GST_MATROSKA_READ_STATE_SCANNING:
+      if (id != GST_MATROSKA_ID_CLUSTER &&
+          id != GST_MATROSKA_ID_CLUSTERTIMECODE) {
+        /* we need to skip byte per byte if we are scanning for a new cluster */
+        read = 1;
+        goto skip;
+      } else {
+        GST_LOG_OBJECT (parse, "Resync done, new cluster found!");
+        parse->common.start_resync_offset = -1;
+        parse->common.state = parse->common.state_to_restore;
+      }
+      /* fall-through */
+    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));
+          if (!parse->common.segmentinfo_parsed) {
+            ret = gst_matroska_read_common_parse_info (&parse->common,
+                GST_ELEMENT_CAST (parse), &ebml);
+            if (ret == GST_FLOW_OK)
+              gst_matroska_parse_send_tags (parse);
+          }
+          gst_matroska_parse_accumulate_streamheader (parse, ebml.buf);
+          break;
+        case GST_MATROSKA_ID_TRACKS:
+          GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
+          if (!parse->tracks_parsed) {
+            ret = gst_matroska_parse_parse_tracks (parse, &ebml);
+          }
+          gst_matroska_parse_accumulate_streamheader (parse, ebml.buf);
+          break;
+        case GST_MATROSKA_ID_CLUSTER:
+          if (G_UNLIKELY (!parse->tracks_parsed)) {
+            GST_DEBUG_OBJECT (parse, "Cluster before Track");
+            goto not_streamable;
+          }
+          if (G_UNLIKELY (parse->common.state
+                  == GST_MATROSKA_READ_STATE_HEADER)) {
+            parse->common.state = GST_MATROSKA_READ_STATE_DATA;
+            parse->first_cluster_offset = parse->common.offset;
+            GST_DEBUG_OBJECT (parse, "signaling no more pads");
+          }
+          parse->cluster_time = GST_CLOCK_TIME_NONE;
+          parse->cluster_offset = parse->common.offset;
+          if (G_UNLIKELY (!parse->seek_first && parse->seek_block)) {
+            GST_DEBUG_OBJECT (parse, "seek target block %" G_GUINT64_FORMAT
+                " not found in Cluster, trying next Cluster's first block instead",
+                parse->seek_block);
+            parse->seek_block = 0;
+          }
+          parse->seek_first = FALSE;
+          /* record next cluster for recovery */
+          if (read != G_MAXUINT64)
+            parse->next_cluster_offset = parse->cluster_offset + read;
+          /* eat cluster prefix */
+          GST_READ_CHECK (gst_matroska_parse_take (parse, needed, &ebml));
+          ret = gst_matroska_parse_output (parse, ebml.buf, TRUE);
+          //gst_matroska_parse_accumulate_streamheader (parse, ebml.buf);
+          break;
+        case GST_MATROSKA_ID_CLUSTERTIMECODE:
+        {
+          guint64 num;
+
+          GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
+          if ((ret = gst_ebml_read_uint (&ebml, &id, &num)) != GST_FLOW_OK)
+            goto parse_failed;
+          GST_DEBUG_OBJECT (parse, "ClusterTimeCode: %" G_GUINT64_FORMAT, num);
+          parse->cluster_time = num;
+#if 0
+          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->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);
+          }
+#endif
+          gst_matroska_parse_output (parse, ebml.buf, FALSE);
+          break;
+        }
+        case GST_MATROSKA_ID_BLOCKGROUP:
+          if (!gst_matroska_parse_seek_block (parse))
+            goto skip;
+          GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
+          DEBUG_ELEMENT_START (parse, &ebml, "BlockGroup");
+          if ((ret = gst_ebml_read_master (&ebml, &id)) == GST_FLOW_OK) {
+            ret = gst_matroska_parse_parse_blockgroup_or_simpleblock (parse,
+                &ebml, parse->cluster_time, parse->cluster_offset, FALSE);
+          }
+          DEBUG_ELEMENT_STOP (parse, &ebml, "BlockGroup", ret);
+          gst_matroska_parse_output (parse, ebml.buf, FALSE);
+          break;
+        case GST_MATROSKA_ID_SIMPLEBLOCK:
+          if (!gst_matroska_parse_seek_block (parse))
+            goto skip;
+          GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
+          DEBUG_ELEMENT_START (parse, &ebml, "SimpleBlock");
+          ret = gst_matroska_parse_parse_blockgroup_or_simpleblock (parse,
+              &ebml, parse->cluster_time, parse->cluster_offset, TRUE);
+          DEBUG_ELEMENT_STOP (parse, &ebml, "SimpleBlock", ret);
+          gst_matroska_parse_output (parse, ebml.buf, FALSE);
+          break;
+        case GST_MATROSKA_ID_ATTACHMENTS:
+          GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
+          if (!parse->common.attachments_parsed) {
+            ret = gst_matroska_read_common_parse_attachments (&parse->common,
+                GST_ELEMENT_CAST (parse), &ebml);
+            if (ret == GST_FLOW_OK)
+              gst_matroska_parse_send_tags (parse);
+          }
+          gst_matroska_parse_output (parse, ebml.buf, FALSE);
+          break;
+        case GST_MATROSKA_ID_TAGS:
+          GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
+          ret = gst_matroska_read_common_parse_metadata (&parse->common,
+              GST_ELEMENT_CAST (parse), &ebml);
+          if (ret == GST_FLOW_OK)
+            gst_matroska_parse_send_tags (parse);
+          gst_matroska_parse_accumulate_streamheader (parse, ebml.buf);
+          break;
+        case GST_MATROSKA_ID_CHAPTERS:
+          GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
+          ret = gst_matroska_read_common_parse_chapters (&parse->common, &ebml);
+          gst_matroska_parse_output (parse, ebml.buf, FALSE);
+          break;
+        case GST_MATROSKA_ID_SEEKHEAD:
+          GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
+          ret = gst_matroska_parse_parse_contents (parse, &ebml);
+          gst_matroska_parse_output (parse, ebml.buf, FALSE);
+          break;
+        case GST_MATROSKA_ID_CUES:
+          GST_READ_CHECK (gst_matroska_parse_take (parse, read, &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->common.state == GST_MATROSKA_READ_STATE_SEEK) {
+              GstEvent *event;
+
+              GST_OBJECT_LOCK (parse);
+              event = parse->seek_event;
+              parse->seek_event = NULL;
+              GST_OBJECT_UNLOCK (parse);
+
+              g_assert (event);
+              /* unlikely to fail, since we managed to seek to this point */
+              if (!gst_matroska_parse_handle_seek_event (parse, NULL, event))
+                goto seek_failed;
+              /* resume data handling, main thread clear to seek again */
+              GST_OBJECT_LOCK (parse);
+              parse->common.state = GST_MATROSKA_READ_STATE_DATA;
+              GST_OBJECT_UNLOCK (parse);
+            }
+          }
+          gst_matroska_parse_output (parse, ebml.buf, FALSE);
+          break;
+        case GST_MATROSKA_ID_POSITION:
+        case GST_MATROSKA_ID_PREVSIZE:
+        case GST_MATROSKA_ID_ENCRYPTEDBLOCK:
+        case GST_MATROSKA_ID_SILENTTRACKS:
+          GST_DEBUG_OBJECT (parse,
+              "Skipping Cluster subelement 0x%x - ignoring", id);
+          /* fall-through */
+        default:
+        skip:
+          GST_DEBUG_OBJECT (parse, "skipping Element 0x%x", id);
+          GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
+          gst_matroska_parse_output (parse, ebml.buf, FALSE);
+          break;
+      }
+      break;
+  }
+
+  if (ret == GST_FLOW_PARSE)
+    goto parse_failed;
+
+exit:
+  gst_ebml_read_clear (&ebml);
+  return ret;
+
+  /* ERRORS */
+read_error:
+  {
+    /* simply exit, maybe not enough data yet */
+    /* no ebml to clear if read error */
+    return ret;
+  }
+parse_failed:
+  {
+    GST_ELEMENT_ERROR (parse, STREAM, DEMUX, (NULL),
+        ("Failed to parse Element 0x%x", id));
+    ret = GST_FLOW_ERROR;
+    goto exit;
+  }
+not_streamable:
+  {
+    GST_ELEMENT_ERROR (parse, STREAM, DEMUX, (NULL),
+        ("File layout does not permit streaming"));
+    ret = GST_FLOW_ERROR;
+    goto exit;
+  }
+#if 0
+no_tracks:
+  {
+    GST_ELEMENT_ERROR (parse, STREAM, DEMUX, (NULL),
+        ("No Tracks element found"));
+    ret = GST_FLOW_ERROR;
+    goto exit;
+  }
+#endif
+invalid_header:
+  {
+    GST_ELEMENT_ERROR (parse, STREAM, DEMUX, (NULL), ("Invalid header"));
+    ret = GST_FLOW_ERROR;
+    goto exit;
+  }
+seek_failed:
+  {
+    GST_ELEMENT_ERROR (parse, STREAM, DEMUX, (NULL), ("Failed to seek"));
+    ret = GST_FLOW_ERROR;
+    goto exit;
+  }
+}
+
+#if 0
+static void
+gst_matroska_parse_loop (GstPad * pad)
+{
+  GstMatroskaParse *parse = GST_MATROSKA_PARSE (GST_PAD_PARENT (pad));
+  GstFlowReturn ret;
+  guint32 id;
+  guint64 length;
+  guint needed;
+
+  /* If we have to close a segment, send a new segment to do this now */
+  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;
+    }
+    if (G_UNLIKELY (parse->new_segment)) {
+      gst_matroska_parse_send_event (parse, parse->new_segment);
+      parse->new_segment = NULL;
+    }
+  }
+
+  ret = gst_matroska_read_common_peek_id_length_pull (&parse->common,
+      GST_ELEMENT_CAST (parse), &id, &length, &needed);
+  if (ret == GST_FLOW_EOS)
+    goto eos;
+  if (ret != GST_FLOW_OK) {
+    if (gst_matroska_parse_check_parse_error (parse))
+      goto pause;
+    else
+      return;
+  }
+
+  GST_LOG_OBJECT (parse, "Offset %" G_GUINT64_FORMAT ", Element id 0x%x, "
+      "size %" G_GUINT64_FORMAT ", needed %d", parse->offset, id,
+      length, needed);
+
+  ret = gst_matroska_parse_parse_id (parse, id, length, needed);
+  if (ret == GST_FLOW_EOS)
+    goto eos;
+  if (ret != GST_FLOW_OK)
+    goto pause;
+
+  /* check if we're at the end of a configured segment */
+  if (G_LIKELY (parse->src->len)) {
+    guint i;
+
+    g_assert (parse->num_streams == parse->src->len);
+    for (i = 0; i < parse->src->len; i++) {
+      GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i);
+      GST_DEBUG_OBJECT (context->pad, "pos %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (context->pos));
+      if (context->eos == FALSE)
+        goto next;
+    }
+
+    GST_INFO_OBJECT (parse, "All streams are EOS");
+    ret = GST_FLOW_EOS;
+    goto eos;
+  }
+
+next:
+  if (G_UNLIKELY (parse->offset ==
+          gst_matroska_read_common_get_length (&parse->common))) {
+    GST_LOG_OBJECT (parse, "Reached end of stream");
+    ret = GST_FLOW_EOS;
+    goto eos;
+  }
+
+  return;
+
+  /* ERRORS */
+eos:
+  {
+    if (parse->segment.rate < 0.0) {
+      ret = gst_matroska_parse_seek_to_previous_keyframe (parse);
+      if (ret == GST_FLOW_OK)
+        return;
+    }
+    /* fall-through */
+  }
+pause:
+  {
+    const gchar *reason = gst_flow_get_name (ret);
+    gboolean push_eos = FALSE;
+
+    GST_LOG_OBJECT (parse, "pausing task, reason %s", reason);
+    parse->segment_running = FALSE;
+    gst_pad_pause_task (parse->common.sinkpad);
+
+    if (ret == GST_FLOW_EOS) {
+      /* perform EOS logic */
+
+      /* Close the segment, i.e. update segment stop with the duration
+       * if no stop was set */
+      if (GST_CLOCK_TIME_IS_VALID (parse->last_stop_end) &&
+          !GST_CLOCK_TIME_IS_VALID (parse->segment.stop)) {
+        GstEvent *event =
+            gst_event_new_new_segment_full (TRUE, parse->segment.rate,
+            parse->segment.applied_rate, parse->segment.format,
+            parse->segment.start,
+            MAX (parse->last_stop_end, parse->segment.start),
+            parse->segment.time);
+        gst_matroska_parse_send_event (parse, event);
+      }
+
+      if (parse->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+        gint64 stop;
+
+        /* for segment playback we need to post when (in stream time)
+         * we stopped, this is either stop (when set) or the duration. */
+        if ((stop = parse->segment.stop) == -1)
+          stop = parse->last_stop_end;
+
+        GST_LOG_OBJECT (parse, "Sending segment done, at end of segment");
+        gst_element_post_message (GST_ELEMENT (parse),
+            gst_message_new_segment_done (GST_OBJECT (parse), GST_FORMAT_TIME,
+                stop));
+        gst_matroska_parse_send_event (parse,
+            gst_event_new_segment_done (GST_FORMAT_TIME, stop));
+      } else {
+        push_eos = TRUE;
+      }
+    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
+      /* for fatal errors we post an error message */
+      GST_ELEMENT_FLOW_ERROR (parse, ret);
+      push_eos = TRUE;
+    }
+    if (push_eos) {
+      /* send EOS, and prevent hanging if no streams yet */
+      GST_LOG_OBJECT (parse, "Sending EOS, at end of stream");
+      if (!gst_matroska_parse_send_event (parse, gst_event_new_eos ()) &&
+          (ret == GST_FLOW_EOS)) {
+        GST_ELEMENT_ERROR (parse, STREAM, DEMUX,
+            (NULL), ("got eos but no streams (yet)"));
+      }
+    }
+    return;
+  }
+}
+#endif
+
+/*
+ * Create and push a flushing seek event upstream
+ */
+static gboolean
+perform_seek_to_offset (GstMatroskaParse * parse, guint64 offset)
+{
+  GstEvent *event;
+  gboolean res = 0;
+
+  GST_DEBUG_OBJECT (parse, "Seeking to %" G_GUINT64_FORMAT, offset);
+
+  event =
+      gst_event_new_seek (1.0, GST_FORMAT_BYTES,
+      GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
+      GST_SEEK_TYPE_NONE, -1);
+
+  res = gst_pad_push_event (parse->common.sinkpad, event);
+
+  /* newsegment event will update offset */
+  return res;
+}
+
+/*
+ * Forge empty default caps when all we know is the stream's EBML
+ * type and whether it has video or not.
+ *
+ * FIXME: Do something with video/x-matroska-3d if possible
+ */
+static GstCaps *
+gst_matroska_parse_forge_caps (gboolean is_webm, gboolean has_video)
+{
+  GstCaps *caps;
+
+  if (is_webm) {
+    if (has_video)
+      caps = gst_caps_new_empty_simple ("video/webm");
+    else
+      caps = gst_caps_new_empty_simple ("audio/webm");
+  } else {
+    if (has_video)
+      caps = gst_caps_new_empty_simple ("video/x-matroska");
+    else
+      caps = gst_caps_new_empty_simple ("audio/x-matroska");
+  }
+  return caps;
+}
+
+static GstFlowReturn
+gst_matroska_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstMatroskaParse *parse = GST_MATROSKA_PARSE (parent);
+  guint available;
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint needed = 0;
+  guint32 id;
+  guint64 length;
+
+  if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buffer))) {
+    GST_DEBUG_OBJECT (parse, "got DISCONT");
+    gst_adapter_clear (parse->common.adapter);
+    GST_OBJECT_LOCK (parse);
+    gst_matroska_read_common_reset_streams (&parse->common,
+        GST_CLOCK_TIME_NONE, FALSE);
+    GST_OBJECT_UNLOCK (parse);
+  }
+
+  gst_adapter_push (parse->common.adapter, buffer);
+  buffer = NULL;
+
+next:
+  available = gst_adapter_available (parse->common.adapter);
+
+  ret = gst_matroska_read_common_peek_id_length_push (&parse->common,
+      GST_ELEMENT_CAST (parse), &id, &length, &needed);
+  if (G_UNLIKELY (ret != GST_FLOW_OK && ret != GST_FLOW_EOS)) {
+    if (parse->common.ebml_segment_length != G_MAXUINT64
+        && parse->common.offset >=
+        parse->common.ebml_segment_start + parse->common.ebml_segment_length) {
+      return GST_FLOW_EOS;
+    } else {
+      /*
+       * parsing error: we need to flush a byte from the adapter if the id is
+       * not a cluster and so on until we found a new cluser or the
+       * INVALID_DATA_THRESHOLD is exceeded, we reuse gst_matroska_parse_parse_id
+       * setting the state to GST_MATROSKA_READ_STATE_SCANNING so the bytes
+       * are skipped until a new cluster is found
+       */
+      gint64 bytes_scanned;
+      if (parse->common.start_resync_offset == -1) {
+        parse->common.start_resync_offset = parse->common.offset;
+        parse->common.state_to_restore = parse->common.state;
+      }
+      bytes_scanned = parse->common.offset - parse->common.start_resync_offset;
+      if (bytes_scanned <= INVALID_DATA_THRESHOLD) {
+        GST_WARNING_OBJECT (parse,
+            "parse error, looking for next cluster, actual offset %"
+            G_GUINT64_FORMAT ", start resync offset %" G_GUINT64_FORMAT,
+            parse->common.offset, parse->common.start_resync_offset);
+        parse->common.state = GST_MATROSKA_READ_STATE_SCANNING;
+        ret = GST_FLOW_OK;
+      } else {
+        GST_WARNING_OBJECT (parse,
+            "unrecoverable parse error, next cluster not found and threshold "
+            "exceeded, bytes scanned %" G_GINT64_FORMAT, bytes_scanned);
+        return ret;
+      }
+    }
+  }
+
+  GST_LOG_OBJECT (parse, "Offset %" G_GUINT64_FORMAT ", Element id 0x%x, "
+      "size %" G_GUINT64_FORMAT ", needed %d, available %d",
+      parse->common.offset, id, length, needed, available);
+
+  if (needed > available)
+    return GST_FLOW_OK;
+
+  ret = gst_matroska_parse_parse_id (parse, id, length, needed);
+  if (ret == GST_FLOW_EOS) {
+    /* need more data */
+    return GST_FLOW_OK;
+  } else if (ret != GST_FLOW_OK) {
+    return ret;
+  } else
+    goto next;
+}
+
+static gboolean
+gst_matroska_parse_handle_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  gboolean res = TRUE;
+  GstMatroskaParse *parse = GST_MATROSKA_PARSE (GST_PAD_PARENT (pad));
+
+  GST_DEBUG_OBJECT (parse,
+      "have event type %s: %p on sink pad", GST_EVENT_TYPE_NAME (event), event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEGMENT:
+    {
+      const GstSegment *segment;
+
+      /* some debug output */
+      gst_event_parse_segment (event, &segment);
+      GST_DEBUG_OBJECT (parse,
+          "received format %d newsegment %" GST_SEGMENT_FORMAT,
+          segment->format, segment);
+
+      if (parse->common.state < GST_MATROSKA_READ_STATE_DATA) {
+        GST_DEBUG_OBJECT (parse, "still starting");
+        goto exit;
+      }
+
+      /* we only expect a BYTE segment, e.g. following a seek */
+      if (segment->format != GST_FORMAT_BYTES) {
+        GST_DEBUG_OBJECT (parse, "unsupported segment format, ignoring");
+        goto exit;
+      }
+
+      GST_DEBUG_OBJECT (parse, "clearing segment state");
+      /* clear current segment leftover */
+      gst_adapter_clear (parse->common.adapter);
+      /* and some streaming setup */
+      parse->common.offset = segment->start;
+      /* do not know where we are;
+       * need to come across a cluster and generate newsegment */
+      parse->common.segment.position = GST_CLOCK_TIME_NONE;
+      parse->cluster_time = GST_CLOCK_TIME_NONE;
+      parse->cluster_offset = 0;
+      parse->need_newsegment = TRUE;
+      /* but keep some of the upstream segment */
+      parse->common.segment.rate = segment->rate;
+    exit:
+      /* chain will send initial newsegment after pads have been added,
+       * or otherwise come up with one */
+      GST_DEBUG_OBJECT (parse, "eating event");
+      gst_event_unref (event);
+      res = TRUE;
+      break;
+    }
+    case GST_EVENT_EOS:
+    {
+      if (parse->common.state != GST_MATROSKA_READ_STATE_DATA
+          && parse->common.state != GST_MATROSKA_READ_STATE_SCANNING) {
+        gst_event_unref (event);
+        GST_ELEMENT_ERROR (parse, STREAM, DEMUX,
+            (NULL), ("got eos and didn't receive a complete header object"));
+      } else if (parse->common.num_streams == 0) {
+        GST_ELEMENT_ERROR (parse, STREAM, DEMUX,
+            (NULL), ("got eos but no streams (yet)"));
+      } else {
+        gst_matroska_parse_send_event (parse, event);
+      }
+      break;
+    }
+    case GST_EVENT_FLUSH_STOP:
+    {
+      gst_adapter_clear (parse->common.adapter);
+      GST_OBJECT_LOCK (parse);
+      gst_matroska_read_common_reset_streams (&parse->common,
+          GST_CLOCK_TIME_NONE, TRUE);
+      GST_OBJECT_UNLOCK (parse);
+      parse->common.segment.position = GST_CLOCK_TIME_NONE;
+      parse->cluster_time = GST_CLOCK_TIME_NONE;
+      parse->cluster_offset = 0;
+      /* fall-through */
+    }
+    default:
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return res;
+}
+
+#if 0
+static void
+gst_matroska_parse_set_index (GstElement * element, GstIndex * index)
+{
+  GstMatroskaParse *parse = GST_MATROSKA_PARSE (element);
+
+  GST_OBJECT_LOCK (parse);
+  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->common.element_index);
+}
+
+static GstIndex *
+gst_matroska_parse_get_index (GstElement * element)
+{
+  GstIndex *result = NULL;
+  GstMatroskaParse *parse = GST_MATROSKA_PARSE (element);
+
+  GST_OBJECT_LOCK (parse);
+  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);
+
+  return result;
+}
+#endif
+
+static GstStateChangeReturn
+gst_matroska_parse_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstMatroskaParse *parse = GST_MATROSKA_PARSE (element);
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+  /* handle upwards state changes here */
+  switch (transition) {
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  /* handle downwards state changes */
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_matroska_parse_reset (GST_ELEMENT (parse));
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+gboolean
+gst_matroska_parse_plugin_init (GstPlugin * plugin)
+{
+  gst_riff_init ();
+
+  /* create an elementfactory for the matroska_parse element */
+  if (!gst_element_register (plugin, "matroskaparse",
+          GST_RANK_NONE, GST_TYPE_MATROSKA_PARSE))
+    return FALSE;
+
+  return TRUE;
+}
diff --git a/gst/matroska/matroska-parse.h b/gst/matroska/matroska-parse.h
new file mode 100644
index 0000000..7d598f2
--- /dev/null
+++ b/gst/matroska/matroska-parse.h
@@ -0,0 +1,105 @@
+/* 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
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MATROSKA_PARSE_H__
+#define __GST_MATROSKA_PARSE_H__
+
+#include <gst/gst.h>
+
+#include "ebml-read.h"
+#include "matroska-ids.h"
+#include "matroska-read-common.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_MATROSKA_PARSE \
+  (gst_matroska_parse_get_type ())
+#define GST_MATROSKA_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MATROSKA_PARSE, GstMatroskaParse))
+#define GST_MATROSKA_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MATROSKA_PARSE, GstMatroskaParseClass))
+#define GST_IS_MATROSKA_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MATROSKA_PARSE))
+#define GST_IS_MATROSKA_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MATROSKA_PARSE))
+
+typedef struct _GstMatroskaParse {
+  GstElement              parent;
+
+  /* < private > */
+
+  GstMatroskaReadCommon    common;
+
+  /* pads */
+  GstPad                  *srcpad;
+  GstClock                *clock;
+  guint                    num_v_streams;
+  guint                    num_a_streams;
+  guint                    num_t_streams;
+
+  GstBuffer *streamheader;
+  gboolean pushed_headers;
+  GstClockTime last_timestamp;
+
+  /* state */
+  //gboolean                 streaming;
+  guint64                  seek_block;
+  gboolean                 seek_first;
+
+  /* did we parse cues/tracks/segmentinfo already? */
+  gboolean                 tracks_parsed;
+  GList                   *seek_parsed;
+
+  /* keeping track of playback position */
+  gboolean                 segment_running;
+  GstClockTime             last_stop_end;
+
+  GstEvent                *close_segment;
+  GstEvent                *new_segment;
+
+  /* some state saving */
+  GstClockTime             cluster_time;
+  guint64                  cluster_offset;
+  guint64                  first_cluster_offset;
+  guint64                  next_cluster_offset;
+
+  /* index stuff */
+  gboolean                 seekable;
+  gboolean                 building_index;
+  guint64                  index_offset;
+  GstEvent                *seek_event;
+  gboolean                 need_newsegment;
+
+  /* reverse playback */
+  GArray                  *seek_index;
+  gint                     seek_entry;
+} GstMatroskaParse;
+
+typedef struct _GstMatroskaParseClass {
+  GstElementClass parent;
+} GstMatroskaParseClass;
+
+gboolean gst_matroska_parse_plugin_init (GstPlugin *plugin);
+
+G_END_DECLS
+
+#endif /* __GST_MATROSKA_PARSE_H__ */
diff --git a/gst/matroska/matroska-read-common.c b/gst/matroska/matroska-read-common.c
new file mode 100644
index 0000000..419ba7f
--- /dev/null
+++ b/gst/matroska/matroska-read-common.c
@@ -0,0 +1,3070 @@
+/* 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif
+
+#ifdef HAVE_BZ2
+#include <bzlib.h>
+#endif
+
+#include <gst/tag/tag.h>
+#include <gst/base/gsttypefindhelper.h>
+
+#include "lzo.h"
+
+#include "ebml-read.h"
+#include "matroska-read-common.h"
+#include "matroska-ids.h"
+
+GST_DEBUG_CATEGORY (matroskareadcommon_debug);
+#define GST_CAT_DEFAULT matroskareadcommon_debug
+
+#define DEBUG_ELEMENT_START(common, ebml, element) \
+    GST_DEBUG_OBJECT (common->sinkpad, "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->sinkpad, "Parsing " element " element " \
+        " finished with '%s'", gst_flow_get_name (ret))
+
+#define GST_MATROSKA_TOC_UID_CHAPTER "chapter"
+#define GST_MATROSKA_TOC_UID_EDITION "edition"
+#define GST_MATROSKA_TOC_UID_EMPTY "empty"
+
+typedef struct
+{
+  GstTagList *result;
+  guint64 target_type_value;
+  gchar *target_type;
+  gboolean audio_only;
+} TargetTypeContext;
+
+
+static gboolean
+gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
+    gpointer * data_out, gsize * 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_STREAM_END) {
+        break;
+      } else if (result != Z_OK) {
+        GST_WARNING ("inflate() returned %d", result);
+        break;
+      }
+
+      new_size += 4096;
+      new_data = g_realloc (new_data, new_size);
+      zstream.next_out = (Bytef *) (new_data + zstream.total_out);
+      zstream.avail_out += 4096;
+    } while (zstream.avail_in > 0);
+
+    if (result != Z_STREAM_END) {
+      ret = FALSE;
+      g_free (new_data);
+    } 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_STREAM_END) {
+        break;
+      } else if (result != BZ_OK) {
+        GST_WARNING ("BZ2_bzDecompress() returned %d", result);
+        break;
+      }
+
+      new_size += 4096;
+      new_data = g_realloc (new_data, new_size);
+      bzstream.next_out = (char *) (new_data + bzstream.total_out_lo32);
+      bzstream.avail_out += 4096;
+    } while (bzstream.avail_in > 0);
+
+    if (result != BZ_STREAM_END) {
+      ret = FALSE;
+      g_free (new_data);
+    } 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 += 4096;
+        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;
+}
+
+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);
+    gpointer data = NULL;
+    gsize 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_decode_data (GArray * encodings, gpointer * data_out,
+    gsize * size_out, GstMatroskaTrackEncodingScope scope, gboolean free)
+{
+  gpointer data;
+  gsize size;
+  gboolean ret = TRUE;
+  gint i;
+
+  g_return_val_if_fail (encodings != NULL, FALSE);
+  g_return_val_if_fail (data_out != NULL && *data_out != NULL, FALSE);
+  g_return_val_if_fail (size_out != NULL, FALSE);
+
+  data = *data_out;
+  size = *size_out;
+
+  for (i = 0; i < encodings->len; i++) {
+    GstMatroskaTrackEncoding *enc =
+        &g_array_index (encodings, GstMatroskaTrackEncoding, i);
+    gpointer new_data = NULL;
+    gsize new_size = 0;
+
+    if ((enc->scope & scope) == 0)
+      continue;
+
+    /* Encryption not supported yet */
+    if (enc->type != 0) {
+      ret = FALSE;
+      break;
+    }
+
+    new_data = data;
+    new_size = size;
+
+    ret =
+        gst_matroska_decompress_data (enc, &new_data, &new_size,
+        enc->comp_algo);
+
+    if (!ret)
+      break;
+
+    if ((data == *data_out && free) || (data != *data_out))
+      g_free (data);
+
+    data = new_data;
+    size = new_size;
+  }
+
+  if (!ret) {
+    if ((data == *data_out && free) || (data != *data_out))
+      g_free (data);
+
+    *data_out = NULL;
+    *size_out = 0;
+  } else {
+    *data_out = data;
+    *size_out = 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;
+}
+
+gint
+gst_matroska_index_seek_find (GstMatroskaIndex * i1, GstClockTime * time,
+    gpointer user_data)
+{
+  if (i1->time < *time)
+    return -1;
+  else if (i1->time > *time)
+    return 1;
+  else
+    return 0;
+}
+
+GstMatroskaIndex *
+gst_matroska_read_common_do_index_seek (GstMatroskaReadCommon * common,
+    GstMatroskaTrackContext * track, gint64 seek_pos, GArray ** _index,
+    gint * _entry_index, GstSearchMode snap_dir)
+{
+  GstMatroskaIndex *entry = NULL;
+  GArray *index;
+
+  /* find entry just before or at the requested position */
+  if (track && track->index_table)
+    index = track->index_table;
+  else
+    index = common->index;
+
+  if (!index || !index->len)
+    return NULL;
+
+  entry =
+      gst_util_array_binary_search (index->data, index->len,
+      sizeof (GstMatroskaIndex),
+      (GCompareDataFunc) gst_matroska_index_seek_find, snap_dir, &seek_pos,
+      NULL);
+
+  if (entry == NULL) {
+    if (snap_dir == GST_SEARCH_MODE_AFTER) {
+      /* Can only happen with a reverse seek past the end */
+      entry = &g_array_index (index, GstMatroskaIndex, index->len - 1);
+    } else {
+      /* Can only happen with a forward seek before the start */
+      entry = &g_array_index (index, GstMatroskaIndex, 0);
+    }
+  }
+
+  if (_index)
+    *_index = index;
+  if (_entry_index)
+    *_entry_index = entry - (GstMatroskaIndex *) index->data;
+
+  return entry;
+}
+
+static gint
+gst_matroska_read_common_encoding_cmp (GstMatroskaTrackEncoding * a,
+    GstMatroskaTrackEncoding * b)
+{
+  if (b->order > a->order)
+    return 1;
+  else if (b->order < a->order)
+    return -1;
+  else
+    return 0;
+}
+
+static gboolean
+gst_matroska_read_common_encoding_order_unique (GArray * encodings, guint64
+    order)
+{
+  gint i;
+
+  if (encodings == NULL || encodings->len == 0)
+    return TRUE;
+
+  for (i = 0; i < encodings->len; i++)
+    if (g_array_index (encodings, GstMatroskaTrackEncoding, i).order == order)
+      return FALSE;
+
+  return TRUE;
+}
+
+/* takes ownership of taglist */
+void
+gst_matroska_read_common_found_global_tag (GstMatroskaReadCommon * common,
+    GstElement * el, GstTagList * taglist)
+{
+  if (common->global_tags) {
+    gst_tag_list_insert (common->global_tags, taglist, GST_TAG_MERGE_APPEND);
+    gst_tag_list_unref (taglist);
+  } else {
+    common->global_tags = taglist;
+  }
+  common->global_tags_changed = TRUE;
+}
+
+gint64
+gst_matroska_read_common_get_length (GstMatroskaReadCommon * common)
+{
+  gint64 end = -1;
+
+  if (!gst_pad_peer_query_duration (common->sinkpad, GST_FORMAT_BYTES,
+          &end) || end < 0)
+    GST_DEBUG_OBJECT (common->sinkpad, "no upstream length");
+
+  return end;
+}
+
+/* determine track to seek in */
+GstMatroskaTrackContext *
+gst_matroska_read_common_get_seek_track (GstMatroskaReadCommon * common,
+    GstMatroskaTrackContext * track)
+{
+  gint i;
+
+  if (track && track->type == GST_MATROSKA_TRACK_TYPE_VIDEO)
+    return track;
+
+  for (i = 0; i < common->src->len; i++) {
+    GstMatroskaTrackContext *stream;
+
+    stream = g_ptr_array_index (common->src, i);
+    if (stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO && stream->index_table)
+      track = stream;
+  }
+
+  return track;
+}
+
+/* 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->sinkpad, "Skipping EBML Void element");
+  } else if (id == GST_EBML_ID_CRC32) {
+    GST_DEBUG_OBJECT (common->sinkpad, "Skipping EBML CRC32 element");
+  } else {
+    GST_WARNING_OBJECT (common->sinkpad,
+        "Unknown %s subelement 0x%x - ignoring", parent_name, id);
+  }
+
+  return gst_ebml_read_skip (ebml);
+}
+
+static GstFlowReturn
+gst_matroska_read_common_parse_attached_file (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml, GstTagList * taglist)
+{
+  guint32 id;
+  GstFlowReturn ret;
+  gchar *description = NULL;
+  gchar *filename = NULL;
+  gchar *mimetype = NULL;
+  guint8 *data = NULL;
+  guint64 datalen = 0;
+
+  DEBUG_ELEMENT_START (common, ebml, "AttachedFile");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "AttachedFile", ret);
+    return ret;
+  }
+
+  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
+    /* read all sub-entries */
+
+    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
+      break;
+
+    switch (id) {
+      case GST_MATROSKA_ID_FILEDESCRIPTION:
+        if (description) {
+          GST_WARNING_OBJECT (common->sinkpad,
+              "FileDescription can only appear once");
+          break;
+        }
+
+        ret = gst_ebml_read_utf8 (ebml, &id, &description);
+        GST_DEBUG_OBJECT (common->sinkpad, "FileDescription: %s",
+            GST_STR_NULL (description));
+        break;
+      case GST_MATROSKA_ID_FILENAME:
+        if (filename) {
+          GST_WARNING_OBJECT (common->sinkpad, "FileName can only appear once");
+          break;
+        }
+
+        ret = gst_ebml_read_utf8 (ebml, &id, &filename);
+
+        GST_DEBUG_OBJECT (common->sinkpad, "FileName: %s",
+            GST_STR_NULL (filename));
+        break;
+      case GST_MATROSKA_ID_FILEMIMETYPE:
+        if (mimetype) {
+          GST_WARNING_OBJECT (common->sinkpad,
+              "FileMimeType can only appear once");
+          break;
+        }
+
+        ret = gst_ebml_read_ascii (ebml, &id, &mimetype);
+        GST_DEBUG_OBJECT (common->sinkpad, "FileMimeType: %s",
+            GST_STR_NULL (mimetype));
+        break;
+      case GST_MATROSKA_ID_FILEDATA:
+        if (data) {
+          GST_WARNING_OBJECT (common->sinkpad, "FileData can only appear once");
+          break;
+        }
+
+        ret = gst_ebml_read_binary (ebml, &id, &data, &datalen);
+        GST_DEBUG_OBJECT (common->sinkpad,
+            "FileData of size %" G_GUINT64_FORMAT, datalen);
+        break;
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (common, ebml,
+            "AttachedFile", id);
+        break;
+      case GST_MATROSKA_ID_FILEUID:
+        ret = gst_ebml_read_skip (ebml);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (common, ebml, "AttachedFile", ret);
+
+  if (filename && mimetype && data && datalen > 0) {
+    GstTagImageType image_type = GST_TAG_IMAGE_TYPE_NONE;
+    GstBuffer *tagbuffer = NULL;
+    GstSample *tagsample = NULL;
+    GstStructure *info = NULL;
+    GstCaps *caps = NULL;
+    gchar *filename_lc = g_utf8_strdown (filename, -1);
+
+    GST_DEBUG_OBJECT (common->sinkpad, "Creating tag for attachment with "
+        "filename '%s', mimetype '%s', description '%s', "
+        "size %" G_GUINT64_FORMAT, filename, mimetype,
+        GST_STR_NULL (description), datalen);
+
+    /* TODO: better heuristics for different image types */
+    if (strstr (filename_lc, "cover")) {
+      if (strstr (filename_lc, "back"))
+        image_type = GST_TAG_IMAGE_TYPE_BACK_COVER;
+      else
+        image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
+    } else if (g_str_has_prefix (mimetype, "image/") ||
+        g_str_has_suffix (filename_lc, "png") ||
+        g_str_has_suffix (filename_lc, "jpg") ||
+        g_str_has_suffix (filename_lc, "jpeg") ||
+        g_str_has_suffix (filename_lc, "gif") ||
+        g_str_has_suffix (filename_lc, "bmp")) {
+      image_type = GST_TAG_IMAGE_TYPE_UNDEFINED;
+    }
+    g_free (filename_lc);
+
+    /* First try to create an image tag buffer from this */
+    if (image_type != GST_TAG_IMAGE_TYPE_NONE) {
+      tagsample =
+          gst_tag_image_data_to_image_sample (data, datalen, image_type);
+
+      if (!tagsample) {
+        image_type = GST_TAG_IMAGE_TYPE_NONE;
+      } else {
+        tagbuffer = gst_buffer_ref (gst_sample_get_buffer (tagsample));
+        caps = gst_caps_ref (gst_sample_get_caps (tagsample));
+        info = gst_structure_copy (gst_sample_get_info (tagsample));
+        gst_sample_unref (tagsample);
+      }
+    }
+
+    /* if this failed create an attachment buffer */
+    if (!tagbuffer) {
+      tagbuffer = gst_buffer_new_wrapped (g_memdup (data, datalen), datalen);
+
+      caps = gst_type_find_helper_for_buffer (NULL, tagbuffer, NULL);
+      if (caps == NULL)
+        caps = gst_caps_new_empty_simple (mimetype);
+    }
+
+    /* Set filename and description in the info */
+    if (info == NULL)
+      info = gst_structure_new_empty ("GstTagImageInfo");
+
+    gst_structure_set (info, "filename", G_TYPE_STRING, filename, NULL);
+    if (description)
+      gst_structure_set (info, "description", G_TYPE_STRING, description, NULL);
+
+    tagsample = gst_sample_new (tagbuffer, caps, NULL, info);
+
+    gst_buffer_unref (tagbuffer);
+    gst_caps_unref (caps);
+
+    GST_DEBUG_OBJECT (common->sinkpad,
+        "Created attachment sample: %" GST_PTR_FORMAT, tagsample);
+
+    /* and append to the tag list */
+    if (image_type != GST_TAG_IMAGE_TYPE_NONE)
+      gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_IMAGE, tagsample,
+          NULL);
+    else
+      gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_ATTACHMENT,
+          tagsample, NULL);
+
+    /* the list adds it own ref */
+    gst_sample_unref (tagsample);
+  }
+
+  g_free (filename);
+  g_free (mimetype);
+  g_free (data);
+  g_free (description);
+
+  return ret;
+}
+
+GstFlowReturn
+gst_matroska_read_common_parse_attachments (GstMatroskaReadCommon * common,
+    GstElement * el, GstEbmlRead * ebml)
+{
+  guint32 id;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstTagList *taglist;
+
+  DEBUG_ELEMENT_START (common, ebml, "Attachments");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "Attachments", ret);
+    return ret;
+  }
+
+  taglist = gst_tag_list_new_empty ();
+  gst_tag_list_set_scope (taglist, GST_TAG_SCOPE_GLOBAL);
+
+  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) {
+      case GST_MATROSKA_ID_ATTACHEDFILE:
+        ret = gst_matroska_read_common_parse_attached_file (common, ebml,
+            taglist);
+        break;
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (common, ebml,
+            "Attachments", id);
+        break;
+    }
+  }
+  DEBUG_ELEMENT_STOP (common, ebml, "Attachments", ret);
+
+  if (gst_tag_list_n_tags (taglist) > 0) {
+    GST_DEBUG_OBJECT (common->sinkpad, "Storing attachment tags");
+    gst_matroska_read_common_found_global_tag (common, el, taglist);
+  } else {
+    GST_DEBUG_OBJECT (common->sinkpad, "No valid attachments found");
+    gst_tag_list_unref (taglist);
+  }
+
+  common->attachments_parsed = TRUE;
+
+  return ret;
+}
+
+static void
+gst_matroska_read_common_parse_toc_tag (GstTocEntry * entry,
+    GstTocEntry * internal_entry, GArray * edition_targets,
+    GArray * chapter_targets, GstTagList * tags)
+{
+  gchar *uid;
+  guint i;
+  guint64 tgt;
+  GArray *targets;
+  GList *cur, *internal_cur;
+  GstTagList *etags;
+
+  targets =
+      (gst_toc_entry_get_entry_type (entry) ==
+      GST_TOC_ENTRY_TYPE_EDITION) ? edition_targets : chapter_targets;
+
+  etags = gst_tag_list_new_empty ();
+
+  for (i = 0; i < targets->len; ++i) {
+    tgt = g_array_index (targets, guint64, i);
+
+    if (tgt == 0)
+      gst_tag_list_insert (etags, tags, GST_TAG_MERGE_APPEND);
+    else {
+      uid = g_strdup_printf ("%" G_GUINT64_FORMAT, tgt);
+      if (g_strcmp0 (gst_toc_entry_get_uid (internal_entry), uid) == 0)
+        gst_tag_list_insert (etags, tags, GST_TAG_MERGE_APPEND);
+      g_free (uid);
+    }
+  }
+
+  gst_toc_entry_merge_tags (entry, etags, GST_TAG_MERGE_APPEND);
+  gst_tag_list_unref (etags);
+
+  cur = gst_toc_entry_get_sub_entries (entry);
+  internal_cur = gst_toc_entry_get_sub_entries (internal_entry);
+  while (cur != NULL && internal_cur != NULL) {
+    gst_matroska_read_common_parse_toc_tag (cur->data, internal_cur->data,
+        edition_targets, chapter_targets, tags);
+    cur = cur->next;
+    internal_cur = internal_cur->next;
+  }
+}
+
+static GstFlowReturn
+gst_matroska_read_common_parse_metadata_targets (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml, GArray * edition_targets, GArray * chapter_targets,
+    GArray * track_targets, guint64 * target_type_value, gchar ** target_type)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint32 id;
+  guint64 uid;
+  guint64 tmp;
+  gchar *str;
+
+  DEBUG_ELEMENT_START (common, ebml, "TagTargets");
+
+  *target_type_value = 50;
+  *target_type = NULL;
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "TagTargets", 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) {
+      case GST_MATROSKA_ID_TARGETCHAPTERUID:
+        if ((ret = gst_ebml_read_uint (ebml, &id, &uid)) == GST_FLOW_OK)
+          g_array_append_val (chapter_targets, uid);
+        break;
+
+      case GST_MATROSKA_ID_TARGETEDITIONUID:
+        if ((ret = gst_ebml_read_uint (ebml, &id, &uid)) == GST_FLOW_OK)
+          g_array_append_val (edition_targets, uid);
+        break;
+
+      case GST_MATROSKA_ID_TARGETTRACKUID:
+        if ((ret = gst_ebml_read_uint (ebml, &id, &uid)) == GST_FLOW_OK)
+          g_array_append_val (track_targets, uid);
+        break;
+
+      case GST_MATROSKA_ID_TARGETTYPEVALUE:
+        if ((ret = gst_ebml_read_uint (ebml, &id, &tmp)) == GST_FLOW_OK)
+          *target_type_value = tmp;
+        break;
+
+      case GST_MATROSKA_ID_TARGETTYPE:
+        if ((ret = gst_ebml_read_ascii (ebml, &id, &str)) == GST_FLOW_OK) {
+          g_free (*target_type);
+          *target_type = str;
+        }
+        break;
+
+      default:
+        ret =
+            gst_matroska_read_common_parse_skip (common, ebml, "TagTargets",
+            id);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (common, ebml, "TagTargets", ret);
+
+  return ret;
+}
+
+static void
+gst_matroska_read_common_postprocess_toc_entries (GList * toc_entries,
+    guint64 max, const gchar * parent_uid)
+{
+  GstTocEntry *cur_info, *prev_info, *next_info;
+  GList *cur_list, *prev_list, *next_list;
+  gint64 cur_start, prev_start, stop;
+
+  cur_list = toc_entries;
+  while (cur_list != NULL) {
+    cur_info = cur_list->data;
+
+    switch (gst_toc_entry_get_entry_type (cur_info)) {
+      case GST_TOC_ENTRY_TYPE_ANGLE:
+      case GST_TOC_ENTRY_TYPE_VERSION:
+      case GST_TOC_ENTRY_TYPE_EDITION:
+        /* in Matroska terms edition has duration of full track */
+        gst_toc_entry_set_start_stop_times (cur_info, 0, max);
+
+        gst_matroska_read_common_postprocess_toc_entries
+            (gst_toc_entry_get_sub_entries (cur_info), max,
+            gst_toc_entry_get_uid (cur_info));
+        break;
+
+      case GST_TOC_ENTRY_TYPE_TITLE:
+      case GST_TOC_ENTRY_TYPE_TRACK:
+      case GST_TOC_ENTRY_TYPE_CHAPTER:
+        prev_list = cur_list->prev;
+        next_list = cur_list->next;
+
+        if (prev_list != NULL)
+          prev_info = prev_list->data;
+        else
+          prev_info = NULL;
+
+        if (next_list != NULL)
+          next_info = next_list->data;
+        else
+          next_info = NULL;
+
+        /* updated stop time in previous chapter and it's subchapters */
+        if (prev_info != NULL) {
+          gst_toc_entry_get_start_stop_times (prev_info, &prev_start, &stop);
+          gst_toc_entry_get_start_stop_times (cur_info, &cur_start, &stop);
+
+          stop = cur_start;
+          gst_toc_entry_set_start_stop_times (prev_info, prev_start, stop);
+
+          gst_matroska_read_common_postprocess_toc_entries
+              (gst_toc_entry_get_sub_entries (prev_info), cur_start,
+              gst_toc_entry_get_uid (prev_info));
+        }
+
+        /* updated stop time in current chapter and it's subchapters */
+        if (next_info == NULL) {
+          gst_toc_entry_get_start_stop_times (cur_info, &cur_start, &stop);
+
+          if (stop == -1) {
+            stop = max;
+            gst_toc_entry_set_start_stop_times (cur_info, cur_start, stop);
+          }
+
+          gst_matroska_read_common_postprocess_toc_entries
+              (gst_toc_entry_get_sub_entries (cur_info), stop,
+              gst_toc_entry_get_uid (cur_info));
+        }
+        break;
+      case GST_TOC_ENTRY_TYPE_INVALID:
+        break;
+    }
+    cur_list = cur_list->next;
+  }
+}
+
+static GstFlowReturn
+gst_matroska_read_common_parse_chapter_titles (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml, GstTagList * titles)
+{
+  guint32 id;
+  gchar *title = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  DEBUG_ELEMENT_START (common, ebml, "ChaptersTitles");
+
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "ChaptersTitles", 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) {
+      case GST_MATROSKA_ID_CHAPSTRING:
+        ret = gst_ebml_read_utf8 (ebml, &id, &title);
+        break;
+
+      default:
+        ret =
+            gst_matroska_read_common_parse_skip (common, ebml, "ChaptersTitles",
+            id);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (common, ebml, "ChaptersTitles", ret);
+
+  if (title != NULL && ret == GST_FLOW_OK)
+    gst_tag_list_add (titles, GST_TAG_MERGE_APPEND, GST_TAG_TITLE, title, NULL);
+
+  g_free (title);
+  return ret;
+}
+
+static GstFlowReturn
+gst_matroska_read_common_parse_chapter_element (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml, GList ** subentries, GList ** internal_subentries)
+{
+  guint32 id;
+  guint64 start_time = -1, stop_time = -1;
+  guint64 is_hidden = 0, is_enabled = 1, uid = 0;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstTocEntry *chapter_info, *internal_chapter_info;
+  GstTagList *tags;
+  gchar *uid_str, *string_uid = NULL;
+  GList *subsubentries = NULL, *internal_subsubentries = NULL, *l, *il;
+
+  DEBUG_ELEMENT_START (common, ebml, "ChaptersElement");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "ChaptersElement", ret);
+    return ret;
+  }
+
+  tags = gst_tag_list_new_empty ();
+
+  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) {
+      case GST_MATROSKA_ID_CHAPTERUID:
+        ret = gst_ebml_read_uint (ebml, &id, &uid);
+        break;
+
+      case GST_MATROSKA_ID_CHAPTERSTRINGUID:
+        ret = gst_ebml_read_utf8 (ebml, &id, &string_uid);
+        break;
+
+      case GST_MATROSKA_ID_CHAPTERTIMESTART:
+        ret = gst_ebml_read_uint (ebml, &id, &start_time);
+        break;
+
+      case GST_MATROSKA_ID_CHAPTERTIMESTOP:
+        ret = gst_ebml_read_uint (ebml, &id, &stop_time);
+        break;
+
+      case GST_MATROSKA_ID_CHAPTERATOM:
+        ret = gst_matroska_read_common_parse_chapter_element (common, ebml,
+            &subsubentries, &internal_subsubentries);
+        break;
+
+      case GST_MATROSKA_ID_CHAPTERDISPLAY:
+        ret =
+            gst_matroska_read_common_parse_chapter_titles (common, ebml, tags);
+        break;
+
+      case GST_MATROSKA_ID_CHAPTERFLAGHIDDEN:
+        ret = gst_ebml_read_uint (ebml, &id, &is_hidden);
+        break;
+
+      case GST_MATROSKA_ID_CHAPTERFLAGENABLED:
+        ret = gst_ebml_read_uint (ebml, &id, &is_enabled);
+        break;
+
+      default:
+        ret =
+            gst_matroska_read_common_parse_skip (common, ebml,
+            "ChaptersElement", id);
+        break;
+    }
+  }
+
+  if (uid == 0)
+    uid = (((guint64) g_random_int ()) << 32) | g_random_int ();
+  uid_str = g_strdup_printf ("%" G_GUINT64_FORMAT, uid);
+  if (string_uid != NULL) {
+    /* init toc with provided String UID */
+    chapter_info = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, string_uid);
+    g_free (string_uid);
+  } else {
+    /* No String UID provided => use the internal UID instead */
+    chapter_info = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, uid_str);
+  }
+  /* init internal toc with internal UID */
+  internal_chapter_info = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER,
+      uid_str);
+  g_free (uid_str);
+
+  gst_toc_entry_set_tags (chapter_info, tags);
+  gst_toc_entry_set_start_stop_times (chapter_info, start_time, stop_time);
+
+  for (l = subsubentries, il = internal_subsubentries;
+      l && il; l = l->next, il = il->next) {
+    gst_toc_entry_append_sub_entry (chapter_info, l->data);
+    gst_toc_entry_append_sub_entry (internal_chapter_info, il->data);
+  }
+  g_list_free (subsubentries);
+  g_list_free (internal_subsubentries);
+
+  DEBUG_ELEMENT_STOP (common, ebml, "ChaptersElement", ret);
+
+  /* start time is mandatory and has no default value,
+   * so we should skip chapters without it */
+  if (is_hidden == 0 && is_enabled > 0 &&
+      start_time != -1 && ret == GST_FLOW_OK) {
+    *subentries = g_list_append (*subentries, chapter_info);
+    *internal_subentries = g_list_append (*internal_subentries,
+        internal_chapter_info);
+  } else {
+    gst_toc_entry_unref (chapter_info);
+    gst_toc_entry_unref (internal_chapter_info);
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_matroska_read_common_parse_chapter_edition (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml, GstToc * toc, GstToc * internal_toc)
+{
+  guint32 id;
+  guint64 is_hidden = 0, uid = 0;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstTocEntry *edition_info, *internal_edition_info;
+  GList *subentries = NULL, *internal_subentries = NULL, *l, *il;
+  gchar *uid_str;
+
+  DEBUG_ELEMENT_START (common, ebml, "ChaptersEdition");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "ChaptersEdition", 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) {
+      case GST_MATROSKA_ID_EDITIONUID:
+        ret = gst_ebml_read_uint (ebml, &id, &uid);
+        break;
+
+      case GST_MATROSKA_ID_CHAPTERATOM:
+        ret = gst_matroska_read_common_parse_chapter_element (common, ebml,
+            &subentries, &internal_subentries);
+        break;
+
+      case GST_MATROSKA_ID_EDITIONFLAGHIDDEN:
+        ret = gst_ebml_read_uint (ebml, &id, &is_hidden);
+        break;
+
+      default:
+        ret =
+            gst_matroska_read_common_parse_skip (common, ebml,
+            "ChaptersEdition", id);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (common, ebml, "ChaptersEdition", ret);
+
+  if (uid == 0)
+    uid = (((guint64) g_random_int ()) << 32) | g_random_int ();
+  uid_str = g_strdup_printf ("%" G_GUINT64_FORMAT, uid);
+  edition_info = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, uid_str);
+  gst_toc_entry_set_start_stop_times (edition_info, -1, -1);
+  internal_edition_info = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION,
+      uid_str);
+  g_free (uid_str);
+
+  for (l = subentries, il = internal_subentries; l && il;
+      l = l->next, il = il->next) {
+    gst_toc_entry_append_sub_entry (edition_info, l->data);
+    gst_toc_entry_append_sub_entry (internal_edition_info, il->data);
+  }
+  g_list_free (subentries);
+  g_list_free (internal_subentries);
+
+  if (is_hidden == 0 && subentries != NULL && ret == GST_FLOW_OK) {
+    gst_toc_append_entry (toc, edition_info);
+    gst_toc_append_entry (internal_toc, internal_edition_info);
+  } else {
+    GST_DEBUG_OBJECT (common->sinkpad,
+        "Skipping empty or hidden edition in the chapters TOC");
+    gst_toc_entry_unref (edition_info);
+    gst_toc_entry_unref (internal_edition_info);
+  }
+
+  return ret;
+}
+
+GstFlowReturn
+gst_matroska_read_common_parse_chapters (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml)
+{
+  guint32 id;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstToc *toc, *internal_toc;
+
+  DEBUG_ELEMENT_START (common, ebml, "Chapters");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "Chapters", ret);
+    return ret;
+  }
+
+  /* FIXME: create CURRENT toc as well */
+  toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
+  internal_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
+
+  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) {
+      case GST_MATROSKA_ID_EDITIONENTRY:
+        ret = gst_matroska_read_common_parse_chapter_edition (common, ebml,
+            toc, internal_toc);
+        break;
+
+      default:
+        ret =
+            gst_matroska_read_common_parse_skip (common, ebml, "Chapters", id);
+        break;
+    }
+  }
+
+  if (gst_toc_get_entries (toc) != NULL) {
+    gst_matroska_read_common_postprocess_toc_entries (gst_toc_get_entries (toc),
+        common->segment.duration, "");
+    /* no need to postprocess internal_toc as we don't need to keep track
+     * of start / end and tags (only UIDs) */
+
+    common->toc = toc;
+    common->internal_toc = internal_toc;
+  } else {
+    gst_toc_unref (toc);
+    gst_toc_unref (internal_toc);
+  }
+
+  common->chapters_parsed = TRUE;
+
+  DEBUG_ELEMENT_STOP (common, ebml, "Chapters", ret);
+  return ret;
+}
+
+GstFlowReturn
+gst_matroska_read_common_parse_header (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml)
+{
+  GstFlowReturn ret;
+  gchar *doctype;
+  guint version;
+  guint32 id;
+
+  /* this function is the first to be called */
+
+  /* default init */
+  doctype = NULL;
+  version = 1;
+
+  ret = gst_ebml_peek_id (ebml, &id);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  GST_DEBUG_OBJECT (common->sinkpad, "id: %08x", id);
+
+  if (id != GST_EBML_ID_HEADER) {
+    GST_ERROR_OBJECT (common->sinkpad, "Failed to read header");
+    goto exit;
+  }
+
+  ret = gst_ebml_read_master (ebml, &id);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  while (gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
+    ret = gst_ebml_peek_id (ebml, &id);
+    if (ret != GST_FLOW_OK)
+      goto exit_error;
+
+    switch (id) {
+        /* is our read version uptodate? */
+      case GST_EBML_ID_EBMLREADVERSION:{
+        guint64 num;
+
+        ret = gst_ebml_read_uint (ebml, &id, &num);
+        if (ret != GST_FLOW_OK)
+          goto exit_error;
+        if (num != GST_EBML_VERSION) {
+          GST_ERROR_OBJECT (common->sinkpad,
+              "Unsupported EBML version %" G_GUINT64_FORMAT, num);
+          goto exit_error;
+        }
+
+        GST_DEBUG_OBJECT (common->sinkpad,
+            "EbmlReadVersion: %" G_GUINT64_FORMAT, num);
+        break;
+      }
+
+        /* we only handle 8 byte lengths at max */
+      case GST_EBML_ID_EBMLMAXSIZELENGTH:{
+        guint64 num;
+
+        ret = gst_ebml_read_uint (ebml, &id, &num);
+        if (ret != GST_FLOW_OK)
+          goto exit_error;
+        if (num > sizeof (guint64)) {
+          GST_ERROR_OBJECT (common->sinkpad,
+              "Unsupported EBML maximum size %" G_GUINT64_FORMAT, num);
+          return GST_FLOW_ERROR;
+        }
+        GST_DEBUG_OBJECT (common->sinkpad,
+            "EbmlMaxSizeLength: %" G_GUINT64_FORMAT, num);
+        break;
+      }
+
+        /* we handle 4 byte IDs at max */
+      case GST_EBML_ID_EBMLMAXIDLENGTH:{
+        guint64 num;
+
+        ret = gst_ebml_read_uint (ebml, &id, &num);
+        if (ret != GST_FLOW_OK)
+          goto exit_error;
+        if (num > sizeof (guint32)) {
+          GST_ERROR_OBJECT (common->sinkpad,
+              "Unsupported EBML maximum ID %" G_GUINT64_FORMAT, num);
+          return GST_FLOW_ERROR;
+        }
+        GST_DEBUG_OBJECT (common->sinkpad,
+            "EbmlMaxIdLength: %" G_GUINT64_FORMAT, num);
+        break;
+      }
+
+      case GST_EBML_ID_DOCTYPE:{
+        gchar *text;
+
+        ret = gst_ebml_read_ascii (ebml, &id, &text);
+        if (ret != GST_FLOW_OK)
+          goto exit_error;
+
+        GST_DEBUG_OBJECT (common->sinkpad, "EbmlDocType: %s",
+            GST_STR_NULL (text));
+
+        g_free (doctype);
+        doctype = text;
+        break;
+      }
+
+      case GST_EBML_ID_DOCTYPEREADVERSION:{
+        guint64 num;
+
+        ret = gst_ebml_read_uint (ebml, &id, &num);
+        if (ret != GST_FLOW_OK)
+          goto exit_error;
+        version = num;
+        GST_DEBUG_OBJECT (common->sinkpad,
+            "EbmlReadVersion: %" G_GUINT64_FORMAT, num);
+        break;
+      }
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (common, ebml,
+            "EBML header", id);
+        if (ret != GST_FLOW_OK)
+          goto exit_error;
+        break;
+
+        /* we ignore these two, as they don't tell us anything we care about */
+      case GST_EBML_ID_EBMLVERSION:
+      case GST_EBML_ID_DOCTYPEVERSION:
+        ret = gst_ebml_read_skip (ebml);
+        if (ret != GST_FLOW_OK)
+          goto exit_error;
+        break;
+    }
+  }
+
+exit:
+
+  if ((doctype != NULL && !strcmp (doctype, GST_MATROSKA_DOCTYPE_MATROSKA)) ||
+      (doctype != NULL && !strcmp (doctype, GST_MATROSKA_DOCTYPE_WEBM)) ||
+      (doctype == NULL)) {
+    if (version <= 2) {
+      if (doctype) {
+        GST_INFO_OBJECT (common->sinkpad, "Input is %s version %d", doctype,
+            version);
+        if (!strcmp (doctype, GST_MATROSKA_DOCTYPE_WEBM))
+          common->is_webm = TRUE;
+      } else {
+        GST_WARNING_OBJECT (common->sinkpad,
+            "Input is EBML without doctype, assuming " "matroska (version %d)",
+            version);
+      }
+      ret = GST_FLOW_OK;
+    } else {
+      GST_ELEMENT_ERROR (common, STREAM, DEMUX, (NULL),
+          ("Demuxer version (2) is too old to read %s version %d",
+              GST_STR_NULL (doctype), version));
+      ret = GST_FLOW_ERROR;
+    }
+  } else {
+    GST_ELEMENT_ERROR (common, STREAM, WRONG_TYPE, (NULL),
+        ("Input is not a matroska stream (doctype=%s)", doctype));
+    ret = GST_FLOW_ERROR;
+  }
+
+exit_error:
+
+  g_free (doctype);
+
+  return ret;
+}
+
+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->sinkpad, "Invalid CueTrack 0");
+          break;
+        }
+
+        GST_DEBUG_OBJECT (common->sinkpad, "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->sinkpad,
+              "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->sinkpad, "Invalid CueBlockNumber 0");
+          break;
+        }
+
+        GST_DEBUG_OBJECT (common->sinkpad, "CueBlockNumber: %" G_GUINT64_FORMAT,
+            num);
+        idx.block = num;
+
+        /* mild sanity check, disregard strange cases ... */
+        if (idx.block > G_MAXUINT16) {
+          GST_DEBUG_OBJECT (common->sinkpad, "... 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);
+
+  /* (e.g.) lavf typically creates entries without a block number,
+   * which is bogus and leads to contradictory information */
+  if (common->index->len) {
+    GstMatroskaIndex *last_idx;
+
+    last_idx = &g_array_index (common->index, GstMatroskaIndex,
+        common->index->len - 1);
+    if (last_idx->block == idx.block && last_idx->pos == idx.pos &&
+        last_idx->track == idx.track && idx.time > last_idx->time) {
+      GST_DEBUG_OBJECT (common->sinkpad, "Cue entry refers to same location, "
+          "but has different time than previous entry; discarding");
+      idx.track = 0;
+    }
+  }
+
+  if ((ret == GST_FLOW_OK || ret == GST_FLOW_EOS)
+      && idx.pos != (guint64) - 1 && idx.track > 0) {
+    g_array_append_val (common->index, idx);
+    (*nentries)++;
+  } else if (ret == GST_FLOW_OK || ret == GST_FLOW_EOS) {
+    GST_DEBUG_OBJECT (common->sinkpad,
+        "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->sinkpad, "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:
+      {
+        ret = gst_matroska_read_common_parse_index_cuetrack (common, ebml,
+            &nentries);
+        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->sinkpad, "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->sinkpad, "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->sinkpad, "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->sinkpad,
+        "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 0
+    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->sinkpad,
+          "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);
+    }
+#endif
+
+    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;
+}
+
+GstFlowReturn
+gst_matroska_read_common_parse_info (GstMatroskaReadCommon * common,
+    GstElement * el, GstEbmlRead * ebml)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  gdouble dur_f = -1.0;
+  guint32 id;
+
+  DEBUG_ELEMENT_START (common, ebml, "SegmentInfo");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "SegmentInfo", 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) {
+        /* cluster timecode */
+      case GST_MATROSKA_ID_TIMECODESCALE:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+
+        GST_DEBUG_OBJECT (common->sinkpad, "TimeCodeScale: %" G_GUINT64_FORMAT,
+            num);
+        common->time_scale = num;
+        break;
+      }
+
+      case GST_MATROSKA_ID_DURATION:{
+        if ((ret = gst_ebml_read_float (ebml, &id, &dur_f)) != GST_FLOW_OK)
+          break;
+
+        if (dur_f <= 0.0) {
+          GST_WARNING_OBJECT (common->sinkpad, "Invalid duration %lf", dur_f);
+          break;
+        }
+
+        GST_DEBUG_OBJECT (common->sinkpad, "Duration: %lf", dur_f);
+        break;
+      }
+
+      case GST_MATROSKA_ID_WRITINGAPP:{
+        gchar *text;
+
+        if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
+          break;
+
+        GST_DEBUG_OBJECT (common->sinkpad, "WritingApp: %s",
+            GST_STR_NULL (text));
+        common->writing_app = text;
+        break;
+      }
+
+      case GST_MATROSKA_ID_MUXINGAPP:{
+        gchar *text;
+
+        if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
+          break;
+
+        GST_DEBUG_OBJECT (common->sinkpad, "MuxingApp: %s",
+            GST_STR_NULL (text));
+        common->muxing_app = text;
+        break;
+      }
+
+      case GST_MATROSKA_ID_DATEUTC:{
+        gint64 time;
+
+        if ((ret = gst_ebml_read_date (ebml, &id, &time)) != GST_FLOW_OK)
+          break;
+
+        GST_DEBUG_OBJECT (common->sinkpad, "DateUTC: %" G_GINT64_FORMAT, time);
+        common->created = time;
+        break;
+      }
+
+      case GST_MATROSKA_ID_TITLE:{
+        gchar *text;
+        GstTagList *taglist;
+
+        if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
+          break;
+
+        GST_DEBUG_OBJECT (common->sinkpad, "Title: %s", GST_STR_NULL (text));
+        taglist = gst_tag_list_new (GST_TAG_TITLE, text, NULL);
+        gst_tag_list_set_scope (taglist, GST_TAG_SCOPE_GLOBAL);
+        gst_matroska_read_common_found_global_tag (common, el, taglist);
+        g_free (text);
+        break;
+      }
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (common, ebml,
+            "SegmentInfo", id);
+        break;
+
+        /* fall through */
+      case GST_MATROSKA_ID_SEGMENTUID:
+      case GST_MATROSKA_ID_SEGMENTFILENAME:
+      case GST_MATROSKA_ID_PREVUID:
+      case GST_MATROSKA_ID_PREVFILENAME:
+      case GST_MATROSKA_ID_NEXTUID:
+      case GST_MATROSKA_ID_NEXTFILENAME:
+      case GST_MATROSKA_ID_SEGMENTFAMILY:
+      case GST_MATROSKA_ID_CHAPTERTRANSLATE:
+        ret = gst_ebml_read_skip (ebml);
+        break;
+    }
+  }
+
+  if (dur_f > 0.0) {
+    GstClockTime dur_u;
+
+    dur_u = gst_gdouble_to_guint64 (dur_f *
+        gst_guint64_to_gdouble (common->time_scale));
+    if (GST_CLOCK_TIME_IS_VALID (dur_u) && dur_u <= G_MAXINT64)
+      common->segment.duration = dur_u;
+  }
+
+  DEBUG_ELEMENT_STOP (common, ebml, "SegmentInfo", ret);
+
+  common->segmentinfo_parsed = TRUE;
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_matroska_read_common_parse_metadata_id_simple_tag (GstMatroskaReadCommon *
+    common, GstEbmlRead * ebml, GstTagList ** p_taglist, gchar * parent)
+{
+  /* FIXME: check if there are more useful mappings */
+  static const struct
+  {
+    const gchar *matroska_tagname;
+    const gchar *gstreamer_tagname;
+  }
+  tag_conv[] = {
+    {
+      /* The following list has the _same_ order as the one in Matroska spec. Please, don't mess it up. */
+      /* TODO: Nesting information:
+         ORIGINAL A special tag that is meant to have other tags inside (using nested tags) to describe the original work of art that this item is based on. All tags in this list can be used "under" the ORIGINAL tag like LYRICIST, PERFORMER, etc.
+         SAMPLE A tag that contains other tags to describe a sample used in the targeted item taken from another work of art. All tags in this list can be used "under" the SAMPLE tag like TITLE, ARTIST, DATE_RELEASED, etc.
+         COUNTRY The name of the country (biblio ISO-639-2) that is meant to have other tags inside (using nested tags) to country specific information about the item. All tags in this list can be used "under" the COUNTRY_SPECIFIC tag like LABEL, PUBLISH_RATING, etc.
+       */
+
+      /* Organizational Information */
+    GST_MATROSKA_TAG_ID_TOTAL_PARTS, GST_TAG_TRACK_COUNT}, {
+    GST_MATROSKA_TAG_ID_PART_NUMBER, GST_TAG_TRACK_NUMBER}, {
+      /* TODO: PART_OFFSET A number to add to PART_NUMBER when the parts at that level don't start at 1. (e.g. if TargetType is TRACK, the track number of the second audio CD) */
+
+      /* Titles */
+    GST_MATROSKA_TAG_ID_SUBTITLE, GST_TAG_TITLE}, {     /* Sub Title of the entity. Since we're concat'ing all title-like entities anyway, might as well add the sub-title. */
+    GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
+    GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {        /* Matroska spec does NOT have this tag! Dunno what it was doing here, probably for compatibility. */
+
+      /* TODO: Nested Information:
+         URL URL corresponding to the tag it's included in.
+         SORT_WITH A child element to indicate what alternative value the parent tag can have to be sorted, for example "Pet Shop Boys" instead of "The Pet Shop Boys". Or "Marley Bob" and "Marley Ziggy" (no comma needed).
+         INSTRUMENTS The instruments that are being used/played, separated by a comma. It should be a child of the following tags: ARTIST, LEAD_PERFORMER or ACCOMPANIMENT.
+         EMAIL Email corresponding to the tag it's included in.
+         ADDRESS The physical address of the entity. The address should include a country code. It can be useful for a recording label.
+         FAX The fax number corresponding to the tag it's included in. It can be useful for a recording label.
+         PHONE The phone number corresponding to the tag it's included in. It can be useful for a recording label.
+       */
+
+      /* Entities */
+    GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
+    GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
+    GST_MATROSKA_TAG_ID_ACCOMPANIMENT, GST_TAG_PERFORMER}, {    /* Band/orchestra/accompaniment/musician. This is akin to the TPE2 tag in ID3. */
+    GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
+      /* ARRANGER The person who arranged the piece, e.g., Ravel. */
+    GST_MATROSKA_TAG_ID_LYRICS, GST_TAG_LYRICS}, {      /* The lyrics corresponding to a song (in case audio synchronization is not known or as a doublon to a subtitle track). Editing this value when subtitles are found should also result in editing the subtitle track for more consistency. */
+      /* LYRICIST The person who wrote the lyrics for a musical item. This is akin to the TEXT tag in ID3. */
+    GST_MATROSKA_TAG_ID_CONDUCTOR, GST_TAG_PERFORMER}, {        /* Conductor/performer refinement. This is akin to the TPE3 tag in ID3. */
+      /* DIRECTOR This is akin to the IART tag in RIFF. */
+    GST_MATROSKA_TAG_ID_AUTHOR, GST_TAG_ARTIST}, {
+      /* ASSISTANT_DIRECTOR The name of the assistant director. */
+      /* DIRECTOR_OF_PHOTOGRAPHY The name of the director of photography, also known as cinematographer. This is akin to the ICNM tag in Extended RIFF. */
+      /* SOUND_ENGINEER The name of the sound engineer or sound recordist. */
+      /* ART_DIRECTOR The person who oversees the artists and craftspeople who build the sets. */
+      /* PRODUCTION_DESIGNER Artist responsible for designing the overall visual appearance of a movie. */
+      /* CHOREGRAPHER The name of the choregrapher */
+      /* COSTUME_DESIGNER The name of the costume designer */
+      /* ACTOR An actor or actress playing a role in this movie. This is the person's real name, not the character's name the person is playing. */
+      /* CHARACTER The name of the character an actor or actress plays in this movie. This should be a sub-tag of an ACTOR tag in order not to cause ambiguities. */
+      /* WRITTEN_BY The author of the story or script (used for movies and TV shows). */
+      /* SCREENPLAY_BY The author of the screenplay or scenario (used for movies and TV shows). */
+      /* EDITED_BY This is akin to the IEDT tag in Extended RIFF. */
+      /* PRODUCER Produced by. This is akin to the IPRO tag in Extended RIFF. */
+      /* COPRODUCER The name of a co-producer. */
+      /* EXECUTIVE_PRODUCER The name of an executive producer. */
+      /* DISTRIBUTED_BY This is akin to the IDST tag in Extended RIFF. */
+      /* MASTERED_BY The engineer who mastered the content for a physical medium or for digital distribution. */
+    GST_MATROSKA_TAG_ID_ENCODED_BY, GST_TAG_ENCODED_BY}, {      /* This is akin to the TENC tag in ID3. */
+      /* MIXED_BY DJ mix by the artist specified */
+      /* REMIXED_BY Interpreted, remixed, or otherwise modified by. This is akin to the TPE4 tag in ID3. */
+      /* PRODUCTION_STUDIO This is akin to the ISTD tag in Extended RIFF. */
+      /* THANKS_TO A very general tag for everyone else that wants to be listed. */
+      /* PUBLISHER This is akin to the TPUB tag in ID3. */
+      /* LABEL The record label or imprint on the disc. */
+      /* Search / Classification */
+    GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}, {
+      /* MOOD Intended to reflect the mood of the item with a few keywords, e.g. "Romantic", "Sad" or "Uplifting". The format follows that of the TMOO tag in ID3. */
+      /* ORIGINAL_MEDIA_TYPE Describes the original type of the media, such as, "DVD", "CD", "computer image," "drawing," "lithograph," and so forth. This is akin to the TMED tag in ID3. */
+      /* CONTENT_TYPE The type of the item. e.g. Documentary, Feature Film, Cartoon, Music Video, Music, Sound FX, ... */
+      /* SUBJECT Describes the topic of the file, such as "Aerial view of Seattle." */
+    GST_MATROSKA_TAG_ID_DESCRIPTION, GST_TAG_DESCRIPTION}, {    /* A short description of the content, such as "Two birds flying." */
+    GST_MATROSKA_TAG_ID_KEYWORDS, GST_TAG_KEYWORDS}, {  /* Keywords to the item separated by a comma, used for searching. */
+      /* SUMMARY A plot outline or a summary of the story. */
+      /* SYNOPSIS A description of the story line of the item. */
+      /* INITIAL_KEY The initial key that a musical track starts in. The format is identical to ID3. */
+      /* PERIOD Describes the period that the piece is from or about. For example, "Renaissance". */
+      /* LAW_RATING Depending on the country it's the format of the rating of a movie (P, R, X in the USA, an age in other countries or a URI defining a logo). */
+      /* ICRA The ICRA content rating for parental control. (Previously RSACi) */
+
+      /* Temporal Information */
+    GST_MATROSKA_TAG_ID_DATE_RELEASED, GST_TAG_DATE}, { /* The time that the item was originaly released. This is akin to the TDRL tag in ID3. */
+    GST_MATROSKA_TAG_ID_DATE_RECORDED, GST_TAG_DATE}, { /* The time that the recording began. This is akin to the TDRC tag in ID3. */
+    GST_MATROSKA_TAG_ID_DATE_ENCODED, GST_TAG_DATE}, {  /* The time that the encoding of this item was completed began. This is akin to the TDEN tag in ID3. */
+    GST_MATROSKA_TAG_ID_DATE_TAGGED, GST_TAG_DATE}, {   /* The time that the tags were done for this item. This is akin to the TDTG tag in ID3. */
+    GST_MATROSKA_TAG_ID_DATE_DIGITIZED, GST_TAG_DATE}, {        /* The time that the item was tranfered to a digital medium. This is akin to the IDIT tag in RIFF. */
+    GST_MATROSKA_TAG_ID_DATE_WRITTEN, GST_TAG_DATE}, {  /* The time that the writing of the music/script began. */
+    GST_MATROSKA_TAG_ID_DATE_PURCHASED, GST_TAG_DATE}, {        /* Information on when the file was purchased (see also purchase tags). */
+    GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {  /* Matroska spec does NOT have this tag! Dunno what it was doing here, probably for compatibility. */
+
+      /* Spacial Information */
+    GST_MATROSKA_TAG_ID_RECORDING_LOCATION, GST_TAG_GEO_LOCATION_NAME}, {       /* The location where the item was recorded. The countries corresponding to the string, same 2 octets as in Internet domains, or possibly ISO-3166. This code is followed by a comma, then more detailed information such as state/province, another comma, and then city. For example, "US, Texas, Austin". This will allow for easy sorting. It is okay to only store the country, or the country and the state/province. More detailed information can be added after the city through the use of additional commas. In cases where the province/state is unknown, but you want to store the city, simply leave a space between the two commas. For example, "US, , Austin". */
+      /* COMPOSITION_LOCATION Location that the item was originaly designed/written. The countries corresponding to the string, same 2 octets as in Internet domains, or possibly ISO-3166. This code is followed by a comma, then more detailed information such as state/province, another comma, and then city. For example, "US, Texas, Austin". This will allow for easy sorting. It is okay to only store the country, or the country and the state/province. More detailed information can be added after the city through the use of additional commas. In cases where the province/state is unknown, but you want to store the city, simply leave a space between the two commas. For example, "US, , Austin". */
+      /* COMPOSER_NATIONALITY Nationality of the main composer of the item, mostly for classical music. The countries corresponding to the string, same 2 octets as in Internet domains, or possibly ISO-3166. */
+
+      /* Personal */
+    GST_MATROSKA_TAG_ID_COMMENT, GST_TAG_COMMENT}, {    /* Any comment related to the content. */
+    GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {   /* Matroska spec does NOT have this tag! Dunno what it was doing here, probably for compatibility. */
+      /* PLAY_COUNTER The number of time the item has been played. */
+      /* TODO: RATING A numeric value defining how much a person likes the song/movie. The number is between 0 and 5 with decimal values possible (e.g. 2.7), 5(.0) being the highest possible rating. Other rating systems with different ranges will have to be scaled. */
+
+      /* Technical Information */
+    GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
+      /* ENCODER_SETTINGS A list of the settings used for encoding this item. No specific format. */
+    GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
+    GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {     /* Matroska spec does NOT have this tag! Dunno what it was doing here, probably for compatibility. */
+      /* WONTFIX (already handled in another way): FPS The average frames per second of the specified item. This is typically the average number of Blocks per second. In the event that lacing is used, each laced chunk is to be counted as a seperate frame. */
+    GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
+      /* MEASURE In music, a measure is a unit of time in Western music like "4/4". It represents a regular grouping of beats, a meter, as indicated in musical notation by the time signature.. The majority of the contemporary rock and pop music you hear on the radio these days is written in the 4/4 time signature. */
+      /* TUNING It is saved as a frequency in hertz to allow near-perfect tuning of instruments to the same tone as the musical piece (e.g. "441.34" in Hertz). The default value is 440.0 Hz. */
+      /* TODO: REPLAYGAIN_GAIN The gain to apply to reach 89dB SPL on playback. This is based on the Replay Gain standard. Note that ReplayGain information can be found at all TargetType levels (track, album, etc). */
+      /* TODO: REPLAYGAIN_PEAK The maximum absolute peak value of the item. This is based on the Replay Gain standard. */
+
+      /* Identifiers */
+    GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
+      /* MCDI This is a binary dump of the TOC of the CDROM that this item was taken from. This holds the same information as the MCDI in ID3. */
+      /* ISBN International Standard Book Number */
+      /* BARCODE EAN-13 (European Article Numbering) or UPC-A (Universal Product Code) bar code identifier */
+      /* CATALOG_NUMBER A label-specific string used to identify the release (TIC 01 for example). */
+      /* LABEL_CODE A 4-digit or 5-digit number to identify the record label, typically printed as (LC) xxxx or (LC) 0xxxx on CDs medias or covers (only the number is stored). */
+      /* LCCN Library of Congress Control Number */
+
+      /* Commercial */
+      /* PURCHASE_ITEM URL to purchase this file. This is akin to the WPAY tag in ID3. */
+      /* PURCHASE_INFO Information on where to purchase this album. This is akin to the WCOM tag in ID3. */
+      /* PURCHASE_OWNER Information on the person who purchased the file. This is akin to the TOWN tag in ID3. */
+      /* PURCHASE_PRICE The amount paid for entity. There should only be a numeric value in here. Only numbers, no letters or symbols other than ".". For instance, you would store "15.59" instead of "$15.59USD". */
+      /* PURCHASE_CURRENCY The currency type used to pay for the entity. Use ISO-4217 for the 3 letter currency code. */
+
+      /* Legal */
+    GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
+    GST_MATROSKA_TAG_ID_PRODUCTION_COPYRIGHT, GST_TAG_COPYRIGHT}, {     /* The copyright information as per the production copyright holder. This is akin to the TPRO tag in ID3. */
+    GST_MATROSKA_TAG_ID_LICENSE, GST_TAG_LICENSE}, {    /* The license applied to the content (like Creative Commons variants). */
+    GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}
+  };
+  static const struct
+  {
+    const gchar *matroska_tagname;
+    const gchar *gstreamer_tagname;
+  }
+  child_tag_conv[] = {
+    {
+    "TITLE/SORT_WITH=", GST_TAG_TITLE_SORTNAME}, {
+    "ARTIST/SORT_WITH=", GST_TAG_ARTIST_SORTNAME}, {
+      /* ALBUM-stuff is handled elsewhere */
+    "COMPOSER/SORT_WITH=", GST_TAG_TITLE_SORTNAME}, {
+    "ORIGINAL/URL=", GST_TAG_LOCATION}, {
+      /* EMAIL, PHONE, FAX all can be mapped to GST_TAG_CONTACT, there is special
+       * code for that later.
+       */
+    "TITLE/URL=", GST_TAG_HOMEPAGE}, {
+    "ARTIST/URL=", GST_TAG_HOMEPAGE}, {
+    "COPYRIGHT/URL=", GST_TAG_COPYRIGHT_URI}, {
+    "LICENSE/URL=", GST_TAG_LICENSE_URI}, {
+    "LICENSE/URL=", GST_TAG_LICENSE_URI}
+  };
+  GstFlowReturn ret;
+  guint32 id;
+  gchar *value = NULL;
+  gchar *tag = NULL;
+  gchar *name_with_parent = NULL;
+  GstTagList *child_taglist = NULL;
+
+  DEBUG_ELEMENT_START (common, ebml, "SimpleTag");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "SimpleTag", ret);
+    return ret;
+  }
+
+  if (parent)
+    child_taglist = *p_taglist;
+  else
+    child_taglist = gst_tag_list_new_empty ();
+
+  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
+    /* read all sub-entries */
+
+    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
+      break;
+
+    switch (id) {
+      case GST_MATROSKA_ID_TAGNAME:
+        g_free (tag);
+        tag = NULL;
+        ret = gst_ebml_read_ascii (ebml, &id, &tag);
+        GST_DEBUG_OBJECT (common->sinkpad, "TagName: %s", GST_STR_NULL (tag));
+        g_free (name_with_parent);
+        if (parent != NULL)
+          name_with_parent = g_strdup_printf ("%s/%s", parent, tag);
+        else
+          name_with_parent = g_strdup (tag);
+        break;
+
+      case GST_MATROSKA_ID_TAGSTRING:
+        g_free (value);
+        value = NULL;
+        ret = gst_ebml_read_utf8 (ebml, &id, &value);
+        GST_DEBUG_OBJECT (common->sinkpad, "TagString: %s",
+            GST_STR_NULL (value));
+        break;
+
+      case GST_MATROSKA_ID_SIMPLETAG:
+        /* Recursive SimpleTag */
+        /* This implementation requires tag name of _this_ tag to be known
+         * in order to read its children. It's not in the spec, just the way
+         * the code is written.
+         */
+        if (name_with_parent != NULL) {
+          ret = gst_matroska_read_common_parse_metadata_id_simple_tag (common,
+              ebml, &child_taglist, name_with_parent);
+          break;
+        }
+        /* fall-through */
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (common, ebml, "SimpleTag",
+            id);
+        break;
+
+      case GST_MATROSKA_ID_TAGLANGUAGE:
+      case GST_MATROSKA_ID_TAGDEFAULT:
+      case GST_MATROSKA_ID_TAGBINARY:
+        ret = gst_ebml_read_skip (ebml);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (common, ebml, "SimpleTag", ret);
+
+  if (parent && tag && value && *value != '\0') {
+    /* Don't bother mapping children tags - parent will do that */
+    gchar *key_val;
+    /* TODO: read LANGUAGE sub-tag, and use "key[lc]=val" form */
+    key_val = g_strdup_printf ("%s=%s", name_with_parent, value);
+    gst_tag_list_add (*p_taglist, GST_TAG_MERGE_APPEND,
+        GST_TAG_EXTENDED_COMMENT, key_val, NULL);
+    g_free (key_val);
+  } else if (tag && value && *value != '\0') {
+    gboolean matched = FALSE;
+    guint i;
+
+    for (i = 0; !matched && i < G_N_ELEMENTS (tag_conv); i++) {
+      const gchar *tagname_gst = tag_conv[i].gstreamer_tagname;
+
+      const gchar *tagname_mkv = tag_conv[i].matroska_tagname;
+
+      if (strcmp (tagname_mkv, tag) == 0) {
+        GValue dest = { 0, };
+        GType dest_type = gst_tag_get_type (tagname_gst);
+
+        /* Ensure that any date string is complete */
+        if (dest_type == G_TYPE_DATE) {
+          guint year = 1901, month = 1, day = 1;
+
+          /* Dates can be yyyy-MM-dd, yyyy-MM or yyyy, but we need
+           * the first type */
+          if (sscanf (value, "%04u-%02u-%02u", &year, &month, &day) != 0) {
+            g_free (value);
+            value = g_strdup_printf ("%04u-%02u-%02u", year, month, day);
+          }
+        }
+
+        g_value_init (&dest, dest_type);
+        if (gst_value_deserialize (&dest, value)) {
+          gst_tag_list_add_values (*p_taglist, GST_TAG_MERGE_APPEND,
+              tagname_gst, &dest, NULL);
+        } else {
+          GST_WARNING_OBJECT (common->sinkpad, "Can't transform tag '%s' with "
+              "value '%s' to target type '%s'", tag, value,
+              g_type_name (dest_type));
+        }
+        g_value_unset (&dest);
+        matched = TRUE;
+      }
+    }
+    if (!matched) {
+      gchar *key_val;
+      /* TODO: read LANGUAGE sub-tag, and use "key[lc]=val" form */
+      key_val = g_strdup_printf ("%s=%s", tag, value);
+      gst_tag_list_add (*p_taglist, GST_TAG_MERGE_APPEND,
+          GST_TAG_EXTENDED_COMMENT, key_val, NULL);
+      g_free (key_val);
+    }
+  }
+
+  if (!parent) {
+    /* Map children tags. This only supports top-anchored mapping. That is,
+     * we start at toplevel tag (this tag), and see how its combinations
+     * with its children can be mapped. Which means that grandchildren
+     * are also combined here, with _this_ tag taken into consideration.
+     * If grandchildren can be combined only with children, that combination
+     * will not happen.
+     */
+    gint child_tags_n = gst_tag_list_n_tags (child_taglist);
+    if (child_tags_n > 0) {
+      gint i;
+      for (i = 0; i < child_tags_n; i++) {
+        gint j;
+        const gchar *child_name = gst_tag_list_nth_tag_name (child_taglist, i);
+        guint taglen = gst_tag_list_get_tag_size (child_taglist, child_name);
+        for (j = 0; j < taglen; j++) {
+          gchar *val;
+          gboolean matched = FALSE;
+          gchar *val_pre, *val_post;
+          gint k;
+
+          if (!gst_tag_list_get_string_index (child_taglist, child_name,
+                  j, &val))
+            continue;
+          if (!strchr (val, '=')) {
+            g_free (val);
+            continue;
+          }
+          val_post = g_strdup (strchr (val, '=') + 1);
+          val_pre = g_strdup (val);
+          *(strchr (val_pre, '=') + 1) = '\0';
+
+          for (k = 0; !matched && k < G_N_ELEMENTS (child_tag_conv); k++) {
+            const gchar *tagname_gst = child_tag_conv[k].gstreamer_tagname;
+
+            const gchar *tagname_mkv = child_tag_conv[k].matroska_tagname;
+
+            /* TODO: Once "key[lc]=value" form support is implemented,
+             * strip [lc] here. It can't be used in combined tags.
+             * If a tag is not combined, leave [lc] as it is.
+             */
+            if (strcmp (tagname_mkv, val_pre) == 0) {
+              GValue dest = { 0, };
+              GType dest_type = gst_tag_get_type (tagname_gst);
+
+              g_value_init (&dest, dest_type);
+              if (gst_value_deserialize (&dest, val_post)) {
+                gst_tag_list_add_values (*p_taglist, GST_TAG_MERGE_APPEND,
+                    tagname_gst, &dest, NULL);
+              } else {
+                GST_WARNING_OBJECT (common->sinkpad,
+                    "Can't transform complex tag '%s' " "to target type '%s'",
+                    val, g_type_name (dest_type));
+              }
+              g_value_unset (&dest);
+              matched = TRUE;
+            }
+          }
+          if (!matched) {
+            gchar *last_slash = strrchr (val_pre, '/');
+            if (last_slash) {
+              last_slash++;
+              if (strcmp (last_slash, "EMAIL=") == 0 ||
+                  strcmp (last_slash, "PHONE=") == 0 ||
+                  strcmp (last_slash, "ADDRESS=") == 0 ||
+                  strcmp (last_slash, "FAX=") == 0) {
+                gst_tag_list_add (*p_taglist, GST_TAG_MERGE_APPEND,
+                    GST_TAG_CONTACT, val_post, NULL);
+                matched = TRUE;
+              }
+            }
+          }
+          if (!matched)
+            gst_tag_list_add (*p_taglist, GST_TAG_MERGE_APPEND,
+                GST_TAG_EXTENDED_COMMENT, val, NULL);
+          g_free (val_post);
+          g_free (val_pre);
+          g_free (val);
+        }
+      }
+    }
+    gst_tag_list_unref (child_taglist);
+  }
+
+  g_free (tag);
+  g_free (value);
+  g_free (name_with_parent);
+
+  return ret;
+}
+
+
+static void
+gst_matroska_read_common_count_streams (GstMatroskaReadCommon * common,
+    gint * a, gint * v, gint * s)
+{
+  gint i;
+  gint video_streams = 0, audio_streams = 0, subtitle_streams = 0;
+
+  for (i = 0; i < common->src->len; i++) {
+    GstMatroskaTrackContext *stream;
+
+    stream = g_ptr_array_index (common->src, i);
+    if (stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO)
+      video_streams += 1;
+    else if (stream->type == GST_MATROSKA_TRACK_TYPE_AUDIO)
+      audio_streams += 1;
+    else if (stream->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE)
+      subtitle_streams += 1;
+  }
+  *v = video_streams;
+  *a = audio_streams;
+  *s = subtitle_streams;
+}
+
+
+static void
+gst_matroska_read_common_apply_target_type_foreach (const GstTagList * list,
+    const gchar * tag, gpointer user_data)
+{
+  guint vallen;
+  guint i;
+  TargetTypeContext *ctx = (TargetTypeContext *) user_data;
+
+  vallen = gst_tag_list_get_tag_size (list, tag);
+  if (vallen == 0)
+    return;
+
+  for (i = 0; i < vallen; i++) {
+    const GValue *val_ref;
+
+    val_ref = gst_tag_list_get_value_index (list, tag, i);
+    if (val_ref == NULL)
+      continue;
+
+    /* TODO: use the optional ctx->target_type somehow */
+    if (strcmp (tag, GST_TAG_TITLE) == 0) {
+      if (ctx->target_type_value >= 70 && !ctx->audio_only) {
+        gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
+            GST_TAG_SHOW_NAME, val_ref);
+        continue;
+      } else if (ctx->target_type_value >= 50) {
+        gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
+            GST_TAG_TITLE, val_ref);
+        continue;
+      }
+    } else if (strcmp (tag, GST_TAG_TITLE_SORTNAME) == 0) {
+      if (ctx->target_type_value >= 70 && !ctx->audio_only) {
+        gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
+            GST_TAG_SHOW_SORTNAME, val_ref);
+        continue;
+      } else if (ctx->target_type_value >= 50) {
+        gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
+            GST_TAG_TITLE_SORTNAME, val_ref);
+        continue;
+      }
+    } else if (strcmp (tag, GST_TAG_ARTIST) == 0) {
+      if (ctx->target_type_value >= 50) {
+        gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
+            GST_TAG_ARTIST, val_ref);
+        continue;
+      }
+    } else if (strcmp (tag, GST_TAG_ARTIST_SORTNAME) == 0) {
+      if (ctx->target_type_value >= 50) {
+        gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
+            GST_TAG_ARTIST_SORTNAME, val_ref);
+        continue;
+      }
+    } else if (strcmp (tag, GST_TAG_TRACK_COUNT) == 0) {
+      if (ctx->target_type_value >= 60) {
+        gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
+            GST_TAG_ALBUM_VOLUME_COUNT, val_ref);
+        continue;
+      }
+    } else if (strcmp (tag, GST_TAG_TRACK_NUMBER) == 0) {
+      if (ctx->target_type_value >= 60 && !ctx->audio_only) {
+        gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
+            GST_TAG_SHOW_SEASON_NUMBER, val_ref);
+        continue;
+      } else if (ctx->target_type_value >= 50 && !ctx->audio_only) {
+        gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
+            GST_TAG_SHOW_EPISODE_NUMBER, val_ref);
+        continue;
+      } else if (ctx->target_type_value >= 50) {
+        gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND,
+            GST_TAG_ALBUM_VOLUME_NUMBER, val_ref);
+        continue;
+      }
+    }
+    gst_tag_list_add_value (ctx->result, GST_TAG_MERGE_APPEND, tag, val_ref);
+  }
+}
+
+
+static GstTagList *
+gst_matroska_read_common_apply_target_type (GstMatroskaReadCommon * common,
+    GstTagList * taglist, guint64 target_type_value, gchar * target_type)
+{
+  TargetTypeContext ctx;
+  gint a = 0;
+  gint v = 0;
+  gint s = 0;
+
+  gst_matroska_read_common_count_streams (common, &a, &v, &s);
+
+  ctx.audio_only = (a > 0 && v == 0 && s == 0);
+  ctx.result = gst_tag_list_new_empty ();
+  ctx.target_type_value = target_type_value;
+  ctx.target_type = target_type;
+
+  gst_tag_list_foreach (taglist,
+      gst_matroska_read_common_apply_target_type_foreach, &ctx);
+
+  gst_tag_list_unref (taglist);
+  return ctx.result;
+}
+
+
+static GstFlowReturn
+gst_matroska_read_common_parse_metadata_id_tag (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml, GstTagList ** p_taglist)
+{
+  guint32 id;
+  GstFlowReturn ret;
+  GArray *chapter_targets, *edition_targets, *track_targets;
+  GstTagList *taglist;
+  GList *cur, *internal_cur;
+  guint64 target_type_value = 50;
+  gchar *target_type = NULL;
+
+  DEBUG_ELEMENT_START (common, ebml, "Tag");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "Tag", ret);
+    return ret;
+  }
+
+  edition_targets = g_array_new (FALSE, FALSE, sizeof (guint64));
+  chapter_targets = g_array_new (FALSE, FALSE, sizeof (guint64));
+  track_targets = g_array_new (FALSE, FALSE, sizeof (guint64));
+  taglist = gst_tag_list_new_empty ();
+  target_type = NULL;
+
+  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
+    /* read all sub-entries */
+
+    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
+      break;
+
+    switch (id) {
+      case GST_MATROSKA_ID_SIMPLETAG:
+        ret = gst_matroska_read_common_parse_metadata_id_simple_tag (common,
+            ebml, &taglist, NULL);
+        break;
+
+      case GST_MATROSKA_ID_TARGETS:
+        g_free (target_type);
+        target_type = NULL;
+        target_type_value = 50;
+        ret = gst_matroska_read_common_parse_metadata_targets (common, ebml,
+            edition_targets, chapter_targets, track_targets,
+            &target_type_value, &target_type);
+        break;
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (common, ebml, "Tag", id);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (common, ebml, "Tag", ret);
+
+  taglist = gst_matroska_read_common_apply_target_type (common, taglist,
+      target_type_value, target_type);
+  g_free (target_type);
+
+  /* if tag is chapter/edition specific - try to find that entry */
+  if (G_UNLIKELY (chapter_targets->len > 0 || edition_targets->len > 0 ||
+          track_targets->len > 0)) {
+    gint i;
+    if (chapter_targets->len > 0 || edition_targets->len > 0) {
+      if (common->toc == NULL)
+        GST_WARNING_OBJECT (common->sinkpad,
+            "Found chapter/edition specific tag, but TOC is not present");
+      else {
+        cur = gst_toc_get_entries (common->toc);
+        internal_cur = gst_toc_get_entries (common->internal_toc);
+        while (cur != NULL && internal_cur != NULL) {
+          gst_matroska_read_common_parse_toc_tag (cur->data, internal_cur->data,
+              edition_targets, chapter_targets, taglist);
+          cur = cur->next;
+          internal_cur = internal_cur->next;
+        }
+        common->toc_updated = TRUE;
+      }
+    }
+    for (i = 0; i < track_targets->len; i++) {
+      gint j;
+      gboolean found = FALSE;
+      guint64 tgt = g_array_index (track_targets, guint64, i);
+
+      for (j = 0; j < common->src->len; j++) {
+        GstMatroskaTrackContext *stream = g_ptr_array_index (common->src, j);
+
+        if (stream->uid == tgt) {
+          gst_tag_list_insert (stream->tags, taglist, GST_TAG_MERGE_REPLACE);
+          stream->tags_changed = TRUE;
+          found = TRUE;
+        }
+      }
+      if (!found) {
+        /* Cache the track taglist: possibly belongs to a track that will be parsed
+           later in gst_matroska_demux.c:gst_matroska_demux_add_stream (...) */
+        gpointer track_uid = GUINT_TO_POINTER (tgt);
+        GstTagList *cached_taglist =
+            g_hash_table_lookup (common->cached_track_taglists, track_uid);
+        if (cached_taglist)
+          gst_tag_list_insert (cached_taglist, taglist, GST_TAG_MERGE_REPLACE);
+        else {
+          gst_tag_list_ref (taglist);
+          g_hash_table_insert (common->cached_track_taglists, track_uid,
+              taglist);
+        }
+        GST_DEBUG_OBJECT (common->sinkpad,
+            "Found track-specific tag(s), but track %" G_GUINT64_FORMAT
+            " is not known yet, caching", tgt);
+      }
+    }
+  } else
+    gst_tag_list_insert (*p_taglist, taglist, GST_TAG_MERGE_APPEND);
+
+  gst_tag_list_unref (taglist);
+  g_array_unref (chapter_targets);
+  g_array_unref (edition_targets);
+  g_array_unref (track_targets);
+
+  return ret;
+}
+
+GstFlowReturn
+gst_matroska_read_common_parse_metadata (GstMatroskaReadCommon * common,
+    GstElement * el, GstEbmlRead * ebml)
+{
+  GstTagList *taglist;
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint32 id;
+  GList *l;
+  guint64 curpos;
+
+  /* Make sure we don't parse a tags element twice and
+   * post it's tags twice */
+  curpos = gst_ebml_read_get_pos (ebml);
+  for (l = common->tags_parsed; l; l = l->next) {
+    guint64 *pos = l->data;
+
+    if (*pos == curpos) {
+      GST_DEBUG_OBJECT (common->sinkpad,
+          "Skipping already parsed Tags at offset %" G_GUINT64_FORMAT, curpos);
+      return GST_FLOW_OK;
+    }
+  }
+
+  common->tags_parsed =
+      g_list_prepend (common->tags_parsed, g_slice_new (guint64));
+  *((guint64 *) common->tags_parsed->data) = curpos;
+  /* fall-through */
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "Tags", ret);
+    return ret;
+  }
+
+  taglist = gst_tag_list_new_empty ();
+  gst_tag_list_set_scope (taglist, GST_TAG_SCOPE_GLOBAL);
+  common->toc_updated = FALSE;
+
+  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) {
+      case GST_MATROSKA_ID_TAG:
+        ret = gst_matroska_read_common_parse_metadata_id_tag (common, ebml,
+            &taglist);
+        break;
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (common, ebml, "Tags", id);
+        break;
+        /* FIXME: Use to limit the tags to specific pads */
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (common, ebml, "Tags", ret);
+
+  if (G_LIKELY (!gst_tag_list_is_empty (taglist)))
+    gst_matroska_read_common_found_global_tag (common, el, taglist);
+  else
+    gst_tag_list_unref (taglist);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_matroska_read_common_peek_adapter (GstMatroskaReadCommon * common, guint
+    peek, const guint8 ** data)
+{
+  /* Caller needs to gst_adapter_unmap. */
+  *data = gst_adapter_map (common->adapter, peek);
+  if (*data == NULL)
+    return GST_FLOW_EOS;
+
+  return GST_FLOW_OK;
+}
+
+/*
+ * Calls pull_range for (offset,size) without advancing our offset
+ */
+GstFlowReturn
+gst_matroska_read_common_peek_bytes (GstMatroskaReadCommon * common, guint64
+    offset, guint size, GstBuffer ** p_buf, guint8 ** bytes)
+{
+  GstFlowReturn ret;
+
+  /* Caching here actually makes much less difference than one would expect.
+   * We do it mainly to avoid pulling buffers of 1 byte all the time */
+  if (common->cached_buffer) {
+    guint64 cache_offset = GST_BUFFER_OFFSET (common->cached_buffer);
+    gsize cache_size = gst_buffer_get_size (common->cached_buffer);
+
+    if (cache_offset <= common->offset &&
+        (common->offset + size) <= (cache_offset + cache_size)) {
+      if (p_buf)
+        *p_buf = gst_buffer_copy_region (common->cached_buffer,
+            GST_BUFFER_COPY_ALL, common->offset - cache_offset, size);
+      if (bytes) {
+        if (!common->cached_data) {
+          gst_buffer_map (common->cached_buffer, &common->cached_map,
+              GST_MAP_READ);
+          common->cached_data = common->cached_map.data;
+        }
+        *bytes = common->cached_data + common->offset - cache_offset;
+      }
+      return GST_FLOW_OK;
+    }
+    /* not enough data in the cache, free cache and get a new one */
+    if (common->cached_data) {
+      gst_buffer_unmap (common->cached_buffer, &common->cached_map);
+      common->cached_data = NULL;
+    }
+    gst_buffer_unref (common->cached_buffer);
+    common->cached_buffer = NULL;
+  }
+
+  /* refill the cache */
+  ret = gst_pad_pull_range (common->sinkpad, common->offset,
+      MAX (size, 64 * 1024), &common->cached_buffer);
+  if (ret != GST_FLOW_OK) {
+    common->cached_buffer = NULL;
+    return ret;
+  }
+
+  if (gst_buffer_get_size (common->cached_buffer) >= size) {
+    if (p_buf)
+      *p_buf = gst_buffer_copy_region (common->cached_buffer,
+          GST_BUFFER_COPY_ALL, 0, size);
+    if (bytes) {
+      gst_buffer_map (common->cached_buffer, &common->cached_map, GST_MAP_READ);
+      common->cached_data = common->cached_map.data;
+      *bytes = common->cached_data;
+    }
+    return GST_FLOW_OK;
+  }
+
+  /* Not possible to get enough data, try a last time with
+   * requesting exactly the size we need */
+  gst_buffer_unref (common->cached_buffer);
+  common->cached_buffer = NULL;
+
+  ret =
+      gst_pad_pull_range (common->sinkpad, common->offset, size,
+      &common->cached_buffer);
+  if (ret != GST_FLOW_OK) {
+    GST_DEBUG_OBJECT (common->sinkpad, "pull_range returned %d", ret);
+    if (p_buf)
+      *p_buf = NULL;
+    if (bytes)
+      *bytes = NULL;
+    return ret;
+  }
+
+  if (gst_buffer_get_size (common->cached_buffer) < size) {
+    GST_WARNING_OBJECT (common->sinkpad, "Dropping short buffer at offset %"
+        G_GUINT64_FORMAT ": wanted %u bytes, got %" G_GSIZE_FORMAT " bytes",
+        common->offset, size, gst_buffer_get_size (common->cached_buffer));
+
+    gst_buffer_unref (common->cached_buffer);
+    common->cached_buffer = NULL;
+    if (p_buf)
+      *p_buf = NULL;
+    if (bytes)
+      *bytes = NULL;
+    return GST_FLOW_EOS;
+  }
+
+  if (p_buf)
+    *p_buf = gst_buffer_copy_region (common->cached_buffer,
+        GST_BUFFER_COPY_ALL, 0, size);
+  if (bytes) {
+    gst_buffer_map (common->cached_buffer, &common->cached_map, GST_MAP_READ);
+    common->cached_data = common->cached_map.data;
+    *bytes = common->cached_data;
+  }
+
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_matroska_read_common_peek_pull (GstMatroskaReadCommon * common, guint peek,
+    guint8 ** data)
+{
+  return gst_matroska_read_common_peek_bytes (common, common->offset, peek,
+      NULL, data);
+}
+
+GstFlowReturn
+gst_matroska_read_common_peek_id_length_pull (GstMatroskaReadCommon * common,
+    GstElement * el, guint32 * _id, guint64 * _length, guint * _needed)
+{
+  return gst_ebml_peek_id_length (_id, _length, _needed,
+      (GstPeekData) gst_matroska_read_common_peek_pull, (gpointer) common, el,
+      common->offset);
+}
+
+GstFlowReturn
+gst_matroska_read_common_peek_id_length_push (GstMatroskaReadCommon * common,
+    GstElement * el, guint32 * _id, guint64 * _length, guint * _needed)
+{
+  GstFlowReturn ret;
+
+  ret = gst_ebml_peek_id_length (_id, _length, _needed,
+      (GstPeekData) gst_matroska_read_common_peek_adapter, (gpointer) common,
+      el, common->offset);
+
+  gst_adapter_unmap (common->adapter);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_matroska_read_common_read_track_encoding (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml, GstMatroskaTrackContext * context)
+{
+  GstMatroskaTrackEncoding enc = { 0, };
+  GstFlowReturn ret;
+  guint32 id;
+
+  DEBUG_ELEMENT_START (common, ebml, "ContentEncoding");
+  /* Set default values */
+  enc.scope = 1;
+  /* All other default values are 0 */
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "ContentEncoding", 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) {
+      case GST_MATROSKA_ID_CONTENTENCODINGORDER:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (!gst_matroska_read_common_encoding_order_unique (context->encodings,
+                num)) {
+          GST_ERROR_OBJECT (common->sinkpad,
+              "ContentEncodingOrder %" G_GUINT64_FORMAT
+              "is not unique for track %" G_GUINT64_FORMAT, num, context->num);
+          ret = GST_FLOW_ERROR;
+          break;
+        }
+
+        GST_DEBUG_OBJECT (common->sinkpad,
+            "ContentEncodingOrder: %" G_GUINT64_FORMAT, num);
+        enc.order = num;
+        break;
+      }
+      case GST_MATROSKA_ID_CONTENTENCODINGSCOPE:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num > 7 || num == 0) {
+          GST_ERROR_OBJECT (common->sinkpad, "Invalid ContentEncodingScope %"
+              G_GUINT64_FORMAT, num);
+          ret = GST_FLOW_ERROR;
+          break;
+        }
+
+        GST_DEBUG_OBJECT (common->sinkpad,
+            "ContentEncodingScope: %" G_GUINT64_FORMAT, num);
+        enc.scope = num;
+
+        break;
+      }
+      case GST_MATROSKA_ID_CONTENTENCODINGTYPE:{
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num > 1) {
+          GST_ERROR_OBJECT (common->sinkpad, "Invalid ContentEncodingType %"
+              G_GUINT64_FORMAT, num);
+          ret = GST_FLOW_ERROR;
+          break;
+        } else if (num != 0) {
+          GST_ERROR_OBJECT (common->sinkpad,
+              "Encrypted tracks are not supported yet");
+          ret = GST_FLOW_ERROR;
+          break;
+        }
+        GST_DEBUG_OBJECT (common->sinkpad,
+            "ContentEncodingType: %" G_GUINT64_FORMAT, num);
+        enc.type = num;
+        break;
+      }
+      case GST_MATROSKA_ID_CONTENTCOMPRESSION:{
+
+        DEBUG_ELEMENT_START (common, ebml, "ContentCompression");
+
+        if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
+          break;
+
+        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) {
+            case GST_MATROSKA_ID_CONTENTCOMPALGO:{
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) {
+                break;
+              }
+              if (num > 3) {
+                GST_ERROR_OBJECT (common->sinkpad, "Invalid ContentCompAlgo %"
+                    G_GUINT64_FORMAT, num);
+                ret = GST_FLOW_ERROR;
+                break;
+              }
+              GST_DEBUG_OBJECT (common->sinkpad,
+                  "ContentCompAlgo: %" G_GUINT64_FORMAT, num);
+              enc.comp_algo = num;
+
+              break;
+            }
+            case GST_MATROSKA_ID_CONTENTCOMPSETTINGS:{
+              guint8 *data;
+              guint64 size;
+
+              if ((ret =
+                      gst_ebml_read_binary (ebml, &id, &data,
+                          &size)) != GST_FLOW_OK) {
+                break;
+              }
+              enc.comp_settings = data;
+              enc.comp_settings_length = size;
+              GST_DEBUG_OBJECT (common->sinkpad,
+                  "ContentCompSettings of size %" G_GUINT64_FORMAT, size);
+              break;
+            }
+            default:
+              GST_WARNING_OBJECT (common->sinkpad,
+                  "Unknown ContentCompression subelement 0x%x - ignoring", id);
+              ret = gst_ebml_read_skip (ebml);
+              break;
+          }
+        }
+        DEBUG_ELEMENT_STOP (common, ebml, "ContentCompression", ret);
+        break;
+      }
+
+      case GST_MATROSKA_ID_CONTENTENCRYPTION:
+        GST_ERROR_OBJECT (common->sinkpad,
+            "Encrypted tracks not yet supported");
+        gst_ebml_read_skip (ebml);
+        ret = GST_FLOW_ERROR;
+        break;
+      default:
+        GST_WARNING_OBJECT (common->sinkpad,
+            "Unknown ContentEncoding subelement 0x%x - ignoring", id);
+        ret = gst_ebml_read_skip (ebml);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (common, ebml, "ContentEncoding", ret);
+  if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS)
+    return ret;
+
+  /* TODO: Check if the combination of values is valid */
+
+  g_array_append_val (context->encodings, enc);
+
+  return ret;
+}
+
+GstFlowReturn
+gst_matroska_read_common_read_track_encodings (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml, GstMatroskaTrackContext * context)
+{
+  GstFlowReturn ret;
+  guint32 id;
+
+  DEBUG_ELEMENT_START (common, ebml, "ContentEncodings");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "ContentEncodings", ret);
+    return ret;
+  }
+
+  context->encodings =
+      g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaTrackEncoding), 1);
+
+  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) {
+      case GST_MATROSKA_ID_CONTENTENCODING:
+        ret = gst_matroska_read_common_read_track_encoding (common, ebml,
+            context);
+        break;
+      default:
+        GST_WARNING_OBJECT (common->sinkpad,
+            "Unknown ContentEncodings subelement 0x%x - ignoring", id);
+        ret = gst_ebml_read_skip (ebml);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (common, ebml, "ContentEncodings", ret);
+  if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS)
+    return ret;
+
+  /* Sort encodings according to their order */
+  g_array_sort (context->encodings,
+      (GCompareFunc) gst_matroska_read_common_encoding_cmp);
+
+  return gst_matroska_decode_content_encodings (context->encodings);
+}
+
+void
+gst_matroska_read_common_free_parsed_el (gpointer mem, gpointer user_data)
+{
+  g_slice_free (guint64, mem);
+}
+
+void
+gst_matroska_read_common_init (GstMatroskaReadCommon * ctx)
+{
+  ctx->src = NULL;
+  ctx->writing_app = NULL;
+  ctx->muxing_app = NULL;
+  ctx->index = NULL;
+  ctx->global_tags = NULL;
+  ctx->adapter = gst_adapter_new ();
+  ctx->toc = NULL;
+  ctx->internal_toc = NULL;
+  ctx->toc_updated = FALSE;
+  ctx->cached_track_taglists =
+      g_hash_table_new_full (NULL, NULL, NULL,
+      (GDestroyNotify) gst_tag_list_unref);
+}
+
+void
+gst_matroska_read_common_finalize (GstMatroskaReadCommon * ctx)
+{
+  if (ctx->src) {
+    g_ptr_array_free (ctx->src, TRUE);
+    ctx->src = NULL;
+  }
+
+  if (ctx->global_tags) {
+    gst_tag_list_unref (ctx->global_tags);
+    ctx->global_tags = NULL;
+  }
+
+  if (ctx->toc) {
+    gst_toc_unref (ctx->toc);
+    ctx->toc = NULL;
+  }
+  if (ctx->internal_toc) {
+    gst_toc_unref (ctx->internal_toc);
+    ctx->internal_toc = NULL;
+  }
+
+  ctx->toc_updated = FALSE;
+
+  g_object_unref (ctx->adapter);
+  g_hash_table_remove_all (ctx->cached_track_taglists);
+  g_hash_table_unref (ctx->cached_track_taglists);
+
+}
+
+void
+gst_matroska_read_common_reset (GstElement * element,
+    GstMatroskaReadCommon * ctx)
+{
+  guint i;
+
+  GST_LOG_OBJECT (ctx->sinkpad, "resetting read context");
+
+  /* reset input */
+  ctx->state = GST_MATROSKA_READ_STATE_START;
+
+  /* clean up existing streams if any */
+  if (ctx->src) {
+    g_assert (ctx->src->len == ctx->num_streams);
+    for (i = 0; i < ctx->src->len; i++) {
+      GstMatroskaTrackContext *context = g_ptr_array_index (ctx->src, i);
+
+      if (context->pad != NULL)
+        gst_element_remove_pad (element, context->pad);
+
+      gst_caps_replace (&context->caps, NULL);
+      gst_matroska_track_free (context);
+    }
+    g_ptr_array_free (ctx->src, TRUE);
+  }
+  ctx->src = g_ptr_array_new ();
+  ctx->num_streams = 0;
+
+  /* reset media info */
+  g_free (ctx->writing_app);
+  ctx->writing_app = NULL;
+  g_free (ctx->muxing_app);
+  ctx->muxing_app = NULL;
+
+  /* reset stream type */
+  ctx->is_webm = FALSE;
+  ctx->has_video = FALSE;
+
+  /* reset indexes */
+  if (ctx->index) {
+    g_array_free (ctx->index, TRUE);
+    ctx->index = NULL;
+  }
+
+  /* reset timers */
+  ctx->time_scale = 1000000;
+  ctx->created = G_MININT64;
+
+  /* cues/tracks/segmentinfo */
+  ctx->index_parsed = FALSE;
+  ctx->segmentinfo_parsed = FALSE;
+  ctx->attachments_parsed = FALSE;
+  ctx->chapters_parsed = FALSE;
+
+  /* tags */
+  ctx->global_tags_changed = FALSE;
+  g_list_foreach (ctx->tags_parsed,
+      (GFunc) gst_matroska_read_common_free_parsed_el, NULL);
+  g_list_free (ctx->tags_parsed);
+  ctx->tags_parsed = NULL;
+  if (ctx->global_tags) {
+    gst_tag_list_unref (ctx->global_tags);
+  }
+  ctx->global_tags = gst_tag_list_new_empty ();
+  gst_tag_list_set_scope (ctx->global_tags, GST_TAG_SCOPE_GLOBAL);
+
+  gst_segment_init (&ctx->segment, GST_FORMAT_TIME);
+  ctx->offset = 0;
+  ctx->start_resync_offset = -1;
+  ctx->state_to_restore = -1;
+
+  if (ctx->cached_buffer) {
+    if (ctx->cached_data) {
+      gst_buffer_unmap (ctx->cached_buffer, &ctx->cached_map);
+      ctx->cached_data = NULL;
+    }
+    gst_buffer_unref (ctx->cached_buffer);
+    ctx->cached_buffer = NULL;
+  }
+
+  /* free chapters TOC if any */
+  if (ctx->toc) {
+    gst_toc_unref (ctx->toc);
+    ctx->toc = NULL;
+  }
+  if (ctx->internal_toc) {
+    gst_toc_unref (ctx->internal_toc);
+    ctx->internal_toc = NULL;
+  }
+  ctx->toc_updated = FALSE;
+}
+
+/* call with object lock held */
+void
+gst_matroska_read_common_reset_streams (GstMatroskaReadCommon * common,
+    GstClockTime time, gboolean full)
+{
+  gint i;
+
+  GST_DEBUG_OBJECT (common->sinkpad, "resetting stream state");
+
+  g_assert (common->src->len == common->num_streams);
+  for (i = 0; i < common->src->len; i++) {
+    GstMatroskaTrackContext *context = g_ptr_array_index (common->src, i);
+    context->pos = time;
+    context->set_discont = TRUE;
+    context->eos = FALSE;
+    context->from_time = GST_CLOCK_TIME_NONE;
+    if (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
+      GstMatroskaTrackVideoContext *videocontext =
+          (GstMatroskaTrackVideoContext *) context;
+      /* demux object lock held by caller */
+      videocontext->earliest_time = GST_CLOCK_TIME_NONE;
+    }
+  }
+}
+
+gboolean
+gst_matroska_read_common_tracknumber_unique (GstMatroskaReadCommon * common,
+    guint64 num)
+{
+  gint i;
+
+  g_assert (common->src->len == common->num_streams);
+  for (i = 0; i < common->src->len; i++) {
+    GstMatroskaTrackContext *context = g_ptr_array_index (common->src, i);
+
+    if (context->num == num)
+      return FALSE;
+  }
+
+  return TRUE;
+}
diff --git a/gst/matroska/matroska-read-common.h b/gst/matroska/matroska-read-common.h
new file mode 100644
index 0000000..a6282d6
--- /dev/null
+++ b/gst/matroska/matroska-read-common.h
@@ -0,0 +1,172 @@
+/* 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MATROSKA_READ_COMMON_H__
+#define __GST_MATROSKA_READ_COMMON_H__
+
+#include <glib.h>
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+#include "matroska-ids.h"
+
+G_BEGIN_DECLS
+
+GST_DEBUG_CATEGORY_EXTERN(matroskareadcommon_debug);
+
+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 {
+#if 0
+  GstIndex                *element_index;
+  gint                     element_index_writer_id;
+#endif
+
+  /* pads */
+  GstPad                  *sinkpad;
+  GPtrArray               *src;
+  guint                    num_streams;
+
+  /* metadata */
+  gchar                   *muxing_app;
+  gchar                   *writing_app;
+  gint64                   created;
+
+  /* state */
+  GstMatroskaReadState     state;
+
+  /* stream type */
+  gboolean                 is_webm;
+  gboolean                 has_video;
+
+  /* did we parse cues/tracks/segmentinfo already? */
+  gboolean                 index_parsed;
+  gboolean                 segmentinfo_parsed;
+  gboolean                 attachments_parsed;
+  gboolean                 chapters_parsed;
+  GList                   *tags_parsed;
+
+  /* chapters stuff */
+  /* Internal toc is used to keep track of the internal UID
+   * which are different from the external StringUID used
+   * in the user toc */
+  GstToc                  *toc;
+  GstToc                  *internal_toc;
+  gboolean                toc_updated;
+
+  /* start-of-segment and length */
+  guint64                  ebml_segment_start;
+  guint64                  ebml_segment_length;
+
+  /* a cue (index) table */
+  GArray                  *index;
+
+  /* timescale in the file */
+  guint64                  time_scale;
+
+  /* keeping track of playback position */
+  GstSegment               segment;
+
+  GstTagList              *global_tags;
+  gboolean                 global_tags_changed;
+
+  /* pull mode caching */
+  GstBuffer *cached_buffer;
+  guint8 *cached_data;
+  GstMapInfo cached_map;
+
+  /* push and pull mode */
+  guint64                  offset;
+
+  guint64                  start_resync_offset;
+
+  /* state to restore after scanning for invalid data */
+  gint                     state_to_restore;
+
+  /* push based mode usual suspects */
+  GstAdapter              *adapter;
+
+  /* cache for track tags that forward-reference their tracks */
+  GHashTable *cached_track_taglists ;
+ 
+} GstMatroskaReadCommon;
+
+GstFlowReturn gst_matroska_decode_content_encodings (GArray * encodings);
+gboolean gst_matroska_decode_data (GArray * encodings, gpointer * data_out,
+    gsize * size_out, GstMatroskaTrackEncodingScope scope, gboolean free);
+gint gst_matroska_index_seek_find (GstMatroskaIndex * i1, GstClockTime * time,
+    gpointer user_data);
+GstMatroskaIndex * gst_matroska_read_common_do_index_seek (
+    GstMatroskaReadCommon * common, GstMatroskaTrackContext * track, gint64
+    seek_pos, GArray ** _index, gint * _entry_index, GstSearchMode snap_dir);
+void gst_matroska_read_common_found_global_tag (GstMatroskaReadCommon * common,
+    GstElement * el, GstTagList * taglist);
+gint64 gst_matroska_read_common_get_length (GstMatroskaReadCommon * common);
+GstMatroskaTrackContext * gst_matroska_read_common_get_seek_track (
+    GstMatroskaReadCommon * common, GstMatroskaTrackContext * track);
+GstFlowReturn gst_matroska_read_common_parse_index (GstMatroskaReadCommon *
+    common, GstEbmlRead * ebml);
+GstFlowReturn gst_matroska_read_common_parse_info (GstMatroskaReadCommon *
+    common, GstElement * el, GstEbmlRead * ebml);
+GstFlowReturn gst_matroska_read_common_parse_attachments (
+    GstMatroskaReadCommon * common, GstElement * el, GstEbmlRead * ebml);
+GstFlowReturn gst_matroska_read_common_parse_chapters (GstMatroskaReadCommon *
+    common, GstEbmlRead * ebml);
+GstFlowReturn gst_matroska_read_common_parse_header (GstMatroskaReadCommon *
+    common, GstEbmlRead * ebml);
+GstFlowReturn gst_matroska_read_common_parse_metadata (GstMatroskaReadCommon *
+    common, GstElement * el, GstEbmlRead * ebml);
+GstFlowReturn gst_matroska_read_common_parse_skip (GstMatroskaReadCommon *
+    common, GstEbmlRead * ebml, const gchar * parent_name, guint id);
+GstFlowReturn gst_matroska_read_common_peek_bytes (GstMatroskaReadCommon *
+    common, guint64 offset, guint size, GstBuffer ** p_buf, guint8 ** bytes);
+GstFlowReturn gst_matroska_read_common_peek_id_length_pull (GstMatroskaReadCommon *
+    common, GstElement * el, guint32 * _id, guint64 * _length, guint *
+    _needed);
+GstFlowReturn gst_matroska_read_common_peek_id_length_push (GstMatroskaReadCommon *
+    common, GstElement * el, guint32 * _id, guint64 * _length, guint *
+    _needed);
+gint gst_matroska_read_common_stream_from_num (GstMatroskaReadCommon * common,
+    guint track_num);
+GstFlowReturn gst_matroska_read_common_read_track_encodings (
+    GstMatroskaReadCommon * common, GstEbmlRead * ebml,
+    GstMatroskaTrackContext * context);
+void gst_matroska_read_common_reset_streams (GstMatroskaReadCommon * common,
+    GstClockTime time, gboolean full);
+void gst_matroska_read_common_free_parsed_el (gpointer mem, gpointer user_data);
+void gst_matroska_read_common_init (GstMatroskaReadCommon * ctx);
+void gst_matroska_read_common_finalize (GstMatroskaReadCommon * ctx);
+void gst_matroska_read_common_reset (GstElement * element,
+    GstMatroskaReadCommon * ctx);
+gboolean gst_matroska_read_common_tracknumber_unique (GstMatroskaReadCommon *
+    common, guint64 num);
+
+G_END_DECLS
+
+#endif /* __GST_MATROSKA_READ_COMMON_H__ */
diff --git a/gst/matroska/matroska.c b/gst/matroska/matroska.c
new file mode 100644
index 0000000..6e43972
--- /dev/null
+++ b/gst/matroska/matroska.c
@@ -0,0 +1,61 @@
+/* GStreamer Matroska muxer/demuxer
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * matroska.c: plugin loader
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "matroska-demux.h"
+#include "matroska-parse.h"
+#include "matroska-read-common.h"
+#include "matroska-mux.h"
+#include "matroska-ids.h"
+#include "webm-mux.h"
+
+#include <gst/pbutils/pbutils.h>
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  gboolean ret;
+
+  gst_pb_utils_init ();
+
+  gst_matroska_register_tags ();
+
+  GST_DEBUG_CATEGORY_INIT (matroskareadcommon_debug, "matroskareadcommon", 0,
+      "Matroska demuxer/parser shared debug");
+
+  ret = gst_matroska_demux_plugin_init (plugin);
+  ret &= gst_matroska_parse_plugin_init (plugin);
+  ret &= gst_element_register (plugin, "matroskamux", GST_RANK_PRIMARY,
+      GST_TYPE_MATROSKA_MUX);
+  ret &= gst_element_register (plugin, "webmmux", GST_RANK_PRIMARY,
+      GST_TYPE_WEBM_MUX);
+
+  return ret;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    matroska,
+    "Matroska and WebM stream handling",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/matroska/meson.build b/gst/matroska/meson.build
new file mode 100644
index 0000000..a5386cf
--- /dev/null
+++ b/gst/matroska/meson.build
@@ -0,0 +1,24 @@
+matroska_sources = [
+  'ebml-read.c',
+  'ebml-write.c',
+  'matroska.c',
+  'matroska-demux.c',
+  'matroska-parse.c',
+  'matroska-ids.c',
+  'matroska-mux.c',
+  'matroska-read-common.c',
+  'webm-mux.c',
+  'lzo.c',
+]
+
+gstmatroska = library('gstmatroska',
+  matroska_sources,
+  c_args : gst_plugins_good_args,
+  link_args : noseh_link_args,
+  include_directories : [configinc],
+  dependencies : [gstpbutils_dep, gstaudio_dep, gstriff_dep,
+                  gstvideo_dep, gsttag_dep, gstbase_dep,
+                  gst_dep, zlib_dep, bz2lib, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/matroska/webm-mux.c b/gst/matroska/webm-mux.c
new file mode 100644
index 0000000..85c8639
--- /dev/null
+++ b/gst/matroska/webm-mux.c
@@ -0,0 +1,101 @@
+/* GStreamer WebM muxer
+ * Copyright (c) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-webmmux
+ *
+ * webmmux muxes VP8 video and Vorbis audio streams into a WebM file.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 webmmux name=mux ! filesink location=newfile.webm         \
+ *   uridecodebin uri=file:///path/to/somefile.ogv name=demux                \
+ *   demux. ! videoconvert ! vp8enc ! queue ! mux.video_0    \
+ *   demux. ! progressreport ! audioconvert ! audiorate ! vorbisenc ! queue ! mux.audio_0
+ * ]| This pipeline re-encodes a video file of any format into a WebM file.
+ * |[
+ * gst-launch-1.0 webmmux name=mux ! filesink location=test.webm            \
+ *   videotestsrc num-buffers=250 ! video/x-raw,framerate=25/1 ! videoconvert ! vp8enc ! queue ! mux.video_0 \
+ *   audiotestsrc samplesperbuffer=44100 num-buffers=10 ! audio/x-raw,rate=44100 ! vorbisenc ! queue ! mux.audio_0
+ * ]| This pipeline muxes a test video and a sine wave into a WebM file.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "webm-mux.h"
+
+#define COMMON_VIDEO_CAPS \
+  "width = (int) [ 16, 4096 ], " \
+  "height = (int) [ 16, 4096 ], " \
+  "framerate = (fraction) [ 0, MAX ]"
+
+#define COMMON_AUDIO_CAPS \
+  "channels = (int) [ 1, MAX ], " \
+  "rate = (int) [ 1, MAX ]"
+
+G_DEFINE_TYPE (GstWebMMux, gst_webm_mux, GST_TYPE_MATROSKA_MUX);
+
+static GstStaticPadTemplate webm_src_templ = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/webm; audio/webm")
+    );
+
+static GstStaticPadTemplate webm_videosink_templ =
+    GST_STATIC_PAD_TEMPLATE ("video_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("video/x-vp8, " COMMON_VIDEO_CAPS ";"
+        "video/x-vp9, " COMMON_VIDEO_CAPS ";" "video/x-av1, " COMMON_VIDEO_CAPS)
+    );
+
+static GstStaticPadTemplate webm_audiosink_templ =
+    GST_STATIC_PAD_TEMPLATE ("audio_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("audio/x-vorbis, " COMMON_AUDIO_CAPS ";"
+        "audio/x-opus, " COMMON_AUDIO_CAPS)
+    );
+
+static void
+gst_webm_mux_class_init (GstWebMMuxClass * klass)
+{
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &webm_videosink_templ);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &webm_audiosink_templ);
+  gst_element_class_add_static_pad_template (gstelement_class, &webm_src_templ);
+  gst_element_class_set_static_metadata (gstelement_class, "WebM muxer",
+      "Codec/Muxer",
+      "Muxes video and audio streams into a WebM stream",
+      "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
+}
+
+static void
+gst_webm_mux_init (GstWebMMux * mux)
+{
+  GST_MATROSKA_MUX (mux)->doctype = GST_MATROSKA_DOCTYPE_WEBM;
+  GST_MATROSKA_MUX (mux)->is_webm = TRUE;
+}
diff --git a/gst/matroska/webm-mux.h b/gst/matroska/webm-mux.h
new file mode 100644
index 0000000..6fee844
--- /dev/null
+++ b/gst/matroska/webm-mux.h
@@ -0,0 +1,49 @@
+/* GStreamer WebM muxer
+ * Copyright (c) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_WEBM_MUX_H__
+#define __GST_WEBM_MUX_H__
+
+#include "matroska-mux.h"
+
+#define GST_TYPE_WEBM_MUX \
+  (gst_webm_mux_get_type ())
+#define GST_WEBM_MUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WEBM_MUX, GstWebMMux))
+#define GST_WEBM_MUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WEBM_MUX, GstWebMMuxClass))
+#define GST_IS_WEBM_MUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WEBM_MUX))
+#define GST_IS_WEBM_MUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WEBM_MUX))
+
+typedef struct _GstWebMMux GstWebMMux;
+typedef struct _GstWebMMuxClass GstWebMMuxClass;
+
+struct _GstWebMMux {
+  GstMatroskaMux matroskamux;
+};
+
+struct _GstWebMMuxClass {
+  GstMatroskaMuxClass matroskamuxclass;
+};
+
+GType   gst_webm_mux_get_type (void);
+
+#endif /* __GST_WEBM_MUX_H__ */
diff --git a/gst/meson.build b/gst/meson.build
new file mode 100644
index 0000000..61df5f5
--- /dev/null
+++ b/gst/meson.build
@@ -0,0 +1,43 @@
+subdir('alpha')
+subdir('apetag')
+subdir('audiofx')
+subdir('audioparsers')
+subdir('auparse')
+subdir('autodetect')
+subdir('avi')
+subdir('cutter')
+subdir('debugutils')
+subdir('deinterlace')
+subdir('dtmf')
+subdir('effectv')
+subdir('equalizer')
+subdir('flv')
+subdir('flx')
+subdir('goom')
+subdir('goom2k1')
+subdir('icydemux')
+subdir('id3demux')
+subdir('imagefreeze')
+subdir('interleave')
+subdir('isomp4')
+subdir('law')
+subdir('level')
+subdir('matroska')
+subdir('monoscope')
+subdir('multifile')
+subdir('multipart')
+subdir('replaygain')
+subdir('rtp')
+subdir('rtpmanager')
+subdir('rtsp')
+subdir('shapewipe')
+subdir('smpte')
+subdir('spectrum')
+subdir('udp')
+subdir('videobox')
+subdir('videocrop')
+subdir('videofilter')
+subdir('videomixer')
+subdir('wavenc')
+subdir('wavparse')
+subdir('y4m')
diff --git a/gst/monoscope/.gitignore b/gst/monoscope/.gitignore
new file mode 100644
index 0000000..08f5ed3
--- /dev/null
+++ b/gst/monoscope/.gitignore
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
diff --git a/gst/monoscope/Makefile.am b/gst/monoscope/Makefile.am
new file mode 100644
index 0000000..a3da884
--- /dev/null
+++ b/gst/monoscope/Makefile.am
@@ -0,0 +1,9 @@
+plugin_LTLIBRARIES = libgstmonoscope.la
+
+libgstmonoscope_la_SOURCES = gstmonoscope.c monoscope.c convolve.c
+
+noinst_HEADERS = gstmonoscope.h monoscope.h convolve.h
+
+libgstmonoscope_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS)
+libgstmonoscope_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS)
+libgstmonoscope_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
diff --git a/gst/monoscope/README b/gst/monoscope/README
new file mode 100644
index 0000000..1aff0c0
--- /dev/null
+++ b/gst/monoscope/README
@@ -0,0 +1,9 @@
+This is a visualization based on on the monoscope output plugin from
+alsaplayer.
+
+The monoscope convolution matching code was written by Ralph Loader.
+
+The monoscope.c and monoscope.h files are under the BSD license (without advertising clause).
+
+This implementation is taken from alsaplayer version 0.99.54, at
+http://www.alsaplayer.org/
diff --git a/gst/monoscope/convolve.c b/gst/monoscope/convolve.c
new file mode 100644
index 0000000..a63e797
--- /dev/null
+++ b/gst/monoscope/convolve.c
@@ -0,0 +1,363 @@
+/* Karatsuba convolution
+ *
+ *  Copyright (C) 1999 Ralph Loader <suckfish@ihug.co.nz>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *
+ * Note: 7th December 2004: This file used to be licensed under the GPL,
+ *       but we got permission from Ralp Loader to relicense it to LGPL.
+ *
+ *  $Id$
+ *
+ */
+
+/* The algorithm is based on the following.  For the convolution of a pair
+ * of pairs, (a,b) * (c,d) = (0, a.c, a.d+b.c, b.d), we can reduce the four
+ * multiplications to three, by the formulae a.d+b.c = (a+b).(c+d) - a.c -
+ * b.d.  A similar relation enables us to compute a 2n by 2n convolution
+ * using 3 n by n convolutions, and thus a 2^n by 2^n convolution using 3^n
+ * multiplications (as opposed to the 4^n that the quadratic algorithm
+ * takes. */
+
+/* For large n, this is slower than the O(n log n) that the FFT method
+ * takes, but we avoid using complex numbers, and we only have to compute
+ * one convolution, as opposed to 3 FFTs.  We have good locality-of-
+ * reference as well, which will help on CPUs with tiny caches.  */
+
+/* E.g., for a 512 x 512 convolution, the FFT method takes 55 * 512 = 28160
+ * (real) multiplications, as opposed to 3^9 = 19683 for the Karatsuba
+ * algorithm.  We actually want 257 outputs of a 256 x 512 convolution;
+ * that doesn't appear to give an easy advantage for the FFT algorithm, but
+ * for the Karatsuba algorithm, it's easy to use two 256 x 256
+ * convolutions, taking 2 x 3^8 = 12312 multiplications.  [This difference
+ * is that the FFT method "wraps" the arrays, doing a 2^n x 2^n -> 2^n,
+ * while the Karatsuba algorithm pads with zeros, doing 2^n x 2^n -> 2.2^n
+ * - 1]. */
+
+/* There's a big lie above, actually... for a 4x4 convolution, it's quicker
+ * to do it using 16 multiplications than the more complex Karatsuba
+ * algorithm...  So the recursion bottoms out at 4x4s.  This increases the
+ * number of multiplications by a factor of 16/9, but reduces the overheads
+ * dramatically. */
+
+/* The convolution algorithm is implemented as a stack machine.  We have a
+ * stack of commands, each in one of the forms "do a 2^n x 2^n
+ * convolution", or "combine these three length 2^n outputs into one
+ * 2^{n+1} output." */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include "convolve.h"
+
+typedef union stack_entry_s
+{
+  struct
+  {
+    const double *left, *right;
+    double *out;
+  }
+  v;
+  struct
+  {
+    double *main, *null;
+  }
+  b;
+
+}
+stack_entry;
+
+struct _struct_convolve_state
+{
+  int depth, small, big, stack_size;
+  double *left;
+  double *right;
+  double *scratch;
+  stack_entry *stack;
+};
+
+/*
+ * Initialisation routine - sets up tables and space to work in.
+ * Returns a pointer to internal state, to be used when performing calls.
+ * On error, returns NULL.
+ * The pointer should be freed when it is finished with, by convolve_close().
+ */
+convolve_state *
+convolve_init (int depth)
+{
+  convolve_state *state;
+
+  state = malloc (sizeof (convolve_state));
+  state->depth = depth;
+  state->small = (1 << depth);
+  state->big = (2 << depth);
+  state->stack_size = depth * 3;
+  state->left = calloc (state->big, sizeof (double));
+  state->right = calloc (state->small * 3, sizeof (double));
+  state->scratch = calloc (state->small * 3, sizeof (double));
+  state->stack = calloc (state->stack_size + 1, sizeof (stack_entry));
+  return state;
+}
+
+/*
+ * Free the state allocated with convolve_init().
+ */
+void
+convolve_close (convolve_state * state)
+{
+  free (state->left);
+  free (state->right);
+  free (state->scratch);
+  free (state->stack);
+  free (state);
+}
+
+static void
+convolve_4 (double *out, const double *left, const double *right)
+/* This does a 4x4 -> 7 convolution.  For what it's worth, the slightly odd
+ * ordering gives about a 1% speed up on my Pentium II. */
+{
+  double l0, l1, l2, l3, r0, r1, r2, r3;
+  double a;
+
+  l0 = left[0];
+  r0 = right[0];
+  a = l0 * r0;
+  l1 = left[1];
+  r1 = right[1];
+  out[0] = a;
+  a = (l0 * r1) + (l1 * r0);
+  l2 = left[2];
+  r2 = right[2];
+  out[1] = a;
+  a = (l0 * r2) + (l1 * r1) + (l2 * r0);
+  l3 = left[3];
+  r3 = right[3];
+  out[2] = a;
+
+  out[3] = (l0 * r3) + (l1 * r2) + (l2 * r1) + (l3 * r0);
+  out[4] = (l1 * r3) + (l2 * r2) + (l3 * r1);
+  out[5] = (l2 * r3) + (l3 * r2);
+  out[6] = l3 * r3;
+}
+
+static void
+convolve_run (stack_entry * top, unsigned size, double *scratch)
+/* Interpret a stack of commands.  The stack starts with two entries; the
+ * convolution to do, and an illegal entry used to mark the stack top.  The
+ * size is the number of entries in each input, and must be a power of 2,
+ * and at least 8.  It is OK to have out equal to left and/or right.
+ * scratch must have length 3*size.  The number of stack entries needed is
+ * 3n-4 where size=2^n. */
+{
+  do {
+    const double *left;
+    const double *right;
+    double *out;
+
+    /* When we get here, the stack top is always a convolve,
+     * with size > 4.  So we will split it.  We repeatedly split
+     * the top entry until we get to size = 4. */
+
+    left = top->v.left;
+    right = top->v.right;
+    out = top->v.out;
+    top++;
+
+    do {
+      double *s_left, *s_right;
+      int i;
+
+      /* Halve the size. */
+      size >>= 1;
+
+      /* Allocate the scratch areas. */
+      s_left = scratch + size * 3;
+      /* s_right is a length 2*size buffer also used for
+       * intermediate output. */
+      s_right = scratch + size * 4;
+
+      /* Create the intermediate factors. */
+      for (i = 0; i < size; i++) {
+        double l = left[i] + left[i + size];
+        double r = right[i] + right[i + size];
+
+        s_left[i + size] = r;
+        s_left[i] = l;
+      }
+
+      /* Push the combine entry onto the stack. */
+      top -= 3;
+      top[2].b.main = out;
+      top[2].b.null = NULL;
+
+      /* Push the low entry onto the stack.  This must be
+       * the last of the three sub-convolutions, because
+       * it may overwrite the arguments. */
+      top[1].v.left = left;
+      top[1].v.right = right;
+      top[1].v.out = out;
+
+      /* Push the mid entry onto the stack. */
+      top[0].v.left = s_left;
+      top[0].v.right = s_right;
+      top[0].v.out = s_right;
+
+      /* Leave the high entry in variables. */
+      left += size;
+      right += size;
+      out += size * 2;
+
+    } while (size > 4);
+
+    /* When we get here, the stack top is a group of 3
+     * convolves, with size = 4, followed by some combines.  */
+    convolve_4 (out, left, right);
+    convolve_4 (top[0].v.out, top[0].v.left, top[0].v.right);
+    convolve_4 (top[1].v.out, top[1].v.left, top[1].v.right);
+    top += 2;
+
+    /* Now process combines. */
+    do {
+      /* b.main is the output buffer, mid is the middle
+       * part which needs to be adjusted in place, and
+       * then folded back into the output.  We do this in
+       * a slightly strange way, so as to avoid having
+       * two loops. */
+      double *out = top->b.main;
+      double *mid = scratch + size * 4;
+      unsigned int i;
+
+      top++;
+      out[size * 2 - 1] = 0;
+      for (i = 0; i < size - 1; i++) {
+        double lo;
+        double hi;
+
+        lo = mid[0] - (out[0] + out[2 * size]) + out[size];
+        hi = mid[size] - (out[size] + out[3 * size]) + out[2 * size];
+        out[size] = lo;
+        out[2 * size] = hi;
+        out++;
+        mid++;
+      }
+      size <<= 1;
+    } while (top->b.null == NULL);
+  } while (top->b.main != NULL);
+}
+
+/*
+ * convolve_match:
+ * @lastchoice: an array of size SMALL.
+ * @input: an array of size BIG (2*SMALL)
+ * @state: a (non-NULL) pointer returned by convolve_init.
+ *
+ * We find the contiguous SMALL-size sub-array of input that best matches
+ * lastchoice. A measure of how good a sub-array is compared with the lastchoice
+ * is given by the sum of the products of each pair of entries.  We maximise
+ * that, by taking an appropriate convolution, and then finding the maximum
+ * entry in the convolutions.
+ *
+ * Return: the position of the best match
+ */
+int
+convolve_match (const int *lastchoice, const short *input,
+    convolve_state * state)
+{
+  double avg = 0;
+  double best;
+  int p = 0;
+  int i;
+  double *left = state->left;
+  double *right = state->right;
+  double *scratch = state->scratch;
+  stack_entry *top = state->stack + (state->stack_size - 1);
+
+  for (i = 0; i < state->big; i++)
+    left[i] = input[i];
+
+  for (i = 0; i < state->small; i++) {
+    double a = lastchoice[(state->small - 1) - i];
+
+    right[i] = a;
+    avg += a;
+  }
+
+  /* We adjust the smaller of the two input arrays to have average
+   * value 0.  This makes the eventual result insensitive to both
+   * constant offsets and positive multipliers of the inputs. */
+  avg /= state->small;
+  for (i = 0; i < state->small; i++)
+    right[i] -= avg;
+  /* End-of-stack marker. */
+  top[1].b.null = scratch;
+  top[1].b.main = NULL;
+  /* The low (small x small) part, of which we want the high outputs. */
+  top->v.left = left;
+  top->v.right = right;
+  top->v.out = right + state->small;
+  convolve_run (top, state->small, scratch);
+
+  /* The high (small x small) part, of which we want the low outputs. */
+  top->v.left = left + state->small;
+  top->v.right = right;
+  top->v.out = right;
+  convolve_run (top, state->small, scratch);
+
+  /* Now find the best position amoungs this.  Apart from the first
+   * and last, the required convolution outputs are formed by adding
+   * outputs from the two convolutions above. */
+  best = right[state->big - 1];
+  right[state->big + state->small - 1] = 0;
+  p = -1;
+  for (i = 0; i < state->small; i++) {
+    double a = right[i] + right[i + state->big];
+
+    if (a > best) {
+      best = a;
+      p = i;
+    }
+  }
+  p++;
+
+#if 0
+  {
+    /* This is some debugging code... */
+    best = 0;
+    for (i = 0; i < state->small; i++)
+      best += ((double) input[i + p]) * ((double) lastchoice[i] - avg);
+
+    for (i = 0; i <= state->small; i++) {
+      double tot = 0;
+      unsigned int j;
+
+      for (j = 0; j < state->small; j++)
+        tot += ((double) input[i + j]) * ((double) lastchoice[j] - avg);
+      if (tot > best)
+        printf ("(%i)", i);
+      if (tot != left[i + (state->small - 1)])
+        printf ("!");
+    }
+
+    printf ("%i\n", p);
+  }
+#endif
+
+  return p;
+}
diff --git a/gst/monoscope/convolve.h b/gst/monoscope/convolve.h
new file mode 100644
index 0000000..d6a7f05
--- /dev/null
+++ b/gst/monoscope/convolve.h
@@ -0,0 +1,48 @@
+/* convolve.h: Header for convolutions.
+ *
+ *  Copyright (C) 1999 Ralph Loader <suckfish@ihug.co.nz>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *
+ * Note: 7th December 2004: This file used to be licensed under the GPL,
+ *       but we got permission from Ralp Loader to relicense it to LGPL.
+ *
+ *
+ */
+
+#ifndef CONVOLVE_H
+#define CONVOLVE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Convolution state */
+typedef struct _struct_convolve_state convolve_state;
+
+convolve_state *convolve_init (int depth);
+void convolve_close (convolve_state * state);
+
+int convolve_match (const int * lastchoice,
+                    const short int * input,
+                    convolve_state * state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/gst/monoscope/gstmonoscope.c b/gst/monoscope/gstmonoscope.c
new file mode 100644
index 0000000..0cbde74
--- /dev/null
+++ b/gst/monoscope/gstmonoscope.c
@@ -0,0 +1,581 @@
+/* gstmonoscope.c: implementation of monoscope drawing element
+ * Copyright (C) <2002> Richard Boulton <richard@tartarus.org>
+ * Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) <2006> Wim Taymans <wim at fluendo dot com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-monoscope
+ * @see_also: goom
+ *
+ * Monoscope is an audio visualisation element. It creates a coloured
+ * curve of the audio signal like on an oscilloscope.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! audioconvert ! monoscope ! videoconvert ! ximagesink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/video/video.h>
+#include <gst/audio/audio.h>
+#include <string.h>
+#include "gstmonoscope.h"
+#include "monoscope.h"
+
+GST_DEBUG_CATEGORY_STATIC (monoscope_debug);
+#define GST_CAT_DEFAULT monoscope_debug
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+#define RGB_ORDER "xRGB"
+#else
+#define RGB_ORDER "BGRx"
+#endif
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-raw, "
+        "format = (string) " RGB_ORDER ", "
+        "width = " G_STRINGIFY (scope_width) ", "
+        "height = " G_STRINGIFY (scope_height) ", "
+        "framerate = " GST_VIDEO_FPS_RANGE)
+    );
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (S16) ", "
+        "rate = (int) [ 8000, 96000 ], "
+        "channels = (int) 1, " "layout = (string) interleaved")
+    );
+
+
+#define gst_monoscope_parent_class parent_class
+G_DEFINE_TYPE (GstMonoscope, gst_monoscope, GST_TYPE_ELEMENT);
+
+static void gst_monoscope_finalize (GObject * object);
+static GstFlowReturn gst_monoscope_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buf);
+static gboolean gst_monoscope_src_setcaps (GstMonoscope * mono, GstCaps * caps);
+static gboolean gst_monoscope_sink_setcaps (GstMonoscope * mono,
+    GstCaps * caps);
+static void gst_monoscope_reset (GstMonoscope * monoscope);
+static gboolean gst_monoscope_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static gboolean gst_monoscope_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static GstStateChangeReturn gst_monoscope_change_state (GstElement * element,
+    GstStateChange transition);
+
+static void
+gst_monoscope_class_init (GstMonoscopeClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->finalize = gst_monoscope_finalize;
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_monoscope_change_state);
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_template);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+  gst_element_class_set_static_metadata (gstelement_class, "Monoscope",
+      "Visualization",
+      "Displays a highly stabilised waveform of audio input",
+      "Richard Boulton <richard@tartarus.org>");
+}
+
+static void
+gst_monoscope_init (GstMonoscope * monoscope)
+{
+  monoscope->sinkpad =
+      gst_pad_new_from_static_template (&sink_template, "sink");
+  gst_pad_set_chain_function (monoscope->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_monoscope_chain));
+  gst_pad_set_event_function (monoscope->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_monoscope_sink_event));
+  gst_element_add_pad (GST_ELEMENT (monoscope), monoscope->sinkpad);
+
+  monoscope->srcpad = gst_pad_new_from_static_template (&src_template, "src");
+  gst_pad_set_event_function (monoscope->srcpad,
+      GST_DEBUG_FUNCPTR (gst_monoscope_src_event));
+  gst_element_add_pad (GST_ELEMENT (monoscope), monoscope->srcpad);
+
+  monoscope->adapter = gst_adapter_new ();
+  monoscope->next_ts = GST_CLOCK_TIME_NONE;
+  monoscope->bps = sizeof (gint16);
+
+  /* reset the initial video state */
+  monoscope->width = scope_width;
+  monoscope->height = scope_height;
+  monoscope->fps_num = 25;      /* desired frame rate */
+  monoscope->fps_denom = 1;
+  monoscope->visstate = NULL;
+
+  /* reset the initial audio state */
+  monoscope->rate = GST_AUDIO_DEF_RATE;
+}
+
+static void
+gst_monoscope_finalize (GObject * object)
+{
+  GstMonoscope *monoscope = GST_MONOSCOPE (object);
+
+  if (monoscope->visstate)
+    monoscope_close (monoscope->visstate);
+
+  g_object_unref (monoscope->adapter);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_monoscope_reset (GstMonoscope * monoscope)
+{
+  monoscope->next_ts = GST_CLOCK_TIME_NONE;
+
+  gst_adapter_clear (monoscope->adapter);
+  gst_segment_init (&monoscope->segment, GST_FORMAT_UNDEFINED);
+
+  GST_OBJECT_LOCK (monoscope);
+  monoscope->proportion = 1.0;
+  monoscope->earliest_time = -1;
+  GST_OBJECT_UNLOCK (monoscope);
+}
+
+static gboolean
+gst_monoscope_sink_setcaps (GstMonoscope * monoscope, GstCaps * caps)
+{
+  GstStructure *structure;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  gst_structure_get_int (structure, "rate", &monoscope->rate);
+
+  GST_DEBUG_OBJECT (monoscope, "sample rate = %d", monoscope->rate);
+  return TRUE;
+}
+
+static gboolean
+gst_monoscope_src_setcaps (GstMonoscope * monoscope, GstCaps * caps)
+{
+  GstStructure *structure;
+  gboolean res;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  gst_structure_get_int (structure, "width", &monoscope->width);
+  gst_structure_get_int (structure, "height", &monoscope->height);
+  gst_structure_get_fraction (structure, "framerate", &monoscope->fps_num,
+      &monoscope->fps_denom);
+
+  monoscope->outsize = monoscope->width * monoscope->height * 4;
+  monoscope->frame_duration = gst_util_uint64_scale_int (GST_SECOND,
+      monoscope->fps_denom, monoscope->fps_num);
+  monoscope->spf =
+      gst_util_uint64_scale_int (monoscope->rate, monoscope->fps_denom,
+      monoscope->fps_num);
+
+  GST_DEBUG_OBJECT (monoscope, "dimension %dx%d, framerate %d/%d, spf %d",
+      monoscope->width, monoscope->height, monoscope->fps_num,
+      monoscope->fps_denom, monoscope->spf);
+
+  if (monoscope->visstate) {
+    monoscope_close (monoscope->visstate);
+    monoscope->visstate = NULL;
+  }
+
+  monoscope->visstate = monoscope_init (monoscope->width, monoscope->height);
+
+  res = gst_pad_set_caps (monoscope->srcpad, caps);
+
+  return res && (monoscope->visstate != NULL);
+}
+
+static gboolean
+gst_monoscope_src_negotiate (GstMonoscope * monoscope)
+{
+  GstCaps *othercaps, *target;
+  GstStructure *structure;
+  GstCaps *templ;
+  GstQuery *query;
+  GstBufferPool *pool;
+  GstStructure *config;
+  guint size, min, max;
+
+  templ = gst_pad_get_pad_template_caps (monoscope->srcpad);
+
+  GST_DEBUG_OBJECT (monoscope, "performing negotiation");
+
+  /* see what the peer can do */
+  othercaps = gst_pad_peer_query_caps (monoscope->srcpad, NULL);
+  if (othercaps) {
+    target = gst_caps_intersect (othercaps, templ);
+    gst_caps_unref (othercaps);
+    gst_caps_unref (templ);
+
+    if (gst_caps_is_empty (target))
+      goto no_format;
+
+    target = gst_caps_truncate (target);
+  } else {
+    target = templ;
+  }
+
+  target = gst_caps_make_writable (target);
+  structure = gst_caps_get_structure (target, 0);
+  gst_structure_fixate_field_nearest_int (structure, "width", 320);
+  gst_structure_fixate_field_nearest_int (structure, "height", 240);
+  gst_structure_fixate_field_nearest_fraction (structure, "framerate", 25, 1);
+
+  gst_monoscope_src_setcaps (monoscope, target);
+
+  /* try to get a bufferpool now */
+  /* find a pool for the negotiated caps now */
+  query = gst_query_new_allocation (target, TRUE);
+
+  if (!gst_pad_peer_query (monoscope->srcpad, query)) {
+  }
+
+  if (gst_query_get_n_allocation_pools (query) > 0) {
+    /* we got configuration from our peer, parse them */
+    gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
+  } else {
+    pool = NULL;
+    size = monoscope->outsize;
+    min = max = 0;
+  }
+
+  if (pool == NULL) {
+    /* we did not get a pool, make one ourselves then */
+    pool = gst_buffer_pool_new ();
+  }
+
+  config = gst_buffer_pool_get_config (pool);
+  gst_buffer_pool_config_set_params (config, target, size, min, max);
+  gst_buffer_pool_set_config (pool, config);
+
+  if (monoscope->pool) {
+    gst_buffer_pool_set_active (monoscope->pool, TRUE);
+    gst_object_unref (monoscope->pool);
+  }
+  monoscope->pool = pool;
+
+  /* and activate */
+  gst_buffer_pool_set_active (pool, TRUE);
+
+  gst_query_unref (query);
+  gst_caps_unref (target);
+
+  return TRUE;
+
+no_format:
+  {
+    gst_caps_unref (target);
+    return FALSE;
+  }
+}
+
+/* make sure we are negotiated */
+static GstFlowReturn
+ensure_negotiated (GstMonoscope * monoscope)
+{
+  gboolean reconfigure;
+
+  reconfigure = gst_pad_check_reconfigure (monoscope->srcpad);
+
+  /* we don't know an output format yet, pick one */
+  if (reconfigure || !gst_pad_has_current_caps (monoscope->srcpad)) {
+    if (!gst_monoscope_src_negotiate (monoscope)) {
+      gst_pad_mark_reconfigure (monoscope->srcpad);
+      if (GST_PAD_IS_FLUSHING (monoscope->srcpad))
+        return GST_FLOW_FLUSHING;
+      else
+        return GST_FLOW_NOT_NEGOTIATED;
+    }
+  }
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_monoscope_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf)
+{
+  GstFlowReturn flow_ret = GST_FLOW_OK;
+  GstMonoscope *monoscope;
+
+  monoscope = GST_MONOSCOPE (parent);
+
+  if (monoscope->rate == 0) {
+    gst_buffer_unref (inbuf);
+    flow_ret = GST_FLOW_NOT_NEGOTIATED;
+    goto out;
+  }
+
+  /* Make sure have an output format */
+  flow_ret = ensure_negotiated (monoscope);
+  if (flow_ret != GST_FLOW_OK) {
+    gst_buffer_unref (inbuf);
+    goto out;
+  }
+
+  /* don't try to combine samples from discont buffer */
+  if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
+    gst_adapter_clear (monoscope->adapter);
+    monoscope->next_ts = GST_CLOCK_TIME_NONE;
+  }
+
+  /* Match timestamps from the incoming audio */
+  if (GST_BUFFER_TIMESTAMP (inbuf) != GST_CLOCK_TIME_NONE)
+    monoscope->next_ts = GST_BUFFER_TIMESTAMP (inbuf);
+
+  GST_LOG_OBJECT (monoscope,
+      "in buffer has %" G_GSIZE_FORMAT " samples, ts=%" GST_TIME_FORMAT,
+      gst_buffer_get_size (inbuf) / monoscope->bps,
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)));
+
+  gst_adapter_push (monoscope->adapter, inbuf);
+  inbuf = NULL;
+
+  /* Collect samples until we have enough for an output frame */
+  while (flow_ret == GST_FLOW_OK) {
+    gint16 *samples;
+    GstBuffer *outbuf = NULL;
+    guint32 *pixels, avail, bytesperframe;
+
+    avail = gst_adapter_available (monoscope->adapter);
+    GST_LOG_OBJECT (monoscope, "bytes avail now %u", avail);
+
+    bytesperframe = monoscope->spf * monoscope->bps;
+    if (avail < bytesperframe)
+      break;
+
+    /* FIXME: something is wrong with QoS, we are skipping way too much
+     * stuff even with very low CPU loads */
+#if 0
+    if (monoscope->next_ts != -1) {
+      gboolean need_skip;
+      gint64 qostime;
+
+      qostime = gst_segment_to_running_time (&monoscope->segment,
+          GST_FORMAT_TIME, monoscope->next_ts);
+
+      GST_OBJECT_LOCK (monoscope);
+      /* check for QoS, don't compute buffers that are known to be late */
+      need_skip =
+          GST_CLOCK_TIME_IS_VALID (monoscope->earliest_time) &&
+          qostime <= monoscope->earliest_time;
+      GST_OBJECT_UNLOCK (monoscope);
+
+      if (need_skip) {
+        GST_WARNING_OBJECT (monoscope,
+            "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (qostime), GST_TIME_ARGS (monoscope->earliest_time));
+        goto skip;
+      }
+    }
+#endif
+
+    samples = (gint16 *) gst_adapter_map (monoscope->adapter, bytesperframe);
+
+    if (monoscope->spf < convolver_big) {
+      gint16 in_data[convolver_big], i;
+      gdouble scale = (gdouble) monoscope->spf / (gdouble) convolver_big;
+
+      for (i = 0; i < convolver_big; ++i) {
+        gdouble off = (gdouble) i * scale;
+        in_data[i] = samples[MIN ((guint) off, monoscope->spf)];
+      }
+      pixels = monoscope_update (monoscope->visstate, in_data);
+    } else {
+      /* not really correct, but looks much prettier */
+      pixels = monoscope_update (monoscope->visstate, samples);
+    }
+
+    GST_LOG_OBJECT (monoscope, "allocating output buffer");
+    flow_ret = gst_buffer_pool_acquire_buffer (monoscope->pool, &outbuf, NULL);
+    if (flow_ret != GST_FLOW_OK) {
+      gst_adapter_unmap (monoscope->adapter);
+      goto out;
+    }
+
+    gst_buffer_fill (outbuf, 0, pixels, monoscope->outsize);
+
+    GST_BUFFER_TIMESTAMP (outbuf) = monoscope->next_ts;
+    GST_BUFFER_DURATION (outbuf) = monoscope->frame_duration;
+
+    flow_ret = gst_pad_push (monoscope->srcpad, outbuf);
+
+#if 0
+  skip:
+#endif
+
+    if (GST_CLOCK_TIME_IS_VALID (monoscope->next_ts))
+      monoscope->next_ts += monoscope->frame_duration;
+
+    gst_adapter_flush (monoscope->adapter, bytesperframe);
+  }
+
+out:
+
+  return flow_ret;
+}
+
+static gboolean
+gst_monoscope_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstMonoscope *monoscope;
+  gboolean res;
+
+  monoscope = GST_MONOSCOPE (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      res = gst_pad_push_event (monoscope->srcpad, event);
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      gst_monoscope_reset (monoscope);
+      res = gst_pad_push_event (monoscope->srcpad, event);
+      break;
+    case GST_EVENT_SEGMENT:
+    {
+      /* the newsegment values are used to clip the input samples
+       * and to convert the incomming timestamps to running time so
+       * we can do QoS */
+      gst_event_copy_segment (event, &monoscope->segment);
+
+      res = gst_pad_push_event (monoscope->srcpad, event);
+      break;
+    }
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      gst_monoscope_sink_setcaps (monoscope, caps);
+      gst_event_unref (event);
+      res = TRUE;
+      break;
+    }
+    default:
+      res = gst_pad_push_event (monoscope->srcpad, event);
+      break;
+  }
+
+  return res;
+}
+
+static gboolean
+gst_monoscope_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstMonoscope *monoscope;
+  gboolean res;
+
+  monoscope = GST_MONOSCOPE (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_QOS:{
+      gdouble proportion;
+      GstClockTimeDiff diff;
+      GstClockTime timestamp;
+
+      gst_event_parse_qos (event, NULL, &proportion, &diff, &timestamp);
+
+      /* save stuff for the _chain() function */
+      GST_OBJECT_LOCK (monoscope);
+      monoscope->proportion = proportion;
+      if (diff >= 0)
+        /* we're late, this is a good estimate for next displayable
+         * frame (see part-qos.txt) */
+        monoscope->earliest_time =
+            timestamp + 2 * diff + monoscope->frame_duration;
+      else
+        monoscope->earliest_time = timestamp + diff;
+      GST_OBJECT_UNLOCK (monoscope);
+
+      res = gst_pad_push_event (monoscope->sinkpad, event);
+      break;
+    }
+    default:
+      res = gst_pad_push_event (monoscope->sinkpad, event);
+      break;
+  }
+
+  return res;
+}
+
+static GstStateChangeReturn
+gst_monoscope_change_state (GstElement * element, GstStateChange transition)
+{
+  GstMonoscope *monoscope = GST_MONOSCOPE (element);
+  GstStateChangeReturn ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_monoscope_reset (monoscope);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      if (monoscope->pool) {
+        gst_buffer_pool_set_active (monoscope->pool, FALSE);
+        gst_object_replace ((GstObject **) & monoscope->pool, NULL);
+      }
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (monoscope_debug, "monoscope", 0,
+      "monoscope element");
+
+  return gst_element_register (plugin, "monoscope",
+      GST_RANK_NONE, GST_TYPE_MONOSCOPE);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    monoscope,
+    "Monoscope visualization",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/monoscope/gstmonoscope.h b/gst/monoscope/gstmonoscope.h
new file mode 100644
index 0000000..b66a6d2
--- /dev/null
+++ b/gst/monoscope/gstmonoscope.h
@@ -0,0 +1,83 @@
+/* GStreamer monoscope visualisation element
+ * Copyright (C) <2002> Richard Boulton <richard@tartarus.org>
+ * Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) <2006> Wim Taymans <wim at fluendo dot com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MONOSCOPE__
+#define __GST_MONOSCOPE__
+
+G_BEGIN_DECLS
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+#define GST_TYPE_MONOSCOPE            (gst_monoscope_get_type())
+#define GST_MONOSCOPE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MONOSCOPE,GstMonoscope))
+#define GST_MONOSCOPE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MONOSCOPE,GstMonoscopeClass))
+#define GST_IS_MONOSCOPE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MONOSCOPE))
+#define GST_IS_MONOSCOPE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MONOSCOPE))
+
+typedef struct _GstMonoscope GstMonoscope;
+typedef struct _GstMonoscopeClass GstMonoscopeClass;
+
+struct _GstMonoscope
+{
+  GstElement element;
+
+  /* pads */
+  GstPad      *sinkpad;
+  GstPad      *srcpad;
+
+  GstAdapter  *adapter;
+
+  guint64      next_ts;             /* expected timestamp of the next frame */
+  guint64      frame_duration;      /* video frame duration    */
+  gint         rate;                /* sample rate             */
+  guint        bps;                 /* bytes per sample        */
+  guint        spf;                 /* samples per video frame */
+  GstBufferPool *pool;
+
+  GstSegment   segment;
+
+  /* QoS stuff *//* with LOCK */
+  gdouble      proportion;
+  GstClockTime earliest_time;
+
+  /* video state */
+  gint         fps_num;
+  gint         fps_denom;
+  gint         width;
+  gint         height;
+  guint        outsize;
+
+  /* visualisation state */
+  struct monoscope_state *visstate;
+};
+
+struct _GstMonoscopeClass
+{
+  GstElementClass parent_class;
+};
+
+GType gst_monoscope_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_MONOSCOPE__ */
+
diff --git a/gst/monoscope/meson.build b/gst/monoscope/meson.build
new file mode 100644
index 0000000..2aad191
--- /dev/null
+++ b/gst/monoscope/meson.build
@@ -0,0 +1,10 @@
+gstmonoscope = library('gstmonoscope',
+  'gstmonoscope.c',
+  'monoscope.c',
+  'convolve.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstbase_dep, gstaudio_dep, gstvideo_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/monoscope/monoscope.c b/gst/monoscope/monoscope.c
new file mode 100644
index 0000000..3500879
--- /dev/null
+++ b/gst/monoscope/monoscope.c
@@ -0,0 +1,168 @@
+/*  monoscope.cpp
+ *  Copyright (C) 2002 Richard Boulton <richard@tartarus.org>
+ *  Copyright (C) 1998-2001 Andy Lo A Foe <andy@alsaplayer.org>
+ *  Original code by Tinic Uro
+ *
+ *  This code is copied from Alsaplayer. The orginal code was by Tinic Uro and under
+ *  the BSD license without a advertisig clause. Andy Lo A Foe then relicensed the
+ *  code when he used it for Alsaplayer to GPL with Tinic's permission. Richard Boulton
+ *  then took this code and made a GPL plugin out of it.
+ *
+ *  7th December 2004 Christian Schaller: Richard Boulton and Andy Lo A Foe gave
+ *  permission to relicense their changes under BSD license so we where able to restore the
+ *  code to Tinic's original BSD license.
+ *
+ * This file is under what is known as the BSD license:
+ *
+ * Redistribution and use in source and binary forms, with or without modification, i
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+ * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "monoscope.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+static void
+colors_init (guint32 * colors)
+{
+  int i;
+  int hq = (scope_height / 4);
+  int hq1 = hq - 1;
+  int hh1 = (scope_height / 2) - 1;
+  double scl = (256.0 / (double) hq);
+
+  for (i = 0; i < hq; i++) {
+    /* green to yellow */
+    colors[i] = ((int) (i * scl) << 16) + (255 << 8);
+    /* yellow to red */
+    colors[i + hq1] = (255 << 16) + ((int) ((hq1 - i) * scl) << 8);
+  }
+  colors[hh1] = (40 << 16) + (75 << 8);
+}
+
+struct monoscope_state *
+monoscope_init (guint32 resx, guint32 resy)
+{
+  struct monoscope_state *stateptr;
+
+  /* I didn't program monoscope to only do 256*128, but it works that way */
+  g_return_val_if_fail (resx == scope_width, 0);
+  g_return_val_if_fail (resy == scope_height, 0);
+  stateptr = calloc (1, sizeof (struct monoscope_state));
+  if (stateptr == 0)
+    return 0;
+  stateptr->cstate = convolve_init (convolver_depth);
+  colors_init (stateptr->colors);
+  return stateptr;
+}
+
+void
+monoscope_close (struct monoscope_state *stateptr)
+{
+  convolve_close (stateptr->cstate);
+  free (stateptr);
+}
+
+guint32 *
+monoscope_update (struct monoscope_state *stateptr, gint16 data[convolver_big])
+{
+  /* Really, we want samples evenly spread over the available data.
+   * Just taking a continuous chunk will do for now, though. */
+  int i;
+  int foo, bar;
+  int avg;
+  int h;
+  int hh = (scope_height / 2);
+  int hh1 = hh - 1;
+  guint32 *loc;
+
+  double factor;
+  int max = 1;
+  short *thisEq = stateptr->copyEq;
+
+  memcpy (thisEq, data, sizeof (short) * convolver_big);
+  thisEq += convolve_match (stateptr->avgEq, thisEq, stateptr->cstate);
+
+  memset (stateptr->display, 0, scope_width * scope_height * sizeof (guint32));
+  for (i = 0; i < convolver_small; i++) {
+    avg = (thisEq[i] + stateptr->avgEq[i]) >> 1;
+    stateptr->avgEq[i] = avg;
+    avg = abs (avg);
+    max = MAX (max, avg);
+  }
+  /* running average, 4 values is enough to make it follow volume changes
+   * if this value is too large it will converge slowly
+   */
+  stateptr->avgMax += (max / 4) - (stateptr->avgMax / 4);
+
+  /* input is +/- avgMax, output is +/- hh */
+  if (stateptr->avgMax) {
+    factor = (gdouble) hh / stateptr->avgMax;
+  } else {
+    factor = 1.0;
+  }
+
+  for (i = 0; i < scope_width; i++) {
+    /* scale 16bit signed audio values to scope_height */
+    foo = stateptr->avgEq[i] * factor;
+    foo = CLAMP (foo, -hh1, hh1);
+    bar = (i + ((foo + hh) * scope_width));
+    if ((bar > 0) && (bar < (scope_width * scope_height))) {
+      loc = stateptr->display + bar;
+      /* draw up / down bars */
+      if (foo < 0) {
+        for (h = 0; h <= (-foo); h++) {
+          *loc = stateptr->colors[h];
+          loc += scope_width;
+        }
+      } else {
+        for (h = 0; h <= foo; h++) {
+          *loc = stateptr->colors[h];
+          loc -= scope_width;
+        }
+      }
+    }
+  }
+
+  /* Draw grid. */
+  {
+    guint32 gray = stateptr->colors[hh1];
+
+    for (i = 16; i < scope_height; i += 16) {
+      for (h = 0; h < scope_width; h += 2) {
+        stateptr->display[(i * scope_width) + h] = gray;
+        if (i == hh)
+          stateptr->display[(i * scope_width) + h + 1] = gray;
+      }
+    }
+    for (i = 16; i < scope_width; i += 16) {
+      for (h = 0; h < scope_height; h += 2) {
+        stateptr->display[i + (h * scope_width)] = gray;
+      }
+    }
+  }
+  return stateptr->display;
+}
diff --git a/gst/monoscope/monoscope.h b/gst/monoscope/monoscope.h
new file mode 100644
index 0000000..1f84dc9
--- /dev/null
+++ b/gst/monoscope/monoscope.h
@@ -0,0 +1,27 @@
+#ifndef _MONOSCOPE_H
+#define _MONOSCOPE_H
+
+#include <glib.h>
+#include "convolve.h"
+
+#define convolver_depth 8
+#define convolver_small (1 << convolver_depth)
+#define convolver_big (2 << convolver_depth)
+#define scope_width 256
+#define scope_height 128
+
+struct monoscope_state {
+  short copyEq[convolver_big];
+  int avgEq[convolver_small];      /* a running average of the last few. */
+  int avgMax;                     /* running average of max sample. */
+  guint32 display[scope_width * scope_height];
+
+  convolve_state *cstate;
+  guint32 colors[scope_height / 2];
+};
+
+struct monoscope_state * monoscope_init (guint32 resx, guint32 resy);
+guint32 * monoscope_update (struct monoscope_state * stateptr, gint16 data [convolver_big]);
+void monoscope_close (struct monoscope_state * stateptr);
+
+#endif
diff --git a/gst/multifile/Makefile.am b/gst/multifile/Makefile.am
new file mode 100644
index 0000000..e6e8a12
--- /dev/null
+++ b/gst/multifile/Makefile.am
@@ -0,0 +1,31 @@
+
+plugin_LTLIBRARIES = libgstmultifile.la
+
+libgstmultifile_la_SOURCES = \
+	gstmultifilesink.c   \
+	gstmultifilesrc.c    \
+	gstmultifile.c       \
+	gstsplitfilesrc.c    \
+	gstsplitmuxsink.c    \
+	gstsplitmuxpartreader.c \
+	gstsplitmuxsrc.c \
+	gstsplitutils.c    \
+	patternspec.c
+libgstmultifile_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS)
+libgstmultifile_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_API_VERSION@ $(GST_BASE_LIBS) $(GST_LIBS) $(GIO_LIBS)
+libgstmultifile_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstmultifilesrc.h gstmultifilesink.h gstsplitfilesrc.h gstsplitmuxsink.h \
+	gstsplitmuxsrc.h gstsplitmuxpartreader.h gstsplitutils.h patternspec.h
+
+noinst_PROGRAMS = test-splitmux-part-reader
+
+test_splitmux_part_reader_SOURCES = \
+	test-splitmuxpartreader.c \
+	gstsplitmuxpartreader.c \
+	gstsplitmuxsrc.c \
+	gstsplitutils.c \
+	patternspec.c
+test_splitmux_part_reader_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS)
+test_splitmux_part_reader_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_API_VERSION@ $(GST_BASE_LIBS) $(GST_LIBS) $(GIO_LIBS)
+test_splitmux_part_reader_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
diff --git a/gst/multifile/gstmultifile.c b/gst/multifile/gstmultifile.c
new file mode 100644
index 0000000..6cbb655
--- /dev/null
+++ b/gst/multifile/gstmultifile.c
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wtay@chello.be>
+ *                    2006 Wim Taymans <wim@fluendo.com>
+ *                    2006 David A. Schleef <ds@schleef.org>
+ *
+ * gstmultifilesink.c:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "gstmultifilesink.h"
+#include "gstmultifilesrc.h"
+#include "gstsplitfilesrc.h"
+#include "gstsplitmuxsink.h"
+#include "gstsplitmuxsrc.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  gst_element_register (plugin, "multifilesrc", GST_RANK_NONE,
+      gst_multi_file_src_get_type ());
+  gst_element_register (plugin, "multifilesink", GST_RANK_NONE,
+      gst_multi_file_sink_get_type ());
+  gst_element_register (plugin, "splitfilesrc", GST_RANK_NONE,
+      gst_split_file_src_get_type ());
+
+  if (!register_splitmuxsink (plugin))
+    return FALSE;
+
+  if (!register_splitmuxsrc (plugin))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    multifile,
+    "Reads/Writes buffers from/to sequentially named files",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/multifile/gstmultifilesink.c b/gst/multifile/gstmultifilesink.c
new file mode 100644
index 0000000..d2a55ef
--- /dev/null
+++ b/gst/multifile/gstmultifilesink.c
@@ -0,0 +1,1129 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wtay@chello.be>
+ *                    2006 Wim Taymans <wim@fluendo.com>
+ *                    2006 David A. Schleef <ds@schleef.org>
+ *                    2011 Collabora Ltd. <tim.muller@collabora.co.uk>
+ *                    2015 Tim-Philipp Müller <tim@centricular.com>
+ *
+ * gstmultifilesink.c:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-multifilesink
+ * @see_also: #GstFileSrc
+ *
+ * Write incoming data to a series of sequentially-named files.
+ *
+ * This element is usually used with data where each buffer is an
+ * independent unit of data in its own right (e.g. raw video buffers or
+ * encoded JPEG or PNG images) or with streamable container formats such
+ * as MPEG-TS or MPEG-PS.
+ *
+ * It is not possible to use this element to create independently playable
+ * mp4 files, use the splitmuxsink element for that instead.
+ *
+ * The filename property should contain a string with a \%d placeholder that will
+ * be substituted with the index for each filename.
+ *
+ * If the #GstMultiFileSink:post-messages property is %TRUE, it sends an application
+ * message named
+ * <classname>&quot;GstMultiFileSink&quot;</classname> after writing each
+ * buffer.
+ *
+ * The message's structure contains these fields:
+ * <itemizedlist>
+ * <listitem>
+ *   <para>
+ *   #gchar *
+ *   <classname>&quot;filename&quot;</classname>:
+ *   the filename where the buffer was written.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #gint
+ *   <classname>&quot;index&quot;</classname>:
+ *   the index of the buffer.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GstClockTime
+ *   <classname>&quot;timestamp&quot;</classname>:
+ *   the timestamp of the buffer.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GstClockTime
+ *   <classname>&quot;stream-time&quot;</classname>:
+ *   the stream time of the buffer.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GstClockTime
+ *   <classname>&quot;running-time&quot;</classname>:
+ *   the running_time of the buffer.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GstClockTime
+ *   <classname>&quot;duration&quot;</classname>:
+ *   the duration of the buffer.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #guint64
+ *   <classname>&quot;offset&quot;</classname>:
+ *   the offset of the buffer that triggered the message.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #guint64
+ *   <classname>&quot;offset-end&quot;</classname>:
+ *   the offset-end of the buffer that triggered the message.
+ *   </para>
+ * </listitem>
+ * </itemizedlist>
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc ! multifilesink
+ * gst-launch-1.0 videotestsrc ! multifilesink post-messages=true location="frame%d"
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+#include <gst/base/gstbasetransform.h>
+#include <gst/video/video.h>
+#include <glib/gstdio.h>
+#include "gstmultifilesink.h"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (gst_multi_file_sink_debug);
+#define GST_CAT_DEFAULT gst_multi_file_sink_debug
+
+#define DEFAULT_LOCATION "%05d"
+#define DEFAULT_INDEX 0
+#define DEFAULT_POST_MESSAGES FALSE
+#define DEFAULT_NEXT_FILE GST_MULTI_FILE_SINK_NEXT_BUFFER
+#define DEFAULT_MAX_FILES 0
+#define DEFAULT_MAX_FILE_SIZE G_GUINT64_CONSTANT(2*1024*1024*1024)
+#define DEFAULT_MAX_FILE_DURATION GST_CLOCK_TIME_NONE
+#define DEFAULT_AGGREGATE_GOPS FALSE
+
+enum
+{
+  PROP_0,
+  PROP_LOCATION,
+  PROP_INDEX,
+  PROP_POST_MESSAGES,
+  PROP_NEXT_FILE,
+  PROP_MAX_FILES,
+  PROP_MAX_FILE_SIZE,
+  PROP_MAX_FILE_DURATION,
+  PROP_AGGREGATE_GOPS
+};
+
+static void gst_multi_file_sink_finalize (GObject * object);
+
+static void gst_multi_file_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_multi_file_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_multi_file_sink_start (GstBaseSink * bsink);
+static gboolean gst_multi_file_sink_stop (GstBaseSink * sink);
+static GstFlowReturn gst_multi_file_sink_render (GstBaseSink * sink,
+    GstBuffer * buffer);
+static GstFlowReturn gst_multi_file_sink_render_list (GstBaseSink * sink,
+    GstBufferList * buffer_list);
+static gboolean gst_multi_file_sink_set_caps (GstBaseSink * sink,
+    GstCaps * caps);
+static gboolean gst_multi_file_sink_open_next_file (GstMultiFileSink *
+    multifilesink);
+static void gst_multi_file_sink_close_file (GstMultiFileSink * multifilesink,
+    GstBuffer * buffer);
+static void gst_multi_file_sink_add_old_file (GstMultiFileSink * multifilesink,
+    gchar * fn);
+static void gst_multi_file_sink_ensure_max_files (GstMultiFileSink *
+    multifilesink);
+static gboolean gst_multi_file_sink_event (GstBaseSink * sink,
+    GstEvent * event);
+
+#define GST_TYPE_MULTI_FILE_SINK_NEXT (gst_multi_file_sink_next_get_type ())
+static GType
+gst_multi_file_sink_next_get_type (void)
+{
+  static GType multi_file_sink_next_type = 0;
+  static const GEnumValue next_types[] = {
+    {GST_MULTI_FILE_SINK_NEXT_BUFFER, "New file for each buffer", "buffer"},
+    {GST_MULTI_FILE_SINK_NEXT_DISCONT, "New file after each discontinuity",
+        "discont"},
+    {GST_MULTI_FILE_SINK_NEXT_KEY_FRAME, "New file at each key frame "
+          "(Useful for MPEG-TS segmenting)", "key-frame"},
+    {GST_MULTI_FILE_SINK_NEXT_KEY_UNIT_EVENT,
+        "New file after a force key unit event", "key-unit-event"},
+    {GST_MULTI_FILE_SINK_NEXT_MAX_SIZE, "New file when the configured maximum "
+          "file size would be exceeded with the next buffer or buffer list",
+        "max-size"},
+    {GST_MULTI_FILE_SINK_NEXT_MAX_DURATION,
+          "New file when the configured maximum "
+          "file duration would be exceeded with the next buffer or buffer list",
+        "max-duration"},
+    {0, NULL, NULL}
+  };
+
+  if (!multi_file_sink_next_type) {
+    multi_file_sink_next_type =
+        g_enum_register_static ("GstMultiFileSinkNext", next_types);
+  }
+
+  return multi_file_sink_next_type;
+}
+
+#define gst_multi_file_sink_parent_class parent_class
+G_DEFINE_TYPE (GstMultiFileSink, gst_multi_file_sink, GST_TYPE_BASE_SINK);
+
+static void
+gst_multi_file_sink_class_init (GstMultiFileSinkClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
+
+  gobject_class->set_property = gst_multi_file_sink_set_property;
+  gobject_class->get_property = gst_multi_file_sink_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_LOCATION,
+      g_param_spec_string ("location", "File Location",
+          "Location of the file to write", NULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_INDEX,
+      g_param_spec_int ("index", "Index",
+          "Index to use with location property to create file names.  The "
+          "index is incremented by one for each buffer written.",
+          0, G_MAXINT, DEFAULT_INDEX,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstMultiFileSink:post-messages:
+   *
+   * Post a message on the GstBus for each file.
+   */
+  g_object_class_install_property (gobject_class, PROP_POST_MESSAGES,
+      g_param_spec_boolean ("post-messages", "Post Messages",
+          "Post a message for each file with information of the buffer",
+          DEFAULT_POST_MESSAGES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstMultiFileSink:next-file:
+   *
+   * When to start a new file.
+   */
+  g_object_class_install_property (gobject_class, PROP_NEXT_FILE,
+      g_param_spec_enum ("next-file", "Next File",
+          "When to start a new file",
+          GST_TYPE_MULTI_FILE_SINK_NEXT, DEFAULT_NEXT_FILE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+
+  /**
+   * GstMultiFileSink:max-files:
+   *
+   * Maximum number of files to keep on disk. Once the maximum is reached, old
+   * files start to be deleted to make room for new ones.
+   */
+  g_object_class_install_property (gobject_class, PROP_MAX_FILES,
+      g_param_spec_uint ("max-files", "Max files",
+          "Maximum number of files to keep on disk. Once the maximum is reached,"
+          "old files start to be deleted to make room for new ones.",
+          0, G_MAXUINT, DEFAULT_MAX_FILES,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstMultiFileSink:max-file-size:
+   *
+   * Maximum file size before starting a new file in max-size mode.
+   */
+  g_object_class_install_property (gobject_class, PROP_MAX_FILE_SIZE,
+      g_param_spec_uint64 ("max-file-size", "Maximum File Size",
+          "Maximum file size before starting a new file in max-size mode",
+          0, G_MAXUINT64, DEFAULT_MAX_FILE_SIZE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstMultiFileSink:max-file-duration:
+   *
+   * Maximum file size before starting a new file in max-size mode.
+   */
+  g_object_class_install_property (gobject_class, PROP_MAX_FILE_DURATION,
+      g_param_spec_uint64 ("max-file-duration", "Maximum File Duration",
+          "Maximum file duration before starting a new file in max-size mode "
+          "(in nanoseconds)", 0, G_MAXUINT64, DEFAULT_MAX_FILE_DURATION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstMultiFileSink:aggregate-gops:
+   *
+   * Whether to aggregate complete GOPs before doing any processing. Set this
+   * to TRUE to make sure each new file starts with a keyframe. This requires
+   * the upstream element to flag buffers containing key units and delta
+   * units correctly. At least the MPEG-PS and MPEG-TS muxers should be doing
+   * this.
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_AGGREGATE_GOPS,
+      g_param_spec_boolean ("aggregate-gops", "Aggregate GOPs",
+          "Whether to aggregate GOPs and process them as a whole without "
+          "splitting", DEFAULT_AGGREGATE_GOPS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gobject_class->finalize = gst_multi_file_sink_finalize;
+
+  gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_multi_file_sink_start);
+  gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_multi_file_sink_stop);
+  gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_multi_file_sink_render);
+  gstbasesink_class->render_list =
+      GST_DEBUG_FUNCPTR (gst_multi_file_sink_render_list);
+  gstbasesink_class->set_caps =
+      GST_DEBUG_FUNCPTR (gst_multi_file_sink_set_caps);
+  gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_multi_file_sink_event);
+
+  GST_DEBUG_CATEGORY_INIT (gst_multi_file_sink_debug, "multifilesink", 0,
+      "multifilesink element");
+
+  gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
+  gst_element_class_set_static_metadata (gstelement_class, "Multi-File Sink",
+      "Sink/File",
+      "Write buffers to a sequentially named set of files",
+      "David Schleef <ds@schleef.org>");
+}
+
+static void
+gst_multi_file_sink_init (GstMultiFileSink * multifilesink)
+{
+  multifilesink->filename = g_strdup (DEFAULT_LOCATION);
+  multifilesink->index = DEFAULT_INDEX;
+  multifilesink->post_messages = DEFAULT_POST_MESSAGES;
+  multifilesink->max_files = DEFAULT_MAX_FILES;
+  multifilesink->max_file_size = DEFAULT_MAX_FILE_SIZE;
+  multifilesink->max_file_duration = DEFAULT_MAX_FILE_DURATION;
+
+  multifilesink->aggregate_gops = DEFAULT_AGGREGATE_GOPS;
+  multifilesink->gop_adapter = NULL;
+
+  gst_base_sink_set_sync (GST_BASE_SINK (multifilesink), FALSE);
+
+  multifilesink->next_segment = GST_CLOCK_TIME_NONE;
+  multifilesink->force_key_unit_count = -1;
+}
+
+static void
+gst_multi_file_sink_finalize (GObject * object)
+{
+  GstMultiFileSink *sink = GST_MULTI_FILE_SINK (object);
+
+  g_free (sink->filename);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_multi_file_sink_set_location (GstMultiFileSink * sink,
+    const gchar * location)
+{
+  g_free (sink->filename);
+  /* FIXME: validate location to have just one %d */
+  sink->filename = g_strdup (location);
+
+  return TRUE;
+}
+
+static void
+gst_multi_file_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstMultiFileSink *sink = GST_MULTI_FILE_SINK (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      gst_multi_file_sink_set_location (sink, g_value_get_string (value));
+      break;
+    case PROP_INDEX:
+      sink->index = g_value_get_int (value);
+      break;
+    case PROP_POST_MESSAGES:
+      sink->post_messages = g_value_get_boolean (value);
+      break;
+    case PROP_NEXT_FILE:
+      sink->next_file = g_value_get_enum (value);
+      break;
+    case PROP_MAX_FILES:
+      sink->max_files = g_value_get_uint (value);
+      break;
+    case PROP_MAX_FILE_SIZE:
+      sink->max_file_size = g_value_get_uint64 (value);
+      break;
+    case PROP_MAX_FILE_DURATION:
+      sink->max_file_duration = g_value_get_uint64 (value);
+      break;
+    case PROP_AGGREGATE_GOPS:
+      sink->aggregate_gops = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_multi_file_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstMultiFileSink *sink = GST_MULTI_FILE_SINK (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      g_value_set_string (value, sink->filename);
+      break;
+    case PROP_INDEX:
+      g_value_set_int (value, sink->index);
+      break;
+    case PROP_POST_MESSAGES:
+      g_value_set_boolean (value, sink->post_messages);
+      break;
+    case PROP_NEXT_FILE:
+      g_value_set_enum (value, sink->next_file);
+      break;
+    case PROP_MAX_FILES:
+      g_value_set_uint (value, sink->max_files);
+      break;
+    case PROP_MAX_FILE_SIZE:
+      g_value_set_uint64 (value, sink->max_file_size);
+      break;
+    case PROP_MAX_FILE_DURATION:
+      g_value_set_uint64 (value, sink->max_file_duration);
+      break;
+    case PROP_AGGREGATE_GOPS:
+      g_value_set_boolean (value, sink->aggregate_gops);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_multi_file_sink_start (GstBaseSink * bsink)
+{
+  GstMultiFileSink *sink = GST_MULTI_FILE_SINK (bsink);
+
+  if (sink->aggregate_gops)
+    sink->gop_adapter = gst_adapter_new ();
+  sink->potential_next_gop = NULL;
+  sink->file_pts = GST_CLOCK_TIME_NONE;
+
+  g_queue_init (&sink->old_files);
+
+  return TRUE;
+}
+
+static gboolean
+gst_multi_file_sink_stop (GstBaseSink * sink)
+{
+  GstMultiFileSink *multifilesink;
+  int i;
+
+  multifilesink = GST_MULTI_FILE_SINK (sink);
+
+  if (multifilesink->file != NULL) {
+    fclose (multifilesink->file);
+    multifilesink->file = NULL;
+  }
+
+  if (multifilesink->streamheaders) {
+    for (i = 0; i < multifilesink->n_streamheaders; i++) {
+      gst_buffer_unref (multifilesink->streamheaders[i]);
+    }
+    g_free (multifilesink->streamheaders);
+    multifilesink->streamheaders = NULL;
+  }
+
+  if (multifilesink->gop_adapter != NULL) {
+    g_object_unref (multifilesink->gop_adapter);
+    multifilesink->gop_adapter = NULL;
+  }
+
+  if (multifilesink->potential_next_gop != NULL) {
+    g_list_free_full (multifilesink->potential_next_gop,
+        (GDestroyNotify) gst_buffer_unref);
+    multifilesink->potential_next_gop = NULL;
+  }
+
+  multifilesink->force_key_unit_count = -1;
+
+  g_queue_foreach (&multifilesink->old_files, (GFunc) g_free, NULL);
+  g_queue_clear (&multifilesink->old_files);
+
+  return TRUE;
+}
+
+
+static void
+gst_multi_file_sink_post_message_full (GstMultiFileSink * multifilesink,
+    GstClockTime timestamp, GstClockTime duration, GstClockTime offset,
+    GstClockTime offset_end, GstClockTime running_time,
+    GstClockTime stream_time, const char *filename)
+{
+  GstStructure *s;
+
+  if (!multifilesink->post_messages)
+    return;
+
+  s = gst_structure_new ("GstMultiFileSink",
+      "filename", G_TYPE_STRING, filename,
+      "index", G_TYPE_INT, multifilesink->index,
+      "timestamp", G_TYPE_UINT64, timestamp,
+      "stream-time", G_TYPE_UINT64, stream_time,
+      "running-time", G_TYPE_UINT64, running_time,
+      "duration", G_TYPE_UINT64, duration,
+      "offset", G_TYPE_UINT64, offset,
+      "offset-end", G_TYPE_UINT64, offset_end, NULL);
+
+  gst_element_post_message (GST_ELEMENT_CAST (multifilesink),
+      gst_message_new_element (GST_OBJECT_CAST (multifilesink), s));
+}
+
+static void
+gst_multi_file_sink_post_message_from_time (GstMultiFileSink * multifilesink,
+    GstClockTime timestamp, GstClockTime duration, const char *filename)
+{
+  GstClockTime running_time, stream_time;
+  guint64 offset, offset_end;
+  GstSegment *segment;
+  GstFormat format;
+
+  if (!multifilesink->post_messages)
+    return;
+
+  segment = &GST_BASE_SINK (multifilesink)->segment;
+  format = segment->format;
+
+  offset = -1;
+  offset_end = -1;
+
+  running_time = gst_segment_to_running_time (segment, format, timestamp);
+  stream_time = gst_segment_to_stream_time (segment, format, timestamp);
+
+  gst_multi_file_sink_post_message_full (multifilesink, timestamp, duration,
+      offset, offset_end, running_time, stream_time, filename);
+}
+
+static void
+gst_multi_file_sink_post_message (GstMultiFileSink * multifilesink,
+    GstBuffer * buffer, const char *filename)
+{
+  GstClockTime duration, timestamp;
+  GstClockTime running_time, stream_time;
+  guint64 offset, offset_end;
+  GstSegment *segment;
+  GstFormat format;
+
+  if (!multifilesink->post_messages)
+    return;
+
+  segment = &GST_BASE_SINK (multifilesink)->segment;
+  format = segment->format;
+
+  timestamp = GST_BUFFER_TIMESTAMP (buffer);
+  duration = GST_BUFFER_DURATION (buffer);
+  offset = GST_BUFFER_OFFSET (buffer);
+  offset_end = GST_BUFFER_OFFSET_END (buffer);
+
+  running_time = gst_segment_to_running_time (segment, format, timestamp);
+  stream_time = gst_segment_to_stream_time (segment, format, timestamp);
+
+  gst_multi_file_sink_post_message_full (multifilesink, timestamp, duration,
+      offset, offset_end, running_time, stream_time, filename);
+}
+
+static gboolean
+gst_multi_file_sink_write_stream_headers (GstMultiFileSink * sink)
+{
+  int i;
+
+  if (sink->streamheaders == NULL)
+    return TRUE;
+
+  /* we want to write these at the beginning */
+  g_assert (sink->cur_file_size == 0);
+
+  for (i = 0; i < sink->n_streamheaders; i++) {
+    GstBuffer *hdr;
+    GstMapInfo map;
+    int ret;
+
+    hdr = sink->streamheaders[i];
+    gst_buffer_map (hdr, &map, GST_MAP_READ);
+    ret = fwrite (map.data, map.size, 1, sink->file);
+    gst_buffer_unmap (hdr, &map);
+
+    if (ret != 1)
+      return FALSE;
+
+    sink->cur_file_size += map.size;
+  }
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_multi_file_sink_write_buffer (GstMultiFileSink * multifilesink,
+    GstBuffer * buffer)
+{
+  GstMapInfo map;
+  gchar *filename;
+  gboolean ret;
+  GError *error = NULL;
+  gboolean first_file = TRUE;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  switch (multifilesink->next_file) {
+    case GST_MULTI_FILE_SINK_NEXT_BUFFER:
+      gst_multi_file_sink_ensure_max_files (multifilesink);
+
+      filename = g_strdup_printf (multifilesink->filename,
+          multifilesink->index);
+      ret = g_file_set_contents (filename, (char *) map.data, map.size, &error);
+      if (!ret)
+        goto write_error;
+
+      gst_multi_file_sink_post_message (multifilesink, buffer, filename);
+
+      gst_multi_file_sink_add_old_file (multifilesink, filename);
+
+      multifilesink->index++;
+
+      break;
+    case GST_MULTI_FILE_SINK_NEXT_DISCONT:
+      if (GST_BUFFER_IS_DISCONT (buffer)) {
+        if (multifilesink->file)
+          gst_multi_file_sink_close_file (multifilesink, buffer);
+      }
+
+      if (multifilesink->file == NULL) {
+        if (!gst_multi_file_sink_open_next_file (multifilesink))
+          goto stdio_write_error;
+      }
+
+      ret = fwrite (map.data, map.size, 1, multifilesink->file);
+      if (ret != 1)
+        goto stdio_write_error;
+
+      break;
+    case GST_MULTI_FILE_SINK_NEXT_KEY_FRAME:
+      if (multifilesink->next_segment == GST_CLOCK_TIME_NONE) {
+        if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
+          multifilesink->next_segment = GST_BUFFER_TIMESTAMP (buffer) +
+              10 * GST_SECOND;
+        }
+      }
+
+      if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
+          GST_BUFFER_TIMESTAMP (buffer) >= multifilesink->next_segment &&
+          !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
+        if (multifilesink->file) {
+          first_file = FALSE;
+          gst_multi_file_sink_close_file (multifilesink, buffer);
+        }
+        multifilesink->next_segment += 10 * GST_SECOND;
+      }
+
+      if (multifilesink->file == NULL) {
+        if (!gst_multi_file_sink_open_next_file (multifilesink))
+          goto stdio_write_error;
+
+        if (!first_file)
+          gst_multi_file_sink_write_stream_headers (multifilesink);
+      }
+
+      ret = fwrite (map.data, map.size, 1, multifilesink->file);
+      if (ret != 1)
+        goto stdio_write_error;
+
+      break;
+    case GST_MULTI_FILE_SINK_NEXT_KEY_UNIT_EVENT:
+      if (multifilesink->file == NULL) {
+        if (!gst_multi_file_sink_open_next_file (multifilesink))
+          goto stdio_write_error;
+
+        /* we don't need to write stream headers here, they will be inserted in
+         * the stream by upstream elements if key unit events have
+         * all_headers=true set
+         */
+      }
+
+      ret = fwrite (map.data, map.size, 1, multifilesink->file);
+
+      if (ret != 1)
+        goto stdio_write_error;
+
+      break;
+    case GST_MULTI_FILE_SINK_NEXT_MAX_SIZE:{
+      guint64 new_size;
+
+      new_size = multifilesink->cur_file_size + map.size;
+      if (new_size > multifilesink->max_file_size) {
+
+        GST_INFO_OBJECT (multifilesink, "current size: %" G_GUINT64_FORMAT
+            ", new_size: %" G_GUINT64_FORMAT ", max. size %" G_GUINT64_FORMAT,
+            multifilesink->cur_file_size, new_size,
+            multifilesink->max_file_size);
+
+        if (multifilesink->file != NULL) {
+          first_file = FALSE;
+          gst_multi_file_sink_close_file (multifilesink, buffer);
+        }
+      }
+
+      if (multifilesink->file == NULL) {
+        if (!gst_multi_file_sink_open_next_file (multifilesink))
+          goto stdio_write_error;
+
+        if (!first_file)
+          gst_multi_file_sink_write_stream_headers (multifilesink);
+      }
+
+      ret = fwrite (map.data, map.size, 1, multifilesink->file);
+
+      if (ret != 1)
+        goto stdio_write_error;
+
+      multifilesink->cur_file_size += map.size;
+      break;
+    }
+    case GST_MULTI_FILE_SINK_NEXT_MAX_DURATION:{
+      GstClockTime new_duration = 0;
+
+      if (GST_BUFFER_PTS_IS_VALID (buffer)
+          && GST_CLOCK_TIME_IS_VALID (multifilesink->file_pts)) {
+        /* The new duration will extend to this new buffer pts ... */
+        new_duration = GST_BUFFER_PTS (buffer) - multifilesink->file_pts;
+        /* ... and duration (if it has one) */
+        if (GST_BUFFER_DURATION_IS_VALID (buffer))
+          new_duration += GST_BUFFER_DURATION (buffer);
+      }
+
+      if (new_duration > multifilesink->max_file_duration) {
+
+        GST_INFO_OBJECT (multifilesink,
+            "new_duration: %" G_GUINT64_FORMAT ", max. duration %"
+            G_GUINT64_FORMAT, new_duration, multifilesink->max_file_duration);
+
+        if (multifilesink->file != NULL) {
+          first_file = FALSE;
+          gst_multi_file_sink_close_file (multifilesink, buffer);
+        }
+      }
+
+      if (multifilesink->file == NULL) {
+        if (!gst_multi_file_sink_open_next_file (multifilesink))
+          goto stdio_write_error;
+
+        multifilesink->file_pts = GST_BUFFER_PTS (buffer);
+        if (!first_file)
+          gst_multi_file_sink_write_stream_headers (multifilesink);
+      }
+
+      ret = fwrite (map.data, map.size, 1, multifilesink->file);
+
+      if (ret != 1)
+        goto stdio_write_error;
+
+      break;
+    }
+    default:
+      g_assert_not_reached ();
+  }
+
+  gst_buffer_unmap (buffer, &map);
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+write_error:
+  {
+    switch (error->code) {
+      case G_FILE_ERROR_NOSPC:{
+        GST_ELEMENT_ERROR (multifilesink, RESOURCE, NO_SPACE_LEFT, (NULL),
+            (NULL));
+        break;
+      }
+      default:{
+        GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE,
+            ("Error while writing to file \"%s\".", filename),
+            ("%s", g_strerror (errno)));
+      }
+    }
+    g_error_free (error);
+    g_free (filename);
+
+    gst_buffer_unmap (buffer, &map);
+    return GST_FLOW_ERROR;
+  }
+stdio_write_error:
+  switch (errno) {
+    case ENOSPC:
+      GST_ELEMENT_ERROR (multifilesink, RESOURCE, NO_SPACE_LEFT,
+          ("Error while writing to file."), ("%s", g_strerror (errno)));
+      break;
+    default:
+      GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE,
+          ("Error while writing to file."), ("%s", g_strerror (errno)));
+  }
+  gst_buffer_unmap (buffer, &map);
+  return GST_FLOW_ERROR;
+}
+
+static GstFlowReturn
+gst_multi_file_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
+{
+  GstMultiFileSink *sink = GST_MULTI_FILE_SINK (bsink);
+  GstFlowReturn flow = GST_FLOW_OK;
+  gboolean key_unit, header;
+
+  header = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_HEADER);
+  key_unit = !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
+
+  if (sink->aggregate_gops) {
+    GstBuffer *gop_buffer = NULL;
+    guint avail;
+
+    avail = gst_adapter_available (sink->gop_adapter);
+
+    GST_LOG_OBJECT (sink, "aggregate GOP: received %s%s unit buffer: "
+        "%" GST_PTR_FORMAT,
+        (key_unit) ? "key" : "delta", (header) ? " header" : "", buffer);
+
+    /* If it's a header buffer, it might potentially be for the next GOP */
+    if (header) {
+      GST_LOG_OBJECT (sink, "Accumulating buffer to potential next GOP");
+      sink->potential_next_gop =
+          g_list_append (sink->potential_next_gop, gst_buffer_ref (buffer));
+    } else {
+      if (key_unit && avail > 0) {
+        GstClockTime pts, dts;
+        GST_LOG_OBJECT (sink, "Grabbing pending completed GOP");
+        pts = gst_adapter_prev_pts_at_offset (sink->gop_adapter, 0, NULL);
+        dts = gst_adapter_prev_dts_at_offset (sink->gop_adapter, 0, NULL);
+        gop_buffer = gst_adapter_take_buffer (sink->gop_adapter, avail);
+        GST_BUFFER_PTS (gop_buffer) = pts;
+        GST_BUFFER_DTS (gop_buffer) = dts;
+      }
+
+      /* just accumulate the buffer */
+      if (sink->potential_next_gop) {
+        GList *tmp;
+        GST_LOG_OBJECT (sink,
+            "Carrying over pending next GOP data into adapter");
+        /* If we have pending data, put that first in the adapter */
+        for (tmp = sink->potential_next_gop; tmp; tmp = tmp->next) {
+          GstBuffer *tmpb = (GstBuffer *) tmp->data;
+          gst_adapter_push (sink->gop_adapter, tmpb);
+        }
+        g_list_free (sink->potential_next_gop);
+        sink->potential_next_gop = NULL;
+      }
+      GST_LOG_OBJECT (sink, "storing buffer in adapter");
+      gst_adapter_push (sink->gop_adapter, gst_buffer_ref (buffer));
+
+      if (gop_buffer != NULL) {
+        GST_DEBUG_OBJECT (sink, "writing out pending GOP, %u bytes", avail);
+        GST_DEBUG_OBJECT (sink,
+            "gop buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
+            " duration:%" GST_TIME_FORMAT,
+            GST_TIME_ARGS (GST_BUFFER_PTS (gop_buffer)),
+            GST_TIME_ARGS (GST_BUFFER_DTS (gop_buffer)),
+            GST_TIME_ARGS (GST_BUFFER_DURATION (gop_buffer)));
+        flow = gst_multi_file_sink_write_buffer (sink, gop_buffer);
+        gst_buffer_unref (gop_buffer);
+      }
+    }
+  } else {
+    flow = gst_multi_file_sink_write_buffer (sink, buffer);
+  }
+  return flow;
+}
+
+static gboolean
+buffer_list_copy_data (GstBuffer ** buf, guint idx, gpointer data)
+{
+  GstBuffer *dest = data;
+  guint num, i;
+
+  if (idx == 0)
+    gst_buffer_copy_into (dest, *buf, GST_BUFFER_COPY_METADATA, 0, -1);
+
+  num = gst_buffer_n_memory (*buf);
+  for (i = 0; i < num; ++i) {
+    GstMemory *mem;
+
+    mem = gst_buffer_get_memory (*buf, i);
+    gst_buffer_append_memory (dest, mem);
+  }
+
+  return TRUE;
+}
+
+/* Our assumption for now is that the buffers in a buffer list should always
+ * end up in the same file. If someone wants different behaviour, they'll just
+ * have to add a property for that. */
+static GstFlowReturn
+gst_multi_file_sink_render_list (GstBaseSink * sink, GstBufferList * list)
+{
+  GstBuffer *buf;
+  guint size;
+
+  size = gst_buffer_list_calculate_size (list);
+  GST_LOG_OBJECT (sink, "total size of buffer list %p: %u", list, size);
+
+  /* copy all buffers in the list into one single buffer, so we can use
+   * the normal render function (FIXME: optimise to avoid the memcpy) */
+  buf = gst_buffer_new ();
+  gst_buffer_list_foreach (list, buffer_list_copy_data, buf);
+  g_assert (gst_buffer_get_size (buf) == size);
+
+  gst_multi_file_sink_render (sink, buf);
+  gst_buffer_unref (buf);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_multi_file_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
+{
+  GstMultiFileSink *multifilesink;
+  GstStructure *structure;
+
+  multifilesink = GST_MULTI_FILE_SINK (sink);
+
+  structure = gst_caps_get_structure (caps, 0);
+  if (structure) {
+    const GValue *value;
+
+    value = gst_structure_get_value (structure, "streamheader");
+
+    if (GST_VALUE_HOLDS_ARRAY (value)) {
+      int i;
+
+      if (multifilesink->streamheaders) {
+        for (i = 0; i < multifilesink->n_streamheaders; i++) {
+          gst_buffer_unref (multifilesink->streamheaders[i]);
+        }
+        g_free (multifilesink->streamheaders);
+      }
+
+      multifilesink->n_streamheaders = gst_value_array_get_size (value);
+      multifilesink->streamheaders =
+          g_malloc (sizeof (GstBuffer *) * multifilesink->n_streamheaders);
+
+      for (i = 0; i < multifilesink->n_streamheaders; i++) {
+        multifilesink->streamheaders[i] =
+            gst_buffer_ref (gst_value_get_buffer (gst_value_array_get_value
+                (value, i)));
+      }
+    }
+  }
+
+  return TRUE;
+}
+
+/* Takes ownership of the filename string */
+static void
+gst_multi_file_sink_add_old_file (GstMultiFileSink * multifilesink, gchar * fn)
+{
+  /* Only add file to the list if a max_files limit is set, otherwise we never
+   * prune the list and memory just builds up until the pipeline is stopped. */
+  if (multifilesink->max_files > 0) {
+    g_queue_push_tail (&multifilesink->old_files, fn);
+  } else {
+    g_free (fn);
+  }
+}
+
+static void
+gst_multi_file_sink_ensure_max_files (GstMultiFileSink * multifilesink)
+{
+  guint max_files = multifilesink->max_files;
+
+  if (max_files == 0)
+    return;
+
+  while (g_queue_get_length (&multifilesink->old_files) >= max_files) {
+    gchar *filename;
+
+    filename = g_queue_pop_head (&multifilesink->old_files);
+    g_remove (filename);
+    g_free (filename);
+  }
+}
+
+static gboolean
+gst_multi_file_sink_event (GstBaseSink * sink, GstEvent * event)
+{
+  GstMultiFileSink *multifilesink;
+  gchar *filename;
+
+  multifilesink = GST_MULTI_FILE_SINK (sink);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CUSTOM_DOWNSTREAM:
+    {
+      GstClockTime timestamp, duration;
+      GstClockTime running_time, stream_time;
+      guint64 offset, offset_end;
+      gboolean all_headers;
+      guint count;
+
+      if (multifilesink->next_file != GST_MULTI_FILE_SINK_NEXT_KEY_UNIT_EVENT ||
+          !gst_video_event_is_force_key_unit (event))
+        goto out;
+
+      gst_video_event_parse_downstream_force_key_unit (event, &timestamp,
+          &stream_time, &running_time, &all_headers, &count);
+
+      if (multifilesink->force_key_unit_count != -1 &&
+          multifilesink->force_key_unit_count == count)
+        goto out;
+
+      multifilesink->force_key_unit_count = count;
+
+      if (multifilesink->file) {
+        duration = GST_CLOCK_TIME_NONE;
+        offset = offset_end = -1;
+        filename = g_strdup_printf (multifilesink->filename,
+            multifilesink->index);
+
+        gst_multi_file_sink_close_file (multifilesink, NULL);
+
+        gst_multi_file_sink_post_message_full (multifilesink, timestamp,
+            duration, offset, offset_end, running_time, stream_time, filename);
+        g_free (filename);
+      }
+
+      if (multifilesink->file == NULL) {
+        if (!gst_multi_file_sink_open_next_file (multifilesink))
+          goto stdio_write_error;
+      }
+
+      break;
+    }
+    case GST_EVENT_EOS:
+      if (multifilesink->aggregate_gops) {
+        GstBuffer *buf = gst_buffer_new ();
+
+        /* push key unit buffer to force writing out the pending GOP data */
+        GST_INFO_OBJECT (sink, "EOS, write pending GOP data");
+        GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
+        gst_multi_file_sink_render (sink, buf);
+        gst_buffer_unref (buf);
+      }
+      if (multifilesink->file) {
+        gchar *filename;
+
+        filename = g_strdup_printf (multifilesink->filename,
+            multifilesink->index);
+
+        gst_multi_file_sink_close_file (multifilesink, NULL);
+
+        gst_multi_file_sink_post_message_from_time (multifilesink,
+            GST_BASE_SINK (multifilesink)->segment.position, -1, filename);
+        g_free (filename);
+      }
+      break;
+    default:
+      break;
+  }
+
+out:
+  return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
+
+  /* ERRORS */
+stdio_write_error:
+  {
+    GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE,
+        ("Error while writing to file."), (NULL));
+    gst_event_unref (event);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_multi_file_sink_open_next_file (GstMultiFileSink * multifilesink)
+{
+  char *filename;
+
+  g_return_val_if_fail (multifilesink->file == NULL, FALSE);
+
+  gst_multi_file_sink_ensure_max_files (multifilesink);
+
+  filename = g_strdup_printf (multifilesink->filename, multifilesink->index);
+  multifilesink->file = g_fopen (filename, "wb");
+  if (multifilesink->file == NULL) {
+    g_free (filename);
+    return FALSE;
+  }
+
+  GST_INFO_OBJECT (multifilesink, "opening file %s", filename);
+
+  gst_multi_file_sink_add_old_file (multifilesink, filename);
+
+  multifilesink->cur_file_size = 0;
+  return TRUE;
+}
+
+static void
+gst_multi_file_sink_close_file (GstMultiFileSink * multifilesink,
+    GstBuffer * buffer)
+{
+  char *filename;
+
+  fclose (multifilesink->file);
+  multifilesink->file = NULL;
+
+  if (buffer) {
+    filename = g_strdup_printf (multifilesink->filename, multifilesink->index);
+    gst_multi_file_sink_post_message (multifilesink, buffer, filename);
+    g_free (filename);
+  }
+
+  multifilesink->index++;
+}
diff --git a/gst/multifile/gstmultifilesink.h b/gst/multifile/gstmultifilesink.h
new file mode 100644
index 0000000..1bfe533
--- /dev/null
+++ b/gst/multifile/gstmultifilesink.h
@@ -0,0 +1,118 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wtay@chello.be>
+ *                    2006 Wim Taymans <wim@fluendo.com>
+ *                    2006 David A. Schleef <ds@schleef.org>
+ *
+ * gstmultifilesink.h:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MULTIFILESINK_H__
+#define __GST_MULTIFILESINK_H__
+
+#include <gst/gst.h>
+#include <gst/base/base.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_MULTI_FILE_SINK \
+  (gst_multi_file_sink_get_type())
+#define GST_MULTI_FILE_SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULTI_FILE_SINK,GstMultiFileSink))
+#define GST_MULTI_FILE_SINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULTI_FILE_SINK,GstMultiFileSinkClass))
+#define GST_IS_MULTI_FILE_SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULTI_FILE_SINK))
+#define GST_IS_MULTI_FILE_SINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULTI_FILE_SINK))
+
+typedef struct _GstMultiFileSink GstMultiFileSink;
+typedef struct _GstMultiFileSinkClass GstMultiFileSinkClass;
+
+/**
+ * GstMultiFileSinkNext:
+ * @GST_MULTI_FILE_SINK_NEXT_BUFFER: New file for each buffer
+ * @GST_MULTI_FILE_SINK_NEXT_DISCONT: New file after each discontinuity
+ * @GST_MULTI_FILE_SINK_NEXT_KEY_FRAME: New file at each key frame
+ *  (Useful for MPEG-TS segmenting)
+ * @GST_MULTI_FILE_SINK_NEXT_KEY_UNIT_EVENT: New file after a force key unit
+ *  event
+ * @GST_MULTI_FILE_SINK_NEXT_MAX_SIZE: New file when the configured maximum file
+ *  size would be exceeded with the next buffer or buffer list
+ * @GST_MULTI_FILE_SINK_NEXT_MAX_DURATION: New file when the configured maximum duration
+ *  would be exceeded with the next buffer or buffer list
+ *
+ * File splitting modes.
+ */
+typedef enum {
+  GST_MULTI_FILE_SINK_NEXT_BUFFER,
+  GST_MULTI_FILE_SINK_NEXT_DISCONT,
+  GST_MULTI_FILE_SINK_NEXT_KEY_FRAME,
+  GST_MULTI_FILE_SINK_NEXT_KEY_UNIT_EVENT,
+  GST_MULTI_FILE_SINK_NEXT_MAX_SIZE,
+  GST_MULTI_FILE_SINK_NEXT_MAX_DURATION
+} GstMultiFileSinkNext;
+
+struct _GstMultiFileSink
+{
+  GstBaseSink parent;
+
+  gchar *filename;
+  gint index;
+  gboolean post_messages;
+  GstMultiFileSinkNext next_file;
+  FILE *file;
+
+  guint max_files;
+  GQueue old_files;        /* keep track of old files for max_files handling */
+
+  gint64 next_segment;
+
+  int n_streamheaders;
+  GstBuffer **streamheaders;
+  guint force_key_unit_count;
+
+  guint64 cur_file_size;
+  guint64 max_file_size;
+
+  GstClockTime file_pts;
+  GstClockTime max_file_duration;
+
+  gboolean aggregate_gops;
+  GstAdapter *gop_adapter;  /* to aggregate GOPs */
+  GList *potential_next_gop;	/* To detect false-positives */
+};
+
+struct _GstMultiFileSinkClass
+{
+  GstBaseSinkClass parent_class;
+};
+
+GType gst_multi_file_sink_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_MULTIFILESINK_H__ */
diff --git a/gst/multifile/gstmultifilesrc.c b/gst/multifile/gstmultifilesrc.c
new file mode 100644
index 0000000..3ad1a1b
--- /dev/null
+++ b/gst/multifile/gstmultifilesrc.c
@@ -0,0 +1,572 @@
+/* GStreamer
+ * Copyright (C) 2006 David A. Schleef <ds@schleef.org>
+ *
+ * gstmultifilesrc.c:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-multifilesrc
+ * @see_also: #GstFileSrc
+ *
+ * Reads buffers from sequentially named files. If used together with an image
+ * decoder, one needs to use the #GstMultiFileSrc:caps property or a capsfilter
+ * to force to caps containing a framerate. Otherwise image decoders send EOS
+ * after the first picture. We also need a videorate element to set timestamps
+ * on all buffers after the first one in accordance with the framerate.
+ *
+ * File names are created by replacing "\%d" with the index using printf().
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 multifilesrc location="img.%04d.png" index=0 caps="image/png,framerate=\(fraction\)12/1" ! \
+ *     pngdec ! videoconvert ! videorate ! theoraenc ! oggmux ! \
+ *     filesink location="images.ogg"
+ * ]| This pipeline creates a video file "images.ogg" by joining multiple PNG
+ * files named img.0000.png, img.0001.png, etc.
+ * </refsect2>
+*/
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "gstmultifilesrc.h"
+
+
+static GstFlowReturn gst_multi_file_src_create (GstPushSrc * src,
+    GstBuffer ** buffer);
+
+static void gst_multi_file_src_dispose (GObject * object);
+
+static void gst_multi_file_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_multi_file_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static GstCaps *gst_multi_file_src_getcaps (GstBaseSrc * src, GstCaps * filter);
+static gboolean gst_multi_file_src_query (GstBaseSrc * src, GstQuery * query);
+static void gst_multi_file_src_uri_handler_init (gpointer g_iface,
+    gpointer iface_data);
+
+
+static GstStaticPadTemplate gst_multi_file_src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (gst_multi_file_src_debug);
+#define GST_CAT_DEFAULT gst_multi_file_src_debug
+
+enum
+{
+  PROP_0,
+  PROP_LOCATION,
+  PROP_INDEX,
+  PROP_START_INDEX,
+  PROP_STOP_INDEX,
+  PROP_CAPS,
+  PROP_LOOP
+};
+
+#define DEFAULT_LOCATION "%05d"
+#define DEFAULT_INDEX 0
+
+#define gst_multi_file_src_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstMultiFileSrc, gst_multi_file_src, GST_TYPE_PUSH_SRC,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
+        gst_multi_file_src_uri_handler_init));
+
+
+static gboolean
+is_seekable (GstBaseSrc * src)
+{
+  GstMultiFileSrc *mfs = GST_MULTI_FILE_SRC (src);
+
+  if (mfs->fps_n != -1)
+    return TRUE;
+
+  return FALSE;
+}
+
+static gboolean
+do_seek (GstBaseSrc * bsrc, GstSegment * segment)
+{
+  gboolean reverse;
+  GstClockTime position;
+  GstMultiFileSrc *src;
+
+  src = GST_MULTI_FILE_SRC (bsrc);
+
+  segment->time = segment->start;
+  position = segment->position;
+  reverse = segment->rate < 0;
+
+  if (reverse) {
+    GST_FIXME_OBJECT (src, "Handle reverse playback");
+
+    return FALSE;
+  }
+
+  /* now move to the position indicated */
+  if (src->fps_n) {
+    src->index = gst_util_uint64_scale (position,
+        src->fps_n, src->fps_d * GST_SECOND);
+  } else {
+    src->index = 0;
+    GST_WARNING_OBJECT (src, "No FPS set, can not seek");
+
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static void
+gst_multi_file_src_class_init (GstMultiFileSrcClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass);
+  GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
+
+  gobject_class->set_property = gst_multi_file_src_set_property;
+  gobject_class->get_property = gst_multi_file_src_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_LOCATION,
+      g_param_spec_string ("location", "File Location",
+          "Pattern to create file names of input files.  File names are "
+          "created by calling sprintf() with the pattern and the current "
+          "index.", DEFAULT_LOCATION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_INDEX,
+      g_param_spec_int ("index", "File Index",
+          "Index to use with location property to create file names.  The "
+          "index is incremented by one for each buffer read.",
+          0, INT_MAX, DEFAULT_INDEX,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_START_INDEX,
+      g_param_spec_int ("start-index", "Start Index",
+          "Start value of index.  The initial value of index can be set "
+          "either by setting index or start-index.  When the end of the loop "
+          "is reached, the index will be set to the value start-index.",
+          0, INT_MAX, DEFAULT_INDEX,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_STOP_INDEX,
+      g_param_spec_int ("stop-index", "Stop Index",
+          "Stop value of index.  The special value -1 means no stop.",
+          -1, INT_MAX, DEFAULT_INDEX,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_CAPS,
+      g_param_spec_boxed ("caps", "Caps",
+          "Caps describing the format of the data.",
+          GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_LOOP,
+      g_param_spec_boolean ("loop", "Loop",
+          "Whether to repeat from the beginning when all files have been read.",
+          FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gobject_class->dispose = gst_multi_file_src_dispose;
+
+  gstbasesrc_class->get_caps = gst_multi_file_src_getcaps;
+  gstbasesrc_class->query = gst_multi_file_src_query;
+  gstbasesrc_class->is_seekable = is_seekable;
+  gstbasesrc_class->do_seek = do_seek;
+
+  gstpushsrc_class->create = gst_multi_file_src_create;
+
+  GST_DEBUG_CATEGORY_INIT (gst_multi_file_src_debug, "multifilesrc", 0,
+      "multifilesrc element");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_multi_file_src_pad_template);
+  gst_element_class_set_static_metadata (gstelement_class, "Multi-File Source",
+      "Source/File", "Read a sequentially named set of files into buffers",
+      "David Schleef <ds@schleef.org>");
+}
+
+static void
+gst_multi_file_src_init (GstMultiFileSrc * multifilesrc)
+{
+  multifilesrc->start_index = DEFAULT_INDEX;
+  multifilesrc->index = DEFAULT_INDEX;
+  multifilesrc->stop_index = -1;
+  multifilesrc->filename = g_strdup (DEFAULT_LOCATION);
+  multifilesrc->successful_read = FALSE;
+  multifilesrc->fps_n = multifilesrc->fps_d = -1;
+
+}
+
+static void
+gst_multi_file_src_dispose (GObject * object)
+{
+  GstMultiFileSrc *src = GST_MULTI_FILE_SRC (object);
+
+  g_free (src->filename);
+  src->filename = NULL;
+  if (src->caps)
+    gst_caps_unref (src->caps);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static GstCaps *
+gst_multi_file_src_getcaps (GstBaseSrc * src, GstCaps * filter)
+{
+  GstMultiFileSrc *multi_file_src = GST_MULTI_FILE_SRC (src);
+
+  GST_DEBUG_OBJECT (src, "returning %" GST_PTR_FORMAT, multi_file_src->caps);
+
+  if (multi_file_src->caps) {
+    if (filter)
+      return gst_caps_intersect_full (filter, multi_file_src->caps,
+          GST_CAPS_INTERSECT_FIRST);
+    else
+      return gst_caps_ref (multi_file_src->caps);
+  } else {
+    if (filter)
+      return gst_caps_ref (filter);
+    else
+      return gst_caps_new_any ();
+  }
+}
+
+static gboolean
+gst_multi_file_src_query (GstBaseSrc * src, GstQuery * query)
+{
+  gboolean res;
+  GstMultiFileSrc *mfsrc;
+
+  mfsrc = GST_MULTI_FILE_SRC (src);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:
+    {
+      GstFormat format;
+
+      gst_query_parse_position (query, &format, NULL);
+      switch (format) {
+        case GST_FORMAT_BUFFERS:
+        case GST_FORMAT_DEFAULT:
+          gst_query_set_position (query, format,
+              mfsrc->index - mfsrc->start_index);
+          res = TRUE;
+          break;
+        default:
+          res = GST_BASE_SRC_CLASS (parent_class)->query (src, query);
+          break;
+      }
+      break;
+    }
+    default:
+      res = GST_BASE_SRC_CLASS (parent_class)->query (src, query);
+      break;
+  }
+  return res;
+}
+
+static gboolean
+gst_multi_file_src_set_location (GstMultiFileSrc * src, const gchar * location)
+{
+  g_free (src->filename);
+  if (location != NULL) {
+    src->filename = g_strdup (location);
+  } else {
+    src->filename = NULL;
+  }
+
+  return TRUE;
+}
+
+static void
+gst_multi_file_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstMultiFileSrc *src = GST_MULTI_FILE_SRC (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      gst_multi_file_src_set_location (src, g_value_get_string (value));
+      break;
+    case PROP_INDEX:
+      GST_OBJECT_LOCK (src);
+      /* index was really meant to be read-only, but for backwards-compatibility
+       * we set start_index to make it work as it used to */
+      if (!GST_OBJECT_FLAG_IS_SET (src, GST_BASE_SRC_FLAG_STARTED))
+        src->start_index = g_value_get_int (value);
+      else
+        src->index = g_value_get_int (value);
+      GST_OBJECT_UNLOCK (src);
+      break;
+    case PROP_START_INDEX:
+      src->start_index = g_value_get_int (value);
+      break;
+    case PROP_STOP_INDEX:
+      src->stop_index = g_value_get_int (value);
+      break;
+    case PROP_CAPS:
+    {
+      GstStructure *st = NULL;
+      const GstCaps *caps = gst_value_get_caps (value);
+      GstCaps *new_caps;
+
+      if (caps == NULL) {
+        new_caps = gst_caps_new_any ();
+      } else {
+        new_caps = gst_caps_copy (caps);
+      }
+      gst_caps_replace (&src->caps, new_caps);
+      gst_pad_set_caps (GST_BASE_SRC_PAD (src), new_caps);
+
+      if (new_caps && gst_caps_get_size (new_caps) == 1 &&
+          (st = gst_caps_get_structure (new_caps, 0))
+          && gst_structure_get_fraction (st, "framerate", &src->fps_n,
+              &src->fps_d)) {
+        GST_INFO_OBJECT (src, "Seting framerate to %d/%d", src->fps_n,
+            src->fps_d);
+      } else {
+        src->fps_n = -1;
+        src->fps_d = -1;
+      }
+    }
+      break;
+    case PROP_LOOP:
+      src->loop = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_multi_file_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstMultiFileSrc *src = GST_MULTI_FILE_SRC (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      g_value_set_string (value, src->filename);
+      break;
+    case PROP_INDEX:
+      g_value_set_int (value, src->index);
+      break;
+    case PROP_START_INDEX:
+      g_value_set_int (value, src->start_index);
+      break;
+    case PROP_STOP_INDEX:
+      g_value_set_int (value, src->stop_index);
+      break;
+    case PROP_CAPS:
+      gst_value_set_caps (value, src->caps);
+      break;
+    case PROP_LOOP:
+      g_value_set_boolean (value, src->loop);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gchar *
+gst_multi_file_src_get_filename (GstMultiFileSrc * multifilesrc)
+{
+  gchar *filename;
+
+  GST_DEBUG ("%d", multifilesrc->index);
+  filename = g_strdup_printf (multifilesrc->filename, multifilesrc->index);
+
+  return filename;
+}
+
+static GstFlowReturn
+gst_multi_file_src_create (GstPushSrc * src, GstBuffer ** buffer)
+{
+  GstMultiFileSrc *multifilesrc;
+  gsize size;
+  gchar *data;
+  gchar *filename;
+  GstBuffer *buf;
+  gboolean ret;
+  GError *error = NULL;
+
+  multifilesrc = GST_MULTI_FILE_SRC (src);
+
+  if (multifilesrc->index < multifilesrc->start_index) {
+    multifilesrc->index = multifilesrc->start_index;
+  }
+
+  if (multifilesrc->stop_index != -1 &&
+      multifilesrc->index > multifilesrc->stop_index) {
+    if (multifilesrc->loop)
+      multifilesrc->index = multifilesrc->start_index;
+    else
+      return GST_FLOW_EOS;
+  }
+
+  filename = gst_multi_file_src_get_filename (multifilesrc);
+
+  GST_DEBUG_OBJECT (multifilesrc, "reading from file \"%s\".", filename);
+
+  ret = g_file_get_contents (filename, &data, &size, &error);
+  if (!ret) {
+    if (multifilesrc->successful_read) {
+      /* If we've read at least one buffer successfully, not finding the
+       * next file is EOS. */
+      g_free (filename);
+      if (error != NULL)
+        g_error_free (error);
+
+      if (multifilesrc->loop) {
+        error = NULL;
+        multifilesrc->index = multifilesrc->start_index;
+
+        filename = gst_multi_file_src_get_filename (multifilesrc);
+        ret = g_file_get_contents (filename, &data, &size, &error);
+        if (!ret) {
+          g_free (filename);
+          if (error != NULL)
+            g_error_free (error);
+
+          return GST_FLOW_EOS;
+        }
+      } else {
+        return GST_FLOW_EOS;
+      }
+    } else {
+      goto handle_error;
+    }
+  }
+
+  multifilesrc->successful_read = TRUE;
+  multifilesrc->index++;
+
+  buf = gst_buffer_new ();
+  gst_buffer_append_memory (buf,
+      gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
+  GST_BUFFER_OFFSET (buf) = multifilesrc->offset;
+  GST_BUFFER_OFFSET_END (buf) = multifilesrc->offset + size;
+  multifilesrc->offset += size;
+
+  GST_DEBUG_OBJECT (multifilesrc, "read file \"%s\".", filename);
+
+  g_free (filename);
+  *buffer = buf;
+  return GST_FLOW_OK;
+
+handle_error:
+  {
+    if (error != NULL) {
+      GST_ELEMENT_ERROR (multifilesrc, RESOURCE, READ,
+          ("Error while reading from file \"%s\".", filename),
+          ("%s", error->message));
+      g_error_free (error);
+    } else {
+      GST_ELEMENT_ERROR (multifilesrc, RESOURCE, READ,
+          ("Error while reading from file \"%s\".", filename),
+          ("%s", g_strerror (errno)));
+    }
+    g_free (filename);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstURIType
+gst_multi_file_src_uri_get_type (GType type)
+{
+  return GST_URI_SRC;
+}
+
+static const gchar *const *
+gst_multi_file_src_uri_get_protocols (GType type)
+{
+  static const gchar *protocols[] = { "multifile", NULL };
+
+  return (const gchar * const *) protocols;
+}
+
+static gchar *
+gst_multi_file_src_uri_get_uri (GstURIHandler * handler)
+{
+  GstMultiFileSrc *src = GST_MULTI_FILE_SRC (handler);
+  gchar *ret;
+
+  GST_OBJECT_LOCK (src);
+  if (src->filename != NULL) {
+    GstUri *uri = gst_uri_new ("multifle", NULL, NULL, GST_URI_NO_PORT,
+        src->filename, NULL, NULL);
+
+    ret = gst_uri_to_string (uri);
+    gst_uri_unref (uri);
+  } else {
+    ret = NULL;
+  }
+  GST_OBJECT_UNLOCK (src);
+
+  return ret;
+}
+
+static gboolean
+gst_multi_file_src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+    GError ** error)
+{
+  GstMultiFileSrc *src = GST_MULTI_FILE_SRC (handler);
+  GstUri *gsturi;
+  gchar *path;
+
+  gsturi = gst_uri_from_string (uri);
+  if (gsturi == NULL)
+    goto invalid_uri;
+
+  /* This should get us the unescaped path */
+  path = gst_uri_get_path (gsturi);
+  if (path == NULL)
+    goto invalid_uri;
+
+  GST_OBJECT_LOCK (src);
+  gst_multi_file_src_set_location (src, path);
+  GST_OBJECT_UNLOCK (src);
+
+  g_free (path);
+  gst_uri_unref (gsturi);
+
+  return TRUE;
+
+/* ERRORS */
+invalid_uri:
+  {
+    GST_WARNING_OBJECT (src, "Invalid multifile URI '%s'", uri);
+    g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
+        "Invalid multifile URI");
+    if (gsturi)
+      gst_uri_unref (gsturi);
+    return FALSE;
+  }
+}
+
+static void
+gst_multi_file_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+  iface->get_type = gst_multi_file_src_uri_get_type;
+  iface->get_protocols = gst_multi_file_src_uri_get_protocols;
+  iface->get_uri = gst_multi_file_src_uri_get_uri;
+  iface->set_uri = gst_multi_file_src_uri_set_uri;
+}
diff --git a/gst/multifile/gstmultifilesrc.h b/gst/multifile/gstmultifilesrc.h
new file mode 100644
index 0000000..65b9730
--- /dev/null
+++ b/gst/multifile/gstmultifilesrc.h
@@ -0,0 +1,72 @@
+/* GStreamer
+ * Copyright (C) 2006 David A. Schleef <ds@schleef.org>
+ *
+ * gstmultifilesrc.c:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MULTIFILESRC_H__
+#define __GST_MULTIFILESRC_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_MULTI_FILE_SRC \
+  (gst_multi_file_src_get_type())
+#define GST_MULTI_FILE_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULTI_FILE_SRC,GstMultiFileSrc))
+#define GST_MULTI_FILE_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULTI_FILE_SRC,GstMultiFileSrcClass))
+#define GST_IS_MULTI_FILE_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULTI_FILE_SRC))
+#define GST_IS_MULTI_FILE_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULTI_FILE_SRC))
+
+typedef struct _GstMultiFileSrc GstMultiFileSrc;
+typedef struct _GstMultiFileSrcClass GstMultiFileSrcClass;
+
+struct _GstMultiFileSrc
+{
+  GstPushSrc parent;
+
+  gchar *filename;
+  int start_index;
+  int stop_index;
+  int index;
+
+  int offset;
+
+  gboolean loop;
+
+  GstCaps *caps;
+  gboolean successful_read;
+
+  gint fps_n, fps_d;
+};
+
+struct _GstMultiFileSrcClass
+{
+  GstPushSrcClass parent_class;
+};
+
+GType gst_multi_file_src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_MULTIFILESRC_H__ */
diff --git a/gst/multifile/gstsplitfilesrc.c b/gst/multifile/gstsplitfilesrc.c
new file mode 100644
index 0000000..2b2d0f8
--- /dev/null
+++ b/gst/multifile/gstsplitfilesrc.c
@@ -0,0 +1,598 @@
+/* GStreamer Split File Source
+ * Copyright (C) 2011 Collabora Ltd. <tim.muller@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-splitfilesrc
+ * @see_also: #GstFileSrc, #GstMultiFileSrc
+ *
+ * Reads data from multiple files, presenting those files as one continuous
+ * file to downstream elements. This is useful for reading a large file that
+ * had to be split into multiple parts due to filesystem file size limitations,
+ * for example.
+ *
+ * The files to select are chosen via the location property, which supports
+ * (and expects) shell-style wildcards (but only for the filename, not for
+ * directories). The results will be sorted.
+ *
+ * <refsect2>
+ * <title>Example launch lines</title>
+ * |[
+ * gst-launch-1.0 splitfilesrc location="/path/to/part-*.mpg" ! decodebin ! ...
+ * ]| Plays the different parts as if they were one single MPEG file.
+ * |[
+ * gst-launch-1.0 playbin uri="splitfile://path/to/foo.avi.*"
+ * ]| Plays the different parts as if they were one single AVI file.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "gstsplitfilesrc.h"
+#include "gstsplitutils.h"
+
+#include <string.h>
+
+enum
+{
+  PROP_LOCATION = 1
+};
+
+#define DEFAULT_LOCATION NULL
+
+static void gst_split_file_src_uri_handler_init (gpointer g_iface,
+    gpointer iface_data);
+static void gst_split_file_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_split_file_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_split_file_src_finalize (GObject * obj);
+
+static gboolean gst_split_file_src_start (GstBaseSrc * basesrc);
+static gboolean gst_split_file_src_stop (GstBaseSrc * basesrc);
+static gboolean gst_split_file_src_can_seek (GstBaseSrc * basesrc);
+static gboolean gst_split_file_src_get_size (GstBaseSrc * basesrc, guint64 * s);
+static gboolean gst_split_file_src_unlock (GstBaseSrc * basesrc);
+static GstFlowReturn gst_split_file_src_create (GstBaseSrc * basesrc,
+    guint64 offset, guint size, GstBuffer ** buffer);
+
+static GstStaticPadTemplate gst_split_file_src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (splitfilesrc_debug);
+#define GST_CAT_DEFAULT splitfilesrc_debug
+
+
+G_DEFINE_TYPE_WITH_CODE (GstSplitFileSrc, gst_split_file_src, GST_TYPE_BASE_SRC,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
+        gst_split_file_src_uri_handler_init));
+
+#ifdef G_OS_WIN32
+#define WIN32_BLURB " Location string must be in UTF-8 encoding (on Windows)."
+#else
+#define WIN32_BLURB             /* nothing */
+#endif
+
+static void
+gst_split_file_src_class_init (GstSplitFileSrcClass * klass)
+{
+  GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = gst_split_file_src_set_property;
+  gobject_class->get_property = gst_split_file_src_get_property;
+  gobject_class->finalize = gst_split_file_src_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_LOCATION,
+      g_param_spec_string ("location", "File Location",
+          "Wildcard pattern to match file names of the input files. If "
+          "the location is an absolute path or contains directory components, "
+          "only the base file name part will be considered for pattern "
+          "matching. The results will be sorted." WIN32_BLURB,
+          DEFAULT_LOCATION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_split_file_src_start);
+  gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_split_file_src_stop);
+  gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_split_file_src_create);
+  gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_split_file_src_get_size);
+  gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_split_file_src_unlock);
+  gstbasesrc_class->is_seekable =
+      GST_DEBUG_FUNCPTR (gst_split_file_src_can_seek);
+
+  GST_DEBUG_CATEGORY_INIT (splitfilesrc_debug, "splitfilesrc", 0,
+      "splitfilesrc element");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_split_file_src_pad_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "Split-File Source",
+      "Source/File",
+      "Read a sequentially named set of files as if it was one large file",
+      "Tim-Philipp Müller <tim.muller@collabora.co.uk>");
+}
+
+static void
+gst_split_file_src_init (GstSplitFileSrc * splitfilesrc)
+{
+}
+
+static void
+gst_split_file_src_finalize (GObject * obj)
+{
+  GstSplitFileSrc *src = GST_SPLIT_FILE_SRC (obj);
+
+  g_free (src->location);
+  src->location = NULL;
+
+  G_OBJECT_CLASS (gst_split_file_src_parent_class)->finalize (obj);
+}
+
+static gboolean
+gst_split_file_src_can_seek (GstBaseSrc * basesrc)
+{
+  return TRUE;
+}
+
+static gboolean
+gst_split_file_src_unlock (GstBaseSrc * basesrc)
+{
+  /* This is not actually that useful, since all normal file
+   * operations are fully blocking anyway */
+#if 0
+  GstSplitFileSrc *src = GST_SPLIT_FILE_SRC (basesrc);
+
+  GST_DEBUG_OBJECT (src, "cancelling pending I/O operation if there is one");
+  /* g_cancellable_cancel (src->cancellable); */
+  GST_DEBUG_OBJECT (src, "done");
+#endif
+
+  return TRUE;
+}
+
+static gboolean
+gst_split_file_src_get_size (GstBaseSrc * basesrc, guint64 * size)
+{
+  GstSplitFileSrc *src = GST_SPLIT_FILE_SRC (basesrc);
+
+  *size = src->parts[src->num_parts - 1].stop + 1;
+  return TRUE;
+}
+
+static void
+gst_split_file_src_set_location (GstSplitFileSrc * src, const char *location)
+{
+  GST_OBJECT_LOCK (src);
+  g_free (src->location);
+
+  if (location != NULL && g_str_has_prefix (location, "splitfile://"))
+    src->location = gst_uri_get_location (location);
+  else
+    src->location = g_strdup (location);
+#ifdef G_OS_WIN32
+  if (!g_utf8_validate (src->location, -1, NULL)) {
+    g_warning ("splitfilesrc 'location' property must be in UTF-8 "
+        "encoding on Windows");
+  }
+#endif
+  GST_OBJECT_UNLOCK (src);
+}
+
+static void
+gst_split_file_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstSplitFileSrc *src = GST_SPLIT_FILE_SRC (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      gst_split_file_src_set_location (src, g_value_get_string (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_split_file_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstSplitFileSrc *src = GST_SPLIT_FILE_SRC (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      GST_OBJECT_LOCK (src);
+      g_value_set_string (value, src->location);
+      GST_OBJECT_UNLOCK (src);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_split_file_src_start (GstBaseSrc * basesrc)
+{
+  GstSplitFileSrc *src = GST_SPLIT_FILE_SRC (basesrc);
+  GCancellable *cancel;
+  gboolean ret = FALSE;
+  guint64 offset;
+  GError *err = NULL;
+  gchar *basename = NULL;
+  gchar *dirname = NULL;
+  gchar **files;
+  guint i;
+
+  GST_OBJECT_LOCK (src);
+  if (src->location != NULL && src->location[0] != '\0') {
+    basename = g_path_get_basename (src->location);
+    dirname = g_path_get_dirname (src->location);
+  }
+  GST_OBJECT_UNLOCK (src);
+
+  files = gst_split_util_find_files (dirname, basename, &err);
+
+  if (files == NULL || *files == NULL)
+    goto no_files;
+
+  src->num_parts = g_strv_length (files);
+  src->parts = g_new0 (GstFilePart, src->num_parts);
+
+  cancel = src->cancellable;
+
+  offset = 0;
+  for (i = 0; i < src->num_parts; ++i) {
+    GFileInputStream *stream;
+    GFileInfo *info;
+    goffset size;
+    GFile *file;
+
+    file = g_file_new_for_path (files[i]);
+    stream = g_file_read (file, cancel, &err);
+    g_object_unref (file);
+
+    if (err != NULL)
+      goto open_read_error;
+
+    info = g_file_input_stream_query_info (stream, "standard::*", NULL, &err);
+    if (err != NULL) {
+      g_object_unref (stream);
+      goto query_info_error;
+    }
+
+    size = g_file_info_get_size (info);
+    g_object_unref (info);
+
+    src->parts[i].stream = stream;
+    src->parts[i].path = g_strdup (files[i]);
+    src->parts[i].start = offset;
+    src->parts[i].stop = offset + size - 1;
+
+    GST_DEBUG ("[%010" G_GUINT64_FORMAT "-%010" G_GUINT64_FORMAT "] %s",
+        src->parts[i].start, src->parts[i].stop, src->parts[i].path);
+
+    offset += size;
+  }
+
+  GST_INFO ("Successfully opened %u file parts for reading", src->num_parts);
+
+  src->cur_part = 0;
+
+  src->cancellable = g_cancellable_new ();
+
+  ret = TRUE;
+
+done:
+  if (err != NULL)
+    g_error_free (err);
+  g_strfreev (files);
+  g_free (basename);
+  g_free (dirname);
+  return ret;
+
+/* ERRORS */
+no_files:
+  {
+    if (err->code == G_IO_ERROR_CANCELLED)
+      goto cancelled;
+
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("%s", err->message),
+        ("Failed to find files in '%s' for pattern '%s'",
+            GST_STR_NULL (dirname), GST_STR_NULL (basename)));
+    goto done;
+  }
+open_read_error:
+  {
+    if (err->code == G_IO_ERROR_CANCELLED)
+      goto cancelled;
+
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("%s", err->message),
+        ("Failed to open file '%s' for reading", files[i]));
+    goto done;
+  }
+query_info_error:
+  {
+    if (err->code == G_IO_ERROR_CANCELLED)
+      goto cancelled;
+
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("%s", err->message),
+        ("Failed to query info for file '%s'", files[i]));
+    goto done;
+  }
+cancelled:
+  {
+    GST_DEBUG_OBJECT (src, "I/O operation cancelled from another thread");
+    goto done;
+  }
+}
+
+static gboolean
+gst_split_file_src_stop (GstBaseSrc * basesrc)
+{
+  GstSplitFileSrc *src = GST_SPLIT_FILE_SRC (basesrc);
+  guint i;
+
+  for (i = 0; i < src->num_parts; ++i) {
+    if (src->parts[i].stream != NULL)
+      g_object_unref (src->parts[i].stream);
+    g_free (src->parts[i].path);
+  }
+  g_free (src->parts);
+  src->parts = NULL;
+  src->num_parts = 0;
+
+  g_object_unref (src->cancellable);
+  src->cancellable = NULL;
+
+  return TRUE;
+}
+
+static gint
+gst_split_file_src_part_search (GstFilePart * part, guint64 * offset,
+    gpointer user_data)
+{
+  if (*offset > part->stop)
+    return -1;                  /* The target is after this part */
+  else if (*offset < part->start)
+    return 1;                   /* The target is before this part */
+  else
+    return 0;                   /* This is the target part */
+}
+
+static gboolean
+gst_split_file_src_find_part_for_offset (GstSplitFileSrc * src, guint64 offset,
+    guint * part_number)
+{
+  gboolean res = TRUE;
+  GstFilePart *part;
+
+  part =
+      gst_util_array_binary_search (src->parts, src->num_parts,
+      sizeof (GstFilePart),
+      (GCompareDataFunc) gst_split_file_src_part_search,
+      GST_SEARCH_MODE_AFTER, &offset, NULL);
+
+  if (part)
+    *part_number = part - src->parts;
+  else
+    res = FALSE;
+
+  return res;
+}
+
+static GstFlowReturn
+gst_split_file_src_create (GstBaseSrc * basesrc, guint64 offset, guint size,
+    GstBuffer ** buffer)
+{
+  GstSplitFileSrc *src = GST_SPLIT_FILE_SRC (basesrc);
+  GstFilePart cur_part;
+  GInputStream *stream;
+  GCancellable *cancel;
+  GSeekable *seekable;
+  GstBuffer *buf;
+  GError *err = NULL;
+  guint64 read_offset;
+  GstMapInfo map;
+  guint8 *data;
+  guint to_read;
+
+  cur_part = src->parts[src->cur_part];
+  if (offset < cur_part.start || offset > cur_part.stop) {
+    if (!gst_split_file_src_find_part_for_offset (src, offset, &src->cur_part))
+      return GST_FLOW_EOS;
+    cur_part = src->parts[src->cur_part];
+  }
+
+  GST_LOG_OBJECT (src, "current part: %u (%" G_GUINT64_FORMAT " - "
+      "%" G_GUINT64_FORMAT ", %s)", src->cur_part, cur_part.start,
+      cur_part.stop, cur_part.path);
+
+  buf = gst_buffer_new_allocate (NULL, size, NULL);
+
+  GST_BUFFER_OFFSET (buf) = offset;
+
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  data = map.data;
+
+  cancel = src->cancellable;
+
+  while (size > 0) {
+    guint64 bytes_to_end_of_part;
+    gsize read = 0;
+
+    /* we want the offset into the file part */
+    read_offset = offset - cur_part.start;
+
+    GST_LOG ("Reading part %03u from offset %" G_GUINT64_FORMAT " (%s)",
+        src->cur_part, read_offset, cur_part.path);
+
+    /* FIXME: only seek when needed (hopefully gio is smart) */
+    seekable = G_SEEKABLE (cur_part.stream);
+    if (!g_seekable_seek (seekable, read_offset, G_SEEK_SET, cancel, &err))
+      goto seek_failed;
+
+    GST_LOG_OBJECT (src, "now: %" G_GUINT64_FORMAT, g_seekable_tell (seekable));
+
+    bytes_to_end_of_part = (cur_part.stop - cur_part.start) + 1 - read_offset;
+    to_read = MIN (size, bytes_to_end_of_part);
+
+    GST_LOG_OBJECT (src, "reading %u bytes from part %u (bytes to end of "
+        "part: %u)", to_read, src->cur_part, (guint) bytes_to_end_of_part);
+
+    stream = G_INPUT_STREAM (cur_part.stream);
+
+    /* NB: we won't try to read beyond EOF */
+    if (!g_input_stream_read_all (stream, data, to_read, &read, cancel, &err))
+      goto read_failed;
+
+    GST_LOG_OBJECT (src, "read %u bytes", (guint) read);
+
+    data += read;
+    size -= read;
+    offset += read;
+
+    /* are we done? */
+    if (size == 0)
+      break;
+
+    GST_LOG_OBJECT (src, "%u bytes left to read for this chunk", size);
+
+    /* corner case, this should never really happen (assuming basesrc clips
+     * requests beyond the file size) */
+    if (read < to_read) {
+      if (src->cur_part == src->num_parts - 1) {
+        /* last file part, stop reading and truncate buffer */
+        gst_buffer_set_size (buf, offset - GST_BUFFER_OFFSET (buf));
+        break;
+      } else {
+        goto file_part_changed;
+      }
+    }
+
+    ++src->cur_part;
+    cur_part = src->parts[src->cur_part];
+  }
+
+  GST_BUFFER_OFFSET_END (buf) = offset;
+
+  gst_buffer_unmap (buf, &map);
+
+  *buffer = buf;
+  GST_LOG_OBJECT (src, "read %" G_GSIZE_FORMAT " bytes into buf %p",
+      gst_buffer_get_size (buf), buf);
+  return GST_FLOW_OK;
+
+/* ERRORS */
+seek_failed:
+  {
+    if (err->code == G_IO_ERROR_CANCELLED)
+      goto cancelled;
+
+    GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (NULL),
+        ("Seek to %" G_GUINT64_FORMAT " in %s failed", read_offset,
+            cur_part.path));
+    g_error_free (err);
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+read_failed:
+  {
+    if (err->code == G_IO_ERROR_CANCELLED)
+      goto cancelled;
+
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, ("%s", err->message),
+        ("Read from %" G_GUINT64_FORMAT " in %s failed", read_offset,
+            cur_part.path));
+    g_error_free (err);
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+file_part_changed:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, READ,
+        ("Read error while reading file part %s", cur_part.path),
+        ("Short read in file part, file may have been modified since start"));
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+cancelled:
+  {
+    GST_DEBUG_OBJECT (src, "I/O operation cancelled from another thread");
+    g_error_free (err);
+    gst_buffer_unref (buf);
+    return GST_FLOW_FLUSHING;
+  }
+}
+
+static GstURIType
+gst_split_file_src_uri_get_type (GType type)
+{
+  return GST_URI_SRC;
+}
+
+static const gchar *const *
+gst_split_file_src_uri_get_protocols (GType type)
+{
+  static const gchar *protocols[] = { "splitfile", NULL };
+
+  return (const gchar * const *) protocols;
+}
+
+static gchar *
+gst_split_file_src_uri_get_uri (GstURIHandler * handler)
+{
+  GstSplitFileSrc *src = GST_SPLIT_FILE_SRC (handler);
+  gchar *ret;
+
+  GST_OBJECT_LOCK (src);
+  if (src->location != NULL)
+    ret = g_strdup_printf ("splitfile://%s", src->location);
+  else
+    ret = NULL;
+  GST_OBJECT_UNLOCK (src);
+
+  return ret;
+}
+
+static gboolean
+gst_split_file_src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+    GError ** error)
+{
+  GstSplitFileSrc *src = GST_SPLIT_FILE_SRC (handler);
+
+  gst_split_file_src_set_location (src, uri);
+
+  return TRUE;
+}
+
+static void
+gst_split_file_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+  iface->get_type = gst_split_file_src_uri_get_type;
+  iface->get_protocols = gst_split_file_src_uri_get_protocols;
+  iface->get_uri = gst_split_file_src_uri_get_uri;
+  iface->set_uri = gst_split_file_src_uri_set_uri;
+}
diff --git a/gst/multifile/gstsplitfilesrc.h b/gst/multifile/gstsplitfilesrc.h
new file mode 100644
index 0000000..80abdd3
--- /dev/null
+++ b/gst/multifile/gstsplitfilesrc.h
@@ -0,0 +1,74 @@
+/* GStreamer Split File Source
+ * Copyright (C) 2011 Collabora Ltd. <tim.muller@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef __GST_SPLIT_FILE_SRC_H__
+#define __GST_SPLIT_FILE_SRC_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesrc.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SPLIT_FILE_SRC \
+  (gst_split_file_src_get_type())
+#define GST_SPLIT_FILE_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPLIT_FILE_SRC,GstSplitFileSrc))
+#define GST_SPLIT_FILE_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPLIT_FILE_SRC,GstSplitFileSrcClass))
+#define GST_IS_SPLIT_FILE_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPLIT_FILE_SRC))
+#define GST_IS_SPLIT_FILE_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPLIT_FILE_SRC))
+
+typedef struct _GstFilePart GstFilePart;
+typedef struct _GstSplitFileSrc GstSplitFileSrc;
+typedef struct _GstSplitFileSrcClass GstSplitFileSrcClass;
+
+struct _GstFilePart
+{
+  GFileInputStream  *stream;
+  gchar             *path;
+  guint64            start; /* inclusive */
+  guint64            stop;  /* inclusive */
+};
+
+struct _GstSplitFileSrc
+{
+  GstBaseSrc   parent;
+
+  gchar       *location;  /* OBJECT_LOCK */
+
+  GstFilePart *parts;
+  guint        num_parts;
+
+  guint        cur_part;  /* part used last (likely also to be used next) */
+
+  GCancellable *cancellable; /* so we can interrupt blocking operations */
+};
+
+struct _GstSplitFileSrcClass
+{
+  GstBaseSrcClass parent_class;
+};
+
+GType gst_split_file_src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_SPLIT_FILE_SRC_H__ */
diff --git a/gst/multifile/gstsplitmuxpartreader.c b/gst/multifile/gstsplitmuxpartreader.c
new file mode 100644
index 0000000..75171cb
--- /dev/null
+++ b/gst/multifile/gstsplitmuxpartreader.c
@@ -0,0 +1,1370 @@
+/* GStreamer Split Demuxer bin that recombines files created by
+ * the splitmuxsink element.
+ *
+ * Copyright (C) <2014> Jan Schmidt <jan@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include "gstsplitmuxsrc.h"
+
+GST_DEBUG_CATEGORY_STATIC (splitmux_part_debug);
+#define GST_CAT_DEFAULT splitmux_part_debug
+
+#define SPLITMUX_PART_LOCK(p) g_mutex_lock(&(p)->lock)
+#define SPLITMUX_PART_UNLOCK(p) g_mutex_unlock(&(p)->lock)
+#define SPLITMUX_PART_WAIT(p) g_cond_wait (&(p)->inactive_cond, &(p)->lock)
+#define SPLITMUX_PART_BROADCAST(p) g_cond_broadcast (&(p)->inactive_cond)
+
+#define SPLITMUX_PART_TYPE_LOCK(p) g_mutex_lock(&(p)->type_lock)
+#define SPLITMUX_PART_TYPE_UNLOCK(p) g_mutex_unlock(&(p)->type_lock)
+
+enum
+{
+  SIGNAL_PREPARED,
+  LAST_SIGNAL
+};
+
+static guint part_reader_signals[LAST_SIGNAL] = { 0 };
+
+typedef struct _GstSplitMuxPartPad
+{
+  GstPad parent;
+
+  /* Reader we belong to */
+  GstSplitMuxPartReader *reader;
+  /* Output splitmuxsrc source pad */
+  GstPad *target;
+
+  GstDataQueue *queue;
+
+  gboolean is_eos;
+  gboolean flushing;
+  gboolean seen_buffer;
+
+  gboolean is_sparse;
+  GstClockTime max_ts;
+  GstSegment segment;
+
+  GstSegment orig_segment;
+  GstClockTime initial_ts_offset;
+} GstSplitMuxPartPad;
+
+typedef struct _GstSplitMuxPartPadClass
+{
+  GstPadClass parent;
+} GstSplitMuxPartPadClass;
+
+static GType gst_splitmux_part_pad_get_type (void);
+#define SPLITMUX_TYPE_PART_PAD gst_splitmux_part_pad_get_type()
+#define SPLITMUX_PART_PAD_CAST(p) ((GstSplitMuxPartPad *)(p))
+
+static void splitmux_part_pad_constructed (GObject * pad);
+static void splitmux_part_pad_finalize (GObject * pad);
+static void handle_buffer_measuring (GstSplitMuxPartReader * reader,
+    GstSplitMuxPartPad * part_pad, GstBuffer * buf);
+
+static gboolean splitmux_data_queue_is_full_cb (GstDataQueue * queue,
+    guint visible, guint bytes, guint64 time, gpointer checkdata);
+static void type_found (GstElement * typefind, guint probability,
+    GstCaps * caps, GstSplitMuxPartReader * reader);
+static void check_if_pads_collected (GstSplitMuxPartReader * reader);
+
+/* Called with reader lock held */
+static gboolean
+have_empty_queue (GstSplitMuxPartReader * reader)
+{
+  GList *cur;
+
+  for (cur = g_list_first (reader->pads); cur != NULL; cur = g_list_next (cur)) {
+    GstSplitMuxPartPad *part_pad = SPLITMUX_PART_PAD_CAST (cur->data);
+    if (part_pad->is_eos) {
+      GST_LOG_OBJECT (part_pad, "Pad is EOS");
+      return TRUE;
+    }
+    if (gst_data_queue_is_empty (part_pad->queue)) {
+      GST_LOG_OBJECT (part_pad, "Queue is empty");
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/* Called with reader lock held */
+static gboolean
+block_until_can_push (GstSplitMuxPartReader * reader)
+{
+  while (reader->running) {
+    if (reader->flushing)
+      goto out;
+    if (reader->active && have_empty_queue (reader))
+      goto out;
+
+    GST_LOG_OBJECT (reader,
+        "Waiting for activation or empty queue on reader %s", reader->path);
+    SPLITMUX_PART_WAIT (reader);
+  }
+
+  GST_LOG_OBJECT (reader, "Done waiting on reader %s active %d flushing %d",
+      reader->path, reader->active, reader->flushing);
+out:
+  return reader->active && !reader->flushing;
+}
+
+static void
+handle_buffer_measuring (GstSplitMuxPartReader * reader,
+    GstSplitMuxPartPad * part_pad, GstBuffer * buf)
+{
+  GstClockTimeDiff ts = GST_CLOCK_STIME_NONE;
+  GstClockTimeDiff offset;
+
+  if (reader->prep_state == PART_STATE_PREPARING_COLLECT_STREAMS &&
+      !part_pad->seen_buffer) {
+    /* If this is the first buffer on the pad in the collect_streams state,
+     * then calculate inital offset based on running time of this segment */
+    part_pad->initial_ts_offset =
+        part_pad->orig_segment.start + part_pad->orig_segment.base -
+        part_pad->orig_segment.time;
+    GST_DEBUG_OBJECT (reader,
+        "Initial TS offset for pad %" GST_PTR_FORMAT " now %" GST_TIME_FORMAT,
+        part_pad, GST_TIME_ARGS (part_pad->initial_ts_offset));
+  }
+  part_pad->seen_buffer = TRUE;
+
+  /* Adjust buffer timestamps */
+  offset = reader->start_offset + part_pad->segment.base;
+  offset -= part_pad->initial_ts_offset;
+
+  /* Update the stored max duration on the pad,
+   * always preferring making DTS contiguous
+   * where possible */
+  if (GST_BUFFER_DTS_IS_VALID (buf))
+    ts = GST_BUFFER_DTS (buf) + offset;
+  else if (GST_BUFFER_PTS_IS_VALID (buf))
+    ts = GST_BUFFER_PTS (buf) + offset;
+
+  GST_DEBUG_OBJECT (reader, "Pad %" GST_PTR_FORMAT
+      " incoming PTS %" GST_TIME_FORMAT
+      " DTS %" GST_TIME_FORMAT " offset by %" GST_STIME_FORMAT
+      " to %" GST_STIME_FORMAT, part_pad,
+      GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
+      GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
+      GST_STIME_ARGS (offset), GST_STIME_ARGS (ts));
+
+  if (GST_CLOCK_STIME_IS_VALID (ts)) {
+    if (GST_BUFFER_DURATION_IS_VALID (buf))
+      ts += GST_BUFFER_DURATION (buf);
+
+    if (GST_CLOCK_STIME_IS_VALID (ts)
+        && ts > (GstClockTimeDiff) part_pad->max_ts) {
+      part_pad->max_ts = ts;
+      GST_LOG_OBJECT (reader,
+          "pad %" GST_PTR_FORMAT " max TS now %" GST_TIME_FORMAT, part_pad,
+          GST_TIME_ARGS (part_pad->max_ts));
+    }
+  }
+  /* Is it time to move to measuring state yet? */
+  check_if_pads_collected (reader);
+}
+
+static gboolean
+splitmux_data_queue_is_full_cb (GstDataQueue * queue,
+    guint visible, guint bytes, guint64 time, gpointer checkdata)
+{
+  /* Arbitrary safety limit. If we hit it, playback is likely to stall */
+  if (time > 20 * GST_SECOND)
+    return TRUE;
+  return FALSE;
+}
+
+static void
+splitmux_part_free_queue_item (GstDataQueueItem * item)
+{
+  gst_mini_object_unref (item->object);
+  g_slice_free (GstDataQueueItem, item);
+}
+
+static GstFlowReturn
+splitmux_part_pad_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstSplitMuxPartPad *part_pad = SPLITMUX_PART_PAD_CAST (pad);
+  GstSplitMuxPartReader *reader = part_pad->reader;
+  GstDataQueueItem *item;
+  GstClockTimeDiff offset;
+
+  GST_LOG_OBJECT (reader, "Pad %" GST_PTR_FORMAT " %" GST_PTR_FORMAT, pad, buf);
+  SPLITMUX_PART_LOCK (reader);
+
+  if (reader->prep_state == PART_STATE_PREPARING_COLLECT_STREAMS ||
+      reader->prep_state == PART_STATE_PREPARING_MEASURE_STREAMS) {
+    handle_buffer_measuring (reader, part_pad, buf);
+    gst_buffer_unref (buf);
+    SPLITMUX_PART_UNLOCK (reader);
+    return GST_FLOW_OK;
+  }
+
+  if (!block_until_can_push (reader)) {
+    /* Flushing */
+    SPLITMUX_PART_UNLOCK (reader);
+    gst_buffer_unref (buf);
+    return GST_FLOW_FLUSHING;
+  }
+
+  /* Adjust buffer timestamps */
+  offset = reader->start_offset + part_pad->segment.base;
+  offset -= part_pad->initial_ts_offset;
+
+  if (GST_BUFFER_PTS_IS_VALID (buf))
+    GST_BUFFER_PTS (buf) += offset;
+  if (GST_BUFFER_DTS_IS_VALID (buf))
+    GST_BUFFER_DTS (buf) += offset;
+
+  /* We are active, and one queue is empty, place this buffer in
+   * the dataqueue */
+  GST_LOG_OBJECT (reader, "Enqueueing buffer %" GST_PTR_FORMAT, buf);
+  item = g_slice_new (GstDataQueueItem);
+  item->destroy = (GDestroyNotify) splitmux_part_free_queue_item;
+  item->object = GST_MINI_OBJECT (buf);
+  item->size = gst_buffer_get_size (buf);
+  item->duration = GST_BUFFER_DURATION (buf);
+  if (item->duration == GST_CLOCK_TIME_NONE)
+    item->duration = 0;
+  item->visible = TRUE;
+
+  gst_object_ref (part_pad);
+
+  SPLITMUX_PART_UNLOCK (reader);
+
+  if (!gst_data_queue_push (part_pad->queue, item)) {
+    splitmux_part_free_queue_item (item);
+    gst_object_unref (part_pad);
+    return GST_FLOW_FLUSHING;
+  }
+
+  gst_object_unref (part_pad);
+  return GST_FLOW_OK;
+}
+
+/* Called with splitmux part lock held */
+static gboolean
+splitmux_part_is_eos_locked (GstSplitMuxPartReader * part)
+{
+  GList *cur;
+  for (cur = g_list_first (part->pads); cur != NULL; cur = g_list_next (cur)) {
+    GstSplitMuxPartPad *part_pad = SPLITMUX_PART_PAD_CAST (cur->data);
+    if (!part_pad->is_eos)
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+splitmux_part_is_prerolled_locked (GstSplitMuxPartReader * part)
+{
+  GList *cur;
+  GST_LOG_OBJECT (part, "Checking for preroll");
+  for (cur = g_list_first (part->pads); cur != NULL; cur = g_list_next (cur)) {
+    GstSplitMuxPartPad *part_pad = SPLITMUX_PART_PAD_CAST (cur->data);
+    if (!part_pad->seen_buffer) {
+      GST_LOG_OBJECT (part, "Part pad %" GST_PTR_FORMAT " is not prerolled",
+          part_pad);
+      return FALSE;
+    }
+  }
+  GST_LOG_OBJECT (part, "Part is prerolled");
+  return TRUE;
+}
+
+
+gboolean
+gst_splitmux_part_is_eos (GstSplitMuxPartReader * reader)
+{
+  gboolean res;
+
+  SPLITMUX_PART_LOCK (reader);
+  res = splitmux_part_is_eos_locked (reader);
+  SPLITMUX_PART_UNLOCK (reader);
+
+  return res;
+}
+
+/* Called with splitmux part lock held */
+static gboolean
+splitmux_is_flushing (GstSplitMuxPartReader * reader)
+{
+  GList *cur;
+  for (cur = g_list_first (reader->pads); cur != NULL; cur = g_list_next (cur)) {
+    GstSplitMuxPartPad *part_pad = SPLITMUX_PART_PAD_CAST (cur->data);
+    if (part_pad->flushing)
+      return TRUE;
+  }
+
+  return FALSE;
+}
+
+static gboolean
+splitmux_part_pad_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstSplitMuxPartPad *part_pad = SPLITMUX_PART_PAD_CAST (pad);
+  GstSplitMuxPartReader *reader = part_pad->reader;
+  gboolean ret = TRUE;
+  SplitMuxSrcPad *target;
+  GstDataQueueItem *item;
+
+  SPLITMUX_PART_LOCK (reader);
+
+  target = gst_object_ref (part_pad->target);
+
+  GST_LOG_OBJECT (reader, "Pad %" GST_PTR_FORMAT " event %" GST_PTR_FORMAT, pad,
+      event);
+
+  if (part_pad->flushing && GST_EVENT_TYPE (event) != GST_EVENT_FLUSH_STOP)
+    goto drop_event;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_STREAM_START:{
+      GstStreamFlags flags;
+      gst_event_parse_stream_flags (event, &flags);
+      part_pad->is_sparse = (flags & GST_STREAM_FLAG_SPARSE);
+      break;
+    }
+    case GST_EVENT_SEGMENT:{
+      GstSegment *seg = &part_pad->segment;
+
+      GST_LOG_OBJECT (pad, "Received segment %" GST_PTR_FORMAT, event);
+
+      gst_event_copy_segment (event, seg);
+      gst_event_copy_segment (event, &part_pad->orig_segment);
+
+      if (seg->format != GST_FORMAT_TIME)
+        goto wrong_segment;
+
+      /* Adjust segment */
+      /* Adjust start/stop so the overall file is 0 + start_offset based */
+      if (seg->stop != -1) {
+        seg->stop -= seg->start;
+        seg->stop += seg->time + reader->start_offset;
+      }
+      seg->start = seg->time + reader->start_offset;
+      seg->time += reader->start_offset;
+      seg->position += reader->start_offset;
+
+      GST_LOG_OBJECT (pad, "Adjusted segment now %" GST_PTR_FORMAT, event);
+
+      /* Replace event */
+      gst_event_unref (event);
+      event = gst_event_new_segment (seg);
+
+      if (reader->prep_state != PART_STATE_PREPARING_COLLECT_STREAMS
+          && reader->prep_state != PART_STATE_PREPARING_MEASURE_STREAMS)
+        break;                  /* Only do further stuff with segments during initial measuring */
+
+      /* Take the first segment from the first part */
+      if (target->segment.format == GST_FORMAT_UNDEFINED) {
+        gst_segment_copy_into (seg, &target->segment);
+        GST_DEBUG_OBJECT (reader,
+            "Target pad segment now %" GST_SEGMENT_FORMAT, &target->segment);
+      }
+
+      if (seg->stop != -1 && target->segment.stop != -1) {
+        GstClockTime stop = seg->base + seg->stop;
+        if (stop > target->segment.stop) {
+          target->segment.stop = stop;
+          GST_DEBUG_OBJECT (reader,
+              "Adjusting segment stop by %" GST_TIME_FORMAT
+              " output now %" GST_SEGMENT_FORMAT,
+              GST_TIME_ARGS (reader->start_offset), &target->segment);
+        }
+      }
+      GST_LOG_OBJECT (pad, "Forwarding segment %" GST_PTR_FORMAT, event);
+      break;
+    }
+    case GST_EVENT_EOS:{
+
+      GST_DEBUG_OBJECT (part_pad,
+          "State %u EOS event. MaxTS seen %" GST_TIME_FORMAT,
+          reader->prep_state, GST_TIME_ARGS (part_pad->max_ts));
+
+      if (reader->prep_state == PART_STATE_PREPARING_COLLECT_STREAMS ||
+          reader->prep_state == PART_STATE_PREPARING_MEASURE_STREAMS) {
+        /* Mark this pad as EOS */
+        part_pad->is_eos = TRUE;
+        if (splitmux_part_is_eos_locked (reader)) {
+          /* Finished measuring things, set state and tell the state change func
+           * so it can seek back to the start */
+          GST_LOG_OBJECT (reader,
+              "EOS while measuring streams. Resetting for ready");
+          reader->prep_state = PART_STATE_PREPARING_RESET_FOR_READY;
+          SPLITMUX_PART_BROADCAST (reader);
+        }
+        goto drop_event;
+      }
+      break;
+    }
+    case GST_EVENT_FLUSH_START:
+      reader->flushing = TRUE;
+      part_pad->flushing = TRUE;
+      GST_LOG_OBJECT (reader, "Pad %" GST_PTR_FORMAT " flushing dataqueue",
+          part_pad);
+      gst_data_queue_set_flushing (part_pad->queue, TRUE);
+      SPLITMUX_PART_BROADCAST (reader);
+      break;
+    case GST_EVENT_FLUSH_STOP:{
+      gst_data_queue_set_flushing (part_pad->queue, FALSE);
+      gst_data_queue_flush (part_pad->queue);
+      part_pad->seen_buffer = FALSE;
+      part_pad->flushing = FALSE;
+      part_pad->is_eos = FALSE;
+
+      reader->flushing = splitmux_is_flushing (reader);
+      GST_LOG_OBJECT (reader,
+          "%s pad %" GST_PTR_FORMAT " flush_stop. Overall flushing=%d",
+          reader->path, pad, reader->flushing);
+      SPLITMUX_PART_BROADCAST (reader);
+      break;
+    }
+    default:
+      break;
+  }
+
+  /* Don't send events downstream while preparing */
+  if (reader->prep_state != PART_STATE_READY)
+    goto drop_event;
+
+  /* Don't pass flush events - those are done by the parent */
+  if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_START ||
+      GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP)
+    goto drop_event;
+
+  if (!block_until_can_push (reader))
+    goto drop_event;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_GAP:{
+      /* FIXME: Drop initial gap (if any) in each segment, not all GAPs */
+      goto drop_event;
+    }
+    default:
+      break;
+  }
+
+  /* We are active, and one queue is empty, place this buffer in
+   * the dataqueue */
+  gst_object_ref (part_pad->queue);
+  SPLITMUX_PART_UNLOCK (reader);
+
+  GST_LOG_OBJECT (reader, "Enqueueing event %" GST_PTR_FORMAT, event);
+  item = g_slice_new (GstDataQueueItem);
+  item->destroy = (GDestroyNotify) splitmux_part_free_queue_item;
+  item->object = GST_MINI_OBJECT (event);
+  item->size = 0;
+  item->duration = 0;
+  if (item->duration == GST_CLOCK_TIME_NONE)
+    item->duration = 0;
+  item->visible = FALSE;
+
+  if (!gst_data_queue_push (part_pad->queue, item)) {
+    splitmux_part_free_queue_item (item);
+    ret = FALSE;
+  }
+
+  gst_object_unref (part_pad->queue);
+  gst_object_unref (target);
+
+  return ret;
+wrong_segment:
+  gst_event_unref (event);
+  gst_object_unref (target);
+  SPLITMUX_PART_UNLOCK (reader);
+  GST_ELEMENT_ERROR (reader, STREAM, FAILED, (NULL),
+      ("Received non-time segment - reader %s pad %" GST_PTR_FORMAT,
+          reader->path, pad));
+  return FALSE;
+drop_event:
+  GST_LOG_OBJECT (pad, "Dropping event %" GST_PTR_FORMAT
+      " from %" GST_PTR_FORMAT " on %" GST_PTR_FORMAT, event, pad, target);
+  gst_event_unref (event);
+  gst_object_unref (target);
+  SPLITMUX_PART_UNLOCK (reader);
+  return TRUE;
+}
+
+static gboolean
+splitmux_part_pad_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  GstSplitMuxPartPad *part_pad = SPLITMUX_PART_PAD_CAST (pad);
+  GstSplitMuxPartReader *reader = part_pad->reader;
+  GstPad *target;
+  gboolean ret = FALSE;
+  gboolean active;
+
+  SPLITMUX_PART_LOCK (reader);
+  target = gst_object_ref (part_pad->target);
+  active = reader->active;
+  SPLITMUX_PART_UNLOCK (reader);
+
+  if (active) {
+    GST_LOG_OBJECT (pad, "Forwarding query %" GST_PTR_FORMAT
+        " from %" GST_PTR_FORMAT " on %" GST_PTR_FORMAT, query, pad, target);
+
+    ret = gst_pad_query (target, query);
+  }
+
+  gst_object_unref (target);
+
+  return ret;
+}
+
+G_DEFINE_TYPE (GstSplitMuxPartPad, gst_splitmux_part_pad, GST_TYPE_PAD);
+
+static void
+splitmux_part_pad_constructed (GObject * pad)
+{
+  gst_pad_set_chain_function (GST_PAD (pad),
+      GST_DEBUG_FUNCPTR (splitmux_part_pad_chain));
+  gst_pad_set_event_function (GST_PAD (pad),
+      GST_DEBUG_FUNCPTR (splitmux_part_pad_event));
+  gst_pad_set_query_function (GST_PAD (pad),
+      GST_DEBUG_FUNCPTR (splitmux_part_pad_query));
+
+  G_OBJECT_CLASS (gst_splitmux_part_pad_parent_class)->constructed (pad);
+}
+
+static void
+gst_splitmux_part_pad_class_init (GstSplitMuxPartPadClass * klass)
+{
+  GObjectClass *gobject_klass = (GObjectClass *) (klass);
+
+  gobject_klass->constructed = splitmux_part_pad_constructed;
+  gobject_klass->finalize = splitmux_part_pad_finalize;
+}
+
+static void
+gst_splitmux_part_pad_init (GstSplitMuxPartPad * pad)
+{
+  pad->queue = gst_data_queue_new (splitmux_data_queue_is_full_cb,
+      NULL, NULL, pad);
+  gst_segment_init (&pad->segment, GST_FORMAT_UNDEFINED);
+  gst_segment_init (&pad->orig_segment, GST_FORMAT_UNDEFINED);
+}
+
+static void
+splitmux_part_pad_finalize (GObject * obj)
+{
+  GstSplitMuxPartPad *pad = (GstSplitMuxPartPad *) (obj);
+
+  GST_DEBUG_OBJECT (obj, "finalize");
+  gst_data_queue_set_flushing (pad->queue, TRUE);
+  gst_data_queue_flush (pad->queue);
+  gst_object_unref (GST_OBJECT_CAST (pad->queue));
+  pad->queue = NULL;
+
+  G_OBJECT_CLASS (gst_splitmux_part_pad_parent_class)->finalize (obj);
+}
+
+static void
+new_decoded_pad_added_cb (GstElement * element, GstPad * pad,
+    GstSplitMuxPartReader * part);
+static void no_more_pads (GstElement * element, GstSplitMuxPartReader * reader);
+static GstStateChangeReturn
+gst_splitmux_part_reader_change_state (GstElement * element,
+    GstStateChange transition);
+static gboolean gst_splitmux_part_reader_send_event (GstElement * element,
+    GstEvent * event);
+static void gst_splitmux_part_reader_set_flushing_locked (GstSplitMuxPartReader
+    * part, gboolean flushing);
+static void bus_handler (GstBin * bin, GstMessage * msg);
+static void splitmux_part_reader_dispose (GObject * object);
+static void splitmux_part_reader_finalize (GObject * object);
+static void splitmux_part_reader_reset (GstSplitMuxPartReader * reader);
+
+#define gst_splitmux_part_reader_parent_class parent_class
+G_DEFINE_TYPE (GstSplitMuxPartReader, gst_splitmux_part_reader,
+    GST_TYPE_PIPELINE);
+
+static void
+gst_splitmux_part_reader_class_init (GstSplitMuxPartReaderClass * klass)
+{
+  GObjectClass *gobject_klass = (GObjectClass *) (klass);
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBinClass *gstbin_class = (GstBinClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (splitmux_part_debug, "splitmuxpartreader", 0,
+      "Split File Demuxing Source helper");
+
+  gobject_klass->dispose = splitmux_part_reader_dispose;
+  gobject_klass->finalize = splitmux_part_reader_finalize;
+
+  part_reader_signals[SIGNAL_PREPARED] =
+      g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstSplitMuxPartReaderClass,
+          prepared), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+  gstelement_class->change_state = gst_splitmux_part_reader_change_state;
+  gstelement_class->send_event = gst_splitmux_part_reader_send_event;
+
+  gstbin_class->handle_message = bus_handler;
+}
+
+static void
+gst_splitmux_part_reader_init (GstSplitMuxPartReader * reader)
+{
+  GstElement *typefind;
+
+  reader->active = FALSE;
+  reader->duration = GST_CLOCK_TIME_NONE;
+
+  g_cond_init (&reader->inactive_cond);
+  g_mutex_init (&reader->lock);
+  g_mutex_init (&reader->type_lock);
+
+  /* FIXME: Create elements on a state change */
+  reader->src = gst_element_factory_make ("filesrc", NULL);
+  if (reader->src == NULL) {
+    GST_ERROR_OBJECT (reader, "Failed to create filesrc element");
+    return;
+  }
+  gst_bin_add (GST_BIN_CAST (reader), reader->src);
+
+  typefind = gst_element_factory_make ("typefind", NULL);
+  if (!typefind) {
+    GST_ERROR_OBJECT (reader,
+        "Failed to create typefind element - check your installation");
+    return;
+  }
+
+  gst_bin_add (GST_BIN_CAST (reader), typefind);
+  reader->typefind = typefind;
+
+  if (!gst_element_link_pads (reader->src, NULL, typefind, "sink")) {
+    GST_ERROR_OBJECT (reader,
+        "Failed to link typefind element - check your installation");
+    return;
+  }
+
+  g_signal_connect (reader->typefind, "have-type", G_CALLBACK (type_found),
+      reader);
+}
+
+static void
+splitmux_part_reader_dispose (GObject * object)
+{
+  GstSplitMuxPartReader *reader = (GstSplitMuxPartReader *) object;
+
+  splitmux_part_reader_reset (reader);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+splitmux_part_reader_finalize (GObject * object)
+{
+  GstSplitMuxPartReader *reader = (GstSplitMuxPartReader *) object;
+
+  g_cond_clear (&reader->inactive_cond);
+  g_mutex_clear (&reader->lock);
+  g_mutex_clear (&reader->type_lock);
+
+  g_free (reader->path);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+splitmux_part_reader_reset (GstSplitMuxPartReader * reader)
+{
+  GList *cur;
+
+  SPLITMUX_PART_LOCK (reader);
+  for (cur = g_list_first (reader->pads); cur != NULL; cur = g_list_next (cur)) {
+    GstPad *pad = GST_PAD_CAST (cur->data);
+    gst_pad_set_active (GST_PAD_CAST (pad), FALSE);
+    gst_object_unref (GST_OBJECT_CAST (pad));
+  }
+
+  g_list_free (reader->pads);
+  reader->pads = NULL;
+  SPLITMUX_PART_UNLOCK (reader);
+}
+
+static GstSplitMuxPartPad *
+gst_splitmux_part_reader_new_proxy_pad (GstSplitMuxPartReader * reader,
+    GstPad * target)
+{
+  GstSplitMuxPartPad *pad = g_object_new (SPLITMUX_TYPE_PART_PAD,
+      "name", GST_PAD_NAME (target),
+      "direction", GST_PAD_SINK,
+      NULL);
+  pad->target = target;
+  pad->reader = reader;
+
+  gst_pad_set_active (GST_PAD_CAST (pad), TRUE);
+
+  return pad;
+}
+
+static void
+new_decoded_pad_added_cb (GstElement * element, GstPad * pad,
+    GstSplitMuxPartReader * reader)
+{
+  GstPad *out_pad = NULL;
+  GstSplitMuxPartPad *proxy_pad;
+  GstCaps *caps;
+  GstPadLinkReturn link_ret;
+
+  caps = gst_pad_get_current_caps (pad);
+
+  GST_DEBUG_OBJECT (reader, "file %s new decoded pad %" GST_PTR_FORMAT
+      " caps %" GST_PTR_FORMAT, reader->path, pad, caps);
+
+  gst_caps_unref (caps);
+
+  /* Look up or create the output pad */
+  if (reader->get_pad_cb)
+    out_pad = reader->get_pad_cb (reader, pad, reader->cb_data);
+  if (out_pad == NULL) {
+    GST_DEBUG_OBJECT (reader,
+        "No output pad for %" GST_PTR_FORMAT ". Ignoring", pad);
+    return;
+  }
+
+  /* Create our proxy pad to interact with this new pad */
+  proxy_pad = gst_splitmux_part_reader_new_proxy_pad (reader, out_pad);
+  GST_DEBUG_OBJECT (reader,
+      "created proxy pad %" GST_PTR_FORMAT " for target %" GST_PTR_FORMAT,
+      proxy_pad, out_pad);
+
+  link_ret = gst_pad_link (pad, GST_PAD (proxy_pad));
+  if (link_ret != GST_PAD_LINK_OK) {
+    gst_object_unref (proxy_pad);
+    GST_ELEMENT_ERROR (reader, STREAM, FAILED, (NULL),
+        ("Failed to link proxy pad for stream part %s pad %" GST_PTR_FORMAT
+            " ret %d", reader->path, pad, link_ret));
+    return;
+  }
+  GST_DEBUG_OBJECT (reader,
+      "new decoded pad %" GST_PTR_FORMAT " linked to %" GST_PTR_FORMAT,
+      pad, proxy_pad);
+
+  SPLITMUX_PART_LOCK (reader);
+  reader->pads = g_list_prepend (reader->pads, proxy_pad);
+  SPLITMUX_PART_UNLOCK (reader);
+}
+
+static gboolean
+gst_splitmux_part_reader_send_event (GstElement * element, GstEvent * event)
+{
+  GstSplitMuxPartReader *reader = (GstSplitMuxPartReader *) element;
+  gboolean ret = FALSE;
+  GstPad *pad = NULL;
+
+  /* Send event to the first source pad we found */
+  SPLITMUX_PART_LOCK (reader);
+  if (reader->pads) {
+    GstPad *proxy_pad = GST_PAD_CAST (reader->pads->data);
+    pad = gst_pad_get_peer (proxy_pad);
+  }
+  SPLITMUX_PART_UNLOCK (reader);
+
+  if (pad) {
+    ret = gst_pad_send_event (pad, event);
+    gst_object_unref (pad);
+  } else {
+    gst_event_unref (event);
+  }
+
+  return ret;
+}
+
+/* Called with lock held. Seeks to an 'internal' time from 0 to length of this piece */
+static void
+gst_splitmux_part_reader_seek_to_time_locked (GstSplitMuxPartReader * reader,
+    GstClockTime time)
+{
+  SPLITMUX_PART_UNLOCK (reader);
+  GST_DEBUG_OBJECT (reader, "Seeking to time %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (time));
+  gst_element_seek (GST_ELEMENT_CAST (reader), 1.0, GST_FORMAT_TIME,
+      GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, time,
+      GST_SEEK_TYPE_END, 0);
+
+  SPLITMUX_PART_LOCK (reader);
+
+  /* Wait for flush to finish, so old data is gone */
+  while (reader->flushing) {
+    GST_LOG_OBJECT (reader, "%s Waiting for flush to finish", reader->path);
+    SPLITMUX_PART_WAIT (reader);
+  }
+}
+
+/* Map the passed segment to 'internal' time from 0 to length of this piece and seek. Lock cannot be held */
+static gboolean
+gst_splitmux_part_reader_seek_to_segment (GstSplitMuxPartReader * reader,
+    GstSegment * target_seg, GstSeekFlags extra_flags)
+{
+  GstSeekFlags flags;
+  GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
+
+  flags = target_seg->flags | GST_SEEK_FLAG_FLUSH | extra_flags;
+
+  SPLITMUX_PART_LOCK (reader);
+  if (target_seg->start >= reader->start_offset)
+    start = target_seg->start - reader->start_offset;
+  /* If the segment stop is within this part, don't play to the end */
+  if (target_seg->stop != -1 &&
+      target_seg->stop < reader->start_offset + reader->duration)
+    stop = target_seg->stop - reader->start_offset;
+
+  SPLITMUX_PART_UNLOCK (reader);
+
+  GST_DEBUG_OBJECT (reader,
+      "Seeking rate %f format %d flags 0x%x start %" GST_TIME_FORMAT " stop %"
+      GST_TIME_FORMAT, target_seg->rate, target_seg->format, flags,
+      GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
+
+  return gst_element_seek (GST_ELEMENT_CAST (reader), target_seg->rate,
+      target_seg->format, flags, GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_SET,
+      stop);
+}
+
+/* Called with lock held */
+static void
+gst_splitmux_part_reader_measure_streams (GstSplitMuxPartReader * reader)
+{
+  /* Trigger a flushing seek to near the end of the file and run each stream
+   * to EOS in order to find the smallest end timestamp to start the next
+   * file from
+   */
+  if (GST_CLOCK_TIME_IS_VALID (reader->duration)
+      && reader->duration > GST_SECOND) {
+    GstClockTime seek_ts = reader->duration - (0.5 * GST_SECOND);
+    gst_splitmux_part_reader_seek_to_time_locked (reader, seek_ts);
+  }
+
+  /* Wait for things to happen */
+  while (reader->prep_state == PART_STATE_PREPARING_MEASURE_STREAMS)
+    SPLITMUX_PART_WAIT (reader);
+
+  if (reader->prep_state == PART_STATE_PREPARING_RESET_FOR_READY) {
+    /* Fire the prepared signal and go to READY state */
+    GST_DEBUG_OBJECT (reader,
+        "Stream measuring complete. File %s is now ready. Firing prepared signal",
+        reader->path);
+    reader->prep_state = PART_STATE_READY;
+    g_signal_emit (reader, part_reader_signals[SIGNAL_PREPARED], 0, NULL);
+  }
+}
+
+static GstElement *
+find_demuxer (GstCaps * caps)
+{
+  GList *factories =
+      gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_DEMUXER,
+      GST_RANK_MARGINAL);
+  GList *compat_elements;
+  GstElement *e = NULL;
+
+  if (factories == NULL)
+    return NULL;
+
+  compat_elements =
+      gst_element_factory_list_filter (factories, caps, GST_PAD_SINK, TRUE);
+
+  if (compat_elements) {
+    /* Just take the first (highest ranked) option */
+    GstElementFactory *factory =
+        GST_ELEMENT_FACTORY_CAST (compat_elements->data);
+    e = gst_element_factory_create (factory, NULL);
+    gst_plugin_feature_list_free (compat_elements);
+  }
+
+  if (factories)
+    gst_plugin_feature_list_free (factories);
+
+  return e;
+}
+
+static void
+type_found (GstElement * typefind, guint probability,
+    GstCaps * caps, GstSplitMuxPartReader * reader)
+{
+  GstElement *demux;
+
+  GST_INFO_OBJECT (reader, "Got type %" GST_PTR_FORMAT, caps);
+
+  /* typefind found a type. Look for the demuxer to handle it */
+  demux = reader->demux = find_demuxer (caps);
+  if (reader->demux == NULL) {
+    GST_ERROR_OBJECT (reader, "Failed to create demuxer element");
+    return;
+  }
+
+  /* Connect to demux signals */
+  g_signal_connect (demux,
+      "pad-added", G_CALLBACK (new_decoded_pad_added_cb), reader);
+  g_signal_connect (demux, "no-more-pads", G_CALLBACK (no_more_pads), reader);
+
+  gst_element_set_locked_state (demux, TRUE);
+  gst_bin_add (GST_BIN_CAST (reader), demux);
+  gst_element_link_pads (reader->typefind, "src", demux, NULL);
+  gst_element_set_state (reader->demux, GST_STATE_TARGET (reader));
+  gst_element_set_locked_state (demux, FALSE);
+}
+
+static void
+check_if_pads_collected (GstSplitMuxPartReader * reader)
+{
+  if (reader->prep_state == PART_STATE_PREPARING_COLLECT_STREAMS) {
+    /* Check we have all pads and each pad has seen a buffer */
+    if (reader->no_more_pads && splitmux_part_is_prerolled_locked (reader)) {
+      GST_DEBUG_OBJECT (reader,
+          "no more pads - file %s. Measuring stream length", reader->path);
+      reader->prep_state = PART_STATE_PREPARING_MEASURE_STREAMS;
+      SPLITMUX_PART_BROADCAST (reader);
+    }
+  }
+}
+
+static void
+no_more_pads (GstElement * element, GstSplitMuxPartReader * reader)
+{
+  GstClockTime duration = GST_CLOCK_TIME_NONE;
+  GList *cur;
+  /* Query the minimum duration of any pad in this piece and store it.
+   * FIXME: Only consider audio and video */
+  SPLITMUX_PART_LOCK (reader);
+  for (cur = g_list_first (reader->pads); cur != NULL; cur = g_list_next (cur)) {
+    GstPad *target = GST_PAD_CAST (cur->data);
+    if (target) {
+      gint64 cur_duration;
+      if (gst_pad_peer_query_duration (target, GST_FORMAT_TIME, &cur_duration)) {
+        GST_INFO_OBJECT (reader,
+            "file %s pad %" GST_PTR_FORMAT " duration %" GST_TIME_FORMAT,
+            reader->path, target, GST_TIME_ARGS (cur_duration));
+        if (cur_duration < duration)
+          duration = cur_duration;
+      }
+    }
+  }
+  GST_INFO_OBJECT (reader, "file %s duration %" GST_TIME_FORMAT,
+      reader->path, GST_TIME_ARGS (duration));
+  reader->duration = (GstClockTime) duration;
+
+  reader->no_more_pads = TRUE;
+
+  check_if_pads_collected (reader);
+  SPLITMUX_PART_UNLOCK (reader);
+}
+
+gboolean
+gst_splitmux_part_reader_src_query (GstSplitMuxPartReader * part,
+    GstPad * src_pad, GstQuery * query)
+{
+  GstPad *target = NULL;
+  gboolean ret;
+  GList *cur;
+
+  SPLITMUX_PART_LOCK (part);
+  /* Find the pad corresponding to the visible output target pad */
+  for (cur = g_list_first (part->pads); cur != NULL; cur = g_list_next (cur)) {
+    GstSplitMuxPartPad *part_pad = SPLITMUX_PART_PAD_CAST (cur->data);
+    if (part_pad->target == src_pad) {
+      target = gst_object_ref (GST_OBJECT_CAST (part_pad));
+      break;
+    }
+  }
+  SPLITMUX_PART_UNLOCK (part);
+
+  if (target == NULL)
+    return FALSE;
+
+  ret = gst_pad_peer_query (target, query);
+
+  if (ret == FALSE)
+    goto out;
+
+  /* Post-massaging of queries */
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:{
+      GstFormat fmt;
+      gint64 position;
+
+      gst_query_parse_position (query, &fmt, &position);
+      if (fmt != GST_FORMAT_TIME)
+        return FALSE;
+      SPLITMUX_PART_LOCK (part);
+      position += part->start_offset;
+      GST_LOG_OBJECT (part, "Position %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (position));
+      SPLITMUX_PART_UNLOCK (part);
+
+      gst_query_set_position (query, fmt, position);
+      break;
+    }
+    default:
+      break;
+  }
+
+out:
+  gst_object_unref (target);
+  return ret;
+}
+
+static GstStateChangeReturn
+gst_splitmux_part_reader_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstSplitMuxPartReader *reader = (GstSplitMuxPartReader *) element;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:{
+      break;
+    }
+    case GST_STATE_CHANGE_READY_TO_PAUSED:{
+      /* Hold the splitmux type lock until after the
+       * parent state change function has finished
+       * changing the states of things, and type finding can continue */
+      SPLITMUX_PART_LOCK (reader);
+      g_object_set (reader->src, "location", reader->path, NULL);
+      reader->prep_state = PART_STATE_PREPARING_COLLECT_STREAMS;
+      gst_splitmux_part_reader_set_flushing_locked (reader, FALSE);
+      reader->running = TRUE;
+      SPLITMUX_PART_UNLOCK (reader);
+      SPLITMUX_PART_TYPE_LOCK (reader);
+      break;
+    }
+    case GST_STATE_CHANGE_READY_TO_NULL:
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      SPLITMUX_PART_LOCK (reader);
+      gst_splitmux_part_reader_set_flushing_locked (reader, TRUE);
+      reader->running = FALSE;
+      SPLITMUX_PART_BROADCAST (reader);
+      SPLITMUX_PART_UNLOCK (reader);
+      break;
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      SPLITMUX_PART_LOCK (reader);
+      reader->active = FALSE;
+      gst_splitmux_part_reader_set_flushing_locked (reader, TRUE);
+      SPLITMUX_PART_BROADCAST (reader);
+      SPLITMUX_PART_UNLOCK (reader);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE) {
+    if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
+      /* Make sure to release the lock we took above */
+      SPLITMUX_PART_TYPE_UNLOCK (reader);
+    }
+    goto beach;
+  }
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      /* Sleep and wait until all streams have been collected, then do the seeks
+       * to measure the stream lengths. This took the type lock above,
+       * but it's OK to release it now and let typefinding happen... */
+      SPLITMUX_PART_TYPE_UNLOCK (reader);
+
+      SPLITMUX_PART_LOCK (reader);
+
+      while (reader->prep_state == PART_STATE_PREPARING_COLLECT_STREAMS) {
+        GST_LOG_OBJECT (reader, "Waiting to collect all output streams");
+        SPLITMUX_PART_WAIT (reader);
+      }
+
+      if (reader->prep_state == PART_STATE_PREPARING_MEASURE_STREAMS ||
+          reader->prep_state == PART_STATE_PREPARING_RESET_FOR_READY) {
+        gst_splitmux_part_reader_measure_streams (reader);
+      } else if (reader->prep_state == PART_STATE_FAILED)
+        ret = GST_STATE_CHANGE_FAILURE;
+      SPLITMUX_PART_UNLOCK (reader);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      SPLITMUX_PART_LOCK (reader);
+      gst_splitmux_part_reader_set_flushing_locked (reader, FALSE);
+      reader->active = TRUE;
+      SPLITMUX_PART_BROADCAST (reader);
+      SPLITMUX_PART_UNLOCK (reader);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      reader->prep_state = PART_STATE_NULL;
+      splitmux_part_reader_reset (reader);
+      break;
+    default:
+      break;
+  }
+
+beach:
+  return ret;
+}
+
+static gboolean
+check_bus_messages (GstSplitMuxPartReader * part)
+{
+  gboolean ret = FALSE;
+  GstBus *bus;
+  GstMessage *m;
+
+  bus = gst_element_get_bus (GST_ELEMENT_CAST (part));
+  while ((m = gst_bus_pop (bus)) != NULL) {
+    if (GST_MESSAGE_TYPE (m) == GST_MESSAGE_ERROR) {
+      GST_LOG_OBJECT (part, "Got error message while preparing. Failing.");
+      gst_message_unref (m);
+      goto done;
+    }
+    gst_message_unref (m);
+  }
+  ret = TRUE;
+done:
+  gst_object_unref (bus);
+  return ret;
+}
+
+gboolean
+gst_splitmux_part_reader_prepare (GstSplitMuxPartReader * part)
+{
+  GstStateChangeReturn ret;
+
+  ret = gst_element_set_state (GST_ELEMENT_CAST (part), GST_STATE_PAUSED);
+
+  if (ret != GST_STATE_CHANGE_SUCCESS)
+    return FALSE;
+
+  return check_bus_messages (part);
+}
+
+void
+gst_splitmux_part_reader_unprepare (GstSplitMuxPartReader * part)
+{
+  gst_element_set_state (GST_ELEMENT_CAST (part), GST_STATE_NULL);
+}
+
+void
+gst_splitmux_part_reader_set_location (GstSplitMuxPartReader * reader,
+    const gchar * path)
+{
+  reader->path = g_strdup (path);
+}
+
+gboolean
+gst_splitmux_part_reader_activate (GstSplitMuxPartReader * reader,
+    GstSegment * seg, GstSeekFlags extra_flags)
+{
+  GST_DEBUG_OBJECT (reader, "Activating part reader");
+
+  if (!gst_splitmux_part_reader_seek_to_segment (reader, seg, extra_flags)) {
+    GST_ERROR_OBJECT (reader, "Failed to seek part to %" GST_SEGMENT_FORMAT,
+        seg);
+    return FALSE;
+  }
+  if (gst_element_set_state (GST_ELEMENT_CAST (reader),
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
+    GST_ERROR_OBJECT (reader, "Failed to set state to PLAYING");
+    return FALSE;
+  }
+  return TRUE;
+}
+
+gboolean
+gst_splitmux_part_reader_is_active (GstSplitMuxPartReader * part)
+{
+  gboolean ret;
+
+  SPLITMUX_PART_LOCK (part);
+  ret = part->active;
+  SPLITMUX_PART_UNLOCK (part);
+
+  return ret;
+}
+
+void
+gst_splitmux_part_reader_deactivate (GstSplitMuxPartReader * reader)
+{
+  GST_DEBUG_OBJECT (reader, "Deactivating reader");
+  gst_element_set_state (GST_ELEMENT_CAST (reader), GST_STATE_PAUSED);
+}
+
+void
+gst_splitmux_part_reader_set_flushing_locked (GstSplitMuxPartReader * reader,
+    gboolean flushing)
+{
+  GList *cur;
+
+  GST_LOG_OBJECT (reader, "%s dataqueues",
+      flushing ? "Flushing" : "Done flushing");
+  for (cur = g_list_first (reader->pads); cur != NULL; cur = g_list_next (cur)) {
+    GstSplitMuxPartPad *part_pad = SPLITMUX_PART_PAD_CAST (cur->data);
+    gst_data_queue_set_flushing (part_pad->queue, flushing);
+    if (flushing)
+      gst_data_queue_flush (part_pad->queue);
+  }
+};
+
+void
+gst_splitmux_part_reader_set_callbacks (GstSplitMuxPartReader * reader,
+    gpointer cb_data, GstSplitMuxPartReaderPadCb get_pad_cb)
+{
+  reader->cb_data = cb_data;
+  reader->get_pad_cb = get_pad_cb;
+}
+
+GstClockTime
+gst_splitmux_part_reader_get_end_offset (GstSplitMuxPartReader * reader)
+{
+  GList *cur;
+  GstClockTime ret = GST_CLOCK_TIME_NONE;
+
+  SPLITMUX_PART_LOCK (reader);
+  for (cur = g_list_first (reader->pads); cur != NULL; cur = g_list_next (cur)) {
+    GstSplitMuxPartPad *part_pad = SPLITMUX_PART_PAD_CAST (cur->data);
+    if (!part_pad->is_sparse && part_pad->max_ts < ret)
+      ret = part_pad->max_ts;
+  }
+
+  SPLITMUX_PART_UNLOCK (reader);
+
+  return ret;
+}
+
+void
+gst_splitmux_part_reader_set_start_offset (GstSplitMuxPartReader * reader,
+    GstClockTime offset)
+{
+  SPLITMUX_PART_LOCK (reader);
+  reader->start_offset = offset;
+  GST_INFO_OBJECT (reader, "TS offset now %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (offset));
+  SPLITMUX_PART_UNLOCK (reader);
+}
+
+GstClockTime
+gst_splitmux_part_reader_get_start_offset (GstSplitMuxPartReader * reader)
+{
+  GstClockTime ret = GST_CLOCK_TIME_NONE;
+
+  SPLITMUX_PART_LOCK (reader);
+  ret = reader->start_offset;
+  SPLITMUX_PART_UNLOCK (reader);
+
+  return ret;
+}
+
+GstClockTime
+gst_splitmux_part_reader_get_duration (GstSplitMuxPartReader * reader)
+{
+  GstClockTime dur;
+
+  SPLITMUX_PART_LOCK (reader);
+  dur = reader->duration;
+  SPLITMUX_PART_UNLOCK (reader);
+
+  return dur;
+}
+
+GstPad *
+gst_splitmux_part_reader_lookup_pad (GstSplitMuxPartReader * reader,
+    GstPad * target)
+{
+  GstPad *result = NULL;
+  GList *cur;
+
+  SPLITMUX_PART_LOCK (reader);
+  for (cur = g_list_first (reader->pads); cur != NULL; cur = g_list_next (cur)) {
+    GstSplitMuxPartPad *part_pad = SPLITMUX_PART_PAD_CAST (cur->data);
+    if (part_pad->target == target) {
+      result = (GstPad *) gst_object_ref (part_pad);
+      break;
+    }
+  }
+  SPLITMUX_PART_UNLOCK (reader);
+
+  return result;
+}
+
+GstFlowReturn
+gst_splitmux_part_reader_pop (GstSplitMuxPartReader * reader, GstPad * pad,
+    GstDataQueueItem ** item)
+{
+  GstSplitMuxPartPad *part_pad = (GstSplitMuxPartPad *) (pad);
+  GstDataQueue *q;
+  GstFlowReturn ret;
+
+  /* Get one item from the appropriate dataqueue */
+  SPLITMUX_PART_LOCK (reader);
+  if (reader->prep_state == PART_STATE_FAILED) {
+    SPLITMUX_PART_UNLOCK (reader);
+    return GST_FLOW_ERROR;
+  }
+
+  q = gst_object_ref (part_pad->queue);
+
+  /* Have to drop the lock around pop, so we can be woken up for flush */
+  SPLITMUX_PART_UNLOCK (reader);
+  if (!gst_data_queue_pop (q, item) || (*item == NULL)) {
+    ret = GST_FLOW_FLUSHING;
+    goto out;
+  }
+
+  SPLITMUX_PART_LOCK (reader);
+
+  SPLITMUX_PART_BROADCAST (reader);
+  if (GST_IS_EVENT ((*item)->object)) {
+    GstEvent *e = (GstEvent *) ((*item)->object);
+    /* Mark this pad as EOS */
+    if (GST_EVENT_TYPE (e) == GST_EVENT_EOS)
+      part_pad->is_eos = TRUE;
+  }
+
+  SPLITMUX_PART_UNLOCK (reader);
+
+  ret = GST_FLOW_OK;
+out:
+  gst_object_unref (q);
+  return ret;
+}
+
+static void
+bus_handler (GstBin * bin, GstMessage * message)
+{
+  GstSplitMuxPartReader *reader = (GstSplitMuxPartReader *) bin;
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_ERROR:
+      /* Make sure to set the state to failed and wake up the listener
+       * on error */
+      SPLITMUX_PART_LOCK (reader);
+      GST_ERROR_OBJECT (reader, "Got error message from child %" GST_PTR_FORMAT
+          " marking this reader as failed", GST_MESSAGE_SRC (message));
+      reader->prep_state = PART_STATE_FAILED;
+      SPLITMUX_PART_BROADCAST (reader);
+      SPLITMUX_PART_UNLOCK (reader);
+      break;
+    default:
+      break;
+  }
+
+  GST_BIN_CLASS (parent_class)->handle_message (bin, message);
+}
diff --git a/gst/multifile/gstsplitmuxpartreader.h b/gst/multifile/gstsplitmuxpartreader.h
new file mode 100644
index 0000000..03b8b5c
--- /dev/null
+++ b/gst/multifile/gstsplitmuxpartreader.h
@@ -0,0 +1,119 @@
+/* GStreamer Split Muxed File Source - Part reader
+ * Copyright (C) 2014 Jan Schmidt <jan@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef __GST_SPLITMUX_PART_READER_H__
+#define __GST_SPLITMUX_PART_READER_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstdataqueue.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SPLITMUX_PART_READER \
+  (gst_splitmux_part_reader_get_type())
+#define GST_SPLITMUX_PART_READER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPLITMUX_PART_READER,GstSplitMuxSrc))
+#define GST_SPLITMUX_PART_READER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPLITMUX_PART_READER,GstSplitMuxSrcClass))
+#define GST_IS_SPLITMUX_PART_READER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPLITMUX_PART_READER))
+#define GST_IS_SPLITMUX_PART_READER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPLITMUX_PART_READER))
+
+typedef struct _GstSplitMuxPartReader GstSplitMuxPartReader;
+typedef struct _GstSplitMuxPartReaderClass GstSplitMuxPartReaderClass;
+typedef struct _SplitMuxSrcPad SplitMuxSrcPad;
+typedef struct _SplitMuxSrcPadClass SplitMuxSrcPadClass;
+
+typedef enum
+{
+  PART_STATE_NULL,
+  PART_STATE_PREPARING_COLLECT_STREAMS,
+  PART_STATE_PREPARING_MEASURE_STREAMS,
+  PART_STATE_PREPARING_RESET_FOR_READY,
+  PART_STATE_READY,
+  PART_STATE_FAILED,
+} GstSplitMuxPartState;
+
+typedef GstPad *(*GstSplitMuxPartReaderPadCb)(GstSplitMuxPartReader *reader, GstPad *src_pad, gpointer cb_data);
+
+struct _GstSplitMuxPartReader
+{
+  GstPipeline parent;
+
+  GstSplitMuxPartState prep_state;
+
+  gchar *path;
+
+  GstElement *src;
+  GstElement *typefind;
+  GstElement *demux;
+
+  gboolean active;
+  gboolean running;
+  gboolean prepared;
+  gboolean flushing;
+  gboolean no_more_pads;
+
+  GstClockTime duration;
+  GstClockTime start_offset;
+
+  GList *pads;
+
+  GCond inactive_cond;
+  GMutex lock;
+  GMutex type_lock;
+
+  GstSplitMuxPartReaderPadCb get_pad_cb;
+  gpointer cb_data;
+};
+
+struct _GstSplitMuxPartReaderClass
+{
+  GstPipelineClass parent_class;
+
+  void (*prepared)  (GstSplitMuxPartReader *reader);
+  void (*end_of_part) (GstSplitMuxPartReader *reader);
+};
+
+GType gst_splitmux_part_reader_get_type (void);
+
+void gst_splitmux_part_reader_set_callbacks (GstSplitMuxPartReader *reader,
+    gpointer cb_data, GstSplitMuxPartReaderPadCb get_pad_cb);
+gboolean gst_splitmux_part_reader_prepare (GstSplitMuxPartReader *part);
+void gst_splitmux_part_reader_unprepare (GstSplitMuxPartReader *part);
+void gst_splitmux_part_reader_set_location (GstSplitMuxPartReader *reader,
+    const gchar *path);
+gboolean gst_splitmux_part_is_eos (GstSplitMuxPartReader *reader);
+
+gboolean gst_splitmux_part_reader_activate (GstSplitMuxPartReader *part, GstSegment *seg, GstSeekFlags extra_flags);
+void gst_splitmux_part_reader_deactivate (GstSplitMuxPartReader *part);
+gboolean gst_splitmux_part_reader_is_active (GstSplitMuxPartReader *part);
+
+gboolean gst_splitmux_part_reader_src_query (GstSplitMuxPartReader *part, GstPad *src_pad, GstQuery * query);
+void gst_splitmux_part_reader_set_start_offset (GstSplitMuxPartReader *part, GstClockTime offset);
+GstClockTime gst_splitmux_part_reader_get_start_offset (GstSplitMuxPartReader *part);
+GstClockTime gst_splitmux_part_reader_get_end_offset (GstSplitMuxPartReader *part);
+GstClockTime gst_splitmux_part_reader_get_duration (GstSplitMuxPartReader * reader);
+
+GstPad *gst_splitmux_part_reader_lookup_pad (GstSplitMuxPartReader *reader, GstPad *target);
+GstFlowReturn gst_splitmux_part_reader_pop (GstSplitMuxPartReader *reader, GstPad *part_pad, GstDataQueueItem ** item);
+
+G_END_DECLS
+
+#endif
diff --git a/gst/multifile/gstsplitmuxsink.c b/gst/multifile/gstsplitmuxsink.c
new file mode 100644
index 0000000..be37933
--- /dev/null
+++ b/gst/multifile/gstsplitmuxsink.c
@@ -0,0 +1,2500 @@
+/* GStreamer Muxer bin that splits output stream by size/time
+ * Copyright (C) <2014> Jan Schmidt <jan@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-splitmuxsink
+ * @short_description: Muxer wrapper for splitting output stream by size or time
+ *
+ * This element wraps a muxer and a sink, and starts a new file when the mux
+ * contents are about to cross a threshold of maximum size of maximum time,
+ * splitting at video keyframe boundaries. Exactly one input video stream
+ * can be muxed, with as many accompanying audio and subtitle streams as
+ * desired.
+ *
+ * By default, it uses mp4mux and filesink, but they can be changed via
+ * the 'muxer' and 'sink' properties.
+ *
+ * The minimum file size is 1 GOP, however - so limits may be overrun if the
+ * distance between any 2 keyframes is larger than the limits.
+ *
+ * If a video stream is available, the splitting process is driven by the video
+ * stream contents, and the video stream must contain closed GOPs for the output
+ * file parts to be played individually correctly. In the absence of a video
+ * stream, the first available stream is used as reference for synchronization.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -e v4l2src num-buffers=500 ! video/x-raw,width=320,height=240 ! videoconvert ! queue ! timeoverlay ! x264enc key-int-max=10 ! h264parse ! splitmuxsink location=video%02d.mov max-size-time=10000000000 max-size-bytes=1000000
+ * ]|
+ * Records a video stream captured from a v4l2 device and muxes it into
+ * ISO mp4 files, splitting as needed to limit size/duration to 10 seconds
+ * and 1MB maximum size.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <glib/gstdio.h>
+#include <gst/video/video.h>
+#include "gstsplitmuxsink.h"
+
+GST_DEBUG_CATEGORY_STATIC (splitmux_debug);
+#define GST_CAT_DEFAULT splitmux_debug
+
+#define GST_SPLITMUX_LOCK(s) g_mutex_lock(&(s)->lock)
+#define GST_SPLITMUX_UNLOCK(s) g_mutex_unlock(&(s)->lock)
+#define GST_SPLITMUX_WAIT_INPUT(s) g_cond_wait (&(s)->input_cond, &(s)->lock)
+#define GST_SPLITMUX_BROADCAST_INPUT(s) g_cond_broadcast (&(s)->input_cond)
+
+#define GST_SPLITMUX_WAIT_OUTPUT(s) g_cond_wait (&(s)->output_cond, &(s)->lock)
+#define GST_SPLITMUX_BROADCAST_OUTPUT(s) g_cond_broadcast (&(s)->output_cond)
+
+static void split_now (GstSplitMuxSink * splitmux);
+
+enum
+{
+  PROP_0,
+  PROP_LOCATION,
+  PROP_MAX_SIZE_TIME,
+  PROP_MAX_SIZE_BYTES,
+  PROP_MAX_SIZE_TIMECODE,
+  PROP_SEND_KEYFRAME_REQUESTS,
+  PROP_MAX_FILES,
+  PROP_MUXER_OVERHEAD,
+  PROP_USE_ROBUST_MUXING,
+  PROP_ALIGNMENT_THRESHOLD,
+  PROP_MUXER,
+  PROP_SINK
+};
+
+#define DEFAULT_MAX_SIZE_TIME       0
+#define DEFAULT_MAX_SIZE_BYTES      0
+#define DEFAULT_MAX_FILES           0
+#define DEFAULT_MUXER_OVERHEAD      0.02
+#define DEFAULT_SEND_KEYFRAME_REQUESTS FALSE
+#define DEFAULT_ALIGNMENT_THRESHOLD 0
+#define DEFAULT_MUXER "mp4mux"
+#define DEFAULT_SINK "filesink"
+#define DEFAULT_USE_ROBUST_MUXING FALSE
+
+enum
+{
+  SIGNAL_FORMAT_LOCATION,
+  SIGNAL_FORMAT_LOCATION_FULL,
+  SIGNAL_SPLIT_NOW,
+  SIGNAL_LAST
+};
+
+static guint signals[SIGNAL_LAST];
+
+static GstStaticPadTemplate video_sink_template =
+GST_STATIC_PAD_TEMPLATE ("video",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS_ANY);
+static GstStaticPadTemplate audio_sink_template =
+GST_STATIC_PAD_TEMPLATE ("audio_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS_ANY);
+static GstStaticPadTemplate subtitle_sink_template =
+GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS_ANY);
+
+static GQuark PAD_CONTEXT;
+
+static void
+_do_init (void)
+{
+  PAD_CONTEXT = g_quark_from_static_string ("pad-context");
+}
+
+#define gst_splitmux_sink_parent_class parent_class
+G_DEFINE_TYPE_EXTENDED (GstSplitMuxSink, gst_splitmux_sink, GST_TYPE_BIN, 0,
+    _do_init ());
+
+static gboolean create_muxer (GstSplitMuxSink * splitmux);
+static gboolean create_sink (GstSplitMuxSink * splitmux);
+static void gst_splitmux_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_splitmux_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_splitmux_sink_dispose (GObject * object);
+static void gst_splitmux_sink_finalize (GObject * object);
+
+static GstPad *gst_splitmux_sink_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
+static void gst_splitmux_sink_release_pad (GstElement * element, GstPad * pad);
+
+static GstStateChangeReturn gst_splitmux_sink_change_state (GstElement *
+    element, GstStateChange transition);
+
+static void bus_handler (GstBin * bin, GstMessage * msg);
+static void set_next_filename (GstSplitMuxSink * splitmux, MqStreamCtx * ctx);
+static void start_next_fragment (GstSplitMuxSink * splitmux, MqStreamCtx * ctx);
+static void mq_stream_ctx_unref (MqStreamCtx * ctx);
+static void grow_blocked_queues (GstSplitMuxSink * splitmux);
+
+static void gst_splitmux_sink_ensure_max_files (GstSplitMuxSink * splitmux);
+static GstElement *create_element (GstSplitMuxSink * splitmux,
+    const gchar * factory, const gchar * name, gboolean locked);
+
+static void do_async_done (GstSplitMuxSink * splitmux);
+
+static MqStreamBuf *
+mq_stream_buf_new (void)
+{
+  return g_slice_new0 (MqStreamBuf);
+}
+
+static void
+mq_stream_buf_free (MqStreamBuf * data)
+{
+  g_slice_free (MqStreamBuf, data);
+}
+
+static SplitMuxOutputCommand *
+out_cmd_buf_new (void)
+{
+  return g_slice_new0 (SplitMuxOutputCommand);
+}
+
+static void
+out_cmd_buf_free (SplitMuxOutputCommand * data)
+{
+  g_slice_free (SplitMuxOutputCommand, data);
+}
+
+static void
+gst_splitmux_sink_class_init (GstSplitMuxSinkClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBinClass *gstbin_class = (GstBinClass *) klass;
+
+  gobject_class->set_property = gst_splitmux_sink_set_property;
+  gobject_class->get_property = gst_splitmux_sink_get_property;
+  gobject_class->dispose = gst_splitmux_sink_dispose;
+  gobject_class->finalize = gst_splitmux_sink_finalize;
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Split Muxing Bin", "Generic/Bin/Muxer",
+      "Convenience bin that muxes incoming streams into multiple time/size limited files",
+      "Jan Schmidt <jan@centricular.com>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &video_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &audio_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &subtitle_sink_template);
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_splitmux_sink_change_state);
+  gstelement_class->request_new_pad =
+      GST_DEBUG_FUNCPTR (gst_splitmux_sink_request_new_pad);
+  gstelement_class->release_pad =
+      GST_DEBUG_FUNCPTR (gst_splitmux_sink_release_pad);
+
+  gstbin_class->handle_message = bus_handler;
+
+  g_object_class_install_property (gobject_class, PROP_LOCATION,
+      g_param_spec_string ("location", "File Output Pattern",
+          "Format string pattern for the location of the files to write (e.g. video%05d.mp4)",
+          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MUXER_OVERHEAD,
+      g_param_spec_double ("mux-overhead", "Muxing Overhead",
+          "Extra size overhead of muxing (0.02 = 2%)", 0.0, 1.0,
+          DEFAULT_MUXER_OVERHEAD,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_SIZE_TIME,
+      g_param_spec_uint64 ("max-size-time", "Max. size (ns)",
+          "Max. amount of time per file (in ns, 0=disable)", 0, G_MAXUINT64,
+          DEFAULT_MAX_SIZE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MAX_SIZE_BYTES,
+      g_param_spec_uint64 ("max-size-bytes", "Max. size bytes",
+          "Max. amount of data per file (in bytes, 0=disable)", 0, G_MAXUINT64,
+          DEFAULT_MAX_SIZE_BYTES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MAX_SIZE_TIMECODE,
+      g_param_spec_string ("max-size-timecode", "Maximum timecode difference",
+          "Maximum difference in timecode between first and last frame. "
+          "Separator is assumed to be \":\" everywhere (e.g. 01:00:00:00). "
+          "Will only be effective if a timecode track is present.",
+          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_SEND_KEYFRAME_REQUESTS,
+      g_param_spec_boolean ("send-keyframe-requests",
+          "Request keyframes at max-size-time",
+          "Request a keyframe every max-size-time ns to try splitting at that point. "
+          "Needs max-size-bytes to be 0 in order to be effective.",
+          DEFAULT_SEND_KEYFRAME_REQUESTS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MAX_FILES,
+      g_param_spec_uint ("max-files", "Max files",
+          "Maximum number of files to keep on disk. Once the maximum is reached,"
+          "old files start to be deleted to make room for new ones.", 0,
+          G_MAXUINT, DEFAULT_MAX_FILES,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_ALIGNMENT_THRESHOLD,
+      g_param_spec_uint64 ("alignment-threshold", "Alignment threshold (ns)",
+          "Allow non-reference streams to be that many ns before the reference"
+          " stream",
+          0, G_MAXUINT64, DEFAULT_ALIGNMENT_THRESHOLD,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MUXER,
+      g_param_spec_object ("muxer", "Muxer",
+          "The muxer element to use (NULL = default mp4mux)",
+          GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_SINK,
+      g_param_spec_object ("sink", "Sink",
+          "The sink element (or element chain) to use (NULL = default filesink)",
+          GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_USE_ROBUST_MUXING,
+      g_param_spec_boolean ("use-robust-muxing",
+          "Support robust-muxing mode of some muxers",
+          "Check if muxers support robust muxing via the reserved-max-duration and "
+          "reserved-duration-remaining properties and use them if so. "
+          "(Only present on qtmux and mp4mux for now). splitmuxsink may then also "
+          " create new fragments if the reserved header space is about to overflow. "
+          "Note this does not set reserved-moov-update-period - apps should do that manually",
+          DEFAULT_USE_ROBUST_MUXING,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstSplitMuxSink::format-location:
+   * @splitmux: the #GstSplitMuxSink
+   * @fragment_id: the sequence number of the file to be created
+   *
+   * Returns: the location to be used for the next output file
+   */
+  signals[SIGNAL_FORMAT_LOCATION] =
+      g_signal_new ("format-location", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_STRING, 1, G_TYPE_UINT);
+
+  /**
+   * GstSplitMuxSink::format-location-full:
+   * @splitmux: the #GstSplitMuxSink
+   * @fragment_id: the sequence number of the file to be created
+   * @first_sample: A #GstSample containing the first buffer
+   *   from the reference stream in the new file
+   *
+   * Returns: the location to be used for the next output file
+   */
+  signals[SIGNAL_FORMAT_LOCATION_FULL] =
+      g_signal_new ("format-location-full", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_STRING, 2, G_TYPE_UINT,
+      GST_TYPE_SAMPLE);
+
+  /**
+   * GstSplitMuxSink::split-now:
+   * @splitmux: the #GstSplitMuxSink
+   *
+   * When called by the user, this action signal splits the video file (and begins a new one) immediately.
+   *
+   *
+   * Since: 1.14
+   */
+
+  signals[SIGNAL_SPLIT_NOW] =
+      g_signal_new ("split-now", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstSplitMuxSinkClass,
+          split_now), NULL, NULL, NULL, G_TYPE_NONE, 0);
+
+  klass->split_now = split_now;
+}
+
+static void
+gst_splitmux_sink_init (GstSplitMuxSink * splitmux)
+{
+  g_mutex_init (&splitmux->lock);
+  g_cond_init (&splitmux->input_cond);
+  g_cond_init (&splitmux->output_cond);
+  g_queue_init (&splitmux->out_cmd_q);
+
+  splitmux->mux_overhead = DEFAULT_MUXER_OVERHEAD;
+  splitmux->threshold_time = DEFAULT_MAX_SIZE_TIME;
+  splitmux->threshold_bytes = DEFAULT_MAX_SIZE_BYTES;
+  splitmux->max_files = DEFAULT_MAX_FILES;
+  splitmux->send_keyframe_requests = DEFAULT_SEND_KEYFRAME_REQUESTS;
+  splitmux->next_max_tc_time = GST_CLOCK_TIME_NONE;
+  splitmux->alignment_threshold = DEFAULT_ALIGNMENT_THRESHOLD;
+  splitmux->use_robust_muxing = DEFAULT_USE_ROBUST_MUXING;
+
+  splitmux->threshold_timecode_str = NULL;
+
+  GST_OBJECT_FLAG_SET (splitmux, GST_ELEMENT_FLAG_SINK);
+  splitmux->split_now = FALSE;
+}
+
+static void
+gst_splitmux_reset (GstSplitMuxSink * splitmux)
+{
+  if (splitmux->muxer) {
+    gst_element_set_locked_state (splitmux->muxer, TRUE);
+    gst_element_set_state (splitmux->muxer, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN (splitmux), splitmux->muxer);
+  }
+  if (splitmux->active_sink) {
+    gst_element_set_locked_state (splitmux->active_sink, TRUE);
+    gst_element_set_state (splitmux->active_sink, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN (splitmux), splitmux->active_sink);
+  }
+
+  splitmux->sink = splitmux->active_sink = splitmux->muxer = NULL;
+}
+
+static void
+gst_splitmux_sink_dispose (GObject * object)
+{
+  GstSplitMuxSink *splitmux = GST_SPLITMUX_SINK (object);
+
+  /* Calling parent dispose invalidates all child pointers */
+  splitmux->sink = splitmux->active_sink = splitmux->muxer = NULL;
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_splitmux_sink_finalize (GObject * object)
+{
+  GstSplitMuxSink *splitmux = GST_SPLITMUX_SINK (object);
+  g_cond_clear (&splitmux->input_cond);
+  g_cond_clear (&splitmux->output_cond);
+  g_mutex_clear (&splitmux->lock);
+  g_queue_foreach (&splitmux->out_cmd_q, (GFunc) out_cmd_buf_free, NULL);
+  g_queue_clear (&splitmux->out_cmd_q);
+
+  if (splitmux->provided_sink)
+    gst_object_unref (splitmux->provided_sink);
+  if (splitmux->provided_muxer)
+    gst_object_unref (splitmux->provided_muxer);
+
+  if (splitmux->threshold_timecode_str)
+    g_free (splitmux->threshold_timecode_str);
+
+  g_free (splitmux->location);
+
+  /* Make sure to free any un-released contexts */
+  g_list_foreach (splitmux->contexts, (GFunc) mq_stream_ctx_unref, NULL);
+  g_list_free (splitmux->contexts);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/*
+ * Set any time threshold to the muxer, if it has
+ * reserved-max-duration and reserved-duration-remaining
+ * properties. Called when creating/claiming the muxer
+ * in create_elements() */
+static void
+update_muxer_properties (GstSplitMuxSink * sink)
+{
+  GObjectClass *klass;
+  GstClockTime threshold_time;
+
+  sink->muxer_has_reserved_props = FALSE;
+  if (sink->muxer == NULL)
+    return;
+  klass = G_OBJECT_GET_CLASS (sink->muxer);
+  if (g_object_class_find_property (klass, "reserved-max-duration") == NULL)
+    return;
+  if (g_object_class_find_property (klass,
+          "reserved-duration-remaining") == NULL)
+    return;
+  sink->muxer_has_reserved_props = TRUE;
+
+  GST_LOG_OBJECT (sink, "Setting muxer reserved time to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (sink->threshold_time));
+  GST_OBJECT_LOCK (sink);
+  threshold_time = sink->threshold_time;
+  GST_OBJECT_UNLOCK (sink);
+
+  if (threshold_time > 0) {
+    /* Tell the muxer how much space to reserve */
+    GstClockTime muxer_threshold = threshold_time;
+    g_object_set (sink->muxer, "reserved-max-duration", muxer_threshold, NULL);
+  }
+}
+
+static void
+gst_splitmux_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstSplitMuxSink *splitmux = GST_SPLITMUX_SINK (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:{
+      GST_OBJECT_LOCK (splitmux);
+      g_free (splitmux->location);
+      splitmux->location = g_value_dup_string (value);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    }
+    case PROP_MAX_SIZE_BYTES:
+      GST_OBJECT_LOCK (splitmux);
+      splitmux->threshold_bytes = g_value_get_uint64 (value);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_MAX_SIZE_TIME:
+      GST_OBJECT_LOCK (splitmux);
+      splitmux->threshold_time = g_value_get_uint64 (value);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_MAX_SIZE_TIMECODE:
+      GST_OBJECT_LOCK (splitmux);
+      splitmux->threshold_timecode_str = g_value_dup_string (value);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_SEND_KEYFRAME_REQUESTS:
+      GST_OBJECT_LOCK (splitmux);
+      splitmux->send_keyframe_requests = g_value_get_boolean (value);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_MAX_FILES:
+      GST_OBJECT_LOCK (splitmux);
+      splitmux->max_files = g_value_get_uint (value);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_MUXER_OVERHEAD:
+      GST_OBJECT_LOCK (splitmux);
+      splitmux->mux_overhead = g_value_get_double (value);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_USE_ROBUST_MUXING:
+      GST_OBJECT_LOCK (splitmux);
+      splitmux->use_robust_muxing = g_value_get_boolean (value);
+      GST_OBJECT_UNLOCK (splitmux);
+      if (splitmux->use_robust_muxing)
+        update_muxer_properties (splitmux);
+      break;
+    case PROP_ALIGNMENT_THRESHOLD:
+      GST_OBJECT_LOCK (splitmux);
+      splitmux->alignment_threshold = g_value_get_uint64 (value);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_SINK:
+      GST_OBJECT_LOCK (splitmux);
+      if (splitmux->provided_sink)
+        gst_object_unref (splitmux->provided_sink);
+      splitmux->provided_sink = g_value_get_object (value);
+      gst_object_ref_sink (splitmux->provided_sink);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_MUXER:
+      GST_OBJECT_LOCK (splitmux);
+      if (splitmux->provided_muxer)
+        gst_object_unref (splitmux->provided_muxer);
+      splitmux->provided_muxer = g_value_get_object (value);
+      gst_object_ref_sink (splitmux->provided_muxer);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_splitmux_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstSplitMuxSink *splitmux = GST_SPLITMUX_SINK (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      GST_OBJECT_LOCK (splitmux);
+      g_value_set_string (value, splitmux->location);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_MAX_SIZE_BYTES:
+      GST_OBJECT_LOCK (splitmux);
+      g_value_set_uint64 (value, splitmux->threshold_bytes);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_MAX_SIZE_TIME:
+      GST_OBJECT_LOCK (splitmux);
+      g_value_set_uint64 (value, splitmux->threshold_time);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_MAX_SIZE_TIMECODE:
+      GST_OBJECT_LOCK (splitmux);
+      g_value_set_string (value, splitmux->threshold_timecode_str);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_SEND_KEYFRAME_REQUESTS:
+      GST_OBJECT_LOCK (splitmux);
+      g_value_set_boolean (value, splitmux->send_keyframe_requests);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_MAX_FILES:
+      GST_OBJECT_LOCK (splitmux);
+      g_value_set_uint (value, splitmux->max_files);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_MUXER_OVERHEAD:
+      GST_OBJECT_LOCK (splitmux);
+      g_value_set_double (value, splitmux->mux_overhead);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_USE_ROBUST_MUXING:
+      GST_OBJECT_LOCK (splitmux);
+      g_value_set_boolean (value, splitmux->use_robust_muxing);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_ALIGNMENT_THRESHOLD:
+      GST_OBJECT_LOCK (splitmux);
+      g_value_set_uint64 (value, splitmux->alignment_threshold);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_SINK:
+      GST_OBJECT_LOCK (splitmux);
+      g_value_set_object (value, splitmux->provided_sink);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    case PROP_MUXER:
+      GST_OBJECT_LOCK (splitmux);
+      g_value_set_object (value, splitmux->provided_muxer);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* Convenience function */
+static inline GstClockTimeDiff
+my_segment_to_running_time (GstSegment * segment, GstClockTime val)
+{
+  GstClockTimeDiff res = GST_CLOCK_STIME_NONE;
+
+  if (GST_CLOCK_TIME_IS_VALID (val)) {
+    gboolean sign =
+        gst_segment_to_running_time_full (segment, GST_FORMAT_TIME, val, &val);
+    if (sign > 0)
+      res = val;
+    else if (sign < 0)
+      res = -val;
+  }
+  return res;
+}
+
+static MqStreamCtx *
+mq_stream_ctx_new (GstSplitMuxSink * splitmux)
+{
+  MqStreamCtx *ctx;
+
+  ctx = g_new0 (MqStreamCtx, 1);
+  g_atomic_int_set (&ctx->refcount, 1);
+  ctx->splitmux = splitmux;
+  gst_segment_init (&ctx->in_segment, GST_FORMAT_UNDEFINED);
+  gst_segment_init (&ctx->out_segment, GST_FORMAT_UNDEFINED);
+  ctx->in_running_time = ctx->out_running_time = GST_CLOCK_STIME_NONE;
+  g_queue_init (&ctx->queued_bufs);
+  return ctx;
+}
+
+static void
+mq_stream_ctx_free (MqStreamCtx * ctx)
+{
+  if (ctx->q) {
+    g_signal_handler_disconnect (ctx->q, ctx->q_overrun_id);
+    gst_element_set_locked_state (ctx->q, TRUE);
+    gst_element_set_state (ctx->q, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN (ctx->splitmux), ctx->q);
+    gst_object_unref (ctx->q);
+  }
+  gst_buffer_replace (&ctx->prev_in_keyframe, NULL);
+  gst_object_unref (ctx->sinkpad);
+  gst_object_unref (ctx->srcpad);
+  g_queue_foreach (&ctx->queued_bufs, (GFunc) mq_stream_buf_free, NULL);
+  g_queue_clear (&ctx->queued_bufs);
+  g_free (ctx);
+}
+
+static void
+mq_stream_ctx_unref (MqStreamCtx * ctx)
+{
+  if (g_atomic_int_dec_and_test (&ctx->refcount))
+    mq_stream_ctx_free (ctx);
+}
+
+static void
+mq_stream_ctx_ref (MqStreamCtx * ctx)
+{
+  g_atomic_int_inc (&ctx->refcount);
+}
+
+static void
+_pad_block_destroy_sink_notify (MqStreamCtx * ctx)
+{
+  ctx->sink_pad_block_id = 0;
+  mq_stream_ctx_unref (ctx);
+}
+
+static void
+_pad_block_destroy_src_notify (MqStreamCtx * ctx)
+{
+  ctx->src_pad_block_id = 0;
+  mq_stream_ctx_unref (ctx);
+}
+
+static void
+send_fragment_opened_closed_msg (GstSplitMuxSink * splitmux, gboolean opened)
+{
+  gchar *location = NULL;
+  GstMessage *msg;
+  const gchar *msg_name = opened ?
+      "splitmuxsink-fragment-opened" : "splitmuxsink-fragment-closed";
+
+  g_object_get (splitmux->sink, "location", &location, NULL);
+
+  msg = gst_message_new_element (GST_OBJECT (splitmux),
+      gst_structure_new (msg_name,
+          "location", G_TYPE_STRING, location,
+          "running-time", GST_TYPE_CLOCK_TIME,
+          splitmux->reference_ctx->out_running_time, NULL));
+  gst_element_post_message (GST_ELEMENT_CAST (splitmux), msg);
+
+  g_free (location);
+}
+
+/* Called with lock held, drops the lock to send EOS to the
+ * pad
+ */
+static void
+send_eos (GstSplitMuxSink * splitmux, MqStreamCtx * ctx)
+{
+  GstEvent *eos;
+  GstPad *pad;
+
+  eos = gst_event_new_eos ();
+  pad = gst_pad_get_peer (ctx->srcpad);
+
+  ctx->out_eos = TRUE;
+
+  GST_INFO_OBJECT (splitmux, "Sending EOS on %" GST_PTR_FORMAT, pad);
+  GST_SPLITMUX_UNLOCK (splitmux);
+  gst_pad_send_event (pad, eos);
+  GST_SPLITMUX_LOCK (splitmux);
+
+  gst_object_unref (pad);
+}
+
+/* Called with splitmux lock held to check if this output
+ * context needs to sleep to wait for the release of the
+ * next GOP, or to send EOS to close out the current file
+ */
+static void
+complete_or_wait_on_out (GstSplitMuxSink * splitmux, MqStreamCtx * ctx)
+{
+  if (ctx->caps_change)
+    return;
+
+  do {
+    /* When first starting up, the reference stream has to output
+     * the first buffer to prepare the muxer and sink */
+    gboolean can_output = (ctx->is_reference || splitmux->ready_for_output);
+    GstClockTimeDiff my_max_out_running_time = splitmux->max_out_running_time;
+
+    if (!(splitmux->max_out_running_time == 0 ||
+            splitmux->max_out_running_time == GST_CLOCK_STIME_NONE ||
+            splitmux->alignment_threshold == 0 ||
+            splitmux->max_out_running_time < splitmux->alignment_threshold)) {
+      my_max_out_running_time -= splitmux->alignment_threshold;
+      GST_LOG_OBJECT (ctx->srcpad,
+          "Max out running time currently %" GST_STIME_FORMAT
+          ", with threshold applied it is %" GST_STIME_FORMAT,
+          GST_STIME_ARGS (splitmux->max_out_running_time),
+          GST_STIME_ARGS (my_max_out_running_time));
+    }
+
+    if (ctx->flushing
+        || splitmux->output_state == SPLITMUX_OUTPUT_STATE_STOPPED)
+      return;
+
+    GST_LOG_OBJECT (ctx->srcpad,
+        "Checking running time %" GST_STIME_FORMAT " against max %"
+        GST_STIME_FORMAT, GST_STIME_ARGS (ctx->out_running_time),
+        GST_STIME_ARGS (my_max_out_running_time));
+
+    if (can_output) {
+      if (splitmux->max_out_running_time == GST_CLOCK_STIME_NONE ||
+          ctx->out_running_time < my_max_out_running_time) {
+        return;
+      }
+
+      switch (splitmux->output_state) {
+        case SPLITMUX_OUTPUT_STATE_OUTPUT_GOP:
+          /* We only get here if we've finished outputting a GOP and need to know
+           * what to do next */
+          splitmux->output_state = SPLITMUX_OUTPUT_STATE_AWAITING_COMMAND;
+          GST_SPLITMUX_BROADCAST_OUTPUT (splitmux);
+          continue;
+
+        case SPLITMUX_OUTPUT_STATE_ENDING_FILE:
+          /* We've reached the max out running_time to get here, so end this file now */
+          if (ctx->out_eos == FALSE) {
+            send_eos (splitmux, ctx);
+            continue;
+          }
+          break;
+        case SPLITMUX_OUTPUT_STATE_START_NEXT_FILE:
+          if (ctx->is_reference) {
+            /* Special handling on the reference ctx to start new fragments
+             * and collect commands from the command queue */
+            /* drops the splitmux lock briefly: */
+            start_next_fragment (splitmux, ctx);
+            continue;
+          }
+          break;
+
+        case SPLITMUX_OUTPUT_STATE_AWAITING_COMMAND:{
+          do {
+            SplitMuxOutputCommand *cmd =
+                g_queue_pop_tail (&splitmux->out_cmd_q);
+            if (cmd != NULL) {
+              /* If we pop the last command, we need to make our queues bigger */
+              if (g_queue_get_length (&splitmux->out_cmd_q) == 0)
+                grow_blocked_queues (splitmux);
+
+              if (cmd->start_new_fragment) {
+                GST_DEBUG_OBJECT (splitmux, "Got cmd to start new fragment");
+                splitmux->output_state = SPLITMUX_OUTPUT_STATE_ENDING_FILE;
+              } else {
+                GST_DEBUG_OBJECT (splitmux,
+                    "Got new output cmd for time %" GST_STIME_FORMAT,
+                    GST_STIME_ARGS (cmd->max_output_ts));
+
+                /* Extend the output range immediately */
+                splitmux->max_out_running_time = cmd->max_output_ts;
+                splitmux->output_state = SPLITMUX_OUTPUT_STATE_OUTPUT_GOP;
+              }
+              GST_SPLITMUX_BROADCAST_OUTPUT (splitmux);
+
+              out_cmd_buf_free (cmd);
+              break;
+            } else {
+              GST_SPLITMUX_WAIT_OUTPUT (splitmux);
+            }
+          } while (splitmux->output_state ==
+              SPLITMUX_OUTPUT_STATE_AWAITING_COMMAND);
+          /* loop and re-check the state */
+          continue;
+        }
+        case SPLITMUX_OUTPUT_STATE_STOPPED:
+          return;
+      }
+    }
+
+    GST_INFO_OBJECT (ctx->srcpad,
+        "Sleeping for running time %"
+        GST_STIME_FORMAT " (max %" GST_STIME_FORMAT ") or state change.",
+        GST_STIME_ARGS (ctx->out_running_time),
+        GST_STIME_ARGS (splitmux->max_out_running_time));
+    GST_SPLITMUX_WAIT_OUTPUT (splitmux);
+    GST_INFO_OBJECT (ctx->srcpad,
+        "Woken for new max running time %" GST_STIME_FORMAT,
+        GST_STIME_ARGS (splitmux->max_out_running_time));
+  }
+  while (1);
+}
+
+static GstClockTime
+calculate_next_max_timecode (GstSplitMuxSink * splitmux,
+    const GstVideoTimeCode * cur_tc)
+{
+  GstVideoTimeCode *target_tc;
+  GstVideoTimeCodeInterval *tc_inter;
+  GstClockTime cur_tc_time, target_tc_time, next_max_tc_time;
+
+  if (cur_tc == NULL || splitmux->threshold_timecode_str == NULL)
+    return GST_CLOCK_TIME_NONE;
+
+  tc_inter =
+      gst_video_time_code_interval_new_from_string
+      (splitmux->threshold_timecode_str);
+  target_tc = gst_video_time_code_add_interval (cur_tc, tc_inter);
+  gst_video_time_code_interval_free (tc_inter);
+
+  /* Convert to ns */
+  target_tc_time = gst_video_time_code_nsec_since_daily_jam (target_tc);
+  cur_tc_time = gst_video_time_code_nsec_since_daily_jam (cur_tc);
+
+  /* Add fragment_start_time, accounting for wraparound */
+  if (target_tc_time >= cur_tc_time) {
+    next_max_tc_time =
+        target_tc_time - cur_tc_time + splitmux->fragment_start_time;
+  } else {
+    GstClockTime day_in_ns = 24 * 60 * 60 * GST_SECOND;
+
+    next_max_tc_time =
+        day_in_ns - cur_tc_time + target_tc_time +
+        splitmux->fragment_start_time;
+  }
+  GST_INFO_OBJECT (splitmux, "Next max TC time: %" GST_TIME_FORMAT
+      " from ref TC: %" GST_TIME_FORMAT, GST_TIME_ARGS (next_max_tc_time),
+      GST_TIME_ARGS (cur_tc_time));
+  gst_video_time_code_free (target_tc);
+
+  return next_max_tc_time;
+}
+
+static gboolean
+request_next_keyframe (GstSplitMuxSink * splitmux, GstBuffer * buffer)
+{
+  GstEvent *ev;
+  GstClockTime target_time;
+  gboolean timecode_based = FALSE;
+
+  splitmux->next_max_tc_time = GST_CLOCK_TIME_NONE;
+  if (splitmux->threshold_timecode_str) {
+    GstVideoTimeCodeMeta *tc_meta;
+
+    if (buffer != NULL) {
+      tc_meta = gst_buffer_get_video_time_code_meta (buffer);
+      if (tc_meta) {
+        splitmux->next_max_tc_time =
+            calculate_next_max_timecode (splitmux, &tc_meta->tc);
+        timecode_based = (splitmux->next_max_tc_time != GST_CLOCK_TIME_NONE);
+      }
+    } else {
+      /* This can happen in the presence of GAP events that trigger
+       * a new fragment start */
+      GST_WARNING_OBJECT (splitmux,
+          "No buffer available to calculate next timecode");
+    }
+  }
+
+  if (splitmux->send_keyframe_requests == FALSE
+      || (splitmux->threshold_time == 0 && !timecode_based)
+      || splitmux->threshold_bytes != 0)
+    return TRUE;
+
+  if (timecode_based) {
+    /* We might have rounding errors: aim slightly earlier */
+    target_time = splitmux->next_max_tc_time - 5 * GST_USECOND;
+  } else {
+    target_time = splitmux->fragment_start_time + splitmux->threshold_time;
+  }
+  ev = gst_video_event_new_upstream_force_key_unit (target_time, TRUE, 0);
+  GST_INFO_OBJECT (splitmux, "Requesting next keyframe at %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (target_time));
+  return gst_pad_push_event (splitmux->reference_ctx->sinkpad, ev);
+}
+
+static GstPadProbeReturn
+handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
+{
+  GstSplitMuxSink *splitmux = ctx->splitmux;
+  MqStreamBuf *buf_info = NULL;
+
+  GST_LOG_OBJECT (pad, "Fired probe type 0x%x", info->type);
+
+  /* FIXME: Handle buffer lists, until then make it clear they won't work */
+  if (info->type & GST_PAD_PROBE_TYPE_BUFFER_LIST) {
+    g_warning ("Buffer list handling not implemented");
+    return GST_PAD_PROBE_DROP;
+  }
+  if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM ||
+      info->type & GST_PAD_PROBE_TYPE_EVENT_FLUSH) {
+    GstEvent *event = gst_pad_probe_info_get_event (info);
+    gboolean locked = FALSE;
+
+    GST_LOG_OBJECT (pad, "Event %" GST_PTR_FORMAT, event);
+
+    switch (GST_EVENT_TYPE (event)) {
+      case GST_EVENT_SEGMENT:
+        gst_event_copy_segment (event, &ctx->out_segment);
+        break;
+      case GST_EVENT_FLUSH_STOP:
+        GST_SPLITMUX_LOCK (splitmux);
+        locked = TRUE;
+        gst_segment_init (&ctx->out_segment, GST_FORMAT_UNDEFINED);
+        g_queue_foreach (&ctx->queued_bufs, (GFunc) mq_stream_buf_free, NULL);
+        g_queue_clear (&ctx->queued_bufs);
+        ctx->flushing = FALSE;
+        break;
+      case GST_EVENT_FLUSH_START:
+        GST_SPLITMUX_LOCK (splitmux);
+        locked = TRUE;
+        GST_LOG_OBJECT (pad, "Flush start");
+        ctx->flushing = TRUE;
+        GST_SPLITMUX_BROADCAST_OUTPUT (splitmux);
+        break;
+      case GST_EVENT_EOS:
+        GST_SPLITMUX_LOCK (splitmux);
+        locked = TRUE;
+        if (splitmux->output_state == SPLITMUX_OUTPUT_STATE_STOPPED)
+          goto beach;
+        ctx->out_eos = TRUE;
+        break;
+      case GST_EVENT_GAP:{
+        GstClockTime gap_ts;
+        GstClockTimeDiff rtime;
+
+        gst_event_parse_gap (event, &gap_ts, NULL);
+        if (gap_ts == GST_CLOCK_TIME_NONE)
+          break;
+
+        GST_SPLITMUX_LOCK (splitmux);
+        locked = TRUE;
+
+        if (splitmux->output_state == SPLITMUX_OUTPUT_STATE_STOPPED)
+          goto beach;
+
+        /* When we get a gap event on the
+         * reference stream and we're trying to open a
+         * new file, we need to store it until we get
+         * the buffer afterwards
+         */
+        if (ctx->is_reference &&
+            (splitmux->output_state != SPLITMUX_OUTPUT_STATE_OUTPUT_GOP)) {
+          GST_DEBUG_OBJECT (pad, "Storing GAP event until buffer arrives");
+          gst_event_replace (&ctx->pending_gap, event);
+          GST_SPLITMUX_UNLOCK (splitmux);
+          return GST_PAD_PROBE_HANDLED;
+        }
+
+        rtime = my_segment_to_running_time (&ctx->out_segment, gap_ts);
+
+        GST_LOG_OBJECT (pad, "Have GAP w/ ts %" GST_STIME_FORMAT,
+            GST_STIME_ARGS (rtime));
+
+        if (rtime != GST_CLOCK_STIME_NONE) {
+          ctx->out_running_time = rtime;
+          complete_or_wait_on_out (splitmux, ctx);
+        }
+        break;
+      }
+      case GST_EVENT_CUSTOM_DOWNSTREAM:{
+        const GstStructure *s;
+        GstClockTimeDiff ts = 0;
+
+        s = gst_event_get_structure (event);
+        if (!gst_structure_has_name (s, "splitmuxsink-unblock"))
+          break;
+
+        gst_structure_get_int64 (s, "timestamp", &ts);
+
+        GST_SPLITMUX_LOCK (splitmux);
+        locked = TRUE;
+
+        if (splitmux->output_state == SPLITMUX_OUTPUT_STATE_STOPPED)
+          goto beach;
+        ctx->out_running_time = ts;
+        if (!ctx->is_reference)
+          complete_or_wait_on_out (splitmux, ctx);
+        GST_SPLITMUX_UNLOCK (splitmux);
+        return GST_PAD_PROBE_DROP;
+      }
+      case GST_EVENT_CAPS:{
+        GstPad *peer;
+
+        if (!ctx->is_reference)
+          break;
+
+        peer = gst_pad_get_peer (pad);
+        if (peer) {
+          gboolean ok = gst_pad_send_event (peer, gst_event_ref (event));
+
+          gst_object_unref (peer);
+
+          if (ok)
+            break;
+
+        } else {
+          break;
+        }
+        /* This is in the case the muxer doesn't allow this change of caps */
+        GST_SPLITMUX_LOCK (splitmux);
+        locked = TRUE;
+        ctx->caps_change = TRUE;
+
+        if (splitmux->output_state != SPLITMUX_OUTPUT_STATE_START_NEXT_FILE) {
+          GST_DEBUG_OBJECT (splitmux,
+              "New caps were not accepted. Switching output file");
+          if (ctx->out_eos == FALSE) {
+            splitmux->output_state = SPLITMUX_OUTPUT_STATE_ENDING_FILE;
+            GST_SPLITMUX_BROADCAST_OUTPUT (splitmux);
+          }
+        }
+
+        /* Lets it fall through, if it fails again, then the muxer just can't
+         * support this format, but at least we have a closed file.
+         */
+        break;
+      }
+      default:
+        break;
+    }
+
+    /* We need to make sure events aren't passed
+     * until the muxer / sink are ready for it */
+    if (!locked)
+      GST_SPLITMUX_LOCK (splitmux);
+    if (!ctx->is_reference)
+      complete_or_wait_on_out (splitmux, ctx);
+    GST_SPLITMUX_UNLOCK (splitmux);
+
+    /* Don't try to forward sticky events before the next buffer is there
+     * because it would cause a new file to be created without the first
+     * buffer being available.
+     */
+    if (ctx->caps_change && GST_EVENT_IS_STICKY (event)) {
+      gst_event_unref (event);
+      return GST_PAD_PROBE_HANDLED;
+    } else
+      return GST_PAD_PROBE_PASS;
+  }
+
+  /* Allow everything through until the configured next stopping point */
+  GST_SPLITMUX_LOCK (splitmux);
+
+  buf_info = g_queue_pop_tail (&ctx->queued_bufs);
+  if (buf_info == NULL)
+    /* Can only happen due to a poorly timed flush */
+    goto beach;
+
+  /* If we have popped a keyframe, decrement the queued_gop count */
+  if (buf_info->keyframe && splitmux->queued_keyframes > 0)
+    splitmux->queued_keyframes--;
+
+  ctx->out_running_time = buf_info->run_ts;
+  ctx->cur_out_buffer = gst_pad_probe_info_get_buffer (info);
+
+  GST_LOG_OBJECT (splitmux,
+      "Pad %" GST_PTR_FORMAT " buffer with run TS %" GST_STIME_FORMAT
+      " size %" G_GUINT64_FORMAT,
+      pad, GST_STIME_ARGS (ctx->out_running_time), buf_info->buf_size);
+
+  ctx->caps_change = FALSE;
+
+  complete_or_wait_on_out (splitmux, ctx);
+
+  splitmux->muxed_out_bytes += buf_info->buf_size;
+
+#ifndef GST_DISABLE_GST_DEBUG
+  {
+    GstBuffer *buf = gst_pad_probe_info_get_buffer (info);
+    GST_LOG_OBJECT (pad, "Returning to pass buffer %" GST_PTR_FORMAT
+        " run ts %" GST_STIME_FORMAT, buf,
+        GST_STIME_ARGS (ctx->out_running_time));
+  }
+#endif
+
+  ctx->cur_out_buffer = NULL;
+  GST_SPLITMUX_UNLOCK (splitmux);
+
+  /* pending_gap is protected by the STREAM lock */
+  if (ctx->pending_gap) {
+    /* If we previously stored a gap event, send it now */
+    GstPad *peer = gst_pad_get_peer (ctx->srcpad);
+
+    GST_DEBUG_OBJECT (splitmux,
+        "Pad %" GST_PTR_FORMAT " sending pending GAP event", ctx->srcpad);
+
+    gst_pad_send_event (peer, ctx->pending_gap);
+    ctx->pending_gap = NULL;
+
+    gst_object_unref (peer);
+  }
+
+  mq_stream_buf_free (buf_info);
+
+  return GST_PAD_PROBE_PASS;
+
+beach:
+  GST_SPLITMUX_UNLOCK (splitmux);
+  return GST_PAD_PROBE_DROP;
+}
+
+static gboolean
+resend_sticky (GstPad * pad, GstEvent ** event, GstPad * peer)
+{
+  return gst_pad_send_event (peer, gst_event_ref (*event));
+}
+
+static void
+restart_context (MqStreamCtx * ctx, GstSplitMuxSink * splitmux)
+{
+  GstPad *peer = gst_pad_get_peer (ctx->srcpad);
+
+  gst_pad_sticky_events_foreach (ctx->srcpad,
+      (GstPadStickyEventsForeachFunction) (resend_sticky), peer);
+
+  /* Clear EOS flag if not actually EOS */
+  ctx->out_eos = GST_PAD_IS_EOS (ctx->srcpad);
+
+  gst_object_unref (peer);
+}
+
+/* Called with lock held when a fragment
+ * reaches EOS and it is time to restart
+ * a new fragment
+ */
+static void
+start_next_fragment (GstSplitMuxSink * splitmux, MqStreamCtx * ctx)
+{
+  GstElement *muxer, *sink;
+
+  /* 1 change to new file */
+  splitmux->switching_fragment = TRUE;
+
+  /* We need to drop the splitmux lock to acquire the state lock
+   * here and ensure there's no racy state change going on elsewhere */
+  muxer = gst_object_ref (splitmux->muxer);
+  sink = gst_object_ref (splitmux->active_sink);
+
+  GST_SPLITMUX_UNLOCK (splitmux);
+  GST_STATE_LOCK (splitmux);
+
+  gst_element_set_locked_state (muxer, TRUE);
+  gst_element_set_locked_state (sink, TRUE);
+  gst_element_set_state (muxer, GST_STATE_NULL);
+  gst_element_set_state (sink, GST_STATE_NULL);
+
+  GST_SPLITMUX_LOCK (splitmux);
+  if (splitmux->muxed_out_bytes > 0 || splitmux->fragment_id == 0)
+    set_next_filename (splitmux, ctx);
+  splitmux->muxed_out_bytes = 0;
+  GST_SPLITMUX_UNLOCK (splitmux);
+
+  gst_element_set_state (sink, GST_STATE_TARGET (splitmux));
+  gst_element_set_state (muxer, GST_STATE_TARGET (splitmux));
+  gst_element_set_locked_state (muxer, FALSE);
+  gst_element_set_locked_state (sink, FALSE);
+
+  gst_object_unref (sink);
+  gst_object_unref (muxer);
+
+  GST_SPLITMUX_LOCK (splitmux);
+  GST_STATE_UNLOCK (splitmux);
+  splitmux->switching_fragment = FALSE;
+  do_async_done (splitmux);
+
+  splitmux->ready_for_output = TRUE;
+
+  g_list_foreach (splitmux->contexts, (GFunc) restart_context, splitmux);
+
+  send_fragment_opened_closed_msg (splitmux, TRUE);
+
+  /* FIXME: Is this always the correct next state? */
+  splitmux->output_state = SPLITMUX_OUTPUT_STATE_AWAITING_COMMAND;
+  GST_SPLITMUX_BROADCAST_OUTPUT (splitmux);
+}
+
+static void
+bus_handler (GstBin * bin, GstMessage * message)
+{
+  GstSplitMuxSink *splitmux = GST_SPLITMUX_SINK (bin);
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_EOS:
+      /* If the state is draining out the current file, drop this EOS */
+      GST_SPLITMUX_LOCK (splitmux);
+
+      send_fragment_opened_closed_msg (splitmux, FALSE);
+
+      if (splitmux->output_state == SPLITMUX_OUTPUT_STATE_ENDING_FILE) {
+        GST_DEBUG_OBJECT (splitmux, "Caught EOS at end of fragment, dropping");
+        splitmux->output_state = SPLITMUX_OUTPUT_STATE_START_NEXT_FILE;
+        GST_SPLITMUX_BROADCAST_OUTPUT (splitmux);
+
+        gst_message_unref (message);
+        GST_SPLITMUX_UNLOCK (splitmux);
+        return;
+      } else {
+        GST_DEBUG_OBJECT (splitmux,
+            "Passing EOS message. Output state %d max_out_running_time %"
+            GST_STIME_FORMAT, splitmux->output_state,
+            GST_STIME_ARGS (splitmux->max_out_running_time));
+      }
+      GST_SPLITMUX_UNLOCK (splitmux);
+      break;
+    case GST_MESSAGE_ASYNC_START:
+    case GST_MESSAGE_ASYNC_DONE:
+      /* Ignore state changes from our children while switching */
+      if (splitmux->switching_fragment) {
+        if (GST_MESSAGE_SRC (message) == (GstObject *) splitmux->active_sink
+            || GST_MESSAGE_SRC (message) == (GstObject *) splitmux->muxer) {
+          GST_LOG_OBJECT (splitmux,
+              "Ignoring state change from child %" GST_PTR_FORMAT
+              " while switching", GST_MESSAGE_SRC (message));
+          gst_message_unref (message);
+          return;
+        }
+      }
+      break;
+    case GST_MESSAGE_WARNING:
+    {
+      GError *gerror = NULL;
+
+      gst_message_parse_warning (message, &gerror, NULL);
+
+      if (g_error_matches (gerror, GST_STREAM_ERROR, GST_STREAM_ERROR_FORMAT)) {
+        GList *item;
+        gboolean caps_change = FALSE;
+
+        GST_SPLITMUX_LOCK (splitmux);
+
+        for (item = splitmux->contexts; item; item = item->next) {
+          MqStreamCtx *ctx = item->data;
+
+          if (ctx->caps_change) {
+            caps_change = TRUE;
+            break;
+          }
+        }
+
+        GST_SPLITMUX_UNLOCK (splitmux);
+
+        if (caps_change) {
+          GST_LOG_OBJECT (splitmux,
+              "Ignoring warning change from child %" GST_PTR_FORMAT
+              " while switching caps", GST_MESSAGE_SRC (message));
+          gst_message_unref (message);
+          return;
+        }
+      }
+      break;
+    }
+    default:
+      break;
+  }
+
+  GST_BIN_CLASS (parent_class)->handle_message (bin, message);
+}
+
+static void
+ctx_set_unblock (MqStreamCtx * ctx)
+{
+  ctx->need_unblock = TRUE;
+}
+
+static gboolean
+need_new_fragment (GstSplitMuxSink * splitmux,
+    GstClockTime queued_time, GstClockTime queued_gop_time,
+    guint64 queued_bytes)
+{
+  guint64 thresh_bytes;
+  GstClockTime thresh_time;
+  gboolean check_robust_muxing;
+
+  GST_OBJECT_LOCK (splitmux);
+  thresh_bytes = splitmux->threshold_bytes;
+  thresh_time = splitmux->threshold_time;
+  check_robust_muxing = splitmux->use_robust_muxing
+      && splitmux->muxer_has_reserved_props;
+  GST_OBJECT_UNLOCK (splitmux);
+
+  /* Have we muxed anything into the new file at all? */
+  if (splitmux->fragment_total_bytes <= 0)
+    return FALSE;
+
+  /* User told us to split now */
+  if (g_atomic_int_get (&(splitmux->split_now)) == TRUE)
+    return TRUE;
+
+  if (thresh_bytes > 0 && queued_bytes >= thresh_bytes)
+    return TRUE;                /* Would overrun byte limit */
+
+  if (thresh_time > 0 && queued_time >= thresh_time)
+    return TRUE;                /* Would overrun byte limit */
+
+  /* Timecode-based threshold accounts for possible rounding errors:
+   * 5us should be bigger than all possible rounding errors but nowhere near
+   * big enough to skip to another frame */
+  if (splitmux->next_max_tc_time != GST_CLOCK_TIME_NONE &&
+      splitmux->reference_ctx->in_running_time >
+      splitmux->next_max_tc_time + 5 * GST_USECOND)
+    return TRUE;                /* Timecode threshold */
+
+  if (check_robust_muxing) {
+    GstClockTime mux_reserved_remain;
+
+    g_object_get (splitmux->muxer,
+        "reserved-duration-remaining", &mux_reserved_remain, NULL);
+
+    GST_LOG_OBJECT (splitmux,
+        "Muxer robust muxing report - %" G_GUINT64_FORMAT
+        " remaining. New GOP would enqueue %" G_GUINT64_FORMAT,
+        mux_reserved_remain, queued_gop_time);
+
+    if (queued_gop_time >= mux_reserved_remain) {
+      GST_INFO_OBJECT (splitmux,
+          "File is about to run out of header room - %" G_GUINT64_FORMAT
+          " remaining. New GOP would enqueue %" G_GUINT64_FORMAT
+          ". Switching to new file", mux_reserved_remain, queued_gop_time);
+      return TRUE;
+    }
+  }
+
+  /* Continue and mux this GOP */
+  return FALSE;
+}
+
+/* Called with splitmux lock held */
+/* Called when entering ProcessingCompleteGop state
+ * Assess if mq contents overflowed the current file
+ *   -> If yes, need to switch to new file
+ *   -> if no, set max_out_running_time to let this GOP in and
+ *      go to COLLECTING_GOP_START state
+ */
+static void
+handle_gathered_gop (GstSplitMuxSink * splitmux)
+{
+  guint64 queued_bytes;
+  GstClockTimeDiff queued_time = 0;
+  GstClockTimeDiff queued_gop_time = 0;
+  GstClockTimeDiff new_out_ts = splitmux->reference_ctx->in_running_time;
+  SplitMuxOutputCommand *cmd;
+
+  /* Assess if the multiqueue contents overflowed the current file */
+  /* When considering if a newly gathered GOP overflows
+   * the time limit for the file, only consider the running time of the
+   * reference stream. Other streams might have run ahead a little bit,
+   * but extra pieces won't be released to the muxer beyond the reference
+   * stream cut-off anyway - so it forms the limit. */
+  queued_bytes = splitmux->fragment_total_bytes + splitmux->gop_total_bytes;
+  queued_time = splitmux->reference_ctx->in_running_time;
+  /* queued_gop_time tracks how much unwritten data there is waiting to
+   * be written to this fragment including this GOP */
+  if (splitmux->reference_ctx->out_running_time != GST_CLOCK_STIME_NONE)
+    queued_gop_time =
+        splitmux->reference_ctx->in_running_time -
+        splitmux->reference_ctx->out_running_time;
+  else
+    queued_gop_time =
+        splitmux->reference_ctx->in_running_time - splitmux->gop_start_time;
+
+  GST_LOG_OBJECT (splitmux, " queued_bytes %" G_GUINT64_FORMAT, queued_bytes);
+
+  g_assert (queued_gop_time >= 0);
+  g_assert (queued_time >= splitmux->fragment_start_time);
+
+  queued_time -= splitmux->fragment_start_time;
+  if (queued_time < queued_gop_time)
+    queued_gop_time = queued_time;
+
+  /* Expand queued bytes estimate by muxer overhead */
+  queued_bytes += (queued_bytes * splitmux->mux_overhead);
+
+  GST_LOG_OBJECT (splitmux, "mq at TS %" GST_STIME_FORMAT
+      " bytes %" G_GUINT64_FORMAT, GST_STIME_ARGS (queued_time), queued_bytes);
+  if (splitmux->next_max_tc_time != GST_CLOCK_TIME_NONE) {
+    GST_LOG_OBJECT (splitmux,
+        "timecode mq TS %" GST_TIME_FORMAT " vs target %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (splitmux->reference_ctx->in_running_time),
+        GST_TIME_ARGS (splitmux->next_max_tc_time + 5 * GST_USECOND));
+  }
+
+  /* Check for overrun - have we output at least one byte and overrun
+   * either threshold? */
+  if (need_new_fragment (splitmux, queued_time, queued_gop_time, queued_bytes)) {
+    g_atomic_int_set (&(splitmux->split_now), FALSE);
+    /* Tell the output side to start a new fragment */
+    GST_INFO_OBJECT (splitmux,
+        "This GOP (dur %" GST_STIME_FORMAT
+        ") would overflow the fragment, Sending start_new_fragment cmd",
+        GST_STIME_ARGS (splitmux->reference_ctx->in_running_time -
+            splitmux->gop_start_time));
+    cmd = out_cmd_buf_new ();
+    cmd->start_new_fragment = TRUE;
+    g_queue_push_head (&splitmux->out_cmd_q, cmd);
+    GST_SPLITMUX_BROADCAST_OUTPUT (splitmux);
+
+    new_out_ts = splitmux->reference_ctx->in_running_time;
+    splitmux->fragment_start_time = splitmux->gop_start_time;
+    splitmux->fragment_total_bytes = 0;
+
+    if (request_next_keyframe (splitmux,
+            splitmux->reference_ctx->prev_in_keyframe) == FALSE) {
+      GST_WARNING_OBJECT (splitmux,
+          "Could not request a keyframe. Files may not split at the exact location they should");
+    }
+    gst_buffer_replace (&splitmux->reference_ctx->prev_in_keyframe, NULL);
+  }
+
+  /* And set up to collect the next GOP */
+  if (!splitmux->reference_ctx->in_eos) {
+    splitmux->input_state = SPLITMUX_INPUT_STATE_COLLECTING_GOP_START;
+    splitmux->gop_start_time = new_out_ts;
+  } else {
+    /* This is probably already the current state, but just in case: */
+    splitmux->input_state = SPLITMUX_INPUT_STATE_FINISHING_UP;
+    new_out_ts = GST_CLOCK_STIME_NONE;  /* EOS runs until forever */
+  }
+
+  /* And wake all input contexts to send a wake-up event */
+  g_list_foreach (splitmux->contexts, (GFunc) ctx_set_unblock, NULL);
+  GST_SPLITMUX_BROADCAST_INPUT (splitmux);
+
+  /* Now either way - either there was no overflow, or we requested a new fragment: release this GOP */
+  splitmux->fragment_total_bytes += splitmux->gop_total_bytes;
+
+  if (splitmux->gop_total_bytes > 0) {
+    GST_LOG_OBJECT (splitmux,
+        "Releasing GOP to output. Bytes in fragment now %" G_GUINT64_FORMAT
+        " time %" GST_STIME_FORMAT,
+        splitmux->fragment_total_bytes, GST_STIME_ARGS (queued_time));
+
+    /* Send this GOP to the output command queue */
+    cmd = out_cmd_buf_new ();
+    cmd->start_new_fragment = FALSE;
+    cmd->max_output_ts = new_out_ts;
+    GST_LOG_OBJECT (splitmux, "Sending GOP cmd to output for TS %"
+        GST_STIME_FORMAT, GST_STIME_ARGS (new_out_ts));
+    g_queue_push_head (&splitmux->out_cmd_q, cmd);
+
+    GST_SPLITMUX_BROADCAST_OUTPUT (splitmux);
+  }
+
+  splitmux->gop_total_bytes = 0;
+}
+
+/* Called with splitmux lock held */
+/* Called from each input pad when it is has all the pieces
+ * for a GOP or EOS, starting with the reference pad which has set the
+ * splitmux->max_in_running_time
+ */
+static void
+check_completed_gop (GstSplitMuxSink * splitmux, MqStreamCtx * ctx)
+{
+  GList *cur;
+  GstEvent *event;
+
+  /* On ENDING_FILE, the reference stream sends a command to start a new
+   * fragment, then releases the GOP for output in the new fragment.
+   *  If somes streams received no buffer during the last GOP that overran,
+   * because its next buffer has a timestamp bigger than
+   * ctx->max_in_running_time, its queue is empty. In that case the only
+   * way to wakeup the output thread is by injecting an event in the
+   * queue. This usually happen with subtitle streams.
+   * See https://bugzilla.gnome.org/show_bug.cgi?id=763711. */
+  if (ctx->need_unblock) {
+    GST_LOG_OBJECT (ctx->sinkpad, "Sending splitmuxsink-unblock event");
+    event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM |
+        GST_EVENT_TYPE_SERIALIZED,
+        gst_structure_new ("splitmuxsink-unblock", "timestamp",
+            G_TYPE_INT64, splitmux->max_in_running_time, NULL));
+
+    GST_SPLITMUX_UNLOCK (splitmux);
+    gst_pad_send_event (ctx->sinkpad, event);
+    GST_SPLITMUX_LOCK (splitmux);
+
+    ctx->need_unblock = FALSE;
+    GST_SPLITMUX_BROADCAST_INPUT (splitmux);
+    /* state may have changed while we were unlocked. Loop again if so */
+    if (splitmux->input_state != SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT)
+      return;
+  }
+
+  if (splitmux->input_state == SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT) {
+    gboolean ready = TRUE;
+
+    /* Iterate each pad, and check that the input running time is at least
+     * up to the reference running time, and if so handle the collected GOP */
+    GST_LOG_OBJECT (splitmux, "Checking GOP collected, Max in running time %"
+        GST_STIME_FORMAT " ctx %p",
+        GST_STIME_ARGS (splitmux->max_in_running_time), ctx);
+    for (cur = g_list_first (splitmux->contexts); cur != NULL;
+        cur = g_list_next (cur)) {
+      MqStreamCtx *tmpctx = (MqStreamCtx *) (cur->data);
+
+      GST_LOG_OBJECT (splitmux,
+          "Context %p (src pad %" GST_PTR_FORMAT ") TS %" GST_STIME_FORMAT
+          " EOS %d", tmpctx, tmpctx->srcpad,
+          GST_STIME_ARGS (tmpctx->in_running_time), tmpctx->in_eos);
+
+      if (splitmux->max_in_running_time != GST_CLOCK_STIME_NONE &&
+          tmpctx->in_running_time < splitmux->max_in_running_time &&
+          !tmpctx->in_eos) {
+        GST_LOG_OBJECT (splitmux,
+            "Context %p (src pad %" GST_PTR_FORMAT ") not ready. We'll sleep",
+            tmpctx, tmpctx->srcpad);
+        ready = FALSE;
+        break;
+      }
+    }
+    if (ready) {
+      GST_DEBUG_OBJECT (splitmux,
+          "Collected GOP is complete. Processing (ctx %p)", ctx);
+      /* All pads have a complete GOP, release it into the multiqueue */
+      handle_gathered_gop (splitmux);
+    }
+  }
+
+  /* If upstream reached EOS we are not expecting more data, no need to wait
+   * here. */
+  if (ctx->in_eos)
+    return;
+
+  /* Some pad is not yet ready, or GOP is being pushed
+   * either way, sleep and wait to get woken */
+  while (splitmux->input_state == SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT &&
+      !ctx->flushing &&
+      (ctx->in_running_time >= splitmux->max_in_running_time) &&
+      (splitmux->max_in_running_time != GST_CLOCK_STIME_NONE)) {
+
+    GST_LOG_OBJECT (splitmux, "Sleeping for GOP collection (ctx %p)", ctx);
+    GST_SPLITMUX_WAIT_INPUT (splitmux);
+    GST_LOG_OBJECT (splitmux, "Done waiting for complete GOP (ctx %p)", ctx);
+  }
+}
+
+static GstPadProbeReturn
+handle_mq_input (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
+{
+  GstSplitMuxSink *splitmux = ctx->splitmux;
+  GstBuffer *buf;
+  MqStreamBuf *buf_info = NULL;
+  GstClockTime ts;
+  gboolean loop_again;
+  gboolean keyframe = FALSE;
+
+  GST_LOG_OBJECT (pad, "Fired probe type 0x%x", info->type);
+
+  /* FIXME: Handle buffer lists, until then make it clear they won't work */
+  if (info->type & GST_PAD_PROBE_TYPE_BUFFER_LIST) {
+    g_warning ("Buffer list handling not implemented");
+    return GST_PAD_PROBE_DROP;
+  }
+  if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM ||
+      info->type & GST_PAD_PROBE_TYPE_EVENT_FLUSH) {
+    GstEvent *event = gst_pad_probe_info_get_event (info);
+
+    GST_LOG_OBJECT (pad, "Event %" GST_PTR_FORMAT, event);
+
+    switch (GST_EVENT_TYPE (event)) {
+      case GST_EVENT_SEGMENT:
+        gst_event_copy_segment (event, &ctx->in_segment);
+        break;
+      case GST_EVENT_FLUSH_STOP:
+        GST_SPLITMUX_LOCK (splitmux);
+        gst_segment_init (&ctx->in_segment, GST_FORMAT_UNDEFINED);
+        ctx->in_eos = FALSE;
+        ctx->in_running_time = GST_CLOCK_STIME_NONE;
+        GST_SPLITMUX_UNLOCK (splitmux);
+        break;
+      case GST_EVENT_EOS:
+        GST_SPLITMUX_LOCK (splitmux);
+        ctx->in_eos = TRUE;
+
+        if (splitmux->input_state == SPLITMUX_INPUT_STATE_STOPPED)
+          goto beach;
+
+        if (ctx->is_reference) {
+          GST_INFO_OBJECT (splitmux, "Got Reference EOS. Finishing up");
+          /* check_completed_gop will act as if this is a new keyframe with infinite timestamp */
+          splitmux->input_state = SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT;
+          /* Wake up other input pads to collect this GOP */
+          GST_SPLITMUX_BROADCAST_INPUT (splitmux);
+          check_completed_gop (splitmux, ctx);
+        } else if (splitmux->input_state ==
+            SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT) {
+          /* If we are waiting for a GOP to be completed (ie, for aux
+           * pads to catch up), then this pad is complete, so check
+           * if the whole GOP is.
+           */
+          check_completed_gop (splitmux, ctx);
+        }
+        GST_SPLITMUX_UNLOCK (splitmux);
+        break;
+      case GST_EVENT_GAP:{
+        GstClockTime gap_ts;
+        GstClockTimeDiff rtime;
+
+        gst_event_parse_gap (event, &gap_ts, NULL);
+        if (gap_ts == GST_CLOCK_TIME_NONE)
+          break;
+
+        GST_SPLITMUX_LOCK (splitmux);
+
+        if (splitmux->input_state == SPLITMUX_INPUT_STATE_STOPPED)
+          goto beach;
+        rtime = my_segment_to_running_time (&ctx->in_segment, gap_ts);
+
+        GST_LOG_OBJECT (pad, "Have GAP w/ ts %" GST_STIME_FORMAT,
+            GST_STIME_ARGS (rtime));
+
+        if (ctx->is_reference
+            && splitmux->fragment_start_time == GST_CLOCK_STIME_NONE) {
+          splitmux->gop_start_time = splitmux->fragment_start_time = rtime;
+          GST_LOG_OBJECT (splitmux, "Mux start time now %" GST_STIME_FORMAT,
+              GST_STIME_ARGS (splitmux->fragment_start_time));
+          /* Also take this as the first start time when starting up,
+           * so that we start counting overflow from the first frame */
+          if (!GST_CLOCK_STIME_IS_VALID (splitmux->max_in_running_time))
+            splitmux->max_in_running_time = splitmux->fragment_start_time;
+        }
+
+        GST_SPLITMUX_UNLOCK (splitmux);
+        break;
+      }
+      default:
+        break;
+    }
+    return GST_PAD_PROBE_PASS;
+  } else if (info->type & GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM) {
+    switch (GST_QUERY_TYPE (GST_QUERY (info->data))) {
+      case GST_QUERY_ALLOCATION:
+        return GST_PAD_PROBE_DROP;
+      default:
+        return GST_PAD_PROBE_PASS;
+    }
+  }
+
+  buf = gst_pad_probe_info_get_buffer (info);
+  buf_info = mq_stream_buf_new ();
+
+  if (GST_BUFFER_PTS_IS_VALID (buf))
+    ts = GST_BUFFER_PTS (buf);
+  else
+    ts = GST_BUFFER_DTS (buf);
+
+  GST_LOG_OBJECT (pad, "Buffer TS is %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
+
+  GST_SPLITMUX_LOCK (splitmux);
+
+  if (splitmux->input_state == SPLITMUX_INPUT_STATE_STOPPED)
+    goto beach;
+
+  /* If this buffer has a timestamp, advance the input timestamp of the
+   * stream */
+  if (GST_CLOCK_TIME_IS_VALID (ts)) {
+    GstClockTimeDiff running_time =
+        my_segment_to_running_time (&ctx->in_segment, ts);
+
+    GST_LOG_OBJECT (pad, "Buffer running TS is %" GST_STIME_FORMAT,
+        GST_STIME_ARGS (running_time));
+
+    if (GST_CLOCK_STIME_IS_VALID (running_time)
+        && running_time > ctx->in_running_time)
+      ctx->in_running_time = running_time;
+  }
+
+  /* Try to make sure we have a valid running time */
+  if (!GST_CLOCK_STIME_IS_VALID (ctx->in_running_time)) {
+    ctx->in_running_time =
+        my_segment_to_running_time (&ctx->in_segment, ctx->in_segment.start);
+  }
+
+  GST_LOG_OBJECT (pad, "in running time now %" GST_STIME_FORMAT,
+      GST_STIME_ARGS (ctx->in_running_time));
+
+  buf_info->run_ts = ctx->in_running_time;
+  buf_info->buf_size = gst_buffer_get_size (buf);
+  buf_info->duration = GST_BUFFER_DURATION (buf);
+
+  /* initialize fragment_start_time */
+  if (ctx->is_reference
+      && splitmux->fragment_start_time == GST_CLOCK_STIME_NONE) {
+    splitmux->gop_start_time = splitmux->fragment_start_time = buf_info->run_ts;
+    GST_LOG_OBJECT (splitmux, "Mux start time now %" GST_STIME_FORMAT,
+        GST_STIME_ARGS (splitmux->fragment_start_time));
+    gst_buffer_replace (&ctx->prev_in_keyframe, buf);
+
+    /* Also take this as the first start time when starting up,
+     * so that we start counting overflow from the first frame */
+    if (!GST_CLOCK_STIME_IS_VALID (splitmux->max_in_running_time))
+      splitmux->max_in_running_time = splitmux->fragment_start_time;
+    if (request_next_keyframe (splitmux, ctx->prev_in_keyframe) == FALSE) {
+      GST_WARNING_OBJECT (splitmux,
+          "Could not request a keyframe. Files may not split at the exact location they should");
+    }
+    gst_buffer_replace (&splitmux->reference_ctx->prev_in_keyframe, NULL);
+  }
+
+  GST_DEBUG_OBJECT (pad, "Buf TS %" GST_STIME_FORMAT
+      " total GOP bytes %" G_GUINT64_FORMAT,
+      GST_STIME_ARGS (buf_info->run_ts), splitmux->gop_total_bytes);
+
+  loop_again = TRUE;
+  do {
+    if (ctx->flushing)
+      break;
+
+    switch (splitmux->input_state) {
+      case SPLITMUX_INPUT_STATE_COLLECTING_GOP_START:
+        if (ctx->is_reference) {
+          /* If a keyframe, we have a complete GOP */
+          if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ||
+              !GST_CLOCK_STIME_IS_VALID (ctx->in_running_time) ||
+              splitmux->max_in_running_time >= ctx->in_running_time) {
+            /* Pass this buffer through */
+            loop_again = FALSE;
+            /* Allow other input pads to catch up to here too */
+            splitmux->max_in_running_time = ctx->in_running_time;
+            GST_SPLITMUX_BROADCAST_INPUT (splitmux);
+            break;
+          }
+          GST_INFO_OBJECT (pad,
+              "Have keyframe with running time %" GST_STIME_FORMAT,
+              GST_STIME_ARGS (ctx->in_running_time));
+          keyframe = TRUE;
+          splitmux->input_state = SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT;
+          splitmux->max_in_running_time = ctx->in_running_time;
+          /* Wake up other input pads to collect this GOP */
+          GST_SPLITMUX_BROADCAST_INPUT (splitmux);
+          check_completed_gop (splitmux, ctx);
+          /* Store this new keyframe to remember the start of GOP */
+          gst_buffer_replace (&ctx->prev_in_keyframe, buf);
+        } else {
+          /* Pass this buffer if the reference ctx is far enough ahead */
+          if (ctx->in_running_time < splitmux->max_in_running_time) {
+            loop_again = FALSE;
+            break;
+          }
+
+          /* We're still waiting for a keyframe on the reference pad, sleep */
+          GST_LOG_OBJECT (pad, "Sleeping for GOP start");
+          GST_SPLITMUX_WAIT_INPUT (splitmux);
+          GST_LOG_OBJECT (pad,
+              "Done sleeping for GOP start input state now %d",
+              splitmux->input_state);
+        }
+        break;
+      case SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT:{
+        /* We're collecting a GOP. If this is the reference context,
+         * we need to check if this is a keyframe that marks the start
+         * of the next GOP. If it is, it marks the end of the GOP we're
+         * collecting, so sleep and wait until all the other pads also
+         * reach that timestamp - at which point, we have an entire GOP
+         * and either go to ENDING_FILE or release this GOP to the muxer and
+         * go back to COLLECT_GOP_START. */
+
+        /* If we overran the target timestamp, it might be time to process
+         * the GOP, otherwise bail out for more data
+         */
+        GST_LOG_OBJECT (pad,
+            "Checking TS %" GST_STIME_FORMAT " against max %"
+            GST_STIME_FORMAT, GST_STIME_ARGS (ctx->in_running_time),
+            GST_STIME_ARGS (splitmux->max_in_running_time));
+
+        if (ctx->in_running_time < splitmux->max_in_running_time) {
+          loop_again = FALSE;
+          break;
+        }
+
+        GST_LOG_OBJECT (pad,
+            "Collected last packet of GOP. Checking other pads");
+        check_completed_gop (splitmux, ctx);
+        break;
+      }
+      case SPLITMUX_INPUT_STATE_FINISHING_UP:
+        loop_again = FALSE;
+        break;
+      default:
+        loop_again = FALSE;
+        break;
+    }
+  }
+  while (loop_again);
+
+  if (keyframe) {
+    splitmux->queued_keyframes++;
+    buf_info->keyframe = TRUE;
+  }
+
+  /* Update total input byte counter for overflow detect */
+  splitmux->gop_total_bytes += buf_info->buf_size;
+
+  /* Now add this buffer to the queue just before returning */
+  g_queue_push_head (&ctx->queued_bufs, buf_info);
+
+  GST_LOG_OBJECT (pad, "Returning to queue buffer %" GST_PTR_FORMAT
+      " run ts %" GST_STIME_FORMAT, buf, GST_STIME_ARGS (ctx->in_running_time));
+
+  GST_SPLITMUX_UNLOCK (splitmux);
+  return GST_PAD_PROBE_PASS;
+
+beach:
+  GST_SPLITMUX_UNLOCK (splitmux);
+  if (buf_info)
+    mq_stream_buf_free (buf_info);
+  return GST_PAD_PROBE_PASS;
+}
+
+static void
+grow_blocked_queues (GstSplitMuxSink * splitmux)
+{
+  GList *cur;
+
+  /* Scan other queues for full-ness and grow them */
+  for (cur = g_list_first (splitmux->contexts);
+      cur != NULL; cur = g_list_next (cur)) {
+    MqStreamCtx *tmpctx = (MqStreamCtx *) (cur->data);
+    guint cur_limit;
+    guint cur_len = g_queue_get_length (&tmpctx->queued_bufs);
+
+    g_object_get (tmpctx->q, "max-size-buffers", &cur_limit, NULL);
+    GST_LOG_OBJECT (tmpctx->q, "Queue len %u", cur_len);
+
+    if (cur_len >= cur_limit) {
+      cur_limit = cur_len + 1;
+      GST_DEBUG_OBJECT (tmpctx->q,
+          "Queue overflowed and needs enlarging. Growing to %u buffers",
+          cur_limit);
+      g_object_set (tmpctx->q, "max-size-buffers", cur_limit, NULL);
+    }
+  }
+}
+
+static void
+handle_q_underrun (GstElement * q, gpointer user_data)
+{
+  MqStreamCtx *ctx = (MqStreamCtx *) (user_data);
+  GstSplitMuxSink *splitmux = ctx->splitmux;
+
+  GST_SPLITMUX_LOCK (splitmux);
+  GST_DEBUG_OBJECT (q,
+      "Queue reported underrun with %d keyframes and %d cmds enqueued",
+      splitmux->queued_keyframes, g_queue_get_length (&splitmux->out_cmd_q));
+  grow_blocked_queues (splitmux);
+  GST_SPLITMUX_UNLOCK (splitmux);
+}
+
+static void
+handle_q_overrun (GstElement * q, gpointer user_data)
+{
+  MqStreamCtx *ctx = (MqStreamCtx *) (user_data);
+  GstSplitMuxSink *splitmux = ctx->splitmux;
+  gboolean allow_grow = FALSE;
+
+  GST_SPLITMUX_LOCK (splitmux);
+  GST_DEBUG_OBJECT (q,
+      "Queue reported overrun with %d keyframes and %d cmds enqueued",
+      splitmux->queued_keyframes, g_queue_get_length (&splitmux->out_cmd_q));
+
+  if (splitmux->queued_keyframes < 2) {
+    /* Less than a full GOP queued, grow the queue */
+    allow_grow = TRUE;
+  } else if (g_queue_get_length (&splitmux->out_cmd_q) < 1) {
+    allow_grow = TRUE;
+  } else {
+    /* If another queue is starved, grow */
+    GList *cur;
+    for (cur = g_list_first (splitmux->contexts);
+        cur != NULL; cur = g_list_next (cur)) {
+      MqStreamCtx *tmpctx = (MqStreamCtx *) (cur->data);
+      if (tmpctx != ctx && g_queue_get_length (&tmpctx->queued_bufs) < 1) {
+        allow_grow = TRUE;
+      }
+    }
+  }
+  GST_SPLITMUX_UNLOCK (splitmux);
+
+  if (allow_grow) {
+    guint cur_limit;
+
+    g_object_get (q, "max-size-buffers", &cur_limit, NULL);
+    cur_limit++;
+
+    GST_DEBUG_OBJECT (q,
+        "Queue overflowed and needs enlarging. Growing to %u buffers",
+        cur_limit);
+
+    g_object_set (q, "max-size-buffers", cur_limit, NULL);
+  }
+}
+
+static GstPad *
+gst_splitmux_sink_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
+{
+  GstSplitMuxSink *splitmux = (GstSplitMuxSink *) element;
+  GstPadTemplate *mux_template = NULL;
+  GstPad *res = NULL;
+  GstElement *q;
+  GstPad *q_sink = NULL, *q_src = NULL;
+  gchar *gname;
+  gboolean is_video = FALSE;
+  MqStreamCtx *ctx;
+
+  GST_DEBUG_OBJECT (element, "templ:%s, name:%s", templ->name_template, name);
+
+  GST_SPLITMUX_LOCK (splitmux);
+  if (!create_muxer (splitmux))
+    goto fail;
+
+  if (templ->name_template) {
+    if (g_str_equal (templ->name_template, "video")) {
+      if (splitmux->have_video)
+        goto already_have_video;
+
+      /* FIXME: Look for a pad template with matching caps, rather than by name */
+      mux_template =
+          gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS
+          (splitmux->muxer), "video_%u");
+
+      /* Fallback to find sink pad templates named 'video' (flvmux) */
+      if (!mux_template) {
+        mux_template =
+            gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS
+            (splitmux->muxer), "video");
+      }
+      is_video = TRUE;
+      name = NULL;
+    } else {
+      mux_template =
+          gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS
+          (splitmux->muxer), templ->name_template);
+
+      /* Fallback to find sink pad templates named 'audio' (flvmux) */
+      if (!mux_template) {
+        mux_template =
+            gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS
+            (splitmux->muxer), "audio");
+        name = NULL;
+      }
+    }
+    if (mux_template == NULL) {
+      /* Fallback to find sink pad templates named 'sink_%d' (mpegtsmux) */
+      mux_template =
+          gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS
+          (splitmux->muxer), "sink_%d");
+      name = NULL;
+    }
+  }
+
+  res = gst_element_request_pad (splitmux->muxer, mux_template, name, caps);
+  if (res == NULL)
+    goto fail;
+
+  if (is_video)
+    gname = g_strdup ("video");
+  else if (name == NULL)
+    gname = gst_pad_get_name (res);
+  else
+    gname = g_strdup (name);
+
+  if ((q = create_element (splitmux, "queue", NULL, FALSE)) == NULL)
+    goto fail;
+
+  gst_element_set_state (q, GST_STATE_TARGET (splitmux));
+
+  g_object_set (q, "max-size-bytes", 0, "max-size-time", (guint64) (0),
+      "max-size-buffers", 5, NULL);
+
+  q_sink = gst_element_get_static_pad (q, "sink");
+  q_src = gst_element_get_static_pad (q, "src");
+
+  if (gst_pad_link (q_src, res) != GST_PAD_LINK_OK) {
+    gst_element_release_request_pad (splitmux->muxer, res);
+    gst_object_unref (GST_OBJECT (res));
+    goto fail;
+  }
+
+  gst_object_unref (GST_OBJECT (res));
+
+  ctx = mq_stream_ctx_new (splitmux);
+  /* Context holds a ref: */
+  ctx->q = gst_object_ref (q);
+  ctx->srcpad = q_src;
+  ctx->sinkpad = q_sink;
+  ctx->q_overrun_id =
+      g_signal_connect (q, "overrun", (GCallback) handle_q_overrun, ctx);
+  g_signal_connect (q, "underrun", (GCallback) handle_q_underrun, ctx);
+
+  mq_stream_ctx_ref (ctx);
+  ctx->src_pad_block_id =
+      gst_pad_add_probe (q_src,
+      GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM | GST_PAD_PROBE_TYPE_EVENT_FLUSH,
+      (GstPadProbeCallback) handle_mq_output, ctx, (GDestroyNotify)
+      _pad_block_destroy_src_notify);
+  if (is_video && splitmux->reference_ctx != NULL) {
+    splitmux->reference_ctx->is_reference = FALSE;
+    splitmux->reference_ctx = NULL;
+  }
+  if (splitmux->reference_ctx == NULL) {
+    splitmux->reference_ctx = ctx;
+    ctx->is_reference = TRUE;
+  }
+
+  res = gst_ghost_pad_new_from_template (gname, q_sink, templ);
+  g_object_set_qdata ((GObject *) (res), PAD_CONTEXT, ctx);
+
+  mq_stream_ctx_ref (ctx);
+  ctx->sink_pad_block_id =
+      gst_pad_add_probe (q_sink,
+      GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM | GST_PAD_PROBE_TYPE_EVENT_FLUSH |
+      GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM,
+      (GstPadProbeCallback) handle_mq_input, ctx, (GDestroyNotify)
+      _pad_block_destroy_sink_notify);
+
+  GST_DEBUG_OBJECT (splitmux, "Request pad %" GST_PTR_FORMAT
+      " feeds queue pad %" GST_PTR_FORMAT, res, q_sink);
+
+  splitmux->contexts = g_list_prepend (splitmux->contexts, ctx);
+
+  g_free (gname);
+
+  if (is_video)
+    splitmux->have_video = TRUE;
+
+  gst_pad_set_active (res, TRUE);
+  gst_element_add_pad (element, res);
+
+  GST_SPLITMUX_UNLOCK (splitmux);
+
+  return res;
+fail:
+  GST_SPLITMUX_UNLOCK (splitmux);
+
+  if (q_sink)
+    gst_object_unref (q_sink);
+  if (q_src)
+    gst_object_unref (q_src);
+  return NULL;
+already_have_video:
+  GST_DEBUG_OBJECT (splitmux, "video sink pad already requested");
+  GST_SPLITMUX_UNLOCK (splitmux);
+  return NULL;
+}
+
+static void
+gst_splitmux_sink_release_pad (GstElement * element, GstPad * pad)
+{
+  GstSplitMuxSink *splitmux = (GstSplitMuxSink *) element;
+  GstPad *muxpad = NULL;
+  MqStreamCtx *ctx =
+      (MqStreamCtx *) (g_object_get_qdata ((GObject *) (pad), PAD_CONTEXT));
+
+  GST_SPLITMUX_LOCK (splitmux);
+
+  if (splitmux->muxer == NULL)
+    goto fail;                  /* Elements don't exist yet - nothing to release */
+
+  GST_INFO_OBJECT (pad, "releasing request pad");
+
+  muxpad = gst_pad_get_peer (ctx->srcpad);
+
+  /* Remove the context from our consideration */
+  splitmux->contexts = g_list_remove (splitmux->contexts, ctx);
+
+  if (ctx->sink_pad_block_id)
+    gst_pad_remove_probe (ctx->sinkpad, ctx->sink_pad_block_id);
+
+  if (ctx->src_pad_block_id)
+    gst_pad_remove_probe (ctx->srcpad, ctx->src_pad_block_id);
+
+  /* Can release the context now */
+  mq_stream_ctx_unref (ctx);
+  if (ctx == splitmux->reference_ctx)
+    splitmux->reference_ctx = NULL;
+
+  /* Release and free the muxer input */
+  if (muxpad) {
+    gst_element_release_request_pad (splitmux->muxer, muxpad);
+    gst_object_unref (muxpad);
+  }
+
+  if (GST_PAD_PAD_TEMPLATE (pad) &&
+      g_str_equal (GST_PAD_TEMPLATE_NAME_TEMPLATE (GST_PAD_PAD_TEMPLATE
+              (pad)), "video"))
+    splitmux->have_video = FALSE;
+
+  gst_element_remove_pad (element, pad);
+
+  /* Reset the internal elements only after all request pads are released */
+  if (splitmux->contexts == NULL)
+    gst_splitmux_reset (splitmux);
+
+fail:
+  GST_SPLITMUX_UNLOCK (splitmux);
+}
+
+static GstElement *
+create_element (GstSplitMuxSink * splitmux,
+    const gchar * factory, const gchar * name, gboolean locked)
+{
+  GstElement *ret = gst_element_factory_make (factory, name);
+  if (ret == NULL) {
+    g_warning ("Failed to create %s - splitmuxsink will not work", name);
+    return NULL;
+  }
+
+  if (locked) {
+    /* Ensure the sink starts in locked state and NULL - it will be changed
+     * by the filename setting code */
+    gst_element_set_locked_state (ret, TRUE);
+    gst_element_set_state (ret, GST_STATE_NULL);
+  }
+
+  if (!gst_bin_add (GST_BIN (splitmux), ret)) {
+    g_warning ("Could not add %s element - splitmuxsink will not work", name);
+    gst_object_unref (ret);
+    return NULL;
+  }
+
+  return ret;
+}
+
+static gboolean
+create_muxer (GstSplitMuxSink * splitmux)
+{
+  /* Create internal elements */
+  if (splitmux->muxer == NULL) {
+    GstElement *provided_muxer = NULL;
+
+    GST_OBJECT_LOCK (splitmux);
+    if (splitmux->provided_muxer != NULL)
+      provided_muxer = gst_object_ref (splitmux->provided_muxer);
+    GST_OBJECT_UNLOCK (splitmux);
+
+    if (provided_muxer == NULL) {
+      if ((splitmux->muxer =
+              create_element (splitmux, "mp4mux", "muxer", FALSE)) == NULL)
+        goto fail;
+    } else {
+      /* Ensure it's not in locked state (we might be reusing an old element) */
+      gst_element_set_locked_state (provided_muxer, FALSE);
+      if (!gst_bin_add (GST_BIN (splitmux), provided_muxer)) {
+        g_warning ("Could not add muxer element - splitmuxsink will not work");
+        gst_object_unref (provided_muxer);
+        goto fail;
+      }
+
+      splitmux->muxer = provided_muxer;
+      gst_object_unref (provided_muxer);
+    }
+
+    if (splitmux->use_robust_muxing) {
+      update_muxer_properties (splitmux);
+    }
+  }
+
+  return TRUE;
+fail:
+  return FALSE;
+}
+
+static GstElement *
+find_sink (GstElement * e)
+{
+  GstElement *res = NULL;
+  GstIterator *iter;
+  gboolean done = FALSE;
+  GValue data = { 0, };
+
+  if (!GST_IS_BIN (e))
+    return e;
+
+  if (g_object_class_find_property (G_OBJECT_GET_CLASS (e), "location") != NULL)
+    return e;
+
+  iter = gst_bin_iterate_sinks (GST_BIN (e));
+  while (!done) {
+    switch (gst_iterator_next (iter, &data)) {
+      case GST_ITERATOR_OK:
+      {
+        GstElement *child = g_value_get_object (&data);
+        if (g_object_class_find_property (G_OBJECT_GET_CLASS (child),
+                "location") != NULL) {
+          res = child;
+          done = TRUE;
+        }
+        g_value_reset (&data);
+        break;
+      }
+      case GST_ITERATOR_RESYNC:
+        gst_iterator_resync (iter);
+        break;
+      case GST_ITERATOR_DONE:
+        done = TRUE;
+        break;
+      case GST_ITERATOR_ERROR:
+        g_assert_not_reached ();
+        break;
+    }
+  }
+  g_value_unset (&data);
+  gst_iterator_free (iter);
+
+  return res;
+}
+
+static gboolean
+create_sink (GstSplitMuxSink * splitmux)
+{
+  GstElement *provided_sink = NULL;
+
+  if (splitmux->active_sink == NULL) {
+
+    GST_OBJECT_LOCK (splitmux);
+    if (splitmux->provided_sink != NULL)
+      provided_sink = gst_object_ref (splitmux->provided_sink);
+    GST_OBJECT_UNLOCK (splitmux);
+
+    if (provided_sink == NULL) {
+      if ((splitmux->sink =
+              create_element (splitmux, DEFAULT_SINK, "sink", TRUE)) == NULL)
+        goto fail;
+      splitmux->active_sink = splitmux->sink;
+    } else {
+      /* Ensure the sink starts in locked state and NULL - it will be changed
+       * by the filename setting code */
+      gst_element_set_locked_state (provided_sink, TRUE);
+      gst_element_set_state (provided_sink, GST_STATE_NULL);
+      if (!gst_bin_add (GST_BIN (splitmux), provided_sink)) {
+        g_warning ("Could not add sink elements - splitmuxsink will not work");
+        gst_object_unref (provided_sink);
+        goto fail;
+      }
+
+      splitmux->active_sink = provided_sink;
+
+      /* The bin holds a ref now, we can drop our tmp ref */
+      gst_object_unref (provided_sink);
+
+      /* Find the sink element */
+      splitmux->sink = find_sink (splitmux->active_sink);
+      if (splitmux->sink == NULL) {
+        g_warning
+            ("Could not locate sink element in provided sink - splitmuxsink will not work");
+        goto fail;
+      }
+    }
+
+#if 1
+    if (g_object_class_find_property (G_OBJECT_GET_CLASS (splitmux->sink),
+            "async") != NULL) {
+      /* async child elements are causing state change races and weird
+       * failures, so let's try and turn that off */
+      g_object_set (splitmux->sink, "async", FALSE, NULL);
+    }
+#endif
+
+    if (!gst_element_link (splitmux->muxer, splitmux->active_sink)) {
+      g_warning ("Failed to link muxer and sink- splitmuxsink will not work");
+      goto fail;
+    }
+  }
+
+  return TRUE;
+fail:
+  return FALSE;
+}
+
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#endif
+static void
+set_next_filename (GstSplitMuxSink * splitmux, MqStreamCtx * ctx)
+{
+  gchar *fname = NULL;
+  GstSample *sample;
+  GstCaps *caps;
+
+  gst_splitmux_sink_ensure_max_files (splitmux);
+
+  if (ctx->cur_out_buffer == NULL) {
+    GST_WARNING_OBJECT (splitmux, "Starting next file without buffer");
+  }
+
+  caps = gst_pad_get_current_caps (ctx->srcpad);
+  sample = gst_sample_new (ctx->cur_out_buffer, caps, &ctx->out_segment, NULL);
+  g_signal_emit (splitmux, signals[SIGNAL_FORMAT_LOCATION_FULL], 0,
+      splitmux->fragment_id, sample, &fname);
+  gst_sample_unref (sample);
+  if (caps)
+    gst_caps_unref (caps);
+
+  if (fname == NULL) {
+    /* Fallback to the old signal if the new one returned nothing */
+    g_signal_emit (splitmux, signals[SIGNAL_FORMAT_LOCATION], 0,
+        splitmux->fragment_id, &fname);
+  }
+
+  if (!fname)
+    fname = splitmux->location ?
+        g_strdup_printf (splitmux->location, splitmux->fragment_id) : NULL;
+
+  if (fname) {
+    GST_INFO_OBJECT (splitmux, "Setting file to %s", fname);
+    g_object_set (splitmux->sink, "location", fname, NULL);
+    g_free (fname);
+
+    splitmux->fragment_id++;
+  }
+}
+
+static void
+do_async_start (GstSplitMuxSink * splitmux)
+{
+  GstMessage *message;
+
+  if (!splitmux->need_async_start) {
+    GST_INFO_OBJECT (splitmux, "no async_start needed");
+    return;
+  }
+
+  splitmux->async_pending = TRUE;
+
+  GST_INFO_OBJECT (splitmux, "Sending async_start message");
+  message = gst_message_new_async_start (GST_OBJECT_CAST (splitmux));
+  GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST
+      (splitmux), message);
+}
+
+static void
+do_async_done (GstSplitMuxSink * splitmux)
+{
+  GstMessage *message;
+
+  if (splitmux->async_pending) {
+    GST_INFO_OBJECT (splitmux, "Sending async_done message");
+    message =
+        gst_message_new_async_done (GST_OBJECT_CAST (splitmux),
+        GST_CLOCK_TIME_NONE);
+    GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST
+        (splitmux), message);
+
+    splitmux->async_pending = FALSE;
+  }
+
+  splitmux->need_async_start = FALSE;
+}
+
+static GstStateChangeReturn
+gst_splitmux_sink_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstSplitMuxSink *splitmux = (GstSplitMuxSink *) element;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:{
+      GST_SPLITMUX_LOCK (splitmux);
+      if (!create_muxer (splitmux) || !create_sink (splitmux)) {
+        ret = GST_STATE_CHANGE_FAILURE;
+        GST_SPLITMUX_UNLOCK (splitmux);
+        goto beach;
+      }
+      GST_SPLITMUX_UNLOCK (splitmux);
+      splitmux->fragment_id = 0;
+      break;
+    }
+    case GST_STATE_CHANGE_READY_TO_PAUSED:{
+      GST_SPLITMUX_LOCK (splitmux);
+      /* Start by collecting one input on each pad */
+      splitmux->input_state = SPLITMUX_INPUT_STATE_COLLECTING_GOP_START;
+      splitmux->output_state = SPLITMUX_OUTPUT_STATE_START_NEXT_FILE;
+      splitmux->max_in_running_time = GST_CLOCK_STIME_NONE;
+      splitmux->gop_start_time = splitmux->fragment_start_time =
+          GST_CLOCK_STIME_NONE;
+      splitmux->muxed_out_bytes = 0;
+      splitmux->ready_for_output = FALSE;
+      GST_SPLITMUX_UNLOCK (splitmux);
+      break;
+    }
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      g_atomic_int_set (&(splitmux->split_now), FALSE);
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      GST_SPLITMUX_LOCK (splitmux);
+      splitmux->output_state = SPLITMUX_OUTPUT_STATE_STOPPED;
+      splitmux->input_state = SPLITMUX_INPUT_STATE_STOPPED;
+      /* Wake up any blocked threads */
+      GST_LOG_OBJECT (splitmux,
+          "State change -> NULL or READY. Waking threads");
+      GST_SPLITMUX_BROADCAST_INPUT (splitmux);
+      GST_SPLITMUX_BROADCAST_OUTPUT (splitmux);
+      GST_SPLITMUX_UNLOCK (splitmux);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    goto beach;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      splitmux->need_async_start = TRUE;
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:{
+      /* Change state async, because our child sink might not
+       * be ready to do that for us yet if it's state is still locked */
+
+      splitmux->need_async_start = TRUE;
+      /* we want to go async to PAUSED until we managed to configure and add the
+       * sink */
+      GST_SPLITMUX_LOCK (splitmux);
+      do_async_start (splitmux);
+      GST_SPLITMUX_UNLOCK (splitmux);
+      ret = GST_STATE_CHANGE_ASYNC;
+      break;
+    }
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      GST_SPLITMUX_LOCK (splitmux);
+      splitmux->fragment_id = 0;
+      /* Reset internal elements only if no pad contexts are using them */
+      if (splitmux->contexts == NULL)
+        gst_splitmux_reset (splitmux);
+      do_async_done (splitmux);
+      GST_SPLITMUX_UNLOCK (splitmux);
+      break;
+    default:
+      break;
+  }
+
+beach:
+  if (transition == GST_STATE_CHANGE_NULL_TO_READY &&
+      ret == GST_STATE_CHANGE_FAILURE) {
+    /* Cleanup elements on failed transition out of NULL */
+    gst_splitmux_reset (splitmux);
+    GST_SPLITMUX_LOCK (splitmux);
+    do_async_done (splitmux);
+    GST_SPLITMUX_UNLOCK (splitmux);
+  }
+  return ret;
+}
+
+gboolean
+register_splitmuxsink (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (splitmux_debug, "splitmuxsink", 0,
+      "Split File Muxing Sink");
+
+  return gst_element_register (plugin, "splitmuxsink", GST_RANK_NONE,
+      GST_TYPE_SPLITMUX_SINK);
+}
+
+static void
+gst_splitmux_sink_ensure_max_files (GstSplitMuxSink * splitmux)
+{
+  if (splitmux->max_files && splitmux->fragment_id >= splitmux->max_files) {
+    splitmux->fragment_id = 0;
+  }
+}
+
+static void
+split_now (GstSplitMuxSink * splitmux)
+{
+  g_atomic_int_set (&(splitmux->split_now), TRUE);
+}
diff --git a/gst/multifile/gstsplitmuxsink.h b/gst/multifile/gstsplitmuxsink.h
new file mode 100644
index 0000000..aab9065
--- /dev/null
+++ b/gst/multifile/gstsplitmuxsink.h
@@ -0,0 +1,184 @@
+/* GStreamer split muxer bin
+ * Copyright (C) 2014 Jan Schmidt <jan@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_SPLITMUXSINK_H__
+#define __GST_SPLITMUXSINK_H__
+
+#include <gst/gst.h>
+#include <gst/pbutils/pbutils.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_SPLITMUX_SINK               (gst_splitmux_sink_get_type())
+#define GST_SPLITMUX_SINK(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPLITMUX_SINK,GstSplitMuxSink))
+#define GST_SPLITMUX_SINK_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPLITMUX_SINK,GstSplitMuxSinkClass))
+#define GST_IS_SPLITMUX_SINK(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPLITMUX_SINK))
+#define GST_IS_SPLITMUX_SINK_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPLITMUX_SINK))
+typedef struct _GstSplitMuxSink GstSplitMuxSink;
+typedef struct _GstSplitMuxSinkClass GstSplitMuxSinkClass;
+
+GType gst_splitmux_sink_get_type (void);
+gboolean register_splitmuxsink (GstPlugin * plugin);
+
+typedef enum _SplitMuxInputState
+{
+  SPLITMUX_INPUT_STATE_STOPPED,
+  SPLITMUX_INPUT_STATE_COLLECTING_GOP_START,    /* Waiting for the next ref ctx keyframe */
+  SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT,     /* Waiting for all streams to collect GOP */
+  SPLITMUX_INPUT_STATE_FINISHING_UP             /* Got EOS from reference ctx, send everything */
+} SplitMuxInputState;
+
+typedef enum _SplitMuxOutputState
+{
+  SPLITMUX_OUTPUT_STATE_STOPPED,
+  SPLITMUX_OUTPUT_STATE_AWAITING_COMMAND,       /* Waiting first command packet from input */
+  SPLITMUX_OUTPUT_STATE_OUTPUT_GOP,     /* Outputting a collected GOP */
+  SPLITMUX_OUTPUT_STATE_ENDING_FILE,    /* Finishing the current fragment */
+  SPLITMUX_OUTPUT_STATE_START_NEXT_FILE /* Restarting after ENDING_FILE */
+} SplitMuxOutputState;
+
+typedef struct _SplitMuxOutputCommand
+{
+  gboolean start_new_fragment;  /* Whether to start a new fragment before advancing output ts */
+  GstClockTimeDiff max_output_ts;       /* Set the limit to stop GOP output */
+} SplitMuxOutputCommand;
+
+typedef struct _MqStreamBuf
+{
+  gboolean keyframe;
+  GstClockTimeDiff run_ts;
+  guint64 buf_size;
+  GstClockTime duration;
+} MqStreamBuf;
+
+typedef struct _MqStreamCtx
+{
+  gint refcount;
+
+  GstSplitMuxSink *splitmux;
+
+  guint q_overrun_id;
+  guint sink_pad_block_id;
+  guint src_pad_block_id;
+
+  gboolean is_reference;
+
+  gboolean flushing;
+  gboolean in_eos;
+  gboolean out_eos;
+  gboolean need_unblock;
+  gboolean caps_change;
+
+  GstSegment in_segment;
+  GstSegment out_segment;
+
+  GstClockTimeDiff in_running_time;
+  GstClockTimeDiff out_running_time;
+
+  GstBuffer *prev_in_keyframe; /* store keyframe for each GOP */
+
+  GstElement *q;
+  GQueue queued_bufs;
+
+  GstPad *sinkpad;
+  GstPad *srcpad;
+
+  GstBuffer *cur_out_buffer;
+  GstEvent *pending_gap;
+} MqStreamCtx;
+
+struct _GstSplitMuxSink
+{
+  GstBin parent;
+
+  GMutex lock;
+  GCond input_cond;
+  GCond output_cond;
+
+  gdouble mux_overhead;
+
+  GstClockTime threshold_time;
+  guint64 threshold_bytes;
+  guint max_files;
+  gboolean send_keyframe_requests;
+  gchar *threshold_timecode_str;
+  GstClockTime next_max_tc_time;
+  GstClockTime alignment_threshold;
+
+  GstElement *muxer;
+  GstElement *sink;
+
+  GstElement *provided_muxer;
+
+  GstElement *provided_sink;
+  GstElement *active_sink;
+
+  gboolean ready_for_output;
+
+  gchar *location;
+  guint fragment_id;
+
+  GList *contexts;
+
+  SplitMuxInputState input_state;
+  GstClockTimeDiff max_in_running_time;
+  /* Number of bytes sent to the
+   * current fragment */
+  guint64 fragment_total_bytes;
+  /* Number of bytes we've collected into
+   * the GOP that's being collected */
+  guint64 gop_total_bytes;
+  /* Start time of the current fragment */
+  GstClockTimeDiff fragment_start_time;
+  /* Start time of the current GOP */
+  GstClockTimeDiff gop_start_time;
+
+  GQueue out_cmd_q;             /* Queue of commands for output thread */
+
+  SplitMuxOutputState output_state;
+  GstClockTimeDiff max_out_running_time;
+
+  guint64 muxed_out_bytes;
+
+  MqStreamCtx *reference_ctx;
+  /* Count of queued keyframes in the reference ctx */
+  guint queued_keyframes;
+
+  gboolean switching_fragment;
+
+  gboolean have_video;
+
+  gboolean need_async_start;
+  gboolean async_pending;
+
+  gboolean use_robust_muxing;
+  gboolean muxer_has_reserved_props;
+
+  gboolean split_now;
+};
+
+struct _GstSplitMuxSinkClass
+{
+  GstBinClass parent_class;
+
+  /* actions */
+  void     (*split_now)   (GstSplitMuxSink * splitmux);
+};
+
+G_END_DECLS
+#endif /* __GST_SPLITMUXSINK_H__ */
diff --git a/gst/multifile/gstsplitmuxsrc.c b/gst/multifile/gstsplitmuxsrc.c
new file mode 100644
index 0000000..7f1ed65
--- /dev/null
+++ b/gst/multifile/gstsplitmuxsrc.c
@@ -0,0 +1,1271 @@
+/* GStreamer Split Demuxer bin that recombines files created by
+ * the splitmuxsink element.
+ *
+ * Copyright (C) <2014> Jan Schmidt <jan@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-splitmuxsrc
+ * @short_description: Split Demuxer bin that recombines files created by
+ * the splitmuxsink element.
+ *
+ * This element reads a set of input files created by the splitmuxsink element
+ * containing contiguous elementary streams split across multiple files.
+ *
+ * This element is similar to splitfilesrc, except that it recombines the
+ * streams in each file part at the demuxed elementary level, rather than
+ * as a single larger bytestream.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 splitmuxsrc location=video*.mov ! decodebin ! xvimagesink
+ * ]| Demux each file part and output the video stream as one continuous stream
+ * |[
+ * gst-launch-1.0 playbin uri="splitmux://path/to/foo.mp4.*"
+ * ]| Play back a set of files created by splitmuxsink
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include "gstsplitmuxsrc.h"
+#include "gstsplitutils.h"
+
+#include "../../gst-libs/gst/gst-i18n-plugin.h"
+
+GST_DEBUG_CATEGORY (splitmux_debug);
+#define GST_CAT_DEFAULT splitmux_debug
+
+enum
+{
+  PROP_0,
+  PROP_LOCATION
+};
+
+enum
+{
+  SIGNAL_FORMAT_LOCATION,
+  SIGNAL_LAST
+};
+
+static guint signals[SIGNAL_LAST];
+
+static GstStaticPadTemplate video_src_template =
+GST_STATIC_PAD_TEMPLATE ("video",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate audio_src_template =
+GST_STATIC_PAD_TEMPLATE ("audio_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate subtitle_src_template =
+GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS_ANY);
+
+static GstStateChangeReturn gst_splitmux_src_change_state (GstElement *
+    element, GstStateChange transition);
+static void gst_splitmux_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_splitmux_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_splitmux_src_dispose (GObject * object);
+static void gst_splitmux_src_finalize (GObject * object);
+static gboolean gst_splitmux_src_start (GstSplitMuxSrc * splitmux);
+static gboolean gst_splitmux_src_stop (GstSplitMuxSrc * splitmux);
+static void splitmux_src_pad_constructed (GObject * pad);
+static gboolean splitmux_src_pad_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static gboolean splitmux_src_pad_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+static void splitmux_src_uri_handler_init (gpointer g_iface,
+    gpointer iface_data);
+
+
+static GstPad *gst_splitmux_find_output_pad (GstSplitMuxPartReader * part,
+    GstPad * pad, GstSplitMuxSrc * splitmux);
+static void gst_splitmux_part_prepared (GstSplitMuxPartReader * reader,
+    GstSplitMuxSrc * splitmux);
+static gboolean gst_splitmux_end_of_part (GstSplitMuxSrc * splitmux,
+    SplitMuxSrcPad * pad);
+static gboolean gst_splitmux_check_new_caps (SplitMuxSrcPad * splitpad,
+    GstEvent * event);
+
+#define _do_init \
+    G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER, splitmux_src_uri_handler_init);
+#define gst_splitmux_src_parent_class parent_class
+
+G_DEFINE_TYPE_EXTENDED (GstSplitMuxSrc, gst_splitmux_src, GST_TYPE_BIN, 0,
+    _do_init);
+
+static GstURIType
+splitmux_src_uri_get_type (GType type)
+{
+  return GST_URI_SRC;
+}
+
+static const gchar *const *
+splitmux_src_uri_get_protocols (GType type)
+{
+  static const gchar *protocols[] = { "splitmux", NULL };
+
+  return protocols;
+}
+
+static gchar *
+splitmux_src_uri_get_uri (GstURIHandler * handler)
+{
+  GstSplitMuxSrc *splitmux = GST_SPLITMUX_SRC (handler);
+  gchar *ret = NULL;
+
+  GST_OBJECT_LOCK (splitmux);
+  if (splitmux->location)
+    ret = g_strdup_printf ("splitmux://%s", splitmux->location);
+  GST_OBJECT_UNLOCK (splitmux);
+  return ret;
+}
+
+static gboolean
+splitmux_src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+    GError ** err)
+{
+  GstSplitMuxSrc *splitmux = GST_SPLITMUX_SRC (handler);
+  gchar *protocol, *location;
+
+  protocol = gst_uri_get_protocol (uri);
+  if (protocol == NULL || !g_str_equal (protocol, "splitmux"))
+    goto wrong_uri;
+  g_free (protocol);
+
+  location = gst_uri_get_location (uri);
+  GST_OBJECT_LOCK (splitmux);
+  g_free (splitmux->location);
+  splitmux->location = location;
+  GST_OBJECT_UNLOCK (splitmux);
+
+  return TRUE;
+
+wrong_uri:
+  g_free (protocol);
+  GST_ELEMENT_ERROR (splitmux, RESOURCE, READ, (NULL),
+      ("Error parsing uri %s", uri));
+  g_set_error_literal (err, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
+      "Could not parse splitmux URI");
+  return FALSE;
+}
+
+static void
+splitmux_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) (g_iface);
+
+  iface->get_type = splitmux_src_uri_get_type;
+  iface->get_protocols = splitmux_src_uri_get_protocols;
+  iface->set_uri = splitmux_src_uri_set_uri;
+  iface->get_uri = splitmux_src_uri_get_uri;
+}
+
+
+static void
+gst_splitmux_src_class_init (GstSplitMuxSrcClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_splitmux_src_set_property;
+  gobject_class->get_property = gst_splitmux_src_get_property;
+  gobject_class->dispose = gst_splitmux_src_dispose;
+  gobject_class->finalize = gst_splitmux_src_finalize;
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Split File Demuxing Bin", "Generic/Bin/Demuxer",
+      "Source that reads a set of files created by splitmuxsink",
+      "Jan Schmidt <jan@centricular.com>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &video_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &audio_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &subtitle_src_template);
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_splitmux_src_change_state);
+
+  g_object_class_install_property (gobject_class, PROP_LOCATION,
+      g_param_spec_string ("location", "File Input Pattern",
+          "Glob pattern for the location of the files to read", NULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstSplitMuxSrc::format-location:
+   * @splitmux: the #GstSplitMuxSrc
+   *
+   * Returns: A NULL-terminated sorted array of strings containing the
+   *   filenames of the input files. The array will be freed internally
+   *   using g_strfreev()
+   *
+   * Since: 1.8
+   */
+  signals[SIGNAL_FORMAT_LOCATION] =
+      g_signal_new ("format-location", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_STRV, 0);
+}
+
+static void
+gst_splitmux_src_init (GstSplitMuxSrc * splitmux)
+{
+  g_mutex_init (&splitmux->lock);
+  g_mutex_init (&splitmux->pads_lock);
+  splitmux->total_duration = GST_CLOCK_TIME_NONE;
+  gst_segment_init (&splitmux->play_segment, GST_FORMAT_TIME);
+}
+
+static void
+gst_splitmux_src_dispose (GObject * object)
+{
+  GstSplitMuxSrc *splitmux = GST_SPLITMUX_SRC (object);
+  GList *cur;
+
+  SPLITMUX_SRC_PADS_LOCK (splitmux);
+
+  for (cur = g_list_first (splitmux->pads);
+      cur != NULL; cur = g_list_next (cur)) {
+    GstPad *pad = GST_PAD (cur->data);
+    gst_element_remove_pad (GST_ELEMENT (splitmux), pad);
+  }
+  g_list_free (splitmux->pads);
+  splitmux->pads = NULL;
+  SPLITMUX_SRC_PADS_UNLOCK (splitmux);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_splitmux_src_finalize (GObject * object)
+{
+  GstSplitMuxSrc *splitmux = GST_SPLITMUX_SRC (object);
+  g_mutex_clear (&splitmux->lock);
+  g_mutex_clear (&splitmux->pads_lock);
+  g_free (splitmux->location);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_splitmux_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstSplitMuxSrc *splitmux = GST_SPLITMUX_SRC (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:{
+      GST_OBJECT_LOCK (splitmux);
+      g_free (splitmux->location);
+      splitmux->location = g_value_dup_string (value);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_splitmux_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstSplitMuxSrc *splitmux = GST_SPLITMUX_SRC (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      GST_OBJECT_LOCK (splitmux);
+      g_value_set_string (value, splitmux->location);
+      GST_OBJECT_UNLOCK (splitmux);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStateChangeReturn
+gst_splitmux_src_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstSplitMuxSrc *splitmux = (GstSplitMuxSrc *) element;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:{
+      break;
+    }
+    case GST_STATE_CHANGE_READY_TO_PAUSED:{
+      if (!gst_splitmux_src_start (splitmux))
+        return GST_STATE_CHANGE_FAILURE;
+      break;
+    }
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      /* Make sure the element will shut down */
+      if (!gst_splitmux_src_stop (splitmux))
+        return GST_STATE_CHANGE_FAILURE;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  return ret;
+}
+
+static GstSplitMuxPartReader *
+gst_splitmux_part_create (GstSplitMuxSrc * splitmux, char *filename)
+{
+  GstSplitMuxPartReader *r;
+
+  r = g_object_new (GST_TYPE_SPLITMUX_PART_READER, NULL);
+
+  g_signal_connect (r, "prepared", (GCallback) gst_splitmux_part_prepared,
+      splitmux);
+
+  gst_splitmux_part_reader_set_callbacks (r, splitmux,
+      (GstSplitMuxPartReaderPadCb) gst_splitmux_find_output_pad);
+  gst_splitmux_part_reader_set_location (r, filename);
+
+  return r;
+}
+
+static gboolean
+gst_splitmux_check_new_caps (SplitMuxSrcPad * splitpad, GstEvent * event)
+{
+  GstCaps *curcaps = gst_pad_get_current_caps ((GstPad *) (splitpad));
+  GstCaps *newcaps;
+  GstCaps *tmpcaps;
+  GstCaps *tmpcurcaps;
+
+  GstStructure *s;
+  gboolean res = TRUE;
+
+  gst_event_parse_caps (event, &newcaps);
+
+  GST_LOG_OBJECT (splitpad, "Comparing caps %" GST_PTR_FORMAT
+      " and %" GST_PTR_FORMAT, curcaps, newcaps);
+
+  if (curcaps == NULL)
+    return TRUE;
+
+  /* If caps are exactly equal exit early */
+  if (gst_caps_is_equal (curcaps, newcaps)) {
+    gst_caps_unref (curcaps);
+    return FALSE;
+  }
+
+  /* More extensive check, ignore changes in framerate, because
+   * demuxers get that wrong */
+  tmpcaps = gst_caps_copy (newcaps);
+  s = gst_caps_get_structure (tmpcaps, 0);
+  gst_structure_remove_field (s, "framerate");
+
+  tmpcurcaps = gst_caps_copy (curcaps);
+  gst_caps_unref (curcaps);
+  s = gst_caps_get_structure (tmpcurcaps, 0);
+  gst_structure_remove_field (s, "framerate");
+
+  /* Now check if these filtered caps are equal */
+  if (gst_caps_is_equal (tmpcurcaps, tmpcaps)) {
+    GST_INFO_OBJECT (splitpad, "Ignoring framerate-only caps change");
+    res = FALSE;
+  }
+
+  gst_caps_unref (tmpcaps);
+  gst_caps_unref (tmpcurcaps);
+  return res;
+}
+
+static void
+gst_splitmux_handle_event (GstSplitMuxSrc * splitmux,
+    SplitMuxSrcPad * splitpad, GstPad * part_pad, GstEvent * event)
+{
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_STREAM_START:{
+      if (splitpad->sent_stream_start)
+        goto drop_event;
+      splitpad->sent_stream_start = TRUE;
+      break;
+    }
+    case GST_EVENT_EOS:{
+      if (gst_splitmux_end_of_part (splitmux, splitpad))
+        // Continuing to next part, drop the EOS
+        goto drop_event;
+      if (splitmux->segment_seqnum)
+        gst_event_set_seqnum (event, splitmux->segment_seqnum);
+      break;
+    }
+    case GST_EVENT_SEGMENT:{
+      GstClockTime duration;
+      GstSegment seg;
+
+      gst_event_copy_segment (event, &seg);
+
+      splitpad->segment.position = seg.position;
+
+      if (splitpad->sent_segment)
+        goto drop_event;        /* We already forwarded a segment event */
+
+      /* Calculate output segment */
+      GST_LOG_OBJECT (splitpad, "Pad seg %" GST_SEGMENT_FORMAT
+          " got seg %" GST_SEGMENT_FORMAT
+          " play seg %" GST_SEGMENT_FORMAT,
+          &splitpad->segment, &seg, &splitmux->play_segment);
+
+      /* If playing forward, take the stop time from the overall
+       * seg or play_segment */
+      if (splitmux->play_segment.rate > 0.0) {
+        if (splitmux->play_segment.stop != -1)
+          seg.stop = splitmux->play_segment.stop;
+        else
+          seg.stop = splitpad->segment.stop;
+      } else {
+        /* Reverse playback from stop time to start time */
+        /* See if an end point was requested in the seek */
+        if (splitmux->play_segment.start != -1) {
+          seg.start = splitmux->play_segment.start;
+          seg.time = splitmux->play_segment.time;
+        } else {
+          seg.start = splitpad->segment.start;
+          seg.time = splitpad->segment.time;
+        }
+      }
+
+      GST_OBJECT_LOCK (splitmux);
+      duration = splitmux->total_duration;
+      GST_OBJECT_UNLOCK (splitmux);
+
+      if (duration > 0)
+        seg.duration = duration;
+      else
+        seg.duration = GST_CLOCK_TIME_NONE;
+
+      GST_INFO_OBJECT (splitpad,
+          "Forwarding segment %" GST_SEGMENT_FORMAT, &seg);
+
+      gst_event_unref (event);
+      event = gst_event_new_segment (&seg);
+      if (splitmux->segment_seqnum)
+        gst_event_set_seqnum (event, splitmux->segment_seqnum);
+      splitpad->sent_segment = TRUE;
+      break;
+    }
+    case GST_EVENT_CAPS:{
+      if (!gst_splitmux_check_new_caps (splitpad, event))
+        goto drop_event;
+      splitpad->sent_caps = TRUE;
+      break;
+    }
+    default:
+      break;
+  }
+
+  gst_pad_push_event ((GstPad *) (splitpad), event);
+  return;
+drop_event:
+  gst_event_unref (event);
+  return;
+}
+
+static GstFlowReturn
+gst_splitmux_handle_buffer (GstSplitMuxSrc * splitmux,
+    SplitMuxSrcPad * splitpad, GstBuffer * buf)
+{
+  GstFlowReturn ret;
+
+  if (splitpad->clear_next_discont) {
+    GST_LOG_OBJECT (splitpad, "Clearing discont flag on buffer");
+    GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
+    splitpad->clear_next_discont = FALSE;
+  }
+  if (splitpad->set_next_discont) {
+    GST_LOG_OBJECT (splitpad, "Setting discont flag on buffer");
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+    splitpad->set_next_discont = FALSE;
+  }
+
+  ret = gst_pad_push (GST_PAD_CAST (splitpad), buf);
+
+  GST_LOG_OBJECT (splitpad, "Pad push returned %d", ret);
+  return ret;
+}
+
+static void
+gst_splitmux_pad_loop (GstPad * pad)
+{
+  /* Get one event/buffer from the associated part and push */
+  SplitMuxSrcPad *splitpad = (SplitMuxSrcPad *) (pad);
+  GstSplitMuxSrc *splitmux = (GstSplitMuxSrc *) gst_pad_get_parent (pad);
+  GstDataQueueItem *item = NULL;
+  GstSplitMuxPartReader *reader = splitpad->reader;
+  GstPad *part_pad;
+  GstFlowReturn ret;
+
+  GST_OBJECT_LOCK (splitpad);
+  if (splitpad->part_pad == NULL) {
+    GST_OBJECT_UNLOCK (splitpad);
+    return;
+  }
+  part_pad = gst_object_ref (splitpad->part_pad);
+  GST_OBJECT_UNLOCK (splitpad);
+
+  GST_LOG_OBJECT (splitpad, "Popping data queue item from %" GST_PTR_FORMAT
+      " pad %" GST_PTR_FORMAT, reader, part_pad);
+  ret = gst_splitmux_part_reader_pop (reader, part_pad, &item);
+  if (ret == GST_FLOW_ERROR)
+    goto error;
+  if (ret == GST_FLOW_FLUSHING || item == NULL)
+    goto flushing;
+
+  GST_DEBUG_OBJECT (splitpad, "Got data queue item %" GST_PTR_FORMAT,
+      item->object);
+
+  if (GST_IS_EVENT (item->object)) {
+    GstEvent *event = (GstEvent *) (item->object);
+    gst_splitmux_handle_event (splitmux, splitpad, part_pad, event);
+  } else {
+    GstBuffer *buf = (GstBuffer *) (item->object);
+    GstFlowReturn ret = gst_splitmux_handle_buffer (splitmux, splitpad, buf);
+    if (G_UNLIKELY (ret != GST_FLOW_OK && ret != GST_FLOW_EOS)) {
+      /* Stop immediately on error or flushing */
+      GST_INFO_OBJECT (splitpad, "Stopping due to pad_push() result %d", ret);
+      gst_pad_pause_task (pad);
+      if (ret < GST_FLOW_EOS || ret == GST_FLOW_NOT_LINKED) {
+        GST_ELEMENT_FLOW_ERROR (splitmux, ret);
+      }
+    }
+  }
+  g_slice_free (GstDataQueueItem, item);
+
+  gst_object_unref (part_pad);
+  gst_object_unref (splitmux);
+  return;
+
+error:
+  /* Fall through */
+  GST_ELEMENT_ERROR (splitmux, RESOURCE, OPEN_READ, (NULL),
+      ("Error reading part file %s", GST_STR_NULL (reader->path)));
+flushing:
+  gst_pad_pause_task (pad);
+  gst_object_unref (part_pad);
+  gst_object_unref (splitmux);
+  return;
+}
+
+static gboolean
+gst_splitmux_src_activate_part (GstSplitMuxSrc * splitmux, guint part,
+    GstSeekFlags extra_flags)
+{
+  GList *cur;
+
+  GST_DEBUG_OBJECT (splitmux, "Activating part %d", part);
+
+  splitmux->cur_part = part;
+  if (!gst_splitmux_part_reader_activate (splitmux->parts[part],
+          &splitmux->play_segment, extra_flags))
+    return FALSE;
+
+  SPLITMUX_SRC_PADS_LOCK (splitmux);
+  for (cur = g_list_first (splitmux->pads);
+      cur != NULL; cur = g_list_next (cur)) {
+    SplitMuxSrcPad *splitpad = (SplitMuxSrcPad *) (cur->data);
+    splitpad->cur_part = part;
+    splitpad->reader = splitmux->parts[splitpad->cur_part];
+    if (splitpad->part_pad)
+      gst_object_unref (splitpad->part_pad);
+    splitpad->part_pad =
+        gst_splitmux_part_reader_lookup_pad (splitpad->reader,
+        (GstPad *) (splitpad));
+
+    /* Make sure we start with a DISCONT */
+    splitpad->set_next_discont = TRUE;
+    splitpad->clear_next_discont = FALSE;
+
+    gst_pad_start_task (GST_PAD (splitpad),
+        (GstTaskFunction) gst_splitmux_pad_loop, splitpad, NULL);
+  }
+  SPLITMUX_SRC_PADS_UNLOCK (splitmux);
+
+  return TRUE;
+}
+
+static gboolean
+gst_splitmux_src_start (GstSplitMuxSrc * splitmux)
+{
+  gboolean ret = FALSE;
+  GError *err = NULL;
+  gchar *basename = NULL;
+  gchar *dirname = NULL;
+  gchar **files;
+  GstClockTime next_offset = 0;
+  guint i;
+  GstClockTime total_duration = 0;
+
+  GST_DEBUG_OBJECT (splitmux, "Starting");
+
+  g_signal_emit (splitmux, signals[SIGNAL_FORMAT_LOCATION], 0, &files);
+
+  if (files == NULL || *files == NULL) {
+    GST_OBJECT_LOCK (splitmux);
+    if (splitmux->location != NULL && splitmux->location[0] != '\0') {
+      basename = g_path_get_basename (splitmux->location);
+      dirname = g_path_get_dirname (splitmux->location);
+    }
+    GST_OBJECT_UNLOCK (splitmux);
+
+    g_strfreev (files);
+    files = gst_split_util_find_files (dirname, basename, &err);
+
+    if (files == NULL || *files == NULL)
+      goto no_files;
+  }
+
+  SPLITMUX_SRC_LOCK (splitmux);
+  splitmux->pads_complete = FALSE;
+  splitmux->running = TRUE;
+  SPLITMUX_SRC_UNLOCK (splitmux);
+
+  splitmux->num_parts = g_strv_length (files);
+
+  splitmux->parts = g_new0 (GstSplitMuxPartReader *, splitmux->num_parts);
+
+  for (i = 0; i < splitmux->num_parts; i++) {
+    splitmux->parts[i] = gst_splitmux_part_create (splitmux, files[i]);
+    if (splitmux->parts[i] == NULL)
+      break;
+
+    /* Figure out the next offset - the smallest one */
+    gst_splitmux_part_reader_set_start_offset (splitmux->parts[i], next_offset);
+    if (!gst_splitmux_part_reader_prepare (splitmux->parts[i])) {
+      GST_WARNING_OBJECT (splitmux,
+          "Failed to prepare file part %s. Cannot play past there.", files[i]);
+      GST_ELEMENT_WARNING (splitmux, RESOURCE, READ, (NULL),
+          ("Failed to prepare file part %s. Cannot play past there.",
+              files[i]));
+      gst_splitmux_part_reader_unprepare (splitmux->parts[i]);
+      g_object_unref (splitmux->parts[i]);
+      splitmux->parts[i] = NULL;
+      break;
+    }
+
+    /* Extend our total duration to cover this part */
+    total_duration =
+        next_offset +
+        gst_splitmux_part_reader_get_duration (splitmux->parts[i]);
+    splitmux->play_segment.duration = total_duration;
+
+    next_offset = gst_splitmux_part_reader_get_end_offset (splitmux->parts[i]);
+  }
+
+  /* Update total_duration state variable */
+  GST_OBJECT_LOCK (splitmux);
+  splitmux->total_duration = total_duration;
+  GST_OBJECT_UNLOCK (splitmux);
+
+  /* Store how many parts we actually created */
+  splitmux->num_parts = i;
+
+  if (splitmux->num_parts < 1)
+    goto failed_part;
+
+  /* All done preparing, activate the first part */
+  GST_INFO_OBJECT (splitmux,
+      "All parts prepared. Total duration %" GST_TIME_FORMAT
+      " Activating first part", GST_TIME_ARGS (total_duration));
+  ret = gst_splitmux_src_activate_part (splitmux, 0, GST_SEEK_FLAG_NONE);
+  if (ret == FALSE)
+    goto failed_first_part;
+done:
+  if (err != NULL)
+    g_error_free (err);
+  g_strfreev (files);
+  g_free (basename);
+  g_free (dirname);
+
+  return ret;
+
+/* ERRORS */
+no_files:
+  {
+    GST_ELEMENT_ERROR (splitmux, RESOURCE, OPEN_READ, ("%s", err->message),
+        ("Failed to find files in '%s' for pattern '%s'",
+            GST_STR_NULL (dirname), GST_STR_NULL (basename)));
+    goto done;
+  }
+failed_part:
+  {
+    GST_ELEMENT_ERROR (splitmux, RESOURCE, OPEN_READ, (NULL),
+        ("Failed to open any files for reading"));
+    goto done;
+  }
+failed_first_part:
+  {
+    GST_ELEMENT_ERROR (splitmux, RESOURCE, OPEN_READ, (NULL),
+        ("Failed to activate first part for playback"));
+    goto done;
+  }
+}
+
+static gboolean
+gst_splitmux_src_stop (GstSplitMuxSrc * splitmux)
+{
+  gboolean ret = TRUE;
+  guint i;
+  GList *cur, *pads_list;
+
+  SPLITMUX_SRC_LOCK (splitmux);
+  if (!splitmux->running)
+    goto out;
+
+  GST_DEBUG_OBJECT (splitmux, "Stopping");
+
+  /* Stop and destroy all parts  */
+  for (i = 0; i < splitmux->num_parts; i++) {
+    if (splitmux->parts[i] == NULL)
+      continue;
+    gst_splitmux_part_reader_unprepare (splitmux->parts[i]);
+    g_object_unref (splitmux->parts[i]);
+    splitmux->parts[i] = NULL;
+  }
+
+  SPLITMUX_SRC_PADS_LOCK (splitmux);
+  pads_list = splitmux->pads;
+  splitmux->pads = NULL;
+  SPLITMUX_SRC_PADS_UNLOCK (splitmux);
+
+  SPLITMUX_SRC_UNLOCK (splitmux);
+  for (cur = g_list_first (pads_list); cur != NULL; cur = g_list_next (cur)) {
+    SplitMuxSrcPad *tmp = (SplitMuxSrcPad *) (cur->data);
+    gst_pad_stop_task (GST_PAD (tmp));
+    gst_element_remove_pad (GST_ELEMENT (splitmux), GST_PAD (tmp));
+  }
+  g_list_free (pads_list);
+  SPLITMUX_SRC_LOCK (splitmux);
+
+  g_free (splitmux->parts);
+  splitmux->parts = NULL;
+  splitmux->num_parts = 0;
+  splitmux->running = FALSE;
+  splitmux->total_duration = GST_CLOCK_TIME_NONE;
+  /* Reset playback segment */
+  gst_segment_init (&splitmux->play_segment, GST_FORMAT_TIME);
+out:
+  SPLITMUX_SRC_UNLOCK (splitmux);
+  return ret;
+}
+
+typedef struct
+{
+  GstSplitMuxSrc *splitmux;
+  SplitMuxSrcPad *splitpad;
+} SplitMuxAndPad;
+
+static gboolean
+handle_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
+{
+  SplitMuxAndPad *splitmux_and_pad;
+  GstSplitMuxSrc *splitmux;
+  SplitMuxSrcPad *splitpad;
+
+  splitmux_and_pad = user_data;
+  splitmux = splitmux_and_pad->splitmux;
+  splitpad = splitmux_and_pad->splitpad;
+
+  GST_DEBUG_OBJECT (splitpad, "handle sticky event %" GST_PTR_FORMAT, *event);
+  gst_event_ref (*event);
+  gst_splitmux_handle_event (splitmux, splitpad, pad, *event);
+
+  return TRUE;
+}
+
+static GstPad *
+gst_splitmux_find_output_pad (GstSplitMuxPartReader * part, GstPad * pad,
+    GstSplitMuxSrc * splitmux)
+{
+  GList *cur;
+  gchar *pad_name = gst_pad_get_name (pad);
+  GstPad *target = NULL;
+  gboolean is_new_pad = FALSE;
+
+  SPLITMUX_SRC_LOCK (splitmux);
+  SPLITMUX_SRC_PADS_LOCK (splitmux);
+  for (cur = g_list_first (splitmux->pads);
+      cur != NULL; cur = g_list_next (cur)) {
+    GstPad *tmp = (GstPad *) (cur->data);
+    if (g_str_equal (GST_PAD_NAME (tmp), pad_name)) {
+      target = tmp;
+      break;
+    }
+  }
+
+  if (target == NULL && !splitmux->pads_complete) {
+    SplitMuxAndPad splitmux_and_pad;
+
+    /* No pad found, create one */
+    target = g_object_new (SPLITMUX_TYPE_SRC_PAD,
+        "name", pad_name, "direction", GST_PAD_SRC, NULL);
+    splitmux->pads = g_list_prepend (splitmux->pads, target);
+
+    gst_pad_set_active (target, TRUE);
+
+    splitmux_and_pad.splitmux = splitmux;
+    splitmux_and_pad.splitpad = (SplitMuxSrcPad *) target;
+    gst_pad_sticky_events_foreach (pad, handle_sticky_events,
+        &splitmux_and_pad);
+    is_new_pad = TRUE;
+  }
+  SPLITMUX_SRC_PADS_UNLOCK (splitmux);
+  SPLITMUX_SRC_UNLOCK (splitmux);
+
+  g_free (pad_name);
+
+  if (target == NULL)
+    goto pad_not_found;
+
+  if (is_new_pad)
+    gst_element_add_pad (GST_ELEMENT_CAST (splitmux), target);
+
+  return target;
+
+pad_not_found:
+  GST_ELEMENT_ERROR (splitmux, STREAM, FAILED, (NULL),
+      ("Stream part %s contains extra unknown pad %" GST_PTR_FORMAT,
+          part->path, pad));
+  return NULL;
+}
+
+static void
+gst_splitmux_part_prepared (GstSplitMuxPartReader * reader,
+    GstSplitMuxSrc * splitmux)
+{
+  gboolean need_no_more_pads;
+
+  GST_LOG_OBJECT (splitmux, "Part %" GST_PTR_FORMAT " prepared", reader);
+  SPLITMUX_SRC_LOCK (splitmux);
+  need_no_more_pads = !splitmux->pads_complete;
+  splitmux->pads_complete = TRUE;
+  SPLITMUX_SRC_UNLOCK (splitmux);
+
+  if (need_no_more_pads) {
+    GST_DEBUG_OBJECT (splitmux, "Signalling no-more-pads");
+    gst_element_no_more_pads (GST_ELEMENT_CAST (splitmux));
+  }
+}
+
+static void
+gst_splitmux_push_event (GstSplitMuxSrc * splitmux, GstEvent * e,
+    guint32 seqnum)
+{
+  GList *cur;
+
+  if (seqnum)
+    gst_event_set_seqnum (e, seqnum);
+
+  SPLITMUX_SRC_PADS_LOCK (splitmux);
+  for (cur = g_list_first (splitmux->pads);
+      cur != NULL; cur = g_list_next (cur)) {
+    GstPad *pad = GST_PAD_CAST (cur->data);
+    gst_event_ref (e);
+    gst_pad_push_event (pad, e);
+  }
+  SPLITMUX_SRC_PADS_UNLOCK (splitmux);
+
+  gst_event_unref (e);
+}
+
+static void
+gst_splitmux_push_flush_stop (GstSplitMuxSrc * splitmux, guint32 seqnum)
+{
+  GstEvent *e = gst_event_new_flush_stop (TRUE);
+  GList *cur;
+
+  if (seqnum)
+    gst_event_set_seqnum (e, seqnum);
+
+  SPLITMUX_SRC_PADS_LOCK (splitmux);
+  for (cur = g_list_first (splitmux->pads);
+      cur != NULL; cur = g_list_next (cur)) {
+    SplitMuxSrcPad *target = (SplitMuxSrcPad *) (cur->data);
+
+    gst_event_ref (e);
+    gst_pad_push_event (GST_PAD_CAST (target), e);
+    target->sent_caps = FALSE;
+    target->sent_stream_start = FALSE;
+    target->sent_segment = FALSE;
+  }
+  SPLITMUX_SRC_PADS_UNLOCK (splitmux);
+
+  gst_event_unref (e);
+}
+
+/* Callback for when a part finishes and we need to move to the next */
+static gboolean
+gst_splitmux_end_of_part (GstSplitMuxSrc * splitmux, SplitMuxSrcPad * splitpad)
+{
+  gint next_part = -1;
+  gint cur_part = splitpad->cur_part;
+  gboolean res = FALSE;
+
+  if (splitmux->play_segment.rate >= 0.0) {
+    if (cur_part + 1 < splitmux->num_parts)
+      next_part = cur_part + 1;
+    /* Make sure the transition is seamless */
+    splitpad->set_next_discont = FALSE;
+    splitpad->clear_next_discont = TRUE;
+  } else {
+    /* Reverse play - move to previous segment */
+    if (cur_part > 0) {
+      next_part = cur_part - 1;
+      /* Non-seamless transition in reverse */
+      splitpad->set_next_discont = TRUE;
+      splitpad->clear_next_discont = FALSE;
+    }
+  }
+
+  SPLITMUX_SRC_LOCK (splitmux);
+
+  /* If all pads are done with this part, deactivate it */
+  if (gst_splitmux_part_is_eos (splitmux->parts[splitpad->cur_part]))
+    gst_splitmux_part_reader_deactivate (splitmux->parts[cur_part]);
+
+  if (splitmux->play_segment.rate >= 0.0) {
+    if (splitmux->play_segment.stop != -1) {
+      GstClockTime part_end =
+          gst_splitmux_part_reader_get_end_offset (splitmux->parts[cur_part]);
+      if (part_end >= splitmux->play_segment.stop) {
+        GST_DEBUG_OBJECT (splitmux,
+            "Stop position was within that part. Finishing");
+        next_part = -1;
+      }
+    }
+  } else {
+    if (splitmux->play_segment.start != -1) {
+      GstClockTime part_start =
+          gst_splitmux_part_reader_get_start_offset (splitmux->parts[cur_part]);
+      if (part_start <= splitmux->play_segment.start) {
+        GST_DEBUG_OBJECT (splitmux,
+            "Start position %" GST_TIME_FORMAT
+            " was within that part. Finishing",
+            GST_TIME_ARGS (splitmux->play_segment.start));
+        next_part = -1;
+      }
+    }
+  }
+
+  if (next_part != -1) {
+    GST_DEBUG_OBJECT (splitmux, "At EOS on pad %" GST_PTR_FORMAT
+        " moving to part %d", splitpad, next_part);
+    splitpad->cur_part = next_part;
+    splitpad->reader = splitmux->parts[splitpad->cur_part];
+    if (splitpad->part_pad)
+      gst_object_unref (splitpad->part_pad);
+    splitpad->part_pad =
+        gst_splitmux_part_reader_lookup_pad (splitpad->reader,
+        (GstPad *) (splitpad));
+
+    if (splitmux->cur_part != next_part) {
+      if (!gst_splitmux_part_reader_is_active (splitpad->reader)) {
+        GstSegment tmp;
+        /* If moving backward into a new part, set stop
+         * to -1 to ensure we play the entire file - workaround
+         * a bug in qtdemux that misses bits at the end */
+        gst_segment_copy_into (&splitmux->play_segment, &tmp);
+        if (tmp.rate < 0)
+          tmp.stop = -1;
+
+        /* This is the first pad to move to the new part, activate it */
+        GST_DEBUG_OBJECT (splitpad,
+            "First pad to change part. Activating part %d with seg %"
+            GST_SEGMENT_FORMAT, next_part, &tmp);
+        if (!gst_splitmux_part_reader_activate (splitpad->reader, &tmp,
+                GST_SEEK_FLAG_NONE))
+          goto error;
+      }
+      splitmux->cur_part = next_part;
+    }
+    res = TRUE;
+  }
+
+  SPLITMUX_SRC_UNLOCK (splitmux);
+  return res;
+error:
+  SPLITMUX_SRC_UNLOCK (splitmux);
+  GST_ELEMENT_ERROR (splitmux, RESOURCE, READ, (NULL),
+      ("Failed to activate part %d", splitmux->cur_part));
+  return FALSE;
+}
+
+G_DEFINE_TYPE (SplitMuxSrcPad, splitmux_src_pad, GST_TYPE_PAD);
+
+static void
+splitmux_src_pad_constructed (GObject * pad)
+{
+  gst_pad_set_event_function (GST_PAD (pad),
+      GST_DEBUG_FUNCPTR (splitmux_src_pad_event));
+  gst_pad_set_query_function (GST_PAD (pad),
+      GST_DEBUG_FUNCPTR (splitmux_src_pad_query));
+
+  G_OBJECT_CLASS (splitmux_src_pad_parent_class)->constructed (pad);
+}
+
+static void
+gst_splitmux_src_pad_dispose (GObject * object)
+{
+  SplitMuxSrcPad *pad = (SplitMuxSrcPad *) (object);
+
+  GST_OBJECT_LOCK (pad);
+  if (pad->part_pad) {
+    gst_object_unref (pad->part_pad);
+    pad->part_pad = NULL;
+  }
+  GST_OBJECT_UNLOCK (pad);
+
+  G_OBJECT_CLASS (splitmux_src_pad_parent_class)->dispose (object);
+}
+
+static void
+splitmux_src_pad_class_init (SplitMuxSrcPadClass * klass)
+{
+  GObjectClass *gobject_klass = (GObjectClass *) (klass);
+
+  gobject_klass->constructed = splitmux_src_pad_constructed;
+  gobject_klass->dispose = gst_splitmux_src_pad_dispose;
+}
+
+static void
+splitmux_src_pad_init (SplitMuxSrcPad * pad)
+{
+}
+
+/* Event handler for source pads. Proxy events into the child
+ * parts as needed
+ */
+static gboolean
+splitmux_src_pad_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstSplitMuxSrc *splitmux = GST_SPLITMUX_SRC (parent);
+  gboolean ret = FALSE;
+
+  GST_DEBUG_OBJECT (parent, "event %" GST_PTR_FORMAT
+      " on %" GST_PTR_FORMAT, event, pad);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:{
+      GstFormat format;
+      gdouble rate;
+      GstSeekFlags flags;
+      GstSeekType start_type, stop_type;
+      gint64 start, stop;
+      guint32 seqnum;
+      gint i;
+      GstClockTime part_start, position;
+      GList *cur;
+      GstSegment tmp;
+
+      gst_event_parse_seek (event, &rate, &format, &flags,
+          &start_type, &start, &stop_type, &stop);
+
+      if (format != GST_FORMAT_TIME) {
+        GST_DEBUG_OBJECT (splitmux, "can only seek on TIME");
+        goto error;
+      }
+      /* FIXME: Support non-flushing seeks, which might never wake up */
+      if (!(flags & GST_SEEK_FLAG_FLUSH)) {
+        GST_DEBUG_OBJECT (splitmux, "Only flushing seeks supported");
+        goto error;
+      }
+      seqnum = gst_event_get_seqnum (event);
+
+      SPLITMUX_SRC_LOCK (splitmux);
+      if (!splitmux->running || splitmux->num_parts < 1) {
+        /* Not started yet */
+        SPLITMUX_SRC_UNLOCK (splitmux);
+        goto error;
+      }
+
+      gst_segment_copy_into (&splitmux->play_segment, &tmp);
+
+      if (!gst_segment_do_seek (&tmp, rate,
+              format, flags, start_type, start, stop_type, stop, NULL)) {
+        /* Invalid seek requested, ignore it */
+        SPLITMUX_SRC_UNLOCK (splitmux);
+        goto error;
+      }
+      position = tmp.position;
+
+      GST_DEBUG_OBJECT (splitmux, "Performing seek with seg %"
+          GST_SEGMENT_FORMAT, &tmp);
+
+      GST_DEBUG_OBJECT (splitmux,
+          "Handling flushing seek. Sending flush start");
+
+      /* Send flush_start */
+      gst_splitmux_push_event (splitmux, gst_event_new_flush_start (), seqnum);
+
+      /* Stop all parts, which will work because of the flush */
+      SPLITMUX_SRC_PADS_LOCK (splitmux);
+      SPLITMUX_SRC_UNLOCK (splitmux);
+      for (cur = g_list_first (splitmux->pads);
+          cur != NULL; cur = g_list_next (cur)) {
+        SplitMuxSrcPad *target = (SplitMuxSrcPad *) (cur->data);
+        GstSplitMuxPartReader *reader = splitmux->parts[target->cur_part];
+        gst_splitmux_part_reader_deactivate (reader);
+      }
+
+      /* Shut down pad tasks */
+      GST_DEBUG_OBJECT (splitmux, "Pausing pad tasks");
+      for (cur = g_list_first (splitmux->pads);
+          cur != NULL; cur = g_list_next (cur)) {
+        GstPad *splitpad = (GstPad *) (cur->data);
+        gst_pad_pause_task (GST_PAD (splitpad));
+      }
+      SPLITMUX_SRC_PADS_UNLOCK (splitmux);
+      SPLITMUX_SRC_LOCK (splitmux);
+
+      /* Send flush stop */
+      GST_DEBUG_OBJECT (splitmux, "Sending flush stop");
+      gst_splitmux_push_flush_stop (splitmux, seqnum);
+
+      /* Everything is stopped, so update the play_segment */
+      gst_segment_copy_into (&tmp, &splitmux->play_segment);
+      splitmux->segment_seqnum = seqnum;
+
+      /* Work out where to start from now */
+      for (i = 0; i < splitmux->num_parts; i++) {
+        GstSplitMuxPartReader *reader = splitmux->parts[i];
+        GstClockTime part_end =
+            gst_splitmux_part_reader_get_end_offset (reader);
+
+        if (part_end > position)
+          break;
+      }
+      if (i == splitmux->num_parts)
+        i = splitmux->num_parts - 1;
+
+      part_start =
+          gst_splitmux_part_reader_get_start_offset (splitmux->parts[i]);
+
+      GST_DEBUG_OBJECT (splitmux,
+          "Seek to time %" GST_TIME_FORMAT " landed in part %d offset %"
+          GST_TIME_FORMAT, GST_TIME_ARGS (position),
+          i, GST_TIME_ARGS (position - part_start));
+
+      ret = gst_splitmux_src_activate_part (splitmux, i, flags);
+      SPLITMUX_SRC_UNLOCK (splitmux);
+    }
+    default:
+      break;
+  }
+
+  gst_event_unref (event);
+error:
+  return ret;
+}
+
+static gboolean
+splitmux_src_pad_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  /* Query handler for source pads. Proxy queries into the child
+   * parts as needed
+   */
+  GstSplitMuxSrc *splitmux = GST_SPLITMUX_SRC (parent);
+  gboolean ret = FALSE;
+
+  GST_LOG_OBJECT (parent, "query %" GST_PTR_FORMAT
+      " on %" GST_PTR_FORMAT, query, pad);
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    case GST_QUERY_POSITION:{
+      GstSplitMuxPartReader *part;
+      SplitMuxSrcPad *anypad;
+
+      SPLITMUX_SRC_LOCK (splitmux);
+      SPLITMUX_SRC_PADS_LOCK (splitmux);
+      anypad = (SplitMuxSrcPad *) (splitmux->pads->data);
+      part = splitmux->parts[anypad->cur_part];
+      ret = gst_splitmux_part_reader_src_query (part, pad, query);
+      SPLITMUX_SRC_PADS_UNLOCK (splitmux);
+      SPLITMUX_SRC_UNLOCK (splitmux);
+      break;
+    }
+    case GST_QUERY_DURATION:{
+      GstClockTime duration;
+      GstFormat fmt;
+
+      gst_query_parse_duration (query, &fmt, NULL);
+      if (fmt != GST_FORMAT_TIME)
+        break;
+
+      GST_OBJECT_LOCK (splitmux);
+      duration = splitmux->total_duration;
+      GST_OBJECT_UNLOCK (splitmux);
+
+      if (duration > 0 && duration != GST_CLOCK_TIME_NONE) {
+        gst_query_set_duration (query, GST_FORMAT_TIME, duration);
+        ret = TRUE;
+      }
+      break;
+    }
+    case GST_QUERY_SEEKING:{
+      GstFormat format;
+
+      gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
+      if (format != GST_FORMAT_TIME)
+        break;
+
+      GST_OBJECT_LOCK (splitmux);
+      gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
+          splitmux->total_duration);
+      ret = TRUE;
+      GST_OBJECT_UNLOCK (splitmux);
+
+      break;
+    }
+    default:
+      break;
+  }
+  return ret;
+}
+
+
+gboolean
+register_splitmuxsrc (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (splitmux_debug, "splitmuxsrc", 0,
+      "Split File Demuxing Source");
+
+  return gst_element_register (plugin, "splitmuxsrc", GST_RANK_NONE,
+      GST_TYPE_SPLITMUX_SRC);
+}
diff --git a/gst/multifile/gstsplitmuxsrc.h b/gst/multifile/gstsplitmuxsrc.h
new file mode 100644
index 0000000..c234c90
--- /dev/null
+++ b/gst/multifile/gstsplitmuxsrc.h
@@ -0,0 +1,109 @@
+/* GStreamer Split Muxed File Source
+ * Copyright (C) 2014 Jan Schmidt <jan@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef __GST_SPLITMUX_SRC_H__
+#define __GST_SPLITMUX_SRC_H__
+
+#include <gst/gst.h>
+
+#include "gstsplitmuxpartreader.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SPLITMUX_SRC \
+  (gst_splitmux_src_get_type())
+#define GST_SPLITMUX_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPLITMUX_SRC,GstSplitMuxSrc))
+#define GST_SPLITMUX_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPLITMUX_SRC,GstSplitMuxSrcClass))
+#define GST_IS_SPLITMUX_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPLITMUX_SRC))
+#define GST_IS_SPLITMUX_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPLITMUX_SRC))
+
+typedef struct _GstSplitMuxSrc GstSplitMuxSrc;
+typedef struct _GstSplitMuxSrcClass GstSplitMuxSrcClass;
+
+struct _GstSplitMuxSrc
+{
+  GstBin parent;
+
+  GMutex lock;
+  gboolean     running;
+
+  gchar       *location;  /* OBJECT_LOCK */
+
+  GstSplitMuxPartReader **parts;
+  guint        num_parts;
+  guint        cur_part;
+
+  gboolean pads_complete;
+  GMutex pads_lock;
+  GList  *pads; /* pads_lock */
+
+  GstClockTime total_duration;
+  GstSegment play_segment;
+  guint32 segment_seqnum;
+};
+
+struct _GstSplitMuxSrcClass
+{
+  GstBinClass parent_class;
+};
+
+GType splitmux_src_pad_get_type (void);
+#define SPLITMUX_TYPE_SRC_PAD splitmux_src_pad_get_type()
+#define SPLITMUX_SRC_PAD_CAST(p) ((SplitMuxSrcPad *)(p))
+#define SPLITMUX_SRC_PAD(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),SPLITMUX_TYPE_SRC_PAD,SplitMuxSrcPad))
+
+struct _SplitMuxSrcPad
+{
+  GstPad parent;
+
+  guint cur_part;
+  GstSplitMuxPartReader *reader;
+  GstPad *part_pad;
+
+  GstSegment segment;
+
+  gboolean set_next_discont;
+  gboolean clear_next_discont;
+
+  gboolean sent_stream_start;
+  gboolean sent_caps;
+  gboolean sent_segment;
+};
+
+struct _SplitMuxSrcPadClass
+{
+  GstPadClass parent;
+};
+
+GType gst_splitmux_src_get_type (void);
+gboolean register_splitmuxsrc (GstPlugin * plugin);
+
+#define SPLITMUX_SRC_LOCK(s) g_mutex_lock(&(s)->lock)
+#define SPLITMUX_SRC_UNLOCK(s) g_mutex_unlock(&(s)->lock)
+
+#define SPLITMUX_SRC_PADS_LOCK(s) g_mutex_lock(&(s)->pads_lock)
+#define SPLITMUX_SRC_PADS_UNLOCK(s) g_mutex_unlock(&(s)->pads_lock)
+
+G_END_DECLS
+
+#endif /* __GST_SPLITMUX_SRC_H__ */
diff --git a/gst/multifile/gstsplitutils.c b/gst/multifile/gstsplitutils.c
new file mode 100644
index 0000000..9b088a5
--- /dev/null
+++ b/gst/multifile/gstsplitutils.c
@@ -0,0 +1,105 @@
+/* GStreamer Split Source Utility Functions
+ * Copyright (C) 2011 Collabora Ltd. <tim.muller@collabora.co.uk>
+ * Copyright (C) 2014 Jan Schmidt <jan@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstsplitutils.h"
+#include "patternspec.h"
+
+static int
+gst_split_util_array_sortfunc (gchar ** a, gchar ** b)
+{
+  return strcmp (*a, *b);
+}
+
+gchar **
+gst_split_util_find_files (const gchar * dirname,
+    const gchar * basename, GError ** err)
+{
+  PatternSpec *pspec;
+  GPtrArray *files;
+  const gchar *name;
+  GDir *dir;
+
+  if (dirname == NULL || basename == NULL)
+    goto invalid_location;
+
+  GST_INFO ("checking in directory '%s' for pattern '%s'", dirname, basename);
+
+  dir = g_dir_open (dirname, 0, err);
+  if (dir == NULL)
+    return NULL;
+
+  if (DEFAULT_PATTERN_MATCH_MODE == MATCH_MODE_UTF8 &&
+      !g_utf8_validate (basename, -1, NULL)) {
+    goto not_utf8;
+  }
+
+  /* mode will be AUTO on linux/unix and UTF8 on win32 */
+  pspec = pattern_spec_new (basename, DEFAULT_PATTERN_MATCH_MODE);
+
+  files = g_ptr_array_new ();
+
+  while ((name = g_dir_read_name (dir))) {
+    GST_TRACE ("check: %s", name);
+    if (pattern_match_string (pspec, name)) {
+      GST_DEBUG ("match: %s", name);
+      g_ptr_array_add (files, g_build_filename (dirname, name, NULL));
+    }
+  }
+
+  if (files->len == 0)
+    goto no_matches;
+
+  g_ptr_array_sort (files, (GCompareFunc) gst_split_util_array_sortfunc);
+  g_ptr_array_add (files, NULL);
+
+  pattern_spec_free (pspec);
+  g_dir_close (dir);
+
+  return (gchar **) g_ptr_array_free (files, FALSE);
+
+/* ERRORS */
+invalid_location:
+  {
+    g_set_error_literal (err, G_FILE_ERROR, G_FILE_ERROR_INVAL,
+        "No filename specified.");
+    return NULL;
+  }
+not_utf8:
+  {
+    g_dir_close (dir);
+    g_set_error_literal (err, G_FILE_ERROR, G_FILE_ERROR_INVAL,
+        "Filename pattern must be UTF-8 on Windows.");
+    return NULL;
+  }
+no_matches:
+  {
+    pattern_spec_free (pspec);
+    g_dir_close (dir);
+    g_set_error_literal (err, G_FILE_ERROR, G_FILE_ERROR_NOENT,
+        "Found no files matching the pattern.");
+    return NULL;
+  }
+}
diff --git a/gst/multifile/gstsplitutils.h b/gst/multifile/gstsplitutils.h
new file mode 100644
index 0000000..2c78b23
--- /dev/null
+++ b/gst/multifile/gstsplitutils.h
@@ -0,0 +1,40 @@
+/* GStreamer Split Source Utility Functions
+ * Copyright (C) 2011 Collabora Ltd. <tim.muller@collabora.co.uk>
+ * Copyright (C) 2014 Jan Schmidt <jan@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_SPLITUTILS_H__
+#define __GST_SPLITUTILS_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#ifdef G_OS_WIN32
+#define DEFAULT_PATTERN_MATCH_MODE MATCH_MODE_UTF8
+#else
+#define DEFAULT_PATTERN_MATCH_MODE MATCH_MODE_AUTO
+#endif
+
+gchar **
+gst_split_util_find_files (const gchar * dirname,
+    const gchar * basename, GError ** err);
+
+G_END_DECLS
+
+#endif
diff --git a/gst/multifile/meson.build b/gst/multifile/meson.build
new file mode 100644
index 0000000..a5e4736
--- /dev/null
+++ b/gst/multifile/meson.build
@@ -0,0 +1,37 @@
+multifile_sources = [
+  'gstmultifilesink.c',
+  'gstmultifilesrc.c',
+  'gstmultifile.c',
+  'gstsplitfilesrc.c',
+  'gstsplitmuxpartreader.c',
+  'gstsplitmuxsink.c',
+  'gstsplitmuxsrc.c',
+  'gstsplitutils.c',
+  'patternspec.c',
+]
+
+gstmultifile = library('gstmultifile',
+  multifile_sources,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc, libsinc],
+  dependencies : [gstvideo_dep, gstbase_dep,
+                  gstpbutils_dep, gio_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
+
+test_splitmuxpartreader_sources = [
+  'test-splitmuxpartreader.c',
+  'gstsplitmuxpartreader.c',
+  'gstsplitmuxsrc.c',
+  'gstsplitutils.c',
+  'patternspec.c',
+]
+
+executable('test-splitmuxpartreader',
+  test_splitmuxpartreader_sources,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc, libsinc],
+  dependencies : [gsttag_dep, gstbase_dep],
+  install : false,
+)
diff --git a/gst/multifile/patternspec.c b/gst/multifile/patternspec.c
new file mode 100644
index 0000000..848aaba
--- /dev/null
+++ b/gst/multifile/patternspec.c
@@ -0,0 +1,334 @@
+/* GPattern copy that supports raw (non-utf8) matching
+ * based on: GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997, 1999  Peter Mattis, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "patternspec.h"
+#include <string.h>
+
+typedef enum
+{
+  MATCH_ALL,                    /* "*A?A*" */
+  MATCH_ALL_TAIL,               /* "*A?AA" */
+  MATCH_HEAD,                   /* "AAAA*" */
+  MATCH_TAIL,                   /* "*AAAA" */
+  MATCH_EXACT,                  /* "AAAAA" */
+  MATCH_LAST
+} MatchType;
+
+struct _PatternSpec
+{
+  MatchMode match_mode;
+  MatchType match_type;
+  guint pattern_length;
+  guint min_length;
+  guint max_length;
+  gchar *pattern;
+};
+
+static inline gchar *
+raw_strreverse (const gchar * str, gssize size)
+{
+  g_assert (size > 0);
+  return g_strreverse (g_strndup (str, size));
+}
+
+static inline gboolean
+pattern_ph_match (const gchar * match_pattern, MatchMode match_mode,
+    const gchar * match_string, gboolean * wildcard_reached_p)
+{
+  register const gchar *pattern, *string;
+  register gchar ch;
+
+  pattern = match_pattern;
+  string = match_string;
+
+  ch = *pattern;
+  pattern++;
+  while (ch) {
+    switch (ch) {
+      case '?':
+        if (!*string)
+          return FALSE;
+        if (match_mode == MATCH_MODE_UTF8)
+          string = g_utf8_next_char (string);
+        else
+          ++string;
+        break;
+
+      case '*':
+        *wildcard_reached_p = TRUE;
+        do {
+          ch = *pattern;
+          pattern++;
+          if (ch == '?') {
+            if (!*string)
+              return FALSE;
+            if (match_mode == MATCH_MODE_UTF8)
+              string = g_utf8_next_char (string);
+            else
+              ++string;
+          }
+        }
+        while (ch == '*' || ch == '?');
+        if (!ch)
+          return TRUE;
+        do {
+          gboolean next_wildcard_reached = FALSE;
+          while (ch != *string) {
+            if (!*string)
+              return FALSE;
+            if (match_mode == MATCH_MODE_UTF8)
+              string = g_utf8_next_char (string);
+            else
+              ++string;
+          }
+          string++;
+          if (pattern_ph_match (pattern, match_mode, string,
+                  &next_wildcard_reached))
+            return TRUE;
+          if (next_wildcard_reached)
+            /* the forthcoming pattern substring up to the next wildcard has
+             * been matched, but a mismatch occoured for the rest of the
+             * pattern, following the next wildcard.
+             * there's no need to advance the current match position any
+             * further if the rest pattern will not match.
+             */
+            return FALSE;
+        }
+        while (*string);
+        break;
+
+      default:
+        if (ch == *string)
+          string++;
+        else
+          return FALSE;
+        break;
+    }
+
+    ch = *pattern;
+    pattern++;
+  }
+
+  return *string == 0;
+}
+
+static gboolean
+pattern_match (PatternSpec * pspec, guint string_length,
+    const gchar * string, const gchar * string_reversed)
+{
+  MatchMode match_mode;
+
+  g_assert (pspec != NULL);
+  g_assert (string != NULL);
+
+  if (string_length < pspec->min_length || string_length > pspec->max_length)
+    return FALSE;
+
+  match_mode = pspec->match_mode;
+  if (match_mode == MATCH_MODE_AUTO) {
+    if (!g_utf8_validate (string, string_length, NULL))
+      match_mode = MATCH_MODE_RAW;
+    else
+      match_mode = MATCH_MODE_UTF8;
+  }
+
+  switch (pspec->match_type) {
+      gboolean dummy;
+    case MATCH_ALL:
+      return pattern_ph_match (pspec->pattern, match_mode, string, &dummy);
+    case MATCH_ALL_TAIL:
+      if (string_reversed)
+        return pattern_ph_match (pspec->pattern, match_mode, string_reversed,
+            &dummy);
+      else {
+        gboolean result;
+        gchar *tmp;
+        if (match_mode == MATCH_MODE_UTF8) {
+          tmp = g_utf8_strreverse (string, string_length);
+        } else {
+          tmp = raw_strreverse (string, string_length);
+        }
+        result = pattern_ph_match (pspec->pattern, match_mode, tmp, &dummy);
+        g_free (tmp);
+        return result;
+      }
+    case MATCH_HEAD:
+      if (pspec->pattern_length == string_length)
+        return memcmp (pspec->pattern, string, string_length) == 0;
+      else if (pspec->pattern_length)
+        return memcmp (pspec->pattern, string, pspec->pattern_length) == 0;
+      else
+        return TRUE;
+    case MATCH_TAIL:
+      if (pspec->pattern_length)
+        /* compare incl. NUL terminator */
+        return memcmp (pspec->pattern,
+            string + (string_length - pspec->pattern_length),
+            pspec->pattern_length + 1) == 0;
+      else
+        return TRUE;
+    case MATCH_EXACT:
+      if (pspec->pattern_length != string_length)
+        return FALSE;
+      else
+        return memcmp (pspec->pattern, string, string_length) == 0;
+    default:
+      g_return_val_if_fail (pspec->match_type < MATCH_LAST, FALSE);
+      return FALSE;
+  }
+}
+
+PatternSpec *
+pattern_spec_new (const gchar * pattern, MatchMode match_mode)
+{
+  PatternSpec *pspec;
+  gboolean seen_joker = FALSE, seen_wildcard = FALSE, more_wildcards = FALSE;
+  gint hw_pos = -1, tw_pos = -1, hj_pos = -1, tj_pos = -1;
+  gboolean follows_wildcard = FALSE;
+  guint pending_jokers = 0;
+  const gchar *s;
+  gchar *d;
+  guint i;
+
+  g_assert (pattern != NULL);
+  g_assert (match_mode != MATCH_MODE_UTF8
+      || g_utf8_validate (pattern, -1, NULL));
+
+  /* canonicalize pattern and collect necessary stats */
+  pspec = g_new (PatternSpec, 1);
+  pspec->match_mode = match_mode;
+  pspec->pattern_length = strlen (pattern);
+  pspec->min_length = 0;
+  pspec->max_length = 0;
+  pspec->pattern = g_new (gchar, pspec->pattern_length + 1);
+
+  if (pspec->match_mode == MATCH_MODE_AUTO) {
+    if (!g_utf8_validate (pattern, -1, NULL))
+      pspec->match_mode = MATCH_MODE_RAW;
+  }
+
+  d = pspec->pattern;
+  for (i = 0, s = pattern; *s != 0; s++) {
+    switch (*s) {
+      case '*':
+        if (follows_wildcard) { /* compress multiple wildcards */
+          pspec->pattern_length--;
+          continue;
+        }
+        follows_wildcard = TRUE;
+        if (hw_pos < 0)
+          hw_pos = i;
+        tw_pos = i;
+        break;
+      case '?':
+        pending_jokers++;
+        pspec->min_length++;
+        if (pspec->match_mode == MATCH_MODE_RAW) {
+          pspec->max_length += 1;
+        } else {
+          pspec->max_length += 4;       /* maximum UTF-8 character length */
+        }
+        continue;
+      default:
+        for (; pending_jokers; pending_jokers--, i++) {
+          *d++ = '?';
+          if (hj_pos < 0)
+            hj_pos = i;
+          tj_pos = i;
+        }
+        follows_wildcard = FALSE;
+        pspec->min_length++;
+        pspec->max_length++;
+        break;
+    }
+    *d++ = *s;
+    i++;
+  }
+  for (; pending_jokers; pending_jokers--) {
+    *d++ = '?';
+    if (hj_pos < 0)
+      hj_pos = i;
+    tj_pos = i;
+  }
+  *d++ = 0;
+  seen_joker = hj_pos >= 0;
+  seen_wildcard = hw_pos >= 0;
+  more_wildcards = seen_wildcard && hw_pos != tw_pos;
+  if (seen_wildcard)
+    pspec->max_length = G_MAXUINT;
+
+  /* special case sole head/tail wildcard or exact matches */
+  if (!seen_joker && !more_wildcards) {
+    if (pspec->pattern[0] == '*') {
+      pspec->match_type = MATCH_TAIL;
+      memmove (pspec->pattern, pspec->pattern + 1, --pspec->pattern_length);
+      pspec->pattern[pspec->pattern_length] = 0;
+      return pspec;
+    }
+    if (pspec->pattern_length > 0 &&
+        pspec->pattern[pspec->pattern_length - 1] == '*') {
+      pspec->match_type = MATCH_HEAD;
+      pspec->pattern[--pspec->pattern_length] = 0;
+      return pspec;
+    }
+    if (!seen_wildcard) {
+      pspec->match_type = MATCH_EXACT;
+      return pspec;
+    }
+  }
+
+  /* now just need to distinguish between head or tail match start */
+  tw_pos = pspec->pattern_length - 1 - tw_pos;  /* last pos to tail distance */
+  tj_pos = pspec->pattern_length - 1 - tj_pos;  /* last pos to tail distance */
+  if (seen_wildcard)
+    pspec->match_type = tw_pos > hw_pos ? MATCH_ALL_TAIL : MATCH_ALL;
+  else                          /* seen_joker */
+    pspec->match_type = tj_pos > hj_pos ? MATCH_ALL_TAIL : MATCH_ALL;
+  if (pspec->match_type == MATCH_ALL_TAIL) {
+    gchar *tmp = pspec->pattern;
+
+    if (pspec->match_mode == MATCH_MODE_RAW) {
+      pspec->pattern = raw_strreverse (pspec->pattern, pspec->pattern_length);
+    } else {
+      pspec->pattern =
+          g_utf8_strreverse (pspec->pattern, pspec->pattern_length);
+    }
+    g_free (tmp);
+  }
+  return pspec;
+}
+
+void
+pattern_spec_free (PatternSpec * pspec)
+{
+  g_assert (pspec != NULL);
+
+  g_free (pspec->pattern);
+  g_free (pspec);
+}
+
+gboolean
+pattern_match_string (PatternSpec * pspec, const gchar * string)
+{
+  return pattern_match (pspec, strlen (string), string, NULL);
+}
diff --git a/gst/multifile/patternspec.h b/gst/multifile/patternspec.h
new file mode 100644
index 0000000..5bb9b40
--- /dev/null
+++ b/gst/multifile/patternspec.h
@@ -0,0 +1,47 @@
+/* GPattern copy that supports raw (non-utf8) matching
+ * based on: GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997, 1999  Peter Mattis, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __PATTERN_SPEC_H__
+#define __PATTERN_SPEC_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+  MATCH_MODE_AUTO = 0,
+  MATCH_MODE_UTF8,
+  MATCH_MODE_RAW
+} MatchMode;
+
+typedef struct _PatternSpec PatternSpec;
+
+PatternSpec * pattern_spec_new       (const gchar  * pattern,
+                                      MatchMode      match_mode);
+
+void          pattern_spec_free      (PatternSpec  * pspec);
+
+gboolean      pattern_match_string   (PatternSpec  * pspec,
+                                      const gchar  * string);
+
+G_END_DECLS
+
+#endif /* __PATTERN_SPEC_H__ */
diff --git a/gst/multifile/test-splitmuxpartreader.c b/gst/multifile/test-splitmuxpartreader.c
new file mode 100644
index 0000000..18756a6
--- /dev/null
+++ b/gst/multifile/test-splitmuxpartreader.c
@@ -0,0 +1,104 @@
+#include <gst/gst.h>
+#include "gstsplitmuxpartreader.h"
+#include "gstsplitmuxsrc.h"
+
+GST_DEBUG_CATEGORY_EXTERN (splitmux_debug);
+
+static const gchar *const path = "out001.mp4";
+
+typedef struct _CustomData
+{
+  GstSplitMuxPartReader *reader;
+  GMainLoop *main_loop;
+  GstBus *bus;
+} CustomData;
+
+static void
+part_prepared (GstSplitMuxPartReader * reader)
+{
+  g_print ("Part prepared\n");
+}
+
+static gboolean
+handle_message (GstBus * bus, GstMessage * msg, CustomData * data)
+{
+  GError *err;
+  gchar *debug_info;
+
+  switch (GST_MESSAGE_TYPE (msg)) {
+    case GST_MESSAGE_ERROR:
+      gst_message_parse_error (msg, &err, &debug_info);
+      g_print ("Error received from element %s: %s\n",
+          GST_OBJECT_NAME (msg->src), err->message);
+      g_print ("Debugging information: %s\n", debug_info ? debug_info : "none");
+      g_clear_error (&err);
+      g_free (debug_info);
+      g_main_loop_quit (data->main_loop);
+      break;
+    case GST_MESSAGE_EOS:
+      g_print ("End-Of-Stream reached.\n");
+      g_main_loop_quit (data->main_loop);
+      break;
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+start_reader (CustomData * data)
+{
+  g_print ("Preparing part reader for %s\n", path);
+  gst_splitmux_part_reader_prepare (data->reader);
+  return FALSE;
+}
+
+static GstPad *
+handle_get_pad (GstSplitMuxPartReader * reader, GstPad * src_pad,
+    CustomData * data)
+{
+  /* Create a dummy target pad for the reader */
+  GstPad *new_pad = g_object_new (SPLITMUX_TYPE_SRC_PAD,
+      "name", GST_PAD_NAME (src_pad), "direction", GST_PAD_SRC, NULL);
+
+  g_print ("Creating new dummy pad %s\n", GST_PAD_NAME (src_pad));
+
+  return new_pad;
+}
+
+int
+main (int argc, char **argv)
+{
+  CustomData data;
+
+  gst_init (&argc, &argv);
+
+  data.main_loop = g_main_loop_new (NULL, FALSE);
+
+  data.reader = g_object_new (GST_TYPE_SPLITMUX_PART_READER, NULL);
+  data.bus = gst_element_get_bus (GST_ELEMENT_CAST (data.reader));
+
+  /* Listen for bus messages */
+  gst_bus_add_watch (data.bus, (GstBusFunc) handle_message, &data);
+
+  gst_splitmux_part_reader_set_location (data.reader, path);
+
+  /* Connect to prepare signal */
+  g_signal_connect (data.reader, "prepared", (GCallback) part_prepared, &data);
+  gst_splitmux_part_reader_set_callbacks (data.reader, &data,
+      (GstSplitMuxPartReaderPadCb) handle_get_pad);
+
+  g_idle_add ((GSourceFunc) start_reader, &data);
+
+  /* Run mainloop */
+  g_main_loop_run (data.main_loop);
+
+  gst_splitmux_part_reader_unprepare (data.reader);
+
+  g_main_loop_unref (data.main_loop);
+  gst_object_unref (data.bus);
+  g_object_unref (data.reader);
+
+  return 0;
+}
diff --git a/gst/multipart/Makefile.am b/gst/multipart/Makefile.am
new file mode 100644
index 0000000..8c730e8
--- /dev/null
+++ b/gst/multipart/Makefile.am
@@ -0,0 +1,8 @@
+plugin_LTLIBRARIES = libgstmultipart.la
+
+libgstmultipart_la_SOURCES = multipart.c multipartdemux.c multipartmux.c
+libgstmultipart_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS)
+libgstmultipart_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS)
+libgstmultipart_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = multipartdemux.h multipartmux.h
diff --git a/gst/multipart/meson.build b/gst/multipart/meson.build
new file mode 100644
index 0000000..61aca62
--- /dev/null
+++ b/gst/multipart/meson.build
@@ -0,0 +1,10 @@
+gstmultipart = library('gstmultipart',
+  'multipart.c',
+  'multipartdemux.c',
+  'multipartmux.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstbase_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/multipart/multipart.c b/gst/multipart/multipart.c
new file mode 100644
index 0000000..30f1062
--- /dev/null
+++ b/gst/multipart/multipart.c
@@ -0,0 +1,42 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "multipartdemux.h"
+#include "multipartmux.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  gst_multipart_demux_plugin_init (plugin);
+  gst_multipart_mux_plugin_init (plugin);
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    multipart,
+    "multipart stream manipulation",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/multipart/multipartdemux.c b/gst/multipart/multipartdemux.c
new file mode 100644
index 0000000..23e67c2
--- /dev/null
+++ b/gst/multipart/multipartdemux.c
@@ -0,0 +1,810 @@
+/* GStreamer
+ * Copyright (C) 2006 Sjoerd Simons <sjoerd@luon.net>
+ * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
+ *
+ * gstmultipartdemux.c: multipart stream demuxer
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-multipartdemux
+ * @see_also: #GstMultipartMux
+ *
+ * MultipartDemux uses the Content-type field of incoming buffers to demux and 
+ * push data to dynamic source pads. Most of the time multipart streams are 
+ * sequential JPEG frames generated from a live source such as a network source
+ * or a camera.
+ *
+ * The output buffers of the multipartdemux typically have no timestamps and are
+ * usually played as fast as possible (at the rate that the source provides the
+ * data).
+ *
+ * the content in multipart files is separated with a boundary string that can
+ * be configured specifically with the #GstMultipartDemux:boundary property
+ * otherwise it will be autodetected.
+ *
+ * <refsect2>
+ * <title>Sample pipelines</title>
+ * |[
+ * gst-launch-1.0 filesrc location=/tmp/test.multipart ! multipartdemux ! image/jpeg,framerate=\(fraction\)5/1 ! jpegparse ! jpegdec ! videoconvert ! autovideosink
+ * ]| a simple pipeline to demux a multipart file muxed with #GstMultipartMux
+ * containing JPEG frames.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "multipartdemux.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_multipart_demux_debug);
+#define GST_CAT_DEFAULT gst_multipart_demux_debug
+
+#define DEFAULT_BOUNDARY		NULL
+#define DEFAULT_SINGLE_STREAM	FALSE
+
+enum
+{
+  PROP_0,
+  PROP_BOUNDARY,
+  PROP_SINGLE_STREAM
+};
+
+static GstStaticPadTemplate multipart_demux_src_template_factory =
+GST_STATIC_PAD_TEMPLATE ("src_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate multipart_demux_sink_template_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("multipart/x-mixed-replace")
+    );
+
+typedef struct
+{
+  const gchar *key;
+  const gchar *val;
+} GstNamesMap;
+
+/* convert from mime types to gst structure names. Add more when needed. The
+ * mime-type is stored as lowercase */
+static const GstNamesMap gstnames[] = {
+  /* RFC 2046 says audio/basic is mulaw, mono, 8000Hz */
+  {"audio/basic", "audio/x-mulaw, channels=1, rate=8000"},
+  {"audio/g726-16",
+      "audio/x-adpcm, bitrate=16000, layout=g726, channels=1, rate=8000"},
+  {"audio/g726-24",
+      "audio/x-adpcm, bitrate=24000, layout=g726, channels=1, rate=8000"},
+  {"audio/g726-32",
+      "audio/x-adpcm, bitrate=32000, layout=g726, channels=1, rate=8000"},
+  {"audio/g726-40",
+      "audio/x-adpcm, bitrate=40000, layout=g726, channels=1, rate=8000"},
+  /* Panasonic Network Cameras non-standard types */
+  {"audio/g726",
+      "audio/x-adpcm, bitrate=32000, layout=g726, channels=1, rate=8000"},
+  {NULL, NULL}
+};
+
+
+static GstFlowReturn gst_multipart_demux_chain (GstPad * pad,
+    GstObject * parent, GstBuffer * buf);
+static gboolean gst_multipart_demux_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+
+static GstStateChangeReturn gst_multipart_demux_change_state (GstElement *
+    element, GstStateChange transition);
+
+static void gst_multipart_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+
+static void gst_multipart_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void gst_multipart_demux_dispose (GObject * object);
+
+#define gst_multipart_demux_parent_class parent_class
+G_DEFINE_TYPE (GstMultipartDemux, gst_multipart_demux, GST_TYPE_ELEMENT);
+
+static void
+gst_multipart_demux_class_init (GstMultipartDemuxClass * klass)
+{
+  int i;
+
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->dispose = gst_multipart_demux_dispose;
+  gobject_class->set_property = gst_multipart_set_property;
+  gobject_class->get_property = gst_multipart_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_BOUNDARY,
+      g_param_spec_string ("boundary", "Boundary",
+          "The boundary string separating data, automatic if NULL",
+          DEFAULT_BOUNDARY,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstMultipartDemux:single-stream:
+   *
+   * Assume that there is only one stream whose content-type will
+   * not change and emit no-more-pads as soon as the first boundary
+   * content is parsed, decoded, and pads are linked.
+   */
+  g_object_class_install_property (gobject_class, PROP_SINGLE_STREAM,
+      g_param_spec_boolean ("single-stream", "Single Stream",
+          "Assume that there is only one stream whose content-type will not change and emit no-more-pads as soon as the first boundary content is parsed, decoded, and pads are linked",
+          DEFAULT_SINGLE_STREAM, G_PARAM_READWRITE));
+
+  /* populate gst names and mime types pairs */
+  klass->gstnames = g_hash_table_new (g_str_hash, g_str_equal);
+  for (i = 0; gstnames[i].key; i++) {
+    g_hash_table_insert (klass->gstnames, (gpointer) gstnames[i].key,
+        (gpointer) gstnames[i].val);
+  }
+
+  gstelement_class->change_state = gst_multipart_demux_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &multipart_demux_sink_template_factory);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &multipart_demux_src_template_factory);
+  gst_element_class_set_static_metadata (gstelement_class, "Multipart demuxer",
+      "Codec/Demuxer", "demux multipart streams",
+      "Wim Taymans <wim.taymans@gmail.com>, Sjoerd Simons <sjoerd@luon.net>");
+}
+
+static void
+gst_multipart_demux_init (GstMultipartDemux * multipart)
+{
+  /* create the sink pad */
+  multipart->sinkpad =
+      gst_pad_new_from_static_template (&multipart_demux_sink_template_factory,
+      "sink");
+  gst_element_add_pad (GST_ELEMENT_CAST (multipart), multipart->sinkpad);
+  gst_pad_set_chain_function (multipart->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_multipart_demux_chain));
+  gst_pad_set_event_function (multipart->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_multipart_demux_event));
+
+  multipart->adapter = gst_adapter_new ();
+  multipart->boundary = DEFAULT_BOUNDARY;
+  multipart->mime_type = NULL;
+  multipart->content_length = -1;
+  multipart->header_completed = FALSE;
+  multipart->scanpos = 0;
+  multipart->singleStream = DEFAULT_SINGLE_STREAM;
+  multipart->have_group_id = FALSE;
+  multipart->group_id = G_MAXUINT;
+}
+
+static void
+gst_multipart_demux_remove_src_pads (GstMultipartDemux * demux)
+{
+  while (demux->srcpads != NULL) {
+    GstMultipartPad *mppad = demux->srcpads->data;
+
+    gst_element_remove_pad (GST_ELEMENT (demux), mppad->pad);
+    g_free (mppad->mime);
+    g_free (mppad);
+    demux->srcpads = g_slist_delete_link (demux->srcpads, demux->srcpads);
+  }
+  demux->srcpads = NULL;
+  demux->numpads = 0;
+}
+
+static void
+gst_multipart_demux_dispose (GObject * object)
+{
+  GstMultipartDemux *demux = GST_MULTIPART_DEMUX (object);
+
+  if (demux->adapter != NULL)
+    g_object_unref (demux->adapter);
+  demux->adapter = NULL;
+  g_free (demux->boundary);
+  demux->boundary = NULL;
+  g_free (demux->mime_type);
+  demux->mime_type = NULL;
+  gst_multipart_demux_remove_src_pads (demux);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static const gchar *
+gst_multipart_demux_get_gstname (GstMultipartDemux * demux, gchar * mimetype)
+{
+  GstMultipartDemuxClass *klass;
+  const gchar *gstname;
+
+  klass = GST_MULTIPART_DEMUX_GET_CLASS (demux);
+
+  /* use hashtable to convert to gst name */
+  gstname = g_hash_table_lookup (klass->gstnames, mimetype);
+  if (gstname == NULL) {
+    /* no gst name mapping, use mime type */
+    gstname = mimetype;
+  }
+  GST_DEBUG_OBJECT (demux, "gst name for %s is %s", mimetype, gstname);
+  return gstname;
+}
+
+static GstFlowReturn
+gst_multipart_combine_flows (GstMultipartDemux * demux, GstMultipartPad * pad,
+    GstFlowReturn ret)
+{
+  GSList *walk;
+
+  /* store the value */
+  pad->last_ret = ret;
+
+  /* any other error that is not-linked can be returned right
+   * away */
+  if (ret != GST_FLOW_NOT_LINKED)
+    goto done;
+
+  /* only return NOT_LINKED if all other pads returned NOT_LINKED */
+  for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
+    GstMultipartPad *opad = (GstMultipartPad *) walk->data;
+
+    ret = opad->last_ret;
+    /* some other return value (must be SUCCESS but we can return
+     * other values as well) */
+    if (ret != GST_FLOW_NOT_LINKED)
+      goto done;
+  }
+  /* if we get here, all other pads were unlinked and we return
+   * NOT_LINKED then */
+done:
+  return ret;
+}
+
+static GstMultipartPad *
+gst_multipart_find_pad_by_mime (GstMultipartDemux * demux, gchar * mime,
+    gboolean * created)
+{
+  GSList *walk;
+
+  walk = demux->srcpads;
+  while (walk) {
+    GstMultipartPad *pad = (GstMultipartPad *) walk->data;
+
+    if (!strcmp (pad->mime, mime)) {
+      if (created) {
+        *created = FALSE;
+      }
+      return pad;
+    }
+
+    walk = walk->next;
+  }
+  /* pad not found, create it */
+  {
+    GstPad *pad;
+    GstMultipartPad *mppad;
+    gchar *name;
+    const gchar *capsname;
+    GstCaps *caps;
+    gchar *stream_id;
+    GstEvent *event;
+
+    mppad = g_new0 (GstMultipartPad, 1);
+
+    GST_DEBUG_OBJECT (demux, "creating pad with mime: %s", mime);
+
+    name = g_strdup_printf ("src_%u", demux->numpads);
+    pad =
+        gst_pad_new_from_static_template (&multipart_demux_src_template_factory,
+        name);
+    g_free (name);
+
+    mppad->pad = pad;
+    mppad->mime = g_strdup (mime);
+    mppad->last_ret = GST_FLOW_OK;
+    mppad->last_ts = GST_CLOCK_TIME_NONE;
+    mppad->discont = TRUE;
+
+    demux->srcpads = g_slist_prepend (demux->srcpads, mppad);
+    demux->numpads++;
+
+    gst_pad_use_fixed_caps (pad);
+    gst_pad_set_active (pad, TRUE);
+
+    /* prepare and send stream-start */
+    if (!demux->have_group_id) {
+      event = gst_pad_get_sticky_event (demux->sinkpad,
+          GST_EVENT_STREAM_START, 0);
+
+      if (event) {
+        demux->have_group_id =
+            gst_event_parse_group_id (event, &demux->group_id);
+        gst_event_unref (event);
+      } else if (!demux->have_group_id) {
+        demux->have_group_id = TRUE;
+        demux->group_id = gst_util_group_id_next ();
+      }
+    }
+
+    stream_id = gst_pad_create_stream_id (pad,
+        GST_ELEMENT_CAST (demux), demux->mime_type);
+
+    event = gst_event_new_stream_start (stream_id);
+    if (demux->have_group_id)
+      gst_event_set_group_id (event, demux->group_id);
+
+    gst_pad_store_sticky_event (pad, event);
+    g_free (stream_id);
+    gst_event_unref (event);
+
+    /* take the mime type, convert it to the caps name */
+    capsname = gst_multipart_demux_get_gstname (demux, mime);
+    caps = gst_caps_from_string (capsname);
+    GST_DEBUG_OBJECT (demux, "caps for pad: %s", capsname);
+    gst_pad_set_caps (pad, caps);
+    gst_element_add_pad (GST_ELEMENT_CAST (demux), pad);
+    gst_caps_unref (caps);
+
+    if (created) {
+      *created = TRUE;
+    }
+
+    if (demux->singleStream) {
+      gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
+    }
+
+    return mppad;
+  }
+}
+
+static gboolean
+get_line_end (const guint8 * data, const guint8 * dataend, guint8 ** end,
+    guint8 ** next)
+{
+  guint8 *x;
+  gboolean foundr = FALSE;
+
+  for (x = (guint8 *) data; x < dataend; x++) {
+    if (*x == '\r') {
+      foundr = TRUE;
+    } else if (*x == '\n') {
+      *end = x - (foundr ? 1 : 0);
+      *next = x + 1;
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+static guint
+get_mime_len (const guint8 * data, guint maxlen)
+{
+  guint8 *x;
+
+  x = (guint8 *) data;
+  while (*x != '\0' && *x != '\r' && *x != '\n' && *x != ';') {
+    x++;
+  }
+  return x - data;
+}
+
+static gint
+multipart_parse_header (GstMultipartDemux * multipart)
+{
+  const guint8 *data;
+  const guint8 *dataend;
+  gchar *boundary;
+  int boundary_len;
+  int datalen;
+  guint8 *pos;
+  guint8 *end, *next;
+
+  datalen = gst_adapter_available (multipart->adapter);
+  data = gst_adapter_map (multipart->adapter, datalen);
+  dataend = data + datalen;
+
+  /* Skip leading whitespace, pos endposition should at least leave space for
+   * the boundary and a \n */
+  for (pos = (guint8 *) data; pos < dataend - 4 && g_ascii_isspace (*pos);
+      pos++);
+
+  if (pos >= dataend - 4)
+    goto need_more_data;
+
+  if (G_UNLIKELY (pos[0] != '-' || pos[1] != '-')) {
+    GST_DEBUG_OBJECT (multipart, "No boundary available");
+    goto wrong_header;
+  }
+
+  /* First the boundary */
+  if (!get_line_end (pos, dataend, &end, &next))
+    goto need_more_data;
+
+  /* Ignore the leading -- */
+  boundary_len = end - pos - 2;
+  boundary = (gchar *) pos + 2;
+  if (boundary_len < 1) {
+    GST_DEBUG_OBJECT (multipart, "No boundary available");
+    goto wrong_header;
+  }
+
+  if (G_UNLIKELY (multipart->boundary == NULL)) {
+    /* First time we see the boundary, copy it */
+    multipart->boundary = g_strndup (boundary, boundary_len);
+    multipart->boundary_len = boundary_len;
+  } else if (G_UNLIKELY (boundary_len != multipart->boundary_len)) {
+    /* Something odd is going on, either the boundary indicated EOS or it's
+     * invalid */
+    if (G_UNLIKELY (boundary_len == multipart->boundary_len + 2 &&
+            !strncmp (boundary, multipart->boundary, multipart->boundary_len) &&
+            !strncmp (boundary + multipart->boundary_len, "--", 2)))
+      goto eos;
+
+    GST_DEBUG_OBJECT (multipart,
+        "Boundary length doesn't match detected boundary (%d <> %d",
+        boundary_len, multipart->boundary_len);
+    goto wrong_header;
+  } else if (G_UNLIKELY (strncmp (boundary, multipart->boundary, boundary_len))) {
+    GST_DEBUG_OBJECT (multipart, "Boundary doesn't match previous boundary");
+    goto wrong_header;
+  }
+
+  pos = next;
+  while (get_line_end (pos, dataend, &end, &next)) {
+    guint len = end - pos;
+
+    if (len == 0) {
+      /* empty line, data starts behind us */
+      GST_DEBUG_OBJECT (multipart,
+          "Parsed the header - boundary: %s, mime-type: %s, content-length: %d",
+          multipart->boundary, multipart->mime_type, multipart->content_length);
+      gst_adapter_unmap (multipart->adapter);
+      return next - data;
+    }
+
+    if (len >= 14 && !g_ascii_strncasecmp ("content-type:", (gchar *) pos, 13)) {
+      guint mime_len;
+
+      /* only take the mime type up to the first ; if any. After ; there can be
+       * properties that we don't handle yet. */
+      mime_len = get_mime_len (pos + 14, len - 14);
+
+      g_free (multipart->mime_type);
+      multipart->mime_type = g_ascii_strdown ((gchar *) pos + 14, mime_len);
+    } else if (len >= 15 &&
+        !g_ascii_strncasecmp ("content-length:", (gchar *) pos, 15)) {
+      multipart->content_length =
+          g_ascii_strtoull ((gchar *) pos + 15, NULL, 10);
+    }
+    pos = next;
+  }
+
+need_more_data:
+  GST_DEBUG_OBJECT (multipart, "Need more data for the header");
+  gst_adapter_unmap (multipart->adapter);
+
+  return MULTIPART_NEED_MORE_DATA;
+
+wrong_header:
+  {
+    GST_ELEMENT_ERROR (multipart, STREAM, DEMUX, (NULL),
+        ("Boundary not found in the multipart header"));
+    gst_adapter_unmap (multipart->adapter);
+    return MULTIPART_DATA_ERROR;
+  }
+eos:
+  {
+    GST_DEBUG_OBJECT (multipart, "we are EOS");
+    gst_adapter_unmap (multipart->adapter);
+    return MULTIPART_DATA_EOS;
+  }
+}
+
+static gint
+multipart_find_boundary (GstMultipartDemux * multipart, gint * datalen)
+{
+  /* Adaptor is positioned at the start of the data */
+  const guint8 *data, *pos;
+  const guint8 *dataend;
+  gint len;
+
+  if (multipart->content_length >= 0) {
+    /* fast path, known content length :) */
+    len = multipart->content_length;
+    if (gst_adapter_available (multipart->adapter) >= len + 2) {
+      *datalen = len;
+      data = gst_adapter_map (multipart->adapter, len + 1);
+
+      /* If data[len] contains \r then assume a newline is \r\n */
+      if (data[len] == '\r')
+        len += 2;
+      else if (data[len] == '\n')
+        len += 1;
+
+      gst_adapter_unmap (multipart->adapter);
+      /* Don't check if boundary is actually there, but let the header parsing
+       * bail out if it isn't */
+      return len;
+    } else {
+      /* need more data */
+      return MULTIPART_NEED_MORE_DATA;
+    }
+  }
+
+  len = gst_adapter_available (multipart->adapter);
+  if (len == 0)
+    return MULTIPART_NEED_MORE_DATA;
+  data = gst_adapter_map (multipart->adapter, len);
+  dataend = data + len;
+
+  for (pos = data + multipart->scanpos;
+      pos <= dataend - multipart->boundary_len - 2; pos++) {
+    if (*pos == '-' && pos[1] == '-' &&
+        !strncmp ((gchar *) pos + 2,
+            multipart->boundary, multipart->boundary_len)) {
+      /* Found the boundary! Check if there was a newline before the boundary */
+      len = pos - data;
+      if (pos - 2 > data && pos[-2] == '\r')
+        len -= 2;
+      else if (pos - 1 > data && pos[-1] == '\n')
+        len -= 1;
+      *datalen = len;
+
+      gst_adapter_unmap (multipart->adapter);
+      multipart->scanpos = 0;
+      return pos - data;
+    }
+  }
+  gst_adapter_unmap (multipart->adapter);
+  multipart->scanpos = pos - data;
+  return MULTIPART_NEED_MORE_DATA;
+}
+
+static gboolean
+gst_multipart_demux_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstMultipartDemux *multipart;
+
+  multipart = GST_MULTIPART_DEMUX (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+      if (!multipart->srcpads) {
+        GST_ELEMENT_ERROR (multipart, STREAM, WRONG_TYPE,
+            ("This stream contains no valid streams."),
+            ("Got EOS before adding any pads"));
+        gst_event_unref (event);
+        return FALSE;
+      } else {
+        return gst_pad_event_default (pad, parent, event);
+      }
+      break;
+    default:
+      return gst_pad_event_default (pad, parent, event);
+  }
+}
+
+static GstFlowReturn
+gst_multipart_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstMultipartDemux *multipart;
+  GstAdapter *adapter;
+  gint size = 1;
+  GstFlowReturn res;
+
+  multipart = GST_MULTIPART_DEMUX (parent);
+  adapter = multipart->adapter;
+
+  res = GST_FLOW_OK;
+
+  if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
+    GSList *l;
+
+    for (l = multipart->srcpads; l != NULL; l = l->next) {
+      GstMultipartPad *srcpad = l->data;
+
+      srcpad->discont = TRUE;
+    }
+    gst_adapter_clear (adapter);
+  }
+  gst_adapter_push (adapter, buf);
+
+  while (gst_adapter_available (adapter) > 0) {
+    GstMultipartPad *srcpad;
+    GstBuffer *outbuf;
+    gboolean created;
+    gint datalen;
+
+    if (G_UNLIKELY (!multipart->header_completed)) {
+      if ((size = multipart_parse_header (multipart)) < 0) {
+        goto nodata;
+      } else {
+        gst_adapter_flush (adapter, size);
+        multipart->header_completed = TRUE;
+      }
+    }
+    if ((size = multipart_find_boundary (multipart, &datalen)) < 0) {
+      goto nodata;
+    }
+
+    /* Invalidate header info */
+    multipart->header_completed = FALSE;
+    multipart->content_length = -1;
+
+    if (G_UNLIKELY (datalen <= 0)) {
+      GST_DEBUG_OBJECT (multipart, "skipping empty content.");
+      gst_adapter_flush (adapter, size - datalen);
+    } else if (G_UNLIKELY (!multipart->mime_type)) {
+      GST_DEBUG_OBJECT (multipart, "content has no MIME type.");
+      gst_adapter_flush (adapter, size - datalen);
+    } else {
+      GstClockTime ts;
+
+      srcpad =
+          gst_multipart_find_pad_by_mime (multipart,
+          multipart->mime_type, &created);
+
+      ts = gst_adapter_prev_pts (adapter, NULL);
+      outbuf = gst_adapter_take_buffer (adapter, datalen);
+      gst_adapter_flush (adapter, size - datalen);
+
+      if (created) {
+        GstTagList *tags;
+        GstSegment segment;
+
+        gst_segment_init (&segment, GST_FORMAT_TIME);
+
+        /* Push new segment, first buffer has 0 timestamp */
+        gst_pad_push_event (srcpad->pad, gst_event_new_segment (&segment));
+
+        tags = gst_tag_list_new (GST_TAG_CONTAINER_FORMAT, "Multipart", NULL);
+        gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
+        gst_pad_push_event (srcpad->pad, gst_event_new_tag (tags));
+      }
+
+      outbuf = gst_buffer_make_writable (outbuf);
+      if (srcpad->last_ts == GST_CLOCK_TIME_NONE || srcpad->last_ts != ts) {
+        GST_BUFFER_TIMESTAMP (outbuf) = ts;
+        srcpad->last_ts = ts;
+      } else {
+        GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
+      }
+
+      if (srcpad->discont) {
+        GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+        srcpad->discont = FALSE;
+      } else {
+        GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DISCONT);
+      }
+
+      GST_DEBUG_OBJECT (multipart,
+          "pushing buffer with timestamp %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
+      res = gst_pad_push (srcpad->pad, outbuf);
+      res = gst_multipart_combine_flows (multipart, srcpad, res);
+      if (res != GST_FLOW_OK)
+        break;
+    }
+  }
+
+nodata:
+  if (G_UNLIKELY (size == MULTIPART_DATA_ERROR))
+    return GST_FLOW_ERROR;
+  if (G_UNLIKELY (size == MULTIPART_DATA_EOS))
+    return GST_FLOW_EOS;
+
+  return res;
+}
+
+static GstStateChangeReturn
+gst_multipart_demux_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstMultipartDemux *multipart;
+  GstStateChangeReturn ret;
+
+  multipart = GST_MULTIPART_DEMUX (element);
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      multipart->header_completed = FALSE;
+      g_free (multipart->boundary);
+      multipart->boundary = NULL;
+      g_free (multipart->mime_type);
+      multipart->mime_type = NULL;
+      gst_adapter_clear (multipart->adapter);
+      multipart->content_length = -1;
+      multipart->scanpos = 0;
+      gst_multipart_demux_remove_src_pads (multipart);
+      multipart->have_group_id = FALSE;
+      multipart->group_id = G_MAXUINT;
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+
+static void
+gst_multipart_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstMultipartDemux *filter;
+
+  filter = GST_MULTIPART_DEMUX (object);
+
+  switch (prop_id) {
+    case PROP_BOUNDARY:
+      /* Not really that useful anymore as we can reliably autoscan */
+      g_free (filter->boundary);
+      filter->boundary = g_value_dup_string (value);
+      if (filter->boundary != NULL) {
+        filter->boundary_len = strlen (filter->boundary);
+      }
+      break;
+    case PROP_SINGLE_STREAM:
+      filter->singleStream = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_multipart_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstMultipartDemux *filter;
+
+  filter = GST_MULTIPART_DEMUX (object);
+
+  switch (prop_id) {
+    case PROP_BOUNDARY:
+      g_value_set_string (value, filter->boundary);
+      break;
+    case PROP_SINGLE_STREAM:
+      g_value_set_boolean (value, filter->singleStream);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+
+
+gboolean
+gst_multipart_demux_plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_multipart_demux_debug,
+      "multipartdemux", 0, "multipart demuxer");
+
+  return gst_element_register (plugin, "multipartdemux", GST_RANK_PRIMARY,
+      GST_TYPE_MULTIPART_DEMUX);
+}
diff --git a/gst/multipart/multipartdemux.h b/gst/multipart/multipartdemux.h
new file mode 100644
index 0000000..cb81a83
--- /dev/null
+++ b/gst/multipart/multipartdemux.h
@@ -0,0 +1,110 @@
+/* GStreamer
+ * Copyright (C) 2006 Sjoerd Simons <sjoerd@luon.net>
+ * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
+ *
+ * gstmultipartdemux.h: multipart stream demuxer
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MULTIPART_DEMUX__
+#define __GST_MULTIPART_DEMUX__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+#include <string.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_MULTIPART_DEMUX (gst_multipart_demux_get_type())
+#define GST_MULTIPART_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULTIPART_DEMUX, GstMultipartDemux))
+#define GST_MULTIPART_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULTIPART_DEMUX, GstMultipartDemux))
+#define GST_MULTIPART_DEMUX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MULTIPART_DEMUX, GstMultipartDemuxClass))
+#define GST_IS_MULTIPART_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULTIPART_DEMUX))
+#define GST_IS_MULTIPART_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULTIPART_DEMUX))
+
+typedef struct _GstMultipartDemux GstMultipartDemux;
+typedef struct _GstMultipartDemuxClass GstMultipartDemuxClass;
+
+#define MULTIPART_NEED_MORE_DATA -1
+#define MULTIPART_DATA_ERROR     -2
+#define MULTIPART_DATA_EOS       -3
+
+/* all information needed for one multipart stream */
+typedef struct
+{
+  GstPad *pad;                  /* reference for this pad is held by element we belong to */
+
+  gchar *mime;
+
+  GstClockTime  last_ts;        /* last timestamp to make sure we don't send
+                                 * two buffers with the same timestamp */
+  GstFlowReturn last_ret;
+
+  gboolean      discont;
+}
+GstMultipartPad;
+
+/**
+ * GstMultipartDemux:
+ *
+ * The opaque #GstMultipartDemux structure.
+ */
+struct _GstMultipartDemux
+{
+  GstElement element;
+
+  /* pad */
+  GstPad *sinkpad;
+
+  GSList *srcpads;
+  guint numpads;
+
+  GstAdapter *adapter;
+
+  /* Header information of the current frame */
+  gboolean header_completed;
+  gchar *boundary;
+  guint boundary_len;
+  gchar *mime_type;
+  gint content_length;
+
+  /* Index inside the current data when manually looking for the boundary */
+  gint scanpos;
+
+  gboolean singleStream;
+
+  /* to handle stream-start */
+  gboolean have_group_id;
+  guint group_id;
+};
+
+struct _GstMultipartDemuxClass
+{
+  GstElementClass parent_class;
+
+  GHashTable *gstnames;
+};
+
+GType gst_multipart_demux_get_type (void);
+
+gboolean gst_multipart_demux_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_MULTIPART_DEMUX__ */
+
diff --git a/gst/multipart/multipartmux.c b/gst/multipart/multipartmux.c
new file mode 100644
index 0000000..e6271ff
--- /dev/null
+++ b/gst/multipart/multipartmux.c
@@ -0,0 +1,695 @@
+/* multipart muxer plugin for GStreamer
+ * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-multipartmux
+ *
+ * MultipartMux uses the #GstCaps of the sink pad as the Content-type field for
+ * incoming buffers when muxing them to a multipart stream. Most of the time 
+ * multipart streams are sequential JPEG frames.
+ *
+ * <refsect2>
+ * <title>Sample pipelines</title>
+ * |[
+ * gst-launch-1.0 videotestsrc ! video/x-raw, framerate='(fraction)'5/1 ! jpegenc ! multipartmux ! filesink location=/tmp/test.multipart
+ * ]| a pipeline to mux 5 JPEG frames per second into a multipart stream
+ * stored to a file.
+ * </refsect2>
+ */
+
+/* FIXME: drop/merge tag events, or at least send them delayed after stream-start */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "multipartmux.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_multipart_mux_debug);
+#define GST_CAT_DEFAULT gst_multipart_mux_debug
+
+#define DEFAULT_BOUNDARY        "ThisRandomString"
+
+enum
+{
+  PROP_0,
+  PROP_BOUNDARY
+      /* FILL ME */
+};
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("multipart/x-mixed-replace")
+    );
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS_ANY         /* we can take anything, really */
+    );
+
+typedef struct
+{
+  const gchar *key;
+  const gchar *val;
+} MimeTypeMap;
+
+/* convert from gst structure names to mime types. Add more when needed. */
+static const MimeTypeMap mimetypes[] = {
+  {"audio/x-mulaw", "audio/basic"},
+  {NULL, NULL}
+};
+
+static void gst_multipart_mux_finalize (GObject * object);
+
+static gboolean gst_multipart_mux_handle_src_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static GstPad *gst_multipart_mux_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
+static GstStateChangeReturn gst_multipart_mux_change_state (GstElement *
+    element, GstStateChange transition);
+
+static gboolean gst_multipart_mux_sink_event (GstCollectPads * pads,
+    GstCollectData * pad, GstEvent * event, GstMultipartMux * mux);
+static GstFlowReturn gst_multipart_mux_collected (GstCollectPads * pads,
+    GstMultipartMux * mux);
+
+static void gst_multipart_mux_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_multipart_mux_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+#define gst_multipart_mux_parent_class parent_class
+G_DEFINE_TYPE (GstMultipartMux, gst_multipart_mux, GST_TYPE_ELEMENT);
+
+static void
+gst_multipart_mux_class_init (GstMultipartMuxClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  gint i;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gst_multipart_mux_finalize;
+  gobject_class->get_property = gst_multipart_mux_get_property;
+  gobject_class->set_property = gst_multipart_mux_set_property;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BOUNDARY,
+      g_param_spec_string ("boundary", "Boundary", "Boundary string",
+          DEFAULT_BOUNDARY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->request_new_pad = gst_multipart_mux_request_new_pad;
+  gstelement_class->change_state = gst_multipart_mux_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class, "Multipart muxer",
+      "Codec/Muxer", "mux multipart streams", "Wim Taymans <wim@fluendo.com>");
+
+  /* populate mime types */
+  klass->mimetypes = g_hash_table_new (g_str_hash, g_str_equal);
+  for (i = 0; mimetypes[i].key; i++) {
+    g_hash_table_insert (klass->mimetypes, (gpointer) mimetypes[i].key,
+        (gpointer) mimetypes[i].val);
+  }
+}
+
+static void
+gst_multipart_mux_init (GstMultipartMux * multipart_mux)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (multipart_mux);
+
+  multipart_mux->srcpad =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "src"), "src");
+  gst_pad_set_event_function (multipart_mux->srcpad,
+      gst_multipart_mux_handle_src_event);
+  gst_element_add_pad (GST_ELEMENT (multipart_mux), multipart_mux->srcpad);
+
+  multipart_mux->boundary = g_strdup (DEFAULT_BOUNDARY);
+
+  multipart_mux->collect = gst_collect_pads_new ();
+  gst_collect_pads_set_event_function (multipart_mux->collect,
+      (GstCollectPadsEventFunction)
+      GST_DEBUG_FUNCPTR (gst_multipart_mux_sink_event), multipart_mux);
+  gst_collect_pads_set_function (multipart_mux->collect,
+      (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_multipart_mux_collected),
+      multipart_mux);
+}
+
+static void
+gst_multipart_mux_finalize (GObject * object)
+{
+  GstMultipartMux *multipart_mux;
+
+  multipart_mux = GST_MULTIPART_MUX (object);
+
+  g_free (multipart_mux->boundary);
+
+  if (multipart_mux->collect)
+    gst_object_unref (multipart_mux->collect);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstPad *
+gst_multipart_mux_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
+{
+  GstMultipartMux *multipart_mux;
+  GstPad *newpad;
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
+  gchar *name;
+
+  if (templ != gst_element_class_get_pad_template (klass, "sink_%u"))
+    goto wrong_template;
+
+  multipart_mux = GST_MULTIPART_MUX (element);
+
+  /* create new pad with the name */
+  name = g_strdup_printf ("sink_%u", multipart_mux->numpads);
+  newpad = gst_pad_new_from_template (templ, name);
+  g_free (name);
+
+  /* construct our own wrapper data structure for the pad to
+   * keep track of its status */
+  {
+    GstMultipartPadData *multipartpad;
+
+    multipartpad = (GstMultipartPadData *)
+        gst_collect_pads_add_pad (multipart_mux->collect, newpad,
+        sizeof (GstMultipartPadData), NULL, TRUE);
+
+    /* save a pointer to our data in the pad */
+    multipartpad->pad = newpad;
+    gst_pad_set_element_private (newpad, multipartpad);
+    multipart_mux->numpads++;
+  }
+
+  /* add the pad to the element */
+  gst_element_add_pad (element, newpad);
+
+  return newpad;
+
+  /* ERRORS */
+wrong_template:
+  {
+    g_warning ("multipart_mux: this is not our template!");
+    return NULL;
+  }
+}
+
+/* handle events */
+static gboolean
+gst_multipart_mux_handle_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstEventType type;
+
+  type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
+
+  switch (type) {
+    case GST_EVENT_SEEK:
+      /* disable seeking for now */
+      return FALSE;
+    default:
+      break;
+  }
+
+  return gst_pad_event_default (pad, parent, event);
+}
+
+static const gchar *
+gst_multipart_mux_get_mime (GstMultipartMux * mux, GstStructure * s)
+{
+  GstMultipartMuxClass *klass;
+  const gchar *mime;
+  const gchar *name;
+  gint rate;
+  gint channels;
+  gint bitrate = 0;
+
+  klass = GST_MULTIPART_MUX_GET_CLASS (mux);
+
+  name = gst_structure_get_name (s);
+
+  /* use hashtable to convert to mime type */
+  mime = g_hash_table_lookup (klass->mimetypes, name);
+  if (mime == NULL) {
+    if (!strcmp (name, "audio/x-adpcm"))
+      gst_structure_get_int (s, "bitrate", &bitrate);
+
+    switch (bitrate) {
+      case 16000:
+        mime = "audio/G726-16";
+        break;
+      case 24000:
+        mime = "audio/G726-24";
+        break;
+      case 32000:
+        mime = "audio/G726-32";
+        break;
+      case 40000:
+        mime = "audio/G726-40";
+        break;
+      default:
+        /* no mime type mapping, use name */
+        mime = name;
+        break;
+    }
+  }
+  /* RFC2046 requires audio/basic to be mulaw 8000Hz mono */
+  if (g_ascii_strcasecmp (mime, "audio/basic") == 0) {
+    if (gst_structure_get_int (s, "rate", &rate) &&
+        gst_structure_get_int (s, "channels", &channels)) {
+      if (rate != 8000 || channels != 1) {
+        mime = name;
+      }
+    } else {
+      mime = name;
+    }
+  }
+  return mime;
+}
+
+/*
+ * Given two pads, compare the buffers queued on it and return 0 if they have
+ * an equal priority, 1 if the new pad is better, -1 if the old pad is better 
+ */
+static gint
+gst_multipart_mux_compare_pads (GstMultipartMux * multipart_mux,
+    GstMultipartPadData * old, GstMultipartPadData * new)
+{
+  guint64 oldtime, newtime;
+
+  /* if the old pad doesn't contain anything or is even NULL, return 
+   * the new pad as best candidate and vice versa */
+  if (old == NULL || old->buffer == NULL)
+    return 1;
+  if (new == NULL || new->buffer == NULL)
+    return -1;
+
+  if (GST_CLOCK_TIME_IS_VALID (old->dts_timestamp) &&
+      GST_CLOCK_TIME_IS_VALID (new->dts_timestamp)) {
+    oldtime = old->dts_timestamp;
+    newtime = new->dts_timestamp;
+  } else {
+    oldtime = old->pts_timestamp;
+    newtime = new->pts_timestamp;
+  }
+
+  /* no timestamp on old buffer, it must go first */
+  if (oldtime == GST_CLOCK_TIME_NONE)
+    return -1;
+
+  /* no timestamp on new buffer, it must go first */
+  if (newtime == GST_CLOCK_TIME_NONE)
+    return 1;
+
+  /* old buffer has higher timestamp, new one should go first */
+  if (newtime < oldtime)
+    return 1;
+  /* new buffer has higher timestamp, old one should go first */
+  else if (newtime > oldtime)
+    return -1;
+
+  /* same priority if all of the above failed */
+  return 0;
+}
+
+/* make sure a buffer is queued on all pads, returns a pointer to an multipartpad
+ * that holds the best buffer or NULL when no pad was usable */
+static GstMultipartPadData *
+gst_multipart_mux_queue_pads (GstMultipartMux * mux)
+{
+  GSList *walk = NULL;
+  GstMultipartPadData *bestpad = NULL;
+
+  g_return_val_if_fail (GST_IS_MULTIPART_MUX (mux), NULL);
+
+  /* try to make sure we have a buffer from each usable pad first */
+  walk = mux->collect->data;
+  while (walk) {
+    GstCollectData *data = (GstCollectData *) walk->data;
+    GstMultipartPadData *pad = (GstMultipartPadData *) data;
+
+    walk = g_slist_next (walk);
+
+    /* try to get a new buffer for this pad if needed and possible */
+    if (pad->buffer == NULL) {
+      GstBuffer *buf = NULL;
+
+      buf = gst_collect_pads_pop (mux->collect, data);
+
+      /* Store timestamps with segment_start and preroll */
+      if (buf && GST_BUFFER_PTS_IS_VALID (buf)) {
+        pad->pts_timestamp =
+            gst_segment_to_running_time (&data->segment, GST_FORMAT_TIME,
+            GST_BUFFER_PTS (buf));
+      } else {
+        pad->pts_timestamp = GST_CLOCK_TIME_NONE;
+      }
+      if (buf && GST_BUFFER_DTS_IS_VALID (buf)) {
+        pad->dts_timestamp =
+            gst_segment_to_running_time (&data->segment, GST_FORMAT_TIME,
+            GST_BUFFER_DTS (buf));
+      } else {
+        pad->dts_timestamp = GST_CLOCK_TIME_NONE;
+      }
+
+
+      pad->buffer = buf;
+    }
+
+    /* we should have a buffer now, see if it is the best stream to
+     * pull on */
+    if (pad->buffer != NULL) {
+      if (gst_multipart_mux_compare_pads (mux, bestpad, pad) > 0) {
+        bestpad = pad;
+      }
+    }
+  }
+
+  return bestpad;
+}
+
+static gboolean
+gst_multipart_mux_sink_event (GstCollectPads * pads, GstCollectData * data,
+    GstEvent * event, GstMultipartMux * mux)
+{
+  gboolean ret;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+    {
+      mux->need_segment = TRUE;
+      break;
+    }
+    default:
+      break;
+  }
+
+  ret = gst_collect_pads_event_default (pads, data, event, FALSE);
+
+  return ret;
+}
+
+/* basic idea:
+ *
+ * 1) find a pad to pull on, this is done by pulling on all pads and
+ *    looking at the buffers to decide which one should be muxed first.
+ * 2) create a new buffer for the header
+ * 3) push both buffers on best pad, go to 1
+ */
+static GstFlowReturn
+gst_multipart_mux_collected (GstCollectPads * pads, GstMultipartMux * mux)
+{
+  GstMultipartPadData *best;
+  GstFlowReturn ret = GST_FLOW_OK;
+  gchar *header = NULL;
+  size_t headerlen;
+  GstBuffer *headerbuf = NULL;
+  GstBuffer *footerbuf = NULL;
+  GstBuffer *databuf = NULL;
+  GstStructure *structure = NULL;
+  GstCaps *caps;
+  const gchar *mime;
+
+  GST_DEBUG_OBJECT (mux, "all pads are collected");
+
+  if (mux->need_stream_start) {
+    gchar s_id[32];
+
+    /* stream-start (FIXME: create id based on input ids) */
+    g_snprintf (s_id, sizeof (s_id), "multipartmux-%08x", g_random_int ());
+    gst_pad_push_event (mux->srcpad, gst_event_new_stream_start (s_id));
+
+    mux->need_stream_start = FALSE;
+  }
+
+  /* queue buffers on all pads; find a buffer with the lowest timestamp */
+  best = gst_multipart_mux_queue_pads (mux);
+  if (!best)
+    /* EOS */
+    goto eos;
+  else if (!best->buffer)
+    goto buffer_error;
+
+  /* If not negotiated yet set caps on src pad */
+  if (!mux->negotiated) {
+    GstCaps *newcaps;
+
+    newcaps = gst_caps_new_simple ("multipart/x-mixed-replace",
+        "boundary", G_TYPE_STRING, mux->boundary, NULL);
+
+    if (!gst_pad_set_caps (mux->srcpad, newcaps)) {
+      gst_caps_unref (newcaps);
+      goto nego_error;
+    }
+
+    gst_caps_unref (newcaps);
+    mux->negotiated = TRUE;
+  }
+
+  /* see if we need to push a segment */
+  if (mux->need_segment) {
+    GstClockTime time;
+    GstSegment segment;
+
+    if (best->dts_timestamp != GST_CLOCK_TIME_NONE) {
+      time = best->dts_timestamp;
+    } else if (best->pts_timestamp != GST_CLOCK_TIME_NONE) {
+      time = best->pts_timestamp;
+    } else {
+      time = 0;
+    }
+
+    /* for the segment, we take the first timestamp we see, we don't know the
+     * length and the position is 0 */
+    gst_segment_init (&segment, GST_FORMAT_TIME);
+    segment.start = time;
+
+    gst_pad_push_event (mux->srcpad, gst_event_new_segment (&segment));
+
+    mux->need_segment = FALSE;
+  }
+
+  caps = gst_pad_get_current_caps (best->pad);
+  if (caps == NULL)
+    goto no_caps;
+
+  structure = gst_caps_get_structure (caps, 0);
+  if (!structure) {
+    gst_caps_unref (caps);
+    goto no_caps;
+  }
+
+  /* get the mime type for the structure */
+  mime = gst_multipart_mux_get_mime (mux, structure);
+  gst_caps_unref (caps);
+
+  header = g_strdup_printf ("--%s\r\nContent-Type: %s\r\n"
+      "Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n",
+      mux->boundary, mime, gst_buffer_get_size (best->buffer));
+  headerlen = strlen (header);
+
+  headerbuf = gst_buffer_new_allocate (NULL, headerlen, NULL);
+  gst_buffer_fill (headerbuf, 0, header, headerlen);
+  g_free (header);
+
+  /* the header has the same timestamps as the data buffer (which we will push
+   * below) and has a duration of 0 */
+  GST_BUFFER_PTS (headerbuf) = best->pts_timestamp;
+  GST_BUFFER_DTS (headerbuf) = best->dts_timestamp;
+  GST_BUFFER_DURATION (headerbuf) = 0;
+  GST_BUFFER_OFFSET (headerbuf) = mux->offset;
+  mux->offset += headerlen;
+  GST_BUFFER_OFFSET_END (headerbuf) = mux->offset;
+
+  GST_DEBUG_OBJECT (mux, "pushing %" G_GSIZE_FORMAT " bytes header buffer",
+      headerlen);
+  ret = gst_pad_push (mux->srcpad, headerbuf);
+  if (ret != GST_FLOW_OK)
+    /* push always takes ownership of the buffer, even after an error, so we
+     * don't need to unref headerbuf here. */
+    goto beach;
+
+  /* take best->buffer, we don't need to unref it later as we will push it
+   * now. */
+  databuf = gst_buffer_make_writable (best->buffer);
+  best->buffer = NULL;
+
+  /* we need to updated the timestamps to match the running_time */
+  GST_BUFFER_PTS (databuf) = best->pts_timestamp;
+  GST_BUFFER_DTS (databuf) = best->dts_timestamp;
+  GST_BUFFER_OFFSET (databuf) = mux->offset;
+  mux->offset += gst_buffer_get_size (databuf);
+  GST_BUFFER_OFFSET_END (databuf) = mux->offset;
+  GST_BUFFER_FLAG_SET (databuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+  GST_DEBUG_OBJECT (mux, "pushing %" G_GSIZE_FORMAT " bytes data buffer",
+      gst_buffer_get_size (databuf));
+  ret = gst_pad_push (mux->srcpad, databuf);
+  if (ret != GST_FLOW_OK)
+    /* push always takes ownership of the buffer, even after an error, so we
+     * don't need to unref headerbuf here. */
+    goto beach;
+
+  footerbuf = gst_buffer_new_allocate (NULL, 2, NULL);
+  gst_buffer_fill (footerbuf, 0, "\r\n", 2);
+
+  /* the footer has the same timestamps as the data buffer and has a
+   * duration of 0 */
+  GST_BUFFER_PTS (footerbuf) = best->pts_timestamp;
+  GST_BUFFER_DTS (footerbuf) = best->dts_timestamp;
+  GST_BUFFER_DURATION (footerbuf) = 0;
+  GST_BUFFER_OFFSET (footerbuf) = mux->offset;
+  mux->offset += 2;
+  GST_BUFFER_OFFSET_END (footerbuf) = mux->offset;
+  GST_BUFFER_FLAG_SET (footerbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+  GST_DEBUG_OBJECT (mux, "pushing 2 bytes footer buffer");
+  ret = gst_pad_push (mux->srcpad, footerbuf);
+
+beach:
+  if (best && best->buffer) {
+    gst_buffer_unref (best->buffer);
+    best->buffer = NULL;
+  }
+  return ret;
+
+  /* ERRORS */
+buffer_error:
+  {
+    /* There is a best but no buffer, this is not quite right.. */
+    GST_ELEMENT_ERROR (mux, STREAM, FAILED, (NULL), ("internal muxing error"));
+    ret = GST_FLOW_ERROR;
+    goto beach;
+  }
+eos:
+  {
+    GST_DEBUG_OBJECT (mux, "Pushing EOS");
+    gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
+    ret = GST_FLOW_EOS;
+    goto beach;
+  }
+nego_error:
+  {
+    GST_WARNING_OBJECT (mux, "failed to set caps");
+    GST_ELEMENT_ERROR (mux, CORE, NEGOTIATION, (NULL), (NULL));
+    ret = GST_FLOW_NOT_NEGOTIATED;
+    goto beach;
+  }
+no_caps:
+  {
+    GST_WARNING_OBJECT (mux, "no caps on the incoming buffer %p", best->buffer);
+    GST_ELEMENT_ERROR (mux, CORE, NEGOTIATION, (NULL), (NULL));
+    ret = GST_FLOW_NOT_NEGOTIATED;
+    goto beach;
+  }
+}
+
+static void
+gst_multipart_mux_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstMultipartMux *mux;
+
+  mux = GST_MULTIPART_MUX (object);
+
+  switch (prop_id) {
+    case PROP_BOUNDARY:
+      g_value_set_string (value, mux->boundary);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_multipart_mux_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstMultipartMux *mux;
+
+  mux = GST_MULTIPART_MUX (object);
+
+  switch (prop_id) {
+    case PROP_BOUNDARY:
+      g_free (mux->boundary);
+      mux->boundary = g_strdup (g_value_get_string (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStateChangeReturn
+gst_multipart_mux_change_state (GstElement * element, GstStateChange transition)
+{
+  GstMultipartMux *multipart_mux;
+  GstStateChangeReturn ret;
+
+  multipart_mux = GST_MULTIPART_MUX (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      multipart_mux->offset = 0;
+      multipart_mux->negotiated = FALSE;
+      multipart_mux->need_segment = TRUE;
+      multipart_mux->need_stream_start = TRUE;
+      GST_DEBUG_OBJECT (multipart_mux, "starting collect pads");
+      gst_collect_pads_start (multipart_mux->collect);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      GST_DEBUG_OBJECT (multipart_mux, "stopping collect pads");
+      gst_collect_pads_stop (multipart_mux->collect);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    return ret;
+
+  switch (transition) {
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+gboolean
+gst_multipart_mux_plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_multipart_mux_debug, "multipartmux", 0,
+      "multipart muxer");
+
+  return gst_element_register (plugin, "multipartmux", GST_RANK_NONE,
+      GST_TYPE_MULTIPART_MUX);
+}
diff --git a/gst/multipart/multipartmux.h b/gst/multipart/multipartmux.h
new file mode 100644
index 0000000..3b44f5a
--- /dev/null
+++ b/gst/multipart/multipartmux.h
@@ -0,0 +1,98 @@
+/* GStreamer
+ * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
+ *
+ * gstmultipartmux.h: multipart stream muxer
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MULTIPART_MUX__
+#define __GST_MULTIPART_MUX__
+
+#include <gst/gst.h>
+#include <gst/base/gstcollectpads.h>
+
+#include <string.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_MULTIPART_MUX (gst_multipart_mux_get_type())
+#define GST_MULTIPART_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULTIPART_MUX, GstMultipartMux))
+#define GST_MULTIPART_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULTIPART_MUX, GstMultipartMux))
+#define GST_MULTIPART_MUX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MULTIPART_MUX, GstMultipartMuxClass))
+#define GST_IS_MULTIPART_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULTIPART_MUX))
+#define GST_IS_MULTIPART_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULTIPART_MUX))
+
+typedef struct _GstMultipartMux GstMultipartMux;
+typedef struct _GstMultipartMuxClass GstMultipartMuxClass;
+
+/* all information needed for one multipart stream */
+typedef struct
+{
+  GstCollectData collect;       /* we extend the CollectData */
+
+  GstBuffer *buffer;            /* the queued buffer for this pad */
+  GstClockTime pts_timestamp;   /* its pts timestamp, converted to running_time so that we can
+                                   correctly sort over multiple segments. */
+  GstClockTime dts_timestamp;   /* its dts timestamp, converted to running_time so that we can
+                                   correctly sort over multiple segments. */
+  GstPad *pad;
+}
+GstMultipartPadData;
+
+/**
+ * GstMultipartMux:
+ *
+ * The opaque #GstMultipartMux structure.
+ */
+struct _GstMultipartMux
+{
+  GstElement element;
+
+  /* pad */
+  GstPad *srcpad;
+
+  /* sinkpads */
+  GstCollectPads *collect;
+
+  gint numpads;
+
+  /* offset in stream */
+  guint64 offset;
+
+  /* boundary string */
+  gchar *boundary;
+
+  gboolean negotiated;
+  gboolean need_segment;
+  gboolean need_stream_start;
+};
+
+struct _GstMultipartMuxClass
+{
+  GstElementClass parent_class;
+
+  GHashTable *mimetypes;
+};
+
+GType gst_multipart_mux_get_type (void);
+
+gboolean gst_multipart_mux_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_MULTIPART_MUX__ */
+
diff --git a/gst/replaygain/Makefile.am b/gst/replaygain/Makefile.am
new file mode 100644
index 0000000..c8e2406
--- /dev/null
+++ b/gst/replaygain/Makefile.am
@@ -0,0 +1,22 @@
+plugin_LTLIBRARIES = libgstreplaygain.la
+
+libgstreplaygain_la_SOURCES = \
+	gstrganalysis.c       \
+	gstrglimiter.c        \
+	gstrgvolume.c         \
+	replaygain.c          \
+	rganalysis.c
+libgstreplaygain_la_CFLAGS  = \
+	$(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstreplaygain_la_LIBADD  = \
+	$(GST_PLUGINS_BASE_LIBS) -lgstpbutils-$(GST_API_VERSION) -lgstaudio-$(GST_API_VERSION)\
+	$(GST_BASE_LIBS) $(GST_LIBS) $(LIBM)
+libgstreplaygain_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+# headers we need but don't want installed
+noinst_HEADERS =         \
+	gstrganalysis.h  \
+	gstrglimiter.h   \
+	gstrgvolume.h    \
+	replaygain.h     \
+	rganalysis.h
diff --git a/gst/replaygain/gstrganalysis.c b/gst/replaygain/gstrganalysis.c
new file mode 100644
index 0000000..214901d
--- /dev/null
+++ b/gst/replaygain/gstrganalysis.c
@@ -0,0 +1,709 @@
+/* GStreamer ReplayGain analysis
+ *
+ * Copyright (C) 2006 Rene Stadler <mail@renestadler.de>
+ * 
+ * gstrganalysis.c: Element that performs the ReplayGain analysis
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+/**
+ * SECTION:element-rganalysis
+ * @see_also: #GstRgVolume
+ *
+ * This element analyzes raw audio sample data in accordance with the proposed
+ * <ulink url="http://replaygain.org">ReplayGain standard</ulink> for
+ * calculating the ideal replay gain for music tracks and albums.  The element
+ * is designed as a pass-through filter that never modifies any data.  As it
+ * receives an EOS event, it finalizes the ongoing analysis and generates a tag
+ * list containing the results.  It is sent downstream with a tag event and
+ * posted on the message bus with a tag message.  The EOS event is forwarded as
+ * normal afterwards.  Result tag lists at least contain the tags
+ * #GST_TAG_TRACK_GAIN, #GST_TAG_TRACK_PEAK and #GST_TAG_REFERENCE_LEVEL.
+ * 
+ * Because the generated metadata tags become available at the end of streams,
+ * downstream muxer and encoder elements are normally unable to save them in
+ * their output since they generally save metadata in the file header.
+ * Therefore, it is often necessary that applications read the results in a bus
+ * event handler for the tag message.  Obtaining the values this way is always
+ * needed for album processing (see #GstRgAnalysis:num-tracks property) since
+ * the album gain and peak values need to be associated with all tracks of an
+ * album, not just the last one.
+ * 
+ * <refsect2>
+ * <title>Example launch lines</title>
+ * |[
+ * gst-launch-1.0 -t audiotestsrc wave=sine num-buffers=512 ! rganalysis ! fakesink
+ * ]| Analyze a simple test waveform
+ * |[
+ * gst-launch-1.0 -t filesrc location=filename.ext ! decodebin \
+ *     ! audioconvert ! audioresample ! rganalysis ! fakesink
+ * ]| Analyze a given file
+ * |[
+ * gst-launch-1.0 -t gnomevfssrc location=http://replaygain.hydrogenaudio.org/ref_pink.wav \
+ *     ! wavparse ! rganalysis ! fakesink
+ * ]| Analyze the pink noise reference file
+ * <para>
+ * The above launch line yields a result gain of +6 dB (instead of the expected
+ * +0 dB).  This is not in error, refer to the #GstRgAnalysis:reference-level
+ * property documentation for more information.
+ * </para>
+ * </refsect2>
+ * <refsect2>
+ * <title>Acknowledgements</title>
+ * <para>
+ * This element is based on code used in the <ulink
+ * url="http://sjeng.org/vorbisgain.html">vorbisgain</ulink> program and many
+ * others.  The relevant parts are copyrighted by David Robinson, Glen Sawyer
+ * and Frank Klemm.
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+
+#include "gstrganalysis.h"
+#include "replaygain.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_rg_analysis_debug);
+#define GST_CAT_DEFAULT gst_rg_analysis_debug
+
+/* Default property value. */
+#define FORCED_DEFAULT TRUE
+#define DEFAULT_MESSAGE FALSE
+
+enum
+{
+  PROP_0,
+  PROP_NUM_TRACKS,
+  PROP_FORCED,
+  PROP_REFERENCE_LEVEL,
+  PROP_MESSAGE
+};
+
+/* The ReplayGain algorithm is intended for use with mono and stereo
+ * audio.  The used implementation has filter coefficients for the
+ * "usual" sample rates in the 8000 to 48000 Hz range. */
+#define REPLAY_GAIN_CAPS "audio/x-raw," \
+  "format = (string) { "GST_AUDIO_NE(F32)","GST_AUDIO_NE(S16)" }, "     \
+  "layout = (string) interleaved, "                                     \
+  "channels = (int) 1, "                                                \
+  "rate = (int) { 8000, 11025, 12000, 16000, 22050, 24000, 32000, "     \
+  "44100, 48000 }; "                                                    \
+  "audio/x-raw,"                                                        \
+  "format = (string) { "GST_AUDIO_NE(F32)","GST_AUDIO_NE(S16)" }, "     \
+  "layout = (string) interleaved, "                                     \
+  "channels = (int) 2, "                                                \
+  "channel-mask = (bitmask) 0x3, "                                      \
+  "rate = (int) { 8000, 11025, 12000, 16000, 22050, 24000, 32000, "     \
+  "44100, 48000 }"
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (REPLAY_GAIN_CAPS));
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (REPLAY_GAIN_CAPS));
+
+#define gst_rg_analysis_parent_class parent_class
+G_DEFINE_TYPE (GstRgAnalysis, gst_rg_analysis, GST_TYPE_BASE_TRANSFORM);
+
+static void gst_rg_analysis_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rg_analysis_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_rg_analysis_start (GstBaseTransform * base);
+static gboolean gst_rg_analysis_set_caps (GstBaseTransform * base,
+    GstCaps * incaps, GstCaps * outcaps);
+static GstFlowReturn gst_rg_analysis_transform_ip (GstBaseTransform * base,
+    GstBuffer * buf);
+static gboolean gst_rg_analysis_sink_event (GstBaseTransform * base,
+    GstEvent * event);
+static gboolean gst_rg_analysis_stop (GstBaseTransform * base);
+
+static void gst_rg_analysis_handle_tags (GstRgAnalysis * filter,
+    const GstTagList * tag_list);
+static void gst_rg_analysis_handle_eos (GstRgAnalysis * filter);
+static gboolean gst_rg_analysis_track_result (GstRgAnalysis * filter,
+    GstTagList ** tag_list);
+static gboolean gst_rg_analysis_album_result (GstRgAnalysis * filter,
+    GstTagList ** tag_list);
+
+static void
+gst_rg_analysis_class_init (GstRgAnalysisClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+  GstBaseTransformClass *trans_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_rg_analysis_set_property;
+  gobject_class->get_property = gst_rg_analysis_get_property;
+
+  /**
+   * GstRgAnalysis:num-tracks:
+   *
+   * Number of remaining album tracks.
+   * 
+   * Analyzing several streams sequentially and assigning them a common result
+   * gain is known as "album processing".  If this gain is used during playback
+   * (by switching to "album mode"), all tracks of an album receive the same
+   * amplification.  This keeps the relative volume levels between the tracks
+   * intact.  To enable this, set this property to the number of streams that
+   * will be processed as album tracks.
+   *
+   * Every time an EOS event is received, the value of this property is
+   * decremented by one.  As it reaches zero, it is assumed that the last track
+   * of the album finished.  The tag list for the final stream will contain the
+   * additional tags #GST_TAG_ALBUM_GAIN and #GST_TAG_ALBUM_PEAK.  All other
+   * streams just get the two track tags posted because the values for the album
+   * tags are not known before all tracks are analyzed.  Applications need to
+   * ensure that the album gain and peak values are also associated with the
+   * other tracks when storing the results.
+   *
+   * If the total number of album tracks is unknown beforehand, just ensure that
+   * the value is greater than 1 before each track starts.  Then before the end
+   * of the last track, set it to the value 1.
+   *
+   * To perform album processing, the element has to preserve data between
+   * streams.  This cannot survive a state change to the NULL or READY state.
+   * If you change your pipeline's state to NULL or READY between tracks, lock
+   * the element's state using gst_element_set_locked_state() when it is in
+   * PAUSED or PLAYING.
+   */
+  g_object_class_install_property (gobject_class, PROP_NUM_TRACKS,
+      g_param_spec_int ("num-tracks", "Number of album tracks",
+          "Number of remaining album tracks", 0, G_MAXINT, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRgAnalysis:forced:
+   *
+   * Whether to analyze streams even when ReplayGain tags exist.
+   *
+   * For assisting transcoder/converter applications, the element can silently
+   * skip the processing of streams that already contain the necessary tags.
+   * Data will flow as usual but the element will not consume CPU time and will
+   * not generate result tags.  To enable possible skipping, set this property
+   * to %FALSE.
+   *
+   * If used in conjunction with <link linkend="GstRgAnalysis--num-tracks">album
+   * processing</link>, the element will skip the number of remaining album
+   * tracks if a full set of tags is found for the first track.  If a subsequent
+   * track of the album is missing tags, processing cannot start again.  If this
+   * is undesired, the application has to scan all files beforehand and enable
+   * forcing of processing if needed.
+   */
+  g_object_class_install_property (gobject_class, PROP_FORCED,
+      g_param_spec_boolean ("forced", "Forced",
+          "Analyze even if ReplayGain tags exist",
+          FORCED_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRgAnalysis:reference-level:
+   *
+   * Reference level [dB].
+   *
+   * Analyzing the ReplayGain pink noise reference waveform computes a result of
+   * +6 dB instead of the expected 0 dB.  This is because the default reference
+   * level is 89 dB.  To obtain values as lined out in the original proposal of
+   * ReplayGain, set this property to 83.
+   *
+   * Almost all software uses 89 dB as a reference however, and this value has
+   * become the new official value.  That is to say, while the change has been
+   * acclaimed by the author of the ReplayGain proposal, the <ulink
+   * url="http://replaygain.org">webpage</ulink> is still outdated at the time
+   * of this writing.
+   *
+   * The value was changed because the original proposal recommends a default
+   * pre-amp value of +6 dB for playback.  This seemed a bit odd, as it means
+   * that the algorithm has the general tendency to produce adjustment values
+   * that are 6 dB too low.  Bumping the reference level by 6 dB compensated for
+   * this.
+   *
+   * The problem of the reference level being ambiguous for lack of concise
+   * standardization is to be solved by adopting the #GST_TAG_REFERENCE_LEVEL
+   * tag, which allows to store the used value alongside the gain values.
+   */
+  g_object_class_install_property (gobject_class, PROP_REFERENCE_LEVEL,
+      g_param_spec_double ("reference-level", "Reference level",
+          "Reference level [dB]", 0.0, 150., RG_REFERENCE_LEVEL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MESSAGE,
+      g_param_spec_boolean ("message", "Message",
+          "Post statics messages",
+          DEFAULT_MESSAGE,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+  trans_class = (GstBaseTransformClass *) klass;
+  trans_class->start = GST_DEBUG_FUNCPTR (gst_rg_analysis_start);
+  trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_rg_analysis_set_caps);
+  trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_rg_analysis_transform_ip);
+  trans_class->sink_event = GST_DEBUG_FUNCPTR (gst_rg_analysis_sink_event);
+  trans_class->stop = GST_DEBUG_FUNCPTR (gst_rg_analysis_stop);
+  trans_class->passthrough_on_same_caps = TRUE;
+
+  gst_element_class_add_static_pad_template (element_class, &src_factory);
+  gst_element_class_add_static_pad_template (element_class, &sink_factory);
+  gst_element_class_set_static_metadata (element_class, "ReplayGain analysis",
+      "Filter/Analyzer/Audio",
+      "Perform the ReplayGain analysis",
+      "Ren\xc3\xa9 Stadler <mail@renestadler.de>");
+
+  GST_DEBUG_CATEGORY_INIT (gst_rg_analysis_debug, "rganalysis", 0,
+      "ReplayGain analysis element");
+}
+
+static void
+gst_rg_analysis_init (GstRgAnalysis * filter)
+{
+  GstBaseTransform *base = GST_BASE_TRANSFORM (filter);
+
+  gst_base_transform_set_gap_aware (base, TRUE);
+
+  filter->num_tracks = 0;
+  filter->forced = FORCED_DEFAULT;
+  filter->message = DEFAULT_MESSAGE;
+  filter->reference_level = RG_REFERENCE_LEVEL;
+
+  filter->ctx = NULL;
+  filter->analyze = NULL;
+}
+
+static void
+gst_rg_analysis_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRgAnalysis *filter = GST_RG_ANALYSIS (object);
+
+  GST_OBJECT_LOCK (filter);
+  switch (prop_id) {
+    case PROP_NUM_TRACKS:
+      filter->num_tracks = g_value_get_int (value);
+      break;
+    case PROP_FORCED:
+      filter->forced = g_value_get_boolean (value);
+      break;
+    case PROP_REFERENCE_LEVEL:
+      filter->reference_level = g_value_get_double (value);
+      break;
+    case PROP_MESSAGE:
+      filter->message = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (filter);
+}
+
+static void
+gst_rg_analysis_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRgAnalysis *filter = GST_RG_ANALYSIS (object);
+
+  GST_OBJECT_LOCK (filter);
+  switch (prop_id) {
+    case PROP_NUM_TRACKS:
+      g_value_set_int (value, filter->num_tracks);
+      break;
+    case PROP_FORCED:
+      g_value_set_boolean (value, filter->forced);
+      break;
+    case PROP_REFERENCE_LEVEL:
+      g_value_set_double (value, filter->reference_level);
+      break;
+    case PROP_MESSAGE:
+      g_value_set_boolean (value, filter->message);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (filter);
+}
+
+static void
+gst_rg_analysis_post_message (gpointer rganalysis, GstClockTime timestamp,
+    GstClockTime duration, gdouble rglevel)
+{
+  GstRgAnalysis *filter = GST_RG_ANALYSIS (rganalysis);
+  if (filter->message) {
+    GstMessage *m;
+
+    m = gst_message_new_element (GST_OBJECT_CAST (rganalysis),
+        gst_structure_new ("rganalysis",
+            "timestamp", G_TYPE_UINT64, timestamp,
+            "duration", G_TYPE_UINT64, duration,
+            "rglevel", G_TYPE_DOUBLE, rglevel, NULL));
+
+    gst_element_post_message (GST_ELEMENT_CAST (rganalysis), m);
+  }
+}
+
+
+static gboolean
+gst_rg_analysis_start (GstBaseTransform * base)
+{
+  GstRgAnalysis *filter = GST_RG_ANALYSIS (base);
+
+  filter->ignore_tags = FALSE;
+  filter->skip = FALSE;
+  filter->has_track_gain = FALSE;
+  filter->has_track_peak = FALSE;
+  filter->has_album_gain = FALSE;
+  filter->has_album_peak = FALSE;
+
+  filter->ctx = rg_analysis_new ();
+  GST_OBJECT_LOCK (filter);
+  rg_analysis_init_silence_detection (filter->ctx, gst_rg_analysis_post_message,
+      filter);
+  GST_OBJECT_UNLOCK (filter);
+  filter->analyze = NULL;
+
+  GST_LOG_OBJECT (filter, "started");
+
+  return TRUE;
+}
+
+static gboolean
+gst_rg_analysis_set_caps (GstBaseTransform * base, GstCaps * in_caps,
+    GstCaps * out_caps)
+{
+  GstRgAnalysis *filter = GST_RG_ANALYSIS (base);
+  GstAudioInfo info;
+  gint rate, channels;
+
+  g_return_val_if_fail (filter->ctx != NULL, FALSE);
+
+  GST_DEBUG_OBJECT (filter,
+      "set_caps in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT,
+      in_caps, out_caps);
+
+  if (!gst_audio_info_from_caps (&info, in_caps))
+    goto invalid_format;
+
+  rate = GST_AUDIO_INFO_RATE (&info);
+
+  if (!rg_analysis_set_sample_rate (filter->ctx, rate))
+    goto invalid_format;
+
+  channels = GST_AUDIO_INFO_CHANNELS (&info);
+
+  if (channels < 1 || channels > 2)
+    goto invalid_format;
+
+  switch (GST_AUDIO_INFO_FORMAT (&info)) {
+    case GST_AUDIO_FORMAT_F32:
+      /* The depth is not variable for float formats of course.  It just
+       * makes the transform function nice and simple if the
+       * rg_analysis_analyze_* functions have a common signature. */
+      filter->depth = sizeof (gfloat) * 8;
+
+      if (channels == 1)
+        filter->analyze = rg_analysis_analyze_mono_float;
+      else
+        filter->analyze = rg_analysis_analyze_stereo_float;
+
+      break;
+    case GST_AUDIO_FORMAT_S16:
+      filter->depth = sizeof (gint16) * 8;
+
+      if (channels == 1)
+        filter->analyze = rg_analysis_analyze_mono_int16;
+      else
+        filter->analyze = rg_analysis_analyze_stereo_int16;
+      break;
+    default:
+      goto invalid_format;
+  }
+
+  return TRUE;
+
+  /* Errors. */
+invalid_format:
+  {
+    filter->analyze = NULL;
+    GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION,
+        ("Invalid incoming caps: %" GST_PTR_FORMAT, in_caps), (NULL));
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_rg_analysis_transform_ip (GstBaseTransform * base, GstBuffer * buf)
+{
+  GstRgAnalysis *filter = GST_RG_ANALYSIS (base);
+  GstMapInfo map;
+
+  g_return_val_if_fail (filter->ctx != NULL, GST_FLOW_FLUSHING);
+  g_return_val_if_fail (filter->analyze != NULL, GST_FLOW_NOT_NEGOTIATED);
+
+  if (filter->skip)
+    return GST_FLOW_OK;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  GST_LOG_OBJECT (filter, "processing buffer of size %" G_GSIZE_FORMAT,
+      map.size);
+
+  rg_analysis_start_buffer (filter->ctx, GST_BUFFER_TIMESTAMP (buf));
+  filter->analyze (filter->ctx, map.data, map.size, filter->depth);
+
+  gst_buffer_unmap (buf, &map);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_rg_analysis_sink_event (GstBaseTransform * base, GstEvent * event)
+{
+  GstRgAnalysis *filter = GST_RG_ANALYSIS (base);
+
+  g_return_val_if_fail (filter->ctx != NULL, TRUE);
+
+  switch (GST_EVENT_TYPE (event)) {
+
+    case GST_EVENT_EOS:
+    {
+      GST_LOG_OBJECT (filter, "received EOS event");
+
+      gst_rg_analysis_handle_eos (filter);
+
+      GST_LOG_OBJECT (filter, "passing on EOS event");
+
+      break;
+    }
+    case GST_EVENT_TAG:
+    {
+      GstTagList *tag_list;
+
+      /* The reference to the tag list is borrowed. */
+      gst_event_parse_tag (event, &tag_list);
+      gst_rg_analysis_handle_tags (filter, tag_list);
+
+      break;
+    }
+    default:
+      break;
+  }
+
+  return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (base, event);
+}
+
+static gboolean
+gst_rg_analysis_stop (GstBaseTransform * base)
+{
+  GstRgAnalysis *filter = GST_RG_ANALYSIS (base);
+
+  g_return_val_if_fail (filter->ctx != NULL, FALSE);
+
+  rg_analysis_destroy (filter->ctx);
+  filter->ctx = NULL;
+
+  GST_LOG_OBJECT (filter, "stopped");
+
+  return TRUE;
+}
+
+/* FIXME: handle global vs. stream-tags? */
+static void
+gst_rg_analysis_handle_tags (GstRgAnalysis * filter,
+    const GstTagList * tag_list)
+{
+  gboolean album_processing = (filter->num_tracks > 0);
+  gdouble dummy;
+
+  if (!album_processing)
+    filter->ignore_tags = FALSE;
+
+  if (filter->skip && album_processing) {
+    GST_DEBUG_OBJECT (filter, "ignoring tag event: skipping album");
+    return;
+  } else if (filter->skip) {
+    GST_DEBUG_OBJECT (filter, "ignoring tag event: skipping track");
+    return;
+  } else if (filter->ignore_tags) {
+    GST_DEBUG_OBJECT (filter, "ignoring tag event: cannot skip anyways");
+    return;
+  }
+
+  filter->has_track_gain |= gst_tag_list_get_double (tag_list,
+      GST_TAG_TRACK_GAIN, &dummy);
+  filter->has_track_peak |= gst_tag_list_get_double (tag_list,
+      GST_TAG_TRACK_PEAK, &dummy);
+  filter->has_album_gain |= gst_tag_list_get_double (tag_list,
+      GST_TAG_ALBUM_GAIN, &dummy);
+  filter->has_album_peak |= gst_tag_list_get_double (tag_list,
+      GST_TAG_ALBUM_PEAK, &dummy);
+
+  if (!(filter->has_track_gain && filter->has_track_peak)) {
+    GST_DEBUG_OBJECT (filter, "track tags not complete yet");
+    return;
+  }
+
+  if (album_processing && !(filter->has_album_gain && filter->has_album_peak)) {
+    GST_DEBUG_OBJECT (filter, "album tags not complete yet");
+    return;
+  }
+
+  if (filter->forced) {
+    GST_DEBUG_OBJECT (filter,
+        "existing tags are sufficient, but processing anyway (forced)");
+    return;
+  }
+
+  filter->skip = TRUE;
+  rg_analysis_reset (filter->ctx);
+
+  if (!album_processing) {
+    GST_DEBUG_OBJECT (filter,
+        "existing tags are sufficient, will not process this track");
+  } else {
+    GST_DEBUG_OBJECT (filter,
+        "existing tags are sufficient, will not process this album");
+  }
+}
+
+static void
+gst_rg_analysis_handle_eos (GstRgAnalysis * filter)
+{
+  gboolean album_processing = (filter->num_tracks > 0);
+  gboolean album_finished = (filter->num_tracks == 1);
+  gboolean album_skipping = album_processing && filter->skip;
+
+  filter->has_track_gain = FALSE;
+  filter->has_track_peak = FALSE;
+
+  if (album_finished) {
+    filter->ignore_tags = FALSE;
+    filter->skip = FALSE;
+    filter->has_album_gain = FALSE;
+    filter->has_album_peak = FALSE;
+  } else if (!album_skipping) {
+    filter->skip = FALSE;
+  }
+
+  /* We might have just fully processed a track because it has
+   * incomplete tags.  If we do album processing and allow skipping
+   * (not forced), prevent switching to skipping if a later track with
+   * full tags comes along: */
+  if (!filter->forced && album_processing && !album_finished)
+    filter->ignore_tags = TRUE;
+
+  if (!filter->skip) {
+    GstTagList *tag_list = NULL;
+    gboolean track_success;
+    gboolean album_success = FALSE;
+
+    track_success = gst_rg_analysis_track_result (filter, &tag_list);
+
+    if (album_finished)
+      album_success = gst_rg_analysis_album_result (filter, &tag_list);
+    else if (!album_processing)
+      rg_analysis_reset_album (filter->ctx);
+
+    if (track_success || album_success) {
+      GST_LOG_OBJECT (filter, "posting tag list with results");
+      gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
+          GST_TAG_REFERENCE_LEVEL, filter->reference_level, NULL);
+      /* This takes ownership of our reference to the list */
+      gst_pad_push_event (GST_BASE_TRANSFORM_SRC_PAD (filter),
+          gst_event_new_tag (tag_list));
+      tag_list = NULL;
+    }
+  }
+
+  if (album_processing) {
+    filter->num_tracks--;
+
+    if (!album_finished) {
+      GST_DEBUG_OBJECT (filter, "album not finished yet (num-tracks is now %u)",
+          filter->num_tracks);
+    } else {
+      GST_DEBUG_OBJECT (filter, "album finished (num-tracks is now 0)");
+    }
+  }
+
+  if (album_processing)
+    g_object_notify (G_OBJECT (filter), "num-tracks");
+}
+
+/* FIXME: return tag list (lists?) based on input tags.. */
+static gboolean
+gst_rg_analysis_track_result (GstRgAnalysis * filter, GstTagList ** tag_list)
+{
+  gboolean track_success;
+  gdouble track_gain, track_peak;
+
+  track_success = rg_analysis_track_result (filter->ctx, &track_gain,
+      &track_peak);
+
+  if (track_success) {
+    track_gain += filter->reference_level - RG_REFERENCE_LEVEL;
+    GST_INFO_OBJECT (filter, "track gain is %+.2f dB, peak %.6f", track_gain,
+        track_peak);
+  } else {
+    GST_INFO_OBJECT (filter, "track was too short to analyze");
+  }
+
+  if (track_success) {
+    if (*tag_list == NULL)
+      *tag_list = gst_tag_list_new_empty ();
+    gst_tag_list_add (*tag_list, GST_TAG_MERGE_APPEND,
+        GST_TAG_TRACK_PEAK, track_peak, GST_TAG_TRACK_GAIN, track_gain, NULL);
+  }
+
+  return track_success;
+}
+
+static gboolean
+gst_rg_analysis_album_result (GstRgAnalysis * filter, GstTagList ** tag_list)
+{
+  gboolean album_success;
+  gdouble album_gain, album_peak;
+
+  album_success = rg_analysis_album_result (filter->ctx, &album_gain,
+      &album_peak);
+
+  if (album_success) {
+    album_gain += filter->reference_level - RG_REFERENCE_LEVEL;
+    GST_INFO_OBJECT (filter, "album gain is %+.2f dB, peak %.6f", album_gain,
+        album_peak);
+  } else {
+    GST_INFO_OBJECT (filter, "album was too short to analyze");
+  }
+
+  if (album_success) {
+    if (*tag_list == NULL)
+      *tag_list = gst_tag_list_new_empty ();
+    gst_tag_list_add (*tag_list, GST_TAG_MERGE_APPEND,
+        GST_TAG_ALBUM_PEAK, album_peak, GST_TAG_ALBUM_GAIN, album_gain, NULL);
+  }
+
+  return album_success;
+}
diff --git a/gst/replaygain/gstrganalysis.h b/gst/replaygain/gstrganalysis.h
new file mode 100644
index 0000000..0d68e63
--- /dev/null
+++ b/gst/replaygain/gstrganalysis.h
@@ -0,0 +1,86 @@
+/* GStreamer ReplayGain analysis
+ *
+ * Copyright (C) 2006 Rene Stadler <mail@renestadler.de>
+ *
+ * gstrganalysis.h: Element that performs the ReplayGain analysis
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __GST_RG_ANALYSIS_H__
+#define __GST_RG_ANALYSIS_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+
+#include "rganalysis.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RG_ANALYSIS \
+  (gst_rg_analysis_get_type())
+#define GST_RG_ANALYSIS(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RG_ANALYSIS,GstRgAnalysis))
+#define GST_RG_ANALYSIS_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RG_ANALYSIS,GstRgAnalysisClass))
+#define GST_IS_RG_ANALYSIS(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RG_ANALYSIS))
+#define GST_IS_RG_ANALYSIS_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RG_ANALYSIS))
+typedef struct _GstRgAnalysis GstRgAnalysis;
+typedef struct _GstRgAnalysisClass GstRgAnalysisClass;
+
+/**
+ * GstRgAnalysis:
+ *
+ * Opaque data structure.
+ */
+struct _GstRgAnalysis
+{
+  GstBaseTransform element;
+
+  /*< private >*/
+
+  RgAnalysisCtx *ctx;
+  void (*analyze) (RgAnalysisCtx * ctx, gconstpointer data, gsize size,
+      guint depth);
+  gint depth;
+
+  /* Property values. */
+  guint num_tracks;
+  gdouble reference_level;
+  gboolean forced;
+  gboolean message;
+
+  /* State machinery for skipping. */
+  gboolean ignore_tags;
+  gboolean skip;
+  gboolean has_track_gain;
+  gboolean has_track_peak;
+  gboolean has_album_gain;
+  gboolean has_album_peak;
+};
+
+struct _GstRgAnalysisClass
+{
+  GstBaseTransformClass parent_class;
+};
+
+GType gst_rg_analysis_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_RG_ANALYSIS_H__ */
diff --git a/gst/replaygain/gstrglimiter.c b/gst/replaygain/gstrglimiter.c
new file mode 100644
index 0000000..5e04e7d
--- /dev/null
+++ b/gst/replaygain/gstrglimiter.c
@@ -0,0 +1,199 @@
+/* GStreamer ReplayGain limiter
+ *
+ * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
+ * 
+ * gstrglimiter.c: Element to apply signal compression to raw audio data
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+/**
+ * SECTION:element-rglimiter
+ * @see_also: #GstRgVolume
+ *
+ * This element applies signal compression/limiting to raw audio data.  It
+ * performs strict hard limiting with soft-knee characteristics, using a
+ * threshold of -6 dB.  This type of filter is mentioned in the proposed <ulink
+ * url="http://replaygain.org">ReplayGain standard</ulink>.
+ * 
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=filename.ext ! decodebin ! audioconvert \
+ *            ! rgvolume pre-amp=6.0 headroom=10.0 ! rglimiter \
+ *            ! audioconvert ! audioresample ! alsasink
+ * ]|Playback of a file
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gst/gst.h>
+#include <math.h>
+#include <gst/audio/audio.h>
+
+#include "gstrglimiter.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_rg_limiter_debug);
+#define GST_CAT_DEFAULT gst_rg_limiter_debug
+
+enum
+{
+  PROP_0,
+  PROP_ENABLED,
+};
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (F32) ", "
+        "layout = (string) { interleaved, non-interleaved }, "
+        "channels = (int) [1, MAX], " "rate = (int) [1, MAX]"));
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (F32) ", "
+        "layout = (string) { interleaved, non-interleaved}, "
+        "channels = (int) [1, MAX], " "rate = (int) [1, MAX]"));
+
+#define gst_rg_limiter_parent_class parent_class
+G_DEFINE_TYPE (GstRgLimiter, gst_rg_limiter, GST_TYPE_BASE_TRANSFORM);
+
+static void gst_rg_limiter_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rg_limiter_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstFlowReturn gst_rg_limiter_transform_ip (GstBaseTransform * base,
+    GstBuffer * buf);
+
+static void
+gst_rg_limiter_class_init (GstRgLimiterClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+  GstBaseTransformClass *trans_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_rg_limiter_set_property;
+  gobject_class->get_property = gst_rg_limiter_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_ENABLED,
+      g_param_spec_boolean ("enabled", "Enabled", "Enable processing", TRUE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  trans_class = GST_BASE_TRANSFORM_CLASS (klass);
+  trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_rg_limiter_transform_ip);
+  trans_class->passthrough_on_same_caps = FALSE;
+
+  gst_element_class_add_static_pad_template (element_class, &src_factory);
+  gst_element_class_add_static_pad_template (element_class, &sink_factory);
+  gst_element_class_set_static_metadata (element_class, "ReplayGain limiter",
+      "Filter/Effect/Audio",
+      "Apply signal compression to raw audio data",
+      "Ren\xc3\xa9 Stadler <mail@renestadler.de>");
+
+  GST_DEBUG_CATEGORY_INIT (gst_rg_limiter_debug, "rglimiter", 0,
+      "ReplayGain limiter element");
+}
+
+static void
+gst_rg_limiter_init (GstRgLimiter * filter)
+{
+  GstBaseTransform *base = GST_BASE_TRANSFORM (filter);
+
+  gst_base_transform_set_passthrough (base, FALSE);
+  gst_base_transform_set_gap_aware (base, TRUE);
+
+  filter->enabled = TRUE;
+}
+
+static void
+gst_rg_limiter_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRgLimiter *filter = GST_RG_LIMITER (object);
+
+  switch (prop_id) {
+    case PROP_ENABLED:
+      filter->enabled = g_value_get_boolean (value);
+      gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter),
+          !filter->enabled);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rg_limiter_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRgLimiter *filter = GST_RG_LIMITER (object);
+
+  switch (prop_id) {
+    case PROP_ENABLED:
+      g_value_set_boolean (value, filter->enabled);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+#define LIMIT 1.0
+#define THRES 0.5               /* ca. -6 dB */
+#define COMPL 0.5               /* LIMIT - THRESH */
+
+static GstFlowReturn
+gst_rg_limiter_transform_ip (GstBaseTransform * base, GstBuffer * buf)
+{
+  GstRgLimiter *filter = GST_RG_LIMITER (base);
+  gfloat *input;
+  GstMapInfo map;
+  guint count;
+  guint i;
+
+  if (!filter->enabled)
+    return GST_FLOW_OK;
+
+  if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP))
+    return GST_FLOW_OK;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  input = (gfloat *) map.data;
+  count = gst_buffer_get_size (buf) / sizeof (gfloat);
+
+  for (i = count; i--;) {
+    if (*input > THRES)
+      *input = tanhf ((*input - THRES) / COMPL) * COMPL + THRES;
+    else if (*input < -THRES)
+      *input = tanhf ((*input + THRES) / COMPL) * COMPL - THRES;
+    input++;
+  }
+
+  gst_buffer_unmap (buf, &map);
+
+  return GST_FLOW_OK;
+}
diff --git a/gst/replaygain/gstrglimiter.h b/gst/replaygain/gstrglimiter.h
new file mode 100644
index 0000000..63bd804
--- /dev/null
+++ b/gst/replaygain/gstrglimiter.h
@@ -0,0 +1,64 @@
+/* GStreamer ReplayGain limiter
+ *
+ * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
+ *
+ * gstrglimiter.h: Element to apply signal compression to raw audio data
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __GST_RG_LIMITER_H__
+#define __GST_RG_LIMITER_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+
+#define GST_TYPE_RG_LIMITER \
+  (gst_rg_limiter_get_type())
+#define GST_RG_LIMITER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RG_LIMITER,GstRgLimiter))
+#define GST_RG_LIMITER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RG_LIMITER,GstRgLimiterClass))
+#define GST_IS_RG_LIMITER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RG_LIMITER))
+#define GST_IS_RG_LIMITER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RG_LIMITER))
+
+typedef struct _GstRgLimiter GstRgLimiter;
+typedef struct _GstRgLimiterClass GstRgLimiterClass;
+
+/**
+ * GstRgLimiter:
+ *
+ * Opaque data structure.
+ */
+struct _GstRgLimiter
+{
+  GstBaseTransform element;
+
+  /*< private >*/
+
+  gboolean enabled;
+};
+
+struct _GstRgLimiterClass
+{
+  GstBaseTransformClass parent_class;
+};
+
+GType gst_rg_limiter_get_type (void);
+
+#endif /* __GST_RG_LIMITER_H__ */
diff --git a/gst/replaygain/gstrgvolume.c b/gst/replaygain/gstrgvolume.c
new file mode 100644
index 0000000..7c4f281
--- /dev/null
+++ b/gst/replaygain/gstrgvolume.c
@@ -0,0 +1,686 @@
+/* GStreamer ReplayGain volume adjustment
+ *
+ * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
+ * 
+ * gstrgvolume.c: Element to apply ReplayGain volume adjustment
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+/**
+ * SECTION:element-rgvolume
+ * @see_also: #GstRgLimiter, #GstRgAnalysis
+ *
+ * This element applies volume changes to streams as lined out in the proposed
+ * <ulink url="http://replaygain.org">ReplayGain standard</ulink>.  It
+ * interprets the ReplayGain meta data tags and carries out the adjustment (by
+ * using a volume element internally).  The relevant tags are:
+ * <itemizedlist>
+ * <listitem>#GST_TAG_TRACK_GAIN</listitem>
+ * <listitem>#GST_TAG_TRACK_PEAK</listitem>
+ * <listitem>#GST_TAG_ALBUM_GAIN</listitem>
+ * <listitem>#GST_TAG_ALBUM_PEAK</listitem>
+ * <listitem>#GST_TAG_REFERENCE_LEVEL</listitem>
+ * </itemizedlist>
+ * The information carried by these tags must have been calculated beforehand by
+ * performing the ReplayGain analysis.  This is implemented by the <link
+ * linkend="GstRgAnalysis">rganalysis</link> element.
+ * 
+ * The signal compression/limiting recommendations outlined in the proposed
+ * standard are not implemented by this element.  This has to be handled by
+ * separate elements because applications might want to have additional filters
+ * between the volume adjustment and the limiting stage.  A basic limiter is
+ * included with this plugin: The <link linkend="GstRgLimiter">rglimiter</link>
+ * element applies -6 dB hard limiting as mentioned in the ReplayGain standard.
+ * 
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=filename.ext ! decodebin ! audioconvert \
+ *     ! rgvolume ! audioconvert ! audioresample ! alsasink
+ * ]| Playback of a file
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gst/gst.h>
+#include <gst/pbutils/pbutils.h>
+#include <gst/audio/audio.h>
+#include <math.h>
+
+#include "gstrgvolume.h"
+#include "replaygain.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_rg_volume_debug);
+#define GST_CAT_DEFAULT gst_rg_volume_debug
+
+enum
+{
+  PROP_0,
+  PROP_ALBUM_MODE,
+  PROP_HEADROOM,
+  PROP_PRE_AMP,
+  PROP_FALLBACK_GAIN,
+  PROP_TARGET_GAIN,
+  PROP_RESULT_GAIN
+};
+
+#define DEFAULT_ALBUM_MODE TRUE
+#define DEFAULT_HEADROOM 0.0
+#define DEFAULT_PRE_AMP 0.0
+#define DEFAULT_FALLBACK_GAIN 0.0
+
+#define DB_TO_LINEAR(x) pow (10., (x) / 20.)
+#define LINEAR_TO_DB(x) (20. * log10 (x))
+
+#define GAIN_FORMAT "+.02f dB"
+#define PEAK_FORMAT ".06f"
+
+#define VALID_GAIN(x) ((x) > -60.00 && (x) < 60.00)
+#define VALID_PEAK(x) ((x) > 0.)
+
+/* Same template caps as GstVolume, for I don't like having just ANY caps. */
+
+#define FORMAT "{ "GST_AUDIO_NE(F32)","GST_AUDIO_NE(S16)" }"
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " FORMAT ", "
+        "layout = (string) { interleaved, non-interleaved }, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]"));
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " FORMAT ", "
+        "layout = (string) { interleaved, non-interleaved }, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]"));
+
+#define gst_rg_volume_parent_class parent_class
+G_DEFINE_TYPE (GstRgVolume, gst_rg_volume, GST_TYPE_BIN);
+
+static void gst_rg_volume_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rg_volume_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_rg_volume_dispose (GObject * object);
+
+static GstStateChangeReturn gst_rg_volume_change_state (GstElement * element,
+    GstStateChange transition);
+static gboolean gst_rg_volume_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+
+static GstEvent *gst_rg_volume_tag_event (GstRgVolume * self, GstEvent * event);
+static void gst_rg_volume_reset (GstRgVolume * self);
+static void gst_rg_volume_update_gain (GstRgVolume * self);
+static inline void gst_rg_volume_determine_gain (GstRgVolume * self,
+    gdouble * target_gain, gdouble * result_gain);
+
+static void
+gst_rg_volume_class_init (GstRgVolumeClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+  GstBinClass *bin_class;
+
+  gobject_class = (GObjectClass *) klass;
+
+  gobject_class->set_property = gst_rg_volume_set_property;
+  gobject_class->get_property = gst_rg_volume_get_property;
+  gobject_class->dispose = gst_rg_volume_dispose;
+
+  /**
+   * GstRgVolume:album-mode:
+   *
+   * Whether to prefer album gain over track gain.
+   *
+   * If set to %TRUE, use album gain instead of track gain if both are
+   * available.  This keeps the relative loudness levels of tracks from the same
+   * album intact.
+   *
+   * If set to %FALSE, track mode is used instead.  This effectively leads to
+   * more extensive normalization.
+   *
+   * If album mode is enabled but the album gain tag is absent in the stream,
+   * the track gain is used instead.  If both gain tags are missing, the value
+   * of the #GstRgVolume:fallback-gain property is used instead.
+   */
+  g_object_class_install_property (gobject_class, PROP_ALBUM_MODE,
+      g_param_spec_boolean ("album-mode", "Album mode",
+          "Prefer album over track gain", DEFAULT_ALBUM_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRgVolume:headroom:
+   *
+   * Extra headroom [dB].  This controls the amount by which the output can
+   * exceed digital full scale.
+   *
+   * Only set this to a value greater than 0.0 if signal compression/limiting of
+   * a suitable form is applied to the output (or output is brought into the
+   * correct range by some other transformation).
+   *
+   * This element internally uses a volume element, which also supports
+   * operating on integer audio formats.  These formats do not allow exceeding
+   * digital full scale.  If extra headroom is used, make sure that the raw
+   * audio data format is floating point (F32).  Otherwise,
+   * clipping distortion might be introduced as part of the volume adjustment
+   * itself.
+   */
+  g_object_class_install_property (gobject_class, PROP_HEADROOM,
+      g_param_spec_double ("headroom", "Headroom", "Extra headroom [dB]",
+          0., 60., DEFAULT_HEADROOM,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRgVolume:pre-amp:
+   *
+   * Additional gain to apply globally [dB].  This controls the trade-off
+   * between uniformity of normalization and utilization of available dynamic
+   * range.
+   *
+   * Note that the default value is 0 dB because the ReplayGain reference value
+   * was adjusted by +6 dB (from 83 to 89 dB).  At the time of this writing, the
+   * <ulink url="http://replaygain.org">webpage</ulink> is still outdated and
+   * does not reflect this change however.  Where the original proposal states
+   * that a proper default pre-amp value is +6 dB, this translates to the used 0
+   * dB.
+   */
+  g_object_class_install_property (gobject_class, PROP_PRE_AMP,
+      g_param_spec_double ("pre-amp", "Pre-amp", "Extra gain [dB]",
+          -60., 60., DEFAULT_PRE_AMP,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRgVolume:fallback-gain:
+   *
+   * Fallback gain [dB] for streams missing ReplayGain tags.
+   */
+  g_object_class_install_property (gobject_class, PROP_FALLBACK_GAIN,
+      g_param_spec_double ("fallback-gain", "Fallback gain",
+          "Gain for streams missing tags [dB]",
+          -60., 60., DEFAULT_FALLBACK_GAIN,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRgVolume:result-gain:
+   *
+   * Applied gain [dB].  This gain is applied to processed buffer data.
+   *
+   * This is set to the #GstRgVolume:target-gain if amplification by that amount
+   * can be applied safely. "Safely" means that the volume adjustment does not
+   * inflict clipping distortion.  Should this not be the case, the result gain
+   * is set to an appropriately reduced value (by applying peak normalization).
+   * The proposed standard calls this "clipping prevention".
+   *
+   * The difference between target and result gain reflects the necessary amount
+   * of reduction.  Applications can make use of this information to temporarily
+   * reduce the #GstRgVolume:pre-amp for subsequent streams, as recommended by
+   * the ReplayGain standard.
+   *
+   * Note that target and result gain differing for a great majority of streams
+   * indicates a problem: What happens in this case is that most streams receive
+   * peak normalization instead of amplification by the ideal replay gain.  To
+   * prevent this, the #GstRgVolume:pre-amp has to be lowered and/or a limiter
+   * has to be used which facilitates the use of #GstRgVolume:headroom.
+   */
+  g_object_class_install_property (gobject_class, PROP_RESULT_GAIN,
+      g_param_spec_double ("result-gain", "Result-gain", "Applied gain [dB]",
+          -120., 120., 0., G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRgVolume:target-gain:
+   *
+   * Applicable gain [dB].  This gain is supposed to be applied.
+   *
+   * Depending on the value of the #GstRgVolume:album-mode property and the
+   * presence of ReplayGain tags in the stream, this is set according to one of
+   * these simple formulas:
+   *
+   * <itemizedlist>
+   * <listitem>#GstRgVolume:pre-amp + album gain of the stream</listitem>
+   * <listitem>#GstRgVolume:pre-amp + track gain of the stream</listitem>
+   * <listitem>#GstRgVolume:pre-amp + #GstRgVolume:fallback-gain</listitem>
+   * </itemizedlist>
+   */
+  g_object_class_install_property (gobject_class, PROP_TARGET_GAIN,
+      g_param_spec_double ("target-gain", "Target-gain",
+          "Applicable gain [dB]", -120., 120., 0.,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  element_class = (GstElementClass *) klass;
+  element_class->change_state = GST_DEBUG_FUNCPTR (gst_rg_volume_change_state);
+
+  bin_class = (GstBinClass *) klass;
+  /* Setting these to NULL makes gst_bin_add and _remove refuse to let anyone
+   * mess with our internals. */
+  bin_class->add_element = NULL;
+  bin_class->remove_element = NULL;
+
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+  gst_element_class_set_static_metadata (element_class, "ReplayGain volume",
+      "Filter/Effect/Audio",
+      "Apply ReplayGain volume adjustment",
+      "Ren\xc3\xa9 Stadler <mail@renestadler.de>");
+
+  GST_DEBUG_CATEGORY_INIT (gst_rg_volume_debug, "rgvolume", 0,
+      "ReplayGain volume element");
+}
+
+static void
+gst_rg_volume_init (GstRgVolume * self)
+{
+  GObjectClass *volume_class;
+  GstPad *volume_pad, *ghost_pad;
+
+  self->album_mode = DEFAULT_ALBUM_MODE;
+  self->headroom = DEFAULT_HEADROOM;
+  self->pre_amp = DEFAULT_PRE_AMP;
+  self->fallback_gain = DEFAULT_FALLBACK_GAIN;
+  self->target_gain = 0.0;
+  self->result_gain = 0.0;
+
+  self->volume_element = gst_element_factory_make ("volume", "rgvolume-volume");
+  if (G_UNLIKELY (self->volume_element == NULL)) {
+    GstMessage *msg;
+
+    GST_WARNING_OBJECT (self, "could not create volume element");
+    msg = gst_missing_element_message_new (GST_ELEMENT_CAST (self), "volume");
+    gst_element_post_message (GST_ELEMENT_CAST (self), msg);
+
+    /* Nothing else to do, we will refuse the state change from NULL to READY to
+     * indicate that something went very wrong.  It is doubtful that someone
+     * attempts changing our state though, since we end up having no pads! */
+    return;
+  }
+
+  volume_class = G_OBJECT_GET_CLASS (G_OBJECT (self->volume_element));
+  self->max_volume = G_PARAM_SPEC_DOUBLE
+      (g_object_class_find_property (volume_class, "volume"))->maximum;
+
+  GST_BIN_CLASS (parent_class)->add_element (GST_BIN_CAST (self),
+      self->volume_element);
+
+  volume_pad = gst_element_get_static_pad (self->volume_element, "sink");
+  ghost_pad = gst_ghost_pad_new_from_template ("sink", volume_pad,
+      GST_PAD_PAD_TEMPLATE (volume_pad));
+  gst_object_unref (volume_pad);
+  gst_pad_set_event_function (ghost_pad, gst_rg_volume_sink_event);
+  gst_element_add_pad (GST_ELEMENT_CAST (self), ghost_pad);
+
+  volume_pad = gst_element_get_static_pad (self->volume_element, "src");
+  ghost_pad = gst_ghost_pad_new_from_template ("src", volume_pad,
+      GST_PAD_PAD_TEMPLATE (volume_pad));
+  gst_object_unref (volume_pad);
+  gst_element_add_pad (GST_ELEMENT_CAST (self), ghost_pad);
+}
+
+static void
+gst_rg_volume_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRgVolume *self = GST_RG_VOLUME (object);
+
+  switch (prop_id) {
+    case PROP_ALBUM_MODE:
+      self->album_mode = g_value_get_boolean (value);
+      break;
+    case PROP_HEADROOM:
+      self->headroom = g_value_get_double (value);
+      break;
+    case PROP_PRE_AMP:
+      self->pre_amp = g_value_get_double (value);
+      break;
+    case PROP_FALLBACK_GAIN:
+      self->fallback_gain = g_value_get_double (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  gst_rg_volume_update_gain (self);
+}
+
+static void
+gst_rg_volume_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRgVolume *self = GST_RG_VOLUME (object);
+
+  switch (prop_id) {
+    case PROP_ALBUM_MODE:
+      g_value_set_boolean (value, self->album_mode);
+      break;
+    case PROP_HEADROOM:
+      g_value_set_double (value, self->headroom);
+      break;
+    case PROP_PRE_AMP:
+      g_value_set_double (value, self->pre_amp);
+      break;
+    case PROP_FALLBACK_GAIN:
+      g_value_set_double (value, self->fallback_gain);
+      break;
+    case PROP_TARGET_GAIN:
+      g_value_set_double (value, self->target_gain);
+      break;
+    case PROP_RESULT_GAIN:
+      g_value_set_double (value, self->result_gain);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rg_volume_dispose (GObject * object)
+{
+  GstRgVolume *self = GST_RG_VOLUME (object);
+
+  if (self->volume_element != NULL) {
+    /* Manually remove our child using the bin implementation of remove_element.
+     * This is needed because we prevent gst_bin_remove from working, which the
+     * parent dispose handler would use if we had any children left. */
+    GST_BIN_CLASS (parent_class)->remove_element (GST_BIN_CAST (self),
+        self->volume_element);
+    self->volume_element = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static GstStateChangeReturn
+gst_rg_volume_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRgVolume *self = GST_RG_VOLUME (element);
+  GstStateChangeReturn res;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+
+      if (G_UNLIKELY (self->volume_element == NULL)) {
+        /* Creating our child volume element in _init failed. */
+        return GST_STATE_CHANGE_FAILURE;
+      }
+      break;
+
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+
+      gst_rg_volume_reset (self);
+      break;
+
+    default:
+      break;
+  }
+
+  res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  return res;
+}
+
+/* Event function for the ghost sink pad. */
+static gboolean
+gst_rg_volume_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstRgVolume *self;
+  GstEvent *send_event = event;
+  gboolean res;
+
+  self = GST_RG_VOLUME (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_TAG:
+
+      GST_LOG_OBJECT (self, "received tag event");
+
+      send_event = gst_rg_volume_tag_event (self, event);
+
+      if (send_event == NULL)
+        GST_LOG_OBJECT (self, "all tags handled, dropping event");
+
+      break;
+
+    case GST_EVENT_EOS:
+
+      gst_rg_volume_reset (self);
+      break;
+
+    default:
+      break;
+  }
+
+  if (G_LIKELY (send_event != NULL))
+    res = gst_pad_event_default (pad, parent, send_event);
+  else
+    res = TRUE;
+
+  return res;
+}
+
+static GstEvent *
+gst_rg_volume_tag_event (GstRgVolume * self, GstEvent * event)
+{
+  GstTagList *tag_list;
+  gboolean has_track_gain, has_track_peak, has_album_gain, has_album_peak;
+  gboolean has_ref_level;
+
+  g_return_val_if_fail (event != NULL, NULL);
+  g_return_val_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_TAG, event);
+
+  gst_event_parse_tag (event, &tag_list);
+
+  if (gst_tag_list_is_empty (tag_list))
+    return event;
+
+  has_track_gain = gst_tag_list_get_double (tag_list, GST_TAG_TRACK_GAIN,
+      &self->track_gain);
+  has_track_peak = gst_tag_list_get_double (tag_list, GST_TAG_TRACK_PEAK,
+      &self->track_peak);
+  has_album_gain = gst_tag_list_get_double (tag_list, GST_TAG_ALBUM_GAIN,
+      &self->album_gain);
+  has_album_peak = gst_tag_list_get_double (tag_list, GST_TAG_ALBUM_PEAK,
+      &self->album_peak);
+  has_ref_level = gst_tag_list_get_double (tag_list, GST_TAG_REFERENCE_LEVEL,
+      &self->reference_level);
+
+  if (!has_track_gain && !has_track_peak && !has_album_gain && !has_album_peak)
+    return event;
+
+  if (has_ref_level && (has_track_gain || has_album_gain)
+      && (ABS (self->reference_level - RG_REFERENCE_LEVEL) > 1.e-6)) {
+    /* Log a message stating the amount of adjustment that is applied below. */
+    GST_DEBUG_OBJECT (self,
+        "compensating for reference level difference by %" GAIN_FORMAT,
+        RG_REFERENCE_LEVEL - self->reference_level);
+  }
+  if (has_track_gain) {
+    self->track_gain += RG_REFERENCE_LEVEL - self->reference_level;
+  }
+  if (has_album_gain) {
+    self->album_gain += RG_REFERENCE_LEVEL - self->reference_level;
+  }
+
+  /* Ignore values that are obviously invalid. */
+  if (G_UNLIKELY (has_track_gain && !VALID_GAIN (self->track_gain))) {
+    GST_DEBUG_OBJECT (self,
+        "ignoring bogus track gain value %" GAIN_FORMAT, self->track_gain);
+    has_track_gain = FALSE;
+  }
+  if (G_UNLIKELY (has_track_peak && !VALID_PEAK (self->track_peak))) {
+    GST_DEBUG_OBJECT (self,
+        "ignoring bogus track peak value %" PEAK_FORMAT, self->track_peak);
+    has_track_peak = FALSE;
+  }
+  if (G_UNLIKELY (has_album_gain && !VALID_GAIN (self->album_gain))) {
+    GST_DEBUG_OBJECT (self,
+        "ignoring bogus album gain value %" GAIN_FORMAT, self->album_gain);
+    has_album_gain = FALSE;
+  }
+  if (G_UNLIKELY (has_album_peak && !VALID_PEAK (self->album_peak))) {
+    GST_DEBUG_OBJECT (self,
+        "ignoring bogus album peak value %" PEAK_FORMAT, self->album_peak);
+    has_album_peak = FALSE;
+  }
+
+  /* Clamp peaks >1.0.  Float based decoders can produce spurious samples >1.0,
+   * cutting these files back to 1.0 should not cause any audible distortion.
+   * This is most often seen with Vorbis files. */
+  if (has_track_peak && self->track_peak > 1.) {
+    GST_DEBUG_OBJECT (self,
+        "clamping track peak %" PEAK_FORMAT " to 1.0", self->track_peak);
+    self->track_peak = 1.0;
+  }
+  if (has_album_peak && self->album_peak > 1.) {
+    GST_DEBUG_OBJECT (self,
+        "clamping album peak %" PEAK_FORMAT " to 1.0", self->album_peak);
+    self->album_peak = 1.0;
+  }
+
+  self->has_track_gain |= has_track_gain;
+  self->has_track_peak |= has_track_peak;
+  self->has_album_gain |= has_album_gain;
+  self->has_album_peak |= has_album_peak;
+
+  tag_list = gst_tag_list_copy (tag_list);
+  gst_tag_list_remove_tag (tag_list, GST_TAG_TRACK_GAIN);
+  gst_tag_list_remove_tag (tag_list, GST_TAG_TRACK_PEAK);
+  gst_tag_list_remove_tag (tag_list, GST_TAG_ALBUM_GAIN);
+  gst_tag_list_remove_tag (tag_list, GST_TAG_ALBUM_PEAK);
+  gst_tag_list_remove_tag (tag_list, GST_TAG_REFERENCE_LEVEL);
+
+  gst_rg_volume_update_gain (self);
+
+  gst_event_unref (event);
+  if (gst_tag_list_is_empty (tag_list)) {
+    gst_tag_list_unref (tag_list);
+    return NULL;
+  }
+
+  return gst_event_new_tag (tag_list);
+}
+
+static void
+gst_rg_volume_reset (GstRgVolume * self)
+{
+  self->has_track_gain = FALSE;
+  self->has_track_peak = FALSE;
+  self->has_album_gain = FALSE;
+  self->has_album_peak = FALSE;
+
+  self->reference_level = RG_REFERENCE_LEVEL;
+
+  gst_rg_volume_update_gain (self);
+}
+
+static void
+gst_rg_volume_update_gain (GstRgVolume * self)
+{
+  gdouble target_gain, result_gain, result_volume;
+  gboolean target_gain_changed, result_gain_changed;
+
+  gst_rg_volume_determine_gain (self, &target_gain, &result_gain);
+
+  result_volume = DB_TO_LINEAR (result_gain);
+
+  /* Ensure that the result volume is within the range that the volume element
+   * can handle.  Currently, the limit is 10. (+20 dB), which should not be
+   * restrictive. */
+  if (G_UNLIKELY (result_volume > self->max_volume)) {
+    GST_INFO_OBJECT (self,
+        "cannot handle result gain of %" GAIN_FORMAT " (%0.6f), adjusting",
+        result_gain, result_volume);
+
+    result_volume = self->max_volume;
+    result_gain = LINEAR_TO_DB (result_volume);
+  }
+
+  /* Direct comparison is OK in this case. */
+  if (target_gain == result_gain) {
+    GST_INFO_OBJECT (self,
+        "result gain is %" GAIN_FORMAT " (%0.6f), matching target",
+        result_gain, result_volume);
+  } else {
+    GST_INFO_OBJECT (self,
+        "result gain is %" GAIN_FORMAT " (%0.6f), target is %" GAIN_FORMAT,
+        result_gain, result_volume, target_gain);
+  }
+
+  target_gain_changed = (self->target_gain != target_gain);
+  result_gain_changed = (self->result_gain != result_gain);
+
+  self->target_gain = target_gain;
+  self->result_gain = result_gain;
+
+  g_object_set (self->volume_element, "volume", result_volume, NULL);
+
+  if (target_gain_changed)
+    g_object_notify ((GObject *) self, "target-gain");
+  if (result_gain_changed)
+    g_object_notify ((GObject *) self, "result-gain");
+}
+
+static inline void
+gst_rg_volume_determine_gain (GstRgVolume * self, gdouble * target_gain,
+    gdouble * result_gain)
+{
+  gdouble gain, peak;
+
+  if (!self->has_track_gain && !self->has_album_gain) {
+
+    GST_DEBUG_OBJECT (self, "using fallback gain");
+    gain = self->fallback_gain;
+    peak = 1.0;
+
+  } else if ((self->album_mode && self->has_album_gain)
+      || (!self->album_mode && !self->has_track_gain)) {
+
+    gain = self->album_gain;
+    if (G_LIKELY (self->has_album_peak)) {
+      peak = self->album_peak;
+    } else {
+      GST_DEBUG_OBJECT (self, "album peak missing, assuming 1.0");
+      peak = 1.0;
+    }
+    /* Falling back from track to album gain shouldn't really happen. */
+    if (G_UNLIKELY (!self->album_mode))
+      GST_INFO_OBJECT (self, "falling back to album gain");
+
+  } else {
+    /* !album_mode && !has_album_gain || album_mode && has_track_gain */
+
+    gain = self->track_gain;
+    if (G_LIKELY (self->has_track_peak)) {
+      peak = self->track_peak;
+    } else {
+      GST_DEBUG_OBJECT (self, "track peak missing, assuming 1.0");
+      peak = 1.0;
+    }
+    if (self->album_mode)
+      GST_INFO_OBJECT (self, "falling back to track gain");
+  }
+
+  gain += self->pre_amp;
+
+  *target_gain = gain;
+  *result_gain = gain;
+
+  if (LINEAR_TO_DB (peak) + gain > self->headroom) {
+    *result_gain = LINEAR_TO_DB (1. / peak) + self->headroom;
+  }
+}
diff --git a/gst/replaygain/gstrgvolume.h b/gst/replaygain/gstrgvolume.h
new file mode 100644
index 0000000..a0a5a8c
--- /dev/null
+++ b/gst/replaygain/gstrgvolume.h
@@ -0,0 +1,88 @@
+/* GStreamer ReplayGain volume adjustment
+ *
+ * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
+ *
+ * gstrgvolume.h: Element to apply ReplayGain volume adjustment
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __GST_RG_VOLUME_H__
+#define __GST_RG_VOLUME_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RG_VOLUME \
+  (gst_rg_volume_get_type())
+#define GST_RG_VOLUME(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RG_VOLUME,GstRgVolume))
+#define GST_RG_VOLUME_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RG_VOLUME,GstRgVolumeClass))
+#define GST_IS_RG_VOLUME(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RG_VOLUME))
+#define GST_IS_RG_VOLUME_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RG_VOLUME))
+
+typedef struct _GstRgVolume GstRgVolume;
+typedef struct _GstRgVolumeClass GstRgVolumeClass;
+
+/**
+ * GstRgVolume:
+ *
+ * Opaque data structure.
+ */
+struct _GstRgVolume
+{
+  GstBin bin;
+
+  /*< private >*/
+
+  GstElement *volume_element;
+  gdouble max_volume;
+
+  gboolean album_mode;
+  gdouble headroom;
+  gdouble pre_amp;
+  gdouble fallback_gain;
+
+  gdouble target_gain;
+  gdouble result_gain;
+
+  gdouble track_gain;
+  gdouble track_peak;
+  gdouble album_gain;
+  gdouble album_peak;
+
+  gboolean has_track_gain;
+  gboolean has_track_peak;
+  gboolean has_album_gain;
+  gboolean has_album_peak;
+
+  gdouble reference_level;
+};
+
+struct _GstRgVolumeClass
+{
+  GstBinClass parent_class;
+};
+
+GType gst_rg_volume_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_RG_VOLUME_H__ */
diff --git a/gst/replaygain/meson.build b/gst/replaygain/meson.build
new file mode 100644
index 0000000..34437a2
--- /dev/null
+++ b/gst/replaygain/meson.build
@@ -0,0 +1,17 @@
+replaygain_sources = [
+  'gstrganalysis.c',
+  'gstrglimiter.c',
+  'gstrgvolume.c',
+  'replaygain.c',
+  'rganalysis.c',
+]
+
+gstreplaygain = library('gstreplaygain',
+  replaygain_sources,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gst_dep, gstbase_dep, gstpbutils_dep, gstaudio_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
+
diff --git a/gst/replaygain/replaygain.c b/gst/replaygain/replaygain.c
new file mode 100644
index 0000000..cb499ed
--- /dev/null
+++ b/gst/replaygain/replaygain.c
@@ -0,0 +1,53 @@
+/* GStreamer ReplayGain plugin
+ *
+ * Copyright (C) 2006 Rene Stadler <mail@renestadler.de>
+ * 
+ * replaygain.c: Plugin providing ReplayGain related elements
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gst/gst.h>
+
+#include "gstrganalysis.h"
+#include "gstrglimiter.h"
+#include "gstrgvolume.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "rganalysis", GST_RANK_NONE,
+          GST_TYPE_RG_ANALYSIS))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "rglimiter", GST_RANK_NONE,
+          GST_TYPE_RG_LIMITER))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "rgvolume", GST_RANK_NONE,
+          GST_TYPE_RG_VOLUME))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, replaygain,
+    "ReplayGain volume normalization", plugin_init, VERSION, GST_LICENSE,
+    GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/replaygain/replaygain.h b/gst/replaygain/replaygain.h
new file mode 100644
index 0000000..15be888
--- /dev/null
+++ b/gst/replaygain/replaygain.h
@@ -0,0 +1,36 @@
+/* GStreamer ReplayGain plugin
+ *
+ * Copyright (C) 2006 Rene Stadler <mail@renestadler.de>
+ *
+ * replaygain.h: Plugin providing ReplayGain related elements
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __REPLAYGAIN_H__
+#define __REPLAYGAIN_H__
+
+G_BEGIN_DECLS
+
+/* Reference level (in dBSPL).  The 2001 proposal specifies 83.  This was
+ * changed later in all implementations to 89, which is the new, offical value:
+ * David Robinson acknowledged the change but didn't update the website yet. */
+
+#define RG_REFERENCE_LEVEL 89.
+
+G_END_DECLS
+
+#endif /* __REPLAYGAIN_H__ */
diff --git a/gst/replaygain/rganalysis.c b/gst/replaygain/rganalysis.c
new file mode 100644
index 0000000..3040376
--- /dev/null
+++ b/gst/replaygain/rganalysis.c
@@ -0,0 +1,824 @@
+/* GStreamer ReplayGain analysis
+ *
+ * Copyright (C) 2006 Rene Stadler <mail@renestadler.de>
+ * Copyright (C) 2001 David Robinson <David@Robinson.org>
+ *                    Glen Sawyer <glensawyer@hotmail.com>
+ *
+ * rganalysis.c: Analyze raw audio data in accordance with ReplayGain
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+/* Based on code with Copyright (C) 2001 David Robinson
+ * <David@Robinson.org> and Glen Sawyer <glensawyer@hotmail.com>,
+ * which is distributed under the LGPL as part of the vorbisgain
+ * program.  The original code also mentions Frank Klemm
+ * (http://www.uni-jena.de/~pfk/mpp/) for having contributed lots of
+ * good code.  Specifically, this is based on the file
+ * "gain_analysis.c" from vorbisgain version 0.34.
+ */
+
+/* Room for future improvement: Mono data is currently in fact copied
+ * to two channels which get processed normally.  This means that mono
+ * input data is processed twice.
+ */
+
+/* Helpful information for understanding this code: The two IIR
+ * filters depend on previous input _and_ previous output samples (up
+ * to the filter's order number of samples).  This explains the whole
+ * lot of memcpy'ing done in rg_analysis_analyze and why the context
+ * holds so many buffers.
+ */
+
+#include <math.h>
+#include <string.h>
+#include <glib.h>
+
+#include "rganalysis.h"
+
+#define YULE_ORDER         10
+#define BUTTER_ORDER        2
+/* Percentile which is louder than the proposed level: */
+#define RMS_PERCENTILE     95
+/* Duration of RMS window in milliseconds: */
+#define RMS_WINDOW_MSECS   50
+/* Histogram array elements per dB: */
+#define STEPS_PER_DB      100
+/* Histogram upper bound in dB (normal max. values in the wild are
+ * assumed to be around 70, 80 dB): */
+#define MAX_DB            120
+/* Calibration value: */
+#define PINK_REF           64.82        /* 298640883795 */
+
+#define MAX_ORDER         MAX (BUTTER_ORDER, YULE_ORDER)
+#define MAX_SAMPLE_RATE   48000
+/* The + 999 has the effect of ceil()ing: */
+#define MAX_SAMPLE_WINDOW (guint) \
+  ((MAX_SAMPLE_RATE * RMS_WINDOW_MSECS + 999) / 1000)
+
+/* Analysis result accumulator. */
+
+struct _RgAnalysisAcc
+{
+  guint32 histogram[STEPS_PER_DB * MAX_DB];
+  gdouble peak;
+};
+
+typedef struct _RgAnalysisAcc RgAnalysisAcc;
+
+/* Analysis context. */
+
+struct _RgAnalysisCtx
+{
+  /* Filter buffers for left channel. */
+  gfloat inprebuf_l[MAX_ORDER * 2];
+  gfloat *inpre_l;
+  gfloat stepbuf_l[MAX_SAMPLE_WINDOW + MAX_ORDER];
+  gfloat *step_l;
+  gfloat outbuf_l[MAX_SAMPLE_WINDOW + MAX_ORDER];
+  gfloat *out_l;
+  /* Filter buffers for right channel. */
+  gfloat inprebuf_r[MAX_ORDER * 2];
+  gfloat *inpre_r;
+  gfloat stepbuf_r[MAX_SAMPLE_WINDOW + MAX_ORDER];
+  gfloat *step_r;
+  gfloat outbuf_r[MAX_SAMPLE_WINDOW + MAX_ORDER];
+  gfloat *out_r;
+
+  /* Number of samples to reach duration of the RMS window: */
+  guint window_n_samples;
+  /* Progress of the running window: */
+  guint window_n_samples_done;
+  gdouble window_square_sum;
+
+  gint sample_rate;
+  gint sample_rate_index;
+
+  RgAnalysisAcc track;
+  RgAnalysisAcc album;
+  void (*post_message) (gpointer analysis,
+      GstClockTime timestamp, GstClockTime duration, gdouble rglevel);
+  gpointer analysis;
+  /* The timestamp of the current incoming buffer. */
+  GstClockTime buffer_timestamp;
+  /* Number of samples processed in current buffer, during emit_signal,
+     this will always be on an RMS window boundary. */
+  guint buffer_n_samples_done;
+};
+
+/* Filter coefficients for the IIR filters that form the equal
+ * loudness filter.  XFilter[ctx->sample_rate_index] gives the array
+ * of the X coefficients (A or B) for the configured sample rate. */
+
+#ifdef _MSC_VER
+/* Disable double-to-float warning: */
+/* A better solution would be to append 'f' to each constant, but that
+ * makes the code ugly. */
+#pragma warning ( disable : 4305 )
+#endif
+
+static const gfloat AYule[9][11] = {
+  {1., -3.84664617118067, 7.81501653005538, -11.34170355132042,
+        13.05504219327545, -12.28759895145294, 9.48293806319790,
+        -5.87257861775999, 2.75465861874613, -0.86984376593551,
+      0.13919314567432},
+  {1., -3.47845948550071, 6.36317777566148, -8.54751527471874, 9.47693607801280,
+        -8.81498681370155, 6.85401540936998, -4.39470996079559,
+      2.19611684890774, -0.75104302451432, 0.13149317958808},
+  {1., -2.37898834973084, 2.84868151156327, -2.64577170229825, 2.23697657451713,
+        -1.67148153367602, 1.00595954808547, -0.45953458054983,
+      0.16378164858596, -0.05032077717131, 0.02347897407020},
+  {1., -1.61273165137247, 1.07977492259970, -0.25656257754070,
+        -0.16276719120440, -0.22638893773906, 0.39120800788284,
+        -0.22138138954925, 0.04500235387352, 0.02005851806501,
+      0.00302439095741},
+  {1., -1.49858979367799, 0.87350271418188, 0.12205022308084, -0.80774944671438,
+        0.47854794562326, -0.12453458140019, -0.04067510197014,
+      0.08333755284107, -0.04237348025746, 0.02977207319925},
+  {1., -0.62820619233671, 0.29661783706366, -0.37256372942400, 0.00213767857124,
+        -0.42029820170918, 0.22199650564824, 0.00613424350682, 0.06747620744683,
+      0.05784820375801, 0.03222754072173},
+  {1., -1.04800335126349, 0.29156311971249, -0.26806001042947, 0.00819999645858,
+        0.45054734505008, -0.33032403314006, 0.06739368333110,
+      -0.04784254229033, 0.01639907836189, 0.01807364323573},
+  {1., -0.51035327095184, -0.31863563325245, -0.20256413484477,
+        0.14728154134330, 0.38952639978999, -0.23313271880868,
+        -0.05246019024463, -0.02505961724053, 0.02442357316099,
+      0.01818801111503},
+  {1., -0.25049871956020, -0.43193942311114, -0.03424681017675,
+        -0.04678328784242, 0.26408300200955, 0.15113130533216,
+        -0.17556493366449, -0.18823009262115, 0.05477720428674,
+      0.04704409688120}
+};
+
+static const gfloat BYule[9][11] = {
+  {0.03857599435200, -0.02160367184185, -0.00123395316851, -0.00009291677959,
+        -0.01655260341619, 0.02161526843274, -0.02074045215285,
+      0.00594298065125, 0.00306428023191, 0.00012025322027, 0.00288463683916},
+  {0.05418656406430, -0.02911007808948, -0.00848709379851, -0.00851165645469,
+        -0.00834990904936, 0.02245293253339, -0.02596338512915,
+        0.01624864962975, -0.00240879051584, 0.00674613682247,
+      -0.00187763777362},
+  {0.15457299681924, -0.09331049056315, -0.06247880153653, 0.02163541888798,
+        -0.05588393329856, 0.04781476674921, 0.00222312597743, 0.03174092540049,
+      -0.01390589421898, 0.00651420667831, -0.00881362733839},
+  {0.30296907319327, -0.22613988682123, -0.08587323730772, 0.03282930172664,
+        -0.00915702933434, -0.02364141202522, -0.00584456039913,
+        0.06276101321749, -0.00000828086748, 0.00205861885564,
+      -0.02950134983287},
+  {0.33642304856132, -0.25572241425570, -0.11828570177555, 0.11921148675203,
+        -0.07834489609479, -0.00469977914380, -0.00589500224440,
+        0.05724228140351, 0.00832043980773, -0.01635381384540,
+      -0.01760176568150},
+  {0.44915256608450, -0.14351757464547, -0.22784394429749, -0.01419140100551,
+        0.04078262797139, -0.12398163381748, 0.04097565135648, 0.10478503600251,
+      -0.01863887810927, -0.03193428438915, 0.00541907748707},
+  {0.56619470757641, -0.75464456939302, 0.16242137742230, 0.16744243493672,
+        -0.18901604199609, 0.30931782841830, -0.27562961986224,
+        0.00647310677246, 0.08647503780351, -0.03788984554840,
+      -0.00588215443421},
+  {0.58100494960553, -0.53174909058578, -0.14289799034253, 0.17520704835522,
+        0.02377945217615, 0.15558449135573, -0.25344790059353, 0.01628462406333,
+      0.06920467763959, -0.03721611395801, -0.00749618797172},
+  {0.53648789255105, -0.42163034350696, -0.00275953611929, 0.04267842219415,
+        -0.10214864179676, 0.14590772289388, -0.02459864859345,
+        -0.11202315195388, -0.04060034127000, 0.04788665548180,
+      -0.02217936801134}
+};
+
+static const gfloat AButter[9][3] = {
+  {1., -1.97223372919527, 0.97261396931306},
+  {1., -1.96977855582618, 0.97022847566350},
+  {1., -1.95835380975398, 0.95920349965459},
+  {1., -1.95002759149878, 0.95124613669835},
+  {1., -1.94561023566527, 0.94705070426118},
+  {1., -1.92783286977036, 0.93034775234268},
+  {1., -1.91858953033784, 0.92177618768381},
+  {1., -1.91542108074780, 0.91885558323625},
+  {1., -1.88903307939452, 0.89487434461664}
+};
+
+static const gfloat BButter[9][3] = {
+  {0.98621192462708, -1.97242384925416, 0.98621192462708},
+  {0.98500175787242, -1.97000351574484, 0.98500175787242},
+  {0.97938932735214, -1.95877865470428, 0.97938932735214},
+  {0.97531843204928, -1.95063686409857, 0.97531843204928},
+  {0.97316523498161, -1.94633046996323, 0.97316523498161},
+  {0.96454515552826, -1.92909031105652, 0.96454515552826},
+  {0.96009142950541, -1.92018285901082, 0.96009142950541},
+  {0.95856916599601, -1.91713833199203, 0.95856916599601},
+  {0.94597685600279, -1.89195371200558, 0.94597685600279}
+};
+
+#ifdef _MSC_VER
+#pragma warning ( default : 4305 )
+#endif
+
+/* Filter functions.  These access elements with negative indices of
+ * the input and output arrays (up to the filter's order). */
+
+/* For much better performance, the function below has been
+ * implemented by unrolling the inner loop for our two use cases. */
+
+/*
+ * static inline void
+ * apply_filter (const gfloat * input, gfloat * output, guint n_samples,
+ *     const gfloat * a, const gfloat * b, guint order)
+ * {
+ *   gfloat y;
+ *   gint i, k;
+ * 
+ *   for (i = 0; i < n_samples; i++) {
+ *     y = input[i] * b[0];
+ *     for (k = 1; k <= order; k++)
+ *       y += input[i - k] * b[k] - output[i - k] * a[k];
+ *     output[i] = y;
+ *   }
+ * }
+ */
+
+static inline void
+yule_filter (const gfloat * input, gfloat * output,
+    const gfloat * a, const gfloat * b)
+{
+  /* 1e-10 is added below to avoid running into denormals when operating on
+   * near silence. */
+
+  output[0] = 1e-10 + input[0] * b[0]
+      + input[-1] * b[1] - output[-1] * a[1]
+      + input[-2] * b[2] - output[-2] * a[2]
+      + input[-3] * b[3] - output[-3] * a[3]
+      + input[-4] * b[4] - output[-4] * a[4]
+      + input[-5] * b[5] - output[-5] * a[5]
+      + input[-6] * b[6] - output[-6] * a[6]
+      + input[-7] * b[7] - output[-7] * a[7]
+      + input[-8] * b[8] - output[-8] * a[8]
+      + input[-9] * b[9] - output[-9] * a[9]
+      + input[-10] * b[10] - output[-10] * a[10];
+}
+
+static inline void
+butter_filter (const gfloat * input, gfloat * output,
+    const gfloat * a, const gfloat * b)
+{
+  output[0] = input[0] * b[0]
+      + input[-1] * b[1] - output[-1] * a[1]
+      + input[-2] * b[2] - output[-2] * a[2];
+}
+
+/* Because butter_filter and yule_filter are inlined, this function is
+ * a bit blown-up (code-size wise), but not inlining gives a ca. 40%
+ * performance penalty. */
+
+static inline void
+apply_filters (const RgAnalysisCtx * ctx, const gfloat * input_l,
+    const gfloat * input_r, guint n_samples)
+{
+  const gfloat *ayule = AYule[ctx->sample_rate_index];
+  const gfloat *byule = BYule[ctx->sample_rate_index];
+  const gfloat *abutter = AButter[ctx->sample_rate_index];
+  const gfloat *bbutter = BButter[ctx->sample_rate_index];
+  gint pos = ctx->window_n_samples_done;
+  gint i;
+
+  for (i = 0; i < n_samples; i++, pos++) {
+    yule_filter (input_l + i, ctx->step_l + pos, ayule, byule);
+    butter_filter (ctx->step_l + pos, ctx->out_l + pos, abutter, bbutter);
+
+    yule_filter (input_r + i, ctx->step_r + pos, ayule, byule);
+    butter_filter (ctx->step_r + pos, ctx->out_r + pos, abutter, bbutter);
+  }
+}
+
+/* Clear filter buffer state and current RMS window. */
+
+static void
+reset_filters (RgAnalysisCtx * ctx)
+{
+  gint i;
+
+  for (i = 0; i < MAX_ORDER; i++) {
+
+    ctx->inprebuf_l[i] = 0.;
+    ctx->stepbuf_l[i] = 0.;
+    ctx->outbuf_l[i] = 0.;
+
+    ctx->inprebuf_r[i] = 0.;
+    ctx->stepbuf_r[i] = 0.;
+    ctx->outbuf_r[i] = 0.;
+  }
+
+  ctx->window_square_sum = 0.;
+  ctx->window_n_samples_done = 0;
+}
+
+/* Accumulator functions. */
+
+/* Add two accumulators in-place.  The sum is defined as the result of
+ * the vector sum of the histogram array and the maximum value of the
+ * peak field.  Thus "adding" the accumulators for all tracks yields
+ * the correct result for obtaining the album gain and peak. */
+
+static void
+accumulator_add (RgAnalysisAcc * acc, const RgAnalysisAcc * acc_other)
+{
+  gint i;
+
+  for (i = 0; i < G_N_ELEMENTS (acc->histogram); i++)
+    acc->histogram[i] += acc_other->histogram[i];
+
+  acc->peak = MAX (acc->peak, acc_other->peak);
+}
+
+/* Reset an accumulator to zero. */
+
+static void
+accumulator_clear (RgAnalysisAcc * acc)
+{
+  memset (acc->histogram, 0, sizeof (acc->histogram));
+  acc->peak = 0.;
+}
+
+/* Obtain final analysis result from an accumulator.  Returns TRUE on
+ * success, FALSE on error (if accumulator is still zero). */
+
+static gboolean
+accumulator_result (const RgAnalysisAcc * acc, gdouble * result_gain,
+    gdouble * result_peak)
+{
+  guint32 sum = 0;
+  guint32 upper;
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (acc->histogram); i++)
+    sum += acc->histogram[i];
+
+  if (sum == 0)
+    /* All entries are 0: We got less than 50ms of data. */
+    return FALSE;
+
+  upper = (guint32) ceil (sum * (1. - (gdouble) (RMS_PERCENTILE / 100.)));
+
+  for (i = G_N_ELEMENTS (acc->histogram); i--;) {
+    if (upper <= acc->histogram[i])
+      break;
+    upper -= acc->histogram[i];
+  }
+
+  if (result_peak != NULL)
+    *result_peak = acc->peak;
+  if (result_gain != NULL)
+    *result_gain = PINK_REF - (gdouble) i / STEPS_PER_DB;
+
+  return TRUE;
+}
+
+/* Functions that operate on contexts, for external usage. */
+
+/* Create a new context.  Before it can be used, a sample rate must be
+ * configured using rg_analysis_set_sample_rate. */
+
+RgAnalysisCtx *
+rg_analysis_new (void)
+{
+  RgAnalysisCtx *ctx;
+
+  ctx = g_new (RgAnalysisCtx, 1);
+
+  ctx->inpre_l = ctx->inprebuf_l + MAX_ORDER;
+  ctx->step_l = ctx->stepbuf_l + MAX_ORDER;
+  ctx->out_l = ctx->outbuf_l + MAX_ORDER;
+
+  ctx->inpre_r = ctx->inprebuf_r + MAX_ORDER;
+  ctx->step_r = ctx->stepbuf_r + MAX_ORDER;
+  ctx->out_r = ctx->outbuf_r + MAX_ORDER;
+
+  ctx->sample_rate = 0;
+
+  accumulator_clear (&ctx->track);
+  accumulator_clear (&ctx->album);
+
+  return ctx;
+}
+
+static void
+reset_silence_detection (RgAnalysisCtx * ctx)
+{
+  ctx->buffer_timestamp = GST_CLOCK_TIME_NONE;
+  ctx->buffer_n_samples_done = 0;
+}
+
+/* Adapt to given sample rate.  Does nothing if already the current
+ * rate (returns TRUE then).  Returns FALSE only if given sample rate
+ * is not supported.  If the configured rate changes, the last
+ * unprocessed incomplete 50ms chunk of data is dropped because the
+ * filters are reset. */
+
+gboolean
+rg_analysis_set_sample_rate (RgAnalysisCtx * ctx, gint sample_rate)
+{
+  g_return_val_if_fail (ctx != NULL, FALSE);
+
+  if (ctx->sample_rate == sample_rate)
+    return TRUE;
+
+  switch (sample_rate) {
+    case 48000:
+      ctx->sample_rate_index = 0;
+      break;
+    case 44100:
+      ctx->sample_rate_index = 1;
+      break;
+    case 32000:
+      ctx->sample_rate_index = 2;
+      break;
+    case 24000:
+      ctx->sample_rate_index = 3;
+      break;
+    case 22050:
+      ctx->sample_rate_index = 4;
+      break;
+    case 16000:
+      ctx->sample_rate_index = 5;
+      break;
+    case 12000:
+      ctx->sample_rate_index = 6;
+      break;
+    case 11025:
+      ctx->sample_rate_index = 7;
+      break;
+    case 8000:
+      ctx->sample_rate_index = 8;
+      break;
+    default:
+      return FALSE;
+  }
+
+  ctx->sample_rate = sample_rate;
+  /* The + 999 has the effect of ceil()ing: */
+  ctx->window_n_samples = (guint) ((sample_rate * RMS_WINDOW_MSECS + 999)
+      / 1000);
+
+  reset_filters (ctx);
+  reset_silence_detection (ctx);
+
+  return TRUE;
+}
+
+void
+rg_analysis_init_silence_detection (RgAnalysisCtx * ctx,
+    void (*post_message) (gpointer analysis, GstClockTime timestamp,
+        GstClockTime duration, gdouble rglevel), gpointer analysis)
+{
+  ctx->post_message = post_message;
+  ctx->analysis = analysis;
+  reset_silence_detection (ctx);
+}
+
+void
+rg_analysis_start_buffer (RgAnalysisCtx * ctx, GstClockTime buffer_timestamp)
+{
+  ctx->buffer_timestamp = buffer_timestamp;
+  ctx->buffer_n_samples_done = 0;
+}
+
+void
+rg_analysis_destroy (RgAnalysisCtx * ctx)
+{
+  g_free (ctx);
+}
+
+/* Entry points for analyzing sample data in common raw data formats.
+ * The stereo format functions expect interleaved frames.  It is
+ * possible to pass data in different formats for the same context,
+ * there are no restrictions.  All functions have the same signature;
+ * the depth argument for the float functions is not variable and must
+ * be given the value 32. */
+
+void
+rg_analysis_analyze_mono_float (RgAnalysisCtx * ctx, gconstpointer data,
+    gsize size, guint depth)
+{
+  gfloat conv_samples[512];
+  const gfloat *samples = (gfloat *) data;
+  guint n_samples = size / sizeof (gfloat);
+  gint i;
+
+  g_return_if_fail (depth == 32);
+  g_return_if_fail (size % sizeof (gfloat) == 0);
+
+  while (n_samples) {
+    gint n = MIN (n_samples, G_N_ELEMENTS (conv_samples));
+
+    n_samples -= n;
+    memcpy (conv_samples, samples, n * sizeof (gfloat));
+    for (i = 0; i < n; i++) {
+      ctx->track.peak = MAX (ctx->track.peak, fabs (conv_samples[i]));
+      conv_samples[i] *= 32768.;
+    }
+    samples += n;
+    rg_analysis_analyze (ctx, conv_samples, NULL, n);
+  }
+}
+
+void
+rg_analysis_analyze_stereo_float (RgAnalysisCtx * ctx, gconstpointer data,
+    gsize size, guint depth)
+{
+  gfloat conv_samples_l[256];
+  gfloat conv_samples_r[256];
+  const gfloat *samples = (gfloat *) data;
+  guint n_frames = size / (sizeof (gfloat) * 2);
+  gint i;
+
+  g_return_if_fail (depth == 32);
+  g_return_if_fail (size % (sizeof (gfloat) * 2) == 0);
+
+  while (n_frames) {
+    gint n = MIN (n_frames, G_N_ELEMENTS (conv_samples_l));
+
+    n_frames -= n;
+    for (i = 0; i < n; i++) {
+      gfloat old_sample;
+
+      old_sample = samples[2 * i];
+      ctx->track.peak = MAX (ctx->track.peak, fabs (old_sample));
+      conv_samples_l[i] = old_sample * 32768.;
+
+      old_sample = samples[2 * i + 1];
+      ctx->track.peak = MAX (ctx->track.peak, fabs (old_sample));
+      conv_samples_r[i] = old_sample * 32768.;
+    }
+    samples += 2 * n;
+    rg_analysis_analyze (ctx, conv_samples_l, conv_samples_r, n);
+  }
+}
+
+void
+rg_analysis_analyze_mono_int16 (RgAnalysisCtx * ctx, gconstpointer data,
+    gsize size, guint depth)
+{
+  gfloat conv_samples[512];
+  gint32 peak_sample = 0;
+  const gint16 *samples = (gint16 *) data;
+  guint n_samples = size / sizeof (gint16);
+  gint shift = 1 << (sizeof (gint16) * 8 - depth);
+  gint i;
+
+  g_return_if_fail (depth <= (sizeof (gint16) * 8));
+  g_return_if_fail (size % sizeof (gint16) == 0);
+
+  while (n_samples) {
+    gint n = MIN (n_samples, G_N_ELEMENTS (conv_samples));
+
+    n_samples -= n;
+    for (i = 0; i < n; i++) {
+      gint16 old_sample = samples[i] * shift;
+
+      peak_sample = MAX (peak_sample, ABS ((gint32) old_sample));
+      conv_samples[i] = (gfloat) old_sample;
+    }
+    samples += n;
+    rg_analysis_analyze (ctx, conv_samples, NULL, n);
+  }
+  ctx->track.peak = MAX (ctx->track.peak,
+      (gdouble) peak_sample / ((gdouble) (1u << 15)));
+}
+
+void
+rg_analysis_analyze_stereo_int16 (RgAnalysisCtx * ctx, gconstpointer data,
+    gsize size, guint depth)
+{
+  gfloat conv_samples_l[256];
+  gfloat conv_samples_r[256];
+  gint32 peak_sample = 0;
+  const gint16 *samples = (gint16 *) data;
+  guint n_frames = size / (sizeof (gint16) * 2);
+  gint shift = 1 << (sizeof (gint16) * 8 - depth);
+  gint i;
+
+  g_return_if_fail (depth <= (sizeof (gint16) * 8));
+  g_return_if_fail (size % (sizeof (gint16) * 2) == 0);
+
+  while (n_frames) {
+    gint n = MIN (n_frames, G_N_ELEMENTS (conv_samples_l));
+
+    n_frames -= n;
+    for (i = 0; i < n; i++) {
+      gint16 old_sample;
+
+      old_sample = samples[2 * i] * shift;
+      peak_sample = MAX (peak_sample, ABS ((gint32) old_sample));
+      conv_samples_l[i] = (gfloat) old_sample;
+
+      old_sample = samples[2 * i + 1] * shift;
+      peak_sample = MAX (peak_sample, ABS ((gint32) old_sample));
+      conv_samples_r[i] = (gfloat) old_sample;
+    }
+    samples += 2 * n;
+    rg_analysis_analyze (ctx, conv_samples_l, conv_samples_r, n);
+  }
+  ctx->track.peak = MAX (ctx->track.peak,
+      (gdouble) peak_sample / ((gdouble) (1u << 15)));
+}
+
+/* Analyze the given chunk of samples.  The sample data is given in
+ * floating point format but should be scaled such that the values
+ * +/-32768.0 correspond to the -0dBFS reference amplitude.
+ *
+ * samples_l: Buffer with sample data for the left channel or of the
+ * mono channel.
+ *
+ * samples_r: Buffer with sample data for the right channel or NULL
+ * for mono.
+ *
+ * n_samples: Number of samples passed in each buffer.
+ */
+
+void
+rg_analysis_analyze (RgAnalysisCtx * ctx, const gfloat * samples_l,
+    const gfloat * samples_r, guint n_samples)
+{
+  const gfloat *input_l, *input_r;
+  guint n_samples_done;
+  gint i;
+
+  g_return_if_fail (ctx != NULL);
+  g_return_if_fail (samples_l != NULL);
+  g_return_if_fail (ctx->sample_rate != 0);
+
+  if (n_samples == 0)
+    return;
+
+  if (samples_r == NULL)
+    /* Mono. */
+    samples_r = samples_l;
+
+  memcpy (ctx->inpre_l, samples_l,
+      MIN (n_samples, MAX_ORDER) * sizeof (gfloat));
+  memcpy (ctx->inpre_r, samples_r,
+      MIN (n_samples, MAX_ORDER) * sizeof (gfloat));
+
+  n_samples_done = 0;
+  while (n_samples_done < n_samples) {
+    /* Limit number of samples to be processed in this iteration to
+     * the number needed to complete the next window: */
+    guint n_samples_current = MIN (n_samples - n_samples_done,
+        ctx->window_n_samples - ctx->window_n_samples_done);
+
+    if (n_samples_done < MAX_ORDER) {
+      input_l = ctx->inpre_l + n_samples_done;
+      input_r = ctx->inpre_r + n_samples_done;
+      n_samples_current = MIN (n_samples_current, MAX_ORDER - n_samples_done);
+    } else {
+      input_l = samples_l + n_samples_done;
+      input_r = samples_r + n_samples_done;
+    }
+
+    apply_filters (ctx, input_l, input_r, n_samples_current);
+
+    /* Update the square sum. */
+    for (i = 0; i < n_samples_current; i++)
+      ctx->window_square_sum += ctx->out_l[ctx->window_n_samples_done + i]
+          * ctx->out_l[ctx->window_n_samples_done + i]
+          + ctx->out_r[ctx->window_n_samples_done + i]
+          * ctx->out_r[ctx->window_n_samples_done + i];
+
+    ctx->window_n_samples_done += n_samples_current;
+    ctx->buffer_n_samples_done += n_samples_current;
+
+    g_return_if_fail (ctx->window_n_samples_done <= ctx->window_n_samples);
+
+    if (ctx->window_n_samples_done == ctx->window_n_samples) {
+      /* Get the Root Mean Square (RMS) for this set of samples. */
+      gdouble val = STEPS_PER_DB * 10. * log10 (ctx->window_square_sum /
+          ctx->window_n_samples * 0.5 + 1.e-37);
+      gint ival = CLAMP ((gint) val, 0,
+          (gint) G_N_ELEMENTS (ctx->track.histogram) - 1);
+      /* Compute the per-window gain */
+      const gdouble gain = PINK_REF - (gdouble) ival / STEPS_PER_DB;
+      const GstClockTime timestamp = ctx->buffer_timestamp
+          + gst_util_uint64_scale_int_ceil (GST_SECOND,
+          ctx->buffer_n_samples_done,
+          ctx->sample_rate)
+          - RMS_WINDOW_MSECS * GST_MSECOND;
+
+      ctx->post_message (ctx->analysis, timestamp,
+          RMS_WINDOW_MSECS * GST_MSECOND, -gain);
+
+
+      ctx->track.histogram[ival]++;
+      ctx->window_square_sum = 0.;
+      ctx->window_n_samples_done = 0;
+
+      /* No need for memmove here, the areas never overlap: Even for
+       * the smallest sample rate, the number of samples needed for
+       * the window is greater than MAX_ORDER. */
+
+      memcpy (ctx->stepbuf_l, ctx->stepbuf_l + ctx->window_n_samples,
+          MAX_ORDER * sizeof (gfloat));
+      memcpy (ctx->outbuf_l, ctx->outbuf_l + ctx->window_n_samples,
+          MAX_ORDER * sizeof (gfloat));
+
+      memcpy (ctx->stepbuf_r, ctx->stepbuf_r + ctx->window_n_samples,
+          MAX_ORDER * sizeof (gfloat));
+      memcpy (ctx->outbuf_r, ctx->outbuf_r + ctx->window_n_samples,
+          MAX_ORDER * sizeof (gfloat));
+    }
+
+    n_samples_done += n_samples_current;
+  }
+
+  if (n_samples >= MAX_ORDER) {
+
+    memcpy (ctx->inprebuf_l, samples_l + n_samples - MAX_ORDER,
+        MAX_ORDER * sizeof (gfloat));
+
+    memcpy (ctx->inprebuf_r, samples_r + n_samples - MAX_ORDER,
+        MAX_ORDER * sizeof (gfloat));
+
+  } else {
+
+    memmove (ctx->inprebuf_l, ctx->inprebuf_l + n_samples,
+        (MAX_ORDER - n_samples) * sizeof (gfloat));
+    memcpy (ctx->inprebuf_l + MAX_ORDER - n_samples, samples_l,
+        n_samples * sizeof (gfloat));
+
+    memmove (ctx->inprebuf_r, ctx->inprebuf_r + n_samples,
+        (MAX_ORDER - n_samples) * sizeof (gfloat));
+    memcpy (ctx->inprebuf_r + MAX_ORDER - n_samples, samples_r,
+        n_samples * sizeof (gfloat));
+
+  }
+}
+
+/* Obtain track gain and peak.  Returns TRUE on success.  Can fail if
+ * not enough samples have been processed.  Updates album accumulator.
+ * Resets track accumulator. */
+
+gboolean
+rg_analysis_track_result (RgAnalysisCtx * ctx, gdouble * gain, gdouble * peak)
+{
+  gboolean result;
+
+  g_return_val_if_fail (ctx != NULL, FALSE);
+
+  accumulator_add (&ctx->album, &ctx->track);
+  result = accumulator_result (&ctx->track, gain, peak);
+  accumulator_clear (&ctx->track);
+
+  reset_filters (ctx);
+  reset_silence_detection (ctx);
+
+  return result;
+}
+
+/* Obtain album gain and peak.  Returns TRUE on success.  Can fail if
+ * not enough samples have been processed.  Resets album
+ * accumulator. */
+
+gboolean
+rg_analysis_album_result (RgAnalysisCtx * ctx, gdouble * gain, gdouble * peak)
+{
+  gboolean result;
+
+  g_return_val_if_fail (ctx != NULL, FALSE);
+
+  result = accumulator_result (&ctx->album, gain, peak);
+  accumulator_clear (&ctx->album);
+
+  return result;
+}
+
+void
+rg_analysis_reset_album (RgAnalysisCtx * ctx)
+{
+  accumulator_clear (&ctx->album);
+}
+
+/* Reset internal buffers as well as track and album accumulators.
+ * Configured sample rate is kept intact. */
+
+void
+rg_analysis_reset (RgAnalysisCtx * ctx)
+{
+  g_return_if_fail (ctx != NULL);
+
+  reset_filters (ctx);
+  accumulator_clear (&ctx->track);
+  accumulator_clear (&ctx->album);
+  reset_silence_detection (ctx);
+}
diff --git a/gst/replaygain/rganalysis.h b/gst/replaygain/rganalysis.h
new file mode 100644
index 0000000..f57ad0a
--- /dev/null
+++ b/gst/replaygain/rganalysis.h
@@ -0,0 +1,63 @@
+/* GStreamer ReplayGain analysis
+ *
+ * Copyright (C) 2006 Rene Stadler <mail@renestadler.de>
+ * Copyright (C) 2001 David Robinson <David@Robinson.org>
+ *                    Glen Sawyer <glensawyer@hotmail.com>
+ *
+ * rganalysis.h: Analyze raw audio data in accordance with ReplayGain
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __RG_ANALYSIS_H__
+#define __RG_ANALYSIS_H__
+
+#include <glib.h>
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef struct _RgAnalysisCtx RgAnalysisCtx;
+
+RgAnalysisCtx *rg_analysis_new (void);
+gboolean rg_analysis_set_sample_rate (RgAnalysisCtx * ctx, gint sample_rate);
+void rg_analysis_analyze_mono_float (RgAnalysisCtx * ctx, gconstpointer data,
+    gsize size, guint depth);
+void rg_analysis_analyze_stereo_float (RgAnalysisCtx * ctx, gconstpointer data,
+    gsize size, guint depth);
+void rg_analysis_analyze_mono_int16 (RgAnalysisCtx * ctx, gconstpointer data,
+    gsize size, guint depth);
+void rg_analysis_analyze_stereo_int16 (RgAnalysisCtx * ctx, gconstpointer data,
+    gsize size, guint depth);
+void rg_analysis_analyze (RgAnalysisCtx * ctx, const gfloat * samples_l,
+    const gfloat * samples_r, guint n_samples);
+gboolean rg_analysis_track_result (RgAnalysisCtx * ctx, gdouble * gain,
+    gdouble * peak);
+gboolean rg_analysis_album_result (RgAnalysisCtx * ctx, gdouble * gain,
+    gdouble * peak);
+void rg_analysis_init_silence_detection (
+    RgAnalysisCtx * ctx,
+    void (*post_message) (gpointer analysis, GstClockTime timestamp, GstClockTime duration, gdouble rglevel),
+    gpointer analysis);
+void rg_analysis_start_buffer (RgAnalysisCtx * ctx,
+                               GstClockTime buffer_timestamp);
+void rg_analysis_reset_album (RgAnalysisCtx * ctx);
+void rg_analysis_reset (RgAnalysisCtx * ctx);
+void rg_analysis_destroy (RgAnalysisCtx * ctx);
+
+G_END_DECLS
+
+#endif /* __RG_ANALYSIS_H__ */
diff --git a/gst/rtp/Makefile.am b/gst/rtp/Makefile.am
new file mode 100644
index 0000000..7b2afd5
--- /dev/null
+++ b/gst/rtp/Makefile.am
@@ -0,0 +1,209 @@
+plugin_LTLIBRARIES = libgstrtp.la
+
+libgstrtp_la_SOURCES = \
+	dboolhuff.c \
+	fnv1hash.c \
+	gstrtp.c \
+	gstrtpchannels.c \
+	gstrtpac3depay.c \
+	gstrtpac3pay.c \
+	gstrtpbvdepay.c \
+	gstrtpbvpay.c \
+	gstrtpceltdepay.c \
+	gstrtpceltpay.c \
+	gstrtpdvdepay.c \
+	gstrtpdvpay.c \
+	gstrtpgstdepay.c \
+	gstrtpgstpay.c \
+	gstrtpilbcdepay.c \
+	gstrtpilbcpay.c \
+	gstrtpmpadepay.c \
+	gstrtpmpapay.c \
+	gstrtpmparobustdepay.c \
+	gstrtpmpvdepay.c \
+	gstrtpmpvpay.c \
+	gstrtppcmadepay.c \
+	gstrtppcmudepay.c \
+	gstrtppcmupay.c \
+	gstrtppcmapay.c \
+	gstrtpg722depay.c \
+	gstrtpg722pay.c \
+	gstrtpg723depay.c \
+	gstrtpg723pay.c \
+	gstrtpg726pay.c \
+	gstrtpg726depay.c \
+	gstrtpg729pay.c \
+	gstrtpg729depay.c \
+	gstrtpgsmdepay.c \
+	gstrtpgsmpay.c \
+	gstrtpamrdepay.c \
+	gstrtpamrpay.c \
+	gstrtph261pay.c \
+	gstrtph261depay.c \
+	gstrtph263pdepay.c \
+	gstrtph263ppay.c \
+	gstrtph263depay.c \
+	gstrtph263pay.c \
+	gstrtph264depay.c \
+	gstrtph264pay.c \
+	gstrtph265depay.c \
+	gstrtph265pay.c \
+	gstrtpj2kdepay.c \
+	gstrtpj2kpay.c \
+	gstrtpjpegdepay.c \
+	gstrtpjpegpay.c \
+	gstrtpklvdepay.c \
+	gstrtpklvpay.c \
+	gstrtpL8depay.c \
+	gstrtpL8pay.c \
+	gstrtpL16depay.c \
+	gstrtpL16pay.c \
+	gstrtpL24depay.c \
+	gstrtpL24pay.c \
+	gstasteriskh263.c \
+	gstrtpmp1sdepay.c \
+	gstrtpmp2tdepay.c \
+	gstrtpmp2tpay.c \
+	gstrtpmp4vdepay.c \
+	gstrtpmp4vpay.c \
+	gstrtpmp4gdepay.c \
+	gstrtpmp4gpay.c \
+	gstrtpmp4adepay.c \
+	gstrtpmp4apay.c \
+	gstrtpopusdepay.c \
+	gstrtpopuspay.c \
+	gstrtpqcelpdepay.c \
+	gstrtpqdmdepay.c \
+	gstrtpsbcdepay.c \
+	gstrtpsbcpay.c \
+	gstrtpsirenpay.c \
+	gstrtpsirendepay.c \
+	gstrtpspeexdepay.c \
+	gstrtpspeexpay.c \
+	gstrtpsv3vdepay.c \
+	gstrtptheoradepay.c \
+	gstrtptheorapay.c \
+	gstrtpvorbisdepay.c \
+	gstrtpvorbispay.c  \
+	gstrtpvp8depay.c \
+	gstrtpvp8pay.c \
+	gstrtpvp9depay.c \
+	gstrtpvp9pay.c \
+	gstrtpvrawdepay.c  \
+	gstrtpvrawpay.c \
+	gstrtpstreampay.c \
+	gstrtpstreamdepay.c \
+	gstrtputils.c
+
+libgstrtp_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS) -Dvp8_norm=gst_rtpvp8_vp8_norm \
+	-Dvp8dx_start_decode=gst_rtpvp8_vp8dx_start_decode \
+	-Dvp8dx_bool_decoder_fill=gst_rtpvp8_vp8dx_bool_decoder_fill
+
+libgstrtp_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+	-lgstaudio-@GST_API_VERSION@ \
+	-lgstvideo-@GST_API_VERSION@ \
+	-lgsttag-@GST_API_VERSION@ \
+	-lgstrtp-@GST_API_VERSION@ \
+	-lgstpbutils-@GST_API_VERSION@ \
+	$(GST_BASE_LIBS) $(GST_LIBS) \
+	$(LIBM)
+libgstrtp_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) 
+
+noinst_HEADERS =			\
+	dboolhuff.h \
+	fnv1hash.h \
+	gstrtpchannels.h \
+	gstrtpL8depay.h \
+	gstrtpL8pay.h \
+	gstrtpL16depay.h \
+	gstrtpL16pay.h \
+	gstrtpL24depay.h \
+	gstrtpL24pay.h \
+	gstrtpac3depay.h \
+	gstrtpac3pay.h \
+	gstrtpbvdepay.h \
+	gstrtpbvpay.h \
+	gstrtpceltpay.h	\
+	gstrtpceltdepay.h \
+	gstrtpdvdepay.h \
+	gstrtpdvpay.h \
+	gstrtpamrdepay.h \
+	gstrtpamrpay.h 	\
+	gstrtpgstdepay.h \
+	gstrtpgstpay.h 	\
+	gstrtpilbcdepay.h \
+	gstrtpilbcpay.h \
+	gstrtppcmadepay.h \
+	gstrtppcmudepay.h \
+	gstrtppcmupay.h \
+	gstrtppcmapay.h \
+	gstrtpg722depay.h \
+	gstrtpg722pay.h \
+	gstrtpg723depay.h\
+	gstrtpg723pay.h \
+	gstrtpg726depay.h \
+	gstrtpg726pay.h \
+	gstrtpg729depay.h \
+	gstrtpg729pay.h \
+	gstrtpgsmdepay.h \
+	gstrtpgsmpay.h 	\
+	gstrtpmpadepay.h \
+	gstrtpmparobustdepay.h \
+	gstrtpmpapay.h \
+	gstrtpmpvdepay.h \
+	gstrtpmpvpay.h \
+	gstrtph261pay.h \
+	gstrtph261depay.h \
+	gstrtph263pdepay.h \
+	gstrtph263ppay.h \
+	gstrtph263depay.h \
+	gstrtph263pay.h \
+	gstrtph264depay.h \
+	gstrtph264pay.h \
+	gstrtph265depay.h \
+	gstrtph265pay.h \
+	gstrtph265types.h \
+	gstrtpj2kdepay.h \
+	gstrtpj2kpay.h \
+	gstrtpj2kcommon.h \
+	gstrtpjpegdepay.h \
+	gstrtpjpegpay.h \
+	gstrtpklvdepay.h \
+	gstrtpklvpay.h \
+	gstrtpmp1sdepay.h \
+	gstrtpmp2tdepay.h \
+	gstrtpmp2tpay.h \
+	gstrtpmp4vdepay.h \
+	gstrtpmp4vpay.h	\
+	gstrtpmp4gdepay.h \
+	gstrtpmp4gpay.h	\
+	gstrtpmp4adepay.h \
+	gstrtpmp4apay.h \
+	gstrtpopusdepay.h \
+	gstrtpopuspay.h \
+	gstasteriskh263.h \
+	gstrtpqcelpdepay.h \
+	gstrtpqdmdepay.h \
+	gstrtpsbcdepay.h \
+	gstrtpsbcpay.h \
+	gstrtpsirenpay.h \
+	gstrtpsirendepay.h \
+	gstrtpspeexdepay.h \
+	gstrtpspeexpay.h \
+	gstrtpsv3vdepay.h \
+	gstrtptheoradepay.h \
+	gstrtptheorapay.h \
+	gstrtpvorbisdepay.h \
+	gstrtpvorbispay.h \
+	gstrtpvp8depay.h \
+	gstrtpvp8pay.h \
+	gstrtpvp9depay.h \
+	gstrtpvp9pay.h \
+	gstrtpvrawdepay.h \
+	gstrtpvrawpay.h \
+	gstrtpstreampay.h \
+	gstrtpstreamdepay.h \
+	gstrtputils.h
+
+EXTRA_DIST = dboolhuff.LICENSE
diff --git a/gst/rtp/README b/gst/rtp/README
new file mode 100644
index 0000000..814311e
--- /dev/null
+++ b/gst/rtp/README
@@ -0,0 +1,398 @@
+This directory contains some RTP payloaders/depayloaders for different payload
+types. Use one payloader/depayloder pair per payload. If several payloads can be
+payloaded/depayloaded by the same element, make different copies of it, one for
+each payload.
+
+The application/x-rtp mime type
+-------------------------------
+
+For valid RTP packets encapsulated in GstBuffers, we use the caps with
+mime type application/x-rtp.
+
+The following fields can or must (*) be specified in the structure:
+
+ * media: (String) [ "audio", "video", "application", "data", "control" ]
+     Defined in RFC 2327 in the SDP media announcement field.
+     Converted to lower case.
+
+ * payload: (int) [0, 127]
+     For audio and video, these will normally be a media payload type as 
+     defined in the RTP Audio/Video Profile. For dynamicaly allocated 
+     payload types, this value will be >= 96 and the encoding-name must be
+     set.
+
+ * clock-rate: (int) [0 - MAXINT]
+    The RTP clock rate. 
+
+   encoding-name: (String) ANY
+     typically second part of the mime type. ex. MP4V-ES. only required if
+     payload type >= 96. Converted to upper case.
+
+   encoding-params: (String) ANY
+     extra encoding parameters (as in the SDP a=rtpmap: field). only required
+     if different from the default of the encoding-name.
+     Converted to lower-case.
+     
+   ssrc: (uint) [0 - MAXINT]
+    The ssrc value currently in use. (default = the SSRC of the first RTP
+    packet)
+
+   timestamp-offset: (uint) [0 - MAXINT]
+    The RTP time representing time npt-start. (default = rtptime of first RTP
+    packet).
+
+   seqnum-offset: (uint) [0 - MAXINT]
+    The RTP sequence number representing the first rtp packet. When this
+    parameter is given, all sequence numbers below this seqnum should be
+    ignored. (default = seqnum of first RTP packet).
+
+   npt-start: (uint64) [0 - MAXINT]
+    The Normal Play Time for clock-base. This is the position in the stream and
+    is between 0 and the duration of the stream. This value is expressed in
+    nanoseconds GstClockTime. (default = 0)
+
+   npt-stop: (uint64) [0 - MAXINT] 
+    The last position in the stream. This value is expressed in nanoseconds
+    GstClockTime. (default = -1, stop unknown)
+
+   play-speed: (gdouble) [-MIN - MAX]
+    The intended playback speed of the stream. The client is delivered data at
+    the adjusted speed. The client should adjust its playback speed with this
+    value and thus corresponds to the GStreamer rate field in the NEWSEGMENT
+    event. (default = 1.0)
+    
+   play-scale: (gdouble) [-MIN - MAX]
+    The rate already applied to the stream. The client is delivered a stream
+    that is scaled by this amount. This value is used to adjust position
+    reporting and corresponds to the GStream applied-rate field in the
+    NEWSEGMENT event. (default = 1.0)
+
+   maxptime: (uint) [0, MAX]
+    The maxptime as defined in RFC 4566, this defines the maximum size of a
+    packet. It overrides the max-ptime property of payloaders.
+
+   Optional parameters as key/value pairs, media type specific. The value type
+   should be of type G_TYPE_STRING. The key is converted to lower-case. The
+   value is left in its original case.
+   A parameter with no value is converted to <param>=1.
+
+ Example:
+
+  "application/x-rtp",
+      "media", G_TYPE_STRING, "audio",		-.
+      "payload", G_TYPE_INT, 96,                 | - required
+      "clock-rate", G_TYPE_INT, 8000,           -'
+      "encoding-name", G_TYPE_STRING, "AMR",    -. - required since payload >= 96
+      "encoding-params", G_TYPE_STRING, "1",	-' - optional param for AMR
+      "octet-align", G_TYPE_STRING, "1",	-.
+      "crc", G_TYPE_STRING, "0",                 |
+      "robust-sorting", G_TYPE_STRING, "0",      |  AMR specific params.
+      "interleaving", G_TYPE_STRING, "0",       -'
+  
+ Mapping of caps to and from SDP fields:
+
+   m=<media> <udp port> RTP/AVP <payload>       -] media and payload from caps
+   a=rtpmap:<payload> <encoding-name>/<clock-rate>[/<encoding-params>]
+              -> when <payload> >= 96
+   a=fmtp:<payload> <param>=<value>;...
+
+ For above caps:
+
+   m=audio <udp port> RTP/AVP 96
+   a=rtpmap:96 AMR/8000/1
+   a=fmtp:96 octet-align=1;crc=0;robust-sorting=0;interleaving=0
+
+ Attributes are converted as follows:
+
+  IANA registered attribute names are prepended with 'a-' before putting them in
+  the caps. Unregistered keys (starting with 'x-') are copied directly into the
+  caps.
+
+ in RTSP, the SSRC is also sent.
+
+ The optional parameters in the SDP fields are case insensitive. In the caps we
+ always use the lowercase names so that the SDP -> caps mapping remains
+ possible.
+
+ Mapping of caps to NEWSEGMENT:
+
+  rate:         <play-speed>
+  applied-rate: <play-scale>
+  format:       GST_FORMAT_TIME
+  start:        <clock-base> * GST_SECOND / <clock-rate>
+  stop:         if <ntp-stop> != -1
+                  <npt-stop> - <npt-start> + start
+		else 
+		  -1
+  time:         <npt-start>
+
+
+Timestamping
+------------
+
+RTP in GStreamer uses a combination of the RTP timestamps and GStreamer buffer
+timestamps to ensure proper synchronisation at the sender and the receiver end.
+
+In RTP applications, the synchronisation is most complex at the receiver side.
+
+At the sender side, the RTP timestamps are generated in the payloaders based on
+GStreamer timestamps. At the receiver, GStreamer timestamps are reconstructed
+from the RTP timestamps and the GStreamer timestamps in the jitterbuffer. This
+process is explained in more detail below.
+
+= synchronisation at the sender
+
+Individual streams at the sender are synchronised using GStreamer timestamps.
+The payloader at the sender will convert the GStreamer timestamp into an RTP
+timestamp using the following formula:
+
+   RTP = ((RT - RT-base) * clock-rate / GST_SECOND) + RTP-offset
+
+  RTP:        the RTP timestamp for the stream. This value is truncated to
+              32 bits.
+  RT:         the GStreamer running time corresponding to the timestamp of the
+              packet to payload
+  RT-base:    the GStreamer running time of the first packet encoded
+  clock-rate: the clock-rate of the stream
+  RTP-offset: a random RTP offset
+
+The RTP timestamp corresponding to RT-base is the clock-base (see caps above). 
+
+In addition to setting an RTP timestamp in the RTP packet, the payloader is also
+responsible for putting the GStreamer timestamp on the resulting output buffer.
+This timestamp is used for further synchronisation at the sender pipeline, such
+as for sending out the packet on the network.
+
+Notice that the absolute timing information is lost; if the sender is sending
+multiple streams, the RTP timestamps in the packets do not contain enough
+information to synchronize them in the receiver. The receiver can however use
+the RTP timestamps to reconstruct the timing of the stream as it was created by
+the sender according to the sender's clock.
+
+Because the payloaded packet contains both an RTP timestamp and a GStreamer
+timestamp, it is possible for an RTP session manager to derive the relation
+between the RTP and GST timestamps. This information is used by a session
+manager to create SR reports. The NTP time in the report will contain the
+running time converted to NTP time and the corresponding RTP timestamp.
+
+Note that at the sender side, the RTP and GStreamer timestamp both increment at
+the same rate, the sender rate. This rate depends on the global pipeline clock
+of the sender. 
+
+Some pipelines to illustrate the process:
+
+    gst-launch-1.0 v4l2src ! videoconvert ! avenc_h263p ! rtph263ppay ! udpsink
+
+  v4l2src puts a GStreamer timestamp on the video frames base on the current
+  running_time. The encoder encodes and passed the timestamp on. The payloader
+  generates an RTP timestamp using the above formula and puts it in the RTP
+  packet. It also copies the incomming GStreamer timestamp on the output RTP
+  packet. udpsink synchronizes on the gstreamer timestamp before pushing out the
+  packet. 
+
+
+= synchronisation at the receiver
+
+The receiver is responsible for timestamping the received RTP packet with the
+running_time of the clock at the time the packet was received. This GStreamer
+timestamp reflects the receiver rate and depends on the global pipeline clock of
+the receiver. The gstreamer timestamp of the received RTP packet contains a
+certain amount of jitter introduced by the network.
+
+The most simple option for the receiver is to depayload the RTP packet and play
+it back as soon as possible, this is with the timestamp when it was received
+from the network. For the above sender pipeline this would be done with the
+following pipeline:
+
+    gst-launch-1.0 udpsrc caps="application/x-rtp, media=(string)video,
+      clock-rate=(int)90000, encoding-name=(string)H263-1998" ! rtph263pdepay !
+      avdec_h263 ! autovideosink
+
+It is important that the depayloader copies the incomming GStreamer timestamp
+directly to the depayloaded output buffer. It should never attempt to perform
+any logic with the RTP timestamp, this task is for the jitterbuffer as we will
+see next.
+
+The above pipeline does not attempt to deal with reordered packets or network
+jitter, which could result in jerky playback in the case of high jitter or
+corrupted video in the case of packet loss or reordering. This functionality is
+performed by the gstrtpjitterbuffer in GStreamer.
+
+The task of the gstrtpjitterbuffer element is to:
+
+ - deal with reordered packets based on the seqnum
+ - calculate the drift between the sender and receiver clocks using the
+   GStreamer timestamps (receiver clock rate) and RTP timestamps (sender clock
+   rate).
+
+To deal with reordered packet, the jitterbuffer holds on to the received RTP
+packets in a queue for a configurable amount of time, called the latency.
+
+The jitterbuffer also eliminates network jitter and then tracks the drift
+between the local clock (as expressed in the GStreamer timestamps) and the
+remote clock (as expressed in the RTP timestamps). It will remove the jitter
+and will apply the drift correction to the GStreamer timestamp before pushing
+the buffer downstream. The result is that the depayloader receives a smoothed
+GStreamer timestamp on the RTP packet, which is copied to the depayloaded data.
+
+The following pipeline illustrates a receiver with a jitterbuffer.
+
+    gst-launch-1.0 udpsrc caps="application/x-rtp, media=(string)video,
+      clock-rate=(int)90000, encoding-name=(string)H263-1998" !
+      rtpjitterbuffer latency=100 ! rtph263pdepay !  avdec_h263 ! autovideosink
+
+The latency property on the jitterbuffer controls the amount of delay (in
+milliseconds) to apply to the outgoing packets. A higher latency will produce
+smoother playback in networks with high jitter but cause a higher latency.
+Choosing a good value for the latency is a tradeoff between the quality and
+latency. The better the network, the lower the latency can be set.
+
+
+usage with UDP
+--------------
+
+To correctly and completely use the RTP payloaders on the sender and the
+receiver you need to write an application. It is not possible to write a full
+blown RTP server with a single gst-launch-1.0 line.
+
+That said, it is possible to do something functional with a few gst-launch
+lines. The biggest problem when constructing a correct gst-launch-1.0 line lies on
+the receiver end. 
+
+The receiver needs to know about the type of the RTP data along with a set of
+RTP configuration parameters. This information is usually transmitted to the
+client using some sort of session description language (SDP) over some reliable
+channel (HTTP/RTSP/...).  
+
+All of the required parameters to connect and use the RTP session on the
+server can be found in the caps on the server end. The client receives this
+information in some way (caps are converted to and from SDP, as explained above,
+for example).
+
+Some gst-launch-1.0 lines:
+
+  gst-launch-1.0 -v videotestsrc ! videoconvert ! avenc_h263p ! rtph263ppay ! udpsink
+
+   Setting pipeline to PAUSED ...
+   /pipeline0/videotestsrc0.src: caps = video/x-raw, format=(string)I420,
+   width=(int)320, height=(int)240, framerate=(fraction)30/1
+   Pipeline is PREROLLING ...
+   ....
+   /pipeline0/udpsink0.sink: caps = application/x-rtp, media=(string)video,
+   payload=(int)96, clock-rate=(int)90000, encoding-name=(string)H263-1998,
+   ssrc=(guint)527842345, clock-base=(guint)1150776941, seqnum-base=(guint)30982
+   ....
+   Pipeline is PREROLLED ...
+   Setting pipeline to PLAYING ...
+   New clock: GstSystemClock
+
+ Write down the caps on the udpsink and set them as the caps of the UDP 
+ receiver:
+
+  gst-launch-1.0 -v udpsrc caps="application/x-rtp, media=(string)video,
+  payload=(int)96, clock-rate=(int)90000, encoding-name=(string)H263-1998,
+  ssrc=(guint)527842345, clock-base=(guint)1150776941, seqnum-base=(guint)30982"
+  ! rtph263pdepay ! avdec_h263 ! autovideosink
+
+ The receiver now displays an h263 image. Since there is no jitterbuffer in the
+ pipeline, frames will be displayed at the time when they are received. This can
+ result in jerky playback in the case of high network jitter or currupted video
+ when packets are dropped or reordered.
+
+ Stream a quicktime file with mpeg4 video and AAC audio on port 5000 and port
+ 5002.
+
+  gst-launch-1.0 -v filesrc location=~/data/sincity.mp4 ! qtdemux name=d ! queue ! rtpmp4vpay ! udpsink port=5000
+                         d. ! queue ! rtpmp4gpay ! udpsink port=5002
+    ....
+    /pipeline0/udpsink0.sink: caps = application/x-rtp, media=(string)video,
+    payload=(int)96, clock-rate=(int)90000, encoding-name=(string)MP4V-ES,
+    ssrc=(guint)1162703703, clock-base=(guint)816135835, seqnum-base=(guint)9294,
+    profile-level-id=(string)3, config=(string)000001b003000001b50900000100000001200086c5d4c307d314043c1463000001b25876694430303334
+    /pipeline0/udpsink1.sink: caps = application/x-rtp, media=(string)audio,
+    payload=(int)96, clock-rate=(int)44100, encoding-name=(string)MPEG4-GENERIC,
+    ssrc=(guint)3246149898, clock-base=(guint)4134514058, seqnum-base=(guint)57633,
+    encoding-params=(string)2, streamtype=(string)5, profile-level-id=(string)1,
+    mode=(string)aac-hbr, config=(string)1210, sizelength=(string)13,
+    indexlength=(string)3, indexdeltalength=(string)3
+    ....
+
+ Again copy the caps on both sinks to the receiver launch line
+
+    gst-launch-1.0
+     udpsrc port=5000 caps="application/x-rtp, media=(string)video, payload=(int)96,
+      clock-rate=(int)90000, encoding-name=(string)MP4V-ES, ssrc=(guint)1162703703,
+      clock-base=(guint)816135835, seqnum-base=(guint)9294, profile-level-id=(string)3,
+      config=(string)000001b003000001b50900000100000001200086c5d4c307d314043c1463000001b25876694430303334"
+      ! rtpmp4vdepay ! ffdec_mpeg4 ! autovideosink sync=false
+     udpsrc port=5002 caps="application/x-rtp, media=(string)audio, payload=(int)96,
+      clock-rate=(int)44100, encoding-name=(string)MPEG4-GENERIC, ssrc=(guint)3246149898,
+      clock-base=(guint)4134514058, seqnum-base=(guint)57633, encoding-params=(string)2,
+      streamtype=(string)5, profile-level-id=(string)1, mode=(string)aac-hbr,
+      config=(string)1210, sizelength=(string)13, indexlength=(string)3,
+      indexdeltalength=(string)3" 
+      ! rtpmp4gdepay ! faad ! alsasink sync=false
+
+ The caps on the udpsinks can be retrieved when the server pipeline prerolled to
+ PAUSED.
+
+ The above pipeline sets sync=false on the audio and video sink which means that
+ no synchronisation will be performed in the sinks, they play the data when it
+ arrives. If you want to enable synchronisation in the sinks it is highly
+ recommended to use a gstrtpjitterbuffer after the udpsrc elements. 
+ 
+ Even when sync is enabled, the two different streams will not play synchronised
+ against eachother because the receiver does not have enough information to
+ perform this task. For this you need to add the rtpbin element in both the
+ sender and receiver pipeline and use additional sources and sinks to transmit
+ RTCP packets used for inter-stream synchronisation.
+
+ The caps on the receiver side can be set on the UDP source elements when the
+ pipeline went to PAUSED. In that state no data is received from the UDP sources
+ as they are live sources and only produce data in PLAYING.
+
+
+Relevant RFCs
+-------------
+
+3550 RTP: A Transport Protocol for Real-Time Applications. ( 1889 Obsolete )
+
+2198 RTP Payload for Redundant Audio Data.
+3119 A More Loss-Tolerant RTP Payload Format for MP3 Audio.
+
+2793 RTP Payload for Text Conversation.
+
+2032 RTP Payload Format for H.261 Video Streams.
+2190 RTP Payload Format for H.263 Video Streams.
+2250 RTP Payload Format for MPEG1/MPEG2 Video.
+2343 RTP Payload Format for Bundled MPEG.
+2429 RTP Payload Format for the 1998 Version of ITU-T Rec. H.263 Video
+2431 RTP Payload Format for BT.656 Video Encoding.
+2435 RTP Payload Format for JPEG-compressed Video.
+3016 RTP Payload Format for MPEG-4 Audio/Visual Streams.
+3047 RTP Payload Format for ITU-T Recommendation G.722.1.
+3189 RTP Payload Format for DV (IEC 61834) Video.
+3190 RTP Payload Format for 12-bit DAT Audio and 20- and 24-bit Linear Sampled Audio.
+3389 Real-time Transport Protocol (RTP) Payload for Comfort Noise (CN)
+2733 An RTP Payload Format for Generic Forward Error Correction.
+2833 RTP Payload for DTMF Digits, Telephony Tones and Telephony
+     Signals.
+2862 RTP Payload Format for Real-Time Pointers.
+3351 RTP Profile for Audio and Video Conferences with Minimal Control. ( 1890 Obsolete )
+3555 MIME Type Registration of RTP Payload Formats.
+
+2508 Compressing IP/UDP/RTP Headers for Low-Speed Serial Links.
+1305 Network Time Protocol (Version 3) Specification, Implementation and Analysis.
+3339 Date and Time on the Internet: Timestamps.
+2246 The TLS Protocol Version 1.0
+3546 Transport Layer Security (TLS) Extensions. ( Updates 2246 )
+
+do we care?
+-----------
+
+2029 RTP Payload Format of Sun's CellB Video Encoding.
+
+useful
+------
+
+http://www.iana.org/assignments/rtp-parameters
diff --git a/gst/rtp/TODO b/gst/rtp/TODO
new file mode 100644
index 0000000..8065a9c
--- /dev/null
+++ b/gst/rtp/TODO
@@ -0,0 +1,15 @@
+* MPEG4 header
+  - ffmpeg mpeg4 decoder gives error message when sending only the config
+    string, parsing is OK, error just means no picture was found in the
+    stream.
+
+* compare H263 encoders and H263+
+
+* better RTP packetizing for h263
+
+* bitrate tuning in ffmpeg
+  - fixed the qmax values so we can quantize more.
+
+* make ffmpeg negotiate only with accepted framerates
+
+
diff --git a/gst/rtp/dboolhuff.LICENSE b/gst/rtp/dboolhuff.LICENSE
new file mode 100644
index 0000000..83e4e6f
--- /dev/null
+++ b/gst/rtp/dboolhuff.LICENSE
@@ -0,0 +1,29 @@
+Copyright (c) 2010, Google Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+  * Neither the name of Google nor the names of its contributors may
+    be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/gst/rtp/dboolhuff.c b/gst/rtp/dboolhuff.c
new file mode 100644
index 0000000..3d0fc8f
--- /dev/null
+++ b/gst/rtp/dboolhuff.c
@@ -0,0 +1,73 @@
+/*
+ *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the dboolhuff.LICENSE file in this directory.
+ *  See the libvpx original distribution for more information,
+ *  including patent information, and author information.
+ */
+
+
+#include "dboolhuff.h"
+
+#ifdef _MSC_VER
+__declspec (align (16))
+     const unsigned char vp8_norm[256] = {
+#else
+const unsigned char vp8_norm[256] __attribute__ ((aligned (16))) = {
+#endif
+0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+      3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+int
+vp8dx_start_decode (BOOL_DECODER * br,
+    const unsigned char *source, unsigned int source_sz)
+{
+  br->user_buffer_end = source + source_sz;
+  br->user_buffer = source;
+  br->value = 0;
+  br->count = -8;
+  br->range = 255;
+
+  if (source_sz && !source)
+    return 1;
+
+  /* Populate the buffer */
+  vp8dx_bool_decoder_fill (br);
+
+  return 0;
+}
+
+
+void
+vp8dx_bool_decoder_fill (BOOL_DECODER * br)
+{
+  const unsigned char *bufptr;
+  const unsigned char *bufend;
+  VP8_BD_VALUE value;
+  int count;
+  bufend = br->user_buffer_end;
+  bufptr = br->user_buffer;
+  value = br->value;
+  count = br->count;
+
+  VP8DX_BOOL_DECODER_FILL (count, value, bufptr, bufend);
+
+  br->user_buffer = bufptr;
+  br->value = value;
+  br->count = count;
+}
diff --git a/gst/rtp/dboolhuff.h b/gst/rtp/dboolhuff.h
new file mode 100644
index 0000000..e0a45a2
--- /dev/null
+++ b/gst/rtp/dboolhuff.h
@@ -0,0 +1,155 @@
+/*
+ *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the dboolhuff.LICENSE file in this directory.
+ *  See the libvpx original distribution for more information,
+ *  including patent information, and author information.
+ */
+
+
+#ifndef DBOOLHUFF_H
+#define DBOOLHUFF_H
+#include <stddef.h>
+#include <limits.h>
+#include <glib.h>
+
+typedef size_t VP8_BD_VALUE;
+
+# define VP8_BD_VALUE_SIZE ((int)sizeof(VP8_BD_VALUE)*CHAR_BIT)
+/*This is meant to be a large, positive constant that can still be efficiently
+   loaded as an immediate (on platforms like ARM, for example).
+  Even relatively modest values like 100 would work fine.*/
+# define VP8_LOTS_OF_BITS (0x40000000)
+
+typedef struct
+{
+    const unsigned char *user_buffer_end;
+    const unsigned char *user_buffer;
+    VP8_BD_VALUE         value;
+    int                  count;
+    unsigned int         range;
+} BOOL_DECODER;
+
+#ifdef _MSC_VER
+__declspec(align(16)) extern const unsigned char vp8_norm[256];
+#else
+extern const unsigned char vp8_norm[256] __attribute__((aligned(16)));
+#endif
+
+int vp8dx_start_decode(BOOL_DECODER *br,
+                       const unsigned char *source,
+                       unsigned int source_sz);
+
+void vp8dx_bool_decoder_fill(BOOL_DECODER *br);
+
+/*The refill loop is used in several places, so define it in a macro to make
+   sure they're all consistent.
+  An inline function would be cleaner, but has a significant penalty, because
+   multiple BOOL_DECODER fields must be modified, and the compiler is not smart
+   enough to eliminate the stores to those fields and the subsequent reloads
+   from them when inlining the function.*/
+#define VP8DX_BOOL_DECODER_FILL(_count,_value,_bufptr,_bufend) \
+    do \
+    { \
+        int shift = VP8_BD_VALUE_SIZE - 8 - ((_count) + 8); \
+        int loop_end, x; \
+        size_t bits_left = ((_bufend)-(_bufptr))*CHAR_BIT; \
+        \
+        x = shift + CHAR_BIT - bits_left; \
+        loop_end = 0; \
+        if(x >= 0) \
+        { \
+            (_count) += VP8_LOTS_OF_BITS; \
+            loop_end = x; \
+            if(!bits_left) break; \
+        } \
+        while(shift >= loop_end) \
+        { \
+            (_count) += CHAR_BIT; \
+            (_value) |= (VP8_BD_VALUE)*(_bufptr)++ << shift; \
+            shift -= CHAR_BIT; \
+        } \
+    } \
+    while(0) \
+
+
+static int vp8dx_decode_bool(BOOL_DECODER *br, int probability) {
+    unsigned int bit = 0;
+    VP8_BD_VALUE value;
+    unsigned int split;
+    VP8_BD_VALUE bigsplit;
+    int count;
+    unsigned int range;
+
+    split = 1 + (((br->range - 1) * probability) >> 8);
+
+    if(br->count < 0)
+        vp8dx_bool_decoder_fill(br);
+
+    value = br->value;
+    count = br->count;
+
+    bigsplit = (VP8_BD_VALUE)split << (VP8_BD_VALUE_SIZE - 8);
+
+    range = split;
+
+    if (value >= bigsplit)
+    {
+        range = br->range - split;
+        value = value - bigsplit;
+        bit = 1;
+    }
+
+    {
+        register unsigned int shift = vp8_norm[range];
+        range <<= shift;
+        value <<= shift;
+        count -= shift;
+    }
+    br->value = value;
+    br->count = count;
+    br->range = range;
+
+    return bit;
+}
+
+static G_GNUC_UNUSED int vp8_decode_value(BOOL_DECODER *br, int bits)
+{
+    int z = 0;
+    int bit;
+
+    for (bit = bits - 1; bit >= 0; bit--)
+    {
+        z |= (vp8dx_decode_bool(br, 0x80) << bit);
+    }
+
+    return z;
+}
+
+static G_GNUC_UNUSED int vp8dx_bool_error(BOOL_DECODER *br)
+{
+    /* Check if we have reached the end of the buffer.
+     *
+     * Variable 'count' stores the number of bits in the 'value' buffer, minus
+     * 8. The top byte is part of the algorithm, and the remainder is buffered
+     * to be shifted into it. So if count == 8, the top 16 bits of 'value' are
+     * occupied, 8 for the algorithm and 8 in the buffer.
+     *
+     * When reading a byte from the user's buffer, count is filled with 8 and
+     * one byte is filled into the value buffer. When we reach the end of the
+     * data, count is additionally filled with VP8_LOTS_OF_BITS. So when
+     * count == VP8_LOTS_OF_BITS - 1, the user's data has been exhausted.
+     */
+    if ((br->count > VP8_BD_VALUE_SIZE) && (br->count < VP8_LOTS_OF_BITS))
+    {
+       /* We have tried to decode bits after the end of
+        * stream was encountered.
+        */
+        return 1;
+    }
+
+    /* No error. */
+    return 0;
+}
+#endif
diff --git a/gst/rtp/fnv1hash.c b/gst/rtp/fnv1hash.c
new file mode 100644
index 0000000..9885bb2
--- /dev/null
+++ b/gst/rtp/fnv1hash.c
@@ -0,0 +1,63 @@
+/* GStreamer
+ * Copyright (C) 2007 Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <glib.h>
+
+#include "fnv1hash.h"
+
+/* This file implements FNV-1 hashing used in the Ogg payload encoders
+ * to generate the 24-bit ident value based on the header pages.
+ * See http://isthe.com/chongo/tech/comp/fnv/
+ */
+
+#define MASK_24 (((guint32) 1 << 24) -1)
+
+#define FNV1_HASH_32_INIT ((guint32) 0x811C9DC5L)
+//2166136261L)
+#define FNV1_HASH_32_PRIME 16777619
+
+guint32
+fnv1_hash_32_new (void)
+{
+  return FNV1_HASH_32_INIT;
+}
+
+guint32
+fnv1_hash_32_update (guint32 hash, const guchar * data, guint length)
+{
+  guint i;
+  const guchar *p = data;
+
+  for (i = 0; i < length; ++i, ++p) {
+    hash *= FNV1_HASH_32_PRIME;
+    hash ^= *p;
+  }
+
+  return hash;
+}
+
+guint32
+fnv1_hash_32_to_24 (guint32 hash)
+{
+  return (hash >> 24) ^ (hash & MASK_24);
+}
diff --git a/gst/rtp/fnv1hash.h b/gst/rtp/fnv1hash.h
new file mode 100644
index 0000000..7047067
--- /dev/null
+++ b/gst/rtp/fnv1hash.h
@@ -0,0 +1,36 @@
+/* GStreamer
+ * Copyright (C) 2007 Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_FNV1_HASH_H__
+#define __GST_FNV1_HASH_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+guint32 fnv1_hash_32_new (void);
+guint32 fnv1_hash_32_update (guint32 hash, const guchar *data, guint length);
+guint32 fnv1_hash_32_to_24 (guint32 hash);
+
+G_END_DECLS
+
+#endif /* __GST_FNV1_HASH_H__ */
+
diff --git a/gst/rtp/gstasteriskh263.c b/gst/rtp/gstasteriskh263.c
new file mode 100644
index 0000000..8aa7fd4
--- /dev/null
+++ b/gst/rtp/gstasteriskh263.c
@@ -0,0 +1,230 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstasteriskh263.h"
+
+#define GST_ASTERISKH263_HEADER_LEN 6
+
+typedef struct _GstAsteriskH263Header
+{
+  guint32 timestamp;            /* Timestamp */
+  guint16 length;               /* Length */
+} GstAsteriskH263Header;
+
+#define GST_ASTERISKH263_HEADER_TIMESTAMP(data) (((GstAsteriskH263Header *)(data))->timestamp)
+#define GST_ASTERISKH263_HEADER_LENGTH(data) (((GstAsteriskH263Header *)(data))->length)
+
+static GstStaticPadTemplate gst_asteriskh263_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-asteriskh263")
+    );
+
+static GstStaticPadTemplate gst_asteriskh263_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) [ 96, 127 ], "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"H263-1998\"")
+    );
+
+static void gst_asteriskh263_finalize (GObject * object);
+
+static GstFlowReturn gst_asteriskh263_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer);
+
+static GstStateChangeReturn gst_asteriskh263_change_state (GstElement *
+    element, GstStateChange transition);
+
+#define gst_asteriskh263_parent_class parent_class
+G_DEFINE_TYPE (GstAsteriskh263, gst_asteriskh263, GST_TYPE_ELEMENT);
+
+static void
+gst_asteriskh263_class_init (GstAsteriskh263Class * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->finalize = gst_asteriskh263_finalize;
+
+  gstelement_class->change_state = gst_asteriskh263_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_asteriskh263_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_asteriskh263_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Asterisk H263 depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts H263 video from RTP and encodes in Asterisk H263 format",
+      "Neil Stratford <neils@vipadia.com>");
+}
+
+static void
+gst_asteriskh263_init (GstAsteriskh263 * asteriskh263)
+{
+  asteriskh263->srcpad =
+      gst_pad_new_from_static_template (&gst_asteriskh263_src_template, "src");
+  gst_element_add_pad (GST_ELEMENT (asteriskh263), asteriskh263->srcpad);
+
+  asteriskh263->sinkpad =
+      gst_pad_new_from_static_template (&gst_asteriskh263_sink_template,
+      "sink");
+  gst_pad_set_chain_function (asteriskh263->sinkpad, gst_asteriskh263_chain);
+  gst_element_add_pad (GST_ELEMENT (asteriskh263), asteriskh263->sinkpad);
+
+  asteriskh263->adapter = gst_adapter_new ();
+}
+
+static void
+gst_asteriskh263_finalize (GObject * object)
+{
+  GstAsteriskh263 *asteriskh263;
+
+  asteriskh263 = GST_ASTERISK_H263 (object);
+
+  g_object_unref (asteriskh263->adapter);
+  asteriskh263->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstFlowReturn
+gst_asteriskh263_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstAsteriskh263 *asteriskh263;
+  GstBuffer *outbuf;
+  GstFlowReturn ret;
+
+  asteriskh263 = GST_ASTERISK_H263 (parent);
+
+  {
+    gint payload_len;
+    guint8 *payload;
+    gboolean M;
+    guint32 timestamp;
+    guint32 samples;
+    guint16 asterisk_len;
+    GstRTPBuffer rtp = { NULL };
+    GstMapInfo map;
+
+    if (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp))
+      goto bad_packet;
+
+    payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+    payload = gst_rtp_buffer_get_payload (&rtp);
+
+    M = gst_rtp_buffer_get_marker (&rtp);
+    timestamp = gst_rtp_buffer_get_timestamp (&rtp);
+
+    gst_rtp_buffer_unmap (&rtp);
+
+    outbuf = gst_buffer_new_and_alloc (payload_len +
+        GST_ASTERISKH263_HEADER_LEN);
+
+    /* build the asterisk header */
+    asterisk_len = payload_len;
+    if (M)
+      asterisk_len |= 0x8000;
+    if (!asteriskh263->lastts)
+      asteriskh263->lastts = timestamp;
+    samples = timestamp - asteriskh263->lastts;
+    asteriskh263->lastts = timestamp;
+
+    gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+    GST_ASTERISKH263_HEADER_TIMESTAMP (map.data) = g_htonl (samples);
+    GST_ASTERISKH263_HEADER_LENGTH (map.data) = g_htons (asterisk_len);
+
+    /* copy the data into place */
+    memcpy (map.data + GST_ASTERISKH263_HEADER_LEN, payload, payload_len);
+
+    gst_buffer_unmap (outbuf, &map);
+
+    GST_BUFFER_PTS (outbuf) = timestamp;
+    if (!gst_pad_has_current_caps (asteriskh263->srcpad)) {
+      GstCaps *caps;
+
+      caps = gst_pad_get_pad_template_caps (asteriskh263->srcpad);
+      gst_pad_set_caps (asteriskh263->srcpad, caps);
+      gst_caps_unref (caps);
+    }
+
+    ret = gst_pad_push (asteriskh263->srcpad, outbuf);
+
+    gst_buffer_unref (buf);
+  }
+
+  return ret;
+
+bad_packet:
+  {
+    GST_DEBUG ("Packet does not validate");
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstStateChangeReturn
+gst_asteriskh263_change_state (GstElement * element, GstStateChange transition)
+{
+  GstAsteriskh263 *asteriskh263;
+  GstStateChangeReturn ret;
+
+  asteriskh263 = GST_ASTERISK_H263 (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_adapter_clear (asteriskh263->adapter);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  /*
+     switch (transition) {
+     case GST_STATE_CHANGE_READY_TO_NULL:
+     break;
+     default:
+     break;
+     }
+   */
+  return ret;
+}
+
+gboolean
+gst_asteriskh263_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "asteriskh263",
+      GST_RANK_NONE, GST_TYPE_ASTERISK_H263);
+}
diff --git a/gst/rtp/gstasteriskh263.h b/gst/rtp/gstasteriskh263.h
new file mode 100644
index 0000000..1c9523d
--- /dev/null
+++ b/gst/rtp/gstasteriskh263.h
@@ -0,0 +1,65 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_ASTERISK_H263_H__
+#define __GST_ASTERISK_H263_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_ASTERISK_H263 \
+  (gst_asteriskh263_get_type())
+#define GST_ASTERISK_H263(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ASTERISK_H263,GstAsteriskh263))
+#define GST_ASTERISK_H263_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ASTERISK_H263,GstAsteriskh263Class))
+#define GST_IS_ASTERISK_H263(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ASTERISK_H263))
+#define GST_IS_ASTERISK_H263_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ASTERISK_H263))
+
+typedef struct _GstAsteriskh263 GstAsteriskh263;
+typedef struct _GstAsteriskh263Class GstAsteriskh263Class;
+
+struct _GstAsteriskh263
+{
+  GstElement element;
+
+  GstPad *sinkpad;
+  GstPad *srcpad;
+
+  GstAdapter *adapter;
+
+  guint32 lastts;
+};
+
+struct _GstAsteriskh263Class
+{
+  GstElementClass parent_class;
+};
+
+GType gst_asteriskh263_get_type (void);
+
+gboolean gst_asteriskh263_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_ASTERISK_H263_H__ */
diff --git a/gst/rtp/gstrtp.c b/gst/rtp/gstrtp.c
new file mode 100644
index 0000000..8b0ef58
--- /dev/null
+++ b/gst/rtp/gstrtp.c
@@ -0,0 +1,398 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/tag/tag.h>
+
+#include "gstrtputils.h"
+
+#include "gstrtpac3depay.h"
+#include "gstrtpac3pay.h"
+#include "gstrtpbvdepay.h"
+#include "gstrtpbvpay.h"
+#include "gstrtpceltdepay.h"
+#include "gstrtpceltpay.h"
+#include "gstrtpdvdepay.h"
+#include "gstrtpdvpay.h"
+#include "gstrtpgstdepay.h"
+#include "gstrtpgstpay.h"
+#include "gstrtpilbcdepay.h"
+#include "gstrtpilbcpay.h"
+#include "gstrtppcmupay.h"
+#include "gstrtppcmapay.h"
+#include "gstrtppcmadepay.h"
+#include "gstrtppcmudepay.h"
+#include "gstrtpg722depay.h"
+#include "gstrtpg722pay.h"
+#include "gstrtpg723depay.h"
+#include "gstrtpg723pay.h"
+#include "gstrtpg726depay.h"
+#include "gstrtpg726pay.h"
+#include "gstrtpg729depay.h"
+#include "gstrtpg729pay.h"
+#include "gstrtpgsmpay.h"
+#include "gstrtpgsmdepay.h"
+#include "gstrtpamrpay.h"
+#include "gstrtpamrdepay.h"
+#include "gstrtpmpapay.h"
+#include "gstrtpmpadepay.h"
+#include "gstrtpmparobustdepay.h"
+#include "gstrtpmpvdepay.h"
+#include "gstrtpmpvpay.h"
+#include "gstrtpopusdepay.h"
+#include "gstrtpopuspay.h"
+#include "gstrtph261pay.h"
+#include "gstrtph261depay.h"
+#include "gstrtph263pdepay.h"
+#include "gstrtph263ppay.h"
+#include "gstrtph263depay.h"
+#include "gstrtph263pay.h"
+#include "gstrtph264depay.h"
+#include "gstrtph264pay.h"
+#include "gstrtph265depay.h"
+#include "gstrtph265pay.h"
+#include "gstrtpj2kdepay.h"
+#include "gstrtpj2kpay.h"
+#include "gstrtpjpegdepay.h"
+#include "gstrtpjpegpay.h"
+#include "gstrtpklvdepay.h"
+#include "gstrtpklvpay.h"
+#include "gstrtpL8depay.h"
+#include "gstrtpL8pay.h"
+#include "gstrtpL16depay.h"
+#include "gstrtpL16pay.h"
+#include "gstrtpL24depay.h"
+#include "gstrtpL24pay.h"
+#include "gstasteriskh263.h"
+#include "gstrtpmp1sdepay.h"
+#include "gstrtpmp2tdepay.h"
+#include "gstrtpmp2tpay.h"
+#include "gstrtpmp4vdepay.h"
+#include "gstrtpmp4vpay.h"
+#include "gstrtpmp4adepay.h"
+#include "gstrtpmp4apay.h"
+#include "gstrtpmp4gdepay.h"
+#include "gstrtpmp4gpay.h"
+#include "gstrtpqcelpdepay.h"
+#include "gstrtpqdmdepay.h"
+#include "gstrtpsbcdepay.h"
+#include "gstrtpsbcpay.h"
+#include "gstrtpsirenpay.h"
+#include "gstrtpsirendepay.h"
+#include "gstrtpspeexpay.h"
+#include "gstrtpspeexdepay.h"
+#include "gstrtpsv3vdepay.h"
+#include "gstrtptheoradepay.h"
+#include "gstrtptheorapay.h"
+#include "gstrtpvorbisdepay.h"
+#include "gstrtpvorbispay.h"
+#include "gstrtpvp8depay.h"
+#include "gstrtpvp8pay.h"
+#include "gstrtpvp9depay.h"
+#include "gstrtpvp9pay.h"
+#include "gstrtpvrawdepay.h"
+#include "gstrtpvrawpay.h"
+#include "gstrtpstreampay.h"
+#include "gstrtpstreamdepay.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  gst_tag_image_type_get_type ();
+
+  rtp_quark_meta_tag_video =
+      g_quark_from_static_string (GST_META_TAG_VIDEO_STR);
+  rtp_quark_meta_tag_audio =
+      g_quark_from_static_string (GST_META_TAG_AUDIO_STR);
+
+  if (!gst_rtp_ac3_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_ac3_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_bv_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_bv_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_celt_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_celt_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_dv_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_dv_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_gst_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_gst_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_ilbc_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_ilbc_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_g722_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_g722_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_g723_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_g723_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_g726_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_g726_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_g729_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_g729_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_gsm_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_gsm_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_amr_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_amr_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_pcma_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_pcmu_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_pcmu_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_pcma_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_mpa_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_mpa_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_mpa_robust_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_mpv_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_mpv_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_opus_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_opus_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_h261_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_h261_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_h263p_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_h263p_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_h263_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_h263_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_h264_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_h264_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_h265_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_h265_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_j2k_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_j2k_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_jpeg_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_jpeg_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_klv_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_klv_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_L8_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_L8_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_L16_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_L16_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_L24_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_L24_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_asteriskh263_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_mp1s_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_mp2t_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_mp2t_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_mp4v_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_mp4v_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_mp4a_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_mp4a_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_mp4g_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_mp4g_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_qcelp_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_qdm2_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_sbc_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_sbc_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_siren_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_siren_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_speex_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_speex_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_sv3v_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_theora_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_theora_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_vorbis_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_vorbis_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_vp8_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_vp8_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_vp9_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_vp9_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_vraw_depay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_vraw_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_stream_pay_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_stream_depay_plugin_init (plugin))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    rtp,
+    "Real-time protocol plugins",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/rtp/gstrtpL16depay.c b/gst/rtp/gstrtpL16depay.c
new file mode 100644
index 0000000..601f16e
--- /dev/null
+++ b/gst/rtp/gstrtpL16depay.c
@@ -0,0 +1,285 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpL16depay
+ * @see_also: rtpL16pay
+ *
+ * Extract raw audio from RTP packets according to RFC 3551.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc3551.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 udpsrc caps='application/x-rtp, media=(string)audio, clock-rate=(int)44100, encoding-name=(string)L16, encoding-params=(string)1, channels=(int)1, payload=(int)96' ! rtpL16depay ! pulsesink
+ * ]| This example pipeline will depayload an RTP raw audio stream. Refer to
+ * the rtpL16pay example to create the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/audio/audio.h>
+
+#include "gstrtpL16depay.h"
+#include "gstrtpchannels.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpL16depay_debug);
+#define GST_CAT_DEFAULT (rtpL16depay_debug)
+
+static GstStaticPadTemplate gst_rtp_L16_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) S16BE, "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+    );
+
+static GstStaticPadTemplate gst_rtp_L16_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", " "clock-rate = (int) [ 1, MAX ], "
+        /* "channels = (int) [1, MAX]"  */
+        /* "emphasis = (string) ANY" */
+        /* "channel-order = (string) ANY" */
+        "encoding-name = (string) \"L16\";"
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) { " GST_RTP_PAYLOAD_L16_STEREO_STRING ", "
+        GST_RTP_PAYLOAD_L16_MONO_STRING " }," "clock-rate = (int) [ 1, MAX ]"
+        /* "channels = (int) [1, MAX]" */
+        /* "emphasis = (string) ANY" */
+        /* "channel-order = (string) ANY" */
+    )
+    );
+
+#define gst_rtp_L16_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpL16Depay, gst_rtp_L16_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_L16_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_L16_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+static void
+gst_rtp_L16_depay_class_init (GstRtpL16DepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gstrtpbasedepayload_class->set_caps = gst_rtp_L16_depay_setcaps;
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_L16_depay_process;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_L16_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_L16_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP audio depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts raw audio from RTP packets",
+      "Zeeshan Ali <zak147@yahoo.com>," "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpL16depay_debug, "rtpL16depay", 0,
+      "Raw Audio RTP Depayloader");
+}
+
+static void
+gst_rtp_L16_depay_init (GstRtpL16Depay * rtpL16depay)
+{
+}
+
+static gint
+gst_rtp_L16_depay_parse_int (GstStructure * structure, const gchar * field,
+    gint def)
+{
+  const gchar *str;
+  gint res;
+
+  if ((str = gst_structure_get_string (structure, field)))
+    return atoi (str);
+
+  if (gst_structure_get_int (structure, field, &res))
+    return res;
+
+  return def;
+}
+
+static gboolean
+gst_rtp_L16_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstRtpL16Depay *rtpL16depay;
+  gint clock_rate, payload;
+  gint channels;
+  GstCaps *srccaps;
+  gboolean res;
+  const gchar *channel_order;
+  const GstRTPChannelOrder *order;
+  GstAudioInfo *info;
+
+  rtpL16depay = GST_RTP_L16_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  payload = 96;
+  gst_structure_get_int (structure, "payload", &payload);
+  switch (payload) {
+    case GST_RTP_PAYLOAD_L16_STEREO:
+      channels = 2;
+      clock_rate = 44100;
+      break;
+    case GST_RTP_PAYLOAD_L16_MONO:
+      channels = 1;
+      clock_rate = 44100;
+      break;
+    default:
+      /* no fixed mapping, we need clock-rate */
+      channels = 0;
+      clock_rate = 0;
+      break;
+  }
+
+  /* caps can overwrite defaults */
+  clock_rate =
+      gst_rtp_L16_depay_parse_int (structure, "clock-rate", clock_rate);
+  if (clock_rate == 0)
+    goto no_clockrate;
+
+  channels =
+      gst_rtp_L16_depay_parse_int (structure, "encoding-params", channels);
+  if (channels == 0) {
+    channels = gst_rtp_L16_depay_parse_int (structure, "channels", channels);
+    if (channels == 0) {
+      /* channels defaults to 1 otherwise */
+      channels = 1;
+    }
+  }
+
+  depayload->clock_rate = clock_rate;
+
+  info = &rtpL16depay->info;
+  gst_audio_info_init (info);
+  info->finfo = gst_audio_format_get_info (GST_AUDIO_FORMAT_S16BE);
+  info->rate = clock_rate;
+  info->channels = channels;
+  info->bpf = (info->finfo->width / 8) * channels;
+
+  /* add channel positions */
+  channel_order = gst_structure_get_string (structure, "channel-order");
+
+  order = gst_rtp_channels_get_by_order (channels, channel_order);
+  rtpL16depay->order = order;
+  if (order) {
+    memcpy (info->position, order->pos,
+        sizeof (GstAudioChannelPosition) * channels);
+    gst_audio_channel_positions_to_valid_order (info->position, info->channels);
+  } else {
+    GST_ELEMENT_WARNING (rtpL16depay, STREAM, DECODE,
+        (NULL), ("Unknown channel order '%s' for %d channels",
+            GST_STR_NULL (channel_order), channels));
+    /* create default NONE layout */
+    gst_rtp_channels_create_default (channels, info->position);
+  }
+
+  srccaps = gst_audio_info_to_caps (info);
+  res = gst_pad_set_caps (depayload->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  return res;
+
+  /* ERRORS */
+no_clockrate:
+  {
+    GST_ERROR_OBJECT (depayload, "no clock-rate specified");
+    return FALSE;
+  }
+}
+
+static GstBuffer *
+gst_rtp_L16_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpL16Depay *rtpL16depay;
+  GstBuffer *outbuf;
+  gint payload_len;
+  gboolean marker;
+
+  rtpL16depay = GST_RTP_L16_DEPAY (depayload);
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  if (payload_len <= 0)
+    goto empty_packet;
+
+  GST_DEBUG_OBJECT (rtpL16depay, "got payload of %d bytes", payload_len);
+
+  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  if (marker) {
+    /* mark talk spurt with RESYNC */
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+  }
+
+  outbuf = gst_buffer_make_writable (outbuf);
+  if (rtpL16depay->order &&
+      !gst_audio_buffer_reorder_channels (outbuf,
+          rtpL16depay->info.finfo->format, rtpL16depay->info.channels,
+          rtpL16depay->info.position, rtpL16depay->order->pos)) {
+    goto reorder_failed;
+  }
+
+  gst_rtp_drop_non_audio_meta (rtpL16depay, outbuf);
+
+  return outbuf;
+
+  /* ERRORS */
+empty_packet:
+  {
+    GST_ELEMENT_WARNING (rtpL16depay, STREAM, DECODE,
+        ("Empty Payload."), (NULL));
+    return NULL;
+  }
+reorder_failed:
+  {
+    GST_ELEMENT_ERROR (rtpL16depay, STREAM, DECODE,
+        ("Channel reordering failed."), (NULL));
+    return NULL;
+  }
+}
+
+gboolean
+gst_rtp_L16_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpL16depay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_L16_DEPAY);
+}
diff --git a/gst/rtp/gstrtpL16depay.h b/gst/rtp/gstrtpL16depay.h
new file mode 100644
index 0000000..125d4cd
--- /dev/null
+++ b/gst/rtp/gstrtpL16depay.h
@@ -0,0 +1,67 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_L16_DEPAY_H__
+#define __GST_RTP_L16_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpchannels.h"
+
+G_BEGIN_DECLS
+
+/* Standard macros for defining types for this element.  */
+#define GST_TYPE_RTP_L16_DEPAY \
+  (gst_rtp_L16_depay_get_type())
+#define GST_RTP_L16_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_L16_DEPAY,GstRtpL16Depay))
+#define GST_RTP_L16_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_L16_DEPAY,GstRtpL16DepayClass))
+#define GST_IS_RTP_L16_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_L16_DEPAY))
+#define GST_IS_RTP_L16_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_L16_DEPAY))
+
+typedef struct _GstRtpL16Depay GstRtpL16Depay;
+typedef struct _GstRtpL16DepayClass GstRtpL16DepayClass;
+
+/* Definition of structure storing data for this element. */
+struct _GstRtpL16Depay
+{
+  GstRTPBaseDepayload depayload;
+
+  GstAudioInfo info;
+  const GstRTPChannelOrder *order;
+};
+
+/* Standard definition defining a class for this element. */
+struct _GstRtpL16DepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_L16_depay_get_type (void);
+
+gboolean gst_rtp_L16_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_L16_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpL16pay.c b/gst/rtp/gstrtpL16pay.c
new file mode 100644
index 0000000..4783a65
--- /dev/null
+++ b/gst/rtp/gstrtpL16pay.c
@@ -0,0 +1,263 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpL16pay
+ * @see_also: rtpL16depay
+ *
+ * Payload raw audio into RTP packets according to RFC 3551.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc3551.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! audioconvert ! rtpL16pay ! udpsink
+ * ]| This example pipeline will payload raw audio. Refer to
+ * the rtpL16depay example to depayload and play the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/audio/audio.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpL16pay.h"
+#include "gstrtpchannels.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpL16pay_debug);
+#define GST_CAT_DEFAULT (rtpL16pay_debug)
+
+static GstStaticPadTemplate gst_rtp_L16_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) S16BE, "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+    );
+
+static GstStaticPadTemplate gst_rtp_L16_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) [ 96, 127 ], "
+        "clock-rate = (int) [ 1, MAX ], "
+        "encoding-name = (string) \"L16\", "
+        "channels = (int) [ 1, MAX ];"
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "encoding-name = (string) \"L16\", "
+        "payload = (int) " GST_RTP_PAYLOAD_L16_STEREO_STRING ", "
+        "clock-rate = (int) 44100;"
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "encoding-name = (string) \"L16\", "
+        "payload = (int) " GST_RTP_PAYLOAD_L16_MONO_STRING ", "
+        "clock-rate = (int) 44100")
+    );
+
+static gboolean gst_rtp_L16_pay_setcaps (GstRTPBasePayload * basepayload,
+    GstCaps * caps);
+static GstCaps *gst_rtp_L16_pay_getcaps (GstRTPBasePayload * rtppayload,
+    GstPad * pad, GstCaps * filter);
+static GstFlowReturn
+gst_rtp_L16_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer);
+
+#define gst_rtp_L16_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpL16Pay, gst_rtp_L16_pay, GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_L16_pay_class_init (GstRtpL16PayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_L16_pay_setcaps;
+  gstrtpbasepayload_class->get_caps = gst_rtp_L16_pay_getcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_L16_pay_handle_buffer;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_L16_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_L16_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP audio payloader", "Codec/Payloader/Network/RTP",
+      "Payload-encode Raw audio into RTP packets (RFC 3551)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpL16pay_debug, "rtpL16pay", 0,
+      "L16 RTP Payloader");
+}
+
+static void
+gst_rtp_L16_pay_init (GstRtpL16Pay * rtpL16pay)
+{
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpL16pay);
+
+  /* tell rtpbaseaudiopayload that this is a sample based codec */
+  gst_rtp_base_audio_payload_set_sample_based (rtpbaseaudiopayload);
+}
+
+static gboolean
+gst_rtp_L16_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+  GstRtpL16Pay *rtpL16pay;
+  gboolean res;
+  gchar *params;
+  GstAudioInfo *info;
+  const GstRTPChannelOrder *order;
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (basepayload);
+  rtpL16pay = GST_RTP_L16_PAY (basepayload);
+
+  info = &rtpL16pay->info;
+  gst_audio_info_init (info);
+  if (!gst_audio_info_from_caps (info, caps))
+    goto invalid_caps;
+
+  order = gst_rtp_channels_get_by_pos (info->channels, info->position);
+  rtpL16pay->order = order;
+
+  gst_rtp_base_payload_set_options (basepayload, "audio", TRUE, "L16",
+      info->rate);
+  params = g_strdup_printf ("%d", info->channels);
+
+  if (!order && info->channels > 2) {
+    GST_ELEMENT_WARNING (rtpL16pay, STREAM, DECODE,
+        (NULL), ("Unknown channel order for %d channels", info->channels));
+  }
+
+  if (order && order->name) {
+    res = gst_rtp_base_payload_set_outcaps (basepayload,
+        "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
+        info->channels, "channel-order", G_TYPE_STRING, order->name, NULL);
+  } else {
+    res = gst_rtp_base_payload_set_outcaps (basepayload,
+        "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
+        info->channels, NULL);
+  }
+
+  g_free (params);
+
+  /* octet-per-sample is 2 * channels for L16 */
+  gst_rtp_base_audio_payload_set_sample_options (rtpbaseaudiopayload,
+      2 * info->channels);
+
+  return res;
+
+  /* ERRORS */
+invalid_caps:
+  {
+    GST_DEBUG_OBJECT (rtpL16pay, "invalid caps");
+    return FALSE;
+  }
+}
+
+static GstCaps *
+gst_rtp_L16_pay_getcaps (GstRTPBasePayload * rtppayload, GstPad * pad,
+    GstCaps * filter)
+{
+  GstCaps *otherpadcaps;
+  GstCaps *caps;
+
+  caps = gst_pad_get_pad_template_caps (pad);
+
+  otherpadcaps = gst_pad_get_allowed_caps (rtppayload->srcpad);
+  if (otherpadcaps) {
+    if (!gst_caps_is_empty (otherpadcaps)) {
+      GstStructure *structure;
+      gint channels;
+      gint pt;
+      gint rate;
+
+      structure = gst_caps_get_structure (otherpadcaps, 0);
+      caps = gst_caps_make_writable (caps);
+
+      if (gst_structure_get_int (structure, "channels", &channels)) {
+        gst_caps_set_simple (caps, "channels", G_TYPE_INT, channels, NULL);
+      } else if (gst_structure_get_int (structure, "payload", &pt)) {
+        if (pt == GST_RTP_PAYLOAD_L16_STEREO)
+          gst_caps_set_simple (caps, "channels", G_TYPE_INT, 2, NULL);
+        else if (pt == GST_RTP_PAYLOAD_L16_MONO)
+          gst_caps_set_simple (caps, "channels", G_TYPE_INT, 1, NULL);
+      }
+
+      if (gst_structure_get_int (structure, "clock-rate", &rate)) {
+        gst_caps_set_simple (caps, "rate", G_TYPE_INT, rate, NULL);
+      } else if (gst_structure_get_int (structure, "payload", &pt)) {
+        if (pt == GST_RTP_PAYLOAD_L16_STEREO || pt == GST_RTP_PAYLOAD_L16_MONO)
+          gst_caps_set_simple (caps, "rate", G_TYPE_INT, 44100, NULL);
+      }
+
+    }
+    gst_caps_unref (otherpadcaps);
+  }
+
+  if (filter) {
+    GstCaps *tcaps = caps;
+
+    caps = gst_caps_intersect_full (filter, tcaps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (tcaps);
+  }
+
+  return caps;
+}
+
+static GstFlowReturn
+gst_rtp_L16_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpL16Pay *rtpL16pay;
+
+  rtpL16pay = GST_RTP_L16_PAY (basepayload);
+  buffer = gst_buffer_make_writable (buffer);
+
+  if (rtpL16pay->order &&
+      !gst_audio_buffer_reorder_channels (buffer, rtpL16pay->info.finfo->format,
+          rtpL16pay->info.channels, rtpL16pay->info.position,
+          rtpL16pay->order->pos)) {
+    return GST_FLOW_ERROR;
+  }
+
+  return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->handle_buffer (basepayload,
+      buffer);
+}
+
+gboolean
+gst_rtp_L16_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpL16pay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_L16_PAY);
+}
diff --git a/gst/rtp/gstrtpL16pay.h b/gst/rtp/gstrtpL16pay.h
new file mode 100644
index 0000000..f4f3702
--- /dev/null
+++ b/gst/rtp/gstrtpL16pay.h
@@ -0,0 +1,63 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_L16_PAY_H__
+#define __GST_RTP_L16_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+#include "gstrtpchannels.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_L16_PAY \
+  (gst_rtp_L16_pay_get_type())
+#define GST_RTP_L16_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_L16_PAY,GstRtpL16Pay))
+#define GST_RTP_L16_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_L16_PAY,GstRtpL16PayClass))
+#define GST_IS_RTP_L16_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_L16_PAY))
+#define GST_IS_RTP_L16_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_L16_PAY))
+
+typedef struct _GstRtpL16Pay GstRtpL16Pay;
+typedef struct _GstRtpL16PayClass GstRtpL16PayClass;
+
+struct _GstRtpL16Pay
+{
+  GstRTPBaseAudioPayload payload;
+
+  GstAudioInfo info;
+  const GstRTPChannelOrder *order;
+};
+
+struct _GstRtpL16PayClass
+{
+  GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_L16_pay_get_type (void);
+
+gboolean gst_rtp_L16_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_L16_PAY_H__ */
diff --git a/gst/rtp/gstrtpL24depay.c b/gst/rtp/gstrtpL24depay.c
new file mode 100644
index 0000000..8b28ee8
--- /dev/null
+++ b/gst/rtp/gstrtpL24depay.c
@@ -0,0 +1,264 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpL24depay
+ * @see_also: rtpL24pay
+ *
+ * Extract raw audio from RTP packets according to RFC 3190, section 4.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc3190.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 udpsrc caps='application/x-rtp, media=(string)audio, clock-rate=(int)44100, encoding-name=(string)L24, encoding-params=(string)1, channels=(int)1, payload=(int)96' ! rtpL24depay ! pulsesink
+ * ]| This example pipeline will depayload an RTP raw audio stream. Refer to
+ * the rtpL24pay example to create the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/audio/audio.h>
+
+#include "gstrtpL24depay.h"
+#include "gstrtpchannels.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpL24depay_debug);
+#define GST_CAT_DEFAULT (rtpL24depay_debug)
+
+static GstStaticPadTemplate gst_rtp_L24_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) S24BE, "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+    );
+
+static GstStaticPadTemplate gst_rtp_L24_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", " "clock-rate = (int) [ 1, MAX ], "
+        "encoding-name = (string) \"L24\"")
+    );
+
+#define gst_rtp_L24_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpL24Depay, gst_rtp_L24_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_L24_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_L24_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+static void
+gst_rtp_L24_depay_class_init (GstRtpL24DepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gstrtpbasedepayload_class->set_caps = gst_rtp_L24_depay_setcaps;
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_L24_depay_process;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_L24_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_L24_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP audio depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts raw 24-bit audio from RTP packets",
+      "Zeeshan Ali <zak147@yahoo.com>," "Wim Taymans <wim.taymans@gmail.com>,"
+      "David Holroyd <dave@badgers-in-foil.co.uk>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpL24depay_debug, "rtpL24depay", 0,
+      "Raw Audio RTP Depayloader");
+}
+
+static void
+gst_rtp_L24_depay_init (GstRtpL24Depay * rtpL24depay)
+{
+}
+
+static gint
+gst_rtp_L24_depay_parse_int (GstStructure * structure, const gchar * field,
+    gint def)
+{
+  const gchar *str;
+  gint res;
+
+  if ((str = gst_structure_get_string (structure, field)))
+    return atoi (str);
+
+  if (gst_structure_get_int (structure, field, &res))
+    return res;
+
+  return def;
+}
+
+static gboolean
+gst_rtp_L24_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstRtpL24Depay *rtpL24depay;
+  gint clock_rate, payload;
+  gint channels;
+  GstCaps *srccaps;
+  gboolean res;
+  const gchar *channel_order;
+  const GstRTPChannelOrder *order;
+  GstAudioInfo *info;
+
+  rtpL24depay = GST_RTP_L24_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  payload = 96;
+  gst_structure_get_int (structure, "payload", &payload);
+  /* no fixed mapping, we need clock-rate */
+  channels = 0;
+  clock_rate = 0;
+
+  /* caps can overwrite defaults */
+  clock_rate =
+      gst_rtp_L24_depay_parse_int (structure, "clock-rate", clock_rate);
+  if (clock_rate == 0)
+    goto no_clockrate;
+
+  channels =
+      gst_rtp_L24_depay_parse_int (structure, "encoding-params", channels);
+  if (channels == 0) {
+    channels = gst_rtp_L24_depay_parse_int (structure, "channels", channels);
+    if (channels == 0) {
+      /* channels defaults to 1 otherwise */
+      channels = 1;
+    }
+  }
+
+  depayload->clock_rate = clock_rate;
+
+  info = &rtpL24depay->info;
+  gst_audio_info_init (info);
+  info->finfo = gst_audio_format_get_info (GST_AUDIO_FORMAT_S24BE);
+  info->rate = clock_rate;
+  info->channels = channels;
+  info->bpf = (info->finfo->width / 8) * channels;
+
+  /* add channel positions */
+  channel_order = gst_structure_get_string (structure, "channel-order");
+
+  order = gst_rtp_channels_get_by_order (channels, channel_order);
+  rtpL24depay->order = order;
+  if (order) {
+    memcpy (info->position, order->pos,
+        sizeof (GstAudioChannelPosition) * channels);
+    gst_audio_channel_positions_to_valid_order (info->position, info->channels);
+  } else {
+    GST_ELEMENT_WARNING (rtpL24depay, STREAM, DECODE,
+        (NULL), ("Unknown channel order '%s' for %d channels",
+            GST_STR_NULL (channel_order), channels));
+    /* create default NONE layout */
+    gst_rtp_channels_create_default (channels, info->position);
+  }
+
+  srccaps = gst_audio_info_to_caps (info);
+  res = gst_pad_set_caps (depayload->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  return res;
+
+  /* ERRORS */
+no_clockrate:
+  {
+    GST_ERROR_OBJECT (depayload, "no clock-rate specified");
+    return FALSE;
+  }
+}
+
+static GstBuffer *
+gst_rtp_L24_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpL24Depay *rtpL24depay;
+  GstBuffer *outbuf;
+  gint payload_len;
+  gboolean marker;
+
+  rtpL24depay = GST_RTP_L24_DEPAY (depayload);
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  if (payload_len <= 0)
+    goto empty_packet;
+
+  GST_DEBUG_OBJECT (rtpL24depay, "got payload of %d bytes", payload_len);
+
+  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  if (marker) {
+    /* mark talk spurt with RESYNC */
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+  }
+
+  outbuf = gst_buffer_make_writable (outbuf);
+  if (outbuf) {
+    gst_rtp_drop_non_audio_meta (rtpL24depay, outbuf);
+  }
+  if (rtpL24depay->order &&
+      !gst_audio_buffer_reorder_channels (outbuf,
+          rtpL24depay->info.finfo->format, rtpL24depay->info.channels,
+          rtpL24depay->info.position, rtpL24depay->order->pos)) {
+    goto reorder_failed;
+  }
+
+  return outbuf;
+
+  /* ERRORS */
+empty_packet:
+  {
+    GST_ELEMENT_WARNING (rtpL24depay, STREAM, DECODE,
+        ("Empty Payload."), (NULL));
+    return NULL;
+  }
+reorder_failed:
+  {
+    GST_ELEMENT_ERROR (rtpL24depay, STREAM, DECODE,
+        ("Channel reordering failed."), (NULL));
+    return NULL;
+  }
+}
+
+gboolean
+gst_rtp_L24_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpL24depay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_L24_DEPAY);
+}
diff --git a/gst/rtp/gstrtpL24depay.h b/gst/rtp/gstrtpL24depay.h
new file mode 100644
index 0000000..c4e00e6
--- /dev/null
+++ b/gst/rtp/gstrtpL24depay.h
@@ -0,0 +1,67 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_L24_DEPAY_H__
+#define __GST_RTP_L24_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpchannels.h"
+
+G_BEGIN_DECLS
+
+/* Standard macros for defining types for this element.  */
+#define GST_TYPE_RTP_L24_DEPAY \
+  (gst_rtp_L24_depay_get_type())
+#define GST_RTP_L24_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_L24_DEPAY,GstRtpL24Depay))
+#define GST_RTP_L24_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_L24_DEPAY,GstRtpL24DepayClass))
+#define GST_IS_RTP_L24_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_L24_DEPAY))
+#define GST_IS_RTP_L24_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_L24_DEPAY))
+
+typedef struct _GstRtpL24Depay GstRtpL24Depay;
+typedef struct _GstRtpL24DepayClass GstRtpL24DepayClass;
+
+/* Definition of structure storing data for this element. */
+struct _GstRtpL24Depay
+{
+  GstRTPBaseDepayload depayload;
+
+  GstAudioInfo info;
+  const GstRTPChannelOrder *order;
+};
+
+/* Standard definition defining a class for this element. */
+struct _GstRtpL24DepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_L24_depay_get_type (void);
+
+gboolean gst_rtp_L24_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_L24_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpL24pay.c b/gst/rtp/gstrtpL24pay.c
new file mode 100644
index 0000000..936bd44
--- /dev/null
+++ b/gst/rtp/gstrtpL24pay.c
@@ -0,0 +1,244 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpL24pay
+ * @see_also: rtpL24depay
+ *
+ * Payload raw 24-bit audio into RTP packets according to RFC 3190, section 4.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc3190.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! audioconvert ! rtpL24pay ! udpsink
+ * ]| This example pipeline will payload raw audio. Refer to
+ * the rtpL24depay example to depayload and play the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/audio/audio.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpL24pay.h"
+#include "gstrtpchannels.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpL24pay_debug);
+#define GST_CAT_DEFAULT (rtpL24pay_debug)
+
+static GstStaticPadTemplate gst_rtp_L24_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) S24BE, "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+    );
+
+static GstStaticPadTemplate gst_rtp_L24_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) [ 96, 127 ], "
+        "clock-rate = (int) [ 1, MAX ], "
+        "encoding-name = (string) \"L24\", " "channels = (int) [ 1, MAX ];")
+    );
+
+static gboolean gst_rtp_L24_pay_setcaps (GstRTPBasePayload * basepayload,
+    GstCaps * caps);
+static GstCaps *gst_rtp_L24_pay_getcaps (GstRTPBasePayload * rtppayload,
+    GstPad * pad, GstCaps * filter);
+static GstFlowReturn
+gst_rtp_L24_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer);
+
+#define gst_rtp_L24_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpL24Pay, gst_rtp_L24_pay, GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_L24_pay_class_init (GstRtpL24PayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_L24_pay_setcaps;
+  gstrtpbasepayload_class->get_caps = gst_rtp_L24_pay_getcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_L24_pay_handle_buffer;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_L24_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_L24_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP audio payloader", "Codec/Payloader/Network/RTP",
+      "Payload-encode Raw 24-bit audio into RTP packets (RFC 3190)",
+      "Wim Taymans <wim.taymans@gmail.com>,"
+      "David Holroyd <dave@badgers-in-foil.co.uk>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpL24pay_debug, "rtpL24pay", 0,
+      "L24 RTP Payloader");
+}
+
+static void
+gst_rtp_L24_pay_init (GstRtpL24Pay * rtpL24pay)
+{
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpL24pay);
+
+  /* tell rtpbaseaudiopayload that this is a sample based codec */
+  gst_rtp_base_audio_payload_set_sample_based (rtpbaseaudiopayload);
+}
+
+static gboolean
+gst_rtp_L24_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+  GstRtpL24Pay *rtpL24pay;
+  gboolean res;
+  gchar *params;
+  GstAudioInfo *info;
+  const GstRTPChannelOrder *order;
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (basepayload);
+  rtpL24pay = GST_RTP_L24_PAY (basepayload);
+
+  info = &rtpL24pay->info;
+  gst_audio_info_init (info);
+  if (!gst_audio_info_from_caps (info, caps))
+    goto invalid_caps;
+
+  order = gst_rtp_channels_get_by_pos (info->channels, info->position);
+  rtpL24pay->order = order;
+
+  gst_rtp_base_payload_set_options (basepayload, "audio", TRUE, "L24",
+      info->rate);
+  params = g_strdup_printf ("%d", info->channels);
+
+  if (!order && info->channels > 2) {
+    GST_ELEMENT_WARNING (rtpL24pay, STREAM, DECODE,
+        (NULL), ("Unknown channel order for %d channels", info->channels));
+  }
+
+  if (order && order->name) {
+    res = gst_rtp_base_payload_set_outcaps (basepayload,
+        "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
+        info->channels, "channel-order", G_TYPE_STRING, order->name, NULL);
+  } else {
+    res = gst_rtp_base_payload_set_outcaps (basepayload,
+        "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
+        info->channels, NULL);
+  }
+
+  g_free (params);
+
+  /* octet-per-sample is 3 * channels for L24 */
+  gst_rtp_base_audio_payload_set_sample_options (rtpbaseaudiopayload,
+      3 * info->channels);
+
+  return res;
+
+  /* ERRORS */
+invalid_caps:
+  {
+    GST_DEBUG_OBJECT (rtpL24pay, "invalid caps");
+    return FALSE;
+  }
+}
+
+static GstCaps *
+gst_rtp_L24_pay_getcaps (GstRTPBasePayload * rtppayload, GstPad * pad,
+    GstCaps * filter)
+{
+  GstCaps *otherpadcaps;
+  GstCaps *caps;
+
+  caps = gst_pad_get_pad_template_caps (pad);
+
+  otherpadcaps = gst_pad_get_allowed_caps (rtppayload->srcpad);
+  if (otherpadcaps) {
+    if (!gst_caps_is_empty (otherpadcaps)) {
+      GstStructure *structure;
+      gint channels;
+      gint rate;
+
+      structure = gst_caps_get_structure (otherpadcaps, 0);
+      caps = gst_caps_make_writable (caps);
+
+      if (gst_structure_get_int (structure, "channels", &channels)) {
+        gst_caps_set_simple (caps, "channels", G_TYPE_INT, channels, NULL);
+      }
+
+      if (gst_structure_get_int (structure, "clock-rate", &rate)) {
+        gst_caps_set_simple (caps, "rate", G_TYPE_INT, rate, NULL);
+      }
+
+    }
+    gst_caps_unref (otherpadcaps);
+  }
+
+  if (filter) {
+    GstCaps *tcaps = caps;
+
+    caps = gst_caps_intersect_full (filter, tcaps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (tcaps);
+  }
+
+  return caps;
+}
+
+static GstFlowReturn
+gst_rtp_L24_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpL24Pay *rtpL24pay;
+
+  rtpL24pay = GST_RTP_L24_PAY (basepayload);
+  buffer = gst_buffer_make_writable (buffer);
+
+  if (rtpL24pay->order &&
+      !gst_audio_buffer_reorder_channels (buffer, rtpL24pay->info.finfo->format,
+          rtpL24pay->info.channels, rtpL24pay->info.position,
+          rtpL24pay->order->pos)) {
+    return GST_FLOW_ERROR;
+  }
+
+  return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->handle_buffer (basepayload,
+      buffer);
+}
+
+gboolean
+gst_rtp_L24_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpL24pay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_L24_PAY);
+}
diff --git a/gst/rtp/gstrtpL24pay.h b/gst/rtp/gstrtpL24pay.h
new file mode 100644
index 0000000..47395ad
--- /dev/null
+++ b/gst/rtp/gstrtpL24pay.h
@@ -0,0 +1,63 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_L24_PAY_H__
+#define __GST_RTP_L24_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+#include "gstrtpchannels.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_L24_PAY \
+  (gst_rtp_L24_pay_get_type())
+#define GST_RTP_L24_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_L24_PAY,GstRtpL24Pay))
+#define GST_RTP_L24_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_L24_PAY,GstRtpL24PayClass))
+#define GST_IS_RTP_L24_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_L24_PAY))
+#define GST_IS_RTP_L24_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_L24_PAY))
+
+typedef struct _GstRtpL24Pay GstRtpL24Pay;
+typedef struct _GstRtpL24PayClass GstRtpL24PayClass;
+
+struct _GstRtpL24Pay
+{
+  GstRTPBaseAudioPayload payload;
+
+  GstAudioInfo info;
+  const GstRTPChannelOrder *order;
+};
+
+struct _GstRtpL24PayClass
+{
+  GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_L24_pay_get_type (void);
+
+gboolean gst_rtp_L24_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_L24_PAY_H__ */
diff --git a/gst/rtp/gstrtpL8depay.c b/gst/rtp/gstrtpL8depay.c
new file mode 100644
index 0000000..5b9520a
--- /dev/null
+++ b/gst/rtp/gstrtpL8depay.c
@@ -0,0 +1,267 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) <2015> GE Intelligent Platforms Embedded Systems, Inc.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpL8depay
+ * @see_also: rtpL8pay
+ *
+ * Extract raw audio from RTP packets according to RFC 3551.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc3551.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch udpsrc caps='application/x-rtp, media=(string)audio, clock-rate=(int)44100, encoding-name=(string)L8, encoding-params=(string)1, channels=(int)1, payload=(int)96' ! rtpL8depay ! pulsesink
+ * ]| This example pipeline will depayload an RTP raw audio stream. Refer to
+ * the rtpL8pay example to create the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/audio/audio.h>
+
+#include "gstrtpL8depay.h"
+#include "gstrtpchannels.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpL8depay_debug);
+#define GST_CAT_DEFAULT (rtpL8depay_debug)
+
+static GstStaticPadTemplate gst_rtp_L8_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) U8, "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+    );
+
+static GstStaticPadTemplate gst_rtp_L8_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) audio, clock-rate = (int) [ 1, MAX ], "
+        /* "channels = (int) [1, MAX]"  */
+        /* "emphasis = (string) ANY" */
+        /* "channel-order = (string) ANY" */
+        "encoding-name = (string) L8;")
+    );
+
+#define gst_rtp_L8_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpL8Depay, gst_rtp_L8_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_L8_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_L8_depay_process (GstRTPBaseDepayload * depayload,
+    GstBuffer * buf);
+
+static void
+gst_rtp_L8_depay_class_init (GstRtpL8DepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gstrtpbasedepayload_class->set_caps = gst_rtp_L8_depay_setcaps;
+  gstrtpbasedepayload_class->process = gst_rtp_L8_depay_process;
+
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&gst_rtp_L8_depay_src_template));
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&gst_rtp_L8_depay_sink_template));
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP audio depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts raw audio from RTP packets",
+      "Zeeshan Ali <zak147@yahoo.com>," "Wim Taymans <wim.taymans@gmail.com>, "
+      "GE Intelligent Platforms Embedded Systems, Inc.");
+
+  GST_DEBUG_CATEGORY_INIT (rtpL8depay_debug, "rtpL8depay", 0,
+      "Raw Audio RTP Depayloader");
+}
+
+static void
+gst_rtp_L8_depay_init (GstRtpL8Depay * rtpL8depay)
+{
+}
+
+static gint
+gst_rtp_L8_depay_parse_int (GstStructure * structure, const gchar * field,
+    gint def)
+{
+  const gchar *str;
+  gint res;
+
+  if ((str = gst_structure_get_string (structure, field)))
+    return atoi (str);
+
+  if (gst_structure_get_int (structure, field, &res))
+    return res;
+
+  return def;
+}
+
+static gboolean
+gst_rtp_L8_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstRtpL8Depay *rtpL8depay;
+  gint clock_rate;
+  gint channels;
+  GstCaps *srccaps;
+  gboolean res;
+  const gchar *channel_order;
+  const GstRTPChannelOrder *order;
+  GstAudioInfo *info;
+
+  rtpL8depay = GST_RTP_L8_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  /* no fixed mapping, we need clock-rate */
+  channels = 0;
+  clock_rate = 0;
+
+  /* caps can overwrite defaults */
+  clock_rate = gst_rtp_L8_depay_parse_int (structure, "clock-rate", clock_rate);
+  if (clock_rate == 0)
+    goto no_clockrate;
+
+  channels =
+      gst_rtp_L8_depay_parse_int (structure, "encoding-params", channels);
+  if (channels == 0) {
+    channels = gst_rtp_L8_depay_parse_int (structure, "channels", channels);
+    if (channels == 0) {
+      /* channels defaults to 1 otherwise */
+      channels = 1;
+    }
+  }
+
+  depayload->clock_rate = clock_rate;
+
+  info = &rtpL8depay->info;
+  gst_audio_info_init (info);
+  info->finfo = gst_audio_format_get_info (GST_AUDIO_FORMAT_U8);
+  info->rate = clock_rate;
+  info->channels = channels;
+  info->bpf = (info->finfo->width / 8) * channels;
+
+  /* add channel positions */
+  channel_order = gst_structure_get_string (structure, "channel-order");
+
+  order = gst_rtp_channels_get_by_order (channels, channel_order);
+  rtpL8depay->order = order;
+  if (order) {
+    memcpy (info->position, order->pos,
+        sizeof (GstAudioChannelPosition) * channels);
+    gst_audio_channel_positions_to_valid_order (info->position, info->channels);
+  } else {
+    GST_ELEMENT_WARNING (rtpL8depay, STREAM, DECODE,
+        (NULL), ("Unknown channel order '%s' for %d channels",
+            GST_STR_NULL (channel_order), channels));
+    /* create default NONE layout */
+    gst_rtp_channels_create_default (channels, info->position);
+  }
+
+  srccaps = gst_audio_info_to_caps (info);
+  res = gst_pad_set_caps (depayload->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  return res;
+
+  /* ERRORS */
+no_clockrate:
+  {
+    GST_ERROR_OBJECT (depayload, "no clock-rate specified");
+    return FALSE;
+  }
+}
+
+static GstBuffer *
+gst_rtp_L8_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+  GstRtpL8Depay *rtpL8depay;
+  GstBuffer *outbuf;
+  gint payload_len;
+  gboolean marker;
+  GstRTPBuffer rtp = { NULL };
+
+  rtpL8depay = GST_RTP_L8_DEPAY (depayload);
+
+  gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+  payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+  if (payload_len <= 0)
+    goto empty_packet;
+
+  GST_DEBUG_OBJECT (rtpL8depay, "got payload of %d bytes", payload_len);
+
+  outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+  marker = gst_rtp_buffer_get_marker (&rtp);
+
+  if (marker) {
+    /* mark talk spurt with RESYNC */
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+  }
+
+  outbuf = gst_buffer_make_writable (outbuf);
+  if (rtpL8depay->order &&
+      !gst_audio_buffer_reorder_channels (outbuf,
+          rtpL8depay->info.finfo->format, rtpL8depay->info.channels,
+          rtpL8depay->info.position, rtpL8depay->order->pos)) {
+    goto reorder_failed;
+  }
+
+  gst_rtp_buffer_unmap (&rtp);
+
+  return outbuf;
+
+  /* ERRORS */
+empty_packet:
+  {
+    GST_ELEMENT_WARNING (rtpL8depay, STREAM, DECODE,
+        ("Empty Payload."), (NULL));
+    gst_rtp_buffer_unmap (&rtp);
+    return NULL;
+  }
+reorder_failed:
+  {
+    GST_ELEMENT_ERROR (rtpL8depay, STREAM, DECODE,
+        ("Channel reordering failed."), (NULL));
+    gst_rtp_buffer_unmap (&rtp);
+    return NULL;
+  }
+}
+
+gboolean
+gst_rtp_L8_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpL8depay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_L8_DEPAY);
+}
diff --git a/gst/rtp/gstrtpL8depay.h b/gst/rtp/gstrtpL8depay.h
new file mode 100644
index 0000000..a2d9bec
--- /dev/null
+++ b/gst/rtp/gstrtpL8depay.h
@@ -0,0 +1,65 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) <2015> GE Intelligent Platforms Embedded Systems, Inc.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_L8_DEPAY_H__
+#define __GST_RTP_L8_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpchannels.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_L8_DEPAY \
+  (gst_rtp_L8_depay_get_type())
+#define GST_RTP_L8_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_L8_DEPAY,GstRtpL8Depay))
+#define GST_RTP_L8_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_L8_DEPAY,GstRtpL8DepayClass))
+#define GST_IS_RTP_L8_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_L8_DEPAY))
+#define GST_IS_RTP_L8_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_L8_DEPAY))
+
+typedef struct _GstRtpL8Depay GstRtpL8Depay;
+typedef struct _GstRtpL8DepayClass GstRtpL8DepayClass;
+
+struct _GstRtpL8Depay
+{
+  GstRTPBaseDepayload depayload;
+
+  GstAudioInfo info;
+  const GstRTPChannelOrder *order;
+};
+
+struct _GstRtpL8DepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_L8_depay_get_type (void);
+
+gboolean gst_rtp_L8_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_L8_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpL8pay.c b/gst/rtp/gstrtpL8pay.c
new file mode 100644
index 0000000..86e7b22
--- /dev/null
+++ b/gst/rtp/gstrtpL8pay.c
@@ -0,0 +1,250 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) <2015> GE Intelligent Platforms Embedded Systems, Inc.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpL8pay
+ * @see_also: rtpL8depay
+ *
+ * Payload raw audio into RTP packets according to RFC 3551.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc3551.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch -v audiotestsrc ! audioconvert ! rtpL8pay ! udpsink
+ * ]| This example pipeline will payload raw audio. Refer to
+ * the rtpL8depay example to depayload and play the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/audio/audio.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpL8pay.h"
+#include "gstrtpchannels.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpL8pay_debug);
+#define GST_CAT_DEFAULT (rtpL8pay_debug)
+
+static GstStaticPadTemplate gst_rtp_L8_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) U8, "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+    );
+
+static GstStaticPadTemplate gst_rtp_L8_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) audio, "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) [ 1, MAX ], "
+        "encoding-name = (string) L8, " "channels = (int) [ 1, MAX ];")
+    );
+
+static gboolean gst_rtp_L8_pay_setcaps (GstRTPBasePayload * basepayload,
+    GstCaps * caps);
+static GstCaps *gst_rtp_L8_pay_getcaps (GstRTPBasePayload * rtppayload,
+    GstPad * pad, GstCaps * filter);
+static GstFlowReturn
+gst_rtp_L8_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer);
+
+#define gst_rtp_L8_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpL8Pay, gst_rtp_L8_pay, GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_L8_pay_class_init (GstRtpL8PayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_L8_pay_setcaps;
+  gstrtpbasepayload_class->get_caps = gst_rtp_L8_pay_getcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_L8_pay_handle_buffer;
+
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&gst_rtp_L8_pay_src_template));
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&gst_rtp_L8_pay_sink_template));
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP audio payloader", "Codec/Payloader/Network/RTP",
+      "Payload-encode Raw audio into RTP packets (RFC 3551)",
+      "Wim Taymans <wim.taymans@gmail.com>, "
+      "GE Intelligent Platforms Embedded Systems, Inc.");
+
+  GST_DEBUG_CATEGORY_INIT (rtpL8pay_debug, "rtpL8pay", 0, "L8 RTP Payloader");
+}
+
+static void
+gst_rtp_L8_pay_init (GstRtpL8Pay * rtpL8pay)
+{
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpL8pay);
+
+  /* tell rtpbaseaudiopayload that this is a sample based codec */
+  gst_rtp_base_audio_payload_set_sample_based (rtpbaseaudiopayload);
+}
+
+static gboolean
+gst_rtp_L8_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+  GstRtpL8Pay *rtpL8pay;
+  gboolean res;
+  gchar *params;
+  GstAudioInfo *info;
+  const GstRTPChannelOrder *order;
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (basepayload);
+  rtpL8pay = GST_RTP_L8_PAY (basepayload);
+
+  info = &rtpL8pay->info;
+  gst_audio_info_init (info);
+  if (!gst_audio_info_from_caps (info, caps))
+    goto invalid_caps;
+
+  order = gst_rtp_channels_get_by_pos (info->channels, info->position);
+  rtpL8pay->order = order;
+
+  gst_rtp_base_payload_set_options (basepayload, "audio", TRUE, "L8",
+      info->rate);
+  params = g_strdup_printf ("%d", info->channels);
+
+  if (!order && info->channels > 2) {
+    GST_ELEMENT_WARNING (rtpL8pay, STREAM, DECODE,
+        (NULL), ("Unknown channel order for %d channels", info->channels));
+  }
+
+  if (order && order->name) {
+    res = gst_rtp_base_payload_set_outcaps (basepayload,
+        "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
+        info->channels, "channel-order", G_TYPE_STRING, order->name, NULL);
+  } else {
+    res = gst_rtp_base_payload_set_outcaps (basepayload,
+        "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
+        info->channels, NULL);
+  }
+
+  g_free (params);
+
+  /* octet-per-sample is # channels for L8 */
+  gst_rtp_base_audio_payload_set_sample_options (rtpbaseaudiopayload,
+      info->channels);
+
+  return res;
+
+  /* ERRORS */
+invalid_caps:
+  {
+    GST_DEBUG_OBJECT (rtpL8pay, "invalid caps");
+    return FALSE;
+  }
+}
+
+static GstCaps *
+gst_rtp_L8_pay_getcaps (GstRTPBasePayload * rtppayload, GstPad * pad,
+    GstCaps * filter)
+{
+  GstCaps *otherpadcaps;
+  GstCaps *caps;
+
+  caps = gst_pad_get_pad_template_caps (pad);
+
+  otherpadcaps = gst_pad_get_allowed_caps (rtppayload->srcpad);
+  if (otherpadcaps) {
+    if (!gst_caps_is_empty (otherpadcaps)) {
+      GstStructure *structure;
+      gint channels;
+      gint rate;
+
+      structure = gst_caps_get_structure (otherpadcaps, 0);
+      caps = gst_caps_make_writable (caps);
+
+      if (gst_structure_get_int (structure, "channels", &channels)) {
+        gst_caps_set_simple (caps, "channels", G_TYPE_INT, channels, NULL);
+      } else {
+        /* Support any number of channels, if not explicitly specified */
+        gst_structure_remove_field (structure, "channels");
+      }
+
+      if (gst_structure_get_int (structure, "clock-rate", &rate)) {
+        gst_caps_set_simple (caps, "rate", G_TYPE_INT, rate, NULL);
+      } else {
+        /* Support any rate, if not explicitly specified */
+        gst_structure_remove_field (structure, "rate");
+      }
+
+    }
+    gst_caps_unref (otherpadcaps);
+  }
+
+  if (filter) {
+    GstCaps *tcaps = caps;
+
+    caps = gst_caps_intersect_full (filter, tcaps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (tcaps);
+  }
+
+  return caps;
+}
+
+static GstFlowReturn
+gst_rtp_L8_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpL8Pay *rtpL8pay;
+
+  rtpL8pay = GST_RTP_L8_PAY (basepayload);
+  buffer = gst_buffer_make_writable (buffer);
+
+  if (rtpL8pay->order &&
+      !gst_audio_buffer_reorder_channels (buffer, rtpL8pay->info.finfo->format,
+          rtpL8pay->info.channels, rtpL8pay->info.position,
+          rtpL8pay->order->pos)) {
+    return GST_FLOW_ERROR;
+  }
+
+  return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->handle_buffer (basepayload,
+      buffer);
+}
+
+gboolean
+gst_rtp_L8_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpL8pay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_L8_PAY);
+}
diff --git a/gst/rtp/gstrtpL8pay.h b/gst/rtp/gstrtpL8pay.h
new file mode 100644
index 0000000..183eb2f
--- /dev/null
+++ b/gst/rtp/gstrtpL8pay.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) <2015> GE Intelligent Platforms Embedded Systems, Inc.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_L8_PAY_H__
+#define __GST_RTP_L8_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+#include "gstrtpchannels.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_L8_PAY \
+  (gst_rtp_L8_pay_get_type())
+#define GST_RTP_L8_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_L8_PAY,GstRtpL8Pay))
+#define GST_RTP_L8_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_L8_PAY,GstRtpL8PayClass))
+#define GST_IS_RTP_L8_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_L8_PAY))
+#define GST_IS_RTP_L8_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_L8_PAY))
+
+typedef struct _GstRtpL8Pay GstRtpL8Pay;
+typedef struct _GstRtpL8PayClass GstRtpL8PayClass;
+
+struct _GstRtpL8Pay
+{
+  GstRTPBaseAudioPayload payload;
+
+  GstAudioInfo info;
+  const GstRTPChannelOrder *order;
+};
+
+struct _GstRtpL8PayClass
+{
+  GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_L8_pay_get_type (void);
+
+gboolean gst_rtp_L8_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_L8_PAY_H__ */
diff --git a/gst/rtp/gstrtpac3depay.c b/gst/rtp/gstrtpac3depay.c
new file mode 100644
index 0000000..ec2b3ba
--- /dev/null
+++ b/gst/rtp/gstrtpac3depay.c
@@ -0,0 +1,180 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpac3depay
+ * @see_also: rtpac3pay
+ *
+ * Extract AC3 audio from RTP packets according to RFC 4184.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc4184.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 udpsrc caps='application/x-rtp, media=(string)audio, clock-rate=(int)44100, encoding-name=(string)AC3, payload=(int)96' ! rtpac3depay ! a52dec ! pulsesink
+ * ]| This example pipeline will depayload and decode an RTP AC3 stream. Refer to
+ * the rtpac3pay example to create the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include <string.h>
+#include "gstrtpac3depay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpac3depay_debug);
+#define GST_CAT_DEFAULT (rtpac3depay_debug)
+
+static GstStaticPadTemplate gst_rtp_ac3_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/ac3")
+    );
+
+static GstStaticPadTemplate gst_rtp_ac3_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) { 32000, 44100, 48000 }, "
+        "encoding-name = (string) \"AC3\"")
+    );
+
+G_DEFINE_TYPE (GstRtpAC3Depay, gst_rtp_ac3_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_ac3_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_ac3_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+static void
+gst_rtp_ac3_depay_class_init (GstRtpAC3DepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_ac3_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_ac3_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP AC3 depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts AC3 audio from RTP packets (RFC 4184)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasedepayload_class->set_caps = gst_rtp_ac3_depay_setcaps;
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_ac3_depay_process;
+
+  GST_DEBUG_CATEGORY_INIT (rtpac3depay_debug, "rtpac3depay", 0,
+      "AC3 Audio RTP Depayloader");
+}
+
+static void
+gst_rtp_ac3_depay_init (GstRtpAC3Depay * rtpac3depay)
+{
+  /* needed because of G_DEFINE_TYPE */
+}
+
+static gboolean
+gst_rtp_ac3_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  gint clock_rate;
+  GstCaps *srccaps;
+  gboolean res;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;         /* default */
+  depayload->clock_rate = clock_rate;
+
+  srccaps = gst_caps_new_empty_simple ("audio/ac3");
+  res = gst_pad_set_caps (depayload->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  return res;
+}
+
+static GstBuffer *
+gst_rtp_ac3_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpAC3Depay *rtpac3depay;
+  GstBuffer *outbuf;
+  guint8 *payload;
+  guint16 FT, NF;
+
+  rtpac3depay = GST_RTP_AC3_DEPAY (depayload);
+
+  if (gst_rtp_buffer_get_payload_len (rtp) < 2)
+    goto empty_packet;
+
+  payload = gst_rtp_buffer_get_payload (rtp);
+
+  /* strip off header
+   *
+   *  0                   1
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |    MBZ    | FT|       NF      |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   */
+  FT = payload[0] & 0x3;
+  NF = payload[1];
+
+  GST_DEBUG_OBJECT (rtpac3depay, "FT: %d, NF: %d", FT, NF);
+
+  /* We don't bother with fragmented packets yet */
+  outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, 2, -1);
+
+  if (outbuf) {
+    gst_rtp_drop_non_audio_meta (rtpac3depay, outbuf);
+    GST_DEBUG_OBJECT (rtpac3depay, "pushing buffer of size %" G_GSIZE_FORMAT,
+        gst_buffer_get_size (outbuf));
+  }
+
+  return outbuf;
+
+  /* ERRORS */
+empty_packet:
+  {
+    GST_ELEMENT_WARNING (rtpac3depay, STREAM, DECODE,
+        ("Empty Payload."), (NULL));
+    return NULL;
+  }
+}
+
+gboolean
+gst_rtp_ac3_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpac3depay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_AC3_DEPAY);
+}
diff --git a/gst/rtp/gstrtpac3depay.h b/gst/rtp/gstrtpac3depay.h
new file mode 100644
index 0000000..294bb12
--- /dev/null
+++ b/gst/rtp/gstrtpac3depay.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_AC3_DEPAY_H__
+#define __GST_RTP_AC3_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_AC3_DEPAY \
+  (gst_rtp_ac3_depay_get_type())
+#define GST_RTP_AC3_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_AC3_DEPAY,GstRtpAC3Depay))
+#define GST_RTP_AC3_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_AC3_DEPAY,GstRtpAC3DepayClass))
+#define GST_IS_RTP_AC3_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_AC3_DEPAY))
+#define GST_IS_RTP_AC3_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_AC3_DEPAY))
+
+typedef struct _GstRtpAC3Depay GstRtpAC3Depay;
+typedef struct _GstRtpAC3DepayClass GstRtpAC3DepayClass;
+
+struct _GstRtpAC3Depay
+{
+  GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpAC3DepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_ac3_depay_get_type (void);
+
+gboolean gst_rtp_ac3_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_AC3_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpac3pay.c b/gst/rtp/gstrtpac3pay.c
new file mode 100644
index 0000000..57020dc
--- /dev/null
+++ b/gst/rtp/gstrtpac3pay.c
@@ -0,0 +1,477 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpac3pay
+ * @see_also: rtpac3depay
+ *
+ * Payload AC3 audio into RTP packets according to RFC 4184.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc4184.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! avenc_ac3 ! rtpac3pay ! udpsink
+ * ]| This example pipeline will encode and payload AC3 stream. Refer to
+ * the rtpac3depay example to depayload and decode the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpac3pay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpac3pay_debug);
+#define GST_CAT_DEFAULT (rtpac3pay_debug)
+
+static GstStaticPadTemplate gst_rtp_ac3_pay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/ac3; " "audio/x-ac3; ")
+    );
+
+static GstStaticPadTemplate gst_rtp_ac3_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) { 32000, 44100, 48000 }, "
+        "encoding-name = (string) \"AC3\"")
+    );
+
+static void gst_rtp_ac3_pay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_ac3_pay_change_state (GstElement * element,
+    GstStateChange transition);
+
+static gboolean gst_rtp_ac3_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static gboolean gst_rtp_ac3_pay_sink_event (GstRTPBasePayload * payload,
+    GstEvent * event);
+static GstFlowReturn gst_rtp_ac3_pay_flush (GstRtpAC3Pay * rtpac3pay);
+static GstFlowReturn gst_rtp_ac3_pay_handle_buffer (GstRTPBasePayload * payload,
+    GstBuffer * buffer);
+
+#define gst_rtp_ac3_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpAC3Pay, gst_rtp_ac3_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_ac3_pay_class_init (GstRtpAC3PayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpac3pay_debug, "rtpac3pay", 0,
+      "AC3 Audio RTP Depayloader");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_ac3_pay_finalize;
+
+  gstelement_class->change_state = gst_rtp_ac3_pay_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_ac3_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_ac3_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP AC3 audio payloader", "Codec/Payloader/Network/RTP",
+      "Payload AC3 audio as RTP packets (RFC 4184)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_ac3_pay_setcaps;
+  gstrtpbasepayload_class->sink_event = gst_rtp_ac3_pay_sink_event;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_ac3_pay_handle_buffer;
+}
+
+static void
+gst_rtp_ac3_pay_init (GstRtpAC3Pay * rtpac3pay)
+{
+  rtpac3pay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_ac3_pay_finalize (GObject * object)
+{
+  GstRtpAC3Pay *rtpac3pay;
+
+  rtpac3pay = GST_RTP_AC3_PAY (object);
+
+  g_object_unref (rtpac3pay->adapter);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_ac3_pay_reset (GstRtpAC3Pay * pay)
+{
+  pay->first_ts = -1;
+  pay->duration = 0;
+  gst_adapter_clear (pay->adapter);
+  GST_DEBUG_OBJECT (pay, "reset depayloader");
+}
+
+static gboolean
+gst_rtp_ac3_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  gboolean res;
+  gint rate;
+  GstStructure *structure;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "rate", &rate))
+    rate = 90000;               /* default */
+
+  gst_rtp_base_payload_set_options (payload, "audio", TRUE, "AC3", rate);
+  res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+  return res;
+}
+
+static gboolean
+gst_rtp_ac3_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+  gboolean res;
+  GstRtpAC3Pay *rtpac3pay;
+
+  rtpac3pay = GST_RTP_AC3_PAY (payload);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+      /* make sure we push the last packets in the adapter on EOS */
+      gst_rtp_ac3_pay_flush (rtpac3pay);
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      gst_rtp_ac3_pay_reset (rtpac3pay);
+      break;
+    default:
+      break;
+  }
+
+  res = GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+
+  return res;
+}
+
+struct frmsize_s
+{
+  guint16 bit_rate;
+  guint16 frm_size[3];
+};
+
+static const struct frmsize_s frmsizecod_tbl[] = {
+  {32, {64, 69, 96}},
+  {32, {64, 70, 96}},
+  {40, {80, 87, 120}},
+  {40, {80, 88, 120}},
+  {48, {96, 104, 144}},
+  {48, {96, 105, 144}},
+  {56, {112, 121, 168}},
+  {56, {112, 122, 168}},
+  {64, {128, 139, 192}},
+  {64, {128, 140, 192}},
+  {80, {160, 174, 240}},
+  {80, {160, 175, 240}},
+  {96, {192, 208, 288}},
+  {96, {192, 209, 288}},
+  {112, {224, 243, 336}},
+  {112, {224, 244, 336}},
+  {128, {256, 278, 384}},
+  {128, {256, 279, 384}},
+  {160, {320, 348, 480}},
+  {160, {320, 349, 480}},
+  {192, {384, 417, 576}},
+  {192, {384, 418, 576}},
+  {224, {448, 487, 672}},
+  {224, {448, 488, 672}},
+  {256, {512, 557, 768}},
+  {256, {512, 558, 768}},
+  {320, {640, 696, 960}},
+  {320, {640, 697, 960}},
+  {384, {768, 835, 1152}},
+  {384, {768, 836, 1152}},
+  {448, {896, 975, 1344}},
+  {448, {896, 976, 1344}},
+  {512, {1024, 1114, 1536}},
+  {512, {1024, 1115, 1536}},
+  {576, {1152, 1253, 1728}},
+  {576, {1152, 1254, 1728}},
+  {640, {1280, 1393, 1920}},
+  {640, {1280, 1394, 1920}}
+};
+
+static GstFlowReturn
+gst_rtp_ac3_pay_flush (GstRtpAC3Pay * rtpac3pay)
+{
+  guint avail, FT, NF, mtu;
+  GstBuffer *outbuf;
+  GstFlowReturn ret;
+
+  /* the data available in the adapter is either smaller
+   * than the MTU or bigger. In the case it is smaller, the complete
+   * adapter contents can be put in one packet. In the case the
+   * adapter has more than one MTU, we need to split the AC3 data
+   * over multiple packets. */
+  avail = gst_adapter_available (rtpac3pay->adapter);
+
+  ret = GST_FLOW_OK;
+
+  FT = 0;
+  /* number of frames */
+  NF = rtpac3pay->NF;
+
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpac3pay);
+
+  GST_LOG_OBJECT (rtpac3pay, "flushing %u bytes", avail);
+
+  while (avail > 0) {
+    guint towrite;
+    guint8 *payload;
+    guint payload_len;
+    guint packet_len;
+    GstRTPBuffer rtp = { NULL, };
+    GstBuffer *payload_buffer;
+
+    /* this will be the total length of the packet */
+    packet_len = gst_rtp_buffer_calc_packet_len (2 + avail, 0, 0);
+
+    /* fill one MTU or all available bytes */
+    towrite = MIN (packet_len, mtu);
+
+    /* this is the payload length */
+    payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+
+    /* create buffer to hold the payload */
+    outbuf = gst_rtp_buffer_new_allocate (2, 0, 0);
+
+    if (FT == 0) {
+      /* check if it all fits */
+      if (towrite < packet_len) {
+        guint maxlen;
+
+        GST_LOG_OBJECT (rtpac3pay, "we need to fragment");
+        /* check if we will be able to put at least 5/8th of the total
+         * frame in this first frame. */
+        if ((avail * 5) / 8 >= (payload_len - 2))
+          FT = 1;
+        else
+          FT = 2;
+        /* check how many fragments we will need */
+        maxlen = gst_rtp_buffer_calc_payload_len (mtu - 2, 0, 0);
+        NF = (avail + maxlen - 1) / maxlen;
+      }
+    } else if (FT != 3) {
+      /* remaining fragment */
+      FT = 3;
+    }
+
+    /*
+     *  0                   1
+     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * |    MBZ    | FT|       NF      |
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     *
+     * FT: 0: one or more complete frames
+     *     1: initial 5/8 fragment
+     *     2: initial fragment not 5/8
+     *     3: other fragment
+     * NF: amount of frames if FT = 0, else number of fragments.
+     */
+    gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+    GST_LOG_OBJECT (rtpac3pay, "FT %u, NF %u", FT, NF);
+    payload = gst_rtp_buffer_get_payload (&rtp);
+    payload[0] = (FT & 3);
+    payload[1] = NF;
+    payload_len -= 2;
+
+    if (avail == payload_len)
+      gst_rtp_buffer_set_marker (&rtp, TRUE);
+    gst_rtp_buffer_unmap (&rtp);
+
+    payload_buffer =
+        gst_adapter_take_buffer_fast (rtpac3pay->adapter, payload_len);
+
+    gst_rtp_copy_audio_meta (rtpac3pay, outbuf, payload_buffer);
+
+    outbuf = gst_buffer_append (outbuf, payload_buffer);
+
+    avail -= payload_len;
+
+    GST_BUFFER_PTS (outbuf) = rtpac3pay->first_ts;
+    GST_BUFFER_DURATION (outbuf) = rtpac3pay->duration;
+
+    ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpac3pay), outbuf);
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_rtp_ac3_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpAC3Pay *rtpac3pay;
+  GstFlowReturn ret;
+  gsize avail, left, NF;
+  GstMapInfo map;
+  guint8 *p;
+  guint packet_len;
+  GstClockTime duration, timestamp;
+
+  rtpac3pay = GST_RTP_AC3_PAY (basepayload);
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  duration = GST_BUFFER_DURATION (buffer);
+  timestamp = GST_BUFFER_PTS (buffer);
+
+  if (GST_BUFFER_IS_DISCONT (buffer)) {
+    GST_DEBUG_OBJECT (rtpac3pay, "DISCONT");
+    gst_rtp_ac3_pay_reset (rtpac3pay);
+  }
+
+  /* count the amount of incomming packets */
+  NF = 0;
+  left = map.size;
+  p = map.data;
+  while (TRUE) {
+    guint bsid, fscod, frmsizecod, frame_size;
+
+    if (left < 6)
+      break;
+
+    if (p[0] != 0x0b || p[1] != 0x77)
+      break;
+
+    bsid = p[5] >> 3;
+    if (bsid > 8)
+      break;
+
+    frmsizecod = p[4] & 0x3f;
+    fscod = p[4] >> 6;
+
+    GST_DEBUG_OBJECT (rtpac3pay, "fscod %u, %u", fscod, frmsizecod);
+
+    if (fscod >= 3 || frmsizecod >= 38)
+      break;
+
+    frame_size = frmsizecod_tbl[frmsizecod].frm_size[fscod] * 2;
+    if (frame_size > left)
+      break;
+
+    NF++;
+    GST_DEBUG_OBJECT (rtpac3pay, "found frame %" G_GSIZE_FORMAT " of size %u",
+        NF, frame_size);
+
+    p += frame_size;
+    left -= frame_size;
+  }
+  gst_buffer_unmap (buffer, &map);
+  if (NF == 0)
+    goto no_frames;
+
+  avail = gst_adapter_available (rtpac3pay->adapter);
+
+  /* get packet length of previous data and this new data,
+   * payload length includes a 4 byte header */
+  packet_len = gst_rtp_buffer_calc_packet_len (2 + avail + map.size, 0, 0);
+
+  /* if this buffer is going to overflow the packet, flush what we
+   * have. */
+  if (gst_rtp_base_payload_is_filled (basepayload,
+          packet_len, rtpac3pay->duration + duration)) {
+    ret = gst_rtp_ac3_pay_flush (rtpac3pay);
+    avail = 0;
+  } else {
+    ret = GST_FLOW_OK;
+  }
+
+  if (avail == 0) {
+    GST_DEBUG_OBJECT (rtpac3pay,
+        "first packet, save timestamp %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (timestamp));
+    rtpac3pay->first_ts = timestamp;
+    rtpac3pay->duration = 0;
+    rtpac3pay->NF = 0;
+  }
+
+  gst_adapter_push (rtpac3pay->adapter, buffer);
+  rtpac3pay->duration += duration;
+  rtpac3pay->NF += NF;
+
+  return ret;
+
+  /* ERRORS */
+no_frames:
+  {
+    GST_WARNING_OBJECT (rtpac3pay, "no valid AC3 frames found");
+    return GST_FLOW_OK;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_ac3_pay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRtpAC3Pay *rtpac3pay;
+  GstStateChangeReturn ret;
+
+  rtpac3pay = GST_RTP_AC3_PAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_ac3_pay_reset (rtpac3pay);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_ac3_pay_reset (rtpac3pay);
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_ac3_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpac3pay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_AC3_PAY);
+}
diff --git a/gst/rtp/gstrtpac3pay.h b/gst/rtp/gstrtpac3pay.h
new file mode 100644
index 0000000..c131eac
--- /dev/null
+++ b/gst/rtp/gstrtpac3pay.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_AC3_PAY_H__
+#define __GST_RTP_AC3_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_AC3_PAY \
+  (gst_rtp_ac3_pay_get_type())
+#define GST_RTP_AC3_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_AC3_PAY,GstRtpAC3Pay))
+#define GST_RTP_AC3_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_AC3_PAY,GstRtpAC3PayClass))
+#define GST_IS_RTP_AC3_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_AC3_PAY))
+#define GST_IS_RTP_AC3_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_AC3_PAY))
+
+typedef struct _GstRtpAC3Pay GstRtpAC3Pay;
+typedef struct _GstRtpAC3PayClass GstRtpAC3PayClass;
+
+struct _GstRtpAC3Pay
+{
+  GstRTPBasePayload payload;
+
+  GstAdapter *adapter;
+  GstClockTime first_ts;
+  GstClockTime duration;
+  guint NF;
+};
+
+struct _GstRtpAC3PayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_ac3_pay_get_type (void);
+
+gboolean gst_rtp_ac3_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_AC3_PAY_H__ */
diff --git a/gst/rtp/gstrtpamrdepay.c b/gst/rtp/gstrtpamrdepay.c
new file mode 100644
index 0000000..7a7c797
--- /dev/null
+++ b/gst/rtp/gstrtpamrdepay.c
@@ -0,0 +1,478 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpamrdepay
+ * @see_also: rtpamrpay
+ *
+ * Extract AMR audio from RTP packets according to RFC 3267.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc3267.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 udpsrc caps='application/x-rtp, media=(string)audio, clock-rate=(int)8000, encoding-name=(string)AMR, encoding-params=(string)1, octet-align=(string)1, payload=(int)96' ! rtpamrdepay ! amrnbdec ! pulsesink
+ * ]| This example pipeline will depayload and decode an RTP AMR stream. Refer to
+ * the rtpamrpay example to create the RTP stream.
+ * </refsect2>
+ */
+
+/*
+ * RFC 3267 - Real-Time Transport Protocol (RTP) Payload Format and File
+ * Storage Format for the Adaptive Multi-Rate (AMR) and Adaptive Multi-Rate
+ * Wideband (AMR-WB) Audio Codecs.
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include "gstrtpamrdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpamrdepay_debug);
+#define GST_CAT_DEFAULT (rtpamrdepay_debug)
+
+/* RtpAMRDepay signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0
+};
+
+/* input is an RTP packet
+ *
+ * params see RFC 3267, section 8.1
+ */
+static GstStaticPadTemplate gst_rtp_amr_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) 8000, " "encoding-name = (string) \"AMR\", "
+        /* This is the default, so the peer doesn't have to specify it
+         * "encoding-params = (string) \"1\", " */
+        /* NOTE that all values must be strings in orde to be able to do SDP <->
+         * GstCaps mapping. */
+        "octet-align = (string) \"1\";"
+        /* following options are not needed for a decoder
+         *
+         "crc = (string) { \"0\", \"1\" }, "
+         "robust-sorting = (string) \"0\", "
+         "interleaving = (string) \"0\";"
+         "mode-set = (int) [ 0, 7 ], "
+         "mode-change-period = (int) [ 1, MAX ], "
+         "mode-change-neighbor = (boolean) { TRUE, FALSE }, "
+         "maxptime = (int) [ 20, MAX ], "
+         "ptime = (int) [ 20, MAX ]"
+         */
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) 16000, " "encoding-name = (string) \"AMR-WB\", "
+        /* This is the default, so the peer doesn't have to specify it
+         * "encoding-params = (string) \"1\", " */
+        /* NOTE that all values must be strings in orde to be able to do SDP <->
+         * GstCaps mapping. */
+        "octet-align = (string) \"1\";"
+        /* following options are not needed for a decoder
+         *
+         "crc = (string) { \"0\", \"1\" }, "
+         "robust-sorting = (string) \"0\", "
+         "interleaving = (string) \"0\""
+         "mode-set = (int) [ 0, 7 ], "
+         "mode-change-period = (int) [ 1, MAX ], "
+         "mode-change-neighbor = (boolean) { TRUE, FALSE }, "
+         "maxptime = (int) [ 20, MAX ], "
+         "ptime = (int) [ 20, MAX ]"
+         */
+    )
+    );
+
+static GstStaticPadTemplate gst_rtp_amr_depay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/AMR, " "channels = (int) 1," "rate = (int) 8000;"
+        "audio/AMR-WB, " "channels = (int) 1," "rate = (int) 16000")
+    );
+
+static gboolean gst_rtp_amr_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_amr_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+#define gst_rtp_amr_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpAMRDepay, gst_rtp_amr_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_amr_depay_class_init (GstRtpAMRDepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_amr_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_amr_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP AMR depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts AMR or AMR-WB audio from RTP packets (RFC 3267)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_amr_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_amr_depay_setcaps;
+
+  GST_DEBUG_CATEGORY_INIT (rtpamrdepay_debug, "rtpamrdepay", 0,
+      "AMR/AMR-WB RTP Depayloader");
+}
+
+static void
+gst_rtp_amr_depay_init (GstRtpAMRDepay * rtpamrdepay)
+{
+  GstRTPBaseDepayload *depayload;
+
+  depayload = GST_RTP_BASE_DEPAYLOAD (rtpamrdepay);
+
+  gst_pad_use_fixed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload));
+}
+
+static gboolean
+gst_rtp_amr_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstCaps *srccaps;
+  GstRtpAMRDepay *rtpamrdepay;
+  const gchar *params;
+  const gchar *str, *type;
+  gint clock_rate, need_clock_rate;
+  gboolean res;
+
+  rtpamrdepay = GST_RTP_AMR_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  /* figure out the mode first and set the clock rates */
+  if ((str = gst_structure_get_string (structure, "encoding-name"))) {
+    if (strcmp (str, "AMR") == 0) {
+      rtpamrdepay->mode = GST_RTP_AMR_DP_MODE_NB;
+      need_clock_rate = 8000;
+      type = "audio/AMR";
+    } else if (strcmp (str, "AMR-WB") == 0) {
+      rtpamrdepay->mode = GST_RTP_AMR_DP_MODE_WB;
+      need_clock_rate = 16000;
+      type = "audio/AMR-WB";
+    } else
+      goto invalid_mode;
+  } else
+    goto invalid_mode;
+
+  if (!(str = gst_structure_get_string (structure, "octet-align")))
+    rtpamrdepay->octet_align = FALSE;
+  else
+    rtpamrdepay->octet_align = (atoi (str) == 1);
+
+  if (!(str = gst_structure_get_string (structure, "crc")))
+    rtpamrdepay->crc = FALSE;
+  else
+    rtpamrdepay->crc = (atoi (str) == 1);
+
+  if (rtpamrdepay->crc) {
+    /* crc mode implies octet aligned mode */
+    rtpamrdepay->octet_align = TRUE;
+  }
+
+  if (!(str = gst_structure_get_string (structure, "robust-sorting")))
+    rtpamrdepay->robust_sorting = FALSE;
+  else
+    rtpamrdepay->robust_sorting = (atoi (str) == 1);
+
+  if (rtpamrdepay->robust_sorting) {
+    /* robust_sorting mode implies octet aligned mode */
+    rtpamrdepay->octet_align = TRUE;
+  }
+
+  if (!(str = gst_structure_get_string (structure, "interleaving")))
+    rtpamrdepay->interleaving = FALSE;
+  else
+    rtpamrdepay->interleaving = (atoi (str) == 1);
+
+  if (rtpamrdepay->interleaving) {
+    /* interleaving mode implies octet aligned mode */
+    rtpamrdepay->octet_align = TRUE;
+  }
+
+  if (!(params = gst_structure_get_string (structure, "encoding-params")))
+    rtpamrdepay->channels = 1;
+  else {
+    rtpamrdepay->channels = atoi (params);
+  }
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = need_clock_rate;
+  depayload->clock_rate = clock_rate;
+
+  /* we require 1 channel, 8000 Hz, octet aligned, no CRC,
+   * no robust sorting, no interleaving for now */
+  if (rtpamrdepay->channels != 1)
+    return FALSE;
+  if (clock_rate != need_clock_rate)
+    return FALSE;
+  if (rtpamrdepay->octet_align != TRUE)
+    return FALSE;
+  if (rtpamrdepay->robust_sorting != FALSE)
+    return FALSE;
+  if (rtpamrdepay->interleaving != FALSE)
+    return FALSE;
+
+  srccaps = gst_caps_new_simple (type,
+      "channels", G_TYPE_INT, rtpamrdepay->channels,
+      "rate", G_TYPE_INT, clock_rate, NULL);
+  res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+  gst_caps_unref (srccaps);
+
+  return res;
+
+  /* ERRORS */
+invalid_mode:
+  {
+    GST_ERROR_OBJECT (rtpamrdepay, "invalid encoding-name");
+    return FALSE;
+  }
+}
+
+/* -1 is invalid */
+static const gint nb_frame_size[16] = {
+  12, 13, 15, 17, 19, 20, 26, 31,
+  5, -1, -1, -1, -1, -1, -1, 0
+};
+
+static const gint wb_frame_size[16] = {
+  17, 23, 32, 36, 40, 46, 50, 58,
+  60, 5, -1, -1, -1, -1, -1, 0
+};
+
+static GstBuffer *
+gst_rtp_amr_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpAMRDepay *rtpamrdepay;
+  const gint *frame_size;
+  GstBuffer *outbuf = NULL;
+  gint payload_len;
+  GstMapInfo map;
+
+  rtpamrdepay = GST_RTP_AMR_DEPAY (depayload);
+
+  /* setup frame size pointer */
+  if (rtpamrdepay->mode == GST_RTP_AMR_DP_MODE_NB)
+    frame_size = nb_frame_size;
+  else
+    frame_size = wb_frame_size;
+
+  /* when we get here, 1 channel, 8000/16000 Hz, octet aligned, no CRC,
+   * no robust sorting, no interleaving data is to be depayloaded */
+  {
+    guint8 *payload, *p, *dp;
+    gint i, num_packets, num_nonempty_packets;
+    gint amr_len;
+    gint ILL, ILP;
+
+    payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+    /* need at least 2 bytes for the header */
+    if (payload_len < 2)
+      goto too_small;
+
+    payload = gst_rtp_buffer_get_payload (rtp);
+
+    /* depay CMR. The CMR is used by the sender to request
+     * a new encoding mode.
+     *
+     *  0 1 2 3 4 5 6 7
+     * +-+-+-+-+-+-+-+-+
+     * | CMR   |R|R|R|R|
+     * +-+-+-+-+-+-+-+-+
+     */
+    /* CMR = (payload[0] & 0xf0) >> 4; */
+
+    /* strip CMR header now, pack FT and the data for the decoder */
+    payload_len -= 1;
+    payload += 1;
+
+    GST_DEBUG_OBJECT (rtpamrdepay, "payload len %d", payload_len);
+
+    if (rtpamrdepay->interleaving) {
+      ILL = (payload[0] & 0xf0) >> 4;
+      ILP = (payload[0] & 0x0f);
+
+      payload_len -= 1;
+      payload += 1;
+
+      if (ILP > ILL)
+        goto wrong_interleaving;
+    }
+
+    /*
+     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
+     * +-+-+-+-+-+-+-+-+..
+     * |F|  FT   |Q|P|P| more FT..
+     * +-+-+-+-+-+-+-+-+..
+     */
+    /* count number of packets by counting the FTs. Also
+     * count number of amr data bytes and number of non-empty
+     * packets (this is also the number of CRCs if present). */
+    amr_len = 0;
+    num_nonempty_packets = 0;
+    num_packets = 0;
+    for (i = 0; i < payload_len; i++) {
+      gint fr_size;
+      guint8 FT;
+
+      FT = (payload[i] & 0x78) >> 3;
+
+      fr_size = frame_size[FT];
+      GST_DEBUG_OBJECT (rtpamrdepay, "frame size %d", fr_size);
+      if (fr_size == -1)
+        goto wrong_framesize;
+
+      if (fr_size > 0) {
+        amr_len += fr_size;
+        num_nonempty_packets++;
+      }
+      num_packets++;
+
+      if ((payload[i] & 0x80) == 0)
+        break;
+    }
+
+    if (rtpamrdepay->crc) {
+      /* data len + CRC len + header bytes should be smaller than payload_len */
+      if (num_packets + num_nonempty_packets + amr_len > payload_len)
+        goto wrong_length_1;
+    } else {
+      /* data len + header bytes should be smaller than payload_len */
+      if (num_packets + amr_len > payload_len)
+        goto wrong_length_2;
+    }
+
+    outbuf = gst_buffer_new_and_alloc (payload_len);
+
+    /* point to destination */
+    gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+
+    /* point to first data packet */
+    p = map.data;
+    dp = payload + num_packets;
+    if (rtpamrdepay->crc) {
+      /* skip CRC if present */
+      dp += num_nonempty_packets;
+    }
+
+    for (i = 0; i < num_packets; i++) {
+      gint fr_size;
+
+      /* copy FT, clear F bit */
+      *p++ = payload[i] & 0x7f;
+
+      fr_size = frame_size[(payload[i] & 0x78) >> 3];
+      if (fr_size > 0) {
+        /* copy data packet, FIXME, calc CRC here. */
+        memcpy (p, dp, fr_size);
+
+        p += fr_size;
+        dp += fr_size;
+      }
+    }
+    gst_buffer_unmap (outbuf, &map);
+
+    /* we can set the duration because each packet is 20 milliseconds */
+    GST_BUFFER_DURATION (outbuf) = num_packets * 20 * GST_MSECOND;
+
+    if (gst_rtp_buffer_get_marker (rtp)) {
+      /* marker bit marks a buffer after a talkspurt. */
+      GST_DEBUG_OBJECT (depayload, "marker bit was set");
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+    }
+
+    GST_DEBUG_OBJECT (depayload, "pushing buffer of size %" G_GSIZE_FORMAT,
+        gst_buffer_get_size (outbuf));
+
+    gst_rtp_copy_audio_meta (rtpamrdepay, outbuf, rtp->buffer);
+  }
+
+  return outbuf;
+
+  /* ERRORS */
+too_small:
+  {
+    GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
+        (NULL), ("AMR RTP payload too small (%d)", payload_len));
+    goto bad_packet;
+  }
+wrong_interleaving:
+  {
+    GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
+        (NULL), ("AMR RTP wrong interleaving"));
+    goto bad_packet;
+  }
+wrong_framesize:
+  {
+    GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
+        (NULL), ("AMR RTP frame size == -1"));
+    goto bad_packet;
+  }
+wrong_length_1:
+  {
+    GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
+        (NULL), ("AMR RTP wrong length 1"));
+    goto bad_packet;
+  }
+wrong_length_2:
+  {
+    GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
+        (NULL), ("AMR RTP wrong length 2"));
+    goto bad_packet;
+  }
+bad_packet:
+  {
+    /* no fatal error */
+    return NULL;
+  }
+}
+
+gboolean
+gst_rtp_amr_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpamrdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_AMR_DEPAY);
+}
diff --git a/gst/rtp/gstrtpamrdepay.h b/gst/rtp/gstrtpamrdepay.h
new file mode 100644
index 0000000..0b80634
--- /dev/null
+++ b/gst/rtp/gstrtpamrdepay.h
@@ -0,0 +1,77 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_AMR_DEPAY_H__
+#define __GST_RTP_AMR_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_AMR_DEPAY \
+  (gst_rtp_amr_depay_get_type())
+#define GST_RTP_AMR_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_AMR_DEPAY,GstRtpAMRDepay))
+#define GST_RTP_AMR_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_AMR_DEPAY,GstRtpAMRDepayClass))
+#define GST_IS_RTP_AMR_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_AMR_DEPAY))
+#define GST_IS_RTP_AMR_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_AMR_DEPAY))
+
+typedef struct _GstRtpAMRDepay GstRtpAMRDepay;
+typedef struct _GstRtpAMRDepayClass GstRtpAMRDepayClass;
+
+typedef enum {
+  GST_RTP_AMR_DP_MODE_INVALID = 0,
+  GST_RTP_AMR_DP_MODE_NB      = 1,
+  GST_RTP_AMR_DP_MODE_WB      = 2
+} GstRtpAMRDepayMode;
+
+struct _GstRtpAMRDepay
+{
+  GstRTPBaseDepayload depayload;
+
+  GstRtpAMRDepayMode mode;
+
+  gboolean octet_align;
+  guint8   mode_set;
+  gint     mode_change_period;
+  gboolean mode_change_neighbor;
+  gint     maxptime;
+  gboolean crc;
+  gboolean robust_sorting;
+  gboolean interleaving;
+  gint     ptime;
+  gint     channels;
+};
+
+struct _GstRtpAMRDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_amr_depay_get_type (void);
+
+gboolean gst_rtp_amr_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_AMR_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpamrpay.c b/gst/rtp/gstrtpamrpay.c
new file mode 100644
index 0000000..5e70f0a
--- /dev/null
+++ b/gst/rtp/gstrtpamrpay.c
@@ -0,0 +1,463 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpamrpay
+ * @see_also: rtpamrdepay
+ *
+ * Payload AMR audio into RTP packets according to RFC 3267.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc3267.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! amrnbenc ! rtpamrpay ! udpsink
+ * ]| This example pipeline will encode and payload an AMR stream. Refer to
+ * the rtpamrdepay example to depayload and decode the RTP stream.
+ * </refsect2>
+ */
+
+/* references:
+ *
+ * RFC 3267 - Real-Time Transport Protocol (RTP) Payload Format and File
+ *    Storage Format for the Adaptive Multi-Rate (AMR) and Adaptive
+ *    Multi-Rate Wideband (AMR-WB) Audio Codecs.
+ *
+ * ETSI TS 126 201 V6.0.0 (2004-12) - Digital cellular telecommunications system (Phase 2+);
+ *                 Universal Mobile Telecommunications System (UMTS);
+ *                          AMR speech codec, wideband;
+ *                                 Frame structure
+ *                    (3GPP TS 26.201 version 6.0.0 Release 6)
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpamrpay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpamrpay_debug);
+#define GST_CAT_DEFAULT (rtpamrpay_debug)
+
+static GstStaticPadTemplate gst_rtp_amr_pay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/AMR, channels=(int)1, rate=(int)8000; "
+        "audio/AMR-WB, channels=(int)1, rate=(int)16000")
+    );
+
+static GstStaticPadTemplate gst_rtp_amr_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 8000, "
+        "encoding-name = (string) \"AMR\", "
+        "encoding-params = (string) \"1\", "
+        "octet-align = (string) \"1\", "
+        "crc = (string) \"0\", "
+        "robust-sorting = (string) \"0\", "
+        "interleaving = (string) \"0\", "
+        "mode-set = (int) [ 0, 7 ], "
+        "mode-change-period = (int) [ 1, MAX ], "
+        "mode-change-neighbor = (string) { \"0\", \"1\" }, "
+        "maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ];"
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 16000, "
+        "encoding-name = (string) \"AMR-WB\", "
+        "encoding-params = (string) \"1\", "
+        "octet-align = (string) \"1\", "
+        "crc = (string) \"0\", "
+        "robust-sorting = (string) \"0\", "
+        "interleaving = (string) \"0\", "
+        "mode-set = (int) [ 0, 7 ], "
+        "mode-change-period = (int) [ 1, MAX ], "
+        "mode-change-neighbor = (string) { \"0\", \"1\" }, "
+        "maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ]")
+    );
+
+static gboolean gst_rtp_amr_pay_setcaps (GstRTPBasePayload * basepayload,
+    GstCaps * caps);
+static GstFlowReturn gst_rtp_amr_pay_handle_buffer (GstRTPBasePayload * pad,
+    GstBuffer * buffer);
+
+static GstStateChangeReturn
+gst_rtp_amr_pay_change_state (GstElement * element, GstStateChange transition);
+
+#define gst_rtp_amr_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpAMRPay, gst_rtp_amr_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_amr_pay_class_init (GstRtpAMRPayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gstelement_class->change_state = gst_rtp_amr_pay_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_amr_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_amr_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP AMR payloader",
+      "Codec/Payloader/Network/RTP",
+      "Payload-encode AMR or AMR-WB audio into RTP packets (RFC 3267)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_amr_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_amr_pay_handle_buffer;
+
+  GST_DEBUG_CATEGORY_INIT (rtpamrpay_debug, "rtpamrpay", 0,
+      "AMR/AMR-WB RTP Payloader");
+}
+
+static void
+gst_rtp_amr_pay_init (GstRtpAMRPay * rtpamrpay)
+{
+}
+
+static void
+gst_rtp_amr_pay_reset (GstRtpAMRPay * pay)
+{
+  pay->next_rtp_time = 0;
+  pay->first_ts = GST_CLOCK_TIME_NONE;
+  pay->first_rtp_time = 0;
+}
+
+static gboolean
+gst_rtp_amr_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+  GstRtpAMRPay *rtpamrpay;
+  gboolean res;
+  const GstStructure *s;
+  const gchar *str;
+
+  rtpamrpay = GST_RTP_AMR_PAY (basepayload);
+
+  /* figure out the mode Narrow or Wideband */
+  s = gst_caps_get_structure (caps, 0);
+  if ((str = gst_structure_get_name (s))) {
+    if (strcmp (str, "audio/AMR") == 0)
+      rtpamrpay->mode = GST_RTP_AMR_P_MODE_NB;
+    else if (strcmp (str, "audio/AMR-WB") == 0)
+      rtpamrpay->mode = GST_RTP_AMR_P_MODE_WB;
+    else
+      goto wrong_type;
+  } else
+    goto wrong_type;
+
+  if (rtpamrpay->mode == GST_RTP_AMR_P_MODE_NB)
+    gst_rtp_base_payload_set_options (basepayload, "audio", TRUE, "AMR", 8000);
+  else
+    gst_rtp_base_payload_set_options (basepayload, "audio", TRUE, "AMR-WB",
+        16000);
+
+  res = gst_rtp_base_payload_set_outcaps (basepayload,
+      "encoding-params", G_TYPE_STRING, "1", "octet-align", G_TYPE_STRING, "1",
+      /* don't set the defaults
+       *
+       * "crc", G_TYPE_STRING, "0",
+       * "robust-sorting", G_TYPE_STRING, "0",
+       * "interleaving", G_TYPE_STRING, "0",
+       */
+      NULL);
+
+  return res;
+
+  /* ERRORS */
+wrong_type:
+  {
+    GST_ERROR_OBJECT (rtpamrpay, "unsupported media type '%s'",
+        GST_STR_NULL (str));
+    return FALSE;
+  }
+}
+
+static void
+gst_rtp_amr_pay_recalc_rtp_time (GstRtpAMRPay * rtpamrpay,
+    GstClockTime timestamp)
+{
+  /* re-sync rtp time */
+  if (GST_CLOCK_TIME_IS_VALID (rtpamrpay->first_ts) &&
+      GST_CLOCK_TIME_IS_VALID (timestamp) && timestamp >= rtpamrpay->first_ts) {
+    GstClockTime diff;
+    guint32 rtpdiff;
+
+    /* interpolate to reproduce gap from start, rather than intermediate
+     * intervals to avoid roundup accumulation errors */
+    diff = timestamp - rtpamrpay->first_ts;
+    rtpdiff = ((diff / GST_MSECOND) * 8) <<
+        (rtpamrpay->mode == GST_RTP_AMR_P_MODE_WB);
+    rtpamrpay->next_rtp_time = rtpamrpay->first_rtp_time + rtpdiff;
+    GST_DEBUG_OBJECT (rtpamrpay,
+        "elapsed time %" GST_TIME_FORMAT ", rtp %" G_GUINT32_FORMAT ", "
+        "new offset %" G_GUINT32_FORMAT, GST_TIME_ARGS (diff), rtpdiff,
+        rtpamrpay->next_rtp_time);
+  }
+}
+
+/* -1 is invalid */
+static const gint nb_frame_size[16] = {
+  12, 13, 15, 17, 19, 20, 26, 31,
+  5, -1, -1, -1, -1, -1, -1, 0
+};
+
+static const gint wb_frame_size[16] = {
+  17, 23, 32, 36, 40, 46, 50, 58,
+  60, 5, -1, -1, -1, -1, -1, 0
+};
+
+static GstFlowReturn
+gst_rtp_amr_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpAMRPay *rtpamrpay;
+  const gint *frame_size;
+  GstFlowReturn ret;
+  guint payload_len;
+  GstMapInfo map;
+  GstBuffer *outbuf;
+  guint8 *payload, *ptr, *payload_amr;
+  GstClockTime timestamp, duration;
+  guint packet_len, mtu;
+  gint i, num_packets, num_nonempty_packets;
+  gint amr_len;
+  gboolean sid = FALSE;
+  GstRTPBuffer rtp = { NULL };
+
+  rtpamrpay = GST_RTP_AMR_PAY (basepayload);
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpamrpay);
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  timestamp = GST_BUFFER_PTS (buffer);
+  duration = GST_BUFFER_DURATION (buffer);
+
+  /* setup frame size pointer */
+  if (rtpamrpay->mode == GST_RTP_AMR_P_MODE_NB)
+    frame_size = nb_frame_size;
+  else
+    frame_size = wb_frame_size;
+
+  GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes", map.size);
+
+  /* FIXME, only
+   * octet aligned, no interleaving, single channel, no CRC,
+   * no robust-sorting. To fix this you need to implement the downstream
+   * negotiation function. */
+
+  /* first count number of packets and total amr frame size */
+  amr_len = num_packets = num_nonempty_packets = 0;
+  for (i = 0; i < map.size; i++) {
+    guint8 FT;
+    gint fr_size;
+
+    FT = (map.data[i] & 0x78) >> 3;
+
+    fr_size = frame_size[FT];
+    GST_DEBUG_OBJECT (basepayload, "frame type %d, frame size %d", FT, fr_size);
+    /* FIXME, we don't handle this yet.. */
+    if (fr_size <= 0)
+      goto wrong_size;
+
+    if (fr_size == 5)
+      sid = TRUE;
+
+    amr_len += fr_size;
+    num_nonempty_packets++;
+    num_packets++;
+    i += fr_size;
+  }
+  if (amr_len > map.size)
+    goto incomplete_frame;
+
+  /* we need one extra byte for the CMR, the ToC is in the input
+   * data */
+  payload_len = map.size + 1;
+
+  /* get packet len to check against MTU */
+  packet_len = gst_rtp_buffer_calc_packet_len (payload_len, 0, 0);
+  if (packet_len > mtu)
+    goto too_big;
+
+  /* now alloc output buffer */
+  outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
+
+  gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+  /* copy timestamp */
+  GST_BUFFER_PTS (outbuf) = timestamp;
+
+  if (duration != GST_CLOCK_TIME_NONE)
+    GST_BUFFER_DURATION (outbuf) = duration;
+  else {
+    GST_BUFFER_DURATION (outbuf) = num_packets * 20 * GST_MSECOND;
+  }
+
+  if (GST_BUFFER_IS_DISCONT (buffer)) {
+    GST_DEBUG_OBJECT (basepayload, "discont, setting marker bit");
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+    gst_rtp_buffer_set_marker (&rtp, TRUE);
+    gst_rtp_amr_pay_recalc_rtp_time (rtpamrpay, timestamp);
+  }
+
+  if (G_UNLIKELY (sid)) {
+    gst_rtp_amr_pay_recalc_rtp_time (rtpamrpay, timestamp);
+  }
+
+  /* perfect rtptime */
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (rtpamrpay->first_ts))) {
+    rtpamrpay->first_ts = timestamp;
+    rtpamrpay->first_rtp_time = rtpamrpay->next_rtp_time;
+  }
+  GST_BUFFER_OFFSET (outbuf) = rtpamrpay->next_rtp_time;
+  rtpamrpay->next_rtp_time +=
+      (num_packets * 160) << (rtpamrpay->mode == GST_RTP_AMR_P_MODE_WB);
+
+  /* get payload, this is now writable */
+  payload = gst_rtp_buffer_get_payload (&rtp);
+
+  /*   0 1 2 3 4 5 6 7
+   *  +-+-+-+-+-+-+-+-+
+   *  |  CMR  |R|R|R|R|
+   *  +-+-+-+-+-+-+-+-+
+   */
+  payload[0] = 0xF0;            /* CMR, no specific mode requested */
+
+  /* this is where we copy the AMR data, after num_packets FTs and the
+   * CMR. */
+  payload_amr = payload + num_packets + 1;
+
+  /* copy data in payload, first we copy all the FTs then all
+   * the AMR data. The last FT has to have the F flag cleared. */
+  ptr = map.data;
+  for (i = 1; i <= num_packets; i++) {
+    guint8 FT;
+    gint fr_size;
+
+    /*   0 1 2 3 4 5 6 7
+     *  +-+-+-+-+-+-+-+-+
+     *  |F|  FT   |Q|P|P| more FT...
+     *  +-+-+-+-+-+-+-+-+
+     */
+    FT = (*ptr & 0x78) >> 3;
+
+    fr_size = frame_size[FT];
+
+    if (i == num_packets)
+      /* last packet, clear F flag */
+      payload[i] = *ptr & 0x7f;
+    else
+      /* set F flag */
+      payload[i] = *ptr | 0x80;
+
+    memcpy (payload_amr, &ptr[1], fr_size);
+
+    /* all sizes are > 0 since we checked for that above */
+    ptr += fr_size + 1;
+    payload_amr += fr_size;
+  }
+
+  gst_buffer_unmap (buffer, &map);
+  gst_rtp_buffer_unmap (&rtp);
+
+  gst_rtp_copy_audio_meta (rtpamrpay, outbuf, buffer);
+
+  gst_buffer_unref (buffer);
+
+  ret = gst_rtp_base_payload_push (basepayload, outbuf);
+
+  return ret;
+
+  /* ERRORS */
+wrong_size:
+  {
+    GST_ELEMENT_ERROR (basepayload, STREAM, FORMAT,
+        (NULL), ("received AMR frame with size <= 0"));
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+
+    return GST_FLOW_ERROR;
+  }
+incomplete_frame:
+  {
+    GST_ELEMENT_ERROR (basepayload, STREAM, FORMAT,
+        (NULL), ("received incomplete AMR frames"));
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+
+    return GST_FLOW_ERROR;
+  }
+too_big:
+  {
+    GST_ELEMENT_ERROR (basepayload, STREAM, FORMAT,
+        (NULL), ("received too many AMR frames for MTU"));
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_amr_pay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+  /* handle upwards state changes here */
+  switch (transition) {
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  /* handle downwards state changes */
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_amr_pay_reset (GST_RTP_AMR_PAY (element));
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+gboolean
+gst_rtp_amr_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpamrpay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_AMR_PAY);
+}
diff --git a/gst/rtp/gstrtpamrpay.h b/gst/rtp/gstrtpamrpay.h
new file mode 100644
index 0000000..a3df1ce
--- /dev/null
+++ b/gst/rtp/gstrtpamrpay.h
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_AMR_PAY_H__
+#define __GST_RTP_AMR_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_AMR_PAY \
+  (gst_rtp_amr_pay_get_type())
+#define GST_RTP_AMR_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_AMR_PAY,GstRtpAMRPay))
+#define GST_RTP_AMR_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_AMR_PAY,GstRtpAMRPayClass))
+#define GST_IS_RTP_AMR_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_AMR_PAY))
+#define GST_IS_RTP_AMR_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_AMR_PAY))
+
+typedef struct _GstRtpAMRPay GstRtpAMRPay;
+typedef struct _GstRtpAMRPayClass GstRtpAMRPayClass;
+
+typedef enum {
+  GST_RTP_AMR_P_MODE_INVALID = 0,
+  GST_RTP_AMR_P_MODE_NB      = 1,
+  GST_RTP_AMR_P_MODE_WB      = 2
+} GstRtpAMRPayMode;
+
+struct _GstRtpAMRPay
+{
+  GstRTPBasePayload payload;
+
+  GstRtpAMRPayMode mode;
+  GstClockTime first_ts;
+  guint32 first_rtp_time;
+  guint32 next_rtp_time;
+};
+
+struct _GstRtpAMRPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_amr_pay_get_type (void);
+
+gboolean gst_rtp_amr_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_AMR_PAY_H__ */
diff --git a/gst/rtp/gstrtpbvdepay.c b/gst/rtp/gstrtpbvdepay.c
new file mode 100644
index 0000000..a0faf83
--- /dev/null
+++ b/gst/rtp/gstrtpbvdepay.c
@@ -0,0 +1,190 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpbvdepay
+ * @see_also: rtpbvpay
+ *
+ * Extract BroadcomVoice audio from RTP packets according to RFC 4298.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc4298.txt
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+#include "gstrtpbvdepay.h"
+#include "gstrtputils.h"
+
+static GstStaticPadTemplate gst_rtp_bv_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) 8000, "
+        "encoding-name = (string) \"BV16\"; "
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) 16000, " "encoding-name = (string) \"BV32\"")
+    );
+
+static GstStaticPadTemplate gst_rtp_bv_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-bv, " "mode = (int) { 16, 32 }")
+    );
+
+static GstBuffer *gst_rtp_bv_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+static gboolean gst_rtp_bv_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+
+#define gst_rtp_bv_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPBVDepay, gst_rtp_bv_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_bv_depay_class_init (GstRTPBVDepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_bv_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_bv_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP BroadcomVoice depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts BroadcomVoice audio from RTP packets (RFC 4298)",
+      "Wim Taymans <wim.taymans@collabora.co.uk>");
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_bv_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_bv_depay_setcaps;
+}
+
+static void
+gst_rtp_bv_depay_init (GstRTPBVDepay * rtpbvdepay)
+{
+  rtpbvdepay->mode = -1;
+}
+
+static gboolean
+gst_rtp_bv_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstRTPBVDepay *rtpbvdepay = GST_RTP_BV_DEPAY (depayload);
+  GstCaps *srccaps;
+  GstStructure *structure;
+  const gchar *mode_str = NULL;
+  gint mode, clock_rate, expected_rate;
+  gboolean ret;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  mode_str = gst_structure_get_string (structure, "encoding-name");
+  if (!mode_str)
+    goto no_mode;
+
+  if (!strcmp (mode_str, "BV16")) {
+    mode = 16;
+    expected_rate = 8000;
+  } else if (!strcmp (mode_str, "BV32")) {
+    mode = 32;
+    expected_rate = 16000;
+  } else
+    goto invalid_mode;
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = expected_rate;
+  else if (clock_rate != expected_rate)
+    goto wrong_rate;
+
+  depayload->clock_rate = clock_rate;
+  rtpbvdepay->mode = mode;
+
+  srccaps = gst_caps_new_simple ("audio/x-bv",
+      "mode", G_TYPE_INT, rtpbvdepay->mode, NULL);
+  ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+
+  GST_DEBUG ("set caps on source: %" GST_PTR_FORMAT " (ret=%d)", srccaps, ret);
+  gst_caps_unref (srccaps);
+
+  return ret;
+
+  /* ERRORS */
+no_mode:
+  {
+    GST_ERROR_OBJECT (rtpbvdepay, "did not receive an encoding-name");
+    return FALSE;
+  }
+invalid_mode:
+  {
+    GST_ERROR_OBJECT (rtpbvdepay,
+        "invalid encoding-name, expected BV16 or BV32, got %s", mode_str);
+    return FALSE;
+  }
+wrong_rate:
+  {
+    GST_ERROR_OBJECT (rtpbvdepay, "invalid clock-rate, expected %d, got %d",
+        expected_rate, clock_rate);
+    return FALSE;
+  }
+}
+
+static GstBuffer *
+gst_rtp_bv_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstBuffer *outbuf;
+  gboolean marker;
+
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+      gst_buffer_get_size (rtp->buffer), marker,
+      gst_rtp_buffer_get_timestamp (rtp), gst_rtp_buffer_get_seq (rtp));
+
+  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);
+
+  if (marker && outbuf) {
+    /* mark start of talkspurt with RESYNC */
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+  }
+
+  if (outbuf) {
+    gst_rtp_drop_non_audio_meta (depayload, outbuf);
+  }
+
+  return outbuf;
+}
+
+gboolean
+gst_rtp_bv_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpbvdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_BV_DEPAY);
+}
diff --git a/gst/rtp/gstrtpbvdepay.h b/gst/rtp/gstrtpbvdepay.h
new file mode 100644
index 0000000..f130682
--- /dev/null
+++ b/gst/rtp/gstrtpbvdepay.h
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_BV_DEPAY_H__
+#define __GST_RTP_BV_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTPBVDepay GstRTPBVDepay;
+typedef struct _GstRTPBVDepayClass GstRTPBVDepayClass;
+
+#define GST_TYPE_RTP_BV_DEPAY \
+  (gst_rtp_bv_depay_get_type())
+#define GST_RTP_BV_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_BV_DEPAY,GstRTPBVDepay))
+#define GST_RTP_BV_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_BV_DEPAY,GstRTPBVDepayClass))
+#define GST_IS_RTP_BV_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_BV_DEPAY))
+#define GST_IS_RTP_BV_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_BV_DEPAY))
+
+struct _GstRTPBVDepay
+{
+  GstRTPBaseDepayload depayload;
+
+  gint mode;
+};
+
+struct _GstRTPBVDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_bv_depay_get_type (void);
+
+gboolean gst_rtp_bv_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_BV_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpbvpay.c b/gst/rtp/gstrtpbvpay.c
new file mode 100644
index 0000000..e202015
--- /dev/null
+++ b/gst/rtp/gstrtpbvpay.c
@@ -0,0 +1,239 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpbvpay
+ * @see_also: rtpbvdepay
+ *
+ * Payload BroadcomVoice audio into RTP packets according to RFC 4298.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc4298.txt
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtpbvpay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpbvpay_debug);
+#define GST_CAT_DEFAULT (rtpbvpay_debug)
+
+static GstStaticPadTemplate gst_rtp_bv_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-bv, " "mode = (int) {16, 32}")
+    );
+
+static GstStaticPadTemplate gst_rtp_bv_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 8000, "
+        "encoding-name = (string) \"BV16\";"
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 16000, " "encoding-name = (string) \"BV32\"")
+    );
+
+
+static GstCaps *gst_rtp_bv_pay_sink_getcaps (GstRTPBasePayload * payload,
+    GstPad * pad, GstCaps * filter);
+static gboolean gst_rtp_bv_pay_sink_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+
+#define gst_rtp_bv_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPBVPay, gst_rtp_bv_pay, GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_bv_pay_class_init (GstRTPBVPayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpbvpay_debug, "rtpbvpay", 0,
+      "BroadcomVoice audio RTP payloader");
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_bv_pay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_bv_pay_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP BV Payloader",
+      "Codec/Payloader/Network/RTP",
+      "Packetize BroadcomVoice audio streams into RTP packets (RFC 4298)",
+      "Wim Taymans <wim.taymans@collabora.co.uk>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_bv_pay_sink_setcaps;
+  gstrtpbasepayload_class->get_caps = gst_rtp_bv_pay_sink_getcaps;
+}
+
+static void
+gst_rtp_bv_pay_init (GstRTPBVPay * rtpbvpay)
+{
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpbvpay);
+
+  rtpbvpay->mode = -1;
+
+  /* tell rtpbaseaudiopayload that this is a frame based codec */
+  gst_rtp_base_audio_payload_set_frame_based (rtpbaseaudiopayload);
+}
+
+static gboolean
+gst_rtp_bv_pay_sink_setcaps (GstRTPBasePayload * rtpbasepayload, GstCaps * caps)
+{
+  GstRTPBVPay *rtpbvpay;
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+  gint mode;
+  GstStructure *structure;
+  const char *payload_name;
+
+  rtpbvpay = GST_RTP_BV_PAY (rtpbasepayload);
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpbasepayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  payload_name = gst_structure_get_name (structure);
+  if (g_ascii_strcasecmp ("audio/x-bv", payload_name))
+    goto wrong_caps;
+
+  if (!gst_structure_get_int (structure, "mode", &mode))
+    goto no_mode;
+
+  if (mode != 16 && mode != 32)
+    goto wrong_mode;
+
+  if (mode == 16) {
+    gst_rtp_base_payload_set_options (rtpbasepayload, "audio", TRUE, "BV16",
+        8000);
+    rtpbasepayload->clock_rate = 8000;
+  } else {
+    gst_rtp_base_payload_set_options (rtpbasepayload, "audio", TRUE, "BV32",
+        16000);
+    rtpbasepayload->clock_rate = 16000;
+  }
+
+  /* set options for this frame based audio codec */
+  gst_rtp_base_audio_payload_set_frame_options (rtpbaseaudiopayload,
+      mode, mode == 16 ? 10 : 20);
+
+  if (mode != rtpbvpay->mode && rtpbvpay->mode != -1)
+    goto mode_changed;
+
+  rtpbvpay->mode = mode;
+
+  return TRUE;
+
+  /* ERRORS */
+wrong_caps:
+  {
+    GST_ERROR_OBJECT (rtpbvpay, "expected audio/x-bv, received %s",
+        payload_name);
+    return FALSE;
+  }
+no_mode:
+  {
+    GST_ERROR_OBJECT (rtpbvpay, "did not receive a mode");
+    return FALSE;
+  }
+wrong_mode:
+  {
+    GST_ERROR_OBJECT (rtpbvpay, "mode must be 16 or 32, received %d", mode);
+    return FALSE;
+  }
+mode_changed:
+  {
+    GST_ERROR_OBJECT (rtpbvpay, "Mode has changed from %d to %d! "
+        "Mode cannot change while streaming", rtpbvpay->mode, mode);
+    return FALSE;
+  }
+}
+
+/* we return the padtemplate caps with the mode field fixated to a value if we
+ * can */
+static GstCaps *
+gst_rtp_bv_pay_sink_getcaps (GstRTPBasePayload * rtppayload, GstPad * pad,
+    GstCaps * filter)
+{
+  GstCaps *otherpadcaps;
+  GstCaps *caps;
+
+  caps = gst_pad_get_pad_template_caps (pad);
+
+  otherpadcaps = gst_pad_get_allowed_caps (rtppayload->srcpad);
+  if (otherpadcaps) {
+    if (!gst_caps_is_empty (otherpadcaps)) {
+      GstStructure *structure;
+      const gchar *mode_str;
+      gint mode;
+
+      structure = gst_caps_get_structure (otherpadcaps, 0);
+
+      /* construct mode, if we can */
+      mode_str = gst_structure_get_string (structure, "encoding-name");
+      if (mode_str) {
+        if (!strcmp (mode_str, "BV16"))
+          mode = 16;
+        else if (!strcmp (mode_str, "BV32"))
+          mode = 32;
+        else
+          mode = -1;
+
+        if (mode == 16 || mode == 32) {
+          caps = gst_caps_make_writable (caps);
+          structure = gst_caps_get_structure (caps, 0);
+          gst_structure_set (structure, "mode", G_TYPE_INT, mode, NULL);
+        }
+      }
+    }
+    gst_caps_unref (otherpadcaps);
+  }
+
+  if (filter) {
+    GstCaps *tmp;
+
+    GST_DEBUG_OBJECT (rtppayload, "Intersect %" GST_PTR_FORMAT " and filter %"
+        GST_PTR_FORMAT, caps, filter);
+    tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    caps = tmp;
+  }
+
+  return caps;
+}
+
+gboolean
+gst_rtp_bv_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpbvpay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_BV_PAY);
+}
diff --git a/gst/rtp/gstrtpbvpay.h b/gst/rtp/gstrtpbvpay.h
new file mode 100644
index 0000000..09766cc
--- /dev/null
+++ b/gst/rtp/gstrtpbvpay.h
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_BV_PAY_H__
+#define __GST_RTP_BV_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_BV_PAY \
+  (gst_rtp_bv_pay_get_type())
+#define GST_RTP_BV_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_BV_PAY,GstRTPBVPay))
+#define GST_RTP_BV_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_BV_PAY,GstRTPBVPayClass))
+#define GST_IS_RTP_BV_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_BV_PAY))
+#define GST_IS_RTP_BV_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_BV_PAY))
+
+typedef struct _GstRTPBVPay GstRTPBVPay;
+typedef struct _GstRTPBVPayClass GstRTPBVPayClass;
+
+struct _GstRTPBVPay
+{
+  GstRTPBaseAudioPayload audiopayload;
+
+  gint mode;
+};
+
+struct _GstRTPBVPayClass
+{
+  GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_bv_pay_get_type (void);
+
+gboolean gst_rtp_bv_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_BV_PAY_H__ */
diff --git a/gst/rtp/gstrtpceltdepay.c b/gst/rtp/gstrtpceltdepay.c
new file mode 100644
index 0000000..97c17f0
--- /dev/null
+++ b/gst/rtp/gstrtpceltdepay.c
@@ -0,0 +1,276 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpceltdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpceltdepay_debug);
+#define GST_CAT_DEFAULT (rtpceltdepay_debug)
+
+/* RtpCELTDepay signals and args */
+
+#define DEFAULT_FRAMESIZE       480
+#define DEFAULT_CHANNELS        1
+#define DEFAULT_CLOCKRATE       32000
+
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0
+};
+
+static GstStaticPadTemplate gst_rtp_celt_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate =  (int) [32000, 48000], "
+        "encoding-name = (string) \"CELT\"")
+    );
+
+static GstStaticPadTemplate gst_rtp_celt_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-celt")
+    );
+
+static GstBuffer *gst_rtp_celt_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+static gboolean gst_rtp_celt_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+
+#define gst_rtp_celt_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpCELTDepay, gst_rtp_celt_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_celt_depay_class_init (GstRtpCELTDepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpceltdepay_debug, "rtpceltdepay", 0,
+      "CELT RTP Depayloader");
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_celt_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_celt_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP CELT depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts CELT audio from RTP packets",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_celt_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_celt_depay_setcaps;
+}
+
+static void
+gst_rtp_celt_depay_init (GstRtpCELTDepay * rtpceltdepay)
+{
+}
+
+/* len 4 bytes LE,
+ * vendor string (len bytes),
+ * user_len 4 (0) bytes LE
+ */
+static const gchar gst_rtp_celt_comment[] =
+    "\045\0\0\0Depayloaded with GStreamer celtdepay\0\0\0\0";
+
+static gboolean
+gst_rtp_celt_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstRtpCELTDepay *rtpceltdepay;
+  gint clock_rate, nb_channels = 0, frame_size = 0;
+  GstBuffer *buf;
+  GstMapInfo map;
+  guint8 *ptr;
+  const gchar *params;
+  GstCaps *srccaps;
+  gboolean res;
+
+  rtpceltdepay = GST_RTP_CELT_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    goto no_clockrate;
+  depayload->clock_rate = clock_rate;
+
+  if ((params = gst_structure_get_string (structure, "encoding-params")))
+    nb_channels = atoi (params);
+  if (!nb_channels)
+    nb_channels = DEFAULT_CHANNELS;
+
+  if ((params = gst_structure_get_string (structure, "frame-size")))
+    frame_size = atoi (params);
+  if (!frame_size)
+    frame_size = DEFAULT_FRAMESIZE;
+  rtpceltdepay->frame_size = frame_size;
+
+  GST_DEBUG_OBJECT (depayload, "clock-rate=%d channels=%d frame-size=%d",
+      clock_rate, nb_channels, frame_size);
+
+  /* construct minimal header and comment packet for the decoder */
+  buf = gst_buffer_new_and_alloc (60);
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  ptr = map.data;
+  memcpy (ptr, "CELT    ", 8);
+  ptr += 8;
+  memcpy (ptr, "1.1.12", 7);
+  ptr += 20;
+  GST_WRITE_UINT32_LE (ptr, 0x80000006);        /* version */
+  ptr += 4;
+  GST_WRITE_UINT32_LE (ptr, 56);        /* header_size */
+  ptr += 4;
+  GST_WRITE_UINT32_LE (ptr, clock_rate);        /* rate */
+  ptr += 4;
+  GST_WRITE_UINT32_LE (ptr, nb_channels);       /* channels */
+  ptr += 4;
+  GST_WRITE_UINT32_LE (ptr, frame_size);        /* frame-size */
+  ptr += 4;
+  GST_WRITE_UINT32_LE (ptr, -1);        /* overlap */
+  ptr += 4;
+  GST_WRITE_UINT32_LE (ptr, -1);        /* bytes_per_packet */
+  ptr += 4;
+  GST_WRITE_UINT32_LE (ptr, 0); /* extra headers */
+  gst_buffer_unmap (buf, &map);
+
+  srccaps = gst_caps_new_empty_simple ("audio/x-celt");
+  res = gst_pad_set_caps (depayload->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpceltdepay), buf);
+
+  buf = gst_buffer_new_and_alloc (sizeof (gst_rtp_celt_comment));
+  gst_buffer_fill (buf, 0, gst_rtp_celt_comment, sizeof (gst_rtp_celt_comment));
+
+  gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpceltdepay), buf);
+
+  return res;
+
+  /* ERRORS */
+no_clockrate:
+  {
+    GST_ERROR_OBJECT (depayload, "no clock-rate specified");
+    return FALSE;
+  }
+}
+
+static GstBuffer *
+gst_rtp_celt_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstBuffer *outbuf = NULL;
+  guint8 *payload;
+  guint offset, pos, payload_len, total_size, size;
+  guint8 s;
+  gint clock_rate = 0, frame_size = 0;
+  GstClockTime framesize_ns = 0, timestamp;
+  guint n = 0;
+  GstRtpCELTDepay *rtpceltdepay;
+
+  rtpceltdepay = GST_RTP_CELT_DEPAY (depayload);
+  clock_rate = depayload->clock_rate;
+  frame_size = rtpceltdepay->frame_size;
+  framesize_ns = gst_util_uint64_scale_int (frame_size, GST_SECOND, clock_rate);
+
+  timestamp = GST_BUFFER_PTS (rtp->buffer);
+
+  GST_LOG_OBJECT (depayload,
+      "got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+      gst_buffer_get_size (rtp->buffer), gst_rtp_buffer_get_marker (rtp),
+      gst_rtp_buffer_get_timestamp (rtp), gst_rtp_buffer_get_seq (rtp));
+
+  GST_LOG_OBJECT (depayload, "got clock-rate=%d, frame_size=%d, "
+      "_ns=%" GST_TIME_FORMAT ", timestamp=%" GST_TIME_FORMAT, clock_rate,
+      frame_size, GST_TIME_ARGS (framesize_ns), GST_TIME_ARGS (timestamp));
+
+  payload = gst_rtp_buffer_get_payload (rtp);
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  /* first count how many bytes are consumed by the size headers and make offset
+   * point to the first data byte */
+  total_size = 0;
+  offset = 0;
+  while (total_size < payload_len) {
+    do {
+      s = payload[offset++];
+      total_size += s + 1;
+    } while (s == 0xff);
+  }
+
+  /* offset is now pointing to the payload */
+  total_size = 0;
+  pos = 0;
+  while (total_size < payload_len) {
+    n++;
+    size = 0;
+    do {
+      s = payload[pos++];
+      size += s;
+      total_size += s + 1;
+    } while (s == 0xff);
+
+    outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, offset, size);
+    offset += size;
+
+    if (frame_size != -1 && clock_rate != -1) {
+      GST_BUFFER_PTS (outbuf) = timestamp + framesize_ns * n;
+      GST_BUFFER_DURATION (outbuf) = framesize_ns;
+    }
+    GST_LOG_OBJECT (depayload, "push timestamp=%"
+        GST_TIME_FORMAT ", duration=%" GST_TIME_FORMAT,
+        GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)),
+        GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
+
+    gst_rtp_drop_non_audio_meta (depayload, outbuf);
+
+    gst_rtp_base_depayload_push (depayload, outbuf);
+  }
+
+  return NULL;
+}
+
+gboolean
+gst_rtp_celt_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpceltdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_CELT_DEPAY);
+}
diff --git a/gst/rtp/gstrtpceltdepay.h b/gst/rtp/gstrtpceltdepay.h
new file mode 100644
index 0000000..0905c68
--- /dev/null
+++ b/gst/rtp/gstrtpceltdepay.h
@@ -0,0 +1,54 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 
+ */
+ 
+#ifndef __GST_RTP_CELT_DEPAY_H__
+#define __GST_RTP_CELT_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpCELTDepay GstRtpCELTDepay;
+typedef struct _GstRtpCELTDepayClass GstRtpCELTDepayClass;
+
+#define GST_TYPE_RTP_CELT_DEPAY \
+  (gst_rtp_celt_depay_get_type())
+#define GST_RTP_CELT_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_CELT_DEPAY,GstRtpCELTDepay))
+#define GST_RTP_CELT_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_CELT_DEPAY,GstRtpCELTDepayClass))
+#define GST_IS_RTP_CELT_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_CELT_DEPAY))
+#define GST_IS_RTP_CELT_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_CELT_DEPAY))
+
+struct _GstRtpCELTDepay
+{
+  GstRTPBaseDepayload depayload;
+  gint frame_size;
+};
+
+struct _GstRtpCELTDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_celt_depay_get_type (void);
+
+gboolean gst_rtp_celt_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_CELT_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpceltpay.c b/gst/rtp/gstrtpceltpay.c
new file mode 100644
index 0000000..c498897
--- /dev/null
+++ b/gst/rtp/gstrtpceltpay.c
@@ -0,0 +1,502 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpceltpay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpceltpay_debug);
+#define GST_CAT_DEFAULT (rtpceltpay_debug)
+
+static GstStaticPadTemplate gst_rtp_celt_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-celt, "
+        "rate = (int) [ 32000, 64000 ], "
+        "channels = (int) [1, 2], " "frame-size = (int) [ 64, 512 ]")
+    );
+
+static GstStaticPadTemplate gst_rtp_celt_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate =  (int) [ 32000, 48000 ], "
+        "encoding-name = (string) \"CELT\"")
+    );
+
+static void gst_rtp_celt_pay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_celt_pay_change_state (GstElement *
+    element, GstStateChange transition);
+
+static gboolean gst_rtp_celt_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static GstCaps *gst_rtp_celt_pay_getcaps (GstRTPBasePayload * payload,
+    GstPad * pad, GstCaps * filter);
+static GstFlowReturn gst_rtp_celt_pay_handle_buffer (GstRTPBasePayload *
+    payload, GstBuffer * buffer);
+
+#define gst_rtp_celt_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpCELTPay, gst_rtp_celt_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_celt_pay_class_init (GstRtpCELTPayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpceltpay_debug, "rtpceltpay", 0,
+      "CELT RTP Payloader");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_celt_pay_finalize;
+
+  gstelement_class->change_state = gst_rtp_celt_pay_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_celt_pay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_celt_pay_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP CELT payloader",
+      "Codec/Payloader/Network/RTP",
+      "Payload-encodes CELT audio into a RTP packet",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_celt_pay_setcaps;
+  gstrtpbasepayload_class->get_caps = gst_rtp_celt_pay_getcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_celt_pay_handle_buffer;
+}
+
+static void
+gst_rtp_celt_pay_init (GstRtpCELTPay * rtpceltpay)
+{
+  rtpceltpay->queue = g_queue_new ();
+}
+
+static void
+gst_rtp_celt_pay_finalize (GObject * object)
+{
+  GstRtpCELTPay *rtpceltpay;
+
+  rtpceltpay = GST_RTP_CELT_PAY (object);
+
+  g_queue_free (rtpceltpay->queue);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_celt_pay_clear_queued (GstRtpCELTPay * rtpceltpay)
+{
+  GstBuffer *buf;
+
+  while ((buf = g_queue_pop_head (rtpceltpay->queue)))
+    gst_buffer_unref (buf);
+
+  rtpceltpay->bytes = 0;
+  rtpceltpay->sbytes = 0;
+  rtpceltpay->qduration = 0;
+}
+
+static void
+gst_rtp_celt_pay_add_queued (GstRtpCELTPay * rtpceltpay, GstBuffer * buffer,
+    guint ssize, guint size, GstClockTime duration)
+{
+  g_queue_push_tail (rtpceltpay->queue, buffer);
+  rtpceltpay->sbytes += ssize;
+  rtpceltpay->bytes += size;
+  /* only add durations when we have a valid previous duration */
+  if (rtpceltpay->qduration != -1) {
+    if (duration != -1)
+      /* only add valid durations */
+      rtpceltpay->qduration += duration;
+    else
+      /* if we add a buffer without valid duration, our total queued duration
+       * becomes unknown */
+      rtpceltpay->qduration = -1;
+  }
+}
+
+static gboolean
+gst_rtp_celt_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  /* don't configure yet, we wait for the ident packet */
+  return TRUE;
+}
+
+
+static GstCaps *
+gst_rtp_celt_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad,
+    GstCaps * filter)
+{
+  GstCaps *otherpadcaps;
+  GstCaps *caps;
+  const gchar *params;
+
+  caps = gst_pad_get_pad_template_caps (pad);
+
+  otherpadcaps = gst_pad_get_allowed_caps (payload->srcpad);
+  if (otherpadcaps) {
+    if (!gst_caps_is_empty (otherpadcaps)) {
+      GstStructure *ps;
+      GstStructure *s;
+      gint clock_rate = 0, frame_size = 0, channels = 1;
+
+      caps = gst_caps_make_writable (caps);
+
+      ps = gst_caps_get_structure (otherpadcaps, 0);
+      s = gst_caps_get_structure (caps, 0);
+
+      if (gst_structure_get_int (ps, "clock-rate", &clock_rate)) {
+        gst_structure_fixate_field_nearest_int (s, "rate", clock_rate);
+      }
+
+      if ((params = gst_structure_get_string (ps, "frame-size")))
+        frame_size = atoi (params);
+      if (frame_size)
+        gst_structure_set (s, "frame-size", G_TYPE_INT, frame_size, NULL);
+
+      if ((params = gst_structure_get_string (ps, "encoding-params"))) {
+        channels = atoi (params);
+        gst_structure_fixate_field_nearest_int (s, "channels", channels);
+      }
+
+      GST_DEBUG_OBJECT (payload, "clock-rate=%d frame-size=%d channels=%d",
+          clock_rate, frame_size, channels);
+    }
+    gst_caps_unref (otherpadcaps);
+  }
+
+  if (filter) {
+    GstCaps *tmp;
+
+    GST_DEBUG_OBJECT (payload, "Intersect %" GST_PTR_FORMAT " and filter %"
+        GST_PTR_FORMAT, caps, filter);
+    tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    caps = tmp;
+  }
+
+  return caps;
+}
+
+static gboolean
+gst_rtp_celt_pay_parse_ident (GstRtpCELTPay * rtpceltpay,
+    const guint8 * data, guint size)
+{
+  guint32 version, header_size, rate, nb_channels, frame_size, overlap;
+  guint32 bytes_per_packet;
+  GstRTPBasePayload *payload;
+  gchar *cstr, *fsstr;
+  gboolean res;
+
+  /* we need the header string (8), the version string (20), the version
+   * and the header length. */
+  if (size < 36)
+    goto too_small;
+
+  if (!g_str_has_prefix ((const gchar *) data, "CELT    "))
+    goto wrong_header;
+
+  /* skip header and version string */
+  data += 28;
+
+  version = GST_READ_UINT32_LE (data);
+  GST_DEBUG_OBJECT (rtpceltpay, "version %08x", version);
+#if 0
+  if (version != 1)
+    goto wrong_version;
+#endif
+
+  data += 4;
+  /* ensure sizes */
+  header_size = GST_READ_UINT32_LE (data);
+  if (header_size < 56)
+    goto header_too_small;
+
+  if (size < header_size)
+    goto payload_too_small;
+
+  data += 4;
+  rate = GST_READ_UINT32_LE (data);
+  data += 4;
+  nb_channels = GST_READ_UINT32_LE (data);
+  data += 4;
+  frame_size = GST_READ_UINT32_LE (data);
+  data += 4;
+  overlap = GST_READ_UINT32_LE (data);
+  data += 4;
+  bytes_per_packet = GST_READ_UINT32_LE (data);
+
+  GST_DEBUG_OBJECT (rtpceltpay, "rate %d, nb_channels %d, frame_size %d",
+      rate, nb_channels, frame_size);
+  GST_DEBUG_OBJECT (rtpceltpay, "overlap %d, bytes_per_packet %d",
+      overlap, bytes_per_packet);
+
+  payload = GST_RTP_BASE_PAYLOAD (rtpceltpay);
+
+  gst_rtp_base_payload_set_options (payload, "audio", FALSE, "CELT", rate);
+  cstr = g_strdup_printf ("%d", nb_channels);
+  fsstr = g_strdup_printf ("%d", frame_size);
+  res = gst_rtp_base_payload_set_outcaps (payload, "encoding-params",
+      G_TYPE_STRING, cstr, "frame-size", G_TYPE_STRING, fsstr, NULL);
+  g_free (cstr);
+  g_free (fsstr);
+
+  return res;
+
+  /* ERRORS */
+too_small:
+  {
+    GST_DEBUG_OBJECT (rtpceltpay,
+        "ident packet too small, need at least 32 bytes");
+    return FALSE;
+  }
+wrong_header:
+  {
+    GST_DEBUG_OBJECT (rtpceltpay,
+        "ident packet does not start with \"CELT    \"");
+    return FALSE;
+  }
+#if 0
+wrong_version:
+  {
+    GST_DEBUG_OBJECT (rtpceltpay, "can only handle version 1, have version %d",
+        version);
+    return FALSE;
+  }
+#endif
+header_too_small:
+  {
+    GST_DEBUG_OBJECT (rtpceltpay,
+        "header size too small, need at least 80 bytes, " "got only %d",
+        header_size);
+    return FALSE;
+  }
+payload_too_small:
+  {
+    GST_DEBUG_OBJECT (rtpceltpay,
+        "payload too small, need at least %d bytes, got only %d", header_size,
+        size);
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_rtp_celt_pay_flush_queued (GstRtpCELTPay * rtpceltpay)
+{
+  GstFlowReturn ret;
+  GstBuffer *buf, *outbuf;
+  guint8 *payload, *spayload;
+  guint payload_len;
+  GstClockTime duration;
+  GstRTPBuffer rtp = { NULL, };
+
+  payload_len = rtpceltpay->bytes + rtpceltpay->sbytes;
+  duration = rtpceltpay->qduration;
+
+  GST_DEBUG_OBJECT (rtpceltpay, "flushing out %u, duration %" GST_TIME_FORMAT,
+      payload_len, GST_TIME_ARGS (rtpceltpay->qduration));
+
+  /* get a big enough packet for the sizes + payloads */
+  outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
+
+  GST_BUFFER_DURATION (outbuf) = duration;
+
+  gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+  /* point to the payload for size headers and data */
+  spayload = gst_rtp_buffer_get_payload (&rtp);
+  payload = spayload + rtpceltpay->sbytes;
+
+  while ((buf = g_queue_pop_head (rtpceltpay->queue))) {
+    guint size;
+
+    /* copy first timestamp to output */
+    if (GST_BUFFER_PTS (outbuf) == -1)
+      GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buf);
+
+    /* write the size to the header */
+    size = gst_buffer_get_size (buf);
+    while (size > 0xff) {
+      *spayload++ = 0xff;
+      size -= 0xff;
+    }
+    *spayload++ = size;
+
+    /* copy payload */
+    size = gst_buffer_get_size (buf);
+    gst_buffer_extract (buf, 0, payload, size);
+    payload += size;
+
+    gst_rtp_copy_audio_meta (rtpceltpay, outbuf, buf);
+
+    gst_buffer_unref (buf);
+  }
+  gst_rtp_buffer_unmap (&rtp);
+
+  /* we consumed it all */
+  rtpceltpay->bytes = 0;
+  rtpceltpay->sbytes = 0;
+  rtpceltpay->qduration = 0;
+
+  ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpceltpay), outbuf);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_rtp_celt_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstFlowReturn ret;
+  GstRtpCELTPay *rtpceltpay;
+  gsize payload_len;
+  GstMapInfo map;
+  GstClockTime duration, packet_dur;
+  guint i, ssize, packet_len;
+
+  rtpceltpay = GST_RTP_CELT_PAY (basepayload);
+
+  ret = GST_FLOW_OK;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  switch (rtpceltpay->packet) {
+    case 0:
+      /* ident packet. We need to parse the headers to construct the RTP
+       * properties. */
+      if (!gst_rtp_celt_pay_parse_ident (rtpceltpay, map.data, map.size))
+        goto parse_error;
+
+      goto cleanup;
+    case 1:
+      /* comment packet, we ignore it */
+      goto cleanup;
+    default:
+      /* other packets go in the payload */
+      break;
+  }
+  gst_buffer_unmap (buffer, &map);
+
+  duration = GST_BUFFER_DURATION (buffer);
+
+  GST_LOG_OBJECT (rtpceltpay,
+      "got buffer of duration %" GST_TIME_FORMAT ", size %" G_GSIZE_FORMAT,
+      GST_TIME_ARGS (duration), map.size);
+
+  /* calculate the size of the size field and the payload */
+  ssize = 1;
+  for (i = map.size; i > 0xff; i -= 0xff)
+    ssize++;
+
+  GST_DEBUG_OBJECT (rtpceltpay, "bytes for size %u", ssize);
+
+  /* calculate what the new size and duration would be of the packet */
+  payload_len = ssize + map.size + rtpceltpay->bytes + rtpceltpay->sbytes;
+  if (rtpceltpay->qduration != -1 && duration != -1)
+    packet_dur = rtpceltpay->qduration + duration;
+  else
+    packet_dur = 0;
+
+  packet_len = gst_rtp_buffer_calc_packet_len (payload_len, 0, 0);
+
+  if (gst_rtp_base_payload_is_filled (basepayload, packet_len, packet_dur)) {
+    /* size or duration would overflow the packet, flush the queued data */
+    ret = gst_rtp_celt_pay_flush_queued (rtpceltpay);
+  }
+
+  /* queue the packet */
+  gst_rtp_celt_pay_add_queued (rtpceltpay, buffer, ssize, map.size, duration);
+
+done:
+  rtpceltpay->packet++;
+
+  return ret;
+
+  /* ERRORS */
+cleanup:
+  {
+    gst_buffer_unmap (buffer, &map);
+    goto done;
+  }
+parse_error:
+  {
+    GST_ELEMENT_ERROR (rtpceltpay, STREAM, DECODE, (NULL),
+        ("Error parsing first identification packet."));
+    gst_buffer_unmap (buffer, &map);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_celt_pay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRtpCELTPay *rtpceltpay;
+  GstStateChangeReturn ret;
+
+  rtpceltpay = GST_RTP_CELT_PAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      rtpceltpay->packet = 0;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_celt_pay_clear_queued (rtpceltpay);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_celt_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpceltpay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_CELT_PAY);
+}
diff --git a/gst/rtp/gstrtpceltpay.h b/gst/rtp/gstrtpceltpay.h
new file mode 100644
index 0000000..dcdd0ec
--- /dev/null
+++ b/gst/rtp/gstrtpceltpay.h
@@ -0,0 +1,62 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 
+ */
+
+
+#ifndef __GST_RTP_CELT_PAY_H__
+#define __GST_RTP_CELT_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpCELTPay GstRtpCELTPay;
+typedef struct _GstRtpCELTPayClass GstRtpCELTPayClass;
+
+#define GST_TYPE_RTP_CELT_PAY \
+  (gst_rtp_celt_pay_get_type())
+#define GST_RTP_CELT_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_CELT_PAY,GstRtpCELTPay))
+#define GST_RTP_CELT_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_CELT_PAY,GstRtpCELTPayClass))
+#define GST_IS_RTP_CELT_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_CELT_PAY))
+#define GST_IS_RTP_CELT_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_CELT_PAY))
+
+struct _GstRtpCELTPay
+{
+  GstRTPBasePayload payload;
+
+  guint64 packet;
+
+  /* queue to hold packets */
+  GQueue      *queue;
+  guint        sbytes;    /* bytes queued for sizes */
+  guint        bytes;     /* bytes queued for data */
+  GstClockTime qduration; /* queued duration */
+};
+
+struct _GstRtpCELTPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_celt_pay_get_type (void);
+
+gboolean gst_rtp_celt_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_CELT_PAY_H__ */
diff --git a/gst/rtp/gstrtpchannels.c b/gst/rtp/gstrtpchannels.c
new file mode 100644
index 0000000..9921293
--- /dev/null
+++ b/gst/rtp/gstrtpchannels.c
@@ -0,0 +1,310 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "gstrtpchannels.h"
+
+/* 
+ * RTP channel positions as discussed in RFC 3551 and also RFC 3555
+ *
+ * We can't really represent the described channel positions in GStreamer but we
+ * implement a (very rough) approximation here.
+ */
+
+static const GstAudioChannelPosition pos_4_1[] = {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT
+};
+
+static const GstAudioChannelPosition pos_4_2[] = {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+  GST_AUDIO_CHANNEL_POSITION_LFE1
+};
+
+static const GstAudioChannelPosition pos_4_3[] = {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+  GST_AUDIO_CHANNEL_POSITION_LFE1
+};
+
+static const GstAudioChannelPosition pos_5_1[] = {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER
+};
+
+static const GstAudioChannelPosition pos_6_1[] = {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+  GST_AUDIO_CHANNEL_POSITION_LFE1
+};
+
+static const GstAudioChannelPosition pos_6_2[] = {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+  GST_AUDIO_CHANNEL_POSITION_LFE1,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT
+};
+
+static const GstAudioChannelPosition pos_8_1[] = {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+  GST_AUDIO_CHANNEL_POSITION_LFE1,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT
+};
+
+static const GstAudioChannelPosition pos_8_2[] = {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+  GST_AUDIO_CHANNEL_POSITION_LFE1,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT
+};
+
+static const GstAudioChannelPosition pos_8_3[] = {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+  GST_AUDIO_CHANNEL_POSITION_LFE1,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT
+};
+
+static const GstAudioChannelPosition pos_def_1[] = {
+  GST_AUDIO_CHANNEL_POSITION_MONO
+};
+
+static const GstAudioChannelPosition pos_def_2[] = {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT
+};
+
+static const GstAudioChannelPosition pos_def_3[] = {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER
+};
+
+static const GstAudioChannelPosition pos_def_4[] = {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_LFE1
+};
+
+static const GstAudioChannelPosition pos_def_5[] = {
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT
+};
+
+static const GstAudioChannelPosition pos_def_6[] = {
+  GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+  GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+  GST_AUDIO_CHANNEL_POSITION_LFE1
+};
+
+const GstRTPChannelOrder gst_rtp_channel_orders[] = {
+  /* 4 channels */
+  {"DV.LRLsRs", 4, pos_4_1},
+  {"DV.LRCS", 4, pos_4_2},
+  {"DV.LRCWo", 4, pos_4_3},
+  /* 5 channels */
+  {"DV.LRLsRsC", 5, pos_5_1},
+  /* 6 channels */
+  {"DV.LRLsRsCS", 6, pos_6_1},
+  {"DV.LmixRmixTWoQ1Q2", 6, pos_6_2},
+  /* 8 channels */
+  {"DV.LRCWoLsRsLmixRmix", 8, pos_8_1},
+  {"DV.LRCWoLs1Rs1Ls2Rs2", 8, pos_8_2},
+  {"DV.LRCWoLsRsLcRc", 8, pos_8_3},
+
+  /* default layouts */
+  {NULL, 1, pos_def_1},
+  {NULL, 2, pos_def_2},
+  {NULL, 3, pos_def_3},
+  {NULL, 4, pos_def_4},
+  {NULL, 5, pos_def_5},
+  {NULL, 6, pos_def_6},
+
+  /* terminator, invalid entry */
+  {NULL, 0, NULL},
+};
+
+static gboolean
+check_channels (const GstRTPChannelOrder * order,
+    const GstAudioChannelPosition * pos)
+{
+  gint i, j;
+  gboolean res = TRUE;
+
+  for (i = 0; i < order->channels; i++) {
+    for (j = 0; j < order->channels; j++) {
+      if (order->pos[j] == pos[i])
+        break;
+    }
+    if (j == order->channels)
+      return FALSE;
+  }
+  return res;
+}
+
+/**
+ * gst_rtp_channels_get_by_pos:
+ * @channels: the amount of channels
+ * @pos: a channel layout
+ *
+ * Return a description of the channel layout.
+ *
+ * Returns: a #GstRTPChannelOrder with the channel information or NULL when @pos
+ * is not a valid layout.
+ */
+const GstRTPChannelOrder *
+gst_rtp_channels_get_by_pos (gint channels, const GstAudioChannelPosition * pos)
+{
+  gint i;
+  const GstRTPChannelOrder *res = NULL;
+
+  g_return_val_if_fail (pos != NULL, NULL);
+
+  for (i = 0; channel_orders[i].pos; i++) {
+    if (channel_orders[i].channels != channels)
+      continue;
+
+    if (check_channels (&channel_orders[i], pos)) {
+      res = &channel_orders[i];
+      break;
+    }
+  }
+  return res;
+}
+
+/**
+ * gst_rtp_channels_create_default:
+ * @channels: the amount of channels
+ * @order: a channel order
+ *
+ * Get the channel order info the @order and @channels.
+ *
+ * Returns: a #GstRTPChannelOrder with the channel information or NULL when
+ * @order is not a know layout for @channels.
+ */
+const GstRTPChannelOrder *
+gst_rtp_channels_get_by_order (gint channels, const gchar * order)
+{
+  gint i;
+  const GstRTPChannelOrder *res = NULL;
+
+  for (i = 0; channel_orders[i].pos; i++) {
+    if (channel_orders[i].channels != channels)
+      continue;
+
+    /* no name but channels match, continue */
+    if (!channel_orders[i].name || !order) {
+      res = &channel_orders[i];
+      break;
+    }
+
+    /* compare names */
+    if (g_ascii_strcasecmp (channel_orders[i].name, order)) {
+      res = &channel_orders[i];
+      break;
+    }
+  }
+  return res;
+}
+
+/**
+ * gst_rtp_channels_get_by_index:
+ * @channels: the amount of channels
+ * @idx: the channel index to retrieve
+ *
+ * Get the allowed channel order descriptions for @channels. @idx can be used to
+ * retrieve the desired index.
+ *
+ * Returns: a #GstRTPChannelOrder at @idx, NULL when there are no valid channel
+ * orders.
+ */
+const GstRTPChannelOrder *
+gst_rtp_channels_get_by_index (gint channels, guint idx)
+{
+  gint i;
+  const GstRTPChannelOrder *res = NULL;
+
+  for (i = 0; channel_orders[i].pos; i++) {
+    if (channel_orders[i].channels != channels)
+      continue;
+
+    if (idx == 0) {
+      res = &channel_orders[i];
+      break;
+    }
+    idx--;
+  }
+  return res;
+}
+
+
+/**
+ * gst_rtp_channels_create_default:
+ * @channels: the amount of channels
+ *
+ * Create a default none channel mapping for @channels.
+ *
+ * Returns: a #GstAudioChannelPosition with all the channel position info set to
+ * #GST_AUDIO_CHANNEL_POSITION_NONE.
+ */
+void
+gst_rtp_channels_create_default (gint channels, GstAudioChannelPosition * posn)
+{
+  gint i;
+
+  g_return_if_fail (channels > 0);
+
+  for (i = 0; i < channels; i++)
+    posn[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
+}
diff --git a/gst/rtp/gstrtpchannels.h b/gst/rtp/gstrtpchannels.h
new file mode 100644
index 0000000..6d3f530
--- /dev/null
+++ b/gst/rtp/gstrtpchannels.h
@@ -0,0 +1,46 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/audio/audio.h>
+
+#ifndef __GST_RTP_CHANNELS_H__
+#define __GST_RTP_CHANNELS_H__
+
+typedef struct
+{
+  const gchar                   *name;
+  gint                           channels;
+  const GstAudioChannelPosition *pos;
+} GstRTPChannelOrder;
+
+#define channel_orders gst_rtp_channel_orders
+G_GNUC_INTERNAL extern const GstRTPChannelOrder gst_rtp_channel_orders[];
+
+const GstRTPChannelOrder *   gst_rtp_channels_get_by_pos     (gint channels,
+                                                              const GstAudioChannelPosition *pos);
+const GstRTPChannelOrder *   gst_rtp_channels_get_by_order   (gint channels,
+                                                              const gchar *order);
+const GstRTPChannelOrder *   gst_rtp_channels_get_by_index   (gint channels, guint idx);
+
+void                         gst_rtp_channels_create_default (gint channels, GstAudioChannelPosition *pos);
+
+#endif /* __GST_RTP_CHANNELS_H__ */
diff --git a/gst/rtp/gstrtpdvdepay.c b/gst/rtp/gstrtpdvdepay.c
new file mode 100644
index 0000000..0235b71
--- /dev/null
+++ b/gst/rtp/gstrtpdvdepay.c
@@ -0,0 +1,425 @@
+/* Farsight
+ * Copyright (C) 2006 Marcel Moreaux <marcelm@spacelabs.nl>
+ *           (C) 2008 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * RTP DV depayloader.
+ *
+ * Important note for NTSC-users:
+ *
+ * Because the author uses PAL video, and he does not have proper DV
+ * documentation (the DV format specification is not freely available),
+ * this code may very well contain PAL-specific assumptions.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/gst.h>
+
+#include "gstrtpdvdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY (rtpdvdepay_debug);
+#define GST_CAT_DEFAULT (rtpdvdepay_debug)
+/* Filter signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+};
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-dv")
+    );
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) { \"video\", \"audio\" },"
+        "encoding-name = (string) \"DV\", "
+        "clock-rate = (int) 90000,"
+        "encode = (string) { \"SD-VCR/525-60\", \"SD-VCR/625-50\", \"HD-VCR/1125-60\","
+        "\"HD-VCR/1250-50\", \"SDL-VCR/525-60\", \"SDL-VCR/625-50\","
+        "\"306M/525-60\", \"306M/625-50\", \"314M-25/525-60\","
+        "\"314M-25/625-50\", \"314M-50/525-60\", \"314M-50/625-50\" }"
+        /* optional parameters can't go in the template
+         * "audio = (string) { \"bundled\", \"none\" }"
+         */
+    )
+    );
+
+static GstStateChangeReturn
+gst_rtp_dv_depay_change_state (GstElement * element, GstStateChange transition);
+
+static GstBuffer *gst_rtp_dv_depay_process (GstRTPBaseDepayload * base,
+    GstRTPBuffer * rtp);
+static gboolean gst_rtp_dv_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+
+#define gst_rtp_dv_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPDVDepay, gst_rtp_dv_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+
+static void
+gst_rtp_dv_depay_class_init (GstRTPDVDepayClass * klass)
+{
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class =
+      (GstRTPBaseDepayloadClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (rtpdvdepay_debug, "rtpdvdepay", 0,
+      "DV RTP Depayloader");
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_rtp_dv_depay_change_state);
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP DV Depayloader",
+      "Codec/Depayloader/Network/RTP",
+      "Depayloads DV from RTP packets (RFC 3189)",
+      "Marcel Moreaux <marcelm@spacelabs.nl>, Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasedepayload_class->process_rtp_packet =
+      GST_DEBUG_FUNCPTR (gst_rtp_dv_depay_process);
+  gstrtpbasedepayload_class->set_caps =
+      GST_DEBUG_FUNCPTR (gst_rtp_dv_depay_setcaps);
+}
+
+/* initialize the new element
+ * instantiate pads and add them to element
+ * set functions
+ * initialize structure
+ */
+static void
+gst_rtp_dv_depay_init (GstRTPDVDepay * filter)
+{
+}
+
+static gboolean
+parse_encode (GstRTPDVDepay * rtpdvdepay, const gchar * encode)
+{
+  rtpdvdepay->width = 720;
+  if (!strcmp (encode, "314M-25/525-60")) {
+    rtpdvdepay->frame_size = 240000;
+    rtpdvdepay->height = 480;
+    rtpdvdepay->rate_num = 30000;
+    rtpdvdepay->rate_denom = 1001;
+  } else if (!strcmp (encode, "SD-VCR/525-60")) {
+    rtpdvdepay->frame_size = 120000;
+    rtpdvdepay->height = 480;
+    rtpdvdepay->rate_num = 30000;
+    rtpdvdepay->rate_denom = 1001;
+  } else if (!strcmp (encode, "314M-50/625-50")) {
+    rtpdvdepay->frame_size = 288000;
+    rtpdvdepay->height = 576;
+    rtpdvdepay->rate_num = 25;
+    rtpdvdepay->rate_denom = 1;
+  } else if (!strcmp (encode, "SD-VCR/625-50")) {
+    rtpdvdepay->frame_size = 144000;
+    rtpdvdepay->height = 576;
+    rtpdvdepay->rate_num = 25;
+    rtpdvdepay->rate_denom = 1;
+  } else if (!strcmp (encode, "314M-25/625-50")) {
+    rtpdvdepay->frame_size = 144000;
+    rtpdvdepay->height = 576;
+    rtpdvdepay->rate_num = 25;
+    rtpdvdepay->rate_denom = 1;
+  } else
+    rtpdvdepay->frame_size = -1;
+
+  return rtpdvdepay->frame_size != -1;
+}
+
+static gboolean
+gst_rtp_dv_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstRTPDVDepay *rtpdvdepay;
+  GstCaps *srccaps;
+  gint clock_rate;
+  gboolean systemstream, ret;
+  const gchar *encode, *media;
+
+  rtpdvdepay = GST_RTP_DV_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;         /* default */
+  depayload->clock_rate = clock_rate;
+
+  /* we really need the encode property to figure out the frame size, it's also
+   * required by the spec */
+  if (!(encode = gst_structure_get_string (structure, "encode")))
+    goto no_encode;
+
+  /* figure out the size of one frame */
+  if (!parse_encode (rtpdvdepay, encode))
+    goto unknown_encode;
+
+  /* check the media, this tells us that the stream has video or not */
+  if (!(media = gst_structure_get_string (structure, "media")))
+    goto no_media;
+
+  systemstream = FALSE;
+
+  if (!strcmp (media, "audio")) {
+    /* we need a demuxer for audio only */
+    systemstream = TRUE;
+  } else if (!strcmp (media, "video")) {
+    const gchar *audio;
+
+    /* check the optional audio field, if it's present and set to bundled, we
+     * are dealing with a system stream. */
+    if ((audio = gst_structure_get_string (structure, "audio"))) {
+      if (!strcmp (audio, "bundled"))
+        systemstream = TRUE;
+    }
+  }
+
+  /* allocate accumulator */
+  rtpdvdepay->acc = gst_buffer_new_and_alloc (rtpdvdepay->frame_size);
+
+  /* Initialize the new accumulator frame.
+   * If the previous frame exists, copy that into the accumulator frame.
+   * This way, missing packets in the stream won't show up badly. */
+  gst_buffer_memset (rtpdvdepay->acc, 0, 0, rtpdvdepay->frame_size);
+
+  srccaps = gst_caps_new_simple ("video/x-dv",
+      "systemstream", G_TYPE_BOOLEAN, systemstream,
+      "width", G_TYPE_INT, rtpdvdepay->width,
+      "height", G_TYPE_INT, rtpdvdepay->height,
+      "framerate", GST_TYPE_FRACTION, rtpdvdepay->rate_num,
+      rtpdvdepay->rate_denom, NULL);
+  ret = gst_pad_set_caps (depayload->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  return ret;
+
+  /* ERRORS */
+no_encode:
+  {
+    GST_ERROR_OBJECT (rtpdvdepay, "required encode property not found in caps");
+    return FALSE;
+  }
+unknown_encode:
+  {
+    GST_ERROR_OBJECT (rtpdvdepay, "unknown encode property %s found", encode);
+    return FALSE;
+  }
+no_media:
+  {
+    GST_ERROR_OBJECT (rtpdvdepay, "required media property not found in caps");
+    return FALSE;
+  }
+}
+
+/* A DV frame consists of a bunch of 80-byte DIF blocks.
+ * Each DIF block contains a 3-byte header telling where in the DV frame the
+ * DIF block should go. We use this information to calculate its position.
+ */
+static guint
+calculate_difblock_location (guint8 * block)
+{
+  gint block_type, dif_sequence, dif_block;
+  guint location;
+
+  block_type = block[0] >> 5;
+  dif_sequence = block[1] >> 4;
+  dif_block = block[2];
+
+  location = dif_sequence * 150;
+
+  switch (block_type) {
+    case 0:                    /* Header block, no offset */
+      break;
+    case 1:                    /* Subcode block */
+      location += (1 + dif_block);
+      break;
+    case 2:                    /* VAUX block */
+      location += (3 + dif_block);
+      break;
+    case 3:                    /* Audio block */
+      location += (6 + dif_block * 16);
+      break;
+    case 4:                    /* Video block */
+      location += (7 + (dif_block / 15) + dif_block);
+      break;
+    default:                   /* Something bogus */
+      GST_DEBUG ("UNKNOWN BLOCK");
+      location = -1;
+      break;
+  }
+  return location;
+}
+
+static gboolean
+foreach_metadata_drop (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data)
+{
+  *meta = NULL;
+  return TRUE;
+}
+
+/* Process one RTP packet. Accumulate RTP payload in the proper place in a DV
+ * frame, and return that frame if we detect a new frame, or NULL otherwise.
+ * We assume a DV frame is 144000 bytes. That should accomodate PAL as well as
+ * NTSC.
+ */
+static GstBuffer *
+gst_rtp_dv_depay_process (GstRTPBaseDepayload * base, GstRTPBuffer * rtp)
+{
+  GstBuffer *out = NULL;
+  guint8 *payload;
+  guint32 rtp_ts;
+  guint payload_len, location;
+  GstRTPDVDepay *dvdepay = GST_RTP_DV_DEPAY (base);
+  gboolean marker;
+  GstMapInfo map;
+
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  /* Check if the received packet contains (the start of) a new frame, we do
+   * this by checking the RTP timestamp. */
+  rtp_ts = gst_rtp_buffer_get_timestamp (rtp);
+
+  /* we cannot copy the packet yet if the marker is set, we will do that below
+   * after taking out the data */
+  if (dvdepay->prev_ts != -1 && rtp_ts != dvdepay->prev_ts && !marker) {
+    /* the timestamp changed */
+    GST_DEBUG_OBJECT (dvdepay, "new frame with ts %u, old ts %u", rtp_ts,
+        dvdepay->prev_ts);
+
+    /* return copy of accumulator. */
+    out = gst_buffer_copy (dvdepay->acc);
+    gst_buffer_foreach_meta (dvdepay->acc, foreach_metadata_drop, NULL);
+  }
+
+  /* Extract the payload */
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+  payload = gst_rtp_buffer_get_payload (rtp);
+
+  /* copy all DIF chunks in their place. */
+  gst_buffer_map (dvdepay->acc, &map, GST_MAP_READWRITE);
+  while (payload_len >= 80) {
+    guint offset;
+
+    /* Calculate where in the frame the payload should go */
+    location = calculate_difblock_location (payload);
+
+    if (location < 6) {
+      /* part of a header, set the flag to mark that we have the header. */
+      dvdepay->header_mask |= (1 << location);
+      GST_LOG_OBJECT (dvdepay, "got header at location %d, now %02x", location,
+          dvdepay->header_mask);
+    } else {
+      GST_LOG_OBJECT (dvdepay, "got block at location %d", location);
+    }
+
+    if (location != -1) {
+      /* get the byte offset of the dif block */
+      offset = location * 80;
+
+      /* And copy it in, provided the location is sane. */
+      if (offset <= dvdepay->frame_size - 80) {
+        memcpy (map.data + offset, payload, 80);
+        gst_rtp_copy_meta (GST_ELEMENT_CAST (dvdepay), dvdepay->acc,
+            rtp->buffer, 0);
+      }
+    }
+
+    payload += 80;
+    payload_len -= 80;
+  }
+  gst_buffer_unmap (dvdepay->acc, &map);
+
+  if (marker) {
+    GST_DEBUG_OBJECT (dvdepay, "marker bit complete frame %u", rtp_ts);
+    /* only copy the frame when we have a complete header */
+    if (dvdepay->header_mask == 0x3f) {
+      /* The marker marks the end of a frame that we need to push. The next frame
+       * will change the timestamp but we won't copy the accumulator again because
+       * we set the prev_ts to -1. */
+      out = gst_buffer_copy (dvdepay->acc);
+      gst_buffer_foreach_meta (dvdepay->acc, foreach_metadata_drop, NULL);
+    } else {
+      GST_WARNING_OBJECT (dvdepay, "waiting for frame headers %02x",
+          dvdepay->header_mask);
+    }
+    dvdepay->prev_ts = -1;
+  } else {
+    /* save last timestamp */
+    dvdepay->prev_ts = rtp_ts;
+  }
+  return out;
+}
+
+static void
+gst_rtp_dv_depay_reset (GstRTPDVDepay * depay)
+{
+  if (depay->acc)
+    gst_buffer_unref (depay->acc);
+  depay->acc = NULL;
+
+  depay->prev_ts = -1;
+  depay->header_mask = 0;
+}
+
+static GstStateChangeReturn
+gst_rtp_dv_depay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstRTPDVDepay *depay = GST_RTP_DV_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_dv_depay_reset (depay);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
+      (element, transition), GST_STATE_CHANGE_FAILURE);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_dv_depay_reset (depay);
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_dv_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpdvdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_DV_DEPAY);
+}
diff --git a/gst/rtp/gstrtpdvdepay.h b/gst/rtp/gstrtpdvdepay.h
new file mode 100644
index 0000000..1ce5b97
--- /dev/null
+++ b/gst/rtp/gstrtpdvdepay.h
@@ -0,0 +1,66 @@
+/* Farsight
+ * Copyright (C) 2006 Marcel Moreaux <marcelm@spacelabs.nl>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GSTRTPDVDEPAY_H__
+#define __GSTRTPDVDEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+/* #define's don't like whitespacey bits */
+#define GST_TYPE_RTP_DV_DEPAY (gst_rtp_dv_depay_get_type())
+#define GST_RTP_DV_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_DV_DEPAY,GstRTPDVDepay))
+#define GST_RTP_DV_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_DV_DEPAY,GstRTPDVDepay))
+#define GST_IS_RTP_DV_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_DV_DEPAY))
+#define GST_IS_RTP_DV_DEPAY_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_DV_DEPAY))
+
+typedef struct _GstRTPDVDepay      GstRTPDVDepay;
+typedef struct _GstRTPDVDepayClass GstRTPDVDepayClass;
+
+struct _GstRTPDVDepay
+{
+  GstRTPBaseDepayload parent;
+
+  GstBuffer *acc;
+  guint frame_size;
+  guint32 prev_ts;
+  guint8 header_mask;
+
+  gint width, height;
+  gint rate_num, rate_denom;
+};
+
+struct _GstRTPDVDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_dv_depay_get_type (void);
+
+gboolean gst_rtp_dv_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GSTRTPDVDEPAY_H__ */
diff --git a/gst/rtp/gstrtpdvpay.c b/gst/rtp/gstrtpdvpay.c
new file mode 100644
index 0000000..4408806
--- /dev/null
+++ b/gst/rtp/gstrtpdvpay.c
@@ -0,0 +1,397 @@
+/* Farsight
+ * Copyright (C) 2006 Marcel Moreaux <marcelm@spacelabs.nl>
+ *           (C) 2008 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpdvpay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY (rtpdvpay_debug);
+#define GST_CAT_DEFAULT (rtpdvpay_debug)
+
+#define DEFAULT_MODE GST_DV_PAY_MODE_VIDEO
+enum
+{
+  PROP_0,
+  PROP_MODE
+};
+
+/* takes both system and non-system streams */
+static GstStaticPadTemplate gst_rtp_dv_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-dv")
+    );
+
+static GstStaticPadTemplate gst_rtp_dv_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) { \"video\", \"audio\" } ,"
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "encoding-name = (string) \"DV\", "
+        "clock-rate = (int) 90000,"
+        "encode = (string) { \"SD-VCR/525-60\", \"SD-VCR/625-50\", \"HD-VCR/1125-60\","
+        "\"HD-VCR/1250-50\", \"SDL-VCR/525-60\", \"SDL-VCR/625-50\","
+        "\"306M/525-60\", \"306M/625-50\", \"314M-25/525-60\","
+        "\"314M-25/625-50\", \"314M-50/525-60\", \"314M-50/625-50\" }"
+        /* optional parameters can't go in the template
+         * "audio = (string) { \"bundled\", \"none\" }"
+         */
+    )
+    );
+
+static gboolean gst_rtp_dv_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static GstFlowReturn gst_rtp_dv_pay_handle_buffer (GstRTPBasePayload * payload,
+    GstBuffer * buffer);
+
+#define GST_TYPE_DV_PAY_MODE (gst_dv_pay_mode_get_type())
+static GType
+gst_dv_pay_mode_get_type (void)
+{
+  static GType dv_pay_mode_type = 0;
+  static const GEnumValue dv_pay_modes[] = {
+    {GST_DV_PAY_MODE_VIDEO, "Video only", "video"},
+    {GST_DV_PAY_MODE_BUNDLED, "Video and Audio bundled", "bundled"},
+    {GST_DV_PAY_MODE_AUDIO, "Audio only", "audio"},
+    {0, NULL, NULL},
+  };
+
+  if (!dv_pay_mode_type) {
+    dv_pay_mode_type = g_enum_register_static ("GstDVPayMode", dv_pay_modes);
+  }
+  return dv_pay_mode_type;
+}
+
+
+static void gst_dv_pay_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_dv_pay_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+#define gst_rtp_dv_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPDVPay, gst_rtp_dv_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_dv_pay_class_init (GstRTPDVPayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpdvpay_debug, "rtpdvpay", 0, "DV RTP Payloader");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->set_property = gst_dv_pay_set_property;
+  gobject_class->get_property = gst_dv_pay_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_MODE,
+      g_param_spec_enum ("mode", "Mode",
+          "The payload mode of payloading",
+          GST_TYPE_DV_PAY_MODE, DEFAULT_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_dv_pay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_dv_pay_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP DV Payloader",
+      "Codec/Payloader/Network/RTP",
+      "Payloads DV into RTP packets (RFC 3189)",
+      "Marcel Moreaux <marcelm@spacelabs.nl>, Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_dv_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_dv_pay_handle_buffer;
+}
+
+static void
+gst_rtp_dv_pay_init (GstRTPDVPay * rtpdvpay)
+{
+}
+
+static void
+gst_dv_pay_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstRTPDVPay *rtpdvpay = GST_RTP_DV_PAY (object);
+
+  switch (prop_id) {
+    case PROP_MODE:
+      rtpdvpay->mode = g_value_get_enum (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_dv_pay_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstRTPDVPay *rtpdvpay = GST_RTP_DV_PAY (object);
+
+  switch (prop_id) {
+    case PROP_MODE:
+      g_value_set_enum (value, rtpdvpay->mode);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_rtp_dv_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  /* We don't do anything here, but we could check if it's a system stream and if
+   * it's not, default to sending the video only. We will negotiate downstream
+   * caps when we get to see the first frame. */
+
+  return TRUE;
+}
+
+static gboolean
+gst_dv_pay_negotiate (GstRTPDVPay * rtpdvpay, guint8 * data, gsize size)
+{
+  const gchar *encode, *media;
+  gboolean audio_bundled, res;
+
+  if ((data[3] & 0x80) == 0) {  /* DSF flag */
+    /* it's an NTSC format */
+    if ((data[80 * 5 + 48 + 3] & 0x4) && (data[80 * 5 + 48] == 0x60)) { /* 4:2:2 sampling */
+      /* NTSC 50Mbps */
+      encode = "314M-25/525-60";
+    } else {                    /* 4:1:1 sampling */
+      /* NTSC 25Mbps */
+      encode = "SD-VCR/525-60";
+    }
+  } else {
+    /* it's a PAL format */
+    if ((data[80 * 5 + 48 + 3] & 0x4) && (data[80 * 5 + 48] == 0x60)) { /* 4:2:2 sampling */
+      /* PAL 50Mbps */
+      encode = "314M-50/625-50";
+    } else if ((data[5] & 0x07) == 0) { /* APT flag */
+      /* PAL 25Mbps 4:2:0 */
+      encode = "SD-VCR/625-50";
+    } else
+      /* PAL 25Mbps 4:1:1 */
+      encode = "314M-25/625-50";
+  }
+
+  media = "video";
+  audio_bundled = FALSE;
+
+  switch (rtpdvpay->mode) {
+    case GST_DV_PAY_MODE_AUDIO:
+      media = "audio";
+      break;
+    case GST_DV_PAY_MODE_BUNDLED:
+      audio_bundled = TRUE;
+      break;
+    default:
+      break;
+  }
+  gst_rtp_base_payload_set_options (GST_RTP_BASE_PAYLOAD (rtpdvpay), media,
+      TRUE, "DV", 90000);
+
+  if (audio_bundled) {
+    res = gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpdvpay),
+        "encode", G_TYPE_STRING, encode,
+        "audio", G_TYPE_STRING, "bundled", NULL);
+  } else {
+    res = gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpdvpay),
+        "encode", G_TYPE_STRING, encode, NULL);
+  }
+  return res;
+}
+
+static gboolean
+include_dif (GstRTPDVPay * rtpdvpay, guint8 * data)
+{
+  gint block_type;
+  gboolean res;
+
+  block_type = data[0] >> 5;
+
+  switch (block_type) {
+    case 0:                    /* Header block */
+    case 1:                    /* Subcode block */
+    case 2:                    /* VAUX block */
+      /* always include these blocks */
+      res = TRUE;
+      break;
+    case 3:                    /* Audio block */
+      /* never include audio if we are doing video only */
+      if (rtpdvpay->mode == GST_DV_PAY_MODE_VIDEO)
+        res = FALSE;
+      else
+        res = TRUE;
+      break;
+    case 4:                    /* Video block */
+      /* never include video if we are doing audio only */
+      if (rtpdvpay->mode == GST_DV_PAY_MODE_AUDIO)
+        res = FALSE;
+      else
+        res = TRUE;
+      break;
+    default:                   /* Something bogus, just ignore */
+      res = FALSE;
+      break;
+  }
+  return res;
+}
+
+/* Get a DV frame, chop it up in pieces, and push the pieces to the RTP layer.
+ */
+static GstFlowReturn
+gst_rtp_dv_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRTPDVPay *rtpdvpay;
+  guint max_payload_size;
+  GstBuffer *outbuf;
+  GstFlowReturn ret = GST_FLOW_OK;
+  gint hdrlen;
+  gsize size;
+  GstMapInfo map;
+  guint8 *data;
+  guint8 *dest;
+  guint filled;
+  GstRTPBuffer rtp = { NULL, };
+
+  rtpdvpay = GST_RTP_DV_PAY (basepayload);
+
+  hdrlen = gst_rtp_buffer_calc_header_len (0);
+  /* DV frames are made up from a bunch of DIF blocks. DIF blocks are 80 bytes
+   * each, and we should put an integral number of them in each RTP packet.
+   * Therefore, we round the available room down to the nearest multiple of 80.
+   *
+   * The available room is just the packet MTU, minus the RTP header length. */
+  max_payload_size = ((GST_RTP_BASE_PAYLOAD_MTU (rtpdvpay) - hdrlen) / 80) * 80;
+
+  /* The length of the buffer to transmit. */
+  if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) {
+    GST_ELEMENT_ERROR (rtpdvpay, CORE, FAILED,
+        (NULL), ("Failed to map buffer"));
+    gst_buffer_unref (buffer);
+    return GST_FLOW_ERROR;
+  }
+  data = map.data;
+  size = map.size;
+
+  GST_DEBUG_OBJECT (rtpdvpay,
+      "DV RTP payloader got buffer of %" G_GSIZE_FORMAT
+      " bytes, splitting in %u byte " "payload fragments, at time %"
+      GST_TIME_FORMAT, size, max_payload_size,
+      GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));
+
+  if (!rtpdvpay->negotiated) {
+    gst_dv_pay_negotiate (rtpdvpay, data, size);
+    /* if we have not yet scanned the stream for its type, do so now */
+    rtpdvpay->negotiated = TRUE;
+  }
+
+  outbuf = NULL;
+  dest = NULL;
+  filled = 0;
+
+  /* while we have a complete DIF chunks left */
+  while (size >= 80) {
+    /* Allocate a new buffer, set the timestamp */
+    if (outbuf == NULL) {
+      outbuf = gst_rtp_buffer_new_allocate (max_payload_size, 0, 0);
+      GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buffer);
+
+      if (!gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp)) {
+        gst_buffer_unref (outbuf);
+        GST_ELEMENT_ERROR (rtpdvpay, CORE, FAILED,
+            (NULL), ("Failed to map RTP buffer"));
+        ret = GST_FLOW_ERROR;
+        goto beach;
+      }
+      dest = gst_rtp_buffer_get_payload (&rtp);
+      filled = 0;
+    }
+
+    /* inspect the DIF chunk, if we don't need to include it, skip to the next one. */
+    if (include_dif (rtpdvpay, data)) {
+      /* copy data in packet */
+      memcpy (dest, data, 80);
+
+      dest += 80;
+      filled += 80;
+    }
+
+    /* go to next dif chunk */
+    size -= 80;
+    data += 80;
+
+    /* push out the buffer if the next one would exceed the max packet size or
+     * when we are pushing the last packet */
+    if (filled + 80 > max_payload_size || size < 80) {
+      if (size < 160) {
+        guint hlen;
+
+        /* set marker */
+        gst_rtp_buffer_set_marker (&rtp, TRUE);
+
+        /* shrink buffer to last packet */
+        hlen = gst_rtp_buffer_get_header_len (&rtp);
+        gst_rtp_buffer_set_packet_len (&rtp, hlen + filled);
+      }
+
+      /* Push out the created piece, and check for errors. */
+      gst_rtp_buffer_unmap (&rtp);
+      gst_rtp_copy_meta (GST_ELEMENT_CAST (basepayload), outbuf, buffer, 0);
+      ret = gst_rtp_base_payload_push (basepayload, outbuf);
+      if (ret != GST_FLOW_OK)
+        break;
+
+      outbuf = NULL;
+    }
+  }
+
+beach:
+  gst_buffer_unmap (buffer, &map);
+  gst_buffer_unref (buffer);
+
+  return ret;
+}
+
+gboolean
+gst_rtp_dv_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpdvpay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_DV_PAY);
+}
diff --git a/gst/rtp/gstrtpdvpay.h b/gst/rtp/gstrtpdvpay.h
new file mode 100644
index 0000000..4c250a8
--- /dev/null
+++ b/gst/rtp/gstrtpdvpay.h
@@ -0,0 +1,69 @@
+/* Farsight
+ * Copyright (C) 2006 Marcel Moreaux <marcelm@spacelabs.nl>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GSTRTPDVPAY_H__
+#define __GSTRTPDVPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTPDVPay GstRTPDVPay;
+typedef struct _GstRTPDVPayClass GstRTPDVPayClass;
+
+#define GST_TYPE_RTP_DV_PAY \
+  (gst_rtp_dv_pay_get_type())
+#define GST_RTP_DV_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_DV_PAY,GstRTPDVPay))
+#define GST_RTP_DV_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_DV_PAY,GstRTPDVPay))
+#define GST_IS_RTP_DV_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_DV_PAY))
+#define GST_IS_RTP_DV_PAY_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_DV_PAY))
+
+typedef enum
+{
+  GST_DV_PAY_MODE_VIDEO,
+  GST_DV_PAY_MODE_BUNDLED,
+  GST_DV_PAY_MODE_AUDIO
+} GstDVPayMode;
+
+struct _GstRTPDVPay
+{
+  GstRTPBasePayload payload;
+
+  gboolean negotiated;
+  GstDVPayMode mode;
+};
+
+struct _GstRTPDVPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_dv_pay_get_type (void);
+
+gboolean gst_rtp_dv_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GSTRTPDVPAY_H__ */
diff --git a/gst/rtp/gstrtpg722depay.c b/gst/rtp/gstrtpg722depay.c
new file mode 100644
index 0000000..5a25eef
--- /dev/null
+++ b/gst/rtp/gstrtpg722depay.c
@@ -0,0 +1,262 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/audio/audio.h>
+
+#include "gstrtpg722depay.h"
+#include "gstrtpchannels.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpg722depay_debug);
+#define GST_CAT_DEFAULT (rtpg722depay_debug)
+
+static GstStaticPadTemplate gst_rtp_g722_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/G722, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+    );
+
+static GstStaticPadTemplate gst_rtp_g722_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", " "clock-rate = (int) 8000, "
+        /* "channels = (int) [1, MAX]"  */
+        /* "channel-order = (string) ANY" */
+        "encoding-name = (string) \"G722\";"
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_G722_STRING ", "
+        "clock-rate = (int) [ 1, MAX ]"
+        /* "channels = (int) [1, MAX]" */
+        /* "emphasis = (string) ANY" */
+        /* "channel-order = (string) ANY" */
+    )
+    );
+
+#define gst_rtp_g722_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpG722Depay, gst_rtp_g722_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_g722_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_g722_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+static void
+gst_rtp_g722_depay_class_init (GstRtpG722DepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpg722depay_debug, "rtpg722depay", 0,
+      "G722 RTP Depayloader");
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g722_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g722_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP audio depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts G722 audio from RTP packets",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasedepayload_class->set_caps = gst_rtp_g722_depay_setcaps;
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_g722_depay_process;
+}
+
+static void
+gst_rtp_g722_depay_init (GstRtpG722Depay * rtpg722depay)
+{
+}
+
+static gint
+gst_rtp_g722_depay_parse_int (GstStructure * structure, const gchar * field,
+    gint def)
+{
+  const gchar *str;
+  gint res;
+
+  if ((str = gst_structure_get_string (structure, field)))
+    return atoi (str);
+
+  if (gst_structure_get_int (structure, field, &res))
+    return res;
+
+  return def;
+}
+
+static gboolean
+gst_rtp_g722_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstRtpG722Depay *rtpg722depay;
+  gint clock_rate, payload, samplerate;
+  gint channels;
+  GstCaps *srccaps;
+  gboolean res;
+#if 0
+  const gchar *channel_order;
+  const GstRTPChannelOrder *order;
+#endif
+
+  rtpg722depay = GST_RTP_G722_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  payload = 96;
+  gst_structure_get_int (structure, "payload", &payload);
+  switch (payload) {
+    case GST_RTP_PAYLOAD_G722:
+      channels = 1;
+      clock_rate = 8000;
+      samplerate = 16000;
+      break;
+    default:
+      /* no fixed mapping, we need clock-rate */
+      channels = 0;
+      clock_rate = 0;
+      samplerate = 0;
+      break;
+  }
+
+  /* caps can overwrite defaults */
+  clock_rate =
+      gst_rtp_g722_depay_parse_int (structure, "clock-rate", clock_rate);
+  if (clock_rate == 0)
+    goto no_clockrate;
+
+  if (clock_rate == 8000)
+    samplerate = 16000;
+
+  if (samplerate == 0)
+    samplerate = clock_rate;
+
+  channels =
+      gst_rtp_g722_depay_parse_int (structure, "encoding-params", channels);
+  if (channels == 0) {
+    channels = gst_rtp_g722_depay_parse_int (structure, "channels", channels);
+    if (channels == 0) {
+      /* channels defaults to 1 otherwise */
+      channels = 1;
+    }
+  }
+
+  depayload->clock_rate = clock_rate;
+  rtpg722depay->rate = samplerate;
+  rtpg722depay->channels = channels;
+
+  srccaps = gst_caps_new_simple ("audio/G722",
+      "rate", G_TYPE_INT, samplerate, "channels", G_TYPE_INT, channels, NULL);
+
+  /* FIXME: Do something with the channel order */
+#if 0
+  /* add channel positions */
+  channel_order = gst_structure_get_string (structure, "channel-order");
+
+  order = gst_rtp_channels_get_by_order (channels, channel_order);
+  if (order) {
+    gst_audio_set_channel_positions (gst_caps_get_structure (srccaps, 0),
+        order->pos);
+  } else {
+    GstAudioChannelPosition *pos;
+
+    GST_ELEMENT_WARNING (rtpg722depay, STREAM, DECODE,
+        (NULL), ("Unknown channel order '%s' for %d channels",
+            GST_STR_NULL (channel_order), channels));
+    /* create default NONE layout */
+    pos = gst_rtp_channels_create_default (channels);
+    gst_audio_set_channel_positions (gst_caps_get_structure (srccaps, 0), pos);
+    g_free (pos);
+  }
+#endif
+
+  res = gst_pad_set_caps (depayload->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  return res;
+
+  /* ERRORS */
+no_clockrate:
+  {
+    GST_ERROR_OBJECT (depayload, "no clock-rate specified");
+    return FALSE;
+  }
+}
+
+static GstBuffer *
+gst_rtp_g722_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpG722Depay *rtpg722depay;
+  GstBuffer *outbuf;
+  gint payload_len;
+  gboolean marker;
+
+  rtpg722depay = GST_RTP_G722_DEPAY (depayload);
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  if (payload_len <= 0)
+    goto empty_packet;
+
+  GST_DEBUG_OBJECT (rtpg722depay, "got payload of %d bytes", payload_len);
+
+  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  if (marker && outbuf) {
+    /* mark talk spurt with RESYNC */
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+  }
+
+  if (outbuf) {
+    gst_rtp_drop_non_audio_meta (rtpg722depay, outbuf);
+  }
+
+  return outbuf;
+
+  /* ERRORS */
+empty_packet:
+  {
+    GST_ELEMENT_WARNING (rtpg722depay, STREAM, DECODE,
+        ("Empty Payload."), (NULL));
+    return NULL;
+  }
+}
+
+gboolean
+gst_rtp_g722_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpg722depay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_G722_DEPAY);
+}
diff --git a/gst/rtp/gstrtpg722depay.h b/gst/rtp/gstrtpg722depay.h
new file mode 100644
index 0000000..8b6ffa0
--- /dev/null
+++ b/gst/rtp/gstrtpg722depay.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_G722_DEPAY_H__
+#define __GST_RTP_G722_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+/* Standard macros for defining types for this element.  */
+#define GST_TYPE_RTP_G722_DEPAY \
+  (gst_rtp_g722_depay_get_type())
+#define GST_RTP_G722_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G722_DEPAY,GstRtpG722Depay))
+#define GST_RTP_G722_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G722_DEPAY,GstRtpG722DepayClass))
+#define GST_IS_RTP_G722_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G722_DEPAY))
+#define GST_IS_RTP_G722_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G722_DEPAY))
+
+typedef struct _GstRtpG722Depay GstRtpG722Depay;
+typedef struct _GstRtpG722DepayClass GstRtpG722DepayClass;
+
+/* Definition of structure storing data for this element. */
+struct _GstRtpG722Depay
+{
+  GstRTPBaseDepayload depayload;
+
+  guint rate;
+  guint channels;
+};
+
+/* Standard definition defining a class for this element. */
+struct _GstRtpG722DepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_g722_depay_get_type (void);
+
+gboolean gst_rtp_g722_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_G722_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpg722pay.c b/gst/rtp/gstrtpg722pay.c
new file mode 100644
index 0000000..00b7f59
--- /dev/null
+++ b/gst/rtp/gstrtpg722pay.c
@@ -0,0 +1,237 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/audio/audio.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpg722pay.h"
+#include "gstrtpchannels.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpg722pay_debug);
+#define GST_CAT_DEFAULT (rtpg722pay_debug)
+
+static GstStaticPadTemplate gst_rtp_g722_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/G722, " "rate = (int) 16000, " "channels = (int) 1")
+    );
+
+static GstStaticPadTemplate gst_rtp_g722_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "encoding-name = (string) \"G722\", "
+        "payload = (int) " GST_RTP_PAYLOAD_G722_STRING ", "
+        "encoding-params = (string) 1, "
+        "clock-rate = (int) 8000; "
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "encoding-name = (string) \"G722\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "encoding-params = (string) 1, "
+        "clock-rate = (int) 8000")
+    );
+
+static gboolean gst_rtp_g722_pay_setcaps (GstRTPBasePayload * basepayload,
+    GstCaps * caps);
+static GstCaps *gst_rtp_g722_pay_getcaps (GstRTPBasePayload * rtppayload,
+    GstPad * pad, GstCaps * filter);
+
+#define gst_rtp_g722_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpG722Pay, gst_rtp_g722_pay,
+    GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_g722_pay_class_init (GstRtpG722PayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpg722pay_debug, "rtpg722pay", 0,
+      "G722 RTP Payloader");
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g722_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g722_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP audio payloader", "Codec/Payloader/Network/RTP",
+      "Payload-encode Raw audio into RTP packets (RFC 3551)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_g722_pay_setcaps;
+  gstrtpbasepayload_class->get_caps = gst_rtp_g722_pay_getcaps;
+}
+
+static void
+gst_rtp_g722_pay_init (GstRtpG722Pay * rtpg722pay)
+{
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpg722pay);
+
+  GST_RTP_BASE_PAYLOAD (rtpg722pay)->pt = GST_RTP_PAYLOAD_G722;
+
+  /* tell rtpbaseaudiopayload that this is a sample based codec */
+  gst_rtp_base_audio_payload_set_sample_based (rtpbaseaudiopayload);
+}
+
+static gboolean
+gst_rtp_g722_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+  GstRtpG722Pay *rtpg722pay;
+  GstStructure *structure;
+  gint rate, channels, clock_rate;
+  gboolean res;
+  gchar *params;
+#if 0
+  GstAudioChannelPosition *pos;
+  const GstRTPChannelOrder *order;
+#endif
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (basepayload);
+  rtpg722pay = GST_RTP_G722_PAY (basepayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  /* first parse input caps */
+  if (!gst_structure_get_int (structure, "rate", &rate))
+    goto no_rate;
+
+  if (!gst_structure_get_int (structure, "channels", &channels))
+    goto no_channels;
+
+  /* FIXME: Do something with the channel positions */
+#if 0
+  /* get the channel order */
+  pos = gst_audio_get_channel_positions (structure);
+  if (pos)
+    order = gst_rtp_channels_get_by_pos (channels, pos);
+  else
+    order = NULL;
+#endif
+
+  /* Clock rate is always 8000 Hz for G722 according to
+   * RFC 3551 although the sampling rate is 16000 Hz */
+  clock_rate = 8000;
+
+  gst_rtp_base_payload_set_options (basepayload, "audio",
+      basepayload->pt != GST_RTP_PAYLOAD_G722, "G722", clock_rate);
+  params = g_strdup_printf ("%d", channels);
+
+#if 0
+  if (!order && channels > 2) {
+    GST_ELEMENT_WARNING (rtpg722pay, STREAM, DECODE,
+        (NULL), ("Unknown channel order for %d channels", channels));
+  }
+
+  if (order && order->name) {
+    res = gst_rtp_base_payload_set_outcaps (basepayload,
+        "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
+        channels, "channel-order", G_TYPE_STRING, order->name, NULL);
+  } else {
+#endif
+    res = gst_rtp_base_payload_set_outcaps (basepayload,
+        "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
+        channels, NULL);
+#if 0
+  }
+#endif
+
+  g_free (params);
+#if 0
+  g_free (pos);
+#endif
+
+  rtpg722pay->rate = rate;
+  rtpg722pay->channels = channels;
+
+  /* bits-per-sample is 4 * channels for G722, but as the RTP clock runs at
+   * half speed (8 instead of 16 khz), pretend it's 8 bits per sample
+   * channels. */
+  gst_rtp_base_audio_payload_set_samplebits_options (rtpbaseaudiopayload,
+      8 * rtpg722pay->channels);
+
+  return res;
+
+  /* ERRORS */
+no_rate:
+  {
+    GST_DEBUG_OBJECT (rtpg722pay, "no rate given");
+    return FALSE;
+  }
+no_channels:
+  {
+    GST_DEBUG_OBJECT (rtpg722pay, "no channels given");
+    return FALSE;
+  }
+}
+
+static GstCaps *
+gst_rtp_g722_pay_getcaps (GstRTPBasePayload * rtppayload, GstPad * pad,
+    GstCaps * filter)
+{
+  GstCaps *otherpadcaps;
+  GstCaps *caps;
+
+  otherpadcaps = gst_pad_get_allowed_caps (rtppayload->srcpad);
+  caps = gst_pad_get_pad_template_caps (pad);
+
+  if (otherpadcaps) {
+    if (!gst_caps_is_empty (otherpadcaps)) {
+      caps = gst_caps_make_writable (caps);
+      gst_caps_set_simple (caps, "channels", G_TYPE_INT, 1, NULL);
+      gst_caps_set_simple (caps, "rate", G_TYPE_INT, 16000, NULL);
+    }
+    gst_caps_unref (otherpadcaps);
+  }
+
+  if (filter) {
+    GstCaps *tmp;
+
+    GST_DEBUG_OBJECT (rtppayload, "Intersect %" GST_PTR_FORMAT " and filter %"
+        GST_PTR_FORMAT, caps, filter);
+    tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    caps = tmp;
+  }
+
+  return caps;
+}
+
+gboolean
+gst_rtp_g722_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpg722pay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_G722_PAY);
+}
diff --git a/gst/rtp/gstrtpg722pay.h b/gst/rtp/gstrtpg722pay.h
new file mode 100644
index 0000000..f238286
--- /dev/null
+++ b/gst/rtp/gstrtpg722pay.h
@@ -0,0 +1,61 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_G722_PAY_H__
+#define __GST_RTP_G722_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_G722_PAY \
+  (gst_rtp_g722_pay_get_type())
+#define GST_RTP_G722_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G722_PAY,GstRtpG722Pay))
+#define GST_RTP_G722_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G722_PAY,GstRtpG722PayClass))
+#define GST_IS_RTP_G722_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G722_PAY))
+#define GST_IS_RTP_G722_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G722_PAY))
+
+typedef struct _GstRtpG722Pay GstRtpG722Pay;
+typedef struct _GstRtpG722PayClass GstRtpG722PayClass;
+
+struct _GstRtpG722Pay
+{
+  GstRTPBaseAudioPayload payload;
+
+  gint rate;
+  gint channels;
+};
+
+struct _GstRtpG722PayClass
+{
+  GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_g722_pay_get_type (void);
+
+gboolean gst_rtp_g722_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_G722_PAY_H__ */
diff --git a/gst/rtp/gstrtpg723depay.c b/gst/rtp/gstrtpg723depay.c
new file mode 100644
index 0000000..901d9ae
--- /dev/null
+++ b/gst/rtp/gstrtpg723depay.c
@@ -0,0 +1,223 @@
+/* GStreamer
+ *
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include "gstrtpg723depay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpg723depay_debug);
+#define GST_CAT_DEFAULT (rtpg723depay_debug)
+
+
+/* references:
+ *
+ * RFC 3551 (4.5.3)
+ */
+
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0
+};
+
+/* input is an RTP packet
+ *
+ */
+static GstStaticPadTemplate gst_rtp_g723_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) 8000, "
+        "encoding-name = (string) \"G723\"; "
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_G723_STRING ", "
+        "clock-rate = (int) 8000")
+    );
+
+static GstStaticPadTemplate gst_rtp_g723_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/G723, " "channels = (int) 1," "rate = (int) 8000")
+    );
+
+static gboolean gst_rtp_g723_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_g723_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+#define gst_rtp_g723_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpG723Depay, gst_rtp_g723_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_g723_depay_class_init (GstRtpG723DepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpg723depay_debug, "rtpg723depay", 0,
+      "G.723 RTP Depayloader");
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g723_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g723_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP G.723 depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts G.723 audio from RTP packets (RFC 3551)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_g723_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_g723_depay_setcaps;
+}
+
+static void
+gst_rtp_g723_depay_init (GstRtpG723Depay * rtpg723depay)
+{
+  GstRTPBaseDepayload *depayload;
+
+  depayload = GST_RTP_BASE_DEPAYLOAD (rtpg723depay);
+
+  gst_pad_use_fixed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload));
+}
+
+static gboolean
+gst_rtp_g723_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstCaps *srccaps;
+  GstRtpG723Depay *rtpg723depay;
+  const gchar *params;
+  gint clock_rate, channels;
+  gboolean ret;
+
+  rtpg723depay = GST_RTP_G723_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!(params = gst_structure_get_string (structure, "encoding-params")))
+    channels = 1;
+  else {
+    channels = atoi (params);
+  }
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 8000;
+
+  if (channels != 1)
+    goto wrong_channels;
+
+  if (clock_rate != 8000)
+    goto wrong_clock_rate;
+
+  depayload->clock_rate = clock_rate;
+
+  srccaps = gst_caps_new_simple ("audio/G723",
+      "channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, clock_rate, NULL);
+  ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+  gst_caps_unref (srccaps);
+
+  return ret;
+
+  /* ERRORS */
+wrong_channels:
+  {
+    GST_DEBUG_OBJECT (rtpg723depay, "expected 1 channel, got %d", channels);
+    return FALSE;
+  }
+wrong_clock_rate:
+  {
+    GST_DEBUG_OBJECT (rtpg723depay, "expected 8000 clock-rate, got %d",
+        clock_rate);
+    return FALSE;
+  }
+}
+
+
+static GstBuffer *
+gst_rtp_g723_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpG723Depay *rtpg723depay;
+  GstBuffer *outbuf = NULL;
+  gint payload_len;
+  gboolean marker;
+
+  rtpg723depay = GST_RTP_G723_DEPAY (depayload);
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  /* At least 4 bytes */
+  if (payload_len < 4)
+    goto too_small;
+
+  GST_LOG_OBJECT (rtpg723depay, "payload len %d", payload_len);
+
+  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  if (marker) {
+    /* marker bit starts talkspurt */
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+  }
+
+  GST_LOG_OBJECT (depayload, "pushing buffer of size %" G_GSIZE_FORMAT,
+      gst_buffer_get_size (outbuf));
+
+  return outbuf;
+
+  /* ERRORS */
+too_small:
+  {
+    GST_ELEMENT_WARNING (rtpg723depay, STREAM, DECODE,
+        (NULL), ("G723 RTP payload too small (%d)", payload_len));
+    goto bad_packet;
+  }
+bad_packet:
+  {
+    /* no fatal error */
+    return NULL;
+  }
+}
+
+gboolean
+gst_rtp_g723_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpg723depay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_G723_DEPAY);
+}
diff --git a/gst/rtp/gstrtpg723depay.h b/gst/rtp/gstrtpg723depay.h
new file mode 100644
index 0000000..dd942b3
--- /dev/null
+++ b/gst/rtp/gstrtpg723depay.h
@@ -0,0 +1,59 @@
+/* GStreamer
+ *
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_G723_DEPAY_H__
+#define __GST_RTP_G723_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_G723_DEPAY \
+  (gst_rtp_g723_depay_get_type())
+#define GST_RTP_G723_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G723_DEPAY,GstRtpG723Depay))
+#define GST_RTP_G723_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G723_DEPAY,GstRtpG723DepayClass))
+#define GST_IS_RTP_G723_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G723_DEPAY))
+#define GST_IS_RTP_G723_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G723_DEPAY))
+
+typedef struct _GstRtpG723Depay GstRtpG723Depay;
+typedef struct _GstRtpG723DepayClass GstRtpG723DepayClass;
+
+struct _GstRtpG723Depay
+{
+  GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpG723DepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_g723_depay_get_type (void);
+
+gboolean gst_rtp_g723_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_G723_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpg723pay.c b/gst/rtp/gstrtpg723pay.c
new file mode 100644
index 0000000..cb6dff5
--- /dev/null
+++ b/gst/rtp/gstrtpg723pay.c
@@ -0,0 +1,307 @@
+/* GStreamer
+ * Copyright (C) <2007> Nokia Corporation
+ * Copyright (C) <2007> Collabora Ltd
+ *  @author: Olivier Crete <olivier.crete@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/base/gstadapter.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpg723pay.h"
+#include "gstrtputils.h"
+
+#define G723_FRAME_DURATION (30 * GST_MSECOND)
+
+static gboolean gst_rtp_g723_pay_set_caps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static GstFlowReturn gst_rtp_g723_pay_handle_buffer (GstRTPBasePayload *
+    payload, GstBuffer * buf);
+
+static GstStaticPadTemplate gst_rtp_g723_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/G723, "     /* according to RFC 3551 */
+        "channels = (int) 1, " "rate = (int) 8000")
+    );
+
+static GstStaticPadTemplate gst_rtp_g723_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_G723_STRING ", "
+        "clock-rate = (int) 8000, "
+        "encoding-name = (string) \"G723\"; "
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 8000, " "encoding-name = (string) \"G723\"")
+    );
+
+static void gst_rtp_g723_pay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_g723_pay_change_state (GstElement * element,
+    GstStateChange transition);
+
+#define gst_rtp_g723_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPG723Pay, gst_rtp_g723_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_g723_pay_class_init (GstRTPG723PayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *payload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  payload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_g723_pay_finalize;
+
+  gstelement_class->change_state = gst_rtp_g723_pay_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g723_pay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g723_pay_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP G.723 payloader", "Codec/Payloader/Network/RTP",
+      "Packetize G.723 audio into RTP packets",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  payload_class->set_caps = gst_rtp_g723_pay_set_caps;
+  payload_class->handle_buffer = gst_rtp_g723_pay_handle_buffer;
+}
+
+static void
+gst_rtp_g723_pay_init (GstRTPG723Pay * pay)
+{
+  GstRTPBasePayload *payload = GST_RTP_BASE_PAYLOAD (pay);
+
+  pay->adapter = gst_adapter_new ();
+
+  payload->pt = GST_RTP_PAYLOAD_G723;
+}
+
+static void
+gst_rtp_g723_pay_finalize (GObject * object)
+{
+  GstRTPG723Pay *pay;
+
+  pay = GST_RTP_G723_PAY (object);
+
+  g_object_unref (pay->adapter);
+  pay->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static gboolean
+gst_rtp_g723_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  gboolean res;
+
+  gst_rtp_base_payload_set_options (payload, "audio",
+      payload->pt != GST_RTP_PAYLOAD_G723, "G723", 8000);
+  res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+  return res;
+}
+
+static GstFlowReturn
+gst_rtp_g723_pay_flush (GstRTPG723Pay * pay)
+{
+  GstBuffer *outbuf, *payload_buf;
+  GstFlowReturn ret;
+  guint avail;
+  GstRTPBuffer rtp = { NULL };
+
+  avail = gst_adapter_available (pay->adapter);
+
+  outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+
+  gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+  GST_BUFFER_PTS (outbuf) = pay->timestamp;
+  GST_BUFFER_DURATION (outbuf) = pay->duration;
+
+  /* copy G723 data as payload */
+  payload_buf = gst_adapter_take_buffer_fast (pay->adapter, avail);
+
+  pay->timestamp = GST_CLOCK_TIME_NONE;
+  pay->duration = 0;
+
+  /* set discont and marker */
+  if (pay->discont) {
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+    gst_rtp_buffer_set_marker (&rtp, TRUE);
+    pay->discont = FALSE;
+  }
+  gst_rtp_buffer_unmap (&rtp);
+  gst_rtp_copy_audio_meta (pay, outbuf, payload_buf);
+
+  outbuf = gst_buffer_append (outbuf, payload_buf);
+
+  ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (pay), outbuf);
+
+  return ret;
+}
+
+/* 00    high-rate speech (6.3 kb/s)            24
+ * 01    low-rate speech  (5.3 kb/s)            20
+ * 10    SID frame                               4
+ * 11    reserved                                0  */
+static const guint size_tab[4] = {
+  24, 20, 4, 0
+};
+
+static GstFlowReturn
+gst_rtp_g723_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buf)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstMapInfo map;
+  guint8 HDR;
+  GstRTPG723Pay *pay;
+  GstClockTime packet_dur, timestamp;
+  guint payload_len, packet_len;
+
+  pay = GST_RTP_G723_PAY (payload);
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  timestamp = GST_BUFFER_PTS (buf);
+
+  if (GST_BUFFER_IS_DISCONT (buf)) {
+    /* flush everything on discont */
+    gst_adapter_clear (pay->adapter);
+    pay->timestamp = GST_CLOCK_TIME_NONE;
+    pay->duration = 0;
+    pay->discont = TRUE;
+  }
+
+  /* should be one of these sizes */
+  if (map.size != 4 && map.size != 20 && map.size != 24)
+    goto invalid_size;
+
+  /* check size by looking at the header bits */
+  HDR = map.data[0] & 0x3;
+  if (size_tab[HDR] != map.size)
+    goto wrong_size;
+
+  /* calculate packet size and duration */
+  payload_len = gst_adapter_available (pay->adapter) + map.size;
+  packet_dur = pay->duration + G723_FRAME_DURATION;
+  packet_len = gst_rtp_buffer_calc_packet_len (payload_len, 0, 0);
+
+  if (gst_rtp_base_payload_is_filled (payload, packet_len, packet_dur)) {
+    /* size or duration would overflow the packet, flush the queued data */
+    ret = gst_rtp_g723_pay_flush (pay);
+  }
+
+  /* update timestamp, we keep the timestamp for the first packet in the adapter
+   * but are able to calculate it from next packets. */
+  if (timestamp != GST_CLOCK_TIME_NONE && pay->timestamp == GST_CLOCK_TIME_NONE) {
+    if (timestamp > pay->duration)
+      pay->timestamp = timestamp - pay->duration;
+    else
+      pay->timestamp = 0;
+  }
+  gst_buffer_unmap (buf, &map);
+
+  /* add packet to the queue */
+  gst_adapter_push (pay->adapter, buf);
+  pay->duration = packet_dur;
+
+  /* check if we can flush now */
+  if (pay->duration >= payload->min_ptime) {
+    ret = gst_rtp_g723_pay_flush (pay);
+  }
+
+  return ret;
+
+  /* WARNINGS */
+invalid_size:
+  {
+    GST_ELEMENT_WARNING (pay, STREAM, WRONG_TYPE,
+        ("Invalid input buffer size"),
+        ("Input size should be 4, 20 or 24, got %" G_GSIZE_FORMAT, map.size));
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    return GST_FLOW_OK;
+  }
+wrong_size:
+  {
+    GST_ELEMENT_WARNING (pay, STREAM, WRONG_TYPE,
+        ("Wrong input buffer size"),
+        ("Expected input buffer size %u but got %" G_GSIZE_FORMAT,
+            size_tab[HDR], map.size));
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    return GST_FLOW_OK;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_g723_pay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstRTPG723Pay *pay;
+
+  pay = GST_RTP_G723_PAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_adapter_clear (pay->adapter);
+      pay->timestamp = GST_CLOCK_TIME_NONE;
+      pay->duration = 0;
+      pay->discont = TRUE;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_adapter_clear (pay->adapter);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+/*Plugin init functions*/
+gboolean
+gst_rtp_g723_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpg723pay", GST_RANK_SECONDARY,
+      gst_rtp_g723_pay_get_type ());
+}
diff --git a/gst/rtp/gstrtpg723pay.h b/gst/rtp/gstrtpg723pay.h
new file mode 100644
index 0000000..3780741
--- /dev/null
+++ b/gst/rtp/gstrtpg723pay.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <2007> Nokia Corporation
+ * Copyright (C) <2007> Collabora Ltd
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_G723_PAY_H__
+#define __GST_RTP_G723_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_G723_PAY \
+  (gst_rtp_g723_pay_get_type())
+#define GST_RTP_G723_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G723_PAY,GstRTPG723Pay))
+#define GST_RTP_G723_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G723_PAY,GstRTPG723PayClass))
+#define GST_IS_RTP_G723_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G723_PAY))
+#define GST_IS_RTP_G723_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G723_PAY))
+
+typedef struct _GstRTPG723Pay GstRTPG723Pay;
+typedef struct _GstRTPG723PayClass GstRTPG723PayClass;
+
+struct _GstRTPG723Pay
+{
+  GstRTPBasePayload payload;
+
+  GstAdapter  *adapter;
+  GstClockTime duration;
+  GstClockTime timestamp;
+  gboolean discont;
+};
+
+struct _GstRTPG723PayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_g723_pay_get_type (void);
+
+gboolean gst_rtp_g723_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_G723_PAY_H__ */
diff --git a/gst/rtp/gstrtpg726depay.c b/gst/rtp/gstrtpg726depay.c
new file mode 100644
index 0000000..7af1928
--- /dev/null
+++ b/gst/rtp/gstrtpg726depay.c
@@ -0,0 +1,393 @@
+/* GStreamer
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2005 Edgard Lima <edgard.lima@gmail.com>
+ * Copyright (C) 2005 Zeeshan Ali <zeenix@gmail.com>
+ * Copyright (C) 2008 Axis Communications <dev-gstreamer@axis.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpg726depay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpg726depay_debug);
+#define GST_CAT_DEFAULT (rtpg726depay_debug)
+
+#define DEFAULT_BIT_RATE 32000
+#define DEFAULT_BLOCK_ALIGN 4
+#define SAMPLE_RATE 8000
+#define LAYOUT_G726 "g726"
+
+/* RtpG726Depay signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+#define DEFAULT_FORCE_AAL2	TRUE
+
+enum
+{
+  PROP_0,
+  PROP_FORCE_AAL2
+};
+
+static GstStaticPadTemplate gst_rtp_g726_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "encoding-name = (string) { \"G726\", \"G726-16\", \"G726-24\", \"G726-32\", \"G726-40\", "
+        "\"AAL2-G726-16\", \"AAL2-G726-24\", \"AAL2-G726-32\", \"AAL2-G726-40\" }, "
+        "clock-rate = (int) 8000;")
+    );
+
+static GstStaticPadTemplate gst_rtp_g726_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-adpcm, "
+        "channels = (int) 1, "
+        "rate = (int) 8000, "
+        "bitrate = (int) { 16000, 24000, 32000, 40000 }, "
+        "block_align = (int) { 2, 3, 4, 5 }, " "layout = (string) \"g726\"")
+    );
+
+static void gst_rtp_g726_depay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_rtp_g726_depay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+
+static GstBuffer *gst_rtp_g726_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+static gboolean gst_rtp_g726_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+
+#define gst_rtp_g726_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpG726Depay, gst_rtp_g726_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_g726_depay_class_init (GstRtpG726DepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpg726depay_debug, "rtpg726depay", 0,
+      "G.726 RTP Depayloader");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->set_property = gst_rtp_g726_depay_set_property;
+  gobject_class->get_property = gst_rtp_g726_depay_get_property;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FORCE_AAL2,
+      g_param_spec_boolean ("force-aal2", "Force AAL2",
+          "Force AAL2 decoding for compatibility with bad payloaders",
+          DEFAULT_FORCE_AAL2, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g726_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g726_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP G.726 depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts G.726 audio from RTP packets",
+      "Axis Communications <dev-gstreamer@axis.com>");
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_g726_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_g726_depay_setcaps;
+}
+
+static void
+gst_rtp_g726_depay_init (GstRtpG726Depay * rtpG726depay)
+{
+  GstRTPBaseDepayload *depayload;
+
+  depayload = GST_RTP_BASE_DEPAYLOAD (rtpG726depay);
+
+  gst_pad_use_fixed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload));
+
+  rtpG726depay->force_aal2 = DEFAULT_FORCE_AAL2;
+}
+
+static gboolean
+gst_rtp_g726_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstCaps *srccaps;
+  GstStructure *structure;
+  gboolean ret;
+  gint clock_rate;
+  const gchar *encoding_name;
+  GstRtpG726Depay *depay;
+
+  depay = GST_RTP_G726_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 8000;          /* default */
+  depayload->clock_rate = clock_rate;
+
+  depay->aal2 = FALSE;
+  encoding_name = gst_structure_get_string (structure, "encoding-name");
+  if (encoding_name == NULL || g_ascii_strcasecmp (encoding_name, "G726") == 0) {
+    depay->bitrate = DEFAULT_BIT_RATE;
+    depay->block_align = DEFAULT_BLOCK_ALIGN;
+  } else {
+    if (g_str_has_prefix (encoding_name, "AAL2-")) {
+      depay->aal2 = TRUE;
+      encoding_name += 5;
+    }
+    if (g_ascii_strcasecmp (encoding_name, "G726-16") == 0) {
+      depay->bitrate = 16000;
+      depay->block_align = 2;
+    } else if (g_ascii_strcasecmp (encoding_name, "G726-24") == 0) {
+      depay->bitrate = 24000;
+      depay->block_align = 3;
+    } else if (g_ascii_strcasecmp (encoding_name, "G726-32") == 0) {
+      depay->bitrate = 32000;
+      depay->block_align = 4;
+    } else if (g_ascii_strcasecmp (encoding_name, "G726-40") == 0) {
+      depay->bitrate = 40000;
+      depay->block_align = 5;
+    } else
+      goto unknown_encoding;
+  }
+
+  GST_DEBUG ("RTP G.726 depayloader, bitrate set to %d\n", depay->bitrate);
+
+  srccaps = gst_caps_new_simple ("audio/x-adpcm",
+      "channels", G_TYPE_INT, 1,
+      "rate", G_TYPE_INT, clock_rate,
+      "bitrate", G_TYPE_INT, depay->bitrate,
+      "block_align", G_TYPE_INT, depay->block_align,
+      "layout", G_TYPE_STRING, LAYOUT_G726, NULL);
+
+  ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+  gst_caps_unref (srccaps);
+
+  return ret;
+
+  /* ERRORS */
+unknown_encoding:
+  {
+    GST_WARNING ("Could not determine bitrate from encoding-name (%s)",
+        encoding_name);
+    return FALSE;
+  }
+}
+
+
+static GstBuffer *
+gst_rtp_g726_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpG726Depay *depay;
+  GstBuffer *outbuf = NULL;
+  gboolean marker;
+
+  depay = GST_RTP_G726_DEPAY (depayload);
+
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+      gst_buffer_get_size (rtp->buffer), marker,
+      gst_rtp_buffer_get_timestamp (rtp), gst_rtp_buffer_get_seq (rtp));
+
+  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;
+    gst_rtp_drop_non_audio_meta (depay, outbuf);
+  } else {
+    guint8 *in, *out, tmp;
+    guint len;
+    GstMapInfo map;
+
+    in = gst_rtp_buffer_get_payload (rtp);
+    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);
+
+    gst_rtp_drop_non_audio_meta (depay, outbuf);
+
+    gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+    out = map.data;
+
+    /* we need to reshuffle the bytes, input is always of the form
+     * A B C D ... with the number of bits depending on the bitrate. */
+    switch (depay->bitrate) {
+      case 16000:
+      {
+        /*  0               
+         *  0 1 2 3 4 5 6 7 
+         * +-+-+-+-+-+-+-+-+-
+         * |D D|C C|B B|A A| ...
+         * |0 1|0 1|0 1|0 1|
+         * +-+-+-+-+-+-+-+-+-
+         */
+        while (len > 0) {
+          tmp = *in++;
+          *out++ = ((tmp & 0xc0) >> 6) |
+              ((tmp & 0x30) >> 2) | ((tmp & 0x0c) << 2) | ((tmp & 0x03) << 6);
+          len--;
+        }
+        break;
+      }
+      case 24000:
+      {
+        /*  0                   1                   2
+         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         * |C C|B B B|A A A|F|E E E|D D D|C|H H H|G G G|F F| ...
+         * |1 2|0 1 2|0 1 2|2|0 1 2|0 1 2|0|0 1 2|0 1 2|0 1|
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         */
+        while (len > 2) {
+          tmp = *in++;
+          *out++ = ((tmp & 0xe0) >> 5) |
+              ((tmp & 0x1c) << 1) | ((tmp & 0x03) << 6);
+          tmp = *in++;
+          *out++ = ((tmp & 0x80) >> 7) |
+              ((tmp & 0x70) >> 3) | ((tmp & 0x0e) << 4) | ((tmp & 0x01) << 7);
+          tmp = *in++;
+          *out++ = ((tmp & 0xc0) >> 6) |
+              ((tmp & 0x38) >> 1) | ((tmp & 0x07) << 5);
+          len -= 3;
+        }
+        break;
+      }
+      case 32000:
+      {
+        /*  0                   1
+         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         * |B B B B|A A A A|D D D D|C C C C| ...
+         * |0 1 2 3|0 1 2 3|0 1 2 3|0 1 2 3|
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         */
+        while (len > 0) {
+          tmp = *in++;
+          *out++ = ((tmp & 0xf0) >> 4) | ((tmp & 0x0f) << 4);
+          len--;
+        }
+        break;
+      }
+      case 40000:
+      {
+        /*  0                   1                   2                   3                   4
+         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         * |B B B|A A A A A|D|C C C C C|B B|E E E E|D D D D|G G|F F F F F|E|H H H H H|G G G|
+         * |2 3 4|0 1 2 3 4|4|0 1 2 3 4|0 1|1 2 3 4|0 1 2 3|3 4|0 1 2 3 4|0|0 1 2 3 4|0 1 2|   
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         */
+        while (len > 4) {
+          tmp = *in++;
+          *out++ = ((tmp & 0xf8) >> 3) | ((tmp & 0x07) << 5);
+          tmp = *in++;
+          *out++ = ((tmp & 0xc0) >> 6) |
+              ((tmp & 0x3e) << 1) | ((tmp & 0x01) << 7);
+          tmp = *in++;
+          *out++ = ((tmp & 0xf0) >> 4) | ((tmp & 0x0f) << 4);
+          tmp = *in++;
+          *out++ = ((tmp & 0x80) >> 7) |
+              ((tmp & 0x7c) >> 1) | ((tmp & 0x03) << 6);
+          tmp = *in++;
+          *out++ = ((tmp & 0xe0) >> 5) | ((tmp & 0x1f) << 3);
+          len -= 5;
+        }
+        break;
+      }
+    }
+    gst_buffer_unmap (outbuf, &map);
+  }
+
+  if (marker) {
+    /* mark start of talkspurt with RESYNC */
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+  }
+
+  return outbuf;
+
+bad_len:
+  {
+    return NULL;
+  }
+}
+
+static void
+gst_rtp_g726_depay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpG726Depay *rtpg726depay;
+
+  rtpg726depay = GST_RTP_G726_DEPAY (object);
+
+  switch (prop_id) {
+    case PROP_FORCE_AAL2:
+      rtpg726depay->force_aal2 = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_g726_depay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpG726Depay *rtpg726depay;
+
+  rtpg726depay = GST_RTP_G726_DEPAY (object);
+
+  switch (prop_id) {
+    case PROP_FORCE_AAL2:
+      g_value_set_boolean (value, rtpg726depay->force_aal2);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+gboolean
+gst_rtp_g726_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpg726depay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_G726_DEPAY);
+}
diff --git a/gst/rtp/gstrtpg726depay.h b/gst/rtp/gstrtpg726depay.h
new file mode 100644
index 0000000..45fd2ed
--- /dev/null
+++ b/gst/rtp/gstrtpg726depay.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) 2005 Edgard Lima <edgard.lima@gmail.com>
+ * Copyright (C) 2008 Axis Communications AB <dev-gstreamer@axis.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more
+ */
+
+#ifndef __GST_RTP_G726_DEPAY_H__
+#define __GST_RTP_G726_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpG726Depay GstRtpG726Depay;
+typedef struct _GstRtpG726DepayClass GstRtpG726DepayClass;
+
+#define GST_TYPE_RTP_G726_DEPAY \
+  (gst_rtp_g726_depay_get_type())
+#define GST_RTP_G726_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G726_DEPAY,GstRtpG726Depay))
+#define GST_RTP_G726_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G726_DEPAY,GstRtpG726DepayClass))
+#define GST_IS_RTP_G726_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G726_DEPAY))
+#define GST_IS_RTP_G726_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G726_DEPAY))
+
+struct _GstRtpG726Depay
+{
+  GstRTPBaseDepayload depayload;
+
+  gboolean aal2;
+  gboolean force_aal2;
+  gint bitrate;
+  guint block_align;
+};
+
+struct _GstRtpG726DepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_g726_depay_get_type (void);
+
+gboolean gst_rtp_g726_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_G726_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpg726pay.c b/gst/rtp/gstrtpg726pay.c
new file mode 100644
index 0000000..0716e51
--- /dev/null
+++ b/gst/rtp/gstrtpg726pay.c
@@ -0,0 +1,422 @@
+/* GStreamer
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2005 Edgard Lima <edgard.lima@gmail.com>
+ * Copyright (C) 2005 Nokia Corporation <kai.vehmanen@nokia.com>
+ * Copyright (C) 2007,2008 Axis Communications <dev-gstreamer@axis.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpg726pay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpg726pay_debug);
+#define GST_CAT_DEFAULT (rtpg726pay_debug)
+
+#define DEFAULT_FORCE_AAL2      TRUE
+
+enum
+{
+  PROP_0,
+  PROP_FORCE_AAL2
+};
+
+static GstStaticPadTemplate gst_rtp_g726_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-adpcm, "
+        "channels = (int) 1, "
+        "rate = (int) 8000, "
+        "bitrate = (int) { 16000, 24000, 32000, 40000 }, "
+        "layout = (string) \"g726\"")
+    );
+
+static GstStaticPadTemplate gst_rtp_g726_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 8000, "
+        "encoding-name = (string) { \"G726-16\", \"G726-24\", \"G726-32\", \"G726-40\", "
+        "    \"AAL2-G726-16\", \"AAL2-G726-24\", \"AAL2-G726-32\", \"AAL2-G726-40\" } ")
+    );
+
+static void gst_rtp_g726_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_rtp_g726_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+
+static gboolean gst_rtp_g726_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static GstFlowReturn gst_rtp_g726_pay_handle_buffer (GstRTPBasePayload *
+    payload, GstBuffer * buffer);
+
+#define gst_rtp_g726_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpG726Pay, gst_rtp_g726_pay,
+    GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_g726_pay_class_init (GstRtpG726PayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->set_property = gst_rtp_g726_pay_set_property;
+  gobject_class->get_property = gst_rtp_g726_pay_get_property;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FORCE_AAL2,
+      g_param_spec_boolean ("force-aal2", "Force AAL2",
+          "Force AAL2 encoding for compatibility with bad depayloaders",
+          DEFAULT_FORCE_AAL2, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g726_pay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g726_pay_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP G.726 payloader", "Codec/Payloader/Network/RTP",
+      "Payload-encodes G.726 audio into a RTP packet",
+      "Axis Communications <dev-gstreamer@axis.com>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_g726_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_g726_pay_handle_buffer;
+
+  GST_DEBUG_CATEGORY_INIT (rtpg726pay_debug, "rtpg726pay", 0,
+      "G.726 RTP Payloader");
+}
+
+static void
+gst_rtp_g726_pay_init (GstRtpG726Pay * rtpg726pay)
+{
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpg726pay);
+
+  GST_RTP_BASE_PAYLOAD (rtpg726pay)->clock_rate = 8000;
+
+  rtpg726pay->force_aal2 = DEFAULT_FORCE_AAL2;
+
+  /* sample based codec */
+  gst_rtp_base_audio_payload_set_sample_based (rtpbaseaudiopayload);
+}
+
+static gboolean
+gst_rtp_g726_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  gchar *encoding_name;
+  GstStructure *structure;
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+  GstRtpG726Pay *pay;
+  GstCaps *peercaps;
+  gboolean res;
+
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (payload);
+  pay = GST_RTP_G726_PAY (payload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "bitrate", &pay->bitrate))
+    pay->bitrate = 32000;
+
+  GST_DEBUG_OBJECT (payload, "using bitrate %d", pay->bitrate);
+
+  pay->aal2 = FALSE;
+
+  /* first see what we can do with the bitrate */
+  switch (pay->bitrate) {
+    case 16000:
+      encoding_name = g_strdup ("G726-16");
+      gst_rtp_base_audio_payload_set_samplebits_options (rtpbaseaudiopayload,
+          2);
+      break;
+    case 24000:
+      encoding_name = g_strdup ("G726-24");
+      gst_rtp_base_audio_payload_set_samplebits_options (rtpbaseaudiopayload,
+          3);
+      break;
+    case 32000:
+      encoding_name = g_strdup ("G726-32");
+      gst_rtp_base_audio_payload_set_samplebits_options (rtpbaseaudiopayload,
+          4);
+      break;
+    case 40000:
+      encoding_name = g_strdup ("G726-40");
+      gst_rtp_base_audio_payload_set_samplebits_options (rtpbaseaudiopayload,
+          5);
+      break;
+    default:
+      goto invalid_bitrate;
+  }
+
+  GST_DEBUG_OBJECT (payload, "selected base encoding %s", encoding_name);
+
+  /* now see if we need to produce AAL2 or not */
+  peercaps = gst_pad_peer_query_caps (payload->srcpad, NULL);
+  if (peercaps) {
+    GstCaps *filter, *intersect;
+    gchar *capsstr;
+
+    GST_DEBUG_OBJECT (payload, "have peercaps %" GST_PTR_FORMAT, peercaps);
+
+    capsstr = g_strdup_printf ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) 8000, "
+        "encoding-name = (string) %s; "
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) 8000, "
+        "encoding-name = (string) AAL2-%s", encoding_name, encoding_name);
+    filter = gst_caps_from_string (capsstr);
+    g_free (capsstr);
+    g_free (encoding_name);
+
+    /* intersect to filter */
+    intersect = gst_caps_intersect (peercaps, filter);
+    gst_caps_unref (peercaps);
+    gst_caps_unref (filter);
+
+    GST_DEBUG_OBJECT (payload, "intersected to %" GST_PTR_FORMAT, intersect);
+
+    if (!intersect)
+      goto no_format;
+    if (gst_caps_is_empty (intersect)) {
+      gst_caps_unref (intersect);
+      goto no_format;
+    }
+
+    structure = gst_caps_get_structure (intersect, 0);
+
+    /* now see what encoding name we settled on, we need to dup because the
+     * string goes away when we unref the intersection below. */
+    encoding_name =
+        g_strdup (gst_structure_get_string (structure, "encoding-name"));
+
+    /* if we managed to negotiate to AAL2, we definatly are going to do AAL2
+     * encoding. Else we only encode AAL2 when explicitly set by the
+     * property. */
+    if (g_str_has_prefix (encoding_name, "AAL2-"))
+      pay->aal2 = TRUE;
+    else
+      pay->aal2 = pay->force_aal2;
+
+    GST_DEBUG_OBJECT (payload, "final encoding %s, AAL2 %d", encoding_name,
+        pay->aal2);
+
+    gst_caps_unref (intersect);
+  } else {
+    /* downstream can do anything but we prefer the better supported non-AAL2 */
+    pay->aal2 = pay->force_aal2;
+    GST_DEBUG_OBJECT (payload, "no peer caps, AAL2 %d", pay->aal2);
+  }
+
+  gst_rtp_base_payload_set_options (payload, "audio", TRUE, encoding_name,
+      8000);
+  res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+  g_free (encoding_name);
+
+  return res;
+
+  /* ERRORS */
+invalid_bitrate:
+  {
+    GST_ERROR_OBJECT (payload, "invalid bitrate %d specified", pay->bitrate);
+    return FALSE;
+  }
+no_format:
+  {
+    GST_ERROR_OBJECT (payload, "could not negotiate format");
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_rtp_g726_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
+{
+  GstFlowReturn res;
+  GstRtpG726Pay *pay;
+
+  pay = GST_RTP_G726_PAY (payload);
+
+  if (!pay->aal2) {
+    GstMapInfo map;
+    guint8 *data, tmp;
+    gsize size;
+
+    /* for non AAL2, we need to reshuffle the bytes, we can do this in-place
+     * when the buffer is writable. */
+    buffer = gst_buffer_make_writable (buffer);
+
+    gst_buffer_map (buffer, &map, GST_MAP_READWRITE);
+    data = map.data;
+    size = map.size;
+
+    GST_LOG_OBJECT (pay, "packing %" G_GSIZE_FORMAT " bytes of data", map.size);
+
+    /* we need to reshuffle the bytes, output is of the form:
+     * A B C D .. with the number of bits depending on the bitrate. */
+    switch (pay->bitrate) {
+      case 16000:
+      {
+        /*  0               
+         *  0 1 2 3 4 5 6 7 
+         * +-+-+-+-+-+-+-+-+-
+         * |D D|C C|B B|A A| ...
+         * |0 1|0 1|0 1|0 1|
+         * +-+-+-+-+-+-+-+-+-
+         */
+        while (size > 0) {
+          tmp = *data;
+          *data++ = ((tmp & 0xc0) >> 6) |
+              ((tmp & 0x30) >> 2) | ((tmp & 0x0c) << 2) | ((tmp & 0x03) << 6);
+          size--;
+        }
+        break;
+      }
+      case 24000:
+      {
+        /*  0                   1                   2
+         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         * |C C|B B B|A A A|F|E E E|D D D|C|H H H|G G G|F F| ...
+         * |1 2|0 1 2|0 1 2|2|0 1 2|0 1 2|0|0 1 2|0 1 2|0 1|
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         */
+        while (size > 2) {
+          tmp = *data;
+          *data++ = ((tmp & 0xc0) >> 6) |
+              ((tmp & 0x38) >> 1) | ((tmp & 0x07) << 5);
+          tmp = *data;
+          *data++ = ((tmp & 0x80) >> 7) |
+              ((tmp & 0x70) >> 3) | ((tmp & 0x0e) << 4) | ((tmp & 0x01) << 7);
+          tmp = *data;
+          *data++ = ((tmp & 0xe0) >> 5) |
+              ((tmp & 0x1c) >> 2) | ((tmp & 0x03) << 6);
+          size -= 3;
+        }
+        break;
+      }
+      case 32000:
+      {
+        /*  0                   1
+         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         * |B B B B|A A A A|D D D D|C C C C| ...
+         * |0 1 2 3|0 1 2 3|0 1 2 3|0 1 2 3|
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         */
+        while (size > 0) {
+          tmp = *data;
+          *data++ = ((tmp & 0xf0) >> 4) | ((tmp & 0x0f) << 4);
+          size--;
+        }
+        break;
+      }
+      case 40000:
+      {
+        /*  0                   1                   2                   3                   4
+         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         * |B B B|A A A A A|D|C C C C C|B B|E E E E|D D D D|G G|F F F F F|E|H H H H H|G G G|
+         * |2 3 4|0 1 2 3 4|4|0 1 2 3 4|0 1|1 2 3 4|0 1 2 3|3 4|0 1 2 3 4|0|0 1 2 3 4|0 1 2|   
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         */
+        while (size > 4) {
+          tmp = *data;
+          *data++ = ((tmp & 0xe0) >> 5) | ((tmp & 0x1f) << 3);
+          tmp = *data;
+          *data++ = ((tmp & 0x80) >> 7) |
+              ((tmp & 0x7c) >> 2) | ((tmp & 0x03) << 6);
+          tmp = *data;
+          *data++ = ((tmp & 0xf0) >> 4) | ((tmp & 0x0f) << 4);
+          tmp = *data;
+          *data++ = ((tmp & 0xc0) >> 6) |
+              ((tmp & 0x3e) << 2) | ((tmp & 0x01) << 7);
+          tmp = *data;
+          *data++ = ((tmp & 0xf8) >> 3) | ((tmp & 0x07) << 5);
+          size -= 5;
+        }
+        break;
+      }
+    }
+    gst_buffer_unmap (buffer, &map);
+  }
+
+  res =
+      GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->handle_buffer (payload,
+      buffer);
+
+  return res;
+}
+
+static void
+gst_rtp_g726_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpG726Pay *rtpg726pay;
+
+  rtpg726pay = GST_RTP_G726_PAY (object);
+
+  switch (prop_id) {
+    case PROP_FORCE_AAL2:
+      rtpg726pay->force_aal2 = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_g726_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpG726Pay *rtpg726pay;
+
+  rtpg726pay = GST_RTP_G726_PAY (object);
+
+  switch (prop_id) {
+    case PROP_FORCE_AAL2:
+      g_value_set_boolean (value, rtpg726pay->force_aal2);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+gboolean
+gst_rtp_g726_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpg726pay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_G726_PAY);
+}
diff --git a/gst/rtp/gstrtpg726pay.h b/gst/rtp/gstrtpg726pay.h
new file mode 100644
index 0000000..d9dbfa4
--- /dev/null
+++ b/gst/rtp/gstrtpg726pay.h
@@ -0,0 +1,55 @@
+/* GStreamer
+ * Copyright (C) 2005 Edgard Lima <edgard.lima@gmail.com>
+ * Copyright (C) 2007,2008 Axis Communications <dev-gstreamer@axis.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more
+ */
+
+#ifndef __GST_RTP_G726_PAY_H__
+#define __GST_RTP_G726_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS typedef struct _GstRtpG726Pay GstRtpG726Pay;
+typedef struct _GstRtpG726PayClass GstRtpG726PayClass;
+
+#define GST_TYPE_RTP_G726_PAY \
+  (gst_rtp_g726_pay_get_type())
+#define GST_RTP_G726_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G726_PAY,GstRtpG726Pay))
+#define GST_RTP_G726_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G726_PAY,GstRtpG726PayClass))
+#define GST_IS_RTP_G726_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G726_PAY))
+#define GST_IS_RTP_G726_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G726_PAY))
+
+struct _GstRtpG726Pay
+{
+  GstRTPBaseAudioPayload audiopayload;
+
+  gboolean aal2;
+  gboolean force_aal2;
+  gint bitrate;
+};
+
+struct _GstRtpG726PayClass
+{
+  GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_g726_pay_get_type (void);
+
+gboolean gst_rtp_g726_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_G726_PAY_H__ */
diff --git a/gst/rtp/gstrtpg729depay.c b/gst/rtp/gstrtpg729depay.c
new file mode 100644
index 0000000..69c1c4d
--- /dev/null
+++ b/gst/rtp/gstrtpg729depay.c
@@ -0,0 +1,225 @@
+/* GStreamer
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include "gstrtpg729depay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpg729depay_debug);
+#define GST_CAT_DEFAULT (rtpg729depay_debug)
+
+
+/* references:
+ *
+ * RFC 3551 (4.5.6)
+ */
+
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0
+};
+
+/* input is an RTP packet
+ *
+ */
+static GstStaticPadTemplate gst_rtp_g729_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) 8000, "
+        "encoding-name = (string) \"G729\"; "
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_G729_STRING ", "
+        "clock-rate = (int) 8000")
+    );
+
+static GstStaticPadTemplate gst_rtp_g729_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/G729, " "channels = (int) 1," "rate = (int) 8000")
+    );
+
+static gboolean gst_rtp_g729_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_g729_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+#define gst_rtp_g729_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpG729Depay, gst_rtp_g729_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_g729_depay_class_init (GstRtpG729DepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpg729depay_debug, "rtpg729depay", 0,
+      "G.729 RTP Depayloader");
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g729_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g729_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP G.729 depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts G.729 audio from RTP packets (RFC 3551)",
+      "Laurent Glayal <spglegle@yahoo.fr>");
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_g729_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_g729_depay_setcaps;
+}
+
+static void
+gst_rtp_g729_depay_init (GstRtpG729Depay * rtpg729depay)
+{
+  GstRTPBaseDepayload *depayload;
+
+  depayload = GST_RTP_BASE_DEPAYLOAD (rtpg729depay);
+
+  gst_pad_use_fixed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload));
+}
+
+static gboolean
+gst_rtp_g729_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstCaps *srccaps;
+  GstRtpG729Depay *rtpg729depay;
+  const gchar *params;
+  gint clock_rate, channels;
+  gboolean ret;
+
+  rtpg729depay = GST_RTP_G729_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!(params = gst_structure_get_string (structure, "encoding-params")))
+    channels = 1;
+  else {
+    channels = atoi (params);
+  }
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 8000;
+
+  if (channels != 1)
+    goto wrong_channels;
+
+  if (clock_rate != 8000)
+    goto wrong_clock_rate;
+
+  depayload->clock_rate = clock_rate;
+
+  srccaps = gst_caps_new_simple ("audio/G729",
+      "channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, clock_rate, NULL);
+  ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+  gst_caps_unref (srccaps);
+
+  return ret;
+
+  /* ERRORS */
+wrong_channels:
+  {
+    GST_DEBUG_OBJECT (rtpg729depay, "expected 1 channel, got %d", channels);
+    return FALSE;
+  }
+wrong_clock_rate:
+  {
+    GST_DEBUG_OBJECT (rtpg729depay, "expected 8000 clock-rate, got %d",
+        clock_rate);
+    return FALSE;
+  }
+}
+
+static GstBuffer *
+gst_rtp_g729_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpG729Depay *rtpg729depay;
+  GstBuffer *outbuf = NULL;
+  gint payload_len;
+  gboolean marker;
+
+  rtpg729depay = GST_RTP_G729_DEPAY (depayload);
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  /* At least 2 bytes (CNG from G729 Annex B) */
+  if (payload_len < 2) {
+    GST_ELEMENT_WARNING (rtpg729depay, STREAM, DECODE,
+        (NULL), ("G729 RTP payload too small (%d)", payload_len));
+    goto bad_packet;
+  }
+
+  GST_LOG_OBJECT (rtpg729depay, "payload len %d", payload_len);
+
+  if ((payload_len % 10) == 2) {
+    GST_LOG_OBJECT (rtpg729depay, "G729 payload contains CNG frame");
+  }
+
+  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  if (marker) {
+    /* marker bit starts talkspurt */
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+  }
+
+  gst_rtp_drop_non_audio_meta (depayload, outbuf);
+
+  GST_LOG_OBJECT (depayload, "pushing buffer of size %" G_GSIZE_FORMAT,
+      gst_buffer_get_size (outbuf));
+
+  return outbuf;
+
+  /* ERRORS */
+bad_packet:
+  {
+    /* no fatal error */
+    return NULL;
+  }
+}
+
+gboolean
+gst_rtp_g729_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpg729depay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_G729_DEPAY);
+}
diff --git a/gst/rtp/gstrtpg729depay.h b/gst/rtp/gstrtpg729depay.h
new file mode 100644
index 0000000..a23562e
--- /dev/null
+++ b/gst/rtp/gstrtpg729depay.h
@@ -0,0 +1,61 @@
+/* GStreamer
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_G729_DEPAY_H__
+#define __GST_RTP_G729_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_G729_DEPAY \
+  (gst_rtp_g729_depay_get_type())
+  
+#define GST_RTP_G729_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G729_DEPAY,GstRtpG729Depay))
+  
+#define GST_RTP_G729_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G729_DEPAY,GstRtpG729DepayClass))
+  
+#define GST_IS_RTP_G729_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G729_DEPAY))
+  
+#define GST_IS_RTP_G729_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G729_DEPAY))
+
+typedef struct _GstRtpG729Depay GstRtpG729Depay;
+typedef struct _GstRtpG729DepayClass GstRtpG729DepayClass;
+
+struct _GstRtpG729Depay
+{
+  GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpG729DepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_g729_depay_get_type (void);
+
+gboolean gst_rtp_g729_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_G729_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpg729pay.c b/gst/rtp/gstrtpg729pay.c
new file mode 100644
index 0000000..378fa64
--- /dev/null
+++ b/gst/rtp/gstrtpg729pay.c
@@ -0,0 +1,396 @@
+/* GStreamer
+ * Copyright (C) <2007> Nokia Corporation
+ * Copyright (C) <2007> Collabora Ltd
+ *  @author: Olivier Crete <olivier.crete@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * This payloader assumes that the data will ALWAYS come as zero or more
+ * 10 bytes frame of audio followed by 0 or 1 2 byte frame of silence.
+ * Any other buffer format won't work
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/base/gstadapter.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpg729pay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpg729pay_debug);
+#define GST_CAT_DEFAULT (rtpg729pay_debug)
+
+#define G729_FRAME_SIZE 10
+#define G729B_CN_FRAME_SIZE 2
+#define G729_FRAME_DURATION (10 * GST_MSECOND)
+#define G729_FRAME_DURATION_MS (10)
+
+static gboolean
+gst_rtp_g729_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps);
+static GstFlowReturn
+gst_rtp_g729_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buf);
+
+static GstStateChangeReturn
+gst_rtp_g729_pay_change_state (GstElement * element, GstStateChange transition);
+
+static GstStaticPadTemplate gst_rtp_g729_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/G729, "     /* according to RFC 3555 */
+        "channels = (int) 1, " "rate = (int) 8000")
+    );
+
+static GstStaticPadTemplate gst_rtp_g729_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_G729_STRING ", "
+        "clock-rate = (int) 8000, "
+        "encoding-name = (string) \"G729\"; "
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 8000, " "encoding-name = (string) \"G729\"")
+    );
+
+#define gst_rtp_g729_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPG729Pay, gst_rtp_g729_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_g729_pay_finalize (GObject * object)
+{
+  GstRTPG729Pay *pay = GST_RTP_G729_PAY (object);
+
+  g_object_unref (pay->adapter);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_g729_pay_class_init (GstRTPG729PayClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstRTPBasePayloadClass *payload_class = GST_RTP_BASE_PAYLOAD_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (rtpg729pay_debug, "rtpg729pay", 0,
+      "G.729 RTP Payloader");
+
+  gobject_class->finalize = gst_rtp_g729_pay_finalize;
+
+  gstelement_class->change_state = gst_rtp_g729_pay_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g729_pay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_g729_pay_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP G.729 payloader", "Codec/Payloader/Network/RTP",
+      "Packetize G.729 audio into RTP packets",
+      "Olivier Crete <olivier.crete@collabora.co.uk>");
+
+  payload_class->set_caps = gst_rtp_g729_pay_set_caps;
+  payload_class->handle_buffer = gst_rtp_g729_pay_handle_buffer;
+}
+
+static void
+gst_rtp_g729_pay_init (GstRTPG729Pay * pay)
+{
+  GstRTPBasePayload *payload = GST_RTP_BASE_PAYLOAD (pay);
+
+  payload->pt = GST_RTP_PAYLOAD_G729;
+
+  pay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_g729_pay_reset (GstRTPG729Pay * pay)
+{
+  gst_adapter_clear (pay->adapter);
+  pay->discont = FALSE;
+  pay->next_rtp_time = 0;
+  pay->first_ts = GST_CLOCK_TIME_NONE;
+  pay->first_rtp_time = 0;
+}
+
+static gboolean
+gst_rtp_g729_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  gboolean res;
+
+  gst_rtp_base_payload_set_options (payload, "audio",
+      payload->pt != GST_RTP_PAYLOAD_G729, "G729", 8000);
+
+  res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+  return res;
+}
+
+static GstFlowReturn
+gst_rtp_g729_pay_push (GstRTPG729Pay * rtpg729pay, GstBuffer * buf)
+{
+  GstRTPBasePayload *basepayload;
+  GstClockTime duration;
+  guint frames;
+  GstBuffer *outbuf;
+  GstFlowReturn ret;
+  GstRTPBuffer rtp = { NULL };
+  guint payload_len = gst_buffer_get_size (buf);
+
+  basepayload = GST_RTP_BASE_PAYLOAD (rtpg729pay);
+
+  GST_DEBUG_OBJECT (rtpg729pay, "Pushing %d bytes ts %" GST_TIME_FORMAT,
+      payload_len, GST_TIME_ARGS (rtpg729pay->next_ts));
+
+  /* create buffer to hold the payload */
+  outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+
+  gst_rtp_buffer_map (outbuf, GST_MAP_READWRITE, &rtp);
+
+  /* set metadata */
+  frames =
+      (payload_len / G729_FRAME_SIZE) + ((payload_len % G729_FRAME_SIZE) >> 1);
+  duration = frames * G729_FRAME_DURATION;
+  GST_BUFFER_PTS (outbuf) = rtpg729pay->next_ts;
+  GST_BUFFER_DURATION (outbuf) = duration;
+  GST_BUFFER_OFFSET (outbuf) = rtpg729pay->next_rtp_time;
+  rtpg729pay->next_ts += duration;
+  rtpg729pay->next_rtp_time += frames * 80;
+
+  if (G_UNLIKELY (rtpg729pay->discont)) {
+    GST_DEBUG_OBJECT (basepayload, "discont, setting marker bit");
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+    gst_rtp_buffer_set_marker (&rtp, TRUE);
+    rtpg729pay->discont = FALSE;
+  }
+  gst_rtp_buffer_unmap (&rtp);
+
+  /* append payload */
+  gst_rtp_copy_audio_meta (basepayload, outbuf, buf);
+  outbuf = gst_buffer_append (outbuf, buf);
+
+  ret = gst_rtp_base_payload_push (basepayload, outbuf);
+
+  return ret;
+}
+
+static void
+gst_rtp_g729_pay_recalc_rtp_time (GstRTPG729Pay * rtpg729pay, GstClockTime time)
+{
+  if (GST_CLOCK_TIME_IS_VALID (rtpg729pay->first_ts)
+      && GST_CLOCK_TIME_IS_VALID (time) && time >= rtpg729pay->first_ts) {
+    GstClockTime diff;
+    guint32 rtpdiff;
+
+    diff = time - rtpg729pay->first_ts;
+    rtpdiff = (diff / GST_MSECOND) * 8;
+    rtpg729pay->next_rtp_time = rtpg729pay->first_rtp_time + rtpdiff;
+    GST_DEBUG_OBJECT (rtpg729pay,
+        "elapsed time %" GST_TIME_FORMAT ", rtp %" G_GUINT32_FORMAT ", "
+        "new offset %" G_GUINT32_FORMAT, GST_TIME_ARGS (diff), rtpdiff,
+        rtpg729pay->next_rtp_time);
+  }
+}
+
+static GstFlowReturn
+gst_rtp_g729_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buf)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstRTPG729Pay *rtpg729pay = GST_RTP_G729_PAY (payload);
+  GstAdapter *adapter = NULL;
+  guint payload_len;
+  guint available;
+  guint maxptime_octets = G_MAXUINT;
+  guint minptime_octets = 0;
+  guint min_payload_len;
+  guint max_payload_len;
+  gsize size;
+  GstClockTime timestamp;
+
+  size = gst_buffer_get_size (buf);
+
+  if (size % G729_FRAME_SIZE != 0 &&
+      size % G729_FRAME_SIZE != G729B_CN_FRAME_SIZE)
+    goto invalid_size;
+
+  /* max number of bytes based on given ptime, has to be multiple of
+   * frame_duration */
+  if (payload->max_ptime != -1) {
+    guint ptime_ms = payload->max_ptime / GST_MSECOND;
+
+    maxptime_octets = G729_FRAME_SIZE *
+        (int) (ptime_ms / G729_FRAME_DURATION_MS);
+
+    if (maxptime_octets < G729_FRAME_SIZE) {
+      GST_WARNING_OBJECT (payload, "Given ptime %" G_GINT64_FORMAT
+          " is smaller than minimum %d ns, overwriting to minimum",
+          payload->max_ptime, G729_FRAME_DURATION_MS);
+      maxptime_octets = G729_FRAME_SIZE;
+    }
+  }
+
+  max_payload_len = MIN (
+      /* MTU max */
+      (int) (gst_rtp_buffer_calc_payload_len (GST_RTP_BASE_PAYLOAD_MTU
+              (payload), 0, 0) / G729_FRAME_SIZE)
+      * G729_FRAME_SIZE,
+      /* ptime max */
+      maxptime_octets);
+
+  /* min number of bytes based on a given ptime, has to be a multiple
+     of frame duration */
+  {
+    guint64 min_ptime = payload->min_ptime;
+
+    min_ptime = min_ptime / GST_MSECOND;
+    minptime_octets = G729_FRAME_SIZE *
+        (int) (min_ptime / G729_FRAME_DURATION_MS);
+  }
+
+  min_payload_len = MAX (minptime_octets, G729_FRAME_SIZE);
+
+  if (min_payload_len > max_payload_len) {
+    min_payload_len = max_payload_len;
+  }
+
+  /* If the ptime is specified in the caps, tried to adhere to it exactly */
+  if (payload->ptime) {
+    guint64 ptime = payload->ptime / GST_MSECOND;
+    guint ptime_in_bytes = G729_FRAME_SIZE *
+        (guint) (ptime / G729_FRAME_DURATION_MS);
+
+    /* clip to computed min and max lengths */
+    ptime_in_bytes = MAX (min_payload_len, ptime_in_bytes);
+    ptime_in_bytes = MIN (max_payload_len, ptime_in_bytes);
+
+    min_payload_len = max_payload_len = ptime_in_bytes;
+  }
+
+  GST_LOG_OBJECT (payload,
+      "Calculated min_payload_len %u and max_payload_len %u",
+      min_payload_len, max_payload_len);
+
+  adapter = rtpg729pay->adapter;
+  available = gst_adapter_available (adapter);
+
+  timestamp = GST_BUFFER_PTS (buf);
+
+  /* resync rtp time on discont or a discontinuous cn packet */
+  if (GST_BUFFER_IS_DISCONT (buf)) {
+    /* flush remainder */
+    if (available > 0) {
+      gst_rtp_g729_pay_push (rtpg729pay,
+          gst_adapter_take_buffer_fast (adapter, available));
+      available = 0;
+    }
+    rtpg729pay->discont = TRUE;
+    gst_rtp_g729_pay_recalc_rtp_time (rtpg729pay, timestamp);
+  }
+
+  if (size < G729_FRAME_SIZE)
+    gst_rtp_g729_pay_recalc_rtp_time (rtpg729pay, timestamp);
+
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (rtpg729pay->first_ts))) {
+    rtpg729pay->first_ts = timestamp;
+    rtpg729pay->first_rtp_time = rtpg729pay->next_rtp_time;
+  }
+
+  /* let's reset the base timestamp when the adapter is empty */
+  if (available == 0)
+    rtpg729pay->next_ts = timestamp;
+
+  if (available == 0 && size >= min_payload_len && size <= max_payload_len) {
+    ret = gst_rtp_g729_pay_push (rtpg729pay, buf);
+    return ret;
+  }
+
+  gst_adapter_push (adapter, buf);
+  available = gst_adapter_available (adapter);
+
+  /* as long as we have full frames */
+  /* this loop will push all available buffers till the last frame */
+  while (available >= min_payload_len ||
+      available % G729_FRAME_SIZE == G729B_CN_FRAME_SIZE) {
+    /* We send as much as we can */
+    if (available <= max_payload_len) {
+      payload_len = available;
+    } else {
+      payload_len = MIN (max_payload_len,
+          (available / G729_FRAME_SIZE) * G729_FRAME_SIZE);
+    }
+
+    ret = gst_rtp_g729_pay_push (rtpg729pay,
+        gst_adapter_take_buffer_fast (adapter, payload_len));
+    available -= payload_len;
+  }
+
+  return ret;
+
+  /* ERRORS */
+invalid_size:
+  {
+    GST_ELEMENT_ERROR (payload, STREAM, WRONG_TYPE,
+        ("Invalid input buffer size"),
+        ("Invalid buffer size, should be a multiple of"
+            " G729_FRAME_SIZE(10) with an optional G729B_CN_FRAME_SIZE(2)"
+            " added to it, but it is %" G_GSIZE_FORMAT, size));
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_g729_pay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+  /* handle upwards state changes here */
+  switch (transition) {
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  /* handle downwards state changes */
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_g729_pay_reset (GST_RTP_G729_PAY (element));
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+gboolean
+gst_rtp_g729_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpg729pay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_G729_PAY);
+}
diff --git a/gst/rtp/gstrtpg729pay.h b/gst/rtp/gstrtpg729pay.h
new file mode 100644
index 0000000..1b92460
--- /dev/null
+++ b/gst/rtp/gstrtpg729pay.h
@@ -0,0 +1,66 @@
+/* GStreamer
+ * Copyright (C) <2007> Nokia Corporation
+ * Copyright (C) <2007> Collabora Ltd
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_G729_PAY_H__
+#define __GST_RTP_G729_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_G729_PAY \
+  (gst_rtp_g729_pay_get_type())
+#define GST_RTP_G729_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G729_PAY,GstRTPG729Pay))
+#define GST_RTP_G729_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G729_PAY,GstRTPG729PayClass))
+#define GST_IS_RTP_G729_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G729_PAY))
+#define GST_IS_RTP_G729_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G729_PAY))
+
+typedef struct _GstRTPG729Pay GstRTPG729Pay;
+typedef struct _GstRTPG729PayClass GstRTPG729PayClass;
+
+struct _GstRTPG729Pay
+{
+  GstRTPBasePayload payload;
+
+  GstAdapter *adapter;
+  GstClockTime next_ts;
+  guint32 next_rtp_time;
+  GstClockTime first_ts;
+  guint32 first_rtp_time;
+  gboolean discont;
+};
+
+struct _GstRTPG729PayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_g729_pay_get_type (void);
+
+gboolean gst_rtp_g729_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_G729_PAY_H__ */
diff --git a/gst/rtp/gstrtpgsmdepay.c b/gst/rtp/gstrtpgsmdepay.c
new file mode 100644
index 0000000..c87c618
--- /dev/null
+++ b/gst/rtp/gstrtpgsmdepay.c
@@ -0,0 +1,152 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Zeeshan Ali <zeenix@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+#include "gstrtpgsmdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpgsmdepay_debug);
+#define GST_CAT_DEFAULT (rtpgsmdepay_debug)
+
+/* RTPGSMDepay signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+static GstStaticPadTemplate gst_rtp_gsm_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-gsm, " "rate = (int) 8000, " "channels = 1")
+    );
+
+static GstStaticPadTemplate gst_rtp_gsm_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) 8000, " "encoding-name = (string) \"GSM\";"
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_GSM_STRING ", "
+        "clock-rate = (int) 8000")
+    );
+
+static GstBuffer *gst_rtp_gsm_depay_process (GstRTPBaseDepayload * _depayload,
+    GstRTPBuffer * rtp);
+static gboolean gst_rtp_gsm_depay_setcaps (GstRTPBaseDepayload * _depayload,
+    GstCaps * caps);
+
+#define gst_rtp_gsm_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPGSMDepay, gst_rtp_gsm_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_gsm_depay_class_init (GstRTPGSMDepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbase_depayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbase_depayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_gsm_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_gsm_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP GSM depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts GSM audio from RTP packets", "Zeeshan Ali <zeenix@gmail.com>");
+
+  gstrtpbase_depayload_class->process_rtp_packet = gst_rtp_gsm_depay_process;
+  gstrtpbase_depayload_class->set_caps = gst_rtp_gsm_depay_setcaps;
+
+  GST_DEBUG_CATEGORY_INIT (rtpgsmdepay_debug, "rtpgsmdepay", 0,
+      "GSM Audio RTP Depayloader");
+}
+
+static void
+gst_rtp_gsm_depay_init (GstRTPGSMDepay * rtpgsmdepay)
+{
+}
+
+static gboolean
+gst_rtp_gsm_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstCaps *srccaps;
+  gboolean ret;
+  GstStructure *structure;
+  gint clock_rate;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 8000;          /* default */
+  depayload->clock_rate = clock_rate;
+
+  srccaps = gst_caps_new_simple ("audio/x-gsm",
+      "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, clock_rate, NULL);
+  ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+  gst_caps_unref (srccaps);
+
+  return ret;
+}
+
+static GstBuffer *
+gst_rtp_gsm_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstBuffer *outbuf = NULL;
+  gboolean marker;
+
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+      gst_buffer_get_size (rtp->buffer), marker,
+      gst_rtp_buffer_get_timestamp (rtp), gst_rtp_buffer_get_seq (rtp));
+
+  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);
+
+  if (marker && outbuf) {
+    /* mark start of talkspurt with RESYNC */
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+  }
+
+  if (outbuf) {
+    gst_rtp_drop_non_audio_meta (depayload, outbuf);
+  }
+
+  return outbuf;
+}
+
+gboolean
+gst_rtp_gsm_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpgsmdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_GSM_DEPAY);
+}
diff --git a/gst/rtp/gstrtpgsmdepay.h b/gst/rtp/gstrtpgsmdepay.h
new file mode 100644
index 0000000..e428aa0
--- /dev/null
+++ b/gst/rtp/gstrtpgsmdepay.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_GSM_DEPAY_H__
+#define __GST_RTP_GSM_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTPGSMDepay GstRTPGSMDepay;
+typedef struct _GstRTPGSMDepayClass GstRTPGSMDepayClass;
+
+#define GST_TYPE_RTP_GSM_DEPAY \
+  (gst_rtp_gsm_depay_get_type())
+#define GST_RTP_GSM_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_GSM_DEPAY,GstRTPGSMDepay))
+#define GST_RTP_GSM_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_GSM_DEPAY,GstRTPGSMDepayClass))
+#define GST_IS_RTP_GSM_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_GSM_DEPAY))
+#define GST_IS_RTP_GSM_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GSM_DEPAY))
+
+struct _GstRTPGSMDepay
+{
+  GstRTPBaseDepayload _depayload;
+};
+
+struct _GstRTPGSMDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_gsm_depay_get_type (void);
+
+gboolean gst_rtp_gsm_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_GSM_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpgsmpay.c b/gst/rtp/gstrtpgsmpay.c
new file mode 100644
index 0000000..aa239a8
--- /dev/null
+++ b/gst/rtp/gstrtpgsmpay.c
@@ -0,0 +1,181 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Zeeshan Ali <zeenix@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpgsmpay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpgsmpay_debug);
+#define GST_CAT_DEFAULT (rtpgsmpay_debug)
+
+static GstStaticPadTemplate gst_rtp_gsm_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-gsm, " "rate = (int) 8000, " "channels = (int) 1")
+    );
+
+static GstStaticPadTemplate gst_rtp_gsm_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_GSM_STRING ", "
+        "clock-rate = (int) 8000, " "encoding-name = (string) \"GSM\"; "
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 8000, " "encoding-name = (string) \"GSM\"")
+    );
+
+static gboolean gst_rtp_gsm_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static GstFlowReturn gst_rtp_gsm_pay_handle_buffer (GstRTPBasePayload * payload,
+    GstBuffer * buffer);
+
+#define gst_rtp_gsm_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPGSMPay, gst_rtp_gsm_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_gsm_pay_class_init (GstRTPGSMPayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpgsmpay_debug, "rtpgsmpay", 0,
+      "GSM Audio RTP Payloader");
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_gsm_pay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_gsm_pay_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP GSM payloader",
+      "Codec/Payloader/Network/RTP",
+      "Payload-encodes GSM audio into a RTP packet",
+      "Zeeshan Ali <zeenix@gmail.com>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_gsm_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_gsm_pay_handle_buffer;
+}
+
+static void
+gst_rtp_gsm_pay_init (GstRTPGSMPay * rtpgsmpay)
+{
+  GST_RTP_BASE_PAYLOAD (rtpgsmpay)->clock_rate = 8000;
+  GST_RTP_BASE_PAYLOAD_PT (rtpgsmpay) = GST_RTP_PAYLOAD_GSM;
+}
+
+static gboolean
+gst_rtp_gsm_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  const char *stname;
+  GstStructure *structure;
+  gboolean res;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  stname = gst_structure_get_name (structure);
+
+  if (strcmp ("audio/x-gsm", stname))
+    goto invalid_type;
+
+  gst_rtp_base_payload_set_options (payload, "audio",
+      payload->pt != GST_RTP_PAYLOAD_GSM, "GSM", 8000);
+  res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+  return res;
+
+  /* ERRORS */
+invalid_type:
+  {
+    GST_WARNING_OBJECT (payload, "invalid media type received");
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_rtp_gsm_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRTPGSMPay *rtpgsmpay;
+  guint payload_len;
+  GstBuffer *outbuf;
+  GstClockTime timestamp, duration;
+  GstFlowReturn ret;
+
+  rtpgsmpay = GST_RTP_GSM_PAY (basepayload);
+
+  timestamp = GST_BUFFER_PTS (buffer);
+  duration = GST_BUFFER_DURATION (buffer);
+
+  /* FIXME, only one GSM frame per RTP packet for now */
+  payload_len = gst_buffer_get_size (buffer);
+
+  /* FIXME, just error out for now */
+  if (payload_len > GST_RTP_BASE_PAYLOAD_MTU (rtpgsmpay))
+    goto too_big;
+
+  outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+
+  /* copy timestamp and duration */
+  GST_BUFFER_PTS (outbuf) = timestamp;
+  GST_BUFFER_DURATION (outbuf) = duration;
+
+  gst_rtp_copy_audio_meta (rtpgsmpay, outbuf, buffer);
+
+  /* append payload */
+  outbuf = gst_buffer_append (outbuf, buffer);
+
+  GST_DEBUG ("gst_rtp_gsm_pay_chain: pushing buffer of size %" G_GSIZE_FORMAT,
+      gst_buffer_get_size (outbuf));
+
+  ret = gst_rtp_base_payload_push (basepayload, outbuf);
+
+  return ret;
+
+  /* ERRORS */
+too_big:
+  {
+    GST_ELEMENT_ERROR (rtpgsmpay, STREAM, ENCODE, (NULL),
+        ("payload_len %u > mtu %u", payload_len,
+            GST_RTP_BASE_PAYLOAD_MTU (rtpgsmpay)));
+    return GST_FLOW_ERROR;
+  }
+}
+
+gboolean
+gst_rtp_gsm_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpgsmpay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_GSM_PAY);
+}
diff --git a/gst/rtp/gstrtpgsmpay.h b/gst/rtp/gstrtpgsmpay.h
new file mode 100644
index 0000000..b6437f5
--- /dev/null
+++ b/gst/rtp/gstrtpgsmpay.h
@@ -0,0 +1,59 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_RTP_GSM_PAY_H__
+#define __GST_RTP_GSM_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTPGSMPay GstRTPGSMPay;
+typedef struct _GstRTPGSMPayClass GstRTPGSMPayClass;
+
+#define GST_TYPE_RTP_GSM_PAY \
+  (gst_rtp_gsm_pay_get_type())
+#define GST_RTP_GSM_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_GSM_PAY,GstRTPGSMPay))
+#define GST_RTP_GSM_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_GSM_PAY,GstRTPGSMPayClass))
+#define GST_IS_RTP_GSM_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_GSM_PAY))
+#define GST_IS_RTP_GSM_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GSM_PAY))
+
+struct _GstRTPGSMPay
+{
+  GstRTPBasePayload payload;
+};
+
+struct _GstRTPGSMPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_gsm_pay_get_type (void);
+
+gboolean gst_rtp_gsm_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_GSM_PAY_H__ */
diff --git a/gst/rtp/gstrtpgstdepay.c b/gst/rtp/gstrtpgstdepay.c
new file mode 100644
index 0000000..7d05742
--- /dev/null
+++ b/gst/rtp/gstrtpgstdepay.c
@@ -0,0 +1,620 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "gstrtpgstdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpgstdepay_debug);
+#define GST_CAT_DEFAULT (rtpgstdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_gst_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate gst_rtp_gst_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"application\", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"X-GST\"")
+    );
+
+#define gst_rtp_gst_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpGSTDepay, gst_rtp_gst_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_gst_depay_finalize (GObject * object);
+
+static gboolean gst_rtp_gst_depay_handle_event (GstRTPBaseDepayload * depay,
+    GstEvent * event);
+static GstStateChangeReturn gst_rtp_gst_depay_change_state (GstElement *
+    element, GstStateChange transition);
+
+static void gst_rtp_gst_depay_reset (GstRtpGSTDepay * rtpgstdepay, gboolean
+    full);
+static gboolean gst_rtp_gst_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_gst_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+static void
+gst_rtp_gst_depay_class_init (GstRtpGSTDepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpgstdepay_debug, "rtpgstdepay", 0,
+      "Gstreamer RTP Depayloader");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_gst_depay_finalize;
+
+  gstelement_class->change_state = gst_rtp_gst_depay_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_gst_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_gst_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "GStreamer depayloader", "Codec/Depayloader/Network",
+      "Extracts GStreamer buffers from RTP packets",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasedepayload_class->handle_event = gst_rtp_gst_depay_handle_event;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_gst_depay_setcaps;
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_gst_depay_process;
+}
+
+static void
+gst_rtp_gst_depay_init (GstRtpGSTDepay * rtpgstdepay)
+{
+  rtpgstdepay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_gst_depay_finalize (GObject * object)
+{
+  GstRtpGSTDepay *rtpgstdepay;
+
+  rtpgstdepay = GST_RTP_GST_DEPAY (object);
+
+  gst_rtp_gst_depay_reset (rtpgstdepay, TRUE);
+  g_object_unref (rtpgstdepay->adapter);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+store_cache (GstRtpGSTDepay * rtpgstdepay, guint CV, GstCaps * caps)
+{
+  if (rtpgstdepay->CV_cache[CV])
+    gst_caps_unref (rtpgstdepay->CV_cache[CV]);
+  rtpgstdepay->CV_cache[CV] = caps;
+}
+
+static void
+gst_rtp_gst_depay_reset (GstRtpGSTDepay * rtpgstdepay, gboolean full)
+{
+  guint i;
+
+  gst_adapter_clear (rtpgstdepay->adapter);
+  if (full) {
+    rtpgstdepay->current_CV = 0;
+    for (i = 0; i < 8; i++)
+      store_cache (rtpgstdepay, i, NULL);
+    g_free (rtpgstdepay->stream_id);
+    rtpgstdepay->stream_id = NULL;
+    if (rtpgstdepay->tags)
+      gst_tag_list_unref (rtpgstdepay->tags);
+    rtpgstdepay->tags = NULL;
+  }
+}
+
+static gboolean
+gst_rtp_gst_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstRtpGSTDepay *rtpgstdepay;
+  GstStructure *structure;
+  gint clock_rate;
+  gboolean res;
+  const gchar *capsenc;
+
+  rtpgstdepay = GST_RTP_GST_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;
+  depayload->clock_rate = clock_rate;
+
+  capsenc = gst_structure_get_string (structure, "caps");
+  if (capsenc) {
+    GstCaps *outcaps;
+    gsize out_len;
+    gchar *capsstr;
+    const gchar *capsver;
+    guint CV;
+
+    /* decode caps */
+    capsstr = (gchar *) g_base64_decode (capsenc, &out_len);
+    outcaps = gst_caps_from_string (capsstr);
+    g_free (capsstr);
+
+    /* parse version */
+    capsver = gst_structure_get_string (structure, "capsversion");
+    if (capsver) {
+      CV = atoi (capsver);
+    } else {
+      /* no version, assume 0 */
+      CV = 0;
+    }
+    /* store in cache */
+    rtpgstdepay->current_CV = CV;
+    gst_caps_ref (outcaps);
+    store_cache (rtpgstdepay, CV, outcaps);
+
+    res = gst_pad_set_caps (depayload->srcpad, outcaps);
+    gst_caps_unref (outcaps);
+  } else {
+    GST_WARNING_OBJECT (depayload, "no caps given");
+    rtpgstdepay->current_CV = -1;
+    res = TRUE;
+  }
+
+  return res;
+}
+
+static gboolean
+read_length (GstRtpGSTDepay * rtpgstdepay, guint8 * data, guint size,
+    guint * length, guint * skip)
+{
+  guint b, len, offset;
+
+  /* start reading the length, we need this to skip to the data later */
+  len = offset = 0;
+  do {
+    if (offset >= size)
+      return FALSE;
+    b = data[offset++];
+    len = (len << 7) | (b & 0x7f);
+  } while (b & 0x80);
+
+  /* check remaining buffer size */
+  if (size - offset < len)
+    return FALSE;
+
+  *length = len;
+  *skip = offset;
+
+  return TRUE;
+}
+
+static GstCaps *
+read_caps (GstRtpGSTDepay * rtpgstdepay, GstBuffer * buf, guint * skip)
+{
+  guint offset, length;
+  GstCaps *caps;
+  GstMapInfo map;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  GST_DEBUG_OBJECT (rtpgstdepay, "buffer size %" G_GSIZE_FORMAT, map.size);
+
+  if (!read_length (rtpgstdepay, map.data, map.size, &length, &offset))
+    goto too_small;
+
+  if (length == 0 || map.data[offset + length - 1] != '\0')
+    goto invalid_buffer;
+
+  GST_DEBUG_OBJECT (rtpgstdepay, "parsing caps %s", &map.data[offset]);
+
+  /* parse and store in cache */
+  caps = gst_caps_from_string ((gchar *) & map.data[offset]);
+  gst_buffer_unmap (buf, &map);
+
+  *skip = length + offset;
+
+  return caps;
+
+too_small:
+  {
+    GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
+        ("Buffer too small."), (NULL));
+    gst_buffer_unmap (buf, &map);
+    return NULL;
+  }
+invalid_buffer:
+  {
+    GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
+        ("caps string not 0-terminated."), (NULL));
+    gst_buffer_unmap (buf, &map);
+    return NULL;
+  }
+}
+
+static GstEvent *
+read_event (GstRtpGSTDepay * rtpgstdepay, guint type,
+    GstBuffer * buf, guint * skip)
+{
+  guint offset, length;
+  GstStructure *s;
+  GstEvent *event;
+  GstEventType etype;
+  gchar *end;
+  GstMapInfo map;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  GST_DEBUG_OBJECT (rtpgstdepay, "buffer size %" G_GSIZE_FORMAT, map.size);
+
+  if (!read_length (rtpgstdepay, map.data, map.size, &length, &offset))
+    goto too_small;
+
+  if (length == 0)
+    goto invalid_buffer;
+  /* backward compat, old payloader did not put 0-byte at the end */
+  if (map.data[offset + length - 1] != '\0'
+      && map.data[offset + length - 1] != ';')
+    goto invalid_buffer;
+
+  GST_DEBUG_OBJECT (rtpgstdepay, "parsing event %s", &map.data[offset]);
+
+  /* parse */
+  s = gst_structure_from_string ((gchar *) & map.data[offset], &end);
+  gst_buffer_unmap (buf, &map);
+
+  if (s == NULL)
+    goto parse_failed;
+
+  switch (type) {
+    case 1:
+      etype = GST_EVENT_TAG;
+      break;
+    case 2:
+      etype = GST_EVENT_CUSTOM_DOWNSTREAM;
+      break;
+    case 3:
+      etype = GST_EVENT_CUSTOM_BOTH;
+      break;
+    case 4:
+      etype = GST_EVENT_STREAM_START;
+      break;
+    default:
+      goto unknown_event;
+  }
+  event = gst_event_new_custom (etype, s);
+
+  *skip = length + offset;
+
+  return event;
+
+too_small:
+  {
+    GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
+        ("Buffer too small."), (NULL));
+    gst_buffer_unmap (buf, &map);
+    return NULL;
+  }
+invalid_buffer:
+  {
+    GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
+        ("event string not 0-terminated."), (NULL));
+    gst_buffer_unmap (buf, &map);
+    return NULL;
+  }
+parse_failed:
+  {
+    GST_WARNING_OBJECT (rtpgstdepay, "could not parse event");
+    return NULL;
+  }
+unknown_event:
+  {
+    GST_DEBUG_OBJECT (rtpgstdepay, "unknown event type");
+    gst_structure_free (s);
+    return NULL;
+  }
+}
+
+static void
+store_event (GstRtpGSTDepay * rtpgstdepay, GstEvent * event)
+{
+  gboolean do_push = FALSE;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_TAG:
+    {
+      GstTagList *old, *tags;
+
+      gst_event_parse_tag (event, &tags);
+
+      old = rtpgstdepay->tags;
+      if (!old || !gst_tag_list_is_equal (old, tags)) {
+        do_push = TRUE;
+        if (old)
+          gst_tag_list_unref (old);
+        rtpgstdepay->tags = gst_tag_list_ref (tags);
+      }
+      break;
+    }
+    case GST_EVENT_CUSTOM_DOWNSTREAM:
+    case GST_EVENT_CUSTOM_BOTH:
+      /* always push custom events */
+      do_push = TRUE;
+      break;
+    case GST_EVENT_STREAM_START:
+    {
+      gchar *old;
+      const gchar *stream_id = NULL;
+
+      gst_event_parse_stream_start (event, &stream_id);
+
+      old = rtpgstdepay->stream_id;
+      if (!old || g_strcmp0 (old, stream_id)) {
+        do_push = TRUE;
+        g_free (old);
+        rtpgstdepay->stream_id = g_strdup (stream_id);
+      }
+      break;
+    }
+    default:
+      /* unknown event, don't push */
+      break;
+  }
+  if (do_push)
+    gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD (rtpgstdepay)->srcpad, event);
+  else
+    gst_event_unref (event);
+}
+
+static GstBuffer *
+gst_rtp_gst_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpGSTDepay *rtpgstdepay;
+  GstBuffer *subbuf, *outbuf = NULL;
+  gint payload_len;
+  guint8 *payload;
+  guint CV, frag_offset, avail, offset;
+
+  rtpgstdepay = GST_RTP_GST_DEPAY (depayload);
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  if (payload_len <= 8)
+    goto empty_packet;
+
+  if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
+    GST_WARNING_OBJECT (rtpgstdepay, "DISCONT, clear adapter");
+    gst_adapter_clear (rtpgstdepay->adapter);
+  }
+
+  payload = gst_rtp_buffer_get_payload (rtp);
+
+  /* strip off header
+   *
+   *  0                   1                   2                   3
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |C| CV  |D|0|0|0|     ETYPE     |  MBZ                          |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Frag_offset                          |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   */
+  frag_offset =
+      (payload[4] << 24) | (payload[5] << 16) | (payload[6] << 8) | payload[7];
+
+  avail = gst_adapter_available (rtpgstdepay->adapter);
+  if (avail != frag_offset)
+    goto wrong_frag;
+
+  /* subbuffer skipping the 8 header bytes */
+  subbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, 8, -1);
+  gst_adapter_push (rtpgstdepay->adapter, subbuf);
+
+  offset = 0;
+  if (gst_rtp_buffer_get_marker (rtp)) {
+    guint avail;
+    GstCaps *outcaps;
+
+    /* take the buffer */
+    avail = gst_adapter_available (rtpgstdepay->adapter);
+    outbuf = gst_adapter_take_buffer (rtpgstdepay->adapter, avail);
+
+    CV = (payload[0] >> 4) & 0x7;
+
+    if (payload[0] & 0x80) {
+      guint size;
+
+      /* C bit, we have inline caps */
+      outcaps = read_caps (rtpgstdepay, outbuf, &size);
+      if (outcaps == NULL)
+        goto no_caps;
+
+      GST_DEBUG_OBJECT (rtpgstdepay,
+          "inline caps %u, length %u, %" GST_PTR_FORMAT, CV, size, outcaps);
+
+      store_cache (rtpgstdepay, CV, outcaps);
+
+      /* skip caps */
+      offset += size;
+      avail -= size;
+    }
+    if (payload[1]) {
+      guint size;
+      GstEvent *event;
+
+      /* we have an event */
+      event = read_event (rtpgstdepay, payload[1], outbuf, &size);
+      if (event == NULL)
+        goto no_event;
+
+      GST_DEBUG_OBJECT (rtpgstdepay,
+          "inline event, length %u, %" GST_PTR_FORMAT, size, event);
+
+      store_event (rtpgstdepay, event);
+
+      /* no buffer after event */
+      avail = 0;
+    }
+
+    if (avail) {
+      if (offset != 0) {
+        GstBuffer *temp;
+
+        GST_DEBUG_OBJECT (rtpgstdepay, "sub buffer: offset %u, size %u", offset,
+            avail);
+
+        temp =
+            gst_buffer_copy_region (outbuf, GST_BUFFER_COPY_ALL, offset, avail);
+
+        gst_buffer_unref (outbuf);
+        outbuf = temp;
+      }
+
+      /* see what caps we need */
+      if (CV != rtpgstdepay->current_CV) {
+        /* we need to switch caps, check if we have the caps */
+        if ((outcaps = rtpgstdepay->CV_cache[CV]) == NULL)
+          goto missing_caps;
+
+        GST_DEBUG_OBJECT (rtpgstdepay,
+            "need caps switch from %u to %u, %" GST_PTR_FORMAT,
+            rtpgstdepay->current_CV, CV, outcaps);
+
+        /* and set caps */
+        if (gst_pad_set_caps (depayload->srcpad, outcaps))
+          rtpgstdepay->current_CV = CV;
+      }
+
+      if (payload[0] & 0x8)
+        GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+    } else {
+      gst_buffer_unref (outbuf);
+      outbuf = NULL;
+    }
+  }
+
+  if (outbuf) {
+    gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpgstdepay), outbuf, 0);
+  }
+
+  return outbuf;
+
+  /* ERRORS */
+empty_packet:
+  {
+    GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
+        ("Empty Payload."), (NULL));
+    return NULL;
+  }
+wrong_frag:
+  {
+    gst_adapter_clear (rtpgstdepay->adapter);
+    GST_LOG_OBJECT (rtpgstdepay, "wrong fragment, skipping");
+    return NULL;
+  }
+no_caps:
+  {
+    GST_WARNING_OBJECT (rtpgstdepay, "failed to parse caps");
+    gst_buffer_unref (outbuf);
+    return NULL;
+  }
+no_event:
+  {
+    GST_WARNING_OBJECT (rtpgstdepay, "failed to parse event");
+    gst_buffer_unref (outbuf);
+    return NULL;
+  }
+missing_caps:
+  {
+    GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
+        ("Missing caps %u.", CV), (NULL));
+    gst_buffer_unref (outbuf);
+    return NULL;
+  }
+}
+
+static gboolean
+gst_rtp_gst_depay_handle_event (GstRTPBaseDepayload * depay, GstEvent * event)
+{
+  GstRtpGSTDepay *rtpgstdepay;
+
+  rtpgstdepay = GST_RTP_GST_DEPAY (depay);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      gst_rtp_gst_depay_reset (rtpgstdepay, FALSE);
+      break;
+    default:
+      break;
+  }
+
+  return
+      GST_RTP_BASE_DEPAYLOAD_CLASS (parent_class)->handle_event (depay, event);
+}
+
+
+static GstStateChangeReturn
+gst_rtp_gst_depay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRtpGSTDepay *rtpgstdepay;
+  GstStateChangeReturn ret;
+
+  rtpgstdepay = GST_RTP_GST_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_gst_depay_reset (rtpgstdepay, TRUE);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_gst_depay_reset (rtpgstdepay, TRUE);
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+
+gboolean
+gst_rtp_gst_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpgstdepay",
+      GST_RANK_MARGINAL, GST_TYPE_RTP_GST_DEPAY);
+}
diff --git a/gst/rtp/gstrtpgstdepay.h b/gst/rtp/gstrtpgstdepay.h
new file mode 100644
index 0000000..4b8f2c6
--- /dev/null
+++ b/gst/rtp/gstrtpgstdepay.h
@@ -0,0 +1,66 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_GST_DEPAY_H__
+#define __GST_RTP_GST_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_GST_DEPAY \
+  (gst_rtp_gst_depay_get_type())
+#define GST_RTP_GST_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_GST_DEPAY,GstRtpGSTDepay))
+#define GST_RTP_GST_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_GST_DEPAY,GstRtpGSTDepayClass))
+#define GST_IS_RTP_GST_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_GST_DEPAY))
+#define GST_IS_RTP_GST_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GST_DEPAY))
+
+typedef struct _GstRtpGSTDepay GstRtpGSTDepay;
+typedef struct _GstRtpGSTDepayClass GstRtpGSTDepayClass;
+
+struct _GstRtpGSTDepay
+{
+  GstRTPBaseDepayload depayload;
+
+  GstAdapter *adapter;
+  guint current_CV;
+  GstCaps *CV_cache[8];
+
+  GstTagList *tags;
+  gchar *stream_id;
+};
+
+struct _GstRtpGSTDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_gst_depay_get_type (void);
+
+gboolean gst_rtp_gst_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_GST_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpgstpay.c b/gst/rtp/gstrtpgstpay.c
new file mode 100644
index 0000000..f5511f4
--- /dev/null
+++ b/gst/rtp/gstrtpgstpay.c
@@ -0,0 +1,661 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpgstpay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_pay_debug);
+#define GST_CAT_DEFAULT gst_rtp_pay_debug
+
+/*
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |C| CV  |D|0|0|0|     ETYPE     |  MBZ                          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                          Frag_offset                          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * C: caps inlined flag
+ *   When C set, first part of payload contains caps definition. Caps definition
+ *   starts with variable-length length prefix and then a string of that length.
+ *   the length is encoded in big endian 7 bit chunks, the top 1 bit of a byte
+ *   is the continuation marker and the 7 next bits the data. A continuation
+ *   marker of 1 means that the next byte contains more data.
+ *
+ * CV: caps version, 0 = caps from SDP, 1 - 7 inlined caps
+ * D: delta unit buffer
+ * ETYPE: type of event. Payload contains the event, prefixed with a
+ *        variable length field.
+ *   0 = NO event
+ *   1 = GST_EVENT_TAG
+ *   2 = GST_EVENT_CUSTOM_DOWNSTREAM
+ *   3 = GST_EVENT_CUSTOM_BOTH
+ *   4 = GST_EVENT_STREAM_START
+ */
+
+static GstStaticPadTemplate gst_rtp_gst_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate gst_rtp_gst_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"application\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"X-GST\"")
+    );
+
+enum
+{
+  PROP_0,
+  PROP_CONFIG_INTERVAL
+};
+
+#define DEFAULT_CONFIG_INTERVAL		      0
+
+static void gst_rtp_gst_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_gst_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_rtp_gst_pay_finalize (GObject * obj);
+static GstStateChangeReturn gst_rtp_gst_pay_change_state (GstElement * element,
+    GstStateChange transition);
+
+static gboolean gst_rtp_gst_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static GstFlowReturn gst_rtp_gst_pay_handle_buffer (GstRTPBasePayload * payload,
+    GstBuffer * buffer);
+static gboolean gst_rtp_gst_pay_sink_event (GstRTPBasePayload * payload,
+    GstEvent * event);
+
+#define gst_rtp_gst_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpGSTPay, gst_rtp_gst_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_gst_pay_class_init (GstRtpGSTPayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->set_property = gst_rtp_gst_pay_set_property;
+  gobject_class->get_property = gst_rtp_gst_pay_get_property;
+  gobject_class->finalize = gst_rtp_gst_pay_finalize;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_CONFIG_INTERVAL,
+      g_param_spec_uint ("config-interval",
+          "Caps/Tags Send Interval",
+          "Interval for sending caps and TAG events in seconds (0 = disabled)",
+          0, 3600, DEFAULT_CONFIG_INTERVAL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
+  gstelement_class->change_state = gst_rtp_gst_pay_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_gst_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_gst_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP GStreamer payloader", "Codec/Payloader/Network/RTP",
+      "Payload GStreamer buffers as RTP packets",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_gst_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_gst_pay_handle_buffer;
+  gstrtpbasepayload_class->sink_event = gst_rtp_gst_pay_sink_event;
+
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_pay_debug, "rtpgstpay", 0,
+      "rtpgstpay element");
+}
+
+static void
+gst_rtp_gst_pay_init (GstRtpGSTPay * rtpgstpay)
+{
+  rtpgstpay->adapter = gst_adapter_new ();
+  rtpgstpay->pending_buffers = NULL;
+  gst_rtp_base_payload_set_options (GST_RTP_BASE_PAYLOAD (rtpgstpay),
+      "application", TRUE, "X-GST", 90000);
+  rtpgstpay->last_config = GST_CLOCK_TIME_NONE;
+  rtpgstpay->taglist = NULL;
+  rtpgstpay->config_interval = DEFAULT_CONFIG_INTERVAL;
+}
+
+static void
+gst_rtp_gst_pay_reset (GstRtpGSTPay * rtpgstpay, gboolean full)
+{
+  rtpgstpay->last_config = GST_CLOCK_TIME_NONE;
+  gst_adapter_clear (rtpgstpay->adapter);
+  rtpgstpay->flags &= 0x70;
+  rtpgstpay->etype = 0;
+  if (rtpgstpay->pending_buffers)
+    g_list_free_full (rtpgstpay->pending_buffers,
+        (GDestroyNotify) gst_buffer_list_unref);
+  rtpgstpay->pending_buffers = NULL;
+  if (full) {
+    if (rtpgstpay->taglist)
+      gst_tag_list_unref (rtpgstpay->taglist);
+    rtpgstpay->taglist = NULL;
+    g_free (rtpgstpay->stream_id);
+    rtpgstpay->stream_id = NULL;
+    rtpgstpay->current_CV = 0;
+    rtpgstpay->next_CV = 0;
+  }
+}
+
+static void
+gst_rtp_gst_pay_finalize (GObject * obj)
+{
+  GstRtpGSTPay *rtpgstpay;
+
+  rtpgstpay = GST_RTP_GST_PAY (obj);
+
+  gst_rtp_gst_pay_reset (rtpgstpay, TRUE);
+
+  g_object_unref (rtpgstpay->adapter);
+
+  G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gst_rtp_gst_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpGSTPay *rtpgstpay;
+
+  rtpgstpay = GST_RTP_GST_PAY (object);
+
+  switch (prop_id) {
+    case PROP_CONFIG_INTERVAL:
+      rtpgstpay->config_interval = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_gst_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpGSTPay *rtpgstpay;
+
+  rtpgstpay = GST_RTP_GST_PAY (object);
+
+  switch (prop_id) {
+    case PROP_CONFIG_INTERVAL:
+      g_value_set_uint (value, rtpgstpay->config_interval);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_gst_pay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRtpGSTPay *rtpgstpay;
+  GstStateChangeReturn ret;
+
+  rtpgstpay = GST_RTP_GST_PAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_gst_pay_reset (rtpgstpay, TRUE);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_gst_pay_reset (rtpgstpay, TRUE);
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+#define RTP_HEADER_LEN 12
+
+static gboolean
+gst_rtp_gst_pay_create_from_adapter (GstRtpGSTPay * rtpgstpay,
+    GstClockTime timestamp)
+{
+  guint avail, mtu;
+  guint frag_offset;
+  GstBufferList *list;
+
+  avail = gst_adapter_available (rtpgstpay->adapter);
+  if (avail == 0)
+    return FALSE;
+
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpgstpay);
+
+  list = gst_buffer_list_new_sized ((avail / (mtu - (RTP_HEADER_LEN + 8))) + 1);
+  frag_offset = 0;
+
+  while (avail) {
+    guint towrite;
+    guint8 *payload;
+    guint payload_len;
+    guint packet_len;
+    GstBuffer *outbuf;
+    GstRTPBuffer rtp = { NULL };
+    GstBuffer *paybuf;
+
+
+    /* this will be the total lenght of the packet */
+    packet_len = gst_rtp_buffer_calc_packet_len (8 + avail, 0, 0);
+
+    /* fill one MTU or all available bytes */
+    towrite = MIN (packet_len, mtu);
+
+    /* this is the payload length */
+    payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+
+    /* create buffer to hold the header */
+    outbuf = gst_rtp_buffer_new_allocate (8, 0, 0);
+
+    gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+    payload = gst_rtp_buffer_get_payload (&rtp);
+
+    GST_DEBUG_OBJECT (rtpgstpay, "new packet len %u, frag %u", packet_len,
+        frag_offset);
+
+    /*
+     *  0                   1                   2                   3
+     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * |C| CV  |D|0|0|0|     ETYPE     |  MBZ                          |
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * |                          Frag_offset                          |
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     */
+    payload[0] = rtpgstpay->flags;
+    payload[1] = rtpgstpay->etype;
+    payload[2] = payload[3] = 0;
+    payload[4] = frag_offset >> 24;
+    payload[5] = frag_offset >> 16;
+    payload[6] = frag_offset >> 8;
+    payload[7] = frag_offset & 0xff;
+
+    payload += 8;
+    payload_len -= 8;
+
+    frag_offset += payload_len;
+    avail -= payload_len;
+
+    if (avail == 0)
+      gst_rtp_buffer_set_marker (&rtp, TRUE);
+
+    gst_rtp_buffer_unmap (&rtp);
+
+    /* create a new buf to hold the payload */
+    GST_DEBUG_OBJECT (rtpgstpay, "take %u bytes from adapter", payload_len);
+    paybuf = gst_adapter_take_buffer_fast (rtpgstpay->adapter, payload_len);
+
+    /* create a new group to hold the rtp header and the payload */
+    gst_rtp_copy_meta (GST_ELEMENT_CAST (rtpgstpay), outbuf, paybuf, 0);
+    outbuf = gst_buffer_append (outbuf, paybuf);
+
+    GST_BUFFER_PTS (outbuf) = timestamp;
+
+    /* and add to list */
+    gst_buffer_list_insert (list, -1, outbuf);
+  }
+
+  rtpgstpay->flags &= 0x70;
+  rtpgstpay->etype = 0;
+  rtpgstpay->pending_buffers = g_list_append (rtpgstpay->pending_buffers, list);
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_rtp_gst_pay_flush (GstRtpGSTPay * rtpgstpay, GstClockTime timestamp)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GList *iter;
+
+  gst_rtp_gst_pay_create_from_adapter (rtpgstpay, timestamp);
+
+  iter = rtpgstpay->pending_buffers;
+  while (iter) {
+    GstBufferList *list = iter->data;
+
+    rtpgstpay->pending_buffers = iter =
+        g_list_delete_link (rtpgstpay->pending_buffers, iter);
+
+    /* push the whole buffer list at once */
+    ret = gst_rtp_base_payload_push_list (GST_RTP_BASE_PAYLOAD (rtpgstpay),
+        list);
+    if (ret != GST_FLOW_OK)
+      break;
+  }
+
+  return ret;
+}
+
+static GstBuffer *
+make_data_buffer (GstRtpGSTPay * rtpgstpay, gchar * data, guint size)
+{
+  guint plen;
+  guint8 *ptr;
+  GstBuffer *outbuf;
+  GstMapInfo map;
+
+  /* calculate length */
+  plen = 1;
+  while (size >> (7 * plen))
+    plen++;
+
+  outbuf = gst_buffer_new_allocate (NULL, plen + size, NULL);
+
+  gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+  ptr = map.data;
+
+  /* write length */
+  while (plen) {
+    plen--;
+    *ptr++ = ((plen > 0) ? 0x80 : 0) | ((size >> (7 * plen)) & 0x7f);
+  }
+  /* copy data */
+  memcpy (ptr, data, size);
+  gst_buffer_unmap (outbuf, &map);
+
+  return outbuf;
+}
+
+static void
+gst_rtp_gst_pay_send_caps (GstRtpGSTPay * rtpgstpay, guint8 cv, GstCaps * caps)
+{
+  gchar *capsstr;
+  guint capslen;
+  GstBuffer *outbuf;
+
+  if (rtpgstpay->flags & (1 << 7))
+    return;
+
+  capsstr = gst_caps_to_string (caps);
+  capslen = strlen (capsstr);
+  /* for 0 byte */
+  capslen++;
+
+  GST_DEBUG_OBJECT (rtpgstpay, "sending caps=%s", capsstr);
+
+  /* make a data buffer of it */
+  outbuf = make_data_buffer (rtpgstpay, capsstr, capslen);
+  g_free (capsstr);
+
+  /* store in adapter, we don't flush yet, buffer might follow */
+  rtpgstpay->flags = (1 << 7) | (cv << 4);
+  gst_adapter_push (rtpgstpay->adapter, outbuf);
+}
+
+static gboolean
+gst_rtp_gst_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  GstRtpGSTPay *rtpgstpay;
+  gboolean res;
+  gchar *capsstr, *capsenc, *capsver;
+  guint capslen;
+
+  rtpgstpay = GST_RTP_GST_PAY (payload);
+
+  capsstr = gst_caps_to_string (caps);
+  capslen = strlen (capsstr);
+
+  /* encode without 0 byte */
+  capsenc = g_base64_encode ((guchar *) capsstr, capslen);
+  GST_DEBUG_OBJECT (payload, "caps=%s, caps(base64)=%s", capsstr, capsenc);
+  g_free (capsstr);
+
+  /* Send the new caps */
+  rtpgstpay->current_CV = rtpgstpay->next_CV;
+  rtpgstpay->next_CV = (rtpgstpay->next_CV + 1) & 0x7;
+  gst_rtp_gst_pay_send_caps (rtpgstpay, rtpgstpay->current_CV, caps);
+
+  /* make caps for SDP */
+  capsver = g_strdup_printf ("%d", rtpgstpay->current_CV);
+  res =
+      gst_rtp_base_payload_set_outcaps (payload, "caps", G_TYPE_STRING, capsenc,
+      "capsversion", G_TYPE_STRING, capsver, NULL);
+  g_free (capsenc);
+  g_free (capsver);
+
+  return res;
+}
+
+static void
+gst_rtp_gst_pay_send_event (GstRtpGSTPay * rtpgstpay, guint etype,
+    GstEvent * event)
+{
+  const GstStructure *s;
+  gchar *estr;
+  guint elen;
+  GstBuffer *outbuf;
+
+  /* Create the standalone caps packet if an inlined caps was pending */
+  gst_rtp_gst_pay_create_from_adapter (rtpgstpay, GST_CLOCK_TIME_NONE);
+
+  s = gst_event_get_structure (event);
+
+  estr = gst_structure_to_string (s);
+  elen = strlen (estr);
+  /* for 0 byte */
+  elen++;
+  outbuf = make_data_buffer (rtpgstpay, estr, elen);
+  GST_DEBUG_OBJECT (rtpgstpay, "sending event=%s", estr);
+  g_free (estr);
+
+  rtpgstpay->etype = etype;
+  gst_adapter_push (rtpgstpay->adapter, outbuf);
+  /* Create the event packet now to avoid conflict with data/caps packets */
+  gst_rtp_gst_pay_create_from_adapter (rtpgstpay, GST_CLOCK_TIME_NONE);
+}
+
+static gboolean
+gst_rtp_gst_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+  gboolean ret;
+  GstRtpGSTPay *rtpgstpay;
+  guint etype = 0;
+
+  rtpgstpay = GST_RTP_GST_PAY (payload);
+
+  ret =
+      GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload,
+      gst_event_ref (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      gst_rtp_gst_pay_reset (rtpgstpay, FALSE);
+      break;
+    case GST_EVENT_TAG:{
+      GstTagList *tags;
+
+      gst_event_parse_tag (event, &tags);
+
+      if (gst_tag_list_get_scope (tags) == GST_TAG_SCOPE_STREAM) {
+        GstTagList *old;
+
+        GST_DEBUG_OBJECT (rtpgstpay, "storing stream tags %" GST_PTR_FORMAT,
+            tags);
+        if ((old = rtpgstpay->taglist))
+          gst_tag_list_unref (old);
+        rtpgstpay->taglist = gst_tag_list_ref (tags);
+      }
+      etype = 1;
+      break;
+    }
+    case GST_EVENT_CUSTOM_DOWNSTREAM:
+      etype = 2;
+      break;
+    case GST_EVENT_CUSTOM_BOTH:
+      etype = 3;
+      break;
+    case GST_EVENT_STREAM_START:{
+      const gchar *stream_id = NULL;
+
+      if (rtpgstpay->taglist)
+        gst_tag_list_unref (rtpgstpay->taglist);
+      rtpgstpay->taglist = NULL;
+
+      gst_event_parse_stream_start (event, &stream_id);
+      if (stream_id) {
+        g_free (rtpgstpay->stream_id);
+        rtpgstpay->stream_id = g_strdup (stream_id);
+      }
+      etype = 4;
+      break;
+    }
+    default:
+      GST_LOG_OBJECT (rtpgstpay, "no event for %s",
+          GST_EVENT_TYPE_NAME (event));
+      break;
+  }
+  if (etype) {
+    GST_DEBUG_OBJECT (rtpgstpay, "make event type %d for %s",
+        etype, GST_EVENT_TYPE_NAME (event));
+    gst_rtp_gst_pay_send_event (rtpgstpay, etype, event);
+    /* Do not send stream-start right away since caps/new-segment were not yet
+       sent, so our data would be considered invalid */
+    if (etype != 4) {
+      /* flush the adapter immediately */
+      gst_rtp_gst_pay_flush (rtpgstpay, GST_CLOCK_TIME_NONE);
+    }
+  }
+
+  gst_event_unref (event);
+
+  return ret;
+}
+
+static void
+gst_rtp_gst_pay_send_config (GstRtpGSTPay * rtpgstpay, GstClockTime timestamp)
+{
+  GstPad *pad = GST_RTP_BASE_PAYLOAD_SINKPAD (rtpgstpay);
+  GstCaps *caps = NULL;
+  GstEvent *tag = NULL;
+  GstEvent *stream_start = NULL;
+
+  GST_DEBUG_OBJECT (rtpgstpay, "time to send config");
+  /* Send tags */
+  if (rtpgstpay->taglist && !gst_tag_list_is_empty (rtpgstpay->taglist))
+    tag = gst_event_new_tag (gst_tag_list_ref (rtpgstpay->taglist));
+  if (tag) {
+    /* Send start-stream to clear tags */
+    if (rtpgstpay->stream_id)
+      stream_start = gst_event_new_stream_start (rtpgstpay->stream_id);
+    if (stream_start) {
+      gst_rtp_gst_pay_send_event (rtpgstpay, 4, stream_start);
+      gst_event_unref (stream_start);
+    }
+    gst_rtp_gst_pay_send_event (rtpgstpay, 1, tag);
+    gst_event_unref (tag);
+  }
+  /* send caps */
+  caps = gst_pad_get_current_caps (pad);
+  if (caps) {
+    gst_rtp_gst_pay_send_caps (rtpgstpay, rtpgstpay->current_CV, caps);
+    gst_caps_unref (caps);
+  }
+  rtpgstpay->last_config = timestamp;
+}
+
+static GstFlowReturn
+gst_rtp_gst_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstFlowReturn ret;
+  GstRtpGSTPay *rtpgstpay;
+  GstClockTime timestamp;
+
+  rtpgstpay = GST_RTP_GST_PAY (basepayload);
+
+  timestamp = GST_BUFFER_PTS (buffer);
+
+  /* check if we need to send the caps and taglist now */
+  if (rtpgstpay->config_interval > 0) {
+    GST_DEBUG_OBJECT (rtpgstpay,
+        "timestamp %" GST_TIME_FORMAT ", last config %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (timestamp), GST_TIME_ARGS (rtpgstpay->last_config));
+
+    if (timestamp != GST_CLOCK_TIME_NONE &&
+        rtpgstpay->last_config != GST_CLOCK_TIME_NONE) {
+      guint64 diff;
+
+      /* calculate diff between last SPS/PPS in milliseconds */
+      if (timestamp > rtpgstpay->last_config)
+        diff = timestamp - rtpgstpay->last_config;
+      else
+        diff = 0;
+
+      GST_DEBUG_OBJECT (rtpgstpay,
+          "interval since last config %" GST_TIME_FORMAT, GST_TIME_ARGS (diff));
+
+      /* bigger than interval, queue SPS/PPS */
+      if (GST_TIME_AS_SECONDS (diff) >= rtpgstpay->config_interval)
+        gst_rtp_gst_pay_send_config (rtpgstpay, timestamp);
+    } else {
+      gst_rtp_gst_pay_send_config (rtpgstpay, timestamp);
+    }
+  }
+
+  /* caps always from SDP for now */
+  if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT))
+    rtpgstpay->flags |= (1 << 3);
+
+  gst_adapter_push (rtpgstpay->adapter, buffer);
+  ret = gst_rtp_gst_pay_flush (rtpgstpay, timestamp);
+
+  return ret;
+}
+
+gboolean
+gst_rtp_gst_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpgstpay",
+      GST_RANK_NONE, GST_TYPE_RTP_GST_PAY);
+}
diff --git a/gst/rtp/gstrtpgstpay.h b/gst/rtp/gstrtpgstpay.h
new file mode 100644
index 0000000..f3272b2
--- /dev/null
+++ b/gst/rtp/gstrtpgstpay.h
@@ -0,0 +1,72 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_GST_PAY_H__
+#define __GST_RTP_GST_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_GST_PAY \
+  (gst_rtp_gst_pay_get_type())
+#define GST_RTP_GST_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_GST_PAY,GstRtpGSTPay))
+#define GST_RTP_GST_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_GST_PAY,GstRtpGSTPayClass))
+#define GST_IS_RTP_GST_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_GST_PAY))
+#define GST_IS_RTP_GST_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GST_PAY))
+
+typedef struct _GstRtpGSTPay GstRtpGSTPay;
+typedef struct _GstRtpGSTPayClass GstRtpGSTPayClass;
+
+struct _GstRtpGSTPay
+{
+  GstRTPBasePayload payload;
+
+  GList *pending_buffers; /* GstBufferList */
+  GstAdapter *adapter;
+  guint8 flags;
+  guint8 etype;
+
+  guint8 current_CV; /* CV field of incoming caps*/
+  guint8 next_CV;
+
+  gchar *stream_id;
+  GstTagList *taglist;
+  guint config_interval;
+  GstClockTime last_config;
+};
+
+struct _GstRtpGSTPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_gst_pay_get_type (void);
+
+gboolean gst_rtp_gst_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_GST_PAY_H__ */
diff --git a/gst/rtp/gstrtph261depay.c b/gst/rtp/gstrtph261depay.c
new file mode 100644
index 0000000..5d37229
--- /dev/null
+++ b/gst/rtp/gstrtph261depay.c
@@ -0,0 +1,294 @@
+/* GStreamer
+ *
+ * Copyright (C) <2014> Stian Selnes <stian@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-rtph261depay
+ * @see_also: rtph261pay
+ *
+ * Extract encoded H.261 video frames from RTP packets according to RFC 4587.
+ * For detailed information see: https://www.rfc-editor.org/rfc/rfc4587.txt
+ *
+ * The depayloader takes an RTP packet and extracts its H.261 stream. It
+ * aggregates the extracted stream until a complete frame is received before
+ * it pushes it downstream.
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 udpsrc caps='application/x-rtp, payload=31' ! rtph261depay ! avdec_h261 ! autovideosink
+ * ]| This example pipeline will depayload and decode an RTP H.261 video stream.
+ * Refer to the rtph261pay example to create the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+#include "gstrtph261depay.h"
+#include "gstrtph261pay.h"      /* GstRtpH261PayHeader */
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtph261depay_debug);
+#define GST_CAT_DEFAULT (rtph261depay_debug)
+
+static const guint8 NO_LEFTOVER = 0xFF;
+
+static GstStaticPadTemplate gst_rtp_h261_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-h261")
+    );
+
+static GstStaticPadTemplate gst_rtp_h261_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_H261_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"H261\"; "
+        "application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"H261\"")
+    );
+
+G_DEFINE_TYPE (GstRtpH261Depay, gst_rtp_h261_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+#define parent_class gst_rtp_h261_depay_parent_class
+
+static GstBuffer *
+gst_rtp_h261_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpH261Depay *depay;
+  GstBuffer *outbuf = NULL;
+  gint payload_len;
+  guint8 *payload;
+  const guint header_len = GST_RTP_H261_PAYLOAD_HEADER_LEN;
+  gboolean marker;
+  GstRtpH261PayHeader *header;
+
+  depay = GST_RTP_H261_DEPAY (depayload);
+
+  if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
+    GST_DEBUG_OBJECT (depay, "Discont buffer, flushing adapter");
+    gst_adapter_clear (depay->adapter);
+    depay->leftover = NO_LEFTOVER;
+    depay->start = FALSE;
+  }
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+  payload = gst_rtp_buffer_get_payload (rtp);
+
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  if (payload_len < header_len + 1) {
+    /* Must have at least one byte payload */
+    GST_WARNING_OBJECT (depay, "Dropping packet with invalid payload length");
+    return NULL;
+  }
+
+  header = (GstRtpH261PayHeader *) payload;
+
+  GST_DEBUG_OBJECT (depay,
+      "payload_len: %d, header_len: %d, sbit: %d, ebit: %d, marker %d",
+      payload_len, header_len, header->sbit, header->ebit, marker);
+
+  payload += header_len;
+  payload_len -= header_len;
+
+  if (!depay->start) {
+    /* Check for picture start code */
+    guint32 bits = GST_READ_UINT32_BE (payload) << header->sbit;
+    if (payload_len > 4 && bits >> 12 == 0x10) {
+      GST_DEBUG_OBJECT (depay, "Found picture start code");
+      depay->start = TRUE;
+    } else {
+      GST_DEBUG_OBJECT (depay, "No picture start code yet, skipping payload");
+      goto skip;
+    }
+  }
+
+  if (header->sbit != 0) {
+    /* Take the leftover from previous packet and merge it at the beginning */
+    payload[0] &= 0xFF >> header->sbit;
+    if (depay->leftover != NO_LEFTOVER) {
+      /* Happens if sbit is set for first packet in frame. Then previous byte
+       * has already been flushed. */
+      payload[0] |= depay->leftover;
+    }
+    depay->leftover = NO_LEFTOVER;
+  }
+
+  if (header->ebit == 0) {
+    /* H.261 stream ends on byte boundary, take entire packet */
+    gst_adapter_push (depay->adapter,
+        gst_rtp_buffer_get_payload_subbuffer (rtp, header_len, payload_len));
+  } else {
+    /* Take the entire buffer except for the last byte, which will be kept to
+     * merge with next packet */
+    gst_adapter_push (depay->adapter,
+        gst_rtp_buffer_get_payload_subbuffer (rtp, header_len,
+            payload_len - 1));
+    depay->leftover = payload[payload_len - 1] & (0xFF << header->ebit);
+  }
+
+skip:
+  if (marker) {
+    if (depay->start) {
+      guint avail;
+
+      if (depay->leftover != NO_LEFTOVER) {
+        GstBuffer *buf = gst_buffer_new_and_alloc (1);
+        gst_buffer_memset (buf, 0, depay->leftover, 1);
+        gst_adapter_push (depay->adapter, buf);
+        depay->leftover = NO_LEFTOVER;
+      }
+
+      avail = gst_adapter_available (depay->adapter);
+      outbuf = gst_adapter_take_buffer (depay->adapter, avail);
+      gst_rtp_drop_non_video_meta (depay, outbuf);
+
+      /* Note that the I flag does not mean intra frame, but that the entire
+       * stream is intra coded. */
+      if (header->i)
+        GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+      else
+        GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+      GST_DEBUG_OBJECT (depay, "Pushing out a buffer of %u bytes", avail);
+      depay->start = FALSE;
+    } else {
+      depay->start = TRUE;
+    }
+  }
+
+  return outbuf;
+}
+
+static gboolean
+gst_rtp_h261_depay_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps)
+{
+  GstCaps *srccaps;
+
+  srccaps = gst_caps_new_empty_simple ("video/x-h261");
+  gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (filter), srccaps);
+  gst_caps_unref (srccaps);
+
+  return TRUE;
+}
+
+static GstStateChangeReturn
+gst_rtp_h261_depay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpH261Depay *depay;
+  GstStateChangeReturn ret;
+
+  depay = GST_RTP_H261_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_adapter_clear (depay->adapter);
+      depay->start = FALSE;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+static void
+gst_rtp_h261_depay_dispose (GObject * object)
+{
+  GstRtpH261Depay *depay;
+
+  depay = GST_RTP_H261_DEPAY (object);
+
+  if (depay->adapter) {
+    gst_object_unref (depay->adapter);
+    depay->adapter = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_rtp_h261_depay_class_init (GstRtpH261DepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gstelement_class = GST_ELEMENT_CLASS (klass);
+  gstrtpbasedepayload_class = GST_RTP_BASE_DEPAYLOAD_CLASS (klass);
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h261_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h261_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP H261 depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts H261 video from RTP packets (RFC 4587)",
+      "Stian Selnes <stian@pexip.com>");
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_h261_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_h261_depay_setcaps;
+
+  gobject_class->dispose = gst_rtp_h261_depay_dispose;
+
+  gstelement_class->change_state = gst_rtp_h261_depay_change_state;
+
+  GST_DEBUG_CATEGORY_INIT (rtph261depay_debug, "rtph261depay", 0,
+      "H261 Video RTP Depayloader");
+}
+
+static void
+gst_rtp_h261_depay_init (GstRtpH261Depay * depay)
+{
+  depay->adapter = gst_adapter_new ();
+  depay->leftover = NO_LEFTOVER;
+}
+
+gboolean
+gst_rtp_h261_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtph261depay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_H261_DEPAY);
+}
diff --git a/gst/rtp/gstrtph261depay.h b/gst/rtp/gstrtph261depay.h
new file mode 100644
index 0000000..f87f817
--- /dev/null
+++ b/gst/rtp/gstrtph261depay.h
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) <2014> Stian Selnes <stian@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_RTP_H261_DEPAY_H__
+#define __GST_RTP_H261_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_H261_DEPAY \
+  (gst_rtp_h261_depay_get_type())
+#define GST_RTP_H261_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H261_DEPAY,GstRtpH261Depay))
+#define GST_RTP_H261_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H261_DEPAY,GstRtpH261DepayClass))
+#define GST_IS_RTP_H261_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H261_DEPAY))
+#define GST_IS_RTP_H261_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H261_DEPAY))
+typedef struct _GstRtpH261Depay GstRtpH261Depay;
+typedef struct _GstRtpH261DepayClass GstRtpH261DepayClass;
+
+struct _GstRtpH261Depay
+{
+  GstRTPBaseDepayload depayload;
+
+  GstAdapter *adapter;
+  gboolean start;
+  guint8 leftover;
+};
+
+struct _GstRtpH261DepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_h261_depay_get_type (void);
+
+gboolean gst_rtp_h261_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_H261_DEPAY_H__ */
diff --git a/gst/rtp/gstrtph261pay.c b/gst/rtp/gstrtph261pay.c
new file mode 100644
index 0000000..b592d11
--- /dev/null
+++ b/gst/rtp/gstrtph261pay.c
@@ -0,0 +1,1071 @@
+/* GStreamer
+ * Copyright (C) <2014> Stian Selnes <stian@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+/**
+ * SECTION:element-rtph261pay
+ * @see_also: rtph261depay
+ *
+ * Payload encoded H.261 video frames into RTP packets according to RFC 4587.
+ * For detailed information see: https://www.rfc-editor.org/rfc/rfc4587.txt
+ *
+ * The payloader takes a H.261 frame, parses it and splits it into fragments
+ * on MB boundaries in order to match configured MTU size. For each fragment
+ * an RTP packet is constructed with an RTP packet header followed by the
+ * fragment. In addition the payloader will make sure the packetized H.261
+ * stream appears as a continuous bit-stream after depacketization by shifting
+ * the encoded bit-stream of a frame to align with the last significant bit of
+ * the previous frame. This helps interoperability in the case where the
+ * encoder does not produce a continuous bit-stream but the decoder requires
+ * it.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 videotestsrc ! avenc_h261 ! rtph261pay ! udpsink
+ * ]| This will encode a test video and payload it. Refer to the rtph261depay
+ * example to depayload and play the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "gstrtph261pay.h"
+#include "gstrtputils.h"
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+#include <gst/base/gstbitreader.h>
+#include <string.h>
+
+GST_DEBUG_CATEGORY_STATIC (rtph261pay_debug);
+#define GST_CAT_DEFAULT (rtph261pay_debug)
+
+#define GST_RTP_HEADER_LEN 12
+#define GST_RTP_H261_PAYLOAD_HEADER_LEN 4
+
+static GstStaticPadTemplate gst_rtp_h261_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-h261")
+    );
+
+static GstStaticPadTemplate gst_rtp_h261_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_H261_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"H261\"; "
+        "application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"H261\"")
+    );
+
+G_DEFINE_TYPE (GstRtpH261Pay, gst_rtp_h261_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+#define parent_class gst_rtp_h261_pay_parent_class
+
+typedef struct
+{
+  guint32 mba;
+  guint32 mtype;
+  guint32 quant;
+  gint mvx;
+  gint mvy;
+  guint endpos;
+  gint gobn;
+} Macroblock;
+
+typedef struct
+{
+  Macroblock last;
+  guint startpos;
+  guint endpos;
+  guint32 gn;
+  guint32 gquant;
+} Gob;
+
+#define PSC_LEN 20
+#define TR_LEN 5
+#define PTYPE_LEN 6
+#define GBSC_LEN 16
+#define GN_LEN 4
+#define GQUANT_LEN 5
+#define GEI_LEN 1
+#define GSPARE_LEN 8
+#define MQUANT_LEN 5
+#define MAX_NUM_GOB 12
+
+typedef enum
+{
+  PARSE_END_OF_BUFFER = -2,
+  PARSE_ERROR = -1,
+  PARSE_OK = 0,
+  PARSE_END_OF_FRAME,
+  PARSE_END_OF_GOB,
+} ParseReturn;
+
+
+#define SKIP_BITS(br,nbits) G_STMT_START {      \
+    if (!gst_bit_reader_skip (br, nbits))       \
+      return PARSE_END_OF_BUFFER;               \
+  } G_STMT_END
+
+#define GET_BITS(br,val,nbits) G_STMT_START {             \
+    if (!gst_bit_reader_get_bits_uint32 (br, val, nbits)) \
+      return PARSE_END_OF_BUFFER;                         \
+  } G_STMT_END
+
+/* Unchecked since we peek outside the buffer. Ok because of padding. */
+#define PEEK_BITS(br,val,nbits) G_STMT_START {                    \
+    *val = gst_bit_reader_peek_bits_uint16_unchecked (br, nbits); \
+  } G_STMT_END
+
+
+#define MBA_STUFFING 34
+#define MBA_START_CODE 35
+#define MBA_LEN 35
+#define MBA_WID 4
+/* [code, mask, nbits, mba] */
+static const guint16 mba_table[MBA_LEN][MBA_WID] = {
+  {0x8000, 0x8000, 1, 1},
+  {0x6000, 0xe000, 3, 2},
+  {0x4000, 0xe000, 3, 3},
+  {0x3000, 0xf000, 4, 4},
+  {0x2000, 0xf000, 4, 5},
+  {0x1800, 0xf800, 5, 6},
+  {0x1000, 0xf800, 5, 7},
+  {0x0e00, 0xfe00, 7, 8},
+  {0x0c00, 0xfe00, 7, 9},
+  {0x0b00, 0xff00, 8, 10},
+  {0x0a00, 0xff00, 8, 11},
+  {0x0900, 0xff00, 8, 12},
+  {0x0800, 0xff00, 8, 13},
+  {0x0700, 0xff00, 8, 14},
+  {0x0600, 0xff00, 8, 15},
+  {0x05c0, 0xffc0, 10, 16},
+  {0x0580, 0xffc0, 10, 17},
+  {0x0540, 0xffc0, 10, 18},
+  {0x0500, 0xffc0, 10, 19},
+  {0x04c0, 0xffc0, 10, 20},
+  {0x0480, 0xffc0, 10, 21},
+  {0x0460, 0xffe0, 11, 22},
+  {0x0440, 0xffe0, 11, 23},
+  {0x0420, 0xffe0, 11, 24},
+  {0x0400, 0xffe0, 11, 25},
+  {0x03e0, 0xffe0, 11, 26},
+  {0x03c0, 0xffe0, 11, 27},
+  {0x03a0, 0xffe0, 11, 28},
+  {0x0380, 0xffe0, 11, 29},
+  {0x0360, 0xffe0, 11, 30},
+  {0x0340, 0xffe0, 11, 31},
+  {0x0320, 0xffe0, 11, 32},
+  {0x0300, 0xffe0, 11, 33},
+  {0x01e0, 0xffe0, 11, MBA_STUFFING},
+  {0x0001, 0xffff, 16, MBA_START_CODE},
+};
+
+#define MTYPE_INTRA    (1 << 0)
+#define MTYPE_INTER    (1 << 1)
+#define MTYPE_MC       (1 << 2)
+#define MTYPE_FIL      (1 << 3)
+#define MTYPE_MQUANT   (1 << 4)
+#define MTYPE_MVD      (1 << 5)
+#define MTYPE_CBP      (1 << 6)
+#define MTYPE_TCOEFF   (1 << 7)
+#define MTYPE_LEN 10
+#define MTYPE_WID 4
+/* [code, mask, nbits, flags] */
+static const guint16 mtype_table[MTYPE_LEN][MTYPE_WID] = {
+  {0x8000, 0x8000, 1, MTYPE_INTER | MTYPE_CBP | MTYPE_TCOEFF},
+  {0x4000, 0xc000, 2,
+      MTYPE_INTER | MTYPE_MC | MTYPE_FIL | MTYPE_MVD | MTYPE_CBP |
+        MTYPE_TCOEFF},
+  {0x2000, 0xe000, 3, MTYPE_INTER | MTYPE_MC | MTYPE_FIL | MTYPE_MVD},
+  {0x1000, 0xf000, 4, MTYPE_INTRA | MTYPE_TCOEFF},
+  {0x0800, 0xf800, 5, MTYPE_INTER | MTYPE_MQUANT | MTYPE_CBP | MTYPE_TCOEFF},
+  {0x0400, 0xfc00, 6,
+      MTYPE_INTER | MTYPE_MC | MTYPE_FIL | MTYPE_MQUANT | MTYPE_MVD |
+        MTYPE_CBP | MTYPE_TCOEFF},
+  {0x0200, 0xfe00, 7, MTYPE_INTRA | MTYPE_MQUANT | MTYPE_TCOEFF},
+  {0x0100, 0xff00, 8,
+      MTYPE_INTER | MTYPE_MC | MTYPE_MVD | MTYPE_CBP | MTYPE_TCOEFF},
+  {0x0080, 0xff80, 9, MTYPE_INTER | MTYPE_MC | MTYPE_MVD},
+  {0x0040, 0xffc0, 10,
+      MTYPE_INTER | MTYPE_MC | MTYPE_MQUANT | MTYPE_MVD | MTYPE_CBP |
+        MTYPE_TCOEFF},
+};
+
+#define MVD_LEN 32
+#define MVD_WID 5
+/* [code, mask, nbits, mvd1, mvd2] */
+static const guint16 mvd_table[MVD_LEN][MVD_WID] = {
+  {0x8000, 0x8000, 1, 0, 0},
+  {0x6000, 0xe000, 3, -1, -1},
+  {0x4000, 0xe000, 3, 1, 1},
+  {0x3000, 0xf000, 4, -2, 30},
+  {0x2000, 0xf000, 4, 2, -30},
+  {0x1800, 0xf800, 5, -3, 29},
+  {0x1000, 0xf800, 5, 3, -29},
+  {0x0e00, 0xfe00, 7, -4, 28},
+  {0x0c00, 0xfe00, 7, 4, -28},
+  {0x0700, 0xff00, 8, -7, 25},
+  {0x0900, 0xff00, 8, -6, 26},
+  {0x0b00, 0xff00, 8, -5, 27},
+  {0x0a00, 0xff00, 8, 5, -27},
+  {0x0800, 0xff00, 8, 6, -26},
+  {0x0600, 0xff00, 8, 7, -25},
+  {0x04c0, 0xffc0, 10, -10, 22},
+  {0x0540, 0xffc0, 10, -9, 23},
+  {0x05c0, 0xffc0, 10, -8, 24},
+  {0x0580, 0xffc0, 10, 8, -24},
+  {0x0500, 0xffc0, 10, 9, -23},
+  {0x0480, 0xffc0, 10, 10, -22},
+  {0x0320, 0xffe0, 11, -16, 16},
+  {0x0360, 0xffe0, 11, -15, 17},
+  {0x03a0, 0xffe0, 11, -14, 18},
+  {0x03e0, 0xffe0, 11, -13, 19},
+  {0x0420, 0xffe0, 11, -12, 20},
+  {0x0460, 0xffe0, 11, -11, 21},
+  {0x0440, 0xffe0, 11, 11, -21},
+  {0x0400, 0xffe0, 11, 12, -20},
+  {0x03c0, 0xffe0, 11, 13, -19},
+  {0x0380, 0xffe0, 11, 14, -18},
+  {0x0340, 0xffe0, 11, 15, -17},
+};
+
+#define CBP_LEN 63
+/* [code, mask, nbits, cbp] */
+static const guint16 cbp_table[CBP_LEN][4] = {
+  {0xe000, 0xe000, 3, 60},
+  {0xd000, 0xf000, 4, 4},
+  {0xc000, 0xf000, 4, 8},
+  {0xb000, 0xf000, 4, 16},
+  {0xa000, 0xf000, 4, 32},
+  {0x9800, 0xf800, 5, 12},
+  {0x9000, 0xf800, 5, 48},
+  {0x8800, 0xf800, 5, 20},
+  {0x8000, 0xf800, 5, 40},
+  {0x7800, 0xf800, 5, 28},
+  {0x7000, 0xf800, 5, 44},
+  {0x6800, 0xf800, 5, 52},
+  {0x6000, 0xf800, 5, 56},
+  {0x5800, 0xf800, 5, 1},
+  {0x5000, 0xf800, 5, 61},
+  {0x4800, 0xf800, 5, 2},
+  {0x4000, 0xf800, 5, 62},
+  {0x3c00, 0xfc00, 6, 24},
+  {0x3800, 0xfc00, 6, 36},
+  {0x3400, 0xfc00, 6, 3},
+  {0x3000, 0xfc00, 6, 63},
+  {0x2e00, 0xfe00, 7, 5},
+  {0x2c00, 0xfe00, 7, 9},
+  {0x2a00, 0xfe00, 7, 17},
+  {0x2800, 0xfe00, 7, 33},
+  {0x2600, 0xfe00, 7, 6},
+  {0x2400, 0xfe00, 7, 10},
+  {0x2200, 0xfe00, 7, 18},
+  {0x2000, 0xfe00, 7, 34},
+  {0x1f00, 0xff00, 8, 7},
+  {0x1e00, 0xff00, 8, 11},
+  {0x1d00, 0xff00, 8, 19},
+  {0x1c00, 0xff00, 8, 35},
+  {0x1b00, 0xff00, 8, 13},
+  {0x1a00, 0xff00, 8, 49},
+  {0x1900, 0xff00, 8, 21},
+  {0x1800, 0xff00, 8, 41},
+  {0x1700, 0xff00, 8, 14},
+  {0x1600, 0xff00, 8, 50},
+  {0x1500, 0xff00, 8, 22},
+  {0x1400, 0xff00, 8, 42},
+  {0x1300, 0xff00, 8, 15},
+  {0x1200, 0xff00, 8, 51},
+  {0x1100, 0xff00, 8, 23},
+  {0x1000, 0xff00, 8, 43},
+  {0x0f00, 0xff00, 8, 25},
+  {0x0e00, 0xff00, 8, 37},
+  {0x0d00, 0xff00, 8, 26},
+  {0x0c00, 0xff00, 8, 38},
+  {0x0b00, 0xff00, 8, 29},
+  {0x0a00, 0xff00, 8, 45},
+  {0x0900, 0xff00, 8, 53},
+  {0x0800, 0xff00, 8, 57},
+  {0x0700, 0xff00, 8, 30},
+  {0x0600, 0xff00, 8, 46},
+  {0x0500, 0xff00, 8, 54},
+  {0x0400, 0xff00, 8, 58},
+  {0x0380, 0xff80, 9, 31},
+  {0x0300, 0xff80, 9, 47},
+  {0x0280, 0xff80, 9, 55},
+  {0x0200, 0xff80, 9, 59},
+  {0x0180, 0xff80, 9, 27},
+  {0x0100, 0xff80, 9, 39},
+};
+
+#define TCOEFF_EOB 0xffff
+#define TCOEFF_ESC 0xfffe
+#define TCOEFF_LEN 65
+/* [code, mask, nbits, run, level] */
+static const guint16 tcoeff_table[TCOEFF_LEN][5] = {
+  {0x8000, 0xc000, 2, TCOEFF_EOB, 0},   /* Not available for first coeff */
+  /* {0x8000, 0x8000,  2,  0,  1}, *//* Available only for first Inter coeff */
+  {0xc000, 0xc000, 3, 0, 1},    /* Not available for first coeff */
+  {0x6000, 0xe000, 4, 1, 1},
+  {0x4000, 0xf000, 5, 0, 2},
+  {0x5000, 0xf000, 5, 2, 1},
+  {0x2800, 0xf800, 6, 0, 3},
+  {0x3800, 0xf800, 6, 3, 1},
+  {0x3000, 0xf800, 6, 4, 1},
+  {0x0400, 0xfc00, 6, TCOEFF_ESC, 0},
+  {0x1800, 0xfc00, 7, 1, 2},
+  {0x1c00, 0xfc00, 7, 5, 1},
+  {0x1400, 0xfc00, 7, 6, 1},
+  {0x1000, 0xfc00, 7, 7, 1},
+  {0x0c00, 0xfe00, 8, 0, 4},
+  {0x0800, 0xfe00, 8, 2, 2},
+  {0x0e00, 0xfe00, 8, 8, 1},
+  {0x0a00, 0xfe00, 8, 9, 1},
+  {0x2600, 0xff00, 9, 0, 5},
+  {0x2100, 0xff00, 9, 0, 6},
+  {0x2500, 0xff00, 9, 1, 3},
+  {0x2400, 0xff00, 9, 3, 2},
+  {0x2700, 0xff00, 9, 10, 1},
+  {0x2300, 0xff00, 9, 11, 1},
+  {0x2200, 0xff00, 9, 12, 1},
+  {0x2000, 0xff00, 9, 13, 1},
+  {0x0280, 0xffc0, 11, 0, 7},
+  {0x0300, 0xffc0, 11, 1, 4},
+  {0x02c0, 0xffc0, 11, 2, 3},
+  {0x03c0, 0xffc0, 11, 4, 2},
+  {0x0240, 0xffc0, 11, 5, 2},
+  {0x0380, 0xffc0, 11, 14, 1},
+  {0x0340, 0xffc0, 11, 15, 1},
+  {0x0200, 0xffc0, 11, 16, 1},
+  {0x01d0, 0xfff0, 13, 0, 8},
+  {0x0180, 0xfff0, 13, 0, 9},
+  {0x0130, 0xfff0, 13, 0, 10},
+  {0x0100, 0xfff0, 13, 0, 11},
+  {0x01b0, 0xfff0, 13, 1, 5},
+  {0x0140, 0xfff0, 13, 2, 4},
+  {0x01c0, 0xfff0, 13, 3, 3},
+  {0x0120, 0xfff0, 13, 4, 3},
+  {0x01e0, 0xfff0, 13, 6, 2},
+  {0x0150, 0xfff0, 13, 7, 2},
+  {0x0110, 0xfff0, 13, 8, 2},
+  {0x01f0, 0xfff0, 13, 17, 1},
+  {0x01a0, 0xfff0, 13, 18, 1},
+  {0x0190, 0xfff0, 13, 19, 1},
+  {0x0170, 0xfff0, 13, 20, 1},
+  {0x0160, 0xfff0, 13, 21, 1},
+  {0x00d0, 0xfff8, 14, 0, 12},
+  {0x00c8, 0xfff8, 14, 0, 13},
+  {0x00c0, 0xfff8, 14, 0, 14},
+  {0x00b8, 0xfff8, 14, 0, 15},
+  {0x00b0, 0xfff8, 14, 1, 6},
+  {0x00a8, 0xfff8, 14, 1, 7},
+  {0x00a0, 0xfff8, 14, 2, 5},
+  {0x0098, 0xfff8, 14, 3, 4},
+  {0x0090, 0xfff8, 14, 5, 3},
+  {0x0088, 0xfff8, 14, 9, 2},
+  {0x0080, 0xfff8, 14, 10, 2},
+  {0x00f8, 0xfff8, 14, 22, 1},
+  {0x00f0, 0xfff8, 14, 23, 1},
+  {0x00e8, 0xfff8, 14, 24, 1},
+  {0x00e0, 0xfff8, 14, 25, 1},
+  {0x00d8, 0xfff8, 14, 26, 1},
+};
+
+static ParseReturn
+decode_mba (GstBitReader * br, gint * mba)
+{
+  gint i;
+  guint16 code;
+
+  *mba = -1;
+  do {
+    PEEK_BITS (br, &code, 16);
+    for (i = 0; i < MBA_LEN; i++) {
+      if ((code & mba_table[i][1]) == mba_table[i][0]) {
+        *mba = mba_table[i][3];
+
+        if (*mba == MBA_START_CODE)
+          return PARSE_END_OF_GOB;
+        SKIP_BITS (br, mba_table[i][2]);
+        if (*mba != MBA_STUFFING)
+          return PARSE_OK;
+      }
+    }
+  } while (*mba == MBA_STUFFING);
+
+  /* 0x0 indicates end of frame since we appended 0-bytes */
+  if (code == 0x0)
+    return PARSE_END_OF_FRAME;
+
+  return PARSE_ERROR;
+}
+
+static ParseReturn
+decode_mtype (GstBitReader * br, guint * mtype)
+{
+  gint i;
+  guint16 code;
+
+  PEEK_BITS (br, &code, 16);
+  for (i = 0; i < MTYPE_LEN; i++) {
+    if ((code & mtype_table[i][1]) == mtype_table[i][0]) {
+      SKIP_BITS (br, mtype_table[i][2]);
+      *mtype = mtype_table[i][3];
+      return PARSE_OK;
+    }
+  }
+
+  return PARSE_ERROR;
+}
+
+static ParseReturn
+decode_mvd (GstBitReader * br, gint * mvd1, gint * mvd2)
+{
+  gint i;
+  guint16 code;
+
+  PEEK_BITS (br, &code, 16);
+  for (i = 0; i < MVD_LEN; i++) {
+    if ((code & mvd_table[i][1]) == mvd_table[i][0]) {
+      SKIP_BITS (br, mvd_table[i][2]);
+      *mvd1 = (gint16) mvd_table[i][3];
+      *mvd2 = (gint16) mvd_table[i][4];
+      return PARSE_OK;
+    }
+  }
+
+  return PARSE_ERROR;
+}
+
+static ParseReturn
+decode_cbp (GstBitReader * br, guint * cbp)
+{
+  gint i;
+  guint16 code;
+
+  PEEK_BITS (br, &code, 16);
+  for (i = 0; i < CBP_LEN; i++) {
+    if ((code & cbp_table[i][1]) == cbp_table[i][0]) {
+      SKIP_BITS (br, cbp_table[i][2]);
+      *cbp = cbp_table[i][3];
+      return PARSE_OK;
+    }
+  }
+
+  return PARSE_ERROR;
+}
+
+static ParseReturn
+decode_tcoeff (GstBitReader * br, guint mtype)
+{
+  gint i;
+  guint16 code;
+  gboolean eob;
+
+  /* Special handling of first coeff */
+  if (mtype & MTYPE_INTER) {
+    /* Inter, different vlc since EOB is not allowed */
+    PEEK_BITS (br, &code, 16);
+    if (code & 0x8000) {
+      SKIP_BITS (br, 2);
+      GST_TRACE ("tcoeff first inter special");
+    } else {
+      /* Fallthrough. Let the first coeff be handled like other coeffs since
+       * the vlc is the same as long as the first bit is not set. */
+    }
+  } else {
+    /* Intra, first coeff is fixed 8-bit */
+    GST_TRACE ("tcoeff first intra special");
+    SKIP_BITS (br, 8);
+  }
+
+  /* Block must end with EOB. */
+  eob = FALSE;
+  while (!eob) {
+    PEEK_BITS (br, &code, 16);
+    for (i = 0; i < TCOEFF_LEN; i++) {
+      if ((code & tcoeff_table[i][1]) == tcoeff_table[i][0]) {
+        GST_TRACE ("tcoeff vlc[%d], run=%d, level=%d", i, tcoeff_table[i][3],
+            tcoeff_table[i][4]);
+        SKIP_BITS (br, tcoeff_table[i][2]);
+        if (tcoeff_table[i][3] == TCOEFF_EOB) {
+          eob = TRUE;
+        } else if (tcoeff_table[i][3] == TCOEFF_ESC) {
+#if 0
+          guint16 val;
+          val = gst_bit_reader_peek_bits_uint16_unchecked (br, 6 + 8);
+          GST_TRACE ("esc run=%d, level=%d", val >> 8, (gint8) (val & 0xff));
+#endif
+          SKIP_BITS (br, 6 + 8);
+        }
+        break;
+      }
+    }
+    if (i == TCOEFF_LEN)
+      /* No matching VLC */
+      return PARSE_ERROR;
+  }
+
+  return PARSE_OK;
+}
+
+static gint
+find_picture_header_offset (const guint8 * data, gsize size)
+{
+  gint i;
+  guint32 val;
+
+  if (size < 4)
+    return -1;
+
+  val = GST_READ_UINT32_BE (data);
+  for (i = 0; i < 8; i++) {
+    if ((val >> (12 - i)) == 0x10)
+      return i;
+  }
+
+  return -1;
+}
+
+static ParseReturn
+parse_picture_header (GstRtpH261Pay * pay, GstBitReader * br, gint * num_gob)
+{
+  guint32 val;
+
+  GET_BITS (br, &val, PSC_LEN);
+  if (val != 0x10)
+    return PARSE_ERROR;
+  SKIP_BITS (br, TR_LEN);
+  GET_BITS (br, &val, PTYPE_LEN);
+  *num_gob = (val & 0x04) == 0 ? 3 : 12;
+
+  return PARSE_OK;
+}
+
+static ParseReturn
+parse_gob_header (GstRtpH261Pay * pay, GstBitReader * br, Gob * gob)
+{
+  guint32 val;
+
+  GET_BITS (br, &val, GBSC_LEN);
+  if (val != 0x01)
+    return PARSE_ERROR;
+  GET_BITS (br, &gob->gn, GN_LEN);
+  GST_TRACE_OBJECT (pay, "Parsing GOB %d", gob->gn);
+
+  GET_BITS (br, &gob->gquant, GQUANT_LEN);
+  GST_TRACE_OBJECT (pay, "GQUANT %d", gob->gquant);
+  GET_BITS (br, &val, GEI_LEN);
+  while (val != 0) {
+    SKIP_BITS (br, GSPARE_LEN);
+    GET_BITS (br, &val, GEI_LEN);
+  }
+
+  return PARSE_OK;
+}
+
+static ParseReturn
+parse_mb (GstRtpH261Pay * pay, GstBitReader * br, const Macroblock * prev,
+    Macroblock * mb)
+{
+  gint mba_diff;
+  guint cbp;
+  ParseReturn ret;
+
+  cbp = 0x3f;
+  mb->quant = prev->quant;
+
+  if ((ret = decode_mba (br, &mba_diff)) != PARSE_OK)
+    return ret;
+  mb->mba = prev->mba == 0 ? mba_diff : prev->mba + mba_diff;
+  GST_TRACE_OBJECT (pay, "Parse MBA %d (mba_diff %d)", mb->mba, mba_diff);
+
+  if ((ret = decode_mtype (br, &mb->mtype)) != PARSE_OK)
+    return ret;
+  GST_TRACE_OBJECT (pay,
+      "MTYPE: inter %d, mc %d, fil %d, mquant %d, mvd %d, cbp %d, tcoeff %d",
+      (mb->mtype & MTYPE_INTER) != 0, (mb->mtype & MTYPE_MC) != 0,
+      (mb->mtype & MTYPE_FIL) != 0, (mb->mtype & MTYPE_MQUANT) != 0,
+      (mb->mtype & MTYPE_MVD) != 0, (mb->mtype & MTYPE_CBP) != 0,
+      (mb->mtype & MTYPE_TCOEFF) != 0);
+
+  if (mb->mtype & MTYPE_MQUANT) {
+    GET_BITS (br, &mb->quant, MQUANT_LEN);
+    GST_TRACE_OBJECT (pay, "MQUANT: %d", mb->quant);
+  }
+
+  if (mb->mtype & MTYPE_MVD) {
+    gint i, pmv[2], mv[2];
+
+    if (mb->mba == 1 || mb->mba == 12 || mb->mba == 23 || mba_diff != 1 ||
+        (prev->mtype & MTYPE_INTER) == 0) {
+      pmv[0] = 0;
+      pmv[1] = 0;
+    } else {
+      pmv[0] = prev->mvx;
+      pmv[1] = prev->mvy;
+    }
+    for (i = 0; i < 2; i++) {
+      gint mvd1, mvd2;
+      if ((ret = decode_mvd (br, &mvd1, &mvd2)) != PARSE_OK)
+        return ret;
+      if (ABS (pmv[i] + mvd1) <= 15)
+        mv[i] = pmv[i] + mvd1;
+      else
+        mv[i] = pmv[i] + mvd2;
+    }
+    mb->mvx = mv[0];
+    mb->mvy = mv[1];
+  } else {
+    mb->mvx = 0;
+    mb->mvy = 0;
+  }
+
+  if (mb->mtype & MTYPE_CBP) {
+    if ((ret = decode_cbp (br, &cbp)) != PARSE_OK)
+      return ret;
+  }
+
+  /* Block layer */
+  if (mb->mtype & MTYPE_TCOEFF) {
+    gint block;
+    for (block = 0; block < 6; block++) {
+      if (cbp & (1 << (5 - block))) {
+        GST_TRACE_OBJECT (pay, "Decode TCOEFF for block %d", block);
+        if ((ret = decode_tcoeff (br, mb->mtype)) != PARSE_OK)
+          return ret;
+      }
+    }
+  }
+
+  mb->endpos = gst_bit_reader_get_pos (br);
+
+  return ret;
+}
+
+/* Parse macroblocks until the next MB that exceeds maxpos. At least one MB is
+ * included even if it exceeds maxpos. Returns endpos of last included MB. */
+static ParseReturn
+parse_mb_until_pos (GstRtpH261Pay * pay, GstBitReader * br, Gob * gob,
+    guint * endpos)
+{
+  ParseReturn ret;
+  gint count = 0;
+  gboolean stop = FALSE;
+  guint maxpos = *endpos;
+  Macroblock mb;
+
+  GST_LOG_OBJECT (pay, "Parse until pos %u, start at pos %u, gobn %d, mba %d",
+      maxpos, gst_bit_reader_get_pos (br), gob->gn, gob->last.mba);
+
+  while (!stop) {
+    ret = parse_mb (pay, br, &gob->last, &mb);
+
+    switch (ret) {
+      case PARSE_OK:
+        if (mb.endpos > maxpos && count > 0) {
+          /* Don't include current MB */
+          stop = TRUE;
+        } else {
+          /* Update to include current MB */
+          *endpos = mb.endpos;
+          gob->last = mb;
+          count++;
+        }
+        break;
+
+      case PARSE_END_OF_FRAME:
+        *endpos = gst_bit_reader_get_pos (br);
+        GST_DEBUG_OBJECT (pay, "End of frame at pos %u (last GOBN %d MBA %d)",
+            *endpos, gob->gn, gob->last.mba);
+        stop = TRUE;
+        break;
+
+      case PARSE_END_OF_GOB:
+        /* Note that a GOB can contain nothing, so we may get here on the first
+         * iteration. */
+        *endpos = gob->last.mba == 0 ?
+            gob->startpos : gst_bit_reader_get_pos (br);
+        GST_DEBUG_OBJECT (pay, "End of gob at pos %u (last GOBN %d MBA %d)",
+            *endpos, gob->gn, gob->last.mba);
+        stop = TRUE;
+        break;
+
+      case PARSE_END_OF_BUFFER:
+      case PARSE_ERROR:
+        GST_WARNING_OBJECT (pay, "Failed to parse stream (reason %d)", ret);
+        return ret;
+        break;
+
+      default:
+        g_assert_not_reached ();
+        break;
+    }
+  }
+  gob->last.gobn = gob->gn;
+
+  if (ret == PARSE_OK) {
+    GST_DEBUG_OBJECT (pay,
+        "Split GOBN %d after MBA %d (endpos %u, maxpos %u, nextpos %u)",
+        gob->gn, gob->last.mba, *endpos, maxpos, mb.endpos);
+    gst_bit_reader_set_pos (br, *endpos);
+  }
+
+  return ret;
+}
+
+static guint
+bitrange_to_bytes (guint first, guint last)
+{
+  return (GST_ROUND_UP_8 (last) - GST_ROUND_DOWN_8 (first)) / 8;
+}
+
+/* Find next 16-bit GOB start code (0x0001), which may not be byte aligned.
+ * Returns the bit offset of the first bit of GBSC. */
+static gssize
+find_gob (GstRtpH261Pay * pay, const guint8 * data, guint size, guint pos)
+{
+  gssize ret = -1;
+  guint offset;
+
+  GST_LOG_OBJECT (pay, "Search for GOB from pos %u", pos);
+
+  for (offset = pos / 8; offset < size - 1; offset++) {
+    if (data[offset] == 0x0) {
+      gint msb = g_bit_nth_msf (data[offset + 1], 8);
+      gint lsb = offset > 0 ? g_bit_nth_lsf (data[offset - 1], -1) : 0;
+      if (lsb == -1)
+        lsb = 8;
+      if (msb >= 0 && lsb >= msb) {
+        ret = offset * 8 - msb;
+        GST_LOG_OBJECT (pay, "Found GOB start code at bitpos %"
+            G_GSSIZE_FORMAT " (%02x %02x %02x)", ret,
+            offset > 0 ? data[offset - 1] : 0, data[offset], data[offset + 1]);
+        break;
+      }
+    }
+  }
+
+  return ret;
+}
+
+/* Scans after all GOB start codes and initalizes the GOB structure with start
+ * and end positions. */
+static ParseReturn
+gst_rtp_h261_pay_init_gobs (GstRtpH261Pay * pay, Gob * gobs, gint num_gobs,
+    const guint8 * bits, gint len, guint pos)
+{
+  gint i;
+
+  for (i = 0; i < num_gobs; i++) {
+    gssize gobpos = find_gob (pay, bits, len, pos);
+    if (gobpos == -1) {
+      GST_WARNING_OBJECT (pay, "Found only %d of %d GOBs", i, num_gobs);
+      return PARSE_ERROR;
+    }
+    GST_LOG_OBJECT (pay, "Found GOB %d at pos %" G_GSSIZE_FORMAT, i, gobpos);
+    pos = gobpos + GBSC_LEN;
+
+    gobs[i].startpos = gobpos;
+    if (i > 0)
+      gobs[i - 1].endpos = gobpos;
+  }
+  gobs[num_gobs - 1].endpos = len * 8;
+
+  return PARSE_OK;
+}
+
+static GstFlowReturn
+gst_rtp_h261_pay_fragment_push (GstRtpH261Pay * pay, GstBuffer * buffer,
+    const guint8 * bits, guint start, guint end,
+    const Macroblock * last_mb_in_previous_packet, gboolean marker)
+{
+  GstBuffer *outbuf;
+  guint8 *payload;
+  GstRtpH261PayHeader *header;
+  gint nbytes;
+  const Macroblock *last = last_mb_in_previous_packet;
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+
+  nbytes = bitrange_to_bytes (start, end);
+
+  outbuf = gst_rtp_buffer_new_allocate (nbytes +
+      GST_RTP_H261_PAYLOAD_HEADER_LEN, 0, 0);
+  gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+  payload = gst_rtp_buffer_get_payload (&rtp);
+  header = (GstRtpH261PayHeader *) payload;
+
+  memset (header, 0, GST_RTP_H261_PAYLOAD_HEADER_LEN);
+  header->v = 1;
+  header->sbit = start & 7;
+  header->ebit = (8 - (end & 7)) & 7;
+
+  if (last != NULL && last->mba != 0 && last->mba != 33) {
+    /* NOTE: MVD assumes that we're running on 2's complement architecture */
+    guint mbap = last->mba - 1;
+    header->gobn = last->gobn;
+    header->mbap1 = mbap >> 1;
+    header->mbap2 = mbap & 1;
+    header->quant = last->quant;
+    header->hmvd1 = last->mvx >> 3;
+    header->hmvd2 = last->mvx & 7;
+    header->vmvd = last->mvy;
+  }
+
+  memcpy (payload + GST_RTP_H261_PAYLOAD_HEADER_LEN,
+      bits + GST_ROUND_DOWN_8 (start) / 8, nbytes);
+
+  GST_BUFFER_TIMESTAMP (outbuf) = pay->timestamp;
+  gst_rtp_buffer_set_marker (&rtp, marker);
+  pay->offset = end & 7;
+
+  GST_DEBUG_OBJECT (pay,
+      "Push fragment, bytes %d, sbit %d, ebit %d, gobn %d, mbap %d, marker %d",
+      nbytes, header->sbit, header->ebit, last != NULL ? last->gobn : 0,
+      last != NULL ? MAX (last->mba - 1, 0) : 0, marker);
+
+  gst_rtp_buffer_unmap (&rtp);
+
+  gst_rtp_copy_video_meta (pay, outbuf, buffer);
+
+  return gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD_CAST (pay), outbuf);
+}
+
+static GstFlowReturn
+gst_rtp_h261_packetize_and_push (GstRtpH261Pay * pay, GstBuffer * buffer,
+    const guint8 * bits, gsize len)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBitReader br_;
+  GstBitReader *br = &br_;
+  guint max_payload_size =
+      gst_rtp_buffer_calc_payload_len (GST_RTP_BASE_PAYLOAD_MTU (pay) -
+      GST_RTP_H261_PAYLOAD_HEADER_LEN, 0, 0);
+  guint startpos;
+  gint num_gobs = 0;
+  Gob gobs[MAX_NUM_GOB];
+  Gob *gob;
+  Macroblock last_mb_in_previous_packet = { 0 };
+  gboolean marker;
+  ParseReturn result;
+
+  gst_bit_reader_init (br, bits, len);
+  gst_bit_reader_set_pos (br, pay->offset);
+  startpos = pay->offset;
+
+  if (parse_picture_header (pay, br, &num_gobs) < PARSE_OK) {
+    GST_WARNING_OBJECT (pay, "Failed to parse picture header");
+    goto beach;
+  }
+
+  if (gst_rtp_h261_pay_init_gobs (pay, gobs, num_gobs, bits, len,
+          gst_bit_reader_get_pos (br)) < PARSE_OK)
+    goto beach;
+
+  /* Split, create and push packets */
+  gob = gobs;
+  marker = FALSE;
+  while (marker == FALSE && ret == GST_FLOW_OK) {
+    guint endpos;
+
+    /* Check if there is wrap around because of extremely high MTU */
+    endpos = GST_ROUND_DOWN_8 (startpos) + max_payload_size * 8;
+    if (endpos < startpos)
+      endpos = G_MAXUINT;
+
+    GST_LOG_OBJECT (pay, "Next packet startpos %u maxpos %u", startpos, endpos);
+
+    /* Find the last GOB that does not completely fit in packet */
+    for (; gob < &gobs[num_gobs - 1]; gob++) {
+      if (bitrange_to_bytes (startpos, gob->endpos) > max_payload_size) {
+        GST_LOG_OBJECT (pay, "Split gob (start %u, end %u)",
+            gob->startpos, gob->endpos);
+        break;
+      }
+    }
+
+    if (startpos <= gob->startpos) {
+      /* Fast-forward until start of GOB */
+      gst_bit_reader_set_pos (br, gob->startpos);
+      if (parse_gob_header (pay, br, gob) < PARSE_OK) {
+        GST_WARNING_OBJECT (pay, "Failed to parse GOB header");
+        goto beach;
+      }
+      gob->last.mba = 0;
+      gob->last.gobn = gob->gn;
+      gob->last.quant = gob->gquant;
+    }
+
+    /* Parse MBs to find position where to split. Can only be done on after MB
+     * or at GOB boundary. */
+    result = parse_mb_until_pos (pay, br, gob, &endpos);
+    if (result < PARSE_OK)
+      goto beach;
+
+    marker = result == PARSE_END_OF_FRAME;
+    ret = gst_rtp_h261_pay_fragment_push (pay, buffer, bits, startpos, endpos,
+        &last_mb_in_previous_packet, marker);
+
+    last_mb_in_previous_packet = gob->last;
+    if (endpos == gob->endpos)
+      gob++;
+    startpos = endpos;
+  }
+
+beach:
+  return ret;
+}
+
+/* Shift buffer to packetize a continuous stream of bits (not bytes). Some
+ * payloaders/decoders are very picky about correct sbit/ebit for frames. */
+static guint8 *
+gst_rtp_h261_pay_shift_buffer (GstRtpH261Pay * pay, const guint8 * data,
+    gsize size, gint offset, gsize * newsize)
+{
+  /* In order to read variable length codes at the very end of the buffer
+   * wihout peeking into possibly unallocated data, we pad with extra 0's
+   * which will generate an invalid code at the end of the buffer. */
+  guint pad = 4;
+  gsize allocsize = size + pad;
+  guint8 *bits = g_malloc (allocsize);
+  gint i;
+
+  if (offset == 0) {
+    memcpy (bits, data, size);
+    *newsize = size;
+  } else if (offset > 0) {
+    bits[0] = 0;
+    for (i = 0; i < size; i++) {
+      bits[i] |= data[i] >> offset;
+      bits[i + 1] = data[i] << (8 - offset);
+    }
+    *newsize = size + 1;
+  } else {
+    gint shift = -offset;
+    for (i = 0; i < size - 1; i++)
+      bits[i] = (data[i] << shift) | (data[i + 1] >> (8 - shift));
+    bits[i] = data[i] << shift;
+    *newsize = size;
+  }
+  for (i = *newsize; i < allocsize; i++)
+    bits[i] = 0;
+
+  return bits;
+}
+
+static GstFlowReturn
+gst_rtp_h261_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstRtpH261Pay *pay = GST_RTP_H261_PAY (payload);
+  gsize len;
+  guint8 *bits;
+  gint psc_offset, shift;
+  GstMapInfo map;
+
+  GST_DEBUG_OBJECT (pay, "Handle buffer of size %" G_GSIZE_FORMAT,
+      gst_buffer_get_size (buffer));
+
+  pay->timestamp = GST_BUFFER_TIMESTAMP (buffer);
+
+  if (!gst_buffer_map (buffer, &map, GST_MAP_READ) || !map.data) {
+    GST_WARNING_OBJECT (pay, "Failed to map buffer");
+    return GST_FLOW_ERROR;
+  }
+
+  psc_offset = find_picture_header_offset (map.data, map.size);
+  if (psc_offset < 0) {
+    GST_WARNING_OBJECT (pay, "Failed to find picture header offset");
+    goto beach;
+  } else {
+    GST_DEBUG_OBJECT (pay, "Picture header offset: %d", psc_offset);
+  }
+
+  shift = pay->offset - psc_offset;
+  bits = gst_rtp_h261_pay_shift_buffer (pay, map.data, map.size, shift, &len);
+  ret = gst_rtp_h261_packetize_and_push (pay, buffer, bits, len);
+  g_free (bits);
+
+beach:
+  gst_buffer_unmap (buffer, &map);
+  gst_buffer_unref (buffer);
+  return ret;
+}
+
+
+static gboolean
+gst_rtp_h261_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  gboolean res;
+
+  gst_rtp_base_payload_set_options (payload, "video",
+      payload->pt != GST_RTP_PAYLOAD_H261, "H261", 90000);
+  res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+  return res;
+}
+
+static void
+gst_rtp_h261_pay_init (GstRtpH261Pay * pay)
+{
+  GstRTPBasePayload *payload = GST_RTP_BASE_PAYLOAD (pay);
+  payload->pt = GST_RTP_PAYLOAD_H261;
+  pay->offset = 0;
+}
+
+static void
+gst_rtp_h261_pay_class_init (GstRtpH261PayClass * klass)
+{
+  GstElementClass *element_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  element_class = GST_ELEMENT_CLASS (klass);
+  gstrtpbasepayload_class = GST_RTP_BASE_PAYLOAD_CLASS (klass);
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_h261_pay_src_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_h261_pay_sink_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "RTP H261 packet payloader", "Codec/Payloader/Network/RTP",
+      "Payload-encodes H261 video in RTP packets (RFC 4587)",
+      "Stian Selnes <stian@pexip.com>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_h261_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_h261_pay_handle_buffer;
+
+  GST_DEBUG_CATEGORY_INIT (rtph261pay_debug, "rtph261pay", 0,
+      "H261 RTP Payloader");
+}
+
+gboolean
+gst_rtp_h261_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtph261pay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_H261_PAY);
+}
diff --git a/gst/rtp/gstrtph261pay.h b/gst/rtp/gstrtph261pay.h
new file mode 100644
index 0000000..eae4bf2
--- /dev/null
+++ b/gst/rtp/gstrtph261pay.h
@@ -0,0 +1,100 @@
+/* GStreamer
+ * Copyright (C) <2014> Stian Selnes <stian@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Dejan Sakelsak sahel@kiberpipa.org
+ */
+
+#ifndef __GST_RTP_H261_PAY_H__
+#define __GST_RTP_H261_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_H261_PAY                   \
+  (gst_rtp_h261_pay_get_type())
+#define GST_RTP_H261_PAY(obj)                                           \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H261_PAY,GstRtpH261Pay))
+#define GST_RTP_H261_PAY_CLASS(klass)                                   \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H261_PAY,GstRtpH261PayClass))
+#define GST_IS_RTP_H261_PAY(obj)                            \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H261_PAY))
+#define GST_IS_RTP_H261_PAY_CLASS(klass)                    \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H261_PAY))
+typedef struct _GstRtpH261PayClass GstRtpH261PayClass;
+typedef struct _GstRtpH261Pay GstRtpH261Pay;
+
+struct _GstRtpH261Pay
+{
+  GstRTPBasePayload payload;
+
+  GstAdapter *adapter;
+  gint offset;
+  GstClockTime timestamp;
+};
+
+struct _GstRtpH261PayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+typedef struct _GstRtpH261PayHeader
+{
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+  unsigned int v:1;             /* Motion vector flag */
+  unsigned int i:1;             /* Intra encoded data */
+  unsigned int ebit:3;          /* End position */
+  unsigned int sbit:3;          /* Start position */
+
+  unsigned int mbap1:4;         /* MB address predictor - part1 */
+  unsigned int gobn:4;          /* GOB number */
+
+  unsigned int hmvd1:2;         /* Horizontal motion vector data - part1 */
+  unsigned int quant:5;         /* Quantizer */
+  unsigned int mbap2:1;         /* MB address predictor - part2 */
+
+  unsigned int vmvd:5;          /* Horizontal motion vector data - part1 */
+  unsigned int hmvd2:3;         /* Vertical motion vector data */
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+  unsigned int sbit:3;          /* Start position */
+  unsigned int ebit:3;          /* End position */
+  unsigned int i:1;             /* Intra encoded data */
+  unsigned int v:1;             /* Motion vector flag */
+
+  unsigned int gobn:4;          /* GOB number */
+  unsigned int mbap1:4;         /* MB address predictor - part1 */
+
+  unsigned int mbap2:1;         /* MB address predictor - part2 */
+  unsigned int quant:5;         /* Quantizer */
+  unsigned int hmvd1:2;         /* Horizontal motion vector data - part1 */
+
+  unsigned int hmvd2:3;         /* Vertical motion vector data */
+  unsigned int vmvd:5;          /* Horizontal motion vector data - part1 */
+#else
+#error "G_BYTE_ORDER should be big or little endian."
+#endif
+} GstRtpH261PayHeader;
+#define GST_RTP_H261_PAYLOAD_HEADER_LEN 4
+
+GType gst_rtp_h261_pay_get_type (void);
+
+gboolean gst_rtp_h261_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_H261_PAY_H__ */
diff --git a/gst/rtp/gstrtph263depay.c b/gst/rtp/gstrtph263depay.c
new file mode 100644
index 0000000..296f917
--- /dev/null
+++ b/gst/rtp/gstrtph263depay.c
@@ -0,0 +1,447 @@
+/* GStreamer
+ *
+ * Copyright 2007 Nokia Corporation
+ * Copyright 2007 Collabora Ltd,
+ *  @author: Philippe Kalaf <philippe.kalaf@collabora.co.uk>
+ *
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *               <2007> Edward Hervey <bilboed@bilboed.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+#include "gstrtph263depay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtph263depay_debug);
+#define GST_CAT_DEFAULT (rtph263depay_debug)
+
+#define GST_RFC2190A_HEADER_LEN 4
+#define GST_RFC2190B_HEADER_LEN 8
+#define GST_RFC2190C_HEADER_LEN 12
+
+static GstStaticPadTemplate gst_rtp_h263_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-h263, "
+        "variant = (string) \"itu\", " "h263version = (string) \"h263\"")
+    );
+
+static GstStaticPadTemplate gst_rtp_h263_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_H263_STRING ", "
+        "clock-rate = (int) 90000; "
+        /* optional SDP attribute:
+         * "a-framesize = (string) \"1234-1234\", "
+         */
+        "application/x-rtp, "
+        "media = (string) \"video\", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"H263\""
+        /* optional SDP attribute:
+         * "a-framesize = (string) \"1234-1234\", "
+         */
+    )
+    );
+
+#define gst_rtp_h263_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpH263Depay, gst_rtp_h263_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_h263_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_h263_depay_change_state (GstElement *
+    element, GstStateChange transition);
+
+static GstBuffer *gst_rtp_h263_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+gboolean gst_rtp_h263_depay_setcaps (GstRTPBaseDepayload * filter,
+    GstCaps * caps);
+
+static void
+gst_rtp_h263_depay_class_init (GstRtpH263DepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtph263depay_debug, "rtph263depay", 0,
+      "H263 Video RTP Depayloader");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_h263_depay_finalize;
+
+  gstelement_class->change_state = gst_rtp_h263_depay_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h263_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h263_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP H263 depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts H263 video from RTP packets (RFC 2190)",
+      "Philippe Kalaf <philippe.kalaf@collabora.co.uk>, "
+      "Edward Hervey <bilboed@bilboed.com>");
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_h263_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_h263_depay_setcaps;
+}
+
+static void
+gst_rtp_h263_depay_init (GstRtpH263Depay * rtph263depay)
+{
+  rtph263depay->adapter = gst_adapter_new ();
+
+  rtph263depay->offset = 0;
+  rtph263depay->leftover = 0;
+}
+
+static void
+gst_rtp_h263_depay_finalize (GObject * object)
+{
+  GstRtpH263Depay *rtph263depay;
+
+  rtph263depay = GST_RTP_H263_DEPAY (object);
+
+  g_object_unref (rtph263depay->adapter);
+  rtph263depay->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_h263_parse_framesize (GstRTPBaseDepayload * filter,
+    const gchar * media_attr, GstCaps * srccaps)
+{
+  gchar *dimension, *endptr;
+  gint width, height;
+  GstStructure *d;
+
+  width = g_ascii_strtoull (media_attr, &endptr, 10);
+  if (width <= 0) {
+    GST_ERROR_OBJECT (filter,
+        "Framesize media attribute width out of valid range");
+    return FALSE;
+  } else if (*endptr != '-') {
+    GST_ERROR_OBJECT (filter,
+        "Framesize media attribute has invalid dimension separator");
+    return FALSE;
+  }
+
+  dimension = endptr + 1;
+  height = g_ascii_strtoull (dimension, &endptr, 10);
+  if (height <= 0) {
+    GST_ERROR_OBJECT (filter,
+        "Framesize media attribute height out of valid range");
+    return FALSE;
+  } else if (*endptr != '\0') {
+    GST_ERROR_OBJECT (filter,
+        "Framesize media attribute unexpectedly has trailing characters");
+    return FALSE;
+  }
+
+  d = gst_caps_get_structure (srccaps, 0);
+  gst_structure_set (d, "width", G_TYPE_INT, width, "height", G_TYPE_INT,
+      height, NULL);
+
+  return TRUE;
+}
+
+gboolean
+gst_rtp_h263_depay_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps)
+{
+  GstCaps *srccaps;
+  GstStructure *structure = gst_caps_get_structure (caps, 0);
+  gint clock_rate;
+  const gchar *framesize;
+
+  srccaps = gst_caps_new_simple ("video/x-h263",
+      "variant", G_TYPE_STRING, "itu",
+      "h263version", G_TYPE_STRING, "h263", NULL);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;         /* default */
+  filter->clock_rate = clock_rate;
+
+  framesize = gst_structure_get_string (structure, "a-framesize");
+  if (framesize != NULL) {
+    if (!gst_rtp_h263_parse_framesize (filter, framesize, srccaps)) {
+      return FALSE;
+    }
+  }
+
+  gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (filter), srccaps);
+  gst_caps_unref (srccaps);
+
+  return TRUE;
+}
+
+static GstBuffer *
+gst_rtp_h263_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpH263Depay *rtph263depay;
+  GstBuffer *outbuf;
+  gint payload_len;
+  guint8 *payload;
+  guint header_len;
+  guint SBIT, EBIT;
+  gboolean F, P, M;
+  gboolean I;
+
+  rtph263depay = GST_RTP_H263_DEPAY (depayload);
+
+  /* flush remaining data on discont */
+  if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
+    GST_LOG_OBJECT (depayload, "Discont buffer, flushing adapter");
+    gst_adapter_clear (rtph263depay->adapter);
+    rtph263depay->offset = 0;
+    rtph263depay->leftover = 0;
+    rtph263depay->start = FALSE;
+  }
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+  payload = gst_rtp_buffer_get_payload (rtp);
+
+  M = gst_rtp_buffer_get_marker (rtp);
+
+  if (payload_len < 1)
+    goto too_small;
+
+  /* Let's see what mode we are using */
+  F = (payload[0] & 0x80) == 0x80;
+  P = (payload[0] & 0x40) == 0x40;
+
+  /* Bit shifting */
+  SBIT = (payload[0] & 0x38) >> 3;
+  EBIT = (payload[0] & 0x07);
+
+  /* Figure out header length and I-flag */
+  if (F == 0) {
+    /* F == 0 and P == 0 or 1
+     * mode A */
+    header_len = GST_RFC2190A_HEADER_LEN;
+    GST_LOG ("Mode A");
+
+    /* 0                   1                   2                   3
+     * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * |F|P|SBIT |EBIT | SRC |I|U|S|A|R      |DBQ| TRB |    TR         |
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     */
+    if (payload_len <= header_len)
+      goto too_small;
+    I = (payload[1] & 0x10) == 0x10;
+  } else {
+    if (P == 0) {
+      /* F == 1 and P == 0
+       * mode B */
+      header_len = GST_RFC2190B_HEADER_LEN;
+      GST_LOG ("Mode B");
+
+      /* 0                   1                   2                   3
+       * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       * |F|P|SBIT |EBIT | SRC | QUANT   |  GOBN   |   MBA           |R  |
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       * |I|U|S|A| HMV1        | VMV1        | HMV2        | VMV2        |
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       */
+      if (payload_len <= header_len)
+        goto too_small;
+      I = (payload[4] & 0x80) == 0x80;
+    } else {
+      /* F == 1 and P == 1
+       * mode C */
+      header_len = GST_RFC2190C_HEADER_LEN;
+      GST_LOG ("Mode C");
+
+      /* 0                   1                   2                   3
+       * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       * |F|P|SBIT |EBIT | SRC | QUANT   |  GOBN   |   MBA           |R  |
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       * |I|U|S|A| HMV1        | VMV1        | HMV2        | VMV2        |
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       * | RR                                  |DBQ| TRB |    TR         |
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       */
+      if (payload_len <= header_len)
+        goto too_small;
+      I = (payload[4] & 0x80) == 0x80;
+    }
+  }
+
+  GST_LOG ("F/P/M/I : %d/%d/%d/%d", F, P, M, I);
+  GST_LOG ("SBIT : %d , EBIT : %d", SBIT, EBIT);
+  GST_LOG ("payload_len : %d, header_len : %d , leftover : 0x%x",
+      payload_len, header_len, rtph263depay->leftover);
+
+  /* skip header */
+  payload += header_len;
+  payload_len -= header_len;
+
+  if (!rtph263depay->start) {
+    /* only mode A should be used when there is a picture start code, but
+     * buggy payloaders may send mode B/C in start of frame */
+    if (payload_len > 4 && (GST_READ_UINT32_BE (payload) >> 10 == 0x20)) {
+      GST_DEBUG ("Mode %c with PSC => frame start", "ABC"[F + P]);
+      rtph263depay->start = TRUE;
+      if ((! !(payload[4] & 0x02)) != I) {
+        GST_DEBUG ("Wrong Picture Coding Type Flag in rtp header");
+        I = !I;
+      }
+      rtph263depay->psc_I = I;
+    } else {
+      GST_DEBUG ("no frame start yet, skipping payload");
+      goto skip;
+    }
+  }
+
+  /* only trust I info from Mode A starting packet
+   * from buggy payloaders or hw */
+  I = rtph263depay->psc_I;
+
+  if (SBIT) {
+    /* take the leftover and merge it at the beginning, FIXME make the buffer
+     * data writable. */
+    GST_LOG ("payload[0] : 0x%x", payload[0]);
+    payload[0] &= 0xFF >> SBIT;
+    GST_LOG ("payload[0] : 0x%x", payload[0]);
+    payload[0] |= rtph263depay->leftover;
+    GST_LOG ("payload[0] : 0x%x", payload[0]);
+    rtph263depay->leftover = 0;
+    rtph263depay->offset = 0;
+  }
+
+  if (!EBIT) {
+    GstBuffer *tmp;
+
+    /* Take the entire buffer */
+    tmp = gst_rtp_buffer_get_payload_subbuffer (rtp, header_len, payload_len);
+    gst_adapter_push (rtph263depay->adapter, tmp);
+  } else {
+    GstBuffer *tmp;
+
+    /* Take the entire buffer except for the last byte */
+    tmp = gst_rtp_buffer_get_payload_subbuffer (rtp, header_len,
+        payload_len - 1);
+    gst_adapter_push (rtph263depay->adapter, tmp);
+
+    /* Put the last byte into the leftover */
+    GST_DEBUG ("payload[payload_len - 1] : 0x%x", payload[payload_len - 1]);
+    GST_DEBUG ("mask : 0x%x", 0xFF << EBIT);
+    rtph263depay->leftover = (payload[payload_len - 1] >> EBIT) << EBIT;
+    rtph263depay->offset = 1;
+    GST_DEBUG ("leftover : 0x%x", rtph263depay->leftover);
+  }
+
+skip:
+  if (M) {
+    if (rtph263depay->start) {
+      /* frame is completed */
+      guint avail;
+
+      if (rtph263depay->offset) {
+        /* push in the leftover */
+        GstBuffer *buf = gst_buffer_new_and_alloc (1);
+
+        GST_DEBUG ("Pushing leftover in adapter");
+        gst_buffer_fill (buf, 0, &rtph263depay->leftover, 1);
+        gst_adapter_push (rtph263depay->adapter, buf);
+      }
+
+      avail = gst_adapter_available (rtph263depay->adapter);
+      outbuf = gst_adapter_take_buffer (rtph263depay->adapter, avail);
+
+      if (I)
+        GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+      GST_DEBUG ("Pushing out a buffer of %d bytes", avail);
+
+      gst_rtp_drop_non_video_meta (rtph263depay, outbuf);
+
+      gst_rtp_base_depayload_push (depayload, outbuf);
+      rtph263depay->offset = 0;
+      rtph263depay->leftover = 0;
+      rtph263depay->start = FALSE;
+    } else {
+      rtph263depay->start = TRUE;
+    }
+  }
+
+  return NULL;
+
+too_small:
+  {
+    GST_ELEMENT_WARNING (rtph263depay, STREAM, DECODE,
+        ("Packet payload was too small"), (NULL));
+    return NULL;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_h263_depay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpH263Depay *rtph263depay;
+  GstStateChangeReturn ret;
+
+  rtph263depay = GST_RTP_H263_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_adapter_clear (rtph263depay->adapter);
+      rtph263depay->start = TRUE;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_h263_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtph263depay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_H263_DEPAY);
+}
diff --git a/gst/rtp/gstrtph263depay.h b/gst/rtp/gstrtph263depay.h
new file mode 100644
index 0000000..2d9ca55
--- /dev/null
+++ b/gst/rtp/gstrtph263depay.h
@@ -0,0 +1,66 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_H263_DEPAY_H__
+#define __GST_RTP_H263_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_H263_DEPAY \
+  (gst_rtp_h263_depay_get_type())
+#define GST_RTP_H263_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H263_DEPAY,GstRtpH263Depay))
+#define GST_RTP_H263_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H263_DEPAY,GstRtpH263DepayClass))
+#define GST_IS_RTP_H263_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H263_DEPAY))
+#define GST_IS_RTP_H263_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H263_DEPAY))
+
+typedef struct _GstRtpH263Depay GstRtpH263Depay;
+typedef struct _GstRtpH263DepayClass GstRtpH263DepayClass;
+
+struct _GstRtpH263Depay
+{
+  GstRTPBaseDepayload depayload;
+
+  guint8 offset;	/* offset to apply to next payload */
+  guint8 leftover;	/* leftover from previous payload (if offset != 0) */
+  gboolean psc_I;       /* Picture-Coding-Type == I from Picture Start Code packet */
+  GstAdapter *adapter;
+  gboolean start;
+};
+
+struct _GstRtpH263DepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_h263_depay_get_type (void);
+
+gboolean gst_rtp_h263_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_H263_DEPAY_H__ */
+
diff --git a/gst/rtp/gstrtph263pay.c b/gst/rtp/gstrtph263pay.c
new file mode 100644
index 0000000..4163bcd
--- /dev/null
+++ b/gst/rtp/gstrtph263pay.c
@@ -0,0 +1,1869 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) <2008> Dejan Sakelsak <dejan.sakelsak@marand.si>
+ * Copyright (C) <2009> Janin Kolenc  <janin.kolenc@marand.si>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+
+#include "gstrtph263pay.h"
+#include "gstrtputils.h"
+
+typedef enum
+{
+  GST_H263_FRAME_TYPE_I = 0,
+  GST_H263_FRAME_TYPE_P = 1,
+  GST_H263_FRAME_TYPE_PB = 2
+} GstRtpH263PayFrameType;
+
+typedef enum
+{
+  GST_RTP_H263_PAYLOAD_PICTURE_FORMAT_RES1 = 0,
+  GST_RTP_H263_PAYLOAD_PICTURE_FORMAT_SQCIF = 1,
+  GST_RTP_H263_PAYLOAD_PICTURE_FORMAT_QCIF = 2,
+  GST_RTP_H263_PAYLOAD_PICTURE_FORMAT_CIF = 3,
+  GST_RTP_H263_PAYLOAD_PICTURE_FORMAT_4CIF = 4,
+  GST_RTP_H263_PAYLOAD_PICTURE_FORMAT_16CIF = 5,
+  GST_RTP_H263_PAYLOAD_PICTURE_FORMAT_RES2 = 6,
+  GST_H263_PAYLOAD_PICTURE_FORMAT_PLUS = 7
+} GstRtpH263PayPictureFormat;
+
+static const guint format_props[8][2] = { {254, 254},
+{6, 8},
+{9, 11},
+{18, 22},
+{18, 88},
+{18, 352},
+{254, 254},
+{255, 255}
+};
+
+/*
+ * I-frame MCBPC table: code, mask, nbits, cb, cr, mb type -> 10 = undefined (because we have guint)
+ */
+#define MCBPC_I_LEN 9
+#define MCBPC_I_WID 6
+static const guint32 mcbpc_I[9][6] = {
+  {0x8000, 0x8000, 1, 0, 0, 3},
+  {0x2000, 0xe000, 3, 0, 1, 3},
+  {0x4000, 0xe000, 3, 1, 0, 3},
+  {0x6000, 0xe000, 3, 1, 1, 3},
+  {0x1000, 0xf000, 4, 0, 0, 4},
+  {0x0400, 0xfc00, 6, 0, 1, 4},
+  {0x0800, 0xfc00, 6, 1, 0, 4},
+  {0x0c00, 0xfc00, 6, 1, 1, 4},
+  {0x0080, 0xff80, 9, 10, 10, 10}
+};
+
+/*
+ * P-frame MCBPC table: code, mask, nbits, cb, cr, mb type -> 10 = undefined (because we have guint)
+ */
+#define MCBPC_P_LEN 21
+#define MCBPC_P_WID 6
+static const guint16 mcbpc_P[21][6] = {
+  {0x8000, 0x8000, 1, 0, 0, 0},
+  {0x3000, 0xf000, 4, 0, 1, 0},
+  {0x2000, 0xf000, 4, 1, 0, 0},
+  {0x1400, 0xfc00, 6, 1, 1, 0},
+  {0x6000, 0xe000, 3, 0, 0, 1},
+  {0x0e00, 0xfe00, 7, 0, 1, 1},
+  {0x0c00, 0xfe00, 7, 1, 0, 1},
+  {0x0280, 0xff80, 9, 1, 1, 1},
+  {0x4000, 0xe000, 3, 0, 0, 2},
+  {0x0a00, 0xfe00, 7, 0, 1, 2},
+  {0x0800, 0xfe00, 7, 1, 0, 2},
+  {0x0500, 0xff00, 8, 1, 1, 2},
+  {0x1800, 0xf800, 5, 0, 0, 3},
+  {0x0400, 0xff00, 8, 0, 1, 3},
+  {0x0300, 0xff00, 8, 1, 0, 3},
+  {0x0600, 0xfe00, 7, 1, 1, 3},
+  {0x1000, 0xfc00, 6, 0, 0, 4},
+  {0x0200, 0xff80, 9, 0, 1, 4},
+  {0x0180, 0xff80, 9, 1, 0, 4},
+  {0x0100, 0xff80, 9, 1, 1, 4},
+  {0x0080, 0xff80, 9, 10, 10, 10}
+};
+
+/*
+ * I-frame CBPY (code, mask, nbits, Y0, Y1, Y2, Y3)
+ */
+#define CBPY_LEN 16
+#define CBPY_WID 7
+static const guint8 cbpy_I[16][7] = {
+  {0x30, 0xf0, 4, 0, 0, 0, 0},
+  {0x28, 0xf8, 5, 0, 0, 0, 1},
+  {0x20, 0xf8, 5, 0, 0, 1, 0},
+  {0x90, 0xf0, 4, 0, 0, 1, 1},
+  {0x18, 0xf8, 5, 0, 1, 0, 0},
+  {0x70, 0xf0, 4, 0, 1, 0, 1},
+  {0x08, 0xfc, 6, 0, 1, 1, 0},
+  {0xb0, 0xf0, 4, 0, 1, 1, 1},
+  {0x10, 0xf8, 5, 1, 0, 0, 0},
+  {0x0c, 0xfc, 6, 1, 0, 0, 1},
+  {0x50, 0xf0, 4, 1, 0, 1, 0},
+  {0xa0, 0xf0, 4, 1, 0, 1, 1},
+  {0x40, 0xf0, 4, 1, 1, 0, 0},
+  {0x80, 0xf0, 4, 1, 1, 0, 1},
+  {0x60, 0xf0, 4, 1, 1, 1, 0},
+  {0xc0, 0xc0, 2, 1, 1, 1, 1}
+};
+
+/*
+ * P-frame CBPY (code, mask, nbits, Y0, Y1, Y2, Y3)
+ */
+static const guint8 cbpy_P[16][7] = {
+  {0x30, 0xf0, 4, 1, 1, 1, 1},
+  {0x28, 0xf8, 5, 1, 1, 1, 0},
+  {0x20, 0xf8, 5, 1, 1, 0, 1},
+  {0x90, 0xf0, 4, 1, 1, 0, 0},
+  {0x18, 0xf8, 5, 1, 0, 1, 1},
+  {0x70, 0xf0, 4, 1, 0, 1, 0},
+  {0x08, 0xfc, 6, 1, 0, 0, 1},
+  {0xb0, 0xf0, 4, 1, 0, 0, 0},
+  {0x10, 0xf8, 5, 0, 1, 1, 1},
+  {0x0c, 0xfc, 6, 0, 1, 1, 0},
+  {0x50, 0xf0, 4, 0, 1, 0, 1},
+  {0xa0, 0xf0, 4, 0, 1, 0, 0},
+  {0x40, 0xf0, 4, 0, 0, 1, 1},
+  {0x80, 0xf0, 4, 0, 0, 1, 0},
+  {0x60, 0xf0, 4, 0, 0, 0, 1},
+  {0xc0, 0xc0, 2, 0, 0, 0, 0}
+};
+
+/*
+ * Block TCOEF table (code, mask, nbits, LAST, RUN, LEVEL)
+ */
+#define TCOEF_LEN 103
+#define TCOEF_WID 6
+static const guint16 tcoef[103][6] = {
+  {0x8000, 0xc000, 3, 0, 0, 1},
+  {0xf000, 0xf000, 5, 0, 0, 2},
+  {0x5400, 0xfc00, 7, 0, 0, 3},
+  {0x2e00, 0xfe00, 8, 0, 0, 4},
+  {0x1f00, 0xff00, 9, 0, 0, 5},
+  {0x1280, 0xff80, 10, 0, 0, 6},
+  {0x1200, 0xff80, 10, 0, 0, 7},
+  {0x0840, 0xffc0, 11, 0, 0, 8},
+  {0x0800, 0xffc0, 11, 0, 0, 9},
+  {0x00e0, 0xffe0, 12, 0, 0, 10},       //10
+  {0x00c0, 0xffe0, 12, 0, 0, 11},
+  {0x0400, 0xffe0, 12, 0, 0, 12},
+  {0xc000, 0xe000, 4, 0, 1, 1},
+  {0x5000, 0xfc00, 7, 0, 1, 2},
+  {0x1e00, 0xff00, 9, 0, 1, 3},
+  {0x03c0, 0xffc0, 11, 0, 1, 4},
+  {0x0420, 0xffe0, 12, 0, 1, 5},
+  {0x0500, 0xfff0, 13, 0, 1, 6},
+  {0xe000, 0xf000, 5, 0, 2, 1},
+  {0x1d00, 0xff00, 9, 0, 2, 2}, //20
+  {0x0380, 0xffc0, 11, 0, 2, 3},
+  {0x0510, 0xfff0, 13, 0, 2, 4},
+  {0x6800, 0xf800, 6, 0, 3, 1},
+  {0x1180, 0xff80, 10, 0, 3, 2},
+  {0x0340, 0xffc0, 11, 0, 3, 3},
+  {0x6000, 0xf800, 6, 0, 4, 1},
+  {0x1100, 0xff80, 10, 0, 4, 2},
+  {0x0520, 0xfff0, 13, 0, 4, 3},
+  {0x5800, 0xf800, 6, 0, 5, 1},
+  {0x0300, 0xffc0, 11, 0, 5, 2},        // 30
+  {0x0530, 0xfff0, 13, 0, 5, 3},
+  {0x4c00, 0xfc00, 7, 0, 6, 1},
+  {0x02c0, 0xffc0, 11, 0, 6, 2},
+  {0x0540, 0xfff0, 13, 0, 6, 3},
+  {0x4800, 0xfc00, 7, 0, 7, 1},
+  {0x0280, 0xffc0, 11, 0, 7, 2},
+  {0x4400, 0xfc00, 7, 0, 8, 1},
+  {0x0240, 0xffc0, 11, 0, 8, 2},
+  {0x4000, 0xfc00, 7, 0, 9, 1},
+  {0x0200, 0xffc0, 11, 0, 9, 2},        // 40
+  {0x2c00, 0xfe00, 8, 0, 10, 1},
+  {0x0550, 0xfff0, 13, 0, 10, 2},
+  {0x2a00, 0xfe00, 8, 0, 11, 1},
+  {0x2800, 0xfe00, 8, 0, 12, 1},
+  {0x1c00, 0xff00, 9, 0, 13, 1},
+  {0x1b00, 0xff00, 9, 0, 14, 1},
+  {0x1080, 0xff80, 10, 0, 15, 1},
+  {0x1000, 0xff80, 10, 0, 16, 1},
+  {0x0f80, 0xff80, 10, 0, 17, 1},
+  {0x0f00, 0xff80, 10, 0, 18, 1},       // 50
+  {0x0e80, 0xff80, 10, 0, 19, 1},
+  {0x0e00, 0xff80, 10, 0, 20, 1},
+  {0x0d80, 0xff80, 10, 0, 21, 1},
+  {0x0d00, 0xff80, 10, 0, 22, 1},
+  {0x0440, 0xffe0, 12, 0, 23, 1},
+  {0x0460, 0xffe0, 12, 0, 24, 1},
+  {0x0560, 0xfff0, 13, 0, 25, 1},
+  {0x0570, 0xfff0, 13, 0, 26, 1},
+  {0x7000, 0xf000, 5, 1, 0, 1},
+  {0x0c80, 0xff80, 10, 1, 0, 2},        // 60
+  {0x00a0, 0xffe0, 12, 1, 0, 3},
+  {0x3c00, 0xfc00, 7, 1, 1, 1},
+  {0x0080, 0xffe0, 12, 1, 1, 2},
+  {0x3800, 0xfc00, 7, 1, 2, 1},
+  {0x3400, 0xfc00, 7, 1, 3, 1},
+  {0x3000, 0xfc00, 7, 1, 4, 1},
+  {0x2600, 0xfe00, 8, 1, 5, 1},
+  {0x2400, 0xfe00, 8, 1, 6, 1},
+  {0x2200, 0xfe00, 8, 1, 7, 1},
+  {0x2000, 0xfe00, 8, 1, 8, 1}, // 70
+  {0x1a00, 0xff00, 9, 1, 9, 1},
+  {0x1900, 0xff00, 9, 1, 10, 1},
+  {0x1800, 0xff00, 9, 1, 11, 1},
+  {0x1700, 0xff00, 9, 1, 12, 1},
+  {0x1600, 0xff00, 9, 1, 13, 1},
+  {0x1500, 0xff00, 9, 1, 14, 1},
+  {0x1400, 0xff00, 9, 1, 15, 1},
+  {0x1300, 0xff00, 9, 1, 16, 1},
+  {0x0c00, 0xff80, 10, 1, 17, 1},
+  {0x0b80, 0xff80, 10, 1, 18, 1},       // 80
+  {0x0b00, 0xff80, 10, 1, 19, 1},
+  {0x0a80, 0xff80, 10, 1, 20, 1},
+  {0x0a00, 0xff80, 10, 1, 21, 1},
+  {0x0980, 0xff80, 10, 1, 22, 1},
+  {0x0900, 0xff80, 10, 1, 23, 1},
+  {0x0880, 0xff80, 10, 1, 24, 1},
+  {0x01c0, 0xffc0, 11, 1, 25, 1},
+  {0x0180, 0xffc0, 11, 1, 26, 1},
+  {0x0140, 0xffc0, 11, 1, 27, 1},
+  {0x0100, 0xffc0, 11, 1, 28, 1},       // 90
+  {0x0480, 0xffe0, 12, 1, 29, 1},
+  {0x04a0, 0xffe0, 12, 1, 30, 1},
+  {0x04c0, 0xffe0, 12, 1, 31, 1},
+  {0x04e0, 0xffe0, 12, 1, 32, 1},
+  {0x0580, 0xfff0, 13, 1, 33, 1},
+  {0x0590, 0xfff0, 13, 1, 34, 1},
+  {0x05a0, 0xfff0, 13, 1, 35, 1},
+  {0x05b0, 0xfff0, 13, 1, 36, 1},
+  {0x05c0, 0xfff0, 13, 1, 37, 1},
+  {0x05d0, 0xfff0, 13, 1, 38, 1},       // 100
+  {0x05e0, 0xfff0, 13, 1, 39, 1},
+  {0x05f0, 0xfff0, 13, 1, 40, 1},
+  {0x0600, 0xfe00, 7, 0, 0xffff, 0xffff}
+};
+
+/*
+ * Motion vector code table (Code, mask, nbits, vector (halfpixel, two's complement), diff (halfpixel, two's complement))
+ */
+#define MVD_LEN 64
+#define MVD_WID 5
+static const guint16 mvd[64][5] = {
+  {0x0028, 0xfff8, 13, 0x0060, 0x0020},
+  {0x0038, 0xfff8, 13, 0x0061, 0x0021},
+  {0x0050, 0xfff0, 12, 0x0062, 0x0022},
+  {0x0070, 0xfff0, 12, 0x0063, 0x0023},
+  {0x0090, 0xfff0, 12, 0x0064, 0x0024},
+  {0x00b0, 0xfff0, 12, 0x0065, 0x0025},
+  {0x00d0, 0xfff0, 12, 0x0066, 0x0026},
+  {0x00f0, 0xfff0, 12, 0x0067, 0x0027},
+  {0x0120, 0xffe0, 11, 0x0068, 0x0028},
+  {0x0160, 0xffe0, 11, 0x0069, 0x0029},
+  {0x01a0, 0xffe0, 11, 0x006a, 0x002a},
+  {0x01e0, 0xffe0, 11, 0x006b, 0x002b},
+  {0x0220, 0xffe0, 11, 0x006c, 0x002c},
+  {0x0260, 0xffe0, 11, 0x006d, 0x002d},
+  {0x02a0, 0xffe0, 11, 0x006e, 0x002e},
+  {0x02e0, 0xffe0, 11, 0x006f, 0x002f},
+  {0x0320, 0xffe0, 11, 0x0070, 0x0030},
+  {0x0360, 0xffe0, 11, 0x0071, 0x0031},
+  {0x03a0, 0xffe0, 11, 0x0072, 0x0032},
+  {0x03e0, 0xffe0, 11, 0x0073, 0x0033},
+  {0x0420, 0xffe0, 11, 0x0074, 0x0034},
+  {0x0460, 0xffe0, 11, 0x0075, 0x0035},
+  {0x04c0, 0xffc0, 10, 0x0076, 0x0036},
+  {0x0540, 0xffc0, 10, 0x0077, 0x0037},
+  {0x05c0, 0xffc0, 10, 0x0078, 0x0038},
+  {0x0700, 0xff00, 8, 0x0079, 0x0039},
+  {0x0900, 0xff00, 8, 0x007a, 0x003a},
+  {0x0b00, 0xff00, 8, 0x007b, 0x003b},
+  {0x0e00, 0xfe00, 7, 0x007c, 0x003c},
+  {0x1800, 0xf800, 5, 0x007d, 0x003d},
+  {0x3000, 0xf000, 4, 0x007e, 0x003e},
+  {0x6000, 0xe000, 3, 0x007f, 0x003f},
+  {0x8000, 0x8000, 1, 0x0000, 0x0000},
+  {0x4000, 0xe000, 3, 0x0001, 0x0041},
+  {0x2000, 0xf000, 4, 0x0002, 0x0042},
+  {0x1000, 0xf800, 5, 0x0003, 0x0043},
+  {0x0c00, 0xfe00, 7, 0x0004, 0x0044},
+  {0x0a00, 0xff00, 8, 0x0005, 0x0045},
+  {0x0800, 0xff00, 8, 0x0006, 0x0046},
+  {0x0600, 0xff00, 8, 0x0007, 0x0047},
+  {0x0580, 0xffc0, 10, 0x0008, 0x0048},
+  {0x0500, 0xffc0, 10, 0x0009, 0x0049},
+  {0x0480, 0xffc0, 10, 0x000a, 0x004a},
+  {0x0440, 0xffe0, 11, 0x000b, 0x004b},
+  {0x0400, 0xffe0, 11, 0x000c, 0x004c},
+  {0x03c0, 0xffe0, 11, 0x000d, 0x004d},
+  {0x0380, 0xffe0, 11, 0x000e, 0x004e},
+  {0x0340, 0xffe0, 11, 0x000f, 0x004f},
+  {0x0300, 0xffe0, 11, 0x0010, 0x0050},
+  {0x02c0, 0xffe0, 11, 0x0011, 0x0051},
+  {0x0280, 0xffe0, 11, 0x0012, 0x0052},
+  {0x0240, 0xffe0, 11, 0x0013, 0x0053},
+  {0x0200, 0xffe0, 11, 0x0014, 0x0054},
+  {0x01c0, 0xffe0, 11, 0x0015, 0x0055},
+  {0x0180, 0xffe0, 11, 0x0016, 0x0056},
+  {0x0140, 0xffe0, 11, 0x0017, 0x0057},
+  {0x0100, 0xffe0, 11, 0x0018, 0x0058},
+  {0x00e0, 0xfff0, 12, 0x0019, 0x0059},
+  {0x00c0, 0xfff0, 12, 0x001a, 0x005a},
+  {0x00a0, 0xfff0, 12, 0x001b, 0x005b},
+  {0x0080, 0xfff0, 12, 0x001c, 0x005c},
+  {0x0060, 0xfff0, 12, 0x001d, 0x005d},
+  {0x0040, 0xfff0, 12, 0x001e, 0x005e},
+  {0x0030, 0xfff8, 13, 0x001f, 0x005f}
+};
+
+GST_DEBUG_CATEGORY_STATIC (rtph263pay_debug);
+#define GST_CAT_DEFAULT (rtph263pay_debug)
+
+#define GST_RTP_HEADER_LEN 12
+
+enum
+{
+  PROP_0,
+  PROP_MODE_A_ONLY
+};
+
+static GstStaticPadTemplate gst_rtp_h263_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-h263, "
+        "variant = (string) \"itu\", " "h263version = (string) \"h263\"")
+    );
+
+static GstStaticPadTemplate gst_rtp_h263_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_H263_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"H263\"; "
+        "application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"H263\"")
+    );
+
+static void gst_rtp_h263_pay_finalize (GObject * object);
+
+static gboolean gst_rtp_h263_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static void gst_rtp_h263_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_h263_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static GstFlowReturn gst_rtp_h263_pay_handle_buffer (GstRTPBasePayload *
+    payload, GstBuffer * buffer);
+
+static void gst_rtp_h263_pay_boundry_init (GstRtpH263PayBoundry * boundry,
+    guint8 * start, guint8 * end, guint8 sbit, guint8 ebit);
+static GstRtpH263PayGob *gst_rtp_h263_pay_gob_new (GstRtpH263PayBoundry *
+    boundry, guint gobn);
+static GstRtpH263PayMB *gst_rtp_h263_pay_mb_new (GstRtpH263PayBoundry * boundry,
+    guint mba);
+static GstRtpH263PayPackage *gst_rtp_h263_pay_package_new_empty ();
+static GstRtpH263PayPackage *gst_rtp_h263_pay_package_new (guint8 * start,
+    guint8 * end, guint length, guint8 sbit, guint8 ebit, GstBuffer * outbuf,
+    gboolean marker);
+
+static void gst_rtp_h263_pay_mb_destroy (GstRtpH263PayMB * mb);
+static void gst_rtp_h263_pay_gob_destroy (GstRtpH263PayGob * gob, guint ind);
+static void gst_rtp_h263_pay_context_destroy (GstRtpH263PayContext * context,
+    guint ind);
+static void gst_rtp_h263_pay_package_destroy (GstRtpH263PayPackage * pack);
+
+#define gst_rtp_h263_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpH263Pay, gst_rtp_h263_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_h263_pay_class_init (GstRtpH263PayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_h263_pay_finalize;
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_h263_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_h263_pay_handle_buffer;
+  gobject_class->set_property = gst_rtp_h263_pay_set_property;
+  gobject_class->get_property = gst_rtp_h263_pay_get_property;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_MODE_A_ONLY, g_param_spec_boolean ("modea-only",
+          "Fragment packets in mode A Only",
+          "Disable packetization modes B and C", DEFAULT_MODE_A,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h263_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h263_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP H263 packet payloader", "Codec/Payloader/Network/RTP",
+      "Payload-encodes H263 video in RTP packets (RFC 2190)",
+      "Neil Stratford <neils@vipadia.com>"
+      "Dejan Sakelsak <dejan.sakelsak@marand.si>");
+
+  GST_DEBUG_CATEGORY_INIT (rtph263pay_debug, "rtph263pay", 0,
+      "H263 RTP Payloader");
+}
+
+static void
+gst_rtp_h263_pay_init (GstRtpH263Pay * rtph263pay)
+{
+  GST_RTP_BASE_PAYLOAD_PT (rtph263pay) = GST_RTP_PAYLOAD_H263;
+  rtph263pay->prop_payload_mode = DEFAULT_MODE_A;
+}
+
+static void
+gst_rtp_h263_pay_finalize (GObject * object)
+{
+  GstRtpH263Pay *rtph263pay;
+
+  rtph263pay = GST_RTP_H263_PAY (object);
+
+  gst_buffer_replace (&rtph263pay->current_buffer, NULL);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_h263_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  GstStructure *s = gst_caps_get_structure (caps, 0);
+  gint width, height;
+  gchar *framesize = NULL;
+  gboolean res;
+
+  if (gst_structure_has_field (s, "width") &&
+      gst_structure_has_field (s, "height")) {
+    if (!gst_structure_get_int (s, "width", &width) || width <= 0) {
+      goto invalid_dimension;
+    }
+
+    if (!gst_structure_get_int (s, "height", &height) || height <= 0) {
+      goto invalid_dimension;
+    }
+
+    framesize = g_strdup_printf ("%d-%d", width, height);
+  }
+
+  gst_rtp_base_payload_set_options (payload, "video",
+      payload->pt != GST_RTP_PAYLOAD_H263, "H263", 90000);
+
+  if (framesize != NULL) {
+    res = gst_rtp_base_payload_set_outcaps (payload,
+        "a-framesize", G_TYPE_STRING, framesize, NULL);
+  } else {
+    res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+  }
+  g_free (framesize);
+
+  return res;
+
+  /* ERRORS */
+invalid_dimension:
+  {
+    GST_ERROR_OBJECT (payload, "Invalid width/height from caps");
+    return FALSE;
+  }
+}
+
+static void
+gst_rtp_h263_pay_context_destroy (GstRtpH263PayContext * context, guint ind)
+{
+  if (!context)
+    return;
+
+  if (context->gobs) {
+    guint i;
+
+    for (i = 0; i < format_props[ind][0]; i++) {
+      if (context->gobs[i]) {
+        gst_rtp_h263_pay_gob_destroy (context->gobs[i], ind);
+      }
+    }
+
+    g_free (context->gobs);
+  }
+
+  g_free (context);
+}
+
+static void
+gst_rtp_h263_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpH263Pay *rtph263pay;
+
+  rtph263pay = GST_RTP_H263_PAY (object);
+
+  switch (prop_id) {
+    case PROP_MODE_A_ONLY:
+      rtph263pay->prop_payload_mode = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_h263_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpH263Pay *rtph263pay;
+
+  rtph263pay = GST_RTP_H263_PAY (object);
+
+  switch (prop_id) {
+    case PROP_MODE_A_ONLY:
+      g_value_set_boolean (value, rtph263pay->prop_payload_mode);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstRtpH263PayPackage *
+gst_rtp_h263_pay_package_new_empty (void)
+{
+  return (GstRtpH263PayPackage *) g_malloc0 (sizeof (GstRtpH263PayPackage));
+}
+
+static GstRtpH263PayPackage *
+gst_rtp_h263_pay_package_new (guint8 * start, guint8 * end, guint length,
+    guint8 sbit, guint8 ebit, GstBuffer * outbuf, gboolean marker)
+{
+
+  GstRtpH263PayPackage *package;
+
+  package = gst_rtp_h263_pay_package_new_empty ();
+
+  package->payload_start = start;
+  package->payload_end = end;
+  package->payload_len = length;
+  package->sbit = sbit;
+  package->ebit = ebit;
+  package->outbuf = outbuf;
+  package->marker = marker;
+
+  return package;
+}
+
+static void
+gst_rtp_h263_pay_package_destroy (GstRtpH263PayPackage * pack)
+{
+  if (pack)
+    g_free (pack);
+}
+
+static void
+gst_rtp_h263_pay_boundry_init (GstRtpH263PayBoundry * boundry,
+    guint8 * start, guint8 * end, guint8 sbit, guint8 ebit)
+{
+  boundry->start = start;
+  boundry->end = end;
+  boundry->sbit = sbit;
+  boundry->ebit = ebit;
+}
+
+static void
+gst_rtp_h263_pay_splat_header_A (guint8 * header,
+    GstRtpH263PayPackage * package, GstRtpH263PayPic * piclayer)
+{
+
+  GstRtpH263PayAHeader *a_header;
+
+  a_header = (GstRtpH263PayAHeader *) header;
+
+  a_header->f = 0;
+  a_header->p = 0;
+  a_header->sbit = package->sbit;
+  a_header->ebit = package->ebit;
+  a_header->src = GST_H263_PICTURELAYER_PLSRC (piclayer);
+  a_header->i = GST_H263_PICTURELAYER_PLTYPE (piclayer);
+  a_header->u = GST_H263_PICTURELAYER_PLUMV (piclayer);
+  a_header->s = GST_H263_PICTURELAYER_PLSAC (piclayer);
+  a_header->a = GST_H263_PICTURELAYER_PLAP (piclayer);
+  a_header->r1 = 0;
+  a_header->r2 = 0;
+  a_header->dbq = 0;
+  a_header->trb = 0;
+  a_header->tr = 0;
+
+}
+
+static void
+gst_rtp_h263_pay_splat_header_B (guint8 * header,
+    GstRtpH263PayPackage * package, GstRtpH263PayPic * piclayer)
+{
+
+  GstRtpH263PayBHeader *b_header;
+
+  b_header = (GstRtpH263PayBHeader *) header;
+
+  b_header->f = 1;
+  b_header->p = 0;
+  b_header->sbit = package->sbit;
+  b_header->ebit = package->ebit;
+  b_header->src = GST_H263_PICTURELAYER_PLSRC (piclayer);
+  b_header->quant = package->quant;
+  b_header->gobn = package->gobn;
+  b_header->mba1 = package->mba >> 6;
+  b_header->mba2 = package->mba & 0x003f;
+  b_header->r = 0;
+  b_header->i = GST_H263_PICTURELAYER_PLTYPE (piclayer);
+  b_header->u = GST_H263_PICTURELAYER_PLUMV (piclayer);
+  b_header->s = GST_H263_PICTURELAYER_PLSAC (piclayer);
+  b_header->a = GST_H263_PICTURELAYER_PLAP (piclayer);
+
+  b_header->hmv11 = 0;
+  b_header->hmv12 = 0;
+  b_header->vmv11 = 0;
+  b_header->vmv12 = 0;
+  b_header->hmv21 = 0;
+  b_header->hmv22 = 0;
+  b_header->vmv21 = 0;
+
+  if (package->nmvd > 0) {
+    //mvd[0]
+    b_header->hmv11 = (package->mvd[0] & 0x7f) >> 3;
+    b_header->hmv12 = (package->mvd[0] & 0x07);
+    //mvd[1]
+    b_header->vmv11 = (package->mvd[1] & 0x07f) >> 2;
+    b_header->vmv12 = (package->mvd[1] & 0x03);
+
+    if (package->nmvd == 8) {
+      //mvd[4]
+      b_header->hmv21 = (package->mvd[4] & 0x7f) >> 1;
+      b_header->hmv22 = (package->mvd[4] & 0x01);
+      //mvd[5]
+      b_header->vmv21 = (package->mvd[5] & 0x7f);
+    }
+  }
+
+}
+
+static gboolean
+gst_rtp_h263_pay_gobfinder (GstRtpH263Pay * rtph263pay,
+    GstRtpH263PayBoundry * boundry)
+{
+  guint8 *current;
+  guint range;
+  guint i;
+
+  current = boundry->end + 1;
+  range = (rtph263pay->data - current) + rtph263pay->available_data;
+
+
+  GST_DEBUG_OBJECT (rtph263pay,
+      "Searching for next GOB, data:%p, len:%u, payload_len:%p,"
+      " current:%p, range:%u", rtph263pay->data, rtph263pay->available_data,
+      boundry->end + 1, current, range);
+
+  /* If we are past the end, stop */
+  if (current >= rtph263pay->data + rtph263pay->available_data)
+    return FALSE;
+
+  for (i = 3; i < range - 3; i++) {
+    if ((current[i] == 0x0) &&
+        (current[i + 1] == 0x0) && (current[i + 2] >> 7 == 0x1)) {
+      GST_LOG_OBJECT (rtph263pay, "GOB end found at: %p start: %p len: %u",
+          current + i - 1, boundry->end + 1,
+          (guint) (current + i - boundry->end + 2));
+      gst_rtp_h263_pay_boundry_init (boundry, boundry->end + 1, current + i - 1,
+          0, 0);
+
+      return TRUE;
+    }
+  }
+
+  GST_DEBUG_OBJECT (rtph263pay,
+      "Couldn't find any new GBSC in this frame, range:%u", range);
+
+  gst_rtp_h263_pay_boundry_init (boundry, boundry->end + 1,
+      (guint8 *) (rtph263pay->data + rtph263pay->available_data - 1), 0, 0);
+
+  return TRUE;
+}
+
+static GstRtpH263PayGob *
+gst_rtp_h263_pay_gob_new (GstRtpH263PayBoundry * boundry, guint gobn)
+{
+  GstRtpH263PayGob *gob;
+
+  gob = (GstRtpH263PayGob *) g_malloc0 (sizeof (GstRtpH263PayGob));
+
+  gob->start = boundry->start;
+  gob->end = boundry->end;
+  gob->length = boundry->end - boundry->start + 1;
+  gob->ebit = boundry->ebit;
+  gob->sbit = boundry->sbit;
+  gob->gobn = gobn;
+  gob->quant = 0;
+  gob->macroblocks = NULL;
+  gob->nmacroblocs = 0;
+
+  return gob;
+}
+
+static void
+gst_rtp_h263_pay_gob_destroy (GstRtpH263PayGob * gob, guint ind)
+{
+
+  if (!gob)
+    return;
+
+  if (gob->macroblocks) {
+
+    guint i;
+
+    for (i = 0; i < gob->nmacroblocs; i++) {
+      gst_rtp_h263_pay_mb_destroy (gob->macroblocks[i]);
+    }
+
+    g_free (gob->macroblocks);
+  }
+
+  g_free (gob);
+}
+
+/*
+ * decode MCBPC for I frames and return index in table or -1 if not found
+ */
+static gint
+gst_rtp_h263_pay_decode_mcbpc_I (GstRtpH263Pay * rtph263pay, guint32 value)
+{
+
+  gint i;
+  guint16 code;
+
+  code = value >> 16;
+
+  GST_TRACE_OBJECT (rtph263pay, "value:0x%08x, code:0x%04x", value, code);
+
+  for (i = 0; i < MCBPC_I_LEN; i++) {
+    if ((code & mcbpc_I[i][1]) == mcbpc_I[i][0]) {
+      return i;
+    }
+  }
+
+  GST_WARNING_OBJECT (rtph263pay, "Couldn't find code, returning -1");
+
+  return -1;
+}
+
+/*
+ * decode MCBPC for P frames and return index in table or -1 if not found
+ */
+static gint
+gst_rtp_h263_pay_decode_mcbpc_P (GstRtpH263Pay * rtph263pay, guint32 value)
+{
+
+  gint i;
+  guint16 code;
+
+  code = value >> 16;
+
+  GST_TRACE_OBJECT (rtph263pay, "value:0x%08x, code:0x%04x", value, code);
+
+  for (i = 0; i < MCBPC_P_LEN; i++) {
+    if ((code & mcbpc_P[i][1]) == mcbpc_P[i][0]) {
+      return i;
+    }
+  }
+
+  GST_WARNING_OBJECT (rtph263pay, "Couldn't find code, returning -1");
+
+  return -1;
+}
+
+/*
+ * decode CBPY and return index in table or -1 if not found
+ */
+static gint
+gst_rtp_h263_pay_decode_cbpy (GstRtpH263Pay * rtph263pay, guint32 value,
+    const guint8 cbpy_table[16][7])
+{
+
+  gint i;
+  guint8 code;
+
+  code = value >> 24;
+
+  GST_TRACE_OBJECT (rtph263pay, "value:0x%08x, code:0x%04x", value, code);
+
+  for (i = 0; i < CBPY_LEN; i++) {
+    if ((code & cbpy_table[i][1]) == cbpy_table[i][0]) {
+      return i;
+    }
+  }
+
+  GST_WARNING_OBJECT (rtph263pay, "Couldn't find code, returning -1");
+
+  return -1;
+}
+
+/*
+ * decode MVD and return index in table or -1 if not found
+ */
+static gint
+gst_rtp_h263_pay_decode_mvd (GstRtpH263Pay * rtph263pay, guint32 value)
+{
+
+  gint i;
+  guint16 code;
+
+  code = value >> 16;
+
+  GST_TRACE_OBJECT (rtph263pay, "value:0x%08x, code:0x%04x", value, code);
+
+  for (i = 0; i < MVD_LEN; i++) {
+    if ((code & mvd[i][1]) == mvd[i][0]) {
+      return i;
+    }
+  }
+
+  GST_WARNING_OBJECT (rtph263pay, "Couldn't find code, returning -1");
+
+  return -1;
+}
+
+/*
+ * decode TCOEF and return index in table or -1 if not found
+ */
+static gint
+gst_rtp_h263_pay_decode_tcoef (GstRtpH263Pay * rtph263pay, guint32 value)
+{
+
+  gint i;
+  guint16 code;
+
+  code = value >> 16;
+
+  GST_TRACE_OBJECT (rtph263pay, "value:0x%08x, code:0x%04x", value, code);
+
+  for (i = 0; i < TCOEF_LEN; i++) {
+    if ((code & tcoef[i][1]) == tcoef[i][0]) {
+      GST_TRACE_OBJECT (rtph263pay, "tcoef is %d", i);
+      return i;
+    }
+  }
+
+  GST_WARNING_OBJECT (rtph263pay, "Couldn't find code, returning -1");
+
+  return -1;
+}
+
+/*
+ * the 32-bit register is like a window that we move right for "move_bits" to get the next v "data" h263 field
+ * "rest_bits" tells how many bits in the "data" byte address are still not used
+ */
+
+static gint
+gst_rtp_h263_pay_move_window_right (GstRtpH263Pay * rtph263pay,
+    GstRtpH263PayContext * context, guint n, guint rest_bits,
+    guint8 ** orig_data, guint8 ** data_end)
+{
+
+  GST_TRACE_OBJECT (rtph263pay,
+      "Moving window: 0x%08x from: %p for %d bits, rest_bits: %d, data_end %p",
+      context->window, context->win_end, n, rest_bits, *data_end);
+
+  if (n == 0)
+    return rest_bits;
+
+  while (n != 0 || context->win_end == ((*data_end) + 1)) {
+    guint8 b = context->win_end <= *data_end ? *context->win_end : 0;
+    if (rest_bits == 0) {
+      if (n > 8) {
+        context->window = (context->window << 8) | b;
+        n -= 8;
+      } else {
+        context->window = (context->window << n) | (b >> (8 - n));
+        rest_bits = 8 - n;
+        if (rest_bits == 0)
+          context->win_end++;
+        break;
+      }
+    } else {
+      if (n > rest_bits) {
+        context->window = (context->window << rest_bits) |
+            (b & (((guint) pow (2.0, (double) rest_bits)) - 1));
+        n -= rest_bits;
+        rest_bits = 0;
+      } else {
+        context->window = (context->window << n) |
+            ((b & (((guint) pow (2.0, (double) rest_bits)) - 1)) >>
+            (rest_bits - n));
+        rest_bits -= n;
+        if (rest_bits == 0)
+          context->win_end++;
+        break;
+      }
+    }
+
+    context->win_end++;
+  }
+
+  *orig_data = context->win_end - 4;
+
+  GST_TRACE_OBJECT (rtph263pay,
+      "Window moved to %p with value: 0x%08x and orig_data: %p rest_bits: %d",
+      context->win_end, context->window, *orig_data, rest_bits);
+  return rest_bits;
+}
+
+/*
+ * Find the start of the next MB (end of the current MB)
+ * returns the number of excess bits and stores the end of the MB in end
+ * data must be placed on first MB byte
+ */
+static GstRtpH263PayMB *
+gst_rtp_h263_pay_B_mbfinder (GstRtpH263Pay * rtph263pay,
+    GstRtpH263PayContext * context, GstRtpH263PayGob * gob,
+    GstRtpH263PayMB * macroblock, guint mba)
+{
+  guint mb_type_index;
+  guint cbpy_type_index;
+  guint tcoef_type_index;
+  GstRtpH263PayMB *mac;
+  GstRtpH263PayBoundry boundry;
+
+  gst_rtp_h263_pay_boundry_init (&boundry, macroblock->end,
+      macroblock->end, 8 - macroblock->ebit, macroblock->ebit);
+  mac = gst_rtp_h263_pay_mb_new (&boundry, mba);
+
+  if (mac->sbit == 8) {
+    mac->start++;
+//     mac->end++;
+    mac->sbit = 0;
+  }
+
+  GST_LOG_OBJECT (rtph263pay,
+      "current_pos:%p, end:%p, rest_bits:%d, window:0x%08x", mac->start,
+      mac->end, macroblock->ebit, context->window);
+
+  if (context->piclayer->ptype_pictype == 0) {
+    //We have an I frame
+    gint i;
+    guint last;
+    guint ind;
+
+    //Step 2 decode MCBPC I
+    mb_type_index =
+        gst_rtp_h263_pay_decode_mcbpc_I (rtph263pay, context->window);
+
+    GST_TRACE_OBJECT (rtph263pay, "MCBPC index: %d", mb_type_index);
+    if (mb_type_index == -1) {
+      GST_ERROR_OBJECT (rtph263pay, "MB index shouldn't be -1 in window: %08x",
+          context->window);
+      goto beach;
+    }
+
+    mac->ebit =
+        gst_rtp_h263_pay_move_window_right (rtph263pay, context,
+        mcbpc_I[mb_type_index][2], mac->ebit, &mac->end, &gob->end);
+
+    mac->mb_type = mcbpc_I[mb_type_index][5];
+
+    if (mb_type_index == 8) {
+      GST_TRACE_OBJECT (rtph263pay, "Stuffing skipping rest of MB header");
+      return mac;
+    }
+    //Step 3 decode CBPY I
+    cbpy_type_index =
+        gst_rtp_h263_pay_decode_cbpy (rtph263pay, context->window, cbpy_I);
+
+    GST_TRACE_OBJECT (rtph263pay, "CBPY index: %d", cbpy_type_index);
+    if (cbpy_type_index == -1) {
+      GST_ERROR_OBJECT (rtph263pay,
+          "CBPY index shouldn't be -1 in window: %08x", context->window);
+      goto beach;
+    }
+
+    mac->ebit =
+        gst_rtp_h263_pay_move_window_right (rtph263pay, context,
+        cbpy_I[cbpy_type_index][2], mac->ebit, &mac->end, &gob->end);
+
+    //Step 4 decode rest of MB
+    //MB type 1 and 4 have DQUANT - we store it for packaging purposes
+    if (mcbpc_I[mb_type_index][5] == 4) {
+      GST_TRACE_OBJECT (rtph263pay, "Shifting DQUANT");
+
+      mac->quant = (context->window >> 30);
+
+      mac->ebit =
+          gst_rtp_h263_pay_move_window_right (rtph263pay, context, 2, mac->ebit,
+          &mac->end, &gob->end);
+    }
+    //Step 5 go trough the blocks - decode DC and TCOEF
+    last = 0;
+    for (i = 0; i < N_BLOCKS; i++) {
+
+      GST_TRACE_OBJECT (rtph263pay, "Decoding INTRADC and TCOEF, i:%d", i);
+      mac->ebit =
+          gst_rtp_h263_pay_move_window_right (rtph263pay, context, 8, mac->ebit,
+          &mac->end, &gob->end);
+
+      if (i > 3) {
+        ind = mcbpc_I[mb_type_index][i - 1];
+      } else {
+        ind = cbpy_I[cbpy_type_index][i + 3];
+      }
+
+      if (ind == 1) {
+        while (last == 0) {
+          tcoef_type_index =
+              gst_rtp_h263_pay_decode_tcoef (rtph263pay, context->window);
+
+          GST_TRACE_OBJECT (rtph263pay, "TCOEF index: %d", tcoef_type_index);
+          if (tcoef_type_index == -1) {
+            GST_ERROR_OBJECT (rtph263pay,
+                "TCOEF index shouldn't be -1 in window: %08x", context->window);
+            goto beach;
+          }
+          mac->ebit =
+              gst_rtp_h263_pay_move_window_right (rtph263pay, context,
+              tcoef[tcoef_type_index][2], mac->ebit, &mac->end, &gob->end);
+
+          last = tcoef[tcoef_type_index][3];
+          if (tcoef_type_index == 102) {
+            if ((context->window & 0x80000000) == 0x80000000)
+              last = 1;
+            else
+              last = 0;
+
+            mac->ebit =
+                gst_rtp_h263_pay_move_window_right (rtph263pay, context, 15,
+                mac->ebit, &mac->end, &gob->end);
+          }
+        }
+        last = 0;
+      }
+    }
+
+  } else {
+    //We have a P frame
+    guint i;
+    guint last;
+    guint ind;
+
+    //Step 1 check COD
+    GST_TRACE_OBJECT (rtph263pay, "Checking for COD");
+    if ((context->window & 0x80000000) == 0x80000000) {
+      //The MB is not coded
+      mac->ebit =
+          gst_rtp_h263_pay_move_window_right (rtph263pay, context, 1, mac->ebit,
+          &mac->end, &gob->end);
+      GST_TRACE_OBJECT (rtph263pay, "COOOOOOOOOOOD = 1");
+
+      return mac;
+    } else {
+      //The MB is coded
+      mac->ebit =
+          gst_rtp_h263_pay_move_window_right (rtph263pay, context, 1, mac->ebit,
+          &mac->end, &gob->end);
+    }
+
+    //Step 2 decode MCBPC P
+    mb_type_index =
+        gst_rtp_h263_pay_decode_mcbpc_P (rtph263pay, context->window);
+
+    GST_TRACE_OBJECT (rtph263pay, "MCBPC index: %d", mb_type_index);
+    if (mb_type_index == -1) {
+      GST_ERROR_OBJECT (rtph263pay, "MB index shouldn't be -1 in window: %08x",
+          context->window);
+      goto beach;
+    }
+    mac->ebit =
+        gst_rtp_h263_pay_move_window_right (rtph263pay, context,
+        mcbpc_P[mb_type_index][2], mac->ebit, &mac->end, &gob->end);
+
+    mac->mb_type = mcbpc_P[mb_type_index][5];
+
+    if (mb_type_index == 20) {
+      GST_TRACE_OBJECT (rtph263pay, "Stuffing skipping rest of MB header");
+      return mac;
+    }
+    //Step 3 decode CBPY P
+    cbpy_type_index =
+        gst_rtp_h263_pay_decode_cbpy (rtph263pay, context->window, cbpy_P);
+
+    GST_TRACE_OBJECT (rtph263pay, "CBPY index: %d", cbpy_type_index);
+    if (cbpy_type_index == -1) {
+      GST_ERROR_OBJECT (rtph263pay,
+          "CBPY index shouldn't be -1 in window: %08x", context->window);
+      goto beach;
+    }
+    mac->ebit =
+        gst_rtp_h263_pay_move_window_right (rtph263pay, context,
+        cbpy_P[cbpy_type_index][2], mac->ebit, &mac->end, &gob->end);
+
+    //MB type 1 and 4 have DQUANT - we add it to MB object and jump over
+    if (mcbpc_P[mb_type_index][5] == 4 || mcbpc_P[mb_type_index][5] == 1) {
+      GST_TRACE_OBJECT (rtph263pay, "Shifting DQUANT");
+
+      mac->quant = context->window >> 30;
+
+      mac->ebit =
+          gst_rtp_h263_pay_move_window_right (rtph263pay, context, 2, mac->ebit,
+          &mac->end, &gob->end);
+    }
+    //MB types < 3 have MVD1-4
+    if (mcbpc_P[mb_type_index][5] < 3) {
+
+      guint nmvd;
+      gint j;
+
+      nmvd = 2;
+      if (mcbpc_P[mb_type_index][5] == 2)
+        nmvd = 8;
+
+      for (j = 0; j < nmvd; j++) {
+        guint mvd_type;
+
+        mvd_type = gst_rtp_h263_pay_decode_mvd (rtph263pay, context->window);
+
+        if (mvd_type == -1) {
+          GST_ERROR_OBJECT (rtph263pay,
+              "MVD1-4 index shouldn't be -1 in window: %08x", context->window);
+          goto beach;
+        }
+        //set the MB mvd values
+        mac->mvd[j] = mvd[mvd_type][3];
+
+        mac->ebit =
+            gst_rtp_h263_pay_move_window_right (rtph263pay, context,
+            mvd[mvd_type][2], mac->ebit, &mac->end, &gob->end);
+      }
+
+
+    }
+    //Step 5 go trough the blocks - decode DC and TCOEF
+    last = 0;
+    for (i = 0; i < N_BLOCKS; i++) {
+
+      //if MB type 3 or 4 then INTRADC coef are present in blocks
+      if (mcbpc_P[mb_type_index][5] > 2) {
+        GST_TRACE_OBJECT (rtph263pay, "INTRADC coef: %d", i);
+        mac->ebit =
+            gst_rtp_h263_pay_move_window_right (rtph263pay, context, 8,
+            mac->ebit, &mac->end, &gob->end);
+      } else {
+        GST_TRACE_OBJECT (rtph263pay, "INTRADC coef is not present");
+      }
+
+      //check if the block has TCOEF
+      if (i > 3) {
+        ind = mcbpc_P[mb_type_index][i - 1];
+      } else {
+        if (mcbpc_P[mb_type_index][5] > 2) {
+          ind = cbpy_I[cbpy_type_index][i + 3];
+        } else {
+          ind = cbpy_P[cbpy_type_index][i + 3];
+        }
+      }
+
+      if (ind == 1) {
+        while (last == 0) {
+          tcoef_type_index =
+              gst_rtp_h263_pay_decode_tcoef (rtph263pay, context->window);
+
+          GST_TRACE_OBJECT (rtph263pay, "TCOEF index: %d", tcoef_type_index);
+          if (tcoef_type_index == -1) {
+            GST_ERROR_OBJECT (rtph263pay,
+                "TCOEF index shouldn't be -1 in window: %08x", context->window);
+            goto beach;
+          }
+
+          mac->ebit =
+              gst_rtp_h263_pay_move_window_right (rtph263pay, context,
+              tcoef[tcoef_type_index][2], mac->ebit, &mac->end, &gob->end);
+
+          last = tcoef[tcoef_type_index][3];
+          if (tcoef_type_index == 102) {
+            if ((context->window & 0x80000000) == 0x80000000)
+              last = 1;
+            else
+              last = 0;
+
+            mac->ebit =
+                gst_rtp_h263_pay_move_window_right (rtph263pay, context, 15,
+                mac->ebit, &mac->end, &gob->end);
+          }
+        }
+        last = 0;
+      }
+    }
+  }
+
+  mac->length = mac->end - mac->start + 1;
+
+  return mac;
+
+beach:
+  gst_rtp_h263_pay_mb_destroy (mac);
+  return NULL;
+}
+
+static GstRtpH263PayMB *
+gst_rtp_h263_pay_mb_new (GstRtpH263PayBoundry * boundry, guint mba)
+{
+  GstRtpH263PayMB *mb;
+  gint i;
+
+  mb = (GstRtpH263PayMB *) g_malloc0 (sizeof (GstRtpH263PayMB));
+
+  mb->start = boundry->start;
+  mb->end = boundry->end;
+  mb->length = boundry->end - boundry->start + 1;
+  mb->sbit = boundry->sbit;
+  mb->ebit = boundry->ebit;
+  mb->mba = mba;
+
+  for (i = 0; i < 5; i++)
+    mb->mvd[i] = 0;
+
+  return mb;
+}
+
+static void
+gst_rtp_h263_pay_mb_destroy (GstRtpH263PayMB * mb)
+{
+  if (!mb)
+    return;
+
+  g_free (mb);
+}
+
+static GstFlowReturn
+gst_rtp_h263_pay_push (GstRtpH263Pay * rtph263pay,
+    GstRtpH263PayContext * context, GstRtpH263PayPackage * package)
+{
+
+  /*
+   * Splat the payload header values
+   */
+  guint8 *header;
+  GstFlowReturn ret;
+  GstRTPBuffer rtp = { NULL };
+
+  gst_rtp_buffer_map (package->outbuf, GST_MAP_WRITE, &rtp);
+
+  header = gst_rtp_buffer_get_payload (&rtp);
+
+  switch (package->mode) {
+    case GST_RTP_H263_PAYLOAD_HEADER_MODE_A:
+      GST_LOG_OBJECT (rtph263pay, "Pushing A packet");
+      gst_rtp_h263_pay_splat_header_A (header, package, context->piclayer);
+      break;
+    case GST_RTP_H263_PAYLOAD_HEADER_MODE_B:
+      GST_LOG_OBJECT (rtph263pay, "Pushing B packet");
+      gst_rtp_h263_pay_splat_header_B (header, package, context->piclayer);
+      break;
+    case GST_RTP_H263_PAYLOAD_HEADER_MODE_C:
+      //gst_rtp_h263_pay_splat_header_C(header, package, context->piclayer);
+      //break;
+    default:
+      return GST_FLOW_ERROR;
+  }
+
+  /*
+   * timestamp the buffer
+   */
+  GST_BUFFER_PTS (package->outbuf) = rtph263pay->first_ts;
+
+  gst_rtp_buffer_set_marker (&rtp, package->marker);
+  if (package->marker)
+    GST_DEBUG_OBJECT (rtph263pay, "Marker set!");
+
+  gst_rtp_buffer_unmap (&rtp);
+
+  /*
+   * Copy the payload data in the buffer
+   */
+  GST_DEBUG_OBJECT (rtph263pay, "Copying memory");
+  gst_buffer_copy_into (package->outbuf, rtph263pay->current_buffer,
+      GST_BUFFER_COPY_MEMORY, package->payload_start - rtph263pay->map.data,
+      package->payload_len);
+  gst_rtp_copy_video_meta (rtph263pay, package->outbuf,
+      rtph263pay->current_buffer);
+
+  ret =
+      gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtph263pay),
+      package->outbuf);
+  GST_DEBUG_OBJECT (rtph263pay, "Package pushed, returning");
+
+  gst_rtp_h263_pay_package_destroy (package);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_rtp_h263_pay_A_fragment_push (GstRtpH263Pay * rtph263pay,
+    GstRtpH263PayContext * context, guint first, guint last)
+{
+
+  GstRtpH263PayPackage *pack;
+
+  pack = gst_rtp_h263_pay_package_new_empty ();
+
+  pack->payload_start = context->gobs[first]->start;
+  pack->sbit = context->gobs[first]->sbit;
+  pack->ebit = context->gobs[last]->ebit;
+  pack->payload_len =
+      (context->gobs[last]->end - context->gobs[first]->start) + 1;
+  pack->marker = FALSE;
+
+  if (last == context->no_gobs - 1) {
+    pack->marker = TRUE;
+  }
+
+  pack->gobn = context->gobs[first]->gobn;
+  pack->mode = GST_RTP_H263_PAYLOAD_HEADER_MODE_A;
+  pack->outbuf = gst_rtp_buffer_new_allocate (pack->mode, 0, 0);
+
+  GST_DEBUG_OBJECT (rtph263pay, "Sending len:%d data to push function",
+      pack->payload_len);
+
+  return gst_rtp_h263_pay_push (rtph263pay, context, pack);
+}
+
+static GstFlowReturn
+gst_rtp_h263_pay_B_fragment_push (GstRtpH263Pay * rtph263pay,
+    GstRtpH263PayContext * context, GstRtpH263PayGob * gob, guint first,
+    guint last, GstRtpH263PayBoundry * boundry)
+{
+
+  GstRtpH263PayPackage *pack;
+  guint mv;
+
+  pack = gst_rtp_h263_pay_package_new_empty ();
+
+  pack->payload_start = gob->macroblocks[first]->start;
+  pack->sbit = gob->macroblocks[first]->sbit;
+  if (first == 0) {
+    pack->payload_start = boundry->start;
+    pack->sbit = boundry->sbit;
+    pack->quant = gob->quant;
+  } else {
+    pack->quant = gob->macroblocks[first]->quant;
+  }
+  pack->payload_end = gob->macroblocks[last]->end;
+
+  pack->ebit = gob->macroblocks[last]->ebit;
+  pack->mba = gob->macroblocks[first]->mba;
+  pack->gobn = gob->gobn;
+  pack->mode = GST_RTP_H263_PAYLOAD_HEADER_MODE_B;
+  pack->nmvd = 0;
+
+  if (gob->macroblocks[first]->mb_type < 3) {
+    if (gob->macroblocks[first]->mb_type == 2)
+      pack->nmvd = 8;
+    else if (gob->macroblocks[first]->mb_type < 2)
+      pack->nmvd = 2;
+
+    for (mv = 0; mv < pack->nmvd; mv++)
+      pack->mvd[mv] = gob->macroblocks[first]->mvd[mv];
+  }
+
+  pack->marker = FALSE;
+  if (last == gob->nmacroblocs - 1) {
+    pack->ebit = 0;
+  }
+
+  if ((format_props[context->piclayer->ptype_srcformat][0] - 1 == gob->gobn)
+      && (last == gob->nmacroblocs - 1)) {
+    pack->marker = TRUE;
+  }
+
+  pack->payload_len = pack->payload_end - pack->payload_start + 1;
+  pack->outbuf = gst_rtp_buffer_new_allocate (pack->mode, 0, 0);
+
+  return gst_rtp_h263_pay_push (rtph263pay, context, pack);
+}
+
+
+static gboolean
+gst_rtp_h263_pay_mode_B_fragment (GstRtpH263Pay * rtph263pay,
+    GstRtpH263PayContext * context, GstRtpH263PayGob * gob)
+{
+
+
+    /*---------- MODE B MODE FRAGMENTATION ----------*/
+  GstRtpH263PayMB *mac, *mac0;
+  guint max_payload_size;
+  GstRtpH263PayBoundry boundry;
+  guint mb;
+  guint8 ebit;
+
+  guint first = 0;
+  guint payload_len;
+
+  max_payload_size =
+      context->mtu - GST_RTP_H263_PAYLOAD_HEADER_MODE_B - GST_RTP_HEADER_LEN;
+
+  gst_rtp_h263_pay_boundry_init (&boundry, gob->start, gob->start, gob->sbit,
+      0);
+
+  gob->macroblocks =
+      (GstRtpH263PayMB **) g_malloc0 (sizeof (GstRtpH263PayMB *) *
+      format_props[context->piclayer->ptype_srcformat][1]);
+
+  GST_LOG_OBJECT (rtph263pay, "GOB isn't PB frame, applying mode B");
+
+  //initializing window
+  context->win_end = boundry.end;
+  if (gst_rtp_h263_pay_move_window_right (rtph263pay, context, 32, boundry.ebit,
+          &boundry.end, &gob->end) != 0) {
+    GST_ERROR_OBJECT (rtph263pay,
+        "The rest of the bits should be 0, exiting, because something bad happend");
+    goto decode_error;
+  }
+  //The first GOB of a frame "has no" actual header - PICTURE header is his header
+  if (gob->gobn == 0) {
+    guint shift;
+    GST_LOG_OBJECT (rtph263pay, "Initial GOB");
+    shift = 43;
+
+    boundry.ebit =
+        gst_rtp_h263_pay_move_window_right (rtph263pay, context, shift,
+        boundry.ebit, &boundry.end, &gob->end);
+
+    //We need PQUANT for mode B packages - so we store it
+    gob->quant = context->window >> 27;
+
+    //if PCM == 1, then PSBI is present - header has 51 bits
+    //shift for PQUANT (5) and PCM (1) = 6 bits
+    shift = 6;
+    if (context->cpm == 1)
+      shift += 2;
+    boundry.ebit =
+        gst_rtp_h263_pay_move_window_right (rtph263pay, context, shift,
+        boundry.ebit, &boundry.end, &gob->end);
+
+    GST_TRACE_OBJECT (rtph263pay, "window: 0x%08x", context->window);
+
+    //Shifting the PEI and PSPARE fields
+    while ((context->window & 0x80000000) == 0x80000000) {
+      boundry.ebit =
+          gst_rtp_h263_pay_move_window_right (rtph263pay, context, 9,
+          boundry.ebit, &boundry.end, &gob->end);
+      GST_TRACE_OBJECT (rtph263pay, "window: 0x%08x", context->window);
+    }
+
+    //shift the last PEI field
+    boundry.ebit =
+        gst_rtp_h263_pay_move_window_right (rtph263pay, context, 1,
+        boundry.ebit, &boundry.end, &gob->end);
+
+  } else {
+    //skipping GOBs 24 header bits + 5 GQUANT
+    guint shift = 24;
+
+    GST_TRACE_OBJECT (rtph263pay, "INTER GOB");
+
+    //if CPM == 1, there are 2 more bits in the header - GSBI header is 31 bits long
+    if (context->cpm == 1)
+      shift += 2;
+
+    GST_TRACE_OBJECT (rtph263pay, "window: 0x%08x", context->window);
+    boundry.ebit =
+        gst_rtp_h263_pay_move_window_right (rtph263pay, context, shift,
+        boundry.ebit, &boundry.end, &gob->end);
+
+    //We need GQUANT for mode B packages - so we store it
+    gob->quant = context->window >> 27;
+
+    shift = 5;
+    boundry.ebit =
+        gst_rtp_h263_pay_move_window_right (rtph263pay, context, shift,
+        boundry.ebit, &boundry.end, &gob->end);
+
+    GST_TRACE_OBJECT (rtph263pay, "window: 0x%08x", context->window);
+  }
+
+  GST_TRACE_OBJECT (rtph263pay, "GQUANT IS: %08x", gob->quant);
+
+  // We are on MB layer
+
+  mac = mac0 = gst_rtp_h263_pay_mb_new (&boundry, 0);
+  for (mb = 0; mb < format_props[context->piclayer->ptype_srcformat][1]; mb++) {
+
+    GST_TRACE_OBJECT (rtph263pay,
+        "================ START MB %d =================", mb);
+
+    //Find next macroblock boundaries
+    ebit = mac->ebit;
+    if (!(mac =
+            gst_rtp_h263_pay_B_mbfinder (rtph263pay, context, gob, mac, mb))) {
+
+      GST_LOG_OBJECT (rtph263pay, "Error decoding MB - sbit: %d", 8 - ebit);
+      GST_ERROR_OBJECT (rtph263pay, "Error decoding in GOB");
+
+      gst_rtp_h263_pay_mb_destroy (mac0);
+      goto decode_error;
+    }
+
+    /* Store macroblock for further processing and delete old MB if any */
+    gst_rtp_h263_pay_mb_destroy (gob->macroblocks[mb]);
+    gob->macroblocks[mb] = mac;
+
+    //If mb_type == stuffing, don't increment the mb address
+    if (mac->mb_type == 10) {
+      mb--;
+      continue;
+    } else {
+      gob->nmacroblocs++;
+    }
+
+    if (mac->end >= gob->end) {
+      GST_LOG_OBJECT (rtph263pay, "No more MBs in this GOB");
+      if (!mac->ebit) {
+        mac->end--;
+      }
+      gob->end = mac->end;
+      break;
+    }
+    GST_DEBUG_OBJECT (rtph263pay,
+        "Found MB: mba: %d start: %p end: %p len: %d sbit: %d ebit: %d",
+        mac->mba, mac->start, mac->end, mac->length, mac->sbit, mac->ebit);
+    GST_TRACE_OBJECT (rtph263pay,
+        "================ END MB %d =================", mb);
+  }
+  gst_rtp_h263_pay_mb_destroy (mac0);
+
+  mb = 0;
+  first = 0;
+  payload_len = boundry.end - boundry.start + 1;
+  GST_DEBUG_OBJECT (rtph263pay,
+      "------------------------- NEW PACKAGE ----------------------");
+  while (mb < gob->nmacroblocs) {
+    if (payload_len + gob->macroblocks[mb]->length < max_payload_size) {
+
+      //FIXME: payload_len is not the real length -> ignoring sbit/ebit
+      payload_len += gob->macroblocks[mb]->length;
+      mb++;
+
+    } else {
+      //FIXME: we should include the last few bits of the GOB in the package - do we do that now?
+      //GST_DEBUG_OBJECT (rtph263pay, "Pushing GOBS %d to %d because payload size is %d", first,
+      //    first == mb - 1, payload_len);
+
+      // FIXME: segfault if mb == 0 (first MB is larger than max_payload_size)
+      GST_DEBUG_OBJECT (rtph263pay, "Push B mode fragment from mb %d to %d",
+          first, mb - 1);
+      if (gst_rtp_h263_pay_B_fragment_push (rtph263pay, context, gob, first,
+              mb - 1, &boundry)) {
+        GST_ERROR_OBJECT (rtph263pay, "Oooops, there was an error sending");
+        goto decode_error;
+      }
+
+      payload_len = 0;
+      first = mb;
+      GST_DEBUG_OBJECT (rtph263pay,
+          "------------------------- END PACKAGE ----------------------");
+      GST_DEBUG_OBJECT (rtph263pay,
+          "------------------------- NEW PACKAGE ----------------------");
+    }
+  }
+
+  /* Push rest */
+  GST_DEBUG_OBJECT (rtph263pay, "Remainder first: %d, MB: %d", first, mb);
+  if (payload_len != 0) {
+    GST_DEBUG_OBJECT (rtph263pay, "Push B mode fragment from mb %d to %d",
+        first, mb - 1);
+    if (gst_rtp_h263_pay_B_fragment_push (rtph263pay, context, gob, first,
+            mb - 1, &boundry)) {
+      GST_ERROR_OBJECT (rtph263pay, "Oooops, there was an error sending!");
+      goto decode_error;
+    }
+  }
+
+    /*---------- END OF MODE B FRAGMENTATION ----------*/
+
+  return TRUE;
+
+decode_error:
+  return FALSE;
+}
+
+static GstFlowReturn
+gst_rtp_h263_send_entire_frame (GstRtpH263Pay * rtph263pay,
+    GstRtpH263PayContext * context)
+{
+  GstRtpH263PayPackage *pack;
+  pack =
+      gst_rtp_h263_pay_package_new (rtph263pay->data,
+      rtph263pay->data + rtph263pay->available_data,
+      rtph263pay->available_data, 0, 0, NULL, TRUE);
+  pack->mode = GST_RTP_H263_PAYLOAD_HEADER_MODE_A;
+
+  GST_DEBUG_OBJECT (rtph263pay, "Available data: %d",
+      rtph263pay->available_data);
+
+  pack->outbuf =
+      gst_rtp_buffer_new_allocate (GST_RTP_H263_PAYLOAD_HEADER_MODE_A, 0, 0);
+
+  return gst_rtp_h263_pay_push (rtph263pay, context, pack);
+}
+
+static GstFlowReturn
+gst_rtp_h263_pay_flush (GstRtpH263Pay * rtph263pay)
+{
+
+  /*
+   * FIXME: GSTUF bits are ignored right now,
+   *  - not using EBIT/SBIT payload header fields in mode A fragmentation - ffmpeg doesn't need them, but others?
+   */
+
+  GstFlowReturn ret;
+  GstRtpH263PayContext *context;
+  gint i;
+
+  ret = 0;
+  context = (GstRtpH263PayContext *) g_malloc0 (sizeof (GstRtpH263PayContext));
+  context->mtu =
+      rtph263pay->payload.mtu - (MTU_SECURITY_OFFSET + GST_RTP_HEADER_LEN +
+      GST_RTP_H263_PAYLOAD_HEADER_MODE_C);
+
+  GST_DEBUG_OBJECT (rtph263pay, "MTU: %d", context->mtu);
+  rtph263pay->available_data = gst_buffer_get_size (rtph263pay->current_buffer);
+  if (rtph263pay->available_data == 0) {
+    ret = GST_FLOW_OK;
+    goto end;
+  }
+
+  /* Get a pointer to all the data for the frame */
+  gst_buffer_map (rtph263pay->current_buffer, &rtph263pay->map, GST_MAP_READ);
+  rtph263pay->data = (guint8 *) rtph263pay->map.data;
+
+  /* Picture header */
+  context->piclayer = (GstRtpH263PayPic *) rtph263pay->data;
+
+  if (context->piclayer->ptype_pictype == 0)
+    GST_DEBUG_OBJECT (rtph263pay, "We got an I-frame");
+  else
+    GST_DEBUG_OBJECT (rtph263pay, "We got a P-frame");
+
+  context->cpm = rtph263pay->data[6] >> 7;
+
+  GST_DEBUG_OBJECT (rtph263pay, "CPM: %d", context->cpm);
+
+  GST_DEBUG_OBJECT (rtph263pay, "Payload length is: %d",
+      rtph263pay->available_data);
+
+  /*
+   * - MODE A - If normal, I and P frames,  -> mode A
+   *   - GOB layer fragmentation
+   * - MODE B - If normal, I and P frames, but GOBs > mtu
+   *   - MB layer fragmentation
+   * - MODE C - For P frames with PB option, but GOBs > mtu
+   *   - MB layer fragmentation
+   */
+  if (rtph263pay->available_data + GST_RTP_H263_PAYLOAD_HEADER_MODE_A +
+      GST_RTP_HEADER_LEN < context->mtu) {
+    ret = gst_rtp_h263_send_entire_frame (rtph263pay, context);
+  } else {
+
+      /*---------- FRAGMENTING THE FRAME BECAUSE TOO LARGE TO FIT IN MTU ----------*/
+    GstRtpH263PayBoundry bound;
+    gint first;
+    guint payload_len;
+    gboolean forcea = FALSE;
+
+    GST_DEBUG_OBJECT (rtph263pay, "Frame too large for MTU");
+    /*
+     * Let's go trough all the data and fragment it untill end is reached
+     */
+
+    gst_rtp_h263_pay_boundry_init (&bound, NULL, rtph263pay->data - 1, 0, 0);
+    context->gobs =
+        (GstRtpH263PayGob **) g_malloc0 (format_props[context->piclayer->
+            ptype_srcformat][0] * sizeof (GstRtpH263PayGob *));
+
+
+    for (i = 0; i < format_props[context->piclayer->ptype_srcformat][0]; i++) {
+      GST_DEBUG_OBJECT (rtph263pay, "Searching for gob %d", i);
+      if (!gst_rtp_h263_pay_gobfinder (rtph263pay, &bound)) {
+        if (i <= 1) {
+          GST_WARNING_OBJECT (rtph263pay,
+              "No GOB's were found in data stream! Please enable RTP mode in encoder. Forcing mode A for now.");
+          ret = gst_rtp_h263_send_entire_frame (rtph263pay, context);
+          goto end;
+        } else {
+          /* try to send fragments corresponding to found GOBs */
+          forcea = TRUE;
+          break;
+        }
+      }
+
+      context->gobs[i] = gst_rtp_h263_pay_gob_new (&bound, i);
+      //FIXME - encoders may generate an EOS gob that has to be processed
+      GST_DEBUG_OBJECT (rtph263pay,
+          "Gob values are: gobn: %d, start: %p len: %d ebit: %d sbit: %d", i,
+          context->gobs[i]->start, context->gobs[i]->length,
+          context->gobs[i]->ebit, context->gobs[i]->sbit);
+    }
+    /* NOTE some places may still assume this to be the max possible */
+    context->no_gobs = i;
+    GST_DEBUG_OBJECT (rtph263pay, "Found %d GOBS of maximum %d",
+        context->no_gobs, format_props[context->piclayer->ptype_srcformat][0]);
+
+    // Make packages smaller than MTU
+    //   A mode
+    // - if ( GOB > MTU) -> B mode || C mode
+    //   Push packages
+
+    first = 0;
+    payload_len = 0;
+    i = 0;
+    while (i < context->no_gobs) {
+
+      if (context->gobs[i]->length >= context->mtu) {
+        if (payload_len == 0) {
+
+          GST_DEBUG_OBJECT (rtph263pay, "GOB len > MTU");
+          if (rtph263pay->prop_payload_mode || forcea) {
+            payload_len = context->gobs[i]->length;
+            goto force_a;
+          }
+          if (!context->piclayer->ptype_pbmode) {
+            GST_DEBUG_OBJECT (rtph263pay, "MODE B on GOB %d needed", i);
+            if (!gst_rtp_h263_pay_mode_B_fragment (rtph263pay, context,
+                    context->gobs[i])) {
+              GST_ERROR_OBJECT (rtph263pay,
+                  "There was an error fragmenting in mode B");
+              ret = GST_FLOW_ERROR;
+              goto end;
+            }
+          } else {
+            //IMPLEMENT C mode
+            GST_ERROR_OBJECT (rtph263pay,
+                "MODE C on GOB %d needed, but not supported yet", i);
+            /*if(!gst_rtp_h263_pay_mode_C_fragment(rtph263pay, context, context->gobs[i])) {
+               ret = GST_FLOW_OK;
+               GST_ERROR("There was an error fragmenting in mode C");
+               goto decode_error;
+               } */
+            goto decode_error;
+          }
+        decode_error:
+          i++;
+          first = i;
+          continue;
+
+        } else {
+          goto payload_a_push;
+        }
+      }
+
+      if (payload_len + context->gobs[i]->length < context->mtu) {
+        GST_DEBUG_OBJECT (rtph263pay, "GOB %d fills mtu", i);
+        payload_len += context->gobs[i]->length;
+        i++;
+        if (i == context->no_gobs) {
+          GST_DEBUG_OBJECT (rtph263pay, "LAST GOB %d", i);
+          goto payload_a_push;
+        }
+
+      } else {
+      payload_a_push:
+        GST_DEBUG_OBJECT (rtph263pay,
+            "Pushing GOBS %d to %d because payload size is %d", first,
+            first == i ? i : i - 1, payload_len);
+        gst_rtp_h263_pay_A_fragment_push (rtph263pay, context, first,
+            first == i ? i : i - 1);
+        payload_len = 0;
+        first = i;
+      }
+      continue;
+
+    force_a:
+      GST_DEBUG_OBJECT (rtph263pay,
+          "Pushing GOBS %d to %d because payload size is %d", first, i,
+          payload_len);
+      gst_rtp_h263_pay_A_fragment_push (rtph263pay, context, first, i);
+      payload_len = 0;
+      i++;
+      first = i;
+    }
+
+
+  }/*---------- END OF FRAGMENTATION ----------*/
+
+  /* Flush the input buffer data */
+
+end:
+  gst_rtp_h263_pay_context_destroy (context,
+      context->piclayer->ptype_srcformat);
+  gst_buffer_unmap (rtph263pay->current_buffer, &rtph263pay->map);
+  gst_buffer_replace (&rtph263pay->current_buffer, NULL);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_rtp_h263_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
+{
+
+  GstRtpH263Pay *rtph263pay;
+  GstFlowReturn ret;
+
+  rtph263pay = GST_RTP_H263_PAY (payload);
+  GST_DEBUG_OBJECT (rtph263pay,
+      "-------------------- NEW FRAME ---------------");
+
+  rtph263pay->first_ts = GST_BUFFER_PTS (buffer);
+
+  gst_buffer_replace (&rtph263pay->current_buffer, buffer);
+  gst_buffer_unref (buffer);
+
+  /* we always encode and flush a full picture */
+  ret = gst_rtp_h263_pay_flush (rtph263pay);
+  GST_DEBUG_OBJECT (rtph263pay,
+      "-------------------- END FRAME ---------------");
+
+  return ret;
+}
+
+gboolean
+gst_rtp_h263_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtph263pay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_H263_PAY);
+}
diff --git a/gst/rtp/gstrtph263pay.h b/gst/rtp/gstrtph263pay.h
new file mode 100644
index 0000000..2abfc87
--- /dev/null
+++ b/gst/rtp/gstrtph263pay.h
@@ -0,0 +1,415 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Dejan Sakelsak sahel@kiberpipa.org
+ */
+
+#ifndef __GST_RTP_H263_PAY_H__
+#define __GST_RTP_H263_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_H263_PAY \
+  (gst_rtp_h263_pay_get_type())
+#define GST_RTP_H263_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H263_PAY,GstRtpH263Pay))
+#define GST_RTP_H263_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H263_PAY,GstRtpH263PayClass))
+#define GST_IS_RTP_H263_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H263_PAY))
+#define GST_IS_RTP_H263_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H263_PAY))
+// blocks per macroblock
+#define N_BLOCKS 6
+#define DEFAULT_MODE_A FALSE
+#define MTU_SECURITY_OFFSET 50
+    typedef enum _GstRtpH263PayHeaderMode
+{
+  GST_RTP_H263_PAYLOAD_HEADER_MODE_A = 4,
+  GST_RTP_H263_PAYLOAD_HEADER_MODE_B = 8,
+  GST_RTP_H263_PAYLOAD_HEADER_MODE_C = 12
+} GstRtpH263PayHeaderMode;
+
+typedef struct _GstRtpH263PayContext GstRtpH263PayContext;
+typedef struct _GstRtpH263PayPic GstRtpH263PayPic;
+typedef struct _GstRtpH263PayClass GstRtpH263PayClass;
+typedef struct _GstRtpH263Pay GstRtpH263Pay;
+typedef struct _GstRtpH263PayBoundry GstRtpH263PayBoundry;
+typedef struct _GstRtpH263PayMB GstRtpH263PayMB;
+typedef struct _GstRtpH263PayGob GstRtpH263PayGob;
+typedef struct _GstRtpH263PayPackage GstRtpH263PayPackage;
+
+//typedef enum _GstRtpH263PayHeaderMode GstRtpH263PayHeaderMode;
+
+struct _GstRtpH263Pay
+{
+  GstRTPBasePayload payload;
+
+  GstBuffer *current_buffer;
+  GstMapInfo map;
+
+  GstClockTime first_ts;
+  gboolean prop_payload_mode;
+  guint8 *data;
+  guint available_data;
+
+};
+
+struct _GstRtpH263PayContext
+{
+  GstRtpH263PayPic *piclayer;
+
+  guint mtu;
+  guint window;
+  guint8 *win_end;
+  guint8 cpm;
+
+  guint no_gobs;
+  GstRtpH263PayGob **gobs;
+
+};
+
+struct _GstRtpH263PayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+typedef struct _GstRtpH263PayAHeader
+{
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+  unsigned int ebit:3;          /* End position */
+  unsigned int sbit:3;          /* Start position */
+  unsigned int p:1;             /* PB-frames mode */
+  unsigned int f:1;             /* flag bit */
+
+  unsigned int r1:1;            /* Reserved */
+  unsigned int a:1;             /* Advanced Prediction */
+  unsigned int s:1;             /* syntax based arithmetic coding */
+  unsigned int u:1;             /* Unrestricted motion vector */
+  unsigned int i:1;             /* Picture coding type */
+  unsigned int src:3;           /* Source format */
+
+  unsigned int trb:3;           /* Temporal ref for B frame */
+  unsigned int dbq:2;           /* Differential Quantisation parameter */
+  unsigned int r2:3;            /* Reserved */
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+  unsigned int f:1;             /* flag bit */
+  unsigned int p:1;             /* PB-frames mode */
+  unsigned int sbit:3;          /* Start position */
+  unsigned int ebit:3;          /* End position */
+
+  unsigned int src:3;           /* Source format */
+  unsigned int i:1;             /* Picture coding type */
+  unsigned int u:1;             /* Unrestricted motion vector */
+  unsigned int s:1;             /* syntax based arithmetic coding */
+  unsigned int a:1;             /* Advanced Prediction */
+  unsigned int r1:1;            /* Reserved */
+
+  unsigned int r2:3;            /* Reserved */
+  unsigned int dbq:2;           /* Differential Quantisation parameter */
+  unsigned int trb:3;           /* Temporal ref for B frame */
+#else
+#error "G_BYTE_ORDER should be big or little endian."
+#endif
+  unsigned int tr:8;            /* Temporal ref for P frame */
+} GstRtpH263PayAHeader;
+
+typedef struct _GstRtpH263PayBHeader
+{
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+  unsigned int ebit:3;          /* End position */
+  unsigned int sbit:3;          /* Start position */
+  unsigned int p:1;             /* PB-frames mode */
+  unsigned int f:1;             /* flag bit */
+
+  unsigned int quant:5;         /* Quantization value for first MB */
+  unsigned int src:3;           /* Source format */
+
+  unsigned int mba1:3;          /* Address of first MB starting count from 0 - part1 */
+  unsigned int gobn:5;          /* GOB number in effect at start of packet */
+
+  unsigned int r:2;             /* Reserved */
+  unsigned int mba2:6;          /* Address of first MB starting count from 0 - part2 */
+
+  unsigned int hmv11:4;         /* horizontal motion vector predictor for MB 1 - part 1 */
+  unsigned int a:1;             /* Advanced Prediction */
+  unsigned int s:1;             /* syntax based arithmetic coding */
+  unsigned int u:1;             /* Unrestricted motion vector */
+  unsigned int i:1;             /* Picture coding type */
+
+  unsigned int vmv11:5;         /* vertical motion vector predictor for MB 1 - part 1 */
+  unsigned int hmv12:3;         /* horizontal motion vector predictor for MB 1 - part 2 */
+
+  unsigned int hmv21:6;         /* horizontal motion vector predictor for MB 3 - part 1 */
+  unsigned int vmv12:2;         /* vertical motion vector predictor for MB 1 - part 2 */
+
+  unsigned int vmv21:7;         /* vertical motion vector predictor for MB 3 */
+  unsigned int hmv22:1;         /* horizontal motion vector predictor for MB 3 - part 2 */
+
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+  unsigned int f:1;             /* flag bit */
+  unsigned int p:1;             /* PB-frames mode */
+  unsigned int sbit:3;          /* Start position */
+  unsigned int ebit:3;          /* End position */
+
+  unsigned int src:3;           /* Source format */
+  unsigned int quant:5;         /* Quantization value for first MB */
+
+  unsigned int gobn:5;          /* GOB number in effect at start of packet */
+  unsigned int mba1:3;          /* Address of first MB starting count from 0 - part1 */
+
+  unsigned int mba2:6;          /* Address of first MB starting count from 0 - part2 */
+  unsigned int r:2;             /* Reserved */
+
+  unsigned int i:1;             /* Picture coding type */
+  unsigned int u:1;             /* Unrestricted motion vector */
+  unsigned int s:1;             /* syntax based arithmetic coding */
+  unsigned int a:1;             /* Advanced Prediction */
+  unsigned int hmv11:4;         /* horizontal motion vector predictor for MB 1 - part 1 */
+
+  unsigned int hmv12:3;         /* horizontal motion vector predictor for MB 1 - part 2 */
+  unsigned int vmv11:5;         /* vertical motion vector predictor for MB 1 - part 1 */
+
+  unsigned int vmv12:2;         /* vertical motion vector predictor for MB 1 - part 2 */
+  unsigned int hmv21:6;         /* horizontal motion vector predictor for MB 3 - part 1 */
+
+  unsigned int hmv22:1;         /* horizontal motion vector predictor for MB 3 - part 2 */
+  unsigned int vmv21:7;          /* vertical motion vector predictor for MB 3 */
+#else
+#error "G_BYTE_ORDER should be big or little endian."
+#endif
+} GstRtpH263PayBHeader;
+
+typedef struct _GstRtpH263PayCHeader
+{
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+  unsigned int ebit:3;          /* End position */
+  unsigned int sbit:3;          /* Start position */
+  unsigned int p:1;             /* PB-frames mode */
+  unsigned int f:1;             /* flag bit */
+
+  unsigned int quant:5;         /* Quantization value for first MB */
+  unsigned int src:3;           /* Source format */
+
+  unsigned int mba1:3;          /* Address of first MB starting count from 0 - part1 */
+  unsigned int gobn:5;          /* GOB number in effect at start of packet */
+
+  unsigned int r:2;             /* Reserved */
+  unsigned int mba2:6;          /* Address of first MB starting count from 0 - part2 */
+
+  unsigned int hmv11:4;         /* horizontal motion vector predictor for MB 1 - part 1 */
+  unsigned int a:1;             /* Advanced Prediction */
+  unsigned int s:1;             /* syntax based arithmetic coding */
+  unsigned int u:1;             /* Unrestricted motion vector */
+  unsigned int i:1;             /* Picture coding type */
+
+  unsigned int vmv11:5;         /* vertical motion vector predictor for MB 1 - part 1 */
+  unsigned int hmv12:3;         /* horizontal motion vector predictor for MB 1 - part 2 */
+
+  unsigned int hmv21:6;         /* horizontal motion vector predictor for MB 3 - part 1 */
+  unsigned int vmv12:2;         /* vertical motion vector predictor for MB 1 - part 2 */
+
+  unsigned int vmv21:7;         /* vertical motion vector predictor for MB 3 */
+  unsigned int hmv22:1;         /* horizontal motion vector predictor for MB 3 - part 2 */
+
+  unsigned int rr1:8;           /* reserved */
+
+  unsigned int rr2:8;           /* reserved */
+
+  unsigned int trb:3;           /* Temporal Reference for the B */
+  unsigned int dbq:2;           /* Differential quantization parameter */
+  unsigned int rr3:3;           /* reserved */
+
+  unsigned int tr:8;            /* Temporal Reference for the P frame */
+
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+  unsigned int f:1;             /* flag bit */
+  unsigned int p:1;             /* PB-frames mode */
+  unsigned int sbit:3;          /* Start position */
+  unsigned int ebit:3;          /* End position */
+
+  unsigned int src:3;           /* Source format */
+  unsigned int quant:5;         /* Quantization value for first MB */
+
+  unsigned int gobn:5;          /* GOB number in effect at start of packet */
+  unsigned int mba1:3;          /* Address of first MB starting count from 0 - part1 */
+
+  unsigned int mba2:6;          /* Address of first MB starting count from 0 - part2 */
+  unsigned int r:2;             /* Reserved */
+
+  unsigned int i:1;             /* Picture coding type */
+  unsigned int u:1;             /* Unrestricted motion vector */
+  unsigned int s:1;             /* syntax based arithmetic coding */
+  unsigned int a:1;             /* Advanced Prediction */
+  unsigned int hmv11:4;         /* horizontal motion vector predictor for MB 1 - part 1 */
+
+  unsigned int hmv12:3;         /* horizontal motion vector predictor for MB 1 - part 2 */
+  unsigned int vmv11:5;         /* vertical motion vector predictor for MB 1 - part 1 */
+
+  unsigned int vmv12:2;         /* vertical motion vector predictor for MB 1 - part 2 */
+  unsigned int hmv21:6;         /* horizontal motion vector predictor for MB 3 - part 1 */
+
+  unsigned int hmv22:1;         /* horizontal motion vector predictor for MB 3 - part 2 */
+  unsigned int vmv21:7;          /* vertical motion vector predictor for MB 3 */
+  unsigned int rr1:8;           /* reserved */
+  unsigned int rr2:8;           /* reserved */
+
+  unsigned int rr3:3;           /* reserved */
+  unsigned int dbq:2;           /* Differential quantization parameter */
+  unsigned int trb:3;           /* Temporal Reference for the B */
+
+  unsigned int tr:8;            /* Temporal Reference for the P frame */
+#else
+#error "G_BYTE_ORDER should be big or little endian."
+#endif
+} GstRtpH263PayCHeader;
+
+struct _GstRtpH263PayPic
+{
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+  unsigned int psc1:16;
+
+  unsigned int tr1:2;
+  unsigned int psc2:6;
+
+  unsigned int ptype_263:1;
+  unsigned int ptype_start:1;
+  unsigned int tr2:6;
+
+  unsigned int ptype_umvmode:1;
+  unsigned int ptype_pictype:1;
+  unsigned int ptype_srcformat:3;
+  unsigned int ptype_freeze:1;
+  unsigned int ptype_camera:1;
+  unsigned int ptype_split:1;
+
+  unsigned int pquant:5;
+  unsigned int ptype_pbmode:1;
+  unsigned int ptype_apmode:1;
+  unsigned int ptype_sacmode:1;
+
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+  unsigned int psc1:16;
+
+  unsigned int psc2:6;
+  unsigned int tr1:2;
+
+  unsigned int tr2:6;
+  unsigned int ptype_start:2;
+
+  unsigned int ptype_split:1;
+  unsigned int ptype_camera:1;
+  unsigned int ptype_freeze:1;
+  unsigned int ptype_srcformat:3;
+  unsigned int ptype_pictype:1;
+  unsigned int ptype_umvmode:1;
+
+  unsigned int ptype_sacmode:1;
+  unsigned int ptype_apmode:1;
+  unsigned int ptype_pbmode:1;
+  unsigned int pquant:5;
+
+#else
+#error "G_BYTE_ORDER should be big or little endian."
+#endif
+};
+
+struct _GstRtpH263PayBoundry
+{
+
+  guint8 *start;
+  guint8 *end;
+  guint8 sbit;
+  guint8 ebit;
+
+};
+
+struct _GstRtpH263PayMB
+{
+  guint8 *start;
+  guint8 *end;
+  guint8 sbit;
+  guint8 ebit;
+  guint length;
+
+  guint8 mb_type;
+  guint quant;
+
+  guint mba;
+  guint8 mvd[10];
+};
+
+struct _GstRtpH263PayGob
+{
+  guint8 *start;
+  guint8 *end;
+  guint length;
+  guint8 sbit;
+  guint8 ebit;
+
+  guint gobn;
+  guint quant;
+
+  GstRtpH263PayMB **macroblocks;
+  guint nmacroblocs;
+};
+
+struct _GstRtpH263PayPackage
+{
+  guint8 *payload_start;
+  guint8 *payload_end;
+  guint payload_len;
+  guint8 sbit;
+  guint8 ebit;
+  GstBuffer *outbuf;
+  gboolean marker;
+
+  GstRtpH263PayHeaderMode mode;
+
+  /*
+   *  mode B,C data
+   */
+
+  guint16 mba;
+  guint nmvd;
+  guint8 mvd[10];
+  guint gobn;
+  guint quant;
+};
+
+#define GST_H263_PICTURELAYER_PLSRC(buf) (((GstRtpH263PayPic *)(buf))->ptype_srcformat)
+#define GST_H263_PICTURELAYER_PLTYPE(buf) (((GstRtpH263PayPic *)(buf))->ptype_pictype)
+#define GST_H263_PICTURELAYER_PLUMV(buf) (((GstRtpH263PayPic *)(buf))->ptype_umvmode)
+#define GST_H263_PICTURELAYER_PLSAC(buf) (((GstRtpH263PayPic *)(buf))->ptype_sacmode)
+#define GST_H263_PICTURELAYER_PLAP(buf) (((GstRtpH263PayPic *)(buf))->ptype_apmode)
+
+/*
+ * TODO: PB frame relevant tables
+ */
+
+#define GST_RTP_H263_PAY_END(start, len) (((guint8 *)start) + ((guint)len))
+#define GST_RTP_H263_PAY_GOBN(gob) (((((guint8 *) gob)[2] >> 2) & 0x1f)
+
+GType gst_rtp_h263_pay_get_type (void);
+
+gboolean gst_rtp_h263_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_H263_PAY_H__ */
diff --git a/gst/rtp/gstrtph263pdepay.c b/gst/rtp/gstrtph263pdepay.c
new file mode 100644
index 0000000..a1fc40c
--- /dev/null
+++ b/gst/rtp/gstrtph263pdepay.c
@@ -0,0 +1,403 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+#include "gstrtph263pdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtph263pdepay_debug);
+#define GST_CAT_DEFAULT (rtph263pdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_h263p_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-h263, " "variant = (string) \"itu\" ")
+    );
+
+static GstStaticPadTemplate gst_rtp_h263p_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "clock-rate = (int) [1, MAX], "
+        "encoding-name = (string) \"H263-1998\"; "
+        /* optional params */
+        /* NOTE all optional SDP params must be strings in the caps */
+        /*
+           "sqcif = (string) [1, 32], "
+           "qcif = (string) [1, 32], "
+           "cif = (string) [1, 32], "
+           "cif4 = (string) [1, 32], "
+           "cif16 = (string) [1, 32], "
+           "custom = (string) ANY, "
+           "f = (string) {0, 1},"
+           "i = (string) {0, 1},"
+           "j = (string) {0, 1},"
+           "t = (string) {0, 1},"
+           "k = (string) {1, 2, 3, 4},"
+           "n = (string) {1, 2, 3, 4},"
+           "p = (string) ANY,"
+           "par = (string) ANY, "
+           "cpcf = (string) ANY, "
+           "bpp = (string) [0, 65536], "
+           "hrd = (string) {0, 1}; "
+         */
+        "application/x-rtp, "
+        "media = (string) \"video\", "
+        "clock-rate = (int) [1, MAX], "
+        "encoding-name = (string) \"H263-2000\" "
+        /* optional params */
+        /* NOTE all optional SDP params must be strings in the caps */
+        /*
+           "profile = (string) [0, 10], "
+           "level = (string) {10, 20, 30, 40, 45, 50, 60, 70}, "
+           "interlace = (string) {0, 1};"
+         */
+    )
+    );
+
+#define gst_rtp_h263p_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpH263PDepay, gst_rtp_h263p_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_h263p_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_h263p_depay_change_state (GstElement *
+    element, GstStateChange transition);
+
+static GstBuffer *gst_rtp_h263p_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+gboolean gst_rtp_h263p_depay_setcaps (GstRTPBaseDepayload * filter,
+    GstCaps * caps);
+
+static void
+gst_rtp_h263p_depay_class_init (GstRtpH263PDepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_h263p_depay_finalize;
+
+  gstelement_class->change_state = gst_rtp_h263p_depay_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h263p_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h263p_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP H263 depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts H263/+/++ video from RTP packets (RFC 4629)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_h263p_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_h263p_depay_setcaps;
+
+  GST_DEBUG_CATEGORY_INIT (rtph263pdepay_debug, "rtph263pdepay", 0,
+      "H263+ Video RTP Depayloader");
+}
+
+static void
+gst_rtp_h263p_depay_init (GstRtpH263PDepay * rtph263pdepay)
+{
+  rtph263pdepay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_h263p_depay_finalize (GObject * object)
+{
+  GstRtpH263PDepay *rtph263pdepay;
+
+  rtph263pdepay = GST_RTP_H263P_DEPAY (object);
+
+  g_object_unref (rtph263pdepay->adapter);
+  rtph263pdepay->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+gboolean
+gst_rtp_h263p_depay_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps)
+{
+  GstCaps *srccaps = NULL;
+  GstStructure *structure = gst_caps_get_structure (caps, 0);
+  gint clock_rate;
+  const gchar *encoding_name = NULL;
+  gboolean res;
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;         /* default */
+  filter->clock_rate = clock_rate;
+
+  encoding_name = gst_structure_get_string (structure, "encoding-name");
+  if (encoding_name == NULL)
+    goto no_encoding_name;
+
+  if (g_ascii_strcasecmp (encoding_name, "H263-2000") == 0) {
+    /* always h263++ */
+    srccaps = gst_caps_new_simple ("video/x-h263",
+        "variant", G_TYPE_STRING, "itu",
+        "h263version", G_TYPE_STRING, "h263pp", NULL);
+  } else if (g_ascii_strcasecmp (encoding_name, "H263-1998") == 0) {
+    /* this can be H263 or H263+ depending on defined appendixes in the optional
+     * SDP params */
+    const gchar *F, *I, *J, *T, *K, *N, *P;
+    gboolean is_h263p = FALSE;
+
+    F = gst_structure_get_string (structure, "f");
+    if (F)
+      if (g_ascii_strcasecmp (F, "1") == 0)
+        is_h263p = TRUE;
+    I = gst_structure_get_string (structure, "i");
+    if (I)
+      if (g_ascii_strcasecmp (I, "1") == 0)
+        is_h263p = TRUE;
+    J = gst_structure_get_string (structure, "j");
+    if (J)
+      if (g_ascii_strcasecmp (J, "1") == 0)
+        is_h263p = TRUE;
+    T = gst_structure_get_string (structure, "t");
+    if (T)
+      if (g_ascii_strcasecmp (T, "1") == 0)
+        is_h263p = TRUE;
+    K = gst_structure_get_string (structure, "k");
+    if (K)
+      is_h263p = TRUE;
+    N = gst_structure_get_string (structure, "n");
+    if (N)
+      is_h263p = TRUE;
+    P = gst_structure_get_string (structure, "p");
+    if (P)
+      is_h263p = TRUE;
+
+    if (is_h263p) {
+      srccaps = gst_caps_new_simple ("video/x-h263",
+          "variant", G_TYPE_STRING, "itu",
+          "h263version", G_TYPE_STRING, "h263p", NULL);
+    } else {
+      srccaps = gst_caps_new_simple ("video/x-h263",
+          "variant", G_TYPE_STRING, "itu",
+          "h263version", G_TYPE_STRING, "h263", NULL);
+    }
+  }
+  if (!srccaps)
+    goto no_caps;
+
+  res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (filter), srccaps);
+  gst_caps_unref (srccaps);
+
+  return res;
+
+  /* ERRORS */
+no_encoding_name:
+  {
+    GST_ERROR_OBJECT (filter, "no encoding-name");
+    return FALSE;
+  }
+no_caps:
+  {
+    GST_ERROR_OBJECT (filter, "invalid encoding-name");
+    return FALSE;
+  }
+}
+
+static GstBuffer *
+gst_rtp_h263p_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp)
+{
+  GstRtpH263PDepay *rtph263pdepay;
+  GstBuffer *outbuf;
+  gint payload_len;
+  guint8 *payload;
+  gboolean P, V, M;
+  guint header_len;
+  guint8 PLEN, PEBIT;
+
+  rtph263pdepay = GST_RTP_H263P_DEPAY (depayload);
+
+  /* flush remaining data on discont */
+  if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
+    GST_LOG_OBJECT (depayload, "DISCONT, flushing adapter");
+    gst_adapter_clear (rtph263pdepay->adapter);
+    rtph263pdepay->wait_start = TRUE;
+  }
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+  header_len = 2;
+
+  if (payload_len < header_len)
+    goto too_small;
+
+  payload = gst_rtp_buffer_get_payload (rtp);
+
+  M = gst_rtp_buffer_get_marker (rtp);
+
+  /*  0                   1
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |   RR    |P|V|   PLEN    |PEBIT|
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   */
+  P = (payload[0] & 0x04) == 0x04;
+  V = (payload[0] & 0x02) == 0x02;
+  PLEN = ((payload[0] & 0x1) << 5) | (payload[1] >> 3);
+  PEBIT = payload[1] & 0x7;
+
+  GST_LOG_OBJECT (depayload, "P %d, V %d, PLEN %d, PEBIT %d", P, V, PLEN,
+      PEBIT);
+
+  if (V) {
+    header_len++;
+  }
+  if (PLEN) {
+    header_len += PLEN;
+  }
+
+  if ((!P && payload_len < header_len) || (P && payload_len < header_len - 2))
+    goto too_small;
+
+  if (P) {
+    rtph263pdepay->wait_start = FALSE;
+    header_len -= 2;
+  }
+
+  if (rtph263pdepay->wait_start)
+    goto waiting_start;
+
+  if (payload_len < header_len)
+    goto too_small;
+
+  /* FIXME do not ignore the VRC header (See RFC 2429 section 4.2) */
+  /* FIXME actually use the RTP picture header when it is lost in the network */
+  /* for now strip off header */
+  payload_len -= header_len;
+
+  if (M) {
+    /* frame is completed: append to previous, push it out */
+    guint len, padlen;
+    guint avail;
+    GstBuffer *padbuf;
+
+    GST_LOG_OBJECT (depayload, "Frame complete");
+
+    outbuf =
+        gst_rtp_buffer_get_payload_subbuffer (rtp, header_len, payload_len);
+    if (P)
+      gst_buffer_memset (outbuf, 0, 0, 2);
+    gst_adapter_push (rtph263pdepay->adapter, outbuf);
+    outbuf = NULL;
+
+    avail = gst_adapter_available (rtph263pdepay->adapter);
+    len = avail + payload_len;
+    padlen = (len % 4) + 4;
+
+    if (avail == 0)
+      goto empty_frame;
+
+    outbuf = gst_adapter_take_buffer (rtph263pdepay->adapter, avail);
+    if (padlen) {
+      padbuf = gst_buffer_new_and_alloc (padlen);
+      gst_buffer_memset (padbuf, 0, 0, padlen);
+      outbuf = gst_buffer_append (outbuf, padbuf);
+    }
+
+    gst_rtp_drop_non_video_meta (rtph263pdepay, outbuf);
+
+    return outbuf;
+  } else {
+    /* frame not completed: store in adapter */
+    GST_LOG_OBJECT (depayload, "Frame incomplete, storing %d", payload_len);
+
+    outbuf =
+        gst_rtp_buffer_get_payload_subbuffer (rtp, header_len, payload_len);
+    if (P)
+      gst_buffer_memset (outbuf, 0, 0, 2);
+    gst_adapter_push (rtph263pdepay->adapter, outbuf);
+  }
+  return NULL;
+
+too_small:
+  {
+    GST_ELEMENT_WARNING (rtph263pdepay, STREAM, DECODE,
+        ("Packet payload was too small"), (NULL));
+    return NULL;
+  }
+waiting_start:
+  {
+    GST_DEBUG_OBJECT (rtph263pdepay, "waiting for picture start");
+    return NULL;
+  }
+empty_frame:
+  {
+    GST_WARNING_OBJECT (rtph263pdepay, "Depayloaded frame is empty, dropping");
+    return NULL;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_h263p_depay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpH263PDepay *rtph263pdepay;
+  GstStateChangeReturn ret;
+
+  rtph263pdepay = GST_RTP_H263P_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_adapter_clear (rtph263pdepay->adapter);
+      rtph263pdepay->wait_start = TRUE;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_h263p_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtph263pdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_H263P_DEPAY);
+}
diff --git a/gst/rtp/gstrtph263pdepay.h b/gst/rtp/gstrtph263pdepay.h
new file mode 100644
index 0000000..bbdb2b0
--- /dev/null
+++ b/gst/rtp/gstrtph263pdepay.h
@@ -0,0 +1,62 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_H263P_DEPAY_H__
+#define __GST_RTP_H263P_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_H263P_DEPAY \
+  (gst_rtp_h263p_depay_get_type())
+#define GST_RTP_H263P_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H263P_DEPAY,GstRtpH263PDepay))
+#define GST_RTP_H263P_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H263P_DEPAY,GstRtpH263PDepayClass))
+#define GST_IS_RTP_H263P_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H263P_DEPAY))
+#define GST_IS_RTP_H263P_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H263P_DEPAY))
+
+typedef struct _GstRtpH263PDepay GstRtpH263PDepay;
+typedef struct _GstRtpH263PDepayClass GstRtpH263PDepayClass;
+
+struct _GstRtpH263PDepay
+{
+  GstRTPBaseDepayload depayload;
+
+  GstAdapter *adapter;
+  gboolean    wait_start;
+};
+
+struct _GstRtpH263PDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_h263p_depay_get_type (void);
+
+gboolean gst_rtp_h263p_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_H263P_DEPAY_H__ */
diff --git a/gst/rtp/gstrtph263ppay.c b/gst/rtp/gstrtph263ppay.c
new file mode 100644
index 0000000..a73f00e
--- /dev/null
+++ b/gst/rtp/gstrtph263ppay.c
@@ -0,0 +1,814 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+
+#include "gstrtph263ppay.h"
+#include "gstrtputils.h"
+
+#define DEFAULT_FRAGMENTATION_MODE   GST_FRAGMENTATION_MODE_NORMAL
+
+enum
+{
+  PROP_0,
+  PROP_FRAGMENTATION_MODE
+};
+
+#define GST_TYPE_FRAGMENTATION_MODE (gst_fragmentation_mode_get_type())
+static GType
+gst_fragmentation_mode_get_type (void)
+{
+  static GType fragmentation_mode_type = 0;
+  static const GEnumValue fragmentation_mode[] = {
+    {GST_FRAGMENTATION_MODE_NORMAL, "Normal", "normal"},
+    {GST_FRAGMENTATION_MODE_SYNC, "Fragment at sync points", "sync"},
+    {0, NULL, NULL},
+  };
+
+  if (!fragmentation_mode_type) {
+    fragmentation_mode_type =
+        g_enum_register_static ("GstFragmentationMode", fragmentation_mode);
+  }
+  return fragmentation_mode_type;
+}
+
+
+GST_DEBUG_CATEGORY_STATIC (rtph263ppay_debug);
+#define GST_CAT_DEFAULT rtph263ppay_debug
+
+static GstStaticPadTemplate gst_rtp_h263p_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-h263, variant = (string) itu")
+    );
+
+/*
+ * We also return these in getcaps() as required by the SDP caps
+ *
+ * width = (int) [16, 4096]
+ * height = (int) [16, 4096]
+ * "annex-f = (boolean) {true, false},"
+ * "annex-i = (boolean) {true, false},"
+ * "annex-j = (boolean) {true, false},"
+ * "annex-l = (boolean) {true, false},"
+ * "annex-t = (boolean) {true, false},"
+ * "annex-v = (boolean) {true, false}")
+ */
+
+
+static GstStaticPadTemplate gst_rtp_h263p_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"H263-1998\"; "
+        "application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"H263-2000\"")
+    );
+
+static void gst_rtp_h263p_pay_finalize (GObject * object);
+
+static void gst_rtp_h263p_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_h263p_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_rtp_h263p_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static GstCaps *gst_rtp_h263p_pay_sink_getcaps (GstRTPBasePayload * payload,
+    GstPad * pad, GstCaps * filter);
+static GstFlowReturn gst_rtp_h263p_pay_handle_buffer (GstRTPBasePayload *
+    payload, GstBuffer * buffer);
+
+#define gst_rtp_h263p_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpH263PPay, gst_rtp_h263p_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_h263p_pay_class_init (GstRtpH263PPayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_h263p_pay_finalize;
+  gobject_class->set_property = gst_rtp_h263p_pay_set_property;
+  gobject_class->get_property = gst_rtp_h263p_pay_get_property;
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_h263p_pay_setcaps;
+  gstrtpbasepayload_class->get_caps = gst_rtp_h263p_pay_sink_getcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_h263p_pay_handle_buffer;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_FRAGMENTATION_MODE, g_param_spec_enum ("fragmentation-mode",
+          "Fragmentation Mode",
+          "Packet Fragmentation Mode", GST_TYPE_FRAGMENTATION_MODE,
+          DEFAULT_FRAGMENTATION_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h263p_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h263p_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP H263 payloader",
+      "Codec/Payloader/Network/RTP",
+      "Payload-encodes H263/+/++ video in RTP packets (RFC 4629)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtph263ppay_debug, "rtph263ppay",
+      0, "rtph263ppay (RFC 4629)");
+}
+
+static void
+gst_rtp_h263p_pay_init (GstRtpH263PPay * rtph263ppay)
+{
+  rtph263ppay->adapter = gst_adapter_new ();
+
+  rtph263ppay->fragmentation_mode = DEFAULT_FRAGMENTATION_MODE;
+}
+
+static void
+gst_rtp_h263p_pay_finalize (GObject * object)
+{
+  GstRtpH263PPay *rtph263ppay;
+
+  rtph263ppay = GST_RTP_H263P_PAY (object);
+
+  g_object_unref (rtph263ppay->adapter);
+  rtph263ppay->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_h263p_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  gboolean res;
+  GstCaps *peercaps;
+  gchar *encoding_name = NULL;
+
+  g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
+
+  peercaps =
+      gst_pad_peer_query_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), NULL);
+  if (peercaps) {
+    GstCaps *tcaps =
+        gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload));
+    GstCaps *intersect = gst_caps_intersect (peercaps, tcaps);
+    gst_caps_unref (tcaps);
+
+    gst_caps_unref (peercaps);
+    if (!gst_caps_is_empty (intersect)) {
+      GstStructure *s = gst_caps_get_structure (intersect, 0);
+      encoding_name = g_strdup (gst_structure_get_string (s, "encoding-name"));
+    }
+    gst_caps_unref (intersect);
+  }
+
+  if (!encoding_name)
+    encoding_name = g_strdup ("H263-1998");
+
+  gst_rtp_base_payload_set_options (payload, "video", TRUE,
+      (gchar *) encoding_name, 90000);
+  res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+  g_free (encoding_name);
+
+  return res;
+}
+
+static GstCaps *
+caps_append (GstCaps * caps, GstStructure * in_s, guint x, guint y, guint mpi)
+{
+  GstStructure *s;
+
+  if (!in_s)
+    return caps;
+
+  if (mpi < 1 || mpi > 32)
+    return caps;
+
+  s = gst_structure_copy (in_s);
+
+  gst_structure_set (s,
+      "width", GST_TYPE_INT_RANGE, 1, x,
+      "height", GST_TYPE_INT_RANGE, 1, y,
+      "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001 * mpi, NULL);
+
+  caps = gst_caps_merge_structure (caps, s);
+
+  return caps;
+}
+
+
+static GstCaps *
+gst_rtp_h263p_pay_sink_getcaps (GstRTPBasePayload * payload, GstPad * pad,
+    GstCaps * filter)
+{
+  GstRtpH263PPay *rtph263ppay;
+  GstCaps *caps = NULL, *templ;
+  GstCaps *peercaps = NULL;
+  GstCaps *intersect = NULL;
+  guint i;
+
+  rtph263ppay = GST_RTP_H263P_PAY (payload);
+
+  peercaps =
+      gst_pad_peer_query_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), NULL);
+
+  /* if we're just outputting to udpsink or fakesink or so, we should also
+   * accept any input compatible with our sink template caps */
+  if (!peercaps || gst_caps_is_any (peercaps)) {
+    if (peercaps)
+      gst_caps_unref (peercaps);
+    caps =
+        gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SINKPAD (payload));
+    goto done;
+  }
+
+  /* We basically need to differentiate two use-cases here: One where there's
+   * a capsfilter after the payloader with caps created from an SDP; in this
+   * case the filter caps are fixed and we want to signal to an encoder what
+   * we want it to produce. The second case is simply payloader ! depayloader
+   * where we are dealing with the depayloader's template caps. In this case
+   * we should accept any input compatible with our sink template caps. */
+  if (!gst_caps_is_fixed (peercaps)) {
+    gst_caps_unref (peercaps);
+    caps =
+        gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SINKPAD (payload));
+    goto done;
+  }
+
+  templ = gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload));
+  intersect = gst_caps_intersect (peercaps, templ);
+  gst_caps_unref (peercaps);
+  gst_caps_unref (templ);
+
+  if (gst_caps_is_empty (intersect))
+    return intersect;
+
+  caps = gst_caps_new_empty ();
+  for (i = 0; i < gst_caps_get_size (intersect); i++) {
+    GstStructure *s = gst_caps_get_structure (intersect, i);
+    const gchar *encoding_name = gst_structure_get_string (s, "encoding-name");
+
+    if (!strcmp (encoding_name, "H263-2000")) {
+      const gchar *profile_str = gst_structure_get_string (s, "profile");
+      const gchar *level_str = gst_structure_get_string (s, "level");
+      int profile = 0;
+      int level = 0;
+
+      if (profile_str && level_str) {
+        gboolean i = FALSE, j = FALSE, l = FALSE, t = FALSE, f = FALSE,
+            v = FALSE;
+        GstStructure *new_s = gst_structure_new ("video/x-h263",
+            "variant", G_TYPE_STRING, "itu",
+            NULL);
+
+        profile = atoi (profile_str);
+        level = atoi (level_str);
+
+        /* These profiles are defined in the H.263 Annex X */
+        switch (profile) {
+          case 0:
+            /* The Baseline Profile (Profile 0) */
+            break;
+          case 1:
+            /* H.320 Coding Efficiency Version 2 Backward-Compatibility Profile
+             * (Profile 1)
+             * Baseline + Annexes I, J, L.4 and T
+             */
+            i = j = l = t = TRUE;
+            break;
+          case 2:
+            /* Version 1 Backward-Compatibility Profile (Profile 2)
+             * Baseline + Annex F
+             */
+            i = j = l = t = f = TRUE;
+            break;
+          case 3:
+            /* Version 2 Interactive and Streaming Wireless Profile
+             * Baseline + Annexes I, J, T
+             */
+            i = j = t = TRUE;
+            break;
+          case 4:
+            /* Version 3 Interactive and Streaming Wireless Profile (Profile 4)
+             * Baseline + Annexes I, J, T, V, W.6.3.8,
+             */
+            /* Missing W.6.3.8 */
+            i = j = t = v = TRUE;
+            break;
+          case 5:
+            /* Conversational High Compression Profile (Profile 5)
+             * Baseline + Annexes F, I, J, L.4, T, D, U
+             */
+            /* Missing D, U */
+            f = i = j = l = t = TRUE;
+            break;
+          case 6:
+            /* Conversational Internet Profile (Profile 6)
+             * Baseline + Annexes F, I, J, L.4, T, D, U and
+             * K with arbitratry slice ordering
+             */
+            /* Missing D, U, K with arbitratry slice ordering */
+            f = i = j = l = t = TRUE;
+            break;
+          case 7:
+            /* Conversational Interlace Profile (Profile 7)
+             * Baseline + Annexes F, I, J, L.4, T, D, U,  W.6.3.11
+             */
+            /* Missing D, U, W.6.3.11 */
+            f = i = j = l = t = TRUE;
+            break;
+          case 8:
+            /* High Latency Profile (Profile 8)
+             * Baseline + Annexes F, I, J, L.4, T, D, U, P.5, O.1.1 and
+             * K with arbitratry slice ordering
+             */
+            /* Missing D, U, P.5, O.1.1 */
+            f = i = j = l = t = TRUE;
+            break;
+        }
+
+
+        if (f || i || j || t || l || v) {
+          GValue list = { 0 };
+          GValue vstr = { 0 };
+
+          g_value_init (&list, GST_TYPE_LIST);
+          g_value_init (&vstr, G_TYPE_STRING);
+
+          g_value_set_static_string (&vstr, "h263");
+          gst_value_list_append_value (&list, &vstr);
+          g_value_set_static_string (&vstr, "h263p");
+          gst_value_list_append_value (&list, &vstr);
+
+          if (l || v) {
+            g_value_set_static_string (&vstr, "h263pp");
+            gst_value_list_append_value (&list, &vstr);
+          }
+          g_value_unset (&vstr);
+
+          gst_structure_set_value (new_s, "h263version", &list);
+          g_value_unset (&list);
+        } else {
+          gst_structure_set (new_s, "h263version", G_TYPE_STRING, "h263", NULL);
+        }
+
+
+        if (!f)
+          gst_structure_set (new_s, "annex-f", G_TYPE_BOOLEAN, FALSE, NULL);
+        if (!i)
+          gst_structure_set (new_s, "annex-i", G_TYPE_BOOLEAN, FALSE, NULL);
+        if (!j)
+          gst_structure_set (new_s, "annex-j", G_TYPE_BOOLEAN, FALSE, NULL);
+        if (!t)
+          gst_structure_set (new_s, "annex-t", G_TYPE_BOOLEAN, FALSE, NULL);
+        if (!l)
+          gst_structure_set (new_s, "annex-l", G_TYPE_BOOLEAN, FALSE, NULL);
+        if (!v)
+          gst_structure_set (new_s, "annex-v", G_TYPE_BOOLEAN, FALSE, NULL);
+
+
+        if (level <= 10 || level == 45) {
+          gst_structure_set (new_s,
+              "width", GST_TYPE_INT_RANGE, 1, 176,
+              "height", GST_TYPE_INT_RANGE, 1, 144,
+              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 2002, NULL);
+          caps = gst_caps_merge_structure (caps, new_s);
+        } else if (level <= 20) {
+          GstStructure *s_copy = gst_structure_copy (new_s);
+
+          gst_structure_set (new_s,
+              "width", GST_TYPE_INT_RANGE, 1, 352,
+              "height", GST_TYPE_INT_RANGE, 1, 288,
+              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 2002, NULL);
+          caps = gst_caps_merge_structure (caps, new_s);
+
+          gst_structure_set (s_copy,
+              "width", GST_TYPE_INT_RANGE, 1, 176,
+              "height", GST_TYPE_INT_RANGE, 1, 144,
+              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001, NULL);
+          caps = gst_caps_merge_structure (caps, s_copy);
+        } else if (level <= 40) {
+
+          gst_structure_set (new_s,
+              "width", GST_TYPE_INT_RANGE, 1, 352,
+              "height", GST_TYPE_INT_RANGE, 1, 288,
+              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001, NULL);
+          caps = gst_caps_merge_structure (caps, new_s);
+        } else if (level <= 50) {
+          GstStructure *s_copy = gst_structure_copy (new_s);
+
+          gst_structure_set (new_s,
+              "width", GST_TYPE_INT_RANGE, 1, 352,
+              "height", GST_TYPE_INT_RANGE, 1, 288,
+              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL);
+          caps = gst_caps_merge_structure (caps, new_s);
+
+          gst_structure_set (s_copy,
+              "width", GST_TYPE_INT_RANGE, 1, 352,
+              "height", GST_TYPE_INT_RANGE, 1, 240,
+              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL);
+          caps = gst_caps_merge_structure (caps, s_copy);
+        } else if (level <= 60) {
+          GstStructure *s_copy = gst_structure_copy (new_s);
+
+          gst_structure_set (new_s,
+              "width", GST_TYPE_INT_RANGE, 1, 720,
+              "height", GST_TYPE_INT_RANGE, 1, 288,
+              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL);
+          caps = gst_caps_merge_structure (caps, new_s);
+
+          gst_structure_set (s_copy,
+              "width", GST_TYPE_INT_RANGE, 1, 720,
+              "height", GST_TYPE_INT_RANGE, 1, 240,
+              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL);
+          caps = gst_caps_merge_structure (caps, s_copy);
+        } else if (level <= 70) {
+          GstStructure *s_copy = gst_structure_copy (new_s);
+
+          gst_structure_set (new_s,
+              "width", GST_TYPE_INT_RANGE, 1, 720,
+              "height", GST_TYPE_INT_RANGE, 1, 576,
+              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL);
+          caps = gst_caps_merge_structure (caps, new_s);
+
+          gst_structure_set (s_copy,
+              "width", GST_TYPE_INT_RANGE, 1, 720,
+              "height", GST_TYPE_INT_RANGE, 1, 480,
+              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL);
+          caps = gst_caps_merge_structure (caps, s_copy);
+        } else {
+          caps = gst_caps_merge_structure (caps, new_s);
+        }
+
+      } else {
+        GstStructure *new_s = gst_structure_new ("video/x-h263",
+            "variant", G_TYPE_STRING, "itu",
+            "h263version", G_TYPE_STRING, "h263",
+            NULL);
+
+        GST_DEBUG_OBJECT (rtph263ppay, "No profile or level specified"
+            " for H263-2000, defaulting to baseline H263");
+
+        caps = gst_caps_merge_structure (caps, new_s);
+      }
+    } else {
+      gboolean f = FALSE, i = FALSE, j = FALSE, t = FALSE;
+      /* FIXME: ffmpeg support the Appendix K too, how do we express it ?
+       *   guint k;
+       */
+      const gchar *str;
+      GstStructure *new_s = gst_structure_new ("video/x-h263",
+          "variant", G_TYPE_STRING, "itu",
+          NULL);
+      gboolean added = FALSE;
+
+      str = gst_structure_get_string (s, "f");
+      if (str && !strcmp (str, "1"))
+        f = TRUE;
+
+      str = gst_structure_get_string (s, "i");
+      if (str && !strcmp (str, "1"))
+        i = TRUE;
+
+      str = gst_structure_get_string (s, "j");
+      if (str && !strcmp (str, "1"))
+        j = TRUE;
+
+      str = gst_structure_get_string (s, "t");
+      if (str && !strcmp (str, "1"))
+        t = TRUE;
+
+      if (f || i || j || t) {
+        GValue list = { 0 };
+        GValue vstr = { 0 };
+
+        g_value_init (&list, GST_TYPE_LIST);
+        g_value_init (&vstr, G_TYPE_STRING);
+
+        g_value_set_static_string (&vstr, "h263");
+        gst_value_list_append_value (&list, &vstr);
+        g_value_set_static_string (&vstr, "h263p");
+        gst_value_list_append_value (&list, &vstr);
+        g_value_unset (&vstr);
+
+        gst_structure_set_value (new_s, "h263version", &list);
+        g_value_unset (&list);
+      } else {
+        gst_structure_set (new_s, "h263version", G_TYPE_STRING, "h263", NULL);
+      }
+
+      if (!f)
+        gst_structure_set (new_s, "annex-f", G_TYPE_BOOLEAN, FALSE, NULL);
+      if (!i)
+        gst_structure_set (new_s, "annex-i", G_TYPE_BOOLEAN, FALSE, NULL);
+      if (!j)
+        gst_structure_set (new_s, "annex-j", G_TYPE_BOOLEAN, FALSE, NULL);
+      if (!t)
+        gst_structure_set (new_s, "annex-t", G_TYPE_BOOLEAN, FALSE, NULL);
+
+
+      str = gst_structure_get_string (s, "custom");
+      if (str) {
+        unsigned int xmax, ymax, mpi;
+        if (sscanf (str, "%u,%u,%u", &xmax, &ymax, &mpi) == 3) {
+          if (xmax % 4 && ymax % 4 && mpi >= 1 && mpi <= 32) {
+            caps = caps_append (caps, new_s, xmax, ymax, mpi);
+            added = TRUE;
+          } else {
+            GST_WARNING_OBJECT (rtph263ppay, "Invalid custom framesize/MPI"
+                " %u x %u at %u, ignoring", xmax, ymax, mpi);
+          }
+        } else {
+          GST_WARNING_OBJECT (rtph263ppay, "Invalid custom framesize/MPI: %s,"
+              " ignoring", str);
+        }
+      }
+
+      str = gst_structure_get_string (s, "16cif");
+      if (str) {
+        int mpi = atoi (str);
+        caps = caps_append (caps, new_s, 1408, 1152, mpi);
+        added = TRUE;
+      }
+
+      str = gst_structure_get_string (s, "4cif");
+      if (str) {
+        int mpi = atoi (str);
+        caps = caps_append (caps, new_s, 704, 576, mpi);
+        added = TRUE;
+      }
+
+      str = gst_structure_get_string (s, "cif");
+      if (str) {
+        int mpi = atoi (str);
+        caps = caps_append (caps, new_s, 352, 288, mpi);
+        added = TRUE;
+      }
+
+      str = gst_structure_get_string (s, "qcif");
+      if (str) {
+        int mpi = atoi (str);
+        caps = caps_append (caps, new_s, 176, 144, mpi);
+        added = TRUE;
+      }
+
+      str = gst_structure_get_string (s, "sqcif");
+      if (str) {
+        int mpi = atoi (str);
+        caps = caps_append (caps, new_s, 128, 96, mpi);
+        added = TRUE;
+      }
+
+      if (added)
+        gst_structure_free (new_s);
+      else
+        caps = gst_caps_merge_structure (caps, new_s);
+    }
+  }
+
+  gst_caps_unref (intersect);
+
+done:
+
+  if (filter) {
+    GstCaps *tmp;
+
+    GST_DEBUG_OBJECT (payload, "Intersect %" GST_PTR_FORMAT " and filter %"
+        GST_PTR_FORMAT, caps, filter);
+    tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    caps = tmp;
+  }
+
+  return caps;
+}
+
+
+static void
+gst_rtp_h263p_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpH263PPay *rtph263ppay;
+
+  rtph263ppay = GST_RTP_H263P_PAY (object);
+
+  switch (prop_id) {
+    case PROP_FRAGMENTATION_MODE:
+      rtph263ppay->fragmentation_mode = g_value_get_enum (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_h263p_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpH263PPay *rtph263ppay;
+
+  rtph263ppay = GST_RTP_H263P_PAY (object);
+
+  switch (prop_id) {
+    case PROP_FRAGMENTATION_MODE:
+      g_value_set_enum (value, rtph263ppay->fragmentation_mode);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstFlowReturn
+gst_rtp_h263p_pay_flush (GstRtpH263PPay * rtph263ppay)
+{
+  guint avail;
+  GstBufferList *list = NULL;
+  GstBuffer *outbuf = NULL;
+  GstFlowReturn ret;
+  gboolean fragmented = FALSE;
+
+  avail = gst_adapter_available (rtph263ppay->adapter);
+  if (avail == 0)
+    return GST_FLOW_OK;
+
+  fragmented = FALSE;
+  /* This algorithm assumes the H263/+/++ encoder sends complete frames in each
+   * buffer */
+  /* With Fragmentation Mode at GST_FRAGMENTATION_MODE_NORMAL:
+   *  This algorithm implements the Follow-on packets method for packetization.
+   *  This assumes low packet loss network. 
+   * With Fragmentation Mode at GST_FRAGMENTATION_MODE_SYNC:
+   *  This algorithm separates large frames at synchronisation points (Segments)
+   *  (See RFC 4629 section 6). It would be interesting to have a property such as network
+   *  quality to select between both packetization methods */
+  /* TODO Add VRC supprt (See RFC 4629 section 5.2) */
+
+  while (avail > 0) {
+    guint towrite;
+    guint8 *payload;
+    gint header_len;
+    guint next_gop = 0;
+    gboolean found_gob = FALSE;
+    GstRTPBuffer rtp = { NULL };
+    GstBuffer *payload_buf;
+
+    if (rtph263ppay->fragmentation_mode == GST_FRAGMENTATION_MODE_SYNC) {
+      /* start after 1st gop possible */
+
+      /* Check if we have a gob or eos , eossbs */
+      /* FIXME EOS and EOSSBS packets should never contain any gobs and vice-versa */
+      next_gop =
+          gst_adapter_masked_scan_uint32 (rtph263ppay->adapter, 0xffff8000,
+          0x00008000, 0, avail);
+      if (next_gop == 0) {
+        GST_DEBUG_OBJECT (rtph263ppay, " Found GOB header");
+        found_gob = TRUE;
+      }
+
+      /* Find next and cut the packet accordingly */
+      /* TODO we should get as many gobs as possible until MTU is reached, this
+       * code seems to just get one GOB per packet */
+      if (next_gop == 0 && avail > 3)
+        next_gop =
+            gst_adapter_masked_scan_uint32 (rtph263ppay->adapter, 0xffff8000,
+            0x00008000, 3, avail - 3);
+      GST_DEBUG_OBJECT (rtph263ppay, " Next GOB Detected at :  %d", next_gop);
+      if (next_gop == -1)
+        next_gop = 0;
+    }
+
+    /* for picture start frames (non-fragmented), we need to remove the first
+     * two 0x00 bytes and set P=1 */
+    if (!fragmented || found_gob) {
+      gst_adapter_flush (rtph263ppay->adapter, 2);
+      avail -= 2;
+    }
+    header_len = 2;
+
+    towrite = MIN (avail, gst_rtp_buffer_calc_payload_len
+        (GST_RTP_BASE_PAYLOAD_MTU (rtph263ppay) - header_len, 0, 0));
+
+    if (next_gop > 0)
+      towrite = MIN (next_gop, towrite);
+
+    outbuf = gst_rtp_buffer_new_allocate (header_len, 0, 0);
+
+    gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+    /* last fragment gets the marker bit set */
+    gst_rtp_buffer_set_marker (&rtp, avail > towrite ? 0 : 1);
+
+    payload = gst_rtp_buffer_get_payload (&rtp);
+
+    /*  0                   1
+     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * |   RR    |P|V|   PLEN    |PEBIT|
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     */
+    /* if fragmented or gop header , write p bit =1 */
+    payload[0] = (fragmented && !found_gob) ? 0x00 : 0x04;
+    payload[1] = 0;
+
+    GST_BUFFER_PTS (outbuf) = rtph263ppay->first_timestamp;
+    GST_BUFFER_DURATION (outbuf) = rtph263ppay->first_duration;
+    gst_rtp_buffer_unmap (&rtp);
+
+    payload_buf = gst_adapter_take_buffer_fast (rtph263ppay->adapter, towrite);
+    gst_rtp_copy_video_meta (rtph263ppay, outbuf, payload_buf);
+    outbuf = gst_buffer_append (outbuf, payload_buf);
+    avail -= towrite;
+
+    /* If more data is available and this is our first iteration,
+     * we create a buffer list and remember that we're fragmented.
+     *
+     * If we're fragmented already, add buffers to the previously
+     * created buffer list.
+     *
+     * Otherwise fragmented will be FALSE and we just push the single output
+     * buffer, and no list is allocated.
+     */
+    if (avail && !fragmented) {
+      fragmented = TRUE;
+      list = gst_buffer_list_new ();
+      gst_buffer_list_add (list, outbuf);
+    } else if (fragmented) {
+      gst_buffer_list_add (list, outbuf);
+    }
+  }
+
+  if (fragmented) {
+    ret =
+        gst_rtp_base_payload_push_list (GST_RTP_BASE_PAYLOAD (rtph263ppay),
+        list);
+  } else {
+    ret =
+        gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtph263ppay), outbuf);
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_rtp_h263p_pay_handle_buffer (GstRTPBasePayload * payload,
+    GstBuffer * buffer)
+{
+  GstRtpH263PPay *rtph263ppay;
+  GstFlowReturn ret;
+
+  rtph263ppay = GST_RTP_H263P_PAY (payload);
+
+  rtph263ppay->first_timestamp = GST_BUFFER_PTS (buffer);
+  rtph263ppay->first_duration = GST_BUFFER_DURATION (buffer);
+
+  /* we always encode and flush a full picture */
+  gst_adapter_push (rtph263ppay->adapter, buffer);
+  ret = gst_rtp_h263p_pay_flush (rtph263ppay);
+
+  return ret;
+}
+
+gboolean
+gst_rtp_h263p_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtph263ppay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_H263P_PAY);
+}
diff --git a/gst/rtp/gstrtph263ppay.h b/gst/rtp/gstrtph263ppay.h
new file mode 100644
index 0000000..23ec8b8
--- /dev/null
+++ b/gst/rtp/gstrtph263ppay.h
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_H263P_PAY_H__
+#define __GST_RTP_H263P_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_H263P_PAY \
+  (gst_rtp_h263p_pay_get_type())
+#define GST_RTP_H263P_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H263P_PAY,GstRtpH263PPay))
+#define GST_RTP_H263P_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H263P_PAY,GstRtpH263PPayClass))
+#define GST_IS_RTP_H263P_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H263P_PAY))
+#define GST_IS_RTP_H263P_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H263P_PAY))
+
+typedef struct _GstRtpH263PPay GstRtpH263PPay;
+typedef struct _GstRtpH263PPayClass GstRtpH263PPayClass;
+
+typedef enum
+{
+  GST_FRAGMENTATION_MODE_NORMAL = 0,
+  GST_FRAGMENTATION_MODE_SYNC   = 1
+} GstFragmentationMode;
+
+struct _GstRtpH263PPay
+{
+  GstRTPBasePayload    payload;
+
+  GstAdapter          *adapter;
+  GstClockTime         first_timestamp;
+  GstClockTime         first_duration;
+  GstFragmentationMode fragmentation_mode;
+};
+
+struct _GstRtpH263PPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_h263p_pay_get_type (void);
+
+gboolean gst_rtp_h263p_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_H263P_PAY_H__ */
diff --git a/gst/rtp/gstrtph264depay.c b/gst/rtp/gstrtph264depay.c
new file mode 100644
index 0000000..6ce3820
--- /dev/null
+++ b/gst/rtp/gstrtph264depay.c
@@ -0,0 +1,1329 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <gst/base/gstbitreader.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/pbutils/pbutils.h>
+#include <gst/video/video.h>
+#include "gstrtph264depay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtph264depay_debug);
+#define GST_CAT_DEFAULT (rtph264depay_debug)
+
+/* This is what we'll default to when downstream hasn't
+ * expressed a restriction or preference via caps */
+#define DEFAULT_BYTE_STREAM   TRUE
+#define DEFAULT_ACCESS_UNIT   FALSE
+
+/* 3 zero bytes syncword */
+static const guint8 sync_bytes[] = { 0, 0, 0, 1 };
+
+static GstStaticPadTemplate gst_rtp_h264_depay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-h264, "
+        "stream-format = (string) avc, alignment = (string) au; "
+        "video/x-h264, "
+        "stream-format = (string) byte-stream, alignment = (string) { nal, au }")
+    );
+
+static GstStaticPadTemplate gst_rtp_h264_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"H264\"")
+        /** optional parameters **/
+    /* "profile-level-id = (string) ANY, " */
+    /* "max-mbps = (string) ANY, " */
+    /* "max-fs = (string) ANY, " */
+    /* "max-cpb = (string) ANY, " */
+    /* "max-dpb = (string) ANY, " */
+    /* "max-br = (string) ANY, " */
+    /* "redundant-pic-cap = (string) { \"0\", \"1\" }, " */
+    /* "sprop-parameter-sets = (string) ANY, " */
+    /* "parameter-add = (string) { \"0\", \"1\" }, " */
+    /* "packetization-mode = (string) { \"0\", \"1\", \"2\" }, " */
+    /* "sprop-interleaving-depth = (string) ANY, " */
+    /* "sprop-deint-buf-req = (string) ANY, " */
+    /* "deint-buf-cap = (string) ANY, " */
+    /* "sprop-init-buf-time = (string) ANY, " */
+    /* "sprop-max-don-diff = (string) ANY, " */
+    /* "max-rcmd-nalu-size = (string) ANY " */
+    );
+
+#define gst_rtp_h264_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpH264Depay, gst_rtp_h264_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_h264_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_h264_depay_change_state (GstElement *
+    element, GstStateChange transition);
+
+static GstBuffer *gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+static gboolean gst_rtp_h264_depay_setcaps (GstRTPBaseDepayload * filter,
+    GstCaps * caps);
+static gboolean gst_rtp_h264_depay_handle_event (GstRTPBaseDepayload * depay,
+    GstEvent * event);
+
+static void
+gst_rtp_h264_depay_class_init (GstRtpH264DepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_h264_depay_finalize;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h264_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h264_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP H264 depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts H264 video from RTP packets (RFC 3984)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+  gstelement_class->change_state = gst_rtp_h264_depay_change_state;
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_h264_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_h264_depay_setcaps;
+  gstrtpbasedepayload_class->handle_event = gst_rtp_h264_depay_handle_event;
+}
+
+static void
+gst_rtp_h264_depay_init (GstRtpH264Depay * rtph264depay)
+{
+  rtph264depay->adapter = gst_adapter_new ();
+  rtph264depay->picture_adapter = gst_adapter_new ();
+  rtph264depay->byte_stream = DEFAULT_BYTE_STREAM;
+  rtph264depay->merge = DEFAULT_ACCESS_UNIT;
+  rtph264depay->sps = g_ptr_array_new_with_free_func (
+      (GDestroyNotify) gst_buffer_unref);
+  rtph264depay->pps = g_ptr_array_new_with_free_func (
+      (GDestroyNotify) gst_buffer_unref);
+}
+
+static void
+gst_rtp_h264_depay_reset (GstRtpH264Depay * rtph264depay, gboolean hard)
+{
+  gst_adapter_clear (rtph264depay->adapter);
+  rtph264depay->wait_start = TRUE;
+  gst_adapter_clear (rtph264depay->picture_adapter);
+  rtph264depay->picture_start = FALSE;
+  rtph264depay->last_keyframe = FALSE;
+  rtph264depay->last_ts = 0;
+  rtph264depay->current_fu_type = 0;
+  rtph264depay->new_codec_data = FALSE;
+  g_ptr_array_set_size (rtph264depay->sps, 0);
+  g_ptr_array_set_size (rtph264depay->pps, 0);
+
+  if (hard) {
+    if (rtph264depay->allocator != NULL) {
+      gst_object_unref (rtph264depay->allocator);
+      rtph264depay->allocator = NULL;
+    }
+    gst_allocation_params_init (&rtph264depay->params);
+  }
+}
+
+static void
+gst_rtp_h264_depay_finalize (GObject * object)
+{
+  GstRtpH264Depay *rtph264depay;
+
+  rtph264depay = GST_RTP_H264_DEPAY (object);
+
+  if (rtph264depay->codec_data)
+    gst_buffer_unref (rtph264depay->codec_data);
+
+  g_object_unref (rtph264depay->adapter);
+  g_object_unref (rtph264depay->picture_adapter);
+
+  g_ptr_array_free (rtph264depay->sps, TRUE);
+  g_ptr_array_free (rtph264depay->pps, TRUE);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_h264_depay_negotiate (GstRtpH264Depay * rtph264depay)
+{
+  GstCaps *caps;
+  gint byte_stream = -1;
+  gint merge = -1;
+
+  caps =
+      gst_pad_get_allowed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph264depay));
+
+  GST_DEBUG_OBJECT (rtph264depay, "allowed caps: %" GST_PTR_FORMAT, caps);
+
+  if (caps) {
+    if (gst_caps_get_size (caps) > 0) {
+      GstStructure *s = gst_caps_get_structure (caps, 0);
+      const gchar *str = NULL;
+
+      if ((str = gst_structure_get_string (s, "stream-format"))) {
+        if (strcmp (str, "avc") == 0) {
+          byte_stream = FALSE;
+        } else if (strcmp (str, "byte-stream") == 0) {
+          byte_stream = TRUE;
+        } else {
+          GST_DEBUG_OBJECT (rtph264depay, "unknown stream-format: %s", str);
+        }
+      }
+
+      if ((str = gst_structure_get_string (s, "alignment"))) {
+        if (strcmp (str, "au") == 0) {
+          merge = TRUE;
+        } else if (strcmp (str, "nal") == 0) {
+          merge = FALSE;
+        } else {
+          GST_DEBUG_OBJECT (rtph264depay, "unknown alignment: %s", str);
+        }
+      }
+    }
+    gst_caps_unref (caps);
+  }
+
+  if (byte_stream != -1) {
+    GST_DEBUG_OBJECT (rtph264depay, "downstream requires byte-stream %d",
+        byte_stream);
+    rtph264depay->byte_stream = byte_stream;
+  } else {
+    GST_DEBUG_OBJECT (rtph264depay, "defaulting to byte-stream %d",
+        DEFAULT_BYTE_STREAM);
+    rtph264depay->byte_stream = DEFAULT_BYTE_STREAM;
+  }
+  if (merge != -1) {
+    GST_DEBUG_OBJECT (rtph264depay, "downstream requires merge %d", merge);
+    rtph264depay->merge = merge;
+  } else {
+    GST_DEBUG_OBJECT (rtph264depay, "defaulting to merge %d",
+        DEFAULT_ACCESS_UNIT);
+    rtph264depay->merge = DEFAULT_ACCESS_UNIT;
+  }
+}
+
+static gboolean
+parse_sps (GstMapInfo * map, guint32 * sps_id)
+{
+  GstBitReader br = GST_BIT_READER_INIT (map->data + 4,
+      map->size - 4);
+
+  if (map->size < 5)
+    return FALSE;
+
+  if (!gst_rtp_read_golomb (&br, sps_id))
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+parse_pps (GstMapInfo * map, guint32 * sps_id, guint32 * pps_id)
+{
+  GstBitReader br = GST_BIT_READER_INIT (map->data + 1,
+      map->size - 1);
+
+  if (map->size < 2)
+    return FALSE;
+
+  if (!gst_rtp_read_golomb (&br, pps_id))
+    return FALSE;
+  if (!gst_rtp_read_golomb (&br, sps_id))
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+gst_rtp_h264_depay_set_output_caps (GstRtpH264Depay * rtph264depay,
+    GstCaps * caps)
+{
+  GstAllocationParams params;
+  GstAllocator *allocator = NULL;
+  GstPad *srcpad;
+  gboolean res;
+
+  gst_allocation_params_init (&params);
+
+  srcpad = GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph264depay);
+
+  res = gst_pad_set_caps (srcpad, caps);
+
+  if (res) {
+    GstQuery *query;
+
+    query = gst_query_new_allocation (caps, TRUE);
+    if (!gst_pad_peer_query (srcpad, query)) {
+      GST_DEBUG_OBJECT (rtph264depay, "downstream ALLOCATION query failed");
+    }
+
+    if (gst_query_get_n_allocation_params (query) > 0) {
+      gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
+    }
+
+    gst_query_unref (query);
+  }
+
+  if (rtph264depay->allocator)
+    gst_object_unref (rtph264depay->allocator);
+
+  rtph264depay->allocator = allocator;
+  rtph264depay->params = params;
+
+  return res;
+}
+
+static gboolean
+gst_rtp_h264_set_src_caps (GstRtpH264Depay * rtph264depay)
+{
+  gboolean res = TRUE;
+  GstCaps *srccaps;
+  GstCaps *old_caps;
+  GstPad *srcpad;
+
+  if (!rtph264depay->byte_stream &&
+      (!rtph264depay->new_codec_data ||
+          rtph264depay->sps->len == 0 || rtph264depay->pps->len == 0))
+    return TRUE;
+
+  srccaps = gst_caps_new_simple ("video/x-h264",
+      "stream-format", G_TYPE_STRING,
+      rtph264depay->byte_stream ? "byte-stream" : "avc",
+      "alignment", G_TYPE_STRING, rtph264depay->merge ? "au" : "nal", NULL);
+
+  if (!rtph264depay->byte_stream) {
+    GstBuffer *codec_data;
+    GstMapInfo map;
+    GstMapInfo nalmap;
+    guint8 *data;
+    guint len;
+    guint new_size;
+    guint i;
+    guchar level = 0;
+    guchar profile_compat = G_MAXUINT8;
+
+    /* start with 7 bytes header */
+    len = 7;
+    /* count sps & pps */
+    for (i = 0; i < rtph264depay->sps->len; i++)
+      len += 2 + gst_buffer_get_size (g_ptr_array_index (rtph264depay->sps, i));
+    for (i = 0; i < rtph264depay->pps->len; i++)
+      len += 2 + gst_buffer_get_size (g_ptr_array_index (rtph264depay->pps, i));
+
+    codec_data = gst_buffer_new_and_alloc (len);
+    gst_buffer_map (codec_data, &map, GST_MAP_READWRITE);
+    data = map.data;
+
+    /* 8 bits version == 1 */
+    *data++ = 1;
+
+    /* According to: ISO/IEC 14496-15:2004(E) section 5.2.4.1
+     * The level is the max level of all SPSes
+     * A profile compat bit can only be set if all SPSes include that bit
+     */
+    for (i = 0; i < rtph264depay->sps->len; i++) {
+      gst_buffer_map (g_ptr_array_index (rtph264depay->sps, i), &nalmap,
+          GST_MAP_READ);
+      profile_compat &= nalmap.data[2];
+      level = MAX (level, nalmap.data[3]);
+      gst_buffer_unmap (g_ptr_array_index (rtph264depay->sps, i), &nalmap);
+    }
+
+    /* Assume all SPSes use the same profile, so extract from the first SPS */
+    gst_buffer_map (g_ptr_array_index (rtph264depay->sps, 0), &nalmap,
+        GST_MAP_READ);
+    *data++ = nalmap.data[1];
+    gst_buffer_unmap (g_ptr_array_index (rtph264depay->sps, 0), &nalmap);
+    *data++ = profile_compat;
+    *data++ = level;
+
+    /* 6 bits reserved | 2 bits lengthSizeMinusOn */
+    *data++ = 0xff;
+    /* 3 bits reserved | 5 bits numOfSequenceParameterSets */
+    *data++ = 0xe0 | (rtph264depay->sps->len & 0x1f);
+
+    /* copy all SPS */
+    for (i = 0; i < rtph264depay->sps->len; i++) {
+      gst_buffer_map (g_ptr_array_index (rtph264depay->sps, i), &nalmap,
+          GST_MAP_READ);
+
+      GST_DEBUG_OBJECT (rtph264depay, "copy SPS %d of length %u", i,
+          (guint) nalmap.size);
+      GST_WRITE_UINT16_BE (data, nalmap.size);
+      data += 2;
+      memcpy (data, nalmap.data, nalmap.size);
+      data += nalmap.size;
+      gst_buffer_unmap (g_ptr_array_index (rtph264depay->sps, i), &nalmap);
+    }
+
+    /* 8 bits numOfPictureParameterSets */
+    *data++ = rtph264depay->pps->len;
+    /* copy all PPS */
+    for (i = 0; i < rtph264depay->pps->len; i++) {
+      gst_buffer_map (g_ptr_array_index (rtph264depay->pps, i), &nalmap,
+          GST_MAP_READ);
+
+      GST_DEBUG_OBJECT (rtph264depay, "copy PPS %d of length %u", i,
+          (guint) nalmap.size);
+      GST_WRITE_UINT16_BE (data, nalmap.size);
+      data += 2;
+      memcpy (data, nalmap.data, nalmap.size);
+      data += nalmap.size;
+      gst_buffer_unmap (g_ptr_array_index (rtph264depay->pps, i), &nalmap);
+    }
+
+    new_size = data - map.data;
+    gst_buffer_unmap (codec_data, &map);
+    gst_buffer_set_size (codec_data, new_size);
+
+    gst_caps_set_simple (srccaps,
+        "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
+    gst_buffer_unref (codec_data);
+  }
+
+  /* Set profile a level from SPS */
+  {
+    gint i;
+    GstBuffer *max_level_sps = NULL;
+    gint level = 0;
+    GstMapInfo nalmap;
+
+    /* Get the SPS with the highest level. We assume
+     * all SPS have the same profile */
+    for (i = 0; i < rtph264depay->sps->len; i++) {
+      gst_buffer_map (g_ptr_array_index (rtph264depay->sps, i), &nalmap,
+          GST_MAP_READ);
+      if (level == 0 || level < nalmap.data[3]) {
+        max_level_sps = g_ptr_array_index (rtph264depay->sps, i);
+        level = nalmap.data[3];
+      }
+      gst_buffer_unmap (g_ptr_array_index (rtph264depay->sps, i), &nalmap);
+    }
+
+    if (max_level_sps) {
+      gst_buffer_map (max_level_sps, &nalmap, GST_MAP_READ);
+      gst_codec_utils_h264_caps_set_level_and_profile (srccaps, nalmap.data + 1,
+          nalmap.size - 1);
+      gst_buffer_unmap (max_level_sps, &nalmap);
+    }
+  }
+
+  srcpad = GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph264depay);
+
+  old_caps = gst_pad_get_current_caps (srcpad);
+
+  if (old_caps == NULL || !gst_caps_is_equal (srccaps, old_caps)) {
+    res = gst_rtp_h264_depay_set_output_caps (rtph264depay, srccaps);
+  }
+
+  gst_caps_unref (srccaps);
+
+  /* Insert SPS and PPS into the stream on next opportunity (if bytestream) */
+  if (rtph264depay->byte_stream
+      && (rtph264depay->sps->len > 0 || rtph264depay->pps->len > 0)) {
+    gint i;
+    GstBuffer *codec_data;
+    GstMapInfo map;
+    guint8 *data;
+    guint len = 0;
+
+    for (i = 0; i < rtph264depay->sps->len; i++) {
+      len += 4 + gst_buffer_get_size (g_ptr_array_index (rtph264depay->sps, i));
+    }
+
+    for (i = 0; i < rtph264depay->pps->len; i++) {
+      len += 4 + gst_buffer_get_size (g_ptr_array_index (rtph264depay->pps, i));
+    }
+
+    codec_data = gst_buffer_new_and_alloc (len);
+    gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
+    data = map.data;
+
+    for (i = 0; i < rtph264depay->sps->len; i++) {
+      GstBuffer *sps_buf = g_ptr_array_index (rtph264depay->sps, i);
+      guint sps_size = gst_buffer_get_size (sps_buf);
+
+      if (rtph264depay->byte_stream)
+        memcpy (data, sync_bytes, sizeof (sync_bytes));
+      else
+        GST_WRITE_UINT32_BE (data, sps_size);
+      gst_buffer_extract (sps_buf, 0, data + 4, -1);
+      data += 4 + sps_size;
+    }
+
+    for (i = 0; i < rtph264depay->pps->len; i++) {
+      GstBuffer *pps_buf = g_ptr_array_index (rtph264depay->pps, i);
+      guint pps_size = gst_buffer_get_size (pps_buf);
+
+      if (rtph264depay->byte_stream)
+        memcpy (data, sync_bytes, sizeof (sync_bytes));
+      else
+        GST_WRITE_UINT32_BE (data, pps_size);
+      gst_buffer_extract (pps_buf, 0, data + 4, -1);
+      data += 4 + pps_size;
+    }
+
+    gst_buffer_unmap (codec_data, &map);
+    if (rtph264depay->codec_data)
+      gst_buffer_unref (rtph264depay->codec_data);
+    rtph264depay->codec_data = codec_data;
+  }
+
+  if (res)
+    rtph264depay->new_codec_data = FALSE;
+
+  return res;
+}
+
+gboolean
+gst_rtp_h264_add_sps_pps (GstElement * rtph264, GPtrArray * sps_array,
+    GPtrArray * pps_array, GstBuffer * nal)
+{
+  GstMapInfo map;
+  guchar type;
+  guint i;
+
+  gst_buffer_map (nal, &map, GST_MAP_READ);
+
+  type = map.data[0] & 0x1f;
+
+  if (type == 7) {
+    guint32 sps_id;
+
+    if (!parse_sps (&map, &sps_id)) {
+      GST_WARNING_OBJECT (rtph264, "Invalid SPS,"
+          " can't parse seq_parameter_set_id");
+      goto drop;
+    }
+
+    for (i = 0; i < sps_array->len; i++) {
+      GstBuffer *sps = g_ptr_array_index (sps_array, i);
+      GstMapInfo spsmap;
+      guint32 tmp_sps_id;
+
+      gst_buffer_map (sps, &spsmap, GST_MAP_READ);
+      parse_sps (&spsmap, &tmp_sps_id);
+
+      if (sps_id == tmp_sps_id) {
+        if (map.size == spsmap.size &&
+            memcmp (map.data, spsmap.data, spsmap.size) == 0) {
+          GST_LOG_OBJECT (rtph264, "Unchanged SPS %u, not updating", sps_id);
+          gst_buffer_unmap (sps, &spsmap);
+          goto drop;
+        } else {
+          gst_buffer_unmap (sps, &spsmap);
+          g_ptr_array_remove_index_fast (sps_array, i);
+          g_ptr_array_add (sps_array, nal);
+          GST_LOG_OBJECT (rtph264, "Modified SPS %u, replacing", sps_id);
+          goto done;
+        }
+      }
+      gst_buffer_unmap (sps, &spsmap);
+    }
+    GST_LOG_OBJECT (rtph264, "Adding new SPS %u", sps_id);
+    g_ptr_array_add (sps_array, nal);
+  } else if (type == 8) {
+    guint32 sps_id;
+    guint32 pps_id;
+
+    if (!parse_pps (&map, &sps_id, &pps_id)) {
+      GST_WARNING_OBJECT (rtph264, "Invalid PPS,"
+          " can't parse seq_parameter_set_id or pic_parameter_set_id");
+      goto drop;
+    }
+
+    for (i = 0; i < pps_array->len; i++) {
+      GstBuffer *pps = g_ptr_array_index (pps_array, i);
+      GstMapInfo ppsmap;
+      guint32 tmp_sps_id;
+      guint32 tmp_pps_id;
+
+
+      gst_buffer_map (pps, &ppsmap, GST_MAP_READ);
+      parse_pps (&ppsmap, &tmp_sps_id, &tmp_pps_id);
+
+      if (pps_id == tmp_pps_id) {
+        if (map.size == ppsmap.size &&
+            memcmp (map.data, ppsmap.data, ppsmap.size) == 0) {
+          GST_LOG_OBJECT (rtph264, "Unchanged PPS %u:%u, not updating", sps_id,
+              pps_id);
+          gst_buffer_unmap (pps, &ppsmap);
+          goto drop;
+        } else {
+          gst_buffer_unmap (pps, &ppsmap);
+          g_ptr_array_remove_index_fast (pps_array, i);
+          g_ptr_array_add (pps_array, nal);
+          GST_LOG_OBJECT (rtph264, "Modified PPS %u:%u, replacing",
+              sps_id, pps_id);
+          goto done;
+        }
+      }
+      gst_buffer_unmap (pps, &ppsmap);
+    }
+    GST_LOG_OBJECT (rtph264, "Adding new PPS %u:%i", sps_id, pps_id);
+    g_ptr_array_add (pps_array, nal);
+  } else {
+    goto drop;
+  }
+
+done:
+  gst_buffer_unmap (nal, &map);
+
+  return TRUE;
+
+drop:
+  gst_buffer_unmap (nal, &map);
+  gst_buffer_unref (nal);
+
+  return FALSE;
+}
+
+
+static void
+gst_rtp_h264_depay_add_sps_pps (GstRtpH264Depay * rtph264depay, GstBuffer * nal)
+{
+  if (gst_rtp_h264_add_sps_pps (GST_ELEMENT (rtph264depay),
+          rtph264depay->sps, rtph264depay->pps, nal))
+    rtph264depay->new_codec_data = TRUE;
+}
+
+static gboolean
+gst_rtp_h264_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  gint clock_rate;
+  GstStructure *structure = gst_caps_get_structure (caps, 0);
+  GstRtpH264Depay *rtph264depay;
+  const gchar *ps;
+  GstBuffer *codec_data;
+  GstMapInfo map;
+  guint8 *ptr;
+
+  rtph264depay = GST_RTP_H264_DEPAY (depayload);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;
+  depayload->clock_rate = clock_rate;
+
+  /* Base64 encoded, comma separated config NALs */
+  ps = gst_structure_get_string (structure, "sprop-parameter-sets");
+
+  /* negotiate with downstream w.r.t. output format and alignment */
+  gst_rtp_h264_depay_negotiate (rtph264depay);
+
+  if (rtph264depay->byte_stream && ps != NULL) {
+    /* for bytestream we only need the parameter sets but we don't error out
+     * when they are not there, we assume they are in the stream. */
+    gchar **params;
+    guint len, total;
+    gint i;
+
+    params = g_strsplit (ps, ",", 0);
+
+    /* count total number of bytes in base64. Also include the sync bytes in
+     * front of the params. */
+    len = 0;
+    for (i = 0; params[i]; i++) {
+      len += strlen (params[i]);
+      len += sizeof (sync_bytes);
+    }
+    /* we seriously overshoot the length, but it's fine. */
+    codec_data = gst_buffer_new_and_alloc (len);
+
+    gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
+    ptr = map.data;
+    total = 0;
+    for (i = 0; params[i]; i++) {
+      guint save = 0;
+      gint state = 0;
+
+      GST_DEBUG_OBJECT (depayload, "decoding param %d (%s)", i, params[i]);
+      memcpy (ptr, sync_bytes, sizeof (sync_bytes));
+      ptr += sizeof (sync_bytes);
+      len =
+          g_base64_decode_step (params[i], strlen (params[i]), ptr, &state,
+          &save);
+      GST_DEBUG_OBJECT (depayload, "decoded %d bytes", len);
+      total += len + sizeof (sync_bytes);
+      ptr += len;
+    }
+    gst_buffer_unmap (codec_data, &map);
+    gst_buffer_resize (codec_data, 0, total);
+    g_strfreev (params);
+
+    /* keep the codec_data, we need to send it as the first buffer. We cannot
+     * push it in the adapter because the adapter might be flushed on discont.
+     */
+    if (rtph264depay->codec_data)
+      gst_buffer_unref (rtph264depay->codec_data);
+    rtph264depay->codec_data = codec_data;
+  } else if (!rtph264depay->byte_stream) {
+    gchar **params;
+    gint i;
+
+    if (ps == NULL)
+      goto incomplete_caps;
+
+    params = g_strsplit (ps, ",", 0);
+
+    GST_DEBUG_OBJECT (depayload, "we have %d params", g_strv_length (params));
+
+    /* start with 7 bytes header */
+    for (i = 0; params[i]; i++) {
+      GstBuffer *nal;
+      GstMapInfo nalmap;
+      gsize nal_len;
+      guint save = 0;
+      gint state = 0;
+
+      nal_len = strlen (params[i]);
+      if (nal_len == 0) {
+        GST_WARNING_OBJECT (depayload, "empty param '%s' (#%d)", params[i], i);
+        continue;
+      }
+      nal = gst_buffer_new_and_alloc (nal_len);
+      gst_buffer_map (nal, &nalmap, GST_MAP_READWRITE);
+
+      nal_len =
+          g_base64_decode_step (params[i], nal_len, nalmap.data, &state, &save);
+
+      GST_DEBUG_OBJECT (depayload, "adding param %d as %s", i,
+          ((nalmap.data[0] & 0x1f) == 7) ? "SPS" : "PPS");
+
+      gst_buffer_unmap (nal, &nalmap);
+      gst_buffer_set_size (nal, nal_len);
+
+      gst_rtp_h264_depay_add_sps_pps (rtph264depay, nal);
+    }
+    g_strfreev (params);
+
+    if (rtph264depay->sps->len == 0 || rtph264depay->pps->len == 0)
+      goto incomplete_caps;
+  }
+
+  return gst_rtp_h264_set_src_caps (rtph264depay);
+
+  /* ERRORS */
+incomplete_caps:
+  {
+    GST_DEBUG_OBJECT (depayload, "we have incomplete caps,"
+        " doing setcaps later");
+    return TRUE;
+  }
+}
+
+static GstBuffer *
+gst_rtp_h264_depay_allocate_output_buffer (GstRtpH264Depay * depay, gsize size)
+{
+  GstBuffer *buffer = NULL;
+
+  g_return_val_if_fail (size > 0, NULL);
+
+  GST_LOG_OBJECT (depay, "want output buffer of %u bytes", (guint) size);
+
+  buffer = gst_buffer_new_allocate (depay->allocator, size, &depay->params);
+  if (buffer == NULL) {
+    GST_INFO_OBJECT (depay, "couldn't allocate output buffer");
+    buffer = gst_buffer_new_allocate (NULL, size, NULL);
+  }
+
+  return buffer;
+}
+
+static GstBuffer *
+gst_rtp_h264_complete_au (GstRtpH264Depay * rtph264depay,
+    GstClockTime * out_timestamp, gboolean * out_keyframe)
+{
+  GstBufferList *list;
+  GstMapInfo outmap;
+  GstBuffer *outbuf;
+  guint outsize, offset = 0;
+  gint b, n_bufs, m, n_mem;
+
+  /* we had a picture in the adapter and we completed it */
+  GST_DEBUG_OBJECT (rtph264depay, "taking completed AU");
+  outsize = gst_adapter_available (rtph264depay->picture_adapter);
+
+  outbuf = gst_rtp_h264_depay_allocate_output_buffer (rtph264depay, outsize);
+
+  if (outbuf == NULL)
+    return NULL;
+
+  if (!gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE))
+    return NULL;
+
+  list = gst_adapter_take_buffer_list (rtph264depay->picture_adapter, outsize);
+
+  n_bufs = gst_buffer_list_length (list);
+  for (b = 0; b < n_bufs; ++b) {
+    GstBuffer *buf = gst_buffer_list_get (list, b);
+
+    n_mem = gst_buffer_n_memory (buf);
+    for (m = 0; m < n_mem; ++m) {
+      GstMemory *mem = gst_buffer_peek_memory (buf, m);
+      gsize mem_size = gst_memory_get_sizes (mem, NULL, NULL);
+      GstMapInfo mem_map;
+
+      if (gst_memory_map (mem, &mem_map, GST_MAP_READ)) {
+        memcpy (outmap.data + offset, mem_map.data, mem_size);
+        gst_memory_unmap (mem, &mem_map);
+      } else {
+        memset (outmap.data + offset, 0, mem_size);
+      }
+      offset += mem_size;
+    }
+
+    gst_rtp_copy_video_meta (rtph264depay, outbuf, buf);
+  }
+  gst_buffer_list_unref (list);
+  gst_buffer_unmap (outbuf, &outmap);
+
+  *out_timestamp = rtph264depay->last_ts;
+  *out_keyframe = rtph264depay->last_keyframe;
+
+  rtph264depay->last_keyframe = FALSE;
+  rtph264depay->picture_start = FALSE;
+
+  return outbuf;
+}
+
+/* SPS/PPS/IDR considered key, all others DELTA;
+ * so downstream waiting for keyframe can pick up at SPS/PPS/IDR */
+#define NAL_TYPE_IS_KEY(nt) (((nt) == 5) || ((nt) == 7) || ((nt) == 8))
+
+static void
+gst_rtp_h264_depay_handle_nal (GstRtpH264Depay * rtph264depay, GstBuffer * nal,
+    GstClockTime in_timestamp, gboolean marker)
+{
+  GstRTPBaseDepayload *depayload = GST_RTP_BASE_DEPAYLOAD (rtph264depay);
+  gint nal_type;
+  GstMapInfo map;
+  GstBuffer *outbuf = NULL;
+  GstClockTime out_timestamp;
+  gboolean keyframe, out_keyframe;
+
+  gst_buffer_map (nal, &map, GST_MAP_READ);
+  if (G_UNLIKELY (map.size < 5))
+    goto short_nal;
+
+  nal_type = map.data[4] & 0x1f;
+  GST_DEBUG_OBJECT (rtph264depay, "handle NAL type %d", nal_type);
+
+  keyframe = NAL_TYPE_IS_KEY (nal_type);
+
+  out_keyframe = keyframe;
+  out_timestamp = in_timestamp;
+
+  if (!rtph264depay->byte_stream) {
+    if (nal_type == 7 || nal_type == 8) {
+      gst_rtp_h264_depay_add_sps_pps (rtph264depay,
+          gst_buffer_copy_region (nal, GST_BUFFER_COPY_ALL,
+              4, gst_buffer_get_size (nal) - 4));
+      gst_buffer_unmap (nal, &map);
+      gst_buffer_unref (nal);
+      return;
+    } else if (rtph264depay->sps->len == 0 || rtph264depay->pps->len == 0) {
+      /* Down push down any buffer in non-bytestream mode if the SPS/PPS haven't
+       * go through yet
+       */
+      gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
+          gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+              gst_structure_new ("GstForceKeyUnit",
+                  "all-headers", G_TYPE_BOOLEAN, TRUE, NULL)));
+      gst_buffer_unmap (nal, &map);
+      gst_buffer_unref (nal);
+      return;
+    }
+
+    if (rtph264depay->new_codec_data &&
+        rtph264depay->sps->len > 0 && rtph264depay->pps->len > 0)
+      gst_rtp_h264_set_src_caps (rtph264depay);
+  }
+
+
+  if (rtph264depay->merge) {
+    gboolean start = FALSE, complete = FALSE;
+
+    /* marker bit isn't mandatory so in the following code we try to guess
+     * an AU boundary by detecting a new picture start */
+    if (!marker) {
+      /* consider a coded slices (IDR or not) to start a picture,
+       * (so ending the previous one) if first_mb_in_slice == 0
+       * (non-0 is part of previous one) */
+      /* NOTE this is not entirely according to Access Unit specs in 7.4.1.2.4,
+       * but in practice it works in sane cases, needs not much parsing,
+       * and also works with broken frame_num in NAL (where spec-wise would fail) */
+      /* FIXME: this code isn't correct for interlaced content as AUs should be
+       * constructed with pairs of fields and the guess here will just push out
+       * AUs with a single field in it */
+      if (nal_type == 1 || nal_type == 2 || nal_type == 5) {
+        /* we have a picture start */
+        start = TRUE;
+        if (map.data[5] & 0x80) {
+          /* first_mb_in_slice == 0 completes a picture */
+          complete = TRUE;
+        }
+      } else if (nal_type >= 6 && nal_type <= 9) {
+        /* SEI, SPS, PPS, AU terminate picture */
+        complete = TRUE;
+      }
+      GST_DEBUG_OBJECT (depayload, "start %d, complete %d", start, complete);
+
+      if (complete && rtph264depay->picture_start)
+        outbuf = gst_rtp_h264_complete_au (rtph264depay, &out_timestamp,
+            &out_keyframe);
+    }
+    /* add to adapter */
+    gst_buffer_unmap (nal, &map);
+
+    GST_DEBUG_OBJECT (depayload, "adding NAL to picture adapter");
+    gst_adapter_push (rtph264depay->picture_adapter, nal);
+    rtph264depay->last_ts = in_timestamp;
+    rtph264depay->last_keyframe |= keyframe;
+    rtph264depay->picture_start |= start;
+
+    if (marker)
+      outbuf = gst_rtp_h264_complete_au (rtph264depay, &out_timestamp,
+          &out_keyframe);
+  } else {
+    /* no merge, output is input nal */
+    GST_DEBUG_OBJECT (depayload, "using NAL as output");
+    outbuf = nal;
+    gst_buffer_unmap (nal, &map);
+  }
+
+  if (outbuf) {
+    /* prepend codec_data */
+    if (rtph264depay->codec_data) {
+      GST_DEBUG_OBJECT (depayload, "prepending codec_data");
+      gst_rtp_copy_video_meta (rtph264depay, rtph264depay->codec_data, outbuf);
+      outbuf = gst_buffer_append (rtph264depay->codec_data, outbuf);
+      rtph264depay->codec_data = NULL;
+      out_keyframe = TRUE;
+    }
+    outbuf = gst_buffer_make_writable (outbuf);
+
+    gst_rtp_drop_non_video_meta (rtph264depay, outbuf);
+
+    GST_BUFFER_PTS (outbuf) = out_timestamp;
+
+    if (out_keyframe)
+      GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+    else
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+    gst_rtp_base_depayload_push (depayload, outbuf);
+  }
+
+  return;
+
+  /* ERRORS */
+short_nal:
+  {
+    GST_WARNING_OBJECT (depayload, "dropping short NAL");
+    gst_buffer_unmap (nal, &map);
+    gst_buffer_unref (nal);
+    return;
+  }
+}
+
+static void
+gst_rtp_h264_finish_fragmentation_unit (GstRtpH264Depay * rtph264depay)
+{
+  guint outsize;
+  GstMapInfo map;
+  GstBuffer *outbuf;
+
+  outsize = gst_adapter_available (rtph264depay->adapter);
+  outbuf = gst_adapter_take_buffer (rtph264depay->adapter, outsize);
+
+  gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+  GST_DEBUG_OBJECT (rtph264depay, "output %d bytes", outsize);
+
+  if (rtph264depay->byte_stream) {
+    memcpy (map.data, sync_bytes, sizeof (sync_bytes));
+  } else {
+    outsize -= 4;
+    map.data[0] = (outsize >> 24);
+    map.data[1] = (outsize >> 16);
+    map.data[2] = (outsize >> 8);
+    map.data[3] = (outsize);
+  }
+  gst_buffer_unmap (outbuf, &map);
+
+  rtph264depay->current_fu_type = 0;
+
+  gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf,
+      rtph264depay->fu_timestamp, rtph264depay->fu_marker);
+}
+
+static GstBuffer *
+gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpH264Depay *rtph264depay;
+  GstBuffer *outbuf = NULL;
+  guint8 nal_unit_type;
+
+  rtph264depay = GST_RTP_H264_DEPAY (depayload);
+
+  /* flush remaining data on discont */
+  if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
+    gst_adapter_clear (rtph264depay->adapter);
+    rtph264depay->wait_start = TRUE;
+    rtph264depay->current_fu_type = 0;
+  }
+
+  {
+    gint payload_len;
+    guint8 *payload;
+    guint header_len;
+    guint8 nal_ref_idc;
+    GstMapInfo map;
+    guint outsize, nalu_size;
+    GstClockTime timestamp;
+    gboolean marker;
+
+    timestamp = GST_BUFFER_PTS (rtp->buffer);
+
+    payload_len = gst_rtp_buffer_get_payload_len (rtp);
+    payload = gst_rtp_buffer_get_payload (rtp);
+    marker = gst_rtp_buffer_get_marker (rtp);
+
+    GST_DEBUG_OBJECT (rtph264depay, "receiving %d bytes", payload_len);
+
+    if (payload_len == 0)
+      goto empty_packet;
+
+    /* +---------------+
+     * |0|1|2|3|4|5|6|7|
+     * +-+-+-+-+-+-+-+-+
+     * |F|NRI|  Type   |
+     * +---------------+
+     *
+     * F must be 0.
+     */
+    nal_ref_idc = (payload[0] & 0x60) >> 5;
+    nal_unit_type = payload[0] & 0x1f;
+
+    /* at least one byte header with type */
+    header_len = 1;
+
+    GST_DEBUG_OBJECT (rtph264depay, "NRI %d, Type %d", nal_ref_idc,
+        nal_unit_type);
+
+    /* If FU unit was being processed, but the current nal is of a different
+     * type.  Assume that the remote payloader is buggy (didn't set the end bit
+     * when the FU ended) and send out what we gathered thusfar */
+    if (G_UNLIKELY (rtph264depay->current_fu_type != 0 &&
+            nal_unit_type != rtph264depay->current_fu_type))
+      gst_rtp_h264_finish_fragmentation_unit (rtph264depay);
+
+    switch (nal_unit_type) {
+      case 0:
+      case 30:
+      case 31:
+        /* undefined */
+        goto undefined_type;
+      case 25:
+        /* STAP-B    Single-time aggregation packet     5.7.1 */
+        /* 2 byte extra header for DON */
+        header_len += 2;
+        /* fallthrough */
+      case 24:
+      {
+        /* strip headers */
+        payload += header_len;
+        payload_len -= header_len;
+
+        rtph264depay->wait_start = FALSE;
+
+
+        /* STAP-A    Single-time aggregation packet     5.7.1 */
+        while (payload_len > 2) {
+          /*                      1
+           *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+           * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+           * |         NALU Size             |
+           * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+           */
+          nalu_size = (payload[0] << 8) | payload[1];
+
+          /* dont include nalu_size */
+          if (nalu_size > (payload_len - 2))
+            nalu_size = payload_len - 2;
+
+          outsize = nalu_size + sizeof (sync_bytes);
+          outbuf = gst_buffer_new_and_alloc (outsize);
+
+          gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+          if (rtph264depay->byte_stream) {
+            memcpy (map.data, sync_bytes, sizeof (sync_bytes));
+          } else {
+            map.data[0] = map.data[1] = 0;
+            map.data[2] = payload[0];
+            map.data[3] = payload[1];
+          }
+
+          /* strip NALU size */
+          payload += 2;
+          payload_len -= 2;
+
+          memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
+          gst_buffer_unmap (outbuf, &map);
+
+          gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);
+
+          gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf, timestamp,
+              marker);
+
+          payload += nalu_size;
+          payload_len -= nalu_size;
+        }
+        break;
+      }
+      case 26:
+        /* MTAP16    Multi-time aggregation packet      5.7.2 */
+        // header_len = 5;
+        /* fallthrough, not implemented */
+      case 27:
+        /* MTAP24    Multi-time aggregation packet      5.7.2 */
+        // header_len = 6;
+        goto not_implemented;
+        break;
+      case 28:
+      case 29:
+      {
+        /* FU-A      Fragmentation unit                 5.8 */
+        /* FU-B      Fragmentation unit                 5.8 */
+        gboolean S, E;
+
+        /* +---------------+
+         * |0|1|2|3|4|5|6|7|
+         * +-+-+-+-+-+-+-+-+
+         * |S|E|R|  Type   |
+         * +---------------+
+         *
+         * R is reserved and always 0
+         */
+        S = (payload[1] & 0x80) == 0x80;
+        E = (payload[1] & 0x40) == 0x40;
+
+        GST_DEBUG_OBJECT (rtph264depay, "S %d, E %d", S, E);
+
+        if (rtph264depay->wait_start && !S)
+          goto waiting_start;
+
+        if (S) {
+          /* NAL unit starts here */
+          guint8 nal_header;
+
+          /* If a new FU unit started, while still processing an older one.
+           * Assume that the remote payloader is buggy (doesn't set the end
+           * bit) and send out what we've gathered thusfar */
+          if (G_UNLIKELY (rtph264depay->current_fu_type != 0))
+            gst_rtp_h264_finish_fragmentation_unit (rtph264depay);
+
+          rtph264depay->current_fu_type = nal_unit_type;
+          rtph264depay->fu_timestamp = timestamp;
+
+          rtph264depay->wait_start = FALSE;
+
+          /* reconstruct NAL header */
+          nal_header = (payload[0] & 0xe0) | (payload[1] & 0x1f);
+
+          /* strip type header, keep FU header, we'll reuse it to reconstruct
+           * the NAL header. */
+          payload += 1;
+          payload_len -= 1;
+
+          nalu_size = payload_len;
+          outsize = nalu_size + sizeof (sync_bytes);
+          outbuf = gst_buffer_new_and_alloc (outsize);
+
+          gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+          memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
+          map.data[sizeof (sync_bytes)] = nal_header;
+          gst_buffer_unmap (outbuf, &map);
+
+          gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);
+
+          GST_DEBUG_OBJECT (rtph264depay, "queueing %d bytes", outsize);
+
+          /* and assemble in the adapter */
+          gst_adapter_push (rtph264depay->adapter, outbuf);
+        } else {
+          /* strip off FU indicator and FU header bytes */
+          payload += 2;
+          payload_len -= 2;
+
+          outsize = payload_len;
+          outbuf = gst_buffer_new_and_alloc (outsize);
+          gst_buffer_fill (outbuf, 0, payload, outsize);
+
+          gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);
+
+          GST_DEBUG_OBJECT (rtph264depay, "queueing %d bytes", outsize);
+
+          /* and assemble in the adapter */
+          gst_adapter_push (rtph264depay->adapter, outbuf);
+        }
+
+        outbuf = NULL;
+        rtph264depay->fu_marker = marker;
+
+        /* if NAL unit ends, flush the adapter */
+        if (E)
+          gst_rtp_h264_finish_fragmentation_unit (rtph264depay);
+        break;
+      }
+      default:
+      {
+        rtph264depay->wait_start = FALSE;
+
+        /* 1-23   NAL unit  Single NAL unit packet per H.264   5.6 */
+        /* the entire payload is the output buffer */
+        nalu_size = payload_len;
+        outsize = nalu_size + sizeof (sync_bytes);
+        outbuf = gst_buffer_new_and_alloc (outsize);
+
+        gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+        if (rtph264depay->byte_stream) {
+          memcpy (map.data, sync_bytes, sizeof (sync_bytes));
+        } else {
+          map.data[0] = map.data[1] = 0;
+          map.data[2] = nalu_size >> 8;
+          map.data[3] = nalu_size & 0xff;
+        }
+        memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
+        gst_buffer_unmap (outbuf, &map);
+
+        gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);
+
+        gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf, timestamp, marker);
+        break;
+      }
+    }
+  }
+
+  return NULL;
+
+  /* ERRORS */
+empty_packet:
+  {
+    GST_DEBUG_OBJECT (rtph264depay, "empty packet");
+    return NULL;
+  }
+undefined_type:
+  {
+    GST_ELEMENT_WARNING (rtph264depay, STREAM, DECODE,
+        (NULL), ("Undefined packet type"));
+    return NULL;
+  }
+waiting_start:
+  {
+    GST_DEBUG_OBJECT (rtph264depay, "waiting for start");
+    return NULL;
+  }
+not_implemented:
+  {
+    GST_ELEMENT_ERROR (rtph264depay, STREAM, FORMAT,
+        (NULL), ("NAL unit type %d not supported yet", nal_unit_type));
+    return NULL;
+  }
+}
+
+static gboolean
+gst_rtp_h264_depay_handle_event (GstRTPBaseDepayload * depay, GstEvent * event)
+{
+  GstRtpH264Depay *rtph264depay;
+
+  rtph264depay = GST_RTP_H264_DEPAY (depay);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      gst_rtp_h264_depay_reset (rtph264depay, FALSE);
+      break;
+    default:
+      break;
+  }
+
+  return
+      GST_RTP_BASE_DEPAYLOAD_CLASS (parent_class)->handle_event (depay, event);
+}
+
+static GstStateChangeReturn
+gst_rtp_h264_depay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpH264Depay *rtph264depay;
+  GstStateChangeReturn ret;
+
+  rtph264depay = GST_RTP_H264_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_h264_depay_reset (rtph264depay, TRUE);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_h264_depay_reset (rtph264depay, TRUE);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_h264_depay_plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (rtph264depay_debug, "rtph264depay", 0,
+      "H264 Video RTP Depayloader");
+
+  return gst_element_register (plugin, "rtph264depay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_H264_DEPAY);
+}
diff --git a/gst/rtp/gstrtph264depay.h b/gst/rtp/gstrtph264depay.h
new file mode 100644
index 0000000..ba41312
--- /dev/null
+++ b/gst/rtp/gstrtph264depay.h
@@ -0,0 +1,89 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_H264_DEPAY_H__
+#define __GST_RTP_H264_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_H264_DEPAY \
+  (gst_rtp_h264_depay_get_type())
+#define GST_RTP_H264_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H264_DEPAY,GstRtpH264Depay))
+#define GST_RTP_H264_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H264_DEPAY,GstRtpH264DepayClass))
+#define GST_IS_RTP_H264_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H264_DEPAY))
+#define GST_IS_RTP_H264_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H264_DEPAY))
+
+typedef struct _GstRtpH264Depay GstRtpH264Depay;
+typedef struct _GstRtpH264DepayClass GstRtpH264DepayClass;
+
+struct _GstRtpH264Depay
+{
+  GstRTPBaseDepayload depayload;
+
+  gboolean    byte_stream;
+
+  GstBuffer  *codec_data;
+  GstAdapter *adapter;
+  gboolean    wait_start;
+
+  /* nal merging */
+  gboolean    merge;
+  GstAdapter *picture_adapter;
+  gboolean    picture_start;
+  GstClockTime last_ts;
+  gboolean    last_keyframe;
+
+  /* Work around broken payloaders wrt. FU-A & FU-B */
+  guint8 current_fu_type;
+  GstClockTime fu_timestamp;
+  gboolean fu_marker;
+
+  /* misc */
+  GPtrArray *sps;
+  GPtrArray *pps;
+  gboolean new_codec_data;
+
+  /* downstream allocator */
+  GstAllocator *allocator;
+  GstAllocationParams params;
+};
+
+struct _GstRtpH264DepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_h264_depay_get_type (void);
+
+gboolean gst_rtp_h264_depay_plugin_init (GstPlugin * plugin);
+
+gboolean gst_rtp_h264_add_sps_pps (GstElement * rtph264, GPtrArray * sps,
+    GPtrArray * pps, GstBuffer * nal);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_H264_DEPAY_H__ */
diff --git a/gst/rtp/gstrtph264pay.c b/gst/rtp/gstrtph264pay.c
new file mode 100644
index 0000000..73f080a
--- /dev/null
+++ b/gst/rtp/gstrtph264pay.c
@@ -0,0 +1,1424 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab: */
+/* GStreamer
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/pbutils/pbutils.h>
+#include <gst/video/video.h>
+
+/* Included to not duplicate gst_rtp_h264_add_sps_pps () */
+#include "gstrtph264depay.h"
+
+#include "gstrtph264pay.h"
+#include "gstrtputils.h"
+
+
+#define IDR_TYPE_ID  5
+#define SPS_TYPE_ID  7
+#define PPS_TYPE_ID  8
+
+GST_DEBUG_CATEGORY_STATIC (rtph264pay_debug);
+#define GST_CAT_DEFAULT (rtph264pay_debug)
+
+/* references:
+ *
+ * RFC 3984
+ */
+
+static GstStaticPadTemplate gst_rtp_h264_pay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-h264, "
+        "stream-format = (string) avc, alignment = (string) au;"
+        "video/x-h264, "
+        "stream-format = (string) byte-stream, alignment = (string) { nal, au }")
+    );
+
+static GstStaticPadTemplate gst_rtp_h264_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"H264\"")
+    );
+
+#define DEFAULT_SPROP_PARAMETER_SETS    NULL
+#define DEFAULT_CONFIG_INTERVAL		      0
+
+enum
+{
+  PROP_0,
+  PROP_SPROP_PARAMETER_SETS,
+  PROP_CONFIG_INTERVAL
+};
+
+#define IS_ACCESS_UNIT(x) (((x) > 0x00) && ((x) < 0x06))
+
+static void gst_rtp_h264_pay_finalize (GObject * object);
+
+static void gst_rtp_h264_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_h264_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_rtp_h264_pay_getcaps (GstRTPBasePayload * payload,
+    GstPad * pad, GstCaps * filter);
+static gboolean gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload,
+    GstCaps * caps);
+static GstFlowReturn gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * pad,
+    GstBuffer * buffer);
+static gboolean gst_rtp_h264_pay_sink_event (GstRTPBasePayload * payload,
+    GstEvent * event);
+static GstStateChangeReturn gst_rtp_h264_pay_change_state (GstElement *
+    element, GstStateChange transition);
+
+#define gst_rtp_h264_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpH264Pay, gst_rtp_h264_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_h264_pay_class_init (GstRtpH264PayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->set_property = gst_rtp_h264_pay_set_property;
+  gobject_class->get_property = gst_rtp_h264_pay_get_property;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_SPROP_PARAMETER_SETS, g_param_spec_string ("sprop-parameter-sets",
+          "sprop-parameter-sets",
+          "The base64 sprop-parameter-sets to set in out caps (set to NULL to "
+          "extract from stream)",
+          DEFAULT_SPROP_PARAMETER_SETS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_CONFIG_INTERVAL,
+      g_param_spec_int ("config-interval",
+          "SPS PPS Send Interval",
+          "Send SPS and PPS Insertion Interval in seconds (sprop parameter sets "
+          "will be multiplexed in the data stream when detected.) "
+          "(0 = disabled, -1 = send with every IDR frame)",
+          -1, 3600, DEFAULT_CONFIG_INTERVAL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
+  gobject_class->finalize = gst_rtp_h264_pay_finalize;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h264_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h264_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP H264 payloader",
+      "Codec/Payloader/Network/RTP",
+      "Payload-encode H264 video into RTP packets (RFC 3984)",
+      "Laurent Glayal <spglegle@yahoo.fr>");
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_rtp_h264_pay_change_state);
+
+  gstrtpbasepayload_class->get_caps = gst_rtp_h264_pay_getcaps;
+  gstrtpbasepayload_class->set_caps = gst_rtp_h264_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_h264_pay_handle_buffer;
+  gstrtpbasepayload_class->sink_event = gst_rtp_h264_pay_sink_event;
+
+  GST_DEBUG_CATEGORY_INIT (rtph264pay_debug, "rtph264pay", 0,
+      "H264 RTP Payloader");
+}
+
+static void
+gst_rtp_h264_pay_init (GstRtpH264Pay * rtph264pay)
+{
+  rtph264pay->queue = g_array_new (FALSE, FALSE, sizeof (guint));
+  rtph264pay->profile = 0;
+  rtph264pay->sps = g_ptr_array_new_with_free_func (
+      (GDestroyNotify) gst_buffer_unref);
+  rtph264pay->pps = g_ptr_array_new_with_free_func (
+      (GDestroyNotify) gst_buffer_unref);
+  rtph264pay->last_spspps = -1;
+  rtph264pay->spspps_interval = DEFAULT_CONFIG_INTERVAL;
+  rtph264pay->delta_unit = FALSE;
+  rtph264pay->discont = FALSE;
+
+  rtph264pay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_h264_pay_clear_sps_pps (GstRtpH264Pay * rtph264pay)
+{
+  g_ptr_array_set_size (rtph264pay->sps, 0);
+  g_ptr_array_set_size (rtph264pay->pps, 0);
+}
+
+static void
+gst_rtp_h264_pay_finalize (GObject * object)
+{
+  GstRtpH264Pay *rtph264pay;
+
+  rtph264pay = GST_RTP_H264_PAY (object);
+
+  g_array_free (rtph264pay->queue, TRUE);
+
+  g_ptr_array_free (rtph264pay->sps, TRUE);
+  g_ptr_array_free (rtph264pay->pps, TRUE);
+
+  g_free (rtph264pay->sprop_parameter_sets);
+
+  g_object_unref (rtph264pay->adapter);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static const gchar all_levels[][4] = {
+  "1",
+  "1b",
+  "1.1",
+  "1.2",
+  "1.3",
+  "2",
+  "2.1",
+  "2.2",
+  "3",
+  "3.1",
+  "3.2",
+  "4",
+  "4.1",
+  "4.2",
+  "5",
+  "5.1"
+};
+
+static GstCaps *
+gst_rtp_h264_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad,
+    GstCaps * filter)
+{
+  GstCaps *template_caps;
+  GstCaps *allowed_caps;
+  GstCaps *caps, *icaps;
+  gboolean append_unrestricted;
+  guint i;
+
+  allowed_caps =
+      gst_pad_peer_query_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), NULL);
+
+  if (allowed_caps == NULL)
+    return NULL;
+
+  template_caps =
+      gst_static_pad_template_get_caps (&gst_rtp_h264_pay_sink_template);
+
+  if (gst_caps_is_any (allowed_caps)) {
+    caps = gst_caps_ref (template_caps);
+    goto done;
+  }
+
+  if (gst_caps_is_empty (allowed_caps)) {
+    caps = gst_caps_ref (allowed_caps);
+    goto done;
+  }
+
+  caps = gst_caps_new_empty ();
+
+  append_unrestricted = FALSE;
+  for (i = 0; i < gst_caps_get_size (allowed_caps); i++) {
+    GstStructure *s = gst_caps_get_structure (allowed_caps, i);
+    GstStructure *new_s = gst_structure_new_empty ("video/x-h264");
+    const gchar *profile_level_id;
+
+    profile_level_id = gst_structure_get_string (s, "profile-level-id");
+
+    if (profile_level_id && strlen (profile_level_id) == 6) {
+      const gchar *profile;
+      const gchar *level;
+      long int spsint;
+      guint8 sps[3];
+
+      spsint = strtol (profile_level_id, NULL, 16);
+      sps[0] = spsint >> 16;
+      sps[1] = spsint >> 8;
+      sps[2] = spsint;
+
+      profile = gst_codec_utils_h264_get_profile (sps, 3);
+      level = gst_codec_utils_h264_get_level (sps, 3);
+
+      if (profile && level) {
+        GST_LOG_OBJECT (payload, "In caps, have profile %s and level %s",
+            profile, level);
+
+        if (!strcmp (profile, "constrained-baseline"))
+          gst_structure_set (new_s, "profile", G_TYPE_STRING, profile, NULL);
+        else {
+          GValue val = { 0, };
+          GValue profiles = { 0, };
+
+          g_value_init (&profiles, GST_TYPE_LIST);
+          g_value_init (&val, G_TYPE_STRING);
+
+          g_value_set_static_string (&val, profile);
+          gst_value_list_append_value (&profiles, &val);
+
+          g_value_set_static_string (&val, "constrained-baseline");
+          gst_value_list_append_value (&profiles, &val);
+
+          gst_structure_take_value (new_s, "profile", &profiles);
+        }
+
+        if (!strcmp (level, "1"))
+          gst_structure_set (new_s, "level", G_TYPE_STRING, level, NULL);
+        else {
+          GValue levels = { 0, };
+          GValue val = { 0, };
+          int j;
+
+          g_value_init (&levels, GST_TYPE_LIST);
+          g_value_init (&val, G_TYPE_STRING);
+
+          for (j = 0; j < G_N_ELEMENTS (all_levels); j++) {
+            g_value_set_static_string (&val, all_levels[j]);
+            gst_value_list_prepend_value (&levels, &val);
+            if (!strcmp (level, all_levels[j]))
+              break;
+          }
+          gst_structure_take_value (new_s, "level", &levels);
+        }
+      } else {
+        /* Invalid profile-level-id means baseline */
+
+        gst_structure_set (new_s,
+            "profile", G_TYPE_STRING, "constrained-baseline", NULL);
+      }
+    } else {
+      /* No profile-level-id means baseline or unrestricted */
+
+      gst_structure_set (new_s,
+          "profile", G_TYPE_STRING, "constrained-baseline", NULL);
+      append_unrestricted = TRUE;
+    }
+
+    caps = gst_caps_merge_structure (caps, new_s);
+  }
+
+  if (append_unrestricted) {
+    caps =
+        gst_caps_merge_structure (caps, gst_structure_new ("video/x-h264", NULL,
+            NULL));
+  }
+
+  icaps = gst_caps_intersect (caps, template_caps);
+  gst_caps_unref (caps);
+  caps = icaps;
+
+done:
+  if (filter) {
+    GST_DEBUG_OBJECT (payload, "Intersect %" GST_PTR_FORMAT " and filter %"
+        GST_PTR_FORMAT, caps, filter);
+    icaps = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    caps = icaps;
+  }
+
+  gst_caps_unref (template_caps);
+  gst_caps_unref (allowed_caps);
+
+  GST_LOG_OBJECT (payload, "returning caps %" GST_PTR_FORMAT, caps);
+  return caps;
+}
+
+/* take the currently configured SPS and PPS lists and set them on the caps as
+ * sprop-parameter-sets */
+static gboolean
+gst_rtp_h264_pay_set_sps_pps (GstRTPBasePayload * basepayload)
+{
+  GstRtpH264Pay *payloader = GST_RTP_H264_PAY (basepayload);
+  gchar *profile;
+  gchar *set;
+  GString *sprops;
+  guint count;
+  gboolean res;
+  GstMapInfo map;
+  guint i;
+
+  sprops = g_string_new ("");
+  count = 0;
+
+  /* build the sprop-parameter-sets */
+  for (i = 0; i < payloader->sps->len; i++) {
+    GstBuffer *sps_buf =
+        GST_BUFFER_CAST (g_ptr_array_index (payloader->sps, i));
+
+    gst_buffer_map (sps_buf, &map, GST_MAP_READ);
+    set = g_base64_encode (map.data, map.size);
+    gst_buffer_unmap (sps_buf, &map);
+
+    g_string_append_printf (sprops, "%s%s", count ? "," : "", set);
+    g_free (set);
+    count++;
+  }
+  for (i = 0; i < payloader->pps->len; i++) {
+    GstBuffer *pps_buf =
+        GST_BUFFER_CAST (g_ptr_array_index (payloader->pps, i));
+
+    gst_buffer_map (pps_buf, &map, GST_MAP_READ);
+    set = g_base64_encode (map.data, map.size);
+    gst_buffer_unmap (pps_buf, &map);
+
+    g_string_append_printf (sprops, "%s%s", count ? "," : "", set);
+    g_free (set);
+    count++;
+  }
+
+  if (G_LIKELY (count)) {
+    if (payloader->profile != 0) {
+      /* profile is 24 bit. Force it to respect the limit */
+      profile = g_strdup_printf ("%06x", payloader->profile & 0xffffff);
+      /* combine into output caps */
+      res = gst_rtp_base_payload_set_outcaps (basepayload,
+          "packetization-mode", G_TYPE_STRING, "1",
+          "profile-level-id", G_TYPE_STRING, profile,
+          "sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL);
+      g_free (profile);
+    } else {
+      res = gst_rtp_base_payload_set_outcaps (basepayload,
+          "packetization-mode", G_TYPE_STRING, "1",
+          "sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL);
+    }
+
+  } else {
+    res = gst_rtp_base_payload_set_outcaps (basepayload, NULL);
+  }
+  g_string_free (sprops, TRUE);
+
+  return res;
+}
+
+
+static gboolean
+gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+  GstRtpH264Pay *rtph264pay;
+  GstStructure *str;
+  const GValue *value;
+  GstMapInfo map;
+  guint8 *data;
+  gsize size;
+  GstBuffer *buffer;
+  const gchar *alignment, *stream_format;
+
+  rtph264pay = GST_RTP_H264_PAY (basepayload);
+
+  str = gst_caps_get_structure (caps, 0);
+
+  /* we can only set the output caps when we found the sprops and profile
+   * NALs */
+  gst_rtp_base_payload_set_options (basepayload, "video", TRUE, "H264", 90000);
+
+  rtph264pay->alignment = GST_H264_ALIGNMENT_UNKNOWN;
+  alignment = gst_structure_get_string (str, "alignment");
+  if (alignment) {
+    if (g_str_equal (alignment, "au"))
+      rtph264pay->alignment = GST_H264_ALIGNMENT_AU;
+    if (g_str_equal (alignment, "nal"))
+      rtph264pay->alignment = GST_H264_ALIGNMENT_NAL;
+  }
+
+  rtph264pay->stream_format = GST_H264_STREAM_FORMAT_UNKNOWN;
+  stream_format = gst_structure_get_string (str, "stream-format");
+  if (stream_format) {
+    if (g_str_equal (stream_format, "avc"))
+      rtph264pay->stream_format = GST_H264_STREAM_FORMAT_AVC;
+    if (g_str_equal (stream_format, "byte-stream"))
+      rtph264pay->stream_format = GST_H264_STREAM_FORMAT_BYTESTREAM;
+  }
+
+  /* packetized AVC video has a codec_data */
+  if ((value = gst_structure_get_value (str, "codec_data"))) {
+    guint num_sps, num_pps;
+    gint i, nal_size;
+
+    GST_DEBUG_OBJECT (rtph264pay, "have packetized h264");
+
+    buffer = gst_value_get_buffer (value);
+
+    gst_buffer_map (buffer, &map, GST_MAP_READ);
+    data = map.data;
+    size = map.size;
+
+    /* parse the avcC data */
+    if (size < 7)
+      goto avcc_too_small;
+    /* parse the version, this must be 1 */
+    if (data[0] != 1)
+      goto wrong_version;
+
+    /* AVCProfileIndication */
+    /* profile_compat */
+    /* AVCLevelIndication */
+    rtph264pay->profile = (data[1] << 16) | (data[2] << 8) | data[3];
+    GST_DEBUG_OBJECT (rtph264pay, "profile %06x", rtph264pay->profile);
+
+    /* 6 bits reserved | 2 bits lengthSizeMinusOne */
+    /* this is the number of bytes in front of the NAL units to mark their
+     * length */
+    rtph264pay->nal_length_size = (data[4] & 0x03) + 1;
+    GST_DEBUG_OBJECT (rtph264pay, "nal length %u", rtph264pay->nal_length_size);
+    /* 3 bits reserved | 5 bits numOfSequenceParameterSets */
+    num_sps = data[5] & 0x1f;
+    GST_DEBUG_OBJECT (rtph264pay, "num SPS %u", num_sps);
+
+    data += 6;
+    size -= 6;
+
+    /* create the sprop-parameter-sets */
+    for (i = 0; i < num_sps; i++) {
+      GstBuffer *sps_buf;
+
+      if (size < 2)
+        goto avcc_error;
+
+      nal_size = (data[0] << 8) | data[1];
+      data += 2;
+      size -= 2;
+
+      GST_LOG_OBJECT (rtph264pay, "SPS %d size %d", i, nal_size);
+
+      if (size < nal_size)
+        goto avcc_error;
+
+      /* make a buffer out of it and add to SPS list */
+      sps_buf = gst_buffer_new_and_alloc (nal_size);
+      gst_buffer_fill (sps_buf, 0, data, nal_size);
+      gst_rtp_h264_add_sps_pps (GST_ELEMENT (rtph264pay), rtph264pay->sps,
+          rtph264pay->pps, sps_buf);
+      data += nal_size;
+      size -= nal_size;
+    }
+    if (size < 1)
+      goto avcc_error;
+
+    /* 8 bits numOfPictureParameterSets */
+    num_pps = data[0];
+    data += 1;
+    size -= 1;
+
+    GST_DEBUG_OBJECT (rtph264pay, "num PPS %u", num_pps);
+    for (i = 0; i < num_pps; i++) {
+      GstBuffer *pps_buf;
+
+      if (size < 2)
+        goto avcc_error;
+
+      nal_size = (data[0] << 8) | data[1];
+      data += 2;
+      size -= 2;
+
+      GST_LOG_OBJECT (rtph264pay, "PPS %d size %d", i, nal_size);
+
+      if (size < nal_size)
+        goto avcc_error;
+
+      /* make a buffer out of it and add to PPS list */
+      pps_buf = gst_buffer_new_and_alloc (nal_size);
+      gst_buffer_fill (pps_buf, 0, data, nal_size);
+      gst_rtp_h264_add_sps_pps (GST_ELEMENT (rtph264pay), rtph264pay->sps,
+          rtph264pay->pps, pps_buf);
+
+      data += nal_size;
+      size -= nal_size;
+    }
+
+    /* and update the caps with the collected data */
+    if (!gst_rtp_h264_pay_set_sps_pps (basepayload))
+      goto set_sps_pps_failed;
+
+    gst_buffer_unmap (buffer, &map);
+  } else {
+    GST_DEBUG_OBJECT (rtph264pay, "have bytestream h264");
+  }
+
+  return TRUE;
+
+avcc_too_small:
+  {
+    GST_ERROR_OBJECT (rtph264pay, "avcC size %" G_GSIZE_FORMAT " < 7", size);
+    goto error;
+  }
+wrong_version:
+  {
+    GST_ERROR_OBJECT (rtph264pay, "wrong avcC version");
+    goto error;
+  }
+avcc_error:
+  {
+    GST_ERROR_OBJECT (rtph264pay, "avcC too small ");
+    goto error;
+  }
+set_sps_pps_failed:
+  {
+    GST_ERROR_OBJECT (rtph264pay, "failed to set sps/pps");
+    goto error;
+  }
+error:
+  {
+    gst_buffer_unmap (buffer, &map);
+    return FALSE;
+  }
+}
+
+static void
+gst_rtp_h264_pay_parse_sprop_parameter_sets (GstRtpH264Pay * rtph264pay)
+{
+  const gchar *ps;
+  gchar **params;
+  guint len;
+  gint i;
+  GstBuffer *buf;
+
+  ps = rtph264pay->sprop_parameter_sets;
+  if (ps == NULL)
+    return;
+
+  gst_rtp_h264_pay_clear_sps_pps (rtph264pay);
+
+  params = g_strsplit (ps, ",", 0);
+  len = g_strv_length (params);
+
+  GST_DEBUG_OBJECT (rtph264pay, "we have %d params", len);
+
+  for (i = 0; params[i]; i++) {
+    gsize nal_len;
+    GstMapInfo map;
+    guint8 *nalp;
+    guint save = 0;
+    gint state = 0;
+
+    nal_len = strlen (params[i]);
+    buf = gst_buffer_new_and_alloc (nal_len);
+
+    gst_buffer_map (buf, &map, GST_MAP_WRITE);
+    nalp = map.data;
+    nal_len = g_base64_decode_step (params[i], nal_len, nalp, &state, &save);
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_resize (buf, 0, nal_len);
+
+    if (!nal_len) {
+      gst_buffer_unref (buf);
+      continue;
+    }
+
+    gst_rtp_h264_add_sps_pps (GST_ELEMENT (rtph264pay), rtph264pay->sps,
+        rtph264pay->pps, buf);
+  }
+  g_strfreev (params);
+}
+
+static guint
+next_start_code (const guint8 * data, guint size)
+{
+  /* Boyer-Moore string matching algorithm, in a degenerative
+   * sense because our search 'alphabet' is binary - 0 & 1 only.
+   * This allow us to simplify the general BM algorithm to a very
+   * simple form. */
+  /* assume 1 is in the 3th byte */
+  guint offset = 2;
+
+  while (offset < size) {
+    if (1 == data[offset]) {
+      unsigned int shift = offset;
+
+      if (0 == data[--shift]) {
+        if (0 == data[--shift]) {
+          return shift;
+        }
+      }
+      /* The jump is always 3 because of the 1 previously matched.
+       * All the 0's must be after this '1' matched at offset */
+      offset += 3;
+    } else if (0 == data[offset]) {
+      /* maybe next byte is 1? */
+      offset++;
+    } else {
+      /* can jump 3 bytes forward */
+      offset += 3;
+    }
+    /* at each iteration, we rescan in a backward manner until
+     * we match 0.0.1 in reverse order. Since our search string
+     * has only 2 'alpabets' (i.e. 0 & 1), we know that any
+     * mismatch will force us to shift a fixed number of steps */
+  }
+  GST_DEBUG ("Cannot find next NAL start code. returning %u", size);
+
+  return size;
+}
+
+static gboolean
+gst_rtp_h264_pay_decode_nal (GstRtpH264Pay * payloader,
+    const guint8 * data, guint size, GstClockTime dts, GstClockTime pts)
+{
+  guint8 header, type;
+  gboolean updated;
+
+  /* default is no update */
+  updated = FALSE;
+
+  GST_DEBUG ("NAL payload len=%u", size);
+
+  header = data[0];
+  type = header & 0x1f;
+
+  /* We record the timestamp of the last SPS/PPS so
+   * that we can insert them at regular intervals and when needed. */
+  if (SPS_TYPE_ID == type || PPS_TYPE_ID == type) {
+    GstBuffer *nal;
+
+    /* trailing 0x0 are not part of the SPS/PPS */
+    while (size > 0 && data[size - 1] == 0x0)
+      size--;
+
+    /* encode the entire SPS NAL in base64 */
+    GST_DEBUG ("Found %s %x %x %x Len=%u", type == SPS_TYPE_ID ? "SPS" : "PPS",
+        (header >> 7), (header >> 5) & 3, type, size);
+
+    nal = gst_buffer_new_allocate (NULL, size, NULL);
+    gst_buffer_fill (nal, 0, data, size);
+
+    updated = gst_rtp_h264_add_sps_pps (GST_ELEMENT (payloader),
+        payloader->sps, payloader->pps, nal);
+
+    /* remember when we last saw SPS */
+    if (updated && pts != -1)
+      payloader->last_spspps = pts;
+  } else {
+    GST_DEBUG ("NAL: %x %x %x Len = %u", (header >> 7),
+        (header >> 5) & 3, type, size);
+  }
+
+  return updated;
+}
+
+static GstFlowReturn
+gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
+    GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
+    gboolean delta_unit, gboolean discont);
+
+static GstFlowReturn
+gst_rtp_h264_pay_send_sps_pps (GstRTPBasePayload * basepayload,
+    GstRtpH264Pay * rtph264pay, GstClockTime dts, GstClockTime pts)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  gboolean sent_all_sps_pps = TRUE;
+  guint i;
+
+  for (i = 0; i < rtph264pay->sps->len; i++) {
+    GstBuffer *sps_buf =
+        GST_BUFFER_CAST (g_ptr_array_index (rtph264pay->sps, i));
+
+    GST_DEBUG_OBJECT (rtph264pay, "inserting SPS in the stream");
+    /* resend SPS */
+    ret = gst_rtp_h264_pay_payload_nal (basepayload, gst_buffer_ref (sps_buf),
+        dts, pts, FALSE, FALSE, FALSE);
+    /* Not critical here; but throw a warning */
+    if (ret != GST_FLOW_OK) {
+      sent_all_sps_pps = FALSE;
+      GST_WARNING_OBJECT (basepayload, "Problem pushing SPS");
+    }
+  }
+  for (i = 0; i < rtph264pay->pps->len; i++) {
+    GstBuffer *pps_buf =
+        GST_BUFFER_CAST (g_ptr_array_index (rtph264pay->pps, i));
+
+    GST_DEBUG_OBJECT (rtph264pay, "inserting PPS in the stream");
+    /* resend PPS */
+    ret = gst_rtp_h264_pay_payload_nal (basepayload, gst_buffer_ref (pps_buf),
+        dts, pts, FALSE, FALSE, FALSE);
+    /* Not critical here; but throw a warning */
+    if (ret != GST_FLOW_OK) {
+      sent_all_sps_pps = FALSE;
+      GST_WARNING_OBJECT (basepayload, "Problem pushing PPS");
+    }
+  }
+
+  if (pts != -1 && sent_all_sps_pps)
+    rtph264pay->last_spspps = pts;
+
+  return ret;
+}
+
+/* @delta_unit: if %FALSE the first packet sent won't have the
+ * GST_BUFFER_FLAG_DELTA_UNIT flag.
+ * @discont: if %TRUE the first packet sent will have the
+ * GST_BUFFER_FLAG_DISCONT flag.
+ */
+static GstFlowReturn
+gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
+    GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
+    gboolean delta_unit, gboolean discont)
+{
+  GstRtpH264Pay *rtph264pay;
+  GstFlowReturn ret;
+  guint8 nalHeader;
+  guint8 nalType;
+  guint packet_len, payload_len, mtu;
+  GstBuffer *outbuf;
+  guint8 *payload;
+  GstBufferList *list = NULL;
+  gboolean send_spspps;
+  GstRTPBuffer rtp = { NULL };
+  guint size = gst_buffer_get_size (paybuf);
+
+  rtph264pay = GST_RTP_H264_PAY (basepayload);
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (rtph264pay);
+
+  gst_buffer_extract (paybuf, 0, &nalHeader, 1);
+  nalType = nalHeader & 0x1f;
+
+  GST_DEBUG_OBJECT (rtph264pay, "Processing Buffer with NAL TYPE=%d", nalType);
+
+  /* should set src caps before pushing stuff,
+   * and if we did not see enough SPS/PPS, that may not be the case */
+  if (G_UNLIKELY (!gst_pad_has_current_caps (GST_RTP_BASE_PAYLOAD_SRCPAD
+              (basepayload))))
+    gst_rtp_h264_pay_set_sps_pps (basepayload);
+
+  send_spspps = FALSE;
+
+  /* check if we need to emit an SPS/PPS now */
+  if (nalType == IDR_TYPE_ID && rtph264pay->spspps_interval > 0) {
+    if (rtph264pay->last_spspps != -1) {
+      guint64 diff;
+
+      GST_LOG_OBJECT (rtph264pay,
+          "now %" GST_TIME_FORMAT ", last SPS/PPS %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (pts), GST_TIME_ARGS (rtph264pay->last_spspps));
+
+      /* calculate diff between last SPS/PPS in milliseconds */
+      if (pts > rtph264pay->last_spspps)
+        diff = pts - rtph264pay->last_spspps;
+      else
+        diff = 0;
+
+      GST_DEBUG_OBJECT (rtph264pay,
+          "interval since last SPS/PPS %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (diff));
+
+      /* bigger than interval, queue SPS/PPS */
+      if (GST_TIME_AS_SECONDS (diff) >= rtph264pay->spspps_interval) {
+        GST_DEBUG_OBJECT (rtph264pay, "time to send SPS/PPS");
+        send_spspps = TRUE;
+      }
+    } else {
+      /* no know previous SPS/PPS time, send now */
+      GST_DEBUG_OBJECT (rtph264pay, "no previous SPS/PPS time, send now");
+      send_spspps = TRUE;
+    }
+  } else if (nalType == IDR_TYPE_ID && rtph264pay->spspps_interval == -1) {
+    GST_DEBUG_OBJECT (rtph264pay, "sending SPS/PPS before current IDR frame");
+    /* send SPS/PPS before every IDR frame */
+    send_spspps = TRUE;
+  }
+
+  if (send_spspps || rtph264pay->send_spspps) {
+    /* we need to send SPS/PPS now first. FIXME, don't use the pts for
+     * checking when we need to send SPS/PPS but convert to running_time first. */
+    rtph264pay->send_spspps = FALSE;
+    ret = gst_rtp_h264_pay_send_sps_pps (basepayload, rtph264pay, dts, pts);
+    if (ret != GST_FLOW_OK) {
+      gst_buffer_unref (paybuf);
+      return ret;
+    }
+  }
+
+  packet_len = gst_rtp_buffer_calc_packet_len (size, 0, 0);
+
+  if (packet_len < mtu) {
+    /* will fit in one packet */
+    GST_DEBUG_OBJECT (basepayload,
+        "NAL Unit fit in one packet datasize=%d mtu=%d", size, mtu);
+
+    /* create buffer without payload containing only the RTP header
+     * (memory block at index 0) */
+    outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+
+    gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+    /* only set the marker bit on packets containing access units */
+    if (IS_ACCESS_UNIT (nalType) && end_of_au) {
+      gst_rtp_buffer_set_marker (&rtp, 1);
+    }
+
+    /* timestamp the outbuffer */
+    GST_BUFFER_PTS (outbuf) = pts;
+    GST_BUFFER_DTS (outbuf) = dts;
+
+    if (!delta_unit)
+      /* Only the first packet sent should not have the flag */
+      delta_unit = TRUE;
+    else
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+    if (discont) {
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+      /* Only the first packet sent should have the flag */
+      discont = FALSE;
+    }
+
+    gst_rtp_buffer_unmap (&rtp);
+
+    /* insert payload memory block */
+    gst_rtp_copy_video_meta (rtph264pay, outbuf, paybuf);
+    outbuf = gst_buffer_append (outbuf, paybuf);
+
+    /* push the buffer to the next element */
+    ret = gst_rtp_base_payload_push (basepayload, outbuf);
+  } else {
+    /* fragmentation Units FU-A */
+    guint limitedSize;
+    int ii = 0, start = 1, end = 0, pos = 0;
+
+    GST_DEBUG_OBJECT (basepayload,
+        "NAL Unit DOES NOT fit in one packet datasize=%d mtu=%d", size, mtu);
+
+    pos++;
+    size--;
+
+    ret = GST_FLOW_OK;
+
+    GST_DEBUG_OBJECT (basepayload, "Using FU-A fragmentation for data size=%d",
+        size);
+
+    /* We keep 2 bytes for FU indicator and FU Header */
+    payload_len = gst_rtp_buffer_calc_payload_len (mtu - 2, 0, 0);
+
+    list = gst_buffer_list_new_sized ((size / payload_len) + 1);
+
+    while (end == 0) {
+      limitedSize = size < payload_len ? size : payload_len;
+      GST_DEBUG_OBJECT (basepayload,
+          "Inside  FU-A fragmentation limitedSize=%d iteration=%d", limitedSize,
+          ii);
+
+      /* use buffer lists
+       * create buffer without payload containing only the RTP header
+       * (memory block at index 0) */
+      outbuf = gst_rtp_buffer_new_allocate (2, 0, 0);
+
+      gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+      GST_BUFFER_DTS (outbuf) = dts;
+      GST_BUFFER_PTS (outbuf) = pts;
+      payload = gst_rtp_buffer_get_payload (&rtp);
+
+      if (limitedSize == size) {
+        GST_DEBUG_OBJECT (basepayload, "end size=%d iteration=%d", size, ii);
+        end = 1;
+      }
+      if (IS_ACCESS_UNIT (nalType)) {
+        gst_rtp_buffer_set_marker (&rtp, end && end_of_au);
+      }
+
+      /* FU indicator */
+      payload[0] = (nalHeader & 0x60) | 28;
+
+      /* FU Header */
+      payload[1] = (start << 7) | (end << 6) | (nalHeader & 0x1f);
+
+      gst_rtp_buffer_unmap (&rtp);
+
+      /* insert payload memory block */
+      gst_rtp_copy_video_meta (rtph264pay, outbuf, paybuf);
+      gst_buffer_copy_into (outbuf, paybuf, GST_BUFFER_COPY_MEMORY, pos,
+          limitedSize);
+
+      if (!delta_unit)
+        /* Only the first packet sent should not have the flag */
+        delta_unit = TRUE;
+      else
+        GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+      if (discont) {
+        GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+        /* Only the first packet sent should have the flag */
+        discont = FALSE;
+      }
+
+      /* add the buffer to the buffer list */
+      gst_buffer_list_add (list, outbuf);
+
+
+      size -= limitedSize;
+      pos += limitedSize;
+      ii++;
+      start = 0;
+    }
+
+    ret = gst_rtp_base_payload_push_list (basepayload, list);
+    gst_buffer_unref (paybuf);
+  }
+  return ret;
+}
+
+static GstFlowReturn
+gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpH264Pay *rtph264pay;
+  GstFlowReturn ret;
+  gsize size;
+  guint nal_len, i;
+  GstMapInfo map;
+  const guint8 *data;
+  GstClockTime dts, pts;
+  GArray *nal_queue;
+  gboolean avc;
+  GstBuffer *paybuf = NULL;
+  gsize skip;
+  gboolean delayed_not_delta_unit = FALSE;
+  gboolean delayed_discont = FALSE;
+
+  rtph264pay = GST_RTP_H264_PAY (basepayload);
+
+  /* the input buffer contains one or more NAL units */
+
+  avc = rtph264pay->stream_format == GST_H264_STREAM_FORMAT_AVC;
+
+  if (avc) {
+    /* In AVC mode, there is no adapter, so nothign to flush */
+    if (buffer == NULL)
+      return GST_FLOW_OK;
+    gst_buffer_map (buffer, &map, GST_MAP_READ);
+    data = map.data;
+    size = map.size;
+    pts = GST_BUFFER_PTS (buffer);
+    dts = GST_BUFFER_DTS (buffer);
+    rtph264pay->delta_unit = GST_BUFFER_FLAG_IS_SET (buffer,
+        GST_BUFFER_FLAG_DELTA_UNIT);
+    rtph264pay->discont = GST_BUFFER_IS_DISCONT (buffer);
+    GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes", size);
+  } else {
+    dts = gst_adapter_prev_dts (rtph264pay->adapter, NULL);
+    pts = gst_adapter_prev_pts (rtph264pay->adapter, NULL);
+    if (buffer) {
+      if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
+        if (gst_adapter_available (rtph264pay->adapter) == 0)
+          rtph264pay->delta_unit = FALSE;
+        else
+          /* This buffer contains a key frame but the adapter isn't empty. So
+           * we'll purge it first by sending a first packet and then the second
+           * one won't have the DELTA_UNIT flag. */
+          delayed_not_delta_unit = TRUE;
+      }
+
+      if (GST_BUFFER_IS_DISCONT (buffer)) {
+        if (gst_adapter_available (rtph264pay->adapter) == 0)
+          rtph264pay->discont = TRUE;
+        else
+          /* This buffer has the DISCONT flag but the adapter isn't empty. So
+           * we'll purge it first by sending a first packet and then the second
+           * one will have the DISCONT flag set. */
+          delayed_discont = TRUE;
+      }
+
+      if (!GST_CLOCK_TIME_IS_VALID (dts))
+        dts = GST_BUFFER_DTS (buffer);
+      if (!GST_CLOCK_TIME_IS_VALID (pts))
+        pts = GST_BUFFER_PTS (buffer);
+
+      gst_adapter_push (rtph264pay->adapter, buffer);
+    }
+    size = gst_adapter_available (rtph264pay->adapter);
+    /* Nothing to do here if the adapter is empty, e.g. on EOS */
+    if (size == 0)
+      return GST_FLOW_OK;
+    data = gst_adapter_map (rtph264pay->adapter, size);
+    GST_DEBUG_OBJECT (basepayload,
+        "got %" G_GSIZE_FORMAT " bytes (%" G_GSIZE_FORMAT ")", size,
+        buffer ? gst_buffer_get_size (buffer) : 0);
+  }
+
+  ret = GST_FLOW_OK;
+
+  /* now loop over all NAL units and put them in a packet
+   * FIXME, we should really try to pack multiple NAL units into one RTP packet
+   * if we can, especially for the config packets that wont't cause decoder 
+   * latency. */
+  if (avc) {
+    guint nal_length_size;
+    gsize offset = 0;
+
+    nal_length_size = rtph264pay->nal_length_size;
+
+    while (size > nal_length_size) {
+      gint i;
+      gboolean end_of_au = FALSE;
+
+      nal_len = 0;
+      for (i = 0; i < nal_length_size; i++) {
+        nal_len = ((nal_len << 8) + data[i]);
+      }
+
+      /* skip the length bytes, make sure we don't run past the buffer size */
+      data += nal_length_size;
+      offset += nal_length_size;
+      size -= nal_length_size;
+
+      if (size >= nal_len) {
+        GST_DEBUG_OBJECT (basepayload, "got NAL of size %u", nal_len);
+      } else {
+        nal_len = size;
+        GST_DEBUG_OBJECT (basepayload, "got incomplete NAL of size %u",
+            nal_len);
+      }
+
+      /* If we're at the end of the buffer, then we're at the end of the
+       * access unit
+       */
+      if (rtph264pay->alignment == GST_H264_ALIGNMENT_AU
+          && size - nal_len <= nal_length_size) {
+        end_of_au = TRUE;
+      }
+
+      paybuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset,
+          nal_len);
+      ret =
+          gst_rtp_h264_pay_payload_nal (basepayload, paybuf, dts, pts,
+          end_of_au, rtph264pay->delta_unit, rtph264pay->discont);
+
+      if (!rtph264pay->delta_unit)
+        /* Only the first outgoing packet doesn't have the DELTA_UNIT flag */
+        rtph264pay->delta_unit = TRUE;
+
+      if (rtph264pay->discont)
+        /* Only the first outgoing packet have the DISCONT flag */
+        rtph264pay->discont = FALSE;
+
+      if (ret != GST_FLOW_OK)
+        break;
+
+      data += nal_len;
+      offset += nal_len;
+      size -= nal_len;
+    }
+  } else {
+    guint next;
+    gboolean update = FALSE;
+
+    /* get offset of first start code */
+    next = next_start_code (data, size);
+
+    /* skip to start code, if no start code is found, next will be size and we
+     * will not collect data. */
+    data += next;
+    size -= next;
+    nal_queue = rtph264pay->queue;
+    skip = next;
+
+    /* array must be empty when we get here */
+    g_assert (nal_queue->len == 0);
+
+    GST_DEBUG_OBJECT (basepayload,
+        "found first start at %u, bytes left %" G_GSIZE_FORMAT, next, size);
+
+    /* first pass to locate NALs and parse SPS/PPS */
+    while (size > 4) {
+      /* skip start code */
+      data += 3;
+      size -= 3;
+
+      /* use next_start_code() to scan buffer.
+       * next_start_code() returns the offset in data, 
+       * starting from zero to the first byte of 0.0.0.1
+       * If no start code is found, it returns the value of the 
+       * 'size' parameter. 
+       * data is unchanged by the call to next_start_code()
+       */
+      next = next_start_code (data, size);
+
+      /* nal or au aligned input needs no delaying until next time */
+      if (next == size && buffer != NULL &&
+          rtph264pay->alignment == GST_H264_ALIGNMENT_UNKNOWN) {
+        /* Didn't find the start of next NAL and it's not EOS,
+         * handle it next time */
+        break;
+      }
+
+      /* nal length is distance to next start code */
+      nal_len = next;
+
+      GST_DEBUG_OBJECT (basepayload, "found next start at %u of size %u", next,
+          nal_len);
+
+      if (rtph264pay->sprop_parameter_sets != NULL) {
+        /* explicitly set profile and sprop, use those */
+        if (rtph264pay->update_caps) {
+          if (!gst_rtp_base_payload_set_outcaps (basepayload,
+                  "sprop-parameter-sets", G_TYPE_STRING,
+                  rtph264pay->sprop_parameter_sets, NULL))
+            goto caps_rejected;
+
+          /* parse SPS and PPS from provided parameter set (for insertion) */
+          gst_rtp_h264_pay_parse_sprop_parameter_sets (rtph264pay);
+
+          rtph264pay->update_caps = FALSE;
+
+          GST_DEBUG ("outcaps update: sprop-parameter-sets=%s",
+              rtph264pay->sprop_parameter_sets);
+        }
+      } else {
+        /* We know our stream is a valid H264 NAL packet,
+         * go parse it for SPS/PPS to enrich the caps */
+        /* order: make sure to check nal */
+        update =
+            gst_rtp_h264_pay_decode_nal (rtph264pay, data, nal_len, dts, pts)
+            || update;
+      }
+      /* move to next NAL packet */
+      data += nal_len;
+      size -= nal_len;
+
+      g_array_append_val (nal_queue, nal_len);
+    }
+
+    /* if has new SPS & PPS, update the output caps */
+    if (G_UNLIKELY (update))
+      if (!gst_rtp_h264_pay_set_sps_pps (basepayload))
+        goto caps_rejected;
+
+    /* second pass to payload and push */
+
+    if (nal_queue->len != 0)
+      gst_adapter_flush (rtph264pay->adapter, skip);
+
+    for (i = 0; i < nal_queue->len; i++) {
+      guint size;
+      gboolean end_of_au = FALSE;
+
+      nal_len = g_array_index (nal_queue, guint, i);
+      /* skip start code */
+      gst_adapter_flush (rtph264pay->adapter, 3);
+
+      /* Trim the end unless we're the last NAL in the stream.
+       * In case we're not at the end of the buffer we know the next block
+       * starts with 0x000001 so all the 0x00 bytes at the end of this one are
+       * trailing 0x0 that can be discarded */
+      size = nal_len;
+      data = gst_adapter_map (rtph264pay->adapter, size);
+      if (i + 1 != nal_queue->len || buffer != NULL)
+        for (; size > 1 && data[size - 1] == 0x0; size--)
+          /* skip */ ;
+
+
+      /* If it's the last nal unit we have in non-bytestream mode, we can
+       * assume it's the end of an access-unit
+       *
+       * FIXME: We need to wait until the next packet or EOS to
+       * actually payload the NAL so we can know if the current NAL is
+       * the last one of an access unit or not if we are in bytestream mode
+       */
+      if ((rtph264pay->alignment == GST_H264_ALIGNMENT_AU || buffer == NULL) &&
+          i == nal_queue->len - 1)
+        end_of_au = TRUE;
+      paybuf = gst_adapter_take_buffer (rtph264pay->adapter, size);
+      g_assert (paybuf);
+
+      /* put the data in one or more RTP packets */
+      ret =
+          gst_rtp_h264_pay_payload_nal (basepayload, paybuf, dts, pts,
+          end_of_au, rtph264pay->delta_unit, rtph264pay->discont);
+
+      if (delayed_not_delta_unit) {
+        rtph264pay->delta_unit = FALSE;
+        delayed_not_delta_unit = FALSE;
+      } else {
+        /* Only the first outgoing packet doesn't have the DELTA_UNIT flag */
+        rtph264pay->delta_unit = TRUE;
+      }
+
+      if (delayed_discont) {
+        rtph264pay->discont = TRUE;
+        delayed_discont = FALSE;
+      } else {
+        /* Only the first outgoing packet have the DISCONT flag */
+        rtph264pay->discont = FALSE;
+      }
+
+      if (ret != GST_FLOW_OK) {
+        break;
+      }
+
+      /* move to next NAL packet */
+      /* Skips the trailing zeros */
+      gst_adapter_flush (rtph264pay->adapter, nal_len - size);
+    }
+    g_array_set_size (nal_queue, 0);
+  }
+
+done:
+  if (avc) {
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+  } else {
+    gst_adapter_unmap (rtph264pay->adapter);
+  }
+
+  return ret;
+
+caps_rejected:
+  {
+    GST_WARNING_OBJECT (basepayload, "Could not set outcaps");
+    g_array_set_size (nal_queue, 0);
+    ret = GST_FLOW_NOT_NEGOTIATED;
+    goto done;
+  }
+}
+
+static gboolean
+gst_rtp_h264_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+  gboolean res;
+  const GstStructure *s;
+  GstRtpH264Pay *rtph264pay = GST_RTP_H264_PAY (payload);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      gst_adapter_clear (rtph264pay->adapter);
+      break;
+    case GST_EVENT_CUSTOM_DOWNSTREAM:
+      s = gst_event_get_structure (event);
+      if (gst_structure_has_name (s, "GstForceKeyUnit")) {
+        gboolean resend_codec_data;
+
+        if (gst_structure_get_boolean (s, "all-headers",
+                &resend_codec_data) && resend_codec_data)
+          rtph264pay->send_spspps = TRUE;
+      }
+      break;
+    case GST_EVENT_EOS:
+    {
+      /* call handle_buffer with NULL to flush last NAL from adapter
+       * in byte-stream mode
+       */
+      gst_rtp_h264_pay_handle_buffer (payload, NULL);
+      break;
+    }
+    case GST_EVENT_STREAM_START:
+      GST_DEBUG_OBJECT (rtph264pay, "New stream detected => Clear SPS and PPS");
+      gst_rtp_h264_pay_clear_sps_pps (rtph264pay);
+      break;
+    default:
+      break;
+  }
+
+  res = GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+
+  return res;
+}
+
+static GstStateChangeReturn
+gst_rtp_h264_pay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstRtpH264Pay *rtph264pay = GST_RTP_H264_PAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      rtph264pay->send_spspps = FALSE;
+      gst_adapter_clear (rtph264pay->adapter);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      rtph264pay->last_spspps = -1;
+      gst_rtp_h264_pay_clear_sps_pps (rtph264pay);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_rtp_h264_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpH264Pay *rtph264pay;
+
+  rtph264pay = GST_RTP_H264_PAY (object);
+
+  switch (prop_id) {
+    case PROP_SPROP_PARAMETER_SETS:
+      g_free (rtph264pay->sprop_parameter_sets);
+      rtph264pay->sprop_parameter_sets = g_value_dup_string (value);
+      rtph264pay->update_caps = TRUE;
+      break;
+    case PROP_CONFIG_INTERVAL:
+      rtph264pay->spspps_interval = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_h264_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpH264Pay *rtph264pay;
+
+  rtph264pay = GST_RTP_H264_PAY (object);
+
+  switch (prop_id) {
+    case PROP_SPROP_PARAMETER_SETS:
+      g_value_set_string (value, rtph264pay->sprop_parameter_sets);
+      break;
+    case PROP_CONFIG_INTERVAL:
+      g_value_set_int (value, rtph264pay->spspps_interval);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+gboolean
+gst_rtp_h264_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtph264pay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_H264_PAY);
+}
diff --git a/gst/rtp/gstrtph264pay.h b/gst/rtp/gstrtph264pay.h
new file mode 100644
index 0000000..c5a5e9f
--- /dev/null
+++ b/gst/rtp/gstrtph264pay.h
@@ -0,0 +1,95 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_H264_PAY_H__
+#define __GST_RTP_H264_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_H264_PAY \
+  (gst_rtp_h264_pay_get_type())
+#define GST_RTP_H264_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H264_PAY,GstRtpH264Pay))
+#define GST_RTP_H264_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H264_PAY,GstRtpH264PayClass))
+#define GST_IS_RTP_H264_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H264_PAY))
+#define GST_IS_RTP_H264_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H264_PAY))
+
+typedef struct _GstRtpH264Pay GstRtpH264Pay;
+typedef struct _GstRtpH264PayClass GstRtpH264PayClass;
+
+typedef enum
+{
+  GST_H264_STREAM_FORMAT_UNKNOWN,
+  GST_H264_STREAM_FORMAT_BYTESTREAM,
+  GST_H264_STREAM_FORMAT_AVC
+} GstH264StreamFormat;
+
+typedef enum
+{
+  GST_H264_ALIGNMENT_UNKNOWN,
+  GST_H264_ALIGNMENT_NAL,
+  GST_H264_ALIGNMENT_AU
+} GstH264Alignment;
+
+struct _GstRtpH264Pay
+{
+  GstRTPBasePayload payload;
+
+  guint profile;
+  GPtrArray *sps, *pps;
+
+  GstH264StreamFormat stream_format;
+  GstH264Alignment alignment;
+  guint nal_length_size;
+  GArray *queue;
+
+  gchar *sprop_parameter_sets;
+  gboolean update_caps;
+
+  GstAdapter *adapter;
+
+  gint spspps_interval;
+  gboolean send_spspps;
+  GstClockTime last_spspps;
+
+  /* TRUE if the next NALU processed should have the DELTA_UNIT flag */
+  gboolean delta_unit;
+  /* TRUE if the next NALU processed should have the DISCONT flag */
+  gboolean discont;
+};
+
+struct _GstRtpH264PayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_h264_pay_get_type (void);
+
+gboolean gst_rtp_h264_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_H264_PAY_H__ */
diff --git a/gst/rtp/gstrtph265depay.c b/gst/rtp/gstrtph265depay.c
new file mode 100644
index 0000000..9b53dfd
--- /dev/null
+++ b/gst/rtp/gstrtph265depay.c
@@ -0,0 +1,1614 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) <2014> Jurgen Slowack <jurgenslowack@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <gst/base/gstbitreader.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+#include "gstrtph265depay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtph265depay_debug);
+#define GST_CAT_DEFAULT (rtph265depay_debug)
+
+/* This is what we'll default to when downstream hasn't
+ * expressed a restriction or preference via caps */
+#define DEFAULT_STREAM_FORMAT GST_H265_STREAM_FORMAT_BYTESTREAM
+#define DEFAULT_ACCESS_UNIT   FALSE
+
+/* 3 zero bytes syncword */
+static const guint8 sync_bytes[] = { 0, 0, 0, 1 };
+
+static GstStaticPadTemplate gst_rtp_h265_depay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS
+    ("video/x-h265, stream-format=(string)hvc1, alignment=(string)au; "
+        /* FIXME: hev1 format is not supported yet */
+        /* "video/x-h265, "
+           "stream-format = (string) hev1, alignment = (string) au; " */
+        "video/x-h265, "
+        "stream-format = (string) byte-stream, alignment = (string) { nal, au }")
+    );
+
+static GstStaticPadTemplate gst_rtp_h265_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"H265\"")
+        /** optional parameters **/
+    /* "profile-space = (int) [ 0, 3 ], " */
+    /* "profile-id = (int) [ 0, 31 ], " */
+    /* "tier-flag = (int) [ 0, 1 ], " */
+    /* "level-id = (int) [ 0, 255 ], " */
+    /* "interop-constraints = (string) ANY, " */
+    /* "profile-compatibility-indicator = (string) ANY, " */
+    /* "sprop-sub-layer-id = (int) [ 0, 6 ], " */
+    /* "recv-sub-layer-id = (int) [ 0, 6 ], " */
+    /* "max-recv-level-id = (int) [ 0, 255 ], " */
+    /* "tx-mode = (string) {MST , SST}, " */
+    /* "sprop-vps = (string) ANY, " */
+    /* "sprop-sps = (string) ANY, " */
+    /* "sprop-pps = (string) ANY, " */
+    /* "sprop-sei = (string) ANY, " */
+    /* "max-lsr = (int) ANY, " *//* MUST be in the range of MaxLumaSR to 16 * MaxLumaSR, inclusive */
+    /* "max-lps = (int) ANY, " *//* MUST be in the range of MaxLumaPS to 16 * MaxLumaPS, inclusive */
+    /* "max-cpb = (int) ANY, " *//* MUST be in the range of MaxCPB to 16 * MaxCPB, inclusive */
+    /* "max-dpb = (int) [1, 16], " */
+    /* "max-br = (int) ANY, " *//* MUST be in the range of MaxBR to 16 * MaxBR, inclusive, for the highest level */
+    /* "max-tr = (int) ANY, " *//* MUST be in the range of MaxTileRows to 16 * MaxTileRows, inclusive, for the highest level */
+    /* "max-tc = (int) ANY, " *//* MUST be in the range of MaxTileCols to 16 * MaxTileCols, inclusive, for the highest level */
+    /* "max-fps = (int) ANY, " */
+    /* "sprop-max-don-diff = (int) [0, 32767], " */
+    /* "sprop-depack-buf-nalus = (int) [0, 32767], " */
+    /* "sprop-depack-buf-nalus = (int) [0, 4294967295], " */
+    /* "depack-buf-cap = (int) [1, 4294967295], " */
+    /* "sprop-segmentation-id = (int) [0, 3], " */
+    /* "sprop-spatial-segmentation-idc = (string) ANY, " */
+    /* "dec-parallel-cap = (string) ANY, " */
+    );
+
+#define gst_rtp_h265_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpH265Depay, gst_rtp_h265_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_h265_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_h265_depay_change_state (GstElement *
+    element, GstStateChange transition);
+
+static GstBuffer *gst_rtp_h265_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+static gboolean gst_rtp_h265_depay_setcaps (GstRTPBaseDepayload * filter,
+    GstCaps * caps);
+static gboolean gst_rtp_h265_depay_handle_event (GstRTPBaseDepayload * depay,
+    GstEvent * event);
+
+static void
+gst_rtp_h265_depay_class_init (GstRtpH265DepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_h265_depay_finalize;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h265_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h265_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP H265 depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts H265 video from RTP packets (RFC 7798)",
+      "Jurgen Slowack <jurgenslowack@gmail.com>");
+  gstelement_class->change_state = gst_rtp_h265_depay_change_state;
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_h265_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_h265_depay_setcaps;
+  gstrtpbasedepayload_class->handle_event = gst_rtp_h265_depay_handle_event;
+}
+
+static void
+gst_rtp_h265_depay_init (GstRtpH265Depay * rtph265depay)
+{
+  rtph265depay->adapter = gst_adapter_new ();
+  rtph265depay->picture_adapter = gst_adapter_new ();
+  rtph265depay->output_format = DEFAULT_STREAM_FORMAT;
+  rtph265depay->byte_stream =
+      (DEFAULT_STREAM_FORMAT == GST_H265_STREAM_FORMAT_BYTESTREAM);
+  rtph265depay->stream_format = NULL;
+  rtph265depay->merge = DEFAULT_ACCESS_UNIT;
+  rtph265depay->vps = g_ptr_array_new_with_free_func (
+      (GDestroyNotify) gst_buffer_unref);
+  rtph265depay->sps = g_ptr_array_new_with_free_func (
+      (GDestroyNotify) gst_buffer_unref);
+  rtph265depay->pps = g_ptr_array_new_with_free_func (
+      (GDestroyNotify) gst_buffer_unref);
+}
+
+static void
+gst_rtp_h265_depay_reset (GstRtpH265Depay * rtph265depay, gboolean hard)
+{
+  gst_adapter_clear (rtph265depay->adapter);
+  rtph265depay->wait_start = TRUE;
+  gst_adapter_clear (rtph265depay->picture_adapter);
+  rtph265depay->picture_start = FALSE;
+  rtph265depay->last_keyframe = FALSE;
+  rtph265depay->last_ts = 0;
+  rtph265depay->current_fu_type = 0;
+  rtph265depay->new_codec_data = FALSE;
+  g_ptr_array_set_size (rtph265depay->vps, 0);
+  g_ptr_array_set_size (rtph265depay->sps, 0);
+  g_ptr_array_set_size (rtph265depay->pps, 0);
+
+  if (hard) {
+    if (rtph265depay->allocator != NULL) {
+      gst_object_unref (rtph265depay->allocator);
+      rtph265depay->allocator = NULL;
+    }
+    gst_allocation_params_init (&rtph265depay->params);
+  }
+}
+
+static void
+gst_rtp_h265_depay_finalize (GObject * object)
+{
+  GstRtpH265Depay *rtph265depay;
+
+  rtph265depay = GST_RTP_H265_DEPAY (object);
+
+  if (rtph265depay->codec_data)
+    gst_buffer_unref (rtph265depay->codec_data);
+
+  g_object_unref (rtph265depay->adapter);
+  g_object_unref (rtph265depay->picture_adapter);
+
+  g_ptr_array_free (rtph265depay->vps, TRUE);
+  g_ptr_array_free (rtph265depay->sps, TRUE);
+  g_ptr_array_free (rtph265depay->pps, TRUE);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static inline const gchar *
+stream_format_get_nick (GstH265StreamFormat fmt)
+{
+  switch (fmt) {
+    case GST_H265_STREAM_FORMAT_BYTESTREAM:
+      return "byte-stream";
+    case GST_H265_STREAM_FORMAT_HVC1:
+      return "hvc1";
+    case GST_H265_STREAM_FORMAT_HEV1:
+      return "hev1";
+    default:
+      break;
+  }
+  return "unknown";
+}
+
+static void
+gst_rtp_h265_depay_negotiate (GstRtpH265Depay * rtph265depay)
+{
+  GstH265StreamFormat stream_format = GST_H265_STREAM_FORMAT_UNKNOWN;
+  GstCaps *caps;
+  gint merge = -1;
+
+  caps =
+      gst_pad_get_allowed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph265depay));
+
+  GST_DEBUG_OBJECT (rtph265depay, "allowed caps: %" GST_PTR_FORMAT, caps);
+
+  if (caps) {
+    if (gst_caps_get_size (caps) > 0) {
+      GstStructure *s = gst_caps_get_structure (caps, 0);
+      const gchar *str = NULL;
+
+      if ((str = gst_structure_get_string (s, "stream-format"))) {
+        rtph265depay->stream_format = g_intern_string (str);
+
+        if (strcmp (str, "hev1") == 0) {
+          stream_format = GST_H265_STREAM_FORMAT_HEV1;
+        } else if (strcmp (str, "hvc1") == 0) {
+          stream_format = GST_H265_STREAM_FORMAT_HVC1;
+        } else if (strcmp (str, "byte-stream") == 0) {
+          stream_format = GST_H265_STREAM_FORMAT_BYTESTREAM;
+        } else {
+          GST_DEBUG_OBJECT (rtph265depay, "unknown stream-format: %s", str);
+        }
+      }
+
+      if ((str = gst_structure_get_string (s, "alignment"))) {
+        if (strcmp (str, "au") == 0) {
+          merge = TRUE;
+        } else if (strcmp (str, "nal") == 0) {
+          merge = FALSE;
+        } else {
+          GST_DEBUG_OBJECT (rtph265depay, "unknown alignment: %s", str);
+        }
+      }
+    }
+    gst_caps_unref (caps);
+  }
+
+  if (stream_format != GST_H265_STREAM_FORMAT_UNKNOWN) {
+    GST_DEBUG_OBJECT (rtph265depay, "downstream wants stream-format %s",
+        stream_format_get_nick (stream_format));
+    rtph265depay->output_format = stream_format;
+  } else {
+    GST_DEBUG_OBJECT (rtph265depay, "defaulting to output stream-format %s",
+        stream_format_get_nick (DEFAULT_STREAM_FORMAT));
+    rtph265depay->stream_format =
+        stream_format_get_nick (DEFAULT_STREAM_FORMAT);
+    rtph265depay->output_format = DEFAULT_STREAM_FORMAT;
+  }
+  rtph265depay->byte_stream =
+      (rtph265depay->output_format == GST_H265_STREAM_FORMAT_BYTESTREAM);
+
+  if (merge != -1) {
+    GST_DEBUG_OBJECT (rtph265depay, "downstream requires merge %d", merge);
+    rtph265depay->merge = merge;
+  } else {
+    GST_DEBUG_OBJECT (rtph265depay, "defaulting to merge %d",
+        DEFAULT_ACCESS_UNIT);
+    rtph265depay->merge = DEFAULT_ACCESS_UNIT;
+  }
+}
+
+static gboolean
+parse_sps (GstMapInfo * map, guint32 * sps_id)
+{                               /* To parse seq_parameter_set_id */
+  GstBitReader br = GST_BIT_READER_INIT (map->data + 15,
+      map->size - 15);
+
+  GST_MEMDUMP ("SPS", map->data, map->size);
+
+  if (map->size < 16)
+    return FALSE;
+
+  if (!gst_rtp_read_golomb (&br, sps_id))
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+parse_pps (GstMapInfo * map, guint32 * sps_id, guint32 * pps_id)
+{                               /* To parse picture_parameter_set_id */
+  GstBitReader br = GST_BIT_READER_INIT (map->data + 2,
+      map->size - 2);
+
+  GST_MEMDUMP ("PPS", map->data, map->size);
+
+  if (map->size < 3)
+    return FALSE;
+
+  if (!gst_rtp_read_golomb (&br, pps_id))
+    return FALSE;
+  if (!gst_rtp_read_golomb (&br, sps_id))
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+gst_rtp_h265_depay_set_output_caps (GstRtpH265Depay * rtph265depay,
+    GstCaps * caps)
+{
+  GstAllocationParams params;
+  GstAllocator *allocator = NULL;
+  GstPad *srcpad;
+  gboolean res;
+
+  gst_allocation_params_init (&params);
+
+  srcpad = GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph265depay);
+
+  res = gst_pad_set_caps (srcpad, caps);
+
+  if (res) {
+    GstQuery *query;
+
+    query = gst_query_new_allocation (caps, TRUE);
+    if (!gst_pad_peer_query (srcpad, query)) {
+      GST_DEBUG_OBJECT (rtph265depay, "downstream ALLOCATION query failed");
+    }
+
+    if (gst_query_get_n_allocation_params (query) > 0) {
+      gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
+    }
+
+    gst_query_unref (query);
+  }
+
+  if (rtph265depay->allocator)
+    gst_object_unref (rtph265depay->allocator);
+
+  rtph265depay->allocator = allocator;
+  rtph265depay->params = params;
+
+  return res;
+}
+
+static gboolean
+gst_rtp_h265_set_src_caps (GstRtpH265Depay * rtph265depay)
+{
+  gboolean res, update_caps;
+  GstCaps *old_caps;
+  GstCaps *srccaps;
+  GstPad *srcpad;
+
+  if (!rtph265depay->byte_stream &&
+      (!rtph265depay->new_codec_data ||
+          rtph265depay->vps->len == 0 || rtph265depay->sps->len == 0
+          || rtph265depay->pps->len == 0))
+    return TRUE;
+
+  srccaps = gst_caps_new_simple ("video/x-h265",
+      "stream-format", G_TYPE_STRING, rtph265depay->stream_format,
+      "alignment", G_TYPE_STRING, rtph265depay->merge ? "au" : "nal", NULL);
+
+  if (!rtph265depay->byte_stream) {
+    GstBuffer *codec_data;
+    gint i = 0;
+    gint len;
+    guint num_vps = rtph265depay->vps->len;
+    guint num_sps = rtph265depay->sps->len;
+    guint num_pps = rtph265depay->pps->len;
+    GstMapInfo map, nalmap;
+    guint8 *data;
+    guint8 num_arrays = 0;
+    guint new_size;
+    GstBitReader br;
+    guint32 tmp;
+    guint8 tmp8 = 0;
+    guint32 max_sub_layers_minus1, temporal_id_nesting_flag, chroma_format_idc,
+        bit_depth_luma_minus8, bit_depth_chroma_minus8,
+        min_spatial_segmentation_idc;
+
+    /* Fixme: Current implementation is not embedding SEI in codec_data */
+
+    if (num_sps == 0)
+      return FALSE;
+
+    /* start with 23 bytes header */
+    len = 23;
+
+    num_arrays = (num_vps > 0) + (num_sps > 0) + (num_pps > 0);
+    len += 3 * num_arrays;
+
+    /* add size of vps, sps & pps */
+    for (i = 0; i < num_vps; i++)
+      len += 2 + gst_buffer_get_size (g_ptr_array_index (rtph265depay->vps, i));
+    for (i = 0; i < num_sps; i++)
+      len += 2 + gst_buffer_get_size (g_ptr_array_index (rtph265depay->sps, i));
+    for (i = 0; i < num_pps; i++)
+      len += 2 + gst_buffer_get_size (g_ptr_array_index (rtph265depay->pps, i));
+
+    GST_DEBUG_OBJECT (rtph265depay,
+        "constructing codec_data: num_vps =%d num_sps=%d, num_pps=%d", num_vps,
+        num_sps, num_pps);
+
+    codec_data = gst_buffer_new_and_alloc (len);
+    gst_buffer_map (codec_data, &map, GST_MAP_READWRITE);
+    data = map.data;
+
+    memset (data, 0, map.size);
+
+    /* Parsing sps to get the info required further on */
+
+    gst_buffer_map (g_ptr_array_index (rtph265depay->sps, 0), &nalmap,
+        GST_MAP_READ);
+
+    max_sub_layers_minus1 = ((nalmap.data[2]) >> 1) & 0x07;
+    temporal_id_nesting_flag = nalmap.data[2] & 0x01;
+
+    gst_bit_reader_init (&br, nalmap.data + 15, nalmap.size - 15);
+
+    gst_rtp_read_golomb (&br, &tmp);    /* sps_seq_parameter_set_id */
+    gst_rtp_read_golomb (&br, &chroma_format_idc);      /* chroma_format_idc */
+
+    if (chroma_format_idc == 3)
+
+      gst_bit_reader_get_bits_uint8 (&br, &tmp8, 1);    /* separate_colour_plane_flag */
+
+    gst_rtp_read_golomb (&br, &tmp);    /* pic_width_in_luma_samples */
+    gst_rtp_read_golomb (&br, &tmp);    /* pic_height_in_luma_samples */
+
+    gst_bit_reader_get_bits_uint8 (&br, &tmp8, 1);      /* conformance_window_flag */
+    if (tmp8) {
+      gst_rtp_read_golomb (&br, &tmp);  /* conf_win_left_offset */
+      gst_rtp_read_golomb (&br, &tmp);  /* conf_win_right_offset */
+      gst_rtp_read_golomb (&br, &tmp);  /* conf_win_top_offset */
+      gst_rtp_read_golomb (&br, &tmp);  /* conf_win_bottom_offset */
+    }
+
+    gst_rtp_read_golomb (&br, &bit_depth_luma_minus8);  /* bit_depth_luma_minus8 */
+    gst_rtp_read_golomb (&br, &bit_depth_chroma_minus8);        /* bit_depth_chroma_minus8 */
+
+    GST_DEBUG_OBJECT (rtph265depay,
+        "Ignoring min_spatial_segmentation for now (assuming zero)");
+
+    min_spatial_segmentation_idc = 0;   /* NOTE - we ignore this for now, but in a perfect world, we should continue parsing to obtain the real value */
+
+    gst_buffer_unmap (g_ptr_array_index (rtph265depay->sps, 0), &nalmap);
+
+    /* HEVCDecoderConfigurationVersion = 1 */
+    data[0] = 1;
+
+    /* Copy from profile_tier_level (Rec. ITU-T H.265 (04/2013) section 7.3.3
+     *
+     * profile_space | tier_flat | profile_idc |
+     * profile_compatibility_flags | constraint_indicator_flags |
+     * level_idc | progressive_source_flag | interlaced_source_flag
+     * non_packed_constraint_flag | frame_only_constraint_flag
+     * reserved_zero_44bits | level_idc */
+    gst_buffer_map (g_ptr_array_index (rtph265depay->sps, 0), &nalmap,
+        GST_MAP_READ);
+    for (i = 0; i < 12; i++)
+      data[i + 1] = nalmap.data[i];
+    gst_buffer_unmap (g_ptr_array_index (rtph265depay->sps, 0), &nalmap);
+
+    /* min_spatial_segmentation_idc */
+    GST_WRITE_UINT16_BE (data + 13, min_spatial_segmentation_idc);
+    data[13] |= 0xf0;
+    data[15] = 0xfc;            /* keeping parrallelismType as zero (unknown) */
+    data[16] = 0xfc | chroma_format_idc;
+    data[17] = 0xf8 | bit_depth_luma_minus8;
+    data[18] = 0xf8 | bit_depth_chroma_minus8;
+    data[19] = 0x00;            /* keep avgFrameRate as unspecified */
+    data[20] = 0x00;            /* keep avgFrameRate as unspecified */
+    /* constFrameRate(2 bits): 0, stream may or may not be of constant framerate
+     * numTemporalLayers (3 bits): number of temporal layers, value from SPS
+     * TemporalIdNested (1 bit): sps_temporal_id_nesting_flag from SPS
+     * lengthSizeMinusOne (2 bits): plus 1 indicates the length of the NALUnitLength */
+    /* we always output NALs with 4-byte nal unit length markers (or sync code) */
+    data[21] = rtph265depay->byte_stream ? 0x00 : 0x03;
+    data[21] |= ((max_sub_layers_minus1 + 1) << 3);
+    data[21] |= (temporal_id_nesting_flag << 2);
+    GST_WRITE_UINT8 (data + 22, num_arrays);    /* numOfArrays */
+
+    data += 23;
+
+    /* copy all VPS */
+    if (num_vps > 0) {
+      /* array_completeness | reserved_zero bit | nal_unit_type */
+      data[0] = 0x00 | 0x20;
+      data++;
+
+      GST_WRITE_UINT16_BE (data, num_vps);
+      data += 2;
+
+      for (i = 0; i < num_vps; i++) {
+        gsize nal_size =
+            gst_buffer_get_size (g_ptr_array_index (rtph265depay->vps, i));
+        GST_WRITE_UINT16_BE (data, nal_size);
+        gst_buffer_extract (g_ptr_array_index (rtph265depay->vps, i), 0,
+            data + 2, nal_size);
+        data += 2 + nal_size;
+        GST_DEBUG_OBJECT (rtph265depay, "Copied VPS %d of length %u", i,
+            (guint) nal_size);
+      }
+    }
+
+    /* copy all SPS */
+    if (num_sps > 0) {
+      /* array_completeness | reserved_zero bit | nal_unit_type */
+      data[0] = 0x00 | 0x21;
+      data++;
+
+      GST_WRITE_UINT16_BE (data, num_sps);
+      data += 2;
+
+      for (i = 0; i < num_sps; i++) {
+        gsize nal_size =
+            gst_buffer_get_size (g_ptr_array_index (rtph265depay->sps, i));
+        GST_WRITE_UINT16_BE (data, nal_size);
+        gst_buffer_extract (g_ptr_array_index (rtph265depay->sps, i), 0,
+            data + 2, nal_size);
+        data += 2 + nal_size;
+        GST_DEBUG_OBJECT (rtph265depay, "Copied SPS %d of length %u", i,
+            (guint) nal_size);
+      }
+    }
+
+    /* copy all PPS */
+    if (num_pps > 0) {
+      /* array_completeness | reserved_zero bit | nal_unit_type */
+      data[0] = 0x00 | 0x22;
+      data++;
+
+      GST_WRITE_UINT16_BE (data, num_pps);
+      data += 2;
+
+      for (i = 0; i < num_pps; i++) {
+        gsize nal_size =
+            gst_buffer_get_size (g_ptr_array_index (rtph265depay->pps, i));
+        GST_WRITE_UINT16_BE (data, nal_size);
+        gst_buffer_extract (g_ptr_array_index (rtph265depay->pps, i), 0,
+            data + 2, nal_size);
+        data += 2 + nal_size;
+        GST_DEBUG_OBJECT (rtph265depay, "Copied PPS %d of length %u", i,
+            (guint) nal_size);
+      }
+    }
+
+    new_size = data - map.data;
+    gst_buffer_unmap (codec_data, &map);
+    gst_buffer_set_size (codec_data, new_size);
+
+    gst_caps_set_simple (srccaps,
+        "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
+    gst_buffer_unref (codec_data);
+  }
+
+  srcpad = GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph265depay);
+
+  old_caps = gst_pad_get_current_caps (srcpad);
+  if (old_caps != NULL) {
+
+    /* Only update the caps if they are not equal. For
+     * AVC we don't update caps if only the codec_data
+     * changes. This is the same behaviour as in h264parse
+     * and gstrtph264depay
+     */
+    if (rtph265depay->byte_stream) {
+      update_caps = !gst_caps_is_equal (srccaps, old_caps);
+    } else {
+      GstCaps *tmp_caps = gst_caps_copy (srccaps);
+      GstStructure *old_s, *tmp_s;
+
+      old_s = gst_caps_get_structure (old_caps, 0);
+      tmp_s = gst_caps_get_structure (tmp_caps, 0);
+      if (gst_structure_has_field (old_s, "codec_data"))
+        gst_structure_set_value (tmp_s, "codec_data",
+            gst_structure_get_value (old_s, "codec_data"));
+
+      update_caps = !gst_caps_is_equal (old_caps, tmp_caps);
+      gst_caps_unref (tmp_caps);
+    }
+    gst_caps_unref (old_caps);
+  } else {
+    update_caps = TRUE;
+  }
+
+  if (update_caps) {
+    res = gst_rtp_h265_depay_set_output_caps (rtph265depay, srccaps);
+  } else {
+    res = TRUE;
+  }
+
+  gst_caps_unref (srccaps);
+
+  /* Insert SPS and PPS into the stream on next opportunity */
+  if (rtph265depay->output_format != GST_H265_STREAM_FORMAT_HVC1
+      && (rtph265depay->sps->len > 0 || rtph265depay->pps->len > 0)) {
+    gint i;
+    GstBuffer *codec_data;
+    GstMapInfo map;
+    guint8 *data;
+    guint len = 0;
+
+    for (i = 0; i < rtph265depay->sps->len; i++) {
+      len += 4 + gst_buffer_get_size (g_ptr_array_index (rtph265depay->sps, i));
+    }
+
+    for (i = 0; i < rtph265depay->pps->len; i++) {
+      len += 4 + gst_buffer_get_size (g_ptr_array_index (rtph265depay->pps, i));
+    }
+
+    codec_data = gst_buffer_new_and_alloc (len);
+    gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
+    data = map.data;
+
+    for (i = 0; i < rtph265depay->sps->len; i++) {
+      GstBuffer *sps_buf = g_ptr_array_index (rtph265depay->sps, i);
+      guint sps_size = gst_buffer_get_size (sps_buf);
+
+      if (rtph265depay->byte_stream)
+        memcpy (data, sync_bytes, sizeof (sync_bytes));
+      else
+        GST_WRITE_UINT32_BE (data, sps_size);
+      gst_buffer_extract (sps_buf, 0, data + 4, -1);
+      data += 4 + sps_size;
+    }
+
+    for (i = 0; i < rtph265depay->pps->len; i++) {
+      GstBuffer *pps_buf = g_ptr_array_index (rtph265depay->pps, i);
+      guint pps_size = gst_buffer_get_size (pps_buf);
+
+      if (rtph265depay->byte_stream)
+        memcpy (data, sync_bytes, sizeof (sync_bytes));
+      else
+        GST_WRITE_UINT32_BE (data, pps_size);
+      gst_buffer_extract (pps_buf, 0, data + 4, -1);
+      data += 4 + pps_size;
+    }
+
+    gst_buffer_unmap (codec_data, &map);
+    if (rtph265depay->codec_data)
+      gst_buffer_unref (rtph265depay->codec_data);
+    rtph265depay->codec_data = codec_data;
+  }
+
+  if (res)
+    rtph265depay->new_codec_data = FALSE;
+
+  return res;
+}
+
+gboolean
+gst_rtp_h265_add_vps_sps_pps (GstElement * rtph265, GPtrArray * vps_array,
+    GPtrArray * sps_array, GPtrArray * pps_array, GstBuffer * nal)
+{
+  GstMapInfo map;
+  guchar type;
+  guint i;
+
+  gst_buffer_map (nal, &map, GST_MAP_READ);
+
+  type = (map.data[0] >> 1) & 0x3f;
+
+  if (type == GST_H265_VPS_NUT) {
+    guint32 vps_id = (map.data[2] >> 4) & 0x0f;
+
+    for (i = 0; i < vps_array->len; i++) {
+      GstBuffer *vps = g_ptr_array_index (vps_array, i);
+      GstMapInfo vpsmap;
+      guint32 tmp_vps_id;
+
+      gst_buffer_map (vps, &vpsmap, GST_MAP_READ);
+      tmp_vps_id = (vpsmap.data[2] >> 4) & 0x0f;
+
+      if (vps_id == tmp_vps_id) {
+        if (map.size == vpsmap.size &&
+            memcmp (map.data, vpsmap.data, vpsmap.size) == 0) {
+          GST_LOG_OBJECT (rtph265, "Unchanged VPS %u, not updating", vps_id);
+          gst_buffer_unmap (vps, &vpsmap);
+          goto drop;
+        } else {
+          gst_buffer_unmap (vps, &vpsmap);
+          g_ptr_array_remove_index_fast (vps_array, i);
+          g_ptr_array_add (vps_array, nal);
+          GST_LOG_OBJECT (rtph265, "Modified VPS %u, replacing", vps_id);
+          goto done;
+        }
+      }
+      gst_buffer_unmap (vps, &vpsmap);
+    }
+    GST_LOG_OBJECT (rtph265, "Adding new VPS %u", vps_id);
+    g_ptr_array_add (vps_array, nal);
+  } else if (type == GST_H265_SPS_NUT) {
+    guint32 sps_id;
+
+    if (!parse_sps (&map, &sps_id)) {
+      GST_WARNING_OBJECT (rtph265, "Invalid SPS,"
+          " can't parse seq_parameter_set_id");
+      goto drop;
+    }
+
+    for (i = 0; i < sps_array->len; i++) {
+      GstBuffer *sps = g_ptr_array_index (sps_array, i);
+      GstMapInfo spsmap;
+      guint32 tmp_sps_id;
+
+      gst_buffer_map (sps, &spsmap, GST_MAP_READ);
+      parse_sps (&spsmap, &tmp_sps_id);
+
+      if (sps_id == tmp_sps_id) {
+        if (map.size == spsmap.size &&
+            memcmp (map.data, spsmap.data, spsmap.size) == 0) {
+          GST_LOG_OBJECT (rtph265, "Unchanged SPS %u, not updating", sps_id);
+          gst_buffer_unmap (sps, &spsmap);
+          goto drop;
+        } else {
+          gst_buffer_unmap (sps, &spsmap);
+          g_ptr_array_remove_index_fast (sps_array, i);
+          g_ptr_array_add (sps_array, nal);
+          GST_LOG_OBJECT (rtph265, "Modified SPS %u, replacing", sps_id);
+          goto done;
+        }
+      }
+      gst_buffer_unmap (sps, &spsmap);
+    }
+    GST_LOG_OBJECT (rtph265, "Adding new SPS %u", sps_id);
+    g_ptr_array_add (sps_array, nal);
+  } else if (type == GST_H265_PPS_NUT) {
+    guint32 sps_id;
+    guint32 pps_id;
+
+    if (!parse_pps (&map, &sps_id, &pps_id)) {
+      GST_WARNING_OBJECT (rtph265, "Invalid PPS,"
+          " can't parse seq_parameter_set_id or pic_parameter_set_id");
+      goto drop;
+    }
+
+    for (i = 0; i < pps_array->len; i++) {
+      GstBuffer *pps = g_ptr_array_index (pps_array, i);
+      GstMapInfo ppsmap;
+      guint32 tmp_sps_id;
+      guint32 tmp_pps_id;
+
+
+      gst_buffer_map (pps, &ppsmap, GST_MAP_READ);
+      parse_pps (&ppsmap, &tmp_sps_id, &tmp_pps_id);
+
+      if (pps_id == tmp_pps_id) {
+        if (map.size == ppsmap.size &&
+            memcmp (map.data, ppsmap.data, ppsmap.size) == 0) {
+          GST_LOG_OBJECT (rtph265, "Unchanged PPS %u:%u, not updating", sps_id,
+              pps_id);
+          gst_buffer_unmap (pps, &ppsmap);
+          goto drop;
+        } else {
+          gst_buffer_unmap (pps, &ppsmap);
+          g_ptr_array_remove_index_fast (pps_array, i);
+          g_ptr_array_add (pps_array, nal);
+          GST_LOG_OBJECT (rtph265, "Modified PPS %u:%u, replacing",
+              sps_id, pps_id);
+          goto done;
+        }
+      }
+      gst_buffer_unmap (pps, &ppsmap);
+    }
+    GST_LOG_OBJECT (rtph265, "Adding new PPS %u:%i", sps_id, pps_id);
+    g_ptr_array_add (pps_array, nal);
+  } else {
+    goto drop;
+  }
+
+done:
+  gst_buffer_unmap (nal, &map);
+
+  return TRUE;
+
+drop:
+  gst_buffer_unmap (nal, &map);
+  gst_buffer_unref (nal);
+
+  return FALSE;
+}
+
+
+static void
+gst_rtp_h265_depay_add_vps_sps_pps (GstRtpH265Depay * rtph265depay,
+    GstBuffer * nal)
+{
+  if (gst_rtp_h265_add_vps_sps_pps (GST_ELEMENT (rtph265depay),
+          rtph265depay->vps, rtph265depay->sps, rtph265depay->pps, nal))
+    rtph265depay->new_codec_data = TRUE;
+}
+
+static gboolean
+gst_rtp_h265_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  gint clock_rate;
+  GstStructure *structure = gst_caps_get_structure (caps, 0);
+  GstRtpH265Depay *rtph265depay;
+  const gchar *vps;
+  const gchar *sps;
+  const gchar *pps;
+  gchar *ps;
+  GstMapInfo map;
+  guint8 *ptr;
+
+  rtph265depay = GST_RTP_H265_DEPAY (depayload);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;
+  depayload->clock_rate = clock_rate;
+
+  /* Base64 encoded, comma separated config NALs */
+  vps = gst_structure_get_string (structure, "sprop-vps");
+  sps = gst_structure_get_string (structure, "sprop-sps");
+  pps = gst_structure_get_string (structure, "sprop-pps");
+  if (vps == NULL || sps == NULL || pps == NULL) {
+    ps = NULL;
+  } else {
+    ps = g_strdup_printf ("%s,%s,%s", vps, sps, pps);
+  }
+
+  /* negotiate with downstream w.r.t. output format and alignment */
+  gst_rtp_h265_depay_negotiate (rtph265depay);
+
+  if (rtph265depay->byte_stream && ps != NULL) {
+    /* for bytestream we only need the parameter sets but we don't error out
+     * when they are not there, we assume they are in the stream. */
+    gchar **params;
+    GstBuffer *codec_data;
+    guint len, total;
+    gint i;
+
+    params = g_strsplit (ps, ",", 0);
+
+    /* count total number of bytes in base64. Also include the sync bytes in
+     * front of the params. */
+    len = 0;
+    for (i = 0; params[i]; i++) {
+      len += strlen (params[i]);
+      len += sizeof (sync_bytes);
+    }
+    /* we seriously overshoot the length, but it's fine. */
+    codec_data = gst_buffer_new_and_alloc (len);
+
+    gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
+    ptr = map.data;
+    total = 0;
+    for (i = 0; params[i]; i++) {
+      guint save = 0;
+      gint state = 0;
+
+      GST_DEBUG_OBJECT (depayload, "decoding param %d (%s)", i, params[i]);
+      memcpy (ptr, sync_bytes, sizeof (sync_bytes));
+      ptr += sizeof (sync_bytes);
+      len =
+          g_base64_decode_step (params[i], strlen (params[i]), ptr, &state,
+          &save);
+      GST_DEBUG_OBJECT (depayload, "decoded %d bytes", len);
+      total += len + sizeof (sync_bytes);
+      ptr += len;
+    }
+    gst_buffer_unmap (codec_data, &map);
+    gst_buffer_resize (codec_data, 0, total);
+    g_strfreev (params);
+
+    /* keep the codec_data, we need to send it as the first buffer. We cannot
+     * push it in the adapter because the adapter might be flushed on discont.
+     */
+    if (rtph265depay->codec_data)
+      gst_buffer_unref (rtph265depay->codec_data);
+    rtph265depay->codec_data = codec_data;
+  } else if (!rtph265depay->byte_stream) {
+    gchar **params;
+    gint i;
+
+    if (ps == NULL)
+      goto incomplete_caps;
+
+    params = g_strsplit (ps, ",", 0);
+
+    GST_DEBUG_OBJECT (depayload, "we have %d params", g_strv_length (params));
+
+    /* start with 23 bytes header */
+    for (i = 0; params[i]; i++) {
+      GstBuffer *nal;
+      GstMapInfo nalmap;
+      gsize nal_len;
+      guint save = 0;
+      gint state = 0;
+
+      nal_len = strlen (params[i]);
+      if (nal_len == 0) {
+        GST_WARNING_OBJECT (depayload, "empty param '%s' (#%d)", params[i], i);
+        continue;
+      }
+      nal = gst_buffer_new_and_alloc (nal_len);
+      gst_buffer_map (nal, &nalmap, GST_MAP_READWRITE);
+
+      nal_len =
+          g_base64_decode_step (params[i], nal_len, nalmap.data, &state, &save);
+
+      GST_DEBUG_OBJECT (depayload, "adding param %d as %s", i,
+          (((nalmap.data[0] >> 1) & 0x3f) ==
+              32) ? "VPS" : (((nalmap.data[0] >> 1) & 0x3f) ==
+              33) ? "SPS" : "PPS");
+
+      gst_buffer_unmap (nal, &nalmap);
+      gst_buffer_set_size (nal, nal_len);
+
+      gst_rtp_h265_depay_add_vps_sps_pps (rtph265depay, nal);
+    }
+    g_strfreev (params);
+
+    if (rtph265depay->vps->len == 0 || rtph265depay->sps->len == 0 ||
+        rtph265depay->pps->len == 0) {
+      goto incomplete_caps;
+    }
+  }
+
+  g_free (ps);
+
+  return gst_rtp_h265_set_src_caps (rtph265depay);
+
+  /* ERRORS */
+incomplete_caps:
+  {
+    GST_DEBUG_OBJECT (depayload, "we have incomplete caps,"
+        " doing setcaps later");
+    g_free (ps);
+    return TRUE;
+  }
+}
+
+static GstBuffer *
+gst_rtp_h265_depay_allocate_output_buffer (GstRtpH265Depay * depay, gsize size)
+{
+  GstBuffer *buffer = NULL;
+
+  g_return_val_if_fail (size > 0, NULL);
+
+  GST_LOG_OBJECT (depay, "want output buffer of %u bytes", (guint) size);
+
+  buffer = gst_buffer_new_allocate (depay->allocator, size, &depay->params);
+  if (buffer == NULL) {
+    GST_INFO_OBJECT (depay, "couldn't allocate output buffer");
+    buffer = gst_buffer_new_allocate (NULL, size, NULL);
+  }
+
+  return buffer;
+}
+
+static GstBuffer *
+gst_rtp_h265_complete_au (GstRtpH265Depay * rtph265depay,
+    GstClockTime * out_timestamp, gboolean * out_keyframe)
+{
+  GstBufferList *list;
+  GstMapInfo outmap;
+  GstBuffer *outbuf;
+  guint outsize, offset = 0;
+  gint b, n_bufs, m, n_mem;
+
+  /* we had a picture in the adapter and we completed it */
+  GST_DEBUG_OBJECT (rtph265depay, "taking completed AU");
+  outsize = gst_adapter_available (rtph265depay->picture_adapter);
+
+  outbuf = gst_rtp_h265_depay_allocate_output_buffer (rtph265depay, outsize);
+
+  if (outbuf == NULL)
+    return NULL;
+
+  if (!gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE))
+    return NULL;
+
+  list = gst_adapter_take_buffer_list (rtph265depay->picture_adapter, outsize);
+
+  n_bufs = gst_buffer_list_length (list);
+  for (b = 0; b < n_bufs; ++b) {
+    GstBuffer *buf = gst_buffer_list_get (list, b);
+
+    n_mem = gst_buffer_n_memory (buf);
+    for (m = 0; m < n_mem; ++m) {
+      GstMemory *mem = gst_buffer_peek_memory (buf, m);
+      gsize mem_size = gst_memory_get_sizes (mem, NULL, NULL);
+      GstMapInfo mem_map;
+
+      if (gst_memory_map (mem, &mem_map, GST_MAP_READ)) {
+        memcpy (outmap.data + offset, mem_map.data, mem_size);
+        gst_memory_unmap (mem, &mem_map);
+      } else {
+        memset (outmap.data + offset, 0, mem_size);
+      }
+      offset += mem_size;
+    }
+
+    gst_rtp_copy_video_meta (rtph265depay, outbuf, buf);
+  }
+  gst_buffer_list_unref (list);
+  gst_buffer_unmap (outbuf, &outmap);
+
+  *out_timestamp = rtph265depay->last_ts;
+  *out_keyframe = rtph265depay->last_keyframe;
+
+  rtph265depay->last_keyframe = FALSE;
+  rtph265depay->picture_start = FALSE;
+
+  return outbuf;
+}
+
+/* VPS/SPS/PPS/RADL/TSA/RASL/IDR/CRA is considered key, all others DELTA;
+ * so downstream waiting for keyframe can pick up at VPS/SPS/PPS/IDR */
+
+#define NAL_TYPE_IS_PARAMETER_SET(nt) (		((nt) == GST_H265_VPS_NUT)\
+										||  ((nt) == GST_H265_SPS_NUT)\
+										||  ((nt) == GST_H265_PPS_NUT)				)
+
+#define NAL_TYPE_IS_CODED_SLICE_SEGMENT(nt) (		((nt) == GST_H265_NAL_SLICE_TRAIL_N)\
+												|| 	((nt) == GST_H265_NAL_SLICE_TRAIL_R)\
+												||  ((nt) == GST_H265_NAL_SLICE_TSA_N)\
+												||  ((nt) == GST_H265_NAL_SLICE_TSA_R)\
+												||  ((nt) == GST_H265_NAL_SLICE_STSA_N)\
+												||  ((nt) == GST_H265_NAL_SLICE_STSA_R)\
+												||  ((nt) == GST_H265_NAL_SLICE_RASL_N)\
+												||  ((nt) == GST_H265_NAL_SLICE_RASL_R)\
+												||  ((nt) == GST_H265_NAL_SLICE_BLA_W_LP)\
+												||  ((nt) == GST_H265_NAL_SLICE_BLA_W_RADL)\
+												||  ((nt) == GST_H265_NAL_SLICE_BLA_N_LP)\
+												||  ((nt) == GST_H265_NAL_SLICE_IDR_W_RADL)\
+												||  ((nt) == GST_H265_NAL_SLICE_IDR_N_LP)\
+												||  ((nt) == GST_H265_NAL_SLICE_CRA_NUT)		)
+
+/* Intra random access point */
+#define NAL_TYPE_IS_IRAP(nt)   (((nt) == GST_H265_NAL_SLICE_BLA_W_LP)   \
+                             || ((nt) == GST_H265_NAL_SLICE_BLA_W_RADL) \
+                             || ((nt) == GST_H265_NAL_SLICE_BLA_N_LP)   \
+                             || ((nt) == GST_H265_NAL_SLICE_IDR_W_RADL) \
+                             || ((nt) == GST_H265_NAL_SLICE_IDR_N_LP)   \
+                             || ((nt) == GST_H265_NAL_SLICE_CRA_NUT))
+
+#define NAL_TYPE_IS_KEY(nt) (NAL_TYPE_IS_PARAMETER_SET(nt) || NAL_TYPE_IS_IRAP(nt))
+
+static void
+gst_rtp_h265_depay_handle_nal (GstRtpH265Depay * rtph265depay, GstBuffer * nal,
+    GstClockTime in_timestamp, gboolean marker)
+{
+  GstRTPBaseDepayload *depayload = GST_RTP_BASE_DEPAYLOAD (rtph265depay);
+  gint nal_type;
+  GstMapInfo map;
+  GstBuffer *outbuf = NULL;
+  GstClockTime out_timestamp;
+  gboolean keyframe, out_keyframe;
+
+  gst_buffer_map (nal, &map, GST_MAP_READ);
+  if (G_UNLIKELY (map.size < 5))
+    goto short_nal;
+
+  nal_type = (map.data[4] >> 1) & 0x3f;
+  GST_DEBUG_OBJECT (rtph265depay, "handle NAL type %d (RTP marker bit %d)",
+      nal_type, marker);
+
+  keyframe = NAL_TYPE_IS_KEY (nal_type);
+
+  out_keyframe = keyframe;
+  out_timestamp = in_timestamp;
+
+  if (!rtph265depay->byte_stream) {
+    if (NAL_TYPE_IS_PARAMETER_SET (nal_type)) {
+      gst_rtp_h265_depay_add_vps_sps_pps (rtph265depay,
+          gst_buffer_copy_region (nal, GST_BUFFER_COPY_ALL,
+              4, gst_buffer_get_size (nal) - 4));
+      gst_buffer_unmap (nal, &map);
+      gst_buffer_unref (nal);
+      return;
+    } else if (rtph265depay->sps->len == 0 || rtph265depay->pps->len == 0) {
+      /* Down push down any buffer in non-bytestream mode if the SPS/PPS haven't
+       * go through yet
+       */
+      gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
+          gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+              gst_structure_new ("GstForceKeyUnit",
+                  "all-headers", G_TYPE_BOOLEAN, TRUE, NULL)));
+      gst_buffer_unmap (nal, &map);
+      gst_buffer_unref (nal);
+      return;
+    }
+
+    if (rtph265depay->new_codec_data &&
+        rtph265depay->sps->len > 0 && rtph265depay->pps->len > 0)
+      gst_rtp_h265_set_src_caps (rtph265depay);
+  }
+
+  if (rtph265depay->merge) {
+    gboolean start = FALSE, complete = FALSE;
+
+    /* marker bit isn't mandatory so in the following code we try to detect
+     * an AU boundary (see H.265 spec section 7.4.2.4.4) */
+    if (!marker) {
+      if (NAL_TYPE_IS_CODED_SLICE_SEGMENT (nal_type)) {
+        /* A NAL unit (X) ends an access unit if the next-occurring VCL NAL unit (Y) has the high-order bit of the first byte after its NAL unit header equal to 1 */
+        start = TRUE;
+        if (((map.data[6] >> 7) & 0x01) == 1) {
+          complete = TRUE;
+        }
+      } else if ((nal_type >= 32 && nal_type <= 35)
+          || nal_type == 39 || (nal_type >= 41 && nal_type <= 44)
+          || (nal_type >= 48 && nal_type <= 55)) {
+        /* VPS, SPS, PPS, SEI, ... terminate an access unit */
+        complete = TRUE;
+      }
+      GST_DEBUG_OBJECT (depayload, "start %d, complete %d", start, complete);
+
+      if (complete && rtph265depay->picture_start)
+        outbuf = gst_rtp_h265_complete_au (rtph265depay, &out_timestamp,
+            &out_keyframe);
+    }
+    /* add to adapter */
+    gst_buffer_unmap (nal, &map);
+
+    GST_DEBUG_OBJECT (depayload, "adding NAL to picture adapter");
+    gst_adapter_push (rtph265depay->picture_adapter, nal);
+    rtph265depay->last_ts = in_timestamp;
+    rtph265depay->last_keyframe |= keyframe;
+    rtph265depay->picture_start |= start;
+
+    if (marker)
+      outbuf = gst_rtp_h265_complete_au (rtph265depay, &out_timestamp,
+          &out_keyframe);
+  } else {
+    /* no merge, output is input nal */
+    GST_DEBUG_OBJECT (depayload, "using NAL as output");
+    outbuf = nal;
+    gst_buffer_unmap (nal, &map);
+  }
+
+  if (outbuf) {
+    /* prepend codec_data */
+    if (rtph265depay->codec_data) {
+      GST_DEBUG_OBJECT (depayload, "prepending codec_data");
+      gst_rtp_copy_video_meta (rtph265depay, rtph265depay->codec_data, outbuf);
+      outbuf = gst_buffer_append (rtph265depay->codec_data, outbuf);
+      rtph265depay->codec_data = NULL;
+      out_keyframe = TRUE;
+    }
+    outbuf = gst_buffer_make_writable (outbuf);
+
+    gst_rtp_drop_non_video_meta (rtph265depay, outbuf);
+
+    GST_BUFFER_PTS (outbuf) = out_timestamp;
+
+    if (out_keyframe)
+      GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+    else
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+    gst_rtp_base_depayload_push (depayload, outbuf);
+  }
+
+  return;
+
+  /* ERRORS */
+short_nal:
+  {
+    GST_WARNING_OBJECT (depayload, "dropping short NAL");
+    gst_buffer_unmap (nal, &map);
+    gst_buffer_unref (nal);
+    return;
+  }
+}
+
+static void
+gst_rtp_h265_finish_fragmentation_unit (GstRtpH265Depay * rtph265depay)
+{
+  guint outsize;
+  GstMapInfo map;
+  GstBuffer *outbuf;
+
+  outsize = gst_adapter_available (rtph265depay->adapter);
+  g_assert (outsize >= 4);
+
+  outbuf = gst_adapter_take_buffer (rtph265depay->adapter, outsize);
+
+  gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+  GST_DEBUG_OBJECT (rtph265depay, "output %d bytes", outsize);
+
+  if (rtph265depay->byte_stream) {
+    memcpy (map.data, sync_bytes, sizeof (sync_bytes));
+  } else {
+    GST_WRITE_UINT32_BE (map.data, outsize - 4);
+  }
+  gst_buffer_unmap (outbuf, &map);
+
+  rtph265depay->current_fu_type = 0;
+
+  gst_rtp_h265_depay_handle_nal (rtph265depay, outbuf,
+      rtph265depay->fu_timestamp, rtph265depay->fu_marker);
+}
+
+static GstBuffer *
+gst_rtp_h265_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpH265Depay *rtph265depay;
+  GstBuffer *outbuf = NULL;
+  guint8 nal_unit_type;
+
+  rtph265depay = GST_RTP_H265_DEPAY (depayload);
+
+  /* flush remaining data on discont */
+  if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
+    gst_adapter_clear (rtph265depay->adapter);
+    rtph265depay->wait_start = TRUE;
+    rtph265depay->current_fu_type = 0;
+  }
+
+  {
+    gint payload_len;
+    guint8 *payload;
+    guint header_len;
+    GstMapInfo map;
+    guint outsize, nalu_size;
+    GstClockTime timestamp;
+    gboolean marker;
+    guint8 nuh_layer_id, nuh_temporal_id_plus1;
+    guint8 S, E;
+    guint16 nal_header;
+#if 0
+    gboolean donl_present = FALSE;
+#endif
+
+    timestamp = GST_BUFFER_PTS (rtp->buffer);
+
+    payload_len = gst_rtp_buffer_get_payload_len (rtp);
+    payload = gst_rtp_buffer_get_payload (rtp);
+    marker = gst_rtp_buffer_get_marker (rtp);
+
+    GST_DEBUG_OBJECT (rtph265depay, "receiving %d bytes", payload_len);
+
+    if (payload_len == 0)
+      goto empty_packet;
+
+    /* +---------------+---------------+
+     * |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * |F|   Type    |  LayerId  | TID |
+     * +-------------+-----------------+
+     *
+     * F must be 0.
+     *
+     */
+    nal_unit_type = (payload[0] >> 1) & 0x3f;
+    nuh_layer_id = ((payload[0] & 0x01) << 5) | (payload[1] >> 3);      /* should be zero for now but this could change in future HEVC extensions */
+    nuh_temporal_id_plus1 = payload[1] & 0x03;
+
+    /* At least two byte header with type */
+    header_len = 2;
+
+    GST_DEBUG_OBJECT (rtph265depay,
+        "NAL header nal_unit_type %d, nuh_temporal_id_plus1 %d", nal_unit_type,
+        nuh_temporal_id_plus1);
+
+    GST_FIXME_OBJECT (rtph265depay, "Assuming DONL field is not present");
+
+    /* FIXME - assuming DONL field is not present for now */
+    /*donl_present = (tx-mode == "MST") || (sprop-max-don-diff > 0); */
+
+    /* If FU unit was being processed, but the current nal is of a different
+     * type.  Assume that the remote payloader is buggy (didn't set the end bit
+     * when the FU ended) and send out what we gathered thusfar */
+    if (G_UNLIKELY (rtph265depay->current_fu_type != 0 &&
+            nal_unit_type != rtph265depay->current_fu_type))
+      gst_rtp_h265_finish_fragmentation_unit (rtph265depay);
+
+    switch (nal_unit_type) {
+      case 48:
+      {
+        GST_DEBUG_OBJECT (rtph265depay, "Processing aggregation packet");
+
+        /* Aggregation packet (section 4.7) */
+
+        /*  An example of an AP packet containing two aggregation units
+           without the DONL and DOND fields
+
+           0                   1                   2                   3
+           0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+           |                          RTP Header                           |
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+           |   PayloadHdr (Type=48)        |         NALU 1 Size           |
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+           |          NALU 1 HDR           |                               |
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+         NALU 1 Data           |
+           |                   . . .                                       |
+           |                                                               |
+           +               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+           |  . . .        | NALU 2 Size                   | NALU 2 HDR    |
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+           | NALU 2 HDR    |                                               |
+           +-+-+-+-+-+-+-+-+              NALU 2 Data                      |
+           |                   . . .                                       |
+           |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+           |                               :...OPTIONAL RTP padding        |
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         */
+
+        /* strip headers */
+        payload += header_len;
+        payload_len -= header_len;
+
+        rtph265depay->wait_start = FALSE;
+
+#if 0
+        if (donl_present)
+          goto not_implemented_donl_present;
+#endif
+
+        while (payload_len > 2) {
+
+          nalu_size = (payload[0] << 8) | payload[1];
+
+          /* dont include nalu_size */
+          if (nalu_size > (payload_len - 2))
+            nalu_size = payload_len - 2;
+
+          outsize = nalu_size + sizeof (sync_bytes);
+          outbuf = gst_buffer_new_and_alloc (outsize);
+
+          gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+          if (rtph265depay->byte_stream) {
+            memcpy (map.data, sync_bytes, sizeof (sync_bytes));
+          } else {
+            GST_WRITE_UINT32_BE (map.data, nalu_size);
+          }
+
+          /* strip NALU size */
+          payload += 2;
+          payload_len -= 2;
+
+          memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
+          gst_buffer_unmap (outbuf, &map);
+
+          gst_rtp_copy_video_meta (rtph265depay, outbuf, rtp->buffer);
+
+          gst_rtp_h265_depay_handle_nal (rtph265depay, outbuf, timestamp,
+              marker);
+
+          payload += nalu_size;
+          payload_len -= nalu_size;
+        }
+        break;
+      }
+      case 49:
+      {
+        GST_DEBUG_OBJECT (rtph265depay, "Processing Fragmentation Unit");
+
+        /* Fragmentation units (FUs)  Section 4.8 */
+
+        /*    The structure of a Fragmentation Unit (FU)
+         *
+         *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         |    PayloadHdr (Type=49)       |   FU header   | DONL (cond)   |
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
+         | DONL (cond)   |                                               |
+         |-+-+-+-+-+-+-+-+                                               |
+         |                         FU payload                            |
+         |                                                               |
+         |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         |                               :...OPTIONAL RTP padding        |
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         *
+         *
+         */
+
+        /* strip headers */
+        payload += header_len;
+        payload_len -= header_len;
+
+        /* processing FU header */
+        S = (payload[0] & 0x80) == 0x80;
+        E = (payload[0] & 0x40) == 0x40;
+
+        GST_DEBUG_OBJECT (rtph265depay,
+            "FU header with S %d, E %d, nal_unit_type %d", S, E,
+            payload[0] & 0x3f);
+
+        if (rtph265depay->wait_start && !S)
+          goto waiting_start;
+
+#if 0
+        if (donl_present)
+          goto not_implemented_donl_present;
+#endif
+
+        if (S) {
+
+          GST_DEBUG_OBJECT (rtph265depay, "Start of Fragmentation Unit");
+
+          /* If a new FU unit started, while still processing an older one.
+           * Assume that the remote payloader is buggy (doesn't set the end
+           * bit) and send out what we've gathered thusfar */
+          if (G_UNLIKELY (rtph265depay->current_fu_type != 0))
+            gst_rtp_h265_finish_fragmentation_unit (rtph265depay);
+
+          rtph265depay->current_fu_type = nal_unit_type;
+          rtph265depay->fu_timestamp = timestamp;
+
+          rtph265depay->wait_start = FALSE;
+
+          /* reconstruct NAL header */
+          nal_header =
+              ((payload[0] & 0x3f) << 9) | (nuh_layer_id << 3) |
+              nuh_temporal_id_plus1;
+
+          /* go back one byte so we can copy the payload + two bytes more in the front which
+           * will be overwritten by the nal_header
+           */
+          payload -= 1;
+          payload_len += 1;
+
+          nalu_size = payload_len;
+          outsize = nalu_size + sizeof (sync_bytes);
+          outbuf = gst_buffer_new_and_alloc (outsize);
+
+          gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+          if (rtph265depay->byte_stream) {
+            GST_WRITE_UINT32_BE (map.data, 0x00000001);
+          } else {
+            /* will be fixed up in finish_fragmentation_unit() */
+            GST_WRITE_UINT32_BE (map.data, 0xffffffff);
+          }
+          memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
+          map.data[4] = nal_header >> 8;
+          map.data[5] = nal_header & 0xff;
+          gst_buffer_unmap (outbuf, &map);
+
+          gst_rtp_copy_video_meta (rtph265depay, outbuf, rtp->buffer);
+
+          GST_DEBUG_OBJECT (rtph265depay, "queueing %d bytes", outsize);
+
+          /* and assemble in the adapter */
+          gst_adapter_push (rtph265depay->adapter, outbuf);
+        } else {
+
+          GST_DEBUG_OBJECT (rtph265depay,
+              "Following part of Fragmentation Unit");
+
+          /* strip off FU header byte */
+          payload += 1;
+          payload_len -= 1;
+
+          outsize = payload_len;
+          outbuf = gst_buffer_new_and_alloc (outsize);
+          gst_buffer_fill (outbuf, 0, payload, outsize);
+
+          gst_rtp_copy_video_meta (rtph265depay, outbuf, rtp->buffer);
+
+          GST_DEBUG_OBJECT (rtph265depay, "queueing %d bytes", outsize);
+
+          /* and assemble in the adapter */
+          gst_adapter_push (rtph265depay->adapter, outbuf);
+        }
+
+        outbuf = NULL;
+        rtph265depay->fu_marker = marker;
+
+        /* if NAL unit ends, flush the adapter */
+        if (E) {
+          gst_rtp_h265_finish_fragmentation_unit (rtph265depay);
+          GST_DEBUG_OBJECT (rtph265depay, "End of Fragmentation Unit");
+        }
+        break;
+      }
+      case 50:
+        goto not_implemented;   /* PACI packets  Section 4.9 */
+      default:
+      {
+        rtph265depay->wait_start = FALSE;
+
+        /* All other cases: Single NAL unit packet   Section 4.6 */
+        /* the entire payload is the output buffer */
+
+#if 0
+        if (donl_present)
+          goto not_implemented_donl_present;
+#endif
+
+        nalu_size = payload_len;
+        outsize = nalu_size + sizeof (sync_bytes);
+        outbuf = gst_buffer_new_and_alloc (outsize);
+
+        gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+        if (rtph265depay->byte_stream) {
+          memcpy (map.data, sync_bytes, sizeof (sync_bytes));
+        } else {
+          GST_WRITE_UINT32_BE (map.data, nalu_size);
+        }
+        memcpy (map.data + 4, payload, nalu_size);
+        gst_buffer_unmap (outbuf, &map);
+
+        gst_rtp_copy_video_meta (rtph265depay, outbuf, rtp->buffer);
+
+        gst_rtp_h265_depay_handle_nal (rtph265depay, outbuf, timestamp, marker);
+        break;
+      }
+    }
+  }
+
+  return NULL;
+
+  /* ERRORS */
+empty_packet:
+  {
+    GST_DEBUG_OBJECT (rtph265depay, "empty packet");
+    return NULL;
+  }
+waiting_start:
+  {
+    GST_DEBUG_OBJECT (rtph265depay, "waiting for start");
+    return NULL;
+  }
+#if 0
+not_implemented_donl_present:
+  {
+    GST_ELEMENT_ERROR (rtph265depay, STREAM, FORMAT,
+        (NULL), ("DONL field present not supported yet"));
+    return NULL;
+  }
+#endif
+not_implemented:
+  {
+    GST_ELEMENT_ERROR (rtph265depay, STREAM, FORMAT,
+        (NULL), ("NAL unit type %d not supported yet", nal_unit_type));
+    return NULL;
+  }
+}
+
+static gboolean
+gst_rtp_h265_depay_handle_event (GstRTPBaseDepayload * depay, GstEvent * event)
+{
+  GstRtpH265Depay *rtph265depay;
+
+  rtph265depay = GST_RTP_H265_DEPAY (depay);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      gst_rtp_h265_depay_reset (rtph265depay, FALSE);
+      break;
+    default:
+      break;
+  }
+
+  return
+      GST_RTP_BASE_DEPAYLOAD_CLASS (parent_class)->handle_event (depay, event);
+}
+
+static GstStateChangeReturn
+gst_rtp_h265_depay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpH265Depay *rtph265depay;
+  GstStateChangeReturn ret;
+
+  rtph265depay = GST_RTP_H265_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_h265_depay_reset (rtph265depay, TRUE);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_h265_depay_reset (rtph265depay, TRUE);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_h265_depay_plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (rtph265depay_debug, "rtph265depay", 0,
+      "H265 Video RTP Depayloader");
+
+  return gst_element_register (plugin, "rtph265depay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_H265_DEPAY);
+}
diff --git a/gst/rtp/gstrtph265depay.h b/gst/rtp/gstrtph265depay.h
new file mode 100644
index 0000000..cf17694
--- /dev/null
+++ b/gst/rtp/gstrtph265depay.h
@@ -0,0 +1,116 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) <2014> Jurgen Slowack <jurgenslowack@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_H265_DEPAY_H__
+#define __GST_RTP_H265_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+#include "gstrtph265types.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_H265_DEPAY \
+  (gst_rtp_h265_depay_get_type())
+#define GST_RTP_H265_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H265_DEPAY,GstRtpH265Depay))
+#define GST_RTP_H265_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H265_DEPAY,GstRtpH265DepayClass))
+#define GST_IS_RTP_H265_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H265_DEPAY))
+#define GST_IS_RTP_H265_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H265_DEPAY))
+typedef struct _GstRtpH265Depay GstRtpH265Depay;
+typedef struct _GstRtpH265DepayClass GstRtpH265DepayClass;
+
+#define GST_H265_VPS_NUT 32
+#define GST_H265_SPS_NUT 33
+#define GST_H265_PPS_NUT 34
+
+typedef enum
+{
+  GST_H265_STREAM_FORMAT_UNKNOWN,
+  GST_H265_STREAM_FORMAT_BYTESTREAM,
+  GST_H265_STREAM_FORMAT_HVC1,
+  GST_H265_STREAM_FORMAT_HEV1
+} GstH265StreamFormat;
+
+struct _GstRtpH265Depay
+{
+  GstRTPBaseDepayload depayload;
+
+  const gchar *stream_format;
+  GstH265StreamFormat output_format;  /* bytestream, hvc1 or hev1 */
+  gboolean byte_stream;
+
+  GstBuffer *codec_data;
+  GstAdapter *adapter;
+  gboolean wait_start;
+
+  /* nal merging */
+  gboolean merge;
+  GstAdapter *picture_adapter;
+  gboolean picture_start;
+  GstClockTime last_ts;
+  gboolean last_keyframe;
+
+  /* Work around broken payloaders wrt. Fragmentation Units */
+  guint8 current_fu_type;
+  GstClockTime fu_timestamp;
+  gboolean fu_marker;
+
+  /* misc */
+  GPtrArray *vps;
+  GPtrArray *sps;
+  GPtrArray *pps;
+  gboolean new_codec_data;
+
+  /* downstream allocator */
+  GstAllocator *allocator;
+  GstAllocationParams params;
+};
+
+struct _GstRtpH265DepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+typedef struct
+{
+  GstElement *element;
+  GstBuffer *outbuf;
+  GQuark copy_tag;
+} CopyMetaData;
+
+typedef struct
+{
+  GstElement *element;
+  GQuark keep_tag;
+} DropMetaData;
+
+GType gst_rtp_h265_depay_get_type (void);
+
+gboolean gst_rtp_h265_depay_plugin_init (GstPlugin * plugin);
+
+gboolean gst_rtp_h265_add_vps_sps_pps (GstElement * rtph265, GPtrArray * vps,
+    GPtrArray * sps, GPtrArray * pps, GstBuffer * nal);
+
+G_END_DECLS
+#endif /* __GST_RTP_H265_DEPAY_H__ */
diff --git a/gst/rtp/gstrtph265pay.c b/gst/rtp/gstrtph265pay.c
new file mode 100644
index 0000000..9a597e0
--- /dev/null
+++ b/gst/rtp/gstrtph265pay.c
@@ -0,0 +1,1438 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) <2014> Jurgen Slowack <jurgenslowack@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/pbutils/pbutils.h>
+#include <gst/video/video.h>
+
+/* Included to not duplicate gst_rtp_h265_add_vps_sps_pps () */
+#include "gstrtph265depay.h"
+
+#include "gstrtph265pay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtph265pay_debug);
+#define GST_CAT_DEFAULT (rtph265pay_debug)
+
+/* references:
+ *
+ * Internet Draft RTP Payload Format for High Efficiency Video Coding
+ *
+ *                   draft-ietf-payload-rtp-h265-03.txt
+ *
+ * This draft will be replaced with an RFC, so some details may change.
+ *
+ */
+
+static GstStaticPadTemplate gst_rtp_h265_pay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (
+        /* only hvc1 and byte-stream formats supported for now */
+        "video/x-h265, stream-format = (string) hvc1, alignment = (string) au; "
+        /* "video/x-h265, "
+           "stream-format = (string) hev1, alignment = (string) au; " */
+        "video/x-h265, stream-format = (string) byte-stream, "
+        "alignment = (string) { nal, au }")
+    );
+
+static GstStaticPadTemplate gst_rtp_h265_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"H265\"")
+                /** optional parameters **/
+    /* "profile-space = (int) [ 0, 3 ], " */
+    /* "profile-id = (int) [ 0, 31 ], " */
+    /* "tier-flag = (int) [ 0, 1 ], " */
+    /* "level-id = (int) [ 0, 255 ], " */
+    /* "interop-constraints = (string) ANY, " */
+    /* "profile-compatibility-indicator = (string) ANY, " */
+    /* "sprop-sub-layer-id = (int) [ 0, 6 ], " */
+    /* "recv-sub-layer-id = (int) [ 0, 6 ], " */
+    /* "max-recv-level-id = (int) [ 0, 255 ], " */
+    /* "tx-mode = (string) {MST , SST}, " */
+    /* "sprop-vps = (string) ANY, " */
+    /* "sprop-sps = (string) ANY, " */
+    /* "sprop-pps = (string) ANY, " */
+    /* "sprop-sei = (string) ANY, " */
+    /* "max-lsr = (int) ANY, " *//* MUST be in the range of MaxLumaSR to 16 * MaxLumaSR, inclusive */
+    /* "max-lps = (int) ANY, " *//* MUST be in the range of MaxLumaPS to 16 * MaxLumaPS, inclusive */
+    /* "max-cpb = (int) ANY, " *//* MUST be in the range of MaxCPB to 16 * MaxCPB, inclusive */
+    /* "max-dpb = (int) [1, 16], " */
+    /* "max-br = (int) ANY, " *//* MUST be in the range of MaxBR to 16 * MaxBR, inclusive, for the highest level */
+    /* "max-tr = (int) ANY, " *//* MUST be in the range of MaxTileRows to 16 * MaxTileRows, inclusive, for the highest level */
+    /* "max-tc = (int) ANY, " *//* MUST be in the range of MaxTileCols to 16 * MaxTileCols, inclusive, for the highest level */
+    /* "max-fps = (int) ANY, " */
+    /* "sprop-max-don-diff = (int) [0, 32767], " */
+    /* "sprop-depack-buf-nalus = (int) [0, 32767], " */
+    /* "sprop-depack-buf-nalus = (int) [0, 4294967295], " */
+    /* "depack-buf-cap = (int) [1, 4294967295], " */
+    /* "sprop-segmentation-id = (int) [0, 3], " */
+    /* "sprop-spatial-segmentation-idc = (string) ANY, " */
+    /* "dec-parallel-cap = (string) ANY, " */
+    );
+
+#define DEFAULT_CONFIG_INTERVAL		      0
+
+enum
+{
+  PROP_0,
+  PROP_CONFIG_INTERVAL
+};
+
+#define IS_ACCESS_UNIT(x) (((x) >= 0x00) && ((x) < 0x20))
+
+static void gst_rtp_h265_pay_finalize (GObject * object);
+
+static void gst_rtp_h265_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_h265_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_rtp_h265_pay_getcaps (GstRTPBasePayload * payload,
+    GstPad * pad, GstCaps * filter);
+static gboolean gst_rtp_h265_pay_setcaps (GstRTPBasePayload * basepayload,
+    GstCaps * caps);
+static GstFlowReturn gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * pad,
+    GstBuffer * buffer);
+static gboolean gst_rtp_h265_pay_sink_event (GstRTPBasePayload * payload,
+    GstEvent * event);
+static GstStateChangeReturn gst_rtp_h265_pay_change_state (GstElement *
+    element, GstStateChange transition);
+
+#define gst_rtp_h265_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpH265Pay, gst_rtp_h265_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_h265_pay_class_init (GstRtpH265PayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->set_property = gst_rtp_h265_pay_set_property;
+  gobject_class->get_property = gst_rtp_h265_pay_get_property;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_CONFIG_INTERVAL,
+      g_param_spec_int ("config-interval",
+          "VPS SPS PPS Send Interval",
+          "Send VPS, SPS and PPS Insertion Interval in seconds (sprop parameter sets "
+          "will be multiplexed in the data stream when detected.) "
+          "(0 = disabled, -1 = send with every IDR frame)",
+          -1, 3600, DEFAULT_CONFIG_INTERVAL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
+  gobject_class->finalize = gst_rtp_h265_pay_finalize;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h265_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_h265_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP H265 payloader",
+      "Codec/Payloader/Network/RTP",
+      "Payload-encode H265 video into RTP packets (RFC 7798)",
+      "Jurgen Slowack <jurgenslowack@gmail.com>");
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_rtp_h265_pay_change_state);
+
+  gstrtpbasepayload_class->get_caps = gst_rtp_h265_pay_getcaps;
+  gstrtpbasepayload_class->set_caps = gst_rtp_h265_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_h265_pay_handle_buffer;
+  gstrtpbasepayload_class->sink_event = gst_rtp_h265_pay_sink_event;
+
+  GST_DEBUG_CATEGORY_INIT (rtph265pay_debug, "rtph265pay", 0,
+      "H265 RTP Payloader");
+}
+
+static void
+gst_rtp_h265_pay_init (GstRtpH265Pay * rtph265pay)
+{
+  rtph265pay->queue = g_array_new (FALSE, FALSE, sizeof (guint));
+  rtph265pay->sps = g_ptr_array_new_with_free_func (
+      (GDestroyNotify) gst_buffer_unref);
+  rtph265pay->pps = g_ptr_array_new_with_free_func (
+      (GDestroyNotify) gst_buffer_unref);
+  rtph265pay->vps = g_ptr_array_new_with_free_func (
+      (GDestroyNotify) gst_buffer_unref);
+  rtph265pay->last_vps_sps_pps = -1;
+  rtph265pay->vps_sps_pps_interval = DEFAULT_CONFIG_INTERVAL;
+
+  rtph265pay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_h265_pay_clear_vps_sps_pps (GstRtpH265Pay * rtph265pay)
+{
+  g_ptr_array_set_size (rtph265pay->vps, 0);
+  g_ptr_array_set_size (rtph265pay->sps, 0);
+  g_ptr_array_set_size (rtph265pay->pps, 0);
+}
+
+static void
+gst_rtp_h265_pay_finalize (GObject * object)
+{
+  GstRtpH265Pay *rtph265pay;
+
+  rtph265pay = GST_RTP_H265_PAY (object);
+
+  g_array_free (rtph265pay->queue, TRUE);
+
+  g_ptr_array_free (rtph265pay->sps, TRUE);
+  g_ptr_array_free (rtph265pay->pps, TRUE);
+  g_ptr_array_free (rtph265pay->vps, TRUE);
+
+  g_object_unref (rtph265pay->adapter);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static const gchar all_levels[][4] = {
+  "1",
+  "2",
+  "2.1",
+  "3",
+  "3.1",
+  "4",
+  "4.1",
+  "5",
+  "5.1",
+  "5.2",
+  "6",
+  "6.1",
+  "6.2"
+};
+
+static gboolean
+parse_field (GstStructure * s, const gchar * field, gulong min, gulong max,
+    guint8 * result)
+{
+  const gchar *str;
+
+  g_assert (result != NULL);
+
+  str = gst_structure_get_string (s, field);
+  if (str != NULL && *str != '\0') {
+    gulong value;
+    gchar *end;
+
+    value = strtoul (str, &end, 10);
+    if (*end == '\0' && value >= min && value <= max) {
+      *result = (guint8) value;
+    } else {
+      return FALSE;
+    }
+  } else {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static GstCaps *
+gst_rtp_h265_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad,
+    GstCaps * filter)
+{
+  GstCaps *template_caps;
+  GstCaps *allowed_caps;
+  GstCaps *caps;
+  GstCaps *icaps;
+  guint i;
+
+  allowed_caps =
+      gst_pad_peer_query_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), NULL);
+
+  if (allowed_caps == NULL)
+    return NULL;
+
+  template_caps =
+      gst_static_pad_template_get_caps (&gst_rtp_h265_pay_sink_template);
+
+  if (gst_caps_is_any (allowed_caps)) {
+    caps = gst_caps_ref (template_caps);
+    goto done;
+  }
+
+  if (gst_caps_is_empty (allowed_caps)) {
+    caps = gst_caps_ref (allowed_caps);
+    goto done;
+  }
+
+  caps = gst_caps_new_empty ();
+  for (i = 0; i < gst_caps_get_size (allowed_caps); i++) {
+    GstStructure *s = gst_caps_get_structure (allowed_caps, i);
+    GstStructure *new_s = gst_structure_new_empty ("video/x-h265");
+    guint8 ptl[12] = { 0, };
+    guint8 value;
+
+    if (parse_field (s, "profile-id", 0, 31, &value)) {
+      const gchar *profile;
+
+      ptl[0] = value;
+      profile = gst_codec_utils_h265_get_profile (ptl, sizeof (ptl));
+      if (profile != NULL) {
+        GST_DEBUG_OBJECT (payload, "profile %s", profile);
+        gst_structure_set (new_s, "profile", G_TYPE_STRING, profile, NULL);
+      } else {
+        GST_WARNING_OBJECT (payload, "invalid profile-id %d in caps", value);
+      }
+    } else {
+      GST_DEBUG_OBJECT (payload, "no valid profile-id in caps");
+    }
+
+    if (parse_field (s, "tier-flag", 0, 1, &value)) {
+      const gchar *tier;
+
+      ptl[0] |= value << 5;
+      tier = gst_codec_utils_h265_get_tier (ptl, sizeof (ptl));
+      GST_DEBUG_OBJECT (payload, "tier %s", tier);
+      gst_structure_set (new_s, "tier", G_TYPE_STRING, tier, NULL);
+    } else {
+      GST_DEBUG_OBJECT (payload, "no valid tier-flag in caps");
+    }
+
+    if (parse_field (s, "level-id", 0, 255, &value)) {
+      const gchar *level;
+
+      ptl[11] = value;
+      level = gst_codec_utils_h265_get_level (ptl, sizeof (ptl));
+      if (level != NULL) {
+        GST_DEBUG_OBJECT (payload, "level %s", level);
+        if (strcmp (level, "1") == 0) {
+          gst_structure_set (new_s, "level", G_TYPE_STRING, level, NULL);
+        } else {
+          GValue levels = { 0, };
+          GValue val = { 0, };
+          int j;
+
+          g_value_init (&levels, GST_TYPE_LIST);
+          g_value_init (&val, G_TYPE_STRING);
+
+          for (j = 0; j < G_N_ELEMENTS (all_levels); j++) {
+            g_value_set_static_string (&val, all_levels[j]);
+            gst_value_list_prepend_value (&levels, &val);
+            if (!strcmp (level, all_levels[j]))
+              break;
+          }
+          gst_structure_take_value (new_s, "level", &levels);
+        }
+      } else {
+        GST_WARNING_OBJECT (payload, "invalid level-id %d in caps", value);
+      }
+    } else {
+      GST_DEBUG_OBJECT (payload, "no valid level-id in caps");
+    }
+
+    caps = gst_caps_merge_structure (caps, new_s);
+  }
+
+  icaps = gst_caps_intersect (caps, template_caps);
+  gst_caps_unref (caps);
+  caps = icaps;
+
+done:
+
+  if (filter) {
+    GstCaps *tmp;
+
+    GST_DEBUG_OBJECT (payload, "Intersect %" GST_PTR_FORMAT " and filter %"
+        GST_PTR_FORMAT, caps, filter);
+    tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    caps = tmp;
+  }
+
+  gst_caps_unref (template_caps);
+  gst_caps_unref (allowed_caps);
+
+  GST_LOG_OBJECT (payload, "returning caps %" GST_PTR_FORMAT, caps);
+  return caps;
+}
+
+/* take the currently configured VPS, SPS and PPS lists and set them on the
+ * caps */
+static gboolean
+gst_rtp_h265_pay_set_vps_sps_pps (GstRTPBasePayload * basepayload)
+{
+  GstRtpH265Pay *payloader = GST_RTP_H265_PAY (basepayload);
+  gchar *set;
+  GString *vps;
+  GString *sps;
+  GString *pps;
+  guint count;
+  gboolean res;
+  GstMapInfo map;
+  guint i;
+
+  vps = g_string_new ("");
+  sps = g_string_new ("");
+  pps = g_string_new ("");
+  count = 0;
+
+  for (i = 0; i < payloader->vps->len; i++) {
+    GstBuffer *vps_buf =
+        GST_BUFFER_CAST (g_ptr_array_index (payloader->vps, i));
+
+    gst_buffer_map (vps_buf, &map, GST_MAP_READ);
+    set = g_base64_encode (map.data, map.size);
+    gst_buffer_unmap (vps_buf, &map);
+
+    g_string_append_printf (vps, "%s%s", i ? "," : "", set);
+    g_free (set);
+    count++;
+  }
+  for (i = 0; i < payloader->sps->len; i++) {
+    GstBuffer *sps_buf =
+        GST_BUFFER_CAST (g_ptr_array_index (payloader->sps, i));
+
+    gst_buffer_map (sps_buf, &map, GST_MAP_READ);
+    set = g_base64_encode (map.data, map.size);
+    gst_buffer_unmap (sps_buf, &map);
+
+    g_string_append_printf (sps, "%s%s", i ? "," : "", set);
+    g_free (set);
+    count++;
+  }
+  for (i = 0; i < payloader->pps->len; i++) {
+    GstBuffer *pps_buf =
+        GST_BUFFER_CAST (g_ptr_array_index (payloader->pps, i));
+
+    gst_buffer_map (pps_buf, &map, GST_MAP_READ);
+    set = g_base64_encode (map.data, map.size);
+    gst_buffer_unmap (pps_buf, &map);
+
+    g_string_append_printf (pps, "%s%s", i ? "," : "", set);
+    g_free (set);
+    count++;
+  }
+
+  if (G_LIKELY (count)) {
+    /* combine into output caps */
+    res = gst_rtp_base_payload_set_outcaps (basepayload,
+        "sprop-vps", G_TYPE_STRING, vps->str,
+        "sprop-sps", G_TYPE_STRING, sps->str,
+        "sprop-pps", G_TYPE_STRING, pps->str, NULL);
+  } else {
+    res = gst_rtp_base_payload_set_outcaps (basepayload, NULL);
+  }
+  g_string_free (vps, TRUE);
+  g_string_free (sps, TRUE);
+  g_string_free (pps, TRUE);
+
+  return res;
+}
+
+
+static gboolean
+gst_rtp_h265_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+  GstRtpH265Pay *rtph265pay;
+  GstStructure *str;
+  const GValue *value;
+  GstMapInfo map;
+  guint8 *data;
+  gsize size;
+  GstBuffer *buffer;
+  const gchar *alignment, *stream_format;
+  guint8 num_arrays;
+
+  rtph265pay = GST_RTP_H265_PAY (basepayload);
+
+  str = gst_caps_get_structure (caps, 0);
+
+  /* we can only set the output caps when we found the sprops and profile
+   * NALs */
+  gst_rtp_base_payload_set_options (basepayload, "video", TRUE, "H265", 90000);
+
+  rtph265pay->alignment = GST_H265_ALIGNMENT_UNKNOWN;
+  alignment = gst_structure_get_string (str, "alignment");
+  if (alignment) {
+    if (g_str_equal (alignment, "au"))
+      rtph265pay->alignment = GST_H265_ALIGNMENT_AU;
+    if (g_str_equal (alignment, "nal"))
+      rtph265pay->alignment = GST_H265_ALIGNMENT_NAL;
+  }
+
+  rtph265pay->stream_format = GST_H265_STREAM_FORMAT_UNKNOWN;
+  stream_format = gst_structure_get_string (str, "stream-format");
+  if (stream_format) {
+    if (g_str_equal (stream_format, "hvc1"))
+      rtph265pay->stream_format = GST_H265_STREAM_FORMAT_HVC1;
+    if (g_str_equal (stream_format, "hev1"))
+      rtph265pay->stream_format = GST_H265_STREAM_FORMAT_HEV1;
+    if (g_str_equal (stream_format, "byte-stream"))
+      rtph265pay->stream_format = GST_H265_STREAM_FORMAT_BYTESTREAM;
+  }
+
+  /* packetized HEVC video has a codec_data */
+  if ((value = gst_structure_get_value (str, "codec_data"))) {
+    guint num_vps, num_sps, num_pps;
+    gint i, j, nal_size;
+
+    GST_DEBUG_OBJECT (rtph265pay, "have packetized h265");
+
+    buffer = gst_value_get_buffer (value);
+
+    gst_buffer_map (buffer, &map, GST_MAP_READ);
+    data = map.data;
+    size = map.size;
+
+    /* parse the hevcC data */
+    if (size < 23)
+      goto hevcc_too_small;
+    /* HEVCDecoderConfigurationVersion (must be 1) */
+    if (data[0] != 1)
+      goto wrong_version;
+
+    /* profile_space | tier_flag | profile_idc */
+    GST_DEBUG_OBJECT (rtph265pay, "profile %06x", data[1]);
+
+    /* profile_compatibility_flags */
+    for (i = 2; i < 6; i++) {
+      for (j = 7; j >= 0; j--) {
+        GST_DEBUG_OBJECT (rtph265pay, "profile_compatibility_flag %06x",
+            (data[i] >> j) & 1);
+      }
+    }
+
+    GST_DEBUG_OBJECT (rtph265pay, "progressive_source_flag %06x",
+        (data[6] >> 7) & 1);
+    GST_DEBUG_OBJECT (rtph265pay, "interlaced_source_flag %06x",
+        (data[6] >> 6) & 1);
+    GST_DEBUG_OBJECT (rtph265pay, "non_packed_constraint_flag %06x",
+        (data[6] >> 5) & 1);
+    GST_DEBUG_OBJECT (rtph265pay, "frame_only_constraint_flag %06x",
+        (data[6] >> 4) & 1);
+
+    GST_DEBUG_OBJECT (rtph265pay, "level_idc %06x", data[12]);
+
+    GST_DEBUG_OBJECT (rtph265pay, "min_spatial_segmentation_idc %06x",
+        ((data[13] ^ 0xf0) << 8) + data[14]);
+    GST_DEBUG_OBJECT (rtph265pay, "parrallelismType %06x (ignored by paloader)",
+        data[15]);
+
+    GST_DEBUG_OBJECT (rtph265pay, "sps_chroma_format_idc %06x",
+        data[16] ^ 0xfc);
+    GST_DEBUG_OBJECT (rtph265pay, "bit_depth_luma_minus8 %06x",
+        data[17] ^ 0xf8);
+    GST_DEBUG_OBJECT (rtph265pay, "bit_depth_chroma_minus8 %06x",
+        data[18] ^ 0xf8);
+    GST_DEBUG_OBJECT (rtph265pay, "avgFrameRate %06x", data[19]);
+    GST_DEBUG_OBJECT (rtph265pay, "avgFrameRate %06x", data[20]);
+
+    /* constFrameRate(2 bits): 0, stream may or may not be of constant framerate
+     * numTemporalLayers (3 bits): number of temporal layers, value from SPS
+     * TemporalIdNested (1 bit): sps_temporal_id_nesting_flag from SPS
+     * lengthSizeMinusOne (2 bits): plus 1 indicates the length of the NALUnitLength */
+    GST_DEBUG_OBJECT (rtph265pay, "constFrameRate %06x",
+        (data[21] >> 6) & 0x03);
+    GST_DEBUG_OBJECT (rtph265pay, "numTemporalLayers %06x",
+        (data[21] >> 3) & 0x07);
+    GST_DEBUG_OBJECT (rtph265pay, "temporal_id_nesting_flag %06x",
+        (data[21] >> 2) & 0x01);
+
+    rtph265pay->nal_length_size = (data[21] & 0x3) + 1;
+    GST_DEBUG_OBJECT (rtph265pay, "nal length %u", rtph265pay->nal_length_size);
+
+    num_arrays = GST_READ_UINT8 (data + 22);
+
+    data += 23;
+    size -= 23;
+
+    if (num_arrays > 0) {
+      if ((data[0] & 0x3f) == 0x20) {   /* VPS */
+
+        data++;
+        num_vps = data[0] << 8 | data[1];
+        data += 2;
+        size -= 2;
+
+        for (i = 0; i < num_vps; i++) {
+
+          GstBuffer *vps_buf;
+
+          if (size < 2)
+            goto hevcc_error;
+
+          nal_size = (data[0] << 8) | data[1];
+          data += 2;
+          size -= 2;
+
+          GST_LOG_OBJECT (rtph265pay, "VPS %d size %d", i, nal_size);
+
+          if (size < nal_size)
+            goto hevcc_error;
+
+          /* make a buffer out of it and add to VPS list */
+          vps_buf = gst_buffer_new_and_alloc (nal_size);
+          gst_buffer_fill (vps_buf, 0, data, nal_size);
+          gst_rtp_h265_add_vps_sps_pps (GST_ELEMENT (rtph265pay),
+              rtph265pay->vps, rtph265pay->sps, rtph265pay->pps, vps_buf);
+          data += nal_size;
+          size -= nal_size;
+        }
+      }
+
+      --num_arrays;
+    }
+
+    if (num_arrays > 0) {
+      if ((data[0] & 0x3f) == 0x21) {   /* SPS */
+
+        data++;
+        num_sps = data[0] << 8 | data[1];
+        data += 2;
+        size -= 2;
+
+        for (i = 0; i < num_sps; i++) {
+
+          GstBuffer *sps_buf;
+
+          if (size < 2)
+            goto hevcc_error;
+
+          nal_size = (data[0] << 8) | data[1];
+          data += 2;
+          size -= 2;
+
+          GST_LOG_OBJECT (rtph265pay, "SPS %d size %d", i, nal_size);
+
+          if (size < nal_size)
+            goto hevcc_error;
+
+          /* make a buffer out of it and add to SPS list */
+          sps_buf = gst_buffer_new_and_alloc (nal_size);
+          gst_buffer_fill (sps_buf, 0, data, nal_size);
+          gst_rtp_h265_add_vps_sps_pps (GST_ELEMENT (rtph265pay),
+              rtph265pay->vps, rtph265pay->sps, rtph265pay->pps, sps_buf);
+          data += nal_size;
+          size -= nal_size;
+        }
+      }
+
+      --num_arrays;
+    }
+
+    if (num_arrays > 0) {
+      if ((data[0] & 0x3f) == 0x22) {   /* PPS */
+
+        data++;
+        num_pps = data[0] << 8 | data[1];
+        data += 2;
+        size -= 2;
+
+        for (i = 0; i < num_pps; i++) {
+
+          GstBuffer *pps_buf;
+
+          if (size < 2)
+            goto hevcc_error;
+
+          nal_size = (data[0] << 8) | data[1];
+          data += 2;
+          size -= 2;
+
+          GST_LOG_OBJECT (rtph265pay, "PPS %d size %d", i, nal_size);
+
+          if (size < nal_size)
+            goto hevcc_error;
+
+          /* make a buffer out of it and add to PPS list */
+          pps_buf = gst_buffer_new_and_alloc (nal_size);
+          gst_buffer_fill (pps_buf, 0, data, nal_size);
+          gst_rtp_h265_add_vps_sps_pps (GST_ELEMENT (rtph265pay),
+              rtph265pay->vps, rtph265pay->sps, rtph265pay->pps, pps_buf);
+          data += nal_size;
+          size -= nal_size;
+        }
+      }
+
+      --num_arrays;
+    }
+
+    /* and update the caps with the collected data */
+    if (!gst_rtp_h265_pay_set_vps_sps_pps (basepayload))
+      goto set_vps_sps_pps_failed;
+
+    GST_DEBUG_OBJECT (rtph265pay, "Caps have been set");
+
+    gst_buffer_unmap (buffer, &map);
+  } else {
+    GST_DEBUG_OBJECT (rtph265pay, "have bytestream h265");
+  }
+
+  return TRUE;
+
+hevcc_too_small:
+  {
+    GST_ERROR_OBJECT (rtph265pay, "hevcC size %" G_GSIZE_FORMAT " < 7", size);
+    goto error;
+  }
+wrong_version:
+  {
+    GST_ERROR_OBJECT (rtph265pay, "wrong hevcC version");
+    goto error;
+  }
+hevcc_error:
+  {
+    GST_ERROR_OBJECT (rtph265pay, "hevcC too small ");
+    goto error;
+  }
+set_vps_sps_pps_failed:
+  {
+    GST_ERROR_OBJECT (rtph265pay, "failed to set vps/sps/pps");
+    goto error;
+  }
+error:
+  {
+    gst_buffer_unmap (buffer, &map);
+    return FALSE;
+  }
+}
+
+static guint
+next_start_code (const guint8 * data, guint size)
+{
+  /* Boyer-Moore string matching algorithm, in a degenerative
+   * sense because our search 'alphabet' is binary - 0 & 1 only.
+   * This allow us to simplify the general BM algorithm to a very
+   * simple form. */
+  /* assume 1 is in the 3rd byte */
+  guint offset = 2;
+
+  while (offset < size) {
+    if (1 == data[offset]) {
+      unsigned int shift = offset;
+
+      if (0 == data[--shift]) {
+        if (0 == data[--shift]) {
+          return shift;
+        }
+      }
+      /* The jump is always 3 because of the 1 previously matched.
+       * All the 0's must be after this '1' matched at offset */
+      offset += 3;
+    } else if (0 == data[offset]) {
+      /* maybe next byte is 1? */
+      offset++;
+    } else {
+      /* can jump 3 bytes forward */
+      offset += 3;
+    }
+    /* at each iteration, we rescan in a backward manner until
+     * we match 0.0.1 in reverse order. Since our search string
+     * has only 2 'alpabets' (i.e. 0 & 1), we know that any
+     * mismatch will force us to shift a fixed number of steps */
+  }
+  GST_DEBUG ("Cannot find next NAL start code. returning %u", size);
+
+  return size;
+}
+
+static gboolean
+gst_rtp_h265_pay_decode_nal (GstRtpH265Pay * payloader,
+    const guint8 * data, guint size, GstClockTime dts, GstClockTime pts)
+{
+  guint8 type;
+  gboolean updated;
+
+  /* default is no update */
+  updated = FALSE;
+
+  GST_DEBUG_OBJECT (payloader, "NAL payload size %u", size);
+
+  type = (data[0] >> 1) & 0x3f;
+
+  /* We record the timestamp of the last SPS/PPS so
+   * that we can insert them at regular intervals and when needed. */
+  if (GST_H265_NAL_VPS == type || GST_H265_NAL_SPS == type
+      || GST_H265_NAL_PPS == type) {
+    GstBuffer *nal;
+
+    /* trailing 0x0 are not part of the VPS/SPS/PPS */
+    while (size > 0 && data[size - 1] == 0x0)
+      size--;
+
+    /* encode the entire NAL in base64 */
+    GST_DEBUG_OBJECT (payloader, "found %s (type 0x%x), size %u",
+        type == GST_H265_NAL_VPS ? "VPS" : type == GST_H265_NAL_SPS ?
+        "SPS" : "PPS", type, size);
+
+    nal = gst_buffer_new_allocate (NULL, size, NULL);
+    gst_buffer_fill (nal, 0, data, size);
+
+    updated = gst_rtp_h265_add_vps_sps_pps (GST_ELEMENT (payloader),
+        payloader->vps, payloader->sps, payloader->pps, nal);
+
+    /* remember when we last saw VPS */
+    if (updated && pts != -1)
+      payloader->last_vps_sps_pps = pts;
+  } else {
+    GST_DEBUG_OBJECT (payloader, "NALU type 0x%x, size %u", type, size);
+  }
+
+  return updated;
+}
+
+static GstFlowReturn
+gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
+    GPtrArray * paybufs, GstClockTime dts, GstClockTime pts);
+
+static GstFlowReturn
+gst_rtp_h265_pay_send_vps_sps_pps (GstRTPBasePayload * basepayload,
+    GstRtpH265Pay * rtph265pay, GstClockTime dts, GstClockTime pts)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  gboolean sent_all_vps_sps_pps = TRUE;
+  guint i;
+  GPtrArray *bufs;
+
+  bufs = g_ptr_array_new ();
+
+  for (i = 0; i < rtph265pay->vps->len; i++) {
+    GstBuffer *vps_buf =
+        GST_BUFFER_CAST (g_ptr_array_index (rtph265pay->vps, i));
+
+    GST_DEBUG_OBJECT (rtph265pay, "inserting VPS in the stream");
+    g_ptr_array_add (bufs, gst_buffer_ref (vps_buf));
+  }
+  for (i = 0; i < rtph265pay->sps->len; i++) {
+    GstBuffer *sps_buf =
+        GST_BUFFER_CAST (g_ptr_array_index (rtph265pay->sps, i));
+
+    GST_DEBUG_OBJECT (rtph265pay, "inserting SPS in the stream");
+    g_ptr_array_add (bufs, gst_buffer_ref (sps_buf));
+  }
+  for (i = 0; i < rtph265pay->pps->len; i++) {
+    GstBuffer *pps_buf =
+        GST_BUFFER_CAST (g_ptr_array_index (rtph265pay->pps, i));
+
+    GST_DEBUG_OBJECT (rtph265pay, "inserting PPS in the stream");
+    g_ptr_array_add (bufs, gst_buffer_ref (pps_buf));
+  }
+
+  ret = gst_rtp_h265_pay_payload_nal (basepayload, bufs, dts, pts);
+  if (ret != GST_FLOW_OK) {
+    /* not critical but warn */
+    GST_WARNING_OBJECT (basepayload, "failed pushing VPS/SPS/PPS");
+
+    sent_all_vps_sps_pps = FALSE;
+  }
+
+  if (pts != -1 && sent_all_vps_sps_pps)
+    rtph265pay->last_vps_sps_pps = pts;
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
+    GPtrArray * paybufs, GstClockTime dts, GstClockTime pts)
+{
+  GstRtpH265Pay *rtph265pay;
+  guint mtu;
+  GstFlowReturn ret;
+  gint i;
+  gboolean sent_ps;
+
+  rtph265pay = GST_RTP_H265_PAY (basepayload);
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (rtph265pay);
+
+  /* should set src caps before pushing stuff,
+   * and if we did not see enough VPS/SPS/PPS, that may not be the case */
+  if (G_UNLIKELY (!gst_pad_has_current_caps (GST_RTP_BASE_PAYLOAD_SRCPAD
+              (basepayload))))
+    gst_rtp_h265_pay_set_vps_sps_pps (basepayload);
+
+  ret = GST_FLOW_OK;
+  sent_ps = FALSE;
+  for (i = 0; i < paybufs->len; i++) {
+    guint8 nalHeader[2];
+    guint8 nalType;
+    guint packet_len, payload_len;
+    GstBuffer *paybuf;
+    GstBuffer *outbuf;
+    guint8 *payload;
+    GstBufferList *outlist = NULL;
+    gboolean send_ps;
+    GstRTPBuffer rtp = { NULL };
+    guint size;
+
+    paybuf = g_ptr_array_index (paybufs, i);
+
+    if (ret != GST_FLOW_OK) {
+      /* unref buffers that will not be payloaded after a flow error */
+      gst_buffer_unref (paybuf);
+      continue;
+    }
+
+    size = gst_buffer_get_size (paybuf);
+    gst_buffer_extract (paybuf, 0, nalHeader, 2);
+    nalType = (nalHeader[0] >> 1) & 0x3f;
+
+    GST_DEBUG_OBJECT (rtph265pay, "Processing Buffer with NAL TYPE=%d",
+        nalType);
+
+    send_ps = FALSE;
+
+    /* check if we need to emit an VPS/SPS/PPS now */
+    if ((nalType == GST_H265_NAL_SLICE_TRAIL_N)
+        || (nalType == GST_H265_NAL_SLICE_TRAIL_R)
+        || (nalType == GST_H265_NAL_SLICE_TSA_N)
+        || (nalType == GST_H265_NAL_SLICE_TSA_R)
+        || (nalType == GST_H265_NAL_SLICE_STSA_N)
+        || (nalType == GST_H265_NAL_SLICE_STSA_R)
+        || (nalType == GST_H265_NAL_SLICE_RASL_N)
+        || (nalType == GST_H265_NAL_SLICE_RASL_R)
+        || (nalType == GST_H265_NAL_SLICE_BLA_W_LP)
+        || (nalType == GST_H265_NAL_SLICE_BLA_W_RADL)
+        || (nalType == GST_H265_NAL_SLICE_BLA_N_LP)
+        || (nalType == GST_H265_NAL_SLICE_IDR_W_RADL)
+        || (nalType == GST_H265_NAL_SLICE_IDR_N_LP)
+        || (nalType == GST_H265_NAL_SLICE_CRA_NUT)) {
+      if (rtph265pay->vps_sps_pps_interval > 0) {
+        if (rtph265pay->last_vps_sps_pps != -1) {
+          guint64 diff;
+
+          GST_LOG_OBJECT (rtph265pay,
+              "now %" GST_TIME_FORMAT ", last VPS/SPS/PPS %" GST_TIME_FORMAT,
+              GST_TIME_ARGS (pts),
+              GST_TIME_ARGS (rtph265pay->last_vps_sps_pps));
+
+          /* calculate diff between last SPS/PPS in milliseconds */
+          if (pts > rtph265pay->last_vps_sps_pps)
+            diff = pts - rtph265pay->last_vps_sps_pps;
+          else
+            diff = 0;
+
+          GST_DEBUG_OBJECT (rtph265pay,
+              "interval since last VPS/SPS/PPS %" GST_TIME_FORMAT,
+              GST_TIME_ARGS (diff));
+
+          /* bigger than interval, queue SPS/PPS */
+          if (GST_TIME_AS_SECONDS (diff) >= rtph265pay->vps_sps_pps_interval) {
+            GST_DEBUG_OBJECT (rtph265pay, "time to send VPS/SPS/PPS");
+            send_ps = TRUE;
+          }
+        } else {
+          /* no known previous SPS/PPS time, send now */
+          GST_DEBUG_OBJECT (rtph265pay,
+              "no previous VPS/SPS/PPS time, send now");
+          send_ps = TRUE;
+        }
+      } else if (rtph265pay->vps_sps_pps_interval == -1
+          && (nalType == GST_H265_NAL_SLICE_IDR_W_RADL
+              || nalType == GST_H265_NAL_SLICE_IDR_N_LP)) {
+        /* send VPS/SPS/PPS before every IDR frame */
+        send_ps = TRUE;
+      }
+    }
+
+    if (!sent_ps && (send_ps || rtph265pay->send_vps_sps_pps)) {
+      /* we need to send SPS/PPS now first. FIXME, don't use the pts for
+       * checking when we need to send SPS/PPS but convert to running_time
+       * first */
+      rtph265pay->send_vps_sps_pps = FALSE;
+      sent_ps = TRUE;
+      GST_DEBUG_OBJECT (rtph265pay, "sending VPS/SPS/PPS before current frame");
+      ret =
+          gst_rtp_h265_pay_send_vps_sps_pps (basepayload, rtph265pay, dts, pts);
+      if (ret != GST_FLOW_OK) {
+        gst_buffer_unref (paybuf);
+        continue;
+      }
+    }
+
+    packet_len = gst_rtp_buffer_calc_packet_len (size, 0, 0);
+
+    if (packet_len < mtu) {
+      GST_DEBUG_OBJECT (rtph265pay,
+          "NAL Unit fit in one packet datasize=%d mtu=%d", size, mtu);
+      /* will fit in one packet */
+
+      /* use buffer lists
+       * create buffer without payload containing only the RTP header
+       * (memory block at index 0) */
+      outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+
+      gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+      /* only set the marker bit on packets containing access units */
+      if (i == paybufs->len - 1
+          && rtph265pay->alignment == GST_H265_ALIGNMENT_AU
+          && IS_ACCESS_UNIT (nalType)) {
+        gst_rtp_buffer_set_marker (&rtp, 1);
+      }
+
+      /* timestamp the outbuffer */
+      GST_BUFFER_PTS (outbuf) = pts;
+      GST_BUFFER_DTS (outbuf) = dts;
+
+      /* insert payload memory block */
+      gst_rtp_copy_video_meta (rtph265pay, outbuf, paybuf);
+      outbuf = gst_buffer_append (outbuf, paybuf);
+
+      outlist = gst_buffer_list_new ();
+
+      /* add the buffer to the buffer list */
+      gst_buffer_list_add (outlist, outbuf);
+
+      gst_rtp_buffer_unmap (&rtp);
+
+      /* push the list to the next element in the pipe */
+      ret = gst_rtp_base_payload_push_list (basepayload, outlist);
+    } else {
+      /* fragmentation Units */
+      guint limitedSize;
+      int ii = 0, start = 1, end = 0, pos = 0;
+
+      GST_DEBUG_OBJECT (basepayload,
+          "NAL Unit DOES NOT fit in one packet datasize=%d mtu=%d", size, mtu);
+
+      pos += 2;
+      size -= 2;
+
+      GST_DEBUG_OBJECT (basepayload, "Using FU fragmentation for data size=%d",
+          size);
+
+      /* We keep 3 bytes for PayloadHdr and FU Header */
+      payload_len = gst_rtp_buffer_calc_payload_len (mtu - 3, 0, 0);
+
+      outlist = gst_buffer_list_new ();
+
+      while (end == 0) {
+        limitedSize = size < payload_len ? size : payload_len;
+        GST_DEBUG_OBJECT (basepayload,
+            "Inside  FU fragmentation limitedSize=%d iteration=%d", limitedSize,
+            ii);
+
+        /* use buffer lists
+         * create buffer without payload containing only the RTP header
+         * (memory block at index 0), and with space for PayloadHdr and FU header */
+        outbuf = gst_rtp_buffer_new_allocate (3, 0, 0);
+
+        gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+        GST_BUFFER_DTS (outbuf) = dts;
+        GST_BUFFER_PTS (outbuf) = pts;
+        payload = gst_rtp_buffer_get_payload (&rtp);
+
+        if (limitedSize == size) {
+          GST_DEBUG_OBJECT (basepayload, "end size=%d iteration=%d", size, ii);
+          end = 1;
+        }
+
+        /* PayloadHdr (type = 49) */
+        payload[0] = (nalHeader[0] & 0x81) | (49 << 1);
+        payload[1] = nalHeader[1];
+
+        /* set the marker bit on the last packet of an access unit */
+        if (IS_ACCESS_UNIT (nalType)) {
+          gst_rtp_buffer_set_marker (&rtp,
+              end && i == paybufs->len - 1
+              && rtph265pay->alignment == GST_H265_ALIGNMENT_AU);
+        }
+
+        /* FU Header */
+        payload[2] = (start << 7) | (end << 6) | (nalType & 0x3f);
+
+        gst_rtp_buffer_unmap (&rtp);
+
+        /* insert payload memory block */
+        gst_rtp_copy_video_meta (rtph265pay, outbuf, paybuf);
+        gst_buffer_copy_into (outbuf, paybuf, GST_BUFFER_COPY_MEMORY, pos,
+            limitedSize);
+        /* add the buffer to the buffer list */
+        gst_buffer_list_add (outlist, outbuf);
+
+        size -= limitedSize;
+        pos += limitedSize;
+        ii++;
+        start = 0;
+      }
+
+      ret = gst_rtp_base_payload_push_list (basepayload, outlist);
+      gst_buffer_unref (paybuf);
+    }
+  }
+
+  g_ptr_array_free (paybufs, TRUE);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpH265Pay *rtph265pay;
+  GstFlowReturn ret;
+  gsize size;
+  guint nal_len, i;
+  GstMapInfo map;
+  const guint8 *data;
+  GstClockTime dts, pts;
+  GArray *nal_queue;
+  gboolean hevc;
+  GstBuffer *paybuf = NULL;
+  gsize skip;
+
+  rtph265pay = GST_RTP_H265_PAY (basepayload);
+
+  /* the input buffer contains one or more NAL units */
+
+  hevc = (rtph265pay->stream_format == GST_H265_STREAM_FORMAT_HEV1)
+      || (rtph265pay->stream_format == GST_H265_STREAM_FORMAT_HVC1);
+
+  if (hevc) {
+    /* In hevc mode, there is no adapter, so nothing to flush */
+    if (buffer == NULL)
+      return GST_FLOW_OK;
+    gst_buffer_map (buffer, &map, GST_MAP_READ);
+    data = map.data;
+    size = map.size;
+    pts = GST_BUFFER_PTS (buffer);
+    dts = GST_BUFFER_DTS (buffer);
+    GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes", size);
+  } else {
+    dts = gst_adapter_prev_dts (rtph265pay->adapter, NULL);
+    pts = gst_adapter_prev_pts (rtph265pay->adapter, NULL);
+    if (buffer) {
+      if (!GST_CLOCK_TIME_IS_VALID (dts))
+        dts = GST_BUFFER_DTS (buffer);
+      if (!GST_CLOCK_TIME_IS_VALID (pts))
+        pts = GST_BUFFER_PTS (buffer);
+
+      gst_adapter_push (rtph265pay->adapter, buffer);
+    }
+    size = gst_adapter_available (rtph265pay->adapter);
+    /* Nothing to do here if the adapter is empty, e.g. on EOS */
+    if (size == 0)
+      return GST_FLOW_OK;
+    data = gst_adapter_map (rtph265pay->adapter, size);
+    GST_DEBUG_OBJECT (basepayload,
+        "got %" G_GSIZE_FORMAT " bytes (%" G_GSIZE_FORMAT ")", size,
+        buffer ? gst_buffer_get_size (buffer) : 0);
+  }
+
+  ret = GST_FLOW_OK;
+
+  /* now loop over all NAL units and put them in a packet
+   * FIXME, we should really try to pack multiple NAL units into one RTP packet
+   * if we can, especially for the config packets that wont't cause decoder
+   * latency. */
+  if (hevc) {
+    guint nal_length_size;
+    gsize offset = 0;
+    GPtrArray *paybufs;
+
+    paybufs = g_ptr_array_new ();
+    nal_length_size = rtph265pay->nal_length_size;
+
+    while (size > nal_length_size) {
+      gint i;
+
+      nal_len = 0;
+      for (i = 0; i < nal_length_size; i++) {
+        nal_len = ((nal_len << 8) + data[i]);
+      }
+
+      /* skip the length bytes, make sure we don't run past the buffer size */
+      data += nal_length_size;
+      offset += nal_length_size;
+      size -= nal_length_size;
+
+      if (size >= nal_len) {
+        GST_DEBUG_OBJECT (basepayload, "got NAL of size %u", nal_len);
+      } else {
+        nal_len = size;
+        GST_DEBUG_OBJECT (basepayload, "got incomplete NAL of size %u",
+            nal_len);
+      }
+
+      paybuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset,
+          nal_len);
+      g_ptr_array_add (paybufs, paybuf);
+
+      data += nal_len;
+      offset += nal_len;
+      size -= nal_len;
+    }
+    ret = gst_rtp_h265_pay_payload_nal (basepayload, paybufs, dts, pts);
+  } else {
+    guint next;
+    gboolean update = FALSE;
+    GPtrArray *paybufs;
+
+    /* get offset of first start code */
+    next = next_start_code (data, size);
+
+    /* skip to start code, if no start code is found, next will be size and we
+     * will not collect data. */
+    data += next;
+    size -= next;
+    nal_queue = rtph265pay->queue;
+    skip = next;
+
+    /* array must be empty when we get here */
+    g_assert (nal_queue->len == 0);
+
+    GST_DEBUG_OBJECT (basepayload,
+        "found first start at %u, bytes left %" G_GSIZE_FORMAT, next, size);
+
+    paybufs = g_ptr_array_new ();
+
+    /* first pass to locate NALs and parse VPS/SPS/PPS */
+    while (size > 4) {
+      /* skip start code */
+      data += 3;
+      size -= 3;
+
+      /* use next_start_code() to scan buffer.
+       * next_start_code() returns the offset in data,
+       * starting from zero to the first byte of 0.0.0.1
+       * If no start code is found, it returns the value of the
+       * 'size' parameter.
+       * data is unchanged by the call to next_start_code()
+       */
+      next = next_start_code (data, size);
+
+      if (next == size && buffer != NULL) {
+        /* Didn't find the start of next NAL and it's not EOS,
+         * handle it next time */
+        break;
+      }
+
+      /* nal length is distance to next start code */
+      nal_len = next;
+
+      GST_DEBUG_OBJECT (basepayload, "found next start at %u of size %u", next,
+          nal_len);
+
+      /* We know our stream is a valid H265 NAL packet,
+       * go parse it for VPS/SPS/PPS to enrich the caps */
+      /* order: make sure to check nal */
+      update = gst_rtp_h265_pay_decode_nal (rtph265pay, data, nal_len, dts, pts)
+          || update;
+
+      /* move to next NAL packet */
+      data += nal_len;
+      size -= nal_len;
+
+      g_array_append_val (nal_queue, nal_len);
+    }
+
+    /* if has new VPS, SPS & PPS, update the output caps */
+    if (G_UNLIKELY (update))
+      if (!gst_rtp_h265_pay_set_vps_sps_pps (basepayload))
+        goto caps_rejected;
+
+    /* second pass to payload and push */
+
+    if (nal_queue->len != 0)
+      gst_adapter_flush (rtph265pay->adapter, skip);
+
+    for (i = 0; i < nal_queue->len; i++) {
+      guint size;
+
+      nal_len = g_array_index (nal_queue, guint, i);
+      /* skip start code */
+      gst_adapter_flush (rtph265pay->adapter, 3);
+
+      /* Trim the end unless we're the last NAL in the stream.
+       * In case we're not at the end of the buffer we know the next block
+       * starts with 0x000001 so all the 0x00 bytes at the end of this one are
+       * trailing 0x0 that can be discarded */
+      size = nal_len;
+      data = gst_adapter_map (rtph265pay->adapter, size);
+      if (i + 1 != nal_queue->len || buffer != NULL)
+        for (; size > 1 && data[size - 1] == 0x0; size--)
+          /* skip */ ;
+
+      /* FIXME: We need to wait until the next packet or EOS to
+       * actually payload the NAL so we can know if the current NAL is
+       * the last one of an access unit or not if we are in bytestream mode
+       */
+
+      paybuf = gst_adapter_take_buffer (rtph265pay->adapter, size);
+      g_assert (paybuf);
+      g_ptr_array_add (paybufs, paybuf);
+
+      /* move to next NAL packet */
+      /* Skips the trailing zeros */
+      gst_adapter_flush (rtph265pay->adapter, nal_len - size);
+    }
+    /* put the data in one or more RTP packets */
+    ret = gst_rtp_h265_pay_payload_nal (basepayload, paybufs, dts, pts);
+    g_array_set_size (nal_queue, 0);
+  }
+
+done:
+  if (hevc) {
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+  } else {
+    gst_adapter_unmap (rtph265pay->adapter);
+  }
+
+  return ret;
+
+caps_rejected:
+  {
+    GST_WARNING_OBJECT (basepayload, "Could not set outcaps");
+    g_array_set_size (nal_queue, 0);
+    ret = GST_FLOW_NOT_NEGOTIATED;
+    goto done;
+  }
+}
+
+static gboolean
+gst_rtp_h265_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+  gboolean res;
+  const GstStructure *s;
+  GstRtpH265Pay *rtph265pay = GST_RTP_H265_PAY (payload);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      gst_adapter_clear (rtph265pay->adapter);
+      break;
+    case GST_EVENT_CUSTOM_DOWNSTREAM:
+      s = gst_event_get_structure (event);
+      if (gst_structure_has_name (s, "GstForceKeyUnit")) {
+        gboolean resend_codec_data;
+
+        if (gst_structure_get_boolean (s, "all-headers",
+                &resend_codec_data) && resend_codec_data)
+          rtph265pay->send_vps_sps_pps = TRUE;
+      }
+      break;
+    case GST_EVENT_EOS:
+    {
+      /* call handle_buffer with NULL to flush last NAL from adapter
+       * in byte-stream mode
+       */
+      gst_rtp_h265_pay_handle_buffer (payload, NULL);
+      break;
+    }
+    case GST_EVENT_STREAM_START:
+      GST_DEBUG_OBJECT (rtph265pay,
+          "New stream detected => Clear VPS, SPS and PPS");
+      gst_rtp_h265_pay_clear_vps_sps_pps (rtph265pay);
+      break;
+    default:
+      break;
+  }
+
+  res = GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+
+  return res;
+}
+
+static GstStateChangeReturn
+gst_rtp_h265_pay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstRtpH265Pay *rtph265pay = GST_RTP_H265_PAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      rtph265pay->send_vps_sps_pps = FALSE;
+      gst_adapter_clear (rtph265pay->adapter);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      rtph265pay->last_vps_sps_pps = -1;
+      gst_rtp_h265_pay_clear_vps_sps_pps (rtph265pay);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_rtp_h265_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpH265Pay *rtph265pay;
+
+  rtph265pay = GST_RTP_H265_PAY (object);
+
+  switch (prop_id) {
+    case PROP_CONFIG_INTERVAL:
+      rtph265pay->vps_sps_pps_interval = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_h265_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpH265Pay *rtph265pay;
+
+  rtph265pay = GST_RTP_H265_PAY (object);
+
+  switch (prop_id) {
+    case PROP_CONFIG_INTERVAL:
+      g_value_set_int (value, rtph265pay->vps_sps_pps_interval);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+gboolean
+gst_rtp_h265_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtph265pay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_H265_PAY);
+}
diff --git a/gst/rtp/gstrtph265pay.h b/gst/rtp/gstrtph265pay.h
new file mode 100644
index 0000000..cd42fba
--- /dev/null
+++ b/gst/rtp/gstrtph265pay.h
@@ -0,0 +1,78 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) <2014> Jurgen Slowack <jurgenslowack@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_H265_PAY_H__
+#define __GST_RTP_H265_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include "gstrtph265types.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_H265_PAY \
+  (gst_rtp_h265_pay_get_type())
+#define GST_RTP_H265_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H265_PAY,GstRtpH265Pay))
+#define GST_RTP_H265_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H265_PAY,GstRtpH265PayClass))
+#define GST_IS_RTP_H265_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H265_PAY))
+#define GST_IS_RTP_H265_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H265_PAY))
+typedef struct _GstRtpH265Pay GstRtpH265Pay;
+typedef struct _GstRtpH265PayClass GstRtpH265PayClass;
+
+typedef enum
+{
+  GST_H265_ALIGNMENT_UNKNOWN,
+  GST_H265_ALIGNMENT_NAL,
+  GST_H265_ALIGNMENT_AU
+} GstH265Alignment;
+
+struct _GstRtpH265Pay
+{
+  GstRTPBasePayload payload;
+
+  GPtrArray *sps, *pps, *vps;
+
+  GstH265StreamFormat stream_format;
+  GstH265Alignment alignment;
+  guint nal_length_size;
+  GArray *queue;
+
+  GstAdapter *adapter;
+
+  gint vps_sps_pps_interval;
+  gboolean send_vps_sps_pps;
+  GstClockTime last_vps_sps_pps;
+};
+
+struct _GstRtpH265PayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_h265_pay_get_type (void);
+
+gboolean gst_rtp_h265_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_H265_PAY_H__ */
diff --git a/gst/rtp/gstrtph265types.h b/gst/rtp/gstrtph265types.h
new file mode 100644
index 0000000..b2692e9
--- /dev/null
+++ b/gst/rtp/gstrtph265types.h
@@ -0,0 +1,76 @@
+/* GStreamer H.265 parser types
+ * Copyright (C) 2013 Intel Corporation
+ * Copyright (C) 2013 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  Contact: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_H265_TYPES_H__
+#define __GST_RTP_H265_TYPES_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+  GST_H265_NAL_SLICE_TRAIL_N    = 0,
+  GST_H265_NAL_SLICE_TRAIL_R    = 1,
+  GST_H265_NAL_SLICE_TSA_N      = 2,
+  GST_H265_NAL_SLICE_TSA_R      = 3,
+  GST_H265_NAL_SLICE_STSA_N     = 4,
+  GST_H265_NAL_SLICE_STSA_R     = 5,
+  GST_H265_NAL_SLICE_RADL_N     = 6,
+  GST_H265_NAL_SLICE_RADL_R     = 7,
+  GST_H265_NAL_SLICE_RASL_N     = 8,
+  GST_H265_NAL_SLICE_RASL_R     = 9,
+  GST_H265_NAL_SLICE_BLA_W_LP   = 16,
+  GST_H265_NAL_SLICE_BLA_W_RADL = 17,
+  GST_H265_NAL_SLICE_BLA_N_LP   = 18,
+  GST_H265_NAL_SLICE_IDR_W_RADL = 19,
+  GST_H265_NAL_SLICE_IDR_N_LP   = 20,
+  GST_H265_NAL_SLICE_CRA_NUT    = 21,
+  GST_H265_NAL_VPS              = 32,
+  GST_H265_NAL_SPS              = 33,
+  GST_H265_NAL_PPS              = 34,
+  GST_H265_NAL_AUD              = 35,
+  GST_H265_NAL_EOS              = 36,
+  GST_H265_NAL_EOB              = 37,
+  GST_H265_NAL_FD               = 38,
+  GST_H265_NAL_PREFIX_SEI       = 39,
+  GST_H265_NAL_SUFFIX_SEI       = 40
+} GstH265NalUnitType;
+
+#define RESERVED_NON_IRAP_SUBLAYER_NAL_TYPE_MIN 10
+#define RESERVED_NON_IRAP_SUBLAYER_NAL_TYPE_MAX 15
+
+#define RESERVED_IRAP_NAL_TYPE_MIN 22
+#define RESERVED_IRAP_NAL_TYPE_MAX 23
+
+#define RESERVED_NON_IRAP_NAL_TYPE_MIN 24
+#define RESERVED_NON_IRAP_NAL_TYPE_MAX 31
+
+#define RESERVED_NON_VCL_NAL_TYPE_MIN 41
+#define RESERVED_NON_VCL_NAL_TYPE_MAX 47
+
+#define UNSPECIFIED_NON_VCL_NAL_TYPE_MIN 48
+#define UNSPECIFIED_NON_VCL_NAL_TYPE_MAX 63
+
+G_END_DECLS
+
+#endif
diff --git a/gst/rtp/gstrtpilbcdepay.c b/gst/rtp/gstrtpilbcdepay.c
new file mode 100644
index 0000000..26de483
--- /dev/null
+++ b/gst/rtp/gstrtpilbcdepay.c
@@ -0,0 +1,237 @@
+/* GStreamer
+ * Copyright (C) <2006> Philippe Khalaf <burger@speedy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+#include "gstrtpilbcdepay.h"
+#include "gstrtputils.h"
+
+/* RtpiLBCDepay signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+#define DEFAULT_MODE GST_ILBC_MODE_30
+
+enum
+{
+  PROP_0,
+  PROP_MODE
+};
+
+/* FIXME, mode should be string because it is a parameter in SDP fmtp */
+static GstStaticPadTemplate gst_rtp_ilbc_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) 8000, " "encoding-name = (string) \"ILBC\"")
+    /* "mode = (string) { \"20\", \"30\" }" */
+    );
+
+static GstStaticPadTemplate gst_rtp_ilbc_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-iLBC, " "mode = (int) { 20, 30 }")
+    );
+
+static void gst_ilbc_depay_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_ilbc_depay_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+static GstBuffer *gst_rtp_ilbc_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+static gboolean gst_rtp_ilbc_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+
+#define gst_rtp_ilbc_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPiLBCDepay, gst_rtp_ilbc_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+#define GST_TYPE_ILBC_MODE (gst_ilbc_mode_get_type())
+static GType
+gst_ilbc_mode_get_type (void)
+{
+  static GType ilbc_mode_type = 0;
+  static const GEnumValue ilbc_modes[] = {
+    {GST_ILBC_MODE_20, "20ms frames", "20ms"},
+    {GST_ILBC_MODE_30, "30ms frames", "30ms"},
+    {0, NULL, NULL},
+  };
+
+  if (!ilbc_mode_type) {
+    ilbc_mode_type = g_enum_register_static ("iLBCMode", ilbc_modes);
+  }
+  return ilbc_mode_type;
+}
+
+static void
+gst_rtp_ilbc_depay_class_init (GstRTPiLBCDepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->set_property = gst_ilbc_depay_set_property;
+  gobject_class->get_property = gst_ilbc_depay_get_property;
+
+  /* FIXME, mode is in the caps */
+  g_object_class_install_property (gobject_class, PROP_MODE,
+      g_param_spec_enum ("mode", "Mode", "iLBC frame mode",
+          GST_TYPE_ILBC_MODE, DEFAULT_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_ilbc_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_ilbc_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP iLBC depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts iLBC audio from RTP packets (RFC 3952)",
+      "Philippe Kalaf <philippe.kalaf@collabora.co.uk>");
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_ilbc_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_ilbc_depay_setcaps;
+}
+
+static void
+gst_rtp_ilbc_depay_init (GstRTPiLBCDepay * rtpilbcdepay)
+{
+  /* Set default mode */
+  rtpilbcdepay->mode = DEFAULT_MODE;
+}
+
+static gboolean
+gst_rtp_ilbc_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstRTPiLBCDepay *rtpilbcdepay = GST_RTP_ILBC_DEPAY (depayload);
+  GstCaps *srccaps;
+  GstStructure *structure;
+  const gchar *mode_str = NULL;
+  gint mode, clock_rate;
+  gboolean ret;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  mode = rtpilbcdepay->mode;
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 8000;
+  depayload->clock_rate = clock_rate;
+
+  /* parse mode, if we can */
+  mode_str = gst_structure_get_string (structure, "mode");
+  if (mode_str) {
+    mode = strtol (mode_str, NULL, 10);
+    if (mode != 20 && mode != 30)
+      mode = rtpilbcdepay->mode;
+  }
+
+  rtpilbcdepay->mode = mode;
+
+  srccaps = gst_caps_new_simple ("audio/x-iLBC",
+      "mode", G_TYPE_INT, rtpilbcdepay->mode, NULL);
+  ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+
+  GST_DEBUG ("set caps on source: %" GST_PTR_FORMAT " (ret=%d)", srccaps, ret);
+  gst_caps_unref (srccaps);
+
+  return ret;
+}
+
+static GstBuffer *
+gst_rtp_ilbc_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstBuffer *outbuf;
+  gboolean marker;
+
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+      gst_buffer_get_size (rtp->buffer), marker,
+      gst_rtp_buffer_get_timestamp (rtp), gst_rtp_buffer_get_seq (rtp));
+
+  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);
+
+  if (marker && outbuf) {
+    /* mark start of talkspurt with RESYNC */
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+  }
+
+  if (outbuf) {
+    gst_rtp_drop_non_audio_meta (depayload, outbuf);
+  }
+
+  return outbuf;
+}
+
+static void
+gst_ilbc_depay_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstRTPiLBCDepay *rtpilbcdepay = GST_RTP_ILBC_DEPAY (object);
+
+  switch (prop_id) {
+    case PROP_MODE:
+      rtpilbcdepay->mode = g_value_get_enum (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_ilbc_depay_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstRTPiLBCDepay *rtpilbcdepay = GST_RTP_ILBC_DEPAY (object);
+
+  switch (prop_id) {
+    case PROP_MODE:
+      g_value_set_enum (value, rtpilbcdepay->mode);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+gboolean
+gst_rtp_ilbc_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpilbcdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_ILBC_DEPAY);
+}
diff --git a/gst/rtp/gstrtpilbcdepay.h b/gst/rtp/gstrtpilbcdepay.h
new file mode 100644
index 0000000..01fd225
--- /dev/null
+++ b/gst/rtp/gstrtpilbcdepay.h
@@ -0,0 +1,65 @@
+/* GStreamer
+ * Copyright (C) <2006> Philippe Khalaf <burger@speedy.org> 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_ILBC_DEPAY_H__
+#define __GST_RTP_ILBC_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTPiLBCDepay GstRTPiLBCDepay;
+typedef struct _GstRTPiLBCDepayClass GstRTPiLBCDepayClass;
+
+#define GST_TYPE_RTP_ILBC_DEPAY \
+  (gst_rtp_ilbc_depay_get_type())
+#define GST_RTP_ILBC_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_ILBC_DEPAY,GstRTPiLBCDepay))
+#define GST_RTP_ILBC_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_ILBC_DEPAY,GstRTPiLBCDepayClass))
+#define GST_IS_RTP_ILBC_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_ILBC_DEPAY))
+#define GST_IS_RTP_ILBC_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_ILBC_DEPAY))
+  
+typedef enum {
+  GST_ILBC_MODE_20 = 20,
+  GST_ILBC_MODE_30 = 30
+} GstiLBCMode; 
+
+struct _GstRTPiLBCDepay
+{
+  GstRTPBaseDepayload depayload;
+
+  GstiLBCMode mode;
+};
+
+struct _GstRTPiLBCDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_ilbc_depay_get_type (void);
+
+gboolean gst_rtp_ilbc_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_ILBC_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpilbcpay.c b/gst/rtp/gstrtpilbcpay.c
new file mode 100644
index 0000000..cbc7d93
--- /dev/null
+++ b/gst/rtp/gstrtpilbcpay.c
@@ -0,0 +1,228 @@
+/* GStreamer
+ * Copyright (C) <2006> Philippe Khalaf <burger@speedy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtpilbcpay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpilbcpay_debug);
+#define GST_CAT_DEFAULT (rtpilbcpay_debug)
+
+static GstStaticPadTemplate gst_rtp_ilbc_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-iLBC, " "mode = (int) {20, 30}")
+    );
+
+static GstStaticPadTemplate gst_rtp_ilbc_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 8000, "
+        "encoding-name = (string) \"ILBC\", "
+        "mode = (string) { \"20\", \"30\" }")
+    );
+
+
+static GstCaps *gst_rtp_ilbc_pay_sink_getcaps (GstRTPBasePayload * payload,
+    GstPad * pad, GstCaps * filter);
+static gboolean gst_rtp_ilbc_pay_sink_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+
+#define gst_rtp_ilbc_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPILBCPay, gst_rtp_ilbc_pay,
+    GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_ilbc_pay_class_init (GstRTPILBCPayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpilbcpay_debug, "rtpilbcpay", 0,
+      "iLBC audio RTP payloader");
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_ilbc_pay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_ilbc_pay_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP iLBC Payloader",
+      "Codec/Payloader/Network/RTP",
+      "Packetize iLBC audio streams into RTP packets",
+      "Philippe Kalaf <philippe.kalaf@collabora.co.uk>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_ilbc_pay_sink_setcaps;
+  gstrtpbasepayload_class->get_caps = gst_rtp_ilbc_pay_sink_getcaps;
+}
+
+static void
+gst_rtp_ilbc_pay_init (GstRTPILBCPay * rtpilbcpay)
+{
+  GstRTPBasePayload *rtpbasepayload;
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+  rtpbasepayload = GST_RTP_BASE_PAYLOAD (rtpilbcpay);
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpilbcpay);
+
+  /* we don't set the payload type, it should be set by the application using
+   * the pt property or the default 96 will be used */
+  rtpbasepayload->clock_rate = 8000;
+
+  rtpilbcpay->mode = -1;
+
+  /* tell rtpbaseaudiopayload that this is a frame based codec */
+  gst_rtp_base_audio_payload_set_frame_based (rtpbaseaudiopayload);
+}
+
+static gboolean
+gst_rtp_ilbc_pay_sink_setcaps (GstRTPBasePayload * rtpbasepayload,
+    GstCaps * caps)
+{
+  GstRTPILBCPay *rtpilbcpay;
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+  gboolean ret;
+  gint mode;
+  gchar *mode_str;
+  GstStructure *structure;
+  const char *payload_name;
+
+  rtpilbcpay = GST_RTP_ILBC_PAY (rtpbasepayload);
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpbasepayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  payload_name = gst_structure_get_name (structure);
+  if (g_ascii_strcasecmp ("audio/x-iLBC", payload_name))
+    goto wrong_caps;
+
+  if (!gst_structure_get_int (structure, "mode", &mode))
+    goto no_mode;
+
+  if (mode != 20 && mode != 30)
+    goto wrong_mode;
+
+  gst_rtp_base_payload_set_options (rtpbasepayload, "audio", TRUE, "ILBC",
+      8000);
+  /* set options for this frame based audio codec */
+  gst_rtp_base_audio_payload_set_frame_options (rtpbaseaudiopayload,
+      mode, mode == 30 ? 50 : 38);
+
+  mode_str = g_strdup_printf ("%d", mode);
+  ret =
+      gst_rtp_base_payload_set_outcaps (rtpbasepayload, "mode", G_TYPE_STRING,
+      mode_str, NULL);
+  g_free (mode_str);
+
+  if (mode != rtpilbcpay->mode && rtpilbcpay->mode != -1)
+    goto mode_changed;
+
+  rtpilbcpay->mode = mode;
+
+  return ret;
+
+  /* ERRORS */
+wrong_caps:
+  {
+    GST_ERROR_OBJECT (rtpilbcpay, "expected audio/x-iLBC, received %s",
+        payload_name);
+    return FALSE;
+  }
+no_mode:
+  {
+    GST_ERROR_OBJECT (rtpilbcpay, "did not receive a mode");
+    return FALSE;
+  }
+wrong_mode:
+  {
+    GST_ERROR_OBJECT (rtpilbcpay, "mode must be 20 or 30, received %d", mode);
+    return FALSE;
+  }
+mode_changed:
+  {
+    GST_ERROR_OBJECT (rtpilbcpay, "Mode has changed from %d to %d! "
+        "Mode cannot change while streaming", rtpilbcpay->mode, mode);
+    return FALSE;
+  }
+}
+
+/* we return the padtemplate caps with the mode field fixated to a value if we
+ * can */
+static GstCaps *
+gst_rtp_ilbc_pay_sink_getcaps (GstRTPBasePayload * rtppayload, GstPad * pad,
+    GstCaps * filter)
+{
+  GstCaps *otherpadcaps;
+  GstCaps *caps;
+
+  otherpadcaps = gst_pad_get_allowed_caps (rtppayload->srcpad);
+  caps = gst_pad_get_pad_template_caps (pad);
+
+  if (otherpadcaps) {
+    if (!gst_caps_is_empty (otherpadcaps)) {
+      GstStructure *structure;
+      const gchar *mode_str;
+      gint mode;
+
+      structure = gst_caps_get_structure (otherpadcaps, 0);
+
+      /* parse mode, if we can */
+      mode_str = gst_structure_get_string (structure, "mode");
+      if (mode_str) {
+        mode = strtol (mode_str, NULL, 10);
+        if (mode == 20 || mode == 30) {
+          caps = gst_caps_make_writable (caps);
+          structure = gst_caps_get_structure (caps, 0);
+          gst_structure_set (structure, "mode", G_TYPE_INT, mode, NULL);
+        }
+      }
+    }
+    gst_caps_unref (otherpadcaps);
+  }
+
+  if (filter) {
+    GstCaps *tmp;
+
+    GST_DEBUG_OBJECT (rtppayload, "Intersect %" GST_PTR_FORMAT " and filter %"
+        GST_PTR_FORMAT, caps, filter);
+    tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    caps = tmp;
+  }
+
+  return caps;
+}
+
+gboolean
+gst_rtp_ilbc_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpilbcpay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_ILBC_PAY);
+}
diff --git a/gst/rtp/gstrtpilbcpay.h b/gst/rtp/gstrtpilbcpay.h
new file mode 100644
index 0000000..14363c0
--- /dev/null
+++ b/gst/rtp/gstrtpilbcpay.h
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) <2006> Philippe Khalaf <burger@speedy.org> 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_ILBC_PAY_H__
+#define __GST_RTP_ILBC_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_ILBC_PAY \
+  (gst_rtp_ilbc_pay_get_type())
+#define GST_RTP_ILBC_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_ILBC_PAY,GstRTPILBCPay))
+#define GST_RTP_ILBC_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_ILBC_PAY,GstRTPILBCPayClass))
+#define GST_IS_RTP_ILBC_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_ILBC_PAY))
+#define GST_IS_RTP_ILBC_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_ILBC_PAY))
+
+typedef struct _GstRTPILBCPay GstRTPILBCPay;
+typedef struct _GstRTPILBCPayClass GstRTPILBCPayClass;
+
+struct _GstRTPILBCPay
+{
+  GstRTPBaseAudioPayload audiopayload;
+
+  gint mode;
+};
+
+struct _GstRTPILBCPayClass
+{
+  GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_ilbc_pay_get_type (void);
+
+gboolean gst_rtp_ilbc_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_ILBC_PAY_H__ */
diff --git a/gst/rtp/gstrtpj2kcommon.h b/gst/rtp/gstrtpj2kcommon.h
new file mode 100644
index 0000000..09f1bbb
--- /dev/null
+++ b/gst/rtp/gstrtpj2kcommon.h
@@ -0,0 +1,102 @@
+/* GStreamer
+* Copyright (C) 2009 Wim Taymans <wim.taymans@gmail.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Library General Public License for more details.
+*
+* You should have received a copy of the GNU Library General Public
+* License along with this library; if not, write to the
+* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+* Boston, MA 02110-1301, USA.
+*/
+
+
+#ifndef __GST_RTP_J2K_COMMON_H__
+#define __GST_RTP_J2K_COMMON_H__
+
+
+
+/* Sampling values from RFC 5371 for JPEG 2000 over RTP : https://datatracker.ietf.org/doc/rfc5371/C
+
+RGB:  standard Red, Green, Blue color space.
+
+BGR:  standard Blue, Green, Red color space.
+
+RGBA:  standard Red, Green, Blue, Alpha color space.
+
+BGRA:  standard Blue, Green, Red, Alpha color space.
+
+YCbCr-4:4:4:  standard YCbCr color space; no subsampling.
+
+YCbCr-4:2:2:  standard YCbCr color space; Cb and Cr are subsampled horizontally by 1/2.
+
+YCbCr-4:2:0:  standard YCbCr color space; Cb and Cr are subsampled horizontally and vertically by 1/2.
+
+YCbCr-4:1:1:  standard YCbCr color space; Cb and Cr are subsampled vertically by 1/4.
+
+GRAYSCALE:  basically, a single component image of just multilevels of grey.
+*/
+
+
+#define GST_RTP_J2K_RGB       "RGB"
+#define GST_RTP_J2K_BGR       "BGR"
+#define GST_RTP_J2K_RGBA      "RGBA"
+#define GST_RTP_J2K_BGRA      "BGRA"
+#define GST_RTP_J2K_YBRA   	  "YCbCrA"
+#define GST_RTP_J2K_YBR444    "YCbCr-4:4:4"
+#define GST_RTP_J2K_YBR422    "YCbCr-4:2:2"
+#define GST_RTP_J2K_YBR420    "YCbCr-4:2:0"
+#define GST_RTP_J2K_YBR410    "YCbCr-4:1:0"
+#define GST_RTP_J2K_GRAYSCALE "GRAYSCALE"
+
+#define GST_RTP_J2K_SAMPLING_LIST "sampling = (string) {\"RGB\", \"BGR\", \"RGBA\", \"BGRA\", \"YCbCrA\", \"YCbCr-4:4:4\", \"YCbCr-4:2:2\", \"YCbCr-4:2:0\", \"YCbCr-4:1:1\", \"GRAYSCALE\"}"
+
+typedef enum
+{
+
+  GST_RTP_SAMPLING_NONE,
+  GST_RTP_SAMPLING_RGB,
+  GST_RTP_SAMPLING_BGR,
+  GST_RTP_SAMPLING_RGBA,
+  GST_RTP_SAMPLING_BGRA,
+  GST_RTP_SAMPLING_YBRA,
+  GST_RTP_SAMPLING_YBR444,
+  GST_RTP_SAMPLING_YBR422,
+  GST_RTP_SAMPLING_YBR420,
+  GST_RTP_SAMPLING_YBR410,
+  GST_RTP_SAMPLING_GRAYSCALE
+} GstRtpSampling;
+
+
+/*
+* GstRtpJ2KMarker:
+* @GST_J2K_MARKER: Prefix for JPEG 2000 marker
+* @GST_J2K_MARKER_SOC: Start of Codestream
+* @GST_J2K_MARKER_SOT: Start of tile
+* @GST_J2K_MARKER_EOC: End of Codestream
+*
+* Identifiers for markers in JPEG 2000 code streams
+*/
+typedef enum
+{
+  GST_J2K_MARKER = 0xFF,
+  GST_J2K_MARKER_SOC = 0x4F,
+  GST_J2K_MARKER_SOT = 0x90,
+  GST_J2K_MARKER_SOP = 0x91,
+  GST_J2K_MARKER_EPH = 0x92,
+  GST_J2K_MARKER_SOD = 0x93,
+  GST_J2K_MARKER_EOC = 0xD9
+} GstRtpJ2KMarker;
+
+
+#define GST_RTP_J2K_HEADER_SIZE 8
+
+
+#endif /* __GST_RTP_J2K_COMMON_H__ */
diff --git a/gst/rtp/gstrtpj2kdepay.c b/gst/rtp/gstrtpj2kdepay.c
new file mode 100644
index 0000000..c30dd34
--- /dev/null
+++ b/gst/rtp/gstrtpj2kdepay.c
@@ -0,0 +1,667 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+ /**
+ * SECTION:element-rtpj2kdepay
+ *
+ * Depayload an RTP-payloaded JPEG 2000 image into RTP packets according to RFC 5371
+ * and RFC 5372.
+ * For detailed information see: https://datatracker.ietf.org/doc/rfc5371/
+ * and https://datatracker.ietf.org/doc/rfc5372/
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+
+#include <string.h>
+#include "gstrtpj2kcommon.h"
+#include "gstrtpj2kdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpj2kdepay_debug);
+#define GST_CAT_DEFAULT (rtpj2kdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_j2k_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("image/x-jpc, "
+        "colorspace = (string) { sRGB, sYUV, GRAY }")
+    );
+
+static GstStaticPadTemplate gst_rtp_j2k_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", " "clock-rate = (int) 90000, "
+        GST_RTP_J2K_SAMPLING_LIST ","
+        "encoding-name = (string) \"JPEG2000\";"
+        "application/x-rtp, "
+        "media = (string) \"video\", " "clock-rate = (int) 90000, "
+        "colorspace = (string) { sRGB, sYUV, GRAY }, "
+        "encoding-name = (string) \"JPEG2000\";")
+    );
+
+enum
+{
+  PROP_0,
+  PROP_LAST
+};
+
+#define gst_rtp_j2k_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpJ2KDepay, gst_rtp_j2k_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_j2k_depay_finalize (GObject * object);
+
+static void gst_rtp_j2k_depay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_j2k_depay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn
+gst_rtp_j2k_depay_change_state (GstElement * element,
+    GstStateChange transition);
+
+static gboolean gst_rtp_j2k_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_j2k_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+static void
+gst_rtp_j2k_depay_class_init (GstRtpJ2KDepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_j2k_depay_finalize;
+
+  gobject_class->set_property = gst_rtp_j2k_depay_set_property;
+  gobject_class->get_property = gst_rtp_j2k_depay_get_property;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_j2k_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_j2k_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP JPEG 2000 depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts JPEG 2000 video from RTP packets (RFC 5371)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstelement_class->change_state = gst_rtp_j2k_depay_change_state;
+
+  gstrtpbasedepayload_class->set_caps = gst_rtp_j2k_depay_setcaps;
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_j2k_depay_process;
+
+  GST_DEBUG_CATEGORY_INIT (rtpj2kdepay_debug, "rtpj2kdepay", 0,
+      "J2K Video RTP Depayloader");
+}
+
+static void
+gst_rtp_j2k_depay_init (GstRtpJ2KDepay * rtpj2kdepay)
+{
+  rtpj2kdepay->pu_adapter = gst_adapter_new ();
+  rtpj2kdepay->t_adapter = gst_adapter_new ();
+  rtpj2kdepay->f_adapter = gst_adapter_new ();
+}
+
+static void
+store_mheader (GstRtpJ2KDepay * rtpj2kdepay, guint idx, GstBuffer * buf)
+{
+  GstBuffer *old;
+
+  GST_DEBUG_OBJECT (rtpj2kdepay, "storing main header %p at index %u", buf,
+      idx);
+  if ((old = rtpj2kdepay->MH[idx]))
+    gst_buffer_unref (old);
+  rtpj2kdepay->MH[idx] = buf;
+}
+
+static void
+clear_mheaders (GstRtpJ2KDepay * rtpj2kdepay)
+{
+  guint i;
+
+  for (i = 0; i < 8; i++)
+    store_mheader (rtpj2kdepay, i, NULL);
+}
+
+static void
+gst_rtp_j2k_depay_reset (GstRtpJ2KDepay * rtpj2kdepay)
+{
+  clear_mheaders (rtpj2kdepay);
+  gst_adapter_clear (rtpj2kdepay->pu_adapter);
+  gst_adapter_clear (rtpj2kdepay->t_adapter);
+  gst_adapter_clear (rtpj2kdepay->f_adapter);
+  rtpj2kdepay->next_frag = 0;
+}
+
+static void
+gst_rtp_j2k_depay_finalize (GObject * object)
+{
+  GstRtpJ2KDepay *rtpj2kdepay;
+
+  rtpj2kdepay = GST_RTP_J2K_DEPAY (object);
+
+  clear_mheaders (rtpj2kdepay);
+
+  g_object_unref (rtpj2kdepay->pu_adapter);
+  g_object_unref (rtpj2kdepay->t_adapter);
+  g_object_unref (rtpj2kdepay->f_adapter);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_j2k_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure = NULL;
+  gint clock_rate;
+  GstCaps *outcaps = NULL;
+  gboolean res = FALSE;
+  const gchar *colorspace = NULL;
+  const gchar *sampling = NULL;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;
+  depayload->clock_rate = clock_rate;
+
+  sampling = gst_structure_get_string (structure, "sampling");
+  if (sampling) {
+    if (!strcmp (sampling, GST_RTP_J2K_RGB) ||
+        !strcmp (sampling, GST_RTP_J2K_RGBA) ||
+        !strcmp (sampling, GST_RTP_J2K_BGR) ||
+        !strcmp (sampling, GST_RTP_J2K_BGRA))
+      colorspace = "sRGB";
+    else if (!strcmp (sampling, GST_RTP_J2K_GRAYSCALE))
+      colorspace = "GRAY";
+    else
+      colorspace = "sYUV";
+  } else {
+    GST_ELEMENT_WARNING (depayload, STREAM, DEMUX, NULL,
+        ("Non-compliant stream: sampling field missing. Frames my appear incorrect"));
+    colorspace = gst_structure_get_string (structure, "colorspace");
+    if (!strcmp (colorspace, "GRAY")) {
+      sampling = GST_RTP_J2K_GRAYSCALE;
+    }
+  }
+
+  outcaps = gst_caps_new_simple ("image/x-jpc",
+      "framerate", GST_TYPE_FRACTION, 0, 1,
+      "fields", G_TYPE_INT, 1, "colorspace", G_TYPE_STRING, colorspace, NULL);
+
+  if (sampling)
+    gst_caps_set_simple (outcaps, "sampling", G_TYPE_STRING, sampling, NULL);
+
+  res = gst_pad_set_caps (depayload->srcpad, outcaps);
+
+  gst_caps_unref (outcaps);
+
+  return res;
+}
+
+static void
+gst_rtp_j2k_depay_clear_pu (GstRtpJ2KDepay * rtpj2kdepay)
+{
+  gst_adapter_clear (rtpj2kdepay->pu_adapter);
+  rtpj2kdepay->have_sync = FALSE;
+}
+
+static GstFlowReturn
+gst_rtp_j2k_depay_flush_pu (GstRTPBaseDepayload * depayload)
+{
+  GstRtpJ2KDepay *rtpj2kdepay;
+  GstBuffer *mheader;
+  guint avail, MHF, mh_id;
+
+  rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
+
+  /* take all available buffers */
+  avail = gst_adapter_available (rtpj2kdepay->pu_adapter);
+  if (avail == 0)
+    goto done;
+
+  MHF = rtpj2kdepay->pu_MHF;
+  mh_id = rtpj2kdepay->last_mh_id;
+
+  GST_DEBUG_OBJECT (rtpj2kdepay, "flushing PU of size %u", avail);
+
+  if (MHF == 0) {
+    GList *packets, *walk;
+
+    packets = gst_adapter_take_list (rtpj2kdepay->pu_adapter, avail);
+    /* append packets */
+    for (walk = packets; walk; walk = g_list_next (walk)) {
+      GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+      GST_DEBUG_OBJECT (rtpj2kdepay,
+          "append pu packet of size %" G_GSIZE_FORMAT,
+          gst_buffer_get_size (buf));
+      gst_adapter_push (rtpj2kdepay->t_adapter, buf);
+    }
+    g_list_free (packets);
+  } else {
+    /* we have a header */
+    GST_DEBUG_OBJECT (rtpj2kdepay, "keeping header %u", mh_id);
+    /* we managed to see the start and end of the header, take all from
+     * adapter and keep in header  */
+    mheader = gst_adapter_take_buffer (rtpj2kdepay->pu_adapter, avail);
+
+    store_mheader (rtpj2kdepay, mh_id, mheader);
+  }
+
+done:
+  rtpj2kdepay->have_sync = FALSE;
+
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_rtp_j2k_depay_flush_tile (GstRTPBaseDepayload * depayload)
+{
+  GstRtpJ2KDepay *rtpj2kdepay;
+  guint avail, mh_id;
+  GList *packets, *walk;
+  guint8 end[2];
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstMapInfo map;
+  GstBuffer *buf;
+
+  rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
+
+  /* flush pending PU */
+  gst_rtp_j2k_depay_flush_pu (depayload);
+
+  /* take all available buffers */
+  avail = gst_adapter_available (rtpj2kdepay->t_adapter);
+  if (avail == 0)
+    goto done;
+
+  mh_id = rtpj2kdepay->last_mh_id;
+
+  GST_DEBUG_OBJECT (rtpj2kdepay, "flushing tile of size %u", avail);
+
+  if (gst_adapter_available (rtpj2kdepay->f_adapter) == 0) {
+    GstBuffer *mheader;
+
+    /* we need a header now */
+    if ((mheader = rtpj2kdepay->MH[mh_id]) == NULL)
+      goto waiting_header;
+
+    /* push header in the adapter */
+    GST_DEBUG_OBJECT (rtpj2kdepay, "pushing header %u", mh_id);
+    gst_adapter_push (rtpj2kdepay->f_adapter, gst_buffer_ref (mheader));
+  }
+
+  /* check for last bytes */
+  gst_adapter_copy (rtpj2kdepay->t_adapter, end, avail - 2, 2);
+
+  /* now append the tile packets to the frame */
+  packets = gst_adapter_take_list (rtpj2kdepay->t_adapter, avail);
+  for (walk = packets; walk; walk = g_list_next (walk)) {
+    buf = GST_BUFFER_CAST (walk->data);
+
+    if (walk == packets) {
+      /* first buffer should contain the SOT */
+      gst_buffer_map (buf, &map, GST_MAP_READ);
+
+      if (map.size < 12)
+        goto invalid_tile;
+
+      if (map.data[0] == GST_J2K_MARKER && map.data[1] == GST_J2K_MARKER_SOT) {
+        guint Psot, nPsot;
+
+        if (end[0] == GST_J2K_MARKER && end[1] == GST_J2K_MARKER_EOC)
+          nPsot = avail - 2;
+        else
+          nPsot = avail;
+
+        Psot = GST_READ_UINT32_BE (&map.data[6]);
+        if (Psot != nPsot && Psot != 0) {
+          /* Psot must match the size of the tile */
+          GST_DEBUG_OBJECT (rtpj2kdepay, "set Psot from %u to %u", Psot, nPsot);
+          gst_buffer_unmap (buf, &map);
+
+          buf = gst_buffer_make_writable (buf);
+
+          gst_buffer_map (buf, &map, GST_MAP_WRITE);
+          GST_WRITE_UINT32_BE (&map.data[6], nPsot);
+        }
+      }
+      gst_buffer_unmap (buf, &map);
+    }
+
+    GST_DEBUG_OBJECT (rtpj2kdepay, "append pu packet of size %" G_GSIZE_FORMAT,
+        gst_buffer_get_size (buf));
+    gst_adapter_push (rtpj2kdepay->f_adapter, buf);
+  }
+  g_list_free (packets);
+
+done:
+  rtpj2kdepay->last_tile = -1;
+
+  return ret;
+
+  /* errors */
+waiting_header:
+  {
+    GST_DEBUG_OBJECT (rtpj2kdepay, "waiting for header %u", mh_id);
+    gst_adapter_clear (rtpj2kdepay->t_adapter);
+    rtpj2kdepay->last_tile = -1;
+    return ret;
+  }
+invalid_tile:
+  {
+    GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE, ("Invalid tile"), (NULL));
+    gst_buffer_unmap (buf, &map);
+    gst_adapter_clear (rtpj2kdepay->t_adapter);
+    rtpj2kdepay->last_tile = -1;
+    return ret;
+  }
+}
+
+static GstFlowReturn
+gst_rtp_j2k_depay_flush_frame (GstRTPBaseDepayload * depayload)
+{
+  GstRtpJ2KDepay *rtpj2kdepay;
+  guint8 end[2];
+  guint avail;
+
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
+
+  /* flush pending tile */
+  gst_rtp_j2k_depay_flush_tile (depayload);
+
+  /* last buffer take all data out of the adapter */
+  avail = gst_adapter_available (rtpj2kdepay->f_adapter);
+  if (avail == 0)
+    goto done;
+
+  if (avail > 2) {
+    GstBuffer *outbuf;
+
+    /* take the last bytes of the JPEG 2000 data to see if there is an EOC
+     * marker */
+    gst_adapter_copy (rtpj2kdepay->f_adapter, end, avail - 2, 2);
+
+    if (end[0] != GST_J2K_MARKER && end[1] != GST_J2K_MARKER_EOC) {
+      end[0] = GST_J2K_MARKER;
+      end[1] = GST_J2K_MARKER_EOC;
+
+      GST_DEBUG_OBJECT (rtpj2kdepay, "no EOC marker, adding one");
+
+      /* no EOI marker, add one */
+      outbuf = gst_buffer_new_and_alloc (2);
+      gst_buffer_fill (outbuf, 0, end, 2);
+
+      gst_adapter_push (rtpj2kdepay->f_adapter, outbuf);
+      avail += 2;
+    }
+
+    GST_DEBUG_OBJECT (rtpj2kdepay, "pushing buffer of %u bytes", avail);
+    outbuf = gst_adapter_take_buffer (rtpj2kdepay->f_adapter, avail);
+    gst_rtp_drop_non_video_meta (depayload, outbuf);
+    ret = gst_rtp_base_depayload_push (depayload, outbuf);
+  } else {
+    GST_WARNING_OBJECT (rtpj2kdepay, "empty packet");
+    gst_adapter_clear (rtpj2kdepay->f_adapter);
+  }
+
+  /* we accept any mh_id now */
+  rtpj2kdepay->last_mh_id = -1;
+
+  /* reset state */
+  rtpj2kdepay->next_frag = 0;
+  rtpj2kdepay->have_sync = FALSE;
+
+done:
+  /* we can't keep headers with mh_id of 0 */
+  store_mheader (rtpj2kdepay, 0, NULL);
+
+  return ret;
+}
+
+static GstBuffer *
+gst_rtp_j2k_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpJ2KDepay *rtpj2kdepay;
+  guint8 *payload;
+  guint MHF, mh_id, frag_offset, tile, payload_len, j2klen;
+  gint gap;
+  guint32 rtptime;
+
+  rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
+
+  payload = gst_rtp_buffer_get_payload (rtp);
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  /* we need at least a header */
+  if (payload_len < GST_RTP_J2K_HEADER_SIZE)
+    goto empty_packet;
+
+  rtptime = gst_rtp_buffer_get_timestamp (rtp);
+
+  /* new timestamp marks new frame */
+  if (rtpj2kdepay->last_rtptime != rtptime) {
+    rtpj2kdepay->last_rtptime = rtptime;
+    /* flush pending frame */
+    gst_rtp_j2k_depay_flush_frame (depayload);
+  }
+
+  /*
+   *  0                   1                   2                   3
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |tp |MHF|mh_id|T|     priority  |           tile number         |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |reserved       |             fragment offset                   |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   */
+  MHF = (payload[0] & 0x30) >> 4;
+  mh_id = (payload[0] & 0xe) >> 1;
+
+  if (rtpj2kdepay->last_mh_id == -1)
+    rtpj2kdepay->last_mh_id = mh_id;
+  else if (rtpj2kdepay->last_mh_id != mh_id)
+    goto wrong_mh_id;
+
+  tile = (payload[2] << 8) | payload[3];
+  frag_offset = (payload[5] << 16) | (payload[6] << 8) | payload[7];
+  j2klen = payload_len - GST_RTP_J2K_HEADER_SIZE;
+
+  GST_DEBUG_OBJECT (rtpj2kdepay, "MHF %u, tile %u, frag %u, expected %u", MHF,
+      tile, frag_offset, rtpj2kdepay->next_frag);
+
+  /* calculate the gap between expected frag */
+  gap = frag_offset - rtpj2kdepay->next_frag;
+  /* calculate next frag */
+  rtpj2kdepay->next_frag = frag_offset + j2klen;
+
+  if (gap != 0) {
+    GST_DEBUG_OBJECT (rtpj2kdepay, "discont of %d, clear PU", gap);
+    /* discont, clear pu adapter and resync */
+    gst_rtp_j2k_depay_clear_pu (rtpj2kdepay);
+  }
+
+  /* check for sync code */
+  if (j2klen > 2 && payload[GST_RTP_J2K_HEADER_SIZE] == GST_J2K_MARKER) {
+    guint marker = payload[GST_RTP_J2K_HEADER_SIZE + 1];
+
+    /* packets must start with SOC, SOT or SOP */
+    switch (marker) {
+      case GST_J2K_MARKER_SOC:
+        GST_DEBUG_OBJECT (rtpj2kdepay, "found SOC packet");
+        /* flush the previous frame, should have happened when the timestamp
+         * changed above. */
+        gst_rtp_j2k_depay_flush_frame (depayload);
+        rtpj2kdepay->have_sync = TRUE;
+        break;
+      case GST_J2K_MARKER_SOT:
+        /* flush the previous tile */
+        gst_rtp_j2k_depay_flush_tile (depayload);
+        GST_DEBUG_OBJECT (rtpj2kdepay, "found SOT packet");
+        rtpj2kdepay->have_sync = TRUE;
+        /* we sync on the tile now */
+        rtpj2kdepay->last_tile = tile;
+        break;
+      case GST_J2K_MARKER_SOP:
+        GST_DEBUG_OBJECT (rtpj2kdepay, "found SOP packet");
+        /* flush the previous PU */
+        gst_rtp_j2k_depay_flush_pu (depayload);
+        if (rtpj2kdepay->last_tile != tile) {
+          /* wrong tile, we lose sync and we need a new SOT or SOC to regain
+           * sync. First flush out the previous tile if we have one. */
+          if (rtpj2kdepay->last_tile != -1)
+            gst_rtp_j2k_depay_flush_tile (depayload);
+          /* now we have no more valid tile and no sync */
+          rtpj2kdepay->last_tile = -1;
+          rtpj2kdepay->have_sync = FALSE;
+        } else {
+          rtpj2kdepay->have_sync = TRUE;
+        }
+        break;
+      default:
+        GST_DEBUG_OBJECT (rtpj2kdepay, "no sync packet 0x%02d", marker);
+        break;
+    }
+  }
+
+  if (rtpj2kdepay->have_sync) {
+    GstBuffer *pu_frag;
+
+    if (gst_adapter_available (rtpj2kdepay->pu_adapter) == 0) {
+      /* first part of pu, record state */
+      GST_DEBUG_OBJECT (rtpj2kdepay, "first PU");
+      rtpj2kdepay->pu_MHF = MHF;
+    }
+    /* and push in pu adapter */
+    GST_DEBUG_OBJECT (rtpj2kdepay, "push pu of size %u in adapter", j2klen);
+    pu_frag = gst_rtp_buffer_get_payload_subbuffer (rtp, 8, -1);
+    gst_adapter_push (rtpj2kdepay->pu_adapter, pu_frag);
+
+    if (MHF & 2) {
+      /* last part of main header received, we can flush it */
+      GST_DEBUG_OBJECT (rtpj2kdepay, "header end, flush pu");
+      gst_rtp_j2k_depay_flush_pu (depayload);
+    }
+  } else {
+    GST_DEBUG_OBJECT (rtpj2kdepay, "discard packet, no sync");
+  }
+
+  /* marker bit finishes the frame */
+  if (gst_rtp_buffer_get_marker (rtp)) {
+    GST_DEBUG_OBJECT (rtpj2kdepay, "marker set, last buffer");
+    /* then flush frame */
+    gst_rtp_j2k_depay_flush_frame (depayload);
+  }
+
+  return NULL;
+
+  /* ERRORS */
+empty_packet:
+  {
+    GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE,
+        ("Empty Payload."), (NULL));
+    return NULL;
+  }
+wrong_mh_id:
+  {
+    GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE,
+        ("Invalid mh_id %u, expected %u", mh_id, rtpj2kdepay->last_mh_id),
+        (NULL));
+    gst_rtp_j2k_depay_clear_pu (rtpj2kdepay);
+    return NULL;
+  }
+}
+
+static void
+gst_rtp_j2k_depay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_j2k_depay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_j2k_depay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRtpJ2KDepay *rtpj2kdepay;
+  GstStateChangeReturn ret;
+
+  rtpj2kdepay = GST_RTP_J2K_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_j2k_depay_reset (rtpj2kdepay);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_j2k_depay_reset (rtpj2kdepay);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_j2k_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpj2kdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_J2K_DEPAY);
+}
diff --git a/gst/rtp/gstrtpj2kdepay.h b/gst/rtp/gstrtpj2kdepay.h
new file mode 100644
index 0000000..ebc7433
--- /dev/null
+++ b/gst/rtp/gstrtpj2kdepay.h
@@ -0,0 +1,72 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_J2K_DEPAY_H__
+#define __GST_RTP_J2K_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_J2K_DEPAY \
+  (gst_rtp_j2k_depay_get_type())
+#define GST_RTP_J2K_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_J2K_DEPAY,GstRtpJ2KDepay))
+#define GST_RTP_J2K_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_J2K_DEPAY,GstRtpJ2KDepayClass))
+#define GST_IS_RTP_J2K_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_J2K_DEPAY))
+#define GST_IS_RTP_J2K_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_J2K_DEPAY))
+typedef struct _GstRtpJ2KDepay GstRtpJ2KDepay;
+typedef struct _GstRtpJ2KDepayClass GstRtpJ2KDepayClass;
+
+struct _GstRtpJ2KDepay
+{
+  GstRTPBaseDepayload depayload;
+
+  guint64 last_rtptime;
+  guint last_mh_id;
+  guint last_tile;
+
+  GstBuffer *MH[8];
+
+  guint pu_MHF;
+  GstAdapter *pu_adapter;
+  GstAdapter *t_adapter;
+  GstAdapter *f_adapter;
+
+  guint next_frag;
+  gboolean have_sync;
+
+  gint width, height;
+};
+
+struct _GstRtpJ2KDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_j2k_depay_get_type (void);
+
+gboolean gst_rtp_j2k_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_J2K_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpj2kpay.c b/gst/rtp/gstrtpj2kpay.c
new file mode 100644
index 0000000..f1c6c03
--- /dev/null
+++ b/gst/rtp/gstrtpj2kpay.c
@@ -0,0 +1,569 @@
+/* GStreamer
+ * Copyright (C) 2009 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+ /**
+ * SECTION:element-rtpj2kpay
+ *
+ * Payload encode JPEG 2000 images into RTP packets according to RFC 5371
+ * and RFC 5372.
+ * For detailed information see: https://datatracker.ietf.org/doc/rfc5371/
+ * and https://datatracker.ietf.org/doc/rfc5372/
+ *
+ * The payloader takes a JPEG 2000 image, scans it for "packetization
+ * units" and constructs the RTP packet header followed by the JPEG 2000
+ * codestream. A "packetization unit" is defined as either a JPEG 2000 main header,
+ * a JPEG 2000 tile-part header, or a JPEG 2000 packet.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+#include "gstrtpj2kcommon.h"
+#include "gstrtpj2kpay.h"
+#include "gstrtputils.h"
+
+static GstStaticPadTemplate gst_rtp_j2k_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("image/x-jpc, " GST_RTP_J2K_SAMPLING_LIST)
+    );
+
+
+static GstStaticPadTemplate gst_rtp_j2k_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "  media = (string) \"video\", "
+        "  payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "  clock-rate = (int) 90000, "
+        GST_RTP_J2K_SAMPLING_LIST "," "  encoding-name = (string) \"JPEG2000\"")
+    );
+
+GST_DEBUG_CATEGORY_STATIC (rtpj2kpay_debug);
+#define GST_CAT_DEFAULT (rtpj2kpay_debug)
+
+
+enum
+{
+  PROP_0,
+  PROP_LAST
+};
+
+typedef struct
+{
+  guint tp:2;
+  guint MHF:2;
+  guint mh_id:3;
+  guint T:1;
+  guint priority:8;
+  guint tile:16;
+  guint offset:24;
+} RtpJ2KHeader;
+
+static void gst_rtp_j2k_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_j2k_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_rtp_j2k_pay_setcaps (GstRTPBasePayload * basepayload,
+    GstCaps * caps);
+
+static GstFlowReturn gst_rtp_j2k_pay_handle_buffer (GstRTPBasePayload * pad,
+    GstBuffer * buffer);
+
+#define gst_rtp_j2k_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpJ2KPay, gst_rtp_j2k_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_j2k_pay_class_init (GstRtpJ2KPayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->set_property = gst_rtp_j2k_pay_set_property;
+  gobject_class->get_property = gst_rtp_j2k_pay_get_property;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_j2k_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_j2k_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP JPEG 2000 payloader", "Codec/Payloader/Network/RTP",
+      "Payload-encodes JPEG 2000 pictures into RTP packets (RFC 5371)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_j2k_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_j2k_pay_handle_buffer;
+
+  GST_DEBUG_CATEGORY_INIT (rtpj2kpay_debug, "rtpj2kpay", 0,
+      "JPEG 2000 RTP Payloader");
+}
+
+static void
+gst_rtp_j2k_pay_init (GstRtpJ2KPay * pay)
+{
+}
+
+static gboolean
+gst_rtp_j2k_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+  GstStructure *caps_structure = gst_caps_get_structure (caps, 0);
+  gboolean res;
+  gint width = 0, height = 0;
+  const gchar *sampling = NULL;
+
+  gboolean has_width = gst_structure_get_int (caps_structure, "width", &width);
+  gboolean has_height =
+      gst_structure_get_int (caps_structure, "height", &height);
+
+
+  /* sampling is a required field */
+  sampling = gst_structure_get_string (caps_structure, "sampling");
+
+  gst_rtp_base_payload_set_options (basepayload, "video", TRUE, "JPEG2000",
+      90000);
+
+  if (has_width && has_height)
+    res = gst_rtp_base_payload_set_outcaps (basepayload,
+        "sampling", G_TYPE_STRING, sampling, "width", G_TYPE_INT, width,
+        "height", G_TYPE_INT, height, NULL);
+  else
+    res =
+        gst_rtp_base_payload_set_outcaps (basepayload, "sampling",
+        G_TYPE_STRING, sampling, NULL);
+  return res;
+}
+
+
+static guint
+gst_rtp_j2k_pay_header_size (const guint8 * data, guint offset)
+{
+  return data[offset] << 8 | data[offset + 1];
+}
+
+
+static GstRtpJ2KMarker
+gst_rtp_j2k_pay_scan_marker (const guint8 * data, guint size, guint * offset)
+{
+  while ((data[(*offset)++] != GST_J2K_MARKER) && ((*offset) < size));
+
+  if (G_UNLIKELY ((*offset) >= size)) {
+    return GST_J2K_MARKER_EOC;
+  } else {
+    guint8 marker = data[(*offset)++];
+    return (GstRtpJ2KMarker) marker;
+  }
+}
+
+typedef struct
+{
+  RtpJ2KHeader header;
+  gboolean multi_tile;
+  gboolean bitstream;
+  guint next_sot;
+  gboolean force_packet;
+} RtpJ2KState;
+
+
+/* Note: The standard recommends that headers be put in their own RTP packets, so we follow
+ * this recommendation in the code. Also, this method groups together all J2K packets
+ * for a tile part and treats this group as a packetization unit. According to the RFC,
+ * only an individual J2K packet is considered a packetization unit.
+ */
+
+static guint
+find_pu_end (GstRtpJ2KPay * pay, const guint8 * data, guint size,
+    guint offset, RtpJ2KState * state)
+{
+  gboolean cut_sop = FALSE;
+  GstRtpJ2KMarker marker;
+
+  /* parse the j2k header for 'start of codestream' */
+  GST_LOG_OBJECT (pay, "checking from offset %u", offset);
+  while (offset < size) {
+    marker = gst_rtp_j2k_pay_scan_marker (data, size, &offset);
+
+    if (state->bitstream) {
+      /* parsing bitstream, only look for SOP */
+      switch (marker) {
+        case GST_J2K_MARKER_SOP:
+          GST_LOG_OBJECT (pay, "found SOP at %u", offset);
+          if (cut_sop)
+            return offset - 2;
+          cut_sop = TRUE;
+          break;
+        case GST_J2K_MARKER_EPH:
+          /* just skip over EPH */
+          GST_LOG_OBJECT (pay, "found EPH at %u", offset);
+          break;
+        default:
+          if (offset >= state->next_sot) {
+            GST_LOG_OBJECT (pay, "reached next SOT at %u", offset);
+            state->bitstream = FALSE;
+            state->force_packet = TRUE;
+            if (marker == GST_J2K_MARKER_EOC && state->next_sot + 2 <= size)
+              /* include EOC but never go past the max size */
+              return state->next_sot + 2;
+            else
+              return state->next_sot;
+          }
+          break;
+      }
+    } else {
+      switch (marker) {
+        case GST_J2K_MARKER_SOC:
+          GST_LOG_OBJECT (pay, "found SOC at %u", offset);
+          /* start off by assuming that we will fit the entire header
+             into the RTP payload */
+          state->header.MHF = 3;
+          break;
+        case GST_J2K_MARKER_SOT:
+        {
+          guint len, Psot, tile;
+
+          GST_LOG_OBJECT (pay, "found SOT at %u", offset);
+          /* SOT for first tile part in code stream:
+             force close of current RTP packet, so that it
+             only contains main header  */
+          if (state->header.MHF) {
+            state->force_packet = TRUE;
+            return offset - 2;
+          }
+
+          /* parse SOT but do some sanity checks first */
+          len = gst_rtp_j2k_pay_header_size (data, offset);
+          GST_LOG_OBJECT (pay, "SOT length %u", len);
+          if (len < 8)
+            return size;
+          if (offset + len >= size)
+            return size;
+
+          /* Isot */
+          tile = GST_READ_UINT16_BE (&data[offset + 2]);
+
+          if (!state->multi_tile) {
+            /* we have detected multiple tiles in this rtp packet : tile bit is now invalid */
+            if (state->header.T == 0 && state->header.tile != tile) {
+              state->header.T = 1;
+              state->multi_tile = TRUE;
+            } else {
+              state->header.T = 0;
+            }
+          }
+          state->header.tile = tile;
+
+          /* Note: Tile parts from multiple tiles in single RTP packet 
+             will make T invalid.
+             This cannot happen in our case since we always
+             send tile headers in their own RTP packets, so we cannot mix
+             tile parts in a single RTP packet  */
+
+          /* Psot: offset of next tile. If it's 0, next tile goes all the way
+             to the end of the data */
+          Psot = GST_READ_UINT32_BE (&data[offset + 4]);
+          if (Psot == 0)
+            state->next_sot = size;
+          else
+            state->next_sot = offset - 2 + Psot;
+
+          offset += len;
+          GST_LOG_OBJECT (pay, "Isot %u, Psot %u, next %u", state->header.tile,
+              Psot, state->next_sot);
+          break;
+        }
+        case GST_J2K_MARKER_SOD:
+          GST_LOG_OBJECT (pay, "found SOD at %u", offset);
+          /* go to bitstream parsing */
+          state->bitstream = TRUE;
+          /* cut at the next SOP or else include all data */
+          cut_sop = TRUE;
+          /* force a new packet when we see SOP, this can be optional but the
+           * spec recommends packing headers separately */
+          state->force_packet = TRUE;
+          break;
+        case GST_J2K_MARKER_EOC:
+          GST_LOG_OBJECT (pay, "found EOC at %u", offset);
+          return offset;
+        default:
+        {
+          guint len = gst_rtp_j2k_pay_header_size (data, offset);
+          GST_LOG_OBJECT (pay, "skip 0x%02x len %u", marker, len);
+          offset += len;
+          break;
+        }
+      }
+    }
+  }
+  GST_DEBUG_OBJECT (pay, "reached end of data");
+  return size;
+}
+
+static GstFlowReturn
+gst_rtp_j2k_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpJ2KPay *pay;
+  GstClockTime timestamp;
+  GstFlowReturn ret = GST_FLOW_ERROR;
+  RtpJ2KState state;
+  GstBufferList *list = NULL;
+  GstMapInfo map;
+  guint mtu, max_size;
+  guint offset;
+  guint end, pos;
+
+  pay = GST_RTP_J2K_PAY (basepayload);
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (pay);
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  timestamp = GST_BUFFER_PTS (buffer);
+  offset = pos = end = 0;
+
+  GST_LOG_OBJECT (pay,
+      "got buffer size %" G_GSIZE_FORMAT ", timestamp %" GST_TIME_FORMAT,
+      map.size, GST_TIME_ARGS (timestamp));
+
+  /* do some header defaults first */
+  state.header.tp = 0;          /* only progressive scan */
+  state.header.MHF = 0;         /* no header */
+  state.header.mh_id = 0;       /* always 0 for now */
+  state.header.T = 1;           /* invalid tile, because we always begin with the main header */
+  state.header.priority = 255;  /* always 255 for now */
+  state.header.tile = 0xffff;   /* no tile number */
+  state.header.offset = 0;      /* offset of 0 */
+  state.multi_tile = FALSE;
+  state.bitstream = FALSE;
+  state.next_sot = 0;
+  state.force_packet = FALSE;
+
+  /* get max packet length */
+  max_size =
+      gst_rtp_buffer_calc_payload_len (mtu - GST_RTP_J2K_HEADER_SIZE, 0, 0);
+
+  list = gst_buffer_list_new_sized ((mtu / max_size) + 1);
+
+  do {
+    GstBuffer *outbuf;
+    guint8 *header;
+    guint payload_size;
+    guint pu_size;
+    GstRTPBuffer rtp = { NULL };
+
+    /* try to pack as much as we can */
+    do {
+      /* see how much we have scanned already */
+      pu_size = end - offset;
+      GST_DEBUG_OBJECT (pay, "scanned pu size %u", pu_size);
+
+      /* we need to make a new packet */
+      if (state.force_packet) {
+        GST_DEBUG_OBJECT (pay, "need to force a new packet");
+        state.force_packet = FALSE;
+        pos = end;
+        break;
+      }
+
+      /* else see if we have enough */
+      if (pu_size > max_size) {
+        if (pos != offset)
+          /* the packet became too large, use previous scanpos */
+          pu_size = pos - offset;
+        else
+          /* the already scanned data was already too big, make sure we start
+           * scanning from the last searched position */
+          pos = end;
+
+        GST_DEBUG_OBJECT (pay, "max size exceeded pu_size %u", pu_size);
+        break;
+      }
+
+      pos = end;
+
+      /* exit when finished */
+      if (pos == map.size)
+        break;
+
+      /* scan next packetization unit and fill in the header */
+      end = find_pu_end (pay, map.data, map.size, pos, &state);
+    } while (TRUE);
+
+    while (pu_size > 0) {
+      guint packet_size, data_size;
+      GstBuffer *paybuf;
+
+      /* calculate the packet size */
+      packet_size =
+          gst_rtp_buffer_calc_packet_len (pu_size + GST_RTP_J2K_HEADER_SIZE, 0,
+          0);
+
+      if (packet_size > mtu) {
+        GST_DEBUG_OBJECT (pay, "needed packet size %u clamped to MTU %u",
+            packet_size, mtu);
+        packet_size = mtu;
+      } else {
+        GST_DEBUG_OBJECT (pay, "needed packet size %u fits in MTU %u",
+            packet_size, mtu);
+      }
+
+      /* get total payload size and data size */
+      payload_size = gst_rtp_buffer_calc_payload_len (packet_size, 0, 0);
+      data_size = payload_size - GST_RTP_J2K_HEADER_SIZE;
+
+      /* make buffer for header */
+      outbuf = gst_rtp_buffer_new_allocate (GST_RTP_J2K_HEADER_SIZE, 0, 0);
+
+      GST_BUFFER_PTS (outbuf) = timestamp;
+
+      gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+      /* get pointer to header */
+      header = gst_rtp_buffer_get_payload (&rtp);
+
+      pu_size -= data_size;
+
+      /* reached the end of a packetization unit */
+      if (pu_size == 0 && end >= map.size) {
+        gst_rtp_buffer_set_marker (&rtp, TRUE);
+      }
+      /* If we were processing a header, see if all fits in one RTP packet
+         or if we have to fragment it */
+      if (state.header.MHF) {
+        switch (state.header.MHF) {
+          case 3:
+            if (pu_size > 0)
+              state.header.MHF = 1;
+            break;
+          case 1:
+            if (pu_size == 0)
+              state.header.MHF = 2;
+            break;
+          default:
+            break;
+        }
+      }
+
+      /*
+       * RtpJ2KHeader:
+       * @tp: type (0 progressive, 1 odd field, 2 even field)
+       * @MHF: Main Header Flag
+       * @mh_id: Main Header Identification
+       * @T: Tile field invalidation flag
+       * @priority: priority
+       * @tile number: the tile number of the payload
+       * @reserved: set to 0
+       * @fragment offset: the byte offset of the current payload
+       *
+       *  0                   1                   2                   3
+       *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       * |tp |MHF|mh_id|T|     priority  |           tile number         |
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       * |reserved       |             fragment offset                   |
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       */
+      header[0] = (state.header.tp << 6) | (state.header.MHF << 4) |
+          (state.header.mh_id << 1) | state.header.T;
+      header[1] = state.header.priority;
+      header[2] = state.header.tile >> 8;
+      header[3] = state.header.tile & 0xff;
+      header[4] = 0;
+      header[5] = state.header.offset >> 16;
+      header[6] = (state.header.offset >> 8) & 0xff;
+      header[7] = state.header.offset & 0xff;
+
+      gst_rtp_buffer_unmap (&rtp);
+
+      /* make subbuffer of j2k data */
+      paybuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL,
+          offset, data_size);
+      gst_rtp_copy_video_meta (basepayload, outbuf, paybuf);
+      outbuf = gst_buffer_append (outbuf, paybuf);
+
+      gst_buffer_list_add (list, outbuf);
+
+      /* reset multi_tile */
+      state.multi_tile = FALSE;
+
+
+      /* set MHF to zero if there is no more main header to process */
+      if (state.header.MHF & 2)
+        state.header.MHF = 0;
+
+      /* tile is valid, if there is no more header to process */
+      if (!state.header.MHF)
+        state.header.T = 0;
+
+
+      offset += data_size;
+      state.header.offset = offset;
+    }
+    offset = pos;
+  } while (offset < map.size);
+
+  gst_buffer_unmap (buffer, &map);
+  gst_buffer_unref (buffer);
+
+  /* push the whole buffer list at once */
+  ret = gst_rtp_base_payload_push_list (basepayload, list);
+
+  return ret;
+}
+
+static void
+gst_rtp_j2k_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_j2k_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+gboolean
+gst_rtp_j2k_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpj2kpay", GST_RANK_SECONDARY,
+      GST_TYPE_RTP_J2K_PAY);
+}
diff --git a/gst/rtp/gstrtpj2kpay.h b/gst/rtp/gstrtpj2kpay.h
new file mode 100644
index 0000000..14f5295
--- /dev/null
+++ b/gst/rtp/gstrtpj2kpay.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) 2009 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_J2K_PAY_H__
+#define __GST_RTP_J2K_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_J2K_PAY \
+  (gst_rtp_j2k_pay_get_type())
+#define GST_RTP_J2K_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_J2K_PAY,GstRtpJ2KPay))
+#define GST_RTP_J2K_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_J2K_PAY,GstRtpJ2KPayClass))
+#define GST_IS_RTP_J2K_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_J2K_PAY))
+#define GST_IS_RTP_J2K_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_J2K_PAY))
+typedef struct _GstRtpJ2KPay GstRtpJ2KPay;
+typedef struct _GstRtpJ2KPayClass GstRtpJ2KPayClass;
+
+struct _GstRtpJ2KPay
+{
+  GstRTPBasePayload payload;
+
+  gint height;
+  gint width;
+};
+
+struct _GstRtpJ2KPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_j2k_pay_get_type (void);
+
+gboolean gst_rtp_j2k_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_J2K_PAY_H__ */
diff --git a/gst/rtp/gstrtpjpegdepay.c b/gst/rtp/gstrtpjpegdepay.c
new file mode 100644
index 0000000..59274f1
--- /dev/null
+++ b/gst/rtp/gstrtpjpegdepay.c
@@ -0,0 +1,799 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gstrtpjpegdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpjpegdepay_debug);
+#define GST_CAT_DEFAULT (rtpjpegdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_jpeg_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("image/jpeg")
+    );
+
+static GstStaticPadTemplate gst_rtp_jpeg_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG\"; "
+        /* optional SDP attributes */
+        /*
+         * "a-framerate = (string) 0.00, "
+         * "x-framerate = (string) 0.00, "
+         * "x-dimensions = (string) \"1234,1234\", "
+         */
+        "application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
+        "clock-rate = (int) 90000"
+        /* optional SDP attributes */
+        /*
+         * "a-framerate = (string) 0.00, "
+         * "x-framerate = (string) 0.00, "
+         * "x-dimensions = (string) \"1234,1234\""
+         */
+    )
+    );
+
+#define gst_rtp_jpeg_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpJPEGDepay, gst_rtp_jpeg_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_jpeg_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_jpeg_depay_change_state (GstElement *
+    element, GstStateChange transition);
+
+static gboolean gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+static void
+gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_jpeg_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_jpeg_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP JPEG depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts JPEG video from RTP packets (RFC 2435)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstelement_class->change_state = gst_rtp_jpeg_depay_change_state;
+
+  gstrtpbasedepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_jpeg_depay_process;
+
+  GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
+      "JPEG Video RTP Depayloader");
+}
+
+static void
+gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay)
+{
+  rtpjpegdepay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_jpeg_depay_reset (GstRtpJPEGDepay * depay)
+{
+  gint i;
+
+  depay->width = 0;
+  depay->height = 0;
+  depay->media_width = 0;
+  depay->media_height = 0;
+  depay->frate_num = 0;
+  depay->frate_denom = 1;
+  depay->discont = TRUE;
+
+  for (i = 0; i < 255; i++) {
+    g_free (depay->qtables[i]);
+    depay->qtables[i] = NULL;
+  }
+
+  gst_adapter_clear (depay->adapter);
+}
+
+static void
+gst_rtp_jpeg_depay_finalize (GObject * object)
+{
+  GstRtpJPEGDepay *rtpjpegdepay;
+
+  rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
+
+  gst_rtp_jpeg_depay_reset (rtpjpegdepay);
+
+  g_object_unref (rtpjpegdepay->adapter);
+  rtpjpegdepay->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static const int zigzag[] = {
+  0, 1, 8, 16, 9, 2, 3, 10,
+  17, 24, 32, 25, 18, 11, 4, 5,
+  12, 19, 26, 33, 40, 48, 41, 34,
+  27, 20, 13, 6, 7, 14, 21, 28,
+  35, 42, 49, 56, 57, 50, 43, 36,
+  29, 22, 15, 23, 30, 37, 44, 51,
+  58, 59, 52, 45, 38, 31, 39, 46,
+  53, 60, 61, 54, 47, 55, 62, 63
+};
+
+/*
+ * Table K.1 from JPEG spec.
+ */
+static const int jpeg_luma_quantizer[64] = {
+  16, 11, 10, 16, 24, 40, 51, 61,
+  12, 12, 14, 19, 26, 58, 60, 55,
+  14, 13, 16, 24, 40, 57, 69, 56,
+  14, 17, 22, 29, 51, 87, 80, 62,
+  18, 22, 37, 56, 68, 109, 103, 77,
+  24, 35, 55, 64, 81, 104, 113, 92,
+  49, 64, 78, 87, 103, 121, 120, 101,
+  72, 92, 95, 98, 112, 100, 103, 99
+};
+
+/*
+ * Table K.2 from JPEG spec.
+ */
+static const int jpeg_chroma_quantizer[64] = {
+  17, 18, 24, 47, 99, 99, 99, 99,
+  18, 21, 26, 66, 99, 99, 99, 99,
+  24, 26, 56, 99, 99, 99, 99, 99,
+  47, 66, 99, 99, 99, 99, 99, 99,
+  99, 99, 99, 99, 99, 99, 99, 99,
+  99, 99, 99, 99, 99, 99, 99, 99,
+  99, 99, 99, 99, 99, 99, 99, 99,
+  99, 99, 99, 99, 99, 99, 99, 99
+};
+
+/* Call MakeTables with the Q factor and a guint8[128] return array
+ */
+static void
+MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
+{
+  gint i;
+  guint factor;
+
+  factor = CLAMP (Q, 1, 99);
+
+  if (Q < 50)
+    Q = 5000 / factor;
+  else
+    Q = 200 - factor * 2;
+
+  for (i = 0; i < 64; i++) {
+    gint lq = (jpeg_luma_quantizer[zigzag[i]] * Q + 50) / 100;
+    gint cq = (jpeg_chroma_quantizer[zigzag[i]] * Q + 50) / 100;
+
+    /* Limit the quantizers to 1 <= q <= 255 */
+    qtable[i] = CLAMP (lq, 1, 255);
+    qtable[i + 64] = CLAMP (cq, 1, 255);
+  }
+}
+
+static const guint8 lum_dc_codelens[] = {
+  0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const guint8 lum_dc_symbols[] = {
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const guint8 lum_ac_codelens[] = {
+  0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
+};
+
+static const guint8 lum_ac_symbols[] = {
+  0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+  0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+  0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+  0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+  0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+  0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+  0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+  0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+  0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+  0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+  0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+  0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+  0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+  0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+  0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+  0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+  0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+  0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+  0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+  0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+  0xf9, 0xfa
+};
+
+static const guint8 chm_dc_codelens[] = {
+  0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
+};
+
+static const guint8 chm_dc_symbols[] = {
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const guint8 chm_ac_codelens[] = {
+  0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
+};
+
+static const guint8 chm_ac_symbols[] = {
+  0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+  0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+  0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+  0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+  0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+  0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+  0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+  0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+  0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+  0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+  0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+  0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+  0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+  0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+  0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+  0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+  0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+  0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+  0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+  0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+  0xf9, 0xfa
+};
+
+static guint8 *
+MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
+{
+  *p++ = 0xff;
+  *p++ = 0xdb;                  /* DQT */
+  *p++ = 0;                     /* length msb */
+  *p++ = size + 3;              /* length lsb */
+  *p++ = tableNo;
+  memcpy (p, qt, size);
+
+  return (p + size);
+}
+
+static guint8 *
+MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
+    const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
+{
+  *p++ = 0xff;
+  *p++ = 0xc4;                  /* DHT */
+  *p++ = 0;                     /* length msb */
+  *p++ = 3 + ncodes + nsymbols; /* length lsb */
+  *p++ = (tableClass << 4) | tableNo;
+  memcpy (p, codelens, ncodes);
+  p += ncodes;
+  memcpy (p, symbols, nsymbols);
+  p += nsymbols;
+
+  return (p);
+}
+
+static guint8 *
+MakeDRIHeader (guint8 * p, guint16 dri)
+{
+  *p++ = 0xff;
+  *p++ = 0xdd;                  /* DRI */
+  *p++ = 0x0;                   /* length msb */
+  *p++ = 4;                     /* length lsb */
+  *p++ = dri >> 8;              /* dri msb */
+  *p++ = dri & 0xff;            /* dri lsb */
+
+  return (p);
+}
+
+/*
+ *  Arguments:
+ *    type, width, height: as supplied in RTP/JPEG header
+ *    qt: quantization tables as either derived from
+ *        the Q field using MakeTables() or as specified
+ *        in section 4.2.
+ *    dri: restart interval in MCUs, or 0 if no restarts.
+ *
+ *    p: pointer to return area
+ *
+ *  Return value:
+ *    The length of the generated headers.
+ *
+ *    Generate a frame and scan headers that can be prepended to the
+ *    RTP/JPEG data payload to produce a JPEG compressed image in
+ *    interchange format (except for possible trailing garbage and
+ *    absence of an EOI marker to terminate the scan).
+ */
+static guint
+MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
+    guint precision, guint16 dri)
+{
+  guint8 *start = p;
+  gint size;
+
+  *p++ = 0xff;
+  *p++ = 0xd8;                  /* SOI */
+
+  size = ((precision & 1) ? 128 : 64);
+  p = MakeQuantHeader (p, qt, size, 0);
+  qt += size;
+
+  size = ((precision & 2) ? 128 : 64);
+  p = MakeQuantHeader (p, qt, size, 1);
+  qt += size;
+
+  if (dri != 0)
+    p = MakeDRIHeader (p, dri);
+
+  *p++ = 0xff;
+  *p++ = 0xc0;                  /* SOF */
+  *p++ = 0;                     /* length msb */
+  *p++ = 17;                    /* length lsb */
+  *p++ = 8;                     /* 8-bit precision */
+  *p++ = height >> 8;           /* height msb */
+  *p++ = height;                /* height lsb */
+  *p++ = width >> 8;            /* width msb */
+  *p++ = width;                 /* width lsb */
+  *p++ = 3;                     /* number of components */
+  *p++ = 0;                     /* comp 0 */
+  if ((type & 0x3f) == 0)
+    *p++ = 0x21;                /* hsamp = 2, vsamp = 1 */
+  else
+    *p++ = 0x22;                /* hsamp = 2, vsamp = 2 */
+  *p++ = 0;                     /* quant table 0 */
+  *p++ = 1;                     /* comp 1 */
+  *p++ = 0x11;                  /* hsamp = 1, vsamp = 1 */
+  *p++ = 1;                     /* quant table 1 */
+  *p++ = 2;                     /* comp 2 */
+  *p++ = 0x11;                  /* hsamp = 1, vsamp = 1 */
+  *p++ = 1;                     /* quant table 1 */
+
+  p = MakeHuffmanHeader (p, lum_dc_codelens,
+      sizeof (lum_dc_codelens), lum_dc_symbols, sizeof (lum_dc_symbols), 0, 0);
+  p = MakeHuffmanHeader (p, lum_ac_codelens,
+      sizeof (lum_ac_codelens), lum_ac_symbols, sizeof (lum_ac_symbols), 0, 1);
+  p = MakeHuffmanHeader (p, chm_dc_codelens,
+      sizeof (chm_dc_codelens), chm_dc_symbols, sizeof (chm_dc_symbols), 1, 0);
+  p = MakeHuffmanHeader (p, chm_ac_codelens,
+      sizeof (chm_ac_codelens), chm_ac_symbols, sizeof (chm_ac_symbols), 1, 1);
+
+  *p++ = 0xff;
+  *p++ = 0xda;                  /* SOS */
+  *p++ = 0;                     /* length msb */
+  *p++ = 12;                    /* length lsb */
+  *p++ = 3;                     /* 3 components */
+  *p++ = 0;                     /* comp 0 */
+  *p++ = 0;                     /* huffman table 0 */
+  *p++ = 1;                     /* comp 1 */
+  *p++ = 0x11;                  /* huffman table 1 */
+  *p++ = 2;                     /* comp 2 */
+  *p++ = 0x11;                  /* huffman table 1 */
+  *p++ = 0;                     /* first DCT coeff */
+  *p++ = 63;                    /* last DCT coeff */
+  *p++ = 0;                     /* sucessive approx. */
+
+  return (p - start);
+};
+
+static gboolean
+gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstRtpJPEGDepay *rtpjpegdepay;
+  GstStructure *structure;
+  gint clock_rate;
+  const gchar *media_attr;
+
+  rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+  GST_DEBUG_OBJECT (rtpjpegdepay, "Caps set: %" GST_PTR_FORMAT, caps);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;
+  depayload->clock_rate = clock_rate;
+
+  /* reset defaults */
+  rtpjpegdepay->width = 0;
+  rtpjpegdepay->height = 0;
+  rtpjpegdepay->media_width = 0;
+  rtpjpegdepay->media_height = 0;
+  rtpjpegdepay->frate_num = 0;
+  rtpjpegdepay->frate_denom = 1;
+
+  /* check for optional SDP attributes */
+  if ((media_attr = gst_structure_get_string (structure, "x-dimensions"))) {
+    gint w, h;
+
+    if (sscanf (media_attr, "%d,%d", &w, &h) == 2) {
+      rtpjpegdepay->media_width = w;
+      rtpjpegdepay->media_height = h;
+    }
+  }
+
+  /* try to get a framerate */
+  media_attr = gst_structure_get_string (structure, "a-framerate");
+  if (!media_attr)
+    media_attr = gst_structure_get_string (structure, "x-framerate");
+
+  if (media_attr) {
+    GValue src = { 0 };
+    GValue dest = { 0 };
+    gchar *s;
+
+    /* canonicalise floating point string so we can handle framerate strings
+     * in the form "24.930" or "24,930" irrespective of the current locale */
+    s = g_strdup (media_attr);
+    g_strdelimit (s, ",", '.');
+
+    /* convert the float to a fraction */
+    g_value_init (&src, G_TYPE_DOUBLE);
+    g_value_set_double (&src, g_ascii_strtod (s, NULL));
+    g_value_init (&dest, GST_TYPE_FRACTION);
+    g_value_transform (&src, &dest);
+
+    rtpjpegdepay->frate_num = gst_value_get_fraction_numerator (&dest);
+    rtpjpegdepay->frate_denom = gst_value_get_fraction_denominator (&dest);
+
+    g_free (s);
+  }
+
+  return TRUE;
+}
+
+static GstBuffer *
+gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpJPEGDepay *rtpjpegdepay;
+  GstBuffer *outbuf;
+  gint payload_len, header_len;
+  guint8 *payload;
+  guint frag_offset;
+  gint Q;
+  guint type, width, height;
+  guint16 dri, precision, length;
+  guint8 *qtable;
+
+  rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
+
+  if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
+    GST_DEBUG_OBJECT (depayload, "DISCONT, reset adapter");
+    gst_adapter_clear (rtpjpegdepay->adapter);
+    rtpjpegdepay->discont = TRUE;
+  }
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  if (payload_len < 8)
+    goto empty_packet;
+
+  payload = gst_rtp_buffer_get_payload (rtp);
+  header_len = 0;
+
+  /*  0                   1                   2                   3
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * | Type-specific |              Fragment Offset                  |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |      Type     |       Q       |     Width     |     Height    |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   */
+  frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
+  type = payload[4];
+  Q = payload[5];
+  width = payload[6] * 8;
+  height = payload[7] * 8;
+
+  /* saw a packet with fragment offset > 0 and we don't already have data queued
+   * up (most importantly, we don't have a header for this data) -- drop it
+   * XXX: maybe we can check if the jpeg is progressive and salvage the data?
+   * XXX: not implemented yet because jpegenc can't create progressive jpegs */
+  if (frag_offset > 0 && gst_adapter_available (rtpjpegdepay->adapter) == 0)
+    goto no_header_packet;
+
+  /* allow frame dimensions > 2040, passed in SDP session or media attributes
+   * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
+  if (!width)
+    width = rtpjpegdepay->media_width;
+
+  if (!height)
+    height = rtpjpegdepay->media_height;
+
+  if (width == 0 || height == 0)
+    goto invalid_dimension;
+
+  GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
+      frag_offset, type, Q, width, height);
+
+  header_len += 8;
+  payload += 8;
+  payload_len -= 8;
+
+  dri = 0;
+  if (type > 63) {
+    if (payload_len < 4)
+      goto empty_packet;
+
+    /*  0                   1                   2                   3
+     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * |       Restart Interval        |F|L|       Restart Count       |
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     */
+    dri = (payload[0] << 8) | payload[1];
+
+    GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
+
+    payload += 4;
+    header_len += 4;
+    payload_len -= 4;
+  }
+
+  if (Q >= 128 && frag_offset == 0) {
+    if (payload_len < 4)
+      goto empty_packet;
+
+    /*  0                   1                   2                   3
+     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * |      MBZ      |   Precision   |             Length            |
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * |                    Quantization Table Data                    |
+     * |                              ...                              |
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     */
+    precision = payload[1];
+    length = (payload[2] << 8) | payload[3];
+
+    GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
+        precision, length);
+
+    if (Q == 255 && length == 0)
+      goto empty_packet;
+
+    payload += 4;
+    header_len += 4;
+    payload_len -= 4;
+
+    if (length > payload_len)
+      goto empty_packet;
+
+    if (length > 0)
+      qtable = payload;
+    else
+      qtable = rtpjpegdepay->qtables[Q];
+
+    payload += length;
+    header_len += length;
+    payload_len -= length;
+  } else {
+    length = 0;
+    qtable = NULL;
+    precision = 0;
+  }
+
+  if (frag_offset == 0) {
+    GstMapInfo map;
+    guint size;
+
+    if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
+      GstCaps *outcaps;
+
+      outcaps =
+          gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
+          rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
+          G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
+      gst_pad_set_caps (depayload->srcpad, outcaps);
+      gst_caps_unref (outcaps);
+
+      rtpjpegdepay->width = width;
+      rtpjpegdepay->height = height;
+    }
+
+    GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
+        length);
+
+    /* first packet */
+    if (length == 0) {
+      if (Q < 128) {
+        /* no quant table, see if we have one cached */
+        qtable = rtpjpegdepay->qtables[Q];
+        if (!qtable) {
+          GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
+          /* make and cache the table */
+          qtable = g_new (guint8, 128);
+          MakeTables (rtpjpegdepay, Q, qtable);
+          rtpjpegdepay->qtables[Q] = qtable;
+        } else {
+          GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
+        }
+        /* all 8 bit quantizers */
+        precision = 0;
+      } else {
+        if (!qtable)
+          goto no_qtable;
+      }
+    }
+
+    /* I think we can get here with a NULL qtable, so make sure we don't
+       go dereferencing it in MakeHeaders if we do */
+    if (!qtable)
+      goto no_qtable;
+
+    /* max header length, should be big enough */
+    outbuf = gst_buffer_new_and_alloc (1000);
+    gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+    size = MakeHeaders (map.data, type, width, height, qtable, precision, dri);
+    gst_buffer_unmap (outbuf, &map);
+    gst_buffer_resize (outbuf, 0, size);
+
+    GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
+
+    gst_adapter_push (rtpjpegdepay->adapter, outbuf);
+  }
+
+  /* take JPEG data, push in the adapter */
+  GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
+  outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, header_len, -1);
+  gst_adapter_push (rtpjpegdepay->adapter, outbuf);
+  outbuf = NULL;
+
+  if (gst_rtp_buffer_get_marker (rtp)) {
+    guint avail;
+    guint8 end[2];
+    GstMapInfo map;
+
+    /* last buffer take all data out of the adapter */
+    avail = gst_adapter_available (rtpjpegdepay->adapter);
+    GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
+
+    if (avail < 2)
+      goto invalid_packet;
+
+    /* take the last bytes of the jpeg data to see if there is an EOI
+     * marker */
+    gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
+
+    if (end[0] != 0xff && end[1] != 0xd9) {
+      GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
+
+      /* no EOI marker, add one */
+      outbuf = gst_buffer_new_and_alloc (2);
+      gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+      map.data[0] = 0xff;
+      map.data[1] = 0xd9;
+      gst_buffer_unmap (outbuf, &map);
+
+      gst_adapter_push (rtpjpegdepay->adapter, outbuf);
+      avail += 2;
+    }
+    outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
+
+    if (rtpjpegdepay->discont) {
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+      rtpjpegdepay->discont = FALSE;
+    }
+
+    gst_rtp_drop_non_video_meta (rtpjpegdepay, outbuf);
+
+    GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
+  }
+
+  return outbuf;
+
+  /* ERRORS */
+empty_packet:
+  {
+    GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
+        ("Empty Payload."), (NULL));
+    return NULL;
+  }
+invalid_dimension:
+  {
+    GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
+        ("Invalid Dimension %dx%d.", width, height), (NULL));
+    return NULL;
+  }
+no_qtable:
+  {
+    GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
+    return NULL;
+  }
+invalid_packet:
+  {
+    GST_WARNING_OBJECT (rtpjpegdepay, "invalid packet");
+    gst_adapter_flush (rtpjpegdepay->adapter,
+        gst_adapter_available (rtpjpegdepay->adapter));
+    return NULL;
+  }
+no_header_packet:
+  {
+    GST_WARNING_OBJECT (rtpjpegdepay,
+        "discarding data packets received when we have no header");
+    return NULL;
+  }
+}
+
+
+static GstStateChangeReturn
+gst_rtp_jpeg_depay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpJPEGDepay *rtpjpegdepay;
+  GstStateChangeReturn ret;
+
+  rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_jpeg_depay_reset (rtpjpegdepay);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+
+gboolean
+gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpjpegdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY);
+}
diff --git a/gst/rtp/gstrtpjpegdepay.h b/gst/rtp/gstrtpjpegdepay.h
new file mode 100644
index 0000000..cb74f12
--- /dev/null
+++ b/gst/rtp/gstrtpjpegdepay.h
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_JPEG_DEPAY_H__
+#define __GST_RTP_JPEG_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_JPEG_DEPAY \
+  (gst_rtp_jpeg_depay_get_type())
+#define GST_RTP_JPEG_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_JPEG_DEPAY,GstRtpJPEGDepay))
+#define GST_RTP_JPEG_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_JPEG_DEPAY,GstRtpJPEGDepayClass))
+#define GST_IS_RTP_JPEG_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_JPEG_DEPAY))
+#define GST_IS_RTP_JPEG_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_JPEG_DEPAY))
+
+typedef struct _GstRtpJPEGDepay GstRtpJPEGDepay;
+typedef struct _GstRtpJPEGDepayClass GstRtpJPEGDepayClass;
+
+struct _GstRtpJPEGDepay
+{
+  GstRTPBaseDepayload depayload;
+
+  GstAdapter *adapter;
+  gboolean    discont;
+
+  /* cached quant tables */
+  guint8 * qtables[255];
+  gint frate_num;
+  gint frate_denom;
+  gint media_width;
+  gint media_height;
+  gint width, height;
+};
+
+struct _GstRtpJPEGDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_jpeg_depay_get_type (void);
+
+gboolean gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_JPEG_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpjpegpay.c b/gst/rtp/gstrtpjpegpay.c
new file mode 100644
index 0000000..fe93016
--- /dev/null
+++ b/gst/rtp/gstrtpjpegpay.c
@@ -0,0 +1,1006 @@
+/* GStreamer
+ * Copyright (C) 2008 Axis Communications <dev-gstreamer@axis.com>
+ * @author Bjorn Ostby <bjorn.ostby@axis.com>
+ * @author Peter Kjellerstedt <peter.kjellerstedt@axis.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpjpegpay
+ *
+ * Payload encode JPEG pictures into RTP packets according to RFC 2435.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc2435.txt
+ *
+ * The payloader takes a JPEG picture, scans the header for quantization
+ * tables (if needed) and constructs the RTP packet header followed by
+ * the actual JPEG entropy scan.
+ *
+ * The payloader assumes that correct width and height is found in the caps.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+
+#include "gstrtpjpegpay.h"
+#include "gstrtputils.h"
+
+static GstStaticPadTemplate gst_rtp_jpeg_pay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("image/jpeg; " "video/x-jpeg")
+    );
+
+static GstStaticPadTemplate gst_rtp_jpeg_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "  media = (string) \"video\", "
+        "  payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
+        "  clock-rate = (int) 90000,   "
+        "  encoding-name = (string) \"JPEG\", "
+        "  width = (int) [ 1, 65536 ], " "  height = (int) [ 1, 65536 ]; "
+        " application/x-rtp, "
+        "  media = (string) \"video\", "
+        "  payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "  clock-rate = (int) 90000,   "
+        "  encoding-name = (string) \"JPEG\", "
+        "  width = (int) [ 1, 65536 ], " "  height = (int) [ 1, 65536 ]")
+    );
+
+GST_DEBUG_CATEGORY_STATIC (rtpjpegpay_debug);
+#define GST_CAT_DEFAULT (rtpjpegpay_debug)
+
+/*
+ * QUANT_PREFIX_LEN:
+ *
+ * Prefix length in the header before the quantization tables:
+ * Two size bytes and one byte for precision
+ */
+#define QUANT_PREFIX_LEN     3
+
+
+typedef enum _RtpJpegMarker RtpJpegMarker;
+
+/*
+ * RtpJpegMarker:
+ * @JPEG_MARKER: Prefix for JPEG marker
+ * @JPEG_MARKER_SOI: Start of Image marker
+ * @JPEG_MARKER_JFIF: JFIF marker
+ * @JPEG_MARKER_CMT: Comment marker
+ * @JPEG_MARKER_DQT: Define Quantization Table marker
+ * @JPEG_MARKER_SOF: Start of Frame marker
+ * @JPEG_MARKER_DHT: Define Huffman Table marker
+ * @JPEG_MARKER_SOS: Start of Scan marker
+ * @JPEG_MARKER_EOI: End of Image marker
+ * @JPEG_MARKER_DRI: Define Restart Interval marker
+ * @JPEG_MARKER_H264: H264 marker
+ *
+ * Identifers for markers in JPEG header
+ */
+enum _RtpJpegMarker
+{
+  JPEG_MARKER = 0xFF,
+  JPEG_MARKER_SOI = 0xD8,
+  JPEG_MARKER_JFIF = 0xE0,
+  JPEG_MARKER_CMT = 0xFE,
+  JPEG_MARKER_DQT = 0xDB,
+  JPEG_MARKER_SOF = 0xC0,
+  JPEG_MARKER_DHT = 0xC4,
+  JPEG_MARKER_JPG = 0xC8,
+  JPEG_MARKER_SOS = 0xDA,
+  JPEG_MARKER_EOI = 0xD9,
+  JPEG_MARKER_DRI = 0xDD,
+  JPEG_MARKER_APP0 = 0xE0,
+  JPEG_MARKER_H264 = 0xE4,      /* APP4 */
+  JPEG_MARKER_APP15 = 0xEF,
+  JPEG_MARKER_JPG0 = 0xF0,
+  JPEG_MARKER_JPG13 = 0xFD
+};
+
+#define DEFAULT_JPEG_QUANT    255
+
+#define DEFAULT_JPEG_QUALITY  255
+#define DEFAULT_JPEG_TYPE     1
+
+enum
+{
+  PROP_0,
+  PROP_JPEG_QUALITY,
+  PROP_JPEG_TYPE
+};
+
+enum
+{
+  Q_TABLE_0 = 0,
+  Q_TABLE_1,
+  Q_TABLE_MAX                   /* only support for two tables at the moment */
+};
+
+typedef struct _RtpJpegHeader RtpJpegHeader;
+
+/*
+ * RtpJpegHeader:
+ * @type_spec: type specific
+ * @offset: fragment offset
+ * @type: type field
+ * @q: quantization table for this frame
+ * @width: width of image in 8-pixel multiples
+ * @height: height of image in 8-pixel multiples
+ *
+ * 0                   1                   2                   3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type-specific |              Fragment Offset                  |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |      Type     |       Q       |     Width     |     Height    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct _RtpJpegHeader
+{
+  guint type_spec:8;
+  guint offset:24;
+  guint8 type;
+  guint8 q;
+  guint8 width;
+  guint8 height;
+};
+
+/*
+ * RtpQuantHeader
+ * @mbz: must be zero
+ * @precision: specify size of quantization tables
+ * @length: length of quantization data
+ *
+ * 0                   1                   2                   3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |      MBZ      |   Precision   |             Length            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                    Quantization Table Data                    |
+ * |                              ...                              |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+typedef struct
+{
+  guint8 mbz;
+  guint8 precision;
+  guint16 length;
+} RtpQuantHeader;
+
+typedef struct
+{
+  guint8 size;
+  const guint8 *data;
+} RtpQuantTable;
+
+/*
+ * RtpRestartMarkerHeader:
+ * @restartInterval: number of MCUs that appear between restart markers
+ * @restartFirstLastCount: a combination of the first packet mark in the chunk
+ *                         last packet mark in the chunk and the position of the
+ *                         first restart interval in the current "chunk"
+ *
+ *    0                   1                   2                   3
+ *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |       Restart Interval        |F|L|       Restart Count       |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *  The restart marker header is implemented according to the following
+ *  methodology specified in section 3.1.7 of rfc2435.txt.
+ *
+ *  "If the restart intervals in a frame are not guaranteed to be aligned
+ *  with packet boundaries, the F (first) and L (last) bits MUST be set
+ *  to 1 and the Restart Count MUST be set to 0x3FFF.  This indicates
+ *  that a receiver MUST reassemble the entire frame before decoding it."
+ *
+ */
+
+typedef struct
+{
+  guint16 restart_interval;
+  guint16 restart_count;
+} RtpRestartMarkerHeader;
+
+typedef struct
+{
+  guint8 id;
+  guint8 samp;
+  guint8 qt;
+} CompInfo;
+
+/* FIXME: restart marker header currently unsupported */
+
+static void gst_rtp_jpeg_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+
+static void gst_rtp_jpeg_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_rtp_jpeg_pay_setcaps (GstRTPBasePayload * basepayload,
+    GstCaps * caps);
+
+static GstFlowReturn gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * pad,
+    GstBuffer * buffer);
+
+#define gst_rtp_jpeg_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpJPEGPay, gst_rtp_jpeg_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_jpeg_pay_class_init (GstRtpJPEGPayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->set_property = gst_rtp_jpeg_pay_set_property;
+  gobject_class->get_property = gst_rtp_jpeg_pay_get_property;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_jpeg_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_jpeg_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP JPEG payloader",
+      "Codec/Payloader/Network/RTP",
+      "Payload-encodes JPEG pictures into RTP packets (RFC 2435)",
+      "Axis Communications <dev-gstreamer@axis.com>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_jpeg_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_jpeg_pay_handle_buffer;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_JPEG_QUALITY,
+      g_param_spec_int ("quality", "Quality",
+          "Quality factor on JPEG data (unused)", 0, 255, 255,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_JPEG_TYPE,
+      g_param_spec_int ("type", "Type",
+          "Default JPEG Type, overwritten by SOF when present", 0, 255,
+          DEFAULT_JPEG_TYPE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  GST_DEBUG_CATEGORY_INIT (rtpjpegpay_debug, "rtpjpegpay", 0,
+      "Motion JPEG RTP Payloader");
+}
+
+static void
+gst_rtp_jpeg_pay_init (GstRtpJPEGPay * pay)
+{
+  pay->quality = DEFAULT_JPEG_QUALITY;
+  pay->quant = DEFAULT_JPEG_QUANT;
+  pay->type = DEFAULT_JPEG_TYPE;
+  pay->width = -1;
+  pay->height = -1;
+
+  GST_RTP_BASE_PAYLOAD_PT (pay) = GST_RTP_PAYLOAD_JPEG;
+}
+
+static gboolean
+gst_rtp_jpeg_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+  GstStructure *caps_structure = gst_caps_get_structure (caps, 0);
+  GstRtpJPEGPay *pay;
+  gboolean res;
+  gint width = -1, height = -1;
+  gint num = 0, denom;
+  gchar *rate = NULL;
+  gchar *dim = NULL;
+
+  pay = GST_RTP_JPEG_PAY (basepayload);
+
+  /* these properties are mandatory, but they might be adjusted by the SOF, if there
+   * is one. */
+  if (!gst_structure_get_int (caps_structure, "height", &height) || height <= 0) {
+    goto invalid_dimension;
+  }
+
+  if (!gst_structure_get_int (caps_structure, "width", &width) || width <= 0) {
+    goto invalid_dimension;
+  }
+
+  if (gst_structure_get_fraction (caps_structure, "framerate", &num, &denom) &&
+      (num < 0 || denom <= 0)) {
+    goto invalid_framerate;
+  }
+
+  if (height > 2040 || width > 2040) {
+    pay->height = 0;
+    pay->width = 0;
+  } else {
+    pay->height = GST_ROUND_UP_8 (height) / 8;
+    pay->width = GST_ROUND_UP_8 (width) / 8;
+  }
+
+  gst_rtp_base_payload_set_options (basepayload, "video",
+      basepayload->pt != GST_RTP_PAYLOAD_JPEG, "JPEG", 90000);
+
+  if (num > 0) {
+    gdouble framerate;
+    gst_util_fraction_to_double (num, denom, &framerate);
+    rate = g_strdup_printf ("%f", framerate);
+  }
+
+  if (pay->width == 0) {
+    GST_DEBUG_OBJECT (pay,
+        "width or height are greater than 2040, adding x-dimensions to caps");
+    dim = g_strdup_printf ("%d,%d", width, height);
+  }
+
+  if (rate != NULL && dim != NULL) {
+    res = gst_rtp_base_payload_set_outcaps (basepayload, "a-framerate",
+        G_TYPE_STRING, rate, "x-dimensions", G_TYPE_STRING, dim, NULL);
+  } else if (rate != NULL && dim == NULL) {
+    res = gst_rtp_base_payload_set_outcaps (basepayload, "a-framerate",
+        G_TYPE_STRING, rate, NULL);
+  } else if (rate == NULL && dim != NULL) {
+    res = gst_rtp_base_payload_set_outcaps (basepayload, "x-dimensions",
+        G_TYPE_STRING, dim, NULL);
+  } else {
+    res = gst_rtp_base_payload_set_outcaps (basepayload, NULL);
+  }
+
+  g_free (dim);
+  g_free (rate);
+
+  return res;
+
+  /* ERRORS */
+invalid_dimension:
+  {
+    GST_ERROR_OBJECT (pay, "Invalid width/height from caps");
+    return FALSE;
+  }
+invalid_framerate:
+  {
+    GST_ERROR_OBJECT (pay, "Invalid framerate from caps");
+    return FALSE;
+  }
+}
+
+static guint
+gst_rtp_jpeg_pay_header_size (const guint8 * data, guint offset)
+{
+  return data[offset] << 8 | data[offset + 1];
+}
+
+static guint
+gst_rtp_jpeg_pay_read_quant_table (const guint8 * data, guint size,
+    guint offset, RtpQuantTable tables[])
+{
+  guint quant_size, tab_size;
+  guint8 prec;
+  guint8 id;
+
+  if (offset + 2 > size)
+    goto too_small;
+
+  quant_size = gst_rtp_jpeg_pay_header_size (data, offset);
+  if (quant_size < 2)
+    goto small_quant_size;
+
+  /* clamp to available data */
+  if (offset + quant_size > size)
+    quant_size = size - offset;
+
+  offset += 2;
+  quant_size -= 2;
+
+  while (quant_size > 0) {
+    /* not enough to read the id */
+    if (offset + 1 > size)
+      break;
+
+    id = data[offset] & 0x0f;
+    if (id == 15)
+      /* invalid id received - corrupt data */
+      goto invalid_id;
+
+    prec = (data[offset] & 0xf0) >> 4;
+    if (prec)
+      tab_size = 128;
+    else
+      tab_size = 64;
+
+    /* there is not enough for the table */
+    if (quant_size < tab_size + 1)
+      goto no_table;
+
+    GST_LOG ("read quant table %d, tab_size %d, prec %02x", id, tab_size, prec);
+
+    tables[id].size = tab_size;
+    tables[id].data = &data[offset + 1];
+
+    tab_size += 1;
+    quant_size -= tab_size;
+    offset += tab_size;
+  }
+done:
+  return offset + quant_size;
+
+  /* ERRORS */
+too_small:
+  {
+    GST_WARNING ("not enough data");
+    return size;
+  }
+small_quant_size:
+  {
+    GST_WARNING ("quant_size too small (%u < 2)", quant_size);
+    return size;
+  }
+invalid_id:
+  {
+    GST_WARNING ("invalid id");
+    goto done;
+  }
+no_table:
+  {
+    GST_WARNING ("not enough data for table (%u < %u)", quant_size,
+        tab_size + 1);
+    goto done;
+  }
+}
+
+static gboolean
+gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data,
+    guint size, guint * offset, CompInfo info[], RtpQuantTable tables[],
+    gulong tables_elements)
+{
+  guint sof_size, off;
+  guint width, height, infolen;
+  CompInfo elem;
+  gint i, j;
+
+  off = *offset;
+
+  /* we need at least 17 bytes for the SOF */
+  if (off + 17 > size)
+    goto wrong_size;
+
+  sof_size = gst_rtp_jpeg_pay_header_size (data, off);
+  if (sof_size < 17)
+    goto wrong_length;
+
+  *offset += sof_size;
+
+  /* skip size */
+  off += 2;
+
+  /* precision should be 8 */
+  if (data[off++] != 8)
+    goto bad_precision;
+
+  /* read dimensions */
+  height = data[off] << 8 | data[off + 1];
+  width = data[off + 2] << 8 | data[off + 3];
+  off += 4;
+
+  GST_LOG_OBJECT (pay, "got dimensions %ux%u", height, width);
+
+  if (height == 0) {
+    goto invalid_dimension;
+  }
+  if (height > 2040) {
+    height = 0;
+  }
+  if (width == 0) {
+    goto invalid_dimension;
+  }
+  if (width > 2040) {
+    width = 0;
+  }
+
+  if (height == 0 || width == 0) {
+    pay->height = 0;
+    pay->width = 0;
+  } else {
+    pay->height = GST_ROUND_UP_8 (height) / 8;
+    pay->width = GST_ROUND_UP_8 (width) / 8;
+  }
+
+  /* we only support 3 components */
+  if (data[off++] != 3)
+    goto bad_components;
+
+  infolen = 0;
+  for (i = 0; i < 3; i++) {
+    elem.id = data[off++];
+    elem.samp = data[off++];
+    elem.qt = data[off++];
+    GST_LOG_OBJECT (pay, "got comp %d, samp %02x, qt %d", elem.id, elem.samp,
+        elem.qt);
+    /* insertion sort from the last element to the first */
+    for (j = infolen; j > 1; j--) {
+      if (G_LIKELY (info[j - 1].id < elem.id))
+        break;
+      info[j] = info[j - 1];
+    }
+    info[j] = elem;
+    infolen++;
+  }
+
+  /* see that the components are supported */
+  if (info[0].samp == 0x21)
+    pay->type = 0;
+  else if (info[0].samp == 0x22)
+    pay->type = 1;
+  else
+    goto invalid_comp;
+
+  if (!(info[1].samp == 0x11))
+    goto invalid_comp;
+
+  if (!(info[2].samp == 0x11))
+    goto invalid_comp;
+
+  return TRUE;
+
+  /* ERRORS */
+wrong_size:
+  {
+    GST_ELEMENT_WARNING (pay, STREAM, FORMAT,
+        ("Wrong size %u (needed %u).", size, off + 17), (NULL));
+    return FALSE;
+  }
+wrong_length:
+  {
+    GST_ELEMENT_WARNING (pay, STREAM, FORMAT,
+        ("Wrong SOF length %u.", sof_size), (NULL));
+    return FALSE;
+  }
+bad_precision:
+  {
+    GST_ELEMENT_WARNING (pay, STREAM, FORMAT,
+        ("Wrong precision, expecting 8."), (NULL));
+    return FALSE;
+  }
+invalid_dimension:
+  {
+    GST_ELEMENT_WARNING (pay, STREAM, FORMAT,
+        ("Wrong dimension, size %ux%u", width, height), (NULL));
+    return FALSE;
+  }
+bad_components:
+  {
+    GST_ELEMENT_WARNING (pay, STREAM, FORMAT,
+        ("Wrong number of components"), (NULL));
+    return FALSE;
+  }
+invalid_comp:
+  {
+    GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("Invalid component"), (NULL));
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_rtp_jpeg_pay_read_dri (GstRtpJPEGPay * pay, const guint8 * data,
+    guint size, guint * offset, RtpRestartMarkerHeader * dri)
+{
+  guint dri_size, off;
+
+  off = *offset;
+
+  /* we need at least 4 bytes for the DRI */
+  if (off + 4 > size)
+    goto wrong_size;
+
+  dri_size = gst_rtp_jpeg_pay_header_size (data, off);
+  if (dri_size < 4)
+    goto wrong_length;
+
+  *offset += dri_size;
+  off += 2;
+
+  dri->restart_interval = g_htons ((data[off] << 8) | (data[off + 1]));
+  dri->restart_count = g_htons (0xFFFF);
+
+  return dri->restart_interval > 0;
+
+wrong_size:
+  {
+    GST_WARNING ("not enough data for DRI");
+    *offset = size;
+    return FALSE;
+  }
+wrong_length:
+  {
+    GST_WARNING ("DRI size too small (%u)", dri_size);
+    *offset += dri_size;
+    return FALSE;
+  }
+}
+
+static RtpJpegMarker
+gst_rtp_jpeg_pay_scan_marker (const guint8 * data, guint size, guint * offset)
+{
+  while ((data[(*offset)++] != JPEG_MARKER) && ((*offset) < size));
+
+  if (G_UNLIKELY ((*offset) >= size)) {
+    GST_LOG ("found EOI marker");
+    return JPEG_MARKER_EOI;
+  } else {
+    guint8 marker;
+
+    marker = data[*offset];
+    GST_LOG ("found 0x%02x marker at offset %u", marker, *offset);
+    (*offset)++;
+    return marker;
+  }
+}
+
+#define RTP_HEADER_LEN 12
+
+static GstFlowReturn
+gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpJPEGPay *pay;
+  GstClockTime timestamp;
+  GstFlowReturn ret = GST_FLOW_ERROR;
+  RtpJpegHeader jpeg_header;
+  RtpQuantHeader quant_header;
+  RtpRestartMarkerHeader restart_marker_header;
+  RtpQuantTable tables[15] = { {0, NULL}, };
+  CompInfo info[3] = { {0,}, };
+  guint quant_data_size;
+  GstMapInfo map;
+  guint8 *data;
+  gsize size;
+  guint mtu, max_payload_size;
+  guint bytes_left;
+  guint jpeg_header_size = 0;
+  guint offset;
+  gboolean frame_done;
+  gboolean sos_found, sof_found, dqt_found, dri_found;
+  gint i;
+  GstBufferList *list = NULL;
+  gboolean discont;
+
+  pay = GST_RTP_JPEG_PAY (basepayload);
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (pay);
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  data = map.data;
+  size = map.size;
+  timestamp = GST_BUFFER_PTS (buffer);
+  offset = 0;
+  discont = GST_BUFFER_IS_DISCONT (buffer);
+
+  GST_LOG_OBJECT (pay, "got buffer size %" G_GSIZE_FORMAT
+      " , timestamp %" GST_TIME_FORMAT, size, GST_TIME_ARGS (timestamp));
+
+  /* parse the jpeg header for 'start of scan' and read quant tables if needed */
+  sos_found = FALSE;
+  dqt_found = FALSE;
+  sof_found = FALSE;
+  dri_found = FALSE;
+
+  while (!sos_found && (offset < size)) {
+    gint marker;
+
+    GST_LOG_OBJECT (pay, "checking from offset %u", offset);
+    switch ((marker = gst_rtp_jpeg_pay_scan_marker (data, size, &offset))) {
+      case JPEG_MARKER_JFIF:
+      case JPEG_MARKER_CMT:
+      case JPEG_MARKER_DHT:
+      case JPEG_MARKER_H264:
+        GST_LOG_OBJECT (pay, "skipping marker");
+        offset += gst_rtp_jpeg_pay_header_size (data, offset);
+        break;
+      case JPEG_MARKER_SOF:
+        if (!gst_rtp_jpeg_pay_read_sof (pay, data, size, &offset, info, tables,
+                G_N_ELEMENTS (tables)))
+          goto invalid_format;
+        sof_found = TRUE;
+        break;
+      case JPEG_MARKER_DQT:
+        GST_LOG ("DQT found");
+        offset = gst_rtp_jpeg_pay_read_quant_table (data, size, offset, tables);
+        dqt_found = TRUE;
+        break;
+      case JPEG_MARKER_SOS:
+        sos_found = TRUE;
+        GST_LOG_OBJECT (pay, "SOS found");
+        jpeg_header_size = offset + gst_rtp_jpeg_pay_header_size (data, offset);
+        break;
+      case JPEG_MARKER_EOI:
+        GST_WARNING_OBJECT (pay, "EOI reached before SOS!");
+        break;
+      case JPEG_MARKER_SOI:
+        GST_LOG_OBJECT (pay, "SOI found");
+        break;
+      case JPEG_MARKER_DRI:
+        GST_LOG_OBJECT (pay, "DRI found");
+        if (gst_rtp_jpeg_pay_read_dri (pay, data, size, &offset,
+                &restart_marker_header))
+          dri_found = TRUE;
+        break;
+      default:
+        if (marker == JPEG_MARKER_JPG ||
+            (marker >= JPEG_MARKER_JPG0 && marker <= JPEG_MARKER_JPG13) ||
+            (marker >= JPEG_MARKER_APP0 && marker <= JPEG_MARKER_APP15)) {
+          GST_LOG_OBJECT (pay, "skipping marker");
+          offset += gst_rtp_jpeg_pay_header_size (data, offset);
+        } else {
+          GST_FIXME_OBJECT (pay, "unhandled marker 0x%02x", marker);
+        }
+        break;
+    }
+  }
+  if (!dqt_found || !sof_found)
+    goto unsupported_jpeg;
+
+  /* by now we should either have negotiated the width/height or the SOF header
+   * should have filled us in */
+  if (pay->width < 0 || pay->height < 0) {
+    goto no_dimension;
+  }
+
+  GST_LOG_OBJECT (pay, "header size %u", jpeg_header_size);
+
+  size -= jpeg_header_size;
+  data += jpeg_header_size;
+  offset = 0;
+
+  if (dri_found)
+    pay->type += 64;
+
+  /* prepare stuff for the jpeg header */
+  jpeg_header.type_spec = 0;
+  jpeg_header.type = pay->type;
+  jpeg_header.q = pay->quant;
+  jpeg_header.width = pay->width;
+  jpeg_header.height = pay->height;
+
+  /* collect the quant headers sizes */
+  quant_header.mbz = 0;
+  quant_header.precision = 0;
+  quant_header.length = 0;
+  quant_data_size = 0;
+
+  if (pay->quant > 127) {
+    /* for the Y and U component, look up the quant table and its size. quant
+     * tables for U and V should be the same */
+    for (i = 0; i < 2; i++) {
+      guint qsize;
+      guint qt;
+
+      qt = info[i].qt;
+      if (qt >= G_N_ELEMENTS (tables))
+        goto invalid_quant;
+
+      qsize = tables[qt].size;
+      if (qsize == 0)
+        goto invalid_quant;
+
+      quant_header.precision |= (qsize == 64 ? 0 : (1 << i));
+      quant_data_size += qsize;
+    }
+    quant_header.length = g_htons (quant_data_size);
+    quant_data_size += sizeof (quant_header);
+  }
+
+  GST_LOG_OBJECT (pay, "quant_data size %u", quant_data_size);
+
+  bytes_left = sizeof (jpeg_header) + quant_data_size + size;
+
+  if (dri_found)
+    bytes_left += sizeof (restart_marker_header);
+
+  max_payload_size = mtu - (RTP_HEADER_LEN + sizeof (jpeg_header));
+  list = gst_buffer_list_new_sized ((bytes_left / max_payload_size) + 1);
+
+  frame_done = FALSE;
+  do {
+    GstBuffer *outbuf;
+    guint8 *payload;
+    guint payload_size;
+    guint header_size;
+    GstBuffer *paybuf;
+    GstRTPBuffer rtp = { NULL };
+    guint rtp_header_size = gst_rtp_buffer_calc_header_len (0);
+
+    /* The available room is the packet MTU, minus the RTP header length. */
+    payload_size =
+        (bytes_left < (mtu - rtp_header_size) ? bytes_left :
+        (mtu - rtp_header_size));
+
+    header_size = sizeof (jpeg_header) + quant_data_size;
+    if (dri_found)
+      header_size += sizeof (restart_marker_header);
+
+    outbuf = gst_rtp_buffer_new_allocate (header_size, 0, 0);
+
+    gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+    if (payload_size == bytes_left) {
+      GST_LOG_OBJECT (pay, "last packet of frame");
+      frame_done = TRUE;
+      gst_rtp_buffer_set_marker (&rtp, 1);
+    }
+
+    payload = gst_rtp_buffer_get_payload (&rtp);
+
+    /* update offset */
+#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
+    jpeg_header.offset = ((offset & 0x0000FF) << 16) |
+        ((offset & 0xFF0000) >> 16) | (offset & 0x00FF00);
+#else
+    jpeg_header.offset = offset;
+#endif
+    memcpy (payload, &jpeg_header, sizeof (jpeg_header));
+    payload += sizeof (jpeg_header);
+    payload_size -= sizeof (jpeg_header);
+
+    if (dri_found) {
+      memcpy (payload, &restart_marker_header, sizeof (restart_marker_header));
+      payload += sizeof (restart_marker_header);
+      payload_size -= sizeof (restart_marker_header);
+    }
+
+    /* only send quant table with first packet */
+    if (G_UNLIKELY (quant_data_size > 0)) {
+      memcpy (payload, &quant_header, sizeof (quant_header));
+      payload += sizeof (quant_header);
+
+      /* copy the quant tables for luma and chrominance */
+      for (i = 0; i < 2; i++) {
+        guint qsize;
+        guint qt;
+
+        qt = info[i].qt;
+        qsize = tables[qt].size;
+        memcpy (payload, tables[qt].data, qsize);
+
+        GST_LOG_OBJECT (pay, "component %d using quant %d, size %d", i, qt,
+            qsize);
+
+        payload += qsize;
+      }
+      payload_size -= quant_data_size;
+      bytes_left -= quant_data_size;
+      quant_data_size = 0;
+    }
+    GST_LOG_OBJECT (pay, "sending payload size %d", payload_size);
+    gst_rtp_buffer_unmap (&rtp);
+
+    /* create a new buf to hold the payload */
+    paybuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL,
+        jpeg_header_size + offset, payload_size);
+
+    /* join memory parts */
+    gst_rtp_copy_video_meta (pay, outbuf, paybuf);
+    outbuf = gst_buffer_append (outbuf, paybuf);
+
+    GST_BUFFER_PTS (outbuf) = timestamp;
+
+    if (discont) {
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+      /* Only the first outputted buffer has the DISCONT flag */
+      discont = FALSE;
+    }
+
+    /* and add to list */
+    gst_buffer_list_insert (list, -1, outbuf);
+
+    bytes_left -= payload_size;
+    offset += payload_size;
+    data += payload_size;
+  }
+  while (!frame_done);
+
+  /* push the whole buffer list at once */
+  ret = gst_rtp_base_payload_push_list (basepayload, list);
+
+  gst_buffer_unmap (buffer, &map);
+  gst_buffer_unref (buffer);
+
+  return ret;
+
+  /* ERRORS */
+unsupported_jpeg:
+  {
+    GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("Unsupported JPEG"), (NULL));
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+    return GST_FLOW_OK;
+  }
+no_dimension:
+  {
+    GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("No size given"), (NULL));
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+    return GST_FLOW_OK;
+  }
+invalid_format:
+  {
+    /* error was posted */
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+    return GST_FLOW_OK;
+  }
+invalid_quant:
+  {
+    GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("Invalid quant tables"), (NULL));
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+    return GST_FLOW_OK;
+  }
+}
+
+static void
+gst_rtp_jpeg_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpJPEGPay *rtpjpegpay;
+
+  rtpjpegpay = GST_RTP_JPEG_PAY (object);
+
+  switch (prop_id) {
+    case PROP_JPEG_QUALITY:
+      rtpjpegpay->quality = g_value_get_int (value);
+      GST_DEBUG_OBJECT (object, "quality = %d", rtpjpegpay->quality);
+      break;
+    case PROP_JPEG_TYPE:
+      rtpjpegpay->type = g_value_get_int (value);
+      GST_DEBUG_OBJECT (object, "type = %d", rtpjpegpay->type);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_jpeg_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpJPEGPay *rtpjpegpay;
+
+  rtpjpegpay = GST_RTP_JPEG_PAY (object);
+
+  switch (prop_id) {
+    case PROP_JPEG_QUALITY:
+      g_value_set_int (value, rtpjpegpay->quality);
+      break;
+    case PROP_JPEG_TYPE:
+      g_value_set_int (value, rtpjpegpay->type);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+gboolean
+gst_rtp_jpeg_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpjpegpay", GST_RANK_SECONDARY,
+      GST_TYPE_RTP_JPEG_PAY);
+}
diff --git a/gst/rtp/gstrtpjpegpay.h b/gst/rtp/gstrtpjpegpay.h
new file mode 100644
index 0000000..4d65ea7
--- /dev/null
+++ b/gst/rtp/gstrtpjpegpay.h
@@ -0,0 +1,63 @@
+/* GStreamer
+ * Copyright (C) 2008 Axis Communications <dev-gstreamer@axis.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_JPEG_PAY_H__
+#define __GST_RTP_JPEG_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_JPEG_PAY \
+  (gst_rtp_jpeg_pay_get_type())
+#define GST_RTP_JPEG_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_JPEG_PAY,GstRtpJPEGPay))
+#define GST_RTP_JPEG_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_JPEG_PAY,GstRtpJPEGPayClass))
+#define GST_IS_RTP_JPEG_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_JPEG_PAY))
+#define GST_IS_RTP_JPEG_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_JPEG_PAY))
+typedef struct _GstRtpJPEGPay GstRtpJPEGPay;
+typedef struct _GstRtpJPEGPayClass GstRtpJPEGPayClass;
+
+struct _GstRtpJPEGPay
+{
+  GstRTPBasePayload payload;
+
+  guint8 quality;
+  guint8 type;
+
+  gint height;
+  gint width;
+
+  guint8 quant;
+};
+
+struct _GstRtpJPEGPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_jpeg_pay_get_type (void);
+
+gboolean gst_rtp_jpeg_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_JPEG_PAY_H__ */
diff --git a/gst/rtp/gstrtpklvdepay.c b/gst/rtp/gstrtpklvdepay.c
new file mode 100644
index 0000000..424f6aa
--- /dev/null
+++ b/gst/rtp/gstrtpklvdepay.c
@@ -0,0 +1,397 @@
+/* GStreamer RTP KLV Depayloader
+ * Copyright (C) 2014-2015 Tim-Philipp Müller <tim@centricular.com>>
+ * Copyright (C) 2014-2015 Centricular Ltd
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpklvdepay
+ * @see_also: rtpklvpay
+ *
+ * Extract KLV metadata from RTP packets according to RFC 6597.
+ * For detailed information see: http://tools.ietf.org/html/rfc6597
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 udpsrc caps='application/x-rtp, media=(string)application, clock-rate=(int)90000, encoding-name=(string)SMPTE336M' ! rtpklvdepay ! fakesink dump=true
+ * ]| This example pipeline will depayload an RTP KLV stream and display
+ * a hexdump of the KLV data on stdout.
+ * </refsect2>
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstrtpklvdepay.h"
+
+#include <string.h>
+
+GST_DEBUG_CATEGORY_STATIC (klvdepay_debug);
+#define GST_CAT_DEFAULT (klvdepay_debug)
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("meta/x-klv, parsed = (bool) true"));
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) application, clock-rate = (int) [1, MAX], "
+        "encoding-name = (string) SMPTE336M")
+    );
+
+#define gst_rtp_klv_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpKlvDepay, gst_rtp_klv_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_klv_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_klv_depay_change_state (GstElement *
+    element, GstStateChange transition);
+static gboolean gst_rtp_klv_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_klv_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+static gboolean gst_rtp_klv_depay_handle_event (GstRTPBaseDepayload * depay,
+    GstEvent * ev);
+
+static void gst_rtp_klv_depay_reset (GstRtpKlvDepay * klvdepay);
+
+static void
+gst_rtp_klv_depay_class_init (GstRtpKlvDepayClass * klass)
+{
+  GstElementClass *element_class = (GstElementClass *) klass;
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstRTPBaseDepayloadClass *rtpbasedepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (klvdepay_debug, "klvdepay", 0,
+      "RTP KLV Depayloader");
+
+  gobject_class->finalize = gst_rtp_klv_depay_finalize;
+
+  element_class->change_state = gst_rtp_klv_depay_change_state;
+
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "RTP KLV Depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts KLV (SMPTE ST 336) metadata from RTP packets",
+      "Tim-Philipp Müller <tim@centricular.com>");
+
+  rtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  rtpbasedepayload_class->set_caps = gst_rtp_klv_depay_setcaps;
+  rtpbasedepayload_class->process_rtp_packet = gst_rtp_klv_depay_process;
+  rtpbasedepayload_class->handle_event = gst_rtp_klv_depay_handle_event;
+}
+
+static void
+gst_rtp_klv_depay_init (GstRtpKlvDepay * klvdepay)
+{
+  klvdepay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_klv_depay_finalize (GObject * object)
+{
+  GstRtpKlvDepay *klvdepay;
+
+  klvdepay = GST_RTP_KLV_DEPAY (object);
+
+  gst_rtp_klv_depay_reset (klvdepay);
+  g_object_unref (klvdepay->adapter);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_klv_depay_reset (GstRtpKlvDepay * klvdepay)
+{
+  GST_DEBUG_OBJECT (klvdepay, "resetting");
+  gst_adapter_clear (klvdepay->adapter);
+  klvdepay->resync = TRUE;
+  klvdepay->last_rtp_ts = -1;
+}
+
+static gboolean
+gst_rtp_klv_depay_handle_event (GstRTPBaseDepayload * depay, GstEvent * ev)
+{
+  switch (GST_EVENT_TYPE (ev)) {
+    case GST_EVENT_STREAM_START:{
+      GstStreamFlags flags;
+
+      ev = gst_event_make_writable (ev);
+      gst_event_parse_stream_flags (ev, &flags);
+      gst_event_set_stream_flags (ev, flags | GST_STREAM_FLAG_SPARSE);
+      break;
+    }
+    default:
+      break;
+  }
+
+  return GST_RTP_BASE_DEPAYLOAD_CLASS (parent_class)->handle_event (depay, ev);
+}
+
+static gboolean
+gst_rtp_klv_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *s;
+  GstCaps *src_caps;
+  gboolean res;
+  gint clock_rate;
+
+  s = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (s, "clock-rate", &clock_rate))
+    return FALSE;
+
+  depayload->clock_rate = clock_rate;
+
+  src_caps = gst_static_pad_template_get_caps (&src_template);
+  res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), src_caps);
+  gst_caps_unref (src_caps);
+
+  return res;
+}
+
+static gboolean
+klv_get_vlen (const guint8 * data, guint data_len, guint64 * v_len,
+    gsize * len_size)
+{
+  guint8 first_byte, len_len;
+  guint64 len;
+
+  g_assert (data_len > 0);
+
+  first_byte = *data++;
+
+  if ((first_byte & 0x80) == 0) {
+    *v_len = first_byte & 0x7f;
+    *len_size = 1;
+    return TRUE;
+  }
+
+  len_len = first_byte & 0x7f;
+
+  if (len_len == 0 || len_len > 8)
+    return FALSE;
+
+  if ((1 + len_len) > data_len)
+    return FALSE;
+
+  *len_size = 1 + len_len;
+
+  len = 0;
+  while (len_len > 0) {
+    len = len << 8 | *data++;
+    --len_len;
+  }
+
+  *v_len = len;
+
+  return TRUE;
+}
+
+static GstBuffer *
+gst_rtp_klv_depay_process_data (GstRtpKlvDepay * klvdepay)
+{
+  gsize avail, data_len, len_size;
+  GstBuffer *outbuf;
+  guint8 data[1 + 8];
+  guint64 v_len;
+
+  avail = gst_adapter_available (klvdepay->adapter);
+
+  GST_TRACE_OBJECT (klvdepay, "%" G_GSIZE_FORMAT " bytes in adapter", avail);
+
+  if (avail == 0)
+    return NULL;
+
+  /* need at least 16 bytes of UL key plus 1 byte of length */
+  if (avail < 16 + 1)
+    goto bad_klv_packet;
+
+  /* check if the declared KLV unit size matches actual bytes available */
+  data_len = MIN (avail - 16, 1 + 8);
+  gst_adapter_copy (klvdepay->adapter, data, 16, data_len);
+  if (!klv_get_vlen (data, data_len, &v_len, &len_size))
+    goto bad_klv_packet;
+
+  GST_LOG_OBJECT (klvdepay, "want %" G_GUINT64_FORMAT " bytes, "
+      "have %" G_GSIZE_FORMAT " bytes", 16 + len_size + v_len, avail);
+
+  if (avail < 16 + len_size + v_len)
+    goto incomplete_klv_packet;
+
+  /* something is wrong, this shouldn't ever happen */
+  if (avail > 16 + len_size + v_len)
+    goto bad_klv_packet;
+
+  outbuf = gst_adapter_take_buffer (klvdepay->adapter, avail);
+
+  /* Mark buffers as key unit to signal this is the start of a KLV unit
+   * (for now all buffers will be flagged like this, since all buffers are
+   * self-contained KLV units, but in future that might change) */
+  outbuf = gst_buffer_make_writable (outbuf);
+  GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+  return outbuf;
+
+/* ERRORS */
+bad_klv_packet:
+  {
+    GST_WARNING_OBJECT (klvdepay, "bad KLV packet, dropping");
+    gst_rtp_klv_depay_reset (klvdepay);
+    return NULL;
+  }
+incomplete_klv_packet:
+  {
+    GST_DEBUG_OBJECT (klvdepay, "partial KLV packet: have %u bytes, want %u",
+        (guint) avail, (guint) (16 + len_size + v_len));
+    return NULL;
+  }
+}
+
+/* We're trying to be pragmatic here, not quite as strict as the spec wants
+ * us to be with regard to marker bits and resyncing after packet loss */
+static GstBuffer *
+gst_rtp_klv_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpKlvDepay *klvdepay = GST_RTP_KLV_DEPAY (depayload);
+  GstBuffer *payload, *outbuf = NULL;
+  gboolean marker, start = FALSE, maybe_start;
+  guint32 rtp_ts;
+  guint16 seq;
+  guint payload_len;
+
+  /* Ignore DISCONT on first buffer and on buffers following a discont */
+  if (GST_BUFFER_IS_DISCONT (rtp->buffer) && klvdepay->last_rtp_ts != -1) {
+    GST_WARNING_OBJECT (klvdepay, "DISCONT, need to resync");
+    gst_rtp_klv_depay_reset (klvdepay);
+  }
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  /* marker bit signals last fragment of a KLV unit */
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  seq = gst_rtp_buffer_get_seq (rtp);
+
+  /* packet directly after one with marker bit set => start */
+  start = klvdepay->last_marker_seq != -1
+      && gst_rtp_buffer_compare_seqnum (klvdepay->last_marker_seq, seq) == 1;
+
+  /* deduce start of new KLV unit in case sender doesn't set marker bits
+   * (it's not like the spec is ambiguous about that, but what can you do) */
+  rtp_ts = gst_rtp_buffer_get_timestamp (rtp);
+
+  maybe_start = klvdepay->last_rtp_ts == -1 || klvdepay->last_rtp_ts != rtp_ts;
+
+  klvdepay->last_rtp_ts = rtp_ts;
+
+  /* fallback to detect self-contained single KLV unit (usual case) */
+  if ((!start || !marker || maybe_start) && payload_len > 16) {
+    const guint8 *data;
+    guint64 v_len;
+    gsize len_size;
+
+    data = gst_rtp_buffer_get_payload (rtp);
+    if (GST_READ_UINT32_BE (data) == 0x060e2b34 &&
+        klv_get_vlen (data + 16, payload_len - 16, &v_len, &len_size)) {
+      if (16 + len_size + v_len == payload_len) {
+        GST_LOG_OBJECT (klvdepay, "Looks like a self-contained KLV unit");
+        marker = TRUE;
+        start = TRUE;
+      } else if (16 + len_size + v_len > payload_len) {
+        GST_LOG_OBJECT (klvdepay,
+            "Looks like the start of a fragmented KLV unit");
+        start = TRUE;
+      }
+    }
+  }
+
+  /* If this is the first packet and looks like a start, clear resync flag */
+  if (klvdepay->resync && klvdepay->last_marker_seq == -1 && start)
+    klvdepay->resync = FALSE;
+
+  if (marker)
+    klvdepay->last_marker_seq = seq;
+
+  GST_LOG_OBJECT (klvdepay, "payload of %u bytes, marker=%d, start=%d",
+      payload_len, marker, start);
+
+  if (klvdepay->resync && !start) {
+    GST_DEBUG_OBJECT (klvdepay, "Dropping buffer, waiting to resync");
+
+    if (marker)
+      klvdepay->resync = FALSE;
+
+    goto done;
+  }
+
+  if (start && !marker)
+    outbuf = gst_rtp_klv_depay_process_data (klvdepay);
+
+  payload = gst_rtp_buffer_get_payload_buffer (rtp);
+  gst_adapter_push (klvdepay->adapter, payload);
+
+  if (marker)
+    outbuf = gst_rtp_klv_depay_process_data (klvdepay);
+
+done:
+
+  return outbuf;
+}
+
+static GstStateChangeReturn
+gst_rtp_klv_depay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRtpKlvDepay *klvdepay;
+  GstStateChangeReturn ret;
+
+  klvdepay = GST_RTP_KLV_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_klv_depay_reset (klvdepay);
+      klvdepay->last_marker_seq = -1;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_klv_depay_reset (klvdepay);
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_klv_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpklvdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_KLV_DEPAY);
+}
diff --git a/gst/rtp/gstrtpklvdepay.h b/gst/rtp/gstrtpklvdepay.h
new file mode 100644
index 0000000..71a256d
--- /dev/null
+++ b/gst/rtp/gstrtpklvdepay.h
@@ -0,0 +1,65 @@
+/* GStreamer RTP KLV Depayloader
+ * Copyright (C) 2014-2015 Tim-Philipp Müller <tim@centricular.com>>
+ * Copyright (C) 2014-2015 Centricular Ltd
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_KLV_DEPAY_H__
+#define __GST_RTP_KLV_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_KLV_DEPAY \
+  (gst_rtp_klv_depay_get_type())
+#define GST_RTP_KLV_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_KLV_DEPAY,GstRtpKlvDepay))
+#define GST_RTP_KLV_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_KLV_DEPAY,GstRtpKlvDepayClass))
+#define GST_IS_RTP_KLV_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_KLV_DEPAY))
+#define GST_IS_RTP_KLV_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_KLV_DEPAY))
+
+typedef struct _GstRtpKlvDepay GstRtpKlvDepay;
+typedef struct _GstRtpKlvDepayClass GstRtpKlvDepayClass;
+
+struct _GstRtpKlvDepay
+{
+  GstRTPBaseDepayload depayload;
+
+  GstAdapter *adapter;
+  gboolean    resync;
+  gint        last_marker_seq;   /* -1 if unset, otherwise 0-G_MAXUINT16 */
+  gint64      last_rtp_ts;       /* -1 if unset, otherwise 0-G_MAXUINT32 */
+};
+
+struct _GstRtpKlvDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+G_GNUC_INTERNAL GType     gst_rtp_klv_depay_get_type (void);
+
+G_GNUC_INTERNAL gboolean  gst_rtp_klv_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_KLV_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpklvpay.c b/gst/rtp/gstrtpklvpay.c
new file mode 100644
index 0000000..5a07d2c
--- /dev/null
+++ b/gst/rtp/gstrtpklvpay.c
@@ -0,0 +1,204 @@
+/* GStreamer RTP KLV Payloader
+ * Copyright (C) 2014-2015 Tim-Philipp Müller <tim@centricular.com>>
+ * Copyright (C) 2014-2015 Centricular Ltd
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpklvpay
+ * @see_also: rtpklvdepay
+ *
+ * Payloads KLV metadata into RTP packets according to RFC 6597.
+ * For detailed information see: http://tools.ietf.org/html/rfc6597
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 filesrc location=video-with-klv.ts ! tsdemux ! rtpklvpay ! udpsink
+ * ]| This example pipeline will payload an RTP KLV stream extracted from an
+ * MPEG-TS stream and send it via UDP to an RTP receiver.
+ * </refsect2>
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstrtpklvpay.h"
+#include "gstrtputils.h"
+
+#include <string.h>
+
+GST_DEBUG_CATEGORY_STATIC (klvpay_debug);
+#define GST_CAT_DEFAULT (klvpay_debug)
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) application, clock-rate = (int) [1, MAX], "
+        "encoding-name = (string) SMPTE336M")
+    );
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("meta/x-klv, parsed = (bool) true"));
+
+#define gst_rtp_klv_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpKlvPay, gst_rtp_klv_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static gboolean gst_rtp_klv_pay_setcaps (GstRTPBasePayload * pay,
+    GstCaps * caps);
+static GstFlowReturn gst_rtp_klv_pay_handle_buffer (GstRTPBasePayload * pay,
+    GstBuffer * buf);
+
+static void
+gst_rtp_klv_pay_class_init (GstRtpKlvPayClass * klass)
+{
+  GstElementClass *element_class = (GstElementClass *) klass;
+  GstRTPBasePayloadClass *rtpbasepay_class;
+
+  GST_DEBUG_CATEGORY_INIT (klvpay_debug, "klvpay", 0, "RTP KLV Payloader");
+
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "RTP KLV Payloader", "Codec/Payloader/Network/RTP",
+      "Payloads KLV (SMPTE ST 336) metadata as RTP packets",
+      "Tim-Philipp Müller <tim@centricular.com>");
+
+  rtpbasepay_class = (GstRTPBasePayloadClass *) klass;
+
+  rtpbasepay_class->set_caps = gst_rtp_klv_pay_setcaps;
+  rtpbasepay_class->handle_buffer = gst_rtp_klv_pay_handle_buffer;
+}
+
+static void
+gst_rtp_klv_pay_init (GstRtpKlvPay * klvpay)
+{
+  /* nothing to do here yet */
+}
+
+static gboolean
+gst_rtp_klv_pay_setcaps (GstRTPBasePayload * pay, GstCaps * caps)
+{
+  /* FIXME: allow other clock rates */
+  gst_rtp_base_payload_set_options (pay, "application", TRUE, "SMPTE336M",
+      90000);
+
+  return gst_rtp_base_payload_set_outcaps (pay, NULL);
+}
+
+static GstFlowReturn
+gst_rtp_klv_pay_handle_buffer (GstRTPBasePayload * basepayload, GstBuffer * buf)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBufferList *list = NULL;
+  GstRtpKlvPay *pay;
+  GstMapInfo map;
+  GstBuffer *outbuf = NULL;
+  gsize offset;
+  guint mtu, rtp_header_size, max_payload_size;
+
+  pay = GST_RTP_KLV_PAY (basepayload);
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (basepayload);
+
+  rtp_header_size = gst_rtp_buffer_calc_header_len (0);
+  max_payload_size = mtu - rtp_header_size;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  if (map.size == 0)
+    goto done;
+
+  /* KLV coding shall use and only use a fixed 16-byte SMPTE-administered
+   * Universal Label, according to SMPTE 298M as Key (Rec. ITU R-BT.1653-1) */
+  if (map.size < 16 || GST_READ_UINT32_BE (map.data) != 0x060E2B34)
+    goto bad_input;
+
+  if (map.size > max_payload_size)
+    list = gst_buffer_list_new ();
+
+  GST_LOG_OBJECT (pay, "%" G_GSIZE_FORMAT " bytes of data to payload",
+      map.size);
+
+  offset = 0;
+  while (offset < map.size) {
+    GstBuffer *payloadbuf;
+    GstRTPBuffer rtp = { NULL };
+    guint payload_size;
+    guint bytes_left;
+
+    bytes_left = map.size - offset;
+    payload_size = MIN (bytes_left, max_payload_size);
+
+    outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+
+    if (payload_size == bytes_left) {
+      GST_LOG_OBJECT (pay, "last packet of KLV unit");
+      gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+      gst_rtp_buffer_set_marker (&rtp, 1);
+      gst_rtp_buffer_unmap (&rtp);
+    }
+
+    GST_LOG_OBJECT (pay, "packet with payload size %u", payload_size);
+
+    gst_rtp_copy_meta (GST_ELEMENT_CAST (pay), outbuf, buf, 0);
+
+    payloadbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_MEMORY,
+        offset, payload_size);
+
+    /* join rtp header + payload memory parts */
+    outbuf = gst_buffer_append (outbuf, payloadbuf);
+
+    GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buf);
+    GST_BUFFER_DTS (outbuf) = GST_BUFFER_DTS (buf);
+
+    /* and add to list */
+    if (list != NULL)
+      gst_buffer_list_insert (list, -1, outbuf);
+
+    offset += payload_size;
+  }
+
+done:
+
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+
+  if (list != NULL)
+    ret = gst_rtp_base_payload_push_list (basepayload, list);
+  else if (outbuf != NULL)
+    ret = gst_rtp_base_payload_push (basepayload, outbuf);
+
+  return ret;
+
+/* ERRORS */
+bad_input:
+  {
+    GST_ERROR_OBJECT (pay, "Input doesn't look like a KLV packet, ignoring");
+    goto done;
+  }
+}
+
+gboolean
+gst_rtp_klv_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpklvpay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_KLV_PAY);
+}
diff --git a/gst/rtp/gstrtpklvpay.h b/gst/rtp/gstrtpklvpay.h
new file mode 100644
index 0000000..9ee8134
--- /dev/null
+++ b/gst/rtp/gstrtpklvpay.h
@@ -0,0 +1,60 @@
+/* GStreamer RTP KLV Payloader
+ * Copyright (C) 2014-2015 Tim-Philipp Müller <tim@centricular.com>>
+ * Copyright (C) 2014-2015 Centricular Ltd
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_KLV_PAY_H__
+#define __GST_RTP_KLV_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/rtp.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_KLV_PAY \
+  (gst_rtp_klv_pay_get_type())
+#define GST_RTP_KLV_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_KLV_PAY,GstRtpKlvPay))
+#define GST_RTP_KLV_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_KLV_PAY,GstRtpKlvPayClass))
+#define GST_IS_RTP_KLV_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_KLV_PAY))
+#define GST_IS_RTP_KLV_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_KLV_PAY))
+
+typedef struct _GstRtpKlvPay GstRtpKlvPay;
+typedef struct _GstRtpKlvPayClass GstRtpKlvPayClass;
+
+struct _GstRtpKlvPay
+{
+  GstRTPBasePayload rtpbasepayload;
+};
+
+struct _GstRtpKlvPayClass
+{
+  GstRTPBasePayloadClass rtpbasepayload_class;
+};
+
+G_GNUC_INTERNAL  GType     gst_rtp_klv_pay_get_type (void);
+
+G_GNUC_INTERNAL  gboolean  gst_rtp_klv_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_KLV_PAY_H__ */
diff --git a/gst/rtp/gstrtpmp1sdepay.c b/gst/rtp/gstrtpmp1sdepay.c
new file mode 100644
index 0000000..31a3108
--- /dev/null
+++ b/gst/rtp/gstrtpmp1sdepay.c
@@ -0,0 +1,143 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <string.h>
+#include "gstrtpmp1sdepay.h"
+#include "gstrtputils.h"
+
+/* RtpMP1SDepay signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_LAST
+};
+
+static GstStaticPadTemplate gst_rtp_mp1s_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/mpeg,systemstream=(boolean)true")
+    );
+
+/* The spec says video/MP1S but I have seen streams with other/MP1S so we will
+ * allow them both */
+static GstStaticPadTemplate gst_rtp_mp1s_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"other\", "
+        "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP1S\";"
+        "application/x-rtp, "
+        "media = (string) \"video\", "
+        "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP1S\"")
+    );
+
+G_DEFINE_TYPE (GstRtpMP1SDepay, gst_rtp_mp1s_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_mp1s_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_mp1s_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+static void
+gst_rtp_mp1s_depay_class_init (GstRtpMP1SDepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_mp1s_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_mp1s_depay_setcaps;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp1s_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp1s_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP MPEG1 System Stream depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts MPEG1 System Streams from RTP packets (RFC 3555)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+}
+
+static void
+gst_rtp_mp1s_depay_init (GstRtpMP1SDepay * rtpmp1sdepay)
+{
+}
+
+static gboolean
+gst_rtp_mp1s_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstCaps *srccaps;
+  GstStructure *structure;
+  gint clock_rate;
+  gboolean res;
+
+  structure = gst_caps_get_structure (caps, 0);
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;         /* default */
+  depayload->clock_rate = clock_rate;
+
+  srccaps = gst_caps_new_simple ("video/mpeg",
+      "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
+  res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+  gst_caps_unref (srccaps);
+
+  return res;
+}
+
+static GstBuffer *
+gst_rtp_mp1s_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstBuffer *outbuf;
+
+  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);
+
+  if (outbuf) {
+    GST_DEBUG ("gst_rtp_mp1s_depay_chain: pushing buffer of size %"
+        G_GSIZE_FORMAT, gst_buffer_get_size (outbuf));
+
+    gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload), outbuf, 0);
+  }
+
+  return outbuf;
+}
+
+gboolean
+gst_rtp_mp1s_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpmp1sdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_MP1S_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmp1sdepay.h b/gst/rtp/gstrtpmp1sdepay.h
new file mode 100644
index 0000000..582933b
--- /dev/null
+++ b/gst/rtp/gstrtpmp1sdepay.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP1S_DEPAY_H__
+#define __GST_RTP_MP1S_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP1S_DEPAY \
+  (gst_rtp_mp1s_depay_get_type())
+#define GST_RTP_MP1S_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP1S_DEPAY,GstRtpMP1SDepay))
+#define GST_RTP_MP1S_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP1S_DEPAY,GstRtpMP1SDepayClass))
+#define GST_IS_RTP_MP1S_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP1S_DEPAY))
+#define GST_IS_RTP_MP1S_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP1S_DEPAY))
+typedef struct _GstRtpMP1SDepay GstRtpMP1SDepay;
+typedef struct _GstRtpMP1SDepayClass GstRtpMP1SDepayClass;
+
+struct _GstRtpMP1SDepay
+{
+  GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpMP1SDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mp1s_depay_get_type (void);
+
+gboolean gst_rtp_mp1s_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP1S_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpmp2tdepay.c b/gst/rtp/gstrtpmp2tdepay.c
new file mode 100644
index 0000000..f8e0d0c
--- /dev/null
+++ b/gst/rtp/gstrtpmp2tdepay.c
@@ -0,0 +1,243 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <string.h>
+#include "gstrtpmp2tdepay.h"
+#include "gstrtputils.h"
+
+/* RtpMP2TDepay signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+#define DEFAULT_SKIP_FIRST_BYTES	0
+
+enum
+{
+  PROP_0,
+  PROP_SKIP_FIRST_BYTES
+};
+
+static GstStaticPadTemplate gst_rtp_mp2t_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/mpegts,"
+        "packetsize=(int)188," "systemstream=(boolean)true")
+    );
+
+static GstStaticPadTemplate gst_rtp_mp2t_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "clock-rate = (int) [1, MAX ], "
+        "encoding-name = (string) { MP2T, MP2T-ES } ;"
+        /* All optional parameters
+         *
+         * "profile-level-id=[1,MAX]"
+         * "config=" 
+         */
+        "application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_MP2T_STRING ", "
+        "clock-rate = (int) [1, MAX ]")
+    );
+
+G_DEFINE_TYPE (GstRtpMP2TDepay, gst_rtp_mp2t_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_mp2t_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_mp2t_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+static void gst_rtp_mp2t_depay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_mp2t_depay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void
+gst_rtp_mp2t_depay_class_init (GstRtpMP2TDepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_mp2t_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_mp2t_depay_setcaps;
+
+  gobject_class->set_property = gst_rtp_mp2t_depay_set_property;
+  gobject_class->get_property = gst_rtp_mp2t_depay_get_property;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp2t_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp2t_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP MPEG Transport Stream depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts MPEG2 TS from RTP packets (RFC 2250)",
+      "Wim Taymans <wim.taymans@gmail.com>, "
+      "Thijs Vermeir <thijs.vermeir@barco.com>");
+
+  g_object_class_install_property (gobject_class, PROP_SKIP_FIRST_BYTES,
+      g_param_spec_uint ("skip-first-bytes",
+          "Skip first bytes",
+          "The amount of bytes that need to be skipped at the beginning of the payload",
+          0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+}
+
+static void
+gst_rtp_mp2t_depay_init (GstRtpMP2TDepay * rtpmp2tdepay)
+{
+  rtpmp2tdepay->skip_first_bytes = DEFAULT_SKIP_FIRST_BYTES;
+}
+
+static gboolean
+gst_rtp_mp2t_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstCaps *srccaps;
+  GstStructure *structure;
+  gint clock_rate;
+  gboolean res;
+
+  structure = gst_caps_get_structure (caps, 0);
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;         /* default */
+  depayload->clock_rate = clock_rate;
+
+  srccaps = gst_caps_new_simple ("video/mpegts",
+      "packetsize", G_TYPE_INT, 188,
+      "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
+  res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+  gst_caps_unref (srccaps);
+
+  return res;
+}
+
+static GstBuffer *
+gst_rtp_mp2t_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpMP2TDepay *rtpmp2tdepay;
+  GstBuffer *outbuf;
+  gint payload_len, leftover;
+
+  rtpmp2tdepay = GST_RTP_MP2T_DEPAY (depayload);
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  if (G_UNLIKELY (payload_len <= rtpmp2tdepay->skip_first_bytes))
+    goto empty_packet;
+
+  payload_len -= rtpmp2tdepay->skip_first_bytes;
+
+  /* RFC 2250
+   *
+   * 2. Encapsulation of MPEG System and Transport Streams
+   *
+   * For MPEG2 Transport Streams the RTP payload will contain an integral
+   * number of MPEG transport packets.
+   */
+  leftover = payload_len % 188;
+  if (G_UNLIKELY (leftover)) {
+    GST_WARNING ("We don't have an integral number of buffers (leftover: %d)",
+        leftover);
+
+    payload_len -= leftover;
+  }
+
+  outbuf =
+      gst_rtp_buffer_get_payload_subbuffer (rtp,
+      rtpmp2tdepay->skip_first_bytes, payload_len);
+
+  if (outbuf) {
+    GST_DEBUG ("gst_rtp_mp2t_depay_chain: pushing buffer of size %"
+        G_GSIZE_FORMAT, gst_buffer_get_size (outbuf));
+
+    gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload), outbuf, 0);
+  }
+
+  return outbuf;
+
+  /* ERRORS */
+empty_packet:
+  {
+    GST_ELEMENT_WARNING (rtpmp2tdepay, STREAM, DECODE,
+        (NULL), ("Packet was empty"));
+    return NULL;
+  }
+}
+
+static void
+gst_rtp_mp2t_depay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpMP2TDepay *rtpmp2tdepay;
+
+  rtpmp2tdepay = GST_RTP_MP2T_DEPAY (object);
+
+  switch (prop_id) {
+    case PROP_SKIP_FIRST_BYTES:
+      rtpmp2tdepay->skip_first_bytes = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_mp2t_depay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpMP2TDepay *rtpmp2tdepay;
+
+  rtpmp2tdepay = GST_RTP_MP2T_DEPAY (object);
+
+  switch (prop_id) {
+    case PROP_SKIP_FIRST_BYTES:
+      g_value_set_uint (value, rtpmp2tdepay->skip_first_bytes);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+gboolean
+gst_rtp_mp2t_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpmp2tdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_MP2T_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmp2tdepay.h b/gst/rtp/gstrtpmp2tdepay.h
new file mode 100644
index 0000000..aa936dc
--- /dev/null
+++ b/gst/rtp/gstrtpmp2tdepay.h
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP2T_DEPAY_H__
+#define __GST_RTP_MP2T_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP2T_DEPAY \
+  (gst_rtp_mp2t_depay_get_type())
+#define GST_RTP_MP2T_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP2T_DEPAY,GstRtpMP2TDepay))
+#define GST_RTP_MP2T_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP2T_DEPAY,GstRtpMP2TDepayClass))
+#define GST_IS_RTP_MP2T_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP2T_DEPAY))
+#define GST_IS_RTP_MP2T_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP2T_DEPAY))
+typedef struct _GstRtpMP2TDepay GstRtpMP2TDepay;
+typedef struct _GstRtpMP2TDepayClass GstRtpMP2TDepayClass;
+
+struct _GstRtpMP2TDepay
+{
+  GstRTPBaseDepayload depayload;
+
+  guint8 skip_first_bytes;
+};
+
+struct _GstRtpMP2TDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mp2t_depay_get_type (void);
+
+gboolean gst_rtp_mp2t_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP2T_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpmp2tpay.c b/gst/rtp/gstrtpmp2tpay.c
new file mode 100644
index 0000000..12f948e
--- /dev/null
+++ b/gst/rtp/gstrtpmp2tpay.c
@@ -0,0 +1,237 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpmp2tpay.h"
+#include "gstrtputils.h"
+
+static GstStaticPadTemplate gst_rtp_mp2t_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/mpegts,"
+        "packetsize=(int)188," "systemstream=(boolean)true")
+    );
+
+static GstStaticPadTemplate gst_rtp_mp2t_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_MP2T_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"MP2T\" ; "
+        "application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"MP2T\"")
+    );
+
+static gboolean gst_rtp_mp2t_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static GstFlowReturn gst_rtp_mp2t_pay_handle_buffer (GstRTPBasePayload *
+    payload, GstBuffer * buffer);
+static GstFlowReturn gst_rtp_mp2t_pay_flush (GstRTPMP2TPay * rtpmp2tpay);
+static void gst_rtp_mp2t_pay_finalize (GObject * object);
+
+#define gst_rtp_mp2t_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPMP2TPay, gst_rtp_mp2t_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_mp2t_pay_class_init (GstRTPMP2TPayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_mp2t_pay_finalize;
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_mp2t_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_mp2t_pay_handle_buffer;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp2t_pay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp2t_pay_src_template);
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP MPEG2 Transport Stream payloader", "Codec/Payloader/Network/RTP",
+      "Payload-encodes MPEG2 TS into RTP packets (RFC 2250)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+}
+
+static void
+gst_rtp_mp2t_pay_init (GstRTPMP2TPay * rtpmp2tpay)
+{
+  GST_RTP_BASE_PAYLOAD (rtpmp2tpay)->clock_rate = 90000;
+  GST_RTP_BASE_PAYLOAD_PT (rtpmp2tpay) = GST_RTP_PAYLOAD_MP2T;
+
+  rtpmp2tpay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_mp2t_pay_finalize (GObject * object)
+{
+  GstRTPMP2TPay *rtpmp2tpay;
+
+  rtpmp2tpay = GST_RTP_MP2T_PAY (object);
+
+  g_object_unref (rtpmp2tpay->adapter);
+  rtpmp2tpay->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_mp2t_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  gboolean res;
+
+  gst_rtp_base_payload_set_options (payload, "video",
+      payload->pt != GST_RTP_PAYLOAD_MP2T, "MP2T", 90000);
+  res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+  return res;
+}
+
+static GstFlowReturn
+gst_rtp_mp2t_pay_flush (GstRTPMP2TPay * rtpmp2tpay)
+{
+  guint avail, mtu;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBuffer *outbuf;
+
+  avail = gst_adapter_available (rtpmp2tpay->adapter);
+
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpmp2tpay);
+
+  while (avail > 0 && (ret == GST_FLOW_OK)) {
+    guint towrite;
+    guint payload_len;
+    guint packet_len;
+    GstBuffer *paybuf;
+
+    /* this will be the total length of the packet */
+    packet_len = gst_rtp_buffer_calc_packet_len (avail, 0, 0);
+
+    /* fill one MTU or all available bytes */
+    towrite = MIN (packet_len, mtu);
+
+    /* this is the payload length */
+    payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+    payload_len -= payload_len % 188;
+
+    /* need whole packets */
+    if (!payload_len)
+      break;
+
+    /* create buffer to hold the payload */
+    outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+
+    /* get payload */
+    paybuf = gst_adapter_take_buffer_fast (rtpmp2tpay->adapter, payload_len);
+    gst_rtp_copy_meta (GST_ELEMENT_CAST (rtpmp2tpay), outbuf, paybuf, 0);
+    outbuf = gst_buffer_append (outbuf, paybuf);
+    avail -= payload_len;
+
+    GST_BUFFER_PTS (outbuf) = rtpmp2tpay->first_ts;
+    GST_BUFFER_DURATION (outbuf) = rtpmp2tpay->duration;
+
+    GST_DEBUG_OBJECT (rtpmp2tpay, "pushing buffer of size %u",
+        (guint) gst_buffer_get_size (outbuf));
+
+    ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpmp2tpay), outbuf);
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_rtp_mp2t_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRTPMP2TPay *rtpmp2tpay;
+  guint size, avail, packet_len;
+  GstClockTime timestamp, duration;
+  GstFlowReturn ret;
+
+  rtpmp2tpay = GST_RTP_MP2T_PAY (basepayload);
+
+  size = gst_buffer_get_size (buffer);
+  timestamp = GST_BUFFER_PTS (buffer);
+  duration = GST_BUFFER_DURATION (buffer);
+
+again:
+  ret = GST_FLOW_OK;
+  avail = gst_adapter_available (rtpmp2tpay->adapter);
+
+  /* Initialize new RTP payload */
+  if (avail == 0) {
+    rtpmp2tpay->first_ts = timestamp;
+    rtpmp2tpay->duration = duration;
+  }
+
+  /* get packet length of previous data and this new data */
+  packet_len = gst_rtp_buffer_calc_packet_len (avail + size, 0, 0);
+
+  /* if this buffer is going to overflow the packet, flush what we have,
+   * or if upstream is handing us several packets, to keep latency low */
+  if (!size || gst_rtp_base_payload_is_filled (basepayload,
+          packet_len, rtpmp2tpay->duration + duration)) {
+    ret = gst_rtp_mp2t_pay_flush (rtpmp2tpay);
+    rtpmp2tpay->first_ts = timestamp;
+    rtpmp2tpay->duration = duration;
+
+    /* keep filling the payload */
+  } else {
+    if (GST_CLOCK_TIME_IS_VALID (duration))
+      rtpmp2tpay->duration += duration;
+  }
+
+  /* copy buffer to adapter */
+  if (buffer) {
+    gst_adapter_push (rtpmp2tpay->adapter, buffer);
+    buffer = NULL;
+  }
+
+  if (size >= (188 * 2)) {
+    size = 0;
+    goto again;
+  }
+
+  return ret;
+
+}
+
+gboolean
+gst_rtp_mp2t_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpmp2tpay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_MP2T_PAY);
+}
diff --git a/gst/rtp/gstrtpmp2tpay.h b/gst/rtp/gstrtpmp2tpay.h
new file mode 100644
index 0000000..12f4959
--- /dev/null
+++ b/gst/rtp/gstrtpmp2tpay.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_RTP_MP2T_PAY_H__
+#define __GST_RTP_MP2T_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTPMP2TPay GstRTPMP2TPay;
+typedef struct _GstRTPMP2TPayClass GstRTPMP2TPayClass;
+
+#define GST_TYPE_RTP_MP2T_PAY \
+  (gst_rtp_mp2t_pay_get_type())
+#define GST_RTP_MP2T_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP2T_PAY,GstRTPMP2TPay))
+#define GST_RTP_MP2T_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP2T_PAY,GstRTPMP2TPayClass))
+#define GST_IS_RTP_MP2T_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP2T_PAY))
+#define GST_IS_RTP_MP2T_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP2T_PAY))
+
+struct _GstRTPMP2TPay
+{
+  GstRTPBasePayload payload;
+  
+  GstAdapter  *adapter;
+  GstClockTime first_ts;
+  GstClockTime duration;
+};
+
+struct _GstRTPMP2TPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_mp2t_pay_get_type (void);
+
+gboolean gst_rtp_mp2t_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP2T_PAY_H__ */
diff --git a/gst/rtp/gstrtpmp4adepay.c b/gst/rtp/gstrtpmp4adepay.c
new file mode 100644
index 0000000..e537d25
--- /dev/null
+++ b/gst/rtp/gstrtpmp4adepay.c
@@ -0,0 +1,466 @@
+/* GStreamer
+ * Copyright (C) <2007> Nokia Corporation (contact <stefan.kost@nokia.com>)
+ *               <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/base/gstbitreader.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include <string.h>
+#include "gstrtpmp4adepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmp4adepay_debug);
+#define GST_CAT_DEFAULT (rtpmp4adepay_debug)
+
+static GstStaticPadTemplate gst_rtp_mp4a_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/mpeg,"
+        "mpegversion = (int) 4," "framed = (boolean) { false, true }, "
+        "stream-format = (string) raw")
+    );
+
+static GstStaticPadTemplate gst_rtp_mp4a_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) [1, MAX ], "
+        "encoding-name = (string) \"MP4A-LATM\""
+        /* All optional parameters
+         *
+         * "profile-level-id=[1,MAX]"
+         * "config="
+         */
+    )
+    );
+
+#define gst_rtp_mp4a_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMP4ADepay, gst_rtp_mp4a_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_mp4a_depay_finalize (GObject * object);
+
+static gboolean gst_rtp_mp4a_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_mp4a_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+static GstStateChangeReturn gst_rtp_mp4a_depay_change_state (GstElement *
+    element, GstStateChange transition);
+
+
+static void
+gst_rtp_mp4a_depay_class_init (GstRtpMP4ADepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_mp4a_depay_finalize;
+
+  gstelement_class->change_state = gst_rtp_mp4a_depay_change_state;
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_mp4a_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_mp4a_depay_setcaps;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp4a_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp4a_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP MPEG4 audio depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts MPEG4 audio from RTP packets (RFC 3016)",
+      "Nokia Corporation (contact <stefan.kost@nokia.com>), "
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpmp4adepay_debug, "rtpmp4adepay", 0,
+      "MPEG4 audio RTP Depayloader");
+}
+
+static void
+gst_rtp_mp4a_depay_init (GstRtpMP4ADepay * rtpmp4adepay)
+{
+  rtpmp4adepay->adapter = gst_adapter_new ();
+  rtpmp4adepay->framed = FALSE;
+}
+
+static void
+gst_rtp_mp4a_depay_finalize (GObject * object)
+{
+  GstRtpMP4ADepay *rtpmp4adepay;
+
+  rtpmp4adepay = GST_RTP_MP4A_DEPAY (object);
+
+  g_object_unref (rtpmp4adepay->adapter);
+  rtpmp4adepay->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static const guint aac_sample_rates[] = { 96000, 88200, 64000, 48000,
+  44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350
+};
+
+static gboolean
+gst_rtp_mp4a_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstRtpMP4ADepay *rtpmp4adepay;
+  GstCaps *srccaps;
+  const gchar *str;
+  gint clock_rate;
+  gint object_type;
+  gint channels = 2;            /* default */
+  gboolean res;
+
+  rtpmp4adepay = GST_RTP_MP4A_DEPAY (depayload);
+
+  rtpmp4adepay->framed = FALSE;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;         /* default */
+  depayload->clock_rate = clock_rate;
+
+  if (!gst_structure_get_int (structure, "object", &object_type))
+    object_type = 2;            /* AAC LC default */
+
+  srccaps = gst_caps_new_simple ("audio/mpeg",
+      "mpegversion", G_TYPE_INT, 4,
+      "framed", G_TYPE_BOOLEAN, FALSE, "channels", G_TYPE_INT, channels,
+      "stream-format", G_TYPE_STRING, "raw", NULL);
+
+  if ((str = gst_structure_get_string (structure, "config"))) {
+    GValue v = { 0 };
+
+    g_value_init (&v, GST_TYPE_BUFFER);
+    if (gst_value_deserialize (&v, str)) {
+      GstBuffer *buffer;
+      GstMapInfo map;
+      guint8 *data;
+      gsize size;
+      gint i;
+      guint32 rate = 0;
+      guint8 obj_type = 0, sr_idx = 0, channels = 0;
+      GstBitReader br;
+
+      buffer = gst_value_get_buffer (&v);
+      gst_buffer_ref (buffer);
+      g_value_unset (&v);
+
+      gst_buffer_map (buffer, &map, GST_MAP_READ);
+      data = map.data;
+      size = map.size;
+
+      if (size < 2) {
+        GST_WARNING_OBJECT (depayload, "config too short (%d < 2)",
+            (gint) size);
+        goto bad_config;
+      }
+
+      /* Parse StreamMuxConfig according to ISO/IEC 14496-3:
+       *
+       * audioMuxVersion           == 0 (1 bit)
+       * allStreamsSameTimeFraming == 1 (1 bit)
+       * numSubFrames              == rtpmp4adepay->numSubFrames (6 bits)
+       * numProgram                == 0 (4 bits)
+       * numLayer                  == 0 (3 bits)
+       *
+       * We only require audioMuxVersion == 0;
+       *
+       * The remaining bit of the second byte and the rest of the bits are used
+       * for audioSpecificConfig which we need to set in codec_info.
+       */
+      if ((data[0] & 0x80) != 0x00) {
+        GST_WARNING_OBJECT (depayload, "unknown audioMuxVersion 1");
+        goto bad_config;
+      }
+
+      rtpmp4adepay->numSubFrames = (data[0] & 0x3F);
+
+      GST_LOG_OBJECT (rtpmp4adepay, "numSubFrames %d",
+          rtpmp4adepay->numSubFrames);
+
+      /* shift rest of string 15 bits down */
+      size -= 2;
+      for (i = 0; i < size; i++) {
+        data[i] = ((data[i + 1] & 1) << 7) | ((data[i + 2] & 0xfe) >> 1);
+      }
+
+      gst_bit_reader_init (&br, data, size);
+
+      /* any object type is fine, we need to copy it to the profile-level-id field. */
+      if (!gst_bit_reader_get_bits_uint8 (&br, &obj_type, 5))
+        goto bad_config;
+      if (obj_type == 0) {
+        GST_WARNING_OBJECT (depayload, "invalid object type 0");
+        goto bad_config;
+      }
+
+      if (!gst_bit_reader_get_bits_uint8 (&br, &sr_idx, 4))
+        goto bad_config;
+      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;
+      }
+      GST_LOG_OBJECT (rtpmp4adepay, "sample rate index %u", sr_idx);
+
+      if (!gst_bit_reader_get_bits_uint8 (&br, &channels, 4))
+        goto bad_config;
+      if (channels > 7) {
+        GST_WARNING_OBJECT (depayload, "invalid channels %u", (guint) channels);
+        goto bad_config;
+      }
+
+      /* rtp rate depends on sampling rate of the audio */
+      if (sr_idx == 15) {
+        /* index of 15 means we get the rate in the next 24 bits */
+        if (!gst_bit_reader_get_bits_uint32 (&br, &rate, 24))
+          goto bad_config;
+      } else if (sr_idx >= G_N_ELEMENTS (aac_sample_rates)) {
+        goto bad_config;
+      } else {
+        /* else use the rate from the table */
+        rate = aac_sample_rates[sr_idx];
+      }
+
+      rtpmp4adepay->frame_len = 1024;
+
+      switch (obj_type) {
+        case 1:
+        case 2:
+        case 3:
+        case 4:
+        case 6:
+        case 7:
+        {
+          guint8 frameLenFlag = 0;
+
+          if (gst_bit_reader_get_bits_uint8 (&br, &frameLenFlag, 1))
+            if (frameLenFlag)
+              rtpmp4adepay->frame_len = 960;
+          break;
+        }
+        default:
+          break;
+      }
+
+      /* ignore remaining bit, we're only interested in full bytes */
+      gst_buffer_resize (buffer, 0, size);
+      gst_buffer_unmap (buffer, &map);
+      data = NULL;
+
+      gst_caps_set_simple (srccaps,
+          "channels", G_TYPE_INT, (gint) channels,
+          "rate", G_TYPE_INT, (gint) rate,
+          "codec_data", GST_TYPE_BUFFER, buffer, NULL);
+    bad_config:
+      if (data)
+        gst_buffer_unmap (buffer, &map);
+      gst_buffer_unref (buffer);
+    } else {
+      g_warning ("cannot convert config to buffer");
+    }
+  }
+  res = gst_pad_set_caps (depayload->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  return res;
+}
+
+static GstBuffer *
+gst_rtp_mp4a_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpMP4ADepay *rtpmp4adepay;
+  GstBuffer *outbuf;
+  GstMapInfo map;
+
+  rtpmp4adepay = GST_RTP_MP4A_DEPAY (depayload);
+
+  /* flush remaining data on discont */
+  if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
+    gst_adapter_clear (rtpmp4adepay->adapter);
+  }
+
+  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);
+
+  if (!rtpmp4adepay->framed) {
+    if (gst_rtp_buffer_get_marker (rtp)) {
+      GstCaps *caps;
+
+      rtpmp4adepay->framed = TRUE;
+
+      gst_rtp_base_depayload_push (depayload, outbuf);
+
+      caps = gst_pad_get_current_caps (depayload->srcpad);
+      caps = gst_caps_make_writable (caps);
+      gst_caps_set_simple (caps, "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+      gst_pad_set_caps (depayload->srcpad, caps);
+      gst_caps_unref (caps);
+      return NULL;
+    } else {
+      return outbuf;
+    }
+  }
+
+  outbuf = gst_buffer_make_writable (outbuf);
+  GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (rtp->buffer);
+  gst_adapter_push (rtpmp4adepay->adapter, outbuf);
+
+  /* RTP marker bit indicates the last packet of the AudioMuxElement => create
+   * and push a buffer */
+  if (gst_rtp_buffer_get_marker (rtp)) {
+    guint avail;
+    guint i;
+    guint8 *data;
+    guint pos;
+    GstClockTime timestamp;
+
+    avail = gst_adapter_available (rtpmp4adepay->adapter);
+    timestamp = gst_adapter_prev_pts (rtpmp4adepay->adapter, NULL);
+
+    GST_LOG_OBJECT (rtpmp4adepay, "have marker and %u available", avail);
+
+    outbuf = gst_adapter_take_buffer (rtpmp4adepay->adapter, avail);
+    gst_buffer_map (outbuf, &map, GST_MAP_READ);
+    data = map.data;
+    /* position in data we are at */
+    pos = 0;
+
+    /* looping through the number of sub-frames in the audio payload */
+    for (i = 0; i <= rtpmp4adepay->numSubFrames; i++) {
+      /* determine payload length and set buffer data pointer accordingly */
+      guint skip;
+      guint data_len;
+      GstBuffer *tmp = NULL;
+
+      /* each subframe starts with a variable length encoding */
+      data_len = 0;
+      for (skip = 0; skip < avail; skip++) {
+        data_len += data[skip];
+        if (data[skip] != 0xff)
+          break;
+      }
+      skip++;
+
+      /* this can not be possible, we have not enough data or the length
+       * decoding failed because we ran out of data. */
+      if (skip + data_len > avail)
+        goto wrong_size;
+
+      GST_LOG_OBJECT (rtpmp4adepay,
+          "subframe %u, header len %u, data len %u, left %u", i, skip, data_len,
+          avail);
+
+      /* take data out, skip the header */
+      pos += skip;
+      tmp = gst_buffer_copy_region (outbuf, GST_BUFFER_COPY_ALL, pos, data_len);
+
+      /* skip data too */
+      skip += data_len;
+      pos += data_len;
+
+      /* update our pointers whith what we consumed */
+      data += skip;
+      avail -= skip;
+
+      GST_BUFFER_PTS (tmp) = timestamp;
+      gst_rtp_drop_non_audio_meta (depayload, tmp);
+      gst_rtp_base_depayload_push (depayload, tmp);
+
+      /* shift ts for next buffers */
+      if (rtpmp4adepay->frame_len && timestamp != -1
+          && depayload->clock_rate != 0) {
+        timestamp +=
+            gst_util_uint64_scale_int (rtpmp4adepay->frame_len, GST_SECOND,
+            depayload->clock_rate);
+      }
+    }
+
+    /* just a check that lengths match */
+    if (avail) {
+      GST_ELEMENT_WARNING (depayload, STREAM, DECODE,
+          ("Packet invalid"), ("Not all payload consumed: "
+              "possible wrongly encoded packet."));
+    }
+
+    gst_buffer_unmap (outbuf, &map);
+    gst_buffer_unref (outbuf);
+  }
+  return NULL;
+
+  /* ERRORS */
+wrong_size:
+  {
+    GST_ELEMENT_WARNING (rtpmp4adepay, STREAM, DECODE,
+        ("Packet did not validate"), ("wrong packet size"));
+    gst_buffer_unmap (outbuf, &map);
+    gst_buffer_unref (outbuf);
+    return NULL;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_mp4a_depay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpMP4ADepay *rtpmp4adepay;
+  GstStateChangeReturn ret;
+
+  rtpmp4adepay = GST_RTP_MP4A_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_adapter_clear (rtpmp4adepay->adapter);
+      rtpmp4adepay->frame_len = 0;
+      rtpmp4adepay->numSubFrames = 0;
+      rtpmp4adepay->framed = FALSE;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_mp4a_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpmp4adepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_MP4A_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmp4adepay.h b/gst/rtp/gstrtpmp4adepay.h
new file mode 100644
index 0000000..31eaf56
--- /dev/null
+++ b/gst/rtp/gstrtpmp4adepay.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <2007> Nokia Corporation (contact <stefan.kost@nokia.com>)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP4A_DEPAY_H__
+#define __GST_RTP_MP4A_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP4A_DEPAY \
+  (gst_rtp_mp4a_depay_get_type())
+#define GST_RTP_MP4A_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP4A_DEPAY,GstRtpMP4ADepay))
+#define GST_RTP_MP4A_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP4A_DEPAY,GstRtpMP4ADepayClass))
+#define GST_IS_RTP_MP4A_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP4A_DEPAY))
+#define GST_IS_RTP_MP4A_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP4A_DEPAY))
+
+typedef struct _GstRtpMP4ADepay GstRtpMP4ADepay;
+typedef struct _GstRtpMP4ADepayClass GstRtpMP4ADepayClass;
+
+struct _GstRtpMP4ADepay
+{
+  GstRTPBaseDepayload depayload;
+  GstAdapter *adapter;
+  guint8 numSubFrames;
+  guint frame_len;
+
+  gboolean framed;
+};
+
+struct _GstRtpMP4ADepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mp4a_depay_get_type (void);
+
+gboolean gst_rtp_mp4a_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP4A_DEPAY_H__ */
+
diff --git a/gst/rtp/gstrtpmp4apay.c b/gst/rtp/gstrtpmp4apay.c
new file mode 100644
index 0000000..f822ddf
--- /dev/null
+++ b/gst/rtp/gstrtpmp4apay.c
@@ -0,0 +1,463 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpmp4apay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmp4apay_debug);
+#define GST_CAT_DEFAULT (rtpmp4apay_debug)
+
+/* FIXME: add framed=(boolean)true once our encoders have this field set
+ * on their output caps */
+static GstStaticPadTemplate gst_rtp_mp4a_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/mpeg, mpegversion=(int)4, "
+        "stream-format=(string)raw")
+    );
+
+static GstStaticPadTemplate gst_rtp_mp4a_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) [1, MAX ], "
+        "encoding-name = (string) \"MP4A-LATM\""
+        /* All optional parameters
+         *
+         * "cpresent = (string) \"0\""
+         * "config=" 
+         */
+    )
+    );
+
+static void gst_rtp_mp4a_pay_finalize (GObject * object);
+
+static gboolean gst_rtp_mp4a_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static GstFlowReturn gst_rtp_mp4a_pay_handle_buffer (GstRTPBasePayload *
+    payload, GstBuffer * buffer);
+
+#define gst_rtp_mp4a_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMP4APay, gst_rtp_mp4a_pay, GST_TYPE_RTP_BASE_PAYLOAD)
+
+     static void gst_rtp_mp4a_pay_class_init (GstRtpMP4APayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_mp4a_pay_finalize;
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_mp4a_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_mp4a_pay_handle_buffer;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp4a_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp4a_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP MPEG4 audio payloader", "Codec/Payloader/Network/RTP",
+      "Payload MPEG4 audio as RTP packets (RFC 3016)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpmp4apay_debug, "rtpmp4apay", 0,
+      "MP4A-LATM RTP Payloader");
+}
+
+static void
+gst_rtp_mp4a_pay_init (GstRtpMP4APay * rtpmp4apay)
+{
+  rtpmp4apay->rate = 90000;
+  rtpmp4apay->profile = g_strdup ("1");
+}
+
+static void
+gst_rtp_mp4a_pay_finalize (GObject * object)
+{
+  GstRtpMP4APay *rtpmp4apay;
+
+  rtpmp4apay = GST_RTP_MP4A_PAY (object);
+
+  g_free (rtpmp4apay->params);
+  rtpmp4apay->params = NULL;
+
+  if (rtpmp4apay->config)
+    gst_buffer_unref (rtpmp4apay->config);
+  rtpmp4apay->config = NULL;
+
+  g_free (rtpmp4apay->profile);
+  rtpmp4apay->profile = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static const unsigned int sampling_table[16] = {
+  96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+  16000, 12000, 11025, 8000, 7350, 0, 0, 0
+};
+
+static gboolean
+gst_rtp_mp4a_pay_parse_audio_config (GstRtpMP4APay * rtpmp4apay,
+    GstBuffer * buffer)
+{
+  GstMapInfo map;
+  guint8 *data;
+  gsize size;
+  guint8 objectType;
+  guint8 samplingIdx;
+  guint8 channelCfg;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  data = map.data;
+  size = map.size;
+
+  if (size < 2)
+    goto too_short;
+
+  /* any object type is fine, we need to copy it to the profile-level-id field. */
+  objectType = (data[0] & 0xf8) >> 3;
+  if (objectType == 0)
+    goto invalid_object;
+
+  samplingIdx = ((data[0] & 0x07) << 1) | ((data[1] & 0x80) >> 7);
+  /* only fixed values for now */
+  if (samplingIdx > 12 && samplingIdx != 15)
+    goto wrong_freq;
+
+  channelCfg = ((data[1] & 0x78) >> 3);
+  if (channelCfg > 7)
+    goto wrong_channels;
+
+  /* rtp rate depends on sampling rate of the audio */
+  if (samplingIdx == 15) {
+    if (size < 5)
+      goto too_short;
+
+    /* index of 15 means we get the rate in the next 24 bits */
+    rtpmp4apay->rate = ((data[1] & 0x7f) << 17) |
+        ((data[2]) << 9) | ((data[3]) << 1) | ((data[4] & 0x80) >> 7);
+  } else {
+    /* else use the rate from the table */
+    rtpmp4apay->rate = sampling_table[samplingIdx];
+  }
+  /* extra rtp params contain the number of channels */
+  g_free (rtpmp4apay->params);
+  rtpmp4apay->params = g_strdup_printf ("%d", channelCfg);
+  /* audio stream type */
+  rtpmp4apay->streamtype = "5";
+  /* profile */
+  g_free (rtpmp4apay->profile);
+  rtpmp4apay->profile = g_strdup_printf ("%d", objectType);
+
+  GST_DEBUG_OBJECT (rtpmp4apay,
+      "objectType: %d, samplingIdx: %d (%d), channelCfg: %d", objectType,
+      samplingIdx, rtpmp4apay->rate, channelCfg);
+
+  gst_buffer_unmap (buffer, &map);
+
+  return TRUE;
+
+  /* ERROR */
+too_short:
+  {
+    GST_ELEMENT_ERROR (rtpmp4apay, STREAM, FORMAT,
+        (NULL),
+        ("config string too short, expected 2 bytes, got %" G_GSIZE_FORMAT,
+            size));
+    gst_buffer_unmap (buffer, &map);
+    return FALSE;
+  }
+invalid_object:
+  {
+    GST_ELEMENT_ERROR (rtpmp4apay, STREAM, FORMAT,
+        (NULL), ("invalid object type 0"));
+    gst_buffer_unmap (buffer, &map);
+    return FALSE;
+  }
+wrong_freq:
+  {
+    GST_ELEMENT_ERROR (rtpmp4apay, STREAM, NOT_IMPLEMENTED,
+        (NULL), ("unsupported frequency index %d", samplingIdx));
+    gst_buffer_unmap (buffer, &map);
+    return FALSE;
+  }
+wrong_channels:
+  {
+    GST_ELEMENT_ERROR (rtpmp4apay, STREAM, NOT_IMPLEMENTED,
+        (NULL), ("unsupported number of channels %d, must < 8", channelCfg));
+    gst_buffer_unmap (buffer, &map);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_rtp_mp4a_pay_new_caps (GstRtpMP4APay * rtpmp4apay)
+{
+  gchar *config;
+  GValue v = { 0 };
+  gboolean res;
+
+  g_value_init (&v, GST_TYPE_BUFFER);
+  gst_value_set_buffer (&v, rtpmp4apay->config);
+  config = gst_value_serialize (&v);
+
+  res = gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpmp4apay),
+      "cpresent", G_TYPE_STRING, "0", "config", G_TYPE_STRING, config, NULL);
+
+  g_value_unset (&v);
+  g_free (config);
+
+  return res;
+}
+
+static gboolean
+gst_rtp_mp4a_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  GstRtpMP4APay *rtpmp4apay;
+  GstStructure *structure;
+  const GValue *codec_data;
+  gboolean res, framed = TRUE;
+  const gchar *stream_format;
+
+  rtpmp4apay = GST_RTP_MP4A_PAY (payload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  /* this is already handled by the template caps, but it is better
+   * to leave here to have meaningful warning messages when linking
+   * fails */
+  stream_format = gst_structure_get_string (structure, "stream-format");
+  if (stream_format) {
+    if (strcmp (stream_format, "raw") != 0) {
+      GST_WARNING_OBJECT (rtpmp4apay, "AAC's stream-format must be 'raw', "
+          "%s is not supported", stream_format);
+      return FALSE;
+    }
+  } else {
+    GST_WARNING_OBJECT (rtpmp4apay, "AAC's stream-format not specified, "
+        "assuming 'raw'");
+  }
+
+  codec_data = gst_structure_get_value (structure, "codec_data");
+  if (codec_data) {
+    GST_LOG_OBJECT (rtpmp4apay, "got codec_data");
+    if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
+      GstBuffer *buffer, *cbuffer;
+      GstMapInfo map;
+      GstMapInfo cmap;
+      guint i;
+
+      buffer = gst_value_get_buffer (codec_data);
+      GST_LOG_OBJECT (rtpmp4apay, "configuring codec_data");
+
+      /* parse buffer */
+      res = gst_rtp_mp4a_pay_parse_audio_config (rtpmp4apay, buffer);
+
+      if (!res)
+        goto config_failed;
+
+      gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+      /* make the StreamMuxConfig, we need 15 bits for the header */
+      cbuffer = gst_buffer_new_and_alloc (map.size + 2);
+      gst_buffer_map (cbuffer, &cmap, GST_MAP_WRITE);
+
+      memset (cmap.data, 0, map.size + 2);
+
+      /* Create StreamMuxConfig according to ISO/IEC 14496-3:
+       *
+       * audioMuxVersion           == 0 (1 bit)
+       * allStreamsSameTimeFraming == 1 (1 bit)
+       * numSubFrames              == numSubFrames (6 bits)
+       * numProgram                == 0 (4 bits)
+       * numLayer                  == 0 (3 bits)
+       */
+      cmap.data[0] = 0x40;
+      cmap.data[1] = 0x00;
+
+      /* append the config bits, shifting them 1 bit left */
+      for (i = 0; i < map.size; i++) {
+        cmap.data[i + 1] |= ((map.data[i] & 0x80) >> 7);
+        cmap.data[i + 2] |= ((map.data[i] & 0x7f) << 1);
+      }
+
+      gst_buffer_unmap (cbuffer, &cmap);
+      gst_buffer_unmap (buffer, &map);
+
+      /* now we can configure the buffer */
+      if (rtpmp4apay->config)
+        gst_buffer_unref (rtpmp4apay->config);
+      rtpmp4apay->config = cbuffer;
+    }
+  }
+
+  if (gst_structure_get_boolean (structure, "framed", &framed) && !framed) {
+    GST_WARNING_OBJECT (payload, "Need framed AAC data as input!");
+  }
+
+  gst_rtp_base_payload_set_options (payload, "audio", TRUE, "MP4A-LATM",
+      rtpmp4apay->rate);
+
+  res = gst_rtp_mp4a_pay_new_caps (rtpmp4apay);
+
+  return res;
+
+  /* ERRORS */
+config_failed:
+  {
+    GST_DEBUG_OBJECT (rtpmp4apay, "failed to parse config");
+    return FALSE;
+  }
+}
+
+#define RTP_HEADER_LEN 12
+
+/* we expect buffers as exactly one complete AU
+ */
+static GstFlowReturn
+gst_rtp_mp4a_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpMP4APay *rtpmp4apay;
+  GstFlowReturn ret;
+  GstBufferList *list;
+  guint mtu;
+  guint offset;
+  gsize size;
+  gboolean fragmented;
+  GstClockTime timestamp;
+
+  ret = GST_FLOW_OK;
+
+  rtpmp4apay = GST_RTP_MP4A_PAY (basepayload);
+
+  offset = 0;
+  size = gst_buffer_get_size (buffer);
+
+  timestamp = GST_BUFFER_PTS (buffer);
+
+  fragmented = FALSE;
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpmp4apay);
+
+  list = gst_buffer_list_new_sized (size / (mtu - RTP_HEADER_LEN) + 1);
+
+  while (size > 0) {
+    guint towrite;
+    GstBuffer *outbuf;
+    guint payload_len;
+    guint packet_len;
+    guint header_len;
+    GstBuffer *paybuf;
+    GstRTPBuffer rtp = { NULL };
+
+    header_len = 0;
+    if (!fragmented) {
+      guint count;
+      /* first packet calculate space for the packet including the header */
+      count = size;
+      while (count >= 0xff) {
+        header_len++;
+        count -= 0xff;
+      }
+      header_len++;
+    }
+
+    packet_len = gst_rtp_buffer_calc_packet_len (header_len + size, 0, 0);
+    towrite = MIN (packet_len, mtu);
+    payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+    payload_len -= header_len;
+
+    GST_DEBUG_OBJECT (rtpmp4apay,
+        "avail %" G_GSIZE_FORMAT
+        ", header_len %d, packet_len %d, payload_len %d", size, header_len,
+        packet_len, payload_len);
+
+    /* create buffer to hold the payload. */
+    outbuf = gst_rtp_buffer_new_allocate (header_len, 0, 0);
+
+    /* copy payload */
+    gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+    if (!fragmented) {
+      guint8 *payload = gst_rtp_buffer_get_payload (&rtp);
+      guint count;
+
+      /* first packet write the header */
+      count = size;
+      while (count >= 0xff) {
+        *payload++ = 0xff;
+        count -= 0xff;
+      }
+      *payload++ = count;
+    }
+
+    /* marker only if the packet is complete */
+    gst_rtp_buffer_set_marker (&rtp, size == payload_len);
+
+    gst_rtp_buffer_unmap (&rtp);
+
+    /* create a new buf to hold the payload */
+    paybuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL,
+        offset, payload_len);
+
+    /* join memory parts */
+    gst_rtp_copy_audio_meta (rtpmp4apay, outbuf, paybuf);
+    outbuf = gst_buffer_append (outbuf, paybuf);
+    gst_buffer_list_add (list, outbuf);
+    offset += payload_len;
+    size -= payload_len;
+
+    /* copy incomming timestamp (if any) to outgoing buffers */
+    GST_BUFFER_PTS (outbuf) = timestamp;
+
+    fragmented = TRUE;
+  }
+
+  ret =
+      gst_rtp_base_payload_push_list (GST_RTP_BASE_PAYLOAD (rtpmp4apay), list);
+
+  gst_buffer_unref (buffer);
+
+  return ret;
+}
+
+gboolean
+gst_rtp_mp4a_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpmp4apay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_MP4A_PAY);
+}
diff --git a/gst/rtp/gstrtpmp4apay.h b/gst/rtp/gstrtpmp4apay.h
new file mode 100644
index 0000000..49d9b65
--- /dev/null
+++ b/gst/rtp/gstrtpmp4apay.h
@@ -0,0 +1,65 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP4A_PAY_H__
+#define __GST_RTP_MP4A_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP4A_PAY \
+  (gst_rtp_mp4a_pay_get_type())
+#define GST_RTP_MP4A_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP4A_PAY,GstRtpMP4APay))
+#define GST_RTP_MP4A_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP4A_PAY,GstRtpMP4APayClass))
+#define GST_IS_RTP_MP4A_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP4A_PAY))
+#define GST_IS_RTP_MP4A_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP4A_PAY))
+
+typedef struct _GstRtpMP4APay GstRtpMP4APay;
+typedef struct _GstRtpMP4APayClass GstRtpMP4APayClass;
+
+struct _GstRtpMP4APay
+{
+  GstRTPBasePayload    payload;
+
+  gint          rate;
+  gchar        *params;
+  gchar        *profile;
+  const gchar  *streamtype;
+  GstBuffer    *config;
+};
+
+struct _GstRtpMP4APayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_mp4a_pay_get_type (void);
+
+gboolean gst_rtp_mp4a_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP4A_PAY_H__ */
diff --git a/gst/rtp/gstrtpmp4gdepay.c b/gst/rtp/gstrtpmp4gdepay.c
new file mode 100644
index 0000000..d7d91c4
--- /dev/null
+++ b/gst/rtp/gstrtpmp4gdepay.c
@@ -0,0 +1,789 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpmp4gdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmp4gdepay_debug);
+#define GST_CAT_DEFAULT (rtpmp4gdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_mp4g_depay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/mpeg,"
+        "mpegversion=(int) 4,"
+        "systemstream=(boolean)false;"
+        "audio/mpeg," "mpegversion=(int) 4, " "stream-format=(string)raw")
+    );
+
+static GstStaticPadTemplate gst_rtp_mp4g_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) { \"video\", \"audio\", \"application\" }, "
+        "clock-rate = (int) [1, MAX ], "
+        "encoding-name = (string) \"MPEG4-GENERIC\", "
+        /* required string params */
+        /* "streamtype = (string) { \"4\", \"5\" }, "  Not set by Wowza    4 = video, 5 = audio */
+        /* "profile-level-id = (string) [1,MAX], " */
+        /* "config = (string) [1,MAX]" */
+        "mode = (string) { \"generic\", \"CELP-cbr\", \"CELP-vbr\", \"AAC-lbr\", \"AAC-hbr\" } "
+        /* Optional general parameters */
+        /* "objecttype = (string) [1,MAX], " */
+        /* "constantsize = (string) [1,MAX], " *//* constant size of each AU */
+        /* "constantduration = (string) [1,MAX], " *//* constant duration of each AU */
+        /* "maxdisplacement = (string) [1,MAX], " */
+        /* "de-interleavebuffersize = (string) [1,MAX], " */
+        /* Optional configuration parameters */
+        /* "sizelength = (string) [1, 32], " */
+        /* "indexlength = (string) [1, 32], " */
+        /* "indexdeltalength = (string) [1, 32], " */
+        /* "ctsdeltalength = (string) [1, 32], " */
+        /* "dtsdeltalength = (string) [1, 32], " */
+        /* "randomaccessindication = (string) {0, 1}, " */
+        /* "streamstateindication = (string) [0, 32], " */
+        /* "auxiliarydatasizelength = (string) [0, 32]" */ )
+    );
+
+/* simple bitstream parser */
+typedef struct
+{
+  const guint8 *data;
+  const guint8 *end;
+  gint head;                    /* bitpos in the cache of next bit */
+  guint64 cache;                /* cached bytes */
+} GstBsParse;
+
+static void
+gst_bs_parse_init (GstBsParse * bs, const guint8 * data, guint size)
+{
+  bs->data = data;
+  bs->end = data + size;
+  bs->head = 0;
+  bs->cache = 0xffffffff;
+}
+
+static guint32
+gst_bs_parse_read (GstBsParse * bs, guint n)
+{
+  guint32 res = 0;
+  gint shift;
+
+  if (n == 0)
+    return res;
+
+  /* fill up the cache if we need to */
+  while (bs->head < n) {
+    if (bs->data >= bs->end) {
+      /* we're at the end, can't produce more than head number of bits */
+      n = bs->head;
+      break;
+    }
+    /* shift bytes in cache, moving the head bits of the cache left */
+    bs->cache = (bs->cache << 8) | *bs->data++;
+    bs->head += 8;
+  }
+
+  /* bring the required bits down and truncate */
+  if ((shift = bs->head - n) > 0)
+    res = bs->cache >> shift;
+  else
+    res = bs->cache;
+
+  /* mask out required bits */
+  if (n < 32)
+    res &= (1 << n) - 1;
+
+  bs->head = shift;
+
+  return res;
+}
+
+
+#define gst_rtp_mp4g_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMP4GDepay, gst_rtp_mp4g_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_mp4g_depay_finalize (GObject * object);
+
+static gboolean gst_rtp_mp4g_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+static gboolean gst_rtp_mp4g_depay_handle_event (GstRTPBaseDepayload * filter,
+    GstEvent * event);
+
+static GstStateChangeReturn gst_rtp_mp4g_depay_change_state (GstElement *
+    element, GstStateChange transition);
+
+
+static void
+gst_rtp_mp4g_depay_class_init (GstRtpMP4GDepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_mp4g_depay_finalize;
+
+  gstelement_class->change_state = gst_rtp_mp4g_depay_change_state;
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_mp4g_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_mp4g_depay_setcaps;
+  gstrtpbasedepayload_class->handle_event = gst_rtp_mp4g_depay_handle_event;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp4g_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp4g_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP MPEG4 ES depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts MPEG4 elementary streams from RTP packets (RFC 3640)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpmp4gdepay_debug, "rtpmp4gdepay", 0,
+      "MP4-generic RTP Depayloader");
+}
+
+static void
+gst_rtp_mp4g_depay_init (GstRtpMP4GDepay * rtpmp4gdepay)
+{
+  rtpmp4gdepay->adapter = gst_adapter_new ();
+  rtpmp4gdepay->packets = g_queue_new ();
+}
+
+static void
+gst_rtp_mp4g_depay_finalize (GObject * object)
+{
+  GstRtpMP4GDepay *rtpmp4gdepay;
+
+  rtpmp4gdepay = GST_RTP_MP4G_DEPAY (object);
+
+  g_object_unref (rtpmp4gdepay->adapter);
+  rtpmp4gdepay->adapter = NULL;
+  g_queue_free (rtpmp4gdepay->packets);
+  rtpmp4gdepay->packets = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gint
+gst_rtp_mp4g_depay_parse_int (GstStructure * structure, const gchar * field,
+    gint def)
+{
+  const gchar *str;
+  gint res;
+
+  if ((str = gst_structure_get_string (structure, field)))
+    return atoi (str);
+
+  if (gst_structure_get_int (structure, field, &res))
+    return res;
+
+  return def;
+}
+
+static gboolean
+gst_rtp_mp4g_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstRtpMP4GDepay *rtpmp4gdepay;
+  GstCaps *srccaps = NULL;
+  const gchar *str;
+  gint clock_rate;
+  gint someint;
+  gboolean res;
+
+  rtpmp4gdepay = GST_RTP_MP4G_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;         /* default */
+  depayload->clock_rate = clock_rate;
+
+  if ((str = gst_structure_get_string (structure, "media"))) {
+    if (strcmp (str, "audio") == 0) {
+      srccaps = gst_caps_new_simple ("audio/mpeg",
+          "mpegversion", G_TYPE_INT, 4, "stream-format", G_TYPE_STRING, "raw",
+          NULL);
+    } else if (strcmp (str, "video") == 0) {
+      srccaps = gst_caps_new_simple ("video/mpeg",
+          "mpegversion", G_TYPE_INT, 4,
+          "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+    }
+  }
+  if (srccaps == NULL)
+    goto unknown_media;
+
+  /* these values are optional and have a default value of 0 (no header) */
+  rtpmp4gdepay->sizelength =
+      gst_rtp_mp4g_depay_parse_int (structure, "sizelength", 0);
+  rtpmp4gdepay->indexlength =
+      gst_rtp_mp4g_depay_parse_int (structure, "indexlength", 0);
+  rtpmp4gdepay->indexdeltalength =
+      gst_rtp_mp4g_depay_parse_int (structure, "indexdeltalength", 0);
+  rtpmp4gdepay->ctsdeltalength =
+      gst_rtp_mp4g_depay_parse_int (structure, "ctsdeltalength", 0);
+  rtpmp4gdepay->dtsdeltalength =
+      gst_rtp_mp4g_depay_parse_int (structure, "dtsdeltalength", 0);
+  someint =
+      gst_rtp_mp4g_depay_parse_int (structure, "randomaccessindication", 0);
+  rtpmp4gdepay->randomaccessindication = someint > 0 ? 1 : 0;
+  rtpmp4gdepay->streamstateindication =
+      gst_rtp_mp4g_depay_parse_int (structure, "streamstateindication", 0);
+  rtpmp4gdepay->auxiliarydatasizelength =
+      gst_rtp_mp4g_depay_parse_int (structure, "auxiliarydatasizelength", 0);
+  rtpmp4gdepay->constantSize =
+      gst_rtp_mp4g_depay_parse_int (structure, "constantsize", 0);
+  rtpmp4gdepay->constantDuration =
+      gst_rtp_mp4g_depay_parse_int (structure, "constantduration", 0);
+  rtpmp4gdepay->maxDisplacement =
+      gst_rtp_mp4g_depay_parse_int (structure, "maxdisplacement", 0);
+
+
+  /* get config string */
+  if ((str = gst_structure_get_string (structure, "config"))) {
+    GValue v = { 0 };
+
+    g_value_init (&v, GST_TYPE_BUFFER);
+    if (gst_value_deserialize (&v, str)) {
+      GstBuffer *buffer;
+
+      buffer = gst_value_get_buffer (&v);
+      gst_caps_set_simple (srccaps,
+          "codec_data", GST_TYPE_BUFFER, buffer, NULL);
+      g_value_unset (&v);
+    } else {
+      g_warning ("cannot convert config to buffer");
+    }
+  }
+
+  res = gst_pad_set_caps (depayload->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  return res;
+
+  /* ERRORS */
+unknown_media:
+  {
+    GST_DEBUG_OBJECT (rtpmp4gdepay, "Unknown media type");
+    return FALSE;
+  }
+}
+
+static void
+gst_rtp_mp4g_depay_clear_queue (GstRtpMP4GDepay * rtpmp4gdepay)
+{
+  GstBuffer *outbuf;
+
+  while ((outbuf = g_queue_pop_head (rtpmp4gdepay->packets)))
+    gst_buffer_unref (outbuf);
+}
+
+static void
+gst_rtp_mp4g_depay_reset (GstRtpMP4GDepay * rtpmp4gdepay)
+{
+  gst_adapter_clear (rtpmp4gdepay->adapter);
+  rtpmp4gdepay->max_AU_index = -1;
+  rtpmp4gdepay->next_AU_index = -1;
+  rtpmp4gdepay->prev_AU_index = -1;
+  rtpmp4gdepay->prev_rtptime = -1;
+  rtpmp4gdepay->last_AU_index = -1;
+  gst_rtp_mp4g_depay_clear_queue (rtpmp4gdepay);
+}
+
+static void
+gst_rtp_mp4g_depay_flush_queue (GstRtpMP4GDepay * rtpmp4gdepay)
+{
+  GstBuffer *outbuf;
+  gboolean discont = FALSE;
+  guint AU_index;
+
+  while ((outbuf = g_queue_pop_head (rtpmp4gdepay->packets))) {
+    AU_index = GST_BUFFER_OFFSET (outbuf);
+
+    GST_DEBUG_OBJECT (rtpmp4gdepay, "next available AU_index %u", AU_index);
+
+    if (rtpmp4gdepay->next_AU_index != AU_index) {
+      GST_DEBUG_OBJECT (rtpmp4gdepay, "discont, expected AU_index %u",
+          rtpmp4gdepay->next_AU_index);
+      discont = TRUE;
+    }
+
+    if (discont) {
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+      discont = FALSE;
+    }
+
+    GST_DEBUG_OBJECT (rtpmp4gdepay, "pushing AU_index %u", AU_index);
+    gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpmp4gdepay), outbuf, 0);
+    gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpmp4gdepay), outbuf);
+    rtpmp4gdepay->next_AU_index = AU_index + 1;
+  }
+}
+
+static void
+gst_rtp_mp4g_depay_queue (GstRtpMP4GDepay * rtpmp4gdepay, GstBuffer * outbuf)
+{
+  guint AU_index = GST_BUFFER_OFFSET (outbuf);
+
+  if (rtpmp4gdepay->next_AU_index == -1) {
+    GST_DEBUG_OBJECT (rtpmp4gdepay, "Init AU counter %u", AU_index);
+    rtpmp4gdepay->next_AU_index = AU_index;
+  }
+
+  if (rtpmp4gdepay->next_AU_index == AU_index) {
+    GST_DEBUG_OBJECT (rtpmp4gdepay, "pushing expected AU_index %u", AU_index);
+
+    /* we received the expected packet, push it and flush as much as we can from
+     * the queue */
+    gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpmp4gdepay), outbuf, 0);
+    gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpmp4gdepay), outbuf);
+    rtpmp4gdepay->next_AU_index++;
+
+    while ((outbuf = g_queue_peek_head (rtpmp4gdepay->packets))) {
+      AU_index = GST_BUFFER_OFFSET (outbuf);
+
+      GST_DEBUG_OBJECT (rtpmp4gdepay, "next available AU_index %u", AU_index);
+
+      if (rtpmp4gdepay->next_AU_index == AU_index) {
+        GST_DEBUG_OBJECT (rtpmp4gdepay, "pushing expected AU_index %u",
+            AU_index);
+        outbuf = g_queue_pop_head (rtpmp4gdepay->packets);
+        gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpmp4gdepay), outbuf, 0);
+        gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpmp4gdepay),
+            outbuf);
+        rtpmp4gdepay->next_AU_index++;
+      } else {
+        GST_DEBUG_OBJECT (rtpmp4gdepay, "waiting for next AU_index %u",
+            rtpmp4gdepay->next_AU_index);
+        break;
+      }
+    }
+  } else {
+    GList *list;
+
+    GST_DEBUG_OBJECT (rtpmp4gdepay, "queueing AU_index %u", AU_index);
+
+    /* loop the list to skip strictly smaller AU_index buffers */
+    for (list = rtpmp4gdepay->packets->head; list; list = g_list_next (list)) {
+      guint idx;
+      gint gap;
+
+      idx = GST_BUFFER_OFFSET (GST_BUFFER_CAST (list->data));
+
+      /* compare the new seqnum to the one in the buffer */
+      gap = (gint) (idx - AU_index);
+
+      GST_DEBUG_OBJECT (rtpmp4gdepay, "compare with AU_index %u, gap %d", idx,
+          gap);
+
+      /* AU_index <= idx, we can stop looking */
+      if (G_LIKELY (gap > 0))
+        break;
+    }
+    if (G_LIKELY (list))
+      g_queue_insert_before (rtpmp4gdepay->packets, list, outbuf);
+    else
+      g_queue_push_tail (rtpmp4gdepay->packets, outbuf);
+  }
+}
+
+static GstBuffer *
+gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpMP4GDepay *rtpmp4gdepay;
+  GstBuffer *outbuf = NULL;
+  GstClockTime timestamp;
+
+  rtpmp4gdepay = GST_RTP_MP4G_DEPAY (depayload);
+
+  /* flush remaining data on discont */
+  if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
+    GST_DEBUG_OBJECT (rtpmp4gdepay, "received DISCONT");
+    gst_adapter_clear (rtpmp4gdepay->adapter);
+  }
+
+  timestamp = GST_BUFFER_PTS (rtp->buffer);
+
+  {
+    gint payload_len, payload_AU;
+    guint8 *payload;
+    guint32 rtptime;
+    guint AU_headers_len;
+    guint AU_size, AU_index, AU_index_delta, payload_AU_size;
+    gboolean M;
+
+    payload_len = gst_rtp_buffer_get_payload_len (rtp);
+    payload = gst_rtp_buffer_get_payload (rtp);
+
+    GST_DEBUG_OBJECT (rtpmp4gdepay, "received payload of %d", payload_len);
+
+    rtptime = gst_rtp_buffer_get_timestamp (rtp);
+    M = gst_rtp_buffer_get_marker (rtp);
+
+    if (rtpmp4gdepay->sizelength > 0) {
+      gint num_AU_headers, AU_headers_bytes, i;
+      GstBsParse bs;
+
+      if (payload_len < 2)
+        goto short_payload;
+
+      /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+
+       * |AU-headers-length|AU-header|AU-header|      |AU-header|padding|
+       * |                 |   (1)   |   (2)   |      |   (n) * | bits  |
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+
+       *
+       * The length is 2 bytes and contains the length of the following
+       * AU-headers in bits.
+       */
+      AU_headers_len = (payload[0] << 8) | payload[1];
+      AU_headers_bytes = (AU_headers_len + 7) / 8;
+      num_AU_headers = AU_headers_len / 16;
+
+      GST_DEBUG_OBJECT (rtpmp4gdepay, "AU headers len %d, bytes %d, num %d",
+          AU_headers_len, AU_headers_bytes, num_AU_headers);
+
+      /* skip header */
+      payload += 2;
+      payload_len -= 2;
+
+      if (payload_len < AU_headers_bytes)
+        goto short_payload;
+
+      /* skip special headers, point to first payload AU */
+      payload_AU = 2 + AU_headers_bytes;
+      payload_AU_size = payload_len - AU_headers_bytes;
+
+      if (G_UNLIKELY (rtpmp4gdepay->auxiliarydatasizelength)) {
+        gint aux_size;
+
+        /* point the bitstream parser to the first auxiliary data bit */
+        gst_bs_parse_init (&bs, payload + AU_headers_bytes,
+            payload_len - AU_headers_bytes);
+        aux_size =
+            gst_bs_parse_read (&bs, rtpmp4gdepay->auxiliarydatasizelength);
+        /* convert to bytes */
+        aux_size = (aux_size + 7) / 8;
+        /* AU data then follows auxiliary data */
+        if (payload_AU_size < aux_size)
+          goto short_payload;
+        payload_AU += aux_size;
+        payload_AU_size -= aux_size;
+      }
+
+      /* point the bitstream parser to the first AU header bit */
+      gst_bs_parse_init (&bs, payload, payload_len);
+      AU_index = AU_index_delta = 0;
+
+      for (i = 0; i < num_AU_headers && payload_AU_size > 0; i++) {
+        /* parse AU header
+         *  +---------------------------------------+
+         *  |     AU-size                           |
+         *  +---------------------------------------+
+         *  |     AU-Index / AU-Index-delta         |
+         *  +---------------------------------------+
+         *  |     CTS-flag                          |
+         *  +---------------------------------------+
+         *  |     CTS-delta                         |
+         *  +---------------------------------------+
+         *  |     DTS-flag                          |
+         *  +---------------------------------------+
+         *  |     DTS-delta                         |
+         *  +---------------------------------------+
+         *  |     RAP-flag                          |
+         *  +---------------------------------------+
+         *  |     Stream-state                      |
+         *  +---------------------------------------+
+         */
+        AU_size = gst_bs_parse_read (&bs, rtpmp4gdepay->sizelength);
+
+        /* calculate the AU_index, which is only on the first AU of the packet
+         * and the AU_index_delta on the other AUs. This will be used to
+         * reconstruct the AU ordering when interleaving. */
+        if (i == 0) {
+          AU_index = gst_bs_parse_read (&bs, rtpmp4gdepay->indexlength);
+
+          GST_DEBUG_OBJECT (rtpmp4gdepay, "AU index %u", AU_index);
+
+          if (AU_index == 0 && rtpmp4gdepay->prev_AU_index == 0) {
+            gint diff;
+            gint cd;
+
+            /* if we see two consecutive packets with AU_index of 0, we can
+             * assume we have constantDuration packets. Since we don't have
+             * the index we must use the AU duration to calculate the
+             * index. Get the diff between the timestamps first, this can be
+             * positive or negative. */
+            if (rtpmp4gdepay->prev_rtptime <= rtptime)
+              diff = rtptime - rtpmp4gdepay->prev_rtptime;
+            else
+              diff = -(rtpmp4gdepay->prev_rtptime - rtptime);
+
+            /* if no constantDuration was given, make one */
+            if (rtpmp4gdepay->constantDuration != 0) {
+              cd = rtpmp4gdepay->constantDuration;
+              GST_DEBUG_OBJECT (depayload, "using constantDuration %d", cd);
+            } else if (rtpmp4gdepay->prev_AU_num > 0) {
+              /* use number of packets and of previous frame */
+              cd = diff / rtpmp4gdepay->prev_AU_num;
+              GST_DEBUG_OBJECT (depayload, "guessing constantDuration %d", cd);
+              if (!GST_BUFFER_IS_DISCONT (rtp->buffer)) {
+                /* rfc3640 - 3.2.3.2
+                 * if we see two consecutive packets with AU_index of 0 and
+                 * there has been no discontinuity, we must conclude that this
+                 * value of constantDuration is correct from now on. */
+                GST_DEBUG_OBJECT (depayload,
+                    "constantDuration of %d detected", cd);
+                rtpmp4gdepay->constantDuration = cd;
+              }
+            } else {
+              /* assume this frame has the same number of packets as the
+               * previous one */
+              cd = diff / num_AU_headers;
+              GST_DEBUG_OBJECT (depayload, "guessing constantDuration %d", cd);
+            }
+
+            if (cd > 0) {
+              /* get the number of packets by dividing with the duration */
+              diff /= cd;
+            } else {
+              diff = 0;
+            }
+
+            rtpmp4gdepay->last_AU_index += diff;
+            rtpmp4gdepay->prev_AU_index = AU_index;
+
+            AU_index = rtpmp4gdepay->last_AU_index;
+
+            GST_DEBUG_OBJECT (rtpmp4gdepay, "diff %d, AU index %u", diff,
+                AU_index);
+          } else {
+            rtpmp4gdepay->prev_AU_index = AU_index;
+            rtpmp4gdepay->last_AU_index = AU_index;
+          }
+
+          /* keep track of the higest AU_index */
+          if (rtpmp4gdepay->max_AU_index != -1
+              && rtpmp4gdepay->max_AU_index <= AU_index) {
+            GST_DEBUG_OBJECT (rtpmp4gdepay, "new interleave group, flushing");
+            /* a new interleave group started, flush */
+            gst_rtp_mp4g_depay_flush_queue (rtpmp4gdepay);
+          }
+          if (G_UNLIKELY (!rtpmp4gdepay->maxDisplacement &&
+                  rtpmp4gdepay->max_AU_index != -1
+                  && rtpmp4gdepay->max_AU_index >= AU_index)) {
+            GstBuffer *outbuf;
+
+            /* some broken non-interleaved streams have AU-index jumping around
+             * all over the place, apparently assuming receiver disregards */
+            GST_DEBUG_OBJECT (rtpmp4gdepay, "non-interleaved broken AU indices;"
+                " forcing continuous flush");
+            /* reset AU to avoid repeated DISCONT in such case */
+            outbuf = g_queue_peek_head (rtpmp4gdepay->packets);
+            if (G_LIKELY (outbuf)) {
+              rtpmp4gdepay->next_AU_index = GST_BUFFER_OFFSET (outbuf);
+              gst_rtp_mp4g_depay_flush_queue (rtpmp4gdepay);
+            }
+            /* rebase next_AU_index to current rtp's first AU_index */
+            rtpmp4gdepay->next_AU_index = AU_index;
+          }
+          rtpmp4gdepay->prev_rtptime = rtptime;
+          rtpmp4gdepay->prev_AU_num = num_AU_headers;
+        } else {
+          AU_index_delta =
+              gst_bs_parse_read (&bs, rtpmp4gdepay->indexdeltalength);
+          AU_index += AU_index_delta + 1;
+        }
+        /* keep track of highest AU_index */
+        if (rtpmp4gdepay->max_AU_index == -1
+            || AU_index > rtpmp4gdepay->max_AU_index)
+          rtpmp4gdepay->max_AU_index = AU_index;
+
+        /* the presentation time offset, a 2s-complement value, we need this to
+         * calculate the timestamp on the output packet. */
+        if (rtpmp4gdepay->ctsdeltalength > 0) {
+          if (gst_bs_parse_read (&bs, 1))
+            gst_bs_parse_read (&bs, rtpmp4gdepay->ctsdeltalength);
+        }
+        /* the decoding time offset, a 2s-complement value */
+        if (rtpmp4gdepay->dtsdeltalength > 0) {
+          if (gst_bs_parse_read (&bs, 1))
+            gst_bs_parse_read (&bs, rtpmp4gdepay->dtsdeltalength);
+        }
+        /* RAP-flag to indicate that the AU contains a keyframe */
+        if (rtpmp4gdepay->randomaccessindication)
+          gst_bs_parse_read (&bs, 1);
+        /* stream-state */
+        if (rtpmp4gdepay->streamstateindication > 0)
+          gst_bs_parse_read (&bs, rtpmp4gdepay->streamstateindication);
+
+        GST_DEBUG_OBJECT (rtpmp4gdepay, "size %d, index %d, delta %d", AU_size,
+            AU_index, AU_index_delta);
+
+        /* fragmented pakets have the AU_size set to the size of the
+         * unfragmented AU. */
+        if (AU_size > payload_AU_size)
+          AU_size = payload_AU_size;
+
+        /* collect stuff in the adapter, strip header from payload and push in
+         * the adapter */
+        outbuf =
+            gst_rtp_buffer_get_payload_subbuffer (rtp, payload_AU, AU_size);
+        gst_adapter_push (rtpmp4gdepay->adapter, outbuf);
+
+        if (M) {
+          guint avail;
+
+          /* packet is complete, flush */
+          avail = gst_adapter_available (rtpmp4gdepay->adapter);
+
+          outbuf = gst_adapter_take_buffer (rtpmp4gdepay->adapter, avail);
+
+          /* copy some of the fields we calculated above on the buffer. We also
+           * copy the AU_index so that we can sort the packets in our queue. */
+          GST_BUFFER_PTS (outbuf) = timestamp;
+          GST_BUFFER_OFFSET (outbuf) = AU_index;
+
+          if (rtpmp4gdepay->constantDuration != 0) {
+            /* if we have constantDuration, calculate timestamp for next AU
+             * in this RTP packet. */
+            timestamp += (rtpmp4gdepay->constantDuration * GST_SECOND) /
+                depayload->clock_rate;
+          } else {
+            /* otherwise, make sure we don't use the timestamp again for other
+             * AUs. */
+            timestamp = GST_CLOCK_TIME_NONE;
+          }
+
+          GST_DEBUG_OBJECT (depayload,
+              "pushing buffer of size %" G_GSIZE_FORMAT,
+              gst_buffer_get_size (outbuf));
+
+          gst_rtp_mp4g_depay_queue (rtpmp4gdepay, outbuf);
+
+        }
+        payload_AU += AU_size;
+        payload_AU_size -= AU_size;
+      }
+    } else {
+      /* push complete buffer in adapter */
+      outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, 0, payload_len);
+      gst_adapter_push (rtpmp4gdepay->adapter, outbuf);
+
+      /* if this was the last packet of the VOP, create and push a buffer */
+      if (M) {
+        guint avail;
+
+        avail = gst_adapter_available (rtpmp4gdepay->adapter);
+
+        outbuf = gst_adapter_take_buffer (rtpmp4gdepay->adapter, avail);
+
+        GST_DEBUG ("gst_rtp_mp4g_depay_chain: pushing buffer of size %"
+            G_GSIZE_FORMAT, gst_buffer_get_size (outbuf));
+
+        return outbuf;
+      }
+    }
+  }
+
+  return NULL;
+
+  /* ERRORS */
+short_payload:
+  {
+    GST_ELEMENT_WARNING (rtpmp4gdepay, STREAM, DECODE,
+        ("Packet payload was too short."), (NULL));
+    return NULL;
+  }
+}
+
+static gboolean
+gst_rtp_mp4g_depay_handle_event (GstRTPBaseDepayload * filter, GstEvent * event)
+{
+  gboolean ret;
+  GstRtpMP4GDepay *rtpmp4gdepay;
+
+  rtpmp4gdepay = GST_RTP_MP4G_DEPAY (filter);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      gst_rtp_mp4g_depay_reset (rtpmp4gdepay);
+      break;
+    default:
+      break;
+  }
+
+  ret =
+      GST_RTP_BASE_DEPAYLOAD_CLASS (parent_class)->handle_event (filter, event);
+
+  return ret;
+}
+
+static GstStateChangeReturn
+gst_rtp_mp4g_depay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpMP4GDepay *rtpmp4gdepay;
+  GstStateChangeReturn ret;
+
+  rtpmp4gdepay = GST_RTP_MP4G_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_mp4g_depay_reset (rtpmp4gdepay);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_mp4g_depay_reset (rtpmp4gdepay);
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_mp4g_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpmp4gdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_MP4G_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmp4gdepay.h b/gst/rtp/gstrtpmp4gdepay.h
new file mode 100644
index 0000000..5d5997a
--- /dev/null
+++ b/gst/rtp/gstrtpmp4gdepay.h
@@ -0,0 +1,86 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP4G_DEPAY_H__
+#define __GST_RTP_MP4G_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP4G_DEPAY \
+  (gst_rtp_mp4g_depay_get_type())
+#define GST_RTP_MP4G_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP4G_DEPAY,GstRtpMP4GDepay))
+#define GST_RTP_MP4G_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP4G_DEPAY,GstRtpMP4GDepayClass))
+#define GST_IS_RTP_MP4G_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP4G_DEPAY))
+#define GST_IS_RTP_MP4G_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP4G_DEPAY))
+
+typedef struct _GstRtpMP4GDepay GstRtpMP4GDepay;
+typedef struct _GstRtpMP4GDepayClass GstRtpMP4GDepayClass;
+
+struct _GstRtpMP4GDepay
+{
+  GstRTPBaseDepayload depayload;
+
+  gint profile_level_id;
+  gint streamtype;
+
+  gint constantSize;
+  gint constantDuration;
+  gint maxDisplacement;
+
+  gint sizelength;
+  gint indexlength;
+  gint indexdeltalength;
+  gint ctsdeltalength;
+  gint dtsdeltalength;
+  gint randomaccessindication;
+  gint streamstateindication;
+  gint auxiliarydatasizelength;
+
+  guint max_AU_index;
+  guint prev_AU_index;
+  guint last_AU_index;
+  guint next_AU_index;
+  guint32 prev_rtptime;
+  guint prev_AU_num;
+
+  GQueue *packets;
+  
+  GstAdapter *adapter;
+};
+
+struct _GstRtpMP4GDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mp4g_depay_get_type (void);
+
+gboolean gst_rtp_mp4g_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP4G_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpmp4gpay.c b/gst/rtp/gstrtpmp4gpay.c
new file mode 100644
index 0000000..7333b49
--- /dev/null
+++ b/gst/rtp/gstrtpmp4gpay.c
@@ -0,0 +1,639 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/base/gstbitreader.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpmp4gpay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmp4gpay_debug);
+#define GST_CAT_DEFAULT (rtpmp4gpay_debug)
+
+static GstStaticPadTemplate gst_rtp_mp4g_pay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/mpeg,"
+        "mpegversion=(int) 4,"
+        "systemstream=(boolean)false;"
+        "audio/mpeg," "mpegversion=(int) 4, " "stream-format=(string) raw")
+    );
+
+static GstStaticPadTemplate gst_rtp_mp4g_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) { \"video\", \"audio\", \"application\" }, "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) [1, MAX ], "
+        "encoding-name = (string) \"MPEG4-GENERIC\", "
+        /* required string params */
+        "streamtype = (string) { \"4\", \"5\" }, "      /* 4 = video, 5 = audio */
+        /* "profile-level-id = (string) [1,MAX], " */
+        /* "config = (string) [1,MAX]" */
+        "mode = (string) { \"generic\", \"CELP-cbr\", \"CELP-vbr\", \"AAC-lbr\", \"AAC-hbr\" } "
+        /* Optional general parameters */
+        /* "objecttype = (string) [1,MAX], " */
+        /* "constantsize = (string) [1,MAX], " *//* constant size of each AU */
+        /* "constantduration = (string) [1,MAX], " *//* constant duration of each AU */
+        /* "maxdisplacement = (string) [1,MAX], " */
+        /* "de-interleavebuffersize = (string) [1,MAX], " */
+        /* Optional configuration parameters */
+        /* "sizelength = (string) [1, 16], " *//* max 16 bits, should be enough... */
+        /* "indexlength = (string) [1, 8], " */
+        /* "indexdeltalength = (string) [1, 8], " */
+        /* "ctsdeltalength = (string) [1, 64], " */
+        /* "dtsdeltalength = (string) [1, 64], " */
+        /* "randomaccessindication = (string) {0, 1}, " */
+        /* "streamstateindication = (string) [0, 64], " */
+        /* "auxiliarydatasizelength = (string) [0, 64]" */ )
+    );
+
+
+static void gst_rtp_mp4g_pay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_mp4g_pay_change_state (GstElement * element,
+    GstStateChange transition);
+
+static gboolean gst_rtp_mp4g_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static GstFlowReturn gst_rtp_mp4g_pay_handle_buffer (GstRTPBasePayload *
+    payload, GstBuffer * buffer);
+static gboolean gst_rtp_mp4g_pay_sink_event (GstRTPBasePayload * payload,
+    GstEvent * event);
+
+#define gst_rtp_mp4g_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMP4GPay, gst_rtp_mp4g_pay, GST_TYPE_RTP_BASE_PAYLOAD)
+
+     static void gst_rtp_mp4g_pay_class_init (GstRtpMP4GPayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_mp4g_pay_finalize;
+
+  gstelement_class->change_state = gst_rtp_mp4g_pay_change_state;
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_mp4g_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_mp4g_pay_handle_buffer;
+  gstrtpbasepayload_class->sink_event = gst_rtp_mp4g_pay_sink_event;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp4g_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp4g_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP MPEG4 ES payloader",
+      "Codec/Payloader/Network/RTP",
+      "Payload MPEG4 elementary streams as RTP packets (RFC 3640)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpmp4gpay_debug, "rtpmp4gpay", 0,
+      "MP4-generic RTP Payloader");
+}
+
+static void
+gst_rtp_mp4g_pay_init (GstRtpMP4GPay * rtpmp4gpay)
+{
+  rtpmp4gpay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_mp4g_pay_reset (GstRtpMP4GPay * rtpmp4gpay)
+{
+  GST_DEBUG_OBJECT (rtpmp4gpay, "reset");
+
+  gst_adapter_clear (rtpmp4gpay->adapter);
+}
+
+static void
+gst_rtp_mp4g_pay_cleanup (GstRtpMP4GPay * rtpmp4gpay)
+{
+  gst_rtp_mp4g_pay_reset (rtpmp4gpay);
+
+  g_free (rtpmp4gpay->params);
+  rtpmp4gpay->params = NULL;
+
+  if (rtpmp4gpay->config)
+    gst_buffer_unref (rtpmp4gpay->config);
+  rtpmp4gpay->config = NULL;
+
+  g_free (rtpmp4gpay->profile);
+  rtpmp4gpay->profile = NULL;
+
+  rtpmp4gpay->streamtype = NULL;
+  rtpmp4gpay->mode = NULL;
+
+  rtpmp4gpay->frame_len = 0;
+}
+
+static void
+gst_rtp_mp4g_pay_finalize (GObject * object)
+{
+  GstRtpMP4GPay *rtpmp4gpay;
+
+  rtpmp4gpay = GST_RTP_MP4G_PAY (object);
+
+  gst_rtp_mp4g_pay_cleanup (rtpmp4gpay);
+
+  g_object_unref (rtpmp4gpay->adapter);
+  rtpmp4gpay->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static const unsigned int sampling_table[16] = {
+  96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+  16000, 12000, 11025, 8000, 7350, 0, 0, 0
+};
+
+static gboolean
+gst_rtp_mp4g_pay_parse_audio_config (GstRtpMP4GPay * rtpmp4gpay,
+    GstBuffer * buffer)
+{
+  GstMapInfo map;
+  guint8 objectType = 0;
+  guint8 samplingIdx = 0;
+  guint8 channelCfg = 0;
+  GstBitReader br;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  gst_bit_reader_init (&br, map.data, map.size);
+
+  /* any object type is fine, we need to copy it to the profile-level-id field. */
+  if (!gst_bit_reader_get_bits_uint8 (&br, &objectType, 5))
+    goto too_short;
+  if (objectType == 0)
+    goto invalid_object;
+
+  if (!gst_bit_reader_get_bits_uint8 (&br, &samplingIdx, 4))
+    goto too_short;
+  /* only fixed values for now */
+  if (samplingIdx > 12 && samplingIdx != 15)
+    goto wrong_freq;
+
+  if (!gst_bit_reader_get_bits_uint8 (&br, &channelCfg, 4))
+    goto too_short;
+  if (channelCfg > 7)
+    goto wrong_channels;
+
+  /* rtp rate depends on sampling rate of the audio */
+  if (samplingIdx == 15) {
+    guint32 rate = 0;
+
+    /* index of 15 means we get the rate in the next 24 bits */
+    if (!gst_bit_reader_get_bits_uint32 (&br, &rate, 24))
+      goto too_short;
+
+    rtpmp4gpay->rate = rate;
+  } else {
+    /* else use the rate from the table */
+    rtpmp4gpay->rate = sampling_table[samplingIdx];
+  }
+
+  rtpmp4gpay->frame_len = 1024;
+
+  switch (objectType) {
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 6:
+    case 7:
+    {
+      guint8 frameLenFlag = 0;
+
+      if (gst_bit_reader_get_bits_uint8 (&br, &frameLenFlag, 1))
+        if (frameLenFlag)
+          rtpmp4gpay->frame_len = 960;
+
+      break;
+    }
+    default:
+      break;
+  }
+
+  /* extra rtp params contain the number of channels */
+  g_free (rtpmp4gpay->params);
+  rtpmp4gpay->params = g_strdup_printf ("%d", channelCfg);
+  /* audio stream type */
+  rtpmp4gpay->streamtype = "5";
+  /* mode only high bitrate for now */
+  rtpmp4gpay->mode = "AAC-hbr";
+  /* profile */
+  g_free (rtpmp4gpay->profile);
+  rtpmp4gpay->profile = g_strdup_printf ("%d", objectType);
+
+  GST_DEBUG_OBJECT (rtpmp4gpay,
+      "objectType: %d, samplingIdx: %d (%d), channelCfg: %d, frame_len %d",
+      objectType, samplingIdx, rtpmp4gpay->rate, channelCfg,
+      rtpmp4gpay->frame_len);
+
+  gst_buffer_unmap (buffer, &map);
+  return TRUE;
+
+  /* ERROR */
+too_short:
+  {
+    GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT,
+        (NULL), ("config string too short"));
+    gst_buffer_unmap (buffer, &map);
+    return FALSE;
+  }
+invalid_object:
+  {
+    GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT,
+        (NULL), ("invalid object type"));
+    gst_buffer_unmap (buffer, &map);
+    return FALSE;
+  }
+wrong_freq:
+  {
+    GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, NOT_IMPLEMENTED,
+        (NULL), ("unsupported frequency index %d", samplingIdx));
+    gst_buffer_unmap (buffer, &map);
+    return FALSE;
+  }
+wrong_channels:
+  {
+    GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, NOT_IMPLEMENTED,
+        (NULL), ("unsupported number of channels %d, must < 8", channelCfg));
+    gst_buffer_unmap (buffer, &map);
+    return FALSE;
+  }
+}
+
+#define VOS_STARTCODE                   0x000001B0
+
+static gboolean
+gst_rtp_mp4g_pay_parse_video_config (GstRtpMP4GPay * rtpmp4gpay,
+    GstBuffer * buffer)
+{
+  GstMapInfo map;
+  guint32 code;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  if (map.size < 5)
+    goto too_short;
+
+  code = GST_READ_UINT32_BE (map.data);
+
+  g_free (rtpmp4gpay->profile);
+  if (code == VOS_STARTCODE) {
+    /* get profile */
+    rtpmp4gpay->profile = g_strdup_printf ("%d", (gint) map.data[4]);
+  } else {
+    GST_ELEMENT_WARNING (rtpmp4gpay, STREAM, FORMAT,
+        (NULL), ("profile not found in config string, assuming \'1\'"));
+    rtpmp4gpay->profile = g_strdup ("1");
+  }
+
+  /* fixed rate */
+  rtpmp4gpay->rate = 90000;
+  /* video stream type */
+  rtpmp4gpay->streamtype = "4";
+  /* no params for video */
+  rtpmp4gpay->params = NULL;
+  /* mode */
+  rtpmp4gpay->mode = "generic";
+
+  GST_LOG_OBJECT (rtpmp4gpay, "profile %s", rtpmp4gpay->profile);
+
+  gst_buffer_unmap (buffer, &map);
+
+  return TRUE;
+
+  /* ERROR */
+too_short:
+  {
+    GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT,
+        (NULL), ("config string too short"));
+    gst_buffer_unmap (buffer, &map);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_rtp_mp4g_pay_new_caps (GstRtpMP4GPay * rtpmp4gpay)
+{
+  gchar *config;
+  GValue v = { 0 };
+  gboolean res;
+
+#define MP4GCAPS						\
+  "streamtype", G_TYPE_STRING, rtpmp4gpay->streamtype, 		\
+  "profile-level-id", G_TYPE_STRING, rtpmp4gpay->profile,	\
+  "mode", G_TYPE_STRING, rtpmp4gpay->mode,			\
+  "config", G_TYPE_STRING, config,				\
+  "sizelength", G_TYPE_STRING, "13",				\
+  "indexlength", G_TYPE_STRING, "3",				\
+  "indexdeltalength", G_TYPE_STRING, "3",			\
+  NULL
+
+  g_value_init (&v, GST_TYPE_BUFFER);
+  gst_value_set_buffer (&v, rtpmp4gpay->config);
+  config = gst_value_serialize (&v);
+
+  /* hmm, silly */
+  if (rtpmp4gpay->params) {
+    res = gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpmp4gpay),
+        "encoding-params", G_TYPE_STRING, rtpmp4gpay->params, MP4GCAPS);
+  } else {
+    res = gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpmp4gpay),
+        MP4GCAPS);
+  }
+
+  g_value_unset (&v);
+  g_free (config);
+
+#undef MP4GCAPS
+  return res;
+}
+
+static gboolean
+gst_rtp_mp4g_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  GstRtpMP4GPay *rtpmp4gpay;
+  GstStructure *structure;
+  const GValue *codec_data;
+  const gchar *media_type = NULL;
+  gboolean res;
+
+  rtpmp4gpay = GST_RTP_MP4G_PAY (payload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  codec_data = gst_structure_get_value (structure, "codec_data");
+  if (codec_data) {
+    GST_LOG_OBJECT (rtpmp4gpay, "got codec_data");
+    if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
+      GstBuffer *buffer;
+      const gchar *name;
+
+      buffer = gst_value_get_buffer (codec_data);
+      GST_LOG_OBJECT (rtpmp4gpay, "configuring codec_data");
+
+      name = gst_structure_get_name (structure);
+
+      /* parse buffer */
+      if (!strcmp (name, "audio/mpeg")) {
+        res = gst_rtp_mp4g_pay_parse_audio_config (rtpmp4gpay, buffer);
+        media_type = "audio";
+      } else if (!strcmp (name, "video/mpeg")) {
+        res = gst_rtp_mp4g_pay_parse_video_config (rtpmp4gpay, buffer);
+        media_type = "video";
+      } else {
+        res = FALSE;
+      }
+      if (!res)
+        goto config_failed;
+
+      /* now we can configure the buffer */
+      if (rtpmp4gpay->config)
+        gst_buffer_unref (rtpmp4gpay->config);
+
+      rtpmp4gpay->config = gst_buffer_copy (buffer);
+    }
+  }
+  if (media_type == NULL)
+    goto config_failed;
+
+  gst_rtp_base_payload_set_options (payload, media_type, TRUE, "MPEG4-GENERIC",
+      rtpmp4gpay->rate);
+
+  res = gst_rtp_mp4g_pay_new_caps (rtpmp4gpay);
+
+  return res;
+
+  /* ERRORS */
+config_failed:
+  {
+    GST_DEBUG_OBJECT (rtpmp4gpay, "failed to parse config");
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_rtp_mp4g_pay_flush (GstRtpMP4GPay * rtpmp4gpay)
+{
+  guint avail, total;
+  GstBuffer *outbuf;
+  GstFlowReturn ret;
+  guint mtu;
+
+  /* the data available in the adapter is either smaller
+   * than the MTU or bigger. In the case it is smaller, the complete
+   * adapter contents can be put in one packet. In the case the
+   * adapter has more than one MTU, we need to fragment the MPEG data
+   * over multiple packets. */
+  total = avail = gst_adapter_available (rtpmp4gpay->adapter);
+
+  ret = GST_FLOW_OK;
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpmp4gpay);
+
+  while (avail > 0) {
+    guint towrite;
+    guint8 *payload;
+    guint payload_len;
+    guint packet_len;
+    GstRTPBuffer rtp = { NULL };
+    GstBuffer *paybuf;
+
+    /* this will be the total lenght of the packet */
+    packet_len = gst_rtp_buffer_calc_packet_len (avail, 0, 0);
+
+    /* fill one MTU or all available bytes, we need 4 spare bytes for
+     * the AU header. */
+    towrite = MIN (packet_len, mtu - 4);
+
+    /* this is the payload length */
+    payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+
+    GST_DEBUG_OBJECT (rtpmp4gpay,
+        "avail %d, towrite %d, packet_len %d, payload_len %d", avail, towrite,
+        packet_len, payload_len);
+
+    /* create buffer to hold the payload, also make room for the 4 header bytes. */
+    outbuf = gst_rtp_buffer_new_allocate (4, 0, 0);
+
+    gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+    /* copy payload */
+    payload = gst_rtp_buffer_get_payload (&rtp);
+
+    /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+
+     * |AU-headers-length|AU-header|AU-header|      |AU-header|padding|
+     * |                 |   (1)   |   (2)   |      |   (n)   | bits  |
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+
+     */
+    /* AU-headers-length, we only have 1 AU-header */
+    payload[0] = 0x00;
+    payload[1] = 0x10;          /* we use 16 bits for the header */
+
+    /* +---------------------------------------+
+     * |     AU-size                           |
+     * +---------------------------------------+
+     * |     AU-Index / AU-Index-delta         |
+     * +---------------------------------------+
+     * |     CTS-flag                          |
+     * +---------------------------------------+
+     * |     CTS-delta                         |
+     * +---------------------------------------+
+     * |     DTS-flag                          |
+     * +---------------------------------------+
+     * |     DTS-delta                         |
+     * +---------------------------------------+
+     * |     RAP-flag                          |
+     * +---------------------------------------+
+     * |     Stream-state                      |
+     * +---------------------------------------+
+     */
+    /* The AU-header, no CTS, DTS, RAP, Stream-state 
+     *
+     * AU-size is always the total size of the AU, not the fragmented size 
+     */
+    payload[2] = (total & 0x1fe0) >> 5;
+    payload[3] = (total & 0x1f) << 3;   /* we use 13 bits for the size, 3 bits index */
+
+    /* marker only if the packet is complete */
+    gst_rtp_buffer_set_marker (&rtp, avail <= payload_len);
+
+    gst_rtp_buffer_unmap (&rtp);
+
+    paybuf = gst_adapter_take_buffer_fast (rtpmp4gpay->adapter, payload_len);
+    gst_rtp_copy_meta (GST_ELEMENT_CAST (rtpmp4gpay), outbuf, paybuf, 0);
+    outbuf = gst_buffer_append (outbuf, paybuf);
+
+    GST_BUFFER_PTS (outbuf) = rtpmp4gpay->first_timestamp;
+    GST_BUFFER_DURATION (outbuf) = rtpmp4gpay->first_duration;
+
+    GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
+
+    if (rtpmp4gpay->discont) {
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+      /* Only the first outputted buffer has the DISCONT flag */
+      rtpmp4gpay->discont = FALSE;
+    }
+
+    ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpmp4gpay), outbuf);
+
+    avail -= payload_len;
+  }
+
+  return ret;
+}
+
+/* we expect buffers as exactly one complete AU
+ */
+static GstFlowReturn
+gst_rtp_mp4g_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpMP4GPay *rtpmp4gpay;
+
+  rtpmp4gpay = GST_RTP_MP4G_PAY (basepayload);
+
+  rtpmp4gpay->first_timestamp = GST_BUFFER_PTS (buffer);
+  rtpmp4gpay->first_duration = GST_BUFFER_DURATION (buffer);
+  rtpmp4gpay->discont = GST_BUFFER_IS_DISCONT (buffer);
+
+  /* we always encode and flush a full AU */
+  gst_adapter_push (rtpmp4gpay->adapter, buffer);
+
+  return gst_rtp_mp4g_pay_flush (rtpmp4gpay);
+}
+
+static gboolean
+gst_rtp_mp4g_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+  GstRtpMP4GPay *rtpmp4gpay;
+
+  rtpmp4gpay = GST_RTP_MP4G_PAY (payload);
+
+  GST_DEBUG ("Got event: %s", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEGMENT:
+    case GST_EVENT_EOS:
+      /* This flush call makes sure that the last buffer is always pushed
+       * to the base payloader */
+      gst_rtp_mp4g_pay_flush (rtpmp4gpay);
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      gst_rtp_mp4g_pay_reset (rtpmp4gpay);
+      break;
+    default:
+      break;
+  }
+
+  /* let parent handle event too */
+  return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+}
+
+static GstStateChangeReturn
+gst_rtp_mp4g_pay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstRtpMP4GPay *rtpmp4gpay;
+
+  rtpmp4gpay = GST_RTP_MP4G_PAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_mp4g_pay_cleanup (rtpmp4gpay);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_mp4g_pay_cleanup (rtpmp4gpay);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+gboolean
+gst_rtp_mp4g_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpmp4gpay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_MP4G_PAY);
+}
diff --git a/gst/rtp/gstrtpmp4gpay.h b/gst/rtp/gstrtpmp4gpay.h
new file mode 100644
index 0000000..14fd68a
--- /dev/null
+++ b/gst/rtp/gstrtpmp4gpay.h
@@ -0,0 +1,72 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP4G_PAY_H__
+#define __GST_RTP_MP4G_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP4G_PAY \
+  (gst_rtp_mp4g_pay_get_type())
+#define GST_RTP_MP4G_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP4G_PAY,GstRtpMP4GPay))
+#define GST_RTP_MP4G_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP4G_PAY,GstRtpMP4GPayClass))
+#define GST_IS_RTP_MP4G_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP4G_PAY))
+#define GST_IS_RTP_MP4G_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP4G_PAY))
+
+typedef struct _GstRtpMP4GPay GstRtpMP4GPay;
+typedef struct _GstRtpMP4GPayClass GstRtpMP4GPayClass;
+
+struct _GstRtpMP4GPay
+{
+  GstRTPBasePayload    payload;
+
+  GstAdapter   *adapter;
+  GstClockTime  first_timestamp;
+  GstClockTime  first_duration;
+  gboolean      discont;
+
+  gint          rate;
+  gchar        *params;
+  gchar        *profile;
+  const gchar  *streamtype;
+  const gchar  *mode;
+  GstBuffer    *config;
+  guint         frame_len;
+};
+
+struct _GstRtpMP4GPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_mp4g_pay_get_type (void);
+
+gboolean gst_rtp_mp4g_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP4G_PAY_H__ */
diff --git a/gst/rtp/gstrtpmp4vdepay.c b/gst/rtp/gstrtpmp4vdepay.c
new file mode 100644
index 0000000..c860f88
--- /dev/null
+++ b/gst/rtp/gstrtpmp4vdepay.c
@@ -0,0 +1,227 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+
+#include <string.h>
+#include "gstrtpmp4vdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmp4vdepay_debug);
+#define GST_CAT_DEFAULT (rtpmp4vdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_mp4v_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/mpeg,"
+        "mpegversion=(int) 4," "systemstream=(boolean)false")
+    );
+
+static GstStaticPadTemplate gst_rtp_mp4v_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP4V-ES\""
+        /* All optional parameters
+         *
+         * "profile-level-id=[1,MAX]"
+         * "config=" 
+         */
+    )
+    );
+
+#define gst_rtp_mp4v_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMP4VDepay, gst_rtp_mp4v_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_mp4v_depay_finalize (GObject * object);
+
+static gboolean gst_rtp_mp4v_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_mp4v_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+static GstStateChangeReturn gst_rtp_mp4v_depay_change_state (GstElement *
+    element, GstStateChange transition);
+
+static void
+gst_rtp_mp4v_depay_class_init (GstRtpMP4VDepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_mp4v_depay_finalize;
+
+  gstelement_class->change_state = gst_rtp_mp4v_depay_change_state;
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_mp4v_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_mp4v_depay_setcaps;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp4v_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp4v_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP MPEG4 video depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts MPEG4 video from RTP packets (RFC 3016)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpmp4vdepay_debug, "rtpmp4vdepay", 0,
+      "MPEG4 video RTP Depayloader");
+}
+
+static void
+gst_rtp_mp4v_depay_init (GstRtpMP4VDepay * rtpmp4vdepay)
+{
+  rtpmp4vdepay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_mp4v_depay_finalize (GObject * object)
+{
+  GstRtpMP4VDepay *rtpmp4vdepay;
+
+  rtpmp4vdepay = GST_RTP_MP4V_DEPAY (object);
+
+  g_object_unref (rtpmp4vdepay->adapter);
+  rtpmp4vdepay->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_mp4v_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstCaps *srccaps;
+  const gchar *str;
+  gint clock_rate;
+  gboolean res;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;         /* default */
+  depayload->clock_rate = clock_rate;
+
+  srccaps = gst_caps_new_simple ("video/mpeg",
+      "mpegversion", G_TYPE_INT, 4,
+      "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+
+  if ((str = gst_structure_get_string (structure, "config"))) {
+    GValue v = { 0 };
+
+    g_value_init (&v, GST_TYPE_BUFFER);
+    if (gst_value_deserialize (&v, str)) {
+      GstBuffer *buffer;
+
+      buffer = gst_value_get_buffer (&v);
+      gst_caps_set_simple (srccaps,
+          "codec_data", GST_TYPE_BUFFER, buffer, NULL);
+      /* caps takes ref */
+      g_value_unset (&v);
+    } else {
+      g_warning ("cannot convert config to buffer");
+    }
+  }
+  res = gst_pad_set_caps (depayload->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  return res;
+}
+
+static GstBuffer *
+gst_rtp_mp4v_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpMP4VDepay *rtpmp4vdepay;
+  GstBuffer *pbuf, *outbuf = NULL;
+  gboolean marker;
+
+  rtpmp4vdepay = GST_RTP_MP4V_DEPAY (depayload);
+
+  /* flush remaining data on discont */
+  if (GST_BUFFER_IS_DISCONT (rtp->buffer))
+    gst_adapter_clear (rtpmp4vdepay->adapter);
+
+  pbuf = gst_rtp_buffer_get_payload_buffer (rtp);
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  gst_adapter_push (rtpmp4vdepay->adapter, pbuf);
+
+  /* if this was the last packet of the VOP, create and push a buffer */
+  if (marker) {
+    guint avail;
+
+    avail = gst_adapter_available (rtpmp4vdepay->adapter);
+    outbuf = gst_adapter_take_buffer (rtpmp4vdepay->adapter, avail);
+
+    GST_DEBUG ("gst_rtp_mp4v_depay_chain: pushing buffer of size %"
+        G_GSIZE_FORMAT, gst_buffer_get_size (outbuf));
+    gst_rtp_drop_non_video_meta (rtpmp4vdepay, outbuf);
+  }
+
+  return outbuf;
+}
+
+static GstStateChangeReturn
+gst_rtp_mp4v_depay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpMP4VDepay *rtpmp4vdepay;
+  GstStateChangeReturn ret;
+
+  rtpmp4vdepay = GST_RTP_MP4V_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_adapter_clear (rtpmp4vdepay->adapter);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_mp4v_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpmp4vdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_MP4V_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmp4vdepay.h b/gst/rtp/gstrtpmp4vdepay.h
new file mode 100644
index 0000000..436e0db
--- /dev/null
+++ b/gst/rtp/gstrtpmp4vdepay.h
@@ -0,0 +1,61 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP4V_DEPAY_H__
+#define __GST_RTP_MP4V_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP4V_DEPAY \
+  (gst_rtp_mp4v_depay_get_type())
+#define GST_RTP_MP4V_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP4V_DEPAY,GstRtpMP4VDepay))
+#define GST_RTP_MP4V_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP4V_DEPAY,GstRtpMP4VDepayClass))
+#define GST_IS_RTP_MP4V_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP4V_DEPAY))
+#define GST_IS_RTP_MP4V_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP4V_DEPAY))
+
+typedef struct _GstRtpMP4VDepay GstRtpMP4VDepay;
+typedef struct _GstRtpMP4VDepayClass GstRtpMP4VDepayClass;
+
+struct _GstRtpMP4VDepay
+{
+  GstRTPBaseDepayload depayload;
+  
+  GstAdapter *adapter;
+};
+
+struct _GstRtpMP4VDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mp4v_depay_get_type (void);
+
+gboolean gst_rtp_mp4v_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP4V_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpmp4vpay.c b/gst/rtp/gstrtpmp4vpay.c
new file mode 100644
index 0000000..5e89fd8
--- /dev/null
+++ b/gst/rtp/gstrtpmp4vpay.c
@@ -0,0 +1,619 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+
+#include "gstrtpmp4vpay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmp4vpay_debug);
+#define GST_CAT_DEFAULT (rtpmp4vpay_debug)
+
+static GstStaticPadTemplate gst_rtp_mp4v_pay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/mpeg,"
+        "mpegversion=(int) 4, systemstream=(boolean)false;" "video/x-divx")
+    );
+
+static GstStaticPadTemplate gst_rtp_mp4v_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP4V-ES\""
+        /* two string params
+         *
+         "profile-level-id = (string) [1,MAX]"
+         "config = (string) [1,MAX]"
+         */
+    )
+    );
+
+#define DEFAULT_CONFIG_INTERVAL 0
+
+enum
+{
+  PROP_0,
+  PROP_CONFIG_INTERVAL
+};
+
+
+static void gst_rtp_mp4v_pay_finalize (GObject * object);
+
+static void gst_rtp_mp4v_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_mp4v_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_rtp_mp4v_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static GstFlowReturn gst_rtp_mp4v_pay_handle_buffer (GstRTPBasePayload *
+    payload, GstBuffer * buffer);
+static gboolean gst_rtp_mp4v_pay_sink_event (GstRTPBasePayload * pay,
+    GstEvent * event);
+
+#define gst_rtp_mp4v_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMP4VPay, gst_rtp_mp4v_pay, GST_TYPE_RTP_BASE_PAYLOAD)
+
+     static void gst_rtp_mp4v_pay_class_init (GstRtpMP4VPayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->set_property = gst_rtp_mp4v_pay_set_property;
+  gobject_class->get_property = gst_rtp_mp4v_pay_get_property;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp4v_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp4v_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP MPEG4 Video payloader", "Codec/Payloader/Network/RTP",
+      "Payload MPEG-4 video as RTP packets (RFC 3016)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CONFIG_INTERVAL,
+      g_param_spec_uint ("config-interval", "Config Send Interval",
+          "Send Config Insertion Interval in seconds (configuration headers "
+          "will be multiplexed in the data stream when detected.) (0 = disabled)",
+          0, 3600, DEFAULT_CONFIG_INTERVAL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
+  gobject_class->finalize = gst_rtp_mp4v_pay_finalize;
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_mp4v_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_mp4v_pay_handle_buffer;
+  gstrtpbasepayload_class->sink_event = gst_rtp_mp4v_pay_sink_event;
+
+  GST_DEBUG_CATEGORY_INIT (rtpmp4vpay_debug, "rtpmp4vpay", 0,
+      "MP4 video RTP Payloader");
+}
+
+static void
+gst_rtp_mp4v_pay_init (GstRtpMP4VPay * rtpmp4vpay)
+{
+  rtpmp4vpay->adapter = gst_adapter_new ();
+  rtpmp4vpay->rate = 90000;
+  rtpmp4vpay->profile = 1;
+  rtpmp4vpay->need_config = TRUE;
+  rtpmp4vpay->config_interval = DEFAULT_CONFIG_INTERVAL;
+  rtpmp4vpay->last_config = -1;
+
+  rtpmp4vpay->config = NULL;
+}
+
+static void
+gst_rtp_mp4v_pay_finalize (GObject * object)
+{
+  GstRtpMP4VPay *rtpmp4vpay;
+
+  rtpmp4vpay = GST_RTP_MP4V_PAY (object);
+
+  if (rtpmp4vpay->config) {
+    gst_buffer_unref (rtpmp4vpay->config);
+    rtpmp4vpay->config = NULL;
+  }
+  g_object_unref (rtpmp4vpay->adapter);
+  rtpmp4vpay->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_mp4v_pay_new_caps (GstRtpMP4VPay * rtpmp4vpay)
+{
+  gchar *profile, *config;
+  GValue v = { 0 };
+  gboolean res;
+
+  profile = g_strdup_printf ("%d", rtpmp4vpay->profile);
+  g_value_init (&v, GST_TYPE_BUFFER);
+  gst_value_set_buffer (&v, rtpmp4vpay->config);
+  config = gst_value_serialize (&v);
+
+  res = gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpmp4vpay),
+      "profile-level-id", G_TYPE_STRING, profile,
+      "config", G_TYPE_STRING, config, NULL);
+
+  g_value_unset (&v);
+
+  g_free (profile);
+  g_free (config);
+
+  return res;
+}
+
+static gboolean
+gst_rtp_mp4v_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  GstRtpMP4VPay *rtpmp4vpay;
+  GstStructure *structure;
+  const GValue *codec_data;
+  gboolean res;
+
+  rtpmp4vpay = GST_RTP_MP4V_PAY (payload);
+
+  gst_rtp_base_payload_set_options (payload, "video", TRUE, "MP4V-ES",
+      rtpmp4vpay->rate);
+
+  res = TRUE;
+
+  structure = gst_caps_get_structure (caps, 0);
+  codec_data = gst_structure_get_value (structure, "codec_data");
+  if (codec_data) {
+    GST_LOG_OBJECT (rtpmp4vpay, "got codec_data");
+    if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
+      GstBuffer *buffer;
+
+      buffer = gst_value_get_buffer (codec_data);
+
+      if (gst_buffer_get_size (buffer) < 5)
+        goto done;
+
+      gst_buffer_extract (buffer, 4, &rtpmp4vpay->profile, 1);
+      GST_LOG_OBJECT (rtpmp4vpay, "configuring codec_data, profile %d",
+          rtpmp4vpay->profile);
+
+      if (rtpmp4vpay->config)
+        gst_buffer_unref (rtpmp4vpay->config);
+      rtpmp4vpay->config = gst_buffer_copy (buffer);
+      res = gst_rtp_mp4v_pay_new_caps (rtpmp4vpay);
+    }
+  }
+
+done:
+  return res;
+}
+
+static void
+gst_rtp_mp4v_pay_empty (GstRtpMP4VPay * rtpmp4vpay)
+{
+  gst_adapter_clear (rtpmp4vpay->adapter);
+}
+
+#define RTP_HEADER_LEN 12
+
+static GstFlowReturn
+gst_rtp_mp4v_pay_flush (GstRtpMP4VPay * rtpmp4vpay)
+{
+  guint avail, mtu;
+  GstBuffer *outbuf;
+  GstBuffer *outbuf_data = NULL;
+  GstFlowReturn ret;
+  GstBufferList *list = NULL;
+
+  /* the data available in the adapter is either smaller
+   * than the MTU or bigger. In the case it is smaller, the complete
+   * adapter contents can be put in one packet. In the case the
+   * adapter has more than one MTU, we need to split the MP4V data
+   * over multiple packets. */
+  avail = gst_adapter_available (rtpmp4vpay->adapter);
+
+  if (rtpmp4vpay->config == NULL && rtpmp4vpay->need_config) {
+    /* when we don't have a config yet, flush things out */
+    gst_adapter_flush (rtpmp4vpay->adapter, avail);
+    avail = 0;
+  }
+
+  if (!avail)
+    return GST_FLOW_OK;
+
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpmp4vpay);
+
+  /* Use buffer lists. Each frame will be put into a list
+   * of buffers and the whole list will be pushed downstream
+   * at once */
+  list = gst_buffer_list_new_sized ((avail / (mtu - RTP_HEADER_LEN)) + 1);
+
+  while (avail > 0) {
+    guint towrite;
+    guint payload_len;
+    guint packet_len;
+    GstRTPBuffer rtp = { NULL };
+
+    /* this will be the total lenght of the packet */
+    packet_len = gst_rtp_buffer_calc_packet_len (avail, 0, 0);
+
+    /* fill one MTU or all available bytes */
+    towrite = MIN (packet_len, mtu);
+
+    /* this is the payload length */
+    payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+
+    /* create buffer without payload. The payload will be put
+     * in next buffer instead. Both buffers will be merged */
+    outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+
+    /* Take buffer with the payload from the adapter */
+    outbuf_data = gst_adapter_take_buffer_fast (rtpmp4vpay->adapter,
+        payload_len);
+
+    avail -= payload_len;
+
+    gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+    gst_rtp_buffer_set_marker (&rtp, avail == 0);
+    gst_rtp_buffer_unmap (&rtp);
+    gst_rtp_copy_video_meta (rtpmp4vpay, outbuf, outbuf_data);
+    outbuf = gst_buffer_append (outbuf, outbuf_data);
+
+    GST_BUFFER_PTS (outbuf) = rtpmp4vpay->first_timestamp;
+
+    /* add to list */
+    gst_buffer_list_insert (list, -1, outbuf);
+  }
+
+  /* push the whole buffer list at once */
+  ret =
+      gst_rtp_base_payload_push_list (GST_RTP_BASE_PAYLOAD (rtpmp4vpay), list);
+
+  return ret;
+}
+
+#define VOS_STARTCODE                   0x000001B0
+#define VOS_ENDCODE                     0x000001B1
+#define USER_DATA_STARTCODE             0x000001B2
+#define GOP_STARTCODE                   0x000001B3
+#define VISUAL_OBJECT_STARTCODE         0x000001B5
+#define VOP_STARTCODE                   0x000001B6
+
+static gboolean
+gst_rtp_mp4v_pay_depay_data (GstRtpMP4VPay * enc, guint8 * data, guint size,
+    gint * strip, gboolean * vopi)
+{
+  guint32 code;
+  gboolean result;
+  *vopi = FALSE;
+
+  *strip = 0;
+
+  if (size < 5)
+    return FALSE;
+
+  code = GST_READ_UINT32_BE (data);
+  GST_DEBUG_OBJECT (enc, "start code 0x%08x", code);
+
+  switch (code) {
+    case VOS_STARTCODE:
+    case 0x00000101:
+    {
+      gint i;
+      guint8 profile;
+      gboolean newprofile = FALSE;
+      gboolean equal;
+
+      if (code == VOS_STARTCODE) {
+        /* profile_and_level_indication */
+        profile = data[4];
+
+        GST_DEBUG_OBJECT (enc, "VOS profile 0x%08x", profile);
+
+        if (profile != enc->profile) {
+          newprofile = TRUE;
+          enc->profile = profile;
+        }
+      }
+
+      /* up to the next GOP_STARTCODE or VOP_STARTCODE is
+       * the config information */
+      code = 0xffffffff;
+      for (i = 5; i < size - 4; i++) {
+        code = (code << 8) | data[i];
+        if (code == GOP_STARTCODE || code == VOP_STARTCODE)
+          break;
+      }
+      i -= 3;
+      /* see if config changed */
+      equal = FALSE;
+      if (enc->config) {
+        if (gst_buffer_get_size (enc->config) == i) {
+          equal = gst_buffer_memcmp (enc->config, 0, data, i) == 0;
+        }
+      }
+      /* if config string changed or new profile, make new caps */
+      if (!equal || newprofile) {
+        if (enc->config)
+          gst_buffer_unref (enc->config);
+        enc->config = gst_buffer_new_and_alloc (i);
+
+        gst_buffer_fill (enc->config, 0, data, i);
+
+        gst_rtp_mp4v_pay_new_caps (enc);
+      }
+      *strip = i;
+      /* we need to flush out the current packet. */
+      result = TRUE;
+      break;
+    }
+    case VOP_STARTCODE:
+      GST_DEBUG_OBJECT (enc, "VOP");
+      /* VOP startcode, we don't have to flush the packet */
+      result = FALSE;
+      /* vop-coding-type == I-frame */
+      if (size > 4 && (data[4] >> 6 == 0)) {
+        GST_DEBUG_OBJECT (enc, "VOP-I");
+        *vopi = TRUE;
+      }
+      break;
+    case GOP_STARTCODE:
+      GST_DEBUG_OBJECT (enc, "GOP");
+      *vopi = TRUE;
+      result = TRUE;
+      break;
+    case 0x00000100:
+      enc->need_config = FALSE;
+      result = TRUE;
+      break;
+    default:
+      if (code >= 0x20 && code <= 0x2f) {
+        GST_DEBUG_OBJECT (enc, "short header");
+        result = FALSE;
+      } else {
+        GST_DEBUG_OBJECT (enc, "other startcode");
+        /* all other startcodes need a flush */
+        result = TRUE;
+      }
+      break;
+  }
+  return result;
+}
+
+/* we expect buffers starting on startcodes. 
+ */
+static GstFlowReturn
+gst_rtp_mp4v_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpMP4VPay *rtpmp4vpay;
+  GstFlowReturn ret;
+  guint avail;
+  guint packet_len;
+  GstMapInfo map;
+  gsize size;
+  gboolean flush;
+  gint strip;
+  GstClockTime timestamp, duration;
+  gboolean vopi;
+  gboolean send_config;
+
+  ret = GST_FLOW_OK;
+  send_config = FALSE;
+
+  rtpmp4vpay = GST_RTP_MP4V_PAY (basepayload);
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  size = map.size;
+  timestamp = GST_BUFFER_PTS (buffer);
+  duration = GST_BUFFER_DURATION (buffer);
+  avail = gst_adapter_available (rtpmp4vpay->adapter);
+
+  if (duration == -1)
+    duration = 0;
+
+  /* empty buffer, take timestamp */
+  if (avail == 0) {
+    rtpmp4vpay->first_timestamp = timestamp;
+    rtpmp4vpay->duration = 0;
+  }
+
+  /* depay incomming data and see if we need to start a new RTP
+   * packet */
+  flush =
+      gst_rtp_mp4v_pay_depay_data (rtpmp4vpay, map.data, size, &strip, &vopi);
+  gst_buffer_unmap (buffer, &map);
+
+  if (strip) {
+    /* strip off config if requested */
+    if (!(rtpmp4vpay->config_interval > 0)) {
+      GstBuffer *subbuf;
+
+      GST_LOG_OBJECT (rtpmp4vpay, "stripping config at %d, size %d", strip,
+          (gint) size - strip);
+
+      /* strip off header */
+      subbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, strip,
+          size - strip);
+      GST_BUFFER_PTS (subbuf) = timestamp;
+      gst_buffer_unref (buffer);
+      buffer = subbuf;
+
+      size = gst_buffer_get_size (buffer);
+    } else {
+      GST_LOG_OBJECT (rtpmp4vpay, "found config in stream");
+      rtpmp4vpay->last_config = timestamp;
+    }
+  }
+
+  /* there is a config request, see if we need to insert it */
+  if (vopi && (rtpmp4vpay->config_interval > 0) && rtpmp4vpay->config) {
+    if (rtpmp4vpay->last_config != -1) {
+      guint64 diff;
+
+      GST_LOG_OBJECT (rtpmp4vpay,
+          "now %" GST_TIME_FORMAT ", last VOP-I %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (timestamp), GST_TIME_ARGS (rtpmp4vpay->last_config));
+
+      /* calculate diff between last config in milliseconds */
+      if (timestamp > rtpmp4vpay->last_config) {
+        diff = timestamp - rtpmp4vpay->last_config;
+      } else {
+        diff = 0;
+      }
+
+      GST_DEBUG_OBJECT (rtpmp4vpay,
+          "interval since last config %" GST_TIME_FORMAT, GST_TIME_ARGS (diff));
+
+      /* bigger than interval, queue config */
+      /* FIXME should convert timestamps to running time */
+      if (GST_TIME_AS_SECONDS (diff) >= rtpmp4vpay->config_interval) {
+        GST_DEBUG_OBJECT (rtpmp4vpay, "time to send config");
+        send_config = TRUE;
+      }
+    } else {
+      /* no known previous config time, send now */
+      GST_DEBUG_OBJECT (rtpmp4vpay, "no previous config time, send now");
+      send_config = TRUE;
+    }
+
+    if (send_config) {
+      /* we need to send config now first */
+      GST_LOG_OBJECT (rtpmp4vpay, "inserting config in stream");
+
+      /* insert header */
+      buffer = gst_buffer_append (gst_buffer_ref (rtpmp4vpay->config), buffer);
+
+      GST_BUFFER_PTS (buffer) = timestamp;
+      size = gst_buffer_get_size (buffer);
+
+      if (timestamp != -1) {
+        rtpmp4vpay->last_config = timestamp;
+      }
+    }
+  }
+
+  /* if we need to flush, do so now */
+  if (flush) {
+    ret = gst_rtp_mp4v_pay_flush (rtpmp4vpay);
+    rtpmp4vpay->first_timestamp = timestamp;
+    rtpmp4vpay->duration = 0;
+    avail = 0;
+  }
+
+  /* get packet length of data and see if we exceeded MTU. */
+  packet_len = gst_rtp_buffer_calc_packet_len (avail + size, 0, 0);
+
+  if (gst_rtp_base_payload_is_filled (basepayload,
+          packet_len, rtpmp4vpay->duration + duration)) {
+    ret = gst_rtp_mp4v_pay_flush (rtpmp4vpay);
+    rtpmp4vpay->first_timestamp = timestamp;
+    rtpmp4vpay->duration = 0;
+  }
+
+  /* push new data */
+  gst_adapter_push (rtpmp4vpay->adapter, buffer);
+
+  rtpmp4vpay->duration += duration;
+
+  return ret;
+}
+
+static gboolean
+gst_rtp_mp4v_pay_sink_event (GstRTPBasePayload * pay, GstEvent * event)
+{
+  GstRtpMP4VPay *rtpmp4vpay;
+
+  rtpmp4vpay = GST_RTP_MP4V_PAY (pay);
+
+  GST_DEBUG ("Got event: %s", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEGMENT:
+    case GST_EVENT_EOS:
+      /* This flush call makes sure that the last buffer is always pushed
+       * to the base payloader */
+      gst_rtp_mp4v_pay_flush (rtpmp4vpay);
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      gst_rtp_mp4v_pay_empty (rtpmp4vpay);
+      break;
+    default:
+      break;
+  }
+
+  /* let parent handle event too */
+  return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (pay, event);
+}
+
+static void
+gst_rtp_mp4v_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpMP4VPay *rtpmp4vpay;
+
+  rtpmp4vpay = GST_RTP_MP4V_PAY (object);
+
+  switch (prop_id) {
+    case PROP_CONFIG_INTERVAL:
+      rtpmp4vpay->config_interval = g_value_get_uint (value);
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_rtp_mp4v_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpMP4VPay *rtpmp4vpay;
+
+  rtpmp4vpay = GST_RTP_MP4V_PAY (object);
+
+  switch (prop_id) {
+    case PROP_CONFIG_INTERVAL:
+      g_value_set_uint (value, rtpmp4vpay->config_interval);
+      break;
+    default:
+      break;
+  }
+}
+
+gboolean
+gst_rtp_mp4v_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpmp4vpay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_MP4V_PAY);
+}
diff --git a/gst/rtp/gstrtpmp4vpay.h b/gst/rtp/gstrtpmp4vpay.h
new file mode 100644
index 0000000..a974a91
--- /dev/null
+++ b/gst/rtp/gstrtpmp4vpay.h
@@ -0,0 +1,74 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP4V_PAY_H__
+#define __GST_RTP_MP4V_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP4V_PAY \
+  (gst_rtp_mp4v_pay_get_type())
+#define GST_RTP_MP4V_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP4V_PAY,GstRtpMP4VPay))
+#define GST_RTP_MP4V_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP4V_PAY,GstRtpMP4VPayClass))
+#define GST_IS_RTP_MP4V_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP4V_PAY))
+#define GST_IS_RTP_MP4V_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP4V_PAY))
+
+typedef struct _GstRtpMP4VPay GstRtpMP4VPay;
+typedef struct _GstRtpMP4VPayClass GstRtpMP4VPayClass;
+
+struct _GstRtpMP4VPay
+{
+  GstRTPBasePayload    payload;
+
+  GstAdapter   *adapter;
+  GstClockTime  first_timestamp;
+  GstClockTime  duration;
+
+  gint          rate;
+  gint          profile;
+  GstBuffer    *config;
+  gboolean      send_config;
+  gboolean      need_config;
+
+  /* naming might be confusing with send_config; but naming matches h264
+   * payloader */
+  guint         config_interval;
+  GstClockTime  last_config;
+};
+
+struct _GstRtpMP4VPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_mp4v_pay_get_type (void);
+
+gboolean gst_rtp_mp4v_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP4V_PAY_H__ */
diff --git a/gst/rtp/gstrtpmpadepay.c b/gst/rtp/gstrtpmpadepay.c
new file mode 100644
index 0000000..18506db
--- /dev/null
+++ b/gst/rtp/gstrtpmpadepay.c
@@ -0,0 +1,181 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include <string.h>
+#include "gstrtpmpadepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmpadepay_debug);
+#define GST_CAT_DEFAULT (rtpmpadepay_debug)
+
+static GstStaticPadTemplate gst_rtp_mpa_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/mpeg, " "mpegversion = (int) 1")
+    );
+
+static GstStaticPadTemplate gst_rtp_mpa_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_MPA_STRING ", "
+        "clock-rate = (int) 90000 ;"
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "encoding-name = (string) \"MPA\", clock-rate = (int) [1, MAX]")
+    );
+
+#define gst_rtp_mpa_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMPADepay, gst_rtp_mpa_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_mpa_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_mpa_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+static void
+gst_rtp_mpa_depay_class_init (GstRtpMPADepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpmpadepay_debug, "rtpmpadepay", 0,
+      "MPEG Audio RTP Depayloader");
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mpa_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mpa_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP MPEG audio depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts MPEG audio from RTP packets (RFC 2038)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasedepayload_class->set_caps = gst_rtp_mpa_depay_setcaps;
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_mpa_depay_process;
+}
+
+static void
+gst_rtp_mpa_depay_init (GstRtpMPADepay * rtpmpadepay)
+{
+}
+
+static gboolean
+gst_rtp_mpa_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstCaps *outcaps;
+  gint clock_rate;
+  gboolean res;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;
+  depayload->clock_rate = clock_rate;
+
+  outcaps =
+      gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1, NULL);
+  res = gst_pad_set_caps (depayload->srcpad, outcaps);
+  gst_caps_unref (outcaps);
+
+  return res;
+}
+
+static GstBuffer *
+gst_rtp_mpa_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpMPADepay *rtpmpadepay;
+  GstBuffer *outbuf;
+  gint payload_len;
+#if 0
+  guint8 *payload;
+  guint16 frag_offset;
+#endif
+  gboolean marker;
+
+  rtpmpadepay = GST_RTP_MPA_DEPAY (depayload);
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  if (payload_len <= 4)
+    goto empty_packet;
+
+#if 0
+  payload = gst_rtp_buffer_get_payload (&rtp);
+  /* strip off header
+   *
+   *  0                   1                   2                   3
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |             MBZ               |          Frag_offset          |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   */
+  frag_offset = (payload[2] << 8) | payload[3];
+#endif
+
+  /* subbuffer skipping the 4 header bytes */
+  outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, 4, -1);
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  if (marker) {
+    /* mark start of talkspurt with RESYNC */
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+  }
+  GST_DEBUG_OBJECT (rtpmpadepay,
+      "gst_rtp_mpa_depay_chain: pushing buffer of size %" G_GSIZE_FORMAT "",
+      gst_buffer_get_size (outbuf));
+
+  if (outbuf) {
+    gst_rtp_drop_non_audio_meta (rtpmpadepay, outbuf);
+  }
+
+  /* FIXME, we can push half mpeg frames when they are split over multiple
+   * RTP packets */
+  return outbuf;
+
+  /* ERRORS */
+empty_packet:
+  {
+    GST_ELEMENT_WARNING (rtpmpadepay, STREAM, DECODE,
+        ("Empty Payload."), (NULL));
+    return NULL;
+  }
+}
+
+gboolean
+gst_rtp_mpa_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpmpadepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_MPA_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmpadepay.h b/gst/rtp/gstrtpmpadepay.h
new file mode 100644
index 0000000..1070d77
--- /dev/null
+++ b/gst/rtp/gstrtpmpadepay.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MPA_DEPAY_H__
+#define __GST_RTP_MPA_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MPA_DEPAY \
+  (gst_rtp_mpa_depay_get_type())
+#define GST_RTP_MPA_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MPA_DEPAY,GstRtpMPADepay))
+#define GST_RTP_MPA_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MPA_DEPAY,GstRtpMPADepayClass))
+#define GST_IS_RTP_MPA_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MPA_DEPAY))
+#define GST_IS_RTP_MPA_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MPA_DEPAY))
+
+typedef struct _GstRtpMPADepay GstRtpMPADepay;
+typedef struct _GstRtpMPADepayClass GstRtpMPADepayClass;
+
+struct _GstRtpMPADepay
+{
+  GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpMPADepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mpa_depay_get_type (void);
+
+gboolean gst_rtp_mpa_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MPA_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpmpapay.c b/gst/rtp/gstrtpmpapay.c
new file mode 100644
index 0000000..09fa8a8
--- /dev/null
+++ b/gst/rtp/gstrtpmpapay.c
@@ -0,0 +1,343 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpmpapay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmpapay_debug);
+#define GST_CAT_DEFAULT (rtpmpapay_debug)
+
+static GstStaticPadTemplate gst_rtp_mpa_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/mpeg, " "mpegversion = (int) 1")
+    );
+
+static GstStaticPadTemplate gst_rtp_mpa_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_MPA_STRING ", "
+        "clock-rate = (int) 90000; "
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"MPA\"")
+    );
+
+static void gst_rtp_mpa_pay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_mpa_pay_change_state (GstElement * element,
+    GstStateChange transition);
+
+static gboolean gst_rtp_mpa_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static gboolean gst_rtp_mpa_pay_sink_event (GstRTPBasePayload * payload,
+    GstEvent * event);
+static GstFlowReturn gst_rtp_mpa_pay_flush (GstRtpMPAPay * rtpmpapay);
+static GstFlowReturn gst_rtp_mpa_pay_handle_buffer (GstRTPBasePayload * payload,
+    GstBuffer * buffer);
+
+#define gst_rtp_mpa_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMPAPay, gst_rtp_mpa_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_mpa_pay_class_init (GstRtpMPAPayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpmpapay_debug, "rtpmpapay", 0,
+      "MPEG Audio RTP Depayloader");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_mpa_pay_finalize;
+
+  gstelement_class->change_state = gst_rtp_mpa_pay_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mpa_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mpa_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP MPEG audio payloader", "Codec/Payloader/Network/RTP",
+      "Payload MPEG audio as RTP packets (RFC 2038)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_mpa_pay_setcaps;
+  gstrtpbasepayload_class->sink_event = gst_rtp_mpa_pay_sink_event;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_mpa_pay_handle_buffer;
+}
+
+static void
+gst_rtp_mpa_pay_init (GstRtpMPAPay * rtpmpapay)
+{
+  rtpmpapay->adapter = gst_adapter_new ();
+
+  GST_RTP_BASE_PAYLOAD (rtpmpapay)->pt = GST_RTP_PAYLOAD_MPA;
+}
+
+static void
+gst_rtp_mpa_pay_finalize (GObject * object)
+{
+  GstRtpMPAPay *rtpmpapay;
+
+  rtpmpapay = GST_RTP_MPA_PAY (object);
+
+  g_object_unref (rtpmpapay->adapter);
+  rtpmpapay->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_mpa_pay_reset (GstRtpMPAPay * pay)
+{
+  pay->first_ts = -1;
+  pay->duration = 0;
+  gst_adapter_clear (pay->adapter);
+  GST_DEBUG_OBJECT (pay, "reset depayloader");
+}
+
+static gboolean
+gst_rtp_mpa_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  gboolean res;
+
+  gst_rtp_base_payload_set_options (payload, "audio",
+      payload->pt != GST_RTP_PAYLOAD_MPA, "MPA", 90000);
+  res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+  return res;
+}
+
+static gboolean
+gst_rtp_mpa_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+  gboolean ret;
+  GstRtpMPAPay *rtpmpapay;
+
+  rtpmpapay = GST_RTP_MPA_PAY (payload);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+      /* make sure we push the last packets in the adapter on EOS */
+      gst_rtp_mpa_pay_flush (rtpmpapay);
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      gst_rtp_mpa_pay_reset (rtpmpapay);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+
+  return ret;
+}
+
+#define RTP_HEADER_LEN 12
+
+static GstFlowReturn
+gst_rtp_mpa_pay_flush (GstRtpMPAPay * rtpmpapay)
+{
+  guint avail;
+  GstBuffer *outbuf;
+  GstFlowReturn ret;
+  guint16 frag_offset;
+  GstBufferList *list;
+
+  /* the data available in the adapter is either smaller
+   * than the MTU or bigger. In the case it is smaller, the complete
+   * adapter contents can be put in one packet. In the case the
+   * adapter has more than one MTU, we need to split the MPA data
+   * over multiple packets. The frag_offset in each packet header
+   * needs to be updated with the position in the MPA frame. */
+  avail = gst_adapter_available (rtpmpapay->adapter);
+
+  ret = GST_FLOW_OK;
+
+  list =
+      gst_buffer_list_new_sized (avail / (GST_RTP_BASE_PAYLOAD_MTU (rtpmpapay) -
+          RTP_HEADER_LEN) + 1);
+
+  frag_offset = 0;
+  while (avail > 0) {
+    guint towrite;
+    guint8 *payload;
+    guint payload_len;
+    guint packet_len;
+    GstRTPBuffer rtp = { NULL };
+    GstBuffer *paybuf;
+
+    /* this will be the total length of the packet */
+    packet_len = gst_rtp_buffer_calc_packet_len (4 + avail, 0, 0);
+
+    /* fill one MTU or all available bytes */
+    towrite = MIN (packet_len, GST_RTP_BASE_PAYLOAD_MTU (rtpmpapay));
+
+    /* this is the payload length */
+    payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+
+    /* create buffer to hold the payload */
+    outbuf = gst_rtp_buffer_new_allocate (4, 0, 0);
+
+    gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+    payload_len -= 4;
+
+    gst_rtp_buffer_set_payload_type (&rtp, GST_RTP_PAYLOAD_MPA);
+
+    /*
+     *  0                   1                   2                   3
+     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * |             MBZ               |          Frag_offset          |
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     */
+    payload = gst_rtp_buffer_get_payload (&rtp);
+    payload[0] = 0;
+    payload[1] = 0;
+    payload[2] = frag_offset >> 8;
+    payload[3] = frag_offset & 0xff;
+
+    avail -= payload_len;
+    frag_offset += payload_len;
+
+    if (avail == 0)
+      gst_rtp_buffer_set_marker (&rtp, TRUE);
+
+    gst_rtp_buffer_unmap (&rtp);
+
+    paybuf = gst_adapter_take_buffer_fast (rtpmpapay->adapter, payload_len);
+    gst_rtp_copy_audio_meta (rtpmpapay, outbuf, paybuf);
+    outbuf = gst_buffer_append (outbuf, paybuf);
+
+    GST_BUFFER_PTS (outbuf) = rtpmpapay->first_ts;
+    GST_BUFFER_DURATION (outbuf) = rtpmpapay->duration;
+    gst_buffer_list_add (list, outbuf);
+  }
+
+  ret = gst_rtp_base_payload_push_list (GST_RTP_BASE_PAYLOAD (rtpmpapay), list);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_rtp_mpa_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpMPAPay *rtpmpapay;
+  GstFlowReturn ret;
+  guint size, avail;
+  guint packet_len;
+  GstClockTime duration, timestamp;
+
+  rtpmpapay = GST_RTP_MPA_PAY (basepayload);
+
+  size = gst_buffer_get_size (buffer);
+  duration = GST_BUFFER_DURATION (buffer);
+  timestamp = GST_BUFFER_PTS (buffer);
+
+  if (GST_BUFFER_IS_DISCONT (buffer)) {
+    GST_DEBUG_OBJECT (rtpmpapay, "DISCONT");
+    gst_rtp_mpa_pay_reset (rtpmpapay);
+  }
+
+  avail = gst_adapter_available (rtpmpapay->adapter);
+
+  /* get packet length of previous data and this new data,
+   * payload length includes a 4 byte header */
+  packet_len = gst_rtp_buffer_calc_packet_len (4 + avail + size, 0, 0);
+
+  /* if this buffer is going to overflow the packet, flush what we
+   * have. */
+  if (gst_rtp_base_payload_is_filled (basepayload,
+          packet_len, rtpmpapay->duration + duration)) {
+    ret = gst_rtp_mpa_pay_flush (rtpmpapay);
+    avail = 0;
+  } else {
+    ret = GST_FLOW_OK;
+  }
+
+  if (avail == 0) {
+    GST_DEBUG_OBJECT (rtpmpapay,
+        "first packet, save timestamp %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (timestamp));
+    rtpmpapay->first_ts = timestamp;
+    rtpmpapay->duration = 0;
+  }
+
+  gst_adapter_push (rtpmpapay->adapter, buffer);
+  rtpmpapay->duration = duration;
+
+  return ret;
+}
+
+static GstStateChangeReturn
+gst_rtp_mpa_pay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRtpMPAPay *rtpmpapay;
+  GstStateChangeReturn ret;
+
+  rtpmpapay = GST_RTP_MPA_PAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_mpa_pay_reset (rtpmpapay);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_mpa_pay_reset (rtpmpapay);
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_mpa_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpmpapay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_MPA_PAY);
+}
diff --git a/gst/rtp/gstrtpmpapay.h b/gst/rtp/gstrtpmpapay.h
new file mode 100644
index 0000000..db29852
--- /dev/null
+++ b/gst/rtp/gstrtpmpapay.h
@@ -0,0 +1,63 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MPA_PAY_H__
+#define __GST_RTP_MPA_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MPA_PAY \
+  (gst_rtp_mpa_pay_get_type())
+#define GST_RTP_MPA_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MPA_PAY,GstRtpMPAPay))
+#define GST_RTP_MPA_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MPA_PAY,GstRtpMPAPayClass))
+#define GST_IS_RTP_MPA_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MPA_PAY))
+#define GST_IS_RTP_MPA_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MPA_PAY))
+
+typedef struct _GstRtpMPAPay GstRtpMPAPay;
+typedef struct _GstRtpMPAPayClass GstRtpMPAPayClass;
+
+struct _GstRtpMPAPay
+{
+  GstRTPBasePayload payload;
+
+  GstAdapter *adapter;
+  GstClockTime first_ts;
+  GstClockTime duration;
+};
+
+struct _GstRtpMPAPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_mpa_pay_get_type (void);
+
+gboolean gst_rtp_mpa_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MPA_PAY_H__ */
diff --git a/gst/rtp/gstrtpmparobustdepay.c b/gst/rtp/gstrtpmparobustdepay.c
new file mode 100644
index 0000000..702d2b0
--- /dev/null
+++ b/gst/rtp/gstrtpmparobustdepay.c
@@ -0,0 +1,811 @@
+/* GStreamer
+ * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ * Copyright (C) <2010> Nokia Corporation
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <stdio.h>
+#include <string.h>
+#include "gstrtpmparobustdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmparobustdepay_debug);
+#define GST_CAT_DEFAULT (rtpmparobustdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_mpa_robust_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/mpeg, " "mpegversion = (int) 1")
+    );
+
+static GstStaticPadTemplate gst_rtp_mpa_robust_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) 90000, "
+        "encoding-name = (string) \"MPA-ROBUST\" " "; "
+        /* draft versions appear still in use out there */
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) [1, MAX], "
+        "encoding-name = (string) { \"X-MP3-DRAFT-00\", \"X-MP3-DRAFT-01\", "
+        " \"X-MP3-DRAFT-02\", \"X-MP3-DRAFT-03\", \"X-MP3-DRAFT-04\", "
+        " \"X-MP3-DRAFT-05\", \"X-MP3-DRAFT-06\" }")
+    );
+
+typedef struct _GstADUFrame
+{
+  guint32 header;
+  gint size;
+  gint side_info;
+  gint data_size;
+  gint layer;
+  gint backpointer;
+
+  GstBuffer *buffer;
+} GstADUFrame;
+
+#define gst_rtp_mpa_robust_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMPARobustDepay, gst_rtp_mpa_robust_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static GstStateChangeReturn gst_rtp_mpa_robust_change_state (GstElement *
+    element, GstStateChange transition);
+
+static gboolean gst_rtp_mpa_robust_depay_setcaps (GstRTPBaseDepayload *
+    depayload, GstCaps * caps);
+static GstBuffer *gst_rtp_mpa_robust_depay_process (GstRTPBaseDepayload *
+    depayload, GstRTPBuffer * rtp);
+
+static void
+gst_rtp_mpa_robust_depay_finalize (GObject * object)
+{
+  GstRtpMPARobustDepay *rtpmpadepay;
+
+  rtpmpadepay = (GstRtpMPARobustDepay *) object;
+
+  g_object_unref (rtpmpadepay->adapter);
+  g_queue_free (rtpmpadepay->adu_frames);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_mpa_robust_depay_class_init (GstRtpMPARobustDepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  GST_DEBUG_CATEGORY_INIT (rtpmparobustdepay_debug, "rtpmparobustdepay", 0,
+      "Robust MPEG Audio RTP Depayloader");
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_mpa_robust_depay_finalize;
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_rtp_mpa_robust_change_state);
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mpa_robust_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mpa_robust_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP MPEG audio depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts MPEG audio from RTP packets (RFC 5219)",
+      "Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>");
+
+  gstrtpbasedepayload_class->set_caps = gst_rtp_mpa_robust_depay_setcaps;
+  gstrtpbasedepayload_class->process_rtp_packet =
+      gst_rtp_mpa_robust_depay_process;
+}
+
+static void
+gst_rtp_mpa_robust_depay_init (GstRtpMPARobustDepay * rtpmpadepay)
+{
+  rtpmpadepay->adapter = gst_adapter_new ();
+  rtpmpadepay->adu_frames = g_queue_new ();
+}
+
+static gboolean
+gst_rtp_mpa_robust_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps)
+{
+  GstRtpMPARobustDepay *rtpmpadepay;
+  GstStructure *structure;
+  GstCaps *outcaps;
+  gint clock_rate, draft;
+  gboolean res;
+  const gchar *encoding;
+
+  rtpmpadepay = GST_RTP_MPA_ROBUST_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;
+  depayload->clock_rate = clock_rate;
+
+  rtpmpadepay->has_descriptor = TRUE;
+  if ((encoding = gst_structure_get_string (structure, "encoding-name"))) {
+    if (sscanf (encoding, "X-MP3-DRAFT-%d", &draft) && (draft == 0))
+      rtpmpadepay->has_descriptor = FALSE;
+  }
+
+  outcaps =
+      gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1, NULL);
+  res = gst_pad_set_caps (depayload->srcpad, outcaps);
+  gst_caps_unref (outcaps);
+
+  return res;
+}
+
+/* thanks again go to mp3parse ... */
+
+static const guint mp3types_bitrates[2][3][16] = {
+  {
+        {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,},
+        {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,},
+        {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,}
+      },
+  {
+        {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,},
+        {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,},
+        {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}
+      },
+};
+
+static const guint mp3types_freqs[3][3] = { {44100, 48000, 32000},
+{22050, 24000, 16000},
+{11025, 12000, 8000}
+};
+
+static inline guint
+mp3_type_frame_length_from_header (GstElement * mp3parse, guint32 header,
+    guint * put_version, guint * put_layer, guint * put_channels,
+    guint * put_bitrate, guint * put_samplerate, guint * put_mode,
+    guint * put_crc)
+{
+  guint length;
+  gulong mode, samplerate, bitrate, layer, channels, padding, crc;
+  gulong version;
+  gint lsf, mpg25;
+
+  if (header & (1 << 20)) {
+    lsf = (header & (1 << 19)) ? 0 : 1;
+    mpg25 = 0;
+  } else {
+    lsf = 1;
+    mpg25 = 1;
+  }
+
+  version = 1 + lsf + mpg25;
+
+  layer = 4 - ((header >> 17) & 0x3);
+
+  crc = (header >> 16) & 0x1;
+
+  bitrate = (header >> 12) & 0xF;
+  bitrate = mp3types_bitrates[lsf][layer - 1][bitrate] * 1000;
+  /* The caller has ensured we have a valid header, so bitrate can't be
+     zero here. */
+  if (bitrate == 0) {
+    GST_DEBUG_OBJECT (mp3parse, "invalid bitrate");
+    return 0;
+  }
+
+  samplerate = (header >> 10) & 0x3;
+  samplerate = mp3types_freqs[lsf + mpg25][samplerate];
+
+  padding = (header >> 9) & 0x1;
+
+  mode = (header >> 6) & 0x3;
+  channels = (mode == 3) ? 1 : 2;
+
+  switch (layer) {
+    case 1:
+      length = 4 * ((bitrate * 12) / samplerate + padding);
+      break;
+    case 2:
+      length = (bitrate * 144) / samplerate + padding;
+      break;
+    default:
+    case 3:
+      length = (bitrate * 144) / (samplerate << lsf) + padding;
+      break;
+  }
+
+  GST_LOG_OBJECT (mp3parse, "Calculated mp3 frame length of %u bytes", length);
+  GST_LOG_OBJECT (mp3parse, "samplerate = %lu, bitrate = %lu, version = %lu, "
+      "layer = %lu, channels = %lu, mode = %lu", samplerate, bitrate, version,
+      layer, channels, mode);
+
+  if (put_version)
+    *put_version = version;
+  if (put_layer)
+    *put_layer = layer;
+  if (put_channels)
+    *put_channels = channels;
+  if (put_bitrate)
+    *put_bitrate = bitrate;
+  if (put_samplerate)
+    *put_samplerate = samplerate;
+  if (put_mode)
+    *put_mode = mode;
+  if (put_crc)
+    *put_crc = crc;
+
+  GST_LOG_OBJECT (mp3parse, "size = %u", length);
+  return length;
+}
+
+/* generate empty/silent/dummy frame that mimics @frame,
+ * except for rate, where maximum possible is selected */
+static GstADUFrame *
+gst_rtp_mpa_robust_depay_generate_dummy_frame (GstRtpMPARobustDepay *
+    rtpmpadepay, GstADUFrame * frame)
+{
+  GstADUFrame *dummy;
+  GstMapInfo map;
+
+  dummy = g_slice_dup (GstADUFrame, frame);
+
+  /* go for maximum bitrate */
+  dummy->header = (frame->header & ~(0xf << 12)) | (0xe << 12);
+  dummy->size =
+      mp3_type_frame_length_from_header (GST_ELEMENT_CAST (rtpmpadepay),
+      dummy->header, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+  dummy->data_size = dummy->size - 4 - dummy->side_info;
+  dummy->backpointer = 0;
+
+  dummy->buffer = gst_buffer_new_and_alloc (dummy->side_info + 4);
+
+  gst_buffer_map (dummy->buffer, &map, GST_MAP_WRITE);
+  memset (map.data, 0, map.size);
+  GST_WRITE_UINT32_BE (map.data, dummy->header);
+  gst_buffer_unmap (dummy->buffer, &map);
+
+  GST_BUFFER_PTS (dummy->buffer) = GST_BUFFER_PTS (frame->buffer);
+
+  return dummy;
+}
+
+/* validates and parses @buf, and queues for further transformation if valid,
+ * otherwise discards @buf
+ * Takes ownership of @buf. */
+static gboolean
+gst_rtp_mpa_robust_depay_queue_frame (GstRtpMPARobustDepay * rtpmpadepay,
+    GstBuffer * buf)
+{
+  GstADUFrame *frame = NULL;
+  guint version, layer, channels, size;
+  guint crc;
+  GstMapInfo map;
+
+  g_return_val_if_fail (buf != NULL, FALSE);
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  if (map.size < 6)
+    goto corrupt_frame;
+
+  frame = g_slice_new0 (GstADUFrame);
+  frame->header = GST_READ_UINT32_BE (map.data);
+
+  size = mp3_type_frame_length_from_header (GST_ELEMENT_CAST (rtpmpadepay),
+      frame->header, &version, &layer, &channels, NULL, NULL, NULL, &crc);
+  if (!size)
+    goto corrupt_frame;
+
+  frame->size = size;
+  frame->layer = layer;
+  if (version == 1 && channels == 2)
+    frame->side_info = 32;
+  else if ((version == 1 && channels == 1) || (version >= 2 && channels == 2))
+    frame->side_info = 17;
+  else if (version >= 2 && channels == 1)
+    frame->side_info = 9;
+  else {
+    g_assert_not_reached ();
+    goto corrupt_frame;
+  }
+
+  /* backpointer */
+  if (layer == 3) {
+    frame->backpointer = GST_READ_UINT16_BE (map.data + 4);
+    frame->backpointer >>= 7;
+    GST_LOG_OBJECT (rtpmpadepay, "backpointer: %d", frame->backpointer);
+  }
+
+  if (!crc)
+    frame->side_info += 2;
+
+  GST_LOG_OBJECT (rtpmpadepay, "side info: %d", frame->side_info);
+  frame->data_size = frame->size - 4 - frame->side_info;
+
+  /* some size validation checks */
+  if (4 + frame->side_info > map.size)
+    goto corrupt_frame;
+
+  /* ADU data would then extend past MP3 frame,
+   * even using past byte reservoir */
+  if (-frame->backpointer + (gint) (map.size) > frame->size)
+    goto corrupt_frame;
+
+  gst_buffer_unmap (buf, &map);
+
+  /* ok, take buffer and queue */
+  frame->buffer = buf;
+  g_queue_push_tail (rtpmpadepay->adu_frames, frame);
+
+  return TRUE;
+
+  /* ERRORS */
+corrupt_frame:
+  {
+    GST_DEBUG_OBJECT (rtpmpadepay, "frame is corrupt");
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+    if (frame)
+      g_slice_free (GstADUFrame, frame);
+    return FALSE;
+  }
+}
+
+static inline void
+gst_rtp_mpa_robust_depay_free_frame (GstADUFrame * frame)
+{
+  if (frame->buffer)
+    gst_buffer_unref (frame->buffer);
+  g_slice_free (GstADUFrame, frame);
+}
+
+static inline void
+gst_rtp_mpa_robust_depay_dequeue_frame (GstRtpMPARobustDepay * rtpmpadepay)
+{
+  GstADUFrame *head;
+
+  GST_LOG_OBJECT (rtpmpadepay, "dequeueing ADU frame");
+
+  if (rtpmpadepay->adu_frames->head == rtpmpadepay->cur_adu_frame)
+    rtpmpadepay->cur_adu_frame = NULL;
+
+  head = g_queue_pop_head (rtpmpadepay->adu_frames);
+  g_assert (head->buffer);
+  gst_rtp_mpa_robust_depay_free_frame (head);
+
+  return;
+}
+
+/* returns TRUE if at least one new ADU frame was enqueued for MP3 conversion.
+ * Takes ownership of @buf. */
+static gboolean
+gst_rtp_mpa_robust_depay_deinterleave (GstRtpMPARobustDepay * rtpmpadepay,
+    GstBuffer * buf)
+{
+  gboolean ret = FALSE;
+  GstMapInfo map;
+  guint val, iindex, icc;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  val = GST_READ_UINT16_BE (map.data) >> 5;
+  gst_buffer_unmap (buf, &map);
+
+  iindex = val >> 3;
+  icc = val & 0x7;
+
+  GST_LOG_OBJECT (rtpmpadepay, "sync: 0x%x, index: %u, cycle count: %u",
+      val, iindex, icc);
+
+  /* basic case; no interleaving ever seen */
+  if (val == 0x7ff && rtpmpadepay->last_icc < 0) {
+    ret = gst_rtp_mpa_robust_depay_queue_frame (rtpmpadepay, buf);
+  } else {
+    if (G_UNLIKELY (rtpmpadepay->last_icc < 0)) {
+      rtpmpadepay->last_icc = icc;
+      rtpmpadepay->last_ii = iindex;
+    }
+    if (icc != rtpmpadepay->last_icc || iindex == rtpmpadepay->last_ii) {
+      gint i;
+
+      for (i = 0; i < 256; ++i) {
+        if (rtpmpadepay->deinter[i] != NULL) {
+          ret |= gst_rtp_mpa_robust_depay_queue_frame (rtpmpadepay,
+              rtpmpadepay->deinter[i]);
+          rtpmpadepay->deinter[i] = NULL;
+        }
+      }
+    }
+    /* rewrite buffer sync header */
+    gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+    val = GST_READ_UINT16_BE (map.data);
+    val = (0x7ff << 5) | val;
+    GST_WRITE_UINT16_BE (map.data, val);
+    gst_buffer_unmap (buf, &map);
+    /* store and keep track of last indices */
+    rtpmpadepay->last_icc = icc;
+    rtpmpadepay->last_ii = iindex;
+    rtpmpadepay->deinter[iindex] = buf;
+  }
+
+  return ret;
+}
+
+/* Head ADU frame corresponds to mp3_frame (i.e. in header in side-info) that
+ * is currently being written
+ * cur_adu_frame refers to ADU frame whose data should be bytewritten next
+ * (possibly starting from offset rather than start 0) (and is typicall tail
+ * at time of last push round).
+ * If at start, position where it should start writing depends on (data) sizes
+ * of previous mp3 frames (corresponding to foregoing ADU frames) kept in size,
+ * and its backpointer */
+static GstFlowReturn
+gst_rtp_mpa_robust_depay_push_mp3_frames (GstRtpMPARobustDepay * rtpmpadepay)
+{
+  GstBuffer *buf;
+  GstADUFrame *frame, *head;
+  gint av;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  while (1) {
+    GstMapInfo map;
+
+    if (G_UNLIKELY (!rtpmpadepay->cur_adu_frame)) {
+      rtpmpadepay->cur_adu_frame = rtpmpadepay->adu_frames->head;
+      rtpmpadepay->offset = 0;
+      rtpmpadepay->size = 0;
+    }
+
+    if (G_UNLIKELY (!rtpmpadepay->cur_adu_frame))
+      break;
+
+    frame = (GstADUFrame *) rtpmpadepay->cur_adu_frame->data;
+    head = (GstADUFrame *) rtpmpadepay->adu_frames->head->data;
+
+    /* special case: non-layer III are sent straight through */
+    if (G_UNLIKELY (frame->layer != 3)) {
+      GST_DEBUG_OBJECT (rtpmpadepay, "layer %d frame, sending as-is",
+          frame->layer);
+      gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpmpadepay),
+          frame->buffer);
+      frame->buffer = NULL;
+      /* and remove it from any further consideration */
+      g_slice_free (GstADUFrame, frame);
+      g_queue_delete_link (rtpmpadepay->adu_frames, rtpmpadepay->cur_adu_frame);
+      rtpmpadepay->cur_adu_frame = NULL;
+      continue;
+    }
+
+    if (rtpmpadepay->offset == gst_buffer_get_size (frame->buffer)) {
+      if (g_list_next (rtpmpadepay->cur_adu_frame)) {
+        rtpmpadepay->size += frame->data_size;
+        rtpmpadepay->cur_adu_frame = g_list_next (rtpmpadepay->cur_adu_frame);
+        frame = (GstADUFrame *) rtpmpadepay->cur_adu_frame->data;
+        rtpmpadepay->offset = 0;
+        GST_LOG_OBJECT (rtpmpadepay,
+            "moving to next ADU frame, size %d, side_info %d, backpointer %d",
+            frame->size, frame->side_info, frame->backpointer);
+        /* layer I and II packets have no bitreservoir and must be sent as-is;
+         * so flush any pending frame */
+        if (G_UNLIKELY (frame->layer != 3 && rtpmpadepay->mp3_frame))
+          goto flush;
+      } else {
+        break;
+      }
+    }
+
+    if (G_UNLIKELY (!rtpmpadepay->mp3_frame)) {
+      GST_LOG_OBJECT (rtpmpadepay,
+          "setting up new MP3 frame of size %d, side_info %d",
+          head->size, head->side_info);
+      rtpmpadepay->mp3_frame = gst_byte_writer_new_with_size (head->size, TRUE);
+      /* 0-fill possible gaps */
+      gst_byte_writer_fill_unchecked (rtpmpadepay->mp3_frame, 0, head->size);
+      gst_byte_writer_set_pos (rtpmpadepay->mp3_frame, 0);
+      /* bytewriter corresponds to head frame,
+       * i.e. the header and the side info must match */
+      g_assert (4 + head->side_info <= head->size);
+      gst_buffer_map (head->buffer, &map, GST_MAP_READ);
+      gst_byte_writer_put_data_unchecked (rtpmpadepay->mp3_frame,
+          map.data, 4 + head->side_info);
+      gst_buffer_unmap (head->buffer, &map);
+    }
+
+    buf = frame->buffer;
+    av = gst_byte_writer_get_remaining (rtpmpadepay->mp3_frame);
+    GST_LOG_OBJECT (rtpmpadepay, "current mp3 frame remaining: %d", av);
+    GST_LOG_OBJECT (rtpmpadepay, "accumulated ADU frame data_size: %d",
+        rtpmpadepay->size);
+
+    if (rtpmpadepay->offset) {
+      gst_buffer_map (buf, &map, GST_MAP_READ);
+      /* no need to position, simply append */
+      g_assert (map.size > rtpmpadepay->offset);
+      av = MIN (av, map.size - rtpmpadepay->offset);
+      GST_LOG_OBJECT (rtpmpadepay,
+          "appending %d bytes from ADU frame at offset %d", av,
+          rtpmpadepay->offset);
+      gst_byte_writer_put_data_unchecked (rtpmpadepay->mp3_frame,
+          map.data + rtpmpadepay->offset, av);
+      rtpmpadepay->offset += av;
+      gst_buffer_unmap (buf, &map);
+    } else {
+      gint pos, tpos;
+
+      /* position writing according to ADU frame backpointer */
+      pos = gst_byte_writer_get_pos (rtpmpadepay->mp3_frame);
+      tpos = rtpmpadepay->size - frame->backpointer + 4 + head->side_info;
+      GST_LOG_OBJECT (rtpmpadepay, "current MP3 frame at position %d, "
+          "starting new ADU frame data at offset %d", pos, tpos);
+      if (tpos < pos) {
+        GstADUFrame *dummy;
+
+        /* try to insert as few frames as possible,
+         * so go for a reasonably large dummy frame size */
+        GST_LOG_OBJECT (rtpmpadepay,
+            "overlapping previous data; inserting dummy frame");
+        dummy =
+            gst_rtp_mpa_robust_depay_generate_dummy_frame (rtpmpadepay, frame);
+        g_queue_insert_before (rtpmpadepay->adu_frames,
+            rtpmpadepay->cur_adu_frame, dummy);
+        /* offset is known to be zero, so we can shift current one */
+        rtpmpadepay->cur_adu_frame = rtpmpadepay->cur_adu_frame->prev;
+        if (!rtpmpadepay->size) {
+          g_assert (rtpmpadepay->cur_adu_frame ==
+              rtpmpadepay->adu_frames->head);
+          GST_LOG_OBJECT (rtpmpadepay, "... which is new head frame");
+          gst_byte_writer_free (rtpmpadepay->mp3_frame);
+          rtpmpadepay->mp3_frame = NULL;
+        }
+        /* ... and continue adding that empty one immediately,
+         * and then see if that provided enough extra space */
+        continue;
+      } else if (tpos >= pos + av) {
+        /* ADU frame no longer needs current MP3 frame; move to its end */
+        GST_LOG_OBJECT (rtpmpadepay, "passed current MP3 frame");
+        gst_byte_writer_set_pos (rtpmpadepay->mp3_frame, pos + av);
+      } else {
+        /* position and append */
+        gst_buffer_map (buf, &map, GST_MAP_READ);
+        GST_LOG_OBJECT (rtpmpadepay, "adding to current MP3 frame");
+        gst_byte_writer_set_pos (rtpmpadepay->mp3_frame, tpos);
+        av -= (tpos - pos);
+        g_assert (map.size >= 4 + frame->side_info);
+        av = MIN (av, map.size - 4 - frame->side_info);
+        gst_byte_writer_put_data_unchecked (rtpmpadepay->mp3_frame,
+            map.data + 4 + frame->side_info, av);
+        rtpmpadepay->offset += av + 4 + frame->side_info;
+        gst_buffer_unmap (buf, &map);
+      }
+    }
+
+    /* if mp3 frame filled, send on its way */
+    if (gst_byte_writer_get_remaining (rtpmpadepay->mp3_frame) == 0) {
+    flush:
+      buf = gst_byte_writer_free_and_get_buffer (rtpmpadepay->mp3_frame);
+      rtpmpadepay->mp3_frame = NULL;
+      GST_BUFFER_PTS (buf) = GST_BUFFER_PTS (head->buffer);
+      /* no longer need head ADU frame header and side info */
+      /* NOTE maybe head == current, then size and offset go off a bit,
+       * but current gets reset to NULL, and then also offset and size */
+      rtpmpadepay->size -= head->data_size;
+      gst_rtp_mpa_robust_depay_dequeue_frame (rtpmpadepay);
+      /* send */
+      ret = gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpmpadepay),
+          buf);
+    }
+  }
+
+  return ret;
+}
+
+/* process ADU frame @buf through:
+ * - deinterleaving
+ * - converting to MP3 frames
+ * Takes ownership of @buf.
+ */
+static GstFlowReturn
+gst_rtp_mpa_robust_depay_submit_adu (GstRtpMPARobustDepay * rtpmpadepay,
+    GstBuffer * buf)
+{
+  if (gst_rtp_mpa_robust_depay_deinterleave (rtpmpadepay, buf))
+    return gst_rtp_mpa_robust_depay_push_mp3_frames (rtpmpadepay);
+
+  return GST_FLOW_OK;
+}
+
+static GstBuffer *
+gst_rtp_mpa_robust_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp)
+{
+  GstRtpMPARobustDepay *rtpmpadepay;
+  gint payload_len, offset;
+  guint8 *payload;
+  gboolean cont, dtype;
+  guint av, size;
+  GstClockTime timestamp;
+  GstBuffer *buf;
+
+  rtpmpadepay = GST_RTP_MPA_ROBUST_DEPAY (depayload);
+
+  timestamp = GST_BUFFER_PTS (rtp->buffer);
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+  if (payload_len <= 1)
+    goto short_read;
+
+  payload = gst_rtp_buffer_get_payload (rtp);
+  offset = 0;
+  GST_LOG_OBJECT (rtpmpadepay, "payload_len: %d", payload_len);
+
+  /* strip off descriptor
+   *
+   *  0                   1
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |C|T|            ADU size         |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   *
+   * C: if 1, data is continuation
+   * T: if 1, size is 14 bits, otherwise 6 bits
+   * ADU size: size of following packet (not including descriptor)
+   */
+  while (payload_len) {
+    if (G_LIKELY (rtpmpadepay->has_descriptor)) {
+      cont = ! !(payload[offset] & 0x80);
+      dtype = ! !(payload[offset] & 0x40);
+      if (dtype) {
+        size = (payload[offset] & 0x3f) << 8 | payload[offset + 1];
+        payload_len--;
+        offset++;
+      } else if (payload_len >= 2) {
+        size = (payload[offset] & 0x3f);
+        payload_len -= 2;
+        offset += 2;
+      } else {
+        goto short_read;
+      }
+    } else {
+      cont = FALSE;
+      dtype = -1;
+      size = payload_len;
+    }
+
+    GST_LOG_OBJECT (rtpmpadepay, "offset %d has cont: %d, dtype: %d, size: %d",
+        offset, cont, dtype, size);
+
+    buf = gst_rtp_buffer_get_payload_subbuffer (rtp, offset,
+        MIN (size, payload_len));
+
+    if (cont) {
+      av = gst_adapter_available (rtpmpadepay->adapter);
+      if (G_UNLIKELY (!av)) {
+        GST_DEBUG_OBJECT (rtpmpadepay,
+            "discarding continuation fragment without prior fragment");
+        gst_buffer_unref (buf);
+      } else {
+        av += gst_buffer_get_size (buf);
+        gst_adapter_push (rtpmpadepay->adapter, buf);
+        if (av == size) {
+          timestamp = gst_adapter_prev_pts (rtpmpadepay->adapter, NULL);
+          buf = gst_adapter_take_buffer (rtpmpadepay->adapter, size);
+          GST_BUFFER_PTS (buf) = timestamp;
+          gst_rtp_mpa_robust_depay_submit_adu (rtpmpadepay, buf);
+        } else if (av > size) {
+          GST_DEBUG_OBJECT (rtpmpadepay,
+              "assembled ADU size %d larger than expected %d; discarding",
+              av, size);
+          gst_adapter_clear (rtpmpadepay->adapter);
+        }
+      }
+      size = payload_len;
+    } else {
+      /* not continuation, first fragment or whole ADU */
+      if (payload_len == size) {
+        /* whole ADU */
+        GST_BUFFER_PTS (buf) = timestamp;
+        gst_rtp_mpa_robust_depay_submit_adu (rtpmpadepay, buf);
+      } else if (payload_len < size) {
+        /* first fragment */
+        gst_adapter_push (rtpmpadepay->adapter, buf);
+        size = payload_len;
+      }
+    }
+
+    offset += size;
+    payload_len -= size;
+
+    /* timestamp applies to first payload, no idea for subsequent ones */
+    timestamp = GST_CLOCK_TIME_NONE;
+  }
+
+  return NULL;
+
+  /* ERRORS */
+short_read:
+  {
+    GST_ELEMENT_WARNING (rtpmpadepay, STREAM, DECODE,
+        (NULL), ("Packet contains invalid data"));
+    return NULL;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_mpa_robust_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstRtpMPARobustDepay *rtpmpadepay;
+
+  rtpmpadepay = GST_RTP_MPA_ROBUST_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      rtpmpadepay->last_ii = -1;
+      rtpmpadepay->last_icc = -1;
+      rtpmpadepay->size = 0;
+      rtpmpadepay->offset = 0;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret != GST_STATE_CHANGE_SUCCESS)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+    {
+      gint i;
+
+      gst_adapter_clear (rtpmpadepay->adapter);
+      for (i = 0; i < G_N_ELEMENTS (rtpmpadepay->deinter); i++) {
+        gst_buffer_replace (&rtpmpadepay->deinter[i], NULL);
+      }
+      rtpmpadepay->cur_adu_frame = NULL;
+      g_queue_foreach (rtpmpadepay->adu_frames,
+          (GFunc) gst_rtp_mpa_robust_depay_free_frame, NULL);
+      g_queue_clear (rtpmpadepay->adu_frames);
+      if (rtpmpadepay->mp3_frame)
+        gst_byte_writer_free (rtpmpadepay->mp3_frame);
+      break;
+    }
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+gboolean
+gst_rtp_mpa_robust_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpmparobustdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_MPA_ROBUST_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmparobustdepay.h b/gst/rtp/gstrtpmparobustdepay.h
new file mode 100644
index 0000000..fc9ec0b
--- /dev/null
+++ b/gst/rtp/gstrtpmparobustdepay.h
@@ -0,0 +1,78 @@
+/* GStreamer
+ * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ * Copyright (C) <2010> Nokia Corporation
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MPA_ROBUST_DEPAY_H__
+#define __GST_RTP_MPA_ROBUST_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+#include <gst/base/gstadapter.h>
+#include <gst/base/gstbytewriter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MPA_ROBUST_DEPAY \
+  (gst_rtp_mpa_robust_depay_get_type())
+#define GST_RTP_MPA_ROBUST_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MPA_ROBUST_DEPAY,GstRtpMPARobustDepay))
+#define GST_RTP_MPA_ROBUST_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MPA_ROBUST_DEPAY,GstRtpMPARobustDepayClass))
+#define GST_IS_RTP_MPA_ROBUST_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MPA_ROBUST_DEPAY))
+#define GST_IS_RTP_MPA_ROBUST_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MPA_ROBUST_DEPAY))
+
+typedef struct _GstRtpMPARobustDepay GstRtpMPARobustDepay;
+typedef struct _GstRtpMPARobustDepayClass GstRtpMPARobustDepayClass;
+
+struct _GstRtpMPARobustDepay
+{
+  GstRTPBaseDepayload depayload;
+
+  GstAdapter *adapter;
+  gboolean    has_descriptor;
+
+  /* last interleave index */
+  gint        last_ii;
+  /* last interleave cycle count */
+  gint        last_icc;
+  /* buffers pending deinterleaving */
+  GstBuffer   *deinter[256];
+
+  /* ADU buffers pending MP3 transformation */
+  GQueue      *adu_frames;
+  GList       *cur_adu_frame;
+  gint         offset;
+  gint         size;
+  GstByteWriter *mp3_frame;
+};
+
+struct _GstRtpMPARobustDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mpa_robust_depay_get_type (void);
+
+gboolean gst_rtp_mpa_robust_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MPA_ROBUST_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpmpvdepay.c b/gst/rtp/gstrtpmpvdepay.c
new file mode 100644
index 0000000..9731946
--- /dev/null
+++ b/gst/rtp/gstrtpmpvdepay.c
@@ -0,0 +1,198 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+
+#include <string.h>
+#include "gstrtpmpvdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmpvdepay_debug);
+#define GST_CAT_DEFAULT (rtpmpvdepay_debug)
+
+/* FIXME, we set the mpeg version to 2, we should ideally be looking at contents
+ * of the stream to figure out the version */
+static GstStaticPadTemplate gst_rtp_mpv_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS
+    ("video/mpeg, mpegversion = (int) 2, systemstream = (boolean) FALSE")
+    );
+
+static GstStaticPadTemplate gst_rtp_mpv_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"MPV\";"
+        "application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_MPV_STRING ", "
+        "clock-rate = (int) 90000")
+    );
+
+G_DEFINE_TYPE (GstRtpMPVDepay, gst_rtp_mpv_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_mpv_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_mpv_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+static void
+gst_rtp_mpv_depay_class_init (GstRtpMPVDepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mpv_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mpv_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP MPEG video depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts MPEG video from RTP packets (RFC 2250)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstrtpbasedepayload_class->set_caps = gst_rtp_mpv_depay_setcaps;
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_mpv_depay_process;
+
+  GST_DEBUG_CATEGORY_INIT (rtpmpvdepay_debug, "rtpmpvdepay", 0,
+      "MPEG Video RTP Depayloader");
+}
+
+static void
+gst_rtp_mpv_depay_init (GstRtpMPVDepay * rtpmpvdepay)
+{
+}
+
+static gboolean
+gst_rtp_mpv_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  gint clock_rate;
+  GstCaps *outcaps;
+  gboolean res;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;         /* default */
+  depayload->clock_rate = clock_rate;
+
+  outcaps = gst_caps_new_simple ("video/mpeg",
+      "mpegversion", G_TYPE_INT, 2,
+      "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+  res = gst_pad_set_caps (depayload->srcpad, outcaps);
+  gst_caps_unref (outcaps);
+
+  return res;
+}
+
+static GstBuffer *
+gst_rtp_mpv_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpMPVDepay *rtpmpvdepay;
+  GstBuffer *outbuf = NULL;
+
+  rtpmpvdepay = GST_RTP_MPV_DEPAY (depayload);
+
+  {
+    gint payload_len, payload_header;
+    guint8 *payload;
+    guint8 T;
+
+    payload_len = gst_rtp_buffer_get_payload_len (rtp);
+    payload = gst_rtp_buffer_get_payload (rtp);
+    payload_header = 0;
+
+    if (payload_len <= 4)
+      goto empty_packet;
+
+    /* 3.4 MPEG Video-specific header
+     *
+     *  0                   1                   2                   3
+     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * |    MBZ  |T|         TR        | |N|S|B|E|  P  | | BFC | | FFC |
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     *                                  AN              FBV     FFV
+     */
+    T = (payload[0] & 0x04);
+
+    payload_len -= 4;
+    payload_header += 4;
+    payload += 4;
+
+    if (T) {
+      /* 
+       * 3.4.1 MPEG-2 Video-specific header extension
+       *
+       *  0                   1                   2                   3
+       *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       * |X|E|f_[0,0]|f_[0,1]|f_[1,0]|f_[1,1]| DC| PS|T|P|C|Q|V|A|R|H|G|D|
+       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       */
+      if (payload_len <= 4)
+        goto empty_packet;
+
+      payload_len -= 4;
+      payload_header += 4;
+      payload += 4;
+    }
+
+    outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, payload_header, -1);
+
+    if (outbuf) {
+      GST_DEBUG_OBJECT (rtpmpvdepay,
+          "gst_rtp_mpv_depay_chain: pushing buffer of size %" G_GSIZE_FORMAT,
+          gst_buffer_get_size (outbuf));
+      gst_rtp_drop_non_video_meta (rtpmpvdepay, outbuf);
+
+    }
+  }
+
+  return outbuf;
+
+  /* ERRORS */
+empty_packet:
+  {
+    GST_ELEMENT_WARNING (rtpmpvdepay, STREAM, DECODE,
+        (NULL), ("Empty payload."));
+    return NULL;
+  }
+}
+
+gboolean
+gst_rtp_mpv_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpmpvdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_MPV_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmpvdepay.h b/gst/rtp/gstrtpmpvdepay.h
new file mode 100644
index 0000000..80f6c43
--- /dev/null
+++ b/gst/rtp/gstrtpmpvdepay.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MPV_DEPAY_H__
+#define __GST_RTP_MPV_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MPV_DEPAY \
+  (gst_rtp_mpv_depay_get_type())
+#define GST_RTP_MPV_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MPV_DEPAY,GstRtpMPVDepay))
+#define GST_RTP_MPV_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MPV_DEPAY,GstRtpMPVDepayClass))
+#define GST_IS_RTP_MPV_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MPV_DEPAY))
+#define GST_IS_RTP_MPV_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MPV_DEPAY))
+
+typedef struct _GstRtpMPVDepay GstRtpMPVDepay;
+typedef struct _GstRtpMPVDepayClass GstRtpMPVDepayClass;
+
+struct _GstRtpMPVDepay
+{
+  GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpMPVDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mpv_depay_get_type (void);
+
+gboolean gst_rtp_mpv_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MPV_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpmpvpay.c b/gst/rtp/gstrtpmpvpay.c
new file mode 100644
index 0000000..eb73af2
--- /dev/null
+++ b/gst/rtp/gstrtpmpvpay.c
@@ -0,0 +1,335 @@
+/* GStreamer
+ * Copyright (C) <2007> Thijs Vermeir <thijsvermeir@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+
+#include "gstrtpmpvpay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmpvpay_debug);
+#define GST_CAT_DEFAULT (rtpmpvpay_debug)
+
+static GstStaticPadTemplate gst_rtp_mpv_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/mpeg, "
+        "mpegversion = (int) 2, systemstream = (boolean) FALSE")
+    );
+
+static GstStaticPadTemplate gst_rtp_mpv_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_MPV_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"MPV\"; "
+        "application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"MPV\"")
+    );
+
+static GstStateChangeReturn gst_rtp_mpv_pay_change_state (GstElement * element,
+    GstStateChange transition);
+
+static void gst_rtp_mpv_pay_finalize (GObject * object);
+
+static GstFlowReturn gst_rtp_mpv_pay_flush (GstRTPMPVPay * rtpmpvpay);
+static gboolean gst_rtp_mpv_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static GstFlowReturn gst_rtp_mpv_pay_handle_buffer (GstRTPBasePayload *
+    payload, GstBuffer * buffer);
+static gboolean gst_rtp_mpv_pay_sink_event (GstRTPBasePayload * payload,
+    GstEvent * event);
+
+#define gst_rtp_mpv_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPMPVPay, gst_rtp_mpv_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_mpv_pay_class_init (GstRTPMPVPayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_mpv_pay_finalize;
+
+  gstelement_class->change_state = gst_rtp_mpv_pay_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mpv_pay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mpv_pay_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP MPEG2 ES video payloader", "Codec/Payloader/Network/RTP",
+      "Payload-encodes MPEG2 ES into RTP packets (RFC 2250)",
+      "Thijs Vermeir <thijsvermeir@gmail.com>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_mpv_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_mpv_pay_handle_buffer;
+  gstrtpbasepayload_class->sink_event = gst_rtp_mpv_pay_sink_event;
+
+  GST_DEBUG_CATEGORY_INIT (rtpmpvpay_debug, "rtpmpvpay", 0,
+      "MPEG2 ES Video RTP Payloader");
+}
+
+static void
+gst_rtp_mpv_pay_init (GstRTPMPVPay * rtpmpvpay)
+{
+  GST_RTP_BASE_PAYLOAD (rtpmpvpay)->clock_rate = 90000;
+  GST_RTP_BASE_PAYLOAD_PT (rtpmpvpay) = GST_RTP_PAYLOAD_MPV;
+
+  rtpmpvpay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_mpv_pay_finalize (GObject * object)
+{
+  GstRTPMPVPay *rtpmpvpay;
+
+  rtpmpvpay = GST_RTP_MPV_PAY (object);
+
+  g_object_unref (rtpmpvpay->adapter);
+  rtpmpvpay->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_mpv_pay_reset (GstRTPMPVPay * pay)
+{
+  pay->first_ts = -1;
+  pay->duration = 0;
+  gst_adapter_clear (pay->adapter);
+  GST_DEBUG_OBJECT (pay, "reset depayloader");
+}
+
+static gboolean
+gst_rtp_mpv_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  gst_rtp_base_payload_set_options (payload, "video",
+      payload->pt != GST_RTP_PAYLOAD_MPV, "MPV", 90000);
+  return gst_rtp_base_payload_set_outcaps (payload, NULL);
+}
+
+static gboolean
+gst_rtp_mpv_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+  gboolean ret;
+  GstRTPMPVPay *rtpmpvpay;
+
+  rtpmpvpay = GST_RTP_MPV_PAY (payload);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+      /* make sure we push the last packets in the adapter on EOS */
+      gst_rtp_mpv_pay_flush (rtpmpvpay);
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      gst_rtp_mpv_pay_reset (rtpmpvpay);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+
+  return ret;
+}
+
+#define RTP_HEADER_LEN 12
+
+static GstFlowReturn
+gst_rtp_mpv_pay_flush (GstRTPMPVPay * rtpmpvpay)
+{
+  GstFlowReturn ret;
+  guint avail;
+  GstBufferList *list;
+  GstBuffer *outbuf;
+
+  guint8 *payload;
+
+  avail = gst_adapter_available (rtpmpvpay->adapter);
+
+  ret = GST_FLOW_OK;
+
+  GST_DEBUG_OBJECT (rtpmpvpay, "available %u", avail);
+  if (avail == 0)
+    return GST_FLOW_OK;
+
+  list =
+      gst_buffer_list_new_sized (avail / (GST_RTP_BASE_PAYLOAD_MTU (rtpmpvpay) -
+          RTP_HEADER_LEN) + 1);
+
+  while (avail > 0) {
+    guint towrite;
+    guint packet_len;
+    guint payload_len;
+    GstRTPBuffer rtp = { NULL };
+    GstBuffer *paybuf;
+
+    packet_len = gst_rtp_buffer_calc_packet_len (avail + 4, 0, 0);
+
+    towrite = MIN (packet_len, GST_RTP_BASE_PAYLOAD_MTU (rtpmpvpay));
+
+    payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+
+    outbuf = gst_rtp_buffer_new_allocate (4, 0, 0);
+
+    payload_len -= 4;
+
+    gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+    payload = gst_rtp_buffer_get_payload (&rtp);
+    /* enable MPEG Video-specific header
+     *
+     *  0                   1                   2                   3
+     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * |    MBZ  |T|         TR        | |N|S|B|E|  P  | | BFC | | FFC |
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     *                                  AN              FBV     FFV
+     */
+
+    /* fill in the MPEG Video-specific header 
+     * data is set to 0x0 here
+     */
+    memset (payload, 0x0, 4);
+
+    avail -= payload_len;
+
+    gst_rtp_buffer_set_marker (&rtp, avail == 0);
+    gst_rtp_buffer_unmap (&rtp);
+
+    paybuf = gst_adapter_take_buffer_fast (rtpmpvpay->adapter, payload_len);
+    gst_rtp_copy_video_meta (rtpmpvpay, outbuf, paybuf);
+    outbuf = gst_buffer_append (outbuf, paybuf);
+
+    GST_DEBUG_OBJECT (rtpmpvpay, "Adding buffer");
+
+    GST_BUFFER_PTS (outbuf) = rtpmpvpay->first_ts;
+    gst_buffer_list_add (list, outbuf);
+  }
+
+  ret = gst_rtp_base_payload_push_list (GST_RTP_BASE_PAYLOAD (rtpmpvpay), list);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_rtp_mpv_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRTPMPVPay *rtpmpvpay;
+  guint avail, packet_len;
+  GstClockTime timestamp, duration;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  rtpmpvpay = GST_RTP_MPV_PAY (basepayload);
+
+  timestamp = GST_BUFFER_PTS (buffer);
+  duration = GST_BUFFER_DURATION (buffer);
+
+  if (GST_BUFFER_IS_DISCONT (buffer)) {
+    GST_DEBUG_OBJECT (rtpmpvpay, "DISCONT");
+    gst_rtp_mpv_pay_reset (rtpmpvpay);
+  }
+
+  avail = gst_adapter_available (rtpmpvpay->adapter);
+
+  if (duration == -1)
+    duration = 0;
+
+  if (rtpmpvpay->first_ts == GST_CLOCK_TIME_NONE || avail == 0)
+    rtpmpvpay->first_ts = timestamp;
+
+  if (avail == 0) {
+    rtpmpvpay->duration = duration;
+  } else {
+    rtpmpvpay->duration += duration;
+  }
+
+  gst_adapter_push (rtpmpvpay->adapter, buffer);
+  avail = gst_adapter_available (rtpmpvpay->adapter);
+
+  /* get packet length of previous data and this new data,
+   * payload length includes a 4 byte MPEG video-specific header */
+  packet_len = gst_rtp_buffer_calc_packet_len (avail, 4, 0);
+  GST_LOG_OBJECT (rtpmpvpay, "available %d, rtp packet length %d", avail,
+      packet_len);
+
+  if (gst_rtp_base_payload_is_filled (basepayload,
+          packet_len, rtpmpvpay->duration)) {
+    ret = gst_rtp_mpv_pay_flush (rtpmpvpay);
+  } else {
+    rtpmpvpay->first_ts = timestamp;
+  }
+
+  return ret;
+}
+
+static GstStateChangeReturn
+gst_rtp_mpv_pay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRTPMPVPay *rtpmpvpay;
+  GstStateChangeReturn ret;
+
+  rtpmpvpay = GST_RTP_MPV_PAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_mpv_pay_reset (rtpmpvpay);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_mpv_pay_reset (rtpmpvpay);
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+
+gboolean
+gst_rtp_mpv_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpmpvpay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_MPV_PAY);
+}
diff --git a/gst/rtp/gstrtpmpvpay.h b/gst/rtp/gstrtpmpvpay.h
new file mode 100644
index 0000000..bcebad9
--- /dev/null
+++ b/gst/rtp/gstrtpmpvpay.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <2007> Thijs Vermeir <thijsvermeir@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_RTP_MPV_PAY_H__
+#define __GST_RTP_MPV_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTPMPVPay GstRTPMPVPay;
+typedef struct _GstRTPMPVPayClass GstRTPMPVPayClass;
+
+#define GST_TYPE_RTP_MPV_PAY \
+  (gst_rtp_mpv_pay_get_type())
+#define GST_RTP_MPV_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MPV_PAY,GstRTPMPVPay))
+#define GST_RTP_MPV_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MPV_PAY,GstRTPMPVPayClass))
+#define GST_IS_RTP_MPV_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MPV_PAY))
+#define GST_IS_RTP_MPV_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MPV_PAY))
+
+struct _GstRTPMPVPay
+{
+  GstRTPBasePayload payload;
+
+  GstAdapter  *adapter;
+  GstClockTime first_ts;
+  GstClockTime duration;
+};
+
+struct _GstRTPMPVPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_mpv_pay_get_type (void);
+
+gboolean gst_rtp_mpv_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MPV_PAY_H__ */
diff --git a/gst/rtp/gstrtpopusdepay.c b/gst/rtp/gstrtpopusdepay.c
new file mode 100644
index 0000000..f672339
--- /dev/null
+++ b/gst/rtp/gstrtpopusdepay.c
@@ -0,0 +1,160 @@
+/*
+ * Opus Depayloader Gst Element
+ *
+ *   @author: Danilo Cesar Lemes de Paula <danilo.cesar@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+#include "gstrtpopusdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpopusdepay_debug);
+#define GST_CAT_DEFAULT (rtpopusdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_opus_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ","
+        "clock-rate = (int) 48000, "
+        "encoding-name = (string) { \"OPUS\", \"X-GST-OPUS-DRAFT-SPITTKA-00\" }")
+    );
+
+static GstStaticPadTemplate gst_rtp_opus_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-opus, channel-mapping-family = (int) 0")
+    );
+
+static GstBuffer *gst_rtp_opus_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp_buffer);
+static gboolean gst_rtp_opus_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+
+G_DEFINE_TYPE (GstRTPOpusDepay, gst_rtp_opus_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_opus_depay_class_init (GstRTPOpusDepayClass * klass)
+{
+  GstRTPBaseDepayloadClass *gstbasertpdepayload_class;
+  GstElementClass *element_class;
+
+  element_class = GST_ELEMENT_CLASS (klass);
+  gstbasertpdepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_opus_depay_src_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_opus_depay_sink_template);
+  gst_element_class_set_static_metadata (element_class,
+      "RTP Opus packet depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts Opus audio from RTP packets",
+      "Danilo Cesar Lemes de Paula <danilo.cesar@collabora.co.uk>");
+
+  gstbasertpdepayload_class->process_rtp_packet = gst_rtp_opus_depay_process;
+  gstbasertpdepayload_class->set_caps = gst_rtp_opus_depay_setcaps;
+
+  GST_DEBUG_CATEGORY_INIT (rtpopusdepay_debug, "rtpopusdepay", 0,
+      "Opus RTP Depayloader");
+}
+
+static void
+gst_rtp_opus_depay_init (GstRTPOpusDepay * rtpopusdepay)
+{
+
+}
+
+static gboolean
+gst_rtp_opus_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstCaps *srccaps;
+  GstStructure *s;
+  gboolean ret;
+  const gchar *sprop_stereo, *sprop_maxcapturerate;
+
+  srccaps =
+      gst_caps_new_simple ("audio/x-opus", "channel-mapping-family", G_TYPE_INT,
+      0, NULL);
+
+  s = gst_caps_get_structure (caps, 0);
+  if ((sprop_stereo = gst_structure_get_string (s, "sprop-stereo"))) {
+    if (strcmp (sprop_stereo, "0") == 0)
+      gst_caps_set_simple (srccaps, "channels", G_TYPE_INT, 1, NULL);
+    else if (strcmp (sprop_stereo, "1") == 0)
+      gst_caps_set_simple (srccaps, "channels", G_TYPE_INT, 2, NULL);
+    else
+      GST_WARNING_OBJECT (depayload, "Unknown sprop-stereo value '%s'",
+          sprop_stereo);
+  }
+
+  if ((sprop_maxcapturerate =
+          gst_structure_get_string (s, "sprop-maxcapturerate"))) {
+    gulong rate;
+    gchar *tailptr;
+
+    rate = strtoul (sprop_maxcapturerate, &tailptr, 10);
+    if (rate > INT_MAX || *tailptr != '\0') {
+      GST_WARNING_OBJECT (depayload,
+          "Failed to parse sprop-maxcapturerate value '%s'",
+          sprop_maxcapturerate);
+    } else {
+      gst_caps_set_simple (srccaps, "rate", G_TYPE_INT, rate, NULL);
+    }
+  }
+
+  ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+
+  GST_DEBUG_OBJECT (depayload,
+      "set caps on source: %" GST_PTR_FORMAT " (ret=%d)", srccaps, ret);
+  gst_caps_unref (srccaps);
+
+  depayload->clock_rate = 48000;
+
+  return ret;
+}
+
+static GstBuffer *
+gst_rtp_opus_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp_buffer)
+{
+  GstBuffer *outbuf;
+
+  outbuf = gst_rtp_buffer_get_payload_buffer (rtp_buffer);
+
+  gst_rtp_drop_non_audio_meta (depayload, outbuf);
+
+  return outbuf;
+}
+
+gboolean
+gst_rtp_opus_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpopusdepay",
+      GST_RANK_PRIMARY, GST_TYPE_RTP_OPUS_DEPAY);
+}
diff --git a/gst/rtp/gstrtpopusdepay.h b/gst/rtp/gstrtpopusdepay.h
new file mode 100644
index 0000000..38cc851
--- /dev/null
+++ b/gst/rtp/gstrtpopusdepay.h
@@ -0,0 +1,59 @@
+/*
+ * Opus Depayloader Gst Element
+ *
+ *   @author: Danilo Cesar Lemes de Paula <danilo.eu@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_OPUS_DEPAY_H__
+#define __GST_RTP_OPUS_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS typedef struct _GstRTPOpusDepay GstRTPOpusDepay;
+typedef struct _GstRTPOpusDepayClass GstRTPOpusDepayClass;
+
+#define GST_TYPE_RTP_OPUS_DEPAY \
+  (gst_rtp_opus_depay_get_type())
+#define GST_RTP_OPUS_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_OPUS_DEPAY,GstRTPOpusDepay))
+#define GST_RTP_OPUS_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_OPUS_DEPAY,GstRTPOpusDepayClass))
+#define GST_IS_RTP_OPUS_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_OPUS_DEPAY))
+#define GST_IS_RTP_OPUS_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_OPUS_DEPAY))
+
+
+struct _GstRTPOpusDepay
+{
+  GstRTPBaseDepayload depayload;
+
+};
+
+struct _GstRTPOpusDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_opus_depay_get_type (void);
+
+gboolean gst_rtp_opus_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_OPUS_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpopuspay.c b/gst/rtp/gstrtpopuspay.c
new file mode 100644
index 0000000..b610885
--- /dev/null
+++ b/gst/rtp/gstrtpopuspay.c
@@ -0,0 +1,255 @@
+/*
+ * Opus Payloader Gst Element
+ *
+ *   @author: Danilo Cesar Lemes de Paula <danilo.cesar@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpopuspay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpopuspay_debug);
+#define GST_CAT_DEFAULT (rtpopuspay_debug)
+
+
+static GstStaticPadTemplate gst_rtp_opus_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS
+    ("audio/x-opus, channels = (int) [1, 2], channel-mapping-family = (int) 0")
+    );
+
+static GstStaticPadTemplate gst_rtp_opus_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 48000, "
+        "encoding-params = (string) \"2\", "
+        "encoding-name = (string) { \"OPUS\", \"X-GST-OPUS-DRAFT-SPITTKA-00\" }")
+    );
+
+static gboolean gst_rtp_opus_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static GstCaps *gst_rtp_opus_pay_getcaps (GstRTPBasePayload * payload,
+    GstPad * pad, GstCaps * filter);
+static GstFlowReturn gst_rtp_opus_pay_handle_buffer (GstRTPBasePayload *
+    payload, GstBuffer * buffer);
+
+G_DEFINE_TYPE (GstRtpOPUSPay, gst_rtp_opus_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_opus_pay_class_init (GstRtpOPUSPayClass * klass)
+{
+  GstRTPBasePayloadClass *gstbasertppayload_class;
+  GstElementClass *element_class;
+
+  gstbasertppayload_class = (GstRTPBasePayloadClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gstbasertppayload_class->set_caps = gst_rtp_opus_pay_setcaps;
+  gstbasertppayload_class->get_caps = gst_rtp_opus_pay_getcaps;
+  gstbasertppayload_class->handle_buffer = gst_rtp_opus_pay_handle_buffer;
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_opus_pay_src_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_opus_pay_sink_template);
+
+  gst_element_class_set_static_metadata (element_class,
+      "RTP Opus payloader",
+      "Codec/Payloader/Network/RTP",
+      "Puts Opus audio in RTP packets",
+      "Danilo Cesar Lemes de Paula <danilo.cesar@collabora.co.uk>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpopuspay_debug, "rtpopuspay", 0,
+      "Opus RTP Payloader");
+}
+
+static void
+gst_rtp_opus_pay_init (GstRtpOPUSPay * rtpopuspay)
+{
+}
+
+static gboolean
+gst_rtp_opus_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  gboolean res;
+  GstCaps *src_caps;
+  GstStructure *s;
+  char *encoding_name;
+  gint channels, rate;
+  const char *sprop_stereo = NULL;
+  char *sprop_maxcapturerate = NULL;
+
+  src_caps = gst_pad_get_allowed_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload));
+  if (src_caps) {
+    src_caps = gst_caps_make_writable (src_caps);
+    src_caps = gst_caps_truncate (src_caps);
+    s = gst_caps_get_structure (src_caps, 0);
+    gst_structure_fixate_field_string (s, "encoding-name", "OPUS");
+    encoding_name = g_strdup (gst_structure_get_string (s, "encoding-name"));
+    gst_caps_unref (src_caps);
+  } else {
+    encoding_name = g_strdup ("X-GST-OPUS-DRAFT-SPITTKA-00");
+  }
+
+  s = gst_caps_get_structure (caps, 0);
+  if (gst_structure_get_int (s, "channels", &channels)) {
+    if (channels > 2) {
+      GST_ERROR_OBJECT (payload,
+          "More than 2 channels with channel-mapping-family=0 is invalid");
+      return FALSE;
+    } else if (channels == 2) {
+      sprop_stereo = "1";
+    } else {
+      sprop_stereo = "0";
+    }
+  }
+
+  if (gst_structure_get_int (s, "rate", &rate)) {
+    sprop_maxcapturerate = g_strdup_printf ("%d", rate);
+  }
+
+  gst_rtp_base_payload_set_options (payload, "audio", FALSE,
+      encoding_name, 48000);
+  g_free (encoding_name);
+
+  if (sprop_maxcapturerate && sprop_stereo) {
+    res =
+        gst_rtp_base_payload_set_outcaps (payload, "sprop-maxcapturerate",
+        G_TYPE_STRING, sprop_maxcapturerate, "sprop-stereo", G_TYPE_STRING,
+        sprop_stereo, NULL);
+  } else if (sprop_maxcapturerate) {
+    res =
+        gst_rtp_base_payload_set_outcaps (payload, "sprop-maxcapturerate",
+        G_TYPE_STRING, sprop_maxcapturerate, NULL);
+  } else if (sprop_stereo) {
+    res =
+        gst_rtp_base_payload_set_outcaps (payload, "sprop-stereo",
+        G_TYPE_STRING, sprop_stereo, NULL);
+  } else {
+    res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+  }
+
+  g_free (sprop_maxcapturerate);
+
+  return res;
+}
+
+static GstFlowReturn
+gst_rtp_opus_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstBuffer *outbuf;
+  GstClockTime pts, dts, duration;
+
+  pts = GST_BUFFER_PTS (buffer);
+  dts = GST_BUFFER_DTS (buffer);
+  duration = GST_BUFFER_DURATION (buffer);
+
+  outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+
+  gst_rtp_copy_audio_meta (basepayload, outbuf, buffer);
+
+  outbuf = gst_buffer_append (outbuf, buffer);
+
+  GST_BUFFER_PTS (outbuf) = pts;
+  GST_BUFFER_DTS (outbuf) = dts;
+  GST_BUFFER_DURATION (outbuf) = duration;
+
+  /* Push out */
+  return gst_rtp_base_payload_push (basepayload, outbuf);
+}
+
+static GstCaps *
+gst_rtp_opus_pay_getcaps (GstRTPBasePayload * payload,
+    GstPad * pad, GstCaps * filter)
+{
+  GstCaps *caps, *peercaps, *tcaps;
+  GstStructure *s;
+  const gchar *stereo;
+
+  if (pad == GST_RTP_BASE_PAYLOAD_SRCPAD (payload))
+    return
+        GST_RTP_BASE_PAYLOAD_CLASS (gst_rtp_opus_pay_parent_class)->get_caps
+        (payload, pad, filter);
+
+  tcaps = gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload));
+  peercaps = gst_pad_peer_query_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload),
+      tcaps);
+  gst_caps_unref (tcaps);
+  if (!peercaps)
+    return
+        GST_RTP_BASE_PAYLOAD_CLASS (gst_rtp_opus_pay_parent_class)->get_caps
+        (payload, pad, filter);
+
+  if (gst_caps_is_empty (peercaps))
+    return peercaps;
+
+  caps = gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SINKPAD (payload));
+
+  s = gst_caps_get_structure (peercaps, 0);
+  stereo = gst_structure_get_string (s, "stereo");
+  if (stereo != NULL) {
+    caps = gst_caps_make_writable (caps);
+
+    if (!strcmp (stereo, "1")) {
+      GstCaps *caps2 = gst_caps_copy (caps);
+
+      gst_caps_set_simple (caps, "channels", G_TYPE_INT, 2, NULL);
+      gst_caps_set_simple (caps2, "channels", G_TYPE_INT, 1, NULL);
+      caps = gst_caps_merge (caps, caps2);
+    } else if (!strcmp (stereo, "0")) {
+      GstCaps *caps2 = gst_caps_copy (caps);
+
+      gst_caps_set_simple (caps, "channels", G_TYPE_INT, 1, NULL);
+      gst_caps_set_simple (caps2, "channels", G_TYPE_INT, 2, NULL);
+      caps = gst_caps_merge (caps, caps2);
+    }
+  }
+  gst_caps_unref (peercaps);
+
+  if (filter) {
+    GstCaps *tmp = gst_caps_intersect_full (caps, filter,
+        GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    caps = tmp;
+  }
+
+  GST_DEBUG_OBJECT (payload, "Returning caps: %" GST_PTR_FORMAT, caps);
+  return caps;
+}
+
+gboolean
+gst_rtp_opus_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpopuspay",
+      GST_RANK_PRIMARY, GST_TYPE_RTP_OPUS_PAY);
+}
diff --git a/gst/rtp/gstrtpopuspay.h b/gst/rtp/gstrtpopuspay.h
new file mode 100644
index 0000000..45f40d8
--- /dev/null
+++ b/gst/rtp/gstrtpopuspay.h
@@ -0,0 +1,60 @@
+/*
+ * Opus Payloader Gst Element
+ *
+ *   @author: Danilo Cesar Lemes de Paula <danilo.eu@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_OPUS_PAY_H__
+#define __GST_RTP_OPUS_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_OPUS_PAY \
+  (gst_rtp_opus_pay_get_type())
+#define GST_RTP_OPUS_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_OPUS_PAY,GstRtpOPUSPay))
+#define GST_RTP_OPUS_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_OPUS_PAY,GstRtpOPUSPayClass))
+#define GST_IS_RTP_OPUS_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_OPUS_PAY))
+#define GST_IS_RTP_OPUS_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_OPUS_PAY))
+
+typedef struct _GstRtpOPUSPay GstRtpOPUSPay;
+typedef struct _GstRtpOPUSPayClass GstRtpOPUSPayClass;
+
+struct _GstRtpOPUSPay
+{
+  GstRTPBasePayload payload;
+};
+
+struct _GstRtpOPUSPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_opus_pay_get_type (void);
+
+gboolean gst_rtp_opus_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_OPUS_PAY_H__ */
diff --git a/gst/rtp/gstrtppcmadepay.c b/gst/rtp/gstrtppcmadepay.c
new file mode 100644
index 0000000..476a20a
--- /dev/null
+++ b/gst/rtp/gstrtppcmadepay.c
@@ -0,0 +1,164 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@gmail.com>
+ * Copyright (C) <2005> Zeeshan Ali <zeenix@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+#include "gstrtppcmadepay.h"
+#include "gstrtputils.h"
+
+/* RtpPcmaDepay signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0
+};
+
+static GstStaticPadTemplate gst_rtp_pcma_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_PCMA_STRING ", "
+        "clock-rate = (int) 8000;"
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) [1, MAX ], encoding-name = (string) \"PCMA\"")
+    );
+
+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) [1, MAX ]")
+    );
+
+static GstBuffer *gst_rtp_pcma_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+static gboolean gst_rtp_pcma_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+
+#define gst_rtp_pcma_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpPcmaDepay, gst_rtp_pcma_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_pcma_depay_class_init (GstRtpPcmaDepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_pcma_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_pcma_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP PCMA depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts PCMA audio from RTP packets",
+      "Edgard Lima <edgard.lima@gmail.com>, Zeeshan Ali <zeenix@gmail.com>");
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_pcma_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_pcma_depay_setcaps;
+}
+
+static void
+gst_rtp_pcma_depay_init (GstRtpPcmaDepay * rtppcmadepay)
+{
+  GstRTPBaseDepayload *depayload;
+
+  depayload = GST_RTP_BASE_DEPAYLOAD (rtppcmadepay);
+
+  gst_pad_use_fixed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload));
+}
+
+static gboolean
+gst_rtp_pcma_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstCaps *srccaps;
+  GstStructure *structure;
+  gboolean ret;
+  gint clock_rate;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 8000;          /* default */
+  depayload->clock_rate = clock_rate;
+
+  srccaps = gst_caps_new_simple ("audio/x-alaw",
+      "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, clock_rate, NULL);
+  ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+  gst_caps_unref (srccaps);
+
+  return ret;
+}
+
+static GstBuffer *
+gst_rtp_pcma_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstBuffer *outbuf = NULL;
+  gboolean marker;
+  guint len;
+
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+      gst_buffer_get_size (rtp->buffer), marker,
+      gst_rtp_buffer_get_timestamp (rtp), gst_rtp_buffer_get_seq (rtp));
+
+  len = gst_rtp_buffer_get_payload_len (rtp);
+  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);
+
+  if (outbuf) {
+    GST_BUFFER_DURATION (outbuf) =
+        gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate);
+
+    if (marker) {
+      /* mark start of talkspurt with RESYNC */
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+    }
+
+    gst_rtp_drop_non_audio_meta (depayload, outbuf);
+  }
+
+  return outbuf;
+}
+
+gboolean
+gst_rtp_pcma_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtppcmadepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_PCMA_DEPAY);
+}
diff --git a/gst/rtp/gstrtppcmadepay.h b/gst/rtp/gstrtppcmadepay.h
new file mode 100644
index 0000000..e664a2d
--- /dev/null
+++ b/gst/rtp/gstrtppcmadepay.h
@@ -0,0 +1,53 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 
+ */
+ 
+#ifndef __GST_RTP_PCMA_DEPAY_H__
+#define __GST_RTP_PCMA_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpPcmaDepay GstRtpPcmaDepay;
+typedef struct _GstRtpPcmaDepayClass GstRtpPcmaDepayClass;
+
+#define GST_TYPE_RTP_PCMA_DEPAY \
+  (gst_rtp_pcma_depay_get_type())
+#define GST_RTP_PCMA_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_PCMA_DEPAY,GstRtpPcmaDepay))
+#define GST_RTP_PCMA_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_PCMA_DEPAY,GstRtpPcmaDepayClass))
+#define GST_IS_RTP_PCMA_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_PCMA_DEPAY))
+#define GST_IS_RTP_PCMA_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_PCMA_DEPAY))
+
+struct _GstRtpPcmaDepay
+{
+  GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpPcmaDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_pcma_depay_get_type (void);
+
+gboolean gst_rtp_pcma_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_PCMA_DEPAY_H__ */
diff --git a/gst/rtp/gstrtppcmapay.c b/gst/rtp/gstrtppcmapay.c
new file mode 100644
index 0000000..fde1b64
--- /dev/null
+++ b/gst/rtp/gstrtppcmapay.c
@@ -0,0 +1,116 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@gmail.com>
+ * Copyright (C) <2005> Nokia Corporation <kai.vehmanen@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtppcmapay.h"
+
+static GstStaticPadTemplate gst_rtp_pcma_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-alaw, channels=(int)1, rate=(int)8000")
+    );
+
+static GstStaticPadTemplate gst_rtp_pcma_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_PCMA_STRING ", "
+        "clock-rate = (int) 8000, " "encoding-name = (string) \"PCMA\"; "
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"PCMA\"")
+    );
+
+static gboolean gst_rtp_pcma_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+
+#define gst_rtp_pcma_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpPcmaPay, gst_rtp_pcma_pay,
+    GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_pcma_pay_class_init (GstRtpPcmaPayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_pcma_pay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_pcma_pay_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP PCMA payloader",
+      "Codec/Payloader/Network/RTP",
+      "Payload-encodes PCMA audio into a RTP packet",
+      "Edgard Lima <edgard.lima@gmail.com>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_pcma_pay_setcaps;
+}
+
+static void
+gst_rtp_pcma_pay_init (GstRtpPcmaPay * rtppcmapay)
+{
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtppcmapay);
+
+  GST_RTP_BASE_PAYLOAD (rtppcmapay)->pt = GST_RTP_PAYLOAD_PCMA;
+  GST_RTP_BASE_PAYLOAD (rtppcmapay)->clock_rate = 8000;
+
+  /* tell rtpbaseaudiopayload that this is a sample based codec */
+  gst_rtp_base_audio_payload_set_sample_based (rtpbaseaudiopayload);
+
+  /* octet-per-sample is 1 for PCM */
+  gst_rtp_base_audio_payload_set_sample_options (rtpbaseaudiopayload, 1);
+}
+
+static gboolean
+gst_rtp_pcma_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  gboolean res;
+
+  gst_rtp_base_payload_set_options (payload, "audio",
+      payload->pt != GST_RTP_PAYLOAD_PCMA, "PCMA", 8000);
+  res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+  return res;
+}
+
+gboolean
+gst_rtp_pcma_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtppcmapay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_PCMA_PAY);
+}
diff --git a/gst/rtp/gstrtppcmapay.h b/gst/rtp/gstrtppcmapay.h
new file mode 100644
index 0000000..4e084ad
--- /dev/null
+++ b/gst/rtp/gstrtppcmapay.h
@@ -0,0 +1,54 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 
+ */
+
+
+#ifndef __GST_RTP_PCMA_PAY_H__
+#define __GST_RTP_PCMA_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpPcmaPay GstRtpPcmaPay;
+typedef struct _GstRtpPcmaPayClass GstRtpPcmaPayClass;
+
+#define GST_TYPE_RTP_PCMA_PAY \
+  (gst_rtp_pcma_pay_get_type())
+#define GST_RTP_PCMA_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_PCMA_PAY,GstRtpPcmaPay))
+#define GST_RTP_PCMA_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_PCMA_PAY,GstRtpPcmaPayClass))
+#define GST_IS_RTP_PCMA_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_PCMA_PAY))
+#define GST_IS_RTP_PCMA_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_PCMA_PAY))
+
+struct _GstRtpPcmaPay
+{
+  GstRTPBaseAudioPayload audiopayload;
+};
+
+struct _GstRtpPcmaPayClass
+{
+  GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_pcma_pay_get_type (void);
+
+gboolean gst_rtp_pcma_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_PCMA_PAY_H__ */
diff --git a/gst/rtp/gstrtppcmudepay.c b/gst/rtp/gstrtppcmudepay.c
new file mode 100644
index 0000000..1a06d18
--- /dev/null
+++ b/gst/rtp/gstrtppcmudepay.c
@@ -0,0 +1,165 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@gmail.com>
+ * Copyright (C) <2005> Zeeshan Ali <zeenix@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+#include "gstrtppcmudepay.h"
+#include "gstrtputils.h"
+
+/* RtpPcmuDepay signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0
+};
+
+static GstStaticPadTemplate gst_rtp_pcmu_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_PCMU_STRING ", "
+        "clock-rate = (int) 8000; "
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "encoding-name = (string) \"PCMU\", 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) [1, MAX ]")
+    );
+
+static GstBuffer *gst_rtp_pcmu_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+static gboolean gst_rtp_pcmu_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+
+#define gst_rtp_pcmu_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpPcmuDepay, gst_rtp_pcmu_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_pcmu_depay_class_init (GstRtpPcmuDepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_pcmu_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_pcmu_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP PCMU depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts PCMU audio from RTP packets",
+      "Edgard Lima <edgard.lima@gmail.com>, Zeeshan Ali <zeenix@gmail.com>");
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_pcmu_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_pcmu_depay_setcaps;
+}
+
+static void
+gst_rtp_pcmu_depay_init (GstRtpPcmuDepay * rtppcmudepay)
+{
+  GstRTPBaseDepayload *depayload;
+
+  depayload = GST_RTP_BASE_DEPAYLOAD (rtppcmudepay);
+
+  gst_pad_use_fixed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload));
+}
+
+static gboolean
+gst_rtp_pcmu_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstCaps *srccaps;
+  GstStructure *structure;
+  gboolean ret;
+  gint clock_rate;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 8000;          /* default */
+  depayload->clock_rate = clock_rate;
+
+  srccaps = gst_caps_new_simple ("audio/x-mulaw",
+      "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, clock_rate, NULL);
+  ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+  gst_caps_unref (srccaps);
+
+  return ret;
+}
+
+static GstBuffer *
+gst_rtp_pcmu_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstBuffer *outbuf = NULL;
+  guint len;
+  gboolean marker;
+
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+      gst_buffer_get_size (rtp->buffer), marker,
+      gst_rtp_buffer_get_timestamp (rtp), gst_rtp_buffer_get_seq (rtp));
+
+  len = gst_rtp_buffer_get_payload_len (rtp);
+  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);
+
+  if (outbuf) {
+    GST_BUFFER_DURATION (outbuf) =
+        gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate);
+
+    if (marker) {
+      /* mark start of talkspurt with RESYNC */
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+    }
+
+    gst_rtp_drop_non_audio_meta (depayload, outbuf);
+  }
+
+  return outbuf;
+}
+
+gboolean
+gst_rtp_pcmu_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtppcmudepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_PCMU_DEPAY);
+}
diff --git a/gst/rtp/gstrtppcmudepay.h b/gst/rtp/gstrtppcmudepay.h
new file mode 100644
index 0000000..6a97559
--- /dev/null
+++ b/gst/rtp/gstrtppcmudepay.h
@@ -0,0 +1,53 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 
+ */
+ 
+#ifndef __GST_RTP_PCMU_DEPAY_H__
+#define __GST_RTP_PCMU_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpPcmuDepay GstRtpPcmuDepay;
+typedef struct _GstRtpPcmuDepayClass GstRtpPcmuDepayClass;
+
+#define GST_TYPE_RTP_PCMU_DEPAY \
+  (gst_rtp_pcmu_depay_get_type())
+#define GST_RTP_PCMU_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_PCMU_DEPAY,GstRtpPcmuDepay))
+#define GST_RTP_PCMU_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_PCMU_DEPAY,GstRtpPcmuDepayClass))
+#define GST_IS_RTP_PCMU_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_PCMU_DEPAY))
+#define GST_IS_RTP_PCMU_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_PCMU_DEPAY))
+
+struct _GstRtpPcmuDepay
+{
+  GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpPcmuDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_pcmu_depay_get_type (void);
+
+gboolean gst_rtp_pcmu_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_PCMU_DEPAY_H__ */
diff --git a/gst/rtp/gstrtppcmupay.c b/gst/rtp/gstrtppcmupay.c
new file mode 100644
index 0000000..5931f85
--- /dev/null
+++ b/gst/rtp/gstrtppcmupay.c
@@ -0,0 +1,116 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@gmail.com>
+ * Copyright (C) <2005> Nokia Corporation <kai.vehmanen@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtppcmupay.h"
+
+static GstStaticPadTemplate gst_rtp_pcmu_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-mulaw, channels=(int)1, rate=(int)8000")
+    );
+
+static GstStaticPadTemplate gst_rtp_pcmu_pay_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_PCMU_STRING ", "
+        "clock-rate = (int) 8000, " "encoding-name = (string) \"PCMU\"; "
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"PCMU\"")
+    );
+
+static gboolean gst_rtp_pcmu_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+
+#define gst_rtp_pcmu_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpPcmuPay, gst_rtp_pcmu_pay,
+    GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_pcmu_pay_class_init (GstRtpPcmuPayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_pcmu_pay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_pcmu_pay_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP PCMU payloader",
+      "Codec/Payloader/Network/RTP",
+      "Payload-encodes PCMU audio into a RTP packet",
+      "Edgard Lima <edgard.lima@gmail.com>");
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_pcmu_pay_setcaps;
+}
+
+static void
+gst_rtp_pcmu_pay_init (GstRtpPcmuPay * rtppcmupay)
+{
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtppcmupay);
+
+  GST_RTP_BASE_PAYLOAD (rtppcmupay)->pt = GST_RTP_PAYLOAD_PCMU;
+  GST_RTP_BASE_PAYLOAD (rtppcmupay)->clock_rate = 8000;
+
+  /* tell rtpbaseaudiopayload that this is a sample based codec */
+  gst_rtp_base_audio_payload_set_sample_based (rtpbaseaudiopayload);
+
+  /* octet-per-sample is 1 for PCM */
+  gst_rtp_base_audio_payload_set_sample_options (rtpbaseaudiopayload, 1);
+}
+
+static gboolean
+gst_rtp_pcmu_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  gboolean res;
+
+  gst_rtp_base_payload_set_options (payload, "audio",
+      payload->pt != GST_RTP_PAYLOAD_PCMU, "PCMU", 8000);
+  res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+  return res;
+}
+
+gboolean
+gst_rtp_pcmu_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtppcmupay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_PCMU_PAY);
+}
diff --git a/gst/rtp/gstrtppcmupay.h b/gst/rtp/gstrtppcmupay.h
new file mode 100644
index 0000000..7529d46
--- /dev/null
+++ b/gst/rtp/gstrtppcmupay.h
@@ -0,0 +1,54 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 
+ */
+
+
+#ifndef __GST_RTP_PCMU_PAY_H__
+#define __GST_RTP_PCMU_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpPcmuPay GstRtpPcmuPay;
+typedef struct _GstRtpPcmuPayClass GstRtpPcmuPayClass;
+
+#define GST_TYPE_RTP_PCMU_PAY \
+  (gst_rtp_pcmu_pay_get_type())
+#define GST_RTP_PCMU_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_PCMU_PAY,GstRtpPcmuPay))
+#define GST_RTP_PCMU_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_PCMU_PAY,GstRtpPcmuPayClass))
+#define GST_IS_RTP_PCMU_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_PCMU_PAY))
+#define GST_IS_RTP_PCMU_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_PCMU_PAY))
+
+struct _GstRtpPcmuPay
+{
+  GstRTPBaseAudioPayload audiopayload;
+};
+
+struct _GstRtpPcmuPayClass
+{
+  GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_pcmu_pay_get_type (void);
+
+gboolean gst_rtp_pcmu_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_PCMU_PAY_H__ */
diff --git a/gst/rtp/gstrtpqcelpdepay.c b/gst/rtp/gstrtpqcelpdepay.c
new file mode 100644
index 0000000..cb5d9eb
--- /dev/null
+++ b/gst/rtp/gstrtpqcelpdepay.c
@@ -0,0 +1,432 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include "gstrtpqcelpdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpqcelpdepay_debug);
+#define GST_CAT_DEFAULT (rtpqcelpdepay_debug)
+
+/* references:
+ *
+ * RFC 2658 - RTP Payload Format for PureVoice(tm) Audio
+ */
+#define FRAME_DURATION (20 * GST_MSECOND)
+
+/* RtpQCELPDepay signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0
+};
+
+static GstStaticPadTemplate gst_rtp_qcelp_depay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) 8000, "
+        "encoding-name = (string) \"QCELP\"; "
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_QCELP_STRING ", "
+        "clock-rate = (int) 8000")
+    );
+
+static GstStaticPadTemplate gst_rtp_qcelp_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/qcelp, " "channels = (int) 1," "rate = (int) 8000")
+    );
+
+static void gst_rtp_qcelp_depay_finalize (GObject * object);
+
+static gboolean gst_rtp_qcelp_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_qcelp_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+#define gst_rtp_qcelp_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpQCELPDepay, gst_rtp_qcelp_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_qcelp_depay_class_init (GstRtpQCELPDepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_qcelp_depay_finalize;
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_qcelp_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_qcelp_depay_setcaps;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_qcelp_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_qcelp_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP QCELP depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts QCELP (PureVoice) audio from RTP packets (RFC 2658)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpqcelpdepay_debug, "rtpqcelpdepay", 0,
+      "QCELP RTP Depayloader");
+}
+
+static void
+gst_rtp_qcelp_depay_init (GstRtpQCELPDepay * rtpqcelpdepay)
+{
+}
+
+static void
+gst_rtp_qcelp_depay_finalize (GObject * object)
+{
+  GstRtpQCELPDepay *depay;
+
+  depay = GST_RTP_QCELP_DEPAY (object);
+
+  if (depay->packets != NULL) {
+    g_ptr_array_foreach (depay->packets, (GFunc) gst_buffer_unref, NULL);
+    g_ptr_array_free (depay->packets, TRUE);
+    depay->packets = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static gboolean
+gst_rtp_qcelp_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstCaps *srccaps;
+  gboolean res;
+
+  srccaps = gst_caps_new_simple ("audio/qcelp",
+      "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL);
+  res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+  gst_caps_unref (srccaps);
+
+  return res;
+}
+
+static const gint frame_size[16] = {
+  1, 4, 8, 17, 35, -8, 0, 0,
+  0, 0, 0, 0, 0, 0, 1, 0
+};
+
+/* get the frame length, 0 is invalid, negative values are invalid but can be
+ * recovered from. */
+static gint
+get_frame_len (GstRtpQCELPDepay * depay, guint8 frame_type)
+{
+  if (frame_type >= G_N_ELEMENTS (frame_size))
+    return 0;
+
+  return frame_size[frame_type];
+}
+
+static guint
+count_packets (GstRtpQCELPDepay * depay, guint8 * data, guint size)
+{
+  guint count = 0;
+
+  while (size > 0) {
+    gint frame_len;
+
+    frame_len = get_frame_len (depay, data[0]);
+
+    /* 0 is invalid and we throw away the remainder of the frames */
+    if (frame_len == 0)
+      break;
+
+    if (frame_len < 0)
+      frame_len = -frame_len;
+
+    if (frame_len > size)
+      break;
+
+    size -= frame_len;
+    data += frame_len;
+    count++;
+  }
+  return count;
+}
+
+static void
+flush_packets (GstRtpQCELPDepay * depay)
+{
+  guint i, size;
+
+  GST_DEBUG_OBJECT (depay, "flushing packets");
+
+  size = depay->packets->len;
+
+  for (i = 0; i < size; i++) {
+    GstBuffer *outbuf;
+
+    outbuf = g_ptr_array_index (depay->packets, i);
+    g_ptr_array_index (depay->packets, i) = NULL;
+
+    gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (depay), outbuf);
+  }
+
+  /* and reset interleaving state */
+  depay->interleaved = FALSE;
+  depay->bundling = 0;
+}
+
+static void
+add_packet (GstRtpQCELPDepay * depay, guint LLL, guint NNN, guint index,
+    GstBuffer * outbuf)
+{
+  guint idx;
+  GstBuffer *old;
+
+  /* figure out the position in the array, note that index is never 0 because we
+   * push those packets immediately. */
+  idx = NNN + ((LLL + 1) * (index - 1));
+
+  GST_DEBUG_OBJECT (depay, "adding packet at index %u", idx);
+  /* free old buffer (should not happen) */
+  old = g_ptr_array_index (depay->packets, idx);
+  if (old)
+    gst_buffer_unref (old);
+
+  /* store new buffer */
+  g_ptr_array_index (depay->packets, idx) = outbuf;
+}
+
+static GstBuffer *
+create_erasure_buffer (GstRtpQCELPDepay * depay)
+{
+  GstBuffer *outbuf;
+  GstMapInfo map;
+
+  outbuf = gst_buffer_new_and_alloc (1);
+  gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+  map.data[0] = 14;
+  gst_buffer_unmap (outbuf, &map);
+
+  return outbuf;
+}
+
+static GstBuffer *
+gst_rtp_qcelp_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp)
+{
+  GstRtpQCELPDepay *depay;
+  GstBuffer *outbuf;
+  GstClockTime timestamp;
+  guint payload_len, offset, index;
+  guint8 *payload;
+  guint LLL, NNN;
+
+  depay = GST_RTP_QCELP_DEPAY (depayload);
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  if (payload_len < 2)
+    goto too_small;
+
+  timestamp = GST_BUFFER_PTS (rtp->buffer);
+
+  payload = gst_rtp_buffer_get_payload (rtp);
+
+  /*  0 1 2 3 4 5 6 7
+   * +-+-+-+-+-+-+-+-+
+   * |RR | LLL | NNN |
+   * +-+-+-+-+-+-+-+-+
+   */
+  /* RR = payload[0] >> 6; */
+  LLL = (payload[0] & 0x38) >> 3;
+  NNN = (payload[0] & 0x07);
+
+  payload_len--;
+  payload++;
+
+  GST_DEBUG_OBJECT (depay, "LLL %u, NNN %u", LLL, NNN);
+
+  if (LLL > 5)
+    goto invalid_lll;
+
+  if (NNN > LLL)
+    goto invalid_nnn;
+
+  if (LLL != 0) {
+    /* we are interleaved */
+    if (!depay->interleaved) {
+      guint size;
+
+      GST_DEBUG_OBJECT (depay, "starting interleaving group");
+      /* bundling is not allowed to change in one interleave group */
+      depay->bundling = count_packets (depay, payload, payload_len);
+      GST_DEBUG_OBJECT (depay, "got bundling of %u", depay->bundling);
+      /* we have one bundle where NNN goes from 0 to L, we don't store the index
+       * 0 frames, so L+1 packets. Each packet has 'bundling - 1' packets */
+      size = (depay->bundling - 1) * (LLL + 1);
+      /* create the array to hold the packets */
+      if (depay->packets == NULL)
+        depay->packets = g_ptr_array_sized_new (size);
+      GST_DEBUG_OBJECT (depay, "created packet array of size %u", size);
+      g_ptr_array_set_size (depay->packets, size);
+      /* we were previously not interleaved, figure out how much space we
+       * need to deinterleave */
+      depay->interleaved = TRUE;
+    }
+  } else {
+    /* we are not interleaved */
+    if (depay->interleaved) {
+      GST_DEBUG_OBJECT (depay, "stopping interleaving");
+      /* flush packets if we were previously interleaved */
+      flush_packets (depay);
+    }
+    depay->bundling = 0;
+  }
+
+  index = 0;
+  offset = 1;
+
+  while (payload_len > 0) {
+    gint frame_len;
+    gboolean do_erasure;
+
+    frame_len = get_frame_len (depay, payload[0]);
+    GST_DEBUG_OBJECT (depay, "got frame len %d", frame_len);
+
+    if (frame_len == 0)
+      goto invalid_frame;
+
+    if (frame_len < 0) {
+      /* need to add an erasure frame but we can recover */
+      frame_len = -frame_len;
+      do_erasure = TRUE;
+    } else {
+      do_erasure = FALSE;
+    }
+
+    if (frame_len > payload_len)
+      goto invalid_frame;
+
+    if (do_erasure) {
+      /* create erasure frame */
+      outbuf = create_erasure_buffer (depay);
+    } else {
+      /* each frame goes into its buffer */
+      outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, offset, frame_len);
+    }
+
+    GST_BUFFER_PTS (outbuf) = timestamp;
+    GST_BUFFER_DURATION (outbuf) = FRAME_DURATION;
+
+    gst_rtp_drop_non_audio_meta (depayload, outbuf);
+
+    if (!depay->interleaved || index == 0) {
+      /* not interleaved or first frame in packet, just push */
+      gst_rtp_base_depayload_push (depayload, outbuf);
+
+      if (timestamp != -1)
+        timestamp += FRAME_DURATION;
+    } else {
+      /* put in interleave buffer */
+      add_packet (depay, LLL, NNN, index, outbuf);
+
+      if (timestamp != -1)
+        timestamp += (FRAME_DURATION * (LLL + 1));
+    }
+
+    payload_len -= frame_len;
+    payload += frame_len;
+    offset += frame_len;
+    index++;
+
+    /* discard excess packets */
+    if (depay->bundling > 0 && depay->bundling <= index)
+      break;
+  }
+  while (index < depay->bundling) {
+    GST_DEBUG_OBJECT (depay, "filling with erasure buffer");
+    /* fill remainder with erasure packets */
+    outbuf = create_erasure_buffer (depay);
+    add_packet (depay, LLL, NNN, index, outbuf);
+    index++;
+  }
+  if (depay->interleaved && LLL == NNN) {
+    GST_DEBUG_OBJECT (depay, "interleave group ended, flushing");
+    /* we have the complete interleave group, flush */
+    flush_packets (depay);
+  }
+
+  return NULL;
+
+  /* ERRORS */
+too_small:
+  {
+    GST_ELEMENT_WARNING (depay, STREAM, DECODE,
+        (NULL), ("QCELP RTP payload too small (%d)", payload_len));
+    return NULL;
+  }
+invalid_lll:
+  {
+    GST_ELEMENT_WARNING (depay, STREAM, DECODE,
+        (NULL), ("QCELP RTP invalid LLL received (%d)", LLL));
+    return NULL;
+  }
+invalid_nnn:
+  {
+    GST_ELEMENT_WARNING (depay, STREAM, DECODE,
+        (NULL), ("QCELP RTP invalid NNN received (%d)", NNN));
+    return NULL;
+  }
+invalid_frame:
+  {
+    GST_ELEMENT_WARNING (depay, STREAM, DECODE,
+        (NULL), ("QCELP RTP invalid frame received"));
+    return NULL;
+  }
+}
+
+gboolean
+gst_rtp_qcelp_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpqcelpdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_QCELP_DEPAY);
+}
diff --git a/gst/rtp/gstrtpqcelpdepay.h b/gst/rtp/gstrtpqcelpdepay.h
new file mode 100644
index 0000000..ade274d
--- /dev/null
+++ b/gst/rtp/gstrtpqcelpdepay.h
@@ -0,0 +1,62 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_QCELP_DEPAY_H__
+#define __GST_RTP_QCELP_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_QCELP_DEPAY \
+  (gst_rtp_qcelp_depay_get_type())
+#define GST_RTP_QCELP_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_QCELP_DEPAY,GstRtpQCELPDepay))
+#define GST_RTP_QCELP_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_QCELP_DEPAY,GstRtpQCELPDepayClass))
+#define GST_IS_RTP_QCELP_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_QCELP_DEPAY))
+#define GST_IS_RTP_QCELP_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_QCELP_DEPAY))
+
+typedef struct _GstRtpQCELPDepay GstRtpQCELPDepay;
+typedef struct _GstRtpQCELPDepayClass GstRtpQCELPDepayClass;
+
+struct _GstRtpQCELPDepay
+{
+  GstRTPBaseDepayload depayload;
+
+  gboolean interleaved;
+  guint bundling;
+  GPtrArray *packets;
+};
+
+struct _GstRtpQCELPDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_qcelp_depay_get_type (void);
+
+gboolean gst_rtp_qcelp_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_QCELP_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpqdmdepay.c b/gst/rtp/gstrtpqdmdepay.c
new file mode 100644
index 0000000..898663a
--- /dev/null
+++ b/gst/rtp/gstrtpqdmdepay.c
@@ -0,0 +1,414 @@
+/* GStreamer
+ * Copyright (C) <2009> Edward Hervey <bilboed@bilboed.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+#include "gstrtpqdmdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY (rtpqdm2depay_debug);
+#define GST_CAT_DEFAULT rtpqdm2depay_debug
+
+static GstStaticPadTemplate gst_rtp_qdm2_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-qdm2")
+    );
+
+static GstStaticPadTemplate gst_rtp_qdm2_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", " "encoding-name = (string)\"X-QDM\"")
+    );
+
+#define gst_rtp_qdm2_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpQDM2Depay, gst_rtp_qdm2_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static const guint8 headheader[20] = {
+  0x0, 0x0, 0x0, 0xc, 0x66, 0x72, 0x6d, 0x61,
+  0x51, 0x44, 0x4d, 0x32, 0x0, 0x0, 0x0, 0x24,
+  0x51, 0x44, 0x43, 0x41
+};
+
+static void gst_rtp_qdm2_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_qdm2_depay_change_state (GstElement *
+    element, GstStateChange transition);
+
+static GstBuffer *gst_rtp_qdm2_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+gboolean gst_rtp_qdm2_depay_setcaps (GstRTPBaseDepayload * filter,
+    GstCaps * caps);
+
+static void
+gst_rtp_qdm2_depay_class_init (GstRtpQDM2DepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_qdm2_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_qdm2_depay_setcaps;
+
+  gobject_class->finalize = gst_rtp_qdm2_depay_finalize;
+
+  gstelement_class->change_state = gst_rtp_qdm2_depay_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_qdm2_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_qdm2_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP QDM2 depayloader",
+      "Codec/Depayloader/Network/RTP",
+      "Extracts QDM2 audio from RTP packets (no RFC)",
+      "Edward Hervey <bilboed@bilboed.com>");
+}
+
+static void
+gst_rtp_qdm2_depay_init (GstRtpQDM2Depay * rtpqdm2depay)
+{
+  rtpqdm2depay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_qdm2_depay_finalize (GObject * object)
+{
+  GstRtpQDM2Depay *rtpqdm2depay;
+
+  rtpqdm2depay = GST_RTP_QDM2_DEPAY (object);
+
+  g_object_unref (rtpqdm2depay->adapter);
+  rtpqdm2depay->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* only on the sink */
+gboolean
+gst_rtp_qdm2_depay_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps)
+{
+  GstStructure *structure = gst_caps_get_structure (caps, 0);
+  gint clock_rate;
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 44100;         /* default */
+  filter->clock_rate = clock_rate;
+
+  /* will set caps later */
+
+  return TRUE;
+}
+
+static void
+flush_data (GstRtpQDM2Depay * depay)
+{
+  guint i;
+  guint avail;
+
+  if ((avail = gst_adapter_available (depay->adapter)))
+    gst_adapter_flush (depay->adapter, avail);
+
+  GST_DEBUG ("Flushing %d packets", depay->nbpackets);
+
+  for (i = 0; depay->packets[i]; i++) {
+    QDM2Packet *pack = depay->packets[i];
+    guint32 crc = 0;
+    int i = 0;
+    GstBuffer *buf;
+    guint8 *data;
+
+    /* CRC is the sum of everything (including first bytes) */
+
+    data = pack->data;
+
+    if (G_UNLIKELY (data == NULL))
+      continue;
+
+    /* If the packet size is bigger than 0xff, we need 2 bytes to store the size */
+    if (depay->packetsize > 0xff) {
+      /* Expanded size 0x02 | 0x80 */
+      data[0] = 0x82;
+      GST_WRITE_UINT16_BE (data + 1, depay->packetsize - 3);
+    } else {
+      data[0] = 0x2;
+      data[1] = depay->packetsize - 2;
+    }
+
+    /* Calculate CRC */
+    for (; i < depay->packetsize; i++)
+      crc += data[i];
+
+    GST_DEBUG ("CRC is 0x%x", crc);
+
+    /* Write CRC */
+    if (depay->packetsize > 0xff)
+      GST_WRITE_UINT16_BE (data + 3, crc);
+    else
+      GST_WRITE_UINT16_BE (data + 2, crc);
+
+    GST_MEMDUMP ("Extracted packet", data, depay->packetsize);
+
+    buf = gst_buffer_new ();
+    gst_buffer_append_memory (buf,
+        gst_memory_new_wrapped (0, data, depay->packetsize, 0,
+            depay->packetsize, data, g_free));
+
+    gst_adapter_push (depay->adapter, buf);
+
+    pack->data = NULL;
+  }
+}
+
+static void
+add_packet (GstRtpQDM2Depay * depay, guint32 pid, guint32 len, guint8 * data)
+{
+  QDM2Packet *packet;
+
+  if (G_UNLIKELY (!depay->configured))
+    return;
+
+  GST_DEBUG ("pid:%d, len:%d, data:%p", pid, len, data);
+
+  if (G_UNLIKELY (depay->packets[pid] == NULL)) {
+    depay->packets[pid] = g_malloc0 (sizeof (QDM2Packet));
+    depay->nbpackets = MAX (depay->nbpackets, pid + 1);
+  }
+  packet = depay->packets[pid];
+
+  GST_DEBUG ("packet:%p", packet);
+  GST_DEBUG ("packet->data:%p", packet->data);
+
+  if (G_UNLIKELY (packet->data == NULL)) {
+    packet->data = g_malloc0 (depay->packetsize);
+    /* We leave space for the header/crc */
+    if (depay->packetsize > 0xff)
+      packet->offs = 5;
+    else
+      packet->offs = 4;
+  }
+
+  /* Finally copy the data over */
+  memcpy (packet->data + packet->offs, data, len);
+  packet->offs += len;
+}
+
+static GstBuffer *
+gst_rtp_qdm2_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpQDM2Depay *rtpqdm2depay;
+  GstBuffer *outbuf = NULL;
+  guint16 seq;
+
+  rtpqdm2depay = GST_RTP_QDM2_DEPAY (depayload);
+
+  {
+    gint payload_len;
+    guint8 *payload;
+    guint avail;
+    guint pos = 0;
+
+    payload_len = gst_rtp_buffer_get_payload_len (rtp);
+    if (payload_len < 3)
+      goto bad_packet;
+
+    payload = gst_rtp_buffer_get_payload (rtp);
+    seq = gst_rtp_buffer_get_seq (rtp);
+    if (G_UNLIKELY (seq != rtpqdm2depay->nextseq)) {
+      GST_DEBUG ("GAP in sequence number, Resetting data !");
+      /* Flush previous data */
+      flush_data (rtpqdm2depay);
+      /* And store new timestamp */
+      rtpqdm2depay->ptimestamp = rtpqdm2depay->timestamp;
+      rtpqdm2depay->timestamp = GST_BUFFER_PTS (rtp->buffer);
+      /* And that previous data will be pushed at the bottom */
+    }
+    rtpqdm2depay->nextseq = seq + 1;
+
+    GST_DEBUG ("Payload size %d 0x%x sequence:%d", payload_len, payload_len,
+        seq);
+
+    GST_MEMDUMP ("Incoming payload", payload, payload_len);
+
+    while (pos < payload_len) {
+      switch (payload[pos]) {
+        case 0x80:{
+          GST_DEBUG ("Unrecognized 0x80 marker, skipping 12 bytes");
+          pos += 12;
+        }
+          break;
+        case 0xff:
+          /* HEADERS */
+          GST_DEBUG ("Headers");
+          /* Store the incoming timestamp */
+          rtpqdm2depay->ptimestamp = rtpqdm2depay->timestamp;
+          rtpqdm2depay->timestamp = GST_BUFFER_PTS (rtp->buffer);
+          /* flush the internal data if needed */
+          flush_data (rtpqdm2depay);
+          if (G_UNLIKELY (!rtpqdm2depay->configured)) {
+            guint8 *ourdata;
+            GstBuffer *codecdata;
+            GstMapInfo cmap;
+            GstCaps *caps;
+
+            /* First bytes are unknown */
+            GST_MEMDUMP ("Header", payload + pos, 32);
+            ourdata = payload + pos + 10;
+            pos += 10;
+            rtpqdm2depay->channs = GST_READ_UINT32_BE (payload + pos + 4);
+            rtpqdm2depay->samplerate = GST_READ_UINT32_BE (payload + pos + 8);
+            rtpqdm2depay->bitrate = GST_READ_UINT32_BE (payload + pos + 12);
+            rtpqdm2depay->blocksize = GST_READ_UINT32_BE (payload + pos + 16);
+            rtpqdm2depay->framesize = GST_READ_UINT32_BE (payload + pos + 20);
+            rtpqdm2depay->packetsize = GST_READ_UINT32_BE (payload + pos + 24);
+            /* 16 bit empty block (0x02 0x00) */
+            pos += 30;
+            GST_DEBUG
+                ("channs:%d, samplerate:%d, bitrate:%d, blocksize:%d, framesize:%d, packetsize:%d",
+                rtpqdm2depay->channs, rtpqdm2depay->samplerate,
+                rtpqdm2depay->bitrate, rtpqdm2depay->blocksize,
+                rtpqdm2depay->framesize, rtpqdm2depay->packetsize);
+
+            /* Caps */
+            codecdata = gst_buffer_new_and_alloc (48);
+            gst_buffer_map (codecdata, &cmap, GST_MAP_WRITE);
+            memcpy (cmap.data, headheader, 20);
+            memcpy (cmap.data + 20, ourdata, 28);
+            gst_buffer_unmap (codecdata, &cmap);
+
+            caps = gst_caps_new_simple ("audio/x-qdm2",
+                "samplesize", G_TYPE_INT, 16,
+                "rate", G_TYPE_INT, rtpqdm2depay->samplerate,
+                "channels", G_TYPE_INT, rtpqdm2depay->channs,
+                "codec_data", GST_TYPE_BUFFER, codecdata, NULL);
+            gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), caps);
+            gst_caps_unref (caps);
+            rtpqdm2depay->configured = TRUE;
+          } else {
+            GST_DEBUG ("Already configured, skipping headers");
+            pos += 40;
+          }
+          break;
+        default:{
+          /* Shuffled packet contents */
+          guint packetid = payload[pos++];
+          guint packettype = payload[pos++];
+          guint packlen = payload[pos++];
+          guint hsize = 2;
+
+          GST_DEBUG ("Packet id:%d, type:0x%x, len:%d",
+              packetid, packettype, packlen);
+
+          /* Packets bigger than 0xff bytes have a type with the high bit set */
+          if (G_UNLIKELY (packettype & 0x80)) {
+            packettype &= 0x7f;
+            packlen <<= 8;
+            packlen |= payload[pos++];
+            hsize = 3;
+            GST_DEBUG ("Packet id:%d, type:0x%x, len:%d",
+                packetid, packettype, packlen);
+          }
+
+          if (packettype > 0x7f) {
+            GST_ERROR ("HOUSTON WE HAVE A PROBLEM !!!!");
+          }
+          add_packet (rtpqdm2depay, packetid, packlen + hsize,
+              payload + pos - hsize);
+          pos += packlen;
+        }
+      }
+    }
+
+    GST_DEBUG ("final pos %d", pos);
+
+    avail = gst_adapter_available (rtpqdm2depay->adapter);
+    if (G_UNLIKELY (avail)) {
+      GST_DEBUG ("Pushing out %d bytes of collected data", avail);
+      outbuf = gst_adapter_take_buffer (rtpqdm2depay->adapter, avail);
+      GST_BUFFER_PTS (outbuf) = rtpqdm2depay->ptimestamp;
+      GST_DEBUG ("Outgoing buffer timestamp %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (rtpqdm2depay->ptimestamp));
+    }
+  }
+
+  return outbuf;
+
+  /* ERRORS */
+bad_packet:
+  {
+    GST_ELEMENT_WARNING (rtpqdm2depay, STREAM, DECODE,
+        (NULL), ("Packet was too short"));
+    return NULL;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_qdm2_depay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpQDM2Depay *rtpqdm2depay;
+  GstStateChangeReturn ret;
+
+  rtpqdm2depay = GST_RTP_QDM2_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_adapter_clear (rtpqdm2depay->adapter);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_qdm2_depay_plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (rtpqdm2depay_debug, "rtpqdm2depay", 0,
+      "RTP QDM2 depayloader");
+
+  return gst_element_register (plugin, "rtpqdm2depay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_QDM2_DEPAY);
+}
diff --git a/gst/rtp/gstrtpqdmdepay.h b/gst/rtp/gstrtpqdmdepay.h
new file mode 100644
index 0000000..8a6b2b2
--- /dev/null
+++ b/gst/rtp/gstrtpqdmdepay.h
@@ -0,0 +1,85 @@
+/* GStreamer
+ * Copyright (C) <2009> Edward Hervey <bilboed@bilboed.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_QDM2_DEPAY_H__
+#define __GST_RTP_QDM2_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_QDM2_DEPAY \
+  (gst_rtp_qdm2_depay_get_type())
+#define GST_RTP_QDM2_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_QDM2_DEPAY,GstRtpQDM2Depay))
+#define GST_RTP_QDM2_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_QDM2_DEPAY,GstRtpQDM2DepayClass))
+#define GST_IS_RTP_QDM2_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_QDM2_DEPAY))
+#define GST_IS_RTP_QDM2_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_QDM2_DEPAY))
+
+typedef struct _GstRtpQDM2Depay GstRtpQDM2Depay;
+typedef struct _GstRtpQDM2DepayClass GstRtpQDM2DepayClass;
+
+typedef struct _QDM2Packet {
+  guint8* data;
+  guint offs;		/* Starts at 4 to give room for the prefix */
+} QDM2Packet;
+
+#define MAX_SCRAMBLED_PACKETS 64
+
+struct _GstRtpQDM2Depay
+{
+  GstRTPBaseDepayload depayload;
+
+  GstAdapter *adapter;
+
+  guint16 nextseq;
+  gboolean configured;
+
+  GstClockTime timestamp; /* Timestamp of current incoming data */
+  GstClockTime ptimestamp; /* Timestamp of data stored in the adapter */
+
+  guint32 channs;
+  guint32 samplerate;
+  guint32 bitrate;
+  guint32 blocksize;
+  guint32 framesize;
+  guint32 packetsize;
+
+  guint nbpackets;	/* Number of packets to unscramble */
+
+  QDM2Packet *packets[MAX_SCRAMBLED_PACKETS];
+};
+
+struct _GstRtpQDM2DepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_qdm2_depay_get_type (void);
+
+gboolean gst_rtp_qdm2_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_QDM2_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpsbcdepay.c b/gst/rtp/gstrtpsbcdepay.c
new file mode 100644
index 0000000..9549bb0
--- /dev/null
+++ b/gst/rtp/gstrtpsbcdepay.c
@@ -0,0 +1,395 @@
+/*
+ * GStreamer RTP SBC depayloader
+ *
+ * Copyright (C) 2012  Collabora Ltd.
+ *   @author: Arun Raghavan <arun.raghavan@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+#include "gstrtpsbcdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpsbcdepay_debug);
+#define GST_CAT_DEFAULT (rtpsbcdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_sbc_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-sbc, "
+        "rate = (int) { 16000, 32000, 44100, 48000 }, "
+        "channels = (int) [ 1, 2 ], "
+        "mode = (string) { mono, dual, stereo, joint }, "
+        "blocks = (int) { 4, 8, 12, 16 }, "
+        "subbands = (int) { 4, 8 }, "
+        "allocation-method = (string) { snr, loudness }, "
+        "bitpool = (int) [ 2, 64 ]")
+    );
+
+static GstStaticPadTemplate gst_rtp_sbc_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) audio,"
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) { 16000, 32000, 44100, 48000 },"
+        "encoding-name = (string) SBC")
+    );
+
+enum
+{
+  PROP_0,
+  PROP_IGNORE_TIMESTAMPS,
+  PROP_LAST
+};
+
+#define DEFAULT_IGNORE_TIMESTAMPS FALSE
+
+#define gst_rtp_sbc_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpSbcDepay, gst_rtp_sbc_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_sbc_depay_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_rtp_sbc_depay_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+static void gst_rtp_sbc_depay_finalize (GObject * object);
+
+static gboolean gst_rtp_sbc_depay_setcaps (GstRTPBaseDepayload * base,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_sbc_depay_process (GstRTPBaseDepayload * base,
+    GstRTPBuffer * rtp);
+
+static void
+gst_rtp_sbc_depay_class_init (GstRtpSbcDepayClass * klass)
+{
+  GstRTPBaseDepayloadClass *gstbasertpdepayload_class =
+      GST_RTP_BASE_DEPAYLOAD_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = gst_rtp_sbc_depay_finalize;
+  gobject_class->set_property = gst_rtp_sbc_depay_set_property;
+  gobject_class->get_property = gst_rtp_sbc_depay_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_IGNORE_TIMESTAMPS,
+      g_param_spec_boolean ("ignore-timestamps", "Ignore Timestamps",
+          "Various statistics", DEFAULT_IGNORE_TIMESTAMPS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstbasertpdepayload_class->set_caps = gst_rtp_sbc_depay_setcaps;
+  gstbasertpdepayload_class->process_rtp_packet = gst_rtp_sbc_depay_process;
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_sbc_depay_src_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_sbc_depay_sink_template);
+
+  GST_DEBUG_CATEGORY_INIT (rtpsbcdepay_debug, "rtpsbcdepay", 0,
+      "SBC Audio RTP Depayloader");
+
+  gst_element_class_set_static_metadata (element_class,
+      "RTP SBC audio depayloader",
+      "Codec/Depayloader/Network/RTP",
+      "Extracts SBC audio from RTP packets",
+      "Arun Raghavan <arun.raghavan@collabora.co.uk>");
+}
+
+static void
+gst_rtp_sbc_depay_init (GstRtpSbcDepay * rtpsbcdepay)
+{
+  rtpsbcdepay->adapter = gst_adapter_new ();
+  rtpsbcdepay->stream_align =
+      gst_audio_stream_align_new (48000, 40 * GST_MSECOND, 1 * GST_SECOND);
+  rtpsbcdepay->ignore_timestamps = DEFAULT_IGNORE_TIMESTAMPS;
+}
+
+static void
+gst_rtp_sbc_depay_finalize (GObject * object)
+{
+  GstRtpSbcDepay *depay = GST_RTP_SBC_DEPAY (object);
+
+  gst_audio_stream_align_free (depay->stream_align);
+  gst_object_unref (depay->adapter);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_sbc_depay_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstRtpSbcDepay *depay = GST_RTP_SBC_DEPAY (object);
+
+  switch (prop_id) {
+    case PROP_IGNORE_TIMESTAMPS:
+      depay->ignore_timestamps = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_sbc_depay_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstRtpSbcDepay *depay = GST_RTP_SBC_DEPAY (object);
+
+  switch (prop_id) {
+    case PROP_IGNORE_TIMESTAMPS:
+      g_value_set_boolean (value, depay->ignore_timestamps);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* FIXME: This duplicates similar functionality rtpsbcpay, but there isn't a
+ * simple way to consolidate the two. This is best done by moving the function
+ * to the codec-utils library in gst-plugins-base when these elements move to
+ * GStreamer. */
+static int
+gst_rtp_sbc_depay_get_params (GstRtpSbcDepay * depay, const guint8 * data,
+    gint size, int *framelen, int *samples)
+{
+  int blocks, channel_mode, channels, subbands, bitpool;
+  int length;
+
+  if (size < 3) {
+    /* Not enough data for the header */
+    return -1;
+  }
+
+  /* Sanity check */
+  if (data[0] != 0x9c) {
+    GST_WARNING_OBJECT (depay, "Bad packet: couldn't find syncword");
+    return -2;
+  }
+
+  blocks = (data[1] >> 4) & 0x3;
+  blocks = (blocks + 1) * 4;
+  channel_mode = (data[1] >> 2) & 0x3;
+  channels = channel_mode ? 2 : 1;
+  subbands = (data[1] & 0x1);
+  subbands = (subbands + 1) * 4;
+  bitpool = data[2];
+
+  length = 4 + ((4 * subbands * channels) / 8);
+
+  if (channel_mode == 0 || channel_mode == 1) {
+    /* Mono || Dual channel */
+    length += ((blocks * channels * bitpool)
+        + 4 /* round up */ ) / 8;
+  } else {
+    /* Stereo || Joint stereo */
+    gboolean joint = (channel_mode == 3);
+
+    length += ((joint * subbands) + (blocks * bitpool)
+        + 4 /* round up */ ) / 8;
+  }
+
+  *framelen = length;
+  *samples = blocks * subbands;
+
+  return 0;
+}
+
+static gboolean
+gst_rtp_sbc_depay_setcaps (GstRTPBaseDepayload * base, GstCaps * caps)
+{
+  GstRtpSbcDepay *depay = GST_RTP_SBC_DEPAY (base);
+  GstStructure *structure;
+  GstCaps *outcaps, *oldcaps;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &depay->rate))
+    goto bad_caps;
+
+  outcaps = gst_caps_new_simple ("audio/x-sbc", "rate", G_TYPE_INT,
+      depay->rate, NULL);
+
+  gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (base), outcaps);
+
+  oldcaps = gst_pad_get_current_caps (GST_RTP_BASE_DEPAYLOAD_SINKPAD (base));
+  if (oldcaps && !gst_caps_can_intersect (oldcaps, caps)) {
+    /* Caps have changed, flush old data */
+    gst_adapter_clear (depay->adapter);
+  }
+
+  gst_caps_unref (outcaps);
+  if (oldcaps)
+    gst_caps_unref (oldcaps);
+
+  /* Reset when the caps are changing */
+  gst_audio_stream_align_set_rate (depay->stream_align, depay->rate);
+
+  return TRUE;
+
+bad_caps:
+  GST_WARNING_OBJECT (depay, "Can't support the caps we got: %"
+      GST_PTR_FORMAT, caps);
+  return FALSE;
+}
+
+static GstBuffer *
+gst_rtp_sbc_depay_process (GstRTPBaseDepayload * base, GstRTPBuffer * rtp)
+{
+  GstRtpSbcDepay *depay = GST_RTP_SBC_DEPAY (base);
+  GstBuffer *data = NULL;
+
+  gboolean fragment, start, last;
+  guint8 nframes;
+  guint8 *payload;
+  guint payload_len;
+  gint samples = 0;
+
+  GstClockTime timestamp;
+
+  GST_LOG_OBJECT (depay, "Got %" G_GSIZE_FORMAT " bytes",
+      gst_buffer_get_size (rtp->buffer));
+
+  if (gst_rtp_buffer_get_marker (rtp)) {
+    /* Marker isn't supposed to be set */
+    GST_WARNING_OBJECT (depay, "Marker bit was set");
+    goto bad_packet;
+  }
+
+  timestamp = GST_BUFFER_DTS_OR_PTS (rtp->buffer);
+  if (depay->ignore_timestamps && timestamp == GST_CLOCK_TIME_NONE) {
+    GstClockTime initial_timestamp;
+    guint64 n_samples;
+
+    initial_timestamp =
+        gst_audio_stream_align_get_timestamp_at_discont (depay->stream_align);
+    n_samples =
+        gst_audio_stream_align_get_samples_since_discont (depay->stream_align);
+
+    if (initial_timestamp == GST_CLOCK_TIME_NONE) {
+      GST_ERROR_OBJECT (depay,
+          "Can only ignore timestamps on streams without valid initial timestamp");
+      return NULL;
+    }
+
+    timestamp =
+        initial_timestamp + gst_util_uint64_scale (n_samples, GST_SECOND,
+        depay->rate);
+  }
+
+  payload = gst_rtp_buffer_get_payload (rtp);
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  fragment = payload[0] & 0x80;
+  start = payload[0] & 0x40;
+  last = payload[0] & 0x20;
+  nframes = payload[0] & 0x0f;
+
+  payload += 1;
+  payload_len -= 1;
+
+  data = gst_rtp_buffer_get_payload_subbuffer (rtp, 1, -1);
+
+  if (fragment) {
+    /* Got a packet with a fragment */
+    GST_LOG_OBJECT (depay, "Got fragment");
+
+    if (start && gst_adapter_available (depay->adapter)) {
+      GST_WARNING_OBJECT (depay, "Missing last fragment");
+      gst_adapter_clear (depay->adapter);
+
+    } else if (!start && !gst_adapter_available (depay->adapter)) {
+      GST_WARNING_OBJECT (depay, "Missing start fragment");
+      gst_buffer_unref (data);
+      data = NULL;
+      goto out;
+    }
+
+    gst_adapter_push (depay->adapter, data);
+
+    if (last) {
+      gint framelen, samples;
+      guint8 header[4];
+
+      data = gst_adapter_take_buffer (depay->adapter,
+          gst_adapter_available (depay->adapter));
+      gst_rtp_drop_non_audio_meta (depay, data);
+
+      if (gst_buffer_extract (data, 0, &header, 4) != 4 ||
+          gst_rtp_sbc_depay_get_params (depay, header,
+              payload_len, &framelen, &samples) < 0) {
+        gst_buffer_unref (data);
+        goto bad_packet;
+      }
+    } else {
+      data = NULL;
+    }
+  } else {
+    /* !fragment */
+    gint framelen;
+
+    GST_LOG_OBJECT (depay, "Got %d frames", nframes);
+
+    if (gst_rtp_sbc_depay_get_params (depay, payload,
+            payload_len, &framelen, &samples) < 0) {
+      gst_adapter_clear (depay->adapter);
+      goto bad_packet;
+    }
+
+    samples *= nframes;
+
+    GST_LOG_OBJECT (depay, "Got payload of %d", payload_len);
+
+    if (nframes * framelen > (gint) payload_len) {
+      GST_WARNING_OBJECT (depay, "Short packet");
+      goto bad_packet;
+    } else if (nframes * framelen < (gint) payload_len) {
+      GST_WARNING_OBJECT (depay, "Junk at end of packet");
+    }
+  }
+
+  if (depay->ignore_timestamps && data) {
+    GstClockTime duration;
+
+    gst_audio_stream_align_process (depay->stream_align,
+        GST_BUFFER_IS_DISCONT (rtp->buffer), timestamp, samples, &timestamp,
+        &duration, NULL);
+
+    GST_BUFFER_PTS (data) = timestamp;
+    GST_BUFFER_DTS (data) = GST_CLOCK_TIME_NONE;
+    GST_BUFFER_DURATION (data) = duration;
+  }
+
+out:
+  return data;
+
+bad_packet:
+  GST_ELEMENT_WARNING (depay, STREAM, DECODE,
+      ("Received invalid RTP payload, dropping"), (NULL));
+  goto out;
+}
+
+gboolean
+gst_rtp_sbc_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpsbcdepay", GST_RANK_SECONDARY,
+      GST_TYPE_RTP_SBC_DEPAY);
+}
diff --git a/gst/rtp/gstrtpsbcdepay.h b/gst/rtp/gstrtpsbcdepay.h
new file mode 100644
index 0000000..9cac3ad
--- /dev/null
+++ b/gst/rtp/gstrtpsbcdepay.h
@@ -0,0 +1,70 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Collabora Ltd.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GST_RTP_SBC_DEPAY_H
+#define __GST_RTP_SBC_DEPAY_H
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+#include <gst/audio/audio.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_SBC_DEPAY \
+	(gst_rtp_sbc_depay_get_type())
+#define GST_RTP_SBC_DEPAY(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SBC_DEPAY,\
+		GstRtpSbcDepay))
+#define GST_RTP_SBC_DEPAY_CLASS(klass) \
+	(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SBC_DEPAY,\
+		GstRtpSbcDepayClass))
+#define GST_IS_RTP_SBC_DEPAY(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SBC_DEPAY))
+#define GST_IS_RTP_SBC_DEPAY_CLASS(obj) \
+	(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SBC_DEPAY))
+typedef struct _GstRtpSbcDepay GstRtpSbcDepay;
+typedef struct _GstRtpSbcDepayClass GstRtpSbcDepayClass;
+
+struct _GstRtpSbcDepay
+{
+  GstRTPBaseDepayload base;
+
+  int rate;
+  GstAdapter *adapter;
+  gboolean ignore_timestamps;
+
+  /* Timestamp tracking when ignoring input timestamps */
+  GstAudioStreamAlign *stream_align;
+};
+
+struct _GstRtpSbcDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_sbc_depay_get_type (void);
+
+gboolean gst_rtp_sbc_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif
diff --git a/gst/rtp/gstrtpsbcpay.c b/gst/rtp/gstrtpsbcpay.c
new file mode 100644
index 0000000..1d2cbd4
--- /dev/null
+++ b/gst/rtp/gstrtpsbcpay.c
@@ -0,0 +1,383 @@
+/*  GStreamer RTP SBC payloader
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gst/audio/audio.h>
+#include "gstrtpsbcpay.h"
+#include <math.h>
+#include <string.h>
+#include "gstrtputils.h"
+
+#define RTP_SBC_PAYLOAD_HEADER_SIZE 1
+#define DEFAULT_MIN_FRAMES 0
+#define RTP_SBC_HEADER_TOTAL (12 + RTP_SBC_PAYLOAD_HEADER_SIZE)
+
+/* BEGIN: Packing for rtp_payload */
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+/* FIXME: this seems all a bit over the top for a single byte.. */
+struct rtp_payload
+{
+  guint8 frame_count:4;
+  guint8 rfa0:1;
+  guint8 is_last_fragment:1;
+  guint8 is_first_fragment:1;
+  guint8 is_fragmented:1;
+}
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+struct rtp_payload
+{
+  guint8 is_fragmented:1;
+  guint8 is_first_fragment:1;
+  guint8 is_last_fragment:1;
+  guint8 rfa0:1;
+  guint8 frame_count:4;
+}
+#else
+#error "Unknown byte order"
+#endif
+
+#ifdef _MSC_VER
+;
+#pragma pack(pop)
+#else
+__attribute__ ((packed));
+#endif
+/* END: Packing for rtp_payload */
+
+enum
+{
+  PROP_0,
+  PROP_MIN_FRAMES
+};
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_sbc_pay_debug);
+#define GST_CAT_DEFAULT gst_rtp_sbc_pay_debug
+
+#define parent_class gst_rtp_sbc_pay_parent_class
+G_DEFINE_TYPE (GstRtpSBCPay, gst_rtp_sbc_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static GstStaticPadTemplate gst_rtp_sbc_pay_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-sbc, "
+        "rate = (int) { 16000, 32000, 44100, 48000 }, "
+        "channels = (int) [ 1, 2 ], "
+        "channel-mode = (string) { mono, dual, stereo, joint }, "
+        "blocks = (int) { 4, 8, 12, 16 }, "
+        "subbands = (int) { 4, 8 }, "
+        "allocation-method = (string) { snr, loudness }, "
+        "bitpool = (int) [ 2, 64 ]")
+    );
+
+static GstStaticPadTemplate gst_rtp_sbc_pay_src_factory =
+GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) audio,"
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) { 16000, 32000, 44100, 48000 },"
+        "encoding-name = (string) SBC")
+    );
+
+static void gst_rtp_sbc_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_sbc_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gint
+gst_rtp_sbc_pay_get_frame_len (gint subbands, gint channels,
+    gint blocks, gint bitpool, const gchar * channel_mode)
+{
+  gint len;
+  gint join;
+
+  len = 4 + (4 * subbands * channels) / 8;
+
+  if (strcmp (channel_mode, "mono") == 0 || strcmp (channel_mode, "dual") == 0)
+    len += ((blocks * channels * bitpool) + 7) / 8;
+  else {
+    join = strcmp (channel_mode, "joint") == 0 ? 1 : 0;
+    len += ((join * subbands + blocks * bitpool) + 7) / 8;
+  }
+
+  return len;
+}
+
+static gboolean
+gst_rtp_sbc_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  GstRtpSBCPay *sbcpay;
+  gint rate, subbands, channels, blocks, bitpool;
+  gint frame_len;
+  const gchar *channel_mode;
+  GstStructure *structure;
+
+  sbcpay = GST_RTP_SBC_PAY (payload);
+
+  structure = gst_caps_get_structure (caps, 0);
+  if (!gst_structure_get_int (structure, "rate", &rate))
+    return FALSE;
+  if (!gst_structure_get_int (structure, "channels", &channels))
+    return FALSE;
+  if (!gst_structure_get_int (structure, "blocks", &blocks))
+    return FALSE;
+  if (!gst_structure_get_int (structure, "bitpool", &bitpool))
+    return FALSE;
+  if (!gst_structure_get_int (structure, "subbands", &subbands))
+    return FALSE;
+
+  channel_mode = gst_structure_get_string (structure, "channel-mode");
+  if (!channel_mode)
+    return FALSE;
+
+  frame_len = gst_rtp_sbc_pay_get_frame_len (subbands, channels, blocks,
+      bitpool, channel_mode);
+
+  sbcpay->frame_length = frame_len;
+  sbcpay->frame_duration = ((blocks * subbands) * GST_SECOND) / rate;
+  sbcpay->last_timestamp = GST_CLOCK_TIME_NONE;
+
+  gst_rtp_base_payload_set_options (payload, "audio", TRUE, "SBC", rate);
+
+  GST_DEBUG_OBJECT (payload, "calculated frame length: %d ", frame_len);
+
+  return gst_rtp_base_payload_set_outcaps (payload, NULL);
+}
+
+static GstFlowReturn
+gst_rtp_sbc_pay_flush_buffers (GstRtpSBCPay * sbcpay)
+{
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+  guint available;
+  guint max_payload;
+  GstBuffer *outbuf, *paybuf;
+  guint8 *payload_data;
+  guint frame_count;
+  guint payload_length;
+  struct rtp_payload *payload;
+  GstFlowReturn res;
+
+  if (sbcpay->frame_length == 0) {
+    GST_ERROR_OBJECT (sbcpay, "Frame length is 0");
+    return GST_FLOW_ERROR;
+  }
+
+  do {
+    available = gst_adapter_available (sbcpay->adapter);
+
+    max_payload =
+        gst_rtp_buffer_calc_payload_len (GST_RTP_BASE_PAYLOAD_MTU (sbcpay) -
+        RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0);
+
+    max_payload = MIN (max_payload, available);
+    frame_count = max_payload / sbcpay->frame_length;
+    payload_length = frame_count * sbcpay->frame_length;
+    if (payload_length == 0)    /* Nothing to send */
+      return GST_FLOW_OK;
+
+    outbuf = gst_rtp_buffer_new_allocate (RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0);
+
+    /* get payload */
+    gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+    gst_rtp_buffer_set_payload_type (&rtp, GST_RTP_BASE_PAYLOAD_PT (sbcpay));
+
+    /* write header and copy data into payload */
+    payload_data = gst_rtp_buffer_get_payload (&rtp);
+    payload = (struct rtp_payload *) payload_data;
+    memset (payload, 0, sizeof (struct rtp_payload));
+    payload->frame_count = frame_count;
+
+    gst_rtp_buffer_unmap (&rtp);
+
+    paybuf = gst_adapter_take_buffer_fast (sbcpay->adapter, payload_length);
+    gst_rtp_copy_audio_meta (sbcpay, outbuf, paybuf);
+    outbuf = gst_buffer_append (outbuf, paybuf);
+
+    GST_BUFFER_PTS (outbuf) = sbcpay->last_timestamp;
+    GST_BUFFER_DURATION (outbuf) = frame_count * sbcpay->frame_duration;
+    GST_DEBUG_OBJECT (sbcpay, "Pushing %d bytes: %" GST_TIME_FORMAT,
+        payload_length, GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)));
+
+    sbcpay->last_timestamp += frame_count * sbcpay->frame_duration;
+
+    res = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (sbcpay), outbuf);
+
+    /* try to send another RTP buffer if available data exceeds MTU size */
+  } while (res == GST_FLOW_OK);
+
+  return res;
+}
+
+static GstFlowReturn
+gst_rtp_sbc_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
+{
+  GstRtpSBCPay *sbcpay;
+  guint available;
+
+  /* FIXME check for negotiation */
+
+  sbcpay = GST_RTP_SBC_PAY (payload);
+
+  if (GST_BUFFER_IS_DISCONT (buffer)) {
+    /* Try to flush whatever's left */
+    gst_rtp_sbc_pay_flush_buffers (sbcpay);
+    /* Drop the rest */
+    gst_adapter_flush (sbcpay->adapter,
+        gst_adapter_available (sbcpay->adapter));
+    /* Reset timestamps */
+    sbcpay->last_timestamp = GST_CLOCK_TIME_NONE;
+  }
+
+  if (sbcpay->last_timestamp == GST_CLOCK_TIME_NONE)
+    sbcpay->last_timestamp = GST_BUFFER_PTS (buffer);
+
+  gst_adapter_push (sbcpay->adapter, buffer);
+
+  available = gst_adapter_available (sbcpay->adapter);
+  if (available + RTP_SBC_HEADER_TOTAL >=
+      GST_RTP_BASE_PAYLOAD_MTU (sbcpay) ||
+      (available > (sbcpay->min_frames * sbcpay->frame_length)))
+    return gst_rtp_sbc_pay_flush_buffers (sbcpay);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_rtp_sbc_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+  GstRtpSBCPay *sbcpay = GST_RTP_SBC_PAY (payload);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+      gst_rtp_sbc_pay_flush_buffers (sbcpay);
+      break;
+    default:
+      break;
+  }
+
+  return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+}
+
+static void
+gst_rtp_sbc_pay_finalize (GObject * object)
+{
+  GstRtpSBCPay *sbcpay = GST_RTP_SBC_PAY (object);
+
+  g_object_unref (sbcpay->adapter);
+
+  GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+static void
+gst_rtp_sbc_pay_class_init (GstRtpSBCPayClass * klass)
+{
+  GstRTPBasePayloadClass *payload_class = GST_RTP_BASE_PAYLOAD_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = gst_rtp_sbc_pay_finalize;
+  gobject_class->set_property = gst_rtp_sbc_pay_set_property;
+  gobject_class->get_property = gst_rtp_sbc_pay_get_property;
+
+  payload_class->set_caps = GST_DEBUG_FUNCPTR (gst_rtp_sbc_pay_set_caps);
+  payload_class->handle_buffer =
+      GST_DEBUG_FUNCPTR (gst_rtp_sbc_pay_handle_buffer);
+  payload_class->sink_event = GST_DEBUG_FUNCPTR (gst_rtp_sbc_pay_sink_event);
+
+  /* properties */
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_MIN_FRAMES,
+      g_param_spec_int ("min-frames", "minimum frame number",
+          "Minimum quantity of frames to send in one packet "
+          "(-1 for maximum allowed by the mtu)",
+          -1, G_MAXINT, DEFAULT_MIN_FRAMES, G_PARAM_READWRITE));
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_sbc_pay_sink_factory);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_sbc_pay_src_factory);
+
+  gst_element_class_set_static_metadata (element_class, "RTP packet payloader",
+      "Codec/Payloader/Network", "Payload SBC audio as RTP packets",
+      "Thiago Sousa Santos <thiagoss@lcc.ufcg.edu.br>");
+
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_sbc_pay_debug, "rtpsbcpay", 0,
+      "RTP SBC payloader");
+}
+
+static void
+gst_rtp_sbc_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpSBCPay *sbcpay;
+
+  sbcpay = GST_RTP_SBC_PAY (object);
+
+  switch (prop_id) {
+    case PROP_MIN_FRAMES:
+      sbcpay->min_frames = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_sbc_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpSBCPay *sbcpay;
+
+  sbcpay = GST_RTP_SBC_PAY (object);
+
+  switch (prop_id) {
+    case PROP_MIN_FRAMES:
+      g_value_set_int (value, sbcpay->min_frames);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_sbc_pay_init (GstRtpSBCPay * self)
+{
+  self->adapter = gst_adapter_new ();
+  self->frame_length = 0;
+  self->last_timestamp = GST_CLOCK_TIME_NONE;
+
+  self->min_frames = DEFAULT_MIN_FRAMES;
+}
+
+gboolean
+gst_rtp_sbc_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpsbcpay", GST_RANK_NONE,
+      GST_TYPE_RTP_SBC_PAY);
+}
diff --git a/gst/rtp/gstrtpsbcpay.h b/gst/rtp/gstrtpsbcpay.h
new file mode 100644
index 0000000..e570229
--- /dev/null
+++ b/gst/rtp/gstrtpsbcpay.h
@@ -0,0 +1,65 @@
+/*  GStreamer RTP SBC payloader
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_SBC_PAY \
+  (gst_rtp_sbc_pay_get_type())
+#define GST_RTP_SBC_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SBC_PAY,\
+                              GstRtpSBCPay))
+#define GST_RTP_SBC_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SBC_PAY,\
+                           GstRtpSBCPayClass))
+#define GST_IS_RTP_SBC_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SBC_PAY))
+#define GST_IS_RTP_SBC_PAY_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SBC_PAY))
+
+typedef struct _GstRtpSBCPay GstRtpSBCPay;
+typedef struct _GstRtpSBCPayClass GstRtpSBCPayClass;
+
+struct _GstRtpSBCPay {
+  GstRTPBasePayload base;
+
+  GstAdapter *adapter;
+  GstClockTime last_timestamp;
+
+  guint frame_length;
+  GstClockTime frame_duration;
+
+  guint min_frames;
+};
+
+struct _GstRtpSBCPayClass {
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_sbc_pay_get_type(void);
+
+gboolean gst_rtp_sbc_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
diff --git a/gst/rtp/gstrtpsirendepay.c b/gst/rtp/gstrtpsirendepay.c
new file mode 100644
index 0000000..f227268
--- /dev/null
+++ b/gst/rtp/gstrtpsirendepay.c
@@ -0,0 +1,125 @@
+/*
+ * Siren Depayloader Gst Element
+ *
+ *   @author: Youness Alaoui <kakaroto@kakaroto.homelinux.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+#include "gstrtpsirendepay.h"
+#include "gstrtputils.h"
+
+static GstStaticPadTemplate gst_rtp_siren_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) 16000, " "encoding-name = (string) \"SIREN\"")
+    /* This is the default, so the peer doesn't have to specify it */
+    /*  " "dct-length = (int) 320") */
+    );
+
+     static GstStaticPadTemplate gst_rtp_siren_depay_src_template =
+         GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-siren, " "dct-length = (int) 320")
+    );
+
+     static GstBuffer *gst_rtp_siren_depay_process (GstRTPBaseDepayload *
+    depayload, GstRTPBuffer * rtp);
+     static gboolean gst_rtp_siren_depay_setcaps (GstRTPBaseDepayload *
+    depayload, GstCaps * caps);
+
+G_DEFINE_TYPE (GstRTPSirenDepay, gst_rtp_siren_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+     static void gst_rtp_siren_depay_class_init (GstRTPSirenDepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_siren_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_siren_depay_setcaps;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_siren_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_siren_depay_sink_template);
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Siren packet depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts Siren audio from RTP packets",
+      "Philippe Kalaf <philippe.kalaf@collabora.co.uk>");
+}
+
+static void
+gst_rtp_siren_depay_init (GstRTPSirenDepay * rtpsirendepay)
+{
+
+}
+
+static gboolean
+gst_rtp_siren_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstCaps *srccaps;
+  gboolean ret;
+
+  srccaps = gst_caps_new_simple ("audio/x-siren",
+      "dct-length", G_TYPE_INT, 320, NULL);
+  ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+
+  GST_DEBUG ("set caps on source: %" GST_PTR_FORMAT " (ret=%d)", srccaps, ret);
+  gst_caps_unref (srccaps);
+
+  /* always fixed clock rate of 16000 */
+  depayload->clock_rate = 16000;
+
+  return ret;
+}
+
+static GstBuffer *
+gst_rtp_siren_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp)
+{
+  GstBuffer *outbuf;
+
+  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);
+
+  if (outbuf) {
+    gst_rtp_drop_non_audio_meta (depayload, outbuf);
+  }
+
+  return outbuf;
+}
+
+gboolean
+gst_rtp_siren_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpsirendepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_SIREN_DEPAY);
+}
diff --git a/gst/rtp/gstrtpsirendepay.h b/gst/rtp/gstrtpsirendepay.h
new file mode 100644
index 0000000..d1ffb11
--- /dev/null
+++ b/gst/rtp/gstrtpsirendepay.h
@@ -0,0 +1,59 @@
+/*
+ * Siren Depayloader Gst Element
+ *
+ *   @author: Youness Alaoui <kakaroto@kakaroto.homelinux.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_SIREN_DEPAY_H__
+#define __GST_RTP_SIREN_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS typedef struct _GstRTPSirenDepay GstRTPSirenDepay;
+typedef struct _GstRTPSirenDepayClass GstRTPSirenDepayClass;
+
+#define GST_TYPE_RTP_SIREN_DEPAY \
+  (gst_rtp_siren_depay_get_type())
+#define GST_RTP_SIREN_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SIREN_DEPAY,GstRTPSirenDepay))
+#define GST_RTP_SIREN_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SIREN_DEPAY,GstRTPSirenDepayClass))
+#define GST_IS_RTP_SIREN_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SIREN_DEPAY))
+#define GST_IS_RTP_SIREN_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SIREN_DEPAY))
+
+
+struct _GstRTPSirenDepay
+{
+  GstRTPBaseDepayload depayload;
+
+};
+
+struct _GstRTPSirenDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_siren_depay_get_type (void);
+
+gboolean gst_rtp_siren_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_SIREN_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpsirenpay.c b/gst/rtp/gstrtpsirenpay.c
new file mode 100644
index 0000000..04f9aa8
--- /dev/null
+++ b/gst/rtp/gstrtpsirenpay.c
@@ -0,0 +1,147 @@
+/*
+ * Siren Payloader Gst Element
+ *
+ *   @author: Youness Alaoui <kakaroto@kakaroto.homelinux.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstrtpsirenpay.h"
+#include <gst/rtp/gstrtpbuffer.h>
+
+GST_DEBUG_CATEGORY_STATIC (rtpsirenpay_debug);
+#define GST_CAT_DEFAULT (rtpsirenpay_debug)
+
+static GstStaticPadTemplate gst_rtp_siren_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-siren, " "dct-length = (int) 320")
+    );
+
+static GstStaticPadTemplate gst_rtp_siren_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 16000, "
+        "encoding-name = (string) \"SIREN\", "
+        "bitrate = (string) \"16000\", " "dct-length = (int) 320")
+    );
+
+static gboolean gst_rtp_siren_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+
+G_DEFINE_TYPE (GstRTPSirenPay, gst_rtp_siren_pay,
+    GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_siren_pay_class_init (GstRTPSirenPayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_siren_pay_setcaps;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_siren_pay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_siren_pay_src_template);
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Payloader for Siren Audio", "Codec/Payloader/Network/RTP",
+      "Packetize Siren audio streams into RTP packets",
+      "Youness Alaoui <kakaroto@kakaroto.homelinux.net>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpsirenpay_debug, "rtpsirenpay", 0,
+      "siren audio RTP payloader");
+}
+
+static void
+gst_rtp_siren_pay_init (GstRTPSirenPay * rtpsirenpay)
+{
+  GstRTPBasePayload *rtpbasepayload;
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+  rtpbasepayload = GST_RTP_BASE_PAYLOAD (rtpsirenpay);
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpsirenpay);
+
+  /* we don't set the payload type, it should be set by the application using
+   * the pt property or the default 96 will be used */
+  rtpbasepayload->clock_rate = 16000;
+
+  /* tell rtpbaseaudiopayload that this is a frame based codec */
+  gst_rtp_base_audio_payload_set_frame_based (rtpbaseaudiopayload);
+}
+
+static gboolean
+gst_rtp_siren_pay_setcaps (GstRTPBasePayload * rtpbasepayload, GstCaps * caps)
+{
+  GstRTPSirenPay *rtpsirenpay;
+  GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+  gint dct_length;
+  GstStructure *structure;
+  const char *payload_name;
+
+  rtpsirenpay = GST_RTP_SIREN_PAY (rtpbasepayload);
+  rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpbasepayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  gst_structure_get_int (structure, "dct-length", &dct_length);
+  if (dct_length != 320)
+    goto wrong_dct;
+
+  payload_name = gst_structure_get_name (structure);
+  if (g_ascii_strcasecmp ("audio/x-siren", payload_name))
+    goto wrong_caps;
+
+  gst_rtp_base_payload_set_options (rtpbasepayload, "audio", TRUE, "SIREN",
+      16000);
+  /* set options for this frame based audio codec */
+  gst_rtp_base_audio_payload_set_frame_options (rtpbaseaudiopayload, 20, 40);
+
+  return gst_rtp_base_payload_set_outcaps (rtpbasepayload, NULL);
+
+  /* ERRORS */
+wrong_dct:
+  {
+    GST_ERROR_OBJECT (rtpsirenpay, "dct-length must be 320, received %d",
+        dct_length);
+    return FALSE;
+  }
+wrong_caps:
+  {
+    GST_ERROR_OBJECT (rtpsirenpay, "expected audio/x-siren, received %s",
+        payload_name);
+    return FALSE;
+  }
+}
+
+gboolean
+gst_rtp_siren_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpsirenpay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_SIREN_PAY);
+}
diff --git a/gst/rtp/gstrtpsirenpay.h b/gst/rtp/gstrtpsirenpay.h
new file mode 100644
index 0000000..eaba5b5
--- /dev/null
+++ b/gst/rtp/gstrtpsirenpay.h
@@ -0,0 +1,57 @@
+/*
+ * Siren Payloader Gst Element
+ *
+ *   @author: Youness Alaoui <kakaroto@kakaroto.homelinux.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_SIREN_PAY_H__
+#define __GST_RTP_SIREN_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_SIREN_PAY \
+  (gst_rtp_siren_pay_get_type())
+#define GST_RTP_SIREN_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SIREN_PAY,GstRTPSirenPay))
+#define GST_RTP_SIREN_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SIREN_PAY,GstRTPSirenPayClass))
+#define GST_IS_RTP_SIREN_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SIREN_PAY))
+#define GST_IS_RTP_SIREN_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SIREN_PAY))
+typedef struct _GstRTPSirenPay GstRTPSirenPay;
+typedef struct _GstRTPSirenPayClass GstRTPSirenPayClass;
+
+struct _GstRTPSirenPay
+{
+  GstRTPBaseAudioPayload audiopayload;
+};
+
+struct _GstRTPSirenPayClass
+{
+  GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_siren_pay_get_type (void);
+
+gboolean gst_rtp_siren_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_SIREN_PAY_H__ */
diff --git a/gst/rtp/gstrtpspeexdepay.c b/gst/rtp/gstrtpspeexdepay.c
new file mode 100644
index 0000000..a2c987b
--- /dev/null
+++ b/gst/rtp/gstrtpspeexdepay.c
@@ -0,0 +1,226 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpspeexdepay.h"
+#include "gstrtputils.h"
+
+/* RtpSPEEXDepay signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0
+};
+
+static GstStaticPadTemplate gst_rtp_speex_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate =  (int) [6000, 48000], "
+        "encoding-name = (string) \"SPEEX\"")
+    /*  "encoding-params = (string) \"1\"" */
+    );
+
+static GstStaticPadTemplate gst_rtp_speex_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-speex")
+    );
+
+static GstBuffer *gst_rtp_speex_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+static gboolean gst_rtp_speex_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+
+G_DEFINE_TYPE (GstRtpSPEEXDepay, gst_rtp_speex_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_speex_depay_class_init (GstRtpSPEEXDepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_speex_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_speex_depay_setcaps;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_speex_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_speex_depay_sink_template);
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Speex depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts Speex audio from RTP packets",
+      "Edgard Lima <edgard.lima@gmail.com>");
+}
+
+static void
+gst_rtp_speex_depay_init (GstRtpSPEEXDepay * rtpspeexdepay)
+{
+}
+
+static gint
+gst_rtp_speex_depay_get_mode (gint rate)
+{
+  if (rate > 25000)
+    return 2;
+  else if (rate > 12500)
+    return 1;
+  else
+    return 0;
+}
+
+/* len 4 bytes LE,
+ * vendor string (len bytes),
+ * user_len 4 (0) bytes LE
+ */
+static const gchar gst_rtp_speex_comment[] =
+    "\045\0\0\0Depayloaded with GStreamer speexdepay\0\0\0\0";
+
+static gboolean
+gst_rtp_speex_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstRtpSPEEXDepay *rtpspeexdepay;
+  gint clock_rate, nb_channels;
+  GstBuffer *buf;
+  GstMapInfo map;
+  guint8 *data;
+  const gchar *params;
+  GstCaps *srccaps;
+  gboolean res;
+
+  rtpspeexdepay = GST_RTP_SPEEX_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    goto no_clockrate;
+  depayload->clock_rate = clock_rate;
+
+  if (!(params = gst_structure_get_string (structure, "encoding-params")))
+    nb_channels = 1;
+  else {
+    nb_channels = atoi (params);
+  }
+
+  /* construct minimal header and comment packet for the decoder */
+  buf = gst_buffer_new_and_alloc (80);
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  data = map.data;
+  memcpy (data, "Speex   ", 8);
+  data += 8;
+  memcpy (data, "1.1.12", 7);
+  data += 20;
+  GST_WRITE_UINT32_LE (data, 1);        /* version */
+  data += 4;
+  GST_WRITE_UINT32_LE (data, 80);       /* header_size */
+  data += 4;
+  GST_WRITE_UINT32_LE (data, clock_rate);       /* rate */
+  data += 4;
+  GST_WRITE_UINT32_LE (data, gst_rtp_speex_depay_get_mode (clock_rate));        /* mode */
+  data += 4;
+  GST_WRITE_UINT32_LE (data, 4);        /* mode_bitstream_version */
+  data += 4;
+  GST_WRITE_UINT32_LE (data, nb_channels);      /* nb_channels */
+  data += 4;
+  GST_WRITE_UINT32_LE (data, -1);       /* bitrate */
+  data += 4;
+  GST_WRITE_UINT32_LE (data, 0xa0);     /* frame_size */
+  data += 4;
+  GST_WRITE_UINT32_LE (data, 0);        /* VBR */
+  data += 4;
+  GST_WRITE_UINT32_LE (data, 1);        /* frames_per_packet */
+  data += 4;
+  GST_WRITE_UINT32_LE (data, 0);        /* extra_headers */
+  data += 4;
+  GST_WRITE_UINT32_LE (data, 0);        /* reserved1 */
+  data += 4;
+  GST_WRITE_UINT32_LE (data, 0);        /* reserved2 */
+  gst_buffer_unmap (buf, &map);
+
+  srccaps = gst_caps_new_empty_simple ("audio/x-speex");
+  res = gst_pad_set_caps (depayload->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpspeexdepay), buf);
+
+  buf = gst_buffer_new_and_alloc (sizeof (gst_rtp_speex_comment));
+  gst_buffer_fill (buf, 0, gst_rtp_speex_comment,
+      sizeof (gst_rtp_speex_comment));
+
+  gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpspeexdepay), buf);
+
+  return res;
+
+  /* ERRORS */
+no_clockrate:
+  {
+    GST_DEBUG_OBJECT (depayload, "no clock-rate specified");
+    return FALSE;
+  }
+}
+
+static GstBuffer *
+gst_rtp_speex_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp)
+{
+  GstBuffer *outbuf = NULL;
+
+  GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+      gst_buffer_get_size (rtp->buffer),
+      gst_rtp_buffer_get_marker (rtp),
+      gst_rtp_buffer_get_timestamp (rtp), gst_rtp_buffer_get_seq (rtp));
+
+  /* nothing special to be done */
+  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);
+
+  if (outbuf) {
+    GST_BUFFER_DURATION (outbuf) = 20 * GST_MSECOND;
+    gst_rtp_drop_non_audio_meta (depayload, outbuf);
+  }
+
+  return outbuf;
+}
+
+gboolean
+gst_rtp_speex_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpspeexdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_SPEEX_DEPAY);
+}
diff --git a/gst/rtp/gstrtpspeexdepay.h b/gst/rtp/gstrtpspeexdepay.h
new file mode 100644
index 0000000..59ffed0
--- /dev/null
+++ b/gst/rtp/gstrtpspeexdepay.h
@@ -0,0 +1,53 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 
+ */
+ 
+#ifndef __GST_RTP_SPEEX_DEPAY_H__
+#define __GST_RTP_SPEEX_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpSPEEXDepay GstRtpSPEEXDepay;
+typedef struct _GstRtpSPEEXDepayClass GstRtpSPEEXDepayClass;
+
+#define GST_TYPE_RTP_SPEEX_DEPAY \
+  (gst_rtp_speex_depay_get_type())
+#define GST_RTP_SPEEX_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SPEEX_DEPAY,GstRtpSPEEXDepay))
+#define GST_RTP_SPEEX_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SPEEX_DEPAY,GstRtpSPEEXDepayClass))
+#define GST_IS_RTP_SPEEX_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SPEEX_DEPAY))
+#define GST_IS_RTP_SPEEX_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SPEEX_DEPAY))
+
+struct _GstRtpSPEEXDepay
+{
+  GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpSPEEXDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_speex_depay_get_type (void);
+
+gboolean gst_rtp_speex_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_SPEEX_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpspeexpay.c b/gst/rtp/gstrtpspeexpay.c
new file mode 100644
index 0000000..7816bd6
--- /dev/null
+++ b/gst/rtp/gstrtpspeexpay.c
@@ -0,0 +1,350 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpspeexpay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpspeexpay_debug);
+#define GST_CAT_DEFAULT (rtpspeexpay_debug)
+
+static GstStaticPadTemplate gst_rtp_speex_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-speex, "
+        "rate = (int) [ 6000, 48000 ], " "channels = (int) 1")
+    );
+
+static GstStaticPadTemplate gst_rtp_speex_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate =  (int) [ 6000, 48000 ], "
+        "encoding-name = (string) \"SPEEX\", "
+        "encoding-params = (string) \"1\"")
+    );
+
+static GstStateChangeReturn gst_rtp_speex_pay_change_state (GstElement *
+    element, GstStateChange transition);
+
+static gboolean gst_rtp_speex_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static GstCaps *gst_rtp_speex_pay_getcaps (GstRTPBasePayload * payload,
+    GstPad * pad, GstCaps * filter);
+static GstFlowReturn gst_rtp_speex_pay_handle_buffer (GstRTPBasePayload *
+    payload, GstBuffer * buffer);
+
+#define gst_rtp_speex_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpSPEEXPay, gst_rtp_speex_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_speex_pay_class_init (GstRtpSPEEXPayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gstelement_class->change_state = gst_rtp_speex_pay_change_state;
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_speex_pay_setcaps;
+  gstrtpbasepayload_class->get_caps = gst_rtp_speex_pay_getcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_speex_pay_handle_buffer;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_speex_pay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_speex_pay_src_template);
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Speex payloader", "Codec/Payloader/Network/RTP",
+      "Payload-encodes Speex audio into a RTP packet",
+      "Edgard Lima <edgard.lima@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpspeexpay_debug, "rtpspeexpay", 0,
+      "Speex RTP Payloader");
+}
+
+static void
+gst_rtp_speex_pay_init (GstRtpSPEEXPay * rtpspeexpay)
+{
+  GST_RTP_BASE_PAYLOAD (rtpspeexpay)->clock_rate = 8000;
+  GST_RTP_BASE_PAYLOAD_PT (rtpspeexpay) = 110;  /* Create String */
+}
+
+static gboolean
+gst_rtp_speex_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  /* don't configure yet, we wait for the ident packet */
+  return TRUE;
+}
+
+
+static GstCaps *
+gst_rtp_speex_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad,
+    GstCaps * filter)
+{
+  GstCaps *otherpadcaps;
+  GstCaps *caps;
+
+  otherpadcaps = gst_pad_get_allowed_caps (payload->srcpad);
+  caps = gst_pad_get_pad_template_caps (pad);
+
+  if (otherpadcaps) {
+    if (!gst_caps_is_empty (otherpadcaps)) {
+      GstStructure *ps;
+      GstStructure *s;
+      gint clock_rate;
+
+      ps = gst_caps_get_structure (otherpadcaps, 0);
+      caps = gst_caps_make_writable (caps);
+      s = gst_caps_get_structure (caps, 0);
+
+      if (gst_structure_get_int (ps, "clock-rate", &clock_rate)) {
+        gst_structure_fixate_field_nearest_int (s, "rate", clock_rate);
+      }
+    }
+    gst_caps_unref (otherpadcaps);
+  }
+
+  if (filter) {
+    GstCaps *tcaps = caps;
+
+    caps = gst_caps_intersect_full (filter, tcaps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (tcaps);
+  }
+
+  return caps;
+}
+
+static gboolean
+gst_rtp_speex_pay_parse_ident (GstRtpSPEEXPay * rtpspeexpay,
+    const guint8 * data, guint size)
+{
+  guint32 version, header_size, rate, mode, nb_channels;
+  GstRTPBasePayload *payload;
+  gchar *cstr;
+  gboolean res;
+
+  /* we need the header string (8), the version string (20), the version
+   * and the header length. */
+  if (size < 36)
+    goto too_small;
+
+  if (!g_str_has_prefix ((const gchar *) data, "Speex   "))
+    goto wrong_header;
+
+  /* skip header and version string */
+  data += 28;
+
+  version = GST_READ_UINT32_LE (data);
+  if (version != 1)
+    goto wrong_version;
+
+  data += 4;
+  /* ensure sizes */
+  header_size = GST_READ_UINT32_LE (data);
+  if (header_size < 80)
+    goto header_too_small;
+
+  if (size < header_size)
+    goto payload_too_small;
+
+  data += 4;
+  rate = GST_READ_UINT32_LE (data);
+  data += 4;
+  mode = GST_READ_UINT32_LE (data);
+  data += 8;
+  nb_channels = GST_READ_UINT32_LE (data);
+
+  GST_DEBUG_OBJECT (rtpspeexpay, "rate %d, mode %d, nb_channels %d",
+      rate, mode, nb_channels);
+
+  payload = GST_RTP_BASE_PAYLOAD (rtpspeexpay);
+
+  gst_rtp_base_payload_set_options (payload, "audio", FALSE, "SPEEX", rate);
+  cstr = g_strdup_printf ("%d", nb_channels);
+  res = gst_rtp_base_payload_set_outcaps (payload, "encoding-params",
+      G_TYPE_STRING, cstr, NULL);
+  g_free (cstr);
+
+  return res;
+
+  /* ERRORS */
+too_small:
+  {
+    GST_DEBUG_OBJECT (rtpspeexpay,
+        "ident packet too small, need at least 32 bytes");
+    return FALSE;
+  }
+wrong_header:
+  {
+    GST_DEBUG_OBJECT (rtpspeexpay,
+        "ident packet does not start with \"Speex   \"");
+    return FALSE;
+  }
+wrong_version:
+  {
+    GST_DEBUG_OBJECT (rtpspeexpay, "can only handle version 1, have version %d",
+        version);
+    return FALSE;
+  }
+header_too_small:
+  {
+    GST_DEBUG_OBJECT (rtpspeexpay,
+        "header size too small, need at least 80 bytes, " "got only %d",
+        header_size);
+    return FALSE;
+  }
+payload_too_small:
+  {
+    GST_DEBUG_OBJECT (rtpspeexpay,
+        "payload too small, need at least %d bytes, got only %d", header_size,
+        size);
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_rtp_speex_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpSPEEXPay *rtpspeexpay;
+  GstMapInfo map;
+  GstBuffer *outbuf;
+  GstClockTime timestamp, duration;
+  GstFlowReturn ret;
+
+  rtpspeexpay = GST_RTP_SPEEX_PAY (basepayload);
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  switch (rtpspeexpay->packet) {
+    case 0:
+      /* ident packet. We need to parse the headers to construct the RTP
+       * properties. */
+      if (!gst_rtp_speex_pay_parse_ident (rtpspeexpay, map.data, map.size)) {
+        gst_buffer_unmap (buffer, &map);
+        goto parse_error;
+      }
+
+      ret = GST_FLOW_OK;
+      gst_buffer_unmap (buffer, &map);
+      goto done;
+    case 1:
+      /* comment packet, we ignore it */
+      ret = GST_FLOW_OK;
+      gst_buffer_unmap (buffer, &map);
+      goto done;
+    default:
+      /* other packets go in the payload */
+      break;
+  }
+  gst_buffer_unmap (buffer, &map);
+
+  if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_GAP)) {
+    ret = GST_FLOW_OK;
+    goto done;
+  }
+
+  timestamp = GST_BUFFER_PTS (buffer);
+  duration = GST_BUFFER_DURATION (buffer);
+
+  /* FIXME, only one SPEEX frame per RTP packet for now */
+
+  outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+  /* FIXME, assert for now */
+  g_assert (gst_buffer_get_size (buffer) <=
+      GST_RTP_BASE_PAYLOAD_MTU (rtpspeexpay));
+
+  /* copy timestamp and duration */
+  GST_BUFFER_PTS (outbuf) = timestamp;
+  GST_BUFFER_DURATION (outbuf) = duration;
+
+  gst_rtp_copy_audio_meta (basepayload, outbuf, buffer);
+  outbuf = gst_buffer_append (outbuf, buffer);
+  buffer = NULL;
+
+  ret = gst_rtp_base_payload_push (basepayload, outbuf);
+
+done:
+  if (buffer)
+    gst_buffer_unref (buffer);
+
+  rtpspeexpay->packet++;
+
+  return ret;
+
+  /* ERRORS */
+parse_error:
+  {
+    GST_ELEMENT_ERROR (rtpspeexpay, STREAM, DECODE, (NULL),
+        ("Error parsing first identification packet."));
+    gst_buffer_unref (buffer);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_speex_pay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRtpSPEEXPay *rtpspeexpay;
+  GstStateChangeReturn ret;
+
+  rtpspeexpay = GST_RTP_SPEEX_PAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      rtpspeexpay->packet = 0;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_speex_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpspeexpay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_SPEEX_PAY);
+}
diff --git a/gst/rtp/gstrtpspeexpay.h b/gst/rtp/gstrtpspeexpay.h
new file mode 100644
index 0000000..0ccaefb
--- /dev/null
+++ b/gst/rtp/gstrtpspeexpay.h
@@ -0,0 +1,56 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 
+ */
+
+
+#ifndef __GST_RTP_SPEEX_PAY_H__
+#define __GST_RTP_SPEEX_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpSPEEXPay GstRtpSPEEXPay;
+typedef struct _GstRtpSPEEXPayClass GstRtpSPEEXPayClass;
+
+#define GST_TYPE_RTP_SPEEX_PAY \
+  (gst_rtp_speex_pay_get_type())
+#define GST_RTP_SPEEX_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SPEEX_PAY,GstRtpSPEEXPay))
+#define GST_RTP_SPEEX_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SPEEX_PAY,GstRtpSPEEXPayClass))
+#define GST_IS_RTP_SPEEX_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SPEEX_PAY))
+#define GST_IS_RTP_SPEEX_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SPEEX_PAY))
+
+struct _GstRtpSPEEXPay
+{
+  GstRTPBasePayload payload;
+
+  guint64 packet;
+};
+
+struct _GstRtpSPEEXPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_speex_pay_get_type (void);
+
+gboolean gst_rtp_speex_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_SPEEX_PAY_H__ */
diff --git a/gst/rtp/gstrtpstreamdepay.c b/gst/rtp/gstrtpstreamdepay.c
new file mode 100644
index 0000000..34500e9
--- /dev/null
+++ b/gst/rtp/gstrtpstreamdepay.c
@@ -0,0 +1,231 @@
+/* GStreamer
+ * Copyright (C) 2013 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpstreamdepay
+ *
+ * Implements stream depayloading of RTP and RTCP packets for connection-oriented
+ * transport protocols according to RFC4571.
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc ! "audio/x-raw,rate=48000" ! vorbisenc ! rtpvorbispay config-interval=1 ! rtpstreampay ! tcpserversink port=5678
+ * gst-launch-1.0 tcpclientsrc port=5678 host=127.0.0.1 do-timestamp=true ! "application/x-rtp-stream,media=audio,clock-rate=48000,encoding-name=VORBIS" ! rtpstreamdepay ! rtpvorbisdepay ! decodebin ! audioconvert ! audioresample ! autoaudiosink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstrtpstreamdepay.h"
+
+GST_DEBUG_CATEGORY (gst_rtp_stream_depay_debug);
+#define GST_CAT_DEFAULT gst_rtp_stream_depay_debug
+
+static GstStaticPadTemplate src_template =
+    GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp; application/x-rtcp;"
+        "application/x-srtp; application/x-srtcp")
+    );
+
+static GstStaticPadTemplate sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp-stream; application/x-rtcp-stream;"
+        "application/x-srtp-stream; application/x-srtcp-stream")
+    );
+
+#define parent_class gst_rtp_stream_depay_parent_class
+G_DEFINE_TYPE (GstRtpStreamDepay, gst_rtp_stream_depay, GST_TYPE_BASE_PARSE);
+
+static gboolean gst_rtp_stream_depay_set_sink_caps (GstBaseParse * parse,
+    GstCaps * caps);
+static GstCaps *gst_rtp_stream_depay_get_sink_caps (GstBaseParse * parse,
+    GstCaps * filter);
+static GstFlowReturn gst_rtp_stream_depay_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize);
+
+static gboolean gst_rtp_stream_depay_sink_activate (GstPad * pad,
+    GstObject * parent);
+
+static void
+gst_rtp_stream_depay_class_init (GstRtpStreamDepayClass * klass)
+{
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_stream_depay_debug, "rtpstreamdepay", 0,
+      "RTP stream depayloader");
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_template);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Stream Depayloading", "Codec/Depayloader/Network",
+      "Depayloads RTP/RTCP packets for streaming protocols according to RFC4571",
+      "Sebastian Dröge <sebastian@centricular.com>");
+
+  parse_class->set_sink_caps =
+      GST_DEBUG_FUNCPTR (gst_rtp_stream_depay_set_sink_caps);
+  parse_class->get_sink_caps =
+      GST_DEBUG_FUNCPTR (gst_rtp_stream_depay_get_sink_caps);
+  parse_class->handle_frame =
+      GST_DEBUG_FUNCPTR (gst_rtp_stream_depay_handle_frame);
+}
+
+static void
+gst_rtp_stream_depay_init (GstRtpStreamDepay * self)
+{
+  gst_base_parse_set_min_frame_size (GST_BASE_PARSE (self), 2);
+
+  /* Force activation in push mode. We need to get a caps event from upstream
+   * to know the full RTP caps. */
+  gst_pad_set_activate_function (GST_BASE_PARSE_SINK_PAD (self),
+      gst_rtp_stream_depay_sink_activate);
+}
+
+static gboolean
+gst_rtp_stream_depay_set_sink_caps (GstBaseParse * parse, GstCaps * caps)
+{
+  GstCaps *othercaps;
+  GstStructure *structure;
+  gboolean ret;
+
+  othercaps = gst_caps_copy (caps);
+  structure = gst_caps_get_structure (othercaps, 0);
+
+  if (gst_structure_has_name (structure, "application/x-rtp-stream"))
+    gst_structure_set_name (structure, "application/x-rtp");
+  else if (gst_structure_has_name (structure, "application/x-rtcp-stream"))
+    gst_structure_set_name (structure, "application/x-rtcp");
+  else if (gst_structure_has_name (structure, "application/x-srtp-stream"))
+    gst_structure_set_name (structure, "application/x-srtp");
+  else
+    gst_structure_set_name (structure, "application/x-srtcp");
+
+  ret = gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), othercaps);
+  gst_caps_unref (othercaps);
+
+  return ret;
+}
+
+static GstCaps *
+gst_rtp_stream_depay_get_sink_caps (GstBaseParse * parse, GstCaps * filter)
+{
+  GstCaps *peerfilter = NULL, *peercaps, *templ;
+  GstCaps *res;
+  GstStructure *structure;
+  guint i, n;
+
+  if (filter) {
+    peerfilter = gst_caps_copy (filter);
+    n = gst_caps_get_size (peerfilter);
+    for (i = 0; i < n; i++) {
+      structure = gst_caps_get_structure (peerfilter, i);
+
+      if (gst_structure_has_name (structure, "application/x-rtp-stream"))
+        gst_structure_set_name (structure, "application/x-rtp");
+      else if (gst_structure_has_name (structure, "application/x-rtcp-stream"))
+        gst_structure_set_name (structure, "application/x-rtcp");
+      else if (gst_structure_has_name (structure, "application/x-srtp-stream"))
+        gst_structure_set_name (structure, "application/x-srtp");
+      else
+        gst_structure_set_name (structure, "application/x-srtcp");
+    }
+  }
+
+  templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
+  peercaps =
+      gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), peerfilter);
+
+  if (peercaps) {
+    /* Rename structure names */
+    peercaps = gst_caps_make_writable (peercaps);
+    n = gst_caps_get_size (peercaps);
+    for (i = 0; i < n; i++) {
+      structure = gst_caps_get_structure (peercaps, i);
+
+      if (gst_structure_has_name (structure, "application/x-rtp"))
+        gst_structure_set_name (structure, "application/x-rtp-stream");
+      else if (gst_structure_has_name (structure, "application/x-rtcp"))
+        gst_structure_set_name (structure, "application/x-rtcp-stream");
+      else if (gst_structure_has_name (structure, "application/x-srtp"))
+        gst_structure_set_name (structure, "application/x-srtp-stream");
+      else
+        gst_structure_set_name (structure, "application/x-srtcp-stream");
+    }
+
+    res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (peercaps);
+  } else {
+    res = templ;
+  }
+
+  if (filter) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (res);
+    res = intersection;
+
+    gst_caps_unref (peerfilter);
+  }
+
+  return res;
+}
+
+static GstFlowReturn
+gst_rtp_stream_depay_handle_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, gint * skipsize)
+{
+  gsize buf_size;
+  guint16 size;
+
+  if (gst_buffer_extract (frame->buffer, 0, &size, 2) != 2)
+    return GST_FLOW_ERROR;
+
+  size = GUINT16_FROM_BE (size);
+  buf_size = gst_buffer_get_size (frame->buffer);
+
+  /* Need more data */
+  if (size + 2 > buf_size)
+    return GST_FLOW_OK;
+
+  frame->out_buffer =
+      gst_buffer_copy_region (frame->buffer, GST_BUFFER_COPY_ALL, 2, size);
+
+  return gst_base_parse_finish_frame (parse, frame, size + 2);
+}
+
+static gboolean
+gst_rtp_stream_depay_sink_activate (GstPad * pad, GstObject * parent)
+{
+  return gst_pad_activate_mode (pad, GST_PAD_MODE_PUSH, TRUE);
+}
+
+gboolean
+gst_rtp_stream_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpstreamdepay",
+      GST_RANK_NONE, GST_TYPE_RTP_STREAM_DEPAY);
+}
diff --git a/gst/rtp/gstrtpstreamdepay.h b/gst/rtp/gstrtpstreamdepay.h
new file mode 100644
index 0000000..b6011cb
--- /dev/null
+++ b/gst/rtp/gstrtpstreamdepay.h
@@ -0,0 +1,57 @@
+/* GStreamer
+ * Copyright (C) 2013 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_STREAM_DEPAY_H__
+#define __GST_RTP_STREAM_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbaseparse.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_STREAM_DEPAY \
+  (gst_rtp_stream_depay_get_type())
+#define GST_RTP_STREAM_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_STREAM_DEPAY,GstRtpStreamDepay))
+#define GST_RTP_STREAM_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_STREAM_DEPAY,GstRtpStreamDepayClass))
+#define GST_IS_RTP_STREAM_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_STREAM_DEPAY))
+#define GST_IS_RTP_STREAM_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_STREAM_DEPAY))
+
+typedef struct _GstRtpStreamDepay GstRtpStreamDepay;
+typedef struct _GstRtpStreamDepayClass GstRtpStreamDepayClass;
+
+struct _GstRtpStreamDepay
+{
+  GstBaseParse parent;
+};
+
+struct _GstRtpStreamDepayClass
+{
+  GstBaseParseClass parent_class;
+};
+
+GType gst_rtp_stream_depay_get_type (void);
+gboolean gst_rtp_stream_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif
diff --git a/gst/rtp/gstrtpstreampay.c b/gst/rtp/gstrtpstreampay.c
new file mode 100644
index 0000000..87848c4
--- /dev/null
+++ b/gst/rtp/gstrtpstreampay.c
@@ -0,0 +1,285 @@
+/*
+ * GStreamer
+ * Copyright (C) 2013 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpstreampay
+ *
+ * Implements stream payloading of RTP and RTCP packets for connection-oriented
+ * transport protocols according to RFC4571.
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc ! "audio/x-raw,rate=48000" ! vorbisenc ! rtpvorbispay config-interval=1 ! rtpstreampay ! tcpserversink port=5678
+ * gst-launch-1.0 tcpclientsrc port=5678 host=127.0.0.1 do-timestamp=true ! "application/x-rtp-stream,media=audio,clock-rate=48000,encoding-name=VORBIS" ! rtpstreamdepay ! rtpvorbisdepay ! decodebin ! audioconvert ! audioresample ! autoaudiosink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstrtpstreampay.h"
+
+#define GST_CAT_DEFAULT gst_rtp_stream_pay_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp; application/x-rtcp; "
+        "application/x-srtp; application/x-srtcp")
+    );
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp-stream; application/x-rtcp-stream; "
+        "application/x-srtp-stream; application/x-srtcp-stream")
+    );
+
+#define parent_class gst_rtp_stream_pay_parent_class
+G_DEFINE_TYPE (GstRtpStreamPay, gst_rtp_stream_pay, GST_TYPE_ELEMENT);
+
+static gboolean gst_rtp_stream_pay_sink_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+static GstFlowReturn gst_rtp_stream_pay_sink_chain (GstPad * pad,
+    GstObject * parent, GstBuffer * inbuf);
+static gboolean gst_rtp_stream_pay_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+
+static void
+gst_rtp_stream_pay_class_init (GstRtpStreamPayClass * klass)
+{
+  GstElementClass *gstelement_class;
+
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_stream_pay_debug, "rtpstreampay", 0,
+      "RTP stream payloader");
+
+  gstelement_class = (GstElementClass *) klass;
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Stream Payloading", "Codec/Payloader/Network",
+      "Payloads RTP/RTCP packets for streaming protocols according to RFC4571",
+      "Sebastian Dröge <sebastian@centricular.com>");
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_template);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+}
+
+static void
+gst_rtp_stream_pay_init (GstRtpStreamPay * self)
+{
+  self->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
+  gst_pad_set_chain_function (self->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_stream_pay_sink_chain));
+  gst_pad_set_event_function (self->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_stream_pay_sink_event));
+  gst_pad_set_query_function (self->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_stream_pay_sink_query));
+  gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
+
+  self->srcpad = gst_pad_new_from_static_template (&src_template, "src");
+  gst_pad_use_fixed_caps (self->srcpad);
+  gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
+}
+
+static GstCaps *
+gst_rtp_stream_pay_sink_get_caps (GstRtpStreamPay * self, GstCaps * filter)
+{
+  GstCaps *peerfilter = NULL, *peercaps, *templ;
+  GstCaps *res;
+  GstStructure *structure;
+  guint i, n;
+
+  if (filter) {
+    peerfilter = gst_caps_copy (filter);
+    n = gst_caps_get_size (peerfilter);
+    for (i = 0; i < n; i++) {
+      structure = gst_caps_get_structure (peerfilter, i);
+
+      if (gst_structure_has_name (structure, "application/x-rtp"))
+        gst_structure_set_name (structure, "application/x-rtp-stream");
+      else if (gst_structure_has_name (structure, "application/x-rtcp"))
+        gst_structure_set_name (structure, "application/x-rtcp-stream");
+      else if (gst_structure_has_name (structure, "application/x-srtp"))
+        gst_structure_set_name (structure, "application/x-srtp-stream");
+      else
+        gst_structure_set_name (structure, "application/x-srtcp-stream");
+    }
+  }
+
+  templ = gst_pad_get_pad_template_caps (self->sinkpad);
+  peercaps = gst_pad_peer_query_caps (self->srcpad, peerfilter);
+
+  if (peercaps) {
+    /* Rename structure names */
+    peercaps = gst_caps_make_writable (peercaps);
+    n = gst_caps_get_size (peercaps);
+    for (i = 0; i < n; i++) {
+      structure = gst_caps_get_structure (peercaps, i);
+
+      if (gst_structure_has_name (structure, "application/x-rtp-stream"))
+        gst_structure_set_name (structure, "application/x-rtp");
+      else if (gst_structure_has_name (structure, "application/x-rtcp-stream"))
+        gst_structure_set_name (structure, "application/x-rtcp");
+      else if (gst_structure_has_name (structure, "application/x-srtp-stream"))
+        gst_structure_set_name (structure, "application/x-srtp");
+      else
+        gst_structure_set_name (structure, "application/x-srtcp");
+    }
+
+    res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (peercaps);
+  } else {
+    res = templ;
+  }
+
+  if (filter) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (res);
+    res = intersection;
+
+    gst_caps_unref (peerfilter);
+  }
+
+  return res;
+}
+
+static gboolean
+gst_rtp_stream_pay_sink_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  GstRtpStreamPay *self = GST_RTP_STREAM_PAY (parent);
+  gboolean ret;
+
+  GST_LOG_OBJECT (pad, "Handling query of type '%s'",
+      gst_query_type_get_name (GST_QUERY_TYPE (query)));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_query_parse_caps (query, &caps);
+      caps = gst_rtp_stream_pay_sink_get_caps (self, caps);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+      ret = TRUE;
+      break;
+    }
+    default:
+      ret = gst_pad_query_default (pad, parent, query);
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_rtp_stream_pay_sink_set_caps (GstRtpStreamPay * self, GstCaps * caps)
+{
+  GstCaps *othercaps;
+  GstStructure *structure;
+  gboolean ret;
+
+  othercaps = gst_caps_copy (caps);
+  structure = gst_caps_get_structure (othercaps, 0);
+
+  if (gst_structure_has_name (structure, "application/x-rtp"))
+    gst_structure_set_name (structure, "application/x-rtp-stream");
+  else if (gst_structure_has_name (structure, "application/x-rtcp"))
+    gst_structure_set_name (structure, "application/x-rtcp-stream");
+  else if (gst_structure_has_name (structure, "application/x-srtp"))
+    gst_structure_set_name (structure, "application/x-srtp-stream");
+  else
+    gst_structure_set_name (structure, "application/x-srtcp-stream");
+
+  ret = gst_pad_set_caps (self->srcpad, othercaps);
+  gst_caps_unref (othercaps);
+
+  return ret;
+}
+
+static gboolean
+gst_rtp_stream_pay_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstRtpStreamPay *self = GST_RTP_STREAM_PAY (parent);
+  gboolean ret;
+
+  GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      ret = gst_rtp_stream_pay_sink_set_caps (self, caps);
+      gst_event_unref (event);
+      break;
+    }
+    default:
+      ret = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_rtp_stream_pay_sink_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * inbuf)
+{
+  GstRtpStreamPay *self = GST_RTP_STREAM_PAY (parent);
+  GstBuffer *outbuf;
+  gsize size;
+  guint8 size16[2];
+
+  size = gst_buffer_get_size (inbuf);
+  if (size > G_MAXUINT16) {
+    GST_ELEMENT_ERROR (self, CORE, FAILED, (NULL),
+        ("Only buffers up to %d bytes supported, got %" G_GSIZE_FORMAT,
+            G_MAXUINT16, size));
+    gst_buffer_unref (inbuf);
+    return GST_FLOW_ERROR;
+  }
+
+  outbuf = gst_buffer_new_and_alloc (2);
+
+  GST_WRITE_UINT16_BE (size16, size);
+  gst_buffer_fill (outbuf, 0, size16, 2);
+
+  gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_ALL, 0, -1);
+
+  gst_buffer_unref (inbuf);
+
+  return gst_pad_push (self->srcpad, outbuf);
+}
+
+gboolean
+gst_rtp_stream_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpstreampay",
+      GST_RANK_NONE, GST_TYPE_RTP_STREAM_PAY);
+}
diff --git a/gst/rtp/gstrtpstreampay.h b/gst/rtp/gstrtpstreampay.h
new file mode 100644
index 0000000..a9436a8
--- /dev/null
+++ b/gst/rtp/gstrtpstreampay.h
@@ -0,0 +1,54 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2013 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+ 
+#ifndef __GST_RTP_STREAM_PAY_H__
+#define __GST_RTP_STREAM_PAY_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_STREAM_PAY            (gst_rtp_stream_pay_get_type())
+#define GST_RTP_STREAM_PAY(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_STREAM_PAY,GstRtpStreamPay))
+#define GST_IS_RTP_STREAM_PAY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_STREAM_PAY))
+#define GST_RTP_STREAM_PAY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_RTP_STREAM_PAY,GstRtpStreamPayClass))
+#define GST_IS_RTP_STREAM_PAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_RTP_STREAM_PAY))
+#define GST_RTP_STREAM_PAY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_RTP_STREAM_PAY,GstRtpStreamPayClass))
+
+typedef struct _GstRtpStreamPay      GstRtpStreamPay;
+typedef struct _GstRtpStreamPayClass GstRtpStreamPayClass;
+
+struct _GstRtpStreamPay {
+  GstElement parent;
+
+  GstPad *srcpad, *sinkpad;
+};
+
+struct _GstRtpStreamPayClass {
+  GstElementClass parent_class;
+};
+
+GType gst_rtp_stream_pay_get_type (void);
+
+gboolean gst_rtp_stream_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_STREAM_PAY_H__ */
diff --git a/gst/rtp/gstrtpsv3vdepay.c b/gst/rtp/gstrtpsv3vdepay.c
new file mode 100644
index 0000000..3d091c2
--- /dev/null
+++ b/gst/rtp/gstrtpsv3vdepay.c
@@ -0,0 +1,322 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+#include "gstrtpsv3vdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY (rtpsv3vdepay_debug);
+#define GST_CAT_DEFAULT rtpsv3vdepay_debug
+
+static GstStaticPadTemplate gst_rtp_sv3v_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-svq, " "svqversion = (int) 3")
+    );
+
+static GstStaticPadTemplate gst_rtp_sv3v_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "clock-rate = (int) 90000, "
+        "encoding-name = (string) { \"X-SV3V-ES\", \"X-SORENSON-VIDEO\" , \"X-SORENSONVIDEO\" , \"X-SorensonVideo\" }")
+    );
+
+#define gst_rtp_sv3v_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpSV3VDepay, gst_rtp_sv3v_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_sv3v_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_sv3v_depay_change_state (GstElement *
+    element, GstStateChange transition);
+
+static GstBuffer *gst_rtp_sv3v_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+gboolean gst_rtp_sv3v_depay_setcaps (GstRTPBaseDepayload * filter,
+    GstCaps * caps);
+
+static void
+gst_rtp_sv3v_depay_class_init (GstRtpSV3VDepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_sv3v_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_sv3v_depay_setcaps;
+
+  gobject_class->finalize = gst_rtp_sv3v_depay_finalize;
+
+  gstelement_class->change_state = gst_rtp_sv3v_depay_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_sv3v_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_sv3v_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP SVQ3 depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts SVQ3 video from RTP packets (no RFC)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+}
+
+static void
+gst_rtp_sv3v_depay_init (GstRtpSV3VDepay * rtpsv3vdepay)
+{
+  rtpsv3vdepay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_sv3v_depay_finalize (GObject * object)
+{
+  GstRtpSV3VDepay *rtpsv3vdepay;
+
+  rtpsv3vdepay = GST_RTP_SV3V_DEPAY (object);
+
+  g_object_unref (rtpsv3vdepay->adapter);
+  rtpsv3vdepay->adapter = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* only on the sink */
+gboolean
+gst_rtp_sv3v_depay_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps)
+{
+  GstStructure *structure = gst_caps_get_structure (caps, 0);
+  gint clock_rate;
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;         /* default */
+  filter->clock_rate = clock_rate;
+
+  /* will set caps later */
+
+  return TRUE;
+}
+
+static GstBuffer *
+gst_rtp_sv3v_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
+{
+  GstRtpSV3VDepay *rtpsv3vdepay;
+  static struct
+  {
+    guint width, height;
+  } resolutions[7] = {
+    {
+    160, 128}, {
+    128, 96}, {
+    176, 144}, {
+    352, 288}, {
+    704, 576}, {
+    240, 180}, {
+    320, 240}
+  };
+  gint payload_len;
+  guint8 *payload;
+  gboolean M;
+  gboolean C, S, E;
+  GstBuffer *outbuf = NULL;
+  guint16 seq;
+
+  rtpsv3vdepay = GST_RTP_SV3V_DEPAY (depayload);
+
+
+  /* flush on sequence number gaps */
+  seq = gst_rtp_buffer_get_seq (rtp);
+
+  GST_DEBUG ("timestamp %" GST_TIME_FORMAT ", sequence number:%d",
+      GST_TIME_ARGS (GST_BUFFER_PTS (rtp->buffer)), seq);
+
+  if (seq != rtpsv3vdepay->nextseq) {
+    GST_DEBUG ("Sequence discontinuity, clearing adapter");
+    gst_adapter_clear (rtpsv3vdepay->adapter);
+  }
+  rtpsv3vdepay->nextseq = seq + 1;
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+  if (payload_len < 3)
+    goto bad_packet;
+
+  payload = gst_rtp_buffer_get_payload (rtp);
+
+  M = gst_rtp_buffer_get_marker (rtp);
+
+  /* This is all a guess:
+   *                      1 1 1 1 1 1
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |0|C|S|E|0|0|0|0|0|0|0|0|0|0|0|0|
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   *
+   * C: config, packet contains config info
+   * S: start, packet contains start of frame
+   * E: end, packet contains end of frame
+   */
+  /* this seems to indicate a packet with a config string sent before each
+   * keyframe */
+  C = (payload[0] & 0x40) == 0x40;
+
+  /* redundant with the RTP marker bit */
+  S = (payload[0] & 0x20) == 0x20;
+  E = (payload[0] & 0x10) == 0x10;
+
+  GST_DEBUG ("M:%d, C:%d, S:%d, E:%d", M, C, S, E);
+
+  GST_MEMDUMP ("incoming buffer", payload, payload_len);
+
+  if (G_UNLIKELY (C)) {
+    GstCaps *caps;
+    GstBuffer *codec_data;
+    GstMapInfo cmap;
+    guint8 res;
+
+    GST_DEBUG ("Configuration packet");
+
+    /* if we already have caps, we don't need to do anything. FIXME, check if
+     * something changed. */
+    if (G_UNLIKELY (gst_pad_has_current_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD
+                (depayload)))) {
+      GST_DEBUG ("Already configured, skipping config parsing");
+      goto beach;
+    }
+
+    res = payload[2] >> 5;
+
+    /* width and height, according to http://wiki.multimedia.cx/index.php?title=Sorenson_Video_1#Stream_Format_And_Header */
+    if (G_LIKELY (res < 7)) {
+      rtpsv3vdepay->width = resolutions[res].width;
+      rtpsv3vdepay->height = resolutions[res].height;
+    } else {
+      /* extended width/height, they're contained in the following 24bit */
+      rtpsv3vdepay->width = ((payload[2] & 0x1f) << 7) | (payload[3] >> 1);
+      rtpsv3vdepay->height =
+          (payload[3] & 0x1) << 11 | payload[4] << 3 | (payload[5] >> 5);
+    }
+
+    /* CodecData needs to be 'SEQH' + len (32bit) + data according to
+     * ffmpeg's libavcodec/svq3.c:svq3_decode_init */
+    codec_data = gst_buffer_new_and_alloc (payload_len + 6);
+    gst_buffer_map (codec_data, &cmap, GST_MAP_WRITE);
+    memcpy (cmap.data, "SEQH", 4);
+    GST_WRITE_UINT32_LE (cmap.data + 4, payload_len - 2);
+    memcpy (cmap.data + 8, payload + 2, payload_len - 2);
+    GST_MEMDUMP ("codec_data", cmap.data, gst_buffer_get_size (codec_data));
+    gst_buffer_unmap (codec_data, &cmap);
+
+    caps = gst_caps_new_simple ("video/x-svq",
+        "svqversion", G_TYPE_INT, 3,
+        "width", G_TYPE_INT, rtpsv3vdepay->width,
+        "height", G_TYPE_INT, rtpsv3vdepay->height,
+        "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
+    gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), caps);
+    gst_caps_unref (caps);
+
+    GST_DEBUG ("Depayloader now configured");
+
+    rtpsv3vdepay->configured = TRUE;
+
+    goto beach;
+  }
+
+  if (G_LIKELY (rtpsv3vdepay->configured)) {
+    GstBuffer *tmpbuf;
+
+    GST_DEBUG ("Storing incoming payload");
+    /* store data in adapter, stip off 2 bytes header */
+    tmpbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, 2, -1);
+    gst_adapter_push (rtpsv3vdepay->adapter, tmpbuf);
+
+    if (G_UNLIKELY (M)) {
+      /* frame is completed: push contents of adapter */
+      guint avail;
+
+      avail = gst_adapter_available (rtpsv3vdepay->adapter);
+      GST_DEBUG ("Returning completed output buffer [%d bytes]", avail);
+      outbuf = gst_adapter_take_buffer (rtpsv3vdepay->adapter, avail);
+      gst_rtp_drop_non_video_meta (rtpsv3vdepay, outbuf);
+    }
+  }
+
+beach:
+  return outbuf;
+
+  /* ERRORS */
+bad_packet:
+  {
+    GST_ELEMENT_WARNING (rtpsv3vdepay, STREAM, DECODE,
+        (NULL), ("Packet was too short"));
+    return NULL;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_sv3v_depay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpSV3VDepay *rtpsv3vdepay;
+  GstStateChangeReturn ret;
+
+  rtpsv3vdepay = GST_RTP_SV3V_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_adapter_clear (rtpsv3vdepay->adapter);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_sv3v_depay_plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (rtpsv3vdepay_debug, "rtpsv3vdepay", 0,
+      "RTP SV3V depayloader");
+
+  return gst_element_register (plugin, "rtpsv3vdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_SV3V_DEPAY);
+}
diff --git a/gst/rtp/gstrtpsv3vdepay.h b/gst/rtp/gstrtpsv3vdepay.h
new file mode 100644
index 0000000..428684a
--- /dev/null
+++ b/gst/rtp/gstrtpsv3vdepay.h
@@ -0,0 +1,67 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_SV3V_DEPAY_H__
+#define __GST_RTP_SV3V_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_SV3V_DEPAY \
+  (gst_rtp_sv3v_depay_get_type())
+#define GST_RTP_SV3V_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SV3V_DEPAY,GstRtpSV3VDepay))
+#define GST_RTP_SV3V_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SV3V_DEPAY,GstRtpSV3VDepayClass))
+#define GST_IS_RTP_SV3V_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SV3V_DEPAY))
+#define GST_IS_RTP_SV3V_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SV3V_DEPAY))
+
+typedef struct _GstRtpSV3VDepay GstRtpSV3VDepay;
+typedef struct _GstRtpSV3VDepayClass GstRtpSV3VDepayClass;
+
+struct _GstRtpSV3VDepay
+{
+  GstRTPBaseDepayload depayload;
+
+  GstAdapter *adapter;
+
+  gboolean configured;
+  
+  guint16 nextseq;
+  guint width;
+  guint height;
+};
+
+struct _GstRtpSV3VDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_sv3v_depay_get_type (void);
+
+gboolean gst_rtp_sv3v_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_SV3V_DEPAY_H__ */
diff --git a/gst/rtp/gstrtptheoradepay.c b/gst/rtp/gstrtptheoradepay.c
new file mode 100644
index 0000000..edc50cf
--- /dev/null
+++ b/gst/rtp/gstrtptheoradepay.c
@@ -0,0 +1,707 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/tag/tag.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+
+#include <string.h>
+#include "gstrtptheoradepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtptheoradepay_debug);
+#define GST_CAT_DEFAULT (rtptheoradepay_debug)
+
+static GstStaticPadTemplate gst_rtp_theora_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"THEORA\""
+        /* All required parameters 
+         *
+         * "sampling = (string) { "YCbCr-4:2:0", "YCbCr-4:2:2", "YCbCr-4:4:4" } "
+         * "width = (string) [1, 1048561] (multiples of 16) "
+         * "height = (string) [1, 1048561] (multiples of 16) "
+         * "delivery-method = (string) { inline, in_band, out_band/<specific_name> } " 
+         * "configuration = (string) ANY" 
+         */
+        /* All optional parameters
+         *
+         * "configuration-uri =" 
+         */
+    )
+    );
+
+static GstStaticPadTemplate gst_rtp_theora_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-theora")
+    );
+
+#define gst_rtp_theora_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpTheoraDepay, gst_rtp_theora_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_theora_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_theora_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+static gboolean gst_rtp_theora_depay_packet_lost (GstRTPBaseDepayload *
+    depayload, GstEvent * event);
+
+static void gst_rtp_theora_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_theora_depay_change_state (GstElement *
+    element, GstStateChange transition);
+
+static void
+gst_rtp_theora_depay_class_init (GstRtpTheoraDepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_theora_depay_finalize;
+
+  gstelement_class->change_state = gst_rtp_theora_depay_change_state;
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_theora_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_theora_depay_setcaps;
+  gstrtpbasedepayload_class->packet_lost = gst_rtp_theora_depay_packet_lost;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_theora_depay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_theora_depay_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Theora depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts Theora video from RTP packets (draft-01 of RFC XXXX)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtptheoradepay_debug, "rtptheoradepay", 0,
+      "Theora RTP Depayloader");
+}
+
+static void
+gst_rtp_theora_depay_init (GstRtpTheoraDepay * rtptheoradepay)
+{
+  rtptheoradepay->adapter = gst_adapter_new ();
+}
+
+static void
+free_config (GstRtpTheoraConfig * config)
+{
+  g_list_free_full (config->headers, (GDestroyNotify) gst_buffer_unref);
+  g_free (config);
+}
+
+static void
+free_indents (GstRtpTheoraDepay * rtptheoradepay)
+{
+  g_list_free_full (rtptheoradepay->configs, (GDestroyNotify) free_config);
+  rtptheoradepay->configs = NULL;
+}
+
+static void
+gst_rtp_theora_depay_finalize (GObject * object)
+{
+  GstRtpTheoraDepay *rtptheoradepay = GST_RTP_THEORA_DEPAY (object);
+
+  g_object_unref (rtptheoradepay->adapter);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_theora_depay_parse_configuration (GstRtpTheoraDepay * rtptheoradepay,
+    GstBuffer * confbuf)
+{
+  GstBuffer *buf;
+  guint32 num_headers;
+  GstMapInfo map;
+  guint8 *data;
+  gsize size;
+  gint i, j;
+
+  gst_buffer_map (confbuf, &map, GST_MAP_READ);
+  data = map.data;
+  size = map.size;
+
+  GST_DEBUG_OBJECT (rtptheoradepay, "config size %" G_GSIZE_FORMAT, size);
+
+  /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                     Number of packed headers                  |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Packed header                        |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Packed header                        |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          ....                                 |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   */
+  if (size < 4)
+    goto too_small;
+
+  num_headers = GST_READ_UINT32_BE (data);
+  size -= 4;
+  data += 4;
+
+  GST_DEBUG_OBJECT (rtptheoradepay, "have %u headers", num_headers);
+
+  /*  0                   1                   2                   3
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                   Ident                       | length       ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..              | n. of headers |    length1    |    length2   ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..              |             Identification Header            ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * .................................................................
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..              |         Comment Header                       ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * .................................................................
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..                        Comment Header                        |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Setup Header                        ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * .................................................................
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..                         Setup Header                         |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   */
+  for (i = 0; i < num_headers; i++) {
+    guint32 ident;
+    guint16 length;
+    guint8 n_headers, b;
+    GstRtpTheoraConfig *conf;
+    guint *h_sizes;
+    guint extra = 1;
+
+    if (size < 6)
+      goto too_small;
+
+    ident = (data[0] << 16) | (data[1] << 8) | data[2];
+    length = (data[3] << 8) | data[4];
+    n_headers = data[5];
+    size -= 6;
+    data += 6;
+
+    GST_DEBUG_OBJECT (rtptheoradepay,
+        "header %d, ident 0x%08x, length %u, left %" G_GSIZE_FORMAT, i, ident,
+        length, size);
+
+    /* FIXME check if we already got this ident */
+
+    /* length might also include count of following size fields */
+    if (size < length && size + 1 != length)
+      goto too_small;
+
+    /* read header sizes we read 2 sizes, the third size (for which we allocate
+     * space) must be derived from the total packed header length. */
+    h_sizes = g_newa (guint, n_headers + 1);
+    for (j = 0; j < n_headers; j++) {
+      guint h_size;
+
+      h_size = 0;
+      do {
+        if (size < 1)
+          goto too_small;
+        b = *data++;
+        size--;
+        extra++;
+        h_size = (h_size << 7) | (b & 0x7f);
+      } while (b & 0x80);
+      GST_DEBUG_OBJECT (rtptheoradepay, "headers %d: size: %u", j, h_size);
+      h_sizes[j] = h_size;
+      length -= h_size;
+    }
+    /* last header length is the remaining space */
+    GST_DEBUG_OBJECT (rtptheoradepay, "last header size: %u", length);
+    h_sizes[j] = length;
+
+    GST_DEBUG_OBJECT (rtptheoradepay, "preparing headers");
+    conf = g_new0 (GstRtpTheoraConfig, 1);
+    conf->ident = ident;
+
+    for (j = 0; j <= n_headers; j++) {
+      guint h_size;
+
+      h_size = h_sizes[j];
+      if (size < h_size) {
+        if (j != n_headers || size + extra != h_size) {
+          free_config (conf);
+          goto too_small;
+        } else {
+          /* otherwise means that overall length field contained total length,
+           * including extra fields */
+          h_size -= extra;
+        }
+      }
+
+      GST_DEBUG_OBJECT (rtptheoradepay, "reading header %d, size %u", j,
+          h_size);
+
+      buf =
+          gst_buffer_copy_region (confbuf, GST_BUFFER_COPY_ALL, data - map.data,
+          h_size);
+      conf->headers = g_list_append (conf->headers, buf);
+      data += h_size;
+      size -= h_size;
+    }
+    rtptheoradepay->configs = g_list_append (rtptheoradepay->configs, conf);
+  }
+
+  gst_buffer_unmap (confbuf, &map);
+  gst_buffer_unref (confbuf);
+
+  return TRUE;
+
+  /* ERRORS */
+too_small:
+  {
+    GST_DEBUG_OBJECT (rtptheoradepay, "configuration too small");
+    gst_buffer_unmap (confbuf, &map);
+    gst_buffer_unref (confbuf);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_rtp_theora_depay_parse_inband_configuration (GstRtpTheoraDepay *
+    rtptheoradepay, guint ident, guint8 * configuration, guint size,
+    guint length)
+{
+  GstBuffer *confbuf;
+  GstMapInfo map;
+
+  if (G_UNLIKELY (size < 4))
+    return FALSE;
+
+  /* transform inline to out-of-band and parse that one */
+  confbuf = gst_buffer_new_and_alloc (size + 9);
+  gst_buffer_map (confbuf, &map, GST_MAP_WRITE);
+  /* 1 header */
+  GST_WRITE_UINT32_BE (map.data, 1);
+  /* write Ident */
+  GST_WRITE_UINT24_BE (map.data + 4, ident);
+  /* write sort-of-length */
+  GST_WRITE_UINT16_BE (map.data + 7, length);
+  /* copy remainder */
+  memcpy (map.data + 9, configuration, size);
+  gst_buffer_unmap (confbuf, &map);
+
+  return gst_rtp_theora_depay_parse_configuration (rtptheoradepay, confbuf);
+}
+
+static gboolean
+gst_rtp_theora_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstRtpTheoraDepay *rtptheoradepay;
+  GstCaps *srccaps;
+  const gchar *configuration;
+  gboolean res;
+
+  rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
+
+  rtptheoradepay->needs_keyframe = FALSE;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  /* read and parse configuration string */
+  configuration = gst_structure_get_string (structure, "configuration");
+  if (configuration) {
+    GstBuffer *confbuf;
+    guint8 *data;
+    gsize size;
+
+    /* deserialize base64 to buffer */
+    data = g_base64_decode (configuration, &size);
+
+    confbuf = gst_buffer_new ();
+    gst_buffer_append_memory (confbuf,
+        gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
+
+    if (!gst_rtp_theora_depay_parse_configuration (rtptheoradepay, confbuf))
+      goto invalid_configuration;
+  }
+
+  /* set caps on pad and on header */
+  srccaps = gst_caps_new_empty_simple ("video/x-theora");
+  res = gst_pad_set_caps (depayload->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  /* Clock rate is always 90000 according to draft-barbato-avt-rtp-theora-01 */
+  depayload->clock_rate = 90000;
+
+  return res;
+
+  /* ERRORS */
+invalid_configuration:
+  {
+    GST_ERROR_OBJECT (rtptheoradepay, "invalid configuration specified");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_rtp_theora_depay_switch_codebook (GstRtpTheoraDepay * rtptheoradepay,
+    guint32 ident)
+{
+  GList *walk;
+  gboolean res = FALSE;
+
+  for (walk = rtptheoradepay->configs; walk; walk = g_list_next (walk)) {
+    GstRtpTheoraConfig *conf = (GstRtpTheoraConfig *) walk->data;
+
+    if (conf->ident == ident) {
+      GList *headers;
+
+      /* FIXME, remove pads, create new pad.. */
+
+      /* push out all the headers */
+      for (headers = conf->headers; headers; headers = g_list_next (headers)) {
+        GstBuffer *header = GST_BUFFER_CAST (headers->data);
+
+        gst_buffer_ref (header);
+        gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtptheoradepay),
+            header);
+      }
+      /* remember the current config */
+      rtptheoradepay->config = conf;
+      res = TRUE;
+    }
+  }
+  if (!res) {
+    /* we don't know about the headers, figure out an alternative method for
+     * getting the codebooks. FIXME, fail for now. */
+  }
+  return res;
+}
+
+static GstBuffer *
+gst_rtp_theora_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp)
+{
+  GstRtpTheoraDepay *rtptheoradepay;
+  GstBuffer *outbuf;
+  GstFlowReturn ret;
+  gint payload_len;
+  GstMapInfo map;
+  GstBuffer *payload_buffer = NULL;
+  guint8 *payload;
+  guint32 header, ident;
+  guint8 F, TDT, packets;
+  guint length;
+
+  rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  GST_DEBUG_OBJECT (depayload, "got RTP packet of size %d", payload_len);
+
+  /* we need at least 4 bytes for the packet header */
+  if (G_UNLIKELY (payload_len < 4))
+    goto packet_short;
+
+  payload = gst_rtp_buffer_get_payload (rtp);
+
+  header = GST_READ_UINT32_BE (payload);
+  /*
+   *  0                   1                   2                   3
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                     Ident                     | F |TDT|# pkts.|
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   *
+   * F: Fragment type (0=none, 1=start, 2=cont, 3=end)
+   * TDT: Theora data type (0=theora, 1=config, 2=comment, 3=reserved)
+   * pkts: number of packets.
+   */
+  TDT = (header & 0x30) >> 4;
+  if (G_UNLIKELY (TDT == 3))
+    goto ignore_reserved;
+
+  ident = (header >> 8) & 0xffffff;
+  F = (header & 0xc0) >> 6;
+  packets = (header & 0xf);
+
+  GST_DEBUG_OBJECT (depayload, "ident: 0x%08x, F: %d, TDT: %d, packets: %d",
+      ident, F, TDT, packets);
+
+  if (TDT == 0) {
+    gboolean do_switch = FALSE;
+
+    /* we have a raw payload, find the codebook for the ident */
+    if (!rtptheoradepay->config) {
+      /* we don't have an active codebook, find the codebook and
+       * activate it */
+      do_switch = TRUE;
+    } else if (rtptheoradepay->config->ident != ident) {
+      /* codebook changed */
+      do_switch = TRUE;
+    }
+    if (do_switch) {
+      if (!gst_rtp_theora_depay_switch_codebook (rtptheoradepay, ident))
+        goto switch_failed;
+    }
+  }
+
+  /* fragmented packets, assemble */
+  if (F != 0) {
+    GstBuffer *vdata;
+
+    if (F == 1) {
+      /* if we start a packet, clear adapter and start assembling. */
+      gst_adapter_clear (rtptheoradepay->adapter);
+      GST_DEBUG_OBJECT (depayload, "start assemble");
+      rtptheoradepay->assembling = TRUE;
+    }
+
+    if (!rtptheoradepay->assembling)
+      goto no_output;
+
+    /* skip header and length. */
+    vdata = gst_rtp_buffer_get_payload_subbuffer (rtp, 6, -1);
+
+    GST_DEBUG_OBJECT (depayload, "assemble theora packet");
+    gst_adapter_push (rtptheoradepay->adapter, vdata);
+
+    /* packet is not complete, we are done */
+    if (F != 3)
+      goto no_output;
+
+    /* construct assembled buffer */
+    length = gst_adapter_available (rtptheoradepay->adapter);
+    payload_buffer = gst_adapter_take_buffer (rtptheoradepay->adapter, length);
+  } else {
+    length = 0;
+    payload_buffer = gst_rtp_buffer_get_payload_subbuffer (rtp, 4, -1);
+  }
+
+  GST_DEBUG_OBJECT (depayload, "assemble done, payload_len %d", payload_len);
+
+  gst_buffer_map (payload_buffer, &map, GST_MAP_READ);
+  payload = map.data;
+  payload_len = map.size;
+
+  /* we not assembling anymore now */
+  rtptheoradepay->assembling = FALSE;
+  gst_adapter_clear (rtptheoradepay->adapter);
+
+  /* payload now points to a length with that many theora data bytes.
+   * Iterate over the packets and send them out.
+   *
+   *  0                   1                   2                   3
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |             length            |          theora data         ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..                        theora data                           |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |            length             |   next theora packet data    ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..                        theora data                           |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*
+   */
+  while (payload_len >= 2) {
+    /* If length is not 0, we have a reassembled packet for which we
+     * calculated the length already and don't have to skip over the
+     * length field anymore
+     */
+    if (length == 0) {
+      length = GST_READ_UINT16_BE (payload);
+      payload += 2;
+      payload_len -= 2;
+    }
+
+    GST_DEBUG_OBJECT (depayload, "read length %u, avail: %d", length,
+        payload_len);
+
+    /* skip packet if something odd happens */
+    if (G_UNLIKELY (length > payload_len))
+      goto length_short;
+
+    /* handle in-band configuration */
+    if (G_UNLIKELY (TDT == 1)) {
+      GST_DEBUG_OBJECT (rtptheoradepay, "in-band configuration");
+      if (!gst_rtp_theora_depay_parse_inband_configuration (rtptheoradepay,
+              ident, payload, payload_len, length))
+        goto invalid_configuration;
+      goto no_output;
+    }
+
+    /* create buffer for packet */
+    outbuf =
+        gst_buffer_copy_region (payload_buffer, GST_BUFFER_COPY_ALL,
+        payload - map.data, length);
+
+    if (payload_len > 0 && (payload[0] & 0xC0) == 0x0) {
+      rtptheoradepay->needs_keyframe = FALSE;
+    } else {
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+    }
+
+    payload += length;
+    payload_len -= length;
+    /* make sure to read next length */
+    length = 0;
+
+    ret = gst_rtp_base_depayload_push (depayload, outbuf);
+    if (ret != GST_FLOW_OK)
+      break;
+  }
+
+  if (rtptheoradepay->needs_keyframe)
+    goto request_keyframe;
+
+out:
+no_output:
+
+  if (payload_buffer) {
+    gst_buffer_unmap (payload_buffer, &map);
+    gst_buffer_unref (payload_buffer);
+  }
+
+  return NULL;
+
+  /* ERORRS */
+switch_failed:
+  {
+    GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
+        (NULL), ("Could not switch codebooks"));
+    goto request_config;
+  }
+packet_short:
+  {
+    GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
+        (NULL), ("Packet was too short (%d < 4)", payload_len));
+    goto request_keyframe;
+  }
+ignore_reserved:
+  {
+    GST_WARNING_OBJECT (rtptheoradepay, "reserved TDT ignored");
+    goto out;
+  }
+length_short:
+  {
+    GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
+        (NULL), ("Packet contains invalid data"));
+    goto request_keyframe;
+  }
+invalid_configuration:
+  {
+    /* fatal, as we otherwise risk carrying on without output */
+    GST_ELEMENT_ERROR (rtptheoradepay, STREAM, DECODE,
+        (NULL), ("Packet contains invalid configuration"));
+    goto request_config;
+  }
+request_config:
+  {
+    gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
+        gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+            gst_structure_new ("GstForceKeyUnit",
+                "all-headers", G_TYPE_BOOLEAN, TRUE, NULL)));
+    goto out;
+  }
+request_keyframe:
+  {
+    rtptheoradepay->needs_keyframe = TRUE;
+    gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
+        gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+            gst_structure_new_empty ("GstForceKeyUnit")));
+    goto out;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_theora_depay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpTheoraDepay *rtptheoradepay;
+  GstStateChangeReturn ret;
+
+  rtptheoradepay = GST_RTP_THEORA_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      free_indents (rtptheoradepay);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_theora_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtptheoradepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_THEORA_DEPAY);
+}
+
+static gboolean
+gst_rtp_theora_depay_packet_lost (GstRTPBaseDepayload * depayload,
+    GstEvent * event)
+{
+  GstRtpTheoraDepay *rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
+  guint seqnum = 0;
+
+  gst_structure_get_uint (gst_event_get_structure (event), "seqnum", &seqnum);
+  GST_LOG_OBJECT (depayload, "Requested keyframe because frame with seqnum %u"
+      " is missing", seqnum);
+  rtptheoradepay->needs_keyframe = TRUE;
+
+  gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
+      gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+          gst_structure_new_empty ("GstForceKeyUnit")));
+
+  return TRUE;
+}
diff --git a/gst/rtp/gstrtptheoradepay.h b/gst/rtp/gstrtptheoradepay.h
new file mode 100644
index 0000000..2b0b260
--- /dev/null
+++ b/gst/rtp/gstrtptheoradepay.h
@@ -0,0 +1,72 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_THEORA_DEPAY_H__
+#define __GST_RTP_THEORA_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_THEORA_DEPAY \
+  (gst_rtp_theora_depay_get_type())
+#define GST_RTP_THEORA_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_THEORA_DEPAY,GstRtpTheoraDepay))
+#define GST_RTP_THEORA_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_THEORA_DEPAY,GstRtpTheoraDepayClass))
+#define GST_IS_RTP_THEORA_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_THEORA_DEPAY))
+#define GST_IS_RTP_THEORA_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_THEORA_DEPAY))
+
+typedef struct _GstRtpTheoraDepay GstRtpTheoraDepay;
+typedef struct _GstRtpTheoraDepayClass GstRtpTheoraDepayClass;
+
+typedef struct _GstRtpTheoraConfig {
+  guint32  ident;
+  GList   *headers;
+} GstRtpTheoraConfig;
+
+struct _GstRtpTheoraDepay
+{
+  GstRTPBaseDepayload parent;
+
+  GList              *configs;
+  GstRtpTheoraConfig *config;
+
+  GstAdapter         *adapter;
+  gboolean            assembling;
+
+  gboolean            needs_keyframe;
+};
+
+struct _GstRtpTheoraDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_theora_depay_get_type (void);
+
+gboolean gst_rtp_theora_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_THEORA_DEPAY_H__ */
diff --git a/gst/rtp/gstrtptheorapay.c b/gst/rtp/gstrtptheorapay.c
new file mode 100644
index 0000000..f9839bc
--- /dev/null
+++ b/gst/rtp/gstrtptheorapay.c
@@ -0,0 +1,982 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+
+#include "fnv1hash.h"
+#include "gstrtptheorapay.h"
+#include "gstrtputils.h"
+
+#define THEORA_ID_LEN	42
+
+GST_DEBUG_CATEGORY_STATIC (rtptheorapay_debug);
+#define GST_CAT_DEFAULT (rtptheorapay_debug)
+
+/* references:
+ * http://svn.xiph.org/trunk/theora/doc/draft-ietf-avt-rtp-theora-01.txt
+ */
+
+static GstStaticPadTemplate gst_rtp_theora_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 90000, " "encoding-name = (string) \"THEORA\""
+        /* All required parameters
+         *
+         * "sampling = (string) { "YCbCr-4:2:0", "YCbCr-4:2:2", "YCbCr-4:4:4" } "
+         * "width = (string) [1, 1048561] (multiples of 16) "
+         * "height = (string) [1, 1048561] (multiples of 16) "
+         * "configuration = (string) ANY"
+         */
+        /* All optional parameters
+         *
+         * "configuration-uri ="
+         * "delivery-method = (string) { inline, in_band, out_band/<specific_name> } "
+         */
+    )
+    );
+
+static GstStaticPadTemplate gst_rtp_theora_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-theora")
+    );
+
+#define DEFAULT_CONFIG_INTERVAL 0
+
+enum
+{
+  PROP_0,
+  PROP_CONFIG_INTERVAL
+};
+
+#define gst_rtp_theora_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpTheoraPay, gst_rtp_theora_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static gboolean gst_rtp_theora_pay_setcaps (GstRTPBasePayload * basepayload,
+    GstCaps * caps);
+static GstStateChangeReturn gst_rtp_theora_pay_change_state (GstElement *
+    element, GstStateChange transition);
+static GstFlowReturn gst_rtp_theora_pay_handle_buffer (GstRTPBasePayload * pad,
+    GstBuffer * buffer);
+static gboolean gst_rtp_theora_pay_sink_event (GstRTPBasePayload * payload,
+    GstEvent * event);
+
+static gboolean gst_rtp_theora_pay_parse_id (GstRTPBasePayload * basepayload,
+    guint8 * data, guint size);
+static gboolean gst_rtp_theora_pay_finish_headers (GstRTPBasePayload *
+    basepayload);
+
+static void gst_rtp_theora_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_theora_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void
+gst_rtp_theora_pay_class_init (GstRtpTheoraPayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gstelement_class->change_state = gst_rtp_theora_pay_change_state;
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_theora_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_theora_pay_handle_buffer;
+  gstrtpbasepayload_class->sink_event = gst_rtp_theora_pay_sink_event;
+
+  gobject_class->set_property = gst_rtp_theora_pay_set_property;
+  gobject_class->get_property = gst_rtp_theora_pay_get_property;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_theora_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_theora_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Theora payloader", "Codec/Payloader/Network/RTP",
+      "Payload-encode Theora video into RTP packets (draft-01 RFC XXXX)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtptheorapay_debug, "rtptheorapay", 0,
+      "Theora RTP Payloader");
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CONFIG_INTERVAL,
+      g_param_spec_uint ("config-interval", "Config Send Interval",
+          "Send Config Insertion Interval in seconds (configuration headers "
+          "will be multiplexed in the data stream when detected.) (0 = disabled)",
+          0, 3600, DEFAULT_CONFIG_INTERVAL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+}
+
+static void
+gst_rtp_theora_pay_init (GstRtpTheoraPay * rtptheorapay)
+{
+  rtptheorapay->last_config = GST_CLOCK_TIME_NONE;
+}
+
+static void
+gst_rtp_theora_pay_clear_packet (GstRtpTheoraPay * rtptheorapay)
+{
+  if (rtptheorapay->packet)
+    gst_buffer_unref (rtptheorapay->packet);
+  rtptheorapay->packet = NULL;
+  g_list_free_full (rtptheorapay->packet_buffers,
+      (GDestroyNotify) gst_buffer_unref);
+  rtptheorapay->packet_buffers = NULL;
+}
+
+static void
+gst_rtp_theora_pay_cleanup (GstRtpTheoraPay * rtptheorapay)
+{
+  gst_rtp_theora_pay_clear_packet (rtptheorapay);
+  g_list_free_full (rtptheorapay->headers, (GDestroyNotify) gst_buffer_unref);
+  rtptheorapay->headers = NULL;
+  g_free (rtptheorapay->config_data);
+  rtptheorapay->config_data = NULL;
+  rtptheorapay->last_config = GST_CLOCK_TIME_NONE;
+}
+
+static gboolean
+gst_rtp_theora_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+  GstRtpTheoraPay *rtptheorapay;
+  GstStructure *s;
+  const GValue *array;
+  gint asize, i;
+  GstBuffer *buf;
+  GstMapInfo map;
+
+  rtptheorapay = GST_RTP_THEORA_PAY (basepayload);
+
+  s = gst_caps_get_structure (caps, 0);
+
+  rtptheorapay->need_headers = TRUE;
+
+  if ((array = gst_structure_get_value (s, "streamheader")) == NULL)
+    goto done;
+
+  if (G_VALUE_TYPE (array) != GST_TYPE_ARRAY)
+    goto done;
+
+  if ((asize = gst_value_array_get_size (array)) < 3)
+    goto done;
+
+  for (i = 0; i < asize; i++) {
+    const GValue *value;
+
+    value = gst_value_array_get_value (array, i);
+    if ((buf = gst_value_get_buffer (value)) == NULL)
+      goto null_buffer;
+
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    /* no data packets allowed */
+    if (map.size < 1)
+      goto invalid_streamheader;
+
+    /* we need packets with id 0x80, 0x81, 0x82 */
+    if (map.data[0] != 0x80 + i)
+      goto invalid_streamheader;
+
+    if (i == 0) {
+      /* identification, we need to parse this in order to get the clock rate. */
+      if (G_UNLIKELY (!gst_rtp_theora_pay_parse_id (basepayload, map.data,
+                  map.size)))
+        goto parse_id_failed;
+    }
+    GST_DEBUG_OBJECT (rtptheorapay, "collecting header %d", i);
+    rtptheorapay->headers =
+        g_list_append (rtptheorapay->headers, gst_buffer_ref (buf));
+    gst_buffer_unmap (buf, &map);
+  }
+  if (!gst_rtp_theora_pay_finish_headers (basepayload))
+    goto finish_failed;
+
+done:
+  return TRUE;
+
+  /* ERRORS */
+null_buffer:
+  {
+    GST_WARNING_OBJECT (rtptheorapay, "streamheader with null buffer received");
+    return FALSE;
+  }
+invalid_streamheader:
+  {
+    GST_WARNING_OBJECT (rtptheorapay, "unable to parse initial header");
+    gst_buffer_unmap (buf, &map);
+    return FALSE;
+  }
+parse_id_failed:
+  {
+    GST_WARNING_OBJECT (rtptheorapay, "unable to parse initial header");
+    gst_buffer_unmap (buf, &map);
+    return FALSE;
+  }
+finish_failed:
+  {
+    GST_WARNING_OBJECT (rtptheorapay, "unable to finish headers");
+    return FALSE;
+  }
+}
+
+static void
+gst_rtp_theora_pay_reset_packet (GstRtpTheoraPay * rtptheorapay, guint8 TDT)
+{
+  guint payload_len;
+  GstRTPBuffer rtp = { NULL };
+
+  GST_DEBUG_OBJECT (rtptheorapay, "reset packet");
+
+  rtptheorapay->payload_pos = 4;
+  gst_rtp_buffer_map (rtptheorapay->packet, GST_MAP_READ, &rtp);
+  payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+  gst_rtp_buffer_unmap (&rtp);
+  rtptheorapay->payload_left = payload_len - 4;
+  rtptheorapay->payload_duration = 0;
+  rtptheorapay->payload_F = 0;
+  rtptheorapay->payload_TDT = TDT;
+  rtptheorapay->payload_pkts = 0;
+}
+
+static void
+gst_rtp_theora_pay_init_packet (GstRtpTheoraPay * rtptheorapay, guint8 TDT,
+    GstClockTime timestamp)
+{
+  GST_DEBUG_OBJECT (rtptheorapay, "starting new packet, TDT: %d", TDT);
+
+  gst_rtp_theora_pay_clear_packet (rtptheorapay);
+
+  /* new packet allocate max packet size */
+  rtptheorapay->packet =
+      gst_rtp_buffer_new_allocate_len (GST_RTP_BASE_PAYLOAD_MTU
+      (rtptheorapay), 0, 0);
+  gst_rtp_theora_pay_reset_packet (rtptheorapay, TDT);
+
+  GST_BUFFER_PTS (rtptheorapay->packet) = timestamp;
+}
+
+static GstFlowReturn
+gst_rtp_theora_pay_flush_packet (GstRtpTheoraPay * rtptheorapay)
+{
+  GstFlowReturn ret;
+  guint8 *payload;
+  guint hlen;
+  GstRTPBuffer rtp = { NULL };
+  GList *l;
+
+  /* check for empty packet */
+  if (!rtptheorapay->packet || rtptheorapay->payload_pos <= 4)
+    return GST_FLOW_OK;
+
+  GST_DEBUG_OBJECT (rtptheorapay, "flushing packet");
+
+  gst_rtp_buffer_map (rtptheorapay->packet, GST_MAP_WRITE, &rtp);
+
+  /* fix header */
+  payload = gst_rtp_buffer_get_payload (&rtp);
+  /*
+   *  0                   1                   2                   3
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                     Ident                     | F |TDT|# pkts.|
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   *
+   * F: Fragment type (0=none, 1=start, 2=cont, 3=end)
+   * TDT: Theora data type (0=theora, 1=config, 2=comment, 3=reserved)
+   * pkts: number of packets.
+   */
+  payload[0] = (rtptheorapay->payload_ident >> 16) & 0xff;
+  payload[1] = (rtptheorapay->payload_ident >> 8) & 0xff;
+  payload[2] = (rtptheorapay->payload_ident) & 0xff;
+  payload[3] = (rtptheorapay->payload_F & 0x3) << 6 |
+      (rtptheorapay->payload_TDT & 0x3) << 4 |
+      (rtptheorapay->payload_pkts & 0xf);
+
+  gst_rtp_buffer_unmap (&rtp);
+
+  /* shrink the buffer size to the last written byte */
+  hlen = gst_rtp_buffer_calc_header_len (0);
+  gst_buffer_resize (rtptheorapay->packet, 0, hlen + rtptheorapay->payload_pos);
+
+  GST_BUFFER_DURATION (rtptheorapay->packet) = rtptheorapay->payload_duration;
+
+  for (l = g_list_last (rtptheorapay->packet_buffers); l; l = l->prev) {
+    GstBuffer *buf = GST_BUFFER_CAST (l->data);
+    gst_rtp_copy_video_meta (rtptheorapay, rtptheorapay->packet, buf);
+    gst_buffer_unref (buf);
+  }
+  g_list_free (rtptheorapay->packet_buffers);
+  rtptheorapay->packet_buffers = NULL;
+
+  /* push, this gives away our ref to the packet, so clear it. */
+  ret =
+      gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtptheorapay),
+      rtptheorapay->packet);
+  rtptheorapay->packet = NULL;
+
+  return ret;
+}
+
+static gboolean
+gst_rtp_theora_pay_finish_headers (GstRTPBasePayload * basepayload)
+{
+  GstRtpTheoraPay *rtptheorapay = GST_RTP_THEORA_PAY (basepayload);
+  GList *walk;
+  guint length, size, n_headers, configlen, extralen;
+  gchar *wstr, *hstr, *configuration;
+  guint8 *data, *config;
+  guint32 ident;
+  gboolean res;
+  const gchar *sampling = NULL;
+
+  GST_DEBUG_OBJECT (rtptheorapay, "finish headers");
+
+  if (!rtptheorapay->headers) {
+    GST_DEBUG_OBJECT (rtptheorapay, "We need 2 headers but have none");
+    goto no_headers;
+  }
+
+  /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                     Number of packed headers                  |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Packed header                        |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Packed header                        |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          ....                                 |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   *
+   * We only construct a config containing 1 packed header like this:
+   *
+   *  0                   1                   2                   3
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                   Ident                       | length       ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..              | n. of headers |    length1    |    length2   ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..              |             Identification Header            ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * .................................................................
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..              |         Comment Header                       ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * .................................................................
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..                        Comment Header                        |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Setup Header                        ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * .................................................................
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..                         Setup Header                         |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   */
+
+  /* we need 4 bytes for the number of headers (which is always 1), 3 bytes for
+   * the ident, 2 bytes for length, 1 byte for n. of headers. */
+  size = 4 + 3 + 2 + 1;
+
+  /* count the size of the headers first and update the hash */
+  length = 0;
+  n_headers = 0;
+  ident = fnv1_hash_32_new ();
+  extralen = 1;
+  for (walk = rtptheorapay->headers; walk; walk = g_list_next (walk)) {
+    GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+    GstMapInfo map;
+    guint bsize;
+
+    bsize = gst_buffer_get_size (buf);
+    length += bsize;
+    n_headers++;
+
+    /* count number of bytes needed for length fields, we don't need this for
+     * the last header. */
+    if (g_list_next (walk)) {
+      do {
+        size++;
+        extralen++;
+        bsize >>= 7;
+      } while (bsize);
+    }
+    /* update hash */
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    ident = fnv1_hash_32_update (ident, map.data, map.size);
+    gst_buffer_unmap (buf, &map);
+  }
+
+  /* packet length is header size + packet length */
+  configlen = size + length;
+  config = data = g_malloc (configlen);
+
+  /* number of packed headers, we only pack 1 header */
+  data[0] = 0;
+  data[1] = 0;
+  data[2] = 0;
+  data[3] = 1;
+
+  ident = fnv1_hash_32_to_24 (ident);
+  rtptheorapay->payload_ident = ident;
+  GST_DEBUG_OBJECT (rtptheorapay, "ident 0x%08x", ident);
+
+  /* take lower 3 bytes */
+  data[4] = (ident >> 16) & 0xff;
+  data[5] = (ident >> 8) & 0xff;
+  data[6] = ident & 0xff;
+
+  /* store length of all theora headers */
+  data[7] = ((length) >> 8) & 0xff;
+  data[8] = (length) & 0xff;
+
+  /* store number of headers minus one. */
+  data[9] = n_headers - 1;
+  data += 10;
+
+  /* store length for each header */
+  for (walk = rtptheorapay->headers; walk; walk = g_list_next (walk)) {
+    GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+    guint bsize, size, temp;
+    guint flag;
+
+    /* only need to store the length when it's not the last header */
+    if (!g_list_next (walk))
+      break;
+
+    bsize = gst_buffer_get_size (buf);
+
+    /* calc size */
+    size = 0;
+    do {
+      size++;
+      bsize >>= 7;
+    } while (bsize);
+    temp = size;
+
+    bsize = gst_buffer_get_size (buf);
+    /* write the size backwards */
+    flag = 0;
+    while (size) {
+      size--;
+      data[size] = (bsize & 0x7f) | flag;
+      bsize >>= 7;
+      flag = 0x80;              /* Flag bit on all bytes of the length except the last */
+    }
+    data += temp;
+  }
+
+  /* copy header data */
+  for (walk = rtptheorapay->headers; walk; walk = g_list_next (walk)) {
+    GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+
+    gst_buffer_extract (buf, 0, data, gst_buffer_get_size (buf));
+    data += gst_buffer_get_size (buf);
+  }
+  rtptheorapay->need_headers = FALSE;
+
+  /* serialize to base64 */
+  configuration = g_base64_encode (config, configlen);
+
+  /* store for later re-sending */
+  g_free (rtptheorapay->config_data);
+  rtptheorapay->config_size = configlen - 4 - 3 - 2;
+  rtptheorapay->config_data = g_malloc (rtptheorapay->config_size);
+  rtptheorapay->config_extra_len = extralen;
+  memcpy (rtptheorapay->config_data, config + 4 + 3 + 2,
+      rtptheorapay->config_size);
+
+  g_free (config);
+
+  /* configure payloader settings */
+  switch (rtptheorapay->pixel_format) {
+    case 2:
+      sampling = "YCbCr-4:2:2";
+      break;
+    case 3:
+      sampling = "YCbCr-4:4:4";
+      break;
+    case 0:
+    default:
+      sampling = "YCbCr-4:2:0";
+      break;
+  }
+
+
+  wstr = g_strdup_printf ("%d", rtptheorapay->width);
+  hstr = g_strdup_printf ("%d", rtptheorapay->height);
+  gst_rtp_base_payload_set_options (basepayload, "video", TRUE, "THEORA",
+      90000);
+  res =
+      gst_rtp_base_payload_set_outcaps (basepayload, "sampling", G_TYPE_STRING,
+      sampling, "width", G_TYPE_STRING, wstr, "height", G_TYPE_STRING,
+      hstr, "configuration", G_TYPE_STRING, configuration, "delivery-method",
+      G_TYPE_STRING, "inline",
+      /* don't set the other defaults 
+       */
+      NULL);
+  g_free (wstr);
+  g_free (hstr);
+  g_free (configuration);
+
+  return res;
+
+  /* ERRORS */
+no_headers:
+  {
+    GST_DEBUG_OBJECT (rtptheorapay, "finish headers");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_rtp_theora_pay_parse_id (GstRTPBasePayload * basepayload, guint8 * data,
+    guint size)
+{
+  GstRtpTheoraPay *rtptheorapay;
+  gint width, height, pixel_format;
+
+  rtptheorapay = GST_RTP_THEORA_PAY (basepayload);
+
+  if (G_UNLIKELY (size < 42))
+    goto too_short;
+
+  if (G_UNLIKELY (memcmp (data, "\200theora", 7)))
+    goto invalid_start;
+  data += 7;
+
+  if (G_UNLIKELY (data[0] != 3))
+    goto invalid_version;
+  if (G_UNLIKELY (data[1] != 2))
+    goto invalid_version;
+  data += 3;
+
+  width = GST_READ_UINT16_BE (data) << 4;
+  data += 2;
+  height = GST_READ_UINT16_BE (data) << 4;
+  data += 29;
+
+  pixel_format = (GST_READ_UINT8 (data) >> 3) & 0x03;
+
+  /* store values */
+  rtptheorapay->pixel_format = pixel_format;
+  rtptheorapay->width = width;
+  rtptheorapay->height = height;
+
+  return TRUE;
+
+  /* ERRORS */
+too_short:
+  {
+    GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+        (NULL),
+        ("Identification packet is too short, need at least 42, got %d", size));
+    return FALSE;
+  }
+invalid_start:
+  {
+    GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+        (NULL), ("Invalid header start in identification packet"));
+    return FALSE;
+  }
+invalid_version:
+  {
+    GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+        (NULL), ("Invalid version"));
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_rtp_theora_pay_payload_buffer (GstRtpTheoraPay * rtptheorapay, guint8 TDT,
+    GstBuffer * buffer, guint8 * data, guint size, GstClockTime timestamp,
+    GstClockTime duration, guint not_in_length)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint newsize;
+  guint packet_len;
+  GstClockTime newduration;
+  gboolean flush;
+  guint plen;
+  guint8 *ppos, *payload;
+  gboolean fragmented;
+  GstRTPBuffer rtp = { NULL };
+
+  /* size increases with packet length and 2 bytes size eader. */
+  newduration = rtptheorapay->payload_duration;
+  if (duration != GST_CLOCK_TIME_NONE)
+    newduration += duration;
+
+  newsize = rtptheorapay->payload_pos + 2 + size;
+  packet_len = gst_rtp_buffer_calc_packet_len (newsize, 0, 0);
+
+  /* check buffer filled against length and max latency */
+  flush = gst_rtp_base_payload_is_filled (GST_RTP_BASE_PAYLOAD (rtptheorapay),
+      packet_len, newduration);
+  /* we can store up to 15 theora packets in one RTP packet. */
+  flush |= (rtptheorapay->payload_pkts == 15);
+  /* flush if we have a new TDT */
+  if (rtptheorapay->packet)
+    flush |= (rtptheorapay->payload_TDT != TDT);
+  if (flush)
+    ret = gst_rtp_theora_pay_flush_packet (rtptheorapay);
+
+  if (ret != GST_FLOW_OK)
+    goto done;
+
+  /* create new packet if we must */
+  if (!rtptheorapay->packet) {
+    gst_rtp_theora_pay_init_packet (rtptheorapay, TDT, timestamp);
+  }
+
+  gst_rtp_buffer_map (rtptheorapay->packet, GST_MAP_WRITE, &rtp);
+  payload = gst_rtp_buffer_get_payload (&rtp);
+  ppos = payload + rtptheorapay->payload_pos;
+  fragmented = FALSE;
+
+  /* put buffer in packet, it either fits completely or needs to be fragmented
+   * over multiple RTP packets. */
+  do {
+    plen = MIN (rtptheorapay->payload_left - 2, size);
+
+    GST_DEBUG_OBJECT (rtptheorapay, "append %u bytes", plen);
+
+    /* data is copied in the payload with a 2 byte length header */
+    ppos[0] = ((plen - not_in_length) >> 8) & 0xff;
+    ppos[1] = ((plen - not_in_length) & 0xff);
+    if (plen)
+      memcpy (&ppos[2], data, plen);
+
+    if (buffer) {
+      if (!rtptheorapay->packet_buffers
+          || rtptheorapay->packet_buffers->data != (gpointer) buffer)
+        rtptheorapay->packet_buffers =
+            g_list_prepend (rtptheorapay->packet_buffers,
+            gst_buffer_ref (buffer));
+    } else {
+      GList *l;
+
+      for (l = rtptheorapay->headers; l; l = l->next)
+        rtptheorapay->packet_buffers =
+            g_list_prepend (rtptheorapay->packet_buffers,
+            gst_buffer_ref (l->data));
+    }
+
+    /* only first (only) configuration cuts length field */
+    /* NOTE: spec (if any) is not clear on this ... */
+    not_in_length = 0;
+
+    size -= plen;
+    data += plen;
+
+    rtptheorapay->payload_pos += plen + 2;
+    rtptheorapay->payload_left -= plen + 2;
+
+    if (fragmented) {
+      if (size == 0)
+        /* last fragment, set F to 0x3. */
+        rtptheorapay->payload_F = 0x3;
+      else
+        /* fragment continues, set F to 0x2. */
+        rtptheorapay->payload_F = 0x2;
+    } else {
+      if (size > 0) {
+        /* fragmented packet starts, set F to 0x1, mark ourselves as
+         * fragmented. */
+        rtptheorapay->payload_F = 0x1;
+        fragmented = TRUE;
+      }
+    }
+    if (fragmented) {
+      gst_rtp_buffer_unmap (&rtp);
+      /* fragmented packets are always flushed and have ptks of 0 */
+      rtptheorapay->payload_pkts = 0;
+      ret = gst_rtp_theora_pay_flush_packet (rtptheorapay);
+
+      if (size > 0) {
+        /* start new packet and get pointers. TDT stays the same. */
+        gst_rtp_theora_pay_init_packet (rtptheorapay,
+            rtptheorapay->payload_TDT, timestamp);
+        gst_rtp_buffer_map (rtptheorapay->packet, GST_MAP_WRITE, &rtp);
+        payload = gst_rtp_buffer_get_payload (&rtp);
+        ppos = payload + rtptheorapay->payload_pos;
+      }
+    } else {
+      /* unfragmented packet, update stats for next packet, size == 0 and we
+       * exit the while loop */
+      rtptheorapay->payload_pkts++;
+      if (duration != GST_CLOCK_TIME_NONE)
+        rtptheorapay->payload_duration += duration;
+    }
+  } while (size && ret == GST_FLOW_OK);
+
+  if (rtp.buffer)
+    gst_rtp_buffer_unmap (&rtp);
+done:
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_rtp_theora_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpTheoraPay *rtptheorapay;
+  GstFlowReturn ret;
+  GstMapInfo map;
+  gsize size;
+  guint8 *data;
+  GstClockTime duration, timestamp;
+  guint8 TDT;
+  gboolean keyframe = FALSE;
+
+  rtptheorapay = GST_RTP_THEORA_PAY (basepayload);
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  data = map.data;
+  size = map.size;
+  duration = GST_BUFFER_DURATION (buffer);
+  timestamp = GST_BUFFER_PTS (buffer);
+
+  GST_DEBUG_OBJECT (rtptheorapay, "size %" G_GSIZE_FORMAT
+      ", duration %" GST_TIME_FORMAT, size, GST_TIME_ARGS (duration));
+
+  /* find packet type */
+  if (size == 0) {
+    TDT = 0;
+    keyframe = FALSE;
+  } else if (data[0] & 0x80) {
+    /* header */
+    if (data[0] == 0x80) {
+      /* identification, we need to parse this in order to get the clock rate.
+       */
+      if (G_UNLIKELY (!gst_rtp_theora_pay_parse_id (basepayload, data, size)))
+        goto parse_id_failed;
+      TDT = 1;
+    } else if (data[0] == 0x81) {
+      /* comment */
+      TDT = 2;
+    } else if (data[0] == 0x82) {
+      /* setup */
+      TDT = 1;
+    } else
+      goto unknown_header;
+  } else {
+    /* data */
+    TDT = 0;
+    keyframe = ((data[0] & 0x40) == 0);
+  }
+
+  /* we need to collect the headers and construct a config string from them */
+  if (TDT != 0) {
+    GST_DEBUG_OBJECT (rtptheorapay, "collecting header, buffer %p", buffer);
+    /* append header to the list of headers */
+    gst_buffer_unmap (buffer, &map);
+    rtptheorapay->headers = g_list_append (rtptheorapay->headers, buffer);
+    ret = GST_FLOW_OK;
+    goto done;
+  } else if (rtptheorapay->headers && rtptheorapay->need_headers) {
+    if (!gst_rtp_theora_pay_finish_headers (basepayload))
+      goto header_error;
+  }
+
+  /* there is a config request, see if we need to insert it */
+  if (keyframe && (rtptheorapay->config_interval > 0) &&
+      rtptheorapay->config_data) {
+    gboolean send_config = FALSE;
+
+    if (rtptheorapay->last_config != -1) {
+      guint64 diff;
+
+      GST_LOG_OBJECT (rtptheorapay,
+          "now %" GST_TIME_FORMAT ", last VOP-I %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (timestamp), GST_TIME_ARGS (rtptheorapay->last_config));
+
+      /* calculate diff between last config in milliseconds */
+      if (timestamp > rtptheorapay->last_config) {
+        diff = timestamp - rtptheorapay->last_config;
+      } else {
+        diff = 0;
+      }
+
+      GST_DEBUG_OBJECT (rtptheorapay,
+          "interval since last config %" GST_TIME_FORMAT, GST_TIME_ARGS (diff));
+
+      /* bigger than interval, queue config */
+      /* FIXME should convert timestamps to running time */
+      if (GST_TIME_AS_SECONDS (diff) >= rtptheorapay->config_interval) {
+        GST_DEBUG_OBJECT (rtptheorapay, "time to send config");
+        send_config = TRUE;
+      }
+    } else {
+      /* no known previous config time, send now */
+      GST_DEBUG_OBJECT (rtptheorapay, "no previous config time, send now");
+      send_config = TRUE;
+    }
+
+    if (send_config) {
+      /* we need to send config now first */
+      /* different TDT type forces flush */
+      gst_rtp_theora_pay_payload_buffer (rtptheorapay, 1,
+          NULL, rtptheorapay->config_data, rtptheorapay->config_size,
+          timestamp, GST_CLOCK_TIME_NONE, rtptheorapay->config_extra_len);
+
+      if (timestamp != -1) {
+        rtptheorapay->last_config = timestamp;
+      }
+    }
+  }
+
+  ret =
+      gst_rtp_theora_pay_payload_buffer (rtptheorapay, TDT, buffer, data, size,
+      timestamp, duration, 0);
+
+  gst_buffer_unmap (buffer, &map);
+  gst_buffer_unref (buffer);
+
+done:
+  return ret;
+
+  /* ERRORS */
+parse_id_failed:
+  {
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+    return GST_FLOW_ERROR;
+  }
+unknown_header:
+  {
+    GST_ELEMENT_WARNING (rtptheorapay, STREAM, DECODE,
+        (NULL), ("Ignoring unknown header received"));
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+    return GST_FLOW_OK;
+  }
+header_error:
+  {
+    GST_ELEMENT_WARNING (rtptheorapay, STREAM, DECODE,
+        (NULL), ("Error initializing header config"));
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+    return GST_FLOW_OK;
+  }
+}
+
+static gboolean
+gst_rtp_theora_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+  GstRtpTheoraPay *rtptheorapay = GST_RTP_THEORA_PAY (payload);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      gst_rtp_theora_pay_clear_packet (rtptheorapay);
+      break;
+    default:
+      break;
+  }
+  /* false to let parent handle event as well */
+  return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+}
+
+static GstStateChangeReturn
+gst_rtp_theora_pay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpTheoraPay *rtptheorapay;
+
+  GstStateChangeReturn ret;
+
+  rtptheorapay = GST_RTP_THEORA_PAY (element);
+
+  switch (transition) {
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_theora_pay_cleanup (rtptheorapay);
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+static void
+gst_rtp_theora_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpTheoraPay *rtptheorapay;
+
+  rtptheorapay = GST_RTP_THEORA_PAY (object);
+
+  switch (prop_id) {
+    case PROP_CONFIG_INTERVAL:
+      rtptheorapay->config_interval = g_value_get_uint (value);
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_rtp_theora_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpTheoraPay *rtptheorapay;
+
+  rtptheorapay = GST_RTP_THEORA_PAY (object);
+
+  switch (prop_id) {
+    case PROP_CONFIG_INTERVAL:
+      g_value_set_uint (value, rtptheorapay->config_interval);
+      break;
+    default:
+      break;
+  }
+}
+
+gboolean
+gst_rtp_theora_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtptheorapay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_THEORA_PAY);
+}
diff --git a/gst/rtp/gstrtptheorapay.h b/gst/rtp/gstrtptheorapay.h
new file mode 100644
index 0000000..22bc01d
--- /dev/null
+++ b/gst/rtp/gstrtptheorapay.h
@@ -0,0 +1,86 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_THEORA_PAY_H__
+#define __GST_RTP_THEORA_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_THEORA_PAY \
+  (gst_rtp_theora_pay_get_type())
+#define GST_RTP_THEORA_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_THEORA_PAY,GstRtpTheoraPay))
+#define GST_RTP_THEORA_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_THEORA_PAY,GstRtpTheoraPayClass))
+#define GST_IS_RTP_THEORA_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_THEORA_PAY))
+#define GST_IS_RTP_THEORA_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_THEORA_PAY))
+
+typedef struct _GstRtpTheoraPay GstRtpTheoraPay;
+typedef struct _GstRtpTheoraPayClass GstRtpTheoraPayClass;
+
+struct _GstRtpTheoraPay
+{
+  GstRTPBasePayload payload;
+
+  /* the headers */
+  gboolean      need_headers;
+  GList        *headers;
+
+  /* queues of buffers along with some stats. */
+  GstBuffer    *packet;
+  GList        *packet_buffers;
+  guint         payload_pos;
+  guint         payload_left;
+  guint32       payload_ident;
+  guint8        payload_F;
+  guint8        payload_TDT;
+  guint         payload_pkts;
+  GstClockTime  payload_timestamp;
+  GstClockTime  payload_duration;
+
+  /* config (re-sending) */
+  guint8       *config_data;
+  guint         config_size;
+  guint         config_extra_len;
+  guint         config_interval;
+  GstClockTime  last_config;
+
+  gint          pixel_format;
+  gint          width;
+  gint          height;
+};
+
+struct _GstRtpTheoraPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_theora_pay_get_type (void);
+
+gboolean gst_rtp_theora_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_THEORA_PAY_H__ */
diff --git a/gst/rtp/gstrtputils.c b/gst/rtp/gstrtputils.c
new file mode 100644
index 0000000..044d1b3
--- /dev/null
+++ b/gst/rtp/gstrtputils.c
@@ -0,0 +1,151 @@
+/* GStreamer
+ * Copyright (C) 2015 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "gstrtputils.h"
+
+typedef struct
+{
+  GstElement *element;
+  GstBuffer *outbuf;
+  GQuark copy_tag;
+} CopyMetaData;
+
+GQuark rtp_quark_meta_tag_video;
+GQuark rtp_quark_meta_tag_audio;
+
+static gboolean
+foreach_metadata_copy (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data)
+{
+  CopyMetaData *data = user_data;
+  GstElement *element = data->element;
+  GstBuffer *outbuf = data->outbuf;
+  GQuark copy_tag = data->copy_tag;
+  const GstMetaInfo *info = (*meta)->info;
+  const gchar *const *tags = gst_meta_api_type_get_tags (info->api);
+
+  if (!tags || (copy_tag != 0 && g_strv_length ((gchar **) tags) == 1
+          && gst_meta_api_type_has_tag (info->api, copy_tag))) {
+    GstMetaTransformCopy copy_data = { FALSE, 0, -1 };
+    GST_DEBUG_OBJECT (element, "copy metadata %s", g_type_name (info->api));
+    /* simply copy then */
+    info->transform_func (outbuf, *meta, inbuf,
+        _gst_meta_transform_copy, &copy_data);
+  } else {
+    GST_DEBUG_OBJECT (element, "not copying metadata %s",
+        g_type_name (info->api));
+  }
+
+  return TRUE;
+}
+
+/* TODO: Should probably make copy_tag an array at some point */
+void
+gst_rtp_copy_meta (GstElement * element, GstBuffer * outbuf, GstBuffer * inbuf,
+    GQuark copy_tag)
+{
+  CopyMetaData data = { element, outbuf, copy_tag };
+
+  gst_buffer_foreach_meta (inbuf, foreach_metadata_copy, &data);
+}
+
+void
+gst_rtp_copy_video_meta (gpointer element, GstBuffer * outbuf,
+    GstBuffer * inbuf)
+{
+  gst_rtp_copy_meta (element, outbuf, inbuf, rtp_quark_meta_tag_video);
+}
+
+void
+gst_rtp_copy_audio_meta (gpointer element, GstBuffer * outbuf,
+    GstBuffer * inbuf)
+{
+  gst_rtp_copy_meta (element, outbuf, inbuf, rtp_quark_meta_tag_audio);
+}
+
+typedef struct
+{
+  GstElement *element;
+  GQuark keep_tag;
+} DropMetaData;
+
+static gboolean
+foreach_metadata_drop (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data)
+{
+  DropMetaData *data = user_data;
+  GstElement *element = data->element;
+  GQuark keep_tag = data->keep_tag;
+  const GstMetaInfo *info = (*meta)->info;
+  const gchar *const *tags = gst_meta_api_type_get_tags (info->api);
+
+  if (!tags || (keep_tag != 0 && g_strv_length ((gchar **) tags) == 1
+          && gst_meta_api_type_has_tag (info->api, keep_tag))) {
+    GST_DEBUG_OBJECT (element, "keeping metadata %s", g_type_name (info->api));
+  } else {
+    GST_DEBUG_OBJECT (element, "dropping metadata %s", g_type_name (info->api));
+    *meta = NULL;
+  }
+
+  return TRUE;
+}
+
+/* TODO: Should probably make keep_tag an array at some point */
+void
+gst_rtp_drop_meta (GstElement * element, GstBuffer * buf, GQuark keep_tag)
+{
+  DropMetaData data = { element, keep_tag };
+
+  gst_buffer_foreach_meta (buf, foreach_metadata_drop, &data);
+}
+
+void
+gst_rtp_drop_non_audio_meta (gpointer element, GstBuffer * buf)
+{
+  gst_rtp_drop_meta (element, buf, rtp_quark_meta_tag_audio);
+}
+
+void
+gst_rtp_drop_non_video_meta (gpointer element, GstBuffer * buf)
+{
+  gst_rtp_drop_meta (element, buf, rtp_quark_meta_tag_video);
+}
+
+/* Stolen from bad/gst/mpegtsdemux/payloader_parsers.c */
+/* variable length Exp-Golomb parsing according to H.265 spec section 9.2*/
+gboolean
+gst_rtp_read_golomb (GstBitReader * br, guint32 * value)
+{
+  guint8 b, leading_zeros = -1;
+  *value = 1;
+
+  for (b = 0; !b; leading_zeros++) {
+    if (!gst_bit_reader_get_bits_uint8 (br, &b, 1))
+      return FALSE;
+    *value *= 2;
+  }
+
+  *value = (*value >> 1) - 1;
+  if (leading_zeros > 0) {
+    guint32 tmp = 0;
+    if (!gst_bit_reader_get_bits_uint32 (br, &tmp, leading_zeros))
+      return FALSE;
+    *value += tmp;
+  }
+
+  return TRUE;
+}
diff --git a/gst/rtp/gstrtputils.h b/gst/rtp/gstrtputils.h
new file mode 100644
index 0000000..d5195f2
--- /dev/null
+++ b/gst/rtp/gstrtputils.h
@@ -0,0 +1,54 @@
+/* GStreamer
+ * Copyright (C) 2015 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_UTILS_H__
+#define __GST_RTP_UTILS_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbitreader.h>
+
+G_BEGIN_DECLS
+
+G_GNUC_INTERNAL
+void gst_rtp_copy_meta (GstElement * element, GstBuffer *outbuf, GstBuffer *inbuf, GQuark copy_tag);
+
+G_GNUC_INTERNAL
+void gst_rtp_copy_audio_meta (gpointer element, GstBuffer *outbuf, GstBuffer *inbuf);
+
+G_GNUC_INTERNAL
+void gst_rtp_copy_video_meta (gpointer element, GstBuffer *outbuf, GstBuffer *inbuf);
+
+G_GNUC_INTERNAL
+void gst_rtp_drop_meta (GstElement * element, GstBuffer *buf, GQuark keep_tag);
+
+G_GNUC_INTERNAL
+void gst_rtp_drop_non_audio_meta (gpointer element, GstBuffer * buf);
+
+G_GNUC_INTERNAL
+void gst_rtp_drop_non_video_meta (gpointer element, GstBuffer * buf);
+
+G_GNUC_INTERNAL
+gboolean gst_rtp_read_golomb (GstBitReader * br, guint32 * value);
+
+G_GNUC_INTERNAL extern GQuark rtp_quark_meta_tag_video;
+G_GNUC_INTERNAL extern GQuark rtp_quark_meta_tag_audio;
+
+G_END_DECLS
+
+#endif /* __GST_RTP_UTILS_H__ */
diff --git a/gst/rtp/gstrtpvorbisdepay.c b/gst/rtp/gstrtpvorbisdepay.c
new file mode 100644
index 0000000..762750a
--- /dev/null
+++ b/gst/rtp/gstrtpvorbisdepay.c
@@ -0,0 +1,688 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/tag/tag.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include <string.h>
+#include "gstrtpvorbisdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpvorbisdepay_debug);
+#define GST_CAT_DEFAULT (rtpvorbisdepay_debug)
+
+/* references:
+ * http://www.rfc-editor.org/rfc/rfc5215.txt
+ */
+
+static GstStaticPadTemplate gst_rtp_vorbis_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"VORBIS\""
+        /* All required parameters 
+         *
+         * "encoding-params = (string) <num channels>"
+         * "configuration = (string) ANY" 
+         */
+    )
+    );
+
+static GstStaticPadTemplate gst_rtp_vorbis_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-vorbis")
+    );
+
+#define gst_rtp_vorbis_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpVorbisDepay, gst_rtp_vorbis_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_vorbis_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_vorbis_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+
+static void gst_rtp_vorbis_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_vorbis_depay_change_state (GstElement *
+    element, GstStateChange transition);
+
+static void
+gst_rtp_vorbis_depay_class_init (GstRtpVorbisDepayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gobject_class->finalize = gst_rtp_vorbis_depay_finalize;
+
+  gstelement_class->change_state = gst_rtp_vorbis_depay_change_state;
+
+  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_vorbis_depay_process;
+  gstrtpbasedepayload_class->set_caps = gst_rtp_vorbis_depay_setcaps;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_vorbis_depay_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_vorbis_depay_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Vorbis depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts Vorbis Audio from RTP packets (RFC 5215)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpvorbisdepay_debug, "rtpvorbisdepay", 0,
+      "Vorbis RTP Depayloader");
+}
+
+static void
+gst_rtp_vorbis_depay_init (GstRtpVorbisDepay * rtpvorbisdepay)
+{
+  rtpvorbisdepay->adapter = gst_adapter_new ();
+}
+
+static void
+free_config (GstRtpVorbisConfig * conf)
+{
+  g_list_free_full (conf->headers, (GDestroyNotify) gst_buffer_unref);
+  g_free (conf);
+}
+
+static void
+free_indents (GstRtpVorbisDepay * rtpvorbisdepay)
+{
+  g_list_free_full (rtpvorbisdepay->configs, (GDestroyNotify) free_config);
+  rtpvorbisdepay->configs = NULL;
+}
+
+static void
+gst_rtp_vorbis_depay_finalize (GObject * object)
+{
+  GstRtpVorbisDepay *rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (object);
+
+  g_object_unref (rtpvorbisdepay->adapter);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* takes ownership of confbuf */
+static gboolean
+gst_rtp_vorbis_depay_parse_configuration (GstRtpVorbisDepay * rtpvorbisdepay,
+    GstBuffer * confbuf)
+{
+  GstBuffer *buf;
+  guint32 num_headers;
+  GstMapInfo map;
+  guint8 *data;
+  gsize size;
+  guint offset;
+  gint i, j;
+
+  gst_buffer_map (confbuf, &map, GST_MAP_READ);
+  data = map.data;
+  size = map.size;
+
+  GST_DEBUG_OBJECT (rtpvorbisdepay, "config size %" G_GSIZE_FORMAT, size);
+
+  /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                     Number of packed headers                  |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Packed header                        |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Packed header                        |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          ....                                 |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   */
+  if (size < 4)
+    goto too_small;
+
+  num_headers = GST_READ_UINT32_BE (data);
+  size -= 4;
+  data += 4;
+  offset = 4;
+
+  GST_DEBUG_OBJECT (rtpvorbisdepay, "have %u headers", num_headers);
+
+  /*  0                   1                   2                   3
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                   Ident                       | length       ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..              | n. of headers |    length1    |    length2   ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..              |             Identification Header            ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * .................................................................
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..              |         Comment Header                       ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * .................................................................
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..                        Comment Header                        |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Setup Header                        ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * .................................................................
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..                         Setup Header                         |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   */
+  for (i = 0; i < num_headers; i++) {
+    guint32 ident;
+    guint16 length;
+    guint8 n_headers, b;
+    GstRtpVorbisConfig *conf;
+    guint *h_sizes;
+    guint extra = 1;
+
+    if (size < 6)
+      goto too_small;
+
+    ident = (data[0] << 16) | (data[1] << 8) | data[2];
+    length = (data[3] << 8) | data[4];
+    n_headers = data[5];
+    size -= 6;
+    data += 6;
+    offset += 6;
+
+    GST_DEBUG_OBJECT (rtpvorbisdepay,
+        "header %d, ident 0x%08x, length %u, left %" G_GSIZE_FORMAT, i, ident,
+        length, size);
+
+    /* FIXME check if we already got this ident */
+
+    /* length might also include count of following size fields */
+    if (size < length && size + 1 != length)
+      goto too_small;
+
+    /* read header sizes we read 2 sizes, the third size (for which we allocate
+     * space) must be derived from the total packed header length. */
+    h_sizes = g_newa (guint, n_headers + 1);
+    for (j = 0; j < n_headers; j++) {
+      guint h_size;
+
+      h_size = 0;
+      do {
+        if (size < 1)
+          goto too_small;
+        b = *data++;
+        offset++;
+        extra++;
+        size--;
+        h_size = (h_size << 7) | (b & 0x7f);
+      } while (b & 0x80);
+      GST_DEBUG_OBJECT (rtpvorbisdepay, "headers %d: size: %u", j, h_size);
+
+      if (length < h_size)
+        goto too_small;
+
+      h_sizes[j] = h_size;
+      length -= h_size;
+    }
+    /* last header length is the remaining space */
+    GST_DEBUG_OBJECT (rtpvorbisdepay, "last header size: %u", length);
+    h_sizes[j] = length;
+
+    GST_DEBUG_OBJECT (rtpvorbisdepay, "preparing headers");
+    conf = g_new0 (GstRtpVorbisConfig, 1);
+    conf->ident = ident;
+
+    for (j = 0; j <= n_headers; j++) {
+      guint h_size;
+
+      h_size = h_sizes[j];
+      if (size < h_size) {
+        if (j != n_headers || size + extra != h_size) {
+          free_config (conf);
+          goto too_small;
+        } else {
+          /* otherwise means that overall length field contained total length,
+           * including extra fields */
+          h_size -= extra;
+        }
+      }
+
+      GST_DEBUG_OBJECT (rtpvorbisdepay, "reading header %d, size %u", j,
+          h_size);
+
+      buf = gst_buffer_copy_region (confbuf, GST_BUFFER_COPY_ALL, offset,
+          h_size);
+      conf->headers = g_list_append (conf->headers, buf);
+      offset += h_size;
+      size -= h_size;
+    }
+    rtpvorbisdepay->configs = g_list_append (rtpvorbisdepay->configs, conf);
+  }
+
+  gst_buffer_unmap (confbuf, &map);
+  gst_buffer_unref (confbuf);
+
+  return TRUE;
+
+  /* ERRORS */
+too_small:
+  {
+    GST_DEBUG_OBJECT (rtpvorbisdepay, "configuration too small");
+    gst_buffer_unmap (confbuf, &map);
+    gst_buffer_unref (confbuf);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_rtp_vorbis_depay_parse_inband_configuration (GstRtpVorbisDepay *
+    rtpvorbisdepay, guint ident, guint8 * configuration, guint size,
+    guint length)
+{
+  GstBuffer *confbuf;
+  GstMapInfo map;
+
+  if (G_UNLIKELY (size < 4))
+    return FALSE;
+
+  /* transform inline to out-of-band and parse that one */
+  confbuf = gst_buffer_new_and_alloc (size + 9);
+  gst_buffer_map (confbuf, &map, GST_MAP_WRITE);
+  /* 1 header */
+  GST_WRITE_UINT32_BE (map.data, 1);
+  /* write Ident */
+  GST_WRITE_UINT24_BE (map.data + 4, ident);
+  /* write sort-of-length */
+  GST_WRITE_UINT16_BE (map.data + 7, length);
+  /* copy remainder */
+  memcpy (map.data + 9, configuration, size);
+  gst_buffer_unmap (confbuf, &map);
+
+  return gst_rtp_vorbis_depay_parse_configuration (rtpvorbisdepay, confbuf);
+}
+
+static gboolean
+gst_rtp_vorbis_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstRtpVorbisDepay *rtpvorbisdepay;
+  GstCaps *srccaps;
+  const gchar *configuration;
+  gint clock_rate;
+  gboolean res;
+
+  rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  /* get clockrate */
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    goto no_rate;
+
+  /* read and parse configuration string */
+  configuration = gst_structure_get_string (structure, "configuration");
+  if (configuration) {
+    GstBuffer *confbuf;
+    guint8 *data;
+    gsize size;
+
+    /* deserialize base64 to buffer */
+    data = g_base64_decode (configuration, &size);
+
+    confbuf = gst_buffer_new ();
+    gst_buffer_append_memory (confbuf,
+        gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
+    if (!gst_rtp_vorbis_depay_parse_configuration (rtpvorbisdepay, confbuf))
+      goto invalid_configuration;
+  } else {
+    GST_WARNING_OBJECT (rtpvorbisdepay, "no configuration specified");
+  }
+
+  /* caps seem good, configure element */
+  depayload->clock_rate = clock_rate;
+
+  /* set caps on pad and on header */
+  srccaps = gst_caps_new_empty_simple ("audio/x-vorbis");
+  res = gst_pad_set_caps (depayload->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  return res;
+
+  /* ERRORS */
+invalid_configuration:
+  {
+    GST_ERROR_OBJECT (rtpvorbisdepay, "invalid configuration specified");
+    return FALSE;
+  }
+no_rate:
+  {
+    GST_ERROR_OBJECT (rtpvorbisdepay, "no clock-rate specified");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_rtp_vorbis_depay_switch_codebook (GstRtpVorbisDepay * rtpvorbisdepay,
+    guint32 ident)
+{
+  GList *walk;
+  gboolean res = FALSE;
+
+  GST_DEBUG_OBJECT (rtpvorbisdepay, "Looking up code book ident 0x%08x", ident);
+  for (walk = rtpvorbisdepay->configs; walk; walk = g_list_next (walk)) {
+    GstRtpVorbisConfig *conf = (GstRtpVorbisConfig *) walk->data;
+
+    if (conf->ident == ident) {
+      GList *headers;
+
+      /* FIXME, remove pads, create new pad.. */
+
+      /* push out all the headers */
+      for (headers = conf->headers; headers; headers = g_list_next (headers)) {
+        GstBuffer *header = GST_BUFFER_CAST (headers->data);
+
+        gst_buffer_ref (header);
+        gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpvorbisdepay),
+            header);
+      }
+      /* remember the current config */
+      rtpvorbisdepay->config = conf;
+      res = TRUE;
+    }
+  }
+  if (!res) {
+    /* we don't know about the headers, figure out an alternative method for
+     * getting the codebooks. FIXME, fail for now. */
+  }
+  return res;
+}
+
+static GstBuffer *
+gst_rtp_vorbis_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp)
+{
+  GstRtpVorbisDepay *rtpvorbisdepay;
+  GstBuffer *outbuf;
+  GstFlowReturn ret;
+  gint payload_len;
+  GstBuffer *payload_buffer = NULL;
+  guint8 *payload;
+  GstMapInfo map;
+  guint32 header, ident;
+  guint8 F, VDT, packets;
+  guint length;
+
+  rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (depayload);
+
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  GST_DEBUG_OBJECT (depayload, "got RTP packet of size %d", payload_len);
+
+  /* we need at least 4 bytes for the packet header */
+  if (G_UNLIKELY (payload_len < 4))
+    goto packet_short;
+
+  payload = gst_rtp_buffer_get_payload (rtp);
+  header = GST_READ_UINT32_BE (payload);
+  /*
+   *  0                   1                   2                   3
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                     Ident                     | F |VDT|# pkts.|
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   *
+   * F: Fragment type (0=none, 1=start, 2=cont, 3=end)
+   * VDT: Vorbis data type (0=vorbis, 1=config, 2=comment, 3=reserved)
+   * pkts: number of packets.
+   */
+  VDT = (header & 0x30) >> 4;
+  if (G_UNLIKELY (VDT == 3))
+    goto ignore_reserved;
+
+  GST_DEBUG_OBJECT (depayload, "header: 0x%08x", header);
+  ident = (header >> 8) & 0xffffff;
+  F = (header & 0xc0) >> 6;
+  packets = (header & 0xf);
+
+  if (VDT == 0) {
+    gboolean do_switch = FALSE;
+
+    /* we have a raw payload, find the codebook for the ident */
+    if (!rtpvorbisdepay->config) {
+      /* we don't have an active codebook, find the codebook and
+       * activate it */
+      GST_DEBUG_OBJECT (rtpvorbisdepay, "No active codebook, switching");
+      do_switch = TRUE;
+    } else if (rtpvorbisdepay->config->ident != ident) {
+      /* codebook changed */
+      GST_DEBUG_OBJECT (rtpvorbisdepay, "codebook changed, switching");
+      do_switch = TRUE;
+    }
+    if (do_switch) {
+      if (!gst_rtp_vorbis_depay_switch_codebook (rtpvorbisdepay, ident))
+        goto switch_failed;
+    }
+  }
+
+  GST_DEBUG_OBJECT (depayload, "ident: %u, F: %d, VDT: %d, packets: %d", ident,
+      F, VDT, packets);
+
+  /* fragmented packets, assemble */
+  if (F != 0) {
+    GstBuffer *vdata;
+
+    if (F == 1) {
+      /* if we start a packet, clear adapter and start assembling. */
+      gst_adapter_clear (rtpvorbisdepay->adapter);
+      GST_DEBUG_OBJECT (depayload, "start assemble");
+      rtpvorbisdepay->assembling = TRUE;
+    }
+
+    if (!rtpvorbisdepay->assembling)
+      goto no_output;
+
+    /* skip header and length. */
+    vdata = gst_rtp_buffer_get_payload_subbuffer (rtp, 6, -1);
+
+    GST_DEBUG_OBJECT (depayload, "assemble vorbis packet");
+    gst_adapter_push (rtpvorbisdepay->adapter, vdata);
+
+    /* packet is not complete, we are done */
+    if (F != 3)
+      goto no_output;
+
+    /* construct assembled buffer */
+    length = gst_adapter_available (rtpvorbisdepay->adapter);
+    payload_buffer = gst_adapter_take_buffer (rtpvorbisdepay->adapter, length);
+  } else {
+    payload_buffer = gst_rtp_buffer_get_payload_subbuffer (rtp, 4, -1);
+    length = 0;
+  }
+
+  GST_DEBUG_OBJECT (depayload, "assemble done");
+
+  gst_buffer_map (payload_buffer, &map, GST_MAP_READ);
+  payload = map.data;
+  payload_len = map.size;
+
+  /* we not assembling anymore now */
+  rtpvorbisdepay->assembling = FALSE;
+  gst_adapter_clear (rtpvorbisdepay->adapter);
+
+  /* payload now points to a length with that many vorbis data bytes.
+   * Iterate over the packets and send them out.
+   *
+   *  0                   1                   2                   3
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |             length            |          vorbis data         ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..                        vorbis data                           |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |            length             |   next vorbis packet data    ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..                        vorbis data                           |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*
+   */
+  while (payload_len > 2) {
+    /* If length is not 0, we have a reassembled packet for which we
+     * calculated the length already and don't have to skip over the
+     * length field anymore
+     */
+    if (length == 0) {
+      length = GST_READ_UINT16_BE (payload);
+      payload += 2;
+      payload_len -= 2;
+    }
+
+    GST_DEBUG_OBJECT (depayload, "read length %u, avail: %d", length,
+        payload_len);
+
+    /* skip packet if something odd happens */
+    if (G_UNLIKELY (length > payload_len))
+      goto length_short;
+
+    /* handle in-band configuration */
+    if (G_UNLIKELY (VDT == 1)) {
+      GST_DEBUG_OBJECT (rtpvorbisdepay, "in-band configuration");
+      if (!gst_rtp_vorbis_depay_parse_inband_configuration (rtpvorbisdepay,
+              ident, payload, payload_len, length))
+        goto invalid_configuration;
+      goto no_output;
+    }
+
+    /* create buffer for packet */
+    outbuf =
+        gst_buffer_copy_region (payload_buffer, GST_BUFFER_COPY_ALL,
+        payload - map.data, length);
+
+    payload += length;
+    payload_len -= length;
+    /* make sure to read next length */
+    length = 0;
+
+    ret = gst_rtp_base_depayload_push (depayload, outbuf);
+    if (ret != GST_FLOW_OK)
+      break;
+  }
+
+  gst_buffer_unmap (payload_buffer, &map);
+  gst_buffer_unref (payload_buffer);
+
+  return NULL;
+
+no_output:
+  {
+    if (payload_buffer) {
+      gst_buffer_unmap (payload_buffer, &map);
+      gst_buffer_unref (payload_buffer);
+    }
+    return NULL;
+  }
+  /* ERORRS */
+switch_failed:
+  {
+    GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
+        (NULL), ("Could not switch codebooks"));
+    return NULL;
+  }
+packet_short:
+  {
+    GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
+        (NULL), ("Packet was too short (%d < 4)", payload_len));
+    return NULL;
+  }
+ignore_reserved:
+  {
+    GST_WARNING_OBJECT (rtpvorbisdepay, "reserved VDT ignored");
+    return NULL;
+  }
+length_short:
+  {
+    GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
+        (NULL), ("Packet contains invalid data"));
+    if (payload_buffer) {
+      gst_buffer_unmap (payload_buffer, &map);
+      gst_buffer_unref (payload_buffer);
+    }
+    return NULL;
+  }
+invalid_configuration:
+  {
+    /* fatal, as we otherwise risk carrying on without output */
+    GST_ELEMENT_ERROR (rtpvorbisdepay, STREAM, DECODE,
+        (NULL), ("Packet contains invalid configuration"));
+    if (payload_buffer) {
+      gst_buffer_unmap (payload_buffer, &map);
+      gst_buffer_unref (payload_buffer);
+    }
+    return NULL;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_vorbis_depay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpVorbisDepay *rtpvorbisdepay;
+  GstStateChangeReturn ret;
+
+  rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      free_indents (rtpvorbisdepay);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_vorbis_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpvorbisdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_VORBIS_DEPAY);
+}
diff --git a/gst/rtp/gstrtpvorbisdepay.h b/gst/rtp/gstrtpvorbisdepay.h
new file mode 100644
index 0000000..a343d04
--- /dev/null
+++ b/gst/rtp/gstrtpvorbisdepay.h
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_VORBIS_DEPAY_H__
+#define __GST_RTP_VORBIS_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_VORBIS_DEPAY \
+  (gst_rtp_vorbis_depay_get_type())
+#define GST_RTP_VORBIS_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_VORBIS_DEPAY,GstRtpVorbisDepay))
+#define GST_RTP_VORBIS_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_VORBIS_DEPAY,GstRtpVorbisDepayClass))
+#define GST_IS_RTP_VORBIS_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_VORBIS_DEPAY))
+#define GST_IS_RTP_VORBIS_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_VORBIS_DEPAY))
+
+typedef struct _GstRtpVorbisDepay GstRtpVorbisDepay;
+typedef struct _GstRtpVorbisDepayClass GstRtpVorbisDepayClass;
+
+typedef struct _GstRtpVorbisConfig {
+  guint32  ident;
+  GList   *headers;
+} GstRtpVorbisConfig;
+
+struct _GstRtpVorbisDepay
+{
+  GstRTPBaseDepayload parent;
+
+  GList              *configs;
+  GstRtpVorbisConfig *config;
+
+  GstAdapter         *adapter;
+  gboolean            assembling;
+};
+
+struct _GstRtpVorbisDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_vorbis_depay_get_type (void);
+
+gboolean gst_rtp_vorbis_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_VORBIS_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpvorbispay.c b/gst/rtp/gstrtpvorbispay.c
new file mode 100644
index 0000000..b6bb507
--- /dev/null
+++ b/gst/rtp/gstrtpvorbispay.c
@@ -0,0 +1,999 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
+
+#include "fnv1hash.h"
+#include "gstrtpvorbispay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpvorbispay_debug);
+#define GST_CAT_DEFAULT (rtpvorbispay_debug)
+
+/* references:
+ * http://www.rfc-editor.org/rfc/rfc5215.txt
+ */
+
+static GstStaticPadTemplate gst_rtp_vorbis_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"VORBIS\""
+        /* All required parameters
+         *
+         * "encoding-params = (string) <num channels>"
+         * "configuration = (string) ANY"
+         */
+    )
+    );
+
+static GstStaticPadTemplate gst_rtp_vorbis_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-vorbis")
+    );
+
+#define DEFAULT_CONFIG_INTERVAL 0
+
+enum
+{
+  PROP_0,
+  PROP_CONFIG_INTERVAL
+};
+
+#define gst_rtp_vorbis_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpVorbisPay, gst_rtp_vorbis_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static gboolean gst_rtp_vorbis_pay_setcaps (GstRTPBasePayload * basepayload,
+    GstCaps * caps);
+static GstStateChangeReturn gst_rtp_vorbis_pay_change_state (GstElement *
+    element, GstStateChange transition);
+static GstFlowReturn gst_rtp_vorbis_pay_handle_buffer (GstRTPBasePayload * pad,
+    GstBuffer * buffer);
+static gboolean gst_rtp_vorbis_pay_sink_event (GstRTPBasePayload * payload,
+    GstEvent * event);
+
+static gboolean gst_rtp_vorbis_pay_parse_id (GstRTPBasePayload * basepayload,
+    guint8 * data, guint size);
+static gboolean gst_rtp_vorbis_pay_finish_headers (GstRTPBasePayload *
+    basepayload);
+
+static void gst_rtp_vorbis_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_vorbis_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void
+gst_rtp_vorbis_pay_class_init (GstRtpVorbisPayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gstelement_class->change_state = gst_rtp_vorbis_pay_change_state;
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_vorbis_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_vorbis_pay_handle_buffer;
+  gstrtpbasepayload_class->sink_event = gst_rtp_vorbis_pay_sink_event;
+
+  gobject_class->set_property = gst_rtp_vorbis_pay_set_property;
+  gobject_class->get_property = gst_rtp_vorbis_pay_get_property;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_vorbis_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_vorbis_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Vorbis payloader",
+      "Codec/Payloader/Network/RTP",
+      "Payload-encode Vorbis audio into RTP packets (RFC 5215)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpvorbispay_debug, "rtpvorbispay", 0,
+      "Vorbis RTP Payloader");
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CONFIG_INTERVAL,
+      g_param_spec_uint ("config-interval", "Config Send Interval",
+          "Send Config Insertion Interval in seconds (configuration headers "
+          "will be multiplexed in the data stream when detected.) (0 = disabled)",
+          0, 3600, DEFAULT_CONFIG_INTERVAL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+}
+
+static void
+gst_rtp_vorbis_pay_init (GstRtpVorbisPay * rtpvorbispay)
+{
+  rtpvorbispay->last_config = GST_CLOCK_TIME_NONE;
+}
+
+static void
+gst_rtp_vorbis_pay_clear_packet (GstRtpVorbisPay * rtpvorbispay)
+{
+  if (rtpvorbispay->packet)
+    gst_buffer_unref (rtpvorbispay->packet);
+  rtpvorbispay->packet = NULL;
+  g_list_free_full (rtpvorbispay->packet_buffers,
+      (GDestroyNotify) gst_buffer_unref);
+  rtpvorbispay->packet_buffers = NULL;
+}
+
+static void
+gst_rtp_vorbis_pay_cleanup (GstRtpVorbisPay * rtpvorbispay)
+{
+  gst_rtp_vorbis_pay_clear_packet (rtpvorbispay);
+  g_list_free_full (rtpvorbispay->headers, (GDestroyNotify) gst_buffer_unref);
+  rtpvorbispay->headers = NULL;
+  g_free (rtpvorbispay->config_data);
+  rtpvorbispay->config_data = NULL;
+  rtpvorbispay->last_config = GST_CLOCK_TIME_NONE;
+}
+
+static gboolean
+gst_rtp_vorbis_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+  GstRtpVorbisPay *rtpvorbispay;
+  GstStructure *s;
+  const GValue *array;
+  gint asize, i;
+  GstBuffer *buf;
+  GstMapInfo map;
+
+  rtpvorbispay = GST_RTP_VORBIS_PAY (basepayload);
+
+  s = gst_caps_get_structure (caps, 0);
+
+  rtpvorbispay->need_headers = TRUE;
+
+  if ((array = gst_structure_get_value (s, "streamheader")) == NULL)
+    goto done;
+
+  if (G_VALUE_TYPE (array) != GST_TYPE_ARRAY)
+    goto done;
+
+  if ((asize = gst_value_array_get_size (array)) < 3)
+    goto done;
+
+  for (i = 0; i < asize; i++) {
+    const GValue *value;
+
+    value = gst_value_array_get_value (array, i);
+    if ((buf = gst_value_get_buffer (value)) == NULL)
+      goto null_buffer;
+
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    if (map.size < 1)
+      goto invalid_streamheader;
+
+    /* no data packets allowed */
+    if ((map.data[0] & 1) == 0)
+      goto invalid_streamheader;
+
+    /* we need packets with id 1, 3, 5 */
+    if (map.data[0] != (i * 2) + 1)
+      goto invalid_streamheader;
+
+    if (i == 0) {
+      /* identification, we need to parse this in order to get the clock rate. */
+      if (G_UNLIKELY (!gst_rtp_vorbis_pay_parse_id (basepayload, map.data,
+                  map.size)))
+        goto parse_id_failed;
+    }
+    GST_DEBUG_OBJECT (rtpvorbispay, "collecting header %d", i);
+    rtpvorbispay->headers =
+        g_list_append (rtpvorbispay->headers, gst_buffer_ref (buf));
+    gst_buffer_unmap (buf, &map);
+  }
+  if (!gst_rtp_vorbis_pay_finish_headers (basepayload))
+    goto finish_failed;
+
+done:
+  return TRUE;
+
+  /* ERRORS */
+null_buffer:
+  {
+    GST_WARNING_OBJECT (rtpvorbispay, "streamheader with null buffer received");
+    return FALSE;
+  }
+invalid_streamheader:
+  {
+    GST_WARNING_OBJECT (rtpvorbispay, "unable to parse initial header");
+    gst_buffer_unmap (buf, &map);
+    return FALSE;
+  }
+parse_id_failed:
+  {
+    GST_WARNING_OBJECT (rtpvorbispay, "unable to parse initial header");
+    gst_buffer_unmap (buf, &map);
+    return FALSE;
+  }
+finish_failed:
+  {
+    GST_WARNING_OBJECT (rtpvorbispay, "unable to finish headers");
+    return FALSE;
+  }
+}
+
+static void
+gst_rtp_vorbis_pay_reset_packet (GstRtpVorbisPay * rtpvorbispay, guint8 VDT)
+{
+  guint payload_len;
+  GstRTPBuffer rtp = { NULL };
+
+  GST_LOG_OBJECT (rtpvorbispay, "reset packet");
+
+  rtpvorbispay->payload_pos = 4;
+  gst_rtp_buffer_map (rtpvorbispay->packet, GST_MAP_READ, &rtp);
+  payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+  gst_rtp_buffer_unmap (&rtp);
+  rtpvorbispay->payload_left = payload_len - 4;
+  rtpvorbispay->payload_duration = 0;
+  rtpvorbispay->payload_F = 0;
+  rtpvorbispay->payload_VDT = VDT;
+  rtpvorbispay->payload_pkts = 0;
+}
+
+static void
+gst_rtp_vorbis_pay_init_packet (GstRtpVorbisPay * rtpvorbispay, guint8 VDT,
+    GstClockTime timestamp)
+{
+  GST_LOG_OBJECT (rtpvorbispay, "starting new packet, VDT: %d", VDT);
+
+  gst_rtp_vorbis_pay_clear_packet (rtpvorbispay);
+
+  /* new packet allocate max packet size */
+  rtpvorbispay->packet =
+      gst_rtp_buffer_new_allocate_len (GST_RTP_BASE_PAYLOAD_MTU
+      (rtpvorbispay), 0, 0);
+  gst_rtp_vorbis_pay_reset_packet (rtpvorbispay, VDT);
+
+  GST_BUFFER_PTS (rtpvorbispay->packet) = timestamp;
+}
+
+static GstFlowReturn
+gst_rtp_vorbis_pay_flush_packet (GstRtpVorbisPay * rtpvorbispay)
+{
+  GstFlowReturn ret;
+  guint8 *payload;
+  guint hlen;
+  GstRTPBuffer rtp = { NULL };
+  GList *l;
+
+  /* check for empty packet */
+  if (!rtpvorbispay->packet || rtpvorbispay->payload_pos <= 4)
+    return GST_FLOW_OK;
+
+  GST_LOG_OBJECT (rtpvorbispay, "flushing packet");
+
+  gst_rtp_buffer_map (rtpvorbispay->packet, GST_MAP_WRITE, &rtp);
+
+  /* fix header */
+  payload = gst_rtp_buffer_get_payload (&rtp);
+  /*
+   *  0                   1                   2                   3
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                     Ident                     | F |VDT|# pkts.|
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   *
+   * F: Fragment type (0=none, 1=start, 2=cont, 3=end)
+   * VDT: Vorbis data type (0=vorbis, 1=config, 2=comment, 3=reserved)
+   * pkts: number of packets.
+   */
+  payload[0] = (rtpvorbispay->payload_ident >> 16) & 0xff;
+  payload[1] = (rtpvorbispay->payload_ident >> 8) & 0xff;
+  payload[2] = (rtpvorbispay->payload_ident) & 0xff;
+  payload[3] = (rtpvorbispay->payload_F & 0x3) << 6 |
+      (rtpvorbispay->payload_VDT & 0x3) << 4 |
+      (rtpvorbispay->payload_pkts & 0xf);
+
+  gst_rtp_buffer_unmap (&rtp);
+
+  /* shrink the buffer size to the last written byte */
+  hlen = gst_rtp_buffer_calc_header_len (0);
+  gst_buffer_resize (rtpvorbispay->packet, 0, hlen + rtpvorbispay->payload_pos);
+
+  GST_BUFFER_DURATION (rtpvorbispay->packet) = rtpvorbispay->payload_duration;
+
+  for (l = g_list_last (rtpvorbispay->packet_buffers); l; l = l->prev) {
+    GstBuffer *buf = GST_BUFFER_CAST (l->data);
+    gst_rtp_copy_audio_meta (rtpvorbispay, rtpvorbispay->packet, buf);
+    gst_buffer_unref (buf);
+  }
+  g_list_free (rtpvorbispay->packet_buffers);
+  rtpvorbispay->packet_buffers = NULL;
+
+  /* push, this gives away our ref to the packet, so clear it. */
+  ret =
+      gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpvorbispay),
+      rtpvorbispay->packet);
+  rtpvorbispay->packet = NULL;
+
+  return ret;
+}
+
+static gboolean
+gst_rtp_vorbis_pay_finish_headers (GstRTPBasePayload * basepayload)
+{
+  GstRtpVorbisPay *rtpvorbispay = GST_RTP_VORBIS_PAY (basepayload);
+  GList *walk;
+  guint length, size, n_headers, configlen, extralen;
+  gchar *cstr, *configuration;
+  guint8 *data, *config;
+  guint32 ident;
+  gboolean res;
+
+  GST_DEBUG_OBJECT (rtpvorbispay, "finish headers");
+
+  if (!rtpvorbispay->headers)
+    goto no_headers;
+
+  /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                     Number of packed headers                  |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Packed header                        |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Packed header                        |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          ....                                 |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   *
+   * We only construct a config containing 1 packed header like this:
+   *
+   *  0                   1                   2                   3
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                   Ident                       | length       ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..              | n. of headers |    length1    |    length2   ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..              |             Identification Header            ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * .................................................................
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..              |         Comment Header                       ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * .................................................................
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..                        Comment Header                        |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Setup Header                        ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * .................................................................
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..                         Setup Header                         |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   */
+
+  /* we need 4 bytes for the number of headers (which is always 1), 3 bytes for
+   * the ident, 2 bytes for length, 1 byte for n. of headers. */
+  size = 4 + 3 + 2 + 1;
+
+  /* count the size of the headers first and update the hash */
+  length = 0;
+  n_headers = 0;
+  ident = fnv1_hash_32_new ();
+  extralen = 1;
+  for (walk = rtpvorbispay->headers; walk; walk = g_list_next (walk)) {
+    GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+    GstMapInfo map;
+    guint bsize;
+
+    bsize = gst_buffer_get_size (buf);
+    length += bsize;
+    n_headers++;
+
+    /* count number of bytes needed for length fields, we don't need this for
+     * the last header. */
+    if (g_list_next (walk)) {
+      do {
+        size++;
+        extralen++;
+        bsize >>= 7;
+      } while (bsize);
+    }
+    /* update hash */
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    ident = fnv1_hash_32_update (ident, map.data, map.size);
+    gst_buffer_unmap (buf, &map);
+  }
+
+  /* packet length is header size + packet length */
+  configlen = size + length;
+  config = data = g_malloc (configlen);
+
+  /* number of packed headers, we only pack 1 header */
+  data[0] = 0;
+  data[1] = 0;
+  data[2] = 0;
+  data[3] = 1;
+
+  ident = fnv1_hash_32_to_24 (ident);
+  rtpvorbispay->payload_ident = ident;
+  GST_DEBUG_OBJECT (rtpvorbispay, "ident 0x%08x", ident);
+
+  /* take lower 3 bytes */
+  data[4] = (ident >> 16) & 0xff;
+  data[5] = (ident >> 8) & 0xff;
+  data[6] = ident & 0xff;
+
+  /* store length of all vorbis headers */
+  data[7] = ((length) >> 8) & 0xff;
+  data[8] = (length) & 0xff;
+
+  /* store number of headers minus one. */
+  data[9] = n_headers - 1;
+  data += 10;
+
+  /* store length for each header */
+  for (walk = rtpvorbispay->headers; walk; walk = g_list_next (walk)) {
+    GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+    guint bsize, size, temp;
+    guint flag;
+
+    /* only need to store the length when it's not the last header */
+    if (!g_list_next (walk))
+      break;
+
+    bsize = gst_buffer_get_size (buf);
+
+    /* calc size */
+    size = 0;
+    do {
+      size++;
+      bsize >>= 7;
+    } while (bsize);
+    temp = size;
+
+    bsize = gst_buffer_get_size (buf);
+    /* write the size backwards */
+    flag = 0;
+    while (size) {
+      size--;
+      data[size] = (bsize & 0x7f) | flag;
+      bsize >>= 7;
+      flag = 0x80;              /* Flag bit on all bytes of the length except the last */
+    }
+    data += temp;
+  }
+
+  /* copy header data */
+  for (walk = rtpvorbispay->headers; walk; walk = g_list_next (walk)) {
+    GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+
+    gst_buffer_extract (buf, 0, data, gst_buffer_get_size (buf));
+    data += gst_buffer_get_size (buf);
+  }
+  rtpvorbispay->need_headers = FALSE;
+
+  /* serialize to base64 */
+  configuration = g_base64_encode (config, configlen);
+
+  /* store for later re-sending */
+  g_free (rtpvorbispay->config_data);
+  rtpvorbispay->config_size = configlen - 4 - 3 - 2;
+  rtpvorbispay->config_data = g_malloc (rtpvorbispay->config_size);
+  rtpvorbispay->config_extra_len = extralen;
+  memcpy (rtpvorbispay->config_data, config + 4 + 3 + 2,
+      rtpvorbispay->config_size);
+
+  g_free (config);
+
+  /* configure payloader settings */
+  cstr = g_strdup_printf ("%d", rtpvorbispay->channels);
+  gst_rtp_base_payload_set_options (basepayload, "audio", TRUE, "VORBIS",
+      rtpvorbispay->rate);
+  res =
+      gst_rtp_base_payload_set_outcaps (basepayload, "encoding-params",
+      G_TYPE_STRING, cstr, "configuration", G_TYPE_STRING, configuration, NULL);
+  g_free (cstr);
+  g_free (configuration);
+
+  return res;
+
+  /* ERRORS */
+no_headers:
+  {
+    GST_DEBUG_OBJECT (rtpvorbispay, "finish headers");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_rtp_vorbis_pay_parse_id (GstRTPBasePayload * basepayload, guint8 * data,
+    guint size)
+{
+  GstRtpVorbisPay *rtpvorbispay = GST_RTP_VORBIS_PAY (basepayload);
+  guint8 channels;
+  gint32 rate, version;
+
+  if (G_UNLIKELY (size < 16))
+    goto too_short;
+
+  if (G_UNLIKELY (memcmp (data, "\001vorbis", 7)))
+    goto invalid_start;
+  data += 7;
+
+  if (G_UNLIKELY ((version = GST_READ_UINT32_LE (data)) != 0))
+    goto invalid_version;
+  data += 4;
+
+  if (G_UNLIKELY ((channels = *data++) < 1))
+    goto invalid_channels;
+
+  if (G_UNLIKELY ((rate = GST_READ_UINT32_LE (data)) < 1))
+    goto invalid_rate;
+
+  /* all fine, store the values */
+  rtpvorbispay->channels = channels;
+  rtpvorbispay->rate = rate;
+
+  return TRUE;
+
+  /* ERRORS */
+too_short:
+  {
+    GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+        ("Identification packet is too short, need at least 16, got %d", size),
+        (NULL));
+    return FALSE;
+  }
+invalid_start:
+  {
+    GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+        ("Invalid header start in identification packet"), (NULL));
+    return FALSE;
+  }
+invalid_version:
+  {
+    GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+        ("Invalid version, expected 0, got %d", version), (NULL));
+    return FALSE;
+  }
+invalid_rate:
+  {
+    GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+        ("Invalid rate %d", rate), (NULL));
+    return FALSE;
+  }
+invalid_channels:
+  {
+    GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+        ("Invalid channels %d", channels), (NULL));
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_rtp_vorbis_pay_payload_buffer (GstRtpVorbisPay * rtpvorbispay, guint8 VDT,
+    GstBuffer * buffer, guint8 * data, guint size, GstClockTime timestamp,
+    GstClockTime duration, guint not_in_length)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint newsize;
+  guint packet_len;
+  GstClockTime newduration;
+  gboolean flush;
+  guint plen;
+  guint8 *ppos, *payload;
+  gboolean fragmented;
+  GstRTPBuffer rtp = { NULL };
+
+  /* size increases with packet length and 2 bytes size eader. */
+  newduration = rtpvorbispay->payload_duration;
+  if (duration != GST_CLOCK_TIME_NONE)
+    newduration += duration;
+
+  newsize = rtpvorbispay->payload_pos + 2 + size;
+  packet_len = gst_rtp_buffer_calc_packet_len (newsize, 0, 0);
+
+  /* check buffer filled against length and max latency */
+  flush = gst_rtp_base_payload_is_filled (GST_RTP_BASE_PAYLOAD (rtpvorbispay),
+      packet_len, newduration);
+  /* we can store up to 15 vorbis packets in one RTP packet. */
+  flush |= (rtpvorbispay->payload_pkts == 15);
+  /* flush if we have a new VDT */
+  if (rtpvorbispay->packet)
+    flush |= (rtpvorbispay->payload_VDT != VDT);
+  if (flush)
+    ret = gst_rtp_vorbis_pay_flush_packet (rtpvorbispay);
+
+  if (ret != GST_FLOW_OK)
+    goto done;
+
+  /* create new packet if we must */
+  if (!rtpvorbispay->packet) {
+    gst_rtp_vorbis_pay_init_packet (rtpvorbispay, VDT, timestamp);
+  }
+
+  gst_rtp_buffer_map (rtpvorbispay->packet, GST_MAP_WRITE, &rtp);
+  payload = gst_rtp_buffer_get_payload (&rtp);
+  ppos = payload + rtpvorbispay->payload_pos;
+  fragmented = FALSE;
+
+  /* put buffer in packet, it either fits completely or needs to be fragmented
+   * over multiple RTP packets. */
+  do {
+    plen = MIN (rtpvorbispay->payload_left - 2, size);
+
+    GST_LOG_OBJECT (rtpvorbispay, "append %u bytes", plen);
+
+    /* data is copied in the payload with a 2 byte length header */
+    ppos[0] = ((plen - not_in_length) >> 8) & 0xff;
+    ppos[1] = ((plen - not_in_length) & 0xff);
+    if (plen)
+      memcpy (&ppos[2], data, plen);
+
+    if (buffer) {
+      if (!rtpvorbispay->packet_buffers
+          || rtpvorbispay->packet_buffers->data != (gpointer) buffer)
+        rtpvorbispay->packet_buffers =
+            g_list_prepend (rtpvorbispay->packet_buffers,
+            gst_buffer_ref (buffer));
+    } else {
+      GList *l;
+
+      for (l = rtpvorbispay->headers; l; l = l->next)
+        rtpvorbispay->packet_buffers =
+            g_list_prepend (rtpvorbispay->packet_buffers,
+            gst_buffer_ref (l->data));
+    }
+
+    /* only first (only) configuration cuts length field */
+    /* NOTE: spec (if any) is not clear on this ... */
+    not_in_length = 0;
+
+    size -= plen;
+    data += plen;
+
+    rtpvorbispay->payload_pos += plen + 2;
+    rtpvorbispay->payload_left -= plen + 2;
+
+    if (fragmented) {
+      if (size == 0)
+        /* last fragment, set F to 0x3. */
+        rtpvorbispay->payload_F = 0x3;
+      else
+        /* fragment continues, set F to 0x2. */
+        rtpvorbispay->payload_F = 0x2;
+    } else {
+      if (size > 0) {
+        /* fragmented packet starts, set F to 0x1, mark ourselves as
+         * fragmented. */
+        rtpvorbispay->payload_F = 0x1;
+        fragmented = TRUE;
+      }
+    }
+    if (fragmented) {
+      gst_rtp_buffer_unmap (&rtp);
+      /* fragmented packets are always flushed and have ptks of 0 */
+      rtpvorbispay->payload_pkts = 0;
+      ret = gst_rtp_vorbis_pay_flush_packet (rtpvorbispay);
+
+      if (size > 0) {
+        /* start new packet and get pointers. VDT stays the same. */
+        gst_rtp_vorbis_pay_init_packet (rtpvorbispay,
+            rtpvorbispay->payload_VDT, timestamp);
+        gst_rtp_buffer_map (rtpvorbispay->packet, GST_MAP_WRITE, &rtp);
+        payload = gst_rtp_buffer_get_payload (&rtp);
+        ppos = payload + rtpvorbispay->payload_pos;
+      }
+    } else {
+      /* unfragmented packet, update stats for next packet, size == 0 and we
+       * exit the while loop */
+      rtpvorbispay->payload_pkts++;
+      if (duration != GST_CLOCK_TIME_NONE)
+        rtpvorbispay->payload_duration += duration;
+    }
+  } while (size && ret == GST_FLOW_OK);
+
+  if (rtp.buffer)
+    gst_rtp_buffer_unmap (&rtp);
+
+done:
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_rtp_vorbis_pay_handle_buffer (GstRTPBasePayload * basepayload,
+    GstBuffer * buffer)
+{
+  GstRtpVorbisPay *rtpvorbispay;
+  GstFlowReturn ret;
+  GstMapInfo map;
+  gsize size;
+  guint8 *data;
+  GstClockTime duration, timestamp;
+  guint8 VDT;
+
+  rtpvorbispay = GST_RTP_VORBIS_PAY (basepayload);
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  data = map.data;
+  size = map.size;
+  duration = GST_BUFFER_DURATION (buffer);
+  timestamp = GST_BUFFER_PTS (buffer);
+
+  GST_LOG_OBJECT (rtpvorbispay, "size %" G_GSIZE_FORMAT
+      ", duration %" GST_TIME_FORMAT, size, GST_TIME_ARGS (duration));
+
+  if (G_UNLIKELY (size < 1))
+    goto wrong_size;
+
+  /* find packet type */
+  if (data[0] & 1) {
+    /* header */
+    if (data[0] == 1) {
+      /* identification, we need to parse this in order to get the clock rate. */
+      if (G_UNLIKELY (!gst_rtp_vorbis_pay_parse_id (basepayload, data, size)))
+        goto parse_id_failed;
+      VDT = 1;
+    } else if (data[0] == 3) {
+      /* comment */
+      VDT = 2;
+    } else if (data[0] == 5) {
+      /* setup */
+      VDT = 1;
+    } else
+      goto unknown_header;
+  } else
+    /* data */
+    VDT = 0;
+
+  /* we need to collect the headers and construct a config string from them */
+  if (VDT != 0) {
+    rtpvorbispay->need_headers = TRUE;
+    if (!rtpvorbispay->need_headers && VDT == 1) {
+      GST_INFO_OBJECT (rtpvorbispay, "getting new headers, replace existing");
+      g_list_free_full (rtpvorbispay->headers,
+          (GDestroyNotify) gst_buffer_unref);
+      rtpvorbispay->headers = NULL;
+    }
+    GST_DEBUG_OBJECT (rtpvorbispay, "collecting header");
+    /* append header to the list of headers, or replace
+     * if the same type of header was already in there.
+     *
+     * This prevents storing an infinite amount of e.g. comment headers, there
+     * must only be one */
+    gst_buffer_unmap (buffer, &map);
+
+    if (rtpvorbispay->headers) {
+      gboolean found = FALSE;
+      GList *l;
+      guint8 new_header_type;
+
+      gst_buffer_extract (buffer, 0, &new_header_type, 1);
+
+      for (l = rtpvorbispay->headers; l; l = l->next) {
+        GstBuffer *header = l->data;
+        guint8 header_type;
+
+        if (gst_buffer_extract (header, 0, &header_type, 1)
+            && header_type == new_header_type) {
+          found = TRUE;
+          gst_buffer_unref (header);
+          l->data = buffer;
+          break;
+        }
+      }
+      if (!found)
+        rtpvorbispay->headers = g_list_append (rtpvorbispay->headers, buffer);
+    } else {
+      rtpvorbispay->headers = g_list_append (rtpvorbispay->headers, buffer);
+    }
+
+    ret = GST_FLOW_OK;
+    goto done;
+  } else if (rtpvorbispay->headers && rtpvorbispay->need_headers) {
+    if (!gst_rtp_vorbis_pay_finish_headers (basepayload))
+      goto header_error;
+  }
+
+  /* there is a config request, see if we need to insert it */
+  if (rtpvorbispay->config_interval > 0 && rtpvorbispay->config_data) {
+    gboolean send_config = FALSE;
+
+    if (rtpvorbispay->last_config != -1) {
+      guint64 diff;
+
+      GST_LOG_OBJECT (rtpvorbispay,
+          "now %" GST_TIME_FORMAT ", last config %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (timestamp), GST_TIME_ARGS (rtpvorbispay->last_config));
+
+      /* calculate diff between last config in milliseconds */
+      if (timestamp > rtpvorbispay->last_config) {
+        diff = timestamp - rtpvorbispay->last_config;
+      } else {
+        diff = 0;
+      }
+
+      GST_DEBUG_OBJECT (rtpvorbispay,
+          "interval since last config %" GST_TIME_FORMAT, GST_TIME_ARGS (diff));
+
+      /* bigger than interval, queue config */
+      /* FIXME should convert timestamps to running time */
+      if (GST_TIME_AS_SECONDS (diff) >= rtpvorbispay->config_interval) {
+        GST_DEBUG_OBJECT (rtpvorbispay, "time to send config");
+        send_config = TRUE;
+      }
+    } else {
+      /* no known previous config time, send now */
+      GST_DEBUG_OBJECT (rtpvorbispay, "no previous config time, send now");
+      send_config = TRUE;
+    }
+
+    if (send_config) {
+      /* we need to send config now first */
+      /* different TDT type forces flush */
+      gst_rtp_vorbis_pay_payload_buffer (rtpvorbispay, 1,
+          NULL, rtpvorbispay->config_data, rtpvorbispay->config_size,
+          timestamp, GST_CLOCK_TIME_NONE, rtpvorbispay->config_extra_len);
+
+      if (timestamp != -1) {
+        rtpvorbispay->last_config = timestamp;
+      }
+    }
+  }
+
+  ret =
+      gst_rtp_vorbis_pay_payload_buffer (rtpvorbispay, VDT, buffer, data, size,
+      timestamp, duration, 0);
+
+  gst_buffer_unmap (buffer, &map);
+  gst_buffer_unref (buffer);
+
+done:
+  return ret;
+
+  /* ERRORS */
+wrong_size:
+  {
+    GST_ELEMENT_WARNING (rtpvorbispay, STREAM, DECODE,
+        ("Invalid packet size (1 < %" G_GSIZE_FORMAT ")", size), (NULL));
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+    return GST_FLOW_OK;
+  }
+parse_id_failed:
+  {
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+    return GST_FLOW_ERROR;
+  }
+unknown_header:
+  {
+    GST_ELEMENT_WARNING (rtpvorbispay, STREAM, DECODE,
+        (NULL), ("Ignoring unknown header received"));
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+    return GST_FLOW_OK;
+  }
+header_error:
+  {
+    GST_ELEMENT_WARNING (rtpvorbispay, STREAM, DECODE,
+        (NULL), ("Error initializing header config"));
+    gst_buffer_unmap (buffer, &map);
+    gst_buffer_unref (buffer);
+    return GST_FLOW_OK;
+  }
+}
+
+static gboolean
+gst_rtp_vorbis_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+  GstRtpVorbisPay *rtpvorbispay = GST_RTP_VORBIS_PAY (payload);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      gst_rtp_vorbis_pay_clear_packet (rtpvorbispay);
+      break;
+    default:
+      break;
+  }
+  /* false to let parent handle event as well */
+  return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+}
+
+static GstStateChangeReturn
+gst_rtp_vorbis_pay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpVorbisPay *rtpvorbispay;
+  GstStateChangeReturn ret;
+
+  rtpvorbispay = GST_RTP_VORBIS_PAY (element);
+
+  switch (transition) {
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_vorbis_pay_cleanup (rtpvorbispay);
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+static void
+gst_rtp_vorbis_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpVorbisPay *rtpvorbispay;
+
+  rtpvorbispay = GST_RTP_VORBIS_PAY (object);
+
+  switch (prop_id) {
+    case PROP_CONFIG_INTERVAL:
+      rtpvorbispay->config_interval = g_value_get_uint (value);
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_rtp_vorbis_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpVorbisPay *rtpvorbispay;
+
+  rtpvorbispay = GST_RTP_VORBIS_PAY (object);
+
+  switch (prop_id) {
+    case PROP_CONFIG_INTERVAL:
+      g_value_set_uint (value, rtpvorbispay->config_interval);
+      break;
+    default:
+      break;
+  }
+}
+
+gboolean
+gst_rtp_vorbis_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpvorbispay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_VORBIS_PAY);
+}
diff --git a/gst/rtp/gstrtpvorbispay.h b/gst/rtp/gstrtpvorbispay.h
new file mode 100644
index 0000000..a5d693a
--- /dev/null
+++ b/gst/rtp/gstrtpvorbispay.h
@@ -0,0 +1,85 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_VORBIS_PAY_H__
+#define __GST_RTP_VORBIS_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_VORBIS_PAY \
+  (gst_rtp_vorbis_pay_get_type())
+#define GST_RTP_VORBIS_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_VORBIS_PAY,GstRtpVorbisPay))
+#define GST_RTP_VORBIS_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_VORBIS_PAY,GstRtpVorbisPayClass))
+#define GST_IS_RTP_VORBIS_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_VORBIS_PAY))
+#define GST_IS_RTP_VORBIS_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_VORBIS_PAY))
+
+typedef struct _GstRtpVorbisPay GstRtpVorbisPay;
+typedef struct _GstRtpVorbisPayClass GstRtpVorbisPayClass;
+
+struct _GstRtpVorbisPay
+{
+  GstRTPBasePayload payload;
+
+  /* the headers */
+  gboolean      need_headers;
+  GList        *headers;
+
+  /* queues of buffers along with some stats. */
+  GstBuffer    *packet;
+  GList        *packet_buffers;
+  guint         payload_pos;
+  guint         payload_left;
+  guint32       payload_ident;
+  guint8        payload_F;
+  guint8        payload_VDT;
+  guint         payload_pkts;
+  GstClockTime  payload_timestamp;
+  GstClockTime  payload_duration;
+
+  /* config (re-sending) */
+  guint8       *config_data;
+  guint         config_size;
+  guint         config_extra_len;
+  guint         config_interval;
+  GstClockTime  last_config;
+
+  gint          rate;
+  gint          channels;
+};
+
+struct _GstRtpVorbisPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_vorbis_pay_get_type (void);
+
+gboolean gst_rtp_vorbis_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_VORBIS_PAY_H__ */
diff --git a/gst/rtp/gstrtpvp8depay.c b/gst/rtp/gstrtpvp8depay.c
new file mode 100644
index 0000000..7c0d707
--- /dev/null
+++ b/gst/rtp/gstrtpvp8depay.c
@@ -0,0 +1,292 @@
+/* gstrtpvp8depay.c - Source for GstRtpVP8Depay
+ * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
+ * Copyright (C) 2011 Collabora Ltd.
+ *   Contact: Youness Alaoui <youness.alaoui@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstrtpvp8depay.h"
+#include "gstrtputils.h"
+
+#include <gst/video/video.h>
+
+#include <stdio.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_vp8_depay_debug);
+#define GST_CAT_DEFAULT gst_rtp_vp8_depay_debug
+
+static void gst_rtp_vp8_depay_dispose (GObject * object);
+static GstBuffer *gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+static GstStateChangeReturn gst_rtp_vp8_depay_change_state (GstElement *
+    element, GstStateChange transition);
+static gboolean gst_rtp_vp8_depay_handle_event (GstRTPBaseDepayload * depay,
+    GstEvent * event);
+
+G_DEFINE_TYPE (GstRtpVP8Depay, gst_rtp_vp8_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static GstStaticPadTemplate gst_rtp_vp8_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-vp8"));
+
+static GstStaticPadTemplate gst_rtp_vp8_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "clock-rate = (int) 90000,"
+        "media = (string) \"video\","
+        "encoding-name = (string) { \"VP8\", \"VP8-DRAFT-IETF-01\" }"));
+
+static void
+gst_rtp_vp8_depay_init (GstRtpVP8Depay * self)
+{
+  self->adapter = gst_adapter_new ();
+  self->started = FALSE;
+}
+
+static void
+gst_rtp_vp8_depay_class_init (GstRtpVP8DepayClass * gst_rtp_vp8_depay_class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (gst_rtp_vp8_depay_class);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (gst_rtp_vp8_depay_class);
+  GstRTPBaseDepayloadClass *depay_class =
+      (GstRTPBaseDepayloadClass *) (gst_rtp_vp8_depay_class);
+
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_vp8_depay_sink_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_vp8_depay_src_template);
+
+  gst_element_class_set_static_metadata (element_class, "RTP VP8 depayloader",
+      "Codec/Depayloader/Network/RTP",
+      "Extracts VP8 video from RTP packets)",
+      "Sjoerd Simons <sjoerd@luon.net>");
+
+  object_class->dispose = gst_rtp_vp8_depay_dispose;
+
+  element_class->change_state = gst_rtp_vp8_depay_change_state;
+
+  depay_class->process_rtp_packet = gst_rtp_vp8_depay_process;
+  depay_class->handle_event = gst_rtp_vp8_depay_handle_event;
+
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_vp8_depay_debug, "rtpvp8depay", 0,
+      "VP8 Video RTP Depayloader");
+}
+
+static void
+gst_rtp_vp8_depay_dispose (GObject * object)
+{
+  GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (object);
+
+  if (self->adapter != NULL)
+    g_object_unref (self->adapter);
+  self->adapter = NULL;
+
+  /* release any references held by the object here */
+
+  if (G_OBJECT_CLASS (gst_rtp_vp8_depay_parent_class)->dispose)
+    G_OBJECT_CLASS (gst_rtp_vp8_depay_parent_class)->dispose (object);
+}
+
+static GstBuffer *
+gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp)
+{
+  GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (depay);
+  GstBuffer *payload;
+  guint8 *data;
+  guint hdrsize;
+  guint size;
+
+  if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (rtp->buffer))) {
+    GST_LOG_OBJECT (self, "Discontinuity, flushing adapter");
+    gst_adapter_clear (self->adapter);
+    self->started = FALSE;
+  }
+
+  size = gst_rtp_buffer_get_payload_len (rtp);
+
+  /* At least one header and one vp8 byte */
+  if (G_UNLIKELY (size < 2))
+    goto too_small;
+
+  data = gst_rtp_buffer_get_payload (rtp);
+
+  if (G_UNLIKELY (!self->started)) {
+    /* Check if this is the start of a VP8 frame, otherwise bail */
+    /* S=1 and PartID= 0 */
+    if ((data[0] & 0x17) != 0x10)
+      goto done;
+
+    self->started = TRUE;
+  }
+
+  hdrsize = 1;
+  /* Check X optional header */
+  if ((data[0] & 0x80) != 0) {
+    hdrsize++;
+    /* Check I optional header */
+    if ((data[1] & 0x80) != 0) {
+      if (G_UNLIKELY (size < 3))
+        goto too_small;
+      hdrsize++;
+      /* Check for 16 bits PictureID */
+      if ((data[2] & 0x80) != 0)
+        hdrsize++;
+    }
+    /* Check L optional header */
+    if ((data[1] & 0x40) != 0)
+      hdrsize++;
+    /* Check T or K optional headers */
+    if ((data[1] & 0x20) != 0 || (data[1] & 0x10) != 0)
+      hdrsize++;
+  }
+  GST_DEBUG_OBJECT (depay, "hdrsize %u, size %u", hdrsize, size);
+
+  if (G_UNLIKELY (hdrsize >= size))
+    goto too_small;
+
+  payload = gst_rtp_buffer_get_payload_subbuffer (rtp, hdrsize, -1);
+  gst_adapter_push (self->adapter, payload);
+
+  /* Marker indicates that it was the last rtp packet for this frame */
+  if (gst_rtp_buffer_get_marker (rtp)) {
+    GstBuffer *out;
+    guint8 header[10];
+
+    if (gst_adapter_available (self->adapter) < 10)
+      goto too_small;
+    gst_adapter_copy (self->adapter, &header, 0, 10);
+
+    out = gst_adapter_take_buffer (self->adapter,
+        gst_adapter_available (self->adapter));
+
+    self->started = FALSE;
+
+    /* mark keyframes */
+    out = gst_buffer_make_writable (out);
+    /* Filter away all metas that are not sensible to copy */
+    gst_rtp_drop_non_video_meta (self, out);
+    if ((header[0] & 0x01)) {
+      GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT);
+
+      if (!self->caps_sent) {
+        gst_buffer_unref (out);
+        out = NULL;
+        GST_INFO_OBJECT (self, "Dropping inter-frame before intra-frame");
+        gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depay),
+            gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
+                TRUE, 0));
+      }
+    } else {
+      guint profile, width, height;
+
+      GST_BUFFER_FLAG_UNSET (out, GST_BUFFER_FLAG_DELTA_UNIT);
+
+      profile = (header[0] & 0x0e) >> 1;
+      width = GST_READ_UINT16_LE (header + 6) & 0x3fff;
+      height = GST_READ_UINT16_LE (header + 8) & 0x3fff;
+
+      if (G_UNLIKELY (self->last_width != width ||
+              self->last_height != height || self->last_profile != profile)) {
+        gchar profile_str[3];
+        GstCaps *srccaps;
+
+        snprintf (profile_str, 3, "%u", profile);
+        srccaps = gst_caps_new_simple ("video/x-vp8",
+            "framerate", GST_TYPE_FRACTION, 0, 1,
+            "height", G_TYPE_INT, height,
+            "width", G_TYPE_INT, width,
+            "profile", G_TYPE_STRING, profile_str, NULL);
+
+        gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depay), srccaps);
+        gst_caps_unref (srccaps);
+
+        self->caps_sent = TRUE;
+        self->last_width = width;
+        self->last_height = height;
+        self->last_profile = profile;
+      }
+    }
+
+    return out;
+  }
+
+done:
+  return NULL;
+
+too_small:
+  GST_LOG_OBJECT (self, "Invalid rtp packet (too small), ignoring");
+  gst_adapter_clear (self->adapter);
+  self->started = FALSE;
+
+  goto done;
+}
+
+static GstStateChangeReturn
+gst_rtp_vp8_depay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      self->last_profile = -1;
+      self->last_height = -1;
+      self->last_width = -1;
+      self->caps_sent = FALSE;
+      break;
+    default:
+      break;
+  }
+
+  return
+      GST_ELEMENT_CLASS (gst_rtp_vp8_depay_parent_class)->change_state (element,
+      transition);
+}
+
+static gboolean
+gst_rtp_vp8_depay_handle_event (GstRTPBaseDepayload * depay, GstEvent * event)
+{
+  GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (depay);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      self->last_profile = -1;
+      self->last_height = -1;
+      self->last_width = -1;
+      break;
+    default:
+      break;
+  }
+
+  return
+      GST_RTP_BASE_DEPAYLOAD_CLASS
+      (gst_rtp_vp8_depay_parent_class)->handle_event (depay, event);
+}
+
+gboolean
+gst_rtp_vp8_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpvp8depay",
+      GST_RANK_MARGINAL, GST_TYPE_RTP_VP8_DEPAY);
+}
diff --git a/gst/rtp/gstrtpvp8depay.h b/gst/rtp/gstrtpvp8depay.h
new file mode 100644
index 0000000..258546a
--- /dev/null
+++ b/gst/rtp/gstrtpvp8depay.h
@@ -0,0 +1,69 @@
+/*
+ * gstrtpvp8depay.h - Header for GstRtpVP8Depay
+ * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GST_RTP_VP8_DEPAY_H__
+#define __GST_RTP_VP8_DEPAY_H__
+
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_VP8_DEPAY \
+  (gst_rtp_vp8_depay_get_type())
+#define GST_RTP_VP8_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_RTP_VP8_DEPAY, GstRtpVP8Depay))
+#define GST_RTP_VP8_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_RTP_VP8_DEPAY, \
+    GstRtpVP8DepayClass))
+#define GST_IS_RTP_VP8_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_RTP_VP8_DEPAY))
+#define GST_IS_RTP_VP8_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_RTP_VP8_DEPAY))
+#define GST_RTP_VP8_DEPAY_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_VP8_DEPAY, \
+    GstRtpVP8DepayClass))
+
+typedef struct _GstRtpVP8Depay GstRtpVP8Depay;
+typedef struct _GstRtpVP8DepayClass GstRtpVP8DepayClass;
+
+struct _GstRtpVP8DepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+struct _GstRtpVP8Depay
+{
+  GstRTPBaseDepayload parent;
+  GstAdapter *adapter;
+  gboolean started;
+
+  gboolean caps_sent;
+  gint last_profile;
+  gint last_width;
+  gint last_height;
+};
+
+GType gst_rtp_vp8_depay_get_type (void);
+
+gboolean gst_rtp_vp8_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* #ifndef __GST_RTP_VP8_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpvp8pay.c b/gst/rtp/gstrtpvp8pay.c
new file mode 100644
index 0000000..9649502
--- /dev/null
+++ b/gst/rtp/gstrtpvp8pay.c
@@ -0,0 +1,541 @@
+/*
+ * gstrtpvp8pay.c - Source for GstRtpVP8Pay
+ * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
+ * Copyright (C) 2011 Collabora Ltd.
+ *   Contact: Youness Alaoui <youness.alaoui@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gst/base/gstbitreader.h>
+#include <gst/rtp/gstrtppayloads.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+#include "dboolhuff.h"
+#include "gstrtpvp8pay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_vp8_pay_debug);
+#define GST_CAT_DEFAULT gst_rtp_vp8_pay_debug
+
+#define DEFAULT_PICTURE_ID_MODE VP8_PAY_NO_PICTURE_ID
+
+enum
+{
+  PROP_0,
+  PROP_PICTURE_ID_MODE
+};
+
+#define GST_TYPE_RTP_VP8_PAY_PICTURE_ID_MODE (gst_rtp_vp8_pay_picture_id_mode_get_type())
+static GType
+gst_rtp_vp8_pay_picture_id_mode_get_type (void)
+{
+  static GType mode_type = 0;
+  static const GEnumValue modes[] = {
+    {VP8_PAY_NO_PICTURE_ID, "No Picture ID", "none"},
+    {VP8_PAY_PICTURE_ID_7BITS, "7-bit Picture ID", "7-bit"},
+    {VP8_PAY_PICTURE_ID_15BITS, "15-bit Picture ID", "15-bit"},
+    {0, NULL, NULL},
+  };
+
+  if (!mode_type) {
+    mode_type = g_enum_register_static ("GstVP8RTPPayMode", modes);
+  }
+  return mode_type;
+}
+
+static void gst_rtp_vp8_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_rtp_vp8_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+
+static GstFlowReturn gst_rtp_vp8_pay_handle_buffer (GstRTPBasePayload * payload,
+    GstBuffer * buffer);
+static gboolean gst_rtp_vp8_pay_sink_event (GstRTPBasePayload * payload,
+    GstEvent * event);
+static gboolean gst_rtp_vp8_pay_set_caps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+
+G_DEFINE_TYPE (GstRtpVP8Pay, gst_rtp_vp8_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static GstStaticPadTemplate gst_rtp_vp8_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ","
+        "clock-rate = (int) 90000, encoding-name = (string) { \"VP8\", \"VP8-DRAFT-IETF-01\" }"));
+
+static GstStaticPadTemplate gst_rtp_vp8_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-vp8"));
+
+static void
+gst_rtp_vp8_pay_init (GstRtpVP8Pay * obj)
+{
+  obj->picture_id_mode = DEFAULT_PICTURE_ID_MODE;
+  if (obj->picture_id_mode == VP8_PAY_PICTURE_ID_7BITS)
+    obj->picture_id = g_random_int_range (0, G_MAXUINT8) & 0x7F;
+  else if (obj->picture_id_mode == VP8_PAY_PICTURE_ID_15BITS)
+    obj->picture_id = g_random_int_range (0, G_MAXUINT16) & 0x7FFF;
+}
+
+static void
+gst_rtp_vp8_pay_class_init (GstRtpVP8PayClass * gst_rtp_vp8_pay_class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (gst_rtp_vp8_pay_class);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (gst_rtp_vp8_pay_class);
+  GstRTPBasePayloadClass *pay_class =
+      GST_RTP_BASE_PAYLOAD_CLASS (gst_rtp_vp8_pay_class);
+
+  gobject_class->set_property = gst_rtp_vp8_pay_set_property;
+  gobject_class->get_property = gst_rtp_vp8_pay_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_PICTURE_ID_MODE,
+      g_param_spec_enum ("picture-id-mode", "Picture ID Mode",
+          "The picture ID mode for payloading",
+          GST_TYPE_RTP_VP8_PAY_PICTURE_ID_MODE, DEFAULT_PICTURE_ID_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_vp8_pay_sink_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_vp8_pay_src_template);
+
+  gst_element_class_set_static_metadata (element_class, "RTP VP8 payloader",
+      "Codec/Payloader/Network/RTP",
+      "Puts VP8 video in RTP packets", "Sjoerd Simons <sjoerd@luon.net>");
+
+  pay_class->handle_buffer = gst_rtp_vp8_pay_handle_buffer;
+  pay_class->sink_event = gst_rtp_vp8_pay_sink_event;
+  pay_class->set_caps = gst_rtp_vp8_pay_set_caps;
+
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_vp8_pay_debug, "rtpvp8pay", 0,
+      "VP8 Video RTP Payloader");
+}
+
+static void
+gst_rtp_vp8_pay_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstRtpVP8Pay *rtpvp8pay = GST_RTP_VP8_PAY (object);
+
+  switch (prop_id) {
+    case PROP_PICTURE_ID_MODE:
+      rtpvp8pay->picture_id_mode = g_value_get_enum (value);
+      if (rtpvp8pay->picture_id_mode == VP8_PAY_PICTURE_ID_7BITS)
+        rtpvp8pay->picture_id = g_random_int_range (0, G_MAXUINT8) & 0x7F;
+      else if (rtpvp8pay->picture_id_mode == VP8_PAY_PICTURE_ID_15BITS)
+        rtpvp8pay->picture_id = g_random_int_range (0, G_MAXUINT16) & 0x7FFF;
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_vp8_pay_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstRtpVP8Pay *rtpvp8pay = GST_RTP_VP8_PAY (object);
+
+  switch (prop_id) {
+    case PROP_PICTURE_ID_MODE:
+      g_value_set_enum (value, rtpvp8pay->picture_id_mode);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer,
+    gsize buffer_size)
+{
+  GstMapInfo map = GST_MAP_INFO_INIT;
+  GstBitReader reader;
+  guint8 *data;
+  gsize size;
+  int i;
+  gboolean keyframe;
+  guint32 partition0_size;
+  guint8 version;
+  guint8 tmp8 = 0;
+  guint8 partitions;
+  guint offset;
+  BOOL_DECODER bc;
+  guint8 *pdata;
+
+  if (G_UNLIKELY (buffer_size < 3))
+    goto error;
+
+  if (!gst_buffer_map (buffer, &map, GST_MAP_READ) || !map.data)
+    goto error;
+
+  data = map.data;
+  size = map.size;
+
+  gst_bit_reader_init (&reader, data, size);
+
+  self->is_keyframe = keyframe = ((data[0] & 0x1) == 0);
+  version = (data[0] >> 1) & 0x7;
+
+  if (G_UNLIKELY (version > 3)) {
+    GST_ERROR_OBJECT (self, "Unknown VP8 version %u", version);
+    goto error;
+  }
+
+  /* keyframe, version and show_frame use 5 bits */
+  partition0_size = data[2] << 11 | data[1] << 3 | (data[0] >> 5);
+
+  /* Include the uncompressed data blob in the first partition */
+  offset = keyframe ? 10 : 3;
+  partition0_size += offset;
+
+  if (!gst_bit_reader_skip (&reader, 24))
+    goto error;
+
+  if (keyframe) {
+    /* check start tag: 0x9d 0x01 0x2a */
+    if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 8) || tmp8 != 0x9d)
+      goto error;
+
+    if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 8) || tmp8 != 0x01)
+      goto error;
+
+    if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 8) || tmp8 != 0x2a)
+      goto error;
+
+    /* Skip horizontal size code (16 bits) vertical size code (16 bits) */
+    if (!gst_bit_reader_skip (&reader, 32))
+      goto error;
+  }
+
+  offset = keyframe ? 10 : 3;
+  vp8dx_start_decode (&bc, data + offset, size - offset);
+
+  if (keyframe) {
+    /* color space (1 bit) and clamping type (1 bit) */
+    vp8dx_decode_bool (&bc, 0x80);
+    vp8dx_decode_bool (&bc, 0x80);
+  }
+
+  /* segmentation_enabled */
+  if (vp8dx_decode_bool (&bc, 0x80)) {
+    guint8 update_mb_segmentation_map = vp8dx_decode_bool (&bc, 0x80);
+    guint8 update_segment_feature_data = vp8dx_decode_bool (&bc, 0x80);
+
+    if (update_segment_feature_data) {
+      /* skip segment feature mode */
+      vp8dx_decode_bool (&bc, 0x80);
+
+      /* quantizer update */
+      for (i = 0; i < 4; i++) {
+        /* skip flagged quantizer value (7 bits) and sign (1 bit) */
+        if (vp8dx_decode_bool (&bc, 0x80))
+          vp8_decode_value (&bc, 8);
+      }
+
+      /* loop filter update */
+      for (i = 0; i < 4; i++) {
+        /* skip flagged lf update value (6 bits) and sign (1 bit) */
+        if (vp8dx_decode_bool (&bc, 0x80))
+          vp8_decode_value (&bc, 7);
+      }
+    }
+
+    if (update_mb_segmentation_map) {
+      /* segment prob update */
+      for (i = 0; i < 3; i++) {
+        /* skip flagged segment prob */
+        if (vp8dx_decode_bool (&bc, 0x80))
+          vp8_decode_value (&bc, 8);
+      }
+    }
+  }
+
+  /* skip filter type (1 bit), loop filter level (6 bits) and
+   * sharpness level (3 bits) */
+  vp8_decode_value (&bc, 1);
+  vp8_decode_value (&bc, 6);
+  vp8_decode_value (&bc, 3);
+
+  /* loop_filter_adj_enabled */
+  if (vp8dx_decode_bool (&bc, 0x80)) {
+
+    /* delta update */
+    if (vp8dx_decode_bool (&bc, 0x80)) {
+
+      for (i = 0; i < 8; i++) {
+        /* 8 updates, 1 bit indicate whether there is one and if follow by a
+         * 7 bit update */
+        if (vp8dx_decode_bool (&bc, 0x80))
+          vp8_decode_value (&bc, 7);
+      }
+    }
+  }
+
+  if (vp8dx_bool_error (&bc))
+    goto error;
+
+  tmp8 = vp8_decode_value (&bc, 2);
+
+  partitions = 1 << tmp8;
+
+  /* Check if things are still sensible */
+  if (partition0_size + (partitions - 1) * 3 >= size)
+    goto error;
+
+  /* partition data is right after the mode partition */
+  pdata = data + partition0_size;
+
+  /* Set up mapping */
+  self->n_partitions = partitions + 1;
+  self->partition_offset[0] = 0;
+  self->partition_size[0] = partition0_size + (partitions - 1) * 3;
+
+  self->partition_offset[1] = self->partition_size[0];
+  for (i = 1; i < partitions; i++) {
+    guint psize = (pdata[2] << 16 | pdata[1] << 8 | pdata[0]);
+
+    pdata += 3;
+    self->partition_size[i] = psize;
+    self->partition_offset[i + 1] = self->partition_offset[i] + psize;
+  }
+
+  /* Check that our partition offsets and sizes don't go outsize the buffer
+   * size. */
+  if (self->partition_offset[i] >= size)
+    goto error;
+
+  self->partition_size[i] = size - self->partition_offset[i];
+
+  self->partition_offset[i + 1] = size;
+
+  gst_buffer_unmap (buffer, &map);
+  return TRUE;
+
+error:
+  GST_DEBUG ("Failed to parse frame");
+  if (map.memory != NULL) {
+    gst_buffer_unmap (buffer, &map);
+  }
+  return FALSE;
+}
+
+static guint
+gst_rtp_vp8_offset_to_partition (GstRtpVP8Pay * self, guint offset)
+{
+  int i;
+
+  for (i = 1; i < self->n_partitions; i++) {
+    if (offset < self->partition_offset[i])
+      return i - 1;
+  }
+
+  return i - 1;
+}
+
+static gsize
+gst_rtp_vp8_calc_header_len (GstRtpVP8Pay * self)
+{
+  switch (self->picture_id_mode) {
+    case VP8_PAY_PICTURE_ID_7BITS:
+      return 3;
+    case VP8_PAY_PICTURE_ID_15BITS:
+      return 4;
+    case VP8_PAY_NO_PICTURE_ID:
+    default:
+      return 1;
+  }
+}
+
+/* When growing the vp8 header keep max payload len calculation in sync */
+static GstBuffer *
+gst_rtp_vp8_create_header_buffer (GstRtpVP8Pay * self, guint8 partid,
+    gboolean start, gboolean mark, GstBuffer * in)
+{
+  GstBuffer *out;
+  guint8 *p;
+  GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
+
+  out = gst_rtp_buffer_new_allocate (gst_rtp_vp8_calc_header_len (self), 0, 0);
+  gst_rtp_buffer_map (out, GST_MAP_READWRITE, &rtpbuffer);
+  p = gst_rtp_buffer_get_payload (&rtpbuffer);
+  /* X=0,R=0,N=0,S=start,PartID=partid */
+  p[0] = (start << 4) | partid;
+  if (self->picture_id_mode != VP8_PAY_NO_PICTURE_ID) {
+    /* Enable X=1 */
+    p[0] |= 0x80;
+    /* X: I=1,L=0,T=0,K=0,RSV=0 */
+    p[1] = 0x80;
+    if (self->picture_id_mode == VP8_PAY_PICTURE_ID_7BITS) {
+      /* I: 7 bit picture_id */
+      p[2] = self->picture_id & 0x7F;
+    } else {
+      /* I: 15 bit picture_id */
+      p[2] = 0x80 | ((self->picture_id & 0x7FFF) >> 8);
+      p[3] = self->picture_id & 0xFF;
+    }
+  }
+
+  gst_rtp_buffer_set_marker (&rtpbuffer, mark);
+
+  gst_rtp_buffer_unmap (&rtpbuffer);
+
+  GST_BUFFER_DURATION (out) = GST_BUFFER_DURATION (in);
+  GST_BUFFER_PTS (out) = GST_BUFFER_PTS (in);
+
+  return out;
+}
+
+static guint
+gst_rtp_vp8_payload_next (GstRtpVP8Pay * self, GstBufferList * list,
+    guint offset, GstBuffer * buffer, gsize buffer_size, gsize max_payload_len)
+{
+  guint partition;
+  GstBuffer *header;
+  GstBuffer *sub;
+  GstBuffer *out;
+  gboolean mark;
+  gsize remaining;
+  gsize available;
+
+  remaining = buffer_size - offset;
+  available = max_payload_len;
+  if (available > remaining)
+    available = remaining;
+
+  partition = gst_rtp_vp8_offset_to_partition (self, offset);
+  g_assert (partition < self->n_partitions);
+
+  mark = (remaining == available);
+  /* whole set of partitions, payload them and done */
+  header = gst_rtp_vp8_create_header_buffer (self, partition,
+      offset == self->partition_offset[partition], mark, buffer);
+  sub = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, available);
+
+  gst_rtp_copy_video_meta (self, header, buffer);
+
+  out = gst_buffer_append (header, sub);
+
+  gst_buffer_list_insert (list, -1, out);
+
+  return available;
+}
+
+
+static GstFlowReturn
+gst_rtp_vp8_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
+{
+  GstRtpVP8Pay *self = GST_RTP_VP8_PAY (payload);
+  GstFlowReturn ret;
+  GstBufferList *list;
+  gsize size, max_paylen;
+  guint offset, mtu, vp8_hdr_len;
+
+  size = gst_buffer_get_size (buffer);
+
+  if (G_UNLIKELY (!gst_rtp_vp8_pay_parse_frame (self, buffer, size))) {
+    GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
+        ("Failed to parse VP8 frame"));
+    return GST_FLOW_ERROR;
+  }
+
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (payload);
+  vp8_hdr_len = gst_rtp_vp8_calc_header_len (self);
+  max_paylen = gst_rtp_buffer_calc_payload_len (mtu - vp8_hdr_len, 0, 0);
+
+  list = gst_buffer_list_new_sized ((size / max_paylen) + 1);
+
+  offset = 0;
+  while (offset < size) {
+    offset +=
+        gst_rtp_vp8_payload_next (self, list, offset, buffer, size, max_paylen);
+  }
+
+  ret = gst_rtp_base_payload_push_list (payload, list);
+
+  /* Incremenent and wrap the picture id if it overflows */
+  if ((self->picture_id_mode == VP8_PAY_PICTURE_ID_7BITS &&
+          ++self->picture_id >= 0x80) ||
+      (self->picture_id_mode == VP8_PAY_PICTURE_ID_15BITS &&
+          ++self->picture_id >= 0x8000))
+    self->picture_id = 0;
+
+  gst_buffer_unref (buffer);
+
+  return ret;
+}
+
+static gboolean
+gst_rtp_vp8_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+  GstRtpVP8Pay *self = GST_RTP_VP8_PAY (payload);
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_START) {
+    if (self->picture_id_mode == VP8_PAY_PICTURE_ID_7BITS)
+      self->picture_id = g_random_int_range (0, G_MAXUINT8) & 0x7F;
+    else if (self->picture_id_mode == VP8_PAY_PICTURE_ID_15BITS)
+      self->picture_id = g_random_int_range (0, G_MAXUINT16) & 0x7FFF;
+  }
+
+  return GST_RTP_BASE_PAYLOAD_CLASS (gst_rtp_vp8_pay_parent_class)->sink_event
+      (payload, event);
+}
+
+static gboolean
+gst_rtp_vp8_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  GstCaps *src_caps;
+  GstStructure *s;
+  char *encoding_name;
+
+  src_caps = gst_pad_get_allowed_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload));
+  if (src_caps) {
+    src_caps = gst_caps_make_writable (src_caps);
+    src_caps = gst_caps_truncate (src_caps);
+    s = gst_caps_get_structure (src_caps, 0);
+    gst_structure_fixate_field_string (s, "encoding-name", "VP8");
+    encoding_name = g_strdup (gst_structure_get_string (s, "encoding-name"));
+    gst_caps_unref (src_caps);
+  } else {
+    encoding_name = g_strdup ("VP8-DRAFT-IETF-01");
+  }
+
+  gst_rtp_base_payload_set_options (payload, "video", TRUE,
+      encoding_name, 90000);
+  g_free (encoding_name);
+  return gst_rtp_base_payload_set_outcaps (payload, NULL);
+}
+
+gboolean
+gst_rtp_vp8_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpvp8pay",
+      GST_RANK_MARGINAL, GST_TYPE_RTP_VP8_PAY);
+}
diff --git a/gst/rtp/gstrtpvp8pay.h b/gst/rtp/gstrtpvp8pay.h
new file mode 100644
index 0000000..2472060
--- /dev/null
+++ b/gst/rtp/gstrtpvp8pay.h
@@ -0,0 +1,74 @@
+/*
+ * gstrtpvp8pay.h - Header for GstRtpVP8Pay
+ * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GST_RTP_VP8_PAY_H__
+#define __GST_RTP_VP8_PAY_H__
+
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_VP8_PAY \
+  (gst_rtp_vp8_pay_get_type())
+#define GST_RTP_VP8_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_RTP_VP8_PAY, GstRtpVP8Pay))
+#define GST_RTP_VP8_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_RTP_VP8_PAY, GstRtpVP8PayClass))
+#define GST_IS_RTP_VP8_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_RTP_VP8_PAY))
+#define GST_IS_RTP_VP8_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_RTP_VP8_PAY))
+#define GST_RTP_VP8_PAY_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_VP8_PAY, GstRtpVP8PayClass))
+
+typedef struct _GstRtpVP8Pay GstRtpVP8Pay;
+typedef struct _GstRtpVP8PayClass GstRtpVP8PayClass;
+typedef enum _PictureIDMode PictureIDMode;
+
+enum _PictureIDMode {
+  VP8_PAY_NO_PICTURE_ID,
+  VP8_PAY_PICTURE_ID_7BITS,
+  VP8_PAY_PICTURE_ID_15BITS,
+};
+
+struct _GstRtpVP8PayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+struct _GstRtpVP8Pay
+{
+  GstRTPBasePayload parent;
+  gboolean is_keyframe;
+  gint n_partitions;
+  /* Treat frame header & tag & partition size block as the first partition,
+   * folowed by max. 8 data partitions. last offset is the end of the buffer */
+  guint partition_offset[10];
+  guint partition_size[9];
+  PictureIDMode picture_id_mode;
+  guint16 picture_id;
+};
+
+GType gst_rtp_vp8_pay_get_type (void);
+
+gboolean gst_rtp_vp8_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* #ifndef __GST_RTP_VP8_PAY_H__ */
diff --git a/gst/rtp/gstrtpvp9depay.c b/gst/rtp/gstrtpvp9depay.c
new file mode 100644
index 0000000..c61affc
--- /dev/null
+++ b/gst/rtp/gstrtpvp9depay.c
@@ -0,0 +1,378 @@
+/* gstrtpvp9depay.c - Source for GstRtpVP9Depay
+ * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
+ * Copyright (C) 2011 Collabora Ltd.
+ *   Contact: Youness Alaoui <youness.alaoui@collabora.co.uk>
+ * Copyright (C) 2015 Stian Selnes <stian@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstrtpvp9depay.h"
+#include "gstrtputils.h"
+
+#include <gst/video/video.h>
+
+#include <stdio.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_vp9_depay_debug);
+#define GST_CAT_DEFAULT gst_rtp_vp9_depay_debug
+
+static void gst_rtp_vp9_depay_dispose (GObject * object);
+static GstBuffer *gst_rtp_vp9_depay_process (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp);
+static GstStateChangeReturn gst_rtp_vp9_depay_change_state (GstElement *
+    element, GstStateChange transition);
+static gboolean gst_rtp_vp9_depay_handle_event (GstRTPBaseDepayload * depay,
+    GstEvent * event);
+
+G_DEFINE_TYPE (GstRtpVP9Depay, gst_rtp_vp9_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static GstStaticPadTemplate gst_rtp_vp9_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-vp9"));
+
+static GstStaticPadTemplate gst_rtp_vp9_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "clock-rate = (int) 90000,"
+        "media = (string) \"video\","
+        "encoding-name = (string) { \"VP9\", \"VP9-DRAFT-IETF-01\" }"));
+
+static void
+gst_rtp_vp9_depay_init (GstRtpVP9Depay * self)
+{
+  self->adapter = gst_adapter_new ();
+  self->started = FALSE;
+}
+
+static void
+gst_rtp_vp9_depay_class_init (GstRtpVP9DepayClass * gst_rtp_vp9_depay_class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (gst_rtp_vp9_depay_class);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (gst_rtp_vp9_depay_class);
+  GstRTPBaseDepayloadClass *depay_class =
+      (GstRTPBaseDepayloadClass *) (gst_rtp_vp9_depay_class);
+
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_vp9_depay_sink_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_vp9_depay_src_template);
+
+  gst_element_class_set_static_metadata (element_class, "RTP VP9 depayloader",
+      "Codec/Depayloader/Network/RTP",
+      "Extracts VP9 video from RTP packets)", "Stian Selnes <stian@pexip.com>");
+
+  object_class->dispose = gst_rtp_vp9_depay_dispose;
+
+  element_class->change_state = gst_rtp_vp9_depay_change_state;
+
+  depay_class->process_rtp_packet = gst_rtp_vp9_depay_process;
+  depay_class->handle_event = gst_rtp_vp9_depay_handle_event;
+
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_vp9_depay_debug, "rtpvp9depay", 0,
+      "VP9 Video RTP Depayloader");
+}
+
+static void
+gst_rtp_vp9_depay_dispose (GObject * object)
+{
+  GstRtpVP9Depay *self = GST_RTP_VP9_DEPAY (object);
+
+  if (self->adapter != NULL)
+    g_object_unref (self->adapter);
+  self->adapter = NULL;
+
+  /* release any references held by the object here */
+
+  if (G_OBJECT_CLASS (gst_rtp_vp9_depay_parent_class)->dispose)
+    G_OBJECT_CLASS (gst_rtp_vp9_depay_parent_class)->dispose (object);
+}
+
+static GstBuffer *
+gst_rtp_vp9_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp)
+{
+  GstRtpVP9Depay *self = GST_RTP_VP9_DEPAY (depay);
+  GstBuffer *payload;
+  guint8 *data;
+  guint hdrsize = 1;
+  guint size;
+  gint spatial_layer = 0;
+  gboolean i_bit, p_bit, l_bit, f_bit, b_bit, e_bit, v_bit;
+
+  if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (rtp->buffer))) {
+    GST_LOG_OBJECT (self, "Discontinuity, flushing adapter");
+    gst_adapter_clear (self->adapter);
+    self->started = FALSE;
+  }
+
+  size = gst_rtp_buffer_get_payload_len (rtp);
+
+  /* Mandatory with at least one header and one vp9 byte */
+  if (G_UNLIKELY (size < hdrsize + 1))
+    goto too_small;
+
+  data = gst_rtp_buffer_get_payload (rtp);
+  i_bit = (data[0] & 0x80) != 0;
+  p_bit = (data[0] & 0x40) != 0;
+  l_bit = (data[0] & 0x20) != 0;
+  f_bit = (data[0] & 0x10) != 0;
+  b_bit = (data[0] & 0x08) != 0;
+  e_bit = (data[0] & 0x04) != 0;
+  v_bit = (data[0] & 0x02) != 0;
+
+  if (G_UNLIKELY (!self->started)) {
+    /* Check if this is the start of a VP9 layer frame, otherwise bail */
+    if (!b_bit)
+      goto done;
+
+    self->started = TRUE;
+  }
+
+  GST_TRACE_OBJECT (self, "IPLFBEV : %d%d%d%d%d%d%d", i_bit, p_bit, l_bit,
+      f_bit, b_bit, e_bit, v_bit);
+
+  /* Check I optional header Picture ID */
+  if (i_bit) {
+    hdrsize++;
+    if (G_UNLIKELY (size < hdrsize + 1))
+      goto too_small;
+    /* Check M for 15 bits PictureID */
+    if ((data[1] & 0x80) != 0) {
+      hdrsize++;
+      if (G_UNLIKELY (size < hdrsize + 1))
+        goto too_small;
+    }
+  }
+
+  /* Check L optional header layer indices */
+  if (l_bit) {
+    hdrsize++;
+    /* Check TL0PICIDX temporal layer zero index (non-flexible mode) */
+    if (!f_bit)
+      hdrsize++;
+  }
+
+  if (p_bit && f_bit) {
+    gint i;
+
+    /* At least one P_DIFF|N, up to three times */
+    for (i = 0; i < 3; i++) {
+      guint p_diff, n_bit;
+
+      if (G_UNLIKELY (size < hdrsize + 1))
+        goto too_small;
+
+      p_diff = data[hdrsize] >> 1;
+      n_bit = data[hdrsize] & 0x1;
+      GST_TRACE_OBJECT (self, "P_DIFF[%d]=%d", i, p_diff);
+      hdrsize++;
+
+      if (!n_bit)
+        break;
+    }
+  }
+
+  /* Check V optional Scalability Structure */
+  if (v_bit) {
+    guint n_s, y_bit, g_bit;
+    guint8 *ss = &data[hdrsize];
+    guint sssize = 1;
+
+    if (G_UNLIKELY (size < hdrsize + sssize + 1))
+      goto too_small;
+
+    n_s = (ss[0] & 0xe0) >> 5;
+    y_bit = (ss[0] & 0x10) != 0;
+    g_bit = (ss[0] & 0x08) != 0;
+
+    GST_TRACE_OBJECT (self, "SS header: N_S=%u, Y=%u, G=%u", n_s, y_bit, g_bit);
+
+    sssize += y_bit ? (n_s + 1) * 4 : 0;
+    if (G_UNLIKELY (size < hdrsize + sssize + 1))
+      goto too_small;
+
+    if (y_bit) {
+      guint i;
+      for (i = 0; i <= n_s; i++) {
+        /* For now, simply use the last layer specified for width and height */
+        self->ss_width = ss[1 + i * 4] * 256 + ss[2 + i * 4];
+        self->ss_height = ss[3 + i * 4] * 256 + ss[4 + i * 4];
+        GST_TRACE_OBJECT (self, "N_S[%d]: WIDTH=%u, HEIGHT=%u", i,
+            self->ss_width, self->ss_height);
+      }
+    }
+
+    if (g_bit) {
+      guint i, j;
+      guint n_g = ss[sssize];
+      sssize++;
+      if (G_UNLIKELY (size < hdrsize + sssize + 1))
+        goto too_small;
+      for (i = 0; i < n_g; i++) {
+        guint t = (ss[sssize] & 0xe0) >> 5;
+        guint u = (ss[sssize] & 0x10) >> 4;
+        guint r = (ss[sssize] & 0x0c) >> 2;
+        GST_TRACE_OBJECT (self, "N_G[%u]: 0x%02x -> T=%u, U=%u, R=%u", i,
+            ss[sssize], t, u, r);
+        for (j = 0; j < r; j++)
+          GST_TRACE_OBJECT (self, "  R[%u]: P_DIFF=%u", j, ss[sssize + 1 + j]);
+        sssize += 1 + r;
+        if (G_UNLIKELY (size < hdrsize + sssize + 1))
+          goto too_small;
+      }
+    }
+    hdrsize += sssize;
+  }
+
+  GST_DEBUG_OBJECT (depay, "hdrsize %u, size %u", hdrsize, size);
+
+  if (G_UNLIKELY (hdrsize >= size))
+    goto too_small;
+
+  payload = gst_rtp_buffer_get_payload_subbuffer (rtp, hdrsize, -1);
+  {
+    GstMapInfo map;
+    gst_buffer_map (payload, &map, GST_MAP_READ);
+    GST_MEMDUMP_OBJECT (self, "vp9 payload", map.data, 16);
+    gst_buffer_unmap (payload, &map);
+  }
+  gst_adapter_push (self->adapter, payload);
+
+  /* Marker indicates that it was the last rtp packet for this frame */
+  if (gst_rtp_buffer_get_marker (rtp)) {
+    GstBuffer *out;
+    gboolean key_frame_first_layer = !p_bit && spatial_layer == 0;
+
+    if (gst_adapter_available (self->adapter) < 10)
+      goto too_small;
+
+    out = gst_adapter_take_buffer (self->adapter,
+        gst_adapter_available (self->adapter));
+
+    self->started = FALSE;
+
+    /* mark keyframes */
+    out = gst_buffer_make_writable (out);
+    /* Filter away all metas that are not sensible to copy */
+    gst_rtp_drop_non_video_meta (self, out);
+    if (!key_frame_first_layer) {
+      GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT);
+
+      if (!self->caps_sent) {
+        gst_buffer_unref (out);
+        out = NULL;
+        GST_INFO_OBJECT (self, "Dropping inter-frame before intra-frame");
+        gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depay),
+            gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
+                TRUE, 0));
+      }
+    } else {
+      GST_BUFFER_FLAG_UNSET (out, GST_BUFFER_FLAG_DELTA_UNIT);
+
+      if (self->last_width != self->ss_width ||
+          self->last_height != self->ss_height) {
+        GstCaps *srccaps;
+
+        /* Width and height are optional in the RTP header. Consider to parse
+         * the frame header in addition if missing from RTP header */
+        if (self->ss_width != 0 && self->ss_height != 0) {
+          srccaps = gst_caps_new_simple ("video/x-vp9",
+              "framerate", GST_TYPE_FRACTION, 0, 1,
+              "width", G_TYPE_INT, self->ss_width,
+              "height", G_TYPE_INT, self->ss_height, NULL);
+        } else {
+          srccaps = gst_caps_new_simple ("video/x-vp9",
+              "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
+        }
+
+        gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depay), srccaps);
+        gst_caps_unref (srccaps);
+
+        self->caps_sent = TRUE;
+        self->last_width = self->ss_width;
+        self->last_height = self->ss_height;
+        self->ss_width = 0;
+        self->ss_height = 0;
+      }
+    }
+
+    return out;
+  }
+
+done:
+  return NULL;
+
+too_small:
+  GST_LOG_OBJECT (self, "Invalid rtp packet (too small), ignoring");
+  gst_adapter_clear (self->adapter);
+  self->started = FALSE;
+
+  goto done;
+}
+
+static GstStateChangeReturn
+gst_rtp_vp9_depay_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRtpVP9Depay *self = GST_RTP_VP9_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      self->last_width = -1;
+      self->last_height = -1;
+      self->caps_sent = FALSE;
+      break;
+    default:
+      break;
+  }
+
+  return
+      GST_ELEMENT_CLASS (gst_rtp_vp9_depay_parent_class)->change_state (element,
+      transition);
+}
+
+static gboolean
+gst_rtp_vp9_depay_handle_event (GstRTPBaseDepayload * depay, GstEvent * event)
+{
+  GstRtpVP9Depay *self = GST_RTP_VP9_DEPAY (depay);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      self->last_width = -1;
+      self->last_height = -1;
+      break;
+    default:
+      break;
+  }
+
+  return
+      GST_RTP_BASE_DEPAYLOAD_CLASS
+      (gst_rtp_vp9_depay_parent_class)->handle_event (depay, event);
+}
+
+gboolean
+gst_rtp_vp9_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpvp9depay",
+      GST_RANK_MARGINAL, GST_TYPE_RTP_VP9_DEPAY);
+}
diff --git a/gst/rtp/gstrtpvp9depay.h b/gst/rtp/gstrtpvp9depay.h
new file mode 100644
index 0000000..6f783ab
--- /dev/null
+++ b/gst/rtp/gstrtpvp9depay.h
@@ -0,0 +1,71 @@
+/*
+ * gstrtpvp9depay.h - Header for GstRtpVP9Depay
+ * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
+ * Copyright (C) 2015 Stian Selnes <stian@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GST_RTP_VP9_DEPAY_H__
+#define __GST_RTP_VP9_DEPAY_H__
+
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_VP9_DEPAY \
+  (gst_rtp_vp9_depay_get_type())
+#define GST_RTP_VP9_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_RTP_VP9_DEPAY, GstRtpVP9Depay))
+#define GST_RTP_VP9_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_RTP_VP9_DEPAY, \
+    GstRtpVP9DepayClass))
+#define GST_IS_RTP_VP9_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_RTP_VP9_DEPAY))
+#define GST_IS_RTP_VP9_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_RTP_VP9_DEPAY))
+#define GST_RTP_VP9_DEPAY_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_VP9_DEPAY, \
+    GstRtpVP9DepayClass))
+
+typedef struct _GstRtpVP9Depay GstRtpVP9Depay;
+typedef struct _GstRtpVP9DepayClass GstRtpVP9DepayClass;
+
+struct _GstRtpVP9DepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+struct _GstRtpVP9Depay
+{
+  GstRTPBaseDepayload parent;
+  GstAdapter *adapter;
+  gboolean started;
+
+  gint ss_width;
+  gint ss_height;
+  gint last_width;
+  gint last_height;
+  gboolean caps_sent;
+};
+
+GType gst_rtp_vp9_depay_get_type (void);
+
+gboolean gst_rtp_vp9_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* #ifndef __GST_RTP_VP9_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpvp9pay.c b/gst/rtp/gstrtpvp9pay.c
new file mode 100644
index 0000000..a0b01e1
--- /dev/null
+++ b/gst/rtp/gstrtpvp9pay.c
@@ -0,0 +1,556 @@
+/*
+ * gstrtpvp9pay.c - Source for GstRtpVP9Pay
+ * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
+ * Copyright (C) 2011 Collabora Ltd.
+ *   Contact: Youness Alaoui <youness.alaoui@collabora.co.uk>
+ * Copyright (C) 2015 Stian Selnes <stian@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gst/base/gstbitreader.h>
+#include <gst/rtp/gstrtppayloads.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+#include "dboolhuff.h"
+#include "gstrtpvp9pay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_vp9_pay_debug);
+#define GST_CAT_DEFAULT gst_rtp_vp9_pay_debug
+
+#define DEFAULT_PICTURE_ID_MODE VP9_PAY_NO_PICTURE_ID
+
+enum
+{
+  PROP_0,
+  PROP_PICTURE_ID_MODE
+};
+
+#define GST_TYPE_RTP_VP9_PAY_PICTURE_ID_MODE (gst_rtp_vp9_pay_picture_id_mode_get_type())
+static GType
+gst_rtp_vp9_pay_picture_id_mode_get_type (void)
+{
+  static GType mode_type = 0;
+  static const GEnumValue modes[] = {
+    {VP9_PAY_NO_PICTURE_ID, "No Picture ID", "none"},
+    {VP9_PAY_PICTURE_ID_7BITS, "7-bit Picture ID", "7-bit"},
+    {VP9_PAY_PICTURE_ID_15BITS, "15-bit Picture ID", "15-bit"},
+    {0, NULL, NULL},
+  };
+
+  if (!mode_type) {
+    mode_type = g_enum_register_static ("GstVP9RTPPayMode", modes);
+  }
+  return mode_type;
+}
+
+static void gst_rtp_vp9_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_rtp_vp9_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+
+static GstFlowReturn gst_rtp_vp9_pay_handle_buffer (GstRTPBasePayload * payload,
+    GstBuffer * buffer);
+static gboolean gst_rtp_vp9_pay_sink_event (GstRTPBasePayload * payload,
+    GstEvent * event);
+static gboolean gst_rtp_vp9_pay_set_caps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+
+G_DEFINE_TYPE (GstRtpVP9Pay, gst_rtp_vp9_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static GstStaticPadTemplate gst_rtp_vp9_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ","
+        "clock-rate = (int) 90000, encoding-name = (string) { \"VP9\", \"VP9-DRAFT-IETF-01\" }"));
+
+static GstStaticPadTemplate gst_rtp_vp9_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-vp9"));
+
+static void
+gst_rtp_vp9_pay_init (GstRtpVP9Pay * obj)
+{
+  obj->picture_id_mode = DEFAULT_PICTURE_ID_MODE;
+  if (obj->picture_id_mode == VP9_PAY_PICTURE_ID_7BITS)
+    obj->picture_id = g_random_int_range (0, G_MAXUINT8) & 0x7F;
+  else if (obj->picture_id_mode == VP9_PAY_PICTURE_ID_15BITS)
+    obj->picture_id = g_random_int_range (0, G_MAXUINT16) & 0x7FFF;
+}
+
+static void
+gst_rtp_vp9_pay_class_init (GstRtpVP9PayClass * gst_rtp_vp9_pay_class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (gst_rtp_vp9_pay_class);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (gst_rtp_vp9_pay_class);
+  GstRTPBasePayloadClass *pay_class =
+      GST_RTP_BASE_PAYLOAD_CLASS (gst_rtp_vp9_pay_class);
+
+  gobject_class->set_property = gst_rtp_vp9_pay_set_property;
+  gobject_class->get_property = gst_rtp_vp9_pay_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_PICTURE_ID_MODE,
+      g_param_spec_enum ("picture-id-mode", "Picture ID Mode",
+          "The picture ID mode for payloading",
+          GST_TYPE_RTP_VP9_PAY_PICTURE_ID_MODE, DEFAULT_PICTURE_ID_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_vp9_pay_sink_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_rtp_vp9_pay_src_template);
+
+  gst_element_class_set_static_metadata (element_class, "RTP VP9 payloader",
+      "Codec/Payloader/Network/RTP",
+      "Puts VP9 video in RTP packets)", "Stian Selnes <stian@pexip.com>");
+
+  pay_class->handle_buffer = gst_rtp_vp9_pay_handle_buffer;
+  pay_class->sink_event = gst_rtp_vp9_pay_sink_event;
+  pay_class->set_caps = gst_rtp_vp9_pay_set_caps;
+
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_vp9_pay_debug, "rtpvp9pay", 0,
+      "VP9 Video RTP Payloader");
+}
+
+static void
+gst_rtp_vp9_pay_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstRtpVP9Pay *rtpvp9pay = GST_RTP_VP9_PAY (object);
+
+  switch (prop_id) {
+    case PROP_PICTURE_ID_MODE:
+      rtpvp9pay->picture_id_mode = g_value_get_enum (value);
+      if (rtpvp9pay->picture_id_mode == VP9_PAY_PICTURE_ID_7BITS)
+        rtpvp9pay->picture_id = g_random_int_range (0, G_MAXUINT8) & 0x7F;
+      else if (rtpvp9pay->picture_id_mode == VP9_PAY_PICTURE_ID_15BITS)
+        rtpvp9pay->picture_id = g_random_int_range (0, G_MAXUINT16) & 0x7FFF;
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_vp9_pay_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstRtpVP9Pay *rtpvp9pay = GST_RTP_VP9_PAY (object);
+
+  switch (prop_id) {
+    case PROP_PICTURE_ID_MODE:
+      g_value_set_enum (value, rtpvp9pay->picture_id_mode);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+#define VP9_PROFILE_0 0
+#define VP9_PROFILE_1 1
+#define VP9_PROFILE_2 2
+#define VP9_PROFILE_3 3
+#define VP9_FRAME_MARKER 0x2
+#define VPX_CS_SRGB 7
+
+static gboolean
+gst_rtp_vp9_pay_parse_frame (GstRtpVP9Pay * self, GstBuffer * buffer,
+    gsize buffer_size)
+{
+  GstMapInfo map = GST_MAP_INFO_INIT;
+  GstBitReader reader;
+  guint8 *data;
+  gsize size;
+  gboolean keyframe;
+  guint32 tmp, profile;
+
+  if (G_UNLIKELY (buffer_size < 3))
+    goto error;
+
+  if (!gst_buffer_map (buffer, &map, GST_MAP_READ) || !map.data)
+    goto error;
+
+  data = map.data;
+  size = map.size;
+
+  gst_bit_reader_init (&reader, data, size);
+
+
+  /* frame marker */
+  if (!gst_bit_reader_get_bits_uint32 (&reader, &tmp, 2)
+      || tmp != VP9_FRAME_MARKER)
+    goto error;
+
+  /* profile, variable length */
+  if (!gst_bit_reader_get_bits_uint32 (&reader, &profile, 2))
+    goto error;
+  if (profile > 2) {
+    if (!gst_bit_reader_get_bits_uint32 (&reader, &tmp, 1))
+      goto error;
+    profile += tmp;
+  }
+
+  /* show existing frame */
+  if (!gst_bit_reader_get_bits_uint32 (&reader, &tmp, 1))
+    goto error;
+  if (tmp) {
+    if (!gst_bit_reader_skip (&reader, 3))
+      goto error;
+    return TRUE;
+  }
+
+  /* frame type */
+  if (!gst_bit_reader_get_bits_uint32 (&reader, &tmp, 1))
+    goto error;
+  self->is_keyframe = keyframe = (tmp == 0);
+
+  /* show frame and resilient mode */
+  if (!gst_bit_reader_skip (&reader, 2))
+    goto error;
+
+  if (keyframe) {
+    /* sync code */
+    const guint32 sync_code = 0x498342;
+    if (!gst_bit_reader_get_bits_uint32 (&reader, &tmp, 24))
+      goto error;
+    if (tmp != sync_code)
+      goto error;
+
+    if (profile >= VP9_PROFILE_2) {
+      /* bit depth */
+      if (!gst_bit_reader_skip (&reader, 1))
+        goto error;
+    }
+
+    /* color space */
+    if (!gst_bit_reader_get_bits_uint32 (&reader, &tmp, 3))
+      goto error;
+    if (tmp != VPX_CS_SRGB) {
+      /* color range */
+      if (!gst_bit_reader_skip (&reader, 1))
+        goto error;
+      if (profile == VP9_PROFILE_1 || profile == VP9_PROFILE_3) {
+        /* subsampling + reserved bit */
+        if (!gst_bit_reader_skip (&reader, 2 + 1))
+          goto error;
+      }
+    } else {
+      if (profile == VP9_PROFILE_1 || profile == VP9_PROFILE_3)
+        /* reserved bit */
+        if (!gst_bit_reader_skip (&reader, 1))
+          goto error;
+    }
+
+    /* frame size */
+    if (!gst_bit_reader_get_bits_uint32 (&reader, &tmp, 16))
+      goto error;
+    self->width = tmp + 1;
+    if (!gst_bit_reader_get_bits_uint32 (&reader, &tmp, 16))
+      goto error;
+    self->height = tmp + 1;
+
+    /* render size */
+    if (!gst_bit_reader_get_bits_uint32 (&reader, &tmp, 1))
+      goto error;
+    if (tmp) {
+      if (!gst_bit_reader_skip (&reader, 32))
+        goto error;
+    }
+
+    GST_INFO_OBJECT (self, "parsed width=%d height=%d", self->width,
+        self->height);
+  }
+
+
+  gst_buffer_unmap (buffer, &map);
+  return TRUE;
+
+error:
+  GST_DEBUG ("Failed to parse frame");
+  if (map.memory != NULL) {
+    gst_buffer_unmap (buffer, &map);
+  }
+  return FALSE;
+}
+
+static gsize
+gst_rtp_vp9_calc_header_len (GstRtpVP9Pay * self, gboolean start)
+{
+  gsize len = 1;
+
+  switch (self->picture_id_mode) {
+    case VP9_PAY_PICTURE_ID_7BITS:
+      len += 1;
+      break;
+    case VP9_PAY_PICTURE_ID_15BITS:
+      len += 2;
+    default:
+      break;
+  }
+
+  /* Assume non-flexible mode */
+  /* Assume L-bit not set, no L header */
+
+  if (self->is_keyframe && start) {
+    /* Assume V-bit set */
+    /* FIXME: SS depends on layers and prediction structure */
+    /* For now assume 1 spatial and 1 temporal layer. */
+    /* FIXME: Only for the first packet in the key frame */
+    len += 8;
+  }
+
+  return len;
+}
+
+/* VP9 RTP header, non-flexible mode:
+
+         0 1 2 3 4 5 6 7
+        +-+-+-+-+-+-+-+-+
+        |I|P|L|F|B|E|V|-| (REQUIRED)
+        +-+-+-+-+-+-+-+-+
+   I:   |M| PICTURE ID  | (RECOMMENDED)
+        +-+-+-+-+-+-+-+-+
+   M:   | EXTENDED PID  | (RECOMMENDED)
+        +-+-+-+-+-+-+-+-+
+   L:   |  T  |U|  S  |D| (CONDITIONALLY RECOMMENDED)
+        +-+-+-+-+-+-+-+-+                             -\
+   P,F: | P_DIFF    |X|N| (CONDITIONALLY RECOMMENDED)  .
+        +-+-+-+-+-+-+-+-+                              . - up to 3 times
+   X:   |EXTENDED P_DIFF| (OPTIONAL)                   .
+        +-+-+-+-+-+-+-+-+                             -/
+   V:   | SS            |
+        | ..            |
+        +-+-+-+-+-+-+-+-+
+
+   Scalability structure (SS)
+     (from https://chromium.googlesource.com/external/webrtc/+/HEAD/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc
+     since latest draft is not up to date with chromium)
+
+        +-+-+-+-+-+-+-+-+
+   V:   | N_S |Y|G|-|-|-|
+        +-+-+-+-+-+-+-+-+              -|
+   Y:   |     WIDTH     | (OPTIONAL)    .
+        +               +               .
+        |               | (OPTIONAL)    .
+        +-+-+-+-+-+-+-+-+               . N_S + 1 times
+        |     HEIGHT    | (OPTIONAL)    .
+        +               +               .
+        |               | (OPTIONAL)    .
+        +-+-+-+-+-+-+-+-+              -|
+   G:   |      N_G      | (OPTIONAL)
+        +-+-+-+-+-+-+-+-+                           -|
+   N_G: |  T  |U| R |-|-| (OPTIONAL)                 .
+        +-+-+-+-+-+-+-+-+              -|            . N_G times
+        |    P_DIFF     | (OPTIONAL)    . R times    .
+        +-+-+-+-+-+-+-+-+              -|           -|
+
+**/
+
+/* When growing the vp9 header keep max payload len calculation in sync */
+static GstBuffer *
+gst_rtp_vp9_create_header_buffer (GstRtpVP9Pay * self,
+    gboolean start, gboolean mark, GstBuffer * in)
+{
+  GstBuffer *out;
+  guint8 *p;
+  GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
+  guint off = 1;
+  guint hdrlen = gst_rtp_vp9_calc_header_len (self, start);
+
+  out = gst_rtp_buffer_new_allocate (hdrlen, 0, 0);
+  gst_rtp_buffer_map (out, GST_MAP_READWRITE, &rtpbuffer);
+  p = gst_rtp_buffer_get_payload (&rtpbuffer);
+  p[0] = 0x0;
+
+  if (self->picture_id_mode != VP9_PAY_NO_PICTURE_ID) {
+    p[0] |= 0x80;
+    if (self->picture_id_mode == VP9_PAY_PICTURE_ID_7BITS) {
+      /* M=0 */
+      p[off++] = self->picture_id & 0x7F;
+    } else {
+      /* M=1 */
+      p[off++] = 0x80 | ((self->picture_id & 0x7FFF) >> 8);
+      p[off++] = self->picture_id & 0xFF;
+    }
+  }
+
+  if (!self->is_keyframe)
+    p[0] |= 0x40;
+  if (start)
+    p[0] |= 0x08;
+  if (mark)
+    p[0] |= 0x04;
+
+  if (self->is_keyframe && start) {
+    p[0] |= 0x02;
+    /* scalability structure, hard coded for now to be similar to chromium for
+     * quick and dirty interop */
+    p[off++] = 0x18;            /* N_S=0 Y=1 G=1 */
+    p[off++] = self->width >> 8;
+    p[off++] = self->width & 0xFF;
+    p[off++] = self->height >> 8;
+    p[off++] = self->height & 0xFF;
+    p[off++] = 0x01;            /* N_G=1 */
+    p[off++] = 0x04;            /* T=0, U=0, R=1 */
+    p[off++] = 0x01;            /* P_DIFF=1 */
+  }
+
+  g_assert_cmpint (off, ==, hdrlen);
+
+  gst_rtp_buffer_set_marker (&rtpbuffer, mark);
+
+  gst_rtp_buffer_unmap (&rtpbuffer);
+
+  GST_BUFFER_DURATION (out) = GST_BUFFER_DURATION (in);
+  GST_BUFFER_PTS (out) = GST_BUFFER_PTS (in);
+
+  return out;
+}
+
+static guint
+gst_rtp_vp9_payload_next (GstRtpVP9Pay * self, GstBufferList * list,
+    guint offset, GstBuffer * buffer, gsize buffer_size, gsize max_payload_len)
+{
+  GstBuffer *header;
+  GstBuffer *sub;
+  GstBuffer *out;
+  gboolean mark;
+  gsize remaining;
+  gsize available;
+
+  remaining = buffer_size - offset;
+  available = max_payload_len;
+  if (available > remaining)
+    available = remaining;
+
+  mark = (remaining == available);
+  header = gst_rtp_vp9_create_header_buffer (self, offset == 0, mark, buffer);
+  sub = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, available);
+
+  gst_rtp_copy_video_meta (self, header, buffer);
+
+  out = gst_buffer_append (header, sub);
+
+  gst_buffer_list_insert (list, -1, out);
+
+  return available;
+}
+
+
+static GstFlowReturn
+gst_rtp_vp9_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
+{
+  GstRtpVP9Pay *self = GST_RTP_VP9_PAY (payload);
+  GstFlowReturn ret;
+  GstBufferList *list;
+  gsize size, max_paylen;
+  guint offset, mtu, vp9_hdr_len;
+
+  size = gst_buffer_get_size (buffer);
+
+  if (G_UNLIKELY (!gst_rtp_vp9_pay_parse_frame (self, buffer, size))) {
+    GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
+        ("Failed to parse VP9 frame"));
+    return GST_FLOW_ERROR;
+  }
+
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (payload);
+  vp9_hdr_len = gst_rtp_vp9_calc_header_len (self, TRUE);
+  max_paylen = gst_rtp_buffer_calc_payload_len (mtu - vp9_hdr_len, 0, 0);
+
+  list = gst_buffer_list_new_sized ((size / max_paylen) + 1);
+
+  offset = 0;
+  while (offset < size) {
+    offset +=
+        gst_rtp_vp9_payload_next (self, list, offset, buffer, size, max_paylen);
+  }
+
+  ret = gst_rtp_base_payload_push_list (payload, list);
+
+  /* Incremenent and wrap the picture id if it overflows */
+  if ((self->picture_id_mode == VP9_PAY_PICTURE_ID_7BITS &&
+          ++self->picture_id >= 0x80) ||
+      (self->picture_id_mode == VP9_PAY_PICTURE_ID_15BITS &&
+          ++self->picture_id >= 0x8000))
+    self->picture_id = 0;
+
+  gst_buffer_unref (buffer);
+
+  return ret;
+}
+
+static gboolean
+gst_rtp_vp9_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+  GstRtpVP9Pay *self = GST_RTP_VP9_PAY (payload);
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_START) {
+    if (self->picture_id_mode == VP9_PAY_PICTURE_ID_7BITS)
+      self->picture_id = g_random_int_range (0, G_MAXUINT8) & 0x7F;
+    else if (self->picture_id_mode == VP9_PAY_PICTURE_ID_15BITS)
+      self->picture_id = g_random_int_range (0, G_MAXUINT16) & 0x7FFF;
+  }
+
+  return GST_RTP_BASE_PAYLOAD_CLASS (gst_rtp_vp9_pay_parent_class)->sink_event
+      (payload, event);
+}
+
+static gboolean
+gst_rtp_vp9_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  GstCaps *src_caps;
+  GstStructure *s;
+  char *encoding_name;
+
+  src_caps = gst_pad_get_allowed_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload));
+  if (src_caps) {
+    src_caps = gst_caps_make_writable (src_caps);
+    src_caps = gst_caps_truncate (src_caps);
+    s = gst_caps_get_structure (src_caps, 0);
+    gst_structure_fixate_field_string (s, "encoding-name", "VP9");
+    encoding_name = g_strdup (gst_structure_get_string (s, "encoding-name"));
+    gst_caps_unref (src_caps);
+  } else {
+    encoding_name = g_strdup ("VP9-DRAFT-IETF-01");
+  }
+
+  gst_rtp_base_payload_set_options (payload, "video", TRUE,
+      encoding_name, 90000);
+  g_free (encoding_name);
+  return gst_rtp_base_payload_set_outcaps (payload, NULL);
+}
+
+gboolean
+gst_rtp_vp9_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpvp9pay",
+      GST_RANK_MARGINAL, GST_TYPE_RTP_VP9_PAY);
+}
diff --git a/gst/rtp/gstrtpvp9pay.h b/gst/rtp/gstrtpvp9pay.h
new file mode 100644
index 0000000..fc2aa8e
--- /dev/null
+++ b/gst/rtp/gstrtpvp9pay.h
@@ -0,0 +1,72 @@
+/*
+ * gstrtpvp9pay.h - Header for GstRtpVP9Pay
+ * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
+ * Copyright (C) 2015 Stian Selnes <stian@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GST_RTP_VP9_PAY_H__
+#define __GST_RTP_VP9_PAY_H__
+
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_VP9_PAY \
+  (gst_rtp_vp9_pay_get_type())
+#define GST_RTP_VP9_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_RTP_VP9_PAY, GstRtpVP9Pay))
+#define GST_RTP_VP9_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_RTP_VP9_PAY, GstRtpVP9PayClass))
+#define GST_IS_RTP_VP9_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_RTP_VP9_PAY))
+#define GST_IS_RTP_VP9_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_RTP_VP9_PAY))
+#define GST_RTP_VP9_PAY_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_VP9_PAY, GstRtpVP9PayClass))
+
+typedef struct _GstRtpVP9Pay GstRtpVP9Pay;
+typedef struct _GstRtpVP9PayClass GstRtpVP9PayClass;
+typedef enum _VP9PictureIDMode VP9PictureIDMode;
+
+enum _VP9PictureIDMode {
+  VP9_PAY_NO_PICTURE_ID,
+  VP9_PAY_PICTURE_ID_7BITS,
+  VP9_PAY_PICTURE_ID_15BITS,
+};
+
+struct _GstRtpVP9PayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+struct _GstRtpVP9Pay
+{
+  GstRTPBasePayload parent;
+  gboolean is_keyframe;
+  guint width;
+  guint height;
+  VP9PictureIDMode picture_id_mode;
+  guint16 picture_id;
+};
+
+GType gst_rtp_vp9_pay_get_type (void);
+
+gboolean gst_rtp_vp9_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* #ifndef __GST_RTP_VP9_PAY_H__ */
diff --git a/gst/rtp/gstrtpvrawdepay.c b/gst/rtp/gstrtpvrawdepay.c
new file mode 100644
index 0000000..a02bb51
--- /dev/null
+++ b/gst/rtp/gstrtpvrawdepay.c
@@ -0,0 +1,666 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include "gstrtpvrawdepay.h"
+#include "gstrtputils.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpvrawdepay_debug);
+#define GST_CAT_DEFAULT (rtpvrawdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_vraw_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-raw")
+    );
+
+static GstStaticPadTemplate gst_rtp_vraw_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "clock-rate = (int) 90000, "
+        "encoding-name = (string) \"RAW\", "
+        "sampling = (string) { \"RGB\", \"RGBA\", \"BGR\", \"BGRA\", "
+        "\"YCbCr-4:4:4\", \"YCbCr-4:2:2\", \"YCbCr-4:2:0\", "
+        "\"YCbCr-4:1:1\" },"
+        /* we cannot express these as strings 
+         * "width = (string) [1 32767],"
+         * "height = (string) [1 32767],"
+         */
+        "depth = (string) { \"8\", \"10\", \"12\", \"16\" }")
+    );
+
+#define gst_rtp_vraw_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpVRawDepay, gst_rtp_vraw_depay,
+    GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_vraw_depay_setcaps (GstRTPBaseDepayload * depayload,
+    GstCaps * caps);
+static GstBuffer *gst_rtp_vraw_depay_process_packet (GstRTPBaseDepayload *
+    depay, GstRTPBuffer * rtp);
+
+static GstStateChangeReturn gst_rtp_vraw_depay_change_state (GstElement *
+    element, GstStateChange transition);
+
+static gboolean gst_rtp_vraw_depay_handle_event (GstRTPBaseDepayload * filter,
+    GstEvent * event);
+
+static void
+gst_rtp_vraw_depay_class_init (GstRtpVRawDepayClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+  gstelement_class->change_state = gst_rtp_vraw_depay_change_state;
+
+  gstrtpbasedepayload_class->set_caps = gst_rtp_vraw_depay_setcaps;
+  gstrtpbasedepayload_class->process_rtp_packet =
+      gst_rtp_vraw_depay_process_packet;
+  gstrtpbasedepayload_class->handle_event = gst_rtp_vraw_depay_handle_event;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_vraw_depay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_vraw_depay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Raw Video depayloader", "Codec/Depayloader/Network/RTP",
+      "Extracts raw video from RTP packets (RFC 4175)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpvrawdepay_debug, "rtpvrawdepay", 0,
+      "raw video RTP Depayloader");
+}
+
+static void
+gst_rtp_vraw_depay_init (GstRtpVRawDepay * rtpvrawdepay)
+{
+}
+
+static void
+gst_rtp_vraw_depay_reset (GstRtpVRawDepay * rtpvrawdepay)
+{
+  if (rtpvrawdepay->outbuf) {
+    gst_video_frame_unmap (&rtpvrawdepay->frame);
+    gst_buffer_unref (rtpvrawdepay->outbuf);
+    rtpvrawdepay->outbuf = NULL;
+  }
+  rtpvrawdepay->timestamp = -1;
+  if (rtpvrawdepay->pool) {
+    gst_buffer_pool_set_active (rtpvrawdepay->pool, FALSE);
+    gst_object_unref (rtpvrawdepay->pool);
+    rtpvrawdepay->pool = NULL;
+  }
+}
+
+static GstFlowReturn
+gst_rtp_vraw_depay_negotiate_pool (GstRtpVRawDepay * depay, GstCaps * caps,
+    GstVideoInfo * info)
+{
+  GstQuery *query;
+  GstBufferPool *pool = NULL;
+  guint size, min, max;
+  GstStructure *config;
+
+  /* find a pool for the negotiated caps now */
+  query = gst_query_new_allocation (caps, TRUE);
+
+  if (!gst_pad_peer_query (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depay), query)) {
+    /* not a problem, we use the defaults of query */
+    GST_DEBUG_OBJECT (depay, "could not get downstream ALLOCATION hints");
+  }
+
+  if (gst_query_get_n_allocation_pools (query) > 0) {
+    /* we got configuration from our peer, parse them */
+    gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
+  } else {
+    GST_DEBUG_OBJECT (depay, "didn't get downstream pool hints");
+    size = info->size;
+    min = max = 0;
+  }
+
+  if (pool == NULL) {
+    /* we did not get a pool, make one ourselves then */
+    pool = gst_video_buffer_pool_new ();
+  }
+
+  if (depay->pool)
+    gst_object_unref (depay->pool);
+  depay->pool = pool;
+
+  config = gst_buffer_pool_get_config (pool);
+  gst_buffer_pool_config_set_params (config, caps, size, min, max);
+  if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
+    /* just set the metadata, if the pool can support it we will transparently use
+     * it through the video info API. We could also see if the pool support this
+     * metadata and only activate it then. */
+    gst_buffer_pool_config_add_option (config,
+        GST_BUFFER_POOL_OPTION_VIDEO_META);
+  }
+
+  gst_buffer_pool_set_config (pool, config);
+  /* and activate */
+  gst_buffer_pool_set_active (pool, TRUE);
+
+  gst_query_unref (query);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_rtp_vraw_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstRtpVRawDepay *rtpvrawdepay;
+  gint clock_rate;
+  const gchar *str;
+  gint format, width, height, depth, pgroup, xinc, yinc;
+  GstCaps *srccaps;
+  gboolean res;
+  GstFlowReturn ret;
+
+  rtpvrawdepay = GST_RTP_VRAW_DEPAY (depayload);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  xinc = yinc = 1;
+
+  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+    clock_rate = 90000;         /* default */
+  depayload->clock_rate = clock_rate;
+
+  if (!(str = gst_structure_get_string (structure, "width")))
+    goto no_width;
+  width = atoi (str);
+
+  if (!(str = gst_structure_get_string (structure, "height")))
+    goto no_height;
+  height = atoi (str);
+
+  if (!(str = gst_structure_get_string (structure, "depth")))
+    goto no_depth;
+  depth = atoi (str);
+
+  /* optional interlace value but we don't handle interlaced
+   * formats yet */
+  if (gst_structure_get_string (structure, "interlace"))
+    goto interlaced;
+
+  if (!(str = gst_structure_get_string (structure, "sampling")))
+    goto no_sampling;
+
+  if (!strcmp (str, "RGB")) {
+    format = GST_VIDEO_FORMAT_RGB;
+    pgroup = 3;
+  } else if (!strcmp (str, "RGBA")) {
+    format = GST_VIDEO_FORMAT_RGBA;
+    pgroup = 4;
+  } else if (!strcmp (str, "BGR")) {
+    format = GST_VIDEO_FORMAT_BGR;
+    pgroup = 3;
+  } else if (!strcmp (str, "BGRA")) {
+    format = GST_VIDEO_FORMAT_BGRA;
+    pgroup = 4;
+  } else if (!strcmp (str, "YCbCr-4:4:4")) {
+    format = GST_VIDEO_FORMAT_AYUV;
+    pgroup = 3;
+  } else if (!strcmp (str, "YCbCr-4:2:2")) {
+    if (depth == 8) {
+      format = GST_VIDEO_FORMAT_UYVY;
+      pgroup = 4;
+    } else if (depth == 10) {
+      format = GST_VIDEO_FORMAT_UYVP;
+      pgroup = 5;
+    } else
+      goto unknown_format;
+    xinc = 2;
+  } else if (!strcmp (str, "YCbCr-4:2:0")) {
+    format = GST_VIDEO_FORMAT_I420;
+    pgroup = 6;
+    xinc = yinc = 2;
+  } else if (!strcmp (str, "YCbCr-4:1:1")) {
+    format = GST_VIDEO_FORMAT_Y41B;
+    pgroup = 6;
+    xinc = 4;
+  } else {
+    goto unknown_format;
+  }
+
+  gst_video_info_init (&rtpvrawdepay->vinfo);
+  gst_video_info_set_format (&rtpvrawdepay->vinfo, format, width, height);
+  GST_VIDEO_INFO_FPS_N (&rtpvrawdepay->vinfo) = 0;
+  GST_VIDEO_INFO_FPS_D (&rtpvrawdepay->vinfo) = 1;
+
+  rtpvrawdepay->pgroup = pgroup;
+  rtpvrawdepay->xinc = xinc;
+  rtpvrawdepay->yinc = yinc;
+
+  srccaps = gst_video_info_to_caps (&rtpvrawdepay->vinfo);
+  res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+  gst_caps_unref (srccaps);
+
+  GST_DEBUG_OBJECT (depayload, "width %d, height %d, format %d", width, height,
+      format);
+  GST_DEBUG_OBJECT (depayload, "xinc %d, yinc %d, pgroup %d",
+      xinc, yinc, pgroup);
+
+  /* negotiate a bufferpool */
+  if ((ret = gst_rtp_vraw_depay_negotiate_pool (rtpvrawdepay, srccaps,
+              &rtpvrawdepay->vinfo)) != GST_FLOW_OK)
+    goto no_bufferpool;
+
+  return res;
+
+  /* ERRORS */
+no_width:
+  {
+    GST_ERROR_OBJECT (depayload, "no width specified");
+    return FALSE;
+  }
+no_height:
+  {
+    GST_ERROR_OBJECT (depayload, "no height specified");
+    return FALSE;
+  }
+no_depth:
+  {
+    GST_ERROR_OBJECT (depayload, "no depth specified");
+    return FALSE;
+  }
+interlaced:
+  {
+    GST_ERROR_OBJECT (depayload, "interlaced formats not supported yet");
+    return FALSE;
+  }
+no_sampling:
+  {
+    GST_ERROR_OBJECT (depayload, "no sampling specified");
+    return FALSE;
+  }
+unknown_format:
+  {
+    GST_ERROR_OBJECT (depayload, "unknown sampling format '%s'", str);
+    return FALSE;
+  }
+no_bufferpool:
+  {
+    GST_DEBUG_OBJECT (depayload, "no bufferpool");
+    return FALSE;
+  }
+}
+
+static GstBuffer *
+gst_rtp_vraw_depay_process_packet (GstRTPBaseDepayload * depayload,
+    GstRTPBuffer * rtp)
+{
+  GstRtpVRawDepay *rtpvrawdepay;
+  guint8 *payload, *p0, *yp, *up, *vp, *headers;
+  guint32 timestamp;
+  guint cont, ystride, uvstride, pgroup, payload_len;
+  gint width, height, xinc, yinc;
+  GstVideoFrame *frame;
+  gboolean marker;
+  GstBuffer *outbuf = NULL;
+
+  rtpvrawdepay = GST_RTP_VRAW_DEPAY (depayload);
+
+  timestamp = gst_rtp_buffer_get_timestamp (rtp);
+
+  if (timestamp != rtpvrawdepay->timestamp || rtpvrawdepay->outbuf == NULL) {
+    GstBuffer *new_buffer;
+    GstFlowReturn ret;
+
+    GST_LOG_OBJECT (depayload, "new frame with timestamp %u", timestamp);
+    /* new timestamp, flush old buffer and create new output buffer */
+    if (rtpvrawdepay->outbuf) {
+      gst_video_frame_unmap (&rtpvrawdepay->frame);
+      gst_rtp_base_depayload_push (depayload, rtpvrawdepay->outbuf);
+      rtpvrawdepay->outbuf = NULL;
+    }
+
+    if (gst_pad_check_reconfigure (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload))) {
+      GstCaps *caps;
+
+      caps =
+          gst_pad_get_current_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload));
+      gst_rtp_vraw_depay_negotiate_pool (rtpvrawdepay, caps,
+          &rtpvrawdepay->vinfo);
+      gst_caps_unref (caps);
+    }
+
+    ret =
+        gst_buffer_pool_acquire_buffer (rtpvrawdepay->pool, &new_buffer, NULL);
+
+    if (G_UNLIKELY (ret != GST_FLOW_OK))
+      goto alloc_failed;
+
+    /* clear timestamp from alloc... */
+    GST_BUFFER_PTS (new_buffer) = -1;
+
+    if (!gst_video_frame_map (&rtpvrawdepay->frame, &rtpvrawdepay->vinfo,
+            new_buffer, GST_MAP_WRITE | GST_VIDEO_FRAME_MAP_FLAG_NO_REF)) {
+      gst_buffer_unref (new_buffer);
+      goto invalid_frame;
+    }
+
+    rtpvrawdepay->outbuf = new_buffer;
+    rtpvrawdepay->timestamp = timestamp;
+  }
+
+  frame = &rtpvrawdepay->frame;
+
+  g_assert (frame->buffer != NULL);
+
+  /* get pointer and strides of the planes */
+  p0 = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  yp = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
+  up = GST_VIDEO_FRAME_COMP_DATA (frame, 1);
+  vp = GST_VIDEO_FRAME_COMP_DATA (frame, 2);
+
+  ystride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
+  uvstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1);
+
+  pgroup = rtpvrawdepay->pgroup;
+  width = GST_VIDEO_INFO_WIDTH (&rtpvrawdepay->vinfo);
+  height = GST_VIDEO_INFO_HEIGHT (&rtpvrawdepay->vinfo);
+  xinc = rtpvrawdepay->xinc;
+  yinc = rtpvrawdepay->yinc;
+
+  payload = gst_rtp_buffer_get_payload (rtp);
+  payload_len = gst_rtp_buffer_get_payload_len (rtp);
+
+  if (payload_len < 3)
+    goto short_packet;
+
+  /* skip extended seqnum */
+  payload += 2;
+  payload_len -= 2;
+
+  /* remember header position */
+  headers = payload;
+
+  gst_rtp_copy_video_meta (rtpvrawdepay, frame->buffer, rtp->buffer);
+
+  /* find data start */
+  do {
+    if (payload_len < 6)
+      goto short_packet;
+
+    cont = payload[4] & 0x80;
+
+    payload += 6;
+    payload_len -= 6;
+  } while (cont);
+
+  while (TRUE) {
+    guint length, line, offs, plen;
+    guint8 *datap;
+
+    /* stop when we run out of data */
+    if (payload_len == 0)
+      break;
+
+    /* read length and cont. This should work because we iterated the headers
+     * above. */
+    length = (headers[0] << 8) | headers[1];
+    line = ((headers[2] & 0x7f) << 8) | headers[3];
+    offs = ((headers[4] & 0x7f) << 8) | headers[5];
+    cont = headers[4] & 0x80;
+    headers += 6;
+
+    /* length must be a multiple of pgroup */
+    if (length % pgroup != 0)
+      goto wrong_length;
+
+    if (length > payload_len)
+      length = payload_len;
+
+    /* sanity check */
+    if (line > (height - yinc)) {
+      GST_WARNING_OBJECT (depayload, "skipping line %d: out of range", line);
+      goto next;
+    }
+    if (offs > (width - xinc)) {
+      GST_WARNING_OBJECT (depayload, "skipping offset %d: out of range", offs);
+      goto next;
+    }
+
+    /* calculate the maximim amount of bytes we can use per line */
+    if (offs + ((length / pgroup) * xinc) > width) {
+      plen = ((width - offs) * pgroup) / xinc;
+      GST_WARNING_OBJECT (depayload, "clipping length %d, offset %d, plen %d",
+          length, offs, plen);
+    } else
+      plen = length;
+
+    GST_LOG_OBJECT (depayload,
+        "writing length %u/%u, line %u, offset %u, remaining %u", plen, length,
+        line, offs, payload_len);
+
+    switch (GST_VIDEO_INFO_FORMAT (&rtpvrawdepay->vinfo)) {
+      case GST_VIDEO_FORMAT_RGB:
+      case GST_VIDEO_FORMAT_RGBA:
+      case GST_VIDEO_FORMAT_BGR:
+      case GST_VIDEO_FORMAT_BGRA:
+      case GST_VIDEO_FORMAT_UYVY:
+      case GST_VIDEO_FORMAT_UYVP:
+        /* samples are packed just like gstreamer packs them */
+        offs /= xinc;
+        datap = p0 + (line * ystride) + (offs * pgroup);
+
+        memcpy (datap, payload, plen);
+        break;
+      case GST_VIDEO_FORMAT_AYUV:
+      {
+        gint i;
+        guint8 *p;
+
+        datap = p0 + (line * ystride) + (offs * 4);
+        p = payload;
+
+        /* samples are packed in order Cb-Y-Cr for both interlaced and
+         * progressive frames */
+        for (i = 0; i < plen; i += pgroup) {
+          *datap++ = 0;
+          *datap++ = p[1];
+          *datap++ = p[0];
+          *datap++ = p[2];
+          p += pgroup;
+        }
+        break;
+      }
+      case GST_VIDEO_FORMAT_I420:
+      {
+        gint i;
+        guint uvoff;
+        guint8 *yd1p, *yd2p, *udp, *vdp, *p;
+
+        yd1p = yp + (line * ystride) + (offs);
+        yd2p = yd1p + ystride;
+        uvoff = (line / yinc * uvstride) + (offs / xinc);
+
+        udp = up + uvoff;
+        vdp = vp + uvoff;
+        p = payload;
+
+        /* line 0/1: Y00-Y01-Y10-Y11-Cb00-Cr00 Y02-Y03-Y12-Y13-Cb01-Cr01 ...  */
+        for (i = 0; i < plen; i += pgroup) {
+          *yd1p++ = p[0];
+          *yd1p++ = p[1];
+          *yd2p++ = p[2];
+          *yd2p++ = p[3];
+          *udp++ = p[4];
+          *vdp++ = p[5];
+          p += pgroup;
+        }
+        break;
+      }
+      case GST_VIDEO_FORMAT_Y41B:
+      {
+        gint i;
+        guint uvoff;
+        guint8 *ydp, *udp, *vdp, *p;
+
+        ydp = yp + (line * ystride) + (offs);
+        uvoff = (line / yinc * uvstride) + (offs / xinc);
+
+        udp = up + uvoff;
+        vdp = vp + uvoff;
+        p = payload;
+
+        /* Samples are packed in order Cb0-Y0-Y1-Cr0-Y2-Y3 for both interlaced
+         * and progressive scan lines */
+        for (i = 0; i < plen; i += pgroup) {
+          *udp++ = p[0];
+          *ydp++ = p[1];
+          *ydp++ = p[2];
+          *vdp++ = p[3];
+          *ydp++ = p[4];
+          *ydp++ = p[5];
+          p += pgroup;
+        }
+        break;
+      }
+      default:
+        goto unknown_sampling;
+    }
+
+  next:
+    if (!cont)
+      break;
+
+    payload += length;
+    payload_len -= length;
+  }
+
+  marker = gst_rtp_buffer_get_marker (rtp);
+
+  if (marker) {
+    GST_LOG_OBJECT (depayload, "marker, flushing frame");
+    gst_video_frame_unmap (&rtpvrawdepay->frame);
+    outbuf = rtpvrawdepay->outbuf;
+    rtpvrawdepay->outbuf = NULL;
+    rtpvrawdepay->timestamp = -1;
+  }
+  return outbuf;
+
+  /* ERRORS */
+unknown_sampling:
+  {
+    GST_ELEMENT_ERROR (depayload, STREAM, FORMAT,
+        (NULL), ("unimplemented sampling"));
+    return NULL;
+  }
+alloc_failed:
+  {
+    GST_WARNING_OBJECT (depayload, "failed to alloc output buffer");
+    return NULL;
+  }
+invalid_frame:
+  {
+    GST_ERROR_OBJECT (depayload, "could not map video frame");
+    return NULL;
+  }
+wrong_length:
+  {
+    GST_WARNING_OBJECT (depayload, "length not multiple of pgroup");
+    return NULL;
+  }
+short_packet:
+  {
+    GST_WARNING_OBJECT (depayload, "short packet");
+    return NULL;
+  }
+}
+
+static gboolean
+gst_rtp_vraw_depay_handle_event (GstRTPBaseDepayload * filter, GstEvent * event)
+{
+  gboolean ret;
+  GstRtpVRawDepay *rtpvrawdepay;
+
+  rtpvrawdepay = GST_RTP_VRAW_DEPAY (filter);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      gst_rtp_vraw_depay_reset (rtpvrawdepay);
+      break;
+    default:
+      break;
+  }
+
+  ret =
+      GST_RTP_BASE_DEPAYLOAD_CLASS (parent_class)->handle_event (filter, event);
+
+  return ret;
+}
+
+static GstStateChangeReturn
+gst_rtp_vraw_depay_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpVRawDepay *rtpvrawdepay;
+  GstStateChangeReturn ret;
+
+  rtpvrawdepay = GST_RTP_VRAW_DEPAY (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_vraw_depay_reset (rtpvrawdepay);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_vraw_depay_reset (rtpvrawdepay);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_rtp_vraw_depay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpvrawdepay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_VRAW_DEPAY);
+}
diff --git a/gst/rtp/gstrtpvrawdepay.h b/gst/rtp/gstrtpvrawdepay.h
new file mode 100644
index 0000000..18ca755
--- /dev/null
+++ b/gst/rtp/gstrtpvrawdepay.h
@@ -0,0 +1,71 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_VRAW_DEPAY_H__
+#define __GST_RTP_VRAW_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideometa.h>
+#include <gst/video/gstvideopool.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_VRAW_DEPAY \
+  (gst_rtp_vraw_depay_get_type())
+#define GST_RTP_VRAW_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_VRAW_DEPAY,GstRtpVRawDepay))
+#define GST_RTP_VRAW_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_VRAW_DEPAY,GstRtpVRawDepayClass))
+#define GST_IS_RTP_VRAW_DEPAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_VRAW_DEPAY))
+#define GST_IS_RTP_VRAW_DEPAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_VRAW_DEPAY))
+
+typedef struct _GstRtpVRawDepay GstRtpVRawDepay;
+typedef struct _GstRtpVRawDepayClass GstRtpVRawDepayClass;
+
+struct _GstRtpVRawDepay
+{
+  GstRTPBaseDepayload payload;
+
+  GstBufferPool *pool;
+  GstVideoInfo vinfo;
+
+  GstVideoFrame frame;
+  GstBuffer *outbuf;
+  guint32 timestamp;
+
+  gint pgroup;
+  gint xinc, yinc;
+};
+
+struct _GstRtpVRawDepayClass
+{
+  GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_vraw_depay_get_type (void);
+
+gboolean gst_rtp_vraw_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_VRAW_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpvrawpay.c b/gst/rtp/gstrtpvrawpay.c
new file mode 100644
index 0000000..50a4820
--- /dev/null
+++ b/gst/rtp/gstrtpvrawpay.c
@@ -0,0 +1,654 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
+
+#include "gstrtpvrawpay.h"
+#include "gstrtputils.h"
+
+enum
+{
+  PROP_CHUNKS_PER_FRAME = 1
+};
+
+#define DEFAULT_CHUNKS_PER_FRAME 10
+
+GST_DEBUG_CATEGORY_STATIC (rtpvrawpay_debug);
+#define GST_CAT_DEFAULT (rtpvrawpay_debug)
+
+static GstStaticPadTemplate gst_rtp_vraw_pay_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-raw, "
+        "format = (string) { RGB, RGBA, BGR, BGRA, AYUV, UYVY, I420, Y41B, UYVP }, "
+        "width = (int) [ 1, 32767 ], " "height = (int) [ 1, 32767 ]; ")
+    );
+
+static GstStaticPadTemplate gst_rtp_vraw_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"video\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 90000, "
+        "encoding-name = (string) \"RAW\","
+        "sampling = (string) { \"RGB\", \"RGBA\", \"BGR\", \"BGRA\", "
+        "\"YCbCr-4:4:4\", \"YCbCr-4:2:2\", \"YCbCr-4:2:0\", "
+        "\"YCbCr-4:1:1\" },"
+        /* we cannot express these as strings 
+         * "width = (string) [1 32767],"
+         * "height = (string) [1 32767],"
+         */
+        "depth = (string) { \"8\", \"10\", \"12\", \"16\" },"
+        "colorimetry = (string) { \"BT601-5\", \"BT709-2\", \"SMPTE240M\" }"
+        /* optional 
+         * interlace = 
+         * top-field-first = 
+         * chroma-position = (string) 
+         * gamma = (float)
+         */
+    )
+    );
+
+static gboolean gst_rtp_vraw_pay_setcaps (GstRTPBasePayload * payload,
+    GstCaps * caps);
+static GstFlowReturn gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload *
+    payload, GstBuffer * buffer);
+static void gst_rtp_vraw_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_rtp_vraw_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+
+G_DEFINE_TYPE (GstRtpVRawPay, gst_rtp_vraw_pay, GST_TYPE_RTP_BASE_PAYLOAD)
+
+     static void gst_rtp_vraw_pay_class_init (GstRtpVRawPayClass * klass)
+{
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
+  GstElementClass *gstelement_class;
+  GObjectClass *gobject_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+  gobject_class->set_property = gst_rtp_vraw_pay_set_property;
+  gobject_class->get_property = gst_rtp_vraw_pay_get_property;
+
+  g_object_class_install_property (gobject_class,
+      PROP_CHUNKS_PER_FRAME,
+      g_param_spec_int ("chunks-per-frame", "Chunks per Frame",
+          "Split and send out each frame in multiple chunks to reduce overhead",
+          1, G_MAXINT, DEFAULT_CHUNKS_PER_FRAME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
+  gstrtpbasepayload_class->set_caps = gst_rtp_vraw_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_vraw_pay_handle_buffer;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_vraw_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_vraw_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Raw Video payloader", "Codec/Payloader/Network/RTP",
+      "Payload raw video as RTP packets (RFC 4175)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (rtpvrawpay_debug, "rtpvrawpay", 0,
+      "Raw video RTP Payloader");
+}
+
+static void
+gst_rtp_vraw_pay_init (GstRtpVRawPay * rtpvrawpay)
+{
+  rtpvrawpay->chunks_per_frame = DEFAULT_CHUNKS_PER_FRAME;
+}
+
+static gboolean
+gst_rtp_vraw_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+  GstRtpVRawPay *rtpvrawpay;
+  gboolean res;
+  gint pgroup, xinc, yinc;
+  const gchar *depthstr, *samplingstr, *colorimetrystr;
+  gchar *wstr, *hstr;
+  GstVideoInfo info;
+
+  rtpvrawpay = GST_RTP_VRAW_PAY (payload);
+
+  if (!gst_video_info_from_caps (&info, caps))
+    goto invalid_caps;
+
+  rtpvrawpay->vinfo = info;
+
+  if (gst_video_colorimetry_matches (&info.colorimetry,
+          GST_VIDEO_COLORIMETRY_BT601)) {
+    colorimetrystr = "BT601-5";
+  } else if (gst_video_colorimetry_matches (&info.colorimetry,
+          GST_VIDEO_COLORIMETRY_BT709)) {
+    colorimetrystr = "BT709-2";
+  } else if (gst_video_colorimetry_matches (&info.colorimetry,
+          GST_VIDEO_COLORIMETRY_SMPTE240M)) {
+    colorimetrystr = "SMPTE240M";
+  } else {
+    colorimetrystr = "SMPTE240M";
+  }
+
+  xinc = yinc = 1;
+
+  /* these values are the only thing we can do */
+  depthstr = "8";
+
+  switch (GST_VIDEO_INFO_FORMAT (&info)) {
+    case GST_VIDEO_FORMAT_RGBA:
+      samplingstr = "RGBA";
+      pgroup = 4;
+      break;
+    case GST_VIDEO_FORMAT_BGRA:
+      samplingstr = "BGRA";
+      pgroup = 4;
+      break;
+    case GST_VIDEO_FORMAT_RGB:
+      samplingstr = "RGB";
+      pgroup = 3;
+      break;
+    case GST_VIDEO_FORMAT_BGR:
+      samplingstr = "BGR";
+      pgroup = 3;
+      break;
+    case GST_VIDEO_FORMAT_AYUV:
+      samplingstr = "YCbCr-4:4:4";
+      pgroup = 3;
+      break;
+    case GST_VIDEO_FORMAT_UYVY:
+      samplingstr = "YCbCr-4:2:2";
+      pgroup = 4;
+      xinc = 2;
+      break;
+    case GST_VIDEO_FORMAT_Y41B:
+      samplingstr = "YCbCr-4:1:1";
+      pgroup = 6;
+      xinc = 4;
+      break;
+    case GST_VIDEO_FORMAT_I420:
+      samplingstr = "YCbCr-4:2:0";
+      pgroup = 6;
+      xinc = yinc = 2;
+      break;
+    case GST_VIDEO_FORMAT_UYVP:
+      samplingstr = "YCbCr-4:2:2";
+      pgroup = 5;
+      xinc = 2;
+      depthstr = "10";
+      break;
+    default:
+      goto unknown_format;
+      break;
+  }
+
+  if (GST_VIDEO_INFO_IS_INTERLACED (&info)) {
+    yinc *= 2;
+  }
+
+  rtpvrawpay->pgroup = pgroup;
+  rtpvrawpay->xinc = xinc;
+  rtpvrawpay->yinc = yinc;
+
+  GST_DEBUG_OBJECT (payload, "width %d, height %d, sampling %s",
+      GST_VIDEO_INFO_WIDTH (&info), GST_VIDEO_INFO_HEIGHT (&info), samplingstr);
+  GST_DEBUG_OBJECT (payload, "xinc %d, yinc %d, pgroup %d", xinc, yinc, pgroup);
+
+  wstr = g_strdup_printf ("%d", GST_VIDEO_INFO_WIDTH (&info));
+  hstr = g_strdup_printf ("%d", GST_VIDEO_INFO_HEIGHT (&info));
+
+  gst_rtp_base_payload_set_options (payload, "video", TRUE, "RAW", 90000);
+  if (GST_VIDEO_INFO_IS_INTERLACED (&info)) {
+    res = gst_rtp_base_payload_set_outcaps (payload, "sampling", G_TYPE_STRING,
+        samplingstr, "depth", G_TYPE_STRING, depthstr, "width", G_TYPE_STRING,
+        wstr, "height", G_TYPE_STRING, hstr, "colorimetry", G_TYPE_STRING,
+        colorimetrystr, "interlace", G_TYPE_STRING, "true", NULL);
+  } else {
+    res = gst_rtp_base_payload_set_outcaps (payload, "sampling", G_TYPE_STRING,
+        samplingstr, "depth", G_TYPE_STRING, depthstr, "width", G_TYPE_STRING,
+        wstr, "height", G_TYPE_STRING, hstr, "colorimetry", G_TYPE_STRING,
+        colorimetrystr, NULL);
+  }
+  g_free (wstr);
+  g_free (hstr);
+
+  return res;
+
+  /* ERRORS */
+invalid_caps:
+  {
+    GST_ERROR_OBJECT (payload, "could not parse caps");
+    return FALSE;
+  }
+unknown_format:
+  {
+    GST_ERROR_OBJECT (payload, "unknown caps format");
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
+{
+  GstRtpVRawPay *rtpvrawpay;
+  GstFlowReturn ret = GST_FLOW_OK;
+  gfloat packets_per_packline;
+  guint pgroups_per_packet;
+  guint packlines_per_list, buffers_per_list;
+  guint lines_delay;            /* after how many packed lines we push out a buffer list */
+  guint last_line;              /* last pack line number we pushed out a buffer list     */
+  guint line, offset;
+  guint8 *p0, *yp, *up, *vp;
+  guint ystride, uvstride;
+  guint xinc, yinc;
+  guint pgroup;
+  guint mtu;
+  guint width, height;
+  gint field, fields;
+  GstVideoFormat format;
+  GstVideoFrame frame;
+  gint interlaced;
+  gboolean use_buffer_lists;
+  GstBufferList *list = NULL;
+  GstRTPBuffer rtp = { NULL, };
+
+  rtpvrawpay = GST_RTP_VRAW_PAY (payload);
+
+  if (!gst_video_frame_map (&frame, &rtpvrawpay->vinfo, buffer, GST_MAP_READ)) {
+    gst_buffer_unref (buffer);
+    return GST_FLOW_ERROR;
+  }
+
+  GST_LOG_OBJECT (rtpvrawpay, "new frame of %" G_GSIZE_FORMAT " bytes",
+      gst_buffer_get_size (buffer));
+
+  /* get pointer and strides of the planes */
+  p0 = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0);
+  yp = GST_VIDEO_FRAME_COMP_DATA (&frame, 0);
+  up = GST_VIDEO_FRAME_COMP_DATA (&frame, 1);
+  vp = GST_VIDEO_FRAME_COMP_DATA (&frame, 2);
+
+  ystride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0);
+  uvstride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 1);
+
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (payload);
+
+  /* amount of bytes for one pixel */
+  pgroup = rtpvrawpay->pgroup;
+  width = GST_VIDEO_INFO_WIDTH (&rtpvrawpay->vinfo);
+  height = GST_VIDEO_INFO_HEIGHT (&rtpvrawpay->vinfo);
+
+  interlaced = GST_VIDEO_INFO_IS_INTERLACED (&rtpvrawpay->vinfo);
+
+  format = GST_VIDEO_INFO_FORMAT (&rtpvrawpay->vinfo);
+
+  yinc = rtpvrawpay->yinc;
+  xinc = rtpvrawpay->xinc;
+
+  /* after how many packed lines we push out a buffer list */
+  lines_delay = GST_ROUND_UP_4 (height / rtpvrawpay->chunks_per_frame);
+
+  /* calculate how many buffers we expect to store in a single buffer list */
+  pgroups_per_packet = (mtu - (12 + 14)) / pgroup;
+  packets_per_packline = width / (xinc * pgroups_per_packet * 1.0);
+  packlines_per_list = height / (yinc * rtpvrawpay->chunks_per_frame);
+  buffers_per_list = packlines_per_list * packets_per_packline;
+  buffers_per_list = GST_ROUND_UP_8 (buffers_per_list);
+
+  use_buffer_lists = (rtpvrawpay->chunks_per_frame < (height / yinc));
+
+  fields = 1 + interlaced;
+
+  /* start with line 0, offset 0 */
+  for (field = 0; field < fields; field++) {
+    line = field;
+    offset = 0;
+    last_line = 0;
+
+    if (use_buffer_lists)
+      list = gst_buffer_list_new_sized (buffers_per_list);
+
+    /* write all lines */
+    while (line < height) {
+      guint left, pack_line;
+      GstBuffer *out;
+      guint8 *outdata, *headers;
+      gboolean next_line, complete = FALSE;
+      guint length, cont, pixels;
+
+      /* get the max allowed payload length size, we try to fill the complete MTU */
+      left = gst_rtp_buffer_calc_payload_len (mtu, 0, 0);
+      out = gst_rtp_buffer_new_allocate (left, 0, 0);
+
+      if (field == 0) {
+        GST_BUFFER_PTS (out) = GST_BUFFER_PTS (buffer);
+      } else {
+        GST_BUFFER_PTS (out) = GST_BUFFER_PTS (buffer) +
+            GST_BUFFER_DURATION (buffer) / 2;
+      }
+
+      gst_rtp_buffer_map (out, GST_MAP_WRITE, &rtp);
+      outdata = gst_rtp_buffer_get_payload (&rtp);
+
+      GST_LOG_OBJECT (rtpvrawpay, "created buffer of size %u for MTU %u", left,
+          mtu);
+
+      /*
+       *   0                   1                   2                   3
+       *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       *  |   Extended Sequence Number    |            Length             |
+       *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       *  |F|          Line No            |C|           Offset            |
+       *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       *  |            Length             |F|          Line No            |
+       *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       *  |C|           Offset            |                               .
+       *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               .
+       *  .                                                               .
+       *  .                 Two (partial) lines of video data             .
+       *  .                                                               .
+       *  +---------------------------------------------------------------+
+       */
+
+      /* need 2 bytes for the extended sequence number */
+      *outdata++ = 0;
+      *outdata++ = 0;
+      left -= 2;
+
+      /* the headers start here */
+      headers = outdata;
+
+      /* make sure we can fit at least *one* header and pixel */
+      if (!(left > (6 + pgroup))) {
+        gst_rtp_buffer_unmap (&rtp);
+        gst_buffer_unref (out);
+        goto too_small;
+      }
+
+      /* while we can fit at least one header and one pixel */
+      while (left > (6 + pgroup)) {
+        /* we need a 6 bytes header */
+        left -= 6;
+
+        /* get how may bytes we need for the remaining pixels */
+        pixels = width - offset;
+        length = (pixels * pgroup) / xinc;
+
+        if (left >= length) {
+          /* pixels and header fit completely, we will write them and skip to the
+           * next line. */
+          next_line = TRUE;
+        } else {
+          /* line does not fit completely, see how many pixels fit */
+          pixels = (left / pgroup) * xinc;
+          length = (pixels * pgroup) / xinc;
+          next_line = FALSE;
+        }
+        GST_LOG_OBJECT (rtpvrawpay, "filling %u bytes in %u pixels", length,
+            pixels);
+        left -= length;
+
+        /* write length */
+        *outdata++ = (length >> 8) & 0xff;
+        *outdata++ = length & 0xff;
+
+        /* write line no */
+        *outdata++ = ((line >> 8) & 0x7f) | ((field << 7) & 0x80);
+        *outdata++ = line & 0xff;
+
+        if (next_line) {
+          /* go to next line we do this here to make the check below easier */
+          line += yinc;
+        }
+
+        /* calculate continuation marker */
+        cont = (left > (6 + pgroup) && line < height) ? 0x80 : 0x00;
+
+        /* write offset and continuation marker */
+        *outdata++ = ((offset >> 8) & 0x7f) | cont;
+        *outdata++ = offset & 0xff;
+
+        if (next_line) {
+          /* reset offset */
+          offset = 0;
+          GST_LOG_OBJECT (rtpvrawpay, "go to next line %u", line);
+        } else {
+          offset += pixels;
+          GST_LOG_OBJECT (rtpvrawpay, "next offset %u", offset);
+        }
+
+        if (!cont)
+          break;
+      }
+      GST_LOG_OBJECT (rtpvrawpay, "consumed %u bytes",
+          (guint) (outdata - headers));
+
+      /* second pass, read headers and write the data */
+      while (TRUE) {
+        guint offs, lin;
+
+        /* read length and cont */
+        length = (headers[0] << 8) | headers[1];
+        lin = ((headers[2] & 0x7f) << 8) | headers[3];
+        offs = ((headers[4] & 0x7f) << 8) | headers[5];
+        cont = headers[4] & 0x80;
+        pixels = length / pgroup;
+        headers += 6;
+
+        GST_LOG_OBJECT (payload,
+            "writing length %u, line %u, offset %u, cont %d", length, lin, offs,
+            cont);
+
+        switch (format) {
+          case GST_VIDEO_FORMAT_RGB:
+          case GST_VIDEO_FORMAT_RGBA:
+          case GST_VIDEO_FORMAT_BGR:
+          case GST_VIDEO_FORMAT_BGRA:
+          case GST_VIDEO_FORMAT_UYVY:
+          case GST_VIDEO_FORMAT_UYVP:
+            offs /= xinc;
+            memcpy (outdata, p0 + (lin * ystride) + (offs * pgroup), length);
+            outdata += length;
+            break;
+          case GST_VIDEO_FORMAT_AYUV:
+          {
+            gint i;
+            guint8 *datap;
+
+            datap = p0 + (lin * ystride) + (offs * 4);
+
+            for (i = 0; i < pixels; i++) {
+              *outdata++ = datap[2];
+              *outdata++ = datap[1];
+              *outdata++ = datap[3];
+              datap += 4;
+            }
+            break;
+          }
+          case GST_VIDEO_FORMAT_I420:
+          {
+            gint i;
+            guint uvoff;
+            guint8 *yd1p, *yd2p, *udp, *vdp;
+
+            yd1p = yp + (lin * ystride) + (offs);
+            yd2p = yd1p + ystride;
+            uvoff = (lin / yinc * uvstride) + (offs / xinc);
+            udp = up + uvoff;
+            vdp = vp + uvoff;
+
+            for (i = 0; i < pixels; i++) {
+              *outdata++ = *yd1p++;
+              *outdata++ = *yd1p++;
+              *outdata++ = *yd2p++;
+              *outdata++ = *yd2p++;
+              *outdata++ = *udp++;
+              *outdata++ = *vdp++;
+            }
+            break;
+          }
+          case GST_VIDEO_FORMAT_Y41B:
+          {
+            gint i;
+            guint uvoff;
+            guint8 *ydp, *udp, *vdp;
+
+            ydp = yp + (lin * ystride) + offs;
+            uvoff = (lin / yinc * uvstride) + (offs / xinc);
+            udp = up + uvoff;
+            vdp = vp + uvoff;
+
+            for (i = 0; i < pixels; i++) {
+              *outdata++ = *udp++;
+              *outdata++ = *ydp++;
+              *outdata++ = *ydp++;
+              *outdata++ = *vdp++;
+              *outdata++ = *ydp++;
+              *outdata++ = *ydp++;
+            }
+            break;
+          }
+          default:
+            gst_rtp_buffer_unmap (&rtp);
+            gst_buffer_unref (out);
+            goto unknown_sampling;
+        }
+
+        if (!cont)
+          break;
+      }
+
+      if (line >= height) {
+        GST_LOG_OBJECT (rtpvrawpay, "field/frame complete, set marker");
+        gst_rtp_buffer_set_marker (&rtp, TRUE);
+        complete = TRUE;
+      }
+      gst_rtp_buffer_unmap (&rtp);
+      if (left > 0) {
+        GST_LOG_OBJECT (rtpvrawpay, "we have %u bytes left", left);
+        gst_buffer_resize (out, 0, gst_buffer_get_size (out) - left);
+      }
+
+      gst_rtp_copy_video_meta (rtpvrawpay, out, buffer);
+
+      /* Now either push out the buffer directly */
+      if (!use_buffer_lists) {
+        ret = gst_rtp_base_payload_push (payload, out);
+        continue;
+      }
+
+      /* or add the buffer to buffer list ... */
+      gst_buffer_list_add (list, out);
+
+      /* .. and check if we need to push out the list */
+      pack_line = (line - field) / fields;
+      if (complete || (pack_line > last_line && pack_line % lines_delay == 0)) {
+        GST_LOG_OBJECT (rtpvrawpay, "pushing list of %u buffers up to pack "
+            "line %u", gst_buffer_list_length (list), pack_line);
+        ret = gst_rtp_base_payload_push_list (payload, list);
+        list = NULL;
+        if (!complete)
+          list = gst_buffer_list_new_sized (buffers_per_list);
+        last_line = pack_line;
+      }
+    }
+
+  }
+
+  gst_video_frame_unmap (&frame);
+  gst_buffer_unref (buffer);
+
+  return ret;
+
+  /* ERRORS */
+unknown_sampling:
+  {
+    GST_ELEMENT_ERROR (payload, STREAM, FORMAT,
+        (NULL), ("unimplemented sampling"));
+    gst_video_frame_unmap (&frame);
+    gst_buffer_unref (buffer);
+    return GST_FLOW_NOT_SUPPORTED;
+  }
+too_small:
+  {
+    GST_ELEMENT_ERROR (payload, RESOURCE, NO_SPACE_LEFT,
+        (NULL), ("not enough space to send at least one pixel"));
+    gst_video_frame_unmap (&frame);
+    gst_buffer_unref (buffer);
+    return GST_FLOW_NOT_SUPPORTED;
+  }
+}
+
+static void
+gst_rtp_vraw_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpVRawPay *rtpvrawpay;
+
+  rtpvrawpay = GST_RTP_VRAW_PAY (object);
+
+  switch (prop_id) {
+    case PROP_CHUNKS_PER_FRAME:
+      rtpvrawpay->chunks_per_frame = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_vraw_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpVRawPay *rtpvrawpay;
+
+  rtpvrawpay = GST_RTP_VRAW_PAY (object);
+
+  switch (prop_id) {
+    case PROP_CHUNKS_PER_FRAME:
+      g_value_set_int (value, rtpvrawpay->chunks_per_frame);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+gboolean
+gst_rtp_vraw_pay_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rtpvrawpay",
+      GST_RANK_SECONDARY, GST_TYPE_RTP_VRAW_PAY);
+}
diff --git a/gst/rtp/gstrtpvrawpay.h b/gst/rtp/gstrtpvrawpay.h
new file mode 100644
index 0000000..3fd2442
--- /dev/null
+++ b/gst/rtp/gstrtpvrawpay.h
@@ -0,0 +1,67 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_VRAW_PAY_H__
+#define __GST_RTP_VRAW_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_VRAW_PAY \
+  (gst_rtp_vraw_pay_get_type())
+#define GST_RTP_VRAW_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_VRAW_PAY,GstRtpVRawPay))
+#define GST_RTP_VRAW_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_VRAW_PAY,GstRtpVRawPayClass))
+#define GST_IS_RTP_VRAW_PAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_VRAW_PAY))
+#define GST_IS_RTP_VRAW_PAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_VRAW_PAY))
+
+typedef struct _GstRtpVRawPay GstRtpVRawPay;
+typedef struct _GstRtpVRawPayClass GstRtpVRawPayClass;
+
+struct _GstRtpVRawPay
+{
+  GstRTPBasePayload payload;
+
+  GstVideoInfo vinfo;
+
+  gint pgroup;
+  gint xinc, yinc;
+
+  /* properties */
+  guint chunks_per_frame;
+};
+
+struct _GstRtpVRawPayClass
+{
+  GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_vraw_pay_get_type (void);
+
+gboolean gst_rtp_vraw_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_VRAW_PAY_H__ */
diff --git a/gst/rtp/meson.build b/gst/rtp/meson.build
new file mode 100644
index 0000000..6f24152
--- /dev/null
+++ b/gst/rtp/meson.build
@@ -0,0 +1,111 @@
+rtp_sources = [
+  'dboolhuff.c',
+  'fnv1hash.c',
+  'gstrtp.c',
+  'gstrtpchannels.c',
+  'gstrtpac3depay.c',
+  'gstrtpac3pay.c',
+  'gstrtpbvdepay.c',
+  'gstrtpbvpay.c',
+  'gstrtpceltdepay.c',
+  'gstrtpceltpay.c',
+  'gstrtpdvdepay.c',
+  'gstrtpdvpay.c',
+  'gstrtpgstdepay.c',
+  'gstrtpgstpay.c',
+  'gstrtpilbcdepay.c',
+  'gstrtpilbcpay.c',
+  'gstrtpklvdepay.c',
+  'gstrtpklvpay.c',
+  'gstrtpmpadepay.c',
+  'gstrtpmpapay.c',
+  'gstrtpmparobustdepay.c',
+  'gstrtpmpvdepay.c',
+  'gstrtpmpvpay.c',
+  'gstrtpopuspay.c',
+  'gstrtpopusdepay.c',
+  'gstrtppcmadepay.c',
+  'gstrtppcmudepay.c',
+  'gstrtppcmupay.c',
+  'gstrtppcmapay.c',
+  'gstrtpg722depay.c',
+  'gstrtpg722pay.c',
+  'gstrtpg723depay.c',
+  'gstrtpg723pay.c',
+  'gstrtpg726pay.c',
+  'gstrtpg726depay.c',
+  'gstrtpg729pay.c',
+  'gstrtpg729depay.c',
+  'gstrtpgsmdepay.c',
+  'gstrtpgsmpay.c',
+  'gstrtpamrdepay.c',
+  'gstrtpamrpay.c',
+  'gstrtph261depay.c',
+  'gstrtph261pay.c',
+  'gstrtph263pdepay.c',
+  'gstrtph263ppay.c',
+  'gstrtph263depay.c',
+  'gstrtph263pay.c',
+  'gstrtph264depay.c',
+  'gstrtph264pay.c',
+  'gstrtph265depay.c',
+  'gstrtph265pay.c',
+  'gstrtpj2kdepay.c',
+  'gstrtpj2kpay.c',
+  'gstrtpjpegdepay.c',
+  'gstrtpjpegpay.c',
+  'gstrtpL8depay.c',
+  'gstrtpL8pay.c',
+  'gstrtpL16depay.c',
+  'gstrtpL16pay.c',
+  'gstrtpL24depay.c',
+  'gstrtpL24pay.c',
+  'gstasteriskh263.c',
+  'gstrtpmp1sdepay.c',
+  'gstrtpmp2tdepay.c',
+  'gstrtpmp2tpay.c',
+  'gstrtpmp4vdepay.c',
+  'gstrtpmp4vpay.c',
+  'gstrtpmp4gdepay.c',
+  'gstrtpmp4gpay.c',
+  'gstrtpmp4adepay.c',
+  'gstrtpmp4apay.c',
+  'gstrtpqcelpdepay.c',
+  'gstrtpqdmdepay.c',
+  'gstrtpsbcdepay.c',
+  'gstrtpsbcpay.c',
+  'gstrtpsirenpay.c',
+  'gstrtpsirendepay.c',
+  'gstrtpspeexdepay.c',
+  'gstrtpspeexpay.c',
+  'gstrtpsv3vdepay.c',
+  'gstrtptheoradepay.c',
+  'gstrtptheorapay.c',
+  'gstrtpvorbisdepay.c',
+  'gstrtpvorbispay.c',
+  'gstrtpvp8depay.c',
+  'gstrtpvp8pay.c',
+  'gstrtpvp9depay.c',
+  'gstrtpvp9pay.c',
+  'gstrtpvrawdepay.c',
+  'gstrtpvrawpay.c',
+  'gstrtpstreampay.c',
+  'gstrtpstreamdepay.c',
+  'gstrtputils.c',
+]
+
+rtp_args = [
+  '-Dvp8_norm=gst_rtpvp8_vp8_norm',
+  '-Dvp8dx_start_decode=gst_rtpvp8_vp8dx_start_decode',
+  '-Dvp8dx_bool_decoder_fill=gst_rtpvp8_vp8dx_bool_decoder_fill',
+]
+
+gstrtp = library('gstrtp',
+  rtp_sources,
+  c_args : gst_plugins_good_args + rtp_args,
+  include_directories : [configinc],
+  dependencies : [gstbase_dep, gstaudio_dep, gstvideo_dep, gsttag_dep,
+                  gstrtp_dep, gstpbutils_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/rtpmanager/Makefile.am b/gst/rtpmanager/Makefile.am
new file mode 100644
index 0000000..598e61f
--- /dev/null
+++ b/gst/rtpmanager/Makefile.am
@@ -0,0 +1,39 @@
+plugin_LTLIBRARIES = libgstrtpmanager.la
+
+libgstrtpmanager_la_SOURCES = gstrtpmanager.c \
+			      gstrtpbin.c \
+			      gstrtpdtmfmux.c \
+			      gstrtpjitterbuffer.c \
+			      gstrtpmux.c \
+			      gstrtpptdemux.c \
+			      gstrtprtxqueue.c \
+			      gstrtprtxreceive.c \
+			      gstrtprtxsend.c \
+			      gstrtpssrcdemux.c \
+			      rtpjitterbuffer.c      \
+			      rtpsession.c      \
+			      rtpsource.c      \
+			      rtpstats.c      \
+			      gstrtpsession.c
+
+noinst_HEADERS = gstrtpbin.h \
+		 gstrtpdtmfmux.h \
+		 gstrtpjitterbuffer.h \
+		 gstrtpmux.h \
+                 gstrtpptdemux.h \
+                 gstrtpssrcdemux.h \
+                 gstrtprtxqueue.h \
+                 gstrtprtxreceive.h \
+                 gstrtprtxsend.h \
+                 rtpjitterbuffer.h \
+		 rtpsession.h  \
+		 rtpsource.h  \
+		 rtpstats.h  \
+		 gstrtpsession.h
+
+libgstrtpmanager_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \
+	$(GST_NET_CFLAGS) $(WARNING_CFLAGS) $(ERROR_CFLAGS)
+libgstrtpmanager_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+	$(GST_NET_LIBS) -lgstrtp-@GST_API_VERSION@ \
+	$(GST_BASE_LIBS) $(GST_LIBS)
+libgstrtpmanager_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c
new file mode 100644
index 0000000..d848711
--- /dev/null
+++ b/gst/rtpmanager/gstrtpbin.c
@@ -0,0 +1,4572 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpbin
+ * @see_also: rtpjitterbuffer, rtpsession, rtpptdemux, rtpssrcdemux
+ *
+ * RTP bin combines the functions of #GstRtpSession, #GstRtpSsrcDemux,
+ * #GstRtpJitterBuffer and #GstRtpPtDemux in one element. It allows for multiple
+ * RTP sessions that will be synchronized together using RTCP SR packets.
+ *
+ * #GstRtpBin is configured with a number of request pads that define the
+ * functionality that is activated, similar to the #GstRtpSession element.
+ *
+ * To use #GstRtpBin as an RTP receiver, request a recv_rtp_sink_\%u pad. The session
+ * number must be specified in the pad name.
+ * Data received on the recv_rtp_sink_\%u pad will be processed in the #GstRtpSession
+ * manager and after being validated forwarded on #GstRtpSsrcDemux element. Each
+ * RTP stream is demuxed based on the SSRC and send to a #GstRtpJitterBuffer. After
+ * the packets are released from the jitterbuffer, they will be forwarded to a
+ * #GstRtpPtDemux element. The #GstRtpPtDemux element will demux the packets based
+ * on the payload type and will create a unique pad recv_rtp_src_\%u_\%u_\%u on
+ * rtpbin with the session number, SSRC and payload type respectively as the pad
+ * name.
+ *
+ * To also use #GstRtpBin as an RTCP receiver, request a recv_rtcp_sink_\%u pad. The
+ * session number must be specified in the pad name.
+ *
+ * If you want the session manager to generate and send RTCP packets, request
+ * the send_rtcp_src_\%u pad with the session number in the pad name. Packet pushed
+ * on this pad contain SR/RR RTCP reports that should be sent to all participants
+ * in the session.
+ *
+ * To use #GstRtpBin as a sender, request a send_rtp_sink_\%u pad, which will
+ * automatically create a send_rtp_src_\%u pad. If the session number is not provided,
+ * the pad from the lowest available session will be returned. The session manager will modify the
+ * SSRC in the RTP packets to its own SSRC and wil forward the packets on the
+ * send_rtp_src_\%u pad after updating its internal state.
+ *
+ * #GstRtpBin can also demultiplex incoming bundled streams. The first
+ * #GstRtpSession will have a #GstRtpSsrcDemux element splitting the streams
+ * based on their SSRC and potentially dispatched to a different #GstRtpSession.
+ * Because retransmission SSRCs need to be merged with the corresponding media
+ * stream the #GstRtpBin::on-bundled-ssrc signal is emitted so that the
+ * application can find out to which session the SSRC belongs.
+ *
+ * The session manager needs the clock-rate of the payload types it is handling
+ * and will signal the #GstRtpSession::request-pt-map signal when it needs such a
+ * mapping. One can clear the cached values with the #GstRtpSession::clear-pt-map
+ * signal.
+ *
+ * Access to the internal statistics of rtpbin is provided with the
+ * get-internal-session property. This action signal gives access to the
+ * RTPSession object which further provides action signals to retrieve the
+ * internal source and other sources.
+ *
+ * #GstRtpBin also has signals (#GstRtpBin::request-rtp-encoder,
+ * #GstRtpBin::request-rtp-decoder, #GstRtpBin::request-rtcp-encoder and
+ * #GstRtpBin::request-rtp-decoder) to dynamically request for RTP and RTCP encoders
+ * and decoders in order to support SRTP. The encoders must provide the pads
+ * rtp_sink_\%u and rtp_src_\%u for RTP and rtcp_sink_\%u and rtcp_src_\%u for
+ * RTCP. The session number will be used in the pad name. The decoders must provide
+ * rtp_sink and rtp_src for RTP and rtcp_sink and rtcp_src for RTCP. The decoders will
+ * be placed before the #GstRtpSession element, thus they must support SSRC demuxing
+ * internally.
+ *
+ * #GstRtpBin has signals (#GstRtpBin::request-aux-sender and
+ * #GstRtpBin::request-aux-receiver to dynamically request an element that can be
+ * used to create or merge additional RTP streams. AUX elements are needed to
+ * implement FEC or retransmission (such as RFC 4588). An AUX sender must have one
+ * sink_\%u pad that matches the sessionid in the signal and it should have 1 or
+ * more src_\%u pads. For each src_%\u pad, a session will be made (if needed)
+ * and the pad will be linked to the session send_rtp_sink pad. Each session will
+ * then expose its source pad as send_rtp_src_\%u on #GstRtpBin.
+ * An AUX receiver has 1 src_\%u pad that much match the sessionid in the signal
+ * and 1 or more sink_\%u pads. A session will be made for each sink_\%u pad
+ * when the corresponding recv_rtp_sink_\%u pad is requested on #GstRtpBin.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 udpsrc port=5000 caps="application/x-rtp, ..." ! .recv_rtp_sink_0 \
+ *     rtpbin ! rtptheoradepay ! theoradec ! xvimagesink
+ * ]| Receive RTP data from port 5000 and send to the session 0 in rtpbin.
+ * |[
+ * gst-launch-1.0 rtpbin name=rtpbin \
+ *         v4l2src ! videoconvert ! ffenc_h263 ! rtph263ppay ! rtpbin.send_rtp_sink_0 \
+ *                   rtpbin.send_rtp_src_0 ! udpsink port=5000                            \
+ *                   rtpbin.send_rtcp_src_0 ! udpsink port=5001 sync=false async=false    \
+ *                   udpsrc port=5005 ! rtpbin.recv_rtcp_sink_0                           \
+ *         audiotestsrc ! amrnbenc ! rtpamrpay ! rtpbin.send_rtp_sink_1                   \
+ *                   rtpbin.send_rtp_src_1 ! udpsink port=5002                            \
+ *                   rtpbin.send_rtcp_src_1 ! udpsink port=5003 sync=false async=false    \
+ *                   udpsrc port=5007 ! rtpbin.recv_rtcp_sink_1
+ * ]| Encode and payload H263 video captured from a v4l2src. Encode and payload AMR
+ * audio generated from audiotestsrc. The video is sent to session 0 in rtpbin
+ * and the audio is sent to session 1. Video packets are sent on UDP port 5000
+ * and audio packets on port 5002. The video RTCP packets for session 0 are sent
+ * on port 5001 and the audio RTCP packets for session 0 are sent on port 5003.
+ * RTCP packets for session 0 are received on port 5005 and RTCP for session 1
+ * is received on port 5007. Since RTCP packets from the sender should be sent
+ * as soon as possible and do not participate in preroll, sync=false and
+ * async=false is configured on udpsink
+ * |[
+ * gst-launch-1.0 -v rtpbin name=rtpbin                                          \
+ *     udpsrc caps="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H263-1998" \
+ *             port=5000 ! rtpbin.recv_rtp_sink_0                                \
+ *         rtpbin. ! rtph263pdepay ! ffdec_h263 ! xvimagesink                    \
+ *      udpsrc port=5001 ! rtpbin.recv_rtcp_sink_0                               \
+ *      rtpbin.send_rtcp_src_0 ! udpsink port=5005 sync=false async=false        \
+ *     udpsrc caps="application/x-rtp,media=(string)audio,clock-rate=(int)8000,encoding-name=(string)AMR,encoding-params=(string)1,octet-align=(string)1" \
+ *             port=5002 ! rtpbin.recv_rtp_sink_1                                \
+ *         rtpbin. ! rtpamrdepay ! amrnbdec ! alsasink                           \
+ *      udpsrc port=5003 ! rtpbin.recv_rtcp_sink_1                               \
+ *      rtpbin.send_rtcp_src_1 ! udpsink port=5007 sync=false async=false
+ * ]| Receive H263 on port 5000, send it through rtpbin in session 0, depayload,
+ * decode and display the video.
+ * Receive AMR on port 5002, send it through rtpbin in session 1, depayload,
+ * decode and play the audio.
+ * Receive server RTCP packets for session 0 on port 5001 and RTCP packets for
+ * session 1 on port 5003. These packets will be used for session management and
+ * synchronisation.
+ * Send RTCP reports for session 0 on port 5005 and RTCP reports for session 1
+ * on port 5007.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdio.h>
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/rtp/gstrtcpbuffer.h>
+
+#include "gstrtpbin.h"
+#include "rtpsession.h"
+#include "gstrtpsession.h"
+#include "gstrtpjitterbuffer.h"
+
+#include <gst/glib-compat-private.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_bin_debug);
+#define GST_CAT_DEFAULT gst_rtp_bin_debug
+
+/* sink pads */
+static GstStaticPadTemplate rtpbin_recv_rtp_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("application/x-rtp;application/x-srtp")
+    );
+
+static GstStaticPadTemplate rtpbin_recv_rtcp_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("application/x-rtcp;application/x-srtcp")
+    );
+
+static GstStaticPadTemplate rtpbin_send_rtp_sink_template =
+GST_STATIC_PAD_TEMPLATE ("send_rtp_sink_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+/* src pads */
+static GstStaticPadTemplate rtpbin_recv_rtp_src_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%u_%u_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static GstStaticPadTemplate rtpbin_send_rtcp_src_template =
+    GST_STATIC_PAD_TEMPLATE ("send_rtcp_src_%u",
+    GST_PAD_SRC,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("application/x-rtcp;application/x-srtcp")
+    );
+
+static GstStaticPadTemplate rtpbin_send_rtp_src_template =
+    GST_STATIC_PAD_TEMPLATE ("send_rtp_src_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("application/x-rtp;application/x-srtp")
+    );
+
+#define GST_RTP_BIN_GET_PRIVATE(obj)  \
+   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTP_BIN, GstRtpBinPrivate))
+
+#define GST_RTP_BIN_LOCK(bin)   g_mutex_lock (&(bin)->priv->bin_lock)
+#define GST_RTP_BIN_UNLOCK(bin) g_mutex_unlock (&(bin)->priv->bin_lock)
+
+/* lock to protect dynamic callbacks, like pad-added and new ssrc. */
+#define GST_RTP_BIN_DYN_LOCK(bin)    g_mutex_lock (&(bin)->priv->dyn_lock)
+#define GST_RTP_BIN_DYN_UNLOCK(bin)  g_mutex_unlock (&(bin)->priv->dyn_lock)
+
+/* lock for shutdown */
+#define GST_RTP_BIN_SHUTDOWN_LOCK(bin,label)     \
+G_STMT_START {                                   \
+  if (g_atomic_int_get (&bin->priv->shutdown))   \
+    goto label;                                  \
+  GST_RTP_BIN_DYN_LOCK (bin);                    \
+  if (g_atomic_int_get (&bin->priv->shutdown)) { \
+    GST_RTP_BIN_DYN_UNLOCK (bin);                \
+    goto label;                                  \
+  }                                              \
+} G_STMT_END
+
+/* unlock for shutdown */
+#define GST_RTP_BIN_SHUTDOWN_UNLOCK(bin)         \
+  GST_RTP_BIN_DYN_UNLOCK (bin);                  \
+
+/* Minimum time offset to apply. This compensates for rounding errors in NTP to
+ * RTP timestamp conversions */
+#define MIN_TS_OFFSET (4 * GST_MSECOND)
+
+struct _GstRtpBinPrivate
+{
+  GMutex bin_lock;
+
+  /* lock protecting dynamic adding/removing */
+  GMutex dyn_lock;
+
+  /* if we are shutting down or not */
+  gint shutdown;
+
+  gboolean autoremove;
+
+  /* NTP time in ns of last SR sync used */
+  guint64 last_ntpnstime;
+
+  /* list of extra elements */
+  GList *elements;
+};
+
+/* signals and args */
+enum
+{
+  SIGNAL_REQUEST_PT_MAP,
+  SIGNAL_PAYLOAD_TYPE_CHANGE,
+  SIGNAL_CLEAR_PT_MAP,
+  SIGNAL_RESET_SYNC,
+  SIGNAL_GET_SESSION,
+  SIGNAL_GET_INTERNAL_SESSION,
+
+  SIGNAL_ON_NEW_SSRC,
+  SIGNAL_ON_SSRC_COLLISION,
+  SIGNAL_ON_SSRC_VALIDATED,
+  SIGNAL_ON_SSRC_ACTIVE,
+  SIGNAL_ON_SSRC_SDES,
+  SIGNAL_ON_BYE_SSRC,
+  SIGNAL_ON_BYE_TIMEOUT,
+  SIGNAL_ON_TIMEOUT,
+  SIGNAL_ON_SENDER_TIMEOUT,
+  SIGNAL_ON_NPT_STOP,
+
+  SIGNAL_REQUEST_RTP_ENCODER,
+  SIGNAL_REQUEST_RTP_DECODER,
+  SIGNAL_REQUEST_RTCP_ENCODER,
+  SIGNAL_REQUEST_RTCP_DECODER,
+
+  SIGNAL_NEW_JITTERBUFFER,
+
+  SIGNAL_REQUEST_AUX_SENDER,
+  SIGNAL_REQUEST_AUX_RECEIVER,
+
+  SIGNAL_ON_NEW_SENDER_SSRC,
+  SIGNAL_ON_SENDER_SSRC_ACTIVE,
+
+  SIGNAL_ON_BUNDLED_SSRC,
+
+  LAST_SIGNAL
+};
+
+#define DEFAULT_LATENCY_MS           200
+#define DEFAULT_DROP_ON_LATENCY      FALSE
+#define DEFAULT_SDES                 NULL
+#define DEFAULT_DO_LOST              FALSE
+#define DEFAULT_IGNORE_PT            FALSE
+#define DEFAULT_NTP_SYNC             FALSE
+#define DEFAULT_AUTOREMOVE           FALSE
+#define DEFAULT_BUFFER_MODE          RTP_JITTER_BUFFER_MODE_SLAVE
+#define DEFAULT_USE_PIPELINE_CLOCK   FALSE
+#define DEFAULT_RTCP_SYNC            GST_RTP_BIN_RTCP_SYNC_ALWAYS
+#define DEFAULT_RTCP_SYNC_INTERVAL   0
+#define DEFAULT_DO_SYNC_EVENT        FALSE
+#define DEFAULT_DO_RETRANSMISSION    FALSE
+#define DEFAULT_RTP_PROFILE          GST_RTP_PROFILE_AVP
+#define DEFAULT_NTP_TIME_SOURCE      GST_RTP_NTP_TIME_SOURCE_NTP
+#define DEFAULT_RTCP_SYNC_SEND_TIME  TRUE
+#define DEFAULT_MAX_RTCP_RTP_TIME_DIFF 1000
+#define DEFAULT_MAX_DROPOUT_TIME     60000
+#define DEFAULT_MAX_MISORDER_TIME    2000
+#define DEFAULT_RFC7273_SYNC         FALSE
+#define DEFAULT_MAX_STREAMS          G_MAXUINT
+#define DEFAULT_MAX_TS_OFFSET_ADJUSTMENT G_GUINT64_CONSTANT(0)
+#define DEFAULT_MAX_TS_OFFSET        G_GINT64_CONSTANT(3000000000)
+
+enum
+{
+  PROP_0,
+  PROP_LATENCY,
+  PROP_DROP_ON_LATENCY,
+  PROP_SDES,
+  PROP_DO_LOST,
+  PROP_IGNORE_PT,
+  PROP_NTP_SYNC,
+  PROP_RTCP_SYNC,
+  PROP_RTCP_SYNC_INTERVAL,
+  PROP_AUTOREMOVE,
+  PROP_BUFFER_MODE,
+  PROP_USE_PIPELINE_CLOCK,
+  PROP_DO_SYNC_EVENT,
+  PROP_DO_RETRANSMISSION,
+  PROP_RTP_PROFILE,
+  PROP_NTP_TIME_SOURCE,
+  PROP_RTCP_SYNC_SEND_TIME,
+  PROP_MAX_RTCP_RTP_TIME_DIFF,
+  PROP_MAX_DROPOUT_TIME,
+  PROP_MAX_MISORDER_TIME,
+  PROP_RFC7273_SYNC,
+  PROP_MAX_STREAMS,
+  PROP_MAX_TS_OFFSET_ADJUSTMENT,
+  PROP_MAX_TS_OFFSET
+};
+
+#define GST_RTP_BIN_RTCP_SYNC_TYPE (gst_rtp_bin_rtcp_sync_get_type())
+static GType
+gst_rtp_bin_rtcp_sync_get_type (void)
+{
+  static GType rtcp_sync_type = 0;
+  static const GEnumValue rtcp_sync_types[] = {
+    {GST_RTP_BIN_RTCP_SYNC_ALWAYS, "always", "always"},
+    {GST_RTP_BIN_RTCP_SYNC_INITIAL, "initial", "initial"},
+    {GST_RTP_BIN_RTCP_SYNC_RTP, "rtp-info", "rtp-info"},
+    {0, NULL, NULL},
+  };
+
+  if (!rtcp_sync_type) {
+    rtcp_sync_type = g_enum_register_static ("GstRTCPSync", rtcp_sync_types);
+  }
+  return rtcp_sync_type;
+}
+
+/* helper objects */
+typedef struct _GstRtpBinSession GstRtpBinSession;
+typedef struct _GstRtpBinStream GstRtpBinStream;
+typedef struct _GstRtpBinClient GstRtpBinClient;
+
+static guint gst_rtp_bin_signals[LAST_SIGNAL] = { 0 };
+
+static GstCaps *pt_map_requested (GstElement * element, guint pt,
+    GstRtpBinSession * session);
+static void payload_type_change (GstElement * element, guint pt,
+    GstRtpBinSession * session);
+static void remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session);
+static void remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session);
+static void remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session);
+static void remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session);
+static void free_client (GstRtpBinClient * client, GstRtpBin * bin);
+static void free_stream (GstRtpBinStream * stream, GstRtpBin * bin);
+static GstRtpBinSession *create_session (GstRtpBin * rtpbin, gint id);
+static GstPad *complete_session_sink (GstRtpBin * rtpbin,
+    GstRtpBinSession * session, gboolean bundle_demuxer_needed);
+static void
+complete_session_receiver (GstRtpBin * rtpbin, GstRtpBinSession * session,
+    guint sessid);
+static GstPad *complete_session_rtcp (GstRtpBin * rtpbin,
+    GstRtpBinSession * session, guint sessid, gboolean bundle_demuxer_needed);
+
+/* Manages the RTP stream for one SSRC.
+ *
+ * We pipe the stream (comming from the SSRC demuxer) into a jitterbuffer.
+ * If we see an SDES RTCP packet that links multiple SSRCs together based on a
+ * common CNAME, we create a GstRtpBinClient structure to group the SSRCs
+ * together (see below).
+ */
+struct _GstRtpBinStream
+{
+  /* the SSRC of this stream */
+  guint32 ssrc;
+
+  /* parent bin */
+  GstRtpBin *bin;
+
+  /* the session this SSRC belongs to */
+  GstRtpBinSession *session;
+
+  /* the jitterbuffer of the SSRC */
+  GstElement *buffer;
+  gulong buffer_handlesync_sig;
+  gulong buffer_ptreq_sig;
+  gulong buffer_ntpstop_sig;
+  gint percent;
+
+  /* the PT demuxer of the SSRC */
+  GstElement *demux;
+  gulong demux_newpad_sig;
+  gulong demux_padremoved_sig;
+  gulong demux_ptreq_sig;
+  gulong demux_ptchange_sig;
+
+  /* if we have calculated a valid rt_delta for this stream */
+  gboolean have_sync;
+  /* mapping to local RTP and NTP time */
+  gint64 rt_delta;
+  gint64 rtp_delta;
+  /* base rtptime in gst time */
+  gint64 clock_base;
+};
+
+#define GST_RTP_SESSION_LOCK(sess)   g_mutex_lock (&(sess)->lock)
+#define GST_RTP_SESSION_UNLOCK(sess) g_mutex_unlock (&(sess)->lock)
+
+/* Manages the receiving end of the packets.
+ *
+ * There is one such structure for each RTP session (audio/video/...).
+ * We get the RTP/RTCP packets and stuff them into the session manager. From
+ * there they are pushed into an SSRC demuxer that splits the stream based on
+ * SSRC. Each of the SSRC streams go into their own jitterbuffer (managed with
+ * the GstRtpBinStream above).
+ */
+struct _GstRtpBinSession
+{
+  /* session id */
+  gint id;
+  /* the parent bin */
+  GstRtpBin *bin;
+  /* the session element */
+  GstElement *session;
+  /* the SSRC demuxer */
+  GstElement *demux;
+  gulong demux_newpad_sig;
+  gulong demux_padremoved_sig;
+
+  /* Bundling support */
+  GstElement *rtp_funnel;
+  GstElement *rtcp_funnel;
+  GstElement *bundle_demux;
+  gulong bundle_demux_newpad_sig;
+
+  GMutex lock;
+
+  /* list of GstRtpBinStream */
+  GSList *streams;
+
+  /* list of elements */
+  GSList *elements;
+
+  /* mapping of payload type to caps */
+  GHashTable *ptmap;
+
+  /* the pads of the session */
+  GstPad *recv_rtp_sink;
+  GstPad *recv_rtp_sink_ghost;
+  GstPad *recv_rtp_src;
+  GstPad *recv_rtcp_sink;
+  GstPad *recv_rtcp_sink_ghost;
+  GstPad *sync_src;
+  GstPad *send_rtp_sink;
+  GstPad *send_rtp_sink_ghost;
+  GstPad *send_rtp_src;
+  GstPad *send_rtp_src_ghost;
+  GstPad *send_rtcp_src;
+  GstPad *send_rtcp_src_ghost;
+};
+
+/* Manages the RTP streams that come from one client and should therefore be
+ * synchronized.
+ */
+struct _GstRtpBinClient
+{
+  /* the common CNAME for the streams */
+  gchar *cname;
+  guint cname_len;
+
+  /* the streams */
+  guint nstreams;
+  GSList *streams;
+};
+
+/* find a session with the given id. Must be called with RTP_BIN_LOCK */
+static GstRtpBinSession *
+find_session_by_id (GstRtpBin * rtpbin, gint id)
+{
+  GSList *walk;
+
+  for (walk = rtpbin->sessions; walk; walk = g_slist_next (walk)) {
+    GstRtpBinSession *sess = (GstRtpBinSession *) walk->data;
+
+    if (sess->id == id)
+      return sess;
+  }
+  return NULL;
+}
+
+/* find a session with the given request pad. Must be called with RTP_BIN_LOCK */
+static GstRtpBinSession *
+find_session_by_pad (GstRtpBin * rtpbin, GstPad * pad)
+{
+  GSList *walk;
+
+  for (walk = rtpbin->sessions; walk; walk = g_slist_next (walk)) {
+    GstRtpBinSession *sess = (GstRtpBinSession *) walk->data;
+
+    if ((sess->recv_rtp_sink_ghost == pad) ||
+        (sess->recv_rtcp_sink_ghost == pad) ||
+        (sess->send_rtp_sink_ghost == pad)
+        || (sess->send_rtcp_src_ghost == pad))
+      return sess;
+  }
+  return NULL;
+}
+
+static void
+on_new_ssrc (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
+{
+  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_NEW_SSRC], 0,
+      sess->id, ssrc);
+}
+
+static void
+on_ssrc_collision (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
+{
+  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SSRC_COLLISION], 0,
+      sess->id, ssrc);
+}
+
+static void
+on_ssrc_validated (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
+{
+  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SSRC_VALIDATED], 0,
+      sess->id, ssrc);
+}
+
+static void
+on_ssrc_active (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
+{
+  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SSRC_ACTIVE], 0,
+      sess->id, ssrc);
+}
+
+static void
+on_ssrc_sdes (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
+{
+  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SSRC_SDES], 0,
+      sess->id, ssrc);
+}
+
+static void
+on_bye_ssrc (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
+{
+  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_BYE_SSRC], 0,
+      sess->id, ssrc);
+}
+
+static void
+on_bye_timeout (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
+{
+  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_BYE_TIMEOUT], 0,
+      sess->id, ssrc);
+
+  if (sess->bin->priv->autoremove)
+    g_signal_emit_by_name (sess->demux, "clear-ssrc", ssrc, NULL);
+}
+
+static void
+on_timeout (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
+{
+  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_TIMEOUT], 0,
+      sess->id, ssrc);
+
+  if (sess->bin->priv->autoremove)
+    g_signal_emit_by_name (sess->demux, "clear-ssrc", ssrc, NULL);
+}
+
+static void
+on_sender_timeout (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
+{
+  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SENDER_TIMEOUT], 0,
+      sess->id, ssrc);
+}
+
+static void
+on_npt_stop (GstElement * jbuf, GstRtpBinStream * stream)
+{
+  g_signal_emit (stream->bin, gst_rtp_bin_signals[SIGNAL_ON_NPT_STOP], 0,
+      stream->session->id, stream->ssrc);
+}
+
+static void
+on_new_sender_ssrc (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
+{
+  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_NEW_SENDER_SSRC], 0,
+      sess->id, ssrc);
+}
+
+static void
+on_sender_ssrc_active (GstElement * session, guint32 ssrc,
+    GstRtpBinSession * sess)
+{
+  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SENDER_SSRC_ACTIVE],
+      0, sess->id, ssrc);
+}
+
+/* must be called with the SESSION lock */
+static GstRtpBinStream *
+find_stream_by_ssrc (GstRtpBinSession * session, guint32 ssrc)
+{
+  GSList *walk;
+
+  for (walk = session->streams; walk; walk = g_slist_next (walk)) {
+    GstRtpBinStream *stream = (GstRtpBinStream *) walk->data;
+
+    if (stream->ssrc == ssrc)
+      return stream;
+  }
+  return NULL;
+}
+
+static void
+ssrc_demux_pad_removed (GstElement * element, guint ssrc, GstPad * pad,
+    GstRtpBinSession * session)
+{
+  GstRtpBinStream *stream = NULL;
+  GstRtpBin *rtpbin;
+
+  rtpbin = session->bin;
+
+  GST_RTP_BIN_LOCK (rtpbin);
+
+  GST_RTP_SESSION_LOCK (session);
+  if ((stream = find_stream_by_ssrc (session, ssrc)))
+    session->streams = g_slist_remove (session->streams, stream);
+  GST_RTP_SESSION_UNLOCK (session);
+
+  if (stream)
+    free_stream (stream, rtpbin);
+
+  GST_RTP_BIN_UNLOCK (rtpbin);
+}
+
+static void
+new_bundled_ssrc_pad_found (GstElement * element, guint ssrc, GstPad * pad,
+    GstRtpBinSession * session)
+{
+  GValue result = G_VALUE_INIT;
+  GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
+  guint session_id = 0;
+  GstRtpBinSession *target_session = NULL;
+  GstRtpBin *rtpbin = session->bin;
+  gchar *name;
+  GstPad *src_pad;
+  GstPad *recv_rtp_sink = NULL;
+  GstPad *recv_rtcp_sink = NULL;
+  GstPadLinkReturn ret;
+
+  GST_RTP_BIN_DYN_LOCK (rtpbin);
+  GST_DEBUG_OBJECT (rtpbin, "new bundled SSRC pad %08x, %s:%s", ssrc,
+      GST_DEBUG_PAD_NAME (pad));
+
+  g_value_init (&result, G_TYPE_UINT);
+  g_value_init (&params[0], GST_TYPE_ELEMENT);
+  g_value_set_object (&params[0], rtpbin);
+  g_value_init (&params[1], G_TYPE_UINT);
+  g_value_set_uint (&params[1], ssrc);
+
+  g_signal_emitv (params,
+      gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC], 0, &result);
+  g_value_unset (&params[0]);
+
+  session_id = g_value_get_uint (&result);
+  if (session_id == 0) {
+    target_session = session;
+  } else {
+    target_session = find_session_by_id (rtpbin, (gint) session_id);
+    if (!target_session) {
+      target_session = create_session (rtpbin, session_id);
+    }
+    if (!target_session) {
+      /* create_session() warned already */
+      GST_RTP_BIN_DYN_UNLOCK (rtpbin);
+      return;
+    }
+
+    if (!target_session->recv_rtp_sink) {
+      recv_rtp_sink = complete_session_sink (rtpbin, target_session, FALSE);
+    }
+
+    if (!target_session->recv_rtp_src)
+      complete_session_receiver (rtpbin, target_session, session_id);
+
+    if (!target_session->recv_rtcp_sink) {
+      recv_rtcp_sink =
+          complete_session_rtcp (rtpbin, target_session, session_id, FALSE);
+    }
+  }
+
+  GST_DEBUG_OBJECT (rtpbin, "Assigning bundled ssrc %u to session %u", ssrc,
+      session_id);
+
+  if (!recv_rtp_sink) {
+    recv_rtp_sink =
+        gst_element_get_request_pad (target_session->rtp_funnel, "sink_%u");
+  }
+
+  if (!recv_rtcp_sink) {
+    recv_rtcp_sink =
+        gst_element_get_request_pad (target_session->rtcp_funnel, "sink_%u");
+  }
+
+  name = g_strdup_printf ("src_%u", ssrc);
+  src_pad = gst_element_get_static_pad (element, name);
+  ret = gst_pad_link (src_pad, recv_rtp_sink);
+  g_free (name);
+  gst_object_unref (src_pad);
+  gst_object_unref (recv_rtp_sink);
+  if (ret != GST_PAD_LINK_OK) {
+    g_warning
+        ("rtpbin: failed to link bundle demuxer to receive rtp funnel for session %u",
+        session_id);
+  }
+
+  name = g_strdup_printf ("rtcp_src_%u", ssrc);
+  src_pad = gst_element_get_static_pad (element, name);
+  gst_pad_link (src_pad, recv_rtcp_sink);
+  g_free (name);
+  gst_object_unref (src_pad);
+  gst_object_unref (recv_rtcp_sink);
+  if (ret != GST_PAD_LINK_OK) {
+    g_warning
+        ("rtpbin: failed to link bundle demuxer to receive rtcp sink pad for session %u",
+        session_id);
+  }
+
+  GST_RTP_BIN_DYN_UNLOCK (rtpbin);
+}
+
+/* create a session with the given id.  Must be called with RTP_BIN_LOCK */
+static GstRtpBinSession *
+create_session (GstRtpBin * rtpbin, gint id)
+{
+  GstRtpBinSession *sess;
+  GstElement *session, *demux;
+  GstState target;
+
+  if (!(session = gst_element_factory_make ("rtpsession", NULL)))
+    goto no_session;
+
+  if (!(demux = gst_element_factory_make ("rtpssrcdemux", NULL)))
+    goto no_demux;
+
+  sess = g_new0 (GstRtpBinSession, 1);
+  g_mutex_init (&sess->lock);
+  sess->id = id;
+  sess->bin = rtpbin;
+  sess->session = session;
+  sess->demux = demux;
+
+  sess->rtp_funnel = gst_element_factory_make ("funnel", NULL);
+  sess->rtcp_funnel = gst_element_factory_make ("funnel", NULL);
+
+  sess->ptmap = g_hash_table_new_full (NULL, NULL, NULL,
+      (GDestroyNotify) gst_caps_unref);
+  rtpbin->sessions = g_slist_prepend (rtpbin->sessions, sess);
+
+  /* configure SDES items */
+  GST_OBJECT_LOCK (rtpbin);
+  g_object_set (session, "sdes", rtpbin->sdes, "rtp-profile",
+      rtpbin->rtp_profile, "rtcp-sync-send-time", rtpbin->rtcp_sync_send_time,
+      NULL);
+  if (rtpbin->use_pipeline_clock)
+    g_object_set (session, "use-pipeline-clock", rtpbin->use_pipeline_clock,
+        NULL);
+  else
+    g_object_set (session, "ntp-time-source", rtpbin->ntp_time_source, NULL);
+
+  g_object_set (session, "max-dropout-time", rtpbin->max_dropout_time,
+      "max-misorder-time", rtpbin->max_misorder_time, NULL);
+  GST_OBJECT_UNLOCK (rtpbin);
+
+  /* provide clock_rate to the session manager when needed */
+  g_signal_connect (session, "request-pt-map",
+      (GCallback) pt_map_requested, sess);
+
+  g_signal_connect (sess->session, "on-new-ssrc",
+      (GCallback) on_new_ssrc, sess);
+  g_signal_connect (sess->session, "on-ssrc-collision",
+      (GCallback) on_ssrc_collision, sess);
+  g_signal_connect (sess->session, "on-ssrc-validated",
+      (GCallback) on_ssrc_validated, sess);
+  g_signal_connect (sess->session, "on-ssrc-active",
+      (GCallback) on_ssrc_active, sess);
+  g_signal_connect (sess->session, "on-ssrc-sdes",
+      (GCallback) on_ssrc_sdes, sess);
+  g_signal_connect (sess->session, "on-bye-ssrc",
+      (GCallback) on_bye_ssrc, sess);
+  g_signal_connect (sess->session, "on-bye-timeout",
+      (GCallback) on_bye_timeout, sess);
+  g_signal_connect (sess->session, "on-timeout", (GCallback) on_timeout, sess);
+  g_signal_connect (sess->session, "on-sender-timeout",
+      (GCallback) on_sender_timeout, sess);
+  g_signal_connect (sess->session, "on-new-sender-ssrc",
+      (GCallback) on_new_sender_ssrc, sess);
+  g_signal_connect (sess->session, "on-sender-ssrc-active",
+      (GCallback) on_sender_ssrc_active, sess);
+
+  gst_bin_add (GST_BIN_CAST (rtpbin), session);
+  gst_bin_add (GST_BIN_CAST (rtpbin), demux);
+  gst_bin_add (GST_BIN_CAST (rtpbin), sess->rtp_funnel);
+  gst_bin_add (GST_BIN_CAST (rtpbin), sess->rtcp_funnel);
+
+  GST_OBJECT_LOCK (rtpbin);
+  target = GST_STATE_TARGET (rtpbin);
+  GST_OBJECT_UNLOCK (rtpbin);
+
+  /* change state only to what's needed */
+  gst_element_set_state (demux, target);
+  gst_element_set_state (session, target);
+  gst_element_set_state (sess->rtp_funnel, target);
+  gst_element_set_state (sess->rtcp_funnel, target);
+
+  return sess;
+
+  /* ERRORS */
+no_session:
+  {
+    g_warning ("rtpbin: could not create rtpsession element");
+    return NULL;
+  }
+no_demux:
+  {
+    gst_object_unref (session);
+    g_warning ("rtpbin: could not create rtpssrcdemux element");
+    return NULL;
+  }
+}
+
+static gboolean
+bin_manage_element (GstRtpBin * bin, GstElement * element)
+{
+  GstRtpBinPrivate *priv = bin->priv;
+
+  if (g_list_find (priv->elements, element)) {
+    GST_DEBUG_OBJECT (bin, "requested element %p already in bin", element);
+  } else {
+    GST_DEBUG_OBJECT (bin, "adding requested element %p", element);
+
+    if (g_object_is_floating (element))
+      element = gst_object_ref_sink (element);
+
+    if (!gst_bin_add (GST_BIN_CAST (bin), element))
+      goto add_failed;
+    if (!gst_element_sync_state_with_parent (element))
+      GST_WARNING_OBJECT (bin, "unable to sync element state with rtpbin");
+  }
+  /* we add the element multiple times, each we need an equal number of
+   * removes to really remove the element from the bin */
+  priv->elements = g_list_prepend (priv->elements, element);
+
+  return TRUE;
+
+  /* ERRORS */
+add_failed:
+  {
+    GST_WARNING_OBJECT (bin, "unable to add element");
+    gst_object_unref (element);
+    return FALSE;
+  }
+}
+
+static void
+remove_bin_element (GstElement * element, GstRtpBin * bin)
+{
+  GstRtpBinPrivate *priv = bin->priv;
+  GList *find;
+
+  find = g_list_find (priv->elements, element);
+  if (find) {
+    priv->elements = g_list_delete_link (priv->elements, find);
+
+    if (!g_list_find (priv->elements, element)) {
+      gst_element_set_locked_state (element, TRUE);
+      gst_bin_remove (GST_BIN_CAST (bin), element);
+      gst_element_set_state (element, GST_STATE_NULL);
+    }
+
+    gst_object_unref (element);
+  }
+}
+
+/* called with RTP_BIN_LOCK */
+static void
+free_session (GstRtpBinSession * sess, GstRtpBin * bin)
+{
+  GST_DEBUG_OBJECT (bin, "freeing session %p", sess);
+
+  gst_element_set_locked_state (sess->demux, TRUE);
+  gst_element_set_locked_state (sess->session, TRUE);
+
+  gst_element_set_state (sess->demux, GST_STATE_NULL);
+  gst_element_set_state (sess->session, GST_STATE_NULL);
+
+  remove_recv_rtp (bin, sess);
+  remove_recv_rtcp (bin, sess);
+  remove_send_rtp (bin, sess);
+  remove_rtcp (bin, sess);
+
+  gst_bin_remove (GST_BIN_CAST (bin), sess->session);
+  gst_bin_remove (GST_BIN_CAST (bin), sess->demux);
+
+  g_slist_foreach (sess->elements, (GFunc) remove_bin_element, bin);
+  g_slist_free (sess->elements);
+
+  g_slist_foreach (sess->streams, (GFunc) free_stream, bin);
+  g_slist_free (sess->streams);
+
+  g_mutex_clear (&sess->lock);
+  g_hash_table_destroy (sess->ptmap);
+
+  g_free (sess);
+}
+
+/* get the payload type caps for the specific payload @pt in @session */
+static GstCaps *
+get_pt_map (GstRtpBinSession * session, guint pt)
+{
+  GstCaps *caps = NULL;
+  GstRtpBin *bin;
+  GValue ret = { 0 };
+  GValue args[3] = { {0}, {0}, {0} };
+
+  GST_DEBUG ("searching pt %u in cache", pt);
+
+  GST_RTP_SESSION_LOCK (session);
+
+  /* first look in the cache */
+  caps = g_hash_table_lookup (session->ptmap, GINT_TO_POINTER (pt));
+  if (caps) {
+    gst_caps_ref (caps);
+    goto done;
+  }
+
+  bin = session->bin;
+
+  GST_DEBUG ("emiting signal for pt %u in session %u", pt, session->id);
+
+  /* not in cache, send signal to request caps */
+  g_value_init (&args[0], GST_TYPE_ELEMENT);
+  g_value_set_object (&args[0], bin);
+  g_value_init (&args[1], G_TYPE_UINT);
+  g_value_set_uint (&args[1], session->id);
+  g_value_init (&args[2], G_TYPE_UINT);
+  g_value_set_uint (&args[2], pt);
+
+  g_value_init (&ret, GST_TYPE_CAPS);
+  g_value_set_boxed (&ret, NULL);
+
+  GST_RTP_SESSION_UNLOCK (session);
+
+  g_signal_emitv (args, gst_rtp_bin_signals[SIGNAL_REQUEST_PT_MAP], 0, &ret);
+
+  GST_RTP_SESSION_LOCK (session);
+
+  g_value_unset (&args[0]);
+  g_value_unset (&args[1]);
+  g_value_unset (&args[2]);
+
+  /* look in the cache again because we let the lock go */
+  caps = g_hash_table_lookup (session->ptmap, GINT_TO_POINTER (pt));
+  if (caps) {
+    gst_caps_ref (caps);
+    g_value_unset (&ret);
+    goto done;
+  }
+
+  caps = (GstCaps *) g_value_dup_boxed (&ret);
+  g_value_unset (&ret);
+  if (!caps)
+    goto no_caps;
+
+  GST_DEBUG ("caching pt %u as %" GST_PTR_FORMAT, pt, caps);
+
+  /* store in cache, take additional ref */
+  g_hash_table_insert (session->ptmap, GINT_TO_POINTER (pt),
+      gst_caps_ref (caps));
+
+done:
+  GST_RTP_SESSION_UNLOCK (session);
+
+  return caps;
+
+  /* ERRORS */
+no_caps:
+  {
+    GST_RTP_SESSION_UNLOCK (session);
+    GST_DEBUG ("no pt map could be obtained");
+    return NULL;
+  }
+}
+
+static gboolean
+return_true (gpointer key, gpointer value, gpointer user_data)
+{
+  return TRUE;
+}
+
+static void
+gst_rtp_bin_reset_sync (GstRtpBin * rtpbin)
+{
+  GSList *clients, *streams;
+
+  GST_DEBUG_OBJECT (rtpbin, "Reset sync on all clients");
+
+  GST_RTP_BIN_LOCK (rtpbin);
+  for (clients = rtpbin->clients; clients; clients = g_slist_next (clients)) {
+    GstRtpBinClient *client = (GstRtpBinClient *) clients->data;
+
+    /* reset sync on all streams for this client */
+    for (streams = client->streams; streams; streams = g_slist_next (streams)) {
+      GstRtpBinStream *stream = (GstRtpBinStream *) streams->data;
+
+      /* make use require a new SR packet for this stream before we attempt new
+       * lip-sync */
+      stream->have_sync = FALSE;
+      stream->rt_delta = 0;
+      stream->rtp_delta = 0;
+      stream->clock_base = -100 * GST_SECOND;
+    }
+  }
+  GST_RTP_BIN_UNLOCK (rtpbin);
+}
+
+static void
+gst_rtp_bin_clear_pt_map (GstRtpBin * bin)
+{
+  GSList *sessions, *streams;
+
+  GST_RTP_BIN_LOCK (bin);
+  GST_DEBUG_OBJECT (bin, "clearing pt map");
+  for (sessions = bin->sessions; sessions; sessions = g_slist_next (sessions)) {
+    GstRtpBinSession *session = (GstRtpBinSession *) sessions->data;
+
+    GST_DEBUG_OBJECT (bin, "clearing session %p", session);
+    g_signal_emit_by_name (session->session, "clear-pt-map", NULL);
+
+    GST_RTP_SESSION_LOCK (session);
+    g_hash_table_foreach_remove (session->ptmap, return_true, NULL);
+
+    for (streams = session->streams; streams; streams = g_slist_next (streams)) {
+      GstRtpBinStream *stream = (GstRtpBinStream *) streams->data;
+
+      GST_DEBUG_OBJECT (bin, "clearing stream %p", stream);
+      g_signal_emit_by_name (stream->buffer, "clear-pt-map", NULL);
+      if (stream->demux)
+        g_signal_emit_by_name (stream->demux, "clear-pt-map", NULL);
+    }
+    GST_RTP_SESSION_UNLOCK (session);
+  }
+  GST_RTP_BIN_UNLOCK (bin);
+
+  /* reset sync too */
+  gst_rtp_bin_reset_sync (bin);
+}
+
+static GstElement *
+gst_rtp_bin_get_session (GstRtpBin * bin, guint session_id)
+{
+  GstRtpBinSession *session;
+  GstElement *ret = NULL;
+
+  GST_RTP_BIN_LOCK (bin);
+  GST_DEBUG_OBJECT (bin, "retrieving GstRtpSession, index: %u", session_id);
+  session = find_session_by_id (bin, (gint) session_id);
+  if (session) {
+    ret = gst_object_ref (session->session);
+  }
+  GST_RTP_BIN_UNLOCK (bin);
+
+  return ret;
+}
+
+static RTPSession *
+gst_rtp_bin_get_internal_session (GstRtpBin * bin, guint session_id)
+{
+  RTPSession *internal_session = NULL;
+  GstRtpBinSession *session;
+
+  GST_RTP_BIN_LOCK (bin);
+  GST_DEBUG_OBJECT (bin, "retrieving internal RTPSession object, index: %u",
+      session_id);
+  session = find_session_by_id (bin, (gint) session_id);
+  if (session) {
+    g_object_get (session->session, "internal-session", &internal_session,
+        NULL);
+  }
+  GST_RTP_BIN_UNLOCK (bin);
+
+  return internal_session;
+}
+
+static GstElement *
+gst_rtp_bin_request_encoder (GstRtpBin * bin, guint session_id)
+{
+  GST_DEBUG_OBJECT (bin, "return NULL encoder");
+  return NULL;
+}
+
+static GstElement *
+gst_rtp_bin_request_decoder (GstRtpBin * bin, guint session_id)
+{
+  GST_DEBUG_OBJECT (bin, "return NULL decoder");
+  return NULL;
+}
+
+static void
+gst_rtp_bin_propagate_property_to_jitterbuffer (GstRtpBin * bin,
+    const gchar * name, const GValue * value)
+{
+  GSList *sessions, *streams;
+
+  GST_RTP_BIN_LOCK (bin);
+  for (sessions = bin->sessions; sessions; sessions = g_slist_next (sessions)) {
+    GstRtpBinSession *session = (GstRtpBinSession *) sessions->data;
+
+    GST_RTP_SESSION_LOCK (session);
+    for (streams = session->streams; streams; streams = g_slist_next (streams)) {
+      GstRtpBinStream *stream = (GstRtpBinStream *) streams->data;
+
+      g_object_set_property (G_OBJECT (stream->buffer), name, value);
+    }
+    GST_RTP_SESSION_UNLOCK (session);
+  }
+  GST_RTP_BIN_UNLOCK (bin);
+}
+
+static void
+gst_rtp_bin_propagate_property_to_session (GstRtpBin * bin,
+    const gchar * name, const GValue * value)
+{
+  GSList *sessions;
+
+  GST_RTP_BIN_LOCK (bin);
+  for (sessions = bin->sessions; sessions; sessions = g_slist_next (sessions)) {
+    GstRtpBinSession *sess = (GstRtpBinSession *) sessions->data;
+
+    g_object_set_property (G_OBJECT (sess->session), name, value);
+  }
+  GST_RTP_BIN_UNLOCK (bin);
+}
+
+/* get a client with the given SDES name. Must be called with RTP_BIN_LOCK */
+static GstRtpBinClient *
+get_client (GstRtpBin * bin, guint8 len, guint8 * data, gboolean * created)
+{
+  GstRtpBinClient *result = NULL;
+  GSList *walk;
+
+  for (walk = bin->clients; walk; walk = g_slist_next (walk)) {
+    GstRtpBinClient *client = (GstRtpBinClient *) walk->data;
+
+    if (len != client->cname_len)
+      continue;
+
+    if (!strncmp ((gchar *) data, client->cname, client->cname_len)) {
+      GST_DEBUG_OBJECT (bin, "found existing client %p with CNAME %s", client,
+          client->cname);
+      result = client;
+      break;
+    }
+  }
+
+  /* nothing found, create one */
+  if (result == NULL) {
+    result = g_new0 (GstRtpBinClient, 1);
+    result->cname = g_strndup ((gchar *) data, len);
+    result->cname_len = len;
+    bin->clients = g_slist_prepend (bin->clients, result);
+    GST_DEBUG_OBJECT (bin, "created new client %p with CNAME %s", result,
+        result->cname);
+  }
+  return result;
+}
+
+static void
+free_client (GstRtpBinClient * client, GstRtpBin * bin)
+{
+  GST_DEBUG_OBJECT (bin, "freeing client %p", client);
+  g_slist_free (client->streams);
+  g_free (client->cname);
+  g_free (client);
+}
+
+static void
+get_current_times (GstRtpBin * bin, GstClockTime * running_time,
+    guint64 * ntpnstime)
+{
+  guint64 ntpns = -1;
+  GstClock *clock;
+  GstClockTime base_time, rt, clock_time;
+
+  GST_OBJECT_LOCK (bin);
+  if ((clock = GST_ELEMENT_CLOCK (bin))) {
+    base_time = GST_ELEMENT_CAST (bin)->base_time;
+    gst_object_ref (clock);
+    GST_OBJECT_UNLOCK (bin);
+
+    /* get current clock time and convert to running time */
+    clock_time = gst_clock_get_time (clock);
+    rt = clock_time - base_time;
+
+    if (bin->use_pipeline_clock) {
+      ntpns = rt;
+      /* add constant to convert from 1970 based time to 1900 based time */
+      ntpns += (2208988800LL * GST_SECOND);
+    } else {
+      switch (bin->ntp_time_source) {
+        case GST_RTP_NTP_TIME_SOURCE_NTP:
+        case GST_RTP_NTP_TIME_SOURCE_UNIX:{
+          GTimeVal current;
+
+          /* get current NTP time */
+          g_get_current_time (&current);
+          ntpns = GST_TIMEVAL_TO_TIME (current);
+
+          /* add constant to convert from 1970 based time to 1900 based time */
+          if (bin->ntp_time_source == GST_RTP_NTP_TIME_SOURCE_NTP)
+            ntpns += (2208988800LL * GST_SECOND);
+          break;
+        }
+        case GST_RTP_NTP_TIME_SOURCE_RUNNING_TIME:
+          ntpns = rt;
+          break;
+        case GST_RTP_NTP_TIME_SOURCE_CLOCK_TIME:
+          ntpns = clock_time;
+          break;
+        default:
+          ntpns = -1;           /* Fix uninited compiler warning */
+          g_assert_not_reached ();
+          break;
+      }
+    }
+
+    gst_object_unref (clock);
+  } else {
+    GST_OBJECT_UNLOCK (bin);
+    rt = -1;
+    ntpns = -1;
+  }
+  if (running_time)
+    *running_time = rt;
+  if (ntpnstime)
+    *ntpnstime = ntpns;
+}
+
+static void
+stream_set_ts_offset (GstRtpBin * bin, GstRtpBinStream * stream,
+    gint64 ts_offset, gint64 max_ts_offset, gint64 min_ts_offset,
+    gboolean allow_positive_ts_offset)
+{
+  gint64 prev_ts_offset;
+
+  g_object_get (stream->buffer, "ts-offset", &prev_ts_offset, NULL);
+
+  /* delta changed, see how much */
+  if (prev_ts_offset != ts_offset) {
+    gint64 diff;
+
+    diff = prev_ts_offset - ts_offset;
+
+    GST_DEBUG_OBJECT (bin,
+        "ts-offset %" G_GINT64_FORMAT ", prev %" G_GINT64_FORMAT
+        ", diff: %" G_GINT64_FORMAT, ts_offset, prev_ts_offset, diff);
+
+    /* ignore minor offsets */
+    if (ABS (diff) < min_ts_offset) {
+      GST_DEBUG_OBJECT (bin, "offset too small, ignoring");
+      return;
+    }
+
+    /* sanity check offset */
+    if (max_ts_offset > 0) {
+      if (ts_offset > 0 && !allow_positive_ts_offset) {
+        GST_DEBUG_OBJECT (bin,
+            "offset is positive (clocks are out of sync), ignoring");
+        return;
+      }
+      if (ABS (ts_offset) > max_ts_offset) {
+        GST_DEBUG_OBJECT (bin, "offset too large, ignoring");
+        return;
+      }
+    }
+
+    g_object_set (stream->buffer, "ts-offset", ts_offset, NULL);
+  }
+  GST_DEBUG_OBJECT (bin, "stream SSRC %08x, delta %" G_GINT64_FORMAT,
+      stream->ssrc, ts_offset);
+}
+
+static void
+gst_rtp_bin_send_sync_event (GstRtpBinStream * stream)
+{
+  if (stream->bin->send_sync_event) {
+    GstEvent *event;
+    GstPad *srcpad;
+
+    GST_DEBUG_OBJECT (stream->bin,
+        "sending GstRTCPSRReceived event downstream");
+
+    event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
+        gst_structure_new_empty ("GstRTCPSRReceived"));
+
+    srcpad = gst_element_get_static_pad (stream->buffer, "src");
+    gst_pad_push_event (srcpad, event);
+    gst_object_unref (srcpad);
+  }
+}
+
+/* associate a stream to the given CNAME. This will make sure all streams for
+ * that CNAME are synchronized together.
+ * Must be called with GST_RTP_BIN_LOCK */
+static void
+gst_rtp_bin_associate (GstRtpBin * bin, GstRtpBinStream * stream, guint8 len,
+    guint8 * data, guint64 ntptime, guint64 last_extrtptime,
+    guint64 base_rtptime, guint64 base_time, guint clock_rate,
+    gint64 rtp_clock_base)
+{
+  GstRtpBinClient *client;
+  gboolean created;
+  GSList *walk;
+  GstClockTime running_time, running_time_rtp;
+  guint64 ntpnstime;
+
+  /* first find or create the CNAME */
+  client = get_client (bin, len, data, &created);
+
+  /* find stream in the client */
+  for (walk = client->streams; walk; walk = g_slist_next (walk)) {
+    GstRtpBinStream *ostream = (GstRtpBinStream *) walk->data;
+
+    if (ostream == stream)
+      break;
+  }
+  /* not found, add it to the list */
+  if (walk == NULL) {
+    GST_DEBUG_OBJECT (bin,
+        "new association of SSRC %08x with client %p with CNAME %s",
+        stream->ssrc, client, client->cname);
+    client->streams = g_slist_prepend (client->streams, stream);
+    client->nstreams++;
+  } else {
+    GST_DEBUG_OBJECT (bin,
+        "found association of SSRC %08x with client %p with CNAME %s",
+        stream->ssrc, client, client->cname);
+  }
+
+  if (!GST_CLOCK_TIME_IS_VALID (last_extrtptime)) {
+    GST_DEBUG_OBJECT (bin, "invalidated sync data");
+    if (bin->rtcp_sync == GST_RTP_BIN_RTCP_SYNC_RTP) {
+      /* we don't need that data, so carry on,
+       * but make some values look saner */
+      last_extrtptime = base_rtptime;
+    } else {
+      /* nothing we can do with this data in this case */
+      GST_DEBUG_OBJECT (bin, "bailing out");
+      return;
+    }
+  }
+
+  /* Take the extended rtptime we found in the SR packet and map it to the
+   * local rtptime. The local rtp time is used to construct timestamps on the
+   * buffers so we will calculate what running_time corresponds to the RTP
+   * timestamp in the SR packet. */
+  running_time_rtp = last_extrtptime - base_rtptime;
+
+  GST_DEBUG_OBJECT (bin,
+      "base %" G_GUINT64_FORMAT ", extrtptime %" G_GUINT64_FORMAT
+      ", local RTP %" G_GUINT64_FORMAT ", clock-rate %d, "
+      "clock-base %" G_GINT64_FORMAT, base_rtptime,
+      last_extrtptime, running_time_rtp, clock_rate, rtp_clock_base);
+
+  /* calculate local RTP time in gstreamer timestamp, we essentially perform the
+   * same conversion that a jitterbuffer would use to convert an rtp timestamp
+   * into a corresponding gstreamer timestamp. Note that the base_time also
+   * contains the drift between sender and receiver. */
+  running_time =
+      gst_util_uint64_scale_int (running_time_rtp, GST_SECOND, clock_rate);
+  running_time += base_time;
+
+  /* convert ntptime to nanoseconds */
+  ntpnstime = gst_util_uint64_scale (ntptime, GST_SECOND,
+      (G_GINT64_CONSTANT (1) << 32));
+
+  stream->have_sync = TRUE;
+
+  GST_DEBUG_OBJECT (bin,
+      "SR RTP running time %" G_GUINT64_FORMAT ", SR NTP %" G_GUINT64_FORMAT,
+      running_time, ntpnstime);
+
+  /* recalc inter stream playout offset, but only if there is more than one
+   * stream or we're doing NTP sync. */
+  if (bin->ntp_sync) {
+    gint64 ntpdiff, rtdiff;
+    guint64 local_ntpnstime;
+    GstClockTime local_running_time;
+
+    /* For NTP sync we need to first get a snapshot of running_time and NTP
+     * time. We know at what running_time we play a certain RTP time, we also
+     * calculated when we would play the RTP time in the SR packet. Now we need
+     * to know how the running_time and the NTP time relate to eachother. */
+    get_current_times (bin, &local_running_time, &local_ntpnstime);
+
+    /* see how far away the NTP time is. This is the difference between the
+     * current NTP time and the NTP time in the last SR packet. */
+    ntpdiff = local_ntpnstime - ntpnstime;
+    /* see how far away the running_time is. This is the difference between the
+     * current running_time and the running_time of the RTP timestamp in the
+     * last SR packet. */
+    rtdiff = local_running_time - running_time;
+
+    GST_DEBUG_OBJECT (bin,
+        "local NTP time %" G_GUINT64_FORMAT ", SR NTP time %" G_GUINT64_FORMAT,
+        local_ntpnstime, ntpnstime);
+    GST_DEBUG_OBJECT (bin,
+        "local running time %" G_GUINT64_FORMAT ", SR RTP running time %"
+        G_GUINT64_FORMAT, local_running_time, running_time);
+    GST_DEBUG_OBJECT (bin,
+        "NTP diff %" G_GINT64_FORMAT ", RT diff %" G_GINT64_FORMAT, ntpdiff,
+        rtdiff);
+
+    /* combine to get the final diff to apply to the running_time */
+    stream->rt_delta = rtdiff - ntpdiff;
+
+    stream_set_ts_offset (bin, stream, stream->rt_delta, bin->max_ts_offset,
+        0, FALSE);
+  } else {
+    gint64 min, rtp_min, clock_base = stream->clock_base;
+    gboolean all_sync, use_rtp;
+    gboolean rtcp_sync = g_atomic_int_get (&bin->rtcp_sync);
+
+    /* calculate delta between server and receiver. ntpnstime is created by
+     * converting the ntptime in the last SR packet to a gstreamer timestamp. This
+     * delta expresses the difference to our timeline and the server timeline. The
+     * difference in itself doesn't mean much but we can combine the delta of
+     * multiple streams to create a stream specific offset. */
+    stream->rt_delta = ntpnstime - running_time;
+
+    /* calculate the min of all deltas, ignoring streams that did not yet have a
+     * valid rt_delta because we did not yet receive an SR packet for those
+     * streams.
+     * We calculate the mininum because we would like to only apply positive
+     * offsets to streams, delaying their playback instead of trying to speed up
+     * other streams (which might be imposible when we have to create negative
+     * latencies).
+     * The stream that has the smallest diff is selected as the reference stream,
+     * all other streams will have a positive offset to this difference. */
+
+    /* some alternative setting allow ignoring RTCP as much as possible,
+     * for servers generating bogus ntp timeline */
+    min = rtp_min = G_MAXINT64;
+    use_rtp = FALSE;
+    if (rtcp_sync == GST_RTP_BIN_RTCP_SYNC_RTP) {
+      guint64 ext_base;
+
+      use_rtp = TRUE;
+      /* signed version for convienience */
+      clock_base = base_rtptime;
+      /* deal with possible wrap-around */
+      ext_base = base_rtptime;
+      rtp_clock_base = gst_rtp_buffer_ext_timestamp (&ext_base, rtp_clock_base);
+      /* sanity check; base rtp and provided clock_base should be close */
+      if (rtp_clock_base >= clock_base) {
+        if (rtp_clock_base - clock_base < 10 * clock_rate) {
+          rtp_clock_base = base_time +
+              gst_util_uint64_scale_int (rtp_clock_base - clock_base,
+              GST_SECOND, clock_rate);
+        } else {
+          use_rtp = FALSE;
+        }
+      } else {
+        if (clock_base - rtp_clock_base < 10 * clock_rate) {
+          rtp_clock_base = base_time -
+              gst_util_uint64_scale_int (clock_base - rtp_clock_base,
+              GST_SECOND, clock_rate);
+        } else {
+          use_rtp = FALSE;
+        }
+      }
+      /* warn and bail for clarity out if no sane values */
+      if (!use_rtp) {
+        GST_WARNING_OBJECT (bin, "unable to sync to provided rtptime");
+        return;
+      }
+      /* store to track changes */
+      clock_base = rtp_clock_base;
+      /* generate a fake as before,
+       * now equating rtptime obtained from RTP-Info,
+       * where the large time represent the otherwise irrelevant npt/ntp time */
+      stream->rtp_delta = (GST_SECOND << 28) - rtp_clock_base;
+    } else {
+      clock_base = rtp_clock_base;
+    }
+
+    all_sync = TRUE;
+    for (walk = client->streams; walk; walk = g_slist_next (walk)) {
+      GstRtpBinStream *ostream = (GstRtpBinStream *) walk->data;
+
+      if (!ostream->have_sync) {
+        all_sync = FALSE;
+        continue;
+      }
+
+      /* change in current stream's base from previously init'ed value
+       * leads to reset of all stream's base */
+      if (stream != ostream && stream->clock_base >= 0 &&
+          (stream->clock_base != clock_base)) {
+        GST_DEBUG_OBJECT (bin, "reset upon clock base change");
+        ostream->clock_base = -100 * GST_SECOND;
+        ostream->rtp_delta = 0;
+      }
+
+      if (ostream->rt_delta < min)
+        min = ostream->rt_delta;
+      if (ostream->rtp_delta < rtp_min)
+        rtp_min = ostream->rtp_delta;
+    }
+
+    /* arrange to re-sync for each stream upon significant change,
+     * e.g. post-seek */
+    all_sync = all_sync && (stream->clock_base == clock_base);
+    stream->clock_base = clock_base;
+
+    /* may need init performed above later on, but nothing more to do now */
+    if (client->nstreams <= 1)
+      return;
+
+    GST_DEBUG_OBJECT (bin, "client %p min delta %" G_GINT64_FORMAT
+        " all sync %d", client, min, all_sync);
+    GST_DEBUG_OBJECT (bin, "rtcp sync mode %d, use_rtp %d", rtcp_sync, use_rtp);
+
+    switch (rtcp_sync) {
+      case GST_RTP_BIN_RTCP_SYNC_RTP:
+        if (!use_rtp)
+          break;
+        GST_DEBUG_OBJECT (bin, "using rtp generated reports; "
+            "client %p min rtp delta %" G_GINT64_FORMAT, client, rtp_min);
+        /* fall-through */
+      case GST_RTP_BIN_RTCP_SYNC_INITIAL:
+        /* if all have been synced already, do not bother further */
+        if (all_sync) {
+          GST_DEBUG_OBJECT (bin, "all streams already synced; done");
+          return;
+        }
+        break;
+      default:
+        break;
+    }
+
+    /* bail out if we adjusted recently enough */
+    if (all_sync && (ntpnstime - bin->priv->last_ntpnstime) <
+        bin->rtcp_sync_interval * GST_MSECOND) {
+      GST_DEBUG_OBJECT (bin, "discarding RTCP sender packet for sync; "
+          "previous sender info too recent "
+          "(previous NTP %" G_GUINT64_FORMAT ")", bin->priv->last_ntpnstime);
+      return;
+    }
+    bin->priv->last_ntpnstime = ntpnstime;
+
+    /* calculate offsets for each stream */
+    for (walk = client->streams; walk; walk = g_slist_next (walk)) {
+      GstRtpBinStream *ostream = (GstRtpBinStream *) walk->data;
+      gint64 ts_offset;
+
+      /* ignore streams for which we didn't receive an SR packet yet, we
+       * can't synchronize them yet. We can however sync other streams just
+       * fine. */
+      if (!ostream->have_sync)
+        continue;
+
+      /* calculate offset to our reference stream, this should always give a
+       * positive number. */
+      if (use_rtp)
+        ts_offset = ostream->rtp_delta - rtp_min;
+      else
+        ts_offset = ostream->rt_delta - min;
+
+      stream_set_ts_offset (bin, ostream, ts_offset, bin->max_ts_offset,
+          MIN_TS_OFFSET, TRUE);
+    }
+  }
+  gst_rtp_bin_send_sync_event (stream);
+
+  return;
+}
+
+#define GST_RTCP_BUFFER_FOR_PACKETS(b,buffer,packet) \
+  for ((b) = gst_rtcp_buffer_get_first_packet ((buffer), (packet)); (b); \
+          (b) = gst_rtcp_packet_move_to_next ((packet)))
+
+#define GST_RTCP_SDES_FOR_ITEMS(b,packet) \
+  for ((b) = gst_rtcp_packet_sdes_first_item ((packet)); (b); \
+          (b) = gst_rtcp_packet_sdes_next_item ((packet)))
+
+#define GST_RTCP_SDES_FOR_ENTRIES(b,packet) \
+  for ((b) = gst_rtcp_packet_sdes_first_entry ((packet)); (b); \
+          (b) = gst_rtcp_packet_sdes_next_entry ((packet)))
+
+static void
+gst_rtp_bin_handle_sync (GstElement * jitterbuffer, GstStructure * s,
+    GstRtpBinStream * stream)
+{
+  GstRtpBin *bin;
+  GstRTCPPacket packet;
+  guint32 ssrc;
+  guint64 ntptime;
+  gboolean have_sr, have_sdes;
+  gboolean more;
+  guint64 base_rtptime;
+  guint64 base_time;
+  guint clock_rate;
+  guint64 clock_base;
+  guint64 extrtptime;
+  GstBuffer *buffer;
+  GstRTCPBuffer rtcp = { NULL, };
+
+  bin = stream->bin;
+
+  GST_DEBUG_OBJECT (bin, "sync handler called");
+
+  /* get the last relation between the rtp timestamps and the gstreamer
+   * timestamps. We get this info directly from the jitterbuffer which
+   * constructs gstreamer timestamps from rtp timestamps and so it know exactly
+   * what the current situation is. */
+  base_rtptime =
+      g_value_get_uint64 (gst_structure_get_value (s, "base-rtptime"));
+  base_time = g_value_get_uint64 (gst_structure_get_value (s, "base-time"));
+  clock_rate = g_value_get_uint (gst_structure_get_value (s, "clock-rate"));
+  clock_base = g_value_get_uint64 (gst_structure_get_value (s, "clock-base"));
+  extrtptime =
+      g_value_get_uint64 (gst_structure_get_value (s, "sr-ext-rtptime"));
+  buffer = gst_value_get_buffer (gst_structure_get_value (s, "sr-buffer"));
+
+  have_sr = FALSE;
+  have_sdes = FALSE;
+
+  gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp);
+
+  GST_RTCP_BUFFER_FOR_PACKETS (more, &rtcp, &packet) {
+    /* first packet must be SR or RR or else the validate would have failed */
+    switch (gst_rtcp_packet_get_type (&packet)) {
+      case GST_RTCP_TYPE_SR:
+        /* only parse first. There is only supposed to be one SR in the packet
+         * but we will deal with malformed packets gracefully */
+        if (have_sr)
+          break;
+        /* get NTP and RTP times */
+        gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, &ntptime, NULL,
+            NULL, NULL);
+
+        GST_DEBUG_OBJECT (bin, "received sync packet from SSRC %08x", ssrc);
+        /* ignore SR that is not ours */
+        if (ssrc != stream->ssrc)
+          continue;
+
+        have_sr = TRUE;
+        break;
+      case GST_RTCP_TYPE_SDES:
+      {
+        gboolean more_items, more_entries;
+
+        /* only deal with first SDES, there is only supposed to be one SDES in
+         * the RTCP packet but we deal with bad packets gracefully. Also bail
+         * out if we have not seen an SR item yet. */
+        if (have_sdes || !have_sr)
+          break;
+
+        GST_RTCP_SDES_FOR_ITEMS (more_items, &packet) {
+          /* skip items that are not about the SSRC of the sender */
+          if (gst_rtcp_packet_sdes_get_ssrc (&packet) != ssrc)
+            continue;
+
+          /* find the CNAME entry */
+          GST_RTCP_SDES_FOR_ENTRIES (more_entries, &packet) {
+            GstRTCPSDESType type;
+            guint8 len;
+            guint8 *data;
+
+            gst_rtcp_packet_sdes_get_entry (&packet, &type, &len, &data);
+
+            if (type == GST_RTCP_SDES_CNAME) {
+              GST_RTP_BIN_LOCK (bin);
+              /* associate the stream to CNAME */
+              gst_rtp_bin_associate (bin, stream, len, data,
+                  ntptime, extrtptime, base_rtptime, base_time, clock_rate,
+                  clock_base);
+              GST_RTP_BIN_UNLOCK (bin);
+            }
+          }
+        }
+        have_sdes = TRUE;
+        break;
+      }
+      default:
+        /* we can ignore these packets */
+        break;
+    }
+  }
+  gst_rtcp_buffer_unmap (&rtcp);
+}
+
+/* create a new stream with @ssrc in @session. Must be called with
+ * RTP_SESSION_LOCK. */
+static GstRtpBinStream *
+create_stream (GstRtpBinSession * session, guint32 ssrc)
+{
+  GstElement *buffer, *demux = NULL;
+  GstRtpBinStream *stream;
+  GstRtpBin *rtpbin;
+  GstState target;
+
+  rtpbin = session->bin;
+
+  if (g_slist_length (session->streams) >= rtpbin->max_streams)
+    goto max_streams;
+
+  if (!(buffer = gst_element_factory_make ("rtpjitterbuffer", NULL)))
+    goto no_jitterbuffer;
+
+  if (!rtpbin->ignore_pt)
+    if (!(demux = gst_element_factory_make ("rtpptdemux", NULL)))
+      goto no_demux;
+
+  stream = g_new0 (GstRtpBinStream, 1);
+  stream->ssrc = ssrc;
+  stream->bin = rtpbin;
+  stream->session = session;
+  stream->buffer = buffer;
+  stream->demux = demux;
+
+  stream->have_sync = FALSE;
+  stream->rt_delta = 0;
+  stream->rtp_delta = 0;
+  stream->percent = 100;
+  stream->clock_base = -100 * GST_SECOND;
+  session->streams = g_slist_prepend (session->streams, stream);
+
+  /* provide clock_rate to the jitterbuffer when needed */
+  stream->buffer_ptreq_sig = g_signal_connect (buffer, "request-pt-map",
+      (GCallback) pt_map_requested, session);
+  stream->buffer_ntpstop_sig = g_signal_connect (buffer, "on-npt-stop",
+      (GCallback) on_npt_stop, stream);
+
+  g_object_set_data (G_OBJECT (buffer), "GstRTPBin.session", session);
+  g_object_set_data (G_OBJECT (buffer), "GstRTPBin.stream", stream);
+
+  /* configure latency and packet lost */
+  g_object_set (buffer, "latency", rtpbin->latency_ms, NULL);
+  g_object_set (buffer, "drop-on-latency", rtpbin->drop_on_latency, NULL);
+  g_object_set (buffer, "do-lost", rtpbin->do_lost, NULL);
+  g_object_set (buffer, "mode", rtpbin->buffer_mode, NULL);
+  g_object_set (buffer, "do-retransmission", rtpbin->do_retransmission, NULL);
+  g_object_set (buffer, "max-rtcp-rtp-time-diff",
+      rtpbin->max_rtcp_rtp_time_diff, NULL);
+  g_object_set (buffer, "max-dropout-time", rtpbin->max_dropout_time,
+      "max-misorder-time", rtpbin->max_misorder_time, NULL);
+  g_object_set (buffer, "rfc7273-sync", rtpbin->rfc7273_sync, NULL);
+  g_object_set (buffer, "max-ts-offset-adjustment",
+      rtpbin->max_ts_offset_adjustment, NULL);
+
+  g_signal_emit (rtpbin, gst_rtp_bin_signals[SIGNAL_NEW_JITTERBUFFER], 0,
+      buffer, session->id, ssrc);
+
+  if (!rtpbin->ignore_pt)
+    gst_bin_add (GST_BIN_CAST (rtpbin), demux);
+  gst_bin_add (GST_BIN_CAST (rtpbin), buffer);
+
+  /* link stuff */
+  if (demux)
+    gst_element_link_pads_full (buffer, "src", demux, "sink",
+        GST_PAD_LINK_CHECK_NOTHING);
+
+  if (rtpbin->buffering) {
+    guint64 last_out;
+
+    GST_INFO_OBJECT (rtpbin,
+        "bin is buffering, set jitterbuffer as not active");
+    g_signal_emit_by_name (buffer, "set-active", FALSE, (gint64) 0, &last_out);
+  }
+
+
+  GST_OBJECT_LOCK (rtpbin);
+  target = GST_STATE_TARGET (rtpbin);
+  GST_OBJECT_UNLOCK (rtpbin);
+
+  /* from sink to source */
+  if (demux)
+    gst_element_set_state (demux, target);
+
+  gst_element_set_state (buffer, target);
+
+  return stream;
+
+  /* ERRORS */
+max_streams:
+  {
+    GST_WARNING_OBJECT (rtpbin, "stream exeeds maximum (%d)",
+        rtpbin->max_streams);
+    return NULL;
+  }
+no_jitterbuffer:
+  {
+    g_warning ("rtpbin: could not create rtpjitterbuffer element");
+    return NULL;
+  }
+no_demux:
+  {
+    gst_object_unref (buffer);
+    g_warning ("rtpbin: could not create rtpptdemux element");
+    return NULL;
+  }
+}
+
+/* called with RTP_BIN_LOCK */
+static void
+free_stream (GstRtpBinStream * stream, GstRtpBin * bin)
+{
+  GSList *clients, *next_client;
+
+  GST_DEBUG_OBJECT (bin, "freeing stream %p", stream);
+
+  if (stream->demux) {
+    g_signal_handler_disconnect (stream->demux, stream->demux_newpad_sig);
+    g_signal_handler_disconnect (stream->demux, stream->demux_ptreq_sig);
+    g_signal_handler_disconnect (stream->demux, stream->demux_ptchange_sig);
+  }
+  g_signal_handler_disconnect (stream->buffer, stream->buffer_handlesync_sig);
+  g_signal_handler_disconnect (stream->buffer, stream->buffer_ptreq_sig);
+  g_signal_handler_disconnect (stream->buffer, stream->buffer_ntpstop_sig);
+
+  if (stream->demux)
+    gst_element_set_locked_state (stream->demux, TRUE);
+  gst_element_set_locked_state (stream->buffer, TRUE);
+
+  if (stream->demux)
+    gst_element_set_state (stream->demux, GST_STATE_NULL);
+  gst_element_set_state (stream->buffer, GST_STATE_NULL);
+
+  /* now remove this signal, we need this while going to NULL because it to
+   * do some cleanups */
+  if (stream->demux)
+    g_signal_handler_disconnect (stream->demux, stream->demux_padremoved_sig);
+
+  gst_bin_remove (GST_BIN_CAST (bin), stream->buffer);
+  if (stream->demux)
+    gst_bin_remove (GST_BIN_CAST (bin), stream->demux);
+
+  for (clients = bin->clients; clients; clients = next_client) {
+    GstRtpBinClient *client = (GstRtpBinClient *) clients->data;
+    GSList *streams, *next_stream;
+
+    next_client = g_slist_next (clients);
+
+    for (streams = client->streams; streams; streams = next_stream) {
+      GstRtpBinStream *ostream = (GstRtpBinStream *) streams->data;
+
+      next_stream = g_slist_next (streams);
+
+      if (ostream == stream) {
+        client->streams = g_slist_delete_link (client->streams, streams);
+        /* If this was the last stream belonging to this client,
+         * clean up the client. */
+        if (--client->nstreams == 0) {
+          bin->clients = g_slist_delete_link (bin->clients, clients);
+          free_client (client, bin);
+          break;
+        }
+      }
+    }
+  }
+  g_free (stream);
+}
+
+/* GObject vmethods */
+static void gst_rtp_bin_dispose (GObject * object);
+static void gst_rtp_bin_finalize (GObject * object);
+static void gst_rtp_bin_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_bin_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+/* GstElement vmethods */
+static GstStateChangeReturn gst_rtp_bin_change_state (GstElement * element,
+    GstStateChange transition);
+static GstPad *gst_rtp_bin_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
+static void gst_rtp_bin_release_pad (GstElement * element, GstPad * pad);
+static void gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message);
+
+#define gst_rtp_bin_parent_class parent_class
+G_DEFINE_TYPE (GstRtpBin, gst_rtp_bin, GST_TYPE_BIN);
+
+static gboolean
+_gst_element_accumulator (GSignalInvocationHint * ihint,
+    GValue * return_accu, const GValue * handler_return, gpointer dummy)
+{
+  GstElement *element;
+
+  element = g_value_get_object (handler_return);
+  GST_DEBUG ("got element %" GST_PTR_FORMAT, element);
+
+  if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
+    g_value_set_object (return_accu, element);
+
+  /* stop emission if we have an element */
+  return (element == NULL);
+}
+
+static gboolean
+_gst_caps_accumulator (GSignalInvocationHint * ihint,
+    GValue * return_accu, const GValue * handler_return, gpointer dummy)
+{
+  GstCaps *caps;
+
+  caps = g_value_get_boxed (handler_return);
+  GST_DEBUG ("got caps %" GST_PTR_FORMAT, caps);
+
+  if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
+    g_value_set_boxed (return_accu, caps);
+
+  /* stop emission if we have a caps */
+  return (caps == NULL);
+}
+
+static void
+gst_rtp_bin_class_init (GstRtpBinClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBinClass *gstbin_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbin_class = (GstBinClass *) klass;
+
+  g_type_class_add_private (klass, sizeof (GstRtpBinPrivate));
+
+  gobject_class->dispose = gst_rtp_bin_dispose;
+  gobject_class->finalize = gst_rtp_bin_finalize;
+  gobject_class->set_property = gst_rtp_bin_set_property;
+  gobject_class->get_property = gst_rtp_bin_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_LATENCY,
+      g_param_spec_uint ("latency", "Buffer latency in ms",
+          "Default amount of ms to buffer in the jitterbuffers", 0,
+          G_MAXUINT, DEFAULT_LATENCY_MS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DROP_ON_LATENCY,
+      g_param_spec_boolean ("drop-on-latency",
+          "Drop buffers when maximum latency is reached",
+          "Tells the jitterbuffer to never exceed the given latency in size",
+          DEFAULT_DROP_ON_LATENCY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpBin::request-pt-map:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @pt: the pt
+   *
+   * Request the payload type as #GstCaps for @pt in @session.
+   */
+  gst_rtp_bin_signals[SIGNAL_REQUEST_PT_MAP] =
+      g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, request_pt_map),
+      _gst_caps_accumulator, NULL, g_cclosure_marshal_generic, GST_TYPE_CAPS,
+      2, G_TYPE_UINT, G_TYPE_UINT);
+
+    /**
+   * GstRtpBin::payload-type-change:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @pt: the pt
+   *
+   * Signal that the current payload type changed to @pt in @session.
+   */
+  gst_rtp_bin_signals[SIGNAL_PAYLOAD_TYPE_CHANGE] =
+      g_signal_new ("payload-type-change", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, payload_type_change),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+
+  /**
+   * GstRtpBin::clear-pt-map:
+   * @rtpbin: the object which received the signal
+   *
+   * Clear all previously cached pt-mapping obtained with
+   * #GstRtpBin::request-pt-map.
+   */
+  gst_rtp_bin_signals[SIGNAL_CLEAR_PT_MAP] =
+      g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpBinClass,
+          clear_pt_map), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
+      0, G_TYPE_NONE);
+
+  /**
+   * GstRtpBin::reset-sync:
+   * @rtpbin: the object which received the signal
+   *
+   * Reset all currently configured lip-sync parameters and require new SR
+   * packets for all streams before lip-sync is attempted again.
+   */
+  gst_rtp_bin_signals[SIGNAL_RESET_SYNC] =
+      g_signal_new ("reset-sync", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpBinClass,
+          reset_sync), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
+      0, G_TYPE_NONE);
+
+  /**
+   * GstRtpBin::get-session:
+   * @rtpbin: the object which received the signal
+   * @id: the session id
+   *
+   * Request the related GstRtpSession as #GstElement related with session @id.
+   *
+   * Since: 1.8
+   */
+  gst_rtp_bin_signals[SIGNAL_GET_SESSION] =
+      g_signal_new ("get-session", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpBinClass,
+          get_session), NULL, NULL, g_cclosure_marshal_generic,
+      GST_TYPE_ELEMENT, 1, G_TYPE_UINT);
+
+  /**
+   * GstRtpBin::get-internal-session:
+   * @rtpbin: the object which received the signal
+   * @id: the session id
+   *
+   * Request the internal RTPSession object as #GObject in session @id.
+   */
+  gst_rtp_bin_signals[SIGNAL_GET_INTERNAL_SESSION] =
+      g_signal_new ("get-internal-session", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpBinClass,
+          get_internal_session), NULL, NULL, g_cclosure_marshal_generic,
+      RTP_TYPE_SESSION, 1, G_TYPE_UINT);
+
+  /**
+   * GstRtpBin::on-new-ssrc:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC
+   *
+   * Notify of a new SSRC that entered @session.
+   */
+  gst_rtp_bin_signals[SIGNAL_ON_NEW_SSRC] =
+      g_signal_new ("on-new-ssrc", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_new_ssrc),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+  /**
+   * GstRtpBin::on-ssrc-collision:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC
+   *
+   * Notify when we have an SSRC collision
+   */
+  gst_rtp_bin_signals[SIGNAL_ON_SSRC_COLLISION] =
+      g_signal_new ("on-ssrc-collision", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_ssrc_collision),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+  /**
+   * GstRtpBin::on-ssrc-validated:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC
+   *
+   * Notify of a new SSRC that became validated.
+   */
+  gst_rtp_bin_signals[SIGNAL_ON_SSRC_VALIDATED] =
+      g_signal_new ("on-ssrc-validated", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_ssrc_validated),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+  /**
+   * GstRtpBin::on-ssrc-active:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC
+   *
+   * Notify of a SSRC that is active, i.e., sending RTCP.
+   */
+  gst_rtp_bin_signals[SIGNAL_ON_SSRC_ACTIVE] =
+      g_signal_new ("on-ssrc-active", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_ssrc_active),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+  /**
+   * GstRtpBin::on-ssrc-sdes:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC
+   *
+   * Notify of a SSRC that is active, i.e., sending RTCP.
+   */
+  gst_rtp_bin_signals[SIGNAL_ON_SSRC_SDES] =
+      g_signal_new ("on-ssrc-sdes", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_ssrc_sdes),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+
+  /**
+   * GstRtpBin::on-bye-ssrc:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC
+   *
+   * Notify of an SSRC that became inactive because of a BYE packet.
+   */
+  gst_rtp_bin_signals[SIGNAL_ON_BYE_SSRC] =
+      g_signal_new ("on-bye-ssrc", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_bye_ssrc),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+  /**
+   * GstRtpBin::on-bye-timeout:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC
+   *
+   * Notify of an SSRC that has timed out because of BYE
+   */
+  gst_rtp_bin_signals[SIGNAL_ON_BYE_TIMEOUT] =
+      g_signal_new ("on-bye-timeout", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_bye_timeout),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+  /**
+   * GstRtpBin::on-timeout:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC
+   *
+   * Notify of an SSRC that has timed out
+   */
+  gst_rtp_bin_signals[SIGNAL_ON_TIMEOUT] =
+      g_signal_new ("on-timeout", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_timeout),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+  /**
+   * GstRtpBin::on-sender-timeout:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC
+   *
+   * Notify of a sender SSRC that has timed out and became a receiver
+   */
+  gst_rtp_bin_signals[SIGNAL_ON_SENDER_TIMEOUT] =
+      g_signal_new ("on-sender-timeout", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_sender_timeout),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+
+  /**
+   * GstRtpBin::on-npt-stop:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC
+   *
+   * Notify that SSRC sender has sent data up to the configured NPT stop time.
+   */
+  gst_rtp_bin_signals[SIGNAL_ON_NPT_STOP] =
+      g_signal_new ("on-npt-stop", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_npt_stop),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+
+  /**
+   * GstRtpBin::request-rtp-encoder:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   *
+   * Request an RTP encoder element for the given @session. The encoder
+   * element will be added to the bin if not previously added.
+   *
+   * If no handler is connected, no encoder will be used.
+   *
+   * Since: 1.4
+   */
+  gst_rtp_bin_signals[SIGNAL_REQUEST_RTP_ENCODER] =
+      g_signal_new ("request-rtp-encoder", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
+          request_rtp_encoder), _gst_element_accumulator, NULL,
+      g_cclosure_marshal_generic, GST_TYPE_ELEMENT, 1, G_TYPE_UINT);
+
+  /**
+   * GstRtpBin::request-rtp-decoder:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   *
+   * Request an RTP decoder element for the given @session. The decoder
+   * element will be added to the bin if not previously added.
+   *
+   * If no handler is connected, no encoder will be used.
+   *
+   * Since: 1.4
+   */
+  gst_rtp_bin_signals[SIGNAL_REQUEST_RTP_DECODER] =
+      g_signal_new ("request-rtp-decoder", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
+          request_rtp_decoder), _gst_element_accumulator, NULL,
+      g_cclosure_marshal_generic, GST_TYPE_ELEMENT, 1, G_TYPE_UINT);
+
+  /**
+   * GstRtpBin::request-rtcp-encoder:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   *
+   * Request an RTCP encoder element for the given @session. The encoder
+   * element will be added to the bin if not previously added.
+   *
+   * If no handler is connected, no encoder will be used.
+   *
+   * Since: 1.4
+   */
+  gst_rtp_bin_signals[SIGNAL_REQUEST_RTCP_ENCODER] =
+      g_signal_new ("request-rtcp-encoder", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
+          request_rtcp_encoder), _gst_element_accumulator, NULL,
+      g_cclosure_marshal_generic, GST_TYPE_ELEMENT, 1, G_TYPE_UINT);
+
+  /**
+   * GstRtpBin::request-rtcp-decoder:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   *
+   * Request an RTCP decoder element for the given @session. The decoder
+   * element will be added to the bin if not previously added.
+   *
+   * If no handler is connected, no encoder will be used.
+   *
+   * Since: 1.4
+   */
+  gst_rtp_bin_signals[SIGNAL_REQUEST_RTCP_DECODER] =
+      g_signal_new ("request-rtcp-decoder", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
+          request_rtcp_decoder), _gst_element_accumulator, NULL,
+      g_cclosure_marshal_generic, GST_TYPE_ELEMENT, 1, G_TYPE_UINT);
+
+  /**
+   * GstRtpBin::new-jitterbuffer:
+   * @rtpbin: the object which received the signal
+   * @jitterbuffer: the new jitterbuffer
+   * @session: the session
+   * @ssrc: the SSRC
+   *
+   * Notify that a new @jitterbuffer was created for @session and @ssrc.
+   * This signal can, for example, be used to configure @jitterbuffer.
+   *
+   * Since: 1.4
+   */
+  gst_rtp_bin_signals[SIGNAL_NEW_JITTERBUFFER] =
+      g_signal_new ("new-jitterbuffer", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
+          new_jitterbuffer), NULL, NULL, g_cclosure_marshal_generic,
+      G_TYPE_NONE, 3, GST_TYPE_ELEMENT, G_TYPE_UINT, G_TYPE_UINT);
+
+  /**
+   * GstRtpBin::request-aux-sender:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   *
+   * Request an AUX sender element for the given @session. The AUX
+   * element will be added to the bin.
+   *
+   * If no handler is connected, no AUX element will be used.
+   *
+   * Since: 1.4
+   */
+  gst_rtp_bin_signals[SIGNAL_REQUEST_AUX_SENDER] =
+      g_signal_new ("request-aux-sender", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
+          request_aux_sender), _gst_element_accumulator, NULL,
+      g_cclosure_marshal_generic, GST_TYPE_ELEMENT, 1, G_TYPE_UINT);
+  /**
+   * GstRtpBin::request-aux-receiver:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   *
+   * Request an AUX receiver element for the given @session. The AUX
+   * element will be added to the bin.
+   *
+   * If no handler is connected, no AUX element will be used.
+   *
+   * Since: 1.4
+   */
+  gst_rtp_bin_signals[SIGNAL_REQUEST_AUX_RECEIVER] =
+      g_signal_new ("request-aux-receiver", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
+          request_aux_receiver), _gst_element_accumulator, NULL,
+      g_cclosure_marshal_generic, GST_TYPE_ELEMENT, 1, G_TYPE_UINT);
+  /**
+   * GstRtpBin::on-new-sender-ssrc:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the sender SSRC
+   *
+   * Notify of a new sender SSRC that entered @session.
+   *
+   * Since: 1.8
+   */
+  gst_rtp_bin_signals[SIGNAL_ON_NEW_SENDER_SSRC] =
+      g_signal_new ("on-new-sender-ssrc", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_new_sender_ssrc),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+  /**
+   * GstRtpBin::on-sender-ssrc-active:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the sender SSRC
+   *
+   * Notify of a sender SSRC that is active, i.e., sending RTCP.
+   *
+   * Since: 1.8
+   */
+  gst_rtp_bin_signals[SIGNAL_ON_SENDER_SSRC_ACTIVE] =
+      g_signal_new ("on-sender-ssrc-active", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
+          on_sender_ssrc_active), NULL, NULL, g_cclosure_marshal_generic,
+      G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
+
+
+  /**
+   * GstRtpBin::on-bundled-ssrc:
+   * @rtpbin: the object which received the signal
+   * @ssrc: the bundled SSRC
+   *
+   * Notify of a new incoming bundled SSRC. If no handler is connected to the
+   * signal then the #GstRtpSession created for the recv_rtp_sink_\%u
+   * request pad will be managing this new SSRC. However if there is a handler
+   * connected then the application can decided to dispatch this new stream to
+   * another session by providing its ID as return value of the handler. This
+   * can be particularly useful to keep retransmission SSRCs grouped with the
+   * session for which they handle retransmission.
+   *
+   * Since: 1.12
+   */
+  gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC] =
+      g_signal_new ("on-bundled-ssrc", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
+          on_bundled_ssrc), NULL, NULL,
+      g_cclosure_marshal_generic, G_TYPE_UINT, 1, G_TYPE_UINT);
+
+
+  g_object_class_install_property (gobject_class, PROP_SDES,
+      g_param_spec_boxed ("sdes", "SDES",
+          "The SDES items of this session",
+          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DO_LOST,
+      g_param_spec_boolean ("do-lost", "Do Lost",
+          "Send an event downstream when a packet is lost", DEFAULT_DO_LOST,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_AUTOREMOVE,
+      g_param_spec_boolean ("autoremove", "Auto Remove",
+          "Automatically remove timed out sources", DEFAULT_AUTOREMOVE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_IGNORE_PT,
+      g_param_spec_boolean ("ignore-pt", "Ignore PT",
+          "Do not demultiplex based on PT values", DEFAULT_IGNORE_PT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_USE_PIPELINE_CLOCK,
+      g_param_spec_boolean ("use-pipeline-clock", "Use pipeline clock",
+          "Use the pipeline running-time to set the NTP time in the RTCP SR messages "
+          "(DEPRECATED: Use ntp-time-source property)",
+          DEFAULT_USE_PIPELINE_CLOCK,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
+  /**
+   * GstRtpBin:buffer-mode:
+   *
+   * Control the buffering and timestamping mode used by the jitterbuffer.
+   */
+  g_object_class_install_property (gobject_class, PROP_BUFFER_MODE,
+      g_param_spec_enum ("buffer-mode", "Buffer Mode",
+          "Control the buffering algorithm in use", RTP_TYPE_JITTER_BUFFER_MODE,
+          DEFAULT_BUFFER_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRtpBin:ntp-sync:
+   *
+   * Set the NTP time from the sender reports as the running-time on the
+   * buffers. When both the sender and receiver have sychronized
+   * running-time, i.e. when the clock and base-time is shared
+   * between the receivers and the and the senders, this option can be
+   * used to synchronize receivers on multiple machines.
+   */
+  g_object_class_install_property (gobject_class, PROP_NTP_SYNC,
+      g_param_spec_boolean ("ntp-sync", "Sync on NTP clock",
+          "Synchronize received streams to the NTP clock", DEFAULT_NTP_SYNC,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpBin:rtcp-sync:
+   *
+   * If not synchronizing (directly) to the NTP clock, determines how to sync
+   * the various streams.
+   */
+  g_object_class_install_property (gobject_class, PROP_RTCP_SYNC,
+      g_param_spec_enum ("rtcp-sync", "RTCP Sync",
+          "Use of RTCP SR in synchronization", GST_RTP_BIN_RTCP_SYNC_TYPE,
+          DEFAULT_RTCP_SYNC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpBin:rtcp-sync-interval:
+   *
+   * Determines how often to sync streams using RTCP data.
+   */
+  g_object_class_install_property (gobject_class, PROP_RTCP_SYNC_INTERVAL,
+      g_param_spec_uint ("rtcp-sync-interval", "RTCP Sync Interval",
+          "RTCP SR interval synchronization (ms) (0 = always)",
+          0, G_MAXUINT, DEFAULT_RTCP_SYNC_INTERVAL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DO_SYNC_EVENT,
+      g_param_spec_boolean ("do-sync-event", "Do Sync Event",
+          "Send event downstream when a stream is synchronized to the sender",
+          DEFAULT_DO_SYNC_EVENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpBin:do-retransmission:
+   *
+   * Enables RTP retransmission on all streams. To control retransmission on
+   * a per-SSRC basis, connect to the #GstRtpBin::new-jitterbuffer signal and
+   * set the #GstRtpJitterBuffer::do-retransmission property on the
+   * #GstRtpJitterBuffer object instead.
+   */
+  g_object_class_install_property (gobject_class, PROP_DO_RETRANSMISSION,
+      g_param_spec_boolean ("do-retransmission", "Do retransmission",
+          "Enable retransmission on all streams",
+          DEFAULT_DO_RETRANSMISSION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpBin:rtp-profile:
+   *
+   * Sets the default RTP profile of newly created RTP sessions. The
+   * profile can be changed afterwards on a per-session basis.
+   */
+  g_object_class_install_property (gobject_class, PROP_RTP_PROFILE,
+      g_param_spec_enum ("rtp-profile", "RTP Profile",
+          "Default RTP profile of newly created sessions",
+          GST_TYPE_RTP_PROFILE, DEFAULT_RTP_PROFILE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NTP_TIME_SOURCE,
+      g_param_spec_enum ("ntp-time-source", "NTP Time Source",
+          "NTP time source for RTCP packets",
+          gst_rtp_ntp_time_source_get_type (), DEFAULT_NTP_TIME_SOURCE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RTCP_SYNC_SEND_TIME,
+      g_param_spec_boolean ("rtcp-sync-send-time", "RTCP Sync Send Time",
+          "Use send time or capture time for RTCP sync "
+          "(TRUE = send time, FALSE = capture time)",
+          DEFAULT_RTCP_SYNC_SEND_TIME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_RTCP_RTP_TIME_DIFF,
+      g_param_spec_int ("max-rtcp-rtp-time-diff", "Max RTCP RTP Time Diff",
+          "Maximum amount of time in ms that the RTP time in RTCP SRs "
+          "is allowed to be ahead (-1 disabled)", -1, G_MAXINT,
+          DEFAULT_MAX_RTCP_RTP_TIME_DIFF,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_DROPOUT_TIME,
+      g_param_spec_uint ("max-dropout-time", "Max dropout time",
+          "The maximum time (milliseconds) of missing packets tolerated.",
+          0, G_MAXUINT, DEFAULT_MAX_DROPOUT_TIME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_MISORDER_TIME,
+      g_param_spec_uint ("max-misorder-time", "Max misorder time",
+          "The maximum time (milliseconds) of misordered packets tolerated.",
+          0, G_MAXUINT, DEFAULT_MAX_MISORDER_TIME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RFC7273_SYNC,
+      g_param_spec_boolean ("rfc7273-sync", "Sync on RFC7273 clock",
+          "Synchronize received streams to the RFC7273 clock "
+          "(requires clock and offset to be provided)", DEFAULT_RFC7273_SYNC,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_STREAMS,
+      g_param_spec_uint ("max-streams", "Max Streams",
+          "The maximum number of streams to create for one session",
+          0, G_MAXUINT, DEFAULT_MAX_STREAMS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpBin:max-ts-offset-adjustment:
+   *
+   * Syncing time stamps to NTP time adds a time offset. This parameter
+   * specifies the maximum number of nanoseconds per frame that this time offset
+   * may be adjusted with. This is used to avoid sudden large changes to time
+   * stamps.
+   */
+  g_object_class_install_property (gobject_class, PROP_MAX_TS_OFFSET_ADJUSTMENT,
+      g_param_spec_uint64 ("max-ts-offset-adjustment",
+          "Max Timestamp Offset Adjustment",
+          "The maximum number of nanoseconds per frame that time stamp offsets "
+          "may be adjusted (0 = no limit).", 0, G_MAXUINT64,
+          DEFAULT_MAX_TS_OFFSET_ADJUSTMENT, G_PARAM_READWRITE |
+          G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpBin:max-ts-offset:
+   *
+   * Used to set an upper limit of how large a time offset may be. This
+   * is used to protect against unrealistic values as a result of either
+   * client,server or clock issues.
+   */
+  g_object_class_install_property (gobject_class, PROP_MAX_TS_OFFSET,
+      g_param_spec_int64 ("max-ts-offset", "Max TS Offset",
+          "The maximum absolute value of the time offset in (nanoseconds). "
+          "Note, if the ntp-sync parameter is set the default value is "
+          "changed to 0 (no limit)", 0, G_MAXINT64, DEFAULT_MAX_TS_OFFSET,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_bin_change_state);
+  gstelement_class->request_new_pad =
+      GST_DEBUG_FUNCPTR (gst_rtp_bin_request_new_pad);
+  gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_bin_release_pad);
+
+  /* sink pads */
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &rtpbin_recv_rtp_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &rtpbin_recv_rtcp_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &rtpbin_send_rtp_sink_template);
+
+  /* src pads */
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &rtpbin_recv_rtp_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &rtpbin_send_rtcp_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &rtpbin_send_rtp_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP Bin",
+      "Filter/Network/RTP",
+      "Real-Time Transport Protocol bin",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstbin_class->handle_message = GST_DEBUG_FUNCPTR (gst_rtp_bin_handle_message);
+
+  klass->clear_pt_map = GST_DEBUG_FUNCPTR (gst_rtp_bin_clear_pt_map);
+  klass->reset_sync = GST_DEBUG_FUNCPTR (gst_rtp_bin_reset_sync);
+  klass->get_session = GST_DEBUG_FUNCPTR (gst_rtp_bin_get_session);
+  klass->get_internal_session =
+      GST_DEBUG_FUNCPTR (gst_rtp_bin_get_internal_session);
+  klass->request_rtp_encoder = GST_DEBUG_FUNCPTR (gst_rtp_bin_request_encoder);
+  klass->request_rtp_decoder = GST_DEBUG_FUNCPTR (gst_rtp_bin_request_decoder);
+  klass->request_rtcp_encoder = GST_DEBUG_FUNCPTR (gst_rtp_bin_request_encoder);
+  klass->request_rtcp_decoder = GST_DEBUG_FUNCPTR (gst_rtp_bin_request_decoder);
+
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_bin_debug, "rtpbin", 0, "RTP bin");
+}
+
+static void
+gst_rtp_bin_init (GstRtpBin * rtpbin)
+{
+  gchar *cname;
+
+  rtpbin->priv = GST_RTP_BIN_GET_PRIVATE (rtpbin);
+  g_mutex_init (&rtpbin->priv->bin_lock);
+  g_mutex_init (&rtpbin->priv->dyn_lock);
+
+  rtpbin->latency_ms = DEFAULT_LATENCY_MS;
+  rtpbin->latency_ns = DEFAULT_LATENCY_MS * GST_MSECOND;
+  rtpbin->drop_on_latency = DEFAULT_DROP_ON_LATENCY;
+  rtpbin->do_lost = DEFAULT_DO_LOST;
+  rtpbin->ignore_pt = DEFAULT_IGNORE_PT;
+  rtpbin->ntp_sync = DEFAULT_NTP_SYNC;
+  rtpbin->rtcp_sync = DEFAULT_RTCP_SYNC;
+  rtpbin->rtcp_sync_interval = DEFAULT_RTCP_SYNC_INTERVAL;
+  rtpbin->priv->autoremove = DEFAULT_AUTOREMOVE;
+  rtpbin->buffer_mode = DEFAULT_BUFFER_MODE;
+  rtpbin->use_pipeline_clock = DEFAULT_USE_PIPELINE_CLOCK;
+  rtpbin->send_sync_event = DEFAULT_DO_SYNC_EVENT;
+  rtpbin->do_retransmission = DEFAULT_DO_RETRANSMISSION;
+  rtpbin->rtp_profile = DEFAULT_RTP_PROFILE;
+  rtpbin->ntp_time_source = DEFAULT_NTP_TIME_SOURCE;
+  rtpbin->rtcp_sync_send_time = DEFAULT_RTCP_SYNC_SEND_TIME;
+  rtpbin->max_rtcp_rtp_time_diff = DEFAULT_MAX_RTCP_RTP_TIME_DIFF;
+  rtpbin->max_dropout_time = DEFAULT_MAX_DROPOUT_TIME;
+  rtpbin->max_misorder_time = DEFAULT_MAX_MISORDER_TIME;
+  rtpbin->rfc7273_sync = DEFAULT_RFC7273_SYNC;
+  rtpbin->max_streams = DEFAULT_MAX_STREAMS;
+  rtpbin->max_ts_offset_adjustment = DEFAULT_MAX_TS_OFFSET_ADJUSTMENT;
+  rtpbin->max_ts_offset = DEFAULT_MAX_TS_OFFSET;
+  rtpbin->max_ts_offset_is_set = FALSE;
+
+  /* some default SDES entries */
+  cname = g_strdup_printf ("user%u@host-%x", g_random_int (), g_random_int ());
+  rtpbin->sdes = gst_structure_new ("application/x-rtp-source-sdes",
+      "cname", G_TYPE_STRING, cname, "tool", G_TYPE_STRING, "GStreamer", NULL);
+  g_free (cname);
+}
+
+static void
+gst_rtp_bin_dispose (GObject * object)
+{
+  GstRtpBin *rtpbin;
+
+  rtpbin = GST_RTP_BIN (object);
+
+  GST_RTP_BIN_LOCK (rtpbin);
+  GST_DEBUG_OBJECT (object, "freeing sessions");
+  g_slist_foreach (rtpbin->sessions, (GFunc) free_session, rtpbin);
+  g_slist_free (rtpbin->sessions);
+  rtpbin->sessions = NULL;
+  GST_RTP_BIN_UNLOCK (rtpbin);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_rtp_bin_finalize (GObject * object)
+{
+  GstRtpBin *rtpbin;
+
+  rtpbin = GST_RTP_BIN (object);
+
+  if (rtpbin->sdes)
+    gst_structure_free (rtpbin->sdes);
+
+  g_mutex_clear (&rtpbin->priv->bin_lock);
+  g_mutex_clear (&rtpbin->priv->dyn_lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gst_rtp_bin_set_sdes_struct (GstRtpBin * bin, const GstStructure * sdes)
+{
+  GSList *item;
+
+  if (sdes == NULL)
+    return;
+
+  GST_RTP_BIN_LOCK (bin);
+
+  GST_OBJECT_LOCK (bin);
+  if (bin->sdes)
+    gst_structure_free (bin->sdes);
+  bin->sdes = gst_structure_copy (sdes);
+  GST_OBJECT_UNLOCK (bin);
+
+  /* store in all sessions */
+  for (item = bin->sessions; item; item = g_slist_next (item)) {
+    GstRtpBinSession *session = item->data;
+    g_object_set (session->session, "sdes", sdes, NULL);
+  }
+
+  GST_RTP_BIN_UNLOCK (bin);
+}
+
+static GstStructure *
+gst_rtp_bin_get_sdes_struct (GstRtpBin * bin)
+{
+  GstStructure *result;
+
+  GST_OBJECT_LOCK (bin);
+  result = gst_structure_copy (bin->sdes);
+  GST_OBJECT_UNLOCK (bin);
+
+  return result;
+}
+
+static void
+gst_rtp_bin_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpBin *rtpbin;
+
+  rtpbin = GST_RTP_BIN (object);
+
+  switch (prop_id) {
+    case PROP_LATENCY:
+      GST_RTP_BIN_LOCK (rtpbin);
+      rtpbin->latency_ms = g_value_get_uint (value);
+      rtpbin->latency_ns = rtpbin->latency_ms * GST_MSECOND;
+      GST_RTP_BIN_UNLOCK (rtpbin);
+      /* propagate the property down to the jitterbuffer */
+      gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin, "latency", value);
+      break;
+    case PROP_DROP_ON_LATENCY:
+      GST_RTP_BIN_LOCK (rtpbin);
+      rtpbin->drop_on_latency = g_value_get_boolean (value);
+      GST_RTP_BIN_UNLOCK (rtpbin);
+      /* propagate the property down to the jitterbuffer */
+      gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin,
+          "drop-on-latency", value);
+      break;
+    case PROP_SDES:
+      gst_rtp_bin_set_sdes_struct (rtpbin, g_value_get_boxed (value));
+      break;
+    case PROP_DO_LOST:
+      GST_RTP_BIN_LOCK (rtpbin);
+      rtpbin->do_lost = g_value_get_boolean (value);
+      GST_RTP_BIN_UNLOCK (rtpbin);
+      gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin, "do-lost", value);
+      break;
+    case PROP_NTP_SYNC:
+      rtpbin->ntp_sync = g_value_get_boolean (value);
+      /* The default value of max_ts_offset depends on ntp_sync. If user
+       * hasn't set it then change default value */
+      if (!rtpbin->max_ts_offset_is_set) {
+        if (rtpbin->ntp_sync) {
+          rtpbin->max_ts_offset = 0;
+        } else {
+          rtpbin->max_ts_offset = DEFAULT_MAX_TS_OFFSET;
+        }
+      }
+      break;
+    case PROP_RTCP_SYNC:
+      g_atomic_int_set (&rtpbin->rtcp_sync, g_value_get_enum (value));
+      break;
+    case PROP_RTCP_SYNC_INTERVAL:
+      rtpbin->rtcp_sync_interval = g_value_get_uint (value);
+      break;
+    case PROP_IGNORE_PT:
+      rtpbin->ignore_pt = g_value_get_boolean (value);
+      break;
+    case PROP_AUTOREMOVE:
+      rtpbin->priv->autoremove = g_value_get_boolean (value);
+      break;
+    case PROP_USE_PIPELINE_CLOCK:
+    {
+      GSList *sessions;
+      GST_RTP_BIN_LOCK (rtpbin);
+      rtpbin->use_pipeline_clock = g_value_get_boolean (value);
+      for (sessions = rtpbin->sessions; sessions;
+          sessions = g_slist_next (sessions)) {
+        GstRtpBinSession *session = (GstRtpBinSession *) sessions->data;
+
+        g_object_set (G_OBJECT (session->session),
+            "use-pipeline-clock", rtpbin->use_pipeline_clock, NULL);
+      }
+      GST_RTP_BIN_UNLOCK (rtpbin);
+    }
+      break;
+    case PROP_DO_SYNC_EVENT:
+      rtpbin->send_sync_event = g_value_get_boolean (value);
+      break;
+    case PROP_BUFFER_MODE:
+      GST_RTP_BIN_LOCK (rtpbin);
+      rtpbin->buffer_mode = g_value_get_enum (value);
+      GST_RTP_BIN_UNLOCK (rtpbin);
+      /* propagate the property down to the jitterbuffer */
+      gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin, "mode", value);
+      break;
+    case PROP_DO_RETRANSMISSION:
+      GST_RTP_BIN_LOCK (rtpbin);
+      rtpbin->do_retransmission = g_value_get_boolean (value);
+      GST_RTP_BIN_UNLOCK (rtpbin);
+      gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin,
+          "do-retransmission", value);
+      break;
+    case PROP_RTP_PROFILE:
+      rtpbin->rtp_profile = g_value_get_enum (value);
+      break;
+    case PROP_NTP_TIME_SOURCE:{
+      GSList *sessions;
+      GST_RTP_BIN_LOCK (rtpbin);
+      rtpbin->ntp_time_source = g_value_get_enum (value);
+      for (sessions = rtpbin->sessions; sessions;
+          sessions = g_slist_next (sessions)) {
+        GstRtpBinSession *session = (GstRtpBinSession *) sessions->data;
+
+        g_object_set (G_OBJECT (session->session),
+            "ntp-time-source", rtpbin->ntp_time_source, NULL);
+      }
+      GST_RTP_BIN_UNLOCK (rtpbin);
+      break;
+    }
+    case PROP_RTCP_SYNC_SEND_TIME:{
+      GSList *sessions;
+      GST_RTP_BIN_LOCK (rtpbin);
+      rtpbin->rtcp_sync_send_time = g_value_get_boolean (value);
+      for (sessions = rtpbin->sessions; sessions;
+          sessions = g_slist_next (sessions)) {
+        GstRtpBinSession *session = (GstRtpBinSession *) sessions->data;
+
+        g_object_set (G_OBJECT (session->session),
+            "rtcp-sync-send-time", rtpbin->rtcp_sync_send_time, NULL);
+      }
+      GST_RTP_BIN_UNLOCK (rtpbin);
+      break;
+    }
+    case PROP_MAX_RTCP_RTP_TIME_DIFF:
+      GST_RTP_BIN_LOCK (rtpbin);
+      rtpbin->max_rtcp_rtp_time_diff = g_value_get_int (value);
+      GST_RTP_BIN_UNLOCK (rtpbin);
+      gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin,
+          "max-rtcp-rtp-time-diff", value);
+      break;
+    case PROP_MAX_DROPOUT_TIME:
+      GST_RTP_BIN_LOCK (rtpbin);
+      rtpbin->max_dropout_time = g_value_get_uint (value);
+      GST_RTP_BIN_UNLOCK (rtpbin);
+      gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin,
+          "max-dropout-time", value);
+      gst_rtp_bin_propagate_property_to_session (rtpbin, "max-dropout-time",
+          value);
+      break;
+    case PROP_MAX_MISORDER_TIME:
+      GST_RTP_BIN_LOCK (rtpbin);
+      rtpbin->max_misorder_time = g_value_get_uint (value);
+      GST_RTP_BIN_UNLOCK (rtpbin);
+      gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin,
+          "max-misorder-time", value);
+      gst_rtp_bin_propagate_property_to_session (rtpbin, "max-misorder-time",
+          value);
+      break;
+    case PROP_RFC7273_SYNC:
+      rtpbin->rfc7273_sync = g_value_get_boolean (value);
+      gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin,
+          "rfc7273-sync", value);
+      break;
+    case PROP_MAX_STREAMS:
+      rtpbin->max_streams = g_value_get_uint (value);
+      break;
+    case PROP_MAX_TS_OFFSET_ADJUSTMENT:
+      rtpbin->max_ts_offset_adjustment = g_value_get_uint64 (value);
+      gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin,
+          "max-ts-offset-adjustment", value);
+      break;
+    case PROP_MAX_TS_OFFSET:
+      rtpbin->max_ts_offset = g_value_get_int64 (value);
+      rtpbin->max_ts_offset_is_set = TRUE;
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_bin_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpBin *rtpbin;
+
+  rtpbin = GST_RTP_BIN (object);
+
+  switch (prop_id) {
+    case PROP_LATENCY:
+      GST_RTP_BIN_LOCK (rtpbin);
+      g_value_set_uint (value, rtpbin->latency_ms);
+      GST_RTP_BIN_UNLOCK (rtpbin);
+      break;
+    case PROP_DROP_ON_LATENCY:
+      GST_RTP_BIN_LOCK (rtpbin);
+      g_value_set_boolean (value, rtpbin->drop_on_latency);
+      GST_RTP_BIN_UNLOCK (rtpbin);
+      break;
+    case PROP_SDES:
+      g_value_take_boxed (value, gst_rtp_bin_get_sdes_struct (rtpbin));
+      break;
+    case PROP_DO_LOST:
+      GST_RTP_BIN_LOCK (rtpbin);
+      g_value_set_boolean (value, rtpbin->do_lost);
+      GST_RTP_BIN_UNLOCK (rtpbin);
+      break;
+    case PROP_IGNORE_PT:
+      g_value_set_boolean (value, rtpbin->ignore_pt);
+      break;
+    case PROP_NTP_SYNC:
+      g_value_set_boolean (value, rtpbin->ntp_sync);
+      break;
+    case PROP_RTCP_SYNC:
+      g_value_set_enum (value, g_atomic_int_get (&rtpbin->rtcp_sync));
+      break;
+    case PROP_RTCP_SYNC_INTERVAL:
+      g_value_set_uint (value, rtpbin->rtcp_sync_interval);
+      break;
+    case PROP_AUTOREMOVE:
+      g_value_set_boolean (value, rtpbin->priv->autoremove);
+      break;
+    case PROP_BUFFER_MODE:
+      g_value_set_enum (value, rtpbin->buffer_mode);
+      break;
+    case PROP_USE_PIPELINE_CLOCK:
+      g_value_set_boolean (value, rtpbin->use_pipeline_clock);
+      break;
+    case PROP_DO_SYNC_EVENT:
+      g_value_set_boolean (value, rtpbin->send_sync_event);
+      break;
+    case PROP_DO_RETRANSMISSION:
+      GST_RTP_BIN_LOCK (rtpbin);
+      g_value_set_boolean (value, rtpbin->do_retransmission);
+      GST_RTP_BIN_UNLOCK (rtpbin);
+      break;
+    case PROP_RTP_PROFILE:
+      g_value_set_enum (value, rtpbin->rtp_profile);
+      break;
+    case PROP_NTP_TIME_SOURCE:
+      g_value_set_enum (value, rtpbin->ntp_time_source);
+      break;
+    case PROP_RTCP_SYNC_SEND_TIME:
+      g_value_set_boolean (value, rtpbin->rtcp_sync_send_time);
+      break;
+    case PROP_MAX_RTCP_RTP_TIME_DIFF:
+      GST_RTP_BIN_LOCK (rtpbin);
+      g_value_set_int (value, rtpbin->max_rtcp_rtp_time_diff);
+      GST_RTP_BIN_UNLOCK (rtpbin);
+      break;
+    case PROP_MAX_DROPOUT_TIME:
+      g_value_set_uint (value, rtpbin->max_dropout_time);
+      break;
+    case PROP_MAX_MISORDER_TIME:
+      g_value_set_uint (value, rtpbin->max_misorder_time);
+      break;
+    case PROP_RFC7273_SYNC:
+      g_value_set_boolean (value, rtpbin->rfc7273_sync);
+      break;
+    case PROP_MAX_STREAMS:
+      g_value_set_uint (value, rtpbin->max_streams);
+      break;
+    case PROP_MAX_TS_OFFSET_ADJUSTMENT:
+      g_value_set_uint64 (value, rtpbin->max_ts_offset_adjustment);
+      break;
+    case PROP_MAX_TS_OFFSET:
+      g_value_set_int64 (value, rtpbin->max_ts_offset);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message)
+{
+  GstRtpBin *rtpbin;
+
+  rtpbin = GST_RTP_BIN (bin);
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_ELEMENT:
+    {
+      const GstStructure *s = gst_message_get_structure (message);
+
+      /* we change the structure name and add the session ID to it */
+      if (gst_structure_has_name (s, "application/x-rtp-source-sdes")) {
+        GstRtpBinSession *sess;
+
+        /* find the session we set it as object data */
+        sess = g_object_get_data (G_OBJECT (GST_MESSAGE_SRC (message)),
+            "GstRTPBin.session");
+
+        if (G_LIKELY (sess)) {
+          message = gst_message_make_writable (message);
+          s = gst_message_get_structure (message);
+          gst_structure_set ((GstStructure *) s, "session", G_TYPE_UINT,
+              sess->id, NULL);
+        }
+      }
+      GST_BIN_CLASS (parent_class)->handle_message (bin, message);
+      break;
+    }
+    case GST_MESSAGE_BUFFERING:
+    {
+      gint percent;
+      gint min_percent = 100;
+      GSList *sessions, *streams;
+      GstRtpBinStream *stream;
+      gboolean change = FALSE, active = FALSE;
+      GstClockTime min_out_time;
+      GstBufferingMode mode;
+      gint avg_in, avg_out;
+      gint64 buffering_left;
+
+      gst_message_parse_buffering (message, &percent);
+      gst_message_parse_buffering_stats (message, &mode, &avg_in, &avg_out,
+          &buffering_left);
+
+      stream =
+          g_object_get_data (G_OBJECT (GST_MESSAGE_SRC (message)),
+          "GstRTPBin.stream");
+
+      GST_DEBUG_OBJECT (bin, "got percent %d from stream %p", percent, stream);
+
+      /* get the stream */
+      if (G_LIKELY (stream)) {
+        GST_RTP_BIN_LOCK (rtpbin);
+        /* fill in the percent */
+        stream->percent = percent;
+
+        /* calculate the min value for all streams */
+        for (sessions = rtpbin->sessions; sessions;
+            sessions = g_slist_next (sessions)) {
+          GstRtpBinSession *session = (GstRtpBinSession *) sessions->data;
+
+          GST_RTP_SESSION_LOCK (session);
+          if (session->streams) {
+            for (streams = session->streams; streams;
+                streams = g_slist_next (streams)) {
+              GstRtpBinStream *stream = (GstRtpBinStream *) streams->data;
+
+              GST_DEBUG_OBJECT (bin, "stream %p percent %d", stream,
+                  stream->percent);
+
+              /* find min percent */
+              if (min_percent > stream->percent)
+                min_percent = stream->percent;
+            }
+          } else {
+            GST_INFO_OBJECT (bin,
+                "session has no streams, setting min_percent to 0");
+            min_percent = 0;
+          }
+          GST_RTP_SESSION_UNLOCK (session);
+        }
+        GST_DEBUG_OBJECT (bin, "min percent %d", min_percent);
+
+        if (rtpbin->buffering) {
+          if (min_percent == 100) {
+            rtpbin->buffering = FALSE;
+            active = TRUE;
+            change = TRUE;
+          }
+        } else {
+          if (min_percent < 100) {
+            /* pause the streams */
+            rtpbin->buffering = TRUE;
+            active = FALSE;
+            change = TRUE;
+          }
+        }
+        GST_RTP_BIN_UNLOCK (rtpbin);
+
+        gst_message_unref (message);
+
+        /* make a new buffering message with the min value */
+        message =
+            gst_message_new_buffering (GST_OBJECT_CAST (bin), min_percent);
+        gst_message_set_buffering_stats (message, mode, avg_in, avg_out,
+            buffering_left);
+
+        if (G_UNLIKELY (change)) {
+          GstClock *clock;
+          guint64 running_time = 0;
+          guint64 offset = 0;
+
+          /* figure out the running time when we have a clock */
+          if (G_LIKELY ((clock =
+                      gst_element_get_clock (GST_ELEMENT_CAST (bin))))) {
+            guint64 now, base_time;
+
+            now = gst_clock_get_time (clock);
+            base_time = gst_element_get_base_time (GST_ELEMENT_CAST (bin));
+            running_time = now - base_time;
+            gst_object_unref (clock);
+          }
+          GST_DEBUG_OBJECT (bin,
+              "running time now %" GST_TIME_FORMAT,
+              GST_TIME_ARGS (running_time));
+
+          GST_RTP_BIN_LOCK (rtpbin);
+
+          /* when we reactivate, calculate the offsets so that all streams have
+           * an output time that is at least as big as the running_time */
+          offset = 0;
+          if (active) {
+            if (running_time > rtpbin->buffer_start) {
+              offset = running_time - rtpbin->buffer_start;
+              if (offset >= rtpbin->latency_ns)
+                offset -= rtpbin->latency_ns;
+              else
+                offset = 0;
+            }
+          }
+
+          /* pause all streams */
+          min_out_time = -1;
+          for (sessions = rtpbin->sessions; sessions;
+              sessions = g_slist_next (sessions)) {
+            GstRtpBinSession *session = (GstRtpBinSession *) sessions->data;
+
+            GST_RTP_SESSION_LOCK (session);
+            for (streams = session->streams; streams;
+                streams = g_slist_next (streams)) {
+              GstRtpBinStream *stream = (GstRtpBinStream *) streams->data;
+              GstElement *element = stream->buffer;
+              guint64 last_out;
+
+              g_signal_emit_by_name (element, "set-active", active, offset,
+                  &last_out);
+
+              if (!active) {
+                g_object_get (element, "percent", &stream->percent, NULL);
+
+                if (last_out == -1)
+                  last_out = 0;
+                if (min_out_time == -1 || last_out < min_out_time)
+                  min_out_time = last_out;
+              }
+
+              GST_DEBUG_OBJECT (bin,
+                  "setting %p to %d, offset %" GST_TIME_FORMAT ", last %"
+                  GST_TIME_FORMAT ", percent %d", element, active,
+                  GST_TIME_ARGS (offset), GST_TIME_ARGS (last_out),
+                  stream->percent);
+            }
+            GST_RTP_SESSION_UNLOCK (session);
+          }
+          GST_DEBUG_OBJECT (bin,
+              "min out time %" GST_TIME_FORMAT, GST_TIME_ARGS (min_out_time));
+
+          /* the buffer_start is the min out time of all paused jitterbuffers */
+          if (!active)
+            rtpbin->buffer_start = min_out_time;
+
+          GST_RTP_BIN_UNLOCK (rtpbin);
+        }
+      }
+      GST_BIN_CLASS (parent_class)->handle_message (bin, message);
+      break;
+    }
+    default:
+    {
+      GST_BIN_CLASS (parent_class)->handle_message (bin, message);
+      break;
+    }
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_bin_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn res;
+  GstRtpBin *rtpbin;
+  GstRtpBinPrivate *priv;
+
+  rtpbin = GST_RTP_BIN (element);
+  priv = rtpbin->priv;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      priv->last_ntpnstime = 0;
+      GST_LOG_OBJECT (rtpbin, "clearing shutdown flag");
+      g_atomic_int_set (&priv->shutdown, 0);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      GST_LOG_OBJECT (rtpbin, "setting shutdown flag");
+      g_atomic_int_set (&priv->shutdown, 1);
+      /* wait for all callbacks to end by taking the lock. No new callbacks will
+       * be able to happen as we set the shutdown flag. */
+      GST_RTP_BIN_DYN_LOCK (rtpbin);
+      GST_LOG_OBJECT (rtpbin, "dynamic lock taken, we can continue shutdown");
+      GST_RTP_BIN_DYN_UNLOCK (rtpbin);
+      break;
+    default:
+      break;
+  }
+
+  res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return res;
+}
+
+static GstElement *
+session_request_element (GstRtpBinSession * session, guint signal)
+{
+  GstElement *element = NULL;
+  GstRtpBin *bin = session->bin;
+
+  g_signal_emit (bin, gst_rtp_bin_signals[signal], 0, session->id, &element);
+
+  if (element) {
+    if (!bin_manage_element (bin, element))
+      goto manage_failed;
+    session->elements = g_slist_prepend (session->elements, element);
+  }
+  return element;
+
+  /* ERRORS */
+manage_failed:
+  {
+    GST_WARNING_OBJECT (bin, "unable to manage element");
+    gst_object_unref (element);
+    return NULL;
+  }
+}
+
+static gboolean
+copy_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
+{
+  GstPad *gpad = GST_PAD_CAST (user_data);
+
+  GST_DEBUG_OBJECT (gpad, "store sticky event %" GST_PTR_FORMAT, *event);
+  gst_pad_store_sticky_event (gpad, *event);
+
+  return TRUE;
+}
+
+/* a new pad (SSRC) was created in @session. This signal is emited from the
+ * payload demuxer. */
+static void
+new_payload_found (GstElement * element, guint pt, GstPad * pad,
+    GstRtpBinStream * stream)
+{
+  GstRtpBin *rtpbin;
+  GstElementClass *klass;
+  GstPadTemplate *templ;
+  gchar *padname;
+  GstPad *gpad;
+
+  rtpbin = stream->bin;
+
+  GST_DEBUG_OBJECT (rtpbin, "new payload pad %u", pt);
+
+  GST_RTP_BIN_SHUTDOWN_LOCK (rtpbin, shutdown);
+
+  /* ghost the pad to the parent */
+  klass = GST_ELEMENT_GET_CLASS (rtpbin);
+  templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%u_%u_%u");
+  padname = g_strdup_printf ("recv_rtp_src_%u_%u_%u",
+      stream->session->id, stream->ssrc, pt);
+  gpad = gst_ghost_pad_new_from_template (padname, pad, templ);
+  g_free (padname);
+  g_object_set_data (G_OBJECT (pad), "GstRTPBin.ghostpad", gpad);
+
+  gst_pad_set_active (gpad, TRUE);
+  GST_RTP_BIN_SHUTDOWN_UNLOCK (rtpbin);
+
+  gst_pad_sticky_events_foreach (pad, copy_sticky_events, gpad);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), gpad);
+
+  return;
+
+shutdown:
+  {
+    GST_DEBUG ("ignoring, we are shutting down");
+    return;
+  }
+}
+
+static void
+payload_pad_removed (GstElement * element, GstPad * pad,
+    GstRtpBinStream * stream)
+{
+  GstRtpBin *rtpbin;
+  GstPad *gpad;
+
+  rtpbin = stream->bin;
+
+  GST_DEBUG ("payload pad removed");
+
+  GST_RTP_BIN_DYN_LOCK (rtpbin);
+  if ((gpad = g_object_get_data (G_OBJECT (pad), "GstRTPBin.ghostpad"))) {
+    g_object_set_data (G_OBJECT (pad), "GstRTPBin.ghostpad", NULL);
+
+    gst_pad_set_active (gpad, FALSE);
+    gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), gpad);
+  }
+  GST_RTP_BIN_DYN_UNLOCK (rtpbin);
+}
+
+static GstCaps *
+pt_map_requested (GstElement * element, guint pt, GstRtpBinSession * session)
+{
+  GstRtpBin *rtpbin;
+  GstCaps *caps;
+
+  rtpbin = session->bin;
+
+  GST_DEBUG_OBJECT (rtpbin, "payload map requested for pt %u in session %u", pt,
+      session->id);
+
+  caps = get_pt_map (session, pt);
+  if (!caps)
+    goto no_caps;
+
+  return caps;
+
+  /* ERRORS */
+no_caps:
+  {
+    GST_DEBUG_OBJECT (rtpbin, "could not get caps");
+    return NULL;
+  }
+}
+
+static void
+payload_type_change (GstElement * element, guint pt, GstRtpBinSession * session)
+{
+  GST_DEBUG_OBJECT (session->bin,
+      "emiting signal for pt type changed to %u in session %u", pt,
+      session->id);
+
+  g_signal_emit (session->bin, gst_rtp_bin_signals[SIGNAL_PAYLOAD_TYPE_CHANGE],
+      0, session->id, pt);
+}
+
+/* emited when caps changed for the session */
+static void
+caps_changed (GstPad * pad, GParamSpec * pspec, GstRtpBinSession * session)
+{
+  GstRtpBin *bin;
+  GstCaps *caps;
+  gint payload;
+  const GstStructure *s;
+
+  bin = session->bin;
+
+  g_object_get (pad, "caps", &caps, NULL);
+
+  if (caps == NULL)
+    return;
+
+  GST_DEBUG_OBJECT (bin, "got caps %" GST_PTR_FORMAT, caps);
+
+  s = gst_caps_get_structure (caps, 0);
+
+  /* get payload, finish when it's not there */
+  if (!gst_structure_get_int (s, "payload", &payload)) {
+    gst_caps_unref (caps);
+    return;
+  }
+
+  GST_RTP_SESSION_LOCK (session);
+  GST_DEBUG_OBJECT (bin, "insert caps for payload %d", payload);
+  g_hash_table_insert (session->ptmap, GINT_TO_POINTER (payload), caps);
+  GST_RTP_SESSION_UNLOCK (session);
+}
+
+/* a new pad (SSRC) was created in @session */
+static void
+new_ssrc_pad_found (GstElement * element, guint ssrc, GstPad * pad,
+    GstRtpBinSession * session)
+{
+  GstRtpBin *rtpbin;
+  GstRtpBinStream *stream;
+  GstPad *sinkpad, *srcpad;
+  gchar *padname;
+
+  rtpbin = session->bin;
+
+  GST_DEBUG_OBJECT (rtpbin, "new SSRC pad %08x, %s:%s", ssrc,
+      GST_DEBUG_PAD_NAME (pad));
+
+  GST_RTP_BIN_SHUTDOWN_LOCK (rtpbin, shutdown);
+
+  GST_RTP_SESSION_LOCK (session);
+
+  /* create new stream */
+  stream = create_stream (session, ssrc);
+  if (!stream)
+    goto no_stream;
+
+  /* get pad and link */
+  GST_DEBUG_OBJECT (rtpbin, "linking jitterbuffer RTP");
+  padname = g_strdup_printf ("src_%u", ssrc);
+  srcpad = gst_element_get_static_pad (element, padname);
+  g_free (padname);
+  sinkpad = gst_element_get_static_pad (stream->buffer, "sink");
+  gst_pad_link_full (srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING);
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+
+  GST_DEBUG_OBJECT (rtpbin, "linking jitterbuffer RTCP");
+  padname = g_strdup_printf ("rtcp_src_%u", ssrc);
+  srcpad = gst_element_get_static_pad (element, padname);
+  g_free (padname);
+  sinkpad = gst_element_get_request_pad (stream->buffer, "sink_rtcp");
+  gst_pad_link_full (srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING);
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+
+  /* connect to the RTCP sync signal from the jitterbuffer */
+  GST_DEBUG_OBJECT (rtpbin, "connecting sync signal");
+  stream->buffer_handlesync_sig = g_signal_connect (stream->buffer,
+      "handle-sync", (GCallback) gst_rtp_bin_handle_sync, stream);
+
+  if (stream->demux) {
+    /* connect to the new-pad signal of the payload demuxer, this will expose the
+     * new pad by ghosting it. */
+    stream->demux_newpad_sig = g_signal_connect (stream->demux,
+        "new-payload-type", (GCallback) new_payload_found, stream);
+    stream->demux_padremoved_sig = g_signal_connect (stream->demux,
+        "pad-removed", (GCallback) payload_pad_removed, stream);
+
+    /* connect to the request-pt-map signal. This signal will be emited by the
+     * demuxer so that it can apply a proper caps on the buffers for the
+     * depayloaders. */
+    stream->demux_ptreq_sig = g_signal_connect (stream->demux,
+        "request-pt-map", (GCallback) pt_map_requested, session);
+    /* connect to the  signal so it can be forwarded. */
+    stream->demux_ptchange_sig = g_signal_connect (stream->demux,
+        "payload-type-change", (GCallback) payload_type_change, session);
+  } else {
+    /* add rtpjitterbuffer src pad to pads */
+    GstElementClass *klass;
+    GstPadTemplate *templ;
+    gchar *padname;
+    GstPad *gpad, *pad;
+
+    pad = gst_element_get_static_pad (stream->buffer, "src");
+
+    /* ghost the pad to the parent */
+    klass = GST_ELEMENT_GET_CLASS (rtpbin);
+    templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%u_%u_%u");
+    padname = g_strdup_printf ("recv_rtp_src_%u_%u_%u",
+        stream->session->id, stream->ssrc, 255);
+    gpad = gst_ghost_pad_new_from_template (padname, pad, templ);
+    g_free (padname);
+
+    gst_pad_set_active (gpad, TRUE);
+    gst_pad_sticky_events_foreach (pad, copy_sticky_events, gpad);
+    gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), gpad);
+
+    gst_object_unref (pad);
+  }
+
+  GST_RTP_SESSION_UNLOCK (session);
+  GST_RTP_BIN_SHUTDOWN_UNLOCK (rtpbin);
+
+  return;
+
+  /* ERRORS */
+shutdown:
+  {
+    GST_DEBUG_OBJECT (rtpbin, "we are shutting down");
+    return;
+  }
+no_stream:
+  {
+    GST_RTP_SESSION_UNLOCK (session);
+    GST_RTP_BIN_SHUTDOWN_UNLOCK (rtpbin);
+    GST_DEBUG_OBJECT (rtpbin, "could not create stream");
+    return;
+  }
+}
+
+static void
+session_maybe_create_bundle_demuxer (GstRtpBinSession * session)
+{
+  GstRtpBin *rtpbin;
+
+  if (session->bundle_demux)
+    return;
+
+  rtpbin = session->bin;
+  if (g_signal_has_handler_pending (rtpbin,
+          gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC], 0, TRUE)) {
+    GST_DEBUG_OBJECT (rtpbin, "Adding a bundle SSRC demuxer to session %u",
+        session->id);
+    session->bundle_demux = gst_element_factory_make ("rtpssrcdemux", NULL);
+    session->bundle_demux_newpad_sig = g_signal_connect (session->bundle_demux,
+        "new-ssrc-pad", (GCallback) new_bundled_ssrc_pad_found, session);
+
+    gst_bin_add (GST_BIN_CAST (rtpbin), session->bundle_demux);
+    gst_element_sync_state_with_parent (session->bundle_demux);
+  } else {
+    GST_DEBUG_OBJECT (rtpbin,
+        "No handler for the on-bundled-ssrc signal so no need for a bundle SSRC demuxer in session %u",
+        session->id);
+  }
+}
+
+static GstPad *
+complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session,
+    gboolean bundle_demuxer_needed)
+{
+  guint sessid = session->id;
+  GstPad *recv_rtp_sink;
+  GstPad *funnel_src;
+  GstElement *decoder;
+
+  g_assert (!session->recv_rtp_sink);
+
+  /* get recv_rtp pad and store */
+  session->recv_rtp_sink =
+      gst_element_get_request_pad (session->session, "recv_rtp_sink");
+  if (session->recv_rtp_sink == NULL)
+    goto pad_failed;
+
+  g_signal_connect (session->recv_rtp_sink, "notify::caps",
+      (GCallback) caps_changed, session);
+
+  if (bundle_demuxer_needed)
+    session_maybe_create_bundle_demuxer (session);
+
+  GST_DEBUG_OBJECT (rtpbin, "requesting RTP decoder");
+  decoder = session_request_element (session, SIGNAL_REQUEST_RTP_DECODER);
+  if (decoder) {
+    GstPad *decsrc, *decsink;
+    GstPadLinkReturn ret;
+
+    GST_DEBUG_OBJECT (rtpbin, "linking RTP decoder");
+    decsink = gst_element_get_static_pad (decoder, "rtp_sink");
+    if (decsink == NULL)
+      goto dec_sink_failed;
+
+    recv_rtp_sink = decsink;
+
+    decsrc = gst_element_get_static_pad (decoder, "rtp_src");
+    if (decsrc == NULL)
+      goto dec_src_failed;
+
+    if (session->bundle_demux) {
+      GstPad *demux_sink;
+      demux_sink = gst_element_get_static_pad (session->bundle_demux, "sink");
+      ret = gst_pad_link (decsrc, demux_sink);
+      gst_object_unref (demux_sink);
+    } else {
+      ret = gst_pad_link (decsrc, session->recv_rtp_sink);
+    }
+    gst_object_unref (decsrc);
+
+    if (ret != GST_PAD_LINK_OK)
+      goto dec_link_failed;
+
+  } else {
+    GST_DEBUG_OBJECT (rtpbin, "no RTP decoder given");
+    if (session->bundle_demux) {
+      recv_rtp_sink =
+          gst_element_get_static_pad (session->bundle_demux, "sink");
+    } else {
+      recv_rtp_sink =
+          gst_element_get_request_pad (session->rtp_funnel, "sink_%u");
+    }
+  }
+
+  funnel_src = gst_element_get_static_pad (session->rtp_funnel, "src");
+  gst_pad_link (funnel_src, session->recv_rtp_sink);
+  gst_object_unref (funnel_src);
+
+  return recv_rtp_sink;
+
+  /* ERRORS */
+pad_failed:
+  {
+    g_warning ("rtpbin: failed to get session recv_rtp_sink pad");
+    return NULL;
+  }
+dec_sink_failed:
+  {
+    g_warning ("rtpbin: failed to get decoder sink pad for session %u", sessid);
+    return NULL;
+  }
+dec_src_failed:
+  {
+    g_warning ("rtpbin: failed to get decoder src pad for session %u", sessid);
+    gst_object_unref (recv_rtp_sink);
+    return NULL;
+  }
+dec_link_failed:
+  {
+    g_warning ("rtpbin: failed to link rtp decoder for session %u", sessid);
+    gst_object_unref (recv_rtp_sink);
+    return NULL;
+  }
+}
+
+static void
+complete_session_receiver (GstRtpBin * rtpbin, GstRtpBinSession * session,
+    guint sessid)
+{
+  GstElement *aux;
+  GstPad *recv_rtp_src;
+
+  g_assert (!session->recv_rtp_src);
+
+  session->recv_rtp_src =
+      gst_element_get_static_pad (session->session, "recv_rtp_src");
+  if (session->recv_rtp_src == NULL)
+    goto pad_failed;
+
+  /* find out if we need AUX elements or if we can go into the SSRC demuxer
+   * directly */
+  aux = session_request_element (session, SIGNAL_REQUEST_AUX_RECEIVER);
+  if (aux) {
+    gchar *pname;
+    GstPad *auxsink;
+    GstPadLinkReturn ret;
+
+    GST_DEBUG_OBJECT (rtpbin, "linking AUX receiver");
+
+    pname = g_strdup_printf ("sink_%u", sessid);
+    auxsink = gst_element_get_static_pad (aux, pname);
+    g_free (pname);
+    if (auxsink == NULL)
+      goto aux_sink_failed;
+
+    ret = gst_pad_link (session->recv_rtp_src, auxsink);
+    gst_object_unref (auxsink);
+    if (ret != GST_PAD_LINK_OK)
+      goto aux_link_failed;
+
+    /* this can be NULL when this AUX element is not to be linked to
+     * an SSRC demuxer */
+    pname = g_strdup_printf ("src_%u", sessid);
+    recv_rtp_src = gst_element_get_static_pad (aux, pname);
+    g_free (pname);
+  } else {
+    recv_rtp_src = gst_object_ref (session->recv_rtp_src);
+  }
+
+  if (recv_rtp_src) {
+    GstPad *sinkdpad;
+
+    GST_DEBUG_OBJECT (rtpbin, "getting demuxer RTP sink pad");
+    sinkdpad = gst_element_get_static_pad (session->demux, "sink");
+    GST_DEBUG_OBJECT (rtpbin, "linking demuxer RTP sink pad");
+    gst_pad_link_full (recv_rtp_src, sinkdpad, GST_PAD_LINK_CHECK_NOTHING);
+    gst_object_unref (sinkdpad);
+    gst_object_unref (recv_rtp_src);
+
+    /* connect to the new-ssrc-pad signal of the SSRC demuxer */
+    session->demux_newpad_sig = g_signal_connect (session->demux,
+        "new-ssrc-pad", (GCallback) new_ssrc_pad_found, session);
+    session->demux_padremoved_sig = g_signal_connect (session->demux,
+        "removed-ssrc-pad", (GCallback) ssrc_demux_pad_removed, session);
+  }
+
+  return;
+
+pad_failed:
+  {
+    g_warning ("rtpbin: failed to get session recv_rtp_src pad");
+    return;
+  }
+aux_sink_failed:
+  {
+    g_warning ("rtpbin: failed to get AUX sink pad for session %u", sessid);
+    return;
+  }
+aux_link_failed:
+  {
+    g_warning ("rtpbin: failed to link AUX pad to session %u", sessid);
+    return;
+  }
+}
+
+/* Create a pad for receiving RTP for the session in @name. Must be called with
+ * RTP_BIN_LOCK.
+ */
+static GstPad *
+create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+{
+  guint sessid;
+  GstRtpBinSession *session;
+  GstPad *recv_rtp_sink;
+
+  /* first get the session number */
+  if (name == NULL || sscanf (name, "recv_rtp_sink_%u", &sessid) != 1)
+    goto no_name;
+
+  GST_DEBUG_OBJECT (rtpbin, "finding session %u", sessid);
+
+  /* get or create session */
+  session = find_session_by_id (rtpbin, sessid);
+  if (!session) {
+    GST_DEBUG_OBJECT (rtpbin, "creating session %u", sessid);
+    /* create session now */
+    session = create_session (rtpbin, sessid);
+    if (session == NULL)
+      goto create_error;
+  }
+
+  /* check if pad was requested */
+  if (session->recv_rtp_sink_ghost != NULL)
+    return session->recv_rtp_sink_ghost;
+
+  /* setup the session sink pad */
+  recv_rtp_sink = complete_session_sink (rtpbin, session, TRUE);
+  if (!recv_rtp_sink)
+    goto session_sink_failed;
+
+
+  GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
+  session->recv_rtp_sink_ghost =
+      gst_ghost_pad_new_from_template (name, recv_rtp_sink, templ);
+  gst_object_unref (recv_rtp_sink);
+  gst_pad_set_active (session->recv_rtp_sink_ghost, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->recv_rtp_sink_ghost);
+
+  complete_session_receiver (rtpbin, session, sessid);
+
+  return session->recv_rtp_sink_ghost;
+
+  /* ERRORS */
+no_name:
+  {
+    g_warning ("rtpbin: invalid name given");
+    return NULL;
+  }
+create_error:
+  {
+    /* create_session already warned */
+    return NULL;
+  }
+session_sink_failed:
+  {
+    /* warning already done */
+    return NULL;
+  }
+}
+
+static void
+remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
+{
+  if (session->demux_newpad_sig) {
+    g_signal_handler_disconnect (session->demux, session->demux_newpad_sig);
+    session->demux_newpad_sig = 0;
+  }
+  if (session->demux_padremoved_sig) {
+    g_signal_handler_disconnect (session->demux, session->demux_padremoved_sig);
+    session->demux_padremoved_sig = 0;
+  }
+  if (session->bundle_demux_newpad_sig) {
+    g_signal_handler_disconnect (session->bundle_demux,
+        session->bundle_demux_newpad_sig);
+    session->bundle_demux_newpad_sig = 0;
+  }
+  if (session->recv_rtp_src) {
+    gst_object_unref (session->recv_rtp_src);
+    session->recv_rtp_src = NULL;
+  }
+  if (session->recv_rtp_sink) {
+    gst_element_release_request_pad (session->session, session->recv_rtp_sink);
+    gst_object_unref (session->recv_rtp_sink);
+    session->recv_rtp_sink = NULL;
+  }
+  if (session->recv_rtp_sink_ghost) {
+    gst_pad_set_active (session->recv_rtp_sink_ghost, FALSE);
+    gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
+        session->recv_rtp_sink_ghost);
+    session->recv_rtp_sink_ghost = NULL;
+  }
+}
+
+static GstPad *
+complete_session_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session,
+    guint sessid, gboolean bundle_demuxer_needed)
+{
+  GstElement *decoder;
+  GstPad *sinkdpad;
+  GstPad *decsink = NULL;
+  GstPad *funnel_src;
+
+  /* get recv_rtp pad and store */
+  GST_DEBUG_OBJECT (rtpbin, "getting RTCP sink pad");
+  session->recv_rtcp_sink =
+      gst_element_get_request_pad (session->session, "recv_rtcp_sink");
+  if (session->recv_rtcp_sink == NULL)
+    goto pad_failed;
+
+  if (bundle_demuxer_needed)
+    session_maybe_create_bundle_demuxer (session);
+
+  GST_DEBUG_OBJECT (rtpbin, "getting RTCP decoder");
+  decoder = session_request_element (session, SIGNAL_REQUEST_RTCP_DECODER);
+  if (decoder) {
+    GstPad *decsrc;
+    GstPadLinkReturn ret;
+
+    GST_DEBUG_OBJECT (rtpbin, "linking RTCP decoder");
+    decsink = gst_element_get_static_pad (decoder, "rtcp_sink");
+    decsrc = gst_element_get_static_pad (decoder, "rtcp_src");
+
+    if (decsink == NULL)
+      goto dec_sink_failed;
+
+    if (decsrc == NULL)
+      goto dec_src_failed;
+
+    if (session->bundle_demux) {
+      GstPad *demux_sink;
+      demux_sink =
+          gst_element_get_static_pad (session->bundle_demux, "rtcp_sink");
+      ret = gst_pad_link (decsrc, demux_sink);
+      gst_object_unref (demux_sink);
+    } else {
+      ret = gst_pad_link (decsrc, session->recv_rtcp_sink);
+    }
+    gst_object_unref (decsrc);
+
+    if (ret != GST_PAD_LINK_OK)
+      goto dec_link_failed;
+  } else {
+    GST_DEBUG_OBJECT (rtpbin, "no RTCP decoder given");
+    if (session->bundle_demux) {
+      decsink = gst_element_get_static_pad (session->bundle_demux, "rtcp_sink");
+    } else {
+      decsink = gst_element_get_request_pad (session->rtcp_funnel, "sink_%u");
+    }
+  }
+
+  /* get srcpad, link to SSRCDemux */
+  GST_DEBUG_OBJECT (rtpbin, "getting sync src pad");
+  session->sync_src = gst_element_get_static_pad (session->session, "sync_src");
+  if (session->sync_src == NULL)
+    goto src_pad_failed;
+
+  GST_DEBUG_OBJECT (rtpbin, "getting demuxer RTCP sink pad");
+  sinkdpad = gst_element_get_static_pad (session->demux, "rtcp_sink");
+  gst_pad_link_full (session->sync_src, sinkdpad, GST_PAD_LINK_CHECK_NOTHING);
+  gst_object_unref (sinkdpad);
+
+  funnel_src = gst_element_get_static_pad (session->rtcp_funnel, "src");
+  gst_pad_link (funnel_src, session->recv_rtcp_sink);
+  gst_object_unref (funnel_src);
+
+  return decsink;
+
+pad_failed:
+  {
+    g_warning ("rtpbin: failed to get session rtcp_sink pad");
+    return NULL;
+  }
+dec_sink_failed:
+  {
+    g_warning ("rtpbin: failed to get decoder sink pad for session %u", sessid);
+    return NULL;
+  }
+dec_src_failed:
+  {
+    g_warning ("rtpbin: failed to get decoder src pad for session %u", sessid);
+    goto cleanup;
+  }
+dec_link_failed:
+  {
+    g_warning ("rtpbin: failed to link rtcp decoder for session %u", sessid);
+    goto cleanup;
+  }
+src_pad_failed:
+  {
+    g_warning ("rtpbin: failed to get session sync_src pad");
+  }
+
+cleanup:
+  gst_object_unref (decsink);
+  return NULL;
+}
+
+/* Create a pad for receiving RTCP for the session in @name. Must be called with
+ * RTP_BIN_LOCK.
+ */
+static GstPad *
+create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
+    const gchar * name)
+{
+  guint sessid;
+  GstRtpBinSession *session;
+  GstPad *decsink = NULL;
+
+  /* first get the session number */
+  if (name == NULL || sscanf (name, "recv_rtcp_sink_%u", &sessid) != 1)
+    goto no_name;
+
+  GST_DEBUG_OBJECT (rtpbin, "finding session %u", sessid);
+
+  /* get or create the session */
+  session = find_session_by_id (rtpbin, sessid);
+  if (!session) {
+    GST_DEBUG_OBJECT (rtpbin, "creating session %u", sessid);
+    /* create session now */
+    session = create_session (rtpbin, sessid);
+    if (session == NULL)
+      goto create_error;
+  }
+
+  /* check if pad was requested */
+  if (session->recv_rtcp_sink_ghost != NULL)
+    return session->recv_rtcp_sink_ghost;
+
+  decsink = complete_session_rtcp (rtpbin, session, sessid, TRUE);
+  if (!decsink)
+    goto create_error;
+
+  session->recv_rtcp_sink_ghost =
+      gst_ghost_pad_new_from_template (name, decsink, templ);
+  gst_object_unref (decsink);
+  gst_pad_set_active (session->recv_rtcp_sink_ghost, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin),
+      session->recv_rtcp_sink_ghost);
+
+  return session->recv_rtcp_sink_ghost;
+
+  /* ERRORS */
+no_name:
+  {
+    g_warning ("rtpbin: invalid name given");
+    return NULL;
+  }
+create_error:
+  {
+    /* create_session already warned */
+    return NULL;
+  }
+}
+
+static void
+remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session)
+{
+  if (session->recv_rtcp_sink_ghost) {
+    gst_pad_set_active (session->recv_rtcp_sink_ghost, FALSE);
+    gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
+        session->recv_rtcp_sink_ghost);
+    session->recv_rtcp_sink_ghost = NULL;
+  }
+  if (session->sync_src) {
+    /* releasing the request pad should also unref the sync pad */
+    gst_object_unref (session->sync_src);
+    session->sync_src = NULL;
+  }
+  if (session->recv_rtcp_sink) {
+    gst_element_release_request_pad (session->session, session->recv_rtcp_sink);
+    gst_object_unref (session->recv_rtcp_sink);
+    session->recv_rtcp_sink = NULL;
+  }
+}
+
+static gboolean
+complete_session_src (GstRtpBin * rtpbin, GstRtpBinSession * session)
+{
+  gchar *gname;
+  guint sessid = session->id;
+  GstPad *send_rtp_src;
+  GstElement *encoder;
+  GstElementClass *klass;
+  GstPadTemplate *templ;
+
+  /* get srcpad */
+  session->send_rtp_src =
+      gst_element_get_static_pad (session->session, "send_rtp_src");
+  if (session->send_rtp_src == NULL)
+    goto no_srcpad;
+
+  GST_DEBUG_OBJECT (rtpbin, "getting RTP encoder");
+  encoder = session_request_element (session, SIGNAL_REQUEST_RTP_ENCODER);
+  if (encoder) {
+    gchar *ename;
+    GstPad *encsrc, *encsink;
+    GstPadLinkReturn ret;
+
+    GST_DEBUG_OBJECT (rtpbin, "linking RTP encoder");
+    ename = g_strdup_printf ("rtp_src_%u", sessid);
+    encsrc = gst_element_get_static_pad (encoder, ename);
+    g_free (ename);
+
+    if (encsrc == NULL)
+      goto enc_src_failed;
+
+    send_rtp_src = encsrc;
+
+    ename = g_strdup_printf ("rtp_sink_%u", sessid);
+    encsink = gst_element_get_static_pad (encoder, ename);
+    g_free (ename);
+    if (encsink == NULL)
+      goto enc_sink_failed;
+
+    ret = gst_pad_link (session->send_rtp_src, encsink);
+    gst_object_unref (encsink);
+
+    if (ret != GST_PAD_LINK_OK)
+      goto enc_link_failed;
+  } else {
+    GST_DEBUG_OBJECT (rtpbin, "no RTP encoder given");
+    send_rtp_src = gst_object_ref (session->send_rtp_src);
+  }
+
+  /* ghost the new source pad */
+  klass = GST_ELEMENT_GET_CLASS (rtpbin);
+  gname = g_strdup_printf ("send_rtp_src_%u", sessid);
+  templ = gst_element_class_get_pad_template (klass, "send_rtp_src_%u");
+  session->send_rtp_src_ghost =
+      gst_ghost_pad_new_from_template (gname, send_rtp_src, templ);
+  gst_object_unref (send_rtp_src);
+  gst_pad_set_active (session->send_rtp_src_ghost, TRUE);
+  gst_pad_sticky_events_foreach (send_rtp_src, copy_sticky_events,
+      session->send_rtp_src_ghost);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtp_src_ghost);
+  g_free (gname);
+
+  return TRUE;
+
+  /* ERRORS */
+no_srcpad:
+  {
+    g_warning ("rtpbin: failed to get rtp source pad for session %u", sessid);
+    return FALSE;
+  }
+enc_src_failed:
+  {
+    g_warning ("rtpbin: failed to get encoder src pad for session %u", sessid);
+    return FALSE;
+  }
+enc_sink_failed:
+  {
+    g_warning ("rtpbin: failed to get encoder sink pad for session %u", sessid);
+    gst_object_unref (send_rtp_src);
+    return FALSE;
+  }
+enc_link_failed:
+  {
+    g_warning ("rtpbin: failed to link rtp encoder for session %u", sessid);
+    gst_object_unref (send_rtp_src);
+    return FALSE;
+  }
+}
+
+static gboolean
+setup_aux_sender_fold (const GValue * item, GValue * result, gpointer user_data)
+{
+  GstPad *pad;
+  gchar *name;
+  guint sessid;
+  GstRtpBinSession *session = user_data, *newsess;
+  GstRtpBin *rtpbin = session->bin;
+  GstPadLinkReturn ret;
+
+  pad = g_value_get_object (item);
+  name = gst_pad_get_name (pad);
+
+  if (name == NULL || sscanf (name, "src_%u", &sessid) != 1)
+    goto no_name;
+
+  g_free (name);
+
+  newsess = find_session_by_id (rtpbin, sessid);
+  if (newsess == NULL) {
+    /* create new session */
+    newsess = create_session (rtpbin, sessid);
+    if (newsess == NULL)
+      goto create_error;
+  } else if (newsess->send_rtp_sink != NULL)
+    goto existing_session;
+
+  /* get send_rtp pad and store */
+  newsess->send_rtp_sink =
+      gst_element_get_request_pad (newsess->session, "send_rtp_sink");
+  if (newsess->send_rtp_sink == NULL)
+    goto pad_failed;
+
+  ret = gst_pad_link (pad, newsess->send_rtp_sink);
+  if (ret != GST_PAD_LINK_OK)
+    goto aux_link_failed;
+
+  if (!complete_session_src (rtpbin, newsess))
+    goto session_src_failed;
+
+  return TRUE;
+
+  /* ERRORS */
+no_name:
+  {
+    GST_WARNING ("ignoring invalid pad name %s", GST_STR_NULL (name));
+    g_free (name);
+    return TRUE;
+  }
+create_error:
+  {
+    /* create_session already warned */
+    return FALSE;
+  }
+existing_session:
+  {
+    g_warning ("rtpbin: session %u is already a sender", sessid);
+    return FALSE;
+  }
+pad_failed:
+  {
+    g_warning ("rtpbin: failed to get session pad for session %u", sessid);
+    return FALSE;
+  }
+aux_link_failed:
+  {
+    g_warning ("rtpbin: failed to link AUX for session %u", sessid);
+    return FALSE;
+  }
+session_src_failed:
+  {
+    g_warning ("rtpbin: failed to complete AUX for session %u", sessid);
+    return FALSE;
+  }
+}
+
+static gboolean
+setup_aux_sender (GstRtpBin * rtpbin, GstRtpBinSession * session,
+    GstElement * aux)
+{
+  GstIterator *it;
+  GValue result = { 0, };
+  GstIteratorResult res;
+
+  it = gst_element_iterate_src_pads (aux);
+  res = gst_iterator_fold (it, setup_aux_sender_fold, &result, session);
+  gst_iterator_free (it);
+
+  return res == GST_ITERATOR_DONE;
+}
+
+/* Create a pad for sending RTP for the session in @name. Must be called with
+ * RTP_BIN_LOCK.
+ */
+static GstPad *
+create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+{
+  gchar *pname;
+  guint sessid;
+  GstPad *send_rtp_sink;
+  GstElement *aux;
+  GstRtpBinSession *session;
+
+  /* first get the session number */
+  if (name == NULL || sscanf (name, "send_rtp_sink_%u", &sessid) != 1)
+    goto no_name;
+
+  /* get or create session */
+  session = find_session_by_id (rtpbin, sessid);
+  if (!session) {
+    /* create session now */
+    session = create_session (rtpbin, sessid);
+    if (session == NULL)
+      goto create_error;
+  }
+
+  /* check if pad was requested */
+  if (session->send_rtp_sink_ghost != NULL)
+    return session->send_rtp_sink_ghost;
+
+  /* check if we are already using this session as a sender */
+  if (session->send_rtp_sink != NULL)
+    goto existing_session;
+
+  GST_DEBUG_OBJECT (rtpbin, "getting RTP AUX sender");
+  aux = session_request_element (session, SIGNAL_REQUEST_AUX_SENDER);
+  if (aux) {
+    GST_DEBUG_OBJECT (rtpbin, "linking AUX sender");
+    if (!setup_aux_sender (rtpbin, session, aux))
+      goto aux_session_failed;
+
+    pname = g_strdup_printf ("sink_%u", sessid);
+    send_rtp_sink = gst_element_get_static_pad (aux, pname);
+    g_free (pname);
+
+    if (send_rtp_sink == NULL)
+      goto aux_sink_failed;
+  } else {
+    /* get send_rtp pad and store */
+    session->send_rtp_sink =
+        gst_element_get_request_pad (session->session, "send_rtp_sink");
+    if (session->send_rtp_sink == NULL)
+      goto pad_failed;
+
+    if (!complete_session_src (rtpbin, session))
+      goto session_src_failed;
+
+    send_rtp_sink = gst_object_ref (session->send_rtp_sink);
+  }
+
+  session->send_rtp_sink_ghost =
+      gst_ghost_pad_new_from_template (name, send_rtp_sink, templ);
+  gst_object_unref (send_rtp_sink);
+  gst_pad_set_active (session->send_rtp_sink_ghost, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtp_sink_ghost);
+
+  return session->send_rtp_sink_ghost;
+
+  /* ERRORS */
+no_name:
+  {
+    g_warning ("rtpbin: invalid name given");
+    return NULL;
+  }
+create_error:
+  {
+    /* create_session already warned */
+    return NULL;
+  }
+existing_session:
+  {
+    g_warning ("rtpbin: session %u is already in use", sessid);
+    return NULL;
+  }
+aux_session_failed:
+  {
+    g_warning ("rtpbin: failed to get AUX sink pad for session %u", sessid);
+    return NULL;
+  }
+aux_sink_failed:
+  {
+    g_warning ("rtpbin: failed to get AUX sink pad for session %u", sessid);
+    return NULL;
+  }
+pad_failed:
+  {
+    g_warning ("rtpbin: failed to get session pad for session %u", sessid);
+    return NULL;
+  }
+session_src_failed:
+  {
+    g_warning ("rtpbin: failed to setup source pads for session %u", sessid);
+    return NULL;
+  }
+}
+
+static void
+remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
+{
+  if (session->send_rtp_src_ghost) {
+    gst_pad_set_active (session->send_rtp_src_ghost, FALSE);
+    gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
+        session->send_rtp_src_ghost);
+    session->send_rtp_src_ghost = NULL;
+  }
+  if (session->send_rtp_src) {
+    gst_object_unref (session->send_rtp_src);
+    session->send_rtp_src = NULL;
+  }
+  if (session->send_rtp_sink) {
+    gst_element_release_request_pad (GST_ELEMENT_CAST (session->session),
+        session->send_rtp_sink);
+    gst_object_unref (session->send_rtp_sink);
+    session->send_rtp_sink = NULL;
+  }
+  if (session->send_rtp_sink_ghost) {
+    gst_pad_set_active (session->send_rtp_sink_ghost, FALSE);
+    gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
+        session->send_rtp_sink_ghost);
+    session->send_rtp_sink_ghost = NULL;
+  }
+}
+
+/* Create a pad for sending RTCP for the session in @name. Must be called with
+ * RTP_BIN_LOCK.
+ */
+static GstPad *
+create_send_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
+    const gchar * name)
+{
+  guint sessid;
+  GstPad *encsrc;
+  GstElement *encoder;
+  GstRtpBinSession *session;
+
+  /* first get the session number */
+  if (name == NULL || sscanf (name, "send_rtcp_src_%u", &sessid) != 1)
+    goto no_name;
+
+  /* get or create session */
+  session = find_session_by_id (rtpbin, sessid);
+  if (!session) {
+    GST_DEBUG_OBJECT (rtpbin, "creating session %u", sessid);
+    /* create session now */
+    session = create_session (rtpbin, sessid);
+    if (session == NULL)
+      goto create_error;
+  }
+
+  /* check if pad was requested */
+  if (session->send_rtcp_src_ghost != NULL)
+    return session->send_rtcp_src_ghost;
+
+  /* get rtcp_src pad and store */
+  session->send_rtcp_src =
+      gst_element_get_request_pad (session->session, "send_rtcp_src");
+  if (session->send_rtcp_src == NULL)
+    goto pad_failed;
+
+  GST_DEBUG_OBJECT (rtpbin, "getting RTCP encoder");
+  encoder = session_request_element (session, SIGNAL_REQUEST_RTCP_ENCODER);
+  if (encoder) {
+    gchar *ename;
+    GstPad *encsink;
+    GstPadLinkReturn ret;
+
+    GST_DEBUG_OBJECT (rtpbin, "linking RTCP encoder");
+
+    ename = g_strdup_printf ("rtcp_src_%u", sessid);
+    encsrc = gst_element_get_static_pad (encoder, ename);
+    g_free (ename);
+    if (encsrc == NULL)
+      goto enc_src_failed;
+
+    ename = g_strdup_printf ("rtcp_sink_%u", sessid);
+    encsink = gst_element_get_static_pad (encoder, ename);
+    g_free (ename);
+    if (encsink == NULL)
+      goto enc_sink_failed;
+
+    ret = gst_pad_link (session->send_rtcp_src, encsink);
+    gst_object_unref (encsink);
+
+    if (ret != GST_PAD_LINK_OK)
+      goto enc_link_failed;
+  } else {
+    GST_DEBUG_OBJECT (rtpbin, "no RTCP encoder given");
+    encsrc = gst_object_ref (session->send_rtcp_src);
+  }
+
+  session->send_rtcp_src_ghost =
+      gst_ghost_pad_new_from_template (name, encsrc, templ);
+  gst_object_unref (encsrc);
+  gst_pad_set_active (session->send_rtcp_src_ghost, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtcp_src_ghost);
+
+  return session->send_rtcp_src_ghost;
+
+  /* ERRORS */
+no_name:
+  {
+    g_warning ("rtpbin: invalid name given");
+    return NULL;
+  }
+create_error:
+  {
+    /* create_session already warned */
+    return NULL;
+  }
+pad_failed:
+  {
+    g_warning ("rtpbin: failed to get rtcp pad for session %u", sessid);
+    return NULL;
+  }
+enc_src_failed:
+  {
+    g_warning ("rtpbin: failed to get encoder src pad for session %u", sessid);
+    return NULL;
+  }
+enc_sink_failed:
+  {
+    g_warning ("rtpbin: failed to get encoder sink pad for session %u", sessid);
+    gst_object_unref (encsrc);
+    return NULL;
+  }
+enc_link_failed:
+  {
+    g_warning ("rtpbin: failed to link rtcp encoder for session %u", sessid);
+    gst_object_unref (encsrc);
+    return NULL;
+  }
+}
+
+static void
+remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session)
+{
+  if (session->send_rtcp_src_ghost) {
+    gst_pad_set_active (session->send_rtcp_src_ghost, FALSE);
+    gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
+        session->send_rtcp_src_ghost);
+    session->send_rtcp_src_ghost = NULL;
+  }
+  if (session->send_rtcp_src) {
+    gst_element_release_request_pad (session->session, session->send_rtcp_src);
+    gst_object_unref (session->send_rtcp_src);
+    session->send_rtcp_src = NULL;
+  }
+}
+
+/* If the requested name is NULL we should create a name with
+ * the session number assuming we want the lowest posible session
+ * with a free pad like the template */
+static gchar *
+gst_rtp_bin_get_free_pad_name (GstElement * element, GstPadTemplate * templ)
+{
+  gboolean name_found = FALSE;
+  gint session = 0;
+  GstIterator *pad_it = NULL;
+  gchar *pad_name = NULL;
+  GValue data = { 0, };
+
+  GST_DEBUG_OBJECT (element, "find a free pad name for template");
+  while (!name_found) {
+    gboolean done = FALSE;
+
+    g_free (pad_name);
+    pad_name = g_strdup_printf (templ->name_template, session++);
+    pad_it = gst_element_iterate_pads (GST_ELEMENT (element));
+    name_found = TRUE;
+    while (!done) {
+      switch (gst_iterator_next (pad_it, &data)) {
+        case GST_ITERATOR_OK:
+        {
+          GstPad *pad;
+          gchar *name;
+
+          pad = g_value_get_object (&data);
+          name = gst_pad_get_name (pad);
+
+          if (strcmp (name, pad_name) == 0) {
+            done = TRUE;
+            name_found = FALSE;
+          }
+          g_free (name);
+          g_value_reset (&data);
+          break;
+        }
+        case GST_ITERATOR_ERROR:
+        case GST_ITERATOR_RESYNC:
+          /* restart iteration */
+          done = TRUE;
+          name_found = FALSE;
+          session = 0;
+          break;
+        case GST_ITERATOR_DONE:
+          done = TRUE;
+          break;
+      }
+    }
+    g_value_unset (&data);
+    gst_iterator_free (pad_it);
+  }
+
+  GST_DEBUG_OBJECT (element, "free pad name found: '%s'", pad_name);
+  return pad_name;
+}
+
+/*
+ */
+static GstPad *
+gst_rtp_bin_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
+{
+  GstRtpBin *rtpbin;
+  GstElementClass *klass;
+  GstPad *result;
+
+  gchar *pad_name = NULL;
+
+  g_return_val_if_fail (templ != NULL, NULL);
+  g_return_val_if_fail (GST_IS_RTP_BIN (element), NULL);
+
+  rtpbin = GST_RTP_BIN (element);
+  klass = GST_ELEMENT_GET_CLASS (element);
+
+  GST_RTP_BIN_LOCK (rtpbin);
+
+  if (name == NULL) {
+    /* use a free pad name */
+    pad_name = gst_rtp_bin_get_free_pad_name (element, templ);
+  } else {
+    /* use the provided name */
+    pad_name = g_strdup (name);
+  }
+
+  GST_DEBUG_OBJECT (rtpbin, "Trying to request a pad with name %s", pad_name);
+
+  /* figure out the template */
+  if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%u")) {
+    result = create_recv_rtp (rtpbin, templ, pad_name);
+  } else if (templ == gst_element_class_get_pad_template (klass,
+          "recv_rtcp_sink_%u")) {
+    result = create_recv_rtcp (rtpbin, templ, pad_name);
+  } else if (templ == gst_element_class_get_pad_template (klass,
+          "send_rtp_sink_%u")) {
+    result = create_send_rtp (rtpbin, templ, pad_name);
+  } else if (templ == gst_element_class_get_pad_template (klass,
+          "send_rtcp_src_%u")) {
+    result = create_send_rtcp (rtpbin, templ, pad_name);
+  } else
+    goto wrong_template;
+
+  g_free (pad_name);
+  GST_RTP_BIN_UNLOCK (rtpbin);
+
+  return result;
+
+  /* ERRORS */
+wrong_template:
+  {
+    g_free (pad_name);
+    GST_RTP_BIN_UNLOCK (rtpbin);
+    g_warning ("rtpbin: this is not our template");
+    return NULL;
+  }
+}
+
+static void
+gst_rtp_bin_release_pad (GstElement * element, GstPad * pad)
+{
+  GstRtpBinSession *session;
+  GstRtpBin *rtpbin;
+
+  g_return_if_fail (GST_IS_GHOST_PAD (pad));
+  g_return_if_fail (GST_IS_RTP_BIN (element));
+
+  rtpbin = GST_RTP_BIN (element);
+
+  GST_RTP_BIN_LOCK (rtpbin);
+  GST_DEBUG_OBJECT (rtpbin, "Trying to release pad %s:%s",
+      GST_DEBUG_PAD_NAME (pad));
+
+  if (!(session = find_session_by_pad (rtpbin, pad)))
+    goto unknown_pad;
+
+  if (session->recv_rtp_sink_ghost == pad) {
+    remove_recv_rtp (rtpbin, session);
+  } else if (session->recv_rtcp_sink_ghost == pad) {
+    remove_recv_rtcp (rtpbin, session);
+  } else if (session->send_rtp_sink_ghost == pad) {
+    remove_send_rtp (rtpbin, session);
+  } else if (session->send_rtcp_src_ghost == pad) {
+    remove_rtcp (rtpbin, session);
+  }
+
+  /* no more request pads, free the complete session */
+  if (session->recv_rtp_sink_ghost == NULL
+      && session->recv_rtcp_sink_ghost == NULL
+      && session->send_rtp_sink_ghost == NULL
+      && session->send_rtcp_src_ghost == NULL) {
+    GST_DEBUG_OBJECT (rtpbin, "no more pads for session %p", session);
+    rtpbin->sessions = g_slist_remove (rtpbin->sessions, session);
+    free_session (session, rtpbin);
+  }
+  GST_RTP_BIN_UNLOCK (rtpbin);
+
+  return;
+
+  /* ERROR */
+unknown_pad:
+  {
+    GST_RTP_BIN_UNLOCK (rtpbin);
+    g_warning ("rtpbin: %s:%s is not one of our request pads",
+        GST_DEBUG_PAD_NAME (pad));
+    return;
+  }
+}
diff --git a/gst/rtpmanager/gstrtpbin.h b/gst/rtpmanager/gstrtpbin.h
new file mode 100644
index 0000000..5722a21
--- /dev/null
+++ b/gst/rtpmanager/gstrtpbin.h
@@ -0,0 +1,139 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_BIN_H__
+#define __GST_RTP_BIN_H__
+
+#include <gst/gst.h>
+
+#include "rtpsession.h"
+#include "gstrtpsession.h"
+#include "rtpjitterbuffer.h"
+
+#define GST_TYPE_RTP_BIN \
+  (gst_rtp_bin_get_type())
+#define GST_RTP_BIN(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_BIN,GstRtpBin))
+#define GST_RTP_BIN_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_BIN,GstRtpBinClass))
+#define GST_IS_RTP_BIN(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_BIN))
+#define GST_IS_RTP_BIN_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_BIN))
+
+typedef enum
+{
+  GST_RTP_BIN_RTCP_SYNC_ALWAYS,
+  GST_RTP_BIN_RTCP_SYNC_INITIAL,
+  GST_RTP_BIN_RTCP_SYNC_RTP
+} GstRTCPSync;
+
+typedef struct _GstRtpBin GstRtpBin;
+typedef struct _GstRtpBinClass GstRtpBinClass;
+typedef struct _GstRtpBinPrivate GstRtpBinPrivate;
+
+struct _GstRtpBin {
+  GstBin         bin;
+
+  /*< private >*/
+  /* default latency for sessions */
+  guint           latency_ms;
+  guint64         latency_ns;
+  gboolean        drop_on_latency;
+  gboolean        do_lost;
+  gboolean        ignore_pt;
+  gboolean        ntp_sync;
+  gint            rtcp_sync;
+  guint           rtcp_sync_interval;
+  RTPJitterBufferMode buffer_mode;
+  gboolean        buffering;
+  gboolean        use_pipeline_clock;
+  GstRtpNtpTimeSource ntp_time_source;
+  gboolean        send_sync_event;
+  GstClockTime    buffer_start;
+  gboolean        do_retransmission;
+  GstRTPProfile   rtp_profile;
+  gboolean        rtcp_sync_send_time;
+  gint            max_rtcp_rtp_time_diff;
+  guint32         max_dropout_time;
+  guint32         max_misorder_time;
+  gboolean        rfc7273_sync;
+  guint           max_streams;
+  guint64         max_ts_offset_adjustment;
+  gint64          max_ts_offset;
+  gboolean        max_ts_offset_is_set;
+
+  /* a list of session */
+  GSList         *sessions;
+
+  /* a list of clients, these are streams with the same CNAME */
+  GSList         *clients;
+
+  /* the default SDES items for sessions */
+  GstStructure   *sdes;
+
+  /*< private >*/
+  GstRtpBinPrivate *priv;
+};
+
+struct _GstRtpBinClass {
+  GstBinClass  parent_class;
+
+  /* get the caps for pt */
+  GstCaps*    (*request_pt_map)       (GstRtpBin *rtpbin, guint session, guint pt);
+
+  void        (*payload_type_change)  (GstRtpBin *rtpbin, guint session, guint pt);
+
+  void        (*new_jitterbuffer)     (GstRtpBin *rtpbin, GstElement *jitterbuffer, guint session, guint32 ssrc);
+
+  /* action signals */
+  void        (*clear_pt_map)         (GstRtpBin *rtpbin);
+  void        (*reset_sync)           (GstRtpBin *rtpbin);
+  GstElement* (*get_session)          (GstRtpBin *rtpbin, guint session);
+  RTPSession* (*get_internal_session) (GstRtpBin *rtpbin, guint session);
+
+  /* session manager signals */
+  void     (*on_new_ssrc)       (GstRtpBin *rtpbin, guint session, guint32 ssrc);
+  void     (*on_ssrc_collision) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
+  void     (*on_ssrc_validated) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
+  void     (*on_ssrc_active)    (GstRtpBin *rtpbin, guint session, guint32 ssrc);
+  void     (*on_ssrc_sdes)      (GstRtpBin *rtpbin, guint session, guint32 ssrc);
+  void     (*on_bye_ssrc)       (GstRtpBin *rtpbin, guint session, guint32 ssrc);
+  void     (*on_bye_timeout)    (GstRtpBin *rtpbin, guint session, guint32 ssrc);
+  void     (*on_timeout)        (GstRtpBin *rtpbin, guint session, guint32 ssrc);
+  void     (*on_sender_timeout) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
+  void     (*on_npt_stop)       (GstRtpBin *rtpbin, guint session, guint32 ssrc);
+
+  GstElement* (*request_rtp_encoder)  (GstRtpBin *rtpbin, guint session);
+  GstElement* (*request_rtp_decoder)  (GstRtpBin *rtpbin, guint session);
+  GstElement* (*request_rtcp_encoder) (GstRtpBin *rtpbin, guint session);
+  GstElement* (*request_rtcp_decoder) (GstRtpBin *rtpbin, guint session);
+
+  GstElement* (*request_aux_sender)   (GstRtpBin *rtpbin, guint session);
+  GstElement* (*request_aux_receiver) (GstRtpBin *rtpbin, guint session);
+
+  void     (*on_new_sender_ssrc)      (GstRtpBin *rtpbin, guint session, guint32 ssrc);
+  void     (*on_sender_ssrc_active)   (GstRtpBin *rtpbin, guint session, guint32 ssrc);
+
+  guint    (*on_bundled_ssrc)         (GstRtpBin *rtpbin, guint ssrc);
+};
+
+GType gst_rtp_bin_get_type (void);
+
+#endif /* __GST_RTP_BIN_H__ */
diff --git a/gst/rtpmanager/gstrtpdtmfmux.c b/gst/rtpmanager/gstrtpdtmfmux.c
new file mode 100644
index 0000000..cc6d747
--- /dev/null
+++ b/gst/rtpmanager/gstrtpdtmfmux.c
@@ -0,0 +1,233 @@
+/* RTP DTMF muxer element for GStreamer
+ *
+ * gstrtpdtmfmux.c:
+ *
+ * Copyright (C) <2007-2010> Nokia Corporation.
+ *   Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
+ * Copyright (C) <2007-2010> Collabora Ltd
+ *   Contact: Olivier Crete <olivier.crete@collabora.co.uk>
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2000,2005 Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpdtmfmux
+ * @see_also: rtpdtmfsrc, dtmfsrc, rtpmux
+ *
+ * The RTP "DTMF" Muxer muxes multiple RTP streams into a valid RTP
+ * stream. It does exactly what its parent (#rtpmux) does, except
+ * that it prevent buffers coming over a regular sink_\%u pad from going through
+ * for the duration of buffers that came in a priority_sink_\%u pad.
+ *
+ * This is especially useful if a discontinuous source like dtmfsrc or
+ * rtpdtmfsrc are connected to the priority sink pads. This way, the generated
+ * DTMF signal can replace the recorded audio while the tone is being sent.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <string.h>
+
+#include "gstrtpdtmfmux.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_dtmf_mux_debug);
+#define GST_CAT_DEFAULT gst_rtp_dtmf_mux_debug
+
+static GstStaticPadTemplate priority_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("priority_sink_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("application/x-rtp"));
+
+static GstPad *gst_rtp_dtmf_mux_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
+static GstStateChangeReturn gst_rtp_dtmf_mux_change_state (GstElement * element,
+    GstStateChange transition);
+
+static gboolean gst_rtp_dtmf_mux_accept_buffer_locked (GstRTPMux * rtp_mux,
+    GstRTPMuxPadPrivate * padpriv, GstRTPBuffer * rtpbuffer);
+static gboolean gst_rtp_dtmf_mux_src_event (GstRTPMux * rtp_mux,
+    GstEvent * event);
+
+G_DEFINE_TYPE (GstRTPDTMFMux, gst_rtp_dtmf_mux, GST_TYPE_RTP_MUX);
+
+static void
+gst_rtp_dtmf_mux_init (GstRTPDTMFMux * mux)
+{
+}
+
+
+static void
+gst_rtp_dtmf_mux_class_init (GstRTPDTMFMuxClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GstRTPMuxClass *gstrtpmux_class;
+
+  gstelement_class = (GstElementClass *) klass;
+  gstrtpmux_class = (GstRTPMuxClass *) klass;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &priority_sink_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP muxer",
+      "Codec/Muxer",
+      "mixes RTP DTMF streams into other RTP streams",
+      "Zeeshan Ali <first.last@nokia.com>");
+
+  gstelement_class->request_new_pad =
+      GST_DEBUG_FUNCPTR (gst_rtp_dtmf_mux_request_new_pad);
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_rtp_dtmf_mux_change_state);
+  gstrtpmux_class->accept_buffer_locked = gst_rtp_dtmf_mux_accept_buffer_locked;
+  gstrtpmux_class->src_event = gst_rtp_dtmf_mux_src_event;
+}
+
+static gboolean
+gst_rtp_dtmf_mux_accept_buffer_locked (GstRTPMux * rtp_mux,
+    GstRTPMuxPadPrivate * padpriv, GstRTPBuffer * rtpbuffer)
+{
+  GstRTPDTMFMux *mux = GST_RTP_DTMF_MUX (rtp_mux);
+  GstClockTime running_ts;
+
+  running_ts = GST_BUFFER_PTS (rtpbuffer->buffer);
+
+  if (GST_CLOCK_TIME_IS_VALID (running_ts)) {
+    if (padpriv && padpriv->segment.format == GST_FORMAT_TIME)
+      running_ts = gst_segment_to_running_time (&padpriv->segment,
+          GST_FORMAT_TIME, GST_BUFFER_PTS (rtpbuffer->buffer));
+
+    if (padpriv && padpriv->priority) {
+      if (GST_BUFFER_PTS_IS_VALID (rtpbuffer->buffer)) {
+        if (GST_CLOCK_TIME_IS_VALID (mux->last_priority_end))
+          mux->last_priority_end =
+              MAX (running_ts + GST_BUFFER_DURATION (rtpbuffer->buffer),
+              mux->last_priority_end);
+        else
+          mux->last_priority_end = running_ts +
+              GST_BUFFER_DURATION (rtpbuffer->buffer);
+        GST_LOG_OBJECT (mux, "Got buffer %p on priority pad, "
+            " blocking regular pads until %" GST_TIME_FORMAT, rtpbuffer->buffer,
+            GST_TIME_ARGS (mux->last_priority_end));
+      } else {
+        GST_WARNING_OBJECT (mux, "Buffer %p has an invalid duration,"
+            " not blocking other pad", rtpbuffer->buffer);
+      }
+    } else {
+      if (GST_CLOCK_TIME_IS_VALID (mux->last_priority_end) &&
+          running_ts < mux->last_priority_end) {
+        GST_LOG_OBJECT (mux, "Dropping buffer %p because running time"
+            " %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT, rtpbuffer->buffer,
+            GST_TIME_ARGS (running_ts), GST_TIME_ARGS (mux->last_priority_end));
+        return FALSE;
+      }
+    }
+  } else {
+    GST_LOG_OBJECT (mux, "Buffer %p has an invalid timestamp,"
+        " letting through", rtpbuffer->buffer);
+  }
+
+  return TRUE;
+}
+
+
+static GstPad *
+gst_rtp_dtmf_mux_request_new_pad (GstElement * element, GstPadTemplate * templ,
+    const gchar * name, const GstCaps * caps)
+{
+  GstPad *pad;
+
+  pad =
+      GST_ELEMENT_CLASS (gst_rtp_dtmf_mux_parent_class)->request_new_pad
+      (element, templ, name, caps);
+
+  if (pad) {
+    GstRTPMuxPadPrivate *padpriv;
+
+    GST_OBJECT_LOCK (element);
+    padpriv = gst_pad_get_element_private (pad);
+
+    if (gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (element),
+            "priority_sink_%u") == GST_PAD_PAD_TEMPLATE (pad))
+      padpriv->priority = TRUE;
+    GST_OBJECT_UNLOCK (element);
+  }
+
+  return pad;
+}
+
+static gboolean
+gst_rtp_dtmf_mux_src_event (GstRTPMux * rtp_mux, GstEvent * event)
+{
+  if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM) {
+    const GstStructure *s = gst_event_get_structure (event);
+
+    if (s && gst_structure_has_name (s, "dtmf-event")) {
+      GST_OBJECT_LOCK (rtp_mux);
+      if (GST_CLOCK_TIME_IS_VALID (rtp_mux->last_stop)) {
+        event = (GstEvent *)
+            gst_mini_object_make_writable (GST_MINI_OBJECT_CAST (event));
+        s = gst_event_get_structure (event);
+        gst_structure_set ((GstStructure *) s,
+            "last-stop", G_TYPE_UINT64, rtp_mux->last_stop, NULL);
+      }
+      GST_OBJECT_UNLOCK (rtp_mux);
+    }
+  }
+
+  return GST_RTP_MUX_CLASS (gst_rtp_dtmf_mux_parent_class)->src_event (rtp_mux,
+      event);
+}
+
+
+static GstStateChangeReturn
+gst_rtp_dtmf_mux_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstRTPDTMFMux *mux = GST_RTP_DTMF_MUX (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+    {
+      GST_OBJECT_LOCK (mux);
+      mux->last_priority_end = GST_CLOCK_TIME_NONE;
+      GST_OBJECT_UNLOCK (mux);
+      break;
+    }
+    default:
+      break;
+  }
+
+  ret =
+      GST_ELEMENT_CLASS (gst_rtp_dtmf_mux_parent_class)->change_state (element,
+      transition);
+
+  return ret;
+}
+
+gboolean
+gst_rtp_dtmf_mux_plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_dtmf_mux_debug, "rtpdtmfmux", 0,
+      "rtp dtmf muxer");
+
+  return gst_element_register (plugin, "rtpdtmfmux", GST_RANK_NONE,
+      GST_TYPE_RTP_DTMF_MUX);
+}
diff --git a/gst/rtpmanager/gstrtpdtmfmux.h b/gst/rtpmanager/gstrtpdtmfmux.h
new file mode 100644
index 0000000..651e9ec
--- /dev/null
+++ b/gst/rtpmanager/gstrtpdtmfmux.h
@@ -0,0 +1,67 @@
+/* RTP muxer element for GStreamer
+ *
+ * gstrtpdtmfmux.h:
+ *
+ * Copyright (C) <2007> Nokia Corporation.
+ *   Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2000,2005 Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_DTMF_MUX_H__
+#define __GST_RTP_DTMF_MUX_H__
+
+#include <gst/gst.h>
+#include "gstrtpmux.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_DTMF_MUX (gst_rtp_dtmf_mux_get_type())
+#define GST_RTP_DTMF_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_DTMF_MUX, GstRTPDTMFMux))
+#define GST_RTP_DTMF_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_DTMF_MUX, GstRTPDTMFMux))
+#define GST_IS_RTP_DTMF_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_DTMF_MUX))
+#define GST_IS_RTP_DTMF_MUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_DTMF_MUX))
+typedef struct _GstRTPDTMFMux GstRTPDTMFMux;
+typedef struct _GstRTPDTMFMuxClass GstRTPDTMFMuxClass;
+
+/**
+ * GstRTPDTMFMux:
+ *
+ * The opaque #GstRTPDTMFMux structure.
+ */
+struct _GstRTPDTMFMux
+{
+  GstRTPMux mux;
+
+  /* Protected by object lock */
+  GstClockTime last_priority_end;
+};
+
+struct _GstRTPDTMFMuxClass
+{
+  GstRTPMuxClass parent_class;
+
+  /* signals */
+  void (*locking) (GstElement * element, GstPad * pad);
+  void (*unlocked) (GstElement * element, GstPad * pad);
+};
+
+GType gst_rtp_dtmf_mux_get_type (void);
+gboolean gst_rtp_dtmf_mux_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_DTMF_MUX_H__ */
diff --git a/gst/rtpmanager/gstrtpjitterbuffer.c b/gst/rtpmanager/gstrtpjitterbuffer.c
new file mode 100644
index 0000000..552c887
--- /dev/null
+++ b/gst/rtpmanager/gstrtpjitterbuffer.c
@@ -0,0 +1,4862 @@
+/*
+ * Farsight Voice+Video library
+ *
+ *  Copyright 2007 Collabora Ltd,
+ *  Copyright 2007 Nokia Corporation
+ *   @author: Philippe Kalaf <philippe.kalaf@collabora.co.uk>.
+ *  Copyright 2007 Wim Taymans <wim.taymans@gmail.com>
+ *  Copyright 2015 Kurento (http://kurento.org/)
+ *   @author: Miguel París <mparisdiaz@gmail.com>
+ *  Copyright 2016 Pexip AS
+ *   @author: Havard Graff <havard@pexip.com>
+ *   @author: Stian Selnes <stian@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+/**
+ * SECTION:element-rtpjitterbuffer
+ *
+ * This element reorders and removes duplicate RTP packets as they are received
+ * from a network source.
+ *
+ * The element needs the clock-rate of the RTP payload in order to estimate the
+ * delay. This information is obtained either from the caps on the sink pad or,
+ * when no caps are present, from the #GstRtpJitterBuffer::request-pt-map signal.
+ * To clear the previous pt-map use the #GstRtpJitterBuffer::clear-pt-map signal.
+ *
+ * The rtpjitterbuffer will wait for missing packets up to a configurable time
+ * limit using the #GstRtpJitterBuffer:latency property. Packets arriving too
+ * late are considered to be lost packets. If the #GstRtpJitterBuffer:do-lost
+ * property is set, lost packets will result in a custom serialized downstream
+ * event of name GstRTPPacketLost. The lost packet events are usually used by a
+ * depayloader or other element to create concealment data or some other logic
+ * to gracefully handle the missing packets.
+ *
+ * The jitterbuffer will use the DTS (or PTS if no DTS is set) of the incomming
+ * buffer and the rtptime inside the RTP packet to create a PTS on the outgoing
+ * buffer.
+ *
+ * The jitterbuffer can also be configured to send early retransmission events
+ * upstream by setting the #GstRtpJitterBuffer:do-retransmission property. In
+ * this mode, the jitterbuffer tries to estimate when a packet should arrive and
+ * sends a custom upstream event named GstRTPRetransmissionRequest when the
+ * packet is considered late. The initial expected packet arrival time is
+ * calculated as follows:
+ *
+ * - If seqnum N arrived at time T, seqnum N+1 is expected to arrive at
+ *     T + packet-spacing + #GstRtpJitterBuffer:rtx-delay. The packet spacing is
+ *     calculated from the DTS (or PTS is no DTS) of two consecutive RTP
+ *     packets with different rtptime.
+ *
+ * - If seqnum N0 arrived at time T0 and seqnum Nm arrived at time Tm,
+ *     seqnum Ni is expected at time Ti = T0 + i*(Tm - T0)/(Nm - N0). Any
+ *     previously scheduled timeout is overwritten.
+ *
+ * - If seqnum N arrived, all seqnum older than
+ *     N - #GstRtpJitterBuffer:rtx-delay-reorder are considered late
+ *     immediately. This is to request fast feedback for abonormally reorder
+ *     packets before any of the previous timeouts is triggered.
+ *
+ * A late packet triggers the GstRTPRetransmissionRequest custom upstream
+ * event. After the initial timeout expires and the retransmission event is
+ * sent, the timeout is scheduled for
+ * T + #GstRtpJitterBuffer:rtx-retry-timeout. If the missing packet did not
+ * arrive after #GstRtpJitterBuffer:rtx-retry-timeout, a new
+ * GstRTPRetransmissionRequest is sent upstream and the timeout is rescheduled
+ * again for T + #GstRtpJitterBuffer:rtx-retry-timeout. This repeats until
+ * #GstRtpJitterBuffer:rtx-retry-period elapsed, at which point no further
+ * retransmission requests are sent and the regular logic is performed to
+ * schedule a lost packet as discussed above.
+ *
+ * This element acts as a live element and so adds #GstRtpJitterBuffer:latency
+ * to the pipeline.
+ *
+ * This element will automatically be used inside rtpbin.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 rtspsrc location=rtsp://192.168.1.133:8554/mpeg1or2AudioVideoTest ! rtpjitterbuffer ! rtpmpvdepay ! mpeg2dec ! xvimagesink
+ * ]| Connect to a streaming server and decode the MPEG video. The jitterbuffer is
+ * inserted into the pipeline to smooth out network jitter and to reorder the
+ * out-of-order RTP packets.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/net/net.h>
+
+#include "gstrtpjitterbuffer.h"
+#include "rtpjitterbuffer.h"
+#include "rtpstats.h"
+
+#include <gst/glib-compat-private.h>
+
+GST_DEBUG_CATEGORY (rtpjitterbuffer_debug);
+#define GST_CAT_DEFAULT (rtpjitterbuffer_debug)
+
+/* RTPJitterBuffer signals and args */
+enum
+{
+  SIGNAL_REQUEST_PT_MAP,
+  SIGNAL_CLEAR_PT_MAP,
+  SIGNAL_HANDLE_SYNC,
+  SIGNAL_ON_NPT_STOP,
+  SIGNAL_SET_ACTIVE,
+  LAST_SIGNAL
+};
+
+#define DEFAULT_LATENCY_MS          200
+#define DEFAULT_DROP_ON_LATENCY     FALSE
+#define DEFAULT_TS_OFFSET           0
+#define DEFAULT_MAX_TS_OFFSET_ADJUSTMENT 0
+#define DEFAULT_DO_LOST             FALSE
+#define DEFAULT_MODE                RTP_JITTER_BUFFER_MODE_SLAVE
+#define DEFAULT_PERCENT             0
+#define DEFAULT_DO_RETRANSMISSION   FALSE
+#define DEFAULT_RTX_NEXT_SEQNUM     TRUE
+#define DEFAULT_RTX_DELAY           -1
+#define DEFAULT_RTX_MIN_DELAY       0
+#define DEFAULT_RTX_DELAY_REORDER   3
+#define DEFAULT_RTX_RETRY_TIMEOUT   -1
+#define DEFAULT_RTX_MIN_RETRY_TIMEOUT   -1
+#define DEFAULT_RTX_RETRY_PERIOD    -1
+#define DEFAULT_RTX_MAX_RETRIES    -1
+#define DEFAULT_RTX_DEADLINE       -1
+#define DEFAULT_RTX_STATS_TIMEOUT   1000
+#define DEFAULT_MAX_RTCP_RTP_TIME_DIFF 1000
+#define DEFAULT_MAX_DROPOUT_TIME    60000
+#define DEFAULT_MAX_MISORDER_TIME   2000
+#define DEFAULT_RFC7273_SYNC        FALSE
+#define DEFAULT_FASTSTART_MIN_PACKETS 0
+
+#define DEFAULT_AUTO_RTX_DELAY (20 * GST_MSECOND)
+#define DEFAULT_AUTO_RTX_TIMEOUT (40 * GST_MSECOND)
+
+enum
+{
+  PROP_0,
+  PROP_LATENCY,
+  PROP_DROP_ON_LATENCY,
+  PROP_TS_OFFSET,
+  PROP_MAX_TS_OFFSET_ADJUSTMENT,
+  PROP_DO_LOST,
+  PROP_MODE,
+  PROP_PERCENT,
+  PROP_DO_RETRANSMISSION,
+  PROP_RTX_NEXT_SEQNUM,
+  PROP_RTX_DELAY,
+  PROP_RTX_MIN_DELAY,
+  PROP_RTX_DELAY_REORDER,
+  PROP_RTX_RETRY_TIMEOUT,
+  PROP_RTX_MIN_RETRY_TIMEOUT,
+  PROP_RTX_RETRY_PERIOD,
+  PROP_RTX_MAX_RETRIES,
+  PROP_RTX_DEADLINE,
+  PROP_RTX_STATS_TIMEOUT,
+  PROP_STATS,
+  PROP_MAX_RTCP_RTP_TIME_DIFF,
+  PROP_MAX_DROPOUT_TIME,
+  PROP_MAX_MISORDER_TIME,
+  PROP_RFC7273_SYNC,
+  PROP_FASTSTART_MIN_PACKETS
+};
+
+#define JBUF_LOCK(priv)   G_STMT_START {			\
+    GST_TRACE("Locking from thread %p", g_thread_self());	\
+    (g_mutex_lock (&(priv)->jbuf_lock));			\
+    GST_TRACE("Locked from thread %p", g_thread_self());	\
+  } G_STMT_END
+
+#define JBUF_LOCK_CHECK(priv,label) G_STMT_START {    \
+  JBUF_LOCK (priv);                                   \
+  if (G_UNLIKELY (priv->srcresult != GST_FLOW_OK))    \
+    goto label;                                       \
+} G_STMT_END
+#define JBUF_UNLOCK(priv) G_STMT_START {			\
+    GST_TRACE ("Unlocking from thread %p", g_thread_self ());	\
+    (g_mutex_unlock (&(priv)->jbuf_lock));			\
+} G_STMT_END
+
+#define JBUF_WAIT_TIMER(priv)   G_STMT_START {            \
+  GST_DEBUG ("waiting timer");                            \
+  (priv)->waiting_timer = TRUE;                           \
+  g_cond_wait (&(priv)->jbuf_timer, &(priv)->jbuf_lock);  \
+  (priv)->waiting_timer = FALSE;                          \
+  GST_DEBUG ("waiting timer done");                       \
+} G_STMT_END
+#define JBUF_SIGNAL_TIMER(priv) G_STMT_START {            \
+  if (G_UNLIKELY ((priv)->waiting_timer)) {               \
+    GST_DEBUG ("signal timer");                           \
+    g_cond_signal (&(priv)->jbuf_timer);                  \
+  }                                                       \
+} G_STMT_END
+
+#define JBUF_WAIT_EVENT(priv,label) G_STMT_START {       \
+  GST_DEBUG ("waiting event");                           \
+  (priv)->waiting_event = TRUE;                          \
+  g_cond_wait (&(priv)->jbuf_event, &(priv)->jbuf_lock); \
+  (priv)->waiting_event = FALSE;                         \
+  GST_DEBUG ("waiting event done");                      \
+  if (G_UNLIKELY (priv->srcresult != GST_FLOW_OK))       \
+    goto label;                                          \
+} G_STMT_END
+#define JBUF_SIGNAL_EVENT(priv) G_STMT_START {           \
+  if (G_UNLIKELY ((priv)->waiting_event)) {              \
+    GST_DEBUG ("signal event");                          \
+    g_cond_signal (&(priv)->jbuf_event);                 \
+  }                                                      \
+} G_STMT_END
+
+#define JBUF_WAIT_QUERY(priv,label) G_STMT_START {       \
+  GST_DEBUG ("waiting query");                           \
+  (priv)->waiting_query = TRUE;                          \
+  g_cond_wait (&(priv)->jbuf_query, &(priv)->jbuf_lock); \
+  (priv)->waiting_query = FALSE;                         \
+  GST_DEBUG ("waiting query done");                      \
+  if (G_UNLIKELY (priv->srcresult != GST_FLOW_OK))       \
+    goto label;                                          \
+} G_STMT_END
+#define JBUF_SIGNAL_QUERY(priv,res) G_STMT_START {       \
+  (priv)->last_query = res;                              \
+  if (G_UNLIKELY ((priv)->waiting_query)) {              \
+    GST_DEBUG ("signal query");                          \
+    g_cond_signal (&(priv)->jbuf_query);                 \
+  }                                                      \
+} G_STMT_END
+
+#define GST_BUFFER_IS_RETRANSMISSION(buffer) \
+  GST_BUFFER_FLAG_IS_SET (buffer, GST_RTP_BUFFER_FLAG_RETRANSMISSION)
+
+typedef struct TimerQueue
+{
+  GQueue *timers;
+  GHashTable *hashtable;
+} TimerQueue;
+
+struct _GstRtpJitterBufferPrivate
+{
+  GstPad *sinkpad, *srcpad;
+  GstPad *rtcpsinkpad;
+
+  RTPJitterBuffer *jbuf;
+  GMutex jbuf_lock;
+  gboolean waiting_timer;
+  GCond jbuf_timer;
+  gboolean waiting_event;
+  GCond jbuf_event;
+  gboolean waiting_query;
+  GCond jbuf_query;
+  gboolean last_query;
+  gboolean discont;
+  gboolean ts_discont;
+  gboolean active;
+  guint64 out_offset;
+
+  gboolean timer_running;
+  GThread *timer_thread;
+
+  /* properties */
+  guint latency_ms;
+  guint64 latency_ns;
+  gboolean drop_on_latency;
+  gint64 ts_offset;
+  guint64 max_ts_offset_adjustment;
+  gboolean do_lost;
+  gboolean do_retransmission;
+  gboolean rtx_next_seqnum;
+  gint rtx_delay;
+  guint rtx_min_delay;
+  gint rtx_delay_reorder;
+  gint rtx_retry_timeout;
+  gint rtx_min_retry_timeout;
+  gint rtx_retry_period;
+  gint rtx_max_retries;
+  guint rtx_stats_timeout;
+  gint rtx_deadline_ms;
+  gint max_rtcp_rtp_time_diff;
+  guint32 max_dropout_time;
+  guint32 max_misorder_time;
+  guint faststart_min_packets;
+
+  /* the last seqnum we pushed out */
+  guint32 last_popped_seqnum;
+  /* the next expected seqnum we push */
+  guint32 next_seqnum;
+  /* seqnum-base, if known */
+  guint32 seqnum_base;
+  /* last output time */
+  GstClockTime last_out_time;
+  /* last valid input timestamp and rtptime pair */
+  GstClockTime ips_pts;
+  guint64 ips_rtptime;
+  GstClockTime packet_spacing;
+  gint equidistant;
+
+  GQueue gap_packets;
+
+  /* the next expected seqnum we receive */
+  GstClockTime last_in_pts;
+  guint32 next_in_seqnum;
+
+  GArray *timers;
+  TimerQueue *rtx_stats_timers;
+
+  /* start and stop ranges */
+  GstClockTime npt_start;
+  GstClockTime npt_stop;
+  guint64 ext_timestamp;
+  guint64 last_elapsed;
+  guint64 estimated_eos;
+  GstClockID eos_id;
+
+  /* state */
+  gboolean eos;
+  guint last_percent;
+
+  /* clock rate and rtp timestamp offset */
+  gint last_pt;
+  gint32 clock_rate;
+  gint64 clock_base;
+  gint64 ts_offset_remainder;
+
+  /* when we are shutting down */
+  GstFlowReturn srcresult;
+  gboolean blocked;
+
+  /* for sync */
+  GstSegment segment;
+  GstClockID clock_id;
+  GstClockTime timer_timeout;
+  guint16 timer_seqnum;
+  /* the latency of the upstream peer, we have to take this into account when
+   * synchronizing the buffers. */
+  GstClockTime peer_latency;
+  guint64 ext_rtptime;
+  GstBuffer *last_sr;
+
+  /* some accounting */
+  guint64 num_pushed;
+  guint64 num_lost;
+  guint64 num_late;
+  guint64 num_duplicates;
+  guint64 num_rtx_requests;
+  guint64 num_rtx_success;
+  guint64 num_rtx_failed;
+  gdouble avg_rtx_num;
+  guint64 avg_rtx_rtt;
+  RTPPacketRateCtx packet_rate_ctx;
+
+  /* for the jitter */
+  GstClockTime last_dts;
+  GstClockTime last_pts;
+  guint64 last_rtptime;
+  GstClockTime avg_jitter;
+};
+
+typedef enum
+{
+  TIMER_TYPE_EXPECTED,
+  TIMER_TYPE_LOST,
+  TIMER_TYPE_DEADLINE,
+  TIMER_TYPE_EOS
+} TimerType;
+
+typedef struct
+{
+  guint idx;
+  guint16 seqnum;
+  guint num;
+  TimerType type;
+  GstClockTime timeout;
+  GstClockTime duration;
+  GstClockTime rtx_base;
+  GstClockTime rtx_delay;
+  GstClockTime rtx_retry;
+  GstClockTime rtx_last;
+  guint num_rtx_retry;
+  guint num_rtx_received;
+} TimerData;
+
+#define GST_RTP_JITTER_BUFFER_GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_RTP_JITTER_BUFFER, \
+                                GstRtpJitterBufferPrivate))
+
+static GstStaticPadTemplate gst_rtp_jitter_buffer_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp"
+        /* "clock-rate = (int) [ 1, 2147483647 ], "
+         * "payload = (int) , "
+         * "encoding-name = (string) "
+         */ )
+    );
+
+static GstStaticPadTemplate gst_rtp_jitter_buffer_sink_rtcp_template =
+GST_STATIC_PAD_TEMPLATE ("sink_rtcp",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("application/x-rtcp")
+    );
+
+static GstStaticPadTemplate gst_rtp_jitter_buffer_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp"
+        /* "payload = (int) , "
+         * "clock-rate = (int) , "
+         * "encoding-name = (string) "
+         */ )
+    );
+
+static guint gst_rtp_jitter_buffer_signals[LAST_SIGNAL] = { 0 };
+
+#define gst_rtp_jitter_buffer_parent_class parent_class
+G_DEFINE_TYPE (GstRtpJitterBuffer, gst_rtp_jitter_buffer, GST_TYPE_ELEMENT);
+
+/* object overrides */
+static void gst_rtp_jitter_buffer_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_rtp_jitter_buffer_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+static void gst_rtp_jitter_buffer_finalize (GObject * object);
+
+/* element overrides */
+static GstStateChangeReturn gst_rtp_jitter_buffer_change_state (GstElement
+    * element, GstStateChange transition);
+static GstPad *gst_rtp_jitter_buffer_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * filter);
+static void gst_rtp_jitter_buffer_release_pad (GstElement * element,
+    GstPad * pad);
+static GstClock *gst_rtp_jitter_buffer_provide_clock (GstElement * element);
+static gboolean gst_rtp_jitter_buffer_set_clock (GstElement * element,
+    GstClock * clock);
+
+/* pad overrides */
+static GstCaps *gst_rtp_jitter_buffer_getcaps (GstPad * pad, GstCaps * filter);
+static GstIterator *gst_rtp_jitter_buffer_iterate_internal_links (GstPad * pad,
+    GstObject * parent);
+
+/* sinkpad overrides */
+static gboolean gst_rtp_jitter_buffer_sink_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static GstFlowReturn gst_rtp_jitter_buffer_chain (GstPad * pad,
+    GstObject * parent, GstBuffer * buffer);
+static GstFlowReturn gst_rtp_jitter_buffer_chain_list (GstPad * pad,
+    GstObject * parent, GstBufferList * buffer_list);
+
+static gboolean gst_rtp_jitter_buffer_sink_rtcp_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static GstFlowReturn gst_rtp_jitter_buffer_chain_rtcp (GstPad * pad,
+    GstObject * parent, GstBuffer * buffer);
+
+static gboolean gst_rtp_jitter_buffer_sink_query (GstPad * pad,
+    GstObject * parent, GstQuery * query);
+
+/* srcpad overrides */
+static gboolean gst_rtp_jitter_buffer_src_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static gboolean gst_rtp_jitter_buffer_src_activate_mode (GstPad * pad,
+    GstObject * parent, GstPadMode mode, gboolean active);
+static void gst_rtp_jitter_buffer_loop (GstRtpJitterBuffer * jitterbuffer);
+static gboolean gst_rtp_jitter_buffer_src_query (GstPad * pad,
+    GstObject * parent, GstQuery * query);
+
+static void
+gst_rtp_jitter_buffer_clear_pt_map (GstRtpJitterBuffer * jitterbuffer);
+static GstClockTime
+gst_rtp_jitter_buffer_set_active (GstRtpJitterBuffer * jitterbuffer,
+    gboolean active, guint64 base_time);
+static void do_handle_sync (GstRtpJitterBuffer * jitterbuffer);
+
+static void unschedule_current_timer (GstRtpJitterBuffer * jitterbuffer);
+static void remove_all_timers (GstRtpJitterBuffer * jitterbuffer);
+
+static void wait_next_timeout (GstRtpJitterBuffer * jitterbuffer);
+
+static GstStructure *gst_rtp_jitter_buffer_create_stats (GstRtpJitterBuffer *
+    jitterbuffer);
+
+static void update_rtx_stats (GstRtpJitterBuffer * jitterbuffer,
+    TimerData * timer, GstClockTime dts, gboolean success);
+
+static TimerQueue *timer_queue_new (void);
+static void timer_queue_free (TimerQueue * queue);
+
+static void
+gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  g_type_class_add_private (klass, sizeof (GstRtpJitterBufferPrivate));
+
+  gobject_class->finalize = gst_rtp_jitter_buffer_finalize;
+
+  gobject_class->set_property = gst_rtp_jitter_buffer_set_property;
+  gobject_class->get_property = gst_rtp_jitter_buffer_get_property;
+
+  /**
+   * GstRtpJitterBuffer:latency:
+   *
+   * The maximum latency of the jitterbuffer. Packets will be kept in the buffer
+   * for at most this time.
+   */
+  g_object_class_install_property (gobject_class, PROP_LATENCY,
+      g_param_spec_uint ("latency", "Buffer latency in ms",
+          "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRtpJitterBuffer:drop-on-latency:
+   *
+   * Drop oldest buffers when the queue is completely filled.
+   */
+  g_object_class_install_property (gobject_class, PROP_DROP_ON_LATENCY,
+      g_param_spec_boolean ("drop-on-latency",
+          "Drop buffers when maximum latency is reached",
+          "Tells the jitterbuffer to never exceed the given latency in size",
+          DEFAULT_DROP_ON_LATENCY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRtpJitterBuffer:ts-offset:
+   *
+   * Adjust GStreamer output buffer timestamps in the jitterbuffer with offset.
+   * This is mainly used to ensure interstream synchronisation.
+   */
+  g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
+      g_param_spec_int64 ("ts-offset", "Timestamp Offset",
+          "Adjust buffer timestamps with offset in nanoseconds", G_MININT64,
+          G_MAXINT64, DEFAULT_TS_OFFSET,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpJitterBuffer:max-ts-offset-adjustment:
+   *
+   * The maximum number of nanoseconds per frame that time offset may be
+   * adjusted with. This is used to avoid sudden large changes to time stamps.
+   */
+  g_object_class_install_property (gobject_class, PROP_MAX_TS_OFFSET_ADJUSTMENT,
+      g_param_spec_uint64 ("max-ts-offset-adjustment",
+          "Max Timestamp Offset Adjustment",
+          "The maximum number of nanoseconds per frame that time stamp "
+          "offsets may be adjusted (0 = no limit).", 0, G_MAXUINT64,
+          DEFAULT_MAX_TS_OFFSET_ADJUSTMENT, G_PARAM_READWRITE |
+          G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpJitterBuffer:do-lost:
+   *
+   * Send out a GstRTPPacketLost event downstream when a packet is considered
+   * lost.
+   */
+  g_object_class_install_property (gobject_class, PROP_DO_LOST,
+      g_param_spec_boolean ("do-lost", "Do Lost",
+          "Send an event downstream when a packet is lost", DEFAULT_DO_LOST,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpJitterBuffer:mode:
+   *
+   * Control the buffering and timestamping mode used by the jitterbuffer.
+   */
+  g_object_class_install_property (gobject_class, PROP_MODE,
+      g_param_spec_enum ("mode", "Mode",
+          "Control the buffering algorithm in use", RTP_TYPE_JITTER_BUFFER_MODE,
+          DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRtpJitterBuffer:percent:
+   *
+   * The percent of the jitterbuffer that is filled.
+   */
+  g_object_class_install_property (gobject_class, PROP_PERCENT,
+      g_param_spec_int ("percent", "percent",
+          "The buffer filled percent", 0, 100,
+          0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRtpJitterBuffer:do-retransmission:
+   *
+   * Send out a GstRTPRetransmission event upstream when a packet is considered
+   * late and should be retransmitted.
+   *
+   * Since: 1.2
+   */
+  g_object_class_install_property (gobject_class, PROP_DO_RETRANSMISSION,
+      g_param_spec_boolean ("do-retransmission", "Do Retransmission",
+          "Send retransmission events upstream when a packet is late",
+          DEFAULT_DO_RETRANSMISSION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpJitterBuffer:rtx-next-seqnum
+   *
+   * Estimate when the next packet should arrive and schedule a retransmission
+   * request for it.
+   * This is, when packet N arrives, a GstRTPRetransmission event is schedule
+   * for packet N+1. So it will be requested if it does not arrive at the expected time.
+   * The expected time is calculated using the dts of N and the packet spacing.
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_RTX_NEXT_SEQNUM,
+      g_param_spec_boolean ("rtx-next-seqnum", "RTX next seqnum",
+          "Estimate when the next packet should arrive and schedule a "
+          "retransmission request for it.",
+          DEFAULT_RTX_NEXT_SEQNUM, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpJitterBuffer:rtx-delay:
+   *
+   * When a packet did not arrive at the expected time, wait this extra amount
+   * of time before sending a retransmission event.
+   *
+   * When -1 is used, the max jitter will be used as extra delay.
+   *
+   * Since: 1.2
+   */
+  g_object_class_install_property (gobject_class, PROP_RTX_DELAY,
+      g_param_spec_int ("rtx-delay", "RTX Delay",
+          "Extra time in ms to wait before sending retransmission "
+          "event (-1 automatic)", -1, G_MAXINT, DEFAULT_RTX_DELAY,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpJitterBuffer:rtx-min-delay:
+   *
+   * When a packet did not arrive at the expected time, wait at least this extra amount
+   * of time before sending a retransmission event.
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_RTX_MIN_DELAY,
+      g_param_spec_uint ("rtx-min-delay", "Minimum RTX Delay",
+          "Minimum time in ms to wait before sending retransmission "
+          "event", 0, G_MAXUINT, DEFAULT_RTX_MIN_DELAY,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRtpJitterBuffer:rtx-delay-reorder:
+   *
+   * Assume that a retransmission event should be sent when we see
+   * this much packet reordering.
+   *
+   * When -1 is used, the value will be estimated based on observed packet
+   * reordering. When 0 is used packet reordering alone will not cause a
+   * retransmission event (Since 1.10).
+   *
+   * Since: 1.2
+   */
+  g_object_class_install_property (gobject_class, PROP_RTX_DELAY_REORDER,
+      g_param_spec_int ("rtx-delay-reorder", "RTX Delay Reorder",
+          "Sending retransmission event when this much reordering "
+          "(0 disable, -1 automatic)",
+          -1, G_MAXINT, DEFAULT_RTX_DELAY_REORDER,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRtpJitterBuffer::rtx-retry-timeout:
+   *
+   * When no packet has been received after sending a retransmission event
+   * for this time, retry sending a retransmission event.
+   *
+   * When -1 is used, the value will be estimated based on observed round
+   * trip time.
+   *
+   * Since: 1.2
+   */
+  g_object_class_install_property (gobject_class, PROP_RTX_RETRY_TIMEOUT,
+      g_param_spec_int ("rtx-retry-timeout", "RTX Retry Timeout",
+          "Retry sending a transmission event after this timeout in "
+          "ms (-1 automatic)", -1, G_MAXINT, DEFAULT_RTX_RETRY_TIMEOUT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRtpJitterBuffer::rtx-min-retry-timeout:
+   *
+   * The minimum amount of time between retry timeouts. When
+   * GstRtpJitterBuffer::rtx-retry-timeout is -1, this value ensures a
+   * minimum interval between retry timeouts.
+   *
+   * When -1 is used, the value will be estimated based on the
+   * packet spacing.
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_RTX_MIN_RETRY_TIMEOUT,
+      g_param_spec_int ("rtx-min-retry-timeout", "RTX Min Retry Timeout",
+          "Minimum timeout between sending a transmission event in "
+          "ms (-1 automatic)", -1, G_MAXINT, DEFAULT_RTX_MIN_RETRY_TIMEOUT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRtpJitterBuffer:rtx-retry-period:
+   *
+   * The amount of time to try to get a retransmission.
+   *
+   * When -1 is used, the value will be estimated based on the jitterbuffer
+   * latency and the observed round trip time.
+   *
+   * Since: 1.2
+   */
+  g_object_class_install_property (gobject_class, PROP_RTX_RETRY_PERIOD,
+      g_param_spec_int ("rtx-retry-period", "RTX Retry Period",
+          "Try to get a retransmission for this many ms "
+          "(-1 automatic)", -1, G_MAXINT, DEFAULT_RTX_RETRY_PERIOD,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRtpJitterBuffer:rtx-max-retries:
+   *
+   * The maximum number of retries to request a retransmission.
+   *
+   * This implies that as maximum (rtx-max-retries + 1) retransmissions will be requested.
+   * When -1 is used, the number of retransmission request will not be limited.
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_RTX_MAX_RETRIES,
+      g_param_spec_int ("rtx-max-retries", "RTX Max Retries",
+          "The maximum number of retries to request a retransmission. "
+          "(-1 not limited)", -1, G_MAXINT, DEFAULT_RTX_MAX_RETRIES,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRtpJitterBuffer:rtx-deadline:
+   *
+   * The deadline for a valid RTX request in ms.
+   *
+   * How long the RTX RTCP will be valid for.
+   * When -1 is used, the size of the jitterbuffer will be used.
+   *
+   * Since: 1.10
+   */
+  g_object_class_install_property (gobject_class, PROP_RTX_DEADLINE,
+      g_param_spec_int ("rtx-deadline", "RTX Deadline (ms)",
+          "The deadline for a valid RTX request in milliseconds. "
+          "(-1 automatic)", -1, G_MAXINT, DEFAULT_RTX_DEADLINE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+/**
+   * GstRtpJitterBuffer::rtx-stats-timeout:
+   *
+   * The time to wait for a retransmitted packet after it has been
+   * considered lost in order to collect RTX statistics.
+   *
+   * Since: 1.10
+   */
+  g_object_class_install_property (gobject_class, PROP_RTX_STATS_TIMEOUT,
+      g_param_spec_uint ("rtx-stats-timeout", "RTX Statistics Timeout",
+          "The time to wait for a retransmitted packet after it has been "
+          "considered lost in order to collect statistics (ms)",
+          0, G_MAXUINT, DEFAULT_RTX_STATS_TIMEOUT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_DROPOUT_TIME,
+      g_param_spec_uint ("max-dropout-time", "Max dropout time",
+          "The maximum time (milliseconds) of missing packets tolerated.",
+          0, G_MAXUINT, DEFAULT_MAX_DROPOUT_TIME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_MISORDER_TIME,
+      g_param_spec_uint ("max-misorder-time", "Max misorder time",
+          "The maximum time (milliseconds) of misordered packets tolerated.",
+          0, G_MAXUINT, DEFAULT_MAX_MISORDER_TIME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRtpJitterBuffer:stats:
+   *
+   * Various jitterbuffer statistics. This property returns a GstStructure
+   * with name application/x-rtp-jitterbuffer-stats with the following fields:
+   *
+   * <itemizedlist>
+   * <listitem>
+   *   <para>
+   *   #guint64
+   *   <classname>&quot;num-pushed&quot;</classname>:
+   *   the number of packets pushed out.
+   *   </para>
+   * </listitem>
+   * <listitem>
+   *   <para>
+   *   #guint64
+   *   <classname>&quot;num-lost&quot;</classname>:
+   *   the number of packets considered lost.
+   *   </para>
+   * </listitem>
+   * <listitem>
+   *   <para>
+   *   #guint64
+   *   <classname>&quot;num-late&quot;</classname>:
+   *   the number of packets arriving too late.
+   *   </para>
+   * </listitem>
+   * <listitem>
+   *   <para>
+   *   #guint64
+   *   <classname>&quot;num-duplicates&quot;</classname>:
+   *   the number of duplicate packets.
+   *   </para>
+   * </listitem>
+   * <listitem>
+   *   <para>
+   *   #guint64
+   *   <classname>&quot;rtx-count&quot;</classname>:
+   *   the number of retransmissions requested.
+   *   </para>
+   * </listitem>
+   * <listitem>
+   *   <para>
+   *   #guint64
+   *   <classname>&quot;rtx-success-count&quot;</classname>:
+   *   the number of successful retransmissions.
+   *   </para>
+   * </listitem>
+   * <listitem>
+   *   <para>
+   *   #gdouble
+   *   <classname>&quot;rtx-per-packet&quot;</classname>:
+   *   average number of RTX per packet.
+   *   </para>
+   * </listitem>
+   * <listitem>
+   *   <para>
+   *   #guint64
+   *   <classname>&quot;rtx-rtt&quot;</classname>:
+   *   average round trip time per RTX.
+   *   </para>
+   * </listitem>
+   * </itemizedlist>
+   *
+   * Since: 1.4
+   */
+  g_object_class_install_property (gobject_class, PROP_STATS,
+      g_param_spec_boxed ("stats", "Statistics",
+          "Various statistics", GST_TYPE_STRUCTURE,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpJitterBuffer:max-rtcp-rtp-time-diff
+   *
+   * The maximum amount of time in ms that the RTP time in the RTCP SRs
+   * is allowed to be ahead of the last RTP packet we received. Use
+   * -1 to disable ignoring of RTCP packets.
+   *
+   * Since: 1.8
+   */
+  g_object_class_install_property (gobject_class, PROP_MAX_RTCP_RTP_TIME_DIFF,
+      g_param_spec_int ("max-rtcp-rtp-time-diff", "Max RTCP RTP Time Diff",
+          "Maximum amount of time in ms that the RTP time in RTCP SRs "
+          "is allowed to be ahead (-1 disabled)", -1, G_MAXINT,
+          DEFAULT_MAX_RTCP_RTP_TIME_DIFF,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RFC7273_SYNC,
+      g_param_spec_boolean ("rfc7273-sync", "Sync on RFC7273 clock",
+          "Synchronize received streams to the RFC7273 clock "
+          "(requires clock and offset to be provided)", DEFAULT_RFC7273_SYNC,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpJitterBuffer:faststart-min-packets
+   *
+   * The number of consecutive packets needed to start (set to 0 to
+   * disable faststart. The jitterbuffer will by default start after the
+   * latency has elapsed)
+   *
+   * Since: 1.14
+   */
+  g_object_class_install_property (gobject_class, PROP_FASTSTART_MIN_PACKETS,
+      g_param_spec_uint ("faststart-min-packets", "Faststart minimum packets",
+          "The number of consecutive packets needed to start (set to 0 to "
+          "disable faststart. The jitterbuffer will by default start after "
+          "the latency has elapsed)",
+          0, G_MAXUINT, DEFAULT_FASTSTART_MIN_PACKETS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpJitterBuffer::request-pt-map:
+   * @buffer: the object which received the signal
+   * @pt: the pt
+   *
+   * Request the payload type as #GstCaps for @pt.
+   */
+  gst_rtp_jitter_buffer_signals[SIGNAL_REQUEST_PT_MAP] =
+      g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpJitterBufferClass,
+          request_pt_map), NULL, NULL, g_cclosure_marshal_generic,
+      GST_TYPE_CAPS, 1, G_TYPE_UINT);
+  /**
+   * GstRtpJitterBuffer::handle-sync:
+   * @buffer: the object which received the signal
+   * @struct: a GstStructure containing sync values.
+   *
+   * Be notified of new sync values.
+   */
+  gst_rtp_jitter_buffer_signals[SIGNAL_HANDLE_SYNC] =
+      g_signal_new ("handle-sync", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpJitterBufferClass,
+          handle_sync), NULL, NULL, g_cclosure_marshal_VOID__BOXED,
+      G_TYPE_NONE, 1, GST_TYPE_STRUCTURE | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+  /**
+   * GstRtpJitterBuffer::on-npt-stop:
+   * @buffer: the object which received the signal
+   *
+   * Signal that the jitterbufer has pushed the RTP packet that corresponds to
+   * the npt-stop position.
+   */
+  gst_rtp_jitter_buffer_signals[SIGNAL_ON_NPT_STOP] =
+      g_signal_new ("on-npt-stop", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpJitterBufferClass,
+          on_npt_stop), NULL, NULL, g_cclosure_marshal_VOID__VOID,
+      G_TYPE_NONE, 0, G_TYPE_NONE);
+
+  /**
+   * GstRtpJitterBuffer::clear-pt-map:
+   * @buffer: the object which received the signal
+   *
+   * Invalidate the clock-rate as obtained with the
+   * #GstRtpJitterBuffer::request-pt-map signal.
+   */
+  gst_rtp_jitter_buffer_signals[SIGNAL_CLEAR_PT_MAP] =
+      g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_STRUCT_OFFSET (GstRtpJitterBufferClass, clear_pt_map), NULL, NULL,
+      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
+
+  /**
+   * GstRtpJitterBuffer::set-active:
+   * @buffer: the object which received the signal
+   *
+   * Start pushing out packets with the given base time. This signal is only
+   * useful in buffering mode.
+   *
+   * Returns: the time of the last pushed packet.
+   */
+  gst_rtp_jitter_buffer_signals[SIGNAL_SET_ACTIVE] =
+      g_signal_new ("set-active", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_STRUCT_OFFSET (GstRtpJitterBufferClass, set_active), NULL, NULL,
+      g_cclosure_marshal_generic, G_TYPE_UINT64, 2, G_TYPE_BOOLEAN,
+      G_TYPE_UINT64);
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_change_state);
+  gstelement_class->request_new_pad =
+      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_request_new_pad);
+  gstelement_class->release_pad =
+      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_release_pad);
+  gstelement_class->provide_clock =
+      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_provide_clock);
+  gstelement_class->set_clock =
+      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_set_clock);
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_jitter_buffer_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_jitter_buffer_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_jitter_buffer_sink_rtcp_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP packet jitter-buffer", "Filter/Network/RTP",
+      "A buffer that deals with network jitter and other transmission faults",
+      "Philippe Kalaf <philippe.kalaf@collabora.co.uk>, "
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  klass->clear_pt_map = GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_clear_pt_map);
+  klass->set_active = GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_set_active);
+
+  GST_DEBUG_CATEGORY_INIT
+      (rtpjitterbuffer_debug, "rtpjitterbuffer", 0, "RTP Jitter Buffer");
+}
+
+static void
+gst_rtp_jitter_buffer_init (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstRtpJitterBufferPrivate *priv;
+
+  priv = GST_RTP_JITTER_BUFFER_GET_PRIVATE (jitterbuffer);
+  jitterbuffer->priv = priv;
+
+  priv->latency_ms = DEFAULT_LATENCY_MS;
+  priv->latency_ns = priv->latency_ms * GST_MSECOND;
+  priv->drop_on_latency = DEFAULT_DROP_ON_LATENCY;
+  priv->ts_offset = DEFAULT_TS_OFFSET;
+  priv->max_ts_offset_adjustment = DEFAULT_MAX_TS_OFFSET_ADJUSTMENT;
+  priv->do_lost = DEFAULT_DO_LOST;
+  priv->do_retransmission = DEFAULT_DO_RETRANSMISSION;
+  priv->rtx_next_seqnum = DEFAULT_RTX_NEXT_SEQNUM;
+  priv->rtx_delay = DEFAULT_RTX_DELAY;
+  priv->rtx_min_delay = DEFAULT_RTX_MIN_DELAY;
+  priv->rtx_delay_reorder = DEFAULT_RTX_DELAY_REORDER;
+  priv->rtx_retry_timeout = DEFAULT_RTX_RETRY_TIMEOUT;
+  priv->rtx_min_retry_timeout = DEFAULT_RTX_MIN_RETRY_TIMEOUT;
+  priv->rtx_retry_period = DEFAULT_RTX_RETRY_PERIOD;
+  priv->rtx_max_retries = DEFAULT_RTX_MAX_RETRIES;
+  priv->rtx_deadline_ms = DEFAULT_RTX_DEADLINE;
+  priv->rtx_stats_timeout = DEFAULT_RTX_STATS_TIMEOUT;
+  priv->max_rtcp_rtp_time_diff = DEFAULT_MAX_RTCP_RTP_TIME_DIFF;
+  priv->max_dropout_time = DEFAULT_MAX_DROPOUT_TIME;
+  priv->max_misorder_time = DEFAULT_MAX_MISORDER_TIME;
+  priv->faststart_min_packets = DEFAULT_FASTSTART_MIN_PACKETS;
+
+  priv->ts_offset_remainder = 0;
+  priv->last_dts = -1;
+  priv->last_pts = -1;
+  priv->last_rtptime = -1;
+  priv->avg_jitter = 0;
+  priv->timers = g_array_new (FALSE, TRUE, sizeof (TimerData));
+  priv->rtx_stats_timers = timer_queue_new ();
+  priv->jbuf = rtp_jitter_buffer_new ();
+  g_mutex_init (&priv->jbuf_lock);
+  g_cond_init (&priv->jbuf_timer);
+  g_cond_init (&priv->jbuf_event);
+  g_cond_init (&priv->jbuf_query);
+  g_queue_init (&priv->gap_packets);
+  gst_segment_init (&priv->segment, GST_FORMAT_TIME);
+
+  /* reset skew detection initialy */
+  rtp_jitter_buffer_reset_skew (priv->jbuf);
+  rtp_jitter_buffer_set_delay (priv->jbuf, priv->latency_ns);
+  rtp_jitter_buffer_set_buffering (priv->jbuf, FALSE);
+  priv->active = TRUE;
+
+  priv->srcpad =
+      gst_pad_new_from_static_template (&gst_rtp_jitter_buffer_src_template,
+      "src");
+
+  gst_pad_set_activatemode_function (priv->srcpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_src_activate_mode));
+  gst_pad_set_query_function (priv->srcpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_src_query));
+  gst_pad_set_event_function (priv->srcpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_src_event));
+
+  priv->sinkpad =
+      gst_pad_new_from_static_template (&gst_rtp_jitter_buffer_sink_template,
+      "sink");
+
+  gst_pad_set_chain_function (priv->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_chain));
+  gst_pad_set_chain_list_function (priv->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_chain_list));
+  gst_pad_set_event_function (priv->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_sink_event));
+  gst_pad_set_query_function (priv->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_sink_query));
+
+  gst_element_add_pad (GST_ELEMENT (jitterbuffer), priv->srcpad);
+  gst_element_add_pad (GST_ELEMENT (jitterbuffer), priv->sinkpad);
+
+  GST_OBJECT_FLAG_SET (jitterbuffer, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
+}
+
+#define IS_DROPABLE(it) (((it)->type == ITEM_TYPE_BUFFER) || ((it)->type == ITEM_TYPE_LOST))
+
+#define ITEM_TYPE_BUFFER        0
+#define ITEM_TYPE_LOST          1
+#define ITEM_TYPE_EVENT         2
+#define ITEM_TYPE_QUERY         3
+
+static RTPJitterBufferItem *
+alloc_item (gpointer data, guint type, GstClockTime dts, GstClockTime pts,
+    guint seqnum, guint count, guint rtptime)
+{
+  RTPJitterBufferItem *item;
+
+  item = g_slice_new (RTPJitterBufferItem);
+  item->data = data;
+  item->next = NULL;
+  item->prev = NULL;
+  item->type = type;
+  item->dts = dts;
+  item->pts = pts;
+  item->seqnum = seqnum;
+  item->count = count;
+  item->rtptime = rtptime;
+
+  return item;
+}
+
+static void
+free_item (RTPJitterBufferItem * item)
+{
+  g_return_if_fail (item != NULL);
+
+  if (item->data && item->type != ITEM_TYPE_QUERY)
+    gst_mini_object_unref (item->data);
+  g_slice_free (RTPJitterBufferItem, item);
+}
+
+static void
+free_item_and_retain_events (RTPJitterBufferItem * item, gpointer user_data)
+{
+  GList **l = user_data;
+
+  if (item->data && item->type == ITEM_TYPE_EVENT
+      && GST_EVENT_IS_STICKY (item->data)) {
+    *l = g_list_prepend (*l, item->data);
+  } else if (item->data && item->type != ITEM_TYPE_QUERY) {
+    gst_mini_object_unref (item->data);
+  }
+  g_slice_free (RTPJitterBufferItem, item);
+}
+
+static void
+gst_rtp_jitter_buffer_finalize (GObject * object)
+{
+  GstRtpJitterBuffer *jitterbuffer;
+  GstRtpJitterBufferPrivate *priv;
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER (object);
+  priv = jitterbuffer->priv;
+
+  g_array_free (priv->timers, TRUE);
+  timer_queue_free (priv->rtx_stats_timers);
+  g_mutex_clear (&priv->jbuf_lock);
+  g_cond_clear (&priv->jbuf_timer);
+  g_cond_clear (&priv->jbuf_event);
+  g_cond_clear (&priv->jbuf_query);
+
+  rtp_jitter_buffer_flush (priv->jbuf, (GFunc) free_item, NULL);
+  g_queue_foreach (&priv->gap_packets, (GFunc) gst_buffer_unref, NULL);
+  g_queue_clear (&priv->gap_packets);
+  g_object_unref (priv->jbuf);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstIterator *
+gst_rtp_jitter_buffer_iterate_internal_links (GstPad * pad, GstObject * parent)
+{
+  GstRtpJitterBuffer *jitterbuffer;
+  GstPad *otherpad = NULL;
+  GstIterator *it = NULL;
+  GValue val = { 0, };
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER_CAST (parent);
+
+  if (pad == jitterbuffer->priv->sinkpad) {
+    otherpad = jitterbuffer->priv->srcpad;
+  } else if (pad == jitterbuffer->priv->srcpad) {
+    otherpad = jitterbuffer->priv->sinkpad;
+  } else if (pad == jitterbuffer->priv->rtcpsinkpad) {
+    it = gst_iterator_new_single (GST_TYPE_PAD, NULL);
+  }
+
+  if (it == NULL) {
+    g_value_init (&val, GST_TYPE_PAD);
+    g_value_set_object (&val, otherpad);
+    it = gst_iterator_new_single (GST_TYPE_PAD, &val);
+    g_value_unset (&val);
+  }
+
+  return it;
+}
+
+static GstPad *
+create_rtcp_sink (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstRtpJitterBufferPrivate *priv;
+
+  priv = jitterbuffer->priv;
+
+  GST_DEBUG_OBJECT (jitterbuffer, "creating RTCP sink pad");
+
+  priv->rtcpsinkpad =
+      gst_pad_new_from_static_template
+      (&gst_rtp_jitter_buffer_sink_rtcp_template, "sink_rtcp");
+  gst_pad_set_chain_function (priv->rtcpsinkpad,
+      gst_rtp_jitter_buffer_chain_rtcp);
+  gst_pad_set_event_function (priv->rtcpsinkpad,
+      (GstPadEventFunction) gst_rtp_jitter_buffer_sink_rtcp_event);
+  gst_pad_set_iterate_internal_links_function (priv->rtcpsinkpad,
+      gst_rtp_jitter_buffer_iterate_internal_links);
+  gst_pad_set_active (priv->rtcpsinkpad, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (jitterbuffer), priv->rtcpsinkpad);
+
+  return priv->rtcpsinkpad;
+}
+
+static void
+remove_rtcp_sink (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstRtpJitterBufferPrivate *priv;
+
+  priv = jitterbuffer->priv;
+
+  GST_DEBUG_OBJECT (jitterbuffer, "removing RTCP sink pad");
+
+  gst_pad_set_active (priv->rtcpsinkpad, FALSE);
+
+  gst_element_remove_pad (GST_ELEMENT_CAST (jitterbuffer), priv->rtcpsinkpad);
+  priv->rtcpsinkpad = NULL;
+}
+
+static GstPad *
+gst_rtp_jitter_buffer_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * filter)
+{
+  GstRtpJitterBuffer *jitterbuffer;
+  GstElementClass *klass;
+  GstPad *result;
+  GstRtpJitterBufferPrivate *priv;
+
+  g_return_val_if_fail (templ != NULL, NULL);
+  g_return_val_if_fail (GST_IS_RTP_JITTER_BUFFER (element), NULL);
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER_CAST (element);
+  priv = jitterbuffer->priv;
+  klass = GST_ELEMENT_GET_CLASS (element);
+
+  GST_DEBUG_OBJECT (element, "requesting pad %s", GST_STR_NULL (name));
+
+  /* figure out the template */
+  if (templ == gst_element_class_get_pad_template (klass, "sink_rtcp")) {
+    if (priv->rtcpsinkpad != NULL)
+      goto exists;
+
+    result = create_rtcp_sink (jitterbuffer);
+  } else
+    goto wrong_template;
+
+  return result;
+
+  /* ERRORS */
+wrong_template:
+  {
+    g_warning ("rtpjitterbuffer: this is not our template");
+    return NULL;
+  }
+exists:
+  {
+    g_warning ("rtpjitterbuffer: pad already requested");
+    return NULL;
+  }
+}
+
+static void
+gst_rtp_jitter_buffer_release_pad (GstElement * element, GstPad * pad)
+{
+  GstRtpJitterBuffer *jitterbuffer;
+  GstRtpJitterBufferPrivate *priv;
+
+  g_return_if_fail (GST_IS_RTP_JITTER_BUFFER (element));
+  g_return_if_fail (GST_IS_PAD (pad));
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER_CAST (element);
+  priv = jitterbuffer->priv;
+
+  GST_DEBUG_OBJECT (element, "releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
+
+  if (priv->rtcpsinkpad == pad) {
+    remove_rtcp_sink (jitterbuffer);
+  } else
+    goto wrong_pad;
+
+  return;
+
+  /* ERRORS */
+wrong_pad:
+  {
+    g_warning ("gstjitterbuffer: asked to release an unknown pad");
+    return;
+  }
+}
+
+static GstClock *
+gst_rtp_jitter_buffer_provide_clock (GstElement * element)
+{
+  return gst_system_clock_obtain ();
+}
+
+static gboolean
+gst_rtp_jitter_buffer_set_clock (GstElement * element, GstClock * clock)
+{
+  GstRtpJitterBuffer *jitterbuffer = GST_RTP_JITTER_BUFFER (element);
+
+  rtp_jitter_buffer_set_pipeline_clock (jitterbuffer->priv->jbuf, clock);
+
+  return GST_ELEMENT_CLASS (parent_class)->set_clock (element, clock);
+}
+
+static void
+gst_rtp_jitter_buffer_clear_pt_map (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstRtpJitterBufferPrivate *priv;
+
+  priv = jitterbuffer->priv;
+
+  /* this will trigger a new pt-map request signal, FIXME, do something better. */
+
+  JBUF_LOCK (priv);
+  priv->clock_rate = -1;
+  /* do not clear current content, but refresh state for new arrival */
+  GST_DEBUG_OBJECT (jitterbuffer, "reset jitterbuffer");
+  rtp_jitter_buffer_reset_skew (priv->jbuf);
+  JBUF_UNLOCK (priv);
+}
+
+static GstClockTime
+gst_rtp_jitter_buffer_set_active (GstRtpJitterBuffer * jbuf, gboolean active,
+    guint64 offset)
+{
+  GstRtpJitterBufferPrivate *priv;
+  GstClockTime last_out;
+  RTPJitterBufferItem *item;
+
+  priv = jbuf->priv;
+
+  JBUF_LOCK (priv);
+  GST_DEBUG_OBJECT (jbuf, "setting active %d with offset %" GST_TIME_FORMAT,
+      active, GST_TIME_ARGS (offset));
+
+  if (active != priv->active) {
+    /* add the amount of time spent in paused to the output offset. All
+     * outgoing buffers will have this offset applied to their timestamps in
+     * order to make them arrive in time in the sink. */
+    priv->out_offset = offset;
+    GST_DEBUG_OBJECT (jbuf, "out offset %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (priv->out_offset));
+    priv->active = active;
+    JBUF_SIGNAL_EVENT (priv);
+  }
+  if (!active) {
+    rtp_jitter_buffer_set_buffering (priv->jbuf, TRUE);
+  }
+  if ((item = rtp_jitter_buffer_peek (priv->jbuf))) {
+    /* head buffer timestamp and offset gives our output time */
+    last_out = item->pts + priv->ts_offset;
+  } else {
+    /* use last known time when the buffer is empty */
+    last_out = priv->last_out_time;
+  }
+  JBUF_UNLOCK (priv);
+
+  return last_out;
+}
+
+static GstCaps *
+gst_rtp_jitter_buffer_getcaps (GstPad * pad, GstCaps * filter)
+{
+  GstRtpJitterBuffer *jitterbuffer;
+  GstRtpJitterBufferPrivate *priv;
+  GstPad *other;
+  GstCaps *caps;
+  GstCaps *templ;
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER (gst_pad_get_parent (pad));
+  priv = jitterbuffer->priv;
+
+  other = (pad == priv->srcpad ? priv->sinkpad : priv->srcpad);
+
+  caps = gst_pad_peer_query_caps (other, filter);
+
+  templ = gst_pad_get_pad_template_caps (pad);
+  if (caps == NULL) {
+    GST_DEBUG_OBJECT (jitterbuffer, "use template");
+    caps = templ;
+  } else {
+    GstCaps *intersect;
+
+    GST_DEBUG_OBJECT (jitterbuffer, "intersect with template");
+
+    intersect = gst_caps_intersect (caps, templ);
+    gst_caps_unref (caps);
+    gst_caps_unref (templ);
+
+    caps = intersect;
+  }
+  gst_object_unref (jitterbuffer);
+
+  return caps;
+}
+
+/*
+ * Must be called with JBUF_LOCK held
+ */
+
+static gboolean
+gst_jitter_buffer_sink_parse_caps (GstRtpJitterBuffer * jitterbuffer,
+    GstCaps * caps, gint pt)
+{
+  GstRtpJitterBufferPrivate *priv;
+  GstStructure *caps_struct;
+  guint val;
+  gint payload = -1;
+  GstClockTime tval;
+  const gchar *ts_refclk, *mediaclk;
+
+  priv = jitterbuffer->priv;
+
+  /* first parse the caps */
+  caps_struct = gst_caps_get_structure (caps, 0);
+
+  GST_DEBUG_OBJECT (jitterbuffer, "got caps %" GST_PTR_FORMAT, caps);
+
+  if (gst_structure_get_int (caps_struct, "payload", &payload) && pt != -1
+      && payload != pt) {
+    GST_ERROR_OBJECT (jitterbuffer,
+        "Got caps with wrong payload type (got %d, expected %d)", pt, payload);
+    return FALSE;
+  }
+
+  if (payload != -1) {
+    GST_DEBUG_OBJECT (jitterbuffer, "Got payload type %d", payload);
+    priv->last_pt = payload;
+  }
+
+  /* we need a clock-rate to convert the rtp timestamps to GStreamer time and to
+   * measure the amount of data in the buffer */
+  if (!gst_structure_get_int (caps_struct, "clock-rate", &priv->clock_rate))
+    goto error;
+
+  if (priv->clock_rate <= 0)
+    goto wrong_rate;
+
+  GST_DEBUG_OBJECT (jitterbuffer, "got clock-rate %d", priv->clock_rate);
+
+  rtp_jitter_buffer_set_clock_rate (priv->jbuf, priv->clock_rate);
+
+  gst_rtp_packet_rate_ctx_reset (&priv->packet_rate_ctx, priv->clock_rate);
+
+  /* The clock base is the RTP timestamp corrsponding to the npt-start value. We
+   * can use this to track the amount of time elapsed on the sender. */
+  if (gst_structure_get_uint (caps_struct, "clock-base", &val))
+    priv->clock_base = val;
+  else
+    priv->clock_base = -1;
+
+  priv->ext_timestamp = priv->clock_base;
+
+  GST_DEBUG_OBJECT (jitterbuffer, "got clock-base %" G_GINT64_FORMAT,
+      priv->clock_base);
+
+  if (gst_structure_get_uint (caps_struct, "seqnum-base", &val)) {
+    /* first expected seqnum, only update when we didn't have a previous base. */
+    if (priv->next_in_seqnum == -1)
+      priv->next_in_seqnum = val;
+    if (priv->next_seqnum == -1) {
+      priv->next_seqnum = val;
+      JBUF_SIGNAL_EVENT (priv);
+    }
+    priv->seqnum_base = val;
+  } else {
+    priv->seqnum_base = -1;
+  }
+
+  GST_DEBUG_OBJECT (jitterbuffer, "got seqnum-base %d", priv->next_in_seqnum);
+
+  /* the start and stop times. The seqnum-base corresponds to the start time. We
+   * will keep track of the seqnums on the output and when we reach the one
+   * corresponding to npt-stop, we emit the npt-stop-reached signal */
+  if (gst_structure_get_clock_time (caps_struct, "npt-start", &tval))
+    priv->npt_start = tval;
+  else
+    priv->npt_start = 0;
+
+  if (gst_structure_get_clock_time (caps_struct, "npt-stop", &tval))
+    priv->npt_stop = tval;
+  else
+    priv->npt_stop = -1;
+
+  GST_DEBUG_OBJECT (jitterbuffer,
+      "npt start/stop: %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
+      GST_TIME_ARGS (priv->npt_start), GST_TIME_ARGS (priv->npt_stop));
+
+  if ((ts_refclk = gst_structure_get_string (caps_struct, "a-ts-refclk"))) {
+    GstClock *clock = NULL;
+    guint64 clock_offset = -1;
+
+    GST_DEBUG_OBJECT (jitterbuffer, "Have timestamp reference clock %s",
+        ts_refclk);
+
+    if (g_str_has_prefix (ts_refclk, "ntp=")) {
+      if (g_str_has_prefix (ts_refclk, "ntp=/traceable/")) {
+        GST_FIXME_OBJECT (jitterbuffer, "Can't handle traceable NTP clocks");
+      } else {
+        const gchar *host, *portstr;
+        gchar *hostname;
+        guint port;
+
+        host = ts_refclk + sizeof ("ntp=") - 1;
+        if (host[0] == '[') {
+          /* IPv6 */
+          portstr = strchr (host, ']');
+          if (portstr && portstr[1] == ':')
+            portstr = portstr + 1;
+          else
+            portstr = NULL;
+        } else {
+          portstr = strrchr (host, ':');
+        }
+
+
+        if (!portstr || sscanf (portstr, ":%u", &port) != 1)
+          port = 123;
+
+        if (portstr)
+          hostname = g_strndup (host, (portstr - host));
+        else
+          hostname = g_strdup (host);
+
+        clock = gst_ntp_clock_new (NULL, hostname, port, 0);
+        g_free (hostname);
+      }
+    } else if (g_str_has_prefix (ts_refclk, "ptp=IEEE1588-2008:")) {
+      const gchar *domainstr =
+          ts_refclk + sizeof ("ptp=IEEE1588-2008:XX-XX-XX-XX-XX-XX-XX-XX") - 1;
+      guint domain;
+
+      if (domainstr[0] != ':' || sscanf (domainstr, ":%u", &domain) != 1)
+        domain = 0;
+
+      clock = gst_ptp_clock_new (NULL, domain);
+    } else {
+      GST_FIXME_OBJECT (jitterbuffer, "Unsupported timestamp reference clock");
+    }
+
+    if ((mediaclk = gst_structure_get_string (caps_struct, "a-mediaclk"))) {
+      GST_DEBUG_OBJECT (jitterbuffer, "Got media clock %s", mediaclk);
+
+      if (!g_str_has_prefix (mediaclk, "direct=")
+          || sscanf (mediaclk, "direct=%" G_GUINT64_FORMAT, &clock_offset) != 1)
+        GST_FIXME_OBJECT (jitterbuffer, "Unsupported media clock");
+      if (strstr (mediaclk, "rate=") != NULL) {
+        GST_FIXME_OBJECT (jitterbuffer, "Rate property not supported");
+        clock_offset = -1;
+      }
+    }
+
+    rtp_jitter_buffer_set_media_clock (priv->jbuf, clock, clock_offset);
+  } else {
+    rtp_jitter_buffer_set_media_clock (priv->jbuf, NULL, -1);
+  }
+
+  return TRUE;
+
+  /* ERRORS */
+error:
+  {
+    GST_DEBUG_OBJECT (jitterbuffer, "No clock-rate in caps!");
+    return FALSE;
+  }
+wrong_rate:
+  {
+    GST_DEBUG_OBJECT (jitterbuffer, "Invalid clock-rate %d", priv->clock_rate);
+    return FALSE;
+  }
+}
+
+static void
+gst_rtp_jitter_buffer_flush_start (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstRtpJitterBufferPrivate *priv;
+
+  priv = jitterbuffer->priv;
+
+  JBUF_LOCK (priv);
+  /* mark ourselves as flushing */
+  priv->srcresult = GST_FLOW_FLUSHING;
+  GST_DEBUG_OBJECT (jitterbuffer, "Disabling pop on queue");
+  /* this unblocks any waiting pops on the src pad task */
+  JBUF_SIGNAL_EVENT (priv);
+  JBUF_SIGNAL_QUERY (priv, FALSE);
+  JBUF_UNLOCK (priv);
+}
+
+static void
+gst_rtp_jitter_buffer_flush_stop (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstRtpJitterBufferPrivate *priv;
+
+  priv = jitterbuffer->priv;
+
+  JBUF_LOCK (priv);
+  GST_DEBUG_OBJECT (jitterbuffer, "Enabling pop on queue");
+  /* Mark as non flushing */
+  priv->srcresult = GST_FLOW_OK;
+  gst_segment_init (&priv->segment, GST_FORMAT_TIME);
+  priv->last_popped_seqnum = -1;
+  priv->last_out_time = GST_CLOCK_TIME_NONE;
+  priv->next_seqnum = -1;
+  priv->seqnum_base = -1;
+  priv->ips_rtptime = -1;
+  priv->ips_pts = GST_CLOCK_TIME_NONE;
+  priv->packet_spacing = 0;
+  priv->next_in_seqnum = -1;
+  priv->clock_rate = -1;
+  priv->last_pt = -1;
+  priv->eos = FALSE;
+  priv->estimated_eos = -1;
+  priv->last_elapsed = 0;
+  priv->ext_timestamp = -1;
+  priv->avg_jitter = 0;
+  priv->last_dts = -1;
+  priv->last_rtptime = -1;
+  priv->last_in_pts = 0;
+  priv->equidistant = 0;
+  GST_DEBUG_OBJECT (jitterbuffer, "flush and reset jitterbuffer");
+  rtp_jitter_buffer_flush (priv->jbuf, (GFunc) free_item, NULL);
+  rtp_jitter_buffer_disable_buffering (priv->jbuf, FALSE);
+  rtp_jitter_buffer_reset_skew (priv->jbuf);
+  remove_all_timers (jitterbuffer);
+  g_queue_foreach (&priv->gap_packets, (GFunc) gst_buffer_unref, NULL);
+  g_queue_clear (&priv->gap_packets);
+  JBUF_UNLOCK (priv);
+}
+
+static gboolean
+gst_rtp_jitter_buffer_src_activate_mode (GstPad * pad, GstObject * parent,
+    GstPadMode mode, gboolean active)
+{
+  gboolean result;
+  GstRtpJitterBuffer *jitterbuffer = NULL;
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER (parent);
+
+  switch (mode) {
+    case GST_PAD_MODE_PUSH:
+      if (active) {
+        /* allow data processing */
+        gst_rtp_jitter_buffer_flush_stop (jitterbuffer);
+
+        /* start pushing out buffers */
+        GST_DEBUG_OBJECT (jitterbuffer, "Starting task on srcpad");
+        result = gst_pad_start_task (jitterbuffer->priv->srcpad,
+            (GstTaskFunction) gst_rtp_jitter_buffer_loop, jitterbuffer, NULL);
+      } else {
+        /* make sure all data processing stops ASAP */
+        gst_rtp_jitter_buffer_flush_start (jitterbuffer);
+
+        /* NOTE this will hardlock if the state change is called from the src pad
+         * task thread because we will _join() the thread. */
+        GST_DEBUG_OBJECT (jitterbuffer, "Stopping task on srcpad");
+        result = gst_pad_stop_task (pad);
+      }
+      break;
+    default:
+      result = FALSE;
+      break;
+  }
+  return result;
+}
+
+static GstStateChangeReturn
+gst_rtp_jitter_buffer_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstRtpJitterBuffer *jitterbuffer;
+  GstRtpJitterBufferPrivate *priv;
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER (element);
+  priv = jitterbuffer->priv;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      JBUF_LOCK (priv);
+      /* reset negotiated values */
+      priv->clock_rate = -1;
+      priv->clock_base = -1;
+      priv->peer_latency = 0;
+      priv->last_pt = -1;
+      /* block until we go to PLAYING */
+      priv->blocked = TRUE;
+      priv->timer_running = TRUE;
+      priv->timer_thread =
+          g_thread_new ("timer", (GThreadFunc) wait_next_timeout, jitterbuffer);
+      JBUF_UNLOCK (priv);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      JBUF_LOCK (priv);
+      /* unblock to allow streaming in PLAYING */
+      priv->blocked = FALSE;
+      JBUF_SIGNAL_EVENT (priv);
+      JBUF_SIGNAL_TIMER (priv);
+      JBUF_UNLOCK (priv);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      /* we are a live element because we sync to the clock, which we can only
+       * do in the PLAYING state */
+      if (ret != GST_STATE_CHANGE_FAILURE)
+        ret = GST_STATE_CHANGE_NO_PREROLL;
+      break;
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      JBUF_LOCK (priv);
+      /* block to stop streaming when PAUSED */
+      priv->blocked = TRUE;
+      unschedule_current_timer (jitterbuffer);
+      JBUF_UNLOCK (priv);
+      if (ret != GST_STATE_CHANGE_FAILURE)
+        ret = GST_STATE_CHANGE_NO_PREROLL;
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      JBUF_LOCK (priv);
+      gst_buffer_replace (&priv->last_sr, NULL);
+      priv->timer_running = FALSE;
+      unschedule_current_timer (jitterbuffer);
+      JBUF_SIGNAL_TIMER (priv);
+      JBUF_SIGNAL_QUERY (priv, FALSE);
+      JBUF_UNLOCK (priv);
+      g_thread_join (priv->timer_thread);
+      priv->timer_thread = NULL;
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_rtp_jitter_buffer_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  gboolean ret = TRUE;
+  GstRtpJitterBuffer *jitterbuffer;
+  GstRtpJitterBufferPrivate *priv;
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER_CAST (parent);
+  priv = jitterbuffer->priv;
+
+  GST_DEBUG_OBJECT (jitterbuffer, "received %s", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_LATENCY:
+    {
+      GstClockTime latency;
+
+      gst_event_parse_latency (event, &latency);
+
+      GST_DEBUG_OBJECT (jitterbuffer,
+          "configuring latency of %" GST_TIME_FORMAT, GST_TIME_ARGS (latency));
+
+      JBUF_LOCK (priv);
+      /* adjust the overall buffer delay to the total pipeline latency in
+       * buffering mode because if downstream consumes too fast (because of
+       * large latency or queues, we would start rebuffering again. */
+      if (rtp_jitter_buffer_get_mode (priv->jbuf) ==
+          RTP_JITTER_BUFFER_MODE_BUFFER) {
+        rtp_jitter_buffer_set_delay (priv->jbuf, latency);
+      }
+      JBUF_UNLOCK (priv);
+
+      ret = gst_pad_push_event (priv->sinkpad, event);
+      break;
+    }
+    default:
+      ret = gst_pad_push_event (priv->sinkpad, event);
+      break;
+  }
+
+  return ret;
+}
+
+/* handles and stores the event in the jitterbuffer, must be called with
+ * LOCK */
+static gboolean
+queue_event (GstRtpJitterBuffer * jitterbuffer, GstEvent * event)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  RTPJitterBufferItem *item;
+  gboolean head;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      gst_jitter_buffer_sink_parse_caps (jitterbuffer, caps, -1);
+      break;
+    }
+    case GST_EVENT_SEGMENT:
+    {
+      GstSegment segment;
+      gst_event_copy_segment (event, &segment);
+
+      /* we need time for now */
+      if (segment.format != GST_FORMAT_TIME) {
+        GST_DEBUG_OBJECT (jitterbuffer, "ignoring non-TIME newsegment");
+        gst_event_unref (event);
+
+        gst_segment_init (&segment, GST_FORMAT_TIME);
+        event = gst_event_new_segment (&segment);
+      }
+
+      priv->segment = segment;
+      break;
+    }
+    case GST_EVENT_EOS:
+      priv->eos = TRUE;
+      rtp_jitter_buffer_disable_buffering (priv->jbuf, TRUE);
+      break;
+    default:
+      break;
+  }
+
+
+  GST_DEBUG_OBJECT (jitterbuffer, "adding event");
+  item = alloc_item (event, ITEM_TYPE_EVENT, -1, -1, -1, 0, -1);
+  rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL);
+  if (head)
+    JBUF_SIGNAL_EVENT (priv);
+
+  return TRUE;
+}
+
+static gboolean
+gst_rtp_jitter_buffer_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  gboolean ret = TRUE;
+  GstRtpJitterBuffer *jitterbuffer;
+  GstRtpJitterBufferPrivate *priv;
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER (parent);
+  priv = jitterbuffer->priv;
+
+  GST_DEBUG_OBJECT (jitterbuffer, "received %s", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      ret = gst_pad_push_event (priv->srcpad, event);
+      gst_rtp_jitter_buffer_flush_start (jitterbuffer);
+      /* wait for the loop to go into PAUSED */
+      gst_pad_pause_task (priv->srcpad);
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      ret = gst_pad_push_event (priv->srcpad, event);
+      ret =
+          gst_rtp_jitter_buffer_src_activate_mode (priv->srcpad, parent,
+          GST_PAD_MODE_PUSH, TRUE);
+      break;
+    default:
+      if (GST_EVENT_IS_SERIALIZED (event)) {
+        /* serialized events go in the queue */
+        JBUF_LOCK (priv);
+        if (priv->srcresult != GST_FLOW_OK) {
+          /* Errors in sticky event pushing are no problem and ignored here
+           * as they will cause more meaningful errors during data flow.
+           * For EOS events, that are not followed by data flow, we still
+           * return FALSE here though.
+           */
+          if (!GST_EVENT_IS_STICKY (event) ||
+              GST_EVENT_TYPE (event) == GST_EVENT_EOS)
+            goto out_flow_error;
+        }
+        /* refuse more events on EOS */
+        if (priv->eos)
+          goto out_eos;
+        ret = queue_event (jitterbuffer, event);
+        JBUF_UNLOCK (priv);
+      } else {
+        /* non-serialized events are forwarded downstream immediately */
+        ret = gst_pad_push_event (priv->srcpad, event);
+      }
+      break;
+  }
+  return ret;
+
+  /* ERRORS */
+out_flow_error:
+  {
+    GST_DEBUG_OBJECT (jitterbuffer,
+        "refusing event, we have a downstream flow error: %s",
+        gst_flow_get_name (priv->srcresult));
+    JBUF_UNLOCK (priv);
+    gst_event_unref (event);
+    return FALSE;
+  }
+out_eos:
+  {
+    GST_DEBUG_OBJECT (jitterbuffer, "refusing event, we are EOS");
+    JBUF_UNLOCK (priv);
+    gst_event_unref (event);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_rtp_jitter_buffer_sink_rtcp_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  gboolean ret = TRUE;
+  GstRtpJitterBuffer *jitterbuffer;
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER (parent);
+
+  GST_DEBUG_OBJECT (jitterbuffer, "received %s", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      gst_event_unref (event);
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      gst_event_unref (event);
+      break;
+    default:
+      ret = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return ret;
+}
+
+/*
+ * Must be called with JBUF_LOCK held, will release the LOCK when emiting the
+ * signal. The function returns GST_FLOW_ERROR when a parsing error happened and
+ * GST_FLOW_FLUSHING when the element is shutting down. On success
+ * GST_FLOW_OK is returned.
+ */
+static GstFlowReturn
+gst_rtp_jitter_buffer_get_clock_rate (GstRtpJitterBuffer * jitterbuffer,
+    guint8 pt)
+{
+  GValue ret = { 0 };
+  GValue args[2] = { {0}, {0} };
+  GstCaps *caps;
+  gboolean res;
+
+  g_value_init (&args[0], GST_TYPE_ELEMENT);
+  g_value_set_object (&args[0], jitterbuffer);
+  g_value_init (&args[1], G_TYPE_UINT);
+  g_value_set_uint (&args[1], pt);
+
+  g_value_init (&ret, GST_TYPE_CAPS);
+  g_value_set_boxed (&ret, NULL);
+
+  JBUF_UNLOCK (jitterbuffer->priv);
+  g_signal_emitv (args, gst_rtp_jitter_buffer_signals[SIGNAL_REQUEST_PT_MAP], 0,
+      &ret);
+  JBUF_LOCK_CHECK (jitterbuffer->priv, out_flushing);
+
+  g_value_unset (&args[0]);
+  g_value_unset (&args[1]);
+  caps = (GstCaps *) g_value_dup_boxed (&ret);
+  g_value_unset (&ret);
+  if (!caps)
+    goto no_caps;
+
+  res = gst_jitter_buffer_sink_parse_caps (jitterbuffer, caps, pt);
+  gst_caps_unref (caps);
+
+  if (G_UNLIKELY (!res))
+    goto parse_failed;
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+no_caps:
+  {
+    GST_DEBUG_OBJECT (jitterbuffer, "could not get caps");
+    return GST_FLOW_ERROR;
+  }
+out_flushing:
+  {
+    GST_DEBUG_OBJECT (jitterbuffer, "we are flushing");
+    return GST_FLOW_FLUSHING;
+  }
+parse_failed:
+  {
+    GST_DEBUG_OBJECT (jitterbuffer, "parse failed");
+    return GST_FLOW_ERROR;
+  }
+}
+
+/* call with jbuf lock held */
+static GstMessage *
+check_buffering_percent (GstRtpJitterBuffer * jitterbuffer, gint percent)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  GstMessage *message = NULL;
+
+  if (percent == -1)
+    return NULL;
+
+  /* Post a buffering message */
+  if (priv->last_percent != percent) {
+    priv->last_percent = percent;
+    message =
+        gst_message_new_buffering (GST_OBJECT_CAST (jitterbuffer), percent);
+    gst_message_set_buffering_stats (message, GST_BUFFERING_LIVE, -1, -1, -1);
+  }
+
+  return message;
+}
+
+static void
+update_offset (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstRtpJitterBufferPrivate *priv;
+
+  priv = jitterbuffer->priv;
+
+  if (priv->ts_offset_remainder != 0) {
+    GST_DEBUG ("adjustment %" G_GUINT64_FORMAT " remain %" G_GINT64_FORMAT
+        " off %" G_GINT64_FORMAT, priv->max_ts_offset_adjustment,
+        priv->ts_offset_remainder, priv->ts_offset);
+    if (ABS (priv->ts_offset_remainder) > priv->max_ts_offset_adjustment) {
+      if (priv->ts_offset_remainder > 0) {
+        priv->ts_offset += priv->max_ts_offset_adjustment;
+        priv->ts_offset_remainder -= priv->max_ts_offset_adjustment;
+      } else {
+        priv->ts_offset -= priv->max_ts_offset_adjustment;
+        priv->ts_offset_remainder += priv->max_ts_offset_adjustment;
+      }
+    } else {
+      priv->ts_offset += priv->ts_offset_remainder;
+      priv->ts_offset_remainder = 0;
+    }
+  }
+}
+
+static GstClockTime
+apply_offset (GstRtpJitterBuffer * jitterbuffer, GstClockTime timestamp)
+{
+  GstRtpJitterBufferPrivate *priv;
+
+  priv = jitterbuffer->priv;
+
+  if (timestamp == -1)
+    return -1;
+
+  /* apply the timestamp offset, this is used for inter stream sync */
+  timestamp += priv->ts_offset;
+  /* add the offset, this is used when buffering */
+  timestamp += priv->out_offset;
+
+  return timestamp;
+}
+
+static TimerQueue *
+timer_queue_new (void)
+{
+  TimerQueue *queue;
+
+  queue = g_slice_new (TimerQueue);
+  queue->timers = g_queue_new ();
+  queue->hashtable = g_hash_table_new (NULL, NULL);
+
+  return queue;
+}
+
+static void
+timer_queue_free (TimerQueue * queue)
+{
+  if (!queue)
+    return;
+
+  g_hash_table_destroy (queue->hashtable);
+  g_queue_free_full (queue->timers, g_free);
+  g_slice_free (TimerQueue, queue);
+}
+
+static void
+timer_queue_append (TimerQueue * queue, const TimerData * timer,
+    GstClockTime timeout, gboolean lost)
+{
+  TimerData *copy;
+
+  copy = g_memdup (timer, sizeof (*timer));
+  copy->timeout = timeout;
+  copy->type = lost ? TIMER_TYPE_LOST : TIMER_TYPE_EXPECTED;
+  copy->idx = -1;
+
+  GST_LOG ("Append rtx-stats timer #%d, %" GST_TIME_FORMAT,
+      copy->seqnum, GST_TIME_ARGS (copy->timeout));
+  g_queue_push_tail (queue->timers, copy);
+  g_hash_table_insert (queue->hashtable, GINT_TO_POINTER (copy->seqnum), copy);
+}
+
+static void
+timer_queue_clear_until (TimerQueue * queue, GstClockTime timeout)
+{
+  TimerData *test;
+
+  test = g_queue_peek_head (queue->timers);
+  while (test && test->timeout < timeout) {
+    GST_LOG ("Pop rtx-stats timer #%d, %" GST_TIME_FORMAT " < %"
+        GST_TIME_FORMAT, test->seqnum, GST_TIME_ARGS (test->timeout),
+        GST_TIME_ARGS (timeout));
+    g_hash_table_remove (queue->hashtable, GINT_TO_POINTER (test->seqnum));
+    g_free (g_queue_pop_head (queue->timers));
+    test = g_queue_peek_head (queue->timers);
+  }
+}
+
+static TimerData *
+timer_queue_find (TimerQueue * queue, guint16 seqnum)
+{
+  return g_hash_table_lookup (queue->hashtable, GINT_TO_POINTER (seqnum));
+}
+
+static TimerData *
+find_timer (GstRtpJitterBuffer * jitterbuffer, guint16 seqnum)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  TimerData *timer = NULL;
+  gint i, len;
+
+  len = priv->timers->len;
+  for (i = 0; i < len; i++) {
+    TimerData *test = &g_array_index (priv->timers, TimerData, i);
+    if (test->seqnum == seqnum) {
+      timer = test;
+      break;
+    }
+  }
+  return timer;
+}
+
+static void
+unschedule_current_timer (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+
+  if (priv->clock_id) {
+    GST_DEBUG_OBJECT (jitterbuffer, "unschedule current timer");
+    gst_clock_id_unschedule (priv->clock_id);
+    priv->clock_id = NULL;
+  }
+}
+
+static GstClockTime
+get_timeout (GstRtpJitterBuffer * jitterbuffer, TimerData * timer)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  GstClockTime test_timeout;
+
+  if ((test_timeout = timer->timeout) == -1)
+    return -1;
+
+  if (timer->type != TIMER_TYPE_EXPECTED) {
+    /* add our latency and offset to get output times. */
+    test_timeout = apply_offset (jitterbuffer, test_timeout);
+    test_timeout += priv->latency_ns;
+  }
+  return test_timeout;
+}
+
+static void
+recalculate_timer (GstRtpJitterBuffer * jitterbuffer, TimerData * timer)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+
+  if (priv->clock_id) {
+    GstClockTime timeout = get_timeout (jitterbuffer, timer);
+
+    GST_DEBUG ("%" GST_TIME_FORMAT " <> %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (timeout), GST_TIME_ARGS (priv->timer_timeout));
+
+    if (timeout == -1 || timeout < priv->timer_timeout)
+      unschedule_current_timer (jitterbuffer);
+  }
+}
+
+static TimerData *
+add_timer (GstRtpJitterBuffer * jitterbuffer, TimerType type,
+    guint16 seqnum, guint num, GstClockTime timeout, GstClockTime delay,
+    GstClockTime duration)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  TimerData *timer;
+  gint len;
+
+  GST_DEBUG_OBJECT (jitterbuffer,
+      "add timer %d for seqnum %d to %" GST_TIME_FORMAT ", delay %"
+      GST_TIME_FORMAT, type, seqnum, GST_TIME_ARGS (timeout),
+      GST_TIME_ARGS (delay));
+
+  len = priv->timers->len;
+  g_array_set_size (priv->timers, len + 1);
+  timer = &g_array_index (priv->timers, TimerData, len);
+  timer->idx = len;
+  timer->type = type;
+  timer->seqnum = seqnum;
+  timer->num = num;
+  timer->timeout = timeout + delay;
+  timer->duration = duration;
+  if (type == TIMER_TYPE_EXPECTED) {
+    timer->rtx_base = timeout;
+    timer->rtx_delay = delay;
+    timer->rtx_retry = 0;
+  }
+  timer->rtx_last = GST_CLOCK_TIME_NONE;
+  timer->num_rtx_retry = 0;
+  timer->num_rtx_received = 0;
+  recalculate_timer (jitterbuffer, timer);
+  JBUF_SIGNAL_TIMER (priv);
+
+  return timer;
+}
+
+static void
+reschedule_timer (GstRtpJitterBuffer * jitterbuffer, TimerData * timer,
+    guint16 seqnum, GstClockTime timeout, GstClockTime delay, gboolean reset)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  gboolean seqchange, timechange;
+  guint16 oldseq;
+  GstClockTime new_timeout;
+
+  oldseq = timer->seqnum;
+  new_timeout = timeout + delay;
+  seqchange = oldseq != seqnum;
+  timechange = timer->timeout != new_timeout;
+
+  if (!seqchange && !timechange) {
+    GST_DEBUG_OBJECT (jitterbuffer,
+        "No changes in seqnum (%d) and timeout (%" GST_TIME_FORMAT
+        "), skipping", oldseq, GST_TIME_ARGS (timer->timeout));
+    return;
+  }
+
+  GST_DEBUG_OBJECT (jitterbuffer,
+      "replace timer %d for seqnum %d->%d timeout %" GST_TIME_FORMAT
+      "->%" GST_TIME_FORMAT, timer->type, oldseq, seqnum,
+      GST_TIME_ARGS (timer->timeout), GST_TIME_ARGS (new_timeout));
+
+  timer->timeout = new_timeout;
+  timer->seqnum = seqnum;
+  if (reset) {
+    GST_DEBUG_OBJECT (jitterbuffer, "reset rtx delay %" GST_TIME_FORMAT
+        "->%" GST_TIME_FORMAT, GST_TIME_ARGS (timer->rtx_delay),
+        GST_TIME_ARGS (delay));
+    timer->rtx_base = timeout;
+    timer->rtx_delay = delay;
+    timer->rtx_retry = 0;
+  }
+  if (seqchange) {
+    timer->num_rtx_retry = 0;
+    timer->num_rtx_received = 0;
+  }
+
+  if (priv->clock_id) {
+    /* we changed the seqnum and there is a timer currently waiting with this
+     * seqnum, unschedule it */
+    if (seqchange && priv->timer_seqnum == oldseq)
+      unschedule_current_timer (jitterbuffer);
+    /* we changed the time, check if it is earlier than what we are waiting
+     * for and unschedule if so */
+    else if (timechange)
+      recalculate_timer (jitterbuffer, timer);
+  }
+}
+
+static TimerData *
+set_timer (GstRtpJitterBuffer * jitterbuffer, TimerType type,
+    guint16 seqnum, GstClockTime timeout)
+{
+  TimerData *timer;
+
+  /* find the seqnum timer */
+  timer = find_timer (jitterbuffer, seqnum);
+  if (timer == NULL) {
+    timer = add_timer (jitterbuffer, type, seqnum, 0, timeout, 0, -1);
+  } else {
+    reschedule_timer (jitterbuffer, timer, seqnum, timeout, 0, FALSE);
+  }
+  return timer;
+}
+
+static void
+remove_timer (GstRtpJitterBuffer * jitterbuffer, TimerData * timer)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  guint idx;
+
+  if (timer->idx == -1)
+    return;
+
+  if (priv->clock_id && priv->timer_seqnum == timer->seqnum)
+    unschedule_current_timer (jitterbuffer);
+
+  idx = timer->idx;
+  GST_DEBUG_OBJECT (jitterbuffer, "removed index %d", idx);
+  g_array_remove_index_fast (priv->timers, idx);
+  timer->idx = idx;
+}
+
+static void
+remove_all_timers (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  GST_DEBUG_OBJECT (jitterbuffer, "removed all timers");
+  g_array_set_size (priv->timers, 0);
+  unschedule_current_timer (jitterbuffer);
+}
+
+/* get the extra delay to wait before sending RTX */
+static GstClockTime
+get_rtx_delay (GstRtpJitterBufferPrivate * priv)
+{
+  GstClockTime delay;
+
+  if (priv->rtx_delay == -1) {
+    if (priv->avg_jitter == 0 && priv->packet_spacing == 0) {
+      delay = DEFAULT_AUTO_RTX_DELAY;
+    } else {
+      /* jitter is in nanoseconds, maximum of 2x jitter and half the
+       * packet spacing is a good margin */
+      delay = MAX (priv->avg_jitter * 2, priv->packet_spacing / 2);
+    }
+  } else {
+    delay = priv->rtx_delay * GST_MSECOND;
+  }
+  if (priv->rtx_min_delay > 0)
+    delay = MAX (delay, priv->rtx_min_delay * GST_MSECOND);
+
+  return delay;
+}
+
+/* Check if packet with seqnum is already considered definitely lost by being
+ * part of a "lost timer" for multiple packets */
+static gboolean
+already_lost (GstRtpJitterBuffer * jitterbuffer, guint16 seqnum)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  gint i, len;
+
+  len = priv->timers->len;
+  for (i = 0; i < len; i++) {
+    TimerData *test = &g_array_index (priv->timers, TimerData, i);
+    gint gap = gst_rtp_buffer_compare_seqnum (test->seqnum, seqnum);
+
+    if (test->num > 1 && test->type == TIMER_TYPE_LOST && gap >= 0 &&
+        gap < test->num) {
+      GST_DEBUG ("seqnum #%d already considered definitely lost (#%d->#%d)",
+          seqnum, test->seqnum, (test->seqnum + test->num - 1) & 0xffff);
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/* we just received a packet with seqnum and dts.
+ *
+ * First check for old seqnum that we are still expecting. If the gap with the
+ * current seqnum is too big, unschedule the timeouts.
+ *
+ * If we have a valid packet spacing estimate we can set a timer for when we
+ * should receive the next packet.
+ * If we don't have a valid estimate, we remove any timer we might have
+ * had for this packet.
+ */
+static void
+update_timers (GstRtpJitterBuffer * jitterbuffer, guint16 seqnum,
+    GstClockTime dts, GstClockTime pts, gboolean do_next_seqnum,
+    gboolean is_rtx, TimerData * timer)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+
+  /* go through all timers and unschedule the ones with a large gap */
+  if (priv->do_retransmission && priv->rtx_delay_reorder > 0) {
+    gint i, len;
+    len = priv->timers->len;
+    for (i = 0; i < len; i++) {
+      TimerData *test = &g_array_index (priv->timers, TimerData, i);
+      gint gap;
+
+      gap = gst_rtp_buffer_compare_seqnum (test->seqnum, seqnum);
+
+      GST_DEBUG_OBJECT (jitterbuffer, "%d, #%d<->#%d gap %d",
+          test->type, test->seqnum, seqnum, gap);
+
+      if (gap > priv->rtx_delay_reorder) {
+        /* max gap, we exceeded the max reorder distance and we don't expect the
+         * missing packet to be this reordered */
+        if (test->num_rtx_retry == 0 && test->type == TIMER_TYPE_EXPECTED)
+          reschedule_timer (jitterbuffer, test, test->seqnum, -1, 0, FALSE);
+      }
+    }
+  }
+
+  do_next_seqnum = do_next_seqnum && priv->packet_spacing > 0
+      && priv->do_retransmission && priv->rtx_next_seqnum;
+
+  if (timer && timer->type != TIMER_TYPE_DEADLINE) {
+    if (timer->num_rtx_retry > 0) {
+      if (is_rtx) {
+        update_rtx_stats (jitterbuffer, timer, dts, TRUE);
+        /* don't try to estimate the next seqnum because this is a retransmitted
+         * packet and it probably did not arrive with the expected packet
+         * spacing. */
+        do_next_seqnum = FALSE;
+      }
+
+      if (!is_rtx || timer->num_rtx_retry > 1) {
+        /* Store timer in order to record stats when/if the retransmitted
+         * packet arrives. We should also store timer information if we've
+         * requested retransmission more than once since we may receive
+         * several retransmitted packets. For accuracy we should update the
+         * stats also when the redundant retransmitted packets arrives. */
+        timer_queue_append (priv->rtx_stats_timers, timer,
+            pts + priv->rtx_stats_timeout * GST_MSECOND, FALSE);
+      }
+    }
+  }
+
+  if (do_next_seqnum && pts != GST_CLOCK_TIME_NONE) {
+    GstClockTime expected, delay;
+
+    /* calculate expected arrival time of the next seqnum */
+    expected = pts + priv->packet_spacing;
+
+    delay = get_rtx_delay (priv);
+
+    /* and update/install timer for next seqnum */
+    GST_DEBUG_OBJECT (jitterbuffer, "Add RTX timer #%d, expected %"
+        GST_TIME_FORMAT ", delay %" GST_TIME_FORMAT ", packet-spacing %"
+        GST_TIME_FORMAT ", jitter %" GST_TIME_FORMAT, priv->next_in_seqnum,
+        GST_TIME_ARGS (expected), GST_TIME_ARGS (delay),
+        GST_TIME_ARGS (priv->packet_spacing), GST_TIME_ARGS (priv->avg_jitter));
+
+    if (timer) {
+      timer->type = TIMER_TYPE_EXPECTED;
+      reschedule_timer (jitterbuffer, timer, priv->next_in_seqnum, expected,
+          delay, TRUE);
+    } else {
+      add_timer (jitterbuffer, TIMER_TYPE_EXPECTED, priv->next_in_seqnum, 0,
+          expected, delay, priv->packet_spacing);
+    }
+  } else if (timer && timer->type != TIMER_TYPE_DEADLINE) {
+    /* if we had a timer, remove it, we don't know when to expect the next
+     * packet. */
+    remove_timer (jitterbuffer, timer);
+  }
+}
+
+static void
+calculate_packet_spacing (GstRtpJitterBuffer * jitterbuffer, guint32 rtptime,
+    GstClockTime pts)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+
+  /* we need consecutive seqnums with a different
+   * rtptime to estimate the packet spacing. */
+  if (priv->ips_rtptime != rtptime) {
+    /* rtptime changed, check pts diff */
+    if (priv->ips_pts != -1 && pts != -1 && pts > priv->ips_pts) {
+      GstClockTime new_packet_spacing = pts - priv->ips_pts;
+      GstClockTime old_packet_spacing = priv->packet_spacing;
+
+      /* Biased towards bigger packet spacings to prevent
+       * too many unneeded retransmission requests for next
+       * packets that just arrive a little later than we would
+       * expect */
+      if (old_packet_spacing > new_packet_spacing)
+        priv->packet_spacing =
+            (new_packet_spacing + 3 * old_packet_spacing) / 4;
+      else if (old_packet_spacing > 0)
+        priv->packet_spacing =
+            (3 * new_packet_spacing + old_packet_spacing) / 4;
+      else
+        priv->packet_spacing = new_packet_spacing;
+
+      GST_DEBUG_OBJECT (jitterbuffer,
+          "new packet spacing %" GST_TIME_FORMAT
+          " old packet spacing %" GST_TIME_FORMAT
+          " combined to %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (new_packet_spacing),
+          GST_TIME_ARGS (old_packet_spacing),
+          GST_TIME_ARGS (priv->packet_spacing));
+    }
+    priv->ips_rtptime = rtptime;
+    priv->ips_pts = pts;
+  }
+}
+
+static void
+calculate_expected (GstRtpJitterBuffer * jitterbuffer, guint32 expected,
+    guint16 seqnum, GstClockTime pts, gint gap)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  GstClockTime duration, expected_pts, delay;
+  TimerType type;
+  gboolean equidistant = priv->equidistant > 0;
+
+  GST_DEBUG_OBJECT (jitterbuffer,
+      "pts %" GST_TIME_FORMAT ", last %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (pts), GST_TIME_ARGS (priv->last_in_pts));
+
+  if (pts == GST_CLOCK_TIME_NONE) {
+    GST_WARNING_OBJECT (jitterbuffer, "Have no PTS");
+    return;
+  }
+
+  if (equidistant) {
+    GstClockTime total_duration;
+    /* the total duration spanned by the missing packets */
+    if (pts >= priv->last_in_pts)
+      total_duration = pts - priv->last_in_pts;
+    else
+      total_duration = 0;
+
+    /* interpolate between the current time and the last time based on
+     * number of packets we are missing, this is the estimated duration
+     * for the missing packet based on equidistant packet spacing. */
+    duration = total_duration / (gap + 1);
+
+    GST_DEBUG_OBJECT (jitterbuffer, "duration %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (duration));
+
+    if (total_duration > priv->latency_ns) {
+      GstClockTime gap_time;
+      guint lost_packets;
+
+      if (duration > 0) {
+        GstClockTime gap_dur = gap * duration;
+        if (gap_dur > priv->latency_ns)
+          gap_time = gap_dur - priv->latency_ns;
+        else
+          gap_time = 0;
+        lost_packets = gap_time / duration;
+      } else {
+        gap_time = total_duration - priv->latency_ns;
+        lost_packets = gap;
+      }
+
+      /* too many lost packets, some of the missing packets are already
+       * too late and we can generate lost packet events for them. */
+      GST_INFO_OBJECT (jitterbuffer,
+          "lost packets (%d, #%d->#%d) duration too large %" GST_TIME_FORMAT
+          " > %" GST_TIME_FORMAT ", consider %u lost (%" GST_TIME_FORMAT ")",
+          gap, expected, seqnum - 1, GST_TIME_ARGS (total_duration),
+          GST_TIME_ARGS (priv->latency_ns), lost_packets,
+          GST_TIME_ARGS (gap_time));
+
+      /* this timer will fire immediately and the lost event will be pushed from
+       * the timer thread */
+      if (lost_packets > 0) {
+        add_timer (jitterbuffer, TIMER_TYPE_LOST, expected, lost_packets,
+            priv->last_in_pts + duration, 0, gap_time);
+        expected += lost_packets;
+        priv->last_in_pts += gap_time;
+      }
+    }
+
+    expected_pts = priv->last_in_pts + duration;
+  } else {
+    /* If we cannot assume equidistant packet spacing, the only thing we now
+     * for sure is that the missing packets have expected pts not later than
+     * the last received pts. */
+    duration = 0;
+    expected_pts = pts;
+  }
+
+  delay = 0;
+
+  if (priv->do_retransmission) {
+    TimerData *timer = find_timer (jitterbuffer, expected);
+
+    type = TIMER_TYPE_EXPECTED;
+    delay = get_rtx_delay (priv);
+
+    /* if we had a timer for the first missing packet, update it. */
+    if (timer && timer->type == TIMER_TYPE_EXPECTED) {
+      GstClockTime timeout = timer->timeout;
+
+      timer->duration = duration;
+      if (timeout > (expected_pts + delay) && timer->num_rtx_retry == 0) {
+        reschedule_timer (jitterbuffer, timer, timer->seqnum, expected_pts,
+            delay, TRUE);
+      }
+      expected++;
+      expected_pts += duration;
+    }
+  } else {
+    type = TIMER_TYPE_LOST;
+  }
+
+  while (gst_rtp_buffer_compare_seqnum (expected, seqnum) > 0) {
+    add_timer (jitterbuffer, type, expected, 0, expected_pts, delay, duration);
+    expected_pts += duration;
+    expected++;
+  }
+}
+
+static void
+calculate_jitter (GstRtpJitterBuffer * jitterbuffer, GstClockTime dts,
+    guint32 rtptime)
+{
+  gint32 rtpdiff;
+  GstClockTimeDiff dtsdiff, rtpdiffns, diff;
+  GstRtpJitterBufferPrivate *priv;
+
+  priv = jitterbuffer->priv;
+
+  if (G_UNLIKELY (dts == GST_CLOCK_TIME_NONE) || priv->clock_rate <= 0)
+    goto no_time;
+
+  if (priv->last_dts != -1)
+    dtsdiff = dts - priv->last_dts;
+  else
+    dtsdiff = 0;
+
+  if (priv->last_rtptime != -1)
+    rtpdiff = rtptime - (guint32) priv->last_rtptime;
+  else
+    rtpdiff = 0;
+
+  /* Guess whether stream currently uses equidistant packet spacing. If we
+   * often see identical timestamps it means the packets are not
+   * equidistant. */
+  if (rtptime == priv->last_rtptime)
+    priv->equidistant -= 2;
+  else
+    priv->equidistant += 1;
+  priv->equidistant = CLAMP (priv->equidistant, -7, 7);
+
+  priv->last_dts = dts;
+  priv->last_rtptime = rtptime;
+
+  if (rtpdiff > 0)
+    rtpdiffns =
+        gst_util_uint64_scale_int (rtpdiff, GST_SECOND, priv->clock_rate);
+  else
+    rtpdiffns =
+        -gst_util_uint64_scale_int (-rtpdiff, GST_SECOND, priv->clock_rate);
+
+  diff = ABS (dtsdiff - rtpdiffns);
+
+  /* jitter is stored in nanoseconds */
+  priv->avg_jitter = (diff + (15 * priv->avg_jitter)) >> 4;
+
+  GST_LOG_OBJECT (jitterbuffer,
+      "dtsdiff %" GST_TIME_FORMAT " rtptime %" GST_TIME_FORMAT
+      ", clock-rate %d, diff %" GST_TIME_FORMAT ", jitter: %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (dtsdiff), GST_TIME_ARGS (rtpdiffns), priv->clock_rate,
+      GST_TIME_ARGS (diff), GST_TIME_ARGS (priv->avg_jitter));
+
+  return;
+
+  /* ERRORS */
+no_time:
+  {
+    GST_DEBUG_OBJECT (jitterbuffer,
+        "no dts or no clock-rate, can't calculate jitter");
+    return;
+  }
+}
+
+static gint
+compare_buffer_seqnum (GstBuffer * a, GstBuffer * b, gpointer user_data)
+{
+  GstRTPBuffer rtp_a = GST_RTP_BUFFER_INIT;
+  GstRTPBuffer rtp_b = GST_RTP_BUFFER_INIT;
+  guint seq_a, seq_b;
+
+  gst_rtp_buffer_map (a, GST_MAP_READ, &rtp_a);
+  seq_a = gst_rtp_buffer_get_seq (&rtp_a);
+  gst_rtp_buffer_unmap (&rtp_a);
+
+  gst_rtp_buffer_map (b, GST_MAP_READ, &rtp_b);
+  seq_b = gst_rtp_buffer_get_seq (&rtp_b);
+  gst_rtp_buffer_unmap (&rtp_b);
+
+  return gst_rtp_buffer_compare_seqnum (seq_b, seq_a);
+}
+
+static gboolean
+handle_big_gap_buffer (GstRtpJitterBuffer * jitterbuffer, GstBuffer * buffer,
+    guint8 pt, guint16 seqnum, gint gap, guint max_dropout, guint max_misorder)
+{
+  GstRtpJitterBufferPrivate *priv;
+  guint gap_packets_length;
+  gboolean reset = FALSE;
+  gboolean future = gap > 0;
+
+  priv = jitterbuffer->priv;
+
+  if ((gap_packets_length = g_queue_get_length (&priv->gap_packets)) > 0) {
+    GList *l;
+    guint32 prev_gap_seq = -1;
+    gboolean all_consecutive = TRUE;
+
+    g_queue_insert_sorted (&priv->gap_packets, buffer,
+        (GCompareDataFunc) compare_buffer_seqnum, NULL);
+
+    for (l = priv->gap_packets.head; l; l = l->next) {
+      GstBuffer *gap_buffer = l->data;
+      GstRTPBuffer gap_rtp = GST_RTP_BUFFER_INIT;
+      guint32 gap_seq;
+
+      gst_rtp_buffer_map (gap_buffer, GST_MAP_READ, &gap_rtp);
+
+      all_consecutive = (gst_rtp_buffer_get_payload_type (&gap_rtp) == pt);
+
+      gap_seq = gst_rtp_buffer_get_seq (&gap_rtp);
+      if (prev_gap_seq == -1)
+        prev_gap_seq = gap_seq;
+      else if (gst_rtp_buffer_compare_seqnum (gap_seq, prev_gap_seq) != -1)
+        all_consecutive = FALSE;
+      else
+        prev_gap_seq = gap_seq;
+
+      gst_rtp_buffer_unmap (&gap_rtp);
+      if (!all_consecutive)
+        break;
+    }
+
+    if (all_consecutive && gap_packets_length > 3) {
+      GST_DEBUG_OBJECT (jitterbuffer,
+          "buffer too %s %d < %d, got 5 consecutive ones - reset",
+          (future ? "new" : "old"), gap,
+          (future ? max_dropout : -max_misorder));
+      reset = TRUE;
+    } else if (!all_consecutive) {
+      g_queue_foreach (&priv->gap_packets, (GFunc) gst_buffer_unref, NULL);
+      g_queue_clear (&priv->gap_packets);
+      GST_DEBUG_OBJECT (jitterbuffer,
+          "buffer too %s %d < %d, got no 5 consecutive ones - dropping",
+          (future ? "new" : "old"), gap,
+          (future ? max_dropout : -max_misorder));
+      buffer = NULL;
+    } else {
+      GST_DEBUG_OBJECT (jitterbuffer,
+          "buffer too %s %d < %d, got %u consecutive ones - waiting",
+          (future ? "new" : "old"), gap,
+          (future ? max_dropout : -max_misorder), gap_packets_length + 1);
+      buffer = NULL;
+    }
+  } else {
+    GST_DEBUG_OBJECT (jitterbuffer,
+        "buffer too %s %d < %d, first one - waiting", (future ? "new" : "old"),
+        gap, -max_misorder);
+    g_queue_push_tail (&priv->gap_packets, buffer);
+    buffer = NULL;
+  }
+
+  return reset;
+}
+
+static GstClockTime
+get_current_running_time (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstClock *clock = gst_element_get_clock (GST_ELEMENT_CAST (jitterbuffer));
+  GstClockTime running_time = GST_CLOCK_TIME_NONE;
+
+  if (clock) {
+    GstClockTime base_time =
+        gst_element_get_base_time (GST_ELEMENT_CAST (jitterbuffer));
+    GstClockTime clock_time = gst_clock_get_time (clock);
+
+    if (clock_time > base_time)
+      running_time = clock_time - base_time;
+    else
+      running_time = 0;
+
+    gst_object_unref (clock);
+  }
+
+  return running_time;
+}
+
+static GstFlowReturn
+gst_rtp_jitter_buffer_reset (GstRtpJitterBuffer * jitterbuffer,
+    GstPad * pad, GstObject * parent, guint16 seqnum)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GList *events = NULL, *l;
+  GList *buffers;
+  gboolean head;
+
+  GST_DEBUG_OBJECT (jitterbuffer, "flush and reset jitterbuffer");
+  rtp_jitter_buffer_flush (priv->jbuf,
+      (GFunc) free_item_and_retain_events, &events);
+  rtp_jitter_buffer_reset_skew (priv->jbuf);
+  remove_all_timers (jitterbuffer);
+  priv->discont = TRUE;
+  priv->last_popped_seqnum = -1;
+
+  if (priv->gap_packets.head) {
+    GstBuffer *gap_buffer = priv->gap_packets.head->data;
+    GstRTPBuffer gap_rtp = GST_RTP_BUFFER_INIT;
+
+    gst_rtp_buffer_map (gap_buffer, GST_MAP_READ, &gap_rtp);
+    priv->next_seqnum = gst_rtp_buffer_get_seq (&gap_rtp);
+    gst_rtp_buffer_unmap (&gap_rtp);
+  } else {
+    priv->next_seqnum = seqnum;
+  }
+
+  priv->last_in_pts = -1;
+  priv->next_in_seqnum = -1;
+
+  /* Insert all sticky events again in order, otherwise we would
+   * potentially loose STREAM_START, CAPS or SEGMENT events
+   */
+  events = g_list_reverse (events);
+  for (l = events; l; l = l->next) {
+    RTPJitterBufferItem *item;
+
+    item = alloc_item (l->data, ITEM_TYPE_EVENT, -1, -1, -1, 0, -1);
+    rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL);
+  }
+  g_list_free (events);
+
+  JBUF_SIGNAL_EVENT (priv);
+
+  /* reset spacing estimation when gap */
+  priv->ips_rtptime = -1;
+  priv->ips_pts = GST_CLOCK_TIME_NONE;
+
+  buffers = g_list_copy (priv->gap_packets.head);
+  g_queue_clear (&priv->gap_packets);
+
+  priv->ips_rtptime = -1;
+  priv->ips_pts = GST_CLOCK_TIME_NONE;
+  JBUF_UNLOCK (jitterbuffer->priv);
+
+  for (l = buffers; l; l = l->next) {
+    ret = gst_rtp_jitter_buffer_chain (pad, parent, l->data);
+    l->data = NULL;
+    if (ret != GST_FLOW_OK) {
+      l = l->next;
+      break;
+    }
+  }
+  for (; l; l = l->next)
+    gst_buffer_unref (l->data);
+  g_list_free (buffers);
+
+  return ret;
+}
+
+static gboolean
+gst_rtp_jitter_buffer_fast_start (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstRtpJitterBufferPrivate *priv;
+  RTPJitterBufferItem *item;
+  TimerData *timer;
+
+  priv = jitterbuffer->priv;
+
+  if (priv->faststart_min_packets == 0)
+    return FALSE;
+
+  item = rtp_jitter_buffer_peek (priv->jbuf);
+  if (!item)
+    return FALSE;
+
+  timer = find_timer (jitterbuffer, item->seqnum);
+  if (!timer || timer->type != TIMER_TYPE_DEADLINE)
+    return FALSE;
+
+  if (rtp_jitter_buffer_can_fast_start (priv->jbuf,
+          priv->faststart_min_packets)) {
+    GST_INFO_OBJECT (jitterbuffer, "We found %i consecutive packet, start now",
+        priv->faststart_min_packets);
+    timer->timeout = -1;
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+static GstFlowReturn
+gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer)
+{
+  GstRtpJitterBuffer *jitterbuffer;
+  GstRtpJitterBufferPrivate *priv;
+  guint16 seqnum;
+  guint32 expected, rtptime;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstClockTime dts, pts;
+  guint64 latency_ts;
+  gboolean head;
+  gint percent = -1;
+  guint8 pt;
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+  gboolean do_next_seqnum = FALSE;
+  RTPJitterBufferItem *item;
+  GstMessage *msg = NULL;
+  gboolean estimated_dts = FALSE;
+  gint32 packet_rate, max_dropout, max_misorder;
+  TimerData *timer = NULL;
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER_CAST (parent);
+
+  priv = jitterbuffer->priv;
+
+  if (G_UNLIKELY (!gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp)))
+    goto invalid_buffer;
+
+  pt = gst_rtp_buffer_get_payload_type (&rtp);
+  seqnum = gst_rtp_buffer_get_seq (&rtp);
+  rtptime = gst_rtp_buffer_get_timestamp (&rtp);
+  gst_rtp_buffer_unmap (&rtp);
+
+  /* make sure we have PTS and DTS set */
+  pts = GST_BUFFER_PTS (buffer);
+  dts = GST_BUFFER_DTS (buffer);
+  if (dts == -1)
+    dts = pts;
+  else if (pts == -1)
+    pts = dts;
+
+  if (dts == -1) {
+    /* If we have no DTS here, i.e. no capture time, get one from the
+     * clock now to have something to calculate with in the future. */
+    dts = get_current_running_time (jitterbuffer);
+    pts = dts;
+
+    /* Remember that we estimated the DTS if we are running already
+     * and this is not our first packet (or first packet after a reset).
+     * If it's the first packet, we somehow must generate a timestamp for
+     * everything, otherwise we can't calculate any times
+     */
+    estimated_dts = (priv->next_in_seqnum != -1);
+  } else {
+    /* take the DTS of the buffer. This is the time when the packet was
+     * received and is used to calculate jitter and clock skew. We will adjust
+     * this DTS with the smoothed value after processing it in the
+     * jitterbuffer and assign it as the PTS. */
+    /* bring to running time */
+    dts = gst_segment_to_running_time (&priv->segment, GST_FORMAT_TIME, dts);
+  }
+
+  GST_DEBUG_OBJECT (jitterbuffer,
+      "Received packet #%d at time %" GST_TIME_FORMAT ", discont %d, rtx %d",
+      seqnum, GST_TIME_ARGS (dts), GST_BUFFER_IS_DISCONT (buffer),
+      GST_BUFFER_IS_RETRANSMISSION (buffer));
+
+  JBUF_LOCK_CHECK (priv, out_flushing);
+
+  if (G_UNLIKELY (priv->last_pt != pt)) {
+    GstCaps *caps;
+
+    GST_DEBUG_OBJECT (jitterbuffer, "pt changed from %u to %u", priv->last_pt,
+        pt);
+
+    priv->last_pt = pt;
+    /* reset clock-rate so that we get a new one */
+    priv->clock_rate = -1;
+
+    /* Try to get the clock-rate from the caps first if we can. If there are no
+     * caps we must fire the signal to get the clock-rate. */
+    if ((caps = gst_pad_get_current_caps (pad))) {
+      gst_jitter_buffer_sink_parse_caps (jitterbuffer, caps, pt);
+      gst_caps_unref (caps);
+    }
+  }
+
+  if (G_UNLIKELY (priv->clock_rate == -1)) {
+    /* no clock rate given on the caps, try to get one with the signal */
+    if (gst_rtp_jitter_buffer_get_clock_rate (jitterbuffer,
+            pt) == GST_FLOW_FLUSHING)
+      goto out_flushing;
+
+    if (G_UNLIKELY (priv->clock_rate == -1))
+      goto no_clock_rate;
+
+    gst_rtp_packet_rate_ctx_reset (&priv->packet_rate_ctx, priv->clock_rate);
+  }
+
+  /* don't accept more data on EOS */
+  if (G_UNLIKELY (priv->eos))
+    goto have_eos;
+
+  if (!GST_BUFFER_IS_RETRANSMISSION (buffer))
+    calculate_jitter (jitterbuffer, dts, rtptime);
+
+  if (priv->seqnum_base != -1) {
+    gint gap;
+
+    gap = gst_rtp_buffer_compare_seqnum (priv->seqnum_base, seqnum);
+
+    if (gap < 0) {
+      GST_DEBUG_OBJECT (jitterbuffer,
+          "packet seqnum #%d before seqnum-base #%d", seqnum,
+          priv->seqnum_base);
+      gst_buffer_unref (buffer);
+      goto finished;
+    } else if (gap > 16384) {
+      /* From now on don't compare against the seqnum base anymore as
+       * at some point in the future we will wrap around and also that
+       * much reordering is very unlikely */
+      priv->seqnum_base = -1;
+    }
+  }
+
+  expected = priv->next_in_seqnum;
+
+  packet_rate =
+      gst_rtp_packet_rate_ctx_update (&priv->packet_rate_ctx, seqnum, rtptime);
+  max_dropout =
+      gst_rtp_packet_rate_ctx_get_max_dropout (&priv->packet_rate_ctx,
+      priv->max_dropout_time);
+  max_misorder =
+      gst_rtp_packet_rate_ctx_get_max_misorder (&priv->packet_rate_ctx,
+      priv->max_misorder_time);
+  GST_TRACE_OBJECT (jitterbuffer,
+      "packet_rate: %d, max_dropout: %d, max_misorder: %d", packet_rate,
+      max_dropout, max_misorder);
+
+  /* now check against our expected seqnum */
+  if (G_UNLIKELY (expected == -1)) {
+    GST_DEBUG_OBJECT (jitterbuffer, "First buffer #%d", seqnum);
+
+    /* calculate a pts based on rtptime and arrival time (dts) */
+    pts =
+        rtp_jitter_buffer_calculate_pts (priv->jbuf, dts, estimated_dts,
+        rtptime, gst_element_get_base_time (GST_ELEMENT_CAST (jitterbuffer)));
+
+    /* we don't know what the next_in_seqnum should be, wait for the last
+     * possible moment to push this buffer, maybe we get an earlier seqnum
+     * while we wait */
+    set_timer (jitterbuffer, TIMER_TYPE_DEADLINE, seqnum, pts);
+
+    do_next_seqnum = TRUE;
+    /* take rtptime and pts to calculate packet spacing */
+    priv->ips_rtptime = rtptime;
+    priv->ips_pts = pts;
+
+  } else {
+    gint gap;
+    /* now calculate gap */
+    gap = gst_rtp_buffer_compare_seqnum (expected, seqnum);
+    GST_DEBUG_OBJECT (jitterbuffer, "expected #%d, got #%d, gap of %d",
+        expected, seqnum, gap);
+
+    if (G_UNLIKELY (gap > 0 && priv->timers->len >= max_dropout)) {
+      /* If we have timers for more than RTP_MAX_DROPOUT packets
+       * pending this means that we have a huge gap overall. We can
+       * reset the jitterbuffer at this point because there's
+       * just too much data missing to be able to do anything
+       * sensible with the past data. Just try again from the
+       * next packet */
+      GST_WARNING_OBJECT (jitterbuffer, "%d pending timers > %d - resetting",
+          priv->timers->len, max_dropout);
+      gst_buffer_unref (buffer);
+      return gst_rtp_jitter_buffer_reset (jitterbuffer, pad, parent, seqnum);
+    }
+
+    /* Special handling of large gaps */
+    if ((gap != -1 && gap < -max_misorder) || (gap >= max_dropout)) {
+      gboolean reset = handle_big_gap_buffer (jitterbuffer, buffer, pt, seqnum,
+          gap, max_dropout, max_misorder);
+      if (reset) {
+        return gst_rtp_jitter_buffer_reset (jitterbuffer, pad, parent, seqnum);
+      } else {
+        GST_DEBUG_OBJECT (jitterbuffer,
+            "Had big gap, waiting for more consecutive packets");
+        goto finished;
+      }
+    }
+
+    /* We had no huge gap, let's drop all the gap packets */
+    GST_DEBUG_OBJECT (jitterbuffer, "Clearing gap packets");
+    g_queue_foreach (&priv->gap_packets, (GFunc) gst_buffer_unref, NULL);
+    g_queue_clear (&priv->gap_packets);
+
+    /* calculate a pts based on rtptime and arrival time (dts) */
+    /* If we estimated the DTS, don't consider it in the clock skew calculations */
+    pts =
+        rtp_jitter_buffer_calculate_pts (priv->jbuf, dts, estimated_dts,
+        rtptime, gst_element_get_base_time (GST_ELEMENT_CAST (jitterbuffer)));
+
+    if (G_LIKELY (gap == 0)) {
+      /* packet is expected */
+      calculate_packet_spacing (jitterbuffer, rtptime, pts);
+      do_next_seqnum = TRUE;
+    } else {
+
+      /* we have a gap */
+      if (gap > 0) {
+        GST_DEBUG_OBJECT (jitterbuffer, "%d missing packets", gap);
+        /* fill in the gap with EXPECTED timers */
+        calculate_expected (jitterbuffer, expected, seqnum, pts, gap);
+        do_next_seqnum = TRUE;
+      } else {
+        GST_DEBUG_OBJECT (jitterbuffer, "old packet received");
+        do_next_seqnum = FALSE;
+      }
+
+      /* reset spacing estimation when gap */
+      priv->ips_rtptime = -1;
+      priv->ips_pts = GST_CLOCK_TIME_NONE;
+    }
+  }
+
+  if (do_next_seqnum) {
+    priv->last_in_pts = pts;
+    priv->next_in_seqnum = (seqnum + 1) & 0xffff;
+  }
+
+  timer = find_timer (jitterbuffer, seqnum);
+  if (GST_BUFFER_IS_RETRANSMISSION (buffer)) {
+    if (!timer)
+      timer = timer_queue_find (priv->rtx_stats_timers, seqnum);
+    if (timer)
+      timer->num_rtx_received++;
+  }
+
+  /* let's check if this buffer is too late, we can only accept packets with
+   * bigger seqnum than the one we last pushed. */
+  if (G_LIKELY (priv->last_popped_seqnum != -1)) {
+    gint gap;
+
+    gap = gst_rtp_buffer_compare_seqnum (priv->last_popped_seqnum, seqnum);
+
+    /* priv->last_popped_seqnum >= seqnum, we're too late. */
+    if (G_UNLIKELY (gap <= 0)) {
+      if (priv->do_retransmission) {
+        if (GST_BUFFER_IS_RETRANSMISSION (buffer) && timer) {
+          update_rtx_stats (jitterbuffer, timer, dts, FALSE);
+          /* Only count the retranmitted packet too late if it has been
+           * considered lost. If the original packet arrived before the
+           * retransmitted we just count it as a duplicate. */
+          if (timer->type != TIMER_TYPE_LOST)
+            goto rtx_duplicate;
+        }
+      }
+      goto too_late;
+    }
+  }
+
+  if (already_lost (jitterbuffer, seqnum))
+    goto already_lost;
+
+  /* let's drop oldest packet if the queue is already full and drop-on-latency
+   * is set. We can only do this when there actually is a latency. When no
+   * latency is set, we just pump it in the queue and let the other end push it
+   * out as fast as possible. */
+  if (priv->latency_ms && priv->drop_on_latency) {
+    latency_ts =
+        gst_util_uint64_scale_int (priv->latency_ms, priv->clock_rate, 1000);
+
+    if (G_UNLIKELY (rtp_jitter_buffer_get_ts_diff (priv->jbuf) >= latency_ts)) {
+      RTPJitterBufferItem *old_item;
+
+      old_item = rtp_jitter_buffer_peek (priv->jbuf);
+
+      if (IS_DROPABLE (old_item)) {
+        old_item = rtp_jitter_buffer_pop (priv->jbuf, &percent);
+        GST_DEBUG_OBJECT (jitterbuffer, "Queue full, dropping old packet %p",
+            old_item);
+        priv->next_seqnum = (old_item->seqnum + old_item->count) & 0xffff;
+        free_item (old_item);
+      }
+      /* we might have removed some head buffers, signal the pushing thread to
+       * see if it can push now */
+      JBUF_SIGNAL_EVENT (priv);
+    }
+  }
+
+  /* If we estimated the DTS, don't consider it in the clock skew calculations
+   * later. The code above always sets dts to pts or the other way around if
+   * any of those is valid in the buffer, so we know that if we estimated the
+   * dts that both are unknown */
+  if (estimated_dts)
+    item =
+        alloc_item (buffer, ITEM_TYPE_BUFFER, GST_CLOCK_TIME_NONE,
+        pts, seqnum, 1, rtptime);
+  else
+    item = alloc_item (buffer, ITEM_TYPE_BUFFER, dts, pts, seqnum, 1, rtptime);
+
+  /* now insert the packet into the queue in sorted order. This function returns
+   * FALSE if a packet with the same seqnum was already in the queue, meaning we
+   * have a duplicate. */
+  if (G_UNLIKELY (!rtp_jitter_buffer_insert (priv->jbuf, item, &head,
+              &percent))) {
+    if (GST_BUFFER_IS_RETRANSMISSION (buffer) && timer)
+      update_rtx_stats (jitterbuffer, timer, dts, FALSE);
+    goto duplicate;
+  }
+
+  /* Trigger fast start if needed */
+  if (gst_rtp_jitter_buffer_fast_start (jitterbuffer))
+    head = TRUE;
+
+  /* update timers */
+  update_timers (jitterbuffer, seqnum, dts, pts, do_next_seqnum,
+      GST_BUFFER_IS_RETRANSMISSION (buffer), timer);
+
+  /* we had an unhandled SR, handle it now */
+  if (priv->last_sr)
+    do_handle_sync (jitterbuffer);
+
+  if (G_UNLIKELY (head)) {
+    /* signal addition of new buffer when the _loop is waiting. */
+    if (G_LIKELY (priv->active))
+      JBUF_SIGNAL_EVENT (priv);
+
+    /* let's unschedule and unblock any waiting buffers. We only want to do this
+     * when the head buffer changed */
+    if (G_UNLIKELY (priv->clock_id)) {
+      GST_DEBUG_OBJECT (jitterbuffer, "Unscheduling waiting new buffer");
+      unschedule_current_timer (jitterbuffer);
+    }
+  }
+
+  GST_DEBUG_OBJECT (jitterbuffer,
+      "Pushed packet #%d, now %d packets, head: %d, " "percent %d", seqnum,
+      rtp_jitter_buffer_num_packets (priv->jbuf), head, percent);
+
+  msg = check_buffering_percent (jitterbuffer, percent);
+
+finished:
+  JBUF_UNLOCK (priv);
+
+  if (msg)
+    gst_element_post_message (GST_ELEMENT_CAST (jitterbuffer), msg);
+
+  return ret;
+
+  /* ERRORS */
+invalid_buffer:
+  {
+    /* this is not fatal but should be filtered earlier */
+    GST_ELEMENT_WARNING (jitterbuffer, STREAM, DECODE, (NULL),
+        ("Received invalid RTP payload, dropping"));
+    gst_buffer_unref (buffer);
+    return GST_FLOW_OK;
+  }
+no_clock_rate:
+  {
+    GST_WARNING_OBJECT (jitterbuffer,
+        "No clock-rate in caps!, dropping buffer");
+    gst_buffer_unref (buffer);
+    goto finished;
+  }
+out_flushing:
+  {
+    ret = priv->srcresult;
+    GST_DEBUG_OBJECT (jitterbuffer, "flushing %s", gst_flow_get_name (ret));
+    gst_buffer_unref (buffer);
+    goto finished;
+  }
+have_eos:
+  {
+    ret = GST_FLOW_EOS;
+    GST_WARNING_OBJECT (jitterbuffer, "we are EOS, refusing buffer");
+    gst_buffer_unref (buffer);
+    goto finished;
+  }
+too_late:
+  {
+    GST_DEBUG_OBJECT (jitterbuffer, "Packet #%d too late as #%d was already"
+        " popped, dropping", seqnum, priv->last_popped_seqnum);
+    priv->num_late++;
+    gst_buffer_unref (buffer);
+    goto finished;
+  }
+already_lost:
+  {
+    GST_DEBUG_OBJECT (jitterbuffer, "Packet #%d too late as it was already "
+        "considered lost", seqnum);
+    priv->num_late++;
+    gst_buffer_unref (buffer);
+    goto finished;
+  }
+duplicate:
+  {
+    GST_DEBUG_OBJECT (jitterbuffer, "Duplicate packet #%d detected, dropping",
+        seqnum);
+    priv->num_duplicates++;
+    free_item (item);
+    goto finished;
+  }
+rtx_duplicate:
+  {
+    GST_DEBUG_OBJECT (jitterbuffer,
+        "Duplicate RTX packet #%d detected, dropping", seqnum);
+    priv->num_duplicates++;
+    gst_buffer_unref (buffer);
+    goto finished;
+  }
+}
+
+/* FIXME: hopefully we can do something more efficient here, especially when
+ * all packets are in order and/or outside of the currently cached range.
+ * Still worthwhile to have it, avoids taking/releasing object lock and pad
+ * stream lock for every single buffer in the default chain_list fallback. */
+static GstFlowReturn
+gst_rtp_jitter_buffer_chain_list (GstPad * pad, GstObject * parent,
+    GstBufferList * buffer_list)
+{
+  GstFlowReturn flow_ret = GST_FLOW_OK;
+  guint i, n;
+
+  n = gst_buffer_list_length (buffer_list);
+  for (i = 0; i < n; ++i) {
+    GstBuffer *buf = gst_buffer_list_get (buffer_list, i);
+
+    flow_ret = gst_rtp_jitter_buffer_chain (pad, parent, gst_buffer_ref (buf));
+
+    if (flow_ret != GST_FLOW_OK)
+      break;
+  }
+  gst_buffer_list_unref (buffer_list);
+
+  return flow_ret;
+}
+
+static GstClockTime
+compute_elapsed (GstRtpJitterBuffer * jitterbuffer, RTPJitterBufferItem * item)
+{
+  guint64 ext_time, elapsed;
+  guint32 rtp_time;
+  GstRtpJitterBufferPrivate *priv;
+
+  priv = jitterbuffer->priv;
+  rtp_time = item->rtptime;
+
+  GST_LOG_OBJECT (jitterbuffer, "rtp %" G_GUINT32_FORMAT ", ext %"
+      G_GUINT64_FORMAT, rtp_time, priv->ext_timestamp);
+
+  ext_time = priv->ext_timestamp;
+  ext_time = gst_rtp_buffer_ext_timestamp (&ext_time, rtp_time);
+  if (ext_time < priv->ext_timestamp) {
+    ext_time = priv->ext_timestamp;
+  } else {
+    priv->ext_timestamp = ext_time;
+  }
+
+  if (ext_time > priv->clock_base)
+    elapsed = ext_time - priv->clock_base;
+  else
+    elapsed = 0;
+
+  elapsed = gst_util_uint64_scale_int (elapsed, GST_SECOND, priv->clock_rate);
+  return elapsed;
+}
+
+static void
+update_estimated_eos (GstRtpJitterBuffer * jitterbuffer,
+    RTPJitterBufferItem * item)
+{
+  guint64 total, elapsed, left, estimated;
+  GstClockTime out_time;
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+
+  if (priv->npt_stop == -1 || priv->ext_timestamp == -1
+      || priv->clock_base == -1 || priv->clock_rate <= 0)
+    return;
+
+  /* compute the elapsed time */
+  elapsed = compute_elapsed (jitterbuffer, item);
+
+  /* do nothing if elapsed time doesn't increment */
+  if (priv->last_elapsed && elapsed <= priv->last_elapsed)
+    return;
+
+  priv->last_elapsed = elapsed;
+
+  /* this is the total time we need to play */
+  total = priv->npt_stop - priv->npt_start;
+  GST_LOG_OBJECT (jitterbuffer, "total %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (total));
+
+  /* this is how much time there is left */
+  if (total > elapsed)
+    left = total - elapsed;
+  else
+    left = 0;
+
+  /* if we have less time left that the size of the buffer, we will not
+   * be able to keep it filled, disabled buffering then */
+  if (left < rtp_jitter_buffer_get_delay (priv->jbuf)) {
+    GST_DEBUG_OBJECT (jitterbuffer, "left %" GST_TIME_FORMAT
+        ", disable buffering close to EOS", GST_TIME_ARGS (left));
+    rtp_jitter_buffer_disable_buffering (priv->jbuf, TRUE);
+  }
+
+  /* this is the current time as running-time */
+  out_time = item->pts;
+
+  if (elapsed > 0)
+    estimated = gst_util_uint64_scale (out_time, total, elapsed);
+  else {
+    /* if there is almost nothing left,
+     * we may never advance enough to end up in the above case */
+    if (total < GST_SECOND)
+      estimated = GST_SECOND;
+    else
+      estimated = -1;
+  }
+  GST_LOG_OBJECT (jitterbuffer, "elapsed %" GST_TIME_FORMAT ", estimated %"
+      GST_TIME_FORMAT, GST_TIME_ARGS (elapsed), GST_TIME_ARGS (estimated));
+
+  if (estimated != -1 && priv->estimated_eos != estimated) {
+    set_timer (jitterbuffer, TIMER_TYPE_EOS, -1, estimated);
+    priv->estimated_eos = estimated;
+  }
+}
+
+/* take a buffer from the queue and push it */
+static GstFlowReturn
+pop_and_push_next (GstRtpJitterBuffer * jitterbuffer, guint seqnum)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  GstFlowReturn result = GST_FLOW_OK;
+  RTPJitterBufferItem *item;
+  GstBuffer *outbuf = NULL;
+  GstEvent *outevent = NULL;
+  GstQuery *outquery = NULL;
+  GstClockTime dts, pts;
+  gint percent = -1;
+  gboolean do_push = TRUE;
+  guint type;
+  GstMessage *msg;
+
+  /* when we get here we are ready to pop and push the buffer */
+  item = rtp_jitter_buffer_pop (priv->jbuf, &percent);
+  type = item->type;
+
+  switch (type) {
+    case ITEM_TYPE_BUFFER:
+
+      /* we need to make writable to change the flags and timestamps */
+      outbuf = gst_buffer_make_writable (item->data);
+
+      if (G_UNLIKELY (priv->discont)) {
+        /* set DISCONT flag when we missed a packet. We pushed the buffer writable
+         * into the jitterbuffer so we can modify now. */
+        GST_DEBUG_OBJECT (jitterbuffer, "mark output buffer discont");
+        GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+        priv->discont = FALSE;
+      }
+      if (G_UNLIKELY (priv->ts_discont)) {
+        GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+        priv->ts_discont = FALSE;
+      }
+
+      dts =
+          gst_segment_position_from_running_time (&priv->segment,
+          GST_FORMAT_TIME, item->dts);
+      pts =
+          gst_segment_position_from_running_time (&priv->segment,
+          GST_FORMAT_TIME, item->pts);
+
+      /* if this is a new frame, check if ts_offset needs to be updated */
+      if (pts != priv->last_pts) {
+        update_offset (jitterbuffer);
+      }
+
+      /* apply timestamp with offset to buffer now */
+      GST_BUFFER_DTS (outbuf) = apply_offset (jitterbuffer, dts);
+      GST_BUFFER_PTS (outbuf) = apply_offset (jitterbuffer, pts);
+
+      /* update the elapsed time when we need to check against the npt stop time. */
+      update_estimated_eos (jitterbuffer, item);
+
+      /* verify that an offset has not caused time stamps to go backwards, if so
+       * handle by reusing the previous timestamp */
+      if (priv->last_out_time != GST_CLOCK_TIME_NONE &&
+          GST_BUFFER_PTS (outbuf) < priv->last_out_time) {
+        GST_DEBUG_OBJECT (jitterbuffer, "buffer PTS %" GST_TIME_FORMAT
+            " older than preceding PTS %" GST_TIME_FORMAT
+            " adjusting to %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)),
+            GST_TIME_ARGS (priv->last_out_time),
+            GST_TIME_ARGS (priv->last_out_time));
+        GST_BUFFER_PTS (outbuf) = priv->last_out_time;
+      }
+
+      priv->last_pts = pts;
+      priv->last_out_time = GST_BUFFER_PTS (outbuf);
+      break;
+    case ITEM_TYPE_LOST:
+      priv->discont = TRUE;
+      if (!priv->do_lost)
+        do_push = FALSE;
+      /* FALLTHROUGH */
+    case ITEM_TYPE_EVENT:
+      outevent = item->data;
+      break;
+    case ITEM_TYPE_QUERY:
+      outquery = item->data;
+      break;
+  }
+
+  /* now we are ready to push the buffer. Save the seqnum and release the lock
+   * so the other end can push stuff in the queue again. */
+  if (seqnum != -1) {
+    priv->last_popped_seqnum = seqnum;
+    priv->next_seqnum = (seqnum + item->count) & 0xffff;
+  }
+  msg = check_buffering_percent (jitterbuffer, percent);
+  JBUF_UNLOCK (priv);
+
+  item->data = NULL;
+  free_item (item);
+
+  if (msg)
+    gst_element_post_message (GST_ELEMENT_CAST (jitterbuffer), msg);
+
+  switch (type) {
+    case ITEM_TYPE_BUFFER:
+      /* push buffer */
+      GST_DEBUG_OBJECT (jitterbuffer,
+          "Pushing buffer %d, dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT,
+          seqnum, GST_TIME_ARGS (GST_BUFFER_DTS (outbuf)),
+          GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)));
+      priv->num_pushed++;
+      result = gst_pad_push (priv->srcpad, outbuf);
+
+      JBUF_LOCK_CHECK (priv, out_flushing);
+      break;
+    case ITEM_TYPE_LOST:
+    case ITEM_TYPE_EVENT:
+      /* We got not enough consecutive packets with a huge gap, we can
+       * as well just drop them here now on EOS */
+      if (outevent && GST_EVENT_TYPE (outevent) == GST_EVENT_EOS) {
+        GST_DEBUG_OBJECT (jitterbuffer, "Clearing gap packets on EOS");
+        g_queue_foreach (&priv->gap_packets, (GFunc) gst_buffer_unref, NULL);
+        g_queue_clear (&priv->gap_packets);
+      }
+
+      GST_DEBUG_OBJECT (jitterbuffer, "%sPushing event %" GST_PTR_FORMAT
+          ", seqnum %d", do_push ? "" : "NOT ", outevent, seqnum);
+
+      if (do_push)
+        gst_pad_push_event (priv->srcpad, outevent);
+      else if (outevent)
+        gst_event_unref (outevent);
+
+      result = GST_FLOW_OK;
+
+      JBUF_LOCK_CHECK (priv, out_flushing);
+      break;
+    case ITEM_TYPE_QUERY:
+    {
+      gboolean res;
+
+      res = gst_pad_peer_query (priv->srcpad, outquery);
+
+      JBUF_LOCK_CHECK (priv, out_flushing);
+      result = GST_FLOW_OK;
+      GST_LOG_OBJECT (jitterbuffer, "did query %p, return %d", outquery, res);
+      JBUF_SIGNAL_QUERY (priv, res);
+      break;
+    }
+  }
+  return result;
+
+  /* ERRORS */
+out_flushing:
+  {
+    return priv->srcresult;
+  }
+}
+
+#define GST_FLOW_WAIT GST_FLOW_CUSTOM_SUCCESS
+
+/* Peek a buffer and compare the seqnum to the expected seqnum.
+ * If all is fine, the buffer is pushed.
+ * If something is wrong, we wait for some event
+ */
+static GstFlowReturn
+handle_next_buffer (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  GstFlowReturn result;
+  RTPJitterBufferItem *item;
+  guint seqnum;
+  guint32 next_seqnum;
+
+  /* only push buffers when PLAYING and active and not buffering */
+  if (priv->blocked || !priv->active ||
+      rtp_jitter_buffer_is_buffering (priv->jbuf)) {
+    return GST_FLOW_WAIT;
+  }
+
+  /* peek a buffer, we're just looking at the sequence number.
+   * If all is fine, we'll pop and push it. If the sequence number is wrong we
+   * wait for a timeout or something to change.
+   * The peeked buffer is valid for as long as we hold the jitterbuffer lock. */
+  item = rtp_jitter_buffer_peek (priv->jbuf);
+  if (item == NULL) {
+    goto wait;
+  }
+
+  /* get the seqnum and the next expected seqnum */
+  seqnum = item->seqnum;
+  if (seqnum == -1) {
+    return pop_and_push_next (jitterbuffer, seqnum);
+  }
+
+  next_seqnum = priv->next_seqnum;
+
+  /* get the gap between this and the previous packet. If we don't know the
+   * previous packet seqnum assume no gap. */
+  if (G_UNLIKELY (next_seqnum == -1)) {
+    GST_DEBUG_OBJECT (jitterbuffer, "First buffer #%d", seqnum);
+    /* we don't know what the next_seqnum should be, the chain function should
+     * have scheduled a DEADLINE timer that will increment next_seqnum when it
+     * fires, so wait for that */
+    result = GST_FLOW_WAIT;
+  } else {
+    gint gap = gst_rtp_buffer_compare_seqnum (next_seqnum, seqnum);
+
+    if (G_LIKELY (gap == 0)) {
+      /* no missing packet, pop and push */
+      result = pop_and_push_next (jitterbuffer, seqnum);
+    } else if (G_UNLIKELY (gap < 0)) {
+      /* if we have a packet that we already pushed or considered dropped, pop it
+       * off and get the next packet */
+      GST_DEBUG_OBJECT (jitterbuffer, "Old packet #%d, next #%d dropping",
+          seqnum, next_seqnum);
+      item = rtp_jitter_buffer_pop (priv->jbuf, NULL);
+      free_item (item);
+      result = GST_FLOW_OK;
+    } else {
+      /* the chain function has scheduled timers to request retransmission or
+       * when to consider the packet lost, wait for that */
+      GST_DEBUG_OBJECT (jitterbuffer,
+          "Sequence number GAP detected: expected %d instead of %d (%d missing)",
+          next_seqnum, seqnum, gap);
+      result = GST_FLOW_WAIT;
+    }
+  }
+
+  return result;
+
+wait:
+  {
+    GST_DEBUG_OBJECT (jitterbuffer, "no buffer, going to wait");
+    if (priv->eos) {
+      return GST_FLOW_EOS;
+    } else {
+      return GST_FLOW_WAIT;
+    }
+  }
+}
+
+static GstClockTime
+get_rtx_retry_timeout (GstRtpJitterBufferPrivate * priv)
+{
+  GstClockTime rtx_retry_timeout;
+  GstClockTime rtx_min_retry_timeout;
+
+  if (priv->rtx_retry_timeout == -1) {
+    if (priv->avg_rtx_rtt == 0)
+      rtx_retry_timeout = DEFAULT_AUTO_RTX_TIMEOUT;
+    else
+      /* we want to ask for a retransmission after we waited for a
+       * complete RTT and the additional jitter */
+      rtx_retry_timeout = priv->avg_rtx_rtt + priv->avg_jitter * 2;
+  } else {
+    rtx_retry_timeout = priv->rtx_retry_timeout * GST_MSECOND;
+  }
+  /* make sure we don't retry too often. On very low latency networks,
+   * the RTT and jitter can be very low. */
+  if (priv->rtx_min_retry_timeout == -1) {
+    rtx_min_retry_timeout = priv->packet_spacing;
+  } else {
+    rtx_min_retry_timeout = priv->rtx_min_retry_timeout * GST_MSECOND;
+  }
+  rtx_retry_timeout = MAX (rtx_retry_timeout, rtx_min_retry_timeout);
+
+  return rtx_retry_timeout;
+}
+
+static GstClockTime
+get_rtx_retry_period (GstRtpJitterBufferPrivate * priv,
+    GstClockTime rtx_retry_timeout)
+{
+  GstClockTime rtx_retry_period;
+
+  if (priv->rtx_retry_period == -1) {
+    /* we retry up to the configured jitterbuffer size but leaving some
+     * room for the retransmission to arrive in time */
+    if (rtx_retry_timeout > priv->latency_ns) {
+      rtx_retry_period = 0;
+    } else {
+      rtx_retry_period = priv->latency_ns - rtx_retry_timeout;
+    }
+  } else {
+    rtx_retry_period = priv->rtx_retry_period * GST_MSECOND;
+  }
+  return rtx_retry_period;
+}
+
+/*
+  1. For *larger* rtx-rtt, weigh a new measurement as before (1/8th)
+  2. For *smaller* rtx-rtt, be a bit more conservative and weigh a bit less (1/16th)
+  3. For very large measurements (> avg * 2), consider them "outliers"
+     and count them a lot less (1/48th)
+*/
+static void
+update_avg_rtx_rtt (GstRtpJitterBufferPrivate * priv, GstClockTime rtt)
+{
+  gint weight;
+
+  if (priv->avg_rtx_rtt == 0) {
+    priv->avg_rtx_rtt = rtt;
+    return;
+  }
+
+  if (rtt > 2 * priv->avg_rtx_rtt)
+    weight = 48;
+  else if (rtt > priv->avg_rtx_rtt)
+    weight = 8;
+  else
+    weight = 16;
+
+  priv->avg_rtx_rtt = (rtt + (weight - 1) * priv->avg_rtx_rtt) / weight;
+}
+
+static void
+update_rtx_stats (GstRtpJitterBuffer * jitterbuffer, TimerData * timer,
+    GstClockTime dts, gboolean success)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  GstClockTime delay;
+
+  if (success) {
+    /* we scheduled a retry for this packet and now we have it */
+    priv->num_rtx_success++;
+    /* all the previous retry attempts failed */
+    priv->num_rtx_failed += timer->num_rtx_retry - 1;
+  } else {
+    /* All retries failed or was too late */
+    priv->num_rtx_failed += timer->num_rtx_retry;
+  }
+
+  /* number of retries before (hopefully) receiving the packet */
+  if (priv->avg_rtx_num == 0.0)
+    priv->avg_rtx_num = timer->num_rtx_retry;
+  else
+    priv->avg_rtx_num = (timer->num_rtx_retry + 7 * priv->avg_rtx_num) / 8;
+
+  /* Calculate the delay between retransmission request and receiving this
+   * packet. We have a valid delay if and only if this packet is a response to
+   * our last request. If not we don't know if this is a response to an
+   * earlier request and delay could be way off. For RTT is more important
+   * with correct values than to update for every packet. */
+  if (timer->num_rtx_retry == timer->num_rtx_received &&
+      dts != GST_CLOCK_TIME_NONE && dts > timer->rtx_last) {
+    delay = dts - timer->rtx_last;
+    update_avg_rtx_rtt (priv, delay);
+  } else {
+    delay = 0;
+  }
+
+  GST_LOG_OBJECT (jitterbuffer,
+      "RTX #%d, result %d, success %" G_GUINT64_FORMAT ", failed %"
+      G_GUINT64_FORMAT ", requests %" G_GUINT64_FORMAT ", dups %"
+      G_GUINT64_FORMAT ", avg-num %g, delay %" GST_TIME_FORMAT ", avg-rtt %"
+      GST_TIME_FORMAT, timer->seqnum, success, priv->num_rtx_success,
+      priv->num_rtx_failed, priv->num_rtx_requests, priv->num_duplicates,
+      priv->avg_rtx_num, GST_TIME_ARGS (delay),
+      GST_TIME_ARGS (priv->avg_rtx_rtt));
+}
+
+/* the timeout for when we expected a packet expired */
+static gboolean
+do_expected_timeout (GstRtpJitterBuffer * jitterbuffer, TimerData * timer,
+    GstClockTime now)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  GstEvent *event;
+  guint delay, delay_ms, avg_rtx_rtt_ms;
+  guint rtx_retry_timeout_ms, rtx_retry_period_ms;
+  guint rtx_deadline_ms;
+  GstClockTime rtx_retry_period;
+  GstClockTime rtx_retry_timeout;
+  GstClock *clock;
+
+  GST_DEBUG_OBJECT (jitterbuffer, "expected %d didn't arrive, now %"
+      GST_TIME_FORMAT, timer->seqnum, GST_TIME_ARGS (now));
+
+  rtx_retry_timeout = get_rtx_retry_timeout (priv);
+  rtx_retry_period = get_rtx_retry_period (priv, rtx_retry_timeout);
+
+  delay = timer->rtx_delay + timer->rtx_retry;
+
+  delay_ms = GST_TIME_AS_MSECONDS (delay);
+  rtx_retry_timeout_ms = GST_TIME_AS_MSECONDS (rtx_retry_timeout);
+  rtx_retry_period_ms = GST_TIME_AS_MSECONDS (rtx_retry_period);
+  avg_rtx_rtt_ms = GST_TIME_AS_MSECONDS (priv->avg_rtx_rtt);
+  rtx_deadline_ms =
+      priv->rtx_deadline_ms != -1 ? priv->rtx_deadline_ms : priv->latency_ms;
+
+  event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+      gst_structure_new ("GstRTPRetransmissionRequest",
+          "seqnum", G_TYPE_UINT, (guint) timer->seqnum,
+          "running-time", G_TYPE_UINT64, timer->rtx_base,
+          "delay", G_TYPE_UINT, delay_ms,
+          "retry", G_TYPE_UINT, timer->num_rtx_retry,
+          "frequency", G_TYPE_UINT, rtx_retry_timeout_ms,
+          "period", G_TYPE_UINT, rtx_retry_period_ms,
+          "deadline", G_TYPE_UINT, rtx_deadline_ms,
+          "packet-spacing", G_TYPE_UINT64, priv->packet_spacing,
+          "avg-rtt", G_TYPE_UINT, avg_rtx_rtt_ms, NULL));
+  GST_DEBUG_OBJECT (jitterbuffer, "Request RTX: %" GST_PTR_FORMAT, event);
+
+  priv->num_rtx_requests++;
+  timer->num_rtx_retry++;
+
+  GST_OBJECT_LOCK (jitterbuffer);
+  if ((clock = GST_ELEMENT_CLOCK (jitterbuffer))) {
+    timer->rtx_last = gst_clock_get_time (clock);
+    timer->rtx_last -= GST_ELEMENT_CAST (jitterbuffer)->base_time;
+  } else {
+    timer->rtx_last = now;
+  }
+  GST_OBJECT_UNLOCK (jitterbuffer);
+
+  /* calculate the timeout for the next retransmission attempt */
+  timer->rtx_retry += rtx_retry_timeout;
+  GST_DEBUG_OBJECT (jitterbuffer, "base %" GST_TIME_FORMAT ", delay %"
+      GST_TIME_FORMAT ", retry %" GST_TIME_FORMAT ", num_retry %u",
+      GST_TIME_ARGS (timer->rtx_base), GST_TIME_ARGS (timer->rtx_delay),
+      GST_TIME_ARGS (timer->rtx_retry), timer->num_rtx_retry);
+  if ((priv->rtx_max_retries != -1
+          && timer->num_rtx_retry >= priv->rtx_max_retries)
+      || (timer->rtx_retry + timer->rtx_delay > rtx_retry_period)
+      || (timer->rtx_base + rtx_retry_period < now)) {
+    GST_DEBUG_OBJECT (jitterbuffer, "reschedule as LOST timer");
+    /* too many retransmission request, we now convert the timer
+     * to a lost timer, leave the num_rtx_retry as it is for stats */
+    timer->type = TIMER_TYPE_LOST;
+    timer->rtx_delay = 0;
+    timer->rtx_retry = 0;
+  }
+  reschedule_timer (jitterbuffer, timer, timer->seqnum,
+      timer->rtx_base + timer->rtx_retry, timer->rtx_delay, FALSE);
+
+  JBUF_UNLOCK (priv);
+  gst_pad_push_event (priv->sinkpad, event);
+  JBUF_LOCK (priv);
+
+  return FALSE;
+}
+
+/* a packet is lost */
+static gboolean
+do_lost_timeout (GstRtpJitterBuffer * jitterbuffer, TimerData * timer,
+    GstClockTime now)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  guint seqnum, lost_packets, num_rtx_retry, next_in_seqnum;
+  gboolean head;
+  GstEvent *event = NULL;
+  RTPJitterBufferItem *item;
+
+  seqnum = timer->seqnum;
+  lost_packets = MAX (timer->num, 1);
+  num_rtx_retry = timer->num_rtx_retry;
+
+  /* we had a gap and thus we lost some packets. Create an event for this.  */
+  if (lost_packets > 1)
+    GST_DEBUG_OBJECT (jitterbuffer, "Packets #%d -> #%d lost", seqnum,
+        seqnum + lost_packets - 1);
+  else
+    GST_DEBUG_OBJECT (jitterbuffer, "Packet #%d lost", seqnum);
+
+  priv->num_lost += lost_packets;
+  priv->num_rtx_failed += num_rtx_retry;
+
+  next_in_seqnum = (seqnum + lost_packets) & 0xffff;
+
+  /* we now only accept seqnum bigger than this */
+  if (gst_rtp_buffer_compare_seqnum (priv->next_in_seqnum, next_in_seqnum) > 0) {
+    priv->next_in_seqnum = next_in_seqnum;
+    priv->last_in_pts = apply_offset (jitterbuffer, timer->timeout);
+  }
+
+  /* Avoid creating events if we don't need it. Note that we still need to create
+   * the lost *ITEM* since it will be used to notify the outgoing thread of
+   * lost items (so that we can set discont flags and such) */
+  if (priv->do_lost) {
+    GstClockTime duration, timestamp;
+    /* create paket lost event */
+    timestamp = apply_offset (jitterbuffer, timer->timeout);
+    duration = timer->duration;
+    if (duration == GST_CLOCK_TIME_NONE && priv->packet_spacing > 0)
+      duration = priv->packet_spacing;
+    event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
+        gst_structure_new ("GstRTPPacketLost",
+            "seqnum", G_TYPE_UINT, (guint) seqnum,
+            "timestamp", G_TYPE_UINT64, timestamp,
+            "duration", G_TYPE_UINT64, duration,
+            "retry", G_TYPE_UINT, num_rtx_retry, NULL));
+  }
+  item = alloc_item (event, ITEM_TYPE_LOST, -1, -1, seqnum, lost_packets, -1);
+  if (!rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL))
+    /* Duplicate */
+    free_item (item);
+
+  if (GST_CLOCK_TIME_IS_VALID (timer->rtx_last)) {
+    /* Store info to update stats if the packet arrives too late */
+    timer_queue_append (priv->rtx_stats_timers, timer,
+        now + priv->rtx_stats_timeout * GST_MSECOND, TRUE);
+  }
+  remove_timer (jitterbuffer, timer);
+
+  if (head)
+    JBUF_SIGNAL_EVENT (priv);
+
+  return TRUE;
+}
+
+static gboolean
+do_eos_timeout (GstRtpJitterBuffer * jitterbuffer, TimerData * timer,
+    GstClockTime now)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+
+  GST_INFO_OBJECT (jitterbuffer, "got the NPT timeout");
+  remove_timer (jitterbuffer, timer);
+  if (!priv->eos) {
+    /* there was no EOS in the buffer, put one in there now */
+    queue_event (jitterbuffer, gst_event_new_eos ());
+  }
+  JBUF_SIGNAL_EVENT (priv);
+
+  return TRUE;
+}
+
+static gboolean
+do_deadline_timeout (GstRtpJitterBuffer * jitterbuffer, TimerData * timer,
+    GstClockTime now)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+
+  GST_INFO_OBJECT (jitterbuffer, "got deadline timeout");
+
+  /* timer seqnum might have been obsoleted by caps seqnum-base,
+   * only mess with current ongoing seqnum if still unknown */
+  if (priv->next_seqnum == -1)
+    priv->next_seqnum = timer->seqnum;
+  remove_timer (jitterbuffer, timer);
+  JBUF_SIGNAL_EVENT (priv);
+
+  return TRUE;
+}
+
+static gboolean
+do_timeout (GstRtpJitterBuffer * jitterbuffer, TimerData * timer,
+    GstClockTime now)
+{
+  gboolean removed = FALSE;
+
+  switch (timer->type) {
+    case TIMER_TYPE_EXPECTED:
+      removed = do_expected_timeout (jitterbuffer, timer, now);
+      break;
+    case TIMER_TYPE_LOST:
+      removed = do_lost_timeout (jitterbuffer, timer, now);
+      break;
+    case TIMER_TYPE_DEADLINE:
+      removed = do_deadline_timeout (jitterbuffer, timer, now);
+      break;
+    case TIMER_TYPE_EOS:
+      removed = do_eos_timeout (jitterbuffer, timer, now);
+      break;
+  }
+  return removed;
+}
+
+/* called when we need to wait for the next timeout.
+ *
+ * We loop over the array of recorded timeouts and wait for the earliest one.
+ * When it timed out, do the logic associated with the timer.
+ *
+ * If there are no timers, we wait on a gcond until something new happens.
+ */
+static void
+wait_next_timeout (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
+  GstClockTime now = 0;
+
+  JBUF_LOCK (priv);
+  while (priv->timer_running) {
+    TimerData *timer = NULL;
+    GstClockTime timer_timeout = -1;
+    gint i, len;
+
+    /* If we have a clock, update "now" now with the very
+     * latest running time we have. If timers are unscheduled below we
+     * otherwise wouldn't update now (it's only updated when timers
+     * expire), and also for the very first loop iteration now would
+     * otherwise always be 0
+     */
+    GST_OBJECT_LOCK (jitterbuffer);
+    if (GST_ELEMENT_CLOCK (jitterbuffer)) {
+      now =
+          gst_clock_get_time (GST_ELEMENT_CLOCK (jitterbuffer)) -
+          GST_ELEMENT_CAST (jitterbuffer)->base_time;
+    }
+    GST_OBJECT_UNLOCK (jitterbuffer);
+
+    GST_DEBUG_OBJECT (jitterbuffer, "now %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (now));
+
+    /* Clear expired rtx-stats timers */
+    if (priv->do_retransmission)
+      timer_queue_clear_until (priv->rtx_stats_timers, now);
+
+    /* Iterate "normal" timers */
+    len = priv->timers->len;
+    for (i = 0; i < len;) {
+      TimerData *test = &g_array_index (priv->timers, TimerData, i);
+      GstClockTime test_timeout = get_timeout (jitterbuffer, test);
+      gboolean save_best = FALSE;
+
+      GST_DEBUG_OBJECT (jitterbuffer,
+          "%d, %d, %d, %" GST_TIME_FORMAT " diff:%" GST_STIME_FORMAT, i,
+          test->type, test->seqnum, GST_TIME_ARGS (test_timeout),
+          GST_STIME_ARGS ((gint64) (test_timeout - now)));
+
+      /* Weed out anything too late */
+      if (test->type == TIMER_TYPE_LOST &&
+          (test_timeout == -1 || test_timeout <= now)) {
+        GST_DEBUG_OBJECT (jitterbuffer, "Weeding out late entry");
+        do_lost_timeout (jitterbuffer, test, now);
+        if (!priv->timer_running)
+          break;
+        /* We don't move the iterator forward since we just removed the current entry,
+         * but we update the termination condition */
+        len = priv->timers->len;
+      } else {
+        /* find the smallest timeout */
+        if (timer == NULL) {
+          save_best = TRUE;
+        } else if (timer_timeout == -1) {
+          /* we already have an immediate timeout, the new timer must be an
+           * immediate timer with smaller seqnum to become the best */
+          if (test_timeout == -1
+              && (gst_rtp_buffer_compare_seqnum (test->seqnum,
+                      timer->seqnum) > 0))
+            save_best = TRUE;
+        } else if (test_timeout == -1) {
+          /* first immediate timer */
+          save_best = TRUE;
+        } else if (test_timeout < timer_timeout) {
+          /* earlier timer */
+          save_best = TRUE;
+        } else if (test_timeout == timer_timeout
+            && (gst_rtp_buffer_compare_seqnum (test->seqnum,
+                    timer->seqnum) > 0)) {
+          /* same timer, smaller seqnum */
+          save_best = TRUE;
+        }
+
+        if (save_best) {
+          GST_DEBUG_OBJECT (jitterbuffer, "new best %d", i);
+          timer = test;
+          timer_timeout = test_timeout;
+        }
+        i++;
+      }
+    }
+    if (timer && !priv->blocked) {
+      GstClock *clock;
+      GstClockTime sync_time;
+      GstClockID id;
+      GstClockReturn ret;
+      GstClockTimeDiff clock_jitter;
+
+      if (timer_timeout == -1 || timer_timeout <= now) {
+        /* We have normally removed all lost timers in the loop above */
+        g_assert (timer->type != TIMER_TYPE_LOST);
+
+        do_timeout (jitterbuffer, timer, now);
+        /* check here, do_timeout could have released the lock */
+        if (!priv->timer_running)
+          break;
+        continue;
+      }
+
+      GST_OBJECT_LOCK (jitterbuffer);
+      clock = GST_ELEMENT_CLOCK (jitterbuffer);
+      if (!clock) {
+        GST_OBJECT_UNLOCK (jitterbuffer);
+        /* let's just push if there is no clock */
+        GST_DEBUG_OBJECT (jitterbuffer, "No clock, timeout right away");
+        now = timer_timeout;
+        continue;
+      }
+
+      /* prepare for sync against clock */
+      sync_time = timer_timeout + GST_ELEMENT_CAST (jitterbuffer)->base_time;
+      /* add latency of peer to get input time */
+      sync_time += priv->peer_latency;
+
+      GST_DEBUG_OBJECT (jitterbuffer, "sync to timestamp %" GST_TIME_FORMAT
+          " with sync time %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (timer_timeout), GST_TIME_ARGS (sync_time));
+
+      /* create an entry for the clock */
+      id = priv->clock_id = gst_clock_new_single_shot_id (clock, sync_time);
+      priv->timer_timeout = timer_timeout;
+      priv->timer_seqnum = timer->seqnum;
+      GST_OBJECT_UNLOCK (jitterbuffer);
+
+      /* release the lock so that the other end can push stuff or unlock */
+      JBUF_UNLOCK (priv);
+
+      ret = gst_clock_id_wait (id, &clock_jitter);
+
+      JBUF_LOCK (priv);
+      if (!priv->timer_running) {
+        gst_clock_id_unref (id);
+        priv->clock_id = NULL;
+        break;
+      }
+
+      if (ret != GST_CLOCK_UNSCHEDULED) {
+        now = timer_timeout + MAX (clock_jitter, 0);
+        GST_DEBUG_OBJECT (jitterbuffer,
+            "sync done, %d, #%d, %" GST_STIME_FORMAT, ret, priv->timer_seqnum,
+            GST_STIME_ARGS (clock_jitter));
+      } else {
+        GST_DEBUG_OBJECT (jitterbuffer, "sync unscheduled");
+      }
+      /* and free the entry */
+      gst_clock_id_unref (id);
+      priv->clock_id = NULL;
+    } else {
+      /* no timers, wait for activity */
+      JBUF_WAIT_TIMER (priv);
+    }
+  }
+  JBUF_UNLOCK (priv);
+
+  GST_DEBUG_OBJECT (jitterbuffer, "we are stopping");
+  return;
+}
+
+/*
+ * This funcion implements the main pushing loop on the source pad.
+ *
+ * It first tries to push as many buffers as possible. If there is a seqnum
+ * mismatch, we wait for the next timeouts.
+ */
+static void
+gst_rtp_jitter_buffer_loop (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstRtpJitterBufferPrivate *priv;
+  GstFlowReturn result = GST_FLOW_OK;
+
+  priv = jitterbuffer->priv;
+
+  JBUF_LOCK_CHECK (priv, flushing);
+  do {
+    result = handle_next_buffer (jitterbuffer);
+    if (G_LIKELY (result == GST_FLOW_WAIT)) {
+      /* now wait for the next event */
+      JBUF_WAIT_EVENT (priv, flushing);
+      result = GST_FLOW_OK;
+    }
+  } while (result == GST_FLOW_OK);
+  /* store result for upstream */
+  priv->srcresult = result;
+  /* if we get here we need to pause */
+  goto pause;
+
+  /* ERRORS */
+flushing:
+  {
+    result = priv->srcresult;
+    goto pause;
+  }
+pause:
+  {
+    GstEvent *event;
+
+    JBUF_SIGNAL_QUERY (priv, FALSE);
+    JBUF_UNLOCK (priv);
+
+    GST_DEBUG_OBJECT (jitterbuffer, "pausing task, reason %s",
+        gst_flow_get_name (result));
+    gst_pad_pause_task (priv->srcpad);
+    if (result == GST_FLOW_EOS) {
+      event = gst_event_new_eos ();
+      gst_pad_push_event (priv->srcpad, event);
+    }
+    return;
+  }
+}
+
+/* collect the info from the lastest RTCP packet and the jitterbuffer sync, do
+ * some sanity checks and then emit the handle-sync signal with the parameters.
+ * This function must be called with the LOCK */
+static void
+do_handle_sync (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstRtpJitterBufferPrivate *priv;
+  guint64 base_rtptime, base_time;
+  guint32 clock_rate;
+  guint64 last_rtptime;
+  guint64 clock_base;
+  guint64 ext_rtptime, diff;
+  gboolean valid = TRUE, keep = FALSE;
+
+  priv = jitterbuffer->priv;
+
+  /* get the last values from the jitterbuffer */
+  rtp_jitter_buffer_get_sync (priv->jbuf, &base_rtptime, &base_time,
+      &clock_rate, &last_rtptime);
+
+  clock_base = priv->clock_base;
+  ext_rtptime = priv->ext_rtptime;
+
+  GST_DEBUG_OBJECT (jitterbuffer, "ext SR %" G_GUINT64_FORMAT ", base %"
+      G_GUINT64_FORMAT ", clock-rate %" G_GUINT32_FORMAT
+      ", clock-base %" G_GUINT64_FORMAT ", last-rtptime %" G_GUINT64_FORMAT,
+      ext_rtptime, base_rtptime, clock_rate, clock_base, last_rtptime);
+
+  if (base_rtptime == -1 || clock_rate == -1 || base_time == -1) {
+    /* we keep this SR packet for later. When we get a valid RTP packet the
+     * above values will be set and we can try to use the SR packet */
+    GST_DEBUG_OBJECT (jitterbuffer, "keeping for later, no RTP values");
+    keep = TRUE;
+  } else {
+    /* we can't accept anything that happened before we did the last resync */
+    if (base_rtptime > ext_rtptime) {
+      GST_DEBUG_OBJECT (jitterbuffer, "dropping, older than base time");
+      valid = FALSE;
+    } else {
+      /* the SR RTP timestamp must be something close to what we last observed
+       * in the jitterbuffer */
+      if (ext_rtptime > last_rtptime) {
+        /* check how far ahead it is to our RTP timestamps */
+        diff = ext_rtptime - last_rtptime;
+        /* if bigger than 1 second, we drop it */
+        if (jitterbuffer->priv->max_rtcp_rtp_time_diff != -1 &&
+            diff >
+            gst_util_uint64_scale (jitterbuffer->priv->max_rtcp_rtp_time_diff,
+                clock_rate, 1000)) {
+          GST_DEBUG_OBJECT (jitterbuffer, "too far ahead");
+          /* should drop this, but some RTSP servers end up with bogus
+           * way too ahead RTCP packet when repeated PAUSE/PLAY,
+           * so still trigger rptbin sync but invalidate RTCP data
+           * (sync might use other methods) */
+          ext_rtptime = -1;
+        }
+        GST_DEBUG_OBJECT (jitterbuffer, "ext last %" G_GUINT64_FORMAT ", diff %"
+            G_GUINT64_FORMAT, last_rtptime, diff);
+      }
+    }
+  }
+
+  if (keep) {
+    GST_DEBUG_OBJECT (jitterbuffer, "keeping RTCP packet for later");
+  } else if (valid) {
+    GstStructure *s;
+
+    s = gst_structure_new ("application/x-rtp-sync",
+        "base-rtptime", G_TYPE_UINT64, base_rtptime,
+        "base-time", G_TYPE_UINT64, base_time,
+        "clock-rate", G_TYPE_UINT, clock_rate,
+        "clock-base", G_TYPE_UINT64, clock_base,
+        "sr-ext-rtptime", G_TYPE_UINT64, ext_rtptime,
+        "sr-buffer", GST_TYPE_BUFFER, priv->last_sr, NULL);
+
+    GST_DEBUG_OBJECT (jitterbuffer, "signaling sync");
+    gst_buffer_replace (&priv->last_sr, NULL);
+    JBUF_UNLOCK (priv);
+    g_signal_emit (jitterbuffer,
+        gst_rtp_jitter_buffer_signals[SIGNAL_HANDLE_SYNC], 0, s);
+    JBUF_LOCK (priv);
+    gst_structure_free (s);
+  } else {
+    GST_DEBUG_OBJECT (jitterbuffer, "dropping RTCP packet");
+    gst_buffer_replace (&priv->last_sr, NULL);
+  }
+}
+
+static GstFlowReturn
+gst_rtp_jitter_buffer_chain_rtcp (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer)
+{
+  GstRtpJitterBuffer *jitterbuffer;
+  GstRtpJitterBufferPrivate *priv;
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint32 ssrc;
+  GstRTCPPacket packet;
+  guint64 ext_rtptime;
+  guint32 rtptime;
+  GstRTCPBuffer rtcp = { NULL, };
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER (parent);
+
+  if (G_UNLIKELY (!gst_rtcp_buffer_validate_reduced (buffer)))
+    goto invalid_buffer;
+
+  priv = jitterbuffer->priv;
+
+  gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp);
+
+  if (!gst_rtcp_buffer_get_first_packet (&rtcp, &packet))
+    goto empty_buffer;
+
+  /* first packet must be SR or RR or else the validate would have failed */
+  switch (gst_rtcp_packet_get_type (&packet)) {
+    case GST_RTCP_TYPE_SR:
+      gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, NULL, &rtptime,
+          NULL, NULL);
+      break;
+    default:
+      goto ignore_buffer;
+  }
+  gst_rtcp_buffer_unmap (&rtcp);
+
+  GST_DEBUG_OBJECT (jitterbuffer, "received RTCP of SSRC %08x", ssrc);
+
+  JBUF_LOCK (priv);
+  /* convert the RTP timestamp to our extended timestamp, using the same offset
+   * we used in the jitterbuffer */
+  ext_rtptime = priv->jbuf->ext_rtptime;
+  ext_rtptime = gst_rtp_buffer_ext_timestamp (&ext_rtptime, rtptime);
+
+  priv->ext_rtptime = ext_rtptime;
+  gst_buffer_replace (&priv->last_sr, buffer);
+
+  do_handle_sync (jitterbuffer);
+  JBUF_UNLOCK (priv);
+
+done:
+  gst_buffer_unref (buffer);
+
+  return ret;
+
+invalid_buffer:
+  {
+    /* this is not fatal but should be filtered earlier */
+    GST_ELEMENT_WARNING (jitterbuffer, STREAM, DECODE, (NULL),
+        ("Received invalid RTCP payload, dropping"));
+    ret = GST_FLOW_OK;
+    goto done;
+  }
+empty_buffer:
+  {
+    /* this is not fatal but should be filtered earlier */
+    GST_ELEMENT_WARNING (jitterbuffer, STREAM, DECODE, (NULL),
+        ("Received empty RTCP payload, dropping"));
+    gst_rtcp_buffer_unmap (&rtcp);
+    ret = GST_FLOW_OK;
+    goto done;
+  }
+ignore_buffer:
+  {
+    GST_DEBUG_OBJECT (jitterbuffer, "ignoring RTCP packet");
+    gst_rtcp_buffer_unmap (&rtcp);
+    ret = GST_FLOW_OK;
+    goto done;
+  }
+}
+
+static gboolean
+gst_rtp_jitter_buffer_sink_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  gboolean res = FALSE;
+  GstRtpJitterBuffer *jitterbuffer;
+  GstRtpJitterBufferPrivate *priv;
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER (parent);
+  priv = jitterbuffer->priv;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *filter, *caps;
+
+      gst_query_parse_caps (query, &filter);
+      caps = gst_rtp_jitter_buffer_getcaps (pad, filter);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+      res = TRUE;
+      break;
+    }
+    default:
+      if (GST_QUERY_IS_SERIALIZED (query)) {
+        RTPJitterBufferItem *item;
+        gboolean head;
+
+        JBUF_LOCK_CHECK (priv, out_flushing);
+        if (rtp_jitter_buffer_get_mode (priv->jbuf) !=
+            RTP_JITTER_BUFFER_MODE_BUFFER) {
+          GST_DEBUG_OBJECT (jitterbuffer, "adding serialized query");
+          item = alloc_item (query, ITEM_TYPE_QUERY, -1, -1, -1, 0, -1);
+          rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL);
+          if (head)
+            JBUF_SIGNAL_EVENT (priv);
+          JBUF_WAIT_QUERY (priv, out_flushing);
+          res = priv->last_query;
+        } else {
+          GST_DEBUG_OBJECT (jitterbuffer, "refusing query, we are buffering");
+          res = FALSE;
+        }
+        JBUF_UNLOCK (priv);
+      } else {
+        res = gst_pad_query_default (pad, parent, query);
+      }
+      break;
+  }
+  return res;
+  /* ERRORS */
+out_flushing:
+  {
+    GST_DEBUG_OBJECT (jitterbuffer, "we are flushing");
+    JBUF_UNLOCK (priv);
+    return FALSE;
+  }
+
+}
+
+static gboolean
+gst_rtp_jitter_buffer_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  GstRtpJitterBuffer *jitterbuffer;
+  GstRtpJitterBufferPrivate *priv;
+  gboolean res = FALSE;
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER (parent);
+  priv = jitterbuffer->priv;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_LATENCY:
+    {
+      /* We need to send the query upstream and add the returned latency to our
+       * own */
+      GstClockTime min_latency, max_latency;
+      gboolean us_live;
+      GstClockTime our_latency;
+
+      if ((res = gst_pad_peer_query (priv->sinkpad, query))) {
+        gst_query_parse_latency (query, &us_live, &min_latency, &max_latency);
+
+        GST_DEBUG_OBJECT (jitterbuffer, "Peer latency: min %"
+            GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
+
+        /* store this so that we can safely sync on the peer buffers. */
+        JBUF_LOCK (priv);
+        priv->peer_latency = min_latency;
+        our_latency = priv->latency_ns;
+        JBUF_UNLOCK (priv);
+
+        GST_DEBUG_OBJECT (jitterbuffer, "Our latency: %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (our_latency));
+
+        /* we add some latency but can buffer an infinite amount of time */
+        min_latency += our_latency;
+        max_latency = -1;
+
+        GST_DEBUG_OBJECT (jitterbuffer, "Calculated total latency : min %"
+            GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
+
+        gst_query_set_latency (query, TRUE, min_latency, max_latency);
+      }
+      break;
+    }
+    case GST_QUERY_POSITION:
+    {
+      GstClockTime start, last_out;
+      GstFormat fmt;
+
+      gst_query_parse_position (query, &fmt, NULL);
+      if (fmt != GST_FORMAT_TIME) {
+        res = gst_pad_query_default (pad, parent, query);
+        break;
+      }
+
+      JBUF_LOCK (priv);
+      start = priv->npt_start;
+      last_out = priv->last_out_time;
+      JBUF_UNLOCK (priv);
+
+      GST_DEBUG_OBJECT (jitterbuffer, "npt start %" GST_TIME_FORMAT
+          ", last out %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
+          GST_TIME_ARGS (last_out));
+
+      if (GST_CLOCK_TIME_IS_VALID (start) && GST_CLOCK_TIME_IS_VALID (last_out)) {
+        /* bring 0-based outgoing time to stream time */
+        gst_query_set_position (query, GST_FORMAT_TIME, start + last_out);
+        res = TRUE;
+      } else {
+        res = gst_pad_query_default (pad, parent, query);
+      }
+      break;
+    }
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *filter, *caps;
+
+      gst_query_parse_caps (query, &filter);
+      caps = gst_rtp_jitter_buffer_getcaps (pad, filter);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+      res = TRUE;
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+
+  return res;
+}
+
+static void
+gst_rtp_jitter_buffer_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstRtpJitterBuffer *jitterbuffer;
+  GstRtpJitterBufferPrivate *priv;
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER (object);
+  priv = jitterbuffer->priv;
+
+  switch (prop_id) {
+    case PROP_LATENCY:
+    {
+      guint new_latency, old_latency;
+
+      new_latency = g_value_get_uint (value);
+
+      JBUF_LOCK (priv);
+      old_latency = priv->latency_ms;
+      priv->latency_ms = new_latency;
+      priv->latency_ns = priv->latency_ms * GST_MSECOND;
+      rtp_jitter_buffer_set_delay (priv->jbuf, priv->latency_ns);
+      JBUF_UNLOCK (priv);
+
+      /* post message if latency changed, this will inform the parent pipeline
+       * that a latency reconfiguration is possible/needed. */
+      if (new_latency != old_latency) {
+        GST_DEBUG_OBJECT (jitterbuffer, "latency changed to: %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (new_latency * GST_MSECOND));
+
+        gst_element_post_message (GST_ELEMENT_CAST (jitterbuffer),
+            gst_message_new_latency (GST_OBJECT_CAST (jitterbuffer)));
+      }
+      break;
+    }
+    case PROP_DROP_ON_LATENCY:
+      JBUF_LOCK (priv);
+      priv->drop_on_latency = g_value_get_boolean (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_TS_OFFSET:
+      JBUF_LOCK (priv);
+      if (priv->max_ts_offset_adjustment != 0) {
+        gint64 new_offset = g_value_get_int64 (value);
+
+        if (new_offset > priv->ts_offset) {
+          priv->ts_offset_remainder = new_offset - priv->ts_offset;
+        } else {
+          priv->ts_offset_remainder = -(priv->ts_offset - new_offset);
+        }
+      } else {
+        priv->ts_offset = g_value_get_int64 (value);
+        priv->ts_offset_remainder = 0;
+      }
+      priv->ts_discont = TRUE;
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_MAX_TS_OFFSET_ADJUSTMENT:
+      JBUF_LOCK (priv);
+      priv->max_ts_offset_adjustment = g_value_get_uint64 (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_DO_LOST:
+      JBUF_LOCK (priv);
+      priv->do_lost = g_value_get_boolean (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_MODE:
+      JBUF_LOCK (priv);
+      rtp_jitter_buffer_set_mode (priv->jbuf, g_value_get_enum (value));
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_DO_RETRANSMISSION:
+      JBUF_LOCK (priv);
+      priv->do_retransmission = g_value_get_boolean (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_NEXT_SEQNUM:
+      JBUF_LOCK (priv);
+      priv->rtx_next_seqnum = g_value_get_boolean (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_DELAY:
+      JBUF_LOCK (priv);
+      priv->rtx_delay = g_value_get_int (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_MIN_DELAY:
+      JBUF_LOCK (priv);
+      priv->rtx_min_delay = g_value_get_uint (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_DELAY_REORDER:
+      JBUF_LOCK (priv);
+      priv->rtx_delay_reorder = g_value_get_int (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_RETRY_TIMEOUT:
+      JBUF_LOCK (priv);
+      priv->rtx_retry_timeout = g_value_get_int (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_MIN_RETRY_TIMEOUT:
+      JBUF_LOCK (priv);
+      priv->rtx_min_retry_timeout = g_value_get_int (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_RETRY_PERIOD:
+      JBUF_LOCK (priv);
+      priv->rtx_retry_period = g_value_get_int (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_MAX_RETRIES:
+      JBUF_LOCK (priv);
+      priv->rtx_max_retries = g_value_get_int (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_DEADLINE:
+      JBUF_LOCK (priv);
+      priv->rtx_deadline_ms = g_value_get_int (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_STATS_TIMEOUT:
+      JBUF_LOCK (priv);
+      priv->rtx_stats_timeout = g_value_get_uint (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_MAX_RTCP_RTP_TIME_DIFF:
+      JBUF_LOCK (priv);
+      priv->max_rtcp_rtp_time_diff = g_value_get_int (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_MAX_DROPOUT_TIME:
+      JBUF_LOCK (priv);
+      priv->max_dropout_time = g_value_get_uint (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_MAX_MISORDER_TIME:
+      JBUF_LOCK (priv);
+      priv->max_misorder_time = g_value_get_uint (value);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RFC7273_SYNC:
+      JBUF_LOCK (priv);
+      rtp_jitter_buffer_set_rfc7273_sync (priv->jbuf,
+          g_value_get_boolean (value));
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_FASTSTART_MIN_PACKETS:
+      JBUF_LOCK (priv);
+      priv->faststart_min_packets = g_value_get_uint (value);
+      JBUF_UNLOCK (priv);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_jitter_buffer_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstRtpJitterBuffer *jitterbuffer;
+  GstRtpJitterBufferPrivate *priv;
+
+  jitterbuffer = GST_RTP_JITTER_BUFFER (object);
+  priv = jitterbuffer->priv;
+
+  switch (prop_id) {
+    case PROP_LATENCY:
+      JBUF_LOCK (priv);
+      g_value_set_uint (value, priv->latency_ms);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_DROP_ON_LATENCY:
+      JBUF_LOCK (priv);
+      g_value_set_boolean (value, priv->drop_on_latency);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_TS_OFFSET:
+      JBUF_LOCK (priv);
+      g_value_set_int64 (value, priv->ts_offset);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_MAX_TS_OFFSET_ADJUSTMENT:
+      JBUF_LOCK (priv);
+      g_value_set_uint64 (value, priv->max_ts_offset_adjustment);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_DO_LOST:
+      JBUF_LOCK (priv);
+      g_value_set_boolean (value, priv->do_lost);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_MODE:
+      JBUF_LOCK (priv);
+      g_value_set_enum (value, rtp_jitter_buffer_get_mode (priv->jbuf));
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_PERCENT:
+    {
+      gint percent;
+
+      JBUF_LOCK (priv);
+      if (priv->srcresult != GST_FLOW_OK)
+        percent = 100;
+      else
+        percent = rtp_jitter_buffer_get_percent (priv->jbuf);
+
+      g_value_set_int (value, percent);
+      JBUF_UNLOCK (priv);
+      break;
+    }
+    case PROP_DO_RETRANSMISSION:
+      JBUF_LOCK (priv);
+      g_value_set_boolean (value, priv->do_retransmission);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_NEXT_SEQNUM:
+      JBUF_LOCK (priv);
+      g_value_set_boolean (value, priv->rtx_next_seqnum);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_DELAY:
+      JBUF_LOCK (priv);
+      g_value_set_int (value, priv->rtx_delay);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_MIN_DELAY:
+      JBUF_LOCK (priv);
+      g_value_set_uint (value, priv->rtx_min_delay);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_DELAY_REORDER:
+      JBUF_LOCK (priv);
+      g_value_set_int (value, priv->rtx_delay_reorder);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_RETRY_TIMEOUT:
+      JBUF_LOCK (priv);
+      g_value_set_int (value, priv->rtx_retry_timeout);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_MIN_RETRY_TIMEOUT:
+      JBUF_LOCK (priv);
+      g_value_set_int (value, priv->rtx_min_retry_timeout);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_RETRY_PERIOD:
+      JBUF_LOCK (priv);
+      g_value_set_int (value, priv->rtx_retry_period);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_MAX_RETRIES:
+      JBUF_LOCK (priv);
+      g_value_set_int (value, priv->rtx_max_retries);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_DEADLINE:
+      JBUF_LOCK (priv);
+      g_value_set_int (value, priv->rtx_deadline_ms);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RTX_STATS_TIMEOUT:
+      JBUF_LOCK (priv);
+      g_value_set_uint (value, priv->rtx_stats_timeout);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_STATS:
+      g_value_take_boxed (value,
+          gst_rtp_jitter_buffer_create_stats (jitterbuffer));
+      break;
+    case PROP_MAX_RTCP_RTP_TIME_DIFF:
+      JBUF_LOCK (priv);
+      g_value_set_int (value, priv->max_rtcp_rtp_time_diff);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_MAX_DROPOUT_TIME:
+      JBUF_LOCK (priv);
+      g_value_set_uint (value, priv->max_dropout_time);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_MAX_MISORDER_TIME:
+      JBUF_LOCK (priv);
+      g_value_set_uint (value, priv->max_misorder_time);
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_RFC7273_SYNC:
+      JBUF_LOCK (priv);
+      g_value_set_boolean (value,
+          rtp_jitter_buffer_get_rfc7273_sync (priv->jbuf));
+      JBUF_UNLOCK (priv);
+      break;
+    case PROP_FASTSTART_MIN_PACKETS:
+      JBUF_LOCK (priv);
+      g_value_set_uint (value, priv->faststart_min_packets);
+      JBUF_UNLOCK (priv);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStructure *
+gst_rtp_jitter_buffer_create_stats (GstRtpJitterBuffer * jbuf)
+{
+  GstRtpJitterBufferPrivate *priv = jbuf->priv;
+  GstStructure *s;
+
+  JBUF_LOCK (priv);
+  s = gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+      "num-pushed", G_TYPE_UINT64, priv->num_pushed,
+      "num-lost", G_TYPE_UINT64, priv->num_lost,
+      "num-late", G_TYPE_UINT64, priv->num_late,
+      "num-duplicates", G_TYPE_UINT64, priv->num_duplicates,
+      "avg-jitter", G_TYPE_UINT64, priv->avg_jitter,
+      "rtx-count", G_TYPE_UINT64, priv->num_rtx_requests,
+      "rtx-success-count", G_TYPE_UINT64, priv->num_rtx_success,
+      "rtx-per-packet", G_TYPE_DOUBLE, priv->avg_rtx_num,
+      "rtx-rtt", G_TYPE_UINT64, priv->avg_rtx_rtt, NULL);
+  JBUF_UNLOCK (priv);
+
+  return s;
+}
diff --git a/gst/rtpmanager/gstrtpjitterbuffer.h b/gst/rtpmanager/gstrtpjitterbuffer.h
new file mode 100644
index 0000000..debb13b
--- /dev/null
+++ b/gst/rtpmanager/gstrtpjitterbuffer.h
@@ -0,0 +1,87 @@
+/*
+ * Farsight Voice+Video library
+ *
+ *  Copyright 2007 Collabora Ltd, 
+ *  Copyright 2007 Nokia Corporation
+ *   @author: Philippe Kalaf <philippe.kalaf@collabora.co.uk>.
+ *  Copyright 2007 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __GST_RTP_JITTER_BUFFER_H__
+#define __GST_RTP_JITTER_BUFFER_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+G_BEGIN_DECLS
+
+/* #define's don't like whitespacey bits */
+#define GST_TYPE_RTP_JITTER_BUFFER \
+  (gst_rtp_jitter_buffer_get_type())
+#define GST_RTP_JITTER_BUFFER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+  GST_TYPE_RTP_JITTER_BUFFER,GstRtpJitterBuffer))
+#define GST_RTP_JITTER_BUFFER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), \
+  GST_TYPE_RTP_JITTER_BUFFER,GstRtpJitterBufferClass))
+#define GST_IS_RTP_JITTER_BUFFER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_JITTER_BUFFER))
+#define GST_IS_RTP_JITTER_BUFFER_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_JITTER_BUFFER))
+#define GST_RTP_JITTER_BUFFER_CAST(obj) \
+  ((GstRtpJitterBuffer *)(obj))
+
+typedef struct _GstRtpJitterBuffer GstRtpJitterBuffer;
+typedef struct _GstRtpJitterBufferClass GstRtpJitterBufferClass;
+typedef struct _GstRtpJitterBufferPrivate GstRtpJitterBufferPrivate;
+
+/**
+ * GstRtpJitterBuffer:
+ *
+ * Opaque jitterbuffer structure.
+ */
+struct _GstRtpJitterBuffer
+{
+  GstElement parent;
+
+  /*< private >*/
+  GstRtpJitterBufferPrivate *priv; /* FIXME: remove? */
+};
+
+struct _GstRtpJitterBufferClass
+{
+  GstElementClass parent_class;
+
+  /* signals */
+  GstCaps* (*request_pt_map)   (GstRtpJitterBuffer *buffer, guint pt);
+
+  void     (*handle_sync)      (GstRtpJitterBuffer *buffer, GstStructure *s);
+  void     (*on_npt_stop)      (GstRtpJitterBuffer *buffer);
+
+  /* actions */
+  void     (*clear_pt_map)   (GstRtpJitterBuffer *buffer);
+
+  GstClockTime (*set_active)     (GstRtpJitterBuffer *buffer, gboolean active, guint64 elapsed);
+};
+
+GType gst_rtp_jitter_buffer_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_JITTER_BUFFER_H__ */
diff --git a/gst/rtpmanager/gstrtpmanager.c b/gst/rtpmanager/gstrtpmanager.c
new file mode 100644
index 0000000..426b0b7
--- /dev/null
+++ b/gst/rtpmanager/gstrtpmanager.c
@@ -0,0 +1,79 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstrtpbin.h"
+#include "gstrtpjitterbuffer.h"
+#include "gstrtpptdemux.h"
+#include "gstrtpsession.h"
+#include "gstrtprtxqueue.h"
+#include "gstrtprtxreceive.h"
+#include "gstrtprtxsend.h"
+#include "gstrtpssrcdemux.h"
+#include "gstrtpdtmfmux.h"
+#include "gstrtpmux.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "rtpbin", GST_RANK_NONE, GST_TYPE_RTP_BIN))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "rtpjitterbuffer", GST_RANK_NONE,
+          GST_TYPE_RTP_JITTER_BUFFER))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "rtpptdemux", GST_RANK_NONE,
+          GST_TYPE_RTP_PT_DEMUX))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "rtpsession", GST_RANK_NONE,
+          GST_TYPE_RTP_SESSION))
+    return FALSE;
+
+  if (!gst_rtp_rtx_queue_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_rtx_receive_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_rtx_send_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "rtpssrcdemux", GST_RANK_NONE,
+          GST_TYPE_RTP_SSRC_DEMUX))
+    return FALSE;
+
+  if (!gst_rtp_mux_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_rtp_dtmf_mux_plugin_init (plugin))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    rtpmanager,
+    "RTP session management plugin library",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/rtpmanager/gstrtpmux.c b/gst/rtpmanager/gstrtpmux.c
new file mode 100644
index 0000000..b96e570
--- /dev/null
+++ b/gst/rtpmanager/gstrtpmux.c
@@ -0,0 +1,1009 @@
+/* RTP muxer element for GStreamer
+ *
+ * gstrtpmux.c:
+ *
+ * Copyright (C) <2007-2010> Nokia Corporation.
+ *   Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
+ * Copyright (C) <2007-2010> Collabora Ltd
+ *   Contact: Olivier Crete <olivier.crete@collabora.co.uk>
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2000,2005 Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpmux
+ * @see_also: rtpdtmfmux
+ *
+ * The rtp muxer takes multiple RTP streams having the same clock-rate and
+ * muxes into a single stream with a single SSRC.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 rtpmux name=mux ! udpsink host=127.0.0.1 port=8888        \
+ *              alsasrc ! alawenc ! rtppcmapay !                        \
+ *              application/x-rtp, payload=8, rate=8000 ! mux.sink_0    \
+ *              audiotestsrc is-live=1 !                                \
+ *              mulawenc ! rtppcmupay !                                 \
+ *              application/x-rtp, payload=0, rate=8000 ! mux.sink_1
+ * ]|
+ * In this example, an audio stream is captured from ALSA and another is
+ * generated, both are encoded into different payload types and muxed together
+ * so they can be sent on the same port.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <string.h>
+
+#include "gstrtpmux.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_mux_debug);
+#define GST_CAT_DEFAULT gst_rtp_mux_debug
+
+enum
+{
+  PROP_0,
+  PROP_TIMESTAMP_OFFSET,
+  PROP_SEQNUM_OFFSET,
+  PROP_SEQNUM,
+  PROP_SSRC
+};
+
+#define DEFAULT_TIMESTAMP_OFFSET -1
+#define DEFAULT_SEQNUM_OFFSET    -1
+#define DEFAULT_SSRC             -1
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static GstPad *gst_rtp_mux_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
+static void gst_rtp_mux_release_pad (GstElement * element, GstPad * pad);
+static GstFlowReturn gst_rtp_mux_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer);
+static GstFlowReturn gst_rtp_mux_chain_list (GstPad * pad, GstObject * parent,
+    GstBufferList * bufferlist);
+static gboolean gst_rtp_mux_setcaps (GstPad * pad, GstRTPMux * rtp_mux,
+    GstCaps * caps);
+static gboolean gst_rtp_mux_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static gboolean gst_rtp_mux_sink_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+
+static GstStateChangeReturn gst_rtp_mux_change_state (GstElement *
+    element, GstStateChange transition);
+
+static void gst_rtp_mux_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_mux_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_rtp_mux_dispose (GObject * object);
+
+static gboolean gst_rtp_mux_src_event_real (GstRTPMux * rtp_mux,
+    GstEvent * event);
+
+G_DEFINE_TYPE (GstRTPMux, gst_rtp_mux, GST_TYPE_ELEMENT);
+
+
+static void
+gst_rtp_mux_class_init (GstRTPMuxClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP muxer",
+      "Codec/Muxer",
+      "multiplex N rtp streams into one", "Zeeshan Ali <first.last@nokia.com>");
+
+  gobject_class->get_property = gst_rtp_mux_get_property;
+  gobject_class->set_property = gst_rtp_mux_set_property;
+  gobject_class->dispose = gst_rtp_mux_dispose;
+
+  klass->src_event = gst_rtp_mux_src_event_real;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_TIMESTAMP_OFFSET, g_param_spec_int ("timestamp-offset",
+          "Timestamp Offset",
+          "Offset to add to all outgoing timestamps (-1 = random)", -1,
+          G_MAXINT, DEFAULT_TIMESTAMP_OFFSET,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET,
+      g_param_spec_int ("seqnum-offset", "Sequence number Offset",
+          "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXINT,
+          DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM,
+      g_param_spec_uint ("seqnum", "Sequence number",
+          "The RTP sequence number of the last processed packet",
+          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
+      g_param_spec_uint ("ssrc", "SSRC",
+          "The SSRC of the packets (default == random)",
+          0, G_MAXUINT, DEFAULT_SSRC,
+          GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE |
+          G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->request_new_pad =
+      GST_DEBUG_FUNCPTR (gst_rtp_mux_request_new_pad);
+  gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_mux_release_pad);
+  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_mux_change_state);
+}
+
+static void
+gst_rtp_mux_dispose (GObject * object)
+{
+  GstRTPMux *rtp_mux = GST_RTP_MUX (object);
+  GList *item;
+
+  g_clear_object (&rtp_mux->last_pad);
+
+restart:
+  for (item = GST_ELEMENT_PADS (object); item; item = g_list_next (item)) {
+    GstPad *pad = GST_PAD (item->data);
+    if (GST_PAD_IS_SINK (pad)) {
+      gst_element_release_request_pad (GST_ELEMENT (object), pad);
+      goto restart;
+    }
+  }
+
+  G_OBJECT_CLASS (gst_rtp_mux_parent_class)->dispose (object);
+}
+
+static gboolean
+gst_rtp_mux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstRTPMux *rtp_mux = GST_RTP_MUX (parent);
+  GstRTPMuxClass *klass;
+  gboolean ret;
+
+  klass = GST_RTP_MUX_GET_CLASS (rtp_mux);
+
+  ret = klass->src_event (rtp_mux, event);
+
+  return ret;
+}
+
+static gboolean
+gst_rtp_mux_src_event_real (GstRTPMux * rtp_mux, GstEvent * event)
+{
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CUSTOM_UPSTREAM:
+    {
+      const GstStructure *s = gst_event_get_structure (event);
+
+      if (gst_structure_has_name (s, "GstRTPCollision")) {
+        guint ssrc = 0;
+
+        if (!gst_structure_get_uint (s, "ssrc", &ssrc))
+          ssrc = -1;
+
+        GST_DEBUG_OBJECT (rtp_mux, "collided ssrc: %" G_GUINT32_FORMAT, ssrc);
+
+        /* choose another ssrc for our stream */
+        GST_OBJECT_LOCK (rtp_mux);
+        if (ssrc == rtp_mux->current_ssrc) {
+          GstCaps *caps;
+          guint suggested_ssrc = 0;
+          guint32 new_ssrc;
+
+          if (gst_structure_get_uint (s, "suggested-ssrc", &suggested_ssrc))
+            rtp_mux->current_ssrc = suggested_ssrc;
+
+          while (ssrc == rtp_mux->current_ssrc)
+            rtp_mux->current_ssrc = g_random_int ();
+
+          new_ssrc = rtp_mux->current_ssrc;
+          GST_OBJECT_UNLOCK (rtp_mux);
+
+          caps = gst_pad_get_current_caps (rtp_mux->srcpad);
+          caps = gst_caps_make_writable (caps);
+          gst_caps_set_simple (caps, "ssrc", G_TYPE_UINT, new_ssrc, NULL);
+          gst_pad_set_caps (rtp_mux->srcpad, caps);
+          gst_caps_unref (caps);
+        } else {
+          GST_OBJECT_UNLOCK (rtp_mux);
+        }
+      }
+      break;
+    }
+    default:
+      break;
+  }
+
+
+  return gst_pad_event_default (rtp_mux->srcpad, GST_OBJECT (rtp_mux), event);
+}
+
+static void
+gst_rtp_mux_init (GstRTPMux * rtp_mux)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (rtp_mux);
+
+  rtp_mux->srcpad =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "src"), "src");
+  gst_pad_set_event_function (rtp_mux->srcpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_mux_src_event));
+  gst_pad_use_fixed_caps (rtp_mux->srcpad);
+  gst_element_add_pad (GST_ELEMENT (rtp_mux), rtp_mux->srcpad);
+
+  rtp_mux->ssrc = DEFAULT_SSRC;
+  rtp_mux->current_ssrc = DEFAULT_SSRC;
+  rtp_mux->ssrc_random = TRUE;
+  rtp_mux->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
+  rtp_mux->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
+
+  rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
+}
+
+static void
+gst_rtp_mux_setup_sinkpad (GstRTPMux * rtp_mux, GstPad * sinkpad)
+{
+  GstRTPMuxPadPrivate *padpriv = g_slice_new0 (GstRTPMuxPadPrivate);
+
+  /* setup some pad functions */
+  gst_pad_set_chain_function (sinkpad, GST_DEBUG_FUNCPTR (gst_rtp_mux_chain));
+  gst_pad_set_chain_list_function (sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_mux_chain_list));
+  gst_pad_set_event_function (sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_mux_sink_event));
+  gst_pad_set_query_function (sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_mux_sink_query));
+
+
+  gst_segment_init (&padpriv->segment, GST_FORMAT_UNDEFINED);
+
+  gst_pad_set_element_private (sinkpad, padpriv);
+
+  gst_pad_set_active (sinkpad, TRUE);
+  gst_element_add_pad (GST_ELEMENT (rtp_mux), sinkpad);
+}
+
+static GstPad *
+gst_rtp_mux_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
+{
+  GstRTPMux *rtp_mux;
+  GstPad *newpad;
+
+  g_return_val_if_fail (templ != NULL, NULL);
+  g_return_val_if_fail (GST_IS_RTP_MUX (element), NULL);
+
+  rtp_mux = GST_RTP_MUX (element);
+
+  if (templ->direction != GST_PAD_SINK) {
+    GST_WARNING_OBJECT (rtp_mux, "request pad that is not a SINK pad");
+    return NULL;
+  }
+
+  newpad = gst_pad_new_from_template (templ, req_name);
+  if (newpad)
+    gst_rtp_mux_setup_sinkpad (rtp_mux, newpad);
+  else
+    GST_WARNING_OBJECT (rtp_mux, "failed to create request pad");
+
+  return newpad;
+}
+
+static void
+gst_rtp_mux_release_pad (GstElement * element, GstPad * pad)
+{
+  GstRTPMuxPadPrivate *padpriv;
+
+  GST_OBJECT_LOCK (element);
+  padpriv = gst_pad_get_element_private (pad);
+  gst_pad_set_element_private (pad, NULL);
+  GST_OBJECT_UNLOCK (element);
+
+  gst_element_remove_pad (element, pad);
+
+  if (padpriv) {
+    g_slice_free (GstRTPMuxPadPrivate, padpriv);
+  }
+}
+
+/* Put our own timestamp-offset on the buffer */
+static void
+gst_rtp_mux_readjust_rtp_timestamp_locked (GstRTPMux * rtp_mux,
+    GstRTPMuxPadPrivate * padpriv, GstRTPBuffer * rtpbuffer)
+{
+  guint32 ts;
+  guint32 sink_ts_base = 0;
+
+  if (padpriv && padpriv->have_timestamp_offset)
+    sink_ts_base = padpriv->timestamp_offset;
+
+  ts = gst_rtp_buffer_get_timestamp (rtpbuffer) - sink_ts_base +
+      rtp_mux->ts_base;
+  GST_LOG_OBJECT (rtp_mux, "Re-adjusting RTP ts %u to %u",
+      gst_rtp_buffer_get_timestamp (rtpbuffer), ts);
+  gst_rtp_buffer_set_timestamp (rtpbuffer, ts);
+}
+
+static gboolean
+process_buffer_locked (GstRTPMux * rtp_mux, GstRTPMuxPadPrivate * padpriv,
+    GstRTPBuffer * rtpbuffer)
+{
+  GstRTPMuxClass *klass = GST_RTP_MUX_GET_CLASS (rtp_mux);
+
+  if (klass->accept_buffer_locked)
+    if (!klass->accept_buffer_locked (rtp_mux, padpriv, rtpbuffer))
+      return FALSE;
+
+  rtp_mux->seqnum++;
+  gst_rtp_buffer_set_seq (rtpbuffer, rtp_mux->seqnum);
+
+  gst_rtp_buffer_set_ssrc (rtpbuffer, rtp_mux->current_ssrc);
+  gst_rtp_mux_readjust_rtp_timestamp_locked (rtp_mux, padpriv, rtpbuffer);
+  GST_LOG_OBJECT (rtp_mux,
+      "Pushing packet size %" G_GSIZE_FORMAT ", seq=%d, ts=%u",
+      rtpbuffer->map[0].size, rtp_mux->seqnum,
+      gst_rtp_buffer_get_timestamp (rtpbuffer));
+
+  if (padpriv) {
+    if (padpriv->segment.format == GST_FORMAT_TIME) {
+      GST_BUFFER_PTS (rtpbuffer->buffer) =
+          gst_segment_to_running_time (&padpriv->segment, GST_FORMAT_TIME,
+          GST_BUFFER_PTS (rtpbuffer->buffer));
+      GST_BUFFER_DTS (rtpbuffer->buffer) =
+          gst_segment_to_running_time (&padpriv->segment, GST_FORMAT_TIME,
+          GST_BUFFER_DTS (rtpbuffer->buffer));
+    }
+  }
+
+  return TRUE;
+}
+
+struct BufferListData
+{
+  GstRTPMux *rtp_mux;
+  GstRTPMuxPadPrivate *padpriv;
+  gboolean drop;
+};
+
+static gboolean
+process_list_item (GstBuffer ** buffer, guint idx, gpointer user_data)
+{
+  struct BufferListData *bd = user_data;
+  GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
+
+  *buffer = gst_buffer_make_writable (*buffer);
+
+  gst_rtp_buffer_map (*buffer, GST_MAP_READWRITE, &rtpbuffer);
+
+  bd->drop = !process_buffer_locked (bd->rtp_mux, bd->padpriv, &rtpbuffer);
+
+  gst_rtp_buffer_unmap (&rtpbuffer);
+
+  if (bd->drop)
+    return FALSE;
+
+  if (GST_BUFFER_DURATION_IS_VALID (*buffer) &&
+      GST_BUFFER_PTS_IS_VALID (*buffer))
+    bd->rtp_mux->last_stop = GST_BUFFER_PTS (*buffer) +
+        GST_BUFFER_DURATION (*buffer);
+  else
+    bd->rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
+
+  return TRUE;
+}
+
+static gboolean resend_events (GstPad * pad, GstEvent ** event,
+    gpointer user_data);
+
+static GstFlowReturn
+gst_rtp_mux_chain_list (GstPad * pad, GstObject * parent,
+    GstBufferList * bufferlist)
+{
+  GstRTPMux *rtp_mux;
+  GstFlowReturn ret;
+  GstRTPMuxPadPrivate *padpriv;
+  gboolean changed = FALSE;
+  struct BufferListData bd;
+
+  rtp_mux = GST_RTP_MUX (parent);
+
+  if (gst_pad_check_reconfigure (rtp_mux->srcpad)) {
+    GstCaps *current_caps = gst_pad_get_current_caps (pad);
+
+    if (!gst_rtp_mux_setcaps (pad, rtp_mux, current_caps)) {
+      gst_pad_mark_reconfigure (rtp_mux->srcpad);
+      if (GST_PAD_IS_FLUSHING (rtp_mux->srcpad))
+        ret = GST_FLOW_FLUSHING;
+      else
+        ret = GST_FLOW_NOT_NEGOTIATED;
+      gst_buffer_list_unref (bufferlist);
+      goto out;
+    }
+    gst_caps_unref (current_caps);
+  }
+
+  GST_OBJECT_LOCK (rtp_mux);
+
+  padpriv = gst_pad_get_element_private (pad);
+  if (!padpriv) {
+    GST_OBJECT_UNLOCK (rtp_mux);
+    ret = GST_FLOW_NOT_LINKED;
+    gst_buffer_list_unref (bufferlist);
+    goto out;
+  }
+
+  bd.rtp_mux = rtp_mux;
+  bd.padpriv = padpriv;
+  bd.drop = FALSE;
+
+  bufferlist = gst_buffer_list_make_writable (bufferlist);
+  gst_buffer_list_foreach (bufferlist, process_list_item, &bd);
+
+  if (!bd.drop && pad != rtp_mux->last_pad) {
+    changed = TRUE;
+    g_clear_object (&rtp_mux->last_pad);
+    rtp_mux->last_pad = g_object_ref (pad);
+  }
+
+  GST_OBJECT_UNLOCK (rtp_mux);
+
+  if (changed)
+    gst_pad_sticky_events_foreach (pad, resend_events, rtp_mux);
+
+  if (bd.drop) {
+    gst_buffer_list_unref (bufferlist);
+    ret = GST_FLOW_OK;
+  } else {
+    ret = gst_pad_push_list (rtp_mux->srcpad, bufferlist);
+  }
+
+out:
+
+  return ret;
+}
+
+static gboolean
+resend_events (GstPad * pad, GstEvent ** event, gpointer user_data)
+{
+  GstRTPMux *rtp_mux = user_data;
+
+  if (GST_EVENT_TYPE (*event) == GST_EVENT_CAPS) {
+    GstCaps *caps;
+
+    gst_event_parse_caps (*event, &caps);
+    gst_rtp_mux_setcaps (pad, rtp_mux, caps);
+  } else if (GST_EVENT_TYPE (*event) == GST_EVENT_SEGMENT) {
+    GstSegment new_segment;
+    gst_segment_init (&new_segment, GST_FORMAT_TIME);
+    gst_pad_push_event (rtp_mux->srcpad, gst_event_new_segment (&new_segment));
+  } else {
+    gst_pad_push_event (rtp_mux->srcpad, gst_event_ref (*event));
+  }
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_rtp_mux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstRTPMux *rtp_mux;
+  GstFlowReturn ret;
+  GstRTPMuxPadPrivate *padpriv;
+  gboolean drop;
+  gboolean changed = FALSE;
+  GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
+
+  rtp_mux = GST_RTP_MUX (parent);
+
+  if (gst_pad_check_reconfigure (rtp_mux->srcpad)) {
+    GstCaps *current_caps = gst_pad_get_current_caps (pad);
+
+    if (!gst_rtp_mux_setcaps (pad, rtp_mux, current_caps)) {
+      gst_pad_mark_reconfigure (rtp_mux->srcpad);
+      if (GST_PAD_IS_FLUSHING (rtp_mux->srcpad))
+        ret = GST_FLOW_FLUSHING;
+      else
+        ret = GST_FLOW_NOT_NEGOTIATED;
+      gst_buffer_unref (buffer);
+      goto out;
+    }
+    gst_caps_unref (current_caps);
+  }
+
+  GST_OBJECT_LOCK (rtp_mux);
+  padpriv = gst_pad_get_element_private (pad);
+
+  if (!padpriv) {
+    GST_OBJECT_UNLOCK (rtp_mux);
+    gst_buffer_unref (buffer);
+    return GST_FLOW_NOT_LINKED;
+  }
+
+  buffer = gst_buffer_make_writable (buffer);
+
+  if (!gst_rtp_buffer_map (buffer, GST_MAP_READWRITE, &rtpbuffer)) {
+    GST_OBJECT_UNLOCK (rtp_mux);
+    gst_buffer_unref (buffer);
+    GST_ERROR_OBJECT (rtp_mux, "Invalid RTP buffer");
+    return GST_FLOW_ERROR;
+  }
+
+  drop = !process_buffer_locked (rtp_mux, padpriv, &rtpbuffer);
+
+  gst_rtp_buffer_unmap (&rtpbuffer);
+
+  if (!drop) {
+    if (pad != rtp_mux->last_pad) {
+      changed = TRUE;
+      g_clear_object (&rtp_mux->last_pad);
+      rtp_mux->last_pad = g_object_ref (pad);
+    }
+
+    if (GST_BUFFER_DURATION_IS_VALID (buffer) &&
+        GST_BUFFER_PTS_IS_VALID (buffer))
+      rtp_mux->last_stop = GST_BUFFER_PTS (buffer) +
+          GST_BUFFER_DURATION (buffer);
+    else
+      rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
+  }
+
+  GST_OBJECT_UNLOCK (rtp_mux);
+
+  if (changed)
+    gst_pad_sticky_events_foreach (pad, resend_events, rtp_mux);
+
+  if (drop) {
+    gst_buffer_unref (buffer);
+    ret = GST_FLOW_OK;
+  } else {
+    ret = gst_pad_push (rtp_mux->srcpad, buffer);
+  }
+
+out:
+  return ret;
+}
+
+static gboolean
+gst_rtp_mux_setcaps (GstPad * pad, GstRTPMux * rtp_mux, GstCaps * caps)
+{
+  GstStructure *structure;
+  gboolean ret = FALSE;
+  GstRTPMuxPadPrivate *padpriv;
+  GstCaps *peercaps;
+
+  if (!gst_caps_is_fixed (caps))
+    return FALSE;
+
+  peercaps = gst_pad_peer_query_caps (rtp_mux->srcpad, NULL);
+  if (peercaps) {
+    GstCaps *tcaps, *othercaps;;
+    tcaps = gst_pad_get_pad_template_caps (pad);
+    othercaps = gst_caps_intersect_full (peercaps, tcaps,
+        GST_CAPS_INTERSECT_FIRST);
+
+    if (gst_caps_get_size (othercaps) > 0) {
+      structure = gst_caps_get_structure (othercaps, 0);
+      GST_OBJECT_LOCK (rtp_mux);
+      if (gst_structure_get_uint (structure, "ssrc", &rtp_mux->current_ssrc)) {
+        GST_DEBUG_OBJECT (pad, "Use downstream ssrc: %x",
+            rtp_mux->current_ssrc);
+        rtp_mux->have_ssrc = TRUE;
+      }
+      GST_OBJECT_UNLOCK (rtp_mux);
+    }
+
+    gst_caps_unref (othercaps);
+
+    gst_caps_unref (peercaps);
+    gst_caps_unref (tcaps);
+  }
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!structure)
+    return FALSE;
+
+  GST_OBJECT_LOCK (rtp_mux);
+  padpriv = gst_pad_get_element_private (pad);
+  if (padpriv &&
+      gst_structure_get_uint (structure, "timestamp-offset",
+          &padpriv->timestamp_offset)) {
+    padpriv->have_timestamp_offset = TRUE;
+  }
+
+  caps = gst_caps_copy (caps);
+
+  /* if we don't have a specified ssrc, first try to take one from the caps,
+     and if that fails, generate one */
+  if (!rtp_mux->have_ssrc) {
+    if (rtp_mux->ssrc_random) {
+      if (!gst_structure_get_uint (structure, "ssrc", &rtp_mux->current_ssrc))
+        rtp_mux->current_ssrc = g_random_int ();
+      rtp_mux->have_ssrc = TRUE;
+    }
+  }
+
+  gst_caps_set_simple (caps,
+      "timestamp-offset", G_TYPE_UINT, rtp_mux->ts_base,
+      "seqnum-offset", G_TYPE_UINT, rtp_mux->seqnum_base,
+      "ssrc", G_TYPE_UINT, rtp_mux->current_ssrc, NULL);
+
+  GST_OBJECT_UNLOCK (rtp_mux);
+
+  if (rtp_mux->send_stream_start) {
+    gchar s_id[32];
+
+    /* stream-start (FIXME: create id based on input ids) */
+    g_snprintf (s_id, sizeof (s_id), "interleave-%08x", g_random_int ());
+    gst_pad_push_event (rtp_mux->srcpad, gst_event_new_stream_start (s_id));
+
+    rtp_mux->send_stream_start = FALSE;
+  }
+
+  GST_DEBUG_OBJECT (rtp_mux,
+      "setting caps %" GST_PTR_FORMAT " on src pad..", caps);
+  ret = gst_pad_set_caps (rtp_mux->srcpad, caps);
+
+
+  gst_caps_unref (caps);
+
+  return ret;
+}
+
+static void
+clear_caps (GstCaps * caps, gboolean only_clock_rate)
+{
+  gint i, j;
+
+  /* Lets only match on the clock-rate */
+  for (i = 0; i < gst_caps_get_size (caps); i++) {
+    GstStructure *s = gst_caps_get_structure (caps, i);
+
+    for (j = 0; j < gst_structure_n_fields (s); j++) {
+      const gchar *name = gst_structure_nth_field_name (s, j);
+
+      if (strcmp (name, "clock-rate") && (only_clock_rate ||
+              (strcmp (name, "ssrc")))) {
+        gst_structure_remove_field (s, name);
+        j--;
+      }
+    }
+  }
+}
+
+static gboolean
+same_clock_rate_fold (const GValue * item, GValue * ret, gpointer user_data)
+{
+  GstPad *mypad = user_data;
+  GstPad *pad = g_value_get_object (item);
+  GstCaps *peercaps;
+  GstCaps *accumcaps;
+
+  if (pad == mypad)
+    return TRUE;
+
+  accumcaps = g_value_get_boxed (ret);
+  peercaps = gst_pad_peer_query_caps (pad, accumcaps);
+  if (!peercaps) {
+    g_warning ("no peercaps");
+    return TRUE;
+  }
+  peercaps = gst_caps_make_writable (peercaps);
+  clear_caps (peercaps, TRUE);
+
+  g_value_take_boxed (ret, peercaps);
+
+  return !gst_caps_is_empty (peercaps);
+}
+
+static GstCaps *
+gst_rtp_mux_getcaps (GstPad * pad, GstRTPMux * mux, GstCaps * filter)
+{
+  GstCaps *caps = NULL;
+  GstIterator *iter = NULL;
+  GValue v = { 0 };
+  GstIteratorResult res;
+  GstCaps *peercaps;
+  GstCaps *othercaps;
+  GstCaps *tcaps;
+
+  peercaps = gst_pad_peer_query_caps (mux->srcpad, NULL);
+
+  if (peercaps) {
+    tcaps = gst_pad_get_pad_template_caps (pad);
+    othercaps = gst_caps_intersect_full (peercaps, tcaps,
+        GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (peercaps);
+  } else {
+    tcaps = gst_pad_get_pad_template_caps (mux->srcpad);
+    if (filter)
+      othercaps = gst_caps_intersect_full (filter, tcaps,
+          GST_CAPS_INTERSECT_FIRST);
+    else
+      othercaps = gst_caps_copy (tcaps);
+  }
+  gst_caps_unref (tcaps);
+
+  GST_LOG_OBJECT (pad, "Intersected srcpad-peercaps and template caps: %"
+      GST_PTR_FORMAT, othercaps);
+
+  clear_caps (othercaps, TRUE);
+
+  g_value_init (&v, GST_TYPE_CAPS);
+
+  iter = gst_element_iterate_sink_pads (GST_ELEMENT (mux));
+  do {
+    gst_value_set_caps (&v, othercaps);
+    res = gst_iterator_fold (iter, same_clock_rate_fold, &v, pad);
+    gst_iterator_resync (iter);
+  } while (res == GST_ITERATOR_RESYNC);
+  gst_iterator_free (iter);
+
+  caps = gst_caps_intersect ((GstCaps *) gst_value_get_caps (&v), othercaps);
+
+  g_value_unset (&v);
+  gst_caps_unref (othercaps);
+
+  if (res == GST_ITERATOR_ERROR) {
+    gst_caps_unref (caps);
+    caps = gst_caps_new_empty ();
+  }
+
+
+  return caps;
+}
+
+static gboolean
+gst_rtp_mux_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  GstRTPMux *mux = GST_RTP_MUX (parent);
+  gboolean res = FALSE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *filter, *caps;
+
+      gst_query_parse_caps (query, &filter);
+      GST_LOG_OBJECT (pad, "Received caps-query with filter-caps: %"
+          GST_PTR_FORMAT, filter);
+      caps = gst_rtp_mux_getcaps (pad, mux, filter);
+      gst_query_set_caps_result (query, caps);
+      GST_LOG_OBJECT (mux, "Answering caps-query with caps: %"
+          GST_PTR_FORMAT, caps);
+      gst_caps_unref (caps);
+      res = TRUE;
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+
+  return res;
+}
+
+static void
+gst_rtp_mux_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstRTPMux *rtp_mux;
+
+  rtp_mux = GST_RTP_MUX (object);
+
+  GST_OBJECT_LOCK (rtp_mux);
+  switch (prop_id) {
+    case PROP_TIMESTAMP_OFFSET:
+      g_value_set_int (value, rtp_mux->ts_offset);
+      break;
+    case PROP_SEQNUM_OFFSET:
+      g_value_set_int (value, rtp_mux->seqnum_offset);
+      break;
+    case PROP_SEQNUM:
+      g_value_set_uint (value, rtp_mux->seqnum);
+      break;
+    case PROP_SSRC:
+      g_value_set_uint (value, rtp_mux->ssrc);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (rtp_mux);
+}
+
+static void
+gst_rtp_mux_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstRTPMux *rtp_mux;
+
+  rtp_mux = GST_RTP_MUX (object);
+
+  switch (prop_id) {
+    case PROP_TIMESTAMP_OFFSET:
+      rtp_mux->ts_offset = g_value_get_int (value);
+      break;
+    case PROP_SEQNUM_OFFSET:
+      rtp_mux->seqnum_offset = g_value_get_int (value);
+      break;
+    case PROP_SSRC:
+      GST_OBJECT_LOCK (rtp_mux);
+      rtp_mux->ssrc = g_value_get_uint (value);
+      rtp_mux->current_ssrc = rtp_mux->ssrc;
+      rtp_mux->have_ssrc = TRUE;
+      rtp_mux->ssrc_random = FALSE;
+      GST_OBJECT_UNLOCK (rtp_mux);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_rtp_mux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstRTPMux *mux = GST_RTP_MUX (parent);
+  gboolean is_pad;
+  gboolean ret;
+
+  GST_OBJECT_LOCK (mux);
+  is_pad = (pad == mux->last_pad);
+  GST_OBJECT_UNLOCK (mux);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      GST_LOG_OBJECT (pad, "Received caps-event with caps: %"
+          GST_PTR_FORMAT, caps);
+      ret = gst_rtp_mux_setcaps (pad, mux, caps);
+      gst_event_unref (event);
+      return ret;
+    }
+    case GST_EVENT_FLUSH_STOP:
+    {
+      GST_OBJECT_LOCK (mux);
+      mux->last_stop = GST_CLOCK_TIME_NONE;
+      GST_OBJECT_UNLOCK (mux);
+      break;
+    }
+    case GST_EVENT_SEGMENT:
+    {
+      GstRTPMuxPadPrivate *padpriv;
+
+      GST_OBJECT_LOCK (mux);
+      padpriv = gst_pad_get_element_private (pad);
+
+      if (padpriv) {
+        gst_event_copy_segment (event, &padpriv->segment);
+      }
+      GST_OBJECT_UNLOCK (mux);
+
+      if (is_pad) {
+        GstSegment new_segment;
+        gst_segment_init (&new_segment, GST_FORMAT_TIME);
+        gst_event_unref (event);
+        event = gst_event_new_segment (&new_segment);
+      }
+      break;
+    }
+    default:
+      break;
+  }
+
+  if (is_pad) {
+    return gst_pad_push_event (mux->srcpad, event);
+  } else {
+    gst_event_unref (event);
+    return TRUE;
+  }
+}
+
+static void
+gst_rtp_mux_ready_to_paused (GstRTPMux * rtp_mux)
+{
+
+  GST_OBJECT_LOCK (rtp_mux);
+
+  g_clear_object (&rtp_mux->last_pad);
+  rtp_mux->send_stream_start = TRUE;
+
+  if (rtp_mux->seqnum_offset == -1)
+    rtp_mux->seqnum_base = g_random_int_range (0, G_MAXUINT16);
+  else
+    rtp_mux->seqnum_base = rtp_mux->seqnum_offset;
+  rtp_mux->seqnum = rtp_mux->seqnum_base;
+
+  if (rtp_mux->ts_offset == -1)
+    rtp_mux->ts_base = g_random_int ();
+  else
+    rtp_mux->ts_base = rtp_mux->ts_offset;
+
+  rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
+
+  if (rtp_mux->ssrc_random) {
+    rtp_mux->have_ssrc = FALSE;
+  } else {
+    rtp_mux->current_ssrc = rtp_mux->ssrc;
+    rtp_mux->have_ssrc = TRUE;
+  }
+
+  GST_DEBUG_OBJECT (rtp_mux, "set timestamp-offset to %u", rtp_mux->ts_base);
+
+  GST_OBJECT_UNLOCK (rtp_mux);
+}
+
+static GstStateChangeReturn
+gst_rtp_mux_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRTPMux *rtp_mux;
+  GstStateChangeReturn ret;
+
+  rtp_mux = GST_RTP_MUX (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_rtp_mux_ready_to_paused (rtp_mux);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (gst_rtp_mux_parent_class)->change_state (element,
+      transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      g_clear_object (&rtp_mux->last_pad);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+gboolean
+gst_rtp_mux_plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_mux_debug, "rtpmux", 0, "rtp muxer");
+
+  return gst_element_register (plugin, "rtpmux", GST_RANK_NONE,
+      GST_TYPE_RTP_MUX);
+}
diff --git a/gst/rtpmanager/gstrtpmux.h b/gst/rtpmanager/gstrtpmux.h
new file mode 100644
index 0000000..3de9f41
--- /dev/null
+++ b/gst/rtpmanager/gstrtpmux.h
@@ -0,0 +1,98 @@
+/* RTP muxer element for GStreamer
+ *
+ * gstrtpmux.h:
+ *
+ * Copyright (C) <2007> Nokia Corporation.
+ *   Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2000,2005 Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MUX_H__
+#define __GST_RTP_MUX_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_MUX (gst_rtp_mux_get_type())
+#define GST_RTP_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MUX, GstRTPMux))
+#define GST_RTP_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MUX, GstRTPMuxClass))
+#define GST_RTP_MUX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_MUX, GstRTPMuxClass))
+#define GST_IS_RTP_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MUX))
+#define GST_IS_RTP_MUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MUX))
+typedef struct _GstRTPMux GstRTPMux;
+typedef struct _GstRTPMuxClass GstRTPMuxClass;
+
+
+typedef struct
+{
+  gboolean have_timestamp_offset;
+  guint timestamp_offset;
+
+  GstSegment segment;
+
+  gboolean priority;
+} GstRTPMuxPadPrivate;
+
+
+/**
+ * GstRTPMux:
+ *
+ * The opaque #GstRTPMux structure.
+ */
+struct _GstRTPMux
+{
+  GstElement element;
+
+  /* pad */
+  GstPad *srcpad;
+
+  guint32 ts_base;
+  guint16 seqnum_base;
+
+  gint32 ts_offset;
+  gint16 seqnum_offset;
+  guint16 seqnum;               /* protected by object lock */
+  guint ssrc;
+  guint current_ssrc;
+  gboolean have_ssrc;
+  gboolean ssrc_random;
+
+  GstPad *last_pad; /* protected by object lock */
+
+  GstClockTime last_stop;
+  gboolean send_stream_start;
+};
+
+struct _GstRTPMuxClass
+{
+  GstElementClass parent_class;
+
+  gboolean (*accept_buffer_locked) (GstRTPMux *rtp_mux,
+      GstRTPMuxPadPrivate * padpriv, GstRTPBuffer * buffer);
+
+  gboolean (*src_event) (GstRTPMux *rtp_mux, GstEvent *event);
+};
+
+
+GType gst_rtp_mux_get_type (void);
+gboolean gst_rtp_mux_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_MUX_H__ */
diff --git a/gst/rtpmanager/gstrtpptdemux.c b/gst/rtpmanager/gstrtpptdemux.c
new file mode 100644
index 0000000..9020a44
--- /dev/null
+++ b/gst/rtpmanager/gstrtpptdemux.c
@@ -0,0 +1,646 @@
+/* 
+ * RTP Demux element
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ * @author Kai Vehmanen <kai.vehmanen@nokia.com>
+ *
+ * Loosely based on GStreamer gstdecodebin
+ * Copyright (C) <2004> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpptdemux
+ *
+ * rtpptdemux acts as a demuxer for RTP packets based on the payload type of
+ * the packets. Its main purpose is to allow an application to easily receive
+ * and decode an RTP stream with multiple payload types.
+ * 
+ * For each payload type that is detected, a new pad will be created and the
+ * #GstRtpPtDemux::new-payload-type signal will be emitted. When the payload for
+ * the RTP stream changes, the #GstRtpPtDemux::payload-type-change signal will be
+ * emitted.
+ * 
+ * The element will try to set complete and unique application/x-rtp caps
+ * on the output pads based on the result of the #GstRtpPtDemux::request-pt-map
+ * signal.
+ * 
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 udpsrc caps="application/x-rtp" ! rtpptdemux ! fakesink
+ * ]| Takes an RTP stream and send the RTP packets with the first detected
+ * payload type to fakesink, discarding the other payload types.
+ * </refsect2>
+ */
+
+/*
+ * Contributors:
+ * Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>
+ */
+/*
+ * Status:
+ *  - works with the test_rtpdemux.c tool
+ *
+ * Check:
+ *  - is emitting a signal enough, or should we
+ *    use GstEvent to notify downstream elements
+ *    of the new packet... no?
+ *
+ * Notes:
+ *  - emits event both for new PTs, and whenever
+ *    a PT is changed
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpptdemux.h"
+
+/* generic templates */
+static GstStaticPadTemplate rtp_pt_demux_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static GstStaticPadTemplate rtp_pt_demux_src_template =
+GST_STATIC_PAD_TEMPLATE ("src_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("application/x-rtp, " "payload = (int) [ 0, 255 ]")
+    );
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_pt_demux_debug);
+#define GST_CAT_DEFAULT gst_rtp_pt_demux_debug
+
+/*
+ * Item for storing GstPad<->pt pairs.
+ */
+struct _GstRtpPtDemuxPad
+{
+  GstPad *pad;        /**< pointer to the actual pad */
+  gint pt;             /**< RTP payload-type attached to pad */
+  gboolean newcaps;
+};
+
+/* signals */
+enum
+{
+  SIGNAL_REQUEST_PT_MAP,
+  SIGNAL_NEW_PAYLOAD_TYPE,
+  SIGNAL_PAYLOAD_TYPE_CHANGE,
+  SIGNAL_CLEAR_PT_MAP,
+  LAST_SIGNAL
+};
+
+#define gst_rtp_pt_demux_parent_class parent_class
+G_DEFINE_TYPE (GstRtpPtDemux, gst_rtp_pt_demux, GST_TYPE_ELEMENT);
+
+static void gst_rtp_pt_demux_finalize (GObject * object);
+
+static void gst_rtp_pt_demux_release (GstRtpPtDemux * ptdemux);
+static gboolean gst_rtp_pt_demux_setup (GstRtpPtDemux * ptdemux);
+
+static gboolean gst_rtp_pt_demux_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static GstFlowReturn gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buf);
+static GstStateChangeReturn gst_rtp_pt_demux_change_state (GstElement * element,
+    GstStateChange transition);
+static void gst_rtp_pt_demux_clear_pt_map (GstRtpPtDemux * rtpdemux);
+
+static GstPad *find_pad_for_pt (GstRtpPtDemux * rtpdemux, guint8 pt);
+
+static gboolean gst_rtp_pt_demux_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+
+
+static guint gst_rtp_pt_demux_signals[LAST_SIGNAL] = { 0 };
+
+static void
+gst_rtp_pt_demux_class_init (GstRtpPtDemuxClass * klass)
+{
+  GObjectClass *gobject_klass;
+  GstElementClass *gstelement_klass;
+
+  gobject_klass = (GObjectClass *) klass;
+  gstelement_klass = (GstElementClass *) klass;
+
+  /**
+   * GstRtpPtDemux::request-pt-map:
+   * @demux: the object which received the signal
+   * @pt: the payload type
+   *
+   * Request the payload type as #GstCaps for @pt.
+   */
+  gst_rtp_pt_demux_signals[SIGNAL_REQUEST_PT_MAP] =
+      g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass, request_pt_map),
+      NULL, NULL, g_cclosure_marshal_generic, GST_TYPE_CAPS, 1, G_TYPE_UINT);
+
+  /**
+   * GstRtpPtDemux::new-payload-type:
+   * @demux: the object which received the signal
+   * @pt: the payload type
+   * @pad: the pad with the new payload
+   *
+   * Emited when a new payload type pad has been created in @demux.
+   */
+  gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE] =
+      g_signal_new ("new-payload-type", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass, new_payload_type),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      GST_TYPE_PAD);
+
+  /**
+   * GstRtpPtDemux::payload-type-change:
+   * @demux: the object which received the signal
+   * @pt: the new payload type
+   *
+   * Emited when the payload type changed.
+   */
+  gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE] =
+      g_signal_new ("payload-type-change", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass,
+          payload_type_change), NULL, NULL, g_cclosure_marshal_VOID__UINT,
+      G_TYPE_NONE, 1, G_TYPE_UINT);
+
+  /**
+   * GstRtpPtDemux::clear-pt-map:
+   * @demux: the object which received the signal
+   *
+   * The application can call this signal to instruct the element to discard the
+   * currently cached payload type map.
+   */
+  gst_rtp_pt_demux_signals[SIGNAL_CLEAR_PT_MAP] =
+      g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_ACTION | G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass,
+          clear_pt_map), NULL, NULL, g_cclosure_marshal_VOID__VOID,
+      G_TYPE_NONE, 0, G_TYPE_NONE);
+
+  gobject_klass->finalize = gst_rtp_pt_demux_finalize;
+
+  gstelement_klass->change_state =
+      GST_DEBUG_FUNCPTR (gst_rtp_pt_demux_change_state);
+
+  klass->clear_pt_map = GST_DEBUG_FUNCPTR (gst_rtp_pt_demux_clear_pt_map);
+
+  gst_element_class_add_static_pad_template (gstelement_klass,
+      &rtp_pt_demux_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_klass,
+      &rtp_pt_demux_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_klass, "RTP Demux",
+      "Demux/Network/RTP",
+      "Parses codec streams transmitted in the same RTP session",
+      "Kai Vehmanen <kai.vehmanen@nokia.com>");
+
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_pt_demux_debug,
+      "rtpptdemux", 0, "RTP codec demuxer");
+}
+
+static void
+gst_rtp_pt_demux_init (GstRtpPtDemux * ptdemux)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (ptdemux);
+
+  ptdemux->sink =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "sink"), "sink");
+  g_assert (ptdemux->sink != NULL);
+
+  gst_pad_set_chain_function (ptdemux->sink, gst_rtp_pt_demux_chain);
+  gst_pad_set_event_function (ptdemux->sink, gst_rtp_pt_demux_sink_event);
+
+  gst_element_add_pad (GST_ELEMENT (ptdemux), ptdemux->sink);
+}
+
+static void
+gst_rtp_pt_demux_finalize (GObject * object)
+{
+  gst_rtp_pt_demux_release (GST_RTP_PT_DEMUX (object));
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstCaps *
+gst_rtp_pt_demux_get_caps (GstRtpPtDemux * rtpdemux, guint pt)
+{
+  GstCaps *caps;
+  GValue ret = { 0 };
+  GValue args[2] = { {0}, {0} };
+
+  /* figure out the caps */
+  g_value_init (&args[0], GST_TYPE_ELEMENT);
+  g_value_set_object (&args[0], rtpdemux);
+  g_value_init (&args[1], G_TYPE_UINT);
+  g_value_set_uint (&args[1], pt);
+
+  g_value_init (&ret, GST_TYPE_CAPS);
+  g_value_set_boxed (&ret, NULL);
+
+  g_signal_emitv (args, gst_rtp_pt_demux_signals[SIGNAL_REQUEST_PT_MAP], 0,
+      &ret);
+
+  g_value_unset (&args[0]);
+  g_value_unset (&args[1]);
+  caps = g_value_dup_boxed (&ret);
+  g_value_unset (&ret);
+  if (caps == NULL) {
+    caps = gst_pad_get_current_caps (rtpdemux->sink);
+  }
+
+  GST_DEBUG ("pt %d, got caps %" GST_PTR_FORMAT, pt, caps);
+
+  return caps;
+}
+
+static void
+gst_rtp_pt_demux_clear_pt_map (GstRtpPtDemux * rtpdemux)
+{
+  GSList *walk;
+
+  GST_OBJECT_LOCK (rtpdemux);
+  GST_DEBUG ("clearing pt map");
+  for (walk = rtpdemux->srcpads; walk; walk = g_slist_next (walk)) {
+    GstRtpPtDemuxPad *pad = walk->data;
+
+    pad->newcaps = TRUE;
+  }
+  GST_OBJECT_UNLOCK (rtpdemux);
+}
+
+static gboolean
+need_caps_for_pt (GstRtpPtDemux * rtpdemux, guint8 pt)
+{
+  GSList *walk;
+  gboolean ret = FALSE;
+
+  GST_OBJECT_LOCK (rtpdemux);
+  for (walk = rtpdemux->srcpads; walk; walk = g_slist_next (walk)) {
+    GstRtpPtDemuxPad *pad = walk->data;
+
+    if (pad->pt == pt) {
+      ret = pad->newcaps;
+    }
+  }
+  GST_OBJECT_UNLOCK (rtpdemux);
+
+  return ret;
+}
+
+
+static void
+clear_newcaps_for_pt (GstRtpPtDemux * rtpdemux, guint8 pt)
+{
+  GSList *walk;
+
+  GST_OBJECT_LOCK (rtpdemux);
+  for (walk = rtpdemux->srcpads; walk; walk = g_slist_next (walk)) {
+    GstRtpPtDemuxPad *pad = walk->data;
+
+    if (pad->pt == pt) {
+      pad->newcaps = FALSE;
+      break;
+    }
+  }
+  GST_OBJECT_UNLOCK (rtpdemux);
+}
+
+static gboolean
+forward_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
+{
+  GstPad *srcpad = GST_PAD_CAST (user_data);
+
+  /* Stream start and caps have already been pushed */
+  if (GST_EVENT_TYPE (*event) >= GST_EVENT_SEGMENT)
+    gst_pad_push_event (srcpad, gst_event_ref (*event));
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstRtpPtDemux *rtpdemux;
+  guint8 pt;
+  GstPad *srcpad;
+  GstCaps *caps;
+  GstRTPBuffer rtp = { NULL };
+
+  rtpdemux = GST_RTP_PT_DEMUX (parent);
+
+  if (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp))
+    goto invalid_buffer;
+
+  pt = gst_rtp_buffer_get_payload_type (&rtp);
+  gst_rtp_buffer_unmap (&rtp);
+
+  GST_DEBUG_OBJECT (rtpdemux, "received buffer for pt %d", pt);
+
+  srcpad = find_pad_for_pt (rtpdemux, pt);
+  if (srcpad == NULL) {
+    /* new PT, create a src pad */
+    GstRtpPtDemuxPad *rtpdemuxpad;
+    GstElementClass *klass;
+    GstPadTemplate *templ;
+    gchar *padname;
+
+    caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt);
+    if (!caps)
+      goto no_caps;
+
+    klass = GST_ELEMENT_GET_CLASS (rtpdemux);
+    templ = gst_element_class_get_pad_template (klass, "src_%u");
+    padname = g_strdup_printf ("src_%u", pt);
+    srcpad = gst_pad_new_from_template (templ, padname);
+    gst_pad_use_fixed_caps (srcpad);
+    g_free (padname);
+    gst_pad_set_event_function (srcpad, gst_rtp_pt_demux_src_event);
+
+    GST_DEBUG ("Adding pt=%d to the list.", pt);
+    rtpdemuxpad = g_slice_new0 (GstRtpPtDemuxPad);
+    rtpdemuxpad->pt = pt;
+    rtpdemuxpad->newcaps = FALSE;
+    rtpdemuxpad->pad = srcpad;
+    gst_object_ref (srcpad);
+    GST_OBJECT_LOCK (rtpdemux);
+    rtpdemux->srcpads = g_slist_append (rtpdemux->srcpads, rtpdemuxpad);
+    GST_OBJECT_UNLOCK (rtpdemux);
+
+    gst_pad_set_active (srcpad, TRUE);
+
+
+    /* First push the stream-start event, it must always come first */
+    gst_pad_push_event (srcpad,
+        gst_pad_get_sticky_event (rtpdemux->sink, GST_EVENT_STREAM_START, 0));
+
+    /* Then caps event is sent */
+    caps = gst_caps_make_writable (caps);
+    gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
+    gst_pad_set_caps (srcpad, caps);
+    gst_caps_unref (caps);
+
+    /* First sticky events on sink pad are forwarded to the new src pad */
+    gst_pad_sticky_events_foreach (rtpdemux->sink, forward_sticky_events,
+        srcpad);
+
+    gst_element_add_pad (GST_ELEMENT_CAST (rtpdemux), srcpad);
+
+    GST_DEBUG ("emitting new-payload-type for pt %d", pt);
+    g_signal_emit (G_OBJECT (rtpdemux),
+        gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE], 0, pt, srcpad);
+  }
+
+  if (pt != rtpdemux->last_pt) {
+    gint emit_pt = pt;
+
+    /* our own signal with an extra flag that this is the only pad */
+    rtpdemux->last_pt = pt;
+    GST_DEBUG ("emitting payload-type-changed for pt %d", emit_pt);
+    g_signal_emit (G_OBJECT (rtpdemux),
+        gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE], 0, emit_pt);
+  }
+
+  while (need_caps_for_pt (rtpdemux, pt)) {
+    GST_DEBUG ("need new caps for %d", pt);
+    caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt);
+    if (!caps)
+      goto no_caps;
+
+    clear_newcaps_for_pt (rtpdemux, pt);
+
+    caps = gst_caps_make_writable (caps);
+    gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
+    gst_pad_set_caps (srcpad, caps);
+    gst_caps_unref (caps);
+  }
+
+  /* push to srcpad */
+  ret = gst_pad_push (srcpad, buf);
+
+  gst_object_unref (srcpad);
+
+  return ret;
+
+  /* ERRORS */
+invalid_buffer:
+  {
+    /* this should not be fatal */
+    GST_ELEMENT_WARNING (rtpdemux, STREAM, DEMUX, (NULL),
+        ("Dropping invalid RTP payload"));
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+no_caps:
+  {
+    GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL),
+        ("Could not get caps for payload"));
+    gst_buffer_unref (buf);
+    if (srcpad)
+      gst_object_unref (srcpad);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstPad *
+find_pad_for_pt (GstRtpPtDemux * rtpdemux, guint8 pt)
+{
+  GstPad *respad = NULL;
+  GSList *walk;
+
+  GST_OBJECT_LOCK (rtpdemux);
+  for (walk = rtpdemux->srcpads; walk; walk = g_slist_next (walk)) {
+    GstRtpPtDemuxPad *pad = walk->data;
+
+    if (pad->pt == pt) {
+      respad = gst_object_ref (pad->pad);
+      break;
+    }
+  }
+  GST_OBJECT_UNLOCK (rtpdemux);
+
+  return respad;
+}
+
+static gboolean
+gst_rtp_pt_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstRtpPtDemux *rtpdemux;
+  gboolean res = FALSE;
+
+  rtpdemux = GST_RTP_PT_DEMUX (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      gst_rtp_pt_demux_clear_pt_map (rtpdemux);
+      /* don't forward the event, we cleared the ptmap and on the next buffer we
+       * will add the pt to the caps and push a new caps event */
+      gst_event_unref (event);
+      res = TRUE;
+      break;
+    }
+    case GST_EVENT_CUSTOM_DOWNSTREAM:
+    {
+      const GstStructure *s;
+
+      s = gst_event_get_structure (event);
+
+      if (gst_structure_has_name (s, "GstRTPPacketLost")) {
+        GstPad *srcpad = find_pad_for_pt (rtpdemux, rtpdemux->last_pt);
+
+        if (srcpad) {
+          res = gst_pad_push_event (srcpad, event);
+          gst_object_unref (srcpad);
+        } else {
+          gst_event_unref (event);
+        }
+
+      } else {
+        res = gst_pad_event_default (pad, parent, event);
+      }
+      break;
+    }
+    default:
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return res;
+}
+
+
+static gboolean
+gst_rtp_pt_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstRtpPtDemux *demux;
+  const GstStructure *s;
+
+  demux = GST_RTP_PT_DEMUX (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CUSTOM_UPSTREAM:
+    case GST_EVENT_CUSTOM_BOTH:
+    case GST_EVENT_CUSTOM_BOTH_OOB:
+      s = gst_event_get_structure (event);
+      if (s && !gst_structure_has_field (s, "payload")) {
+        GSList *walk;
+
+        GST_OBJECT_LOCK (demux);
+        for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
+          GstRtpPtDemuxPad *dpad = (GstRtpPtDemuxPad *) walk->data;
+
+          if (dpad->pad == pad) {
+            GstStructure *ws;
+
+            event =
+                GST_EVENT_CAST (gst_mini_object_make_writable
+                (GST_MINI_OBJECT_CAST (event)));
+            ws = gst_event_writable_structure (event);
+            gst_structure_set (ws, "payload", G_TYPE_UINT, dpad->pt, NULL);
+            break;
+          }
+        }
+        GST_OBJECT_UNLOCK (demux);
+      }
+      break;
+    default:
+      break;
+  }
+
+  return gst_pad_event_default (pad, parent, event);
+}
+
+/*
+ * Reserves resources for the object.
+ */
+static gboolean
+gst_rtp_pt_demux_setup (GstRtpPtDemux * ptdemux)
+{
+  ptdemux->srcpads = NULL;
+  ptdemux->last_pt = 0xFFFF;
+
+  return TRUE;
+}
+
+/*
+ * Free resources for the object.
+ */
+static void
+gst_rtp_pt_demux_release (GstRtpPtDemux * ptdemux)
+{
+  GSList *tmppads;
+  GSList *walk;
+
+  GST_OBJECT_LOCK (ptdemux);
+  tmppads = ptdemux->srcpads;
+  ptdemux->srcpads = NULL;
+  GST_OBJECT_UNLOCK (ptdemux);
+
+  for (walk = tmppads; walk; walk = g_slist_next (walk)) {
+    GstRtpPtDemuxPad *pad = walk->data;
+
+    gst_pad_set_active (pad->pad, FALSE);
+    gst_element_remove_pad (GST_ELEMENT_CAST (ptdemux), pad->pad);
+    g_slice_free (GstRtpPtDemuxPad, pad);
+  }
+  g_slist_free (tmppads);
+}
+
+static GstStateChangeReturn
+gst_rtp_pt_demux_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstRtpPtDemux *ptdemux;
+
+  ptdemux = GST_RTP_PT_DEMUX (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      if (gst_rtp_pt_demux_setup (ptdemux) != TRUE)
+        ret = GST_STATE_CHANGE_FAILURE;
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      gst_rtp_pt_demux_release (ptdemux);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
diff --git a/gst/rtpmanager/gstrtpptdemux.h b/gst/rtpmanager/gstrtpptdemux.h
new file mode 100644
index 0000000..aa1bb7f
--- /dev/null
+++ b/gst/rtpmanager/gstrtpptdemux.h
@@ -0,0 +1,62 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_PT_DEMUX_H__
+#define __GST_RTP_PT_DEMUX_H__
+
+#include <gst/gst.h>
+
+#define GST_TYPE_RTP_PT_DEMUX            (gst_rtp_pt_demux_get_type())
+#define GST_RTP_PT_DEMUX(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_PT_DEMUX,GstRtpPtDemux))
+#define GST_RTP_PT_DEMUX_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_PT_DEMUX,GstRtpPtDemuxClass))
+#define GST_IS_RTP_PT_DEMUX(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_PT_DEMUX))
+#define GST_IS_RTP_PT_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_PT_DEMUX))
+
+typedef struct _GstRtpPtDemux GstRtpPtDemux;
+typedef struct _GstRtpPtDemuxClass GstRtpPtDemuxClass;
+typedef struct _GstRtpPtDemuxPad GstRtpPtDemuxPad;
+
+struct _GstRtpPtDemux
+{
+  GstElement parent;  /**< parent class */
+
+  GstPad *sink;       /**< the sink pad */
+  guint16 last_pt;    /**< pt of the last packet 0xFFFF if none */
+  GSList *srcpads;    /**< a linked list of GstRtpPtDemuxPad objects */
+};
+
+struct _GstRtpPtDemuxClass
+{
+  GstElementClass parent_class;
+
+  /* get the caps for pt */
+  GstCaps* (*request_pt_map)      (GstRtpPtDemux *demux, guint pt);
+
+  /* signal emmited when a new PT is found from the incoming stream */
+  void     (*new_payload_type)    (GstRtpPtDemux *demux, guint pt, GstPad * pad);
+
+  /* signal emitted when the payload type changes */
+  void     (*payload_type_change) (GstRtpPtDemux *demux, guint pt);
+
+  void     (*clear_pt_map)        (GstRtpPtDemux *demux);
+};
+
+GType gst_rtp_pt_demux_get_type (void);
+
+#endif /* __GST_RTP_PT_DEMUX_H__ */
diff --git a/gst/rtpmanager/gstrtprtxqueue.c b/gst/rtpmanager/gstrtprtxqueue.c
new file mode 100644
index 0000000..a0d6cbe
--- /dev/null
+++ b/gst/rtpmanager/gstrtprtxqueue.c
@@ -0,0 +1,521 @@
+/* RTP Retransmission queue element for GStreamer
+ *
+ * gstrtprtxqueue.c:
+ *
+ * Copyright (C) 2013 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtprtxqueue
+ *
+ * rtprtxqueue maintains a queue of transmitted RTP packets, up to a
+ * configurable limit (see #GstRTPRtxQueue::max-size-time,
+ * #GstRTPRtxQueue::max-size-packets), and retransmits them upon request
+ * from the downstream rtpsession (GstRTPRetransmissionRequest event).
+ *
+ * This element is similar to rtprtxsend, but it has differences:
+ * - Retransmission from rtprtxqueue is not RFC 4588 compliant. The
+ * retransmitted packets have the same ssrc and payload type as the original
+ * stream.
+ * - As a side-effect of the above, rtprtxqueue does not require the use of
+ * rtprtxreceive on the receiving end. rtpjitterbuffer alone is able to
+ * reconstruct the stream.
+ * - Retransmission from rtprtxqueue happens as soon as the next regular flow
+ * packet is chained, while rtprtxsend retransmits as soon as the retransmission
+ * event is received, using a helper thread.
+ * - rtprtxqueue can be used with rtpbin without the need of hooking to its
+ * #GstRtpBin::request-aux-sender signal, which means it can be used with
+ * rtpbin using gst-launch.
+ *
+ * See also #GstRtpRtxSend, #GstRtpRtxReceive
+ *
+ * # Example pipelines
+ * |[
+ * gst-launch-1.0 rtpbin name=b rtp-profile=avpf \
+ *    audiotestsrc is-live=true ! opusenc ! rtpopuspay pt=96 ! rtprtxqueue ! b.send_rtp_sink_0 \
+ *    b.send_rtp_src_0 ! identity drop-probability=0.01 ! udpsink host="127.0.0.1" port=5000 \
+ *    udpsrc port=5001 ! b.recv_rtcp_sink_0 \
+ *    b.send_rtcp_src_0 ! udpsink host="127.0.0.1" port=5002 sync=false async=false
+ * ]| Sender pipeline
+ * |[
+ * gst-launch-1.0 rtpbin name=b rtp-profile=avpf do-retransmission=true \
+ *    udpsrc port=5000 caps="application/x-rtp,media=(string)audio,clock-rate=(int)48000,encoding-name=(string)OPUS,payload=(int)96" ! \
+ *        b.recv_rtp_sink_0 \
+ *    b. ! rtpopusdepay ! opusdec ! audioconvert ! audioresample ! autoaudiosink \
+ *    udpsrc port=5002 ! b.recv_rtcp_sink_0 \
+ *    b.send_rtcp_src_0 ! udpsink host="127.0.0.1" port=5001 sync=false async=false
+ * ]| Receiver pipeline
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <string.h>
+
+#include "gstrtprtxqueue.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_rtx_queue_debug);
+#define GST_CAT_DEFAULT gst_rtp_rtx_queue_debug
+
+#define DEFAULT_MAX_SIZE_TIME    0
+#define DEFAULT_MAX_SIZE_PACKETS 100
+
+enum
+{
+  PROP_0,
+  PROP_MAX_SIZE_TIME,
+  PROP_MAX_SIZE_PACKETS,
+  PROP_REQUESTS,
+  PROP_FULFILLED_REQUESTS,
+};
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static gboolean gst_rtp_rtx_queue_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static gboolean gst_rtp_rtx_queue_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static GstFlowReturn gst_rtp_rtx_queue_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer);
+static GstFlowReturn gst_rtp_rtx_queue_chain_list (GstPad * pad,
+    GstObject * parent, GstBufferList * list);
+
+static GstStateChangeReturn gst_rtp_rtx_queue_change_state (GstElement *
+    element, GstStateChange transition);
+
+static void gst_rtp_rtx_queue_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_rtx_queue_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_rtp_rtx_queue_finalize (GObject * object);
+
+G_DEFINE_TYPE (GstRTPRtxQueue, gst_rtp_rtx_queue, GST_TYPE_ELEMENT);
+
+static void
+gst_rtp_rtx_queue_class_init (GstRTPRtxQueueClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->get_property = gst_rtp_rtx_queue_get_property;
+  gobject_class->set_property = gst_rtp_rtx_queue_set_property;
+  gobject_class->finalize = gst_rtp_rtx_queue_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_MAX_SIZE_TIME,
+      g_param_spec_uint ("max-size-time", "Max Size Times",
+          "Amount of ms to queue (0 = unlimited)", 0, G_MAXUINT,
+          DEFAULT_MAX_SIZE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_SIZE_PACKETS,
+      g_param_spec_uint ("max-size-packets", "Max Size Packets",
+          "Amount of packets to queue (0 = unlimited)", 0, G_MAXUINT,
+          DEFAULT_MAX_SIZE_PACKETS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_REQUESTS,
+      g_param_spec_uint ("requests", "Requests",
+          "Total number of retransmission requests", 0, G_MAXUINT,
+          0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_FULFILLED_REQUESTS,
+      g_param_spec_uint ("fulfilled-requests", "Fulfilled Requests",
+          "Number of fulfilled retransmission requests", 0, G_MAXUINT,
+          0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Retransmission Queue", "Codec",
+      "Keep RTP packets in a queue for retransmission",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_rtp_rtx_queue_change_state);
+}
+
+static void
+gst_rtp_rtx_queue_reset (GstRTPRtxQueue * rtx, gboolean full)
+{
+  g_mutex_lock (&rtx->lock);
+  g_queue_foreach (rtx->queue, (GFunc) gst_buffer_unref, NULL);
+  g_queue_clear (rtx->queue);
+  g_list_foreach (rtx->pending, (GFunc) gst_buffer_unref, NULL);
+  g_list_free (rtx->pending);
+  rtx->pending = NULL;
+  rtx->n_requests = 0;
+  rtx->n_fulfilled_requests = 0;
+  g_mutex_unlock (&rtx->lock);
+}
+
+static void
+gst_rtp_rtx_queue_finalize (GObject * object)
+{
+  GstRTPRtxQueue *rtx = GST_RTP_RTX_QUEUE (object);
+
+  gst_rtp_rtx_queue_reset (rtx, TRUE);
+  g_queue_free (rtx->queue);
+  g_mutex_clear (&rtx->lock);
+
+  G_OBJECT_CLASS (gst_rtp_rtx_queue_parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_rtx_queue_init (GstRTPRtxQueue * rtx)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (rtx);
+
+  rtx->srcpad =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "src"), "src");
+  GST_PAD_SET_PROXY_CAPS (rtx->srcpad);
+  GST_PAD_SET_PROXY_ALLOCATION (rtx->srcpad);
+  gst_pad_set_event_function (rtx->srcpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_rtx_queue_src_event));
+  gst_element_add_pad (GST_ELEMENT (rtx), rtx->srcpad);
+
+  rtx->sinkpad =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "sink"), "sink");
+  GST_PAD_SET_PROXY_CAPS (rtx->sinkpad);
+  GST_PAD_SET_PROXY_ALLOCATION (rtx->sinkpad);
+  gst_pad_set_event_function (rtx->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_rtx_queue_sink_event));
+  gst_pad_set_chain_function (rtx->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_rtx_queue_chain));
+  gst_pad_set_chain_list_function (rtx->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_rtx_queue_chain_list));
+  gst_element_add_pad (GST_ELEMENT (rtx), rtx->sinkpad);
+
+  rtx->queue = g_queue_new ();
+  g_mutex_init (&rtx->lock);
+
+  rtx->max_size_time = DEFAULT_MAX_SIZE_TIME;
+  rtx->max_size_packets = DEFAULT_MAX_SIZE_PACKETS;
+}
+
+typedef struct
+{
+  GstRTPRtxQueue *rtx;
+  guint seqnum;
+  gboolean found;
+} RTXData;
+
+static void
+push_seqnum (GstBuffer * buffer, RTXData * data)
+{
+  GstRTPRtxQueue *rtx = data->rtx;
+  GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
+  guint16 seqnum;
+
+  if (data->found)
+    return;
+
+  if (!GST_IS_BUFFER (buffer) ||
+      !gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtpbuffer))
+    return;
+
+  seqnum = gst_rtp_buffer_get_seq (&rtpbuffer);
+  gst_rtp_buffer_unmap (&rtpbuffer);
+
+  if (seqnum == data->seqnum) {
+    data->found = TRUE;
+    GST_DEBUG_OBJECT (rtx, "found %d", seqnum);
+    rtx->pending = g_list_prepend (rtx->pending, gst_buffer_ref (buffer));
+  }
+}
+
+static gboolean
+gst_rtp_rtx_queue_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstRTPRtxQueue *rtx = GST_RTP_RTX_QUEUE (parent);
+  gboolean res;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CUSTOM_UPSTREAM:
+    {
+      const GstStructure *s;
+
+      s = gst_event_get_structure (event);
+      if (gst_structure_has_name (s, "GstRTPRetransmissionRequest")) {
+        guint seqnum;
+        RTXData data;
+
+        if (!gst_structure_get_uint (s, "seqnum", &seqnum))
+          seqnum = -1;
+
+        GST_DEBUG_OBJECT (rtx, "request %d", seqnum);
+
+        g_mutex_lock (&rtx->lock);
+        data.rtx = rtx;
+        data.seqnum = seqnum;
+        data.found = FALSE;
+        rtx->n_requests += 1;
+        g_queue_foreach (rtx->queue, (GFunc) push_seqnum, &data);
+        g_mutex_unlock (&rtx->lock);
+
+        gst_event_unref (event);
+        res = TRUE;
+      } else {
+        res = gst_pad_event_default (pad, parent, event);
+      }
+      break;
+    }
+    default:
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+  return res;
+}
+
+static gboolean
+gst_rtp_rtx_queue_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstRTPRtxQueue *rtx = GST_RTP_RTX_QUEUE (parent);
+  gboolean res;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEGMENT:
+    {
+      g_mutex_lock (&rtx->lock);
+      gst_event_copy_segment (event, &rtx->head_segment);
+      g_queue_push_head (rtx->queue, gst_event_ref (event));
+      g_mutex_unlock (&rtx->lock);
+      /* fall through */
+    }
+    default:
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+  return res;
+}
+
+static void
+do_push (GstBuffer * buffer, GstRTPRtxQueue * rtx)
+{
+  rtx->n_fulfilled_requests += 1;
+  gst_pad_push (rtx->srcpad, buffer);
+}
+
+static guint32
+get_ts_diff (GstRTPRtxQueue * rtx)
+{
+  GstClockTime high_ts, low_ts;
+  GstClockTimeDiff result;
+  GstBuffer *high_buf, *low_buf;
+
+  high_buf = g_queue_peek_head (rtx->queue);
+
+  while (GST_IS_EVENT ((low_buf = g_queue_peek_tail (rtx->queue)))) {
+    GstEvent *event = g_queue_pop_tail (rtx->queue);
+    gst_event_copy_segment (event, &rtx->tail_segment);
+    gst_event_unref (event);
+  }
+
+  if (!high_buf || !low_buf || high_buf == low_buf)
+    return 0;
+
+  high_ts = GST_BUFFER_TIMESTAMP (high_buf);
+  low_ts = GST_BUFFER_TIMESTAMP (low_buf);
+
+  high_ts = gst_segment_to_running_time (&rtx->head_segment, GST_FORMAT_TIME,
+      high_ts);
+  low_ts = gst_segment_to_running_time (&rtx->tail_segment, GST_FORMAT_TIME,
+      low_ts);
+
+  result = high_ts - low_ts;
+
+  /* return value in ms instead of ns */
+  return (guint32) gst_util_uint64_scale_int (result, 1, GST_MSECOND);
+}
+
+/* Must be called with rtx->lock */
+static void
+shrink_queue (GstRTPRtxQueue * rtx)
+{
+  if (rtx->max_size_packets) {
+    while (g_queue_get_length (rtx->queue) > rtx->max_size_packets)
+      gst_buffer_unref (g_queue_pop_tail (rtx->queue));
+  }
+  if (rtx->max_size_time) {
+    while (get_ts_diff (rtx) > rtx->max_size_time)
+      gst_buffer_unref (g_queue_pop_tail (rtx->queue));
+  }
+}
+
+static GstFlowReturn
+gst_rtp_rtx_queue_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstRTPRtxQueue *rtx;
+  GstFlowReturn ret;
+  GList *pending;
+
+  rtx = GST_RTP_RTX_QUEUE (parent);
+
+  g_mutex_lock (&rtx->lock);
+  g_queue_push_head (rtx->queue, gst_buffer_ref (buffer));
+  shrink_queue (rtx);
+
+  pending = rtx->pending;
+  rtx->pending = NULL;
+  g_mutex_unlock (&rtx->lock);
+
+  pending = g_list_reverse (pending);
+  g_list_foreach (pending, (GFunc) do_push, rtx);
+  g_list_free (pending);
+
+  ret = gst_pad_push (rtx->srcpad, buffer);
+
+  return ret;
+}
+
+static gboolean
+push_to_queue (GstBuffer ** buffer, guint idx, gpointer user_data)
+{
+  GQueue *queue = user_data;
+
+  g_queue_push_head (queue, gst_buffer_ref (*buffer));
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_rtp_rtx_queue_chain_list (GstPad * pad, GstObject * parent,
+    GstBufferList * list)
+{
+  GstRTPRtxQueue *rtx;
+  GstFlowReturn ret;
+  GList *pending;
+
+  rtx = GST_RTP_RTX_QUEUE (parent);
+
+  g_mutex_lock (&rtx->lock);
+  gst_buffer_list_foreach (list, push_to_queue, rtx->queue);
+  shrink_queue (rtx);
+
+  pending = rtx->pending;
+  rtx->pending = NULL;
+  g_mutex_unlock (&rtx->lock);
+
+  pending = g_list_reverse (pending);
+  g_list_foreach (pending, (GFunc) do_push, rtx);
+  g_list_free (pending);
+
+  ret = gst_pad_push_list (rtx->srcpad, list);
+
+  return ret;
+}
+
+static void
+gst_rtp_rtx_queue_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstRTPRtxQueue *rtx = GST_RTP_RTX_QUEUE (object);
+
+  switch (prop_id) {
+    case PROP_MAX_SIZE_TIME:
+      g_value_set_uint (value, rtx->max_size_time);
+      break;
+    case PROP_MAX_SIZE_PACKETS:
+      g_value_set_uint (value, rtx->max_size_packets);
+      break;
+    case PROP_REQUESTS:
+      g_value_set_uint (value, rtx->n_requests);
+      break;
+    case PROP_FULFILLED_REQUESTS:
+      g_value_set_uint (value, rtx->n_fulfilled_requests);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_rtx_queue_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstRTPRtxQueue *rtx = GST_RTP_RTX_QUEUE (object);
+
+  switch (prop_id) {
+    case PROP_MAX_SIZE_TIME:
+      rtx->max_size_time = g_value_get_uint (value);
+      break;
+    case PROP_MAX_SIZE_PACKETS:
+      rtx->max_size_packets = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_rtx_queue_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstRTPRtxQueue *rtx;
+
+  rtx = GST_RTP_RTX_QUEUE (element);
+
+  switch (transition) {
+    default:
+      break;
+  }
+
+  ret =
+      GST_ELEMENT_CLASS (gst_rtp_rtx_queue_parent_class)->change_state (element,
+      transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_rtx_queue_reset (rtx, TRUE);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+gboolean
+gst_rtp_rtx_queue_plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_rtx_queue_debug, "rtprtxqueue", 0,
+      "rtp retransmission queue");
+
+  return gst_element_register (plugin, "rtprtxqueue", GST_RANK_NONE,
+      GST_TYPE_RTP_RTX_QUEUE);
+}
diff --git a/gst/rtpmanager/gstrtprtxqueue.h b/gst/rtpmanager/gstrtprtxqueue.h
new file mode 100644
index 0000000..bee8d44
--- /dev/null
+++ b/gst/rtpmanager/gstrtprtxqueue.h
@@ -0,0 +1,80 @@
+/* RTP muxer element for GStreamer
+ *
+ * gstrtpmux.h:
+ *
+ * Copyright (C) <2007> Nokia Corporation.
+ *   Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2000,2005 Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_RTX_QUEUE_H__
+#define __GST_RTP_RTX_QUEUE_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_RTX_QUEUE (gst_rtp_rtx_queue_get_type())
+#define GST_RTP_RTX_QUEUE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_RTX_QUEUE, GstRTPRtxQueue))
+#define GST_RTP_RTX_QUEUE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_RTX_QUEUE, GstRTPRtxQueueClass))
+#define GST_RTP_RTX_QUEUE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_RTX_QUEUE, GstRTPRtxQueueClass))
+#define GST_IS_RTP_RTX_QUEUE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_RTX_QUEUE))
+#define GST_IS_RTP_RTX_QUEUE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_RTX_QUEUE))
+typedef struct _GstRTPRtxQueue GstRTPRtxQueue;
+typedef struct _GstRTPRtxQueueClass GstRTPRtxQueueClass;
+
+/**
+ * GstRTPRtxQueue:
+ *
+ * The opaque #GstRTPRtxQueue structure.
+ */
+struct _GstRTPRtxQueue
+{
+  GstElement element;
+
+  /* pad */
+  GstPad *sinkpad;
+  GstPad *srcpad;
+
+  GMutex lock;
+  GQueue *queue;
+  GList *pending;
+
+  guint max_size_time;
+  guint max_size_packets;
+
+  GstSegment head_segment;
+  GstSegment tail_segment;
+
+  /* Statistics */
+  guint n_requests;
+  guint n_fulfilled_requests;
+};
+
+struct _GstRTPRtxQueueClass
+{
+  GstElementClass parent_class;
+};
+
+
+GType gst_rtp_rtx_queue_get_type (void);
+gboolean gst_rtp_rtx_queue_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_RTX_QUEUE_H__ */
diff --git a/gst/rtpmanager/gstrtprtxreceive.c b/gst/rtpmanager/gstrtprtxreceive.c
new file mode 100644
index 0000000..9a8a666
--- /dev/null
+++ b/gst/rtpmanager/gstrtprtxreceive.c
@@ -0,0 +1,791 @@
+/* RTP Retransmission receiver element for GStreamer
+ *
+ * gstrtprtxreceive.c:
+ *
+ * Copyright (C) 2013 Collabora Ltd.
+ *   @author Julien Isorce <julien.isorce@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtprtxreceive
+ * @see_also: rtprtxsend, rtpsession, rtpjitterbuffer
+ *
+ * rtprtxreceive listens to the retransmission events from the
+ * downstream rtpjitterbuffer and remembers the SSRC (ssrc1) of the stream and
+ * the sequence number that was requested. When it receives a packet with
+ * a sequence number equal to one of the ones stored and with a different SSRC,
+ * it identifies the new SSRC (ssrc2) as the retransmission stream of ssrc1.
+ * From this point on, it replaces ssrc2 with ssrc1 in all packets of the
+ * ssrc2 stream and flags them as retransmissions, so that rtpjitterbuffer
+ * can reconstruct the original stream.
+ *
+ * This algorithm is implemented as specified in RFC 4588.
+ *
+ * This element is meant to be used with rtprtxsend on the sender side.
+ * See #GstRtpRtxSend
+ *
+ * Below you can see some examples that illustrate how rtprtxreceive and
+ * rtprtxsend fit among the other rtp elements and how they work internally.
+ * Normally, hoewever, you should avoid using such pipelines and use
+ * rtpbin instead, with its #GstRtpBin::request-aux-sender and
+ * #GstRtpBin::request-aux-receiver signals. See #GstRtpBin.
+ *
+ * # Example pipelines
+ * |[
+ * gst-launch-1.0 rtpsession name=rtpsession rtp-profile=avpf \
+ *     audiotestsrc is-live=true ! opusenc ! rtpopuspay pt=96 ! \
+ *         rtprtxsend payload-type-map="application/x-rtp-pt-map,96=(uint)97" ! \
+ *         rtpsession.send_rtp_sink \
+ *     rtpsession.send_rtp_src ! identity drop-probability=0.01 ! \
+ *         udpsink host="127.0.0.1" port=5000 \
+ *     udpsrc port=5001 ! rtpsession.recv_rtcp_sink \
+ *     rtpsession.send_rtcp_src ! udpsink host="127.0.0.1" port=5002 \
+ *         sync=false async=false
+ * ]| Send audio stream through port 5000 (5001 and 5002 are just the rtcp
+ * link with the receiver)
+ * |[
+ * gst-launch-1.0 rtpsession name=rtpsession rtp-profile=avpf \
+ *     udpsrc port=5000 caps="application/x-rtp,media=(string)audio,clock-rate=(int)48000,encoding-name=(string)OPUS,payload=(int)96" ! \
+ *         rtpsession.recv_rtp_sink \
+ *     rtpsession.recv_rtp_src ! \
+ *         rtprtxreceive payload-type-map="application/x-rtp-pt-map,96=(uint)97" ! \
+ *         rtpssrcdemux ! rtpjitterbuffer do-retransmission=true ! \
+ *         rtpopusdepay ! opusdec ! audioconvert ! audioresample ! autoaudiosink \
+ *     rtpsession.send_rtcp_src ! \
+ *         udpsink host="127.0.0.1" port=5001 sync=false async=false \
+ *     udpsrc port=5002 ! rtpsession.recv_rtcp_sink
+ * ]| Receive audio stream from port 5000 (5001 and 5002 are just the rtcp
+ * link with the sender)
+ *
+ * In this example we can see a simple streaming of an OPUS stream with some
+ * of the packets being artificially dropped by the identity element.
+ * Thanks to retransmission, you should still hear a clear sound when setting
+ * drop-probability to something greater than 0.
+ *
+ * Internally, the rtpjitterbuffer will generate a custom upstream event,
+ * GstRTPRetransmissionRequest, when it detects that one packet is missing.
+ * Then this request is translated to a FB NACK in the rtcp link by rtpsession.
+ * Finally the rtpsession of the sender side will re-convert it in a
+ * GstRTPRetransmissionRequest that will be handled by rtprtxsend. rtprtxsend
+ * will then re-send the missing packet with a new srrc and a different payload
+ * type (here, 97), but with the same original sequence number. On the receiver
+ * side, rtprtxreceive will associate this new stream with the original and
+ * forward the retransmission packets to rtpjitterbuffer with the original
+ * ssrc and payload type.
+ *
+ * |[
+ * gst-launch-1.0 rtpsession name=rtpsession rtp-profile=avpf \
+ *     audiotestsrc is-live=true ! opusenc ! rtpopuspay pt=97 seqnum-offset=1 ! \
+ *         rtprtxsend payload-type-map="application/x-rtp-pt-map,97=(uint)99" ! \
+ *         funnel name=f ! rtpsession.send_rtp_sink \
+ *     audiotestsrc freq=660.0 is-live=true ! opusenc ! \
+ *         rtpopuspay pt=97 seqnum-offset=100 ! \
+ *         rtprtxsend payload-type-map="application/x-rtp-pt-map,97=(uint)99" ! \
+ *         f. \
+ *     rtpsession.send_rtp_src ! identity drop-probability=0.01 ! \
+ *         udpsink host="127.0.0.1" port=5000 \
+ *     udpsrc port=5001 ! rtpsession.recv_rtcp_sink \
+ *     rtpsession.send_rtcp_src ! udpsink host="127.0.0.1" port=5002 \
+ *         sync=false async=false
+ * ]| Send two audio streams to port 5000.
+ * |[
+ * gst-launch-1.0 rtpsession name=rtpsession rtp-profile=avpf \
+ *     udpsrc port=5000 caps="application/x-rtp,media=(string)audio,clock-rate=(int)48000,encoding-name=(string)OPUS,payload=(int)97" ! \
+ *         rtpsession.recv_rtp_sink \
+ *     rtpsession.recv_rtp_src ! \
+ *         rtprtxreceive payload-type-map="application/x-rtp-pt-map,97=(uint)99" ! \
+ *         rtpssrcdemux name=demux \
+ *     demux. ! queue ! rtpjitterbuffer do-retransmission=true ! rtpopusdepay ! \
+ *         opusdec ! audioconvert ! autoaudiosink \
+ *     demux. ! queue ! rtpjitterbuffer do-retransmission=true ! rtpopusdepay ! \
+ *         opusdec ! audioconvert ! autoaudiosink \
+ *     udpsrc port=5002 ! rtpsession.recv_rtcp_sink \
+ *     rtpsession.send_rtcp_src ! udpsink host="127.0.0.1" port=5001 \
+ *         sync=false async=false
+ * ]| Receive two audio streams from port 5000.
+ *
+ * In this example we are streaming two streams of the same type through the
+ * same port. They, however, are using a different SSRC (ssrc is randomly
+ * generated on each payloader - rtpopuspay in this example), so they can be
+ * identified and demultiplexed by rtpssrcdemux on the receiver side. This is
+ * an example of SSRC-multiplexing.
+ *
+ * It is important here to use a different starting sequence number
+ * (seqnum-offset), since this is the only means of identification that
+ * rtprtxreceive uses the very first time to identify retransmission streams.
+ * It is an error, according to RFC4588 to have two retransmission requests for
+ * packets belonging to two different streams but with the same sequence number.
+ * Note that the default seqnum-offset value (-1, which means random) would
+ * work just fine, but it is overriden here for illustration purposes.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "gstrtprtxreceive.h"
+
+#define ASSOC_TIMEOUT (GST_SECOND)
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_rtx_receive_debug);
+#define GST_CAT_DEFAULT gst_rtp_rtx_receive_debug
+
+enum
+{
+  PROP_0,
+  PROP_PAYLOAD_TYPE_MAP,
+  PROP_NUM_RTX_REQUESTS,
+  PROP_NUM_RTX_PACKETS,
+  PROP_NUM_RTX_ASSOC_PACKETS
+};
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static gboolean gst_rtp_rtx_receive_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static GstFlowReturn gst_rtp_rtx_receive_chain (GstPad * pad,
+    GstObject * parent, GstBuffer * buffer);
+
+static GstStateChangeReturn gst_rtp_rtx_receive_change_state (GstElement *
+    element, GstStateChange transition);
+
+static void gst_rtp_rtx_receive_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_rtx_receive_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_rtp_rtx_receive_finalize (GObject * object);
+
+G_DEFINE_TYPE (GstRtpRtxReceive, gst_rtp_rtx_receive, GST_TYPE_ELEMENT);
+
+static void
+gst_rtp_rtx_receive_class_init (GstRtpRtxReceiveClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->get_property = gst_rtp_rtx_receive_get_property;
+  gobject_class->set_property = gst_rtp_rtx_receive_set_property;
+  gobject_class->finalize = gst_rtp_rtx_receive_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_PAYLOAD_TYPE_MAP,
+      g_param_spec_boxed ("payload-type-map", "Payload Type Map",
+          "Map of original payload types to their retransmission payload types",
+          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NUM_RTX_REQUESTS,
+      g_param_spec_uint ("num-rtx-requests", "Num RTX Requests",
+          "Number of retransmission events received", 0, G_MAXUINT,
+          0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NUM_RTX_PACKETS,
+      g_param_spec_uint ("num-rtx-packets", "Num RTX Packets",
+          " Number of retransmission packets received", 0, G_MAXUINT,
+          0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NUM_RTX_ASSOC_PACKETS,
+      g_param_spec_uint ("num-rtx-assoc-packets",
+          "Num RTX Associated Packets", "Number of retransmission packets "
+          "correctly associated with retransmission requests", 0, G_MAXUINT,
+          0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Retransmission receiver", "Codec",
+      "Receive retransmitted RTP packets according to RFC4588",
+      "Julien Isorce <julien.isorce@collabora.co.uk>");
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_rtp_rtx_receive_change_state);
+}
+
+static void
+gst_rtp_rtx_receive_reset (GstRtpRtxReceive * rtx)
+{
+  GST_OBJECT_LOCK (rtx);
+  g_hash_table_remove_all (rtx->ssrc2_ssrc1_map);
+  g_hash_table_remove_all (rtx->seqnum_ssrc1_map);
+  rtx->num_rtx_requests = 0;
+  rtx->num_rtx_packets = 0;
+  rtx->num_rtx_assoc_packets = 0;
+  GST_OBJECT_UNLOCK (rtx);
+}
+
+static void
+gst_rtp_rtx_receive_finalize (GObject * object)
+{
+  GstRtpRtxReceive *rtx = GST_RTP_RTX_RECEIVE (object);
+
+  g_hash_table_unref (rtx->ssrc2_ssrc1_map);
+  g_hash_table_unref (rtx->seqnum_ssrc1_map);
+  g_hash_table_unref (rtx->rtx_pt_map);
+  if (rtx->rtx_pt_map_structure)
+    gst_structure_free (rtx->rtx_pt_map_structure);
+
+  G_OBJECT_CLASS (gst_rtp_rtx_receive_parent_class)->finalize (object);
+}
+
+typedef struct
+{
+  guint32 ssrc;
+  GstClockTime time;
+} SsrcAssoc;
+
+static SsrcAssoc *
+ssrc_assoc_new (guint32 ssrc, GstClockTime time)
+{
+  SsrcAssoc *assoc = g_slice_new (SsrcAssoc);
+
+  assoc->ssrc = ssrc;
+  assoc->time = time;
+
+  return assoc;
+}
+
+static void
+ssrc_assoc_free (SsrcAssoc * assoc)
+{
+  g_slice_free (SsrcAssoc, assoc);
+}
+
+static void
+gst_rtp_rtx_receive_init (GstRtpRtxReceive * rtx)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (rtx);
+
+  rtx->srcpad =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "src"), "src");
+  GST_PAD_SET_PROXY_CAPS (rtx->srcpad);
+  GST_PAD_SET_PROXY_ALLOCATION (rtx->srcpad);
+  gst_pad_set_event_function (rtx->srcpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_rtx_receive_src_event));
+  gst_element_add_pad (GST_ELEMENT (rtx), rtx->srcpad);
+
+  rtx->sinkpad =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "sink"), "sink");
+  GST_PAD_SET_PROXY_CAPS (rtx->sinkpad);
+  GST_PAD_SET_PROXY_ALLOCATION (rtx->sinkpad);
+  gst_pad_set_chain_function (rtx->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_rtx_receive_chain));
+  gst_element_add_pad (GST_ELEMENT (rtx), rtx->sinkpad);
+
+  rtx->ssrc2_ssrc1_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+  rtx->seqnum_ssrc1_map = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+      NULL, (GDestroyNotify) ssrc_assoc_free);
+
+  rtx->rtx_pt_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+}
+
+static gboolean
+gst_rtp_rtx_receive_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstRtpRtxReceive *rtx = GST_RTP_RTX_RECEIVE (parent);
+  gboolean res;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CUSTOM_UPSTREAM:
+    {
+      const GstStructure *s = gst_event_get_structure (event);
+
+      /* This event usually comes from the downstream gstrtpjitterbuffer */
+      if (gst_structure_has_name (s, "GstRTPRetransmissionRequest")) {
+        guint seqnum = 0;
+        guint ssrc = 0;
+        gpointer ssrc2 = 0;
+
+        /* retrieve seqnum of the packet that need to be retransmitted */
+        if (!gst_structure_get_uint (s, "seqnum", &seqnum))
+          seqnum = -1;
+
+        /* retrieve ssrc of the packet that need to be retransmitted
+         * it's useful when reconstructing the original packet from the rtx packet */
+        if (!gst_structure_get_uint (s, "ssrc", &ssrc))
+          ssrc = -1;
+
+        GST_DEBUG_OBJECT (rtx, "got rtx request for seqnum: %u, ssrc: %X",
+            seqnum, ssrc);
+
+        GST_OBJECT_LOCK (rtx);
+
+        /* increase number of seen requests for our statistics */
+        ++rtx->num_rtx_requests;
+
+        /* First, we lookup in our map to see if we have already associate this
+         * master stream ssrc with its retransmitted stream.
+         * Every ssrc are unique so we can use the same hash table
+         * for both retrieving the ssrc1 from ssrc2 and also ssrc2 from ssrc1
+         */
+        if (g_hash_table_lookup_extended (rtx->ssrc2_ssrc1_map,
+                GUINT_TO_POINTER (ssrc), NULL, &ssrc2)
+            && GPOINTER_TO_UINT (ssrc2) != GPOINTER_TO_UINT (ssrc)) {
+          GST_TRACE_OBJECT (rtx, "Retransmited stream %X already associated "
+              "to its master, %X", GPOINTER_TO_UINT (ssrc2), ssrc);
+        } else {
+          SsrcAssoc *assoc;
+
+          /* not already associated but also we have to check that we have not
+           * already considered this request.
+           */
+          if (g_hash_table_lookup_extended (rtx->seqnum_ssrc1_map,
+                  GUINT_TO_POINTER (seqnum), NULL, (gpointer *) & assoc)) {
+            if (assoc->ssrc == ssrc) {
+              /* same seqnum, same ssrc */
+
+              /* do nothing because we have already considered this request
+               * The jitter may be too impatient of the rtx packet has been
+               * lost too.
+               * It does not mean we reject the event, we still want to forward
+               * the request to the gstrtpsession to be translater into a FB NACK
+               */
+              GST_LOG_OBJECT (rtx, "Duplicate request: seqnum: %u, ssrc: %X",
+                  seqnum, ssrc);
+            } else {
+              /* same seqnum, different ssrc */
+
+              /* If the association attempt is larger than ASSOC_TIMEOUT,
+               * then we give up on it, and try this one.
+               */
+              if (!GST_CLOCK_TIME_IS_VALID (rtx->last_time) ||
+                  !GST_CLOCK_TIME_IS_VALID (assoc->time) ||
+                  assoc->time + ASSOC_TIMEOUT < rtx->last_time) {
+                /* From RFC 4588:
+                 * the receiver MUST NOT have two outstanding requests for the
+                 * same packet sequence number in two different original streams
+                 * before the association is resolved. Otherwise it's impossible
+                 * to associate a rtx stream and its master stream
+                 */
+
+                /* remove seqnum in order to reuse the spot */
+                g_hash_table_remove (rtx->seqnum_ssrc1_map,
+                    GUINT_TO_POINTER (seqnum));
+                goto retransmit;
+              } else {
+                GST_INFO_OBJECT (rtx, "rejecting request for seqnum %u"
+                    " of master stream %X; there is already a pending request "
+                    "for the same seqnum on ssrc %X that has not expired",
+                    seqnum, ssrc, assoc->ssrc);
+
+                /* do not forward the event as we are rejecting this request */
+                GST_OBJECT_UNLOCK (rtx);
+                gst_event_unref (event);
+                return TRUE;
+              }
+            }
+          } else {
+          retransmit:
+            /* the request has not been already considered
+             * insert it for the first time */
+            g_hash_table_insert (rtx->seqnum_ssrc1_map,
+                GUINT_TO_POINTER (seqnum),
+                ssrc_assoc_new (ssrc, rtx->last_time));
+          }
+        }
+
+        GST_DEBUG_OBJECT (rtx, "packet number %u of master stream %X"
+            " needs to be retransmitted", seqnum, ssrc);
+
+        GST_OBJECT_UNLOCK (rtx);
+      }
+
+      /* Transfer event upstream so that the request can acutally by translated
+       * through gstrtpsession through the network */
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+    }
+    default:
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+  return res;
+}
+
+/* Copy fixed header and extension. Replace current ssrc by ssrc1,
+ * remove OSN and replace current seq num by OSN.
+ * Copy memory to avoid to manually copy each rtp buffer field.
+ */
+static GstBuffer *
+_gst_rtp_buffer_new_from_rtx (GstRTPBuffer * rtp, guint32 ssrc1,
+    guint16 orign_seqnum, guint8 origin_payload_type)
+{
+  GstMemory *mem = NULL;
+  GstRTPBuffer new_rtp = GST_RTP_BUFFER_INIT;
+  GstBuffer *new_buffer = gst_buffer_new ();
+  GstMapInfo map;
+  guint payload_len = 0;
+
+  /* copy fixed header */
+  mem = gst_memory_copy (rtp->map[0].memory,
+      (guint8 *) rtp->data[0] - rtp->map[0].data, rtp->size[0]);
+  gst_buffer_append_memory (new_buffer, mem);
+
+  /* copy extension if any */
+  if (rtp->size[1]) {
+    mem = gst_memory_copy (rtp->map[1].memory,
+        (guint8 *) rtp->data[1] - rtp->map[1].data, rtp->size[1]);
+    gst_buffer_append_memory (new_buffer, mem);
+  }
+
+  /* copy payload and remove OSN */
+  payload_len = rtp->size[2] - 2;
+  mem = gst_allocator_alloc (NULL, payload_len, NULL);
+
+  gst_memory_map (mem, &map, GST_MAP_WRITE);
+  if (rtp->size[2])
+    memcpy (map.data, (guint8 *) rtp->data[2] + 2, payload_len);
+  gst_memory_unmap (mem, &map);
+  gst_buffer_append_memory (new_buffer, mem);
+
+  /* the sender always constructs rtx packets without padding,
+   * But the receiver can still receive rtx packets with padding.
+   * So just copy it.
+   */
+  if (rtp->size[3]) {
+    guint pad_len = rtp->size[3];
+
+    mem = gst_allocator_alloc (NULL, pad_len, NULL);
+
+    gst_memory_map (mem, &map, GST_MAP_WRITE);
+    map.data[pad_len - 1] = pad_len;
+    gst_memory_unmap (mem, &map);
+
+    gst_buffer_append_memory (new_buffer, mem);
+  }
+
+  /* set ssrc and seq num */
+  gst_rtp_buffer_map (new_buffer, GST_MAP_WRITE, &new_rtp);
+  gst_rtp_buffer_set_ssrc (&new_rtp, ssrc1);
+  gst_rtp_buffer_set_seq (&new_rtp, orign_seqnum);
+  gst_rtp_buffer_set_payload_type (&new_rtp, origin_payload_type);
+  gst_rtp_buffer_unmap (&new_rtp);
+
+  gst_buffer_copy_into (new_buffer, rtp->buffer,
+      GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+  GST_BUFFER_FLAG_SET (new_buffer, GST_RTP_BUFFER_FLAG_RETRANSMISSION);
+
+  return new_buffer;
+}
+
+static GstFlowReturn
+gst_rtp_rtx_receive_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstRtpRtxReceive *rtx = GST_RTP_RTX_RECEIVE (parent);
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBuffer *new_buffer = NULL;
+  guint32 ssrc = 0;
+  gpointer ssrc1 = 0;
+  guint32 ssrc2 = 0;
+  guint16 seqnum = 0;
+  guint16 orign_seqnum = 0;
+  guint8 payload_type = 0;
+  gpointer payload = NULL;
+  guint8 origin_payload_type = 0;
+  gboolean is_rtx;
+  gboolean drop = FALSE;
+
+  /* map current rtp packet to parse its header */
+  if (!gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp))
+    goto invalid_buffer;
+
+  ssrc = gst_rtp_buffer_get_ssrc (&rtp);
+  seqnum = gst_rtp_buffer_get_seq (&rtp);
+  payload_type = gst_rtp_buffer_get_payload_type (&rtp);
+
+  /* check if we have a retransmission packet (this information comes from SDP) */
+  GST_OBJECT_LOCK (rtx);
+
+  is_rtx =
+      g_hash_table_lookup_extended (rtx->rtx_pt_map,
+      GUINT_TO_POINTER (payload_type), NULL, NULL);
+
+  if (is_rtx) {
+    payload = gst_rtp_buffer_get_payload (&rtp);
+
+    if (!payload || gst_rtp_buffer_get_payload_len (&rtp) < 2) {
+      GST_OBJECT_UNLOCK (rtx);
+      gst_rtp_buffer_unmap (&rtp);
+      goto invalid_buffer;
+    }
+  }
+
+  rtx->last_time = GST_BUFFER_PTS (buffer);
+
+  if (g_hash_table_size (rtx->seqnum_ssrc1_map) > 0) {
+    GHashTableIter iter;
+    gpointer key, value;
+
+    g_hash_table_iter_init (&iter, rtx->seqnum_ssrc1_map);
+    while (g_hash_table_iter_next (&iter, &key, &value)) {
+      SsrcAssoc *assoc = value;
+
+      /* remove association request if it is too old */
+      if (GST_CLOCK_TIME_IS_VALID (rtx->last_time) &&
+          GST_CLOCK_TIME_IS_VALID (assoc->time) &&
+          assoc->time + ASSOC_TIMEOUT < rtx->last_time) {
+        g_hash_table_iter_remove (&iter);
+      }
+    }
+  }
+
+  /* if the current packet is from a retransmission stream */
+  if (is_rtx) {
+    /* increase our statistic */
+    ++rtx->num_rtx_packets;
+
+    /* read OSN in the rtx payload */
+    orign_seqnum = GST_READ_UINT16_BE (gst_rtp_buffer_get_payload (&rtp));
+    origin_payload_type =
+        GPOINTER_TO_UINT (g_hash_table_lookup (rtx->rtx_pt_map,
+            GUINT_TO_POINTER (payload_type)));
+
+    GST_DEBUG_OBJECT (rtx, "Got rtx packet: rtx seqnum %u, rtx ssrc %X, "
+        "rtx pt %u, orig seqnum %u, orig pt %u", seqnum, ssrc, payload_type,
+        orign_seqnum, origin_payload_type);
+
+    /* first we check if we already have associated this retransmission stream
+     * to a master stream */
+    if (g_hash_table_lookup_extended (rtx->ssrc2_ssrc1_map,
+            GUINT_TO_POINTER (ssrc), NULL, &ssrc1)) {
+      GST_TRACE_OBJECT (rtx,
+          "packet is from retransmission stream %X already associated to "
+          "master stream %X", ssrc, GPOINTER_TO_UINT (ssrc1));
+      ssrc2 = ssrc;
+    } else {
+      SsrcAssoc *assoc;
+
+      /* the current retransmitted packet has its rtx stream not already
+       * associated to a master stream, so retrieve it from our request
+       * history */
+      if (g_hash_table_lookup_extended (rtx->seqnum_ssrc1_map,
+              GUINT_TO_POINTER (orign_seqnum), NULL, (gpointer *) & assoc)) {
+        GST_LOG_OBJECT (rtx,
+            "associating retransmitted stream %X to master stream %X thanks "
+            "to rtx packet %u (orig seqnum %u)", ssrc, assoc->ssrc, seqnum,
+            orign_seqnum);
+        ssrc1 = GUINT_TO_POINTER (assoc->ssrc);
+        ssrc2 = ssrc;
+
+        /* just put a guard */
+        if (GPOINTER_TO_UINT (ssrc1) == ssrc2)
+          GST_WARNING_OBJECT (rtx, "RTX receiver ssrc2_ssrc1_map bad state, "
+              "master and rtx SSRCs are the same (%X)\n", ssrc);
+
+        /* free the spot so that this seqnum can be used to do another
+         * association */
+        g_hash_table_remove (rtx->seqnum_ssrc1_map,
+            GUINT_TO_POINTER (orign_seqnum));
+
+        /* actually do the association between rtx stream and master stream */
+        g_hash_table_insert (rtx->ssrc2_ssrc1_map, GUINT_TO_POINTER (ssrc2),
+            ssrc1);
+
+        /* also do the association between master stream and rtx stream
+         * every ssrc are unique so we can use the same hash table
+         * for both retrieving the ssrc1 from ssrc2 and also ssrc2 from ssrc1
+         */
+        g_hash_table_insert (rtx->ssrc2_ssrc1_map, ssrc1,
+            GUINT_TO_POINTER (ssrc2));
+
+      } else {
+        /* we are not able to associate this rtx packet with a master stream */
+        GST_INFO_OBJECT (rtx,
+            "dropping rtx packet %u because its orig seqnum (%u) is not in our"
+            " pending retransmission requests", seqnum, orign_seqnum);
+        drop = TRUE;
+      }
+    }
+  }
+
+  /* if not dropped the packet was successfully associated */
+  if (is_rtx && !drop)
+    ++rtx->num_rtx_assoc_packets;
+
+  GST_OBJECT_UNLOCK (rtx);
+
+  /* just drop the packet if the association could not have been made */
+  if (drop) {
+    gst_rtp_buffer_unmap (&rtp);
+    gst_buffer_unref (buffer);
+    return GST_FLOW_OK;
+  }
+
+  /* create the retransmission packet */
+  if (is_rtx)
+    new_buffer =
+        _gst_rtp_buffer_new_from_rtx (&rtp, GPOINTER_TO_UINT (ssrc1),
+        orign_seqnum, origin_payload_type);
+
+  gst_rtp_buffer_unmap (&rtp);
+
+  /* push the packet */
+  if (is_rtx) {
+    gst_buffer_unref (buffer);
+    GST_LOG_OBJECT (rtx, "pushing packet seqnum:%u from restransmission "
+        "stream ssrc: %X (master ssrc %X)", orign_seqnum, ssrc2,
+        GPOINTER_TO_UINT (ssrc1));
+    ret = gst_pad_push (rtx->srcpad, new_buffer);
+  } else {
+    GST_TRACE_OBJECT (rtx, "pushing packet seqnum:%u from master stream "
+        "ssrc: %X", seqnum, ssrc);
+    ret = gst_pad_push (rtx->srcpad, buffer);
+  }
+
+  return ret;
+
+invalid_buffer:
+  {
+    GST_ELEMENT_WARNING (rtx, STREAM, DECODE, (NULL),
+        ("Received invalid RTP payload, dropping"));
+    gst_buffer_unref (buffer);
+    return GST_FLOW_OK;
+  }
+}
+
+static void
+gst_rtp_rtx_receive_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstRtpRtxReceive *rtx = GST_RTP_RTX_RECEIVE (object);
+
+  switch (prop_id) {
+    case PROP_PAYLOAD_TYPE_MAP:
+      GST_OBJECT_LOCK (rtx);
+      g_value_set_boxed (value, rtx->rtx_pt_map_structure);
+      GST_OBJECT_UNLOCK (rtx);
+      break;
+    case PROP_NUM_RTX_REQUESTS:
+      GST_OBJECT_LOCK (rtx);
+      g_value_set_uint (value, rtx->num_rtx_requests);
+      GST_OBJECT_UNLOCK (rtx);
+      break;
+    case PROP_NUM_RTX_PACKETS:
+      GST_OBJECT_LOCK (rtx);
+      g_value_set_uint (value, rtx->num_rtx_packets);
+      GST_OBJECT_UNLOCK (rtx);
+      break;
+    case PROP_NUM_RTX_ASSOC_PACKETS:
+      GST_OBJECT_LOCK (rtx);
+      g_value_set_uint (value, rtx->num_rtx_assoc_packets);
+      GST_OBJECT_UNLOCK (rtx);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+structure_to_hash_table_inv (GQuark field_id, const GValue * value,
+    gpointer hash)
+{
+  const gchar *field_str;
+  guint field_uint;
+  guint value_uint;
+
+  field_str = g_quark_to_string (field_id);
+  field_uint = atoi (field_str);
+  value_uint = g_value_get_uint (value);
+  g_hash_table_insert ((GHashTable *) hash, GUINT_TO_POINTER (value_uint),
+      GUINT_TO_POINTER (field_uint));
+
+  return TRUE;
+}
+
+static void
+gst_rtp_rtx_receive_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstRtpRtxReceive *rtx = GST_RTP_RTX_RECEIVE (object);
+
+  switch (prop_id) {
+    case PROP_PAYLOAD_TYPE_MAP:
+      GST_OBJECT_LOCK (rtx);
+      if (rtx->rtx_pt_map_structure)
+        gst_structure_free (rtx->rtx_pt_map_structure);
+      rtx->rtx_pt_map_structure = g_value_dup_boxed (value);
+      g_hash_table_remove_all (rtx->rtx_pt_map);
+      gst_structure_foreach (rtx->rtx_pt_map_structure,
+          structure_to_hash_table_inv, rtx->rtx_pt_map);
+      GST_OBJECT_UNLOCK (rtx);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_rtx_receive_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstRtpRtxReceive *rtx;
+
+  rtx = GST_RTP_RTX_RECEIVE (element);
+
+  switch (transition) {
+    default:
+      break;
+  }
+
+  ret =
+      GST_ELEMENT_CLASS (gst_rtp_rtx_receive_parent_class)->change_state
+      (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_rtx_receive_reset (rtx);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+gboolean
+gst_rtp_rtx_receive_plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_rtx_receive_debug, "rtprtxreceive", 0,
+      "rtp retransmission receiver");
+
+  return gst_element_register (plugin, "rtprtxreceive", GST_RANK_NONE,
+      GST_TYPE_RTP_RTX_RECEIVE);
+}
diff --git a/gst/rtpmanager/gstrtprtxreceive.h b/gst/rtpmanager/gstrtprtxreceive.h
new file mode 100644
index 0000000..cf6c4a9
--- /dev/null
+++ b/gst/rtpmanager/gstrtprtxreceive.h
@@ -0,0 +1,80 @@
+/* RTP Retransmission receiver element for GStreamer
+ *
+ * gstrtprtxreceive.h:
+ *
+ * Copyright (C) 2013 Collabora Ltd.
+ *   @author Julien Isorce <julien.isorce@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_RTX_RECEIVE_H__
+#define __GST_RTP_RTX_RECEIVE_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_RTX_RECEIVE (gst_rtp_rtx_receive_get_type())
+#define GST_RTP_RTX_RECEIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_RTX_RECEIVE, GstRtpRtxReceive))
+#define GST_RTP_RTX_RECEIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_RTX_RECEIVE, GstRtpRtxReceiveClass))
+#define GST_RTP_RTX_RECEIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_RTX_RECEIVE, GstRtpRtxReceiveClass))
+#define GST_IS_RTP_RTX_RECEIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_RTX_RECEIVE))
+#define GST_IS_RTP_RTX_RECEIVE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_RTX_RECEIVE))
+typedef struct _GstRtpRtxReceive GstRtpRtxReceive;
+typedef struct _GstRtpRtxReceiveClass GstRtpRtxReceiveClass;
+
+struct _GstRtpRtxReceive
+{
+  GstElement element;
+
+  /* pad */
+  GstPad *sinkpad;
+  GstPad *srcpad;
+
+  /* retrieve associated master stream from rtx stream
+   * it also works to retrieve rtx stream from master stream
+   * as we make sure all ssrc are unique */
+  GHashTable *ssrc2_ssrc1_map;
+
+  /* contains seqnum of request packets of whom their ssrc have
+   * not been associated to a rtx stream yet */
+  GHashTable *seqnum_ssrc1_map;
+
+  /* rtx pt (uint) -> origin pt (uint) */
+  GHashTable *rtx_pt_map;
+  /* origin pt (string) -> rtx pt (uint) */
+  GstStructure *rtx_pt_map_structure;
+
+  /* statistics */
+  guint num_rtx_requests;
+  guint num_rtx_packets;
+  guint num_rtx_assoc_packets;
+
+  GstClockTime last_time;
+};
+
+struct _GstRtpRtxReceiveClass
+{
+  GstElementClass parent_class;
+};
+
+
+GType gst_rtp_rtx_receive_get_type (void);
+gboolean gst_rtp_rtx_receive_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_RTX_RECEIVE_H__ */
diff --git a/gst/rtpmanager/gstrtprtxsend.c b/gst/rtpmanager/gstrtprtxsend.c
new file mode 100644
index 0000000..4329d84
--- /dev/null
+++ b/gst/rtpmanager/gstrtprtxsend.c
@@ -0,0 +1,948 @@
+/* RTP Retransmission sender element for GStreamer
+ *
+ * gstrtprtxsend.c:
+ *
+ * Copyright (C) 2013 Collabora Ltd.
+ *   @author Julien Isorce <julien.isorce@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtprtxsend
+ *
+ * See #GstRtpRtxReceive for examples
+ * 
+ * The purpose of the sender RTX object is to keep a history of RTP packets up
+ * to a configurable limit (max-size-time or max-size-packets). It will listen
+ * for upstream custom retransmission events (GstRTPRetransmissionRequest) that
+ * comes from downstream (#GstRtpSession). When receiving a request it will
+ * look up the requested seqnum in its list of stored packets. If the packet
+ * is available, it will create a RTX packet according to RFC 4588 and send
+ * this as an auxiliary stream. RTX is SSRC-multiplexed
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "gstrtprtxsend.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_rtx_send_debug);
+#define GST_CAT_DEFAULT gst_rtp_rtx_send_debug
+
+#define DEFAULT_RTX_PAYLOAD_TYPE 0
+#define DEFAULT_MAX_SIZE_TIME    0
+#define DEFAULT_MAX_SIZE_PACKETS 100
+
+enum
+{
+  PROP_0,
+  PROP_SSRC_MAP,
+  PROP_PAYLOAD_TYPE_MAP,
+  PROP_MAX_SIZE_TIME,
+  PROP_MAX_SIZE_PACKETS,
+  PROP_NUM_RTX_REQUESTS,
+  PROP_NUM_RTX_PACKETS
+};
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, " "clock-rate = (int) [1, MAX]")
+    );
+
+static gboolean gst_rtp_rtx_send_queue_check_full (GstDataQueue * queue,
+    guint visible, guint bytes, guint64 time, gpointer checkdata);
+
+static gboolean gst_rtp_rtx_send_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static gboolean gst_rtp_rtx_send_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static GstFlowReturn gst_rtp_rtx_send_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer);
+static GstFlowReturn gst_rtp_rtx_send_chain_list (GstPad * pad,
+    GstObject * parent, GstBufferList * list);
+
+static void gst_rtp_rtx_send_src_loop (GstRtpRtxSend * rtx);
+static gboolean gst_rtp_rtx_send_activate_mode (GstPad * pad,
+    GstObject * parent, GstPadMode mode, gboolean active);
+
+static GstStateChangeReturn gst_rtp_rtx_send_change_state (GstElement *
+    element, GstStateChange transition);
+
+static void gst_rtp_rtx_send_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_rtx_send_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_rtp_rtx_send_finalize (GObject * object);
+
+G_DEFINE_TYPE (GstRtpRtxSend, gst_rtp_rtx_send, GST_TYPE_ELEMENT);
+
+typedef struct
+{
+  guint16 seqnum;
+  guint32 timestamp;
+  GstBuffer *buffer;
+} BufferQueueItem;
+
+static void
+buffer_queue_item_free (BufferQueueItem * item)
+{
+  gst_buffer_unref (item->buffer);
+  g_slice_free (BufferQueueItem, item);
+}
+
+typedef struct
+{
+  guint32 rtx_ssrc;
+  guint16 seqnum_base, next_seqnum;
+  gint clock_rate;
+
+  /* history of rtp packets */
+  GSequence *queue;
+} SSRCRtxData;
+
+static SSRCRtxData *
+ssrc_rtx_data_new (guint32 rtx_ssrc)
+{
+  SSRCRtxData *data = g_slice_new0 (SSRCRtxData);
+
+  data->rtx_ssrc = rtx_ssrc;
+  data->next_seqnum = data->seqnum_base = g_random_int_range (0, G_MAXUINT16);
+  data->queue = g_sequence_new ((GDestroyNotify) buffer_queue_item_free);
+
+  return data;
+}
+
+static void
+ssrc_rtx_data_free (SSRCRtxData * data)
+{
+  g_sequence_free (data->queue);
+  g_slice_free (SSRCRtxData, data);
+}
+
+static void
+gst_rtp_rtx_send_class_init (GstRtpRtxSendClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->get_property = gst_rtp_rtx_send_get_property;
+  gobject_class->set_property = gst_rtp_rtx_send_set_property;
+  gobject_class->finalize = gst_rtp_rtx_send_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_SSRC_MAP,
+      g_param_spec_boxed ("ssrc-map", "SSRC Map",
+          "Map of SSRCs to their retransmission SSRCs for SSRC-multiplexed mode"
+          " (default = random)", GST_TYPE_STRUCTURE,
+          G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_PAYLOAD_TYPE_MAP,
+      g_param_spec_boxed ("payload-type-map", "Payload Type Map",
+          "Map of original payload types to their retransmission payload types",
+          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_SIZE_TIME,
+      g_param_spec_uint ("max-size-time", "Max Size Time",
+          "Amount of ms to queue (0 = unlimited)", 0, G_MAXUINT,
+          DEFAULT_MAX_SIZE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_SIZE_PACKETS,
+      g_param_spec_uint ("max-size-packets", "Max Size Packets",
+          "Amount of packets to queue (0 = unlimited)", 0, G_MAXINT16,
+          DEFAULT_MAX_SIZE_PACKETS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NUM_RTX_REQUESTS,
+      g_param_spec_uint ("num-rtx-requests", "Num RTX Requests",
+          "Number of retransmission events received", 0, G_MAXUINT,
+          0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NUM_RTX_PACKETS,
+      g_param_spec_uint ("num-rtx-packets", "Num RTX Packets",
+          " Number of retransmission packets sent", 0, G_MAXUINT,
+          0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP Retransmission Sender", "Codec",
+      "Retransmit RTP packets when needed, according to RFC4588",
+      "Julien Isorce <julien.isorce@collabora.co.uk>");
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_rtp_rtx_send_change_state);
+}
+
+static void
+gst_rtp_rtx_send_reset (GstRtpRtxSend * rtx)
+{
+  GST_OBJECT_LOCK (rtx);
+  gst_data_queue_flush (rtx->queue);
+  g_hash_table_remove_all (rtx->ssrc_data);
+  g_hash_table_remove_all (rtx->rtx_ssrcs);
+  rtx->num_rtx_requests = 0;
+  rtx->num_rtx_packets = 0;
+  GST_OBJECT_UNLOCK (rtx);
+}
+
+static void
+gst_rtp_rtx_send_finalize (GObject * object)
+{
+  GstRtpRtxSend *rtx = GST_RTP_RTX_SEND (object);
+
+  g_hash_table_unref (rtx->ssrc_data);
+  g_hash_table_unref (rtx->rtx_ssrcs);
+  if (rtx->external_ssrc_map)
+    gst_structure_free (rtx->external_ssrc_map);
+  g_hash_table_unref (rtx->rtx_pt_map);
+  if (rtx->rtx_pt_map_structure)
+    gst_structure_free (rtx->rtx_pt_map_structure);
+  g_object_unref (rtx->queue);
+
+  G_OBJECT_CLASS (gst_rtp_rtx_send_parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_rtx_send_init (GstRtpRtxSend * rtx)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (rtx);
+
+  rtx->srcpad =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "src"), "src");
+  GST_PAD_SET_PROXY_CAPS (rtx->srcpad);
+  GST_PAD_SET_PROXY_ALLOCATION (rtx->srcpad);
+  gst_pad_set_event_function (rtx->srcpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_rtx_send_src_event));
+  gst_pad_set_activatemode_function (rtx->srcpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_rtx_send_activate_mode));
+  gst_element_add_pad (GST_ELEMENT (rtx), rtx->srcpad);
+
+  rtx->sinkpad =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "sink"), "sink");
+  GST_PAD_SET_PROXY_CAPS (rtx->sinkpad);
+  GST_PAD_SET_PROXY_ALLOCATION (rtx->sinkpad);
+  gst_pad_set_event_function (rtx->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_rtx_send_sink_event));
+  gst_pad_set_chain_function (rtx->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_rtx_send_chain));
+  gst_pad_set_chain_list_function (rtx->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_rtp_rtx_send_chain_list));
+  gst_element_add_pad (GST_ELEMENT (rtx), rtx->sinkpad);
+
+  rtx->queue = gst_data_queue_new (gst_rtp_rtx_send_queue_check_full, NULL,
+      NULL, rtx);
+  rtx->ssrc_data = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+      NULL, (GDestroyNotify) ssrc_rtx_data_free);
+  rtx->rtx_ssrcs = g_hash_table_new (g_direct_hash, g_direct_equal);
+  rtx->rtx_pt_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  rtx->max_size_time = DEFAULT_MAX_SIZE_TIME;
+  rtx->max_size_packets = DEFAULT_MAX_SIZE_PACKETS;
+}
+
+static void
+gst_rtp_rtx_send_set_flushing (GstRtpRtxSend * rtx, gboolean flush)
+{
+  GST_OBJECT_LOCK (rtx);
+  gst_data_queue_set_flushing (rtx->queue, flush);
+  gst_data_queue_flush (rtx->queue);
+  GST_OBJECT_UNLOCK (rtx);
+}
+
+static gboolean
+gst_rtp_rtx_send_queue_check_full (GstDataQueue * queue,
+    guint visible, guint bytes, guint64 time, gpointer checkdata)
+{
+  return FALSE;
+}
+
+static void
+gst_rtp_rtx_data_queue_item_free (gpointer item)
+{
+  GstDataQueueItem *data = item;
+  if (data->object)
+    gst_mini_object_unref (data->object);
+  g_slice_free (GstDataQueueItem, data);
+}
+
+static gboolean
+gst_rtp_rtx_send_push_out (GstRtpRtxSend * rtx, gpointer object)
+{
+  GstDataQueueItem *data;
+  gboolean success;
+
+  data = g_slice_new0 (GstDataQueueItem);
+  data->object = GST_MINI_OBJECT (object);
+  data->size = 1;
+  data->duration = 1;
+  data->visible = TRUE;
+  data->destroy = gst_rtp_rtx_data_queue_item_free;
+
+  success = gst_data_queue_push (rtx->queue, data);
+
+  if (!success)
+    data->destroy (data);
+
+  return success;
+}
+
+static guint32
+gst_rtp_rtx_send_choose_ssrc (GstRtpRtxSend * rtx, guint32 choice,
+    gboolean consider_choice)
+{
+  guint32 ssrc = consider_choice ? choice : g_random_int ();
+
+  /* make sure to be different than any other */
+  while (g_hash_table_contains (rtx->ssrc_data, GUINT_TO_POINTER (ssrc)) ||
+      g_hash_table_contains (rtx->rtx_ssrcs, GUINT_TO_POINTER (ssrc))) {
+    ssrc = g_random_int ();
+  }
+
+  return ssrc;
+}
+
+static SSRCRtxData *
+gst_rtp_rtx_send_get_ssrc_data (GstRtpRtxSend * rtx, guint32 ssrc)
+{
+  SSRCRtxData *data;
+  guint32 rtx_ssrc = 0;
+  gboolean consider = FALSE;
+
+  if (G_UNLIKELY (!g_hash_table_contains (rtx->ssrc_data,
+              GUINT_TO_POINTER (ssrc)))) {
+    if (rtx->external_ssrc_map) {
+      gchar *ssrc_str;
+      ssrc_str = g_strdup_printf ("%" G_GUINT32_FORMAT, ssrc);
+      consider = gst_structure_get_uint (rtx->external_ssrc_map, ssrc_str,
+          &rtx_ssrc);
+      g_free (ssrc_str);
+    }
+    rtx_ssrc = gst_rtp_rtx_send_choose_ssrc (rtx, rtx_ssrc, consider);
+    data = ssrc_rtx_data_new (rtx_ssrc);
+    g_hash_table_insert (rtx->ssrc_data, GUINT_TO_POINTER (ssrc), data);
+    g_hash_table_insert (rtx->rtx_ssrcs, GUINT_TO_POINTER (rtx_ssrc),
+        GUINT_TO_POINTER (ssrc));
+  } else {
+    data = g_hash_table_lookup (rtx->ssrc_data, GUINT_TO_POINTER (ssrc));
+  }
+  return data;
+}
+
+/* Copy fixed header and extension. Add OSN before to copy payload
+ * Copy memory to avoid to manually copy each rtp buffer field.
+ */
+static GstBuffer *
+gst_rtp_rtx_buffer_new (GstRtpRtxSend * rtx, GstBuffer * buffer)
+{
+  GstMemory *mem = NULL;
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+  GstRTPBuffer new_rtp = GST_RTP_BUFFER_INIT;
+  GstBuffer *new_buffer = gst_buffer_new ();
+  GstMapInfo map;
+  guint payload_len = 0;
+  SSRCRtxData *data;
+  guint32 ssrc;
+  guint16 seqnum;
+  guint8 fmtp;
+
+  gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp);
+
+  /* get needed data from GstRtpRtxSend */
+  ssrc = gst_rtp_buffer_get_ssrc (&rtp);
+  data = gst_rtp_rtx_send_get_ssrc_data (rtx, ssrc);
+  ssrc = data->rtx_ssrc;
+  seqnum = data->next_seqnum++;
+  fmtp = GPOINTER_TO_UINT (g_hash_table_lookup (rtx->rtx_pt_map,
+          GUINT_TO_POINTER (gst_rtp_buffer_get_payload_type (&rtp))));
+
+  GST_DEBUG_OBJECT (rtx, "creating rtx buffer, orig seqnum: %u, "
+      "rtx seqnum: %u, rtx ssrc: %X", gst_rtp_buffer_get_seq (&rtp),
+      seqnum, ssrc);
+
+  /* gst_rtp_buffer_map does not map the payload so do it now */
+  gst_rtp_buffer_get_payload (&rtp);
+
+  /* copy fixed header */
+  mem = gst_memory_copy (rtp.map[0].memory, 0, rtp.size[0]);
+  gst_buffer_append_memory (new_buffer, mem);
+
+  /* copy extension if any */
+  if (rtp.size[1]) {
+    mem = gst_memory_copy (rtp.map[1].memory, 0, rtp.size[1]);
+    gst_buffer_append_memory (new_buffer, mem);
+  }
+
+  /* copy payload and add OSN just before */
+  payload_len = 2 + rtp.size[2];
+  mem = gst_allocator_alloc (NULL, payload_len, NULL);
+
+  gst_memory_map (mem, &map, GST_MAP_WRITE);
+  GST_WRITE_UINT16_BE (map.data, gst_rtp_buffer_get_seq (&rtp));
+  if (rtp.size[2])
+    memcpy (map.data + 2, rtp.data[2], rtp.size[2]);
+  gst_memory_unmap (mem, &map);
+  gst_buffer_append_memory (new_buffer, mem);
+
+  /* everything needed is copied */
+  gst_rtp_buffer_unmap (&rtp);
+
+  /* set ssrc, seqnum and fmtp */
+  gst_rtp_buffer_map (new_buffer, GST_MAP_WRITE, &new_rtp);
+  gst_rtp_buffer_set_ssrc (&new_rtp, ssrc);
+  gst_rtp_buffer_set_seq (&new_rtp, seqnum);
+  gst_rtp_buffer_set_payload_type (&new_rtp, fmtp);
+  /* RFC 4588: let other elements do the padding, as normal */
+  gst_rtp_buffer_set_padding (&new_rtp, FALSE);
+  gst_rtp_buffer_unmap (&new_rtp);
+
+  /* Copy over timestamps */
+  gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+
+  return new_buffer;
+}
+
+static gint
+buffer_queue_items_cmp (BufferQueueItem * a, BufferQueueItem * b,
+    gpointer user_data)
+{
+  /* gst_rtp_buffer_compare_seqnum returns the opposite of what we want,
+   * it returns negative when seqnum1 > seqnum2 and we want negative
+   * when b > a, i.e. a is smaller, so it comes first in the sequence */
+  return gst_rtp_buffer_compare_seqnum (b->seqnum, a->seqnum);
+}
+
+static gboolean
+gst_rtp_rtx_send_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstRtpRtxSend *rtx = GST_RTP_RTX_SEND (parent);
+  gboolean res;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CUSTOM_UPSTREAM:
+    {
+      const GstStructure *s = gst_event_get_structure (event);
+
+      /* This event usually comes from the downstream gstrtpsession */
+      if (gst_structure_has_name (s, "GstRTPRetransmissionRequest")) {
+        guint seqnum = 0;
+        guint ssrc = 0;
+        GstBuffer *rtx_buf = NULL;
+
+        /* retrieve seqnum of the packet that need to be retransmitted */
+        if (!gst_structure_get_uint (s, "seqnum", &seqnum))
+          seqnum = -1;
+
+        /* retrieve ssrc of the packet that need to be retransmitted */
+        if (!gst_structure_get_uint (s, "ssrc", &ssrc))
+          ssrc = -1;
+
+        GST_DEBUG_OBJECT (rtx, "got rtx request for seqnum: %u, ssrc: %X",
+            seqnum, ssrc);
+
+        GST_OBJECT_LOCK (rtx);
+        /* check if request is for us */
+        if (g_hash_table_contains (rtx->ssrc_data, GUINT_TO_POINTER (ssrc))) {
+          SSRCRtxData *data;
+          GSequenceIter *iter;
+          BufferQueueItem search_item;
+
+          /* update statistics */
+          ++rtx->num_rtx_requests;
+
+          data = gst_rtp_rtx_send_get_ssrc_data (rtx, ssrc);
+
+          search_item.seqnum = seqnum;
+          iter = g_sequence_lookup (data->queue, &search_item,
+              (GCompareDataFunc) buffer_queue_items_cmp, NULL);
+          if (iter) {
+            BufferQueueItem *item = g_sequence_get (iter);
+            GST_LOG_OBJECT (rtx, "found %u", item->seqnum);
+            rtx_buf = gst_rtp_rtx_buffer_new (rtx, item->buffer);
+          }
+        }
+        GST_OBJECT_UNLOCK (rtx);
+
+        if (rtx_buf)
+          gst_rtp_rtx_send_push_out (rtx, rtx_buf);
+
+        gst_event_unref (event);
+        res = TRUE;
+
+        /* This event usually comes from the downstream gstrtpsession */
+      } else if (gst_structure_has_name (s, "GstRTPCollision")) {
+        guint ssrc = 0;
+
+        if (!gst_structure_get_uint (s, "ssrc", &ssrc))
+          ssrc = -1;
+
+        GST_DEBUG_OBJECT (rtx, "got ssrc collision, ssrc: %X", ssrc);
+
+        GST_OBJECT_LOCK (rtx);
+
+        /* choose another ssrc for our retransmited stream */
+        if (g_hash_table_contains (rtx->rtx_ssrcs, GUINT_TO_POINTER (ssrc))) {
+          guint master_ssrc;
+          SSRCRtxData *data;
+
+          master_ssrc = GPOINTER_TO_UINT (g_hash_table_lookup (rtx->rtx_ssrcs,
+                  GUINT_TO_POINTER (ssrc)));
+          data = gst_rtp_rtx_send_get_ssrc_data (rtx, master_ssrc);
+
+          /* change rtx_ssrc and update the reverse map */
+          data->rtx_ssrc = gst_rtp_rtx_send_choose_ssrc (rtx, 0, FALSE);
+          g_hash_table_remove (rtx->rtx_ssrcs, GUINT_TO_POINTER (ssrc));
+          g_hash_table_insert (rtx->rtx_ssrcs,
+              GUINT_TO_POINTER (data->rtx_ssrc),
+              GUINT_TO_POINTER (master_ssrc));
+
+          GST_OBJECT_UNLOCK (rtx);
+
+          /* no need to forward to payloader because we make sure to have
+           * a different ssrc
+           */
+          gst_event_unref (event);
+          res = TRUE;
+        } else {
+          /* if master ssrc has collided, remove it from our data, as it
+           * is not going to be used any longer */
+          if (g_hash_table_contains (rtx->ssrc_data, GUINT_TO_POINTER (ssrc))) {
+            SSRCRtxData *data;
+            data = gst_rtp_rtx_send_get_ssrc_data (rtx, ssrc);
+            g_hash_table_remove (rtx->rtx_ssrcs,
+                GUINT_TO_POINTER (data->rtx_ssrc));
+            g_hash_table_remove (rtx->ssrc_data, GUINT_TO_POINTER (ssrc));
+          }
+
+          GST_OBJECT_UNLOCK (rtx);
+
+          /* forward event to payloader in case collided ssrc is
+           * master stream */
+          res = gst_pad_event_default (pad, parent, event);
+        }
+      } else {
+        res = gst_pad_event_default (pad, parent, event);
+      }
+      break;
+    }
+    default:
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+  return res;
+}
+
+static gboolean
+gst_rtp_rtx_send_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstRtpRtxSend *rtx = GST_RTP_RTX_SEND (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      gst_pad_push_event (rtx->srcpad, event);
+      gst_rtp_rtx_send_set_flushing (rtx, TRUE);
+      gst_pad_pause_task (rtx->srcpad);
+      return TRUE;
+    case GST_EVENT_FLUSH_STOP:
+      gst_pad_push_event (rtx->srcpad, event);
+      gst_rtp_rtx_send_set_flushing (rtx, FALSE);
+      gst_pad_start_task (rtx->srcpad,
+          (GstTaskFunction) gst_rtp_rtx_send_src_loop, rtx, NULL);
+      return TRUE;
+    case GST_EVENT_EOS:
+      GST_INFO_OBJECT (rtx, "Got EOS - enqueueing it");
+      gst_rtp_rtx_send_push_out (rtx, event);
+      return TRUE;
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+      GstStructure *s;
+      guint ssrc;
+      gint payload;
+      gpointer rtx_payload;
+      SSRCRtxData *data;
+
+      gst_event_parse_caps (event, &caps);
+
+      s = gst_caps_get_structure (caps, 0);
+      if (!gst_structure_get_uint (s, "ssrc", &ssrc))
+        ssrc = -1;
+      if (!gst_structure_get_int (s, "payload", &payload))
+        payload = -1;
+
+      if (payload == -1)
+        GST_WARNING_OBJECT (rtx, "No payload in caps");
+
+      GST_OBJECT_LOCK (rtx);
+      data = gst_rtp_rtx_send_get_ssrc_data (rtx, ssrc);
+      if (!g_hash_table_lookup_extended (rtx->rtx_pt_map,
+              GUINT_TO_POINTER (payload), NULL, &rtx_payload))
+        rtx_payload = GINT_TO_POINTER (-1);
+
+      if (GPOINTER_TO_INT (rtx_payload) == -1 && payload != -1)
+        GST_WARNING_OBJECT (rtx, "Payload %d not in rtx-pt-map", payload);
+
+      GST_DEBUG_OBJECT (rtx,
+          "got caps for payload: %d->%d, ssrc: %u->%u : %" GST_PTR_FORMAT,
+          payload, GPOINTER_TO_INT (rtx_payload), ssrc, data->rtx_ssrc, caps);
+
+      gst_structure_get_int (s, "clock-rate", &data->clock_rate);
+
+      /* The session might need to know the RTX ssrc */
+      caps = gst_caps_copy (caps);
+      gst_caps_set_simple (caps, "rtx-ssrc", G_TYPE_UINT, data->rtx_ssrc,
+          "rtx-seqnum-offset", G_TYPE_UINT, data->seqnum_base, NULL);
+
+      if (GPOINTER_TO_INT (rtx_payload) != -1)
+        gst_caps_set_simple (caps, "rtx-payload", G_TYPE_INT,
+            GPOINTER_TO_INT (rtx_payload), NULL);
+
+      GST_DEBUG_OBJECT (rtx, "got clock-rate from caps: %d for ssrc: %u",
+          data->clock_rate, ssrc);
+      GST_OBJECT_UNLOCK (rtx);
+
+      gst_event_unref (event);
+      event = gst_event_new_caps (caps);
+      gst_caps_unref (caps);
+      break;
+    }
+    default:
+      break;
+  }
+  return gst_pad_event_default (pad, parent, event);
+}
+
+/* like rtp_jitter_buffer_get_ts_diff() */
+static guint32
+gst_rtp_rtx_send_get_ts_diff (SSRCRtxData * data)
+{
+  guint64 high_ts, low_ts;
+  BufferQueueItem *high_buf, *low_buf;
+  guint32 result;
+
+  high_buf =
+      g_sequence_get (g_sequence_iter_prev (g_sequence_get_end_iter
+          (data->queue)));
+  low_buf = g_sequence_get (g_sequence_get_begin_iter (data->queue));
+
+  if (!high_buf || !low_buf || high_buf == low_buf)
+    return 0;
+
+  high_ts = high_buf->timestamp;
+  low_ts = low_buf->timestamp;
+
+  /* it needs to work if ts wraps */
+  if (high_ts >= low_ts) {
+    result = (guint32) (high_ts - low_ts);
+  } else {
+    result = (guint32) (high_ts + G_MAXUINT32 + 1 - low_ts);
+  }
+
+  /* return value in ms instead of clock ticks */
+  return (guint32) gst_util_uint64_scale_int (result, 1000, data->clock_rate);
+}
+
+/* Must be called with lock */
+static void
+process_buffer (GstRtpRtxSend * rtx, GstBuffer * buffer)
+{
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+  BufferQueueItem *item;
+  SSRCRtxData *data;
+  guint16 seqnum;
+  guint8 payload_type;
+  guint32 ssrc, rtptime;
+
+  /* read the information we want from the buffer */
+  gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp);
+  seqnum = gst_rtp_buffer_get_seq (&rtp);
+  payload_type = gst_rtp_buffer_get_payload_type (&rtp);
+  ssrc = gst_rtp_buffer_get_ssrc (&rtp);
+  rtptime = gst_rtp_buffer_get_timestamp (&rtp);
+  gst_rtp_buffer_unmap (&rtp);
+
+  GST_TRACE_OBJECT (rtx, "Processing buffer seqnum: %u, ssrc: %X", seqnum,
+      ssrc);
+
+  /* do not store the buffer if it's payload type is unknown */
+  if (g_hash_table_contains (rtx->rtx_pt_map, GUINT_TO_POINTER (payload_type))) {
+    data = gst_rtp_rtx_send_get_ssrc_data (rtx, ssrc);
+
+    /* add current rtp buffer to queue history */
+    item = g_slice_new0 (BufferQueueItem);
+    item->seqnum = seqnum;
+    item->timestamp = rtptime;
+    item->buffer = gst_buffer_ref (buffer);
+    g_sequence_append (data->queue, item);
+
+    /* remove oldest packets from history if they are too many */
+    if (rtx->max_size_packets) {
+      while (g_sequence_get_length (data->queue) > rtx->max_size_packets)
+        g_sequence_remove (g_sequence_get_begin_iter (data->queue));
+    }
+    if (rtx->max_size_time) {
+      while (gst_rtp_rtx_send_get_ts_diff (data) > rtx->max_size_time)
+        g_sequence_remove (g_sequence_get_begin_iter (data->queue));
+    }
+  }
+}
+
+static GstFlowReturn
+gst_rtp_rtx_send_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstRtpRtxSend *rtx = GST_RTP_RTX_SEND (parent);
+  GstFlowReturn ret;
+
+  GST_OBJECT_LOCK (rtx);
+  process_buffer (rtx, buffer);
+  GST_OBJECT_UNLOCK (rtx);
+  ret = gst_pad_push (rtx->srcpad, buffer);
+
+  return ret;
+}
+
+static gboolean
+process_buffer_from_list (GstBuffer ** buffer, guint idx, gpointer user_data)
+{
+  process_buffer (user_data, *buffer);
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_rtp_rtx_send_chain_list (GstPad * pad, GstObject * parent,
+    GstBufferList * list)
+{
+  GstRtpRtxSend *rtx = GST_RTP_RTX_SEND (parent);
+  GstFlowReturn ret;
+
+  GST_OBJECT_LOCK (rtx);
+  gst_buffer_list_foreach (list, process_buffer_from_list, rtx);
+  GST_OBJECT_UNLOCK (rtx);
+
+  ret = gst_pad_push_list (rtx->srcpad, list);
+
+  return ret;
+}
+
+static void
+gst_rtp_rtx_send_src_loop (GstRtpRtxSend * rtx)
+{
+  GstDataQueueItem *data;
+
+  if (gst_data_queue_pop (rtx->queue, &data)) {
+    GST_LOG_OBJECT (rtx, "pushing rtx buffer %p", data->object);
+
+    if (G_LIKELY (GST_IS_BUFFER (data->object))) {
+      GST_OBJECT_LOCK (rtx);
+      /* Update statistics just before pushing. */
+      rtx->num_rtx_packets++;
+      GST_OBJECT_UNLOCK (rtx);
+
+      gst_pad_push (rtx->srcpad, GST_BUFFER (data->object));
+    } else if (GST_IS_EVENT (data->object)) {
+      gst_pad_push_event (rtx->srcpad, GST_EVENT (data->object));
+
+      /* after EOS, we should not send any more buffers,
+       * even if there are more requests coming in */
+      if (GST_EVENT_TYPE (data->object) == GST_EVENT_EOS) {
+        gst_rtp_rtx_send_set_flushing (rtx, TRUE);
+      }
+    } else {
+      g_assert_not_reached ();
+    }
+
+    data->object = NULL;        /* we no longer own that object */
+    data->destroy (data);
+  } else {
+    GST_LOG_OBJECT (rtx, "flushing");
+    gst_pad_pause_task (rtx->srcpad);
+  }
+}
+
+static gboolean
+gst_rtp_rtx_send_activate_mode (GstPad * pad, GstObject * parent,
+    GstPadMode mode, gboolean active)
+{
+  GstRtpRtxSend *rtx = GST_RTP_RTX_SEND (parent);
+  gboolean ret = FALSE;
+
+  switch (mode) {
+    case GST_PAD_MODE_PUSH:
+      if (active) {
+        gst_rtp_rtx_send_set_flushing (rtx, FALSE);
+        ret = gst_pad_start_task (rtx->srcpad,
+            (GstTaskFunction) gst_rtp_rtx_send_src_loop, rtx, NULL);
+      } else {
+        gst_rtp_rtx_send_set_flushing (rtx, TRUE);
+        ret = gst_pad_stop_task (rtx->srcpad);
+      }
+      GST_INFO_OBJECT (rtx, "activate_mode: active %d, ret %d", active, ret);
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+static void
+gst_rtp_rtx_send_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstRtpRtxSend *rtx = GST_RTP_RTX_SEND (object);
+
+  switch (prop_id) {
+    case PROP_PAYLOAD_TYPE_MAP:
+      GST_OBJECT_LOCK (rtx);
+      g_value_set_boxed (value, rtx->rtx_pt_map_structure);
+      GST_OBJECT_UNLOCK (rtx);
+      break;
+    case PROP_MAX_SIZE_TIME:
+      GST_OBJECT_LOCK (rtx);
+      g_value_set_uint (value, rtx->max_size_time);
+      GST_OBJECT_UNLOCK (rtx);
+      break;
+    case PROP_MAX_SIZE_PACKETS:
+      GST_OBJECT_LOCK (rtx);
+      g_value_set_uint (value, rtx->max_size_packets);
+      GST_OBJECT_UNLOCK (rtx);
+      break;
+    case PROP_NUM_RTX_REQUESTS:
+      GST_OBJECT_LOCK (rtx);
+      g_value_set_uint (value, rtx->num_rtx_requests);
+      GST_OBJECT_UNLOCK (rtx);
+      break;
+    case PROP_NUM_RTX_PACKETS:
+      GST_OBJECT_LOCK (rtx);
+      g_value_set_uint (value, rtx->num_rtx_packets);
+      GST_OBJECT_UNLOCK (rtx);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+structure_to_hash_table (GQuark field_id, const GValue * value, gpointer hash)
+{
+  const gchar *field_str;
+  guint field_uint;
+  guint value_uint;
+
+  field_str = g_quark_to_string (field_id);
+  field_uint = atoi (field_str);
+  value_uint = g_value_get_uint (value);
+  g_hash_table_insert ((GHashTable *) hash, GUINT_TO_POINTER (field_uint),
+      GUINT_TO_POINTER (value_uint));
+
+  return TRUE;
+}
+
+static void
+gst_rtp_rtx_send_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstRtpRtxSend *rtx = GST_RTP_RTX_SEND (object);
+
+  switch (prop_id) {
+    case PROP_SSRC_MAP:
+      GST_OBJECT_LOCK (rtx);
+      if (rtx->external_ssrc_map)
+        gst_structure_free (rtx->external_ssrc_map);
+      rtx->external_ssrc_map = g_value_dup_boxed (value);
+      GST_OBJECT_UNLOCK (rtx);
+      break;
+    case PROP_PAYLOAD_TYPE_MAP:
+      GST_OBJECT_LOCK (rtx);
+      if (rtx->rtx_pt_map_structure)
+        gst_structure_free (rtx->rtx_pt_map_structure);
+      rtx->rtx_pt_map_structure = g_value_dup_boxed (value);
+      g_hash_table_remove_all (rtx->rtx_pt_map);
+      gst_structure_foreach (rtx->rtx_pt_map_structure, structure_to_hash_table,
+          rtx->rtx_pt_map);
+      GST_OBJECT_UNLOCK (rtx);
+      break;
+    case PROP_MAX_SIZE_TIME:
+      GST_OBJECT_LOCK (rtx);
+      rtx->max_size_time = g_value_get_uint (value);
+      GST_OBJECT_UNLOCK (rtx);
+      break;
+    case PROP_MAX_SIZE_PACKETS:
+      GST_OBJECT_LOCK (rtx);
+      rtx->max_size_packets = g_value_get_uint (value);
+      GST_OBJECT_UNLOCK (rtx);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStateChangeReturn
+gst_rtp_rtx_send_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstRtpRtxSend *rtx;
+
+  rtx = GST_RTP_RTX_SEND (element);
+
+  switch (transition) {
+    default:
+      break;
+  }
+
+  ret =
+      GST_ELEMENT_CLASS (gst_rtp_rtx_send_parent_class)->change_state (element,
+      transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_rtx_send_reset (rtx);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+gboolean
+gst_rtp_rtx_send_plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_rtx_send_debug, "rtprtxsend", 0,
+      "rtp retransmission sender");
+
+  return gst_element_register (plugin, "rtprtxsend", GST_RANK_NONE,
+      GST_TYPE_RTP_RTX_SEND);
+}
diff --git a/gst/rtpmanager/gstrtprtxsend.h b/gst/rtpmanager/gstrtprtxsend.h
new file mode 100644
index 0000000..5f084e8
--- /dev/null
+++ b/gst/rtpmanager/gstrtprtxsend.h
@@ -0,0 +1,84 @@
+/* RTP Retransmission sender element for GStreamer
+ *
+ * gstrtprtxsend.h:
+ *
+ * Copyright (C) 2013 Collabora Ltd.
+ *   @author Julien Isorce <julien.isorce@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_RTX_SEND_H__
+#define __GST_RTP_RTX_SEND_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/base/gstdataqueue.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_RTX_SEND (gst_rtp_rtx_send_get_type())
+#define GST_RTP_RTX_SEND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_RTX_SEND, GstRtpRtxSend))
+#define GST_RTP_RTX_SEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_RTX_SEND, GstRtpRtxSendClass))
+#define GST_RTP_RTX_SEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_RTX_SEND, GstRtpRtxSendClass))
+#define GST_IS_RTP_RTX_SEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_RTX_SEND))
+#define GST_IS_RTP_RTX_SEND_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_RTX_SEND))
+typedef struct _GstRtpRtxSend GstRtpRtxSend;
+typedef struct _GstRtpRtxSendClass GstRtpRtxSendClass;
+
+struct _GstRtpRtxSend
+{
+  GstElement element;
+
+  /* pad */
+  GstPad *sinkpad;
+  GstPad *srcpad;
+
+  /* rtp packets that will be pushed out */
+  GstDataQueue *queue;
+
+  /* ssrc -> SSRCRtxData */
+  GHashTable *ssrc_data;
+  /* rtx ssrc -> master ssrc */
+  GHashTable *rtx_ssrcs;
+
+  /* master ssrc -> rtx ssrc (property) */
+  GstStructure *external_ssrc_map;
+
+  /* orig pt (uint) -> rtx pt (uint) */
+  GHashTable *rtx_pt_map;
+  /* orig pt (string) -> rtx pt (uint) */
+  GstStructure *rtx_pt_map_structure;
+
+  /* buffering control properties */
+  guint max_size_time;
+  guint max_size_packets;
+
+  /* statistics */
+  guint num_rtx_requests;
+  guint num_rtx_packets;
+};
+
+struct _GstRtpRtxSendClass
+{
+  GstElementClass parent_class;
+};
+
+
+GType gst_rtp_rtx_send_get_type (void);
+gboolean gst_rtp_rtx_send_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_RTX_SEND_H__ */
diff --git a/gst/rtpmanager/gstrtpsession.c b/gst/rtpmanager/gstrtpsession.c
new file mode 100644
index 0000000..4d8922a
--- /dev/null
+++ b/gst/rtpmanager/gstrtpsession.c
@@ -0,0 +1,2719 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpsession
+ * @see_also: rtpjitterbuffer, rtpbin, rtpptdemux, rtpssrcdemux
+ *
+ * The RTP session manager models participants with unique SSRC in an RTP
+ * session. This session can be used to send and receive RTP and RTCP packets.
+ * Based on what REQUEST pads are requested from the session manager, specific
+ * functionality can be activated.
+ *
+ * The session manager currently implements RFC 3550 including:
+ * <itemizedlist>
+ *   <listitem>
+ *     <para>RTP packet validation based on consecutive sequence numbers.</para>
+ *   </listitem>
+ *   <listitem>
+ *     <para>Maintainance of the SSRC participant database.</para>
+ *   </listitem>
+ *   <listitem>
+ *     <para>Keeping per participant statistics based on received RTCP packets.</para>
+ *   </listitem>
+ *   <listitem>
+ *     <para>Scheduling of RR/SR RTCP packets.</para>
+ *   </listitem>
+ *   <listitem>
+ *     <para>Support for multiple sender SSRC.</para>
+ *   </listitem>
+ * </itemizedlist>
+ *
+ * The rtpsession will not demux packets based on SSRC or payload type, nor will
+ * it correct for packet reordering and jitter. Use #GstRtpsSrcDemux,
+ * #GstRtpPtDemux and GstRtpJitterBuffer in addition to #GstRtpSession to
+ * perform these tasks. It is usually a good idea to use #GstRtpBin, which
+ * combines all these features in one element.
+ *
+ * To use #GstRtpSession as an RTP receiver, request a recv_rtp_sink pad, which will
+ * automatically create recv_rtp_src pad. Data received on the recv_rtp_sink pad
+ * will be processed in the session and after being validated forwarded on the
+ * recv_rtp_src pad.
+ *
+ * To also use #GstRtpSession as an RTCP receiver, request a recv_rtcp_sink pad,
+ * which will automatically create a sync_src pad. Packets received on the RTCP
+ * pad will be used by the session manager to update the stats and database of
+ * the other participants. SR packets will be forwarded on the sync_src pad
+ * so that they can be used to perform inter-stream synchronisation when needed.
+ *
+ * If you want the session manager to generate and send RTCP packets, request
+ * the send_rtcp_src pad. Packet pushed on this pad contain SR/RR RTCP reports
+ * that should be sent to all participants in the session.
+ *
+ * To use #GstRtpSession as a sender, request a send_rtp_sink pad, which will
+ * automatically create a send_rtp_src pad. The session manager will
+ * forward the packets on the send_rtp_src pad after updating its internal state.
+ *
+ * The session manager needs the clock-rate of the payload types it is handling
+ * and will signal the #GstRtpSession::request-pt-map signal when it needs such a
+ * mapping. One can clear the cached values with the #GstRtpSession::clear-pt-map
+ * signal.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 udpsrc port=5000 caps="application/x-rtp, ..." ! .recv_rtp_sink rtpsession .recv_rtp_src ! rtptheoradepay ! theoradec ! xvimagesink
+ * ]| Receive theora RTP packets from port 5000 and send them to the depayloader,
+ * decoder and display. Note that the application/x-rtp caps on udpsrc should be
+ * configured based on some negotiation process such as RTSP for this pipeline
+ * to work correctly.
+ * |[
+ * gst-launch-1.0 udpsrc port=5000 caps="application/x-rtp, ..." ! .recv_rtp_sink rtpsession name=session \
+ *        .recv_rtp_src ! rtptheoradepay ! theoradec ! xvimagesink \
+ *     udpsrc port=5001 caps="application/x-rtcp" ! session.recv_rtcp_sink
+ * ]| Receive theora RTP packets from port 5000 and send them to the depayloader,
+ * decoder and display. Receive RTCP packets from port 5001 and process them in
+ * the session manager.
+ * Note that the application/x-rtp caps on udpsrc should be
+ * configured based on some negotiation process such as RTSP for this pipeline
+ * to work correctly.
+ * |[
+ * gst-launch-1.0 videotestsrc ! theoraenc ! rtptheorapay ! .send_rtp_sink rtpsession .send_rtp_src ! udpsink port=5000
+ * ]| Send theora RTP packets through the session manager and out on UDP port
+ * 5000.
+ * |[
+ * gst-launch-1.0 videotestsrc ! theoraenc ! rtptheorapay ! .send_rtp_sink rtpsession name=session .send_rtp_src \
+ *     ! udpsink port=5000  session.send_rtcp_src ! udpsink port=5001
+ * ]| Send theora RTP packets through the session manager and out on UDP port
+ * 5000. Send RTCP packets on port 5001. Note that this pipeline will not preroll
+ * correctly because the second udpsink will not preroll correctly (no RTCP
+ * packets are sent in the PAUSED state). Applications should manually set and
+ * keep (see gst_element_set_locked_state()) the RTCP udpsink to the PLAYING state.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <gst/glib-compat-private.h>
+
+#include "gstrtpsession.h"
+#include "rtpsession.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_session_debug);
+#define GST_CAT_DEFAULT gst_rtp_session_debug
+
+GType
+gst_rtp_ntp_time_source_get_type (void)
+{
+  static GType type = 0;
+  static const GEnumValue values[] = {
+    {GST_RTP_NTP_TIME_SOURCE_NTP, "NTP time based on realtime clock", "ntp"},
+    {GST_RTP_NTP_TIME_SOURCE_UNIX, "UNIX time based on realtime clock", "unix"},
+    {GST_RTP_NTP_TIME_SOURCE_RUNNING_TIME,
+          "Running time based on pipeline clock",
+        "running-time"},
+    {GST_RTP_NTP_TIME_SOURCE_CLOCK_TIME, "Pipeline clock time", "clock-time"},
+    {0, NULL, NULL},
+  };
+
+  if (!type) {
+    type = g_enum_register_static ("GstRtpNtpTimeSource", values);
+  }
+  return type;
+}
+
+/* sink pads */
+static GstStaticPadTemplate rtpsession_recv_rtp_sink_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static GstStaticPadTemplate rtpsession_recv_rtcp_sink_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("application/x-rtcp")
+    );
+
+static GstStaticPadTemplate rtpsession_send_rtp_sink_template =
+GST_STATIC_PAD_TEMPLATE ("send_rtp_sink",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+/* src pads */
+static GstStaticPadTemplate rtpsession_recv_rtp_src_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtp_src",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static GstStaticPadTemplate rtpsession_sync_src_template =
+GST_STATIC_PAD_TEMPLATE ("sync_src",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("application/x-rtcp")
+    );
+
+static GstStaticPadTemplate rtpsession_send_rtp_src_template =
+GST_STATIC_PAD_TEMPLATE ("send_rtp_src",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static GstStaticPadTemplate rtpsession_send_rtcp_src_template =
+GST_STATIC_PAD_TEMPLATE ("send_rtcp_src",
+    GST_PAD_SRC,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("application/x-rtcp")
+    );
+
+/* signals and args */
+enum
+{
+  SIGNAL_REQUEST_PT_MAP,
+  SIGNAL_CLEAR_PT_MAP,
+
+  SIGNAL_ON_NEW_SSRC,
+  SIGNAL_ON_SSRC_COLLISION,
+  SIGNAL_ON_SSRC_VALIDATED,
+  SIGNAL_ON_SSRC_ACTIVE,
+  SIGNAL_ON_SSRC_SDES,
+  SIGNAL_ON_BYE_SSRC,
+  SIGNAL_ON_BYE_TIMEOUT,
+  SIGNAL_ON_TIMEOUT,
+  SIGNAL_ON_SENDER_TIMEOUT,
+  SIGNAL_ON_NEW_SENDER_SSRC,
+  SIGNAL_ON_SENDER_SSRC_ACTIVE,
+  LAST_SIGNAL
+};
+
+#define DEFAULT_BANDWIDTH            0
+#define DEFAULT_RTCP_FRACTION        RTP_STATS_RTCP_FRACTION
+#define DEFAULT_RTCP_RR_BANDWIDTH    -1
+#define DEFAULT_RTCP_RS_BANDWIDTH    -1
+#define DEFAULT_SDES                 NULL
+#define DEFAULT_NUM_SOURCES          0
+#define DEFAULT_NUM_ACTIVE_SOURCES   0
+#define DEFAULT_USE_PIPELINE_CLOCK   FALSE
+#define DEFAULT_RTCP_MIN_INTERVAL    (RTP_STATS_MIN_INTERVAL * GST_SECOND)
+#define DEFAULT_PROBATION            RTP_DEFAULT_PROBATION
+#define DEFAULT_MAX_DROPOUT_TIME     60000
+#define DEFAULT_MAX_MISORDER_TIME    2000
+#define DEFAULT_RTP_PROFILE          GST_RTP_PROFILE_AVP
+#define DEFAULT_NTP_TIME_SOURCE      GST_RTP_NTP_TIME_SOURCE_NTP
+#define DEFAULT_RTCP_SYNC_SEND_TIME  TRUE
+
+enum
+{
+  PROP_0,
+  PROP_BANDWIDTH,
+  PROP_RTCP_FRACTION,
+  PROP_RTCP_RR_BANDWIDTH,
+  PROP_RTCP_RS_BANDWIDTH,
+  PROP_SDES,
+  PROP_NUM_SOURCES,
+  PROP_NUM_ACTIVE_SOURCES,
+  PROP_INTERNAL_SESSION,
+  PROP_USE_PIPELINE_CLOCK,
+  PROP_RTCP_MIN_INTERVAL,
+  PROP_PROBATION,
+  PROP_MAX_DROPOUT_TIME,
+  PROP_MAX_MISORDER_TIME,
+  PROP_STATS,
+  PROP_RTP_PROFILE,
+  PROP_NTP_TIME_SOURCE,
+  PROP_RTCP_SYNC_SEND_TIME
+};
+
+#define GST_RTP_SESSION_GET_PRIVATE(obj)  \
+	   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTP_SESSION, GstRtpSessionPrivate))
+
+#define GST_RTP_SESSION_LOCK(sess)   g_mutex_lock (&(sess)->priv->lock)
+#define GST_RTP_SESSION_UNLOCK(sess) g_mutex_unlock (&(sess)->priv->lock)
+
+#define GST_RTP_SESSION_WAIT(sess)   g_cond_wait (&(sess)->priv->cond, &(sess)->priv->lock)
+#define GST_RTP_SESSION_SIGNAL(sess) g_cond_signal (&(sess)->priv->cond)
+
+struct _GstRtpSessionPrivate
+{
+  GMutex lock;
+  GCond cond;
+  GstClock *sysclock;
+
+  RTPSession *session;
+
+  /* thread for sending out RTCP */
+  GstClockID id;
+  gboolean stop_thread;
+  GThread *thread;
+  gboolean thread_stopped;
+  gboolean wait_send;
+
+  /* caps mapping */
+  GHashTable *ptmap;
+
+  GstClockTime send_latency;
+
+  gboolean use_pipeline_clock;
+  GstRtpNtpTimeSource ntp_time_source;
+  gboolean rtcp_sync_send_time;
+
+  guint rtx_count;
+};
+
+/* callbacks to handle actions from the session manager */
+static GstFlowReturn gst_rtp_session_process_rtp (RTPSession * sess,
+    RTPSource * src, GstBuffer * buffer, gpointer user_data);
+static GstFlowReturn gst_rtp_session_send_rtp (RTPSession * sess,
+    RTPSource * src, gpointer data, gpointer user_data);
+static GstFlowReturn gst_rtp_session_send_rtcp (RTPSession * sess,
+    RTPSource * src, GstBuffer * buffer, gboolean eos, gpointer user_data);
+static GstFlowReturn gst_rtp_session_sync_rtcp (RTPSession * sess,
+    GstBuffer * buffer, gpointer user_data);
+static gint gst_rtp_session_clock_rate (RTPSession * sess, guint8 payload,
+    gpointer user_data);
+static void gst_rtp_session_reconsider (RTPSession * sess, gpointer user_data);
+static void gst_rtp_session_request_key_unit (RTPSession * sess, guint32 ssrc,
+    gboolean all_headers, gpointer user_data);
+static GstClockTime gst_rtp_session_request_time (RTPSession * session,
+    gpointer user_data);
+static void gst_rtp_session_notify_nack (RTPSession * sess,
+    guint16 seqnum, guint16 blp, guint32 ssrc, gpointer user_data);
+static void gst_rtp_session_reconfigure (RTPSession * sess, gpointer user_data);
+
+static RTPSessionCallbacks callbacks = {
+  gst_rtp_session_process_rtp,
+  gst_rtp_session_send_rtp,
+  gst_rtp_session_sync_rtcp,
+  gst_rtp_session_send_rtcp,
+  gst_rtp_session_clock_rate,
+  gst_rtp_session_reconsider,
+  gst_rtp_session_request_key_unit,
+  gst_rtp_session_request_time,
+  gst_rtp_session_notify_nack,
+  gst_rtp_session_reconfigure
+};
+
+/* GObject vmethods */
+static void gst_rtp_session_finalize (GObject * object);
+static void gst_rtp_session_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_session_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+/* GstElement vmethods */
+static GstStateChangeReturn gst_rtp_session_change_state (GstElement * element,
+    GstStateChange transition);
+static GstPad *gst_rtp_session_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
+static void gst_rtp_session_release_pad (GstElement * element, GstPad * pad);
+
+static gboolean gst_rtp_session_sink_setcaps (GstPad * pad,
+    GstRtpSession * rtpsession, GstCaps * caps);
+static gboolean gst_rtp_session_setcaps_send_rtp (GstPad * pad,
+    GstRtpSession * rtpsession, GstCaps * caps);
+
+static void gst_rtp_session_clear_pt_map (GstRtpSession * rtpsession);
+
+static GstStructure *gst_rtp_session_create_stats (GstRtpSession * rtpsession);
+
+static guint gst_rtp_session_signals[LAST_SIGNAL] = { 0 };
+
+static void
+on_new_ssrc (RTPSession * session, RTPSource * src, GstRtpSession * sess)
+{
+  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_NEW_SSRC], 0,
+      src->ssrc);
+}
+
+static void
+on_ssrc_collision (RTPSession * session, RTPSource * src, GstRtpSession * sess)
+{
+  GstPad *send_rtp_sink;
+
+  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_SSRC_COLLISION], 0,
+      src->ssrc);
+
+  GST_RTP_SESSION_LOCK (sess);
+  if ((send_rtp_sink = sess->send_rtp_sink))
+    gst_object_ref (send_rtp_sink);
+  GST_RTP_SESSION_UNLOCK (sess);
+
+  if (send_rtp_sink) {
+    GstStructure *structure;
+    GstEvent *event;
+    RTPSource *internal_src;
+    guint32 suggested_ssrc;
+
+    structure = gst_structure_new ("GstRTPCollision", "ssrc", G_TYPE_UINT,
+        (guint) src->ssrc, NULL);
+
+    /* if there is no source using the suggested ssrc, most probably because
+     * this ssrc has just collided, suggest upstream to use it */
+    suggested_ssrc = rtp_session_suggest_ssrc (session, NULL);
+    internal_src = rtp_session_get_source_by_ssrc (session, suggested_ssrc);
+    if (!internal_src)
+      gst_structure_set (structure, "suggested-ssrc", G_TYPE_UINT,
+          (guint) suggested_ssrc, NULL);
+    else
+      g_object_unref (internal_src);
+
+    event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, structure);
+    gst_pad_push_event (send_rtp_sink, event);
+    gst_object_unref (send_rtp_sink);
+  }
+}
+
+static void
+on_ssrc_validated (RTPSession * session, RTPSource * src, GstRtpSession * sess)
+{
+  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_SSRC_VALIDATED], 0,
+      src->ssrc);
+}
+
+static void
+on_ssrc_active (RTPSession * session, RTPSource * src, GstRtpSession * sess)
+{
+  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_SSRC_ACTIVE], 0,
+      src->ssrc);
+}
+
+static void
+on_ssrc_sdes (RTPSession * session, RTPSource * src, GstRtpSession * sess)
+{
+  GstStructure *s;
+  GstMessage *m;
+
+  /* convert the new SDES info into a message */
+  RTP_SESSION_LOCK (session);
+  g_object_get (src, "sdes", &s, NULL);
+  RTP_SESSION_UNLOCK (session);
+
+  m = gst_message_new_custom (GST_MESSAGE_ELEMENT, GST_OBJECT (sess), s);
+  gst_element_post_message (GST_ELEMENT_CAST (sess), m);
+
+  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_SSRC_SDES], 0,
+      src->ssrc);
+}
+
+static void
+on_bye_ssrc (RTPSession * session, RTPSource * src, GstRtpSession * sess)
+{
+  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_BYE_SSRC], 0,
+      src->ssrc);
+}
+
+static void
+on_bye_timeout (RTPSession * session, RTPSource * src, GstRtpSession * sess)
+{
+  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_BYE_TIMEOUT], 0,
+      src->ssrc);
+}
+
+static void
+on_timeout (RTPSession * session, RTPSource * src, GstRtpSession * sess)
+{
+  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_TIMEOUT], 0,
+      src->ssrc);
+}
+
+static void
+on_sender_timeout (RTPSession * session, RTPSource * src, GstRtpSession * sess)
+{
+  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_SENDER_TIMEOUT], 0,
+      src->ssrc);
+}
+
+static void
+on_new_sender_ssrc (RTPSession * session, RTPSource * src, GstRtpSession * sess)
+{
+  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_NEW_SENDER_SSRC], 0,
+      src->ssrc);
+}
+
+static void
+on_sender_ssrc_active (RTPSession * session, RTPSource * src,
+    GstRtpSession * sess)
+{
+  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_SENDER_SSRC_ACTIVE], 0,
+      src->ssrc);
+}
+
+static void
+on_notify_stats (RTPSession * session, GParamSpec * spec,
+    GstRtpSession * rtpsession)
+{
+  g_object_notify (G_OBJECT (rtpsession), "stats");
+}
+
+#define gst_rtp_session_parent_class parent_class
+G_DEFINE_TYPE (GstRtpSession, gst_rtp_session, GST_TYPE_ELEMENT);
+
+static void
+gst_rtp_session_class_init (GstRtpSessionClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  g_type_class_add_private (klass, sizeof (GstRtpSessionPrivate));
+
+  gobject_class->finalize = gst_rtp_session_finalize;
+  gobject_class->set_property = gst_rtp_session_set_property;
+  gobject_class->get_property = gst_rtp_session_get_property;
+
+  /**
+   * GstRtpSession::request-pt-map:
+   * @sess: the object which received the signal
+   * @pt: the pt
+   *
+   * Request the payload type as #GstCaps for @pt.
+   */
+  gst_rtp_session_signals[SIGNAL_REQUEST_PT_MAP] =
+      g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass, request_pt_map),
+      NULL, NULL, g_cclosure_marshal_generic, GST_TYPE_CAPS, 1, G_TYPE_UINT);
+  /**
+   * GstRtpSession::clear-pt-map:
+   * @sess: the object which received the signal
+   *
+   * Clear the cached pt-maps requested with #GstRtpSession::request-pt-map.
+   */
+  gst_rtp_session_signals[SIGNAL_CLEAR_PT_MAP] =
+      g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpSessionClass, clear_pt_map),
+      NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
+
+  /**
+   * GstRtpSession::on-new-ssrc:
+   * @sess: the object which received the signal
+   * @ssrc: the SSRC
+   *
+   * Notify of a new SSRC that entered @session.
+   */
+  gst_rtp_session_signals[SIGNAL_ON_NEW_SSRC] =
+      g_signal_new ("on-new-ssrc", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass, on_new_ssrc),
+      NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
+  /**
+   * GstRtpSession::on-ssrc_collision:
+   * @sess: the object which received the signal
+   * @ssrc: the SSRC
+   *
+   * Notify when we have an SSRC collision
+   */
+  gst_rtp_session_signals[SIGNAL_ON_SSRC_COLLISION] =
+      g_signal_new ("on-ssrc-collision", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass,
+          on_ssrc_collision), NULL, NULL, g_cclosure_marshal_VOID__UINT,
+      G_TYPE_NONE, 1, G_TYPE_UINT);
+  /**
+   * GstRtpSession::on-ssrc_validated:
+   * @sess: the object which received the signal
+   * @ssrc: the SSRC
+   *
+   * Notify of a new SSRC that became validated.
+   */
+  gst_rtp_session_signals[SIGNAL_ON_SSRC_VALIDATED] =
+      g_signal_new ("on-ssrc-validated", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass,
+          on_ssrc_validated), NULL, NULL, g_cclosure_marshal_VOID__UINT,
+      G_TYPE_NONE, 1, G_TYPE_UINT);
+  /**
+   * GstRtpSession::on-ssrc-active:
+   * @sess: the object which received the signal
+   * @ssrc: the SSRC
+   *
+   * Notify of a SSRC that is active, i.e., sending RTCP.
+   */
+  gst_rtp_session_signals[SIGNAL_ON_SSRC_ACTIVE] =
+      g_signal_new ("on-ssrc-active", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass,
+          on_ssrc_active), NULL, NULL, g_cclosure_marshal_VOID__UINT,
+      G_TYPE_NONE, 1, G_TYPE_UINT);
+  /**
+   * GstRtpSession::on-ssrc-sdes:
+   * @session: the object which received the signal
+   * @src: the SSRC
+   *
+   * Notify that a new SDES was received for SSRC.
+   */
+  gst_rtp_session_signals[SIGNAL_ON_SSRC_SDES] =
+      g_signal_new ("on-ssrc-sdes", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass, on_ssrc_sdes),
+      NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
+
+  /**
+   * GstRtpSession::on-bye-ssrc:
+   * @sess: the object which received the signal
+   * @ssrc: the SSRC
+   *
+   * Notify of an SSRC that became inactive because of a BYE packet.
+   */
+  gst_rtp_session_signals[SIGNAL_ON_BYE_SSRC] =
+      g_signal_new ("on-bye-ssrc", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass, on_bye_ssrc),
+      NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
+  /**
+   * GstRtpSession::on-bye-timeout:
+   * @sess: the object which received the signal
+   * @ssrc: the SSRC
+   *
+   * Notify of an SSRC that has timed out because of BYE
+   */
+  gst_rtp_session_signals[SIGNAL_ON_BYE_TIMEOUT] =
+      g_signal_new ("on-bye-timeout", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass, on_bye_timeout),
+      NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
+  /**
+   * GstRtpSession::on-timeout:
+   * @sess: the object which received the signal
+   * @ssrc: the SSRC
+   *
+   * Notify of an SSRC that has timed out
+   */
+  gst_rtp_session_signals[SIGNAL_ON_TIMEOUT] =
+      g_signal_new ("on-timeout", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass, on_timeout),
+      NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
+  /**
+   * GstRtpSession::on-sender-timeout:
+   * @sess: the object which received the signal
+   * @ssrc: the SSRC
+   *
+   * Notify of a sender SSRC that has timed out and became a receiver
+   */
+  gst_rtp_session_signals[SIGNAL_ON_SENDER_TIMEOUT] =
+      g_signal_new ("on-sender-timeout", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass,
+          on_sender_timeout), NULL, NULL, g_cclosure_marshal_VOID__UINT,
+      G_TYPE_NONE, 1, G_TYPE_UINT);
+
+  /**
+   * GstRtpSession::on-new-sender-ssrc:
+   * @sess: the object which received the signal
+   * @ssrc: the sender SSRC
+   *
+   * Notify of a new sender SSRC that entered @session.
+   *
+   * Since: 1.8
+   */
+  gst_rtp_session_signals[SIGNAL_ON_NEW_SENDER_SSRC] =
+      g_signal_new ("on-new-sender-ssrc", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass, on_new_ssrc),
+      NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
+
+  /**
+   * GstRtpSession::on-sender-ssrc-active:
+   * @sess: the object which received the signal
+   * @ssrc: the sender SSRC
+   *
+   * Notify of a sender SSRC that is active, i.e., sending RTCP.
+   *
+   * Since: 1.8
+   */
+  gst_rtp_session_signals[SIGNAL_ON_SENDER_SSRC_ACTIVE] =
+      g_signal_new ("on-sender-ssrc-active", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass,
+          on_ssrc_active), NULL, NULL, g_cclosure_marshal_VOID__UINT,
+      G_TYPE_NONE, 1, G_TYPE_UINT);
+
+  g_object_class_install_property (gobject_class, PROP_BANDWIDTH,
+      g_param_spec_double ("bandwidth", "Bandwidth",
+          "The bandwidth of the session in bytes per second (0 for auto-discover)",
+          0.0, G_MAXDOUBLE, DEFAULT_BANDWIDTH,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RTCP_FRACTION,
+      g_param_spec_double ("rtcp-fraction", "RTCP Fraction",
+          "The RTCP bandwidth of the session in bytes per second "
+          "(or as a real fraction of the RTP bandwidth if < 1.0)",
+          0.0, G_MAXDOUBLE, DEFAULT_RTCP_FRACTION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RTCP_RR_BANDWIDTH,
+      g_param_spec_int ("rtcp-rr-bandwidth", "RTCP RR bandwidth",
+          "The RTCP bandwidth used for receivers in bytes per second (-1 = default)",
+          -1, G_MAXINT, DEFAULT_RTCP_RR_BANDWIDTH,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RTCP_RS_BANDWIDTH,
+      g_param_spec_int ("rtcp-rs-bandwidth", "RTCP RS bandwidth",
+          "The RTCP bandwidth used for senders in bytes per second (-1 = default)",
+          -1, G_MAXINT, DEFAULT_RTCP_RS_BANDWIDTH,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_SDES,
+      g_param_spec_boxed ("sdes", "SDES",
+          "The SDES items of this session",
+          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NUM_SOURCES,
+      g_param_spec_uint ("num-sources", "Num Sources",
+          "The number of sources in the session", 0, G_MAXUINT,
+          DEFAULT_NUM_SOURCES, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NUM_ACTIVE_SOURCES,
+      g_param_spec_uint ("num-active-sources", "Num Active Sources",
+          "The number of active sources in the session", 0, G_MAXUINT,
+          DEFAULT_NUM_ACTIVE_SOURCES,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_INTERNAL_SESSION,
+      g_param_spec_object ("internal-session", "Internal Session",
+          "The internal RTPSession object", RTP_TYPE_SESSION,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_USE_PIPELINE_CLOCK,
+      g_param_spec_boolean ("use-pipeline-clock", "Use pipeline clock",
+          "Use the pipeline running-time to set the NTP time in the RTCP SR messages "
+          "(DEPRECATED: Use ntp-time-source property)",
+          DEFAULT_USE_PIPELINE_CLOCK,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
+
+  g_object_class_install_property (gobject_class, PROP_RTCP_MIN_INTERVAL,
+      g_param_spec_uint64 ("rtcp-min-interval", "Minimum RTCP interval",
+          "Minimum interval between Regular RTCP packet (in ns)",
+          0, G_MAXUINT64, DEFAULT_RTCP_MIN_INTERVAL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_PROBATION,
+      g_param_spec_uint ("probation", "Number of probations",
+          "Consecutive packet sequence numbers to accept the source",
+          0, G_MAXUINT, DEFAULT_PROBATION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_DROPOUT_TIME,
+      g_param_spec_uint ("max-dropout-time", "Max dropout time",
+          "The maximum time (milliseconds) of missing packets tolerated.",
+          0, G_MAXUINT, DEFAULT_MAX_DROPOUT_TIME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_MISORDER_TIME,
+      g_param_spec_uint ("max-misorder-time", "Max misorder time",
+          "The maximum time (milliseconds) of misordered packets tolerated.",
+          0, G_MAXUINT, DEFAULT_MAX_MISORDER_TIME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpSession::stats:
+   *
+   * Various session statistics. This property returns a GstStructure
+   * with name application/x-rtp-session-stats with the following fields:
+   *
+   *  "rtx-count"       G_TYPE_UINT   The number of retransmission events
+   *      received from downstream (in receiver mode)
+   *  "rtx-drop-count"  G_TYPE_UINT   The number of retransmission events
+   *      dropped (due to bandwidth constraints)
+   *  "sent-nack-count" G_TYPE_UINT   Number of NACKs sent
+   *  "recv-nack-count" G_TYPE_UINT   Number of NACKs received
+   *  "source-stats"    G_TYPE_BOXED  GValueArray of #RTPSource::stats for all
+   *      RTP sources (Since 1.8)
+   *
+   * Since: 1.4
+   */
+  g_object_class_install_property (gobject_class, PROP_STATS,
+      g_param_spec_boxed ("stats", "Statistics",
+          "Various statistics", GST_TYPE_STRUCTURE,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RTP_PROFILE,
+      g_param_spec_enum ("rtp-profile", "RTP Profile",
+          "RTP profile to use", GST_TYPE_RTP_PROFILE, DEFAULT_RTP_PROFILE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NTP_TIME_SOURCE,
+      g_param_spec_enum ("ntp-time-source", "NTP Time Source",
+          "NTP time source for RTCP packets",
+          gst_rtp_ntp_time_source_get_type (), DEFAULT_NTP_TIME_SOURCE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RTCP_SYNC_SEND_TIME,
+      g_param_spec_boolean ("rtcp-sync-send-time", "RTCP Sync Send Time",
+          "Use send time or capture time for RTCP sync "
+          "(TRUE = send time, FALSE = capture time)",
+          DEFAULT_RTCP_SYNC_SEND_TIME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_rtp_session_change_state);
+  gstelement_class->request_new_pad =
+      GST_DEBUG_FUNCPTR (gst_rtp_session_request_new_pad);
+  gstelement_class->release_pad =
+      GST_DEBUG_FUNCPTR (gst_rtp_session_release_pad);
+
+  klass->clear_pt_map = GST_DEBUG_FUNCPTR (gst_rtp_session_clear_pt_map);
+
+  /* sink pads */
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &rtpsession_recv_rtp_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &rtpsession_recv_rtcp_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &rtpsession_send_rtp_sink_template);
+
+  /* src pads */
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &rtpsession_recv_rtp_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &rtpsession_sync_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &rtpsession_send_rtp_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &rtpsession_send_rtcp_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP Session",
+      "Filter/Network/RTP",
+      "Implement an RTP session", "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_session_debug,
+      "rtpsession", 0, "RTP Session");
+}
+
+static void
+gst_rtp_session_init (GstRtpSession * rtpsession)
+{
+  rtpsession->priv = GST_RTP_SESSION_GET_PRIVATE (rtpsession);
+  g_mutex_init (&rtpsession->priv->lock);
+  g_cond_init (&rtpsession->priv->cond);
+  rtpsession->priv->sysclock = gst_system_clock_obtain ();
+  rtpsession->priv->session = rtp_session_new ();
+  rtpsession->priv->use_pipeline_clock = DEFAULT_USE_PIPELINE_CLOCK;
+  rtpsession->priv->rtcp_sync_send_time = DEFAULT_RTCP_SYNC_SEND_TIME;
+
+  /* configure callbacks */
+  rtp_session_set_callbacks (rtpsession->priv->session, &callbacks, rtpsession);
+  /* configure signals */
+  g_signal_connect (rtpsession->priv->session, "on-new-ssrc",
+      (GCallback) on_new_ssrc, rtpsession);
+  g_signal_connect (rtpsession->priv->session, "on-ssrc-collision",
+      (GCallback) on_ssrc_collision, rtpsession);
+  g_signal_connect (rtpsession->priv->session, "on-ssrc-validated",
+      (GCallback) on_ssrc_validated, rtpsession);
+  g_signal_connect (rtpsession->priv->session, "on-ssrc-active",
+      (GCallback) on_ssrc_active, rtpsession);
+  g_signal_connect (rtpsession->priv->session, "on-ssrc-sdes",
+      (GCallback) on_ssrc_sdes, rtpsession);
+  g_signal_connect (rtpsession->priv->session, "on-bye-ssrc",
+      (GCallback) on_bye_ssrc, rtpsession);
+  g_signal_connect (rtpsession->priv->session, "on-bye-timeout",
+      (GCallback) on_bye_timeout, rtpsession);
+  g_signal_connect (rtpsession->priv->session, "on-timeout",
+      (GCallback) on_timeout, rtpsession);
+  g_signal_connect (rtpsession->priv->session, "on-sender-timeout",
+      (GCallback) on_sender_timeout, rtpsession);
+  g_signal_connect (rtpsession->priv->session, "on-new-sender-ssrc",
+      (GCallback) on_new_sender_ssrc, rtpsession);
+  g_signal_connect (rtpsession->priv->session, "on-sender-ssrc-active",
+      (GCallback) on_sender_ssrc_active, rtpsession);
+  g_signal_connect (rtpsession->priv->session, "notify::stats",
+      (GCallback) on_notify_stats, rtpsession);
+  rtpsession->priv->ptmap = g_hash_table_new_full (NULL, NULL, NULL,
+      (GDestroyNotify) gst_caps_unref);
+
+  gst_segment_init (&rtpsession->recv_rtp_seg, GST_FORMAT_UNDEFINED);
+  gst_segment_init (&rtpsession->send_rtp_seg, GST_FORMAT_UNDEFINED);
+
+  rtpsession->priv->thread_stopped = TRUE;
+
+  rtpsession->priv->rtx_count = 0;
+
+  rtpsession->priv->ntp_time_source = DEFAULT_NTP_TIME_SOURCE;
+}
+
+static void
+gst_rtp_session_finalize (GObject * object)
+{
+  GstRtpSession *rtpsession;
+
+  rtpsession = GST_RTP_SESSION (object);
+
+  g_hash_table_destroy (rtpsession->priv->ptmap);
+  g_mutex_clear (&rtpsession->priv->lock);
+  g_cond_clear (&rtpsession->priv->cond);
+  g_object_unref (rtpsession->priv->sysclock);
+  g_object_unref (rtpsession->priv->session);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_session_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpSession *rtpsession;
+  GstRtpSessionPrivate *priv;
+
+  rtpsession = GST_RTP_SESSION (object);
+  priv = rtpsession->priv;
+
+  switch (prop_id) {
+    case PROP_BANDWIDTH:
+      g_object_set_property (G_OBJECT (priv->session), "bandwidth", value);
+      break;
+    case PROP_RTCP_FRACTION:
+      g_object_set_property (G_OBJECT (priv->session), "rtcp-fraction", value);
+      break;
+    case PROP_RTCP_RR_BANDWIDTH:
+      g_object_set_property (G_OBJECT (priv->session), "rtcp-rr-bandwidth",
+          value);
+      break;
+    case PROP_RTCP_RS_BANDWIDTH:
+      g_object_set_property (G_OBJECT (priv->session), "rtcp-rs-bandwidth",
+          value);
+      break;
+    case PROP_SDES:
+      rtp_session_set_sdes_struct (priv->session, g_value_get_boxed (value));
+      break;
+    case PROP_USE_PIPELINE_CLOCK:
+      priv->use_pipeline_clock = g_value_get_boolean (value);
+      break;
+    case PROP_RTCP_MIN_INTERVAL:
+      g_object_set_property (G_OBJECT (priv->session), "rtcp-min-interval",
+          value);
+      break;
+    case PROP_PROBATION:
+      g_object_set_property (G_OBJECT (priv->session), "probation", value);
+      break;
+    case PROP_MAX_DROPOUT_TIME:
+      g_object_set_property (G_OBJECT (priv->session), "max-dropout-time",
+          value);
+      break;
+    case PROP_MAX_MISORDER_TIME:
+      g_object_set_property (G_OBJECT (priv->session), "max-misorder-time",
+          value);
+      break;
+    case PROP_RTP_PROFILE:
+      g_object_set_property (G_OBJECT (priv->session), "rtp-profile", value);
+      break;
+    case PROP_NTP_TIME_SOURCE:
+      priv->ntp_time_source = g_value_get_enum (value);
+      break;
+    case PROP_RTCP_SYNC_SEND_TIME:
+      priv->rtcp_sync_send_time = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_session_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpSession *rtpsession;
+  GstRtpSessionPrivate *priv;
+
+  rtpsession = GST_RTP_SESSION (object);
+  priv = rtpsession->priv;
+
+  switch (prop_id) {
+    case PROP_BANDWIDTH:
+      g_object_get_property (G_OBJECT (priv->session), "bandwidth", value);
+      break;
+    case PROP_RTCP_FRACTION:
+      g_object_get_property (G_OBJECT (priv->session), "rtcp-fraction", value);
+      break;
+    case PROP_RTCP_RR_BANDWIDTH:
+      g_object_get_property (G_OBJECT (priv->session), "rtcp-rr-bandwidth",
+          value);
+      break;
+    case PROP_RTCP_RS_BANDWIDTH:
+      g_object_get_property (G_OBJECT (priv->session), "rtcp-rs-bandwidth",
+          value);
+      break;
+    case PROP_SDES:
+      g_value_take_boxed (value, rtp_session_get_sdes_struct (priv->session));
+      break;
+    case PROP_NUM_SOURCES:
+      g_value_set_uint (value, rtp_session_get_num_sources (priv->session));
+      break;
+    case PROP_NUM_ACTIVE_SOURCES:
+      g_value_set_uint (value,
+          rtp_session_get_num_active_sources (priv->session));
+      break;
+    case PROP_INTERNAL_SESSION:
+      g_value_set_object (value, priv->session);
+      break;
+    case PROP_USE_PIPELINE_CLOCK:
+      g_value_set_boolean (value, priv->use_pipeline_clock);
+      break;
+    case PROP_RTCP_MIN_INTERVAL:
+      g_object_get_property (G_OBJECT (priv->session), "rtcp-min-interval",
+          value);
+      break;
+    case PROP_PROBATION:
+      g_object_get_property (G_OBJECT (priv->session), "probation", value);
+      break;
+    case PROP_MAX_DROPOUT_TIME:
+      g_object_get_property (G_OBJECT (priv->session), "max-dropout-time",
+          value);
+      break;
+    case PROP_MAX_MISORDER_TIME:
+      g_object_get_property (G_OBJECT (priv->session), "max-misorder-time",
+          value);
+      break;
+    case PROP_STATS:
+      g_value_take_boxed (value, gst_rtp_session_create_stats (rtpsession));
+      break;
+    case PROP_RTP_PROFILE:
+      g_object_get_property (G_OBJECT (priv->session), "rtp-profile", value);
+      break;
+    case PROP_NTP_TIME_SOURCE:
+      g_value_set_enum (value, priv->ntp_time_source);
+      break;
+    case PROP_RTCP_SYNC_SEND_TIME:
+      g_value_set_boolean (value, priv->rtcp_sync_send_time);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStructure *
+gst_rtp_session_create_stats (GstRtpSession * rtpsession)
+{
+  GstStructure *s;
+
+  g_object_get (rtpsession->priv->session, "stats", &s, NULL);
+  gst_structure_set (s, "rtx-count", G_TYPE_UINT, rtpsession->priv->rtx_count,
+      NULL);
+
+  return s;
+}
+
+static void
+get_current_times (GstRtpSession * rtpsession, GstClockTime * running_time,
+    guint64 * ntpnstime)
+{
+  guint64 ntpns = -1;
+  GstClock *clock;
+  GstClockTime base_time, rt, clock_time;
+
+  GST_OBJECT_LOCK (rtpsession);
+  if ((clock = GST_ELEMENT_CLOCK (rtpsession))) {
+    base_time = GST_ELEMENT_CAST (rtpsession)->base_time;
+    gst_object_ref (clock);
+    GST_OBJECT_UNLOCK (rtpsession);
+
+    /* get current clock time and convert to running time */
+    clock_time = gst_clock_get_time (clock);
+    rt = clock_time - base_time;
+
+    if (rtpsession->priv->use_pipeline_clock) {
+      ntpns = rt;
+      /* add constant to convert from 1970 based time to 1900 based time */
+      ntpns += (2208988800LL * GST_SECOND);
+    } else {
+      switch (rtpsession->priv->ntp_time_source) {
+        case GST_RTP_NTP_TIME_SOURCE_NTP:
+        case GST_RTP_NTP_TIME_SOURCE_UNIX:{
+          GTimeVal current;
+
+          /* get current NTP time */
+          g_get_current_time (&current);
+          ntpns = GST_TIMEVAL_TO_TIME (current);
+
+          /* add constant to convert from 1970 based time to 1900 based time */
+          if (rtpsession->priv->ntp_time_source == GST_RTP_NTP_TIME_SOURCE_NTP)
+            ntpns += (2208988800LL * GST_SECOND);
+          break;
+        }
+        case GST_RTP_NTP_TIME_SOURCE_RUNNING_TIME:
+          ntpns = rt;
+          break;
+        case GST_RTP_NTP_TIME_SOURCE_CLOCK_TIME:
+          ntpns = clock_time;
+          break;
+        default:
+          ntpns = -1;
+          g_assert_not_reached ();
+          break;
+      }
+    }
+
+    gst_object_unref (clock);
+  } else {
+    GST_OBJECT_UNLOCK (rtpsession);
+    rt = -1;
+    ntpns = -1;
+  }
+  if (running_time)
+    *running_time = rt;
+  if (ntpnstime)
+    *ntpnstime = ntpns;
+}
+
+/* must be called with GST_RTP_SESSION_LOCK */
+static void
+signal_waiting_rtcp_thread_unlocked (GstRtpSession * rtpsession)
+{
+  if (rtpsession->priv->wait_send) {
+    GST_LOG_OBJECT (rtpsession, "signal RTCP thread");
+    rtpsession->priv->wait_send = FALSE;
+    GST_RTP_SESSION_SIGNAL (rtpsession);
+  }
+}
+
+static void
+rtcp_thread (GstRtpSession * rtpsession)
+{
+  GstClockID id;
+  GstClockTime current_time;
+  GstClockTime next_timeout;
+  guint64 ntpnstime;
+  GstClockTime running_time;
+  RTPSession *session;
+  GstClock *sysclock;
+
+  GST_DEBUG_OBJECT (rtpsession, "entering RTCP thread");
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+
+  while (rtpsession->priv->wait_send) {
+    GST_LOG_OBJECT (rtpsession, "waiting for getting started");
+    GST_RTP_SESSION_WAIT (rtpsession);
+    GST_LOG_OBJECT (rtpsession, "signaled...");
+  }
+
+  sysclock = rtpsession->priv->sysclock;
+  current_time = gst_clock_get_time (sysclock);
+
+  session = rtpsession->priv->session;
+
+  GST_DEBUG_OBJECT (rtpsession, "starting at %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (current_time));
+  session->start_time = current_time;
+
+  while (!rtpsession->priv->stop_thread) {
+    GstClockReturn res;
+
+    /* get initial estimate */
+    next_timeout = rtp_session_next_timeout (session, current_time);
+
+    GST_DEBUG_OBJECT (rtpsession, "next check time %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (next_timeout));
+
+    /* leave if no more timeouts, the session ended */
+    if (next_timeout == GST_CLOCK_TIME_NONE)
+      break;
+
+    id = rtpsession->priv->id =
+        gst_clock_new_single_shot_id (sysclock, next_timeout);
+    GST_RTP_SESSION_UNLOCK (rtpsession);
+
+    res = gst_clock_id_wait (id, NULL);
+
+    GST_RTP_SESSION_LOCK (rtpsession);
+    gst_clock_id_unref (id);
+    rtpsession->priv->id = NULL;
+
+    if (rtpsession->priv->stop_thread)
+      break;
+
+    /* update current time */
+    current_time = gst_clock_get_time (sysclock);
+
+    /* get current NTP time */
+    get_current_times (rtpsession, &running_time, &ntpnstime);
+
+    /* we get unlocked because we need to perform reconsideration, don't perform
+     * the timeout but get a new reporting estimate. */
+    GST_DEBUG_OBJECT (rtpsession, "unlocked %d, current %" GST_TIME_FORMAT,
+        res, GST_TIME_ARGS (current_time));
+
+    /* perform actions, we ignore result. Release lock because it might push. */
+    GST_RTP_SESSION_UNLOCK (rtpsession);
+    rtp_session_on_timeout (session, current_time, ntpnstime, running_time);
+    GST_RTP_SESSION_LOCK (rtpsession);
+  }
+  /* mark the thread as stopped now */
+  rtpsession->priv->thread_stopped = TRUE;
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  GST_DEBUG_OBJECT (rtpsession, "leaving RTCP thread");
+}
+
+static gboolean
+start_rtcp_thread (GstRtpSession * rtpsession)
+{
+  GError *error = NULL;
+  gboolean res;
+
+  GST_DEBUG_OBJECT (rtpsession, "starting RTCP thread");
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+  rtpsession->priv->stop_thread = FALSE;
+  if (rtpsession->priv->thread_stopped) {
+    /* if the thread stopped, and we still have a handle to the thread, join it
+     * now. We can safely join with the lock held, the thread will not take it
+     * anymore. */
+    if (rtpsession->priv->thread)
+      g_thread_join (rtpsession->priv->thread);
+    /* only create a new thread if the old one was stopped. Otherwise we can
+     * just reuse the currently running one. */
+    rtpsession->priv->thread = g_thread_try_new ("rtpsession-rtcp-thread",
+        (GThreadFunc) rtcp_thread, rtpsession, &error);
+    rtpsession->priv->thread_stopped = FALSE;
+  }
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  if (error != NULL) {
+    res = FALSE;
+    GST_DEBUG_OBJECT (rtpsession, "failed to start thread, %s", error->message);
+    g_error_free (error);
+  } else {
+    res = TRUE;
+  }
+  return res;
+}
+
+static void
+stop_rtcp_thread (GstRtpSession * rtpsession)
+{
+  GST_DEBUG_OBJECT (rtpsession, "stopping RTCP thread");
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+  rtpsession->priv->stop_thread = TRUE;
+  signal_waiting_rtcp_thread_unlocked (rtpsession);
+  if (rtpsession->priv->id)
+    gst_clock_id_unschedule (rtpsession->priv->id);
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+}
+
+static void
+join_rtcp_thread (GstRtpSession * rtpsession)
+{
+  GST_RTP_SESSION_LOCK (rtpsession);
+  /* don't try to join when we have no thread */
+  if (rtpsession->priv->thread != NULL) {
+    GST_DEBUG_OBJECT (rtpsession, "joining RTCP thread");
+    GST_RTP_SESSION_UNLOCK (rtpsession);
+
+    g_thread_join (rtpsession->priv->thread);
+
+    GST_RTP_SESSION_LOCK (rtpsession);
+    /* after the join, take the lock and clear the thread structure. The caller
+     * is supposed to not concurrently call start and join. */
+    rtpsession->priv->thread = NULL;
+  }
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+}
+
+static GstStateChangeReturn
+gst_rtp_session_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn res;
+  GstRtpSession *rtpsession;
+
+  rtpsession = GST_RTP_SESSION (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      GST_RTP_SESSION_LOCK (rtpsession);
+      if (rtpsession->send_rtp_src)
+        rtpsession->priv->wait_send = TRUE;
+      GST_RTP_SESSION_UNLOCK (rtpsession);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      /* no need to join yet, we might want to continue later. Also, the
+       * dataflow could block downstream so that a join could just block
+       * forever. */
+      stop_rtcp_thread (rtpsession);
+      break;
+    default:
+      break;
+  }
+
+  res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      if (!start_rtcp_thread (rtpsession))
+        goto failed_thread;
+      break;
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      /* downstream is now releasing the dataflow and we can join. */
+      join_rtcp_thread (rtpsession);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return res;
+
+  /* ERRORS */
+failed_thread:
+  {
+    return GST_STATE_CHANGE_FAILURE;
+  }
+}
+
+static gboolean
+return_true (gpointer key, gpointer value, gpointer user_data)
+{
+  return TRUE;
+}
+
+static void
+gst_rtp_session_clear_pt_map (GstRtpSession * rtpsession)
+{
+  g_hash_table_foreach_remove (rtpsession->priv->ptmap, return_true, NULL);
+}
+
+/* called when the session manager has an RTP packet or a list of packets
+ * ready for further processing */
+static GstFlowReturn
+gst_rtp_session_process_rtp (RTPSession * sess, RTPSource * src,
+    GstBuffer * buffer, gpointer user_data)
+{
+  GstFlowReturn result;
+  GstRtpSession *rtpsession;
+  GstPad *rtp_src;
+
+  rtpsession = GST_RTP_SESSION (user_data);
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+  if ((rtp_src = rtpsession->recv_rtp_src))
+    gst_object_ref (rtp_src);
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  if (rtp_src) {
+    GST_LOG_OBJECT (rtpsession, "pushing received RTP packet");
+    result = gst_pad_push (rtp_src, buffer);
+    gst_object_unref (rtp_src);
+  } else {
+    GST_DEBUG_OBJECT (rtpsession, "dropping received RTP packet");
+    gst_buffer_unref (buffer);
+    result = GST_FLOW_OK;
+  }
+  return result;
+}
+
+/* called when the session manager has an RTP packet ready for further
+ * sending */
+static GstFlowReturn
+gst_rtp_session_send_rtp (RTPSession * sess, RTPSource * src,
+    gpointer data, gpointer user_data)
+{
+  GstFlowReturn result;
+  GstRtpSession *rtpsession;
+  GstPad *rtp_src;
+
+  rtpsession = GST_RTP_SESSION (user_data);
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+  if ((rtp_src = rtpsession->send_rtp_src))
+    gst_object_ref (rtp_src);
+  signal_waiting_rtcp_thread_unlocked (rtpsession);
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  if (rtp_src) {
+    if (GST_IS_BUFFER (data)) {
+      GST_LOG_OBJECT (rtpsession, "sending RTP packet");
+      result = gst_pad_push (rtp_src, GST_BUFFER_CAST (data));
+    } else {
+      GST_LOG_OBJECT (rtpsession, "sending RTP list");
+      result = gst_pad_push_list (rtp_src, GST_BUFFER_LIST_CAST (data));
+    }
+    gst_object_unref (rtp_src);
+  } else {
+    gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
+    result = GST_FLOW_OK;
+  }
+  return result;
+}
+
+static void
+do_rtcp_events (GstRtpSession * rtpsession, GstPad * srcpad)
+{
+  GstCaps *caps;
+  GstSegment seg;
+  GstEvent *event;
+  gchar *stream_id;
+  gboolean have_group_id;
+  guint group_id;
+
+  stream_id =
+      g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
+      g_random_int (), g_random_int ());
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+  if (rtpsession->recv_rtp_sink) {
+    event =
+        gst_pad_get_sticky_event (rtpsession->recv_rtp_sink,
+        GST_EVENT_STREAM_START, 0);
+    if (event) {
+      if (gst_event_parse_group_id (event, &group_id))
+        have_group_id = TRUE;
+      else
+        have_group_id = FALSE;
+      gst_event_unref (event);
+    } else {
+      have_group_id = TRUE;
+      group_id = gst_util_group_id_next ();
+    }
+  } else {
+    have_group_id = TRUE;
+    group_id = gst_util_group_id_next ();
+  }
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  event = gst_event_new_stream_start (stream_id);
+  if (have_group_id)
+    gst_event_set_group_id (event, group_id);
+  gst_pad_push_event (srcpad, event);
+  g_free (stream_id);
+
+  caps = gst_caps_new_empty_simple ("application/x-rtcp");
+  gst_pad_set_caps (srcpad, caps);
+  gst_caps_unref (caps);
+
+  gst_segment_init (&seg, GST_FORMAT_TIME);
+  event = gst_event_new_segment (&seg);
+  gst_pad_push_event (srcpad, event);
+}
+
+/* called when the session manager has an RTCP packet ready for further
+ * sending. The eos flag is set when an EOS event should be sent downstream as
+ * well. */
+static GstFlowReturn
+gst_rtp_session_send_rtcp (RTPSession * sess, RTPSource * src,
+    GstBuffer * buffer, gboolean eos, gpointer user_data)
+{
+  GstFlowReturn result;
+  GstRtpSession *rtpsession;
+  GstPad *rtcp_src;
+
+  rtpsession = GST_RTP_SESSION (user_data);
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+  if (rtpsession->priv->stop_thread)
+    goto stopping;
+
+  if ((rtcp_src = rtpsession->send_rtcp_src)) {
+    gst_object_ref (rtcp_src);
+    GST_RTP_SESSION_UNLOCK (rtpsession);
+
+    /* set rtcp caps on output pad */
+    if (!gst_pad_has_current_caps (rtcp_src))
+      do_rtcp_events (rtpsession, rtcp_src);
+
+    GST_LOG_OBJECT (rtpsession, "sending RTCP");
+    result = gst_pad_push (rtcp_src, buffer);
+
+    /* we have to send EOS after this packet */
+    if (eos) {
+      GST_LOG_OBJECT (rtpsession, "sending EOS");
+      gst_pad_push_event (rtcp_src, gst_event_new_eos ());
+    }
+    gst_object_unref (rtcp_src);
+  } else {
+    GST_RTP_SESSION_UNLOCK (rtpsession);
+
+    GST_DEBUG_OBJECT (rtpsession, "not sending RTCP, no output pad");
+    gst_buffer_unref (buffer);
+    result = GST_FLOW_OK;
+  }
+  return result;
+
+  /* ERRORS */
+stopping:
+  {
+    GST_DEBUG_OBJECT (rtpsession, "we are stopping");
+    gst_buffer_unref (buffer);
+    GST_RTP_SESSION_UNLOCK (rtpsession);
+    return GST_FLOW_OK;
+  }
+}
+
+/* called when the session manager has an SR RTCP packet ready for handling
+ * inter stream synchronisation */
+static GstFlowReturn
+gst_rtp_session_sync_rtcp (RTPSession * sess,
+    GstBuffer * buffer, gpointer user_data)
+{
+  GstFlowReturn result;
+  GstRtpSession *rtpsession;
+  GstPad *sync_src;
+
+  rtpsession = GST_RTP_SESSION (user_data);
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+  if (rtpsession->priv->stop_thread)
+    goto stopping;
+
+  if ((sync_src = rtpsession->sync_src)) {
+    gst_object_ref (sync_src);
+    GST_RTP_SESSION_UNLOCK (rtpsession);
+
+    /* set rtcp caps on output pad, this happens
+     * when we receive RTCP muxed with RTP according
+     * to RFC5761. Otherwise we would have forwarded
+     * the events from the recv_rtcp_sink pad already
+     */
+    if (!gst_pad_has_current_caps (sync_src))
+      do_rtcp_events (rtpsession, sync_src);
+
+    GST_LOG_OBJECT (rtpsession, "sending Sync RTCP");
+    result = gst_pad_push (sync_src, buffer);
+    gst_object_unref (sync_src);
+  } else {
+    GST_RTP_SESSION_UNLOCK (rtpsession);
+
+    GST_DEBUG_OBJECT (rtpsession, "not sending Sync RTCP, no output pad");
+    gst_buffer_unref (buffer);
+    result = GST_FLOW_OK;
+  }
+  return result;
+
+  /* ERRORS */
+stopping:
+  {
+    GST_DEBUG_OBJECT (rtpsession, "we are stopping");
+    gst_buffer_unref (buffer);
+    GST_RTP_SESSION_UNLOCK (rtpsession);
+    return GST_FLOW_OK;
+  }
+}
+
+static void
+gst_rtp_session_cache_caps (GstRtpSession * rtpsession, GstCaps * caps)
+{
+  GstRtpSessionPrivate *priv;
+  const GstStructure *s;
+  gint payload;
+
+  priv = rtpsession->priv;
+
+  GST_DEBUG_OBJECT (rtpsession, "parsing caps");
+
+  s = gst_caps_get_structure (caps, 0);
+  if (!gst_structure_get_int (s, "payload", &payload))
+    return;
+
+  if (g_hash_table_lookup (priv->ptmap, GINT_TO_POINTER (payload)))
+    return;
+
+  g_hash_table_insert (priv->ptmap, GINT_TO_POINTER (payload),
+      gst_caps_ref (caps));
+}
+
+static GstCaps *
+gst_rtp_session_get_caps_for_pt (GstRtpSession * rtpsession, guint payload)
+{
+  GstCaps *caps = NULL;
+  GValue args[2] = { {0}, {0} };
+  GValue ret = { 0 };
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+  caps = g_hash_table_lookup (rtpsession->priv->ptmap,
+      GINT_TO_POINTER (payload));
+  if (caps) {
+    gst_caps_ref (caps);
+    goto done;
+  }
+
+  /* not found in the cache, try to get it with a signal */
+  g_value_init (&args[0], GST_TYPE_ELEMENT);
+  g_value_set_object (&args[0], rtpsession);
+  g_value_init (&args[1], G_TYPE_UINT);
+  g_value_set_uint (&args[1], payload);
+
+  g_value_init (&ret, GST_TYPE_CAPS);
+  g_value_set_boxed (&ret, NULL);
+
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  g_signal_emitv (args, gst_rtp_session_signals[SIGNAL_REQUEST_PT_MAP], 0,
+      &ret);
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+
+  g_value_unset (&args[0]);
+  g_value_unset (&args[1]);
+  caps = (GstCaps *) g_value_dup_boxed (&ret);
+  g_value_unset (&ret);
+  if (!caps)
+    goto no_caps;
+
+  gst_rtp_session_cache_caps (rtpsession, caps);
+
+done:
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  return caps;
+
+no_caps:
+  {
+    GST_DEBUG_OBJECT (rtpsession, "could not get caps");
+    goto done;
+  }
+}
+
+/* called when the session manager needs the clock rate */
+static gint
+gst_rtp_session_clock_rate (RTPSession * sess, guint8 payload,
+    gpointer user_data)
+{
+  gint result = -1;
+  GstRtpSession *rtpsession;
+  GstCaps *caps;
+  const GstStructure *s;
+
+  rtpsession = GST_RTP_SESSION_CAST (user_data);
+
+  caps = gst_rtp_session_get_caps_for_pt (rtpsession, payload);
+
+  if (!caps)
+    goto done;
+
+  s = gst_caps_get_structure (caps, 0);
+  if (!gst_structure_get_int (s, "clock-rate", &result))
+    goto no_clock_rate;
+
+  gst_caps_unref (caps);
+
+  GST_DEBUG_OBJECT (rtpsession, "parsed clock-rate %d", result);
+
+done:
+
+  return result;
+
+  /* ERRORS */
+no_clock_rate:
+  {
+    gst_caps_unref (caps);
+    GST_DEBUG_OBJECT (rtpsession, "No clock-rate in caps!");
+    goto done;
+  }
+}
+
+/* called when the session manager asks us to reconsider the timeout */
+static void
+gst_rtp_session_reconsider (RTPSession * sess, gpointer user_data)
+{
+  GstRtpSession *rtpsession;
+
+  rtpsession = GST_RTP_SESSION_CAST (user_data);
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+  GST_DEBUG_OBJECT (rtpsession, "unlock timer for reconsideration");
+  if (rtpsession->priv->id)
+    gst_clock_id_unschedule (rtpsession->priv->id);
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+}
+
+static gboolean
+gst_rtp_session_event_recv_rtp_sink (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstRtpSession *rtpsession;
+  gboolean ret = FALSE;
+
+  rtpsession = GST_RTP_SESSION (parent);
+
+  GST_DEBUG_OBJECT (rtpsession, "received event %s",
+      GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      /* process */
+      gst_event_parse_caps (event, &caps);
+      gst_rtp_session_sink_setcaps (pad, rtpsession, caps);
+      ret = gst_pad_push_event (rtpsession->recv_rtp_src, event);
+      break;
+    }
+    case GST_EVENT_FLUSH_STOP:
+      gst_segment_init (&rtpsession->recv_rtp_seg, GST_FORMAT_UNDEFINED);
+      ret = gst_pad_push_event (rtpsession->recv_rtp_src, event);
+      break;
+    case GST_EVENT_SEGMENT:
+    {
+      GstSegment *segment, in_segment;
+
+      segment = &rtpsession->recv_rtp_seg;
+
+      /* the newsegment event is needed to convert the RTP timestamp to
+       * running_time, which is needed to generate a mapping from RTP to NTP
+       * timestamps in SR reports */
+      gst_event_copy_segment (event, &in_segment);
+      GST_DEBUG_OBJECT (rtpsession, "received segment %" GST_SEGMENT_FORMAT,
+          &in_segment);
+
+      /* accept upstream */
+      gst_segment_copy_into (&in_segment, segment);
+
+      /* push event forward */
+      ret = gst_pad_push_event (rtpsession->recv_rtp_src, event);
+      break;
+    }
+    case GST_EVENT_EOS:
+    {
+      GstPad *rtcp_src;
+
+      ret =
+          gst_pad_push_event (rtpsession->recv_rtp_src, gst_event_ref (event));
+
+      GST_RTP_SESSION_LOCK (rtpsession);
+      if ((rtcp_src = rtpsession->send_rtcp_src))
+        gst_object_ref (rtcp_src);
+      GST_RTP_SESSION_UNLOCK (rtpsession);
+
+      if (rtcp_src) {
+        ret = gst_pad_push_event (rtcp_src, event);
+        gst_object_unref (rtcp_src);
+      } else {
+        gst_event_unref (event);
+        ret = TRUE;
+      }
+      break;
+    }
+    default:
+      ret = gst_pad_push_event (rtpsession->recv_rtp_src, event);
+      break;
+  }
+
+  return ret;
+
+}
+
+static gboolean
+gst_rtp_session_request_remote_key_unit (GstRtpSession * rtpsession,
+    guint32 ssrc, guint payload, gboolean all_headers, gint count)
+{
+  GstCaps *caps;
+
+  caps = gst_rtp_session_get_caps_for_pt (rtpsession, payload);
+
+  if (caps) {
+    const GstStructure *s = gst_caps_get_structure (caps, 0);
+    gboolean pli;
+    gboolean fir;
+
+    pli = gst_structure_has_field (s, "rtcp-fb-nack-pli");
+    fir = gst_structure_has_field (s, "rtcp-fb-ccm-fir") && all_headers;
+
+    /* Google Talk uses FIR for repair, so send it even if we just want a
+     * regular PLI */
+    if (!pli &&
+        gst_structure_has_field (s, "rtcp-fb-x-gstreamer-fir-as-repair"))
+      fir = TRUE;
+
+    gst_caps_unref (caps);
+
+    if (pli || fir)
+      return rtp_session_request_key_unit (rtpsession->priv->session, ssrc,
+          fir, count);
+  }
+
+  return FALSE;
+}
+
+static gboolean
+gst_rtp_session_event_recv_rtp_src (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstRtpSession *rtpsession;
+  gboolean forward = TRUE;
+  gboolean ret = TRUE;
+  const GstStructure *s;
+  guint32 ssrc;
+  guint pt;
+
+  rtpsession = GST_RTP_SESSION (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CUSTOM_UPSTREAM:
+      s = gst_event_get_structure (event);
+      if (gst_structure_has_name (s, "GstForceKeyUnit") &&
+          gst_structure_get_uint (s, "ssrc", &ssrc) &&
+          gst_structure_get_uint (s, "payload", &pt)) {
+        gboolean all_headers = FALSE;
+        gint count = -1;
+
+        gst_structure_get_boolean (s, "all-headers", &all_headers);
+        if (gst_structure_get_int (s, "count", &count) && count < 0)
+          count += G_MAXINT;    /* Make sure count is positive if present */
+        if (gst_rtp_session_request_remote_key_unit (rtpsession, ssrc, pt,
+                all_headers, count))
+          forward = FALSE;
+      } else if (gst_structure_has_name (s, "GstRTPRetransmissionRequest")) {
+        GstClockTime running_time;
+        guint seqnum, delay, deadline, max_delay, avg_rtt;
+
+        GST_RTP_SESSION_LOCK (rtpsession);
+        rtpsession->priv->rtx_count++;
+        GST_RTP_SESSION_UNLOCK (rtpsession);
+
+        if (!gst_structure_get_clock_time (s, "running-time", &running_time))
+          running_time = -1;
+        if (!gst_structure_get_uint (s, "ssrc", &ssrc))
+          ssrc = -1;
+        if (!gst_structure_get_uint (s, "seqnum", &seqnum))
+          seqnum = -1;
+        if (!gst_structure_get_uint (s, "delay", &delay))
+          delay = 0;
+        if (!gst_structure_get_uint (s, "deadline", &deadline))
+          deadline = 100;
+        if (!gst_structure_get_uint (s, "avg-rtt", &avg_rtt))
+          avg_rtt = 40;
+
+        /* remaining time to receive the packet */
+        max_delay = deadline;
+        if (max_delay > delay)
+          max_delay -= delay;
+        /* estimated RTT */
+        if (max_delay > avg_rtt)
+          max_delay -= avg_rtt;
+        else
+          max_delay = 0;
+
+        if (rtp_session_request_nack (rtpsession->priv->session, ssrc, seqnum,
+                max_delay * GST_MSECOND))
+          forward = FALSE;
+      }
+      break;
+    default:
+      break;
+  }
+
+  if (forward) {
+    GstPad *recv_rtp_sink;
+
+    GST_RTP_SESSION_LOCK (rtpsession);
+    if ((recv_rtp_sink = rtpsession->recv_rtp_sink))
+      gst_object_ref (recv_rtp_sink);
+    GST_RTP_SESSION_UNLOCK (rtpsession);
+
+    if (recv_rtp_sink) {
+      ret = gst_pad_push_event (recv_rtp_sink, event);
+      gst_object_unref (recv_rtp_sink);
+    } else
+      gst_event_unref (event);
+  } else {
+    gst_event_unref (event);
+  }
+
+  return ret;
+}
+
+
+static GstIterator *
+gst_rtp_session_iterate_internal_links (GstPad * pad, GstObject * parent)
+{
+  GstRtpSession *rtpsession;
+  GstPad *otherpad = NULL;
+  GstIterator *it = NULL;
+
+  rtpsession = GST_RTP_SESSION (parent);
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+  if (pad == rtpsession->recv_rtp_src) {
+    otherpad = gst_object_ref (rtpsession->recv_rtp_sink);
+  } else if (pad == rtpsession->recv_rtp_sink) {
+    otherpad = gst_object_ref (rtpsession->recv_rtp_src);
+  } else if (pad == rtpsession->send_rtp_src) {
+    otherpad = gst_object_ref (rtpsession->send_rtp_sink);
+  } else if (pad == rtpsession->send_rtp_sink) {
+    otherpad = gst_object_ref (rtpsession->send_rtp_src);
+  }
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  if (otherpad) {
+    GValue val = { 0, };
+
+    g_value_init (&val, GST_TYPE_PAD);
+    g_value_set_object (&val, otherpad);
+    it = gst_iterator_new_single (GST_TYPE_PAD, &val);
+    g_value_unset (&val);
+    gst_object_unref (otherpad);
+  } else {
+    it = gst_iterator_new_single (GST_TYPE_PAD, NULL);
+  }
+
+  return it;
+}
+
+static gboolean
+gst_rtp_session_sink_setcaps (GstPad * pad, GstRtpSession * rtpsession,
+    GstCaps * caps)
+{
+  GST_RTP_SESSION_LOCK (rtpsession);
+  gst_rtp_session_cache_caps (rtpsession, caps);
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  return TRUE;
+}
+
+/* receive a packet from a sender, send it to the RTP session manager and
+ * forward the packet on the rtp_src pad
+ */
+static GstFlowReturn
+gst_rtp_session_chain_recv_rtp (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer)
+{
+  GstRtpSession *rtpsession;
+  GstRtpSessionPrivate *priv;
+  GstFlowReturn ret;
+  GstClockTime current_time, running_time;
+  GstClockTime timestamp;
+  guint64 ntpnstime;
+
+  rtpsession = GST_RTP_SESSION (parent);
+  priv = rtpsession->priv;
+
+  GST_LOG_OBJECT (rtpsession, "received RTP packet");
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+  signal_waiting_rtcp_thread_unlocked (rtpsession);
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  /* get NTP time when this packet was captured, this depends on the timestamp. */
+  timestamp = GST_BUFFER_PTS (buffer);
+  if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+    /* convert to running time using the segment values */
+    running_time =
+        gst_segment_to_running_time (&rtpsession->recv_rtp_seg, GST_FORMAT_TIME,
+        timestamp);
+    ntpnstime = GST_CLOCK_TIME_NONE;
+  } else {
+    get_current_times (rtpsession, &running_time, &ntpnstime);
+  }
+  current_time = gst_clock_get_time (priv->sysclock);
+
+  ret = rtp_session_process_rtp (priv->session, buffer, current_time,
+      running_time, ntpnstime);
+  if (ret != GST_FLOW_OK)
+    goto push_error;
+
+done:
+
+  return ret;
+
+  /* ERRORS */
+push_error:
+  {
+    GST_DEBUG_OBJECT (rtpsession, "process returned %s",
+        gst_flow_get_name (ret));
+    goto done;
+  }
+}
+
+static gboolean
+gst_rtp_session_event_recv_rtcp_sink (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstRtpSession *rtpsession;
+  gboolean ret = FALSE;
+
+  rtpsession = GST_RTP_SESSION (parent);
+
+  GST_DEBUG_OBJECT (rtpsession, "received event %s",
+      GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEGMENT:
+      /* Make sure that the sync_src pad has caps before the segment event.
+       * Otherwise we might get a segment event before caps from the receive
+       * RTCP pad, and then later when receiving RTCP packets will set caps.
+       * This will results in a sticky event misordering warning
+       */
+      if (!gst_pad_has_current_caps (rtpsession->sync_src)) {
+        GstCaps *caps = gst_caps_new_empty_simple ("application/x-rtcp");
+        gst_pad_set_caps (rtpsession->sync_src, caps);
+        gst_caps_unref (caps);
+      }
+      /* fall through */
+    default:
+      ret = gst_pad_push_event (rtpsession->sync_src, event);
+      break;
+  }
+
+  return ret;
+}
+
+/* Receive an RTCP packet from a sender, send it to the RTP session manager and
+ * forward the SR packets to the sync_src pad.
+ */
+static GstFlowReturn
+gst_rtp_session_chain_recv_rtcp (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer)
+{
+  GstRtpSession *rtpsession;
+  GstRtpSessionPrivate *priv;
+  GstClockTime current_time;
+  guint64 ntpnstime;
+
+  rtpsession = GST_RTP_SESSION (parent);
+  priv = rtpsession->priv;
+
+  GST_LOG_OBJECT (rtpsession, "received RTCP packet");
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+  signal_waiting_rtcp_thread_unlocked (rtpsession);
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  current_time = gst_clock_get_time (priv->sysclock);
+  get_current_times (rtpsession, NULL, &ntpnstime);
+
+  rtp_session_process_rtcp (priv->session, buffer, current_time, ntpnstime);
+
+  return GST_FLOW_OK;           /* always return OK */
+}
+
+static gboolean
+gst_rtp_session_query_send_rtcp_src (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  GstRtpSession *rtpsession;
+  gboolean ret = FALSE;
+
+  rtpsession = GST_RTP_SESSION (parent);
+
+  GST_DEBUG_OBJECT (rtpsession, "received QUERY %s",
+      GST_QUERY_TYPE_NAME (query));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_LATENCY:
+      ret = TRUE;
+      /* use the defaults for the latency query. */
+      gst_query_set_latency (query, FALSE, 0, -1);
+      break;
+    default:
+      /* other queries simply fail for now */
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_rtp_session_event_send_rtcp_src (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstRtpSession *rtpsession;
+  gboolean ret = TRUE;
+
+  rtpsession = GST_RTP_SESSION (parent);
+  GST_DEBUG_OBJECT (rtpsession, "received EVENT %s",
+      GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+    case GST_EVENT_LATENCY:
+      gst_event_unref (event);
+      ret = TRUE;
+      break;
+    default:
+      /* other events simply fail for now */
+      gst_event_unref (event);
+      ret = FALSE;
+      break;
+  }
+
+  return ret;
+}
+
+
+static gboolean
+gst_rtp_session_event_send_rtp_sink (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstRtpSession *rtpsession;
+  gboolean ret = FALSE;
+
+  rtpsession = GST_RTP_SESSION (parent);
+
+  GST_DEBUG_OBJECT (rtpsession, "received EVENT %s",
+      GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      /* process */
+      gst_event_parse_caps (event, &caps);
+      gst_rtp_session_setcaps_send_rtp (pad, rtpsession, caps);
+      ret = gst_pad_push_event (rtpsession->send_rtp_src, event);
+      break;
+    }
+    case GST_EVENT_FLUSH_STOP:
+      gst_segment_init (&rtpsession->send_rtp_seg, GST_FORMAT_UNDEFINED);
+      ret = gst_pad_push_event (rtpsession->send_rtp_src, event);
+      break;
+    case GST_EVENT_SEGMENT:{
+      GstSegment *segment, in_segment;
+
+      segment = &rtpsession->send_rtp_seg;
+
+      /* the newsegment event is needed to convert the RTP timestamp to
+       * running_time, which is needed to generate a mapping from RTP to NTP
+       * timestamps in SR reports */
+      gst_event_copy_segment (event, &in_segment);
+      GST_DEBUG_OBJECT (rtpsession, "received segment %" GST_SEGMENT_FORMAT,
+          &in_segment);
+
+      /* accept upstream */
+      gst_segment_copy_into (&in_segment, segment);
+
+      /* push event forward */
+      ret = gst_pad_push_event (rtpsession->send_rtp_src, event);
+      break;
+    }
+    case GST_EVENT_EOS:{
+      GstClockTime current_time;
+
+      /* push downstream FIXME, we are not supposed to leave the session just
+       * because we stop sending. */
+      ret = gst_pad_push_event (rtpsession->send_rtp_src, event);
+      current_time = gst_clock_get_time (rtpsession->priv->sysclock);
+
+      GST_DEBUG_OBJECT (rtpsession, "scheduling BYE message");
+      rtp_session_mark_all_bye (rtpsession->priv->session, "End Of Stream");
+      rtp_session_schedule_bye (rtpsession->priv->session, current_time);
+      break;
+    }
+    default:{
+      GstPad *send_rtp_src;
+
+      GST_RTP_SESSION_LOCK (rtpsession);
+      if ((send_rtp_src = rtpsession->send_rtp_src))
+        gst_object_ref (send_rtp_src);
+      GST_RTP_SESSION_UNLOCK (rtpsession);
+
+      if (send_rtp_src) {
+        ret = gst_pad_push_event (send_rtp_src, event);
+        gst_object_unref (send_rtp_src);
+      } else
+        gst_event_unref (event);
+
+      break;
+    }
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_rtp_session_event_send_rtp_src (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstRtpSession *rtpsession;
+  gboolean ret = FALSE;
+
+  rtpsession = GST_RTP_SESSION (parent);
+
+  GST_DEBUG_OBJECT (rtpsession, "received EVENT %s",
+      GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_LATENCY:
+      /* save the latency, we need this to know when an RTP packet will be
+       * rendered by the sink */
+      gst_event_parse_latency (event, &rtpsession->priv->send_latency);
+
+      ret = gst_pad_event_default (pad, parent, event);
+      break;
+    default:
+      ret = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+  return ret;
+}
+
+static GstCaps *
+gst_rtp_session_getcaps_send_rtp (GstPad * pad, GstRtpSession * rtpsession,
+    GstCaps * filter)
+{
+  GstRtpSessionPrivate *priv;
+  GstCaps *result;
+  GstStructure *s1, *s2;
+  guint ssrc;
+  gboolean is_random;
+
+  priv = rtpsession->priv;
+
+  ssrc = rtp_session_suggest_ssrc (priv->session, &is_random);
+
+  /* we can basically accept anything but we prefer to receive packets with our
+   * internal SSRC so that we don't have to patch it. Create a structure with
+   * the SSRC and another one without.
+   * Only do this if the session actually decided on an ssrc already,
+   * otherwise we give upstream the opportunity to select an ssrc itself */
+  if (!is_random) {
+    s1 = gst_structure_new ("application/x-rtp", "ssrc", G_TYPE_UINT, ssrc,
+        NULL);
+    s2 = gst_structure_new_empty ("application/x-rtp");
+
+    result = gst_caps_new_full (s1, s2, NULL);
+  } else {
+    result = gst_caps_new_empty_simple ("application/x-rtp");
+  }
+
+  if (filter) {
+    GstCaps *caps = result;
+
+    result = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+  }
+
+  GST_DEBUG_OBJECT (rtpsession, "getting caps %" GST_PTR_FORMAT, result);
+
+  return result;
+}
+
+static gboolean
+gst_rtp_session_query_send_rtp (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  gboolean res = FALSE;
+  GstRtpSession *rtpsession;
+
+  rtpsession = GST_RTP_SESSION (parent);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *filter, *caps;
+
+      gst_query_parse_caps (query, &filter);
+      caps = gst_rtp_session_getcaps_send_rtp (pad, rtpsession, filter);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+      res = TRUE;
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+
+  return res;
+}
+
+static gboolean
+gst_rtp_session_setcaps_send_rtp (GstPad * pad, GstRtpSession * rtpsession,
+    GstCaps * caps)
+{
+  GstRtpSessionPrivate *priv;
+
+  priv = rtpsession->priv;
+
+  rtp_session_update_send_caps (priv->session, caps);
+
+  return TRUE;
+}
+
+/* Recieve an RTP packet or a list of packets to be send to the receivers,
+ * send to RTP session manager and forward to send_rtp_src.
+ */
+static GstFlowReturn
+gst_rtp_session_chain_send_rtp_common (GstRtpSession * rtpsession,
+    gpointer data, gboolean is_list)
+{
+  GstRtpSessionPrivate *priv;
+  GstFlowReturn ret;
+  GstClockTime timestamp, running_time;
+  GstClockTime current_time;
+
+  priv = rtpsession->priv;
+
+  GST_LOG_OBJECT (rtpsession, "received RTP %s", is_list ? "list" : "packet");
+
+  /* get NTP time when this packet was captured, this depends on the timestamp. */
+  if (is_list) {
+    GstBuffer *buffer = NULL;
+
+    /* All groups in an list have the same timestamp.
+     * So, just take it from the first group. */
+    buffer = gst_buffer_list_get (GST_BUFFER_LIST_CAST (data), 0);
+    if (buffer)
+      timestamp = GST_BUFFER_PTS (buffer);
+    else
+      timestamp = -1;
+  } else {
+    timestamp = GST_BUFFER_PTS (GST_BUFFER_CAST (data));
+  }
+
+  if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+    /* convert to running time using the segment start value. */
+    running_time =
+        gst_segment_to_running_time (&rtpsession->send_rtp_seg, GST_FORMAT_TIME,
+        timestamp);
+    if (priv->rtcp_sync_send_time)
+      running_time += priv->send_latency;
+  } else {
+    /* no timestamp. */
+    running_time = -1;
+  }
+
+  current_time = gst_clock_get_time (priv->sysclock);
+  ret = rtp_session_send_rtp (priv->session, data, is_list, current_time,
+      running_time);
+  if (ret != GST_FLOW_OK)
+    goto push_error;
+
+done:
+
+  return ret;
+
+  /* ERRORS */
+push_error:
+  {
+    GST_DEBUG_OBJECT (rtpsession, "process returned %s",
+        gst_flow_get_name (ret));
+    goto done;
+  }
+}
+
+static GstFlowReturn
+gst_rtp_session_chain_send_rtp (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer)
+{
+  GstRtpSession *rtpsession = GST_RTP_SESSION (parent);
+
+  return gst_rtp_session_chain_send_rtp_common (rtpsession, buffer, FALSE);
+}
+
+static GstFlowReturn
+gst_rtp_session_chain_send_rtp_list (GstPad * pad, GstObject * parent,
+    GstBufferList * list)
+{
+  GstRtpSession *rtpsession = GST_RTP_SESSION (parent);
+
+  return gst_rtp_session_chain_send_rtp_common (rtpsession, list, TRUE);
+}
+
+/* Create sinkpad to receive RTP packets from senders. This will also create a
+ * srcpad for the RTP packets.
+ */
+static GstPad *
+create_recv_rtp_sink (GstRtpSession * rtpsession)
+{
+  GST_DEBUG_OBJECT (rtpsession, "creating RTP sink pad");
+
+  rtpsession->recv_rtp_sink =
+      gst_pad_new_from_static_template (&rtpsession_recv_rtp_sink_template,
+      "recv_rtp_sink");
+  gst_pad_set_chain_function (rtpsession->recv_rtp_sink,
+      gst_rtp_session_chain_recv_rtp);
+  gst_pad_set_event_function (rtpsession->recv_rtp_sink,
+      gst_rtp_session_event_recv_rtp_sink);
+  gst_pad_set_iterate_internal_links_function (rtpsession->recv_rtp_sink,
+      gst_rtp_session_iterate_internal_links);
+  GST_PAD_SET_PROXY_ALLOCATION (rtpsession->recv_rtp_sink);
+  gst_pad_set_active (rtpsession->recv_rtp_sink, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpsession),
+      rtpsession->recv_rtp_sink);
+
+  GST_DEBUG_OBJECT (rtpsession, "creating RTP src pad");
+  rtpsession->recv_rtp_src =
+      gst_pad_new_from_static_template (&rtpsession_recv_rtp_src_template,
+      "recv_rtp_src");
+  gst_pad_set_event_function (rtpsession->recv_rtp_src,
+      gst_rtp_session_event_recv_rtp_src);
+  gst_pad_set_iterate_internal_links_function (rtpsession->recv_rtp_src,
+      gst_rtp_session_iterate_internal_links);
+  gst_pad_use_fixed_caps (rtpsession->recv_rtp_src);
+  gst_pad_set_active (rtpsession->recv_rtp_src, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpsession), rtpsession->recv_rtp_src);
+
+  return rtpsession->recv_rtp_sink;
+}
+
+/* Remove sinkpad to receive RTP packets from senders. This will also remove
+ * the srcpad for the RTP packets.
+ */
+static void
+remove_recv_rtp_sink (GstRtpSession * rtpsession)
+{
+  GST_DEBUG_OBJECT (rtpsession, "removing RTP sink pad");
+
+  /* deactivate from source to sink */
+  gst_pad_set_active (rtpsession->recv_rtp_src, FALSE);
+  gst_pad_set_active (rtpsession->recv_rtp_sink, FALSE);
+
+  /* remove pads */
+  gst_element_remove_pad (GST_ELEMENT_CAST (rtpsession),
+      rtpsession->recv_rtp_sink);
+  rtpsession->recv_rtp_sink = NULL;
+
+  GST_DEBUG_OBJECT (rtpsession, "removing RTP src pad");
+  gst_element_remove_pad (GST_ELEMENT_CAST (rtpsession),
+      rtpsession->recv_rtp_src);
+  rtpsession->recv_rtp_src = NULL;
+}
+
+/* Create a sinkpad to receive RTCP messages from senders, this will also create a
+ * sync_src pad for the SR packets.
+ */
+static GstPad *
+create_recv_rtcp_sink (GstRtpSession * rtpsession)
+{
+  GST_DEBUG_OBJECT (rtpsession, "creating RTCP sink pad");
+
+  rtpsession->recv_rtcp_sink =
+      gst_pad_new_from_static_template (&rtpsession_recv_rtcp_sink_template,
+      "recv_rtcp_sink");
+  gst_pad_set_chain_function (rtpsession->recv_rtcp_sink,
+      gst_rtp_session_chain_recv_rtcp);
+  gst_pad_set_event_function (rtpsession->recv_rtcp_sink,
+      gst_rtp_session_event_recv_rtcp_sink);
+  gst_pad_set_iterate_internal_links_function (rtpsession->recv_rtcp_sink,
+      gst_rtp_session_iterate_internal_links);
+  gst_pad_set_active (rtpsession->recv_rtcp_sink, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpsession),
+      rtpsession->recv_rtcp_sink);
+
+  GST_DEBUG_OBJECT (rtpsession, "creating sync src pad");
+  rtpsession->sync_src =
+      gst_pad_new_from_static_template (&rtpsession_sync_src_template,
+      "sync_src");
+  gst_pad_set_iterate_internal_links_function (rtpsession->sync_src,
+      gst_rtp_session_iterate_internal_links);
+  gst_pad_use_fixed_caps (rtpsession->sync_src);
+  gst_pad_set_active (rtpsession->sync_src, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpsession), rtpsession->sync_src);
+
+  return rtpsession->recv_rtcp_sink;
+}
+
+static void
+remove_recv_rtcp_sink (GstRtpSession * rtpsession)
+{
+  GST_DEBUG_OBJECT (rtpsession, "removing RTCP sink pad");
+
+  gst_pad_set_active (rtpsession->sync_src, FALSE);
+  gst_pad_set_active (rtpsession->recv_rtcp_sink, FALSE);
+
+  gst_element_remove_pad (GST_ELEMENT_CAST (rtpsession),
+      rtpsession->recv_rtcp_sink);
+  rtpsession->recv_rtcp_sink = NULL;
+
+  GST_DEBUG_OBJECT (rtpsession, "removing sync src pad");
+  gst_element_remove_pad (GST_ELEMENT_CAST (rtpsession), rtpsession->sync_src);
+  rtpsession->sync_src = NULL;
+}
+
+/* Create a sinkpad to receive RTP packets for receivers. This will also create a
+ * send_rtp_src pad.
+ */
+static GstPad *
+create_send_rtp_sink (GstRtpSession * rtpsession)
+{
+  GST_DEBUG_OBJECT (rtpsession, "creating pad");
+
+  rtpsession->send_rtp_sink =
+      gst_pad_new_from_static_template (&rtpsession_send_rtp_sink_template,
+      "send_rtp_sink");
+  gst_pad_set_chain_function (rtpsession->send_rtp_sink,
+      gst_rtp_session_chain_send_rtp);
+  gst_pad_set_chain_list_function (rtpsession->send_rtp_sink,
+      gst_rtp_session_chain_send_rtp_list);
+  gst_pad_set_query_function (rtpsession->send_rtp_sink,
+      gst_rtp_session_query_send_rtp);
+  gst_pad_set_event_function (rtpsession->send_rtp_sink,
+      gst_rtp_session_event_send_rtp_sink);
+  gst_pad_set_iterate_internal_links_function (rtpsession->send_rtp_sink,
+      gst_rtp_session_iterate_internal_links);
+  GST_PAD_SET_PROXY_CAPS (rtpsession->send_rtp_sink);
+  GST_PAD_SET_PROXY_ALLOCATION (rtpsession->send_rtp_sink);
+  gst_pad_set_active (rtpsession->send_rtp_sink, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpsession),
+      rtpsession->send_rtp_sink);
+
+  rtpsession->send_rtp_src =
+      gst_pad_new_from_static_template (&rtpsession_send_rtp_src_template,
+      "send_rtp_src");
+  gst_pad_set_iterate_internal_links_function (rtpsession->send_rtp_src,
+      gst_rtp_session_iterate_internal_links);
+  gst_pad_set_event_function (rtpsession->send_rtp_src,
+      gst_rtp_session_event_send_rtp_src);
+  GST_PAD_SET_PROXY_CAPS (rtpsession->send_rtp_src);
+  gst_pad_set_active (rtpsession->send_rtp_src, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpsession), rtpsession->send_rtp_src);
+
+  return rtpsession->send_rtp_sink;
+}
+
+static void
+remove_send_rtp_sink (GstRtpSession * rtpsession)
+{
+  GST_DEBUG_OBJECT (rtpsession, "removing pad");
+
+  gst_pad_set_active (rtpsession->send_rtp_src, FALSE);
+  gst_pad_set_active (rtpsession->send_rtp_sink, FALSE);
+
+  gst_element_remove_pad (GST_ELEMENT_CAST (rtpsession),
+      rtpsession->send_rtp_sink);
+  rtpsession->send_rtp_sink = NULL;
+
+  gst_element_remove_pad (GST_ELEMENT_CAST (rtpsession),
+      rtpsession->send_rtp_src);
+  rtpsession->send_rtp_src = NULL;
+}
+
+/* Create a srcpad with the RTCP packets to send out.
+ * This pad will be driven by the RTP session manager when it wants to send out
+ * RTCP packets.
+ */
+static GstPad *
+create_send_rtcp_src (GstRtpSession * rtpsession)
+{
+  GST_DEBUG_OBJECT (rtpsession, "creating pad");
+
+  rtpsession->send_rtcp_src =
+      gst_pad_new_from_static_template (&rtpsession_send_rtcp_src_template,
+      "send_rtcp_src");
+  gst_pad_use_fixed_caps (rtpsession->send_rtcp_src);
+  gst_pad_set_active (rtpsession->send_rtcp_src, TRUE);
+  gst_pad_set_iterate_internal_links_function (rtpsession->send_rtcp_src,
+      gst_rtp_session_iterate_internal_links);
+  gst_pad_set_query_function (rtpsession->send_rtcp_src,
+      gst_rtp_session_query_send_rtcp_src);
+  gst_pad_set_event_function (rtpsession->send_rtcp_src,
+      gst_rtp_session_event_send_rtcp_src);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpsession),
+      rtpsession->send_rtcp_src);
+
+  return rtpsession->send_rtcp_src;
+}
+
+static void
+remove_send_rtcp_src (GstRtpSession * rtpsession)
+{
+  GST_DEBUG_OBJECT (rtpsession, "removing pad");
+
+  gst_pad_set_active (rtpsession->send_rtcp_src, FALSE);
+
+  gst_element_remove_pad (GST_ELEMENT_CAST (rtpsession),
+      rtpsession->send_rtcp_src);
+  rtpsession->send_rtcp_src = NULL;
+}
+
+static GstPad *
+gst_rtp_session_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
+{
+  GstRtpSession *rtpsession;
+  GstElementClass *klass;
+  GstPad *result;
+
+  g_return_val_if_fail (templ != NULL, NULL);
+  g_return_val_if_fail (GST_IS_RTP_SESSION (element), NULL);
+
+  rtpsession = GST_RTP_SESSION (element);
+  klass = GST_ELEMENT_GET_CLASS (element);
+
+  GST_DEBUG_OBJECT (element, "requesting pad %s", GST_STR_NULL (name));
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+
+  /* figure out the template */
+  if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink")) {
+    if (rtpsession->recv_rtp_sink != NULL)
+      goto exists;
+
+    result = create_recv_rtp_sink (rtpsession);
+  } else if (templ == gst_element_class_get_pad_template (klass,
+          "recv_rtcp_sink")) {
+    if (rtpsession->recv_rtcp_sink != NULL)
+      goto exists;
+
+    result = create_recv_rtcp_sink (rtpsession);
+  } else if (templ == gst_element_class_get_pad_template (klass,
+          "send_rtp_sink")) {
+    if (rtpsession->send_rtp_sink != NULL)
+      goto exists;
+
+    result = create_send_rtp_sink (rtpsession);
+  } else if (templ == gst_element_class_get_pad_template (klass,
+          "send_rtcp_src")) {
+    if (rtpsession->send_rtcp_src != NULL)
+      goto exists;
+
+    result = create_send_rtcp_src (rtpsession);
+  } else
+    goto wrong_template;
+
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  return result;
+
+  /* ERRORS */
+wrong_template:
+  {
+    GST_RTP_SESSION_UNLOCK (rtpsession);
+    g_warning ("rtpsession: this is not our template");
+    return NULL;
+  }
+exists:
+  {
+    GST_RTP_SESSION_UNLOCK (rtpsession);
+    g_warning ("rtpsession: pad already requested");
+    return NULL;
+  }
+}
+
+static void
+gst_rtp_session_release_pad (GstElement * element, GstPad * pad)
+{
+  GstRtpSession *rtpsession;
+
+  g_return_if_fail (GST_IS_RTP_SESSION (element));
+  g_return_if_fail (GST_IS_PAD (pad));
+
+  rtpsession = GST_RTP_SESSION (element);
+
+  GST_DEBUG_OBJECT (element, "releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+
+  if (rtpsession->recv_rtp_sink == pad) {
+    remove_recv_rtp_sink (rtpsession);
+  } else if (rtpsession->recv_rtcp_sink == pad) {
+    remove_recv_rtcp_sink (rtpsession);
+  } else if (rtpsession->send_rtp_sink == pad) {
+    remove_send_rtp_sink (rtpsession);
+  } else if (rtpsession->send_rtcp_src == pad) {
+    remove_send_rtcp_src (rtpsession);
+  } else
+    goto wrong_pad;
+
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  return;
+
+  /* ERRORS */
+wrong_pad:
+  {
+    GST_RTP_SESSION_UNLOCK (rtpsession);
+    g_warning ("rtpsession: asked to release an unknown pad");
+    return;
+  }
+}
+
+static void
+gst_rtp_session_request_key_unit (RTPSession * sess,
+    guint32 ssrc, gboolean all_headers, gpointer user_data)
+{
+  GstRtpSession *rtpsession = GST_RTP_SESSION (user_data);
+  GstEvent *event;
+  GstPad *send_rtp_sink;
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+  if ((send_rtp_sink = rtpsession->send_rtp_sink))
+    gst_object_ref (send_rtp_sink);
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  if (send_rtp_sink) {
+    event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+        gst_structure_new ("GstForceKeyUnit", "ssrc", G_TYPE_UINT, ssrc,
+            "all-headers", G_TYPE_BOOLEAN, all_headers, NULL));
+    gst_pad_push_event (send_rtp_sink, event);
+    gst_object_unref (send_rtp_sink);
+  }
+}
+
+static GstClockTime
+gst_rtp_session_request_time (RTPSession * session, gpointer user_data)
+{
+  GstRtpSession *rtpsession = GST_RTP_SESSION (user_data);
+
+  return gst_clock_get_time (rtpsession->priv->sysclock);
+}
+
+static void
+gst_rtp_session_notify_nack (RTPSession * sess, guint16 seqnum,
+    guint16 blp, guint32 ssrc, gpointer user_data)
+{
+  GstRtpSession *rtpsession = GST_RTP_SESSION (user_data);
+  GstEvent *event;
+  GstPad *send_rtp_sink;
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+  if ((send_rtp_sink = rtpsession->send_rtp_sink))
+    gst_object_ref (send_rtp_sink);
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  if (send_rtp_sink) {
+    while (TRUE) {
+      event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+          gst_structure_new ("GstRTPRetransmissionRequest",
+              "seqnum", G_TYPE_UINT, (guint) seqnum,
+              "ssrc", G_TYPE_UINT, (guint) ssrc, NULL));
+      gst_pad_push_event (send_rtp_sink, event);
+
+      if (blp == 0)
+        break;
+
+      seqnum++;
+      while ((blp & 1) == 0) {
+        seqnum++;
+        blp >>= 1;
+      }
+      blp >>= 1;
+    }
+    gst_object_unref (send_rtp_sink);
+  }
+}
+
+static void
+gst_rtp_session_reconfigure (RTPSession * sess, gpointer user_data)
+{
+  GstRtpSession *rtpsession = GST_RTP_SESSION (user_data);
+  GstPad *send_rtp_sink;
+
+  GST_RTP_SESSION_LOCK (rtpsession);
+  if ((send_rtp_sink = rtpsession->send_rtp_sink))
+    gst_object_ref (send_rtp_sink);
+  GST_RTP_SESSION_UNLOCK (rtpsession);
+
+  if (send_rtp_sink) {
+    gst_pad_push_event (send_rtp_sink, gst_event_new_reconfigure ());
+    gst_object_unref (send_rtp_sink);
+  }
+}
diff --git a/gst/rtpmanager/gstrtpsession.h b/gst/rtpmanager/gstrtpsession.h
new file mode 100644
index 0000000..1c1c109
--- /dev/null
+++ b/gst/rtpmanager/gstrtpsession.h
@@ -0,0 +1,90 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_SESSION_H__
+#define __GST_RTP_SESSION_H__
+
+#include <gst/gst.h>
+
+#define GST_TYPE_RTP_SESSION \
+  (gst_rtp_session_get_type())
+#define GST_RTP_SESSION(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SESSION,GstRtpSession))
+#define GST_RTP_SESSION_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SESSION,GstRtpSessionClass))
+#define GST_IS_RTP_SESSION(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SESSION))
+#define GST_IS_RTP_SESSION_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SESSION))
+#define GST_RTP_SESSION_CAST(obj) ((GstRtpSession *)(obj))
+
+typedef struct _GstRtpSession GstRtpSession;
+typedef struct _GstRtpSessionClass GstRtpSessionClass;
+typedef struct _GstRtpSessionPrivate GstRtpSessionPrivate;
+
+struct _GstRtpSession {
+  GstElement     element;
+
+  /*< private >*/
+  GstPad        *recv_rtp_sink;
+  GstSegment     recv_rtp_seg;
+  GstPad        *recv_rtcp_sink;
+  GstPad        *send_rtp_sink;
+  GstSegment     send_rtp_seg;
+
+  GstPad        *recv_rtp_src;
+  GstPad        *sync_src;
+  GstPad        *send_rtp_src;
+  GstPad        *send_rtcp_src;
+
+  GstRtpSessionPrivate *priv;
+};
+
+struct _GstRtpSessionClass {
+  GstElementClass parent_class;
+
+  /* signals */
+  GstCaps* (*request_pt_map) (GstRtpSession *sess, guint pt);
+  void     (*clear_pt_map)   (GstRtpSession *sess);
+
+  void     (*on_new_ssrc)       (GstRtpSession *sess, guint32 ssrc);
+  void     (*on_ssrc_collision) (GstRtpSession *sess, guint32 ssrc);
+  void     (*on_ssrc_validated) (GstRtpSession *sess, guint32 ssrc);
+  void     (*on_ssrc_active)    (GstRtpSession *sess, guint32 ssrc);
+  void     (*on_ssrc_sdes)      (GstRtpSession *sess, guint32 ssrc);
+  void     (*on_bye_ssrc)       (GstRtpSession *sess, guint32 ssrc);
+  void     (*on_bye_timeout)    (GstRtpSession *sess, guint32 ssrc);
+  void     (*on_timeout)        (GstRtpSession *sess, guint32 ssrc);
+  void     (*on_sender_timeout) (GstRtpSession *sess, guint32 ssrc);
+  void     (*on_new_sender_ssrc)      (GstRtpSession *sess, guint32 ssrc);
+  void     (*on_sender_ssrc_active)   (GstRtpSession *sess, guint32 ssrc);
+};
+
+GType gst_rtp_session_get_type (void);
+
+typedef enum {
+  GST_RTP_NTP_TIME_SOURCE_NTP,
+  GST_RTP_NTP_TIME_SOURCE_UNIX,
+  GST_RTP_NTP_TIME_SOURCE_RUNNING_TIME,
+  GST_RTP_NTP_TIME_SOURCE_CLOCK_TIME
+} GstRtpNtpTimeSource;
+
+GType gst_rtp_ntp_time_source_get_type (void);
+
+#endif /* __GST_RTP_SESSION_H__ */
diff --git a/gst/rtpmanager/gstrtpssrcdemux.c b/gst/rtpmanager/gstrtpssrcdemux.c
new file mode 100644
index 0000000..c4a3c43
--- /dev/null
+++ b/gst/rtpmanager/gstrtpssrcdemux.c
@@ -0,0 +1,956 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * RTP SSRC demuxer
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpssrcdemux
+ *
+ * rtpssrcdemux acts as a demuxer for RTP packets based on the SSRC of the
+ * packets. Its main purpose is to allow an application to easily receive and
+ * decode an RTP stream with multiple SSRCs.
+ * 
+ * For each SSRC that is detected, a new pad will be created and the
+ * #GstRtpSsrcDemux::new-ssrc-pad signal will be emitted. 
+ * 
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 udpsrc caps="application/x-rtp" ! rtpssrcdemux ! fakesink
+ * ]| Takes an RTP stream and send the RTP packets with the first detected SSRC
+ * to fakesink, discarding the other SSRCs.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/rtp/gstrtcpbuffer.h>
+
+#include "gstrtpssrcdemux.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_ssrc_demux_debug);
+#define GST_CAT_DEFAULT gst_rtp_ssrc_demux_debug
+
+/* generic templates */
+static GstStaticPadTemplate rtp_ssrc_demux_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static GstStaticPadTemplate rtp_ssrc_demux_rtcp_sink_template =
+GST_STATIC_PAD_TEMPLATE ("rtcp_sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtcp")
+    );
+
+static GstStaticPadTemplate rtp_ssrc_demux_src_template =
+GST_STATIC_PAD_TEMPLATE ("src_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static GstStaticPadTemplate rtp_ssrc_demux_rtcp_src_template =
+GST_STATIC_PAD_TEMPLATE ("rtcp_src_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("application/x-rtcp")
+    );
+
+#define GST_PAD_LOCK(obj)   (g_rec_mutex_lock (&(obj)->padlock))
+#define GST_PAD_UNLOCK(obj) (g_rec_mutex_unlock (&(obj)->padlock))
+
+typedef enum
+{
+  RTP_PAD,
+  RTCP_PAD
+} PadType;
+
+/* signals */
+enum
+{
+  SIGNAL_NEW_SSRC_PAD,
+  SIGNAL_REMOVED_SSRC_PAD,
+  SIGNAL_CLEAR_SSRC,
+  LAST_SIGNAL
+};
+
+#define gst_rtp_ssrc_demux_parent_class parent_class
+G_DEFINE_TYPE (GstRtpSsrcDemux, gst_rtp_ssrc_demux, GST_TYPE_ELEMENT);
+
+/* GObject vmethods */
+static void gst_rtp_ssrc_demux_dispose (GObject * object);
+static void gst_rtp_ssrc_demux_finalize (GObject * object);
+
+/* GstElement vmethods */
+static GstStateChangeReturn gst_rtp_ssrc_demux_change_state (GstElement *
+    element, GstStateChange transition);
+
+static void gst_rtp_ssrc_demux_clear_ssrc (GstRtpSsrcDemux * demux,
+    guint32 ssrc);
+
+/* sinkpad stuff */
+static GstFlowReturn gst_rtp_ssrc_demux_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buf);
+static gboolean gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+
+static GstFlowReturn gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad,
+    GstObject * parent, GstBuffer * buf);
+static GstIterator *gst_rtp_ssrc_demux_iterate_internal_links_sink (GstPad *
+    pad, GstObject * parent);
+
+/* srcpad stuff */
+static gboolean gst_rtp_ssrc_demux_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static GstIterator *gst_rtp_ssrc_demux_iterate_internal_links_src (GstPad * pad,
+    GstObject * parent);
+static gboolean gst_rtp_ssrc_demux_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+
+static guint gst_rtp_ssrc_demux_signals[LAST_SIGNAL] = { 0 };
+
+/*
+ * Item for storing GstPad <-> SSRC pairs.
+ */
+struct _GstRtpSsrcDemuxPad
+{
+  guint32 ssrc;
+  GstPad *rtp_pad;
+  GstCaps *caps;
+  GstPad *rtcp_pad;
+
+  gboolean pushed_initial_rtp_events;
+  gboolean pushed_initial_rtcp_events;
+};
+
+/* find a src pad for a given SSRC, returns NULL if the SSRC was not found
+ */
+static GstRtpSsrcDemuxPad *
+find_demux_pad_for_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc)
+{
+  GSList *walk;
+
+  for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
+    GstRtpSsrcDemuxPad *pad = (GstRtpSsrcDemuxPad *) walk->data;
+
+    if (pad->ssrc == ssrc)
+      return pad;
+  }
+  return NULL;
+}
+
+static GstEvent *
+add_ssrc_and_ref (GstEvent * event, guint32 ssrc)
+{
+  /* Set the ssrc on the output caps */
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+      GstCaps *newcaps;
+      GstStructure *s;
+
+      gst_event_parse_caps (event, &caps);
+      newcaps = gst_caps_copy (caps);
+
+      s = gst_caps_get_structure (newcaps, 0);
+      gst_structure_set (s, "ssrc", G_TYPE_UINT, ssrc, NULL);
+      event = gst_event_new_caps (newcaps);
+      gst_caps_unref (newcaps);
+      break;
+    }
+    default:
+      gst_event_ref (event);
+      break;
+  }
+
+  return event;
+}
+
+struct ForwardStickyEventData
+{
+  GstPad *pad;
+  guint32 ssrc;
+};
+
+static gboolean
+forward_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
+{
+  struct ForwardStickyEventData *data = user_data;
+  GstEvent *newevent;
+
+  newevent = add_ssrc_and_ref (*event, data->ssrc);
+
+  gst_pad_push_event (data->pad, newevent);
+
+  return TRUE;
+}
+
+static void
+forward_initial_events (GstRtpSsrcDemux * demux, guint32 ssrc, GstPad * pad,
+    PadType padtype)
+{
+  struct ForwardStickyEventData fdata;
+  GstPad *sinkpad = NULL;
+
+  if (padtype == RTP_PAD)
+    sinkpad = demux->rtp_sink;
+  else if (padtype == RTCP_PAD)
+    sinkpad = demux->rtcp_sink;
+  else
+    g_assert_not_reached ();
+
+  fdata.ssrc = ssrc;
+  fdata.pad = pad;
+
+  gst_pad_sticky_events_foreach (sinkpad, forward_sticky_events, &fdata);
+}
+
+static GstPad *
+find_or_create_demux_pad_for_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc,
+    PadType padtype)
+{
+  GstPad *rtp_pad, *rtcp_pad;
+  GstElementClass *klass;
+  GstPadTemplate *templ;
+  gchar *padname;
+  GstRtpSsrcDemuxPad *demuxpad;
+  GstPad *retpad;
+  gulong rtp_block, rtcp_block;
+
+  GST_PAD_LOCK (demux);
+
+  demuxpad = find_demux_pad_for_ssrc (demux, ssrc);
+  if (demuxpad != NULL) {
+    gboolean forward = FALSE;
+
+    switch (padtype) {
+      case RTP_PAD:
+        retpad = gst_object_ref (demuxpad->rtp_pad);
+        if (!demuxpad->pushed_initial_rtp_events) {
+          forward = TRUE;
+          demuxpad->pushed_initial_rtp_events = TRUE;
+        }
+        break;
+      case RTCP_PAD:
+        retpad = gst_object_ref (demuxpad->rtcp_pad);
+        if (!demuxpad->pushed_initial_rtcp_events) {
+          forward = TRUE;
+          demuxpad->pushed_initial_rtcp_events = TRUE;
+        }
+        break;
+      default:
+        retpad = NULL;
+        g_assert_not_reached ();
+    }
+
+    GST_PAD_UNLOCK (demux);
+
+    if (forward)
+      forward_initial_events (demux, ssrc, retpad, padtype);
+    return retpad;
+  }
+
+  GST_DEBUG_OBJECT (demux, "creating new pad for SSRC %08x", ssrc);
+
+  klass = GST_ELEMENT_GET_CLASS (demux);
+  templ = gst_element_class_get_pad_template (klass, "src_%u");
+  padname = g_strdup_printf ("src_%u", ssrc);
+  rtp_pad = gst_pad_new_from_template (templ, padname);
+  g_free (padname);
+
+  templ = gst_element_class_get_pad_template (klass, "rtcp_src_%u");
+  padname = g_strdup_printf ("rtcp_src_%u", ssrc);
+  rtcp_pad = gst_pad_new_from_template (templ, padname);
+  g_free (padname);
+
+  /* wrap in structure and add to list */
+  demuxpad = g_new0 (GstRtpSsrcDemuxPad, 1);
+  demuxpad->ssrc = ssrc;
+  demuxpad->rtp_pad = rtp_pad;
+  demuxpad->rtcp_pad = rtcp_pad;
+
+  gst_pad_set_element_private (rtp_pad, demuxpad);
+  gst_pad_set_element_private (rtcp_pad, demuxpad);
+
+  demux->srcpads = g_slist_prepend (demux->srcpads, demuxpad);
+
+  gst_pad_set_query_function (rtp_pad, gst_rtp_ssrc_demux_src_query);
+  gst_pad_set_iterate_internal_links_function (rtp_pad,
+      gst_rtp_ssrc_demux_iterate_internal_links_src);
+  gst_pad_set_event_function (rtp_pad, gst_rtp_ssrc_demux_src_event);
+  gst_pad_use_fixed_caps (rtp_pad);
+  gst_pad_set_active (rtp_pad, TRUE);
+
+  gst_pad_set_event_function (rtcp_pad, gst_rtp_ssrc_demux_src_event);
+  gst_pad_set_iterate_internal_links_function (rtcp_pad,
+      gst_rtp_ssrc_demux_iterate_internal_links_src);
+  gst_pad_use_fixed_caps (rtcp_pad);
+  gst_pad_set_active (rtcp_pad, TRUE);
+
+  if (padtype == RTP_PAD) {
+    demuxpad->pushed_initial_rtp_events = TRUE;
+    forward_initial_events (demux, ssrc, rtp_pad, padtype);
+  } else if (padtype == RTCP_PAD) {
+    demuxpad->pushed_initial_rtcp_events = TRUE;
+    forward_initial_events (demux, ssrc, rtcp_pad, padtype);
+  } else {
+    g_assert_not_reached ();
+  }
+
+  gst_element_add_pad (GST_ELEMENT_CAST (demux), rtp_pad);
+  gst_element_add_pad (GST_ELEMENT_CAST (demux), rtcp_pad);
+
+  switch (padtype) {
+    case RTP_PAD:
+      retpad = gst_object_ref (demuxpad->rtp_pad);
+      break;
+    case RTCP_PAD:
+      retpad = gst_object_ref (demuxpad->rtcp_pad);
+      break;
+    default:
+      retpad = NULL;
+      g_assert_not_reached ();
+  }
+
+  gst_object_ref (rtp_pad);
+  gst_object_ref (rtcp_pad);
+
+  rtp_block = gst_pad_add_probe (rtp_pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+      NULL, NULL, NULL);
+  rtcp_block = gst_pad_add_probe (rtcp_pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+      NULL, NULL, NULL);
+
+  GST_PAD_UNLOCK (demux);
+
+  g_signal_emit (G_OBJECT (demux),
+      gst_rtp_ssrc_demux_signals[SIGNAL_NEW_SSRC_PAD], 0, ssrc, rtp_pad);
+
+  gst_pad_remove_probe (rtp_pad, rtp_block);
+  gst_pad_remove_probe (rtcp_pad, rtcp_block);
+
+  gst_object_unref (rtp_pad);
+  gst_object_unref (rtcp_pad);
+
+  return retpad;
+}
+
+static void
+gst_rtp_ssrc_demux_class_init (GstRtpSsrcDemuxClass * klass)
+{
+  GObjectClass *gobject_klass;
+  GstElementClass *gstelement_klass;
+  GstRtpSsrcDemuxClass *gstrtpssrcdemux_klass;
+
+  gobject_klass = (GObjectClass *) klass;
+  gstelement_klass = (GstElementClass *) klass;
+  gstrtpssrcdemux_klass = (GstRtpSsrcDemuxClass *) klass;
+
+  gobject_klass->dispose = gst_rtp_ssrc_demux_dispose;
+  gobject_klass->finalize = gst_rtp_ssrc_demux_finalize;
+
+  /**
+   * GstRtpSsrcDemux::new-ssrc-pad:
+   * @demux: the object which received the signal
+   * @ssrc: the SSRC of the pad
+   * @pad: the new pad.
+   *
+   * Emited when a new SSRC pad has been created.
+   */
+  gst_rtp_ssrc_demux_signals[SIGNAL_NEW_SSRC_PAD] =
+      g_signal_new ("new-ssrc-pad",
+      G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstRtpSsrcDemuxClass, new_ssrc_pad),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      GST_TYPE_PAD);
+
+  /**
+   * GstRtpSsrcDemux::removed-ssrc-pad:
+   * @demux: the object which received the signal
+   * @ssrc: the SSRC of the pad
+   * @pad: the removed pad.
+   *
+   * Emited when a SSRC pad has been removed.
+   */
+  gst_rtp_ssrc_demux_signals[SIGNAL_REMOVED_SSRC_PAD] =
+      g_signal_new ("removed-ssrc-pad",
+      G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstRtpSsrcDemuxClass, removed_ssrc_pad),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      GST_TYPE_PAD);
+
+  /**
+   * GstRtpSsrcDemux::clear-ssrc:
+   * @demux: the object which received the signal
+   * @ssrc: the SSRC of the pad
+   *
+   * Action signal to remove the pad for SSRC.
+   */
+  gst_rtp_ssrc_demux_signals[SIGNAL_CLEAR_SSRC] =
+      g_signal_new ("clear-ssrc",
+      G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_STRUCT_OFFSET (GstRtpSsrcDemuxClass, clear_ssrc),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_UINT);
+
+  gstelement_klass->change_state =
+      GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_change_state);
+  gstrtpssrcdemux_klass->clear_ssrc =
+      GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_clear_ssrc);
+
+  gst_element_class_add_static_pad_template (gstelement_klass,
+      &rtp_ssrc_demux_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_klass,
+      &rtp_ssrc_demux_rtcp_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_klass,
+      &rtp_ssrc_demux_src_template);
+  gst_element_class_add_static_pad_template (gstelement_klass,
+      &rtp_ssrc_demux_rtcp_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_klass, "RTP SSRC Demux",
+      "Demux/Network/RTP",
+      "Splits RTP streams based on the SSRC",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  GST_DEBUG_CATEGORY_INIT (gst_rtp_ssrc_demux_debug,
+      "rtpssrcdemux", 0, "RTP SSRC demuxer");
+}
+
+static void
+gst_rtp_ssrc_demux_init (GstRtpSsrcDemux * demux)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (demux);
+
+  demux->rtp_sink =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "sink"), "sink");
+  gst_pad_set_chain_function (demux->rtp_sink, gst_rtp_ssrc_demux_chain);
+  gst_pad_set_event_function (demux->rtp_sink, gst_rtp_ssrc_demux_sink_event);
+  gst_pad_set_iterate_internal_links_function (demux->rtp_sink,
+      gst_rtp_ssrc_demux_iterate_internal_links_sink);
+  gst_element_add_pad (GST_ELEMENT_CAST (demux), demux->rtp_sink);
+
+  demux->rtcp_sink =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "rtcp_sink"), "rtcp_sink");
+  gst_pad_set_chain_function (demux->rtcp_sink, gst_rtp_ssrc_demux_rtcp_chain);
+  gst_pad_set_event_function (demux->rtcp_sink, gst_rtp_ssrc_demux_sink_event);
+  gst_pad_set_iterate_internal_links_function (demux->rtcp_sink,
+      gst_rtp_ssrc_demux_iterate_internal_links_sink);
+  gst_element_add_pad (GST_ELEMENT_CAST (demux), demux->rtcp_sink);
+
+  g_rec_mutex_init (&demux->padlock);
+}
+
+static void
+gst_rtp_ssrc_demux_reset (GstRtpSsrcDemux * demux)
+{
+  GSList *walk;
+
+  for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
+    GstRtpSsrcDemuxPad *dpad = (GstRtpSsrcDemuxPad *) walk->data;
+
+    gst_pad_set_active (dpad->rtp_pad, FALSE);
+    gst_pad_set_active (dpad->rtcp_pad, FALSE);
+
+    gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtp_pad);
+    gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtcp_pad);
+    g_free (dpad);
+  }
+  g_slist_free (demux->srcpads);
+  demux->srcpads = NULL;
+}
+
+static void
+gst_rtp_ssrc_demux_dispose (GObject * object)
+{
+  GstRtpSsrcDemux *demux;
+
+  demux = GST_RTP_SSRC_DEMUX (object);
+
+  gst_rtp_ssrc_demux_reset (demux);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_rtp_ssrc_demux_finalize (GObject * object)
+{
+  GstRtpSsrcDemux *demux;
+
+  demux = GST_RTP_SSRC_DEMUX (object);
+  g_rec_mutex_clear (&demux->padlock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_ssrc_demux_clear_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc)
+{
+  GstRtpSsrcDemuxPad *dpad;
+
+  GST_PAD_LOCK (demux);
+  dpad = find_demux_pad_for_ssrc (demux, ssrc);
+  if (dpad == NULL) {
+    GST_PAD_UNLOCK (demux);
+    goto unknown_pad;
+  }
+
+  GST_DEBUG_OBJECT (demux, "clearing pad for SSRC %08x", ssrc);
+
+  demux->srcpads = g_slist_remove (demux->srcpads, dpad);
+  GST_PAD_UNLOCK (demux);
+
+  gst_pad_set_active (dpad->rtp_pad, FALSE);
+  gst_pad_set_active (dpad->rtcp_pad, FALSE);
+
+  g_signal_emit (G_OBJECT (demux),
+      gst_rtp_ssrc_demux_signals[SIGNAL_REMOVED_SSRC_PAD], 0, ssrc,
+      dpad->rtp_pad);
+
+  gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtp_pad);
+  gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtcp_pad);
+
+  g_free (dpad);
+
+  return;
+
+  /* ERRORS */
+unknown_pad:
+  {
+    GST_WARNING_OBJECT (demux, "unknown SSRC %08x", ssrc);
+    return;
+  }
+}
+
+struct ForwardEventData
+{
+  GstRtpSsrcDemux *demux;
+  GstEvent *event;
+  gboolean res;
+  GstPad *pad;
+};
+
+static gboolean
+forward_event (GstPad * pad, gpointer user_data)
+{
+  struct ForwardEventData *fdata = user_data;
+  GSList *walk = NULL;
+  GstEvent *newevent = NULL;
+
+  GST_PAD_LOCK (fdata->demux);
+  for (walk = fdata->demux->srcpads; walk; walk = walk->next) {
+    GstRtpSsrcDemuxPad *dpad = (GstRtpSsrcDemuxPad *) walk->data;
+
+    /* Only forward the event if the initial events have been through first,
+     * the initial events should be forwarded before any other event
+     * or buffer is pushed */
+    if ((pad == dpad->rtp_pad && dpad->pushed_initial_rtp_events) ||
+        (pad == dpad->rtcp_pad && dpad->pushed_initial_rtcp_events)) {
+      newevent = add_ssrc_and_ref (fdata->event, dpad->ssrc);
+      break;
+    }
+  }
+  GST_PAD_UNLOCK (fdata->demux);
+
+  if (newevent)
+    fdata->res &= gst_pad_push_event (pad, newevent);
+
+  return TRUE;
+}
+
+
+static gboolean
+gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstRtpSsrcDemux *demux;
+  struct ForwardEventData fdata;
+
+  demux = GST_RTP_SSRC_DEMUX (parent);
+
+  fdata.demux = demux;
+  fdata.pad = pad;
+  fdata.event = event;
+  fdata.res = TRUE;
+
+  gst_pad_forward (pad, forward_event, &fdata);
+
+  gst_event_unref (event);
+
+  return fdata.res;
+}
+
+static GstFlowReturn
+gst_rtp_ssrc_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstFlowReturn ret;
+  GstRtpSsrcDemux *demux;
+  guint32 ssrc;
+  GstRTPBuffer rtp = { NULL };
+  GstPad *srcpad;
+  GstRtpSsrcDemuxPad *dpad;
+
+  demux = GST_RTP_SSRC_DEMUX (parent);
+
+  if (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp))
+    goto invalid_payload;
+
+  ssrc = gst_rtp_buffer_get_ssrc (&rtp);
+  gst_rtp_buffer_unmap (&rtp);
+
+  GST_DEBUG_OBJECT (demux, "received buffer of SSRC %08x", ssrc);
+
+  srcpad = find_or_create_demux_pad_for_ssrc (demux, ssrc, RTP_PAD);
+  if (srcpad == NULL)
+    goto create_failed;
+
+  /* push to srcpad */
+  ret = gst_pad_push (srcpad, buf);
+
+  if (ret != GST_FLOW_OK) {
+    /* check if the ssrc still there, may have been removed */
+    GST_PAD_LOCK (demux);
+    dpad = find_demux_pad_for_ssrc (demux, ssrc);
+    if (dpad == NULL || dpad->rtp_pad != srcpad) {
+      /* SSRC was removed during the push ... ignore the error */
+      ret = GST_FLOW_OK;
+    }
+    GST_PAD_UNLOCK (demux);
+  }
+
+  gst_object_unref (srcpad);
+
+  return ret;
+
+  /* ERRORS */
+invalid_payload:
+  {
+    /* this is fatal and should be filtered earlier */
+    GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
+        ("Dropping invalid RTP payload"));
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+create_failed:
+  {
+    GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
+        ("Could not create new pad"));
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstFlowReturn
+gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buf)
+{
+  GstFlowReturn ret;
+  GstRtpSsrcDemux *demux;
+  guint32 ssrc;
+  GstRTCPPacket packet;
+  GstRTCPBuffer rtcp = { NULL, };
+  GstPad *srcpad;
+  GstRtpSsrcDemuxPad *dpad;
+
+  demux = GST_RTP_SSRC_DEMUX (parent);
+
+  if (!gst_rtcp_buffer_validate_reduced (buf))
+    goto invalid_rtcp;
+
+  gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp);
+  if (!gst_rtcp_buffer_get_first_packet (&rtcp, &packet)) {
+    gst_rtcp_buffer_unmap (&rtcp);
+    goto invalid_rtcp;
+  }
+
+  /* first packet must be SR or RR, or in case of a reduced size RTCP packet
+   * it must be APP, RTPFB or PSFB feeadback, or else the validate would
+   * have failed */
+  switch (gst_rtcp_packet_get_type (&packet)) {
+    case GST_RTCP_TYPE_SR:
+      /* get the ssrc so that we can route it to the right source pad */
+      gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, NULL, NULL, NULL,
+          NULL);
+      break;
+    case GST_RTCP_TYPE_RR:
+      ssrc = gst_rtcp_packet_rr_get_ssrc (&packet);
+      break;
+    case GST_RTCP_TYPE_APP:
+    case GST_RTCP_TYPE_RTPFB:
+    case GST_RTCP_TYPE_PSFB:
+      ssrc = gst_rtcp_packet_fb_get_sender_ssrc (&packet);
+      break;
+    default:
+      goto unexpected_rtcp;
+  }
+  gst_rtcp_buffer_unmap (&rtcp);
+
+  GST_DEBUG_OBJECT (demux, "received RTCP of SSRC %08x", ssrc);
+
+  srcpad = find_or_create_demux_pad_for_ssrc (demux, ssrc, RTCP_PAD);
+  if (srcpad == NULL)
+    goto create_failed;
+
+  /* push to srcpad */
+  ret = gst_pad_push (srcpad, buf);
+
+  if (ret != GST_FLOW_OK) {
+    /* check if the ssrc still there, may have been removed */
+    GST_PAD_LOCK (demux);
+    dpad = find_demux_pad_for_ssrc (demux, ssrc);
+    if (dpad == NULL || dpad->rtcp_pad != srcpad) {
+      /* SSRC was removed during the push ... ignore the error */
+      ret = GST_FLOW_OK;
+    }
+    GST_PAD_UNLOCK (demux);
+  }
+
+  gst_object_unref (srcpad);
+
+  return ret;
+
+  /* ERRORS */
+invalid_rtcp:
+  {
+    /* this is fatal and should be filtered earlier */
+    GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
+        ("Dropping invalid RTCP packet"));
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+unexpected_rtcp:
+  {
+    GST_DEBUG_OBJECT (demux, "dropping unexpected RTCP packet");
+    gst_buffer_unref (buf);
+    return GST_FLOW_OK;
+  }
+create_failed:
+  {
+    GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
+        ("Could not create new pad"));
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstRtpSsrcDemuxPad *
+find_demux_pad_for_pad (GstRtpSsrcDemux * demux, GstPad * pad)
+{
+  GSList *walk;
+
+  for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
+    GstRtpSsrcDemuxPad *dpad = (GstRtpSsrcDemuxPad *) walk->data;
+    if (dpad->rtp_pad == pad || dpad->rtcp_pad == pad) {
+      return dpad;
+    }
+  }
+
+  return NULL;
+}
+
+
+static gboolean
+gst_rtp_ssrc_demux_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstRtpSsrcDemux *demux;
+  const GstStructure *s;
+
+  demux = GST_RTP_SSRC_DEMUX (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CUSTOM_UPSTREAM:
+    case GST_EVENT_CUSTOM_BOTH:
+    case GST_EVENT_CUSTOM_BOTH_OOB:
+      s = gst_event_get_structure (event);
+      if (s && !gst_structure_has_field (s, "ssrc")) {
+        GstRtpSsrcDemuxPad *dpad = find_demux_pad_for_pad (demux, pad);
+
+        if (dpad) {
+          GstStructure *ws;
+
+          event = gst_event_make_writable (event);
+          ws = gst_event_writable_structure (event);
+          gst_structure_set (ws, "ssrc", G_TYPE_UINT, dpad->ssrc, NULL);
+        }
+      }
+      break;
+    default:
+      break;
+  }
+
+  return gst_pad_event_default (pad, parent, event);
+}
+
+static GstIterator *
+gst_rtp_ssrc_demux_iterate_internal_links_src (GstPad * pad, GstObject * parent)
+{
+  GstRtpSsrcDemux *demux;
+  GstPad *otherpad = NULL;
+  GstIterator *it = NULL;
+  GSList *current;
+
+  demux = GST_RTP_SSRC_DEMUX (parent);
+
+  GST_PAD_LOCK (demux);
+  for (current = demux->srcpads; current; current = g_slist_next (current)) {
+    GstRtpSsrcDemuxPad *dpad = (GstRtpSsrcDemuxPad *) current->data;
+
+    if (pad == dpad->rtp_pad) {
+      otherpad = demux->rtp_sink;
+      break;
+    } else if (pad == dpad->rtcp_pad) {
+      otherpad = demux->rtcp_sink;
+      break;
+    }
+  }
+  if (otherpad) {
+    GValue val = { 0, };
+
+    g_value_init (&val, GST_TYPE_PAD);
+    g_value_set_object (&val, otherpad);
+    it = gst_iterator_new_single (GST_TYPE_PAD, &val);
+    g_value_unset (&val);
+
+  }
+  GST_PAD_UNLOCK (demux);
+
+  return it;
+}
+
+/* Should return 0 for elements to be included */
+static gint
+src_pad_compare_func (gconstpointer a, gconstpointer b)
+{
+  GstPad *pad = GST_PAD (g_value_get_object (a));
+  const gchar *prefix = g_value_get_string (b);
+  gint res;
+
+  /* 0 means equal means we accept the pad, accepted if there is a name
+   * and it starts with the prefix */
+  GST_OBJECT_LOCK (pad);
+  res = !GST_PAD_NAME (pad) || !g_str_has_prefix (GST_PAD_NAME (pad), prefix);
+  GST_OBJECT_UNLOCK (pad);
+
+  return res;
+}
+
+static GstIterator *
+gst_rtp_ssrc_demux_iterate_internal_links_sink (GstPad * pad,
+    GstObject * parent)
+{
+  GstRtpSsrcDemux *demux;
+  GstIterator *it = NULL;
+  GValue gval = { 0, };
+
+  demux = GST_RTP_SSRC_DEMUX (parent);
+
+  g_value_init (&gval, G_TYPE_STRING);
+  if (pad == demux->rtp_sink)
+    g_value_set_static_string (&gval, "src_");
+  else if (pad == demux->rtcp_sink)
+    g_value_set_static_string (&gval, "rtcp_src_");
+  else
+    g_assert_not_reached ();
+
+  it = gst_element_iterate_src_pads (GST_ELEMENT_CAST (demux));
+  it = gst_iterator_filter (it, src_pad_compare_func, &gval);
+
+  return it;
+}
+
+
+static gboolean
+gst_rtp_ssrc_demux_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  GstRtpSsrcDemux *demux;
+  gboolean res = FALSE;
+
+  demux = GST_RTP_SSRC_DEMUX (parent);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_LATENCY:
+    {
+
+      if ((res = gst_pad_peer_query (demux->rtp_sink, query))) {
+        gboolean live;
+        GstClockTime min_latency, max_latency;
+        GstRtpSsrcDemuxPad *demuxpad;
+
+        demuxpad = gst_pad_get_element_private (pad);
+
+        gst_query_parse_latency (query, &live, &min_latency, &max_latency);
+
+        GST_DEBUG_OBJECT (demux, "peer min latency %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (min_latency));
+
+        GST_DEBUG_OBJECT (demux, "latency for SSRC %08x", demuxpad->ssrc);
+
+        gst_query_set_latency (query, live, min_latency, max_latency);
+      }
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+
+  return res;
+}
+
+static GstStateChangeReturn
+gst_rtp_ssrc_demux_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstRtpSsrcDemux *demux;
+
+  demux = GST_RTP_SSRC_DEMUX (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_ssrc_demux_reset (demux);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+    default:
+      break;
+  }
+  return ret;
+}
diff --git a/gst/rtpmanager/gstrtpssrcdemux.h b/gst/rtpmanager/gstrtpssrcdemux.h
new file mode 100644
index 0000000..82df444
--- /dev/null
+++ b/gst/rtpmanager/gstrtpssrcdemux.h
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_SSRC_DEMUX_H__
+#define __GST_RTP_SSRC_DEMUX_H__
+
+#include <gst/gst.h>
+
+#define GST_TYPE_RTP_SSRC_DEMUX            (gst_rtp_ssrc_demux_get_type())
+#define GST_RTP_SSRC_DEMUX(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SSRC_DEMUX,GstRtpSsrcDemux))
+#define GST_RTP_SSRC_DEMUX_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SSRC_DEMUX,GstRtpSsrcDemuxClass))
+#define GST_IS_RTP_SSRC_DEMUX(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SSRC_DEMUX))
+#define GST_IS_RTP_SSRC_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SSRC_DEMUX))
+
+typedef struct _GstRtpSsrcDemux GstRtpSsrcDemux;
+typedef struct _GstRtpSsrcDemuxClass GstRtpSsrcDemuxClass;
+typedef struct _GstRtpSsrcDemuxPad GstRtpSsrcDemuxPad;
+
+struct _GstRtpSsrcDemux
+{
+  GstElement parent;
+
+  GstPad *rtp_sink;
+  GstPad *rtcp_sink;
+
+  GRecMutex padlock;
+  GSList *srcpads;
+};
+
+struct _GstRtpSsrcDemuxClass
+{
+  GstElementClass parent_class;
+
+  /* signals */
+  void (*new_ssrc_pad)     (GstRtpSsrcDemux *demux, guint32 ssrc, GstPad *pad);
+  void (*removed_ssrc_pad) (GstRtpSsrcDemux *demux, guint32 ssrc, GstPad *pad);
+
+  /* actions */
+  void (*clear_ssrc)       (GstRtpSsrcDemux *demux, guint32 ssrc);
+};
+
+GType gst_rtp_ssrc_demux_get_type (void);
+
+#endif /* __GST_RTP_SSRC_DEMUX_H__ */
diff --git a/gst/rtpmanager/meson.build b/gst/rtpmanager/meson.build
new file mode 100644
index 0000000..2a56f37
--- /dev/null
+++ b/gst/rtpmanager/meson.build
@@ -0,0 +1,26 @@
+rtpmanager_sources = [
+  'gstrtpmanager.c',
+  'gstrtpbin.c',
+  'gstrtpdtmfmux.c',
+  'gstrtpjitterbuffer.c',
+  'gstrtpmux.c',
+  'gstrtpptdemux.c',
+  'gstrtprtxqueue.c',
+  'gstrtprtxreceive.c',
+  'gstrtprtxsend.c',
+  'gstrtpssrcdemux.c',
+  'rtpjitterbuffer.c',
+  'rtpsession.c',
+  'rtpsource.c',
+  'rtpstats.c',
+  'gstrtpsession.c',
+]
+
+gstrtpmanager = library('gstrtpmanager',
+  rtpmanager_sources,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc, libsinc],
+  dependencies : [gstbase_dep, gstnet_dep, gstrtp_dep, gio_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/rtpmanager/rtpjitterbuffer.c b/gst/rtpmanager/rtpjitterbuffer.c
new file mode 100644
index 0000000..f1187e2
--- /dev/null
+++ b/gst/rtpmanager/rtpjitterbuffer.c
@@ -0,0 +1,1297 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/rtp/gstrtcpbuffer.h>
+
+#include "rtpjitterbuffer.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtp_jitter_buffer_debug);
+#define GST_CAT_DEFAULT rtp_jitter_buffer_debug
+
+#define MAX_WINDOW	RTP_JITTER_BUFFER_MAX_WINDOW
+#define MAX_TIME	(2 * GST_SECOND)
+
+/* signals and args */
+enum
+{
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0
+};
+
+/* GObject vmethods */
+static void rtp_jitter_buffer_finalize (GObject * object);
+
+GType
+rtp_jitter_buffer_mode_get_type (void)
+{
+  static GType jitter_buffer_mode_type = 0;
+  static const GEnumValue jitter_buffer_modes[] = {
+    {RTP_JITTER_BUFFER_MODE_NONE, "Only use RTP timestamps", "none"},
+    {RTP_JITTER_BUFFER_MODE_SLAVE, "Slave receiver to sender clock", "slave"},
+    {RTP_JITTER_BUFFER_MODE_BUFFER, "Do low/high watermark buffering",
+        "buffer"},
+    {RTP_JITTER_BUFFER_MODE_SYNCED, "Synchronized sender and receiver clocks",
+        "synced"},
+    {0, NULL, NULL},
+  };
+
+  if (!jitter_buffer_mode_type) {
+    jitter_buffer_mode_type =
+        g_enum_register_static ("RTPJitterBufferMode", jitter_buffer_modes);
+  }
+  return jitter_buffer_mode_type;
+}
+
+/* static guint rtp_jitter_buffer_signals[LAST_SIGNAL] = { 0 }; */
+
+G_DEFINE_TYPE (RTPJitterBuffer, rtp_jitter_buffer, G_TYPE_OBJECT);
+
+static void
+rtp_jitter_buffer_class_init (RTPJitterBufferClass * klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = (GObjectClass *) klass;
+
+  gobject_class->finalize = rtp_jitter_buffer_finalize;
+
+  GST_DEBUG_CATEGORY_INIT (rtp_jitter_buffer_debug, "rtpjitterbuffer", 0,
+      "RTP Jitter Buffer");
+}
+
+static void
+rtp_jitter_buffer_init (RTPJitterBuffer * jbuf)
+{
+  g_mutex_init (&jbuf->clock_lock);
+
+  jbuf->packets = g_queue_new ();
+  jbuf->mode = RTP_JITTER_BUFFER_MODE_SLAVE;
+
+  rtp_jitter_buffer_reset_skew (jbuf);
+}
+
+static void
+rtp_jitter_buffer_finalize (GObject * object)
+{
+  RTPJitterBuffer *jbuf;
+
+  jbuf = RTP_JITTER_BUFFER_CAST (object);
+
+  if (jbuf->media_clock_synced_id)
+    g_signal_handler_disconnect (jbuf->media_clock,
+        jbuf->media_clock_synced_id);
+  if (jbuf->media_clock)
+    gst_object_unref (jbuf->media_clock);
+
+  if (jbuf->pipeline_clock)
+    gst_object_unref (jbuf->pipeline_clock);
+
+  g_queue_free (jbuf->packets);
+
+  g_mutex_clear (&jbuf->clock_lock);
+
+  G_OBJECT_CLASS (rtp_jitter_buffer_parent_class)->finalize (object);
+}
+
+/**
+ * rtp_jitter_buffer_new:
+ *
+ * Create an #RTPJitterBuffer.
+ *
+ * Returns: a new #RTPJitterBuffer. Use g_object_unref() after usage.
+ */
+RTPJitterBuffer *
+rtp_jitter_buffer_new (void)
+{
+  RTPJitterBuffer *jbuf;
+
+  jbuf = g_object_new (RTP_TYPE_JITTER_BUFFER, NULL);
+
+  return jbuf;
+}
+
+/**
+ * rtp_jitter_buffer_get_mode:
+ * @jbuf: an #RTPJitterBuffer
+ *
+ * Get the current jitterbuffer mode.
+ *
+ * Returns: the current jitterbuffer mode.
+ */
+RTPJitterBufferMode
+rtp_jitter_buffer_get_mode (RTPJitterBuffer * jbuf)
+{
+  return jbuf->mode;
+}
+
+/**
+ * rtp_jitter_buffer_set_mode:
+ * @jbuf: an #RTPJitterBuffer
+ * @mode: a #RTPJitterBufferMode
+ *
+ * Set the buffering and clock slaving algorithm used in the @jbuf.
+ */
+void
+rtp_jitter_buffer_set_mode (RTPJitterBuffer * jbuf, RTPJitterBufferMode mode)
+{
+  jbuf->mode = mode;
+}
+
+GstClockTime
+rtp_jitter_buffer_get_delay (RTPJitterBuffer * jbuf)
+{
+  return jbuf->delay;
+}
+
+void
+rtp_jitter_buffer_set_delay (RTPJitterBuffer * jbuf, GstClockTime delay)
+{
+  jbuf->delay = delay;
+  jbuf->low_level = (delay * 15) / 100;
+  /* the high level is at 90% in order to release packets before we fill up the
+   * buffer up to the latency */
+  jbuf->high_level = (delay * 90) / 100;
+
+  GST_DEBUG ("delay %" GST_TIME_FORMAT ", min %" GST_TIME_FORMAT ", max %"
+      GST_TIME_FORMAT, GST_TIME_ARGS (jbuf->delay),
+      GST_TIME_ARGS (jbuf->low_level), GST_TIME_ARGS (jbuf->high_level));
+}
+
+/**
+ * rtp_jitter_buffer_set_clock_rate:
+ * @jbuf: an #RTPJitterBuffer
+ * @clock_rate: the new clock rate
+ *
+ * Set the clock rate in the jitterbuffer.
+ */
+void
+rtp_jitter_buffer_set_clock_rate (RTPJitterBuffer * jbuf, guint32 clock_rate)
+{
+  if (jbuf->clock_rate != clock_rate) {
+    GST_DEBUG ("Clock rate changed from %" G_GUINT32_FORMAT " to %"
+        G_GUINT32_FORMAT, jbuf->clock_rate, clock_rate);
+    jbuf->clock_rate = clock_rate;
+    rtp_jitter_buffer_reset_skew (jbuf);
+  }
+}
+
+/**
+ * rtp_jitter_buffer_get_clock_rate:
+ * @jbuf: an #RTPJitterBuffer
+ *
+ * Get the currently configure clock rate in @jbuf.
+ *
+ * Returns: the current clock-rate
+ */
+guint32
+rtp_jitter_buffer_get_clock_rate (RTPJitterBuffer * jbuf)
+{
+  return jbuf->clock_rate;
+}
+
+static void
+media_clock_synced_cb (GstClock * clock, gboolean synced,
+    RTPJitterBuffer * jbuf)
+{
+  GstClockTime internal, external;
+
+  g_mutex_lock (&jbuf->clock_lock);
+  if (jbuf->pipeline_clock) {
+    internal = gst_clock_get_internal_time (jbuf->media_clock);
+    external = gst_clock_get_time (jbuf->pipeline_clock);
+
+    gst_clock_set_calibration (jbuf->media_clock, internal, external, 1, 1);
+  }
+  g_mutex_unlock (&jbuf->clock_lock);
+}
+
+/**
+ * rtp_jitter_buffer_set_media_clock:
+ * @jbuf: an #RTPJitterBuffer
+ * @clock: (transfer full): media #GstClock
+ * @clock_offset: RTP time at clock epoch or -1
+ *
+ * Sets the media clock for the media and the clock offset
+ *
+ */
+void
+rtp_jitter_buffer_set_media_clock (RTPJitterBuffer * jbuf, GstClock * clock,
+    guint64 clock_offset)
+{
+  g_mutex_lock (&jbuf->clock_lock);
+  if (jbuf->media_clock) {
+    if (jbuf->media_clock_synced_id)
+      g_signal_handler_disconnect (jbuf->media_clock,
+          jbuf->media_clock_synced_id);
+    jbuf->media_clock_synced_id = 0;
+    gst_object_unref (jbuf->media_clock);
+  }
+  jbuf->media_clock = clock;
+  jbuf->media_clock_offset = clock_offset;
+
+  if (jbuf->pipeline_clock && jbuf->media_clock &&
+      jbuf->pipeline_clock != jbuf->media_clock) {
+    jbuf->media_clock_synced_id =
+        g_signal_connect (jbuf->media_clock, "synced",
+        G_CALLBACK (media_clock_synced_cb), jbuf);
+    if (gst_clock_is_synced (jbuf->media_clock)) {
+      GstClockTime internal, external;
+
+      internal = gst_clock_get_internal_time (jbuf->media_clock);
+      external = gst_clock_get_time (jbuf->pipeline_clock);
+
+      gst_clock_set_calibration (jbuf->media_clock, internal, external, 1, 1);
+    }
+
+    gst_clock_set_master (jbuf->media_clock, jbuf->pipeline_clock);
+  }
+  g_mutex_unlock (&jbuf->clock_lock);
+}
+
+/**
+ * rtp_jitter_buffer_set_pipeline_clock:
+ * @jbuf: an #RTPJitterBuffer
+ * @clock: pipeline #GstClock
+ *
+ * Sets the pipeline clock
+ *
+ */
+void
+rtp_jitter_buffer_set_pipeline_clock (RTPJitterBuffer * jbuf, GstClock * clock)
+{
+  g_mutex_lock (&jbuf->clock_lock);
+  if (jbuf->pipeline_clock)
+    gst_object_unref (jbuf->pipeline_clock);
+  jbuf->pipeline_clock = clock ? gst_object_ref (clock) : NULL;
+
+  if (jbuf->pipeline_clock && jbuf->media_clock &&
+      jbuf->pipeline_clock != jbuf->media_clock) {
+    if (gst_clock_is_synced (jbuf->media_clock)) {
+      GstClockTime internal, external;
+
+      internal = gst_clock_get_internal_time (jbuf->media_clock);
+      external = gst_clock_get_time (jbuf->pipeline_clock);
+
+      gst_clock_set_calibration (jbuf->media_clock, internal, external, 1, 1);
+    }
+
+    gst_clock_set_master (jbuf->media_clock, jbuf->pipeline_clock);
+  }
+  g_mutex_unlock (&jbuf->clock_lock);
+}
+
+gboolean
+rtp_jitter_buffer_get_rfc7273_sync (RTPJitterBuffer * jbuf)
+{
+  return jbuf->rfc7273_sync;
+}
+
+void
+rtp_jitter_buffer_set_rfc7273_sync (RTPJitterBuffer * jbuf,
+    gboolean rfc7273_sync)
+{
+  jbuf->rfc7273_sync = rfc7273_sync;
+}
+
+/**
+ * rtp_jitter_buffer_reset_skew:
+ * @jbuf: an #RTPJitterBuffer
+ *
+ * Reset the skew calculations in @jbuf.
+ */
+void
+rtp_jitter_buffer_reset_skew (RTPJitterBuffer * jbuf)
+{
+  jbuf->base_time = -1;
+  jbuf->base_rtptime = -1;
+  jbuf->base_extrtp = -1;
+  jbuf->media_clock_base_time = -1;
+  jbuf->ext_rtptime = -1;
+  jbuf->last_rtptime = -1;
+  jbuf->window_pos = 0;
+  jbuf->window_filling = TRUE;
+  jbuf->window_min = 0;
+  jbuf->skew = 0;
+  jbuf->prev_send_diff = -1;
+  jbuf->prev_out_time = -1;
+  jbuf->need_resync = TRUE;
+
+  GST_DEBUG ("reset skew correction");
+}
+
+/**
+ * rtp_jitter_buffer_disable_buffering:
+ * @jbuf: an #RTPJitterBuffer
+ * @disabled: the new state
+ *
+ * Enable or disable buffering on @jbuf.
+ */
+void
+rtp_jitter_buffer_disable_buffering (RTPJitterBuffer * jbuf, gboolean disabled)
+{
+  jbuf->buffering_disabled = disabled;
+}
+
+static void
+rtp_jitter_buffer_resync (RTPJitterBuffer * jbuf, GstClockTime time,
+    GstClockTime gstrtptime, guint64 ext_rtptime, gboolean reset_skew)
+{
+  jbuf->base_time = time;
+  jbuf->media_clock_base_time = -1;
+  jbuf->base_rtptime = gstrtptime;
+  jbuf->base_extrtp = ext_rtptime;
+  jbuf->prev_out_time = -1;
+  jbuf->prev_send_diff = -1;
+  if (reset_skew) {
+    jbuf->window_filling = TRUE;
+    jbuf->window_pos = 0;
+    jbuf->window_min = 0;
+    jbuf->window_size = 0;
+    jbuf->skew = 0;
+  }
+  jbuf->need_resync = FALSE;
+}
+
+static guint64
+get_buffer_level (RTPJitterBuffer * jbuf)
+{
+  RTPJitterBufferItem *high_buf = NULL, *low_buf = NULL;
+  guint64 level;
+
+  /* first buffer with timestamp */
+  high_buf = (RTPJitterBufferItem *) g_queue_peek_tail_link (jbuf->packets);
+  while (high_buf) {
+    if (high_buf->dts != -1 || high_buf->pts != -1)
+      break;
+
+    high_buf = (RTPJitterBufferItem *) g_list_previous (high_buf);
+  }
+
+  low_buf = (RTPJitterBufferItem *) g_queue_peek_head_link (jbuf->packets);
+  while (low_buf) {
+    if (low_buf->dts != -1 || low_buf->pts != -1)
+      break;
+
+    low_buf = (RTPJitterBufferItem *) g_list_next (low_buf);
+  }
+
+  if (!high_buf || !low_buf || high_buf == low_buf) {
+    level = 0;
+  } else {
+    guint64 high_ts, low_ts;
+
+    high_ts = high_buf->dts != -1 ? high_buf->dts : high_buf->pts;
+    low_ts = low_buf->dts != -1 ? low_buf->dts : low_buf->pts;
+
+    if (high_ts > low_ts)
+      level = high_ts - low_ts;
+    else
+      level = 0;
+
+    GST_LOG_OBJECT (jbuf,
+        "low %" GST_TIME_FORMAT " high %" GST_TIME_FORMAT " level %"
+        G_GUINT64_FORMAT, GST_TIME_ARGS (low_ts), GST_TIME_ARGS (high_ts),
+        level);
+  }
+  return level;
+}
+
+static void
+update_buffer_level (RTPJitterBuffer * jbuf, gint * percent)
+{
+  gboolean post = FALSE;
+  guint64 level;
+
+  level = get_buffer_level (jbuf);
+  GST_DEBUG ("buffer level %" GST_TIME_FORMAT, GST_TIME_ARGS (level));
+
+  if (jbuf->buffering_disabled) {
+    GST_DEBUG ("buffering is disabled");
+    level = jbuf->high_level;
+  }
+
+  if (jbuf->buffering) {
+    post = TRUE;
+    if (level >= jbuf->high_level) {
+      GST_DEBUG ("buffering finished");
+      jbuf->buffering = FALSE;
+    }
+  } else {
+    if (level < jbuf->low_level) {
+      GST_DEBUG ("buffering started");
+      jbuf->buffering = TRUE;
+      post = TRUE;
+    }
+  }
+  if (post) {
+    gint perc;
+
+    if (jbuf->buffering && (jbuf->high_level != 0)) {
+      perc = (level * 100 / jbuf->high_level);
+      perc = MIN (perc, 100);
+    } else {
+      perc = 100;
+    }
+
+    if (percent)
+      *percent = perc;
+
+    GST_DEBUG ("buffering %d", perc);
+  }
+}
+
+/* For the clock skew we use a windowed low point averaging algorithm as can be
+ * found in Fober, Orlarey and Letz, 2005, "Real Time Clock Skew Estimation
+ * over Network Delays":
+ * http://www.grame.fr/Ressources/pub/TR-050601.pdf
+ * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.102.1546
+ *
+ * The idea is that the jitter is composed of:
+ *
+ *  J = N + n
+ *
+ *   N   : a constant network delay.
+ *   n   : random added noise. The noise is concentrated around 0
+ *
+ * In the receiver we can track the elapsed time at the sender with:
+ *
+ *  send_diff(i) = (Tsi - Ts0);
+ *
+ *   Tsi : The time at the sender at packet i
+ *   Ts0 : The time at the sender at the first packet
+ *
+ * This is the difference between the RTP timestamp in the first received packet
+ * and the current packet.
+ *
+ * At the receiver we have to deal with the jitter introduced by the network.
+ *
+ *  recv_diff(i) = (Tri - Tr0)
+ *
+ *   Tri : The time at the receiver at packet i
+ *   Tr0 : The time at the receiver at the first packet
+ *
+ * Both of these values contain a jitter Ji, a jitter for packet i, so we can
+ * write:
+ *
+ *  recv_diff(i) = (Cri + D + ni) - (Cr0 + D + n0))
+ *
+ *    Cri    : The time of the clock at the receiver for packet i
+ *    D + ni : The jitter when receiving packet i
+ *
+ * We see that the network delay is irrelevant here as we can elliminate D:
+ *
+ *  recv_diff(i) = (Cri + ni) - (Cr0 + n0))
+ *
+ * The drift is now expressed as:
+ *
+ *  Drift(i) = recv_diff(i) - send_diff(i);
+ *
+ * We now keep the W latest values of Drift and find the minimum (this is the
+ * one with the lowest network jitter and thus the one which is least affected
+ * by it). We average this lowest value to smooth out the resulting network skew.
+ *
+ * Both the window and the weighting used for averaging influence the accuracy
+ * of the drift estimation. Finding the correct parameters turns out to be a
+ * compromise between accuracy and inertia.
+ *
+ * We use a 2 second window or up to 512 data points, which is statistically big
+ * enough to catch spikes (FIXME, detect spikes).
+ * We also use a rather large weighting factor (125) to smoothly adapt. During
+ * startup, when filling the window, we use a parabolic weighting factor, the
+ * more the window is filled, the faster we move to the detected possible skew.
+ *
+ * Returns: @time adjusted with the clock skew.
+ */
+static GstClockTime
+calculate_skew (RTPJitterBuffer * jbuf, guint64 ext_rtptime,
+    GstClockTime gstrtptime, GstClockTime time)
+{
+  guint64 send_diff, recv_diff;
+  gint64 delta;
+  gint64 old;
+  gint pos, i;
+  GstClockTime out_time;
+  guint64 slope;
+
+  /* elapsed time at sender */
+  send_diff = gstrtptime - jbuf->base_rtptime;
+
+  /* we don't have an arrival timestamp so we can't do skew detection. we
+   * should still apply a timestamp based on RTP timestamp and base_time */
+  if (time == -1 || jbuf->base_time == -1)
+    goto no_skew;
+
+  /* elapsed time at receiver, includes the jitter */
+  recv_diff = time - jbuf->base_time;
+
+  /* measure the diff */
+  delta = ((gint64) recv_diff) - ((gint64) send_diff);
+
+  /* measure the slope, this gives a rought estimate between the sender speed
+   * and the receiver speed. This should be approximately 8, higher values
+   * indicate a burst (especially when the connection starts) */
+  if (recv_diff > 0)
+    slope = (send_diff * 8) / recv_diff;
+  else
+    slope = 8;
+
+  GST_DEBUG ("time %" GST_TIME_FORMAT ", base %" GST_TIME_FORMAT ", recv_diff %"
+      GST_TIME_FORMAT ", slope %" G_GUINT64_FORMAT, GST_TIME_ARGS (time),
+      GST_TIME_ARGS (jbuf->base_time), GST_TIME_ARGS (recv_diff), slope);
+
+  /* if the difference between the sender timeline and the receiver timeline
+   * changed too quickly we have to resync because the server likely restarted
+   * its timestamps. */
+  if (ABS (delta - jbuf->skew) > GST_SECOND) {
+    GST_WARNING ("delta - skew: %" GST_TIME_FORMAT " too big, reset skew",
+        GST_TIME_ARGS (ABS (delta - jbuf->skew)));
+    rtp_jitter_buffer_resync (jbuf, time, gstrtptime, ext_rtptime, TRUE);
+    send_diff = 0;
+    delta = 0;
+  }
+
+  pos = jbuf->window_pos;
+
+  if (G_UNLIKELY (jbuf->window_filling)) {
+    /* we are filling the window */
+    GST_DEBUG ("filling %d, delta %" G_GINT64_FORMAT, pos, delta);
+    jbuf->window[pos++] = delta;
+    /* calc the min delta we observed */
+    if (G_UNLIKELY (pos == 1 || delta < jbuf->window_min))
+      jbuf->window_min = delta;
+
+    if (G_UNLIKELY (send_diff >= MAX_TIME || pos >= MAX_WINDOW)) {
+      jbuf->window_size = pos;
+
+      /* window filled */
+      GST_DEBUG ("min %" G_GINT64_FORMAT, jbuf->window_min);
+
+      /* the skew is now the min */
+      jbuf->skew = jbuf->window_min;
+      jbuf->window_filling = FALSE;
+    } else {
+      gint perc_time, perc_window, perc;
+
+      /* figure out how much we filled the window, this depends on the amount of
+       * time we have or the max number of points we keep. */
+      perc_time = send_diff * 100 / MAX_TIME;
+      perc_window = pos * 100 / MAX_WINDOW;
+      perc = MAX (perc_time, perc_window);
+
+      /* make a parabolic function, the closer we get to the MAX, the more value
+       * we give to the scaling factor of the new value */
+      perc = perc * perc;
+
+      /* quickly go to the min value when we are filling up, slowly when we are
+       * just starting because we're not sure it's a good value yet. */
+      jbuf->skew =
+          (perc * jbuf->window_min + ((10000 - perc) * jbuf->skew)) / 10000;
+      jbuf->window_size = pos + 1;
+    }
+  } else {
+    /* pick old value and store new value. We keep the previous value in order
+     * to quickly check if the min of the window changed */
+    old = jbuf->window[pos];
+    jbuf->window[pos++] = delta;
+
+    if (G_UNLIKELY (delta <= jbuf->window_min)) {
+      /* if the new value we inserted is smaller or equal to the current min,
+       * it becomes the new min */
+      jbuf->window_min = delta;
+    } else if (G_UNLIKELY (old == jbuf->window_min)) {
+      gint64 min = G_MAXINT64;
+
+      /* if we removed the old min, we have to find a new min */
+      for (i = 0; i < jbuf->window_size; i++) {
+        /* we found another value equal to the old min, we can stop searching now */
+        if (jbuf->window[i] == old) {
+          min = old;
+          break;
+        }
+        if (jbuf->window[i] < min)
+          min = jbuf->window[i];
+      }
+      jbuf->window_min = min;
+    }
+    /* average the min values */
+    jbuf->skew = (jbuf->window_min + (124 * jbuf->skew)) / 125;
+    GST_DEBUG ("delta %" G_GINT64_FORMAT ", new min: %" G_GINT64_FORMAT,
+        delta, jbuf->window_min);
+  }
+  /* wrap around in the window */
+  if (G_UNLIKELY (pos >= jbuf->window_size))
+    pos = 0;
+  jbuf->window_pos = pos;
+
+no_skew:
+  /* the output time is defined as the base timestamp plus the RTP time
+   * adjusted for the clock skew .*/
+  if (jbuf->base_time != -1) {
+    out_time = jbuf->base_time + send_diff;
+    /* skew can be negative and we don't want to make invalid timestamps */
+    if (jbuf->skew < 0 && out_time < -jbuf->skew) {
+      out_time = 0;
+    } else {
+      out_time += jbuf->skew;
+    }
+  } else
+    out_time = -1;
+
+  GST_DEBUG ("skew %" G_GINT64_FORMAT ", out %" GST_TIME_FORMAT,
+      jbuf->skew, GST_TIME_ARGS (out_time));
+
+  return out_time;
+}
+
+static void
+queue_do_insert (RTPJitterBuffer * jbuf, GList * list, GList * item)
+{
+  GQueue *queue = jbuf->packets;
+
+  /* It's more likely that the packet was inserted at the tail of the queue */
+  if (G_LIKELY (list)) {
+    item->prev = list;
+    item->next = list->next;
+    list->next = item;
+  } else {
+    item->prev = NULL;
+    item->next = queue->head;
+    queue->head = item;
+  }
+  if (item->next)
+    item->next->prev = item;
+  else
+    queue->tail = item;
+  queue->length++;
+}
+
+GstClockTime
+rtp_jitter_buffer_calculate_pts (RTPJitterBuffer * jbuf, GstClockTime dts,
+    gboolean estimated_dts, guint32 rtptime, GstClockTime base_time)
+{
+  guint64 ext_rtptime;
+  GstClockTime gstrtptime, pts;
+  GstClock *media_clock, *pipeline_clock;
+  guint64 media_clock_offset;
+  gboolean rfc7273_mode;
+
+  /* rtp time jumps are checked for during skew calculation, but bypassed
+   * in other mode, so mind those here and reset jb if needed.
+   * Only reset if valid input time, which is likely for UDP input
+   * where we expect this might happen due to async thread effects
+   * (in seek and state change cycles), but not so much for TCP input */
+  if (GST_CLOCK_TIME_IS_VALID (dts) && !estimated_dts &&
+      jbuf->mode != RTP_JITTER_BUFFER_MODE_SLAVE &&
+      jbuf->base_time != -1 && jbuf->last_rtptime != -1) {
+    GstClockTime ext_rtptime = jbuf->ext_rtptime;
+
+    ext_rtptime = gst_rtp_buffer_ext_timestamp (&ext_rtptime, rtptime);
+    if (ext_rtptime > jbuf->last_rtptime + 3 * jbuf->clock_rate ||
+        ext_rtptime + 3 * jbuf->clock_rate < jbuf->last_rtptime) {
+      /* reset even if we don't have valid incoming time;
+       * still better than producing possibly very bogus output timestamp */
+      GST_WARNING ("rtp delta too big, reset skew");
+      rtp_jitter_buffer_reset_skew (jbuf);
+    }
+  }
+
+  /* Return the last time if we got the same RTP timestamp again */
+  ext_rtptime = gst_rtp_buffer_ext_timestamp (&jbuf->ext_rtptime, rtptime);
+  if (jbuf->last_rtptime != -1 && ext_rtptime == jbuf->last_rtptime) {
+    return jbuf->prev_out_time;
+  }
+
+  /* keep track of the last extended rtptime */
+  jbuf->last_rtptime = ext_rtptime;
+
+  g_mutex_lock (&jbuf->clock_lock);
+  media_clock = jbuf->media_clock ? gst_object_ref (jbuf->media_clock) : NULL;
+  pipeline_clock =
+      jbuf->pipeline_clock ? gst_object_ref (jbuf->pipeline_clock) : NULL;
+  media_clock_offset = jbuf->media_clock_offset;
+  g_mutex_unlock (&jbuf->clock_lock);
+
+  gstrtptime =
+      gst_util_uint64_scale_int (ext_rtptime, GST_SECOND, jbuf->clock_rate);
+
+  if (G_LIKELY (jbuf->base_rtptime != -1)) {
+    /* check elapsed time in RTP units */
+    if (gstrtptime < jbuf->base_rtptime) {
+      /* elapsed time at sender, timestamps can go backwards and thus be
+       * smaller than our base time, schedule to take a new base time in
+       * that case. */
+      GST_WARNING ("backward timestamps at server, schedule resync");
+      jbuf->need_resync = TRUE;
+    }
+  }
+
+  switch (jbuf->mode) {
+    case RTP_JITTER_BUFFER_MODE_NONE:
+    case RTP_JITTER_BUFFER_MODE_BUFFER:
+      /* send 0 as the first timestamp and -1 for the other ones. This will
+       * interpolate them from the RTP timestamps with a 0 origin. In buffering
+       * mode we will adjust the outgoing timestamps according to the amount of
+       * time we spent buffering. */
+      if (jbuf->base_time == -1)
+        dts = 0;
+      else
+        dts = -1;
+      break;
+    case RTP_JITTER_BUFFER_MODE_SYNCED:
+      /* synchronized clocks, take first timestamp as base, use RTP timestamps
+       * to interpolate */
+      if (jbuf->base_time != -1 && !jbuf->need_resync)
+        dts = -1;
+      break;
+    case RTP_JITTER_BUFFER_MODE_SLAVE:
+    default:
+      break;
+  }
+
+  /* need resync, lock on to time and gstrtptime if we can, otherwise we
+   * do with the previous values */
+  if (G_UNLIKELY (jbuf->need_resync && dts != -1)) {
+    GST_INFO ("resync to time %" GST_TIME_FORMAT ", rtptime %"
+        GST_TIME_FORMAT, GST_TIME_ARGS (dts), GST_TIME_ARGS (gstrtptime));
+    rtp_jitter_buffer_resync (jbuf, dts, gstrtptime, ext_rtptime, FALSE);
+  }
+
+  GST_DEBUG ("extrtp %" G_GUINT64_FORMAT ", gstrtp %" GST_TIME_FORMAT ", base %"
+      GST_TIME_FORMAT ", send_diff %" GST_TIME_FORMAT, ext_rtptime,
+      GST_TIME_ARGS (gstrtptime), GST_TIME_ARGS (jbuf->base_rtptime),
+      GST_TIME_ARGS (gstrtptime - jbuf->base_rtptime));
+
+  rfc7273_mode = media_clock && pipeline_clock
+      && gst_clock_is_synced (media_clock);
+
+  if (rfc7273_mode && jbuf->mode == RTP_JITTER_BUFFER_MODE_SLAVE
+      && (media_clock_offset == -1 || !jbuf->rfc7273_sync)) {
+    GstClockTime internal, external;
+    GstClockTime rate_num, rate_denom;
+    GstClockTime nsrtptimediff, rtpntptime, rtpsystime;
+
+    gst_clock_get_calibration (media_clock, &internal, &external, &rate_num,
+        &rate_denom);
+
+    /* Slave to the RFC7273 media clock instead of trying to estimate it
+     * based on receive times and RTP timestamps */
+
+    if (jbuf->media_clock_base_time == -1) {
+      if (jbuf->base_time != -1) {
+        jbuf->media_clock_base_time =
+            gst_clock_unadjust_with_calibration (media_clock,
+            jbuf->base_time + base_time, internal, external, rate_num,
+            rate_denom);
+      } else {
+        if (dts != -1)
+          jbuf->media_clock_base_time =
+              gst_clock_unadjust_with_calibration (media_clock, dts + base_time,
+              internal, external, rate_num, rate_denom);
+        else
+          jbuf->media_clock_base_time =
+              gst_clock_get_internal_time (media_clock);
+        jbuf->base_rtptime = gstrtptime;
+      }
+    }
+
+    if (gstrtptime > jbuf->base_rtptime)
+      nsrtptimediff = gstrtptime - jbuf->base_rtptime;
+    else
+      nsrtptimediff = 0;
+
+    rtpntptime = nsrtptimediff + jbuf->media_clock_base_time;
+
+    rtpsystime =
+        gst_clock_adjust_with_calibration (media_clock, rtpntptime, internal,
+        external, rate_num, rate_denom);
+
+    if (rtpsystime > base_time)
+      pts = rtpsystime - base_time;
+    else
+      pts = 0;
+
+    GST_DEBUG ("RFC7273 clock time %" GST_TIME_FORMAT ", out %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (rtpsystime), GST_TIME_ARGS (pts));
+  } else if (rfc7273_mode && (jbuf->mode == RTP_JITTER_BUFFER_MODE_SLAVE
+          || jbuf->mode == RTP_JITTER_BUFFER_MODE_SYNCED)
+      && media_clock_offset != -1 && jbuf->rfc7273_sync) {
+    GstClockTime ntptime, rtptime_tmp;
+    GstClockTime ntprtptime, rtpsystime;
+    GstClockTime internal, external;
+    GstClockTime rate_num, rate_denom;
+
+    /* Don't do any of the dts related adjustments further down */
+    dts = -1;
+
+    /* Calculate the actual clock time on the sender side based on the
+     * RFC7273 clock and convert it to our pipeline clock
+     */
+
+    gst_clock_get_calibration (media_clock, &internal, &external, &rate_num,
+        &rate_denom);
+
+    ntptime = gst_clock_get_internal_time (media_clock);
+
+    ntprtptime = gst_util_uint64_scale (ntptime, jbuf->clock_rate, GST_SECOND);
+    ntprtptime += media_clock_offset;
+    ntprtptime &= 0xffffffff;
+
+    rtptime_tmp = rtptime;
+    /* Check for wraparounds, we assume that the diff between current RTP
+     * timestamp and current media clock time can't be bigger than
+     * 2**31 clock units */
+    if (ntprtptime > rtptime_tmp && ntprtptime - rtptime_tmp >= 0x80000000)
+      rtptime_tmp += G_GUINT64_CONSTANT (0x100000000);
+    else if (rtptime_tmp > ntprtptime && rtptime_tmp - ntprtptime >= 0x80000000)
+      ntprtptime += G_GUINT64_CONSTANT (0x100000000);
+
+    if (ntprtptime > rtptime_tmp)
+      ntptime -=
+          gst_util_uint64_scale (ntprtptime - rtptime_tmp, jbuf->clock_rate,
+          GST_SECOND);
+    else
+      ntptime +=
+          gst_util_uint64_scale (rtptime_tmp - ntprtptime, jbuf->clock_rate,
+          GST_SECOND);
+
+    rtpsystime =
+        gst_clock_adjust_with_calibration (media_clock, ntptime, internal,
+        external, rate_num, rate_denom);
+    /* All this assumes that the pipeline has enough additional
+     * latency to cover for the network delay */
+    if (rtpsystime > base_time)
+      pts = rtpsystime - base_time;
+    else
+      pts = 0;
+
+    GST_DEBUG ("RFC7273 clock time %" GST_TIME_FORMAT ", out %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (rtpsystime), GST_TIME_ARGS (pts));
+  } else {
+    /* If we used the RFC7273 clock before and not anymore,
+     * we need to resync it later again */
+    jbuf->media_clock_base_time = -1;
+
+    /* do skew calculation by measuring the difference between rtptime and the
+     * receive dts, this function will return the skew corrected rtptime. */
+    pts = calculate_skew (jbuf, ext_rtptime, gstrtptime, dts);
+  }
+
+  /* check if timestamps are not going backwards, we can only check this if we
+   * have a previous out time and a previous send_diff */
+  if (G_LIKELY (pts != -1 && jbuf->prev_out_time != -1
+          && jbuf->prev_send_diff != -1)) {
+    /* now check for backwards timestamps */
+    if (G_UNLIKELY (
+            /* if the server timestamps went up and the out_time backwards */
+            (gstrtptime - jbuf->base_rtptime > jbuf->prev_send_diff
+                && pts < jbuf->prev_out_time) ||
+            /* if the server timestamps went backwards and the out_time forwards */
+            (gstrtptime - jbuf->base_rtptime < jbuf->prev_send_diff
+                && pts > jbuf->prev_out_time) ||
+            /* if the server timestamps did not change */
+            gstrtptime - jbuf->base_rtptime == jbuf->prev_send_diff)) {
+      GST_DEBUG ("backwards timestamps, using previous time");
+      pts = jbuf->prev_out_time;
+    }
+  }
+
+  if (dts != -1 && pts + jbuf->delay < dts) {
+    /* if we are going to produce a timestamp that is later than the input
+     * timestamp, we need to reset the jitterbuffer. Likely the server paused
+     * temporarily */
+    GST_DEBUG ("out %" GST_TIME_FORMAT " + %" G_GUINT64_FORMAT " < time %"
+        GST_TIME_FORMAT ", reset jitterbuffer", GST_TIME_ARGS (pts),
+        jbuf->delay, GST_TIME_ARGS (dts));
+    rtp_jitter_buffer_resync (jbuf, dts, gstrtptime, ext_rtptime, TRUE);
+    pts = dts;
+  }
+
+  jbuf->prev_out_time = pts;
+  jbuf->prev_send_diff = gstrtptime - jbuf->base_rtptime;
+
+  if (media_clock)
+    gst_object_unref (media_clock);
+  if (pipeline_clock)
+    gst_object_unref (pipeline_clock);
+
+  return pts;
+}
+
+
+/**
+ * rtp_jitter_buffer_insert:
+ * @jbuf: an #RTPJitterBuffer
+ * @item: an #RTPJitterBufferItem to insert
+ * @head: TRUE when the head element changed.
+ * @percent: the buffering percent after insertion
+ *
+ * Inserts @item into the packet queue of @jbuf. The sequence number of the
+ * packet will be used to sort the packets. This function takes ownerhip of
+ * @buf when the function returns %TRUE.
+ *
+ * When @head is %TRUE, the new packet was added at the head of the queue and
+ * will be available with the next call to rtp_jitter_buffer_pop() and
+ * rtp_jitter_buffer_peek().
+ *
+ * Returns: %FALSE if a packet with the same number already existed.
+ */
+gboolean
+rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, RTPJitterBufferItem * item,
+    gboolean * head, gint * percent)
+{
+  GList *list, *event = NULL;
+  guint16 seqnum;
+
+  g_return_val_if_fail (jbuf != NULL, FALSE);
+  g_return_val_if_fail (item != NULL, FALSE);
+
+  list = jbuf->packets->tail;
+
+  /* no seqnum, simply append then */
+  if (item->seqnum == -1)
+    goto append;
+
+  seqnum = item->seqnum;
+
+  /* loop the list to skip strictly larger seqnum buffers */
+  for (; list; list = g_list_previous (list)) {
+    guint16 qseq;
+    gint gap;
+    RTPJitterBufferItem *qitem = (RTPJitterBufferItem *) list;
+
+    if (qitem->seqnum == -1) {
+      /* keep a pointer to the first consecutive event if not already
+       * set. we will insert the packet after the event if we can't find
+       * a packet with lower sequence number before the event. */
+      if (event == NULL)
+        event = list;
+      continue;
+    }
+
+    qseq = qitem->seqnum;
+
+    /* compare the new seqnum to the one in the buffer */
+    gap = gst_rtp_buffer_compare_seqnum (seqnum, qseq);
+
+    /* we hit a packet with the same seqnum, notify a duplicate */
+    if (G_UNLIKELY (gap == 0))
+      goto duplicate;
+
+    /* seqnum > qseq, we can stop looking */
+    if (G_LIKELY (gap < 0))
+      break;
+
+    /* if we've found a packet with greater sequence number, cleanup the
+     * event pointer as the packet will be inserted before the event */
+    event = NULL;
+  }
+
+  /* if event is set it means that packets before the event had smaller
+   * sequence number, so we will insert our packet after the event */
+  if (event)
+    list = event;
+
+append:
+  queue_do_insert (jbuf, list, (GList *) item);
+
+  /* buffering mode, update buffer stats */
+  if (jbuf->mode == RTP_JITTER_BUFFER_MODE_BUFFER)
+    update_buffer_level (jbuf, percent);
+  else if (percent)
+    *percent = -1;
+
+  /* head was changed when we did not find a previous packet, we set the return
+   * flag when requested. */
+  if (G_LIKELY (head))
+    *head = (list == NULL);
+
+  return TRUE;
+
+  /* ERRORS */
+duplicate:
+  {
+    GST_DEBUG ("duplicate packet %d found", (gint) seqnum);
+    if (G_LIKELY (head))
+      *head = FALSE;
+    return FALSE;
+  }
+}
+
+/**
+ * rtp_jitter_buffer_pop:
+ * @jbuf: an #RTPJitterBuffer
+ * @percent: the buffering percent
+ *
+ * Pops the oldest buffer from the packet queue of @jbuf. The popped buffer will
+ * have its timestamp adjusted with the incomming running_time and the detected
+ * clock skew.
+ *
+ * Returns: a #GstBuffer or %NULL when there was no packet in the queue.
+ */
+RTPJitterBufferItem *
+rtp_jitter_buffer_pop (RTPJitterBuffer * jbuf, gint * percent)
+{
+  GList *item = NULL;
+  GQueue *queue;
+
+  g_return_val_if_fail (jbuf != NULL, NULL);
+
+  queue = jbuf->packets;
+
+  item = queue->head;
+  if (item) {
+    queue->head = item->next;
+    if (queue->head)
+      queue->head->prev = NULL;
+    else
+      queue->tail = NULL;
+    queue->length--;
+  }
+
+  /* buffering mode, update buffer stats */
+  if (jbuf->mode == RTP_JITTER_BUFFER_MODE_BUFFER)
+    update_buffer_level (jbuf, percent);
+  else if (percent)
+    *percent = -1;
+
+  return (RTPJitterBufferItem *) item;
+}
+
+/**
+ * rtp_jitter_buffer_peek:
+ * @jbuf: an #RTPJitterBuffer
+ *
+ * Peek the oldest buffer from the packet queue of @jbuf.
+ *
+ * See rtp_jitter_buffer_insert() to check when an older packet was
+ * added.
+ *
+ * Returns: a #GstBuffer or %NULL when there was no packet in the queue.
+ */
+RTPJitterBufferItem *
+rtp_jitter_buffer_peek (RTPJitterBuffer * jbuf)
+{
+  g_return_val_if_fail (jbuf != NULL, NULL);
+
+  return (RTPJitterBufferItem *) jbuf->packets->head;
+}
+
+/**
+ * rtp_jitter_buffer_flush:
+ * @jbuf: an #RTPJitterBuffer
+ * @free_func: function to free each item
+ * @user_data: user data passed to @free_func
+ *
+ * Flush all packets from the jitterbuffer.
+ */
+void
+rtp_jitter_buffer_flush (RTPJitterBuffer * jbuf, GFunc free_func,
+    gpointer user_data)
+{
+  GList *item;
+
+  g_return_if_fail (jbuf != NULL);
+  g_return_if_fail (free_func != NULL);
+
+  while ((item = g_queue_pop_head_link (jbuf->packets)))
+    free_func ((RTPJitterBufferItem *) item, user_data);
+}
+
+/**
+ * rtp_jitter_buffer_is_buffering:
+ * @jbuf: an #RTPJitterBuffer
+ *
+ * Check if @jbuf is buffering currently. Users of the jitterbuffer should not
+ * pop packets while in buffering mode.
+ *
+ * Returns: the buffering state of @jbuf
+ */
+gboolean
+rtp_jitter_buffer_is_buffering (RTPJitterBuffer * jbuf)
+{
+  return jbuf->buffering && !jbuf->buffering_disabled;
+}
+
+/**
+ * rtp_jitter_buffer_set_buffering:
+ * @jbuf: an #RTPJitterBuffer
+ * @buffering: the new buffering state
+ *
+ * Forces @jbuf to go into the buffering state.
+ */
+void
+rtp_jitter_buffer_set_buffering (RTPJitterBuffer * jbuf, gboolean buffering)
+{
+  jbuf->buffering = buffering;
+}
+
+/**
+ * rtp_jitter_buffer_get_percent:
+ * @jbuf: an #RTPJitterBuffer
+ *
+ * Get the buffering percent of the jitterbuffer.
+ *
+ * Returns: the buffering percent
+ */
+gint
+rtp_jitter_buffer_get_percent (RTPJitterBuffer * jbuf)
+{
+  gint percent;
+  guint64 level;
+
+  if (G_UNLIKELY (jbuf->high_level == 0))
+    return 100;
+
+  if (G_UNLIKELY (jbuf->buffering_disabled))
+    return 100;
+
+  level = get_buffer_level (jbuf);
+  percent = (level * 100 / jbuf->high_level);
+  percent = MIN (percent, 100);
+
+  return percent;
+}
+
+/**
+ * rtp_jitter_buffer_num_packets:
+ * @jbuf: an #RTPJitterBuffer
+ *
+ * Get the number of packets currently in "jbuf.
+ *
+ * Returns: The number of packets in @jbuf.
+ */
+guint
+rtp_jitter_buffer_num_packets (RTPJitterBuffer * jbuf)
+{
+  g_return_val_if_fail (jbuf != NULL, 0);
+
+  return jbuf->packets->length;
+}
+
+/**
+ * rtp_jitter_buffer_get_ts_diff:
+ * @jbuf: an #RTPJitterBuffer
+ *
+ * Get the difference between the timestamps of first and last packet in the
+ * jitterbuffer.
+ *
+ * Returns: The difference expressed in the timestamp units of the packets.
+ */
+guint32
+rtp_jitter_buffer_get_ts_diff (RTPJitterBuffer * jbuf)
+{
+  guint64 high_ts, low_ts;
+  RTPJitterBufferItem *high_buf, *low_buf;
+  guint32 result;
+
+  g_return_val_if_fail (jbuf != NULL, 0);
+
+  high_buf = (RTPJitterBufferItem *) g_queue_peek_tail_link (jbuf->packets);
+  low_buf = (RTPJitterBufferItem *) g_queue_peek_head_link (jbuf->packets);
+
+  if (!high_buf || !low_buf || high_buf == low_buf)
+    return 0;
+
+  high_ts = high_buf->rtptime;
+  low_ts = low_buf->rtptime;
+
+  /* it needs to work if ts wraps */
+  if (high_ts >= low_ts) {
+    result = (guint32) (high_ts - low_ts);
+  } else {
+    result = (guint32) (high_ts + G_MAXUINT32 + 1 - low_ts);
+  }
+  return result;
+}
+
+/**
+ * rtp_jitter_buffer_get_sync:
+ * @jbuf: an #RTPJitterBuffer
+ * @rtptime: result RTP time
+ * @timestamp: result GStreamer timestamp
+ * @clock_rate: clock-rate of @rtptime
+ * @last_rtptime: last seen rtptime.
+ *
+ * Calculates the relation between the RTP timestamp and the GStreamer timestamp
+ * used for constructing timestamps.
+ *
+ * For extended RTP timestamp @rtptime with a clock-rate of @clock_rate,
+ * the GStreamer timestamp is currently @timestamp.
+ *
+ * The last seen extended RTP timestamp with clock-rate @clock-rate is returned in
+ * @last_rtptime.
+ */
+void
+rtp_jitter_buffer_get_sync (RTPJitterBuffer * jbuf, guint64 * rtptime,
+    guint64 * timestamp, guint32 * clock_rate, guint64 * last_rtptime)
+{
+  if (rtptime)
+    *rtptime = jbuf->base_extrtp;
+  if (timestamp)
+    *timestamp = jbuf->base_time + jbuf->skew;
+  if (clock_rate)
+    *clock_rate = jbuf->clock_rate;
+  if (last_rtptime)
+    *last_rtptime = jbuf->last_rtptime;
+}
+
+/**
+ * rtp_jitter_buffer_can_fast_start:
+ * @jbuf: an #RTPJitterBuffer
+ * @num_packets: Number of consecutive packets needed
+ *
+ * Check if in the queue if there is enough packets with consecutive seqnum in
+ * order to start delivering them.
+ *
+ * Returns: %TRUE if the required number of consecutive packets was found.
+ */
+gboolean
+rtp_jitter_buffer_can_fast_start (RTPJitterBuffer * jbuf, gint num_packet)
+{
+  gboolean ret = TRUE;
+  RTPJitterBufferItem *last_item = NULL, *item;
+  gint i;
+
+  if (rtp_jitter_buffer_num_packets (jbuf) < num_packet)
+    return FALSE;
+
+  item = rtp_jitter_buffer_peek (jbuf);
+  for (i = 0; i < num_packet; i++) {
+    if (G_LIKELY (last_item)) {
+      guint16 expected_seqnum = last_item->seqnum + 1;
+
+      if (expected_seqnum != item->seqnum) {
+        ret = FALSE;
+        break;
+      }
+    }
+
+    last_item = item;
+    item = (RTPJitterBufferItem *) last_item->next;
+  }
+
+  return ret;
+}
diff --git a/gst/rtpmanager/rtpjitterbuffer.h b/gst/rtpmanager/rtpjitterbuffer.h
new file mode 100644
index 0000000..16db644
--- /dev/null
+++ b/gst/rtpmanager/rtpjitterbuffer.h
@@ -0,0 +1,197 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __RTP_JITTER_BUFFER_H__
+#define __RTP_JITTER_BUFFER_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtcpbuffer.h>
+
+typedef struct _RTPJitterBuffer RTPJitterBuffer;
+typedef struct _RTPJitterBufferClass RTPJitterBufferClass;
+typedef struct _RTPJitterBufferItem RTPJitterBufferItem;
+
+#define RTP_TYPE_JITTER_BUFFER             (rtp_jitter_buffer_get_type())
+#define RTP_JITTER_BUFFER(src)             (G_TYPE_CHECK_INSTANCE_CAST((src),RTP_TYPE_JITTER_BUFFER,RTPJitterBuffer))
+#define RTP_JITTER_BUFFER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),RTP_TYPE_JITTER_BUFFER,RTPJitterBufferClass))
+#define RTP_IS_JITTER_BUFFER(src)          (G_TYPE_CHECK_INSTANCE_TYPE((src),RTP_TYPE_JITTER_BUFFER))
+#define RTP_IS_JITTER_BUFFER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),RTP_TYPE_JITTER_BUFFER))
+#define RTP_JITTER_BUFFER_CAST(src)        ((RTPJitterBuffer *)(src))
+
+/**
+ * RTPJitterBufferMode:
+ * @RTP_JITTER_BUFFER_MODE_NONE: don't do any skew correction, outgoing
+ *    timestamps are calculated directly from the RTP timestamps. This mode is
+ *    good for recording but not for real-time applications.
+ * @RTP_JITTER_BUFFER_MODE_SLAVE: calculate the skew between sender and receiver
+ *    and produce smoothed adjusted outgoing timestamps. This mode is good for
+ *    low latency communications.
+ * @RTP_JITTER_BUFFER_MODE_BUFFER: buffer packets between low/high watermarks.
+ *    This mode is good for streaming communication.
+ * @RTP_JITTER_BUFFER_MODE_SYNCED: sender and receiver clocks are synchronized,
+ *    like #RTP_JITTER_BUFFER_MODE_SLAVE but skew is assumed to be 0. Good for
+ *    low latency communication when sender and receiver clocks are
+ *    synchronized and there is thus no clock skew.
+ * @RTP_JITTER_BUFFER_MODE_LAST: last buffer mode.
+ *
+ * The different buffer modes for a jitterbuffer.
+ */
+typedef enum {
+  RTP_JITTER_BUFFER_MODE_NONE    = 0,
+  RTP_JITTER_BUFFER_MODE_SLAVE   = 1,
+  RTP_JITTER_BUFFER_MODE_BUFFER  = 2,
+  /* FIXME 3 is missing because it was used for 'auto' in jitterbuffer */
+  RTP_JITTER_BUFFER_MODE_SYNCED  = 4,
+  RTP_JITTER_BUFFER_MODE_LAST
+} RTPJitterBufferMode;
+
+#define RTP_TYPE_JITTER_BUFFER_MODE (rtp_jitter_buffer_mode_get_type())
+GType rtp_jitter_buffer_mode_get_type (void);
+
+#define RTP_JITTER_BUFFER_MAX_WINDOW 512
+/**
+ * RTPJitterBuffer:
+ *
+ * A JitterBuffer in the #RTPSession
+ */
+struct _RTPJitterBuffer {
+  GObject        object;
+
+  GQueue        *packets;
+
+  RTPJitterBufferMode mode;
+
+  GstClockTime   delay;
+
+  /* for buffering */
+  gboolean          buffering;
+  guint64           low_level;
+  guint64           high_level;
+
+  /* for calculating skew */
+  gboolean       need_resync;
+  GstClockTime   base_time;
+  GstClockTime   base_rtptime;
+  GstClockTime   media_clock_base_time;
+  guint32        clock_rate;
+  GstClockTime   base_extrtp;
+  GstClockTime   prev_out_time;
+  guint64        ext_rtptime;
+  guint64        last_rtptime;
+  gint64         window[RTP_JITTER_BUFFER_MAX_WINDOW];
+  guint          window_pos;
+  guint          window_size;
+  gboolean       window_filling;
+  gint64         window_min;
+  gint64         skew;
+  gint64         prev_send_diff;
+  gboolean       buffering_disabled;
+
+  GMutex         clock_lock;
+  GstClock      *pipeline_clock;
+  GstClock      *media_clock;
+  gulong         media_clock_synced_id;
+  guint64        media_clock_offset;
+
+  gboolean       rfc7273_sync;
+};
+
+struct _RTPJitterBufferClass {
+  GObjectClass   parent_class;
+};
+
+/**
+ * RTPJitterBufferItem:
+ * @data: the data of the item
+ * @next: pointer to next item
+ * @prev: pointer to previous item
+ * @type: the type of @data, used freely by caller
+ * @dts: input DTS
+ * @pts: output PTS
+ * @seqnum: seqnum, the seqnum is used to insert the item in the
+ *   right position in the jitterbuffer and detect duplicates. Use -1 to
+ *   append.
+ * @count: amount of seqnum in this item
+ * @rtptime: rtp timestamp
+ *
+ * An object containing an RTP packet or event.
+ */
+struct _RTPJitterBufferItem {
+  gpointer data;
+  GList *next;
+  GList *prev;
+  guint type;
+  GstClockTime dts;
+  GstClockTime pts;
+  guint seqnum;
+  guint count;
+  guint rtptime;
+};
+
+GType rtp_jitter_buffer_get_type (void);
+
+/* managing lifetime */
+RTPJitterBuffer*      rtp_jitter_buffer_new              (void);
+
+RTPJitterBufferMode   rtp_jitter_buffer_get_mode         (RTPJitterBuffer *jbuf);
+void                  rtp_jitter_buffer_set_mode         (RTPJitterBuffer *jbuf, RTPJitterBufferMode mode);
+
+GstClockTime          rtp_jitter_buffer_get_delay        (RTPJitterBuffer *jbuf);
+void                  rtp_jitter_buffer_set_delay        (RTPJitterBuffer *jbuf, GstClockTime delay);
+
+void                  rtp_jitter_buffer_set_clock_rate   (RTPJitterBuffer *jbuf, guint32 clock_rate);
+guint32               rtp_jitter_buffer_get_clock_rate   (RTPJitterBuffer *jbuf);
+
+void                  rtp_jitter_buffer_set_media_clock  (RTPJitterBuffer *jbuf, GstClock * clock, guint64 clock_offset);
+void                  rtp_jitter_buffer_set_pipeline_clock (RTPJitterBuffer *jbuf, GstClock * clock);
+
+gboolean              rtp_jitter_buffer_get_rfc7273_sync (RTPJitterBuffer *jbuf);
+void                  rtp_jitter_buffer_set_rfc7273_sync (RTPJitterBuffer *jbuf, gboolean rfc7273_sync);
+
+void                  rtp_jitter_buffer_reset_skew       (RTPJitterBuffer *jbuf);
+
+gboolean              rtp_jitter_buffer_insert           (RTPJitterBuffer *jbuf,
+                                                          RTPJitterBufferItem *item,
+                                                          gboolean *head, gint *percent);
+
+void                  rtp_jitter_buffer_disable_buffering (RTPJitterBuffer *jbuf, gboolean disabled);
+
+RTPJitterBufferItem * rtp_jitter_buffer_peek             (RTPJitterBuffer *jbuf);
+RTPJitterBufferItem * rtp_jitter_buffer_pop              (RTPJitterBuffer *jbuf, gint *percent);
+
+void                  rtp_jitter_buffer_flush            (RTPJitterBuffer *jbuf,
+                                                          GFunc free_func, gpointer user_data);
+
+gboolean              rtp_jitter_buffer_is_buffering     (RTPJitterBuffer * jbuf);
+void                  rtp_jitter_buffer_set_buffering    (RTPJitterBuffer * jbuf, gboolean buffering);
+gint                  rtp_jitter_buffer_get_percent      (RTPJitterBuffer * jbuf);
+
+guint                 rtp_jitter_buffer_num_packets      (RTPJitterBuffer *jbuf);
+guint32               rtp_jitter_buffer_get_ts_diff      (RTPJitterBuffer *jbuf);
+
+void                  rtp_jitter_buffer_get_sync         (RTPJitterBuffer *jbuf, guint64 *rtptime,
+                                                          guint64 *timestamp, guint32 *clock_rate,
+                                                          guint64 *last_rtptime);
+
+GstClockTime          rtp_jitter_buffer_calculate_pts    (RTPJitterBuffer * jbuf, GstClockTime dts, gboolean estimated_dts,
+                                                          guint32 rtptime, GstClockTime base_time);
+
+gboolean              rtp_jitter_buffer_can_fast_start   (RTPJitterBuffer * jbuf, gint num_packet);
+
+#endif /* __RTP_JITTER_BUFFER_H__ */
diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c
new file mode 100644
index 0000000..0b99d23
--- /dev/null
+++ b/gst/rtpmanager/rtpsession.c
@@ -0,0 +1,4428 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/rtp/gstrtcpbuffer.h>
+
+#include <gst/glib-compat-private.h>
+
+#include "rtpsession.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtp_session_debug);
+#define GST_CAT_DEFAULT rtp_session_debug
+
+/* signals and args */
+enum
+{
+  SIGNAL_GET_SOURCE_BY_SSRC,
+  SIGNAL_ON_NEW_SSRC,
+  SIGNAL_ON_SSRC_COLLISION,
+  SIGNAL_ON_SSRC_VALIDATED,
+  SIGNAL_ON_SSRC_ACTIVE,
+  SIGNAL_ON_SSRC_SDES,
+  SIGNAL_ON_BYE_SSRC,
+  SIGNAL_ON_BYE_TIMEOUT,
+  SIGNAL_ON_TIMEOUT,
+  SIGNAL_ON_SENDER_TIMEOUT,
+  SIGNAL_ON_SENDING_RTCP,
+  SIGNAL_ON_APP_RTCP,
+  SIGNAL_ON_FEEDBACK_RTCP,
+  SIGNAL_SEND_RTCP,
+  SIGNAL_SEND_RTCP_FULL,
+  SIGNAL_ON_RECEIVING_RTCP,
+  SIGNAL_ON_NEW_SENDER_SSRC,
+  SIGNAL_ON_SENDER_SSRC_ACTIVE,
+  LAST_SIGNAL
+};
+
+#define DEFAULT_INTERNAL_SOURCE      NULL
+#define DEFAULT_BANDWIDTH            0.0
+#define DEFAULT_RTCP_FRACTION        RTP_STATS_RTCP_FRACTION
+#define DEFAULT_RTCP_RR_BANDWIDTH    -1
+#define DEFAULT_RTCP_RS_BANDWIDTH    -1
+#define DEFAULT_RTCP_MTU             1400
+#define DEFAULT_SDES                 NULL
+#define DEFAULT_NUM_SOURCES          0
+#define DEFAULT_NUM_ACTIVE_SOURCES   0
+#define DEFAULT_SOURCES              NULL
+#define DEFAULT_RTCP_MIN_INTERVAL    (RTP_STATS_MIN_INTERVAL * GST_SECOND)
+#define DEFAULT_RTCP_FEEDBACK_RETENTION_WINDOW (2 * GST_SECOND)
+#define DEFAULT_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD (3)
+#define DEFAULT_PROBATION            RTP_DEFAULT_PROBATION
+#define DEFAULT_MAX_DROPOUT_TIME     60000
+#define DEFAULT_MAX_MISORDER_TIME    2000
+#define DEFAULT_RTP_PROFILE          GST_RTP_PROFILE_AVP
+#define DEFAULT_RTCP_REDUCED_SIZE    FALSE
+
+enum
+{
+  PROP_0,
+  PROP_INTERNAL_SSRC,
+  PROP_INTERNAL_SOURCE,
+  PROP_BANDWIDTH,
+  PROP_RTCP_FRACTION,
+  PROP_RTCP_RR_BANDWIDTH,
+  PROP_RTCP_RS_BANDWIDTH,
+  PROP_RTCP_MTU,
+  PROP_SDES,
+  PROP_NUM_SOURCES,
+  PROP_NUM_ACTIVE_SOURCES,
+  PROP_SOURCES,
+  PROP_FAVOR_NEW,
+  PROP_RTCP_MIN_INTERVAL,
+  PROP_RTCP_FEEDBACK_RETENTION_WINDOW,
+  PROP_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD,
+  PROP_PROBATION,
+  PROP_MAX_DROPOUT_TIME,
+  PROP_MAX_MISORDER_TIME,
+  PROP_STATS,
+  PROP_RTP_PROFILE,
+  PROP_RTCP_REDUCED_SIZE
+};
+
+/* update average packet size */
+#define INIT_AVG(avg, val) \
+   (avg) = (val);
+#define UPDATE_AVG(avg, val)            \
+  if ((avg) == 0)                       \
+   (avg) = (val);                       \
+  else                                  \
+   (avg) = ((val) + (15 * (avg))) >> 4;
+
+
+/* GObject vmethods */
+static void rtp_session_finalize (GObject * object);
+static void rtp_session_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void rtp_session_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean rtp_session_send_rtcp (RTPSession * sess,
+    GstClockTime max_delay);
+
+static guint rtp_session_signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (RTPSession, rtp_session, G_TYPE_OBJECT);
+
+static guint32 rtp_session_create_new_ssrc (RTPSession * sess);
+static RTPSource *obtain_source (RTPSession * sess, guint32 ssrc,
+    gboolean * created, RTPPacketInfo * pinfo, gboolean rtp);
+static RTPSource *obtain_internal_source (RTPSession * sess,
+    guint32 ssrc, gboolean * created, GstClockTime current_time);
+static GstFlowReturn rtp_session_schedule_bye_locked (RTPSession * sess,
+    GstClockTime current_time);
+static GstClockTime calculate_rtcp_interval (RTPSession * sess,
+    gboolean deterministic, gboolean first);
+
+static gboolean
+accumulate_trues (GSignalInvocationHint * ihint, GValue * return_accu,
+    const GValue * handler_return, gpointer data)
+{
+  if (g_value_get_boolean (handler_return))
+    g_value_set_boolean (return_accu, TRUE);
+
+  return TRUE;
+}
+
+static void
+rtp_session_class_init (RTPSessionClass * klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = (GObjectClass *) klass;
+
+  gobject_class->finalize = rtp_session_finalize;
+  gobject_class->set_property = rtp_session_set_property;
+  gobject_class->get_property = rtp_session_get_property;
+
+  /**
+   * RTPSession::get-source-by-ssrc:
+   * @session: the object which received the signal
+   * @ssrc: the SSRC of the RTPSource
+   *
+   * Request the #RTPSource object with SSRC @ssrc in @session.
+   */
+  rtp_session_signals[SIGNAL_GET_SOURCE_BY_SSRC] =
+      g_signal_new ("get-source-by-ssrc", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (RTPSessionClass,
+          get_source_by_ssrc), NULL, NULL, g_cclosure_marshal_generic,
+      RTP_TYPE_SOURCE, 1, G_TYPE_UINT);
+
+  /**
+   * RTPSession::on-new-ssrc:
+   * @session: the object which received the signal
+   * @src: the new RTPSource
+   *
+   * Notify of a new SSRC that entered @session.
+   */
+  rtp_session_signals[SIGNAL_ON_NEW_SSRC] =
+      g_signal_new ("on-new-ssrc", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_new_ssrc),
+      NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+      RTP_TYPE_SOURCE);
+  /**
+   * RTPSession::on-ssrc-collision:
+   * @session: the object which received the signal
+   * @src: the #RTPSource that caused a collision
+   *
+   * Notify when we have an SSRC collision
+   */
+  rtp_session_signals[SIGNAL_ON_SSRC_COLLISION] =
+      g_signal_new ("on-ssrc-collision", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_ssrc_collision),
+      NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+      RTP_TYPE_SOURCE);
+  /**
+   * RTPSession::on-ssrc-validated:
+   * @session: the object which received the signal
+   * @src: the new validated RTPSource
+   *
+   * Notify of a new SSRC that became validated.
+   */
+  rtp_session_signals[SIGNAL_ON_SSRC_VALIDATED] =
+      g_signal_new ("on-ssrc-validated", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_ssrc_validated),
+      NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+      RTP_TYPE_SOURCE);
+  /**
+   * RTPSession::on-ssrc-active:
+   * @session: the object which received the signal
+   * @src: the active RTPSource
+   *
+   * Notify of a SSRC that is active, i.e., sending RTCP.
+   */
+  rtp_session_signals[SIGNAL_ON_SSRC_ACTIVE] =
+      g_signal_new ("on-ssrc-active", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_ssrc_active),
+      NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+      RTP_TYPE_SOURCE);
+  /**
+   * RTPSession::on-ssrc-sdes:
+   * @session: the object which received the signal
+   * @src: the RTPSource
+   *
+   * Notify that a new SDES was received for SSRC.
+   */
+  rtp_session_signals[SIGNAL_ON_SSRC_SDES] =
+      g_signal_new ("on-ssrc-sdes", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_ssrc_sdes),
+      NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+      RTP_TYPE_SOURCE);
+  /**
+   * RTPSession::on-bye-ssrc:
+   * @session: the object which received the signal
+   * @src: the RTPSource that went away
+   *
+   * Notify of an SSRC that became inactive because of a BYE packet.
+   */
+  rtp_session_signals[SIGNAL_ON_BYE_SSRC] =
+      g_signal_new ("on-bye-ssrc", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_bye_ssrc),
+      NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+      RTP_TYPE_SOURCE);
+  /**
+   * RTPSession::on-bye-timeout:
+   * @session: the object which received the signal
+   * @src: the RTPSource that timed out
+   *
+   * Notify of an SSRC that has timed out because of BYE
+   */
+  rtp_session_signals[SIGNAL_ON_BYE_TIMEOUT] =
+      g_signal_new ("on-bye-timeout", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_bye_timeout),
+      NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+      RTP_TYPE_SOURCE);
+  /**
+   * RTPSession::on-timeout:
+   * @session: the object which received the signal
+   * @src: the RTPSource that timed out
+   *
+   * Notify of an SSRC that has timed out
+   */
+  rtp_session_signals[SIGNAL_ON_TIMEOUT] =
+      g_signal_new ("on-timeout", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_timeout),
+      NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+      RTP_TYPE_SOURCE);
+  /**
+   * RTPSession::on-sender-timeout:
+   * @session: the object which received the signal
+   * @src: the RTPSource that timed out
+   *
+   * Notify of an SSRC that was a sender but timed out and became a receiver.
+   */
+  rtp_session_signals[SIGNAL_ON_SENDER_TIMEOUT] =
+      g_signal_new ("on-sender-timeout", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_sender_timeout),
+      NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+      RTP_TYPE_SOURCE);
+
+  /**
+   * RTPSession::on-sending-rtcp
+   * @session: the object which received the signal
+   * @buffer: the #GstBuffer containing the RTCP packet about to be sent
+   * @early: %TRUE if the packet is early, %FALSE if it is regular
+   *
+   * This signal is emitted before sending an RTCP packet, it can be used
+   * to add extra RTCP Packets.
+   *
+   * Returns: %TRUE if the RTCP buffer should NOT be suppressed, %FALSE
+   * if suppressing it is acceptable
+   */
+  rtp_session_signals[SIGNAL_ON_SENDING_RTCP] =
+      g_signal_new ("on-sending-rtcp", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_sending_rtcp),
+      accumulate_trues, NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 2,
+      GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, G_TYPE_BOOLEAN);
+
+  /**
+   * RTPSession::on-app-rtcp:
+   * @session: the object which received the signal
+   * @subtype: The subtype of the packet
+   * @ssrc: The SSRC/CSRC of the packet
+   * @name: The name of the packet
+   * @data: a #GstBuffer with the application-dependant data or %NULL if
+   * there was no data
+   *
+   * Notify that a RTCP APP packet has been received
+   */
+  rtp_session_signals[SIGNAL_ON_APP_RTCP] =
+      g_signal_new ("on-app-rtcp", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_app_rtcp),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 4,
+      G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, GST_TYPE_BUFFER);
+
+  /**
+   * RTPSession::on-feedback-rtcp:
+   * @session: the object which received the signal
+   * @type: Type of RTCP packet, will be %GST_RTCP_TYPE_RTPFB or
+   *  %GST_RTCP_TYPE_RTPFB
+   * @fbtype: The type of RTCP FB packet, probably part of #GstRTCPFBType
+   * @sender_ssrc: The SSRC of the sender
+   * @media_ssrc: The SSRC of the media this refers to
+   * @fci: a #GstBuffer with the FCI data from the FB packet or %NULL if
+   * there was no FCI
+   *
+   * Notify that a RTCP feedback packet has been received
+   */
+  rtp_session_signals[SIGNAL_ON_FEEDBACK_RTCP] =
+      g_signal_new ("on-feedback-rtcp", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_feedback_rtcp),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 5, G_TYPE_UINT,
+      G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, GST_TYPE_BUFFER);
+
+  /**
+   * RTPSession::send-rtcp:
+   * @session: the object which received the signal
+   * @max_delay: The maximum delay after which the feedback will not be useful
+   *  anymore
+   *
+   * Requests that the #RTPSession initiate a new RTCP packet as soon as
+   * possible within the requested delay.
+   *
+   * This sets feedback to %TRUE if not already done before.
+   */
+  rtp_session_signals[SIGNAL_SEND_RTCP] =
+      g_signal_new ("send-rtcp", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_STRUCT_OFFSET (RTPSessionClass, send_rtcp), NULL, NULL,
+      g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_UINT64);
+
+  /**
+   * RTPSession::send-rtcp-full:
+   * @session: the object which received the signal
+   * @max_delay: The maximum delay after which the feedback will not be useful
+   *  anymore
+   *
+   * Requests that the #RTPSession initiate a new RTCP packet as soon as
+   * possible within the requested delay.
+   *
+   * This sets feedback to %TRUE if not already done before.
+   *
+   * Returns: TRUE if the new RTCP packet could be scheduled within the
+   * requested delay, FALSE otherwise.
+   *
+   * Since: 1.6
+   */
+  rtp_session_signals[SIGNAL_SEND_RTCP_FULL] =
+      g_signal_new ("send-rtcp-full", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_STRUCT_OFFSET (RTPSessionClass, send_rtcp), NULL, NULL,
+      g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 1, G_TYPE_UINT64);
+
+  /**
+   * RTPSession::on-receiving-rtcp
+   * @session: the object which received the signal
+   * @buffer: the #GstBuffer containing the RTCP packet that was received
+   *
+   * This signal is emitted when receiving an RTCP packet before it is handled
+   * by the session. It can be used to extract custom information from RTCP packets.
+   *
+   * Since: 1.6
+   */
+  rtp_session_signals[SIGNAL_ON_RECEIVING_RTCP] =
+      g_signal_new ("on-receiving-rtcp", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_receiving_rtcp),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
+      GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+  /**
+   * RTPSession::on-new-sender-ssrc:
+   * @session: the object which received the signal
+   * @src: the new sender RTPSource
+   *
+   * Notify of a new sender SSRC that entered @session.
+   *
+   * Since: 1.8
+   */
+  rtp_session_signals[SIGNAL_ON_NEW_SENDER_SSRC] =
+      g_signal_new ("on-new-sender-ssrc", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_new_sender_ssrc),
+      NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+      RTP_TYPE_SOURCE);
+
+  /**
+   * RTPSession::on-sender-ssrc-active:
+   * @session: the object which received the signal
+   * @src: the active sender RTPSource
+   *
+   * Notify of a sender SSRC that is active, i.e., sending RTCP.
+   *
+   * Since: 1.8
+   */
+  rtp_session_signals[SIGNAL_ON_SENDER_SSRC_ACTIVE] =
+      g_signal_new ("on-sender-ssrc-active", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass,
+          on_sender_ssrc_active), NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
+      G_TYPE_NONE, 1, RTP_TYPE_SOURCE);
+
+  g_object_class_install_property (gobject_class, PROP_INTERNAL_SSRC,
+      g_param_spec_uint ("internal-ssrc", "Internal SSRC",
+          "The internal SSRC used for the session (deprecated)",
+          0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_INTERNAL_SOURCE,
+      g_param_spec_object ("internal-source", "Internal Source",
+          "The internal source element of the session (deprecated)",
+          RTP_TYPE_SOURCE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_BANDWIDTH,
+      g_param_spec_double ("bandwidth", "Bandwidth",
+          "The bandwidth of the session in bits per second (0 for auto-discover)",
+          0.0, G_MAXDOUBLE, DEFAULT_BANDWIDTH,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RTCP_FRACTION,
+      g_param_spec_double ("rtcp-fraction", "RTCP Fraction",
+          "The fraction of the bandwidth used for RTCP in bits per second (or as a real fraction of the RTP bandwidth if < 1)",
+          0.0, G_MAXDOUBLE, DEFAULT_RTCP_FRACTION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RTCP_RR_BANDWIDTH,
+      g_param_spec_int ("rtcp-rr-bandwidth", "RTCP RR bandwidth",
+          "The RTCP bandwidth used for receivers in bits per second (-1 = default)",
+          -1, G_MAXINT, DEFAULT_RTCP_RR_BANDWIDTH,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RTCP_RS_BANDWIDTH,
+      g_param_spec_int ("rtcp-rs-bandwidth", "RTCP RS bandwidth",
+          "The RTCP bandwidth used for senders in bits per second (-1 = default)",
+          -1, G_MAXINT, DEFAULT_RTCP_RS_BANDWIDTH,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RTCP_MTU,
+      g_param_spec_uint ("rtcp-mtu", "RTCP MTU",
+          "The maximum size of the RTCP packets",
+          16, G_MAXINT16, DEFAULT_RTCP_MTU,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_SDES,
+      g_param_spec_boxed ("sdes", "SDES",
+          "The SDES items of this session",
+          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NUM_SOURCES,
+      g_param_spec_uint ("num-sources", "Num Sources",
+          "The number of sources in the session", 0, G_MAXUINT,
+          DEFAULT_NUM_SOURCES, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NUM_ACTIVE_SOURCES,
+      g_param_spec_uint ("num-active-sources", "Num Active Sources",
+          "The number of active sources in the session", 0, G_MAXUINT,
+          DEFAULT_NUM_ACTIVE_SOURCES,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  /**
+   * RTPSource::sources
+   *
+   * Get a GValue Array of all sources in the session.
+   *
+   * <example>
+   * <title>Getting the #RTPSources of a session
+   * <programlisting>
+   * {
+   *   GValueArray *arr;
+   *   GValue *val;
+   *   guint i;
+   *
+   *   g_object_get (sess, "sources", &arr, NULL);
+   *
+   *   for (i = 0; i < arr->n_values; i++) {
+   *     RTPSource *source;
+   *
+   *     val = g_value_array_get_nth (arr, i);
+   *     source = g_value_get_object (val);
+   *   }
+   *   g_value_array_free (arr);
+   * }
+   * </programlisting>
+   * </example>
+   */
+  g_object_class_install_property (gobject_class, PROP_SOURCES,
+      g_param_spec_boxed ("sources", "Sources",
+          "An array of all known sources in the session",
+          G_TYPE_VALUE_ARRAY, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_FAVOR_NEW,
+      g_param_spec_boolean ("favor-new", "Favor new sources",
+          "Resolve SSRC conflict in favor of new sources", FALSE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RTCP_MIN_INTERVAL,
+      g_param_spec_uint64 ("rtcp-min-interval", "Minimum RTCP interval",
+          "Minimum interval between Regular RTCP packet (in ns)",
+          0, G_MAXUINT64, DEFAULT_RTCP_MIN_INTERVAL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_RTCP_FEEDBACK_RETENTION_WINDOW,
+      g_param_spec_uint64 ("rtcp-feedback-retention-window",
+          "RTCP Feedback retention window",
+          "Duration during which RTCP Feedback packets are retained (in ns)",
+          0, G_MAXUINT64, DEFAULT_RTCP_FEEDBACK_RETENTION_WINDOW,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD,
+      g_param_spec_uint ("rtcp-immediate-feedback-threshold",
+          "RTCP Immediate Feedback threshold",
+          "The maximum number of members of a RTP session for which immediate"
+          " feedback is used (DEPRECATED: has no effect and is not needed)",
+          0, G_MAXUINT, DEFAULT_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
+
+  g_object_class_install_property (gobject_class, PROP_PROBATION,
+      g_param_spec_uint ("probation", "Number of probations",
+          "Consecutive packet sequence numbers to accept the source",
+          0, G_MAXUINT, DEFAULT_PROBATION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_DROPOUT_TIME,
+      g_param_spec_uint ("max-dropout-time", "Max dropout time",
+          "The maximum time (milliseconds) of missing packets tolerated.",
+          0, G_MAXUINT, DEFAULT_MAX_DROPOUT_TIME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_MISORDER_TIME,
+      g_param_spec_uint ("max-misorder-time", "Max misorder time",
+          "The maximum time (milliseconds) of misordered packets tolerated.",
+          0, G_MAXUINT, DEFAULT_MAX_MISORDER_TIME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * RTPSession::stats:
+   *
+   * Various session statistics. This property returns a GstStructure
+   * with name application/x-rtp-session-stats with the following fields:
+   *
+   *  "rtx-drop-count"  G_TYPE_UINT   The number of retransmission events
+   *      dropped (due to bandwidth constraints)
+   *  "sent-nack-count" G_TYPE_UINT   Number of NACKs sent
+   *  "recv-nack-count" G_TYPE_UINT   Number of NACKs received
+   *  "source-stats"    G_TYPE_BOXED  GValueArray of #RTPSource::stats for all
+   *      RTP sources (Since 1.8)
+   *
+   * Since: 1.4
+   */
+  g_object_class_install_property (gobject_class, PROP_STATS,
+      g_param_spec_boxed ("stats", "Statistics",
+          "Various statistics", GST_TYPE_STRUCTURE,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RTP_PROFILE,
+      g_param_spec_enum ("rtp-profile", "RTP Profile",
+          "RTP profile to use for this session", GST_TYPE_RTP_PROFILE,
+          DEFAULT_RTP_PROFILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RTCP_REDUCED_SIZE,
+      g_param_spec_boolean ("rtcp-reduced-size", "RTCP Reduced Size",
+          "Use Reduced Size RTCP for feedback packets",
+          DEFAULT_RTCP_REDUCED_SIZE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  klass->get_source_by_ssrc =
+      GST_DEBUG_FUNCPTR (rtp_session_get_source_by_ssrc);
+  klass->send_rtcp = GST_DEBUG_FUNCPTR (rtp_session_send_rtcp);
+
+  GST_DEBUG_CATEGORY_INIT (rtp_session_debug, "rtpsession", 0, "RTP Session");
+}
+
+static void
+rtp_session_init (RTPSession * sess)
+{
+  gint i;
+  gchar *str;
+
+  g_mutex_init (&sess->lock);
+  sess->key = g_random_int ();
+  sess->mask_idx = 0;
+  sess->mask = 0;
+
+  /* TODO: We currently only use the first hash table but this is the
+   * beginning of an implementation for RFC2762
+   for (i = 0; i < 32; i++) {
+   */
+  for (i = 0; i < 1; i++) {
+    sess->ssrcs[i] =
+        g_hash_table_new_full (NULL, NULL, NULL,
+        (GDestroyNotify) g_object_unref);
+  }
+
+  rtp_stats_init_defaults (&sess->stats);
+  INIT_AVG (sess->stats.avg_rtcp_packet_size, 100);
+  rtp_stats_set_min_interval (&sess->stats,
+      (gdouble) DEFAULT_RTCP_MIN_INTERVAL / GST_SECOND);
+
+  sess->recalc_bandwidth = TRUE;
+  sess->bandwidth = DEFAULT_BANDWIDTH;
+  sess->rtcp_bandwidth = DEFAULT_RTCP_FRACTION;
+  sess->rtcp_rr_bandwidth = DEFAULT_RTCP_RR_BANDWIDTH;
+  sess->rtcp_rs_bandwidth = DEFAULT_RTCP_RS_BANDWIDTH;
+
+  /* default UDP header length */
+  sess->header_len = 28;
+  sess->mtu = DEFAULT_RTCP_MTU;
+
+  sess->probation = DEFAULT_PROBATION;
+  sess->max_dropout_time = DEFAULT_MAX_DROPOUT_TIME;
+  sess->max_misorder_time = DEFAULT_MAX_MISORDER_TIME;
+
+  /* some default SDES entries */
+  sess->sdes = gst_structure_new_empty ("application/x-rtp-source-sdes");
+
+  /* we do not want to leak details like the username or hostname here */
+  str = g_strdup_printf ("user%u@host-%x", g_random_int (), g_random_int ());
+  gst_structure_set (sess->sdes, "cname", G_TYPE_STRING, str, NULL);
+  g_free (str);
+
+#if 0
+  /* we do not want to leak the user's real name here */
+  str = g_strdup_printf ("Anon%u", g_random_int ());
+  gst_structure_set (sdes, "name", G_TYPE_STRING, str, NULL);
+  g_free (str);
+#endif
+
+  gst_structure_set (sess->sdes, "tool", G_TYPE_STRING, "GStreamer", NULL);
+
+  /* this is the SSRC we suggest */
+  sess->suggested_ssrc = rtp_session_create_new_ssrc (sess);
+  sess->internal_ssrc_set = FALSE;
+
+  sess->first_rtcp = TRUE;
+  sess->next_rtcp_check_time = GST_CLOCK_TIME_NONE;
+  sess->last_rtcp_check_time = GST_CLOCK_TIME_NONE;
+  sess->last_rtcp_send_time = GST_CLOCK_TIME_NONE;
+  sess->last_rtcp_interval = GST_CLOCK_TIME_NONE;
+
+  sess->next_early_rtcp_time = GST_CLOCK_TIME_NONE;
+  sess->rtcp_feedback_retention_window = DEFAULT_RTCP_FEEDBACK_RETENTION_WINDOW;
+  sess->rtcp_immediate_feedback_threshold =
+      DEFAULT_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD;
+  sess->rtp_profile = DEFAULT_RTP_PROFILE;
+  sess->reduced_size_rtcp = DEFAULT_RTCP_REDUCED_SIZE;
+
+  sess->is_doing_ptp = TRUE;
+}
+
+static void
+rtp_session_finalize (GObject * object)
+{
+  RTPSession *sess;
+  gint i;
+
+  sess = RTP_SESSION_CAST (object);
+
+  gst_structure_free (sess->sdes);
+
+  g_list_free_full (sess->conflicting_addresses,
+      (GDestroyNotify) rtp_conflicting_address_free);
+
+  /* TODO: Change this again when implementing RFC 2762
+   * for (i = 0; i < 32; i++)
+   */
+  for (i = 0; i < 1; i++)
+    g_hash_table_destroy (sess->ssrcs[i]);
+
+  g_mutex_clear (&sess->lock);
+
+  G_OBJECT_CLASS (rtp_session_parent_class)->finalize (object);
+}
+
+static void
+copy_source (gpointer key, RTPSource * source, GValueArray * arr)
+{
+  GValue value = { 0 };
+
+  g_value_init (&value, RTP_TYPE_SOURCE);
+  g_value_take_object (&value, source);
+  /* copies the value */
+  g_value_array_append (arr, &value);
+}
+
+static GValueArray *
+rtp_session_create_sources (RTPSession * sess)
+{
+  GValueArray *res;
+  guint size;
+
+  RTP_SESSION_LOCK (sess);
+  /* get number of elements in the table */
+  size = g_hash_table_size (sess->ssrcs[sess->mask_idx]);
+  /* create the result value array */
+  res = g_value_array_new (size);
+
+  /* and copy all values into the array */
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx], (GHFunc) copy_source, res);
+  RTP_SESSION_UNLOCK (sess);
+
+  return res;
+}
+
+static void
+create_source_stats (gpointer key, RTPSource * source, GValueArray * arr)
+{
+  GValue value = G_VALUE_INIT;
+  GstStructure *s;
+
+  g_object_get (source, "stats", &s, NULL);
+
+  g_value_init (&value, GST_TYPE_STRUCTURE);
+  gst_value_set_structure (&value, s);
+  g_value_array_append (arr, &value);
+  gst_structure_free (s);
+  g_value_unset (&value);
+}
+
+static GstStructure *
+rtp_session_create_stats (RTPSession * sess)
+{
+  GstStructure *s;
+  GValueArray *source_stats;
+  GValue source_stats_v = G_VALUE_INIT;
+  guint size;
+
+  RTP_SESSION_LOCK (sess);
+  s = gst_structure_new ("application/x-rtp-session-stats",
+      "rtx-drop-count", G_TYPE_UINT, sess->stats.nacks_dropped,
+      "sent-nack-count", G_TYPE_UINT, sess->stats.nacks_sent,
+      "recv-nack-count", G_TYPE_UINT, sess->stats.nacks_received, NULL);
+
+  size = g_hash_table_size (sess->ssrcs[sess->mask_idx]);
+  source_stats = g_value_array_new (size);
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+      (GHFunc) create_source_stats, source_stats);
+  RTP_SESSION_UNLOCK (sess);
+
+  g_value_init (&source_stats_v, G_TYPE_VALUE_ARRAY);
+  g_value_take_boxed (&source_stats_v, source_stats);
+  gst_structure_take_value (s, "source-stats", &source_stats_v);
+
+  return s;
+}
+
+static void
+rtp_session_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  RTPSession *sess;
+
+  sess = RTP_SESSION (object);
+
+  switch (prop_id) {
+    case PROP_INTERNAL_SSRC:
+      RTP_SESSION_LOCK (sess);
+      sess->suggested_ssrc = g_value_get_uint (value);
+      sess->internal_ssrc_set = TRUE;
+      sess->internal_ssrc_from_caps_or_property = TRUE;
+      RTP_SESSION_UNLOCK (sess);
+      if (sess->callbacks.reconfigure)
+        sess->callbacks.reconfigure (sess, sess->reconfigure_user_data);
+      break;
+    case PROP_BANDWIDTH:
+      RTP_SESSION_LOCK (sess);
+      sess->bandwidth = g_value_get_double (value);
+      sess->recalc_bandwidth = TRUE;
+      RTP_SESSION_UNLOCK (sess);
+      break;
+    case PROP_RTCP_FRACTION:
+      RTP_SESSION_LOCK (sess);
+      sess->rtcp_bandwidth = g_value_get_double (value);
+      sess->recalc_bandwidth = TRUE;
+      RTP_SESSION_UNLOCK (sess);
+      break;
+    case PROP_RTCP_RR_BANDWIDTH:
+      RTP_SESSION_LOCK (sess);
+      sess->rtcp_rr_bandwidth = g_value_get_int (value);
+      sess->recalc_bandwidth = TRUE;
+      RTP_SESSION_UNLOCK (sess);
+      break;
+    case PROP_RTCP_RS_BANDWIDTH:
+      RTP_SESSION_LOCK (sess);
+      sess->rtcp_rs_bandwidth = g_value_get_int (value);
+      sess->recalc_bandwidth = TRUE;
+      RTP_SESSION_UNLOCK (sess);
+      break;
+    case PROP_RTCP_MTU:
+      sess->mtu = g_value_get_uint (value);
+      break;
+    case PROP_SDES:
+      rtp_session_set_sdes_struct (sess, g_value_get_boxed (value));
+      break;
+    case PROP_FAVOR_NEW:
+      sess->favor_new = g_value_get_boolean (value);
+      break;
+    case PROP_RTCP_MIN_INTERVAL:
+      rtp_stats_set_min_interval (&sess->stats,
+          (gdouble) g_value_get_uint64 (value) / GST_SECOND);
+      /* trigger reconsideration */
+      RTP_SESSION_LOCK (sess);
+      sess->next_rtcp_check_time = 0;
+      RTP_SESSION_UNLOCK (sess);
+      if (sess->callbacks.reconsider)
+        sess->callbacks.reconsider (sess, sess->reconsider_user_data);
+      break;
+    case PROP_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD:
+      sess->rtcp_immediate_feedback_threshold = g_value_get_uint (value);
+      break;
+    case PROP_PROBATION:
+      sess->probation = g_value_get_uint (value);
+      break;
+    case PROP_MAX_DROPOUT_TIME:
+      sess->max_dropout_time = g_value_get_uint (value);
+      break;
+    case PROP_MAX_MISORDER_TIME:
+      sess->max_misorder_time = g_value_get_uint (value);
+      break;
+    case PROP_RTP_PROFILE:
+      sess->rtp_profile = g_value_get_enum (value);
+      /* trigger reconsideration */
+      RTP_SESSION_LOCK (sess);
+      sess->next_rtcp_check_time = 0;
+      RTP_SESSION_UNLOCK (sess);
+      if (sess->callbacks.reconsider)
+        sess->callbacks.reconsider (sess, sess->reconsider_user_data);
+      break;
+    case PROP_RTCP_REDUCED_SIZE:
+      sess->reduced_size_rtcp = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+rtp_session_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  RTPSession *sess;
+
+  sess = RTP_SESSION (object);
+
+  switch (prop_id) {
+    case PROP_INTERNAL_SSRC:
+      g_value_set_uint (value, rtp_session_suggest_ssrc (sess, NULL));
+      break;
+    case PROP_INTERNAL_SOURCE:
+      /* FIXME, return a random source */
+      g_value_set_object (value, NULL);
+      break;
+    case PROP_BANDWIDTH:
+      g_value_set_double (value, sess->bandwidth);
+      break;
+    case PROP_RTCP_FRACTION:
+      g_value_set_double (value, sess->rtcp_bandwidth);
+      break;
+    case PROP_RTCP_RR_BANDWIDTH:
+      g_value_set_int (value, sess->rtcp_rr_bandwidth);
+      break;
+    case PROP_RTCP_RS_BANDWIDTH:
+      g_value_set_int (value, sess->rtcp_rs_bandwidth);
+      break;
+    case PROP_RTCP_MTU:
+      g_value_set_uint (value, sess->mtu);
+      break;
+    case PROP_SDES:
+      g_value_take_boxed (value, rtp_session_get_sdes_struct (sess));
+      break;
+    case PROP_NUM_SOURCES:
+      g_value_set_uint (value, rtp_session_get_num_sources (sess));
+      break;
+    case PROP_NUM_ACTIVE_SOURCES:
+      g_value_set_uint (value, rtp_session_get_num_active_sources (sess));
+      break;
+    case PROP_SOURCES:
+      g_value_take_boxed (value, rtp_session_create_sources (sess));
+      break;
+    case PROP_FAVOR_NEW:
+      g_value_set_boolean (value, sess->favor_new);
+      break;
+    case PROP_RTCP_MIN_INTERVAL:
+      g_value_set_uint64 (value, sess->stats.min_interval * GST_SECOND);
+      break;
+    case PROP_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD:
+      g_value_set_uint (value, sess->rtcp_immediate_feedback_threshold);
+      break;
+    case PROP_PROBATION:
+      g_value_set_uint (value, sess->probation);
+      break;
+    case PROP_MAX_DROPOUT_TIME:
+      g_value_set_uint (value, sess->max_dropout_time);
+      break;
+    case PROP_MAX_MISORDER_TIME:
+      g_value_set_uint (value, sess->max_misorder_time);
+      break;
+    case PROP_STATS:
+      g_value_take_boxed (value, rtp_session_create_stats (sess));
+      break;
+    case PROP_RTP_PROFILE:
+      g_value_set_enum (value, sess->rtp_profile);
+      break;
+    case PROP_RTCP_REDUCED_SIZE:
+      g_value_set_boolean (value, sess->reduced_size_rtcp);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+on_new_ssrc (RTPSession * sess, RTPSource * source)
+{
+  g_object_ref (source);
+  RTP_SESSION_UNLOCK (sess);
+  g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_NEW_SSRC], 0, source);
+  RTP_SESSION_LOCK (sess);
+  g_object_unref (source);
+}
+
+static void
+on_ssrc_collision (RTPSession * sess, RTPSource * source)
+{
+  g_object_ref (source);
+  RTP_SESSION_UNLOCK (sess);
+  g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_SSRC_COLLISION], 0,
+      source);
+  RTP_SESSION_LOCK (sess);
+  g_object_unref (source);
+}
+
+static void
+on_ssrc_validated (RTPSession * sess, RTPSource * source)
+{
+  g_object_ref (source);
+  RTP_SESSION_UNLOCK (sess);
+  g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_SSRC_VALIDATED], 0,
+      source);
+  RTP_SESSION_LOCK (sess);
+  g_object_unref (source);
+}
+
+static void
+on_ssrc_active (RTPSession * sess, RTPSource * source)
+{
+  g_object_ref (source);
+  RTP_SESSION_UNLOCK (sess);
+  g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_SSRC_ACTIVE], 0, source);
+  RTP_SESSION_LOCK (sess);
+  g_object_unref (source);
+}
+
+static void
+on_ssrc_sdes (RTPSession * sess, RTPSource * source)
+{
+  g_object_ref (source);
+  GST_DEBUG ("SDES changed for SSRC %08x", source->ssrc);
+  RTP_SESSION_UNLOCK (sess);
+  g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_SSRC_SDES], 0, source);
+  RTP_SESSION_LOCK (sess);
+  g_object_unref (source);
+}
+
+static void
+on_bye_ssrc (RTPSession * sess, RTPSource * source)
+{
+  g_object_ref (source);
+  RTP_SESSION_UNLOCK (sess);
+  g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_BYE_SSRC], 0, source);
+  RTP_SESSION_LOCK (sess);
+  g_object_unref (source);
+}
+
+static void
+on_bye_timeout (RTPSession * sess, RTPSource * source)
+{
+  g_object_ref (source);
+  RTP_SESSION_UNLOCK (sess);
+  g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_BYE_TIMEOUT], 0, source);
+  RTP_SESSION_LOCK (sess);
+  g_object_unref (source);
+}
+
+static void
+on_timeout (RTPSession * sess, RTPSource * source)
+{
+  g_object_ref (source);
+  RTP_SESSION_UNLOCK (sess);
+  g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_TIMEOUT], 0, source);
+  RTP_SESSION_LOCK (sess);
+  g_object_unref (source);
+}
+
+static void
+on_sender_timeout (RTPSession * sess, RTPSource * source)
+{
+  g_object_ref (source);
+  RTP_SESSION_UNLOCK (sess);
+  g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_SENDER_TIMEOUT], 0,
+      source);
+  RTP_SESSION_LOCK (sess);
+  g_object_unref (source);
+}
+
+static void
+on_new_sender_ssrc (RTPSession * sess, RTPSource * source)
+{
+  g_object_ref (source);
+  RTP_SESSION_UNLOCK (sess);
+  g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_NEW_SENDER_SSRC], 0,
+      source);
+  RTP_SESSION_LOCK (sess);
+  g_object_unref (source);
+}
+
+static void
+on_sender_ssrc_active (RTPSession * sess, RTPSource * source)
+{
+  g_object_ref (source);
+  RTP_SESSION_UNLOCK (sess);
+  g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_SENDER_SSRC_ACTIVE], 0,
+      source);
+  RTP_SESSION_LOCK (sess);
+  g_object_unref (source);
+}
+
+/**
+ * rtp_session_new:
+ *
+ * Create a new session object.
+ *
+ * Returns: a new #RTPSession. g_object_unref() after usage.
+ */
+RTPSession *
+rtp_session_new (void)
+{
+  RTPSession *sess;
+
+  sess = g_object_new (RTP_TYPE_SESSION, NULL);
+
+  return sess;
+}
+
+/**
+ * rtp_session_set_callbacks:
+ * @sess: an #RTPSession
+ * @callbacks: callbacks to configure
+ * @user_data: user data passed in the callbacks
+ *
+ * Configure a set of callbacks to be notified of actions.
+ */
+void
+rtp_session_set_callbacks (RTPSession * sess, RTPSessionCallbacks * callbacks,
+    gpointer user_data)
+{
+  g_return_if_fail (RTP_IS_SESSION (sess));
+
+  if (callbacks->process_rtp) {
+    sess->callbacks.process_rtp = callbacks->process_rtp;
+    sess->process_rtp_user_data = user_data;
+  }
+  if (callbacks->send_rtp) {
+    sess->callbacks.send_rtp = callbacks->send_rtp;
+    sess->send_rtp_user_data = user_data;
+  }
+  if (callbacks->send_rtcp) {
+    sess->callbacks.send_rtcp = callbacks->send_rtcp;
+    sess->send_rtcp_user_data = user_data;
+  }
+  if (callbacks->sync_rtcp) {
+    sess->callbacks.sync_rtcp = callbacks->sync_rtcp;
+    sess->sync_rtcp_user_data = user_data;
+  }
+  if (callbacks->clock_rate) {
+    sess->callbacks.clock_rate = callbacks->clock_rate;
+    sess->clock_rate_user_data = user_data;
+  }
+  if (callbacks->reconsider) {
+    sess->callbacks.reconsider = callbacks->reconsider;
+    sess->reconsider_user_data = user_data;
+  }
+  if (callbacks->request_key_unit) {
+    sess->callbacks.request_key_unit = callbacks->request_key_unit;
+    sess->request_key_unit_user_data = user_data;
+  }
+  if (callbacks->request_time) {
+    sess->callbacks.request_time = callbacks->request_time;
+    sess->request_time_user_data = user_data;
+  }
+  if (callbacks->notify_nack) {
+    sess->callbacks.notify_nack = callbacks->notify_nack;
+    sess->notify_nack_user_data = user_data;
+  }
+  if (callbacks->reconfigure) {
+    sess->callbacks.reconfigure = callbacks->reconfigure;
+    sess->reconfigure_user_data = user_data;
+  }
+}
+
+/**
+ * rtp_session_set_process_rtp_callback:
+ * @sess: an #RTPSession
+ * @callback: callback to set
+ * @user_data: user data passed in the callback
+ *
+ * Configure only the process_rtp callback to be notified of the process_rtp action.
+ */
+void
+rtp_session_set_process_rtp_callback (RTPSession * sess,
+    RTPSessionProcessRTP callback, gpointer user_data)
+{
+  g_return_if_fail (RTP_IS_SESSION (sess));
+
+  sess->callbacks.process_rtp = callback;
+  sess->process_rtp_user_data = user_data;
+}
+
+/**
+ * rtp_session_set_send_rtp_callback:
+ * @sess: an #RTPSession
+ * @callback: callback to set
+ * @user_data: user data passed in the callback
+ *
+ * Configure only the send_rtp callback to be notified of the send_rtp action.
+ */
+void
+rtp_session_set_send_rtp_callback (RTPSession * sess,
+    RTPSessionSendRTP callback, gpointer user_data)
+{
+  g_return_if_fail (RTP_IS_SESSION (sess));
+
+  sess->callbacks.send_rtp = callback;
+  sess->send_rtp_user_data = user_data;
+}
+
+/**
+ * rtp_session_set_send_rtcp_callback:
+ * @sess: an #RTPSession
+ * @callback: callback to set
+ * @user_data: user data passed in the callback
+ *
+ * Configure only the send_rtcp callback to be notified of the send_rtcp action.
+ */
+void
+rtp_session_set_send_rtcp_callback (RTPSession * sess,
+    RTPSessionSendRTCP callback, gpointer user_data)
+{
+  g_return_if_fail (RTP_IS_SESSION (sess));
+
+  sess->callbacks.send_rtcp = callback;
+  sess->send_rtcp_user_data = user_data;
+}
+
+/**
+ * rtp_session_set_sync_rtcp_callback:
+ * @sess: an #RTPSession
+ * @callback: callback to set
+ * @user_data: user data passed in the callback
+ *
+ * Configure only the sync_rtcp callback to be notified of the sync_rtcp action.
+ */
+void
+rtp_session_set_sync_rtcp_callback (RTPSession * sess,
+    RTPSessionSyncRTCP callback, gpointer user_data)
+{
+  g_return_if_fail (RTP_IS_SESSION (sess));
+
+  sess->callbacks.sync_rtcp = callback;
+  sess->sync_rtcp_user_data = user_data;
+}
+
+/**
+ * rtp_session_set_clock_rate_callback:
+ * @sess: an #RTPSession
+ * @callback: callback to set
+ * @user_data: user data passed in the callback
+ *
+ * Configure only the clock_rate callback to be notified of the clock_rate action.
+ */
+void
+rtp_session_set_clock_rate_callback (RTPSession * sess,
+    RTPSessionClockRate callback, gpointer user_data)
+{
+  g_return_if_fail (RTP_IS_SESSION (sess));
+
+  sess->callbacks.clock_rate = callback;
+  sess->clock_rate_user_data = user_data;
+}
+
+/**
+ * rtp_session_set_reconsider_callback:
+ * @sess: an #RTPSession
+ * @callback: callback to set
+ * @user_data: user data passed in the callback
+ *
+ * Configure only the reconsider callback to be notified of the reconsider action.
+ */
+void
+rtp_session_set_reconsider_callback (RTPSession * sess,
+    RTPSessionReconsider callback, gpointer user_data)
+{
+  g_return_if_fail (RTP_IS_SESSION (sess));
+
+  sess->callbacks.reconsider = callback;
+  sess->reconsider_user_data = user_data;
+}
+
+/**
+ * rtp_session_set_request_time_callback:
+ * @sess: an #RTPSession
+ * @callback: callback to set
+ * @user_data: user data passed in the callback
+ *
+ * Configure only the request_time callback
+ */
+void
+rtp_session_set_request_time_callback (RTPSession * sess,
+    RTPSessionRequestTime callback, gpointer user_data)
+{
+  g_return_if_fail (RTP_IS_SESSION (sess));
+
+  sess->callbacks.request_time = callback;
+  sess->request_time_user_data = user_data;
+}
+
+/**
+ * rtp_session_set_bandwidth:
+ * @sess: an #RTPSession
+ * @bandwidth: the bandwidth allocated
+ *
+ * Set the session bandwidth in bits per second.
+ */
+void
+rtp_session_set_bandwidth (RTPSession * sess, gdouble bandwidth)
+{
+  g_return_if_fail (RTP_IS_SESSION (sess));
+
+  RTP_SESSION_LOCK (sess);
+  sess->stats.bandwidth = bandwidth;
+  RTP_SESSION_UNLOCK (sess);
+}
+
+/**
+ * rtp_session_get_bandwidth:
+ * @sess: an #RTPSession
+ *
+ * Get the session bandwidth.
+ *
+ * Returns: the session bandwidth.
+ */
+gdouble
+rtp_session_get_bandwidth (RTPSession * sess)
+{
+  gdouble result;
+
+  g_return_val_if_fail (RTP_IS_SESSION (sess), 0);
+
+  RTP_SESSION_LOCK (sess);
+  result = sess->stats.bandwidth;
+  RTP_SESSION_UNLOCK (sess);
+
+  return result;
+}
+
+/**
+ * rtp_session_set_rtcp_fraction:
+ * @sess: an #RTPSession
+ * @bandwidth: the RTCP bandwidth
+ *
+ * Set the bandwidth in bits per second that should be used for RTCP
+ * messages.
+ */
+void
+rtp_session_set_rtcp_fraction (RTPSession * sess, gdouble bandwidth)
+{
+  g_return_if_fail (RTP_IS_SESSION (sess));
+
+  RTP_SESSION_LOCK (sess);
+  sess->stats.rtcp_bandwidth = bandwidth;
+  RTP_SESSION_UNLOCK (sess);
+}
+
+/**
+ * rtp_session_get_rtcp_fraction:
+ * @sess: an #RTPSession
+ *
+ * Get the session bandwidth used for RTCP.
+ *
+ * Returns: The bandwidth used for RTCP messages.
+ */
+gdouble
+rtp_session_get_rtcp_fraction (RTPSession * sess)
+{
+  gdouble result;
+
+  g_return_val_if_fail (RTP_IS_SESSION (sess), 0.0);
+
+  RTP_SESSION_LOCK (sess);
+  result = sess->stats.rtcp_bandwidth;
+  RTP_SESSION_UNLOCK (sess);
+
+  return result;
+}
+
+/**
+ * rtp_session_get_sdes_struct:
+ * @sess: an #RTSPSession
+ *
+ * Get the SDES data as a #GstStructure
+ *
+ * Returns: a GstStructure with SDES items for @sess. This function returns a
+ * copy of the SDES structure, use gst_structure_free() after usage.
+ */
+GstStructure *
+rtp_session_get_sdes_struct (RTPSession * sess)
+{
+  GstStructure *result = NULL;
+
+  g_return_val_if_fail (RTP_IS_SESSION (sess), NULL);
+
+  RTP_SESSION_LOCK (sess);
+  if (sess->sdes)
+    result = gst_structure_copy (sess->sdes);
+  RTP_SESSION_UNLOCK (sess);
+
+  return result;
+}
+
+/**
+ * rtp_session_set_sdes_struct:
+ * @sess: an #RTSPSession
+ * @sdes: a #GstStructure
+ *
+ * Set the SDES data as a #GstStructure. This function makes a copy of @sdes.
+ */
+void
+rtp_session_set_sdes_struct (RTPSession * sess, const GstStructure * sdes)
+{
+  g_return_if_fail (sdes);
+  g_return_if_fail (RTP_IS_SESSION (sess));
+
+  RTP_SESSION_LOCK (sess);
+  if (sess->sdes)
+    gst_structure_free (sess->sdes);
+  sess->sdes = gst_structure_copy (sdes);
+  RTP_SESSION_UNLOCK (sess);
+}
+
+static GstFlowReturn
+source_push_rtp (RTPSource * source, gpointer data, RTPSession * session)
+{
+  GstFlowReturn result = GST_FLOW_OK;
+
+  if (source->internal) {
+    GST_LOG ("source %08x pushed sender RTP packet", source->ssrc);
+
+    RTP_SESSION_UNLOCK (session);
+
+    if (session->callbacks.send_rtp)
+      result =
+          session->callbacks.send_rtp (session, source, data,
+          session->send_rtp_user_data);
+    else {
+      gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
+    }
+  } else {
+    GST_LOG ("source %08x pushed receiver RTP packet", source->ssrc);
+    RTP_SESSION_UNLOCK (session);
+
+    if (session->callbacks.process_rtp)
+      result =
+          session->callbacks.process_rtp (session, source,
+          GST_BUFFER_CAST (data), session->process_rtp_user_data);
+    else
+      gst_buffer_unref (GST_BUFFER_CAST (data));
+  }
+  RTP_SESSION_LOCK (session);
+
+  return result;
+}
+
+static gint
+source_clock_rate (RTPSource * source, guint8 pt, RTPSession * session)
+{
+  gint result;
+
+  RTP_SESSION_UNLOCK (session);
+
+  if (session->callbacks.clock_rate)
+    result =
+        session->callbacks.clock_rate (session, pt,
+        session->clock_rate_user_data);
+  else
+    result = -1;
+
+  RTP_SESSION_LOCK (session);
+
+  GST_DEBUG ("got clock-rate %d for pt %d", result, pt);
+
+  return result;
+}
+
+static RTPSourceCallbacks callbacks = {
+  (RTPSourcePushRTP) source_push_rtp,
+  (RTPSourceClockRate) source_clock_rate,
+};
+
+
+/**
+ * rtp_session_find_conflicting_address:
+ * @session: The session the packet came in
+ * @address: address to check for
+ * @time: The time when the packet that is possibly in conflict arrived
+ *
+ * Checks if an address which has a conflict is already known. If it is
+ * a known conflict, remember the time
+ *
+ * Returns: TRUE if it was a known conflict, FALSE otherwise
+ */
+static gboolean
+rtp_session_find_conflicting_address (RTPSession * session,
+    GSocketAddress * address, GstClockTime time)
+{
+  return find_conflicting_address (session->conflicting_addresses, address,
+      time);
+}
+
+/**
+ * rtp_session_add_conflicting_address:
+ * @session: The session the packet came in
+ * @address: address to remember
+ * @time: The time when the packet that is in conflict arrived
+ *
+ * Adds a new conflict address
+ */
+static void
+rtp_session_add_conflicting_address (RTPSession * sess,
+    GSocketAddress * address, GstClockTime time)
+{
+  sess->conflicting_addresses =
+      add_conflicting_address (sess->conflicting_addresses, address, time);
+}
+
+
+static gboolean
+check_collision (RTPSession * sess, RTPSource * source,
+    RTPPacketInfo * pinfo, gboolean rtp)
+{
+  guint32 ssrc;
+
+  /* If we have no pinfo address, we can't do collision checking */
+  if (!pinfo->address)
+    return FALSE;
+
+  ssrc = rtp_source_get_ssrc (source);
+
+  if (!source->internal) {
+    GSocketAddress *from;
+
+    /* This is not our local source, but lets check if two remote
+     * source collide */
+    if (rtp) {
+      from = source->rtp_from;
+    } else {
+      from = source->rtcp_from;
+    }
+
+    if (from) {
+      if (__g_socket_address_equal (from, pinfo->address)) {
+        /* Address is the same */
+        return FALSE;
+      } else {
+        GST_LOG ("we have a third-party collision or loop ssrc:%x", ssrc);
+        if (sess->favor_new) {
+          if (rtp_source_find_conflicting_address (source,
+                  pinfo->address, pinfo->current_time)) {
+            gchar *buf1;
+
+            buf1 = __g_socket_address_to_string (pinfo->address);
+            GST_LOG ("Known conflict on %x for %s, dropping packet", ssrc,
+                buf1);
+            g_free (buf1);
+
+            return TRUE;
+          } else {
+            gchar *buf1, *buf2;
+
+            /* Current address is not a known conflict, lets assume this is
+             * a new source. Save old address in possible conflict list
+             */
+            rtp_source_add_conflicting_address (source, from,
+                pinfo->current_time);
+
+            buf1 = __g_socket_address_to_string (from);
+            buf2 = __g_socket_address_to_string (pinfo->address);
+
+            GST_DEBUG ("New conflict for ssrc %x, replacing %s with %s,"
+                " saving old as known conflict", ssrc, buf1, buf2);
+
+            if (rtp)
+              rtp_source_set_rtp_from (source, pinfo->address);
+            else
+              rtp_source_set_rtcp_from (source, pinfo->address);
+
+            g_free (buf1);
+            g_free (buf2);
+
+            return FALSE;
+          }
+        } else {
+          /* Don't need to save old addresses, we ignore new sources */
+          return TRUE;
+        }
+      }
+    } else {
+      /* We don't already have a from address for RTP, just set it */
+      if (rtp)
+        rtp_source_set_rtp_from (source, pinfo->address);
+      else
+        rtp_source_set_rtcp_from (source, pinfo->address);
+      return FALSE;
+    }
+
+    /* FIXME: Log 3rd party collision somehow
+     * Maybe should be done in upper layer, only the SDES can tell us
+     * if its a collision or a loop
+     */
+  } else {
+    /* This is sending with our ssrc, is it an address we already know */
+    if (rtp_session_find_conflicting_address (sess, pinfo->address,
+            pinfo->current_time)) {
+      /* Its a known conflict, its probably a loop, not a collision
+       * lets just drop the incoming packet
+       */
+      GST_DEBUG ("Our packets are being looped back to us, dropping");
+    } else {
+      /* Its a new collision, lets change our SSRC */
+      rtp_session_add_conflicting_address (sess, pinfo->address,
+          pinfo->current_time);
+
+      GST_DEBUG ("Collision for SSRC %x", ssrc);
+      /* mark the source BYE */
+      rtp_source_mark_bye (source, "SSRC Collision");
+      /* if we were suggesting this SSRC, change to something else */
+      if (sess->suggested_ssrc == ssrc) {
+        sess->suggested_ssrc = rtp_session_create_new_ssrc (sess);
+        sess->internal_ssrc_set = TRUE;
+      }
+
+      on_ssrc_collision (sess, source);
+
+      rtp_session_schedule_bye_locked (sess, pinfo->current_time);
+    }
+  }
+
+  return TRUE;
+}
+
+typedef struct
+{
+  gboolean is_doing_ptp;
+  GSocketAddress *new_addr;
+} CompareAddrData;
+
+/* check if the two given ip addr are the same (do not care about the port) */
+static gboolean
+ip_addr_equal (GSocketAddress * a, GSocketAddress * b)
+{
+  return
+      g_inet_address_equal (g_inet_socket_address_get_address
+      (G_INET_SOCKET_ADDRESS (a)),
+      g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (b)));
+}
+
+static void
+compare_rtp_source_addr (const gchar * key, RTPSource * source,
+    CompareAddrData * data)
+{
+  /* only compare ip addr of remote sources which are also not closing */
+  if (!source->internal && !source->closing && source->rtp_from) {
+    /* look for the first rtp source */
+    if (!data->new_addr)
+      data->new_addr = source->rtp_from;
+    /* compare current ip addr with the first one */
+    else
+      data->is_doing_ptp &= ip_addr_equal (data->new_addr, source->rtp_from);
+  }
+}
+
+static void
+compare_rtcp_source_addr (const gchar * key, RTPSource * source,
+    CompareAddrData * data)
+{
+  /* only compare ip addr of remote sources which are also not closing */
+  if (!source->internal && !source->closing && source->rtcp_from) {
+    /* look for the first rtcp source */
+    if (!data->new_addr)
+      data->new_addr = source->rtcp_from;
+    else
+      /* compare current ip addr with the first one */
+      data->is_doing_ptp &= ip_addr_equal (data->new_addr, source->rtcp_from);
+  }
+}
+
+/* loop over our non-internal source to know if the session
+ * is doing point-to-point */
+static void
+session_update_ptp (RTPSession * sess)
+{
+  /* to know if the session is doing point to point, the ip addr
+   * of each non-internal (=remotes) source have to be compared
+   * to each other.
+   */
+  gboolean is_doing_rtp_ptp;
+  gboolean is_doing_rtcp_ptp;
+  CompareAddrData data;
+
+  /* compare the first remote source's ip addr that receive rtp packets
+   * with other remote rtp source.
+   * it's enough because the session just needs to know if they are all
+   * equals or not
+   */
+  data.is_doing_ptp = TRUE;
+  data.new_addr = NULL;
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+      (GHFunc) compare_rtp_source_addr, (gpointer) & data);
+  is_doing_rtp_ptp = data.is_doing_ptp;
+
+  /* same but about rtcp */
+  data.is_doing_ptp = TRUE;
+  data.new_addr = NULL;
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+      (GHFunc) compare_rtcp_source_addr, (gpointer) & data);
+  is_doing_rtcp_ptp = data.is_doing_ptp;
+
+  /* the session is doing point-to-point if all rtp remote have the same
+   * ip addr and if all rtcp remote sources have the same ip addr */
+  sess->is_doing_ptp = is_doing_rtp_ptp && is_doing_rtcp_ptp;
+
+  GST_DEBUG ("doing point-to-point: %d", sess->is_doing_ptp);
+}
+
+static void
+add_source (RTPSession * sess, RTPSource * src)
+{
+  g_hash_table_insert (sess->ssrcs[sess->mask_idx],
+      GINT_TO_POINTER (src->ssrc), src);
+  /* report the new source ASAP */
+  src->generation = sess->generation;
+  /* we have one more source now */
+  sess->total_sources++;
+  if (RTP_SOURCE_IS_ACTIVE (src))
+    sess->stats.active_sources++;
+  if (src->internal) {
+    sess->stats.internal_sources++;
+    if (!sess->internal_ssrc_from_caps_or_property
+        && sess->suggested_ssrc != src->ssrc) {
+      sess->suggested_ssrc = src->ssrc;
+      sess->internal_ssrc_set = TRUE;
+    }
+  }
+
+  /* update point-to-point status */
+  if (!src->internal)
+    session_update_ptp (sess);
+}
+
+static RTPSource *
+find_source (RTPSession * sess, guint32 ssrc)
+{
+  return g_hash_table_lookup (sess->ssrcs[sess->mask_idx],
+      GINT_TO_POINTER (ssrc));
+}
+
+/* must be called with the session lock, the returned source needs to be
+ * unreffed after usage. */
+static RTPSource *
+obtain_source (RTPSession * sess, guint32 ssrc, gboolean * created,
+    RTPPacketInfo * pinfo, gboolean rtp)
+{
+  RTPSource *source;
+
+  source = find_source (sess, ssrc);
+  if (source == NULL) {
+    /* make new Source in probation and insert */
+    source = rtp_source_new (ssrc);
+
+    GST_DEBUG ("creating new source %08x %p", ssrc, source);
+
+    /* for RTP packets we need to set the source in probation. Receiving RTCP
+     * packets of an SSRC, on the other hand, is a strong indication that we
+     * are dealing with a valid source. */
+    g_object_set (source, "probation", rtp ? sess->probation : 0,
+        "max-dropout-time", sess->max_dropout_time, "max-misorder-time",
+        sess->max_misorder_time, NULL);
+
+    /* store from address, if any */
+    if (pinfo->address) {
+      if (rtp)
+        rtp_source_set_rtp_from (source, pinfo->address);
+      else
+        rtp_source_set_rtcp_from (source, pinfo->address);
+    }
+
+    /* configure a callback on the source */
+    rtp_source_set_callbacks (source, &callbacks, sess);
+
+    add_source (sess, source);
+    *created = TRUE;
+  } else {
+    *created = FALSE;
+    /* check for collision, this updates the address when not previously set */
+    if (check_collision (sess, source, pinfo, rtp)) {
+      return NULL;
+    }
+    /* Receiving RTCP packets of an SSRC is a strong indication that we
+     * are dealing with a valid source. */
+    if (!rtp)
+      g_object_set (source, "probation", 0, NULL);
+  }
+  /* update last activity */
+  source->last_activity = pinfo->current_time;
+  if (rtp)
+    source->last_rtp_activity = pinfo->current_time;
+  g_object_ref (source);
+
+  return source;
+}
+
+/* must be called with the session lock, the returned source needs to be
+ * unreffed after usage. */
+static RTPSource *
+obtain_internal_source (RTPSession * sess, guint32 ssrc, gboolean * created,
+    GstClockTime current_time)
+{
+  RTPSource *source;
+
+  source = find_source (sess, ssrc);
+  if (source == NULL) {
+    /* make new internal Source and insert */
+    source = rtp_source_new (ssrc);
+
+    GST_DEBUG ("creating new internal source %08x %p", ssrc, source);
+
+    source->validated = TRUE;
+    source->internal = TRUE;
+    source->probation = FALSE;
+    rtp_source_set_sdes_struct (source, gst_structure_copy (sess->sdes));
+    rtp_source_set_callbacks (source, &callbacks, sess);
+
+    add_source (sess, source);
+    *created = TRUE;
+  } else {
+    *created = FALSE;
+  }
+  /* update last activity */
+  if (current_time != GST_CLOCK_TIME_NONE) {
+    source->last_activity = current_time;
+    source->last_rtp_activity = current_time;
+  }
+  g_object_ref (source);
+
+  return source;
+}
+
+/**
+ * rtp_session_suggest_ssrc:
+ * @sess: a #RTPSession
+ * @is_random: if the suggested ssrc is random
+ *
+ * Suggest an unused SSRC in @sess.
+ *
+ * Returns: a free unused SSRC
+ */
+guint32
+rtp_session_suggest_ssrc (RTPSession * sess, gboolean * is_random)
+{
+  guint32 result;
+
+  g_return_val_if_fail (RTP_IS_SESSION (sess), 0);
+
+  RTP_SESSION_LOCK (sess);
+  result = sess->suggested_ssrc;
+  if (is_random)
+    *is_random = !sess->internal_ssrc_set;
+  RTP_SESSION_UNLOCK (sess);
+
+  return result;
+}
+
+/**
+ * rtp_session_add_source:
+ * @sess: a #RTPSession
+ * @src: #RTPSource to add
+ *
+ * Add @src to @session.
+ *
+ * Returns: %TRUE on success, %FALSE if a source with the same SSRC already
+ * existed in the session.
+ */
+gboolean
+rtp_session_add_source (RTPSession * sess, RTPSource * src)
+{
+  gboolean result = FALSE;
+  RTPSource *find;
+
+  g_return_val_if_fail (RTP_IS_SESSION (sess), FALSE);
+  g_return_val_if_fail (src != NULL, FALSE);
+
+  RTP_SESSION_LOCK (sess);
+  find = find_source (sess, src->ssrc);
+  if (find == NULL) {
+    add_source (sess, src);
+    result = TRUE;
+  }
+  RTP_SESSION_UNLOCK (sess);
+
+  return result;
+}
+
+/**
+ * rtp_session_get_num_sources:
+ * @sess: an #RTPSession
+ *
+ * Get the number of sources in @sess.
+ *
+ * Returns: The number of sources in @sess.
+ */
+guint
+rtp_session_get_num_sources (RTPSession * sess)
+{
+  guint result;
+
+  g_return_val_if_fail (RTP_IS_SESSION (sess), FALSE);
+
+  RTP_SESSION_LOCK (sess);
+  result = sess->total_sources;
+  RTP_SESSION_UNLOCK (sess);
+
+  return result;
+}
+
+/**
+ * rtp_session_get_num_active_sources:
+ * @sess: an #RTPSession
+ *
+ * Get the number of active sources in @sess. A source is considered active when
+ * it has been validated and has not yet received a BYE RTCP message.
+ *
+ * Returns: The number of active sources in @sess.
+ */
+guint
+rtp_session_get_num_active_sources (RTPSession * sess)
+{
+  guint result;
+
+  g_return_val_if_fail (RTP_IS_SESSION (sess), 0);
+
+  RTP_SESSION_LOCK (sess);
+  result = sess->stats.active_sources;
+  RTP_SESSION_UNLOCK (sess);
+
+  return result;
+}
+
+/**
+ * rtp_session_get_source_by_ssrc:
+ * @sess: an #RTPSession
+ * @ssrc: an SSRC
+ *
+ * Find the source with @ssrc in @sess.
+ *
+ * Returns: a #RTPSource with SSRC @ssrc or NULL if the source was not found.
+ * g_object_unref() after usage.
+ */
+RTPSource *
+rtp_session_get_source_by_ssrc (RTPSession * sess, guint32 ssrc)
+{
+  RTPSource *result;
+
+  g_return_val_if_fail (RTP_IS_SESSION (sess), NULL);
+
+  RTP_SESSION_LOCK (sess);
+  result = find_source (sess, ssrc);
+  if (result != NULL)
+    g_object_ref (result);
+  RTP_SESSION_UNLOCK (sess);
+
+  return result;
+}
+
+/* should be called with the SESSION lock */
+static guint32
+rtp_session_create_new_ssrc (RTPSession * sess)
+{
+  guint32 ssrc;
+
+  while (TRUE) {
+    ssrc = g_random_int ();
+
+    /* see if it exists in the session, we're done if it doesn't */
+    if (find_source (sess, ssrc) == NULL)
+      break;
+  }
+  return ssrc;
+}
+
+
+/**
+ * rtp_session_create_source:
+ * @sess: an #RTPSession
+ *
+ * Create an #RTPSource for use in @sess. This function will create a source
+ * with an ssrc that is currently not used by any participants in the session.
+ *
+ * Returns: an #RTPSource.
+ */
+RTPSource *
+rtp_session_create_source (RTPSession * sess)
+{
+  guint32 ssrc;
+  RTPSource *source;
+
+  RTP_SESSION_LOCK (sess);
+  ssrc = rtp_session_create_new_ssrc (sess);
+  source = rtp_source_new (ssrc);
+  rtp_source_set_callbacks (source, &callbacks, sess);
+  /* we need an additional ref for the source in the hashtable */
+  g_object_ref (source);
+  add_source (sess, source);
+  RTP_SESSION_UNLOCK (sess);
+
+  return source;
+}
+
+static gboolean
+update_packet (GstBuffer ** buffer, guint idx, RTPPacketInfo * pinfo)
+{
+  GstNetAddressMeta *meta;
+
+  /* get packet size including header overhead */
+  pinfo->bytes += gst_buffer_get_size (*buffer) + pinfo->header_len;
+  pinfo->packets++;
+
+  if (pinfo->rtp) {
+    GstRTPBuffer rtp = { NULL };
+
+    if (!gst_rtp_buffer_map (*buffer, GST_MAP_READ, &rtp))
+      goto invalid_packet;
+
+    pinfo->payload_len += gst_rtp_buffer_get_payload_len (&rtp);
+    if (idx == 0) {
+      gint i;
+
+      /* only keep info for first buffer */
+      pinfo->ssrc = gst_rtp_buffer_get_ssrc (&rtp);
+      pinfo->seqnum = gst_rtp_buffer_get_seq (&rtp);
+      pinfo->pt = gst_rtp_buffer_get_payload_type (&rtp);
+      pinfo->rtptime = gst_rtp_buffer_get_timestamp (&rtp);
+      /* copy available csrc */
+      pinfo->csrc_count = gst_rtp_buffer_get_csrc_count (&rtp);
+      for (i = 0; i < pinfo->csrc_count; i++)
+        pinfo->csrcs[i] = gst_rtp_buffer_get_csrc (&rtp, i);
+    }
+    gst_rtp_buffer_unmap (&rtp);
+  }
+
+  if (idx == 0) {
+    /* for netbuffer we can store the IP address to check for collisions */
+    meta = gst_buffer_get_net_address_meta (*buffer);
+    if (pinfo->address)
+      g_object_unref (pinfo->address);
+    if (meta) {
+      pinfo->address = G_SOCKET_ADDRESS (g_object_ref (meta->addr));
+    } else {
+      pinfo->address = NULL;
+    }
+  }
+  return TRUE;
+
+  /* ERRORS */
+invalid_packet:
+  {
+    GST_DEBUG ("invalid RTP packet received");
+    return FALSE;
+  }
+}
+
+/* update the RTPPacketInfo structure with the current time and other bits
+ * about the current buffer we are handling.
+ * This function is typically called when a validated packet is received.
+ * This function should be called with the SESSION_LOCK
+ */
+static gboolean
+update_packet_info (RTPSession * sess, RTPPacketInfo * pinfo,
+    gboolean send, gboolean rtp, gboolean is_list, gpointer data,
+    GstClockTime current_time, GstClockTime running_time, guint64 ntpnstime)
+{
+  gboolean res;
+
+  pinfo->send = send;
+  pinfo->rtp = rtp;
+  pinfo->is_list = is_list;
+  pinfo->data = data;
+  pinfo->current_time = current_time;
+  pinfo->running_time = running_time;
+  pinfo->ntpnstime = ntpnstime;
+  pinfo->header_len = sess->header_len;
+  pinfo->bytes = 0;
+  pinfo->payload_len = 0;
+  pinfo->packets = 0;
+
+  if (is_list) {
+    GstBufferList *list = GST_BUFFER_LIST_CAST (data);
+    res =
+        gst_buffer_list_foreach (list, (GstBufferListFunc) update_packet,
+        pinfo);
+  } else {
+    GstBuffer *buffer = GST_BUFFER_CAST (data);
+    res = update_packet (&buffer, 0, pinfo);
+  }
+  return res;
+}
+
+static void
+clean_packet_info (RTPPacketInfo * pinfo)
+{
+  if (pinfo->address)
+    g_object_unref (pinfo->address);
+  if (pinfo->data) {
+    gst_mini_object_unref (pinfo->data);
+    pinfo->data = NULL;
+  }
+}
+
+static gboolean
+source_update_active (RTPSession * sess, RTPSource * source,
+    gboolean prevactive)
+{
+  gboolean active = RTP_SOURCE_IS_ACTIVE (source);
+  guint32 ssrc = source->ssrc;
+
+  if (prevactive == active)
+    return FALSE;
+
+  if (active) {
+    sess->stats.active_sources++;
+    GST_DEBUG ("source: %08x became active, %d active sources", ssrc,
+        sess->stats.active_sources);
+  } else {
+    sess->stats.active_sources--;
+    GST_DEBUG ("source: %08x became inactive, %d active sources", ssrc,
+        sess->stats.active_sources);
+  }
+  return TRUE;
+}
+
+static gboolean
+source_update_sender (RTPSession * sess, RTPSource * source,
+    gboolean prevsender)
+{
+  gboolean sender = RTP_SOURCE_IS_SENDER (source);
+  guint32 ssrc = source->ssrc;
+
+  if (prevsender == sender)
+    return FALSE;
+
+  if (sender) {
+    sess->stats.sender_sources++;
+    if (source->internal)
+      sess->stats.internal_sender_sources++;
+    GST_DEBUG ("source: %08x became sender, %d sender sources", ssrc,
+        sess->stats.sender_sources);
+  } else {
+    sess->stats.sender_sources--;
+    if (source->internal)
+      sess->stats.internal_sender_sources--;
+    GST_DEBUG ("source: %08x became non sender, %d sender sources", ssrc,
+        sess->stats.sender_sources);
+  }
+  return TRUE;
+}
+
+/**
+ * rtp_session_process_rtp:
+ * @sess: and #RTPSession
+ * @buffer: an RTP buffer
+ * @current_time: the current system time
+ * @running_time: the running_time of @buffer
+ *
+ * Process an RTP buffer in the session manager. This function takes ownership
+ * of @buffer.
+ *
+ * Returns: a #GstFlowReturn.
+ */
+GstFlowReturn
+rtp_session_process_rtp (RTPSession * sess, GstBuffer * buffer,
+    GstClockTime current_time, GstClockTime running_time, guint64 ntpnstime)
+{
+  GstFlowReturn result;
+  guint32 ssrc;
+  RTPSource *source;
+  gboolean created;
+  gboolean prevsender, prevactive;
+  RTPPacketInfo pinfo = { 0, };
+  guint64 oldrate;
+
+  g_return_val_if_fail (RTP_IS_SESSION (sess), GST_FLOW_ERROR);
+  g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
+
+  RTP_SESSION_LOCK (sess);
+
+  /* update pinfo stats */
+  if (!update_packet_info (sess, &pinfo, FALSE, TRUE, FALSE, buffer,
+          current_time, running_time, ntpnstime)) {
+    GST_DEBUG ("invalid RTP packet received");
+    RTP_SESSION_UNLOCK (sess);
+    return rtp_session_process_rtcp (sess, buffer, current_time, ntpnstime);
+  }
+
+  ssrc = pinfo.ssrc;
+
+  source = obtain_source (sess, ssrc, &created, &pinfo, TRUE);
+  if (!source)
+    goto collision;
+
+  prevsender = RTP_SOURCE_IS_SENDER (source);
+  prevactive = RTP_SOURCE_IS_ACTIVE (source);
+  oldrate = source->bitrate;
+
+  /* let source process the packet */
+  result = rtp_source_process_rtp (source, &pinfo);
+
+  /* source became active */
+  if (source_update_active (sess, source, prevactive))
+    on_ssrc_validated (sess, source);
+
+  source_update_sender (sess, source, prevsender);
+
+  if (oldrate != source->bitrate)
+    sess->recalc_bandwidth = TRUE;
+
+  if (created)
+    on_new_ssrc (sess, source);
+
+  if (source->validated) {
+    gboolean created;
+    gint i;
+
+    /* for validated sources, we add the CSRCs as well */
+    for (i = 0; i < pinfo.csrc_count; i++) {
+      guint32 csrc;
+      RTPSource *csrc_src;
+
+      csrc = pinfo.csrcs[i];
+
+      /* get source */
+      csrc_src = obtain_source (sess, csrc, &created, &pinfo, TRUE);
+      if (!csrc_src)
+        continue;
+
+      if (created) {
+        GST_DEBUG ("created new CSRC: %08x", csrc);
+        rtp_source_set_as_csrc (csrc_src);
+        source_update_active (sess, csrc_src, FALSE);
+        on_new_ssrc (sess, csrc_src);
+      }
+      g_object_unref (csrc_src);
+    }
+  }
+  g_object_unref (source);
+
+  RTP_SESSION_UNLOCK (sess);
+
+  clean_packet_info (&pinfo);
+
+  return result;
+
+  /* ERRORS */
+collision:
+  {
+    RTP_SESSION_UNLOCK (sess);
+    clean_packet_info (&pinfo);
+    GST_DEBUG ("ignoring packet because its collisioning");
+    return GST_FLOW_OK;
+  }
+}
+
+static void
+rtp_session_process_rb (RTPSession * sess, RTPSource * source,
+    GstRTCPPacket * packet, RTPPacketInfo * pinfo)
+{
+  guint count, i;
+
+  count = gst_rtcp_packet_get_rb_count (packet);
+  for (i = 0; i < count; i++) {
+    guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
+    guint8 fractionlost;
+    gint32 packetslost;
+    RTPSource *src;
+
+    gst_rtcp_packet_get_rb (packet, i, &ssrc, &fractionlost,
+        &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
+
+    GST_DEBUG ("RB %d: SSRC %08x, jitter %" G_GUINT32_FORMAT, i, ssrc, jitter);
+
+    /* find our own source */
+    src = find_source (sess, ssrc);
+    if (src == NULL)
+      continue;
+
+    if (src->internal && RTP_SOURCE_IS_ACTIVE (src)) {
+      /* only deal with report blocks for our session, we update the stats of
+       * the sender of the RTCP message. We could also compare our stats against
+       * the other sender to see if we are better or worse. */
+      /* FIXME, need to keep track who the RB block is from */
+      rtp_source_process_rb (source, pinfo->ntpnstime, fractionlost,
+          packetslost, exthighestseq, jitter, lsr, dlsr);
+    }
+  }
+  on_ssrc_active (sess, source);
+}
+
+/* A Sender report contains statistics about how the sender is doing. This
+ * includes timing informataion such as the relation between RTP and NTP
+ * timestamps and the number of packets/bytes it sent to us.
+ *
+ * In this report is also included a set of report blocks related to how this
+ * sender is receiving data (in case we (or somebody else) is also sending stuff
+ * to it). This info includes the packet loss, jitter and seqnum. It also
+ * contains information to calculate the round trip time (LSR/DLSR).
+ */
+static void
+rtp_session_process_sr (RTPSession * sess, GstRTCPPacket * packet,
+    RTPPacketInfo * pinfo, gboolean * do_sync)
+{
+  guint32 senderssrc, rtptime, packet_count, octet_count;
+  guint64 ntptime;
+  RTPSource *source;
+  gboolean created, prevsender;
+
+  gst_rtcp_packet_sr_get_sender_info (packet, &senderssrc, &ntptime, &rtptime,
+      &packet_count, &octet_count);
+
+  GST_DEBUG ("got SR packet: SSRC %08x, time %" GST_TIME_FORMAT,
+      senderssrc, GST_TIME_ARGS (pinfo->current_time));
+
+  source = obtain_source (sess, senderssrc, &created, pinfo, FALSE);
+  if (!source)
+    return;
+
+  /* skip non-bye packets for sources that are marked BYE */
+  if (sess->scheduled_bye && RTP_SOURCE_IS_MARKED_BYE (source))
+    goto out;
+
+  /* don't try to do lip-sync for sources that sent a BYE */
+  if (RTP_SOURCE_IS_MARKED_BYE (source))
+    *do_sync = FALSE;
+  else
+    *do_sync = TRUE;
+
+  prevsender = RTP_SOURCE_IS_SENDER (source);
+
+  /* first update the source */
+  rtp_source_process_sr (source, pinfo->current_time, ntptime, rtptime,
+      packet_count, octet_count);
+
+  source_update_sender (sess, source, prevsender);
+
+  if (created)
+    on_new_ssrc (sess, source);
+
+  rtp_session_process_rb (sess, source, packet, pinfo);
+
+out:
+  g_object_unref (source);
+}
+
+/* A receiver report contains statistics about how a receiver is doing. It
+ * includes stuff like packet loss, jitter and the seqnum it received last. It
+ * also contains info to calculate the round trip time.
+ *
+ * We are only interested in how the sender of this report is doing wrt to us.
+ */
+static void
+rtp_session_process_rr (RTPSession * sess, GstRTCPPacket * packet,
+    RTPPacketInfo * pinfo)
+{
+  guint32 senderssrc;
+  RTPSource *source;
+  gboolean created;
+
+  senderssrc = gst_rtcp_packet_rr_get_ssrc (packet);
+
+  GST_DEBUG ("got RR packet: SSRC %08x", senderssrc);
+
+  source = obtain_source (sess, senderssrc, &created, pinfo, FALSE);
+  if (!source)
+    return;
+
+  /* skip non-bye packets for sources that are marked BYE */
+  if (sess->scheduled_bye && RTP_SOURCE_IS_MARKED_BYE (source))
+    goto out;
+
+  if (created)
+    on_new_ssrc (sess, source);
+
+  rtp_session_process_rb (sess, source, packet, pinfo);
+
+out:
+  g_object_unref (source);
+}
+
+/* Get SDES items and store them in the SSRC */
+static void
+rtp_session_process_sdes (RTPSession * sess, GstRTCPPacket * packet,
+    RTPPacketInfo * pinfo)
+{
+  guint items, i, j;
+  gboolean more_items, more_entries;
+
+  items = gst_rtcp_packet_sdes_get_item_count (packet);
+  GST_DEBUG ("got SDES packet with %d items", items);
+
+  more_items = gst_rtcp_packet_sdes_first_item (packet);
+  i = 0;
+  while (more_items) {
+    guint32 ssrc;
+    gboolean changed, created, prevactive;
+    RTPSource *source;
+    GstStructure *sdes;
+
+    ssrc = gst_rtcp_packet_sdes_get_ssrc (packet);
+
+    GST_DEBUG ("item %d, SSRC %08x", i, ssrc);
+
+    changed = FALSE;
+
+    /* find src, no probation when dealing with RTCP */
+    source = obtain_source (sess, ssrc, &created, pinfo, FALSE);
+    if (!source)
+      return;
+
+    /* skip non-bye packets for sources that are marked BYE */
+    if (sess->scheduled_bye && RTP_SOURCE_IS_MARKED_BYE (source))
+      goto next;
+
+    sdes = gst_structure_new_empty ("application/x-rtp-source-sdes");
+
+    more_entries = gst_rtcp_packet_sdes_first_entry (packet);
+    j = 0;
+    while (more_entries) {
+      GstRTCPSDESType type;
+      guint8 len;
+      guint8 *data;
+      gchar *name;
+      gchar *value;
+
+      gst_rtcp_packet_sdes_get_entry (packet, &type, &len, &data);
+
+      GST_DEBUG ("entry %d, type %d, len %d, data %.*s", j, type, len, len,
+          data);
+
+      if (type == GST_RTCP_SDES_PRIV) {
+        name = g_strndup ((const gchar *) &data[1], data[0]);
+        len -= data[0] + 1;
+        data += data[0] + 1;
+      } else {
+        name = g_strdup (gst_rtcp_sdes_type_to_name (type));
+      }
+
+      value = g_strndup ((const gchar *) data, len);
+
+      if (g_utf8_validate (value, -1, NULL)) {
+        gst_structure_set (sdes, name, G_TYPE_STRING, value, NULL);
+      } else {
+        GST_WARNING ("ignore SDES field %s with non-utf8 data %s", name, value);
+      }
+
+      g_free (name);
+      g_free (value);
+
+      more_entries = gst_rtcp_packet_sdes_next_entry (packet);
+      j++;
+    }
+
+    /* takes ownership of sdes */
+    changed = rtp_source_set_sdes_struct (source, sdes);
+
+    prevactive = RTP_SOURCE_IS_ACTIVE (source);
+    source->validated = TRUE;
+
+    if (created)
+      on_new_ssrc (sess, source);
+
+    /* source became active */
+    if (source_update_active (sess, source, prevactive))
+      on_ssrc_validated (sess, source);
+
+    if (changed)
+      on_ssrc_sdes (sess, source);
+
+  next:
+    g_object_unref (source);
+
+    more_items = gst_rtcp_packet_sdes_next_item (packet);
+    i++;
+  }
+}
+
+/* BYE is sent when a client leaves the session
+ */
+static void
+rtp_session_process_bye (RTPSession * sess, GstRTCPPacket * packet,
+    RTPPacketInfo * pinfo)
+{
+  guint count, i;
+  gchar *reason;
+  gboolean reconsider = FALSE;
+
+  reason = gst_rtcp_packet_bye_get_reason (packet);
+  GST_DEBUG ("got BYE packet (reason: %s)", GST_STR_NULL (reason));
+
+  count = gst_rtcp_packet_bye_get_ssrc_count (packet);
+  for (i = 0; i < count; i++) {
+    guint32 ssrc;
+    RTPSource *source;
+    gboolean prevactive, prevsender;
+    guint pmembers, members;
+
+    ssrc = gst_rtcp_packet_bye_get_nth_ssrc (packet, i);
+    GST_DEBUG ("SSRC: %08x", ssrc);
+
+    /* find src and mark bye, no probation when dealing with RTCP */
+    source = find_source (sess, ssrc);
+    if (!source || source->internal) {
+      GST_DEBUG ("Ignoring suspicious BYE packet (reason: %s)",
+          !source ? "can't find source" : "has internal source SSRC");
+      break;
+    }
+
+    /* store time for when we need to time out this source */
+    source->bye_time = pinfo->current_time;
+
+    prevactive = RTP_SOURCE_IS_ACTIVE (source);
+    prevsender = RTP_SOURCE_IS_SENDER (source);
+
+    /* mark the source BYE */
+    rtp_source_mark_bye (source, reason);
+
+    pmembers = sess->stats.active_sources;
+
+    source_update_active (sess, source, prevactive);
+    source_update_sender (sess, source, prevsender);
+
+    members = sess->stats.active_sources;
+
+    if (!sess->scheduled_bye && members < pmembers) {
+      /* some members went away since the previous timeout estimate.
+       * Perform reverse reconsideration but only when we are not scheduling a
+       * BYE ourselves. */
+      if (sess->next_rtcp_check_time != GST_CLOCK_TIME_NONE &&
+          pinfo->current_time < sess->next_rtcp_check_time) {
+        GstClockTime time_remaining;
+
+        /* Scale our next RTCP check time according to the change of numbers
+         * of members. But only if a) this is the first RTCP, or b) this is not
+         * a feedback session, or c) this is a feedback session but we schedule
+         * for every RTCP interval (aka no t-rr-interval set).
+         *
+         * FIXME: a) and b) are not great as we will possibly go below Tmin
+         * for non-feedback profiles and in case of a) below
+         * Tmin/t-rr-interval in any case.
+         */
+        if (sess->last_rtcp_send_time == GST_CLOCK_TIME_NONE ||
+            !(sess->rtp_profile == GST_RTP_PROFILE_AVPF
+                || sess->rtp_profile == GST_RTP_PROFILE_SAVPF) ||
+            sess->next_rtcp_check_time - sess->last_rtcp_send_time ==
+            sess->last_rtcp_interval) {
+          time_remaining = sess->next_rtcp_check_time - pinfo->current_time;
+          sess->next_rtcp_check_time =
+              gst_util_uint64_scale (time_remaining, members, pmembers);
+          sess->next_rtcp_check_time += pinfo->current_time;
+        }
+        sess->last_rtcp_interval =
+            gst_util_uint64_scale (sess->last_rtcp_interval, members, pmembers);
+
+        GST_DEBUG ("reverse reconsideration %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (sess->next_rtcp_check_time));
+
+        /* mark pending reconsider. We only want to signal the reconsideration
+         * once after we handled all the source in the bye packet */
+        reconsider = TRUE;
+      }
+    }
+
+    on_bye_ssrc (sess, source);
+  }
+  if (reconsider) {
+    RTP_SESSION_UNLOCK (sess);
+    /* notify app of reconsideration */
+    if (sess->callbacks.reconsider)
+      sess->callbacks.reconsider (sess, sess->reconsider_user_data);
+    RTP_SESSION_LOCK (sess);
+  }
+
+  g_free (reason);
+}
+
+static void
+rtp_session_process_app (RTPSession * sess, GstRTCPPacket * packet,
+    RTPPacketInfo * pinfo)
+{
+  GST_DEBUG ("received APP");
+
+  if (g_signal_has_handler_pending (sess,
+          rtp_session_signals[SIGNAL_ON_APP_RTCP], 0, TRUE)) {
+    GstBuffer *data_buffer = NULL;
+    guint16 data_length;
+    gchar name[5];
+
+    data_length = gst_rtcp_packet_app_get_data_length (packet) * 4;
+    if (data_length > 0) {
+      guint8 *data = gst_rtcp_packet_app_get_data (packet);
+      data_buffer = gst_buffer_copy_region (packet->rtcp->buffer,
+          GST_BUFFER_COPY_MEMORY, data - packet->rtcp->map.data, data_length);
+      GST_BUFFER_PTS (data_buffer) = pinfo->running_time;
+    }
+
+    memcpy (name, gst_rtcp_packet_app_get_name (packet), 4);
+    name[4] = '\0';
+
+    RTP_SESSION_UNLOCK (sess);
+    g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_APP_RTCP], 0,
+        gst_rtcp_packet_app_get_subtype (packet),
+        gst_rtcp_packet_app_get_ssrc (packet), name, data_buffer);
+    RTP_SESSION_LOCK (sess);
+
+    if (data_buffer)
+      gst_buffer_unref (data_buffer);
+  }
+}
+
+static gboolean
+rtp_session_request_local_key_unit (RTPSession * sess, RTPSource * src,
+    guint32 media_ssrc, gboolean fir, GstClockTime current_time)
+{
+  guint32 round_trip = 0;
+
+  rtp_source_get_last_rb (src, NULL, NULL, NULL, NULL, NULL, NULL, &round_trip);
+
+  if (src->last_keyframe_request != GST_CLOCK_TIME_NONE && round_trip) {
+    GstClockTime round_trip_in_ns = gst_util_uint64_scale (round_trip,
+        GST_SECOND, 65536);
+
+    /* Sanity check to avoid always ignoring PLI/FIR if we receive RTCP
+     * packets with erroneous values resulting in crazy high RTT. */
+    if (round_trip_in_ns > 5 * GST_SECOND)
+      round_trip_in_ns = GST_SECOND / 2;
+
+    if (current_time - src->last_keyframe_request < 2 * round_trip_in_ns) {
+      GST_DEBUG ("Ignoring %s request from %X because one was send without one "
+          "RTT (%" GST_TIME_FORMAT " < %" GST_TIME_FORMAT ")",
+          fir ? "FIR" : "PLI", rtp_source_get_ssrc (src),
+          GST_TIME_ARGS (current_time - src->last_keyframe_request),
+          GST_TIME_ARGS (round_trip_in_ns));
+      return FALSE;
+    }
+  }
+
+  src->last_keyframe_request = current_time;
+
+  GST_LOG ("received %s request from %X about %X %p(%p)", fir ? "FIR" : "PLI",
+      rtp_source_get_ssrc (src), media_ssrc, sess->callbacks.process_rtp,
+      sess->callbacks.request_key_unit);
+
+  RTP_SESSION_UNLOCK (sess);
+  sess->callbacks.request_key_unit (sess, media_ssrc, fir,
+      sess->request_key_unit_user_data);
+  RTP_SESSION_LOCK (sess);
+
+  return TRUE;
+}
+
+static void
+rtp_session_process_pli (RTPSession * sess, guint32 sender_ssrc,
+    guint32 media_ssrc, GstClockTime current_time)
+{
+  RTPSource *src;
+
+  if (!sess->callbacks.request_key_unit)
+    return;
+
+  src = find_source (sess, sender_ssrc);
+  if (src == NULL)
+    return;
+
+  rtp_session_request_local_key_unit (sess, src, media_ssrc, FALSE,
+      current_time);
+}
+
+static void
+rtp_session_process_fir (RTPSession * sess, guint32 sender_ssrc,
+    guint32 media_ssrc, guint8 * fci_data, guint fci_length,
+    GstClockTime current_time)
+{
+  RTPSource *src;
+  guint32 ssrc;
+  guint position = 0;
+  gboolean our_request = FALSE;
+
+  if (!sess->callbacks.request_key_unit)
+    return;
+
+  if (fci_length < 8)
+    return;
+
+  src = find_source (sess, sender_ssrc);
+
+  /* Hack because Google fails to set the sender_ssrc correctly */
+  if (!src && sender_ssrc == 1) {
+    GHashTableIter iter;
+
+    /* we can't find the source if there are multiple */
+    if (sess->stats.sender_sources > sess->stats.internal_sender_sources + 1)
+      return;
+
+    g_hash_table_iter_init (&iter, sess->ssrcs[sess->mask_idx]);
+    while (g_hash_table_iter_next (&iter, NULL, (gpointer *) & src)) {
+      if (!src->internal && rtp_source_is_sender (src))
+        break;
+      src = NULL;
+    }
+  }
+  if (!src)
+    return;
+
+  for (position = 0; position < fci_length; position += 8) {
+    guint8 *data = fci_data + position;
+    RTPSource *own;
+
+    ssrc = GST_READ_UINT32_BE (data);
+
+    own = find_source (sess, ssrc);
+    if (own == NULL)
+      continue;
+
+    if (own->internal) {
+      our_request = TRUE;
+      break;
+    }
+  }
+  if (!our_request)
+    return;
+
+  rtp_session_request_local_key_unit (sess, src, media_ssrc, TRUE,
+      current_time);
+}
+
+static void
+rtp_session_process_nack (RTPSession * sess, guint32 sender_ssrc,
+    guint32 media_ssrc, guint8 * fci_data, guint fci_length,
+    GstClockTime current_time)
+{
+  sess->stats.nacks_received++;
+
+  if (!sess->callbacks.notify_nack)
+    return;
+
+  while (fci_length > 0) {
+    guint16 seqnum, blp;
+
+    seqnum = GST_READ_UINT16_BE (fci_data);
+    blp = GST_READ_UINT16_BE (fci_data + 2);
+
+    GST_DEBUG ("NACK #%u, blp %04x, SSRC 0x%08x", seqnum, blp, media_ssrc);
+
+    RTP_SESSION_UNLOCK (sess);
+    sess->callbacks.notify_nack (sess, seqnum, blp, media_ssrc,
+        sess->notify_nack_user_data);
+    RTP_SESSION_LOCK (sess);
+
+    fci_data += 4;
+    fci_length -= 4;
+  }
+}
+
+static void
+rtp_session_process_feedback (RTPSession * sess, GstRTCPPacket * packet,
+    RTPPacketInfo * pinfo, GstClockTime current_time)
+{
+  GstRTCPType type;
+  GstRTCPFBType fbtype;
+  guint32 sender_ssrc, media_ssrc;
+  guint8 *fci_data;
+  guint fci_length;
+  RTPSource *src;
+
+  /* The feedback packet must include both sender SSRC and media SSRC */
+  if (packet->length < 2)
+    return;
+
+  type = gst_rtcp_packet_get_type (packet);
+  fbtype = gst_rtcp_packet_fb_get_type (packet);
+  sender_ssrc = gst_rtcp_packet_fb_get_sender_ssrc (packet);
+  media_ssrc = gst_rtcp_packet_fb_get_media_ssrc (packet);
+
+  src = find_source (sess, media_ssrc);
+
+  /* skip non-bye packets for sources that are marked BYE */
+  if (sess->scheduled_bye && src && RTP_SOURCE_IS_MARKED_BYE (src))
+    return;
+
+  fci_data = gst_rtcp_packet_fb_get_fci (packet);
+  fci_length = gst_rtcp_packet_fb_get_fci_length (packet) * sizeof (guint32);
+
+  GST_DEBUG ("received feedback %d:%d from %08X about %08X with FCI of "
+      "length %d", type, fbtype, sender_ssrc, media_ssrc, fci_length);
+
+  if (g_signal_has_handler_pending (sess,
+          rtp_session_signals[SIGNAL_ON_FEEDBACK_RTCP], 0, TRUE)) {
+    GstBuffer *fci_buffer = NULL;
+
+    if (fci_length > 0) {
+      fci_buffer = gst_buffer_copy_region (packet->rtcp->buffer,
+          GST_BUFFER_COPY_MEMORY, fci_data - packet->rtcp->map.data,
+          fci_length);
+      GST_BUFFER_PTS (fci_buffer) = pinfo->running_time;
+    }
+
+    RTP_SESSION_UNLOCK (sess);
+    g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_FEEDBACK_RTCP], 0,
+        type, fbtype, sender_ssrc, media_ssrc, fci_buffer);
+    RTP_SESSION_LOCK (sess);
+
+    if (fci_buffer)
+      gst_buffer_unref (fci_buffer);
+  }
+
+  if (src && sess->rtcp_feedback_retention_window) {
+    rtp_source_retain_rtcp_packet (src, packet, pinfo->running_time);
+  }
+
+  if ((src && src->internal) ||
+      /* PSFB FIR puts the media ssrc inside the FCI */
+      (type == GST_RTCP_TYPE_PSFB && fbtype == GST_RTCP_PSFB_TYPE_FIR)) {
+    switch (type) {
+      case GST_RTCP_TYPE_PSFB:
+        switch (fbtype) {
+          case GST_RTCP_PSFB_TYPE_PLI:
+            if (src)
+              src->stats.recv_pli_count++;
+            rtp_session_process_pli (sess, sender_ssrc, media_ssrc,
+                current_time);
+            break;
+          case GST_RTCP_PSFB_TYPE_FIR:
+            if (src)
+              src->stats.recv_fir_count++;
+            rtp_session_process_fir (sess, sender_ssrc, media_ssrc, fci_data,
+                fci_length, current_time);
+            break;
+          default:
+            break;
+        }
+        break;
+      case GST_RTCP_TYPE_RTPFB:
+        switch (fbtype) {
+          case GST_RTCP_RTPFB_TYPE_NACK:
+            if (src)
+              src->stats.recv_nack_count++;
+            rtp_session_process_nack (sess, sender_ssrc, media_ssrc,
+                fci_data, fci_length, current_time);
+            break;
+          default:
+            break;
+        }
+      default:
+        break;
+    }
+  }
+}
+
+/**
+ * rtp_session_process_rtcp:
+ * @sess: and #RTPSession
+ * @buffer: an RTCP buffer
+ * @current_time: the current system time
+ * @ntpnstime: the current NTP time in nanoseconds
+ *
+ * Process an RTCP buffer in the session manager. This function takes ownership
+ * of @buffer.
+ *
+ * Returns: a #GstFlowReturn.
+ */
+GstFlowReturn
+rtp_session_process_rtcp (RTPSession * sess, GstBuffer * buffer,
+    GstClockTime current_time, guint64 ntpnstime)
+{
+  GstRTCPPacket packet;
+  gboolean more, is_bye = FALSE, do_sync = FALSE;
+  RTPPacketInfo pinfo = { 0, };
+  GstFlowReturn result = GST_FLOW_OK;
+  GstRTCPBuffer rtcp = { NULL, };
+
+  g_return_val_if_fail (RTP_IS_SESSION (sess), GST_FLOW_ERROR);
+  g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
+
+  if (!gst_rtcp_buffer_validate_reduced (buffer))
+    goto invalid_packet;
+
+  GST_DEBUG ("received RTCP packet");
+
+  g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_RECEIVING_RTCP], 0,
+      buffer);
+
+  RTP_SESSION_LOCK (sess);
+  /* update pinfo stats */
+  update_packet_info (sess, &pinfo, FALSE, FALSE, FALSE, buffer, current_time,
+      -1, ntpnstime);
+
+  /* start processing the compound packet */
+  gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp);
+  more = gst_rtcp_buffer_get_first_packet (&rtcp, &packet);
+  while (more) {
+    GstRTCPType type;
+
+    type = gst_rtcp_packet_get_type (&packet);
+
+    switch (type) {
+      case GST_RTCP_TYPE_SR:
+        rtp_session_process_sr (sess, &packet, &pinfo, &do_sync);
+        break;
+      case GST_RTCP_TYPE_RR:
+        rtp_session_process_rr (sess, &packet, &pinfo);
+        break;
+      case GST_RTCP_TYPE_SDES:
+        rtp_session_process_sdes (sess, &packet, &pinfo);
+        break;
+      case GST_RTCP_TYPE_BYE:
+        is_bye = TRUE;
+        /* don't try to attempt lip-sync anymore for streams with a BYE */
+        do_sync = FALSE;
+        rtp_session_process_bye (sess, &packet, &pinfo);
+        break;
+      case GST_RTCP_TYPE_APP:
+        rtp_session_process_app (sess, &packet, &pinfo);
+        break;
+      case GST_RTCP_TYPE_RTPFB:
+      case GST_RTCP_TYPE_PSFB:
+        rtp_session_process_feedback (sess, &packet, &pinfo, current_time);
+        break;
+      case GST_RTCP_TYPE_XR:
+        /* FIXME: This block is added to downgrade warning level.
+         * Once the parser is implemented, it should be replaced with
+         * a proper process function. */
+        GST_DEBUG ("got RTCP XR packet, but ignored");
+        break;
+      default:
+        GST_WARNING ("got unknown RTCP packet type: %d", type);
+        break;
+    }
+    more = gst_rtcp_packet_move_to_next (&packet);
+  }
+
+  gst_rtcp_buffer_unmap (&rtcp);
+
+  /* if we are scheduling a BYE, we only want to count bye packets, else we
+   * count everything */
+  if (sess->scheduled_bye && is_bye) {
+    sess->bye_stats.bye_members++;
+    UPDATE_AVG (sess->bye_stats.avg_rtcp_packet_size, pinfo.bytes);
+  }
+
+  /* keep track of average packet size */
+  UPDATE_AVG (sess->stats.avg_rtcp_packet_size, pinfo.bytes);
+
+  GST_DEBUG ("%p, received RTCP packet, avg size %u, %u", &sess->stats,
+      sess->stats.avg_rtcp_packet_size, pinfo.bytes);
+  RTP_SESSION_UNLOCK (sess);
+
+  pinfo.data = NULL;
+  clean_packet_info (&pinfo);
+
+  /* notify caller of sr packets in the callback */
+  if (do_sync && sess->callbacks.sync_rtcp) {
+    result = sess->callbacks.sync_rtcp (sess, buffer,
+        sess->sync_rtcp_user_data);
+  } else
+    gst_buffer_unref (buffer);
+
+  return result;
+
+  /* ERRORS */
+invalid_packet:
+  {
+    GST_DEBUG ("invalid RTCP packet received");
+    gst_buffer_unref (buffer);
+    return GST_FLOW_OK;
+  }
+}
+
+/**
+ * rtp_session_update_send_caps:
+ * @sess: an #RTPSession
+ * @caps: a #GstCaps
+ *
+ * Update the caps of the sender in the rtp session.
+ */
+void
+rtp_session_update_send_caps (RTPSession * sess, GstCaps * caps)
+{
+  GstStructure *s;
+  guint ssrc;
+
+  g_return_if_fail (RTP_IS_SESSION (sess));
+  g_return_if_fail (GST_IS_CAPS (caps));
+
+  GST_LOG ("received caps %" GST_PTR_FORMAT, caps);
+
+  s = gst_caps_get_structure (caps, 0);
+
+  if (gst_structure_get_uint (s, "ssrc", &ssrc)) {
+    RTPSource *source;
+    gboolean created;
+
+    RTP_SESSION_LOCK (sess);
+    source = obtain_internal_source (sess, ssrc, &created, GST_CLOCK_TIME_NONE);
+    sess->suggested_ssrc = ssrc;
+    sess->internal_ssrc_set = TRUE;
+    sess->internal_ssrc_from_caps_or_property = TRUE;
+    if (source) {
+      rtp_source_update_caps (source, caps);
+
+      if (created)
+        on_new_sender_ssrc (sess, source);
+
+      g_object_unref (source);
+    }
+
+    if (gst_structure_get_uint (s, "rtx-ssrc", &ssrc)) {
+      source =
+          obtain_internal_source (sess, ssrc, &created, GST_CLOCK_TIME_NONE);
+      if (source) {
+        rtp_source_update_caps (source, caps);
+        g_object_unref (source);
+      }
+    }
+    RTP_SESSION_UNLOCK (sess);
+  } else {
+    sess->internal_ssrc_from_caps_or_property = FALSE;
+  }
+}
+
+/**
+ * rtp_session_send_rtp:
+ * @sess: an #RTPSession
+ * @data: pointer to either an RTP buffer or a list of RTP buffers
+ * @is_list: TRUE when @data is a buffer list
+ * @current_time: the current system time
+ * @running_time: the running time of @data
+ *
+ * Send the RTP buffer in the session manager. This function takes ownership of
+ * @buffer.
+ *
+ * Returns: a #GstFlowReturn.
+ */
+GstFlowReturn
+rtp_session_send_rtp (RTPSession * sess, gpointer data, gboolean is_list,
+    GstClockTime current_time, GstClockTime running_time)
+{
+  GstFlowReturn result;
+  RTPSource *source;
+  gboolean prevsender;
+  guint64 oldrate;
+  RTPPacketInfo pinfo = { 0, };
+  gboolean created;
+
+  g_return_val_if_fail (RTP_IS_SESSION (sess), GST_FLOW_ERROR);
+  g_return_val_if_fail (is_list || GST_IS_BUFFER (data), GST_FLOW_ERROR);
+
+  GST_LOG ("received RTP %s for sending", is_list ? "list" : "packet");
+
+  RTP_SESSION_LOCK (sess);
+  if (!update_packet_info (sess, &pinfo, TRUE, TRUE, is_list, data,
+          current_time, running_time, -1))
+    goto invalid_packet;
+
+  source = obtain_internal_source (sess, pinfo.ssrc, &created, current_time);
+  if (created)
+    on_new_sender_ssrc (sess, source);
+
+  prevsender = RTP_SOURCE_IS_SENDER (source);
+  oldrate = source->bitrate;
+
+  /* we use our own source to send */
+  result = rtp_source_send_rtp (source, &pinfo);
+
+  source_update_sender (sess, source, prevsender);
+
+  if (oldrate != source->bitrate)
+    sess->recalc_bandwidth = TRUE;
+  RTP_SESSION_UNLOCK (sess);
+
+  g_object_unref (source);
+  clean_packet_info (&pinfo);
+
+  return result;
+
+invalid_packet:
+  {
+    gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
+    RTP_SESSION_UNLOCK (sess);
+    GST_DEBUG ("invalid RTP packet received");
+    return GST_FLOW_OK;
+  }
+}
+
+static void
+add_bitrates (gpointer key, RTPSource * source, gdouble * bandwidth)
+{
+  *bandwidth += source->bitrate;
+}
+
+/* must be called with session lock */
+static GstClockTime
+calculate_rtcp_interval (RTPSession * sess, gboolean deterministic,
+    gboolean first)
+{
+  GstClockTime result;
+  RTPSessionStats *stats;
+
+  /* recalculate bandwidth when it changed */
+  if (sess->recalc_bandwidth) {
+    gdouble bandwidth;
+
+    if (sess->bandwidth > 0)
+      bandwidth = sess->bandwidth;
+    else {
+      /* If it is <= 0, then try to estimate the actual bandwidth */
+      bandwidth = 0;
+
+      g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+          (GHFunc) add_bitrates, &bandwidth);
+    }
+    if (bandwidth < RTP_STATS_BANDWIDTH)
+      bandwidth = RTP_STATS_BANDWIDTH;
+
+    rtp_stats_set_bandwidths (&sess->stats, bandwidth,
+        sess->rtcp_bandwidth, sess->rtcp_rs_bandwidth, sess->rtcp_rr_bandwidth);
+
+    sess->recalc_bandwidth = FALSE;
+  }
+
+  if (sess->scheduled_bye) {
+    stats = &sess->bye_stats;
+    result = rtp_stats_calculate_bye_interval (stats);
+  } else {
+    session_update_ptp (sess);
+
+    stats = &sess->stats;
+    result = rtp_stats_calculate_rtcp_interval (stats,
+        stats->internal_sender_sources > 0, sess->rtp_profile,
+        sess->is_doing_ptp, first);
+  }
+
+  GST_DEBUG ("next deterministic interval: %" GST_TIME_FORMAT ", first %d",
+      GST_TIME_ARGS (result), first);
+
+  if (!deterministic && result != GST_CLOCK_TIME_NONE)
+    result = rtp_stats_add_rtcp_jitter (stats, result);
+
+  GST_DEBUG ("next interval: %" GST_TIME_FORMAT, GST_TIME_ARGS (result));
+
+  return result;
+}
+
+static void
+source_mark_bye (const gchar * key, RTPSource * source, const gchar * reason)
+{
+  if (source->internal)
+    rtp_source_mark_bye (source, reason);
+}
+
+/**
+ * rtp_session_mark_all_bye:
+ * @sess: an #RTPSession
+ * @reason: a reason
+ *
+ * Mark all internal sources of the session as BYE with @reason.
+ */
+void
+rtp_session_mark_all_bye (RTPSession * sess, const gchar * reason)
+{
+  g_return_if_fail (RTP_IS_SESSION (sess));
+
+  RTP_SESSION_LOCK (sess);
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+      (GHFunc) source_mark_bye, (gpointer) reason);
+  RTP_SESSION_UNLOCK (sess);
+}
+
+/* Stop the current @sess and schedule a BYE message for the other members.
+ * One must have the session lock to call this function
+ */
+static GstFlowReturn
+rtp_session_schedule_bye_locked (RTPSession * sess, GstClockTime current_time)
+{
+  GstFlowReturn result = GST_FLOW_OK;
+  GstClockTime interval;
+
+  /* nothing to do it we already scheduled bye */
+  if (sess->scheduled_bye)
+    goto done;
+
+  /* we schedule BYE now */
+  sess->scheduled_bye = TRUE;
+  /* at least one member wants to send a BYE */
+  memcpy (&sess->bye_stats, &sess->stats, sizeof (RTPSessionStats));
+  INIT_AVG (sess->bye_stats.avg_rtcp_packet_size, 100);
+  sess->bye_stats.bye_members = 1;
+  sess->first_rtcp = TRUE;
+
+  /* reschedule transmission */
+  sess->last_rtcp_send_time = current_time;
+  sess->last_rtcp_check_time = current_time;
+  interval = calculate_rtcp_interval (sess, FALSE, TRUE);
+
+  if (interval != GST_CLOCK_TIME_NONE)
+    sess->next_rtcp_check_time = current_time + interval;
+  else
+    sess->next_rtcp_check_time = GST_CLOCK_TIME_NONE;
+  sess->last_rtcp_interval = interval;
+
+  GST_DEBUG ("Schedule BYE for %" GST_TIME_FORMAT ", %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (interval), GST_TIME_ARGS (sess->next_rtcp_check_time));
+
+  RTP_SESSION_UNLOCK (sess);
+  /* notify app of reconsideration */
+  if (sess->callbacks.reconsider)
+    sess->callbacks.reconsider (sess, sess->reconsider_user_data);
+  RTP_SESSION_LOCK (sess);
+done:
+
+  return result;
+}
+
+/**
+ * rtp_session_schedule_bye:
+ * @sess: an #RTPSession
+ * @current_time: the current system time
+ *
+ * Schedule a BYE message for all sources marked as BYE in @sess.
+ *
+ * Returns: a #GstFlowReturn.
+ */
+GstFlowReturn
+rtp_session_schedule_bye (RTPSession * sess, GstClockTime current_time)
+{
+  GstFlowReturn result;
+
+  g_return_val_if_fail (RTP_IS_SESSION (sess), GST_FLOW_ERROR);
+
+  RTP_SESSION_LOCK (sess);
+  result = rtp_session_schedule_bye_locked (sess, current_time);
+  RTP_SESSION_UNLOCK (sess);
+
+  return result;
+}
+
+/**
+ * rtp_session_next_timeout:
+ * @sess: an #RTPSession
+ * @current_time: the current system time
+ *
+ * Get the next time we should perform session maintenance tasks.
+ *
+ * Returns: a time when rtp_session_on_timeout() should be called with the
+ * current system time.
+ */
+GstClockTime
+rtp_session_next_timeout (RTPSession * sess, GstClockTime current_time)
+{
+  GstClockTime result, interval = 0;
+
+  g_return_val_if_fail (RTP_IS_SESSION (sess), GST_CLOCK_TIME_NONE);
+
+  RTP_SESSION_LOCK (sess);
+
+  if (GST_CLOCK_TIME_IS_VALID (sess->next_early_rtcp_time)) {
+    GST_DEBUG ("have early rtcp time");
+    result = sess->next_early_rtcp_time;
+    goto early_exit;
+  }
+
+  result = sess->next_rtcp_check_time;
+
+  GST_DEBUG ("current time: %" GST_TIME_FORMAT
+      ", next time: %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (current_time), GST_TIME_ARGS (result));
+
+  if (result == GST_CLOCK_TIME_NONE || result < current_time) {
+    GST_DEBUG ("take current time as base");
+    /* our previous check time expired, start counting from the current time
+     * again. */
+    result = current_time;
+  }
+
+  if (sess->scheduled_bye) {
+    if (sess->bye_stats.active_sources >= 50) {
+      GST_DEBUG ("reconsider BYE, more than 50 sources");
+      /* reconsider BYE if members >= 50 */
+      interval = calculate_rtcp_interval (sess, FALSE, TRUE);
+      sess->last_rtcp_interval = interval;
+    }
+  } else {
+    if (sess->first_rtcp) {
+      GST_DEBUG ("first RTCP packet");
+      /* we are called for the first time */
+      interval = calculate_rtcp_interval (sess, FALSE, TRUE);
+      sess->last_rtcp_interval = interval;
+    } else if (sess->next_rtcp_check_time < current_time) {
+      GST_DEBUG ("old check time expired, getting new timeout");
+      /* get a new timeout when we need to */
+      interval = calculate_rtcp_interval (sess, FALSE, FALSE);
+      sess->last_rtcp_interval = interval;
+
+      if ((sess->rtp_profile == GST_RTP_PROFILE_AVPF
+              || sess->rtp_profile == GST_RTP_PROFILE_SAVPF)
+          && interval != GST_CLOCK_TIME_NONE) {
+        /* Apply the rules from RFC 4585 section 3.5.3 */
+        if (sess->stats.min_interval != 0) {
+          GstClockTime T_rr_current_interval = g_random_double_range (0.5,
+              1.5) * sess->stats.min_interval * GST_SECOND;
+
+          if (T_rr_current_interval > interval) {
+            GST_DEBUG ("Adjusting interval for t-rr-interval: %" GST_TIME_FORMAT
+                " > %" GST_TIME_FORMAT, GST_TIME_ARGS (T_rr_current_interval),
+                GST_TIME_ARGS (interval));
+            interval = T_rr_current_interval;
+          }
+        }
+      }
+    }
+  }
+
+  if (interval != GST_CLOCK_TIME_NONE)
+    result += interval;
+  else
+    result = GST_CLOCK_TIME_NONE;
+
+  sess->next_rtcp_check_time = result;
+
+early_exit:
+
+  GST_DEBUG ("current time: %" GST_TIME_FORMAT
+      ", next time: %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (current_time), GST_TIME_ARGS (result));
+  RTP_SESSION_UNLOCK (sess);
+
+  return result;
+}
+
+typedef struct
+{
+  RTPSource *source;
+  gboolean is_bye;
+  GstBuffer *buffer;
+} ReportOutput;
+
+typedef struct
+{
+  GstRTCPBuffer rtcpbuf;
+  RTPSession *sess;
+  RTPSource *source;
+  guint num_to_report;
+  gboolean have_fir;
+  gboolean have_pli;
+  gboolean have_nack;
+  GstBuffer *rtcp;
+  GstClockTime current_time;
+  guint64 ntpnstime;
+  GstClockTime running_time;
+  GstClockTime interval;
+  GstRTCPPacket packet;
+  gboolean has_sdes;
+  gboolean is_early;
+  gboolean may_suppress;
+  GQueue output;
+  guint nacked_seqnums;
+} ReportData;
+
+static void
+session_start_rtcp (RTPSession * sess, ReportData * data)
+{
+  GstRTCPPacket *packet = &data->packet;
+  RTPSource *own = data->source;
+  GstRTCPBuffer *rtcp = &data->rtcpbuf;
+
+  data->rtcp = gst_rtcp_buffer_new (sess->mtu);
+  data->has_sdes = FALSE;
+
+  gst_rtcp_buffer_map (data->rtcp, GST_MAP_READWRITE, rtcp);
+
+  if (data->is_early && sess->reduced_size_rtcp)
+    return;
+
+  if (RTP_SOURCE_IS_SENDER (own)) {
+    guint64 ntptime;
+    guint32 rtptime;
+    guint32 packet_count, octet_count;
+
+    /* we are a sender, create SR */
+    GST_DEBUG ("create SR for SSRC %08x", own->ssrc);
+    gst_rtcp_buffer_add_packet (rtcp, GST_RTCP_TYPE_SR, packet);
+
+    /* get latest stats */
+    rtp_source_get_new_sr (own, data->ntpnstime, data->running_time,
+        &ntptime, &rtptime, &packet_count, &octet_count);
+    /* store stats */
+    rtp_source_process_sr (own, data->current_time, ntptime, rtptime,
+        packet_count, octet_count);
+
+    /* fill in sender report info */
+    gst_rtcp_packet_sr_set_sender_info (packet, own->ssrc,
+        ntptime, rtptime, packet_count, octet_count);
+  } else {
+    /* we are only receiver, create RR */
+    GST_DEBUG ("create RR for SSRC %08x", own->ssrc);
+    gst_rtcp_buffer_add_packet (rtcp, GST_RTCP_TYPE_RR, packet);
+    gst_rtcp_packet_rr_set_ssrc (packet, own->ssrc);
+  }
+}
+
+/* construct a Sender or Receiver Report */
+static void
+session_report_blocks (const gchar * key, RTPSource * source, ReportData * data)
+{
+  RTPSession *sess = data->sess;
+  GstRTCPPacket *packet = &data->packet;
+  guint8 fractionlost;
+  gint32 packetslost;
+  guint32 exthighestseq, jitter;
+  guint32 lsr, dlsr;
+
+  /* don't report for sources in future generations */
+  if (((gint16) (source->generation - sess->generation)) > 0) {
+    GST_DEBUG ("source %08x generation %u > %u", source->ssrc,
+        source->generation, sess->generation);
+    return;
+  }
+
+  if (g_hash_table_contains (source->reported_in_sr_of,
+          GUINT_TO_POINTER (data->source->ssrc))) {
+    GST_DEBUG ("source %08x already reported in this generation", source->ssrc);
+    return;
+  }
+
+  if (gst_rtcp_packet_get_rb_count (packet) == GST_RTCP_MAX_RB_COUNT) {
+    GST_DEBUG ("max RB count reached");
+    return;
+  }
+
+  /* only report about other sender */
+  if (source == data->source)
+    goto reported;
+
+  if (!RTP_SOURCE_IS_SENDER (source)) {
+    GST_DEBUG ("source %08x not sender", source->ssrc);
+    goto reported;
+  }
+
+  GST_DEBUG ("create RB for SSRC %08x", source->ssrc);
+
+  /* get new stats */
+  rtp_source_get_new_rb (source, data->current_time, &fractionlost,
+      &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
+
+  /* store last generated RR packet */
+  source->last_rr.is_valid = TRUE;
+  source->last_rr.fractionlost = fractionlost;
+  source->last_rr.packetslost = packetslost;
+  source->last_rr.exthighestseq = exthighestseq;
+  source->last_rr.jitter = jitter;
+  source->last_rr.lsr = lsr;
+  source->last_rr.dlsr = dlsr;
+
+  /* packet is not yet filled, add report block for this source. */
+  gst_rtcp_packet_add_rb (packet, source->ssrc, fractionlost, packetslost,
+      exthighestseq, jitter, lsr, dlsr);
+
+reported:
+  g_hash_table_add (source->reported_in_sr_of,
+      GUINT_TO_POINTER (data->source->ssrc));
+}
+
+/* construct FIR */
+static void
+session_add_fir (const gchar * key, RTPSource * source, ReportData * data)
+{
+  GstRTCPPacket *packet = &data->packet;
+  guint16 len;
+  guint8 *fci_data;
+
+  if (!source->send_fir)
+    return;
+
+  len = gst_rtcp_packet_fb_get_fci_length (packet);
+  if (!gst_rtcp_packet_fb_set_fci_length (packet, len + 2))
+    /* exit because the packet is full, will put next request in a
+     * further packet */
+    return;
+
+  fci_data = gst_rtcp_packet_fb_get_fci (packet) + (len * 4);
+
+  GST_WRITE_UINT32_BE (fci_data, source->ssrc);
+  fci_data += 4;
+  fci_data[0] = source->current_send_fir_seqnum;
+  fci_data[1] = fci_data[2] = fci_data[3] = 0;
+
+  source->send_fir = FALSE;
+  source->stats.sent_fir_count++;
+}
+
+static void
+session_fir (RTPSession * sess, ReportData * data)
+{
+  GstRTCPBuffer *rtcp = &data->rtcpbuf;
+  GstRTCPPacket *packet = &data->packet;
+
+  if (!gst_rtcp_buffer_add_packet (rtcp, GST_RTCP_TYPE_PSFB, packet))
+    return;
+
+  gst_rtcp_packet_fb_set_type (packet, GST_RTCP_PSFB_TYPE_FIR);
+  gst_rtcp_packet_fb_set_sender_ssrc (packet, data->source->ssrc);
+  gst_rtcp_packet_fb_set_media_ssrc (packet, 0);
+
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+      (GHFunc) session_add_fir, data);
+
+  if (gst_rtcp_packet_fb_get_fci_length (packet) == 0)
+    gst_rtcp_packet_remove (packet);
+  else
+    data->may_suppress = FALSE;
+}
+
+static gboolean
+has_pli_compare_func (gconstpointer a, gconstpointer ignored)
+{
+  GstRTCPPacket packet;
+  GstRTCPBuffer rtcp = { NULL, };
+  gboolean ret = FALSE;
+
+  gst_rtcp_buffer_map ((GstBuffer *) a, GST_MAP_READ, &rtcp);
+
+  if (gst_rtcp_buffer_get_first_packet (&rtcp, &packet)) {
+    if (gst_rtcp_packet_get_type (&packet) == GST_RTCP_TYPE_PSFB &&
+        gst_rtcp_packet_fb_get_type (&packet) == GST_RTCP_PSFB_TYPE_PLI)
+      ret = TRUE;
+  }
+
+  gst_rtcp_buffer_unmap (&rtcp);
+
+  return ret;
+}
+
+/* construct PLI */
+static void
+session_pli (const gchar * key, RTPSource * source, ReportData * data)
+{
+  GstRTCPBuffer *rtcp = &data->rtcpbuf;
+  GstRTCPPacket *packet = &data->packet;
+
+  if (!source->send_pli)
+    return;
+
+  if (rtp_source_has_retained (source, has_pli_compare_func, NULL))
+    return;
+
+  if (!gst_rtcp_buffer_add_packet (rtcp, GST_RTCP_TYPE_PSFB, packet))
+    /* exit because the packet is full, will put next request in a
+     * further packet */
+    return;
+
+  gst_rtcp_packet_fb_set_type (packet, GST_RTCP_PSFB_TYPE_PLI);
+  gst_rtcp_packet_fb_set_sender_ssrc (packet, data->source->ssrc);
+  gst_rtcp_packet_fb_set_media_ssrc (packet, source->ssrc);
+
+  source->send_pli = FALSE;
+  data->may_suppress = FALSE;
+
+  source->stats.sent_pli_count++;
+}
+
+/* construct NACK */
+static void
+session_nack (const gchar * key, RTPSource * source, ReportData * data)
+{
+  GstRTCPBuffer *rtcp = &data->rtcpbuf;
+  GstRTCPPacket *packet = &data->packet;
+  guint32 *nacks;
+  guint n_nacks, i;
+  guint8 *fci_data;
+
+  if (!source->send_nack)
+    return;
+
+  if (!gst_rtcp_buffer_add_packet (rtcp, GST_RTCP_TYPE_RTPFB, packet))
+    /* exit because the packet is full, will put next request in a
+     * further packet */
+    return;
+
+  gst_rtcp_packet_fb_set_type (packet, GST_RTCP_RTPFB_TYPE_NACK);
+  gst_rtcp_packet_fb_set_sender_ssrc (packet, data->source->ssrc);
+  gst_rtcp_packet_fb_set_media_ssrc (packet, source->ssrc);
+
+  nacks = rtp_source_get_nacks (source, &n_nacks);
+  GST_DEBUG ("%u NACKs", n_nacks);
+  if (!gst_rtcp_packet_fb_set_fci_length (packet, n_nacks))
+    return;
+
+  fci_data = gst_rtcp_packet_fb_get_fci (packet);
+  for (i = 0; i < n_nacks; i++) {
+    GST_WRITE_UINT32_BE (fci_data, nacks[i]);
+    fci_data += 4;
+    data->nacked_seqnums++;
+  }
+
+  rtp_source_clear_nacks (source);
+  data->may_suppress = FALSE;
+  source->stats.sent_nack_count += n_nacks;
+}
+
+/* perform cleanup of sources that timed out */
+static void
+session_cleanup (const gchar * key, RTPSource * source, ReportData * data)
+{
+  gboolean remove = FALSE;
+  gboolean byetimeout = FALSE;
+  gboolean sendertimeout = FALSE;
+  gboolean is_sender, is_active;
+  RTPSession *sess = data->sess;
+  GstClockTime interval, binterval;
+  GstClockTime btime;
+
+  GST_DEBUG ("look at %08x, generation %u", source->ssrc, source->generation);
+
+  /* check for outdated collisions */
+  if (source->internal) {
+    GST_DEBUG ("Timing out collisions for %x", source->ssrc);
+    rtp_source_timeout (source, data->current_time,
+        data->running_time - sess->rtcp_feedback_retention_window);
+  }
+
+  /* nothing else to do when without RTCP */
+  if (data->interval == GST_CLOCK_TIME_NONE)
+    return;
+
+  is_sender = RTP_SOURCE_IS_SENDER (source);
+  is_active = RTP_SOURCE_IS_ACTIVE (source);
+
+  /* our own rtcp interval may have been forced low by secondary configuration,
+   * while sender side may still operate with higher interval,
+   * so do not just take our interval to decide on timing out sender,
+   * but take (if data->interval <= 5 * GST_SECOND):
+   *   interval = CLAMP (sender_interval, data->interval, 5 * GST_SECOND)
+   * where sender_interval is difference between last 2 received RTCP reports
+   */
+  if (data->interval >= 5 * GST_SECOND || source->internal) {
+    binterval = data->interval;
+  } else {
+    GST_LOG ("prev_rtcp %" GST_TIME_FORMAT ", last_rtcp %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (source->stats.prev_rtcptime),
+        GST_TIME_ARGS (source->stats.last_rtcptime));
+    /* if not received enough yet, fallback to larger default */
+    if (source->stats.last_rtcptime > source->stats.prev_rtcptime)
+      binterval = source->stats.last_rtcptime - source->stats.prev_rtcptime;
+    else
+      binterval = 5 * GST_SECOND;
+    binterval = CLAMP (binterval, data->interval, 5 * GST_SECOND);
+  }
+  GST_LOG ("timeout base interval %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (binterval));
+
+  if (!source->internal && source->marked_bye) {
+    /* if we received a BYE from the source, remove the source after some
+     * time. */
+    if (data->current_time > source->bye_time &&
+        data->current_time - source->bye_time > sess->stats.bye_timeout) {
+      GST_DEBUG ("removing BYE source %08x", source->ssrc);
+      remove = TRUE;
+      byetimeout = TRUE;
+    }
+  }
+
+  if (source->internal && source->sent_bye) {
+    GST_DEBUG ("removing internal source that has sent BYE %08x", source->ssrc);
+    remove = TRUE;
+  }
+
+  /* sources that were inactive for more than 5 times the deterministic reporting
+   * interval get timed out. the min timeout is 5 seconds. */
+  /* mind old time that might pre-date last time going to PLAYING */
+  btime = MAX (source->last_activity, sess->start_time);
+  if (data->current_time > btime) {
+    interval = MAX (binterval * 5, 5 * GST_SECOND);
+    if (data->current_time - btime > interval) {
+      GST_DEBUG ("removing timeout source %08x, last %" GST_TIME_FORMAT,
+          source->ssrc, GST_TIME_ARGS (btime));
+      if (source->internal) {
+        /* this is an internal source that is not using our suggested ssrc.
+         * since there must be another source using this ssrc, we can remove
+         * this one instead of making it a receiver forever */
+        if (source->ssrc != sess->suggested_ssrc) {
+          rtp_source_mark_bye (source, "timed out");
+          /* do not schedule bye here, since we are inside the RTCP timeout
+           * processing and scheduling bye will interfere with SR/RR sending */
+        }
+      } else {
+        remove = TRUE;
+      }
+    }
+  }
+
+  /* senders that did not send for a long time become a receiver, this also
+   * holds for our own sources. */
+  if (is_sender) {
+    /* mind old time that might pre-date last time going to PLAYING */
+    btime = MAX (source->last_rtp_activity, sess->start_time);
+    if (data->current_time > btime) {
+      interval = MAX (binterval * 2, 5 * GST_SECOND);
+      if (data->current_time - btime > interval) {
+        GST_DEBUG ("sender source %08x timed out and became receiver, last %"
+            GST_TIME_FORMAT, source->ssrc, GST_TIME_ARGS (btime));
+        sendertimeout = TRUE;
+      }
+    }
+  }
+
+  if (remove) {
+    sess->total_sources--;
+    if (is_sender) {
+      sess->stats.sender_sources--;
+      if (source->internal)
+        sess->stats.internal_sender_sources--;
+    }
+    if (is_active)
+      sess->stats.active_sources--;
+
+    if (source->internal)
+      sess->stats.internal_sources--;
+
+    if (byetimeout)
+      on_bye_timeout (sess, source);
+    else
+      on_timeout (sess, source);
+  } else {
+    if (sendertimeout) {
+      source->is_sender = FALSE;
+      sess->stats.sender_sources--;
+      if (source->internal)
+        sess->stats.internal_sender_sources--;
+
+      on_sender_timeout (sess, source);
+    }
+    /* count how many source to report in this generation */
+    if (((gint16) (source->generation - sess->generation)) <= 0)
+      data->num_to_report++;
+  }
+  source->closing = remove;
+}
+
+static void
+session_sdes (RTPSession * sess, ReportData * data)
+{
+  GstRTCPPacket *packet = &data->packet;
+  const GstStructure *sdes;
+  gint i, n_fields;
+  GstRTCPBuffer *rtcp = &data->rtcpbuf;
+
+  /* add SDES packet */
+  gst_rtcp_buffer_add_packet (rtcp, GST_RTCP_TYPE_SDES, packet);
+
+  gst_rtcp_packet_sdes_add_item (packet, data->source->ssrc);
+
+  sdes = rtp_source_get_sdes_struct (data->source);
+
+  /* add all fields in the structure, the order is not important. */
+  n_fields = gst_structure_n_fields (sdes);
+  for (i = 0; i < n_fields; ++i) {
+    const gchar *field;
+    const gchar *value;
+    GstRTCPSDESType type;
+
+    field = gst_structure_nth_field_name (sdes, i);
+    if (field == NULL)
+      continue;
+    value = gst_structure_get_string (sdes, field);
+    if (value == NULL)
+      continue;
+    type = gst_rtcp_sdes_name_to_type (field);
+
+    /* Early packets are minimal and only include the CNAME */
+    if (data->is_early && type != GST_RTCP_SDES_CNAME)
+      continue;
+
+    if (type > GST_RTCP_SDES_END && type < GST_RTCP_SDES_PRIV) {
+      gst_rtcp_packet_sdes_add_entry (packet, type, strlen (value),
+          (const guint8 *) value);
+    } else if (type == GST_RTCP_SDES_PRIV) {
+      gsize prefix_len;
+      gsize value_len;
+      gsize data_len;
+      guint8 data[256];
+
+      /* don't accept entries that are too big */
+      prefix_len = strlen (field);
+      if (prefix_len > 255)
+        continue;
+      value_len = strlen (value);
+      if (value_len > 255)
+        continue;
+      data_len = 1 + prefix_len + value_len;
+      if (data_len > 255)
+        continue;
+
+      data[0] = prefix_len;
+      memcpy (&data[1], field, prefix_len);
+      memcpy (&data[1 + prefix_len], value, value_len);
+
+      gst_rtcp_packet_sdes_add_entry (packet, type, data_len, data);
+    }
+  }
+
+  data->has_sdes = TRUE;
+}
+
+/* schedule a BYE packet */
+static void
+make_source_bye (RTPSession * sess, RTPSource * source, ReportData * data)
+{
+  GstRTCPPacket *packet = &data->packet;
+  GstRTCPBuffer *rtcp = &data->rtcpbuf;
+
+  /* add SDES */
+  session_sdes (sess, data);
+  /* add a BYE packet */
+  gst_rtcp_buffer_add_packet (rtcp, GST_RTCP_TYPE_BYE, packet);
+  gst_rtcp_packet_bye_add_ssrc (packet, source->ssrc);
+  if (source->bye_reason)
+    gst_rtcp_packet_bye_set_reason (packet, source->bye_reason);
+
+  /* we have a BYE packet now */
+  source->sent_bye = TRUE;
+}
+
+static gboolean
+is_rtcp_time (RTPSession * sess, GstClockTime current_time, ReportData * data)
+{
+  GstClockTime new_send_time;
+  GstClockTime interval;
+  RTPSessionStats *stats;
+
+  if (sess->scheduled_bye)
+    stats = &sess->bye_stats;
+  else
+    stats = &sess->stats;
+
+  if (GST_CLOCK_TIME_IS_VALID (sess->next_early_rtcp_time))
+    data->is_early = TRUE;
+  else
+    data->is_early = FALSE;
+
+  if (data->is_early && sess->next_early_rtcp_time < current_time) {
+    GST_DEBUG ("early feedback %" GST_TIME_FORMAT " < now %"
+        GST_TIME_FORMAT, GST_TIME_ARGS (sess->next_early_rtcp_time),
+        GST_TIME_ARGS (current_time));
+  } else if (sess->next_rtcp_check_time == GST_CLOCK_TIME_NONE ||
+      sess->next_rtcp_check_time > current_time) {
+    GST_DEBUG ("no check time yet, next %" GST_TIME_FORMAT " > now %"
+        GST_TIME_FORMAT, GST_TIME_ARGS (sess->next_rtcp_check_time),
+        GST_TIME_ARGS (current_time));
+    return FALSE;
+  }
+
+  /* take interval and add jitter */
+  interval = data->interval;
+  if (interval != GST_CLOCK_TIME_NONE)
+    interval = rtp_stats_add_rtcp_jitter (stats, interval);
+
+  if (sess->last_rtcp_check_time != GST_CLOCK_TIME_NONE) {
+    /* perform forward reconsideration */
+    if (interval != GST_CLOCK_TIME_NONE) {
+      GstClockTime elapsed;
+
+      /* get elapsed time since we last reported */
+      elapsed = current_time - sess->last_rtcp_check_time;
+
+      GST_DEBUG ("forward reconsideration %" GST_TIME_FORMAT ", elapsed %"
+          GST_TIME_FORMAT, GST_TIME_ARGS (interval), GST_TIME_ARGS (elapsed));
+      new_send_time = interval + sess->last_rtcp_check_time;
+    } else {
+      new_send_time = sess->last_rtcp_check_time;
+    }
+  } else {
+    /* If this is the first RTCP packet, we can reconsider anything based
+     * on the last RTCP send time because there was none.
+     */
+    g_warn_if_fail (!data->is_early);
+    data->is_early = FALSE;
+    new_send_time = current_time;
+  }
+
+  if (!data->is_early) {
+    /* check if reconsideration */
+    if (new_send_time == GST_CLOCK_TIME_NONE || current_time < new_send_time) {
+      GST_DEBUG ("reconsider RTCP for %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (new_send_time));
+      /* store new check time */
+      sess->next_rtcp_check_time = new_send_time;
+      sess->last_rtcp_interval = interval;
+      return FALSE;
+    }
+
+    sess->last_rtcp_interval = interval;
+    if ((sess->rtp_profile == GST_RTP_PROFILE_AVPF
+            || sess->rtp_profile == GST_RTP_PROFILE_SAVPF)
+        && interval != GST_CLOCK_TIME_NONE) {
+      /* Apply the rules from RFC 4585 section 3.5.3 */
+      if (stats->min_interval != 0 && !sess->first_rtcp) {
+        GstClockTime T_rr_current_interval =
+            g_random_double_range (0.5, 1.5) * stats->min_interval * GST_SECOND;
+
+        if (T_rr_current_interval > interval) {
+          GST_DEBUG ("Adjusting interval for t-rr-interval: %" GST_TIME_FORMAT
+              " > %" GST_TIME_FORMAT, GST_TIME_ARGS (T_rr_current_interval),
+              GST_TIME_ARGS (interval));
+          interval = T_rr_current_interval;
+        }
+      }
+    }
+    sess->next_rtcp_check_time = current_time + interval;
+  }
+
+
+  GST_DEBUG ("can send RTCP now, next %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (sess->next_rtcp_check_time));
+
+  return TRUE;
+}
+
+static void
+clone_ssrcs_hashtable (gchar * key, RTPSource * source, GHashTable * hash_table)
+{
+  g_hash_table_insert (hash_table, key, g_object_ref (source));
+}
+
+static gboolean
+remove_closing_sources (const gchar * key, RTPSource * source,
+    ReportData * data)
+{
+  if (source->closing)
+    return TRUE;
+
+  if (source->send_fir)
+    data->have_fir = TRUE;
+  if (source->send_pli)
+    data->have_pli = TRUE;
+  if (source->send_nack)
+    data->have_nack = TRUE;
+
+  return FALSE;
+}
+
+static void
+generate_rtcp (const gchar * key, RTPSource * source, ReportData * data)
+{
+  RTPSession *sess = data->sess;
+  gboolean is_bye = FALSE;
+  ReportOutput *output;
+
+  /* only generate RTCP for active internal sources */
+  if (!source->internal || source->sent_bye)
+    return;
+
+  /* ignore other sources when we do the timeout after a scheduled BYE */
+  if (sess->scheduled_bye && !source->marked_bye)
+    return;
+
+  data->source = source;
+
+  /* open packet */
+  session_start_rtcp (sess, data);
+
+  if (source->marked_bye) {
+    /* send BYE */
+    make_source_bye (sess, source, data);
+    is_bye = TRUE;
+  } else if (!data->is_early) {
+    /* loop over all known sources and add report blocks. If we are early, we
+     * just make a minimal RTCP packet and skip this step */
+    g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+        (GHFunc) session_report_blocks, data);
+  }
+  if (!data->has_sdes && (!data->is_early || !sess->reduced_size_rtcp))
+    session_sdes (sess, data);
+
+  if (data->have_fir)
+    session_fir (sess, data);
+
+  if (data->have_pli)
+    g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+        (GHFunc) session_pli, data);
+
+  if (data->have_nack)
+    g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+        (GHFunc) session_nack, data);
+
+  gst_rtcp_buffer_unmap (&data->rtcpbuf);
+
+  output = g_slice_new (ReportOutput);
+  output->source = g_object_ref (source);
+  output->is_bye = is_bye;
+  output->buffer = data->rtcp;
+  /* queue the RTCP packet to push later */
+  g_queue_push_tail (&data->output, output);
+}
+
+static void
+update_generation (const gchar * key, RTPSource * source, ReportData * data)
+{
+  RTPSession *sess = data->sess;
+
+  if (g_hash_table_size (source->reported_in_sr_of) >=
+      sess->stats.internal_sources) {
+    /* source is reported, move to next generation */
+    source->generation = sess->generation + 1;
+    g_hash_table_remove_all (source->reported_in_sr_of);
+
+    GST_LOG ("reported source %x, new generation: %d", source->ssrc,
+        source->generation);
+
+    /* if we reported all sources in this generation, move to next */
+    if (--data->num_to_report == 0) {
+      sess->generation++;
+      GST_DEBUG ("all reported, generation now %u", sess->generation);
+    }
+  }
+}
+
+static gboolean
+rtp_session_are_all_sources_bye (RTPSession * sess)
+{
+  GHashTableIter iter;
+  RTPSource *src;
+
+  g_hash_table_iter_init (&iter, sess->ssrcs[sess->mask_idx]);
+  while (g_hash_table_iter_next (&iter, NULL, (gpointer *) & src)) {
+    if (src->internal && !src->sent_bye)
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+ * rtp_session_on_timeout:
+ * @sess: an #RTPSession
+ * @current_time: the current system time
+ * @ntpnstime: the current NTP time in nanoseconds
+ * @running_time: the current running_time of the pipeline
+ *
+ * Perform maintenance actions after the timeout obtained with
+ * rtp_session_next_timeout() expired.
+ *
+ * This function will perform timeouts of receivers and senders, send a BYE
+ * packet or generate RTCP packets with current session stats.
+ *
+ * This function can call the #RTPSessionSendRTCP callback, possibly multiple
+ * times, for each packet that should be processed.
+ *
+ * Returns: a #GstFlowReturn.
+ */
+GstFlowReturn
+rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
+    guint64 ntpnstime, GstClockTime running_time)
+{
+  GstFlowReturn result = GST_FLOW_OK;
+  ReportData data = { GST_RTCP_BUFFER_INIT };
+  GHashTable *table_copy;
+  ReportOutput *output;
+  gboolean all_empty = FALSE;
+
+  g_return_val_if_fail (RTP_IS_SESSION (sess), GST_FLOW_ERROR);
+
+  GST_DEBUG ("reporting at %" GST_TIME_FORMAT ", NTP time %" GST_TIME_FORMAT
+      ", running-time %" GST_TIME_FORMAT, GST_TIME_ARGS (current_time),
+      GST_TIME_ARGS (ntpnstime), GST_TIME_ARGS (running_time));
+
+  data.sess = sess;
+  data.current_time = current_time;
+  data.ntpnstime = ntpnstime;
+  data.running_time = running_time;
+  data.num_to_report = 0;
+  data.may_suppress = FALSE;
+  data.nacked_seqnums = 0;
+  g_queue_init (&data.output);
+
+  RTP_SESSION_LOCK (sess);
+  /* get a new interval, we need this for various cleanups etc */
+  data.interval = calculate_rtcp_interval (sess, TRUE, sess->first_rtcp);
+
+  GST_DEBUG ("interval %" GST_TIME_FORMAT, GST_TIME_ARGS (data.interval));
+
+  /* we need an internal source now */
+  if (sess->stats.internal_sources == 0) {
+    RTPSource *source;
+    gboolean created;
+
+    source = obtain_internal_source (sess, sess->suggested_ssrc, &created,
+        current_time);
+    sess->internal_ssrc_set = TRUE;
+
+    if (created)
+      on_new_sender_ssrc (sess, source);
+
+    g_object_unref (source);
+  }
+
+  sess->conflicting_addresses =
+      timeout_conflicting_addresses (sess->conflicting_addresses, current_time);
+
+  /* Make a local copy of the hashtable. We need to do this because the
+   * cleanup stage below releases the session lock. */
+  table_copy = g_hash_table_new_full (NULL, NULL, NULL,
+      (GDestroyNotify) g_object_unref);
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+      (GHFunc) clone_ssrcs_hashtable, table_copy);
+
+  /* Clean up the session, mark the source for removing, this might release the
+   * session lock. */
+  g_hash_table_foreach (table_copy, (GHFunc) session_cleanup, &data);
+  g_hash_table_destroy (table_copy);
+
+  /* Now remove the marked sources */
+  g_hash_table_foreach_remove (sess->ssrcs[sess->mask_idx],
+      (GHRFunc) remove_closing_sources, &data);
+
+  /* update point-to-point status */
+  session_update_ptp (sess);
+
+  /* see if we need to generate SR or RR packets */
+  if (!is_rtcp_time (sess, current_time, &data))
+    goto done;
+
+  /* check if all the buffers are empty afer generation */
+  all_empty = TRUE;
+
+  GST_DEBUG
+      ("doing RTCP generation %u for %u sources, early %d, may suppress %d",
+      sess->generation, data.num_to_report, data.is_early, data.may_suppress);
+
+  /* generate RTCP for all internal sources */
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+      (GHFunc) generate_rtcp, &data);
+
+  /* update the generation for all the sources that have been reported */
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+      (GHFunc) update_generation, &data);
+
+  /* we keep track of the last report time in order to timeout inactive
+   * receivers or senders */
+  if (!data.is_early) {
+    GST_DEBUG ("Time since last regular RTCP: %" GST_TIME_FORMAT " - %"
+        GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (data.current_time),
+        GST_TIME_ARGS (sess->last_rtcp_send_time),
+        GST_TIME_ARGS (data.current_time - sess->last_rtcp_send_time));
+    sess->last_rtcp_send_time = data.current_time;
+  }
+
+  GST_DEBUG ("Time since last RTCP: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT
+      " = %" GST_TIME_FORMAT, GST_TIME_ARGS (data.current_time),
+      GST_TIME_ARGS (sess->last_rtcp_check_time),
+      GST_TIME_ARGS (data.current_time - sess->last_rtcp_check_time));
+  sess->last_rtcp_check_time = data.current_time;
+  sess->first_rtcp = FALSE;
+  sess->next_early_rtcp_time = GST_CLOCK_TIME_NONE;
+  sess->scheduled_bye = FALSE;
+
+done:
+  RTP_SESSION_UNLOCK (sess);
+
+  /* notify about updated statistics */
+  g_object_notify (G_OBJECT (sess), "stats");
+
+  /* push out the RTCP packets */
+  while ((output = g_queue_pop_head (&data.output))) {
+    gboolean do_not_suppress, empty_buffer;
+    GstBuffer *buffer = output->buffer;
+    RTPSource *source = output->source;
+
+    /* Give the user a change to add its own packet */
+    g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_SENDING_RTCP], 0,
+        buffer, data.is_early, &do_not_suppress);
+
+    empty_buffer = gst_buffer_get_size (buffer) == 0;
+
+    if (!empty_buffer)
+      all_empty = FALSE;
+
+    if (sess->callbacks.send_rtcp &&
+        !empty_buffer && (do_not_suppress || !data.may_suppress)) {
+      guint packet_size;
+
+      packet_size = gst_buffer_get_size (buffer) + sess->header_len;
+
+      UPDATE_AVG (sess->stats.avg_rtcp_packet_size, packet_size);
+      GST_DEBUG ("%p, sending RTCP packet, avg size %u, %u", &sess->stats,
+          sess->stats.avg_rtcp_packet_size, packet_size);
+      result =
+          sess->callbacks.send_rtcp (sess, source, buffer,
+          rtp_session_are_all_sources_bye (sess), sess->send_rtcp_user_data);
+
+      RTP_SESSION_LOCK (sess);
+      sess->stats.nacks_sent += data.nacked_seqnums;
+      on_sender_ssrc_active (sess, source);
+      RTP_SESSION_UNLOCK (sess);
+    } else {
+      GST_DEBUG ("freeing packet callback: %p"
+          " empty_buffer: %d, "
+          " do_not_suppress: %d may_suppress: %d", sess->callbacks.send_rtcp,
+          empty_buffer, do_not_suppress, data.may_suppress);
+      if (!empty_buffer) {
+        RTP_SESSION_LOCK (sess);
+        sess->stats.nacks_dropped += data.nacked_seqnums;
+        RTP_SESSION_UNLOCK (sess);
+      }
+      gst_buffer_unref (buffer);
+    }
+    g_object_unref (source);
+    g_slice_free (ReportOutput, output);
+  }
+
+  if (all_empty)
+    GST_ERROR ("generated empty RTCP messages for all the sources");
+
+  return result;
+}
+
+/**
+ * rtp_session_request_early_rtcp:
+ * @sess: an #RTPSession
+ * @current_time: the current system time
+ * @max_delay: maximum delay
+ *
+ * Request transmission of early RTCP
+ *
+ * Returns: %TRUE if the related RTCP can be scheduled.
+ */
+gboolean
+rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time,
+    GstClockTime max_delay)
+{
+  GstClockTime T_dither_max, T_rr, offset = 0;
+  gboolean ret;
+  gboolean allow_early;
+
+  /* Implements the algorithm described in RFC 4585 section 3.5.2 */
+
+  RTP_SESSION_LOCK (sess);
+
+  /* We assume a feedback profile if something is requesting RTCP
+   * to be sent */
+  sess->rtp_profile = GST_RTP_PROFILE_AVPF;
+
+  /* Check if already requested */
+  /*  RFC 4585 section 3.5.2 step 2 */
+  if (GST_CLOCK_TIME_IS_VALID (sess->next_early_rtcp_time)) {
+    GST_LOG_OBJECT (sess, "already have next early rtcp time");
+    ret = (current_time + max_delay > sess->next_early_rtcp_time);
+    goto end;
+  }
+
+  if (!GST_CLOCK_TIME_IS_VALID (sess->next_rtcp_check_time)) {
+    GST_LOG_OBJECT (sess, "no next RTCP check time");
+    ret = FALSE;
+    goto end;
+  }
+
+  /* RFC 4585 section 3.5.3 step 1
+   * If no regular RTCP packet has been sent before, then a regular
+   * RTCP packet has to be scheduled first and FB messages might be
+   * included there
+   */
+  if (!GST_CLOCK_TIME_IS_VALID (sess->last_rtcp_send_time)) {
+    GST_LOG_OBJECT (sess, "no RTCP sent yet");
+
+    if (current_time + max_delay > sess->next_rtcp_check_time) {
+      GST_LOG_OBJECT (sess,
+          "next scheduled time is soon %" GST_TIME_FORMAT " + %" GST_TIME_FORMAT
+          " > %" GST_TIME_FORMAT, GST_TIME_ARGS (current_time),
+          GST_TIME_ARGS (max_delay),
+          GST_TIME_ARGS (sess->next_rtcp_check_time));
+      ret = TRUE;
+    } else {
+      GST_LOG_OBJECT (sess,
+          "can't allow early feedback, next scheduled time is too late %"
+          GST_TIME_FORMAT " + %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (current_time), GST_TIME_ARGS (max_delay),
+          GST_TIME_ARGS (sess->next_rtcp_check_time));
+      ret = FALSE;
+    }
+    goto end;
+  }
+
+  T_rr = sess->last_rtcp_interval;
+
+  /*  RFC 4585 section 3.5.2 step 2b */
+  /* If the total sources is <=2, then there is only us and one peer */
+  /* When there is one auxiliary stream the session can still do point
+   * to point.
+   */
+  if (sess->is_doing_ptp) {
+    T_dither_max = 0;
+  } else {
+    /* Divide by 2 because l = 0.5 */
+    T_dither_max = T_rr;
+    T_dither_max /= 2;
+  }
+
+  /*  RFC 4585 section 3.5.2 step 3 */
+  if (current_time + T_dither_max > sess->next_rtcp_check_time) {
+    GST_LOG_OBJECT (sess,
+        "don't send because of dither, next scheduled time is too soon %"
+        GST_TIME_FORMAT " + %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (current_time), GST_TIME_ARGS (T_dither_max),
+        GST_TIME_ARGS (sess->next_rtcp_check_time));
+    ret = T_dither_max <= max_delay;
+    goto end;
+  }
+
+  /*  RFC 4585 section 3.5.2 step 4a and
+   *  RFC 4585 section 3.5.2 step 6 */
+  allow_early = FALSE;
+  if (sess->last_rtcp_check_time == sess->last_rtcp_send_time) {
+    /* Last time we sent a full RTCP packet, we can now immediately
+     * send an early one as allow_early was reset to TRUE */
+    allow_early = TRUE;
+  } else if (sess->last_rtcp_check_time + T_rr <= current_time + max_delay) {
+    /* Last packet we sent was an early RTCP packet and more than
+     * T_rr has passed since then, meaning we would have suppressed
+     * a regular RTCP packet already and reset allow_early to TRUE */
+    allow_early = TRUE;
+
+    /* We have to offset a bit as T_rr has not passed yet, but will before
+     * max_delay */
+    if (sess->last_rtcp_check_time + T_rr > current_time)
+      offset = (sess->last_rtcp_check_time + T_rr) - current_time;
+  } else {
+    GST_DEBUG_OBJECT (sess,
+        "can't allow early RTCP yet: last regular %" GST_TIME_FORMAT ", %"
+        GST_TIME_FORMAT " + %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT " + %"
+        GST_TIME_FORMAT, GST_TIME_ARGS (sess->last_rtcp_send_time),
+        GST_TIME_ARGS (sess->last_rtcp_check_time), GST_TIME_ARGS (T_rr),
+        GST_TIME_ARGS (current_time), GST_TIME_ARGS (max_delay));
+  }
+
+  if (!allow_early) {
+    /* Ignore the request a scheduled packet will be in time anyway */
+    if (current_time + max_delay > sess->next_rtcp_check_time) {
+      GST_LOG_OBJECT (sess,
+          "next scheduled time is soon %" GST_TIME_FORMAT " + %" GST_TIME_FORMAT
+          " > %" GST_TIME_FORMAT, GST_TIME_ARGS (current_time),
+          GST_TIME_ARGS (max_delay),
+          GST_TIME_ARGS (sess->next_rtcp_check_time));
+      ret = TRUE;
+    } else {
+      GST_LOG_OBJECT (sess,
+          "can't allow early feedback and next scheduled time is too late %"
+          GST_TIME_FORMAT " + %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (current_time), GST_TIME_ARGS (max_delay),
+          GST_TIME_ARGS (sess->next_rtcp_check_time));
+      ret = FALSE;
+    }
+    goto end;
+  }
+
+  /*  RFC 4585 section 3.5.2 step 4b */
+  if (T_dither_max) {
+    /* Schedule an early transmission later */
+    sess->next_early_rtcp_time = g_random_double () * T_dither_max +
+        current_time + offset;
+  } else {
+    /* If no dithering, schedule it for NOW */
+    sess->next_early_rtcp_time = current_time + offset;
+  }
+
+  GST_LOG_OBJECT (sess, "next early RTCP time %" GST_TIME_FORMAT
+      ", next regular RTCP time %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (sess->next_early_rtcp_time),
+      GST_TIME_ARGS (sess->next_rtcp_check_time));
+  RTP_SESSION_UNLOCK (sess);
+
+  /* notify app of need to send packet early
+   * and therefore of timeout change */
+  if (sess->callbacks.reconsider)
+    sess->callbacks.reconsider (sess, sess->reconsider_user_data);
+
+  return TRUE;
+
+end:
+
+  RTP_SESSION_UNLOCK (sess);
+
+  return ret;
+}
+
+static gboolean
+rtp_session_send_rtcp (RTPSession * sess, GstClockTime max_delay)
+{
+  GstClockTime now;
+
+  if (!sess->callbacks.send_rtcp)
+    return FALSE;
+
+  now = sess->callbacks.request_time (sess, sess->request_time_user_data);
+
+  return rtp_session_request_early_rtcp (sess, now, max_delay);
+}
+
+gboolean
+rtp_session_request_key_unit (RTPSession * sess, guint32 ssrc,
+    gboolean fir, gint count)
+{
+  RTPSource *src;
+
+  if (!rtp_session_send_rtcp (sess, 5 * GST_SECOND)) {
+    GST_DEBUG ("FIR/PLI not sent");
+    return FALSE;
+  }
+
+  RTP_SESSION_LOCK (sess);
+  src = find_source (sess, ssrc);
+  if (src == NULL)
+    goto no_source;
+
+  if (fir) {
+    src->send_pli = FALSE;
+    src->send_fir = TRUE;
+
+    if (count == -1 || count != src->last_fir_count)
+      src->current_send_fir_seqnum++;
+    src->last_fir_count = count;
+  } else if (!src->send_fir) {
+    src->send_pli = TRUE;
+  }
+  RTP_SESSION_UNLOCK (sess);
+
+  return TRUE;
+
+  /* ERRORS */
+no_source:
+  {
+    RTP_SESSION_UNLOCK (sess);
+    return FALSE;
+  }
+}
+
+/**
+ * rtp_session_request_nack:
+ * @sess: a #RTPSession
+ * @ssrc: the SSRC
+ * @seqnum: the missing seqnum
+ * @max_delay: max delay to request NACK
+ *
+ * Request scheduling of a NACK feedback packet for @seqnum in @ssrc.
+ *
+ * Returns: %TRUE if the NACK feedback could be scheduled
+ */
+gboolean
+rtp_session_request_nack (RTPSession * sess, guint32 ssrc, guint16 seqnum,
+    GstClockTime max_delay)
+{
+  RTPSource *source;
+
+  if (!rtp_session_send_rtcp (sess, max_delay)) {
+    GST_DEBUG ("NACK not sent");
+    return FALSE;
+  }
+
+  RTP_SESSION_LOCK (sess);
+  source = find_source (sess, ssrc);
+  if (source == NULL)
+    goto no_source;
+
+  GST_DEBUG ("request NACK for %08x, #%u", ssrc, seqnum);
+  rtp_source_register_nack (source, seqnum);
+  RTP_SESSION_UNLOCK (sess);
+
+  return TRUE;
+
+  /* ERRORS */
+no_source:
+  {
+    RTP_SESSION_UNLOCK (sess);
+    return FALSE;
+  }
+}
diff --git a/gst/rtpmanager/rtpsession.h b/gst/rtpmanager/rtpsession.h
new file mode 100644
index 0000000..5ca8a82
--- /dev/null
+++ b/gst/rtpmanager/rtpsession.h
@@ -0,0 +1,404 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __RTP_SESSION_H__
+#define __RTP_SESSION_H__
+
+#include <gst/gst.h>
+
+#include "rtpsource.h"
+
+typedef struct _RTPSession RTPSession;
+typedef struct _RTPSessionClass RTPSessionClass;
+
+#define RTP_TYPE_SESSION             (rtp_session_get_type())
+#define RTP_SESSION(sess)            (G_TYPE_CHECK_INSTANCE_CAST((sess),RTP_TYPE_SESSION,RTPSession))
+#define RTP_SESSION_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),RTP_TYPE_SESSION,RTPSessionClass))
+#define RTP_IS_SESSION(sess)         (G_TYPE_CHECK_INSTANCE_TYPE((sess),RTP_TYPE_SESSION))
+#define RTP_IS_SESSION_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),RTP_TYPE_SESSION))
+#define RTP_SESSION_CAST(sess)       ((RTPSession *)(sess))
+
+#define RTP_SESSION_LOCK(sess)     (g_mutex_lock (&(sess)->lock))
+#define RTP_SESSION_UNLOCK(sess)   (g_mutex_unlock (&(sess)->lock))
+
+/**
+ * RTPSessionProcessRTP:
+ * @sess: an #RTPSession
+ * @src: the #RTPSource
+ * @buffer: the RTP buffer ready for processing
+ * @user_data: user data specified when registering
+ *
+ * This callback will be called when @sess has @buffer ready for further
+ * processing. Processing the buffer typically includes decoding and displaying
+ * the buffer.
+ *
+ * Returns: a #GstFlowReturn.
+ */
+typedef GstFlowReturn (*RTPSessionProcessRTP) (RTPSession *sess, RTPSource *src, GstBuffer *buffer, gpointer user_data);
+
+/**
+ * RTPSessionSendRTP:
+ * @sess: an #RTPSession
+ * @src: the #RTPSource
+ * @buffer: the RTP buffer ready for sending
+ * @user_data: user data specified when registering
+ *
+ * This callback will be called when @sess has @buffer ready for sending to
+ * all listening participants in this session.
+ *
+ * Returns: a #GstFlowReturn.
+ */
+typedef GstFlowReturn (*RTPSessionSendRTP) (RTPSession *sess, RTPSource *src, gpointer data, gpointer user_data);
+
+/**
+ * RTPSessionSendRTCP:
+ * @sess: an #RTPSession
+ * @src: the #RTPSource
+ * @buffer: the RTCP buffer ready for sending
+ * @eos: if an EOS event should be pushed
+ * @user_data: user data specified when registering
+ *
+ * This callback will be called when @sess has @buffer ready for sending to
+ * all listening participants in this session.
+ *
+ * Returns: a #GstFlowReturn.
+ */
+typedef GstFlowReturn (*RTPSessionSendRTCP) (RTPSession *sess, RTPSource *src, GstBuffer *buffer,
+    gboolean eos, gpointer user_data);
+
+/**
+ * RTPSessionSyncRTCP:
+ * @sess: an #RTPSession
+ * @buffer: the RTCP buffer ready for synchronisation
+ * @user_data: user data specified when registering
+ *
+ * This callback will be called when @sess has an SR @buffer ready for doing
+ * synchronisation between streams.
+ *
+ * Returns: a #GstFlowReturn.
+ */
+typedef GstFlowReturn (*RTPSessionSyncRTCP) (RTPSession *sess, GstBuffer *buffer, gpointer user_data);
+
+/**
+ * RTPSessionClockRate:
+ * @sess: an #RTPSession
+ * @payload: the payload
+ * @user_data: user data specified when registering
+ *
+ * This callback will be called when @sess needs the clock-rate of @payload.
+ *
+ * Returns: the clock-rate of @pt.
+ */
+typedef gint (*RTPSessionClockRate) (RTPSession *sess, guint8 payload, gpointer user_data);
+
+/**
+ * RTPSessionReconsider:
+ * @sess: an #RTPSession
+ * @user_data: user data specified when registering
+ *
+ * This callback will be called when @sess needs to cancel the current timeout.
+ * The currently running timeout should be canceled and a new reporting interval
+ * should be requested from @sess.
+ */
+typedef void (*RTPSessionReconsider) (RTPSession *sess, gpointer user_data);
+
+/**
+ * RTPSessionRequestKeyUnit:
+ * @sess: an #RTPSession
+ * @ssrc: SSRC of the source related to the key unit request
+ * @all_headers: %TRUE if "all-headers" property should be set on the key unit
+ *  request
+ * @user_data: user data specified when registering
+ *
+ * Asks the encoder to produce a key unit as soon as possibly within the
+ * bandwidth constraints
+ */
+typedef void (*RTPSessionRequestKeyUnit) (RTPSession *sess, guint32 ssrc,
+    gboolean all_headers, gpointer user_data);
+
+/**
+ * RTPSessionRequestTime:
+ * @sess: an #RTPSession
+ * @user_data: user data specified when registering
+ *
+ * This callback will be called when @sess needs the current time. The time
+ * should be returned as a #GstClockTime
+ */
+typedef GstClockTime (*RTPSessionRequestTime) (RTPSession *sess,
+    gpointer user_data);
+
+/**
+ * RTPSessionNotifyNACK:
+ * @sess: an #RTPSession
+ * @seqnum: the missing seqnum
+ * @blp: other missing seqnums
+ * @ssrc: SSRC of requested stream
+ * @user_data: user data specified when registering
+ *
+ * Notifies of NACKed frames.
+ */
+typedef void (*RTPSessionNotifyNACK) (RTPSession *sess,
+    guint16 seqnum, guint16 blp, guint32 ssrc, gpointer user_data);
+
+/**
+ * RTPSessionReconfigure:
+ * @sess: an #RTPSession
+ * @user_data: user data specified when registering
+ *
+ * This callback will be called when @sess wants to reconfigure the
+ * negotiated parameters.
+ */
+typedef void (*RTPSessionReconfigure) (RTPSession *sess, gpointer user_data);
+
+/**
+ * RTPSessionCallbacks:
+ * @RTPSessionProcessRTP: callback to process RTP packets
+ * @RTPSessionSendRTP: callback for sending RTP packets
+ * @RTPSessionSendRTCP: callback for sending RTCP packets
+ * @RTPSessionSyncRTCP: callback for handling SR packets
+ * @RTPSessionReconsider: callback for reconsidering the timeout
+ * @RTPSessionRequestKeyUnit: callback for requesting a new key unit
+ * @RTPSessionRequestTime: callback for requesting the current time
+ * @RTPSessionNotifyNACK: callback for notifying NACK
+ * @RTPSessionReconfigure: callback for requesting reconfiguration
+ *
+ * These callbacks can be installed on the session manager to get notification
+ * when RTP and RTCP packets are ready for further processing. These callbacks
+ * are not implemented with signals for performance reasons.
+ */
+typedef struct {
+  RTPSessionProcessRTP  process_rtp;
+  RTPSessionSendRTP     send_rtp;
+  RTPSessionSyncRTCP    sync_rtcp;
+  RTPSessionSendRTCP    send_rtcp;
+  RTPSessionClockRate   clock_rate;
+  RTPSessionReconsider  reconsider;
+  RTPSessionRequestKeyUnit request_key_unit;
+  RTPSessionRequestTime request_time;
+  RTPSessionNotifyNACK  notify_nack;
+  RTPSessionReconfigure reconfigure;
+} RTPSessionCallbacks;
+
+/**
+ * RTPSession:
+ * @lock: lock to protect the session
+ * @source: the source of this session
+ * @ssrcs: Hashtable of sources indexed by SSRC
+ * @num_sources: the number of sources
+ * @activecount: the number of active sources
+ * @callbacks: callbacks
+ * @user_data: user data passed in callbacks
+ * @stats: session statistics
+ * @conflicting_addresses: GList of conflicting addresses
+ *
+ * The RTP session manager object
+ */
+struct _RTPSession {
+  GObject       object;
+
+  GMutex        lock;
+
+  guint         header_len;
+  guint         mtu;
+
+  GstStructure *sdes;
+
+  guint         probation;
+  guint32       max_dropout_time;
+  guint32       max_misorder_time;
+
+  GstRTPProfile rtp_profile;
+
+  gboolean      reduced_size_rtcp;
+
+  /* bandwidths */
+  gboolean     recalc_bandwidth;
+  guint        bandwidth;
+  gdouble      rtcp_bandwidth;
+  guint        rtcp_rr_bandwidth;
+  guint        rtcp_rs_bandwidth;
+
+  guint32       suggested_ssrc;
+  gboolean      internal_ssrc_set;
+  gboolean      internal_ssrc_from_caps_or_property;
+
+  /* for sender/receiver counting */
+  guint32       key;
+  guint32       mask_idx;
+  guint32       mask;
+  GHashTable   *ssrcs[32];
+  guint         total_sources;
+
+  guint16       generation;
+  GstClockTime  next_rtcp_check_time; /* tn */
+  GstClockTime  last_rtcp_check_time; /* tp */
+  GstClockTime  last_rtcp_send_time;  /* t_rr_last */
+  GstClockTime  last_rtcp_interval;   /* T_rr */
+  GstClockTime  start_time;
+  gboolean      first_rtcp;
+  gboolean      allow_early;
+
+  GstClockTime  next_early_rtcp_time;
+
+  gboolean      scheduled_bye;
+
+  RTPSessionCallbacks   callbacks;
+  gpointer              process_rtp_user_data;
+  gpointer              send_rtp_user_data;
+  gpointer              send_rtcp_user_data;
+  gpointer              sync_rtcp_user_data;
+  gpointer              clock_rate_user_data;
+  gpointer              reconsider_user_data;
+  gpointer              request_key_unit_user_data;
+  gpointer              request_time_user_data;
+  gpointer              notify_nack_user_data;
+  gpointer              reconfigure_user_data;
+
+  RTPSessionStats stats;
+  RTPSessionStats bye_stats;
+
+  gboolean      favor_new;
+  GstClockTime  rtcp_feedback_retention_window;
+  guint         rtcp_immediate_feedback_threshold;
+
+  gboolean      is_doing_ptp;
+
+  GList         *conflicting_addresses;
+};
+
+/**
+ * RTPSessionClass:
+ * @on_new_ssrc: emited when a new source is found
+ * @on_bye_ssrc: emited when a source is gone
+ *
+ * The session class.
+ */
+struct _RTPSessionClass {
+  GObjectClass   parent_class;
+
+  /* action signals */
+  RTPSource* (*get_source_by_ssrc) (RTPSession *sess, guint32 ssrc);
+
+  /* signals */
+  void (*on_new_ssrc)       (RTPSession *sess, RTPSource *source);
+  void (*on_ssrc_collision) (RTPSession *sess, RTPSource *source);
+  void (*on_ssrc_validated) (RTPSession *sess, RTPSource *source);
+  void (*on_ssrc_active)    (RTPSession *sess, RTPSource *source);
+  void (*on_ssrc_sdes)      (RTPSession *sess, RTPSource *source);
+  void (*on_bye_ssrc)       (RTPSession *sess, RTPSource *source);
+  void (*on_bye_timeout)    (RTPSession *sess, RTPSource *source);
+  void (*on_timeout)        (RTPSession *sess, RTPSource *source);
+  void (*on_sender_timeout) (RTPSession *sess, RTPSource *source);
+  gboolean (*on_sending_rtcp) (RTPSession *sess, GstBuffer *buffer,
+      gboolean early);
+  void (*on_app_rtcp)       (RTPSession *sess, guint subtype, guint ssrc,
+      const gchar *name, GstBuffer *data);
+  void (*on_feedback_rtcp)  (RTPSession *sess, guint type, guint fbtype,
+      guint sender_ssrc, guint media_ssrc, GstBuffer *fci);
+  gboolean (*send_rtcp)     (RTPSession *sess, GstClockTime max_delay);
+  void (*on_receiving_rtcp) (RTPSession *sess, GstBuffer *buffer);
+  void (*on_new_sender_ssrc)     (RTPSession *sess, RTPSource *source);
+  void (*on_sender_ssrc_active)  (RTPSession *sess, RTPSource *source);
+};
+
+GType rtp_session_get_type (void);
+
+/* create and configure */
+RTPSession*     rtp_session_new           (void);
+void            rtp_session_set_callbacks          (RTPSession *sess,
+		                                    RTPSessionCallbacks *callbacks,
+                                                    gpointer user_data);
+void            rtp_session_set_process_rtp_callback   (RTPSession * sess,
+                                                    RTPSessionProcessRTP callback,
+                                                    gpointer user_data);
+void            rtp_session_set_send_rtp_callback  (RTPSession * sess,
+                                                    RTPSessionSendRTP callback,
+                                                    gpointer user_data);
+void            rtp_session_set_send_rtcp_callback   (RTPSession * sess,
+                                                    RTPSessionSendRTCP callback,
+                                                    gpointer user_data);
+void            rtp_session_set_sync_rtcp_callback   (RTPSession * sess,
+                                                    RTPSessionSyncRTCP callback,
+                                                    gpointer user_data);
+void            rtp_session_set_clock_rate_callback   (RTPSession * sess,
+                                                    RTPSessionClockRate callback,
+                                                    gpointer user_data);
+void            rtp_session_set_reconsider_callback (RTPSession * sess,
+                                                    RTPSessionReconsider callback,
+                                                    gpointer user_data);
+void            rtp_session_set_request_time_callback (RTPSession * sess,
+                                                    RTPSessionRequestTime callback,
+                                                    gpointer user_data);
+
+void            rtp_session_set_bandwidth          (RTPSession *sess, gdouble bandwidth);
+gdouble         rtp_session_get_bandwidth          (RTPSession *sess);
+void            rtp_session_set_rtcp_fraction      (RTPSession *sess, gdouble fraction);
+gdouble         rtp_session_get_rtcp_fraction      (RTPSession *sess);
+
+GstStructure *  rtp_session_get_sdes_struct        (RTPSession *sess);
+void            rtp_session_set_sdes_struct        (RTPSession *sess, const GstStructure *sdes);
+
+/* handling sources */
+guint32         rtp_session_suggest_ssrc           (RTPSession *sess, gboolean *is_random);
+
+gboolean        rtp_session_add_source             (RTPSession *sess, RTPSource *src);
+guint           rtp_session_get_num_sources        (RTPSession *sess);
+guint           rtp_session_get_num_active_sources (RTPSession *sess);
+RTPSource*      rtp_session_get_source_by_ssrc     (RTPSession *sess, guint32 ssrc);
+RTPSource*      rtp_session_create_source          (RTPSession *sess);
+
+/* processing packets from receivers */
+GstFlowReturn   rtp_session_process_rtp            (RTPSession *sess, GstBuffer *buffer,
+                                                    GstClockTime current_time,
+						    GstClockTime running_time,
+                                                    guint64 ntpnstime);
+GstFlowReturn   rtp_session_process_rtcp           (RTPSession *sess, GstBuffer *buffer,
+                                                    GstClockTime current_time,
+                                                    guint64 ntpnstime);
+
+/* processing packets for sending */
+void            rtp_session_update_send_caps       (RTPSession *sess, GstCaps *caps);
+GstFlowReturn   rtp_session_send_rtp               (RTPSession *sess, gpointer data, gboolean is_list,
+                                                    GstClockTime current_time, GstClockTime running_time);
+
+/* scheduling bye */
+void            rtp_session_mark_all_bye           (RTPSession *sess, const gchar *reason);
+GstFlowReturn   rtp_session_schedule_bye           (RTPSession *sess, GstClockTime current_time);
+
+/* get interval for next RTCP interval */
+GstClockTime    rtp_session_next_timeout           (RTPSession *sess, GstClockTime current_time);
+GstFlowReturn   rtp_session_on_timeout             (RTPSession *sess, GstClockTime current_time,
+                                                    guint64 ntpnstime, GstClockTime running_time);
+
+/* request the transmittion of an early RTCP packet */
+gboolean        rtp_session_request_early_rtcp     (RTPSession * sess, GstClockTime current_time,
+                                                    GstClockTime max_delay);
+
+/* Notify session of a request for a new key unit */
+gboolean        rtp_session_request_key_unit       (RTPSession * sess,
+                                                    guint32 ssrc,
+                                                    gboolean fir,
+                                                    gint count);
+gboolean        rtp_session_request_nack           (RTPSession * sess,
+                                                    guint32 ssrc,
+                                                    guint16 seqnum,
+                                                    GstClockTime max_delay);
+
+
+#endif /* __RTP_SESSION_H__ */
diff --git a/gst/rtpmanager/rtpsource.c b/gst/rtpmanager/rtpsource.c
new file mode 100644
index 0000000..d726408
--- /dev/null
+++ b/gst/rtpmanager/rtpsource.c
@@ -0,0 +1,1948 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C)  2015 Kurento (http://kurento.org/)
+ *   @author: Miguel París <mparisdiaz@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/rtp/gstrtcpbuffer.h>
+
+#include "rtpsource.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtp_source_debug);
+#define GST_CAT_DEFAULT rtp_source_debug
+
+#define RTP_MAX_PROBATION_LEN  32
+
+/* signals and args */
+enum
+{
+  LAST_SIGNAL
+};
+
+#define DEFAULT_SSRC                 0
+#define DEFAULT_IS_CSRC              FALSE
+#define DEFAULT_IS_VALIDATED         FALSE
+#define DEFAULT_IS_SENDER            FALSE
+#define DEFAULT_SDES                 NULL
+#define DEFAULT_PROBATION            RTP_DEFAULT_PROBATION
+#define DEFAULT_MAX_DROPOUT_TIME     60000
+#define DEFAULT_MAX_MISORDER_TIME    2000
+
+enum
+{
+  PROP_0,
+  PROP_SSRC,
+  PROP_IS_CSRC,
+  PROP_IS_VALIDATED,
+  PROP_IS_SENDER,
+  PROP_SDES,
+  PROP_STATS,
+  PROP_PROBATION,
+  PROP_MAX_DROPOUT_TIME,
+  PROP_MAX_MISORDER_TIME
+};
+
+/* GObject vmethods */
+static void rtp_source_finalize (GObject * object);
+static void rtp_source_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void rtp_source_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+/* static guint rtp_source_signals[LAST_SIGNAL] = { 0 }; */
+
+G_DEFINE_TYPE (RTPSource, rtp_source, G_TYPE_OBJECT);
+
+static void
+rtp_source_class_init (RTPSourceClass * klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = (GObjectClass *) klass;
+
+  gobject_class->finalize = rtp_source_finalize;
+
+  gobject_class->set_property = rtp_source_set_property;
+  gobject_class->get_property = rtp_source_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_SSRC,
+      g_param_spec_uint ("ssrc", "SSRC",
+          "The SSRC of this source", 0, G_MAXUINT, DEFAULT_SSRC,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_IS_CSRC,
+      g_param_spec_boolean ("is-csrc", "Is CSRC",
+          "If this SSRC is acting as a contributing source",
+          DEFAULT_IS_CSRC, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_IS_VALIDATED,
+      g_param_spec_boolean ("is-validated", "Is Validated",
+          "If this SSRC is validated", DEFAULT_IS_VALIDATED,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_IS_SENDER,
+      g_param_spec_boolean ("is-sender", "Is Sender",
+          "If this SSRC is a sender", DEFAULT_IS_SENDER,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * RTPSource::sdes
+   *
+   * The current SDES items of the source. Returns a structure with name
+   * application/x-rtp-source-sdes and may contain the following fields:
+   *
+   *  'cname'       G_TYPE_STRING  : The canonical name in the form user@host
+   *  'name'        G_TYPE_STRING  : The user name
+   *  'email'       G_TYPE_STRING  : The user's electronic mail address
+   *  'phone'       G_TYPE_STRING  : The user's phone number
+   *  'location'    G_TYPE_STRING  : The geographic user location
+   *  'tool'        G_TYPE_STRING  : The name of application or tool
+   *  'note'        G_TYPE_STRING  : A notice about the source
+   *
+   *  Other fields may be present and these represent private items in
+   *  the SDES where the field name is the prefix.
+   */
+  g_object_class_install_property (gobject_class, PROP_SDES,
+      g_param_spec_boxed ("sdes", "SDES",
+          "The SDES information for this source",
+          GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * RTPSource::stats
+   *
+   * This property returns a GstStructure named application/x-rtp-source-stats with
+   * fields useful for statistics and diagnostics.
+   *
+   * Take note of each respective field's units:
+   *
+   * - NTP times are in the appropriate 32-bit or 64-bit fixed-point format
+   *   starting from January 1, 1970 (except for timespans).
+   * - RTP times are in clock rate units (i.e. clock rate = 1 second)
+   *   starting at a random offset.
+   * - For fields indicating packet loss, note that late packets are not considered lost,
+   *   and duplicates are not taken into account. Hence, the loss may be negative
+   *   if there are duplicates.
+   *
+   * The following fields are always present.
+   *
+   *  "ssrc"         G_TYPE_UINT     the SSRC of this source
+   *  "internal"     G_TYPE_BOOLEAN  this source is a source of the session
+   *  "validated"    G_TYPE_BOOLEAN  the source is validated
+   *  "received-bye" G_TYPE_BOOLEAN  we received a BYE from this source
+   *  "is-csrc"      G_TYPE_BOOLEAN  this source was found as CSRC
+   *  "is-sender"    G_TYPE_BOOLEAN  this source is a sender
+   *  "seqnum-base"  G_TYPE_INT      first seqnum if known
+   *  "clock-rate"   G_TYPE_INT      the clock rate of the media
+   *
+   * The following fields are only present when known.
+   *
+   *  "rtp-from"     G_TYPE_STRING   where we received the last RTP packet from
+   *  "rtcp-from"    G_TYPE_STRING   where we received the last RTCP packet from
+   *
+   * The following fields make sense for internal sources and will only increase
+   * when "is-sender" is TRUE.
+   *
+   *  "octets-sent"  G_TYPE_UINT64   number of bytes we sent
+   *  "packets-sent" G_TYPE_UINT64   number of packets we sent
+   *
+   * The following fields make sense for non-internal sources and will only
+   * increase when "is-sender" is TRUE.
+   *
+   *  "octets-received"  G_TYPE_UINT64  total number of bytes received
+   *  "packets-received" G_TYPE_UINT64  total number of packets received
+   *
+   * Following fields are updated when "is-sender" is TRUE.
+   *
+   *  "bitrate"      G_TYPE_UINT64   bitrate in bits per second
+   *  "jitter"       G_TYPE_UINT     estimated jitter (in clock rate units)
+   *  "packets-lost" G_TYPE_INT      estimated amount of packets lost
+   *
+   * The last SR report this source sent. This only updates when "is-sender" is
+   * TRUE.
+   *
+   *  "have-sr"         G_TYPE_BOOLEAN  the source has sent SR
+   *  "sr-ntptime"      G_TYPE_UINT64   NTP time of SR (in NTP Timestamp Format, 32.32 fixed point)
+   *  "sr-rtptime"      G_TYPE_UINT     RTP time of SR (in clock rate units)
+   *  "sr-octet-count"  G_TYPE_UINT     the number of bytes in the SR
+   *  "sr-packet-count" G_TYPE_UINT     the number of packets in the SR
+   *
+   * The following fields are only present for non-internal sources and
+   * represent the content of the last RB packet that was sent to this source.
+   * These values are only updated when the source is sending.
+   *
+   *  "sent-rb"               G_TYPE_BOOLEAN  we have sent an RB
+   *  "sent-rb-fractionlost"  G_TYPE_UINT     calculated lost 8-bit fraction
+   *  "sent-rb-packetslost"   G_TYPE_INT      lost packets
+   *  "sent-rb-exthighestseq" G_TYPE_UINT     last seen seqnum
+   *  "sent-rb-jitter"        G_TYPE_UINT     jitter (in clock rate units)
+   *  "sent-rb-lsr"           G_TYPE_UINT     last SR time (seconds in NTP Short Format, 16.16 fixed point)
+   *  "sent-rb-dlsr"          G_TYPE_UINT     delay since last SR (seconds in NTP Short Format, 16.16 fixed point)
+   *
+   * The following fields are only present for non-internal sources and
+   * represents the last RB that this source sent. This is only updated
+   * when the source is receiving data and sending RB blocks.
+   *
+   *  "have-rb"          G_TYPE_BOOLEAN  the source has sent RB
+   *  "rb-fractionlost"  G_TYPE_UINT     lost 8-bit fraction
+   *  "rb-packetslost"   G_TYPE_INT      lost packets
+   *  "rb-exthighestseq" G_TYPE_UINT     highest received seqnum
+   *  "rb-jitter"        G_TYPE_UINT     reception jitter (in clock rate units)
+   *  "rb-lsr"           G_TYPE_UINT     last SR time (seconds in NTP Short Format, 16.16 fixed point)
+   *  "rb-dlsr"          G_TYPE_UINT     delay since last SR (seconds in NTP Short Format, 16.16 fixed point)
+   *
+   * The round trip of this source is calculated from the last RB
+   * values and the reception time of the last RB packet. It is only present for
+   * non-internal sources.
+   *
+   *  "rb-round-trip"    G_TYPE_UINT     the round-trip time (seconds in NTP Short Format, 16.16 fixed point)
+   *
+   */
+  g_object_class_install_property (gobject_class, PROP_STATS,
+      g_param_spec_boxed ("stats", "Stats",
+          "The stats of this source", GST_TYPE_STRUCTURE,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_PROBATION,
+      g_param_spec_uint ("probation", "Number of probations",
+          "Consecutive packet sequence numbers to accept the source",
+          0, G_MAXUINT, DEFAULT_PROBATION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_DROPOUT_TIME,
+      g_param_spec_uint ("max-dropout-time", "Max dropout time",
+          "The maximum time (milliseconds) of missing packets tolerated.",
+          0, G_MAXUINT, DEFAULT_MAX_DROPOUT_TIME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_MISORDER_TIME,
+      g_param_spec_uint ("max-misorder-time", "Max misorder time",
+          "The maximum time (milliseconds) of misordered packets tolerated.",
+          0, G_MAXUINT, DEFAULT_MAX_MISORDER_TIME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  GST_DEBUG_CATEGORY_INIT (rtp_source_debug, "rtpsource", 0, "RTP Source");
+}
+
+/**
+ * rtp_source_reset:
+ * @src: an #RTPSource
+ *
+ * Reset the stats of @src.
+ */
+void
+rtp_source_reset (RTPSource * src)
+{
+  src->marked_bye = FALSE;
+  if (src->bye_reason)
+    g_free (src->bye_reason);
+  src->bye_reason = NULL;
+  src->sent_bye = FALSE;
+  g_hash_table_remove_all (src->reported_in_sr_of);
+
+  src->stats.cycles = -1;
+  src->stats.jitter = 0;
+  src->stats.transit = -1;
+  src->stats.curr_sr = 0;
+  src->stats.sr[0].is_valid = FALSE;
+  src->stats.curr_rr = 0;
+  src->stats.rr[0].is_valid = FALSE;
+  src->stats.prev_rtptime = GST_CLOCK_TIME_NONE;
+  src->stats.prev_rtcptime = GST_CLOCK_TIME_NONE;
+  src->stats.last_rtptime = GST_CLOCK_TIME_NONE;
+  src->stats.last_rtcptime = GST_CLOCK_TIME_NONE;
+  g_array_set_size (src->nacks, 0);
+
+  src->stats.sent_pli_count = 0;
+  src->stats.sent_fir_count = 0;
+  src->stats.sent_nack_count = 0;
+  src->stats.recv_nack_count = 0;
+}
+
+static void
+rtp_source_init (RTPSource * src)
+{
+  /* sources are initialy on probation until we receive enough valid RTP
+   * packets or a valid RTCP packet */
+  src->validated = FALSE;
+  src->internal = FALSE;
+  src->probation = DEFAULT_PROBATION;
+  src->curr_probation = src->probation;
+  src->closing = FALSE;
+  src->max_dropout_time = DEFAULT_MAX_DROPOUT_TIME;
+  src->max_misorder_time = DEFAULT_MAX_MISORDER_TIME;
+
+  src->sdes = gst_structure_new_empty ("application/x-rtp-source-sdes");
+
+  src->payload = -1;
+  src->clock_rate = -1;
+  src->packets = g_queue_new ();
+  src->seqnum_offset = -1;
+  src->last_rtptime = -1;
+
+  src->retained_feedback = g_queue_new ();
+  src->nacks = g_array_new (FALSE, FALSE, sizeof (guint32));
+
+  src->reported_in_sr_of = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  src->last_keyframe_request = GST_CLOCK_TIME_NONE;
+
+  rtp_source_reset (src);
+
+  src->pt_set = FALSE;
+}
+
+void
+rtp_conflicting_address_free (RTPConflictingAddress * addr)
+{
+  g_object_unref (addr->address);
+  g_slice_free (RTPConflictingAddress, addr);
+}
+
+static void
+rtp_source_finalize (GObject * object)
+{
+  RTPSource *src;
+
+  src = RTP_SOURCE_CAST (object);
+
+  g_queue_foreach (src->packets, (GFunc) gst_buffer_unref, NULL);
+  g_queue_free (src->packets);
+
+  gst_structure_free (src->sdes);
+
+  g_free (src->bye_reason);
+
+  gst_caps_replace (&src->caps, NULL);
+
+  g_list_free_full (src->conflicting_addresses,
+      (GDestroyNotify) rtp_conflicting_address_free);
+  g_queue_foreach (src->retained_feedback, (GFunc) gst_buffer_unref, NULL);
+  g_queue_free (src->retained_feedback);
+
+  g_array_free (src->nacks, TRUE);
+
+  if (src->rtp_from)
+    g_object_unref (src->rtp_from);
+  if (src->rtcp_from)
+    g_object_unref (src->rtcp_from);
+
+  g_hash_table_unref (src->reported_in_sr_of);
+
+  G_OBJECT_CLASS (rtp_source_parent_class)->finalize (object);
+}
+
+static GstStructure *
+rtp_source_create_stats (RTPSource * src)
+{
+  GstStructure *s;
+  gboolean is_sender = src->is_sender;
+  gboolean internal = src->internal;
+  gchar *address_str;
+  gboolean have_rb;
+  guint8 fractionlost = 0;
+  gint32 packetslost = 0;
+  guint32 exthighestseq = 0;
+  guint32 jitter = 0;
+  guint32 lsr = 0;
+  guint32 dlsr = 0;
+  guint32 round_trip = 0;
+  gboolean have_sr;
+  GstClockTime time = 0;
+  guint64 ntptime = 0;
+  guint32 rtptime = 0;
+  guint32 packet_count = 0;
+  guint32 octet_count = 0;
+
+
+  /* common data for all types of sources */
+  s = gst_structure_new ("application/x-rtp-source-stats",
+      "ssrc", G_TYPE_UINT, (guint) src->ssrc,
+      "internal", G_TYPE_BOOLEAN, internal,
+      "validated", G_TYPE_BOOLEAN, src->validated,
+      "received-bye", G_TYPE_BOOLEAN, src->marked_bye,
+      "is-csrc", G_TYPE_BOOLEAN, src->is_csrc,
+      "is-sender", G_TYPE_BOOLEAN, is_sender,
+      "seqnum-base", G_TYPE_INT, src->seqnum_offset,
+      "clock-rate", G_TYPE_INT, src->clock_rate, NULL);
+
+  /* add address and port */
+  if (src->rtp_from) {
+    address_str = __g_socket_address_to_string (src->rtp_from);
+    gst_structure_set (s, "rtp-from", G_TYPE_STRING, address_str, NULL);
+    g_free (address_str);
+  }
+  if (src->rtcp_from) {
+    address_str = __g_socket_address_to_string (src->rtcp_from);
+    gst_structure_set (s, "rtcp-from", G_TYPE_STRING, address_str, NULL);
+    g_free (address_str);
+  }
+
+  gst_structure_set (s,
+      "octets-sent", G_TYPE_UINT64, src->stats.octets_sent,
+      "packets-sent", G_TYPE_UINT64, src->stats.packets_sent,
+      "octets-received", G_TYPE_UINT64, src->stats.octets_received,
+      "packets-received", G_TYPE_UINT64, src->stats.packets_received,
+      "bitrate", G_TYPE_UINT64, src->bitrate,
+      "packets-lost", G_TYPE_INT,
+      (gint) rtp_stats_get_packets_lost (&src->stats), "jitter", G_TYPE_UINT,
+      (guint) (src->stats.jitter >> 4),
+      "sent-pli-count", G_TYPE_UINT, src->stats.sent_pli_count,
+      "recv-pli-count", G_TYPE_UINT, src->stats.recv_pli_count,
+      "sent-fir-count", G_TYPE_UINT, src->stats.sent_fir_count,
+      "recv-fir-count", G_TYPE_UINT, src->stats.recv_fir_count,
+      "sent-nack-count", G_TYPE_UINT, src->stats.sent_nack_count,
+      "recv-nack-count", G_TYPE_UINT, src->stats.recv_nack_count, NULL);
+
+  /* get the last SR. */
+  have_sr = rtp_source_get_last_sr (src, &time, &ntptime, &rtptime,
+      &packet_count, &octet_count);
+  gst_structure_set (s,
+      "have-sr", G_TYPE_BOOLEAN, have_sr,
+      "sr-ntptime", G_TYPE_UINT64, ntptime,
+      "sr-rtptime", G_TYPE_UINT, (guint) rtptime,
+      "sr-octet-count", G_TYPE_UINT, (guint) octet_count,
+      "sr-packet-count", G_TYPE_UINT, (guint) packet_count, NULL);
+
+  if (!internal) {
+    /* get the last RB we sent */
+    gst_structure_set (s,
+        "sent-rb", G_TYPE_BOOLEAN, src->last_rr.is_valid,
+        "sent-rb-fractionlost", G_TYPE_UINT, (guint) src->last_rr.fractionlost,
+        "sent-rb-packetslost", G_TYPE_INT, (gint) src->last_rr.packetslost,
+        "sent-rb-exthighestseq", G_TYPE_UINT,
+        (guint) src->last_rr.exthighestseq, "sent-rb-jitter", G_TYPE_UINT,
+        (guint) src->last_rr.jitter, "sent-rb-lsr", G_TYPE_UINT,
+        (guint) src->last_rr.lsr, "sent-rb-dlsr", G_TYPE_UINT,
+        (guint) src->last_rr.dlsr, NULL);
+
+    /* get the last RB */
+    have_rb = rtp_source_get_last_rb (src, &fractionlost, &packetslost,
+        &exthighestseq, &jitter, &lsr, &dlsr, &round_trip);
+
+    gst_structure_set (s,
+        "have-rb", G_TYPE_BOOLEAN, have_rb,
+        "rb-fractionlost", G_TYPE_UINT, (guint) fractionlost,
+        "rb-packetslost", G_TYPE_INT, (gint) packetslost,
+        "rb-exthighestseq", G_TYPE_UINT, (guint) exthighestseq,
+        "rb-jitter", G_TYPE_UINT, (guint) jitter,
+        "rb-lsr", G_TYPE_UINT, (guint) lsr,
+        "rb-dlsr", G_TYPE_UINT, (guint) dlsr,
+        "rb-round-trip", G_TYPE_UINT, (guint) round_trip, NULL);
+  }
+
+  return s;
+}
+
+/**
+ * rtp_source_get_sdes_struct:
+ * @src: an #RTPSource
+ *
+ * Get the SDES from @src. See the SDES property for more details.
+ *
+ * Returns: %GstStructure of type "application/x-rtp-source-sdes". The result is
+ * valid until the SDES items of @src are modified.
+ */
+const GstStructure *
+rtp_source_get_sdes_struct (RTPSource * src)
+{
+  g_return_val_if_fail (RTP_IS_SOURCE (src), NULL);
+
+  return src->sdes;
+}
+
+static gboolean
+sdes_struct_compare_func (GQuark field_id, const GValue * value,
+    gpointer user_data)
+{
+  GstStructure *old;
+  const gchar *field;
+
+  old = GST_STRUCTURE (user_data);
+  field = g_quark_to_string (field_id);
+
+  if (!gst_structure_has_field (old, field))
+    return FALSE;
+
+  g_assert (G_VALUE_HOLDS_STRING (value));
+
+  return strcmp (g_value_get_string (value), gst_structure_get_string (old,
+          field)) == 0;
+}
+
+/**
+ * rtp_source_set_sdes_struct:
+ * @src: an #RTPSource
+ * @sdes: the SDES structure
+ *
+ * Store the @sdes in @src. @sdes must be a structure of type
+ * "application/x-rtp-source-sdes", see the SDES property for more details.
+ *
+ * This function takes ownership of @sdes.
+ *
+ * Returns: %FALSE if the SDES was unchanged.
+ */
+gboolean
+rtp_source_set_sdes_struct (RTPSource * src, GstStructure * sdes)
+{
+  gboolean changed;
+
+  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
+  g_return_val_if_fail (strcmp (gst_structure_get_name (sdes),
+          "application/x-rtp-source-sdes") == 0, FALSE);
+
+  changed = !gst_structure_foreach (sdes, sdes_struct_compare_func, src->sdes);
+
+  if (changed) {
+    gst_structure_free (src->sdes);
+    src->sdes = sdes;
+  } else {
+    gst_structure_free (sdes);
+  }
+  return changed;
+}
+
+static void
+rtp_source_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  RTPSource *src;
+
+  src = RTP_SOURCE (object);
+
+  switch (prop_id) {
+    case PROP_SSRC:
+      src->ssrc = g_value_get_uint (value);
+      break;
+    case PROP_PROBATION:
+      src->probation = g_value_get_uint (value);
+      break;
+    case PROP_MAX_DROPOUT_TIME:
+      src->max_dropout_time = g_value_get_uint (value);
+      break;
+    case PROP_MAX_MISORDER_TIME:
+      src->max_misorder_time = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+rtp_source_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  RTPSource *src;
+
+  src = RTP_SOURCE (object);
+
+  switch (prop_id) {
+    case PROP_SSRC:
+      g_value_set_uint (value, rtp_source_get_ssrc (src));
+      break;
+    case PROP_IS_CSRC:
+      g_value_set_boolean (value, rtp_source_is_as_csrc (src));
+      break;
+    case PROP_IS_VALIDATED:
+      g_value_set_boolean (value, rtp_source_is_validated (src));
+      break;
+    case PROP_IS_SENDER:
+      g_value_set_boolean (value, rtp_source_is_sender (src));
+      break;
+    case PROP_SDES:
+      g_value_set_boxed (value, rtp_source_get_sdes_struct (src));
+      break;
+    case PROP_STATS:
+      g_value_take_boxed (value, rtp_source_create_stats (src));
+      break;
+    case PROP_PROBATION:
+      g_value_set_uint (value, src->probation);
+      break;
+    case PROP_MAX_DROPOUT_TIME:
+      g_value_set_uint (value, src->max_dropout_time);
+      break;
+    case PROP_MAX_MISORDER_TIME:
+      g_value_set_uint (value, src->max_misorder_time);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/**
+ * rtp_source_new:
+ * @ssrc: an SSRC
+ *
+ * Create a #RTPSource with @ssrc.
+ *
+ * Returns: a new #RTPSource. Use g_object_unref() after usage.
+ */
+RTPSource *
+rtp_source_new (guint32 ssrc)
+{
+  RTPSource *src;
+
+  src = g_object_new (RTP_TYPE_SOURCE, NULL);
+  src->ssrc = ssrc;
+
+  return src;
+}
+
+/**
+ * rtp_source_set_callbacks:
+ * @src: an #RTPSource
+ * @cb: callback functions
+ * @user_data: user data
+ *
+ * Set the callbacks for the source.
+ */
+void
+rtp_source_set_callbacks (RTPSource * src, RTPSourceCallbacks * cb,
+    gpointer user_data)
+{
+  g_return_if_fail (RTP_IS_SOURCE (src));
+
+  src->callbacks.push_rtp = cb->push_rtp;
+  src->callbacks.clock_rate = cb->clock_rate;
+  src->user_data = user_data;
+}
+
+/**
+ * rtp_source_get_ssrc:
+ * @src: an #RTPSource
+ *
+ * Get the SSRC of @source.
+ *
+ * Returns: the SSRC of src.
+ */
+guint32
+rtp_source_get_ssrc (RTPSource * src)
+{
+  guint32 result;
+
+  g_return_val_if_fail (RTP_IS_SOURCE (src), 0);
+
+  result = src->ssrc;
+
+  return result;
+}
+
+/**
+ * rtp_source_set_as_csrc:
+ * @src: an #RTPSource
+ *
+ * Configure @src as a CSRC, this will also validate @src.
+ */
+void
+rtp_source_set_as_csrc (RTPSource * src)
+{
+  g_return_if_fail (RTP_IS_SOURCE (src));
+
+  src->validated = TRUE;
+  src->is_csrc = TRUE;
+}
+
+/**
+ * rtp_source_is_as_csrc:
+ * @src: an #RTPSource
+ *
+ * Check if @src is a contributing source.
+ *
+ * Returns: %TRUE if @src is acting as a contributing source.
+ */
+gboolean
+rtp_source_is_as_csrc (RTPSource * src)
+{
+  gboolean result;
+
+  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
+
+  result = src->is_csrc;
+
+  return result;
+}
+
+/**
+ * rtp_source_is_active:
+ * @src: an #RTPSource
+ *
+ * Check if @src is an active source. A source is active if it has been
+ * validated and has not yet received a BYE packet
+ *
+ * Returns: %TRUE if @src is an qactive source.
+ */
+gboolean
+rtp_source_is_active (RTPSource * src)
+{
+  gboolean result;
+
+  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
+
+  result = RTP_SOURCE_IS_ACTIVE (src);
+
+  return result;
+}
+
+/**
+ * rtp_source_is_validated:
+ * @src: an #RTPSource
+ *
+ * Check if @src is a validated source.
+ *
+ * Returns: %TRUE if @src is a validated source.
+ */
+gboolean
+rtp_source_is_validated (RTPSource * src)
+{
+  gboolean result;
+
+  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
+
+  result = src->validated;
+
+  return result;
+}
+
+/**
+ * rtp_source_is_sender:
+ * @src: an #RTPSource
+ *
+ * Check if @src is a sending source.
+ *
+ * Returns: %TRUE if @src is a sending source.
+ */
+gboolean
+rtp_source_is_sender (RTPSource * src)
+{
+  gboolean result;
+
+  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
+
+  result = RTP_SOURCE_IS_SENDER (src);
+
+  return result;
+}
+
+/**
+ * rtp_source_is_marked_bye:
+ * @src: an #RTPSource
+ *
+ * Check if @src is marked as leaving the session with a BYE packet.
+ *
+ * Returns: %TRUE if @src has been marked BYE.
+ */
+gboolean
+rtp_source_is_marked_bye (RTPSource * src)
+{
+  gboolean result;
+
+  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
+
+  result = RTP_SOURCE_IS_MARKED_BYE (src);
+
+  return result;
+}
+
+
+/**
+ * rtp_source_get_bye_reason:
+ * @src: an #RTPSource
+ *
+ * Get the BYE reason for @src. Check if the source is marked as leaving the
+ * session with a BYE message first with rtp_source_is_marked_bye().
+ *
+ * Returns: The BYE reason or NULL when no reason was given or the source was
+ * not marked BYE yet. g_free() after usage.
+ */
+gchar *
+rtp_source_get_bye_reason (RTPSource * src)
+{
+  gchar *result;
+
+  g_return_val_if_fail (RTP_IS_SOURCE (src), NULL);
+
+  result = g_strdup (src->bye_reason);
+
+  return result;
+}
+
+/**
+ * rtp_source_update_caps:
+ * @src: an #RTPSource
+ * @caps: a #GstCaps
+ *
+ * Parse @caps and store all relevant information in @source.
+ */
+void
+rtp_source_update_caps (RTPSource * src, GstCaps * caps)
+{
+  GstStructure *s;
+  guint val;
+  gint ival;
+  gboolean rtx;
+
+  /* nothing changed, return */
+  if (caps == NULL || src->caps == caps)
+    return;
+
+  s = gst_caps_get_structure (caps, 0);
+
+  rtx = (gst_structure_get_uint (s, "rtx-ssrc", &val) && val == src->ssrc);
+
+  if (gst_structure_get_int (s, rtx ? "rtx-payload" : "payload", &ival))
+    src->payload = ival;
+  else
+    src->payload = -1;
+
+  GST_DEBUG ("got %spayload %d", rtx ? "rtx " : "", src->payload);
+
+  if (gst_structure_get_int (s, "clock-rate", &ival))
+    src->clock_rate = ival;
+  else
+    src->clock_rate = -1;
+
+  GST_DEBUG ("got clock-rate %d", src->clock_rate);
+
+  if (gst_structure_get_uint (s, rtx ? "rtx-seqnum-offset" : "seqnum-offset",
+          &val))
+    src->seqnum_offset = val;
+  else
+    src->seqnum_offset = -1;
+
+  GST_DEBUG ("got %sseqnum-offset %" G_GINT32_FORMAT, rtx ? "rtx " : "",
+      src->seqnum_offset);
+
+  gst_caps_replace (&src->caps, caps);
+}
+
+/**
+ * rtp_source_set_rtp_from:
+ * @src: an #RTPSource
+ * @address: the RTP address to set
+ *
+ * Set that @src is receiving RTP packets from @address. This is used for
+ * collistion checking.
+ */
+void
+rtp_source_set_rtp_from (RTPSource * src, GSocketAddress * address)
+{
+  g_return_if_fail (RTP_IS_SOURCE (src));
+
+  if (src->rtp_from)
+    g_object_unref (src->rtp_from);
+  src->rtp_from = G_SOCKET_ADDRESS (g_object_ref (address));
+}
+
+/**
+ * rtp_source_set_rtcp_from:
+ * @src: an #RTPSource
+ * @address: the RTCP address to set
+ *
+ * Set that @src is receiving RTCP packets from @address. This is used for
+ * collistion checking.
+ */
+void
+rtp_source_set_rtcp_from (RTPSource * src, GSocketAddress * address)
+{
+  g_return_if_fail (RTP_IS_SOURCE (src));
+
+  if (src->rtcp_from)
+    g_object_unref (src->rtcp_from);
+  src->rtcp_from = G_SOCKET_ADDRESS (g_object_ref (address));
+}
+
+static GstFlowReturn
+push_packet (RTPSource * src, GstBuffer * buffer)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  /* push queued packets first if any */
+  while (!g_queue_is_empty (src->packets)) {
+    GstBuffer *buffer = GST_BUFFER_CAST (g_queue_pop_head (src->packets));
+
+    GST_LOG ("pushing queued packet");
+    if (src->callbacks.push_rtp)
+      src->callbacks.push_rtp (src, buffer, src->user_data);
+    else
+      gst_buffer_unref (buffer);
+  }
+  GST_LOG ("pushing new packet");
+  /* push packet */
+  if (src->callbacks.push_rtp)
+    ret = src->callbacks.push_rtp (src, buffer, src->user_data);
+  else
+    gst_buffer_unref (buffer);
+
+  return ret;
+}
+
+static gint
+get_clock_rate (RTPSource * src, guint8 payload)
+{
+  if (src->payload == -1) {
+    /* first payload received, nothing was in the caps, lock on to this payload */
+    src->payload = payload;
+    GST_DEBUG ("first payload %d", payload);
+  } else if (payload != src->payload) {
+    /* we have a different payload than before, reset the clock-rate */
+    GST_DEBUG ("new payload %d", payload);
+    src->payload = payload;
+    src->clock_rate = -1;
+    src->stats.transit = -1;
+  }
+
+  if (src->clock_rate == -1) {
+    gint clock_rate = -1;
+
+    if (src->callbacks.clock_rate)
+      clock_rate = src->callbacks.clock_rate (src, payload, src->user_data);
+
+    GST_DEBUG ("got clock-rate %d", clock_rate);
+
+    src->clock_rate = clock_rate;
+    gst_rtp_packet_rate_ctx_reset (&src->packet_rate_ctx, clock_rate);
+  }
+  return src->clock_rate;
+}
+
+/* Jitter is the variation in the delay of received packets in a flow. It is
+ * measured by comparing the interval when RTP packets were sent to the interval
+ * at which they were received. For instance, if packet #1 and packet #2 leave
+ * 50 milliseconds apart and arrive 60 milliseconds apart, then the jitter is 10
+ * milliseconds. */
+static void
+calculate_jitter (RTPSource * src, RTPPacketInfo * pinfo)
+{
+  GstClockTime running_time;
+  guint32 rtparrival, transit, rtptime;
+  gint32 diff;
+  gint clock_rate;
+  guint8 pt;
+
+  /* get arrival time */
+  if ((running_time = pinfo->running_time) == GST_CLOCK_TIME_NONE)
+    goto no_time;
+
+  pt = pinfo->pt;
+
+  GST_LOG ("SSRC %08x got payload %d", src->ssrc, pt);
+
+  /* get clockrate */
+  if ((clock_rate = get_clock_rate (src, pt)) == -1)
+    goto no_clock_rate;
+
+  rtptime = pinfo->rtptime;
+
+  /* convert arrival time to RTP timestamp units, truncate to 32 bits, we don't
+   * care about the absolute value, just the difference. */
+  rtparrival = gst_util_uint64_scale_int (running_time, clock_rate, GST_SECOND);
+
+  /* transit time is difference with RTP timestamp */
+  transit = rtparrival - rtptime;
+
+  /* get ABS diff with previous transit time */
+  if (src->stats.transit != -1) {
+    if (transit > src->stats.transit)
+      diff = transit - src->stats.transit;
+    else
+      diff = src->stats.transit - transit;
+  } else
+    diff = 0;
+
+  src->stats.transit = transit;
+
+  /* update jitter, the value we store is scaled up so we can keep precision. */
+  src->stats.jitter += diff - ((src->stats.jitter + 8) >> 4);
+
+  src->stats.prev_rtptime = src->stats.last_rtptime;
+  src->stats.last_rtptime = rtparrival;
+
+  GST_LOG ("rtparrival %u, rtptime %u, clock-rate %d, diff %d, jitter: %f",
+      rtparrival, rtptime, clock_rate, diff, (src->stats.jitter) / 16.0);
+
+  return;
+
+  /* ERRORS */
+no_time:
+  {
+    GST_WARNING ("cannot get current running_time");
+    return;
+  }
+no_clock_rate:
+  {
+    GST_WARNING ("cannot get clock-rate for pt %d", pt);
+    return;
+  }
+}
+
+static void
+init_seq (RTPSource * src, guint16 seq)
+{
+  src->stats.base_seq = seq;
+  src->stats.max_seq = seq;
+  src->stats.bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */
+  src->stats.cycles = 0;
+  src->stats.packets_received = 0;
+  src->stats.octets_received = 0;
+  src->stats.bytes_received = 0;
+  src->stats.prev_received = 0;
+  src->stats.prev_expected = 0;
+  src->stats.recv_pli_count = 0;
+  src->stats.recv_fir_count = 0;
+
+  GST_DEBUG ("base_seq %d", seq);
+}
+
+#define BITRATE_INTERVAL (2 * GST_SECOND)
+
+static void
+do_bitrate_estimation (RTPSource * src, GstClockTime running_time,
+    guint64 * bytes_handled)
+{
+  guint64 elapsed;
+
+  if (src->prev_rtime) {
+    elapsed = running_time - src->prev_rtime;
+
+    if (elapsed > BITRATE_INTERVAL) {
+      guint64 rate;
+
+      rate = gst_util_uint64_scale (*bytes_handled, 8 * GST_SECOND, elapsed);
+
+      GST_LOG ("Elapsed %" G_GUINT64_FORMAT ", bytes %" G_GUINT64_FORMAT
+          ", rate %" G_GUINT64_FORMAT, elapsed, *bytes_handled, rate);
+
+      if (src->bitrate == 0)
+        src->bitrate = rate;
+      else
+        src->bitrate = ((src->bitrate * 3) + rate) / 4;
+
+      src->prev_rtime = running_time;
+      *bytes_handled = 0;
+    }
+  } else {
+    GST_LOG ("Reset bitrate measurement");
+    src->prev_rtime = running_time;
+    src->bitrate = 0;
+  }
+}
+
+static gboolean
+update_receiver_stats (RTPSource * src, RTPPacketInfo * pinfo,
+    gboolean is_receive)
+{
+  guint16 seqnr, expected;
+  RTPSourceStats *stats;
+  gint16 delta;
+  gint32 packet_rate, max_dropout, max_misorder;
+
+  stats = &src->stats;
+
+  seqnr = pinfo->seqnum;
+
+  packet_rate =
+      gst_rtp_packet_rate_ctx_update (&src->packet_rate_ctx, pinfo->seqnum,
+      pinfo->rtptime);
+  max_dropout =
+      gst_rtp_packet_rate_ctx_get_max_dropout (&src->packet_rate_ctx,
+      src->max_dropout_time);
+  max_misorder =
+      gst_rtp_packet_rate_ctx_get_max_misorder (&src->packet_rate_ctx,
+      src->max_misorder_time);
+  GST_TRACE ("SSRC %08x, packet_rate: %d, max_dropout: %d, max_misorder: %d",
+      src->ssrc, packet_rate, max_dropout, max_misorder);
+
+  if (stats->cycles == -1) {
+    GST_DEBUG ("received first packet");
+    /* first time we heard of this source */
+    init_seq (src, seqnr);
+    src->stats.max_seq = seqnr - 1;
+    src->curr_probation = src->probation;
+  }
+
+  if (is_receive) {
+    expected = src->stats.max_seq + 1;
+    delta = gst_rtp_buffer_compare_seqnum (expected, seqnr);
+
+    /* if we are still on probation, check seqnum */
+    if (src->curr_probation) {
+      /* when in probation, we require consecutive seqnums */
+      if (delta == 0) {
+        /* expected packet */
+        GST_DEBUG ("probation: seqnr %d == expected %d", seqnr, expected);
+        src->curr_probation--;
+        if (seqnr < stats->max_seq) {
+          /* sequence number wrapped - count another 64K cycle. */
+          stats->cycles += RTP_SEQ_MOD;
+        }
+        src->stats.max_seq = seqnr;
+
+        if (src->curr_probation == 0) {
+          GST_DEBUG ("probation done!");
+          init_seq (src, seqnr);
+        } else {
+          GstBuffer *q;
+
+          GST_DEBUG ("probation %d: queue packet", src->curr_probation);
+          /* when still in probation, keep packets in a list. */
+          g_queue_push_tail (src->packets, pinfo->data);
+          pinfo->data = NULL;
+          /* remove packets from queue if there are too many */
+          while (g_queue_get_length (src->packets) > RTP_MAX_PROBATION_LEN) {
+            q = g_queue_pop_head (src->packets);
+            gst_buffer_unref (q);
+          }
+          goto done;
+        }
+      } else {
+        /* unexpected seqnum in probation */
+        goto probation_seqnum;
+      }
+    } else if (delta >= 0 && delta < max_dropout) {
+      /* Clear bad packets */
+      stats->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */
+      g_queue_foreach (src->packets, (GFunc) gst_buffer_unref, NULL);
+      g_queue_clear (src->packets);
+
+      /* in order, with permissible gap */
+      if (seqnr < stats->max_seq) {
+        /* sequence number wrapped - count another 64K cycle. */
+        stats->cycles += RTP_SEQ_MOD;
+      }
+      stats->max_seq = seqnr;
+    } else if (delta < -max_misorder || delta >= max_dropout) {
+      /* the sequence number made a very large jump */
+      if (seqnr == stats->bad_seq && src->packets->head) {
+        /* two sequential packets -- assume that the other side
+         * restarted without telling us so just re-sync
+         * (i.e., pretend this was the first packet).  */
+        init_seq (src, seqnr);
+      } else {
+        /* unacceptable jump */
+        stats->bad_seq = (seqnr + 1) & (RTP_SEQ_MOD - 1);
+        g_queue_foreach (src->packets, (GFunc) gst_buffer_unref, NULL);
+        g_queue_clear (src->packets);
+        g_queue_push_tail (src->packets, pinfo->data);
+        pinfo->data = NULL;
+        goto bad_sequence;
+      }
+    } else {                    /* delta < 0 && delta >= -max_misorder */
+      /* Clear bad packets */
+      stats->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */
+      g_queue_foreach (src->packets, (GFunc) gst_buffer_unref, NULL);
+      g_queue_clear (src->packets);
+
+      /* duplicate or reordered packet, will be filtered by jitterbuffer. */
+      GST_INFO ("duplicate or reordered packet (seqnr %u, expected %u)",
+          seqnr, expected);
+    }
+  }
+
+  src->stats.octets_received += pinfo->payload_len;
+  src->stats.bytes_received += pinfo->bytes;
+  src->stats.packets_received++;
+  /* for the bitrate estimation */
+  src->bytes_received += pinfo->payload_len;
+
+  GST_LOG ("seq %u, PC: %" G_GUINT64_FORMAT ", OC: %" G_GUINT64_FORMAT,
+      seqnr, src->stats.packets_received, src->stats.octets_received);
+
+  return TRUE;
+
+  /* ERRORS */
+done:
+  {
+    return FALSE;
+  }
+bad_sequence:
+  {
+    GST_WARNING
+        ("unacceptable seqnum received (seqnr %u, delta %d, packet_rate: %d, max_dropout: %d, max_misorder: %d)",
+        seqnr, delta, packet_rate, max_dropout, max_misorder);
+    return FALSE;
+  }
+probation_seqnum:
+  {
+    GST_WARNING ("probation: seqnr %d != expected %d", seqnr, expected);
+    src->curr_probation = src->probation;
+    src->stats.max_seq = seqnr;
+    return FALSE;
+  }
+}
+
+/**
+ * rtp_source_process_rtp:
+ * @src: an #RTPSource
+ * @pinfo: an #RTPPacketInfo
+ *
+ * Let @src handle the incomming RTP packet described in @pinfo.
+ *
+ * Returns: a #GstFlowReturn.
+ */
+GstFlowReturn
+rtp_source_process_rtp (RTPSource * src, RTPPacketInfo * pinfo)
+{
+  GstFlowReturn result;
+
+  g_return_val_if_fail (RTP_IS_SOURCE (src), GST_FLOW_ERROR);
+  g_return_val_if_fail (pinfo != NULL, GST_FLOW_ERROR);
+
+  if (!update_receiver_stats (src, pinfo, TRUE))
+    return GST_FLOW_OK;
+
+  /* the source that sent the packet must be a sender */
+  src->is_sender = TRUE;
+  src->validated = TRUE;
+
+  do_bitrate_estimation (src, pinfo->running_time, &src->bytes_received);
+
+  /* calculate jitter for the stats */
+  calculate_jitter (src, pinfo);
+
+  /* we're ready to push the RTP packet now */
+  result = push_packet (src, pinfo->data);
+  pinfo->data = NULL;
+
+  return result;
+}
+
+/**
+ * rtp_source_mark_bye:
+ * @src: an #RTPSource
+ * @reason: the reason for leaving
+ *
+ * Mark @src in the BYE state. This can happen when the source wants to
+ * leave the sesssion or when a BYE packets has been received.
+ *
+ * This will make the source inactive.
+ */
+void
+rtp_source_mark_bye (RTPSource * src, const gchar * reason)
+{
+  g_return_if_fail (RTP_IS_SOURCE (src));
+
+  GST_DEBUG ("marking SSRC %08x as BYE, reason: %s", src->ssrc,
+      GST_STR_NULL (reason));
+
+  /* copy the reason and mark as bye */
+  g_free (src->bye_reason);
+  src->bye_reason = g_strdup (reason);
+  src->marked_bye = TRUE;
+}
+
+/**
+ * rtp_source_send_rtp:
+ * @src: an #RTPSource
+ * @data: an RTP buffer or a list of RTP buffers
+ * @is_list: if @data is a buffer or list
+ * @running_time: the running time of @data
+ *
+ * Send @data (an RTP buffer or list of buffers) originating from @src.
+ * This will make @src a sender. This function takes ownership of @data and
+ * modifies the SSRC in the RTP packet to that of @src when needed.
+ *
+ * Returns: a #GstFlowReturn.
+ */
+GstFlowReturn
+rtp_source_send_rtp (RTPSource * src, RTPPacketInfo * pinfo)
+{
+  GstFlowReturn result;
+  GstClockTime running_time;
+  guint32 rtptime;
+  guint64 ext_rtptime;
+  guint64 rt_diff, rtp_diff;
+
+  g_return_val_if_fail (RTP_IS_SOURCE (src), GST_FLOW_ERROR);
+
+  /* we are a sender now */
+  src->is_sender = TRUE;
+
+  /* we are also a receiver of our packets */
+  if (!update_receiver_stats (src, pinfo, FALSE))
+    return GST_FLOW_OK;
+
+  if (src->pt_set && src->pt != pinfo->pt) {
+    GST_WARNING ("Changing pt from %u to %u for SSRC %u", src->pt, pinfo->pt,
+        src->ssrc);
+  }
+
+  src->pt = pinfo->pt;
+  src->pt_set = TRUE;
+
+  /* update stats for the SR */
+  src->stats.packets_sent += pinfo->packets;
+  src->stats.octets_sent += pinfo->payload_len;
+  src->bytes_sent += pinfo->payload_len;
+
+  running_time = pinfo->running_time;
+
+  do_bitrate_estimation (src, running_time, &src->bytes_sent);
+
+  rtptime = pinfo->rtptime;
+
+  ext_rtptime = src->last_rtptime;
+  ext_rtptime = gst_rtp_buffer_ext_timestamp (&ext_rtptime, rtptime);
+
+  GST_LOG ("SSRC %08x, RTP %" G_GUINT64_FORMAT ", running_time %"
+      GST_TIME_FORMAT, src->ssrc, ext_rtptime, GST_TIME_ARGS (running_time));
+
+  if (ext_rtptime > src->last_rtptime) {
+    rtp_diff = ext_rtptime - src->last_rtptime;
+    rt_diff = running_time - src->last_rtime;
+
+    /* calc the diff so we can detect drift at the sender. This can also be used
+     * to guestimate the clock rate if the NTP time is locked to the RTP
+     * timestamps (as is the case when the capture device is providing the clock). */
+    GST_LOG ("SSRC %08x, diff RTP %" G_GUINT64_FORMAT ", diff running_time %"
+        GST_TIME_FORMAT, src->ssrc, rtp_diff, GST_TIME_ARGS (rt_diff));
+  }
+
+  /* we keep track of the last received RTP timestamp and the corresponding
+   * buffer running_time so that we can use this info when constructing SR reports */
+  src->last_rtime = running_time;
+  src->last_rtptime = ext_rtptime;
+
+  /* push packet */
+  if (!src->callbacks.push_rtp)
+    goto no_callback;
+
+  GST_LOG ("pushing RTP %s %" G_GUINT64_FORMAT,
+      pinfo->is_list ? "list" : "packet", src->stats.packets_sent);
+
+  result = src->callbacks.push_rtp (src, pinfo->data, src->user_data);
+  pinfo->data = NULL;
+
+  return result;
+
+  /* ERRORS */
+no_callback:
+  {
+    GST_WARNING ("no callback installed, dropping packet");
+    return GST_FLOW_OK;
+  }
+}
+
+/**
+ * rtp_source_process_sr:
+ * @src: an #RTPSource
+ * @time: time of packet arrival
+ * @ntptime: the NTP time (in NTP Timestamp Format, 32.32 fixed point)
+ * @rtptime: the RTP time (in clock rate units)
+ * @packet_count: the packet count
+ * @octet_count: the octet count
+ *
+ * Update the sender report in @src.
+ */
+void
+rtp_source_process_sr (RTPSource * src, GstClockTime time, guint64 ntptime,
+    guint32 rtptime, guint32 packet_count, guint32 octet_count)
+{
+  RTPSenderReport *curr;
+  gint curridx;
+
+  g_return_if_fail (RTP_IS_SOURCE (src));
+
+  GST_DEBUG ("got SR packet: SSRC %08x, NTP %08x:%08x, RTP %" G_GUINT32_FORMAT
+      ", PC %" G_GUINT32_FORMAT ", OC %" G_GUINT32_FORMAT, src->ssrc,
+      (guint32) (ntptime >> 32), (guint32) (ntptime & 0xffffffff), rtptime,
+      packet_count, octet_count);
+
+  curridx = src->stats.curr_sr ^ 1;
+  curr = &src->stats.sr[curridx];
+
+  /* this is a sender now */
+  src->is_sender = TRUE;
+
+  /* update current */
+  curr->is_valid = TRUE;
+  curr->ntptime = ntptime;
+  curr->rtptime = rtptime;
+  curr->packet_count = packet_count;
+  curr->octet_count = octet_count;
+  curr->time = time;
+
+  /* make current */
+  src->stats.curr_sr = curridx;
+
+  src->stats.prev_rtcptime = src->stats.last_rtcptime;
+  src->stats.last_rtcptime = time;
+}
+
+/**
+ * rtp_source_process_rb:
+ * @src: an #RTPSource
+ * @ntpnstime: the current time in nanoseconds since 1970
+ * @fractionlost: fraction lost since last SR/RR
+ * @packetslost: the cumulative number of packets lost
+ * @exthighestseq: the extended last sequence number received
+ * @jitter: the interarrival jitter (in clock rate units)
+ * @lsr: the time of the last SR packet on this source
+ *   (in NTP Short Format, 16.16 fixed point)
+ * @dlsr: the delay since the last SR packet
+ *   (in NTP Short Format, 16.16 fixed point)
+ *
+ * Update the report block in @src.
+ */
+void
+rtp_source_process_rb (RTPSource * src, guint64 ntpnstime,
+    guint8 fractionlost, gint32 packetslost, guint32 exthighestseq,
+    guint32 jitter, guint32 lsr, guint32 dlsr)
+{
+  RTPReceiverReport *curr;
+  gint curridx;
+  guint32 ntp, A;
+  guint64 f_ntp;
+
+  g_return_if_fail (RTP_IS_SOURCE (src));
+
+  GST_DEBUG ("got RB packet: SSRC %08x, FL %2x, PL %d, HS %" G_GUINT32_FORMAT
+      ", jitter %" G_GUINT32_FORMAT ", LSR %04x:%04x, DLSR %04x:%04x",
+      src->ssrc, fractionlost, packetslost, exthighestseq, jitter, lsr >> 16,
+      lsr & 0xffff, dlsr >> 16, dlsr & 0xffff);
+
+  curridx = src->stats.curr_rr ^ 1;
+  curr = &src->stats.rr[curridx];
+
+  /* update current */
+  curr->is_valid = TRUE;
+  curr->fractionlost = fractionlost;
+  curr->packetslost = packetslost;
+  curr->exthighestseq = exthighestseq;
+  curr->jitter = jitter;
+  curr->lsr = lsr;
+  curr->dlsr = dlsr;
+
+  /* convert the NTP time in nanoseconds to 32.32 fixed point */
+  f_ntp = gst_util_uint64_scale (ntpnstime, (1LL << 32), GST_SECOND);
+  /* calculate round trip, round the time up */
+  ntp = ((f_ntp + 0xffff) >> 16) & 0xffffffff;
+
+  A = dlsr + lsr;
+  if (A > 0 && ntp > A)
+    A = ntp - A;
+  else
+    A = 0;
+  curr->round_trip = A;
+
+  GST_DEBUG ("NTP %04x:%04x, round trip %04x:%04x", ntp >> 16, ntp & 0xffff,
+      A >> 16, A & 0xffff);
+
+  /* make current */
+  src->stats.curr_rr = curridx;
+}
+
+/**
+ * rtp_source_get_new_sr:
+ * @src: an #RTPSource
+ * @ntpnstime: the current time in nanoseconds since 1970
+ * @running_time: the current running_time of the pipeline
+ * @ntptime: the NTP time (in NTP Timestamp Format, 32.32 fixed point)
+ * @rtptime: the RTP time corresponding to @ntptime (in clock rate units)
+ * @packet_count: the packet count
+ * @octet_count: the octet count
+ *
+ * Get new values to put into a new SR report from this source.
+ *
+ * @running_time and @ntpnstime are captured at the same time and represent the
+ * running time of the pipeline clock and the absolute current system time in
+ * nanoseconds respectively. Together with the last running_time and RTP timestamp
+ * we have observed in the source, we can generate @ntptime and @rtptime for an SR
+ * packet. @ntptime is basically the fixed point representation of @ntpnstime
+ * and @rtptime the associated RTP timestamp.
+ *
+ * Returns: %TRUE on success.
+ */
+gboolean
+rtp_source_get_new_sr (RTPSource * src, guint64 ntpnstime,
+    GstClockTime running_time, guint64 * ntptime, guint32 * rtptime,
+    guint32 * packet_count, guint32 * octet_count)
+{
+  guint64 t_rtp;
+  guint64 t_current_ntp;
+  GstClockTimeDiff diff;
+
+  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
+
+  /* We last saw a buffer with last_rtptime at last_rtime. Given a running_time
+   * and an NTP time, we can scale the RTP timestamps so that they match the
+   * given NTP time.  for scaling, we assume that the slope of the rtptime vs
+   * running_time vs ntptime curve is close to 1, which is certainly
+   * sufficient for the frequency at which we report SR and the rate we send
+   * out RTP packets. */
+  t_rtp = src->last_rtptime;
+
+  GST_DEBUG ("last_rtime %" GST_TIME_FORMAT ", last_rtptime %"
+      G_GUINT64_FORMAT, GST_TIME_ARGS (src->last_rtime), t_rtp);
+
+  if (src->clock_rate == -1 && src->pt_set) {
+    GST_INFO ("no clock-rate, getting for pt %u and SSRC %u", src->pt,
+        src->ssrc);
+    get_clock_rate (src, src->pt);
+  }
+
+  if (src->clock_rate != -1) {
+    /* get the diff between the clock running_time and the buffer running_time.
+     * This is the elapsed time, as measured against the pipeline clock, between
+     * when the rtp timestamp was observed and the current running_time.
+     *
+     * We need to apply this diff to the RTP timestamp to get the RTP timestamp
+     * for the given ntpnstime. */
+    diff = GST_CLOCK_DIFF (src->last_rtime, running_time);
+    GST_DEBUG ("running_time %" GST_TIME_FORMAT ", diff %" GST_STIME_FORMAT,
+        GST_TIME_ARGS (running_time), GST_STIME_ARGS (diff));
+
+    /* now translate the diff to RTP time, handle positive and negative cases.
+     * If there is no diff, we already set rtptime correctly above. */
+    if (diff > 0) {
+      t_rtp += gst_util_uint64_scale_int (diff, src->clock_rate, GST_SECOND);
+    } else {
+      diff = -diff;
+      t_rtp -= gst_util_uint64_scale_int (diff, src->clock_rate, GST_SECOND);
+    }
+  } else {
+    GST_WARNING ("no clock-rate, cannot interpolate rtp time for SSRC %u",
+        src->ssrc);
+  }
+
+  /* convert the NTP time in nanoseconds to 32.32 fixed point */
+  t_current_ntp = gst_util_uint64_scale (ntpnstime, (1LL << 32), GST_SECOND);
+
+  GST_DEBUG ("NTP %08x:%08x, RTP %" G_GUINT32_FORMAT,
+      (guint32) (t_current_ntp >> 32), (guint32) (t_current_ntp & 0xffffffff),
+      (guint32) t_rtp);
+
+  if (ntptime)
+    *ntptime = t_current_ntp;
+  if (rtptime)
+    *rtptime = t_rtp;
+  if (packet_count)
+    *packet_count = src->stats.packets_sent;
+  if (octet_count)
+    *octet_count = src->stats.octets_sent;
+
+  return TRUE;
+}
+
+/**
+ * rtp_source_get_new_rb:
+ * @src: an #RTPSource
+ * @time: the current time of the system clock
+ * @fractionlost: fraction lost since last SR/RR
+ * @packetslost: the cumulative number of packets lost
+ * @exthighestseq: the extended last sequence number received
+ * @jitter: the interarrival jitter (in clock rate units)
+ * @lsr: the time of the last SR packet on this source
+ *   (in NTP Short Format, 16.16 fixed point)
+ * @dlsr: the delay since the last SR packet
+ *   (in NTP Short Format, 16.16 fixed point)
+ *
+ * Get new values to put into a new report block from this source.
+ *
+ * Returns: %TRUE on success.
+ */
+gboolean
+rtp_source_get_new_rb (RTPSource * src, GstClockTime time,
+    guint8 * fractionlost, gint32 * packetslost, guint32 * exthighestseq,
+    guint32 * jitter, guint32 * lsr, guint32 * dlsr)
+{
+  RTPSourceStats *stats;
+  guint64 extended_max, expected;
+  guint64 expected_interval, received_interval, ntptime;
+  gint64 lost, lost_interval;
+  guint32 fraction, LSR, DLSR;
+  GstClockTime sr_time;
+
+  stats = &src->stats;
+
+  extended_max = stats->cycles + stats->max_seq;
+  expected = extended_max - stats->base_seq + 1;
+
+  GST_DEBUG ("ext_max %" G_GUINT64_FORMAT ", expected %" G_GUINT64_FORMAT
+      ", received %" G_GUINT64_FORMAT ", base_seq %" G_GUINT32_FORMAT,
+      extended_max, expected, stats->packets_received, stats->base_seq);
+
+  lost = expected - stats->packets_received;
+  lost = CLAMP (lost, -0x800000, 0x7fffff);
+
+  expected_interval = expected - stats->prev_expected;
+  stats->prev_expected = expected;
+  received_interval = stats->packets_received - stats->prev_received;
+  stats->prev_received = stats->packets_received;
+
+  lost_interval = expected_interval - received_interval;
+
+  if (expected_interval == 0 || lost_interval <= 0)
+    fraction = 0;
+  else
+    fraction = (lost_interval << 8) / expected_interval;
+
+  GST_DEBUG ("add RR for SSRC %08x", src->ssrc);
+  /* we scaled the jitter up for additional precision */
+  GST_DEBUG ("fraction %" G_GUINT32_FORMAT ", lost %" G_GINT64_FORMAT
+      ", extseq %" G_GUINT64_FORMAT ", jitter %d", fraction, lost,
+      extended_max, stats->jitter >> 4);
+
+  if (rtp_source_get_last_sr (src, &sr_time, &ntptime, NULL, NULL, NULL)) {
+    GstClockTime diff;
+
+    /* LSR is middle 32 bits of the last ntptime */
+    LSR = (ntptime >> 16) & 0xffffffff;
+    diff = time - sr_time;
+    GST_DEBUG ("last SR time diff %" GST_TIME_FORMAT, GST_TIME_ARGS (diff));
+    /* DLSR, delay since last SR is expressed in 1/65536 second units */
+    DLSR = gst_util_uint64_scale_int (diff, 65536, GST_SECOND);
+  } else {
+    /* No valid SR received, LSR/DLSR are set to 0 then */
+    GST_DEBUG ("no valid SR received");
+    LSR = 0;
+    DLSR = 0;
+  }
+  GST_DEBUG ("LSR %04x:%04x, DLSR %04x:%04x", LSR >> 16, LSR & 0xffff,
+      DLSR >> 16, DLSR & 0xffff);
+
+  if (fractionlost)
+    *fractionlost = fraction;
+  if (packetslost)
+    *packetslost = lost;
+  if (exthighestseq)
+    *exthighestseq = extended_max;
+  if (jitter)
+    *jitter = stats->jitter >> 4;
+  if (lsr)
+    *lsr = LSR;
+  if (dlsr)
+    *dlsr = DLSR;
+
+  return TRUE;
+}
+
+/**
+ * rtp_source_get_last_sr:
+ * @src: an #RTPSource
+ * @time: time of packet arrival
+ * @ntptime: the NTP time (in NTP Timestamp Format, 32.32 fixed point)
+ * @rtptime: the RTP time (in clock rate units)
+ * @packet_count: the packet count
+ * @octet_count: the octet count
+ *
+ * Get the values of the last sender report as set with rtp_source_process_sr().
+ *
+ * Returns: %TRUE if there was a valid SR report.
+ */
+gboolean
+rtp_source_get_last_sr (RTPSource * src, GstClockTime * time, guint64 * ntptime,
+    guint32 * rtptime, guint32 * packet_count, guint32 * octet_count)
+{
+  RTPSenderReport *curr;
+
+  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
+
+  curr = &src->stats.sr[src->stats.curr_sr];
+  if (!curr->is_valid)
+    return FALSE;
+
+  if (ntptime)
+    *ntptime = curr->ntptime;
+  if (rtptime)
+    *rtptime = curr->rtptime;
+  if (packet_count)
+    *packet_count = curr->packet_count;
+  if (octet_count)
+    *octet_count = curr->octet_count;
+  if (time)
+    *time = curr->time;
+
+  return TRUE;
+}
+
+/**
+ * rtp_source_get_last_rb:
+ * @src: an #RTPSource
+ * @fractionlost: fraction lost since last SR/RR
+ * @packetslost: the cumulative number of packets lost
+ * @exthighestseq: the extended last sequence number received
+ * @jitter: the interarrival jitter (in clock rate units)
+ * @lsr: the time of the last SR packet on this source
+ *   (in NTP Short Format, 16.16 fixed point)
+ * @dlsr: the delay since the last SR packet
+ *   (in NTP Short Format, 16.16 fixed point)
+ * @round_trip: the round-trip time
+ *   (in NTP Short Format, 16.16 fixed point)
+ *
+ * Get the values of the last RB report set with rtp_source_process_rb().
+ *
+ * Returns: %TRUE if there was a valid SB report.
+ */
+gboolean
+rtp_source_get_last_rb (RTPSource * src, guint8 * fractionlost,
+    gint32 * packetslost, guint32 * exthighestseq, guint32 * jitter,
+    guint32 * lsr, guint32 * dlsr, guint32 * round_trip)
+{
+  RTPReceiverReport *curr;
+
+  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
+
+  curr = &src->stats.rr[src->stats.curr_rr];
+  if (!curr->is_valid)
+    return FALSE;
+
+  if (fractionlost)
+    *fractionlost = curr->fractionlost;
+  if (packetslost)
+    *packetslost = curr->packetslost;
+  if (exthighestseq)
+    *exthighestseq = curr->exthighestseq;
+  if (jitter)
+    *jitter = curr->jitter;
+  if (lsr)
+    *lsr = curr->lsr;
+  if (dlsr)
+    *dlsr = curr->dlsr;
+  if (round_trip)
+    *round_trip = curr->round_trip;
+
+  return TRUE;
+}
+
+gboolean
+find_conflicting_address (GList * conflicting_addresses,
+    GSocketAddress * address, GstClockTime time)
+{
+  GList *item;
+
+  for (item = conflicting_addresses; item; item = g_list_next (item)) {
+    RTPConflictingAddress *known_conflict = item->data;
+
+    if (__g_socket_address_equal (address, known_conflict->address)) {
+      known_conflict->time = time;
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+GList *
+add_conflicting_address (GList * conflicting_addresses,
+    GSocketAddress * address, GstClockTime time)
+{
+  RTPConflictingAddress *new_conflict;
+
+  new_conflict = g_slice_new (RTPConflictingAddress);
+
+  new_conflict->address = G_SOCKET_ADDRESS (g_object_ref (address));
+  new_conflict->time = time;
+
+  return g_list_prepend (conflicting_addresses, new_conflict);
+}
+
+GList *
+timeout_conflicting_addresses (GList * conflicting_addresses,
+    GstClockTime current_time)
+{
+  GList *item;
+  /* "a relatively long time" -- RFC 3550 section 8.2 */
+  const GstClockTime collision_timeout =
+      RTP_STATS_MIN_INTERVAL * GST_SECOND * 10;
+
+  item = g_list_first (conflicting_addresses);
+  while (item) {
+    RTPConflictingAddress *known_conflict = item->data;
+    GList *next_item = g_list_next (item);
+
+    if (known_conflict->time < current_time - collision_timeout) {
+      gchar *buf;
+
+      conflicting_addresses = g_list_delete_link (conflicting_addresses, item);
+      buf = __g_socket_address_to_string (known_conflict->address);
+      GST_DEBUG ("collision %p timed out: %s", known_conflict, buf);
+      g_free (buf);
+      rtp_conflicting_address_free (known_conflict);
+    }
+    item = next_item;
+  }
+
+  return conflicting_addresses;
+}
+
+/**
+ * rtp_source_find_conflicting_address:
+ * @src: The source the packet came in
+ * @address: address to check for
+ * @time: The time when the packet that is possibly in conflict arrived
+ *
+ * Checks if an address which has a conflict is already known. If it is
+ * a known conflict, remember the time
+ *
+ * Returns: TRUE if it was a known conflict, FALSE otherwise
+ */
+gboolean
+rtp_source_find_conflicting_address (RTPSource * src, GSocketAddress * address,
+    GstClockTime time)
+{
+  return find_conflicting_address (src->conflicting_addresses, address, time);
+}
+
+/**
+ * rtp_source_add_conflicting_address:
+ * @src: The source the packet came in
+ * @address: address to remember
+ * @time: The time when the packet that is in conflict arrived
+ *
+ * Adds a new conflict address
+ */
+void
+rtp_source_add_conflicting_address (RTPSource * src,
+    GSocketAddress * address, GstClockTime time)
+{
+  src->conflicting_addresses =
+      add_conflicting_address (src->conflicting_addresses, address, time);
+}
+
+/**
+ * rtp_source_timeout:
+ * @src: The #RTPSource
+ * @current_time: The current time
+ * @feedback_retention_window: The running time before which retained feedback
+ * packets have to be discarded
+ *
+ * This is processed on each RTCP interval. It times out old collisions.
+ * It also times out old retained feedback packets
+ */
+void
+rtp_source_timeout (RTPSource * src, GstClockTime current_time,
+    GstClockTime feedback_retention_window)
+{
+  GstRTCPPacket *pkt;
+
+  src->conflicting_addresses =
+      timeout_conflicting_addresses (src->conflicting_addresses, current_time);
+
+  /* Time out AVPF packets that are older than the desired length */
+  while ((pkt = g_queue_peek_tail (src->retained_feedback)) &&
+      GST_BUFFER_PTS (pkt) < feedback_retention_window)
+    gst_buffer_unref (g_queue_pop_tail (src->retained_feedback));
+}
+
+static gint
+compare_buffers (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+  const GstBuffer *bufa = a;
+  const GstBuffer *bufb = b;
+
+  return GST_BUFFER_PTS (bufa) - GST_BUFFER_PTS (bufb);
+}
+
+void
+rtp_source_retain_rtcp_packet (RTPSource * src, GstRTCPPacket * packet,
+    GstClockTime running_time)
+{
+  GstBuffer *buffer;
+
+  buffer = gst_buffer_copy_region (packet->rtcp->buffer, GST_BUFFER_COPY_MEMORY,
+      packet->offset, (gst_rtcp_packet_get_length (packet) + 1) * 4);
+
+  GST_BUFFER_PTS (buffer) = running_time;
+
+  g_queue_insert_sorted (src->retained_feedback, buffer, compare_buffers, NULL);
+}
+
+gboolean
+rtp_source_has_retained (RTPSource * src, GCompareFunc func, gconstpointer data)
+{
+  if (g_queue_find_custom (src->retained_feedback, data, func))
+    return TRUE;
+  else
+    return FALSE;
+}
+
+/**
+ * rtp_source_register_nack:
+ * @src: The #RTPSource
+ * @seqnum: a seqnum
+ *
+ * Register that @seqnum has not been received from @src.
+ */
+void
+rtp_source_register_nack (RTPSource * src, guint16 seqnum)
+{
+  guint i, len;
+  guint32 dword = seqnum << 16;
+  gint diff = 16;
+
+  len = src->nacks->len;
+  for (i = 0; i < len; i++) {
+    guint32 tdword;
+    guint16 tseq;
+
+    tdword = g_array_index (src->nacks, guint32, i);
+    tseq = tdword >> 16;
+
+    diff = gst_rtp_buffer_compare_seqnum (tseq, seqnum);
+    if (diff < 16)
+      break;
+  }
+  /* we already have this seqnum */
+  if (diff == 0)
+    return;
+  /* it comes before the recorded seqnum, FIXME, we could merge it
+   * if not to far away */
+  if (diff < 0) {
+    GST_DEBUG ("insert NACK #%u at %u", seqnum, i);
+    g_array_insert_val (src->nacks, i, dword);
+  } else if (diff < 16) {
+    /* we can merge it */
+    dword = g_array_index (src->nacks, guint32, i);
+    dword |= 1 << (diff - 1);
+    GST_DEBUG ("merge NACK #%u at %u with NACK #%u -> 0x%08x", seqnum, i,
+        dword >> 16, dword);
+    g_array_index (src->nacks, guint32, i) = dword;
+  } else {
+    GST_DEBUG ("append NACK #%u", seqnum);
+    g_array_append_val (src->nacks, dword);
+  }
+  src->send_nack = TRUE;
+}
+
+/**
+ * rtp_source_get_nacks:
+ * @src: The #RTPSource
+ * @n_nacks: result number of nacks
+ *
+ * Get the registered NACKS since the last rtp_source_clear_nacks().
+ *
+ * Returns: an array of @n_nacks seqnum values.
+ */
+guint32 *
+rtp_source_get_nacks (RTPSource * src, guint * n_nacks)
+{
+  if (n_nacks)
+    *n_nacks = src->nacks->len;
+
+  return (guint32 *) src->nacks->data;
+}
+
+void
+rtp_source_clear_nacks (RTPSource * src)
+{
+  g_array_set_size (src->nacks, 0);
+  src->send_nack = FALSE;
+}
diff --git a/gst/rtpmanager/rtpsource.h b/gst/rtpmanager/rtpsource.h
new file mode 100644
index 0000000..282267e
--- /dev/null
+++ b/gst/rtpmanager/rtpsource.h
@@ -0,0 +1,305 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C)  2015 Kurento (http://kurento.org/)
+ *   @author: Miguel París <mparisdiaz@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __RTP_SOURCE_H__
+#define __RTP_SOURCE_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/rtp.h>
+#include <gst/net/gstnetaddressmeta.h>
+#include <gio/gio.h>
+
+#include "rtpstats.h"
+
+/* the default number of consecutive RTP packets we need to receive before the
+ * source is considered valid */
+#define RTP_NO_PROBATION        0
+#define RTP_DEFAULT_PROBATION   2
+
+#define RTP_SEQ_MOD          (1 << 16)
+
+typedef struct _RTPSource RTPSource;
+typedef struct _RTPSourceClass RTPSourceClass;
+
+#define RTP_TYPE_SOURCE             (rtp_source_get_type())
+#define RTP_SOURCE(src)             (G_TYPE_CHECK_INSTANCE_CAST((src),RTP_TYPE_SOURCE,RTPSource))
+#define RTP_SOURCE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),RTP_TYPE_SOURCE,RTPSourceClass))
+#define RTP_IS_SOURCE(src)          (G_TYPE_CHECK_INSTANCE_TYPE((src),RTP_TYPE_SOURCE))
+#define RTP_IS_SOURCE_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),RTP_TYPE_SOURCE))
+#define RTP_SOURCE_CAST(src)        ((RTPSource *)(src))
+
+/**
+ * RTP_SOURCE_IS_ACTIVE:
+ * @src: an #RTPSource
+ *
+ * Check if @src is active. A source is active when it has been validated
+ * and has not yet received a BYE packet.
+ */
+#define RTP_SOURCE_IS_ACTIVE(src)  (src->validated && !src->marked_bye)
+
+/**
+ * RTP_SOURCE_IS_SENDER:
+ * @src: an #RTPSource
+ *
+ * Check if @src is a sender.
+ */
+#define RTP_SOURCE_IS_SENDER(src)  (src->is_sender)
+/**
+ * RTP_SOURCE_IS_MARKED_BYE:
+ * @src: an #RTPSource
+ *
+ * Check if @src is a marked as BYE.
+ */
+#define RTP_SOURCE_IS_MARKED_BYE(src)  (src->marked_bye)
+
+
+/**
+ * RTPSourcePushRTP:
+ * @src: an #RTPSource
+ * @data: the RTP buffer or buffer list ready for processing
+ * @user_data: user data specified when registering
+ *
+ * This callback will be called when @src has @buffer ready for further
+ * processing.
+ *
+ * Returns: a #GstFlowReturn.
+ */
+typedef GstFlowReturn (*RTPSourcePushRTP) (RTPSource *src, gpointer data,
+	gpointer user_data);
+
+/**
+ * RTPSourceClockRate:
+ * @src: an #RTPSource
+ * @payload: a payload type
+ * @user_data: user data specified when registering
+ *
+ * This callback will be called when @src needs the clock-rate of the
+ * @payload.
+ *
+ * Returns: a clock-rate for @payload.
+ */
+typedef gint (*RTPSourceClockRate) (RTPSource *src, guint8 payload, gpointer user_data);
+
+/**
+ * RTPSourceCallbacks:
+ * @push_rtp: a packet becomes available for handling
+ * @clock_rate: a clock-rate is requested
+ * @get_time: the current clock time is requested
+ *
+ * Callbacks performed by #RTPSource when actions need to be performed.
+ */
+typedef struct {
+  RTPSourcePushRTP     push_rtp;
+  RTPSourceClockRate   clock_rate;
+} RTPSourceCallbacks;
+
+/**
+ * RTPConflictingAddress:
+ * @address: #GSocketAddress which conflicted
+ * @last_conflict_time: time when the last conflict was seen
+ *
+ * This structure is used to account for addresses that have conflicted to find
+ * loops.
+ */
+typedef struct {
+  GSocketAddress *address;
+  GstClockTime time;
+} RTPConflictingAddress;
+
+/**
+ * RTPSource:
+ *
+ * A source in the #RTPSession
+ *
+ * @conflicting_addresses: GList of conflicting addresses
+ */
+struct _RTPSource {
+  GObject       object;
+
+  /*< private >*/
+  guint32       ssrc;
+
+  guint16       generation;
+  GHashTable    *reported_in_sr_of;     /* set of SSRCs */
+
+  guint         probation;
+  guint         curr_probation;
+  gboolean      validated;
+  gboolean      internal;
+  gboolean      is_csrc;
+  gboolean      is_sender;
+  gboolean      closing;
+
+  GstStructure  *sdes;
+
+  gboolean      marked_bye;
+  gchar        *bye_reason;
+  gboolean      sent_bye;
+
+  GSocketAddress *rtp_from;
+  GSocketAddress *rtcp_from;
+
+  gint          payload;
+  GstCaps      *caps;
+  gint          clock_rate;
+  gint32        seqnum_offset;
+
+  GstClockTime  bye_time;
+  GstClockTime  last_activity;
+  GstClockTime  last_rtp_activity;
+
+  GstClockTime  last_rtime;
+  GstClockTime  last_rtptime;
+
+  /* for bitrate estimation */
+  guint64       bitrate;
+  GstClockTime  prev_rtime;
+  guint64       bytes_sent;
+  guint64       bytes_received;
+
+  GQueue       *packets;
+  RTPPacketRateCtx packet_rate_ctx;
+  guint32       max_dropout_time;
+  guint32       max_misorder_time;
+
+  RTPSourceCallbacks callbacks;
+  gpointer           user_data;
+
+  RTPSourceStats stats;
+  RTPReceiverReport last_rr;
+
+  GList         *conflicting_addresses;
+
+  GQueue        *retained_feedback;
+
+  gboolean     send_pli;
+  gboolean     send_fir;
+  guint8       current_send_fir_seqnum;
+  gint         last_fir_count;
+  GstClockTime last_keyframe_request;
+
+  gboolean     send_nack;
+  GArray      *nacks;
+
+  gboolean      pt_set;
+  guint8        pt;
+};
+
+struct _RTPSourceClass {
+  GObjectClass   parent_class;
+};
+
+GType rtp_source_get_type (void);
+
+/* managing lifetime of sources */
+RTPSource*      rtp_source_new                 (guint32 ssrc);
+void            rtp_source_set_callbacks       (RTPSource *src, RTPSourceCallbacks *cb, gpointer data);
+
+/* properties */
+guint32         rtp_source_get_ssrc            (RTPSource *src);
+
+void            rtp_source_set_as_csrc         (RTPSource *src);
+gboolean        rtp_source_is_as_csrc          (RTPSource *src);
+
+gboolean        rtp_source_is_active           (RTPSource *src);
+gboolean        rtp_source_is_validated        (RTPSource *src);
+gboolean        rtp_source_is_sender           (RTPSource *src);
+
+void            rtp_source_mark_bye            (RTPSource *src, const gchar *reason);
+gboolean        rtp_source_is_marked_bye       (RTPSource *src);
+gchar *         rtp_source_get_bye_reason      (RTPSource *src);
+
+void            rtp_source_update_caps         (RTPSource *src, GstCaps *caps);
+
+/* SDES info */
+const GstStructure *
+                rtp_source_get_sdes_struct     (RTPSource * src);
+gboolean        rtp_source_set_sdes_struct     (RTPSource * src, GstStructure *sdes);
+
+/* handling network address */
+void            rtp_source_set_rtp_from        (RTPSource *src, GSocketAddress *address);
+void            rtp_source_set_rtcp_from       (RTPSource *src, GSocketAddress *address);
+
+/* handling RTP */
+GstFlowReturn   rtp_source_process_rtp         (RTPSource *src, RTPPacketInfo *pinfo);
+
+GstFlowReturn   rtp_source_send_rtp            (RTPSource *src, RTPPacketInfo *pinfo);
+
+/* RTCP messages */
+void            rtp_source_process_sr          (RTPSource *src, GstClockTime time, guint64 ntptime,
+                                                guint32 rtptime, guint32 packet_count, guint32 octet_count);
+void            rtp_source_process_rb          (RTPSource *src, guint64 ntpnstime, guint8 fractionlost,
+                                                gint32 packetslost, guint32 exthighestseq, guint32 jitter,
+                                                guint32 lsr, guint32 dlsr);
+
+gboolean        rtp_source_get_new_sr          (RTPSource *src, guint64 ntpnstime, GstClockTime running_time,
+                                                guint64 *ntptime, guint32 *rtptime, guint32 *packet_count,
+						guint32 *octet_count);
+gboolean        rtp_source_get_new_rb          (RTPSource *src, GstClockTime time, guint8 *fractionlost,
+                                                gint32 *packetslost, guint32 *exthighestseq, guint32 *jitter,
+                                                guint32 *lsr, guint32 *dlsr);
+
+gboolean        rtp_source_get_last_sr         (RTPSource *src, GstClockTime *time, guint64 *ntptime,
+                                                guint32 *rtptime, guint32 *packet_count,
+						guint32 *octet_count);
+gboolean        rtp_source_get_last_rb         (RTPSource *src, guint8 *fractionlost, gint32 *packetslost,
+                                                guint32 *exthighestseq, guint32 *jitter,
+                                                guint32 *lsr, guint32 *dlsr, guint32 *round_trip);
+
+void            rtp_source_reset               (RTPSource * src);
+
+gboolean        rtp_source_find_conflicting_address (RTPSource * src,
+                                                GSocketAddress *address,
+                                                GstClockTime time);
+
+void            rtp_source_add_conflicting_address (RTPSource * src,
+                                                GSocketAddress *address,
+                                                GstClockTime time);
+
+gboolean        find_conflicting_address       (GList * conflicting_address,
+                                                GSocketAddress * address,
+                                                GstClockTime time);
+
+GList *         add_conflicting_address        (GList * conflicting_addresses,
+                                                GSocketAddress * address,
+                                                GstClockTime time);
+GList *         timeout_conflicting_addresses  (GList * conflicting_addresses,
+                                                GstClockTime current_time);
+
+void            rtp_conflicting_address_free   (RTPConflictingAddress * addr);
+
+void            rtp_source_timeout             (RTPSource * src,
+                                                GstClockTime current_time,
+                                                GstClockTime feedback_retention_window);
+
+void            rtp_source_retain_rtcp_packet  (RTPSource * src,
+                                                GstRTCPPacket *pkt,
+                                                GstClockTime running_time);
+gboolean        rtp_source_has_retained        (RTPSource * src,
+                                                GCompareFunc func,
+                                                gconstpointer data);
+
+void            rtp_source_register_nack       (RTPSource * src,
+                                                guint16 seqnum);
+guint32 *       rtp_source_get_nacks           (RTPSource * src, guint *n_nacks);
+void            rtp_source_clear_nacks         (RTPSource * src);
+
+#endif /* __RTP_SOURCE_H__ */
diff --git a/gst/rtpmanager/rtpstats.c b/gst/rtpmanager/rtpstats.c
new file mode 100644
index 0000000..73bd189
--- /dev/null
+++ b/gst/rtpmanager/rtpstats.c
@@ -0,0 +1,430 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C)  2015 Kurento (http://kurento.org/)
+ *   @author: Miguel París <mparisdiaz@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "rtpstats.h"
+
+void
+gst_rtp_packet_rate_ctx_reset (RTPPacketRateCtx * ctx, gint32 clock_rate)
+{
+  ctx->clock_rate = clock_rate;
+  ctx->probed = FALSE;
+  ctx->avg_packet_rate = -1;
+  ctx->last_ts = -1;
+}
+
+guint32
+gst_rtp_packet_rate_ctx_update (RTPPacketRateCtx * ctx, guint16 seqnum,
+    guint32 ts)
+{
+  guint64 new_ts, diff_ts;
+  gint diff_seqnum;
+  gint32 new_packet_rate;
+
+  if (ctx->clock_rate <= 0) {
+    return ctx->avg_packet_rate;
+  }
+
+  new_ts = ctx->last_ts;
+  gst_rtp_buffer_ext_timestamp (&new_ts, ts);
+
+  if (!ctx->probed) {
+    ctx->last_seqnum = seqnum;
+    ctx->last_ts = new_ts;
+    ctx->probed = TRUE;
+    return ctx->avg_packet_rate;
+  }
+
+  diff_seqnum = gst_rtp_buffer_compare_seqnum (ctx->last_seqnum, seqnum);
+  if (diff_seqnum <= 0 || new_ts <= ctx->last_ts) {
+    return ctx->avg_packet_rate;
+  }
+
+  diff_ts = new_ts - ctx->last_ts;
+  diff_ts = gst_util_uint64_scale_int (diff_ts, GST_SECOND, ctx->clock_rate);
+  new_packet_rate = gst_util_uint64_scale (diff_seqnum, GST_SECOND, diff_ts);
+
+  /* The goal is that higher packet rates "win".
+   * If there's a sudden burst, the average will go up fast,
+   * but it will go down again slowly.
+   * This is useful for bursty cases, where a lot of packets are close
+   * to each other and should allow a higher reorder/dropout there.
+   * Round up the new average.
+   */
+  if (ctx->avg_packet_rate > new_packet_rate) {
+    ctx->avg_packet_rate = (7 * ctx->avg_packet_rate + new_packet_rate + 7) / 8;
+  } else {
+    ctx->avg_packet_rate = (ctx->avg_packet_rate + new_packet_rate + 1) / 2;
+  }
+
+  ctx->last_seqnum = seqnum;
+  ctx->last_ts = new_ts;
+
+  return ctx->avg_packet_rate;
+}
+
+guint32
+gst_rtp_packet_rate_ctx_get (RTPPacketRateCtx * ctx)
+{
+  return ctx->avg_packet_rate;
+}
+
+guint32
+gst_rtp_packet_rate_ctx_get_max_dropout (RTPPacketRateCtx * ctx, gint32 time_ms)
+{
+  if (time_ms <= 0 || !ctx->probed) {
+    return RTP_DEF_DROPOUT;
+  }
+
+  return MAX (RTP_MIN_DROPOUT, ctx->avg_packet_rate * time_ms / 1000);
+}
+
+guint32
+gst_rtp_packet_rate_ctx_get_max_misorder (RTPPacketRateCtx * ctx,
+    gint32 time_ms)
+{
+  if (time_ms <= 0 || !ctx->probed) {
+    return RTP_DEF_MISORDER;
+  }
+
+  return MAX (RTP_MIN_MISORDER, ctx->avg_packet_rate * time_ms / 1000);
+}
+
+/**
+ * rtp_stats_init_defaults:
+ * @stats: an #RTPSessionStats struct
+ *
+ * Initialize @stats with its default values.
+ */
+void
+rtp_stats_init_defaults (RTPSessionStats * stats)
+{
+  rtp_stats_set_bandwidths (stats, -1, -1, -1, -1);
+  stats->min_interval = RTP_STATS_MIN_INTERVAL;
+  stats->bye_timeout = RTP_STATS_BYE_TIMEOUT;
+  stats->nacks_dropped = 0;
+  stats->nacks_sent = 0;
+  stats->nacks_received = 0;
+}
+
+/**
+ * rtp_stats_set_bandwidths:
+ * @stats: an #RTPSessionStats struct
+ * @rtp_bw: RTP bandwidth
+ * @rtcp_bw: RTCP bandwidth
+ * @rs: sender RTCP bandwidth
+ * @rr: receiver RTCP bandwidth
+ *
+ * Configure the bandwidth parameters in the stats. When an input variable is
+ * set to -1, it will be calculated from the other input variables and from the
+ * defaults.
+ */
+void
+rtp_stats_set_bandwidths (RTPSessionStats * stats, guint rtp_bw,
+    gdouble rtcp_bw, guint rs, guint rr)
+{
+  GST_DEBUG ("recalc bandwidths: RTP %u, RTCP %f, RS %u, RR %u", rtp_bw,
+      rtcp_bw, rs, rr);
+
+  /* when given, sender and receive bandwidth add up to the total
+   * rtcp bandwidth */
+  if (rs != -1 && rr != -1)
+    rtcp_bw = rs + rr;
+
+  /* If rtcp_bw is between 0 and 1, it is a fraction of rtp_bw */
+  if (rtcp_bw > 0.0 && rtcp_bw < 1.0) {
+    if (rtp_bw > 0.0)
+      rtcp_bw = rtp_bw * rtcp_bw;
+    else
+      rtcp_bw = -1.0;
+  }
+
+  /* RTCP is 5% of the RTP bandwidth */
+  if (rtp_bw == -1 && rtcp_bw > 1.0)
+    rtp_bw = rtcp_bw * 20;
+  else if (rtp_bw != -1 && rtcp_bw < 0.0)
+    rtcp_bw = rtp_bw / 20;
+  else if (rtp_bw == -1 && rtcp_bw < 0.0) {
+    /* nothing given, take defaults */
+    rtp_bw = RTP_STATS_BANDWIDTH;
+    rtcp_bw = rtp_bw * RTP_STATS_RTCP_FRACTION;
+  }
+
+  stats->bandwidth = rtp_bw;
+  stats->rtcp_bandwidth = rtcp_bw;
+
+  /* now figure out the fractions */
+  if (rs == -1) {
+    /* rs unknown */
+    if (rr == -1) {
+      /* both not given, use defaults */
+      rs = stats->rtcp_bandwidth * RTP_STATS_SENDER_FRACTION;
+      rr = stats->rtcp_bandwidth * RTP_STATS_RECEIVER_FRACTION;
+    } else {
+      /* rr known, calculate rs */
+      if (stats->rtcp_bandwidth > rr)
+        rs = stats->rtcp_bandwidth - rr;
+      else
+        rs = 0;
+    }
+  } else if (rr == -1) {
+    /* rs known, calculate rr */
+    if (stats->rtcp_bandwidth > rs)
+      rr = stats->rtcp_bandwidth - rs;
+    else
+      rr = 0;
+  }
+
+  if (stats->rtcp_bandwidth > 0) {
+    stats->sender_fraction = ((gdouble) rs) / ((gdouble) stats->rtcp_bandwidth);
+    stats->receiver_fraction = 1.0 - stats->sender_fraction;
+  } else {
+    /* no RTCP bandwidth, set dummy values */
+    stats->sender_fraction = 0.0;
+    stats->receiver_fraction = 0.0;
+  }
+  GST_DEBUG ("bandwidths: RTP %u, RTCP %u, RS %f, RR %f", stats->bandwidth,
+      stats->rtcp_bandwidth, stats->sender_fraction, stats->receiver_fraction);
+}
+
+/**
+ * rtp_stats_calculate_rtcp_interval:
+ * @stats: an #RTPSessionStats struct
+ * @sender: if we are a sender
+ * @profile: RTP profile of this session
+ * @ptp: if this session is a point-to-point session
+ * @first: if this is the first time
+ *
+ * Calculate the RTCP interval. The result of this function is the amount of
+ * time to wait (in nanoseconds) before sending a new RTCP message.
+ *
+ * Returns: the RTCP interval.
+ */
+GstClockTime
+rtp_stats_calculate_rtcp_interval (RTPSessionStats * stats, gboolean we_send,
+    GstRTPProfile profile, gboolean ptp, gboolean first)
+{
+  gdouble members, senders, n;
+  gdouble avg_rtcp_size, rtcp_bw;
+  gdouble interval;
+  gdouble rtcp_min_time;
+
+  if (profile == GST_RTP_PROFILE_AVPF || profile == GST_RTP_PROFILE_SAVPF) {
+    /* RFC 4585 3.4d), 3.5.1 */
+
+    if (first && !ptp)
+      rtcp_min_time = 1.0;
+    else
+      rtcp_min_time = 0.0;
+  } else {
+    /* Very first call at application start-up uses half the min
+     * delay for quicker notification while still allowing some time
+     * before reporting for randomization and to learn about other
+     * sources so the report interval will converge to the correct
+     * interval more quickly.
+     */
+    rtcp_min_time = stats->min_interval;
+    if (first)
+      rtcp_min_time /= 2.0;
+  }
+
+  /* Dedicate a fraction of the RTCP bandwidth to senders unless
+   * the number of senders is large enough that their share is
+   * more than that fraction.
+   */
+  n = members = stats->active_sources;
+  senders = (gdouble) stats->sender_sources;
+  rtcp_bw = stats->rtcp_bandwidth;
+
+  if (senders <= members * stats->sender_fraction) {
+    if (we_send) {
+      rtcp_bw *= stats->sender_fraction;
+      n = senders;
+    } else {
+      rtcp_bw *= stats->receiver_fraction;
+      n -= senders;
+    }
+  }
+
+  /* no bandwidth for RTCP, return NONE to signal that we don't want to send
+   * RTCP packets */
+  if (rtcp_bw <= 0.0001)
+    return GST_CLOCK_TIME_NONE;
+
+  avg_rtcp_size = 8.0 * stats->avg_rtcp_packet_size;
+  /*
+   * The effective number of sites times the average packet size is
+   * the total number of octets sent when each site sends a report.
+   * Dividing this by the effective bandwidth gives the time
+   * interval over which those packets must be sent in order to
+   * meet the bandwidth target, with a minimum enforced.  In that
+   * time interval we send one report so this time is also our
+   * average time between reports.
+   */
+  GST_DEBUG ("avg size %f, n %f, rtcp_bw %f", avg_rtcp_size, n, rtcp_bw);
+  interval = avg_rtcp_size * n / rtcp_bw;
+  if (interval < rtcp_min_time)
+    interval = rtcp_min_time;
+
+  return interval * GST_SECOND;
+}
+
+/**
+ * rtp_stats_add_rtcp_jitter:
+ * @stats: an #RTPSessionStats struct
+ * @interval: an RTCP interval
+ *
+ * Apply a random jitter to the @interval. @interval is typically obtained with
+ * rtp_stats_calculate_rtcp_interval().
+ *
+ * Returns: the new RTCP interval.
+ */
+GstClockTime
+rtp_stats_add_rtcp_jitter (RTPSessionStats * stats, GstClockTime interval)
+{
+  gdouble temp;
+
+  /* see RFC 3550 p 30
+   * To compensate for "unconditional reconsideration" converging to a
+   * value below the intended average.
+   */
+#define COMPENSATION  (2.71828 - 1.5);
+
+  temp = (interval * g_random_double_range (0.5, 1.5)) / COMPENSATION;
+
+  return (GstClockTime) temp;
+}
+
+
+/**
+ * rtp_stats_calculate_bye_interval:
+ * @stats: an #RTPSessionStats struct
+ *
+ * Calculate the BYE interval. The result of this function is the amount of
+ * time to wait (in nanoseconds) before sending a BYE message.
+ *
+ * Returns: the BYE interval.
+ */
+GstClockTime
+rtp_stats_calculate_bye_interval (RTPSessionStats * stats)
+{
+  gdouble members;
+  gdouble avg_rtcp_size, rtcp_bw;
+  gdouble interval;
+  gdouble rtcp_min_time;
+
+  /* no interval when we have less than 50 members */
+  if (stats->active_sources < 50)
+    return 0;
+
+  rtcp_min_time = (stats->min_interval) / 2.0;
+
+  /* Dedicate a fraction of the RTCP bandwidth to senders unless
+   * the number of senders is large enough that their share is
+   * more than that fraction.
+   */
+  members = stats->bye_members;
+  rtcp_bw = stats->rtcp_bandwidth * stats->receiver_fraction;
+
+  /* no bandwidth for RTCP, return NONE to signal that we don't want to send
+   * RTCP packets */
+  if (rtcp_bw <= 0.0001)
+    return GST_CLOCK_TIME_NONE;
+
+  avg_rtcp_size = 8.0 * stats->avg_rtcp_packet_size;
+  /*
+   * The effective number of sites times the average packet size is
+   * the total number of octets sent when each site sends a report.
+   * Dividing this by the effective bandwidth gives the time
+   * interval over which those packets must be sent in order to
+   * meet the bandwidth target, with a minimum enforced.  In that
+   * time interval we send one report so this time is also our
+   * average time between reports.
+   */
+  interval = avg_rtcp_size * members / rtcp_bw;
+  if (interval < rtcp_min_time)
+    interval = rtcp_min_time;
+
+  return interval * GST_SECOND;
+}
+
+/**
+ * rtp_stats_get_packets_lost:
+ * @stats: an #RTPSourceStats struct
+ *
+ * Calculate the total number of RTP packets lost since beginning of
+ * reception. Packets that arrive late are not considered lost, and
+ * duplicates are not taken into account. Hence, the loss may be negative
+ * if there are duplicates.
+ *
+ * Returns: total RTP packets lost.
+ */
+gint64
+rtp_stats_get_packets_lost (const RTPSourceStats * stats)
+{
+  gint64 lost;
+  guint64 extended_max, expected;
+
+  extended_max = stats->cycles + stats->max_seq;
+  expected = extended_max - stats->base_seq + 1;
+  lost = expected - stats->packets_received;
+
+  return lost;
+}
+
+void
+rtp_stats_set_min_interval (RTPSessionStats * stats, gdouble min_interval)
+{
+  stats->min_interval = min_interval;
+}
+
+gboolean
+__g_socket_address_equal (GSocketAddress * a, GSocketAddress * b)
+{
+  GInetSocketAddress *ia, *ib;
+  GInetAddress *iaa, *iab;
+
+  ia = G_INET_SOCKET_ADDRESS (a);
+  ib = G_INET_SOCKET_ADDRESS (b);
+
+  if (g_inet_socket_address_get_port (ia) !=
+      g_inet_socket_address_get_port (ib))
+    return FALSE;
+
+  iaa = g_inet_socket_address_get_address (ia);
+  iab = g_inet_socket_address_get_address (ib);
+
+  return g_inet_address_equal (iaa, iab);
+}
+
+gchar *
+__g_socket_address_to_string (GSocketAddress * addr)
+{
+  GInetSocketAddress *ia;
+  gchar *ret, *tmp;
+
+  ia = G_INET_SOCKET_ADDRESS (addr);
+
+  tmp = g_inet_address_to_string (g_inet_socket_address_get_address (ia));
+  ret = g_strdup_printf ("%s:%u", tmp, g_inet_socket_address_get_port (ia));
+  g_free (tmp);
+
+  return ret;
+}
diff --git a/gst/rtpmanager/rtpstats.h b/gst/rtpmanager/rtpstats.h
new file mode 100644
index 0000000..b0fbddb
--- /dev/null
+++ b/gst/rtpmanager/rtpstats.h
@@ -0,0 +1,264 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C)  2015 Kurento (http://kurento.org/)
+ *   @author: Miguel París <mparisdiaz@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __RTP_STATS_H__
+#define __RTP_STATS_H__
+
+#include <gst/gst.h>
+#include <gst/net/gstnetaddressmeta.h>
+#include <gst/rtp/rtp.h>
+#include <gio/gio.h>
+
+/**
+ * RTPSenderReport:
+ *
+ * A sender report structure.
+ */
+typedef struct {
+  gboolean is_valid;
+  guint64 ntptime;
+  guint32 rtptime;
+  guint32 packet_count;
+  guint32 octet_count;
+  GstClockTime time;
+} RTPSenderReport;
+
+/**
+ * RTPReceiverReport:
+ *
+ * A receiver report structure.
+ */
+typedef struct {
+  gboolean is_valid;
+  guint32 ssrc; /* who the report is from */
+  guint8  fractionlost;
+  guint32 packetslost;
+  guint32 exthighestseq;
+  guint32 jitter;
+  guint32 lsr;
+  guint32 dlsr;
+  guint32 round_trip;
+} RTPReceiverReport;
+
+/**
+ * RTPPacketInfo:
+ * @send: if this is a packet for sending
+ * @rtp: if this info is about an RTP packet
+ * @is_list: if this is a bufferlist
+ * @data: a #GstBuffer or #GstBufferList
+ * @address: address of the sender of the packet
+ * @current_time: current time according to the system clock
+ * @running_time: time of a packet as buffer running_time
+ * @ntpnstime: time of a packet NTP time in nanoseconds
+ * @header_len: number of overhead bytes per packet
+ * @bytes: bytes of the packet including lowlevel overhead
+ * @payload_len: bytes of the RTP payload
+ * @seqnum: the seqnum of the packet
+ * @pt: the payload type of the packet
+ * @rtptime: the RTP time of the packet
+ *
+ * Structure holding information about the packet.
+ */
+typedef struct {
+  gboolean      send;
+  gboolean      rtp;
+  gboolean      is_list;
+  gpointer      data;
+  GSocketAddress *address;
+  GstClockTime  current_time;
+  GstClockTime  running_time;
+  guint64       ntpnstime;
+  guint         header_len;
+  guint         bytes;
+  guint         packets;
+  guint         payload_len;
+  guint32       ssrc;
+  guint16       seqnum;
+  guint8        pt;
+  guint32       rtptime;
+  guint32       csrc_count;
+  guint32       csrcs[16];
+} RTPPacketInfo;
+
+/**
+ * RTPSourceStats:
+ * @packetsreceived: number of received packets in total
+ * @prevpacketsreceived: number of packets received in previous reporting
+ *                       interval
+ * @octetsreceived: number of payload bytes received
+ * @bytesreceived: number of total bytes received including headers and lower
+ *                 protocol level overhead
+ * @max_seqnr: highest sequence number received
+ * @transit: previous transit time used for calculating @jitter
+ * @jitter: current jitter (in clock rate units scaled by 16 for precision)
+ * @prev_rtptime: previous time when an RTP packet was received
+ * @prev_rtcptime: previous time when an RTCP packet was received
+ * @last_rtptime: time when last RTP packet received
+ * @last_rtcptime: time when last RTCP packet received
+ * @curr_rr: index of current @rr block
+ * @rr: previous and current receiver report block
+ * @curr_sr: index of current @sr block
+ * @sr: previous and current sender report block
+ *
+ * Stats about a source.
+ */
+typedef struct {
+  guint64      packets_received;
+  guint64      octets_received;
+  guint64      bytes_received;
+
+  guint32      prev_expected;
+  guint32      prev_received;
+
+  guint16      max_seq;
+  guint64      cycles;
+  guint32      base_seq;
+  guint32      bad_seq;
+  guint32      transit;
+  guint32      jitter;
+
+  guint64      packets_sent;
+  guint64      octets_sent;
+
+  guint        sent_pli_count;
+  guint        recv_pli_count;
+  guint        sent_fir_count;
+  guint        recv_fir_count;
+  guint        sent_nack_count;
+  guint        recv_nack_count;
+
+  /* when we received stuff */
+  GstClockTime prev_rtptime;
+  GstClockTime prev_rtcptime;
+  GstClockTime last_rtptime;
+  GstClockTime last_rtcptime;
+
+  /* sender and receiver reports */
+  gint              curr_rr;
+  RTPReceiverReport rr[2];
+  gint              curr_sr;
+  RTPSenderReport   sr[2];
+} RTPSourceStats;
+
+#define RTP_STATS_BANDWIDTH           64000
+#define RTP_STATS_RTCP_FRACTION       0.05
+/*
+ * Minimum average time between RTCP packets from this site (in
+ * seconds).  This time prevents the reports from `clumping' when
+ * sessions are small and the law of large numbers isn't helping
+ * to smooth out the traffic.  It also keeps the report interval
+ * from becoming ridiculously small during transient outages like
+ * a network partition.
+ */
+#define RTP_STATS_MIN_INTERVAL      5.0
+/*
+ * Fraction of the RTCP bandwidth to be shared among active
+ * senders.  (This fraction was chosen so that in a typical
+ * session with one or two active senders, the computed report
+ * time would be roughly equal to the minimum report time so that
+ * we don't unnecessarily slow down receiver reports.) The
+ * receiver fraction must be 1 - the sender fraction.
+ */
+#define RTP_STATS_SENDER_FRACTION       (0.25)
+#define RTP_STATS_RECEIVER_FRACTION     (1.0 - RTP_STATS_SENDER_FRACTION)
+
+/*
+ * When receiving a BYE from a source, remove the source from the database
+ * after this timeout.
+ */
+#define RTP_STATS_BYE_TIMEOUT           (2 * GST_SECOND)
+
+/*
+ * The default and minimum values of the maximum number of missing packets we tolerate.
+ * These are packets with asequence number bigger than the last seen packet.
+ */
+#define RTP_DEF_DROPOUT      3000
+#define RTP_MIN_DROPOUT      30
+
+/*
+ * The default and minimum values of the maximum number of misordered packets we tolerate.
+ * These are packets with a sequence number smaller than the last seen packet.
+ */
+#define RTP_DEF_MISORDER     100
+#define RTP_MIN_MISORDER     10
+
+/**
+ * RTPPacketRateCtx:
+ *
+ * Context to calculate the pseudo-average packet rate.
+ */
+typedef struct {
+  gboolean probed;
+  gint32 clock_rate;
+  guint16 last_seqnum;
+  guint64 last_ts;
+  guint32 avg_packet_rate;
+} RTPPacketRateCtx;
+
+void gst_rtp_packet_rate_ctx_reset (RTPPacketRateCtx * ctx, gint32 clock_rate);
+guint32 gst_rtp_packet_rate_ctx_update (RTPPacketRateCtx *ctx, guint16 seqnum, guint32 ts);
+guint32 gst_rtp_packet_rate_ctx_get (RTPPacketRateCtx *ctx);
+guint32 gst_rtp_packet_rate_ctx_get_max_dropout (RTPPacketRateCtx *ctx, gint32 time_ms);
+guint32 gst_rtp_packet_rate_ctx_get_max_misorder (RTPPacketRateCtx *ctx, gint32 time_ms);
+
+/**
+ * RTPSessionStats:
+ *
+ * Stats kept for a session and used to produce RTCP packet timeouts.
+ */
+typedef struct {
+  guint         bandwidth;
+  guint         rtcp_bandwidth;
+  gdouble       sender_fraction;
+  gdouble       receiver_fraction;
+  gdouble       min_interval;
+  GstClockTime  bye_timeout;
+  guint         internal_sources;
+  guint         sender_sources;
+  guint         internal_sender_sources;
+  guint         active_sources;
+  guint         avg_rtcp_packet_size;
+  guint         bye_members;
+  guint         nacks_dropped;
+  guint         nacks_sent;
+  guint         nacks_received;
+} RTPSessionStats;
+
+void           rtp_stats_init_defaults              (RTPSessionStats *stats);
+
+void           rtp_stats_set_bandwidths             (RTPSessionStats *stats,
+                                                     guint rtp_bw,
+                                                     gdouble rtcp_bw,
+                                                     guint rs, guint rr);
+
+GstClockTime   rtp_stats_calculate_rtcp_interval    (RTPSessionStats *stats, gboolean sender, GstRTPProfile profile, gboolean ptp, gboolean first);
+GstClockTime   rtp_stats_add_rtcp_jitter            (RTPSessionStats *stats, GstClockTime interval);
+GstClockTime   rtp_stats_calculate_bye_interval     (RTPSessionStats *stats);
+gint64         rtp_stats_get_packets_lost           (const RTPSourceStats *stats);
+
+void           rtp_stats_set_min_interval           (RTPSessionStats *stats,
+                                                     gdouble min_interval);
+
+
+gboolean __g_socket_address_equal (GSocketAddress *a, GSocketAddress *b);
+gchar * __g_socket_address_to_string (GSocketAddress * addr);
+
+#endif /* __RTP_STATS_H__ */
diff --git a/gst/rtsp/.gitignore b/gst/rtsp/.gitignore
new file mode 100644
index 0000000..10846d7
--- /dev/null
+++ b/gst/rtsp/.gitignore
@@ -0,0 +1,8 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
+test
diff --git a/gst/rtsp/COPYING.MIT b/gst/rtsp/COPYING.MIT
new file mode 100644
index 0000000..6369b6d
--- /dev/null
+++ b/gst/rtsp/COPYING.MIT
@@ -0,0 +1,21 @@
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
diff --git a/gst/rtsp/Makefile.am b/gst/rtsp/Makefile.am
new file mode 100644
index 0000000..92a791e
--- /dev/null
+++ b/gst/rtsp/Makefile.am
@@ -0,0 +1,15 @@
+plugin_LTLIBRARIES = libgstrtsp.la
+
+libgstrtsp_la_SOURCES = gstrtsp.c gstrtspsrc.c \
+			gstrtpdec.c gstrtspext.c
+
+libgstrtsp_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS)
+libgstrtsp_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_LIBS) $(GST_BASE_LIBS) $(GIO_LIBS) \
+		       -lgstrtp-@GST_API_VERSION@ -lgstrtsp-@GST_API_VERSION@ \
+		       -lgstsdp-@GST_API_VERSION@ $(GST_NET_LIBS) $(GST_LIBS)
+libgstrtsp_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstrtspsrc.h     \
+		 gstrtsp.h        \
+		 gstrtpdec.h      \
+		 gstrtspext.h
diff --git a/gst/rtsp/README b/gst/rtsp/README
new file mode 100644
index 0000000..3c6f3a0
--- /dev/null
+++ b/gst/rtsp/README
@@ -0,0 +1,377 @@
+RTSP source 
+-----------
+
+The RTSP source establishes a connection to an RTSP server and sets up
+the UDP sources and RTP session handlers.
+
+An RTSP session is created as follows:
+
+- Parse RTSP URL:
+
+   ex:
+     rtsp://thread:5454/south-rtsp.mp3
+
+- Open a connection to the server with the url. All further conversation with
+  the server should be done with this connection. Each request/reply has
+  a CSeq number added to the header.
+
+- Send a DESCRIBE request for the url. We currently support a response in
+  SDP.
+
+  ex:
+
+    >> DESCRIBE rtsp://thread:5454/south-rtsp.mp3 RTSP/1.0
+    >> Accept: application/sdp
+    >> CSeq: 0
+    >>
+    << RTSP/1.0 200 OK
+    << Content-Length: 84
+    << Content-Type: application/sdp
+    << CSeq: 0
+    << Date: Wed May 11 13:09:37 2005 GMT
+    <<
+    << v=0
+    << o=- 0 0 IN IP4 192.168.1.1
+    << s=No Title
+    << m=audio 0 RTP/AVP 14
+    << a=control:streamid=0
+
+- Parse the SDP message, for each stream (m=) we create an GstRTPStream. We need
+  to allocate two local UDP ports for receiving the RTP and RTCP data because we
+  need to send the port numbers to the server in the next request.
+
+  In RTSPSrc we first create an element that can handle the udp://0.0.0.0:0 uri. This
+  will create an udp source element with a random port number. We get the port
+  number by getting the "port" property of the element after setting the element to 
+  PAUSED. This element is used for the RTP packets and has to be an even number. If
+  the random port number is not an even number we retry to allocate a new udp source.
+
+  We then create another UDP source element with the next (uneven) port number to 
+  receive the RTCP packet on. After this step we have two udp ports we can use to
+  accept RTP packets.
+
+    +-----------------+
+    | +------------+  |
+    | | udpsrc0    |  |
+    | |  port=5000 |  |
+    | +------------+  |
+    | +------------+  |
+    | | udpsrc1    |  |
+    | |  port=5001 |  |
+    | +------------+  |
+    +-----------------+
+
+- Send a SETUP message to the server with the RTP ports. We get the setup URI from
+  the a= attribute in the SDP message. This can be an absolute URL or a relative
+  url.
+
+  ex:
+
+    >> SETUP rtsp://thread:5454/south-rtsp.mp3/streamid=0 RTSP/1.0
+    >> CSeq: 1
+    >> Transport: RTP/AVP/UDP;unicast;client_port=5000-5001,RTP/AVP/UDP;multicast,RTP/AVP/TCP
+    >>
+    << RTSP/1.0 200 OK
+    << Transport: RTP/AVP/UDP;unicast;client_port=5000-5001;server_port=6000-6001
+    << CSeq: 1
+    << Date: Wed May 11 13:21:43 2005 GMT
+    << Session: 5d5cb94413288ccd
+    <<
+
+  The client needs to send the local ports to the server along with the supported 
+  transport types. The server selects the final transport which it returns in the
+  Transport header field. The server also includes its ports where RTP and RTCP
+  messages can be sent to.
+
+  In the above example UDP was choosen as a transport. At this point the RTSPSrc element
+  will furter configure its elements to process this stream.
+
+  The RTSPSrc will create and connect an RTP session manager element and will
+  connect it to the src pads of the udp element. The data pad from the RTP session 
+  manager is ghostpadded to RTPSrc.
+  The RTCP pad of the rtpdec is routed to a new udpsink that sends data to the RTCP
+  port of the server as returned in the Transport: header field.
+
+    +---------------------------------------------+
+    | +------------+                              |
+    | | udpsrc0    |   +--------+                 |
+    | |  port=5000 ----- rtpdec --------------------
+    | +------------+   |        |                 |
+    | +------------+   |        |  +------------+ |
+    | | udpsrc1    ----- RTCP   ---- udpsink    | |
+    | |  port=5001 |   +--------+  |  port=6001 | |
+    | +------------+               +------------+ |
+    +---------------------------------------------+
+
+  The output type of rtpdec is configured as the media type specified in the SDP
+  message. 
+
+- All the elements are set to PAUSED/PLAYING and the PLAY RTSP message is
+  sent.
+
+    >> PLAY rtsp://thread:5454/south-rtsp.mp3 RTSP/1.0
+    >> CSeq: 2
+    >> Session: 5d5cb94413288ccd
+    >>
+    << RTSP/1.0 200 OK
+    << CSeq: 2
+    << Date: Wed May 11 13:21:43 2005 GMT
+    << Session: 5d5cb94413288ccd
+    <<
+
+- The udp source elements receive data from that point and the RTP/RTCP messages
+  are processed by the elements.
+
+- In the case of interleaved mode, the SETUP method yields:
+
+    >> SETUP rtsp://thread:5454/south-rtsp.mp3/streamid=0 RTSP/1.0
+    >> CSeq: 1
+    >> Transport: RTP/AVP/UDP;unicast;client_port=5000-5001,RTP/AVP/UDP;multicast,RTP/AVP/TCP
+    >>
+    << RTSP/1.0 200 OK
+    << Transport: RTP/AVP/TCP;interleaved=0-1
+    << CSeq: 1
+    << Date: Wed May 11 13:21:43 2005 GMT
+    << Session: 5d5cb94413288ccd
+    <<
+
+  This means that RTP/RTCP messages will be sent on channel 0/1 respectively and that
+  the data will be received on the same connection as the RTSP connection.
+
+  At this point, we remove the UDP source elements as we don't need them anymore. We
+  set up the rtpsess session manager element though as follows:
+
+    +---------------------------------------------+
+    | +------------+                              |
+    | | _loop()    |   +--------+                 |
+    | |            ----- rtpses --------------------
+    | |            |   |        |                 |
+    | |            |   |        |  +------------+ |
+    | |            ----- RTCP   ---- udpsink    | |
+    | |            |   +--------+  |  port=6001 | |
+    | +------------+               +------------+ |
+    +---------------------------------------------+
+
+  We start an interal task to start reading from the RTSP connection waiting
+  for data. The received data is then pushed to the rtpdec element.
+
+  When reading from the RTSP connection we receive data packets in the
+  following layout (see also RFC2326)
+
+    $<1 byte channel><2 bytes length, big endian><length bytes of data>
+
+
+RTSP server
+-----------
+
+An RTSP server listen on a port (default 554) for client connections. The client
+typically keeps this channel open during the RTSP session to instruct the server
+to pause/play/stop the stream.
+
+The server exposes a stream consisting of one or more media streams using an
+URL. The media streams are typically audio and video.
+
+  ex:
+     rtsp://thread:5454/alien-rtsp.mpeg
+
+     exposes an audio/video stream. The video is mpeg packetized in RTP and
+     the audio is mp3 in RTP.
+
+The streaming server typically uses a different channel to send the media
+data to clients, typically using RTP over UDP. It is also possible to stream
+the data to the client using the initial RTSP TCP session (the interleaved
+mode). This last mode is useful when the client is behind a firewall but
+does not take advantage of the RTP/UDP features.
+
+In both cases, media data is send to the clients in an unmultiplexed format
+packetized as RTP packets.
+
+The streaming server has to negotiate a connection protocol for each of the
+media streams with the client.
+
+Minimal server requirements:
+
+- The server should copy the CSeq header field in a client request to the
+  response so that the client can match the response to the request.
+
+- The server should keep a session for each client after the client issued
+  a SETUP command. The client should use the same session id for all future
+  request to this server.
+
+- the server must support an OPTIONS request send over the RTSP connection.
+
+    >> OPTIONS * RTSP/1.0
+    >> CSeq: 1
+    >>
+    << RTSP/1.0 200 OK
+    << CSeq: 1
+    << Date: Wed May 11 13:21:43 2005 GMT
+    << Session: 5d5cb94413288ccd
+    << Public: DESCRIBE, SETUP, TEARDOWN, PLAY
+    <<
+
+   The OPTIONS request should list all supported methods on the server.
+ 
+ - The server should support the DESCRIBE method.
+
+    >> DESCRIBE rtsp://thread:5454/south-rtsp.mp3 RTSP/1.0
+    >> Accept: application/sdp
+    >> CSeq: 2
+    >>
+    << RTSP/1.0 200 OK
+    << Content-Length: 84
+    << Content-Type: application/sdp
+    << CSeq: 2
+    << Date: Wed May 11 13:09:37 2005 GMT
+    <<
+    << v=0
+    << o=- 0 0 IN IP4 192.168.1.1
+    << s=No Title
+    << m=audio 0 RTP/AVP 14
+    << a=control:streamid=0
+
+    The client issues a DESCRIBE command for a specific URL that corresponds
+    to an available stream. The client will also send an Accept header to
+    list its supported formats. 
+
+    The server answers this request with a reply in one of the client supported
+    formats (application/sdp is the most common). The server typically sends a
+    fixed reply to all clients for each configured stream.
+
+ - The server must support the SETUP command to configure the media streams 
+   that were listed in the DESCRIBE command.
+
+    >> SETUP rtsp://thread:5454/south-rtsp.mp3/streamid=0 RTSP/1.0
+    >> CSeq: 3
+    >> Transport: RTP/AVP/UDP;unicast;client_port=5000-5001,RTP/AVP/UDP;multicast,RTP/AVP/TCP
+    >>
+    << RTSP/1.0 200 OK
+    << Transport: RTP/AVP/UDP;unicast;client_port=5000-5001;server_port=6000-6001
+    << CSeq: 3
+    << Date: Wed May 11 13:21:43 2005 GMT
+    << Session: 5d5cb94413288ccd
+
+    The client will send a SETUP command for each of the streams listed in the 
+    DESCRIBE reply. For sdp will use a URL as listed in the a=control: property.
+
+    The client will list the supported transports in the Transport: header field.
+    Each transport is separated with a comma (,) and listed in order of preference.
+    The server has to select the first supported transport.
+ 
+    In the above example 3 transport are listed:
+
+       RTP/AVP/UDP;unicast;client_port=5000-5001
+
+         The client will accept RTP over UDP on the port pair 5000-5001. Port
+	 5000 will accept the RTP packets, 5001 the RTSP packets send by the
+	 server.
+       
+       RTP/AVP/UDP;multicast
+
+         The client can join a multicast group for the specific media stream.
+	 The port numbers of the multicast group it will connect to have to
+	 be specified by the server in the reply.
+       
+       RTP/AVP/TCP
+
+         the client can accept RTP packets interleaved on the RTSP connection.
+
+    The server selects a supported transport an allocates an RTP port pair to
+    receive RTP and RTSP data from the client. This last step is optional when
+    the server does not accept RTP data.
+
+    The server should allocate a session for the client and should send the
+    sessionId to the client. The client should use this session id for all
+    future requests.
+
+    The server may refuse a client that does not use the same transport method
+    for all media streams.
+
+    The server stores all client port pairs in the server client session along
+    with the transport method.
+
+    ex:
+
+      For an on-demand stream the server could construct a (minimal) RTP GStreamer 
+      pipeline for the client as follows (for an mp3 stream):
+    
+      +---------+    +-----------+    +------------+    +-------------+
+      | filesrc |    | rtpmp3enc |    | rtpsession |    | udpsink     |
+      |         |    |           |    |            |    |   host=XXX  |
+      |         |    |           |    |            |    |   port=5000 |
+      |        src--sink        src--rtpsink   rtpsrc--sink           |
+      +---------+    +-----------+    |            |    +-------------+
+                                      |            |    +-------------+
+                                      |            |    | udpsink     |
+                                      |            |    |   host=XXX  |
+                                      |            |    |   port=5001 |
+                                      |       rtspsrc--sink           |
+                                      +------------+    +-------------+
+
+      The server would set the above pipeline to PAUSE to make sure no data
+      is sent to the client yet.
+
+      optionally udpsrc elements can be configured to receive client RTP and
+      RTSP messages.
+
+    ex:
+
+      For a live stream the server could construct a (minimal) RTP GStreamer 
+      pipeline for the clients as follows (for an mp3 stream):
+    
+      +---------+    +--------+    +-----------+    +------------+    +--------------+
+      | source  |    | mp3enc |    | rtpmp3enc |    | rtpsession |    | multiudpsink |
+      |         |    |        |    |           |    |            |    |   host=...   |
+      |         |    |        |    |           |    |            |    |   port=...   |
+      |        src--sink     src--sink        src--rtpsink   rtpsrc--sink            |
+      +---------+    +--------+    +-----------+    |            |    +--------------+
+                                                    |            |    +--------------+
+                                                    |            |    | multiudpsink |
+                                                    |            |    |   host=...   |
+                                                    |            |    |   port=...   |
+                                                    |       rtspsrc--sink            |
+                                                    +------------+    +--------------+
+
+      Media data is streamed to clients by adding the client host and port numbers
+      to the multiudpsinks.
+
+      optionally udpsrc elements can be configured to receive client RTP and
+      RTSP messages.
+     
+ - The server must support the PLAY command to start playback of the configured
+   media streams.
+
+    >> PLAY rtsp://thread:5454/south-rtsp.mp3 RTSP/1.0
+    >> CSeq: 2
+    >> Session: 5d5cb94413288ccd
+    >>
+    << RTSP/1.0 200 OK
+    << CSeq: 2
+    << Date: Wed May 11 13:21:43 2005 GMT
+    << Session: 5d5cb94413288ccd
+    <<
+
+    Using the Session: header field, the server finds the pipeline of the session
+    to PLAY and sets the pipeline to PLAYING at which point the client receives
+    the media stream data.
+
+    In case of a live stream, the server adds the port numbers to a multiudpsink
+    element.
+
+ - The server must support the TEARDOWN command to stop playback and free the
+   session of a client.
+
+    >> TEARDOWN rtsp://thread:5454/south-rtsp.mp3 RTSP/1.0
+    >> CSeq: 4
+    >> Session: 5d5cb94413288ccd
+    >>
+    << RTSP/1.0 200 OK
+    << CSeq: 4
+    << Date: Wed May 11 13:21:43 2005 GMT
+    <<
+
+    The server destroys the client pipeline in case of an on-demand stream or
+    removes the client ports from the multiudpsinks. This effectively stops
+    streaming to the client.
+
+
diff --git a/gst/rtsp/URLS b/gst/rtsp/URLS
new file mode 100644
index 0000000..26b4008
--- /dev/null
+++ b/gst/rtsp/URLS
@@ -0,0 +1,38 @@
+Some test URLS:
+
+SVQ3 video: 
+  rtsp://cumulus.creative.auckland.ac.nz/~shado/nelson_iv_512k.mov
+  rtsp://streamr.hitpops.jp/ngc/mov/m0609.mov 
+
+ASF (audio/video): 
+  rtsp://aod.mylisten.com/aod/8/03/069803_0903135.wma
+  rtsp://195.246.8.69/dur_pull_hi
+  rtsp://195.219.160.200/mcp?chid=25&pid=196&vid=2402201&br=800&tid=1&void=2844&muk=H1J4yFr0mJB
+  rtsp://a1174.v26630f.c26630.g.vm.akamaistream.net/7/1174/26630/361/od-video.msn.com/8/mbr/rs_perf_dilana_091206_finale9135.wmv
+
+MP4V-ES/mpeg4-generic(ACC):
+  rtsp://vod.nwec.jp/quicktime/505.mov
+  rtsp://203.140.68.241:554/hirakataeizou9.mp4
+  rtsp://kmdi.utoronto.ca:555/osconf/2004_may9.1.mp4
+
+X-QT(h264)/mpeg4-generic(ACC):
+  rtsp://a2047.v1413b.c1413.g.vq.akamaistream.net/5/2047/1413/1_h264_110/1a1a1ae656c632970267e04ebd3196c428970e7ce857b81c4aab1677e445aedc3fae1b4a7bafe013/8848125_1_110.mov
+
+MP4V-ES/MP4A-LATM
+  rtsp://68.251.168.13/thisislove.3gp
+
+H264/MPA
+  rtsp://130.192.86.166/ed.mov
+
+REAL:
+  rtsp://213.254.239.61/farm/*/encoder/tagesschau/live1high.rm
+  rtsp://64.192.137.105:554/real.amazon-de.eu2/phononet/B/0/0/0/H/W/Y/4/K/S/01.01.rm?cloakport=80,554,7070
+
+  rtsp://211.89.225.1/encoder/cnr7_p
+  rtsp://stream2.visual.cz/broadcast/ct/CT24-High.rm
+
+AAC, interleaved:
+  rtsp://ia300135.us.archive.org:554/0/items/uncovered_interviews/uncovered_interviews_3_256kb.mp4
+
+Various samples here:
+  http://www.jet-stream.nl/samples/mp4.html
diff --git a/gst/rtsp/gstrtpdec.c b/gst/rtsp/gstrtpdec.c
new file mode 100644
index 0000000..3cf7c79
--- /dev/null
+++ b/gst/rtsp/gstrtpdec.c
@@ -0,0 +1,898 @@
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* Element-Checklist-Version: 5 */
+
+/**
+ * SECTION:element-rtpdec
+ *
+ * A simple RTP session manager used internally by rtspsrc.
+ */
+
+/* #define HAVE_RTCP */
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#ifdef HAVE_RTCP
+#include <gst/rtp/gstrtcpbuffer.h>
+#endif
+
+#include "gstrtpdec.h"
+#include <stdio.h>
+
+GST_DEBUG_CATEGORY_STATIC (rtpdec_debug);
+#define GST_CAT_DEFAULT (rtpdec_debug)
+
+/* GstRTPDec signals and args */
+enum
+{
+  SIGNAL_REQUEST_PT_MAP,
+  SIGNAL_CLEAR_PT_MAP,
+
+  SIGNAL_ON_NEW_SSRC,
+  SIGNAL_ON_SSRC_COLLISION,
+  SIGNAL_ON_SSRC_VALIDATED,
+  SIGNAL_ON_BYE_SSRC,
+  SIGNAL_ON_BYE_TIMEOUT,
+  SIGNAL_ON_TIMEOUT,
+  LAST_SIGNAL
+};
+
+#define DEFAULT_LATENCY_MS      200
+
+enum
+{
+  PROP_0,
+  PROP_LATENCY
+};
+
+static GstStaticPadTemplate gst_rtp_dec_recv_rtp_sink_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static GstStaticPadTemplate gst_rtp_dec_recv_rtcp_sink_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("application/x-rtcp")
+    );
+
+static GstStaticPadTemplate gst_rtp_dec_recv_rtp_src_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%u_%u_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+
+static GstStaticPadTemplate gst_rtp_dec_rtcp_src_template =
+GST_STATIC_PAD_TEMPLATE ("rtcp_src_%u",
+    GST_PAD_SRC,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS ("application/x-rtcp")
+    );
+
+static void gst_rtp_dec_finalize (GObject * object);
+static void gst_rtp_dec_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_rtp_dec_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+static GstClock *gst_rtp_dec_provide_clock (GstElement * element);
+static GstStateChangeReturn gst_rtp_dec_change_state (GstElement * element,
+    GstStateChange transition);
+static GstPad *gst_rtp_dec_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
+static void gst_rtp_dec_release_pad (GstElement * element, GstPad * pad);
+
+static GstFlowReturn gst_rtp_dec_chain_rtp (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer);
+static GstFlowReturn gst_rtp_dec_chain_rtcp (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer);
+
+
+/* Manages the receiving end of the packets.
+ *
+ * There is one such structure for each RTP session (audio/video/...).
+ * We get the RTP/RTCP packets and stuff them into the session manager. 
+ */
+struct _GstRTPDecSession
+{
+  /* session id */
+  gint id;
+  /* the parent bin */
+  GstRTPDec *dec;
+
+  gboolean active;
+  /* we only support one ssrc and one pt */
+  guint32 ssrc;
+  guint8 pt;
+  GstCaps *caps;
+
+  /* the pads of the session */
+  GstPad *recv_rtp_sink;
+  GstPad *recv_rtp_src;
+  GstPad *recv_rtcp_sink;
+  GstPad *rtcp_src;
+};
+
+/* find a session with the given id */
+static GstRTPDecSession *
+find_session_by_id (GstRTPDec * rtpdec, gint id)
+{
+  GSList *walk;
+
+  for (walk = rtpdec->sessions; walk; walk = g_slist_next (walk)) {
+    GstRTPDecSession *sess = (GstRTPDecSession *) walk->data;
+
+    if (sess->id == id)
+      return sess;
+  }
+  return NULL;
+}
+
+/* create a session with the given id */
+static GstRTPDecSession *
+create_session (GstRTPDec * rtpdec, gint id)
+{
+  GstRTPDecSession *sess;
+
+  sess = g_new0 (GstRTPDecSession, 1);
+  sess->id = id;
+  sess->dec = rtpdec;
+  rtpdec->sessions = g_slist_prepend (rtpdec->sessions, sess);
+
+  return sess;
+}
+
+static void
+free_session (GstRTPDecSession * session)
+{
+  g_free (session);
+}
+
+static guint gst_rtp_dec_signals[LAST_SIGNAL] = { 0 };
+
+#define gst_rtp_dec_parent_class parent_class
+G_DEFINE_TYPE (GstRTPDec, gst_rtp_dec, GST_TYPE_ELEMENT);
+
+static void
+gst_rtp_dec_class_init (GstRTPDecClass * g_class)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRTPDecClass *klass;
+
+  klass = (GstRTPDecClass *) g_class;
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (rtpdec_debug, "rtpdec", 0, "RTP decoder");
+
+  gobject_class->finalize = gst_rtp_dec_finalize;
+  gobject_class->set_property = gst_rtp_dec_set_property;
+  gobject_class->get_property = gst_rtp_dec_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_LATENCY,
+      g_param_spec_uint ("latency", "Buffer latency in ms",
+          "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTPDec::request-pt-map:
+   * @rtpdec: the object which received the signal
+   * @session: the session
+   * @pt: the pt
+   *
+   * Request the payload type as #GstCaps for @pt in @session.
+   */
+  gst_rtp_dec_signals[SIGNAL_REQUEST_PT_MAP] =
+      g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, request_pt_map),
+      NULL, NULL, g_cclosure_marshal_generic, GST_TYPE_CAPS, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+
+  gst_rtp_dec_signals[SIGNAL_CLEAR_PT_MAP] =
+      g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, clear_pt_map),
+      NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
+
+  /**
+   * GstRTPDec::on-new-ssrc:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC 
+   *
+   * Notify of a new SSRC that entered @session.
+   */
+  gst_rtp_dec_signals[SIGNAL_ON_NEW_SSRC] =
+      g_signal_new ("on-new-ssrc", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_new_ssrc),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+  /**
+   * GstRTPDec::on-ssrc_collision:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC 
+   *
+   * Notify when we have an SSRC collision
+   */
+  gst_rtp_dec_signals[SIGNAL_ON_SSRC_COLLISION] =
+      g_signal_new ("on-ssrc-collision", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_ssrc_collision),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+  /**
+   * GstRTPDec::on-ssrc_validated:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC 
+   *
+   * Notify of a new SSRC that became validated.
+   */
+  gst_rtp_dec_signals[SIGNAL_ON_SSRC_VALIDATED] =
+      g_signal_new ("on-ssrc-validated", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_ssrc_validated),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+
+  /**
+   * GstRTPDec::on-bye-ssrc:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC 
+   *
+   * Notify of an SSRC that became inactive because of a BYE packet.
+   */
+  gst_rtp_dec_signals[SIGNAL_ON_BYE_SSRC] =
+      g_signal_new ("on-bye-ssrc", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_bye_ssrc),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+  /**
+   * GstRTPDec::on-bye-timeout:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC 
+   *
+   * Notify of an SSRC that has timed out because of BYE
+   */
+  gst_rtp_dec_signals[SIGNAL_ON_BYE_TIMEOUT] =
+      g_signal_new ("on-bye-timeout", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_bye_timeout),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+  /**
+   * GstRTPDec::on-timeout:
+   * @rtpbin: the object which received the signal
+   * @session: the session
+   * @ssrc: the SSRC 
+   *
+   * Notify of an SSRC that has timed out
+   */
+  gst_rtp_dec_signals[SIGNAL_ON_TIMEOUT] =
+      g_signal_new ("on-timeout", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_timeout),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
+      G_TYPE_UINT);
+
+  gstelement_class->provide_clock =
+      GST_DEBUG_FUNCPTR (gst_rtp_dec_provide_clock);
+  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_dec_change_state);
+  gstelement_class->request_new_pad =
+      GST_DEBUG_FUNCPTR (gst_rtp_dec_request_new_pad);
+  gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_dec_release_pad);
+
+  /* sink pads */
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_dec_recv_rtp_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_dec_recv_rtcp_sink_template);
+  /* src pads */
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_dec_recv_rtp_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_dec_rtcp_src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "RTP Decoder",
+      "Codec/Parser/Network",
+      "Accepts raw RTP and RTCP packets and sends them forward",
+      "Wim Taymans <wim.taymans@gmail.com>");
+}
+
+static void
+gst_rtp_dec_init (GstRTPDec * rtpdec)
+{
+  rtpdec->provided_clock = gst_system_clock_obtain ();
+  rtpdec->latency = DEFAULT_LATENCY_MS;
+
+  GST_OBJECT_FLAG_SET (rtpdec, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
+}
+
+static void
+gst_rtp_dec_finalize (GObject * object)
+{
+  GstRTPDec *rtpdec;
+
+  rtpdec = GST_RTP_DEC (object);
+
+  gst_object_unref (rtpdec->provided_clock);
+  g_slist_foreach (rtpdec->sessions, (GFunc) free_session, NULL);
+  g_slist_free (rtpdec->sessions);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_dec_query_src (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  gboolean res;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_LATENCY:
+    {
+      /* we pretend to be live with a 3 second latency */
+      /* FIXME: Do we really have infinite maximum latency? */
+      gst_query_set_latency (query, TRUE, 3 * GST_SECOND, -1);
+      res = TRUE;
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+  return res;
+}
+
+static GstFlowReturn
+gst_rtp_dec_chain_rtp (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstFlowReturn res;
+  GstRTPDec *rtpdec;
+  GstRTPDecSession *session;
+  guint32 ssrc;
+  guint8 pt;
+  GstRTPBuffer rtp = { NULL, };
+
+  rtpdec = GST_RTP_DEC (parent);
+
+  GST_DEBUG_OBJECT (rtpdec, "got rtp packet");
+
+  if (!gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp))
+    goto bad_packet;
+
+  ssrc = gst_rtp_buffer_get_ssrc (&rtp);
+  pt = gst_rtp_buffer_get_payload_type (&rtp);
+  gst_rtp_buffer_unmap (&rtp);
+
+  GST_DEBUG_OBJECT (rtpdec, "SSRC %08x, PT %d", ssrc, pt);
+
+  /* find session */
+  session = gst_pad_get_element_private (pad);
+
+  /* see if we have the pad */
+  if (!session->active) {
+    GstPadTemplate *templ;
+    GstElementClass *klass;
+    gchar *name;
+    GstCaps *caps;
+    GValue ret = { 0 };
+    GValue args[3] = { {0}
+    , {0}
+    , {0}
+    };
+
+    GST_DEBUG_OBJECT (rtpdec, "creating stream");
+
+    session->ssrc = ssrc;
+    session->pt = pt;
+
+    /* get pt map */
+    g_value_init (&args[0], GST_TYPE_ELEMENT);
+    g_value_set_object (&args[0], rtpdec);
+    g_value_init (&args[1], G_TYPE_UINT);
+    g_value_set_uint (&args[1], session->id);
+    g_value_init (&args[2], G_TYPE_UINT);
+    g_value_set_uint (&args[2], pt);
+
+    g_value_init (&ret, GST_TYPE_CAPS);
+    g_value_set_boxed (&ret, NULL);
+
+    g_signal_emitv (args, gst_rtp_dec_signals[SIGNAL_REQUEST_PT_MAP], 0, &ret);
+
+    caps = (GstCaps *) g_value_get_boxed (&ret);
+
+    name = g_strdup_printf ("recv_rtp_src_%u_%u_%u", session->id, ssrc, pt);
+    klass = GST_ELEMENT_GET_CLASS (rtpdec);
+    templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%u_%u_%u");
+    session->recv_rtp_src = gst_pad_new_from_template (templ, name);
+    g_free (name);
+
+    gst_pad_set_caps (session->recv_rtp_src, caps);
+
+    gst_pad_set_element_private (session->recv_rtp_src, session);
+    gst_pad_set_query_function (session->recv_rtp_src, gst_rtp_dec_query_src);
+    gst_pad_set_active (session->recv_rtp_src, TRUE);
+    gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_src);
+
+    session->active = TRUE;
+  }
+
+  res = gst_pad_push (session->recv_rtp_src, buffer);
+
+  return res;
+
+bad_packet:
+  {
+    GST_ELEMENT_WARNING (rtpdec, STREAM, DECODE, (NULL),
+        ("RTP packet did not validate, dropping"));
+    gst_buffer_unref (buffer);
+    return GST_FLOW_OK;
+  }
+}
+
+static GstFlowReturn
+gst_rtp_dec_chain_rtcp (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstRTPDec *src;
+
+#ifdef HAVE_RTCP
+  gboolean valid;
+  GstRTCPPacket packet;
+  gboolean more;
+#endif
+
+  src = GST_RTP_DEC (parent);
+
+  GST_DEBUG_OBJECT (src, "got rtcp packet");
+
+#ifdef HAVE_RTCP
+  valid = gst_rtcp_buffer_validate (buffer);
+  if (!valid)
+    goto bad_packet;
+
+  /* position on first packet */
+  more = gst_rtcp_buffer_get_first_packet (buffer, &packet);
+  while (more) {
+    switch (gst_rtcp_packet_get_type (&packet)) {
+      case GST_RTCP_TYPE_SR:
+      {
+        guint32 ssrc, rtptime, packet_count, octet_count;
+        guint64 ntptime;
+        guint count, i;
+
+        gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, &ntptime, &rtptime,
+            &packet_count, &octet_count);
+
+        GST_DEBUG_OBJECT (src,
+            "got SR packet: SSRC %08x, NTP %" G_GUINT64_FORMAT
+            ", RTP %u, PC %u, OC %u", ssrc, ntptime, rtptime, packet_count,
+            octet_count);
+
+        count = gst_rtcp_packet_get_rb_count (&packet);
+        for (i = 0; i < count; i++) {
+          guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
+          guint8 fractionlost;
+          gint32 packetslost;
+
+          gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
+              &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
+
+          GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
+              ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
+              packetslost, exthighestseq, jitter, lsr, dlsr);
+        }
+        break;
+      }
+      case GST_RTCP_TYPE_RR:
+      {
+        guint32 ssrc;
+        guint count, i;
+
+        ssrc = gst_rtcp_packet_rr_get_ssrc (&packet);
+
+        GST_DEBUG_OBJECT (src, "got RR packet: SSRC %08x", ssrc);
+
+        count = gst_rtcp_packet_get_rb_count (&packet);
+        for (i = 0; i < count; i++) {
+          guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
+          guint8 fractionlost;
+          gint32 packetslost;
+
+          gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
+              &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
+
+          GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
+              ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
+              packetslost, exthighestseq, jitter, lsr, dlsr);
+        }
+        break;
+      }
+      case GST_RTCP_TYPE_SDES:
+      {
+        guint chunks, i, j;
+        gboolean more_chunks, more_items;
+
+        chunks = gst_rtcp_packet_sdes_get_chunk_count (&packet);
+        GST_DEBUG_OBJECT (src, "got SDES packet with %d chunks", chunks);
+
+        more_chunks = gst_rtcp_packet_sdes_first_chunk (&packet);
+        i = 0;
+        while (more_chunks) {
+          guint32 ssrc;
+
+          ssrc = gst_rtcp_packet_sdes_get_ssrc (&packet);
+
+          GST_DEBUG_OBJECT (src, "chunk %d, SSRC %08x", i, ssrc);
+
+          more_items = gst_rtcp_packet_sdes_first_item (&packet);
+          j = 0;
+          while (more_items) {
+            GstRTCPSDESType type;
+            guint8 len;
+            gchar *data;
+
+            gst_rtcp_packet_sdes_get_item (&packet, &type, &len, &data);
+
+            GST_DEBUG_OBJECT (src, "item %d, type %d, len %d, data %s", j,
+                type, len, data);
+
+            more_items = gst_rtcp_packet_sdes_next_item (&packet);
+            j++;
+          }
+          more_chunks = gst_rtcp_packet_sdes_next_chunk (&packet);
+          i++;
+        }
+        break;
+      }
+      case GST_RTCP_TYPE_BYE:
+      {
+        guint count, i;
+        gchar *reason;
+
+        reason = gst_rtcp_packet_bye_get_reason (&packet);
+        GST_DEBUG_OBJECT (src, "got BYE packet (reason: %s)",
+            GST_STR_NULL (reason));
+        g_free (reason);
+
+        count = gst_rtcp_packet_bye_get_ssrc_count (&packet);
+        for (i = 0; i < count; i++) {
+          guint32 ssrc;
+
+
+          ssrc = gst_rtcp_packet_bye_get_nth_ssrc (&packet, i);
+
+          GST_DEBUG_OBJECT (src, "SSRC: %08x", ssrc);
+        }
+        break;
+      }
+      case GST_RTCP_TYPE_APP:
+        GST_DEBUG_OBJECT (src, "got APP packet");
+        break;
+      default:
+        GST_WARNING_OBJECT (src, "got unknown RTCP packet");
+        break;
+    }
+    more = gst_rtcp_packet_move_to_next (&packet);
+  }
+  gst_buffer_unref (buffer);
+  return GST_FLOW_OK;
+
+bad_packet:
+  {
+    GST_WARNING_OBJECT (src, "got invalid RTCP packet");
+    gst_buffer_unref (buffer);
+    return GST_FLOW_OK;
+  }
+#else
+  gst_buffer_unref (buffer);
+  return GST_FLOW_OK;
+#endif
+}
+
+static void
+gst_rtp_dec_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRTPDec *src;
+
+  src = GST_RTP_DEC (object);
+
+  switch (prop_id) {
+    case PROP_LATENCY:
+      src->latency = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_dec_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstRTPDec *src;
+
+  src = GST_RTP_DEC (object);
+
+  switch (prop_id) {
+    case PROP_LATENCY:
+      g_value_set_uint (value, src->latency);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstClock *
+gst_rtp_dec_provide_clock (GstElement * element)
+{
+  GstRTPDec *rtpdec;
+
+  rtpdec = GST_RTP_DEC (element);
+
+  return GST_CLOCK_CAST (gst_object_ref (rtpdec->provided_clock));
+}
+
+static GstStateChangeReturn
+gst_rtp_dec_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+
+  switch (transition) {
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      /* we're NO_PREROLL when going to PAUSED */
+      ret = GST_STATE_CHANGE_NO_PREROLL;
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+/* Create a pad for receiving RTP for the session in @name
+ */
+static GstPad *
+create_recv_rtp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
+{
+  guint sessid;
+  GstRTPDecSession *session;
+
+  /* first get the session number */
+  if (name == NULL || sscanf (name, "recv_rtp_sink_%u", &sessid) != 1)
+    goto no_name;
+
+  GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
+
+  /* get or create session */
+  session = find_session_by_id (rtpdec, sessid);
+  if (!session) {
+    GST_DEBUG_OBJECT (rtpdec, "creating session %d", sessid);
+    /* create session now */
+    session = create_session (rtpdec, sessid);
+    if (session == NULL)
+      goto create_error;
+  }
+  /* check if pad was requested */
+  if (session->recv_rtp_sink != NULL)
+    goto existed;
+
+  GST_DEBUG_OBJECT (rtpdec, "getting RTP sink pad");
+
+  session->recv_rtp_sink = gst_pad_new_from_template (templ, name);
+  gst_pad_set_element_private (session->recv_rtp_sink, session);
+  gst_pad_set_chain_function (session->recv_rtp_sink, gst_rtp_dec_chain_rtp);
+  gst_pad_set_active (session->recv_rtp_sink, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_sink);
+
+  return session->recv_rtp_sink;
+
+  /* ERRORS */
+no_name:
+  {
+    g_warning ("rtpdec: invalid name given");
+    return NULL;
+  }
+create_error:
+  {
+    /* create_session already warned */
+    return NULL;
+  }
+existed:
+  {
+    g_warning ("rtpdec: recv_rtp pad already requested for session %d", sessid);
+    return NULL;
+  }
+}
+
+/* Create a pad for receiving RTCP for the session in @name
+ */
+static GstPad *
+create_recv_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ,
+    const gchar * name)
+{
+  guint sessid;
+  GstRTPDecSession *session;
+
+  /* first get the session number */
+  if (name == NULL || sscanf (name, "recv_rtcp_sink_%u", &sessid) != 1)
+    goto no_name;
+
+  GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
+
+  /* get the session, it must exist or we error */
+  session = find_session_by_id (rtpdec, sessid);
+  if (!session)
+    goto no_session;
+
+  /* check if pad was requested */
+  if (session->recv_rtcp_sink != NULL)
+    goto existed;
+
+  GST_DEBUG_OBJECT (rtpdec, "getting RTCP sink pad");
+
+  session->recv_rtcp_sink = gst_pad_new_from_template (templ, name);
+  gst_pad_set_element_private (session->recv_rtp_sink, session);
+  gst_pad_set_chain_function (session->recv_rtcp_sink, gst_rtp_dec_chain_rtcp);
+  gst_pad_set_active (session->recv_rtcp_sink, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtcp_sink);
+
+  return session->recv_rtcp_sink;
+
+  /* ERRORS */
+no_name:
+  {
+    g_warning ("rtpdec: invalid name given");
+    return NULL;
+  }
+no_session:
+  {
+    g_warning ("rtpdec: no session with id %d", sessid);
+    return NULL;
+  }
+existed:
+  {
+    g_warning ("rtpdec: recv_rtcp pad already requested for session %d",
+        sessid);
+    return NULL;
+  }
+}
+
+/* Create a pad for sending RTCP for the session in @name
+ */
+static GstPad *
+create_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
+{
+  guint sessid;
+  GstRTPDecSession *session;
+
+  /* first get the session number */
+  if (name == NULL || sscanf (name, "rtcp_src_%u", &sessid) != 1)
+    goto no_name;
+
+  /* get or create session */
+  session = find_session_by_id (rtpdec, sessid);
+  if (!session)
+    goto no_session;
+
+  /* check if pad was requested */
+  if (session->rtcp_src != NULL)
+    goto existed;
+
+  session->rtcp_src = gst_pad_new_from_template (templ, name);
+  gst_pad_set_active (session->rtcp_src, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->rtcp_src);
+
+  return session->rtcp_src;
+
+  /* ERRORS */
+no_name:
+  {
+    g_warning ("rtpdec: invalid name given");
+    return NULL;
+  }
+no_session:
+  {
+    g_warning ("rtpdec: session with id %d does not exist", sessid);
+    return NULL;
+  }
+existed:
+  {
+    g_warning ("rtpdec: rtcp_src pad already requested for session %d", sessid);
+    return NULL;
+  }
+}
+
+/* 
+ */
+static GstPad *
+gst_rtp_dec_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
+{
+  GstRTPDec *rtpdec;
+  GstElementClass *klass;
+  GstPad *result;
+
+  g_return_val_if_fail (templ != NULL, NULL);
+  g_return_val_if_fail (GST_IS_RTP_DEC (element), NULL);
+
+  rtpdec = GST_RTP_DEC (element);
+  klass = GST_ELEMENT_GET_CLASS (element);
+
+  /* figure out the template */
+  if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%u")) {
+    result = create_recv_rtp (rtpdec, templ, name);
+  } else if (templ == gst_element_class_get_pad_template (klass,
+          "recv_rtcp_sink_%u")) {
+    result = create_recv_rtcp (rtpdec, templ, name);
+  } else if (templ == gst_element_class_get_pad_template (klass, "rtcp_src_%u")) {
+    result = create_rtcp (rtpdec, templ, name);
+  } else
+    goto wrong_template;
+
+  return result;
+
+  /* ERRORS */
+wrong_template:
+  {
+    g_warning ("rtpdec: this is not our template");
+    return NULL;
+  }
+}
+
+static void
+gst_rtp_dec_release_pad (GstElement * element, GstPad * pad)
+{
+}
diff --git a/gst/rtsp/gstrtpdec.h b/gst/rtsp/gstrtpdec.h
new file mode 100644
index 0000000..5e83e23
--- /dev/null
+++ b/gst/rtsp/gstrtpdec.h
@@ -0,0 +1,88 @@
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_RTP_DEC_H__
+#define __GST_RTP_DEC_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_DEC  		(gst_rtp_dec_get_type())
+#define GST_IS_RTP_DEC(obj)  		(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_DEC))
+#define GST_IS_RTP_DEC_CLASS(klass) 	(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_DEC))
+#define GST_RTP_DEC(obj)  		(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_DEC, GstRTPDec))
+#define GST_RTP_DEC_CLASS(klass)  	(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_DEC, GstRTPDecClass))
+
+typedef struct _GstRTPDec GstRTPDec;
+typedef struct _GstRTPDecClass GstRTPDecClass;
+typedef struct _GstRTPDecSession GstRTPDecSession;
+
+struct _GstRTPDec {
+  GstElement  element;
+
+  guint       latency;
+  GSList     *sessions;
+  GstClock   *provided_clock;
+};
+
+struct _GstRTPDecClass {
+  GstElementClass parent_class;
+
+  /* get the caps for pt */
+  GstCaps* (*request_pt_map)  (GstRTPDec *rtpdec, guint session, guint pt);
+
+  void     (*clear_pt_map)    (GstRTPDec *rtpdec);
+
+  void     (*on_new_ssrc)       (GstRTPDec *rtpdec, guint session, guint32 ssrc);
+  void     (*on_ssrc_collision) (GstRTPDec *rtpdec, guint session, guint32 ssrc);
+  void     (*on_ssrc_validated) (GstRTPDec *rtpdec, guint session, guint32 ssrc);
+  void     (*on_bye_ssrc)       (GstRTPDec *rtpdec, guint session, guint32 ssrc);
+  void     (*on_bye_timeout)    (GstRTPDec *rtpdec, guint session, guint32 ssrc);
+  void     (*on_timeout)        (GstRTPDec *rtpdec, guint session, guint32 ssrc);
+};
+
+GType gst_rtp_dec_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_DEC_H__ */
diff --git a/gst/rtsp/gstrtsp.c b/gst/rtsp/gstrtsp.c
new file mode 100644
index 0000000..66e2c3f
--- /dev/null
+++ b/gst/rtsp/gstrtsp.c
@@ -0,0 +1,74 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *               <2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gst/gst-i18n-plugin.h"
+
+#include "gstrtpdec.h"
+#include "gstrtspsrc.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+#ifdef ENABLE_NLS
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif /* ENABLE_NLS */
+
+  if (!gst_element_register (plugin, "rtspsrc", GST_RANK_NONE,
+          GST_TYPE_RTSPSRC))
+    return FALSE;
+  if (!gst_element_register (plugin, "rtpdec", GST_RANK_NONE, GST_TYPE_RTP_DEC))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    rtsp,
+    "transfer data via RTSP",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/rtsp/gstrtsp.h b/gst/rtsp/gstrtsp.h
new file mode 100644
index 0000000..e0f5ef8
--- /dev/null
+++ b/gst/rtsp/gstrtsp.h
@@ -0,0 +1,53 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *               <2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_RTSP_H__
+#define __GST_RTSP_H__
+
+G_BEGIN_DECLS
+
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_H__ */
+
diff --git a/gst/rtsp/gstrtspext.c b/gst/rtsp/gstrtspext.c
new file mode 100644
index 0000000..07b5a97
--- /dev/null
+++ b/gst/rtsp/gstrtspext.c
@@ -0,0 +1,268 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "gstrtspext.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtspext_debug);
+#define GST_CAT_DEFAULT (rtspext_debug)
+
+static GList *extensions;
+
+static gboolean
+gst_rtsp_ext_list_filter (GstPluginFeature * feature, gpointer user_data)
+{
+  GstElementFactory *factory;
+  guint rank;
+
+  /* we only care about element factories */
+  if (!GST_IS_ELEMENT_FACTORY (feature))
+    return FALSE;
+
+  factory = GST_ELEMENT_FACTORY (feature);
+
+  if (!gst_element_factory_has_interface (factory, "GstRTSPExtension"))
+    return FALSE;
+
+  /* only select elements with autoplugging rank */
+  rank = gst_plugin_feature_get_rank (feature);
+  if (rank < GST_RANK_MARGINAL)
+    return FALSE;
+
+  return TRUE;
+}
+
+void
+gst_rtsp_ext_list_init (void)
+{
+  GST_DEBUG_CATEGORY_INIT (rtspext_debug, "rtspext", 0, "RTSP extension");
+
+  /* get a list of all extensions */
+  extensions = gst_registry_feature_filter (gst_registry_get (),
+      (GstPluginFeatureFilter) gst_rtsp_ext_list_filter, FALSE, NULL);
+}
+
+GstRTSPExtensionList *
+gst_rtsp_ext_list_get (void)
+{
+  GstRTSPExtensionList *result;
+  GList *walk;
+
+  result = g_new0 (GstRTSPExtensionList, 1);
+
+  for (walk = extensions; walk; walk = g_list_next (walk)) {
+    GstElementFactory *factory = GST_ELEMENT_FACTORY (walk->data);
+    GstElement *element;
+
+    element = gst_element_factory_create (factory, NULL);
+    if (!element) {
+      GST_ERROR ("could not create extension instance");
+      continue;
+    }
+
+    GST_DEBUG ("added extension interface for '%s'",
+        GST_ELEMENT_NAME (element));
+    result->extensions = g_list_prepend (result->extensions, element);
+  }
+  return result;
+}
+
+void
+gst_rtsp_ext_list_free (GstRTSPExtensionList * ext)
+{
+  GList *walk;
+
+  for (walk = ext->extensions; walk; walk = g_list_next (walk)) {
+    GstRTSPExtension *elem = (GstRTSPExtension *) walk->data;
+
+    gst_object_unref (GST_OBJECT_CAST (elem));
+  }
+  g_list_free (ext->extensions);
+  g_free (ext);
+}
+
+gboolean
+gst_rtsp_ext_list_detect_server (GstRTSPExtensionList * ext,
+    GstRTSPMessage * resp)
+{
+  GList *walk;
+  gboolean res = TRUE;
+
+  for (walk = ext->extensions; walk; walk = g_list_next (walk)) {
+    GstRTSPExtension *elem = (GstRTSPExtension *) walk->data;
+
+    res = gst_rtsp_extension_detect_server (elem, resp);
+  }
+  return res;
+}
+
+GstRTSPResult
+gst_rtsp_ext_list_before_send (GstRTSPExtensionList * ext, GstRTSPMessage * req)
+{
+  GList *walk;
+  GstRTSPResult res = GST_RTSP_OK;
+
+  for (walk = ext->extensions; walk; walk = g_list_next (walk)) {
+    GstRTSPExtension *elem = (GstRTSPExtension *) walk->data;
+
+    res = gst_rtsp_extension_before_send (elem, req);
+  }
+  return res;
+}
+
+GstRTSPResult
+gst_rtsp_ext_list_after_send (GstRTSPExtensionList * ext, GstRTSPMessage * req,
+    GstRTSPMessage * resp)
+{
+  GList *walk;
+  GstRTSPResult res = GST_RTSP_OK;
+
+  for (walk = ext->extensions; walk; walk = g_list_next (walk)) {
+    GstRTSPExtension *elem = (GstRTSPExtension *) walk->data;
+
+    res = gst_rtsp_extension_after_send (elem, req, resp);
+  }
+  return res;
+}
+
+GstRTSPResult
+gst_rtsp_ext_list_parse_sdp (GstRTSPExtensionList * ext, GstSDPMessage * sdp,
+    GstStructure * s)
+{
+  GList *walk;
+  GstRTSPResult res = GST_RTSP_OK;
+
+  for (walk = ext->extensions; walk; walk = g_list_next (walk)) {
+    GstRTSPExtension *elem = (GstRTSPExtension *) walk->data;
+
+    res = gst_rtsp_extension_parse_sdp (elem, sdp, s);
+  }
+  return res;
+}
+
+GstRTSPResult
+gst_rtsp_ext_list_setup_media (GstRTSPExtensionList * ext, GstSDPMedia * media)
+{
+  GList *walk;
+  GstRTSPResult res = GST_RTSP_OK;
+
+  for (walk = ext->extensions; walk; walk = g_list_next (walk)) {
+    GstRTSPExtension *elem = (GstRTSPExtension *) walk->data;
+
+    res = gst_rtsp_extension_setup_media (elem, media);
+  }
+  return res;
+}
+
+gboolean
+gst_rtsp_ext_list_configure_stream (GstRTSPExtensionList * ext, GstCaps * caps)
+{
+  GList *walk;
+  gboolean res = TRUE;
+
+  for (walk = ext->extensions; walk; walk = g_list_next (walk)) {
+    GstRTSPExtension *elem = (GstRTSPExtension *) walk->data;
+
+    res = gst_rtsp_extension_configure_stream (elem, caps);
+    if (!res)
+      break;
+  }
+  return res;
+}
+
+GstRTSPResult
+gst_rtsp_ext_list_get_transports (GstRTSPExtensionList * ext,
+    GstRTSPLowerTrans protocols, gchar ** transport)
+{
+  GList *walk;
+  GstRTSPResult res = GST_RTSP_OK;
+
+  for (walk = ext->extensions; walk; walk = g_list_next (walk)) {
+    GstRTSPExtension *elem = (GstRTSPExtension *) walk->data;
+
+    res = gst_rtsp_extension_get_transports (elem, protocols, transport);
+  }
+  return res;
+}
+
+GstRTSPResult
+gst_rtsp_ext_list_stream_select (GstRTSPExtensionList * ext, GstRTSPUrl * url)
+{
+  GList *walk;
+  GstRTSPResult res = GST_RTSP_OK;
+
+  for (walk = ext->extensions; walk; walk = g_list_next (walk)) {
+    GstRTSPExtension *elem = (GstRTSPExtension *) walk->data;
+
+    res = gst_rtsp_extension_stream_select (elem, url);
+  }
+  return res;
+}
+
+void
+gst_rtsp_ext_list_connect (GstRTSPExtensionList * ext,
+    const gchar * detailed_signal, GCallback c_handler, gpointer data)
+{
+  GList *walk;
+
+  for (walk = ext->extensions; walk; walk = g_list_next (walk)) {
+    GstRTSPExtension *elem = (GstRTSPExtension *) walk->data;
+
+    g_signal_connect (elem, detailed_signal, c_handler, data);
+  }
+}
+
+GstRTSPResult
+gst_rtsp_ext_list_receive_request (GstRTSPExtensionList * ext,
+    GstRTSPMessage * req)
+{
+  GList *walk;
+  GstRTSPResult res = GST_RTSP_ENOTIMPL;
+
+  for (walk = ext->extensions; walk; walk = g_list_next (walk)) {
+    GstRTSPExtension *elem = (GstRTSPExtension *) walk->data;
+
+    res = gst_rtsp_extension_receive_request (elem, req);
+    if (res != GST_RTSP_ENOTIMPL)
+      break;
+  }
+  return res;
+}
diff --git a/gst/rtsp/gstrtspext.h b/gst/rtsp/gstrtspext.h
new file mode 100644
index 0000000..2e87796
--- /dev/null
+++ b/gst/rtsp/gstrtspext.h
@@ -0,0 +1,83 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_RTSP_EXT_H__
+#define __GST_RTSP_EXT_H__
+
+#include <gst/gst.h>
+#include <gst/rtsp/gstrtspextension.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTSPExtensionList GstRTSPExtensionList;
+
+struct _GstRTSPExtensionList
+{
+  GList *extensions;
+};
+
+void                    gst_rtsp_ext_list_init    (void);
+
+GstRTSPExtensionList *  gst_rtsp_ext_list_get     (void);
+void                    gst_rtsp_ext_list_free    (GstRTSPExtensionList *ext);
+
+gboolean      gst_rtsp_ext_list_detect_server     (GstRTSPExtensionList *ext, GstRTSPMessage *resp);
+  
+GstRTSPResult gst_rtsp_ext_list_before_send       (GstRTSPExtensionList *ext, GstRTSPMessage *req);
+GstRTSPResult gst_rtsp_ext_list_after_send        (GstRTSPExtensionList *ext, GstRTSPMessage *req,
+                                                   GstRTSPMessage *resp);
+GstRTSPResult gst_rtsp_ext_list_parse_sdp         (GstRTSPExtensionList *ext, GstSDPMessage *sdp,
+                                                   GstStructure *s);
+GstRTSPResult gst_rtsp_ext_list_setup_media       (GstRTSPExtensionList *ext, GstSDPMedia *media);
+gboolean      gst_rtsp_ext_list_configure_stream  (GstRTSPExtensionList *ext, GstCaps *caps);
+GstRTSPResult gst_rtsp_ext_list_get_transports    (GstRTSPExtensionList *ext, GstRTSPLowerTrans protocols,
+                                                   gchar **transport);
+GstRTSPResult gst_rtsp_ext_list_stream_select     (GstRTSPExtensionList *ext, GstRTSPUrl *url);
+
+void          gst_rtsp_ext_list_connect           (GstRTSPExtensionList *ext,
+			                           const gchar *detailed_signal, GCallback c_handler,
+                                                   gpointer data);
+GstRTSPResult gst_rtsp_ext_list_receive_request   (GstRTSPExtensionList *ext, GstRTSPMessage *req);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_EXT_H__ */
diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c
new file mode 100644
index 0000000..d636073
--- /dev/null
+++ b/gst/rtsp/gstrtspsrc.c
@@ -0,0 +1,8755 @@
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim at fluendo dot com>
+ *               <2006> Lutz Mueller <lutz at topfrose dot de>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/**
+ * SECTION:element-rtspsrc
+ *
+ * Makes a connection to an RTSP server and read the data.
+ * rtspsrc strictly follows RFC 2326 and therefore does not (yet) support
+ * RealMedia/Quicktime/Microsoft extensions.
+ *
+ * RTSP supports transport over TCP or UDP in unicast or multicast mode. By
+ * default rtspsrc will negotiate a connection in the following order:
+ * UDP unicast/UDP multicast/TCP. The order cannot be changed but the allowed
+ * protocols can be controlled with the #GstRTSPSrc:protocols property.
+ *
+ * rtspsrc currently understands SDP as the format of the session description.
+ * For each stream listed in the SDP a new rtp_stream\%d pad will be created
+ * with caps derived from the SDP media description. This is a caps of mime type
+ * "application/x-rtp" that can be connected to any available RTP depayloader
+ * element.
+ *
+ * rtspsrc will internally instantiate an RTP session manager element
+ * that will handle the RTCP messages to and from the server, jitter removal,
+ * packet reordering along with providing a clock for the pipeline.
+ * This feature is implemented using the gstrtpbin element.
+ *
+ * rtspsrc acts like a live source and will therefore only generate data in the
+ * PLAYING state.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 rtspsrc location=rtsp://some.server/url ! fakesink
+ * ]| Establish a connection to an RTSP server and send the raw RTP packets to a
+ * fakesink.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <gst/net/gstnet.h>
+#include <gst/sdp/gstsdpmessage.h>
+#include <gst/sdp/gstmikey.h>
+#include <gst/rtp/rtp.h>
+
+#include "gst/gst-i18n-plugin.h"
+
+#include "gstrtspsrc.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtspsrc_debug);
+#define GST_CAT_DEFAULT (rtspsrc_debug)
+
+static GstStaticPadTemplate rtptemplate = GST_STATIC_PAD_TEMPLATE ("stream_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS ("application/x-rtp; application/x-rdt"));
+
+/* templates used internally */
+static GstStaticPadTemplate anysrctemplate =
+GST_STATIC_PAD_TEMPLATE ("internalsrc_%u",
+    GST_PAD_SRC,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate anysinktemplate =
+GST_STATIC_PAD_TEMPLATE ("internalsink_%u",
+    GST_PAD_SINK,
+    GST_PAD_SOMETIMES,
+    GST_STATIC_CAPS_ANY);
+
+enum
+{
+  SIGNAL_HANDLE_REQUEST,
+  SIGNAL_ON_SDP,
+  SIGNAL_SELECT_STREAM,
+  SIGNAL_NEW_MANAGER,
+  SIGNAL_REQUEST_RTCP_KEY,
+  SIGNAL_ACCEPT_CERTIFICATE,
+  SIGNAL_BEFORE_SEND,
+  LAST_SIGNAL
+};
+
+enum _GstRtspSrcRtcpSyncMode
+{
+  RTCP_SYNC_ALWAYS,
+  RTCP_SYNC_INITIAL,
+  RTCP_SYNC_RTP
+};
+
+enum _GstRtspSrcBufferMode
+{
+  BUFFER_MODE_NONE,
+  BUFFER_MODE_SLAVE,
+  BUFFER_MODE_BUFFER,
+  BUFFER_MODE_AUTO,
+  BUFFER_MODE_SYNCED
+};
+
+#define GST_TYPE_RTSP_SRC_BUFFER_MODE (gst_rtsp_src_buffer_mode_get_type())
+static GType
+gst_rtsp_src_buffer_mode_get_type (void)
+{
+  static GType buffer_mode_type = 0;
+  static const GEnumValue buffer_modes[] = {
+    {BUFFER_MODE_NONE, "Only use RTP timestamps", "none"},
+    {BUFFER_MODE_SLAVE, "Slave receiver to sender clock", "slave"},
+    {BUFFER_MODE_BUFFER, "Do low/high watermark buffering", "buffer"},
+    {BUFFER_MODE_AUTO, "Choose mode depending on stream live", "auto"},
+    {BUFFER_MODE_SYNCED, "Synchronized sender and receiver clocks", "synced"},
+    {0, NULL, NULL},
+  };
+
+  if (!buffer_mode_type) {
+    buffer_mode_type =
+        g_enum_register_static ("GstRTSPSrcBufferMode", buffer_modes);
+  }
+  return buffer_mode_type;
+}
+
+enum _GstRtspSrcNtpTimeSource
+{
+  NTP_TIME_SOURCE_NTP,
+  NTP_TIME_SOURCE_UNIX,
+  NTP_TIME_SOURCE_RUNNING_TIME,
+  NTP_TIME_SOURCE_CLOCK_TIME
+};
+
+#define DEBUG_RTSP(__self,msg) gst_rtspsrc_print_rtsp_message (__self, msg)
+#define DEBUG_SDP(__self,msg) gst_rtspsrc_print_sdp_message (__self, msg)
+
+#define GST_TYPE_RTSP_SRC_NTP_TIME_SOURCE (gst_rtsp_src_ntp_time_source_get_type())
+static GType
+gst_rtsp_src_ntp_time_source_get_type (void)
+{
+  static GType ntp_time_source_type = 0;
+  static const GEnumValue ntp_time_source_values[] = {
+    {NTP_TIME_SOURCE_NTP, "NTP time based on realtime clock", "ntp"},
+    {NTP_TIME_SOURCE_UNIX, "UNIX time based on realtime clock", "unix"},
+    {NTP_TIME_SOURCE_RUNNING_TIME,
+          "Running time based on pipeline clock",
+        "running-time"},
+    {NTP_TIME_SOURCE_CLOCK_TIME, "Pipeline clock time", "clock-time"},
+    {0, NULL, NULL},
+  };
+
+  if (!ntp_time_source_type) {
+    ntp_time_source_type =
+        g_enum_register_static ("GstRTSPSrcNtpTimeSource",
+        ntp_time_source_values);
+  }
+  return ntp_time_source_type;
+}
+
+#define DEFAULT_LOCATION         NULL
+#define DEFAULT_PROTOCOLS        GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP
+#define DEFAULT_DEBUG            FALSE
+#define DEFAULT_RETRY            20
+#define DEFAULT_TIMEOUT          5000000
+#define DEFAULT_UDP_BUFFER_SIZE  0x80000
+#define DEFAULT_TCP_TIMEOUT      20000000
+#define DEFAULT_LATENCY_MS       2000
+#define DEFAULT_DROP_ON_LATENCY  FALSE
+#define DEFAULT_CONNECTION_SPEED 0
+#define DEFAULT_NAT_METHOD       GST_RTSP_NAT_DUMMY
+#define DEFAULT_DO_RTCP          TRUE
+#define DEFAULT_DO_RTSP_KEEP_ALIVE       TRUE
+#define DEFAULT_PROXY            NULL
+#define DEFAULT_RTP_BLOCKSIZE    0
+#define DEFAULT_USER_ID          NULL
+#define DEFAULT_USER_PW          NULL
+#define DEFAULT_BUFFER_MODE      BUFFER_MODE_AUTO
+#define DEFAULT_PORT_RANGE       NULL
+#define DEFAULT_SHORT_HEADER     FALSE
+#define DEFAULT_PROBATION        2
+#define DEFAULT_UDP_RECONNECT    TRUE
+#define DEFAULT_MULTICAST_IFACE  NULL
+#define DEFAULT_NTP_SYNC         FALSE
+#define DEFAULT_USE_PIPELINE_CLOCK       FALSE
+#define DEFAULT_TLS_VALIDATION_FLAGS     G_TLS_CERTIFICATE_VALIDATE_ALL
+#define DEFAULT_TLS_DATABASE     NULL
+#define DEFAULT_TLS_INTERACTION     NULL
+#define DEFAULT_DO_RETRANSMISSION        TRUE
+#define DEFAULT_NTP_TIME_SOURCE  NTP_TIME_SOURCE_NTP
+#define DEFAULT_USER_AGENT       "GStreamer/" PACKAGE_VERSION
+#define DEFAULT_MAX_RTCP_RTP_TIME_DIFF 1000
+#define DEFAULT_RFC7273_SYNC         FALSE
+#define DEFAULT_MAX_TS_OFFSET_ADJUSTMENT   G_GUINT64_CONSTANT(0)
+#define DEFAULT_MAX_TS_OFFSET   G_GINT64_CONSTANT(3000000000)
+#define DEFAULT_VERSION         GST_RTSP_VERSION_1_0
+
+enum
+{
+  PROP_0,
+  PROP_LOCATION,
+  PROP_PROTOCOLS,
+  PROP_DEBUG,
+  PROP_RETRY,
+  PROP_TIMEOUT,
+  PROP_TCP_TIMEOUT,
+  PROP_LATENCY,
+  PROP_DROP_ON_LATENCY,
+  PROP_CONNECTION_SPEED,
+  PROP_NAT_METHOD,
+  PROP_DO_RTCP,
+  PROP_DO_RTSP_KEEP_ALIVE,
+  PROP_PROXY,
+  PROP_PROXY_ID,
+  PROP_PROXY_PW,
+  PROP_RTP_BLOCKSIZE,
+  PROP_USER_ID,
+  PROP_USER_PW,
+  PROP_BUFFER_MODE,
+  PROP_PORT_RANGE,
+  PROP_UDP_BUFFER_SIZE,
+  PROP_SHORT_HEADER,
+  PROP_PROBATION,
+  PROP_UDP_RECONNECT,
+  PROP_MULTICAST_IFACE,
+  PROP_NTP_SYNC,
+  PROP_USE_PIPELINE_CLOCK,
+  PROP_SDES,
+  PROP_TLS_VALIDATION_FLAGS,
+  PROP_TLS_DATABASE,
+  PROP_TLS_INTERACTION,
+  PROP_DO_RETRANSMISSION,
+  PROP_NTP_TIME_SOURCE,
+  PROP_USER_AGENT,
+  PROP_MAX_RTCP_RTP_TIME_DIFF,
+  PROP_RFC7273_SYNC,
+  PROP_MAX_TS_OFFSET_ADJUSTMENT,
+  PROP_MAX_TS_OFFSET,
+  PROP_DEFAULT_VERSION,
+};
+
+#define GST_TYPE_RTSP_NAT_METHOD (gst_rtsp_nat_method_get_type())
+static GType
+gst_rtsp_nat_method_get_type (void)
+{
+  static GType rtsp_nat_method_type = 0;
+  static const GEnumValue rtsp_nat_method[] = {
+    {GST_RTSP_NAT_NONE, "None", "none"},
+    {GST_RTSP_NAT_DUMMY, "Send Dummy packets", "dummy"},
+    {0, NULL, NULL},
+  };
+
+  if (!rtsp_nat_method_type) {
+    rtsp_nat_method_type =
+        g_enum_register_static ("GstRTSPNatMethod", rtsp_nat_method);
+  }
+  return rtsp_nat_method_type;
+}
+
+#define RTSP_SRC_RESPONSE_ERROR(src, response_msg, err_cat, err_code, error_message) \
+  do { \
+    GST_ELEMENT_ERROR_WITH_DETAILS((src), err_cat, err_code, ("%s", error_message), \
+        ("%s (%d)", (response_msg)->type_data.response.reason, (response_msg)->type_data.response.code), \
+        ("rtsp-status-code", G_TYPE_UINT, (response_msg)->type_data.response.code, \
+         "rtsp-status-reason", G_TYPE_STRING, GST_STR_NULL((response_msg)->type_data.response.reason), NULL)); \
+  } while (0)
+
+static void gst_rtspsrc_finalize (GObject * object);
+
+static void gst_rtspsrc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtspsrc_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstClock *gst_rtspsrc_provide_clock (GstElement * element);
+
+static void gst_rtspsrc_uri_handler_init (gpointer g_iface,
+    gpointer iface_data);
+
+static gboolean gst_rtspsrc_set_proxy (GstRTSPSrc * rtsp, const gchar * proxy);
+static void gst_rtspsrc_set_tcp_timeout (GstRTSPSrc * rtspsrc, guint64 timeout);
+
+static GstStateChangeReturn gst_rtspsrc_change_state (GstElement * element,
+    GstStateChange transition);
+static gboolean gst_rtspsrc_send_event (GstElement * element, GstEvent * event);
+static void gst_rtspsrc_handle_message (GstBin * bin, GstMessage * message);
+
+static gboolean gst_rtspsrc_setup_auth (GstRTSPSrc * src,
+    GstRTSPMessage * response);
+
+static gboolean gst_rtspsrc_loop_send_cmd (GstRTSPSrc * src, gint cmd,
+    gint mask);
+static GstRTSPResult gst_rtspsrc_send_cb (GstRTSPExtension * ext,
+    GstRTSPMessage * request, GstRTSPMessage * response, GstRTSPSrc * src);
+
+static GstRTSPResult gst_rtspsrc_open (GstRTSPSrc * src, gboolean async);
+static GstRTSPResult gst_rtspsrc_play (GstRTSPSrc * src, GstSegment * segment,
+    gboolean async, const gchar * seek_style);
+static GstRTSPResult gst_rtspsrc_pause (GstRTSPSrc * src, gboolean async);
+static GstRTSPResult gst_rtspsrc_close (GstRTSPSrc * src, gboolean async,
+    gboolean only_close);
+
+static gboolean gst_rtspsrc_uri_set_uri (GstURIHandler * handler,
+    const gchar * uri, GError ** error);
+static gchar *gst_rtspsrc_uri_get_uri (GstURIHandler * handler);
+
+static gboolean gst_rtspsrc_activate_streams (GstRTSPSrc * src);
+static gboolean gst_rtspsrc_loop (GstRTSPSrc * src);
+static gboolean gst_rtspsrc_stream_push_event (GstRTSPSrc * src,
+    GstRTSPStream * stream, GstEvent * event);
+static gboolean gst_rtspsrc_push_event (GstRTSPSrc * src, GstEvent * event);
+static void gst_rtspsrc_connection_flush (GstRTSPSrc * src, gboolean flush);
+static GstRTSPResult gst_rtsp_conninfo_close (GstRTSPSrc * src,
+    GstRTSPConnInfo * info, gboolean free);
+static void
+gst_rtspsrc_print_rtsp_message (GstRTSPSrc * src, const GstRTSPMessage * msg);
+static void
+gst_rtspsrc_print_sdp_message (GstRTSPSrc * src, const GstSDPMessage * msg);
+
+typedef struct
+{
+  guint8 pt;
+  GstCaps *caps;
+} PtMapItem;
+
+/* commands we send to out loop to notify it of events */
+#define CMD_OPEN       (1 << 0)
+#define CMD_PLAY       (1 << 1)
+#define CMD_PAUSE      (1 << 2)
+#define CMD_CLOSE      (1 << 3)
+#define CMD_WAIT       (1 << 4)
+#define CMD_RECONNECT  (1 << 5)
+#define CMD_LOOP       (1 << 6)
+
+/* mask for all commands */
+#define CMD_ALL         ((CMD_LOOP << 1) - 1)
+
+#define GST_ELEMENT_PROGRESS(el, type, code, text)      \
+G_STMT_START {                                          \
+  gchar *__txt = _gst_element_error_printf text;        \
+  gst_element_post_message (GST_ELEMENT_CAST (el),      \
+      gst_message_new_progress (GST_OBJECT_CAST (el),   \
+          GST_PROGRESS_TYPE_ ##type, code, __txt));     \
+  g_free (__txt);                                       \
+} G_STMT_END
+
+static guint gst_rtspsrc_signals[LAST_SIGNAL] = { 0 };
+
+#define gst_rtspsrc_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstRTSPSrc, gst_rtspsrc, GST_TYPE_BIN,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_rtspsrc_uri_handler_init));
+
+#ifndef GST_DISABLE_GST_DEBUG
+static inline const char *
+cmd_to_string (guint cmd)
+{
+  switch (cmd) {
+    case CMD_OPEN:
+      return "OPEN";
+    case CMD_PLAY:
+      return "PLAY";
+    case CMD_PAUSE:
+      return "PAUSE";
+    case CMD_CLOSE:
+      return "CLOSE";
+    case CMD_WAIT:
+      return "WAIT";
+    case CMD_RECONNECT:
+      return "RECONNECT";
+    case CMD_LOOP:
+      return "LOOP";
+  }
+
+  return "unknown";
+}
+#endif
+
+static gboolean
+default_select_stream (GstRTSPSrc * src, guint id, GstCaps * caps)
+{
+  GST_DEBUG_OBJECT (src, "default handler");
+  return TRUE;
+}
+
+static gboolean
+select_stream_accum (GSignalInvocationHint * ihint,
+    GValue * return_accu, const GValue * handler_return, gpointer data)
+{
+  gboolean myboolean;
+
+  myboolean = g_value_get_boolean (handler_return);
+  GST_DEBUG ("accum %d", myboolean);
+  g_value_set_boolean (return_accu, myboolean);
+
+  /* stop emission if FALSE */
+  return myboolean;
+}
+
+static gboolean
+default_before_send (GstRTSPSrc * src, GstRTSPMessage * msg)
+{
+  GST_DEBUG_OBJECT (src, "default handler");
+  return TRUE;
+}
+
+static gboolean
+before_send_accum (GSignalInvocationHint * ihint,
+    GValue * return_accu, const GValue * handler_return, gpointer data)
+{
+  gboolean myboolean;
+
+  myboolean = g_value_get_boolean (handler_return);
+  g_value_set_boolean (return_accu, myboolean);
+
+  /* prevent send if FALSE */
+  return myboolean;
+}
+
+static void
+gst_rtspsrc_class_init (GstRTSPSrcClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBinClass *gstbin_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbin_class = (GstBinClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (rtspsrc_debug, "rtspsrc", 0, "RTSP src");
+
+  gobject_class->set_property = gst_rtspsrc_set_property;
+  gobject_class->get_property = gst_rtspsrc_get_property;
+
+  gobject_class->finalize = gst_rtspsrc_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_LOCATION,
+      g_param_spec_string ("location", "RTSP Location",
+          "Location of the RTSP url to read",
+          DEFAULT_LOCATION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
+      g_param_spec_flags ("protocols", "Protocols",
+          "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS,
+          DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DEBUG,
+      g_param_spec_boolean ("debug", "Debug",
+          "Dump request and response messages to stdout"
+          "(DEPRECATED: Printed all RTSP message to gstreamer log as 'log' level)",
+          DEFAULT_DEBUG,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
+
+  g_object_class_install_property (gobject_class, PROP_RETRY,
+      g_param_spec_uint ("retry", "Retry",
+          "Max number of retries when allocating RTP ports.",
+          0, G_MAXUINT16, DEFAULT_RETRY,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_TIMEOUT,
+      g_param_spec_uint64 ("timeout", "Timeout",
+          "Retry TCP transport after UDP timeout microseconds (0 = disabled)",
+          0, G_MAXUINT64, DEFAULT_TIMEOUT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_TCP_TIMEOUT,
+      g_param_spec_uint64 ("tcp-timeout", "TCP Timeout",
+          "Fail after timeout microseconds on TCP connections (0 = disabled)",
+          0, G_MAXUINT64, DEFAULT_TCP_TIMEOUT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_LATENCY,
+      g_param_spec_uint ("latency", "Buffer latency in ms",
+          "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DROP_ON_LATENCY,
+      g_param_spec_boolean ("drop-on-latency",
+          "Drop buffers when maximum latency is reached",
+          "Tells the jitterbuffer to never exceed the given latency in size",
+          DEFAULT_DROP_ON_LATENCY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CONNECTION_SPEED,
+      g_param_spec_uint64 ("connection-speed", "Connection Speed",
+          "Network connection speed in kbps (0 = unknown)",
+          0, G_MAXUINT64 / 1000, DEFAULT_CONNECTION_SPEED,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NAT_METHOD,
+      g_param_spec_enum ("nat-method", "NAT Method",
+          "Method to use for traversing firewalls and NAT",
+          GST_TYPE_RTSP_NAT_METHOD, DEFAULT_NAT_METHOD,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc:do-rtcp:
+   *
+   * Enable RTCP support. Some old server don't like RTCP and then this property
+   * needs to be set to FALSE.
+   */
+  g_object_class_install_property (gobject_class, PROP_DO_RTCP,
+      g_param_spec_boolean ("do-rtcp", "Do RTCP",
+          "Send RTCP packets, disable for old incompatible server.",
+          DEFAULT_DO_RTCP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc:do-rtsp-keep-alive:
+   *
+   * Enable RTSP keep alive support. Some old server don't like RTSP
+   * keep alive and then this property needs to be set to FALSE.
+   */
+  g_object_class_install_property (gobject_class, PROP_DO_RTSP_KEEP_ALIVE,
+      g_param_spec_boolean ("do-rtsp-keep-alive", "Do RTSP Keep Alive",
+          "Send RTSP keep alive packets, disable for old incompatible server.",
+          DEFAULT_DO_RTSP_KEEP_ALIVE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc:proxy:
+   *
+   * Set the proxy parameters. This has to be a string of the format
+   * [http://][user:passwd@]host[:port].
+   */
+  g_object_class_install_property (gobject_class, PROP_PROXY,
+      g_param_spec_string ("proxy", "Proxy",
+          "Proxy settings for HTTP tunneling. Format: [http://][user:passwd@]host[:port]",
+          DEFAULT_PROXY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRTSPSrc:proxy-id:
+   *
+   * Sets the proxy URI user id for authentication. If the URI set via the
+   * "proxy" property contains a user-id already, that will take precedence.
+   *
+   * Since: 1.2
+   */
+  g_object_class_install_property (gobject_class, PROP_PROXY_ID,
+      g_param_spec_string ("proxy-id", "proxy-id",
+          "HTTP proxy URI user id for authentication", "",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstRTSPSrc:proxy-pw:
+   *
+   * Sets the proxy URI password for authentication. If the URI set via the
+   * "proxy" property contains a password already, that will take precedence.
+   *
+   * Since: 1.2
+   */
+  g_object_class_install_property (gobject_class, PROP_PROXY_PW,
+      g_param_spec_string ("proxy-pw", "proxy-pw",
+          "HTTP proxy URI user password for authentication", "",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc:rtp-blocksize:
+   *
+   * RTP package size to suggest to server.
+   */
+  g_object_class_install_property (gobject_class, PROP_RTP_BLOCKSIZE,
+      g_param_spec_uint ("rtp-blocksize", "RTP Blocksize",
+          "RTP package size to suggest to server (0 = disabled)",
+          0, 65536, DEFAULT_RTP_BLOCKSIZE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_USER_ID,
+      g_param_spec_string ("user-id", "user-id",
+          "RTSP location URI user id for authentication", DEFAULT_USER_ID,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_USER_PW,
+      g_param_spec_string ("user-pw", "user-pw",
+          "RTSP location URI user password for authentication", DEFAULT_USER_PW,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc:buffer-mode:
+   *
+   * Control the buffering and timestamping mode used by the jitterbuffer.
+   */
+  g_object_class_install_property (gobject_class, PROP_BUFFER_MODE,
+      g_param_spec_enum ("buffer-mode", "Buffer Mode",
+          "Control the buffering algorithm in use",
+          GST_TYPE_RTSP_SRC_BUFFER_MODE, DEFAULT_BUFFER_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc:port-range:
+   *
+   * Configure the client port numbers that can be used to recieve RTP and
+   * RTCP.
+   */
+  g_object_class_install_property (gobject_class, PROP_PORT_RANGE,
+      g_param_spec_string ("port-range", "Port range",
+          "Client port range that can be used to receive RTP and RTCP data, "
+          "eg. 3000-3005 (NULL = no restrictions)", DEFAULT_PORT_RANGE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc:udp-buffer-size:
+   *
+   * Size of the kernel UDP receive buffer in bytes.
+   */
+  g_object_class_install_property (gobject_class, PROP_UDP_BUFFER_SIZE,
+      g_param_spec_int ("udp-buffer-size", "UDP Buffer Size",
+          "Size of the kernel UDP receive buffer in bytes, 0=default",
+          0, G_MAXINT, DEFAULT_UDP_BUFFER_SIZE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc:short-header:
+   *
+   * Only send the basic RTSP headers for broken encoders.
+   */
+  g_object_class_install_property (gobject_class, PROP_SHORT_HEADER,
+      g_param_spec_boolean ("short-header", "Short Header",
+          "Only send the basic RTSP headers for broken encoders",
+          DEFAULT_SHORT_HEADER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_PROBATION,
+      g_param_spec_uint ("probation", "Number of probations",
+          "Consecutive packet sequence numbers to accept the source",
+          0, G_MAXUINT, DEFAULT_PROBATION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_UDP_RECONNECT,
+      g_param_spec_boolean ("udp-reconnect", "Reconnect to the server",
+          "Reconnect to the server if RTSP connection is closed when doing UDP",
+          DEFAULT_UDP_RECONNECT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MULTICAST_IFACE,
+      g_param_spec_string ("multicast-iface", "Multicast Interface",
+          "The network interface on which to join the multicast group",
+          DEFAULT_MULTICAST_IFACE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NTP_SYNC,
+      g_param_spec_boolean ("ntp-sync", "Sync on NTP clock",
+          "Synchronize received streams to the NTP clock", DEFAULT_NTP_SYNC,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_USE_PIPELINE_CLOCK,
+      g_param_spec_boolean ("use-pipeline-clock", "Use pipeline clock",
+          "Use the pipeline running-time to set the NTP time in the RTCP SR messages"
+          "(DEPRECATED: Use ntp-time-source property)",
+          DEFAULT_USE_PIPELINE_CLOCK,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
+
+  g_object_class_install_property (gobject_class, PROP_SDES,
+      g_param_spec_boxed ("sdes", "SDES",
+          "The SDES items of this session",
+          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc::tls-validation-flags:
+   *
+   * TLS certificate validation flags used to validate server
+   * certificate.
+   *
+   * Since: 1.2.1
+   */
+  g_object_class_install_property (gobject_class, PROP_TLS_VALIDATION_FLAGS,
+      g_param_spec_flags ("tls-validation-flags", "TLS validation flags",
+          "TLS certificate validation flags used to validate the server certificate",
+          G_TYPE_TLS_CERTIFICATE_FLAGS, DEFAULT_TLS_VALIDATION_FLAGS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc::tls-database:
+   *
+   * TLS database with anchor certificate authorities used to validate
+   * the server certificate.
+   *
+   * Since: 1.4
+   */
+  g_object_class_install_property (gobject_class, PROP_TLS_DATABASE,
+      g_param_spec_object ("tls-database", "TLS database",
+          "TLS database with anchor certificate authorities used to validate the server certificate",
+          G_TYPE_TLS_DATABASE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc::tls-interaction:
+   *
+   * A #GTlsInteraction object to be used when the connection or certificate
+   * database need to interact with the user. This will be used to prompt the
+   * user for passwords where necessary.
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_TLS_INTERACTION,
+      g_param_spec_object ("tls-interaction", "TLS interaction",
+          "A GTlsInteraction object to promt the user for password or certificate",
+          G_TYPE_TLS_INTERACTION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc::do-retransmission:
+   *
+   * Attempt to ask the server to retransmit lost packets according to RFC4588.
+   *
+   * Note: currently only works with SSRC-multiplexed retransmission streams
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_DO_RETRANSMISSION,
+      g_param_spec_boolean ("do-retransmission", "Retransmission",
+          "Ask the server to retransmit lost packets",
+          DEFAULT_DO_RETRANSMISSION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc::ntp-time-source:
+   *
+   * allows to select the time source that should be used
+   * for the NTP time in RTCP packets
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_NTP_TIME_SOURCE,
+      g_param_spec_enum ("ntp-time-source", "NTP Time Source",
+          "NTP time source for RTCP packets",
+          GST_TYPE_RTSP_SRC_NTP_TIME_SOURCE, DEFAULT_NTP_TIME_SOURCE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc::user-agent:
+   *
+   * The string to set in the User-Agent header.
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_USER_AGENT,
+      g_param_spec_string ("user-agent", "User Agent",
+          "The User-Agent string to send to the server",
+          DEFAULT_USER_AGENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MAX_RTCP_RTP_TIME_DIFF,
+      g_param_spec_int ("max-rtcp-rtp-time-diff", "Max RTCP RTP Time Diff",
+          "Maximum amount of time in ms that the RTP time in RTCP SRs "
+          "is allowed to be ahead (-1 disabled)", -1, G_MAXINT,
+          DEFAULT_MAX_RTCP_RTP_TIME_DIFF,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RFC7273_SYNC,
+      g_param_spec_boolean ("rfc7273-sync", "Sync on RFC7273 clock",
+          "Synchronize received streams to the RFC7273 clock "
+          "(requires clock and offset to be provided)", DEFAULT_RFC7273_SYNC,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc:default-rtsp-version:
+   *
+   * The preferred RTSP version to use while negotiating the version with the server.
+   *
+   * Since: 1.14
+   */
+  g_object_class_install_property (gobject_class, PROP_DEFAULT_VERSION,
+      g_param_spec_enum ("default-rtsp-version",
+          "The RTSP version to try first",
+          "The RTSP version that should be tried first when negotiating version.",
+          GST_TYPE_RTSP_VERSION, DEFAULT_VERSION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc:max-ts-offset-adjustment:
+   *
+   * Syncing time stamps to NTP time adds a time offset. This parameter
+   * specifies the maximum number of nanoseconds per frame that this time offset
+   * may be adjusted with. This is used to avoid sudden large changes to time
+   * stamps.
+   */
+  g_object_class_install_property (gobject_class, PROP_MAX_TS_OFFSET_ADJUSTMENT,
+      g_param_spec_uint64 ("max-ts-offset-adjustment",
+          "Max Timestamp Offset Adjustment",
+          "The maximum number of nanoseconds per frame that time stamp offsets "
+          "may be adjusted (0 = no limit).", 0, G_MAXUINT64,
+          DEFAULT_MAX_TS_OFFSET_ADJUSTMENT, G_PARAM_READWRITE |
+          G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRtpBin:max-ts-offset:
+   *
+   * Used to set an upper limit of how large a time offset may be. This
+   * is used to protect against unrealistic values as a result of either
+   * client,server or clock issues.
+   */
+  g_object_class_install_property (gobject_class, PROP_MAX_TS_OFFSET,
+      g_param_spec_int64 ("max-ts-offset", "Max TS Offset",
+          "The maximum absolute value of the time offset in (nanoseconds). "
+          "Note, if the ntp-sync parameter is set the default value is "
+          "changed to 0 (no limit)", 0, G_MAXINT64, DEFAULT_MAX_TS_OFFSET,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstRTSPSrc::handle-request:
+   * @rtspsrc: a #GstRTSPSrc
+   * @request: a #GstRTSPMessage
+   * @response: a #GstRTSPMessage
+   *
+   * Handle a server request in @request and prepare @response.
+   *
+   * This signal is called from the streaming thread, you should therefore not
+   * do any state changes on @rtspsrc because this might deadlock. If you want
+   * to modify the state as a result of this signal, post a
+   * #GST_MESSAGE_REQUEST_STATE message on the bus or signal the main thread
+   * in some other way.
+   *
+   * Since: 1.2
+   */
+  gst_rtspsrc_signals[SIGNAL_HANDLE_REQUEST] =
+      g_signal_new ("handle-request", G_TYPE_FROM_CLASS (klass), 0,
+      0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2,
+      G_TYPE_POINTER, G_TYPE_POINTER);
+
+  /**
+   * GstRTSPSrc::on-sdp:
+   * @rtspsrc: a #GstRTSPSrc
+   * @sdp: a #GstSDPMessage
+   *
+   * Emited when the client has retrieved the SDP and before it configures the
+   * streams in the SDP. @sdp can be inspected and modified.
+   *
+   * This signal is called from the streaming thread, you should therefore not
+   * do any state changes on @rtspsrc because this might deadlock. If you want
+   * to modify the state as a result of this signal, post a
+   * #GST_MESSAGE_REQUEST_STATE message on the bus or signal the main thread
+   * in some other way.
+   *
+   * Since: 1.2
+   */
+  gst_rtspsrc_signals[SIGNAL_ON_SDP] =
+      g_signal_new ("on-sdp", G_TYPE_FROM_CLASS (klass), 0,
+      0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
+      GST_TYPE_SDP_MESSAGE | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+  /**
+   * GstRTSPSrc::select-stream:
+   * @rtspsrc: a #GstRTSPSrc
+   * @num: the stream number
+   * @caps: the stream caps
+   *
+   * Emited before the client decides to configure the stream @num with
+   * @caps.
+   *
+   * Returns: %TRUE when the stream should be selected, %FALSE when the stream
+   * is to be ignored.
+   *
+   * Since: 1.2
+   */
+  gst_rtspsrc_signals[SIGNAL_SELECT_STREAM] =
+      g_signal_new_class_handler ("select-stream", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_CLEANUP,
+      (GCallback) default_select_stream, select_stream_accum, NULL,
+      g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 2, G_TYPE_UINT,
+      GST_TYPE_CAPS);
+  /**
+   * GstRTSPSrc::new-manager:
+   * @rtspsrc: a #GstRTSPSrc
+   * @manager: a #GstElement
+   *
+   * Emited after a new manager (like rtpbin) was created and the default
+   * properties were configured.
+   *
+   * Since: 1.4
+   */
+  gst_rtspsrc_signals[SIGNAL_NEW_MANAGER] =
+      g_signal_new_class_handler ("new-manager", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_CLEANUP, 0, NULL, NULL,
+      g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
+
+  /**
+   * GstRTSPSrc::request-rtcp-key:
+   * @rtspsrc: a #GstRTSPSrc
+   * @num: the stream number
+   *
+   * Signal emited to get the crypto parameters relevant to the RTCP
+   * stream. User should provide the key and the RTCP encryption ciphers
+   * and authentication, and return them wrapped in a GstCaps.
+   *
+   * Since: 1.4
+   */
+  gst_rtspsrc_signals[SIGNAL_REQUEST_RTCP_KEY] =
+      g_signal_new ("request-rtcp-key", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, GST_TYPE_CAPS, 1, G_TYPE_UINT);
+
+  /**
+   * GstRTSPSrc::accept-certificate:
+   * @rtspsrc: a #GstRTSPSrc
+   * @peer_cert: the peer's #GTlsCertificate
+   * @errors: the problems with @peer_cert
+   * @user_data: user data set when the signal handler was connected.
+   *
+   * This will directly map to #GTlsConnection 's "accept-certificate"
+   * signal and be performed after the default checks of #GstRTSPConnection
+   * (checking against the #GTlsDatabase with the given #GTlsCertificateFlags)
+   * have failed. If no #GTlsDatabase is set on this connection, only this
+   * signal will be emitted.
+   *
+   * Since: 1.14
+   */
+  gst_rtspsrc_signals[SIGNAL_ACCEPT_CERTIFICATE] =
+      g_signal_new ("accept-certificate", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, g_signal_accumulator_true_handled, NULL, NULL,
+      G_TYPE_BOOLEAN, 3, G_TYPE_TLS_CONNECTION, G_TYPE_TLS_CERTIFICATE,
+      G_TYPE_TLS_CERTIFICATE_FLAGS);
+
+  /*
+   * GstRTSPSrc::before-send
+   * @rtspsrc: a #GstRTSPSrc
+   * @num: the stream number
+   *
+   * Emitted before each RTSP request is sent, in order to allow
+   * the application to modify send parameters or to skip the message entirely.
+   * This can be used, for example, to work with ONVIF Profile G servers,
+   * which need a different/additional range, rate-control, and intra/x
+   * parameters.
+   *
+   * Returns: %TRUE when the command should be sent, %FALSE when the
+   * command should be dropped.
+   *
+   * Since: 1.14
+   */
+  gst_rtspsrc_signals[SIGNAL_BEFORE_SEND] =
+      g_signal_new_class_handler ("before-send", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_CLEANUP,
+      (GCallback) default_before_send, before_send_accum, NULL,
+      g_cclosure_marshal_generic, G_TYPE_BOOLEAN,
+      1, GST_TYPE_RTSP_MESSAGE | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+  gstelement_class->send_event = gst_rtspsrc_send_event;
+  gstelement_class->provide_clock = gst_rtspsrc_provide_clock;
+  gstelement_class->change_state = gst_rtspsrc_change_state;
+
+  gst_element_class_add_static_pad_template (gstelement_class, &rtptemplate);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTSP packet receiver", "Source/Network",
+      "Receive data over the network via RTSP (RFC 2326)",
+      "Wim Taymans <wim@fluendo.com>, "
+      "Thijs Vermeir <thijs.vermeir@barco.com>, "
+      "Lutz Mueller <lutz@topfrose.de>");
+
+  gstbin_class->handle_message = gst_rtspsrc_handle_message;
+
+  gst_rtsp_ext_list_init ();
+}
+
+static void
+gst_rtspsrc_init (GstRTSPSrc * src)
+{
+  src->conninfo.location = g_strdup (DEFAULT_LOCATION);
+  src->protocols = DEFAULT_PROTOCOLS;
+  src->debug = DEFAULT_DEBUG;
+  src->retry = DEFAULT_RETRY;
+  src->udp_timeout = DEFAULT_TIMEOUT;
+  gst_rtspsrc_set_tcp_timeout (src, DEFAULT_TCP_TIMEOUT);
+  src->latency = DEFAULT_LATENCY_MS;
+  src->drop_on_latency = DEFAULT_DROP_ON_LATENCY;
+  src->connection_speed = DEFAULT_CONNECTION_SPEED;
+  src->nat_method = DEFAULT_NAT_METHOD;
+  src->do_rtcp = DEFAULT_DO_RTCP;
+  src->do_rtsp_keep_alive = DEFAULT_DO_RTSP_KEEP_ALIVE;
+  gst_rtspsrc_set_proxy (src, DEFAULT_PROXY);
+  src->rtp_blocksize = DEFAULT_RTP_BLOCKSIZE;
+  src->user_id = g_strdup (DEFAULT_USER_ID);
+  src->user_pw = g_strdup (DEFAULT_USER_PW);
+  src->buffer_mode = DEFAULT_BUFFER_MODE;
+  src->client_port_range.min = 0;
+  src->client_port_range.max = 0;
+  src->udp_buffer_size = DEFAULT_UDP_BUFFER_SIZE;
+  src->short_header = DEFAULT_SHORT_HEADER;
+  src->probation = DEFAULT_PROBATION;
+  src->udp_reconnect = DEFAULT_UDP_RECONNECT;
+  src->multi_iface = g_strdup (DEFAULT_MULTICAST_IFACE);
+  src->ntp_sync = DEFAULT_NTP_SYNC;
+  src->use_pipeline_clock = DEFAULT_USE_PIPELINE_CLOCK;
+  src->sdes = NULL;
+  src->tls_validation_flags = DEFAULT_TLS_VALIDATION_FLAGS;
+  src->tls_database = DEFAULT_TLS_DATABASE;
+  src->tls_interaction = DEFAULT_TLS_INTERACTION;
+  src->do_retransmission = DEFAULT_DO_RETRANSMISSION;
+  src->ntp_time_source = DEFAULT_NTP_TIME_SOURCE;
+  src->user_agent = g_strdup (DEFAULT_USER_AGENT);
+  src->max_rtcp_rtp_time_diff = DEFAULT_MAX_RTCP_RTP_TIME_DIFF;
+  src->rfc7273_sync = DEFAULT_RFC7273_SYNC;
+  src->max_ts_offset_adjustment = DEFAULT_MAX_TS_OFFSET_ADJUSTMENT;
+  src->max_ts_offset = DEFAULT_MAX_TS_OFFSET;
+  src->max_ts_offset_is_set = FALSE;
+  src->default_version = DEFAULT_VERSION;
+  src->version = GST_RTSP_VERSION_INVALID;
+
+  /* get a list of all extensions */
+  src->extensions = gst_rtsp_ext_list_get ();
+
+  /* connect to send signal */
+  gst_rtsp_ext_list_connect (src->extensions, "send",
+      (GCallback) gst_rtspsrc_send_cb, src);
+
+  /* protects the streaming thread in interleaved mode or the polling
+   * thread in UDP mode. */
+  g_rec_mutex_init (&src->stream_rec_lock);
+
+  /* protects our state changes from multiple invocations */
+  g_rec_mutex_init (&src->state_rec_lock);
+
+  src->state = GST_RTSP_STATE_INVALID;
+
+  g_mutex_init (&src->conninfo.send_lock);
+  g_mutex_init (&src->conninfo.recv_lock);
+
+  GST_OBJECT_FLAG_SET (src, GST_ELEMENT_FLAG_SOURCE);
+  gst_bin_set_suppressed_flags (GST_BIN (src),
+      GST_ELEMENT_FLAG_SOURCE | GST_ELEMENT_FLAG_SINK);
+}
+
+static void
+gst_rtspsrc_finalize (GObject * object)
+{
+  GstRTSPSrc *rtspsrc;
+
+  rtspsrc = GST_RTSPSRC (object);
+
+  gst_rtsp_ext_list_free (rtspsrc->extensions);
+  g_free (rtspsrc->conninfo.location);
+  gst_rtsp_url_free (rtspsrc->conninfo.url);
+  g_free (rtspsrc->conninfo.url_str);
+  g_free (rtspsrc->user_id);
+  g_free (rtspsrc->user_pw);
+  g_free (rtspsrc->multi_iface);
+  g_free (rtspsrc->user_agent);
+
+  if (rtspsrc->sdp) {
+    gst_sdp_message_free (rtspsrc->sdp);
+    rtspsrc->sdp = NULL;
+  }
+  if (rtspsrc->provided_clock)
+    gst_object_unref (rtspsrc->provided_clock);
+
+  if (rtspsrc->sdes)
+    gst_structure_free (rtspsrc->sdes);
+
+  if (rtspsrc->tls_database)
+    g_object_unref (rtspsrc->tls_database);
+
+  if (rtspsrc->tls_interaction)
+    g_object_unref (rtspsrc->tls_interaction);
+
+  /* free locks */
+  g_rec_mutex_clear (&rtspsrc->stream_rec_lock);
+  g_rec_mutex_clear (&rtspsrc->state_rec_lock);
+
+  g_mutex_clear (&rtspsrc->conninfo.send_lock);
+  g_mutex_clear (&rtspsrc->conninfo.recv_lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstClock *
+gst_rtspsrc_provide_clock (GstElement * element)
+{
+  GstRTSPSrc *src = GST_RTSPSRC (element);
+  GstClock *clock;
+
+  if ((clock = src->provided_clock) != NULL)
+    return gst_object_ref (clock);
+
+  return GST_ELEMENT_CLASS (parent_class)->provide_clock (element);
+}
+
+/* a proxy string of the format [user:passwd@]host[:port] */
+static gboolean
+gst_rtspsrc_set_proxy (GstRTSPSrc * rtsp, const gchar * proxy)
+{
+  gchar *p, *at, *col;
+
+  g_free (rtsp->proxy_user);
+  rtsp->proxy_user = NULL;
+  g_free (rtsp->proxy_passwd);
+  rtsp->proxy_passwd = NULL;
+  g_free (rtsp->proxy_host);
+  rtsp->proxy_host = NULL;
+  rtsp->proxy_port = 0;
+
+  p = (gchar *) proxy;
+
+  if (p == NULL)
+    return TRUE;
+
+  /* we allow http:// in front but ignore it */
+  if (g_str_has_prefix (p, "http://"))
+    p += 7;
+
+  at = strchr (p, '@');
+  if (at) {
+    /* look for user:passwd */
+    col = strchr (proxy, ':');
+    if (col == NULL || col > at)
+      return FALSE;
+
+    rtsp->proxy_user = g_strndup (p, col - p);
+    col++;
+    rtsp->proxy_passwd = g_strndup (col, at - col);
+
+    /* move to host */
+    p = at + 1;
+  } else {
+    if (rtsp->prop_proxy_id != NULL && *rtsp->prop_proxy_id != '\0')
+      rtsp->proxy_user = g_strdup (rtsp->prop_proxy_id);
+    if (rtsp->prop_proxy_pw != NULL && *rtsp->prop_proxy_pw != '\0')
+      rtsp->proxy_passwd = g_strdup (rtsp->prop_proxy_pw);
+    if (rtsp->proxy_user != NULL || rtsp->proxy_passwd != NULL) {
+      GST_LOG_OBJECT (rtsp, "set proxy user/pw from properties: %s:%s",
+          GST_STR_NULL (rtsp->proxy_user), GST_STR_NULL (rtsp->proxy_passwd));
+    }
+  }
+  col = strchr (p, ':');
+
+  if (col) {
+    /* everything before the colon is the hostname */
+    rtsp->proxy_host = g_strndup (p, col - p);
+    p = col + 1;
+    rtsp->proxy_port = strtoul (p, (char **) &p, 10);
+  } else {
+    rtsp->proxy_host = g_strdup (p);
+    rtsp->proxy_port = 8080;
+  }
+  return TRUE;
+}
+
+static void
+gst_rtspsrc_set_tcp_timeout (GstRTSPSrc * rtspsrc, guint64 timeout)
+{
+  rtspsrc->tcp_timeout.tv_sec = timeout / G_USEC_PER_SEC;
+  rtspsrc->tcp_timeout.tv_usec = timeout % G_USEC_PER_SEC;
+
+  if (timeout != 0)
+    rtspsrc->ptcp_timeout = &rtspsrc->tcp_timeout;
+  else
+    rtspsrc->ptcp_timeout = NULL;
+}
+
+static void
+gst_rtspsrc_set_property (GObject * object, guint prop_id, const GValue * value,
+    GParamSpec * pspec)
+{
+  GstRTSPSrc *rtspsrc;
+
+  rtspsrc = GST_RTSPSRC (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      gst_rtspsrc_uri_set_uri (GST_URI_HANDLER (rtspsrc),
+          g_value_get_string (value), NULL);
+      break;
+    case PROP_PROTOCOLS:
+      rtspsrc->protocols = g_value_get_flags (value);
+      break;
+    case PROP_DEBUG:
+      rtspsrc->debug = g_value_get_boolean (value);
+      break;
+    case PROP_RETRY:
+      rtspsrc->retry = g_value_get_uint (value);
+      break;
+    case PROP_TIMEOUT:
+      rtspsrc->udp_timeout = g_value_get_uint64 (value);
+      break;
+    case PROP_TCP_TIMEOUT:
+      gst_rtspsrc_set_tcp_timeout (rtspsrc, g_value_get_uint64 (value));
+      break;
+    case PROP_LATENCY:
+      rtspsrc->latency = g_value_get_uint (value);
+      break;
+    case PROP_DROP_ON_LATENCY:
+      rtspsrc->drop_on_latency = g_value_get_boolean (value);
+      break;
+    case PROP_CONNECTION_SPEED:
+      rtspsrc->connection_speed = g_value_get_uint64 (value);
+      break;
+    case PROP_NAT_METHOD:
+      rtspsrc->nat_method = g_value_get_enum (value);
+      break;
+    case PROP_DO_RTCP:
+      rtspsrc->do_rtcp = g_value_get_boolean (value);
+      break;
+    case PROP_DO_RTSP_KEEP_ALIVE:
+      rtspsrc->do_rtsp_keep_alive = g_value_get_boolean (value);
+      break;
+    case PROP_PROXY:
+      gst_rtspsrc_set_proxy (rtspsrc, g_value_get_string (value));
+      break;
+    case PROP_PROXY_ID:
+      g_free (rtspsrc->prop_proxy_id);
+      rtspsrc->prop_proxy_id = g_value_dup_string (value);
+      break;
+    case PROP_PROXY_PW:
+      g_free (rtspsrc->prop_proxy_pw);
+      rtspsrc->prop_proxy_pw = g_value_dup_string (value);
+      break;
+    case PROP_RTP_BLOCKSIZE:
+      rtspsrc->rtp_blocksize = g_value_get_uint (value);
+      break;
+    case PROP_USER_ID:
+      g_free (rtspsrc->user_id);
+      rtspsrc->user_id = g_value_dup_string (value);
+      break;
+    case PROP_USER_PW:
+      g_free (rtspsrc->user_pw);
+      rtspsrc->user_pw = g_value_dup_string (value);
+      break;
+    case PROP_BUFFER_MODE:
+      rtspsrc->buffer_mode = g_value_get_enum (value);
+      break;
+    case PROP_PORT_RANGE:
+    {
+      const gchar *str;
+
+      str = g_value_get_string (value);
+      if (sscanf (str, "%u-%u", &rtspsrc->client_port_range.min,
+              &rtspsrc->client_port_range.max) != 2) {
+        rtspsrc->client_port_range.min = 0;
+        rtspsrc->client_port_range.max = 0;
+      }
+      break;
+    }
+    case PROP_UDP_BUFFER_SIZE:
+      rtspsrc->udp_buffer_size = g_value_get_int (value);
+      break;
+    case PROP_SHORT_HEADER:
+      rtspsrc->short_header = g_value_get_boolean (value);
+      break;
+    case PROP_PROBATION:
+      rtspsrc->probation = g_value_get_uint (value);
+      break;
+    case PROP_UDP_RECONNECT:
+      rtspsrc->udp_reconnect = g_value_get_boolean (value);
+      break;
+    case PROP_MULTICAST_IFACE:
+      g_free (rtspsrc->multi_iface);
+
+      if (g_value_get_string (value) == NULL)
+        rtspsrc->multi_iface = g_strdup (DEFAULT_MULTICAST_IFACE);
+      else
+        rtspsrc->multi_iface = g_value_dup_string (value);
+      break;
+    case PROP_NTP_SYNC:
+      rtspsrc->ntp_sync = g_value_get_boolean (value);
+      /* The default value of max_ts_offset depends on ntp_sync. If user
+       * hasn't set it then change default value */
+      if (!rtspsrc->max_ts_offset_is_set) {
+        if (rtspsrc->ntp_sync) {
+          rtspsrc->max_ts_offset = 0;
+        } else {
+          rtspsrc->max_ts_offset = DEFAULT_MAX_TS_OFFSET;
+        }
+      }
+      break;
+    case PROP_USE_PIPELINE_CLOCK:
+      rtspsrc->use_pipeline_clock = g_value_get_boolean (value);
+      break;
+    case PROP_SDES:
+      rtspsrc->sdes = g_value_dup_boxed (value);
+      break;
+    case PROP_TLS_VALIDATION_FLAGS:
+      rtspsrc->tls_validation_flags = g_value_get_flags (value);
+      break;
+    case PROP_TLS_DATABASE:
+      g_clear_object (&rtspsrc->tls_database);
+      rtspsrc->tls_database = g_value_dup_object (value);
+      break;
+    case PROP_TLS_INTERACTION:
+      g_clear_object (&rtspsrc->tls_interaction);
+      rtspsrc->tls_interaction = g_value_dup_object (value);
+      break;
+    case PROP_DO_RETRANSMISSION:
+      rtspsrc->do_retransmission = g_value_get_boolean (value);
+      break;
+    case PROP_NTP_TIME_SOURCE:
+      rtspsrc->ntp_time_source = g_value_get_enum (value);
+      break;
+    case PROP_USER_AGENT:
+      g_free (rtspsrc->user_agent);
+      rtspsrc->user_agent = g_value_dup_string (value);
+      break;
+    case PROP_MAX_RTCP_RTP_TIME_DIFF:
+      rtspsrc->max_rtcp_rtp_time_diff = g_value_get_int (value);
+      break;
+    case PROP_RFC7273_SYNC:
+      rtspsrc->rfc7273_sync = g_value_get_boolean (value);
+      break;
+    case PROP_MAX_TS_OFFSET_ADJUSTMENT:
+      rtspsrc->max_ts_offset_adjustment = g_value_get_uint64 (value);
+      break;
+    case PROP_MAX_TS_OFFSET:
+      rtspsrc->max_ts_offset = g_value_get_int64 (value);
+      rtspsrc->max_ts_offset_is_set = TRUE;
+      break;
+    case PROP_DEFAULT_VERSION:
+      rtspsrc->default_version = g_value_get_enum (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtspsrc_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstRTSPSrc *rtspsrc;
+
+  rtspsrc = GST_RTSPSRC (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      g_value_set_string (value, rtspsrc->conninfo.location);
+      break;
+    case PROP_PROTOCOLS:
+      g_value_set_flags (value, rtspsrc->protocols);
+      break;
+    case PROP_DEBUG:
+      g_value_set_boolean (value, rtspsrc->debug);
+      break;
+    case PROP_RETRY:
+      g_value_set_uint (value, rtspsrc->retry);
+      break;
+    case PROP_TIMEOUT:
+      g_value_set_uint64 (value, rtspsrc->udp_timeout);
+      break;
+    case PROP_TCP_TIMEOUT:
+    {
+      guint64 timeout;
+
+      timeout = ((guint64) rtspsrc->tcp_timeout.tv_sec) * G_USEC_PER_SEC +
+          rtspsrc->tcp_timeout.tv_usec;
+      g_value_set_uint64 (value, timeout);
+      break;
+    }
+    case PROP_LATENCY:
+      g_value_set_uint (value, rtspsrc->latency);
+      break;
+    case PROP_DROP_ON_LATENCY:
+      g_value_set_boolean (value, rtspsrc->drop_on_latency);
+      break;
+    case PROP_CONNECTION_SPEED:
+      g_value_set_uint64 (value, rtspsrc->connection_speed);
+      break;
+    case PROP_NAT_METHOD:
+      g_value_set_enum (value, rtspsrc->nat_method);
+      break;
+    case PROP_DO_RTCP:
+      g_value_set_boolean (value, rtspsrc->do_rtcp);
+      break;
+    case PROP_DO_RTSP_KEEP_ALIVE:
+      g_value_set_boolean (value, rtspsrc->do_rtsp_keep_alive);
+      break;
+    case PROP_PROXY:
+    {
+      gchar *str;
+
+      if (rtspsrc->proxy_host) {
+        str =
+            g_strdup_printf ("%s:%d", rtspsrc->proxy_host, rtspsrc->proxy_port);
+      } else {
+        str = NULL;
+      }
+      g_value_take_string (value, str);
+      break;
+    }
+    case PROP_PROXY_ID:
+      g_value_set_string (value, rtspsrc->prop_proxy_id);
+      break;
+    case PROP_PROXY_PW:
+      g_value_set_string (value, rtspsrc->prop_proxy_pw);
+      break;
+    case PROP_RTP_BLOCKSIZE:
+      g_value_set_uint (value, rtspsrc->rtp_blocksize);
+      break;
+    case PROP_USER_ID:
+      g_value_set_string (value, rtspsrc->user_id);
+      break;
+    case PROP_USER_PW:
+      g_value_set_string (value, rtspsrc->user_pw);
+      break;
+    case PROP_BUFFER_MODE:
+      g_value_set_enum (value, rtspsrc->buffer_mode);
+      break;
+    case PROP_PORT_RANGE:
+    {
+      gchar *str;
+
+      if (rtspsrc->client_port_range.min != 0) {
+        str = g_strdup_printf ("%u-%u", rtspsrc->client_port_range.min,
+            rtspsrc->client_port_range.max);
+      } else {
+        str = NULL;
+      }
+      g_value_take_string (value, str);
+      break;
+    }
+    case PROP_UDP_BUFFER_SIZE:
+      g_value_set_int (value, rtspsrc->udp_buffer_size);
+      break;
+    case PROP_SHORT_HEADER:
+      g_value_set_boolean (value, rtspsrc->short_header);
+      break;
+    case PROP_PROBATION:
+      g_value_set_uint (value, rtspsrc->probation);
+      break;
+    case PROP_UDP_RECONNECT:
+      g_value_set_boolean (value, rtspsrc->udp_reconnect);
+      break;
+    case PROP_MULTICAST_IFACE:
+      g_value_set_string (value, rtspsrc->multi_iface);
+      break;
+    case PROP_NTP_SYNC:
+      g_value_set_boolean (value, rtspsrc->ntp_sync);
+      break;
+    case PROP_USE_PIPELINE_CLOCK:
+      g_value_set_boolean (value, rtspsrc->use_pipeline_clock);
+      break;
+    case PROP_SDES:
+      g_value_set_boxed (value, rtspsrc->sdes);
+      break;
+    case PROP_TLS_VALIDATION_FLAGS:
+      g_value_set_flags (value, rtspsrc->tls_validation_flags);
+      break;
+    case PROP_TLS_DATABASE:
+      g_value_set_object (value, rtspsrc->tls_database);
+      break;
+    case PROP_TLS_INTERACTION:
+      g_value_set_object (value, rtspsrc->tls_interaction);
+      break;
+    case PROP_DO_RETRANSMISSION:
+      g_value_set_boolean (value, rtspsrc->do_retransmission);
+      break;
+    case PROP_NTP_TIME_SOURCE:
+      g_value_set_enum (value, rtspsrc->ntp_time_source);
+      break;
+    case PROP_USER_AGENT:
+      g_value_set_string (value, rtspsrc->user_agent);
+      break;
+    case PROP_MAX_RTCP_RTP_TIME_DIFF:
+      g_value_set_int (value, rtspsrc->max_rtcp_rtp_time_diff);
+      break;
+    case PROP_RFC7273_SYNC:
+      g_value_set_boolean (value, rtspsrc->rfc7273_sync);
+      break;
+    case PROP_MAX_TS_OFFSET_ADJUSTMENT:
+      g_value_set_uint64 (value, rtspsrc->max_ts_offset_adjustment);
+      break;
+    case PROP_MAX_TS_OFFSET:
+      g_value_set_int64 (value, rtspsrc->max_ts_offset);
+      break;
+    case PROP_DEFAULT_VERSION:
+      g_value_set_enum (value, rtspsrc->default_version);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gint
+find_stream_by_id (GstRTSPStream * stream, gint * id)
+{
+  if (stream->id == *id)
+    return 0;
+
+  return -1;
+}
+
+static gint
+find_stream_by_channel (GstRTSPStream * stream, gint * channel)
+{
+  /* ignore unconfigured channels here (e.g., those that
+   * were explicitly skipped during SETUP) */
+  if ((stream->channelpad[0] != NULL) &&
+      (stream->channel[0] == *channel || stream->channel[1] == *channel))
+    return 0;
+
+  return -1;
+}
+
+static gint
+find_stream_by_udpsrc (GstRTSPStream * stream, gconstpointer a)
+{
+  GstElement *src = (GstElement *) a;
+
+  if (stream->udpsrc[0] == src)
+    return 0;
+  if (stream->udpsrc[1] == src)
+    return 0;
+
+  return -1;
+}
+
+static gint
+find_stream_by_setup (GstRTSPStream * stream, gconstpointer a)
+{
+  if (stream->conninfo.location) {
+    /* check qualified setup_url */
+    if (!strcmp (stream->conninfo.location, (gchar *) a))
+      return 0;
+  }
+  if (stream->control_url) {
+    /* check original control_url */
+    if (!strcmp (stream->control_url, (gchar *) a))
+      return 0;
+
+    /* check if qualified setup_url ends with string */
+    if (g_str_has_suffix (stream->control_url, (gchar *) a))
+      return 0;
+  }
+
+  return -1;
+}
+
+static GstRTSPStream *
+find_stream (GstRTSPSrc * src, gconstpointer data, gconstpointer func)
+{
+  GList *lstream;
+
+  /* find and get stream */
+  if ((lstream = g_list_find_custom (src->streams, data, (GCompareFunc) func)))
+    return (GstRTSPStream *) lstream->data;
+
+  return NULL;
+}
+
+static const GstSDPBandwidth *
+gst_rtspsrc_get_bandwidth (GstRTSPSrc * src, const GstSDPMessage * sdp,
+    const GstSDPMedia * media, const gchar * type)
+{
+  guint i, len;
+
+  /* first look in the media specific section */
+  len = gst_sdp_media_bandwidths_len (media);
+  for (i = 0; i < len; i++) {
+    const GstSDPBandwidth *bw = gst_sdp_media_get_bandwidth (media, i);
+
+    if (strcmp (bw->bwtype, type) == 0)
+      return bw;
+  }
+  /* then look in the message specific section */
+  len = gst_sdp_message_bandwidths_len (sdp);
+  for (i = 0; i < len; i++) {
+    const GstSDPBandwidth *bw = gst_sdp_message_get_bandwidth (sdp, i);
+
+    if (strcmp (bw->bwtype, type) == 0)
+      return bw;
+  }
+  return NULL;
+}
+
+static void
+gst_rtspsrc_collect_bandwidth (GstRTSPSrc * src, const GstSDPMessage * sdp,
+    const GstSDPMedia * media, GstRTSPStream * stream)
+{
+  const GstSDPBandwidth *bw;
+
+  if ((bw = gst_rtspsrc_get_bandwidth (src, sdp, media, GST_SDP_BWTYPE_AS)))
+    stream->as_bandwidth = bw->bandwidth;
+  else
+    stream->as_bandwidth = -1;
+
+  if ((bw = gst_rtspsrc_get_bandwidth (src, sdp, media, GST_SDP_BWTYPE_RR)))
+    stream->rr_bandwidth = bw->bandwidth;
+  else
+    stream->rr_bandwidth = -1;
+
+  if ((bw = gst_rtspsrc_get_bandwidth (src, sdp, media, GST_SDP_BWTYPE_RS)))
+    stream->rs_bandwidth = bw->bandwidth;
+  else
+    stream->rs_bandwidth = -1;
+}
+
+static void
+gst_rtspsrc_do_stream_connection (GstRTSPSrc * src, GstRTSPStream * stream,
+    const GstSDPConnection * conn)
+{
+  if (conn->nettype == NULL || strcmp (conn->nettype, "IN") != 0)
+    return;
+
+  if (conn->addrtype == NULL)
+    return;
+
+  /* check for IPV6 */
+  if (strcmp (conn->addrtype, "IP4") == 0)
+    stream->is_ipv6 = FALSE;
+  else if (strcmp (conn->addrtype, "IP6") == 0)
+    stream->is_ipv6 = TRUE;
+  else
+    return;
+
+  /* save address */
+  g_free (stream->destination);
+  stream->destination = g_strdup (conn->address);
+
+  /* check for multicast */
+  stream->is_multicast =
+      gst_sdp_address_is_multicast (conn->nettype, conn->addrtype,
+      conn->address);
+  stream->ttl = conn->ttl;
+}
+
+/* Go over the connections for a stream.
+ * - If we are dealing with IPV6, we will setup IPV6 sockets for sending and
+ *   receiving.
+ * - If we are dealing with a localhost address, we disable multicast
+ */
+static void
+gst_rtspsrc_collect_connections (GstRTSPSrc * src, const GstSDPMessage * sdp,
+    const GstSDPMedia * media, GstRTSPStream * stream)
+{
+  const GstSDPConnection *conn;
+  guint i, len;
+
+  /* first look in the media specific section */
+  len = gst_sdp_media_connections_len (media);
+  for (i = 0; i < len; i++) {
+    conn = gst_sdp_media_get_connection (media, i);
+
+    gst_rtspsrc_do_stream_connection (src, stream, conn);
+  }
+  /* then look in the message specific section */
+  if ((conn = gst_sdp_message_get_connection (sdp))) {
+    gst_rtspsrc_do_stream_connection (src, stream, conn);
+  }
+}
+
+static gchar *
+make_stream_id (GstRTSPStream * stream, const GstSDPMedia * media)
+{
+  gchar *stream_id =
+      g_strdup_printf ("%s:%d:%d:%s:%d", media->media, media->port,
+      media->num_ports, media->proto, stream->default_pt);
+
+  g_strcanon (stream_id, G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS, ':');
+
+  return stream_id;
+}
+
+/*   m=<media> <UDP port> RTP/AVP <payload>
+ */
+static void
+gst_rtspsrc_collect_payloads (GstRTSPSrc * src, const GstSDPMessage * sdp,
+    const GstSDPMedia * media, GstRTSPStream * stream)
+{
+  guint i, len;
+  const gchar *proto;
+  GstCaps *global_caps;
+
+  /* get proto */
+  proto = gst_sdp_media_get_proto (media);
+  if (proto == NULL)
+    goto no_proto;
+
+  if (g_str_equal (proto, "RTP/AVP"))
+    stream->profile = GST_RTSP_PROFILE_AVP;
+  else if (g_str_equal (proto, "RTP/SAVP"))
+    stream->profile = GST_RTSP_PROFILE_SAVP;
+  else if (g_str_equal (proto, "RTP/AVPF"))
+    stream->profile = GST_RTSP_PROFILE_AVPF;
+  else if (g_str_equal (proto, "RTP/SAVPF"))
+    stream->profile = GST_RTSP_PROFILE_SAVPF;
+  else
+    goto unknown_proto;
+
+  if (gst_sdp_media_get_attribute_val (media, "recvonly") != NULL)
+    goto recvonly_media;
+
+  /* Parse global SDP attributes once */
+  global_caps = gst_caps_new_empty_simple ("application/x-unknown");
+  GST_DEBUG ("mapping sdp session level attributes to caps");
+  gst_sdp_message_attributes_to_caps (sdp, global_caps);
+  GST_DEBUG ("mapping sdp media level attributes to caps");
+  gst_sdp_media_attributes_to_caps (media, global_caps);
+
+  /* Keep a copy of the SDP key management */
+  gst_sdp_media_parse_keymgmt (media, &stream->mikey);
+  if (stream->mikey == NULL)
+    gst_sdp_message_parse_keymgmt (sdp, &stream->mikey);
+
+  len = gst_sdp_media_formats_len (media);
+  for (i = 0; i < len; i++) {
+    gint pt;
+    GstCaps *caps, *outcaps;
+    GstStructure *s;
+    const gchar *enc;
+    PtMapItem item;
+
+    pt = atoi (gst_sdp_media_get_format (media, i));
+
+    GST_DEBUG_OBJECT (src, " looking at %d pt: %d", i, pt);
+
+    /* convert caps */
+    caps = gst_sdp_media_get_caps_from_media (media, pt);
+    if (caps == NULL) {
+      GST_WARNING_OBJECT (src, " skipping pt %d without caps", pt);
+      continue;
+    }
+
+    /* do some tweaks */
+    s = gst_caps_get_structure (caps, 0);
+    if ((enc = gst_structure_get_string (s, "encoding-name"))) {
+      stream->is_real = (strstr (enc, "-REAL") != NULL);
+      if (strcmp (enc, "X-ASF-PF") == 0)
+        stream->container = TRUE;
+    }
+
+    /* Merge in global caps */
+    /* Intersect will merge in missing fields to the current caps */
+    outcaps = gst_caps_intersect (caps, global_caps);
+    gst_caps_unref (caps);
+
+    /* the first pt will be the default */
+    if (stream->ptmap->len == 0)
+      stream->default_pt = pt;
+
+    item.pt = pt;
+    item.caps = outcaps;
+
+    g_array_append_val (stream->ptmap, item);
+  }
+
+  stream->stream_id = make_stream_id (stream, media);
+
+  gst_caps_unref (global_caps);
+  return;
+
+no_proto:
+  {
+    GST_ERROR_OBJECT (src, "can't find proto in media");
+    return;
+  }
+unknown_proto:
+  {
+    GST_ERROR_OBJECT (src, "unknown proto in media: '%s'", proto);
+    return;
+  }
+recvonly_media:
+  {
+    GST_DEBUG_OBJECT (src, "recvonly media ignored");
+    return;
+  }
+}
+
+static const gchar *
+get_aggregate_control (GstRTSPSrc * src)
+{
+  const gchar *base;
+
+  if (src->control)
+    base = src->control;
+  else if (src->content_base)
+    base = src->content_base;
+  else if (src->conninfo.url_str)
+    base = src->conninfo.url_str;
+  else
+    base = "/";
+
+  return base;
+}
+
+static void
+clear_ptmap_item (PtMapItem * item)
+{
+  if (item->caps)
+    gst_caps_unref (item->caps);
+}
+
+static GstRTSPStream *
+gst_rtspsrc_create_stream (GstRTSPSrc * src, GstSDPMessage * sdp, gint idx,
+    gint n_streams)
+{
+  GstRTSPStream *stream;
+  const gchar *control_url;
+  const GstSDPMedia *media;
+
+  /* get media, should not return NULL */
+  media = gst_sdp_message_get_media (sdp, idx);
+  if (media == NULL)
+    return NULL;
+
+  stream = g_new0 (GstRTSPStream, 1);
+  stream->parent = src;
+  /* we mark the pad as not linked, we will mark it as OK when we add the pad to
+   * the element. */
+  stream->last_ret = GST_FLOW_NOT_LINKED;
+  stream->added = FALSE;
+  stream->setup = FALSE;
+  stream->skipped = FALSE;
+  stream->id = idx;
+  stream->eos = FALSE;
+  stream->discont = TRUE;
+  stream->seqbase = -1;
+  stream->timebase = -1;
+  stream->send_ssrc = g_random_int ();
+  stream->profile = GST_RTSP_PROFILE_AVP;
+  stream->ptmap = g_array_new (FALSE, FALSE, sizeof (PtMapItem));
+  stream->mikey = NULL;
+  stream->stream_id = NULL;
+  g_mutex_init (&stream->conninfo.send_lock);
+  g_mutex_init (&stream->conninfo.recv_lock);
+  g_array_set_clear_func (stream->ptmap, (GDestroyNotify) clear_ptmap_item);
+
+  /* collect bandwidth information for this steam. FIXME, configure in the RTP
+   * session manager to scale RTCP. */
+  gst_rtspsrc_collect_bandwidth (src, sdp, media, stream);
+
+  /* collect connection info */
+  gst_rtspsrc_collect_connections (src, sdp, media, stream);
+
+  /* make the payload type map */
+  gst_rtspsrc_collect_payloads (src, sdp, media, stream);
+
+  /* collect port number */
+  stream->port = gst_sdp_media_get_port (media);
+
+  /* get control url to construct the setup url. The setup url is used to
+   * configure the transport of the stream and is used to identity the stream in
+   * the RTP-Info header field returned from PLAY. */
+  control_url = gst_sdp_media_get_attribute_val (media, "control");
+  if (control_url == NULL)
+    control_url = gst_sdp_message_get_attribute_val_n (sdp, "control", 0);
+
+  GST_DEBUG_OBJECT (src, "stream %d, (%p)", stream->id, stream);
+  GST_DEBUG_OBJECT (src, " port: %d", stream->port);
+  GST_DEBUG_OBJECT (src, " container: %d", stream->container);
+  GST_DEBUG_OBJECT (src, " control: %s", GST_STR_NULL (control_url));
+
+  /* RFC 2326, C.3: missing control_url permitted in case of a single stream */
+  if (control_url == NULL && n_streams == 1) {
+    control_url = "";
+  }
+
+  if (control_url != NULL) {
+    stream->control_url = g_strdup (control_url);
+    /* Build a fully qualified url using the content_base if any or by prefixing
+     * the original request.
+     * If the control_url starts with a '/' or a non rtsp: protocol we will most
+     * likely build a URL that the server will fail to understand, this is ok,
+     * we will fail then. */
+    if (g_str_has_prefix (control_url, "rtsp://"))
+      stream->conninfo.location = g_strdup (control_url);
+    else {
+      const gchar *base;
+      gboolean has_slash;
+
+      if (g_strcmp0 (control_url, "*") == 0)
+        control_url = "";
+
+      base = get_aggregate_control (src);
+
+      /* check if the base ends or control starts with / */
+      has_slash = g_str_has_prefix (control_url, "/");
+      has_slash = has_slash || g_str_has_suffix (base, "/");
+
+      /* concatenate the two strings, insert / when not present */
+      stream->conninfo.location =
+          g_strdup_printf ("%s%s%s", base, has_slash ? "" : "/", control_url);
+    }
+  }
+  GST_DEBUG_OBJECT (src, " setup: %s",
+      GST_STR_NULL (stream->conninfo.location));
+
+  /* we keep track of all streams */
+  src->streams = g_list_append (src->streams, stream);
+
+  return stream;
+
+  /* ERRORS */
+}
+
+static void
+gst_rtspsrc_stream_free (GstRTSPSrc * src, GstRTSPStream * stream)
+{
+  gint i;
+
+  GST_DEBUG_OBJECT (src, "free stream %p", stream);
+
+  g_array_free (stream->ptmap, TRUE);
+
+  g_free (stream->destination);
+  g_free (stream->control_url);
+  g_free (stream->conninfo.location);
+  g_free (stream->stream_id);
+
+  for (i = 0; i < 2; i++) {
+    if (stream->udpsrc[i]) {
+      gst_element_set_state (stream->udpsrc[i], GST_STATE_NULL);
+      gst_bin_remove (GST_BIN_CAST (src), stream->udpsrc[i]);
+      gst_object_unref (stream->udpsrc[i]);
+    }
+    if (stream->channelpad[i])
+      gst_object_unref (stream->channelpad[i]);
+
+    if (stream->udpsink[i]) {
+      gst_element_set_state (stream->udpsink[i], GST_STATE_NULL);
+      gst_bin_remove (GST_BIN_CAST (src), stream->udpsink[i]);
+      gst_object_unref (stream->udpsink[i]);
+    }
+  }
+  if (stream->fakesrc) {
+    gst_element_set_state (stream->fakesrc, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN_CAST (src), stream->fakesrc);
+    gst_object_unref (stream->fakesrc);
+  }
+  if (stream->srcpad) {
+    gst_pad_set_active (stream->srcpad, FALSE);
+    if (stream->added)
+      gst_element_remove_pad (GST_ELEMENT_CAST (src), stream->srcpad);
+  }
+  if (stream->srtpenc)
+    gst_object_unref (stream->srtpenc);
+  if (stream->srtpdec)
+    gst_object_unref (stream->srtpdec);
+  if (stream->srtcpparams)
+    gst_caps_unref (stream->srtcpparams);
+  if (stream->mikey)
+    gst_mikey_message_unref (stream->mikey);
+  if (stream->rtcppad)
+    gst_object_unref (stream->rtcppad);
+  if (stream->session)
+    g_object_unref (stream->session);
+  if (stream->rtx_pt_map)
+    gst_structure_free (stream->rtx_pt_map);
+
+  g_mutex_clear (&stream->conninfo.send_lock);
+  g_mutex_clear (&stream->conninfo.recv_lock);
+
+  g_free (stream);
+}
+
+static void
+gst_rtspsrc_cleanup (GstRTSPSrc * src)
+{
+  GList *walk;
+
+  GST_DEBUG_OBJECT (src, "cleanup");
+
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+
+    gst_rtspsrc_stream_free (src, stream);
+  }
+  g_list_free (src->streams);
+  src->streams = NULL;
+  if (src->manager) {
+    if (src->manager_sig_id) {
+      g_signal_handler_disconnect (src->manager, src->manager_sig_id);
+      src->manager_sig_id = 0;
+    }
+    gst_element_set_state (src->manager, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN_CAST (src), src->manager);
+    src->manager = NULL;
+  }
+  if (src->props)
+    gst_structure_free (src->props);
+  src->props = NULL;
+
+  g_free (src->content_base);
+  src->content_base = NULL;
+
+  g_free (src->control);
+  src->control = NULL;
+
+  if (src->range)
+    gst_rtsp_range_free (src->range);
+  src->range = NULL;
+
+  /* don't clear the SDP when it was used in the url */
+  if (src->sdp && !src->from_sdp) {
+    gst_sdp_message_free (src->sdp);
+    src->sdp = NULL;
+  }
+
+  src->need_segment = FALSE;
+
+  if (src->provided_clock) {
+    gst_object_unref (src->provided_clock);
+    src->provided_clock = NULL;
+  }
+}
+
+static gboolean
+gst_rtspsrc_alloc_udp_ports (GstRTSPStream * stream,
+    gint * rtpport, gint * rtcpport)
+{
+  GstRTSPSrc *src;
+  GstStateChangeReturn ret;
+  GstElement *udpsrc0, *udpsrc1;
+  gint tmp_rtp, tmp_rtcp;
+  guint count;
+  const gchar *host;
+
+  src = stream->parent;
+
+  udpsrc0 = NULL;
+  udpsrc1 = NULL;
+  count = 0;
+
+  /* Start at next port */
+  tmp_rtp = src->next_port_num;
+
+  if (stream->is_ipv6)
+    host = "udp://[::0]";
+  else
+    host = "udp://0.0.0.0";
+
+  /* try to allocate 2 UDP ports, the RTP port should be an even
+   * number and the RTCP port should be the next (uneven) port */
+again:
+
+  if (tmp_rtp != 0 && src->client_port_range.max > 0 &&
+      tmp_rtp >= src->client_port_range.max)
+    goto no_ports;
+
+  udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL);
+  if (udpsrc0 == NULL)
+    goto no_udp_protocol;
+  g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, "reuse", FALSE, NULL);
+
+  if (src->udp_buffer_size != 0)
+    g_object_set (G_OBJECT (udpsrc0), "buffer-size", src->udp_buffer_size,
+        NULL);
+
+  ret = gst_element_set_state (udpsrc0, GST_STATE_READY);
+  if (ret == GST_STATE_CHANGE_FAILURE) {
+    if (tmp_rtp != 0) {
+      GST_DEBUG_OBJECT (src, "Unable to make udpsrc from RTP port %d", tmp_rtp);
+
+      tmp_rtp += 2;
+      if (++count > src->retry)
+        goto no_ports;
+
+      GST_DEBUG_OBJECT (src, "free RTP udpsrc");
+      gst_element_set_state (udpsrc0, GST_STATE_NULL);
+      gst_object_unref (udpsrc0);
+      udpsrc0 = NULL;
+
+      GST_DEBUG_OBJECT (src, "retry %d", count);
+      goto again;
+    }
+    goto no_udp_protocol;
+  }
+
+  g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL);
+  GST_DEBUG_OBJECT (src, "got RTP port %d", tmp_rtp);
+
+  /* check if port is even */
+  if ((tmp_rtp & 0x01) != 0) {
+    /* port not even, close and allocate another */
+    if (++count > src->retry)
+      goto no_ports;
+
+    GST_DEBUG_OBJECT (src, "RTP port not even");
+
+    GST_DEBUG_OBJECT (src, "free RTP udpsrc");
+    gst_element_set_state (udpsrc0, GST_STATE_NULL);
+    gst_object_unref (udpsrc0);
+    udpsrc0 = NULL;
+
+    GST_DEBUG_OBJECT (src, "retry %d", count);
+    tmp_rtp++;
+    goto again;
+  }
+
+  /* allocate port+1 for RTCP now */
+  udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL);
+  if (udpsrc1 == NULL)
+    goto no_udp_rtcp_protocol;
+
+  /* set port */
+  tmp_rtcp = tmp_rtp + 1;
+  if (src->client_port_range.max > 0 && tmp_rtcp > src->client_port_range.max)
+    goto no_ports;
+
+  g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, "reuse", FALSE, NULL);
+
+  GST_DEBUG_OBJECT (src, "starting RTCP on port %d", tmp_rtcp);
+  ret = gst_element_set_state (udpsrc1, GST_STATE_READY);
+  /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */
+  if (ret == GST_STATE_CHANGE_FAILURE) {
+    GST_DEBUG_OBJECT (src, "Unable to make udpsrc from RTCP port %d", tmp_rtcp);
+
+    if (++count > src->retry)
+      goto no_ports;
+
+    GST_DEBUG_OBJECT (src, "free RTP udpsrc");
+    gst_element_set_state (udpsrc0, GST_STATE_NULL);
+    gst_object_unref (udpsrc0);
+    udpsrc0 = NULL;
+
+    GST_DEBUG_OBJECT (src, "free RTCP udpsrc");
+    gst_element_set_state (udpsrc1, GST_STATE_NULL);
+    gst_object_unref (udpsrc1);
+    udpsrc1 = NULL;
+
+    tmp_rtp += 2;
+    GST_DEBUG_OBJECT (src, "retry %d", count);
+    goto again;
+  }
+
+  /* all fine, do port check */
+  g_object_get (G_OBJECT (udpsrc0), "port", rtpport, NULL);
+  g_object_get (G_OBJECT (udpsrc1), "port", rtcpport, NULL);
+
+  /* this should not happen... */
+  if (*rtpport != tmp_rtp || *rtcpport != tmp_rtcp)
+    goto port_error;
+
+  /* we keep these elements, we configure all in configure_transport when the
+   * server told us to really use the UDP ports. */
+  stream->udpsrc[0] = gst_object_ref_sink (udpsrc0);
+  stream->udpsrc[1] = gst_object_ref_sink (udpsrc1);
+  gst_element_set_locked_state (stream->udpsrc[0], TRUE);
+  gst_element_set_locked_state (stream->udpsrc[1], TRUE);
+
+  /* keep track of next available port number when we have a range
+   * configured */
+  if (src->next_port_num != 0)
+    src->next_port_num = tmp_rtcp + 1;
+
+  return TRUE;
+
+  /* ERRORS */
+no_udp_protocol:
+  {
+    GST_DEBUG_OBJECT (src, "could not get UDP source");
+    goto cleanup;
+  }
+no_ports:
+  {
+    GST_DEBUG_OBJECT (src, "could not allocate UDP port pair after %d retries",
+        count);
+    goto cleanup;
+  }
+no_udp_rtcp_protocol:
+  {
+    GST_DEBUG_OBJECT (src, "could not get UDP source for RTCP");
+    goto cleanup;
+  }
+port_error:
+  {
+    GST_DEBUG_OBJECT (src, "ports don't match rtp: %d<->%d, rtcp: %d<->%d",
+        tmp_rtp, *rtpport, tmp_rtcp, *rtcpport);
+    goto cleanup;
+  }
+cleanup:
+  {
+    if (udpsrc0) {
+      gst_element_set_state (udpsrc0, GST_STATE_NULL);
+      gst_object_unref (udpsrc0);
+    }
+    if (udpsrc1) {
+      gst_element_set_state (udpsrc1, GST_STATE_NULL);
+      gst_object_unref (udpsrc1);
+    }
+    return FALSE;
+  }
+}
+
+static void
+gst_rtspsrc_set_state (GstRTSPSrc * src, GstState state)
+{
+  GList *walk;
+
+  if (src->manager)
+    gst_element_set_state (GST_ELEMENT_CAST (src->manager), state);
+
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+    gint i;
+
+    for (i = 0; i < 2; i++) {
+      if (stream->udpsrc[i])
+        gst_element_set_state (stream->udpsrc[i], state);
+    }
+  }
+}
+
+static void
+gst_rtspsrc_flush (GstRTSPSrc * src, gboolean flush, gboolean playing)
+{
+  GstEvent *event;
+  gint cmd;
+  GstState state;
+
+  if (flush) {
+    event = gst_event_new_flush_start ();
+    GST_DEBUG_OBJECT (src, "start flush");
+    cmd = CMD_WAIT;
+    state = GST_STATE_PAUSED;
+  } else {
+    event = gst_event_new_flush_stop (FALSE);
+    GST_DEBUG_OBJECT (src, "stop flush; playing %d", playing);
+    cmd = CMD_LOOP;
+    if (playing)
+      state = GST_STATE_PLAYING;
+    else
+      state = GST_STATE_PAUSED;
+  }
+  gst_rtspsrc_push_event (src, event);
+  gst_rtspsrc_loop_send_cmd (src, cmd, CMD_LOOP);
+  gst_rtspsrc_set_state (src, state);
+}
+
+static GstRTSPResult
+gst_rtspsrc_connection_send (GstRTSPSrc * src, GstRTSPConnInfo * conninfo,
+    GstRTSPMessage * message, GTimeVal * timeout)
+{
+  GstRTSPResult ret;
+
+  if (conninfo->connection) {
+    g_mutex_lock (&conninfo->send_lock);
+    ret = gst_rtsp_connection_send (conninfo->connection, message, timeout);
+    g_mutex_unlock (&conninfo->send_lock);
+  } else {
+    ret = GST_RTSP_ERROR;
+  }
+
+  return ret;
+}
+
+static GstRTSPResult
+gst_rtspsrc_connection_receive (GstRTSPSrc * src, GstRTSPConnInfo * conninfo,
+    GstRTSPMessage * message, GTimeVal * timeout)
+{
+  GstRTSPResult ret;
+
+  if (conninfo->connection) {
+    g_mutex_lock (&conninfo->recv_lock);
+    ret = gst_rtsp_connection_receive (conninfo->connection, message, timeout);
+    g_mutex_unlock (&conninfo->recv_lock);
+  } else {
+    ret = GST_RTSP_ERROR;
+  }
+
+  return ret;
+}
+
+static void
+gst_rtspsrc_get_position (GstRTSPSrc * src)
+{
+  GstQuery *query;
+  GList *walk;
+
+  query = gst_query_new_position (GST_FORMAT_TIME);
+  /*  should be known somewhere down the stream (e.g. jitterbuffer) */
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+    GstFormat fmt;
+    gint64 pos;
+
+    if (stream->srcpad) {
+      if (gst_pad_query (stream->srcpad, query)) {
+        gst_query_parse_position (query, &fmt, &pos);
+        GST_DEBUG_OBJECT (src, "retaining position %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (pos));
+        src->last_pos = pos;
+        goto out;
+      }
+    }
+  }
+
+  src->last_pos = 0;
+
+out:
+
+  gst_query_unref (query);
+}
+
+static gboolean
+gst_rtspsrc_perform_seek (GstRTSPSrc * src, GstEvent * event)
+{
+  gdouble rate;
+  GstFormat format;
+  GstSeekFlags flags;
+  GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
+  gint64 cur, stop;
+  gboolean flush, skip;
+  gboolean update;
+  gboolean playing;
+  GstSegment seeksegment = { 0, };
+  GList *walk;
+  const gchar *seek_style = NULL;
+
+  if (event) {
+    GST_DEBUG_OBJECT (src, "doing seek with event %" GST_PTR_FORMAT, event);
+
+    gst_event_parse_seek (event, &rate, &format, &flags,
+        &cur_type, &cur, &stop_type, &stop);
+
+    /* no negative rates yet */
+    if (rate < 0.0)
+      goto negative_rate;
+
+    /* we need TIME format */
+    if (format != src->segment.format)
+      goto no_format;
+
+    /* Check if we are not at all seekable */
+    if (src->seekable == -1.0)
+      goto not_seekable;
+
+    /* Additional seeking-to-beginning-only check */
+    if (src->seekable == 0.0 && cur != 0)
+      goto not_seekable;
+  } else {
+    GST_DEBUG_OBJECT (src, "doing seek without event");
+    flags = 0;
+    cur_type = GST_SEEK_TYPE_SET;
+    stop_type = GST_SEEK_TYPE_SET;
+  }
+
+  /* get flush flag */
+  flush = flags & GST_SEEK_FLAG_FLUSH;
+  skip = flags & GST_SEEK_FLAG_SKIP;
+
+  /* now we need to make sure the streaming thread is stopped. We do this by
+   * either sending a FLUSH_START event downstream which will cause the
+   * streaming thread to stop with a WRONG_STATE.
+   * For a non-flushing seek we simply pause the task, which will happen as soon
+   * as it completes one iteration (and thus might block when the sink is
+   * blocking in preroll). */
+  if (flush) {
+    GST_DEBUG_OBJECT (src, "starting flush");
+    gst_rtspsrc_flush (src, TRUE, FALSE);
+  } else {
+    if (src->task) {
+      gst_task_pause (src->task);
+    }
+  }
+
+  /* we should now be able to grab the streaming thread because we stopped it
+   * with the above flush/pause code */
+  GST_RTSP_STREAM_LOCK (src);
+
+  GST_DEBUG_OBJECT (src, "stopped streaming");
+
+  /* stop flushing the rtsp connection so we can send PAUSE/PLAY below */
+  gst_rtspsrc_connection_flush (src, FALSE);
+
+  /* copy segment, we need this because we still need the old
+   * segment when we close the current segment. */
+  memcpy (&seeksegment, &src->segment, sizeof (GstSegment));
+
+  /* configure the seek parameters in the seeksegment. We will then have the
+   * right values in the segment to perform the seek */
+  if (event) {
+    GST_DEBUG_OBJECT (src, "configuring seek");
+    gst_segment_do_seek (&seeksegment, rate, format, flags,
+        cur_type, cur, stop_type, stop, &update);
+  }
+
+  /* figure out the last position we need to play. If it's configured (stop !=
+   * -1), use that, else we play until the total duration of the file */
+  if ((stop = seeksegment.stop) == -1)
+    stop = seeksegment.duration;
+
+  /* if we were playing, pause first */
+  playing = (src->state == GST_RTSP_STATE_PLAYING);
+  if (playing) {
+    /* obtain current position in case seek fails */
+    gst_rtspsrc_get_position (src);
+    gst_rtspsrc_pause (src, FALSE);
+  }
+  src->skip = skip;
+
+  src->state = GST_RTSP_STATE_SEEKING;
+
+  /* PLAY will add the range header now. */
+  src->need_range = TRUE;
+
+  /* prepare for streaming again */
+  if (flush) {
+    /* if we started flush, we stop now */
+    GST_DEBUG_OBJECT (src, "stopping flush");
+    gst_rtspsrc_flush (src, FALSE, playing);
+  }
+
+  /* now we did the seek and can activate the new segment values */
+  memcpy (&src->segment, &seeksegment, sizeof (GstSegment));
+
+  /* if we're doing a segment seek, post a SEGMENT_START message */
+  if (src->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+    gst_element_post_message (GST_ELEMENT_CAST (src),
+        gst_message_new_segment_start (GST_OBJECT_CAST (src),
+            src->segment.format, src->segment.position));
+  }
+
+  /* now create the newsegment */
+  GST_DEBUG_OBJECT (src, "Creating newsegment from %" G_GINT64_FORMAT
+      " to %" G_GINT64_FORMAT, src->segment.position, stop);
+
+  /* mark discont */
+  GST_DEBUG_OBJECT (src, "mark DISCONT, we did a seek to another position");
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+    stream->discont = TRUE;
+  }
+
+  /* and continue playing if needed */
+  GST_OBJECT_LOCK (src);
+  playing = (GST_STATE_PENDING (src) == GST_STATE_VOID_PENDING
+      && GST_STATE (src) == GST_STATE_PLAYING)
+      || (GST_STATE_PENDING (src) == GST_STATE_PLAYING);
+  GST_OBJECT_UNLOCK (src);
+
+  if (src->version >= GST_RTSP_VERSION_2_0) {
+    if (flags & GST_SEEK_FLAG_ACCURATE)
+      seek_style = "RAP";
+    else if (flags & GST_SEEK_FLAG_KEY_UNIT)
+      seek_style = "CoRAP";
+    else if (flags & GST_SEEK_FLAG_KEY_UNIT
+        && flags & GST_SEEK_FLAG_SNAP_BEFORE)
+      seek_style = "First-Prior";
+    else if (flags & GST_SEEK_FLAG_KEY_UNIT && flags & GST_SEEK_FLAG_SNAP_AFTER)
+      seek_style = "Next";
+  }
+
+  if (playing)
+    gst_rtspsrc_play (src, &seeksegment, FALSE, seek_style);
+
+  GST_RTSP_STREAM_UNLOCK (src);
+
+  return TRUE;
+
+  /* ERRORS */
+negative_rate:
+  {
+    GST_DEBUG_OBJECT (src, "negative playback rates are not supported yet.");
+    return FALSE;
+  }
+no_format:
+  {
+    GST_DEBUG_OBJECT (src, "unsupported format given, seek aborted.");
+    return FALSE;
+  }
+not_seekable:
+  {
+    GST_DEBUG_OBJECT (src, "stream is not seekable");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_rtspsrc_handle_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstRTSPSrc *src;
+  gboolean res = TRUE;
+  gboolean forward;
+
+  src = GST_RTSPSRC_CAST (parent);
+
+  GST_DEBUG_OBJECT (src, "pad %s:%s received event %s",
+      GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+      res = gst_rtspsrc_perform_seek (src, event);
+      forward = FALSE;
+      break;
+    case GST_EVENT_QOS:
+    case GST_EVENT_NAVIGATION:
+    case GST_EVENT_LATENCY:
+    default:
+      forward = TRUE;
+      break;
+  }
+  if (forward) {
+    GstPad *target;
+
+    if ((target = gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (pad)))) {
+      res = gst_pad_send_event (target, event);
+      gst_object_unref (target);
+    } else {
+      gst_event_unref (event);
+    }
+  } else {
+    gst_event_unref (event);
+  }
+
+  return res;
+}
+
+static gboolean
+gst_rtspsrc_handle_src_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstRTSPStream *stream;
+
+  stream = gst_pad_get_element_private (pad);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_STREAM_START:{
+      const gchar *upstream_id;
+      gchar *stream_id;
+
+      gst_event_parse_stream_start (event, &upstream_id);
+      stream_id = g_strdup_printf ("%s/%s", upstream_id, stream->stream_id);
+
+      gst_event_unref (event);
+      event = gst_event_new_stream_start (stream_id);
+      g_free (stream_id);
+      break;
+    }
+    default:
+      break;
+  }
+
+  return gst_pad_push_event (stream->srcpad, event);
+}
+
+/* this is the final event function we receive on the internal source pad when
+ * we deal with TCP connections */
+static gboolean
+gst_rtspsrc_handle_internal_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  gboolean res;
+
+  GST_DEBUG_OBJECT (pad, "received event %s", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+    case GST_EVENT_QOS:
+    case GST_EVENT_NAVIGATION:
+    case GST_EVENT_LATENCY:
+    default:
+      gst_event_unref (event);
+      res = TRUE;
+      break;
+  }
+  return res;
+}
+
+/* this is the final query function we receive on the internal source pad when
+ * we deal with TCP connections */
+static gboolean
+gst_rtspsrc_handle_internal_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  GstRTSPSrc *src;
+  gboolean res = TRUE;
+
+  src = GST_RTSPSRC_CAST (gst_pad_get_element_private (pad));
+
+  GST_DEBUG_OBJECT (src, "pad %s:%s received query %s",
+      GST_DEBUG_PAD_NAME (pad), GST_QUERY_TYPE_NAME (query));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:
+    {
+      /* no idea */
+      break;
+    }
+    case GST_QUERY_DURATION:
+    {
+      GstFormat format;
+
+      gst_query_parse_duration (query, &format, NULL);
+
+      switch (format) {
+        case GST_FORMAT_TIME:
+          gst_query_set_duration (query, format, src->segment.duration);
+          break;
+        default:
+          res = FALSE;
+          break;
+      }
+      break;
+    }
+    case GST_QUERY_LATENCY:
+    {
+      /* we are live with a min latency of 0 and unlimited max latency, this
+       * result will be updated by the session manager if there is any. */
+      gst_query_set_latency (query, TRUE, 0, -1);
+      break;
+    }
+    default:
+      break;
+  }
+
+  return res;
+}
+
+/* this query is executed on the ghost source pad exposed on rtspsrc. */
+static gboolean
+gst_rtspsrc_handle_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  GstRTSPSrc *src;
+  gboolean res = FALSE;
+
+  src = GST_RTSPSRC_CAST (parent);
+
+  GST_DEBUG_OBJECT (src, "pad %s:%s received query %s",
+      GST_DEBUG_PAD_NAME (pad), GST_QUERY_TYPE_NAME (query));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_DURATION:
+    {
+      GstFormat format;
+
+      gst_query_parse_duration (query, &format, NULL);
+
+      switch (format) {
+        case GST_FORMAT_TIME:
+          gst_query_set_duration (query, format, src->segment.duration);
+          res = TRUE;
+          break;
+        default:
+          break;
+      }
+      break;
+    }
+    case GST_QUERY_SEEKING:
+    {
+      GstFormat format;
+
+      gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
+      if (format == GST_FORMAT_TIME) {
+        gboolean seekable =
+            src->cur_protocols != GST_RTSP_LOWER_TRANS_UDP_MCAST;
+        GstClockTime start = 0, duration = src->segment.duration;
+
+        /* seeking without duration is unlikely */
+        seekable = seekable && src->seekable >= 0.0 && src->segment.duration &&
+            GST_CLOCK_TIME_IS_VALID (src->segment.duration);
+
+        if (seekable) {
+          if (src->seekable > 0.0) {
+            start = src->last_pos - src->seekable * GST_SECOND;
+          } else {
+            /* src->seekable == 0 means that we can only seek to 0 */
+            start = 0;
+            duration = 0;
+          }
+        }
+
+        GST_LOG_OBJECT (src, "seekable : %d", seekable);
+
+        gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, start,
+            duration);
+        res = TRUE;
+      }
+      break;
+    }
+    case GST_QUERY_URI:
+    {
+      gchar *uri;
+
+      uri = gst_rtspsrc_uri_get_uri (GST_URI_HANDLER (src));
+      if (uri != NULL) {
+        gst_query_set_uri (query, uri);
+        g_free (uri);
+        res = TRUE;
+      }
+      break;
+    }
+    default:
+    {
+      GstPad *target = gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (pad));
+
+      /* forward the query to the proxy target pad */
+      if (target) {
+        res = gst_pad_query (target, query);
+        gst_object_unref (target);
+      }
+      break;
+    }
+  }
+
+  return res;
+}
+
+/* callback for RTCP messages to be sent to the server when operating in TCP
+ * mode. */
+static GstFlowReturn
+gst_rtspsrc_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstRTSPSrc *src;
+  GstRTSPStream *stream;
+  GstFlowReturn res = GST_FLOW_OK;
+  GstMapInfo map;
+  guint8 *data;
+  guint size;
+  GstRTSPResult ret;
+  GstRTSPMessage message = { 0 };
+  GstRTSPConnInfo *conninfo;
+
+  stream = (GstRTSPStream *) gst_pad_get_element_private (pad);
+  src = stream->parent;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  size = map.size;
+  data = map.data;
+
+  gst_rtsp_message_init_data (&message, stream->channel[1]);
+
+  /* lend the body data to the message */
+  gst_rtsp_message_take_body (&message, data, size);
+
+  if (stream->conninfo.connection)
+    conninfo = &stream->conninfo;
+  else
+    conninfo = &src->conninfo;
+
+  GST_DEBUG_OBJECT (src, "sending %u bytes RTCP", size);
+  ret = gst_rtspsrc_connection_send (src, conninfo, &message, NULL);
+  GST_DEBUG_OBJECT (src, "sent RTCP, %d", ret);
+
+  /* and steal it away again because we will free it when unreffing the
+   * buffer */
+  gst_rtsp_message_steal_body (&message, &data, &size);
+  gst_rtsp_message_unset (&message);
+
+  gst_buffer_unmap (buffer, &map);
+  gst_buffer_unref (buffer);
+
+  return res;
+}
+
+static GstPadProbeReturn
+pad_blocked (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
+{
+  GstRTSPSrc *src = user_data;
+
+  GST_DEBUG_OBJECT (src, "pad %s:%s blocked, activating streams",
+      GST_DEBUG_PAD_NAME (pad));
+
+  /* activate the streams */
+  GST_OBJECT_LOCK (src);
+  if (!src->need_activate)
+    goto was_ok;
+
+  src->need_activate = FALSE;
+  GST_OBJECT_UNLOCK (src);
+
+  gst_rtspsrc_activate_streams (src);
+
+  return GST_PAD_PROBE_OK;
+
+was_ok:
+  {
+    GST_OBJECT_UNLOCK (src);
+    return GST_PAD_PROBE_OK;
+  }
+}
+
+static gboolean
+copy_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
+{
+  GstPad *gpad = GST_PAD_CAST (user_data);
+
+  GST_DEBUG_OBJECT (gpad, "store sticky event %" GST_PTR_FORMAT, *event);
+  gst_pad_store_sticky_event (gpad, *event);
+
+  return TRUE;
+}
+
+/* this callback is called when the session manager generated a new src pad with
+ * payloaded RTP packets. We simply ghost the pad here. */
+static void
+new_manager_pad (GstElement * manager, GstPad * pad, GstRTSPSrc * src)
+{
+  gchar *name;
+  GstPadTemplate *template;
+  gint id, ssrc, pt;
+  GList *ostreams;
+  GstRTSPStream *stream;
+  gboolean all_added;
+  GstPad *internal_src;
+
+  GST_DEBUG_OBJECT (src, "got new manager pad %" GST_PTR_FORMAT, pad);
+
+  GST_RTSP_STATE_LOCK (src);
+  /* find stream */
+  name = gst_object_get_name (GST_OBJECT_CAST (pad));
+  if (sscanf (name, "recv_rtp_src_%u_%u_%u", &id, &ssrc, &pt) != 3)
+    goto unknown_stream;
+
+  GST_DEBUG_OBJECT (src, "stream: %u, SSRC %08x, PT %d", id, ssrc, pt);
+
+  stream = find_stream (src, &id, (gpointer) find_stream_by_id);
+  if (stream == NULL)
+    goto unknown_stream;
+
+  /* save SSRC */
+  stream->ssrc = ssrc;
+
+  /* we'll add it later see below */
+  stream->added = TRUE;
+
+  /* check if we added all streams */
+  all_added = TRUE;
+  for (ostreams = src->streams; ostreams; ostreams = g_list_next (ostreams)) {
+    GstRTSPStream *ostream = (GstRTSPStream *) ostreams->data;
+
+    GST_DEBUG_OBJECT (src, "stream %p, container %d, added %d, setup %d",
+        ostream, ostream->container, ostream->added, ostream->setup);
+
+    /* if we find a stream for which we did a setup that is not added, we
+     * need to wait some more */
+    if (ostream->setup && !ostream->added) {
+      all_added = FALSE;
+      break;
+    }
+  }
+  GST_RTSP_STATE_UNLOCK (src);
+
+  /* create a new pad we will use to stream to */
+  template = gst_static_pad_template_get (&rtptemplate);
+  stream->srcpad = gst_ghost_pad_new_from_template (name, pad, template);
+  gst_object_unref (template);
+  g_free (name);
+
+  /* We intercept and modify the stream start event */
+  internal_src =
+      GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (stream->srcpad)));
+  gst_pad_set_element_private (internal_src, stream);
+  gst_pad_set_event_function (internal_src, gst_rtspsrc_handle_src_sink_event);
+  gst_object_unref (internal_src);
+
+  gst_pad_set_event_function (stream->srcpad, gst_rtspsrc_handle_src_event);
+  gst_pad_set_query_function (stream->srcpad, gst_rtspsrc_handle_src_query);
+  gst_pad_set_active (stream->srcpad, TRUE);
+  gst_pad_sticky_events_foreach (pad, copy_sticky_events, stream->srcpad);
+  gst_element_add_pad (GST_ELEMENT_CAST (src), stream->srcpad);
+
+  if (all_added) {
+    GST_DEBUG_OBJECT (src, "We added all streams");
+    /* when we get here, all stream are added and we can fire the no-more-pads
+     * signal. */
+    gst_element_no_more_pads (GST_ELEMENT_CAST (src));
+  }
+
+  return;
+
+  /* ERRORS */
+unknown_stream:
+  {
+    GST_DEBUG_OBJECT (src, "ignoring unknown stream");
+    GST_RTSP_STATE_UNLOCK (src);
+    g_free (name);
+    return;
+  }
+}
+
+static GstCaps *
+stream_get_caps_for_pt (GstRTSPStream * stream, guint pt)
+{
+  guint i, len;
+
+  len = stream->ptmap->len;
+  for (i = 0; i < len; i++) {
+    PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i);
+    if (item->pt == pt)
+      return item->caps;
+  }
+  return NULL;
+}
+
+static GstCaps *
+request_pt_map (GstElement * manager, guint session, guint pt, GstRTSPSrc * src)
+{
+  GstRTSPStream *stream;
+  GstCaps *caps;
+
+  GST_DEBUG_OBJECT (src, "getting pt map for pt %d in session %d", pt, session);
+
+  GST_RTSP_STATE_LOCK (src);
+  stream = find_stream (src, &session, (gpointer) find_stream_by_id);
+  if (!stream)
+    goto unknown_stream;
+
+  if ((caps = stream_get_caps_for_pt (stream, pt)))
+    gst_caps_ref (caps);
+  GST_RTSP_STATE_UNLOCK (src);
+
+  return caps;
+
+unknown_stream:
+  {
+    GST_DEBUG_OBJECT (src, "unknown stream %d", session);
+    GST_RTSP_STATE_UNLOCK (src);
+    return NULL;
+  }
+}
+
+static void
+gst_rtspsrc_do_stream_eos (GstRTSPSrc * src, GstRTSPStream * stream)
+{
+  GST_DEBUG_OBJECT (src, "setting stream for session %u to EOS", stream->id);
+
+  if (stream->eos)
+    goto was_eos;
+
+  stream->eos = TRUE;
+  gst_rtspsrc_stream_push_event (src, stream, gst_event_new_eos ());
+  return;
+
+  /* ERRORS */
+was_eos:
+  {
+    GST_DEBUG_OBJECT (src, "stream for session %u was already EOS", stream->id);
+    return;
+  }
+}
+
+static void
+on_bye_ssrc (GObject * session, GObject * source, GstRTSPStream * stream)
+{
+  GstRTSPSrc *src = stream->parent;
+  guint ssrc;
+
+  g_object_get (source, "ssrc", &ssrc, NULL);
+
+  GST_DEBUG_OBJECT (src, "source %08x, stream %08x, session %u received BYE",
+      ssrc, stream->ssrc, stream->id);
+
+  if (ssrc == stream->ssrc)
+    gst_rtspsrc_do_stream_eos (src, stream);
+}
+
+static void
+on_timeout (GObject * session, GObject * source, GstRTSPStream * stream)
+{
+  GstRTSPSrc *src = stream->parent;
+  guint ssrc;
+
+  g_object_get (source, "ssrc", &ssrc, NULL);
+
+  GST_WARNING_OBJECT (src, "source %08x, stream %08x in session %u timed out",
+      ssrc, stream->ssrc, stream->id);
+
+  if (ssrc == stream->ssrc)
+    gst_rtspsrc_do_stream_eos (src, stream);
+}
+
+static void
+on_npt_stop (GstElement * rtpbin, guint session, guint ssrc, GstRTSPSrc * src)
+{
+  GstRTSPStream *stream;
+
+  GST_DEBUG_OBJECT (src, "source in session %u reached NPT stop", session);
+
+  /* get stream for session */
+  stream = find_stream (src, &session, (gpointer) find_stream_by_id);
+  if (stream) {
+    gst_rtspsrc_do_stream_eos (src, stream);
+  }
+}
+
+static void
+on_ssrc_active (GObject * session, GObject * source, GstRTSPStream * stream)
+{
+  GST_DEBUG_OBJECT (stream->parent, "source in session %u is active",
+      stream->id);
+}
+
+static void
+set_manager_buffer_mode (GstRTSPSrc * src)
+{
+  GObjectClass *klass;
+
+  if (src->manager == NULL)
+    return;
+
+  klass = G_OBJECT_GET_CLASS (G_OBJECT (src->manager));
+
+  if (!g_object_class_find_property (klass, "buffer-mode"))
+    return;
+
+  if (src->buffer_mode != BUFFER_MODE_AUTO) {
+    g_object_set (src->manager, "buffer-mode", src->buffer_mode, NULL);
+
+    return;
+  }
+
+  GST_DEBUG_OBJECT (src,
+      "auto buffering mode, have clock %" GST_PTR_FORMAT, src->provided_clock);
+
+  if (src->provided_clock) {
+    GstClock *clock = gst_element_get_clock (GST_ELEMENT_CAST (src));
+
+    if (clock == src->provided_clock) {
+      GST_DEBUG_OBJECT (src, "selected synced");
+      g_object_set (src->manager, "buffer-mode", BUFFER_MODE_SYNCED, NULL);
+
+      if (clock)
+        gst_object_unref (clock);
+
+      return;
+    }
+
+    /* Otherwise fall-through and use another buffer mode */
+    if (clock)
+      gst_object_unref (clock);
+  }
+
+  GST_DEBUG_OBJECT (src, "auto buffering mode");
+  if (src->use_buffering) {
+    GST_DEBUG_OBJECT (src, "selected buffer");
+    g_object_set (src->manager, "buffer-mode", BUFFER_MODE_BUFFER, NULL);
+  } else {
+    GST_DEBUG_OBJECT (src, "selected slave");
+    g_object_set (src->manager, "buffer-mode", BUFFER_MODE_SLAVE, NULL);
+  }
+}
+
+static GstCaps *
+request_key (GstElement * srtpdec, guint ssrc, GstRTSPStream * stream)
+{
+  guint i;
+  GstCaps *caps;
+  GstMIKEYMessage *msg = stream->mikey;
+
+  GST_DEBUG ("request key SSRC %u", ssrc);
+
+  caps = gst_caps_ref (stream_get_caps_for_pt (stream, stream->default_pt));
+  caps = gst_caps_make_writable (caps);
+
+  /* parse crypto sessions and look for the SSRC rollover counter */
+  msg = stream->mikey;
+  for (i = 0; msg && i < gst_mikey_message_get_n_cs (msg); i++) {
+    const GstMIKEYMapSRTP *map = gst_mikey_message_get_cs_srtp (msg, i);
+
+    if (ssrc == map->ssrc) {
+      gst_caps_set_simple (caps, "roc", G_TYPE_UINT, map->roc, NULL);
+      break;
+    }
+  }
+
+  return caps;
+}
+
+static GstElement *
+request_rtp_decoder (GstElement * rtpbin, guint session, GstRTSPStream * stream)
+{
+  GST_DEBUG ("decoder session %u, stream %p, %d", session, stream, stream->id);
+  if (stream->id != session)
+    return NULL;
+
+  if (stream->profile != GST_RTSP_PROFILE_SAVP &&
+      stream->profile != GST_RTSP_PROFILE_SAVPF)
+    return NULL;
+
+  if (stream->srtpdec == NULL) {
+    gchar *name;
+
+    name = g_strdup_printf ("srtpdec_%u", session);
+    stream->srtpdec = gst_element_factory_make ("srtpdec", name);
+    g_free (name);
+
+    if (stream->srtpdec == NULL) {
+      GST_ELEMENT_ERROR (stream->parent, CORE, MISSING_PLUGIN, (NULL),
+          ("no srtpdec element present!"));
+      return NULL;
+    }
+    g_signal_connect (stream->srtpdec, "request-key",
+        (GCallback) request_key, stream);
+  }
+  return gst_object_ref (stream->srtpdec);
+}
+
+static GstElement *
+request_rtcp_encoder (GstElement * rtpbin, guint session,
+    GstRTSPStream * stream)
+{
+  gchar *name;
+  GstPad *pad;
+
+  GST_DEBUG ("decoder session %u, stream %p, %d", session, stream, stream->id);
+  if (stream->id != session)
+    return NULL;
+
+  if (stream->profile != GST_RTSP_PROFILE_SAVP &&
+      stream->profile != GST_RTSP_PROFILE_SAVPF)
+    return NULL;
+
+  if (stream->srtpenc == NULL) {
+    GstStructure *s;
+
+    name = g_strdup_printf ("srtpenc_%u", session);
+    stream->srtpenc = gst_element_factory_make ("srtpenc", name);
+    g_free (name);
+
+    if (stream->srtpenc == NULL) {
+      GST_ELEMENT_ERROR (stream->parent, CORE, MISSING_PLUGIN, (NULL),
+          ("no srtpenc element present!"));
+      return NULL;
+    }
+
+    /* get RTCP crypto parameters from caps */
+    s = gst_caps_get_structure (stream->srtcpparams, 0);
+    if (s) {
+      GstBuffer *buf;
+      const gchar *str;
+      GType ciphertype, authtype;
+      GValue rtcp_cipher = G_VALUE_INIT, rtcp_auth = G_VALUE_INIT;
+
+      ciphertype = g_type_from_name ("GstSrtpCipherType");
+      authtype = g_type_from_name ("GstSrtpAuthType");
+      g_value_init (&rtcp_cipher, ciphertype);
+      g_value_init (&rtcp_auth, authtype);
+
+      str = gst_structure_get_string (s, "srtcp-cipher");
+      gst_value_deserialize (&rtcp_cipher, str);
+      str = gst_structure_get_string (s, "srtcp-auth");
+      gst_value_deserialize (&rtcp_auth, str);
+      gst_structure_get (s, "srtp-key", GST_TYPE_BUFFER, &buf, NULL);
+
+      g_object_set_property (G_OBJECT (stream->srtpenc), "rtp-cipher",
+          &rtcp_cipher);
+      g_object_set_property (G_OBJECT (stream->srtpenc), "rtp-auth",
+          &rtcp_auth);
+      g_object_set_property (G_OBJECT (stream->srtpenc), "rtcp-cipher",
+          &rtcp_cipher);
+      g_object_set_property (G_OBJECT (stream->srtpenc), "rtcp-auth",
+          &rtcp_auth);
+      g_object_set (stream->srtpenc, "key", buf, NULL);
+
+      g_value_unset (&rtcp_cipher);
+      g_value_unset (&rtcp_auth);
+      gst_buffer_unref (buf);
+    }
+  }
+  name = g_strdup_printf ("rtcp_sink_%d", session);
+  pad = gst_element_get_request_pad (stream->srtpenc, name);
+  g_free (name);
+  gst_object_unref (pad);
+
+  return gst_object_ref (stream->srtpenc);
+}
+
+static GstElement *
+request_aux_receiver (GstElement * rtpbin, guint sessid, GstRTSPSrc * src)
+{
+  GstElement *rtx, *bin;
+  GstPad *pad;
+  gchar *name;
+  GstRTSPStream *stream;
+
+  stream = find_stream (src, &sessid, (gpointer) find_stream_by_id);
+  if (!stream) {
+    GST_WARNING_OBJECT (src, "Stream %u not found", sessid);
+    return NULL;
+  }
+
+  GST_INFO_OBJECT (src, "creating retransmision receiver for session %u "
+      "with map %" GST_PTR_FORMAT, sessid, stream->rtx_pt_map);
+  bin = gst_bin_new (NULL);
+  rtx = gst_element_factory_make ("rtprtxreceive", NULL);
+  g_object_set (rtx, "payload-type-map", stream->rtx_pt_map, NULL);
+  gst_bin_add (GST_BIN (bin), rtx);
+
+  pad = gst_element_get_static_pad (rtx, "src");
+  name = g_strdup_printf ("src_%u", sessid);
+  gst_element_add_pad (bin, gst_ghost_pad_new (name, pad));
+  g_free (name);
+  gst_object_unref (pad);
+
+  pad = gst_element_get_static_pad (rtx, "sink");
+  name = g_strdup_printf ("sink_%u", sessid);
+  gst_element_add_pad (bin, gst_ghost_pad_new (name, pad));
+  g_free (name);
+  gst_object_unref (pad);
+
+  return bin;
+}
+
+static void
+add_retransmission (GstRTSPSrc * src, GstRTSPTransport * transport)
+{
+  GList *walk;
+  guint signal_id;
+  gboolean do_retransmission = FALSE;
+
+  if (transport->trans != GST_RTSP_TRANS_RTP)
+    return;
+  if (transport->profile != GST_RTSP_PROFILE_AVPF &&
+      transport->profile != GST_RTSP_PROFILE_SAVPF)
+    return;
+
+  signal_id = g_signal_lookup ("request-aux-receiver",
+      G_OBJECT_TYPE (src->manager));
+  /* there's already something connected */
+  if (g_signal_handler_find (src->manager, G_SIGNAL_MATCH_ID, signal_id, 0,
+          NULL, NULL, NULL) != 0) {
+    GST_DEBUG_OBJECT (src, "Not adding RTX AUX element as "
+        "\"request-aux-receiver\" signal is "
+        "already used by the application");
+    return;
+  }
+
+  /* build the retransmission payload type map */
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+    gboolean do_retransmission_stream = FALSE;
+    int i;
+
+    if (stream->rtx_pt_map)
+      gst_structure_free (stream->rtx_pt_map);
+    stream->rtx_pt_map = gst_structure_new_empty ("application/x-rtp-pt-map");
+
+    for (i = 0; i < stream->ptmap->len; i++) {
+      PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i);
+      GstStructure *s = gst_caps_get_structure (item->caps, 0);
+      const gchar *encoding;
+
+      /* we only care about RTX streams */
+      if ((encoding = gst_structure_get_string (s, "encoding-name"))
+          && g_strcmp0 (encoding, "RTX") == 0) {
+        const gchar *stream_pt_s;
+        gint rtx_pt;
+
+        if (gst_structure_get_int (s, "payload", &rtx_pt)
+            && (stream_pt_s = gst_structure_get_string (s, "apt"))) {
+
+          if (rtx_pt != 0) {
+            gst_structure_set (stream->rtx_pt_map, stream_pt_s, G_TYPE_UINT,
+                rtx_pt, NULL);
+            do_retransmission_stream = TRUE;
+          }
+        }
+      }
+    }
+
+    if (do_retransmission_stream) {
+      GST_DEBUG_OBJECT (src, "built retransmission payload map for stream "
+          "id %i: %" GST_PTR_FORMAT, stream->id, stream->rtx_pt_map);
+      do_retransmission = TRUE;
+    } else {
+      GST_DEBUG_OBJECT (src, "no retransmission payload map for stream "
+          "id %i", stream->id);
+      gst_structure_free (stream->rtx_pt_map);
+      stream->rtx_pt_map = NULL;
+    }
+  }
+
+  if (do_retransmission) {
+    GST_DEBUG_OBJECT (src, "Enabling retransmissions");
+
+    g_object_set (src->manager, "do-retransmission", TRUE, NULL);
+
+    /* enable RFC4588 retransmission handling by setting rtprtxreceive
+     * as the "aux" element of rtpbin */
+    g_signal_connect (src->manager, "request-aux-receiver",
+        (GCallback) request_aux_receiver, src);
+  } else {
+    GST_DEBUG_OBJECT (src,
+        "Not enabling retransmissions as no stream had a retransmission payload map");
+  }
+}
+
+/* try to get and configure a manager */
+static gboolean
+gst_rtspsrc_stream_configure_manager (GstRTSPSrc * src, GstRTSPStream * stream,
+    GstRTSPTransport * transport)
+{
+  const gchar *manager;
+  gchar *name;
+  GstStateChangeReturn ret;
+
+  /* find a manager */
+  if (gst_rtsp_transport_get_manager (transport->trans, &manager, 0) < 0)
+    goto no_manager;
+
+  if (manager) {
+    GST_DEBUG_OBJECT (src, "using manager %s", manager);
+
+    /* configure the manager */
+    if (src->manager == NULL) {
+      GObjectClass *klass;
+
+      if (!(src->manager = gst_element_factory_make (manager, "manager"))) {
+        /* fallback */
+        if (gst_rtsp_transport_get_manager (transport->trans, &manager, 1) < 0)
+          goto no_manager;
+
+        if (!manager)
+          goto use_no_manager;
+
+        if (!(src->manager = gst_element_factory_make (manager, "manager")))
+          goto manager_failed;
+      }
+
+      /* we manage this element */
+      gst_element_set_locked_state (src->manager, TRUE);
+      gst_bin_add (GST_BIN_CAST (src), src->manager);
+
+      ret = gst_element_set_state (src->manager, GST_STATE_PAUSED);
+      if (ret == GST_STATE_CHANGE_FAILURE)
+        goto start_manager_failure;
+
+      g_object_set (src->manager, "latency", src->latency, NULL);
+
+      klass = G_OBJECT_GET_CLASS (G_OBJECT (src->manager));
+
+      if (g_object_class_find_property (klass, "ntp-sync")) {
+        g_object_set (src->manager, "ntp-sync", src->ntp_sync, NULL);
+      }
+
+      if (g_object_class_find_property (klass, "rfc7273-sync")) {
+        g_object_set (src->manager, "rfc7273-sync", src->rfc7273_sync, NULL);
+      }
+
+      if (src->use_pipeline_clock) {
+        if (g_object_class_find_property (klass, "use-pipeline-clock")) {
+          g_object_set (src->manager, "use-pipeline-clock", TRUE, NULL);
+        }
+      } else {
+        if (g_object_class_find_property (klass, "ntp-time-source")) {
+          g_object_set (src->manager, "ntp-time-source", src->ntp_time_source,
+              NULL);
+        }
+      }
+
+      if (src->sdes && g_object_class_find_property (klass, "sdes")) {
+        g_object_set (src->manager, "sdes", src->sdes, NULL);
+      }
+
+      if (g_object_class_find_property (klass, "drop-on-latency")) {
+        g_object_set (src->manager, "drop-on-latency", src->drop_on_latency,
+            NULL);
+      }
+
+      if (g_object_class_find_property (klass, "max-rtcp-rtp-time-diff")) {
+        g_object_set (src->manager, "max-rtcp-rtp-time-diff",
+            src->max_rtcp_rtp_time_diff, NULL);
+      }
+
+      if (g_object_class_find_property (klass, "max-ts-offset-adjustment")) {
+        g_object_set (src->manager, "max-ts-offset-adjustment",
+            src->max_ts_offset_adjustment, NULL);
+      }
+
+      if (g_object_class_find_property (klass, "max-ts-offset")) {
+        gint64 max_ts_offset;
+
+        /* setting max-ts-offset in the manager has side effects so only do it
+         * if the value differs */
+        g_object_get (src->manager, "max-ts-offset", &max_ts_offset, NULL);
+        if (max_ts_offset != src->max_ts_offset) {
+          g_object_set (src->manager, "max-ts-offset", src->max_ts_offset,
+              NULL);
+        }
+      }
+
+      /* buffer mode pauses are handled by adding offsets to buffer times,
+       * but some depayloaders may have a hard time syncing output times
+       * with such input times, e.g. container ones, most notably ASF */
+      /* TODO alternatives are having an event that indicates these shifts,
+       * or having rtsp extensions provide suggestion on buffer mode */
+      /* valid duration implies not likely live pipeline,
+       * so slaving in jitterbuffer does not make much sense
+       * (and might mess things up due to bursts) */
+      if (GST_CLOCK_TIME_IS_VALID (src->segment.duration) &&
+          src->segment.duration && stream->container) {
+        src->use_buffering = TRUE;
+      } else {
+        src->use_buffering = FALSE;
+      }
+
+      set_manager_buffer_mode (src);
+
+      /* connect to signals */
+      GST_DEBUG_OBJECT (src, "connect to signals on session manager, stream %p",
+          stream);
+      src->manager_sig_id =
+          g_signal_connect (src->manager, "pad-added",
+          (GCallback) new_manager_pad, src);
+      src->manager_ptmap_id =
+          g_signal_connect (src->manager, "request-pt-map",
+          (GCallback) request_pt_map, src);
+
+      g_signal_connect (src->manager, "on-npt-stop", (GCallback) on_npt_stop,
+          src);
+
+      g_signal_emit (src, gst_rtspsrc_signals[SIGNAL_NEW_MANAGER], 0,
+          src->manager);
+
+      if (src->do_retransmission)
+        add_retransmission (src, transport);
+    }
+    g_signal_connect (src->manager, "request-rtp-decoder",
+        (GCallback) request_rtp_decoder, stream);
+    g_signal_connect (src->manager, "request-rtcp-decoder",
+        (GCallback) request_rtp_decoder, stream);
+    g_signal_connect (src->manager, "request-rtcp-encoder",
+        (GCallback) request_rtcp_encoder, stream);
+
+    /* we stream directly to the manager, get some pads. Each RTSP stream goes
+     * into a separate RTP session. */
+    name = g_strdup_printf ("recv_rtp_sink_%u", stream->id);
+    stream->channelpad[0] = gst_element_get_request_pad (src->manager, name);
+    g_free (name);
+    name = g_strdup_printf ("recv_rtcp_sink_%u", stream->id);
+    stream->channelpad[1] = gst_element_get_request_pad (src->manager, name);
+    g_free (name);
+
+    /* now configure the bandwidth in the manager */
+    if (g_signal_lookup ("get-internal-session",
+            G_OBJECT_TYPE (src->manager)) != 0) {
+      GObject *rtpsession;
+
+      g_signal_emit_by_name (src->manager, "get-internal-session", stream->id,
+          &rtpsession);
+      if (rtpsession) {
+        GstRTPProfile rtp_profile;
+
+        GST_INFO_OBJECT (src, "configure bandwidth in session %p", rtpsession);
+
+        stream->session = rtpsession;
+
+        if (stream->as_bandwidth != -1) {
+          GST_INFO_OBJECT (src, "setting AS: %f",
+              (gdouble) (stream->as_bandwidth * 1000));
+          g_object_set (rtpsession, "bandwidth",
+              (gdouble) (stream->as_bandwidth * 1000), NULL);
+        }
+        if (stream->rr_bandwidth != -1) {
+          GST_INFO_OBJECT (src, "setting RR: %u", stream->rr_bandwidth);
+          g_object_set (rtpsession, "rtcp-rr-bandwidth", stream->rr_bandwidth,
+              NULL);
+        }
+        if (stream->rs_bandwidth != -1) {
+          GST_INFO_OBJECT (src, "setting RS: %u", stream->rs_bandwidth);
+          g_object_set (rtpsession, "rtcp-rs-bandwidth", stream->rs_bandwidth,
+              NULL);
+        }
+
+        switch (stream->profile) {
+          case GST_RTSP_PROFILE_AVPF:
+            rtp_profile = GST_RTP_PROFILE_AVPF;
+            break;
+          case GST_RTSP_PROFILE_SAVP:
+            rtp_profile = GST_RTP_PROFILE_SAVP;
+            break;
+          case GST_RTSP_PROFILE_SAVPF:
+            rtp_profile = GST_RTP_PROFILE_SAVPF;
+            break;
+          case GST_RTSP_PROFILE_AVP:
+          default:
+            rtp_profile = GST_RTP_PROFILE_AVP;
+            break;
+        }
+
+        g_object_set (rtpsession, "rtp-profile", rtp_profile, NULL);
+
+        g_object_set (rtpsession, "probation", src->probation, NULL);
+
+        g_object_set (rtpsession, "internal-ssrc", stream->send_ssrc, NULL);
+
+        g_signal_connect (rtpsession, "on-bye-ssrc", (GCallback) on_bye_ssrc,
+            stream);
+        g_signal_connect (rtpsession, "on-bye-timeout", (GCallback) on_timeout,
+            stream);
+        g_signal_connect (rtpsession, "on-timeout", (GCallback) on_timeout,
+            stream);
+        g_signal_connect (rtpsession, "on-ssrc-active",
+            (GCallback) on_ssrc_active, stream);
+      }
+    }
+  }
+
+use_no_manager:
+  return TRUE;
+
+  /* ERRORS */
+no_manager:
+  {
+    GST_DEBUG_OBJECT (src, "cannot get a session manager");
+    return FALSE;
+  }
+manager_failed:
+  {
+    GST_DEBUG_OBJECT (src, "no session manager element %s found", manager);
+    return FALSE;
+  }
+start_manager_failure:
+  {
+    GST_DEBUG_OBJECT (src, "could not start session manager");
+    return FALSE;
+  }
+}
+
+/* free the UDP sources allocated when negotiating a transport.
+ * This function is called when the server negotiated to a transport where the
+ * UDP sources are not needed anymore, such as TCP or multicast. */
+static void
+gst_rtspsrc_stream_free_udp (GstRTSPStream * stream)
+{
+  gint i;
+
+  for (i = 0; i < 2; i++) {
+    if (stream->udpsrc[i]) {
+      GST_DEBUG ("free UDP source %d for stream %p", i, stream);
+      gst_element_set_state (stream->udpsrc[i], GST_STATE_NULL);
+      gst_object_unref (stream->udpsrc[i]);
+      stream->udpsrc[i] = NULL;
+    }
+  }
+}
+
+/* for TCP, create pads to send and receive data to and from the manager and to
+ * intercept various events and queries
+ */
+static gboolean
+gst_rtspsrc_stream_configure_tcp (GstRTSPSrc * src, GstRTSPStream * stream,
+    GstRTSPTransport * transport, GstPad ** outpad)
+{
+  gchar *name;
+  GstPadTemplate *template;
+  GstPad *pad0, *pad1;
+
+  /* configure for interleaved delivery, nothing needs to be done
+   * here, the loop function will call the chain functions of the
+   * session manager. */
+  stream->channel[0] = transport->interleaved.min;
+  stream->channel[1] = transport->interleaved.max;
+  GST_DEBUG_OBJECT (src, "stream %p on channels %d-%d", stream,
+      stream->channel[0], stream->channel[1]);
+
+  /* we can remove the allocated UDP ports now */
+  gst_rtspsrc_stream_free_udp (stream);
+
+  /* no session manager, send data to srcpad directly */
+  if (!stream->channelpad[0]) {
+    GST_DEBUG_OBJECT (src, "no manager, creating pad");
+
+    /* create a new pad we will use to stream to */
+    name = g_strdup_printf ("stream_%u", stream->id);
+    template = gst_static_pad_template_get (&rtptemplate);
+    stream->channelpad[0] = gst_pad_new_from_template (template, name);
+    gst_object_unref (template);
+    g_free (name);
+
+    /* set caps and activate */
+    gst_pad_use_fixed_caps (stream->channelpad[0]);
+    gst_pad_set_active (stream->channelpad[0], TRUE);
+
+    *outpad = gst_object_ref (stream->channelpad[0]);
+  } else {
+    GST_DEBUG_OBJECT (src, "using manager source pad");
+
+    template = gst_static_pad_template_get (&anysrctemplate);
+
+    /* allocate pads for sending the channel data into the manager */
+    pad0 = gst_pad_new_from_template (template, "internalsrc_0");
+    gst_pad_link_full (pad0, stream->channelpad[0], GST_PAD_LINK_CHECK_NOTHING);
+    gst_object_unref (stream->channelpad[0]);
+    stream->channelpad[0] = pad0;
+    gst_pad_set_event_function (pad0, gst_rtspsrc_handle_internal_src_event);
+    gst_pad_set_query_function (pad0, gst_rtspsrc_handle_internal_src_query);
+    gst_pad_set_element_private (pad0, src);
+    gst_pad_set_active (pad0, TRUE);
+
+    if (stream->channelpad[1]) {
+      /* if we have a sinkpad for the other channel, create a pad and link to the
+       * manager. */
+      pad1 = gst_pad_new_from_template (template, "internalsrc_1");
+      gst_pad_set_event_function (pad1, gst_rtspsrc_handle_internal_src_event);
+      gst_pad_link_full (pad1, stream->channelpad[1],
+          GST_PAD_LINK_CHECK_NOTHING);
+      gst_object_unref (stream->channelpad[1]);
+      stream->channelpad[1] = pad1;
+      gst_pad_set_active (pad1, TRUE);
+    }
+    gst_object_unref (template);
+  }
+  /* setup RTCP transport back to the server if we have to. */
+  if (src->manager && src->do_rtcp) {
+    GstPad *pad;
+
+    template = gst_static_pad_template_get (&anysinktemplate);
+
+    stream->rtcppad = gst_pad_new_from_template (template, "internalsink_0");
+    gst_pad_set_chain_function (stream->rtcppad, gst_rtspsrc_sink_chain);
+    gst_pad_set_element_private (stream->rtcppad, stream);
+    gst_pad_set_active (stream->rtcppad, TRUE);
+
+    /* get session RTCP pad */
+    name = g_strdup_printf ("send_rtcp_src_%u", stream->id);
+    pad = gst_element_get_request_pad (src->manager, name);
+    g_free (name);
+
+    /* and link */
+    if (pad) {
+      gst_pad_link_full (pad, stream->rtcppad, GST_PAD_LINK_CHECK_NOTHING);
+      gst_object_unref (pad);
+    }
+
+    gst_object_unref (template);
+  }
+  return TRUE;
+}
+
+static void
+gst_rtspsrc_get_transport_info (GstRTSPSrc * src, GstRTSPStream * stream,
+    GstRTSPTransport * transport, const gchar ** destination, gint * min,
+    gint * max, guint * ttl)
+{
+  if (transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
+    if (destination) {
+      if (!(*destination = transport->destination))
+        *destination = stream->destination;
+    }
+    if (min && max) {
+      /* transport first */
+      *min = transport->port.min;
+      *max = transport->port.max;
+      if (*min == -1 && *max == -1) {
+        /* then try from SDP */
+        if (stream->port != 0) {
+          *min = stream->port;
+          *max = stream->port + 1;
+        }
+      }
+    }
+
+    if (ttl) {
+      if (!(*ttl = transport->ttl))
+        *ttl = stream->ttl;
+    }
+  } else {
+    if (destination) {
+      /* first take the source, then the endpoint to figure out where to send
+       * the RTCP. */
+      if (!(*destination = transport->source)) {
+        if (src->conninfo.connection)
+          *destination = gst_rtsp_connection_get_ip (src->conninfo.connection);
+        else if (stream->conninfo.connection)
+          *destination =
+              gst_rtsp_connection_get_ip (stream->conninfo.connection);
+      }
+    }
+    if (min && max) {
+      /* for unicast we only expect the ports here */
+      *min = transport->server_port.min;
+      *max = transport->server_port.max;
+    }
+  }
+}
+
+/* For multicast create UDP sources and join the multicast group. */
+static gboolean
+gst_rtspsrc_stream_configure_mcast (GstRTSPSrc * src, GstRTSPStream * stream,
+    GstRTSPTransport * transport, GstPad ** outpad)
+{
+  gchar *uri;
+  const gchar *destination;
+  gint min, max;
+
+  GST_DEBUG_OBJECT (src, "creating UDP sources for multicast");
+
+  /* we can remove the allocated UDP ports now */
+  gst_rtspsrc_stream_free_udp (stream);
+
+  gst_rtspsrc_get_transport_info (src, stream, transport, &destination, &min,
+      &max, NULL);
+
+  /* we need a destination now */
+  if (destination == NULL)
+    goto no_destination;
+
+  /* we really need ports now or we won't be able to receive anything at all */
+  if (min == -1 && max == -1)
+    goto no_ports;
+
+  GST_DEBUG_OBJECT (src, "have destination '%s' and ports (%d)-(%d)",
+      destination, min, max);
+
+  /* creating UDP source for RTP */
+  if (min != -1) {
+    uri = g_strdup_printf ("udp://%s:%d", destination, min);
+    stream->udpsrc[0] =
+        gst_element_make_from_uri (GST_URI_SRC, uri, NULL, NULL);
+    g_free (uri);
+    if (stream->udpsrc[0] == NULL)
+      goto no_element;
+
+    /* take ownership */
+    gst_object_ref_sink (stream->udpsrc[0]);
+
+    if (src->udp_buffer_size != 0)
+      g_object_set (G_OBJECT (stream->udpsrc[0]), "buffer-size",
+          src->udp_buffer_size, NULL);
+
+    if (src->multi_iface != NULL)
+      g_object_set (G_OBJECT (stream->udpsrc[0]), "multicast-iface",
+          src->multi_iface, NULL);
+
+    /* change state */
+    gst_element_set_locked_state (stream->udpsrc[0], TRUE);
+    gst_element_set_state (stream->udpsrc[0], GST_STATE_READY);
+  }
+
+  /* creating another UDP source for RTCP */
+  if (max != -1) {
+    GstCaps *caps;
+
+    uri = g_strdup_printf ("udp://%s:%d", destination, max);
+    stream->udpsrc[1] =
+        gst_element_make_from_uri (GST_URI_SRC, uri, NULL, NULL);
+    g_free (uri);
+    if (stream->udpsrc[1] == NULL)
+      goto no_element;
+
+    if (stream->profile == GST_RTSP_PROFILE_SAVP ||
+        stream->profile == GST_RTSP_PROFILE_SAVPF)
+      caps = gst_caps_new_empty_simple ("application/x-srtcp");
+    else
+      caps = gst_caps_new_empty_simple ("application/x-rtcp");
+    g_object_set (stream->udpsrc[1], "caps", caps, NULL);
+    gst_caps_unref (caps);
+
+    /* take ownership */
+    gst_object_ref_sink (stream->udpsrc[1]);
+
+    if (src->multi_iface != NULL)
+      g_object_set (G_OBJECT (stream->udpsrc[1]), "multicast-iface",
+          src->multi_iface, NULL);
+
+    gst_element_set_state (stream->udpsrc[1], GST_STATE_READY);
+  }
+  return TRUE;
+
+  /* ERRORS */
+no_element:
+  {
+    GST_DEBUG_OBJECT (src, "no UDP source element found");
+    return FALSE;
+  }
+no_destination:
+  {
+    GST_DEBUG_OBJECT (src, "no destination found");
+    return FALSE;
+  }
+no_ports:
+  {
+    GST_DEBUG_OBJECT (src, "no ports found");
+    return FALSE;
+  }
+}
+
+/* configure the remainder of the UDP ports */
+static gboolean
+gst_rtspsrc_stream_configure_udp (GstRTSPSrc * src, GstRTSPStream * stream,
+    GstRTSPTransport * transport, GstPad ** outpad)
+{
+  /* we manage the UDP elements now. For unicast, the UDP sources where
+   * allocated in the stream when we suggested a transport. */
+  if (stream->udpsrc[0]) {
+    GstCaps *caps;
+
+    gst_element_set_locked_state (stream->udpsrc[0], TRUE);
+    gst_bin_add (GST_BIN_CAST (src), stream->udpsrc[0]);
+
+    GST_DEBUG_OBJECT (src, "setting up UDP source");
+
+    /* configure a timeout on the UDP port. When the timeout message is
+     * posted, we assume UDP transport is not possible. We reconnect using TCP
+     * if we can. */
+    g_object_set (G_OBJECT (stream->udpsrc[0]), "timeout",
+        src->udp_timeout * 1000, NULL);
+
+    if ((caps = stream_get_caps_for_pt (stream, stream->default_pt)))
+      g_object_set (stream->udpsrc[0], "caps", caps, NULL);
+
+    /* get output pad of the UDP source. */
+    *outpad = gst_element_get_static_pad (stream->udpsrc[0], "src");
+
+    /* save it so we can unblock */
+    stream->blockedpad = *outpad;
+
+    /* configure pad block on the pad. As soon as there is dataflow on the
+     * UDP source, we know that UDP is not blocked by a firewall and we can
+     * configure all the streams to let the application autoplug decoders. */
+    stream->blockid =
+        gst_pad_add_probe (stream->blockedpad,
+        GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER |
+        GST_PAD_PROBE_TYPE_BUFFER_LIST, pad_blocked, src, NULL);
+
+    if (stream->channelpad[0]) {
+      GST_DEBUG_OBJECT (src, "connecting UDP source 0 to manager");
+      /* configure for UDP delivery, we need to connect the UDP pads to
+       * the session plugin. */
+      gst_pad_link_full (*outpad, stream->channelpad[0],
+          GST_PAD_LINK_CHECK_NOTHING);
+      gst_object_unref (*outpad);
+      *outpad = NULL;
+      /* we connected to pad-added signal to get pads from the manager */
+    } else {
+      GST_DEBUG_OBJECT (src, "using UDP src pad as output");
+    }
+  }
+
+  /* RTCP port */
+  if (stream->udpsrc[1]) {
+    GstCaps *caps;
+
+    gst_element_set_locked_state (stream->udpsrc[1], TRUE);
+    gst_bin_add (GST_BIN_CAST (src), stream->udpsrc[1]);
+
+    if (stream->profile == GST_RTSP_PROFILE_SAVP ||
+        stream->profile == GST_RTSP_PROFILE_SAVPF)
+      caps = gst_caps_new_empty_simple ("application/x-srtcp");
+    else
+      caps = gst_caps_new_empty_simple ("application/x-rtcp");
+    g_object_set (stream->udpsrc[1], "caps", caps, NULL);
+    gst_caps_unref (caps);
+
+    if (stream->channelpad[1]) {
+      GstPad *pad;
+
+      GST_DEBUG_OBJECT (src, "connecting UDP source 1 to manager");
+
+      pad = gst_element_get_static_pad (stream->udpsrc[1], "src");
+      gst_pad_link_full (pad, stream->channelpad[1],
+          GST_PAD_LINK_CHECK_NOTHING);
+      gst_object_unref (pad);
+    } else {
+      /* leave unlinked */
+    }
+  }
+  return TRUE;
+}
+
+/* configure the UDP sink back to the server for status reports */
+static gboolean
+gst_rtspsrc_stream_configure_udp_sinks (GstRTSPSrc * src,
+    GstRTSPStream * stream, GstRTSPTransport * transport)
+{
+  GstPad *pad;
+  gint rtp_port, rtcp_port;
+  gboolean do_rtp, do_rtcp;
+  const gchar *destination;
+  gchar *uri, *name;
+  guint ttl = 0;
+  GSocket *socket;
+
+  /* get transport info */
+  gst_rtspsrc_get_transport_info (src, stream, transport, &destination,
+      &rtp_port, &rtcp_port, &ttl);
+
+  /* see what we need to do */
+  do_rtp = (rtp_port != -1);
+  /* it's possible that the server does not want us to send RTCP in which case
+   * the port is -1 */
+  do_rtcp = (rtcp_port != -1 && src->manager != NULL && src->do_rtcp);
+
+  /* we need a destination when we have RTP or RTCP ports */
+  if (destination == NULL && (do_rtp || do_rtcp))
+    goto no_destination;
+
+  /* try to construct the fakesrc to the RTP port of the server to open up any
+   * NAT firewalls */
+  if (do_rtp) {
+    GST_DEBUG_OBJECT (src, "configure RTP UDP sink for %s:%d", destination,
+        rtp_port);
+
+    uri = g_strdup_printf ("udp://%s:%d", destination, rtp_port);
+    stream->udpsink[0] =
+        gst_element_make_from_uri (GST_URI_SINK, uri, NULL, NULL);
+    g_free (uri);
+    if (stream->udpsink[0] == NULL)
+      goto no_sink_element;
+
+    /* don't join multicast group, we will have the source socket do that */
+    /* no sync or async state changes needed */
+    g_object_set (G_OBJECT (stream->udpsink[0]), "auto-multicast", FALSE,
+        "loop", FALSE, "sync", FALSE, "async", FALSE, NULL);
+    if (ttl > 0)
+      g_object_set (G_OBJECT (stream->udpsink[0]), "ttl", ttl, NULL);
+
+    if (stream->udpsrc[0]) {
+      /* configure socket, we give it the same UDP socket as the udpsrc for RTP
+       * so that NAT firewalls will open a hole for us */
+      g_object_get (G_OBJECT (stream->udpsrc[0]), "used-socket", &socket, NULL);
+      if (!socket)
+        goto no_socket;
+
+      GST_DEBUG_OBJECT (src, "RTP UDP src has sock %p", socket);
+      /* configure socket and make sure udpsink does not close it when shutting
+       * down, it belongs to udpsrc after all. */
+      g_object_set (G_OBJECT (stream->udpsink[0]), "socket", socket,
+          "close-socket", FALSE, NULL);
+      g_object_unref (socket);
+    }
+
+    /* the source for the dummy packets to open up NAT */
+    stream->fakesrc = gst_element_factory_make ("fakesrc", NULL);
+    if (stream->fakesrc == NULL)
+      goto no_fakesrc_element;
+
+    /* random data in 5 buffers, a size of 200 bytes should be fine */
+    g_object_set (G_OBJECT (stream->fakesrc), "filltype", 3, "num-buffers", 5,
+        "sizetype", 2, "sizemax", 200, "silent", TRUE, NULL);
+
+    /* keep everything locked */
+    gst_element_set_locked_state (stream->udpsink[0], TRUE);
+    gst_element_set_locked_state (stream->fakesrc, TRUE);
+
+    gst_object_ref (stream->udpsink[0]);
+    gst_bin_add (GST_BIN_CAST (src), stream->udpsink[0]);
+    gst_object_ref (stream->fakesrc);
+    gst_bin_add (GST_BIN_CAST (src), stream->fakesrc);
+
+    gst_element_link_pads_full (stream->fakesrc, "src", stream->udpsink[0],
+        "sink", GST_PAD_LINK_CHECK_NOTHING);
+  }
+  if (do_rtcp) {
+    GST_DEBUG_OBJECT (src, "configure RTCP UDP sink for %s:%d", destination,
+        rtcp_port);
+
+    uri = g_strdup_printf ("udp://%s:%d", destination, rtcp_port);
+    stream->udpsink[1] =
+        gst_element_make_from_uri (GST_URI_SINK, uri, NULL, NULL);
+    g_free (uri);
+    if (stream->udpsink[1] == NULL)
+      goto no_sink_element;
+
+    /* don't join multicast group, we will have the source socket do that */
+    /* no sync or async state changes needed */
+    g_object_set (G_OBJECT (stream->udpsink[1]), "auto-multicast", FALSE,
+        "loop", FALSE, "sync", FALSE, "async", FALSE, NULL);
+    if (ttl > 0)
+      g_object_set (G_OBJECT (stream->udpsink[0]), "ttl", ttl, NULL);
+
+    if (stream->udpsrc[1]) {
+      /* configure socket, we give it the same UDP socket as the udpsrc for RTCP
+       * because some servers check the port number of where it sends RTCP to identify
+       * the RTCP packets it receives */
+      g_object_get (G_OBJECT (stream->udpsrc[1]), "used-socket", &socket, NULL);
+      if (!socket)
+        goto no_socket;
+
+      GST_DEBUG_OBJECT (src, "RTCP UDP src has sock %p", socket);
+      /* configure socket and make sure udpsink does not close it when shutting
+       * down, it belongs to udpsrc after all. */
+      g_object_set (G_OBJECT (stream->udpsink[1]), "socket", socket,
+          "close-socket", FALSE, NULL);
+      g_object_unref (socket);
+    }
+
+    /* we keep this playing always */
+    gst_element_set_locked_state (stream->udpsink[1], TRUE);
+    gst_element_set_state (stream->udpsink[1], GST_STATE_PLAYING);
+
+    gst_object_ref (stream->udpsink[1]);
+    gst_bin_add (GST_BIN_CAST (src), stream->udpsink[1]);
+
+    stream->rtcppad = gst_element_get_static_pad (stream->udpsink[1], "sink");
+
+    /* get session RTCP pad */
+    name = g_strdup_printf ("send_rtcp_src_%u", stream->id);
+    pad = gst_element_get_request_pad (src->manager, name);
+    g_free (name);
+
+    /* and link */
+    if (pad) {
+      gst_pad_link_full (pad, stream->rtcppad, GST_PAD_LINK_CHECK_NOTHING);
+      gst_object_unref (pad);
+    }
+  }
+
+  return TRUE;
+
+  /* ERRORS */
+no_destination:
+  {
+    GST_ERROR_OBJECT (src, "no destination address specified");
+    return FALSE;
+  }
+no_sink_element:
+  {
+    GST_ERROR_OBJECT (src, "no UDP sink element found");
+    return FALSE;
+  }
+no_fakesrc_element:
+  {
+    GST_ERROR_OBJECT (src, "no fakesrc element found");
+    return FALSE;
+  }
+no_socket:
+  {
+    GST_ERROR_OBJECT (src, "failed to create socket");
+    return FALSE;
+  }
+}
+
+/* sets up all elements needed for streaming over the specified transport.
+ * Does not yet expose the element pads, this will be done when there is actuall
+ * dataflow detected, which might never happen when UDP is blocked in a
+ * firewall, for example.
+ */
+static gboolean
+gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
+    GstRTSPTransport * transport)
+{
+  GstRTSPSrc *src;
+  GstPad *outpad = NULL;
+  GstPadTemplate *template;
+  gchar *name;
+  const gchar *media_type;
+  guint i, len;
+
+  src = stream->parent;
+
+  GST_DEBUG_OBJECT (src, "configuring transport for stream %p", stream);
+
+  /* get the proper media type for this stream now */
+  if (gst_rtsp_transport_get_media_type (transport, &media_type) < 0)
+    goto unknown_transport;
+  if (!media_type)
+    goto unknown_transport;
+
+  /* configure the final media type */
+  GST_DEBUG_OBJECT (src, "setting media type to %s", media_type);
+
+  len = stream->ptmap->len;
+  for (i = 0; i < len; i++) {
+    GstStructure *s;
+    PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i);
+
+    if (item->caps == NULL)
+      continue;
+
+    s = gst_caps_get_structure (item->caps, 0);
+    gst_structure_set_name (s, media_type);
+    /* set ssrc if known */
+    if (transport->ssrc)
+      gst_structure_set (s, "ssrc", G_TYPE_UINT, transport->ssrc, NULL);
+  }
+
+  /* try to get and configure a manager, channelpad[0-1] will be configured with
+   * the pads for the manager, or NULL when no manager is needed. */
+  if (!gst_rtspsrc_stream_configure_manager (src, stream, transport))
+    goto no_manager;
+
+  switch (transport->lower_transport) {
+    case GST_RTSP_LOWER_TRANS_TCP:
+      if (!gst_rtspsrc_stream_configure_tcp (src, stream, transport, &outpad))
+        goto transport_failed;
+      break;
+    case GST_RTSP_LOWER_TRANS_UDP_MCAST:
+      if (!gst_rtspsrc_stream_configure_mcast (src, stream, transport, &outpad))
+        goto transport_failed;
+      /* fallthrough, the rest is the same for UDP and MCAST */
+    case GST_RTSP_LOWER_TRANS_UDP:
+      if (!gst_rtspsrc_stream_configure_udp (src, stream, transport, &outpad))
+        goto transport_failed;
+      /* configure udpsinks back to the server for RTCP messages and for the
+       * dummy RTP messages to open NAT. */
+      if (!gst_rtspsrc_stream_configure_udp_sinks (src, stream, transport))
+        goto transport_failed;
+      break;
+    default:
+      goto unknown_transport;
+  }
+
+  if (outpad) {
+    GST_DEBUG_OBJECT (src, "creating ghostpad");
+
+    gst_pad_use_fixed_caps (outpad);
+
+    /* create ghostpad, don't add just yet, this will be done when we activate
+     * the stream. */
+    name = g_strdup_printf ("stream_%u", stream->id);
+    template = gst_static_pad_template_get (&rtptemplate);
+    stream->srcpad = gst_ghost_pad_new_from_template (name, outpad, template);
+    gst_pad_set_event_function (stream->srcpad, gst_rtspsrc_handle_src_event);
+    gst_pad_set_query_function (stream->srcpad, gst_rtspsrc_handle_src_query);
+    gst_object_unref (template);
+    g_free (name);
+
+    gst_object_unref (outpad);
+  }
+  /* mark pad as ok */
+  stream->last_ret = GST_FLOW_OK;
+
+  return TRUE;
+
+  /* ERRORS */
+transport_failed:
+  {
+    GST_DEBUG_OBJECT (src, "failed to configure transport");
+    return FALSE;
+  }
+unknown_transport:
+  {
+    GST_DEBUG_OBJECT (src, "unknown transport");
+    return FALSE;
+  }
+no_manager:
+  {
+    GST_DEBUG_OBJECT (src, "cannot get a session manager");
+    return FALSE;
+  }
+}
+
+/* send a couple of dummy random packets on the receiver RTP port to the server,
+ * this should make a firewall think we initiated the data transfer and
+ * hopefully allow packets to go from the sender port to our RTP receiver port */
+static gboolean
+gst_rtspsrc_send_dummy_packets (GstRTSPSrc * src)
+{
+  GList *walk;
+
+  if (src->nat_method != GST_RTSP_NAT_DUMMY)
+    return TRUE;
+
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+
+    if (stream->fakesrc && stream->udpsink[0]) {
+      GST_DEBUG_OBJECT (src, "sending dummy packet to stream %p", stream);
+      gst_element_set_state (stream->udpsink[0], GST_STATE_NULL);
+      gst_element_set_state (stream->fakesrc, GST_STATE_NULL);
+      gst_element_set_state (stream->udpsink[0], GST_STATE_PLAYING);
+      gst_element_set_state (stream->fakesrc, GST_STATE_PLAYING);
+    }
+  }
+  return TRUE;
+}
+
+/* Adds the source pads of all configured streams to the element.
+ * This code is performed when we detected dataflow.
+ *
+ * We detect dataflow from either the _loop function or with pad probes on the
+ * udp sources.
+ */
+static gboolean
+gst_rtspsrc_activate_streams (GstRTSPSrc * src)
+{
+  GList *walk;
+
+  GST_DEBUG_OBJECT (src, "activating streams");
+
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+
+    if (stream->udpsrc[0]) {
+      /* remove timeout, we are streaming now and timeouts will be handled by
+       * the session manager and jitter buffer */
+      g_object_set (G_OBJECT (stream->udpsrc[0]), "timeout", (guint64) 0, NULL);
+    }
+    if (stream->srcpad) {
+      GST_DEBUG_OBJECT (src, "activating stream pad %p", stream);
+      gst_pad_set_active (stream->srcpad, TRUE);
+
+      /* if we don't have a session manager, set the caps now. If we have a
+       * session, we will get a notification of the pad and the caps. */
+      if (!src->manager) {
+        GstCaps *caps;
+
+        caps = stream_get_caps_for_pt (stream, stream->default_pt);
+        GST_DEBUG_OBJECT (src, "setting pad caps for stream %p", stream);
+        gst_pad_set_caps (stream->srcpad, caps);
+      }
+      /* add the pad */
+      if (!stream->added) {
+        GST_DEBUG_OBJECT (src, "adding stream pad %p", stream);
+        gst_element_add_pad (GST_ELEMENT_CAST (src), stream->srcpad);
+        stream->added = TRUE;
+      }
+    }
+  }
+
+  /* unblock all pads */
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+
+    if (stream->blockid) {
+      GST_DEBUG_OBJECT (src, "unblocking stream pad %p", stream);
+      gst_pad_remove_probe (stream->blockedpad, stream->blockid);
+      stream->blockid = 0;
+    }
+  }
+
+  return TRUE;
+}
+
+static void
+gst_rtspsrc_configure_caps (GstRTSPSrc * src, GstSegment * segment,
+    gboolean reset_manager)
+{
+  GList *walk;
+  guint64 start, stop;
+  gdouble play_speed, play_scale;
+
+  GST_DEBUG_OBJECT (src, "configuring stream caps");
+
+  start = segment->position;
+  stop = segment->duration;
+  play_speed = segment->rate;
+  play_scale = segment->applied_rate;
+
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+    guint j, len;
+
+    if (!stream->setup)
+      continue;
+
+    len = stream->ptmap->len;
+    for (j = 0; j < len; j++) {
+      GstCaps *caps;
+      PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, j);
+
+      if (item->caps == NULL)
+        continue;
+
+      caps = gst_caps_make_writable (item->caps);
+      /* update caps */
+      if (stream->timebase != -1)
+        gst_caps_set_simple (caps, "clock-base", G_TYPE_UINT,
+            (guint) stream->timebase, NULL);
+      if (stream->seqbase != -1)
+        gst_caps_set_simple (caps, "seqnum-base", G_TYPE_UINT,
+            (guint) stream->seqbase, NULL);
+      gst_caps_set_simple (caps, "npt-start", G_TYPE_UINT64, start, NULL);
+      if (stop != -1)
+        gst_caps_set_simple (caps, "npt-stop", G_TYPE_UINT64, stop, NULL);
+      gst_caps_set_simple (caps, "play-speed", G_TYPE_DOUBLE, play_speed, NULL);
+      gst_caps_set_simple (caps, "play-scale", G_TYPE_DOUBLE, play_scale, NULL);
+
+      item->caps = caps;
+      GST_DEBUG_OBJECT (src, "stream %p, pt %d, caps %" GST_PTR_FORMAT, stream,
+          item->pt, caps);
+
+      if (item->pt == stream->default_pt) {
+        if (stream->udpsrc[0])
+          g_object_set (stream->udpsrc[0], "caps", caps, NULL);
+        stream->need_caps = TRUE;
+      }
+    }
+  }
+  if (reset_manager && src->manager) {
+    GST_DEBUG_OBJECT (src, "clear session");
+    g_signal_emit_by_name (src->manager, "clear-pt-map", NULL);
+  }
+}
+
+static GstFlowReturn
+gst_rtspsrc_combine_flows (GstRTSPSrc * src, GstRTSPStream * stream,
+    GstFlowReturn ret)
+{
+  GList *streams;
+
+  /* store the value */
+  stream->last_ret = ret;
+
+  /* if it's success we can return the value right away */
+  if (ret == GST_FLOW_OK)
+    goto done;
+
+  /* any other error that is not-linked can be returned right
+   * away */
+  if (ret != GST_FLOW_NOT_LINKED)
+    goto done;
+
+  /* only return NOT_LINKED if all other pads returned NOT_LINKED */
+  for (streams = src->streams; streams; streams = g_list_next (streams)) {
+    GstRTSPStream *ostream = (GstRTSPStream *) streams->data;
+
+    ret = ostream->last_ret;
+    /* some other return value (must be SUCCESS but we can return
+     * other values as well) */
+    if (ret != GST_FLOW_NOT_LINKED)
+      goto done;
+  }
+  /* if we get here, all other pads were unlinked and we return
+   * NOT_LINKED then */
+done:
+  return ret;
+}
+
+static gboolean
+gst_rtspsrc_stream_push_event (GstRTSPSrc * src, GstRTSPStream * stream,
+    GstEvent * event)
+{
+  gboolean res = TRUE;
+
+  /* only streams that have a connection to the outside world */
+  if (!stream->setup)
+    goto done;
+
+  if (stream->udpsrc[0]) {
+    gst_event_ref (event);
+    res = gst_element_send_event (stream->udpsrc[0], event);
+  } else if (stream->channelpad[0]) {
+    gst_event_ref (event);
+    if (GST_PAD_IS_SRC (stream->channelpad[0]))
+      res = gst_pad_push_event (stream->channelpad[0], event);
+    else
+      res = gst_pad_send_event (stream->channelpad[0], event);
+  }
+
+  if (stream->udpsrc[1]) {
+    gst_event_ref (event);
+    res &= gst_element_send_event (stream->udpsrc[1], event);
+  } else if (stream->channelpad[1]) {
+    gst_event_ref (event);
+    if (GST_PAD_IS_SRC (stream->channelpad[1]))
+      res &= gst_pad_push_event (stream->channelpad[1], event);
+    else
+      res &= gst_pad_send_event (stream->channelpad[1], event);
+  }
+
+done:
+  gst_event_unref (event);
+
+  return res;
+}
+
+static gboolean
+gst_rtspsrc_push_event (GstRTSPSrc * src, GstEvent * event)
+{
+  GList *streams;
+  gboolean res = TRUE;
+
+  for (streams = src->streams; streams; streams = g_list_next (streams)) {
+    GstRTSPStream *ostream = (GstRTSPStream *) streams->data;
+
+    gst_event_ref (event);
+    res &= gst_rtspsrc_stream_push_event (src, ostream, event);
+  }
+  gst_event_unref (event);
+
+  return res;
+}
+
+static gboolean
+accept_certificate_cb (GTlsConnection * conn, GTlsCertificate * peer_cert,
+    GTlsCertificateFlags errors, gpointer user_data)
+{
+  GstRTSPSrc *src = user_data;
+  gboolean accept = FALSE;
+
+  g_signal_emit (src, gst_rtspsrc_signals[SIGNAL_ACCEPT_CERTIFICATE], 0, conn,
+      peer_cert, errors, &accept);
+
+  return accept;
+}
+
+static GstRTSPResult
+gst_rtsp_conninfo_connect (GstRTSPSrc * src, GstRTSPConnInfo * info,
+    gboolean async)
+{
+  GstRTSPResult res;
+  GstRTSPMessage response;
+  gboolean retry = FALSE;
+  memset (&response, 0, sizeof (response));
+  gst_rtsp_message_init (&response);
+  do {
+    if (info->connection == NULL) {
+      if (info->url == NULL) {
+        GST_DEBUG_OBJECT (src, "parsing uri (%s)...", info->location);
+        if ((res = gst_rtsp_url_parse (info->location, &info->url)) < 0)
+          goto parse_error;
+      }
+      /* create connection */
+      GST_DEBUG_OBJECT (src, "creating connection (%s)...", info->location);
+      if ((res = gst_rtsp_connection_create (info->url, &info->connection)) < 0)
+        goto could_not_create;
+
+      if (retry) {
+        gst_rtspsrc_setup_auth (src, &response);
+      }
+
+      g_free (info->url_str);
+      info->url_str = gst_rtsp_url_get_request_uri (info->url);
+
+      GST_DEBUG_OBJECT (src, "sanitized uri %s", info->url_str);
+
+      if (info->url->transports & GST_RTSP_LOWER_TRANS_TLS) {
+        if (!gst_rtsp_connection_set_tls_validation_flags (info->connection,
+                src->tls_validation_flags))
+          GST_WARNING_OBJECT (src, "Unable to set TLS validation flags");
+
+        if (src->tls_database)
+          gst_rtsp_connection_set_tls_database (info->connection,
+              src->tls_database);
+
+        if (src->tls_interaction)
+          gst_rtsp_connection_set_tls_interaction (info->connection,
+              src->tls_interaction);
+        gst_rtsp_connection_set_accept_certificate_func (info->connection,
+            accept_certificate_cb, src, NULL);
+      }
+
+      if (info->url->transports & GST_RTSP_LOWER_TRANS_HTTP)
+        gst_rtsp_connection_set_tunneled (info->connection, TRUE);
+
+      if (src->proxy_host) {
+        GST_DEBUG_OBJECT (src, "setting proxy %s:%d", src->proxy_host,
+            src->proxy_port);
+        gst_rtsp_connection_set_proxy (info->connection, src->proxy_host,
+            src->proxy_port);
+      }
+    }
+
+    if (!info->connected) {
+      /* connect */
+      if (async)
+        GST_ELEMENT_PROGRESS (src, CONTINUE, "connect",
+            ("Connecting to %s", info->location));
+      GST_DEBUG_OBJECT (src, "connecting (%s)...", info->location);
+      res = gst_rtsp_connection_connect_with_response (info->connection,
+          src->ptcp_timeout, &response);
+
+      if (response.type == GST_RTSP_MESSAGE_HTTP_RESPONSE &&
+          response.type_data.response.code == GST_RTSP_STS_UNAUTHORIZED) {
+        gst_rtsp_conninfo_close (src, info, TRUE);
+        if (!retry)
+          retry = TRUE;
+        else
+          retry = FALSE;        // we should not retry more than once
+      } else {
+        retry = FALSE;
+      }
+
+      if (res == GST_RTSP_OK)
+        info->connected = TRUE;
+      else if (!retry)
+        goto could_not_connect;
+    }
+  } while (!info->connected && retry);
+
+  gst_rtsp_message_unset (&response);
+  return GST_RTSP_OK;
+
+  /* ERRORS */
+parse_error:
+  {
+    GST_ERROR_OBJECT (src, "No valid RTSP URL was provided");
+    gst_rtsp_message_unset (&response);
+    return res;
+  }
+could_not_create:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+    GST_ERROR_OBJECT (src, "Could not create connection. (%s)", str);
+    g_free (str);
+    gst_rtsp_message_unset (&response);
+    return res;
+  }
+could_not_connect:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+    GST_ERROR_OBJECT (src, "Could not connect to server. (%s)", str);
+    g_free (str);
+    gst_rtsp_message_unset (&response);
+    return res;
+  }
+}
+
+static GstRTSPResult
+gst_rtsp_conninfo_close (GstRTSPSrc * src, GstRTSPConnInfo * info,
+    gboolean free)
+{
+  GST_RTSP_STATE_LOCK (src);
+  if (info->connected) {
+    GST_DEBUG_OBJECT (src, "closing connection...");
+    gst_rtsp_connection_close (info->connection);
+    info->connected = FALSE;
+  }
+  if (free && info->connection) {
+    /* free connection */
+    GST_DEBUG_OBJECT (src, "freeing connection...");
+    gst_rtsp_connection_free (info->connection);
+    info->connection = NULL;
+    info->flushing = FALSE;
+  }
+  GST_RTSP_STATE_UNLOCK (src);
+  return GST_RTSP_OK;
+}
+
+static GstRTSPResult
+gst_rtsp_conninfo_reconnect (GstRTSPSrc * src, GstRTSPConnInfo * info,
+    gboolean async)
+{
+  GstRTSPResult res;
+
+  GST_DEBUG_OBJECT (src, "reconnecting connection...");
+  gst_rtsp_conninfo_close (src, info, FALSE);
+  res = gst_rtsp_conninfo_connect (src, info, async);
+
+  return res;
+}
+
+static void
+gst_rtspsrc_connection_flush (GstRTSPSrc * src, gboolean flush)
+{
+  GList *walk;
+
+  GST_DEBUG_OBJECT (src, "set flushing %d", flush);
+  GST_RTSP_STATE_LOCK (src);
+  if (src->conninfo.connection && src->conninfo.flushing != flush) {
+    GST_DEBUG_OBJECT (src, "connection flush");
+    gst_rtsp_connection_flush (src->conninfo.connection, flush);
+    src->conninfo.flushing = flush;
+  }
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+    if (stream->conninfo.connection && stream->conninfo.flushing != flush) {
+      GST_DEBUG_OBJECT (src, "stream %p flush", stream);
+      gst_rtsp_connection_flush (stream->conninfo.connection, flush);
+      stream->conninfo.flushing = flush;
+    }
+  }
+  GST_RTSP_STATE_UNLOCK (src);
+}
+
+static GstRTSPResult
+gst_rtspsrc_init_request (GstRTSPSrc * src, GstRTSPMessage * msg,
+    GstRTSPMethod method, const gchar * uri)
+{
+  GstRTSPResult res;
+
+  res = gst_rtsp_message_init_request (msg, method, uri);
+  if (res < 0)
+    return res;
+
+  /* set user-agent */
+  if (src->user_agent)
+    gst_rtsp_message_add_header (msg, GST_RTSP_HDR_USER_AGENT, src->user_agent);
+
+  return res;
+}
+
+/* FIXME, handle server request, reply with OK, for now */
+static GstRTSPResult
+gst_rtspsrc_handle_request (GstRTSPSrc * src, GstRTSPConnInfo * conninfo,
+    GstRTSPMessage * request)
+{
+  GstRTSPMessage response = { 0 };
+  GstRTSPResult res;
+
+  GST_DEBUG_OBJECT (src, "got server request message");
+
+  DEBUG_RTSP (src, request);
+
+  res = gst_rtsp_ext_list_receive_request (src->extensions, request);
+
+  if (res == GST_RTSP_ENOTIMPL) {
+    /* default implementation, send OK */
+    GST_DEBUG_OBJECT (src, "prepare OK reply");
+    res =
+        gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, "OK",
+        request);
+    if (res < 0)
+      goto send_error;
+
+    /* let app parse and reply */
+    g_signal_emit (src, gst_rtspsrc_signals[SIGNAL_HANDLE_REQUEST],
+        0, request, &response);
+
+    DEBUG_RTSP (src, &response);
+
+    res = gst_rtspsrc_connection_send (src, conninfo, &response, NULL);
+    if (res < 0)
+      goto send_error;
+
+    gst_rtsp_message_unset (&response);
+  } else if (res == GST_RTSP_EEOF)
+    return res;
+
+  return GST_RTSP_OK;
+
+  /* ERRORS */
+send_error:
+  {
+    gst_rtsp_message_unset (&response);
+    return res;
+  }
+}
+
+/* send server keep-alive */
+static GstRTSPResult
+gst_rtspsrc_send_keep_alive (GstRTSPSrc * src)
+{
+  GstRTSPMessage request = { 0 };
+  GstRTSPResult res;
+  GstRTSPMethod method;
+  const gchar *control;
+
+  if (src->do_rtsp_keep_alive == FALSE) {
+    GST_DEBUG_OBJECT (src, "do-rtsp-keep-alive is FALSE, not sending.");
+    gst_rtsp_connection_reset_timeout (src->conninfo.connection);
+    return GST_RTSP_OK;
+  }
+
+  GST_DEBUG_OBJECT (src, "creating server keep-alive");
+
+  /* find a method to use for keep-alive */
+  if (src->methods & GST_RTSP_GET_PARAMETER)
+    method = GST_RTSP_GET_PARAMETER;
+  else
+    method = GST_RTSP_OPTIONS;
+
+  control = get_aggregate_control (src);
+  if (control == NULL)
+    goto no_control;
+
+  res = gst_rtspsrc_init_request (src, &request, method, control);
+  if (res < 0)
+    goto send_error;
+
+  request.type_data.request.version = src->version;
+
+  res = gst_rtspsrc_connection_send (src, &src->conninfo, &request, NULL);
+  if (res < 0)
+    goto send_error;
+
+  gst_rtsp_connection_reset_timeout (src->conninfo.connection);
+  gst_rtsp_message_unset (&request);
+
+  return GST_RTSP_OK;
+
+  /* ERRORS */
+no_control:
+  {
+    GST_WARNING_OBJECT (src, "no control url to send keepalive");
+    return GST_RTSP_OK;
+  }
+send_error:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+
+    gst_rtsp_message_unset (&request);
+    GST_ELEMENT_WARNING (src, RESOURCE, WRITE, (NULL),
+        ("Could not send keep-alive. (%s)", str));
+    g_free (str);
+    return res;
+  }
+}
+
+static GstFlowReturn
+gst_rtspsrc_handle_data (GstRTSPSrc * src, GstRTSPMessage * message)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  gint channel;
+  GstRTSPStream *stream;
+  GstPad *outpad = NULL;
+  guint8 *data;
+  guint size;
+  GstBuffer *buf;
+  gboolean is_rtcp;
+
+  channel = message->type_data.data.channel;
+
+  stream = find_stream (src, &channel, (gpointer) find_stream_by_channel);
+  if (!stream)
+    goto unknown_stream;
+
+  if (channel == stream->channel[0]) {
+    outpad = stream->channelpad[0];
+    is_rtcp = FALSE;
+  } else if (channel == stream->channel[1]) {
+    outpad = stream->channelpad[1];
+    is_rtcp = TRUE;
+  } else {
+    is_rtcp = FALSE;
+  }
+
+  /* take a look at the body to figure out what we have */
+  gst_rtsp_message_get_body (message, &data, &size);
+  if (size < 2)
+    goto invalid_length;
+
+  /* channels are not correct on some servers, do extra check */
+  if (data[1] >= 200 && data[1] <= 204) {
+    /* hmm RTCP message switch to the RTCP pad of the same stream. */
+    outpad = stream->channelpad[1];
+    is_rtcp = TRUE;
+  }
+
+  /* we have no clue what this is, just ignore then. */
+  if (outpad == NULL)
+    goto unknown_stream;
+
+  /* take the message body for further processing */
+  gst_rtsp_message_steal_body (message, &data, &size);
+
+  /* strip the trailing \0 */
+  size -= 1;
+
+  buf = gst_buffer_new ();
+  gst_buffer_append_memory (buf,
+      gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
+
+  /* don't need message anymore */
+  gst_rtsp_message_unset (message);
+
+  GST_DEBUG_OBJECT (src, "pushing data of size %d on channel %d", size,
+      channel);
+
+  if (src->need_activate) {
+    gchar *stream_id;
+    GstEvent *event;
+    GChecksum *cs;
+    gchar *uri;
+    GList *streams;
+    guint group_id = gst_util_group_id_next ();
+
+    /* generate an SHA256 sum of the URI */
+    cs = g_checksum_new (G_CHECKSUM_SHA256);
+    uri = src->conninfo.location;
+    g_checksum_update (cs, (const guchar *) uri, strlen (uri));
+
+    for (streams = src->streams; streams; streams = g_list_next (streams)) {
+      GstRTSPStream *ostream = (GstRTSPStream *) streams->data;
+      GstCaps *caps;
+
+      stream_id =
+          g_strdup_printf ("%s/%d", g_checksum_get_string (cs), ostream->id);
+      event = gst_event_new_stream_start (stream_id);
+      gst_event_set_group_id (event, group_id);
+
+      g_free (stream_id);
+      gst_rtspsrc_stream_push_event (src, ostream, event);
+
+      if ((caps = stream_get_caps_for_pt (ostream, ostream->default_pt))) {
+        /* only streams that have a connection to the outside world */
+        if (ostream->setup) {
+          if (ostream->udpsrc[0]) {
+            gst_element_send_event (ostream->udpsrc[0],
+                gst_event_new_caps (caps));
+          } else if (ostream->channelpad[0]) {
+            if (GST_PAD_IS_SRC (ostream->channelpad[0]))
+              gst_pad_push_event (ostream->channelpad[0],
+                  gst_event_new_caps (caps));
+            else
+              gst_pad_send_event (ostream->channelpad[0],
+                  gst_event_new_caps (caps));
+          }
+          ostream->need_caps = FALSE;
+
+          if (ostream->profile == GST_RTSP_PROFILE_SAVP ||
+              ostream->profile == GST_RTSP_PROFILE_SAVPF)
+            caps = gst_caps_new_empty_simple ("application/x-srtcp");
+          else
+            caps = gst_caps_new_empty_simple ("application/x-rtcp");
+
+          if (ostream->udpsrc[1]) {
+            gst_element_send_event (ostream->udpsrc[1],
+                gst_event_new_caps (caps));
+          } else if (ostream->channelpad[1]) {
+            if (GST_PAD_IS_SRC (ostream->channelpad[1]))
+              gst_pad_push_event (ostream->channelpad[1],
+                  gst_event_new_caps (caps));
+            else
+              gst_pad_send_event (ostream->channelpad[1],
+                  gst_event_new_caps (caps));
+          }
+
+          gst_caps_unref (caps);
+        }
+      }
+    }
+    g_checksum_free (cs);
+
+    gst_rtspsrc_activate_streams (src);
+    src->need_activate = FALSE;
+    src->need_segment = TRUE;
+  }
+
+  if (src->base_time == -1) {
+    /* Take current running_time. This timestamp will be put on
+     * the first buffer of each stream because we are a live source and so we
+     * timestamp with the running_time. When we are dealing with TCP, we also
+     * only timestamp the first buffer (using the DISCONT flag) because a server
+     * typically bursts data, for which we don't want to compensate by speeding
+     * up the media. The other timestamps will be interpollated from this one
+     * using the RTP timestamps. */
+    GST_OBJECT_LOCK (src);
+    if (GST_ELEMENT_CLOCK (src)) {
+      GstClockTime now;
+      GstClockTime base_time;
+
+      now = gst_clock_get_time (GST_ELEMENT_CLOCK (src));
+      base_time = GST_ELEMENT_CAST (src)->base_time;
+
+      src->base_time = now - base_time;
+
+      GST_DEBUG_OBJECT (src, "first buffer at time %" GST_TIME_FORMAT ", base %"
+          GST_TIME_FORMAT, GST_TIME_ARGS (now), GST_TIME_ARGS (base_time));
+    }
+    GST_OBJECT_UNLOCK (src);
+  }
+
+  /* If needed send a new segment, don't forget we are live and buffer are
+   * timestamped with running time */
+  if (src->need_segment) {
+    GstSegment segment;
+    src->need_segment = FALSE;
+    gst_segment_init (&segment, GST_FORMAT_TIME);
+    gst_rtspsrc_push_event (src, gst_event_new_segment (&segment));
+  }
+
+  if (stream->need_caps) {
+    GstCaps *caps;
+
+    if ((caps = stream_get_caps_for_pt (stream, stream->default_pt))) {
+      /* only streams that have a connection to the outside world */
+      if (stream->setup) {
+        /* Only need to update the TCP caps here, UDP is already handled */
+        if (stream->channelpad[0]) {
+          if (GST_PAD_IS_SRC (stream->channelpad[0]))
+            gst_pad_push_event (stream->channelpad[0],
+                gst_event_new_caps (caps));
+          else
+            gst_pad_send_event (stream->channelpad[0],
+                gst_event_new_caps (caps));
+        }
+        stream->need_caps = FALSE;
+      }
+    }
+
+    stream->need_caps = FALSE;
+  }
+
+  if (stream->discont && !is_rtcp) {
+    /* mark first RTP buffer as discont */
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+    stream->discont = FALSE;
+    /* first buffer gets the timestamp, other buffers are not timestamped and
+     * their presentation time will be interpollated from the rtp timestamps. */
+    GST_DEBUG_OBJECT (src, "setting timestamp %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (src->base_time));
+
+    GST_BUFFER_TIMESTAMP (buf) = src->base_time;
+  }
+
+  /* chain to the peer pad */
+  if (GST_PAD_IS_SINK (outpad))
+    ret = gst_pad_chain (outpad, buf);
+  else
+    ret = gst_pad_push (outpad, buf);
+
+  if (!is_rtcp) {
+    /* combine all stream flows for the data transport */
+    ret = gst_rtspsrc_combine_flows (src, stream, ret);
+  }
+  return ret;
+
+  /* ERRORS */
+unknown_stream:
+  {
+    GST_DEBUG_OBJECT (src, "unknown stream on channel %d, ignored", channel);
+    gst_rtsp_message_unset (message);
+    return GST_FLOW_OK;
+  }
+invalid_length:
+  {
+    GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL),
+        ("Short message received, ignoring."));
+    gst_rtsp_message_unset (message);
+    return GST_FLOW_OK;
+  }
+}
+
+static GstFlowReturn
+gst_rtspsrc_loop_interleaved (GstRTSPSrc * src)
+{
+  GstRTSPMessage message = { 0 };
+  GstRTSPResult res;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GTimeVal tv_timeout;
+
+  while (TRUE) {
+    /* get the next timeout interval */
+    gst_rtsp_connection_next_timeout (src->conninfo.connection, &tv_timeout);
+
+    /* see if the timeout period expired */
+    if ((tv_timeout.tv_sec | tv_timeout.tv_usec) == 0) {
+      GST_DEBUG_OBJECT (src, "timout, sending keep-alive");
+      /* send keep-alive, only act on interrupt, a warning will be posted for
+       * other errors. */
+      if ((res = gst_rtspsrc_send_keep_alive (src)) == GST_RTSP_EINTR)
+        goto interrupt;
+      /* get new timeout */
+      gst_rtsp_connection_next_timeout (src->conninfo.connection, &tv_timeout);
+    }
+
+    GST_DEBUG_OBJECT (src, "doing receive with timeout %ld seconds, %ld usec",
+        tv_timeout.tv_sec, tv_timeout.tv_usec);
+
+    /* protect the connection with the connection lock so that we can see when
+     * we are finished doing server communication */
+    res =
+        gst_rtspsrc_connection_receive (src, &src->conninfo,
+        &message, src->ptcp_timeout);
+
+    switch (res) {
+      case GST_RTSP_OK:
+        GST_DEBUG_OBJECT (src, "we received a server message");
+        break;
+      case GST_RTSP_EINTR:
+        /* we got interrupted this means we need to stop */
+        goto interrupt;
+      case GST_RTSP_ETIMEOUT:
+        /* no reply, send keep alive */
+        GST_DEBUG_OBJECT (src, "timeout, sending keep-alive");
+        if ((res = gst_rtspsrc_send_keep_alive (src)) == GST_RTSP_EINTR)
+          goto interrupt;
+        continue;
+      case GST_RTSP_EEOF:
+        /* go EOS when the server closed the connection */
+        goto server_eof;
+      default:
+        goto receive_error;
+    }
+
+    switch (message.type) {
+      case GST_RTSP_MESSAGE_REQUEST:
+        /* server sends us a request message, handle it */
+        res = gst_rtspsrc_handle_request (src, &src->conninfo, &message);
+        if (res == GST_RTSP_EEOF)
+          goto server_eof;
+        else if (res < 0)
+          goto handle_request_failed;
+        break;
+      case GST_RTSP_MESSAGE_RESPONSE:
+        /* we ignore response messages */
+        GST_DEBUG_OBJECT (src, "ignoring response message");
+        DEBUG_RTSP (src, &message);
+        break;
+      case GST_RTSP_MESSAGE_DATA:
+        GST_DEBUG_OBJECT (src, "got data message");
+        ret = gst_rtspsrc_handle_data (src, &message);
+        if (ret != GST_FLOW_OK)
+          goto handle_data_failed;
+        break;
+      default:
+        GST_WARNING_OBJECT (src, "ignoring unknown message type %d",
+            message.type);
+        break;
+    }
+  }
+  g_assert_not_reached ();
+
+  /* ERRORS */
+server_eof:
+  {
+    GST_DEBUG_OBJECT (src, "we got an eof from the server");
+    GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL),
+        ("The server closed the connection."));
+    src->conninfo.connected = FALSE;
+    gst_rtsp_message_unset (&message);
+    return GST_FLOW_EOS;
+  }
+interrupt:
+  {
+    gst_rtsp_message_unset (&message);
+    GST_DEBUG_OBJECT (src, "got interrupted");
+    return GST_FLOW_FLUSHING;
+  }
+receive_error:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+        ("Could not receive message. (%s)", str));
+    g_free (str);
+
+    gst_rtsp_message_unset (&message);
+    return GST_FLOW_ERROR;
+  }
+handle_request_failed:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+
+    GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
+        ("Could not handle server message. (%s)", str));
+    g_free (str);
+    gst_rtsp_message_unset (&message);
+    return GST_FLOW_ERROR;
+  }
+handle_data_failed:
+  {
+    GST_DEBUG_OBJECT (src, "could no handle data message");
+    return ret;
+  }
+}
+
+static GstFlowReturn
+gst_rtspsrc_loop_udp (GstRTSPSrc * src)
+{
+  GstRTSPResult res;
+  GstRTSPMessage message = { 0 };
+  gint retry = 0;
+
+  while (TRUE) {
+    GTimeVal tv_timeout;
+
+    /* get the next timeout interval */
+    gst_rtsp_connection_next_timeout (src->conninfo.connection, &tv_timeout);
+
+    GST_DEBUG_OBJECT (src, "doing receive with timeout %d seconds",
+        (gint) tv_timeout.tv_sec);
+
+    gst_rtsp_message_unset (&message);
+
+    /* we should continue reading the TCP socket because the server might
+     * send us requests. When the session timeout expires, we need to send a
+     * keep-alive request to keep the session open. */
+    res = gst_rtspsrc_connection_receive (src, &src->conninfo,
+        &message, &tv_timeout);
+
+    switch (res) {
+      case GST_RTSP_OK:
+        GST_DEBUG_OBJECT (src, "we received a server message");
+        break;
+      case GST_RTSP_EINTR:
+        /* we got interrupted, see what we have to do */
+        goto interrupt;
+      case GST_RTSP_ETIMEOUT:
+        /* send keep-alive, ignore the result, a warning will be posted. */
+        GST_DEBUG_OBJECT (src, "timeout, sending keep-alive");
+        if ((res = gst_rtspsrc_send_keep_alive (src)) == GST_RTSP_EINTR)
+          goto interrupt;
+        continue;
+      case GST_RTSP_EEOF:
+        /* server closed the connection. not very fatal for UDP, reconnect and
+         * see what happens. */
+        GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL),
+            ("The server closed the connection."));
+        if (src->udp_reconnect) {
+          if ((res =
+                  gst_rtsp_conninfo_reconnect (src, &src->conninfo, FALSE)) < 0)
+            goto connect_error;
+        } else {
+          goto server_eof;
+        }
+        continue;
+      case GST_RTSP_ENET:
+        GST_DEBUG_OBJECT (src, "An ethernet problem occured.");
+      default:
+        GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL),
+            ("Unhandled return value %d.", res));
+        goto receive_error;
+    }
+
+    switch (message.type) {
+      case GST_RTSP_MESSAGE_REQUEST:
+        /* server sends us a request message, handle it */
+        res = gst_rtspsrc_handle_request (src, &src->conninfo, &message);
+        if (res == GST_RTSP_EEOF)
+          goto server_eof;
+        else if (res < 0)
+          goto handle_request_failed;
+        break;
+      case GST_RTSP_MESSAGE_RESPONSE:
+        /* we ignore response and data messages */
+        GST_DEBUG_OBJECT (src, "ignoring response message");
+        DEBUG_RTSP (src, &message);
+        if (message.type_data.response.code == GST_RTSP_STS_UNAUTHORIZED) {
+          GST_DEBUG_OBJECT (src, "but is Unauthorized response ...");
+          if (gst_rtspsrc_setup_auth (src, &message) && !(retry++)) {
+            GST_DEBUG_OBJECT (src, "so retrying keep-alive");
+            if ((res = gst_rtspsrc_send_keep_alive (src)) == GST_RTSP_EINTR)
+              goto interrupt;
+          }
+        } else {
+          retry = 0;
+        }
+        break;
+      case GST_RTSP_MESSAGE_DATA:
+        /* we ignore response and data messages */
+        GST_DEBUG_OBJECT (src, "ignoring data message");
+        break;
+      default:
+        GST_WARNING_OBJECT (src, "ignoring unknown message type %d",
+            message.type);
+        break;
+    }
+  }
+  g_assert_not_reached ();
+
+  /* we get here when the connection got interrupted */
+interrupt:
+  {
+    gst_rtsp_message_unset (&message);
+    GST_DEBUG_OBJECT (src, "got interrupted");
+    return GST_FLOW_FLUSHING;
+  }
+connect_error:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+    GstFlowReturn ret;
+
+    src->conninfo.connected = FALSE;
+    if (res != GST_RTSP_EINTR) {
+      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL),
+          ("Could not connect to server. (%s)", str));
+      g_free (str);
+      ret = GST_FLOW_ERROR;
+    } else {
+      ret = GST_FLOW_FLUSHING;
+    }
+    return ret;
+  }
+receive_error:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+        ("Could not receive message. (%s)", str));
+    g_free (str);
+    return GST_FLOW_ERROR;
+  }
+handle_request_failed:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+    GstFlowReturn ret;
+
+    gst_rtsp_message_unset (&message);
+    if (res != GST_RTSP_EINTR) {
+      GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
+          ("Could not handle server message. (%s)", str));
+      g_free (str);
+      ret = GST_FLOW_ERROR;
+    } else {
+      ret = GST_FLOW_FLUSHING;
+    }
+    return ret;
+  }
+server_eof:
+  {
+    GST_DEBUG_OBJECT (src, "we got an eof from the server");
+    GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL),
+        ("The server closed the connection."));
+    src->conninfo.connected = FALSE;
+    gst_rtsp_message_unset (&message);
+    return GST_FLOW_EOS;
+  }
+}
+
+static GstRTSPResult
+gst_rtspsrc_reconnect (GstRTSPSrc * src, gboolean async)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  gboolean restart;
+
+  GST_DEBUG_OBJECT (src, "doing reconnect");
+
+  GST_OBJECT_LOCK (src);
+  /* only restart when the pads were not yet activated, else we were
+   * streaming over UDP */
+  restart = src->need_activate;
+  GST_OBJECT_UNLOCK (src);
+
+  /* no need to restart, we're done */
+  if (!restart)
+    goto done;
+
+  /* we can try only TCP now */
+  src->cur_protocols = GST_RTSP_LOWER_TRANS_TCP;
+
+  /* close and cleanup our state */
+  if ((res = gst_rtspsrc_close (src, async, FALSE)) < 0)
+    goto done;
+
+  /* see if we have TCP left to try. Also don't try TCP when we were configured
+   * with an SDP. */
+  if (!(src->protocols & GST_RTSP_LOWER_TRANS_TCP) || src->from_sdp)
+    goto no_protocols;
+
+  /* We post a warning message now to inform the user
+   * that nothing happened. It's most likely a firewall thing. */
+  GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL),
+      ("Could not receive any UDP packets for %.4f seconds, maybe your "
+          "firewall is blocking it. Retrying using a tcp connection.",
+          gst_guint64_to_gdouble (src->udp_timeout) / 1000000.0));
+
+  /* open new connection using tcp */
+  if (gst_rtspsrc_open (src, async) < 0)
+    goto open_failed;
+
+  /* start playback */
+  if (gst_rtspsrc_play (src, &src->segment, async, NULL) < 0)
+    goto play_failed;
+
+done:
+  return res;
+
+  /* ERRORS */
+no_protocols:
+  {
+    src->cur_protocols = 0;
+    /* no transport possible, post an error and stop */
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+        ("Could not receive any UDP packets for %.4f seconds, maybe your "
+            "firewall is blocking it. No other protocols to try.",
+            gst_guint64_to_gdouble (src->udp_timeout) / 1000000.0));
+    return GST_RTSP_ERROR;
+  }
+open_failed:
+  {
+    GST_DEBUG_OBJECT (src, "open failed");
+    return GST_RTSP_OK;
+  }
+play_failed:
+  {
+    GST_DEBUG_OBJECT (src, "play failed");
+    return GST_RTSP_OK;
+  }
+}
+
+static void
+gst_rtspsrc_loop_start_cmd (GstRTSPSrc * src, gint cmd)
+{
+  switch (cmd) {
+    case CMD_OPEN:
+      GST_ELEMENT_PROGRESS (src, START, "open", ("Opening Stream"));
+      break;
+    case CMD_PLAY:
+      GST_ELEMENT_PROGRESS (src, START, "request", ("Sending PLAY request"));
+      break;
+    case CMD_PAUSE:
+      GST_ELEMENT_PROGRESS (src, START, "request", ("Sending PAUSE request"));
+      break;
+    case CMD_CLOSE:
+      GST_ELEMENT_PROGRESS (src, START, "close", ("Closing Stream"));
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_rtspsrc_loop_complete_cmd (GstRTSPSrc * src, gint cmd)
+{
+  switch (cmd) {
+    case CMD_OPEN:
+      GST_ELEMENT_PROGRESS (src, COMPLETE, "open", ("Opened Stream"));
+      break;
+    case CMD_PLAY:
+      GST_ELEMENT_PROGRESS (src, COMPLETE, "request", ("Sent PLAY request"));
+      break;
+    case CMD_PAUSE:
+      GST_ELEMENT_PROGRESS (src, COMPLETE, "request", ("Sent PAUSE request"));
+      break;
+    case CMD_CLOSE:
+      GST_ELEMENT_PROGRESS (src, COMPLETE, "close", ("Closed Stream"));
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_rtspsrc_loop_cancel_cmd (GstRTSPSrc * src, gint cmd)
+{
+  switch (cmd) {
+    case CMD_OPEN:
+      GST_ELEMENT_PROGRESS (src, CANCELED, "open", ("Open canceled"));
+      break;
+    case CMD_PLAY:
+      GST_ELEMENT_PROGRESS (src, CANCELED, "request", ("PLAY canceled"));
+      break;
+    case CMD_PAUSE:
+      GST_ELEMENT_PROGRESS (src, CANCELED, "request", ("PAUSE canceled"));
+      break;
+    case CMD_CLOSE:
+      GST_ELEMENT_PROGRESS (src, CANCELED, "close", ("Close canceled"));
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_rtspsrc_loop_error_cmd (GstRTSPSrc * src, gint cmd)
+{
+  switch (cmd) {
+    case CMD_OPEN:
+      GST_ELEMENT_PROGRESS (src, ERROR, "open", ("Open failed"));
+      break;
+    case CMD_PLAY:
+      GST_ELEMENT_PROGRESS (src, ERROR, "request", ("PLAY failed"));
+      break;
+    case CMD_PAUSE:
+      GST_ELEMENT_PROGRESS (src, ERROR, "request", ("PAUSE failed"));
+      break;
+    case CMD_CLOSE:
+      GST_ELEMENT_PROGRESS (src, ERROR, "close", ("Close failed"));
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_rtspsrc_loop_end_cmd (GstRTSPSrc * src, gint cmd, GstRTSPResult ret)
+{
+  if (ret == GST_RTSP_OK)
+    gst_rtspsrc_loop_complete_cmd (src, cmd);
+  else if (ret == GST_RTSP_EINTR)
+    gst_rtspsrc_loop_cancel_cmd (src, cmd);
+  else
+    gst_rtspsrc_loop_error_cmd (src, cmd);
+}
+
+static gboolean
+gst_rtspsrc_loop_send_cmd (GstRTSPSrc * src, gint cmd, gint mask)
+{
+  gint old;
+  gboolean flushed = FALSE;
+
+  /* start new request */
+  gst_rtspsrc_loop_start_cmd (src, cmd);
+
+  GST_DEBUG_OBJECT (src, "sending cmd %s", cmd_to_string (cmd));
+
+  GST_OBJECT_LOCK (src);
+  old = src->pending_cmd;
+  if (old == CMD_RECONNECT) {
+    GST_DEBUG_OBJECT (src, "ignore, we were reconnecting");
+    cmd = CMD_RECONNECT;
+  } else if (old == CMD_CLOSE) {
+    /* our CMD_CLOSE might have interrutped CMD_LOOP. gst_rtspsrc_loop
+     * will send a CMD_WAIT which would cancel our pending CMD_CLOSE (if
+     * still pending). We just avoid it here by making sure CMD_CLOSE is
+     * still the pending command. */
+    GST_DEBUG_OBJECT (src, "ignore, we were closing");
+    cmd = CMD_CLOSE;
+  } else if (old != CMD_WAIT) {
+    src->pending_cmd = CMD_WAIT;
+    GST_OBJECT_UNLOCK (src);
+    /* cancel previous request */
+    GST_DEBUG_OBJECT (src, "cancel previous request %s", cmd_to_string (old));
+    gst_rtspsrc_loop_cancel_cmd (src, old);
+    GST_OBJECT_LOCK (src);
+  }
+  src->pending_cmd = cmd;
+  /* interrupt if allowed */
+  if (src->busy_cmd & mask) {
+    GST_DEBUG_OBJECT (src, "connection flush busy %s",
+        cmd_to_string (src->busy_cmd));
+    gst_rtspsrc_connection_flush (src, TRUE);
+    flushed = TRUE;
+  } else {
+    GST_DEBUG_OBJECT (src, "not interrupting busy cmd %s",
+        cmd_to_string (src->busy_cmd));
+  }
+  if (src->task)
+    gst_task_start (src->task);
+  GST_OBJECT_UNLOCK (src);
+
+  return flushed;
+}
+
+static gboolean
+gst_rtspsrc_loop (GstRTSPSrc * src)
+{
+  GstFlowReturn ret;
+
+  if (!src->conninfo.connection || !src->conninfo.connected)
+    goto no_connection;
+
+  if (src->interleaved)
+    ret = gst_rtspsrc_loop_interleaved (src);
+  else
+    ret = gst_rtspsrc_loop_udp (src);
+
+  if (ret != GST_FLOW_OK)
+    goto pause;
+
+  return TRUE;
+
+  /* ERRORS */
+no_connection:
+  {
+    GST_WARNING_OBJECT (src, "we are not connected");
+    ret = GST_FLOW_FLUSHING;
+    goto pause;
+  }
+pause:
+  {
+    const gchar *reason = gst_flow_get_name (ret);
+
+    GST_DEBUG_OBJECT (src, "pausing task, reason %s", reason);
+    src->running = FALSE;
+    if (ret == GST_FLOW_EOS) {
+      /* perform EOS logic */
+      if (src->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+        gst_element_post_message (GST_ELEMENT_CAST (src),
+            gst_message_new_segment_done (GST_OBJECT_CAST (src),
+                src->segment.format, src->segment.position));
+        gst_rtspsrc_push_event (src,
+            gst_event_new_segment_done (src->segment.format,
+                src->segment.position));
+      } else {
+        gst_rtspsrc_push_event (src, gst_event_new_eos ());
+      }
+    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
+      /* for fatal errors we post an error message, post the error before the
+       * EOS so the app knows about the error first. */
+      GST_ELEMENT_FLOW_ERROR (src, ret);
+      gst_rtspsrc_push_event (src, gst_event_new_eos ());
+    }
+    gst_rtspsrc_loop_send_cmd (src, CMD_WAIT, CMD_LOOP);
+    return FALSE;
+  }
+}
+
+#ifndef GST_DISABLE_GST_DEBUG
+static const gchar *
+gst_rtsp_auth_method_to_string (GstRTSPAuthMethod method)
+{
+  gint index = 0;
+
+  while (method != 0) {
+    index++;
+    method >>= 1;
+  }
+  switch (index) {
+    case 0:
+      return "None";
+    case 1:
+      return "Basic";
+    case 2:
+      return "Digest";
+  }
+
+  return "Unknown";
+}
+#endif
+
+/* Parse a WWW-Authenticate Response header and determine the
+ * available authentication methods
+ *
+ * This code should also cope with the fact that each WWW-Authenticate
+ * header can contain multiple challenge methods + tokens
+ *
+ * At the moment, for Basic auth, we just do a minimal check and don't
+ * even parse out the realm */
+static void
+gst_rtspsrc_parse_auth_hdr (GstRTSPMessage * response,
+    GstRTSPAuthMethod * methods, GstRTSPConnection * conn, gboolean * stale)
+{
+  GstRTSPAuthCredential **credentials, **credential;
+
+  g_return_if_fail (response != NULL);
+  g_return_if_fail (methods != NULL);
+  g_return_if_fail (stale != NULL);
+
+  credentials =
+      gst_rtsp_message_parse_auth_credentials (response,
+      GST_RTSP_HDR_WWW_AUTHENTICATE);
+  if (!credentials)
+    return;
+
+  credential = credentials;
+  while (*credential) {
+    if ((*credential)->scheme == GST_RTSP_AUTH_BASIC) {
+      *methods |= GST_RTSP_AUTH_BASIC;
+    } else if ((*credential)->scheme == GST_RTSP_AUTH_DIGEST) {
+      GstRTSPAuthParam **param = (*credential)->params;
+
+      *methods |= GST_RTSP_AUTH_DIGEST;
+
+      gst_rtsp_connection_clear_auth_params (conn);
+      *stale = FALSE;
+
+      while (*param) {
+        if (strcmp ((*param)->name, "stale") == 0
+            && g_ascii_strcasecmp ((*param)->value, "TRUE") == 0)
+          *stale = TRUE;
+        gst_rtsp_connection_set_auth_param (conn, (*param)->name,
+            (*param)->value);
+        param++;
+      }
+    }
+
+    credential++;
+  }
+
+  gst_rtsp_auth_credentials_free (credentials);
+}
+
+/**
+ * gst_rtspsrc_setup_auth:
+ * @src: the rtsp source
+ *
+ * Configure a username and password and auth method on the
+ * connection object based on a response we received from the
+ * peer.
+ *
+ * Currently, this requires that a username and password were supplied
+ * in the uri. In the future, they may be requested on demand by sending
+ * a message up the bus.
+ *
+ * Returns: TRUE if authentication information could be set up correctly.
+ */
+static gboolean
+gst_rtspsrc_setup_auth (GstRTSPSrc * src, GstRTSPMessage * response)
+{
+  gchar *user = NULL;
+  gchar *pass = NULL;
+  GstRTSPAuthMethod avail_methods = GST_RTSP_AUTH_NONE;
+  GstRTSPAuthMethod method;
+  GstRTSPResult auth_result;
+  GstRTSPUrl *url;
+  GstRTSPConnection *conn;
+  gboolean stale = FALSE;
+
+  conn = src->conninfo.connection;
+
+  /* Identify the available auth methods and see if any are supported */
+  gst_rtspsrc_parse_auth_hdr (response, &avail_methods, conn, &stale);
+
+  if (avail_methods == GST_RTSP_AUTH_NONE)
+    goto no_auth_available;
+
+  /* For digest auth, if the response indicates that the session
+   * data are stale, we just update them in the connection object and
+   * return TRUE to retry the request */
+  if (stale)
+    src->tried_url_auth = FALSE;
+
+  url = gst_rtsp_connection_get_url (conn);
+
+  /* Do we have username and password available? */
+  if (url != NULL && !src->tried_url_auth && url->user != NULL
+      && url->passwd != NULL) {
+    user = url->user;
+    pass = url->passwd;
+    src->tried_url_auth = TRUE;
+    GST_DEBUG_OBJECT (src,
+        "Attempting authentication using credentials from the URL");
+  } else {
+    user = src->user_id;
+    pass = src->user_pw;
+    GST_DEBUG_OBJECT (src,
+        "Attempting authentication using credentials from the properties");
+  }
+
+  /* FIXME: If the url didn't contain username and password or we tried them
+   * already, request a username and passwd from the application via some kind
+   * of credentials request message */
+
+  /* If we don't have a username and passwd at this point, bail out. */
+  if (user == NULL || pass == NULL)
+    goto no_user_pass;
+
+  /* Try to configure for each available authentication method, strongest to
+   * weakest */
+  for (method = GST_RTSP_AUTH_MAX; method != GST_RTSP_AUTH_NONE; method >>= 1) {
+    /* Check if this method is available on the server */
+    if ((method & avail_methods) == 0)
+      continue;
+
+    /* Pass the credentials to the connection to try on the next request */
+    auth_result = gst_rtsp_connection_set_auth (conn, method, user, pass);
+    /* INVAL indicates an invalid username/passwd were supplied, so we'll just
+     * ignore it and end up retrying later */
+    if (auth_result == GST_RTSP_OK || auth_result == GST_RTSP_EINVAL) {
+      GST_DEBUG_OBJECT (src, "Attempting %s authentication",
+          gst_rtsp_auth_method_to_string (method));
+      break;
+    }
+  }
+
+  if (method == GST_RTSP_AUTH_NONE)
+    goto no_auth_available;
+
+  return TRUE;
+
+no_auth_available:
+  {
+    /* Output an error indicating that we couldn't connect because there were
+     * no supported authentication protocols */
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
+        ("No supported authentication protocol was found"));
+    return FALSE;
+  }
+no_user_pass:
+  {
+    /* We don't fire an error message, we just return FALSE and let the
+     * normal NOT_AUTHORIZED error be propagated */
+    return FALSE;
+  }
+}
+
+static GstRTSPResult
+gst_rtsp_src_receive_response (GstRTSPSrc * src, GstRTSPConnInfo * conninfo,
+    GstRTSPMessage * response, GstRTSPStatusCode * code)
+{
+  GstRTSPStatusCode thecode;
+  gchar *content_base = NULL;
+  GstRTSPResult res = gst_rtspsrc_connection_receive (src, conninfo,
+      response, src->ptcp_timeout);
+
+  if (res < 0)
+    goto receive_error;
+
+  DEBUG_RTSP (src, response);
+
+  switch (response->type) {
+    case GST_RTSP_MESSAGE_REQUEST:
+      res = gst_rtspsrc_handle_request (src, conninfo, response);
+      if (res == GST_RTSP_EEOF)
+        goto server_eof;
+      else if (res < 0)
+        goto handle_request_failed;
+
+      /* Not a response, receive next message */
+      return gst_rtsp_src_receive_response (src, conninfo, response, code);
+    case GST_RTSP_MESSAGE_RESPONSE:
+      /* ok, a response is good */
+      GST_DEBUG_OBJECT (src, "received response message");
+      break;
+    case GST_RTSP_MESSAGE_DATA:
+      /* get next response */
+      GST_DEBUG_OBJECT (src, "handle data response message");
+      gst_rtspsrc_handle_data (src, response);
+
+      /* Not a response, receive next message */
+      return gst_rtsp_src_receive_response (src, conninfo, response, code);
+    default:
+      GST_WARNING_OBJECT (src, "ignoring unknown message type %d",
+          response->type);
+
+      /* Not a response, receive next message */
+      return gst_rtsp_src_receive_response (src, conninfo, response, code);
+  }
+
+  thecode = response->type_data.response.code;
+
+  GST_DEBUG_OBJECT (src, "got response message %d", thecode);
+
+  /* if the caller wanted the result code, we store it. */
+  if (code)
+    *code = thecode;
+
+  /* If the request didn't succeed, bail out before doing any more */
+  if (thecode != GST_RTSP_STS_OK)
+    return GST_RTSP_OK;
+
+  /* store new content base if any */
+  gst_rtsp_message_get_header (response, GST_RTSP_HDR_CONTENT_BASE,
+      &content_base, 0);
+  if (content_base) {
+    g_free (src->content_base);
+    src->content_base = g_strdup (content_base);
+  }
+
+  return GST_RTSP_OK;
+
+  /* ERRORS */
+receive_error:
+  {
+    switch (res) {
+      case GST_RTSP_EEOF:
+        return GST_RTSP_EEOF;
+      default:
+      {
+        gchar *str = gst_rtsp_strresult (res);
+
+        if (res != GST_RTSP_EINTR) {
+          GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+              ("Could not receive message. (%s)", str));
+        } else {
+          GST_WARNING_OBJECT (src, "receive interrupted");
+        }
+        g_free (str);
+        break;
+      }
+    }
+    return res;
+  }
+handle_request_failed:
+  {
+    /* ERROR was posted */
+    gst_rtsp_message_unset (response);
+    return res;
+  }
+server_eof:
+  {
+    GST_DEBUG_OBJECT (src, "we got an eof from the server");
+    GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL),
+        ("The server closed the connection."));
+    gst_rtsp_message_unset (response);
+    return res;
+  }
+}
+
+
+static GstRTSPResult
+gst_rtspsrc_try_send (GstRTSPSrc * src, GstRTSPConnInfo * conninfo,
+    GstRTSPMessage * request, GstRTSPMessage * response,
+    GstRTSPStatusCode * code)
+{
+  GstRTSPResult res;
+  gint try = 0;
+  gboolean allow_send = TRUE;
+
+again:
+  if (!src->short_header)
+    gst_rtsp_ext_list_before_send (src->extensions, request);
+
+  g_signal_emit (src, gst_rtspsrc_signals[SIGNAL_BEFORE_SEND], 0,
+      request, &allow_send);
+  if (!allow_send) {
+    GST_DEBUG_OBJECT (src, "skipping message, disabled by signal");
+    return GST_RTSP_OK;
+  }
+
+  GST_DEBUG_OBJECT (src, "sending message");
+
+  DEBUG_RTSP (src, request);
+
+  res = gst_rtspsrc_connection_send (src, conninfo, request, src->ptcp_timeout);
+  if (res < 0)
+    goto send_error;
+
+  gst_rtsp_connection_reset_timeout (conninfo->connection);
+  if (!response)
+    return res;
+
+  res = gst_rtsp_src_receive_response (src, conninfo, response, code);
+  if (res == GST_RTSP_EEOF) {
+    GST_WARNING_OBJECT (src, "server closed connection");
+    /* only try once after reconnect, then fallthrough and error out */
+    if ((try == 0) && !src->interleaved && src->udp_reconnect) {
+      try++;
+      /* if reconnect succeeds, try again */
+      if ((res = gst_rtsp_conninfo_reconnect (src, &src->conninfo, FALSE)) == 0)
+        goto again;
+    }
+  }
+  gst_rtsp_ext_list_after_send (src->extensions, request, response);
+
+  return res;
+
+send_error:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+
+    if (res != GST_RTSP_EINTR) {
+      GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
+          ("Could not send message. (%s)", str));
+    } else {
+      GST_WARNING_OBJECT (src, "send interrupted");
+    }
+    g_free (str);
+    return res;
+  }
+}
+
+/**
+ * gst_rtspsrc_send:
+ * @src: the rtsp source
+ * @conninfo: the connection information to send on
+ * @request: must point to a valid request
+ * @response: must point to an empty #GstRTSPMessage
+ * @code: an optional code result
+ * @versions: List of versions to try, setting it back onto the @request message
+ *            if not set, `src->version` will be used as RTSP version.
+ *
+ * send @request and retrieve the response in @response. optionally @code can be
+ * non-NULL in which case it will contain the status code of the response.
+ *
+ * If This function returns #GST_RTSP_OK, @response will contain a valid response
+ * message that should be cleaned with gst_rtsp_message_unset() after usage.
+ *
+ * If @code is NULL, this function will return #GST_RTSP_ERROR (with an invalid
+ * @response message) if the response code was not 200 (OK).
+ *
+ * If the attempt results in an authentication failure, then this will attempt
+ * to retrieve authentication credentials via gst_rtspsrc_setup_auth and retry
+ * the request.
+ *
+ * Returns: #GST_RTSP_OK if the processing was successful.
+ */
+static GstRTSPResult
+gst_rtspsrc_send (GstRTSPSrc * src, GstRTSPConnInfo * conninfo,
+    GstRTSPMessage * request, GstRTSPMessage * response,
+    GstRTSPStatusCode * code, GstRTSPVersion * versions)
+{
+  GstRTSPStatusCode int_code = GST_RTSP_STS_OK;
+  GstRTSPResult res = GST_RTSP_ERROR;
+  gint count;
+  gboolean retry;
+  GstRTSPMethod method = GST_RTSP_INVALID;
+  gint version_retry = 0;
+
+  count = 0;
+  do {
+    retry = FALSE;
+
+    /* make sure we don't loop forever */
+    if (count++ > 8)
+      break;
+
+    /* save method so we can disable it when the server complains */
+    method = request->type_data.request.method;
+
+    if (!versions)
+      request->type_data.request.version = src->version;
+
+    if ((res =
+            gst_rtspsrc_try_send (src, conninfo, request, response,
+                &int_code)) < 0)
+      goto error;
+
+    switch (int_code) {
+      case GST_RTSP_STS_UNAUTHORIZED:
+      case GST_RTSP_STS_NOT_FOUND:
+        if (gst_rtspsrc_setup_auth (src, response)) {
+          /* Try the request/response again after configuring the auth info
+           * and loop again */
+          retry = TRUE;
+        }
+        break;
+      case GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED:
+        GST_INFO_OBJECT (src, "Version %s not supported by the server",
+            versions ? gst_rtsp_version_as_text (versions[version_retry]) :
+            "unknown");
+        if (versions && versions[version_retry] != GST_RTSP_VERSION_INVALID) {
+          GST_INFO_OBJECT (src, "Unsupported version %s => trying %s",
+              gst_rtsp_version_as_text (request->type_data.request.version),
+              gst_rtsp_version_as_text (versions[version_retry]));
+          request->type_data.request.version = versions[version_retry];
+          retry = TRUE;
+          version_retry++;
+          break;
+        }
+        /* falltrough */
+      default:
+        break;
+    }
+  } while (retry == TRUE);
+
+  /* If the user requested the code, let them handle errors, otherwise
+   * post an error below */
+  if (code != NULL)
+    *code = int_code;
+  else if (int_code != GST_RTSP_STS_OK)
+    goto error_response;
+
+  return res;
+
+  /* ERRORS */
+error:
+  {
+    GST_DEBUG_OBJECT (src, "got error %d", res);
+    return res;
+  }
+error_response:
+  {
+    res = GST_RTSP_ERROR;
+
+    switch (response->type_data.response.code) {
+      case GST_RTSP_STS_NOT_FOUND:
+        RTSP_SRC_RESPONSE_ERROR (src, response, RESOURCE, NOT_FOUND,
+            "Not found");
+        break;
+      case GST_RTSP_STS_UNAUTHORIZED:
+        RTSP_SRC_RESPONSE_ERROR (src, response, RESOURCE, NOT_AUTHORIZED,
+            "Unauthorized");
+        break;
+      case GST_RTSP_STS_MOVED_PERMANENTLY:
+      case GST_RTSP_STS_MOVE_TEMPORARILY:
+      {
+        gchar *new_location;
+        GstRTSPLowerTrans transports;
+
+        GST_DEBUG_OBJECT (src, "got redirection");
+        /* if we don't have a Location Header, we must error */
+        if (gst_rtsp_message_get_header (response, GST_RTSP_HDR_LOCATION,
+                &new_location, 0) < 0)
+          break;
+
+        /* When we receive a redirect result, we go back to the INIT state after
+         * parsing the new URI. The caller should do the needed steps to issue
+         * a new setup when it detects this state change. */
+        GST_DEBUG_OBJECT (src, "redirection to %s", new_location);
+
+        /* save current transports */
+        if (src->conninfo.url)
+          transports = src->conninfo.url->transports;
+        else
+          transports = GST_RTSP_LOWER_TRANS_UNKNOWN;
+
+        gst_rtspsrc_uri_set_uri (GST_URI_HANDLER (src), new_location, NULL);
+
+        /* set old transports */
+        if (src->conninfo.url && transports != GST_RTSP_LOWER_TRANS_UNKNOWN)
+          src->conninfo.url->transports = transports;
+
+        src->need_redirect = TRUE;
+        res = GST_RTSP_OK;
+        break;
+      }
+      case GST_RTSP_STS_NOT_ACCEPTABLE:
+      case GST_RTSP_STS_NOT_IMPLEMENTED:
+      case GST_RTSP_STS_METHOD_NOT_ALLOWED:
+        GST_WARNING_OBJECT (src, "got NOT IMPLEMENTED, disable method %s",
+            gst_rtsp_method_as_text (method));
+        src->methods &= ~method;
+        res = GST_RTSP_OK;
+        break;
+      default:
+        RTSP_SRC_RESPONSE_ERROR (src, response, RESOURCE, READ,
+            "Unhandled error");
+        break;
+    }
+    /* if we return ERROR we should unset the response ourselves */
+    if (res == GST_RTSP_ERROR)
+      gst_rtsp_message_unset (response);
+
+    return res;
+  }
+}
+
+static GstRTSPResult
+gst_rtspsrc_send_cb (GstRTSPExtension * ext, GstRTSPMessage * request,
+    GstRTSPMessage * response, GstRTSPSrc * src)
+{
+  return gst_rtspsrc_send (src, &src->conninfo, request, response, NULL, NULL);
+}
+
+
+/* parse the response and collect all the supported methods. We need this
+ * information so that we don't try to send an unsupported request to the
+ * server.
+ */
+static gboolean
+gst_rtspsrc_parse_methods (GstRTSPSrc * src, GstRTSPMessage * response)
+{
+  GstRTSPHeaderField field;
+  gchar *respoptions;
+  gint indx = 0;
+
+  /* reset supported methods */
+  src->methods = 0;
+
+  /* Try Allow Header first */
+  field = GST_RTSP_HDR_ALLOW;
+  while (TRUE) {
+    respoptions = NULL;
+    gst_rtsp_message_get_header (response, field, &respoptions, indx);
+    if (!respoptions)
+      break;
+
+    src->methods |= gst_rtsp_options_from_text (respoptions);
+
+    indx++;
+  }
+
+  indx = 0;
+  field = GST_RTSP_HDR_PUBLIC;
+  while (TRUE) {
+    respoptions = NULL;
+    gst_rtsp_message_get_header (response, field, &respoptions, indx);
+    if (!respoptions)
+      break;
+
+    src->methods |= gst_rtsp_options_from_text (respoptions);
+
+    indx++;
+  }
+
+  if (src->methods == 0) {
+    /* neither Allow nor Public are required, assume the server supports
+     * at least DESCRIBE, SETUP, we always assume it supports PLAY as
+     * well. */
+    GST_DEBUG_OBJECT (src, "could not get OPTIONS");
+    src->methods = GST_RTSP_DESCRIBE | GST_RTSP_SETUP;
+  }
+  /* always assume PLAY, FIXME, extensions should be able to override
+   * this */
+  src->methods |= GST_RTSP_PLAY;
+  /* also assume it will support Range */
+  src->seekable = G_MAXFLOAT;
+
+  /* we need describe and setup */
+  if (!(src->methods & GST_RTSP_DESCRIBE))
+    goto no_describe;
+  if (!(src->methods & GST_RTSP_SETUP))
+    goto no_setup;
+
+  return TRUE;
+
+  /* ERRORS */
+no_describe:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
+        ("Server does not support DESCRIBE."));
+    return FALSE;
+  }
+no_setup:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
+        ("Server does not support SETUP."));
+    return FALSE;
+  }
+}
+
+/* masks to be kept in sync with the hardcoded protocol order of preference
+ * in code below */
+static const guint protocol_masks[] = {
+  GST_RTSP_LOWER_TRANS_UDP,
+  GST_RTSP_LOWER_TRANS_UDP_MCAST,
+  GST_RTSP_LOWER_TRANS_TCP,
+  0
+};
+
+static GstRTSPResult
+gst_rtspsrc_create_transports_string (GstRTSPSrc * src,
+    GstRTSPLowerTrans protocols, GstRTSPProfile profile, gchar ** transports)
+{
+  GstRTSPResult res;
+  GString *result;
+  gboolean add_udp_str;
+
+  *transports = NULL;
+
+  res =
+      gst_rtsp_ext_list_get_transports (src->extensions, protocols, transports);
+
+  if (res < 0)
+    goto failed;
+
+  GST_DEBUG_OBJECT (src, "got transports %s", GST_STR_NULL (*transports));
+
+  /* extension listed transports, use those */
+  if (*transports != NULL)
+    return GST_RTSP_OK;
+
+  /* it's the default */
+  add_udp_str = FALSE;
+
+  /* the default RTSP transports */
+  result = g_string_new ("RTP");
+
+  switch (profile) {
+    case GST_RTSP_PROFILE_AVP:
+      g_string_append (result, "/AVP");
+      break;
+    case GST_RTSP_PROFILE_SAVP:
+      g_string_append (result, "/SAVP");
+      break;
+    case GST_RTSP_PROFILE_AVPF:
+      g_string_append (result, "/AVPF");
+      break;
+    case GST_RTSP_PROFILE_SAVPF:
+      g_string_append (result, "/SAVPF");
+      break;
+    default:
+      break;
+  }
+
+  if (protocols & GST_RTSP_LOWER_TRANS_UDP) {
+    GST_DEBUG_OBJECT (src, "adding UDP unicast");
+    if (add_udp_str)
+      g_string_append (result, "/UDP");
+    g_string_append (result, ";unicast;client_port=%%u1-%%u2");
+  } else if (protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) {
+    GST_DEBUG_OBJECT (src, "adding UDP multicast");
+    /* we don't have to allocate any UDP ports yet, if the selected transport
+     * turns out to be multicast we can create them and join the multicast
+     * group indicated in the transport reply */
+    if (add_udp_str)
+      g_string_append (result, "/UDP");
+    g_string_append (result, ";multicast");
+    if (src->next_port_num != 0) {
+      if (src->client_port_range.max > 0 &&
+          src->next_port_num >= src->client_port_range.max)
+        goto no_ports;
+
+      g_string_append_printf (result, ";client_port=%d-%d",
+          src->next_port_num, src->next_port_num + 1);
+    }
+  } else if (protocols & GST_RTSP_LOWER_TRANS_TCP) {
+    GST_DEBUG_OBJECT (src, "adding TCP");
+
+    g_string_append (result, "/TCP;unicast;interleaved=%%i1-%%i2");
+  }
+  *transports = g_string_free (result, FALSE);
+
+  GST_DEBUG_OBJECT (src, "prepared transports %s", GST_STR_NULL (*transports));
+
+  return GST_RTSP_OK;
+
+  /* ERRORS */
+failed:
+  {
+    GST_ERROR ("extension gave error %d", res);
+    return res;
+  }
+no_ports:
+  {
+    GST_ERROR ("no more ports available");
+    return GST_RTSP_ERROR;
+  }
+}
+
+static GstRTSPResult
+gst_rtspsrc_prepare_transports (GstRTSPStream * stream, gchar ** transports,
+    gint orig_rtpport, gint orig_rtcpport)
+{
+  GstRTSPSrc *src;
+  gint nr_udp, nr_int;
+  gchar *next, *p;
+  gint rtpport = 0, rtcpport = 0;
+  GString *str;
+
+  src = stream->parent;
+
+  /* find number of placeholders first */
+  if (strstr (*transports, "%%i2"))
+    nr_int = 2;
+  else if (strstr (*transports, "%%i1"))
+    nr_int = 1;
+  else
+    nr_int = 0;
+
+  if (strstr (*transports, "%%u2"))
+    nr_udp = 2;
+  else if (strstr (*transports, "%%u1"))
+    nr_udp = 1;
+  else
+    nr_udp = 0;
+
+  if (nr_udp == 0 && nr_int == 0)
+    goto done;
+
+  if (nr_udp > 0) {
+    if (!orig_rtpport || !orig_rtcpport) {
+      if (!gst_rtspsrc_alloc_udp_ports (stream, &rtpport, &rtcpport))
+        goto failed;
+    } else {
+      rtpport = orig_rtpport;
+      rtcpport = orig_rtcpport;
+    }
+  }
+
+  str = g_string_new ("");
+  p = *transports;
+  while ((next = strstr (p, "%%"))) {
+    g_string_append_len (str, p, next - p);
+    if (next[2] == 'u') {
+      if (next[3] == '1')
+        g_string_append_printf (str, "%d", rtpport);
+      else if (next[3] == '2')
+        g_string_append_printf (str, "%d", rtcpport);
+    }
+    if (next[2] == 'i') {
+      if (next[3] == '1')
+        g_string_append_printf (str, "%d", src->free_channel);
+      else if (next[3] == '2')
+        g_string_append_printf (str, "%d", src->free_channel + 1);
+
+    }
+
+    p = next + 4;
+  }
+  if (src->version >= GST_RTSP_VERSION_2_0)
+    src->free_channel += 2;
+
+  /* append final part */
+  g_string_append (str, p);
+
+  g_free (*transports);
+  *transports = g_string_free (str, FALSE);
+
+done:
+  return GST_RTSP_OK;
+
+  /* ERRORS */
+failed:
+  {
+    GST_ERROR ("failed to allocate udp ports");
+    return GST_RTSP_ERROR;
+  }
+}
+
+static GstCaps *
+signal_get_srtcp_params (GstRTSPSrc * src, GstRTSPStream * stream)
+{
+  GstCaps *caps = NULL;
+
+  g_signal_emit (src, gst_rtspsrc_signals[SIGNAL_REQUEST_RTCP_KEY], 0,
+      stream->id, &caps);
+
+  if (caps != NULL)
+    GST_DEBUG_OBJECT (src, "SRTP parameters received");
+
+  return caps;
+}
+
+static GstCaps *
+default_srtcp_params (void)
+{
+  guint i;
+  GstCaps *caps;
+  GstBuffer *buf;
+  guint8 *key_data;
+#define KEY_SIZE 30
+  guint data_size = GST_ROUND_UP_4 (KEY_SIZE);
+
+  /* create a random key */
+  key_data = g_malloc (data_size);
+  for (i = 0; i < data_size; i += 4)
+    GST_WRITE_UINT32_BE (key_data + i, g_random_int ());
+
+  buf = gst_buffer_new_wrapped (key_data, KEY_SIZE);
+
+  caps = gst_caps_new_simple ("application/x-srtcp",
+      "srtp-key", GST_TYPE_BUFFER, buf,
+      "srtp-cipher", G_TYPE_STRING, "aes-128-icm",
+      "srtp-auth", G_TYPE_STRING, "hmac-sha1-80",
+      "srtcp-cipher", G_TYPE_STRING, "aes-128-icm",
+      "srtcp-auth", G_TYPE_STRING, "hmac-sha1-80", NULL);
+
+  gst_buffer_unref (buf);
+
+  return caps;
+}
+
+static gchar *
+gst_rtspsrc_stream_make_keymgmt (GstRTSPSrc * src, GstRTSPStream * stream)
+{
+  gchar *base64, *result = NULL;
+  GstMIKEYMessage *mikey_msg;
+
+  stream->srtcpparams = signal_get_srtcp_params (src, stream);
+  if (stream->srtcpparams == NULL)
+    stream->srtcpparams = default_srtcp_params ();
+
+  mikey_msg = gst_mikey_message_new_from_caps (stream->srtcpparams);
+  if (mikey_msg) {
+    /* add policy '0' for our SSRC */
+    gst_mikey_message_add_cs_srtp (mikey_msg, 0, stream->send_ssrc, 0);
+
+    base64 = gst_mikey_message_base64_encode (mikey_msg);
+    gst_mikey_message_unref (mikey_msg);
+
+    if (base64) {
+      result = gst_sdp_make_keymgmt (stream->conninfo.location, base64);
+      g_free (base64);
+    }
+  }
+
+  return result;
+}
+
+static GstRTSPResult
+gst_rtsp_src_setup_stream_from_response (GstRTSPSrc * src,
+    GstRTSPStream * stream, GstRTSPMessage * response,
+    GstRTSPLowerTrans * protocols, gint retry, gint * rtpport, gint * rtcpport)
+{
+  gchar *resptrans = NULL;
+  GstRTSPTransport transport = { 0 };
+
+  gst_rtsp_message_get_header (response, GST_RTSP_HDR_TRANSPORT, &resptrans, 0);
+  if (!resptrans) {
+    gst_rtspsrc_stream_free_udp (stream);
+    goto no_transport;
+  }
+
+  /* parse transport, go to next stream on parse error */
+  if (gst_rtsp_transport_parse (resptrans, &transport) != GST_RTSP_OK) {
+    GST_WARNING_OBJECT (src, "failed to parse transport %s", resptrans);
+    return GST_RTSP_ELAST;
+  }
+
+  /* update allowed transports for other streams. once the transport of
+   * one stream has been determined, we make sure that all other streams
+   * are configured in the same way */
+  switch (transport.lower_transport) {
+    case GST_RTSP_LOWER_TRANS_TCP:
+      GST_DEBUG_OBJECT (src, "stream %p as TCP interleaved", stream);
+      if (protocols)
+        *protocols = GST_RTSP_LOWER_TRANS_TCP;
+      src->interleaved = TRUE;
+      if (src->version < GST_RTSP_VERSION_2_0) {
+        /* update free channels */
+        src->free_channel = MAX (transport.interleaved.min, src->free_channel);
+        src->free_channel = MAX (transport.interleaved.max, src->free_channel);
+        src->free_channel++;
+      }
+      break;
+    case GST_RTSP_LOWER_TRANS_UDP_MCAST:
+      /* only allow multicast for other streams */
+      GST_DEBUG_OBJECT (src, "stream %p as UDP multicast", stream);
+      if (protocols)
+        *protocols = GST_RTSP_LOWER_TRANS_UDP_MCAST;
+      /* if the server selected our ports, increment our counters so that
+       * we select a new port later */
+      if (src->next_port_num == transport.port.min &&
+          src->next_port_num + 1 == transport.port.max) {
+        src->next_port_num += 2;
+      }
+      break;
+    case GST_RTSP_LOWER_TRANS_UDP:
+      /* only allow unicast for other streams */
+      GST_DEBUG_OBJECT (src, "stream %p as UDP unicast", stream);
+      if (protocols)
+        *protocols = GST_RTSP_LOWER_TRANS_UDP;
+      break;
+    default:
+      GST_DEBUG_OBJECT (src, "stream %p unknown transport %d", stream,
+          transport.lower_transport);
+      break;
+  }
+
+  if (!src->interleaved || !retry) {
+    /* now configure the stream with the selected transport */
+    if (!gst_rtspsrc_stream_configure_transport (stream, &transport)) {
+      GST_DEBUG_OBJECT (src,
+          "could not configure stream %p transport, skipping stream", stream);
+      goto done;
+    } else if (stream->udpsrc[0] && stream->udpsrc[1] && rtpport && rtcpport) {
+      /* retain the first allocated UDP port pair */
+      g_object_get (G_OBJECT (stream->udpsrc[0]), "port", rtpport, NULL);
+      g_object_get (G_OBJECT (stream->udpsrc[1]), "port", rtcpport, NULL);
+    }
+  }
+  /* we need to activate at least one stream when we detect activity */
+  src->need_activate = TRUE;
+
+  /* stream is setup now */
+  stream->setup = TRUE;
+  stream->waiting_setup_response = FALSE;
+
+  if (src->version >= GST_RTSP_VERSION_2_0) {
+    gchar *prop, *media_properties;
+    gchar **props;
+    gint i;
+
+    if (gst_rtsp_message_get_header (response, GST_RTSP_HDR_MEDIA_PROPERTIES,
+            &media_properties, 0) != GST_RTSP_OK) {
+      GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
+          ("Error: No MEDIA_PROPERTY header in a SETUP request in RTSP 2.0"
+              " - this header is mandatory."));
+
+      gst_rtsp_message_unset (response);
+      return GST_RTSP_ERROR;
+    }
+
+    props = g_strsplit (media_properties, ",", -2);
+    for (i = 0; props[i]; i++) {
+      prop = props[i];
+
+      while (*prop == ' ')
+        prop++;
+
+      if (strstr (prop, "Random-Access")) {
+        gchar **random_seekable_val = g_strsplit (prop, "=", 2);
+
+        if (!random_seekable_val[1])
+          src->seekable = G_MAXFLOAT;
+        else
+          src->seekable = g_ascii_strtod (random_seekable_val[1], NULL);
+
+        g_strfreev (random_seekable_val);
+      } else if (!g_strcmp0 (prop, "No-Seeking")) {
+        src->seekable = -1.0;
+      } else if (!g_strcmp0 (prop, "Beginning-Only")) {
+        src->seekable = 0.0;
+      }
+    }
+
+    g_strfreev (props);
+  }
+
+done:
+  /* clean up our transport struct */
+  gst_rtsp_transport_init (&transport);
+  /* clean up used RTSP messages */
+  gst_rtsp_message_unset (response);
+
+  return GST_RTSP_OK;
+
+no_transport:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+        ("Server did not select transport."));
+
+    gst_rtsp_message_unset (response);
+    return GST_RTSP_ERROR;
+  }
+}
+
+static GstRTSPResult
+gst_rtspsrc_setup_streams_end (GstRTSPSrc * src, gboolean async)
+{
+  GList *tmp;
+  GstRTSPConnInfo *conninfo;
+
+  g_assert (src->version >= GST_RTSP_VERSION_2_0);
+
+  conninfo = &src->conninfo;
+  for (tmp = src->streams; tmp; tmp = tmp->next) {
+    GstRTSPStream *stream = (GstRTSPStream *) tmp->data;
+    GstRTSPMessage response = { 0, };
+
+    if (!stream->waiting_setup_response)
+      continue;
+
+    if (!src->conninfo.connection)
+      conninfo = &((GstRTSPStream *) tmp->data)->conninfo;
+
+    gst_rtsp_src_receive_response (src, conninfo, &response, NULL);
+
+    gst_rtsp_src_setup_stream_from_response (src, stream,
+        &response, NULL, 0, NULL, NULL);
+  }
+
+  return GST_RTSP_OK;
+}
+
+/* Perform the SETUP request for all the streams.
+ *
+ * We ask the server for a specific transport, which initially includes all the
+ * ones we can support (UDP/TCP/MULTICAST). For the UDP transport we allocate
+ * two local UDP ports that we send to the server.
+ *
+ * Once the server replied with a transport, we configure the other streams
+ * with the same transport.
+ *
+ * In case setup request are not pipelined, this function will also configure the
+ * stream for the selected transport, * which basically means creating the pipeline.
+ * Otherwise, the first stream is setup right away from the reply and a
+ * CMD_FINALIZE_SETUP command is set for the stream pipelines to happen on the
+ * remaining streams from the RTSP thread.
+ */
+static GstRTSPResult
+gst_rtspsrc_setup_streams_start (GstRTSPSrc * src, gboolean async)
+{
+  GList *walk;
+  GstRTSPResult res = GST_RTSP_ERROR;
+  GstRTSPMessage request = { 0 };
+  GstRTSPMessage response = { 0 };
+  GstRTSPStream *stream = NULL;
+  GstRTSPLowerTrans protocols;
+  GstRTSPStatusCode code;
+  gboolean unsupported_real = FALSE;
+  gint rtpport, rtcpport;
+  GstRTSPUrl *url;
+  gchar *hval;
+  gchar *pipelined_request_id = NULL;
+
+  if (src->conninfo.connection) {
+    url = gst_rtsp_connection_get_url (src->conninfo.connection);
+    /* we initially allow all configured lower transports. based on the URL
+     * transports and the replies from the server we narrow them down. */
+    protocols = url->transports & src->cur_protocols;
+  } else {
+    url = NULL;
+    protocols = src->cur_protocols;
+  }
+
+  if (protocols == 0)
+    goto no_protocols;
+
+  /* reset some state */
+  src->free_channel = 0;
+  src->interleaved = FALSE;
+  src->need_activate = FALSE;
+  /* keep track of next port number, 0 is random */
+  src->next_port_num = src->client_port_range.min;
+  rtpport = rtcpport = 0;
+
+  if (G_UNLIKELY (src->streams == NULL))
+    goto no_streams;
+
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPConnInfo *conninfo;
+    gchar *transports;
+    gint retry = 0;
+    guint mask = 0;
+    gboolean selected;
+    GstCaps *caps;
+
+    stream = (GstRTSPStream *) walk->data;
+
+    caps = stream_get_caps_for_pt (stream, stream->default_pt);
+    if (caps == NULL) {
+      GST_DEBUG_OBJECT (src, "skipping stream %p, no caps", stream);
+      continue;
+    }
+
+    if (stream->skipped) {
+      GST_DEBUG_OBJECT (src, "skipping stream %p", stream);
+      continue;
+    }
+
+    /* see if we need to configure this stream */
+    if (!gst_rtsp_ext_list_configure_stream (src->extensions, caps)) {
+      GST_DEBUG_OBJECT (src, "skipping stream %p, disabled by extension",
+          stream);
+      continue;
+    }
+
+    g_signal_emit (src, gst_rtspsrc_signals[SIGNAL_SELECT_STREAM], 0,
+        stream->id, caps, &selected);
+    if (!selected) {
+      GST_DEBUG_OBJECT (src, "skipping stream %p, disabled by signal", stream);
+      continue;
+    }
+
+    /* merge/overwrite global caps */
+    if (caps) {
+      guint j, num;
+      GstStructure *s;
+
+      s = gst_caps_get_structure (caps, 0);
+
+      num = gst_structure_n_fields (src->props);
+      for (j = 0; j < num; j++) {
+        const gchar *name;
+        const GValue *val;
+
+        name = gst_structure_nth_field_name (src->props, j);
+        val = gst_structure_get_value (src->props, name);
+        gst_structure_set_value (s, name, val);
+
+        GST_DEBUG_OBJECT (src, "copied %s", name);
+      }
+    }
+
+    /* skip setup if we have no URL for it */
+    if (stream->conninfo.location == NULL) {
+      GST_DEBUG_OBJECT (src, "skipping stream %p, no setup", stream);
+      continue;
+    }
+
+    if (src->conninfo.connection == NULL) {
+      if (!gst_rtsp_conninfo_connect (src, &stream->conninfo, async)) {
+        GST_DEBUG_OBJECT (src, "skipping stream %p, failed to connect", stream);
+        continue;
+      }
+      conninfo = &stream->conninfo;
+    } else {
+      conninfo = &src->conninfo;
+    }
+    GST_DEBUG_OBJECT (src, "doing setup of stream %p with %s", stream,
+        stream->conninfo.location);
+
+    /* if we have a multicast connection, only suggest multicast from now on */
+    if (stream->is_multicast)
+      protocols &= GST_RTSP_LOWER_TRANS_UDP_MCAST;
+
+  next_protocol:
+    /* first selectable protocol */
+    while (protocol_masks[mask] && !(protocols & protocol_masks[mask]))
+      mask++;
+    if (!protocol_masks[mask])
+      goto no_protocols;
+
+  retry:
+    GST_DEBUG_OBJECT (src, "protocols = 0x%x, protocol mask = 0x%x", protocols,
+        protocol_masks[mask]);
+    /* create a string with first transport in line */
+    transports = NULL;
+    res = gst_rtspsrc_create_transports_string (src,
+        protocols & protocol_masks[mask], stream->profile, &transports);
+    if (res < 0 || transports == NULL)
+      goto setup_transport_failed;
+
+    if (strlen (transports) == 0) {
+      g_free (transports);
+      GST_DEBUG_OBJECT (src, "no transports found");
+      mask++;
+      goto next_protocol;
+    }
+
+    GST_DEBUG_OBJECT (src, "replace ports in %s", GST_STR_NULL (transports));
+
+    /* replace placeholders with real values, this function will optionally
+     * allocate UDP ports and other info needed to execute the setup request */
+    res = gst_rtspsrc_prepare_transports (stream, &transports,
+        retry > 0 ? rtpport : 0, retry > 0 ? rtcpport : 0);
+    if (res < 0) {
+      g_free (transports);
+      goto setup_transport_failed;
+    }
+
+    GST_DEBUG_OBJECT (src, "transport is now %s", GST_STR_NULL (transports));
+    /* create SETUP request */
+    res =
+        gst_rtspsrc_init_request (src, &request, GST_RTSP_SETUP,
+        stream->conninfo.location);
+    if (res < 0) {
+      g_free (transports);
+      goto create_request_failed;
+    }
+
+    if (src->version >= GST_RTSP_VERSION_2_0) {
+      if (!pipelined_request_id)
+        pipelined_request_id = g_strdup_printf ("%d",
+            g_random_int_range (0, G_MAXINT32));
+
+      gst_rtsp_message_add_header (&request, GST_RTSP_HDR_PIPELINED_REQUESTS,
+          pipelined_request_id);
+      gst_rtsp_message_add_header (&request, GST_RTSP_HDR_ACCEPT_RANGES,
+          "npt, clock, smpte, clock");
+    }
+
+    /* select transport */
+    gst_rtsp_message_take_header (&request, GST_RTSP_HDR_TRANSPORT, transports);
+
+    /* set up keys */
+    if (stream->profile == GST_RTSP_PROFILE_SAVP ||
+        stream->profile == GST_RTSP_PROFILE_SAVPF) {
+      hval = gst_rtspsrc_stream_make_keymgmt (src, stream);
+      gst_rtsp_message_take_header (&request, GST_RTSP_HDR_KEYMGMT, hval);
+    }
+
+    /* if the user wants a non default RTP packet size we add the blocksize
+     * parameter */
+    if (src->rtp_blocksize > 0) {
+      hval = g_strdup_printf ("%d", src->rtp_blocksize);
+      gst_rtsp_message_take_header (&request, GST_RTSP_HDR_BLOCKSIZE, hval);
+    }
+
+    if (async)
+      GST_ELEMENT_PROGRESS (src, CONTINUE, "request", ("SETUP stream %d",
+              stream->id));
+
+    /* handle the code ourselves */
+    res =
+        gst_rtspsrc_send (src, conninfo, &request,
+        pipelined_request_id ? NULL : &response, &code, NULL);
+    if (res < 0)
+      goto send_error;
+
+    switch (code) {
+      case GST_RTSP_STS_OK:
+        break;
+      case GST_RTSP_STS_UNSUPPORTED_TRANSPORT:
+        gst_rtsp_message_unset (&request);
+        gst_rtsp_message_unset (&response);
+        /* cleanup of leftover transport */
+        gst_rtspsrc_stream_free_udp (stream);
+        /* MS WMServer RTSP MUST use same UDP pair in all SETUP requests;
+         * we might be in this case */
+        if (stream->container && rtpport && rtcpport && !retry) {
+          GST_DEBUG_OBJECT (src, "retrying with original port pair %u-%u",
+              rtpport, rtcpport);
+          retry++;
+          goto retry;
+        }
+        /* this transport did not go down well, but we may have others to try
+         * that we did not send yet, try those and only give up then
+         * but not without checking for lost cause/extension so we can
+         * post a nicer/more useful error message later */
+        if (!unsupported_real)
+          unsupported_real = stream->is_real;
+        /* select next available protocol, give up on this stream if none */
+        mask++;
+        while (protocol_masks[mask] && !(protocols & protocol_masks[mask]))
+          mask++;
+        if (!protocol_masks[mask] || unsupported_real)
+          continue;
+        else
+          goto retry;
+      default:
+        /* cleanup of leftover transport and move to the next stream */
+        gst_rtspsrc_stream_free_udp (stream);
+        goto response_error;
+    }
+
+
+    if (!pipelined_request_id) {
+      /* parse response transport */
+      res = gst_rtsp_src_setup_stream_from_response (src, stream,
+          &response, &protocols, retry, &rtpport, &rtcpport);
+      switch (res) {
+        case GST_RTSP_ERROR:
+          goto cleanup_error;
+        case GST_RTSP_ELAST:
+          goto retry;
+        default:
+          break;
+      }
+    } else {
+      stream->waiting_setup_response = TRUE;
+      /* we need to activate at least one stream when we detect activity */
+      src->need_activate = TRUE;
+    }
+
+    {
+      GList *skip = walk;
+
+      while (TRUE) {
+        GstRTSPStream *sskip;
+
+        skip = g_list_next (skip);
+        if (skip == NULL)
+          break;
+
+        sskip = (GstRTSPStream *) skip->data;
+
+        /* skip all streams with the same control url */
+        if (g_str_equal (stream->conninfo.location, sskip->conninfo.location)) {
+          GST_DEBUG_OBJECT (src, "found stream %p with same control %s",
+              sskip, sskip->conninfo.location);
+          sskip->skipped = TRUE;
+        }
+      }
+    }
+    gst_rtsp_message_unset (&request);
+  }
+
+  if (pipelined_request_id) {
+    gst_rtspsrc_setup_streams_end (src, TRUE);
+  }
+
+  /* store the transport protocol that was configured */
+  src->cur_protocols = protocols;
+
+  gst_rtsp_ext_list_stream_select (src->extensions, url);
+
+  if (pipelined_request_id)
+    g_free (pipelined_request_id);
+
+  /* if there is nothing to activate, error out */
+  if (!src->need_activate)
+    goto nothing_to_activate;
+
+  return res;
+
+  /* ERRORS */
+no_protocols:
+  {
+    /* no transport possible, post an error and stop */
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+        ("Could not connect to server, no protocols left"));
+    return GST_RTSP_ERROR;
+  }
+no_streams:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+        ("SDP contains no streams"));
+    return GST_RTSP_ERROR;
+  }
+create_request_failed:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+
+    GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL),
+        ("Could not create request. (%s)", str));
+    g_free (str);
+    goto cleanup_error;
+  }
+setup_transport_failed:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+        ("Could not setup transport."));
+    res = GST_RTSP_ERROR;
+    goto cleanup_error;
+  }
+response_error:
+  {
+    const gchar *str = gst_rtsp_status_as_text (code);
+
+    GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
+        ("Error (%d): %s", code, GST_STR_NULL (str)));
+    res = GST_RTSP_ERROR;
+    goto cleanup_error;
+  }
+send_error:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+
+    if (res != GST_RTSP_EINTR) {
+      GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
+          ("Could not send message. (%s)", str));
+    } else {
+      GST_WARNING_OBJECT (src, "send interrupted");
+    }
+    g_free (str);
+    goto cleanup_error;
+  }
+nothing_to_activate:
+  {
+    /* none of the available error codes is really right .. */
+    if (unsupported_real) {
+      GST_ELEMENT_ERROR (src, STREAM, CODEC_NOT_FOUND,
+          (_("No supported stream was found. You might need to install a "
+                  "GStreamer RTSP extension plugin for Real media streams.")),
+          (NULL));
+    } else {
+      GST_ELEMENT_ERROR (src, STREAM, CODEC_NOT_FOUND,
+          (_("No supported stream was found. You might need to allow "
+                  "more transport protocols or may otherwise be missing "
+                  "the right GStreamer RTSP extension plugin.")), (NULL));
+    }
+    return GST_RTSP_ERROR;
+  }
+cleanup_error:
+  {
+    if (pipelined_request_id)
+      g_free (pipelined_request_id);
+    gst_rtsp_message_unset (&request);
+    gst_rtsp_message_unset (&response);
+    return res;
+  }
+}
+
+static gboolean
+gst_rtspsrc_parse_range (GstRTSPSrc * src, const gchar * range,
+    GstSegment * segment)
+{
+  gint64 seconds;
+  GstRTSPTimeRange *therange;
+
+  if (src->range)
+    gst_rtsp_range_free (src->range);
+
+  if (gst_rtsp_range_parse (range, &therange) == GST_RTSP_OK) {
+    GST_DEBUG_OBJECT (src, "parsed range %s", range);
+    src->range = therange;
+  } else {
+    GST_DEBUG_OBJECT (src, "failed to parse range %s", range);
+    src->range = NULL;
+    gst_segment_init (segment, GST_FORMAT_TIME);
+    return FALSE;
+  }
+
+  GST_DEBUG_OBJECT (src, "range: type %d, min %f - type %d,  max %f ",
+      therange->min.type, therange->min.seconds, therange->max.type,
+      therange->max.seconds);
+
+  if (therange->min.type == GST_RTSP_TIME_NOW)
+    seconds = 0;
+  else if (therange->min.type == GST_RTSP_TIME_END)
+    seconds = 0;
+  else
+    seconds = therange->min.seconds * GST_SECOND;
+
+  GST_DEBUG_OBJECT (src, "range: min %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (seconds));
+
+  /* we need to start playback without clipping from the position reported by
+   * the server */
+  segment->start = seconds;
+  segment->position = seconds;
+
+  if (therange->max.type == GST_RTSP_TIME_NOW)
+    seconds = -1;
+  else if (therange->max.type == GST_RTSP_TIME_END)
+    seconds = -1;
+  else
+    seconds = therange->max.seconds * GST_SECOND;
+
+  GST_DEBUG_OBJECT (src, "range: max %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (seconds));
+
+  /* live (WMS) server might send overflowed large max as its idea of infinity,
+   * compensate to prevent problems later on */
+  if (seconds != -1 && seconds < 0) {
+    seconds = -1;
+    GST_DEBUG_OBJECT (src, "insane range, set to NONE");
+  }
+
+  /* live (WMS) might send min == max, which is not worth recording */
+  if (segment->duration == -1 && seconds == segment->start)
+    seconds = -1;
+
+  /* don't change duration with unknown value, we might have a valid value
+   * there that we want to keep. */
+  if (seconds != -1)
+    segment->duration = seconds;
+
+  return TRUE;
+}
+
+/* Parse clock profived by the server with following syntax:
+ *
+ * "GstNetTimeProvider <wrapped-clock> <server-IP:port> <clock-time>"
+ */
+static gboolean
+gst_rtspsrc_parse_gst_clock (GstRTSPSrc * src, const gchar * gstclock)
+{
+  gboolean res = FALSE;
+
+  if (g_str_has_prefix (gstclock, "GstNetTimeProvider ")) {
+    gchar **fields = NULL, **parts = NULL;
+    gchar *remote_ip, *str;
+    gint port;
+    GstClockTime base_time;
+    GstClock *netclock;
+
+    fields = g_strsplit (gstclock, " ", 0);
+
+    /* wrapped clock, not very interesting for now */
+    if (fields[1] == NULL)
+      goto cleanup;
+
+    /* remote IP address and port */
+    if ((str = fields[2]) == NULL)
+      goto cleanup;
+
+    parts = g_strsplit (str, ":", 0);
+
+    if ((remote_ip = parts[0]) == NULL)
+      goto cleanup;
+
+    if ((str = parts[1]) == NULL)
+      goto cleanup;
+
+    port = atoi (str);
+    if (port == 0)
+      goto cleanup;
+
+    /* base-time */
+    if ((str = fields[3]) == NULL)
+      goto cleanup;
+
+    base_time = g_ascii_strtoull (str, NULL, 10);
+
+    netclock =
+        gst_net_client_clock_new ((gchar *) "GstRTSPClock", remote_ip, port,
+        base_time);
+
+    if (src->provided_clock)
+      gst_object_unref (src->provided_clock);
+    src->provided_clock = netclock;
+
+    gst_element_post_message (GST_ELEMENT_CAST (src),
+        gst_message_new_clock_provide (GST_OBJECT_CAST (src),
+            src->provided_clock, TRUE));
+
+    res = TRUE;
+  cleanup:
+    g_strfreev (fields);
+    g_strfreev (parts);
+  }
+  return res;
+}
+
+/* must be called with the RTSP state lock */
+static GstRTSPResult
+gst_rtspsrc_open_from_sdp (GstRTSPSrc * src, GstSDPMessage * sdp,
+    gboolean async)
+{
+  GstRTSPResult res;
+  gint i, n_streams;
+
+  /* prepare global stream caps properties */
+  if (src->props)
+    gst_structure_remove_all_fields (src->props);
+  else
+    src->props = gst_structure_new_empty ("RTSPProperties");
+
+  DEBUG_SDP (src, sdp);
+
+  gst_rtsp_ext_list_parse_sdp (src->extensions, sdp, src->props);
+
+  /* let the app inspect and change the SDP */
+  g_signal_emit (src, gst_rtspsrc_signals[SIGNAL_ON_SDP], 0, sdp);
+
+  gst_segment_init (&src->segment, GST_FORMAT_TIME);
+
+  /* parse range for duration reporting. */
+  {
+    const gchar *range;
+
+    for (i = 0;; i++) {
+      range = gst_sdp_message_get_attribute_val_n (sdp, "range", i);
+      if (range == NULL)
+        break;
+
+      /* keep track of the range and configure it in the segment */
+      if (gst_rtspsrc_parse_range (src, range, &src->segment))
+        break;
+    }
+  }
+  /* parse clock information. This is GStreamer specific, a server can tell the
+   * client what clock it is using and wrap that in a network clock. The
+   * advantage of that is that we can slave to it. */
+  {
+    const gchar *gstclock;
+
+    for (i = 0;; i++) {
+      gstclock = gst_sdp_message_get_attribute_val_n (sdp, "x-gst-clock", i);
+      if (gstclock == NULL)
+        break;
+
+      /* parse the clock and expose it in the provide_clock method */
+      if (gst_rtspsrc_parse_gst_clock (src, gstclock))
+        break;
+    }
+  }
+  /* try to find a global control attribute. Note that a '*' means that we should
+   * do aggregate control with the current url (so we don't do anything and
+   * leave the current connection as is) */
+  {
+    const gchar *control;
+
+    for (i = 0;; i++) {
+      control = gst_sdp_message_get_attribute_val_n (sdp, "control", i);
+      if (control == NULL)
+        break;
+
+      /* only take fully qualified urls */
+      if (g_str_has_prefix (control, "rtsp://"))
+        break;
+    }
+    if (control) {
+      g_free (src->conninfo.location);
+      src->conninfo.location = g_strdup (control);
+      /* make a connection for this, if there was a connection already, nothing
+       * happens. */
+      if (gst_rtsp_conninfo_connect (src, &src->conninfo, async) < 0) {
+        GST_ERROR_OBJECT (src, "could not connect");
+      }
+    }
+    /* we need to keep the control url separate from the connection url because
+     * the rules for constructing the media control url need it */
+    g_free (src->control);
+    src->control = g_strdup (control);
+  }
+
+  /* create streams */
+  n_streams = gst_sdp_message_medias_len (sdp);
+  for (i = 0; i < n_streams; i++) {
+    gst_rtspsrc_create_stream (src, sdp, i, n_streams);
+  }
+
+  src->state = GST_RTSP_STATE_INIT;
+
+  /* setup streams */
+  if ((res = gst_rtspsrc_setup_streams_start (src, async)) < 0)
+    goto setup_failed;
+
+  /* reset our state */
+  src->need_range = TRUE;
+  src->skip = FALSE;
+
+  src->state = GST_RTSP_STATE_READY;
+
+  return res;
+
+  /* ERRORS */
+setup_failed:
+  {
+    GST_ERROR_OBJECT (src, "setup failed");
+    gst_rtspsrc_cleanup (src);
+    return res;
+  }
+}
+
+static GstRTSPResult
+gst_rtspsrc_retrieve_sdp (GstRTSPSrc * src, GstSDPMessage ** sdp,
+    gboolean async)
+{
+  GstRTSPResult res;
+  GstRTSPMessage request = { 0 };
+  GstRTSPMessage response = { 0 };
+  guint8 *data;
+  guint size;
+  gchar *respcont = NULL;
+  GstRTSPVersion versions[] =
+      { GST_RTSP_VERSION_2_0, GST_RTSP_VERSION_INVALID };
+
+  src->version = src->default_version;
+  if (src->default_version == GST_RTSP_VERSION_2_0) {
+    versions[0] = GST_RTSP_VERSION_1_0;
+  }
+
+restart:
+  src->need_redirect = FALSE;
+
+  /* can't continue without a valid url */
+  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)
+    goto connect_failed;
+
+  /* create OPTIONS */
+  GST_DEBUG_OBJECT (src, "create options... (%s)", async ? "async" : "sync");
+  res =
+      gst_rtspsrc_init_request (src, &request, GST_RTSP_OPTIONS,
+      src->conninfo.url_str);
+  if (res < 0)
+    goto create_request_failed;
+
+  /* send OPTIONS */
+  request.type_data.request.version = src->version;
+  GST_DEBUG_OBJECT (src, "send options...");
+
+  if (async)
+    GST_ELEMENT_PROGRESS (src, CONTINUE, "open", ("Retrieving server options"));
+
+  if ((res =
+          gst_rtspsrc_send (src, &src->conninfo, &request, &response,
+              NULL, versions)) < 0) {
+    goto send_error;
+  }
+
+  src->version = request.type_data.request.version;
+  GST_INFO_OBJECT (src, "Now using version: %s",
+      gst_rtsp_version_as_text (src->version));
+
+  /* parse OPTIONS */
+  if (!gst_rtspsrc_parse_methods (src, &response))
+    goto methods_error;
+
+  /* create DESCRIBE */
+  GST_DEBUG_OBJECT (src, "create describe...");
+  res =
+      gst_rtspsrc_init_request (src, &request, GST_RTSP_DESCRIBE,
+      src->conninfo.url_str);
+  if (res < 0)
+    goto create_request_failed;
+
+  /* we only accept SDP for now */
+  gst_rtsp_message_add_header (&request, GST_RTSP_HDR_ACCEPT,
+      "application/sdp");
+
+  /* send DESCRIBE */
+  GST_DEBUG_OBJECT (src, "send describe...");
+
+  if (async)
+    GST_ELEMENT_PROGRESS (src, CONTINUE, "open", ("Retrieving media info"));
+
+  if ((res =
+          gst_rtspsrc_send (src, &src->conninfo, &request, &response,
+              NULL, NULL)) < 0)
+    goto send_error;
+
+  /* we only perform redirect for describe and play, currently */
+  if (src->need_redirect) {
+    /* close connection, we don't have to send a TEARDOWN yet, ignore the
+     * result. */
+    gst_rtsp_conninfo_close (src, &src->conninfo, TRUE);
+
+    gst_rtsp_message_unset (&request);
+    gst_rtsp_message_unset (&response);
+
+    /* and now retry */
+    goto restart;
+  }
+
+  /* it could be that the DESCRIBE method was not implemented */
+  if (!(src->methods & GST_RTSP_DESCRIBE))
+    goto no_describe;
+
+  /* check if reply is SDP */
+  gst_rtsp_message_get_header (&response, GST_RTSP_HDR_CONTENT_TYPE, &respcont,
+      0);
+  /* could not be set but since the request returned OK, we assume it
+   * was SDP, else check it. */
+  if (respcont) {
+    const gchar *props = strchr (respcont, ';');
+
+    if (props) {
+      gchar *mimetype = g_strndup (respcont, props - respcont);
+
+      mimetype = g_strstrip (mimetype);
+      if (g_ascii_strcasecmp (mimetype, "application/sdp") != 0) {
+        g_free (mimetype);
+        goto wrong_content_type;
+      }
+
+      /* TODO: Check for charset property and do conversions of all messages if
+       * needed. Some servers actually send that property */
+
+      g_free (mimetype);
+    } else if (g_ascii_strcasecmp (respcont, "application/sdp") != 0) {
+      goto wrong_content_type;
+    }
+  }
+
+  /* get message body and parse as SDP */
+  gst_rtsp_message_get_body (&response, &data, &size);
+  if (data == NULL || size == 0)
+    goto no_describe;
+
+  GST_DEBUG_OBJECT (src, "parse SDP...");
+  gst_sdp_message_new (sdp);
+  gst_sdp_message_parse_buffer (data, size, *sdp);
+
+  /* clean up any messages */
+  gst_rtsp_message_unset (&request);
+  gst_rtsp_message_unset (&response);
+
+  return res;
+
+  /* ERRORS */
+no_url:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
+        ("No valid RTSP URL was provided"));
+    goto cleanup_error;
+  }
+connect_failed:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+
+    if (res != GST_RTSP_EINTR) {
+      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL),
+          ("Failed to connect. (%s)", str));
+    } else {
+      GST_WARNING_OBJECT (src, "connect interrupted");
+    }
+    g_free (str);
+    goto cleanup_error;
+  }
+create_request_failed:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+
+    GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL),
+        ("Could not create request. (%s)", str));
+    g_free (str);
+    goto cleanup_error;
+  }
+send_error:
+  {
+    /* Don't post a message - the rtsp_send method will have
+     * taken care of it because we passed NULL for the response code */
+    goto cleanup_error;
+  }
+methods_error:
+  {
+    /* error was posted */
+    res = GST_RTSP_ERROR;
+    goto cleanup_error;
+  }
+wrong_content_type:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+        ("Server does not support SDP, got %s.", respcont));
+    res = GST_RTSP_ERROR;
+    goto cleanup_error;
+  }
+no_describe:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+        ("Server can not provide an SDP."));
+    res = GST_RTSP_ERROR;
+    goto cleanup_error;
+  }
+cleanup_error:
+  {
+    if (src->conninfo.connection) {
+      GST_DEBUG_OBJECT (src, "free connection");
+      gst_rtsp_conninfo_close (src, &src->conninfo, TRUE);
+    }
+    gst_rtsp_message_unset (&request);
+    gst_rtsp_message_unset (&response);
+    return res;
+  }
+}
+
+static GstRTSPResult
+gst_rtspsrc_open (GstRTSPSrc * src, gboolean async)
+{
+  GstRTSPResult ret;
+
+  src->methods =
+      GST_RTSP_SETUP | GST_RTSP_PLAY | GST_RTSP_PAUSE | GST_RTSP_TEARDOWN;
+
+  if (src->sdp == NULL) {
+    if ((ret = gst_rtspsrc_retrieve_sdp (src, &src->sdp, async)) < 0)
+      goto no_sdp;
+  }
+
+  if ((ret = gst_rtspsrc_open_from_sdp (src, src->sdp, async)) < 0)
+    goto open_failed;
+
+done:
+  if (async)
+    gst_rtspsrc_loop_end_cmd (src, CMD_OPEN, ret);
+
+  return ret;
+
+  /* ERRORS */
+no_sdp:
+  {
+    GST_WARNING_OBJECT (src, "can't get sdp");
+    src->open_error = TRUE;
+    goto done;
+  }
+open_failed:
+  {
+    GST_WARNING_OBJECT (src, "can't setup streaming from sdp");
+    src->open_error = TRUE;
+    goto done;
+  }
+}
+
+static GstRTSPResult
+gst_rtspsrc_close (GstRTSPSrc * src, gboolean async, gboolean only_close)
+{
+  GstRTSPMessage request = { 0 };
+  GstRTSPMessage response = { 0 };
+  GstRTSPResult res = GST_RTSP_OK;
+  GList *walk;
+  const gchar *control;
+
+  GST_DEBUG_OBJECT (src, "TEARDOWN...");
+
+  gst_rtspsrc_set_state (src, GST_STATE_READY);
+
+  if (src->state < GST_RTSP_STATE_READY) {
+    GST_DEBUG_OBJECT (src, "not ready, doing cleanup");
+    goto close;
+  }
+
+  if (only_close)
+    goto close;
+
+  /* construct a control url */
+  control = get_aggregate_control (src);
+
+  if (!(src->methods & (GST_RTSP_PLAY | GST_RTSP_TEARDOWN)))
+    goto not_supported;
+
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+    const gchar *setup_url;
+    GstRTSPConnInfo *info;
+
+    /* try aggregate control first but do non-aggregate control otherwise */
+    if (control)
+      setup_url = control;
+    else if ((setup_url = stream->conninfo.location) == NULL)
+      continue;
+
+    if (src->conninfo.connection) {
+      info = &src->conninfo;
+    } else if (stream->conninfo.connection) {
+      info = &stream->conninfo;
+    } else {
+      continue;
+    }
+    if (!info->connected)
+      goto next;
+
+    /* do TEARDOWN */
+    res =
+        gst_rtspsrc_init_request (src, &request, GST_RTSP_TEARDOWN, setup_url);
+    if (res < 0)
+      goto create_request_failed;
+
+    if (async)
+      GST_ELEMENT_PROGRESS (src, CONTINUE, "close", ("Closing stream"));
+
+    if ((res =
+            gst_rtspsrc_send (src, info, &request, &response, NULL, NULL)) < 0)
+      goto send_error;
+
+    /* FIXME, parse result? */
+    gst_rtsp_message_unset (&request);
+    gst_rtsp_message_unset (&response);
+
+  next:
+    /* early exit when we did aggregate control */
+    if (control)
+      break;
+  }
+
+close:
+  /* close connections */
+  GST_DEBUG_OBJECT (src, "closing connection...");
+  gst_rtsp_conninfo_close (src, &src->conninfo, TRUE);
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+    gst_rtsp_conninfo_close (src, &stream->conninfo, TRUE);
+  }
+
+  /* cleanup */
+  gst_rtspsrc_cleanup (src);
+
+  src->state = GST_RTSP_STATE_INVALID;
+
+  if (async)
+    gst_rtspsrc_loop_end_cmd (src, CMD_CLOSE, res);
+
+  return res;
+
+  /* ERRORS */
+create_request_failed:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+
+    GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL),
+        ("Could not create request. (%s)", str));
+    g_free (str);
+    goto close;
+  }
+send_error:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+
+    gst_rtsp_message_unset (&request);
+    if (res != GST_RTSP_EINTR) {
+      GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
+          ("Could not send message. (%s)", str));
+    } else {
+      GST_WARNING_OBJECT (src, "TEARDOWN interrupted");
+    }
+    g_free (str);
+    goto close;
+  }
+not_supported:
+  {
+    GST_DEBUG_OBJECT (src,
+        "TEARDOWN and PLAY not supported, can't do TEARDOWN");
+    goto close;
+  }
+}
+
+/* RTP-Info is of the format:
+ *
+ * url=<URL>;[seq=<seqbase>;rtptime=<timebase>] [, url=...]
+ *
+ * rtptime corresponds to the timestamp for the NPT time given in the header
+ * seqbase corresponds to the next sequence number we received. This number
+ * indicates the first seqnum after the seek and should be used to discard
+ * packets that are from before the seek.
+ */
+static gboolean
+gst_rtspsrc_parse_rtpinfo (GstRTSPSrc * src, gchar * rtpinfo)
+{
+  gchar **infos;
+  gint i, j;
+
+  GST_DEBUG_OBJECT (src, "parsing RTP-Info %s", rtpinfo);
+
+  infos = g_strsplit (rtpinfo, ",", 0);
+  for (i = 0; infos[i]; i++) {
+    gchar **fields;
+    GstRTSPStream *stream;
+    gint32 seqbase;
+    gint64 timebase;
+
+    GST_DEBUG_OBJECT (src, "parsing info %s", infos[i]);
+
+    /* init values, types of seqbase and timebase are bigger than needed so we
+     * can store -1 as uninitialized values */
+    stream = NULL;
+    seqbase = -1;
+    timebase = -1;
+
+    /* parse url, find stream for url.
+     * parse seq and rtptime. The seq number should be configured in the rtp
+     * depayloader or session manager to detect gaps. Same for the rtptime, it
+     * should be used to create an initial time newsegment. */
+    fields = g_strsplit (infos[i], ";", 0);
+    for (j = 0; fields[j]; j++) {
+      GST_DEBUG_OBJECT (src, "parsing field %s", fields[j]);
+      /* remove leading whitespace */
+      fields[j] = g_strchug (fields[j]);
+      if (g_str_has_prefix (fields[j], "url=")) {
+        /* get the url and the stream */
+        stream =
+            find_stream (src, (fields[j] + 4), (gpointer) find_stream_by_setup);
+      } else if (g_str_has_prefix (fields[j], "seq=")) {
+        seqbase = atoi (fields[j] + 4);
+      } else if (g_str_has_prefix (fields[j], "rtptime=")) {
+        timebase = g_ascii_strtoll (fields[j] + 8, NULL, 10);
+      }
+    }
+    g_strfreev (fields);
+    /* now we need to store the values for the caps of the stream */
+    if (stream != NULL) {
+      GST_DEBUG_OBJECT (src,
+          "found stream %p, setting: seqbase %d, timebase %" G_GINT64_FORMAT,
+          stream, seqbase, timebase);
+
+      /* we have a stream, configure detected params */
+      stream->seqbase = seqbase;
+      stream->timebase = timebase;
+    }
+  }
+  g_strfreev (infos);
+
+  return TRUE;
+}
+
+static void
+gst_rtspsrc_handle_rtcp_interval (GstRTSPSrc * src, gchar * rtcp)
+{
+  guint64 interval;
+  GList *walk;
+
+  interval = strtoul (rtcp, NULL, 10);
+  GST_DEBUG_OBJECT (src, "rtcp interval: %" G_GUINT64_FORMAT " ms", interval);
+
+  if (!interval)
+    return;
+
+  interval *= GST_MSECOND;
+
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+
+    /* already (optionally) retrieved this when configuring manager */
+    if (stream->session) {
+      GObject *rtpsession = stream->session;
+
+      GST_DEBUG_OBJECT (src, "configure rtcp interval in session %p",
+          rtpsession);
+      g_object_set (rtpsession, "rtcp-min-interval", interval, NULL);
+    }
+  }
+
+  /* now it happens that (Xenon) server sending this may also provide bogus
+   * RTCP SR sync data (i.e. with quite some jitter), so never mind those
+   * and just use RTP-Info to sync */
+  if (src->manager) {
+    GObjectClass *klass;
+
+    klass = G_OBJECT_GET_CLASS (G_OBJECT (src->manager));
+    if (g_object_class_find_property (klass, "rtcp-sync")) {
+      GST_DEBUG_OBJECT (src, "configuring rtp sync method");
+      g_object_set (src->manager, "rtcp-sync", RTCP_SYNC_RTP, NULL);
+    }
+  }
+}
+
+static gdouble
+gst_rtspsrc_get_float (const gchar * dstr)
+{
+  gchar s[G_ASCII_DTOSTR_BUF_SIZE] = { 0, };
+
+  /* canonicalise floating point string so we can handle float strings
+   * in the form "24.930" or "24,930" irrespective of the current locale */
+  g_strlcpy (s, dstr, sizeof (s));
+  g_strdelimit (s, ",", '.');
+  return g_ascii_strtod (s, NULL);
+}
+
+static gchar *
+gen_range_header (GstRTSPSrc * src, GstSegment * segment)
+{
+  gchar val_str[G_ASCII_DTOSTR_BUF_SIZE] = { 0, };
+
+  if (src->range && src->range->min.type == GST_RTSP_TIME_NOW) {
+    g_strlcpy (val_str, "now", sizeof (val_str));
+  } else {
+    if (segment->position == 0) {
+      g_strlcpy (val_str, "0", sizeof (val_str));
+    } else {
+      g_ascii_dtostr (val_str, sizeof (val_str),
+          ((gdouble) segment->position) / GST_SECOND);
+    }
+  }
+  return g_strdup_printf ("npt=%s-", val_str);
+}
+
+static void
+clear_rtp_base (GstRTSPSrc * src, GstRTSPStream * stream)
+{
+  guint i, len;
+
+  stream->timebase = -1;
+  stream->seqbase = -1;
+
+  len = stream->ptmap->len;
+  for (i = 0; i < len; i++) {
+    PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i);
+    GstStructure *s;
+
+    if (item->caps == NULL)
+      continue;
+
+    item->caps = gst_caps_make_writable (item->caps);
+    s = gst_caps_get_structure (item->caps, 0);
+    gst_structure_remove_fields (s, "clock-base", "seqnum-base", NULL);
+    if (item->pt == stream->default_pt && stream->udpsrc[0])
+      g_object_set (stream->udpsrc[0], "caps", item->caps, NULL);
+  }
+  stream->need_caps = TRUE;
+}
+
+static GstRTSPResult
+gst_rtspsrc_ensure_open (GstRTSPSrc * src, gboolean async)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+
+  if (src->state < GST_RTSP_STATE_READY) {
+    res = GST_RTSP_ERROR;
+    if (src->open_error) {
+      GST_DEBUG_OBJECT (src, "the stream was in error");
+      goto done;
+    }
+    if (async)
+      gst_rtspsrc_loop_start_cmd (src, CMD_OPEN);
+
+    if ((res = gst_rtspsrc_open (src, async)) < 0) {
+      GST_DEBUG_OBJECT (src, "failed to open stream");
+      goto done;
+    }
+  }
+
+done:
+  return res;
+}
+
+static GstRTSPResult
+gst_rtspsrc_play (GstRTSPSrc * src, GstSegment * segment, gboolean async,
+    const gchar * seek_style)
+{
+  GstRTSPMessage request = { 0 };
+  GstRTSPMessage response = { 0 };
+  GstRTSPResult res = GST_RTSP_OK;
+  GList *walk;
+  gchar *hval;
+  gint hval_idx;
+  const gchar *control;
+
+  GST_DEBUG_OBJECT (src, "PLAY...");
+
+restart:
+  if ((res = gst_rtspsrc_ensure_open (src, async)) < 0)
+    goto open_failed;
+
+  if (!(src->methods & GST_RTSP_PLAY))
+    goto not_supported;
+
+  if (src->state == GST_RTSP_STATE_PLAYING)
+    goto was_playing;
+
+  if (!src->conninfo.connection || !src->conninfo.connected)
+    goto done;
+
+  /* send some dummy packets before we activate the receive in the
+   * udp sources */
+  gst_rtspsrc_send_dummy_packets (src);
+
+  /* require new SR packets */
+  if (src->manager)
+    g_signal_emit_by_name (src->manager, "reset-sync", NULL);
+
+  /* construct a control url */
+  control = get_aggregate_control (src);
+
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+    const gchar *setup_url;
+    GstRTSPConnInfo *conninfo;
+
+    /* try aggregate control first but do non-aggregate control otherwise */
+    if (control)
+      setup_url = control;
+    else if ((setup_url = stream->conninfo.location) == NULL)
+      continue;
+
+    if (src->conninfo.connection) {
+      conninfo = &src->conninfo;
+    } else if (stream->conninfo.connection) {
+      conninfo = &stream->conninfo;
+    } else {
+      continue;
+    }
+
+    /* do play */
+    res = gst_rtspsrc_init_request (src, &request, GST_RTSP_PLAY, setup_url);
+    if (res < 0)
+      goto create_request_failed;
+
+    if (src->need_range && src->seekable >= 0.0) {
+      hval = gen_range_header (src, segment);
+
+      gst_rtsp_message_take_header (&request, GST_RTSP_HDR_RANGE, hval);
+
+      /* store the newsegment event so it can be sent from the streaming thread. */
+      src->need_segment = TRUE;
+    }
+
+    if (segment->rate != 1.0) {
+      gchar hval[G_ASCII_DTOSTR_BUF_SIZE];
+
+      g_ascii_dtostr (hval, sizeof (hval), segment->rate);
+      if (src->skip)
+        gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SCALE, hval);
+      else
+        gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SPEED, hval);
+    }
+
+    if (seek_style)
+      gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SEEK_STYLE,
+          seek_style);
+
+    if (async)
+      GST_ELEMENT_PROGRESS (src, CONTINUE, "request", ("Sending PLAY request"));
+
+    if ((res =
+            gst_rtspsrc_send (src, conninfo, &request, &response, NULL, NULL))
+        < 0)
+      goto send_error;
+
+    if (src->need_redirect) {
+      GST_DEBUG_OBJECT (src,
+          "redirect: tearing down and restarting with new url");
+      /* teardown and restart with new url */
+      gst_rtspsrc_close (src, TRUE, FALSE);
+      /* reset protocols to force re-negotiation with redirected url */
+      src->cur_protocols = src->protocols;
+      gst_rtsp_message_unset (&request);
+      gst_rtsp_message_unset (&response);
+      goto restart;
+    }
+
+    /* seek may have silently failed as it is not supported */
+    if (!(src->methods & GST_RTSP_PLAY)) {
+      GST_DEBUG_OBJECT (src, "PLAY Range not supported; re-enable PLAY");
+
+      if (src->version >= GST_RTSP_VERSION_2_0 && src->seekable >= 0.0) {
+        GST_WARNING_OBJECT (src, "Server declared stream as seekable but"
+            " playing with range failed... Ignoring information.");
+      }
+      /* obviously it is supported as we made it here */
+      src->methods |= GST_RTSP_PLAY;
+      src->seekable = -1.0;
+      /* but there is nothing to parse in the response,
+       * so convey we have no idea and not to expect anything particular */
+      clear_rtp_base (src, stream);
+      if (control) {
+        GList *run;
+
+        /* need to do for all streams */
+        for (run = src->streams; run; run = g_list_next (run))
+          clear_rtp_base (src, (GstRTSPStream *) run->data);
+      }
+      /* NOTE the above also disables npt based eos detection */
+      /* and below forces position to 0,
+       * which is visible feedback we lost the plot */
+      segment->start = segment->position = src->last_pos;
+    }
+
+    gst_rtsp_message_unset (&request);
+
+    /* parse RTP npt field. This is the current position in the stream (Normal
+     * Play Time) and should be put in the NEWSEGMENT position field. */
+    if (gst_rtsp_message_get_header (&response, GST_RTSP_HDR_RANGE, &hval,
+            0) == GST_RTSP_OK)
+      gst_rtspsrc_parse_range (src, hval, segment);
+
+    /* assume 1.0 rate now, overwrite when the SCALE or SPEED headers are present. */
+    segment->rate = 1.0;
+
+    /* parse Speed header. This is the intended playback rate of the stream
+     * and should be put in the NEWSEGMENT rate field. */
+    if (gst_rtsp_message_get_header (&response, GST_RTSP_HDR_SPEED, &hval,
+            0) == GST_RTSP_OK) {
+      segment->rate = gst_rtspsrc_get_float (hval);
+    } else if (gst_rtsp_message_get_header (&response, GST_RTSP_HDR_SCALE,
+            &hval, 0) == GST_RTSP_OK) {
+      segment->rate = gst_rtspsrc_get_float (hval);
+    }
+
+    /* parse the RTP-Info header field (if ANY) to get the base seqnum and timestamp
+     * for the RTP packets. If this is not present, we assume all starts from 0...
+     * This is info for the RTP session manager that we pass to it in caps. */
+    hval_idx = 0;
+    while (gst_rtsp_message_get_header (&response, GST_RTSP_HDR_RTP_INFO,
+            &hval, hval_idx++) == GST_RTSP_OK)
+      gst_rtspsrc_parse_rtpinfo (src, hval);
+
+    /* some servers indicate RTCP parameters in PLAY response,
+     * rather than properly in SDP */
+    if (gst_rtsp_message_get_header (&response, GST_RTSP_HDR_RTCP_INTERVAL,
+            &hval, 0) == GST_RTSP_OK)
+      gst_rtspsrc_handle_rtcp_interval (src, hval);
+
+    gst_rtsp_message_unset (&response);
+
+    /* early exit when we did aggregate control */
+    if (control)
+      break;
+  }
+  /* configure the caps of the streams after we parsed all headers. Only reset
+   * the manager object when we set a new Range header (we did a seek) */
+  gst_rtspsrc_configure_caps (src, segment, src->need_range);
+
+  /* set to PLAYING after we have configured the caps, otherwise we
+   * might end up calling request_key (with SRTP) while caps are still
+   * being configured. */
+  gst_rtspsrc_set_state (src, GST_STATE_PLAYING);
+
+  /* set again when needed */
+  src->need_range = FALSE;
+
+  src->running = TRUE;
+  src->base_time = -1;
+  src->state = GST_RTSP_STATE_PLAYING;
+
+  /* mark discont */
+  GST_DEBUG_OBJECT (src, "mark DISCONT, we did a seek to another position");
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+    stream->discont = TRUE;
+  }
+
+done:
+  if (async)
+    gst_rtspsrc_loop_end_cmd (src, CMD_PLAY, res);
+
+  return res;
+
+  /* ERRORS */
+open_failed:
+  {
+    GST_DEBUG_OBJECT (src, "failed to open stream");
+    goto done;
+  }
+not_supported:
+  {
+    GST_DEBUG_OBJECT (src, "PLAY is not supported");
+    goto done;
+  }
+was_playing:
+  {
+    GST_DEBUG_OBJECT (src, "we were already PLAYING");
+    goto done;
+  }
+create_request_failed:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+
+    GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL),
+        ("Could not create request. (%s)", str));
+    g_free (str);
+    goto done;
+  }
+send_error:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+
+    gst_rtsp_message_unset (&request);
+    if (res != GST_RTSP_EINTR) {
+      GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
+          ("Could not send message. (%s)", str));
+    } else {
+      GST_WARNING_OBJECT (src, "PLAY interrupted");
+    }
+    g_free (str);
+    goto done;
+  }
+}
+
+static GstRTSPResult
+gst_rtspsrc_pause (GstRTSPSrc * src, gboolean async)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPMessage request = { 0 };
+  GstRTSPMessage response = { 0 };
+  GList *walk;
+  const gchar *control;
+
+  GST_DEBUG_OBJECT (src, "PAUSE...");
+
+  if ((res = gst_rtspsrc_ensure_open (src, async)) < 0)
+    goto open_failed;
+
+  if (!(src->methods & GST_RTSP_PAUSE))
+    goto not_supported;
+
+  if (src->state == GST_RTSP_STATE_READY)
+    goto was_paused;
+
+  if (!src->conninfo.connection || !src->conninfo.connected)
+    goto no_connection;
+
+  /* construct a control url */
+  control = get_aggregate_control (src);
+
+  /* loop over the streams. We might exit the loop early when we could do an
+   * aggregate control */
+  for (walk = src->streams; walk; walk = g_list_next (walk)) {
+    GstRTSPStream *stream = (GstRTSPStream *) walk->data;
+    GstRTSPConnInfo *conninfo;
+    const gchar *setup_url;
+
+    /* try aggregate control first but do non-aggregate control otherwise */
+    if (control)
+      setup_url = control;
+    else if ((setup_url = stream->conninfo.location) == NULL)
+      continue;
+
+    if (src->conninfo.connection) {
+      conninfo = &src->conninfo;
+    } else if (stream->conninfo.connection) {
+      conninfo = &stream->conninfo;
+    } else {
+      continue;
+    }
+
+    if (async)
+      GST_ELEMENT_PROGRESS (src, CONTINUE, "request",
+          ("Sending PAUSE request"));
+
+    if ((res =
+            gst_rtspsrc_init_request (src, &request, GST_RTSP_PAUSE,
+                setup_url)) < 0)
+      goto create_request_failed;
+
+    if ((res =
+            gst_rtspsrc_send (src, conninfo, &request, &response, NULL,
+                NULL)) < 0)
+      goto send_error;
+
+    gst_rtsp_message_unset (&request);
+    gst_rtsp_message_unset (&response);
+
+    /* exit early when we did agregate control */
+    if (control)
+      break;
+  }
+
+  /* change element states now */
+  gst_rtspsrc_set_state (src, GST_STATE_PAUSED);
+
+no_connection:
+  src->state = GST_RTSP_STATE_READY;
+
+done:
+  if (async)
+    gst_rtspsrc_loop_end_cmd (src, CMD_PAUSE, res);
+
+  return res;
+
+  /* ERRORS */
+open_failed:
+  {
+    GST_DEBUG_OBJECT (src, "failed to open stream");
+    goto done;
+  }
+not_supported:
+  {
+    GST_DEBUG_OBJECT (src, "PAUSE is not supported");
+    goto done;
+  }
+was_paused:
+  {
+    GST_DEBUG_OBJECT (src, "we were already PAUSED");
+    goto done;
+  }
+create_request_failed:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+
+    GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL),
+        ("Could not create request. (%s)", str));
+    g_free (str);
+    goto done;
+  }
+send_error:
+  {
+    gchar *str = gst_rtsp_strresult (res);
+
+    gst_rtsp_message_unset (&request);
+    if (res != GST_RTSP_EINTR) {
+      GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
+          ("Could not send message. (%s)", str));
+    } else {
+      GST_WARNING_OBJECT (src, "PAUSE interrupted");
+    }
+    g_free (str);
+    goto done;
+  }
+}
+
+static void
+gst_rtspsrc_handle_message (GstBin * bin, GstMessage * message)
+{
+  GstRTSPSrc *rtspsrc;
+
+  rtspsrc = GST_RTSPSRC (bin);
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_EOS:
+      gst_message_unref (message);
+      break;
+    case GST_MESSAGE_ELEMENT:
+    {
+      const GstStructure *s = gst_message_get_structure (message);
+
+      if (gst_structure_has_name (s, "GstUDPSrcTimeout")) {
+        gboolean ignore_timeout;
+
+        GST_DEBUG_OBJECT (bin, "timeout on UDP port");
+
+        GST_OBJECT_LOCK (rtspsrc);
+        ignore_timeout = rtspsrc->ignore_timeout;
+        rtspsrc->ignore_timeout = TRUE;
+        GST_OBJECT_UNLOCK (rtspsrc);
+
+        /* we only act on the first udp timeout message, others are irrelevant
+         * and can be ignored. */
+        if (!ignore_timeout)
+          gst_rtspsrc_loop_send_cmd (rtspsrc, CMD_RECONNECT, CMD_LOOP);
+        /* eat and free */
+        gst_message_unref (message);
+        return;
+      }
+      GST_BIN_CLASS (parent_class)->handle_message (bin, message);
+      break;
+    }
+    case GST_MESSAGE_ERROR:
+    {
+      GstObject *udpsrc;
+      GstRTSPStream *stream;
+      GstFlowReturn ret;
+
+      udpsrc = GST_MESSAGE_SRC (message);
+
+      GST_DEBUG_OBJECT (rtspsrc, "got error from %s",
+          GST_ELEMENT_NAME (udpsrc));
+
+      stream = find_stream (rtspsrc, udpsrc, (gpointer) find_stream_by_udpsrc);
+      if (!stream)
+        goto forward;
+
+      /* we ignore the RTCP udpsrc */
+      if (stream->udpsrc[1] == GST_ELEMENT_CAST (udpsrc))
+        goto done;
+
+      /* if we get error messages from the udp sources, that's not a problem as
+       * long as not all of them error out. We also don't really know what the
+       * problem is, the message does not give enough detail... */
+      ret = gst_rtspsrc_combine_flows (rtspsrc, stream, GST_FLOW_NOT_LINKED);
+      GST_DEBUG_OBJECT (rtspsrc, "combined flows: %s", gst_flow_get_name (ret));
+      if (ret != GST_FLOW_OK)
+        goto forward;
+
+    done:
+      gst_message_unref (message);
+      break;
+
+    forward:
+      /* fatal but not our message, forward */
+      GST_BIN_CLASS (parent_class)->handle_message (bin, message);
+      break;
+    }
+    default:
+    {
+      GST_BIN_CLASS (parent_class)->handle_message (bin, message);
+      break;
+    }
+  }
+}
+
+/* the thread where everything happens */
+static void
+gst_rtspsrc_thread (GstRTSPSrc * src)
+{
+  gint cmd;
+
+  GST_OBJECT_LOCK (src);
+  cmd = src->pending_cmd;
+  if (cmd == CMD_RECONNECT || cmd == CMD_PLAY || cmd == CMD_PAUSE
+      || cmd == CMD_LOOP || cmd == CMD_OPEN)
+    src->pending_cmd = CMD_LOOP;
+  else
+    src->pending_cmd = CMD_WAIT;
+  GST_DEBUG_OBJECT (src, "got command %s", cmd_to_string (cmd));
+
+  /* we got the message command, so ensure communication is possible again */
+  gst_rtspsrc_connection_flush (src, FALSE);
+
+  src->busy_cmd = cmd;
+  GST_OBJECT_UNLOCK (src);
+
+  switch (cmd) {
+    case CMD_OPEN:
+      gst_rtspsrc_open (src, TRUE);
+      break;
+    case CMD_PLAY:
+      gst_rtspsrc_play (src, &src->segment, TRUE, NULL);
+      break;
+    case CMD_PAUSE:
+      gst_rtspsrc_pause (src, TRUE);
+      break;
+    case CMD_CLOSE:
+      gst_rtspsrc_close (src, TRUE, FALSE);
+      break;
+    case CMD_LOOP:
+      gst_rtspsrc_loop (src);
+      break;
+    case CMD_RECONNECT:
+      gst_rtspsrc_reconnect (src, FALSE);
+      break;
+    default:
+      break;
+  }
+
+  GST_OBJECT_LOCK (src);
+  /* and go back to sleep */
+  if (src->pending_cmd == CMD_WAIT) {
+    if (src->task)
+      gst_task_pause (src->task);
+  }
+  /* reset waiting */
+  src->busy_cmd = CMD_WAIT;
+  GST_OBJECT_UNLOCK (src);
+}
+
+static gboolean
+gst_rtspsrc_start (GstRTSPSrc * src)
+{
+  GST_DEBUG_OBJECT (src, "starting");
+
+  GST_OBJECT_LOCK (src);
+
+  src->pending_cmd = CMD_WAIT;
+
+  if (src->task == NULL) {
+    src->task = gst_task_new ((GstTaskFunction) gst_rtspsrc_thread, src, NULL);
+    if (src->task == NULL)
+      goto task_error;
+
+    gst_task_set_lock (src->task, GST_RTSP_STREAM_GET_LOCK (src));
+  }
+  GST_OBJECT_UNLOCK (src);
+
+  return TRUE;
+
+  /* ERRORS */
+task_error:
+  {
+    GST_OBJECT_UNLOCK (src);
+    GST_ERROR_OBJECT (src, "failed to create task");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_rtspsrc_stop (GstRTSPSrc * src)
+{
+  GstTask *task;
+
+  GST_DEBUG_OBJECT (src, "stopping");
+
+  /* also cancels pending task */
+  gst_rtspsrc_loop_send_cmd (src, CMD_WAIT, CMD_ALL);
+
+  GST_OBJECT_LOCK (src);
+  if ((task = src->task)) {
+    src->task = NULL;
+    GST_OBJECT_UNLOCK (src);
+
+    gst_task_stop (task);
+
+    /* make sure it is not running */
+    GST_RTSP_STREAM_LOCK (src);
+    GST_RTSP_STREAM_UNLOCK (src);
+
+    /* now wait for the task to finish */
+    gst_task_join (task);
+
+    /* and free the task */
+    gst_object_unref (GST_OBJECT (task));
+
+    GST_OBJECT_LOCK (src);
+  }
+  GST_OBJECT_UNLOCK (src);
+
+  /* ensure synchronously all is closed and clean */
+  gst_rtspsrc_close (src, FALSE, TRUE);
+
+  return TRUE;
+}
+
+static GstStateChangeReturn
+gst_rtspsrc_change_state (GstElement * element, GstStateChange transition)
+{
+  GstRTSPSrc *rtspsrc;
+  GstStateChangeReturn ret;
+
+  rtspsrc = GST_RTSPSRC (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      if (!gst_rtspsrc_start (rtspsrc))
+        goto start_failed;
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      /* init some state */
+      rtspsrc->cur_protocols = rtspsrc->protocols;
+      /* first attempt, don't ignore timeouts */
+      rtspsrc->ignore_timeout = FALSE;
+      rtspsrc->open_error = FALSE;
+      gst_rtspsrc_loop_send_cmd (rtspsrc, CMD_OPEN, 0);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      set_manager_buffer_mode (rtspsrc);
+      /* fall-through */
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      /* unblock the tcp tasks and make the loop waiting */
+      if (gst_rtspsrc_loop_send_cmd (rtspsrc, CMD_WAIT, CMD_LOOP)) {
+        /* make sure it is waiting before we send PAUSE or PLAY below */
+        GST_RTSP_STREAM_LOCK (rtspsrc);
+        GST_RTSP_STREAM_UNLOCK (rtspsrc);
+      }
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    goto done;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      ret = GST_STATE_CHANGE_SUCCESS;
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      ret = GST_STATE_CHANGE_NO_PREROLL;
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      gst_rtspsrc_loop_send_cmd (rtspsrc, CMD_PLAY, 0);
+      ret = GST_STATE_CHANGE_SUCCESS;
+      break;
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      /* send pause request and keep the idle task around */
+      gst_rtspsrc_loop_send_cmd (rtspsrc, CMD_PAUSE, CMD_LOOP);
+      ret = GST_STATE_CHANGE_NO_PREROLL;
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtspsrc_loop_send_cmd (rtspsrc, CMD_CLOSE, CMD_ALL);
+      ret = GST_STATE_CHANGE_SUCCESS;
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      gst_rtspsrc_stop (rtspsrc);
+      ret = GST_STATE_CHANGE_SUCCESS;
+      break;
+    default:
+      /* Otherwise it's success, we don't want to return spurious
+       * NO_PREROLL or ASYNC from internal elements as we care for
+       * state changes ourselves here
+       *
+       * This is to catch PAUSED->PAUSED and PLAYING->PLAYING transitions.
+       */
+      if (GST_STATE_TRANSITION_NEXT (transition) == GST_STATE_PAUSED)
+        ret = GST_STATE_CHANGE_NO_PREROLL;
+      else
+        ret = GST_STATE_CHANGE_SUCCESS;
+      break;
+  }
+
+done:
+  return ret;
+
+start_failed:
+  {
+    GST_DEBUG_OBJECT (rtspsrc, "start failed");
+    return GST_STATE_CHANGE_FAILURE;
+  }
+}
+
+static gboolean
+gst_rtspsrc_send_event (GstElement * element, GstEvent * event)
+{
+  gboolean res;
+  GstRTSPSrc *rtspsrc;
+
+  rtspsrc = GST_RTSPSRC (element);
+
+  if (GST_EVENT_IS_DOWNSTREAM (event)) {
+    res = gst_rtspsrc_push_event (rtspsrc, event);
+  } else {
+    res = GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
+  }
+
+  return res;
+}
+
+
+/*** GSTURIHANDLER INTERFACE *************************************************/
+
+static GstURIType
+gst_rtspsrc_uri_get_type (GType type)
+{
+  return GST_URI_SRC;
+}
+
+static const gchar *const *
+gst_rtspsrc_uri_get_protocols (GType type)
+{
+  static const gchar *protocols[] =
+      { "rtsp", "rtspu", "rtspt", "rtsph", "rtsp-sdp",
+    "rtsps", "rtspsu", "rtspst", "rtspsh", NULL
+  };
+
+  return protocols;
+}
+
+static gchar *
+gst_rtspsrc_uri_get_uri (GstURIHandler * handler)
+{
+  GstRTSPSrc *src = GST_RTSPSRC (handler);
+
+  /* FIXME: make thread-safe */
+  return g_strdup (src->conninfo.location);
+}
+
+static gboolean
+gst_rtspsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+    GError ** error)
+{
+  GstRTSPSrc *src;
+  GstRTSPResult res;
+  GstSDPResult sres;
+  GstRTSPUrl *newurl = NULL;
+  GstSDPMessage *sdp = NULL;
+
+  src = GST_RTSPSRC (handler);
+
+  /* same URI, we're fine */
+  if (src->conninfo.location && uri && !strcmp (uri, src->conninfo.location))
+    goto was_ok;
+
+  if (g_str_has_prefix (uri, "rtsp-sdp://")) {
+    sres = gst_sdp_message_new (&sdp);
+    if (sres < 0)
+      goto sdp_failed;
+
+    GST_DEBUG_OBJECT (src, "parsing SDP message");
+    sres = gst_sdp_message_parse_uri (uri, sdp);
+    if (sres < 0)
+      goto invalid_sdp;
+  } else {
+    /* try to parse */
+    GST_DEBUG_OBJECT (src, "parsing URI");
+    if ((res = gst_rtsp_url_parse (uri, &newurl)) < 0)
+      goto parse_error;
+  }
+
+  /* if worked, free previous and store new url object along with the original
+   * location. */
+  GST_DEBUG_OBJECT (src, "configuring URI");
+  g_free (src->conninfo.location);
+  src->conninfo.location = g_strdup (uri);
+  gst_rtsp_url_free (src->conninfo.url);
+  src->conninfo.url = newurl;
+  g_free (src->conninfo.url_str);
+  if (newurl)
+    src->conninfo.url_str = gst_rtsp_url_get_request_uri (src->conninfo.url);
+  else
+    src->conninfo.url_str = NULL;
+
+  if (src->sdp)
+    gst_sdp_message_free (src->sdp);
+  src->sdp = sdp;
+  src->from_sdp = sdp != NULL;
+
+  GST_DEBUG_OBJECT (src, "set uri: %s", GST_STR_NULL (uri));
+  GST_DEBUG_OBJECT (src, "request uri is: %s",
+      GST_STR_NULL (src->conninfo.url_str));
+
+  return TRUE;
+
+  /* Special cases */
+was_ok:
+  {
+    GST_DEBUG_OBJECT (src, "URI was ok: '%s'", GST_STR_NULL (uri));
+    return TRUE;
+  }
+sdp_failed:
+  {
+    GST_ERROR_OBJECT (src, "Could not create new SDP (%d)", sres);
+    g_set_error_literal (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
+        "Could not create SDP");
+    return FALSE;
+  }
+invalid_sdp:
+  {
+    GST_ERROR_OBJECT (src, "Not a valid SDP (%d) '%s'", sres,
+        GST_STR_NULL (uri));
+    gst_sdp_message_free (sdp);
+    g_set_error_literal (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
+        "Invalid SDP");
+    return FALSE;
+  }
+parse_error:
+  {
+    GST_ERROR_OBJECT (src, "Not a valid RTSP url '%s' (%d)",
+        GST_STR_NULL (uri), res);
+    g_set_error_literal (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
+        "Invalid RTSP URI");
+    return FALSE;
+  }
+}
+
+static void
+gst_rtspsrc_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+  iface->get_type = gst_rtspsrc_uri_get_type;
+  iface->get_protocols = gst_rtspsrc_uri_get_protocols;
+  iface->get_uri = gst_rtspsrc_uri_get_uri;
+  iface->set_uri = gst_rtspsrc_uri_set_uri;
+}
+
+typedef struct _RTSPKeyValue
+{
+  GstRTSPHeaderField field;
+  gchar *value;
+  gchar *custom_key;            /* custom header string (field is INVALID then) */
+} RTSPKeyValue;
+
+static void
+key_value_foreach (GArray * array, GFunc func, gpointer user_data)
+{
+  guint i;
+
+  g_return_if_fail (array != NULL);
+
+  for (i = 0; i < array->len; i++) {
+    (*func) (&g_array_index (array, RTSPKeyValue, i), user_data);
+  }
+}
+
+static void
+dump_key_value (gpointer data, gpointer user_data G_GNUC_UNUSED)
+{
+  RTSPKeyValue *key_value = (RTSPKeyValue *) data;
+  GstRTSPSrc *src = GST_RTSPSRC (user_data);
+  const gchar *key_string;
+
+  if (key_value->custom_key != NULL)
+    key_string = key_value->custom_key;
+  else
+    key_string = gst_rtsp_header_as_text (key_value->field);
+
+  GST_LOG_OBJECT (src, "   key: '%s', value: '%s'", key_string,
+      key_value->value);
+}
+
+static void
+gst_rtspsrc_print_rtsp_message (GstRTSPSrc * src, const GstRTSPMessage * msg)
+{
+  guint8 *data;
+  guint size;
+  GString *body_string = NULL;
+
+  g_return_if_fail (src != NULL);
+  g_return_if_fail (msg != NULL);
+
+  if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) < GST_LEVEL_LOG)
+    return;
+
+  GST_LOG_OBJECT (src, "--------------------------------------------");
+  switch (msg->type) {
+    case GST_RTSP_MESSAGE_REQUEST:
+      GST_LOG_OBJECT (src, "RTSP request message %p", msg);
+      GST_LOG_OBJECT (src, " request line:");
+      GST_LOG_OBJECT (src, "   method: '%s'",
+          gst_rtsp_method_as_text (msg->type_data.request.method));
+      GST_LOG_OBJECT (src, "   uri:    '%s'", msg->type_data.request.uri);
+      GST_LOG_OBJECT (src, "   version: '%s'",
+          gst_rtsp_version_as_text (msg->type_data.request.version));
+      GST_LOG_OBJECT (src, " headers:");
+      key_value_foreach (msg->hdr_fields, dump_key_value, src);
+      GST_LOG_OBJECT (src, " body:");
+      gst_rtsp_message_get_body (msg, &data, &size);
+      if (size > 0) {
+        body_string = g_string_new_len ((const gchar *) data, size);
+        GST_LOG_OBJECT (src, " %s(%d)", body_string->str, size);
+        g_string_free (body_string, TRUE);
+        body_string = NULL;
+      }
+      break;
+    case GST_RTSP_MESSAGE_RESPONSE:
+      GST_LOG_OBJECT (src, "RTSP response message %p", msg);
+      GST_LOG_OBJECT (src, " status line:");
+      GST_LOG_OBJECT (src, "   code:   '%d'", msg->type_data.response.code);
+      GST_LOG_OBJECT (src, "   reason: '%s'", msg->type_data.response.reason);
+      GST_LOG_OBJECT (src, "   version: '%s",
+          gst_rtsp_version_as_text (msg->type_data.response.version));
+      GST_LOG_OBJECT (src, " headers:");
+      key_value_foreach (msg->hdr_fields, dump_key_value, src);
+      gst_rtsp_message_get_body (msg, &data, &size);
+      GST_LOG_OBJECT (src, " body: length %d", size);
+      if (size > 0) {
+        body_string = g_string_new_len ((const gchar *) data, size);
+        GST_LOG_OBJECT (src, " %s(%d)", body_string->str, size);
+        g_string_free (body_string, TRUE);
+        body_string = NULL;
+      }
+      break;
+    case GST_RTSP_MESSAGE_HTTP_REQUEST:
+      GST_LOG_OBJECT (src, "HTTP request message %p", msg);
+      GST_LOG_OBJECT (src, " request line:");
+      GST_LOG_OBJECT (src, "   method:  '%s'",
+          gst_rtsp_method_as_text (msg->type_data.request.method));
+      GST_LOG_OBJECT (src, "   uri:     '%s'", msg->type_data.request.uri);
+      GST_LOG_OBJECT (src, "   version: '%s'",
+          gst_rtsp_version_as_text (msg->type_data.request.version));
+      GST_LOG_OBJECT (src, " headers:");
+      key_value_foreach (msg->hdr_fields, dump_key_value, src);
+      GST_LOG_OBJECT (src, " body:");
+      gst_rtsp_message_get_body (msg, &data, &size);
+      if (size > 0) {
+        body_string = g_string_new_len ((const gchar *) data, size);
+        GST_LOG_OBJECT (src, " %s(%d)", body_string->str, size);
+        g_string_free (body_string, TRUE);
+        body_string = NULL;
+      }
+      break;
+    case GST_RTSP_MESSAGE_HTTP_RESPONSE:
+      GST_LOG_OBJECT (src, "HTTP response message %p", msg);
+      GST_LOG_OBJECT (src, " status line:");
+      GST_LOG_OBJECT (src, "   code:    '%d'", msg->type_data.response.code);
+      GST_LOG_OBJECT (src, "   reason:  '%s'", msg->type_data.response.reason);
+      GST_LOG_OBJECT (src, "   version: '%s'",
+          gst_rtsp_version_as_text (msg->type_data.response.version));
+      GST_LOG_OBJECT (src, " headers:");
+      key_value_foreach (msg->hdr_fields, dump_key_value, src);
+      gst_rtsp_message_get_body (msg, &data, &size);
+      GST_LOG_OBJECT (src, " body: length %d", size);
+      if (size > 0) {
+        body_string = g_string_new_len ((const gchar *) data, size);
+        GST_LOG_OBJECT (src, " %s(%d)", body_string->str, size);
+        g_string_free (body_string, TRUE);
+        body_string = NULL;
+      }
+      break;
+    case GST_RTSP_MESSAGE_DATA:
+      GST_LOG_OBJECT (src, "RTSP data message %p", msg);
+      GST_LOG_OBJECT (src, " channel: '%d'", msg->type_data.data.channel);
+      GST_LOG_OBJECT (src, " size:    '%d'", msg->body_size);
+      gst_rtsp_message_get_body (msg, &data, &size);
+      if (size > 0) {
+        body_string = g_string_new_len ((const gchar *) data, size);
+        GST_LOG_OBJECT (src, " %s(%d)", body_string->str, size);
+        g_string_free (body_string, TRUE);
+        body_string = NULL;
+      }
+      break;
+    default:
+      GST_LOG_OBJECT (src, "unsupported message type %d", msg->type);
+      break;
+  }
+  GST_LOG_OBJECT (src, "--------------------------------------------");
+}
+
+static void
+gst_rtspsrc_print_sdp_media (GstRTSPSrc * src, GstSDPMedia * media)
+{
+  GST_LOG_OBJECT (src, "   media:       '%s'", GST_STR_NULL (media->media));
+  GST_LOG_OBJECT (src, "   port:        '%u'", media->port);
+  GST_LOG_OBJECT (src, "   num_ports:   '%u'", media->num_ports);
+  GST_LOG_OBJECT (src, "   proto:       '%s'", GST_STR_NULL (media->proto));
+  if (media->fmts && media->fmts->len > 0) {
+    guint i;
+
+    GST_LOG_OBJECT (src, "   formats:");
+    for (i = 0; i < media->fmts->len; i++) {
+      GST_LOG_OBJECT (src, "    format  '%s'", g_array_index (media->fmts,
+              gchar *, i));
+    }
+  }
+  GST_LOG_OBJECT (src, "   information: '%s'",
+      GST_STR_NULL (media->information));
+  if (media->connections && media->connections->len > 0) {
+    guint i;
+
+    GST_LOG_OBJECT (src, "   connections:");
+    for (i = 0; i < media->connections->len; i++) {
+      GstSDPConnection *conn =
+          &g_array_index (media->connections, GstSDPConnection, i);
+
+      GST_LOG_OBJECT (src, "    nettype:      '%s'",
+          GST_STR_NULL (conn->nettype));
+      GST_LOG_OBJECT (src, "    addrtype:     '%s'",
+          GST_STR_NULL (conn->addrtype));
+      GST_LOG_OBJECT (src, "    address:      '%s'",
+          GST_STR_NULL (conn->address));
+      GST_LOG_OBJECT (src, "    ttl:          '%u'", conn->ttl);
+      GST_LOG_OBJECT (src, "    addr_number:  '%u'", conn->addr_number);
+    }
+  }
+  if (media->bandwidths && media->bandwidths->len > 0) {
+    guint i;
+
+    GST_LOG_OBJECT (src, "   bandwidths:");
+    for (i = 0; i < media->bandwidths->len; i++) {
+      GstSDPBandwidth *bw =
+          &g_array_index (media->bandwidths, GstSDPBandwidth, i);
+
+      GST_LOG_OBJECT (src, "    type:         '%s'", GST_STR_NULL (bw->bwtype));
+      GST_LOG_OBJECT (src, "    bandwidth:    '%u'", bw->bandwidth);
+    }
+  }
+  GST_LOG_OBJECT (src, "   key:");
+  GST_LOG_OBJECT (src, "    type:       '%s'", GST_STR_NULL (media->key.type));
+  GST_LOG_OBJECT (src, "    data:       '%s'", GST_STR_NULL (media->key.data));
+  if (media->attributes && media->attributes->len > 0) {
+    guint i;
+
+    GST_LOG_OBJECT (src, "   attributes:");
+    for (i = 0; i < media->attributes->len; i++) {
+      GstSDPAttribute *attr =
+          &g_array_index (media->attributes, GstSDPAttribute, i);
+
+      GST_LOG_OBJECT (src, "    attribute '%s' : '%s'", attr->key, attr->value);
+    }
+  }
+}
+
+void
+gst_rtspsrc_print_sdp_message (GstRTSPSrc * src, const GstSDPMessage * msg)
+{
+  g_return_if_fail (src != NULL);
+  g_return_if_fail (msg != NULL);
+
+  if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) < GST_LEVEL_LOG)
+    return;
+
+  GST_LOG_OBJECT (src, "--------------------------------------------");
+  GST_LOG_OBJECT (src, "sdp packet %p:", msg);
+  GST_LOG_OBJECT (src, " version:       '%s'", GST_STR_NULL (msg->version));
+  GST_LOG_OBJECT (src, " origin:");
+  GST_LOG_OBJECT (src, "  username:     '%s'",
+      GST_STR_NULL (msg->origin.username));
+  GST_LOG_OBJECT (src, "  sess_id:      '%s'",
+      GST_STR_NULL (msg->origin.sess_id));
+  GST_LOG_OBJECT (src, "  sess_version: '%s'",
+      GST_STR_NULL (msg->origin.sess_version));
+  GST_LOG_OBJECT (src, "  nettype:      '%s'",
+      GST_STR_NULL (msg->origin.nettype));
+  GST_LOG_OBJECT (src, "  addrtype:     '%s'",
+      GST_STR_NULL (msg->origin.addrtype));
+  GST_LOG_OBJECT (src, "  addr:         '%s'", GST_STR_NULL (msg->origin.addr));
+  GST_LOG_OBJECT (src, " session_name:  '%s'",
+      GST_STR_NULL (msg->session_name));
+  GST_LOG_OBJECT (src, " information:   '%s'", GST_STR_NULL (msg->information));
+  GST_LOG_OBJECT (src, " uri:           '%s'", GST_STR_NULL (msg->uri));
+
+  if (msg->emails && msg->emails->len > 0) {
+    guint i;
+
+    GST_LOG_OBJECT (src, " emails:");
+    for (i = 0; i < msg->emails->len; i++) {
+      GST_LOG_OBJECT (src, "  email '%s'", g_array_index (msg->emails, gchar *,
+              i));
+    }
+  }
+  if (msg->phones && msg->phones->len > 0) {
+    guint i;
+
+    GST_LOG_OBJECT (src, " phones:");
+    for (i = 0; i < msg->phones->len; i++) {
+      GST_LOG_OBJECT (src, "  phone '%s'", g_array_index (msg->phones, gchar *,
+              i));
+    }
+  }
+  GST_LOG_OBJECT (src, " connection:");
+  GST_LOG_OBJECT (src, "  nettype:      '%s'",
+      GST_STR_NULL (msg->connection.nettype));
+  GST_LOG_OBJECT (src, "  addrtype:     '%s'",
+      GST_STR_NULL (msg->connection.addrtype));
+  GST_LOG_OBJECT (src, "  address:      '%s'",
+      GST_STR_NULL (msg->connection.address));
+  GST_LOG_OBJECT (src, "  ttl:          '%u'", msg->connection.ttl);
+  GST_LOG_OBJECT (src, "  addr_number:  '%u'", msg->connection.addr_number);
+  if (msg->bandwidths && msg->bandwidths->len > 0) {
+    guint i;
+
+    GST_LOG_OBJECT (src, " bandwidths:");
+    for (i = 0; i < msg->bandwidths->len; i++) {
+      GstSDPBandwidth *bw =
+          &g_array_index (msg->bandwidths, GstSDPBandwidth, i);
+
+      GST_LOG_OBJECT (src, "  type:         '%s'", GST_STR_NULL (bw->bwtype));
+      GST_LOG_OBJECT (src, "  bandwidth:    '%u'", bw->bandwidth);
+    }
+  }
+  GST_LOG_OBJECT (src, " key:");
+  GST_LOG_OBJECT (src, "  type:         '%s'", GST_STR_NULL (msg->key.type));
+  GST_LOG_OBJECT (src, "  data:         '%s'", GST_STR_NULL (msg->key.data));
+  if (msg->attributes && msg->attributes->len > 0) {
+    guint i;
+
+    GST_LOG_OBJECT (src, " attributes:");
+    for (i = 0; i < msg->attributes->len; i++) {
+      GstSDPAttribute *attr =
+          &g_array_index (msg->attributes, GstSDPAttribute, i);
+
+      GST_LOG_OBJECT (src, "  attribute '%s' : '%s'", attr->key, attr->value);
+    }
+  }
+  if (msg->medias && msg->medias->len > 0) {
+    guint i;
+
+    GST_LOG_OBJECT (src, " medias:");
+    for (i = 0; i < msg->medias->len; i++) {
+      GST_LOG_OBJECT (src, "  media %u:", i);
+      gst_rtspsrc_print_sdp_media (src, &g_array_index (msg->medias,
+              GstSDPMedia, i));
+    }
+  }
+  GST_LOG_OBJECT (src, "--------------------------------------------");
+}
diff --git a/gst/rtsp/gstrtspsrc.h b/gst/rtsp/gstrtspsrc.h
new file mode 100644
index 0000000..57921d2
--- /dev/null
+++ b/gst/rtsp/gstrtspsrc.h
@@ -0,0 +1,307 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *               <2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_RTSPSRC_H__
+#define __GST_RTSPSRC_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#include <gst/rtsp/rtsp.h>
+#include <gio/gio.h>
+
+#include "gstrtspext.h"
+
+#define GST_TYPE_RTSPSRC \
+  (gst_rtspsrc_get_type())
+#define GST_RTSPSRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTSPSRC,GstRTSPSrc))
+#define GST_RTSPSRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTSPSRC,GstRTSPSrcClass))
+#define GST_IS_RTSPSRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTSPSRC))
+#define GST_IS_RTSPSRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTSPSRC))
+#define GST_RTSPSRC_CAST(obj) \
+  ((GstRTSPSrc *)(obj))
+
+typedef struct _GstRTSPSrc GstRTSPSrc;
+typedef struct _GstRTSPSrcClass GstRTSPSrcClass;
+
+#define GST_RTSP_STATE_GET_LOCK(rtsp)    (&GST_RTSPSRC_CAST(rtsp)->state_rec_lock)
+#define GST_RTSP_STATE_LOCK(rtsp)        (g_rec_mutex_lock (GST_RTSP_STATE_GET_LOCK(rtsp)))
+#define GST_RTSP_STATE_UNLOCK(rtsp)      (g_rec_mutex_unlock (GST_RTSP_STATE_GET_LOCK(rtsp)))
+
+#define GST_RTSP_STREAM_GET_LOCK(rtsp)   (&GST_RTSPSRC_CAST(rtsp)->stream_rec_lock)
+#define GST_RTSP_STREAM_LOCK(rtsp)       (g_rec_mutex_lock (GST_RTSP_STREAM_GET_LOCK(rtsp)))
+#define GST_RTSP_STREAM_UNLOCK(rtsp)     (g_rec_mutex_unlock (GST_RTSP_STREAM_GET_LOCK(rtsp)))
+
+typedef struct _GstRTSPConnInfo GstRTSPConnInfo;
+
+struct _GstRTSPConnInfo {
+  gchar              *location;
+  GstRTSPUrl         *url;
+  gchar              *url_str;
+  GstRTSPConnection  *connection;
+  gboolean            connected;
+  gboolean            flushing;
+
+  GMutex              send_lock;
+  GMutex              recv_lock;
+};
+
+typedef struct _GstRTSPStream GstRTSPStream;
+
+struct _GstRTSPStream {
+  gint          id;
+
+  GstRTSPSrc   *parent; /* parent, no extra ref to parent is taken */
+
+  /* pad we expose or NULL when it does not have an actual pad */
+  GstPad       *srcpad;
+  GstFlowReturn last_ret;
+  gboolean      added;
+  gboolean      setup;
+  gboolean      skipped;
+  gboolean      eos;
+  gboolean      discont;
+  gboolean      need_caps;
+  gboolean      waiting_setup_response;
+
+  /* for interleaved mode */
+  guint8        channel[2];
+  GstPad       *channelpad[2];
+
+  /* our udp sources */
+  GstElement   *udpsrc[2];
+  GstPad       *blockedpad;
+  gulong        blockid;
+  gboolean      is_ipv6;
+
+  /* our udp sinks back to the server */
+  GstElement   *udpsink[2];
+  GstPad       *rtcppad;
+
+  /* fakesrc for sending dummy data */
+  GstElement   *fakesrc;
+
+  /* state */
+  guint         port;
+  gboolean      container;
+  gboolean      is_real;
+  guint8        default_pt;
+  GstRTSPProfile profile;
+  GArray       *ptmap;
+  /* original control url */
+  gchar        *control_url;
+  guint32       ssrc;
+  guint32       seqbase;
+  guint64       timebase;
+  GstElement   *srtpdec;
+  GstCaps      *srtcpparams;
+  GstElement   *srtpenc;
+  guint32       send_ssrc;
+
+  /* per stream connection */
+  GstRTSPConnInfo  conninfo;
+
+  /* session */
+  GObject      *session;
+
+  /* srtp key management */
+  GstMIKEYMessage *mikey;
+
+  /* bandwidth */
+  guint         as_bandwidth;
+  guint         rs_bandwidth;
+  guint         rr_bandwidth;
+
+  /* destination */
+  gchar        *destination;
+  gboolean      is_multicast;
+  guint         ttl;
+
+  /* A unique and stable id we will use for the stream start event */
+  gchar *stream_id;
+
+  GstStructure     *rtx_pt_map;
+};
+
+/**
+ * GstRTSPNatMethod:
+ * @GST_RTSP_NAT_NONE: none
+ * @GST_RTSP_NAT_DUMMY: send dummy packets
+ *
+ * Different methods for trying to traverse firewalls.
+ */
+typedef enum
+{
+  GST_RTSP_NAT_NONE,
+  GST_RTSP_NAT_DUMMY
+} GstRTSPNatMethod;
+
+struct _GstRTSPSrc {
+  GstBin           parent;
+
+  /* task and mutex for interleaved mode */
+  gboolean         interleaved;
+  GstTask         *task;
+  GRecMutex        stream_rec_lock;
+  GstSegment       segment;
+  gboolean         running;
+  gboolean         need_range;
+  gboolean         skip;
+  gint             free_channel;
+  gboolean         need_segment;
+  GstClockTime     base_time;
+
+  /* UDP mode loop */
+  gint             pending_cmd;
+  gint             busy_cmd;
+  gboolean         ignore_timeout;
+  gboolean         open_error;
+
+  /* mutex for protecting state changes */
+  GRecMutex        state_rec_lock;
+
+  GstSDPMessage   *sdp;
+  gboolean         from_sdp;
+  GList           *streams;
+  GstStructure    *props;
+  gboolean         need_activate;
+
+  /* properties */
+  GstRTSPLowerTrans protocols;
+  gboolean          debug;
+  guint             retry;
+  guint64           udp_timeout;
+  GTimeVal          tcp_timeout;
+  GTimeVal         *ptcp_timeout;
+  guint             latency;
+  gboolean          drop_on_latency;
+  guint64           connection_speed;
+  GstRTSPNatMethod  nat_method;
+  gboolean          do_rtcp;
+  gboolean          do_rtsp_keep_alive;
+  gchar            *proxy_host;
+  guint             proxy_port;
+  gchar            *proxy_user;        /* from url or property */
+  gchar            *proxy_passwd;      /* from url or property */
+  gchar            *prop_proxy_id;     /* set via property */
+  gchar            *prop_proxy_pw;     /* set via property */
+  guint             rtp_blocksize;
+  gchar            *user_id;
+  gchar            *user_pw;
+  gint              buffer_mode;
+  GstRTSPRange      client_port_range;
+  gint              udp_buffer_size;
+  gboolean          short_header;
+  guint             probation;
+  gboolean          udp_reconnect;
+  gchar            *multi_iface;
+  gboolean          ntp_sync;
+  gboolean          use_pipeline_clock;
+  GstStructure     *sdes;
+  GTlsCertificateFlags tls_validation_flags;
+  GTlsDatabase     *tls_database;
+  GTlsInteraction  *tls_interaction;
+  gboolean          do_retransmission;
+  gint              ntp_time_source;
+  gchar            *user_agent;
+  GstClockTime      max_rtcp_rtp_time_diff;
+  gboolean          rfc7273_sync;
+  guint64           max_ts_offset_adjustment;
+  gint64            max_ts_offset;
+  gboolean          max_ts_offset_is_set;
+
+  /* state */
+  GstRTSPState       state;
+  gchar             *content_base;
+  GstRTSPLowerTrans  cur_protocols;
+  gboolean           tried_url_auth;
+  gchar             *addr;
+  gboolean           need_redirect;
+  GstRTSPTimeRange  *range;
+  gchar             *control;
+  guint              next_port_num;
+  GstClock          *provided_clock;
+
+  /* supported methods */
+  gint               methods;
+
+  /* seekability
+   * -1.0 : Stream is not seekable
+   *  0.0 : seekable only to the beginning
+   * G_MAXFLOAT : Any value is possible
+   *
+   * Any other positive value indicates the longest duration
+   * between any two random access points
+   *  */
+  gfloat             seekable;
+  GstClockTime       last_pos;
+
+  /* session management */
+  GstElement      *manager;
+  gulong           manager_sig_id;
+  gulong           manager_ptmap_id;
+  gboolean         use_buffering;
+
+  GstRTSPConnInfo  conninfo;
+
+  /* a list of RTSP extensions as GstElement */
+  GstRTSPExtensionList  *extensions;
+
+  GstRTSPVersion default_version;
+  GstRTSPVersion version;
+};
+
+struct _GstRTSPSrcClass {
+  GstBinClass parent_class;
+};
+
+GType gst_rtspsrc_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_RTSPSRC_H__ */
diff --git a/gst/rtsp/meson.build b/gst/rtsp/meson.build
new file mode 100644
index 0000000..1fe8a7b
--- /dev/null
+++ b/gst/rtsp/meson.build
@@ -0,0 +1,15 @@
+rtsp_sources = [
+  'gstrtsp.c',
+  'gstrtspsrc.c',
+  'gstrtpdec.c',
+  'gstrtspext.c',
+]
+
+gstrtsp = library('gstrtsp',
+  rtsp_sources,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc, libsinc],
+  dependencies : [gstbase_dep, gio_dep, gstrtp_dep, gstrtsp_dep, gstsdp_dep, gstnet_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/shapewipe/Makefile.am b/gst/shapewipe/Makefile.am
new file mode 100644
index 0000000..2f3d938
--- /dev/null
+++ b/gst/shapewipe/Makefile.am
@@ -0,0 +1,9 @@
+plugin_LTLIBRARIES = libgstshapewipe.la
+
+libgstshapewipe_la_SOURCES = gstshapewipe.c
+
+libgstshapewipe_la_CFLAGS = $(GIO_CFLAGS) $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS)
+libgstshapewipe_la_LIBADD = $(GIO_LIBS) $(GST_LIBS) $(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_API_VERSION@
+libgstshapewipe_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstshapewipe.h
diff --git a/gst/shapewipe/gstshapewipe.c b/gst/shapewipe/gstshapewipe.c
new file mode 100644
index 0000000..3a0dfda
--- /dev/null
+++ b/gst/shapewipe/gstshapewipe.c
@@ -0,0 +1,1150 @@
+/* GStreamer
+ * Copyright (C) 2009,2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-shapewipe
+ *
+ * The shapewipe element provides custom transitions on video streams
+ * based on a grayscale bitmap. The state of the transition can be
+ * controlled by the position property and an optional blended border
+ * can be added by the border property.
+ *
+ * Transition bitmaps can be downloaded from the
+ * <ulink url="http://cinelerra.org/transitions.php">Cinelerra transition</ulink>
+ * page.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! video/x-raw,format=AYUV,width=640,height=480 ! shapewipe position=0.5 name=shape ! videomixer name=mixer ! videoconvert ! autovideosink     filesrc location=mask.png ! typefind ! decodebin ! videoconvert ! videoscale ! queue ! shape.mask_sink    videotestsrc pattern=snow ! video/x-raw,format=AYUV,width=640,height=480 ! queue ! mixer.
+ * ]| This pipeline adds the transition from mask.png with position 0.5 to an SMPTE test screen and snow.
+ * </refsect2>
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/gst.h>
+
+#include "gstshapewipe.h"
+
+static void gst_shape_wipe_finalize (GObject * object);
+static void gst_shape_wipe_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_shape_wipe_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+
+static void gst_shape_wipe_reset (GstShapeWipe * self);
+static void gst_shape_wipe_update_qos (GstShapeWipe * self, gdouble proportion,
+    GstClockTimeDiff diff, GstClockTime time);
+static void gst_shape_wipe_reset_qos (GstShapeWipe * self);
+static void gst_shape_wipe_read_qos (GstShapeWipe * self, gdouble * proportion,
+    GstClockTime * time);
+
+static GstStateChangeReturn gst_shape_wipe_change_state (GstElement * element,
+    GstStateChange transition);
+
+static GstFlowReturn gst_shape_wipe_video_sink_chain (GstPad * pad,
+    GstObject * parent, GstBuffer * buffer);
+static gboolean gst_shape_wipe_video_sink_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static gboolean gst_shape_wipe_video_sink_setcaps (GstShapeWipe * self,
+    GstCaps * caps);
+static GstCaps *gst_shape_wipe_video_sink_getcaps (GstShapeWipe * self,
+    GstPad * pad, GstCaps * filter);
+static gboolean gst_shape_wipe_video_sink_query (GstPad * pad,
+    GstObject * parent, GstQuery * query);
+static GstFlowReturn gst_shape_wipe_mask_sink_chain (GstPad * pad,
+    GstObject * parent, GstBuffer * buffer);
+static gboolean gst_shape_wipe_mask_sink_event (GstPad * pad,
+    GstObject * parent, GstEvent * event);
+static gboolean gst_shape_wipe_mask_sink_setcaps (GstShapeWipe * self,
+    GstCaps * caps);
+static GstCaps *gst_shape_wipe_mask_sink_getcaps (GstShapeWipe * self,
+    GstPad * pad, GstCaps * filter);
+static gboolean gst_shape_wipe_mask_sink_query (GstPad * pad,
+    GstObject * parent, GstQuery * query);
+static gboolean gst_shape_wipe_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static GstCaps *gst_shape_wipe_src_getcaps (GstPad * pad, GstCaps * filter);
+static gboolean gst_shape_wipe_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+
+enum
+{
+  PROP_0,
+  PROP_POSITION,
+  PROP_BORDER
+};
+
+#define DEFAULT_POSITION 0.0
+#define DEFAULT_BORDER 0.0
+
+static GstStaticPadTemplate video_sink_pad_template =
+GST_STATIC_PAD_TEMPLATE ("video_sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, ARGB, BGRA, ABGR, RGBA }")));
+
+static GstStaticPadTemplate mask_sink_pad_template =
+    GST_STATIC_PAD_TEMPLATE ("mask_sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-raw, "
+        "format = (string) GRAY8, "
+        "width = " GST_VIDEO_SIZE_RANGE ", "
+        "height = " GST_VIDEO_SIZE_RANGE ", " "framerate = 0/1 ; "
+        "video/x-raw, " "format = (string) " GST_VIDEO_NE (GRAY16) ", "
+        "width = " GST_VIDEO_SIZE_RANGE ", "
+        "height = " GST_VIDEO_SIZE_RANGE ", " "framerate = 0/1"));
+
+static GstStaticPadTemplate src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, ARGB, BGRA, ABGR, RGBA }")));
+
+GST_DEBUG_CATEGORY_STATIC (gst_shape_wipe_debug);
+#define GST_CAT_DEFAULT gst_shape_wipe_debug
+
+#define gst_shape_wipe_parent_class parent_class
+G_DEFINE_TYPE (GstShapeWipe, gst_shape_wipe, GST_TYPE_ELEMENT);
+
+static void
+gst_shape_wipe_class_init (GstShapeWipeClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->finalize = gst_shape_wipe_finalize;
+  gobject_class->set_property = gst_shape_wipe_set_property;
+  gobject_class->get_property = gst_shape_wipe_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_POSITION,
+      g_param_spec_float ("position", "Position", "Position of the mask",
+          0.0, 1.0, DEFAULT_POSITION,
+          G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (gobject_class, PROP_BORDER,
+      g_param_spec_float ("border", "Border", "Border of the mask",
+          0.0, 1.0, DEFAULT_BORDER,
+          G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_shape_wipe_change_state);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Shape Wipe transition filter",
+      "Filter/Editor/Video",
+      "Adds a shape wipe transition to a video stream",
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &video_sink_pad_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &mask_sink_pad_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &src_pad_template);
+}
+
+static void
+gst_shape_wipe_init (GstShapeWipe * self)
+{
+  self->video_sinkpad =
+      gst_pad_new_from_static_template (&video_sink_pad_template, "video_sink");
+  gst_pad_set_chain_function (self->video_sinkpad,
+      GST_DEBUG_FUNCPTR (gst_shape_wipe_video_sink_chain));
+  gst_pad_set_event_function (self->video_sinkpad,
+      GST_DEBUG_FUNCPTR (gst_shape_wipe_video_sink_event));
+  gst_pad_set_query_function (self->video_sinkpad,
+      GST_DEBUG_FUNCPTR (gst_shape_wipe_video_sink_query));
+  gst_element_add_pad (GST_ELEMENT (self), self->video_sinkpad);
+
+  self->mask_sinkpad =
+      gst_pad_new_from_static_template (&mask_sink_pad_template, "mask_sink");
+  gst_pad_set_chain_function (self->mask_sinkpad,
+      GST_DEBUG_FUNCPTR (gst_shape_wipe_mask_sink_chain));
+  gst_pad_set_event_function (self->mask_sinkpad,
+      GST_DEBUG_FUNCPTR (gst_shape_wipe_mask_sink_event));
+  gst_pad_set_query_function (self->mask_sinkpad,
+      GST_DEBUG_FUNCPTR (gst_shape_wipe_mask_sink_query));
+  gst_element_add_pad (GST_ELEMENT (self), self->mask_sinkpad);
+
+  self->srcpad = gst_pad_new_from_static_template (&src_pad_template, "src");
+  gst_pad_set_event_function (self->srcpad,
+      GST_DEBUG_FUNCPTR (gst_shape_wipe_src_event));
+  gst_pad_set_query_function (self->srcpad,
+      GST_DEBUG_FUNCPTR (gst_shape_wipe_src_query));
+  gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
+
+  g_mutex_init (&self->mask_mutex);
+  g_cond_init (&self->mask_cond);
+
+  gst_shape_wipe_reset (self);
+}
+
+static void
+gst_shape_wipe_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstShapeWipe *self = GST_SHAPE_WIPE (object);
+
+  switch (prop_id) {
+    case PROP_POSITION:
+      g_value_set_float (value, self->mask_position);
+      break;
+    case PROP_BORDER:
+      g_value_set_float (value, self->mask_border);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_shape_wipe_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstShapeWipe *self = GST_SHAPE_WIPE (object);
+
+  switch (prop_id) {
+    case PROP_POSITION:{
+      gfloat f = g_value_get_float (value);
+
+      GST_LOG_OBJECT (self, "Setting mask position: %f", f);
+      self->mask_position = f;
+      break;
+    }
+    case PROP_BORDER:{
+      gfloat f = g_value_get_float (value);
+
+      GST_LOG_OBJECT (self, "Setting mask border: %f", f);
+      self->mask_border = f;
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_shape_wipe_finalize (GObject * object)
+{
+  GstShapeWipe *self = GST_SHAPE_WIPE (object);
+
+  gst_shape_wipe_reset (self);
+
+  g_cond_clear (&self->mask_cond);
+  g_mutex_clear (&self->mask_mutex);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_shape_wipe_reset (GstShapeWipe * self)
+{
+  GST_DEBUG_OBJECT (self, "Resetting internal state");
+
+  if (self->mask)
+    gst_buffer_unref (self->mask);
+  self->mask = NULL;
+
+  g_mutex_lock (&self->mask_mutex);
+  g_cond_signal (&self->mask_cond);
+  g_mutex_unlock (&self->mask_mutex);
+
+  gst_video_info_init (&self->vinfo);
+  gst_video_info_init (&self->minfo);
+  self->mask_bpp = 0;
+
+  gst_segment_init (&self->segment, GST_FORMAT_TIME);
+
+  gst_shape_wipe_reset_qos (self);
+  self->frame_duration = 0;
+}
+
+static gboolean
+gst_shape_wipe_video_sink_setcaps (GstShapeWipe * self, GstCaps * caps)
+{
+  gboolean ret = TRUE;
+  GstVideoInfo info;
+
+  GST_DEBUG_OBJECT (self, "Setting caps: %" GST_PTR_FORMAT, caps);
+
+  if (!gst_video_info_from_caps (&info, caps))
+    goto invalid_caps;
+
+  if ((self->vinfo.width != info.width || self->vinfo.height != info.height) &&
+      self->vinfo.width > 0 && self->vinfo.height > 0) {
+    g_mutex_lock (&self->mask_mutex);
+    if (self->mask)
+      gst_buffer_unref (self->mask);
+    self->mask = NULL;
+    g_mutex_unlock (&self->mask_mutex);
+  }
+
+
+  if (info.fps_n != 0)
+    self->frame_duration =
+        gst_util_uint64_scale (GST_SECOND, info.fps_d, info.fps_n);
+  else
+    self->frame_duration = 0;
+
+  self->vinfo = info;
+
+  ret = gst_pad_set_caps (self->srcpad, caps);
+
+  return ret;
+
+  /* ERRORS */
+invalid_caps:
+  {
+    GST_ERROR_OBJECT (self, "Invalid caps");
+    return FALSE;
+  }
+}
+
+static GstCaps *
+gst_shape_wipe_video_sink_getcaps (GstShapeWipe * self, GstPad * pad,
+    GstCaps * filter)
+{
+  GstCaps *templ, *ret, *tmp;
+
+  ret = gst_pad_get_current_caps (pad);
+  if (ret != NULL)
+    return ret;
+
+  templ = gst_pad_get_pad_template_caps (pad);
+  tmp = gst_pad_peer_query_caps (self->srcpad, NULL);
+  if (tmp) {
+    ret = gst_caps_intersect (tmp, templ);
+    gst_caps_unref (templ);
+    gst_caps_unref (tmp);
+  } else {
+    ret = templ;
+  }
+
+  GST_LOG_OBJECT (pad, "srcpad accepted caps: %" GST_PTR_FORMAT, ret);
+
+  if (gst_caps_is_empty (ret))
+    goto done;
+
+  tmp = gst_pad_peer_query_caps (pad, NULL);
+
+  GST_LOG_OBJECT (pad, "peerpad accepted caps: %" GST_PTR_FORMAT, tmp);
+  if (tmp) {
+    GstCaps *intersection;
+
+    intersection = gst_caps_intersect (tmp, ret);
+    gst_caps_unref (tmp);
+    gst_caps_unref (ret);
+    ret = intersection;
+  }
+
+  GST_LOG_OBJECT (pad, "intersection: %" GST_PTR_FORMAT, tmp);
+
+  if (gst_caps_is_empty (ret))
+    goto done;
+
+  if (self->vinfo.height && self->vinfo.width) {
+    guint i, n;
+
+    ret = gst_caps_make_writable (ret);
+    n = gst_caps_get_size (ret);
+    for (i = 0; i < n; i++) {
+      GstStructure *s = gst_caps_get_structure (ret, i);
+
+      gst_structure_set (s, "width", G_TYPE_INT, self->vinfo.width, "height",
+          G_TYPE_INT, self->vinfo.height, NULL);
+    }
+  }
+
+  tmp = gst_pad_peer_query_caps (self->mask_sinkpad, NULL);
+
+  GST_LOG_OBJECT (pad, "mask accepted caps: %" GST_PTR_FORMAT, tmp);
+  if (tmp) {
+    GstCaps *intersection, *tmp2;
+    guint i, n;
+
+    tmp2 = gst_pad_get_pad_template_caps (self->mask_sinkpad);
+    intersection = gst_caps_intersect (tmp, tmp2);
+    gst_caps_unref (tmp);
+    gst_caps_unref (tmp2);
+    tmp = intersection;
+
+    tmp = gst_caps_make_writable (tmp);
+    n = gst_caps_get_size (tmp);
+
+    for (i = 0; i < n; i++) {
+      GstStructure *s = gst_caps_get_structure (tmp, i);
+
+      gst_structure_remove_fields (s, "format", "framerate", NULL);
+      gst_structure_set_name (s, "video/x-raw");
+    }
+
+    intersection = gst_caps_intersect (tmp, ret);
+    gst_caps_unref (tmp);
+    gst_caps_unref (ret);
+    ret = intersection;
+  }
+done:
+  GST_LOG_OBJECT (pad, "Returning caps: %" GST_PTR_FORMAT, ret);
+
+  return ret;
+}
+
+static gboolean
+gst_shape_wipe_mask_sink_setcaps (GstShapeWipe * self, GstCaps * caps)
+{
+  gboolean ret = TRUE;
+  gint width, height, bpp;
+  GstVideoInfo info;
+
+  GST_DEBUG_OBJECT (self, "Setting caps: %" GST_PTR_FORMAT, caps);
+
+  if (!gst_video_info_from_caps (&info, caps)) {
+    ret = FALSE;
+    goto done;
+  }
+
+  width = GST_VIDEO_INFO_WIDTH (&info);
+  height = GST_VIDEO_INFO_HEIGHT (&info);
+  bpp = GST_VIDEO_INFO_COMP_DEPTH (&info, 0);
+
+  if ((self->vinfo.width != width || self->vinfo.height != height) &&
+      self->vinfo.width > 0 && self->vinfo.height > 0) {
+    GST_ERROR_OBJECT (self, "Mask caps must have the same width/height "
+        "as the video caps");
+    ret = FALSE;
+    goto done;
+  }
+
+  self->mask_bpp = bpp;
+  self->minfo = info;
+
+done:
+  return ret;
+}
+
+static GstCaps *
+gst_shape_wipe_mask_sink_getcaps (GstShapeWipe * self, GstPad * pad,
+    GstCaps * filter)
+{
+  GstCaps *ret, *tmp, *tcaps;
+  guint i, n;
+
+  ret = gst_pad_get_current_caps (pad);
+  if (ret != NULL)
+    return ret;
+
+  tcaps = gst_pad_get_pad_template_caps (self->video_sinkpad);
+  tmp = gst_pad_peer_query_caps (self->video_sinkpad, NULL);
+  if (tmp) {
+    ret = gst_caps_intersect (tmp, tcaps);
+    gst_caps_unref (tcaps);
+    gst_caps_unref (tmp);
+  } else {
+    ret = tcaps;
+  }
+
+  GST_LOG_OBJECT (pad, "video sink accepted caps: %" GST_PTR_FORMAT, ret);
+
+  if (gst_caps_is_empty (ret))
+    goto done;
+
+  tmp = gst_pad_peer_query_caps (self->srcpad, NULL);
+  GST_LOG_OBJECT (pad, "srcpad accepted caps: %" GST_PTR_FORMAT, ret);
+
+  if (tmp) {
+    GstCaps *intersection;
+
+    intersection = gst_caps_intersect (ret, tmp);
+    gst_caps_unref (ret);
+    gst_caps_unref (tmp);
+    ret = intersection;
+  }
+
+  GST_LOG_OBJECT (pad, "intersection: %" GST_PTR_FORMAT, ret);
+
+  if (gst_caps_is_empty (ret))
+    goto done;
+
+  ret = gst_caps_make_writable (ret);
+  n = gst_caps_get_size (ret);
+  tmp = gst_caps_new_empty ();
+  for (i = 0; i < n; i++) {
+    GstStructure *s = gst_caps_get_structure (ret, i);
+    GstStructure *t;
+
+    gst_structure_set_name (s, "video/x-raw");
+    gst_structure_remove_fields (s, "format", "framerate", NULL);
+
+    if (self->vinfo.width && self->vinfo.height)
+      gst_structure_set (s, "width", G_TYPE_INT, self->vinfo.width, "height",
+          G_TYPE_INT, self->vinfo.height, NULL);
+
+    gst_structure_set (s, "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
+
+    t = gst_structure_copy (s);
+
+    gst_structure_set (s, "format", G_TYPE_STRING, GST_VIDEO_NE (GRAY16), NULL);
+    gst_structure_set (t, "format", G_TYPE_STRING, "GRAY8", NULL);
+
+    gst_caps_append_structure (tmp, t);
+  }
+  gst_caps_append (ret, tmp);
+
+  tmp = gst_pad_peer_query_caps (pad, NULL);
+  GST_LOG_OBJECT (pad, "peer accepted caps: %" GST_PTR_FORMAT, tmp);
+
+  if (tmp) {
+    GstCaps *intersection;
+
+    intersection = gst_caps_intersect (tmp, ret);
+    gst_caps_unref (tmp);
+    gst_caps_unref (ret);
+    ret = intersection;
+  }
+
+done:
+  GST_LOG_OBJECT (pad, "Returning caps: %" GST_PTR_FORMAT, ret);
+
+  return ret;
+}
+
+static GstCaps *
+gst_shape_wipe_src_getcaps (GstPad * pad, GstCaps * filter)
+{
+  GstShapeWipe *self = GST_SHAPE_WIPE (gst_pad_get_parent (pad));
+  GstCaps *templ, *ret, *tmp;
+
+  ret = gst_pad_get_current_caps (pad);
+  if (ret != NULL)
+    return ret;
+
+  ret = gst_pad_get_current_caps (self->video_sinkpad);
+  if (ret != NULL)
+    return ret;
+
+  templ = gst_pad_get_pad_template_caps (self->video_sinkpad);
+  tmp = gst_pad_peer_query_caps (self->video_sinkpad, NULL);
+  if (tmp) {
+    ret = gst_caps_intersect (tmp, templ);
+    gst_caps_unref (templ);
+    gst_caps_unref (tmp);
+  } else {
+    ret = templ;
+  }
+
+  GST_LOG_OBJECT (pad, "video sink accepted caps: %" GST_PTR_FORMAT, ret);
+
+  if (gst_caps_is_empty (ret))
+    goto done;
+
+  tmp = gst_pad_peer_query_caps (pad, NULL);
+  GST_LOG_OBJECT (pad, "peer accepted caps: %" GST_PTR_FORMAT, ret);
+  if (tmp) {
+    GstCaps *intersection;
+
+    intersection = gst_caps_intersect (tmp, ret);
+    gst_caps_unref (tmp);
+    gst_caps_unref (ret);
+    ret = intersection;
+  }
+
+  GST_LOG_OBJECT (pad, "intersection: %" GST_PTR_FORMAT, ret);
+
+  if (gst_caps_is_empty (ret))
+    goto done;
+
+  if (self->vinfo.height && self->vinfo.width) {
+    guint i, n;
+
+    ret = gst_caps_make_writable (ret);
+    n = gst_caps_get_size (ret);
+    for (i = 0; i < n; i++) {
+      GstStructure *s = gst_caps_get_structure (ret, i);
+
+      gst_structure_set (s, "width", G_TYPE_INT, self->vinfo.width, "height",
+          G_TYPE_INT, self->vinfo.height, NULL);
+    }
+  }
+
+  tmp = gst_pad_peer_query_caps (self->mask_sinkpad, NULL);
+  GST_LOG_OBJECT (pad, "mask sink accepted caps: %" GST_PTR_FORMAT, ret);
+  if (tmp) {
+    GstCaps *intersection, *tmp2;
+    guint i, n;
+
+    tmp2 = gst_pad_get_pad_template_caps (self->mask_sinkpad);
+    intersection = gst_caps_intersect (tmp, tmp2);
+    gst_caps_unref (tmp);
+    gst_caps_unref (tmp2);
+
+    tmp = gst_caps_make_writable (intersection);
+    n = gst_caps_get_size (tmp);
+
+    for (i = 0; i < n; i++) {
+      GstStructure *s = gst_caps_get_structure (tmp, i);
+
+      gst_structure_remove_fields (s, "format", "framerate", NULL);
+      gst_structure_set_name (s, "video/x-raw");
+    }
+
+    intersection = gst_caps_intersect (tmp, ret);
+    gst_caps_unref (tmp);
+    gst_caps_unref (ret);
+    ret = intersection;
+  }
+
+done:
+
+  gst_object_unref (self);
+
+  GST_LOG_OBJECT (pad, "Returning caps: %" GST_PTR_FORMAT, ret);
+
+  return ret;
+}
+
+static gboolean
+gst_shape_wipe_video_sink_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  GstShapeWipe *self = (GstShapeWipe *) parent;
+  gboolean ret;
+
+  GST_LOG_OBJECT (pad, "Handling query of type '%s'",
+      gst_query_type_get_name (GST_QUERY_TYPE (query)));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *filter, *caps;
+
+      gst_query_parse_caps (query, &filter);
+      caps = gst_shape_wipe_video_sink_getcaps (self, pad, filter);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+      ret = TRUE;
+      break;
+    }
+    default:
+      ret = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_shape_wipe_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  GstShapeWipe *self = GST_SHAPE_WIPE (parent);
+  gboolean ret;
+
+  GST_LOG_OBJECT (pad, "Handling query of type '%s'",
+      gst_query_type_get_name (GST_QUERY_TYPE (query)));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *filter, *caps;
+
+      gst_query_parse_caps (query, &filter);
+      caps = gst_shape_wipe_src_getcaps (pad, filter);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+      ret = TRUE;
+      break;
+    }
+    default:
+      ret = gst_pad_peer_query (self->video_sinkpad, query);
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_shape_wipe_update_qos (GstShapeWipe * self, gdouble proportion,
+    GstClockTimeDiff diff, GstClockTime timestamp)
+{
+  GST_OBJECT_LOCK (self);
+  self->proportion = proportion;
+  if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) {
+    if (G_UNLIKELY (diff > 0))
+      self->earliest_time = timestamp + 2 * diff + self->frame_duration;
+    else
+      self->earliest_time = timestamp + diff;
+  } else {
+    self->earliest_time = GST_CLOCK_TIME_NONE;
+  }
+  GST_OBJECT_UNLOCK (self);
+}
+
+static void
+gst_shape_wipe_reset_qos (GstShapeWipe * self)
+{
+  gst_shape_wipe_update_qos (self, 0.5, 0, GST_CLOCK_TIME_NONE);
+}
+
+static void
+gst_shape_wipe_read_qos (GstShapeWipe * self, gdouble * proportion,
+    GstClockTime * time)
+{
+  GST_OBJECT_LOCK (self);
+  *proportion = self->proportion;
+  *time = self->earliest_time;
+  GST_OBJECT_UNLOCK (self);
+}
+
+/* Perform qos calculations before processing the next frame. Returns TRUE if
+ * the frame should be processed, FALSE if the frame can be dropped entirely */
+static gboolean
+gst_shape_wipe_do_qos (GstShapeWipe * self, GstClockTime timestamp)
+{
+  GstClockTime qostime, earliest_time;
+  gdouble proportion;
+
+  /* no timestamp, can't do QoS => process frame */
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
+    GST_LOG_OBJECT (self, "invalid timestamp, can't do QoS, process frame");
+    return TRUE;
+  }
+
+  /* get latest QoS observation values */
+  gst_shape_wipe_read_qos (self, &proportion, &earliest_time);
+
+  /* skip qos if we have no observation (yet) => process frame */
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
+    GST_LOG_OBJECT (self, "no observation yet, process frame");
+    return TRUE;
+  }
+
+  /* qos is done on running time */
+  qostime = gst_segment_to_running_time (&self->segment, GST_FORMAT_TIME,
+      timestamp);
+
+  /* see how our next timestamp relates to the latest qos timestamp */
+  GST_LOG_OBJECT (self, "qostime %" GST_TIME_FORMAT ", earliest %"
+      GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
+
+  if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
+    GST_DEBUG_OBJECT (self, "we are late, drop frame");
+    return FALSE;
+  }
+
+  GST_LOG_OBJECT (self, "process frame");
+  return TRUE;
+}
+
+#define CREATE_ARGB_FUNCTIONS(depth, name, shift, a, r, g, b) \
+static void \
+gst_shape_wipe_blend_##name##_##depth (GstShapeWipe * self, GstVideoFrame * inframe, \
+    GstVideoFrame * maskframe, GstVideoFrame * outframe) \
+{ \
+  const guint##depth *mask = (const guint##depth *) GST_VIDEO_FRAME_PLANE_DATA (maskframe, 0); \
+  const guint8 *input = (const guint8 *) GST_VIDEO_FRAME_PLANE_DATA (inframe, 0); \
+  guint8 *output = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (outframe, 0); \
+  guint i, j; \
+  gint width = GST_VIDEO_FRAME_WIDTH (inframe); \
+  gint height = GST_VIDEO_FRAME_HEIGHT (inframe); \
+  guint mask_increment = ((depth == 16) ? GST_ROUND_UP_2 (width) : \
+                           GST_ROUND_UP_4 (width)) - width; \
+  gfloat position = self->mask_position; \
+  gfloat low = position - (self->mask_border / 2.0f); \
+  gfloat high = position + (self->mask_border / 2.0f); \
+  guint32 low_i, high_i, round_i; \
+  \
+  if (low < 0.0f) { \
+    high = 0.0f; \
+    low = 0.0f; \
+  } \
+  \
+  if (high > 1.0f) { \
+    low = 1.0f; \
+    high = 1.0f; \
+  } \
+  \
+  low_i = low * 65536; \
+  high_i = high * 65536; \
+  round_i = (high_i - low_i) >> 1; \
+  \
+  for (i = 0; i < height; i++) { \
+    for (j = 0; j < width; j++) { \
+      guint32 in = *mask << shift; \
+      \
+      if (in < low_i) { \
+        output[a] = 0x00;       /* A */ \
+        output[r] = input[r];   /* R */ \
+        output[g] = input[g];   /* G */ \
+        output[b] = input[b];   /* B */ \
+      } else if (in >= high_i) { \
+        output[a] = input[a];   /* A */ \
+        output[r] = input[r];   /* R */ \
+        output[g] = input[g];   /* G */ \
+        output[b] = input[b];   /* B */ \
+      } else { \
+        guint32 val; \
+        /* Note: This will never overflow or be larger than 255! */ \
+        val = (((in - low_i) << 16) + round_i) / (high_i - low_i); \
+        val = (val * input[a] + 32768) >> 16; \
+        \
+        output[a] = val;        /* A */ \
+        output[r] = input[r];   /* R */ \
+        output[g] = input[g];   /* G */ \
+        output[b] = input[b];   /* B */ \
+      } \
+      \
+      mask++; \
+      input += 4; \
+      output += 4; \
+    } \
+    mask += mask_increment; \
+  } \
+}
+
+CREATE_ARGB_FUNCTIONS (16, argb, 0, 0, 1, 2, 3);
+CREATE_ARGB_FUNCTIONS (8, argb, 8, 0, 1, 2, 3);
+
+CREATE_ARGB_FUNCTIONS (16, bgra, 0, 3, 2, 1, 0);
+CREATE_ARGB_FUNCTIONS (8, bgra, 8, 3, 2, 1, 0);
+
+static GstFlowReturn
+gst_shape_wipe_video_sink_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer)
+{
+  GstShapeWipe *self = GST_SHAPE_WIPE (parent);
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBuffer *mask = NULL, *outbuf = NULL;
+  GstClockTime timestamp;
+  GstVideoFrame inframe, outframe, maskframe;
+
+  if (G_UNLIKELY (GST_VIDEO_INFO_FORMAT (&self->vinfo) ==
+          GST_VIDEO_FORMAT_UNKNOWN))
+    goto not_negotiated;
+
+  timestamp = GST_BUFFER_TIMESTAMP (buffer);
+  timestamp =
+      gst_segment_to_stream_time (&self->segment, GST_FORMAT_TIME, timestamp);
+
+  if (GST_CLOCK_TIME_IS_VALID (timestamp))
+    gst_object_sync_values (GST_OBJECT (self), timestamp);
+
+  GST_LOG_OBJECT (self,
+      "Blending buffer with timestamp %" GST_TIME_FORMAT " at position %f",
+      GST_TIME_ARGS (timestamp), self->mask_position);
+
+  g_mutex_lock (&self->mask_mutex);
+  if (self->shutdown)
+    goto shutdown;
+
+  if (!self->mask)
+    g_cond_wait (&self->mask_cond, &self->mask_mutex);
+
+  if (self->mask == NULL || self->shutdown) {
+    goto shutdown;
+  } else {
+    mask = gst_buffer_ref (self->mask);
+  }
+  g_mutex_unlock (&self->mask_mutex);
+
+  if (!gst_shape_wipe_do_qos (self, GST_BUFFER_TIMESTAMP (buffer)))
+    goto qos;
+
+  /* Will blend inplace if buffer is writable */
+  outbuf = gst_buffer_make_writable (buffer);
+  gst_video_frame_map (&outframe, &self->vinfo, outbuf, GST_MAP_READWRITE);
+  gst_video_frame_map (&inframe, &self->vinfo, outbuf, GST_MAP_READ);
+
+  gst_video_frame_map (&maskframe, &self->minfo, mask, GST_MAP_READ);
+
+  switch (GST_VIDEO_INFO_FORMAT (&self->vinfo)) {
+    case GST_VIDEO_FORMAT_AYUV:
+    case GST_VIDEO_FORMAT_ARGB:
+    case GST_VIDEO_FORMAT_ABGR:
+      if (self->mask_bpp == 16)
+        gst_shape_wipe_blend_argb_16 (self, &inframe, &maskframe, &outframe);
+      else
+        gst_shape_wipe_blend_argb_8 (self, &inframe, &maskframe, &outframe);
+      break;
+    case GST_VIDEO_FORMAT_BGRA:
+    case GST_VIDEO_FORMAT_RGBA:
+      if (self->mask_bpp == 16)
+        gst_shape_wipe_blend_bgra_16 (self, &inframe, &maskframe, &outframe);
+      else
+        gst_shape_wipe_blend_bgra_8 (self, &inframe, &maskframe, &outframe);
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+
+  gst_video_frame_unmap (&outframe);
+  gst_video_frame_unmap (&inframe);
+
+  gst_video_frame_unmap (&maskframe);
+
+  gst_buffer_unref (mask);
+
+  ret = gst_pad_push (self->srcpad, outbuf);
+  if (G_UNLIKELY (ret != GST_FLOW_OK))
+    goto push_failed;
+
+  return ret;
+
+  /* Errors */
+not_negotiated:
+  {
+    GST_ERROR_OBJECT (self, "No valid caps yet");
+    gst_buffer_unref (buffer);
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+shutdown:
+  {
+    GST_DEBUG_OBJECT (self, "Shutting down");
+    gst_buffer_unref (buffer);
+    return GST_FLOW_FLUSHING;
+  }
+qos:
+  {
+    GST_DEBUG_OBJECT (self, "Dropping buffer because of QoS");
+    gst_buffer_unref (buffer);
+    gst_buffer_unref (mask);
+    return GST_FLOW_OK;
+  }
+push_failed:
+  {
+    if (ret != GST_FLOW_FLUSHING)
+      GST_ERROR_OBJECT (self, "Pushing buffer downstream failed: %s",
+          gst_flow_get_name (ret));
+    return ret;
+  }
+}
+
+static GstFlowReturn
+gst_shape_wipe_mask_sink_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer)
+{
+  GstShapeWipe *self = GST_SHAPE_WIPE (parent);
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  g_mutex_lock (&self->mask_mutex);
+  GST_DEBUG_OBJECT (self, "Setting new mask buffer: %" GST_PTR_FORMAT, buffer);
+
+  gst_buffer_replace (&self->mask, buffer);
+  g_cond_signal (&self->mask_cond);
+  g_mutex_unlock (&self->mask_mutex);
+
+  gst_buffer_unref (buffer);
+
+  return ret;
+}
+
+static GstStateChangeReturn
+gst_shape_wipe_change_state (GstElement * element, GstStateChange transition)
+{
+  GstShapeWipe *self = GST_SHAPE_WIPE (element);
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      self->shutdown = FALSE;
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      /* Unblock video sink chain function */
+      g_mutex_lock (&self->mask_mutex);
+      self->shutdown = TRUE;
+      g_cond_signal (&self->mask_cond);
+      g_mutex_unlock (&self->mask_mutex);
+      break;
+    default:
+      break;
+  }
+
+  if (GST_ELEMENT_CLASS (parent_class)->change_state)
+    ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_shape_wipe_reset (self);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_shape_wipe_video_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstShapeWipe *self = GST_SHAPE_WIPE (parent);
+  gboolean ret;
+
+  GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      ret = gst_shape_wipe_video_sink_setcaps (self, caps);
+      gst_event_unref (event);
+      break;
+    }
+    case GST_EVENT_SEGMENT:
+    {
+      GstSegment seg;
+
+      gst_event_copy_segment (event, &seg);
+      if (seg.format == GST_FORMAT_TIME) {
+        GST_DEBUG_OBJECT (pad,
+            "Got SEGMENT event in GST_FORMAT_TIME %" GST_PTR_FORMAT, &seg);
+        self->segment = seg;
+      } else {
+        gst_segment_init (&self->segment, GST_FORMAT_TIME);
+      }
+    }
+      /* fall through */
+    case GST_EVENT_FLUSH_STOP:
+      gst_shape_wipe_reset_qos (self);
+      /* fall through */
+    default:
+      ret = gst_pad_push_event (self->srcpad, event);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_shape_wipe_mask_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstShapeWipe *self = GST_SHAPE_WIPE (parent);
+
+  GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      gst_shape_wipe_mask_sink_setcaps (self, caps);
+      break;
+    }
+    case GST_EVENT_FLUSH_STOP:
+      g_mutex_lock (&self->mask_mutex);
+      gst_buffer_replace (&self->mask, NULL);
+      g_mutex_unlock (&self->mask_mutex);
+      break;
+    default:
+      break;
+  }
+
+  /* Dropping all events here */
+  gst_event_unref (event);
+
+  return TRUE;
+}
+
+static gboolean
+gst_shape_wipe_mask_sink_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  GstShapeWipe *self = GST_SHAPE_WIPE (parent);
+  gboolean ret;
+
+  GST_LOG_OBJECT (pad, "Handling query of type '%s'",
+      gst_query_type_get_name (GST_QUERY_TYPE (query)));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *filter, *caps;
+
+      gst_query_parse_caps (query, &filter);
+      caps = gst_shape_wipe_mask_sink_getcaps (self, pad, filter);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+      ret = TRUE;
+      break;
+    }
+    default:
+      ret = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+
+  return ret;
+}
+
+
+static gboolean
+gst_shape_wipe_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstShapeWipe *self = GST_SHAPE_WIPE (parent);
+  gboolean ret;
+
+  GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_QOS:{
+      GstQOSType type;
+      GstClockTimeDiff diff;
+      GstClockTime timestamp;
+      gdouble proportion;
+
+      gst_event_parse_qos (event, &type, &proportion, &diff, &timestamp);
+
+      gst_shape_wipe_update_qos (self, proportion, diff, timestamp);
+    }
+      /* fall through */
+    default:
+      ret = gst_pad_push_event (self->video_sinkpad, event);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_shape_wipe_debug, "shapewipe", 0,
+      "shapewipe element");
+
+  if (!gst_element_register (plugin, "shapewipe", GST_RANK_NONE,
+          GST_TYPE_SHAPE_WIPE))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    shapewipe,
+    "Shape Wipe transition filter",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/shapewipe/gstshapewipe.h b/gst/shapewipe/gstshapewipe.h
new file mode 100644
index 0000000..66731ce
--- /dev/null
+++ b/gst/shapewipe/gstshapewipe.h
@@ -0,0 +1,81 @@
+/* GStreamer
+ * Copyright (C) 2009,2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_SHAPE_WIPE_H__
+#define __GST_SHAPE_WIPE_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SHAPE_WIPE \
+  (gst_shape_wipe_get_type())
+#define GST_SHAPE_WIPE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SHAPE_WIPE,GstShapeWipe))
+#define GST_SHAPE_WIPE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SHAPE_WIPE,GstShapeWipeClass))
+#define GST_SHAPE_WIPE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_SHAPE_WIPE,GstShapeWipeClass))
+#define GST_IS_SHAPE_WIPE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SHAPE_WIPE))
+#define GST_IS_SHAPE_WIPE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SHAPE_WIPE))
+
+typedef struct _GstShapeWipe GstShapeWipe;
+typedef struct _GstShapeWipeClass GstShapeWipeClass;
+
+struct _GstShapeWipe
+{
+  GstElement parent;
+
+  /* private */
+  GstPad *video_sinkpad;
+  GstPad *mask_sinkpad;
+
+  GstPad *srcpad;
+
+  GstSegment segment;
+
+  GstBuffer *mask;
+  gfloat mask_position;
+  gfloat mask_border;
+  GMutex mask_mutex;
+  GCond mask_cond;
+  gint mask_bpp;
+
+  GstVideoInfo vinfo;
+  GstVideoInfo minfo;
+
+  gboolean shutdown;
+
+  gdouble proportion;
+  GstClockTime earliest_time;
+  GstClockTime frame_duration;
+};
+
+struct _GstShapeWipeClass
+{
+  GstElementClass parent_class;
+};
+
+GType gst_shape_wipe_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_SHAPE_WIPE_H__ */
diff --git a/gst/shapewipe/meson.build b/gst/shapewipe/meson.build
new file mode 100644
index 0000000..ecb3cdf
--- /dev/null
+++ b/gst/shapewipe/meson.build
@@ -0,0 +1,8 @@
+gstshapewipe = library('gstshapewipe',
+  'gstshapewipe.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gio_dep, gst_dep, gstvideo_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/smpte/Makefile.am b/gst/smpte/Makefile.am
new file mode 100644
index 0000000..d5111b2
--- /dev/null
+++ b/gst/smpte/Makefile.am
@@ -0,0 +1,10 @@
+plugin_LTLIBRARIES = libgstsmpte.la
+
+libgstsmpte_la_SOURCES = gstsmpte.c gstmask.c barboxwipes.c paint.c gstsmptealpha.c plugin.c
+
+noinst_HEADERS = gstsmpte.h gstmask.h paint.h gstsmptealpha.h
+
+libgstsmpte_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+libgstsmpte_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(LIBM) \
+			-lgstvideo-$(GST_API_VERSION) 
+libgstsmpte_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
diff --git a/gst/smpte/barboxwipes.c b/gst/smpte/barboxwipes.c
new file mode 100644
index 0000000..7855eaa
--- /dev/null
+++ b/gst/smpte/barboxwipes.c
@@ -0,0 +1,957 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "paint.h"
+#include "gstmask.h"
+
+enum
+{
+  BOX_VERTICAL = 1,
+  BOX_HORIZONTAL = 2,
+  BOX_CLOCK = 3,
+  TRIGANLE_LINEAR = 4
+};
+
+static const gint boxes_1b[][7] = {
+#define WIPE_B1_1       0
+  {BOX_VERTICAL, 0, 0, 0, 1, 1, 1},
+#define WIPE_B1_2       1
+  {BOX_HORIZONTAL, 0, 0, 0, 1, 1, 1}
+};
+
+static const gint boxes_2b[][7 * 2] = {
+#define WIPE_B2_21      0
+  {BOX_VERTICAL, 0, 0, 1, 1, 2, 0,
+      BOX_VERTICAL, 1, 0, 0, 2, 2, 1},
+#define WIPE_B2_22      1
+  {BOX_HORIZONTAL, 0, 0, 1, 2, 1, 0,
+      BOX_HORIZONTAL, 0, 1, 0, 2, 2, 1},
+};
+
+static const gint box_clock_1b[][1 * 10] = {
+#define WIPE_B1_241     0
+  {BOX_CLOCK, 0, 0, 0, 1, 0, 0, 0, 1, 1},
+#define WIPE_B1_242     1
+  {BOX_CLOCK, 0, 1, 0, 1, 1, 0, 0, 0, 1},
+#define WIPE_B1_243     2
+  {BOX_CLOCK, 1, 1, 0, 0, 1, 0, 1, 0, 1},
+#define WIPE_B1_244     3
+  {BOX_CLOCK, 1, 0, 0, 0, 0, 0, 1, 1, 1},
+};
+
+#define WIPE_B2_221     0
+static const gint box_clock_2b[][2 * 10] = {
+#define WIPE_B2_221     0
+  {BOX_CLOCK, 1, 0, 0, 2, 0, 0, 1, 2, 1,
+      BOX_CLOCK, 1, 0, 0, 1, 2, 1, 0, 0, 2},
+#define WIPE_B2_222     1
+  {BOX_CLOCK, 2, 1, 0, 2, 2, 0, 0, 1, 1,
+      BOX_CLOCK, 2, 1, 0, 0, 1, 1, 2, 0, 2},
+#define WIPE_B2_223     2
+  {BOX_CLOCK, 1, 2, 0, 0, 2, 0, 1, 0, 1,
+      BOX_CLOCK, 1, 2, 0, 1, 0, 1, 2, 2, 2},
+#define WIPE_B2_224     3
+  {BOX_CLOCK, 0, 1, 0, 0, 0, 0, 2, 1, 1,
+      BOX_CLOCK, 0, 1, 0, 2, 1, 1, 0, 2, 2},
+#define WIPE_B2_225     4
+  {BOX_CLOCK, 1, 0, 0, 2, 0, 0, 1, 2, 1,
+      BOX_CLOCK, 1, 2, 0, 0, 2, 0, 1, 0, 1},
+#define WIPE_B2_226     5
+  {BOX_CLOCK, 0, 1, 0, 0, 0, 0, 2, 1, 1,
+      BOX_CLOCK, 2, 1, 0, 2, 2, 0, 0, 1, 1},
+#define WIPE_B2_231     6
+  {BOX_CLOCK, 1, 0, 0, 1, 2, 0, 2, 0, 1,
+      BOX_CLOCK, 1, 0, 0, 1, 2, 0, 0, 0, 1},
+#define WIPE_B2_232     7
+  {BOX_CLOCK, 2, 1, 0, 0, 1, 0, 2, 0, 1,
+      BOX_CLOCK, 2, 1, 0, 0, 1, 0, 2, 2, 1},
+#define WIPE_B2_233     8
+  {BOX_CLOCK, 1, 2, 0, 1, 0, 0, 2, 2, 1,
+      BOX_CLOCK, 1, 2, 0, 1, 0, 0, 0, 2, 1},
+#define WIPE_B2_234     9
+  {BOX_CLOCK, 0, 1, 0, 2, 1, 0, 0, 0, 1,
+      BOX_CLOCK, 0, 1, 0, 2, 1, 0, 0, 2, 1},
+#define WIPE_B2_251     10
+  {BOX_CLOCK, 0, 0, 0, 1, 0, 0, 0, 2, 1,
+      BOX_CLOCK, 2, 0, 0, 1, 0, 0, 2, 2, 1},
+#define WIPE_B2_252     11
+  {BOX_CLOCK, 0, 0, 0, 0, 1, 0, 2, 0, 1,
+      BOX_CLOCK, 0, 2, 0, 0, 1, 0, 2, 2, 1},
+#define WIPE_B2_253     12
+  {BOX_CLOCK, 0, 2, 0, 1, 2, 0, 0, 0, 1,
+      BOX_CLOCK, 2, 2, 0, 1, 2, 0, 2, 0, 1},
+#define WIPE_B2_254     13
+  {BOX_CLOCK, 2, 0, 0, 2, 1, 0, 0, 0, 1,
+      BOX_CLOCK, 2, 2, 0, 2, 1, 0, 0, 2, 1},
+};
+
+static const gint box_clock_4b[][4 * 10] = {
+#define WIPE_B4_201     0
+  {BOX_CLOCK, 1, 1, 0, 1, 0, 0, 2, 1, 1,
+        BOX_CLOCK, 1, 1, 0, 2, 1, 1, 1, 2, 2,
+        BOX_CLOCK, 1, 1, 0, 1, 2, 2, 0, 1, 3,
+      BOX_CLOCK, 1, 1, 0, 0, 1, 3, 1, 0, 4},
+#define WIPE_B4_202     1
+  {BOX_CLOCK, 1, 1, 0, 1, 0, 3, 2, 1, 4,
+        BOX_CLOCK, 1, 1, 0, 2, 1, 0, 1, 2, 1,
+        BOX_CLOCK, 1, 1, 0, 1, 2, 1, 0, 1, 2,
+      BOX_CLOCK, 1, 1, 0, 0, 1, 2, 1, 0, 3},
+#define WIPE_B4_203     2
+  {BOX_CLOCK, 1, 1, 0, 1, 0, 2, 2, 1, 3,
+        BOX_CLOCK, 1, 1, 0, 2, 1, 3, 1, 2, 4,
+        BOX_CLOCK, 1, 1, 0, 1, 2, 0, 0, 1, 1,
+      BOX_CLOCK, 1, 1, 0, 0, 1, 1, 1, 0, 2},
+#define WIPE_B4_204     3
+  {BOX_CLOCK, 1, 1, 0, 1, 0, 1, 2, 1, 2,
+        BOX_CLOCK, 1, 1, 0, 2, 1, 2, 1, 2, 3,
+        BOX_CLOCK, 1, 1, 0, 1, 2, 3, 0, 1, 4,
+      BOX_CLOCK, 1, 1, 0, 0, 1, 0, 1, 0, 1},
+#define WIPE_B4_205     4
+  {BOX_CLOCK, 1, 1, 0, 1, 0, 0, 2, 1, 1,
+        BOX_CLOCK, 1, 1, 0, 2, 1, 1, 1, 2, 2,
+        BOX_CLOCK, 1, 1, 0, 1, 2, 0, 0, 1, 1,
+      BOX_CLOCK, 1, 1, 0, 0, 1, 1, 1, 0, 2},
+#define WIPE_B4_206     5
+  {BOX_CLOCK, 1, 1, 0, 1, 0, 1, 2, 1, 2,
+        BOX_CLOCK, 1, 1, 0, 2, 1, 0, 1, 2, 1,
+        BOX_CLOCK, 1, 1, 0, 1, 2, 1, 0, 1, 2,
+      BOX_CLOCK, 1, 1, 0, 0, 1, 0, 1, 0, 1},
+#define WIPE_B4_207     6
+  {BOX_CLOCK, 1, 1, 0, 1, 0, 0, 2, 1, 1,
+        BOX_CLOCK, 1, 1, 0, 2, 1, 0, 1, 2, 1,
+        BOX_CLOCK, 1, 1, 0, 1, 2, 0, 0, 1, 1,
+      BOX_CLOCK, 1, 1, 0, 0, 1, 0, 1, 0, 1},
+#define WIPE_B4_211     7
+  {BOX_CLOCK, 1, 1, 0, 1, 0, 0, 2, 1, 1,
+        BOX_CLOCK, 1, 1, 0, 2, 1, 1, 1, 2, 2,
+        BOX_CLOCK, 1, 1, 0, 1, 0, 0, 0, 1, 1,
+      BOX_CLOCK, 1, 1, 0, 0, 1, 1, 1, 2, 2},
+#define WIPE_B4_212     8
+  {BOX_CLOCK, 1, 1, 0, 2, 1, 0, 1, 0, 1,
+        BOX_CLOCK, 1, 1, 0, 1, 0, 1, 0, 1, 2,
+        BOX_CLOCK, 1, 1, 0, 2, 1, 0, 1, 2, 1,
+      BOX_CLOCK, 1, 1, 0, 1, 2, 1, 0, 1, 2},
+#define WIPE_B4_213     9
+  {BOX_CLOCK, 1, 1, 0, 1, 0, 0, 2, 1, 1,
+        BOX_CLOCK, 1, 1, 0, 1, 0, 0, 0, 1, 1,
+        BOX_CLOCK, 1, 1, 0, 1, 2, 0, 2, 1, 1,
+      BOX_CLOCK, 1, 1, 0, 1, 2, 0, 0, 1, 1},
+#define WIPE_B4_214     10
+  {BOX_CLOCK, 1, 1, 0, 2, 1, 0, 1, 0, 1,
+        BOX_CLOCK, 1, 1, 0, 2, 1, 0, 1, 2, 1,
+        BOX_CLOCK, 1, 1, 0, 0, 1, 0, 1, 0, 1,
+      BOX_CLOCK, 1, 1, 0, 0, 1, 0, 1, 2, 1},
+#define WIPE_B4_227     11
+  {BOX_CLOCK, 1, 0, 0, 2, 0, 0, 1, 1, 1,
+        BOX_CLOCK, 1, 0, 0, 1, 1, 1, 0, 0, 2,
+        BOX_CLOCK, 1, 2, 0, 2, 2, 0, 1, 1, 1,
+      BOX_CLOCK, 1, 2, 0, 1, 1, 1, 0, 2, 2},
+#define WIPE_B4_228     12
+  {BOX_CLOCK, 0, 1, 0, 0, 0, 0, 1, 1, 1,
+        BOX_CLOCK, 0, 1, 0, 1, 1, 1, 0, 2, 2,
+        BOX_CLOCK, 2, 1, 0, 2, 0, 0, 1, 1, 1,
+      BOX_CLOCK, 2, 1, 0, 1, 1, 1, 2, 2, 2},
+#define WIPE_B4_235     13
+  {BOX_CLOCK, 1, 0, 0, 1, 1, 0, 0, 0, 1,
+        BOX_CLOCK, 1, 0, 0, 1, 1, 0, 2, 0, 1,
+        BOX_CLOCK, 1, 2, 0, 1, 1, 0, 2, 2, 1,
+      BOX_CLOCK, 1, 2, 0, 1, 1, 0, 0, 2, 1},
+#define WIPE_B4_236     14
+  {BOX_CLOCK, 0, 1, 0, 1, 1, 0, 0, 0, 1,
+        BOX_CLOCK, 0, 1, 0, 1, 1, 0, 0, 2, 1,
+        BOX_CLOCK, 2, 1, 0, 1, 1, 0, 2, 0, 1,
+      BOX_CLOCK, 2, 1, 0, 1, 1, 0, 2, 2, 1},
+};
+
+static const gint box_clock_8b[][8 * 10] = {
+#define WIPE_B8_261     0
+  {BOX_CLOCK, 2, 1, 0, 2, 2, 0, 4, 1, 1,
+        BOX_CLOCK, 2, 1, 0, 4, 1, 1, 2, 0, 2,
+        BOX_CLOCK, 2, 1, 0, 2, 0, 2, 0, 1, 3,
+        BOX_CLOCK, 2, 1, 0, 0, 1, 3, 2, 2, 4,
+        BOX_CLOCK, 2, 3, 0, 2, 2, 0, 4, 3, 1,
+        BOX_CLOCK, 2, 3, 0, 4, 3, 1, 2, 4, 2,
+        BOX_CLOCK, 2, 3, 0, 2, 4, 2, 0, 3, 3,
+      BOX_CLOCK, 2, 3, 0, 0, 3, 3, 2, 2, 4},
+#define WIPE_B8_262     1
+  {BOX_CLOCK, 1, 2, 0, 2, 2, 0, 1, 0, 1,
+        BOX_CLOCK, 1, 2, 0, 1, 0, 1, 0, 2, 2,
+        BOX_CLOCK, 1, 2, 0, 0, 2, 2, 1, 4, 3,
+        BOX_CLOCK, 1, 2, 0, 1, 4, 3, 2, 2, 4,
+        BOX_CLOCK, 3, 2, 0, 2, 2, 0, 3, 0, 1,
+        BOX_CLOCK, 3, 2, 0, 3, 0, 1, 4, 2, 2,
+        BOX_CLOCK, 3, 2, 0, 4, 2, 2, 3, 4, 3,
+      BOX_CLOCK, 3, 2, 0, 3, 4, 3, 2, 2, 4},
+#define WIPE_B8_263     2
+  {BOX_CLOCK, 2, 1, 0, 2, 0, 0, 4, 1, 1,
+        BOX_CLOCK, 2, 1, 0, 4, 1, 1, 2, 2, 2,
+        BOX_CLOCK, 2, 1, 0, 2, 0, 0, 0, 1, 1,
+        BOX_CLOCK, 2, 1, 0, 0, 1, 1, 2, 2, 2,
+        BOX_CLOCK, 2, 3, 0, 2, 4, 0, 4, 3, 1,
+        BOX_CLOCK, 2, 3, 0, 4, 3, 1, 2, 2, 2,
+        BOX_CLOCK, 2, 3, 0, 2, 4, 0, 0, 3, 1,
+      BOX_CLOCK, 2, 3, 0, 0, 3, 1, 2, 2, 2},
+#define WIPE_B8_264     3
+  {BOX_CLOCK, 1, 2, 0, 0, 2, 0, 1, 0, 1,
+        BOX_CLOCK, 1, 2, 0, 1, 0, 1, 2, 2, 2,
+        BOX_CLOCK, 1, 2, 0, 0, 2, 0, 1, 4, 1,
+        BOX_CLOCK, 1, 2, 0, 1, 4, 1, 2, 2, 2,
+        BOX_CLOCK, 3, 2, 0, 4, 2, 0, 3, 0, 1,
+        BOX_CLOCK, 3, 2, 0, 3, 0, 1, 2, 2, 2,
+        BOX_CLOCK, 3, 2, 0, 4, 2, 0, 3, 4, 1,
+      BOX_CLOCK, 3, 2, 0, 3, 4, 1, 2, 2, 2},
+};
+
+static const gint triangles_2t[][2 * 9] = {
+  /* 3 -> 6 */
+#define WIPE_T2_3       0
+  {0, 0, 0, 0, 1, 1, 1, 1, 1,
+      1, 0, 1, 0, 0, 0, 1, 1, 1},
+#define WIPE_T2_4       WIPE_T2_3+1
+  {0, 0, 1, 1, 0, 0, 0, 1, 1,
+      1, 0, 0, 0, 1, 1, 1, 1, 1},
+#define WIPE_T2_5       WIPE_T2_4+1
+  {0, 0, 1, 0, 1, 1, 1, 1, 0,
+      1, 0, 1, 0, 0, 1, 1, 1, 0},
+#define WIPE_T2_6       WIPE_T2_5+1
+  {0, 0, 1, 1, 0, 1, 0, 1, 0,
+      1, 0, 1, 0, 1, 0, 1, 1, 1},
+#define WIPE_T2_41      WIPE_T2_6+1
+  {0, 0, 0, 1, 0, 1, 0, 1, 1,
+      1, 0, 1, 0, 1, 1, 1, 1, 2},
+#define WIPE_T2_42      WIPE_T2_41+1
+  {0, 0, 1, 1, 0, 0, 1, 1, 1,
+      0, 0, 1, 0, 1, 2, 1, 1, 1},
+#define WIPE_T2_45      WIPE_T2_42+1
+  {0, 0, 1, 1, 0, 0, 0, 1, 0,
+      1, 0, 0, 0, 1, 0, 1, 1, 1},
+#define WIPE_T2_46      WIPE_T2_45+1
+  {0, 0, 0, 1, 0, 1, 1, 1, 0,
+      0, 0, 0, 0, 1, 1, 1, 1, 0},
+#define WIPE_T2_245     WIPE_T2_46+1
+  {0, 0, 0, 2, 0, 0, 2, 2, 1,
+      2, 2, 0, 0, 2, 0, 0, 0, 1},
+#define WIPE_T2_246     WIPE_T2_245+1
+  {0, 2, 0, 0, 0, 0, 2, 0, 1,
+      2, 0, 0, 2, 2, 0, 0, 2, 1},
+};
+
+static const gint triangles_3t[][3 * 9] = {
+  /* 23 -> 26 */
+#define WIPE_T3_23      0
+  {0, 0, 1, 1, 0, 0, 0, 2, 1,
+        1, 0, 0, 0, 2, 1, 2, 2, 1,
+      1, 0, 0, 2, 0, 1, 2, 2, 1},
+#define WIPE_T3_24      1
+  {0, 0, 1, 2, 0, 1, 2, 1, 0,
+        0, 0, 1, 2, 1, 0, 0, 2, 1,
+      2, 1, 0, 0, 2, 1, 2, 2, 1},
+#define WIPE_T3_25      2
+  {0, 0, 1, 0, 2, 1, 1, 2, 0,
+        0, 0, 1, 2, 0, 1, 1, 2, 0,
+      2, 0, 1, 1, 2, 0, 2, 2, 1},
+#define WIPE_T3_26      3
+  {0, 0, 1, 2, 0, 1, 0, 1, 0,
+        2, 0, 1, 0, 1, 0, 2, 2, 1,
+      0, 1, 0, 0, 2, 1, 2, 2, 1},
+};
+
+static const gint triangles_4t[][4 * 9] = {
+#define WIPE_T4_61      0
+  {0, 0, 1, 1, 0, 0, 1, 2, 1,
+        0, 0, 1, 0, 2, 2, 1, 2, 1,
+        1, 0, 0, 2, 0, 1, 1, 2, 1,
+      2, 0, 1, 1, 2, 1, 2, 2, 2},
+#define WIPE_T4_62      1
+  {0, 0, 2, 2, 0, 1, 0, 1, 1,
+        2, 0, 1, 0, 1, 1, 2, 1, 0,
+        0, 1, 1, 2, 1, 0, 2, 2, 1,
+      0, 1, 1, 0, 2, 2, 2, 2, 1},
+#define WIPE_T4_63      2
+  {0, 0, 2, 1, 0, 1, 0, 2, 1,
+        1, 0, 1, 0, 2, 1, 1, 2, 0,
+        1, 0, 1, 1, 2, 0, 2, 2, 1,
+      1, 0, 1, 2, 0, 2, 2, 2, 1},
+#define WIPE_T4_64      3
+  {0, 0, 1, 2, 0, 2, 2, 1, 1,
+        0, 0, 1, 0, 1, 0, 2, 1, 1,
+        0, 1, 0, 2, 1, 1, 0, 2, 1,
+      2, 1, 1, 0, 2, 1, 2, 2, 2},
+#define WIPE_T4_65      4
+  {0, 0, 0, 1, 0, 1, 1, 2, 0,
+        0, 0, 0, 0, 2, 1, 1, 2, 0,
+        1, 0, 1, 2, 0, 0, 1, 2, 0,
+      2, 0, 0, 1, 2, 0, 2, 2, 1},
+#define WIPE_T4_66      5
+  {0, 0, 1, 2, 0, 0, 0, 1, 0,
+        2, 0, 0, 0, 1, 0, 2, 1, 1,
+        0, 1, 0, 2, 1, 1, 2, 2, 0,
+      0, 1, 0, 0, 2, 1, 2, 2, 0},
+#define WIPE_T4_67      6
+  {0, 0, 1, 1, 0, 0, 0, 2, 0,
+        1, 0, 0, 0, 2, 0, 1, 2, 1,
+        1, 0, 0, 1, 2, 1, 2, 2, 0,
+      1, 0, 0, 2, 0, 1, 2, 2, 0},
+#define WIPE_T4_68      7
+  {0, 0, 0, 2, 0, 1, 2, 1, 0,
+        0, 0, 0, 0, 1, 1, 2, 1, 0,
+        0, 1, 1, 2, 1, 0, 0, 2, 0,
+      2, 1, 0, 0, 2, 0, 2, 2, 1},
+#define WIPE_T4_101     8
+  {0, 0, 1, 2, 0, 1, 1, 1, 0,
+        0, 0, 1, 1, 1, 0, 0, 2, 1,
+        1, 1, 0, 0, 2, 1, 2, 2, 1,
+      2, 0, 1, 1, 1, 0, 2, 2, 1},
+};
+
+static const gint triangles_8t[][8 * 9] = {
+  /* 7 */
+#define WIPE_T8_7       0
+  {0, 0, 0, 1, 0, 1, 1, 1, 1,
+        1, 0, 1, 2, 0, 0, 1, 1, 1,
+        2, 0, 0, 1, 1, 1, 2, 1, 1,
+        1, 1, 1, 2, 1, 1, 2, 2, 0,
+        1, 1, 1, 1, 2, 1, 2, 2, 0,
+        1, 1, 1, 0, 2, 0, 1, 2, 1,
+        0, 1, 1, 1, 1, 1, 0, 2, 0,
+      0, 0, 0, 0, 1, 1, 1, 1, 1},
+#define WIPE_T8_43      1
+  {0, 0, 1, 1, 0, 0, 1, 1, 1,
+        1, 0, 0, 2, 0, 1, 1, 1, 1,
+        2, 0, 1, 1, 1, 1, 2, 1, 2,
+        1, 1, 1, 2, 1, 2, 2, 2, 1,
+        1, 1, 1, 1, 2, 0, 2, 2, 1,
+        1, 1, 1, 0, 2, 1, 1, 2, 0,
+        0, 1, 2, 1, 1, 1, 0, 2, 1,
+      0, 0, 1, 0, 1, 2, 1, 1, 1},
+#define WIPE_T8_44      2
+  {0, 0, 1, 1, 0, 2, 1, 1, 1,
+        1, 0, 2, 2, 0, 1, 1, 1, 1,
+        2, 0, 1, 1, 1, 1, 2, 1, 0,
+        1, 1, 1, 2, 1, 0, 2, 2, 1,
+        1, 1, 1, 1, 2, 2, 2, 2, 1,
+        1, 1, 1, 0, 2, 1, 1, 2, 2,
+        0, 1, 0, 1, 1, 1, 0, 2, 1,
+      0, 0, 1, 0, 1, 0, 1, 1, 1},
+#define WIPE_T8_47      3
+  {0, 0, 0, 1, 0, 1, 1, 1, 0,
+        1, 0, 1, 2, 0, 0, 1, 1, 0,
+        2, 0, 0, 1, 1, 0, 2, 1, 1,
+        1, 1, 0, 2, 1, 1, 2, 2, 0,
+        1, 1, 0, 1, 2, 1, 2, 2, 0,
+        1, 1, 0, 0, 2, 0, 1, 2, 1,
+        0, 1, 1, 1, 1, 0, 0, 2, 0,
+      0, 0, 0, 0, 1, 1, 1, 1, 0},
+#define WIPE_T8_48      4
+  {0, 0, 1, 1, 0, 0, 0, 1, 0,
+        1, 0, 0, 0, 1, 0, 1, 1, 1,
+        1, 0, 0, 2, 0, 1, 2, 1, 0,
+        1, 0, 0, 1, 1, 1, 2, 1, 0,
+        0, 1, 0, 1, 1, 1, 1, 2, 0,
+        0, 1, 0, 0, 2, 1, 1, 2, 0,
+        1, 1, 1, 2, 1, 0, 1, 2, 0,
+      2, 1, 0, 1, 2, 0, 2, 2, 1},
+};
+
+static const gint triangles_16t[][16 * 9] = {
+  /* 8 */
+#define WIPE_T16_8      0
+  {0, 0, 1, 2, 0, 1, 1, 1, 0,
+        2, 0, 1, 1, 1, 0, 2, 2, 1,
+        1, 1, 0, 0, 2, 1, 2, 2, 1,
+        0, 0, 1, 1, 1, 0, 0, 2, 1,
+        2, 0, 1, 4, 0, 1, 3, 1, 0,
+        4, 0, 1, 3, 1, 0, 4, 2, 1,
+        3, 1, 0, 2, 2, 1, 4, 2, 1,
+        2, 0, 1, 3, 1, 0, 2, 2, 1,
+        0, 2, 1, 2, 2, 1, 1, 3, 0,
+        2, 2, 1, 1, 3, 0, 2, 4, 1,
+        1, 3, 0, 0, 4, 1, 2, 4, 1,
+        0, 2, 1, 1, 3, 0, 0, 4, 1,
+        2, 2, 1, 4, 2, 1, 3, 3, 0,
+        4, 2, 1, 3, 3, 0, 4, 4, 1,
+        3, 3, 0, 2, 4, 1, 4, 4, 1,
+      2, 2, 1, 3, 3, 0, 2, 4, 1}
+};
+
+typedef struct _GstWipeConfig GstWipeConfig;
+
+struct _GstWipeConfig
+{
+  const gint *objects;
+  gint nobjects;
+  gint xscale;
+  gint yscale;
+  gint cscale;
+};
+
+static const GstWipeConfig wipe_config[] = {
+#define WIPE_CONFIG_1   0
+  {boxes_1b[WIPE_B1_1], 1, 0, 0, 0},    /* 1 */
+#define WIPE_CONFIG_2   WIPE_CONFIG_1+1
+  {boxes_1b[WIPE_B1_2], 1, 0, 0, 0},    /* 2 */
+#define WIPE_CONFIG_3   WIPE_CONFIG_2+1
+  {triangles_2t[WIPE_T2_3], 2, 0, 0, 0},        /* 3 */
+#define WIPE_CONFIG_4   WIPE_CONFIG_3+1
+  {triangles_2t[WIPE_T2_4], 2, 0, 0, 0},        /* 4 */
+#define WIPE_CONFIG_5   WIPE_CONFIG_4+1
+  {triangles_2t[WIPE_T2_5], 2, 0, 0, 0},        /* 5 */
+#define WIPE_CONFIG_6   WIPE_CONFIG_5+1
+  {triangles_2t[WIPE_T2_6], 2, 0, 0, 0},        /* 6 */
+#define WIPE_CONFIG_7   WIPE_CONFIG_6+1
+  {triangles_8t[WIPE_T8_7], 8, 1, 1, 0},        /* 7 */
+#define WIPE_CONFIG_8   WIPE_CONFIG_7+1
+  {triangles_16t[WIPE_T16_8], 16, 2, 2, 0},     /* 8 */
+
+#define WIPE_CONFIG_21  WIPE_CONFIG_8+1
+  {boxes_2b[WIPE_B2_21], 2, 1, 1, 0},   /* 21 */
+#define WIPE_CONFIG_22  WIPE_CONFIG_21+1
+  {boxes_2b[WIPE_B2_22], 2, 1, 1, 0},   /* 22 */
+
+#define WIPE_CONFIG_23  WIPE_CONFIG_22+1
+  {triangles_3t[WIPE_T3_23], 3, 1, 1, 0},       /* 23 */
+#define WIPE_CONFIG_24  WIPE_CONFIG_23+1
+  {triangles_3t[WIPE_T3_24], 3, 1, 1, 0},       /* 24 */
+#define WIPE_CONFIG_25  WIPE_CONFIG_24+1
+  {triangles_3t[WIPE_T3_25], 3, 1, 1, 0},       /* 25 */
+#define WIPE_CONFIG_26  WIPE_CONFIG_25+1
+  {triangles_3t[WIPE_T3_26], 3, 1, 1, 0},       /* 26 */
+#define WIPE_CONFIG_41  WIPE_CONFIG_26+1
+  {triangles_2t[WIPE_T2_41], 2, 0, 0, 1},       /* 41 */
+#define WIPE_CONFIG_42  WIPE_CONFIG_41+1
+  {triangles_2t[WIPE_T2_42], 2, 0, 0, 1},       /* 42 */
+#define WIPE_CONFIG_43  WIPE_CONFIG_42+1
+  {triangles_8t[WIPE_T8_43], 8, 1, 1, 1},       /* 43 */
+#define WIPE_CONFIG_44  WIPE_CONFIG_43+1
+  {triangles_8t[WIPE_T8_44], 8, 1, 1, 1},       /* 44 */
+#define WIPE_CONFIG_45  WIPE_CONFIG_44+1
+  {triangles_2t[WIPE_T2_45], 2, 0, 0, 0},       /* 45 */
+#define WIPE_CONFIG_46  WIPE_CONFIG_45+1
+  {triangles_2t[WIPE_T2_46], 2, 0, 0, 0},       /* 46 */
+#define WIPE_CONFIG_47  WIPE_CONFIG_46+1
+  {triangles_8t[WIPE_T8_47], 8, 1, 1, 0},       /* 47 */
+#define WIPE_CONFIG_48  WIPE_CONFIG_47+1
+  {triangles_8t[WIPE_T8_48], 8, 1, 1, 0},       /* 48 */
+#define WIPE_CONFIG_61  WIPE_CONFIG_48+1
+  {triangles_4t[WIPE_T4_61], 4, 1, 1, 1},       /* 61 */
+#define WIPE_CONFIG_62  WIPE_CONFIG_61+1
+  {triangles_4t[WIPE_T4_62], 4, 1, 1, 1},       /* 62 */
+#define WIPE_CONFIG_63  WIPE_CONFIG_62+1
+  {triangles_4t[WIPE_T4_63], 4, 1, 1, 1},       /* 63 */
+#define WIPE_CONFIG_64  WIPE_CONFIG_63+1
+  {triangles_4t[WIPE_T4_64], 4, 1, 1, 1},       /* 64 */
+#define WIPE_CONFIG_65  WIPE_CONFIG_64+1
+  {triangles_4t[WIPE_T4_65], 4, 1, 1, 0},       /* 65 */
+#define WIPE_CONFIG_66  WIPE_CONFIG_65+1
+  {triangles_4t[WIPE_T4_66], 4, 1, 1, 0},       /* 66 */
+#define WIPE_CONFIG_67  WIPE_CONFIG_66+1
+  {triangles_4t[WIPE_T4_67], 4, 1, 1, 0},       /* 67 */
+#define WIPE_CONFIG_68  WIPE_CONFIG_67+1
+  {triangles_4t[WIPE_T4_68], 4, 1, 1, 0},       /* 68 */
+#define WIPE_CONFIG_101 WIPE_CONFIG_68+1
+  {triangles_4t[WIPE_T4_101], 4, 1, 1, 0},      /* 101 */
+#define WIPE_CONFIG_201 WIPE_CONFIG_101+1
+  {box_clock_4b[WIPE_B4_201], 4, 1, 1, 2},      /* 201 */
+#define WIPE_CONFIG_202 WIPE_CONFIG_201+1
+  {box_clock_4b[WIPE_B4_202], 4, 1, 1, 2},      /* 202 */
+#define WIPE_CONFIG_203 WIPE_CONFIG_202+1
+  {box_clock_4b[WIPE_B4_203], 4, 1, 1, 2},      /* 203 */
+#define WIPE_CONFIG_204 WIPE_CONFIG_203+1
+  {box_clock_4b[WIPE_B4_204], 4, 1, 1, 2},      /* 204 */
+#define WIPE_CONFIG_205 WIPE_CONFIG_204+1
+  {box_clock_4b[WIPE_B4_205], 4, 1, 1, 1},      /* 205 */
+#define WIPE_CONFIG_206 WIPE_CONFIG_205+1
+  {box_clock_4b[WIPE_B4_206], 4, 1, 1, 1},      /* 206 */
+#define WIPE_CONFIG_207 WIPE_CONFIG_206+1
+  {box_clock_4b[WIPE_B4_207], 4, 1, 1, 0},      /* 207 */
+#define WIPE_CONFIG_211 WIPE_CONFIG_207+1
+  {box_clock_4b[WIPE_B4_211], 4, 1, 1, 1},      /* 211 */
+#define WIPE_CONFIG_212 WIPE_CONFIG_211+1
+  {box_clock_4b[WIPE_B4_212], 4, 1, 1, 1},      /* 212 */
+#define WIPE_CONFIG_213 WIPE_CONFIG_212+1
+  {box_clock_4b[WIPE_B4_213], 4, 1, 1, 0},      /* 213 */
+#define WIPE_CONFIG_214 WIPE_CONFIG_213+1
+  {box_clock_4b[WIPE_B4_214], 4, 1, 1, 0},      /* 214 */
+#define WIPE_CONFIG_221 WIPE_CONFIG_214+1
+  {box_clock_2b[WIPE_B2_221], 2, 1, 1, 1},      /* 221 */
+#define WIPE_CONFIG_222 WIPE_CONFIG_221+1
+  {box_clock_2b[WIPE_B2_222], 2, 1, 1, 1},      /* 222 */
+#define WIPE_CONFIG_223 WIPE_CONFIG_222+1
+  {box_clock_2b[WIPE_B2_223], 2, 1, 1, 1},      /* 223 */
+#define WIPE_CONFIG_224 WIPE_CONFIG_223+1
+  {box_clock_2b[WIPE_B2_224], 2, 1, 1, 1},      /* 224 */
+#define WIPE_CONFIG_225 WIPE_CONFIG_224+1
+  {box_clock_2b[WIPE_B2_225], 2, 1, 1, 0},      /* 225 */
+#define WIPE_CONFIG_226 WIPE_CONFIG_225+1
+  {box_clock_2b[WIPE_B2_226], 2, 1, 1, 0},      /* 226 */
+#define WIPE_CONFIG_227 WIPE_CONFIG_226+1
+  {box_clock_4b[WIPE_B4_227], 4, 1, 1, 1},      /* 227 */
+#define WIPE_CONFIG_228 WIPE_CONFIG_227+1
+  {box_clock_4b[WIPE_B4_228], 4, 1, 1, 1},      /* 228 */
+#define WIPE_CONFIG_231 WIPE_CONFIG_228+1
+  {box_clock_2b[WIPE_B2_231], 2, 1, 1, 0},      /* 231 */
+#define WIPE_CONFIG_232 WIPE_CONFIG_231+1
+  {box_clock_2b[WIPE_B2_232], 2, 1, 1, 0},      /* 232 */
+#define WIPE_CONFIG_233 WIPE_CONFIG_232+1
+  {box_clock_2b[WIPE_B2_233], 2, 1, 1, 0},      /* 233 */
+#define WIPE_CONFIG_234 WIPE_CONFIG_233+1
+  {box_clock_2b[WIPE_B2_234], 2, 1, 1, 0},      /* 234 */
+#define WIPE_CONFIG_235 WIPE_CONFIG_234+1
+  {box_clock_4b[WIPE_B4_235], 4, 1, 1, 0},      /* 235 */
+#define WIPE_CONFIG_236 WIPE_CONFIG_235+1
+  {box_clock_4b[WIPE_B4_236], 4, 1, 1, 0},      /* 236 */
+#define WIPE_CONFIG_241 WIPE_CONFIG_236+1
+  {box_clock_1b[WIPE_B1_241], 1, 0, 0, 0},      /* 241 */
+#define WIPE_CONFIG_242 WIPE_CONFIG_241+1
+  {box_clock_1b[WIPE_B1_242], 1, 0, 0, 0},      /* 242 */
+#define WIPE_CONFIG_243 WIPE_CONFIG_242+1
+  {box_clock_1b[WIPE_B1_243], 1, 0, 0, 0},      /* 243 */
+#define WIPE_CONFIG_244 WIPE_CONFIG_243+1
+  {box_clock_1b[WIPE_B1_244], 1, 0, 0, 0},      /* 244 */
+#define WIPE_CONFIG_245 WIPE_CONFIG_244+1
+  {triangles_2t[WIPE_T2_245], 2, 1, 1, 0},      /* 245 */
+#define WIPE_CONFIG_246 WIPE_CONFIG_245+1
+  {triangles_2t[WIPE_T2_246], 2, 1, 1, 0},      /* 246 */
+#define WIPE_CONFIG_251 WIPE_CONFIG_246+1
+  {box_clock_2b[WIPE_B2_251], 2, 1, 1, 0},      /* 251 */
+#define WIPE_CONFIG_252 WIPE_CONFIG_251+1
+  {box_clock_2b[WIPE_B2_252], 2, 1, 1, 0},      /* 252 */
+#define WIPE_CONFIG_253 WIPE_CONFIG_252+1
+  {box_clock_2b[WIPE_B2_253], 2, 1, 1, 0},      /* 253 */
+#define WIPE_CONFIG_254 WIPE_CONFIG_253+1
+  {box_clock_2b[WIPE_B2_254], 2, 1, 1, 0},      /* 254 */
+
+#define WIPE_CONFIG_261 WIPE_CONFIG_254+1
+  {box_clock_8b[WIPE_B8_261], 8, 2, 2, 2},      /* 261 */
+#define WIPE_CONFIG_262 WIPE_CONFIG_261+1
+  {box_clock_8b[WIPE_B8_262], 8, 2, 2, 2},      /* 262 */
+#define WIPE_CONFIG_263 WIPE_CONFIG_262+1
+  {box_clock_8b[WIPE_B8_263], 8, 2, 2, 1},      /* 263 */
+#define WIPE_CONFIG_264 WIPE_CONFIG_263+1
+  {box_clock_8b[WIPE_B8_264], 8, 2, 2, 1},      /* 264 */
+};
+
+static void
+gst_wipe_boxes_draw (GstMask * mask)
+{
+  const GstWipeConfig *config = mask->user_data;
+  const gint *impacts = config->objects;
+  gint width = (mask->width >> config->xscale);
+  gint height = (mask->height >> config->yscale);
+  gint depth = (1 << mask->bpp) >> config->cscale;
+
+  gint i;
+
+  for (i = 0; i < config->nobjects; i++) {
+    switch (impacts[0]) {
+      case BOX_VERTICAL:
+        /* vbox does not draw last pixels */
+        gst_smpte_paint_vbox (mask->data, mask->width,
+            impacts[1] * width, impacts[2] * height, impacts[3] * depth,
+            impacts[4] * width, impacts[5] * height, impacts[6] * depth);
+        impacts += 7;
+        break;
+      case BOX_HORIZONTAL:
+        /* hbox does not draw last pixels */
+        gst_smpte_paint_hbox (mask->data, mask->width,
+            impacts[1] * width, impacts[2] * height, impacts[3] * depth,
+            impacts[4] * width, impacts[5] * height, impacts[6] * depth);
+        impacts += 7;
+        break;
+      case BOX_CLOCK:
+      {
+        gint x0, y0, x1, y1, x2, y2;
+
+        /* make sure not to draw outside the area */
+        x0 = MIN (impacts[1] * width, mask->width - 1);
+        y0 = MIN (impacts[2] * height, mask->height - 1);
+        x1 = MIN (impacts[4] * width, mask->width - 1);
+        y1 = MIN (impacts[5] * height, mask->height - 1);
+        x2 = MIN (impacts[7] * width, mask->width - 1);
+        y2 = MIN (impacts[8] * height, mask->height - 1);
+
+        gst_smpte_paint_box_clock (mask->data, mask->width,
+            x0, y0, impacts[3] * depth, x1, y1, impacts[6] * depth,
+            x2, y2, impacts[9] * depth);
+        impacts += 10;
+      }
+      default:
+        break;
+    }
+  }
+}
+
+static void
+gst_wipe_triangles_clock_draw (GstMask * mask)
+{
+  const GstWipeConfig *config = mask->user_data;
+  const gint *impacts = config->objects;
+  gint width = (mask->width >> config->xscale);
+  gint height = (mask->height >> config->yscale);
+  gint depth = (1 << mask->bpp) >> config->cscale;
+  gint i;
+
+  for (i = 0; i < config->nobjects; i++) {
+    gint x0, y0, x1, y1, x2, y2;
+
+    /* make sure not to draw outside the area */
+    x0 = MIN (impacts[0] * width, mask->width - 1);
+    y0 = MIN (impacts[1] * height, mask->height - 1);
+    x1 = MIN (impacts[3] * width, mask->width - 1);
+    y1 = MIN (impacts[4] * height, mask->height - 1);
+    x2 = MIN (impacts[6] * width, mask->width - 1);
+    y2 = MIN (impacts[7] * height, mask->height - 1);
+
+    gst_smpte_paint_triangle_clock (mask->data, mask->width,
+        x0, y0, impacts[2] * depth, x1, y1, impacts[5] * depth,
+        x2, y2, impacts[8] * depth);
+    impacts += 9;
+  }
+}
+
+static void
+gst_wipe_triangles_draw (GstMask * mask)
+{
+  const GstWipeConfig *config = mask->user_data;
+  const gint *impacts = config->objects;
+  gint width = (mask->width >> config->xscale);
+  gint height = (mask->height >> config->yscale);
+  gint depth = (1 << mask->bpp) >> config->cscale;
+
+  gint i;
+
+  for (i = 0; i < config->nobjects; i++) {
+    gint x0, y0, x1, y1, x2, y2;
+
+    /* make sure not to draw outside the area */
+    x0 = MIN (impacts[0] * width, mask->width - 1);
+    y0 = MIN (impacts[1] * height, mask->height - 1);
+    x1 = MIN (impacts[3] * width, mask->width - 1);
+    y1 = MIN (impacts[4] * height, mask->height - 1);
+    x2 = MIN (impacts[6] * width, mask->width - 1);
+    y2 = MIN (impacts[7] * height, mask->height - 1);
+
+    gst_smpte_paint_triangle_linear (mask->data, mask->width,
+        x0, y0, impacts[2] * depth, x1, y1, impacts[5] * depth,
+        x2, y2, impacts[8] * depth);
+    impacts += 9;
+  }
+}
+
+/* see also:
+ * http://www.w3c.rl.ac.uk/pasttalks/slidemaker/XML_Multimedia/htmls/transitions.html
+ */
+static const GstMaskDefinition definitions[] = {
+  {1, "bar-wipe-lr",
+        "A bar moves from left to right",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_1]},
+  {2, "bar-wipe-tb",
+        "A bar moves from top to bottom",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_2]},
+  {3, "box-wipe-tl",
+        "A box expands from the upper-left corner to the lower-right corner",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_3]},
+  {4, "box-wipe-tr",
+        "A box expands from the upper-right corner to the lower-left corner",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_4]},
+  {5, "box-wipe-br",
+        "A box expands from the lower-right corner to the upper-left corner",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_5]},
+  {6, "box-wipe-bl",
+        "A box expands from the lower-left corner to the upper-right corner",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_6]},
+  {7, "four-box-wipe-ci",
+        "A box shape expands from each of the four corners toward the center",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_7]},
+  {8, "four-box-wipe-co",
+        "A box shape expands from the center of each quadrant toward the corners of each quadrant",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_8]},
+  {21, "barndoor-v",
+        "A central, vertical line splits and expands toward the left and right edges",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_21]},
+  {22, "barndoor-h",
+        "A central, horizontal line splits and expands toward the top and bottom edges",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_22]},
+  {23, "box-wipe-tc",
+        "A box expands from the top edge's midpoint to the bottom corners",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_23]},
+  {24, "box-wipe-rc",
+        "A box expands from the right edge's midpoint to the left corners",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_24]},
+  {25, "box-wipe-bc",
+        "A box expands from the bottom edge's midpoint to the top corners",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_25]},
+  {26, "box-wipe-lc",
+        "A box expands from the left edge's midpoint to the right corners",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_26]},
+  {41, "diagonal-tl",
+        "A diagonal line moves from the upper-left corner to the lower-right corner",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_41]},
+  {42, "diagonal-tr",
+        "A diagonal line moves from the upper right corner to the lower-left corner",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_42]},
+  {43, "bowtie-v",
+        "Two wedge shapes slide in from the top and bottom edges toward the center",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_43]},
+  {44, "bowtie-h",
+        "Two wedge shapes slide in from the left and right edges toward the center",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_44]},
+  {45, "barndoor-dbl",
+        "A diagonal line from the lower-left to upper-right corners splits and expands toward the opposite corners",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_45]},
+  {46, "barndoor-dtl",
+        "A diagonal line from upper-left to lower-right corners splits and expands toward the opposite corners",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_46]},
+  {47, "misc-diagonal-dbd",
+        "Four wedge shapes split from the center and retract toward the four edges",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_47]},
+  {48, "misc-diagonal-dd",
+        "A diamond connecting the four edge midpoints simultaneously contracts toward the center and expands toward the edges",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_48]},
+  {61, "vee-d",
+        "A wedge shape moves from top to bottom",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_61]},
+  {62, "vee-l",
+        "A wedge shape moves from right to left",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_62]},
+  {63, "vee-u",
+        "A wedge shape moves from bottom to top",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_63]},
+  {64, "vee-r",
+        "A wedge shape moves from left to right",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_64]},
+  {65, "barnvee-d",
+        "A 'V' shape extending from the bottom edge's midpoint to the opposite corners contracts toward the center and expands toward the edges",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_65]},
+  {66, "barnvee-l",
+        "A 'V' shape extending from the left edge's midpoint to the opposite corners contracts toward the center and expands toward the edges",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_66]},
+  {67, "barnvee-u",
+        "A 'V' shape extending from the top edge's midpoint to the opposite corners contracts toward the center and expands toward the edges",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_67]},
+  {68, "barnvee-r",
+        "A 'V' shape extending from the right edge's midpoint to the opposite corners contracts toward the center and expands toward the edges",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_68]},
+  {101, "iris-rect",
+        "A rectangle expands from the center.",
+        gst_wipe_triangles_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_101]},
+  {201, "clock-cw12",
+        "A radial hand sweeps clockwise from the twelve o'clock position",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_201]},
+  {202, "clock-cw3",
+        "A radial hand sweeps clockwise from the three o'clock position",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_202]},
+  {203, "clock-cw6",
+        "A radial hand sweeps clockwise from the six o'clock position",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_203]},
+  {204, "clock-cw9",
+        "A radial hand sweeps clockwise from the nine o'clock position",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_204]},
+  {205, "pinwheel-tbv",
+        "Two radial hands sweep clockwise from the twelve and six o'clock positions",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_205]},
+  {206, "pinwheel-tbh",
+        "Two radial hands sweep clockwise from the nine and three o'clock positions",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_206]},
+  {207, "pinwheel-fb",
+        "Four radial hands sweep clockwise",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_207]},
+  {211, "fan-ct",
+        "A fan unfolds from the top edge, the fan axis at the center",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_211]},
+  {212, "fan-cr",
+        "A fan unfolds from the right edge, the fan axis at the center",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_212]},
+  {213, "doublefan-fov",
+        "Two fans, their axes at the center, unfold from the top and bottom",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_213]},
+  {214, "doublefan-foh",
+        "Two fans, their axes at the center, unfold from the left and right",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_214]},
+  {221, "singlesweep-cwt",
+        "A radial hand sweeps clockwise from the top edge's midpoint",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_221]},
+  {222, "singlesweep-cwr",
+        "A radial hand sweeps clockwise from the right edge's midpoint",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_222]},
+  {223, "singlesweep-cwb",
+        "A radial hand sweeps clockwise from the bottom edge's midpoint",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_223]},
+  {224, "singlesweep-cwl",
+        "A radial hand sweeps clockwise from the left edge's midpoint",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_224]},
+  {225, "doublesweep-pv",
+        "Two radial hands sweep clockwise and counter-clockwise from the top and bottom edges' midpoints",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_225]},
+  {226, "doublesweep-pd",
+        "Two radial hands sweep clockwise and counter-clockwise from the left and right edges' midpoints",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_226]},
+  {227, "doublesweep-ov",
+        "Two radial hands attached at the top and bottom edges' midpoints sweep from right to left",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_227]},
+  {228, "doublesweep-oh",
+        "Two radial hands attached at the left and right edges' midpoints sweep from top to bottom",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_228]},
+  {231, "fan-t",
+        "A fan unfolds from the bottom, the fan axis at the top edge's midpoint",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_231]},
+  {232, "fan-r",
+        "A fan unfolds from the left, the fan axis at the right edge's midpoint",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_232]},
+  {233, "fan-b",
+        "A fan unfolds from the top, the fan axis at the bottom edge's midpoint",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_233]},
+  {234, "fan-l",
+        "A fan unfolds from the right, the fan axis at the left edge's midpoint",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_234]},
+  {235, "doublefan-fiv",
+        "Two fans, their axes at the top and bottom, unfold from the center",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_235]},
+  {236, "doublefan-fih",
+        "Two fans, their axes at the left and right, unfold from the center",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_236]},
+  {241, "singlesweep-cwtl",
+        "A radial hand sweeps clockwise from the upper-left corner",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_241]},
+  {242, "singlesweep-cwbl",
+        "A radial hand sweeps counter-clockwise from the lower-left corner.",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_242]},
+  {243, "singlesweep-cwbr",
+        "A radial hand sweeps clockwise from the lower-right corner",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_243]},
+  {244, "singlesweep-cwtr",
+        "A radial hand sweeps counter-clockwise from the upper-right corner",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_244]},
+  {245, "doublesweep-pdtl",
+        "Two radial hands attached at the upper-left and lower-right corners sweep down and up",
+        gst_wipe_triangles_clock_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_245]},
+  {246, "doublesweep-pdbl",
+        "Two radial hands attached at the lower-left and upper-right corners sweep down and up",
+        gst_wipe_triangles_clock_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_246]},
+  {251, "saloondoor-t",
+        "Two radial hands attached at the upper-left and upper-right corners sweep down",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_251]},
+  {252, "saloondoor-l",
+        "Two radial hands attached at the upper-left and lower-left corners sweep to the right",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_252]},
+  {253, "saloondoor-b",
+        "Two radial hands attached at the lower-left and lower-right corners sweep up",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_253]},
+  {254, "saloondoor-r",
+        "Two radial hands attached at the upper-right and lower-right corners sweep to the left",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_254]},
+  {261, "windshield-r",
+        "Two radial hands attached at the midpoints of the top and bottom halves sweep from right to left",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_261]},
+  {262, "windshield-u",
+        "Two radial hands attached at the midpoints of the left and right halves sweep from top to bottom",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_262]},
+  {263, "windshield-v",
+        "Two sets of radial hands attached at the midpoints of the top and bottom halves sweep from top to bottom and bottom to top",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_263]},
+  {264, "windshield-h",
+        "Two sets of radial hands attached at the midpoints of the left and right halves sweep from left to right and right to left",
+        gst_wipe_boxes_draw, _gst_mask_default_destroy,
+      &wipe_config[WIPE_CONFIG_264]},
+  {0, NULL, NULL, NULL}
+};
+
+void
+_gst_barboxwipes_register (void)
+{
+  gint i = 0;
+
+  while (definitions[i].short_name) {
+    _gst_mask_register (&definitions[i]);
+    i++;
+  }
+}
diff --git a/gst/smpte/gstmask.c b/gst/smpte/gstmask.c
new file mode 100644
index 0000000..92b5919
--- /dev/null
+++ b/gst/smpte/gstmask.c
@@ -0,0 +1,121 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstmask.h"
+#include "paint.h"
+
+static GList *masks = NULL;
+
+void
+_gst_mask_init (void)
+{
+  _gst_barboxwipes_register ();
+}
+
+static gint
+gst_mask_compare (GstMaskDefinition * def1, GstMaskDefinition * def2)
+{
+  return (def1->type - def2->type);
+}
+
+void
+_gst_mask_register (const GstMaskDefinition * definition)
+{
+  masks =
+      g_list_insert_sorted (masks, (gpointer) definition,
+      (GCompareFunc) gst_mask_compare);
+}
+
+const GList *
+gst_mask_get_definitions (void)
+{
+  return masks;
+}
+
+static GstMaskDefinition *
+gst_mask_find_definition (gint type)
+{
+  GList *walk = masks;
+
+  while (walk) {
+    GstMaskDefinition *def = (GstMaskDefinition *) walk->data;
+
+    if (def->type == type)
+      return def;
+
+    walk = g_list_next (walk);
+  }
+  return NULL;
+}
+
+GstMask *
+gst_mask_factory_new (gint type, gboolean invert, gint bpp, gint width,
+    gint height)
+{
+  GstMaskDefinition *definition;
+  GstMask *mask = NULL;
+
+  definition = gst_mask_find_definition (type);
+  if (definition) {
+    mask = g_new0 (GstMask, 1);
+
+    mask->type = definition->type;
+    mask->bpp = bpp;
+    mask->width = width;
+    mask->height = height;
+    mask->destroy_func = definition->destroy_func;
+    mask->user_data = definition->user_data;
+    mask->data = g_malloc (width * height * sizeof (guint32));
+
+    definition->draw_func (mask);
+
+    if (invert) {
+      gint i, j;
+      guint32 *datap = mask->data;
+      guint32 max = (1 << bpp);
+
+      for (i = 0; i < height; i++) {
+        for (j = 0; j < width; j++) {
+          *datap = max - *datap;
+          datap++;
+        }
+      }
+    }
+  }
+
+  return mask;
+}
+
+void
+_gst_mask_default_destroy (GstMask * mask)
+{
+  g_free (mask->data);
+  g_free (mask);
+}
+
+void
+gst_mask_destroy (GstMask * mask)
+{
+  if (mask->destroy_func)
+    mask->destroy_func (mask);
+}
diff --git a/gst/smpte/gstmask.h b/gst/smpte/gstmask.h
new file mode 100644
index 0000000..53a5082
--- /dev/null
+++ b/gst/smpte/gstmask.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_MASK_H__
+#define __GST_MASK_H__
+
+#include <gst/gst.h>
+
+typedef struct _GstMask GstMask;
+typedef struct _GstMaskDefinition GstMaskDefinition;
+
+typedef void            (*GstMaskDrawFunc)              (GstMask *mask);
+typedef void            (*GstMaskDestroyFunc)           (GstMask *mask);
+
+struct _GstMaskDefinition {
+  gint                   type;
+  const gchar           *short_name;
+  const gchar           *long_name;
+  GstMaskDrawFunc        draw_func;
+  GstMaskDestroyFunc     destroy_func;
+  gconstpointer          user_data;
+};
+
+struct _GstMask {
+  gint                   type;
+  guint32               *data;
+  gconstpointer          user_data;
+
+  gint                   width;
+  gint                   height;
+  gint                   bpp;
+
+  GstMaskDestroyFunc     destroy_func;
+};
+
+void                    _gst_mask_init                  (void);
+void                    _gst_mask_register              (const GstMaskDefinition *definition);
+
+void                    _gst_mask_default_destroy       (GstMask *mask);
+
+const GList*            gst_mask_get_definitions        (void);
+GstMask*                gst_mask_factory_new            (gint type, gboolean invert, gint bpp, gint width, gint height);
+void                    gst_mask_destroy                (GstMask *mask);
+
+void _gst_barboxwipes_register (void);
+
+#endif /* __GST_MASK_H__ */
diff --git a/gst/smpte/gstsmpte.c b/gst/smpte/gstsmpte.c
new file mode 100644
index 0000000..18c522c
--- /dev/null
+++ b/gst/smpte/gstsmpte.c
@@ -0,0 +1,671 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-smpte
+ *
+ * smpte can accept I420 video streams with the same width, height and
+ * framerate. The two incomming buffers are blended together using an effect
+ * specific alpha mask. 
+ *
+ * The #GstSmpte:depth property defines the presision in bits of the mask. A
+ * higher presision will create a mask with smoother gradients in order to avoid
+ * banding.
+ *
+ * <refsect2>
+ * <title>Sample pipelines</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc pattern=1 ! smpte name=s border=20000 type=234 duration=2000000000 ! videoconvert ! ximagesink videotestsrc ! s.
+ * ]| A pipeline to demonstrate the smpte transition.
+ * It shows a pinwheel transition a from a snow videotestsrc to an smpte
+ * pattern videotestsrc. The transition will take 2 seconds to complete. The
+ * edges of the transition are smoothed with a 20000 big border.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+#include "gstsmpte.h"
+#include "paint.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_smpte_debug);
+#define GST_CAT_DEFAULT gst_smpte_debug
+
+static GstStaticPadTemplate gst_smpte_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420")
+    )
+    );
+
+static GstStaticPadTemplate gst_smpte_sink1_template =
+GST_STATIC_PAD_TEMPLATE ("sink1",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420")
+    )
+    );
+
+static GstStaticPadTemplate gst_smpte_sink2_template =
+GST_STATIC_PAD_TEMPLATE ("sink2",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420")
+    )
+    );
+
+
+/* SMPTE signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+#define DEFAULT_PROP_TYPE	1
+#define DEFAULT_PROP_BORDER	0
+#define DEFAULT_PROP_DEPTH	16
+#define DEFAULT_PROP_DURATION	GST_SECOND
+#define DEFAULT_PROP_INVERT   FALSE
+
+enum
+{
+  PROP_0,
+  PROP_TYPE,
+  PROP_BORDER,
+  PROP_DEPTH,
+  PROP_DURATION,
+  PROP_INVERT
+};
+
+#define GST_TYPE_SMPTE_TRANSITION_TYPE (gst_smpte_transition_type_get_type())
+static GType
+gst_smpte_transition_type_get_type (void)
+{
+  static GType smpte_transition_type = 0;
+  GEnumValue *smpte_transitions;
+
+  if (!smpte_transition_type) {
+    const GList *definitions;
+    gint i = 0;
+
+    definitions = gst_mask_get_definitions ();
+    smpte_transitions =
+        g_new0 (GEnumValue, g_list_length ((GList *) definitions) + 1);
+
+    while (definitions) {
+      GstMaskDefinition *definition = (GstMaskDefinition *) definitions->data;
+
+      definitions = g_list_next (definitions);
+
+      smpte_transitions[i].value = definition->type;
+      /* older GLib versions have the two fields as non-const, hence the cast */
+      smpte_transitions[i].value_nick = (gchar *) definition->short_name;
+      smpte_transitions[i].value_name = (gchar *) definition->long_name;
+
+      i++;
+    }
+
+    smpte_transition_type =
+        g_enum_register_static ("GstSMPTETransitionType", smpte_transitions);
+  }
+  return smpte_transition_type;
+}
+
+
+static void gst_smpte_finalize (GstSMPTE * smpte);
+
+static GstFlowReturn gst_smpte_collected (GstCollectPads * pads,
+    GstSMPTE * smpte);
+
+static void gst_smpte_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_smpte_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn gst_smpte_change_state (GstElement * element,
+    GstStateChange transition);
+
+/*static guint gst_smpte_signals[LAST_SIGNAL] = { 0 }; */
+
+#define gst_smpte_parent_class parent_class
+G_DEFINE_TYPE (GstSMPTE, gst_smpte, GST_TYPE_ELEMENT);
+
+static void
+gst_smpte_class_init (GstSMPTEClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->set_property = gst_smpte_set_property;
+  gobject_class->get_property = gst_smpte_get_property;
+  gobject_class->finalize = (GObjectFinalizeFunc) gst_smpte_finalize;
+
+  _gst_mask_init ();
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TYPE,
+      g_param_spec_enum ("type", "Type", "The type of transition to use",
+          GST_TYPE_SMPTE_TRANSITION_TYPE, DEFAULT_PROP_TYPE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BORDER,
+      g_param_spec_int ("border", "Border",
+          "The border width of the transition", 0, G_MAXINT,
+          DEFAULT_PROP_BORDER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEPTH,
+      g_param_spec_int ("depth", "Depth", "Depth of the mask in bits", 1, 24,
+          DEFAULT_PROP_DEPTH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DURATION,
+      g_param_spec_uint64 ("duration", "Duration",
+          "Duration of the transition effect in nanoseconds", 0, G_MAXUINT64,
+          DEFAULT_PROP_DURATION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_INVERT,
+      g_param_spec_boolean ("invert", "Invert",
+          "Invert transition mask", DEFAULT_PROP_INVERT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_smpte_change_state);
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_smpte_sink1_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_smpte_sink2_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_smpte_src_template);
+  gst_element_class_set_static_metadata (gstelement_class, "SMPTE transitions",
+      "Filter/Editor/Video",
+      "Apply the standard SMPTE transitions on video images",
+      "Wim Taymans <wim.taymans@chello.be>");
+}
+
+/*                              wht  yel  cya  grn  mag  red  blu  blk   -I    Q */
+static const int y_colors[] = { 255, 226, 179, 150, 105, 76, 29, 16, 16, 0 };
+static const int u_colors[] = { 128, 0, 170, 46, 212, 85, 255, 128, 0, 128 };
+static const int v_colors[] = { 128, 155, 0, 21, 235, 255, 107, 128, 128, 255 };
+
+static void
+fill_i420 (GstVideoInfo * vinfo, guint8 * data, gint height, gint color)
+{
+  gint size = GST_VIDEO_INFO_COMP_STRIDE (vinfo, 0) * GST_ROUND_UP_2 (height);
+  gint size4 = size >> 2;
+  guint8 *yp = data;
+  guint8 *up = data + GST_VIDEO_INFO_COMP_OFFSET (vinfo, 1);
+  guint8 *vp = data + GST_VIDEO_INFO_COMP_OFFSET (vinfo, 2);
+
+  memset (yp, y_colors[color], size);
+  memset (up, u_colors[color], size4);
+  memset (vp, v_colors[color], size4);
+}
+
+static gboolean
+gst_smpte_update_mask (GstSMPTE * smpte, gint type, gboolean invert,
+    gint depth, gint width, gint height)
+{
+  GstMask *newmask;
+
+  if (smpte->mask) {
+    if (smpte->type == type &&
+        smpte->invert == invert &&
+        smpte->depth == depth &&
+        smpte->width == width && smpte->height == height)
+      return TRUE;
+  }
+
+  newmask = gst_mask_factory_new (type, invert, depth, width, height);
+  if (newmask) {
+    if (smpte->mask) {
+      gst_mask_destroy (smpte->mask);
+    }
+    smpte->mask = newmask;
+    smpte->type = type;
+    smpte->invert = invert;
+    smpte->depth = depth;
+    smpte->width = width;
+    smpte->height = height;
+
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static gboolean
+gst_smpte_setcaps (GstPad * pad, GstCaps * caps)
+{
+  GstSMPTE *smpte;
+  gboolean ret;
+  GstVideoInfo vinfo;
+
+  smpte = GST_SMPTE (GST_PAD_PARENT (pad));
+
+  gst_video_info_init (&vinfo);
+  if (!gst_video_info_from_caps (&vinfo, caps))
+    return FALSE;
+
+  smpte->width = GST_VIDEO_INFO_WIDTH (&vinfo);
+  smpte->height = GST_VIDEO_INFO_HEIGHT (&vinfo);
+  smpte->fps_num = GST_VIDEO_INFO_FPS_N (&vinfo);
+  smpte->fps_denom = GST_VIDEO_INFO_FPS_D (&vinfo);
+
+  /* figure out the duration in frames */
+  smpte->end_position = gst_util_uint64_scale (smpte->duration,
+      smpte->fps_num, GST_SECOND * smpte->fps_denom);
+
+  GST_DEBUG_OBJECT (smpte, "duration: %d frames", smpte->end_position);
+
+  ret =
+      gst_smpte_update_mask (smpte, smpte->type, smpte->invert, smpte->depth,
+      smpte->width, smpte->height);
+
+  if (pad == smpte->sinkpad1) {
+    GST_DEBUG_OBJECT (smpte, "setting pad1 info");
+    smpte->vinfo1 = vinfo;
+  } else {
+    GST_DEBUG_OBJECT (smpte, "setting pad2 info");
+    smpte->vinfo2 = vinfo;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_smpte_sink_event (GstCollectPads * pads,
+    GstCollectData * data, GstEvent * event, gpointer user_data)
+{
+  GstPad *pad;
+  gboolean ret = FALSE;
+
+  pad = data->pad;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      ret = gst_smpte_setcaps (pad, caps);
+      gst_event_unref (event);
+      event = NULL;
+      break;
+    }
+    default:
+      break;
+  }
+
+  if (event != NULL)
+    return gst_collect_pads_event_default (pads, data, event, FALSE);
+
+  return ret;
+}
+
+static void
+gst_smpte_init (GstSMPTE * smpte)
+{
+  smpte->sinkpad1 =
+      gst_pad_new_from_static_template (&gst_smpte_sink1_template, "sink1");
+  GST_PAD_SET_PROXY_CAPS (smpte->sinkpad1);
+  gst_element_add_pad (GST_ELEMENT (smpte), smpte->sinkpad1);
+
+  smpte->sinkpad2 =
+      gst_pad_new_from_static_template (&gst_smpte_sink2_template, "sink2");
+  GST_PAD_SET_PROXY_CAPS (smpte->sinkpad2);
+  gst_element_add_pad (GST_ELEMENT (smpte), smpte->sinkpad2);
+
+  smpte->srcpad =
+      gst_pad_new_from_static_template (&gst_smpte_src_template, "src");
+  gst_element_add_pad (GST_ELEMENT (smpte), smpte->srcpad);
+
+  smpte->collect = gst_collect_pads_new ();
+  gst_collect_pads_set_function (smpte->collect,
+      (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_smpte_collected), smpte);
+  gst_collect_pads_set_event_function (smpte->collect,
+      GST_DEBUG_FUNCPTR (gst_smpte_sink_event), smpte);
+
+  gst_collect_pads_add_pad (smpte->collect, smpte->sinkpad1,
+      sizeof (GstCollectData), NULL, TRUE);
+  gst_collect_pads_add_pad (smpte->collect, smpte->sinkpad2,
+      sizeof (GstCollectData), NULL, TRUE);
+
+  smpte->type = DEFAULT_PROP_TYPE;
+  smpte->border = DEFAULT_PROP_BORDER;
+  smpte->depth = DEFAULT_PROP_DEPTH;
+  smpte->duration = DEFAULT_PROP_DURATION;
+  smpte->invert = DEFAULT_PROP_INVERT;
+  smpte->fps_num = 0;
+  smpte->fps_denom = 1;
+}
+
+static void
+gst_smpte_finalize (GstSMPTE * smpte)
+{
+  if (smpte->collect) {
+    gst_object_unref (smpte->collect);
+  }
+  if (smpte->mask) {
+    gst_mask_destroy (smpte->mask);
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize ((GObject *) smpte);
+}
+
+static void
+gst_smpte_reset (GstSMPTE * smpte)
+{
+  smpte->width = -1;
+  smpte->height = -1;
+  smpte->position = 0;
+  smpte->end_position = 0;
+  smpte->send_stream_start = TRUE;
+}
+
+static void
+gst_smpte_blend_i420 (GstVideoFrame * frame1, GstVideoFrame * frame2,
+    GstVideoFrame * oframe, GstMask * mask, gint border, gint pos)
+{
+  guint32 *maskp;
+  gint value;
+  gint i, j;
+  gint min, max;
+  guint8 *in1, *in2, *out, *in1u, *in1v, *in2u, *in2v, *outu, *outv;
+  gint width, height;
+
+  if (border == 0)
+    border++;
+
+  min = pos - border;
+  max = pos;
+
+  width = GST_VIDEO_FRAME_WIDTH (frame1);
+  height = GST_VIDEO_FRAME_HEIGHT (frame1);
+
+  in1 = GST_VIDEO_FRAME_COMP_DATA (frame1, 0);
+  in2 = GST_VIDEO_FRAME_COMP_DATA (frame2, 0);
+  out = GST_VIDEO_FRAME_COMP_DATA (oframe, 0);
+
+  in1u = GST_VIDEO_FRAME_COMP_DATA (frame1, 1);
+  in1v = GST_VIDEO_FRAME_COMP_DATA (frame1, 2);
+  in2u = GST_VIDEO_FRAME_COMP_DATA (frame2, 1);
+  in2v = GST_VIDEO_FRAME_COMP_DATA (frame2, 2);
+  outu = GST_VIDEO_FRAME_COMP_DATA (oframe, 1);
+  outv = GST_VIDEO_FRAME_COMP_DATA (oframe, 2);
+
+  maskp = mask->data;
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      value = *maskp++;
+      value = ((CLAMP (value, min, max) - min) << 8) / border;
+
+      out[j] = ((in1[j] * value) + (in2[j] * (256 - value))) >> 8;
+      if (!(i & 1) && !(j & 1)) {
+        outu[j / 2] =
+            ((in1u[j / 2] * value) + (in2u[j / 2] * (256 - value))) >> 8;
+        outv[j / 2] =
+            ((in1v[j / 2] * value) + (in2v[j / 2] * (256 - value))) >> 8;
+      }
+    }
+
+    in1 += GST_VIDEO_FRAME_COMP_STRIDE (frame1, 0);
+    in2 += GST_VIDEO_FRAME_COMP_STRIDE (frame2, 0);
+    out += GST_VIDEO_FRAME_COMP_STRIDE (oframe, 0);
+
+    if (!(i & 1)) {
+      in1u += GST_VIDEO_FRAME_COMP_STRIDE (frame1, 1);
+      in2u += GST_VIDEO_FRAME_COMP_STRIDE (frame2, 1);
+      in1v += GST_VIDEO_FRAME_COMP_STRIDE (frame1, 2);
+      in2v += GST_VIDEO_FRAME_COMP_STRIDE (frame1, 2);
+      outu += GST_VIDEO_FRAME_COMP_STRIDE (oframe, 1);
+      outv += GST_VIDEO_FRAME_COMP_STRIDE (oframe, 2);
+    }
+  }
+}
+
+static GstFlowReturn
+gst_smpte_collected (GstCollectPads * pads, GstSMPTE * smpte)
+{
+  GstBuffer *outbuf;
+  GstClockTime ts;
+  GstBuffer *in1 = NULL, *in2 = NULL;
+  GSList *collected;
+  GstMapInfo map;
+  GstVideoFrame frame1, frame2, oframe;
+
+  if (G_UNLIKELY (smpte->fps_num == 0))
+    goto not_negotiated;
+
+  if (!gst_pad_has_current_caps (smpte->sinkpad1) ||
+      !gst_pad_has_current_caps (smpte->sinkpad2))
+    goto not_negotiated;
+
+  if (!gst_video_info_is_equal (&smpte->vinfo1, &smpte->vinfo2))
+    goto input_formats_do_not_match;
+
+  if (smpte->send_stream_start) {
+    gchar s_id[32];
+
+    /* stream-start (FIXME: create id based on input ids) */
+    g_snprintf (s_id, sizeof (s_id), "smpte-%08x", g_random_int ());
+    gst_pad_push_event (smpte->srcpad, gst_event_new_stream_start (s_id));
+    smpte->send_stream_start = FALSE;
+  }
+
+  ts = gst_util_uint64_scale_int (smpte->position * GST_SECOND,
+      smpte->fps_denom, smpte->fps_num);
+
+  for (collected = pads->data; collected; collected = g_slist_next (collected)) {
+    GstCollectData *data;
+
+    data = (GstCollectData *) collected->data;
+
+    if (data->pad == smpte->sinkpad1)
+      in1 = gst_collect_pads_pop (pads, data);
+    else if (data->pad == smpte->sinkpad2)
+      in2 = gst_collect_pads_pop (pads, data);
+  }
+
+  if (in1 == NULL) {
+    /* if no input, make picture black */
+    in1 = gst_buffer_new_and_alloc (GST_VIDEO_INFO_SIZE (&smpte->vinfo1));
+    gst_buffer_map (in1, &map, GST_MAP_WRITE);
+    fill_i420 (&smpte->vinfo1, map.data, smpte->height, 7);
+    gst_buffer_unmap (in1, &map);
+  }
+  if (in2 == NULL) {
+    /* if no input, make picture white */
+    in2 = gst_buffer_new_and_alloc (GST_VIDEO_INFO_SIZE (&smpte->vinfo2));
+    gst_buffer_map (in2, &map, GST_MAP_WRITE);
+    fill_i420 (&smpte->vinfo2, map.data, smpte->height, 0);
+    gst_buffer_unmap (in2, &map);
+  }
+
+  if (smpte->position < smpte->end_position) {
+    outbuf = gst_buffer_new_and_alloc (GST_VIDEO_INFO_SIZE (&smpte->vinfo1));
+
+    /* set caps if not done yet */
+    if (!gst_pad_has_current_caps (smpte->srcpad)) {
+      GstCaps *caps;
+      GstSegment segment;
+
+      caps = gst_video_info_to_caps (&smpte->vinfo1);
+
+      gst_pad_set_caps (smpte->srcpad, caps);
+      gst_caps_unref (caps);
+
+      gst_segment_init (&segment, GST_FORMAT_TIME);
+      gst_pad_push_event (smpte->srcpad, gst_event_new_segment (&segment));
+    }
+
+    gst_video_frame_map (&frame1, &smpte->vinfo1, in1, GST_MAP_READ);
+    gst_video_frame_map (&frame2, &smpte->vinfo2, in2, GST_MAP_READ);
+    /* re-use either info, now know they are essentially identical */
+    gst_video_frame_map (&oframe, &smpte->vinfo1, outbuf, GST_MAP_WRITE);
+    gst_smpte_blend_i420 (&frame1, &frame2, &oframe, smpte->mask, smpte->border,
+        ((1 << smpte->depth) + smpte->border) *
+        smpte->position / smpte->end_position);
+    gst_video_frame_unmap (&frame1);
+    gst_video_frame_unmap (&frame2);
+    gst_video_frame_unmap (&oframe);
+  } else {
+    outbuf = in2;
+    gst_buffer_ref (in2);
+  }
+
+  smpte->position++;
+
+  if (in1)
+    gst_buffer_unref (in1);
+  if (in2)
+    gst_buffer_unref (in2);
+
+  GST_BUFFER_TIMESTAMP (outbuf) = ts;
+
+  return gst_pad_push (smpte->srcpad, outbuf);
+
+  /* ERRORS */
+not_negotiated:
+  {
+    GST_ELEMENT_ERROR (smpte, CORE, NEGOTIATION, (NULL),
+        ("No input format negotiated"));
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+input_formats_do_not_match:
+  {
+    GstCaps *caps1, *caps2;
+
+    caps1 = gst_pad_get_current_caps (smpte->sinkpad1);
+    caps2 = gst_pad_get_current_caps (smpte->sinkpad2);
+    GST_ELEMENT_ERROR (smpte, CORE, NEGOTIATION, (NULL),
+        ("input formats don't match: %" GST_PTR_FORMAT " vs. %" GST_PTR_FORMAT,
+            caps1, caps2));
+    if (caps1)
+      gst_caps_unref (caps1);
+    if (caps2)
+      gst_caps_unref (caps2);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static void
+gst_smpte_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstSMPTE *smpte;
+
+  smpte = GST_SMPTE (object);
+
+  switch (prop_id) {
+    case PROP_TYPE:
+      smpte->type = g_value_get_enum (value);
+      break;
+    case PROP_BORDER:
+      smpte->border = g_value_get_int (value);
+      break;
+    case PROP_DEPTH:
+      smpte->depth = g_value_get_int (value);
+      break;
+    case PROP_DURATION:
+      smpte->duration = g_value_get_uint64 (value);
+      break;
+    case PROP_INVERT:
+      smpte->invert = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_smpte_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstSMPTE *smpte;
+
+  smpte = GST_SMPTE (object);
+
+  switch (prop_id) {
+    case PROP_TYPE:
+      g_value_set_enum (value, smpte->type);
+      break;
+    case PROP_BORDER:
+      g_value_set_int (value, smpte->border);
+      break;
+    case PROP_DEPTH:
+      g_value_set_int (value, smpte->depth);
+      break;
+    case PROP_DURATION:
+      g_value_set_uint64 (value, smpte->duration);
+      break;
+    case PROP_INVERT:
+      g_value_set_boolean (value, smpte->invert);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStateChangeReturn
+gst_smpte_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstSMPTE *smpte;
+
+  smpte = GST_SMPTE (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_smpte_reset (smpte);
+      GST_LOG_OBJECT (smpte, "starting collectpads");
+      gst_collect_pads_start (smpte->collect);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      GST_LOG_OBJECT (smpte, "stopping collectpads");
+      gst_collect_pads_stop (smpte->collect);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_smpte_reset (smpte);
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+gboolean
+gst_smpte_plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_smpte_debug, "smpte", 0,
+      "SMPTE transition effect");
+
+  return gst_element_register (plugin, "smpte", GST_RANK_NONE, GST_TYPE_SMPTE);
+}
diff --git a/gst/smpte/gstsmpte.h b/gst/smpte/gstsmpte.h
new file mode 100644
index 0000000..3039942
--- /dev/null
+++ b/gst/smpte/gstsmpte.h
@@ -0,0 +1,85 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_SMPTE_H__
+#define __GST_SMPTE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstcollectpads.h>
+#include <gst/video/video.h>
+
+G_BEGIN_DECLS
+
+#include "gstmask.h"
+
+#define GST_TYPE_SMPTE \
+  (gst_smpte_get_type())
+#define GST_SMPTE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SMPTE,GstSMPTE))
+#define GST_SMPTE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SMPTE,GstSMPTEClass))
+#define GST_IS_SMPTE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SMPTE))
+#define GST_IS_SMPTE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SMPTE))
+
+typedef struct _GstSMPTE GstSMPTE;
+typedef struct _GstSMPTEClass GstSMPTEClass;
+
+struct _GstSMPTE {
+  GstElement     element;
+
+  /* pads */
+  GstPad        *srcpad,
+                *sinkpad1,
+                *sinkpad2;
+  GstCollectPads *collect;
+  gboolean        send_stream_start;
+
+  /* properties */
+  gint           type;
+  gint           border;
+  gint           depth;
+  guint64        duration;
+  gboolean       invert;
+
+  /* negotiated format */
+  gint           width;
+  gint           height;
+  gint           fps_num;
+  gint           fps_denom;
+  GstVideoInfo   vinfo1;
+  GstVideoInfo   vinfo2;
+
+  /* state of the effect */
+  gint           position;
+  gint           end_position;
+  GstMask       *mask;
+};
+
+struct _GstSMPTEClass {
+  GstElementClass parent_class;
+};
+
+GType gst_smpte_get_type (void);
+gboolean gst_smpte_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_SMPTE_H__ */
diff --git a/gst/smpte/gstsmptealpha.c b/gst/smpte/gstsmptealpha.c
new file mode 100644
index 0000000..750748f
--- /dev/null
+++ b/gst/smpte/gstsmptealpha.c
@@ -0,0 +1,811 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-smptealpha
+ *
+ * smptealpha can accept an I420 or AYUV video stream. An alpha channel is added
+ * using an effect specific SMPTE mask in the I420 input case. In the AYUV case,
+ * the alpha channel is modified using the effect specific SMPTE mask.
+ *
+ * The #GstSmpteAlpha:position property is a controllabe double between 0.0 and
+ * 1.0 that specifies the position in the transition. 0.0 is the start of the
+ * transition with the alpha channel to complete opaque where 1.0 has the alpha
+ * channel set to completely transparent.
+ *
+ * The #GstSmpteAlpha:depth property defines the precision in bits of the mask.
+ * A higher presision will create a mask with smoother gradients in order to
+ * avoid banding.
+ *
+ * <refsect2>
+ * <title>Sample pipelines</title>
+ * <para>
+ * Here is a pipeline to demonstrate the smpte transition :
+ * <programlisting>
+ * gst-launch-1.0 -v videotestsrc ! smptealpha border=20000 type=44
+ * position=0.5 ! videomixer ! videoconvert ! ximagesink
+ * </programlisting>
+ * This shows a midway bowtie-h transition a from a videotestsrc to a
+ * transparent image. The edges of the transition are smoothed with a
+ * 20000 big border.
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+
+#include "gstsmptealpha.h"
+#include "paint.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_smpte_alpha_debug);
+#define GST_CAT_DEFAULT gst_smpte_alpha_debug
+
+static GstStaticPadTemplate gst_smpte_alpha_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("AYUV") ";"
+        GST_VIDEO_CAPS_MAKE ("ARGB") ";" GST_VIDEO_CAPS_MAKE ("BGRA") ";"
+        GST_VIDEO_CAPS_MAKE ("RGBA") ";" GST_VIDEO_CAPS_MAKE ("ARGB"))
+    );
+
+static GstStaticPadTemplate gst_smpte_alpha_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420") ";"
+        GST_VIDEO_CAPS_MAKE ("YV12")
+        ";" GST_VIDEO_CAPS_MAKE ("AYUV")
+        ";" GST_VIDEO_CAPS_MAKE ("ARGB") ";" GST_VIDEO_CAPS_MAKE ("BGRA")
+        ";" GST_VIDEO_CAPS_MAKE ("RGBA") ";" GST_VIDEO_CAPS_MAKE ("ARGB"))
+    );
+
+/* SMPTE signals and properties */
+
+#define DEFAULT_PROP_TYPE	1
+#define DEFAULT_PROP_BORDER	0
+#define DEFAULT_PROP_DEPTH	16
+#define DEFAULT_PROP_POSITION	0.0
+#define DEFAULT_PROP_INVERT   FALSE
+
+enum
+{
+  PROP_0,
+  PROP_TYPE,
+  PROP_BORDER,
+  PROP_DEPTH,
+  PROP_POSITION,
+  PROP_INVERT
+};
+
+#define AYUV_SIZE(w,h)     ((w) * (h) * 4)
+
+#define GST_TYPE_SMPTE_TRANSITION_TYPE (gst_smpte_alpha_transition_type_get_type())
+static GType
+gst_smpte_alpha_transition_type_get_type (void)
+{
+  static GType smpte_transition_type = 0;
+  GEnumValue *smpte_transitions;
+
+  if (!smpte_transition_type) {
+    const GList *definitions;
+    gint i = 0;
+
+    definitions = gst_mask_get_definitions ();
+    smpte_transitions =
+        g_new0 (GEnumValue, g_list_length ((GList *) definitions) + 1);
+
+    while (definitions) {
+      GstMaskDefinition *definition = (GstMaskDefinition *) definitions->data;
+
+      definitions = g_list_next (definitions);
+
+      smpte_transitions[i].value = definition->type;
+      /* older GLib versions have the two fields as non-const, hence the cast */
+      smpte_transitions[i].value_nick = (gchar *) definition->short_name;
+      smpte_transitions[i].value_name = (gchar *) definition->long_name;
+
+      i++;
+    }
+
+    smpte_transition_type =
+        g_enum_register_static ("GstSMPTEAlphaTransitionType",
+        smpte_transitions);
+  }
+  return smpte_transition_type;
+}
+
+
+static void gst_smpte_alpha_finalize (GstSMPTEAlpha * smpte);
+
+static void gst_smpte_alpha_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_smpte_alpha_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_smpte_alpha_set_info (GstVideoFilter * vfilter,
+    GstCaps * incaps, GstVideoInfo * in_info,
+    GstCaps * outcaps, GstVideoInfo * out_info);
+static GstFlowReturn gst_smpte_alpha_transform_frame (GstVideoFilter * vfilter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame);
+static void gst_smpte_alpha_before_transform (GstBaseTransform * trans,
+    GstBuffer * buf);
+static GstCaps *gst_smpte_alpha_transform_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * from, GstCaps * filter);
+
+#define gst_smpte_alpha_parent_class parent_class
+G_DEFINE_TYPE (GstSMPTEAlpha, gst_smpte_alpha, GST_TYPE_VIDEO_FILTER);
+
+static void
+gst_smpte_alpha_class_init (GstSMPTEAlphaClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *element_class = (GstElementClass *) (klass);
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->set_property = gst_smpte_alpha_set_property;
+  gobject_class->get_property = gst_smpte_alpha_get_property;
+
+  gobject_class->finalize = (GObjectFinalizeFunc) gst_smpte_alpha_finalize;
+
+  _gst_mask_init ();
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TYPE,
+      g_param_spec_enum ("type", "Type", "The type of transition to use",
+          GST_TYPE_SMPTE_TRANSITION_TYPE, DEFAULT_PROP_TYPE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BORDER,
+      g_param_spec_int ("border", "Border",
+          "The border width of the transition", 0, G_MAXINT,
+          DEFAULT_PROP_BORDER,
+          GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEPTH,
+      g_param_spec_int ("depth", "Depth", "Depth of the mask in bits", 1, 24,
+          DEFAULT_PROP_DEPTH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_POSITION,
+      g_param_spec_double ("position", "Position",
+          "Position of the transition effect", 0.0, 1.0, DEFAULT_PROP_POSITION,
+          GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstSMPTEAlpha:invert:
+   *
+   * Set to TRUE to invert the transition mask (ie. flip it horizontally).
+   */
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_INVERT,
+      g_param_spec_boolean ("invert", "Invert",
+          "Invert transition mask", DEFAULT_PROP_POSITION,
+          GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  trans_class->before_transform =
+      GST_DEBUG_FUNCPTR (gst_smpte_alpha_before_transform);
+  trans_class->transform_caps =
+      GST_DEBUG_FUNCPTR (gst_smpte_alpha_transform_caps);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_smpte_alpha_set_info);
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_smpte_alpha_transform_frame);
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_smpte_alpha_sink_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_smpte_alpha_src_template);
+  gst_element_class_set_static_metadata (element_class, "SMPTE transitions",
+      "Filter/Editor/Video",
+      "Apply the standard SMPTE transitions as alpha on video images",
+      "Wim Taymans <wim.taymans@gmail.com>");
+}
+
+static gboolean
+gst_smpte_alpha_update_mask (GstSMPTEAlpha * smpte, gint type,
+    gboolean invert, gint depth, gint width, gint height)
+{
+  GstMask *newmask;
+
+  /* try to avoid regenerating the mask if we already have one that is
+   * correct */
+  if (smpte->mask) {
+    if (smpte->type == type &&
+        smpte->invert == invert &&
+        smpte->depth == depth &&
+        smpte->width == width && smpte->height == height)
+      return TRUE;
+  }
+
+  smpte->type = type;
+  smpte->invert = invert;
+  smpte->depth = depth;
+  smpte->width = width;
+  smpte->height = height;
+
+  /* Not negotiated yet */
+  if (width == 0 || height == 0) {
+    return TRUE;
+  }
+
+  newmask = gst_mask_factory_new (type, invert, depth, width, height);
+  if (!newmask)
+    goto mask_failed;
+
+  if (smpte->mask)
+    gst_mask_destroy (smpte->mask);
+
+  smpte->mask = newmask;
+
+  return TRUE;
+
+  /* ERRORS */
+mask_failed:
+  {
+    GST_ERROR_OBJECT (smpte, "failed to create a mask");
+    return FALSE;
+  }
+}
+
+static void
+gst_smpte_alpha_init (GstSMPTEAlpha * smpte)
+{
+  smpte->type = DEFAULT_PROP_TYPE;
+  smpte->border = DEFAULT_PROP_BORDER;
+  smpte->depth = DEFAULT_PROP_DEPTH;
+  smpte->position = DEFAULT_PROP_POSITION;
+  smpte->invert = DEFAULT_PROP_INVERT;
+}
+
+#define CREATE_ARGB_FUNC(name, A, R, G, B) \
+static void \
+gst_smpte_alpha_process_##name##_##name (GstSMPTEAlpha * smpte, \
+    const GstVideoFrame * in_frame, GstVideoFrame * out_frame, GstMask * mask, \
+    gint border, gint pos) \
+{ \
+  gint i, j; \
+  const guint32 *maskp; \
+  gint value; \
+  gint min, max; \
+  gint width, height; \
+  guint8 *in, *out; \
+  gint src_wrap, dest_wrap; \
+  \
+  if (border == 0) \
+    border++; \
+  \
+  min = pos - border; \
+  max = pos; \
+  GST_DEBUG_OBJECT (smpte, "pos %d, min %d, max %d, border %d", pos, min, max, \
+      border); \
+  \
+  maskp = mask->data; \
+  \
+  width = GST_VIDEO_FRAME_WIDTH (out_frame); \
+  height = GST_VIDEO_FRAME_HEIGHT (out_frame); \
+  \
+  in = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0); \
+  out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0); \
+  src_wrap = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0) - (width << 2); \
+  dest_wrap = GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0) - (width << 2); \
+  \
+  /* we basically copy the source to dest but we scale the alpha channel with \
+   * the mask */ \
+  for (i = 0; i < height; i++) { \
+    for (j = 0; j < width; j++) { \
+      value = *maskp++; \
+      out[A] = (in[A] * ((CLAMP (value, min, max) - min) << 8) / border) >> 8; \
+      out[R] = in[R]; \
+      out[G] = in[G]; \
+      out[B] = in[B]; \
+      out += 4; \
+      in += 4; \
+    } \
+    in += src_wrap; \
+    out += dest_wrap; \
+  } \
+}
+
+CREATE_ARGB_FUNC (argb, 0, 1, 2, 3);
+CREATE_ARGB_FUNC (bgra, 3, 2, 1, 0);
+CREATE_ARGB_FUNC (abgr, 0, 3, 2, 1);
+CREATE_ARGB_FUNC (rgba, 3, 0, 1, 2);
+
+static void
+gst_smpte_alpha_process_ayuv_ayuv (GstSMPTEAlpha * smpte,
+    const GstVideoFrame * in_frame, GstVideoFrame * out_frame, GstMask * mask,
+    gint border, gint pos)
+{
+  gint i, j;
+  const guint32 *maskp;
+  gint value;
+  gint min, max;
+  gint width, height;
+  guint8 *in, *out;
+  gint src_wrap, dest_wrap;
+
+  if (border == 0)
+    border++;
+
+  min = pos - border;
+  max = pos;
+  GST_DEBUG_OBJECT (smpte, "pos %d, min %d, max %d, border %d", pos, min, max,
+      border);
+
+  maskp = mask->data;
+
+  width = GST_VIDEO_FRAME_WIDTH (out_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (out_frame);
+
+  in = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+  src_wrap = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0) - (width << 2);
+  dest_wrap = GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0) - (width << 2);
+
+  /* we basically copy the source to dest but we scale the alpha channel with
+   * the mask */
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      value = *maskp++;
+      *out++ = (*in++ * ((CLAMP (value, min, max) - min) << 8) / border) >> 8;
+      *out++ = *in++;
+      *out++ = *in++;
+      *out++ = *in++;
+    }
+    in += src_wrap;
+    out += dest_wrap;
+  }
+}
+
+static void
+gst_smpte_alpha_process_i420_ayuv (GstSMPTEAlpha * smpte,
+    const GstVideoFrame * in_frame, GstVideoFrame * out_frame, GstMask * mask,
+    gint border, gint pos)
+{
+  const guint8 *srcY;
+  const guint8 *srcU;
+  const guint8 *srcV;
+  guint8 *out;
+  gint i, j;
+  gint src_wrap, src_u_wrap, src_v_wrap, dest_wrap;
+  gint y_stride, u_stride, v_stride;
+  gboolean odd_width;
+  const guint32 *maskp;
+  gint value;
+  gint min, max;
+  gint width, height;
+
+  if (border == 0)
+    border++;
+
+  min = pos - border;
+  max = pos;
+  GST_DEBUG_OBJECT (smpte, "pos %d, min %d, max %d, border %d", pos, min, max,
+      border);
+
+  maskp = mask->data;
+
+  width = GST_VIDEO_FRAME_WIDTH (out_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (out_frame);
+
+  y_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
+  u_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 1);
+  v_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 2);
+
+  src_wrap = y_stride - width;
+  src_u_wrap = u_stride - (width / 2);
+  src_v_wrap = v_stride - (width / 2);
+
+  srcY = GST_VIDEO_FRAME_COMP_DATA (in_frame, 0);
+  srcU = GST_VIDEO_FRAME_COMP_DATA (in_frame, 1);
+  srcV = GST_VIDEO_FRAME_COMP_DATA (in_frame, 2);
+
+  out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+  dest_wrap = GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0) - (width << 2);
+
+  odd_width = (width % 2 != 0);
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width / 2; j++) {
+      value = *maskp++;
+      *out++ = (0xff * ((CLAMP (value, min, max) - min) << 8) / border) >> 8;
+      *out++ = *srcY++;
+      *out++ = *srcU;
+      *out++ = *srcV;
+      value = *maskp++;
+      *out++ = (0xff * ((CLAMP (value, min, max) - min) << 8) / border) >> 8;
+      *out++ = *srcY++;
+      *out++ = *srcU++;
+      *out++ = *srcV++;
+    }
+    /* Might have one odd column left to do */
+    if (odd_width) {
+      value = *maskp++;
+      *out++ = (0xff * ((CLAMP (value, min, max) - min) << 8) / border) >> 8;
+      *out++ = *srcY++;
+      *out++ = *srcU;
+      *out++ = *srcV;
+    }
+    if (i % 2 == 0) {
+      srcU -= width / 2;
+      srcV -= width / 2;
+    } else {
+      srcU += src_u_wrap;
+      srcV += src_v_wrap;
+    }
+    srcY += src_wrap;
+    out += dest_wrap;
+  }
+}
+
+static void
+gst_smpte_alpha_before_transform (GstBaseTransform * trans, GstBuffer * buf)
+{
+  GstSMPTEAlpha *smpte = GST_SMPTE_ALPHA (trans);
+  GstClockTime timestamp, stream_time;
+
+  /* first sync the controller to the current stream_time of the buffer */
+  timestamp = GST_BUFFER_TIMESTAMP (buf);
+  stream_time =
+      gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (smpte, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (smpte), stream_time);
+}
+
+static GstFlowReturn
+gst_smpte_alpha_transform_frame (GstVideoFilter * vfilter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame)
+{
+  GstSMPTEAlpha *smpte = GST_SMPTE_ALPHA (vfilter);
+  gdouble position;
+  gint border;
+
+  if (G_UNLIKELY (!smpte->process))
+    goto not_negotiated;
+
+  GST_OBJECT_LOCK (smpte);
+  position = smpte->position;
+  border = smpte->border;
+
+  /* run the type specific filter code */
+  smpte->process (smpte, in_frame, out_frame,
+      smpte->mask, border, ((1 << smpte->depth) + border) * position);
+  GST_OBJECT_UNLOCK (smpte);
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+not_negotiated:
+  {
+    GST_ELEMENT_ERROR (smpte, CORE, NEGOTIATION, (NULL),
+        ("No input format negotiated"));
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+}
+
+static GstCaps *
+gst_smpte_alpha_transform_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * from, GstCaps * filter)
+{
+  GstCaps *result, *tmp_caps, *tmpl_caps = NULL;
+  gint i, j;
+
+  tmp_caps = gst_caps_new_empty ();
+
+  for (i = 0; i < gst_caps_get_size (from); i++) {
+    GstStructure *structure;
+    const GValue *val, *lval;
+    GValue list = { 0, };
+    GValue aval = { 0, };
+    const gchar *str;
+
+    structure = gst_structure_copy (gst_caps_get_structure (from, i));
+    /* we can transform I420 to AYUV,
+     * so need to locate and substitute AYUV for the both of them */
+    val = gst_structure_get_value (structure, "format");
+    if (val && GST_VALUE_HOLDS_LIST (val)) {
+      gboolean seen_ayuv = FALSE, seen_i420 = FALSE;
+
+      g_value_init (&list, GST_TYPE_LIST);
+      for (j = 0; j < gst_value_list_get_size (val); j++) {
+        lval = gst_value_list_get_value (val, j);
+        if ((str = g_value_get_string (lval))) {
+          if (strcmp (str, "AYUV") == 0) {
+            seen_ayuv = TRUE;
+          } else if (strcmp (str, "I420") == 0) {
+            seen_i420 = TRUE;
+          }
+        }
+      }
+      if (seen_ayuv && !seen_i420) {
+        str = "I420";
+      } else if (seen_i420 && !seen_ayuv) {
+        str = "AYUV";
+      } else
+        str = NULL;
+      if (str) {
+        g_value_copy (val, &list);
+        g_value_init (&aval, G_TYPE_STRING);
+        g_value_set_string (&aval, str);
+        gst_value_list_append_value (&list, &aval);
+        g_value_reset (&aval);
+        gst_structure_set_value (structure, "format", &list);
+        g_value_unset (&list);
+      }
+    } else if (val && G_VALUE_HOLDS_STRING (val)) {
+      if ((str = g_value_get_string (val)) &&
+          ((strcmp (str, "AYUV") == 0) || (strcmp (str, "I420") == 0))) {
+        g_value_init (&list, GST_TYPE_LIST);
+        g_value_init (&aval, G_TYPE_STRING);
+        g_value_set_string (&aval, "AYUV");
+        gst_value_list_append_value (&list, &aval);
+        g_value_reset (&aval);
+        g_value_set_string (&aval, "I420");
+        gst_value_list_append_value (&list, &aval);
+        g_value_reset (&aval);
+        gst_structure_set_value (structure, "format", &list);
+        g_value_unset (&list);
+      }
+    } else {
+      gst_structure_remove_field (structure, "format");
+    }
+
+    gst_structure_remove_field (structure, "colorimetry");
+    gst_structure_remove_field (structure, "chroma-site");
+
+    gst_caps_append_structure (tmp_caps, structure);
+  }
+
+  /* Get the appropriate template */
+  if (direction == GST_PAD_SINK) {
+    tmpl_caps =
+        gst_static_pad_template_get_caps (&gst_smpte_alpha_src_template);
+  } else if (direction == GST_PAD_SRC) {
+    tmpl_caps =
+        gst_static_pad_template_get_caps (&gst_smpte_alpha_sink_template);
+  } else {
+    g_assert_not_reached ();
+  }
+
+  /* Intersect with our template caps */
+  result = gst_caps_intersect (tmp_caps, tmpl_caps);
+  gst_caps_unref (tmpl_caps);
+  gst_caps_unref (tmp_caps);
+
+  result = gst_caps_simplify (result);
+
+  GST_LOG_OBJECT (trans, "transformed %" GST_PTR_FORMAT " to %" GST_PTR_FORMAT,
+      from, result);
+
+  if (filter) {
+    GstCaps *intersection;
+
+    GST_DEBUG_OBJECT (trans, "Using filter caps %" GST_PTR_FORMAT, filter);
+    intersection =
+        gst_caps_intersect_full (filter, result, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (result);
+    result = intersection;
+    GST_DEBUG_OBJECT (trans, "Intersection %" GST_PTR_FORMAT, result);
+  }
+
+  return result;
+}
+
+static gboolean
+gst_smpte_alpha_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstSMPTEAlpha *smpte = GST_SMPTE_ALPHA (vfilter);
+  gboolean ret;
+
+  smpte->process = NULL;
+  smpte->in_format = GST_VIDEO_INFO_FORMAT (in_info);
+  smpte->out_format = GST_VIDEO_INFO_FORMAT (out_info);
+
+  /* try to update the mask now, this will also adjust the width/height on
+   * success */
+  GST_OBJECT_LOCK (smpte);
+  ret =
+      gst_smpte_alpha_update_mask (smpte, smpte->type, smpte->invert,
+      smpte->depth, GST_VIDEO_INFO_WIDTH (out_info),
+      GST_VIDEO_INFO_HEIGHT (out_info));
+  GST_OBJECT_UNLOCK (smpte);
+
+  if (!ret)
+    goto mask_failed;
+
+  switch (smpte->out_format) {
+    case GST_VIDEO_FORMAT_AYUV:
+      switch (smpte->in_format) {
+        case GST_VIDEO_FORMAT_AYUV:
+          smpte->process = gst_smpte_alpha_process_ayuv_ayuv;
+          break;
+        case GST_VIDEO_FORMAT_I420:
+          smpte->process = gst_smpte_alpha_process_i420_ayuv;
+          break;
+        default:
+          break;
+      }
+      break;
+    case GST_VIDEO_FORMAT_ARGB:
+      switch (smpte->in_format) {
+        case GST_VIDEO_FORMAT_ARGB:
+          smpte->process = gst_smpte_alpha_process_argb_argb;
+          break;
+        default:
+          break;
+      }
+      break;
+    case GST_VIDEO_FORMAT_RGBA:
+      switch (smpte->in_format) {
+        case GST_VIDEO_FORMAT_RGBA:
+          smpte->process = gst_smpte_alpha_process_rgba_rgba;
+          break;
+        default:
+          break;
+      }
+      break;
+    case GST_VIDEO_FORMAT_ABGR:
+      switch (smpte->in_format) {
+        case GST_VIDEO_FORMAT_ABGR:
+          smpte->process = gst_smpte_alpha_process_abgr_abgr;
+          break;
+        default:
+          break;
+      }
+      break;
+    case GST_VIDEO_FORMAT_BGRA:
+      switch (smpte->in_format) {
+        case GST_VIDEO_FORMAT_BGRA:
+          smpte->process = gst_smpte_alpha_process_bgra_bgra;
+          break;
+        default:
+          break;
+      }
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+
+  /* ERRORS */
+mask_failed:
+  {
+    GST_ERROR_OBJECT (smpte, "failed creating the mask");
+    return FALSE;
+  }
+}
+
+static void
+gst_smpte_alpha_finalize (GstSMPTEAlpha * smpte)
+{
+  if (smpte->mask)
+    gst_mask_destroy (smpte->mask);
+  smpte->mask = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize ((GObject *) smpte);
+}
+
+static void
+gst_smpte_alpha_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstSMPTEAlpha *smpte = GST_SMPTE_ALPHA (object);
+
+  switch (prop_id) {
+    case PROP_TYPE:{
+      gint type;
+
+      type = g_value_get_enum (value);
+
+      GST_OBJECT_LOCK (smpte);
+      gst_smpte_alpha_update_mask (smpte, type, smpte->invert,
+          smpte->depth, smpte->width, smpte->height);
+      GST_OBJECT_UNLOCK (smpte);
+      break;
+    }
+    case PROP_BORDER:
+      GST_OBJECT_LOCK (smpte);
+      smpte->border = g_value_get_int (value);
+      GST_OBJECT_UNLOCK (smpte);
+      break;
+    case PROP_DEPTH:{
+      gint depth;
+
+      depth = g_value_get_int (value);
+
+      GST_OBJECT_LOCK (smpte);
+      gst_smpte_alpha_update_mask (smpte, smpte->type, smpte->invert,
+          depth, smpte->width, smpte->height);
+      GST_OBJECT_UNLOCK (smpte);
+      break;
+    }
+    case PROP_POSITION:
+      GST_OBJECT_LOCK (smpte);
+      smpte->position = g_value_get_double (value);
+      GST_OBJECT_UNLOCK (smpte);
+      break;
+    case PROP_INVERT:{
+      gboolean invert;
+
+      invert = g_value_get_boolean (value);
+      GST_OBJECT_LOCK (smpte);
+      gst_smpte_alpha_update_mask (smpte, smpte->type, invert,
+          smpte->depth, smpte->width, smpte->height);
+      GST_OBJECT_UNLOCK (smpte);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_smpte_alpha_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstSMPTEAlpha *smpte;
+
+  smpte = GST_SMPTE_ALPHA (object);
+
+  switch (prop_id) {
+    case PROP_TYPE:
+      GST_OBJECT_LOCK (smpte);
+      g_value_set_enum (value, smpte->type);
+      GST_OBJECT_UNLOCK (smpte);
+      break;
+    case PROP_BORDER:
+      GST_OBJECT_LOCK (smpte);
+      g_value_set_int (value, smpte->border);
+      GST_OBJECT_UNLOCK (smpte);
+      break;
+    case PROP_DEPTH:
+      GST_OBJECT_LOCK (smpte);
+      g_value_set_int (value, smpte->depth);
+      GST_OBJECT_UNLOCK (smpte);
+      break;
+    case PROP_POSITION:
+      GST_OBJECT_LOCK (smpte);
+      g_value_set_double (value, smpte->position);
+      GST_OBJECT_UNLOCK (smpte);
+      break;
+    case PROP_INVERT:
+      GST_OBJECT_LOCK (smpte);
+      g_value_set_boolean (value, smpte->invert);
+      GST_OBJECT_UNLOCK (smpte);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+gboolean
+gst_smpte_alpha_plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_smpte_alpha_debug, "smptealpha", 0,
+      "SMPTE alpha effect");
+
+  return gst_element_register (plugin, "smptealpha", GST_RANK_NONE,
+      GST_TYPE_SMPTE_ALPHA);
+}
diff --git a/gst/smpte/gstsmptealpha.h b/gst/smpte/gstsmptealpha.h
new file mode 100644
index 0000000..f8d2b35
--- /dev/null
+++ b/gst/smpte/gstsmptealpha.h
@@ -0,0 +1,79 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_SMPTE_ALPHA_H__
+#define __GST_SMPTE_ALPHA_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+
+G_BEGIN_DECLS
+
+#include "gstmask.h"
+
+#define GST_TYPE_SMPTE_ALPHA \
+  (gst_smpte_alpha_get_type())
+#define GST_SMPTE_ALPHA(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SMPTE_ALPHA,GstSMPTEAlpha))
+#define GST_SMPTE_ALPHA_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SMPTE_ALPHA,GstSMPTEAlphaClass))
+#define GST_IS_SMPTE_ALPHA(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SMPTE_ALPHA))
+#define GST_IS_SMPTE_ALPHA_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SMPTE_ALPHA))
+
+typedef struct _GstSMPTEAlpha GstSMPTEAlpha;
+typedef struct _GstSMPTEAlphaClass GstSMPTEAlphaClass;
+
+struct _GstSMPTEAlpha {
+  GstVideoFilter element;
+
+  /* properties */
+  gint           type;
+  gint           border;
+  gint           depth;
+  gdouble        position;
+  gboolean       invert;
+
+  /* negotiated format */
+  GstVideoFormat in_format, out_format;
+  gint           width;
+  gint           height;
+
+  /* state of the effect */
+  GstMask       *mask;
+
+  /* processing function */
+  void (*process) (GstSMPTEAlpha * smpte, const GstVideoFrame * in, GstVideoFrame * out,
+    GstMask * mask, gint border, gint pos);
+};
+
+struct _GstSMPTEAlphaClass {
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_smpte_alpha_get_type (void);
+gboolean gst_smpte_alpha_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_SMPTE_ALPHA_H__ */
diff --git a/gst/smpte/meson.build b/gst/smpte/meson.build
new file mode 100644
index 0000000..45539d3
--- /dev/null
+++ b/gst/smpte/meson.build
@@ -0,0 +1,17 @@
+smpte_sources = [
+  'gstsmpte.c',
+  'gstmask.c',
+  'barboxwipes.c',
+  'paint.c',
+  'gstsmptealpha.c',
+  'plugin.c',
+]
+
+gstsmpte = library('gstsmpte',
+  smpte_sources,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstvideo_dep, gst_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/smpte/paint.c b/gst/smpte/paint.c
new file mode 100644
index 0000000..cd97323
--- /dev/null
+++ b/gst/smpte/paint.c
@@ -0,0 +1,338 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <stdlib.h>
+#include "paint.h"
+
+#ifndef M_PI
+#define M_PI  3.14159265358979323846
+#endif
+
+void
+gst_smpte_paint_vbox (guint32 * dest, gint stride,
+    gint x0, gint y0, gint c0, gint x1, gint y1, gint c1)
+{
+  gint i, j;
+  gint width, height;
+
+  width = x1 - x0;
+  height = y1 - y0;
+
+  g_assert (width > 0);
+  g_assert (height > 0);
+
+  dest = dest + y0 * stride + x0;
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      dest[j] = (c1 * j + c0 * (width - j)) / width;
+    }
+    dest += stride;
+  }
+}
+
+void
+gst_smpte_paint_hbox (guint32 * dest, gint stride,
+    gint x0, gint y0, gint c0, gint x1, gint y1, gint c1)
+{
+  gint i, j;
+  gint width, height;
+
+  width = x1 - x0;
+  height = y1 - y0;
+
+  g_assert (width > 0);
+  g_assert (height > 0);
+
+  dest = dest + y0 * stride + x0;
+
+  for (i = 0; i < height; i++) {
+    guint32 value = (c1 * i + c0 * (height - i)) / height;
+
+    for (j = 0; j < width; j++) {
+      dest[j] = value;
+    }
+    dest += stride;
+  }
+}
+
+#define STEP_3D_LINE(dxabs,dyabs,dzabs,sdx,sdy,sdz,xr,yr,zr,px,py,pz)           \
+G_STMT_START {                                          \
+  if (dxabs >= dyabs && dxabs >= dzabs) {               \
+    yr += dyabs;                                        \
+    zr += dzabs;                                        \
+    if (yr >= dxabs) {                                  \
+      py += sdy;                                        \
+      yr -= dxabs;                                      \
+    }                                                   \
+    if (zr >= dzabs) {                                  \
+      pz += sdz;                                        \
+      zr -= dxabs;                                      \
+    }                                                   \
+    px += sdx;                                          \
+  } else if (dyabs >= dxabs && dyabs >= dzabs) {        \
+    xr += dxabs;                                        \
+    zr += dzabs;                                        \
+    if (xr >= dyabs) {                                  \
+      px += sdx;                                        \
+      xr -= dyabs;                                      \
+    }                                                   \
+    if (zr >= dzabs) {                                  \
+      pz += sdz;                                        \
+      zr -= dyabs;                                      \
+    }                                                   \
+    py += sdy;                                          \
+  } else {                                              \
+    yr += dyabs;                                        \
+    xr += dxabs;                                        \
+    if (yr >= dyabs) {                                  \
+      py += sdy;                                        \
+      yr -= dzabs;                                      \
+    }                                                   \
+    if (xr >= dyabs) {                                  \
+      px += sdx;                                        \
+      xr -= dzabs;                                      \
+    }                                                   \
+    pz += sdz;                                          \
+  }                                                     \
+} G_STMT_END
+
+#define SWAP_INT(a,b)           \
+G_STMT_START {                  \
+  gint tmp;                     \
+  tmp = (a);                    \
+  (a) = (b);                    \
+  (b) = (tmp);                  \
+} G_STMT_END
+
+#define SIGN(a) ((a) < 0 ? -1 : 1)
+
+#define PREPARE_3D_LINE(x0,y0,z0,x1,y1,z1,dxabs,dyabs,dzabs,sdx,sdy,sdz,xr,yr,zr,px,py,pz)\
+G_STMT_START {                  \
+  gint dx, dy, dz;              \
+  dx = x1 - x0;                 \
+  dy = y1 - y0;                 \
+  dz = z1 - z0;                 \
+  dxabs = abs (dx);             \
+  dyabs = abs (dy);             \
+  dzabs = abs (dz);             \
+  sdx = SIGN (dx);              \
+  sdy = SIGN (dy);              \
+  sdz = SIGN (dz);              \
+  xr = dxabs >> 1;              \
+  yr = dyabs >> 1;              \
+  zr = dzabs >> 1;              \
+  px = x0;                      \
+  py = y0;                      \
+  pz = z0;                      \
+} G_STMT_END
+
+void
+gst_smpte_paint_triangle_linear (guint32 * dest, gint stride,
+    gint x0, gint y0, gint c0,
+    gint x1, gint y1, gint c1, gint x2, gint y2, gint c2)
+{
+  gint sdxl, sdyl, sdcl, dxlabs, dylabs, dclabs, xrl, yrl, crl, pxl, pyl, pcl;
+  gint sdxr, sdyr, sdcr, dxrabs, dyrabs, dcrabs, xrr, yrr, crr, pxr, pyr, pcr;
+  gint i, j, k, seg_start, seg_end;
+
+  if (y0 > y1) {
+    SWAP_INT (x0, x1);
+    SWAP_INT (y0, y1);
+    SWAP_INT (c0, c1);
+  }
+  if (y0 > y2) {
+    SWAP_INT (x0, x2);
+    SWAP_INT (y0, y2);
+    SWAP_INT (c0, c2);
+  }
+  if (y1 > y2) {
+    SWAP_INT (x1, x2);
+    SWAP_INT (y1, y2);
+    SWAP_INT (c1, c2);
+  }
+
+  PREPARE_3D_LINE (x0, y0, c0, x2, y2, c2,
+      dxlabs, dylabs, dclabs, sdxl, sdyl, sdcl, xrl, yrl, crl, pxl, pyl, pcl);
+
+  PREPARE_3D_LINE (x0, y0, c0, x1, y1, c1,
+      dxrabs, dyrabs, dcrabs, sdxr, sdyr, sdcr, xrr, yrr, crr, pxr, pyr, pcr);
+
+  dest = dest + stride * y0;
+  seg_start = y0;
+  seg_end = y1;
+
+  /* do two passes */
+  for (k = 0; k < 2; k++) {
+    for (i = seg_start; i < seg_end; i++) {
+      gint s = pxl, e = pxr, sc = pcl, ec = pcr;
+      gint sign = SIGN (e - s);
+
+      e += sign;
+      for (j = s; j != e; j += sign) {
+        dest[j] = (ec * (j - s) + sc * (e - j)) / (e - s);
+      }
+
+      while (pyr == i) {
+        STEP_3D_LINE (dxrabs, dyrabs, dcrabs, sdxr, sdyr, sdcr,
+            xrr, yrr, crr, pxr, pyr, pcr);
+      }
+      while (pyl == i) {
+        STEP_3D_LINE (dxlabs, dylabs, dclabs, sdxl, sdyl, sdcl,
+            xrl, yrl, crl, pxl, pyl, pcl);
+      }
+      dest += stride;
+    }
+
+    PREPARE_3D_LINE (x1, y1, c1, x2, y2, c2,
+        dxrabs, dyrabs, dcrabs, sdxr, sdyr, sdcr, xrr, yrr, crr, pxr, pyr, pcr);
+
+    seg_start = y1;
+    seg_end = y2;
+  }
+}
+
+static void
+draw_bresenham_line (guint32 * dest, gint stride,
+    gint x0, gint y0, gint x1, gint y1, guint32 col)
+{
+  gint dx, dy;
+  gint x_incr, y_incr;
+  gint i, dpr, dpru, P, indep;
+
+  dx = abs (x1 - x0);
+  dy = abs (y1 - y0);
+
+  dest = dest + y0 * stride + x0;
+
+  x_incr = SIGN (x1 - x0);
+  y_incr = SIGN (y1 - y0) * stride;
+
+  if (dx >= dy) {
+    dpr = dy << 1;
+    i = dx;
+    indep = x_incr;
+  } else {
+    dpr = dx << 1;
+    i = dy;
+    indep = y_incr;
+  }
+
+  dpru = dpr - (i << 1);
+  P = dpr - i;
+
+  for (; i >= 0; i--) {
+    *dest = col;
+
+    if (P > 0) {
+      dest += x_incr;
+      dest += y_incr;
+      P += dpru;
+    } else {
+      dest += indep;
+      P += dpr;
+    }
+  }
+}
+
+void
+gst_smpte_paint_triangle_clock (guint32 * dest, gint stride,
+    gint x0, gint y0, gint c0,
+    gint x1, gint y1, gint c1, gint x2, gint y2, gint c2)
+{
+  gint i;
+  gint sign;
+  gfloat angle, angle_e;
+  gfloat len1;
+
+  angle_e = acos (((x1 - x0) * (x2 - x0) + (y1 - y0) * (y2 - y0)) /
+      (sqrt ((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)) *
+          sqrt ((x2 - x0) * (x2 - x0) + (y2 - y0) * (y2 - y0))));
+
+  len1 = sqrt ((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
+
+  if (x1 == x2) {
+    sign = SIGN (y2 - y1);
+
+    for (i = y1; i != (y2 + sign); i += sign) {
+      if (y1 == i)
+        angle = 0;
+      else
+        angle = acos (((x1 - x0) * (x2 - x0) + (y1 - y0) * (i - y0)) /
+            (len1 * sqrt ((x1 - x0) * (x1 - x0) + (i - y0) * (i -
+                        y0)))) / angle_e;
+
+      draw_bresenham_line (dest, stride,
+          x0, y0, x1, i, (c2 * angle + c1 * (1.0 - angle)));
+    }
+  } else if (y1 == y2) {
+    sign = SIGN (x2 - x1);
+
+    for (i = x1; i != (x2 + sign); i += sign) {
+      if (x1 == i)
+        angle = 0;
+      else
+        angle = acos (((x1 - x0) * (i - x0) + (y1 - y0) * (y2 - y0)) /
+            (len1 * sqrt ((i - x0) * (i - x0) + (y2 - y0) * (y2 -
+                        y0)))) / angle_e;
+
+      draw_bresenham_line (dest, stride,
+          x0, y0, i, y1, (c2 * angle + c1 * (1.0 - angle)));
+    }
+  } else {
+    g_warning ("paint triangle clock: not supported");
+    return;
+  }
+}
+
+void
+gst_smpte_paint_box_clock (guint32 * dest, gint stride,
+    gint x0, gint y0, gint c0,
+    gint x1, gint y1, gint c1, gint x2, gint y2, gint c2)
+{
+  gfloat angle_m, col_m;
+  gint xv, yv;
+
+  if (x1 == x0) {
+    xv = x2;
+    yv = y1;
+  } else if (y1 == y0) {
+    xv = x1;
+    yv = y2;
+  } else {
+    g_warning ("paint box clock: not supported");
+    return;
+  }
+
+  angle_m = 2 * acos (((x1 - x0) * (xv - x0) + (y1 - y0) * (yv - y0)) /
+      (sqrt ((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)) *
+          sqrt ((xv - x0) * (xv - x0) + (yv - y0) * (yv - y0)))) / M_PI;
+
+  col_m = c2 * angle_m + c1 * (1.0 - angle_m);
+
+  gst_smpte_paint_triangle_clock (dest, stride,
+      x0, y0, c0, x1, y1, c1, xv, yv, col_m);
+  gst_smpte_paint_triangle_clock (dest, stride,
+      x0, y0, c0, xv, yv, col_m, x2, y2, c2);
+}
diff --git a/gst/smpte/paint.h b/gst/smpte/paint.h
new file mode 100644
index 0000000..c815e0b
--- /dev/null
+++ b/gst/smpte/paint.h
@@ -0,0 +1,47 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_SMPTE_PAINT_H__
+#define __GST_SMPTE_PAINT_H__
+
+#include <glib.h>
+
+void    gst_smpte_paint_vbox            (guint32 *dest, gint stride, 
+                                         gint x0, gint y0, gint c0, 
+                                         gint x1, gint y1, gint c1);
+void    gst_smpte_paint_hbox            (guint32 *dest, gint stride, 
+                                         gint x0, gint y0, gint c0, 
+                                         gint x1, gint y1, gint c1);
+
+void    gst_smpte_paint_triangle_linear (guint32 *dest, gint stride,
+                                         gint x0, gint y0, gint c0,
+                                         gint x1, gint y1, gint c1, 
+                                         gint x2, gint y2, gint c2);
+
+void    gst_smpte_paint_triangle_clock  (guint32 *dest, gint stride,
+                                         gint x0, gint y0, gint c0,
+                                         gint x1, gint y1, gint c1, 
+                                         gint x2, gint y2, gint c2);
+
+void    gst_smpte_paint_box_clock       (guint32 *dest, gint stride,
+                                         gint x0, gint y0, gint c0,
+                                         gint x1, gint y1, gint c1,
+                                         gint x2, gint y2, gint c2);
+
+#endif /* __GST_SMPTE_PAINT_H__ */
diff --git a/gst/smpte/plugin.c b/gst/smpte/plugin.c
new file mode 100644
index 0000000..43eba8a
--- /dev/null
+++ b/gst/smpte/plugin.c
@@ -0,0 +1,43 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@google.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstsmpte.h"
+#include "gstsmptealpha.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_smpte_plugin_init (plugin))
+    return FALSE;
+
+  if (!gst_smpte_alpha_plugin_init (plugin))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    smpte,
+    "Apply the standard SMPTE transitions on video images",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/spectrum/.gitignore b/gst/spectrum/.gitignore
new file mode 100644
index 0000000..08f366f
--- /dev/null
+++ b/gst/spectrum/.gitignore
@@ -0,0 +1,9 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
+demo-audiotest
+demo-osssrc
diff --git a/gst/spectrum/Makefile.am b/gst/spectrum/Makefile.am
new file mode 100644
index 0000000..dc0c9e4
--- /dev/null
+++ b/gst/spectrum/Makefile.am
@@ -0,0 +1,11 @@
+plugin_LTLIBRARIES = libgstspectrum.la
+
+libgstspectrum_la_SOURCES = gstspectrum.c
+libgstspectrum_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS)
+libgstspectrum_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+	-lgstfft-$(GST_API_VERSION) -lgstaudio-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) $(GST_LIBS) $(LIBM)
+libgstspectrum_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstspectrum.h
diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c
new file mode 100644
index 0000000..4be8960
--- /dev/null
+++ b/gst/spectrum/gstspectrum.c
@@ -0,0 +1,1007 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *               <2006,2011> Stefan Kost <ensonic@users.sf.net>
+ *               <2007-2009> Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-spectrum
+ *
+ * The Spectrum element analyzes the frequency spectrum of an audio signal.
+ * If the #GstSpectrum:post-messages property is %TRUE, it sends analysis results
+ * as element messages named
+ * <classname>&quot;spectrum&quot;</classname> after each interval of time given
+ * by the #GstSpectrum:interval property.
+ *
+ * The message's structure contains some combination of these fields:
+ * <itemizedlist>
+ * <listitem>
+ *   <para>
+ *   #GstClockTime
+ *   <classname>&quot;timestamp&quot;</classname>:
+ *   the timestamp of the buffer that triggered the message.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GstClockTime
+ *   <classname>&quot;stream-time&quot;</classname>:
+ *   the stream time of the buffer.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GstClockTime
+ *   <classname>&quot;running-time&quot;</classname>:
+ *   the running_time of the buffer.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GstClockTime
+ *   <classname>&quot;duration&quot;</classname>:
+ *   the duration of the buffer.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GstClockTime
+ *   <classname>&quot;endtime&quot;</classname>:
+ *   the end time of the buffer that triggered the message as stream time (this
+ *   is deprecated, as it can be calculated from stream-time + duration)
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GstValueList of #gfloat
+ *   <classname>&quot;magnitude&quot;</classname>:
+ *   the level for each frequency band in dB. All values below the value of the
+ *   #GstSpectrum:threshold property will be set to the threshold. Only present
+ *   if the #GstSpectrum:message-magnitude property is %TRUE.
+ *   </para>
+ * </listitem>
+ * <listitem>
+ *   <para>
+ *   #GstValueList of #gfloat
+ *   <classname>&quot;phase&quot;</classname>:
+ *   The phase for each frequency band. The value is between -pi and pi. Only
+ *   present if the #GstSpectrum:message-phase property is %TRUE.
+ *   </para>
+ * </listitem>
+ * </itemizedlist>
+ *
+ * If #GstSpectrum:multi-channel property is set to true. magnitude and phase
+ * fields will be each a nested #GstValueArray. The first dimension are the
+ * channels and the second dimension are the values.
+ *
+ * <refsect2>
+ * <title>Example application</title>
+ * <informalexample><programlisting language="C">
+ * <xi:include xmlns:xi="http://www.w3.org/2003/XInclude" parse="text" href="../../../../tests/examples/spectrum/spectrum-example.c" />
+ * </programlisting></informalexample>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <math.h>
+#include "gstspectrum.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_spectrum_debug);
+#define GST_CAT_DEFAULT gst_spectrum_debug
+
+/* elementfactory information */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+# define FORMATS "{ S16LE, S24LE, S32LE, F32LE, F64LE }"
+#else
+# define FORMATS "{ S16BE, S24BE, S32BE, F32BE, F64BE }"
+#endif
+
+#define ALLOWED_CAPS \
+  GST_AUDIO_CAPS_MAKE (FORMATS) ", " \
+  "layout = (string) interleaved"
+
+/* Spectrum properties */
+#define DEFAULT_POST_MESSAGES	        TRUE
+#define DEFAULT_MESSAGE_MAGNITUDE	TRUE
+#define DEFAULT_MESSAGE_PHASE		FALSE
+#define DEFAULT_INTERVAL		(GST_SECOND / 10)
+#define DEFAULT_BANDS			128
+#define DEFAULT_THRESHOLD		-60
+#define DEFAULT_MULTI_CHANNEL		FALSE
+
+enum
+{
+  PROP_0,
+  PROP_POST_MESSAGES,
+  PROP_MESSAGE_MAGNITUDE,
+  PROP_MESSAGE_PHASE,
+  PROP_INTERVAL,
+  PROP_BANDS,
+  PROP_THRESHOLD,
+  PROP_MULTI_CHANNEL
+};
+
+#define gst_spectrum_parent_class parent_class
+G_DEFINE_TYPE (GstSpectrum, gst_spectrum, GST_TYPE_AUDIO_FILTER);
+
+static void gst_spectrum_finalize (GObject * object);
+static void gst_spectrum_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_spectrum_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static gboolean gst_spectrum_start (GstBaseTransform * trans);
+static gboolean gst_spectrum_stop (GstBaseTransform * trans);
+static GstFlowReturn gst_spectrum_transform_ip (GstBaseTransform * trans,
+    GstBuffer * in);
+static gboolean gst_spectrum_setup (GstAudioFilter * base,
+    const GstAudioInfo * info);
+
+static void
+gst_spectrum_class_init (GstSpectrumClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GstBaseTransformClass *trans_class = GST_BASE_TRANSFORM_CLASS (klass);
+  GstAudioFilterClass *filter_class = GST_AUDIO_FILTER_CLASS (klass);
+  GstCaps *caps;
+
+  gobject_class->set_property = gst_spectrum_set_property;
+  gobject_class->get_property = gst_spectrum_get_property;
+  gobject_class->finalize = gst_spectrum_finalize;
+
+  trans_class->start = GST_DEBUG_FUNCPTR (gst_spectrum_start);
+  trans_class->stop = GST_DEBUG_FUNCPTR (gst_spectrum_stop);
+  trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_spectrum_transform_ip);
+  trans_class->passthrough_on_same_caps = TRUE;
+
+  filter_class->setup = GST_DEBUG_FUNCPTR (gst_spectrum_setup);
+
+  g_object_class_install_property (gobject_class, PROP_POST_MESSAGES,
+      g_param_spec_boolean ("post-messages", "Post Messages",
+          "Whether to post a 'spectrum' element message on the bus for each "
+          "passed interval", DEFAULT_POST_MESSAGES,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MESSAGE_MAGNITUDE,
+      g_param_spec_boolean ("message-magnitude", "Magnitude",
+          "Whether to add a 'magnitude' field to the structure of any "
+          "'spectrum' element messages posted on the bus",
+          DEFAULT_MESSAGE_MAGNITUDE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MESSAGE_PHASE,
+      g_param_spec_boolean ("message-phase", "Phase",
+          "Whether to add a 'phase' field to the structure of any "
+          "'spectrum' element messages posted on the bus",
+          DEFAULT_MESSAGE_PHASE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_INTERVAL,
+      g_param_spec_uint64 ("interval", "Interval",
+          "Interval of time between message posts (in nanoseconds)",
+          1, G_MAXUINT64, DEFAULT_INTERVAL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_BANDS,
+      g_param_spec_uint ("bands", "Bands", "Number of frequency bands",
+          2, ((guint) G_MAXINT + 2) / 2, DEFAULT_BANDS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_THRESHOLD,
+      g_param_spec_int ("threshold", "Threshold",
+          "dB threshold for result. All lower values will be set to this",
+          G_MININT, 0, DEFAULT_THRESHOLD,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MULTI_CHANNEL,
+      g_param_spec_boolean ("multi-channel", "Multichannel results",
+          "Send separate results for each channel",
+          DEFAULT_MULTI_CHANNEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  GST_DEBUG_CATEGORY_INIT (gst_spectrum_debug, "spectrum", 0,
+      "audio spectrum analyser element");
+
+  gst_element_class_set_static_metadata (element_class, "Spectrum analyzer",
+      "Filter/Analyzer/Audio",
+      "Run an FFT on the audio signal, output spectrum data",
+      "Erik Walthinsen <omega@cse.ogi.edu>, "
+      "Stefan Kost <ensonic@users.sf.net>, "
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  caps = gst_caps_from_string (ALLOWED_CAPS);
+  gst_audio_filter_class_add_pad_templates (filter_class, caps);
+  gst_caps_unref (caps);
+}
+
+static void
+gst_spectrum_init (GstSpectrum * spectrum)
+{
+  spectrum->post_messages = DEFAULT_POST_MESSAGES;
+  spectrum->message_magnitude = DEFAULT_MESSAGE_MAGNITUDE;
+  spectrum->message_phase = DEFAULT_MESSAGE_PHASE;
+  spectrum->interval = DEFAULT_INTERVAL;
+  spectrum->bands = DEFAULT_BANDS;
+  spectrum->threshold = DEFAULT_THRESHOLD;
+
+  g_mutex_init (&spectrum->lock);
+}
+
+static void
+gst_spectrum_alloc_channel_data (GstSpectrum * spectrum)
+{
+  gint i;
+  GstSpectrumChannel *cd;
+  guint bands = spectrum->bands;
+  guint nfft = 2 * bands - 2;
+
+  g_assert (spectrum->channel_data == NULL);
+
+  spectrum->num_channels = (spectrum->multi_channel) ?
+      GST_AUDIO_FILTER_CHANNELS (spectrum) : 1;
+
+  GST_DEBUG_OBJECT (spectrum, "allocating data for %d channels",
+      spectrum->num_channels);
+
+  spectrum->channel_data = g_new (GstSpectrumChannel, spectrum->num_channels);
+  for (i = 0; i < spectrum->num_channels; i++) {
+    cd = &spectrum->channel_data[i];
+    cd->fft_ctx = gst_fft_f32_new (nfft, FALSE);
+    cd->input = g_new0 (gfloat, nfft);
+    cd->input_tmp = g_new0 (gfloat, nfft);
+    cd->freqdata = g_new0 (GstFFTF32Complex, bands);
+    cd->spect_magnitude = g_new0 (gfloat, bands);
+    cd->spect_phase = g_new0 (gfloat, bands);
+  }
+}
+
+static void
+gst_spectrum_free_channel_data (GstSpectrum * spectrum)
+{
+  if (spectrum->channel_data) {
+    gint i;
+    GstSpectrumChannel *cd;
+
+    GST_DEBUG_OBJECT (spectrum, "freeing data for %d channels",
+        spectrum->num_channels);
+
+    for (i = 0; i < spectrum->num_channels; i++) {
+      cd = &spectrum->channel_data[i];
+      if (cd->fft_ctx)
+        gst_fft_f32_free (cd->fft_ctx);
+      g_free (cd->input);
+      g_free (cd->input_tmp);
+      g_free (cd->freqdata);
+      g_free (cd->spect_magnitude);
+      g_free (cd->spect_phase);
+    }
+    g_free (spectrum->channel_data);
+    spectrum->channel_data = NULL;
+  }
+}
+
+static void
+gst_spectrum_flush (GstSpectrum * spectrum)
+{
+  spectrum->num_frames = 0;
+  spectrum->num_fft = 0;
+
+  spectrum->accumulated_error = 0;
+}
+
+static void
+gst_spectrum_reset_state (GstSpectrum * spectrum)
+{
+  GST_DEBUG_OBJECT (spectrum, "resetting state");
+
+  gst_spectrum_free_channel_data (spectrum);
+  gst_spectrum_flush (spectrum);
+}
+
+static void
+gst_spectrum_finalize (GObject * object)
+{
+  GstSpectrum *spectrum = GST_SPECTRUM (object);
+
+  gst_spectrum_reset_state (spectrum);
+  g_mutex_clear (&spectrum->lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_spectrum_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstSpectrum *filter = GST_SPECTRUM (object);
+
+  switch (prop_id) {
+    case PROP_POST_MESSAGES:
+      filter->post_messages = g_value_get_boolean (value);
+      break;
+    case PROP_MESSAGE_MAGNITUDE:
+      filter->message_magnitude = g_value_get_boolean (value);
+      break;
+    case PROP_MESSAGE_PHASE:
+      filter->message_phase = g_value_get_boolean (value);
+      break;
+    case PROP_INTERVAL:{
+      guint64 interval = g_value_get_uint64 (value);
+      g_mutex_lock (&filter->lock);
+      if (filter->interval != interval) {
+        filter->interval = interval;
+        gst_spectrum_reset_state (filter);
+      }
+      g_mutex_unlock (&filter->lock);
+      break;
+    }
+    case PROP_BANDS:{
+      guint bands = g_value_get_uint (value);
+      g_mutex_lock (&filter->lock);
+      if (filter->bands != bands) {
+        filter->bands = bands;
+        gst_spectrum_reset_state (filter);
+      }
+      g_mutex_unlock (&filter->lock);
+      break;
+    }
+    case PROP_THRESHOLD:
+      filter->threshold = g_value_get_int (value);
+      break;
+    case PROP_MULTI_CHANNEL:{
+      gboolean multi_channel = g_value_get_boolean (value);
+      g_mutex_lock (&filter->lock);
+      if (filter->multi_channel != multi_channel) {
+        filter->multi_channel = multi_channel;
+        gst_spectrum_reset_state (filter);
+      }
+      g_mutex_unlock (&filter->lock);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_spectrum_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstSpectrum *filter = GST_SPECTRUM (object);
+
+  switch (prop_id) {
+    case PROP_POST_MESSAGES:
+      g_value_set_boolean (value, filter->post_messages);
+      break;
+    case PROP_MESSAGE_MAGNITUDE:
+      g_value_set_boolean (value, filter->message_magnitude);
+      break;
+    case PROP_MESSAGE_PHASE:
+      g_value_set_boolean (value, filter->message_phase);
+      break;
+    case PROP_INTERVAL:
+      g_value_set_uint64 (value, filter->interval);
+      break;
+    case PROP_BANDS:
+      g_value_set_uint (value, filter->bands);
+      break;
+    case PROP_THRESHOLD:
+      g_value_set_int (value, filter->threshold);
+      break;
+    case PROP_MULTI_CHANNEL:
+      g_value_set_boolean (value, filter->multi_channel);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_spectrum_start (GstBaseTransform * trans)
+{
+  GstSpectrum *spectrum = GST_SPECTRUM (trans);
+
+  gst_spectrum_reset_state (spectrum);
+
+  return TRUE;
+}
+
+static gboolean
+gst_spectrum_stop (GstBaseTransform * trans)
+{
+  GstSpectrum *spectrum = GST_SPECTRUM (trans);
+
+  gst_spectrum_reset_state (spectrum);
+
+  return TRUE;
+}
+
+/* mixing data readers */
+
+static void
+input_data_mixed_float (const guint8 * _in, gfloat * out, guint len,
+    guint channels, gfloat max_value, guint op, guint nfft)
+{
+  guint i, j, ip = 0;
+  gfloat v;
+  gfloat *in = (gfloat *) _in;
+
+  for (j = 0; j < len; j++) {
+    v = in[ip++];
+    for (i = 1; i < channels; i++)
+      v += in[ip++];
+    out[op] = v / channels;
+    op = (op + 1) % nfft;
+  }
+}
+
+static void
+input_data_mixed_double (const guint8 * _in, gfloat * out, guint len,
+    guint channels, gfloat max_value, guint op, guint nfft)
+{
+  guint i, j, ip = 0;
+  gfloat v;
+  gdouble *in = (gdouble *) _in;
+
+  for (j = 0; j < len; j++) {
+    v = in[ip++];
+    for (i = 1; i < channels; i++)
+      v += in[ip++];
+    out[op] = v / channels;
+    op = (op + 1) % nfft;
+  }
+}
+
+static void
+input_data_mixed_int32_max (const guint8 * _in, gfloat * out, guint len,
+    guint channels, gfloat max_value, guint op, guint nfft)
+{
+  guint i, j, ip = 0;
+  gint32 *in = (gint32 *) _in;
+  gfloat v;
+
+  for (j = 0; j < len; j++) {
+    v = in[ip++] / max_value;
+    for (i = 1; i < channels; i++)
+      v += in[ip++] / max_value;
+    out[op] = v / channels;
+    op = (op + 1) % nfft;
+  }
+}
+
+static void
+input_data_mixed_int24_max (const guint8 * _in, gfloat * out, guint len,
+    guint channels, gfloat max_value, guint op, guint nfft)
+{
+  guint i, j;
+  gfloat v = 0.0;
+
+  for (j = 0; j < len; j++) {
+    for (i = 0; i < channels; i++) {
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+      gint32 value = GST_READ_UINT24_BE (_in);
+#else
+      gint32 value = GST_READ_UINT24_LE (_in);
+#endif
+      if (value & 0x00800000)
+        value |= 0xff000000;
+      v += value / max_value;
+      _in += 3;
+    }
+    out[op] = v / channels;
+    op = (op + 1) % nfft;
+  }
+}
+
+static void
+input_data_mixed_int16_max (const guint8 * _in, gfloat * out, guint len,
+    guint channels, gfloat max_value, guint op, guint nfft)
+{
+  guint i, j, ip = 0;
+  gint16 *in = (gint16 *) _in;
+  gfloat v;
+
+  for (j = 0; j < len; j++) {
+    v = in[ip++] / max_value;
+    for (i = 1; i < channels; i++)
+      v += in[ip++] / max_value;
+    out[op] = v / channels;
+    op = (op + 1) % nfft;
+  }
+}
+
+/* non mixing data readers */
+
+static void
+input_data_float (const guint8 * _in, gfloat * out, guint len, guint channels,
+    gfloat max_value, guint op, guint nfft)
+{
+  guint j, ip;
+  gfloat *in = (gfloat *) _in;
+
+  for (j = 0, ip = 0; j < len; j++, ip += channels) {
+    out[op] = in[ip];
+    op = (op + 1) % nfft;
+  }
+}
+
+static void
+input_data_double (const guint8 * _in, gfloat * out, guint len, guint channels,
+    gfloat max_value, guint op, guint nfft)
+{
+  guint j, ip;
+  gdouble *in = (gdouble *) _in;
+
+  for (j = 0, ip = 0; j < len; j++, ip += channels) {
+    out[op] = in[ip];
+    op = (op + 1) % nfft;
+  }
+}
+
+static void
+input_data_int32_max (const guint8 * _in, gfloat * out, guint len,
+    guint channels, gfloat max_value, guint op, guint nfft)
+{
+  guint j, ip;
+  gint32 *in = (gint32 *) _in;
+
+  for (j = 0, ip = 0; j < len; j++, ip += channels) {
+    out[op] = in[ip] / max_value;
+    op = (op + 1) % nfft;
+  }
+}
+
+static void
+input_data_int24_max (const guint8 * _in, gfloat * out, guint len,
+    guint channels, gfloat max_value, guint op, guint nfft)
+{
+  guint j;
+
+  for (j = 0; j < len; j++) {
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+    gint32 v = GST_READ_UINT24_BE (_in);
+#else
+    gint32 v = GST_READ_UINT24_LE (_in);
+#endif
+    if (v & 0x00800000)
+      v |= 0xff000000;
+    _in += 3 * channels;
+    out[op] = v / max_value;
+    op = (op + 1) % nfft;
+  }
+}
+
+static void
+input_data_int16_max (const guint8 * _in, gfloat * out, guint len,
+    guint channels, gfloat max_value, guint op, guint nfft)
+{
+  guint j, ip;
+  gint16 *in = (gint16 *) _in;
+
+  for (j = 0, ip = 0; j < len; j++, ip += channels) {
+    out[op] = in[ip] / max_value;
+    op = (op + 1) % nfft;
+  }
+}
+
+static gboolean
+gst_spectrum_setup (GstAudioFilter * base, const GstAudioInfo * info)
+{
+  GstSpectrum *spectrum = GST_SPECTRUM (base);
+  gboolean multi_channel = spectrum->multi_channel;
+  GstSpectrumInputData input_data = NULL;
+
+  g_mutex_lock (&spectrum->lock);
+  switch (GST_AUDIO_INFO_FORMAT (info)) {
+    case GST_AUDIO_FORMAT_S16:
+      input_data =
+          multi_channel ? input_data_int16_max : input_data_mixed_int16_max;
+      break;
+    case GST_AUDIO_FORMAT_S24:
+      input_data =
+          multi_channel ? input_data_int24_max : input_data_mixed_int24_max;
+      break;
+    case GST_AUDIO_FORMAT_S32:
+      input_data =
+          multi_channel ? input_data_int32_max : input_data_mixed_int32_max;
+      break;
+    case GST_AUDIO_FORMAT_F32:
+      input_data = multi_channel ? input_data_float : input_data_mixed_float;
+      break;
+    case GST_AUDIO_FORMAT_F64:
+      input_data = multi_channel ? input_data_double : input_data_mixed_double;
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+  spectrum->input_data = input_data;
+
+  gst_spectrum_reset_state (spectrum);
+  g_mutex_unlock (&spectrum->lock);
+
+  return TRUE;
+}
+
+static GValue *
+gst_spectrum_message_add_container (GstStructure * s, GType type,
+    const gchar * name)
+{
+  GValue v = { 0, };
+
+  g_value_init (&v, type);
+  /* will copy-by-value */
+  gst_structure_set_value (s, name, &v);
+  g_value_unset (&v);
+  return (GValue *) gst_structure_get_value (s, name);
+}
+
+static void
+gst_spectrum_message_add_list (GValue * cv, gfloat * data, guint num_values)
+{
+  GValue v = { 0, };
+  guint i;
+
+  g_value_init (&v, G_TYPE_FLOAT);
+  for (i = 0; i < num_values; i++) {
+    g_value_set_float (&v, data[i]);
+    gst_value_list_append_value (cv, &v);       /* copies by value */
+  }
+  g_value_unset (&v);
+}
+
+static void
+gst_spectrum_message_add_array (GValue * cv, gfloat * data, guint num_values)
+{
+  GValue v = { 0, };
+  GValue a = { 0, };
+  guint i;
+
+  g_value_init (&a, GST_TYPE_ARRAY);
+
+  g_value_init (&v, G_TYPE_FLOAT);
+  for (i = 0; i < num_values; i++) {
+    g_value_set_float (&v, data[i]);
+    gst_value_array_append_value (&a, &v);      /* copies by value */
+  }
+  g_value_unset (&v);
+
+  gst_value_array_append_value (cv, &a);        /* copies by value */
+  g_value_unset (&a);
+}
+
+static GstMessage *
+gst_spectrum_message_new (GstSpectrum * spectrum, GstClockTime timestamp,
+    GstClockTime duration)
+{
+  GstBaseTransform *trans = GST_BASE_TRANSFORM_CAST (spectrum);
+  GstSpectrumChannel *cd;
+  GstStructure *s;
+  GValue *mcv = NULL, *pcv = NULL;
+  GstClockTime endtime, running_time, stream_time;
+
+  GST_DEBUG_OBJECT (spectrum, "preparing message, bands =%d ", spectrum->bands);
+
+  running_time = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
+      timestamp);
+  stream_time = gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
+      timestamp);
+  /* endtime is for backwards compatibility */
+  endtime = stream_time + duration;
+
+  s = gst_structure_new ("spectrum",
+      "endtime", GST_TYPE_CLOCK_TIME, endtime,
+      "timestamp", G_TYPE_UINT64, timestamp,
+      "stream-time", G_TYPE_UINT64, stream_time,
+      "running-time", G_TYPE_UINT64, running_time,
+      "duration", G_TYPE_UINT64, duration, NULL);
+
+  if (!spectrum->multi_channel) {
+    cd = &spectrum->channel_data[0];
+
+    if (spectrum->message_magnitude) {
+      /* FIXME 0.11: this should be an array, not a list */
+      mcv = gst_spectrum_message_add_container (s, GST_TYPE_LIST, "magnitude");
+      gst_spectrum_message_add_list (mcv, cd->spect_magnitude, spectrum->bands);
+    }
+    if (spectrum->message_phase) {
+      /* FIXME 0.11: this should be an array, not a list */
+      pcv = gst_spectrum_message_add_container (s, GST_TYPE_LIST, "phase");
+      gst_spectrum_message_add_list (pcv, cd->spect_phase, spectrum->bands);
+    }
+  } else {
+    guint c;
+    guint channels = GST_AUDIO_FILTER_CHANNELS (spectrum);
+
+    if (spectrum->message_magnitude) {
+      mcv = gst_spectrum_message_add_container (s, GST_TYPE_ARRAY, "magnitude");
+    }
+    if (spectrum->message_phase) {
+      pcv = gst_spectrum_message_add_container (s, GST_TYPE_ARRAY, "phase");
+    }
+
+    for (c = 0; c < channels; c++) {
+      cd = &spectrum->channel_data[c];
+
+      if (spectrum->message_magnitude) {
+        gst_spectrum_message_add_array (mcv, cd->spect_magnitude,
+            spectrum->bands);
+      }
+      if (spectrum->message_phase) {
+        gst_spectrum_message_add_array (pcv, cd->spect_phase, spectrum->bands);
+      }
+    }
+  }
+  return gst_message_new_element (GST_OBJECT (spectrum), s);
+}
+
+static void
+gst_spectrum_run_fft (GstSpectrum * spectrum, GstSpectrumChannel * cd,
+    guint input_pos)
+{
+  guint i;
+  guint bands = spectrum->bands;
+  guint nfft = 2 * bands - 2;
+  gint threshold = spectrum->threshold;
+  gfloat *input = cd->input;
+  gfloat *input_tmp = cd->input_tmp;
+  gfloat *spect_magnitude = cd->spect_magnitude;
+  gfloat *spect_phase = cd->spect_phase;
+  GstFFTF32Complex *freqdata = cd->freqdata;
+  GstFFTF32 *fft_ctx = cd->fft_ctx;
+
+  for (i = 0; i < nfft; i++)
+    input_tmp[i] = input[(input_pos + i) % nfft];
+
+  gst_fft_f32_window (fft_ctx, input_tmp, GST_FFT_WINDOW_HAMMING);
+
+  gst_fft_f32_fft (fft_ctx, input_tmp, freqdata);
+
+  if (spectrum->message_magnitude) {
+    gdouble val;
+    /* Calculate magnitude in db */
+    for (i = 0; i < bands; i++) {
+      val = freqdata[i].r * freqdata[i].r;
+      val += freqdata[i].i * freqdata[i].i;
+      val /= nfft * nfft;
+      val = 10.0 * log10 (val);
+      if (val < threshold)
+        val = threshold;
+      spect_magnitude[i] += val;
+    }
+  }
+
+  if (spectrum->message_phase) {
+    /* Calculate phase */
+    for (i = 0; i < bands; i++)
+      spect_phase[i] += atan2 (freqdata[i].i, freqdata[i].r);
+  }
+}
+
+static void
+gst_spectrum_prepare_message_data (GstSpectrum * spectrum,
+    GstSpectrumChannel * cd)
+{
+  guint i;
+  guint bands = spectrum->bands;
+  guint num_fft = spectrum->num_fft;
+
+  /* Calculate average */
+  if (spectrum->message_magnitude) {
+    gfloat *spect_magnitude = cd->spect_magnitude;
+    for (i = 0; i < bands; i++)
+      spect_magnitude[i] /= num_fft;
+  }
+  if (spectrum->message_phase) {
+    gfloat *spect_phase = cd->spect_phase;
+    for (i = 0; i < bands; i++)
+      spect_phase[i] /= num_fft;
+  }
+}
+
+static void
+gst_spectrum_reset_message_data (GstSpectrum * spectrum,
+    GstSpectrumChannel * cd)
+{
+  guint bands = spectrum->bands;
+  gfloat *spect_magnitude = cd->spect_magnitude;
+  gfloat *spect_phase = cd->spect_phase;
+
+  /* reset spectrum accumulators */
+  memset (spect_magnitude, 0, bands * sizeof (gfloat));
+  memset (spect_phase, 0, bands * sizeof (gfloat));
+}
+
+static GstFlowReturn
+gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
+{
+  GstSpectrum *spectrum = GST_SPECTRUM (trans);
+  guint rate = GST_AUDIO_FILTER_RATE (spectrum);
+  guint channels = GST_AUDIO_FILTER_CHANNELS (spectrum);
+  guint bps = GST_AUDIO_FILTER_BPS (spectrum);
+  guint bpf = GST_AUDIO_FILTER_BPF (spectrum);
+  guint output_channels = spectrum->multi_channel ? channels : 1;
+  guint c;
+  gfloat max_value = (1UL << ((bps << 3) - 1)) - 1;
+  guint bands = spectrum->bands;
+  guint nfft = 2 * bands - 2;
+  guint input_pos;
+  gfloat *input;
+  GstMapInfo map;
+  const guint8 *data;
+  gsize size;
+  guint fft_todo, msg_todo, block_size;
+  gboolean have_full_interval;
+  GstSpectrumChannel *cd;
+  GstSpectrumInputData input_data;
+
+  g_mutex_lock (&spectrum->lock);
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  data = map.data;
+  size = map.size;
+
+  GST_LOG_OBJECT (spectrum, "input size: %" G_GSIZE_FORMAT " bytes", size);
+
+  if (GST_BUFFER_IS_DISCONT (buffer)) {
+    GST_DEBUG_OBJECT (spectrum, "Discontinuity detected -- flushing");
+    gst_spectrum_flush (spectrum);
+  }
+
+  /* If we don't have a FFT context yet (or it was reset due to parameter
+   * changes) get one and allocate memory for everything
+   */
+  if (spectrum->channel_data == NULL) {
+    GST_DEBUG_OBJECT (spectrum, "allocating for bands %u", bands);
+
+    gst_spectrum_alloc_channel_data (spectrum);
+
+    /* number of sample frames we process before posting a message
+     * interval is in ns */
+    spectrum->frames_per_interval =
+        gst_util_uint64_scale (spectrum->interval, rate, GST_SECOND);
+    spectrum->frames_todo = spectrum->frames_per_interval;
+    /* rounding error for frames_per_interval in ns,
+     * aggregated it in accumulated_error */
+    spectrum->error_per_interval = (spectrum->interval * rate) % GST_SECOND;
+    if (spectrum->frames_per_interval == 0)
+      spectrum->frames_per_interval = 1;
+
+    GST_INFO_OBJECT (spectrum, "interval %" GST_TIME_FORMAT ", fpi %"
+        G_GUINT64_FORMAT ", error %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (spectrum->interval), spectrum->frames_per_interval,
+        GST_TIME_ARGS (spectrum->error_per_interval));
+
+    spectrum->input_pos = 0;
+
+    gst_spectrum_flush (spectrum);
+  }
+
+  if (spectrum->num_frames == 0)
+    spectrum->message_ts = GST_BUFFER_TIMESTAMP (buffer);
+
+  input_pos = spectrum->input_pos;
+  input_data = spectrum->input_data;
+
+  while (size >= bpf) {
+    /* run input_data for a chunk of data */
+    fft_todo = nfft - (spectrum->num_frames % nfft);
+    msg_todo = spectrum->frames_todo - spectrum->num_frames;
+    GST_LOG_OBJECT (spectrum,
+        "message frames todo: %u, fft frames todo: %u, input frames %"
+        G_GSIZE_FORMAT, msg_todo, fft_todo, (size / bpf));
+    block_size = msg_todo;
+    if (block_size > (size / bpf))
+      block_size = (size / bpf);
+    if (block_size > fft_todo)
+      block_size = fft_todo;
+
+    for (c = 0; c < output_channels; c++) {
+      cd = &spectrum->channel_data[c];
+      input = cd->input;
+      /* Move the current frames into our ringbuffers */
+      input_data (data + c * bps, input, block_size, channels, max_value,
+          input_pos, nfft);
+    }
+    data += block_size * bpf;
+    size -= block_size * bpf;
+    input_pos = (input_pos + block_size) % nfft;
+    spectrum->num_frames += block_size;
+
+    have_full_interval = (spectrum->num_frames == spectrum->frames_todo);
+
+    GST_LOG_OBJECT (spectrum,
+        "size: %" G_GSIZE_FORMAT ", do-fft = %d, do-message = %d", size,
+        (spectrum->num_frames % nfft == 0), have_full_interval);
+
+    /* If we have enough frames for an FFT or we have all frames required for
+     * the interval and we haven't run a FFT, then run an FFT */
+    if ((spectrum->num_frames % nfft == 0) ||
+        (have_full_interval && !spectrum->num_fft)) {
+      for (c = 0; c < output_channels; c++) {
+        cd = &spectrum->channel_data[c];
+        gst_spectrum_run_fft (spectrum, cd, input_pos);
+      }
+      spectrum->num_fft++;
+    }
+
+    /* Do we have the FFTs for one interval? */
+    if (have_full_interval) {
+      GST_DEBUG_OBJECT (spectrum, "nfft: %u frames: %" G_GUINT64_FORMAT
+          " fpi: %" G_GUINT64_FORMAT " error: %" GST_TIME_FORMAT, nfft,
+          spectrum->num_frames, spectrum->frames_per_interval,
+          GST_TIME_ARGS (spectrum->accumulated_error));
+
+      spectrum->frames_todo = spectrum->frames_per_interval;
+      if (spectrum->accumulated_error >= GST_SECOND) {
+        spectrum->accumulated_error -= GST_SECOND;
+        spectrum->frames_todo++;
+      }
+      spectrum->accumulated_error += spectrum->error_per_interval;
+
+      if (spectrum->post_messages) {
+        GstMessage *m;
+
+        for (c = 0; c < output_channels; c++) {
+          cd = &spectrum->channel_data[c];
+          gst_spectrum_prepare_message_data (spectrum, cd);
+        }
+
+        m = gst_spectrum_message_new (spectrum, spectrum->message_ts,
+            spectrum->interval);
+
+        gst_element_post_message (GST_ELEMENT (spectrum), m);
+      }
+
+      if (GST_CLOCK_TIME_IS_VALID (spectrum->message_ts))
+        spectrum->message_ts +=
+            gst_util_uint64_scale (spectrum->num_frames, GST_SECOND, rate);
+
+      for (c = 0; c < output_channels; c++) {
+        cd = &spectrum->channel_data[c];
+        gst_spectrum_reset_message_data (spectrum, cd);
+      }
+      spectrum->num_frames = 0;
+      spectrum->num_fft = 0;
+    }
+  }
+
+  spectrum->input_pos = input_pos;
+
+  gst_buffer_unmap (buffer, &map);
+  g_mutex_unlock (&spectrum->lock);
+
+  g_assert (size == 0);
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "spectrum", GST_RANK_NONE,
+      GST_TYPE_SPECTRUM);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    spectrum,
+    "Run an FFT on the audio signal, output spectrum data",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/spectrum/gstspectrum.h b/gst/spectrum/gstspectrum.h
new file mode 100644
index 0000000..c6e7e8a
--- /dev/null
+++ b/gst/spectrum/gstspectrum.h
@@ -0,0 +1,95 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_SPECTRUM_H__
+#define __GST_SPECTRUM_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiofilter.h>
+#include <gst/fft/gstfftf32.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SPECTRUM            (gst_spectrum_get_type())
+#define GST_SPECTRUM(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPECTRUM,GstSpectrum))
+#define GST_IS_SPECTRUM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPECTRUM))
+#define GST_SPECTRUM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_SPECTRUM,GstSpectrumClass))
+#define GST_IS_SPECTRUM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_SPECTRUM))
+typedef struct _GstSpectrum GstSpectrum;
+typedef struct _GstSpectrumClass GstSpectrumClass;
+typedef struct _GstSpectrumChannel GstSpectrumChannel;
+
+typedef void (*GstSpectrumInputData)(const guint8 * in, gfloat * out,
+    guint len, guint channels, gfloat max_value, guint op, guint nfft);
+
+struct _GstSpectrumChannel
+{
+  gfloat *input;
+  gfloat *input_tmp;
+  GstFFTF32Complex *freqdata;
+  gfloat *spect_magnitude;      /* accumulated mangitude and phase */
+  gfloat *spect_phase;          /* will be scaled by num_fft before sending */
+  GstFFTF32 *fft_ctx;
+};
+
+struct _GstSpectrum
+{
+  GstAudioFilter parent;
+
+  /* properties */
+  gboolean post_messages;       /* whether or not to post messages */
+  gboolean message_magnitude;
+  gboolean message_phase;
+  guint64 interval;             /* how many nanoseconds between emits */
+  guint64 frames_per_interval;  /* how many frames per interval */
+  guint64 frames_todo;
+  guint bands;                  /* number of spectrum bands */
+  gint threshold;               /* energy level treshold */
+  gboolean multi_channel;       /* send separate channel results */
+
+  guint64 num_frames;           /* frame count (1 sample per channel)
+                                 * since last emit */
+  guint64 num_fft;              /* number of FFTs since last emit */
+  GstClockTime message_ts;      /* starttime for next message */
+
+  /* <private> */
+  GstSpectrumChannel *channel_data;
+  guint num_channels;
+
+  guint input_pos;
+  guint64 error_per_interval;
+  guint64 accumulated_error;
+
+  GMutex lock;
+
+  GstSpectrumInputData input_data;
+};
+
+struct _GstSpectrumClass
+{
+  GstAudioFilterClass parent_class;
+};
+
+GType gst_spectrum_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_SPECTRUM_H__ */
diff --git a/gst/spectrum/meson.build b/gst/spectrum/meson.build
new file mode 100644
index 0000000..4dd5e97
--- /dev/null
+++ b/gst/spectrum/meson.build
@@ -0,0 +1,8 @@
+gstspectrum = library('gstspectrum',
+  'gstspectrum.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstbase_dep, gstfft_dep, gstaudio_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/udp/Makefile.am b/gst/udp/Makefile.am
new file mode 100644
index 0000000..697405a
--- /dev/null
+++ b/gst/udp/Makefile.am
@@ -0,0 +1,13 @@
+plugin_LTLIBRARIES = libgstudp.la
+
+libgstudp_la_SOURCES = gstudp.c gstudpsrc.c gstudpsink.c gstmultiudpsink.c gstdynudpsink.c gstudpnetutils.c
+
+libgstudp_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_NET_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS)
+libgstudp_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_NET_LIBS) $(GIO_LIBS)
+libgstudp_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstudpsink.h gstudpsrc.h gstmultiudpsink.h gstdynudpsink.h gstudpnetutils.h
+
+EXTRA_DIST = README
+
+CLEANFILES = $(BUILT_SOURCES)
diff --git a/gst/udp/README b/gst/udp/README
new file mode 100644
index 0000000..9b7cebb
--- /dev/null
+++ b/gst/udp/README
@@ -0,0 +1,7 @@
+* What is UDP src/sink?
+
+It is a set of element to transfer data using UDP, nothing more, nothing less.
+Its main purpose is to be used in conjunction with RTP but they are kept as
+separate elements because we can.
+
+
diff --git a/gst/udp/gstdynudpsink.c b/gst/udp/gstdynudpsink.c
new file mode 100644
index 0000000..78e6d75
--- /dev/null
+++ b/gst/udp/gstdynudpsink.c
@@ -0,0 +1,599 @@
+/* GStreamer
+ * Copyright (C) <2005> Philippe Khalaf <burger@speedy.org>
+ * Copyright (C) <2005> Nokia Corporation <kai.vehmanen@nokia.com>
+ * Copyright (C) <2006> Joni Valtanen <joni.valtanen@movial.fi>
+ * Copyright (C) <2012> Collabora Ltd.
+ *   Author: Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "gstdynudpsink.h"
+
+#include <gst/net/gstnetaddressmeta.h>
+
+GST_DEBUG_CATEGORY_STATIC (dynudpsink_debug);
+#define GST_CAT_DEFAULT (dynudpsink_debug)
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+/* DynUDPSink signals and args */
+enum
+{
+  /* methods */
+  SIGNAL_GET_STATS,
+
+  /* signals */
+
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+#define UDP_DEFAULT_SOCKET		NULL
+#define UDP_DEFAULT_CLOSE_SOCKET	TRUE
+#define UDP_DEFAULT_BIND_ADDRESS	NULL
+#define UDP_DEFAULT_BIND_PORT   	0
+
+enum
+{
+  PROP_0,
+  PROP_SOCKET,
+  PROP_SOCKET_V6,
+  PROP_CLOSE_SOCKET,
+  PROP_BIND_ADDRESS,
+  PROP_BIND_PORT
+};
+
+static void gst_dynudpsink_finalize (GObject * object);
+
+static GstFlowReturn gst_dynudpsink_render (GstBaseSink * sink,
+    GstBuffer * buffer);
+static gboolean gst_dynudpsink_stop (GstBaseSink * bsink);
+static gboolean gst_dynudpsink_start (GstBaseSink * bsink);
+static gboolean gst_dynudpsink_unlock (GstBaseSink * bsink);
+static gboolean gst_dynudpsink_unlock_stop (GstBaseSink * bsink);
+
+static void gst_dynudpsink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_dynudpsink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static GstStructure *gst_dynudpsink_get_stats (GstDynUDPSink * sink,
+    const gchar * host, gint port);
+
+static guint gst_dynudpsink_signals[LAST_SIGNAL] = { 0 };
+
+#define gst_dynudpsink_parent_class parent_class
+G_DEFINE_TYPE (GstDynUDPSink, gst_dynudpsink, GST_TYPE_BASE_SINK);
+
+static void
+gst_dynudpsink_class_init (GstDynUDPSinkClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSinkClass *gstbasesink_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesink_class = (GstBaseSinkClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->set_property = gst_dynudpsink_set_property;
+  gobject_class->get_property = gst_dynudpsink_get_property;
+  gobject_class->finalize = gst_dynudpsink_finalize;
+
+  gst_dynudpsink_signals[SIGNAL_GET_STATS] =
+      g_signal_new ("get-stats", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_STRUCT_OFFSET (GstDynUDPSinkClass, get_stats),
+      NULL, NULL, g_cclosure_marshal_generic, GST_TYPE_STRUCTURE, 2,
+      G_TYPE_STRING, G_TYPE_INT);
+
+  g_object_class_install_property (gobject_class, PROP_SOCKET,
+      g_param_spec_object ("socket", "Socket",
+          "Socket to use for UDP sending. (NULL == allocate)",
+          G_TYPE_SOCKET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_SOCKET_V6,
+      g_param_spec_object ("socket-v6", "Socket IPv6",
+          "Socket to use for UDPv6 sending. (NULL == allocate)",
+          G_TYPE_SOCKET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_CLOSE_SOCKET,
+      g_param_spec_boolean ("close-socket", "Close socket",
+          "Close socket if passed as property on state change",
+          UDP_DEFAULT_CLOSE_SOCKET,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_BIND_ADDRESS,
+      g_param_spec_string ("bind-address", "Bind Address",
+          "Address to bind the socket to", UDP_DEFAULT_BIND_ADDRESS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_BIND_PORT,
+      g_param_spec_int ("bind-port", "Bind Port",
+          "Port to bind the socket to", 0, G_MAXUINT16,
+          UDP_DEFAULT_BIND_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "UDP packet sender",
+      "Sink/Network",
+      "Send data over the network via UDP with packet destinations picked up "
+      "dynamically from meta on the buffers passed",
+      "Philippe Khalaf <burger@speedy.org>");
+
+  gstbasesink_class->render = gst_dynudpsink_render;
+  gstbasesink_class->start = gst_dynudpsink_start;
+  gstbasesink_class->stop = gst_dynudpsink_stop;
+  gstbasesink_class->unlock = gst_dynudpsink_unlock;
+  gstbasesink_class->unlock_stop = gst_dynudpsink_unlock_stop;
+
+  klass->get_stats = gst_dynudpsink_get_stats;
+
+  GST_DEBUG_CATEGORY_INIT (dynudpsink_debug, "dynudpsink", 0, "UDP sink");
+}
+
+static void
+gst_dynudpsink_init (GstDynUDPSink * sink)
+{
+  sink->socket = UDP_DEFAULT_SOCKET;
+  sink->socket_v6 = UDP_DEFAULT_SOCKET;
+  sink->close_socket = UDP_DEFAULT_CLOSE_SOCKET;
+  sink->external_socket = FALSE;
+  sink->bind_address = UDP_DEFAULT_BIND_ADDRESS;
+  sink->bind_port = UDP_DEFAULT_BIND_PORT;
+
+  sink->used_socket = NULL;
+  sink->used_socket_v6 = NULL;
+}
+
+static void
+gst_dynudpsink_finalize (GObject * object)
+{
+  GstDynUDPSink *sink;
+
+  sink = GST_DYNUDPSINK (object);
+
+  if (sink->socket)
+    g_object_unref (sink->socket);
+  sink->socket = NULL;
+
+  if (sink->socket_v6)
+    g_object_unref (sink->socket_v6);
+  sink->socket_v6 = NULL;
+
+  if (sink->used_socket)
+    g_object_unref (sink->used_socket);
+  sink->used_socket = NULL;
+
+  if (sink->used_socket_v6)
+    g_object_unref (sink->used_socket_v6);
+  sink->used_socket_v6 = NULL;
+
+  g_free (sink->bind_address);
+  sink->bind_address = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstFlowReturn
+gst_dynudpsink_render (GstBaseSink * bsink, GstBuffer * buffer)
+{
+  GstDynUDPSink *sink;
+  gssize ret;
+  GstMapInfo map;
+  GstNetAddressMeta *meta;
+  GSocketAddress *addr;
+  GError *err = NULL;
+  GSocketFamily family;
+  GSocket *socket;
+
+  meta = gst_buffer_get_net_address_meta (buffer);
+
+  if (meta == NULL) {
+    GST_DEBUG ("Received buffer without GstNetAddressMeta, skipping");
+    return GST_FLOW_OK;
+  }
+
+  sink = GST_DYNUDPSINK (bsink);
+
+  /* let's get the address from the metadata */
+  addr = meta->addr;
+
+  family = g_socket_address_get_family (addr);
+  if (family == G_SOCKET_FAMILY_IPV6 && !sink->used_socket_v6)
+    goto invalid_family;
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+  GST_DEBUG ("about to send %" G_GSIZE_FORMAT " bytes", map.size);
+
+#ifndef GST_DISABLE_GST_DEBUG
+  {
+    gchar *host;
+
+    host =
+        g_inet_address_to_string (g_inet_socket_address_get_address
+        (G_INET_SOCKET_ADDRESS (addr)));
+    GST_DEBUG ("sending %" G_GSIZE_FORMAT " bytes to client %s port %d",
+        map.size, host,
+        g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)));
+    g_free (host);
+  }
+#endif
+
+  /* Select socket to send from for this address */
+  if (family == G_SOCKET_FAMILY_IPV6 || !sink->used_socket)
+    socket = sink->used_socket_v6;
+  else
+    socket = sink->used_socket;
+
+  ret =
+      g_socket_send_to (socket, addr, (gchar *) map.data, map.size,
+      sink->cancellable, &err);
+  gst_buffer_unmap (buffer, &map);
+
+  if (ret < 0)
+    goto send_error;
+
+  GST_DEBUG ("sent %" G_GSSIZE_FORMAT " bytes", ret);
+
+  return GST_FLOW_OK;
+
+send_error:
+  {
+    GstFlowReturn flow_ret;
+
+    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+      GST_DEBUG_OBJECT (sink, "send cancelled");
+      flow_ret = GST_FLOW_FLUSHING;
+    } else {
+      GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL),
+          ("send error: %s", err->message));
+      flow_ret = GST_FLOW_ERROR;
+    }
+    g_clear_error (&err);
+    return flow_ret;
+  }
+invalid_family:
+  {
+    GST_DEBUG ("invalid address family (got %d)", family);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static void
+gst_dynudpsink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstDynUDPSink *udpsink;
+
+  udpsink = GST_DYNUDPSINK (object);
+
+  switch (prop_id) {
+    case PROP_SOCKET:
+      if (udpsink->socket != NULL && udpsink->socket != udpsink->used_socket &&
+          udpsink->close_socket) {
+        GError *err = NULL;
+
+        if (!g_socket_close (udpsink->socket, &err)) {
+          GST_ERROR ("failed to close socket %p: %s", udpsink->socket,
+              err->message);
+          g_clear_error (&err);
+        }
+      }
+      if (udpsink->socket)
+        g_object_unref (udpsink->socket);
+      udpsink->socket = g_value_dup_object (value);
+      GST_DEBUG ("setting socket to %p", udpsink->socket);
+      break;
+    case PROP_SOCKET_V6:
+      if (udpsink->socket_v6 != NULL
+          && udpsink->socket_v6 != udpsink->used_socket_v6
+          && udpsink->close_socket) {
+        GError *err = NULL;
+
+        if (!g_socket_close (udpsink->socket_v6, &err)) {
+          GST_ERROR ("failed to close socket %p: %s", udpsink->socket_v6,
+              err->message);
+          g_clear_error (&err);
+        }
+      }
+      if (udpsink->socket_v6)
+        g_object_unref (udpsink->socket_v6);
+      udpsink->socket_v6 = g_value_dup_object (value);
+      GST_DEBUG ("setting socket v6 to %p", udpsink->socket_v6);
+      break;
+    case PROP_CLOSE_SOCKET:
+      udpsink->close_socket = g_value_get_boolean (value);
+      break;
+    case PROP_BIND_ADDRESS:
+      g_free (udpsink->bind_address);
+      udpsink->bind_address = g_value_dup_string (value);
+      break;
+    case PROP_BIND_PORT:
+      udpsink->bind_port = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_dynudpsink_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstDynUDPSink *udpsink;
+
+  udpsink = GST_DYNUDPSINK (object);
+
+  switch (prop_id) {
+    case PROP_SOCKET:
+      g_value_set_object (value, udpsink->socket);
+      break;
+    case PROP_SOCKET_V6:
+      g_value_set_object (value, udpsink->socket_v6);
+      break;
+    case PROP_CLOSE_SOCKET:
+      g_value_set_boolean (value, udpsink->close_socket);
+      break;
+    case PROP_BIND_ADDRESS:
+      g_value_set_string (value, udpsink->bind_address);
+      break;
+    case PROP_BIND_PORT:
+      g_value_set_int (value, udpsink->bind_port);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_dynudpsink_create_cancellable (GstDynUDPSink * sink)
+{
+  GPollFD pollfd;
+
+  sink->cancellable = g_cancellable_new ();
+  sink->made_cancel_fd = g_cancellable_make_pollfd (sink->cancellable, &pollfd);
+}
+
+static void
+gst_dynudpsink_free_cancellable (GstDynUDPSink * sink)
+{
+  if (sink->made_cancel_fd) {
+    g_cancellable_release_fd (sink->cancellable);
+    sink->made_cancel_fd = FALSE;
+  }
+  g_object_unref (sink->cancellable);
+  sink->cancellable = NULL;
+}
+
+/* create a socket for sending to remote machine */
+static gboolean
+gst_dynudpsink_start (GstBaseSink * bsink)
+{
+  GstDynUDPSink *udpsink;
+  GError *err = NULL;
+
+  udpsink = GST_DYNUDPSINK (bsink);
+
+  gst_dynudpsink_create_cancellable (udpsink);
+
+  udpsink->external_socket = FALSE;
+
+  if (udpsink->socket) {
+    if (g_socket_get_family (udpsink->socket) == G_SOCKET_FAMILY_IPV6) {
+      udpsink->used_socket_v6 = G_SOCKET (g_object_ref (udpsink->socket));
+      udpsink->external_socket = TRUE;
+    } else {
+      udpsink->used_socket = G_SOCKET (g_object_ref (udpsink->socket));
+      udpsink->external_socket = TRUE;
+    }
+  }
+
+  if (udpsink->socket_v6) {
+    g_return_val_if_fail (g_socket_get_family (udpsink->socket) !=
+        G_SOCKET_FAMILY_IPV6, FALSE);
+
+    if (udpsink->used_socket_v6
+        && udpsink->used_socket_v6 != udpsink->socket_v6) {
+      GST_ERROR_OBJECT (udpsink,
+          "Provided different IPv6 sockets in socket and socket-v6 properties");
+      return FALSE;
+    }
+
+    udpsink->used_socket_v6 = G_SOCKET (g_object_ref (udpsink->socket_v6));
+    udpsink->external_socket = TRUE;
+  }
+
+  if (!udpsink->used_socket && !udpsink->used_socket_v6) {
+    GSocketAddress *bind_addr;
+    GInetAddress *bind_iaddr;
+
+    if (udpsink->bind_address) {
+      GSocketFamily family;
+
+      bind_iaddr = g_inet_address_new_from_string (udpsink->bind_address);
+      if (!bind_iaddr) {
+        GList *results;
+        GResolver *resolver;
+
+        resolver = g_resolver_get_default ();
+        results =
+            g_resolver_lookup_by_name (resolver, udpsink->bind_address,
+            udpsink->cancellable, &err);
+        if (!results) {
+          g_object_unref (resolver);
+          goto name_resolve;
+        }
+        bind_iaddr = G_INET_ADDRESS (g_object_ref (results->data));
+        g_resolver_free_addresses (results);
+        g_object_unref (resolver);
+      }
+
+      bind_addr = g_inet_socket_address_new (bind_iaddr, udpsink->bind_port);
+      g_object_unref (bind_iaddr);
+      family = g_socket_address_get_family (G_SOCKET_ADDRESS (bind_addr));
+
+      if ((udpsink->used_socket =
+              g_socket_new (family, G_SOCKET_TYPE_DATAGRAM,
+                  G_SOCKET_PROTOCOL_UDP, &err)) == NULL) {
+        g_object_unref (bind_addr);
+        goto no_socket;
+      }
+
+      g_socket_bind (udpsink->used_socket, bind_addr, TRUE, &err);
+      if (err != NULL)
+        goto bind_error;
+    } else {
+      /* create sender sockets if none available */
+      if ((udpsink->used_socket = g_socket_new (G_SOCKET_FAMILY_IPV4,
+                  G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
+        goto no_socket;
+
+      bind_iaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
+      bind_addr = g_inet_socket_address_new (bind_iaddr, 0);
+      g_socket_bind (udpsink->used_socket, bind_addr, TRUE, &err);
+      g_object_unref (bind_addr);
+      g_object_unref (bind_iaddr);
+      if (err != NULL)
+        goto bind_error;
+
+      if ((udpsink->used_socket_v6 = g_socket_new (G_SOCKET_FAMILY_IPV6,
+                  G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP,
+                  &err)) == NULL) {
+        GST_INFO_OBJECT (udpsink, "Failed to create IPv6 socket: %s",
+            err->message);
+        g_clear_error (&err);
+      } else {
+        bind_iaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6);
+        bind_addr = g_inet_socket_address_new (bind_iaddr, 0);
+        g_socket_bind (udpsink->used_socket_v6, bind_addr, TRUE, &err);
+        g_object_unref (bind_addr);
+        g_object_unref (bind_iaddr);
+        if (err != NULL)
+          goto bind_error;
+      }
+    }
+  }
+
+  if (udpsink->used_socket)
+    g_socket_set_broadcast (udpsink->used_socket, TRUE);
+  if (udpsink->used_socket_v6)
+    g_socket_set_broadcast (udpsink->used_socket_v6, TRUE);
+
+  return TRUE;
+
+  /* ERRORS */
+no_socket:
+  {
+    GST_ERROR_OBJECT (udpsink, "Failed to create IPv4 socket: %s",
+        err->message);
+    g_clear_error (&err);
+    return FALSE;
+  }
+bind_error:
+  {
+    GST_ELEMENT_ERROR (udpsink, RESOURCE, FAILED, (NULL),
+        ("Failed to bind socket: %s", err->message));
+    g_clear_error (&err);
+    return FALSE;
+  }
+name_resolve:
+  {
+    GST_ELEMENT_ERROR (udpsink, RESOURCE, FAILED, (NULL),
+        ("Failed to resolve bind address %s: %s", udpsink->bind_address,
+            err->message));
+    g_clear_error (&err);
+    return FALSE;
+  }
+}
+
+static GstStructure *
+gst_dynudpsink_get_stats (GstDynUDPSink * sink, const gchar * host, gint port)
+{
+  return NULL;
+}
+
+static gboolean
+gst_dynudpsink_stop (GstBaseSink * bsink)
+{
+  GstDynUDPSink *udpsink;
+
+  udpsink = GST_DYNUDPSINK (bsink);
+
+  if (udpsink->used_socket) {
+    if (udpsink->close_socket || !udpsink->external_socket) {
+      GError *err = NULL;
+
+      if (!g_socket_close (udpsink->used_socket, &err)) {
+        GST_ERROR_OBJECT (udpsink, "Failed to close socket: %s", err->message);
+        g_clear_error (&err);
+      }
+    }
+
+    g_object_unref (udpsink->used_socket);
+    udpsink->used_socket = NULL;
+  }
+
+  if (udpsink->used_socket_v6) {
+    if (udpsink->close_socket || !udpsink->external_socket) {
+      GError *err = NULL;
+
+      if (!g_socket_close (udpsink->used_socket_v6, &err)) {
+        GST_ERROR_OBJECT (udpsink, "Failed to close socket: %s", err->message);
+        g_clear_error (&err);
+      }
+    }
+
+    g_object_unref (udpsink->used_socket_v6);
+    udpsink->used_socket_v6 = NULL;
+  }
+
+  gst_dynudpsink_free_cancellable (udpsink);
+
+  return TRUE;
+}
+
+static gboolean
+gst_dynudpsink_unlock (GstBaseSink * bsink)
+{
+  GstDynUDPSink *udpsink;
+
+  udpsink = GST_DYNUDPSINK (bsink);
+
+  g_cancellable_cancel (udpsink->cancellable);
+
+  return TRUE;
+}
+
+static gboolean
+gst_dynudpsink_unlock_stop (GstBaseSink * bsink)
+{
+  GstDynUDPSink *udpsink;
+
+  udpsink = GST_DYNUDPSINK (bsink);
+
+  gst_dynudpsink_free_cancellable (udpsink);
+  gst_dynudpsink_create_cancellable (udpsink);
+
+  return TRUE;
+}
diff --git a/gst/udp/gstdynudpsink.h b/gst/udp/gstdynudpsink.h
new file mode 100644
index 0000000..6d85bb6
--- /dev/null
+++ b/gst/udp/gstdynudpsink.h
@@ -0,0 +1,72 @@
+/* GStreamer
+ * Copyright (C) <2005> Philippe Khalaf <burger@speedy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_DYNUDPSINK_H__
+#define __GST_DYNUDPSINK_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesink.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#include "gstudpnetutils.h"
+
+#define GST_TYPE_DYNUDPSINK             (gst_dynudpsink_get_type())
+#define GST_DYNUDPSINK(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DYNUDPSINK,GstDynUDPSink))
+#define GST_DYNUDPSINK_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DYNUDPSINK,GstDynUDPSinkClass))
+#define GST_IS_DYNUDPSINK(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DYNUDPSINK))
+#define GST_IS_DYNUDPSINK_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DYNUDPSINK))
+
+typedef struct _GstDynUDPSink GstDynUDPSink;
+typedef struct _GstDynUDPSinkClass GstDynUDPSinkClass;
+
+
+/* sends udp packets to host/port pairs contained in the GstNetBuffer received.
+ */
+struct _GstDynUDPSink {
+  GstBaseSink parent;
+
+  /* properties */
+  GSocket *socket, *socket_v6;
+  gboolean close_socket;
+  gchar *bind_address;
+  gint bind_port;
+
+  /* the socket in use */
+  GSocket *used_socket, *used_socket_v6;
+  gboolean external_socket;
+  gboolean made_cancel_fd;
+  GCancellable *cancellable;
+};
+
+struct _GstDynUDPSinkClass {
+  GstBaseSinkClass parent_class;
+
+  /* element methods */
+  GstStructure*  (*get_stats)    (GstDynUDPSink *sink, const gchar *host, gint port);
+
+  /* signals */
+};
+
+GType gst_dynudpsink_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_DYNUDPSINK_H__ */
diff --git a/gst/udp/gstmultiudpsink.c b/gst/udp/gstmultiudpsink.c
new file mode 100644
index 0000000..8c69634
--- /dev/null
+++ b/gst/udp/gstmultiudpsink.c
@@ -0,0 +1,1874 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) <2009> Jarkko Palviainen <jarkko.palviainen@sesca.com>
+ * Copyright (C) <2012> Collabora Ltd.
+ *   Author: Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-multiudpsink
+ * @see_also: udpsink, multifdsink
+ *
+ * multiudpsink is a network sink that sends UDP packets to multiple
+ * clients.
+ * It can be combined with rtp payload encoders to implement RTP streaming.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "gstmultiudpsink.h"
+
+#include <string.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifndef G_OS_WIN32
+#include <netinet/in.h>
+#endif
+
+#include "gst/glib-compat-private.h"
+
+GST_DEBUG_CATEGORY_STATIC (multiudpsink_debug);
+#define GST_CAT_DEFAULT (multiudpsink_debug)
+
+#define UDP_MAX_SIZE 65507
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+/* MultiUDPSink signals and args */
+enum
+{
+  /* methods */
+  SIGNAL_ADD,
+  SIGNAL_REMOVE,
+  SIGNAL_CLEAR,
+  SIGNAL_GET_STATS,
+
+  /* signals */
+  SIGNAL_CLIENT_ADDED,
+  SIGNAL_CLIENT_REMOVED,
+
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+#define DEFAULT_SOCKET             NULL
+#define DEFAULT_CLOSE_SOCKET       TRUE
+#define DEFAULT_USED_SOCKET        NULL
+#define DEFAULT_CLIENTS            NULL
+/* FIXME, this should be disabled by default, we don't need to join a multicast
+ * group for sending, if this socket is also used for receiving, it should
+ * be configured in the element that does the receive. */
+#define DEFAULT_AUTO_MULTICAST     TRUE
+#define DEFAULT_MULTICAST_IFACE    NULL
+#define DEFAULT_TTL                64
+#define DEFAULT_TTL_MC             1
+#define DEFAULT_LOOP               TRUE
+#define DEFAULT_FORCE_IPV4         FALSE
+#define DEFAULT_QOS_DSCP           -1
+#define DEFAULT_SEND_DUPLICATES    TRUE
+#define DEFAULT_BUFFER_SIZE        0
+#define DEFAULT_BIND_ADDRESS       NULL
+#define DEFAULT_BIND_PORT          0
+
+enum
+{
+  PROP_0,
+  PROP_BYTES_TO_SERVE,
+  PROP_BYTES_SERVED,
+  PROP_SOCKET,
+  PROP_SOCKET_V6,
+  PROP_CLOSE_SOCKET,
+  PROP_USED_SOCKET,
+  PROP_USED_SOCKET_V6,
+  PROP_CLIENTS,
+  PROP_AUTO_MULTICAST,
+  PROP_MULTICAST_IFACE,
+  PROP_TTL,
+  PROP_TTL_MC,
+  PROP_LOOP,
+  PROP_FORCE_IPV4,
+  PROP_QOS_DSCP,
+  PROP_SEND_DUPLICATES,
+  PROP_BUFFER_SIZE,
+  PROP_BIND_ADDRESS,
+  PROP_BIND_PORT
+};
+
+static void gst_multiudpsink_finalize (GObject * object);
+
+static GstFlowReturn gst_multiudpsink_render (GstBaseSink * sink,
+    GstBuffer * buffer);
+static GstFlowReturn gst_multiudpsink_render_list (GstBaseSink * bsink,
+    GstBufferList * buffer_list);
+
+static gboolean gst_multiudpsink_start (GstBaseSink * bsink);
+static gboolean gst_multiudpsink_stop (GstBaseSink * bsink);
+static gboolean gst_multiudpsink_unlock (GstBaseSink * bsink);
+static gboolean gst_multiudpsink_unlock_stop (GstBaseSink * bsink);
+
+static void gst_multiudpsink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_multiudpsink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void gst_multiudpsink_add_internal (GstMultiUDPSink * sink,
+    const gchar * host, gint port, gboolean lock);
+static void gst_multiudpsink_clear_internal (GstMultiUDPSink * sink,
+    gboolean lock);
+
+static guint gst_multiudpsink_signals[LAST_SIGNAL] = { 0 };
+
+#define gst_multiudpsink_parent_class parent_class
+G_DEFINE_TYPE (GstMultiUDPSink, gst_multiudpsink, GST_TYPE_BASE_SINK);
+
+static void
+gst_multiudpsink_class_init (GstMultiUDPSinkClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSinkClass *gstbasesink_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesink_class = (GstBaseSinkClass *) klass;
+
+  gobject_class->set_property = gst_multiudpsink_set_property;
+  gobject_class->get_property = gst_multiudpsink_get_property;
+  gobject_class->finalize = gst_multiudpsink_finalize;
+
+  /**
+   * GstMultiUDPSink::add:
+   * @gstmultiudpsink: the sink on which the signal is emitted
+   * @host: the hostname/IP address of the client to add
+   * @port: the port of the client to add
+   *
+   * Add a client with destination @host and @port to the list of
+   * clients. When the same host/port pair is added multiple times, the
+   * send-duplicates property defines if the packets are sent multiple times to
+   * the same host/port pair or not.
+   *
+   * When a host/port pair is added multiple times, an equal amount of remove
+   * calls must be performed to actually remove the host/port pair from the list
+   * of destinations.
+   */
+  gst_multiudpsink_signals[SIGNAL_ADD] =
+      g_signal_new ("add", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_STRUCT_OFFSET (GstMultiUDPSinkClass, add),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2,
+      G_TYPE_STRING, G_TYPE_INT);
+  /**
+   * GstMultiUDPSink::remove:
+   * @gstmultiudpsink: the sink on which the signal is emitted
+   * @host: the hostname/IP address of the client to remove
+   * @port: the port of the client to remove
+   *
+   * Remove the client with destination @host and @port from the list of
+   * clients.
+   */
+  gst_multiudpsink_signals[SIGNAL_REMOVE] =
+      g_signal_new ("remove", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_STRUCT_OFFSET (GstMultiUDPSinkClass, remove),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2,
+      G_TYPE_STRING, G_TYPE_INT);
+  /**
+   * GstMultiUDPSink::clear:
+   * @gstmultiudpsink: the sink on which the signal is emitted
+   *
+   * Clear the list of clients.
+   */
+  gst_multiudpsink_signals[SIGNAL_CLEAR] =
+      g_signal_new ("clear", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_STRUCT_OFFSET (GstMultiUDPSinkClass, clear),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 0);
+  /**
+   * GstMultiUDPSink::get-stats:
+   * @gstmultiudpsink: the sink on which the signal is emitted
+   * @host: the hostname/IP address of the client to get stats on
+   * @port: the port of the client to get stats on
+   *
+   * Get the statistics of the client with destination @host and @port.
+   *
+   * Returns: a GstStructure: bytes_sent, packets_sent,
+   *           connect_time (in epoch seconds), disconnect_time (in epoch seconds)
+   */
+  gst_multiudpsink_signals[SIGNAL_GET_STATS] =
+      g_signal_new ("get-stats", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_STRUCT_OFFSET (GstMultiUDPSinkClass, get_stats),
+      NULL, NULL, g_cclosure_marshal_generic, GST_TYPE_STRUCTURE, 2,
+      G_TYPE_STRING, G_TYPE_INT);
+  /**
+   * GstMultiUDPSink::client-added:
+   * @gstmultiudpsink: the sink emitting the signal
+   * @host: the hostname/IP address of the added client
+   * @port: the port of the added client
+   *
+   * Signal emited when a new client is added to the list of
+   * clients.
+   */
+  gst_multiudpsink_signals[SIGNAL_CLIENT_ADDED] =
+      g_signal_new ("client-added", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstMultiUDPSinkClass, client_added),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2,
+      G_TYPE_STRING, G_TYPE_INT);
+  /**
+   * GstMultiUDPSink::client-removed:
+   * @gstmultiudpsink: the sink emitting the signal
+   * @host: the hostname/IP address of the removed client
+   * @port: the port of the removed client
+   *
+   * Signal emited when a client is removed from the list of
+   * clients.
+   */
+  gst_multiudpsink_signals[SIGNAL_CLIENT_REMOVED] =
+      g_signal_new ("client-removed", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstMultiUDPSinkClass,
+          client_removed), NULL, NULL, g_cclosure_marshal_generic,
+      G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BYTES_TO_SERVE,
+      g_param_spec_uint64 ("bytes-to-serve", "Bytes to serve",
+          "Number of bytes received to serve to clients", 0, G_MAXUINT64, 0,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BYTES_SERVED,
+      g_param_spec_uint64 ("bytes-served", "Bytes served",
+          "Total number of bytes sent to all clients", 0, G_MAXUINT64, 0,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_SOCKET,
+      g_param_spec_object ("socket", "Socket Handle",
+          "Socket to use for UDP sending. (NULL == allocate)",
+          G_TYPE_SOCKET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_SOCKET_V6,
+      g_param_spec_object ("socket-v6", "Socket Handle IPv6",
+          "Socket to use for UDPv6 sending. (NULL == allocate)",
+          G_TYPE_SOCKET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_CLOSE_SOCKET,
+      g_param_spec_boolean ("close-socket", "Close socket",
+          "Close socket if passed as property on state change",
+          DEFAULT_CLOSE_SOCKET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_USED_SOCKET,
+      g_param_spec_object ("used-socket", "Used Socket Handle",
+          "Socket currently in use for UDP sending. (NULL == no socket)",
+          G_TYPE_SOCKET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_USED_SOCKET_V6,
+      g_param_spec_object ("used-socket-v6", "Used Socket Handle IPv6",
+          "Socket currently in use for UDPv6 sending. (NULL == no socket)",
+          G_TYPE_SOCKET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_CLIENTS,
+      g_param_spec_string ("clients", "Clients",
+          "A comma separated list of host:port pairs with destinations",
+          DEFAULT_CLIENTS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_AUTO_MULTICAST,
+      g_param_spec_boolean ("auto-multicast",
+          "Automatically join/leave multicast groups",
+          "Automatically join/leave the multicast groups, FALSE means user"
+          " has to do it himself", DEFAULT_AUTO_MULTICAST,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MULTICAST_IFACE,
+      g_param_spec_string ("multicast-iface", "Multicast Interface",
+          "The network interface on which to join the multicast group",
+          DEFAULT_MULTICAST_IFACE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_TTL,
+      g_param_spec_int ("ttl", "Unicast TTL",
+          "Used for setting the unicast TTL parameter",
+          0, 255, DEFAULT_TTL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_TTL_MC,
+      g_param_spec_int ("ttl-mc", "Multicast TTL",
+          "Used for setting the multicast TTL parameter",
+          0, 255, DEFAULT_TTL_MC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_LOOP,
+      g_param_spec_boolean ("loop", "Multicast Loopback",
+          "Used for setting the multicast loop parameter. TRUE = enable,"
+          " FALSE = disable", DEFAULT_LOOP,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstMultiUDPSink::force-ipv4:
+   *
+   * Force the use of an IPv4 socket.
+   *
+   * Since: 1.0.2
+   */
+#ifndef GST_REMOVE_DEPRECATED
+  g_object_class_install_property (gobject_class, PROP_FORCE_IPV4,
+      g_param_spec_boolean ("force-ipv4", "Force IPv4",
+          "Forcing the use of an IPv4 socket (DEPRECATED, has no effect anymore)",
+          DEFAULT_FORCE_IPV4,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
+#endif
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QOS_DSCP,
+      g_param_spec_int ("qos-dscp", "QoS diff srv code point",
+          "Quality of Service, differentiated services code point (-1 default)",
+          -1, 63, DEFAULT_QOS_DSCP,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstMultiUDPSink::send-duplicates:
+   *
+   * When a host/port pair is added mutliple times, send the packet to the host
+   * multiple times as well.
+   */
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEND_DUPLICATES,
+      g_param_spec_boolean ("send-duplicates", "Send Duplicates",
+          "When a distination/port pair is added multiple times, send packets "
+          "multiple times as well", DEFAULT_SEND_DUPLICATES,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BUFFER_SIZE,
+      g_param_spec_int ("buffer-size", "Buffer Size",
+          "Size of the kernel send buffer in bytes, 0=default", 0, G_MAXINT,
+          DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_BIND_ADDRESS,
+      g_param_spec_string ("bind-address", "Bind Address",
+          "Address to bind the socket to", DEFAULT_BIND_ADDRESS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_BIND_PORT,
+      g_param_spec_int ("bind-port", "Bind Port",
+          "Port to bind the socket to", 0, G_MAXUINT16,
+          DEFAULT_BIND_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "UDP packet sender",
+      "Sink/Network",
+      "Send data over the network via UDP to one or multiple recipients "
+      "which can be added or removed at runtime using action signals",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  gstbasesink_class->render = gst_multiudpsink_render;
+  gstbasesink_class->render_list = gst_multiudpsink_render_list;
+  gstbasesink_class->start = gst_multiudpsink_start;
+  gstbasesink_class->stop = gst_multiudpsink_stop;
+  gstbasesink_class->unlock = gst_multiudpsink_unlock;
+  gstbasesink_class->unlock_stop = gst_multiudpsink_unlock_stop;
+  klass->add = gst_multiudpsink_add;
+  klass->remove = gst_multiudpsink_remove;
+  klass->clear = gst_multiudpsink_clear;
+  klass->get_stats = gst_multiudpsink_get_stats;
+
+  GST_DEBUG_CATEGORY_INIT (multiudpsink_debug, "multiudpsink", 0, "UDP sink");
+}
+
+static void
+gst_multiudpsink_create_cancellable (GstMultiUDPSink * sink)
+{
+  GPollFD pollfd;
+
+  sink->cancellable = g_cancellable_new ();
+  sink->made_cancel_fd = g_cancellable_make_pollfd (sink->cancellable, &pollfd);
+}
+
+static void
+gst_multiudpsink_free_cancellable (GstMultiUDPSink * sink)
+{
+  if (sink->made_cancel_fd) {
+    g_cancellable_release_fd (sink->cancellable);
+    sink->made_cancel_fd = FALSE;
+  }
+  g_object_unref (sink->cancellable);
+  sink->cancellable = NULL;
+}
+
+static void
+gst_multiudpsink_init (GstMultiUDPSink * sink)
+{
+  guint max_mem;
+
+  g_mutex_init (&sink->client_lock);
+  sink->clients = NULL;
+  sink->num_v4_unique = 0;
+  sink->num_v4_all = 0;
+  sink->num_v6_unique = 0;
+  sink->num_v6_all = 0;
+
+  sink->socket = DEFAULT_SOCKET;
+  sink->socket_v6 = DEFAULT_SOCKET;
+  sink->used_socket = DEFAULT_USED_SOCKET;
+  sink->used_socket_v6 = DEFAULT_USED_SOCKET;
+  sink->close_socket = DEFAULT_CLOSE_SOCKET;
+  sink->external_socket = (sink->socket != NULL);
+  sink->auto_multicast = DEFAULT_AUTO_MULTICAST;
+  sink->ttl = DEFAULT_TTL;
+  sink->ttl_mc = DEFAULT_TTL_MC;
+  sink->loop = DEFAULT_LOOP;
+  sink->force_ipv4 = DEFAULT_FORCE_IPV4;
+  sink->qos_dscp = DEFAULT_QOS_DSCP;
+  sink->send_duplicates = DEFAULT_SEND_DUPLICATES;
+  sink->multi_iface = g_strdup (DEFAULT_MULTICAST_IFACE);
+
+  gst_multiudpsink_create_cancellable (sink);
+
+  /* pre-allocate OutputVector, MapInfo and OutputMessage arrays
+   * for use in the render and render_list functions */
+  max_mem = gst_buffer_get_max_memory ();
+
+  sink->n_vecs = max_mem;
+  sink->vecs = g_new (GOutputVector, sink->n_vecs);
+
+  sink->n_maps = max_mem;
+  sink->maps = g_new (GstMapInfo, sink->n_maps);
+
+  sink->n_messages = 1;
+  sink->messages = g_new (GstOutputMessage, sink->n_messages);
+
+  /* we assume that the number of memories per buffer can fit into a guint8 */
+  g_warn_if_fail (max_mem <= G_MAXUINT8);
+}
+
+static GstUDPClient *
+gst_udp_client_new (GstMultiUDPSink * sink, const gchar * host, gint port)
+{
+  GstUDPClient *client;
+  GInetAddress *addr;
+  GResolver *resolver;
+  GError *err = NULL;
+
+  addr = g_inet_address_new_from_string (host);
+  if (!addr) {
+    GList *results;
+
+    resolver = g_resolver_get_default ();
+    results =
+        g_resolver_lookup_by_name (resolver, host, sink->cancellable, &err);
+    if (!results)
+      goto name_resolve;
+    addr = G_INET_ADDRESS (g_object_ref (results->data));
+
+    g_resolver_free_addresses (results);
+    g_object_unref (resolver);
+  }
+#ifndef GST_DISABLE_GST_DEBUG
+  {
+    gchar *ip = g_inet_address_to_string (addr);
+
+    GST_DEBUG_OBJECT (sink, "IP address for host %s is %s", host, ip);
+    g_free (ip);
+  }
+#endif
+
+  client = g_slice_new0 (GstUDPClient);
+  client->ref_count = 1;
+  client->add_count = 0;
+  client->host = g_strdup (host);
+  client->port = port;
+  client->addr = g_inet_socket_address_new (addr, port);
+  g_object_unref (addr);
+
+  return client;
+
+name_resolve:
+  {
+    g_clear_error (&err);
+    g_object_unref (resolver);
+
+    return NULL;
+  }
+}
+
+/* call with client lock held */
+static void
+gst_udp_client_unref (GstUDPClient * client)
+{
+  if (--client->ref_count == 0) {
+    g_object_unref (client->addr);
+    g_free (client->host);
+    g_slice_free (GstUDPClient, client);
+  }
+}
+
+/* call with client lock held */
+static inline GstUDPClient *
+gst_udp_client_ref (GstUDPClient * client)
+{
+  ++client->ref_count;
+  return client;
+}
+
+static gint
+client_compare (GstUDPClient * a, GstUDPClient * b)
+{
+  if ((a->port == b->port) && (strcmp (a->host, b->host) == 0))
+    return 0;
+
+  return 1;
+}
+
+static void
+gst_multiudpsink_finalize (GObject * object)
+{
+  GstMultiUDPSink *sink;
+
+  sink = GST_MULTIUDPSINK (object);
+
+  g_list_foreach (sink->clients, (GFunc) gst_udp_client_unref, NULL);
+  g_list_free (sink->clients);
+
+  if (sink->socket)
+    g_object_unref (sink->socket);
+  sink->socket = NULL;
+
+  if (sink->socket_v6)
+    g_object_unref (sink->socket_v6);
+  sink->socket_v6 = NULL;
+
+  if (sink->used_socket)
+    g_object_unref (sink->used_socket);
+  sink->used_socket = NULL;
+
+  if (sink->used_socket_v6)
+    g_object_unref (sink->used_socket_v6);
+  sink->used_socket_v6 = NULL;
+
+  gst_multiudpsink_free_cancellable (sink);
+
+  g_free (sink->multi_iface);
+  sink->multi_iface = NULL;
+
+  g_free (sink->vecs);
+  sink->vecs = NULL;
+  g_free (sink->maps);
+  sink->maps = NULL;
+  g_free (sink->messages);
+  sink->messages = NULL;
+
+  g_free (sink->bind_address);
+  sink->bind_address = NULL;
+
+  g_mutex_clear (&sink->client_lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* replacement until we can depend unconditionally on the real one in GLib */
+#ifndef HAVE_G_SOCKET_SEND_MESSAGES
+#define g_socket_send_messages gst_socket_send_messages
+
+static gint
+gst_socket_send_messages (GSocket * socket, GstOutputMessage * messages,
+    guint num_messages, gint flags, GCancellable * cancellable, GError ** error)
+{
+  gssize result;
+  gint i;
+
+  for (i = 0; i < num_messages; ++i) {
+    GstOutputMessage *msg = &messages[i];
+    GError *msg_error = NULL;
+
+    result = g_socket_send_message (socket, msg->address,
+        msg->vectors, msg->num_vectors,
+        msg->control_messages, msg->num_control_messages,
+        flags, cancellable, &msg_error);
+
+    if (result < 0) {
+      /* if we couldn't send all messages, just return how many we did
+       * manage to send, provided we managed to send at least one */
+      if (msg_error->code == G_IO_ERROR_WOULD_BLOCK && i > 0) {
+        g_error_free (msg_error);
+        return i;
+      } else {
+        g_propagate_error (error, msg_error);
+        return -1;
+      }
+    }
+
+    msg->bytes_sent = result;
+  }
+
+  return i;
+}
+#endif /* HAVE_G_SOCKET_SEND_MESSAGES */
+
+static gsize
+fill_vectors (GOutputVector * vecs, GstMapInfo * maps, guint n, GstBuffer * buf)
+{
+  GstMemory *mem;
+  gsize size = 0;
+  guint i;
+
+  g_assert (gst_buffer_n_memory (buf) == n);
+
+  for (i = 0; i < n; ++i) {
+    mem = gst_buffer_peek_memory (buf, i);
+    if (gst_memory_map (mem, &maps[i], GST_MAP_READ)) {
+      vecs[i].buffer = maps[i].data;
+      vecs[i].size = maps[i].size;
+    } else {
+      GST_WARNING ("Failed to map memory %p for reading", mem);
+      vecs[i].buffer = "";
+      vecs[i].size = 0;
+    }
+    size += vecs[i].size;
+  }
+
+  return size;
+}
+
+static gsize
+gst_udp_calc_message_size (GstOutputMessage * msg)
+{
+  gsize size = 0;
+  guint i;
+
+  for (i = 0; i < msg->num_vectors; ++i)
+    size += msg->vectors[i].size;
+
+  return size;
+}
+
+static gint
+gst_udp_messsages_find_first_not_sent (GstOutputMessage * messages,
+    guint num_messages)
+{
+  guint i;
+
+  for (i = 0; i < num_messages; ++i) {
+    GstOutputMessage *msg = &messages[i];
+
+    if (msg->bytes_sent == 0 && gst_udp_calc_message_size (msg) > 0)
+      return i;
+  }
+
+  return -1;
+}
+
+static inline gchar *
+gst_udp_address_get_string (GSocketAddress * addr, gchar * s, gsize size)
+{
+  GInetSocketAddress *isa = G_INET_SOCKET_ADDRESS (addr);
+  GInetAddress *ia;
+  gchar *addr_str;
+
+  ia = g_inet_socket_address_get_address (isa);
+  addr_str = g_inet_address_to_string (ia);
+  g_snprintf (s, size, "%s:%u", addr_str, g_inet_socket_address_get_port (isa));
+  g_free (addr_str);
+
+  return s;
+}
+
+/* Wrapper around g_socket_send_messages() plus error handling (ignoring).
+ * Returns FALSE if we got cancelled, otherwise TRUE. */
+static GstFlowReturn
+gst_multiudpsink_send_messages (GstMultiUDPSink * sink, GSocket * socket,
+    GstOutputMessage * messages, guint num_messages)
+{
+  gboolean sent_max_size_warning = FALSE;
+
+  while (num_messages > 0) {
+    gchar astr[64] G_GNUC_UNUSED;
+    GError *err = NULL;
+    guint msg_size, skip, i;
+    gint ret, err_idx;
+
+    ret = g_socket_send_messages (socket, messages, num_messages, 0,
+        sink->cancellable, &err);
+
+    if (G_UNLIKELY (ret < 0)) {
+      GstOutputMessage *msg;
+
+      if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+        GstFlowReturn flow_ret;
+
+        g_clear_error (&err);
+
+        flow_ret = gst_base_sink_wait_preroll (GST_BASE_SINK (sink));
+
+        if (flow_ret == GST_FLOW_OK)
+          continue;
+
+        return flow_ret;
+      }
+
+      err_idx = gst_udp_messsages_find_first_not_sent (messages, num_messages);
+      if (err_idx < 0)
+        break;
+
+      msg = &messages[err_idx];
+      msg_size = gst_udp_calc_message_size (msg);
+
+      GST_LOG_OBJECT (sink, "error sending %u bytes to client %s: %s", msg_size,
+          gst_udp_address_get_string (msg->address, astr, sizeof (astr)),
+          err->message);
+
+      skip = 1;
+      if (msg_size > UDP_MAX_SIZE) {
+        if (!sent_max_size_warning) {
+          GST_ELEMENT_WARNING (sink, RESOURCE, WRITE,
+              ("Attempting to send a UDP packets larger than maximum size "
+                  "(%u > %d)", msg_size, UDP_MAX_SIZE),
+              ("Reason: %s", err ? err->message : "unknown reason"));
+          sent_max_size_warning = FALSE;
+        }
+      } else {
+        GST_ELEMENT_WARNING (sink, RESOURCE, WRITE,
+            ("Error sending UDP packets"), ("client %s, reason: %s",
+                gst_udp_address_get_string (msg->address, astr, sizeof (astr)),
+                (err != NULL) ? err->message : "unknown reason"));
+
+        for (i = err_idx + 1; i < num_messages; ++i, ++skip) {
+          if (messages[i].address != msg->address)
+            break;
+        }
+        GST_DEBUG_OBJECT (sink, "skipping %d message(s) to same client", skip);
+      }
+
+      /* ignore any errors and try sending the rest */
+      g_clear_error (&err);
+      ret = skip;
+    }
+
+    g_assert (ret <= num_messages);
+
+    messages += ret;
+    num_messages -= ret;
+  }
+
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_multiudpsink_render_buffers (GstMultiUDPSink * sink, GstBuffer ** buffers,
+    guint num_buffers, guint8 * mem_nums, guint total_mem_num)
+{
+  GstOutputMessage *msgs;
+  gboolean send_duplicates;
+  GstUDPClient **clients;
+  GOutputVector *vecs;
+  GstMapInfo *map_infos;
+  GstFlowReturn flow_ret;
+  guint num_addr_v4, num_addr_v6;
+  guint num_addr, num_msgs;
+  guint i, j, mem;
+  gsize size = 0;
+  GList *l;
+
+  send_duplicates = sink->send_duplicates;
+
+  g_mutex_lock (&sink->client_lock);
+
+  if (send_duplicates) {
+    num_addr_v4 = sink->num_v4_all;
+    num_addr_v6 = sink->num_v6_all;
+  } else {
+    num_addr_v4 = sink->num_v4_unique;
+    num_addr_v6 = sink->num_v6_unique;
+  }
+  num_addr = num_addr_v4 + num_addr_v6;
+
+  if (num_addr == 0)
+    goto no_clients;
+
+  clients = g_newa (GstUDPClient *, num_addr);
+  for (l = sink->clients, i = 0; l != NULL; l = l->next) {
+    GstUDPClient *client = l->data;
+
+    clients[i++] = gst_udp_client_ref (client);
+    for (j = 1; send_duplicates && j < client->add_count; ++j)
+      clients[i++] = gst_udp_client_ref (client);
+  }
+  g_assert_cmpuint (i, ==, num_addr);
+
+  g_mutex_unlock (&sink->client_lock);
+
+  GST_LOG_OBJECT (sink, "%u buffers, %u memories -> to be sent to %u clients",
+      num_buffers, total_mem_num, num_addr);
+
+  /* ensure our pre-allocated scratch space arrays are large enough */
+  if (sink->n_vecs < total_mem_num) {
+    sink->n_vecs = GST_ROUND_UP_16 (total_mem_num);
+    g_free (sink->vecs);
+    sink->vecs = g_new (GOutputVector, sink->n_vecs);
+  }
+  vecs = sink->vecs;
+
+  if (sink->n_maps < total_mem_num) {
+    sink->n_maps = GST_ROUND_UP_16 (total_mem_num);
+    g_free (sink->maps);
+    sink->maps = g_new (GstMapInfo, sink->n_maps);
+  }
+  map_infos = sink->maps;
+
+  num_msgs = num_addr * num_buffers;
+  if (sink->n_messages < num_msgs) {
+    sink->n_messages = GST_ROUND_UP_16 (num_msgs);
+    g_free (sink->messages);
+    sink->messages = g_new (GstOutputMessage, sink->n_messages);
+  }
+  msgs = sink->messages;
+
+  /* populate first num_buffers messages with output vectors for the buffers */
+  for (i = 0, mem = 0; i < num_buffers; ++i) {
+    size += fill_vectors (&vecs[mem], &map_infos[mem], mem_nums[i], buffers[i]);
+    msgs[i].vectors = &vecs[mem];
+    msgs[i].num_vectors = mem_nums[i];
+    msgs[i].num_control_messages = 0;
+    msgs[i].bytes_sent = 0;
+    msgs[i].control_messages = NULL;
+    msgs[i].address = clients[0]->addr;
+    mem += mem_nums[i];
+  }
+
+  /* FIXME: how about some locking? (there wasn't any before either, but..) */
+  sink->bytes_to_serve += size;
+
+  /* now copy the pre-filled num_buffer messages over to the next num_buffer
+   * messages for the next client, where we also change the target adddress */
+  for (i = 1; i < num_addr; ++i) {
+    for (j = 0; j < num_buffers; ++j) {
+      msgs[i * num_buffers + j] = msgs[j];
+      msgs[i * num_buffers + j].address = clients[i]->addr;
+    }
+  }
+
+  /* now send it! */
+
+  /* no IPv4 socket? Send it all from the IPv6 socket then.. */
+  if (sink->used_socket == NULL) {
+    flow_ret = gst_multiudpsink_send_messages (sink, sink->used_socket_v6,
+        msgs, num_msgs);
+  } else {
+    guint num_msgs_v4 = num_buffers * num_addr_v4;
+    guint num_msgs_v6 = num_buffers * num_addr_v6;
+
+    /* our client list is sorted with IPv4 clients first and IPv6 ones last */
+    flow_ret = gst_multiudpsink_send_messages (sink, sink->used_socket,
+        msgs, num_msgs_v4);
+
+    if (flow_ret != GST_FLOW_OK)
+      goto cancelled;
+
+    flow_ret = gst_multiudpsink_send_messages (sink, sink->used_socket_v6,
+        msgs + num_msgs_v4, num_msgs_v6);
+  }
+
+  if (flow_ret != GST_FLOW_OK)
+    goto cancelled;
+
+  /* now update stats */
+  g_mutex_lock (&sink->client_lock);
+
+  for (i = 0; i < num_addr; ++i) {
+    GstUDPClient *client = clients[i];
+
+    for (j = 0; j < num_buffers; ++j) {
+      gsize bytes_sent;
+
+      bytes_sent = msgs[i * num_buffers + j].bytes_sent;
+
+      client->bytes_sent += bytes_sent;
+      client->packets_sent++;
+      sink->bytes_served += bytes_sent;
+    }
+    gst_udp_client_unref (client);
+  }
+
+  g_mutex_unlock (&sink->client_lock);
+
+out:
+
+  for (i = 0; i < mem; ++i)
+    gst_memory_unmap (map_infos[i].memory, &map_infos[i]);
+
+  return flow_ret;
+
+no_clients:
+  {
+    g_mutex_unlock (&sink->client_lock);
+    GST_LOG_OBJECT (sink, "no clients");
+    return GST_FLOW_OK;
+  }
+cancelled:
+  {
+    GST_INFO_OBJECT (sink, "cancelled");
+
+    g_mutex_lock (&sink->client_lock);
+    for (i = 0; i < num_addr; ++i)
+      gst_udp_client_unref (clients[i]);
+    g_mutex_unlock (&sink->client_lock);
+    goto out;
+  }
+}
+
+static GstFlowReturn
+gst_multiudpsink_render_list (GstBaseSink * bsink, GstBufferList * buffer_list)
+{
+  GstMultiUDPSink *sink;
+  GstBuffer **buffers;
+  GstFlowReturn flow;
+  guint8 *mem_nums;
+  guint total_mems;
+  guint i, num_buffers;
+
+  sink = GST_MULTIUDPSINK_CAST (bsink);
+
+  num_buffers = gst_buffer_list_length (buffer_list);
+  if (num_buffers == 0)
+    goto no_data;
+
+  buffers = g_newa (GstBuffer *, num_buffers);
+  mem_nums = g_newa (guint8, num_buffers);
+  for (i = 0, total_mems = 0; i < num_buffers; ++i) {
+    buffers[i] = gst_buffer_list_get (buffer_list, i);
+    mem_nums[i] = gst_buffer_n_memory (buffers[i]);
+    total_mems += mem_nums[i];
+  }
+
+  flow = gst_multiudpsink_render_buffers (sink, buffers, num_buffers,
+      mem_nums, total_mems);
+
+  return flow;
+
+no_data:
+  {
+    GST_LOG_OBJECT (sink, "empty buffer");
+    return GST_FLOW_OK;
+  }
+}
+
+static GstFlowReturn
+gst_multiudpsink_render (GstBaseSink * bsink, GstBuffer * buffer)
+{
+  GstMultiUDPSink *sink;
+  GstFlowReturn flow;
+  guint8 n_mem;
+
+  sink = GST_MULTIUDPSINK_CAST (bsink);
+
+  n_mem = gst_buffer_n_memory (buffer);
+
+  if (n_mem > 0)
+    flow = gst_multiudpsink_render_buffers (sink, &buffer, 1, &n_mem, n_mem);
+  else
+    flow = GST_FLOW_OK;
+
+  return flow;
+}
+
+static void
+gst_multiudpsink_set_clients_string (GstMultiUDPSink * sink,
+    const gchar * string)
+{
+  gchar **clients;
+  gint i;
+
+  clients = g_strsplit (string, ",", 0);
+
+  g_mutex_lock (&sink->client_lock);
+  /* clear all existing clients */
+  gst_multiudpsink_clear_internal (sink, FALSE);
+  for (i = 0; clients[i]; i++) {
+    gchar *host, *p;
+    gint64 port = 0;
+
+    host = clients[i];
+    p = strstr (clients[i], ":");
+    if (p != NULL) {
+      *p = '\0';
+      port = g_ascii_strtoll (p + 1, NULL, 10);
+    }
+    if (port != 0)
+      gst_multiudpsink_add_internal (sink, host, port, FALSE);
+  }
+  g_mutex_unlock (&sink->client_lock);
+
+  g_strfreev (clients);
+}
+
+static gchar *
+gst_multiudpsink_get_clients_string (GstMultiUDPSink * sink)
+{
+  GString *str;
+  GList *clients;
+
+  str = g_string_new ("");
+
+  g_mutex_lock (&sink->client_lock);
+  clients = sink->clients;
+  while (clients) {
+    GstUDPClient *client;
+    gint count;
+
+    client = (GstUDPClient *) clients->data;
+
+    clients = g_list_next (clients);
+
+    count = client->add_count;
+    while (count--) {
+      g_string_append_printf (str, "%s:%d%s", client->host, client->port,
+          (clients || count > 1 ? "," : ""));
+    }
+  }
+  g_mutex_unlock (&sink->client_lock);
+
+  return g_string_free (str, FALSE);
+}
+
+static void
+gst_multiudpsink_setup_qos_dscp (GstMultiUDPSink * sink, GSocket * socket)
+{
+  /* don't touch on -1 */
+  if (sink->qos_dscp < 0)
+    return;
+
+  if (socket == NULL)
+    return;
+
+#ifdef IP_TOS
+  {
+    gint tos;
+    gint fd;
+
+    fd = g_socket_get_fd (socket);
+
+    GST_DEBUG_OBJECT (sink, "setting TOS to %d", sink->qos_dscp);
+
+    /* Extract and shift 6 bits of DSFIELD */
+    tos = (sink->qos_dscp & 0x3f) << 2;
+
+    if (setsockopt (fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos)) < 0) {
+      GST_ERROR_OBJECT (sink, "could not set TOS: %s", g_strerror (errno));
+    }
+#ifdef IPV6_TCLASS
+    if (g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6) {
+      if (setsockopt (fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof (tos)) < 0) {
+        GST_ERROR_OBJECT (sink, "could not set TCLASS: %s", g_strerror (errno));
+      }
+    }
+#endif
+  }
+#endif
+}
+
+static void
+gst_multiudpsink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstMultiUDPSink *udpsink;
+
+  udpsink = GST_MULTIUDPSINK (object);
+
+  switch (prop_id) {
+    case PROP_SOCKET:
+      if (udpsink->socket != NULL && udpsink->socket != udpsink->used_socket &&
+          udpsink->close_socket) {
+        GError *err = NULL;
+
+        if (!g_socket_close (udpsink->socket, &err)) {
+          GST_ERROR ("failed to close socket %p: %s", udpsink->socket,
+              err->message);
+          g_clear_error (&err);
+        }
+      }
+      if (udpsink->socket)
+        g_object_unref (udpsink->socket);
+      udpsink->socket = g_value_dup_object (value);
+      GST_DEBUG_OBJECT (udpsink, "setting socket to %p", udpsink->socket);
+      break;
+    case PROP_SOCKET_V6:
+      if (udpsink->socket_v6 != NULL
+          && udpsink->socket_v6 != udpsink->used_socket_v6
+          && udpsink->close_socket) {
+        GError *err = NULL;
+
+        if (!g_socket_close (udpsink->socket_v6, &err)) {
+          GST_ERROR ("failed to close socket %p: %s", udpsink->socket_v6,
+              err->message);
+          g_clear_error (&err);
+        }
+      }
+      if (udpsink->socket_v6)
+        g_object_unref (udpsink->socket_v6);
+      udpsink->socket_v6 = g_value_dup_object (value);
+      GST_DEBUG_OBJECT (udpsink, "setting socket to %p", udpsink->socket_v6);
+      break;
+    case PROP_CLOSE_SOCKET:
+      udpsink->close_socket = g_value_get_boolean (value);
+      break;
+    case PROP_CLIENTS:
+      gst_multiudpsink_set_clients_string (udpsink, g_value_get_string (value));
+      break;
+    case PROP_AUTO_MULTICAST:
+      udpsink->auto_multicast = g_value_get_boolean (value);
+      break;
+    case PROP_MULTICAST_IFACE:
+      g_free (udpsink->multi_iface);
+
+      if (g_value_get_string (value) == NULL)
+        udpsink->multi_iface = g_strdup (DEFAULT_MULTICAST_IFACE);
+      else
+        udpsink->multi_iface = g_value_dup_string (value);
+      break;
+    case PROP_TTL:
+      udpsink->ttl = g_value_get_int (value);
+      break;
+    case PROP_TTL_MC:
+      udpsink->ttl_mc = g_value_get_int (value);
+      break;
+    case PROP_LOOP:
+      udpsink->loop = g_value_get_boolean (value);
+      break;
+    case PROP_FORCE_IPV4:
+      udpsink->force_ipv4 = g_value_get_boolean (value);
+      break;
+    case PROP_QOS_DSCP:
+      udpsink->qos_dscp = g_value_get_int (value);
+      gst_multiudpsink_setup_qos_dscp (udpsink, udpsink->used_socket);
+      gst_multiudpsink_setup_qos_dscp (udpsink, udpsink->used_socket_v6);
+      break;
+    case PROP_SEND_DUPLICATES:
+      udpsink->send_duplicates = g_value_get_boolean (value);
+      break;
+    case PROP_BUFFER_SIZE:
+      udpsink->buffer_size = g_value_get_int (value);
+      break;
+    case PROP_BIND_ADDRESS:
+      g_free (udpsink->bind_address);
+      udpsink->bind_address = g_value_dup_string (value);
+      break;
+    case PROP_BIND_PORT:
+      udpsink->bind_port = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_multiudpsink_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstMultiUDPSink *udpsink;
+
+  udpsink = GST_MULTIUDPSINK (object);
+
+  switch (prop_id) {
+    case PROP_BYTES_TO_SERVE:
+      g_value_set_uint64 (value, udpsink->bytes_to_serve);
+      break;
+    case PROP_BYTES_SERVED:
+      g_value_set_uint64 (value, udpsink->bytes_served);
+      break;
+    case PROP_SOCKET:
+      g_value_set_object (value, udpsink->socket);
+      break;
+    case PROP_SOCKET_V6:
+      g_value_set_object (value, udpsink->socket_v6);
+      break;
+    case PROP_CLOSE_SOCKET:
+      g_value_set_boolean (value, udpsink->close_socket);
+      break;
+    case PROP_USED_SOCKET:
+      g_value_set_object (value, udpsink->used_socket);
+      break;
+    case PROP_USED_SOCKET_V6:
+      g_value_set_object (value, udpsink->used_socket_v6);
+      break;
+    case PROP_CLIENTS:
+      g_value_take_string (value,
+          gst_multiudpsink_get_clients_string (udpsink));
+      break;
+    case PROP_AUTO_MULTICAST:
+      g_value_set_boolean (value, udpsink->auto_multicast);
+      break;
+    case PROP_MULTICAST_IFACE:
+      g_value_set_string (value, udpsink->multi_iface);
+      break;
+    case PROP_TTL:
+      g_value_set_int (value, udpsink->ttl);
+      break;
+    case PROP_TTL_MC:
+      g_value_set_int (value, udpsink->ttl_mc);
+      break;
+    case PROP_LOOP:
+      g_value_set_boolean (value, udpsink->loop);
+      break;
+    case PROP_FORCE_IPV4:
+      g_value_set_boolean (value, udpsink->force_ipv4);
+      break;
+    case PROP_QOS_DSCP:
+      g_value_set_int (value, udpsink->qos_dscp);
+      break;
+    case PROP_SEND_DUPLICATES:
+      g_value_set_boolean (value, udpsink->send_duplicates);
+      break;
+    case PROP_BUFFER_SIZE:
+      g_value_set_int (value, udpsink->buffer_size);
+      break;
+    case PROP_BIND_ADDRESS:
+      g_value_set_string (value, udpsink->bind_address);
+      break;
+    case PROP_BIND_PORT:
+      g_value_set_int (value, udpsink->bind_port);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_multiudpsink_configure_client (GstMultiUDPSink * sink,
+    GstUDPClient * client)
+{
+  GInetSocketAddress *saddr = G_INET_SOCKET_ADDRESS (client->addr);
+  GInetAddress *addr = g_inet_socket_address_get_address (saddr);
+  GSocketFamily family = g_socket_address_get_family (G_SOCKET_ADDRESS (saddr));
+  GSocket *socket;
+  GError *err = NULL;
+
+  GST_DEBUG_OBJECT (sink, "configuring client %p", client);
+
+  if (family == G_SOCKET_FAMILY_IPV6 && !sink->used_socket_v6)
+    goto invalid_family;
+
+  /* Select socket to send from for this address */
+  if (family == G_SOCKET_FAMILY_IPV6 || !sink->used_socket)
+    socket = sink->used_socket_v6;
+  else
+    socket = sink->used_socket;
+
+  if (g_inet_address_get_is_multicast (addr)) {
+    GST_DEBUG_OBJECT (sink, "we have a multicast client %p", client);
+    if (sink->auto_multicast) {
+      GST_DEBUG_OBJECT (sink, "autojoining group");
+      if (!g_socket_join_multicast_group (socket, addr, FALSE,
+              sink->multi_iface, &err))
+        goto join_group_failed;
+    }
+    GST_DEBUG_OBJECT (sink, "setting loop to %d", sink->loop);
+    g_socket_set_multicast_loopback (socket, sink->loop);
+    GST_DEBUG_OBJECT (sink, "setting ttl to %d", sink->ttl_mc);
+    g_socket_set_multicast_ttl (socket, sink->ttl_mc);
+  } else {
+    GST_DEBUG_OBJECT (sink, "setting unicast ttl to %d", sink->ttl);
+    g_socket_set_ttl (socket, sink->ttl);
+  }
+  return TRUE;
+
+  /* ERRORS */
+join_group_failed:
+  {
+    gst_multiudpsink_stop (GST_BASE_SINK (sink));
+    GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
+        ("Could not join multicast group: %s",
+            err ? err->message : "unknown reason"));
+    g_clear_error (&err);
+    return FALSE;
+  }
+invalid_family:
+  {
+    gst_multiudpsink_stop (GST_BASE_SINK (sink));
+    GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
+        ("Invalid address family (got %d)", family));
+    return FALSE;
+  }
+}
+
+/* create a socket for sending to remote machine */
+static gboolean
+gst_multiudpsink_start (GstBaseSink * bsink)
+{
+  GstMultiUDPSink *sink;
+  GList *clients;
+  GstUDPClient *client;
+  GError *err = NULL;
+
+  sink = GST_MULTIUDPSINK (bsink);
+
+  sink->external_socket = FALSE;
+
+  if (sink->socket) {
+    GST_DEBUG_OBJECT (sink, "using configured socket");
+    if (g_socket_get_family (sink->socket) == G_SOCKET_FAMILY_IPV6) {
+      sink->used_socket_v6 = G_SOCKET (g_object_ref (sink->socket));
+      sink->external_socket = TRUE;
+    } else {
+      sink->used_socket = G_SOCKET (g_object_ref (sink->socket));
+      sink->external_socket = TRUE;
+    }
+  }
+
+  if (sink->socket_v6) {
+    GST_DEBUG_OBJECT (sink, "using configured IPv6 socket");
+    g_return_val_if_fail (!sink->socket || g_socket_get_family (sink->socket) !=
+        G_SOCKET_FAMILY_IPV6, FALSE);
+
+    if (sink->used_socket_v6 && sink->used_socket_v6 != sink->socket_v6) {
+      GST_ERROR_OBJECT (sink,
+          "Provided different IPv6 sockets in socket and socket-v6 properties");
+      return FALSE;
+    }
+
+    sink->used_socket_v6 = G_SOCKET (g_object_ref (sink->socket_v6));
+    sink->external_socket = TRUE;
+  }
+
+  if (!sink->used_socket && !sink->used_socket_v6) {
+    GSocketAddress *bind_addr;
+    GInetAddress *bind_iaddr;
+
+    if (sink->bind_address) {
+      GSocketFamily family;
+
+      bind_iaddr = g_inet_address_new_from_string (sink->bind_address);
+      if (!bind_iaddr) {
+        GList *results;
+        GResolver *resolver;
+
+        resolver = g_resolver_get_default ();
+        results =
+            g_resolver_lookup_by_name (resolver, sink->bind_address,
+            sink->cancellable, &err);
+        if (!results) {
+          g_object_unref (resolver);
+          goto name_resolve;
+        }
+        bind_iaddr = G_INET_ADDRESS (g_object_ref (results->data));
+        g_resolver_free_addresses (results);
+        g_object_unref (resolver);
+      }
+
+      bind_addr = g_inet_socket_address_new (bind_iaddr, sink->bind_port);
+      g_object_unref (bind_iaddr);
+      family = g_socket_address_get_family (G_SOCKET_ADDRESS (bind_addr));
+
+      if ((sink->used_socket =
+              g_socket_new (family, G_SOCKET_TYPE_DATAGRAM,
+                  G_SOCKET_PROTOCOL_UDP, &err)) == NULL) {
+        g_object_unref (bind_addr);
+        goto no_socket;
+      }
+
+      g_socket_bind (sink->used_socket, bind_addr, TRUE, &err);
+      g_object_unref (bind_addr);
+      if (err != NULL)
+        goto bind_error;
+    } else {
+      /* create sender sockets if none available */
+      if ((sink->used_socket = g_socket_new (G_SOCKET_FAMILY_IPV4,
+                  G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
+        goto no_socket;
+
+      bind_iaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
+      bind_addr = g_inet_socket_address_new (bind_iaddr, sink->bind_port);
+      g_socket_bind (sink->used_socket, bind_addr, TRUE, &err);
+      g_object_unref (bind_addr);
+      g_object_unref (bind_iaddr);
+      if (err != NULL)
+        goto bind_error;
+
+      if ((sink->used_socket_v6 = g_socket_new (G_SOCKET_FAMILY_IPV6,
+                  G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP,
+                  &err)) == NULL) {
+        GST_INFO_OBJECT (sink, "Failed to create IPv6 socket: %s",
+            err->message);
+        g_clear_error (&err);
+      } else {
+        bind_iaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6);
+        bind_addr = g_inet_socket_address_new (bind_iaddr, sink->bind_port);
+        g_socket_bind (sink->used_socket_v6, bind_addr, TRUE, &err);
+        g_object_unref (bind_addr);
+        g_object_unref (bind_iaddr);
+        if (err != NULL)
+          goto bind_error;
+      }
+    }
+  }
+#ifdef SO_SNDBUF
+  {
+    socklen_t len;
+    gint sndsize, ret;
+
+    len = sizeof (sndsize);
+    if (sink->buffer_size != 0) {
+      sndsize = sink->buffer_size;
+
+      GST_DEBUG_OBJECT (sink, "setting udp buffer of %d bytes", sndsize);
+      /* set buffer size, Note that on Linux this is typically limited to a
+       * maximum of around 100K. Also a minimum of 128 bytes is required on
+       * Linux. */
+
+      if (sink->used_socket) {
+        ret =
+            setsockopt (g_socket_get_fd (sink->used_socket), SOL_SOCKET,
+            SO_SNDBUF, (void *) &sndsize, len);
+        if (ret != 0) {
+          GST_ELEMENT_WARNING (sink, RESOURCE, SETTINGS, (NULL),
+              ("Could not create a buffer of requested %d bytes, %d: %s",
+                  sndsize, ret, g_strerror (errno)));
+        }
+      }
+
+      if (sink->used_socket_v6) {
+        ret =
+            setsockopt (g_socket_get_fd (sink->used_socket_v6), SOL_SOCKET,
+            SO_SNDBUF, (void *) &sndsize, len);
+        if (ret != 0) {
+          GST_ELEMENT_WARNING (sink, RESOURCE, SETTINGS, (NULL),
+              ("Could not create a buffer of requested %d bytes, %d: %s",
+                  sndsize, ret, g_strerror (errno)));
+        }
+      }
+    }
+
+    /* read the value of the receive buffer. Note that on linux this returns 2x the
+     * value we set because the kernel allocates extra memory for metadata.
+     * The default on Linux is about 100K (which is about 50K without metadata) */
+    if (sink->used_socket) {
+      ret =
+          getsockopt (g_socket_get_fd (sink->used_socket), SOL_SOCKET,
+          SO_SNDBUF, (void *) &sndsize, &len);
+      if (ret == 0)
+        GST_DEBUG_OBJECT (sink, "have UDP buffer of %d bytes", sndsize);
+      else
+        GST_DEBUG_OBJECT (sink, "could not get UDP buffer size");
+    }
+
+    if (sink->used_socket_v6) {
+      ret =
+          getsockopt (g_socket_get_fd (sink->used_socket_v6), SOL_SOCKET,
+          SO_SNDBUF, (void *) &sndsize, &len);
+      if (ret == 0)
+        GST_DEBUG_OBJECT (sink, "have UDPv6 buffer of %d bytes", sndsize);
+      else
+        GST_DEBUG_OBJECT (sink, "could not get UDPv6 buffer size");
+    }
+  }
+#endif
+
+#ifdef SO_BINDTODEVICE
+  if (sink->multi_iface) {
+    if (sink->used_socket) {
+      if (setsockopt (g_socket_get_fd (sink->used_socket), SOL_SOCKET,
+              SO_BINDTODEVICE, sink->multi_iface,
+              strlen (sink->multi_iface)) < 0)
+        GST_WARNING_OBJECT (sink, "setsockopt SO_BINDTODEVICE failed: %s",
+            strerror (errno));
+    }
+    if (sink->used_socket_v6) {
+      if (setsockopt (g_socket_get_fd (sink->used_socket_v6), SOL_SOCKET,
+              SO_BINDTODEVICE, sink->multi_iface,
+              strlen (sink->multi_iface)) < 0)
+        GST_WARNING_OBJECT (sink, "setsockopt SO_BINDTODEVICE failed (v6): %s",
+            strerror (errno));
+    }
+  }
+#endif
+
+  if (sink->used_socket)
+    g_socket_set_broadcast (sink->used_socket, TRUE);
+  if (sink->used_socket_v6)
+    g_socket_set_broadcast (sink->used_socket_v6, TRUE);
+
+  sink->bytes_to_serve = 0;
+  sink->bytes_served = 0;
+
+  gst_multiudpsink_setup_qos_dscp (sink, sink->used_socket);
+  gst_multiudpsink_setup_qos_dscp (sink, sink->used_socket_v6);
+
+  /* look for multicast clients and join multicast groups appropriately
+     set also ttl and multicast loopback delivery appropriately  */
+  for (clients = sink->clients; clients; clients = g_list_next (clients)) {
+    client = (GstUDPClient *) clients->data;
+
+    if (!gst_multiudpsink_configure_client (sink, client))
+      return FALSE;
+  }
+  return TRUE;
+
+  /* ERRORS */
+no_socket:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (NULL),
+        ("Could not create socket: %s", err->message));
+    g_clear_error (&err);
+    return FALSE;
+  }
+bind_error:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (NULL),
+        ("Failed to bind socket: %s", err->message));
+    g_clear_error (&err);
+    return FALSE;
+  }
+name_resolve:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (NULL),
+        ("Failed to resolve bind address %s: %s", sink->bind_address,
+            err->message));
+    g_clear_error (&err);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_multiudpsink_stop (GstBaseSink * bsink)
+{
+  GstMultiUDPSink *udpsink;
+
+  udpsink = GST_MULTIUDPSINK (bsink);
+
+  if (udpsink->used_socket) {
+    if (udpsink->close_socket || !udpsink->external_socket) {
+      GError *err = NULL;
+
+      if (!g_socket_close (udpsink->used_socket, &err)) {
+        GST_ERROR_OBJECT (udpsink, "Failed to close socket: %s", err->message);
+        g_clear_error (&err);
+      }
+    }
+
+    g_object_unref (udpsink->used_socket);
+    udpsink->used_socket = NULL;
+  }
+
+  if (udpsink->used_socket_v6) {
+    if (udpsink->close_socket || !udpsink->external_socket) {
+      GError *err = NULL;
+
+      if (!g_socket_close (udpsink->used_socket_v6, &err)) {
+        GST_ERROR_OBJECT (udpsink, "Failed to close socket: %s", err->message);
+        g_clear_error (&err);
+      }
+    }
+
+    g_object_unref (udpsink->used_socket_v6);
+    udpsink->used_socket_v6 = NULL;
+  }
+
+  return TRUE;
+}
+
+static gint
+gst_udp_client_compare_socket_family (GstUDPClient * a, GstUDPClient * b)
+{
+  GSocketFamily fa = g_socket_address_get_family (a->addr);
+  GSocketFamily fb = g_socket_address_get_family (b->addr);
+
+  if (fa == fb)
+    return 0;
+
+  /* a should go before b */
+  if (fa == G_SOCKET_FAMILY_IPV4 && fb == G_SOCKET_FAMILY_IPV6)
+    return -1;
+
+  /* b should go before a */
+  return 1;
+}
+
+static void
+gst_multiudpsink_add_internal (GstMultiUDPSink * sink, const gchar * host,
+    gint port, gboolean lock)
+{
+  GSocketFamily family;
+  GstUDPClient *client;
+  GstUDPClient udpclient;
+  GTimeVal now;
+  GList *find;
+
+  udpclient.host = (gchar *) host;
+  udpclient.port = port;
+
+  GST_DEBUG_OBJECT (sink, "adding client on host %s, port %d", host, port);
+
+  if (lock)
+    g_mutex_lock (&sink->client_lock);
+
+  find = g_list_find_custom (sink->clients, &udpclient,
+      (GCompareFunc) client_compare);
+
+  if (!find) {
+    find = g_list_find_custom (sink->clients_to_be_removed, &udpclient,
+        (GCompareFunc) client_compare);
+    if (find)
+      gst_udp_client_ref (find->data);
+  }
+
+  if (find) {
+    client = (GstUDPClient *) find->data;
+
+    family = g_socket_address_get_family (client->addr);
+
+    GST_DEBUG_OBJECT (sink, "found %d existing clients with host %s, port %d",
+        client->add_count, host, port);
+  } else {
+    client = gst_udp_client_new (sink, host, port);
+    if (!client)
+      goto error;
+
+    family = g_socket_address_get_family (client->addr);
+
+    g_get_current_time (&now);
+    client->connect_time = GST_TIMEVAL_TO_TIME (now);
+
+    if (sink->used_socket)
+      gst_multiudpsink_configure_client (sink, client);
+
+    GST_DEBUG_OBJECT (sink, "add client with host %s, port %d", host, port);
+
+    /* keep IPv4 clients at the beginning, and IPv6 at the end, we can make
+     * use of this in gst_multiudpsink_render_buffers() */
+    sink->clients = g_list_insert_sorted (sink->clients, client,
+        (GCompareFunc) gst_udp_client_compare_socket_family);
+
+    if (family == G_SOCKET_FAMILY_IPV4)
+      ++sink->num_v4_unique;
+    else
+      ++sink->num_v6_unique;
+  }
+
+  ++client->add_count;
+
+  if (family == G_SOCKET_FAMILY_IPV4)
+    ++sink->num_v4_all;
+  else
+    ++sink->num_v6_all;
+
+  if (lock)
+    g_mutex_unlock (&sink->client_lock);
+
+  g_signal_emit (G_OBJECT (sink),
+      gst_multiudpsink_signals[SIGNAL_CLIENT_ADDED], 0, host, port);
+
+  GST_DEBUG_OBJECT (sink, "added client on host %s, port %d", host, port);
+  return;
+
+  /* ERRORS */
+error:
+  {
+    GST_DEBUG_OBJECT (sink, "did not add client on host %s, port %d", host,
+        port);
+    if (lock)
+      g_mutex_unlock (&sink->client_lock);
+    return;
+  }
+}
+
+void
+gst_multiudpsink_add (GstMultiUDPSink * sink, const gchar * host, gint port)
+{
+  gst_multiudpsink_add_internal (sink, host, port, TRUE);
+}
+
+void
+gst_multiudpsink_remove (GstMultiUDPSink * sink, const gchar * host, gint port)
+{
+  GSocketFamily family;
+  GList *find;
+  GstUDPClient udpclient;
+  GstUDPClient *client;
+  GTimeVal now;
+
+  udpclient.host = (gchar *) host;
+  udpclient.port = port;
+
+  g_mutex_lock (&sink->client_lock);
+  find = g_list_find_custom (sink->clients, &udpclient,
+      (GCompareFunc) client_compare);
+  if (!find)
+    goto not_found;
+
+  client = (GstUDPClient *) find->data;
+
+  GST_DEBUG_OBJECT (sink, "found %d clients with host %s, port %d",
+      client->add_count, host, port);
+
+  --client->add_count;
+
+  family = g_socket_address_get_family (client->addr);
+  if (family == G_SOCKET_FAMILY_IPV4)
+    --sink->num_v4_all;
+  else
+    --sink->num_v6_all;
+
+  if (client->add_count == 0) {
+    GInetSocketAddress *saddr = G_INET_SOCKET_ADDRESS (client->addr);
+    GInetAddress *addr = g_inet_socket_address_get_address (saddr);
+    GSocket *socket;
+
+    /* Select socket to send from for this address */
+    if (family == G_SOCKET_FAMILY_IPV6 || !sink->used_socket)
+      socket = sink->used_socket_v6;
+    else
+      socket = sink->used_socket;
+
+    GST_DEBUG_OBJECT (sink, "remove client with host %s, port %d", host, port);
+
+    g_get_current_time (&now);
+    client->disconnect_time = GST_TIMEVAL_TO_TIME (now);
+
+    if (socket && sink->auto_multicast
+        && g_inet_address_get_is_multicast (addr)) {
+      GError *err = NULL;
+
+      if (!g_socket_leave_multicast_group (socket, addr, FALSE,
+              sink->multi_iface, &err)) {
+        GST_DEBUG_OBJECT (sink, "Failed to leave multicast group: %s",
+            err->message);
+        g_clear_error (&err);
+      }
+    }
+
+    if (family == G_SOCKET_FAMILY_IPV4)
+      --sink->num_v4_unique;
+    else
+      --sink->num_v6_unique;
+
+    /* Keep state consistent for streaming thread, so remove from client list,
+     * but keep it around until after the signal has been emitted, in case a
+     * callback wants to get stats for that client or so */
+    sink->clients = g_list_delete_link (sink->clients, find);
+
+    sink->clients_to_be_removed =
+        g_list_prepend (sink->clients_to_be_removed, client);
+
+    /* Unlock to emit signal before we delete the actual client */
+    g_mutex_unlock (&sink->client_lock);
+    g_signal_emit (G_OBJECT (sink),
+        gst_multiudpsink_signals[SIGNAL_CLIENT_REMOVED], 0, host, port);
+    g_mutex_lock (&sink->client_lock);
+
+    sink->clients_to_be_removed =
+        g_list_remove (sink->clients_to_be_removed, client);
+
+    gst_udp_client_unref (client);
+  }
+  g_mutex_unlock (&sink->client_lock);
+
+  return;
+
+  /* ERRORS */
+not_found:
+  {
+    g_mutex_unlock (&sink->client_lock);
+    GST_WARNING_OBJECT (sink, "client at host %s, port %d not found",
+        host, port);
+    return;
+  }
+}
+
+static void
+gst_multiudpsink_clear_internal (GstMultiUDPSink * sink, gboolean lock)
+{
+  GST_DEBUG_OBJECT (sink, "clearing");
+  /* we only need to remove the client structure, there is no additional
+   * socket or anything to free for UDP */
+  if (lock)
+    g_mutex_lock (&sink->client_lock);
+  g_list_foreach (sink->clients, (GFunc) gst_udp_client_unref, sink);
+  g_list_free (sink->clients);
+  sink->clients = NULL;
+  sink->num_v4_unique = 0;
+  sink->num_v4_all = 0;
+  sink->num_v6_unique = 0;
+  sink->num_v6_all = 0;
+  if (lock)
+    g_mutex_unlock (&sink->client_lock);
+}
+
+void
+gst_multiudpsink_clear (GstMultiUDPSink * sink)
+{
+  gst_multiudpsink_clear_internal (sink, TRUE);
+}
+
+GstStructure *
+gst_multiudpsink_get_stats (GstMultiUDPSink * sink, const gchar * host,
+    gint port)
+{
+  GstUDPClient *client;
+  GstStructure *result = NULL;
+  GstUDPClient udpclient;
+  GList *find;
+
+  udpclient.host = (gchar *) host;
+  udpclient.port = port;
+
+  g_mutex_lock (&sink->client_lock);
+
+  find = g_list_find_custom (sink->clients, &udpclient,
+      (GCompareFunc) client_compare);
+
+  if (!find)
+    find = g_list_find_custom (sink->clients_to_be_removed, &udpclient,
+        (GCompareFunc) client_compare);
+
+  if (!find)
+    goto not_found;
+
+  GST_DEBUG_OBJECT (sink, "stats for client with host %s, port %d", host, port);
+
+  client = (GstUDPClient *) find->data;
+
+  result = gst_structure_new_empty ("multiudpsink-stats");
+
+  gst_structure_set (result,
+      "bytes-sent", G_TYPE_UINT64, client->bytes_sent,
+      "packets-sent", G_TYPE_UINT64, client->packets_sent,
+      "connect-time", G_TYPE_UINT64, client->connect_time,
+      "disconnect-time", G_TYPE_UINT64, client->disconnect_time, NULL);
+
+  g_mutex_unlock (&sink->client_lock);
+
+  return result;
+
+  /* ERRORS */
+not_found:
+  {
+    g_mutex_unlock (&sink->client_lock);
+    GST_WARNING_OBJECT (sink, "client with host %s, port %d not found",
+        host, port);
+    /* Apparently (see comment in gstmultifdsink.c) returning NULL from here may
+     * confuse/break python bindings */
+    return gst_structure_new_empty ("multiudpsink-stats");
+  }
+}
+
+static gboolean
+gst_multiudpsink_unlock (GstBaseSink * bsink)
+{
+  GstMultiUDPSink *sink;
+
+  sink = GST_MULTIUDPSINK (bsink);
+
+  g_cancellable_cancel (sink->cancellable);
+
+  return TRUE;
+}
+
+static gboolean
+gst_multiudpsink_unlock_stop (GstBaseSink * bsink)
+{
+  GstMultiUDPSink *sink;
+
+  sink = GST_MULTIUDPSINK (bsink);
+
+  gst_multiudpsink_free_cancellable (sink);
+  gst_multiudpsink_create_cancellable (sink);
+
+  return TRUE;
+}
diff --git a/gst/udp/gstmultiudpsink.h b/gst/udp/gstmultiudpsink.h
new file mode 100644
index 0000000..8849f38
--- /dev/null
+++ b/gst/udp/gstmultiudpsink.h
@@ -0,0 +1,150 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MULTIUDPSINK_H__
+#define __GST_MULTIUDPSINK_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesink.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#include "gstudpnetutils.h"
+
+#define GST_TYPE_MULTIUDPSINK            (gst_multiudpsink_get_type())
+#define GST_MULTIUDPSINK(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULTIUDPSINK,GstMultiUDPSink))
+#define GST_MULTIUDPSINK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULTIUDPSINK,GstMultiUDPSinkClass))
+#define GST_IS_MULTIUDPSINK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULTIUDPSINK))
+#define GST_IS_MULTIUDPSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULTIUDPSINK))
+#define GST_MULTIUDPSINK_CAST(obj)       ((GstMultiUDPSink*)(obj))
+
+typedef struct _GstMultiUDPSink GstMultiUDPSink;
+typedef struct _GstMultiUDPSinkClass GstMultiUDPSinkClass;
+
+#if GLIB_CHECK_VERSION (2, 43, 2)
+#define HAVE_G_SOCKET_SEND_MESSAGES
+#endif
+
+#ifndef HAVE_G_SOCKET_SEND_MESSAGES
+/* same as GOutputMessage used for g_socket_send_messages() */
+typedef struct {
+  /*< private >*/
+  GSocketAddress         *address;
+
+  GOutputVector          *vectors;
+  guint                   num_vectors;
+
+  guint                   bytes_sent;
+
+  GSocketControlMessage **control_messages;
+  guint                   num_control_messages;
+} GstOutputMessage;
+#else
+typedef GOutputMessage GstOutputMessage;
+#endif /* HAVE_G_SOCKET_SEND_MESSAGES*/
+
+typedef struct {
+  gint ref_count;         /* for memory management */
+  gint add_count;         /* how often this address has been added */
+
+  GSocketAddress *addr;
+  gchar *host;
+  gint port;
+
+  /* Per-client stats */
+  guint64 bytes_sent;
+  guint64 packets_sent;
+  guint64 connect_time;
+  guint64 disconnect_time;
+} GstUDPClient;
+
+/* sends udp packets to multiple host/port pairs.
+ */
+struct _GstMultiUDPSink {
+  GstBaseSink parent;
+
+  GSocket       *used_socket, *used_socket_v6;
+
+  GCancellable  *cancellable;
+  gboolean       made_cancel_fd;
+
+  /* client management */
+  GMutex         client_lock;
+  GList         *clients;
+  guint          num_v4_unique;  /* number IPv4 clients (excluding duplicates) */
+  guint          num_v4_all;     /* number IPv4 clients (including duplicates) */
+  guint          num_v6_unique;  /* number IPv6 clients (excluding duplicates) */
+  guint          num_v6_all;     /* number IPv6 clients (including duplicates) */
+  GList         *clients_to_be_removed;
+
+  /* pre-allocated scrap space for render function */
+  GOutputVector    *vecs;
+  guint             n_vecs;
+  GstMapInfo       *maps;
+  guint             n_maps;
+  GstOutputMessage *messages;
+  guint             n_messages;
+
+  /* properties */
+  guint64        bytes_to_serve;
+  guint64        bytes_served;
+  GSocket       *socket, *socket_v6;
+  gboolean       close_socket;
+
+  gboolean       external_socket;
+
+  gboolean       auto_multicast;
+  gchar         *multi_iface;
+  gint           ttl;
+  gint           ttl_mc;
+  gboolean       loop;
+  gboolean       force_ipv4;
+  gint           qos_dscp;
+
+  gboolean       send_duplicates;
+  gint           buffer_size;
+  gchar         *bind_address;
+  gint           bind_port;
+};
+
+struct _GstMultiUDPSinkClass {
+  GstBaseSinkClass parent_class;
+
+  /* element methods */
+  void          (*add)          (GstMultiUDPSink *sink, const gchar *host, gint port);
+  void          (*remove)       (GstMultiUDPSink *sink, const gchar *host, gint port);
+  void          (*clear)        (GstMultiUDPSink *sink);
+  GstStructure* (*get_stats)    (GstMultiUDPSink *sink, const gchar *host, gint port);
+
+  /* signals */
+  void          (*client_added) (GstElement *element, const gchar *host, gint port);
+  void          (*client_removed) (GstElement *element, const gchar *host, gint port);
+};
+
+GType gst_multiudpsink_get_type(void);
+
+void            gst_multiudpsink_add            (GstMultiUDPSink *sink, const gchar *host, gint port);
+void            gst_multiudpsink_remove         (GstMultiUDPSink *sink, const gchar *host, gint port);
+void            gst_multiudpsink_clear          (GstMultiUDPSink *sink);
+GstStructure*   gst_multiudpsink_get_stats      (GstMultiUDPSink *sink, const gchar *host, gint port);
+
+G_END_DECLS
+
+#endif /* __GST_MULTIUDPSINK_H__ */
diff --git a/gst/udp/gstudp.c b/gst/udp/gstudp.c
new file mode 100644
index 0000000..eb02112
--- /dev/null
+++ b/gst/udp/gstudp.c
@@ -0,0 +1,67 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/net/gstnetaddressmeta.h>
+
+#include "gstudpsrc.h"
+#include "gstmultiudpsink.h"
+#include "gstudpsink.h"
+#include "gstdynudpsink.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  /* not using GLIB_CHECK_VERSION on purpose, run-time version matters */
+  if (glib_check_version (2, 36, 0) != NULL) {
+    GST_WARNING ("Your GLib version is < 2.36, UDP multicasting support may "
+        "be broken, see https://bugzilla.gnome.org/show_bug.cgi?id=688378");
+  }
+
+  /* register info of the netaddress metadata so that we can use it from
+   * multiple threads right away. Note that the plugin loading is always
+   * serialized */
+  gst_net_address_meta_get_info ();
+
+  if (!gst_element_register (plugin, "udpsink", GST_RANK_NONE,
+          GST_TYPE_UDPSINK))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "multiudpsink", GST_RANK_NONE,
+          GST_TYPE_MULTIUDPSINK))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "dynudpsink", GST_RANK_NONE,
+          GST_TYPE_DYNUDPSINK))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "udpsrc", GST_RANK_NONE, GST_TYPE_UDPSRC))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    udp,
+    "transfer data via UDP",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/udp/gstudpnetutils.c b/gst/udp/gstudpnetutils.c
new file mode 100644
index 0000000..b4dc5ef
--- /dev/null
+++ b/gst/udp/gstudpnetutils.c
@@ -0,0 +1,108 @@
+/* GStreamer UDP network utility functions
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2006 Joni Valtanen <joni.valtanen@movial.fi>
+ * Copyright (C) 2009 Jarkko Palviainen <jarkko.palviainen@sesca.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <string.h>
+
+#include "gstudpnetutils.h"
+
+gboolean
+gst_udp_parse_uri (const gchar * uristr, gchar ** host, guint16 * port)
+{
+  gchar *protocol, *location_start;
+  gchar *location, *location_end;
+  gchar *colptr;
+
+  /* consider no protocol to be udp:// */
+  protocol = gst_uri_get_protocol (uristr);
+  if (!protocol)
+    goto no_protocol;
+  if (strcmp (protocol, "udp") != 0)
+    goto wrong_protocol;
+  g_free (protocol);
+
+  location_start = gst_uri_get_location (uristr);
+  if (!location_start)
+    return FALSE;
+
+  GST_DEBUG ("got location '%s'", location_start);
+
+  /* VLC compatibility, strip everything before the @ sign. VLC uses that as the
+   * remote address. */
+  location = g_strstr_len (location_start, -1, "@");
+  if (location == NULL)
+    location = location_start;
+  else
+    location += 1;
+
+  if (location[0] == '[') {
+    GST_DEBUG ("parse IPV6 address '%s'", location);
+    location_end = strchr (location, ']');
+    if (location_end == NULL)
+      goto wrong_address;
+
+    *host = g_strndup (location + 1, location_end - location - 1);
+    colptr = strrchr (location_end, ':');
+  } else {
+    GST_DEBUG ("parse IPV4 address '%s'", location);
+    colptr = strrchr (location, ':');
+
+    if (colptr != NULL) {
+      *host = g_strndup (location, colptr - location);
+    } else {
+      *host = g_strdup (location);
+    }
+  }
+  GST_DEBUG ("host set to '%s'", *host);
+
+  if (colptr != NULL) {
+    *port = g_ascii_strtoll (colptr + 1, NULL, 10);
+  } else {
+    *port = 0;
+  }
+  g_free (location_start);
+
+  return TRUE;
+
+  /* ERRORS */
+no_protocol:
+  {
+    GST_ERROR ("error parsing uri %s: no protocol", uristr);
+    return FALSE;
+  }
+wrong_protocol:
+  {
+    GST_ERROR ("error parsing uri %s: wrong protocol (%s != udp)", uristr,
+        protocol);
+    g_free (protocol);
+    return FALSE;
+  }
+wrong_address:
+  {
+    GST_ERROR ("error parsing uri %s", uristr);
+    g_free (location);
+    return FALSE;
+  }
+}
diff --git a/gst/udp/gstudpnetutils.h b/gst/udp/gstudpnetutils.h
new file mode 100644
index 0000000..a62be56
--- /dev/null
+++ b/gst/udp/gstudpnetutils.h
@@ -0,0 +1,29 @@
+/* GStreamer UDP network utility functions
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2006 Joni Valtanen <joni.valtanen@movial.fi>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/gst.h>
+
+#ifndef __GST_UDP_NET_UTILS_H__
+#define __GST_UDP_NET_UTILS_H__
+
+gboolean     gst_udp_parse_uri            (const gchar *uristr, gchar **host, guint16 *port);
+
+#endif /* __GST_UDP_NET_UTILS_H__*/
+
diff --git a/gst/udp/gstudpsink.c b/gst/udp/gstudpsink.c
new file mode 100644
index 0000000..224d578
--- /dev/null
+++ b/gst/udp/gstudpsink.c
@@ -0,0 +1,259 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim@fluendo.com>
+ * Copyright (C) <2012> Collabora Ltd.
+ *   Author: Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-udpsink
+ * @see_also: udpsrc, multifdsink
+ *
+ * udpsink is a network sink that sends UDP packets to the network.
+ * It can be combined with RTP payloaders to implement RTP streaming.
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! udpsink
+ * ]|
+ * </refsect2>
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "gstudpsink.h"
+
+#define UDP_DEFAULT_HOST        "localhost"
+#define UDP_DEFAULT_PORT        5004
+
+/* UDPSink signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_HOST,
+  PROP_PORT,
+  PROP_URI,
+  /* FILL ME */
+};
+
+static void gst_udpsink_finalize (GstUDPSink * udpsink);
+
+static void gst_udpsink_uri_handler_init (gpointer g_iface,
+    gpointer iface_data);
+
+static void gst_udpsink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_udpsink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+/*static guint gst_udpsink_signals[LAST_SIGNAL] = { 0 }; */
+#define gst_udpsink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstUDPSink, gst_udpsink, GST_TYPE_MULTIUDPSINK,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_udpsink_uri_handler_init));
+
+static void
+gst_udpsink_class_init (GstUDPSinkClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_udpsink_set_property;
+  gobject_class->get_property = gst_udpsink_get_property;
+
+  gobject_class->finalize = (GObjectFinalizeFunc) gst_udpsink_finalize;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HOST,
+      g_param_spec_string ("host", "host",
+          "The host/IP/Multicast group to send the packets to",
+          UDP_DEFAULT_HOST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PORT,
+      g_param_spec_int ("port", "port", "The port to send the packets to",
+          0, 65535, UDP_DEFAULT_PORT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class, "UDP packet sender",
+      "Sink/Network",
+      "Send data over the network via UDP", "Wim Taymans <wim@fluendo.com>");
+}
+
+static void
+gst_udpsink_init (GstUDPSink * udpsink)
+{
+  udpsink->host = g_strdup (UDP_DEFAULT_HOST);
+  udpsink->port = UDP_DEFAULT_PORT;
+  udpsink->uri = g_strdup_printf ("udp://%s:%d", udpsink->host, udpsink->port);
+
+  gst_multiudpsink_add (GST_MULTIUDPSINK (udpsink), udpsink->host,
+      udpsink->port);
+}
+
+static void
+gst_udpsink_finalize (GstUDPSink * udpsink)
+{
+  g_free (udpsink->host);
+  udpsink->host = NULL;
+
+  g_free (udpsink->uri);
+  udpsink->uri = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize ((GObject *) udpsink);
+}
+
+static gboolean
+gst_udpsink_set_uri (GstUDPSink * sink, const gchar * uri, GError ** error)
+{
+  gchar *host;
+  guint16 port;
+
+  gst_multiudpsink_remove (GST_MULTIUDPSINK (sink), sink->host, sink->port);
+
+  if (!gst_udp_parse_uri (uri, &host, &port))
+    goto wrong_uri;
+
+  g_free (sink->host);
+  sink->host = host;
+  sink->port = port;
+
+  g_free (sink->uri);
+  sink->uri = g_strdup (uri);
+
+  gst_multiudpsink_add (GST_MULTIUDPSINK (sink), sink->host, sink->port);
+
+  return TRUE;
+
+  /* ERRORS */
+wrong_uri:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, READ, (NULL),
+        ("error parsing uri %s", uri));
+    g_set_error_literal (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
+        "Could not parse UDP URI");
+    return FALSE;
+  }
+}
+
+static void
+gst_udpsink_set_property (GObject * object, guint prop_id, const GValue * value,
+    GParamSpec * pspec)
+{
+  GstUDPSink *udpsink;
+
+  udpsink = GST_UDPSINK (object);
+
+  /* remove old host */
+  gst_multiudpsink_remove (GST_MULTIUDPSINK (udpsink),
+      udpsink->host, udpsink->port);
+
+  switch (prop_id) {
+    case PROP_HOST:
+    {
+      const gchar *host;
+
+      host = g_value_get_string (value);
+      g_free (udpsink->host);
+      udpsink->host = g_strdup (host);
+      g_free (udpsink->uri);
+      udpsink->uri =
+          g_strdup_printf ("udp://%s:%d", udpsink->host, udpsink->port);
+      break;
+    }
+    case PROP_PORT:
+      udpsink->port = g_value_get_int (value);
+      g_free (udpsink->uri);
+      udpsink->uri =
+          g_strdup_printf ("udp://%s:%d", udpsink->host, udpsink->port);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  /* add new host */
+  gst_multiudpsink_add (GST_MULTIUDPSINK (udpsink),
+      udpsink->host, udpsink->port);
+}
+
+static void
+gst_udpsink_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstUDPSink *udpsink;
+
+  udpsink = GST_UDPSINK (object);
+
+  switch (prop_id) {
+    case PROP_HOST:
+      g_value_set_string (value, udpsink->host);
+      break;
+    case PROP_PORT:
+      g_value_set_int (value, udpsink->port);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/*** GSTURIHANDLER INTERFACE *************************************************/
+
+static GstURIType
+gst_udpsink_uri_get_type (GType type)
+{
+  return GST_URI_SINK;
+}
+
+static const gchar *const *
+gst_udpsink_uri_get_protocols (GType type)
+{
+  static const gchar *protocols[] = { "udp", NULL };
+
+  return protocols;
+}
+
+static gchar *
+gst_udpsink_uri_get_uri (GstURIHandler * handler)
+{
+  GstUDPSink *sink = GST_UDPSINK (handler);
+
+  return g_strdup (sink->uri);
+}
+
+static gboolean
+gst_udpsink_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+    GError ** error)
+{
+  return gst_udpsink_set_uri (GST_UDPSINK (handler), uri, error);
+}
+
+static void
+gst_udpsink_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+  iface->get_type = gst_udpsink_uri_get_type;
+  iface->get_protocols = gst_udpsink_uri_get_protocols;
+  iface->get_uri = gst_udpsink_uri_get_uri;
+  iface->set_uri = gst_udpsink_uri_set_uri;
+}
diff --git a/gst/udp/gstudpsink.h b/gst/udp/gstudpsink.h
new file mode 100644
index 0000000..a7b5b34
--- /dev/null
+++ b/gst/udp/gstudpsink.h
@@ -0,0 +1,57 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_UDPSINK_H__
+#define __GST_UDPSINK_H__
+
+#include <gst/gst.h>
+#include "gstmultiudpsink.h"
+
+G_BEGIN_DECLS
+
+#include "gstudpnetutils.h"
+
+#define GST_TYPE_UDPSINK                (gst_udpsink_get_type())
+#define GST_UDPSINK(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_UDPSINK,GstUDPSink))
+#define GST_UDPSINK_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_UDPSINK,GstUDPSinkClass))
+#define GST_IS_UDPSINK(obj)             (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_UDPSINK))
+#define GST_IS_UDPSINK_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_UDPSINK))
+
+typedef struct _GstUDPSink GstUDPSink;
+typedef struct _GstUDPSinkClass GstUDPSinkClass;
+
+struct _GstUDPSink {
+  GstMultiUDPSink parent;
+
+  gchar *host;
+  guint16 port;
+
+  gchar *uri;
+};
+
+struct _GstUDPSinkClass {
+  GstMultiUDPSinkClass parent_class;
+};
+
+GType gst_udpsink_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_UDPSINK_H__ */
diff --git a/gst/udp/gstudpsrc.c b/gst/udp/gstudpsrc.c
new file mode 100644
index 0000000..fdeca5d
--- /dev/null
+++ b/gst/udp/gstudpsrc.c
@@ -0,0 +1,1762 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim@fluendo.com>
+ * Copyright (C) <2005> Nokia Corporation <kai.vehmanen@nokia.com>
+ * Copyright (C) <2012> Collabora Ltd.
+ *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ * Copyright (C) 2014 Tim-Philipp Müller <tim@centricular.com>
+ * Copyright (C) 2014 Centricular Ltd
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-udpsrc
+ * @see_also: udpsink, multifdsink
+ *
+ * udpsrc is a network source that reads UDP packets from the network.
+ * It can be combined with RTP depayloaders to implement RTP streaming.
+ *
+ * The udpsrc element supports automatic port allocation by setting the
+ * #GstUDPSrc:port property to 0. After setting the udpsrc to PAUSED, the
+ * allocated port can be obtained by reading the port property.
+ *
+ * udpsrc can read from multicast groups by setting the #GstUDPSrc:multicast-group
+ * property to the IP address of the multicast group.
+ *
+ * Alternatively one can provide a custom socket to udpsrc with the #GstUDPSrc:socket
+ * property, udpsrc will then not allocate a socket itself but use the provided
+ * one.
+ *
+ * The #GstUDPSrc:caps property is mainly used to give a type to the UDP packet
+ * so that they can be autoplugged in GStreamer pipelines. This is very useful
+ * for RTP implementations where the contents of the UDP packets is transfered
+ * out-of-bounds using SDP or other means.
+ *
+ * The #GstUDPSrc:buffer-size property is used to change the default kernel
+ * buffersizes used for receiving packets. The buffer size may be increased for
+ * high-volume connections, or may be decreased to limit the possible backlog of
+ * incoming data. The system places an absolute limit on these values, on Linux,
+ * for example, the default buffer size is typically 50K and can be increased to
+ * maximally 100K.
+ *
+ * The #GstUDPSrc:skip-first-bytes property is used to strip off an arbitrary
+ * number of bytes from the start of the raw udp packet and can be used to strip
+ * off proprietary header, for example.
+ *
+ * The udpsrc is always a live source. It does however not provide a #GstClock,
+ * this is left for downstream elements such as an RTP session manager or demuxer
+ * (such as an MPEG demuxer). As with all live sources, the captured buffers
+ * will have their timestamp set to the current running time of the pipeline.
+ *
+ * udpsrc implements a #GstURIHandler interface that handles udp://host:port
+ * type URIs.
+ *
+ * If the #GstUDPSrc:timeout property is set to a value bigger than 0, udpsrc
+ * will generate an element message named
+ * <classname>&quot;GstUDPSrcTimeout&quot;</classname>
+ * if no data was recieved in the given timeout.
+ * The message's structure contains one field:
+ * <itemizedlist>
+ * <listitem>
+ *   <para>
+ *   #guint64
+ *   <classname>&quot;timeout&quot;</classname>: the timeout in microseconds that
+ *   expired when waiting for data.
+ *   </para>
+ * </listitem>
+ * </itemizedlist>
+ * The message is typically used to detect that no UDP arrives in the receiver
+ * because it is blocked by a firewall.
+ *
+ * A custom file descriptor can be configured with the
+ * #GstUDPSrc:socket property. The socket will be closed when setting
+ * the element to READY by default. This behaviour can be overriden
+ * with the #GstUDPSrc:close-socket property, in which case the
+ * application is responsible for closing the file descriptor.
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch-1.0 -v udpsrc ! fakesink dump=1
+ * ]| A pipeline to read from the default port and dump the udp packets.
+ * To actually generate udp packets on the default port one can use the
+ * udpsink element. When running the following pipeline in another terminal, the
+ * above mentioned pipeline should dump data packets to the console.
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! udpsink
+ * ]|
+ * |[
+ * gst-launch-1.0 -v udpsrc port=0 ! fakesink
+ * ]| read udp packets from a free port.
+ * </refsect2>
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Needed to get struct in6_pktinfo.
+ * Also all these have to be before glib.h is included as
+ * otherwise struct in6_pktinfo is not defined completely
+ * due to broken glibc headers */
+#define _GNU_SOURCE
+/* Needed for OSX/iOS to define the IPv6 variants */
+#define __APPLE_USE_RFC_3542
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#include <string.h>
+#include "gstudpsrc.h"
+
+#include <gst/net/gstnetaddressmeta.h>
+
+#include <gio/gnetworking.h>
+
+/* Required for other parts of in_pktinfo / in6_pktinfo but only
+ * on non-Windows and can be included after glib.h */
+#ifndef G_PLATFORM_WIN32
+#include <netinet/ip.h>
+#endif
+
+/* Control messages for getting the destination address */
+#ifdef IP_PKTINFO
+GType gst_ip_pktinfo_message_get_type (void);
+
+#define GST_TYPE_IP_PKTINFO_MESSAGE         (gst_ip_pktinfo_message_get_type ())
+#define GST_IP_PKTINFO_MESSAGE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GST_TYPE_IP_PKTINFO_MESSAGE, GstIPPktinfoMessage))
+#define GST_IP_PKTINFO_MESSAGE_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c), GST_TYPE_IP_PKTINFO_MESSAGE, GstIPPktinfoMessageClass))
+#define GST_IS_IP_PKTINFO_MESSAGE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GST_TYPE_IP_PKTINFO_MESSAGE))
+#define GST_IS_IP_PKTINFO_MESSAGE_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c), GST_TYPE_IP_PKTINFO_MESSAGE))
+#define GST_IP_PKTINFO_MESSAGE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GST_TYPE_IP_PKTINFO_MESSAGE, GstIPPktinfoMessageClass))
+
+typedef struct _GstIPPktinfoMessage GstIPPktinfoMessage;
+typedef struct _GstIPPktinfoMessageClass GstIPPktinfoMessageClass;
+
+struct _GstIPPktinfoMessageClass
+{
+  GSocketControlMessageClass parent_class;
+
+};
+
+struct _GstIPPktinfoMessage
+{
+  GSocketControlMessage parent;
+
+  guint ifindex;
+#ifndef G_PLATFORM_WIN32
+#ifndef __NetBSD__
+  struct in_addr spec_dst;
+#endif
+#endif
+  struct in_addr addr;
+};
+
+G_DEFINE_TYPE (GstIPPktinfoMessage, gst_ip_pktinfo_message,
+    G_TYPE_SOCKET_CONTROL_MESSAGE);
+
+static gsize
+gst_ip_pktinfo_message_get_size (GSocketControlMessage * message)
+{
+  return sizeof (struct in_pktinfo);
+}
+
+static int
+gst_ip_pktinfo_message_get_level (GSocketControlMessage * message)
+{
+  return IPPROTO_IP;
+}
+
+static int
+gst_ip_pktinfo_message_get_msg_type (GSocketControlMessage * message)
+{
+  return IP_PKTINFO;
+}
+
+static GSocketControlMessage *
+gst_ip_pktinfo_message_deserialize (gint level,
+    gint type, gsize size, gpointer data)
+{
+  struct in_pktinfo *pktinfo;
+  GstIPPktinfoMessage *message;
+
+  if (level != IPPROTO_IP || type != IP_PKTINFO)
+    return NULL;
+
+  if (size < sizeof (struct in_pktinfo))
+    return NULL;
+
+  pktinfo = data;
+
+  message = g_object_new (GST_TYPE_IP_PKTINFO_MESSAGE, NULL);
+  message->ifindex = pktinfo->ipi_ifindex;
+#ifndef G_PLATFORM_WIN32
+#ifndef __NetBSD__
+  message->spec_dst = pktinfo->ipi_spec_dst;
+#endif
+#endif
+  message->addr = pktinfo->ipi_addr;
+
+  return G_SOCKET_CONTROL_MESSAGE (message);
+}
+
+static void
+gst_ip_pktinfo_message_init (GstIPPktinfoMessage * message)
+{
+}
+
+static void
+gst_ip_pktinfo_message_class_init (GstIPPktinfoMessageClass * class)
+{
+  GSocketControlMessageClass *scm_class;
+
+  scm_class = G_SOCKET_CONTROL_MESSAGE_CLASS (class);
+  scm_class->get_size = gst_ip_pktinfo_message_get_size;
+  scm_class->get_level = gst_ip_pktinfo_message_get_level;
+  scm_class->get_type = gst_ip_pktinfo_message_get_msg_type;
+  scm_class->deserialize = gst_ip_pktinfo_message_deserialize;
+}
+#endif
+
+#ifdef IPV6_PKTINFO
+GType gst_ipv6_pktinfo_message_get_type (void);
+
+#define GST_TYPE_IPV6_PKTINFO_MESSAGE         (gst_ipv6_pktinfo_message_get_type ())
+#define GST_IPV6_PKTINFO_MESSAGE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GST_TYPE_IPV6_PKTINFO_MESSAGE, GstIPV6PktinfoMessage))
+#define GST_IPV6_PKTINFO_MESSAGE_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c), GST_TYPE_IPV6_PKTINFO_MESSAGE, GstIPV6PktinfoMessageClass))
+#define GST_IS_IPV6_PKTINFO_MESSAGE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GST_TYPE_IPV6_PKTINFO_MESSAGE))
+#define GST_IS_IPV6_PKTINFO_MESSAGE_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c), GST_TYPE_IPV6_PKTINFO_MESSAGE))
+#define GST_IPV6_PKTINFO_MESSAGE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GST_TYPE_IPV6_PKTINFO_MESSAGE, GstIPV6PktinfoMessageClass))
+
+typedef struct _GstIPV6PktinfoMessage GstIPV6PktinfoMessage;
+typedef struct _GstIPV6PktinfoMessageClass GstIPV6PktinfoMessageClass;
+
+struct _GstIPV6PktinfoMessageClass
+{
+  GSocketControlMessageClass parent_class;
+
+};
+
+struct _GstIPV6PktinfoMessage
+{
+  GSocketControlMessage parent;
+
+  guint ifindex;
+  struct in6_addr addr;
+};
+
+G_DEFINE_TYPE (GstIPV6PktinfoMessage, gst_ipv6_pktinfo_message,
+    G_TYPE_SOCKET_CONTROL_MESSAGE);
+
+static gsize
+gst_ipv6_pktinfo_message_get_size (GSocketControlMessage * message)
+{
+  return sizeof (struct in6_pktinfo);
+}
+
+static int
+gst_ipv6_pktinfo_message_get_level (GSocketControlMessage * message)
+{
+  return IPPROTO_IPV6;
+}
+
+static int
+gst_ipv6_pktinfo_message_get_msg_type (GSocketControlMessage * message)
+{
+  return IPV6_PKTINFO;
+}
+
+static GSocketControlMessage *
+gst_ipv6_pktinfo_message_deserialize (gint level,
+    gint type, gsize size, gpointer data)
+{
+  struct in6_pktinfo *pktinfo;
+  GstIPV6PktinfoMessage *message;
+
+  if (level != IPPROTO_IPV6 || type != IPV6_PKTINFO)
+    return NULL;
+
+  if (size < sizeof (struct in6_pktinfo))
+    return NULL;
+
+  pktinfo = data;
+
+  message = g_object_new (GST_TYPE_IPV6_PKTINFO_MESSAGE, NULL);
+  message->ifindex = pktinfo->ipi6_ifindex;
+  message->addr = pktinfo->ipi6_addr;
+
+  return G_SOCKET_CONTROL_MESSAGE (message);
+}
+
+static void
+gst_ipv6_pktinfo_message_init (GstIPV6PktinfoMessage * message)
+{
+}
+
+static void
+gst_ipv6_pktinfo_message_class_init (GstIPV6PktinfoMessageClass * class)
+{
+  GSocketControlMessageClass *scm_class;
+
+  scm_class = G_SOCKET_CONTROL_MESSAGE_CLASS (class);
+  scm_class->get_size = gst_ipv6_pktinfo_message_get_size;
+  scm_class->get_level = gst_ipv6_pktinfo_message_get_level;
+  scm_class->get_type = gst_ipv6_pktinfo_message_get_msg_type;
+  scm_class->deserialize = gst_ipv6_pktinfo_message_deserialize;
+}
+
+#endif
+
+#ifdef IP_RECVDSTADDR
+GType gst_ip_recvdstaddr_message_get_type (void);
+
+#define GST_TYPE_IP_RECVDSTADDR_MESSAGE         (gst_ip_recvdstaddr_message_get_type ())
+#define GST_IP_RECVDSTADDR_MESSAGE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GST_TYPE_IP_RECVDSTADDR_MESSAGE, GstIPRecvdstaddrMessage))
+#define GST_IP_RECVDSTADDR_MESSAGE_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c), GST_TYPE_IP_RECVDSTADDR_MESSAGE, GstIPRecvdstaddrMessageClass))
+#define GST_IS_IP_RECVDSTADDR_MESSAGE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GST_TYPE_IP_RECVDSTADDR_MESSAGE))
+#define GST_IS_IP_RECVDSTADDR_MESSAGE_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c), GST_TYPE_IP_RECVDSTADDR_MESSAGE))
+#define GST_IP_RECVDSTADDR_MESSAGE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GST_TYPE_IP_RECVDSTADDR_MESSAGE, GstIPRecvdstaddrMessageClass))
+
+typedef struct _GstIPRecvdstaddrMessage GstIPRecvdstaddrMessage;
+typedef struct _GstIPRecvdstaddrMessageClass GstIPRecvdstaddrMessageClass;
+
+struct _GstIPRecvdstaddrMessageClass
+{
+  GSocketControlMessageClass parent_class;
+
+};
+
+struct _GstIPRecvdstaddrMessage
+{
+  GSocketControlMessage parent;
+
+  guint ifindex;
+  struct in_addr addr;
+};
+
+G_DEFINE_TYPE (GstIPRecvdstaddrMessage, gst_ip_recvdstaddr_message,
+    G_TYPE_SOCKET_CONTROL_MESSAGE);
+
+static gsize
+gst_ip_recvdstaddr_message_get_size (GSocketControlMessage * message)
+{
+  return sizeof (struct in_addr);
+}
+
+static int
+gst_ip_recvdstaddr_message_get_level (GSocketControlMessage * message)
+{
+  return IPPROTO_IP;
+}
+
+static int
+gst_ip_recvdstaddr_message_get_msg_type (GSocketControlMessage * message)
+{
+  return IP_RECVDSTADDR;
+}
+
+static GSocketControlMessage *
+gst_ip_recvdstaddr_message_deserialize (gint level,
+    gint type, gsize size, gpointer data)
+{
+  struct in_addr *addr;
+  GstIPRecvdstaddrMessage *message;
+
+  if (level != IPPROTO_IP || type != IP_RECVDSTADDR)
+    return NULL;
+
+  if (size < sizeof (struct in_addr))
+    return NULL;
+
+  addr = data;
+
+  message = g_object_new (GST_TYPE_IP_RECVDSTADDR_MESSAGE, NULL);
+  message->addr = *addr;
+
+  return G_SOCKET_CONTROL_MESSAGE (message);
+}
+
+static void
+gst_ip_recvdstaddr_message_init (GstIPRecvdstaddrMessage * message)
+{
+}
+
+static void
+gst_ip_recvdstaddr_message_class_init (GstIPRecvdstaddrMessageClass * class)
+{
+  GSocketControlMessageClass *scm_class;
+
+  scm_class = G_SOCKET_CONTROL_MESSAGE_CLASS (class);
+  scm_class->get_size = gst_ip_recvdstaddr_message_get_size;
+  scm_class->get_level = gst_ip_recvdstaddr_message_get_level;
+  scm_class->get_type = gst_ip_recvdstaddr_message_get_msg_type;
+  scm_class->deserialize = gst_ip_recvdstaddr_message_deserialize;
+}
+#endif
+
+/* not 100% correct, but a good upper bound for memory allocation purposes */
+#define MAX_IPV4_UDP_PACKET_SIZE (65536 - 8)
+
+GST_DEBUG_CATEGORY_STATIC (udpsrc_debug);
+#define GST_CAT_DEFAULT (udpsrc_debug)
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+#define UDP_DEFAULT_PORT                5004
+#define UDP_DEFAULT_MULTICAST_GROUP     "0.0.0.0"
+#define UDP_DEFAULT_MULTICAST_IFACE     NULL
+#define UDP_DEFAULT_URI                 "udp://"UDP_DEFAULT_MULTICAST_GROUP":"G_STRINGIFY(UDP_DEFAULT_PORT)
+#define UDP_DEFAULT_CAPS                NULL
+#define UDP_DEFAULT_SOCKET              NULL
+#define UDP_DEFAULT_BUFFER_SIZE		0
+#define UDP_DEFAULT_TIMEOUT             0
+#define UDP_DEFAULT_SKIP_FIRST_BYTES	0
+#define UDP_DEFAULT_CLOSE_SOCKET       TRUE
+#define UDP_DEFAULT_USED_SOCKET        NULL
+#define UDP_DEFAULT_AUTO_MULTICAST     TRUE
+#define UDP_DEFAULT_REUSE              TRUE
+#define UDP_DEFAULT_LOOP               TRUE
+#define UDP_DEFAULT_RETRIEVE_SENDER_ADDRESS TRUE
+
+enum
+{
+  PROP_0,
+
+  PROP_PORT,
+  PROP_MULTICAST_GROUP,
+  PROP_MULTICAST_IFACE,
+  PROP_URI,
+  PROP_CAPS,
+  PROP_SOCKET,
+  PROP_BUFFER_SIZE,
+  PROP_TIMEOUT,
+  PROP_SKIP_FIRST_BYTES,
+  PROP_CLOSE_SOCKET,
+  PROP_USED_SOCKET,
+  PROP_AUTO_MULTICAST,
+  PROP_REUSE,
+  PROP_ADDRESS,
+  PROP_LOOP,
+  PROP_RETRIEVE_SENDER_ADDRESS
+};
+
+static void gst_udpsrc_uri_handler_init (gpointer g_iface, gpointer iface_data);
+
+static GstCaps *gst_udpsrc_getcaps (GstBaseSrc * src, GstCaps * filter);
+static GstFlowReturn gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf);
+static gboolean gst_udpsrc_close (GstUDPSrc * src);
+static gboolean gst_udpsrc_unlock (GstBaseSrc * bsrc);
+static gboolean gst_udpsrc_unlock_stop (GstBaseSrc * bsrc);
+static gboolean gst_udpsrc_negotiate (GstBaseSrc * basesrc);
+
+static void gst_udpsrc_finalize (GObject * object);
+
+static void gst_udpsrc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_udpsrc_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn gst_udpsrc_change_state (GstElement * element,
+    GstStateChange transition);
+
+#define gst_udpsrc_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstUDPSrc, gst_udpsrc, GST_TYPE_PUSH_SRC,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_udpsrc_uri_handler_init));
+
+static void
+gst_udpsrc_class_init (GstUDPSrcClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSrcClass *gstbasesrc_class;
+  GstPushSrcClass *gstpushsrc_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesrc_class = (GstBaseSrcClass *) klass;
+  gstpushsrc_class = (GstPushSrcClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (udpsrc_debug, "udpsrc", 0, "UDP src");
+
+#ifdef IP_PKTINFO
+  GST_TYPE_IP_PKTINFO_MESSAGE;
+#endif
+#ifdef IPV6_PKTINFO
+  GST_TYPE_IPV6_PKTINFO_MESSAGE;
+#endif
+#ifdef IP_RECVDSTADDR
+  GST_TYPE_IP_RECVDSTADDR_MESSAGE;
+#endif
+
+  gobject_class->set_property = gst_udpsrc_set_property;
+  gobject_class->get_property = gst_udpsrc_get_property;
+  gobject_class->finalize = gst_udpsrc_finalize;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PORT,
+      g_param_spec_int ("port", "Port",
+          "The port to receive the packets from, 0=allocate", 0, G_MAXUINT16,
+          UDP_DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /* FIXME 2.0: Remove multicast-group property */
+#ifndef GST_REMOVE_DEPRECATED
+  g_object_class_install_property (gobject_class, PROP_MULTICAST_GROUP,
+      g_param_spec_string ("multicast-group", "Multicast Group",
+          "The Address of multicast group to join. (DEPRECATED: "
+          "Use address property instead)", UDP_DEFAULT_MULTICAST_GROUP,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
+#endif
+  g_object_class_install_property (gobject_class, PROP_MULTICAST_IFACE,
+      g_param_spec_string ("multicast-iface", "Multicast Interface",
+          "The network interface on which to join the multicast group."
+          "This allows multiple interfaces seperated by comma. (\"eth0,eth1\")",
+          UDP_DEFAULT_MULTICAST_IFACE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_URI,
+      g_param_spec_string ("uri", "URI",
+          "URI in the form of udp://multicast_group:port", UDP_DEFAULT_URI,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_CAPS,
+      g_param_spec_boxed ("caps", "Caps",
+          "The caps of the source pad", GST_TYPE_CAPS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_SOCKET,
+      g_param_spec_object ("socket", "Socket",
+          "Socket to use for UDP reception. (NULL == allocate)",
+          G_TYPE_SOCKET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BUFFER_SIZE,
+      g_param_spec_int ("buffer-size", "Buffer Size",
+          "Size of the kernel receive buffer in bytes, 0=default", 0, G_MAXINT,
+          UDP_DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMEOUT,
+      g_param_spec_uint64 ("timeout", "Timeout",
+          "Post a message after timeout nanoseconds (0 = disabled)", 0,
+          G_MAXUINT64, UDP_DEFAULT_TIMEOUT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_SKIP_FIRST_BYTES, g_param_spec_int ("skip-first-bytes",
+          "Skip first bytes", "number of bytes to skip for each udp packet", 0,
+          G_MAXINT, UDP_DEFAULT_SKIP_FIRST_BYTES,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_CLOSE_SOCKET,
+      g_param_spec_boolean ("close-socket", "Close socket",
+          "Close socket if passed as property on state change",
+          UDP_DEFAULT_CLOSE_SOCKET,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_USED_SOCKET,
+      g_param_spec_object ("used-socket", "Socket Handle",
+          "Socket currently in use for UDP reception. (NULL = no socket)",
+          G_TYPE_SOCKET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_AUTO_MULTICAST,
+      g_param_spec_boolean ("auto-multicast", "Auto Multicast",
+          "Automatically join/leave multicast groups",
+          UDP_DEFAULT_AUTO_MULTICAST,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_REUSE,
+      g_param_spec_boolean ("reuse", "Reuse", "Enable reuse of the port",
+          UDP_DEFAULT_REUSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_ADDRESS,
+      g_param_spec_string ("address", "Address",
+          "Address to receive packets for. This is equivalent to the "
+          "multicast-group property for now", UDP_DEFAULT_MULTICAST_GROUP,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstUDPSrc::loop:
+   *
+   * Can be used to disable multicast loopback.
+   *
+   * Since: 1.8
+   */
+  g_object_class_install_property (gobject_class, PROP_LOOP,
+      g_param_spec_boolean ("loop", "Multicast Loopback",
+          "Used for setting the multicast loop parameter. TRUE = enable,"
+          " FALSE = disable", UDP_DEFAULT_LOOP,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstUDPSrc::retrieve-sender-address:
+   *
+   * Whether to retrieve the sender address and add it to the buffers as
+   * meta. Disabling this might result in minor performance improvements
+   * in certain scenarios.
+   *
+   * Since: 1.10
+   */
+  g_object_class_install_property (gobject_class, PROP_RETRIEVE_SENDER_ADDRESS,
+      g_param_spec_boolean ("retrieve-sender-address",
+          "Retrieve Sender Address",
+          "Whether to retrieve the sender address and add it to buffers as "
+          "meta. Disabling this might result in minor performance improvements "
+          "in certain scenarios", UDP_DEFAULT_RETRIEVE_SENDER_ADDRESS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "UDP packet receiver", "Source/Network",
+      "Receive data over the network via UDP",
+      "Wim Taymans <wim@fluendo.com>, "
+      "Thijs Vermeir <thijs.vermeir@barco.com>");
+
+  gstelement_class->change_state = gst_udpsrc_change_state;
+
+  gstbasesrc_class->unlock = gst_udpsrc_unlock;
+  gstbasesrc_class->unlock_stop = gst_udpsrc_unlock_stop;
+  gstbasesrc_class->get_caps = gst_udpsrc_getcaps;
+  gstbasesrc_class->negotiate = gst_udpsrc_negotiate;
+
+  gstpushsrc_class->create = gst_udpsrc_create;
+}
+
+static void
+gst_udpsrc_init (GstUDPSrc * udpsrc)
+{
+  udpsrc->uri =
+      g_strdup_printf ("udp://%s:%u", UDP_DEFAULT_MULTICAST_GROUP,
+      UDP_DEFAULT_PORT);
+
+  udpsrc->address = g_strdup (UDP_DEFAULT_MULTICAST_GROUP);
+  udpsrc->port = UDP_DEFAULT_PORT;
+  udpsrc->socket = UDP_DEFAULT_SOCKET;
+  udpsrc->multi_iface = g_strdup (UDP_DEFAULT_MULTICAST_IFACE);
+  udpsrc->buffer_size = UDP_DEFAULT_BUFFER_SIZE;
+  udpsrc->timeout = UDP_DEFAULT_TIMEOUT;
+  udpsrc->skip_first_bytes = UDP_DEFAULT_SKIP_FIRST_BYTES;
+  udpsrc->close_socket = UDP_DEFAULT_CLOSE_SOCKET;
+  udpsrc->external_socket = (udpsrc->socket != NULL);
+  udpsrc->auto_multicast = UDP_DEFAULT_AUTO_MULTICAST;
+  udpsrc->used_socket = UDP_DEFAULT_USED_SOCKET;
+  udpsrc->reuse = UDP_DEFAULT_REUSE;
+  udpsrc->loop = UDP_DEFAULT_LOOP;
+  udpsrc->retrieve_sender_address = UDP_DEFAULT_RETRIEVE_SENDER_ADDRESS;
+
+  /* configure basesrc to be a live source */
+  gst_base_src_set_live (GST_BASE_SRC (udpsrc), TRUE);
+  /* make basesrc output a segment in time */
+  gst_base_src_set_format (GST_BASE_SRC (udpsrc), GST_FORMAT_TIME);
+  /* make basesrc set timestamps on outgoing buffers based on the running_time
+   * when they were captured */
+  gst_base_src_set_do_timestamp (GST_BASE_SRC (udpsrc), TRUE);
+}
+
+static void
+gst_udpsrc_finalize (GObject * object)
+{
+  GstUDPSrc *udpsrc;
+
+  udpsrc = GST_UDPSRC (object);
+
+  if (udpsrc->caps)
+    gst_caps_unref (udpsrc->caps);
+  udpsrc->caps = NULL;
+
+  g_free (udpsrc->multi_iface);
+  udpsrc->multi_iface = NULL;
+
+  g_free (udpsrc->uri);
+  udpsrc->uri = NULL;
+
+  g_free (udpsrc->address);
+  udpsrc->address = NULL;
+
+  if (udpsrc->socket)
+    g_object_unref (udpsrc->socket);
+  udpsrc->socket = NULL;
+
+  if (udpsrc->used_socket)
+    g_object_unref (udpsrc->used_socket);
+  udpsrc->used_socket = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstCaps *
+gst_udpsrc_getcaps (GstBaseSrc * src, GstCaps * filter)
+{
+  GstUDPSrc *udpsrc;
+  GstCaps *caps, *result;
+
+  udpsrc = GST_UDPSRC (src);
+
+  GST_OBJECT_LOCK (src);
+  if ((caps = udpsrc->caps))
+    gst_caps_ref (caps);
+  GST_OBJECT_UNLOCK (src);
+
+  if (caps) {
+    if (filter) {
+      result = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+      gst_caps_unref (caps);
+    } else {
+      result = caps;
+    }
+  } else {
+    result = (filter) ? gst_caps_ref (filter) : gst_caps_new_any ();
+  }
+  return result;
+}
+
+static void
+gst_udpsrc_reset_memory_allocator (GstUDPSrc * src)
+{
+  if (src->mem != NULL) {
+    gst_memory_unmap (src->mem, &src->map);
+    gst_memory_unref (src->mem);
+    src->mem = NULL;
+  }
+  if (src->mem_max != NULL) {
+    gst_memory_unmap (src->mem_max, &src->map_max);
+    gst_memory_unref (src->mem_max);
+    src->mem_max = NULL;
+  }
+
+  src->vec[0].buffer = NULL;
+  src->vec[0].size = 0;
+  src->vec[1].buffer = NULL;
+  src->vec[1].size = 0;
+
+  if (src->allocator != NULL) {
+    gst_object_unref (src->allocator);
+    src->allocator = NULL;
+  }
+}
+
+static gboolean
+gst_udpsrc_negotiate (GstBaseSrc * basesrc)
+{
+  GstUDPSrc *src = GST_UDPSRC_CAST (basesrc);
+  gboolean ret;
+
+  /* just chain up to the default implementation, we just want to
+   * retrieve the allocator at the end of it (if there is one) */
+  ret = GST_BASE_SRC_CLASS (parent_class)->negotiate (basesrc);
+
+  if (ret) {
+    GstAllocationParams new_params;
+    GstAllocator *new_allocator = NULL;
+
+    /* retrieve new allocator */
+    gst_base_src_get_allocator (basesrc, &new_allocator, &new_params);
+
+    if (src->allocator != new_allocator ||
+        memcmp (&src->params, &new_params, sizeof (GstAllocationParams)) != 0) {
+      /* drop old allocator and throw away any memory allocated with it */
+      gst_udpsrc_reset_memory_allocator (src);
+
+      /* and save the new allocator and/or new allocation parameters */
+      src->allocator = new_allocator;
+      src->params = new_params;
+
+      GST_INFO_OBJECT (src, "new allocator: %" GST_PTR_FORMAT, new_allocator);
+    }
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_udpsrc_alloc_mem (GstUDPSrc * src, GstMemory ** p_mem, GstMapInfo * map,
+    gsize size)
+{
+  GstMemory *mem;
+
+  mem = gst_allocator_alloc (src->allocator, size, &src->params);
+
+  if (!gst_memory_map (mem, map, GST_MAP_WRITE)) {
+    gst_memory_unref (mem);
+    memset (map, 0, sizeof (GstMapInfo));
+    return FALSE;
+  }
+  *p_mem = mem;
+  return TRUE;
+}
+
+static gboolean
+gst_udpsrc_ensure_mem (GstUDPSrc * src)
+{
+  if (src->mem == NULL) {
+    gsize mem_size = 1500;      /* typical max. MTU */
+
+    /* if packets are likely to be smaller, just use that size, otherwise
+     * default to assuming incoming packets are around MTU size */
+    if (src->max_size > 0 && src->max_size < mem_size)
+      mem_size = src->max_size;
+
+    if (!gst_udpsrc_alloc_mem (src, &src->mem, &src->map, mem_size))
+      return FALSE;
+
+    src->vec[0].buffer = src->map.data;
+    src->vec[0].size = src->map.size;
+  }
+
+  if (src->mem_max == NULL) {
+    gsize max_size = MAX_IPV4_UDP_PACKET_SIZE;
+
+    if (!gst_udpsrc_alloc_mem (src, &src->mem_max, &src->map_max, max_size))
+      return FALSE;
+
+    src->vec[1].buffer = src->map_max.data;
+    src->vec[1].size = src->map_max.size;
+  }
+
+  return TRUE;
+}
+
+static void
+gst_udpsrc_create_cancellable (GstUDPSrc * src)
+{
+  GPollFD pollfd;
+
+  src->cancellable = g_cancellable_new ();
+  src->made_cancel_fd = g_cancellable_make_pollfd (src->cancellable, &pollfd);
+}
+
+static void
+gst_udpsrc_free_cancellable (GstUDPSrc * src)
+{
+  if (src->made_cancel_fd) {
+    g_cancellable_release_fd (src->cancellable);
+    src->made_cancel_fd = FALSE;
+  }
+  g_object_unref (src->cancellable);
+  src->cancellable = NULL;
+}
+
+static GstFlowReturn
+gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
+{
+  GstUDPSrc *udpsrc;
+  GstBuffer *outbuf = NULL;
+  GSocketAddress *saddr = NULL;
+  GSocketAddress **p_saddr;
+  gint flags = G_SOCKET_MSG_NONE;
+  gboolean try_again;
+  GError *err = NULL;
+  gssize res;
+  gsize offset;
+  GSocketControlMessage **msgs = NULL;
+  GSocketControlMessage ***p_msgs;
+  gint n_msgs = 0, i;
+
+  udpsrc = GST_UDPSRC_CAST (psrc);
+
+  if (!gst_udpsrc_ensure_mem (udpsrc))
+    goto memory_alloc_error;
+
+  /* optimization: use messages only in multicast mode and
+   * if we can't let the kernel do the filtering for us */
+  p_msgs =
+      (g_inet_address_get_is_multicast (g_inet_socket_address_get_address
+          (udpsrc->addr))) ? &msgs : NULL;
+#ifdef IP_MULTICAST_ALL
+  if (g_inet_address_get_family (g_inet_socket_address_get_address
+          (udpsrc->addr)) == G_SOCKET_FAMILY_IPV4)
+    p_msgs = NULL;
+#endif
+
+  /* Retrieve sender address unless we've been configured not to do so */
+  p_saddr = (udpsrc->retrieve_sender_address) ? &saddr : NULL;
+
+retry:
+  if (saddr != NULL) {
+    g_object_unref (saddr);
+    saddr = NULL;
+  }
+
+  do {
+    gint64 timeout;
+
+    try_again = FALSE;
+
+    if (udpsrc->timeout)
+      timeout = udpsrc->timeout / 1000;
+    else
+      timeout = -1;
+
+    GST_LOG_OBJECT (udpsrc, "doing select, timeout %" G_GINT64_FORMAT, timeout);
+
+    if (!g_socket_condition_timed_wait (udpsrc->used_socket, G_IO_IN | G_IO_PRI,
+            timeout, udpsrc->cancellable, &err)) {
+      if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_BUSY)
+          || g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+        goto stopped;
+      } else if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
+        g_clear_error (&err);
+        /* timeout, post element message */
+        gst_element_post_message (GST_ELEMENT_CAST (udpsrc),
+            gst_message_new_element (GST_OBJECT_CAST (udpsrc),
+                gst_structure_new ("GstUDPSrcTimeout",
+                    "timeout", G_TYPE_UINT64, udpsrc->timeout, NULL)));
+      } else {
+        goto select_error;
+      }
+
+      try_again = TRUE;
+    }
+  } while (G_UNLIKELY (try_again));
+
+  res =
+      g_socket_receive_message (udpsrc->used_socket, p_saddr, udpsrc->vec, 2,
+      p_msgs, &n_msgs, &flags, udpsrc->cancellable, &err);
+
+  if (G_UNLIKELY (res < 0)) {
+    /* G_IO_ERROR_HOST_UNREACHABLE for a UDP socket means that a packet sent
+     * with udpsink generated a "port unreachable" ICMP response. We ignore
+     * that and try again.
+     * On Windows we get G_IO_ERROR_CONNECTION_CLOSED instead */
+#if GLIB_CHECK_VERSION(2,44,0)
+    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE) ||
+        g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED)) {
+#else
+    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE)) {
+#endif
+      g_clear_error (&err);
+      goto retry;
+    }
+    goto receive_error;
+  }
+
+  /* remember maximum packet size */
+  if (res > udpsrc->max_size)
+    udpsrc->max_size = res;
+
+  /* Retry if multicast and the destination address is not ours. We don't want
+   * to receive arbitrary packets */
+  if (p_msgs) {
+    GInetAddress *iaddr = g_inet_socket_address_get_address (udpsrc->addr);
+    gboolean skip_packet = FALSE;
+    gsize iaddr_size = g_inet_address_get_native_size (iaddr);
+    const guint8 *iaddr_bytes = g_inet_address_to_bytes (iaddr);
+
+    for (i = 0; i < n_msgs && !skip_packet; i++) {
+#ifdef IP_PKTINFO
+      if (GST_IS_IP_PKTINFO_MESSAGE (msgs[i])) {
+        GstIPPktinfoMessage *msg = GST_IP_PKTINFO_MESSAGE (msgs[i]);
+
+        if (sizeof (msg->addr) == iaddr_size
+            && memcmp (iaddr_bytes, &msg->addr, sizeof (msg->addr)))
+          skip_packet = TRUE;
+      }
+#endif
+#ifdef IPV6_PKTINFO
+      if (GST_IS_IPV6_PKTINFO_MESSAGE (msgs[i])) {
+        GstIPV6PktinfoMessage *msg = GST_IPV6_PKTINFO_MESSAGE (msgs[i]);
+
+        if (sizeof (msg->addr) == iaddr_size
+            && memcmp (iaddr_bytes, &msg->addr, sizeof (msg->addr)))
+          skip_packet = TRUE;
+      }
+#endif
+#ifdef IP_RECVDSTADDR
+      if (GST_IS_IP_RECVDSTADDR_MESSAGE (msgs[i])) {
+        GstIPRecvdstaddrMessage *msg = GST_IP_RECVDSTADDR_MESSAGE (msgs[i]);
+
+        if (sizeof (msg->addr) == iaddr_size
+            && memcmp (iaddr_bytes, &msg->addr, sizeof (msg->addr)))
+          skip_packet = TRUE;
+      }
+#endif
+    }
+
+    for (i = 0; i < n_msgs; i++) {
+      g_object_unref (msgs[i]);
+    }
+    g_free (msgs);
+
+    if (skip_packet) {
+      GST_DEBUG_OBJECT (udpsrc,
+          "Dropping packet for a different multicast address");
+      goto retry;
+    }
+  }
+
+  outbuf = gst_buffer_new ();
+
+  /* append first memory chunk to buffer */
+  gst_buffer_append_memory (outbuf, udpsrc->mem);
+
+  /* if the packet didn't fit into the first chunk, add second one as well */
+  if (res > udpsrc->map.size) {
+    gst_buffer_append_memory (outbuf, udpsrc->mem_max);
+    gst_memory_unmap (udpsrc->mem_max, &udpsrc->map_max);
+    udpsrc->vec[1].buffer = NULL;
+    udpsrc->vec[1].size = 0;
+    udpsrc->mem_max = NULL;
+  }
+
+  /* make sure we allocate a new chunk next time (we do this only here because
+   * we look at map.size to see if the second memory chunk is needed above) */
+  gst_memory_unmap (udpsrc->mem, &udpsrc->map);
+  udpsrc->vec[0].buffer = NULL;
+  udpsrc->vec[0].size = 0;
+  udpsrc->mem = NULL;
+
+  offset = udpsrc->skip_first_bytes;
+
+  if (G_UNLIKELY (offset > 0 && res < offset))
+    goto skip_error;
+
+  gst_buffer_resize (outbuf, offset, res - offset);
+
+  /* use buffer metadata so receivers can also track the address */
+  if (saddr) {
+    gst_buffer_add_net_address_meta (outbuf, saddr);
+    g_object_unref (saddr);
+    saddr = NULL;
+  }
+
+  GST_LOG_OBJECT (udpsrc, "read packet of %d bytes", (int) res);
+
+  *buf = GST_BUFFER_CAST (outbuf);
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+memory_alloc_error:
+  {
+    GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
+        ("Failed to allocate or map memory"));
+    return GST_FLOW_ERROR;
+  }
+select_error:
+  {
+    GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
+        ("select error: %s", err->message));
+    g_clear_error (&err);
+    return GST_FLOW_ERROR;
+  }
+stopped:
+  {
+    GST_DEBUG ("stop called");
+    g_clear_error (&err);
+    return GST_FLOW_FLUSHING;
+  }
+receive_error:
+  {
+    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_BUSY) ||
+        g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+      g_clear_error (&err);
+      return GST_FLOW_FLUSHING;
+    } else {
+      GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
+          ("receive error %" G_GSSIZE_FORMAT ": %s", res, err->message));
+      g_clear_error (&err);
+      return GST_FLOW_ERROR;
+    }
+  }
+skip_error:
+  {
+    gst_buffer_unref (outbuf);
+
+    GST_ELEMENT_ERROR (udpsrc, STREAM, DECODE, (NULL),
+        ("UDP buffer to small to skip header"));
+    return GST_FLOW_ERROR;
+  }
+}
+
+static gboolean
+gst_udpsrc_set_uri (GstUDPSrc * src, const gchar * uri, GError ** error)
+{
+  gchar *address;
+  guint16 port;
+
+  if (!gst_udp_parse_uri (uri, &address, &port))
+    goto wrong_uri;
+
+  if (port == (guint16) - 1)
+    port = UDP_DEFAULT_PORT;
+
+  g_free (src->address);
+  src->address = address;
+  src->port = port;
+
+  g_free (src->uri);
+  src->uri = g_strdup (uri);
+
+  return TRUE;
+
+  /* ERRORS */
+wrong_uri:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+        ("error parsing uri %s", uri));
+    g_set_error_literal (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
+        "Could not parse UDP URI");
+    return FALSE;
+  }
+}
+
+static void
+gst_udpsrc_set_property (GObject * object, guint prop_id, const GValue * value,
+    GParamSpec * pspec)
+{
+  GstUDPSrc *udpsrc = GST_UDPSRC (object);
+
+  switch (prop_id) {
+    case PROP_BUFFER_SIZE:
+      udpsrc->buffer_size = g_value_get_int (value);
+      break;
+    case PROP_PORT:
+      udpsrc->port = g_value_get_int (value);
+      g_free (udpsrc->uri);
+      udpsrc->uri =
+          g_strdup_printf ("udp://%s:%u", udpsrc->address, udpsrc->port);
+      break;
+    case PROP_MULTICAST_GROUP:
+    case PROP_ADDRESS:
+    {
+      const gchar *group;
+
+      g_free (udpsrc->address);
+      if ((group = g_value_get_string (value)))
+        udpsrc->address = g_strdup (group);
+      else
+        udpsrc->address = g_strdup (UDP_DEFAULT_MULTICAST_GROUP);
+
+      g_free (udpsrc->uri);
+      udpsrc->uri =
+          g_strdup_printf ("udp://%s:%u", udpsrc->address, udpsrc->port);
+      break;
+    }
+    case PROP_MULTICAST_IFACE:
+      g_free (udpsrc->multi_iface);
+
+      if (g_value_get_string (value) == NULL)
+        udpsrc->multi_iface = g_strdup (UDP_DEFAULT_MULTICAST_IFACE);
+      else
+        udpsrc->multi_iface = g_value_dup_string (value);
+      break;
+    case PROP_URI:
+      gst_udpsrc_set_uri (udpsrc, g_value_get_string (value), NULL);
+      break;
+    case PROP_CAPS:
+    {
+      const GstCaps *new_caps_val = gst_value_get_caps (value);
+      GstCaps *new_caps;
+      GstCaps *old_caps;
+
+      if (new_caps_val == NULL) {
+        new_caps = gst_caps_new_any ();
+      } else {
+        new_caps = gst_caps_copy (new_caps_val);
+      }
+
+      GST_OBJECT_LOCK (udpsrc);
+      old_caps = udpsrc->caps;
+      udpsrc->caps = new_caps;
+      GST_OBJECT_UNLOCK (udpsrc);
+      if (old_caps)
+        gst_caps_unref (old_caps);
+
+      gst_pad_mark_reconfigure (GST_BASE_SRC_PAD (udpsrc));
+      break;
+    }
+    case PROP_SOCKET:
+      if (udpsrc->socket != NULL && udpsrc->socket != udpsrc->used_socket &&
+          udpsrc->close_socket) {
+        GError *err = NULL;
+
+        if (!g_socket_close (udpsrc->socket, &err)) {
+          GST_ERROR ("failed to close socket %p: %s", udpsrc->socket,
+              err->message);
+          g_clear_error (&err);
+        }
+      }
+      if (udpsrc->socket)
+        g_object_unref (udpsrc->socket);
+      udpsrc->socket = g_value_dup_object (value);
+      GST_DEBUG ("setting socket to %p", udpsrc->socket);
+      break;
+    case PROP_TIMEOUT:
+      udpsrc->timeout = g_value_get_uint64 (value);
+      break;
+    case PROP_SKIP_FIRST_BYTES:
+      udpsrc->skip_first_bytes = g_value_get_int (value);
+      break;
+    case PROP_CLOSE_SOCKET:
+      udpsrc->close_socket = g_value_get_boolean (value);
+      break;
+    case PROP_AUTO_MULTICAST:
+      udpsrc->auto_multicast = g_value_get_boolean (value);
+      break;
+    case PROP_REUSE:
+      udpsrc->reuse = g_value_get_boolean (value);
+      break;
+    case PROP_LOOP:
+      udpsrc->loop = g_value_get_boolean (value);
+      break;
+    case PROP_RETRIEVE_SENDER_ADDRESS:
+      udpsrc->retrieve_sender_address = g_value_get_boolean (value);
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_udpsrc_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstUDPSrc *udpsrc = GST_UDPSRC (object);
+
+  switch (prop_id) {
+    case PROP_BUFFER_SIZE:
+      g_value_set_int (value, udpsrc->buffer_size);
+      break;
+    case PROP_PORT:
+      g_value_set_int (value, udpsrc->port);
+      break;
+    case PROP_MULTICAST_GROUP:
+    case PROP_ADDRESS:
+      g_value_set_string (value, udpsrc->address);
+      break;
+    case PROP_MULTICAST_IFACE:
+      g_value_set_string (value, udpsrc->multi_iface);
+      break;
+    case PROP_URI:
+      g_value_set_string (value, udpsrc->uri);
+      break;
+    case PROP_CAPS:
+      GST_OBJECT_LOCK (udpsrc);
+      gst_value_set_caps (value, udpsrc->caps);
+      GST_OBJECT_UNLOCK (udpsrc);
+      break;
+    case PROP_SOCKET:
+      g_value_set_object (value, udpsrc->socket);
+      break;
+    case PROP_TIMEOUT:
+      g_value_set_uint64 (value, udpsrc->timeout);
+      break;
+    case PROP_SKIP_FIRST_BYTES:
+      g_value_set_int (value, udpsrc->skip_first_bytes);
+      break;
+    case PROP_CLOSE_SOCKET:
+      g_value_set_boolean (value, udpsrc->close_socket);
+      break;
+    case PROP_USED_SOCKET:
+      g_value_set_object (value, udpsrc->used_socket);
+      break;
+    case PROP_AUTO_MULTICAST:
+      g_value_set_boolean (value, udpsrc->auto_multicast);
+      break;
+    case PROP_REUSE:
+      g_value_set_boolean (value, udpsrc->reuse);
+      break;
+    case PROP_LOOP:
+      g_value_set_boolean (value, udpsrc->loop);
+      break;
+    case PROP_RETRIEVE_SENDER_ADDRESS:
+      g_value_set_boolean (value, udpsrc->retrieve_sender_address);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GInetAddress *
+gst_udpsrc_resolve (GstUDPSrc * src, const gchar * address)
+{
+  GInetAddress *addr;
+  GError *err = NULL;
+  GResolver *resolver;
+
+  addr = g_inet_address_new_from_string (address);
+  if (!addr) {
+    GList *results;
+
+    GST_DEBUG_OBJECT (src, "resolving IP address for host %s", address);
+    resolver = g_resolver_get_default ();
+    results =
+        g_resolver_lookup_by_name (resolver, address, src->cancellable, &err);
+    if (!results)
+      goto name_resolve;
+    addr = G_INET_ADDRESS (g_object_ref (results->data));
+
+    g_resolver_free_addresses (results);
+    g_object_unref (resolver);
+  }
+#ifndef GST_DISABLE_GST_DEBUG
+  {
+    gchar *ip = g_inet_address_to_string (addr);
+
+    GST_DEBUG_OBJECT (src, "IP address for host %s is %s", address, ip);
+    g_free (ip);
+  }
+#endif
+
+  return addr;
+
+name_resolve:
+  {
+    GST_WARNING_OBJECT (src, "Failed to resolve %s: %s", address, err->message);
+    g_clear_error (&err);
+    g_object_unref (resolver);
+    return NULL;
+  }
+}
+
+/* create a socket for sending to remote machine */
+static gboolean
+gst_udpsrc_open (GstUDPSrc * src)
+{
+  GInetAddress *addr, *bind_addr;
+  GSocketAddress *bind_saddr;
+  GError *err = NULL;
+
+  gst_udpsrc_create_cancellable (src);
+
+  if (src->socket == NULL) {
+    /* need to allocate a socket */
+    GST_DEBUG_OBJECT (src, "allocating socket for %s:%d", src->address,
+        src->port);
+
+    addr = gst_udpsrc_resolve (src, src->address);
+    if (!addr)
+      goto name_resolve;
+
+    if ((src->used_socket =
+            g_socket_new (g_inet_address_get_family (addr),
+                G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
+      goto no_socket;
+
+    src->external_socket = FALSE;
+
+    GST_DEBUG_OBJECT (src, "got socket %p", src->used_socket);
+
+    if (src->addr)
+      g_object_unref (src->addr);
+    src->addr =
+        G_INET_SOCKET_ADDRESS (g_inet_socket_address_new (addr, src->port));
+
+    GST_DEBUG_OBJECT (src, "binding on port %d", src->port);
+
+    /* For multicast, bind to ANY and join the multicast group later */
+    if (g_inet_address_get_is_multicast (addr))
+      bind_addr = g_inet_address_new_any (g_inet_address_get_family (addr));
+    else
+      bind_addr = G_INET_ADDRESS (g_object_ref (addr));
+
+    g_object_unref (addr);
+
+    bind_saddr = g_inet_socket_address_new (bind_addr, src->port);
+    g_object_unref (bind_addr);
+    if (!g_socket_bind (src->used_socket, bind_saddr, src->reuse, &err))
+      goto bind_error;
+
+    g_object_unref (bind_saddr);
+    g_socket_set_multicast_loopback (src->used_socket, src->loop);
+  } else {
+    GInetSocketAddress *local_addr;
+
+    GST_DEBUG_OBJECT (src, "using provided socket %p", src->socket);
+    /* we use the configured socket, try to get some info about it */
+    src->used_socket = G_SOCKET (g_object_ref (src->socket));
+    src->external_socket = TRUE;
+
+    local_addr =
+        G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket,
+            &err));
+    if (!local_addr)
+      goto getsockname_error;
+
+    addr = gst_udpsrc_resolve (src, src->address);
+    if (!addr)
+      goto name_resolve;
+
+    /* If bound to ANY and address points to a multicast address, make
+     * sure that address is not overridden with ANY but we have the
+     * opportunity later to join the multicast address. This ensures that we
+     * have the same behaviour as for sockets created by udpsrc */
+    if (!src->auto_multicast ||
+        !g_inet_address_get_is_any (g_inet_socket_address_get_address
+            (local_addr))
+        || !g_inet_address_get_is_multicast (addr)) {
+      g_object_unref (addr);
+      if (src->addr)
+        g_object_unref (src->addr);
+      src->addr = local_addr;
+    } else {
+      g_object_unref (local_addr);
+      if (src->addr)
+        g_object_unref (src->addr);
+      src->addr =
+          G_INET_SOCKET_ADDRESS (g_inet_socket_address_new (addr, src->port));
+      g_object_unref (addr);
+    }
+  }
+
+  {
+    gint val = 0;
+
+    if (src->buffer_size != 0) {
+      GError *opt_err = NULL;
+
+      GST_INFO_OBJECT (src, "setting udp buffer of %d bytes", src->buffer_size);
+      /* set buffer size, Note that on Linux this is typically limited to a
+       * maximum of around 100K. Also a minimum of 128 bytes is required on
+       * Linux. */
+      if (!g_socket_set_option (src->used_socket, SOL_SOCKET, SO_RCVBUF,
+              src->buffer_size, &opt_err)) {
+        GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL),
+            ("Could not create a buffer of requested %d bytes: %s",
+                src->buffer_size, opt_err->message));
+        g_error_free (opt_err);
+        opt_err = NULL;
+      }
+    }
+
+    /* read the value of the receive buffer. Note that on linux this returns
+     * 2x the value we set because the kernel allocates extra memory for
+     * metadata. The default on Linux is about 100K (which is about 50K
+     * without metadata) */
+    if (g_socket_get_option (src->used_socket, SOL_SOCKET, SO_RCVBUF, &val,
+            NULL)) {
+      GST_INFO_OBJECT (src, "have udp buffer of %d bytes", val);
+    } else {
+      GST_DEBUG_OBJECT (src, "could not get udp buffer size");
+    }
+  }
+
+  g_socket_set_broadcast (src->used_socket, TRUE);
+
+  if (src->auto_multicast
+      &&
+      g_inet_address_get_is_multicast (g_inet_socket_address_get_address
+          (src->addr))) {
+
+    if (src->multi_iface) {
+      GStrv multi_ifaces = g_strsplit (src->multi_iface, ",", -1);
+      gchar **ifaces = multi_ifaces;
+      while (*ifaces) {
+        g_strstrip (*ifaces);
+        GST_DEBUG_OBJECT (src, "joining multicast group %s interface %s",
+            src->address, *ifaces);
+        if (!g_socket_join_multicast_group (src->used_socket,
+                g_inet_socket_address_get_address (src->addr),
+                FALSE, *ifaces, &err)) {
+          g_strfreev (multi_ifaces);
+          goto membership;
+        }
+
+        ifaces++;
+      }
+      g_strfreev (multi_ifaces);
+    } else {
+      GST_DEBUG_OBJECT (src, "joining multicast group %s", src->address);
+      if (!g_socket_join_multicast_group (src->used_socket,
+              g_inet_socket_address_get_address (src->addr), FALSE, NULL, &err))
+        goto membership;
+    }
+
+    if (g_inet_address_get_family (g_inet_socket_address_get_address
+            (src->addr)) == G_SOCKET_FAMILY_IPV4) {
+#if defined(IP_MULTICAST_ALL)
+      if (!g_socket_set_option (src->used_socket, IPPROTO_IP, IP_MULTICAST_ALL,
+              0, &err)) {
+        GST_WARNING_OBJECT (src, "Failed to disable IP_MULTICAST_ALL: %s",
+            err->message);
+        g_clear_error (&err);
+      }
+#elif defined(IP_PKTINFO)
+      if (!g_socket_set_option (src->used_socket, IPPROTO_IP, IP_PKTINFO, TRUE,
+              &err)) {
+        GST_WARNING_OBJECT (src, "Failed to enable IP_PKTINFO: %s",
+            err->message);
+        g_clear_error (&err);
+      }
+#elif defined(IP_RECVDSTADDR)
+      if (!g_socket_set_option (src->used_socket, IPPROTO_IP, IP_RECVDSTADDR,
+              TRUE, &err)) {
+        GST_WARNING_OBJECT (src, "Failed to enable IP_RECVDSTADDR: %s",
+            err->message);
+        g_clear_error (&err);
+      }
+#else
+#pragma message("No API available for getting IPv4 destination address")
+      GST_WARNING_OBJECT (src, "No API available for getting IPv4 destination "
+          "address, will receive packets for every destination to our port");
+#endif
+    } else
+        if (g_inet_address_get_family (g_inet_socket_address_get_address
+            (src->addr)) == G_SOCKET_FAMILY_IPV6) {
+#ifdef IPV6_PKTINFO
+#ifdef IPV6_RECVPKTINFO
+      if (!g_socket_set_option (src->used_socket, IPPROTO_IPV6,
+              IPV6_RECVPKTINFO, TRUE, &err)) {
+#else
+      if (!g_socket_set_option (src->used_socket, IPPROTO_IPV6, IPV6_PKTINFO,
+              TRUE, &err)) {
+#endif
+        GST_WARNING_OBJECT (src, "Failed to enable IPV6_PKTINFO: %s",
+            err->message);
+        g_clear_error (&err);
+      }
+#else
+#pragma message("No API available for getting IPv6 destination address")
+      GST_WARNING_OBJECT (src, "No API available for getting IPv6 destination "
+          "address, will receive packets for every destination to our port");
+#endif
+    }
+  }
+
+  /* NOTE: sockaddr_in.sin_port works for ipv4 and ipv6 because sin_port
+   * follows ss_family on both */
+  {
+    GInetSocketAddress *addr;
+    guint16 port;
+
+    addr =
+        G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket,
+            &err));
+    if (!addr)
+      goto getsockname_error;
+
+    port = g_inet_socket_address_get_port (addr);
+    GST_DEBUG_OBJECT (src, "bound, on port %d", port);
+    if (port != src->port) {
+      src->port = port;
+      GST_DEBUG_OBJECT (src, "notifying port %d", port);
+      g_object_notify (G_OBJECT (src), "port");
+    }
+    g_object_unref (addr);
+  }
+
+  src->allocator = NULL;
+  gst_allocation_params_init (&src->params);
+
+  src->max_size = 0;
+
+  return TRUE;
+
+  /* ERRORS */
+name_resolve:
+  {
+    return FALSE;
+  }
+no_socket:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
+        ("no socket error: %s", err->message));
+    g_clear_error (&err);
+    g_object_unref (addr);
+    return FALSE;
+  }
+bind_error:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+        ("bind failed: %s", err->message));
+    g_clear_error (&err);
+    g_object_unref (bind_saddr);
+    gst_udpsrc_close (src);
+    return FALSE;
+  }
+membership:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+        ("could not add membership: %s", err->message));
+    g_clear_error (&err);
+    gst_udpsrc_close (src);
+    return FALSE;
+  }
+getsockname_error:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+        ("getsockname failed: %s", err->message));
+    g_clear_error (&err);
+    gst_udpsrc_close (src);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_udpsrc_unlock (GstBaseSrc * bsrc)
+{
+  GstUDPSrc *src;
+
+  src = GST_UDPSRC (bsrc);
+
+  GST_LOG_OBJECT (src, "Flushing");
+  g_cancellable_cancel (src->cancellable);
+
+  return TRUE;
+}
+
+static gboolean
+gst_udpsrc_unlock_stop (GstBaseSrc * bsrc)
+{
+  GstUDPSrc *src;
+
+  src = GST_UDPSRC (bsrc);
+
+  GST_LOG_OBJECT (src, "No longer flushing");
+
+  gst_udpsrc_free_cancellable (src);
+  gst_udpsrc_create_cancellable (src);
+
+  return TRUE;
+}
+
+static gboolean
+gst_udpsrc_close (GstUDPSrc * src)
+{
+  GST_DEBUG ("closing sockets");
+
+  if (src->used_socket) {
+    if (src->auto_multicast
+        &&
+        g_inet_address_get_is_multicast (g_inet_socket_address_get_address
+            (src->addr))) {
+      GError *err = NULL;
+
+      if (src->multi_iface) {
+        GStrv multi_ifaces = g_strsplit (src->multi_iface, ",", -1);
+        gchar **ifaces = multi_ifaces;
+        while (*ifaces) {
+          g_strstrip (*ifaces);
+          GST_DEBUG_OBJECT (src, "leaving multicast group %s interface %s",
+              src->address, *ifaces);
+          if (!g_socket_leave_multicast_group (src->used_socket,
+                  g_inet_socket_address_get_address (src->addr),
+                  FALSE, *ifaces, &err)) {
+            GST_ERROR_OBJECT (src, "Failed to leave multicast group: %s",
+                err->message);
+            g_clear_error (&err);
+          }
+          ifaces++;
+        }
+        g_strfreev (multi_ifaces);
+
+      } else {
+        GST_DEBUG_OBJECT (src, "leaving multicast group %s", src->address);
+        if (!g_socket_leave_multicast_group (src->used_socket,
+                g_inet_socket_address_get_address (src->addr), FALSE,
+                NULL, &err)) {
+          GST_ERROR_OBJECT (src, "Failed to leave multicast group: %s",
+              err->message);
+          g_clear_error (&err);
+        }
+      }
+    }
+
+    if (src->close_socket || !src->external_socket) {
+      GError *err = NULL;
+      if (!g_socket_close (src->used_socket, &err)) {
+        GST_ERROR_OBJECT (src, "Failed to close socket: %s", err->message);
+        g_clear_error (&err);
+      }
+    }
+
+    g_object_unref (src->used_socket);
+    src->used_socket = NULL;
+    g_object_unref (src->addr);
+    src->addr = NULL;
+  }
+
+  gst_udpsrc_reset_memory_allocator (src);
+
+  gst_udpsrc_free_cancellable (src);
+
+  return TRUE;
+}
+
+
+static GstStateChangeReturn
+gst_udpsrc_change_state (GstElement * element, GstStateChange transition)
+{
+  GstUDPSrc *src;
+  GstStateChangeReturn result;
+
+  src = GST_UDPSRC (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      if (!gst_udpsrc_open (src))
+        goto open_failed;
+      break;
+    default:
+      break;
+  }
+  if ((result =
+          GST_ELEMENT_CLASS (parent_class)->change_state (element,
+              transition)) == GST_STATE_CHANGE_FAILURE)
+    goto failure;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      gst_udpsrc_close (src);
+      break;
+    default:
+      break;
+  }
+  return result;
+  /* ERRORS */
+open_failed:
+  {
+    GST_DEBUG_OBJECT (src, "failed to open socket");
+    return GST_STATE_CHANGE_FAILURE;
+  }
+failure:
+  {
+    GST_DEBUG_OBJECT (src, "parent failed state change");
+    return result;
+  }
+}
+
+
+
+
+/*** GSTURIHANDLER INTERFACE *************************************************/
+
+static GstURIType
+gst_udpsrc_uri_get_type (GType type)
+{
+  return GST_URI_SRC;
+}
+
+static const gchar *const *
+gst_udpsrc_uri_get_protocols (GType type)
+{
+  static const gchar *protocols[] = { "udp", NULL };
+
+  return protocols;
+}
+
+static gchar *
+gst_udpsrc_uri_get_uri (GstURIHandler * handler)
+{
+  GstUDPSrc *src = GST_UDPSRC (handler);
+
+  return g_strdup (src->uri);
+}
+
+static gboolean
+gst_udpsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+    GError ** error)
+{
+  return gst_udpsrc_set_uri (GST_UDPSRC (handler), uri, error);
+}
+
+static void
+gst_udpsrc_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+  iface->get_type = gst_udpsrc_uri_get_type;
+  iface->get_protocols = gst_udpsrc_uri_get_protocols;
+  iface->get_uri = gst_udpsrc_uri_get_uri;
+  iface->set_uri = gst_udpsrc_uri_set_uri;
+}
diff --git a/gst/udp/gstudpsrc.h b/gst/udp/gstudpsrc.h
new file mode 100644
index 0000000..96f844b
--- /dev/null
+++ b/gst/udp/gstudpsrc.h
@@ -0,0 +1,99 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_UDPSRC_H__
+#define __GST_UDPSRC_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#include "gstudpnetutils.h"
+
+#define GST_TYPE_UDPSRC \
+  (gst_udpsrc_get_type())
+#define GST_UDPSRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_UDPSRC,GstUDPSrc))
+#define GST_UDPSRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_UDPSRC,GstUDPSrcClass))
+#define GST_IS_UDPSRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_UDPSRC))
+#define GST_IS_UDPSRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_UDPSRC))
+#define GST_UDPSRC_CAST(obj) ((GstUDPSrc *)(obj))
+
+typedef struct _GstUDPSrc GstUDPSrc;
+typedef struct _GstUDPSrcClass GstUDPSrcClass;
+
+struct _GstUDPSrc {
+  GstPushSrc parent;
+
+  /* properties */
+  gchar     *address;
+  gint       port;
+  gchar     *multi_iface;
+  gint       ttl;
+  GstCaps   *caps;
+  gint       buffer_size;
+  guint64    timeout;
+  gint       skip_first_bytes;
+  GSocket   *socket;
+  gboolean   close_socket;
+  gboolean   auto_multicast;
+  gboolean   reuse;
+  gboolean   loop;
+  gboolean   retrieve_sender_address;
+
+  /* stats */
+  guint      max_size;
+
+  /* our sockets */
+  GSocket   *used_socket;
+  GInetSocketAddress *addr;
+  gboolean   external_socket;
+
+  gboolean   made_cancel_fd;
+  GCancellable *cancellable;
+
+  /* memory management */
+  GstAllocator *allocator;
+  GstAllocationParams params;
+
+  GstMemory   *mem;
+  GstMapInfo   map;
+  GstMemory   *mem_max;
+  GstMapInfo   map_max;
+  GInputVector vec[2];
+
+  gchar     *uri;
+};
+
+struct _GstUDPSrcClass {
+  GstPushSrcClass parent_class;
+};
+
+GType gst_udpsrc_get_type(void);
+
+G_END_DECLS
+
+
+#endif /* __GST_UDPSRC_H__ */
diff --git a/gst/udp/meson.build b/gst/udp/meson.build
new file mode 100644
index 0000000..2fc576d
--- /dev/null
+++ b/gst/udp/meson.build
@@ -0,0 +1,17 @@
+udp_sources = [
+  'gstudp.c',
+  'gstudpsrc.c',
+  'gstudpsink.c',
+  'gstmultiudpsink.c',
+  'gstdynudpsink.c',
+  'gstudpnetutils.c'
+]
+
+gstudp = library('gstudp',
+  udp_sources,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc, libsinc],
+  dependencies : [gst_dep, gstbase_dep, gstnet_dep, gio_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/videobox/Makefile.am b/gst/videobox/Makefile.am
new file mode 100644
index 0000000..f4b5a10
--- /dev/null
+++ b/gst/videobox/Makefile.am
@@ -0,0 +1,20 @@
+plugin_LTLIBRARIES = libgstvideobox.la
+
+ORC_SOURCE=gstvideoboxorc
+include $(top_srcdir)/common/orc.mak
+
+libgstvideobox_la_SOURCES = gstvideobox.c
+nodist_libgstvideobox_la_SOURCES = $(ORC_NODIST_SOURCES)
+libgstvideobox_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
+			   $(GST_BASE_CFLAGS) \
+			   $(GST_CFLAGS) \
+			   $(ORC_CFLAGS)
+libgstvideobox_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+			   $(GST_BASE_LIBS) \
+			   $(GST_LIBS) \
+			   $(ORC_LIBS) \
+			   -lgstvideo-@GST_API_VERSION@
+libgstvideobox_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstvideobox.h
+EXTRA_DIST += README
diff --git a/gst/videobox/README b/gst/videobox/README
new file mode 100644
index 0000000..e71da59
--- /dev/null
+++ b/gst/videobox/README
@@ -0,0 +1,21 @@
+Videobox
+--------
+
+This plugin crops or enlarges the image. It takes 4 values as input, a
+top, bottom, left and right offset. Positive values will crop that much
+pixels from the respective border of the image, negative values will add
+that much pixels. When pixels are added, you can specify their color. 
+Some predefined colors are usable with an enum property.
+
+The plugin is alpha channel aware and will try to negotiate with a format
+that supports alpha channels first. When alpha channel is active two
+other properties, alpha and border_alpha can be used to set the alpha
+values of the inner picture and the border respectively. an alpha value of
+0.0 means total transparency, 1.0 is opaque.
+
+The videobox plugin has many uses such as doing a mosaic of pictures, 
+letterboxing video, cutting out pieces of video, picture in picture, etc..
+
+TODO
+
+- add enum to specify common aspect ratios/sizes and add borders/crop
diff --git a/gst/videobox/gstvideobox.c b/gst/videobox/gstvideobox.c
new file mode 100644
index 0000000..f8f984c
--- /dev/null
+++ b/gst/videobox/gstvideobox.c
@@ -0,0 +1,3347 @@
+/* GStreamer
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-videobox
+ * @see_also: #GstVideoCrop
+ *
+ * This plugin crops or enlarges the image. It takes 4 values as input, a
+ * top, bottom, left and right offset. Positive values will crop that much
+ * pixels from the respective border of the image, negative values will add
+ * that much pixels. When pixels are added, you can specify their color. 
+ * Some predefined colors are usable with an enum property.
+ * 
+ * The plugin is alpha channel aware and will try to negotiate with a format
+ * that supports alpha channels first. When alpha channel is active two
+ * other properties, alpha and border_alpha can be used to set the alpha
+ * values of the inner picture and the border respectively. an alpha value of
+ * 0.0 means total transparency, 1.0 is opaque.
+ * 
+ * The videobox plugin has many uses such as doing a mosaic of pictures, 
+ * letterboxing video, cutting out pieces of video, picture in picture, etc..
+ *
+ * Setting autocrop to true changes the behavior of the plugin so that
+ * caps determine crop properties rather than the other way around: given
+ * input and output dimensions, the crop values are selected so that the
+ * smaller frame is effectively centered in the larger frame.  This
+ * involves either cropping or padding.
+ * 
+ * If you use autocrop there is little point in setting the other
+ * properties manually because they will be overriden if the caps change,
+ * but nothing stops you from doing so.
+ * 
+ * Sample pipeline:
+ * |[
+ * gst-launch-1.0 videotestsrc ! videobox autocrop=true ! \
+ *   "video/x-raw, width=600, height=400" ! videoconvert ! ximagesink
+ * ]|
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstvideobox.h"
+#include "gstvideoboxorc.h"
+
+#include <math.h>
+#include <string.h>
+
+GST_DEBUG_CATEGORY_STATIC (videobox_debug);
+#define GST_CAT_DEFAULT videobox_debug
+
+/* From videotestsrc.c */
+static const guint8 yuv_sdtv_colors_Y[VIDEO_BOX_FILL_LAST] =
+    { 16, 145, 41, 81, 210, 235 };
+static const guint8 yuv_sdtv_colors_U[VIDEO_BOX_FILL_LAST] =
+    { 128, 54, 240, 90, 16, 128 };
+static const guint8 yuv_sdtv_colors_V[VIDEO_BOX_FILL_LAST] =
+    { 128, 34, 110, 240, 146, 128 };
+
+static const guint8 yuv_hdtv_colors_Y[VIDEO_BOX_FILL_LAST] =
+    { 16, 173, 32, 63, 219, 235 };
+static const guint8 yuv_hdtv_colors_U[VIDEO_BOX_FILL_LAST] =
+    { 128, 42, 240, 102, 16, 128 };
+static const guint8 yuv_hdtv_colors_V[VIDEO_BOX_FILL_LAST] =
+    { 128, 26, 118, 240, 138, 128 };
+
+static const guint8 rgb_colors_R[VIDEO_BOX_FILL_LAST] =
+    { 0, 0, 0, 255, 255, 255 };
+static const guint8 rgb_colors_G[VIDEO_BOX_FILL_LAST] =
+    { 0, 255, 0, 0, 255, 255 };
+static const guint8 rgb_colors_B[VIDEO_BOX_FILL_LAST] =
+    { 0, 0, 255, 0, 0, 255 };
+
+/* Generated by -bad/ext/cog/generate_tables */
+static const int cog_ycbcr_to_rgb_matrix_8bit_hdtv[] = {
+  298, 0, 459, -63514,
+  298, -55, -136, 19681,
+  298, 541, 0, -73988,
+};
+
+static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
+  298, 0, 409, -57068,
+  298, -100, -208, 34707,
+  298, 516, 0, -70870,
+};
+
+static const gint cog_rgb_to_ycbcr_matrix_8bit_hdtv[] = {
+  47, 157, 16, 4096,
+  -26, -87, 112, 32768,
+  112, -102, -10, 32768,
+};
+
+static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
+  66, 129, 25, 4096,
+  -38, -74, 112, 32768,
+  112, -94, -18, 32768,
+};
+
+static const gint cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit[] = {
+  256, -30, -53, 10600,
+  0, 261, 29, -4367,
+  0, 19, 262, -3289,
+};
+
+static const gint cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit[] = {
+  256, 25, 49, -9536,
+  0, 253, -28, 3958,
+  0, -19, 252, 2918,
+};
+
+static const gint cog_identity_matrix_8bit[] = {
+  256, 0, 0, 0,
+  0, 256, 0, 0,
+  0, 0, 256, 0,
+};
+
+#define APPLY_MATRIX(m,o,v1,v2,v3) ((m[o*4] * v1 + m[o*4+1] * v2 + m[o*4+2] * v3 + m[o*4+3]) >> 8)
+
+static void
+fill_ayuv (GstVideoBoxFill fill_type, guint b_alpha,
+    GstVideoFrame * frame, gboolean sdtv)
+{
+  guint32 empty_pixel;
+  guint8 *dest;
+  gint width, height;
+  gint stride;
+
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
+
+  b_alpha = CLAMP (b_alpha, 0, 255);
+
+  if (sdtv)
+    empty_pixel = GUINT32_FROM_BE ((b_alpha << 24) |
+        (yuv_sdtv_colors_Y[fill_type] << 16) |
+        (yuv_sdtv_colors_U[fill_type] << 8) | yuv_sdtv_colors_V[fill_type]);
+  else
+    empty_pixel = GUINT32_FROM_BE ((b_alpha << 24) |
+        (yuv_hdtv_colors_Y[fill_type] << 16) |
+        (yuv_hdtv_colors_U[fill_type] << 8) | yuv_hdtv_colors_V[fill_type]);
+
+  dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+
+  if (G_LIKELY (stride == 4 * width))
+    video_box_orc_splat_u32 ((guint32 *) dest, empty_pixel, width * height);
+  else if (height) {
+    for (; height; --height) {
+      video_box_orc_splat_u32 ((guint32 *) dest, empty_pixel, width);
+      dest += stride;
+    }
+  }
+}
+
+static void
+copy_ayuv_ayuv (guint i_alpha, GstVideoFrame * dest_frame,
+    gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src_frame,
+    gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
+{
+  gint i, j;
+  gint src_stride;
+  gint dest_stride;
+  guint8 *dest, *src;
+
+  src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src_frame, 0);
+  dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest_frame, 0);
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (src_frame, 0);
+  dest = GST_VIDEO_FRAME_PLANE_DATA (dest_frame, 0);
+
+  dest = dest + dest_y * dest_stride + dest_x * 4;
+  src = src + src_y * src_stride + src_x * 4;
+
+  w *= 4;
+
+  if (dest_sdtv != src_sdtv) {
+    gint matrix[12];
+    gint y, u, v;
+
+    memcpy (matrix,
+        dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j += 4) {
+        /* ORC FIXME */
+        dest[j] = (src[j] * i_alpha) >> 8;
+        y = src[j + 1];
+        u = src[j + 2];
+        v = src[j + 3];
+        dest[j + 1] = APPLY_MATRIX (matrix, 0, y, u, v);
+        dest[j + 2] = APPLY_MATRIX (matrix, 1, y, u, v);
+        dest[j + 3] = APPLY_MATRIX (matrix, 2, y, u, v);
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  } else {
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j += 4) {
+        /* ORC FIXME */
+        dest[j] = (src[j] * i_alpha) >> 8;
+        dest[j + 1] = src[j + 1];
+        dest[j + 2] = src[j + 2];
+        dest[j + 3] = src[j + 3];
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  }
+}
+
+static void
+copy_ayuv_i420 (guint i_alpha, GstVideoFrame * dest_frame,
+    gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src_frame,
+    gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
+{
+  gint i, j;
+  guint8 *destY, *destY2, *destU, *destV;
+  gint dest_strideY, dest_strideU, dest_strideV;
+  const guint8 *src2;
+  gint src_stride;
+  gint y_idx, uv_idx;
+  gint y1, y2, y3, y4;
+  gint u1, u2, u3, u4;
+  gint v1, v2, v3, v4;
+  gint matrix[12];
+  guint8 *src;
+  gint dest_height, src_height, dest_width;
+
+  dest_height = GST_VIDEO_FRAME_HEIGHT (dest_frame);
+  dest_width = GST_VIDEO_FRAME_WIDTH (dest_frame);
+  src_height = GST_VIDEO_FRAME_HEIGHT (src_frame);
+
+  dest_strideY = GST_VIDEO_FRAME_COMP_STRIDE (dest_frame, 0);
+  dest_strideU = GST_VIDEO_FRAME_COMP_STRIDE (dest_frame, 1);
+  dest_strideV = GST_VIDEO_FRAME_COMP_STRIDE (dest_frame, 2);
+
+  src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src_frame, 0);
+
+  destY = GST_VIDEO_FRAME_COMP_DATA (dest_frame, 0);
+  destU = GST_VIDEO_FRAME_COMP_DATA (dest_frame, 1);
+  destV = GST_VIDEO_FRAME_COMP_DATA (dest_frame, 2);
+
+  destY = destY + dest_y * dest_strideY + dest_x;
+  destY2 = (dest_y < dest_height) ? destY + dest_strideY : destY;
+  destU = destU + (dest_y / 2) * dest_strideU + dest_x / 2;
+  destV = destV + (dest_y / 2) * dest_strideV + dest_x / 2;
+
+  src = GST_VIDEO_FRAME_PLANE_DATA (src_frame, 0);
+  src = src + src_y * src_stride + src_x * 4;
+  src2 = (src_y < src_height) ? src + src_stride : src;
+
+  h = dest_y + h;
+  w = dest_x + w;
+
+  if (src_sdtv != dest_sdtv)
+    memcpy (matrix,
+        dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+  else
+    memcpy (matrix, cog_identity_matrix_8bit, 12 * sizeof (gint));
+
+  /* 1. Handle the first destination scanline specially if it
+   *    doesn't start at the macro pixel boundary, i.e. blend
+   *    with the background! */
+  if (dest_y % 2 == 1) {
+    /* 1.1. Handle the first destination pixel if it doesn't
+     *      start at the macro pixel boundary, i.e. blend with
+     *      the background! */
+    if (dest_x % 2 == 1) {
+      y1 = src[4 * 0 + 1];
+      u1 = src[4 * 0 + 2];
+      v1 = src[4 * 0 + 3];
+
+      destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[0] =
+          CLAMP ((3 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
+          255);
+      destV[0] =
+          CLAMP ((3 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4, 0,
+          255);
+
+      j = dest_x + 1;
+      y_idx = uv_idx = 1;
+    } else {
+      j = dest_x;
+      y_idx = uv_idx = 0;
+    }
+
+    /* 1.2. Copy all macro pixels from the source to the destination
+     *      but blend with the background because we're only filling
+     *      the lower part of the macro pixels. */
+    for (; j < w - 1; j += 2) {
+      y1 = src[4 * y_idx + 1];
+      y2 = src[4 * y_idx + 4 + 1];
+
+      u1 = src[4 * y_idx + 2];
+      u2 = src[4 * y_idx + 4 + 2];
+
+      v1 = src[4 * y_idx + 3];
+      v2 = src[4 * y_idx + 4 + 3];
+
+      destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[y_idx + 1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+      destU[uv_idx] = CLAMP (
+          (2 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
+      destV[uv_idx] = CLAMP (
+          (2 * destV[uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
+
+      y_idx += 2;
+      uv_idx++;
+    }
+
+    /* 1.3. Now copy the last pixel if one exists and blend it
+     *      with the background because we only fill part of
+     *      the macro pixel. In case this is the last pixel of
+     *      the destination we will a larger part. */
+    if (j == w - 1 && j == dest_width - 1) {
+      y1 = src[4 * y_idx + 1];
+      u1 = src[4 * y_idx + 2];
+      v1 = src[4 * y_idx + 3];
+
+      destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[uv_idx] = CLAMP (
+          (destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
+      destV[uv_idx] = CLAMP (
+          (destV[uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 2, 0, 255);
+    } else if (j == w - 1) {
+      y1 = src[4 * y_idx + 1];
+      u1 = src[4 * y_idx + 2];
+      v1 = src[4 * y_idx + 3];
+
+      destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[uv_idx] = CLAMP (
+          (3 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
+          255);
+      destV[uv_idx] =
+          CLAMP ((3 * destV[uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4,
+          0, 255);
+    }
+
+    destY += dest_strideY;
+    destY2 += dest_strideY;
+    destU += dest_strideU;
+    destV += dest_strideV;
+    src += src_stride;
+    src2 += src_stride;
+    i = dest_y + 1;
+  } else {
+    i = dest_y;
+  }
+
+  /* 2. Copy all macro pixel scanlines, the destination scanline
+   *    now starts at macro pixel boundary. */
+  for (; i < h - 1; i += 2) {
+    /* 2.1. Handle the first destination pixel if it doesn't
+     *      start at the macro pixel boundary, i.e. blend with
+     *      the background! */
+    if (dest_x % 2 == 1) {
+      y1 = src[4 * 0 + 1];
+      y2 = src2[4 * 0 + 1];
+      u1 = src[4 * 0 + 2];
+      u2 = src2[4 * 0 + 2];
+      v1 = src[4 * 0 + 3];
+      v2 = src2[4 * 0 + 3];
+
+      destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY2[0] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+      destU[0] = CLAMP (
+          (2 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
+      destV[0] = CLAMP (
+          (2 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
+      j = dest_x + 1;
+      y_idx = uv_idx = 1;
+    } else {
+      j = dest_x;
+      y_idx = uv_idx = 0;
+    }
+
+    /* 2.2. Copy all macro pixels from the source to the destination.
+     *      All pixels now start at macro pixel boundary, i.e. no
+     *      blending with the background is necessary. */
+    for (; j < w - 1; j += 2) {
+      y1 = src[4 * y_idx + 1];
+      y2 = src[4 * y_idx + 4 + 1];
+      y3 = src2[4 * y_idx + 1];
+      y4 = src2[4 * y_idx + 4 + 1];
+
+      u1 = src[4 * y_idx + 2];
+      u2 = src[4 * y_idx + 4 + 2];
+      u3 = src2[4 * y_idx + 2];
+      u4 = src2[4 * y_idx + 4 + 2];
+
+      v1 = src[4 * y_idx + 3];
+      v2 = src[4 * y_idx + 4 + 3];
+      v3 = src2[4 * y_idx + 3];
+      v4 = src2[4 * y_idx + 4 + 3];
+
+      destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[y_idx + 1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+      destY2[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y3, u3, v3), 0, 255);
+      destY2[y_idx + 1] = CLAMP (APPLY_MATRIX (matrix, 0, y4, u4, v4), 0, 255);
+
+      destU[uv_idx] = CLAMP (
+          (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 1, y2,
+                  u2, v2) + APPLY_MATRIX (matrix, 1, y3, u3,
+                  v3) + APPLY_MATRIX (matrix, 1, y4, u4, v4)) / 4, 0, 255);
+      destV[uv_idx] = CLAMP (
+          (APPLY_MATRIX (matrix, 2, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
+                  u2, v2) + APPLY_MATRIX (matrix, 2, y3, u3,
+                  v3) + APPLY_MATRIX (matrix, 2, y4, u4, v4)) / 4, 0, 255);
+
+      y_idx += 2;
+      uv_idx++;
+    }
+
+    /* 2.3. Now copy the last pixel if one exists and blend it
+     *      with the background because we only fill part of
+     *      the macro pixel. In case this is the last pixel of
+     *      the destination we will a larger part. */
+    if (j == w - 1 && j == dest_width - 1) {
+      y1 = src[4 * y_idx + 1];
+      y2 = src2[4 * y_idx + 1];
+
+      u1 = src[4 * y_idx + 2];
+      u2 = src2[4 * y_idx + 2];
+
+      v1 = src[4 * y_idx + 3];
+      v2 = src2[4 * y_idx + 3];
+
+      destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY2[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+      destU[uv_idx] = CLAMP (
+          (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
+                  u2, v2)) / 2, 0, 255);
+      destV[uv_idx] = CLAMP (
+          (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
+                  u2, v2)) / 2, 0, 255);
+    } else if (j == w - 1) {
+      y1 = src[4 * y_idx + 1];
+      y2 = src2[4 * y_idx + 1];
+
+      u1 = src[4 * y_idx + 2];
+      u2 = src2[4 * y_idx + 2];
+
+      v1 = src[4 * y_idx + 3];
+      v2 = src2[4 * y_idx + 3];
+
+      destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY2[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+      destU[uv_idx] = CLAMP (
+          (2 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
+      destV[uv_idx] = CLAMP (
+          (2 * destV[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
+    }
+
+    destY += 2 * dest_strideY;
+    destY2 += 2 * dest_strideY;
+    destU += dest_strideU;
+    destV += dest_strideV;
+    src += 2 * src_stride;
+    src2 += 2 * src_stride;
+  }
+
+  /* 3. Handle the last scanline if one exists. This again
+   *    doesn't start at macro pixel boundary but should
+   *    only fill the upper part of the macro pixels. */
+  if (i == h - 1 && i == dest_height - 1) {
+    /* 3.1. Handle the first destination pixel if it doesn't
+     *      start at the macro pixel boundary, i.e. blend with
+     *      the background! */
+    if (dest_x % 2 == 1) {
+      y1 = src[4 * 0 + 1];
+      u1 = src[4 * 0 + 2];
+      v1 = src[4 * 0 + 3];
+
+      destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[0] =
+          CLAMP ((destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
+      destV[0] =
+          CLAMP ((destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 2, 0, 255);
+
+      j = dest_x + 1;
+      y_idx = uv_idx = 1;
+    } else {
+      j = dest_x;
+      y_idx = uv_idx = 0;
+    }
+
+    /* 3.2. Copy all macro pixels from the source to the destination
+     *      but blend with the background because we're only filling
+     *      the upper part of the macro pixels. */
+    for (; j < w - 1; j += 2) {
+      y1 = src[4 * y_idx + 1];
+      y2 = src[4 * y_idx + 4 + 1];
+
+      u1 = src[4 * y_idx + 2];
+      u2 = src[4 * y_idx + 4 + 2];
+
+      v1 = src[4 * y_idx + 3];
+      v2 = src[4 * y_idx + 4 + 3];
+
+      destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[y_idx + 1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+
+      destU[uv_idx] = CLAMP (
+          (2 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
+      destV[uv_idx] = CLAMP (
+          (2 * destV[uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
+
+      y_idx += 2;
+      uv_idx++;
+    }
+
+    /* 3.3. Now copy the last pixel if one exists and blend it
+     *      with the background because we only fill part of
+     *      the macro pixel. In case this is the last pixel of
+     *      the destination we will a larger part. */
+    if (j == w - 1 && j == dest_width - 1) {
+      y1 = src[4 * y_idx + 1];
+      u1 = src[4 * y_idx + 2];
+      v1 = src[4 * y_idx + 3];
+
+      destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[uv_idx] = CLAMP (
+          (destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
+      destV[uv_idx] = CLAMP (
+          (destV[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
+    } else if (j == w - 1) {
+      y1 = src[4 * y_idx + 1];
+      u1 = src[4 * y_idx + 2];
+      v1 = src[4 * y_idx + 3];
+
+      destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[uv_idx] = CLAMP (
+          (3 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
+          255);
+      destV[uv_idx] =
+          CLAMP ((3 * destV[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4,
+          0, 255);
+    }
+  } else if (i == h - 1) {
+    /* 3.1. Handle the first destination pixel if it doesn't
+     *      start at the macro pixel boundary, i.e. blend with
+     *      the background! */
+    if (dest_x % 2 == 1) {
+      y1 = src[4 * 0 + 1];
+      u1 = src[4 * 0 + 2];
+      v1 = src[4 * 0 + 3];
+
+      destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[0] =
+          CLAMP ((3 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
+          255);
+      destV[0] =
+          CLAMP ((3 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4, 0,
+          255);
+
+      j = dest_x + 1;
+      y_idx = uv_idx = 1;
+    } else {
+      j = dest_x;
+      y_idx = uv_idx = 0;
+    }
+
+    /* 3.2. Copy all macro pixels from the source to the destination
+     *      but blend with the background because we're only filling
+     *      the upper part of the macro pixels. */
+    for (; j < w - 1; j += 2) {
+      y1 = src[4 * y_idx + 1];
+      y2 = src[4 * y_idx + 4 + 1];
+
+      u1 = src[4 * y_idx + 2];
+      u2 = src[4 * y_idx + 4 + 2];
+
+      v1 = src[4 * y_idx + 3];
+      v2 = src[4 * y_idx + 4 + 3];
+
+      destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[y_idx + 1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+
+      destU[uv_idx] = CLAMP (
+          (2 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
+      destV[uv_idx] = CLAMP (
+          (2 * destV[uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
+
+      y_idx += 2;
+      uv_idx++;
+    }
+
+    /* 3.3. Now copy the last pixel if one exists and blend it
+     *      with the background because we only fill part of
+     *      the macro pixel. In case this is the last pixel of
+     *      the destination we will a larger part. */
+    if (j == w - 1 && j == dest_width - 1) {
+      y1 = src[4 * y_idx + 1];
+      u1 = src[4 * y_idx + 2];
+      v1 = src[4 * y_idx + 3];
+
+      destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[uv_idx] = CLAMP (
+          (destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
+      destV[uv_idx] = CLAMP (
+          (destV[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
+    } else if (j == w - 1) {
+      y1 = src[4 * y_idx + 1];
+      u1 = src[4 * y_idx + 2];
+      v1 = src[4 * y_idx + 3];
+
+      destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[uv_idx] = CLAMP (
+          (3 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
+          255);
+      destV[uv_idx] =
+          CLAMP ((3 * destV[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4,
+          0, 255);
+    }
+  }
+}
+
+static void
+fill_planar_yuv (GstVideoBoxFill fill_type, guint b_alpha,
+    GstVideoFrame * frame, gboolean sdtv)
+{
+  guint8 empty_pixel[3];
+  guint8 *destY, *destU, *destV;
+  gint strideY, strideU, strideV;
+  gint heightY, heightU, heightV;
+  gint widthY, widthU, widthV;
+
+  if (sdtv) {
+    empty_pixel[0] = yuv_sdtv_colors_Y[fill_type];
+    empty_pixel[1] = yuv_sdtv_colors_U[fill_type];
+    empty_pixel[2] = yuv_sdtv_colors_V[fill_type];
+  } else {
+    empty_pixel[0] = yuv_hdtv_colors_Y[fill_type];
+    empty_pixel[1] = yuv_hdtv_colors_U[fill_type];
+    empty_pixel[2] = yuv_hdtv_colors_V[fill_type];
+  }
+
+  strideY = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
+  strideU = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1);
+  strideV = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2);
+
+  destY = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
+  destU = GST_VIDEO_FRAME_COMP_DATA (frame, 1);
+  destV = GST_VIDEO_FRAME_COMP_DATA (frame, 2);
+
+  widthY = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0);
+  widthU = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1);
+  widthV = GST_VIDEO_FRAME_COMP_WIDTH (frame, 2);
+
+  heightY = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0);
+  heightU = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1);
+  heightV = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 2);
+
+  if (strideY == widthY) {
+    memset (destY, empty_pixel[0], strideY * heightY);
+  } else if (heightY) {
+    for (; heightY; --heightY) {
+      memset (destY, empty_pixel[0], widthY);
+      destY += strideY;
+    }
+  }
+  if (strideU == widthU) {
+    memset (destU, empty_pixel[1], strideU * heightU);
+  } else if (heightU) {
+    for (; heightU; --heightU) {
+      memset (destU, empty_pixel[1], widthU);
+      destU += strideU;
+    }
+  }
+  if (strideV == widthV) {
+    memset (destV, empty_pixel[2], strideV * heightV);
+  } else if (heightV) {
+    for (; heightV; --heightV) {
+      memset (destV, empty_pixel[2], widthV);
+      destV += strideV;
+    }
+  }
+}
+
+static void
+copy_y444_y444 (guint i_alpha, GstVideoFrame * dest,
+    gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src,
+    gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
+{
+  gint i, j;
+  guint8 *destY, *destU, *destV;
+  const guint8 *srcY, *srcU, *srcV;
+  gint dest_strideY, dest_strideU, dest_strideV;
+  gint src_strideY, src_strideU, src_strideV;
+
+  dest_strideY = GST_VIDEO_FRAME_COMP_STRIDE (dest, 0);
+  dest_strideU = GST_VIDEO_FRAME_COMP_STRIDE (dest, 1);
+  dest_strideV = GST_VIDEO_FRAME_COMP_STRIDE (dest, 2);
+
+  src_strideY = GST_VIDEO_FRAME_COMP_STRIDE (src, 0);
+  src_strideU = GST_VIDEO_FRAME_COMP_STRIDE (src, 1);
+  src_strideV = GST_VIDEO_FRAME_COMP_STRIDE (src, 2);
+
+  destY = GST_VIDEO_FRAME_COMP_DATA (dest, 0);
+  destU = GST_VIDEO_FRAME_COMP_DATA (dest, 1);
+  destV = GST_VIDEO_FRAME_COMP_DATA (dest, 2);
+
+  srcY = GST_VIDEO_FRAME_COMP_DATA (src, 0);
+  srcU = GST_VIDEO_FRAME_COMP_DATA (src, 1);
+  srcV = GST_VIDEO_FRAME_COMP_DATA (src, 2);
+
+  destY = destY + dest_y * dest_strideY + dest_x;
+  destU = destU + dest_y * dest_strideU + dest_x;
+  destV = destV + dest_y * dest_strideV + dest_x;
+
+  srcY = srcY + src_y * src_strideY + src_x;
+  srcU = srcU + src_y * src_strideU + src_x;
+  srcV = srcV + src_y * src_strideV + src_x;
+
+  if (src_sdtv != dest_sdtv) {
+    gint matrix[12];
+    gint y, u, v;
+
+    memcpy (matrix,
+        dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j++) {
+        y = APPLY_MATRIX (matrix, 0, srcY[j], srcU[j], srcV[j]);
+        u = APPLY_MATRIX (matrix, 1, srcY[j], srcU[j], srcV[j]);
+        v = APPLY_MATRIX (matrix, 2, srcY[j], srcU[j], srcV[j]);
+
+        destY[j] = y;
+        destU[j] = u;
+        destV[j] = v;
+      }
+      destY += dest_strideY;
+      destU += dest_strideU;
+      destV += dest_strideV;
+
+      srcY += src_strideY;
+      srcU += src_strideU;
+      srcV += src_strideV;
+    }
+  } else {
+    for (i = 0; i < h; i++) {
+      memcpy (destY, srcY, w);
+      memcpy (destU, srcU, w);
+      memcpy (destV, srcV, w);
+
+      destY += dest_strideY;
+      destU += dest_strideU;
+      destV += dest_strideV;
+
+      srcY += src_strideY;
+      srcU += src_strideU;
+      srcV += src_strideV;
+    }
+  }
+}
+
+static void
+copy_y42b_y42b (guint i_alpha, GstVideoFrame * dest,
+    gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src,
+    gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
+{
+  gint i, j;
+  guint8 *destY, *destU, *destV;
+  const guint8 *srcY, *srcU, *srcV;
+  gint dest_strideY, dest_strideU, dest_strideV;
+  gint src_strideY, src_strideU, src_strideV;
+  gint src_y_idx, src_uv_idx;
+  gint dest_y_idx, dest_uv_idx;
+  gint matrix[12];
+  gint y1, y2;
+  gint u1, u2;
+  gint v1, v2;
+  gint dest_width;
+
+  dest_width = GST_VIDEO_FRAME_WIDTH (dest);
+
+  dest_strideY = GST_VIDEO_FRAME_COMP_STRIDE (dest, 0);
+  dest_strideU = GST_VIDEO_FRAME_COMP_STRIDE (dest, 1);
+  dest_strideV = GST_VIDEO_FRAME_COMP_STRIDE (dest, 2);
+
+  src_strideY = GST_VIDEO_FRAME_COMP_STRIDE (src, 0);
+  src_strideU = GST_VIDEO_FRAME_COMP_STRIDE (src, 1);
+  src_strideV = GST_VIDEO_FRAME_COMP_STRIDE (src, 2);
+
+  destY = GST_VIDEO_FRAME_COMP_DATA (dest, 0);
+  destU = GST_VIDEO_FRAME_COMP_DATA (dest, 1);
+  destV = GST_VIDEO_FRAME_COMP_DATA (dest, 2);
+
+  srcY = GST_VIDEO_FRAME_COMP_DATA (src, 0);
+  srcU = GST_VIDEO_FRAME_COMP_DATA (src, 1);
+  srcV = GST_VIDEO_FRAME_COMP_DATA (src, 2);
+
+  destY = destY + dest_y * dest_strideY + dest_x;
+  destU = destU + dest_y * dest_strideU + dest_x / 2;
+  destV = destV + dest_y * dest_strideV + dest_x / 2;
+
+  srcY = srcY + src_y * src_strideY + src_x;
+  srcU = srcU + src_y * src_strideU + src_x / 2;
+  srcV = srcV + src_y * src_strideV + src_x / 2;
+
+  h = dest_y + h;
+  w = dest_x + w;
+
+  if (src_sdtv != dest_sdtv)
+    memcpy (matrix,
+        dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+  else
+    memcpy (matrix, cog_identity_matrix_8bit, 12 * sizeof (gint));
+
+  /* 1. Copy all macro pixel scanlines, the destination scanline
+   *    now starts at macro pixel boundary. */
+  for (i = dest_y; i < h; i++) {
+    /* 1.1. Handle the first destination pixel if it doesn't
+     *      start at the macro pixel boundary, i.e. blend with
+     *      the background! */
+    if (dest_x % 2 == 1) {
+      y1 = srcY[0];
+      u1 = srcU[0];
+      v1 = srcV[0];
+
+      destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[0] = CLAMP (
+          (destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
+      destV[0] = CLAMP (
+          (destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 2, 0, 255);
+      j = dest_x + 1;
+      src_y_idx = dest_y_idx = dest_uv_idx = 1;
+      src_uv_idx = (src_x % 2) + 1;
+    } else {
+      j = dest_x;
+      src_y_idx = dest_y_idx = dest_uv_idx = 0;
+      src_uv_idx = (src_x % 2);
+    }
+
+    /* 1.2. Copy all macro pixels from the source to the destination.
+     *      All pixels now start at macro pixel boundary, i.e. no
+     *      blending with the background is necessary. */
+    for (; j < w - 1; j += 2) {
+      y1 = srcY[src_y_idx];
+      y2 = srcY[src_y_idx + 1];
+
+      u1 = srcU[src_uv_idx / 2];
+      v1 = srcV[src_uv_idx / 2];
+      src_uv_idx++;
+      u2 = srcU[src_uv_idx / 2];
+      v2 = srcV[src_uv_idx / 2];
+      src_uv_idx++;
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[dest_y_idx + 1] =
+          CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+
+      destU[dest_uv_idx] = CLAMP (
+          (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 1, y2,
+                  u2, v2)) / 2, 0, 255);
+      destV[dest_uv_idx] = CLAMP (
+          (APPLY_MATRIX (matrix, 2, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
+                  u2, v2)) / 2, 0, 255);
+
+      dest_y_idx += 2;
+      src_y_idx += 2;
+      dest_uv_idx++;
+    }
+
+    /* 1.3. Now copy the last pixel if one exists and blend it
+     *      with the background because we only fill part of
+     *      the macro pixel. In case this is the last pixel of
+     *      the destination we will a larger part. */
+    if (j == w - 1 && j == dest_width - 1) {
+      y1 = srcY[src_y_idx];
+      u1 = srcU[src_uv_idx / 2];
+      v1 = srcV[src_uv_idx / 2];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
+      destV[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
+    } else if (j == w - 1) {
+      y1 = srcY[src_y_idx];
+      u1 = srcU[src_uv_idx / 2];
+      v1 = srcV[src_uv_idx / 2];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[dest_uv_idx] = CLAMP (
+          (destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1)) / 2, 0, 255);
+      destV[dest_uv_idx] = CLAMP (
+          (destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1)) / 2, 0, 255);
+    }
+
+    destY += dest_strideY;
+    destU += dest_strideU;
+    destV += dest_strideV;
+    srcY += src_strideY;
+
+    srcU += src_strideU;
+    srcV += src_strideV;
+  }
+}
+
+static void
+copy_y41b_y41b (guint i_alpha, GstVideoFrame * dest,
+    gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src,
+    gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
+{
+  gint i, j;
+  guint8 *destY, *destU, *destV;
+  const guint8 *srcY, *srcU, *srcV;
+  gint dest_strideY, dest_strideU, dest_strideV;
+  gint src_strideY, src_strideU, src_strideV;
+  gint src_y_idx, src_uv_idx;
+  gint dest_y_idx, dest_uv_idx;
+  gint matrix[12];
+  gint y1, y2, y3, y4;
+  gint u1, u2, u3, u4;
+  gint v1, v2, v3, v4;
+  gint dest_width;
+
+  dest_width = GST_VIDEO_FRAME_WIDTH (dest);
+
+  dest_strideY = GST_VIDEO_FRAME_COMP_STRIDE (dest, 0);
+  dest_strideU = GST_VIDEO_FRAME_COMP_STRIDE (dest, 1);
+  dest_strideV = GST_VIDEO_FRAME_COMP_STRIDE (dest, 2);
+
+  src_strideY = GST_VIDEO_FRAME_COMP_STRIDE (src, 0);
+  src_strideU = GST_VIDEO_FRAME_COMP_STRIDE (src, 1);
+  src_strideV = GST_VIDEO_FRAME_COMP_STRIDE (src, 2);
+
+  destY = GST_VIDEO_FRAME_COMP_DATA (dest, 0);
+  destU = GST_VIDEO_FRAME_COMP_DATA (dest, 1);
+  destV = GST_VIDEO_FRAME_COMP_DATA (dest, 2);
+
+  srcY = GST_VIDEO_FRAME_COMP_DATA (src, 0);
+  srcU = GST_VIDEO_FRAME_COMP_DATA (src, 1);
+  srcV = GST_VIDEO_FRAME_COMP_DATA (src, 2);
+
+  destY = destY + dest_y * dest_strideY + dest_x;
+  destU = destU + dest_y * dest_strideU + dest_x / 4;
+  destV = destV + dest_y * dest_strideV + dest_x / 4;
+
+  srcY = srcY + src_y * src_strideY + src_x;
+  srcU = srcU + src_y * src_strideU + src_x / 4;
+  srcV = srcV + src_y * src_strideV + src_x / 4;
+
+  h = dest_y + h;
+  w = dest_x + w;
+
+  if (src_sdtv != dest_sdtv)
+    memcpy (matrix,
+        dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+  else
+    memcpy (matrix, cog_identity_matrix_8bit, 12 * sizeof (gint));
+
+  /* 1. Copy all macro pixel scanlines, the destination scanline
+   *    now starts at macro pixel boundary. */
+  for (i = dest_y; i < h; i++) {
+    /* 1.1. Handle the first destination pixel if it doesn't
+     *      start at the macro pixel boundary, i.e. blend with
+     *      the background! */
+    if (dest_x % 4 == 1) {
+      y1 = srcY[0];
+      y2 = srcY[1];
+      y3 = srcY[2];
+      u1 = srcU[0];
+      v1 = srcV[0];
+
+      destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
+      destY[2] = CLAMP (APPLY_MATRIX (matrix, 0, y3, u1, v1), 0, 255);
+
+      destU[0] = CLAMP (
+          (destU[0] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 1, y2, u1,
+                  v1) + APPLY_MATRIX (matrix, 1, y3, u1, v1)) / 4, 0, 255);
+      destV[0] =
+          CLAMP ((destV[0] + APPLY_MATRIX (matrix, 2, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 2, y2, u1,
+                  v1) + APPLY_MATRIX (matrix, 2, y3, u1, v1)) / 4, 0, 255);
+
+      j = dest_x + 3;
+      src_y_idx = dest_y_idx = 3;
+      dest_uv_idx = 1;
+      src_uv_idx = (src_x % 4) + 3;
+    } else if (dest_x % 4 == 2) {
+      y1 = srcY[0];
+      y2 = srcY[1];
+      u1 = srcU[0];
+      v1 = srcV[0];
+
+      destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
+
+      destU[0] = CLAMP (
+          (2 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 1, y2, u1, v1)) / 4, 0, 255);
+      destV[0] =
+          CLAMP ((2 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 2, y2, u1, v1)) / 4, 0, 255);
+
+      j = dest_x + 2;
+      src_y_idx = dest_y_idx = 2;
+      dest_uv_idx = 1;
+      src_uv_idx = (src_x % 4) + 2;
+    } else if (dest_x % 4 == 3) {
+      y1 = srcY[0];
+      u1 = srcU[0];
+      v1 = srcV[0];
+
+      destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+
+      destU[0] = CLAMP (
+          (3 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0, 255);
+      destV[0] = CLAMP (
+          (3 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4, 0, 255);
+
+      j = dest_x + 1;
+      src_y_idx = dest_y_idx = 1;
+      dest_uv_idx = 1;
+      src_uv_idx = (src_x % 4) + 1;
+    } else {
+      j = dest_x;
+      src_y_idx = dest_y_idx = dest_uv_idx = 0;
+      src_uv_idx = (src_x % 4);
+    }
+
+    /* 1.2. Copy all macro pixels from the source to the destination.
+     *      All pixels now start at macro pixel boundary, i.e. no
+     *      blending with the background is necessary. */
+    for (; j < w - 3; j += 4) {
+      y1 = srcY[src_y_idx];
+      y2 = srcY[src_y_idx + 1];
+      y3 = srcY[src_y_idx + 2];
+      y4 = srcY[src_y_idx + 3];
+
+      u1 = srcU[src_uv_idx / 4];
+      v1 = srcV[src_uv_idx / 4];
+      src_uv_idx++;
+      u2 = srcU[src_uv_idx / 4];
+      v2 = srcV[src_uv_idx / 4];
+      src_uv_idx++;
+      u3 = srcU[src_uv_idx / 4];
+      v3 = srcV[src_uv_idx / 4];
+      src_uv_idx++;
+      u4 = srcU[src_uv_idx / 4];
+      v4 = srcV[src_uv_idx / 4];
+      src_uv_idx++;
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[dest_y_idx + 1] =
+          CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+      destY[dest_y_idx + 2] =
+          CLAMP (APPLY_MATRIX (matrix, 0, y3, u3, v3), 0, 255);
+      destY[dest_y_idx + 3] =
+          CLAMP (APPLY_MATRIX (matrix, 0, y4, u4, v4), 0, 255);
+
+      destU[dest_uv_idx] = CLAMP (
+          (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 1, y2,
+                  u2, v2) + APPLY_MATRIX (matrix, 1, y3, u3,
+                  v3) + APPLY_MATRIX (matrix, 1, y4, u4, v4)) / 4, 0, 255);
+      destV[dest_uv_idx] =
+          CLAMP ((APPLY_MATRIX (matrix, 2, y1, u1, v1) + APPLY_MATRIX (matrix,
+                  2, y2, u2, v2) + APPLY_MATRIX (matrix, 2, y3, u3,
+                  v3) + APPLY_MATRIX (matrix, 2, y4, u4, v4)) / 4, 0, 255);
+
+      dest_y_idx += 4;
+      src_y_idx += 4;
+      dest_uv_idx++;
+    }
+
+    /* 1.3. Now copy the last pixel if one exists and blend it
+     *      with the background because we only fill part of
+     *      the macro pixel. In case this is the last pixel of
+     *      the destination we will a larger part. */
+    if (j == w - 1 && j == dest_width - 1) {
+      y1 = srcY[src_y_idx];
+      u1 = srcU[src_uv_idx / 4];
+      v1 = srcV[src_uv_idx / 4];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
+      destV[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
+    } else if (j == w - 1) {
+      y1 = srcY[src_y_idx];
+      u1 = srcU[src_uv_idx / 4];
+      v1 = srcV[src_uv_idx / 4];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[dest_uv_idx] = CLAMP (
+          (destU[dest_uv_idx] + 3 * APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1)) / 4, 0, 255);
+      destV[dest_uv_idx] = CLAMP (
+          (destV[dest_uv_idx] + 3 * APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1)) / 4, 0, 255);
+    } else if (j == w - 2 && j == dest_width - 2) {
+      y1 = srcY[src_y_idx];
+      y2 = srcY[src_y_idx + 1];
+      u1 = srcU[src_uv_idx / 4];
+      v1 = srcV[src_uv_idx / 4];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[dest_y_idx + 1] =
+          CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
+      destU[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
+      destV[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
+    } else if (j == w - 2) {
+      y1 = srcY[src_y_idx];
+      y2 = srcY[src_y_idx + 1];
+      u1 = srcU[src_uv_idx / 4];
+      v1 = srcV[src_uv_idx / 4];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[dest_y_idx + 1] =
+          CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
+      destU[dest_uv_idx] =
+          CLAMP ((destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1)) / 2, 0, 255);
+      destV[dest_uv_idx] =
+          CLAMP ((destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1)) / 2, 0, 255);
+    } else if (j == w - 3 && j == dest_width - 3) {
+      y1 = srcY[src_y_idx];
+      y2 = srcY[src_y_idx + 1];
+      y3 = srcY[src_y_idx + 2];
+      u1 = srcU[src_uv_idx / 4];
+      v1 = srcV[src_uv_idx / 4];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[dest_y_idx + 1] =
+          CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
+      destY[dest_y_idx + 2] =
+          CLAMP (APPLY_MATRIX (matrix, 0, y3, u1, v1), 0, 255);
+      destU[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
+      destV[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
+    } else if (j == w - 3) {
+      y1 = srcY[src_y_idx];
+      y2 = srcY[src_y_idx + 1];
+      y3 = srcY[src_y_idx + 2];
+      u1 = srcU[src_uv_idx / 4];
+      v1 = srcV[src_uv_idx / 4];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[dest_y_idx + 1] =
+          CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
+      destY[dest_y_idx + 2] =
+          CLAMP (APPLY_MATRIX (matrix, 0, y3, u1, v1), 0, 255);
+      destU[dest_uv_idx] =
+          CLAMP ((3 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1)) / 4, 0, 255);
+      destV[dest_uv_idx] =
+          CLAMP ((3 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1)) / 4, 0, 255);
+    }
+
+    destY += dest_strideY;
+    destU += dest_strideU;
+    destV += dest_strideV;
+    srcY += src_strideY;
+    srcU += src_strideU;
+    srcV += src_strideV;
+  }
+}
+
+static void
+copy_i420_i420 (guint i_alpha, GstVideoFrame * dest,
+    gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src,
+    gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
+{
+  gint i, j;
+  guint8 *destY, *destU, *destV;
+  const guint8 *srcY, *srcU, *srcV;
+  guint8 *destY2;
+  const guint8 *srcY2, *srcU2, *srcV2;
+  gint dest_strideY, dest_strideU, dest_strideV;
+  gint src_strideY, src_strideU, src_strideV;
+  gint src_y_idx, src_uv_idx;
+  gint dest_y_idx, dest_uv_idx;
+  gint matrix[12];
+  gint y1, y2, y3, y4;
+  gint u1, u2, u3, u4;
+  gint v1, v2, v3, v4;
+  gint dest_width, dest_height;
+
+  dest_width = GST_VIDEO_FRAME_WIDTH (dest);
+  dest_height = GST_VIDEO_FRAME_HEIGHT (dest);
+
+  dest_strideY = GST_VIDEO_FRAME_COMP_STRIDE (dest, 0);
+  dest_strideU = GST_VIDEO_FRAME_COMP_STRIDE (dest, 1);
+  dest_strideV = GST_VIDEO_FRAME_COMP_STRIDE (dest, 2);
+
+  src_strideY = GST_VIDEO_FRAME_COMP_STRIDE (src, 0);
+  src_strideU = GST_VIDEO_FRAME_COMP_STRIDE (src, 1);
+  src_strideV = GST_VIDEO_FRAME_COMP_STRIDE (src, 2);
+
+  destY = GST_VIDEO_FRAME_COMP_DATA (dest, 0);
+  destU = GST_VIDEO_FRAME_COMP_DATA (dest, 1);
+  destV = GST_VIDEO_FRAME_COMP_DATA (dest, 2);
+
+  srcY = GST_VIDEO_FRAME_COMP_DATA (src, 0);
+  srcU = GST_VIDEO_FRAME_COMP_DATA (src, 1);
+  srcV = GST_VIDEO_FRAME_COMP_DATA (src, 2);
+
+  destY = destY + dest_y * dest_strideY + dest_x;
+  destU = destU + (dest_y / 2) * dest_strideU + dest_x / 2;
+  destV = destV + (dest_y / 2) * dest_strideV + dest_x / 2;
+
+  srcY = srcY + src_y * src_strideY + src_x;
+  srcU = srcU + (src_y / 2) * src_strideU + src_x / 2;
+  srcV = srcV + (src_y / 2) * src_strideV + src_x / 2;
+
+  destY2 = destY + dest_strideY;
+  srcY2 = srcY + src_strideY;
+
+  h = dest_y + h;
+  w = dest_x + w;
+
+  if (src_sdtv != dest_sdtv)
+    memcpy (matrix,
+        dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+  else
+    memcpy (matrix, cog_identity_matrix_8bit, 12 * sizeof (gint));
+
+  /* 1. Handle the first destination scanline specially if it
+   *    doesn't start at the macro pixel boundary, i.e. blend
+   *    with the background! */
+  if (dest_y % 2 == 1) {
+    /* 1.1. Handle the first destination pixel if it doesn't
+     *      start at the macro pixel boundary, i.e. blend with
+     *      the background! */
+    if (dest_x % 2 == 1) {
+      y1 = srcY[0];
+      u1 = srcU[0];
+      v1 = srcV[0];
+
+      destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[0] =
+          CLAMP ((3 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
+          255);
+      destV[0] =
+          CLAMP ((3 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4, 0,
+          255);
+
+      j = dest_x + 1;
+      src_y_idx = dest_y_idx = dest_uv_idx = 1;
+      src_uv_idx = (src_x % 2) + 1;
+    } else {
+      j = dest_x;
+      src_y_idx = dest_y_idx = dest_uv_idx = 0;
+      src_uv_idx = (src_x % 2);
+    }
+
+    /* 1.2. Copy all macro pixels from the source to the destination
+     *      but blend with the background because we're only filling
+     *      the lower part of the macro pixels. */
+    for (; j < w - 1; j += 2) {
+      y1 = srcY[src_y_idx];
+      y2 = srcY[src_y_idx + 1];
+
+      u1 = srcU[src_uv_idx / 2];
+      v1 = srcV[src_uv_idx / 2];
+      src_uv_idx++;
+      u2 = srcU[src_uv_idx / 2];
+      v2 = srcV[src_uv_idx / 2];
+      src_uv_idx++;
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[dest_y_idx + 1] =
+          CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+      destU[dest_uv_idx] =
+          CLAMP ((2 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
+      destV[dest_uv_idx] =
+          CLAMP ((2 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
+
+      dest_y_idx += 2;
+      src_y_idx += 2;
+      dest_uv_idx++;
+    }
+
+    /* 1.3. Now copy the last pixel if one exists and blend it
+     *      with the background because we only fill part of
+     *      the macro pixel. In case this is the last pixel of
+     *      the destination we will a larger part. */
+    if (j == w - 1 && j == dest_width - 1) {
+      y1 = srcY[src_y_idx];
+      u1 = srcU[src_uv_idx / 2];
+      v1 = srcV[src_uv_idx / 2];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[dest_uv_idx] = CLAMP (
+          (destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0,
+          255);
+      destV[dest_uv_idx] =
+          CLAMP ((destV[dest_uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
+                  v1)) / 2, 0, 255);
+    } else if (j == w - 1) {
+      y1 = srcY[src_y_idx];
+      u1 = srcU[src_uv_idx / 2];
+      v1 = srcV[src_uv_idx / 2];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[dest_uv_idx] = CLAMP (
+          (3 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4,
+          0, 255);
+      destV[dest_uv_idx] =
+          CLAMP ((3 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
+                  v1)) / 4, 0, 255);
+    }
+
+    destY += dest_strideY;
+    destY2 += dest_strideY;
+    destU += dest_strideU;
+    destV += dest_strideV;
+    srcY += src_strideY;
+    srcY2 += src_strideY;
+    src_y++;
+    if (src_y % 2 == 0) {
+      srcU += src_strideU;
+      srcV += src_strideV;
+    }
+    i = dest_y + 1;
+  } else {
+    i = dest_y;
+  }
+
+  /* 2. Copy all macro pixel scanlines, the destination scanline
+   *    now starts at macro pixel boundary. */
+  for (; i < h - 1; i += 2) {
+    /* 2.1. Handle the first destination pixel if it doesn't
+     *      start at the macro pixel boundary, i.e. blend with
+     *      the background! */
+
+    srcU2 = srcU;
+    srcV2 = srcV;
+    if (src_y % 2 == 1) {
+      srcU2 += src_strideU;
+      srcV2 += src_strideV;
+    }
+
+    if (dest_x % 2 == 1) {
+      y1 = srcY[0];
+      y2 = srcY2[0];
+      u1 = srcU[0];
+      v1 = srcV[0];
+      u2 = srcU2[0];
+      v2 = srcV2[0];
+
+      destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY2[0] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+      destU[0] = CLAMP (
+          (2 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
+      destV[0] = CLAMP (
+          (2 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
+      j = dest_x + 1;
+      src_y_idx = dest_y_idx = dest_uv_idx = 1;
+      src_uv_idx = (src_x % 2) + 1;
+    } else {
+      j = dest_x;
+      src_y_idx = dest_y_idx = dest_uv_idx = 0;
+      src_uv_idx = (src_x % 2);
+    }
+
+    /* 2.2. Copy all macro pixels from the source to the destination.
+     *      All pixels now start at macro pixel boundary, i.e. no
+     *      blending with the background is necessary. */
+    for (; j < w - 1; j += 2) {
+      y1 = srcY[src_y_idx];
+      y2 = srcY[src_y_idx + 1];
+      y3 = srcY2[src_y_idx];
+      y4 = srcY2[src_y_idx + 1];
+
+      u1 = srcU[src_uv_idx / 2];
+      u3 = srcU2[src_uv_idx / 2];
+      v1 = srcV[src_uv_idx / 2];
+      v3 = srcV2[src_uv_idx / 2];
+      src_uv_idx++;
+      u2 = srcU[src_uv_idx / 2];
+      u4 = srcU2[src_uv_idx / 2];
+      v2 = srcV[src_uv_idx / 2];
+      v4 = srcV2[src_uv_idx / 2];
+      src_uv_idx++;
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[dest_y_idx + 1] =
+          CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+      destY2[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y3, u3, v3), 0, 255);
+      destY2[dest_y_idx + 1] =
+          CLAMP (APPLY_MATRIX (matrix, 0, y4, u4, v4), 0, 255);
+
+      destU[dest_uv_idx] = CLAMP (
+          (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 1, y2,
+                  u2, v2) + APPLY_MATRIX (matrix, 1, y3, u3,
+                  v3) + APPLY_MATRIX (matrix, 1, y4, u4, v4)) / 4, 0, 255);
+      destV[dest_uv_idx] = CLAMP (
+          (APPLY_MATRIX (matrix, 2, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
+                  u2, v2) + APPLY_MATRIX (matrix, 2, y3, u3,
+                  v3) + APPLY_MATRIX (matrix, 2, y4, u4, v4)) / 4, 0, 255);
+
+      dest_y_idx += 2;
+      src_y_idx += 2;
+      dest_uv_idx++;
+    }
+
+    /* 2.3. Now copy the last pixel if one exists and blend it
+     *      with the background because we only fill part of
+     *      the macro pixel. In case this is the last pixel of
+     *      the destination we will a larger part. */
+    if (j == w - 1 && j == dest_width - 1) {
+      y1 = srcY[src_y_idx];
+      y2 = srcY2[src_y_idx];
+
+      u1 = srcU[src_uv_idx / 2];
+      u2 = srcU2[src_uv_idx / 2];
+
+      v1 = srcV[src_uv_idx / 2];
+      v2 = srcV2[src_uv_idx / 2];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY2[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+      destU[dest_uv_idx] = CLAMP (
+          (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
+                  u2, v2)) / 2, 0, 255);
+      destV[dest_uv_idx] = CLAMP (
+          (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
+                  u2, v2)) / 2, 0, 255);
+    } else if (j == w - 1) {
+      y1 = srcY[src_y_idx];
+      y2 = srcY2[src_y_idx];
+
+      u1 = srcU[src_uv_idx / 2];
+      u2 = srcU2[src_uv_idx / 2];
+
+      v1 = srcV[src_uv_idx / 2];
+      v2 = srcV2[src_uv_idx / 2];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY2[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+      destU[dest_uv_idx] = CLAMP (
+          (2 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
+      destV[dest_uv_idx] = CLAMP (
+          (2 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
+    }
+
+    destY += 2 * dest_strideY;
+    destY2 += 2 * dest_strideY;
+    destU += dest_strideU;
+    destV += dest_strideV;
+    srcY += 2 * src_strideY;
+    srcY2 += 2 * src_strideY;
+
+    src_y += 2;
+    srcU += src_strideU;
+    srcV += src_strideV;
+  }
+
+  /* 3. Handle the last scanline if one exists. This again
+   *    doesn't start at macro pixel boundary but should
+   *    only fill the upper part of the macro pixels. */
+  if (i == h - 1 && i == dest_height - 1) {
+    /* 3.1. Handle the first destination pixel if it doesn't
+     *      start at the macro pixel boundary, i.e. blend with
+     *      the background! */
+    if (dest_x % 2 == 1) {
+      y1 = srcY[0];
+      u1 = srcU[0];
+      v1 = srcV[0];
+
+      destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[0] =
+          CLAMP ((destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
+      destV[0] =
+          CLAMP ((destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 2, 0, 255);
+
+      j = dest_x + 1;
+      src_y_idx = dest_y_idx = dest_uv_idx = 1;
+      src_uv_idx = (src_x % 2) + 1;
+    } else {
+      j = dest_x;
+      src_y_idx = dest_y_idx = dest_uv_idx = 0;
+      src_uv_idx = (src_x % 2);
+    }
+
+    /* 3.2. Copy all macro pixels from the source to the destination
+     *      but blend with the background because we're only filling
+     *      the upper part of the macro pixels. */
+    for (; j < w - 1; j += 2) {
+      y1 = srcY[src_y_idx];
+      y2 = srcY[src_y_idx + 1];
+
+      u1 = srcU[src_uv_idx / 2];
+      v1 = srcV[src_uv_idx / 2];
+      src_uv_idx++;
+      u2 = srcU[src_uv_idx / 2];
+      v2 = srcV[src_uv_idx / 2];
+      src_uv_idx++;
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[dest_y_idx + 1] =
+          CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+
+      destU[dest_uv_idx] = CLAMP (
+          (2 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
+      destV[dest_uv_idx] = CLAMP (
+          (2 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
+
+      dest_y_idx += 2;
+      src_y_idx += 2;
+      dest_uv_idx++;
+    }
+
+    /* 3.3. Now copy the last pixel if one exists and blend it
+     *      with the background because we only fill part of
+     *      the macro pixel. In case this is the last pixel of
+     *      the destination we will a larger part. */
+    if (j == w - 1 && j == dest_width - 1) {
+      y1 = srcY[src_y_idx];
+      u1 = srcU[src_uv_idx / 2];
+      v1 = srcV[src_uv_idx / 2];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[dest_uv_idx] = CLAMP (
+          (destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0,
+          255);
+      destV[dest_uv_idx] =
+          CLAMP ((destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1)) / 2, 0, 255);
+    } else if (j == w - 1) {
+      y1 = srcY[src_y_idx];
+      u1 = srcU[src_uv_idx / 2];
+      v1 = srcV[src_uv_idx / 2];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[dest_uv_idx] = CLAMP (
+          (3 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4,
+          0, 255);
+      destV[dest_uv_idx] =
+          CLAMP ((3 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1)) / 4, 0, 255);
+    }
+  } else if (i == h - 1) {
+    /* 3.1. Handle the first destination pixel if it doesn't
+     *      start at the macro pixel boundary, i.e. blend with
+     *      the background! */
+    if (dest_x % 2 == 1) {
+      y1 = srcY[0];
+      u1 = srcU[0];
+      v1 = srcV[0];
+
+      destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[0] =
+          CLAMP ((3 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
+          255);
+      destV[0] =
+          CLAMP ((3 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4, 0,
+          255);
+
+      j = dest_x + 1;
+      src_y_idx = dest_y_idx = dest_uv_idx = 1;
+      src_uv_idx = (src_x % 2) + 1;
+    } else {
+      j = dest_x;
+      src_y_idx = dest_y_idx = dest_uv_idx = 0;
+      src_uv_idx = (src_x % 2);
+    }
+
+    /* 3.2. Copy all macro pixels from the source to the destination
+     *      but blend with the background because we're only filling
+     *      the upper part of the macro pixels. */
+    for (; j < w - 1; j += 2) {
+      y1 = srcY[src_y_idx];
+      y2 = srcY[src_y_idx + 1];
+
+      u1 = srcU[src_uv_idx / 2];
+      v1 = srcV[src_uv_idx / 2];
+      src_uv_idx++;
+      u2 = srcU[src_uv_idx / 2];
+      v2 = srcV[src_uv_idx / 2];
+      src_uv_idx++;
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destY[dest_y_idx + 1] =
+          CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
+
+      destU[dest_uv_idx] = CLAMP (
+          (2 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
+      destV[dest_uv_idx] = CLAMP (
+          (2 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
+                  v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
+
+      dest_y_idx += 2;
+      src_y_idx += 2;
+      dest_uv_idx++;
+    }
+
+    /* 3.3. Now copy the last pixel if one exists and blend it
+     *      with the background because we only fill part of
+     *      the macro pixel. In case this is the last pixel of
+     *      the destination we will a larger part. */
+    if (j == w - 1 && j == dest_width - 1) {
+      y1 = srcY[src_y_idx];
+      u1 = srcU[src_uv_idx / 2];
+      v1 = srcV[src_uv_idx / 2];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[dest_uv_idx] = CLAMP (
+          (destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0,
+          255);
+      destV[dest_uv_idx] =
+          CLAMP ((destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1)) / 2, 0, 255);
+    } else if (j == w - 1) {
+      y1 = srcY[src_y_idx];
+      u1 = srcU[src_uv_idx / 2];
+      v1 = srcV[src_uv_idx / 2];
+
+      destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
+      destU[dest_uv_idx] = CLAMP (
+          (3 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4,
+          0, 255);
+      destV[dest_uv_idx] =
+          CLAMP ((3 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
+                  v1)) / 4, 0, 255);
+    }
+  }
+}
+
+static void
+copy_i420_ayuv (guint i_alpha, GstVideoFrame * dest_frame,
+    gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src_frame,
+    gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
+{
+  const guint8 *srcY, *srcU, *srcV;
+  gint src_strideY, src_strideU, src_strideV;
+  gint dest_stride;
+  guint8 *dest;
+
+  src_strideY = GST_VIDEO_FRAME_COMP_STRIDE (src_frame, 0);
+  src_strideU = GST_VIDEO_FRAME_COMP_STRIDE (src_frame, 1);
+  src_strideV = GST_VIDEO_FRAME_COMP_STRIDE (src_frame, 2);
+
+  srcY = GST_VIDEO_FRAME_COMP_DATA (src_frame, 0);
+  srcU = GST_VIDEO_FRAME_COMP_DATA (src_frame, 1);
+  srcV = GST_VIDEO_FRAME_COMP_DATA (src_frame, 2);
+
+  dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest_frame, 0);
+
+  dest = GST_VIDEO_FRAME_PLANE_DATA (dest_frame, 0);
+  dest = dest + dest_y * dest_stride + dest_x * 4;
+
+  srcY = srcY + src_y * src_strideY + src_x;
+  srcU = srcU + (src_y / 2) * src_strideU + src_x / 2;
+  srcV = srcV + (src_y / 2) * src_strideV + src_x / 2;
+
+  i_alpha = CLAMP (i_alpha, 0, 255);
+
+  if (src_sdtv != dest_sdtv) {
+    gint i, j, uv_idx;
+    gint y, u, v;
+    gint y1, u1, v1;
+    gint matrix[12];
+
+    memcpy (matrix,
+        dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+
+    for (i = 0; i < h; i++) {
+      for (j = 0, uv_idx = src_x % 2; j < w; j++, uv_idx++) {
+        y = srcY[j];
+        u = srcU[uv_idx / 2];
+        v = srcV[uv_idx / 2];
+
+        y1 = APPLY_MATRIX (matrix, 0, y, u, v);
+        u1 = APPLY_MATRIX (matrix, 1, y, u, v);
+        v1 = APPLY_MATRIX (matrix, 2, y, u, v);
+
+        dest[4 * j + 0] = i_alpha;
+        dest[4 * j + 1] = y1;
+        dest[4 * j + 2] = u1;
+        dest[4 * j + 3] = v1;
+      }
+      dest += dest_stride;
+
+      src_y++;
+      srcY += src_strideY;
+      if (src_y % 2 == 0) {
+        srcU += src_strideU;
+        srcV += src_strideV;
+      }
+    }
+  } else {
+    gint i, j, uv_idx;
+    gint y, u, v;
+
+    for (i = 0; i < h; i++) {
+      for (j = 0, uv_idx = src_x % 2; j < w; j++, uv_idx++) {
+        y = srcY[j];
+        u = srcU[uv_idx / 2];
+        v = srcV[uv_idx / 2];
+
+        dest[4 * j + 0] = i_alpha;
+        dest[4 * j + 1] = y;
+        dest[4 * j + 2] = u;
+        dest[4 * j + 3] = v;
+      }
+      dest += dest_stride;
+
+      src_y++;
+      srcY += src_strideY;
+      if (src_y % 2 == 0) {
+        srcU += src_strideU;
+        srcV += src_strideV;
+      }
+    }
+  }
+}
+
+static void
+fill_rgb32 (GstVideoBoxFill fill_type, guint b_alpha,
+    GstVideoFrame * frame, gboolean sdtv)
+{
+  guint32 empty_pixel;
+  gint p[4];
+  guint8 *dest;
+  guint stride;
+  gint width, height;
+
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
+
+  dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+
+  p[0] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 3);
+  p[1] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 0);
+  p[2] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 1);
+  p[3] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 2);
+
+  b_alpha = CLAMP (b_alpha, 0, 255);
+
+  if (GST_VIDEO_FRAME_N_COMPONENTS (frame) == 4) {
+    empty_pixel = GUINT32_FROM_LE ((b_alpha << (p[0] * 8)) |
+        (rgb_colors_R[fill_type] << (p[1] * 8)) |
+        (rgb_colors_G[fill_type] << (p[2] * 8)) |
+        (rgb_colors_B[fill_type] << (p[3] * 8)));
+  } else {
+    empty_pixel = GUINT32_FROM_LE (
+        (rgb_colors_R[fill_type] << (p[1] * 8)) |
+        (rgb_colors_G[fill_type] << (p[2] * 8)) |
+        (rgb_colors_B[fill_type] << (p[3] * 8)));
+  }
+
+  if (stride == width * 4) {
+    video_box_orc_splat_u32 ((guint32 *) dest, empty_pixel, width * height);
+  } else if (height) {
+    for (; height; --height) {
+      video_box_orc_splat_u32 ((guint32 *) dest, empty_pixel, width);
+      dest += stride;
+    }
+  }
+}
+
+static void
+fill_rgb24 (GstVideoBoxFill fill_type, guint b_alpha,
+    GstVideoFrame * frame, gboolean sdtv)
+{
+  gint dest_stride;
+  gint p[4];
+  gint i, j;
+  guint8 *dest;
+  gint width, height;
+
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
+
+  dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+
+  p[1] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 0);
+  p[2] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 1);
+  p[3] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 2);
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      dest[3 * j + p[1]] = rgb_colors_R[fill_type];
+      dest[3 * j + p[2]] = rgb_colors_G[fill_type];
+      dest[3 * j + p[3]] = rgb_colors_B[fill_type];
+    }
+    dest += dest_stride;
+  }
+}
+
+static void
+copy_rgb32 (guint i_alpha, GstVideoFrame * dest_frame,
+    gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src_frame,
+    gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
+{
+  gint i, j;
+  gint src_stride, dest_stride;
+  gboolean in_alpha, out_alpha;
+  gint in_bpp, out_bpp;
+  gint p_out[4];
+  gint p_in[4];
+  gboolean packed_out;
+  gboolean packed_in;
+  guint8 *src, *dest;
+
+  src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src_frame, 0);
+  dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest_frame, 0);
+  in_bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (src_frame, 0);
+  out_bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (dest_frame, 0);
+  packed_in = (in_bpp < 4);
+  packed_out = (out_bpp < 4);
+
+  out_alpha = GST_VIDEO_INFO_HAS_ALPHA (&dest_frame->info);
+  p_out[0] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 3);
+  p_out[1] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 0);
+  p_out[2] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 1);
+  p_out[3] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 2);
+
+  in_alpha = GST_VIDEO_INFO_HAS_ALPHA (&src_frame->info);
+  p_in[0] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 3);
+  p_in[1] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 0);
+  p_in[2] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 1);
+  p_in[3] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 2);
+
+  dest = GST_VIDEO_FRAME_PLANE_DATA (dest_frame, 0);
+  dest = dest + dest_y * dest_stride + dest_x * out_bpp;
+  src = GST_VIDEO_FRAME_PLANE_DATA (src_frame, 0);
+  src = src + src_y * src_stride + src_x * in_bpp;
+
+  if (in_alpha && out_alpha) {
+    w *= 4;
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j += 4) {
+        dest[j + p_out[0]] = (src[j + p_in[0]] * i_alpha) >> 8;
+        dest[j + p_out[1]] = src[j + p_in[1]];
+        dest[j + p_out[2]] = src[j + p_in[2]];
+        dest[j + p_out[3]] = src[j + p_in[3]];
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  } else if (out_alpha && !packed_in) {
+    w *= 4;
+    i_alpha = CLAMP (i_alpha, 0, 255);
+
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j += 4) {
+        dest[j + p_out[0]] = i_alpha;
+        dest[j + p_out[1]] = src[j + p_in[1]];
+        dest[j + p_out[2]] = src[j + p_in[2]];
+        dest[j + p_out[3]] = src[j + p_in[3]];
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  } else if (out_alpha && packed_in) {
+    i_alpha = CLAMP (i_alpha, 0, 255);
+
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j++) {
+        dest[4 * j + p_out[0]] = i_alpha;
+        dest[4 * j + p_out[1]] = src[in_bpp * j + p_in[1]];
+        dest[4 * j + p_out[2]] = src[in_bpp * j + p_in[2]];
+        dest[4 * j + p_out[3]] = src[in_bpp * j + p_in[3]];
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  } else if (!packed_out && !packed_in) {
+    w *= 4;
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j += 4) {
+        dest[j + p_out[1]] = src[j + p_in[1]];
+        dest[j + p_out[2]] = src[j + p_in[2]];
+        dest[j + p_out[3]] = src[j + p_in[3]];
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  } else {
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j++) {
+        dest[out_bpp * j + p_out[1]] = src[in_bpp * j + p_in[1]];
+        dest[out_bpp * j + p_out[2]] = src[in_bpp * j + p_in[2]];
+        dest[out_bpp * j + p_out[3]] = src[in_bpp * j + p_in[3]];
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  }
+}
+
+static void
+copy_rgb32_ayuv (guint i_alpha, GstVideoFrame * dest_frame,
+    gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src_frame,
+    gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
+{
+  gint i, j;
+  gint src_stride, dest_stride;
+  gboolean in_alpha;
+  gint in_bpp;
+  gint p_in[4];
+  gboolean packed_in;
+  gint matrix[12];
+  gint a;
+  gint y, u, v;
+  gint r, g, b;
+  guint8 *dest, *src;
+
+  dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest_frame, 0);
+  src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src_frame, 0);
+  in_bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (src_frame, 0);
+  packed_in = (in_bpp < 4);
+
+  in_alpha = GST_VIDEO_INFO_HAS_ALPHA (&src_frame->info);
+  p_in[0] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 3);
+  p_in[1] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 0);
+  p_in[2] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 1);
+  p_in[3] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 2);
+
+  memcpy (matrix,
+      (dest_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
+      cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
+
+  dest = GST_VIDEO_FRAME_PLANE_DATA (dest_frame, 0);
+  dest = dest + dest_y * dest_stride + dest_x * 4;
+  src = GST_VIDEO_FRAME_PLANE_DATA (src_frame, 0);
+  src = src + src_y * src_stride + src_x * in_bpp;
+
+  if (in_alpha) {
+    w *= 4;
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j += 4) {
+        a = (src[j + p_in[0]] * i_alpha) >> 8;
+        r = src[j + p_in[1]];
+        g = src[j + p_in[2]];
+        b = src[j + p_in[3]];
+
+        y = APPLY_MATRIX (matrix, 0, r, g, b);
+        u = APPLY_MATRIX (matrix, 1, r, g, b);
+        v = APPLY_MATRIX (matrix, 2, r, g, b);
+
+        dest[j + 0] = a;
+        dest[j + 1] = CLAMP (y, 0, 255);
+        dest[j + 2] = CLAMP (u, 0, 255);
+        dest[j + 3] = CLAMP (v, 0, 255);
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  } else if (!packed_in) {
+    w *= 4;
+    i_alpha = CLAMP (i_alpha, 0, 255);
+
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j += 4) {
+        a = i_alpha;
+        r = src[j + p_in[1]];
+        g = src[j + p_in[2]];
+        b = src[j + p_in[3]];
+
+        y = APPLY_MATRIX (matrix, 0, r, g, b);
+        u = APPLY_MATRIX (matrix, 1, r, g, b);
+        v = APPLY_MATRIX (matrix, 2, r, g, b);
+
+        dest[j + 0] = a;
+        dest[j + 1] = CLAMP (y, 0, 255);
+        dest[j + 2] = CLAMP (u, 0, 255);
+        dest[j + 3] = CLAMP (v, 0, 255);
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  } else {
+    i_alpha = CLAMP (i_alpha, 0, 255);
+
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j++) {
+        a = i_alpha;
+        r = src[in_bpp * j + p_in[1]];
+        g = src[in_bpp * j + p_in[2]];
+        b = src[in_bpp * j + p_in[3]];
+
+        y = APPLY_MATRIX (matrix, 0, r, g, b);
+        u = APPLY_MATRIX (matrix, 1, r, g, b);
+        v = APPLY_MATRIX (matrix, 2, r, g, b);
+
+        dest[4 * j + 0] = a;
+        dest[4 * j + 1] = CLAMP (y, 0, 255);
+        dest[4 * j + 2] = CLAMP (u, 0, 255);
+        dest[4 * j + 3] = CLAMP (v, 0, 255);
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  }
+}
+
+static void
+copy_ayuv_rgb32 (guint i_alpha, GstVideoFrame * dest_frame,
+    gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src_frame,
+    gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
+{
+  gint i, j;
+  gint src_stride, dest_stride;
+  gboolean out_alpha;
+  gint out_bpp;
+  gint p_out[4];
+  gboolean packed_out;
+  gint matrix[12];
+  gint a;
+  gint y, u, v;
+  gint r, g, b;
+  guint8 *src, *dest;
+
+  src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src_frame, 0);
+  dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest_frame, 0);
+  out_bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (dest_frame, 0);
+  packed_out = (out_bpp < 4);
+
+  out_alpha = GST_VIDEO_INFO_HAS_ALPHA (&dest_frame->info);
+  p_out[0] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 3);
+  p_out[1] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 0);
+  p_out[2] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 1);
+  p_out[3] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 2);
+
+  memcpy (matrix,
+      (src_sdtv) ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
+      cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
+
+  dest = GST_VIDEO_FRAME_PLANE_DATA (dest_frame, 0);
+  dest = dest + dest_y * dest_stride + dest_x * out_bpp;
+  src = GST_VIDEO_FRAME_PLANE_DATA (src_frame, 0);
+  src = src + src_y * src_stride + src_x * 4;
+
+  if (out_alpha) {
+    w *= 4;
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j += 4) {
+        a = (src[j + 0] * i_alpha) >> 8;
+        y = src[j + 1];
+        u = src[j + 2];
+        v = src[j + 3];
+
+        r = APPLY_MATRIX (matrix, 0, y, u, v);
+        g = APPLY_MATRIX (matrix, 1, y, u, v);
+        b = APPLY_MATRIX (matrix, 2, y, u, v);
+
+        dest[j + p_out[0]] = a;
+        dest[j + p_out[1]] = CLAMP (r, 0, 255);
+        dest[j + p_out[2]] = CLAMP (g, 0, 255);
+        dest[j + p_out[3]] = CLAMP (b, 0, 255);
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  } else if (!packed_out) {
+    w *= 4;
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j += 4) {
+        y = src[j + 1];
+        u = src[j + 2];
+        v = src[j + 3];
+
+        r = APPLY_MATRIX (matrix, 0, y, u, v);
+        g = APPLY_MATRIX (matrix, 1, y, u, v);
+        b = APPLY_MATRIX (matrix, 2, y, u, v);
+
+        dest[j + p_out[1]] = CLAMP (r, 0, 255);
+        dest[j + p_out[2]] = CLAMP (g, 0, 255);
+        dest[j + p_out[3]] = CLAMP (b, 0, 255);
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  } else {
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j++) {
+        y = src[4 * j + 1];
+        u = src[4 * j + 2];
+        v = src[4 * j + 3];
+
+        r = APPLY_MATRIX (matrix, 0, y, u, v);
+        g = APPLY_MATRIX (matrix, 1, y, u, v);
+        b = APPLY_MATRIX (matrix, 2, y, u, v);
+
+        dest[out_bpp * j + p_out[1]] = CLAMP (r, 0, 255);
+        dest[out_bpp * j + p_out[2]] = CLAMP (g, 0, 255);
+        dest[out_bpp * j + p_out[3]] = CLAMP (b, 0, 255);
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  }
+}
+
+static void
+fill_gray (GstVideoBoxFill fill_type, guint b_alpha,
+    GstVideoFrame * frame, gboolean sdtv)
+{
+  gint i, j;
+  gint dest_stride;
+  guint8 *dest;
+  gint width, height;
+  GstVideoFormat format;
+
+  format = GST_VIDEO_FRAME_FORMAT (frame);
+
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
+
+  dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+
+  if (format == GST_VIDEO_FORMAT_GRAY8) {
+    guint8 val = yuv_sdtv_colors_Y[fill_type];
+
+    for (i = 0; i < height; i++) {
+      memset (dest, val, width);
+      dest += dest_stride;
+    }
+  } else {
+    guint16 val = yuv_sdtv_colors_Y[fill_type] << 8;
+
+    if (format == GST_VIDEO_FORMAT_GRAY16_BE) {
+      for (i = 0; i < height; i++) {
+        for (j = 0; j < width; j++) {
+          GST_WRITE_UINT16_BE (dest + 2 * j, val);
+        }
+        dest += dest_stride;
+      }
+    } else {
+      for (i = 0; i < height; i++) {
+        for (j = 0; j < width; j++) {
+          GST_WRITE_UINT16_LE (dest + 2 * j, val);
+        }
+        dest += dest_stride;
+      }
+    }
+  }
+}
+
+static void
+copy_packed_simple (guint i_alpha, GstVideoFrame * dest_frame,
+    gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src_frame,
+    gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
+{
+  gint i;
+  gint src_stride, dest_stride;
+  gint pixel_stride, row_size;
+  guint8 *src, *dest;
+
+  src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src_frame, 0);
+  dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest_frame, 0);
+  pixel_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (dest_frame, 0);
+  row_size = w * pixel_stride;
+
+  dest = GST_VIDEO_FRAME_PLANE_DATA (dest_frame, 0);
+  dest = dest + dest_y * dest_stride + dest_x * pixel_stride;
+  src = GST_VIDEO_FRAME_PLANE_DATA (src_frame, 0);
+  src = src + src_y * src_stride + src_x * pixel_stride;
+
+  for (i = 0; i < h; i++) {
+    memcpy (dest, src, row_size);
+    dest += dest_stride;
+    src += src_stride;
+  }
+}
+
+static void
+fill_yuy2 (GstVideoBoxFill fill_type, guint b_alpha,
+    GstVideoFrame * frame, gboolean sdtv)
+{
+  guint8 y, u, v;
+  gint i, j;
+  gint stride;
+  gint width, height;
+  guint8 *dest;
+  GstVideoFormat format;
+
+  format = GST_VIDEO_FRAME_FORMAT (frame);
+
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
+
+  dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+
+  y = (sdtv) ? yuv_sdtv_colors_Y[fill_type] : yuv_hdtv_colors_Y[fill_type];
+  u = (sdtv) ? yuv_sdtv_colors_U[fill_type] : yuv_hdtv_colors_U[fill_type];
+  v = (sdtv) ? yuv_sdtv_colors_V[fill_type] : yuv_hdtv_colors_V[fill_type];
+
+  width = width + (width % 2);
+
+  if (format == GST_VIDEO_FORMAT_YUY2) {
+    for (i = 0; i < height; i++) {
+      for (j = 0; j < width; j += 2) {
+        dest[j * 2 + 0] = y;
+        dest[j * 2 + 1] = u;
+        dest[j * 2 + 2] = y;
+        dest[j * 2 + 3] = v;
+      }
+
+      dest += stride;
+    }
+  } else if (format == GST_VIDEO_FORMAT_YVYU) {
+    for (i = 0; i < height; i++) {
+      for (j = 0; j < width; j += 2) {
+        dest[j * 2 + 0] = y;
+        dest[j * 2 + 1] = v;
+        dest[j * 2 + 2] = y;
+        dest[j * 2 + 3] = u;
+      }
+
+      dest += stride;
+    }
+  } else {
+    for (i = 0; i < height; i++) {
+      for (j = 0; j < width; j += 2) {
+        dest[j * 2 + 0] = u;
+        dest[j * 2 + 1] = y;
+        dest[j * 2 + 2] = v;
+        dest[j * 2 + 3] = y;
+      }
+
+      dest += stride;
+    }
+  }
+}
+
+static void
+copy_yuy2_yuy2 (guint i_alpha, GstVideoFrame * dest_frame,
+    gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src_frame,
+    gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
+{
+  gint i, j;
+  gint src_stride, dest_stride;
+  guint8 *src, *dest;
+  GstVideoFormat src_format;
+
+  src_format = GST_VIDEO_FRAME_FORMAT (src_frame);
+
+  src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src_frame, 0);
+  dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest_frame, 0);
+
+  dest_x = (dest_x & ~1);
+  src_x = (src_x & ~1);
+
+  w = w + (w % 2);
+
+  dest = GST_VIDEO_FRAME_PLANE_DATA (dest_frame, 0);
+  dest = dest + dest_y * dest_stride + dest_x * 2;
+  src = GST_VIDEO_FRAME_PLANE_DATA (src_frame, 0);
+  src = src + src_y * src_stride + src_x * 2;
+
+  if (src_sdtv != dest_sdtv) {
+    gint y1, u1, v1;
+    gint y2, u2, v2;
+    gint matrix[12];
+
+    memcpy (matrix,
+        dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+
+    if (src_format == GST_VIDEO_FORMAT_YUY2) {
+      for (i = 0; i < h; i++) {
+        for (j = 0; j < w; j += 2) {
+          y1 = src[j * 2 + 0];
+          y2 = src[j * 2 + 2];
+          u1 = u2 = src[j * 2 + 1];
+          v1 = v2 = src[j * 2 + 3];
+
+          dest[j * 2 + 0] = APPLY_MATRIX (matrix, 0, y1, u1, v1);
+          dest[j * 2 + 1] = APPLY_MATRIX (matrix, 1, y1, u1, v1);
+          dest[j * 2 + 2] = APPLY_MATRIX (matrix, 0, y1, u2, v2);
+          dest[j * 2 + 3] = APPLY_MATRIX (matrix, 2, y2, u2, v2);
+        }
+        dest += dest_stride;
+        src += src_stride;
+      }
+    } else if (src_format == GST_VIDEO_FORMAT_YVYU) {
+      for (i = 0; i < h; i++) {
+        for (j = 0; j < w; j += 2) {
+          y1 = src[j * 2 + 0];
+          y2 = src[j * 2 + 2];
+          v1 = v2 = src[j * 2 + 1];
+          u1 = u2 = src[j * 2 + 3];
+
+          dest[j * 2 + 0] = APPLY_MATRIX (matrix, 0, y1, u1, v1);
+          dest[j * 2 + 1] = APPLY_MATRIX (matrix, 2, y1, u1, v1);
+          dest[j * 2 + 2] = APPLY_MATRIX (matrix, 0, y1, u2, v2);
+          dest[j * 2 + 3] = APPLY_MATRIX (matrix, 1, y2, u2, v2);
+        }
+        dest += dest_stride;
+        src += src_stride;
+      }
+    } else {
+      for (i = 0; i < h; i++) {
+        for (j = 0; j < w; j += 2) {
+          u1 = u2 = src[j * 2 + 0];
+          v1 = v2 = src[j * 2 + 2];
+          y1 = src[j * 2 + 1];
+          y2 = src[j * 2 + 3];
+
+          dest[j * 2 + 1] = APPLY_MATRIX (matrix, 0, y1, u1, v1);
+          dest[j * 2 + 0] = APPLY_MATRIX (matrix, 1, y1, u1, v1);
+          dest[j * 2 + 3] = APPLY_MATRIX (matrix, 0, y1, u2, v2);
+          dest[j * 2 + 2] = APPLY_MATRIX (matrix, 2, y2, u2, v2);
+        }
+        dest += dest_stride;
+        src += src_stride;
+      }
+    }
+  } else {
+    for (i = 0; i < h; i++) {
+      memcpy (dest, src, w * 2);
+      dest += dest_stride;
+      src += src_stride;
+    }
+  }
+}
+
+#define DEFAULT_LEFT      0
+#define DEFAULT_RIGHT     0
+#define DEFAULT_TOP       0
+#define DEFAULT_BOTTOM    0
+#define DEFAULT_FILL_TYPE VIDEO_BOX_FILL_BLACK
+#define DEFAULT_ALPHA     1.0
+#define DEFAULT_BORDER_ALPHA 1.0
+
+enum
+{
+  PROP_0,
+  PROP_LEFT,
+  PROP_RIGHT,
+  PROP_TOP,
+  PROP_BOTTOM,
+  PROP_FILL_TYPE,
+  PROP_ALPHA,
+  PROP_BORDER_ALPHA,
+  PROP_AUTOCROP
+      /* FILL ME */
+};
+
+static GstStaticPadTemplate gst_video_box_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, "
+            "ARGB, BGRA, ABGR, RGBA, xRGB, BGRx, xBGR, RGBx, RGB, BGR, "
+            "Y444, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B, "
+            "GRAY8, GRAY16_BE, GRAY16_LE } "))
+    );
+
+static GstStaticPadTemplate gst_video_box_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, "
+            "ARGB, BGRA, ABGR, RGBA, xRGB, BGRx, xBGR, RGBx, RGB, BGR, "
+            "Y444, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B, "
+            "GRAY8, GRAY16_BE, GRAY16_LE } "))
+    );
+
+#define gst_video_box_parent_class parent_class
+G_DEFINE_TYPE (GstVideoBox, gst_video_box, GST_TYPE_VIDEO_FILTER);
+
+static void gst_video_box_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_video_box_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_video_box_recalc_transform (GstVideoBox * video_box);
+static GstCaps *gst_video_box_transform_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * from, GstCaps * filter);
+static void gst_video_box_before_transform (GstBaseTransform * trans,
+    GstBuffer * in);
+static gboolean gst_video_box_src_event (GstBaseTransform * trans,
+    GstEvent * event);
+
+static gboolean gst_video_box_set_info (GstVideoFilter * vfilter, GstCaps * in,
+    GstVideoInfo * in_info, GstCaps * out, GstVideoInfo * out_info);
+static GstFlowReturn gst_video_box_transform_frame (GstVideoFilter * vfilter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame);
+
+#define GST_TYPE_VIDEO_BOX_FILL (gst_video_box_fill_get_type())
+static GType
+gst_video_box_fill_get_type (void)
+{
+  static GType video_box_fill_type = 0;
+  static const GEnumValue video_box_fill[] = {
+    {VIDEO_BOX_FILL_BLACK, "Black", "black"},
+    {VIDEO_BOX_FILL_GREEN, "Green", "green"},
+    {VIDEO_BOX_FILL_BLUE, "Blue", "blue"},
+    {VIDEO_BOX_FILL_RED, "Red", "red"},
+    {VIDEO_BOX_FILL_YELLOW, "Yellow", "yellow"},
+    {VIDEO_BOX_FILL_WHITE, "White", "white"},
+    {0, NULL, NULL},
+  };
+
+  if (!video_box_fill_type) {
+    video_box_fill_type =
+        g_enum_register_static ("GstVideoBoxFill", video_box_fill);
+  }
+  return video_box_fill_type;
+}
+
+static void
+gst_video_box_finalize (GObject * object)
+{
+  GstVideoBox *video_box = GST_VIDEO_BOX (object);
+
+  g_mutex_clear (&video_box->mutex);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_video_box_class_init (GstVideoBoxClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *element_class = (GstElementClass *) (klass);
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->set_property = gst_video_box_set_property;
+  gobject_class->get_property = gst_video_box_get_property;
+  gobject_class->finalize = gst_video_box_finalize;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FILL_TYPE,
+      g_param_spec_enum ("fill", "Fill", "How to fill the borders",
+          GST_TYPE_VIDEO_BOX_FILL, DEFAULT_FILL_TYPE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LEFT,
+      g_param_spec_int ("left", "Left",
+          "Pixels to box at left (<0  = add a border)", G_MININT, G_MAXINT,
+          DEFAULT_LEFT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_RIGHT,
+      g_param_spec_int ("right", "Right",
+          "Pixels to box at right (<0 = add a border)", G_MININT, G_MAXINT,
+          DEFAULT_RIGHT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TOP,
+      g_param_spec_int ("top", "Top",
+          "Pixels to box at top (<0 = add a border)", G_MININT, G_MAXINT,
+          DEFAULT_TOP,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BOTTOM,
+      g_param_spec_int ("bottom", "Bottom",
+          "Pixels to box at bottom (<0 = add a border)", G_MININT, G_MAXINT,
+          DEFAULT_BOTTOM,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALPHA,
+      g_param_spec_double ("alpha", "Alpha", "Alpha value picture", 0.0, 1.0,
+          DEFAULT_ALPHA,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BORDER_ALPHA,
+      g_param_spec_double ("border-alpha", "Border Alpha",
+          "Alpha value of the border", 0.0, 1.0, DEFAULT_BORDER_ALPHA,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  /**
+   * GstVideoBox:autocrop:
+   *
+   * If set to %TRUE videobox will automatically crop/pad the input
+   * video to be centered in the output.
+   */
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOCROP,
+      g_param_spec_boolean ("autocrop", "Auto crop",
+          "Auto crop", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  trans_class->before_transform =
+      GST_DEBUG_FUNCPTR (gst_video_box_before_transform);
+  trans_class->transform_caps =
+      GST_DEBUG_FUNCPTR (gst_video_box_transform_caps);
+  trans_class->src_event = GST_DEBUG_FUNCPTR (gst_video_box_src_event);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_video_box_set_info);
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_video_box_transform_frame);
+
+  gst_element_class_set_static_metadata (element_class, "Video box filter",
+      "Filter/Effect/Video",
+      "Resizes a video by adding borders or cropping",
+      "Wim Taymans <wim@fluendo.com>");
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_video_box_sink_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_video_box_src_template);
+}
+
+static void
+gst_video_box_init (GstVideoBox * video_box)
+{
+  video_box->box_right = DEFAULT_RIGHT;
+  video_box->box_left = DEFAULT_LEFT;
+  video_box->box_top = DEFAULT_TOP;
+  video_box->box_bottom = DEFAULT_BOTTOM;
+  video_box->crop_right = 0;
+  video_box->crop_left = 0;
+  video_box->crop_top = 0;
+  video_box->crop_bottom = 0;
+  video_box->fill_type = DEFAULT_FILL_TYPE;
+  video_box->alpha = DEFAULT_ALPHA;
+  video_box->border_alpha = DEFAULT_BORDER_ALPHA;
+  video_box->autocrop = FALSE;
+
+  g_mutex_init (&video_box->mutex);
+}
+
+static void
+gst_video_box_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVideoBox *video_box = GST_VIDEO_BOX (object);
+
+  g_mutex_lock (&video_box->mutex);
+  switch (prop_id) {
+    case PROP_LEFT:
+      video_box->box_left = g_value_get_int (value);
+      if (video_box->box_left < 0) {
+        video_box->border_left = -video_box->box_left;
+        video_box->crop_left = 0;
+      } else {
+        video_box->border_left = 0;
+        video_box->crop_left = video_box->box_left;
+      }
+      break;
+    case PROP_RIGHT:
+      video_box->box_right = g_value_get_int (value);
+      if (video_box->box_right < 0) {
+        video_box->border_right = -video_box->box_right;
+        video_box->crop_right = 0;
+      } else {
+        video_box->border_right = 0;
+        video_box->crop_right = video_box->box_right;
+      }
+      break;
+    case PROP_TOP:
+      video_box->box_top = g_value_get_int (value);
+      if (video_box->box_top < 0) {
+        video_box->border_top = -video_box->box_top;
+        video_box->crop_top = 0;
+      } else {
+        video_box->border_top = 0;
+        video_box->crop_top = video_box->box_top;
+      }
+      break;
+    case PROP_BOTTOM:
+      video_box->box_bottom = g_value_get_int (value);
+      if (video_box->box_bottom < 0) {
+        video_box->border_bottom = -video_box->box_bottom;
+        video_box->crop_bottom = 0;
+      } else {
+        video_box->border_bottom = 0;
+        video_box->crop_bottom = video_box->box_bottom;
+      }
+      break;
+    case PROP_FILL_TYPE:
+      video_box->fill_type = g_value_get_enum (value);
+      break;
+    case PROP_ALPHA:
+      video_box->alpha = g_value_get_double (value);
+      break;
+    case PROP_BORDER_ALPHA:
+      video_box->border_alpha = g_value_get_double (value);
+      break;
+    case PROP_AUTOCROP:
+      video_box->autocrop = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  gst_video_box_recalc_transform (video_box);
+
+  GST_DEBUG_OBJECT (video_box, "Calling reconfigure");
+  gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM_CAST (video_box));
+
+  g_mutex_unlock (&video_box->mutex);
+}
+
+static void
+gst_video_box_autocrop (GstVideoBox * video_box)
+{
+  gint crop_w = video_box->in_width - video_box->out_width;
+  gint crop_h = video_box->in_height - video_box->out_height;
+
+  video_box->box_left = crop_w / 2;
+  if (video_box->box_left < 0) {
+    video_box->border_left = -video_box->box_left;
+    video_box->crop_left = 0;
+  } else {
+    video_box->border_left = 0;
+    video_box->crop_left = video_box->box_left;
+  }
+
+  /* Round down/up for odd width differences */
+  if (crop_w < 0)
+    crop_w -= 1;
+  else
+    crop_w += 1;
+
+  video_box->box_right = crop_w / 2;
+  if (video_box->box_right < 0) {
+    video_box->border_right = -video_box->box_right;
+    video_box->crop_right = 0;
+  } else {
+    video_box->border_right = 0;
+    video_box->crop_right = video_box->box_right;
+  }
+
+  video_box->box_top = crop_h / 2;
+  if (video_box->box_top < 0) {
+    video_box->border_top = -video_box->box_top;
+    video_box->crop_top = 0;
+  } else {
+    video_box->border_top = 0;
+    video_box->crop_top = video_box->box_top;
+  }
+
+  /* Round down/up for odd height differences */
+  if (crop_h < 0)
+    crop_h -= 1;
+  else
+    crop_h += 1;
+  video_box->box_bottom = crop_h / 2;
+
+  if (video_box->box_bottom < 0) {
+    video_box->border_bottom = -video_box->box_bottom;
+    video_box->crop_bottom = 0;
+  } else {
+    video_box->border_bottom = 0;
+    video_box->crop_bottom = video_box->box_bottom;
+  }
+}
+
+static void
+gst_video_box_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstVideoBox *video_box = GST_VIDEO_BOX (object);
+
+  switch (prop_id) {
+    case PROP_LEFT:
+      g_value_set_int (value, video_box->box_left);
+      break;
+    case PROP_RIGHT:
+      g_value_set_int (value, video_box->box_right);
+      break;
+    case PROP_TOP:
+      g_value_set_int (value, video_box->box_top);
+      break;
+    case PROP_BOTTOM:
+      g_value_set_int (value, video_box->box_bottom);
+      break;
+    case PROP_FILL_TYPE:
+      g_value_set_enum (value, video_box->fill_type);
+      break;
+    case PROP_ALPHA:
+      g_value_set_double (value, video_box->alpha);
+      break;
+    case PROP_BORDER_ALPHA:
+      g_value_set_double (value, video_box->border_alpha);
+      break;
+    case PROP_AUTOCROP:
+      g_value_set_boolean (value, video_box->autocrop);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static inline gint
+gst_video_box_transform_dimension (gint val, gint delta)
+{
+  gint64 new_val = (gint64) val + (gint64) delta;
+
+  new_val = CLAMP (new_val, 1, G_MAXINT);
+
+  return (gint) new_val;
+}
+
+static gboolean
+gst_video_box_transform_dimension_value (const GValue * src_val,
+    gint delta, GValue * dest_val)
+{
+  gboolean ret = TRUE;
+
+  g_value_init (dest_val, G_VALUE_TYPE (src_val));
+
+  if (G_VALUE_HOLDS_INT (src_val)) {
+    gint ival = g_value_get_int (src_val);
+
+    ival = gst_video_box_transform_dimension (ival, delta);
+    g_value_set_int (dest_val, ival);
+  } else if (GST_VALUE_HOLDS_INT_RANGE (src_val)) {
+    gint min = gst_value_get_int_range_min (src_val);
+    gint max = gst_value_get_int_range_max (src_val);
+
+    min = gst_video_box_transform_dimension (min, delta);
+    max = gst_video_box_transform_dimension (max, delta);
+    if (min >= max) {
+      ret = FALSE;
+      g_value_unset (dest_val);
+    } else {
+      gst_value_set_int_range (dest_val, min, max);
+    }
+  } else if (GST_VALUE_HOLDS_LIST (src_val)) {
+    gint i;
+
+    for (i = 0; i < gst_value_list_get_size (src_val); ++i) {
+      const GValue *list_val;
+      GValue newval = { 0, };
+
+      list_val = gst_value_list_get_value (src_val, i);
+      if (gst_video_box_transform_dimension_value (list_val, delta, &newval))
+        gst_value_list_append_value (dest_val, &newval);
+      g_value_unset (&newval);
+    }
+
+    if (gst_value_list_get_size (dest_val) == 0) {
+      g_value_unset (dest_val);
+      ret = FALSE;
+    }
+  } else {
+    g_value_unset (dest_val);
+    ret = FALSE;
+  }
+
+  return ret;
+}
+
+static GstCaps *
+gst_video_box_transform_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * from, GstCaps * filter)
+{
+  GstVideoBox *video_box = GST_VIDEO_BOX (trans);
+  GstCaps *to, *ret;
+  GstCaps *templ;
+  GstStructure *structure;
+  GstPad *other;
+  gint i, j;
+
+  to = gst_caps_new_empty ();
+  for (i = 0; i < gst_caps_get_size (from); i++) {
+    const GValue *fval, *lval;
+    GValue list = { 0, };
+    GValue val = { 0, };
+    gboolean seen_yuv = FALSE, seen_rgb = FALSE;
+    const gchar *str;
+
+    structure = gst_structure_copy (gst_caps_get_structure (from, i));
+
+    /* Transform width/height */
+    if (video_box->autocrop) {
+      gst_structure_remove_field (structure, "width");
+      gst_structure_remove_field (structure, "height");
+    } else {
+      gint dw = 0, dh = 0;
+      const GValue *v;
+      GValue w_val = { 0, };
+      GValue h_val = { 0, };
+
+      /* calculate width and height */
+      if (direction == GST_PAD_SINK) {
+        dw -= video_box->box_left;
+        dw -= video_box->box_right;
+      } else {
+        dw += video_box->box_left;
+        dw += video_box->box_right;
+      }
+
+      if (direction == GST_PAD_SINK) {
+        dh -= video_box->box_top;
+        dh -= video_box->box_bottom;
+      } else {
+        dh += video_box->box_top;
+        dh += video_box->box_bottom;
+      }
+
+      v = gst_structure_get_value (structure, "width");
+      if (!gst_video_box_transform_dimension_value (v, dw, &w_val)) {
+        GST_WARNING_OBJECT (video_box,
+            "could not tranform width value with dw=%d" ", caps structure=%"
+            GST_PTR_FORMAT, dw, structure);
+        goto bail;
+      }
+      gst_structure_set_value (structure, "width", &w_val);
+
+      v = gst_structure_get_value (structure, "height");
+      if (!gst_video_box_transform_dimension_value (v, dh, &h_val)) {
+        g_value_unset (&w_val);
+        GST_WARNING_OBJECT (video_box,
+            "could not tranform height value with dh=%d" ", caps structure=%"
+            GST_PTR_FORMAT, dh, structure);
+        goto bail;
+      }
+      gst_structure_set_value (structure, "height", &h_val);
+      g_value_unset (&w_val);
+      g_value_unset (&h_val);
+    }
+
+    /* Supported conversions:
+     * I420->AYUV
+     * I420->YV12
+     * YV12->AYUV
+     * YV12->I420
+     * AYUV->I420
+     * AYUV->YV12
+     * AYUV->xRGB (24bpp, 32bpp, incl. alpha)
+     * xRGB->xRGB (24bpp, 32bpp, from/to all variants, incl. alpha)
+     * xRGB->AYUV (24bpp, 32bpp, incl. alpha)
+     *
+     * Passthrough only for everything else.
+     */
+    fval = gst_structure_get_value (structure, "format");
+    if (fval && GST_VALUE_HOLDS_LIST (fval)) {
+      for (j = 0; j < gst_value_list_get_size (fval); j++) {
+        lval = gst_value_list_get_value (fval, j);
+        if ((str = g_value_get_string (lval))) {
+          if (strcmp (str, "AYUV") == 0) {
+            seen_yuv = TRUE;
+            seen_rgb = TRUE;
+            break;
+          } else if (strstr (str, "RGB") || strstr (str, "BGR")) {
+            seen_rgb = TRUE;
+          } else if (strcmp (str, "I420") == 0 || strcmp (str, "YV12") == 0) {
+            seen_yuv = TRUE;
+          }
+        }
+      }
+    } else if (fval && G_VALUE_HOLDS_STRING (fval)) {
+      if ((str = g_value_get_string (fval))) {
+        if (strcmp (str, "AYUV") == 0) {
+          seen_yuv = TRUE;
+          seen_rgb = TRUE;
+        } else if (strstr (str, "RGB") || strstr (str, "BGR")) {
+          seen_rgb = TRUE;
+        } else if (strcmp (str, "I420") == 0 || strcmp (str, "YV12") == 0) {
+          seen_yuv = TRUE;
+        }
+      }
+    }
+
+    if (seen_yuv || seen_rgb) {
+      g_value_init (&list, GST_TYPE_LIST);
+
+      g_value_init (&val, G_TYPE_STRING);
+      g_value_set_string (&val, "AYUV");
+      gst_value_list_append_value (&list, &val);
+      g_value_unset (&val);
+
+      if (seen_yuv) {
+        g_value_init (&val, G_TYPE_STRING);
+        g_value_set_string (&val, "I420");
+        gst_value_list_append_value (&list, &val);
+        g_value_reset (&val);
+        g_value_set_string (&val, "YV12");
+        gst_value_list_append_value (&list, &val);
+        g_value_unset (&val);
+      }
+      if (seen_rgb) {
+        g_value_init (&val, G_TYPE_STRING);
+        g_value_set_string (&val, "RGBx");
+        gst_value_list_append_value (&list, &val);
+        g_value_reset (&val);
+        g_value_set_string (&val, "BGRx");
+        gst_value_list_append_value (&list, &val);
+        g_value_reset (&val);
+        g_value_set_string (&val, "xRGB");
+        gst_value_list_append_value (&list, &val);
+        g_value_reset (&val);
+        g_value_set_string (&val, "xBGR");
+        gst_value_list_append_value (&list, &val);
+        g_value_reset (&val);
+        g_value_set_string (&val, "RGBA");
+        gst_value_list_append_value (&list, &val);
+        g_value_reset (&val);
+        g_value_set_string (&val, "BGRA");
+        gst_value_list_append_value (&list, &val);
+        g_value_reset (&val);
+        g_value_set_string (&val, "ARGB");
+        gst_value_list_append_value (&list, &val);
+        g_value_reset (&val);
+        g_value_set_string (&val, "ABGR");
+        gst_value_list_append_value (&list, &val);
+        g_value_reset (&val);
+        g_value_set_string (&val, "RGB");
+        gst_value_list_append_value (&list, &val);
+        g_value_reset (&val);
+        g_value_set_string (&val, "BGR");
+        gst_value_list_append_value (&list, &val);
+        g_value_unset (&val);
+      }
+      gst_value_list_merge (&val, fval, &list);
+      gst_structure_set_value (structure, "format", &val);
+      g_value_unset (&val);
+      g_value_unset (&list);
+    }
+
+    gst_structure_remove_field (structure, "colorimetry");
+    gst_structure_remove_field (structure, "chroma-site");
+
+    gst_caps_append_structure (to, structure);
+  }
+
+  /* filter against set allowed caps on the pad */
+  other = (direction == GST_PAD_SINK) ? trans->srcpad : trans->sinkpad;
+  templ = gst_pad_get_pad_template_caps (other);
+  ret = gst_caps_intersect (to, templ);
+  gst_caps_unref (to);
+  gst_caps_unref (templ);
+
+  GST_DEBUG_OBJECT (video_box, "direction %d, transformed %" GST_PTR_FORMAT
+      " to %" GST_PTR_FORMAT, direction, from, ret);
+
+  if (ret && filter) {
+    GstCaps *intersection;
+
+    GST_DEBUG_OBJECT (video_box, "Using filter caps %" GST_PTR_FORMAT, filter);
+    intersection =
+        gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (ret);
+    ret = intersection;
+    GST_DEBUG_OBJECT (video_box, "Intersection %" GST_PTR_FORMAT, ret);
+  }
+
+  return ret;
+
+  /* ERRORS */
+bail:
+  {
+    gst_structure_free (structure);
+    gst_caps_unref (to);
+    to = gst_caps_new_empty ();
+    return to;
+  }
+}
+
+static gboolean
+gst_video_box_recalc_transform (GstVideoBox * video_box)
+{
+  gboolean res = TRUE;
+
+  /* if we have the same format in and out and we don't need to perform any
+   * cropping at all, we can just operate in passthrough mode */
+  if (video_box->in_format == video_box->out_format &&
+      video_box->box_left == 0 && video_box->box_right == 0 &&
+      video_box->box_top == 0 && video_box->box_bottom == 0 &&
+      video_box->in_sdtv == video_box->out_sdtv) {
+
+    GST_LOG_OBJECT (video_box, "we are using passthrough");
+    gst_base_transform_set_passthrough (GST_BASE_TRANSFORM_CAST (video_box),
+        TRUE);
+  } else {
+    GST_LOG_OBJECT (video_box, "we are not using passthrough");
+    gst_base_transform_set_passthrough (GST_BASE_TRANSFORM_CAST (video_box),
+        FALSE);
+  }
+  return res;
+}
+
+static gboolean
+gst_video_box_select_processing_functions (GstVideoBox * video_box)
+{
+  switch (video_box->out_format) {
+    case GST_VIDEO_FORMAT_AYUV:
+      video_box->fill = fill_ayuv;
+      switch (video_box->in_format) {
+        case GST_VIDEO_FORMAT_AYUV:
+          video_box->copy = copy_ayuv_ayuv;
+          break;
+        case GST_VIDEO_FORMAT_I420:
+        case GST_VIDEO_FORMAT_YV12:
+          video_box->copy = copy_i420_ayuv;
+          break;
+        case GST_VIDEO_FORMAT_ARGB:
+        case GST_VIDEO_FORMAT_ABGR:
+        case GST_VIDEO_FORMAT_RGBA:
+        case GST_VIDEO_FORMAT_BGRA:
+        case GST_VIDEO_FORMAT_xRGB:
+        case GST_VIDEO_FORMAT_xBGR:
+        case GST_VIDEO_FORMAT_RGBx:
+        case GST_VIDEO_FORMAT_BGRx:
+        case GST_VIDEO_FORMAT_RGB:
+        case GST_VIDEO_FORMAT_BGR:
+          video_box->copy = copy_rgb32_ayuv;
+          break;
+        default:
+          break;
+      }
+      break;
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+      video_box->fill = fill_planar_yuv;
+      switch (video_box->in_format) {
+        case GST_VIDEO_FORMAT_AYUV:
+          video_box->copy = copy_ayuv_i420;
+          break;
+        case GST_VIDEO_FORMAT_I420:
+        case GST_VIDEO_FORMAT_YV12:
+          video_box->copy = copy_i420_i420;
+          break;
+        default:
+          break;
+      }
+      break;
+    case GST_VIDEO_FORMAT_ARGB:
+    case GST_VIDEO_FORMAT_ABGR:
+    case GST_VIDEO_FORMAT_RGBA:
+    case GST_VIDEO_FORMAT_BGRA:
+    case GST_VIDEO_FORMAT_xRGB:
+    case GST_VIDEO_FORMAT_xBGR:
+    case GST_VIDEO_FORMAT_RGBx:
+    case GST_VIDEO_FORMAT_BGRx:
+    case GST_VIDEO_FORMAT_RGB:
+    case GST_VIDEO_FORMAT_BGR:
+      video_box->fill = (video_box->out_format == GST_VIDEO_FORMAT_BGR
+          || video_box->out_format ==
+          GST_VIDEO_FORMAT_RGB) ? fill_rgb24 : fill_rgb32;
+      switch (video_box->in_format) {
+        case GST_VIDEO_FORMAT_ARGB:
+        case GST_VIDEO_FORMAT_ABGR:
+        case GST_VIDEO_FORMAT_RGBA:
+        case GST_VIDEO_FORMAT_BGRA:
+        case GST_VIDEO_FORMAT_xRGB:
+        case GST_VIDEO_FORMAT_xBGR:
+        case GST_VIDEO_FORMAT_RGBx:
+        case GST_VIDEO_FORMAT_BGRx:
+        case GST_VIDEO_FORMAT_RGB:
+        case GST_VIDEO_FORMAT_BGR:
+          video_box->copy = copy_rgb32;
+          break;
+        case GST_VIDEO_FORMAT_AYUV:
+          video_box->copy = copy_ayuv_rgb32;
+        default:
+          break;
+      }
+      break;
+    case GST_VIDEO_FORMAT_GRAY8:
+    case GST_VIDEO_FORMAT_GRAY16_BE:
+    case GST_VIDEO_FORMAT_GRAY16_LE:
+      video_box->fill = fill_gray;
+      switch (video_box->in_format) {
+        case GST_VIDEO_FORMAT_GRAY8:
+        case GST_VIDEO_FORMAT_GRAY16_BE:
+        case GST_VIDEO_FORMAT_GRAY16_LE:
+          video_box->copy = copy_packed_simple;
+          break;
+        default:
+          break;
+      }
+      break;
+    case GST_VIDEO_FORMAT_YUY2:
+    case GST_VIDEO_FORMAT_YVYU:
+    case GST_VIDEO_FORMAT_UYVY:
+      video_box->fill = fill_yuy2;
+      switch (video_box->in_format) {
+        case GST_VIDEO_FORMAT_YUY2:
+        case GST_VIDEO_FORMAT_YVYU:
+        case GST_VIDEO_FORMAT_UYVY:
+          video_box->copy = copy_yuy2_yuy2;
+          break;
+        default:
+          break;
+      }
+      break;
+    case GST_VIDEO_FORMAT_Y444:
+    case GST_VIDEO_FORMAT_Y42B:
+    case GST_VIDEO_FORMAT_Y41B:
+      video_box->fill = fill_planar_yuv;
+      switch (video_box->in_format) {
+        case GST_VIDEO_FORMAT_Y444:
+          video_box->copy = copy_y444_y444;
+          break;
+        case GST_VIDEO_FORMAT_Y42B:
+          video_box->copy = copy_y42b_y42b;
+          break;
+        case GST_VIDEO_FORMAT_Y41B:
+          video_box->copy = copy_y41b_y41b;
+          break;
+        default:
+          break;
+      }
+      break;
+    default:
+      break;
+  }
+
+  return video_box->fill != NULL && video_box->copy != NULL;
+}
+
+static gboolean
+gst_video_box_set_info (GstVideoFilter * vfilter, GstCaps * in,
+    GstVideoInfo * in_info, GstCaps * out, GstVideoInfo * out_info)
+{
+  GstVideoBox *video_box = GST_VIDEO_BOX (vfilter);
+  gboolean ret;
+
+  g_mutex_lock (&video_box->mutex);
+
+  video_box->in_format = GST_VIDEO_INFO_FORMAT (in_info);
+  video_box->in_width = GST_VIDEO_INFO_WIDTH (in_info);
+  video_box->in_height = GST_VIDEO_INFO_HEIGHT (in_info);
+
+  video_box->out_format = GST_VIDEO_INFO_FORMAT (out_info);
+  video_box->out_width = GST_VIDEO_INFO_WIDTH (out_info);
+  video_box->out_height = GST_VIDEO_INFO_HEIGHT (out_info);
+
+  video_box->in_sdtv =
+      in_info->colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_BT601;
+  video_box->out_sdtv =
+      out_info->colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_BT601;
+
+  GST_DEBUG_OBJECT (video_box, "Input w: %d h: %d", video_box->in_width,
+      video_box->in_height);
+  GST_DEBUG_OBJECT (video_box, "Output w: %d h: %d", video_box->out_width,
+      video_box->out_height);
+
+  if (video_box->autocrop)
+    gst_video_box_autocrop (video_box);
+
+  /* recalc the transformation strategy */
+  ret = gst_video_box_recalc_transform (video_box);
+
+  if (ret)
+    ret = gst_video_box_select_processing_functions (video_box);
+  g_mutex_unlock (&video_box->mutex);
+
+  return ret;
+}
+
+static gboolean
+gst_video_box_src_event (GstBaseTransform * trans, GstEvent * event)
+{
+  GstVideoBox *video_box = GST_VIDEO_BOX (trans);
+  GstStructure *new_structure;
+  const GstStructure *structure;
+  const gchar *event_name;
+  gdouble pointer_x;
+  gdouble pointer_y;
+
+  GST_OBJECT_LOCK (video_box);
+  if (GST_EVENT_TYPE (event) == GST_EVENT_NAVIGATION &&
+      (video_box->box_left != 0 || video_box->box_top != 0)) {
+    structure = gst_event_get_structure (event);
+    event_name = gst_structure_get_string (structure, "event");
+
+    if (event_name &&
+        (strcmp (event_name, "mouse-move") == 0 ||
+            strcmp (event_name, "mouse-button-press") == 0 ||
+            strcmp (event_name, "mouse-button-release") == 0)) {
+      if (gst_structure_get_double (structure, "pointer_x", &pointer_x) &&
+          gst_structure_get_double (structure, "pointer_y", &pointer_y)) {
+        gdouble new_pointer_x, new_pointer_y;
+        GstEvent *new_event;
+
+        new_pointer_x = pointer_x + video_box->box_left;
+        new_pointer_y = pointer_y + video_box->box_top;
+
+        new_structure = gst_structure_copy (structure);
+        gst_structure_set (new_structure,
+            "pointer_x", G_TYPE_DOUBLE, (gdouble) (new_pointer_x),
+            "pointer_y", G_TYPE_DOUBLE, (gdouble) (new_pointer_y), NULL);
+
+        new_event = gst_event_new_navigation (new_structure);
+        gst_event_unref (event);
+        event = new_event;
+      } else {
+        GST_WARNING_OBJECT (video_box, "Failed to read navigation event");
+      }
+    }
+  }
+  GST_OBJECT_UNLOCK (video_box);
+
+  return GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event);
+}
+
+static void
+gst_video_box_process (GstVideoBox * video_box, GstVideoFrame * in,
+    GstVideoFrame * out)
+{
+  guint b_alpha = CLAMP (video_box->border_alpha * 256, 0, 255);
+  guint i_alpha = CLAMP (video_box->alpha * 256, 0, 255);
+  GstVideoBoxFill fill_type = video_box->fill_type;
+  gint br, bl, bt, bb, crop_w, crop_h;
+
+  crop_h = 0;
+  crop_w = 0;
+
+  br = video_box->box_right;
+  bl = video_box->box_left;
+  bt = video_box->box_top;
+  bb = video_box->box_bottom;
+
+  if (br >= 0 && bl >= 0) {
+    crop_w = video_box->in_width - (br + bl);
+  } else if (br >= 0 && bl < 0) {
+    crop_w = video_box->in_width - (br);
+  } else if (br < 0 && bl >= 0) {
+    crop_w = video_box->in_width - (bl);
+  } else if (br < 0 && bl < 0) {
+    crop_w = video_box->in_width;
+  }
+
+  if (bb >= 0 && bt >= 0) {
+    crop_h = video_box->in_height - (bb + bt);
+  } else if (bb >= 0 && bt < 0) {
+    crop_h = video_box->in_height - (bb);
+  } else if (bb < 0 && bt >= 0) {
+    crop_h = video_box->in_height - (bt);
+  } else if (bb < 0 && bt < 0) {
+    crop_h = video_box->in_height;
+  }
+
+  GST_DEBUG_OBJECT (video_box, "Borders are: L:%d, R:%d, T:%d, B:%d", bl, br,
+      bt, bb);
+  GST_DEBUG_OBJECT (video_box, "Alpha value is: %u (frame) %u (border)",
+      i_alpha, b_alpha);
+
+  if (crop_h < 0 || crop_w < 0) {
+    video_box->fill (fill_type, b_alpha, out, video_box->out_sdtv);
+  } else if (bb == 0 && bt == 0 && br == 0 && bl == 0) {
+    video_box->copy (i_alpha, out, video_box->out_sdtv, 0, 0, in,
+        video_box->in_sdtv, 0, 0, crop_w, crop_h);
+  } else {
+    gint src_x = 0, src_y = 0;
+    gint dest_x = 0, dest_y = 0;
+
+    /* Fill everything if a border should be added somewhere */
+    if (bt < 0 || bb < 0 || br < 0 || bl < 0)
+      video_box->fill (fill_type, b_alpha, out, video_box->out_sdtv);
+
+    /* Top border */
+    if (bt < 0) {
+      dest_y += -bt;
+    } else {
+      src_y += bt;
+    }
+
+    /* Left border */
+    if (bl < 0) {
+      dest_x += -bl;
+    } else {
+      src_x += bl;
+    }
+
+    /* Frame */
+    video_box->copy (i_alpha, out, video_box->out_sdtv, dest_x, dest_y,
+        in, video_box->in_sdtv, src_x, src_y, crop_w, crop_h);
+  }
+
+  GST_LOG_OBJECT (video_box, "image created");
+}
+
+static void
+gst_video_box_before_transform (GstBaseTransform * trans, GstBuffer * in)
+{
+  GstVideoBox *video_box = GST_VIDEO_BOX (trans);
+  GstClockTime timestamp, stream_time;
+
+  timestamp = GST_BUFFER_TIMESTAMP (in);
+  stream_time =
+      gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (video_box, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (video_box), stream_time);
+}
+
+static GstFlowReturn
+gst_video_box_transform_frame (GstVideoFilter * vfilter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame)
+{
+  GstVideoBox *video_box = GST_VIDEO_BOX (vfilter);
+
+  g_mutex_lock (&video_box->mutex);
+  gst_video_box_process (video_box, in_frame, out_frame);
+  g_mutex_unlock (&video_box->mutex);
+  return GST_FLOW_OK;
+}
+
+/* FIXME: 0.11 merge with videocrop plugin */
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (videobox_debug, "videobox", 0,
+      "Resizes a video by adding borders or cropping");
+
+  return gst_element_register (plugin, "videobox", GST_RANK_NONE,
+      GST_TYPE_VIDEO_BOX);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    videobox,
+    "resizes a video by adding borders or cropping",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/videobox/gstvideobox.h b/gst/videobox/gstvideobox.h
new file mode 100644
index 0000000..cbb98ac
--- /dev/null
+++ b/gst/videobox/gstvideobox.h
@@ -0,0 +1,92 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/gst.h>
+#include <gst/video/gstvideofilter.h>
+#include <gst/video/video.h>
+
+#ifndef __GST_VIDEO_BOX_H__
+#define __GST_VIDEO_BOX_H__
+
+#define GST_TYPE_VIDEO_BOX \
+  (gst_video_box_get_type())
+#define GST_VIDEO_BOX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_BOX,GstVideoBox))
+#define GST_VIDEO_BOX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_BOX,GstVideoBoxClass))
+#define GST_IS_VIDEO_BOX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_BOX))
+#define GST_IS_VIDEO_BOX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_BOX))
+
+typedef struct _GstVideoBox GstVideoBox;
+typedef struct _GstVideoBoxClass GstVideoBoxClass;
+
+typedef enum
+{
+  VIDEO_BOX_FILL_BLACK,
+  VIDEO_BOX_FILL_GREEN,
+  VIDEO_BOX_FILL_BLUE,
+  VIDEO_BOX_FILL_RED,
+  VIDEO_BOX_FILL_YELLOW,
+  VIDEO_BOX_FILL_WHITE,
+  VIDEO_BOX_FILL_LAST
+}
+GstVideoBoxFill;
+
+struct _GstVideoBox
+{
+  GstVideoFilter element;
+
+  /* <private> */
+
+  /* Guarding everything below */
+  GMutex mutex;
+  /* caps */
+  GstVideoFormat in_format;
+  gint in_width, in_height;
+  gboolean in_sdtv;
+  GstVideoFormat out_format;
+  gint out_width, out_height;
+  gboolean out_sdtv;
+
+  gint box_left, box_right, box_top, box_bottom;
+
+  gint border_left, border_right, border_top, border_bottom;
+  gint crop_left, crop_right, crop_top, crop_bottom;
+
+  gdouble alpha;
+  gdouble border_alpha;
+
+  GstVideoBoxFill fill_type;
+
+  gboolean autocrop;
+
+  void (*fill) (GstVideoBoxFill fill_type, guint b_alpha, GstVideoFrame *dest, gboolean sdtv);
+  void (*copy) (guint i_alpha, GstVideoFrame * dest, gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src, gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h);
+};
+
+struct _GstVideoBoxClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_video_box_get_type (void);
+
+#endif /* __GST_VIDEO_BOX_H__ */
diff --git a/gst/videobox/gstvideoboxorc-dist.c b/gst/videobox/gstvideoboxorc-dist.c
new file mode 100644
index 0000000..098b490
--- /dev/null
+++ b/gst/videobox/gstvideoboxorc-dist.c
@@ -0,0 +1,242 @@
+
+/* autogenerated from gstvideoboxorc.orc */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <glib.h>
+
+#ifndef _ORC_INTEGER_TYPEDEFS_
+#define _ORC_INTEGER_TYPEDEFS_
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+typedef int8_t orc_int8;
+typedef int16_t orc_int16;
+typedef int32_t orc_int32;
+typedef int64_t orc_int64;
+typedef uint8_t orc_uint8;
+typedef uint16_t orc_uint16;
+typedef uint32_t orc_uint32;
+typedef uint64_t orc_uint64;
+#define ORC_UINT64_C(x) UINT64_C(x)
+#elif defined(_MSC_VER)
+typedef signed __int8 orc_int8;
+typedef signed __int16 orc_int16;
+typedef signed __int32 orc_int32;
+typedef signed __int64 orc_int64;
+typedef unsigned __int8 orc_uint8;
+typedef unsigned __int16 orc_uint16;
+typedef unsigned __int32 orc_uint32;
+typedef unsigned __int64 orc_uint64;
+#define ORC_UINT64_C(x) (x##Ui64)
+#define inline __inline
+#else
+#include <limits.h>
+typedef signed char orc_int8;
+typedef short orc_int16;
+typedef int orc_int32;
+typedef unsigned char orc_uint8;
+typedef unsigned short orc_uint16;
+typedef unsigned int orc_uint32;
+#if INT_MAX == LONG_MAX
+typedef long long orc_int64;
+typedef unsigned long long orc_uint64;
+#define ORC_UINT64_C(x) (x##ULL)
+#else
+typedef long orc_int64;
+typedef unsigned long orc_uint64;
+#define ORC_UINT64_C(x) (x##UL)
+#endif
+#endif
+typedef union
+{
+  orc_int16 i;
+  orc_int8 x2[2];
+} orc_union16;
+typedef union
+{
+  orc_int32 i;
+  float f;
+  orc_int16 x2[2];
+  orc_int8 x4[4];
+} orc_union32;
+typedef union
+{
+  orc_int64 i;
+  double f;
+  orc_int32 x2[2];
+  float x2f[2];
+  orc_int16 x4[4];
+} orc_union64;
+#endif
+#ifndef ORC_RESTRICT
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define ORC_RESTRICT restrict
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define ORC_RESTRICT __restrict__
+#else
+#define ORC_RESTRICT
+#endif
+#endif
+
+#ifndef ORC_INTERNAL
+#if defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#define ORC_INTERNAL __hidden
+#elif defined (__GNUC__)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#else
+#define ORC_INTERNAL
+#endif
+#endif
+
+
+#ifndef DISABLE_ORC
+#include <orc/orc.h>
+#endif
+void video_box_orc_splat_u32 (guint32 * ORC_RESTRICT d1, int p1, int n);
+
+
+/* begin Orc C target preamble */
+#define ORC_CLAMP(x,a,b) ((x)<(a) ? (a) : ((x)>(b) ? (b) : (x)))
+#define ORC_ABS(a) ((a)<0 ? -(a) : (a))
+#define ORC_MIN(a,b) ((a)<(b) ? (a) : (b))
+#define ORC_MAX(a,b) ((a)>(b) ? (a) : (b))
+#define ORC_SB_MAX 127
+#define ORC_SB_MIN (-1-ORC_SB_MAX)
+#define ORC_UB_MAX (orc_uint8) 255
+#define ORC_UB_MIN 0
+#define ORC_SW_MAX 32767
+#define ORC_SW_MIN (-1-ORC_SW_MAX)
+#define ORC_UW_MAX (orc_uint16)65535
+#define ORC_UW_MIN 0
+#define ORC_SL_MAX 2147483647
+#define ORC_SL_MIN (-1-ORC_SL_MAX)
+#define ORC_UL_MAX 4294967295U
+#define ORC_UL_MIN 0
+#define ORC_CLAMP_SB(x) ORC_CLAMP(x,ORC_SB_MIN,ORC_SB_MAX)
+#define ORC_CLAMP_UB(x) ORC_CLAMP(x,ORC_UB_MIN,ORC_UB_MAX)
+#define ORC_CLAMP_SW(x) ORC_CLAMP(x,ORC_SW_MIN,ORC_SW_MAX)
+#define ORC_CLAMP_UW(x) ORC_CLAMP(x,ORC_UW_MIN,ORC_UW_MAX)
+#define ORC_CLAMP_SL(x) ORC_CLAMP(x,ORC_SL_MIN,ORC_SL_MAX)
+#define ORC_CLAMP_UL(x) ORC_CLAMP(x,ORC_UL_MIN,ORC_UL_MAX)
+#define ORC_SWAP_W(x) ((((x)&0xffU)<<8) | (((x)&0xff00U)>>8))
+#define ORC_SWAP_L(x) ((((x)&0xffU)<<24) | (((x)&0xff00U)<<8) | (((x)&0xff0000U)>>8) | (((x)&0xff000000U)>>24))
+#define ORC_SWAP_Q(x) ((((x)&ORC_UINT64_C(0xff))<<56) | (((x)&ORC_UINT64_C(0xff00))<<40) | (((x)&ORC_UINT64_C(0xff0000))<<24) | (((x)&ORC_UINT64_C(0xff000000))<<8) | (((x)&ORC_UINT64_C(0xff00000000))>>8) | (((x)&ORC_UINT64_C(0xff0000000000))>>24) | (((x)&ORC_UINT64_C(0xff000000000000))>>40) | (((x)&ORC_UINT64_C(0xff00000000000000))>>56))
+#define ORC_PTR_OFFSET(ptr,offset) ((void *)(((unsigned char *)(ptr)) + (offset)))
+#define ORC_DENORMAL(x) ((x) & ((((x)&0x7f800000) == 0) ? 0xff800000 : 0xffffffff))
+#define ORC_ISNAN(x) ((((x)&0x7f800000) == 0x7f800000) && (((x)&0x007fffff) != 0))
+#define ORC_DENORMAL_DOUBLE(x) ((x) & ((((x)&ORC_UINT64_C(0x7ff0000000000000)) == 0) ? ORC_UINT64_C(0xfff0000000000000) : ORC_UINT64_C(0xffffffffffffffff)))
+#define ORC_ISNAN_DOUBLE(x) ((((x)&ORC_UINT64_C(0x7ff0000000000000)) == ORC_UINT64_C(0x7ff0000000000000)) && (((x)&ORC_UINT64_C(0x000fffffffffffff)) != 0))
+#ifndef ORC_RESTRICT
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define ORC_RESTRICT restrict
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define ORC_RESTRICT __restrict__
+#else
+#define ORC_RESTRICT
+#endif
+#endif
+/* end Orc C target preamble */
+
+
+
+/* video_box_orc_splat_u32 */
+#ifdef DISABLE_ORC
+void
+video_box_orc_splat_u32 (guint32 * ORC_RESTRICT d1, int p1, int n)
+{
+  int i;
+  orc_union32 *ORC_RESTRICT ptr0;
+  orc_union32 var32;
+  orc_union32 var33;
+
+  ptr0 = (orc_union32 *) d1;
+
+  /* 0: loadpl */
+  var32.i = p1;
+
+  for (i = 0; i < n; i++) {
+    /* 1: copyl */
+    var33.i = var32.i;
+    /* 2: storel */
+    ptr0[i] = var33;
+  }
+
+}
+
+#else
+static void
+_backup_video_box_orc_splat_u32 (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union32 *ORC_RESTRICT ptr0;
+  orc_union32 var32;
+  orc_union32 var33;
+
+  ptr0 = (orc_union32 *) ex->arrays[0];
+
+  /* 0: loadpl */
+  var32.i = ex->params[24];
+
+  for (i = 0; i < n; i++) {
+    /* 1: copyl */
+    var33.i = var32.i;
+    /* 2: storel */
+    ptr0[i] = var33;
+  }
+
+}
+
+void
+video_box_orc_splat_u32 (guint32 * ORC_RESTRICT d1, int p1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 23, 118, 105, 100, 101, 111, 95, 98, 111, 120, 95, 111, 114, 99,
+        95, 115, 112, 108, 97, 116, 95, 117, 51, 50, 11, 4, 4, 16, 4, 112,
+        0, 24, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p, _backup_video_box_orc_splat_u32);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "video_box_orc_splat_u32");
+      orc_program_set_backup_function (p, _backup_video_box_orc_splat_u32);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_parameter (p, 4, "p1");
+
+      orc_program_append_2 (p, "copyl", 0, ORC_VAR_D1, ORC_VAR_P1, ORC_VAR_D1,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->params[ORC_VAR_P1] = p1;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
diff --git a/gst/videobox/gstvideoboxorc-dist.h b/gst/videobox/gstvideoboxorc-dist.h
new file mode 100644
index 0000000..23c2d0b
--- /dev/null
+++ b/gst/videobox/gstvideoboxorc-dist.h
@@ -0,0 +1,90 @@
+
+/* autogenerated from gstvideoboxorc.orc */
+
+#ifndef _GSTVIDEOBOXORC_H_
+#define _GSTVIDEOBOXORC_H_
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#ifndef _ORC_INTEGER_TYPEDEFS_
+#define _ORC_INTEGER_TYPEDEFS_
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+typedef int8_t orc_int8;
+typedef int16_t orc_int16;
+typedef int32_t orc_int32;
+typedef int64_t orc_int64;
+typedef uint8_t orc_uint8;
+typedef uint16_t orc_uint16;
+typedef uint32_t orc_uint32;
+typedef uint64_t orc_uint64;
+#define ORC_UINT64_C(x) UINT64_C(x)
+#elif defined(_MSC_VER)
+typedef signed __int8 orc_int8;
+typedef signed __int16 orc_int16;
+typedef signed __int32 orc_int32;
+typedef signed __int64 orc_int64;
+typedef unsigned __int8 orc_uint8;
+typedef unsigned __int16 orc_uint16;
+typedef unsigned __int32 orc_uint32;
+typedef unsigned __int64 orc_uint64;
+#define ORC_UINT64_C(x) (x##Ui64)
+#define inline __inline
+#else
+#include <limits.h>
+typedef signed char orc_int8;
+typedef short orc_int16;
+typedef int orc_int32;
+typedef unsigned char orc_uint8;
+typedef unsigned short orc_uint16;
+typedef unsigned int orc_uint32;
+#if INT_MAX == LONG_MAX
+typedef long long orc_int64;
+typedef unsigned long long orc_uint64;
+#define ORC_UINT64_C(x) (x##ULL)
+#else
+typedef long orc_int64;
+typedef unsigned long orc_uint64;
+#define ORC_UINT64_C(x) (x##UL)
+#endif
+#endif
+typedef union { orc_int16 i; orc_int8 x2[2]; } orc_union16;
+typedef union { orc_int32 i; float f; orc_int16 x2[2]; orc_int8 x4[4]; } orc_union32;
+typedef union { orc_int64 i; double f; orc_int32 x2[2]; float x2f[2]; orc_int16 x4[4]; } orc_union64;
+#endif
+#ifndef ORC_RESTRICT
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define ORC_RESTRICT restrict
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define ORC_RESTRICT __restrict__
+#else
+#define ORC_RESTRICT
+#endif
+#endif
+
+#ifndef ORC_INTERNAL
+#if defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#define ORC_INTERNAL __hidden
+#elif defined (__GNUC__)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#else
+#define ORC_INTERNAL
+#endif
+#endif
+
+void video_box_orc_splat_u32 (guint32 * ORC_RESTRICT d1, int p1, int n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/gst/videobox/gstvideoboxorc.orc b/gst/videobox/gstvideoboxorc.orc
new file mode 100644
index 0000000..1dbf9e7
--- /dev/null
+++ b/gst/videobox/gstvideoboxorc.orc
@@ -0,0 +1,7 @@
+
+.function video_box_orc_splat_u32
+.dest 4 d1 guint32
+.param 4 p1
+
+copyl d1, p1
+
diff --git a/gst/videobox/meson.build b/gst/videobox/meson.build
new file mode 100644
index 0000000..430ede0
--- /dev/null
+++ b/gst/videobox/meson.build
@@ -0,0 +1,27 @@
+orcsrc = 'gstvideoboxorc'
+if have_orcc
+  orc_h = custom_target(orcsrc + '.h',
+    input : orcsrc + '.orc',
+    output : orcsrc + '.h',
+    command : orcc_args + ['--header', '-o', '@OUTPUT@', '@INPUT@'])
+  orc_c = custom_target(orcsrc + '.c',
+    input : orcsrc + '.orc',
+    output : orcsrc + '.c',
+    command : orcc_args + ['--implementation', '-o', '@OUTPUT@', '@INPUT@'])
+else
+  orc_h = configure_file(input : orcsrc + '-dist.h',
+    output : orcsrc + '.h',
+    configuration : configuration_data())
+  orc_c = configure_file(input : orcsrc + '-dist.c',
+    output : orcsrc + '.c',
+    configuration : configuration_data())
+endif
+
+gstvideobox = library('gstvideobox',
+  'gstvideobox.c', orc_c, orc_h,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [orc_dep, gstbase_dep, gstvideo_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/videocrop/Makefile.am b/gst/videocrop/Makefile.am
new file mode 100644
index 0000000..3520c21
--- /dev/null
+++ b/gst/videocrop/Makefile.am
@@ -0,0 +1,12 @@
+plugin_LTLIBRARIES = libgstvideocrop.la
+
+# Note: we only use defines from gst/video/video.h, but none
+# of the functions, so we don't need to link to libgstvideo
+
+libgstvideocrop_la_SOURCES = gstvideocrop.c gstaspectratiocrop.c
+libgstvideocrop_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
+	$(GST_PLUGINS_BASE_CFLAGS)
+libgstvideocrop_la_LIBADD = $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION)
+libgstvideocrop_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstvideocrop.h gstaspectratiocrop.h
diff --git a/gst/videocrop/gstaspectratiocrop.c b/gst/videocrop/gstaspectratiocrop.c
new file mode 100644
index 0000000..2c1d9d7
--- /dev/null
+++ b/gst/videocrop/gstaspectratiocrop.c
@@ -0,0 +1,491 @@
+/* GStreamer video frame cropping to aspect-ratio
+ * Copyright (C) 2009 Thijs Vermeir <thijsvermeir@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-aspectratiocrop
+ * @see_also: #GstVideoCrop
+ *
+ * This element crops video frames to a specified #GstAspectRatioCrop:aspect-ratio.
+ *
+ * If the aspect-ratio is already correct, the element will operate
+ * in pass-through mode.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! video/x-raw,height=640,width=480 ! aspectratiocrop aspect-ratio=16/9 ! ximagesink
+ * ]| This pipeline generates a videostream in 4/3 and crops it to 16/9.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include "gstaspectratiocrop.h"
+
+#include "gst/glib-compat-private.h"
+
+GST_DEBUG_CATEGORY_STATIC (aspect_ratio_crop_debug);
+#define GST_CAT_DEFAULT aspect_ratio_crop_debug
+
+enum
+{
+  PROP_0,
+  PROP_ASPECT_RATIO_CROP,
+};
+
+/* we support the same caps as videocrop (sync changes) */
+#define ASPECT_RATIO_CROP_CAPS                        \
+  GST_VIDEO_CAPS_MAKE ("{ RGBx, xRGB, BGRx, xBGR, "    \
+      "RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, " \
+      "YVYU, UYVY, I420, YV12, RGB16, RGB15, GRAY8, "  \
+      "NV12, NV21, GRAY16_LE, GRAY16_BE }")
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (ASPECT_RATIO_CROP_CAPS)
+    );
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (ASPECT_RATIO_CROP_CAPS)
+    );
+
+#define gst_aspect_ratio_crop_parent_class parent_class
+G_DEFINE_TYPE (GstAspectRatioCrop, gst_aspect_ratio_crop, GST_TYPE_BIN);
+
+static void gst_aspect_ratio_crop_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_aspect_ratio_crop_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_aspect_ratio_crop_set_cropping (GstAspectRatioCrop *
+    aspect_ratio_crop, gint top, gint right, gint bottom, gint left);
+static GstCaps *gst_aspect_ratio_crop_get_caps (GstPad * pad, GstCaps * filter);
+static gboolean gst_aspect_ratio_crop_src_query (GstPad * pad,
+    GstObject * parent, GstQuery * query);
+static gboolean gst_aspect_ratio_crop_set_caps (GstAspectRatioCrop *
+    aspect_ratio_crop, GstCaps * caps);
+static gboolean gst_aspect_ratio_crop_sink_event (GstPad * pad,
+    GstObject * parent, GstEvent * evt);
+static void gst_aspect_ratio_crop_finalize (GObject * object);
+static void gst_aspect_ratio_transform_structure (GstAspectRatioCrop *
+    aspect_ratio_crop, GstStructure * structure, GstStructure ** new_structure,
+    gboolean set_videocrop);
+
+static void
+gst_aspect_ratio_crop_set_cropping (GstAspectRatioCrop * aspect_ratio_crop,
+    gint top, gint right, gint bottom, gint left)
+{
+  GValue value = { 0 };
+  if (G_UNLIKELY (!aspect_ratio_crop->videocrop)) {
+    GST_WARNING_OBJECT (aspect_ratio_crop,
+        "Can't set the settings if there is no cropping element");
+    return;
+  }
+
+  g_value_init (&value, G_TYPE_INT);
+  g_value_set_int (&value, top);
+  GST_DEBUG_OBJECT (aspect_ratio_crop, "set top cropping to: %d", top);
+  g_object_set_property (G_OBJECT (aspect_ratio_crop->videocrop), "top",
+      &value);
+  g_value_set_int (&value, right);
+  GST_DEBUG_OBJECT (aspect_ratio_crop, "set right cropping to: %d", right);
+  g_object_set_property (G_OBJECT (aspect_ratio_crop->videocrop), "right",
+      &value);
+  g_value_set_int (&value, bottom);
+  GST_DEBUG_OBJECT (aspect_ratio_crop, "set bottom cropping to: %d", bottom);
+  g_object_set_property (G_OBJECT (aspect_ratio_crop->videocrop), "bottom",
+      &value);
+  g_value_set_int (&value, left);
+  GST_DEBUG_OBJECT (aspect_ratio_crop, "set left cropping to: %d", left);
+  g_object_set_property (G_OBJECT (aspect_ratio_crop->videocrop), "left",
+      &value);
+
+  g_value_unset (&value);
+}
+
+static gboolean
+gst_aspect_ratio_crop_set_caps (GstAspectRatioCrop * aspect_ratio_crop,
+    GstCaps * caps)
+{
+  GstPad *peer_pad;
+  GstStructure *structure;
+  gboolean ret;
+
+  g_mutex_lock (&aspect_ratio_crop->crop_lock);
+
+  structure = gst_caps_get_structure (caps, 0);
+  gst_aspect_ratio_transform_structure (aspect_ratio_crop, structure, NULL,
+      TRUE);
+  peer_pad =
+      gst_element_get_static_pad (GST_ELEMENT (aspect_ratio_crop->videocrop),
+      "sink");
+  ret = gst_pad_set_caps (peer_pad, caps);
+  gst_object_unref (peer_pad);
+  g_mutex_unlock (&aspect_ratio_crop->crop_lock);
+  return ret;
+}
+
+static gboolean
+gst_aspect_ratio_crop_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * evt)
+{
+  GstAspectRatioCrop *aspect_ratio_crop = GST_ASPECT_RATIO_CROP (parent);
+
+  switch (GST_EVENT_TYPE (evt)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (evt, &caps);
+      gst_aspect_ratio_crop_set_caps (aspect_ratio_crop, caps);
+      break;
+    }
+    default:
+      break;
+  }
+
+  return gst_pad_event_default (pad, parent, evt);
+}
+
+static void
+gst_aspect_ratio_crop_class_init (GstAspectRatioCropClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_aspect_ratio_crop_set_property;
+  gobject_class->get_property = gst_aspect_ratio_crop_get_property;
+  gobject_class->finalize = gst_aspect_ratio_crop_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_ASPECT_RATIO_CROP,
+      gst_param_spec_fraction ("aspect-ratio", "aspect-ratio",
+          "Target aspect-ratio of video", 0, 1, G_MAXINT, 1, 0, 1,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (element_class, "aspectratiocrop",
+      "Filter/Effect/Video",
+      "Crops video into a user-defined aspect-ratio",
+      "Thijs Vermeir <thijsvermeir@gmail.com>");
+
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+}
+
+static void
+gst_aspect_ratio_crop_finalize (GObject * object)
+{
+  GstAspectRatioCrop *aspect_ratio_crop;
+
+  aspect_ratio_crop = GST_ASPECT_RATIO_CROP (object);
+
+  g_mutex_clear (&aspect_ratio_crop->crop_lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_aspect_ratio_crop_init (GstAspectRatioCrop * aspect_ratio_crop)
+{
+  GstPad *link_pad;
+  GstPad *src_pad;
+
+  GST_DEBUG_CATEGORY_INIT (aspect_ratio_crop_debug, "aspectratiocrop", 0,
+      "aspectratiocrop");
+
+  aspect_ratio_crop->ar_num = 0;
+  aspect_ratio_crop->ar_denom = 1;
+
+  g_mutex_init (&aspect_ratio_crop->crop_lock);
+
+  /* add the transform element */
+  aspect_ratio_crop->videocrop = gst_element_factory_make ("videocrop", NULL);
+  gst_bin_add (GST_BIN (aspect_ratio_crop), aspect_ratio_crop->videocrop);
+
+  /* create ghost pad src */
+  link_pad =
+      gst_element_get_static_pad (GST_ELEMENT (aspect_ratio_crop->videocrop),
+      "src");
+  src_pad = gst_ghost_pad_new ("src", link_pad);
+  gst_pad_set_query_function (src_pad,
+      GST_DEBUG_FUNCPTR (gst_aspect_ratio_crop_src_query));
+  gst_element_add_pad (GST_ELEMENT (aspect_ratio_crop), src_pad);
+  gst_object_unref (link_pad);
+  /* create ghost pad sink */
+  link_pad =
+      gst_element_get_static_pad (GST_ELEMENT (aspect_ratio_crop->videocrop),
+      "sink");
+  aspect_ratio_crop->sink = gst_ghost_pad_new ("sink", link_pad);
+  gst_element_add_pad (GST_ELEMENT (aspect_ratio_crop),
+      aspect_ratio_crop->sink);
+  gst_object_unref (link_pad);
+
+  gst_pad_set_event_function (aspect_ratio_crop->sink,
+      GST_DEBUG_FUNCPTR (gst_aspect_ratio_crop_sink_event));
+}
+
+static void
+gst_aspect_ratio_transform_structure (GstAspectRatioCrop * aspect_ratio_crop,
+    GstStructure * structure, GstStructure ** new_structure,
+    gboolean set_videocrop)
+{
+  gdouble incoming_ar;
+  gdouble requested_ar;
+  gint width, height;
+  gint cropvalue;
+  gint par_d, par_n;
+
+  /* Check if we need to change the aspect ratio */
+  if (aspect_ratio_crop->ar_num < 1) {
+    GST_DEBUG_OBJECT (aspect_ratio_crop, "No cropping requested");
+    goto beach;
+  }
+
+  /* get the information from the caps */
+  if (!gst_structure_get_int (structure, "width", &width) ||
+      !gst_structure_get_int (structure, "height", &height))
+    goto beach;
+
+  if (!gst_structure_get_fraction (structure, "pixel-aspect-ratio",
+          &par_n, &par_d)) {
+    par_d = par_n = 1;
+  }
+
+  incoming_ar = ((gdouble) (width * par_n)) / (height * par_d);
+  GST_LOG_OBJECT (aspect_ratio_crop,
+      "incoming caps width(%d), height(%d), par (%d/%d) : ar = %f", width,
+      height, par_n, par_d, incoming_ar);
+
+  requested_ar =
+      (gdouble) aspect_ratio_crop->ar_num / aspect_ratio_crop->ar_denom;
+
+  /* check if the original aspect-ratio is the aspect-ratio that we want */
+  if (requested_ar == incoming_ar) {
+    GST_DEBUG_OBJECT (aspect_ratio_crop,
+        "Input video already has the correct aspect ratio (%.3f == %.3f)",
+        incoming_ar, requested_ar);
+    goto beach;
+  } else if (requested_ar > incoming_ar) {
+    /* fix aspect ratio with cropping on top and bottom */
+    cropvalue =
+        ((((double) aspect_ratio_crop->ar_denom /
+                (double) (aspect_ratio_crop->ar_num)) * ((double) par_n /
+                (double) par_d) * width) - height) / 2;
+    if (cropvalue < 0) {
+      cropvalue *= -1;
+    }
+    if (cropvalue >= (height / 2))
+      goto crop_failed;
+    if (set_videocrop) {
+      gst_aspect_ratio_crop_set_cropping (aspect_ratio_crop, cropvalue, 0,
+          cropvalue, 0);
+    }
+    if (new_structure) {
+      *new_structure = gst_structure_copy (structure);
+      gst_structure_set (*new_structure,
+          "height", G_TYPE_INT, (int) (height - (cropvalue * 2)), NULL);
+    }
+  } else {
+    /* fix aspect ratio with cropping on left and right */
+    cropvalue =
+        ((((double) aspect_ratio_crop->ar_num /
+                (double) (aspect_ratio_crop->ar_denom)) * ((double) par_d /
+                (double) par_n) * height) - width) / 2;
+    if (cropvalue < 0) {
+      cropvalue *= -1;
+    }
+    if (cropvalue >= (width / 2))
+      goto crop_failed;
+    if (set_videocrop) {
+      gst_aspect_ratio_crop_set_cropping (aspect_ratio_crop, 0, cropvalue,
+          0, cropvalue);
+    }
+    if (new_structure) {
+      *new_structure = gst_structure_copy (structure);
+      gst_structure_set (*new_structure,
+          "width", G_TYPE_INT, (int) (width - (cropvalue * 2)), NULL);
+    }
+  }
+
+  return;
+
+crop_failed:
+  GST_WARNING_OBJECT (aspect_ratio_crop,
+      "can't crop to aspect ratio requested");
+  goto beach;
+beach:
+  if (set_videocrop) {
+    gst_aspect_ratio_crop_set_cropping (aspect_ratio_crop, 0, 0, 0, 0);
+  }
+
+  if (new_structure) {
+    *new_structure = gst_structure_copy (structure);
+  }
+}
+
+static GstCaps *
+gst_aspect_ratio_crop_transform_caps (GstAspectRatioCrop * aspect_ratio_crop,
+    GstCaps * caps)
+{
+  GstCaps *transform;
+  gint size, i;
+
+  transform = gst_caps_new_empty ();
+
+  size = gst_caps_get_size (caps);
+
+  for (i = 0; i < size; i++) {
+    GstStructure *s;
+    GstStructure *trans_s;
+
+    s = gst_caps_get_structure (caps, i);
+
+    gst_aspect_ratio_transform_structure (aspect_ratio_crop, s, &trans_s,
+        FALSE);
+    gst_caps_append_structure (transform, trans_s);
+  }
+
+  return transform;
+}
+
+static GstCaps *
+gst_aspect_ratio_crop_get_caps (GstPad * pad, GstCaps * filter)
+{
+  GstPad *peer;
+  GstAspectRatioCrop *aspect_ratio_crop;
+  GstCaps *return_caps;
+
+  aspect_ratio_crop = GST_ASPECT_RATIO_CROP (gst_pad_get_parent (pad));
+
+  g_mutex_lock (&aspect_ratio_crop->crop_lock);
+
+  peer = gst_pad_get_peer (aspect_ratio_crop->sink);
+  if (peer == NULL) {
+    return_caps = gst_static_pad_template_get_caps (&src_template);
+  } else {
+    GstCaps *peer_caps;
+
+    peer_caps = gst_pad_query_caps (peer, filter);
+    return_caps =
+        gst_aspect_ratio_crop_transform_caps (aspect_ratio_crop, peer_caps);
+    gst_caps_unref (peer_caps);
+    gst_object_unref (peer);
+  }
+
+  g_mutex_unlock (&aspect_ratio_crop->crop_lock);
+  gst_object_unref (aspect_ratio_crop);
+
+  if (return_caps && filter) {
+    GstCaps *tmp =
+        gst_caps_intersect_full (filter, return_caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_replace (&return_caps, tmp);
+    gst_caps_unref (tmp);
+  }
+
+  return return_caps;
+}
+
+static gboolean
+gst_aspect_ratio_crop_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query)
+{
+  gboolean res = FALSE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *filter, *caps;
+
+      gst_query_parse_caps (query, &filter);
+      caps = gst_aspect_ratio_crop_get_caps (pad, filter);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+      res = TRUE;
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+  return res;
+}
+
+static void
+gst_aspect_ratio_crop_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstAspectRatioCrop *aspect_ratio_crop;
+  gboolean recheck = FALSE;
+
+  aspect_ratio_crop = GST_ASPECT_RATIO_CROP (object);
+
+  GST_OBJECT_LOCK (aspect_ratio_crop);
+  switch (prop_id) {
+    case PROP_ASPECT_RATIO_CROP:
+      if (GST_VALUE_HOLDS_FRACTION (value)) {
+        aspect_ratio_crop->ar_num = gst_value_get_fraction_numerator (value);
+        aspect_ratio_crop->ar_denom =
+            gst_value_get_fraction_denominator (value);
+        recheck = gst_pad_has_current_caps (aspect_ratio_crop->sink);
+      }
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (aspect_ratio_crop);
+
+  if (recheck) {
+    GstCaps *caps = gst_pad_get_current_caps (aspect_ratio_crop->sink);
+    if (caps != NULL) {
+      gst_aspect_ratio_crop_set_caps (aspect_ratio_crop, caps);
+      gst_caps_unref (caps);
+    }
+  }
+}
+
+static void
+gst_aspect_ratio_crop_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstAspectRatioCrop *aspect_ratio_crop;
+
+  aspect_ratio_crop = GST_ASPECT_RATIO_CROP (object);
+
+  GST_OBJECT_LOCK (aspect_ratio_crop);
+  switch (prop_id) {
+    case PROP_ASPECT_RATIO_CROP:
+      gst_value_set_fraction (value, aspect_ratio_crop->ar_num,
+          aspect_ratio_crop->ar_denom);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (aspect_ratio_crop);
+}
diff --git a/gst/videocrop/gstaspectratiocrop.h b/gst/videocrop/gstaspectratiocrop.h
new file mode 100644
index 0000000..2caeb5c
--- /dev/null
+++ b/gst/videocrop/gstaspectratiocrop.h
@@ -0,0 +1,67 @@
+/* GStreamer video frame cropping to aspect-ratio
+ * Copyright (C) 2009 Thijs Vermeir <thijsvermeir@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_ASPECT_RATIO_CROP_H__
+#define __GST_ASPECT_RATIO_CROP_H__
+
+#include <gst/gstbin.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_ASPECT_RATIO_CROP \
+  (gst_aspect_ratio_crop_get_type())
+#define GST_ASPECT_RATIO_CROP(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ASPECT_RATIO_CROP,GstAspectRatioCrop))
+#define GST_ASPECT_RATIO_CROP_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ASPECT_RATIO_CROP,GstAspectRatioCropClass))
+#define GST_IS_ASPECT_RATIO_CROP(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ASPECT_RATIO_CROP))
+#define GST_IS_ASPECT_RATIO_CROP_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ASPECT_RATIO_CROP))
+
+typedef struct _GstAspectRatioCrop GstAspectRatioCrop;
+typedef struct _GstAspectRatioCropClass GstAspectRatioCropClass;
+
+struct _GstAspectRatioCrop
+{
+  GstBin parent;
+
+  /* our videocrop element */
+  GstElement *videocrop;
+
+  GstPad *sink;
+
+  /* target aspect ratio */
+  gint ar_num; /* if < 1 then don't change ar */
+  gint ar_denom;
+
+  GMutex crop_lock;
+};
+
+struct _GstAspectRatioCropClass
+{
+  GstBinClass parent_class;
+};
+
+GType gst_aspect_ratio_crop_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_ASPECT_RATIO_CROP_H__ */
+
diff --git a/gst/videocrop/gstvideocrop.c b/gst/videocrop/gstvideocrop.c
new file mode 100644
index 0000000..31e7d67
--- /dev/null
+++ b/gst/videocrop/gstvideocrop.c
@@ -0,0 +1,919 @@
+/* GStreamer video frame cropping
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-videocrop
+ * @see_also: #GstVideoBox
+ *
+ * This element crops video frames, meaning it can remove parts of the
+ * picture on the left, right, top or bottom of the picture and output
+ * a smaller picture than the input picture, with the unwanted parts at the
+ * border removed.
+ *
+ * The videocrop element is similar to the videobox element, but its main
+ * goal is to support a multitude of formats as efficiently as possible.
+ * Unlike videbox, it cannot add borders to the picture and unlike videbox
+ * it will always output images in exactly the same format as the input image.
+ *
+ * If there is nothing to crop, the element will operate in pass-through mode.
+ *
+ * Note that no special efforts are made to handle chroma-subsampled formats
+ * in the case of odd-valued cropping and compensate for sub-unit chroma plane
+ * shifts for such formats in the case where the #GstVideoCrop:left or
+ * #GstVideoCrop:top property is set to an odd number. This doesn't matter for 
+ * most use cases, but it might matter for yours.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! videocrop top=42 left=1 right=4 bottom=0 ! ximagesink
+ * ]|
+ * </refsect2>
+ */
+
+/* TODO:
+ *  - for packed formats, we could avoid memcpy() in case crop_left
+ *    and crop_right are 0 and just create a sub-buffer of the input
+ *    buffer
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include "gstvideocrop.h"
+#include "gstaspectratiocrop.h"
+
+#include <string.h>
+
+GST_DEBUG_CATEGORY_STATIC (videocrop_debug);
+#define GST_CAT_DEFAULT videocrop_debug
+
+enum
+{
+  PROP_0,
+  PROP_LEFT,
+  PROP_RIGHT,
+  PROP_TOP,
+  PROP_BOTTOM
+};
+
+/* we support the same caps as aspectratiocrop (sync changes) */
+#define VIDEO_CROP_CAPS                                \
+  GST_VIDEO_CAPS_MAKE ("{ RGBx, xRGB, BGRx, xBGR, "    \
+      "RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, " \
+      "YVYU, UYVY, I420, YV12, RGB16, RGB15, GRAY8, "  \
+      "NV12, NV21, GRAY16_LE, GRAY16_BE }")
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (VIDEO_CROP_CAPS)
+    );
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (VIDEO_CROP_CAPS)
+    );
+
+#define gst_video_crop_parent_class parent_class
+G_DEFINE_TYPE (GstVideoCrop, gst_video_crop, GST_TYPE_VIDEO_FILTER);
+
+static void gst_video_crop_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_video_crop_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_video_crop_transform_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * filter_caps);
+static gboolean gst_video_crop_src_event (GstBaseTransform * trans,
+    GstEvent * event);
+
+static gboolean gst_video_crop_set_info (GstVideoFilter * vfilter, GstCaps * in,
+    GstVideoInfo * in_info, GstCaps * out, GstVideoInfo * out_info);
+static GstFlowReturn gst_video_crop_transform_frame (GstVideoFilter * vfilter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame);
+
+static gboolean gst_video_crop_decide_allocation (GstBaseTransform * trans,
+    GstQuery * query);
+static gboolean gst_video_crop_propose_allocation (GstBaseTransform * trans,
+    GstQuery * decide_query, GstQuery * query);
+static GstFlowReturn gst_video_crop_transform_ip (GstBaseTransform * trans,
+    GstBuffer * buf);
+
+static gboolean
+gst_video_crop_src_event (GstBaseTransform * trans, GstEvent * event)
+{
+  GstEvent *new_event;
+  GstStructure *new_structure;
+  const GstStructure *structure;
+  const gchar *event_name;
+  double pointer_x;
+  double pointer_y;
+
+  GstVideoCrop *vcrop = GST_VIDEO_CROP (trans);
+  new_event = NULL;
+
+  GST_OBJECT_LOCK (vcrop);
+  if (GST_EVENT_TYPE (event) == GST_EVENT_NAVIGATION &&
+      (vcrop->crop_left != 0 || vcrop->crop_top != 0)) {
+    structure = gst_event_get_structure (event);
+    event_name = gst_structure_get_string (structure, "event");
+
+    if (event_name &&
+        (strcmp (event_name, "mouse-move") == 0 ||
+            strcmp (event_name, "mouse-button-press") == 0 ||
+            strcmp (event_name, "mouse-button-release") == 0)) {
+
+      if (gst_structure_get_double (structure, "pointer_x", &pointer_x) &&
+          gst_structure_get_double (structure, "pointer_y", &pointer_y)) {
+
+        new_structure = gst_structure_copy (structure);
+        gst_structure_set (new_structure,
+            "pointer_x", G_TYPE_DOUBLE, (double) (pointer_x + vcrop->crop_left),
+            "pointer_y", G_TYPE_DOUBLE, (double) (pointer_y + vcrop->crop_top),
+            NULL);
+
+        new_event = gst_event_new_navigation (new_structure);
+        gst_event_unref (event);
+      } else {
+        GST_WARNING_OBJECT (vcrop, "Failed to read navigation event");
+      }
+    }
+  }
+
+  GST_OBJECT_UNLOCK (vcrop);
+
+  return GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans,
+      (new_event ? new_event : event));
+}
+
+static void
+gst_video_crop_class_init (GstVideoCropClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+  GstBaseTransformClass *basetransform_class;
+  GstVideoFilterClass *vfilter_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = (GstElementClass *) klass;
+  basetransform_class = (GstBaseTransformClass *) klass;
+  vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->set_property = gst_video_crop_set_property;
+  gobject_class->get_property = gst_video_crop_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_LEFT,
+      g_param_spec_int ("left", "Left",
+          "Pixels to crop at left (-1 to auto-crop)", -1, G_MAXINT, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+          GST_PARAM_MUTABLE_PLAYING));
+  g_object_class_install_property (gobject_class, PROP_RIGHT,
+      g_param_spec_int ("right", "Right",
+          "Pixels to crop at right (-1 to auto-crop)", -1, G_MAXINT, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+          GST_PARAM_MUTABLE_PLAYING));
+  g_object_class_install_property (gobject_class, PROP_TOP,
+      g_param_spec_int ("top", "Top", "Pixels to crop at top (-1 to auto-crop)",
+          -1, G_MAXINT, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+          GST_PARAM_MUTABLE_PLAYING));
+  g_object_class_install_property (gobject_class, PROP_BOTTOM,
+      g_param_spec_int ("bottom", "Bottom",
+          "Pixels to crop at bottom (-1 to auto-crop)", -1, G_MAXINT, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+          GST_PARAM_MUTABLE_PLAYING));
+
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+  gst_element_class_set_static_metadata (element_class, "Crop",
+      "Filter/Effect/Video",
+      "Crops video into a user-defined region",
+      "Tim-Philipp Müller <tim centricular net>");
+
+  basetransform_class->transform_ip_on_passthrough = FALSE;
+  basetransform_class->transform_caps =
+      GST_DEBUG_FUNCPTR (gst_video_crop_transform_caps);
+  basetransform_class->src_event = GST_DEBUG_FUNCPTR (gst_video_crop_src_event);
+  basetransform_class->decide_allocation =
+      GST_DEBUG_FUNCPTR (gst_video_crop_decide_allocation);
+  basetransform_class->propose_allocation =
+      GST_DEBUG_FUNCPTR (gst_video_crop_propose_allocation);
+  basetransform_class->transform_ip =
+      GST_DEBUG_FUNCPTR (gst_video_crop_transform_ip);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_video_crop_set_info);
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_video_crop_transform_frame);
+}
+
+static void
+gst_video_crop_init (GstVideoCrop * vcrop)
+{
+  vcrop->crop_right = 0;
+  vcrop->crop_left = 0;
+  vcrop->crop_top = 0;
+  vcrop->crop_bottom = 0;
+}
+
+#define ROUND_DOWN_2(n)  ((n)&(~1))
+
+static void
+gst_video_crop_transform_packed_complex (GstVideoCrop * vcrop,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame, gint x, gint y)
+{
+  guint8 *in_data, *out_data;
+  guint i, dx;
+  gint width, height;
+  gint in_stride;
+  gint out_stride;
+
+  width = GST_VIDEO_FRAME_WIDTH (out_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (out_frame);
+
+  in_data = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  out_data = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  in_stride = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0);
+  out_stride = GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0);
+
+  in_data += vcrop->crop_top * in_stride;
+
+  /* rounding down here so we end up at the start of a macro-pixel and not
+   * in the middle of one */
+  in_data += ROUND_DOWN_2 (vcrop->crop_left) *
+      GST_VIDEO_FRAME_COMP_PSTRIDE (in_frame, 0);
+
+  dx = width * GST_VIDEO_FRAME_COMP_PSTRIDE (out_frame, 0);
+
+  /* UYVY = 4:2:2 - [U0 Y0 V0 Y1] [U2 Y2 V2 Y3] [U4 Y4 V4 Y5]
+   * YUYV = 4:2:2 - [Y0 U0 Y1 V0] [Y2 U2 Y3 V2] [Y4 U4 Y5 V4] = YUY2 */
+  if ((vcrop->crop_left % 2) != 0) {
+    for (i = 0; i < height; ++i) {
+      gint j;
+
+      memcpy (out_data, in_data, dx);
+
+      /* move just the Y samples one pixel to the left, don't worry about
+       * chroma shift */
+      for (j = vcrop->macro_y_off; j < out_stride - 2; j += 2)
+        out_data[j] = in_data[j + 2];
+
+      in_data += in_stride;
+      out_data += out_stride;
+    }
+  } else {
+    for (i = 0; i < height; ++i) {
+      memcpy (out_data, in_data, dx);
+      in_data += in_stride;
+      out_data += out_stride;
+    }
+  }
+}
+
+static void
+gst_video_crop_transform_packed_simple (GstVideoCrop * vcrop,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame, gint x, gint y)
+{
+  guint8 *in_data, *out_data;
+  gint width, height;
+  guint i, dx;
+  gint in_stride, out_stride;
+
+  width = GST_VIDEO_FRAME_WIDTH (out_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (out_frame);
+
+  in_data = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  out_data = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  in_stride = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0);
+  out_stride = GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0);
+
+  in_data += (vcrop->crop_top + y) * in_stride;
+  in_data +=
+      (vcrop->crop_left + x) * GST_VIDEO_FRAME_COMP_PSTRIDE (in_frame, 0);
+
+  dx = width * GST_VIDEO_FRAME_COMP_PSTRIDE (out_frame, 0);
+
+  for (i = 0; i < height; ++i) {
+    memcpy (out_data, in_data, dx);
+    in_data += in_stride;
+    out_data += out_stride;
+  }
+}
+
+static void
+gst_video_crop_transform_planar (GstVideoCrop * vcrop,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame, gint x, gint y)
+{
+  gint width, height;
+  gint crop_top, crop_left;
+  guint8 *y_out, *u_out, *v_out;
+  guint8 *y_in, *u_in, *v_in;
+  guint i, dx;
+
+  width = GST_VIDEO_FRAME_WIDTH (out_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (out_frame);
+  crop_left = vcrop->crop_left + x;
+  crop_top = vcrop->crop_top + y;
+
+  /* Y plane */
+  y_in = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  y_out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  y_in += (crop_top * GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0)) + crop_left;
+  dx = width;
+
+  for (i = 0; i < height; ++i) {
+    memcpy (y_out, y_in, dx);
+    y_in += GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0);
+    y_out += GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0);
+  }
+
+  /* U + V planes */
+  u_in = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 1);
+  u_out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 1);
+
+  u_in += (crop_top / 2) * GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 1);
+  u_in += crop_left / 2;
+
+  v_in = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 2);
+  v_out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 2);
+
+  v_in += (crop_top / 2) * GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 2);
+  v_in += crop_left / 2;
+
+  dx = GST_ROUND_UP_2 (width) / 2;
+
+  for (i = 0; i < GST_ROUND_UP_2 (height) / 2; ++i) {
+    memcpy (u_out, u_in, dx);
+    memcpy (v_out, v_in, dx);
+    u_in += GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 1);
+    u_out += GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 1);
+    v_in += GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 2);
+    v_out += GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 2);
+  }
+}
+
+static void
+gst_video_crop_transform_semi_planar (GstVideoCrop * vcrop,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame, gint x, gint y)
+{
+  gint width, height;
+  gint crop_top, crop_left;
+  guint8 *y_out, *uv_out;
+  guint8 *y_in, *uv_in;
+  guint i, dx;
+
+  width = GST_VIDEO_FRAME_WIDTH (out_frame);
+  height = GST_VIDEO_FRAME_HEIGHT (out_frame);
+  crop_left = vcrop->crop_left + x;
+  crop_top = vcrop->crop_top + y;
+
+  /* Y plane */
+  y_in = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
+  y_out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
+
+  /* UV plane */
+  uv_in = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 1);
+  uv_out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 1);
+
+  y_in += crop_top * GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0) + crop_left;
+  dx = width;
+
+  for (i = 0; i < height; ++i) {
+    memcpy (y_out, y_in, dx);
+    y_in += GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0);
+    y_out += GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0);
+  }
+
+  uv_in += (crop_top / 2) * GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 1);
+  uv_in += GST_ROUND_DOWN_2 (crop_left);
+  dx = GST_ROUND_UP_2 (width);
+
+  for (i = 0; i < GST_ROUND_UP_2 (height) / 2; i++) {
+    memcpy (uv_out, uv_in, dx);
+    uv_in += GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 1);
+    uv_out += GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 1);
+  }
+}
+
+static GstFlowReturn
+gst_video_crop_transform_frame (GstVideoFilter * vfilter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame)
+{
+  GstVideoCrop *vcrop = GST_VIDEO_CROP (vfilter);
+  GstVideoCropMeta *meta = gst_buffer_get_video_crop_meta (in_frame->buffer);
+  gint x = 0, y = 0;
+
+  if (G_UNLIKELY (vcrop->need_update)) {
+    if (!gst_video_crop_set_info (vfilter, NULL, &vcrop->in_info, NULL,
+            &vcrop->out_info)) {
+      return GST_FLOW_ERROR;
+    }
+  }
+
+  if (meta) {
+    x = meta->x;
+    y = meta->y;
+  }
+
+  switch (vcrop->packing) {
+    case VIDEO_CROP_PIXEL_FORMAT_PACKED_SIMPLE:
+      gst_video_crop_transform_packed_simple (vcrop, in_frame, out_frame, x, y);
+      break;
+    case VIDEO_CROP_PIXEL_FORMAT_PACKED_COMPLEX:
+      gst_video_crop_transform_packed_complex (vcrop, in_frame, out_frame, x,
+          y);
+      break;
+    case VIDEO_CROP_PIXEL_FORMAT_PLANAR:
+      gst_video_crop_transform_planar (vcrop, in_frame, out_frame, x, y);
+      break;
+    case VIDEO_CROP_PIXEL_FORMAT_SEMI_PLANAR:
+      gst_video_crop_transform_semi_planar (vcrop, in_frame, out_frame, x, y);
+      break;
+    default:
+      g_assert_not_reached ();
+  }
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_video_crop_decide_allocation (GstBaseTransform * trans, GstQuery * query)
+{
+  GstVideoCrop *crop = GST_VIDEO_CROP (trans);
+  gboolean use_crop_meta;
+
+  use_crop_meta = (gst_query_find_allocation_meta (query,
+          GST_VIDEO_CROP_META_API_TYPE, NULL) &&
+      gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL));
+
+  if ((crop->crop_left | crop->crop_right | crop->crop_top | crop->
+          crop_bottom) == 0) {
+    GST_INFO_OBJECT (crop, "we are using passthrough");
+    gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (crop), TRUE);
+    gst_base_transform_set_in_place (GST_BASE_TRANSFORM (crop), FALSE);
+  } else if (use_crop_meta) {
+    GST_INFO_OBJECT (crop, "we are doing in-place transform using crop meta");
+    gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (crop), FALSE);
+    gst_base_transform_set_in_place (GST_BASE_TRANSFORM (crop), TRUE);
+  } else {
+    GST_INFO_OBJECT (crop, "we are not using passthrough");
+    gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (crop), FALSE);
+    gst_base_transform_set_in_place (GST_BASE_TRANSFORM (crop), FALSE);
+  }
+
+  return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans,
+      query);
+}
+
+static gboolean
+gst_video_crop_propose_allocation (GstBaseTransform * trans,
+    GstQuery * decide_query, GstQuery * query)
+{
+  /* if we are not passthrough, we can handle video meta and crop meta */
+  if (decide_query) {
+    GST_DEBUG_OBJECT (trans, "Advertising video meta and crop meta support");
+    gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
+    gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL);
+  }
+
+  return GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans,
+      decide_query, query);
+}
+
+static GstFlowReturn
+gst_video_crop_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
+{
+  GstVideoCrop *vcrop = GST_VIDEO_CROP (trans);
+  GstVideoMeta *video_meta;
+  GstVideoCropMeta *crop_meta;
+
+  GST_LOG_OBJECT (trans, "Transforming in-place");
+
+  /* The video meta is required since we are going to make the caps
+   * width/height smaller, which would not result in a usable GstVideoInfo for
+   * mapping the buffer. */
+  video_meta = gst_buffer_get_video_meta (buf);
+  if (!video_meta) {
+    video_meta = gst_buffer_add_video_meta (buf, GST_VIDEO_FRAME_FLAG_NONE,
+        GST_VIDEO_INFO_FORMAT (&vcrop->in_info), vcrop->in_info.width,
+        vcrop->in_info.height);
+  }
+
+  crop_meta = gst_buffer_get_video_crop_meta (buf);
+  if (!crop_meta) {
+    crop_meta = gst_buffer_add_video_crop_meta (buf);
+    crop_meta->width = vcrop->in_info.width;
+    crop_meta->height = vcrop->in_info.height;
+  }
+
+  crop_meta->x += vcrop->crop_left;
+  crop_meta->y += vcrop->crop_top;
+  crop_meta->width = GST_VIDEO_INFO_WIDTH (&vcrop->out_info);
+  crop_meta->height = GST_VIDEO_INFO_HEIGHT (&vcrop->out_info);
+
+  return GST_FLOW_OK;
+}
+
+static gint
+gst_video_crop_transform_dimension (gint val, gint delta)
+{
+  gint64 new_val = (gint64) val + (gint64) delta;
+
+  new_val = CLAMP (new_val, 1, G_MAXINT);
+
+  return (gint) new_val;
+}
+
+static gboolean
+gst_video_crop_transform_dimension_value (const GValue * src_val,
+    gint delta, GValue * dest_val, GstPadDirection direction, gboolean dynamic)
+{
+  gboolean ret = TRUE;
+
+  if (G_VALUE_HOLDS_INT (src_val)) {
+    gint ival = g_value_get_int (src_val);
+    ival = gst_video_crop_transform_dimension (ival, delta);
+
+    if (dynamic) {
+      if (direction == GST_PAD_SRC) {
+        if (ival == G_MAXINT) {
+          g_value_init (dest_val, G_TYPE_INT);
+          g_value_set_int (dest_val, ival);
+        } else {
+          g_value_init (dest_val, GST_TYPE_INT_RANGE);
+          gst_value_set_int_range (dest_val, ival, G_MAXINT);
+        }
+      } else {
+        if (ival == 1) {
+          g_value_init (dest_val, G_TYPE_INT);
+          g_value_set_int (dest_val, ival);
+        } else {
+          g_value_init (dest_val, GST_TYPE_INT_RANGE);
+          gst_value_set_int_range (dest_val, 1, ival);
+        }
+      }
+    } else {
+      g_value_init (dest_val, G_TYPE_INT);
+      g_value_set_int (dest_val, ival);
+    }
+  } else if (GST_VALUE_HOLDS_INT_RANGE (src_val)) {
+    gint min = gst_value_get_int_range_min (src_val);
+    gint max = gst_value_get_int_range_max (src_val);
+
+    min = gst_video_crop_transform_dimension (min, delta);
+    max = gst_video_crop_transform_dimension (max, delta);
+
+    if (dynamic) {
+      if (direction == GST_PAD_SRC)
+        max = G_MAXINT;
+      else
+        min = 1;
+    }
+
+    if (min == max) {
+      g_value_init (dest_val, G_TYPE_INT);
+      g_value_set_int (dest_val, min);
+    } else {
+      g_value_init (dest_val, GST_TYPE_INT_RANGE);
+      gst_value_set_int_range (dest_val, min, max);
+    }
+  } else if (GST_VALUE_HOLDS_LIST (src_val)) {
+    gint i;
+
+    g_value_init (dest_val, GST_TYPE_LIST);
+
+    for (i = 0; i < gst_value_list_get_size (src_val); ++i) {
+      const GValue *list_val;
+      GValue newval = { 0, };
+
+      list_val = gst_value_list_get_value (src_val, i);
+      if (gst_video_crop_transform_dimension_value (list_val, delta, &newval,
+              direction, dynamic))
+        gst_value_list_append_value (dest_val, &newval);
+      g_value_unset (&newval);
+    }
+
+    if (gst_value_list_get_size (dest_val) == 0) {
+      g_value_unset (dest_val);
+      ret = FALSE;
+    }
+  } else {
+    ret = FALSE;
+  }
+
+  return ret;
+}
+
+static GstCaps *
+gst_video_crop_transform_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * filter_caps)
+{
+  GstVideoCrop *vcrop;
+  GstCaps *other_caps;
+  gint dy, dx, i, left, right, bottom, top;
+  gboolean w_dynamic, h_dynamic;
+
+  vcrop = GST_VIDEO_CROP (trans);
+
+  GST_OBJECT_LOCK (vcrop);
+
+  GST_LOG_OBJECT (vcrop, "l=%d,r=%d,b=%d,t=%d",
+      vcrop->prop_left, vcrop->prop_right, vcrop->prop_bottom, vcrop->prop_top);
+
+  w_dynamic = (vcrop->prop_left == -1 || vcrop->prop_right == -1);
+  h_dynamic = (vcrop->prop_top == -1 || vcrop->prop_bottom == -1);
+
+  left = (vcrop->prop_left == -1) ? 0 : vcrop->prop_left;
+  right = (vcrop->prop_right == -1) ? 0 : vcrop->prop_right;
+  bottom = (vcrop->prop_bottom == -1) ? 0 : vcrop->prop_bottom;
+  top = (vcrop->prop_top == -1) ? 0 : vcrop->prop_top;
+
+  GST_OBJECT_UNLOCK (vcrop);
+
+  if (direction == GST_PAD_SRC) {
+    dx = left + right;
+    dy = top + bottom;
+  } else {
+    dx = 0 - (left + right);
+    dy = 0 - (top + bottom);
+  }
+
+  GST_LOG_OBJECT (vcrop, "transforming caps %" GST_PTR_FORMAT, caps);
+
+  other_caps = gst_caps_new_empty ();
+
+  for (i = 0; i < gst_caps_get_size (caps); ++i) {
+    const GValue *v;
+    GstStructure *structure, *new_structure;
+    GValue w_val = { 0, }, h_val = {
+    0,};
+
+    structure = gst_caps_get_structure (caps, i);
+
+    v = gst_structure_get_value (structure, "width");
+    if (!gst_video_crop_transform_dimension_value (v, dx, &w_val, direction,
+            w_dynamic)) {
+      GST_WARNING_OBJECT (vcrop, "could not tranform width value with dx=%d"
+          ", caps structure=%" GST_PTR_FORMAT, dx, structure);
+      continue;
+    }
+
+    v = gst_structure_get_value (structure, "height");
+    if (!gst_video_crop_transform_dimension_value (v, dy, &h_val, direction,
+            h_dynamic)) {
+      g_value_unset (&w_val);
+      GST_WARNING_OBJECT (vcrop, "could not tranform height value with dy=%d"
+          ", caps structure=%" GST_PTR_FORMAT, dy, structure);
+      continue;
+    }
+
+    new_structure = gst_structure_copy (structure);
+    gst_structure_set_value (new_structure, "width", &w_val);
+    gst_structure_set_value (new_structure, "height", &h_val);
+    g_value_unset (&w_val);
+    g_value_unset (&h_val);
+    GST_LOG_OBJECT (vcrop, "transformed structure %2d: %" GST_PTR_FORMAT
+        " => %" GST_PTR_FORMAT, i, structure, new_structure);
+    gst_caps_append_structure (other_caps, new_structure);
+  }
+
+  if (!gst_caps_is_empty (other_caps) && filter_caps) {
+    GstCaps *tmp = gst_caps_intersect_full (filter_caps, other_caps,
+        GST_CAPS_INTERSECT_FIRST);
+    gst_caps_replace (&other_caps, tmp);
+    gst_caps_unref (tmp);
+  }
+
+  return other_caps;
+}
+
+static gboolean
+gst_video_crop_set_info (GstVideoFilter * vfilter, GstCaps * in,
+    GstVideoInfo * in_info, GstCaps * out, GstVideoInfo * out_info)
+{
+  GstVideoCrop *crop = GST_VIDEO_CROP (vfilter);
+  int dx, dy;
+
+  GST_OBJECT_LOCK (crop);
+  crop->need_update = FALSE;
+  crop->crop_left = crop->prop_left;
+  crop->crop_right = crop->prop_right;
+  crop->crop_top = crop->prop_top;
+  crop->crop_bottom = crop->prop_bottom;
+  GST_OBJECT_UNLOCK (crop);
+
+  dx = GST_VIDEO_INFO_WIDTH (in_info) - GST_VIDEO_INFO_WIDTH (out_info);
+  dy = GST_VIDEO_INFO_HEIGHT (in_info) - GST_VIDEO_INFO_HEIGHT (out_info);
+
+  if (crop->crop_left == -1 && crop->crop_right == -1) {
+    crop->crop_left = dx / 2;
+    crop->crop_right = dx / 2 + (dx & 1);
+  } else if (crop->crop_left == -1) {
+    if (G_UNLIKELY (crop->crop_right > dx))
+      goto cropping_too_much;
+    crop->crop_left = dx - crop->crop_right;
+  } else if (crop->crop_right == -1) {
+    if (G_UNLIKELY (crop->crop_left > dx))
+      goto cropping_too_much;
+    crop->crop_right = dx - crop->crop_left;
+  }
+
+  if (crop->crop_top == -1 && crop->crop_bottom == -1) {
+    crop->crop_top = dy / 2;
+    crop->crop_bottom = dy / 2 + (dy & 1);
+  } else if (crop->crop_top == -1) {
+    if (G_UNLIKELY (crop->crop_bottom > dy))
+      goto cropping_too_much;
+    crop->crop_top = dy - crop->crop_bottom;
+  } else if (crop->crop_bottom == -1) {
+    if (G_UNLIKELY (crop->crop_top > dy))
+      goto cropping_too_much;
+    crop->crop_bottom = dy - crop->crop_top;
+  }
+
+  if (G_UNLIKELY ((crop->crop_left + crop->crop_right) >=
+          GST_VIDEO_INFO_WIDTH (in_info)
+          || (crop->crop_top + crop->crop_bottom) >=
+          GST_VIDEO_INFO_HEIGHT (in_info)))
+    goto cropping_too_much;
+
+  if (in && out)
+    GST_LOG_OBJECT (crop, "incaps = %" GST_PTR_FORMAT ", outcaps = %"
+        GST_PTR_FORMAT, in, out);
+
+  if (GST_VIDEO_INFO_IS_RGB (in_info)
+      || GST_VIDEO_INFO_IS_GRAY (in_info)) {
+    crop->packing = VIDEO_CROP_PIXEL_FORMAT_PACKED_SIMPLE;
+  } else {
+    switch (GST_VIDEO_INFO_FORMAT (in_info)) {
+      case GST_VIDEO_FORMAT_AYUV:
+        crop->packing = VIDEO_CROP_PIXEL_FORMAT_PACKED_SIMPLE;
+        break;
+      case GST_VIDEO_FORMAT_YVYU:
+      case GST_VIDEO_FORMAT_YUY2:
+      case GST_VIDEO_FORMAT_UYVY:
+        crop->packing = VIDEO_CROP_PIXEL_FORMAT_PACKED_COMPLEX;
+        if (GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_UYVY) {
+          /* UYVY = 4:2:2 - [U0 Y0 V0 Y1] [U2 Y2 V2 Y3] [U4 Y4 V4 Y5] */
+          crop->macro_y_off = 1;
+        } else {
+          /* YUYV = 4:2:2 - [Y0 U0 Y1 V0] [Y2 U2 Y3 V2] [Y4 U4 Y5 V4] = YUY2 */
+          crop->macro_y_off = 0;
+        }
+        break;
+      case GST_VIDEO_FORMAT_I420:
+      case GST_VIDEO_FORMAT_YV12:
+        crop->packing = VIDEO_CROP_PIXEL_FORMAT_PLANAR;
+        break;
+      case GST_VIDEO_FORMAT_NV12:
+      case GST_VIDEO_FORMAT_NV21:
+        crop->packing = VIDEO_CROP_PIXEL_FORMAT_SEMI_PLANAR;
+        break;
+      default:
+        goto unknown_format;
+    }
+  }
+
+  crop->in_info = *in_info;
+  crop->out_info = *out_info;
+
+  /* Ensure our decide_allocation will be called again */
+  gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (crop), FALSE);
+  gst_base_transform_set_in_place (GST_BASE_TRANSFORM (crop), FALSE);
+
+  return TRUE;
+
+  /* ERROR */
+cropping_too_much:
+  {
+    GST_WARNING_OBJECT (crop, "we are cropping too much");
+    return FALSE;
+  }
+unknown_format:
+  {
+    GST_WARNING_OBJECT (crop, "Unsupported format");
+    return FALSE;
+  }
+}
+
+/* called with object lock */
+static inline void
+gst_video_crop_set_crop (GstVideoCrop * vcrop, gint new_value, gint * prop)
+{
+  if (*prop != new_value) {
+    *prop = new_value;
+    vcrop->need_update = TRUE;
+  }
+}
+
+static void
+gst_video_crop_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVideoCrop *video_crop;
+
+  video_crop = GST_VIDEO_CROP (object);
+
+  GST_OBJECT_LOCK (video_crop);
+  switch (prop_id) {
+    case PROP_LEFT:
+      gst_video_crop_set_crop (video_crop, g_value_get_int (value),
+          &video_crop->prop_left);
+      break;
+    case PROP_RIGHT:
+      gst_video_crop_set_crop (video_crop, g_value_get_int (value),
+          &video_crop->prop_right);
+      break;
+    case PROP_TOP:
+      gst_video_crop_set_crop (video_crop, g_value_get_int (value),
+          &video_crop->prop_top);
+      break;
+    case PROP_BOTTOM:
+      gst_video_crop_set_crop (video_crop, g_value_get_int (value),
+          &video_crop->prop_bottom);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_LOG_OBJECT (video_crop, "l=%d,r=%d,b=%d,t=%d, need_update:%d",
+      video_crop->prop_left, video_crop->prop_right, video_crop->prop_bottom,
+      video_crop->prop_top, video_crop->need_update);
+
+  GST_OBJECT_UNLOCK (video_crop);
+
+  gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (video_crop));
+}
+
+static void
+gst_video_crop_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstVideoCrop *video_crop;
+
+  video_crop = GST_VIDEO_CROP (object);
+
+  GST_OBJECT_LOCK (video_crop);
+  switch (prop_id) {
+    case PROP_LEFT:
+      g_value_set_int (value, video_crop->prop_left);
+      break;
+    case PROP_RIGHT:
+      g_value_set_int (value, video_crop->prop_right);
+      break;
+    case PROP_TOP:
+      g_value_set_int (value, video_crop->prop_top);
+      break;
+    case PROP_BOTTOM:
+      g_value_set_int (value, video_crop->prop_bottom);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_OBJECT_UNLOCK (video_crop);
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (videocrop_debug, "videocrop", 0, "videocrop");
+
+  if (gst_element_register (plugin, "videocrop", GST_RANK_NONE,
+          GST_TYPE_VIDEO_CROP)
+      && gst_element_register (plugin, "aspectratiocrop", GST_RANK_NONE,
+          GST_TYPE_ASPECT_RATIO_CROP))
+    return TRUE;
+
+  return FALSE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    videocrop,
+    "Crops video into a user-defined region",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/videocrop/gstvideocrop.h b/gst/videocrop/gstvideocrop.h
new file mode 100644
index 0000000..f654e84
--- /dev/null
+++ b/gst/videocrop/gstvideocrop.h
@@ -0,0 +1,83 @@
+/* GStreamer video frame cropping
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_VIDEO_CROP_H__
+#define __GST_VIDEO_CROP_H__
+
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VIDEO_CROP \
+  (gst_video_crop_get_type())
+#define GST_VIDEO_CROP(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_CROP,GstVideoCrop))
+#define GST_VIDEO_CROP_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_CROP,GstVideoCropClass))
+#define GST_IS_VIDEO_CROP(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_CROP))
+#define GST_IS_VIDEO_CROP_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_CROP))
+
+typedef enum {
+  VIDEO_CROP_PIXEL_FORMAT_PACKED_SIMPLE = 0,  /* RGBx, AYUV */
+  VIDEO_CROP_PIXEL_FORMAT_PACKED_COMPLEX,     /* UYVY, YVYU */
+  VIDEO_CROP_PIXEL_FORMAT_PLANAR,             /* I420, YV12 */
+  VIDEO_CROP_PIXEL_FORMAT_SEMI_PLANAR         /* NV12, NV21 */
+} VideoCropPixelFormat;
+
+typedef struct _GstVideoCropImageDetails GstVideoCropImageDetails;
+
+typedef struct _GstVideoCrop GstVideoCrop;
+typedef struct _GstVideoCropClass GstVideoCropClass;
+
+struct _GstVideoCrop
+{
+  GstVideoFilter parent;
+
+  /*< private >*/
+  gint prop_left;
+  gint prop_right;
+  gint prop_top;
+  gint prop_bottom;
+  gboolean need_update;
+
+  GstVideoInfo in_info;
+  GstVideoInfo out_info;
+
+  gint crop_left;
+  gint crop_right;
+  gint crop_top;
+  gint crop_bottom;
+
+  VideoCropPixelFormat  packing;
+  gint macro_y_off;
+};
+
+struct _GstVideoCropClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_video_crop_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_VIDEO_CROP_H__ */
+
diff --git a/gst/videocrop/meson.build b/gst/videocrop/meson.build
new file mode 100644
index 0000000..606b7be
--- /dev/null
+++ b/gst/videocrop/meson.build
@@ -0,0 +1,8 @@
+gstvideocrop = library('gstvideocrop',
+  'gstvideocrop.c', 'gstaspectratiocrop.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc, libsinc],
+  dependencies : [gst_dep, gstbase_dep, gstvideo_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/videofilter/.gitignore b/gst/videofilter/.gitignore
new file mode 100644
index 0000000..acc0880
--- /dev/null
+++ b/gst/videofilter/.gitignore
@@ -0,0 +1,3 @@
+gstvideoexample.h
+gstvideoexample.c
+
diff --git a/gst/videofilter/Makefile.am b/gst/videofilter/Makefile.am
new file mode 100644
index 0000000..cb517fe
--- /dev/null
+++ b/gst/videofilter/Makefile.am
@@ -0,0 +1,22 @@
+plugin_LTLIBRARIES = libgstvideofilter.la
+
+noinst_HEADERS = gstvideoflip.h gstvideobalance.h gstgamma.h gstvideomedian.h
+
+EXTRA_DIST = gstvideotemplate.c make_filter
+CLEANFILES = gstvideoexample.c
+
+libgstvideofilter_la_SOURCES = plugin.c \
+			gstvideoflip.c \
+			gstvideobalance.c \
+			gstgamma.c \
+			gstvideomedian.c
+libgstvideofilter_la_CFLAGS = $(GST_CFLAGS) \
+			$(GST_BASE_CFLAGS) \
+			$(GST_PLUGINS_BASE_CFLAGS)
+libgstvideofilter_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+			-lgstvideo-@GST_API_VERSION@ \
+			$(GST_BASE_LIBS) $(GST_LIBS)
+libgstvideofilter_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(LIBM)
+
+gstvideoexample.c: $(srcdir)/make_filter $(srcdir)/gstvideotemplate.c
+	$(srcdir)/make_filter Videoexample $(srcdir)/gstvideotemplate.c
diff --git a/gst/videofilter/gstgamma.c b/gst/videofilter/gstgamma.c
new file mode 100644
index 0000000..fd4409f
--- /dev/null
+++ b/gst/videofilter/gstgamma.c
@@ -0,0 +1,414 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ * Copyright (C) 2003 Arwed v. Merkatz <v.merkatz@gmx.net>
+ * Copyright (C) 2006 Mark Nauwelaerts <manauw@skynet.be>
+ * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * This file was (probably) generated from
+ * gstvideotemplate.c,v 1.12 2004/01/07 21:07:12 ds Exp 
+ * and
+ * make_filter,v 1.6 2004/01/07 21:33:01 ds Exp 
+ */
+
+/**
+ * SECTION:element-gamma
+ *
+ * Performs gamma correction on a video stream.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 videotestsrc ! gamma gamma=2.0 ! videoconvert ! ximagesink
+ * ]| This pipeline will make the image "brighter".
+ * |[
+ * gst-launch-1.0 videotestsrc ! gamma gamma=0.5 ! videoconvert ! ximagesink
+ * ]| This pipeline will make the image "darker".
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstgamma.h"
+#include <string.h>
+#include <math.h>
+
+#include <gst/video/video.h>
+
+GST_DEBUG_CATEGORY_STATIC (gamma_debug);
+#define GST_CAT_DEFAULT gamma_debug
+
+/* GstGamma properties */
+enum
+{
+  PROP_0,
+  PROP_GAMMA
+      /* FILL ME */
+};
+
+#define DEFAULT_PROP_GAMMA  1
+
+static GstStaticPadTemplate gst_gamma_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, "
+            "ARGB, BGRA, ABGR, RGBA, Y444, "
+            "xRGB, RGBx, xBGR, BGRx, RGB, BGR, Y42B, NV12, "
+            "NV21, YUY2, UYVY, YVYU, I420, YV12, IYUV, Y41B }"))
+    );
+
+static GstStaticPadTemplate gst_gamma_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, "
+            "ARGB, BGRA, ABGR, RGBA, Y444, "
+            "xRGB, RGBx, xBGR, BGRx, RGB, BGR, Y42B, NV12, "
+            "NV21, YUY2, UYVY, YVYU, I420, YV12, IYUV, Y41B }"))
+    );
+
+static void gst_gamma_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gamma_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_gamma_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info);
+static GstFlowReturn gst_gamma_transform_frame_ip (GstVideoFilter * vfilter,
+    GstVideoFrame * frame);
+static void gst_gamma_before_transform (GstBaseTransform * transform,
+    GstBuffer * buf);
+
+static void gst_gamma_calculate_tables (GstGamma * gamma);
+
+G_DEFINE_TYPE (GstGamma, gst_gamma, GST_TYPE_VIDEO_FILTER);
+
+static void
+gst_gamma_class_init (GstGammaClass * g_class)
+{
+  GObjectClass *gobject_class = (GObjectClass *) g_class;
+  GstElementClass *gstelement_class = (GstElementClass *) g_class;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) g_class;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) g_class;
+
+  GST_DEBUG_CATEGORY_INIT (gamma_debug, "gamma", 0, "gamma");
+
+  gobject_class->set_property = gst_gamma_set_property;
+  gobject_class->get_property = gst_gamma_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_GAMMA,
+      g_param_spec_double ("gamma", "Gamma", "gamma",
+          0.01, 10, DEFAULT_PROP_GAMMA,
+          GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE));
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Video gamma correction", "Filter/Effect/Video",
+      "Adjusts gamma on a video stream", "Arwed v. Merkatz <v.merkatz@gmx.net");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_gamma_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_gamma_src_template);
+
+  trans_class->before_transform =
+      GST_DEBUG_FUNCPTR (gst_gamma_before_transform);
+  trans_class->transform_ip_on_passthrough = FALSE;
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_gamma_set_info);
+  vfilter_class->transform_frame_ip =
+      GST_DEBUG_FUNCPTR (gst_gamma_transform_frame_ip);
+}
+
+static void
+gst_gamma_init (GstGamma * gamma)
+{
+  /* properties */
+  gamma->gamma = DEFAULT_PROP_GAMMA;
+  gst_gamma_calculate_tables (gamma);
+}
+
+static void
+gst_gamma_set_property (GObject * object, guint prop_id, const GValue * value,
+    GParamSpec * pspec)
+{
+  GstGamma *gamma = GST_GAMMA (object);
+
+  switch (prop_id) {
+    case PROP_GAMMA:{
+      gdouble val = g_value_get_double (value);
+
+      GST_DEBUG_OBJECT (gamma, "Changing gamma from %lf to %lf", gamma->gamma,
+          val);
+      GST_OBJECT_LOCK (gamma);
+      gamma->gamma = val;
+      GST_OBJECT_UNLOCK (gamma);
+      gst_gamma_calculate_tables (gamma);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gamma_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstGamma *gamma = GST_GAMMA (object);
+
+  switch (prop_id) {
+    case PROP_GAMMA:
+      g_value_set_double (value, gamma->gamma);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gamma_calculate_tables (GstGamma * gamma)
+{
+  gint n;
+  gdouble val;
+  gdouble exp;
+  gboolean passthrough = FALSE;
+
+  GST_OBJECT_LOCK (gamma);
+  if (gamma->gamma == 1.0) {
+    passthrough = TRUE;
+  } else {
+    exp = 1.0 / gamma->gamma;
+    for (n = 0; n < 256; n++) {
+      val = n / 255.0;
+      val = pow (val, exp);
+      val = 255.0 * val;
+      gamma->gamma_table[n] = (guint8) floor (val + 0.5);
+    }
+  }
+  GST_OBJECT_UNLOCK (gamma);
+
+  gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (gamma), passthrough);
+}
+
+static void
+gst_gamma_planar_yuv_ip (GstGamma * gamma, GstVideoFrame * frame)
+{
+  gint i, j, height;
+  gint width, stride, row_wrap;
+  const guint8 *table = gamma->gamma_table;
+  guint8 *data;
+
+  data = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
+  stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
+  width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0);
+  height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0);
+  row_wrap = stride - width;
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      *data = table[*data];
+      data++;
+    }
+    data += row_wrap;
+  }
+}
+
+static void
+gst_gamma_packed_yuv_ip (GstGamma * gamma, GstVideoFrame * frame)
+{
+  gint i, j, height;
+  gint width, stride, row_wrap;
+  gint pixel_stride;
+  const guint8 *table = gamma->gamma_table;
+  guint8 *data;
+
+  data = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
+  stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
+  width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0);
+  height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0);
+  pixel_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
+  row_wrap = stride - pixel_stride * width;
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      *data = table[*data];
+      data += pixel_stride;
+    }
+    data += row_wrap;
+  }
+}
+
+static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
+  298, 0, 409, -57068,
+  298, -100, -208, 34707,
+  298, 516, 0, -70870,
+};
+
+static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
+  66, 129, 25, 4096,
+  -38, -74, 112, 32768,
+  112, -94, -18, 32768,
+};
+
+#define APPLY_MATRIX(m,o,v1,v2,v3) ((m[o*4] * v1 + m[o*4+1] * v2 + m[o*4+2] * v3 + m[o*4+3]) >> 8)
+
+static void
+gst_gamma_packed_rgb_ip (GstGamma * gamma, GstVideoFrame * frame)
+{
+  gint i, j, height;
+  gint width, stride, row_wrap;
+  gint pixel_stride;
+  const guint8 *table = gamma->gamma_table;
+  gint offsets[3];
+  gint r, g, b;
+  gint y, u, v;
+  guint8 *data;
+
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+  width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0);
+  height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0);
+
+  offsets[0] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 0);
+  offsets[1] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 1);
+  offsets[2] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 2);
+
+  pixel_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
+  row_wrap = stride - pixel_stride * width;
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      r = data[offsets[0]];
+      g = data[offsets[1]];
+      b = data[offsets[2]];
+
+      y = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 0, r, g, b);
+      u = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 1, r, g, b);
+      v = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 2, r, g, b);
+
+      y = table[CLAMP (y, 0, 255)];
+      r = APPLY_MATRIX (cog_ycbcr_to_rgb_matrix_8bit_sdtv, 0, y, u, v);
+      g = APPLY_MATRIX (cog_ycbcr_to_rgb_matrix_8bit_sdtv, 1, y, u, v);
+      b = APPLY_MATRIX (cog_ycbcr_to_rgb_matrix_8bit_sdtv, 2, y, u, v);
+
+      data[offsets[0]] = CLAMP (r, 0, 255);
+      data[offsets[1]] = CLAMP (g, 0, 255);
+      data[offsets[2]] = CLAMP (b, 0, 255);
+      data += pixel_stride;
+    }
+    data += row_wrap;
+  }
+}
+
+static gboolean
+gst_gamma_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstGamma *gamma = GST_GAMMA (vfilter);
+
+  GST_DEBUG_OBJECT (gamma,
+      "setting caps: in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps,
+      outcaps);
+
+  switch (GST_VIDEO_INFO_FORMAT (in_info)) {
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+    case GST_VIDEO_FORMAT_Y41B:
+    case GST_VIDEO_FORMAT_Y42B:
+    case GST_VIDEO_FORMAT_Y444:
+    case GST_VIDEO_FORMAT_NV12:
+    case GST_VIDEO_FORMAT_NV21:
+      gamma->process = gst_gamma_planar_yuv_ip;
+      break;
+    case GST_VIDEO_FORMAT_YUY2:
+    case GST_VIDEO_FORMAT_UYVY:
+    case GST_VIDEO_FORMAT_AYUV:
+    case GST_VIDEO_FORMAT_YVYU:
+      gamma->process = gst_gamma_packed_yuv_ip;
+      break;
+    case GST_VIDEO_FORMAT_ARGB:
+    case GST_VIDEO_FORMAT_ABGR:
+    case GST_VIDEO_FORMAT_RGBA:
+    case GST_VIDEO_FORMAT_BGRA:
+    case GST_VIDEO_FORMAT_xRGB:
+    case GST_VIDEO_FORMAT_xBGR:
+    case GST_VIDEO_FORMAT_RGBx:
+    case GST_VIDEO_FORMAT_BGRx:
+    case GST_VIDEO_FORMAT_RGB:
+    case GST_VIDEO_FORMAT_BGR:
+      gamma->process = gst_gamma_packed_rgb_ip;
+      break;
+    default:
+      goto invalid_caps;
+      break;
+  }
+  return TRUE;
+
+  /* ERRORS */
+invalid_caps:
+  {
+    GST_ERROR_OBJECT (gamma, "Invalid caps: %" GST_PTR_FORMAT, incaps);
+    return FALSE;
+  }
+}
+
+static void
+gst_gamma_before_transform (GstBaseTransform * base, GstBuffer * outbuf)
+{
+  GstGamma *gamma = GST_GAMMA (base);
+  GstClockTime timestamp, stream_time;
+
+  timestamp = GST_BUFFER_TIMESTAMP (outbuf);
+  stream_time =
+      gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (gamma, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (gamma), stream_time);
+}
+
+static GstFlowReturn
+gst_gamma_transform_frame_ip (GstVideoFilter * vfilter, GstVideoFrame * frame)
+{
+  GstGamma *gamma = GST_GAMMA (vfilter);
+
+  if (!gamma->process)
+    goto not_negotiated;
+
+  GST_OBJECT_LOCK (gamma);
+  gamma->process (gamma, frame);
+  GST_OBJECT_UNLOCK (gamma);
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+not_negotiated:
+  {
+    GST_ERROR_OBJECT (gamma, "Not negotiated yet");
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+}
diff --git a/gst/videofilter/gstgamma.h b/gst/videofilter/gstgamma.h
new file mode 100644
index 0000000..13f967b
--- /dev/null
+++ b/gst/videofilter/gstgamma.h
@@ -0,0 +1,75 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ * Copyright (C) 2003 Arwed v. Merkatz <v.merkatz@gmx.net>
+ * Copyright (C) 2006 Mark Nauwelaerts <manauw@skynet.be>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_VIDEO_GAMMA_H__
+#define __GST_VIDEO_GAMMA_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GAMMA \
+  (gst_gamma_get_type())
+#define GST_GAMMA(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GAMMA,GstGamma))
+#define GST_GAMMA_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GAMMA,GstGammaClass))
+#define GST_IS_GAMMA(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GAMMA))
+#define GST_IS_GAMMA_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GAMMA))
+
+typedef struct _GstGamma GstGamma;
+typedef struct _GstGammaClass GstGammaClass;
+
+/**
+ * GstGamma:
+ *
+ * Opaque data structure.
+ */
+struct _GstGamma
+{
+  GstVideoFilter videofilter;
+
+  /* < private > */
+  /* properties */
+  gdouble gamma;
+
+  /* tables */
+  guint8 gamma_table[256];
+
+  void (*process) (GstGamma *gamma, GstVideoFrame *frame);
+};
+
+struct _GstGammaClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_gamma_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_VIDEO_GAMMA_H__ */
diff --git a/gst/videofilter/gstvideobalance.c b/gst/videofilter/gstvideobalance.c
new file mode 100644
index 0000000..068bcd7
--- /dev/null
+++ b/gst/videofilter/gstvideobalance.c
@@ -0,0 +1,842 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ * Copyright (C) <2010> Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * This file was (probably) generated from gstvideobalance.c,
+ * gstvideobalance.c,v 1.7 2003/11/08 02:48:59 dschleef Exp 
+ */
+
+/**
+ * SECTION:element-videobalance
+ *
+ * Adjusts brightness, contrast, hue, saturation on a video stream.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 videotestsrc ! videobalance saturation=0.0 ! videoconvert ! ximagesink
+ * ]| This pipeline converts the image to black and white by setting the
+ * saturation to 0.0.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/math-compat.h>
+
+#include "gstvideobalance.h"
+#include <string.h>
+
+#include <gst/video/colorbalance.h>
+
+GST_DEBUG_CATEGORY_STATIC (videobalance_debug);
+#define GST_CAT_DEFAULT videobalance_debug
+
+/* GstVideoBalance properties */
+#define DEFAULT_PROP_CONTRAST		1.0
+#define DEFAULT_PROP_BRIGHTNESS		0.0
+#define DEFAULT_PROP_HUE		0.0
+#define DEFAULT_PROP_SATURATION		1.0
+
+enum
+{
+  PROP_0,
+  PROP_CONTRAST,
+  PROP_BRIGHTNESS,
+  PROP_HUE,
+  PROP_SATURATION
+};
+
+#define PROCESSING_CAPS \
+  "{ AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, " \
+  "xBGR, BGRx, RGB, BGR, Y42B, YUY2, UYVY, YVYU, " \
+  "I420, YV12, IYUV, Y41B, NV12, NV21 }"
+
+static GstStaticPadTemplate gst_video_balance_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (PROCESSING_CAPS) ";"
+        "video/x-raw(ANY)")
+    );
+
+static GstStaticPadTemplate gst_video_balance_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (PROCESSING_CAPS) ";"
+        "video/x-raw(ANY)")
+    );
+
+static void gst_video_balance_colorbalance_init (GstColorBalanceInterface *
+    iface);
+
+static void gst_video_balance_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_video_balance_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+#define gst_video_balance_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstVideoBalance, gst_video_balance,
+    GST_TYPE_VIDEO_FILTER,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
+        gst_video_balance_colorbalance_init));
+
+/*
+ * look-up tables (LUT).
+ */
+static void
+gst_video_balance_update_tables (GstVideoBalance * vb)
+{
+  gint i, j;
+  gdouble y, u, v, hue_cos, hue_sin;
+
+  /* Y */
+  for (i = 0; i < 256; i++) {
+    y = 16 + ((i - 16) * vb->contrast + vb->brightness * 255);
+    if (y < 0)
+      y = 0;
+    else if (y > 255)
+      y = 255;
+    vb->tabley[i] = rint (y);
+  }
+
+  hue_cos = cos (G_PI * vb->hue);
+  hue_sin = sin (G_PI * vb->hue);
+
+  /* U/V lookup tables are 2D, since we need both U/V for each table
+   * separately. */
+  for (i = -128; i < 128; i++) {
+    for (j = -128; j < 128; j++) {
+      u = 128 + ((i * hue_cos + j * hue_sin) * vb->saturation);
+      v = 128 + ((-i * hue_sin + j * hue_cos) * vb->saturation);
+      if (u < 0)
+        u = 0;
+      else if (u > 255)
+        u = 255;
+      if (v < 0)
+        v = 0;
+      else if (v > 255)
+        v = 255;
+      vb->tableu[i + 128][j + 128] = rint (u);
+      vb->tablev[i + 128][j + 128] = rint (v);
+    }
+  }
+}
+
+static gboolean
+gst_video_balance_is_passthrough (GstVideoBalance * videobalance)
+{
+  return videobalance->contrast == 1.0 &&
+      videobalance->brightness == 0.0 &&
+      videobalance->hue == 0.0 && videobalance->saturation == 1.0;
+}
+
+static void
+gst_video_balance_update_properties (GstVideoBalance * videobalance)
+{
+  gboolean passthrough;
+  GstBaseTransform *base = GST_BASE_TRANSFORM (videobalance);
+
+  GST_OBJECT_LOCK (videobalance);
+  passthrough = gst_video_balance_is_passthrough (videobalance);
+  if (!passthrough)
+    gst_video_balance_update_tables (videobalance);
+  GST_OBJECT_UNLOCK (videobalance);
+
+  gst_base_transform_set_passthrough (base, passthrough);
+}
+
+static void
+gst_video_balance_planar_yuv (GstVideoBalance * videobalance,
+    GstVideoFrame * frame)
+{
+  gint x, y;
+  guint8 *ydata;
+  guint8 *udata, *vdata;
+  gint ystride, ustride, vstride;
+  gint width, height;
+  gint width2, height2;
+  guint8 *tabley = videobalance->tabley;
+  guint8 **tableu = videobalance->tableu;
+  guint8 **tablev = videobalance->tablev;
+
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
+
+  ydata = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  ystride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+
+  for (y = 0; y < height; y++) {
+    guint8 *yptr;
+
+    yptr = ydata + y * ystride;
+    for (x = 0; x < width; x++) {
+      *yptr = tabley[*yptr];
+      yptr++;
+    }
+  }
+
+  width2 = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1);
+  height2 = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1);
+
+  udata = GST_VIDEO_FRAME_PLANE_DATA (frame, 1);
+  vdata = GST_VIDEO_FRAME_PLANE_DATA (frame, 2);
+  ustride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 1);
+  vstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 2);
+
+  for (y = 0; y < height2; y++) {
+    guint8 *uptr, *vptr;
+    guint8 u1, v1;
+
+    uptr = udata + y * ustride;
+    vptr = vdata + y * vstride;
+
+    for (x = 0; x < width2; x++) {
+      u1 = *uptr;
+      v1 = *vptr;
+
+      *uptr++ = tableu[u1][v1];
+      *vptr++ = tablev[u1][v1];
+    }
+  }
+}
+
+static void
+gst_video_balance_semiplanar_yuv (GstVideoBalance * videobalance,
+    GstVideoFrame * frame)
+{
+  gint x, y;
+  guint8 *ydata;
+  guint8 *uvdata;
+  gint ystride, uvstride;
+  gint width, height;
+  gint width2, height2;
+  guint8 *tabley = videobalance->tabley;
+  guint8 **tableu = videobalance->tableu;
+  guint8 **tablev = videobalance->tablev;
+  gint upos, vpos;
+
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
+
+  ydata = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  ystride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+
+  for (y = 0; y < height; y++) {
+    guint8 *yptr;
+
+    yptr = ydata + y * ystride;
+    for (x = 0; x < width; x++) {
+      *yptr = tabley[*yptr];
+      yptr++;
+    }
+  }
+
+  width2 = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1);
+  height2 = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1);
+
+  uvdata = GST_VIDEO_FRAME_PLANE_DATA (frame, 1);
+  uvstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 1);
+
+  upos = GST_VIDEO_INFO_FORMAT (&frame->info) == GST_VIDEO_FORMAT_NV12 ? 0 : 1;
+  vpos = GST_VIDEO_INFO_FORMAT (&frame->info) == GST_VIDEO_FORMAT_NV12 ? 1 : 0;
+
+  for (y = 0; y < height2; y++) {
+    guint8 *uvptr;
+    guint8 u1, v1;
+
+    uvptr = uvdata + y * uvstride;
+
+    for (x = 0; x < width2; x++) {
+      u1 = uvptr[upos];
+      v1 = uvptr[vpos];
+
+      uvptr[upos] = tableu[u1][v1];
+      uvptr[vpos] = tablev[u1][v1];
+      uvptr += 2;
+    }
+  }
+}
+
+static void
+gst_video_balance_packed_yuv (GstVideoBalance * videobalance,
+    GstVideoFrame * frame)
+{
+  gint x, y, stride;
+  guint8 *ydata, *udata, *vdata;
+  gint yoff, uoff, voff;
+  gint width, height;
+  gint width2, height2;
+  guint8 *tabley = videobalance->tabley;
+  guint8 **tableu = videobalance->tableu;
+  guint8 **tablev = videobalance->tablev;
+
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
+
+  stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+  ydata = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
+  yoff = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
+
+  for (y = 0; y < height; y++) {
+    guint8 *yptr;
+
+    yptr = ydata + y * stride;
+    for (x = 0; x < width; x++) {
+      *yptr = tabley[*yptr];
+      yptr += yoff;
+    }
+  }
+
+  width2 = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1);
+  height2 = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1);
+
+  udata = GST_VIDEO_FRAME_COMP_DATA (frame, 1);
+  vdata = GST_VIDEO_FRAME_COMP_DATA (frame, 2);
+  uoff = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 1);
+  voff = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 2);
+
+  for (y = 0; y < height2; y++) {
+    guint8 *uptr, *vptr;
+    guint8 u1, v1;
+
+    uptr = udata + y * stride;
+    vptr = vdata + y * stride;
+
+    for (x = 0; x < width2; x++) {
+      u1 = *uptr;
+      v1 = *vptr;
+
+      *uptr = tableu[u1][v1];
+      *vptr = tablev[u1][v1];
+
+      uptr += uoff;
+      vptr += voff;
+    }
+  }
+}
+
+static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
+  298, 0, 409, -57068,
+  298, -100, -208, 34707,
+  298, 516, 0, -70870,
+};
+
+static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
+  66, 129, 25, 4096,
+  -38, -74, 112, 32768,
+  112, -94, -18, 32768,
+};
+
+#define APPLY_MATRIX(m,o,v1,v2,v3) ((m[o*4] * v1 + m[o*4+1] * v2 + m[o*4+2] * v3 + m[o*4+3]) >> 8)
+
+static void
+gst_video_balance_packed_rgb (GstVideoBalance * videobalance,
+    GstVideoFrame * frame)
+{
+  gint i, j, height;
+  gint width, stride, row_wrap;
+  gint pixel_stride;
+  guint8 *data;
+  gint offsets[3];
+  gint r, g, b;
+  gint y, u, v;
+  gint u_tmp, v_tmp;
+  guint8 *tabley = videobalance->tabley;
+  guint8 **tableu = videobalance->tableu;
+  guint8 **tablev = videobalance->tablev;
+
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
+
+  offsets[0] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 0);
+  offsets[1] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 1);
+  offsets[2] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 2);
+
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+
+  pixel_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
+  row_wrap = stride - pixel_stride * width;
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      r = data[offsets[0]];
+      g = data[offsets[1]];
+      b = data[offsets[2]];
+
+      y = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 0, r, g, b);
+      u_tmp = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 1, r, g, b);
+      v_tmp = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 2, r, g, b);
+
+      y = CLAMP (y, 0, 255);
+      u_tmp = CLAMP (u_tmp, 0, 255);
+      v_tmp = CLAMP (v_tmp, 0, 255);
+
+      y = tabley[y];
+      u = tableu[u_tmp][v_tmp];
+      v = tablev[u_tmp][v_tmp];
+
+      r = APPLY_MATRIX (cog_ycbcr_to_rgb_matrix_8bit_sdtv, 0, y, u, v);
+      g = APPLY_MATRIX (cog_ycbcr_to_rgb_matrix_8bit_sdtv, 1, y, u, v);
+      b = APPLY_MATRIX (cog_ycbcr_to_rgb_matrix_8bit_sdtv, 2, y, u, v);
+
+      data[offsets[0]] = CLAMP (r, 0, 255);
+      data[offsets[1]] = CLAMP (g, 0, 255);
+      data[offsets[2]] = CLAMP (b, 0, 255);
+      data += pixel_stride;
+    }
+    data += row_wrap;
+  }
+}
+
+/* get notified of caps and plug in the correct process function */
+static gboolean
+gst_video_balance_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstVideoBalance *videobalance = GST_VIDEO_BALANCE (vfilter);
+
+  GST_DEBUG_OBJECT (videobalance,
+      "in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps);
+
+  videobalance->process = NULL;
+
+  switch (GST_VIDEO_INFO_FORMAT (in_info)) {
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+    case GST_VIDEO_FORMAT_Y41B:
+    case GST_VIDEO_FORMAT_Y42B:
+    case GST_VIDEO_FORMAT_Y444:
+      videobalance->process = gst_video_balance_planar_yuv;
+      break;
+    case GST_VIDEO_FORMAT_YUY2:
+    case GST_VIDEO_FORMAT_UYVY:
+    case GST_VIDEO_FORMAT_AYUV:
+    case GST_VIDEO_FORMAT_YVYU:
+      videobalance->process = gst_video_balance_packed_yuv;
+      break;
+    case GST_VIDEO_FORMAT_NV12:
+    case GST_VIDEO_FORMAT_NV21:
+      videobalance->process = gst_video_balance_semiplanar_yuv;
+      break;
+    case GST_VIDEO_FORMAT_ARGB:
+    case GST_VIDEO_FORMAT_ABGR:
+    case GST_VIDEO_FORMAT_RGBA:
+    case GST_VIDEO_FORMAT_BGRA:
+    case GST_VIDEO_FORMAT_xRGB:
+    case GST_VIDEO_FORMAT_xBGR:
+    case GST_VIDEO_FORMAT_RGBx:
+    case GST_VIDEO_FORMAT_BGRx:
+    case GST_VIDEO_FORMAT_RGB:
+    case GST_VIDEO_FORMAT_BGR:
+      videobalance->process = gst_video_balance_packed_rgb;
+      break;
+    default:
+      if (!gst_video_balance_is_passthrough (videobalance))
+        goto unknown_format;
+      break;
+  }
+
+  return TRUE;
+
+  /* ERRORS */
+unknown_format:
+  {
+    GST_ERROR_OBJECT (videobalance, "unknown format %" GST_PTR_FORMAT, incaps);
+    return FALSE;
+  }
+}
+
+static void
+gst_video_balance_before_transform (GstBaseTransform * base, GstBuffer * buf)
+{
+  GstVideoBalance *balance = GST_VIDEO_BALANCE (base);
+  GstClockTime timestamp, stream_time;
+
+  timestamp = GST_BUFFER_TIMESTAMP (buf);
+  stream_time =
+      gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (balance, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (balance), stream_time);
+}
+
+static GstCaps *
+gst_video_balance_transform_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
+{
+  GstVideoBalance *balance = GST_VIDEO_BALANCE (trans);
+  GstCaps *ret;
+
+  if (!gst_video_balance_is_passthrough (balance)) {
+    static GstStaticCaps raw_caps =
+        GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (PROCESSING_CAPS));
+
+    caps = gst_caps_intersect (caps, gst_static_caps_get (&raw_caps));
+
+    if (filter) {
+      ret = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+      gst_caps_unref (caps);
+    } else {
+      ret = caps;
+    }
+  } else {
+    if (filter) {
+      ret = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    } else {
+      ret = gst_caps_ref (caps);
+    }
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_video_balance_transform_frame_ip (GstVideoFilter * vfilter,
+    GstVideoFrame * frame)
+{
+  GstVideoBalance *videobalance = GST_VIDEO_BALANCE (vfilter);
+
+  if (!videobalance->process)
+    goto not_negotiated;
+
+  GST_OBJECT_LOCK (videobalance);
+  videobalance->process (videobalance, frame);
+  GST_OBJECT_UNLOCK (videobalance);
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+not_negotiated:
+  {
+    GST_ERROR_OBJECT (videobalance, "Not negotiated yet");
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+}
+
+static void
+gst_video_balance_finalize (GObject * object)
+{
+  GList *channels = NULL;
+  GstVideoBalance *balance = GST_VIDEO_BALANCE (object);
+
+  g_free (balance->tableu[0]);
+
+  channels = balance->channels;
+  while (channels) {
+    GstColorBalanceChannel *channel = channels->data;
+
+    g_object_unref (channel);
+    channels->data = NULL;
+    channels = g_list_next (channels);
+  }
+
+  if (balance->channels)
+    g_list_free (balance->channels);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_video_balance_class_init (GstVideoBalanceClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (videobalance_debug, "videobalance", 0,
+      "videobalance");
+
+  gobject_class->finalize = gst_video_balance_finalize;
+  gobject_class->set_property = gst_video_balance_set_property;
+  gobject_class->get_property = gst_video_balance_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_CONTRAST,
+      g_param_spec_double ("contrast", "Contrast", "contrast",
+          0.0, 2.0, DEFAULT_PROP_CONTRAST,
+          GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
+      g_param_spec_double ("brightness", "Brightness", "brightness", -1.0, 1.0,
+          DEFAULT_PROP_BRIGHTNESS,
+          GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_HUE,
+      g_param_spec_double ("hue", "Hue", "hue", -1.0, 1.0, DEFAULT_PROP_HUE,
+          GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_SATURATION,
+      g_param_spec_double ("saturation", "Saturation", "saturation", 0.0, 2.0,
+          DEFAULT_PROP_SATURATION,
+          GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class, "Video balance",
+      "Filter/Effect/Video",
+      "Adjusts brightness, contrast, hue, saturation on a video stream",
+      "David Schleef <ds@schleef.org>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_video_balance_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_video_balance_src_template);
+
+  trans_class->before_transform =
+      GST_DEBUG_FUNCPTR (gst_video_balance_before_transform);
+  trans_class->transform_ip_on_passthrough = FALSE;
+  trans_class->transform_caps =
+      GST_DEBUG_FUNCPTR (gst_video_balance_transform_caps);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_video_balance_set_info);
+  vfilter_class->transform_frame_ip =
+      GST_DEBUG_FUNCPTR (gst_video_balance_transform_frame_ip);
+}
+
+static void
+gst_video_balance_init (GstVideoBalance * videobalance)
+{
+  const gchar *channels[4] = { "HUE", "SATURATION",
+    "BRIGHTNESS", "CONTRAST"
+  };
+  gint i;
+
+  /* Initialize propertiews */
+  videobalance->contrast = DEFAULT_PROP_CONTRAST;
+  videobalance->brightness = DEFAULT_PROP_BRIGHTNESS;
+  videobalance->hue = DEFAULT_PROP_HUE;
+  videobalance->saturation = DEFAULT_PROP_SATURATION;
+
+  videobalance->tableu[0] = g_new (guint8, 256 * 256 * 2);
+  for (i = 0; i < 256; i++) {
+    videobalance->tableu[i] =
+        videobalance->tableu[0] + i * 256 * sizeof (guint8);
+    videobalance->tablev[i] =
+        videobalance->tableu[0] + 256 * 256 * sizeof (guint8) +
+        i * 256 * sizeof (guint8);
+  }
+
+  gst_video_balance_update_properties (videobalance);
+
+  /* Generate the channels list */
+  for (i = 0; i < G_N_ELEMENTS (channels); i++) {
+    GstColorBalanceChannel *channel;
+
+    channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
+    channel->label = g_strdup (channels[i]);
+    channel->min_value = -1000;
+    channel->max_value = 1000;
+
+    videobalance->channels = g_list_append (videobalance->channels, channel);
+  }
+}
+
+static const GList *
+gst_video_balance_colorbalance_list_channels (GstColorBalance * balance)
+{
+  GstVideoBalance *videobalance = GST_VIDEO_BALANCE (balance);
+
+  g_return_val_if_fail (videobalance != NULL, NULL);
+  g_return_val_if_fail (GST_IS_VIDEO_BALANCE (videobalance), NULL);
+
+  return videobalance->channels;
+}
+
+static void
+gst_video_balance_colorbalance_set_value (GstColorBalance * balance,
+    GstColorBalanceChannel * channel, gint value)
+{
+  GstVideoBalance *vb = GST_VIDEO_BALANCE (balance);
+  gdouble new_val;
+  gboolean changed = FALSE;
+
+  g_return_if_fail (vb != NULL);
+  g_return_if_fail (GST_IS_VIDEO_BALANCE (vb));
+  g_return_if_fail (GST_IS_VIDEO_FILTER (vb));
+  g_return_if_fail (channel->label != NULL);
+
+  GST_OBJECT_LOCK (vb);
+  if (!g_ascii_strcasecmp (channel->label, "HUE")) {
+    new_val = (value + 1000.0) * 2.0 / 2000.0 - 1.0;
+    changed = new_val != vb->hue;
+    vb->hue = new_val;
+  } else if (!g_ascii_strcasecmp (channel->label, "SATURATION")) {
+    new_val = (value + 1000.0) * 2.0 / 2000.0;
+    changed = new_val != vb->saturation;
+    vb->saturation = new_val;
+  } else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) {
+    new_val = (value + 1000.0) * 2.0 / 2000.0 - 1.0;
+    changed = new_val != vb->brightness;
+    vb->brightness = new_val;
+  } else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) {
+    new_val = (value + 1000.0) * 2.0 / 2000.0;
+    changed = new_val != vb->contrast;
+    vb->contrast = new_val;
+  }
+  GST_OBJECT_UNLOCK (vb);
+
+  if (changed)
+    gst_video_balance_update_properties (vb);
+
+  if (changed) {
+    gst_color_balance_value_changed (balance, channel,
+        gst_color_balance_get_value (balance, channel));
+  }
+}
+
+static gint
+gst_video_balance_colorbalance_get_value (GstColorBalance * balance,
+    GstColorBalanceChannel * channel)
+{
+  GstVideoBalance *vb = GST_VIDEO_BALANCE (balance);
+  gint value = 0;
+
+  g_return_val_if_fail (vb != NULL, 0);
+  g_return_val_if_fail (GST_IS_VIDEO_BALANCE (vb), 0);
+  g_return_val_if_fail (channel->label != NULL, 0);
+
+  if (!g_ascii_strcasecmp (channel->label, "HUE")) {
+    value = (vb->hue + 1) * 2000.0 / 2.0 - 1000.0;
+  } else if (!g_ascii_strcasecmp (channel->label, "SATURATION")) {
+    value = vb->saturation * 2000.0 / 2.0 - 1000.0;
+  } else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) {
+    value = (vb->brightness + 1) * 2000.0 / 2.0 - 1000.0;
+  } else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) {
+    value = vb->contrast * 2000.0 / 2.0 - 1000.0;
+  }
+
+  return value;
+}
+
+static GstColorBalanceType
+gst_video_balance_colorbalance_get_balance_type (GstColorBalance * balance)
+{
+  return GST_COLOR_BALANCE_SOFTWARE;
+}
+
+static void
+gst_video_balance_colorbalance_init (GstColorBalanceInterface * iface)
+{
+  iface->list_channels = gst_video_balance_colorbalance_list_channels;
+  iface->set_value = gst_video_balance_colorbalance_set_value;
+  iface->get_value = gst_video_balance_colorbalance_get_value;
+  iface->get_balance_type = gst_video_balance_colorbalance_get_balance_type;
+}
+
+static GstColorBalanceChannel *
+gst_video_balance_find_channel (GstVideoBalance * balance, const gchar * label)
+{
+  GList *l;
+
+  for (l = balance->channels; l; l = l->next) {
+    GstColorBalanceChannel *channel = l->data;
+
+    if (g_ascii_strcasecmp (channel->label, label) == 0)
+      return channel;
+  }
+  return NULL;
+}
+
+static void
+gst_video_balance_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVideoBalance *balance = GST_VIDEO_BALANCE (object);
+  gdouble d;
+  const gchar *label = NULL;
+
+  GST_OBJECT_LOCK (balance);
+  switch (prop_id) {
+    case PROP_CONTRAST:
+      d = g_value_get_double (value);
+      GST_DEBUG_OBJECT (balance, "Changing contrast from %lf to %lf",
+          balance->contrast, d);
+      if (d != balance->contrast)
+        label = "CONTRAST";
+      balance->contrast = d;
+      break;
+    case PROP_BRIGHTNESS:
+      d = g_value_get_double (value);
+      GST_DEBUG_OBJECT (balance, "Changing brightness from %lf to %lf",
+          balance->brightness, d);
+      if (d != balance->brightness)
+        label = "BRIGHTNESS";
+      balance->brightness = d;
+      break;
+    case PROP_HUE:
+      d = g_value_get_double (value);
+      GST_DEBUG_OBJECT (balance, "Changing hue from %lf to %lf", balance->hue,
+          d);
+      if (d != balance->hue)
+        label = "HUE";
+      balance->hue = d;
+      break;
+    case PROP_SATURATION:
+      d = g_value_get_double (value);
+      GST_DEBUG_OBJECT (balance, "Changing saturation from %lf to %lf",
+          balance->saturation, d);
+      if (d != balance->saturation)
+        label = "SATURATION";
+      balance->saturation = d;
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  GST_OBJECT_UNLOCK (balance);
+  gst_video_balance_update_properties (balance);
+
+  if (label) {
+    GstColorBalanceChannel *channel =
+        gst_video_balance_find_channel (balance, label);
+    gst_color_balance_value_changed (GST_COLOR_BALANCE (balance), channel,
+        gst_color_balance_get_value (GST_COLOR_BALANCE (balance), channel));
+  }
+}
+
+static void
+gst_video_balance_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstVideoBalance *balance = GST_VIDEO_BALANCE (object);
+
+  switch (prop_id) {
+    case PROP_CONTRAST:
+      g_value_set_double (value, balance->contrast);
+      break;
+    case PROP_BRIGHTNESS:
+      g_value_set_double (value, balance->brightness);
+      break;
+    case PROP_HUE:
+      g_value_set_double (value, balance->hue);
+      break;
+    case PROP_SATURATION:
+      g_value_set_double (value, balance->saturation);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/gst/videofilter/gstvideobalance.h b/gst/videofilter/gstvideobalance.h
new file mode 100644
index 0000000..8b9f921
--- /dev/null
+++ b/gst/videofilter/gstvideobalance.h
@@ -0,0 +1,79 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_VIDEO_BALANCE_H__
+#define __GST_VIDEO_BALANCE_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VIDEO_BALANCE \
+  (gst_video_balance_get_type())
+#define GST_VIDEO_BALANCE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_BALANCE,GstVideoBalance))
+#define GST_VIDEO_BALANCE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_BALANCE,GstVideoBalanceClass))
+#define GST_IS_VIDEO_BALANCE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_BALANCE))
+#define GST_IS_VIDEO_BALANCE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_BALANCE))
+
+typedef struct _GstVideoBalance GstVideoBalance;
+typedef struct _GstVideoBalanceClass GstVideoBalanceClass;
+
+/**
+ * GstVideoBalance:
+ *
+ * Opaque data structure.
+ */
+struct _GstVideoBalance {
+  GstVideoFilter videofilter;
+
+  /* < private > */
+
+  /* channels for interface */
+  GList *channels;
+
+  /* properties */
+  gdouble contrast;
+  gdouble brightness;
+  gdouble hue;
+  gdouble saturation;
+
+  /* tables */
+  guint8 tabley[256];
+  guint8 *tableu[256];
+  guint8 *tablev[256];
+
+  void (*process) (GstVideoBalance *balance, GstVideoFrame *frame);
+};
+
+struct _GstVideoBalanceClass {
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_video_balance_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_VIDEO_BALANCE_H__ */
diff --git a/gst/videofilter/gstvideoflip.c b/gst/videofilter/gstvideoflip.c
new file mode 100644
index 0000000..c6132f5
--- /dev/null
+++ b/gst/videofilter/gstvideoflip.c
@@ -0,0 +1,1346 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ * Copyright (C) <2010> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ * Copyright (C) <2011> Youness Alaoui <youness.alaoui@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * This file was (probably) generated from gstvideoflip.c,
+ * gstvideoflip.c,v 1.7 2003/11/08 02:48:59 dschleef Exp 
+ */
+/**
+ * SECTION:element-videoflip
+ *
+ * Flips and rotates video.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 videotestsrc ! videoflip method=clockwise ! videoconvert ! ximagesink
+ * ]| This pipeline flips the test image 90 degrees clockwise.
+ * </refsect2>
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstvideoflip.h"
+
+#include <string.h>
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+/* GstVideoFlip properties */
+enum
+{
+  PROP_0,
+  PROP_METHOD,
+  PROP_VIDEO_DIRECTION
+      /* FILL ME */
+};
+
+#define PROP_METHOD_DEFAULT GST_VIDEO_FLIP_METHOD_IDENTITY
+
+GST_DEBUG_CATEGORY_STATIC (video_flip_debug);
+#define GST_CAT_DEFAULT video_flip_debug
+
+static GstStaticPadTemplate gst_video_flip_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, "
+            "ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, "
+            "RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21, "
+            "GRAY8, GRAY16_BE, GRAY16_LE }"))
+    );
+
+static GstStaticPadTemplate gst_video_flip_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, "
+            "ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, "
+            "RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21, "
+            "GRAY8, GRAY16_BE, GRAY16_LE }"))
+    );
+
+#define GST_TYPE_VIDEO_FLIP_METHOD (gst_video_flip_method_get_type())
+
+static const GEnumValue video_flip_methods[] = {
+  {GST_VIDEO_FLIP_METHOD_IDENTITY, "Identity (no rotation)", "none"},
+  {GST_VIDEO_FLIP_METHOD_90R, "Rotate clockwise 90 degrees", "clockwise"},
+  {GST_VIDEO_FLIP_METHOD_180, "Rotate 180 degrees", "rotate-180"},
+  {GST_VIDEO_FLIP_METHOD_90L, "Rotate counter-clockwise 90 degrees",
+      "counterclockwise"},
+  {GST_VIDEO_FLIP_METHOD_HORIZ, "Flip horizontally", "horizontal-flip"},
+  {GST_VIDEO_FLIP_METHOD_VERT, "Flip vertically", "vertical-flip"},
+  {GST_VIDEO_FLIP_METHOD_TRANS,
+      "Flip across upper left/lower right diagonal", "upper-left-diagonal"},
+  {GST_VIDEO_FLIP_METHOD_OTHER,
+      "Flip across upper right/lower left diagonal", "upper-right-diagonal"},
+  {GST_VIDEO_FLIP_METHOD_AUTO,
+      "Select flip method based on image-orientation tag", "automatic"},
+  {0, NULL, NULL},
+};
+
+static GType
+gst_video_flip_method_get_type (void)
+{
+  static GType video_flip_method_type = 0;
+
+  if (!video_flip_method_type) {
+    video_flip_method_type = g_enum_register_static ("GstVideoFlipMethod",
+        video_flip_methods);
+  }
+  return video_flip_method_type;
+}
+
+static void
+gst_video_flip_video_direction_interface_init (GstVideoDirectionInterface *
+    iface)
+{
+  /* We implement the video-direction property */
+}
+
+#define gst_video_flip_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstVideoFlip, gst_video_flip, GST_TYPE_VIDEO_FILTER,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_DIRECTION,
+        gst_video_flip_video_direction_interface_init));
+
+static GstCaps *
+gst_video_flip_transform_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
+{
+  GstVideoFlip *videoflip = GST_VIDEO_FLIP (trans);
+  GstCaps *ret;
+  gint width, height, i;
+
+  ret = gst_caps_copy (caps);
+
+  for (i = 0; i < gst_caps_get_size (ret); i++) {
+    GstStructure *structure = gst_caps_get_structure (ret, i);
+    gint par_n, par_d;
+
+    if (gst_structure_get_int (structure, "width", &width) &&
+        gst_structure_get_int (structure, "height", &height)) {
+
+      switch (videoflip->active_method) {
+        case GST_VIDEO_ORIENTATION_90R:
+        case GST_VIDEO_ORIENTATION_90L:
+        case GST_VIDEO_ORIENTATION_UL_LR:
+        case GST_VIDEO_ORIENTATION_UR_LL:
+          gst_structure_set (structure, "width", G_TYPE_INT, height,
+              "height", G_TYPE_INT, width, NULL);
+          if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
+                  &par_n, &par_d)) {
+            if (par_n != 1 || par_d != 1) {
+              GValue val = { 0, };
+
+              g_value_init (&val, GST_TYPE_FRACTION);
+              gst_value_set_fraction (&val, par_d, par_n);
+              gst_structure_set_value (structure, "pixel-aspect-ratio", &val);
+              g_value_unset (&val);
+            }
+          }
+          break;
+        case GST_VIDEO_ORIENTATION_IDENTITY:
+        case GST_VIDEO_ORIENTATION_180:
+        case GST_VIDEO_ORIENTATION_HORIZ:
+        case GST_VIDEO_ORIENTATION_VERT:
+          gst_structure_set (structure, "width", G_TYPE_INT, width,
+              "height", G_TYPE_INT, height, NULL);
+          break;
+        case GST_VIDEO_ORIENTATION_CUSTOM:
+          GST_WARNING_OBJECT (videoflip, "unsuported custom orientation");
+          break;
+        default:
+          g_assert_not_reached ();
+          break;
+      }
+    }
+  }
+
+  GST_DEBUG_OBJECT (videoflip, "transformed %" GST_PTR_FORMAT " to %"
+      GST_PTR_FORMAT, caps, ret);
+
+  if (filter) {
+    GstCaps *intersection;
+
+    GST_DEBUG_OBJECT (videoflip, "Using filter caps %" GST_PTR_FORMAT, filter);
+    intersection =
+        gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (ret);
+    ret = intersection;
+    GST_DEBUG_OBJECT (videoflip, "Intersection %" GST_PTR_FORMAT, ret);
+  }
+
+  return ret;
+}
+
+static void
+gst_video_flip_planar_yuv (GstVideoFlip * videoflip, GstVideoFrame * dest,
+    const GstVideoFrame * src)
+{
+  gint x, y;
+  guint8 const *s;
+  guint8 *d;
+  gint src_y_stride, src_u_stride, src_v_stride;
+  gint src_y_height, src_u_height, src_v_height;
+  gint src_y_width, src_u_width, src_v_width;
+  gint dest_y_stride, dest_u_stride, dest_v_stride;
+  gint dest_y_height, dest_u_height, dest_v_height;
+  gint dest_y_width, dest_u_width, dest_v_width;
+
+  src_y_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 0);
+  src_u_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 1);
+  src_v_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 2);
+
+  dest_y_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 0);
+  dest_u_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 1);
+  dest_v_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 2);
+
+  src_y_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 0);
+  src_u_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 1);
+  src_v_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 2);
+
+  dest_y_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 0);
+  dest_u_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 1);
+  dest_v_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 2);
+
+  src_y_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 0);
+  src_u_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 1);
+  src_v_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 2);
+
+  dest_y_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 0);
+  dest_u_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 1);
+  dest_v_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 2);
+
+  switch (videoflip->active_method) {
+    case GST_VIDEO_ORIENTATION_90R:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[(src_y_height - 1 - x) * src_y_stride + y];
+        }
+      }
+      /* Flip U */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_u_height; y++) {
+        for (x = 0; x < dest_u_width; x++) {
+          d[y * dest_u_stride + x] =
+              s[(src_u_height - 1 - x) * src_u_stride + y];
+        }
+      }
+      /* Flip V */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
+      for (y = 0; y < dest_v_height; y++) {
+        for (x = 0; x < dest_v_width; x++) {
+          d[y * dest_v_stride + x] =
+              s[(src_v_height - 1 - x) * src_v_stride + y];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_90L:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[x * src_y_stride + (src_y_width - 1 - y)];
+        }
+      }
+      /* Flip U */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_u_height; y++) {
+        for (x = 0; x < dest_u_width; x++) {
+          d[y * dest_u_stride + x] =
+              s[x * src_u_stride + (src_u_width - 1 - y)];
+        }
+      }
+      /* Flip V */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
+      for (y = 0; y < dest_v_height; y++) {
+        for (x = 0; x < dest_v_width; x++) {
+          d[y * dest_v_stride + x] =
+              s[x * src_v_stride + (src_v_width - 1 - y)];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_180:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[(src_y_height - 1 - y) * src_y_stride + (src_y_width - 1 - x)];
+        }
+      }
+      /* Flip U */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_u_height; y++) {
+        for (x = 0; x < dest_u_width; x++) {
+          d[y * dest_u_stride + x] =
+              s[(src_u_height - 1 - y) * src_u_stride + (src_u_width - 1 - x)];
+        }
+      }
+      /* Flip V */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
+      for (y = 0; y < dest_v_height; y++) {
+        for (x = 0; x < dest_v_width; x++) {
+          d[y * dest_v_stride + x] =
+              s[(src_v_height - 1 - y) * src_v_stride + (src_v_width - 1 - x)];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_HORIZ:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[y * src_y_stride + (src_y_width - 1 - x)];
+        }
+      }
+      /* Flip U */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_u_height; y++) {
+        for (x = 0; x < dest_u_width; x++) {
+          d[y * dest_u_stride + x] =
+              s[y * src_u_stride + (src_u_width - 1 - x)];
+        }
+      }
+      /* Flip V */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
+      for (y = 0; y < dest_v_height; y++) {
+        for (x = 0; x < dest_v_width; x++) {
+          d[y * dest_v_stride + x] =
+              s[y * src_v_stride + (src_v_width - 1 - x)];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_VERT:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[(src_y_height - 1 - y) * src_y_stride + x];
+        }
+      }
+      /* Flip U */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_u_height; y++) {
+        for (x = 0; x < dest_u_width; x++) {
+          d[y * dest_u_stride + x] =
+              s[(src_u_height - 1 - y) * src_u_stride + x];
+        }
+      }
+      /* Flip V */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
+      for (y = 0; y < dest_v_height; y++) {
+        for (x = 0; x < dest_v_width; x++) {
+          d[y * dest_v_stride + x] =
+              s[(src_v_height - 1 - y) * src_v_stride + x];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_UL_LR:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] = s[x * src_y_stride + y];
+        }
+      }
+      /* Flip U */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_u_height; y++) {
+        for (x = 0; x < dest_u_width; x++) {
+          d[y * dest_u_stride + x] = s[x * src_u_stride + y];
+        }
+      }
+      /* Flip V */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
+      for (y = 0; y < dest_u_height; y++) {
+        for (x = 0; x < dest_u_width; x++) {
+          d[y * dest_v_stride + x] = s[x * src_v_stride + y];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_UR_LL:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[(src_y_height - 1 - x) * src_y_stride + (src_y_width - 1 - y)];
+        }
+      }
+      /* Flip U */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_u_height; y++) {
+        for (x = 0; x < dest_u_width; x++) {
+          d[y * dest_u_stride + x] =
+              s[(src_u_height - 1 - x) * src_u_stride + (src_u_width - 1 - y)];
+        }
+      }
+      /* Flip V */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
+      for (y = 0; y < dest_v_height; y++) {
+        for (x = 0; x < dest_v_width; x++) {
+          d[y * dest_v_stride + x] =
+              s[(src_v_height - 1 - x) * src_v_stride + (src_v_width - 1 - y)];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_IDENTITY:
+      g_assert_not_reached ();
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+static void
+gst_video_flip_semi_planar_yuv (GstVideoFlip * videoflip, GstVideoFrame * dest,
+    const GstVideoFrame * src)
+{
+  gint x, y;
+  guint8 const *s;
+  guint8 *d;
+  gint s_off, d_off;
+  gint src_y_stride, src_uv_stride;
+  gint src_y_height, src_uv_height;
+  gint src_y_width, src_uv_width;
+  gint dest_y_stride, dest_uv_stride;
+  gint dest_y_height, dest_uv_height;
+  gint dest_y_width, dest_uv_width;
+
+
+  src_y_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 0);
+  src_uv_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 1);
+
+  dest_y_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 0);
+  dest_uv_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 1);
+
+  src_y_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 0);
+  src_uv_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 1);
+
+  dest_y_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 0);
+  dest_uv_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 1);
+
+  src_y_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 0);
+  src_uv_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 1);
+
+  dest_y_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 0);
+  dest_uv_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 1);
+
+  switch (videoflip->active_method) {
+    case GST_VIDEO_ORIENTATION_90R:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[(src_y_height - 1 - x) * src_y_stride + y];
+        }
+      }
+      /* Flip UV */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_uv_height; y++) {
+        for (x = 0; x < dest_uv_width; x++) {
+          d_off = y * dest_uv_stride + x * 2;
+          s_off = (src_uv_height - 1 - x) * src_uv_stride + y * 2;
+          d[d_off] = s[s_off];
+          d[d_off + 1] = s[s_off + 1];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_90L:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[x * src_y_stride + (src_y_width - 1 - y)];
+        }
+      }
+      /* Flip UV */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_uv_height; y++) {
+        for (x = 0; x < dest_uv_width; x++) {
+          d_off = y * dest_uv_stride + x * 2;
+          s_off = x * src_uv_stride + (src_uv_width - 1 - y) * 2;
+          d[d_off] = s[s_off];
+          d[d_off + 1] = s[s_off + 1];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_180:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[(src_y_height - 1 - y) * src_y_stride + (src_y_width - 1 - x)];
+        }
+      }
+      /* Flip UV */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_uv_height; y++) {
+        for (x = 0; x < dest_uv_width; x++) {
+          d_off = y * dest_uv_stride + x * 2;
+          s_off = (src_uv_height - 1 - y) * src_uv_stride + (src_uv_width - 1 -
+              x) * 2;
+          d[d_off] = s[s_off];
+          d[d_off + 1] = s[s_off + 1];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_HORIZ:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[y * src_y_stride + (src_y_width - 1 - x)];
+        }
+      }
+      /* Flip UV */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_uv_height; y++) {
+        for (x = 0; x < dest_uv_width; x++) {
+          d_off = y * dest_uv_stride + x * 2;
+          s_off = y * src_uv_stride + (src_uv_width - 1 - x) * 2;
+          d[d_off] = s[s_off];
+          d[d_off + 1] = s[s_off + 1];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_VERT:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[(src_y_height - 1 - y) * src_y_stride + x];
+        }
+      }
+      /* Flip UV */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_uv_height; y++) {
+        for (x = 0; x < dest_uv_width; x++) {
+          d_off = y * dest_uv_stride + x * 2;
+          s_off = (src_uv_height - 1 - y) * src_uv_stride + x * 2;
+          d[d_off] = s[s_off];
+          d[d_off + 1] = s[s_off + 1];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_UL_LR:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] = s[x * src_y_stride + y];
+        }
+      }
+      /* Flip UV */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_uv_height; y++) {
+        for (x = 0; x < dest_uv_width; x++) {
+          d_off = y * dest_uv_stride + x * 2;
+          s_off = x * src_uv_stride + y * 2;
+          d[d_off] = s[s_off];
+          d[d_off + 1] = s[s_off + 1];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_UR_LL:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[(src_y_height - 1 - x) * src_y_stride + (src_y_width - 1 - y)];
+        }
+      }
+      /* Flip UV */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_uv_height; y++) {
+        for (x = 0; x < dest_uv_width; x++) {
+          d_off = y * dest_uv_stride + x * 2;
+          s_off = (src_uv_height - 1 - x) * src_uv_stride + (src_uv_width - 1 -
+              y) * 2;
+          d[d_off] = s[s_off];
+          d[d_off + 1] = s[s_off + 1];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_IDENTITY:
+      g_assert_not_reached ();
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+static void
+gst_video_flip_packed_simple (GstVideoFlip * videoflip, GstVideoFrame * dest,
+    const GstVideoFrame * src)
+{
+  gint x, y, z;
+  guint8 const *s;
+  guint8 *d;
+  gint sw = GST_VIDEO_FRAME_WIDTH (src);
+  gint sh = GST_VIDEO_FRAME_HEIGHT (src);
+  gint dw = GST_VIDEO_FRAME_WIDTH (dest);
+  gint dh = GST_VIDEO_FRAME_HEIGHT (dest);
+  gint src_stride, dest_stride;
+  gint bpp;
+
+  s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+  d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+
+  src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 0);
+  dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 0);
+  /* This is only true for non-subsampled formats! */
+  bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (src, 0);
+
+  switch (videoflip->active_method) {
+    case GST_VIDEO_ORIENTATION_90R:
+      for (y = 0; y < dh; y++) {
+        for (x = 0; x < dw; x++) {
+          for (z = 0; z < bpp; z++) {
+            d[y * dest_stride + x * bpp + z] =
+                s[(sh - 1 - x) * src_stride + y * bpp + z];
+          }
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_90L:
+      for (y = 0; y < dh; y++) {
+        for (x = 0; x < dw; x++) {
+          for (z = 0; z < bpp; z++) {
+            d[y * dest_stride + x * bpp + z] =
+                s[x * src_stride + (sw - 1 - y) * bpp + z];
+          }
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_180:
+      for (y = 0; y < dh; y++) {
+        for (x = 0; x < dw; x++) {
+          for (z = 0; z < bpp; z++) {
+            d[y * dest_stride + x * bpp + z] =
+                s[(sh - 1 - y) * src_stride + (sw - 1 - x) * bpp + z];
+          }
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_HORIZ:
+      for (y = 0; y < dh; y++) {
+        for (x = 0; x < dw; x++) {
+          for (z = 0; z < bpp; z++) {
+            d[y * dest_stride + x * bpp + z] =
+                s[y * src_stride + (sw - 1 - x) * bpp + z];
+          }
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_VERT:
+      for (y = 0; y < dh; y++) {
+        for (x = 0; x < dw; x++) {
+          for (z = 0; z < bpp; z++) {
+            d[y * dest_stride + x * bpp + z] =
+                s[(sh - 1 - y) * src_stride + x * bpp + z];
+          }
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_UL_LR:
+      for (y = 0; y < dh; y++) {
+        for (x = 0; x < dw; x++) {
+          for (z = 0; z < bpp; z++) {
+            d[y * dest_stride + x * bpp + z] = s[x * src_stride + y * bpp + z];
+          }
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_UR_LL:
+      for (y = 0; y < dh; y++) {
+        for (x = 0; x < dw; x++) {
+          for (z = 0; z < bpp; z++) {
+            d[y * dest_stride + x * bpp + z] =
+                s[(sh - 1 - x) * src_stride + (sw - 1 - y) * bpp + z];
+          }
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_IDENTITY:
+      g_assert_not_reached ();
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+
+static void
+gst_video_flip_y422 (GstVideoFlip * videoflip, GstVideoFrame * dest,
+    const GstVideoFrame * src)
+{
+  gint x, y;
+  guint8 const *s;
+  guint8 *d;
+  gint sw = GST_VIDEO_FRAME_WIDTH (src);
+  gint sh = GST_VIDEO_FRAME_HEIGHT (src);
+  gint dw = GST_VIDEO_FRAME_WIDTH (dest);
+  gint dh = GST_VIDEO_FRAME_HEIGHT (dest);
+  gint src_stride, dest_stride;
+  gint bpp;
+  gint y_offset;
+  gint u_offset;
+  gint v_offset;
+  gint y_stride;
+
+  s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+  d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+
+  src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 0);
+  dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 0);
+
+  y_offset = GST_VIDEO_FRAME_COMP_OFFSET (src, 0);
+  u_offset = GST_VIDEO_FRAME_COMP_OFFSET (src, 1);
+  v_offset = GST_VIDEO_FRAME_COMP_OFFSET (src, 2);
+  y_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (src, 0);
+  bpp = y_stride;
+
+  switch (videoflip->active_method) {
+    case GST_VIDEO_ORIENTATION_90R:
+      for (y = 0; y < dh; y++) {
+        for (x = 0; x < dw; x += 2) {
+          guint8 u;
+          guint8 v;
+          /* u/v must be calculated using the offset of the even column */
+          gint even_y = (y & ~1);
+
+          u = s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset];
+          if (x + 1 < dw)
+            u = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]
+                + u) >> 1;
+          v = s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset];
+          if (x + 1 < dw)
+            v = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]
+                + v) >> 1;
+
+          d[y * dest_stride + x * bpp + u_offset] = u;
+          d[y * dest_stride + x * bpp + v_offset] = v;
+          d[y * dest_stride + x * bpp + y_offset] =
+              s[(sh - 1 - x) * src_stride + y * bpp + y_offset];
+          if (x + 1 < dw)
+            d[y * dest_stride + (x + 1) * bpp + y_offset] =
+                s[(sh - 1 - (x + 1)) * src_stride + y * bpp + y_offset];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_90L:
+      for (y = 0; y < dh; y++) {
+        for (x = 0; x < dw; x += 2) {
+          guint8 u;
+          guint8 v;
+          /* u/v must be calculated using the offset of the even column */
+          gint even_y = ((sw - 1 - y) & ~1);
+
+          u = s[x * src_stride + even_y * bpp + u_offset];
+          if (x + 1 < dw)
+            u = (s[(x + 1) * src_stride + even_y * bpp + u_offset] + u) >> 1;
+          v = s[x * src_stride + even_y * bpp + v_offset];
+          if (x + 1 < dw)
+            v = (s[(x + 1) * src_stride + even_y * bpp + v_offset] + v) >> 1;
+
+          d[y * dest_stride + x * bpp + u_offset] = u;
+          d[y * dest_stride + x * bpp + v_offset] = v;
+          d[y * dest_stride + x * bpp + y_offset] =
+              s[x * src_stride + (sw - 1 - y) * bpp + y_offset];
+          if (x + 1 < dw)
+            d[y * dest_stride + (x + 1) * bpp + y_offset] =
+                s[(x + 1) * src_stride + (sw - 1 - y) * bpp + y_offset];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_180:
+      for (y = 0; y < dh; y++) {
+        for (x = 0; x < dw; x += 2) {
+          guint8 u;
+          guint8 v;
+          /* u/v must be calculated using the offset of the even column */
+          gint even_x = ((sw - 1 - x) & ~1);
+
+          u = (s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset] +
+              s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset]) / 2;
+          v = (s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset] +
+              s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset]) / 2;
+
+          d[y * dest_stride + x * bpp + u_offset] = u;
+          d[y * dest_stride + x * bpp + v_offset] = v;
+          d[y * dest_stride + x * bpp + y_offset] =
+              s[(sh - 1 - y) * src_stride + (sw - 1 - x) * bpp + y_offset];
+          if (x + 1 < dw)
+            d[y * dest_stride + (x + 1) * bpp + y_offset] =
+                s[(sh - 1 - y) * src_stride + (sw - 1 - (x + 1)) * bpp +
+                y_offset];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_HORIZ:
+      for (y = 0; y < dh; y++) {
+        for (x = 0; x < dw; x += 2) {
+          guint8 u;
+          guint8 v;
+          /* u/v must be calculated using the offset of the even column */
+          gint even_x = ((sw - 1 - x) & ~1);
+
+          u = (s[y * src_stride + even_x * bpp + u_offset] +
+              s[y * src_stride + even_x * bpp + u_offset]) / 2;
+          v = (s[y * src_stride + even_x * bpp + v_offset] +
+              s[y * src_stride + even_x * bpp + v_offset]) / 2;
+
+          d[y * dest_stride + x * bpp + u_offset] = u;
+          d[y * dest_stride + x * bpp + v_offset] = v;
+          d[y * dest_stride + x * bpp + y_offset] =
+              s[y * src_stride + (sw - 1 - x) * bpp + y_offset];
+          if (x + 1 < dw)
+            d[y * dest_stride + (x + 1) * bpp + y_offset] =
+                s[y * src_stride + (sw - 1 - (x + 1)) * bpp + y_offset];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_VERT:
+      for (y = 0; y < dh; y++) {
+        for (x = 0; x < dw; x += 2) {
+          guint8 u;
+          guint8 v;
+          /* u/v must be calculated using the offset of the even column */
+          gint even_x = (x & ~1);
+
+          u = (s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset] +
+              s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset]) / 2;
+          v = (s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset] +
+              s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset]) / 2;
+
+          d[y * dest_stride + x * bpp + u_offset] = u;
+          d[y * dest_stride + x * bpp + v_offset] = v;
+          d[y * dest_stride + x * bpp + y_offset] =
+              s[(sh - 1 - y) * src_stride + x * bpp + y_offset];
+          if (x + 1 < dw)
+            d[y * dest_stride + (x + 1) * bpp + y_offset] =
+                s[(sh - 1 - y) * src_stride + (x + 1) * bpp + y_offset];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_UL_LR:
+      for (y = 0; y < dh; y++) {
+        for (x = 0; x < dw; x += 2) {
+          guint8 u;
+          guint8 v;
+          /* u/v must be calculated using the offset of the even column */
+          gint even_y = (y & ~1);
+
+          u = s[x * src_stride + even_y * bpp + u_offset];
+          if (x + 1 < dw)
+            u = (s[(x + 1) * src_stride + even_y * bpp + u_offset] + u) >> 1;
+          v = s[x * src_stride + even_y * bpp + v_offset];
+          if (x + 1 < dw)
+            v = (s[(x + 1) * src_stride + even_y * bpp + v_offset] + v) >> 1;
+
+          d[y * dest_stride + x * bpp + u_offset] = u;
+          d[y * dest_stride + x * bpp + v_offset] = v;
+          d[y * dest_stride + x * bpp + y_offset] =
+              s[x * src_stride + y * bpp + y_offset];
+          if (x + 1 < dw)
+            d[y * dest_stride + (x + 1) * bpp + y_offset] =
+                s[(x + 1) * src_stride + y * bpp + y_offset];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_UR_LL:
+      for (y = 0; y < dh; y++) {
+        for (x = 0; x < dw; x += 2) {
+          guint8 u;
+          guint8 v;
+          /* u/v must be calculated using the offset of the even column */
+          gint even_y = ((sw - 1 - y) & ~1);
+
+          u = s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset];
+          if (x + 1 < dw)
+            u = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]
+                + u) >> 1;
+          v = s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset];
+          if (x + 1 < dw)
+            v = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]
+                + v) >> 1;
+
+          d[y * dest_stride + x * bpp + u_offset] = u;
+          d[y * dest_stride + x * bpp + v_offset] = v;
+          d[y * dest_stride + x * bpp + y_offset] =
+              s[(sh - 1 - x) * src_stride + (sw - 1 - y) * bpp + y_offset];
+          if (x + 1 < dw)
+            d[y * dest_stride + (x + 1) * bpp + y_offset] =
+                s[(sh - 1 - (x + 1)) * src_stride + (sw - 1 - y) * bpp +
+                y_offset];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_IDENTITY:
+      g_assert_not_reached ();
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+
+static gboolean
+gst_video_flip_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstVideoFlip *vf = GST_VIDEO_FLIP (vfilter);
+  gboolean ret = FALSE;
+
+  vf->process = NULL;
+
+  if (GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_INFO_FORMAT (out_info))
+    goto invalid_caps;
+
+  /* Check that they are correct */
+  switch (vf->active_method) {
+    case GST_VIDEO_ORIENTATION_90R:
+    case GST_VIDEO_ORIENTATION_90L:
+    case GST_VIDEO_ORIENTATION_UL_LR:
+    case GST_VIDEO_ORIENTATION_UR_LL:
+      if ((in_info->width != out_info->height) ||
+          (in_info->height != out_info->width)) {
+        GST_ERROR_OBJECT (vf, "we are inverting width and height but caps "
+            "are not correct : %dx%d to %dx%d", in_info->width,
+            in_info->height, out_info->width, out_info->height);
+        goto beach;
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_IDENTITY:
+
+      break;
+    case GST_VIDEO_ORIENTATION_180:
+    case GST_VIDEO_ORIENTATION_HORIZ:
+    case GST_VIDEO_ORIENTATION_VERT:
+      if ((in_info->width != out_info->width) ||
+          (in_info->height != out_info->height)) {
+        GST_ERROR_OBJECT (vf, "we are keeping width and height but caps "
+            "are not correct : %dx%d to %dx%d", in_info->width,
+            in_info->height, out_info->width, out_info->height);
+        goto beach;
+      }
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+
+  ret = TRUE;
+
+  switch (GST_VIDEO_INFO_FORMAT (in_info)) {
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+    case GST_VIDEO_FORMAT_Y444:
+      vf->process = gst_video_flip_planar_yuv;
+      break;
+    case GST_VIDEO_FORMAT_YUY2:
+    case GST_VIDEO_FORMAT_UYVY:
+    case GST_VIDEO_FORMAT_YVYU:
+      vf->process = gst_video_flip_y422;
+      break;
+    case GST_VIDEO_FORMAT_AYUV:
+    case GST_VIDEO_FORMAT_ARGB:
+    case GST_VIDEO_FORMAT_ABGR:
+    case GST_VIDEO_FORMAT_RGBA:
+    case GST_VIDEO_FORMAT_BGRA:
+    case GST_VIDEO_FORMAT_xRGB:
+    case GST_VIDEO_FORMAT_xBGR:
+    case GST_VIDEO_FORMAT_RGBx:
+    case GST_VIDEO_FORMAT_BGRx:
+    case GST_VIDEO_FORMAT_RGB:
+    case GST_VIDEO_FORMAT_BGR:
+    case GST_VIDEO_FORMAT_GRAY8:
+    case GST_VIDEO_FORMAT_GRAY16_BE:
+    case GST_VIDEO_FORMAT_GRAY16_LE:
+      vf->process = gst_video_flip_packed_simple;
+      break;
+    case GST_VIDEO_FORMAT_NV12:
+    case GST_VIDEO_FORMAT_NV21:
+      vf->process = gst_video_flip_semi_planar_yuv;
+      break;
+    default:
+      break;
+  }
+
+beach:
+  return ret && (vf->process != NULL);
+
+invalid_caps:
+  GST_ERROR_OBJECT (vf, "Invalid caps: %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT,
+      incaps, outcaps);
+  return FALSE;
+}
+
+static void
+gst_video_flip_set_method (GstVideoFlip * videoflip,
+    GstVideoOrientationMethod method, gboolean from_tag)
+{
+  GST_OBJECT_LOCK (videoflip);
+
+  if (method == GST_VIDEO_ORIENTATION_CUSTOM) {
+    GST_WARNING_OBJECT (videoflip, "unsupported custom orientation");
+    GST_OBJECT_UNLOCK (videoflip);
+    return;
+  }
+
+  /* Store updated method */
+  if (from_tag)
+    videoflip->tag_method = method;
+  else
+    videoflip->method = method;
+
+  /* Get the new method */
+  if (videoflip->method == GST_VIDEO_ORIENTATION_AUTO)
+    method = videoflip->tag_method;
+  else
+    method = videoflip->method;
+
+  if (method != videoflip->active_method) {
+    GEnumValue *active_method_enum, *method_enum;
+    GstBaseTransform *btrans = GST_BASE_TRANSFORM (videoflip);
+    GEnumClass *enum_class =
+        g_type_class_ref (GST_TYPE_VIDEO_ORIENTATION_METHOD);
+
+    active_method_enum =
+        g_enum_get_value (enum_class, videoflip->active_method);
+    method_enum = g_enum_get_value (enum_class, method);
+    GST_DEBUG_OBJECT (videoflip, "Changing method from %s to %s",
+        active_method_enum ? active_method_enum->value_nick : "(nil)",
+        method_enum ? method_enum->value_nick : "(nil)");
+    g_type_class_unref (enum_class);
+
+    videoflip->active_method = method;
+
+    GST_OBJECT_UNLOCK (videoflip);
+
+    gst_base_transform_set_passthrough (btrans,
+        method == GST_VIDEO_ORIENTATION_IDENTITY);
+    gst_base_transform_reconfigure_src (btrans);
+  } else {
+    GST_OBJECT_UNLOCK (videoflip);
+  }
+}
+
+static void
+gst_video_flip_before_transform (GstBaseTransform * trans, GstBuffer * in)
+{
+  GstVideoFlip *videoflip = GST_VIDEO_FLIP (trans);
+  GstClockTime timestamp, stream_time;
+
+  timestamp = GST_BUFFER_TIMESTAMP (in);
+  stream_time =
+      gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, timestamp);
+
+  GST_DEBUG_OBJECT (videoflip, "sync to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (timestamp));
+
+  if (GST_CLOCK_TIME_IS_VALID (stream_time))
+    gst_object_sync_values (GST_OBJECT (videoflip), stream_time);
+}
+
+static GstFlowReturn
+gst_video_flip_transform_frame (GstVideoFilter * vfilter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame)
+{
+  GEnumClass *enum_class;
+  GEnumValue *active_method_enum;
+  GstVideoFlip *videoflip = GST_VIDEO_FLIP (vfilter);
+
+  if (G_UNLIKELY (videoflip->process == NULL))
+    goto not_negotiated;
+
+  enum_class = g_type_class_ref (GST_TYPE_VIDEO_ORIENTATION_METHOD);
+  active_method_enum = g_enum_get_value (enum_class, videoflip->active_method);
+  GST_LOG_OBJECT (videoflip, "videoflip: flipping (%s)",
+      active_method_enum ? active_method_enum->value_nick : "(nil)");
+  g_type_class_unref (enum_class);
+
+  GST_OBJECT_LOCK (videoflip);
+  videoflip->process (videoflip, out_frame, in_frame);
+  GST_OBJECT_UNLOCK (videoflip);
+
+  return GST_FLOW_OK;
+
+not_negotiated:
+  {
+    GST_ERROR_OBJECT (videoflip, "Not negotiated yet");
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+}
+
+static gboolean
+gst_video_flip_src_event (GstBaseTransform * trans, GstEvent * event)
+{
+  GstVideoFlip *vf = GST_VIDEO_FLIP (trans);
+  gdouble new_x, new_y, x, y;
+  GstStructure *structure;
+  gboolean ret;
+  GstVideoInfo *out_info = &GST_VIDEO_FILTER (trans)->out_info;
+
+  GST_DEBUG_OBJECT (vf, "handling %s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_NAVIGATION:
+      event =
+          GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event)));
+
+      structure = (GstStructure *) gst_event_get_structure (event);
+      if (gst_structure_get_double (structure, "pointer_x", &x) &&
+          gst_structure_get_double (structure, "pointer_y", &y)) {
+        GST_DEBUG_OBJECT (vf, "converting %fx%f", x, y);
+        switch (vf->active_method) {
+          case GST_VIDEO_ORIENTATION_90R:
+            new_x = y;
+            new_y = out_info->width - x;
+            break;
+          case GST_VIDEO_ORIENTATION_90L:
+            new_x = out_info->height - y;
+            new_y = x;
+            break;
+          case GST_VIDEO_ORIENTATION_UR_LL:
+            new_x = out_info->height - y;
+            new_y = out_info->width - x;
+            break;
+          case GST_VIDEO_ORIENTATION_UL_LR:
+            new_x = y;
+            new_y = x;
+            break;
+          case GST_VIDEO_ORIENTATION_180:
+            new_x = out_info->width - x;
+            new_y = out_info->height - y;
+            break;
+          case GST_VIDEO_ORIENTATION_HORIZ:
+            new_x = out_info->width - x;
+            new_y = y;
+            break;
+          case GST_VIDEO_ORIENTATION_VERT:
+            new_x = x;
+            new_y = out_info->height - y;
+            break;
+          default:
+            new_x = x;
+            new_y = y;
+            break;
+        }
+        GST_DEBUG_OBJECT (vf, "to %fx%f", new_x, new_y);
+        gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, new_x,
+            "pointer_y", G_TYPE_DOUBLE, new_y, NULL);
+      }
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event);
+
+  return ret;
+}
+
+static gboolean
+gst_video_flip_sink_event (GstBaseTransform * trans, GstEvent * event)
+{
+  GstVideoFlip *vf = GST_VIDEO_FLIP (trans);
+  GstTagList *taglist;
+  gchar *orientation;
+  gboolean ret;
+
+  GST_DEBUG_OBJECT (vf, "handling %s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_TAG:
+      gst_event_parse_tag (event, &taglist);
+
+      if (gst_tag_list_get_string (taglist, "image-orientation", &orientation)) {
+        if (!g_strcmp0 ("rotate-0", orientation))
+          gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_IDENTITY, TRUE);
+        else if (!g_strcmp0 ("rotate-90", orientation))
+          gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_90R, TRUE);
+        else if (!g_strcmp0 ("rotate-180", orientation))
+          gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_180, TRUE);
+        else if (!g_strcmp0 ("rotate-270", orientation))
+          gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_90L, TRUE);
+        else if (!g_strcmp0 ("flip-rotate-0", orientation))
+          gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_HORIZ, TRUE);
+        else if (!g_strcmp0 ("flip-rotate-90", orientation))
+          gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_UL_LR, TRUE);
+        else if (!g_strcmp0 ("flip-rotate-180", orientation))
+          gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_VERT, TRUE);
+        else if (!g_strcmp0 ("flip-rotate-270", orientation))
+          gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_UR_LL, TRUE);
+
+        g_free (orientation);
+      }
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
+
+  return ret;
+}
+
+static void
+gst_video_flip_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVideoFlip *videoflip = GST_VIDEO_FLIP (object);
+
+  switch (prop_id) {
+    case PROP_METHOD:
+    case PROP_VIDEO_DIRECTION:
+      gst_video_flip_set_method (videoflip, g_value_get_enum (value), FALSE);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_video_flip_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstVideoFlip *videoflip = GST_VIDEO_FLIP (object);
+
+  switch (prop_id) {
+    case PROP_METHOD:
+    case PROP_VIDEO_DIRECTION:
+      g_value_set_enum (value, videoflip->method);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_video_flip_class_init (GstVideoFlipClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (video_flip_debug, "videoflip", 0, "videoflip");
+
+  gobject_class->set_property = gst_video_flip_set_property;
+  gobject_class->get_property = gst_video_flip_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_METHOD,
+      g_param_spec_enum ("method", "method",
+          "method (deprecated, use video-direction instead)",
+          GST_TYPE_VIDEO_FLIP_METHOD, PROP_METHOD_DEFAULT,
+          GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
+          G_PARAM_STATIC_STRINGS));
+  g_object_class_override_property (gobject_class, PROP_VIDEO_DIRECTION,
+      "video-direction");
+
+  gst_element_class_set_static_metadata (gstelement_class, "Video flipper",
+      "Filter/Effect/Video",
+      "Flips and rotates video", "David Schleef <ds@schleef.org>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_video_flip_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_video_flip_src_template);
+
+  trans_class->transform_caps =
+      GST_DEBUG_FUNCPTR (gst_video_flip_transform_caps);
+  trans_class->before_transform =
+      GST_DEBUG_FUNCPTR (gst_video_flip_before_transform);
+  trans_class->src_event = GST_DEBUG_FUNCPTR (gst_video_flip_src_event);
+  trans_class->sink_event = GST_DEBUG_FUNCPTR (gst_video_flip_sink_event);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_video_flip_set_info);
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_video_flip_transform_frame);
+}
+
+static void
+gst_video_flip_init (GstVideoFlip * videoflip)
+{
+  /* AUTO is not valid for active method, this is just to ensure we setup the
+   * method in gst_video_flip_set_method() */
+  videoflip->active_method = GST_VIDEO_ORIENTATION_AUTO;
+}
diff --git a/gst/videofilter/gstvideoflip.h b/gst/videofilter/gstvideoflip.h
new file mode 100644
index 0000000..0fca8e9
--- /dev/null
+++ b/gst/videofilter/gstvideoflip.h
@@ -0,0 +1,92 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_VIDEO_FLIP_H__
+#define __GST_VIDEO_FLIP_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstVideoFlipMethod:
+ * @GST_VIDEO_FLIP_METHOD_IDENTITY: Identity (no rotation)
+ * @GST_VIDEO_FLIP_METHOD_90R: Rotate clockwise 90 degrees
+ * @GST_VIDEO_FLIP_METHOD_180: Rotate 180 degrees
+ * @GST_VIDEO_FLIP_METHOD_90L: Rotate counter-clockwise 90 degrees
+ * @GST_VIDEO_FLIP_METHOD_HORIZ: Flip horizontally
+ * @GST_VIDEO_FLIP_METHOD_VERT: Flip vertically
+ * @GST_VIDEO_FLIP_METHOD_TRANS: Flip across upper left/lower right diagonal
+ * @GST_VIDEO_FLIP_METHOD_OTHER: Flip across upper right/lower left diagonal
+ * @GST_VIDEO_FLIP_METHOD_AUTO: Select flip method based on image-orientation tag
+ *
+ * The different flip methods.
+ */
+typedef enum {
+  GST_VIDEO_FLIP_METHOD_IDENTITY,
+  GST_VIDEO_FLIP_METHOD_90R,
+  GST_VIDEO_FLIP_METHOD_180,
+  GST_VIDEO_FLIP_METHOD_90L,
+  GST_VIDEO_FLIP_METHOD_HORIZ,
+  GST_VIDEO_FLIP_METHOD_VERT,
+  GST_VIDEO_FLIP_METHOD_TRANS,
+  GST_VIDEO_FLIP_METHOD_OTHER,
+  GST_VIDEO_FLIP_METHOD_AUTO
+} GstVideoFlipMethod;
+
+#define GST_TYPE_VIDEO_FLIP \
+  (gst_video_flip_get_type())
+#define GST_VIDEO_FLIP(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_FLIP,GstVideoFlip))
+#define GST_VIDEO_FLIP_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_FLIP,GstVideoFlipClass))
+#define GST_IS_VIDEO_FLIP(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_FLIP))
+#define GST_IS_VIDEO_FLIP_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_FLIP))
+
+typedef struct _GstVideoFlip GstVideoFlip;
+typedef struct _GstVideoFlipClass GstVideoFlipClass;
+
+/**
+ * GstVideoFlip:
+ *
+ * Opaque datastructure.
+ */
+struct _GstVideoFlip {
+  GstVideoFilter videofilter;
+
+  /* < private > */
+  GstVideoOrientationMethod method;
+  GstVideoOrientationMethod tag_method;
+  GstVideoOrientationMethod active_method;
+  void (*process) (GstVideoFlip *videoflip, GstVideoFrame *dest, const GstVideoFrame *src);
+};
+
+struct _GstVideoFlipClass {
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_video_flip_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_VIDEO_FLIP_H__ */
diff --git a/gst/videofilter/gstvideomedian.c b/gst/videofilter/gstvideomedian.c
new file mode 100644
index 0000000..042cd23
--- /dev/null
+++ b/gst/videofilter/gstvideomedian.c
@@ -0,0 +1,323 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+#include "gstvideomedian.h"
+
+static GstStaticPadTemplate video_median_src_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ I420, YV12 }"))
+    );
+
+static GstStaticPadTemplate video_median_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ I420, YV12 }"))
+    );
+
+
+/* Median signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+#define DEFAULT_FILTERSIZE   5
+#define DEFAULT_LUM_ONLY     TRUE
+enum
+{
+  PROP_0,
+  PROP_FILTERSIZE,
+  PROP_LUM_ONLY
+};
+
+#define GST_TYPE_VIDEO_MEDIAN_SIZE (gst_video_median_size_get_type())
+
+static const GEnumValue video_median_sizes[] = {
+  {GST_VIDEO_MEDIAN_SIZE_5, "Median of 5 neighbour pixels", "5"},
+  {GST_VIDEO_MEDIAN_SIZE_9, "Median of 9 neighbour pixels", "9"},
+  {0, NULL, NULL},
+};
+
+static GType
+gst_video_median_size_get_type (void)
+{
+  static GType video_median_size_type = 0;
+
+  if (!video_median_size_type) {
+    video_median_size_type = g_enum_register_static ("GstVideoMedianSize",
+        video_median_sizes);
+  }
+  return video_median_size_type;
+}
+
+#define gst_video_median_parent_class parent_class
+G_DEFINE_TYPE (GstVideoMedian, gst_video_median, GST_TYPE_VIDEO_FILTER);
+
+static GstFlowReturn gst_video_median_transform_frame (GstVideoFilter * filter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame);
+
+static void gst_video_median_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_video_median_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void
+gst_video_median_class_init (GstVideoMedianClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstVideoFilterClass *vfilter_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  vfilter_class = (GstVideoFilterClass *) klass;
+
+  gobject_class->set_property = gst_video_median_set_property;
+  gobject_class->get_property = gst_video_median_get_property;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FILTERSIZE,
+      g_param_spec_enum ("filtersize", "Filtersize", "The size of the filter",
+          GST_TYPE_VIDEO_MEDIAN_SIZE, DEFAULT_FILTERSIZE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LUM_ONLY,
+      g_param_spec_boolean ("lum-only", "Lum Only", "Only apply filter on "
+          "luminance", DEFAULT_LUM_ONLY,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &video_median_sink_factory);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &video_median_src_factory);
+  gst_element_class_set_static_metadata (gstelement_class, "Median effect",
+      "Filter/Effect/Video", "Apply a median filter to an image",
+      "Wim Taymans <wim.taymans@gmail.com>");
+
+  vfilter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_video_median_transform_frame);
+}
+
+void
+gst_video_median_init (GstVideoMedian * median)
+{
+  median->filtersize = DEFAULT_FILTERSIZE;
+  median->lum_only = DEFAULT_LUM_ONLY;
+}
+
+#define PIX_SORT(a,b) { if ((a)>(b)) PIX_SWAP((a),(b)); }
+#define PIX_SWAP(a,b) { unsigned char temp=(a);(a)=(b);(b)=temp; }
+
+static void
+median_5 (guint8 * dest, gint dstride, const guint8 * src, gint sstride,
+    gint width, gint height)
+{
+  unsigned char p[5];
+  int i, j, k;
+
+  /* copy the top and bottom rows into the result array */
+  for (i = 0; i < width; i++) {
+    dest[i] = src[i];
+    dest[(height - 1) * dstride + i] = src[(height - 1) * sstride + i];
+  }
+
+  /* process the interior pixels */
+  for (k = 2; k < height; k++) {
+    dest += dstride;
+    src += sstride;
+
+    dest[0] = src[0];
+    for (j = 2, i = 1; j < width; j++, i++) {
+      p[0] = src[i - sstride];
+      p[1] = src[i - 1];
+      p[2] = src[i];
+      p[3] = src[i + 1];
+      p[4] = src[i + sstride];
+      PIX_SORT (p[0], p[1]);
+      PIX_SORT (p[3], p[4]);
+      PIX_SORT (p[0], p[3]);
+      PIX_SORT (p[1], p[4]);
+      PIX_SORT (p[1], p[2]);
+      PIX_SORT (p[2], p[3]);
+      PIX_SORT (p[1], p[2]);
+      dest[i] = p[2];
+    }
+    dest[i] = src[i];
+  }
+}
+
+static void
+median_9 (guint8 * dest, gint dstride, const guint8 * src, gint sstride,
+    gint width, gint height)
+{
+  unsigned char p[9];
+  int i, j, k;
+
+  /*copy the top and bottom rows into the result array */
+  for (i = 0; i < width; i++) {
+    dest[i] = src[i];
+    dest[(height - 1) * dstride + i] = src[(height - 1) * sstride + i];
+  }
+  /* process the interior pixels */
+  for (k = 2; k < height; k++) {
+    dest += dstride;
+    src += sstride;
+
+    dest[0] = src[0];
+    for (j = 2, i = 1; j < width; j++, i++) {
+      p[0] = src[i - sstride - 1];
+      p[1] = src[i - sstride];
+      p[2] = src[i - sstride + 1];
+      p[3] = src[i - 1];
+      p[4] = src[i];
+      p[5] = src[i + 1];
+      p[6] = src[i + sstride - 1];
+      p[7] = src[i + sstride];
+      p[8] = src[i + sstride + 1];
+      PIX_SORT (p[1], p[2]);
+      PIX_SORT (p[4], p[5]);
+      PIX_SORT (p[7], p[8]);
+      PIX_SORT (p[0], p[1]);
+      PIX_SORT (p[3], p[4]);
+      PIX_SORT (p[6], p[7]);
+      PIX_SORT (p[1], p[2]);
+      PIX_SORT (p[4], p[5]);
+      PIX_SORT (p[7], p[8]);
+      PIX_SORT (p[0], p[3]);
+      PIX_SORT (p[5], p[8]);
+      PIX_SORT (p[4], p[7]);
+      PIX_SORT (p[3], p[6]);
+      PIX_SORT (p[1], p[4]);
+      PIX_SORT (p[2], p[5]);
+      PIX_SORT (p[4], p[7]);
+      PIX_SORT (p[4], p[2]);
+      PIX_SORT (p[6], p[4]);
+      PIX_SORT (p[4], p[2]);
+      dest[i] = p[4];
+    }
+    dest[i] = src[i];
+  }
+}
+
+static GstFlowReturn
+gst_video_median_transform_frame (GstVideoFilter * filter,
+    GstVideoFrame * in_frame, GstVideoFrame * out_frame)
+{
+  GstVideoMedian *median = GST_VIDEO_MEDIAN (filter);
+
+  if (median->filtersize == 5) {
+    median_5 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0),
+        GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0),
+        GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0),
+        GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0),
+        GST_VIDEO_FRAME_WIDTH (in_frame), GST_VIDEO_FRAME_HEIGHT (in_frame));
+
+    if (median->lum_only) {
+      gst_video_frame_copy_plane (out_frame, in_frame, 1);
+      gst_video_frame_copy_plane (out_frame, in_frame, 2);
+    } else {
+      median_5 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 1),
+          GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 1),
+          GST_VIDEO_FRAME_PLANE_DATA (in_frame, 1),
+          GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 1),
+          GST_VIDEO_FRAME_WIDTH (in_frame) / 2,
+          GST_VIDEO_FRAME_HEIGHT (in_frame) / 2);
+      median_5 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 2),
+          GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 2),
+          GST_VIDEO_FRAME_PLANE_DATA (in_frame, 2),
+          GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 2),
+          GST_VIDEO_FRAME_WIDTH (in_frame) / 2,
+          GST_VIDEO_FRAME_HEIGHT (in_frame) / 2);
+    }
+  } else {
+    median_9 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0),
+        GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0),
+        GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0),
+        GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0),
+        GST_VIDEO_FRAME_WIDTH (in_frame), GST_VIDEO_FRAME_HEIGHT (in_frame));
+
+    if (median->lum_only) {
+      gst_video_frame_copy_plane (out_frame, in_frame, 1);
+      gst_video_frame_copy_plane (out_frame, in_frame, 2);
+    } else {
+      median_9 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 1),
+          GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 1),
+          GST_VIDEO_FRAME_PLANE_DATA (in_frame, 1),
+          GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 1),
+          GST_VIDEO_FRAME_WIDTH (in_frame) / 2,
+          GST_VIDEO_FRAME_HEIGHT (in_frame) / 2);
+      median_9 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 2),
+          GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 2),
+          GST_VIDEO_FRAME_PLANE_DATA (in_frame, 2),
+          GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 2),
+          GST_VIDEO_FRAME_WIDTH (in_frame) / 2,
+          GST_VIDEO_FRAME_HEIGHT (in_frame) / 2);
+    }
+  }
+
+  return GST_FLOW_OK;
+}
+
+static void
+gst_video_median_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVideoMedian *median;
+
+  median = GST_VIDEO_MEDIAN (object);
+
+  switch (prop_id) {
+    case PROP_FILTERSIZE:
+      median->filtersize = g_value_get_enum (value);
+      break;
+    case PROP_LUM_ONLY:
+      median->lum_only = g_value_get_boolean (value);
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_video_median_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstVideoMedian *median;
+
+  median = GST_VIDEO_MEDIAN (object);
+
+  switch (prop_id) {
+    case PROP_FILTERSIZE:
+      g_value_set_enum (value, median->filtersize);
+      break;
+    case PROP_LUM_ONLY:
+      g_value_set_boolean (value, median->lum_only);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/gst/videofilter/gstvideomedian.h b/gst/videofilter/gstvideomedian.h
new file mode 100644
index 0000000..0877672
--- /dev/null
+++ b/gst/videofilter/gstvideomedian.h
@@ -0,0 +1,66 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_VIDEO_MEDIAN_H__
+#define __GST_VIDEO_MEDIAN_H__
+
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VIDEO_MEDIAN \
+  (gst_video_median_get_type())
+#define GST_VIDEO_MEDIAN(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_MEDIAN,GstVideoMedian))
+#define GST_VIDEO_MEDIAN_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_MEDIAN,GstVideoMedianClass))
+#define GST_IS_VIDEO_MEDIAN(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_MEDIAN))
+#define GST_IS_VIDEO_MEDIAN_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_MEDIAN))
+
+typedef struct _GstVideoMedian GstVideoMedian;
+typedef struct _GstVideoMedianClass GstVideoMedianClass;
+
+typedef enum
+{
+  GST_VIDEO_MEDIAN_SIZE_5 = 5,
+  GST_VIDEO_MEDIAN_SIZE_9 = 9
+} GstVideoMedianSize;
+
+struct _GstVideoMedian {
+  GstVideoFilter parent;
+
+  GstVideoMedianSize filtersize;
+  gboolean lum_only;
+};
+
+struct _GstVideoMedianClass {
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_video_median_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_VIDEO_MEDIAN_H__ */
diff --git a/gst/videofilter/gstvideotemplate.c b/gst/videofilter/gstvideotemplate.c
new file mode 100644
index 0000000..660526a
--- /dev/null
+++ b/gst/videofilter/gstvideotemplate.c
@@ -0,0 +1,253 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * This file was (probably) generated from
+ * $Id$
+ * and
+ * MAKEFILTERVERSION
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gstvideofilter.h>
+#include <string.h>
+
+#define GST_TYPE_VIDEOTEMPLATE \
+  (gst_videotemplate_get_type())
+#define GST_VIDEOTEMPLATE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEOTEMPLATE,GstVideotemplate))
+#define GST_VIDEOTEMPLATE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEOTEMPLATE,GstVideotemplateClass))
+#define GST_IS_VIDEOTEMPLATE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEOTEMPLATE))
+#define GST_IS_VIDEOTEMPLATE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEOTEMPLATE))
+
+typedef struct _GstVideotemplate GstVideotemplate;
+typedef struct _GstVideotemplateClass GstVideotemplateClass;
+
+struct _GstVideotemplate
+{
+  GstVideofilter videofilter;
+
+};
+
+struct _GstVideotemplateClass
+{
+  GstVideofilterClass parent_class;
+};
+
+
+/* GstVideotemplate signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0
+      /* FILL ME */
+};
+
+static void gst_videotemplate_base_init (gpointer g_class);
+static void gst_videotemplate_class_init (gpointer g_class,
+    gpointer class_data);
+static void gst_videotemplate_init (GTypeInstance * instance, gpointer g_class);
+
+static void gst_videotemplate_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_videotemplate_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void gst_videotemplate_planar411 (GstVideofilter * videofilter,
+    void *dest, void *src);
+static void gst_videotemplate_setup (GstVideofilter * videofilter);
+
+GType
+gst_videotemplate_get_type (void)
+{
+  static GType videotemplate_type = 0;
+
+  if (!videotemplate_type) {
+    static const GTypeInfo videotemplate_info = {
+      sizeof (GstVideotemplateClass),
+      gst_videotemplate_base_init,
+      NULL,
+      gst_videotemplate_class_init,
+      NULL,
+      NULL,
+      sizeof (GstVideotemplate),
+      0,
+      gst_videotemplate_init,
+    };
+
+    videotemplate_type = g_type_register_static (GST_TYPE_VIDEOFILTER,
+        "GstVideotemplate", &videotemplate_info, 0);
+  }
+  return videotemplate_type;
+}
+
+static const GstVideofilterFormat gst_videotemplate_formats[] = {
+  {"I420", 12, gst_videotemplate_planar411,},
+};
+
+
+static void
+gst_videotemplate_base_init (gpointer g_class)
+{
+
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+  GstVideofilterClass *videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
+  int i;
+
+  gst_element_class_set_static_metadata (element_class, "Video filter template",
+      "Filter/Effect/Video",
+      "Template for a video filter", "David Schleef <ds@schleef.org>");
+
+  for (i = 0; i < G_N_ELEMENTS (gst_videotemplate_formats); i++) {
+    gst_videofilter_class_add_format (videofilter_class,
+        gst_videotemplate_formats + i);
+  }
+
+  gst_videofilter_class_add_pad_templates (GST_VIDEOFILTER_CLASS (g_class));
+}
+
+static void
+gst_videotemplate_class_init (gpointer g_class, gpointer class_data)
+{
+  GObjectClass *gobject_class;
+  GstVideofilterClass *videofilter_class;
+
+  gobject_class = G_OBJECT_CLASS (g_class);
+  videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
+
+#if 0
+  g_object_class_install_property (gobject_class, PROP_METHOD,
+      g_param_spec_enum ("method", "method", "method",
+          GST_TYPE_VIDEOTEMPLATE_METHOD, GST_VIDEOTEMPLATE_METHOD_1,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#endif
+
+  gobject_class->set_property = gst_videotemplate_set_property;
+  gobject_class->get_property = gst_videotemplate_get_property;
+
+  videofilter_class->setup = gst_videotemplate_setup;
+}
+
+static void
+gst_videotemplate_init (GTypeInstance * instance, gpointer g_class)
+{
+  GstVideotemplate *videotemplate = GST_VIDEOTEMPLATE (instance);
+  GstVideofilter *videofilter;
+
+  GST_DEBUG ("gst_videotemplate_init");
+
+  videofilter = GST_VIDEOFILTER (videotemplate);
+
+  /* do stuff */
+}
+
+static void
+gst_videotemplate_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVideotemplate *src;
+
+  g_return_if_fail (GST_IS_VIDEOTEMPLATE (object));
+  src = GST_VIDEOTEMPLATE (object);
+
+  GST_DEBUG ("gst_videotemplate_set_property");
+  switch (prop_id) {
+#if 0
+    case PROP_METHOD:
+      src->method = g_value_get_enum (value);
+      break;
+#endif
+    default:
+      break;
+  }
+}
+
+static void
+gst_videotemplate_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstVideotemplate *src;
+
+  g_return_if_fail (GST_IS_VIDEOTEMPLATE (object));
+  src = GST_VIDEOTEMPLATE (object);
+
+  switch (prop_id) {
+#if 0
+    case PROP_METHOD:
+      g_value_set_enum (value, src->method);
+      break;
+#endif
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "videotemplate", GST_RANK_NONE,
+      GST_TYPE_VIDEOTEMPLATE);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    videotemplate,
+    "Template for a video filter",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
+
+     static void gst_videotemplate_setup (GstVideofilter * videofilter)
+{
+  GstVideotemplate *videotemplate;
+
+  g_return_if_fail (GST_IS_VIDEOTEMPLATE (videofilter));
+  videotemplate = GST_VIDEOTEMPLATE (videofilter);
+
+  /* if any setup needs to be done, do it here */
+
+}
+
+static void
+gst_videotemplate_planar411 (GstVideofilter * videofilter,
+    void *dest, void *src)
+{
+  GstVideotemplate *videotemplate;
+  int width = gst_videofilter_get_input_width (videofilter);
+  int height = gst_videofilter_get_input_height (videofilter);
+
+  g_return_if_fail (GST_IS_VIDEOTEMPLATE (videofilter));
+  videotemplate = GST_VIDEOTEMPLATE (videofilter);
+
+  /* do something interesting here.  This simply copies the source
+   * to the destination. */
+  memcpy (dest, src, width * height + (width / 2) * (height / 2) * 2);
+}
diff --git a/gst/videofilter/make_filter b/gst/videofilter/make_filter
new file mode 100755
index 0000000..692d0d5
--- /dev/null
+++ b/gst/videofilter/make_filter
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+LANG=C
+export LANG
+LC_COLLATE=C
+export LC_COLLATE
+
+Template=$1;
+srcfile=$2;
+
+if test x"$1" = x ; then
+	echo "$0 Objectname [srcfile]\n";
+	echo "  creates gstobjectname.{c,h} implementing GstObjectname,\n";
+	echo "  subclassing GstVideofilter.\n";
+	exit 1;
+fi
+
+if test x"$2" = x ; then
+	srcfile="gstvideotemplate.c"
+fi
+
+id=`echo '$Id$' | sed \
+	-e 's/\$I[d]: \([^$]*\)\$/\1/g'`
+echo $id
+
+TEMPLATE=`echo $Template | tr [:lower:] [:upper:]`
+template=`echo $Template | tr [:upper:] [:lower:]`
+
+# remember to break up the Id: in the line below
+sed \
+	-e 's/gstvideotemplate\.c/SOURCEFILE/g' \
+	-e "s/Videotemplate/$Template/g" \
+	-e "s/videotemplate/$template/g" \
+	-e "s/VIDEOTEMPLATE/$TEMPLATE/g" \
+	-e 's/\$I[d]: \([^$]*\)\$/\1/g' \
+	-e 's/SOURCEFILE/gstvideotemplate\.c/g' \
+	-e "s%MAKEFILTERVERSION%$id%g" \
+	$srcfile >gst$template.c.tmp && mv gst$template.c.tmp gst$template.c
+
diff --git a/gst/videofilter/meson.build b/gst/videofilter/meson.build
new file mode 100644
index 0000000..8fac1d5
--- /dev/null
+++ b/gst/videofilter/meson.build
@@ -0,0 +1,16 @@
+vfilter_sources = [
+  'plugin.c',
+  'gstvideoflip.c',
+  'gstvideobalance.c',
+  'gstgamma.c',
+  'gstvideomedian.c',
+]
+
+gstvideofilter = library('gstvideofilter',
+  vfilter_sources,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstbase_dep, gstvideo_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/videofilter/plugin.c b/gst/videofilter/plugin.c
new file mode 100644
index 0000000..da736dc
--- /dev/null
+++ b/gst/videofilter/plugin.c
@@ -0,0 +1,47 @@
+/* GStreamer
+ * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "gstgamma.h"
+#include "gstvideoflip.h"
+#include "gstvideobalance.h"
+#include "gstvideomedian.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return (gst_element_register (plugin, "gamma", GST_RANK_NONE, GST_TYPE_GAMMA)
+      && gst_element_register (plugin, "videobalance", GST_RANK_NONE,
+          GST_TYPE_VIDEO_BALANCE)
+      && gst_element_register (plugin, "videoflip", GST_RANK_NONE,
+          GST_TYPE_VIDEO_FLIP)
+      && gst_element_register (plugin, "videomedian", GST_RANK_NONE,
+          GST_TYPE_VIDEO_MEDIAN));
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    videofilter,
+    "Video filters plugin",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/videomixer/Makefile.am b/gst/videomixer/Makefile.am
new file mode 100644
index 0000000..b10289a
--- /dev/null
+++ b/gst/videomixer/Makefile.am
@@ -0,0 +1,23 @@
+plugin_LTLIBRARIES = libgstvideomixer.la
+
+ORC_SOURCE=videomixerorc
+
+include $(top_srcdir)/common/orc.mak
+
+libgstvideomixer_la_SOURCES = \
+	blend.c \
+	videomixer2.c
+
+nodist_libgstvideomixer_la_SOURCES = $(ORC_NODIST_SOURCES)
+libgstvideomixer_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) $(GST_CFLAGS) $(ORC_CFLAGS)
+libgstvideomixer_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+	-lgstvideo-@GST_API_VERSION@ \
+	$(GST_BASE_LIBS) $(GST_LIBS) $(ORC_LIBS) $(LIBM)
+libgstvideomixer_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+# headers we need but don't want installed
+noinst_HEADERS = \
+	blend.h \
+	videomixer2.h \
+	videomixer2pad.h
diff --git a/gst/videomixer/README b/gst/videomixer/README
new file mode 100644
index 0000000..6794a48
--- /dev/null
+++ b/gst/videomixer/README
@@ -0,0 +1,27 @@
+Video Mixer
+-----------
+
+A generice video mixer, it blends the ayuv buffers from all pads onto 
+a new buffer. The new buffer has by default a checkerboard pattern but
+its color can be changed with a property.
+The mixer can mix streams with different framerates and video sizes. It
+uses the duration value of the buffer to schedule the rendering of the
+buffers. For streams with a different resoltion than the final output
+resolution one can specify the position of the top left corner where this
+image should be placed with the pad properties xpos and ypos.
+The overall alpha value of a stream can also be specified with a pad
+property.
+By default, the streams are blended in the order that the pads were 
+requested from the element. This can be overridden by changing the 
+zorder pad property of the stream, a stream with lower zorder gets
+drawn first.
+
+
+TODO
+----
+
+- really implement zorder
+- take I420 yuv as well
+- output AYUV if possible.
+- implement different blend modes, some code is already done
+- use filter caps on srcpad to decide on the final output size
diff --git a/gst/videomixer/blend.c b/gst/videomixer/blend.c
new file mode 100644
index 0000000..e13f925
--- /dev/null
+++ b/gst/videomixer/blend.c
@@ -0,0 +1,1061 @@
+/* 
+ * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
+ * Copyright (C) 2006 Mindfruit Bv.
+ *   Author: Sjoerd Simons <sjoerd@luon.net>
+ *   Author: Alex Ugarte <alexugarte@gmail.com>
+ * Copyright (C) 2009 Alex Ugarte <augarte@vicomtech.org>
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "blend.h"
+#include "videomixerorc.h"
+
+#include <string.h>
+
+#include <gst/video/video.h>
+
+#define BLEND(D,S,alpha) (((D) * (256 - (alpha)) + (S) * (alpha)) >> 8)
+
+GST_DEBUG_CATEGORY_STATIC (gst_videomixer_blend_debug);
+#define GST_CAT_DEFAULT gst_videomixer_blend_debug
+
+/* Below are the implementations of everything */
+
+/* A32 is for AYUV, ARGB and BGRA */
+#define BLEND_A32(name, method, LOOP)		\
+static void \
+method##_ ##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
+    gdouble src_alpha, GstVideoFrame * destframe) \
+{ \
+  guint s_alpha; \
+  gint src_stride, dest_stride; \
+  gint dest_width, dest_height; \
+  guint8 *src, *dest; \
+  gint src_width, src_height; \
+  \
+  src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
+  src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
+  src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 0); \
+  src_stride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
+  dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 0); \
+  dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
+  dest_width = GST_VIDEO_FRAME_COMP_WIDTH (destframe, 0); \
+  dest_height = GST_VIDEO_FRAME_COMP_HEIGHT (destframe, 0); \
+  \
+  s_alpha = CLAMP ((gint) (src_alpha * 256), 0, 256); \
+  \
+  /* If it's completely transparent... we just return */ \
+  if (G_UNLIKELY (s_alpha == 0)) \
+    return; \
+  \
+  /* adjust src pointers for negative sizes */ \
+  if (xpos < 0) { \
+    src += -xpos * 4; \
+    src_width -= -xpos; \
+    xpos = 0; \
+  } \
+  if (ypos < 0) { \
+    src += -ypos * src_stride; \
+    src_height -= -ypos; \
+    ypos = 0; \
+  } \
+  /* adjust width/height if the src is bigger than dest */ \
+  if (xpos + src_width > dest_width) { \
+    src_width = dest_width - xpos; \
+  } \
+  if (ypos + src_height > dest_height) { \
+    src_height = dest_height - ypos; \
+  } \
+  \
+  if (src_height > 0 && src_width > 0) { \
+    dest = dest + 4 * xpos + (ypos * dest_stride); \
+  \
+    LOOP (dest, src, src_height, src_width, src_stride, dest_stride, s_alpha); \
+  } \
+}
+
+#define BLEND_A32_LOOP(name, method)			\
+static inline void \
+_##method##_loop_##name (guint8 * dest, const guint8 * src, gint src_height, \
+    gint src_width, gint src_stride, gint dest_stride, guint s_alpha) \
+{ \
+  s_alpha = MIN (255, s_alpha); \
+  video_mixer_orc_##method##_##name (dest, dest_stride, src, src_stride, \
+      s_alpha, src_width, src_height); \
+}
+
+BLEND_A32_LOOP (argb, blend);
+BLEND_A32_LOOP (bgra, blend);
+BLEND_A32_LOOP (argb, overlay);
+BLEND_A32_LOOP (bgra, overlay);
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+BLEND_A32 (argb, blend, _blend_loop_argb);
+BLEND_A32 (bgra, blend, _blend_loop_bgra);
+BLEND_A32 (argb, overlay, _overlay_loop_argb);
+BLEND_A32 (bgra, overlay, _overlay_loop_bgra);
+#else
+BLEND_A32 (argb, blend, _blend_loop_bgra);
+BLEND_A32 (bgra, blend, _blend_loop_argb);
+BLEND_A32 (argb, overlay, _overlay_loop_bgra);
+BLEND_A32 (bgra, overlay, _overlay_loop_argb);
+#endif
+
+#define A32_CHECKER_C(name, RGB, A, C1, C2, C3) \
+static void \
+fill_checker_##name##_c (GstVideoFrame * frame) \
+{ \
+  gint i, j; \
+  gint val; \
+  static const gint tab[] = { 80, 160, 80, 160 }; \
+  gint width, height; \
+  guint8 *dest; \
+  \
+  dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
+  width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
+  height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
+  \
+  if (!RGB) { \
+    for (i = 0; i < height; i++) { \
+      for (j = 0; j < width; j++) { \
+        dest[A] = 0xff; \
+        dest[C1] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
+        dest[C2] = 128; \
+        dest[C3] = 128; \
+        dest += 4; \
+      } \
+    } \
+  } else { \
+    for (i = 0; i < height; i++) { \
+      for (j = 0; j < width; j++) { \
+        val = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
+        dest[A] = 0xFF; \
+        dest[C1] = val; \
+        dest[C2] = val; \
+        dest[C3] = val; \
+        dest += 4; \
+      } \
+    } \
+  } \
+}
+
+A32_CHECKER_C (argb, TRUE, 0, 1, 2, 3);
+A32_CHECKER_C (bgra, TRUE, 3, 2, 1, 0);
+A32_CHECKER_C (ayuv, FALSE, 0, 1, 2, 3);
+
+#define YUV_TO_R(Y,U,V) (CLAMP (1.164 * (Y - 16) + 1.596 * (V - 128), 0, 255))
+#define YUV_TO_G(Y,U,V) (CLAMP (1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128), 0, 255))
+#define YUV_TO_B(Y,U,V) (CLAMP (1.164 * (Y - 16) + 2.018 * (U - 128), 0, 255))
+
+#define A32_COLOR(name, RGB, A, C1, C2, C3) \
+static void \
+fill_color_##name (GstVideoFrame * frame, gint Y, gint U, gint V) \
+{ \
+  gint c1, c2, c3; \
+  guint32 val; \
+  gint width, height; \
+  guint8 *dest; \
+  \
+  dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
+  width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
+  height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
+  \
+  if (RGB) { \
+    c1 = YUV_TO_R (Y, U, V); \
+    c2 = YUV_TO_G (Y, U, V); \
+    c3 = YUV_TO_B (Y, U, V); \
+  } else { \
+    c1 = Y; \
+    c2 = U; \
+    c3 = V; \
+  } \
+  val = GUINT32_FROM_BE ((0xff << A) | (c1 << C1) | (c2 << C2) | (c3 << C3)); \
+  \
+  video_mixer_orc_splat_u32 ((guint32 *) dest, val, height * width); \
+}
+
+A32_COLOR (argb, TRUE, 24, 16, 8, 0);
+A32_COLOR (bgra, TRUE, 0, 8, 16, 24);
+A32_COLOR (abgr, TRUE, 24, 0, 8, 16);
+A32_COLOR (rgba, TRUE, 0, 24, 16, 8);
+A32_COLOR (ayuv, FALSE, 24, 16, 8, 0);
+
+/* Y444, Y42B, I420, YV12, Y41B */
+#define PLANAR_YUV_BLEND(format_name,format_enum,x_round,y_round,MEMCPY,BLENDLOOP) \
+inline static void \
+_blend_##format_name (const guint8 * src, guint8 * dest, \
+    gint src_stride, gint dest_stride, gint src_width, gint src_height, \
+    gdouble src_alpha) \
+{ \
+  gint i; \
+  gint b_alpha; \
+  \
+  /* If it's completely transparent... we just return */ \
+  if (G_UNLIKELY (src_alpha == 0.0)) { \
+    GST_INFO ("Fast copy (alpha == 0.0)"); \
+    return; \
+  } \
+  \
+  /* If it's completely opaque, we do a fast copy */ \
+  if (G_UNLIKELY (src_alpha == 1.0)) { \
+    GST_INFO ("Fast copy (alpha == 1.0)"); \
+    for (i = 0; i < src_height; i++) { \
+      MEMCPY (dest, src, src_width); \
+      src += src_stride; \
+      dest += dest_stride; \
+    } \
+    return; \
+  } \
+  \
+  b_alpha = CLAMP ((gint) (src_alpha * 256), 0, 256); \
+  \
+  BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width, src_height); \
+} \
+\
+static void \
+blend_##format_name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
+    gdouble src_alpha, GstVideoFrame * destframe) \
+{ \
+  const guint8 *b_src; \
+  guint8 *b_dest; \
+  gint b_src_width; \
+  gint b_src_height; \
+  gint xoffset = 0; \
+  gint yoffset = 0; \
+  gint src_comp_rowstride, dest_comp_rowstride; \
+  gint src_comp_height; \
+  gint src_comp_width; \
+  gint comp_ypos, comp_xpos; \
+  gint comp_yoffset, comp_xoffset; \
+  gint dest_width, dest_height; \
+  const GstVideoFormatInfo *info; \
+  gint src_width, src_height; \
+  \
+  src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
+  src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
+  \
+  info = srcframe->info.finfo; \
+  dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
+  dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
+  \
+  xpos = x_round (xpos); \
+  ypos = y_round (ypos); \
+  \
+  b_src_width = src_width; \
+  b_src_height = src_height; \
+  \
+  /* adjust src pointers for negative sizes */ \
+  if (xpos < 0) { \
+    xoffset = -xpos; \
+    b_src_width -= -xpos; \
+    xpos = 0; \
+  } \
+  if (ypos < 0) { \
+    yoffset = -ypos; \
+    b_src_height -= -ypos; \
+    ypos = 0; \
+  } \
+  /* If x or y offset are larger then the source it's outside of the picture */ \
+  if (xoffset >= src_width || yoffset >= src_height) { \
+    return; \
+  } \
+  \
+  /* adjust width/height if the src is bigger than dest */ \
+  if (xpos + b_src_width > dest_width) { \
+    b_src_width = dest_width - xpos; \
+  } \
+  if (ypos + b_src_height > dest_height) { \
+    b_src_height = dest_height - ypos; \
+  } \
+  if (b_src_width <= 0 || b_src_height <= 0) { \
+    return; \
+  } \
+  \
+  /* First mix Y, then U, then V */ \
+  b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 0); \
+  b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 0); \
+  src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
+  dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
+  src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 0, b_src_width); \
+  src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, b_src_height); \
+  comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xpos); \
+  comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, ypos); \
+  comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xoffset); \
+  comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, yoffset); \
+  _blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
+      b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
+      src_comp_rowstride, \
+      dest_comp_rowstride, src_comp_width, src_comp_height, \
+      src_alpha); \
+  \
+  b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 1); \
+  b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 1); \
+  src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 1); \
+  dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 1); \
+  src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 1, b_src_width); \
+  src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, b_src_height); \
+  comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xpos); \
+  comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 1, ypos); \
+  comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xoffset); \
+  comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 1, yoffset); \
+  _blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
+      b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
+      src_comp_rowstride, \
+      dest_comp_rowstride, src_comp_width, src_comp_height, \
+      src_alpha); \
+  \
+  b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 2); \
+  b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 2); \
+  src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 2); \
+  dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 2); \
+  src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 2, b_src_width); \
+  src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 2, b_src_height); \
+  comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 2, xpos); \
+  comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 2, ypos); \
+  comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 2, xoffset); \
+  comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 2, yoffset); \
+  _blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
+      b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
+      src_comp_rowstride, \
+      dest_comp_rowstride, src_comp_width, src_comp_height, \
+      src_alpha); \
+}
+
+#define PLANAR_YUV_FILL_CHECKER(format_name, format_enum, MEMSET) \
+static void \
+fill_checker_##format_name (GstVideoFrame * frame) \
+{ \
+  gint i, j; \
+  static const int tab[] = { 80, 160, 80, 160 }; \
+  guint8 *p; \
+  gint comp_width, comp_height; \
+  gint rowstride; \
+  \
+  p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
+  comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
+  comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
+  rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
+  \
+  for (i = 0; i < comp_height; i++) { \
+    for (j = 0; j < comp_width; j++) { \
+      *p++ = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
+    } \
+    p += rowstride - comp_width; \
+  } \
+  \
+  p = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
+  comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
+  comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1); \
+  rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
+  \
+  for (i = 0; i < comp_height; i++) { \
+    MEMSET (p, 0x80, comp_width); \
+    p += rowstride; \
+  } \
+  \
+  p = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
+  comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 2); \
+  comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 2); \
+  rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2); \
+  \
+  for (i = 0; i < comp_height; i++) { \
+    MEMSET (p, 0x80, comp_width); \
+    p += rowstride; \
+  } \
+}
+
+#define PLANAR_YUV_FILL_COLOR(format_name,format_enum,MEMSET) \
+static void \
+fill_color_##format_name (GstVideoFrame * frame, \
+    gint colY, gint colU, gint colV) \
+{ \
+  guint8 *p; \
+  gint comp_width, comp_height; \
+  gint rowstride; \
+  gint i; \
+  \
+  p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
+  comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
+  comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
+  rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
+  \
+  for (i = 0; i < comp_height; i++) { \
+    MEMSET (p, colY, comp_width); \
+    p += rowstride; \
+  } \
+  \
+  p = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
+  comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
+  comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1); \
+  rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
+  \
+  for (i = 0; i < comp_height; i++) { \
+    MEMSET (p, colU, comp_width); \
+    p += rowstride; \
+  } \
+  \
+  p = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
+  comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 2); \
+  comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 2); \
+  rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2); \
+  \
+  for (i = 0; i < comp_height; i++) { \
+    MEMSET (p, colV, comp_width); \
+    p += rowstride; \
+  } \
+}
+
+#define GST_ROUND_UP_1(x) (x)
+
+PLANAR_YUV_BLEND (i420, GST_VIDEO_FORMAT_I420, GST_ROUND_UP_2,
+    GST_ROUND_UP_2, memcpy, video_mixer_orc_blend_u8);
+PLANAR_YUV_FILL_CHECKER (i420, GST_VIDEO_FORMAT_I420, memset);
+PLANAR_YUV_FILL_COLOR (i420, GST_VIDEO_FORMAT_I420, memset);
+PLANAR_YUV_FILL_COLOR (yv12, GST_VIDEO_FORMAT_YV12, memset);
+PLANAR_YUV_BLEND (y444, GST_VIDEO_FORMAT_Y444, GST_ROUND_UP_1,
+    GST_ROUND_UP_1, memcpy, video_mixer_orc_blend_u8);
+PLANAR_YUV_FILL_CHECKER (y444, GST_VIDEO_FORMAT_Y444, memset);
+PLANAR_YUV_FILL_COLOR (y444, GST_VIDEO_FORMAT_Y444, memset);
+PLANAR_YUV_BLEND (y42b, GST_VIDEO_FORMAT_Y42B, GST_ROUND_UP_2,
+    GST_ROUND_UP_1, memcpy, video_mixer_orc_blend_u8);
+PLANAR_YUV_FILL_CHECKER (y42b, GST_VIDEO_FORMAT_Y42B, memset);
+PLANAR_YUV_FILL_COLOR (y42b, GST_VIDEO_FORMAT_Y42B, memset);
+PLANAR_YUV_BLEND (y41b, GST_VIDEO_FORMAT_Y41B, GST_ROUND_UP_4,
+    GST_ROUND_UP_1, memcpy, video_mixer_orc_blend_u8);
+PLANAR_YUV_FILL_CHECKER (y41b, GST_VIDEO_FORMAT_Y41B, memset);
+PLANAR_YUV_FILL_COLOR (y41b, GST_VIDEO_FORMAT_Y41B, memset);
+
+/* NV12, NV21 */
+#define NV_YUV_BLEND(format_name,MEMCPY,BLENDLOOP) \
+inline static void \
+_blend_##format_name (const guint8 * src, guint8 * dest, \
+    gint src_stride, gint dest_stride, gint src_width, gint src_height, \
+    gdouble src_alpha) \
+{ \
+  gint i; \
+  gint b_alpha; \
+  \
+  /* If it's completely transparent... we just return */ \
+  if (G_UNLIKELY (src_alpha == 0.0)) { \
+    GST_INFO ("Fast copy (alpha == 0.0)"); \
+    return; \
+  } \
+  \
+  /* If it's completely opaque, we do a fast copy */ \
+  if (G_UNLIKELY (src_alpha == 1.0)) { \
+    GST_INFO ("Fast copy (alpha == 1.0)"); \
+    for (i = 0; i < src_height; i++) { \
+      MEMCPY (dest, src, src_width); \
+      src += src_stride; \
+      dest += dest_stride; \
+    } \
+    return; \
+  } \
+  \
+  b_alpha = CLAMP ((gint) (src_alpha * 256), 0, 256); \
+  \
+  BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width, src_height); \
+} \
+\
+static void \
+blend_##format_name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
+    gdouble src_alpha, GstVideoFrame * destframe)                    \
+{ \
+  const guint8 *b_src; \
+  guint8 *b_dest; \
+  gint b_src_width; \
+  gint b_src_height; \
+  gint xoffset = 0; \
+  gint yoffset = 0; \
+  gint src_comp_rowstride, dest_comp_rowstride; \
+  gint src_comp_height; \
+  gint src_comp_width; \
+  gint comp_ypos, comp_xpos; \
+  gint comp_yoffset, comp_xoffset; \
+  gint dest_width, dest_height; \
+  const GstVideoFormatInfo *info; \
+  gint src_width, src_height; \
+  \
+  src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
+  src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
+  \
+  info = srcframe->info.finfo; \
+  dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
+  dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
+  \
+  xpos = GST_ROUND_UP_2 (xpos); \
+  ypos = GST_ROUND_UP_2 (ypos); \
+  \
+  b_src_width = src_width; \
+  b_src_height = src_height; \
+  \
+  /* adjust src pointers for negative sizes */ \
+  if (xpos < 0) { \
+    xoffset = -xpos; \
+    b_src_width -= -xpos; \
+    xpos = 0; \
+  } \
+  if (ypos < 0) { \
+    yoffset += -ypos; \
+    b_src_height -= -ypos; \
+    ypos = 0; \
+  } \
+  /* If x or y offset are larger then the source it's outside of the picture */ \
+  if (xoffset > src_width || yoffset > src_height) { \
+    return; \
+  } \
+  \
+  /* adjust width/height if the src is bigger than dest */ \
+  if (xpos + src_width > dest_width) { \
+    b_src_width = dest_width - xpos; \
+  } \
+  if (ypos + src_height > dest_height) { \
+    b_src_height = dest_height - ypos; \
+  } \
+  if (b_src_width < 0 || b_src_height < 0) { \
+    return; \
+  } \
+  \
+  /* First mix Y, then UV */ \
+  b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 0); \
+  b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 0); \
+  src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
+  dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
+  src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 0, b_src_width); \
+  src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, b_src_height); \
+  comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xpos); \
+  comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, ypos); \
+  comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xoffset); \
+  comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, yoffset); \
+  _blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
+      b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
+      src_comp_rowstride, \
+      dest_comp_rowstride, src_comp_width, src_comp_height, \
+      src_alpha); \
+  \
+  b_src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 1); \
+  b_dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 1); \
+  src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 1); \
+  dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 1); \
+  src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 1, b_src_width); \
+  src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, b_src_height); \
+  comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xpos); \
+  comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 1, ypos); \
+  comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xoffset); \
+  comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 1, yoffset); \
+  _blend_##format_name (b_src + comp_xoffset * 2 + comp_yoffset * src_comp_rowstride, \
+      b_dest + comp_xpos * 2 + comp_ypos * dest_comp_rowstride, \
+      src_comp_rowstride, \
+      dest_comp_rowstride, 2 * src_comp_width, src_comp_height, \
+      src_alpha); \
+}
+
+#define NV_YUV_FILL_CHECKER(format_name, MEMSET)        \
+static void \
+fill_checker_##format_name (GstVideoFrame * frame) \
+{ \
+  gint i, j; \
+  static const int tab[] = { 80, 160, 80, 160 }; \
+  guint8 *p; \
+  gint comp_width, comp_height; \
+  gint rowstride; \
+  \
+  p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
+  comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
+  comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
+  rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
+  \
+  for (i = 0; i < comp_height; i++) { \
+    for (j = 0; j < comp_width; j++) { \
+      *p++ = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
+    } \
+    p += rowstride - comp_width; \
+  } \
+  \
+  p = GST_VIDEO_FRAME_PLANE_DATA (frame, 1); \
+  comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
+  comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1); \
+  rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
+  \
+  for (i = 0; i < comp_height; i++) { \
+    MEMSET (p, 0x80, comp_width * 2); \
+    p += rowstride; \
+  } \
+}
+
+#define NV_YUV_FILL_COLOR(format_name,MEMSET) \
+static void \
+fill_color_##format_name (GstVideoFrame * frame, \
+    gint colY, gint colU, gint colV) \
+{ \
+  guint8 *y, *u, *v; \
+  gint comp_width, comp_height; \
+  gint rowstride; \
+  gint i, j; \
+  \
+  y = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
+  comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
+  comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
+  rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
+  \
+  for (i = 0; i < comp_height; i++) { \
+    MEMSET (y, colY, comp_width); \
+    y += rowstride; \
+  } \
+  \
+  u = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
+  v = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
+  comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
+  comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1); \
+  rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
+  \
+  for (i = 0; i < comp_height; i++) { \
+    for (j = 0; j < comp_width; j++) { \
+      u[j*2] = colU; \
+      v[j*2] = colV; \
+    } \
+    u += rowstride; \
+    v += rowstride; \
+  } \
+}
+
+NV_YUV_BLEND (nv12, memcpy, video_mixer_orc_blend_u8);
+NV_YUV_FILL_CHECKER (nv12, memset);
+NV_YUV_FILL_COLOR (nv12, memset);
+NV_YUV_BLEND (nv21, memcpy, video_mixer_orc_blend_u8);
+NV_YUV_FILL_CHECKER (nv21, memset);
+
+/* RGB, BGR, xRGB, xBGR, RGBx, BGRx */
+
+#define RGB_BLEND(name, bpp, MEMCPY, BLENDLOOP) \
+static void \
+blend_##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
+    gdouble src_alpha, GstVideoFrame * destframe) \
+{ \
+  gint b_alpha; \
+  gint i; \
+  gint src_stride, dest_stride; \
+  gint dest_width, dest_height; \
+  guint8 *dest, *src; \
+  gint src_width, src_height; \
+  \
+  src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
+  src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
+  \
+  src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 0); \
+  dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 0); \
+  \
+  dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
+  dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
+  \
+  src_stride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
+  dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
+  \
+  b_alpha = CLAMP ((gint) (src_alpha * 256), 0, 256); \
+  \
+  /* adjust src pointers for negative sizes */ \
+  if (xpos < 0) { \
+    src += -xpos * bpp; \
+    src_width -= -xpos; \
+    xpos = 0; \
+  } \
+  if (ypos < 0) { \
+    src += -ypos * src_stride; \
+    src_height -= -ypos; \
+    ypos = 0; \
+  } \
+  /* adjust width/height if the src is bigger than dest */ \
+  if (xpos + src_width > dest_width) { \
+    src_width = dest_width - xpos; \
+  } \
+  if (ypos + src_height > dest_height) { \
+    src_height = dest_height - ypos; \
+  } \
+  \
+  dest = dest + bpp * xpos + (ypos * dest_stride); \
+  /* If it's completely transparent... we just return */ \
+  if (G_UNLIKELY (src_alpha == 0.0)) { \
+    GST_INFO ("Fast copy (alpha == 0.0)"); \
+    return; \
+  } \
+  \
+  /* If it's completely opaque, we do a fast copy */ \
+  if (G_UNLIKELY (src_alpha == 1.0)) { \
+    GST_INFO ("Fast copy (alpha == 1.0)"); \
+    for (i = 0; i < src_height; i++) { \
+      MEMCPY (dest, src, bpp * src_width); \
+      src += src_stride; \
+      dest += dest_stride; \
+    } \
+    return; \
+  } \
+  \
+  BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width * bpp, src_height); \
+}
+
+#define RGB_FILL_CHECKER_C(name, bpp, r, g, b) \
+static void \
+fill_checker_##name##_c (GstVideoFrame * frame) \
+{ \
+  gint i, j; \
+  static const int tab[] = { 80, 160, 80, 160 }; \
+  gint stride, dest_add, width, height; \
+  guint8 *dest; \
+  \
+  width = GST_VIDEO_FRAME_WIDTH (frame); \
+  height = GST_VIDEO_FRAME_HEIGHT (frame); \
+  dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
+  stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
+  dest_add = stride - width * bpp; \
+  \
+  for (i = 0; i < height; i++) { \
+    for (j = 0; j < width; j++) { \
+      dest[r] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)];       /* red */ \
+      dest[g] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)];       /* green */ \
+      dest[b] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)];       /* blue */ \
+      dest += bpp; \
+    } \
+    dest += dest_add; \
+  } \
+}
+
+#define RGB_FILL_COLOR(name, bpp, MEMSET_RGB) \
+static void \
+fill_color_##name (GstVideoFrame * frame, \
+    gint colY, gint colU, gint colV) \
+{ \
+  gint red, green, blue; \
+  gint i; \
+  gint dest_stride; \
+  gint width, height; \
+  guint8 *dest; \
+  \
+  width = GST_VIDEO_FRAME_WIDTH (frame); \
+  height = GST_VIDEO_FRAME_HEIGHT (frame); \
+  dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
+  dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
+  \
+  red = YUV_TO_R (colY, colU, colV); \
+  green = YUV_TO_G (colY, colU, colV); \
+  blue = YUV_TO_B (colY, colU, colV); \
+  \
+  for (i = 0; i < height; i++) { \
+    MEMSET_RGB (dest, red, green, blue, width); \
+    dest += dest_stride; \
+  } \
+}
+
+#define MEMSET_RGB_C(name, r, g, b) \
+static inline void \
+_memset_##name##_c (guint8* dest, gint red, gint green, gint blue, gint width) { \
+  gint j; \
+  \
+  for (j = 0; j < width; j++) { \
+    dest[r] = red; \
+    dest[g] = green; \
+    dest[b] = blue; \
+    dest += 3; \
+  } \
+}
+
+#define MEMSET_XRGB(name, r, g, b) \
+static inline void \
+_memset_##name (guint8* dest, gint red, gint green, gint blue, gint width) { \
+  guint32 val; \
+  \
+  val = GUINT32_FROM_BE ((red << r) | (green << g) | (blue << b)); \
+  video_mixer_orc_splat_u32 ((guint32 *) dest, val, width); \
+}
+
+#define _orc_memcpy_u32(dest,src,len) video_mixer_orc_memcpy_u32((guint32 *) dest, (const guint32 *) src, len/4)
+
+RGB_BLEND (rgb, 3, memcpy, video_mixer_orc_blend_u8);
+RGB_FILL_CHECKER_C (rgb, 3, 0, 1, 2);
+MEMSET_RGB_C (rgb, 0, 1, 2);
+RGB_FILL_COLOR (rgb_c, 3, _memset_rgb_c);
+
+MEMSET_RGB_C (bgr, 2, 1, 0);
+RGB_FILL_COLOR (bgr_c, 3, _memset_bgr_c);
+
+RGB_BLEND (xrgb, 4, _orc_memcpy_u32, video_mixer_orc_blend_u8);
+RGB_FILL_CHECKER_C (xrgb, 4, 1, 2, 3);
+MEMSET_XRGB (xrgb, 24, 16, 0);
+RGB_FILL_COLOR (xrgb, 4, _memset_xrgb);
+
+MEMSET_XRGB (xbgr, 0, 16, 24);
+RGB_FILL_COLOR (xbgr, 4, _memset_xbgr);
+
+MEMSET_XRGB (rgbx, 24, 16, 8);
+RGB_FILL_COLOR (rgbx, 4, _memset_rgbx);
+
+MEMSET_XRGB (bgrx, 8, 16, 24);
+RGB_FILL_COLOR (bgrx, 4, _memset_bgrx);
+
+/* YUY2, YVYU, UYVY */
+
+#define PACKED_422_BLEND(name, MEMCPY, BLENDLOOP) \
+static void \
+blend_##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
+    gdouble src_alpha, GstVideoFrame * destframe) \
+{ \
+  gint b_alpha; \
+  gint i; \
+  gint src_stride, dest_stride; \
+  gint dest_width, dest_height; \
+  guint8 *src, *dest; \
+  gint src_width, src_height; \
+  \
+  src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
+  src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
+  \
+  dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
+  dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
+  \
+  src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 0); \
+  dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 0); \
+  \
+  src_stride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
+  dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
+  \
+  b_alpha = CLAMP ((gint) (src_alpha * 256), 0, 256); \
+  \
+  xpos = GST_ROUND_UP_2 (xpos); \
+  \
+  /* adjust src pointers for negative sizes */ \
+  if (xpos < 0) { \
+    src += -xpos * 2; \
+    src_width -= -xpos; \
+    xpos = 0; \
+  } \
+  if (ypos < 0) { \
+    src += -ypos * src_stride; \
+    src_height -= -ypos; \
+    ypos = 0; \
+  } \
+  \
+  /* adjust width/height if the src is bigger than dest */ \
+  if (xpos + src_width > dest_width) { \
+    src_width = dest_width - xpos; \
+  } \
+  if (ypos + src_height > dest_height) { \
+    src_height = dest_height - ypos; \
+  } \
+  \
+  dest = dest + 2 * xpos + (ypos * dest_stride); \
+  /* If it's completely transparent... we just return */ \
+  if (G_UNLIKELY (src_alpha == 0.0)) { \
+    GST_INFO ("Fast copy (alpha == 0.0)"); \
+    return; \
+  } \
+  \
+  /* If it's completely opaque, we do a fast copy */ \
+  if (G_UNLIKELY (src_alpha == 1.0)) { \
+    GST_INFO ("Fast copy (alpha == 1.0)"); \
+    for (i = 0; i < src_height; i++) { \
+      MEMCPY (dest, src, 2 * src_width); \
+      src += src_stride; \
+      dest += dest_stride; \
+    } \
+    return; \
+  } \
+  \
+  BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, 2 * src_width, src_height); \
+}
+
+#define PACKED_422_FILL_CHECKER_C(name, Y1, U, Y2, V) \
+static void \
+fill_checker_##name##_c (GstVideoFrame * frame) \
+{ \
+  gint i, j; \
+  static const int tab[] = { 80, 160, 80, 160 }; \
+  gint dest_add; \
+  gint width, height; \
+  guint8 *dest; \
+  \
+  width = GST_VIDEO_FRAME_WIDTH (frame); \
+  width = GST_ROUND_UP_2 (width); \
+  height = GST_VIDEO_FRAME_HEIGHT (frame); \
+  dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
+  dest_add = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) - width * 2; \
+  width /= 2; \
+  \
+  for (i = 0; i < height; i++) { \
+    for (j = 0; j < width; j++) { \
+      dest[Y1] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
+      dest[Y2] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
+      dest[U] = 128; \
+      dest[V] = 128; \
+      dest += 4; \
+    } \
+    dest += dest_add; \
+  } \
+}
+
+#define PACKED_422_FILL_COLOR(name, Y1, U, Y2, V) \
+static void \
+fill_color_##name (GstVideoFrame * frame, \
+    gint colY, gint colU, gint colV) \
+{ \
+  gint i; \
+  gint dest_stride; \
+  guint32 val; \
+  gint width, height; \
+  guint8 *dest; \
+  \
+  width = GST_VIDEO_FRAME_WIDTH (frame); \
+  width = GST_ROUND_UP_2 (width); \
+  height = GST_VIDEO_FRAME_HEIGHT (frame); \
+  dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
+  dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
+  width /= 2; \
+  \
+  val = GUINT32_FROM_BE ((colY << Y1) | (colY << Y2) | (colU << U) | (colV << V)); \
+  \
+  for (i = 0; i < height; i++) { \
+    video_mixer_orc_splat_u32 ((guint32 *) dest, val, width); \
+    dest += dest_stride; \
+  } \
+}
+
+PACKED_422_BLEND (yuy2, memcpy, video_mixer_orc_blend_u8);
+PACKED_422_FILL_CHECKER_C (yuy2, 0, 1, 2, 3);
+PACKED_422_FILL_CHECKER_C (uyvy, 1, 0, 3, 2);
+PACKED_422_FILL_COLOR (yuy2, 24, 16, 8, 0);
+PACKED_422_FILL_COLOR (yvyu, 24, 0, 8, 16);
+PACKED_422_FILL_COLOR (uyvy, 16, 24, 0, 8);
+
+/* Init function */
+BlendFunction gst_video_mixer_blend_argb;
+BlendFunction gst_video_mixer_blend_bgra;
+BlendFunction gst_video_mixer_overlay_argb;
+BlendFunction gst_video_mixer_overlay_bgra;
+/* AYUV/ABGR is equal to ARGB, RGBA is equal to BGRA */
+BlendFunction gst_video_mixer_blend_y444;
+BlendFunction gst_video_mixer_blend_y42b;
+BlendFunction gst_video_mixer_blend_i420;
+/* I420 is equal to YV12 */
+BlendFunction gst_video_mixer_blend_nv12;
+BlendFunction gst_video_mixer_blend_nv21;
+BlendFunction gst_video_mixer_blend_y41b;
+BlendFunction gst_video_mixer_blend_rgb;
+/* BGR is equal to RGB */
+BlendFunction gst_video_mixer_blend_rgbx;
+/* BGRx, xRGB, xBGR are equal to RGBx */
+BlendFunction gst_video_mixer_blend_yuy2;
+/* YVYU and UYVY are equal to YUY2 */
+
+FillCheckerFunction gst_video_mixer_fill_checker_argb;
+FillCheckerFunction gst_video_mixer_fill_checker_bgra;
+/* ABGR is equal to ARGB, RGBA is equal to BGRA */
+FillCheckerFunction gst_video_mixer_fill_checker_ayuv;
+FillCheckerFunction gst_video_mixer_fill_checker_y444;
+FillCheckerFunction gst_video_mixer_fill_checker_y42b;
+FillCheckerFunction gst_video_mixer_fill_checker_i420;
+/* I420 is equal to YV12 */
+FillCheckerFunction gst_video_mixer_fill_checker_nv12;
+FillCheckerFunction gst_video_mixer_fill_checker_nv21;
+FillCheckerFunction gst_video_mixer_fill_checker_y41b;
+FillCheckerFunction gst_video_mixer_fill_checker_rgb;
+/* BGR is equal to RGB */
+FillCheckerFunction gst_video_mixer_fill_checker_xrgb;
+/* BGRx, xRGB, xBGR are equal to RGBx */
+FillCheckerFunction gst_video_mixer_fill_checker_yuy2;
+/* YVYU is equal to YUY2 */
+FillCheckerFunction gst_video_mixer_fill_checker_uyvy;
+
+FillColorFunction gst_video_mixer_fill_color_argb;
+FillColorFunction gst_video_mixer_fill_color_bgra;
+FillColorFunction gst_video_mixer_fill_color_abgr;
+FillColorFunction gst_video_mixer_fill_color_rgba;
+FillColorFunction gst_video_mixer_fill_color_ayuv;
+FillColorFunction gst_video_mixer_fill_color_y444;
+FillColorFunction gst_video_mixer_fill_color_y42b;
+FillColorFunction gst_video_mixer_fill_color_i420;
+FillColorFunction gst_video_mixer_fill_color_yv12;
+FillColorFunction gst_video_mixer_fill_color_nv12;
+/* NV21 is equal to NV12 */
+FillColorFunction gst_video_mixer_fill_color_y41b;
+FillColorFunction gst_video_mixer_fill_color_rgb;
+FillColorFunction gst_video_mixer_fill_color_bgr;
+FillColorFunction gst_video_mixer_fill_color_xrgb;
+FillColorFunction gst_video_mixer_fill_color_xbgr;
+FillColorFunction gst_video_mixer_fill_color_rgbx;
+FillColorFunction gst_video_mixer_fill_color_bgrx;
+FillColorFunction gst_video_mixer_fill_color_yuy2;
+FillColorFunction gst_video_mixer_fill_color_yvyu;
+FillColorFunction gst_video_mixer_fill_color_uyvy;
+
+void
+gst_video_mixer_init_blend (void)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_videomixer_blend_debug, "videomixer_blend", 0,
+      "video mixer blending functions");
+
+  gst_video_mixer_blend_argb = blend_argb;
+  gst_video_mixer_blend_bgra = blend_bgra;
+  gst_video_mixer_overlay_argb = overlay_argb;
+  gst_video_mixer_overlay_bgra = overlay_bgra;
+  gst_video_mixer_blend_i420 = blend_i420;
+  gst_video_mixer_blend_nv12 = blend_nv12;
+  gst_video_mixer_blend_nv21 = blend_nv21;
+  gst_video_mixer_blend_y444 = blend_y444;
+  gst_video_mixer_blend_y42b = blend_y42b;
+  gst_video_mixer_blend_y41b = blend_y41b;
+  gst_video_mixer_blend_rgb = blend_rgb;
+  gst_video_mixer_blend_xrgb = blend_xrgb;
+  gst_video_mixer_blend_yuy2 = blend_yuy2;
+
+  gst_video_mixer_fill_checker_argb = fill_checker_argb_c;
+  gst_video_mixer_fill_checker_bgra = fill_checker_bgra_c;
+  gst_video_mixer_fill_checker_ayuv = fill_checker_ayuv_c;
+  gst_video_mixer_fill_checker_i420 = fill_checker_i420;
+  gst_video_mixer_fill_checker_nv12 = fill_checker_nv12;
+  gst_video_mixer_fill_checker_nv21 = fill_checker_nv21;
+  gst_video_mixer_fill_checker_y444 = fill_checker_y444;
+  gst_video_mixer_fill_checker_y42b = fill_checker_y42b;
+  gst_video_mixer_fill_checker_y41b = fill_checker_y41b;
+  gst_video_mixer_fill_checker_rgb = fill_checker_rgb_c;
+  gst_video_mixer_fill_checker_xrgb = fill_checker_xrgb_c;
+  gst_video_mixer_fill_checker_yuy2 = fill_checker_yuy2_c;
+  gst_video_mixer_fill_checker_uyvy = fill_checker_uyvy_c;
+
+  gst_video_mixer_fill_color_argb = fill_color_argb;
+  gst_video_mixer_fill_color_bgra = fill_color_bgra;
+  gst_video_mixer_fill_color_abgr = fill_color_abgr;
+  gst_video_mixer_fill_color_rgba = fill_color_rgba;
+  gst_video_mixer_fill_color_ayuv = fill_color_ayuv;
+  gst_video_mixer_fill_color_i420 = fill_color_i420;
+  gst_video_mixer_fill_color_yv12 = fill_color_yv12;
+  gst_video_mixer_fill_color_nv12 = fill_color_nv12;
+  gst_video_mixer_fill_color_y444 = fill_color_y444;
+  gst_video_mixer_fill_color_y42b = fill_color_y42b;
+  gst_video_mixer_fill_color_y41b = fill_color_y41b;
+  gst_video_mixer_fill_color_rgb = fill_color_rgb_c;
+  gst_video_mixer_fill_color_bgr = fill_color_bgr_c;
+  gst_video_mixer_fill_color_xrgb = fill_color_xrgb;
+  gst_video_mixer_fill_color_xbgr = fill_color_xbgr;
+  gst_video_mixer_fill_color_rgbx = fill_color_rgbx;
+  gst_video_mixer_fill_color_bgrx = fill_color_bgrx;
+  gst_video_mixer_fill_color_yuy2 = fill_color_yuy2;
+  gst_video_mixer_fill_color_yvyu = fill_color_yvyu;
+  gst_video_mixer_fill_color_uyvy = fill_color_uyvy;
+}
diff --git a/gst/videomixer/blend.h b/gst/videomixer/blend.h
new file mode 100644
index 0000000..7d16c56
--- /dev/null
+++ b/gst/videomixer/blend.h
@@ -0,0 +1,103 @@
+/* 
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLEND_H__
+#define __BLEND_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+typedef void (*BlendFunction) (GstVideoFrame *srcframe, gint xpos, gint ypos, gdouble src_alpha, GstVideoFrame * destframe);
+typedef void (*FillCheckerFunction) (GstVideoFrame * frame);
+typedef void (*FillColorFunction) (GstVideoFrame * frame, gint c1, gint c2, gint c3);
+
+extern BlendFunction gst_video_mixer_blend_argb;
+extern BlendFunction gst_video_mixer_blend_bgra;
+#define gst_video_mixer_blend_ayuv gst_video_mixer_blend_argb
+#define gst_video_mixer_blend_abgr gst_video_mixer_blend_argb
+#define gst_video_mixer_blend_rgba gst_video_mixer_blend_bgra
+extern BlendFunction gst_video_mixer_overlay_argb;
+extern BlendFunction gst_video_mixer_overlay_bgra;
+#define gst_video_mixer_overlay_ayuv gst_video_mixer_overlay_argb
+#define gst_video_mixer_overlay_abgr gst_video_mixer_overlay_argb
+#define gst_video_mixer_overlay_rgba gst_video_mixer_overlay_bgra
+extern BlendFunction gst_video_mixer_blend_i420;
+#define gst_video_mixer_blend_yv12 gst_video_mixer_blend_i420
+extern BlendFunction gst_video_mixer_blend_nv12;
+extern BlendFunction gst_video_mixer_blend_nv21;
+extern BlendFunction gst_video_mixer_blend_y41b;
+extern BlendFunction gst_video_mixer_blend_y42b;
+extern BlendFunction gst_video_mixer_blend_y444;
+extern BlendFunction gst_video_mixer_blend_rgb;
+#define gst_video_mixer_blend_bgr gst_video_mixer_blend_rgb
+extern BlendFunction gst_video_mixer_blend_rgbx;
+#define gst_video_mixer_blend_bgrx gst_video_mixer_blend_rgbx
+#define gst_video_mixer_blend_xrgb gst_video_mixer_blend_rgbx
+#define gst_video_mixer_blend_xbgr gst_video_mixer_blend_rgbx
+extern BlendFunction gst_video_mixer_blend_yuy2;
+#define gst_video_mixer_blend_uyvy gst_video_mixer_blend_yuy2;
+#define gst_video_mixer_blend_yvyu gst_video_mixer_blend_yuy2;
+
+extern FillCheckerFunction gst_video_mixer_fill_checker_argb;
+#define gst_video_mixer_fill_checker_abgr gst_video_mixer_fill_checker_argb
+extern FillCheckerFunction gst_video_mixer_fill_checker_bgra;
+#define gst_video_mixer_fill_checker_rgba gst_video_mixer_fill_checker_bgra
+extern FillCheckerFunction gst_video_mixer_fill_checker_ayuv;
+extern FillCheckerFunction gst_video_mixer_fill_checker_i420;
+#define gst_video_mixer_fill_checker_yv12 gst_video_mixer_fill_checker_i420
+extern FillCheckerFunction gst_video_mixer_fill_checker_nv12;
+extern FillCheckerFunction gst_video_mixer_fill_checker_nv21;
+extern FillCheckerFunction gst_video_mixer_fill_checker_y41b;
+extern FillCheckerFunction gst_video_mixer_fill_checker_y42b;
+extern FillCheckerFunction gst_video_mixer_fill_checker_y444;
+extern FillCheckerFunction gst_video_mixer_fill_checker_rgb;
+#define gst_video_mixer_fill_checker_bgr gst_video_mixer_fill_checker_rgb
+extern FillCheckerFunction gst_video_mixer_fill_checker_rgbx;
+#define gst_video_mixer_fill_checker_bgrx gst_video_mixer_fill_checker_rgbx
+#define gst_video_mixer_fill_checker_xrgb gst_video_mixer_fill_checker_rgbx
+#define gst_video_mixer_fill_checker_xbgr gst_video_mixer_fill_checker_rgbx
+extern FillCheckerFunction gst_video_mixer_fill_checker_yuy2;
+#define gst_video_mixer_fill_checker_yvyu gst_video_mixer_fill_checker_yuy2;
+extern FillCheckerFunction gst_video_mixer_fill_checker_uyvy;
+
+extern FillColorFunction gst_video_mixer_fill_color_argb;
+extern FillColorFunction gst_video_mixer_fill_color_abgr;
+extern FillColorFunction gst_video_mixer_fill_color_bgra;
+extern FillColorFunction gst_video_mixer_fill_color_rgba;
+extern FillColorFunction gst_video_mixer_fill_color_ayuv;
+extern FillColorFunction gst_video_mixer_fill_color_i420;
+extern FillColorFunction gst_video_mixer_fill_color_yv12;
+extern FillColorFunction gst_video_mixer_fill_color_nv12;
+#define gst_video_mixer_fill_color_nv21 gst_video_mixer_fill_color_nv12;
+extern FillColorFunction gst_video_mixer_fill_color_y41b;
+extern FillColorFunction gst_video_mixer_fill_color_y42b;
+extern FillColorFunction gst_video_mixer_fill_color_y444;
+extern FillColorFunction gst_video_mixer_fill_color_rgb;
+extern FillColorFunction gst_video_mixer_fill_color_bgr;
+extern FillColorFunction gst_video_mixer_fill_color_xrgb;
+extern FillColorFunction gst_video_mixer_fill_color_xbgr;
+extern FillColorFunction gst_video_mixer_fill_color_rgbx;
+extern FillColorFunction gst_video_mixer_fill_color_bgrx;
+extern FillColorFunction gst_video_mixer_fill_color_yuy2;
+extern FillColorFunction gst_video_mixer_fill_color_yvyu;
+extern FillColorFunction gst_video_mixer_fill_color_uyvy;
+
+void gst_video_mixer_init_blend (void);
+
+#endif /* __BLEND_H__ */
diff --git a/gst/videomixer/meson.build b/gst/videomixer/meson.build
new file mode 100644
index 0000000..1425a43
--- /dev/null
+++ b/gst/videomixer/meson.build
@@ -0,0 +1,32 @@
+vmixer_sources = [
+  'blend.c',
+  'videomixer2.c',
+]
+
+orcsrc = 'videomixerorc'
+if have_orcc
+  orc_h = custom_target(orcsrc + '.h',
+    input : orcsrc + '.orc',
+    output : orcsrc + '.h',
+    command : orcc_args + ['--header', '-o', '@OUTPUT@', '@INPUT@'])
+  orc_c = custom_target(orcsrc + '.c',
+    input : orcsrc + '.orc',
+    output : orcsrc + '.c',
+    command : orcc_args + ['--implementation', '-o', '@OUTPUT@', '@INPUT@'])
+else
+  orc_h = configure_file(input : orcsrc + '-dist.h',
+    output : orcsrc + '.h',
+    configuration : configuration_data())
+  orc_c = configure_file(input : orcsrc + '-dist.c',
+    output : orcsrc + '.c',
+    configuration : configuration_data())
+endif
+
+gstvideomixer = library('gstvideomixer',
+  vmixer_sources, orc_c, orc_h,
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [orc_dep, gstvideo_dep, gstbase_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/videomixer/videomixer2.c b/gst/videomixer/videomixer2.c
new file mode 100644
index 0000000..c6f2da8
--- /dev/null
+++ b/gst/videomixer/videomixer2.c
@@ -0,0 +1,2291 @@
+/* Generic video mixer plugin
+ * Copyright (C) 2004, 2008 Wim Taymans <wim@fluendo.com>
+ * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-videomixer
+ *
+ * Videomixer can accept AYUV, ARGB and BGRA video streams. For each of the requested
+ * sink pads it will compare the incoming geometry and framerate to define the
+ * output parameters. Indeed output video frames will have the geometry of the
+ * biggest incoming video stream and the framerate of the fastest incoming one.
+ *
+ * Videomixer will do colorspace conversion.
+ * 
+ * Individual parameters for each input stream can be configured on the
+ * #GstVideoMixer2Pad.
+ *
+ * <refsect2>
+ * <title>Sample pipelines</title>
+ * |[
+ * gst-launch-1.0 \
+ *   videotestsrc pattern=1 ! \
+ *   video/x-raw,format=AYUV,framerate=\(fraction\)10/1,width=100,height=100 ! \
+ *   videobox border-alpha=0 top=-70 bottom=-70 right=-220 ! \
+ *   videomixer name=mix sink_0::alpha=0.7 sink_1::alpha=0.5 ! \
+ *   videoconvert ! xvimagesink \
+ *   videotestsrc ! \
+ *   video/x-raw,format=AYUV,framerate=\(fraction\)5/1,width=320,height=240 ! mix.
+ * ]| A pipeline to demonstrate videomixer used together with videobox.
+ * This should show a 320x240 pixels video test source with some transparency
+ * showing the background checker pattern. Another video test source with just
+ * the snow pattern of 100x100 pixels is overlaid on top of the first one on
+ * the left vertically centered with a small transparency showing the first
+ * video test source behind and the checker pattern under it. Note that the
+ * framerate of the output video is 10 frames per second.
+ * |[
+ * gst-launch-1.0 videotestsrc pattern=1 ! \
+ *   video/x-raw, framerate=\(fraction\)10/1, width=100, height=100 ! \
+ *   videomixer name=mix ! videoconvert ! ximagesink \
+ *   videotestsrc !  \
+ *   video/x-raw, framerate=\(fraction\)5/1, width=320, height=240 ! mix.
+ * ]| A pipeline to demostrate bgra mixing. (This does not demonstrate alpha blending). 
+ * |[
+ * gst-launch-1.0 videotestsrc pattern=1 ! \
+ *   video/x-raw,format =I420, framerate=\(fraction\)10/1, width=100, height=100 ! \
+ *   videomixer name=mix ! videoconvert ! ximagesink \
+ *   videotestsrc ! \
+ *   video/x-raw,format=I420, framerate=\(fraction\)5/1, width=320, height=240 ! mix.
+ * ]| A pipeline to test I420
+ * |[
+ * gst-launch-1.0 videomixer name=mixer sink_1::alpha=0.5 sink_1::xpos=50 sink_1::ypos=50 ! \
+ *   videoconvert ! ximagesink \
+ *   videotestsrc pattern=snow timestamp-offset=3000000000 ! \
+ *   "video/x-raw,format=AYUV,width=640,height=480,framerate=(fraction)30/1" ! \
+ *   timeoverlay ! queue2 ! mixer. \
+ *   videotestsrc pattern=smpte ! \
+ *   "video/x-raw,format=AYUV,width=800,height=600,framerate=(fraction)10/1" ! \
+ *   timeoverlay ! queue2 ! mixer.
+ * ]| A pipeline to demonstrate synchronized mixing (the second stream starts after 3 seconds)
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "videomixer2.h"
+#include "videomixer2pad.h"
+
+#ifdef DISABLE_ORC
+#define orc_memset memset
+#else
+#include <orc/orcfunctions.h>
+#endif
+
+GST_DEBUG_CATEGORY_STATIC (gst_videomixer2_debug);
+#define GST_CAT_DEFAULT gst_videomixer2_debug
+
+#define GST_VIDEO_MIXER2_GET_LOCK(mix) \
+  (&GST_VIDEO_MIXER2(mix)->lock)
+#define GST_VIDEO_MIXER2_LOCK(mix) \
+  (g_mutex_lock(GST_VIDEO_MIXER2_GET_LOCK (mix)))
+#define GST_VIDEO_MIXER2_UNLOCK(mix) \
+  (g_mutex_unlock(GST_VIDEO_MIXER2_GET_LOCK (mix)))
+#define GST_VIDEO_MIXER2_GET_SETCAPS_LOCK(mix) \
+  (&GST_VIDEO_MIXER2(mix)->setcaps_lock)
+#define GST_VIDEO_MIXER2_SETCAPS_LOCK(mix) \
+  (g_mutex_lock(GST_VIDEO_MIXER2_GET_SETCAPS_LOCK (mix)))
+#define GST_VIDEO_MIXER2_SETCAPS_UNLOCK(mix) \
+  (g_mutex_unlock(GST_VIDEO_MIXER2_GET_SETCAPS_LOCK (mix)))
+
+#define FORMATS " { AYUV, BGRA, ARGB, RGBA, ABGR, Y444, Y42B, YUY2, UYVY, "\
+                "   YVYU, I420, YV12, NV12, NV21, Y41B, RGB, BGR, xRGB, xBGR, "\
+                "   RGBx, BGRx } "
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (FORMATS))
+    );
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (FORMATS))
+    );
+
+static void gst_videomixer2_child_proxy_init (gpointer g_iface,
+    gpointer iface_data);
+static gboolean gst_videomixer2_push_sink_event (GstVideoMixer2 * mix,
+    GstEvent * event);
+static void gst_videomixer2_release_pad (GstElement * element, GstPad * pad);
+static void gst_videomixer2_reset_qos (GstVideoMixer2 * mix);
+
+struct _GstVideoMixer2Collect
+{
+  GstCollectData collect;       /* we extend the CollectData */
+
+  GstVideoMixer2Pad *mixpad;
+
+  GstBuffer *queued;            /* buffer for which we don't know the end time yet */
+  GstVideoInfo queued_vinfo;
+
+  GstBuffer *buffer;            /* buffer that should be blended now */
+  GstVideoInfo buffer_vinfo;
+
+  GstClockTime start_time;
+  GstClockTime end_time;
+};
+
+#define DEFAULT_PAD_ZORDER 0
+#define DEFAULT_PAD_XPOS   0
+#define DEFAULT_PAD_YPOS   0
+#define DEFAULT_PAD_ALPHA  1.0
+enum
+{
+  PROP_PAD_0,
+  PROP_PAD_ZORDER,
+  PROP_PAD_XPOS,
+  PROP_PAD_YPOS,
+  PROP_PAD_ALPHA
+};
+
+G_DEFINE_TYPE (GstVideoMixer2Pad, gst_videomixer2_pad, GST_TYPE_PAD);
+
+static void
+gst_videomixer2_collect_free (GstCollectData * data)
+{
+  GstVideoMixer2Collect *cdata = (GstVideoMixer2Collect *) data;
+
+  gst_buffer_replace (&cdata->buffer, NULL);
+}
+
+static gboolean gst_videomixer2_src_setcaps (GstPad * pad, GstVideoMixer2 * mix,
+    GstCaps * caps);
+
+static gboolean
+gst_videomixer2_update_src_caps (GstVideoMixer2 * mix)
+{
+  GSList *l;
+  gint best_width = -1, best_height = -1;
+  gdouble best_fps = -1, cur_fps;
+  gint best_fps_n = -1, best_fps_d = -1;
+  gboolean ret = TRUE;
+
+  GST_VIDEO_MIXER2_SETCAPS_LOCK (mix);
+  GST_VIDEO_MIXER2_LOCK (mix);
+
+  for (l = mix->sinkpads; l; l = l->next) {
+    GstVideoMixer2Pad *mpad = l->data;
+    gint this_width, this_height;
+    gint fps_n, fps_d;
+    gint width, height;
+
+    fps_n = GST_VIDEO_INFO_FPS_N (&mpad->info);
+    fps_d = GST_VIDEO_INFO_FPS_D (&mpad->info);
+    width = GST_VIDEO_INFO_WIDTH (&mpad->info);
+    height = GST_VIDEO_INFO_HEIGHT (&mpad->info);
+
+    if (width == 0 || height == 0)
+      continue;
+
+    this_width = width + MAX (mpad->xpos, 0);
+    this_height = height + MAX (mpad->ypos, 0);
+
+    if (best_width < this_width)
+      best_width = this_width;
+    if (best_height < this_height)
+      best_height = this_height;
+
+    if (fps_d == 0)
+      cur_fps = 0.0;
+    else
+      gst_util_fraction_to_double (fps_n, fps_d, &cur_fps);
+
+    if (best_fps < cur_fps) {
+      best_fps = cur_fps;
+      best_fps_n = fps_n;
+      best_fps_d = fps_d;
+    }
+  }
+
+  if (best_fps_n <= 0 || best_fps_d <= 0 || best_fps == 0.0) {
+    best_fps_n = 25;
+    best_fps_d = 1;
+    best_fps = 25.0;
+  }
+
+  if (best_width > 0 && best_height > 0 && best_fps > 0) {
+    GstCaps *caps, *peercaps;
+    GstStructure *s;
+    GstVideoInfo info;
+
+    if (GST_VIDEO_INFO_FPS_N (&mix->info) != best_fps_n ||
+        GST_VIDEO_INFO_FPS_D (&mix->info) != best_fps_d) {
+      if (mix->segment.position != -1) {
+        mix->ts_offset = mix->segment.position - mix->segment.start;
+        mix->nframes = 0;
+      }
+    }
+    gst_video_info_init (&info);
+    gst_video_info_set_format (&info, GST_VIDEO_INFO_FORMAT (&mix->info),
+        best_width, best_height);
+    info.fps_n = best_fps_n;
+    info.fps_d = best_fps_d;
+    info.par_n = GST_VIDEO_INFO_PAR_N (&mix->info);
+    info.par_d = GST_VIDEO_INFO_PAR_D (&mix->info);
+
+    caps = gst_video_info_to_caps (&info);
+
+    peercaps = gst_pad_peer_query_caps (mix->srcpad, NULL);
+    if (peercaps && !gst_caps_can_intersect (peercaps, caps)) {
+      GstCaps *tmp;
+
+      s = gst_caps_get_structure (caps, 0);
+      gst_structure_set (s, "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, "height",
+          GST_TYPE_INT_RANGE, 1, G_MAXINT, "framerate", GST_TYPE_FRACTION_RANGE,
+          0, 1, G_MAXINT, 1, NULL);
+
+      tmp = gst_caps_intersect (caps, peercaps);
+      gst_caps_unref (caps);
+      gst_caps_unref (peercaps);
+      caps = tmp;
+      if (gst_caps_is_empty (caps)) {
+        GST_DEBUG_OBJECT (mix, "empty caps");
+        ret = FALSE;
+        GST_VIDEO_MIXER2_UNLOCK (mix);
+        goto done;
+      }
+
+      caps = gst_caps_truncate (caps);
+      s = gst_caps_get_structure (caps, 0);
+      gst_structure_fixate_field_nearest_int (s, "width", best_width);
+      gst_structure_fixate_field_nearest_int (s, "height", best_height);
+      gst_structure_fixate_field_nearest_fraction (s, "framerate", best_fps_n,
+          best_fps_d);
+
+      gst_structure_get_int (s, "width", &info.width);
+      gst_structure_get_int (s, "height", &info.height);
+      gst_structure_get_fraction (s, "fraction", &info.fps_n, &info.fps_d);
+    }
+
+    gst_caps_unref (caps);
+    caps = gst_video_info_to_caps (&info);
+
+    GST_VIDEO_MIXER2_UNLOCK (mix);
+    ret = gst_videomixer2_src_setcaps (mix->srcpad, mix, caps);
+    gst_caps_unref (caps);
+  } else {
+    GST_VIDEO_MIXER2_UNLOCK (mix);
+  }
+
+done:
+  GST_VIDEO_MIXER2_SETCAPS_UNLOCK (mix);
+
+  return ret;
+}
+
+static gboolean
+gst_videomixer2_update_converters (GstVideoMixer2 * mix)
+{
+  GSList *tmp;
+  GstVideoFormat best_format;
+  GstVideoInfo best_info;
+  GstVideoMixer2Pad *pad;
+  gboolean need_alpha = FALSE;
+  gboolean at_least_one_alpha = FALSE;
+  GstCaps *downstream_caps;
+  GstCaps *possible_caps;
+  gchar *best_colorimetry;
+  const gchar *best_chroma;
+  GHashTable *formats_table;
+  gint best_format_number = 0;
+
+  best_format = GST_VIDEO_FORMAT_UNKNOWN;
+  gst_video_info_init (&best_info);
+
+  downstream_caps = gst_pad_get_allowed_caps (mix->srcpad);
+
+  if (!downstream_caps || gst_caps_is_empty (downstream_caps)) {
+    if (downstream_caps)
+      gst_caps_unref (downstream_caps);
+    return FALSE;
+  }
+
+  formats_table = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  /* first find new preferred format */
+  for (tmp = mix->sinkpads; tmp; tmp = tmp->next) {
+    GstStructure *s;
+    gint format_number;
+
+    pad = tmp->data;
+
+    if (!pad->info.finfo)
+      continue;
+
+    if (pad->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA)
+      at_least_one_alpha = TRUE;
+
+    /* If we want alpha, disregard all the other formats */
+    if (need_alpha && !(pad->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA))
+      continue;
+
+    /* This can happen if we release a pad and another pad hasn't been negotiated yet */
+    if (GST_VIDEO_INFO_FORMAT (&pad->info) == GST_VIDEO_FORMAT_UNKNOWN)
+      continue;
+
+    possible_caps = gst_video_info_to_caps (&pad->info);
+
+    s = gst_caps_get_structure (possible_caps, 0);
+    gst_structure_remove_fields (s, "width", "height", "framerate",
+        "pixel-aspect-ratio", "interlace-mode", NULL);
+
+    /* Can downstream accept this format ? */
+    if (!gst_caps_can_intersect (downstream_caps, possible_caps)) {
+      gst_caps_unref (possible_caps);
+      continue;
+    }
+
+    gst_caps_unref (possible_caps);
+
+    format_number =
+        GPOINTER_TO_INT (g_hash_table_lookup (formats_table,
+            GINT_TO_POINTER (GST_VIDEO_INFO_FORMAT (&pad->info))));
+    format_number += 1;
+
+    g_hash_table_replace (formats_table,
+        GINT_TO_POINTER (GST_VIDEO_INFO_FORMAT (&pad->info)),
+        GINT_TO_POINTER (format_number));
+
+    /* If that pad is the first with alpha, set it as the new best format */
+    if (!need_alpha && (pad->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA)) {
+      need_alpha = TRUE;
+      best_format = GST_VIDEO_INFO_FORMAT (&pad->info);
+      best_info = pad->info;
+      best_format_number = format_number;
+    } else if (format_number > best_format_number) {
+      best_format = GST_VIDEO_INFO_FORMAT (&pad->info);
+      best_info = pad->info;
+      best_format_number = format_number;
+    }
+  }
+
+  g_hash_table_unref (formats_table);
+
+  if (best_format == GST_VIDEO_FORMAT_UNKNOWN) {
+    downstream_caps = gst_caps_fixate (downstream_caps);
+    gst_video_info_from_caps (&best_info, downstream_caps);
+    best_format = GST_VIDEO_INFO_FORMAT (&best_info);
+  }
+
+  gst_caps_unref (downstream_caps);
+
+  if (at_least_one_alpha
+      && !(best_info.finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA)) {
+    GST_ELEMENT_ERROR (mix, CORE, NEGOTIATION,
+        ("At least one of the input pads contains alpha, but downstream can't support alpha."),
+        ("Either convert your inputs to not contain alpha or add a videoconvert after the mixer"));
+    return FALSE;
+  }
+
+  best_colorimetry = gst_video_colorimetry_to_string (&(best_info.colorimetry));
+  best_chroma = gst_video_chroma_to_string (best_info.chroma_site);
+
+  if (GST_VIDEO_INFO_FPS_N (&mix->info) != GST_VIDEO_INFO_FPS_N (&best_info) ||
+      GST_VIDEO_INFO_FPS_D (&mix->info) != GST_VIDEO_INFO_FPS_D (&best_info)) {
+    if (mix->segment.position != -1) {
+      mix->ts_offset = mix->segment.position - mix->segment.start;
+      mix->nframes = 0;
+    } else {
+      mix->ts_offset += gst_util_uint64_scale_round (mix->nframes,
+          GST_SECOND * GST_VIDEO_INFO_FPS_D (&mix->info),
+          GST_VIDEO_INFO_FPS_N (&mix->info));
+      mix->nframes = 0;
+    }
+  }
+
+  mix->info = best_info;
+
+  GST_DEBUG_OBJECT (mix,
+      "The output format will now be : %d with colorimetry : %s and chroma : %s",
+      best_format, best_colorimetry, best_chroma);
+
+  /* Then browse the sinks once more, setting or unsetting conversion if needed */
+  for (tmp = mix->sinkpads; tmp; tmp = tmp->next) {
+    gchar *colorimetry;
+    const gchar *chroma;
+
+    pad = tmp->data;
+
+    if (!pad->info.finfo)
+      continue;
+
+    if (GST_VIDEO_INFO_FORMAT (&pad->info) == GST_VIDEO_FORMAT_UNKNOWN)
+      continue;
+
+    if (pad->convert)
+      gst_video_converter_free (pad->convert);
+
+    pad->convert = NULL;
+
+    colorimetry = gst_video_colorimetry_to_string (&(pad->info.colorimetry));
+    chroma = gst_video_chroma_to_string (pad->info.chroma_site);
+
+    if (best_format != GST_VIDEO_INFO_FORMAT (&pad->info) ||
+        g_strcmp0 (colorimetry, best_colorimetry) ||
+        g_strcmp0 (chroma, best_chroma)) {
+      GstVideoInfo tmp_info = pad->info;
+      tmp_info.finfo = best_info.finfo;
+      tmp_info.chroma_site = best_info.chroma_site;
+      tmp_info.colorimetry = best_info.colorimetry;
+
+      GST_DEBUG_OBJECT (pad, "This pad will be converted from %d to %d",
+          GST_VIDEO_INFO_FORMAT (&pad->info),
+          GST_VIDEO_INFO_FORMAT (&best_info));
+      pad->convert = gst_video_converter_new (&pad->info, &tmp_info, NULL);
+      pad->need_conversion_update = TRUE;
+      if (!pad->convert) {
+        g_free (colorimetry);
+        g_free (best_colorimetry);
+        GST_WARNING ("No path found for conversion");
+        return FALSE;
+      }
+    } else {
+      GST_DEBUG_OBJECT (pad, "This pad will not need conversion");
+    }
+    g_free (colorimetry);
+  }
+
+  g_free (best_colorimetry);
+  return TRUE;
+}
+
+static gboolean
+gst_videomixer2_pad_sink_setcaps (GstPad * pad, GstObject * parent,
+    GstCaps * caps)
+{
+  GstVideoMixer2 *mix;
+  GstVideoMixer2Pad *mixpad;
+  GstVideoInfo info;
+  gboolean ret = FALSE;
+
+  GST_INFO_OBJECT (pad, "Setting caps %" GST_PTR_FORMAT, caps);
+
+  mix = GST_VIDEO_MIXER2 (parent);
+  mixpad = GST_VIDEO_MIXER2_PAD (pad);
+
+  if (!gst_video_info_from_caps (&info, caps)) {
+    GST_ERROR_OBJECT (pad, "Failed to parse caps");
+    goto beach;
+  }
+
+  GST_VIDEO_MIXER2_LOCK (mix);
+  if (GST_VIDEO_INFO_FORMAT (&mix->info) != GST_VIDEO_FORMAT_UNKNOWN) {
+    if (GST_VIDEO_INFO_PAR_N (&mix->info) != GST_VIDEO_INFO_PAR_N (&info)
+        || GST_VIDEO_INFO_PAR_D (&mix->info) != GST_VIDEO_INFO_PAR_D (&info) ||
+        GST_VIDEO_INFO_INTERLACE_MODE (&mix->info) !=
+        GST_VIDEO_INFO_INTERLACE_MODE (&info)) {
+      GST_DEBUG_OBJECT (pad,
+          "got input caps %" GST_PTR_FORMAT ", but " "current caps are %"
+          GST_PTR_FORMAT, caps, mix->current_caps);
+      GST_VIDEO_MIXER2_UNLOCK (mix);
+      return FALSE;
+    }
+  }
+
+  mixpad->info = info;
+
+  GST_COLLECT_PADS_STREAM_LOCK (mix->collect);
+
+  ret = gst_videomixer2_update_converters (mix);
+
+  GST_VIDEO_MIXER2_UNLOCK (mix);
+  if (ret)
+    ret = gst_videomixer2_update_src_caps (mix);
+  GST_COLLECT_PADS_STREAM_UNLOCK (mix->collect);
+
+beach:
+  return ret;
+}
+
+static GstCaps *
+gst_videomixer2_pad_sink_getcaps (GstPad * pad, GstVideoMixer2 * mix,
+    GstCaps * filter)
+{
+  GstCaps *srccaps;
+  GstCaps *template_caps;
+  GstCaps *filtered_caps;
+  GstCaps *returned_caps;
+  GstStructure *s;
+  gboolean had_current_caps = TRUE;
+  gint i, n;
+
+  template_caps = gst_pad_get_pad_template_caps (GST_PAD (mix->srcpad));
+
+  srccaps = gst_pad_get_current_caps (GST_PAD (mix->srcpad));
+  if (srccaps == NULL) {
+    had_current_caps = FALSE;
+    srccaps = template_caps;
+  }
+
+  srccaps = gst_caps_make_writable (srccaps);
+
+  n = gst_caps_get_size (srccaps);
+  for (i = 0; i < n; i++) {
+    s = gst_caps_get_structure (srccaps, i);
+    gst_structure_set (s, "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+        "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+        "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
+    if (!gst_structure_has_field (s, "pixel-aspect-ratio"))
+      gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
+          NULL);
+
+    gst_structure_remove_fields (s, "colorimetry", "chroma-site", "format",
+        NULL);
+  }
+
+  filtered_caps = srccaps;
+  if (filter)
+    filtered_caps = gst_caps_intersect (srccaps, filter);
+  returned_caps = gst_caps_intersect (filtered_caps, template_caps);
+
+  gst_caps_unref (srccaps);
+  if (filter)
+    gst_caps_unref (filtered_caps);
+  if (had_current_caps)
+    gst_caps_unref (template_caps);
+
+  return returned_caps;
+}
+
+static gboolean
+gst_videomixer2_pad_sink_acceptcaps (GstPad * pad, GstVideoMixer2 * mix,
+    GstCaps * caps)
+{
+  gboolean ret;
+  GstCaps *modified_caps;
+  GstCaps *accepted_caps;
+  GstCaps *template_caps;
+  gboolean had_current_caps = TRUE;
+  gint i, n;
+  GstStructure *s;
+
+  GST_DEBUG_OBJECT (pad, "%" GST_PTR_FORMAT, caps);
+
+  accepted_caps = gst_pad_get_current_caps (GST_PAD (mix->srcpad));
+
+  template_caps = gst_pad_get_pad_template_caps (GST_PAD (mix->srcpad));
+
+  if (accepted_caps == NULL) {
+    accepted_caps = template_caps;
+    had_current_caps = FALSE;
+  }
+
+  accepted_caps = gst_caps_make_writable (accepted_caps);
+
+  GST_LOG_OBJECT (pad, "src caps %" GST_PTR_FORMAT, accepted_caps);
+
+  n = gst_caps_get_size (accepted_caps);
+  for (i = 0; i < n; i++) {
+    s = gst_caps_get_structure (accepted_caps, i);
+    gst_structure_set (s, "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+        "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+        "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
+    if (!gst_structure_has_field (s, "pixel-aspect-ratio"))
+      gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
+          NULL);
+
+    gst_structure_remove_fields (s, "colorimetry", "chroma-site", "format",
+        NULL);
+  }
+
+  modified_caps = gst_caps_intersect (accepted_caps, template_caps);
+
+  ret = gst_caps_can_intersect (caps, accepted_caps);
+  GST_DEBUG_OBJECT (pad, "%saccepted caps %" GST_PTR_FORMAT,
+      (ret ? "" : "not "), caps);
+  GST_DEBUG_OBJECT (pad, "acceptable caps are %" GST_PTR_FORMAT, accepted_caps);
+  gst_caps_unref (accepted_caps);
+  gst_caps_unref (modified_caps);
+  if (had_current_caps)
+    gst_caps_unref (template_caps);
+  return ret;
+}
+
+static gboolean
+gst_videomixer2_sink_query (GstCollectPads * pads, GstCollectData * cdata,
+    GstQuery * query, GstVideoMixer2 * mix)
+{
+  GstVideoMixer2Pad *pad = GST_VIDEO_MIXER2_PAD (cdata->pad);
+  gboolean ret = FALSE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *filter, *caps;
+
+      gst_query_parse_caps (query, &filter);
+      caps = gst_videomixer2_pad_sink_getcaps (GST_PAD (pad), mix, filter);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+      ret = TRUE;
+      break;
+    }
+    case GST_QUERY_ACCEPT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_query_parse_accept_caps (query, &caps);
+      ret = gst_videomixer2_pad_sink_acceptcaps (GST_PAD (pad), mix, caps);
+      gst_query_set_accept_caps_result (query, ret);
+      ret = TRUE;
+      break;
+    }
+    default:
+      ret = gst_collect_pads_query_default (pads, cdata, query, FALSE);
+      break;
+  }
+  return ret;
+}
+
+static void
+gst_videomixer2_pad_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVideoMixer2Pad *pad = GST_VIDEO_MIXER2_PAD (object);
+
+  switch (prop_id) {
+    case PROP_PAD_ZORDER:
+      g_value_set_uint (value, pad->zorder);
+      break;
+    case PROP_PAD_XPOS:
+      g_value_set_int (value, pad->xpos);
+      break;
+    case PROP_PAD_YPOS:
+      g_value_set_int (value, pad->ypos);
+      break;
+    case PROP_PAD_ALPHA:
+      g_value_set_double (value, pad->alpha);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static int
+pad_zorder_compare (const GstVideoMixer2Pad * pad1,
+    const GstVideoMixer2Pad * pad2)
+{
+  return pad1->zorder - pad2->zorder;
+}
+
+static void
+gst_videomixer2_pad_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVideoMixer2Pad *pad = GST_VIDEO_MIXER2_PAD (object);
+  GstVideoMixer2 *mix = GST_VIDEO_MIXER2 (gst_pad_get_parent (GST_PAD (pad)));
+
+  switch (prop_id) {
+    case PROP_PAD_ZORDER:
+      GST_VIDEO_MIXER2_LOCK (mix);
+      pad->zorder = g_value_get_uint (value);
+
+      mix->sinkpads = g_slist_sort (mix->sinkpads,
+          (GCompareFunc) pad_zorder_compare);
+      GST_VIDEO_MIXER2_UNLOCK (mix);
+      break;
+    case PROP_PAD_XPOS:
+      pad->xpos = g_value_get_int (value);
+      break;
+    case PROP_PAD_YPOS:
+      pad->ypos = g_value_get_int (value);
+      break;
+    case PROP_PAD_ALPHA:
+      pad->alpha = g_value_get_double (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  gst_object_unref (mix);
+}
+
+static void
+gst_videomixer2_pad_class_init (GstVideoMixer2PadClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+
+  gobject_class->set_property = gst_videomixer2_pad_set_property;
+  gobject_class->get_property = gst_videomixer2_pad_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_PAD_ZORDER,
+      g_param_spec_uint ("zorder", "Z-Order", "Z Order of the picture",
+          0, 10000, DEFAULT_PAD_ZORDER,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_PAD_XPOS,
+      g_param_spec_int ("xpos", "X Position", "X Position of the picture",
+          G_MININT, G_MAXINT, DEFAULT_PAD_XPOS,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_PAD_YPOS,
+      g_param_spec_int ("ypos", "Y Position", "Y Position of the picture",
+          G_MININT, G_MAXINT, DEFAULT_PAD_YPOS,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_PAD_ALPHA,
+      g_param_spec_double ("alpha", "Alpha", "Alpha of the picture", 0.0, 1.0,
+          DEFAULT_PAD_ALPHA,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_videomixer2_pad_init (GstVideoMixer2Pad * mixerpad)
+{
+  mixerpad->zorder = DEFAULT_PAD_ZORDER;
+  mixerpad->xpos = DEFAULT_PAD_XPOS;
+  mixerpad->ypos = DEFAULT_PAD_YPOS;
+  mixerpad->alpha = DEFAULT_PAD_ALPHA;
+  mixerpad->convert = NULL;
+  mixerpad->need_conversion_update = FALSE;
+}
+
+/* GstVideoMixer2 */
+#define DEFAULT_BACKGROUND VIDEO_MIXER2_BACKGROUND_CHECKER
+enum
+{
+  PROP_0,
+  PROP_BACKGROUND
+};
+
+#define GST_TYPE_VIDEO_MIXER2_BACKGROUND (gst_videomixer2_background_get_type())
+static GType
+gst_videomixer2_background_get_type (void)
+{
+  static GType video_mixer_background_type = 0;
+
+  static const GEnumValue video_mixer_background[] = {
+    {VIDEO_MIXER2_BACKGROUND_CHECKER, "Checker pattern", "checker"},
+    {VIDEO_MIXER2_BACKGROUND_BLACK, "Black", "black"},
+    {VIDEO_MIXER2_BACKGROUND_WHITE, "White", "white"},
+    {VIDEO_MIXER2_BACKGROUND_TRANSPARENT,
+        "Transparent Background to enable further mixing", "transparent"},
+    {0, NULL, NULL},
+  };
+
+  if (!video_mixer_background_type) {
+    video_mixer_background_type =
+        g_enum_register_static ("GstVideoMixer2Background",
+        video_mixer_background);
+  }
+  return video_mixer_background_type;
+}
+
+#define gst_videomixer2_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstVideoMixer2, gst_videomixer2, GST_TYPE_ELEMENT,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
+        gst_videomixer2_child_proxy_init));
+
+static void
+gst_videomixer2_update_qos (GstVideoMixer2 * mix, gdouble proportion,
+    GstClockTimeDiff diff, GstClockTime timestamp)
+{
+  GST_DEBUG_OBJECT (mix,
+      "Updating QoS: proportion %lf, diff %" GST_STIME_FORMAT ", timestamp %"
+      GST_TIME_FORMAT, proportion, GST_STIME_ARGS (diff),
+      GST_TIME_ARGS (timestamp));
+
+  GST_OBJECT_LOCK (mix);
+  mix->proportion = proportion;
+  if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) {
+    if (!mix->live && G_UNLIKELY (diff > 0))
+      mix->earliest_time =
+          timestamp + 2 * diff + gst_util_uint64_scale_int_round (GST_SECOND,
+          GST_VIDEO_INFO_FPS_D (&mix->info), GST_VIDEO_INFO_FPS_N (&mix->info));
+    else
+      mix->earliest_time = timestamp + diff;
+  } else {
+    mix->earliest_time = GST_CLOCK_TIME_NONE;
+  }
+  GST_OBJECT_UNLOCK (mix);
+}
+
+static void
+gst_videomixer2_reset_qos (GstVideoMixer2 * mix)
+{
+  gst_videomixer2_update_qos (mix, 0.5, 0, GST_CLOCK_TIME_NONE);
+  mix->qos_processed = mix->qos_dropped = 0;
+}
+
+static void
+gst_videomixer2_read_qos (GstVideoMixer2 * mix, gdouble * proportion,
+    GstClockTime * time)
+{
+  GST_OBJECT_LOCK (mix);
+  *proportion = mix->proportion;
+  *time = mix->earliest_time;
+  GST_OBJECT_UNLOCK (mix);
+}
+
+static void
+gst_videomixer2_reset (GstVideoMixer2 * mix)
+{
+  GSList *l;
+
+  gst_video_info_init (&mix->info);
+  mix->ts_offset = 0;
+  mix->nframes = 0;
+
+  gst_segment_init (&mix->segment, GST_FORMAT_TIME);
+  mix->segment.position = -1;
+
+  gst_videomixer2_reset_qos (mix);
+
+  for (l = mix->sinkpads; l; l = l->next) {
+    GstVideoMixer2Pad *p = l->data;
+    GstVideoMixer2Collect *mixcol = p->mixcol;
+
+    gst_buffer_replace (&mixcol->buffer, NULL);
+    mixcol->start_time = -1;
+    mixcol->end_time = -1;
+
+    gst_video_info_init (&p->info);
+  }
+
+  mix->newseg_pending = TRUE;
+}
+
+/*  1 == OK
+ *  0 == need more data
+ * -1 == EOS
+ * -2 == error
+ */
+static gint
+gst_videomixer2_fill_queues (GstVideoMixer2 * mix,
+    GstClockTime output_start_time, GstClockTime output_end_time)
+{
+  GSList *l;
+  gboolean eos = TRUE;
+  gboolean need_more_data = FALSE;
+
+  for (l = mix->sinkpads; l; l = l->next) {
+    GstVideoMixer2Pad *pad = l->data;
+    GstVideoMixer2Collect *mixcol = pad->mixcol;
+    GstSegment *segment = &pad->mixcol->collect.segment;
+    GstBuffer *buf;
+    GstVideoInfo *vinfo;
+
+    buf = gst_collect_pads_peek (mix->collect, &mixcol->collect);
+    if (buf) {
+      GstClockTime start_time, end_time;
+
+      start_time = GST_BUFFER_TIMESTAMP (buf);
+      if (start_time == -1) {
+        gst_buffer_unref (buf);
+        GST_ERROR_OBJECT (pad, "Need timestamped buffers!");
+        return -2;
+      }
+
+      vinfo = &pad->info;
+
+      /* FIXME: Make all this work with negative rates */
+
+      if ((mixcol->buffer && start_time < GST_BUFFER_TIMESTAMP (mixcol->buffer))
+          || (mixcol->queued
+              && start_time < GST_BUFFER_TIMESTAMP (mixcol->queued))) {
+        GST_WARNING_OBJECT (pad, "Buffer from the past, dropping");
+        gst_buffer_unref (buf);
+        buf = gst_collect_pads_pop (mix->collect, &mixcol->collect);
+        gst_buffer_unref (buf);
+        need_more_data = TRUE;
+        continue;
+      }
+
+      if (mixcol->queued) {
+        end_time = start_time - GST_BUFFER_TIMESTAMP (mixcol->queued);
+        start_time = GST_BUFFER_TIMESTAMP (mixcol->queued);
+        gst_buffer_unref (buf);
+        buf = gst_buffer_ref (mixcol->queued);
+        vinfo = &mixcol->queued_vinfo;
+      } else {
+        end_time = GST_BUFFER_DURATION (buf);
+
+        if (end_time == -1) {
+          mixcol->queued = buf;
+          buf = gst_collect_pads_pop (mix->collect, &mixcol->collect);
+          gst_buffer_unref (buf);
+          mixcol->queued_vinfo = pad->info;
+          need_more_data = TRUE;
+          continue;
+        }
+      }
+
+      g_assert (start_time != -1 && end_time != -1);
+      end_time += start_time;   /* convert from duration to position */
+
+      /* Check if it's inside the segment */
+      if (start_time >= segment->stop || end_time < segment->start) {
+        GST_DEBUG_OBJECT (pad, "Buffer outside the segment");
+
+        if (buf == mixcol->queued) {
+          gst_buffer_unref (buf);
+          gst_buffer_replace (&mixcol->queued, NULL);
+        } else {
+          gst_buffer_unref (buf);
+          buf = gst_collect_pads_pop (mix->collect, &mixcol->collect);
+          gst_buffer_unref (buf);
+        }
+
+        need_more_data = TRUE;
+        continue;
+      }
+
+      /* Clip to segment and convert to running time */
+      start_time = MAX (start_time, segment->start);
+      if (segment->stop != -1)
+        end_time = MIN (end_time, segment->stop);
+      start_time =
+          gst_segment_to_running_time (segment, GST_FORMAT_TIME, start_time);
+      end_time =
+          gst_segment_to_running_time (segment, GST_FORMAT_TIME, end_time);
+      g_assert (start_time != -1 && end_time != -1);
+
+      /* Convert to the output segment rate */
+      if (ABS (mix->segment.rate) != 1.0) {
+        start_time *= ABS (mix->segment.rate);
+        end_time *= ABS (mix->segment.rate);
+      }
+
+      if (mixcol->end_time != -1 && mixcol->end_time > end_time) {
+        GST_DEBUG_OBJECT (pad, "Buffer from the past, dropping");
+        if (buf == mixcol->queued) {
+          gst_buffer_unref (buf);
+          gst_buffer_replace (&mixcol->queued, NULL);
+        } else {
+          gst_buffer_unref (buf);
+          buf = gst_collect_pads_pop (mix->collect, &mixcol->collect);
+          gst_buffer_unref (buf);
+        }
+
+        need_more_data = TRUE;
+        continue;
+      }
+
+      if (end_time >= output_start_time && start_time < output_end_time) {
+        GST_DEBUG_OBJECT (pad,
+            "Taking new buffer with start time %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (start_time));
+        gst_buffer_replace (&mixcol->buffer, buf);
+        mixcol->buffer_vinfo = *vinfo;
+        mixcol->start_time = start_time;
+        mixcol->end_time = end_time;
+
+        if (buf == mixcol->queued) {
+          gst_buffer_unref (buf);
+          gst_buffer_replace (&mixcol->queued, NULL);
+        } else {
+          gst_buffer_unref (buf);
+          buf = gst_collect_pads_pop (mix->collect, &mixcol->collect);
+          gst_buffer_unref (buf);
+        }
+        eos = FALSE;
+      } else if (start_time >= output_end_time) {
+        GST_DEBUG_OBJECT (pad, "Keeping buffer until %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (start_time));
+        gst_buffer_unref (buf);
+        eos = FALSE;
+      } else {
+        GST_DEBUG_OBJECT (pad, "Too old buffer -- dropping");
+        if (buf == mixcol->queued) {
+          gst_buffer_unref (buf);
+          gst_buffer_replace (&mixcol->queued, NULL);
+        } else {
+          gst_buffer_unref (buf);
+          buf = gst_collect_pads_pop (mix->collect, &mixcol->collect);
+          gst_buffer_unref (buf);
+        }
+
+        need_more_data = TRUE;
+        continue;
+      }
+    } else {
+      if (mixcol->end_time != -1) {
+        if (mixcol->end_time <= output_start_time) {
+          gst_buffer_replace (&mixcol->buffer, NULL);
+          mixcol->start_time = mixcol->end_time = -1;
+          if (!GST_COLLECT_PADS_STATE_IS_SET (mixcol,
+                  GST_COLLECT_PADS_STATE_EOS))
+            need_more_data = TRUE;
+        } else if (!GST_COLLECT_PADS_STATE_IS_SET (mixcol,
+                GST_COLLECT_PADS_STATE_EOS)) {
+          eos = FALSE;
+        }
+      }
+    }
+  }
+
+  if (need_more_data)
+    return 0;
+  if (eos)
+    return -1;
+
+  return 1;
+}
+
+static GstFlowReturn
+gst_videomixer2_blend_buffers (GstVideoMixer2 * mix,
+    GstClockTime output_start_time, GstClockTime output_end_time,
+    GstBuffer ** outbuf)
+{
+  GSList *l;
+  guint outsize;
+  BlendFunction composite;
+  GstVideoFrame outframe;
+  static GstAllocationParams params = { 0, 15, 0, 0, };
+
+  outsize = GST_VIDEO_INFO_SIZE (&mix->info);
+
+  *outbuf = gst_buffer_new_allocate (NULL, outsize, &params);
+  GST_BUFFER_TIMESTAMP (*outbuf) = output_start_time;
+  GST_BUFFER_DURATION (*outbuf) = output_end_time - output_start_time;
+
+  gst_video_frame_map (&outframe, &mix->info, *outbuf, GST_MAP_READWRITE);
+
+  /* default to blending */
+  composite = mix->blend;
+  switch (mix->background) {
+    case VIDEO_MIXER2_BACKGROUND_CHECKER:
+      mix->fill_checker (&outframe);
+      break;
+    case VIDEO_MIXER2_BACKGROUND_BLACK:
+      mix->fill_color (&outframe, 16, 128, 128);
+      break;
+    case VIDEO_MIXER2_BACKGROUND_WHITE:
+      mix->fill_color (&outframe, 240, 128, 128);
+      break;
+    case VIDEO_MIXER2_BACKGROUND_TRANSPARENT:
+    {
+      guint i, plane, num_planes, height;
+
+      num_planes = GST_VIDEO_FRAME_N_PLANES (&outframe);
+      for (plane = 0; plane < num_planes; ++plane) {
+        guint8 *pdata;
+        gsize rowsize, plane_stride;
+
+        pdata = GST_VIDEO_FRAME_PLANE_DATA (&outframe, plane);
+        plane_stride = GST_VIDEO_FRAME_PLANE_STRIDE (&outframe, plane);
+        rowsize = GST_VIDEO_FRAME_COMP_WIDTH (&outframe, plane)
+            * GST_VIDEO_FRAME_COMP_PSTRIDE (&outframe, plane);
+        height = GST_VIDEO_FRAME_COMP_HEIGHT (&outframe, plane);
+        for (i = 0; i < height; ++i) {
+          memset (pdata, 0, rowsize);
+          pdata += plane_stride;
+        }
+      }
+
+      /* use overlay to keep background transparent */
+      composite = mix->overlay;
+      break;
+    }
+  }
+
+  for (l = mix->sinkpads; l; l = l->next) {
+    GstVideoMixer2Pad *pad = l->data;
+    GstVideoMixer2Collect *mixcol = pad->mixcol;
+
+    if (mixcol->buffer != NULL) {
+      GstClockTime timestamp;
+      gint64 stream_time;
+      GstSegment *seg;
+      GstVideoFrame converted_frame;
+      GstBuffer *converted_buf = NULL;
+      GstVideoFrame frame;
+
+      seg = &mixcol->collect.segment;
+
+      timestamp = GST_BUFFER_TIMESTAMP (mixcol->buffer);
+
+      stream_time =
+          gst_segment_to_stream_time (seg, GST_FORMAT_TIME, timestamp);
+
+      /* sync object properties on stream time */
+      if (GST_CLOCK_TIME_IS_VALID (stream_time))
+        gst_object_sync_values (GST_OBJECT (pad), stream_time);
+
+      gst_video_frame_map (&frame, &mixcol->buffer_vinfo, mixcol->buffer,
+          GST_MAP_READ);
+
+      if (pad->convert) {
+        gint converted_size;
+
+        /* We wait until here to set the conversion infos, in case mix->info changed */
+        if (pad->need_conversion_update) {
+          pad->conversion_info = mix->info;
+          gst_video_info_set_format (&(pad->conversion_info),
+              GST_VIDEO_INFO_FORMAT (&mix->info), pad->info.width,
+              pad->info.height);
+          pad->need_conversion_update = FALSE;
+        }
+
+        converted_size = pad->conversion_info.size;
+        converted_size = converted_size > outsize ? converted_size : outsize;
+        converted_buf = gst_buffer_new_allocate (NULL, converted_size, &params);
+
+        gst_video_frame_map (&converted_frame, &(pad->conversion_info),
+            converted_buf, GST_MAP_READWRITE);
+        gst_video_converter_frame (pad->convert, &frame, &converted_frame);
+        gst_video_frame_unmap (&frame);
+      } else {
+        converted_frame = frame;
+      }
+
+      composite (&converted_frame, pad->xpos, pad->ypos, pad->alpha, &outframe);
+
+      if (pad->convert)
+        gst_buffer_unref (converted_buf);
+
+      gst_video_frame_unmap (&converted_frame);
+    }
+  }
+  gst_video_frame_unmap (&outframe);
+
+  return GST_FLOW_OK;
+}
+
+/* Perform qos calculations before processing the next frame. Returns TRUE if
+ * the frame should be processed, FALSE if the frame can be dropped entirely */
+static gint64
+gst_videomixer2_do_qos (GstVideoMixer2 * mix, GstClockTime timestamp)
+{
+  GstClockTime qostime, earliest_time;
+  gdouble proportion;
+  gint64 jitter;
+
+  /* no timestamp, can't do QoS => process frame */
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
+    GST_LOG_OBJECT (mix, "invalid timestamp, can't do QoS, process frame");
+    return -1;
+  }
+
+  /* get latest QoS observation values */
+  gst_videomixer2_read_qos (mix, &proportion, &earliest_time);
+
+  /* skip qos if we have no observation (yet) => process frame */
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
+    GST_LOG_OBJECT (mix, "no observation yet, process frame");
+    return -1;
+  }
+
+  /* qos is done on running time */
+  qostime =
+      gst_segment_to_running_time (&mix->segment, GST_FORMAT_TIME, timestamp);
+
+  /* see how our next timestamp relates to the latest qos timestamp */
+  GST_LOG_OBJECT (mix, "qostime %" GST_TIME_FORMAT ", earliest %"
+      GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
+
+  jitter = GST_CLOCK_DIFF (qostime, earliest_time);
+  if (qostime != GST_CLOCK_TIME_NONE && jitter > 0) {
+    GST_DEBUG_OBJECT (mix, "we are late, drop frame");
+    return jitter;
+  }
+
+  GST_LOG_OBJECT (mix, "process frame");
+  return jitter;
+}
+
+static GstFlowReturn
+gst_videomixer2_collected (GstCollectPads * pads, GstVideoMixer2 * mix)
+{
+  GstFlowReturn ret;
+  GstClockTime output_start_time, output_end_time;
+  GstBuffer *outbuf = NULL;
+  gint res;
+  gint64 jitter;
+
+  /* If we're not negotiated yet... */
+  if (GST_VIDEO_INFO_FORMAT (&mix->info) == GST_VIDEO_FORMAT_UNKNOWN)
+    return GST_FLOW_NOT_NEGOTIATED;
+
+  if (mix->send_stream_start) {
+    gchar s_id[32];
+
+    /* stream-start (FIXME: create id based on input ids) */
+    g_snprintf (s_id, sizeof (s_id), "mix-%08x", g_random_int ());
+    if (!gst_pad_push_event (mix->srcpad, gst_event_new_stream_start (s_id))) {
+      GST_WARNING_OBJECT (mix->srcpad, "Sending stream start event failed");
+    }
+    mix->send_stream_start = FALSE;
+  }
+
+  if (gst_pad_check_reconfigure (mix->srcpad))
+    gst_videomixer2_update_src_caps (mix);
+
+  if (mix->send_caps) {
+    if (!gst_pad_push_event (mix->srcpad,
+            gst_event_new_caps (mix->current_caps))) {
+      GST_WARNING_OBJECT (mix->srcpad, "Sending caps event failed");
+    }
+    mix->send_caps = FALSE;
+  }
+
+  GST_VIDEO_MIXER2_LOCK (mix);
+
+  if (mix->newseg_pending) {
+    GST_DEBUG_OBJECT (mix, "Sending NEWSEGMENT event");
+    GST_VIDEO_MIXER2_UNLOCK (mix);
+    if (!gst_pad_push_event (mix->srcpad,
+            gst_event_new_segment (&mix->segment))) {
+      ret = GST_FLOW_ERROR;
+      goto done_unlocked;
+    }
+    GST_VIDEO_MIXER2_LOCK (mix);
+    mix->newseg_pending = FALSE;
+  }
+
+  if (mix->segment.position == -1)
+    output_start_time = mix->segment.start;
+  else
+    output_start_time = mix->segment.position;
+
+  output_end_time =
+      mix->ts_offset + gst_util_uint64_scale_round (mix->nframes + 1,
+      GST_SECOND * GST_VIDEO_INFO_FPS_D (&mix->info),
+      GST_VIDEO_INFO_FPS_N (&mix->info)) + mix->segment.start;
+
+  if (output_end_time >= mix->segment.stop) {
+    GST_DEBUG_OBJECT (mix, "Segment done");
+    if (!(mix->segment.flags & GST_SEGMENT_FLAG_SEGMENT)) {
+      GST_VIDEO_MIXER2_UNLOCK (mix);
+      gst_pad_push_event (mix->srcpad, gst_event_new_eos ());
+
+      ret = GST_FLOW_EOS;
+      goto done_unlocked;
+    }
+  }
+
+  if (G_UNLIKELY (mix->pending_tags)) {
+    gst_pad_push_event (mix->srcpad, gst_event_new_tag (mix->pending_tags));
+    mix->pending_tags = NULL;
+  }
+
+  if (mix->segment.stop != -1)
+    output_end_time = MIN (output_end_time, mix->segment.stop);
+
+  res = gst_videomixer2_fill_queues (mix, output_start_time, output_end_time);
+
+  if (res == 0) {
+    GST_DEBUG_OBJECT (mix, "Need more data for decisions");
+    ret = GST_FLOW_OK;
+    goto done;
+  } else if (res == -1) {
+    GST_VIDEO_MIXER2_UNLOCK (mix);
+    GST_DEBUG_OBJECT (mix, "All sinkpads are EOS -- forwarding");
+    gst_pad_push_event (mix->srcpad, gst_event_new_eos ());
+    ret = GST_FLOW_EOS;
+    goto done_unlocked;
+  } else if (res == -2) {
+    GST_ERROR_OBJECT (mix, "Error collecting buffers");
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+
+  jitter = gst_videomixer2_do_qos (mix, output_start_time);
+  if (jitter <= 0) {
+    ret =
+        gst_videomixer2_blend_buffers (mix, output_start_time,
+        output_end_time, &outbuf);
+    mix->qos_processed++;
+  } else {
+    GstMessage *msg;
+
+    mix->qos_dropped++;
+
+    /* TODO: live */
+    msg =
+        gst_message_new_qos (GST_OBJECT_CAST (mix), FALSE,
+        gst_segment_to_running_time (&mix->segment, GST_FORMAT_TIME,
+            output_start_time), gst_segment_to_stream_time (&mix->segment,
+            GST_FORMAT_TIME, output_start_time), output_start_time,
+        output_end_time - output_start_time);
+    gst_message_set_qos_values (msg, jitter, mix->proportion, 1000000);
+    gst_message_set_qos_stats (msg, GST_FORMAT_BUFFERS, mix->qos_processed,
+        mix->qos_dropped);
+    gst_element_post_message (GST_ELEMENT_CAST (mix), msg);
+
+    ret = GST_FLOW_OK;
+  }
+
+  mix->segment.position = output_end_time;
+  mix->nframes++;
+
+  GST_VIDEO_MIXER2_UNLOCK (mix);
+  if (outbuf) {
+    GST_LOG_OBJECT (mix,
+        "Pushing buffer with ts %" GST_TIME_FORMAT " and duration %"
+        GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
+        GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
+    ret = gst_pad_push (mix->srcpad, outbuf);
+  }
+  goto done_unlocked;
+
+done:
+  GST_VIDEO_MIXER2_UNLOCK (mix);
+
+done_unlocked:
+  return ret;
+}
+
+/* FIXME, the duration query should reflect how long you will produce
+ * data, that is the amount of stream time until you will emit EOS.
+ *
+ * For synchronized mixing this is always the max of all the durations
+ * of upstream since we emit EOS when all of them finished.
+ *
+ * We don't do synchronized mixing so this really depends on where the
+ * streams where punched in and what their relative offsets are against
+ * eachother which we can get from the first timestamps we see.
+ *
+ * When we add a new stream (or remove a stream) the duration might
+ * also become invalid again and we need to post a new DURATION
+ * message to notify this fact to the parent.
+ * For now we take the max of all the upstream elements so the simple
+ * cases work at least somewhat.
+ */
+static gboolean
+gst_videomixer2_query_duration (GstVideoMixer2 * mix, GstQuery * query)
+{
+  GValue item = { 0 };
+  gint64 max;
+  gboolean res;
+  GstFormat format;
+  GstIterator *it;
+  gboolean done;
+
+  /* parse format */
+  gst_query_parse_duration (query, &format, NULL);
+
+  max = -1;
+  res = TRUE;
+  done = FALSE;
+
+  /* Take maximum of all durations */
+  it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (mix));
+  while (!done) {
+    switch (gst_iterator_next (it, &item)) {
+      case GST_ITERATOR_DONE:
+        done = TRUE;
+        break;
+      case GST_ITERATOR_OK:
+      {
+        GstPad *pad;
+        gint64 duration;
+
+        pad = g_value_get_object (&item);
+
+        /* ask sink peer for duration */
+        res &= gst_pad_peer_query_duration (pad, format, &duration);
+        /* take max from all valid return values */
+        if (res) {
+          /* valid unknown length, stop searching */
+          if (duration == -1) {
+            max = duration;
+            done = TRUE;
+          }
+          /* else see if bigger than current max */
+          else if (duration > max)
+            max = duration;
+        }
+        g_value_reset (&item);
+        break;
+      }
+      case GST_ITERATOR_RESYNC:
+        max = -1;
+        res = TRUE;
+        gst_iterator_resync (it);
+        break;
+      default:
+        res = FALSE;
+        done = TRUE;
+        break;
+    }
+  }
+  g_value_unset (&item);
+  gst_iterator_free (it);
+
+  if (res) {
+    /* and store the max */
+    GST_DEBUG_OBJECT (mix, "Total duration in format %s: %"
+        GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max));
+    gst_query_set_duration (query, format, max);
+  }
+
+  return res;
+}
+
+static gboolean
+gst_videomixer2_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  GstVideoMixer2 *mix = GST_VIDEO_MIXER2 (parent);
+  gboolean res = FALSE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:
+    {
+      GstFormat format;
+
+      gst_query_parse_position (query, &format, NULL);
+
+      switch (format) {
+        case GST_FORMAT_TIME:
+          gst_query_set_position (query, format,
+              gst_segment_to_stream_time (&mix->segment, GST_FORMAT_TIME,
+                  mix->segment.position));
+          res = TRUE;
+          break;
+        default:
+          break;
+      }
+      break;
+    }
+    case GST_QUERY_DURATION:
+      res = gst_videomixer2_query_duration (mix, query);
+      break;
+    case GST_QUERY_CAPS:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+    default:
+      /* FIXME, needs a custom query handler because we have multiple
+       * sinkpads */
+      res = FALSE;
+      break;
+  }
+  return res;
+}
+
+static gboolean
+gst_videomixer2_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstVideoMixer2 *mix = GST_VIDEO_MIXER2 (parent);
+  gboolean result;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_QOS:
+    {
+      GstQOSType type;
+      GstClockTimeDiff diff;
+      GstClockTime timestamp;
+      gdouble proportion;
+
+      gst_event_parse_qos (event, &type, &proportion, &diff, &timestamp);
+
+      gst_videomixer2_update_qos (mix, proportion, diff, timestamp);
+
+      result = gst_videomixer2_push_sink_event (mix, event);
+      break;
+    }
+    case GST_EVENT_SEEK:
+    {
+      gdouble rate;
+      GstFormat fmt;
+      GstSeekFlags flags;
+      GstSeekType start_type, stop_type;
+      gint64 start, stop;
+      GSList *l;
+      gdouble abs_rate;
+
+      /* parse the seek parameters */
+      gst_event_parse_seek (event, &rate, &fmt, &flags, &start_type,
+          &start, &stop_type, &stop);
+
+      if (rate <= 0.0) {
+        GST_ERROR_OBJECT (mix, "Negative rates not supported yet");
+        result = FALSE;
+        gst_event_unref (event);
+        break;
+      }
+
+      GST_DEBUG_OBJECT (mix, "Handling SEEK event");
+
+      abs_rate = ABS (rate);
+
+      GST_VIDEO_MIXER2_LOCK (mix);
+      for (l = mix->sinkpads; l; l = l->next) {
+        GstVideoMixer2Pad *p = l->data;
+
+        if (flags & GST_SEEK_FLAG_FLUSH) {
+          gst_buffer_replace (&p->mixcol->buffer, NULL);
+          p->mixcol->start_time = p->mixcol->end_time = -1;
+          continue;
+        }
+
+        /* Convert to the output segment rate */
+        if (ABS (mix->segment.rate) != abs_rate) {
+          if (ABS (mix->segment.rate) != 1.0 && p->mixcol->buffer) {
+            p->mixcol->start_time /= ABS (mix->segment.rate);
+            p->mixcol->end_time /= ABS (mix->segment.rate);
+          }
+          if (abs_rate != 1.0 && p->mixcol->buffer) {
+            p->mixcol->start_time *= abs_rate;
+            p->mixcol->end_time *= abs_rate;
+          }
+        }
+      }
+      GST_VIDEO_MIXER2_UNLOCK (mix);
+
+      gst_segment_do_seek (&mix->segment, rate, fmt, flags, start_type, start,
+          stop_type, stop, NULL);
+      mix->segment.position = -1;
+      mix->ts_offset = 0;
+      mix->nframes = 0;
+      mix->newseg_pending = TRUE;
+
+      gst_videomixer2_reset_qos (mix);
+
+      result = gst_collect_pads_src_event_default (mix->collect, pad, event);
+      break;
+    }
+    case GST_EVENT_NAVIGATION:
+      /* navigation is rather pointless. */
+      result = FALSE;
+      gst_event_unref (event);
+      break;
+    default:
+      /* just forward the rest for now */
+      result = gst_videomixer2_push_sink_event (mix, event);
+      break;
+  }
+
+  return result;
+}
+
+static gboolean
+gst_videomixer2_src_setcaps (GstPad * pad, GstVideoMixer2 * mix, GstCaps * caps)
+{
+  gboolean ret = FALSE;
+  GstVideoInfo info;
+
+  GST_INFO_OBJECT (pad, "set src caps: %" GST_PTR_FORMAT, caps);
+
+  if (!gst_video_info_from_caps (&info, caps))
+    goto done;
+
+  GST_VIDEO_MIXER2_LOCK (mix);
+
+  mix->blend = NULL;
+  mix->overlay = NULL;
+  mix->fill_checker = NULL;
+  mix->fill_color = NULL;
+
+  if (GST_VIDEO_INFO_FPS_N (&mix->info) != GST_VIDEO_INFO_FPS_N (&info) ||
+      GST_VIDEO_INFO_FPS_D (&mix->info) != GST_VIDEO_INFO_FPS_D (&info)) {
+    if (mix->segment.position != -1) {
+      mix->ts_offset = mix->segment.position - mix->segment.start;
+      mix->nframes = 0;
+    }
+    gst_videomixer2_reset_qos (mix);
+  }
+
+  mix->info = info;
+
+  switch (GST_VIDEO_INFO_FORMAT (&mix->info)) {
+    case GST_VIDEO_FORMAT_AYUV:
+      mix->blend = gst_video_mixer_blend_ayuv;
+      mix->overlay = gst_video_mixer_overlay_ayuv;
+      mix->fill_checker = gst_video_mixer_fill_checker_ayuv;
+      mix->fill_color = gst_video_mixer_fill_color_ayuv;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_ARGB:
+      mix->blend = gst_video_mixer_blend_argb;
+      mix->overlay = gst_video_mixer_overlay_argb;
+      mix->fill_checker = gst_video_mixer_fill_checker_argb;
+      mix->fill_color = gst_video_mixer_fill_color_argb;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_BGRA:
+      mix->blend = gst_video_mixer_blend_bgra;
+      mix->overlay = gst_video_mixer_overlay_bgra;
+      mix->fill_checker = gst_video_mixer_fill_checker_bgra;
+      mix->fill_color = gst_video_mixer_fill_color_bgra;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_ABGR:
+      mix->blend = gst_video_mixer_blend_abgr;
+      mix->overlay = gst_video_mixer_overlay_abgr;
+      mix->fill_checker = gst_video_mixer_fill_checker_abgr;
+      mix->fill_color = gst_video_mixer_fill_color_abgr;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_RGBA:
+      mix->blend = gst_video_mixer_blend_rgba;
+      mix->overlay = gst_video_mixer_overlay_rgba;
+      mix->fill_checker = gst_video_mixer_fill_checker_rgba;
+      mix->fill_color = gst_video_mixer_fill_color_rgba;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_Y444:
+      mix->blend = gst_video_mixer_blend_y444;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_y444;
+      mix->fill_color = gst_video_mixer_fill_color_y444;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_Y42B:
+      mix->blend = gst_video_mixer_blend_y42b;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_y42b;
+      mix->fill_color = gst_video_mixer_fill_color_y42b;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_YUY2:
+      mix->blend = gst_video_mixer_blend_yuy2;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_yuy2;
+      mix->fill_color = gst_video_mixer_fill_color_yuy2;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_UYVY:
+      mix->blend = gst_video_mixer_blend_uyvy;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_uyvy;
+      mix->fill_color = gst_video_mixer_fill_color_uyvy;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_YVYU:
+      mix->blend = gst_video_mixer_blend_yvyu;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_yvyu;
+      mix->fill_color = gst_video_mixer_fill_color_yvyu;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_I420:
+      mix->blend = gst_video_mixer_blend_i420;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_i420;
+      mix->fill_color = gst_video_mixer_fill_color_i420;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_YV12:
+      mix->blend = gst_video_mixer_blend_yv12;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_yv12;
+      mix->fill_color = gst_video_mixer_fill_color_yv12;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_NV12:
+      mix->blend = gst_video_mixer_blend_nv12;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_nv12;
+      mix->fill_color = gst_video_mixer_fill_color_nv12;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_NV21:
+      mix->blend = gst_video_mixer_blend_nv21;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_nv21;
+      mix->fill_color = gst_video_mixer_fill_color_nv21;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_Y41B:
+      mix->blend = gst_video_mixer_blend_y41b;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_y41b;
+      mix->fill_color = gst_video_mixer_fill_color_y41b;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_RGB:
+      mix->blend = gst_video_mixer_blend_rgb;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_rgb;
+      mix->fill_color = gst_video_mixer_fill_color_rgb;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_BGR:
+      mix->blend = gst_video_mixer_blend_bgr;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_bgr;
+      mix->fill_color = gst_video_mixer_fill_color_bgr;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_xRGB:
+      mix->blend = gst_video_mixer_blend_xrgb;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_xrgb;
+      mix->fill_color = gst_video_mixer_fill_color_xrgb;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_xBGR:
+      mix->blend = gst_video_mixer_blend_xbgr;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_xbgr;
+      mix->fill_color = gst_video_mixer_fill_color_xbgr;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_RGBx:
+      mix->blend = gst_video_mixer_blend_rgbx;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_rgbx;
+      mix->fill_color = gst_video_mixer_fill_color_rgbx;
+      ret = TRUE;
+      break;
+    case GST_VIDEO_FORMAT_BGRx:
+      mix->blend = gst_video_mixer_blend_bgrx;
+      mix->overlay = mix->blend;
+      mix->fill_checker = gst_video_mixer_fill_checker_bgrx;
+      mix->fill_color = gst_video_mixer_fill_color_bgrx;
+      ret = TRUE;
+      break;
+    default:
+      break;
+  }
+  GST_VIDEO_MIXER2_UNLOCK (mix);
+
+  if (mix->current_caps == NULL ||
+      gst_caps_is_equal (caps, mix->current_caps) == FALSE) {
+    gst_caps_replace (&mix->current_caps, caps);
+    mix->send_caps = TRUE;
+  }
+
+done:
+  return ret;
+}
+
+static GstFlowReturn
+gst_videomixer2_sink_clip (GstCollectPads * pads,
+    GstCollectData * data, GstBuffer * buf, GstBuffer ** outbuf,
+    GstVideoMixer2 * mix)
+{
+  GstVideoMixer2Pad *pad = GST_VIDEO_MIXER2_PAD (data->pad);
+  GstVideoMixer2Collect *mixcol = pad->mixcol;
+  GstClockTime start_time, end_time;
+
+  start_time = GST_BUFFER_TIMESTAMP (buf);
+  if (start_time == -1) {
+    GST_ERROR_OBJECT (pad, "Timestamped buffers required!");
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+
+  end_time = GST_BUFFER_DURATION (buf);
+  if (end_time == -1 && GST_VIDEO_INFO_FPS_N (&pad->info) != 0)
+    end_time =
+        gst_util_uint64_scale_int_round (GST_SECOND,
+        GST_VIDEO_INFO_FPS_D (&pad->info), GST_VIDEO_INFO_FPS_N (&pad->info));
+  if (end_time == -1) {
+    *outbuf = buf;
+    return GST_FLOW_OK;
+  }
+
+  start_time = MAX (start_time, mixcol->collect.segment.start);
+  start_time =
+      gst_segment_to_running_time (&mixcol->collect.segment,
+      GST_FORMAT_TIME, start_time);
+
+  end_time += GST_BUFFER_TIMESTAMP (buf);
+  if (mixcol->collect.segment.stop != -1)
+    end_time = MIN (end_time, mixcol->collect.segment.stop);
+  end_time =
+      gst_segment_to_running_time (&mixcol->collect.segment,
+      GST_FORMAT_TIME, end_time);
+
+  /* Convert to the output segment rate */
+  if (ABS (mix->segment.rate) != 1.0) {
+    start_time *= ABS (mix->segment.rate);
+    end_time *= ABS (mix->segment.rate);
+  }
+
+  if (mixcol->buffer != NULL && end_time < mixcol->end_time) {
+    gst_buffer_unref (buf);
+    *outbuf = NULL;
+    return GST_FLOW_OK;
+  }
+
+  *outbuf = buf;
+  return GST_FLOW_OK;
+}
+
+static void
+gst_videomixer2_flush (GstCollectPads * pads, GstVideoMixer2 * mix)
+{
+  if (mix->pending_tags) {
+    gst_tag_list_unref (mix->pending_tags);
+    mix->pending_tags = NULL;
+  }
+}
+
+static gboolean
+gst_videomixer2_sink_event (GstCollectPads * pads, GstCollectData * cdata,
+    GstEvent * event, GstVideoMixer2 * mix)
+{
+  GstVideoMixer2Pad *pad = GST_VIDEO_MIXER2_PAD (cdata->pad);
+  gboolean ret = TRUE, discard = FALSE;
+
+  GST_DEBUG_OBJECT (pad, "Got %s event: %" GST_PTR_FORMAT,
+      GST_EVENT_TYPE_NAME (event), event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      ret =
+          gst_videomixer2_pad_sink_setcaps (GST_PAD (pad), GST_OBJECT (mix),
+          caps);
+      gst_event_unref (event);
+      event = NULL;
+      break;
+    }
+    case GST_EVENT_SEGMENT:{
+      GstSegment seg;
+      gst_event_copy_segment (event, &seg);
+
+      g_assert (seg.format == GST_FORMAT_TIME);
+      gst_videomixer2_reset_qos (mix);
+      break;
+    }
+    case GST_EVENT_FLUSH_STOP:
+      mix->newseg_pending = TRUE;
+
+      gst_videomixer2_reset_qos (mix);
+      gst_buffer_replace (&pad->mixcol->buffer, NULL);
+      pad->mixcol->start_time = -1;
+      pad->mixcol->end_time = -1;
+
+      mix->segment.position = -1;
+      mix->ts_offset = 0;
+      mix->nframes = 0;
+      break;
+    case GST_EVENT_TAG:
+    {
+      /* collect tags here so we can push them out when we collect data */
+      GstTagList *tags;
+
+      gst_event_parse_tag (event, &tags);
+      tags = gst_tag_list_merge (mix->pending_tags, tags, GST_TAG_MERGE_APPEND);
+      if (mix->pending_tags)
+        gst_tag_list_unref (mix->pending_tags);
+      mix->pending_tags = tags;
+      event = NULL;
+      break;
+    }
+    default:
+      break;
+  }
+
+  if (event != NULL)
+    return gst_collect_pads_event_default (pads, cdata, event, discard);
+
+  return ret;
+}
+
+static gboolean
+forward_event_func (GValue * item, GValue * ret, GstEvent * event)
+{
+  GstPad *pad = g_value_get_object (item);
+  gst_event_ref (event);
+  GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event));
+  if (!gst_pad_push_event (pad, event)) {
+    g_value_set_boolean (ret, FALSE);
+    GST_WARNING_OBJECT (pad, "Sending event  %p (%s) failed.",
+        event, GST_EVENT_TYPE_NAME (event));
+  } else {
+    GST_LOG_OBJECT (pad, "Sent event  %p (%s).",
+        event, GST_EVENT_TYPE_NAME (event));
+  }
+  return TRUE;
+}
+
+static gboolean
+gst_videomixer2_push_sink_event (GstVideoMixer2 * mix, GstEvent * event)
+{
+  GstIterator *it;
+  GValue vret = { 0 };
+
+  GST_LOG_OBJECT (mix, "Forwarding event %p (%s)", event,
+      GST_EVENT_TYPE_NAME (event));
+
+  g_value_init (&vret, G_TYPE_BOOLEAN);
+  g_value_set_boolean (&vret, TRUE);
+  it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (mix));
+  gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret,
+      event);
+  gst_iterator_free (it);
+  gst_event_unref (event);
+
+  return g_value_get_boolean (&vret);
+}
+
+/* GstElement vmethods */
+static GstStateChangeReturn
+gst_videomixer2_change_state (GstElement * element, GstStateChange transition)
+{
+  GstVideoMixer2 *mix = GST_VIDEO_MIXER2 (element);
+  GstStateChangeReturn ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      mix->send_stream_start = TRUE;
+      mix->send_caps = TRUE;
+      gst_segment_init (&mix->segment, GST_FORMAT_TIME);
+      gst_caps_replace (&mix->current_caps, NULL);
+      GST_LOG_OBJECT (mix, "starting collectpads");
+      gst_collect_pads_start (mix->collect);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      GST_LOG_OBJECT (mix, "stopping collectpads");
+      gst_collect_pads_stop (mix->collect);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_videomixer2_reset (mix);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static GstPad *
+gst_videomixer2_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
+{
+  GstVideoMixer2 *mix;
+  GstVideoMixer2Pad *mixpad;
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
+
+  mix = GST_VIDEO_MIXER2 (element);
+
+  if (templ == gst_element_class_get_pad_template (klass, "sink_%u")) {
+    guint serial = 0;
+    gchar *name = NULL;
+    GstVideoMixer2Collect *mixcol = NULL;
+
+    GST_VIDEO_MIXER2_LOCK (mix);
+    if (req_name == NULL || strlen (req_name) < 6
+        || !g_str_has_prefix (req_name, "sink_")) {
+      /* no name given when requesting the pad, use next available int */
+      serial = mix->next_sinkpad++;
+    } else {
+      /* parse serial number from requested padname */
+      serial = g_ascii_strtoull (&req_name[5], NULL, 10);
+      if (serial >= mix->next_sinkpad)
+        mix->next_sinkpad = serial + 1;
+    }
+    /* create new pad with the name */
+    name = g_strdup_printf ("sink_%u", serial);
+    mixpad = g_object_new (GST_TYPE_VIDEO_MIXER2_PAD, "name", name, "direction",
+        templ->direction, "template", templ, NULL);
+    g_free (name);
+
+    mixpad->zorder = mix->numpads;
+    mixpad->xpos = DEFAULT_PAD_XPOS;
+    mixpad->ypos = DEFAULT_PAD_YPOS;
+    mixpad->alpha = DEFAULT_PAD_ALPHA;
+
+    mixcol = (GstVideoMixer2Collect *)
+        gst_collect_pads_add_pad (mix->collect, GST_PAD (mixpad),
+        sizeof (GstVideoMixer2Collect),
+        (GstCollectDataDestroyNotify) gst_videomixer2_collect_free, TRUE);
+
+    /* Keep track of each other */
+    mixcol->mixpad = mixpad;
+    mixpad->mixcol = mixcol;
+
+    mixcol->start_time = -1;
+    mixcol->end_time = -1;
+
+    /* Keep an internal list of mixpads for zordering */
+    mix->sinkpads = g_slist_insert_sorted (mix->sinkpads, mixpad,
+        (GCompareFunc) pad_zorder_compare);
+    mix->numpads++;
+    GST_VIDEO_MIXER2_UNLOCK (mix);
+  } else {
+    return NULL;
+  }
+
+  GST_DEBUG_OBJECT (element, "Adding pad %s", GST_PAD_NAME (mixpad));
+
+  /* add the pad to the element */
+  gst_element_add_pad (element, GST_PAD (mixpad));
+  gst_child_proxy_child_added (GST_CHILD_PROXY (mix), G_OBJECT (mixpad),
+      GST_OBJECT_NAME (mixpad));
+
+  return GST_PAD (mixpad);
+}
+
+static void
+gst_videomixer2_release_pad (GstElement * element, GstPad * pad)
+{
+  GstVideoMixer2 *mix = NULL;
+  GstVideoMixer2Pad *mixpad;
+  gboolean update_caps;
+
+  mix = GST_VIDEO_MIXER2 (element);
+
+  GST_VIDEO_MIXER2_LOCK (mix);
+  if (G_UNLIKELY (g_slist_find (mix->sinkpads, pad) == NULL)) {
+    g_warning ("Unknown pad %s", GST_PAD_NAME (pad));
+    goto error;
+  }
+
+  mixpad = GST_VIDEO_MIXER2_PAD (pad);
+
+  if (mixpad->convert)
+    gst_video_converter_free (mixpad->convert);
+  mixpad->convert = NULL;
+
+  mix->sinkpads = g_slist_remove (mix->sinkpads, pad);
+  gst_child_proxy_child_removed (GST_CHILD_PROXY (mix), G_OBJECT (mixpad),
+      GST_OBJECT_NAME (mixpad));
+  mix->numpads--;
+
+  GST_COLLECT_PADS_STREAM_LOCK (mix->collect);
+  gst_videomixer2_update_converters (mix);
+  GST_COLLECT_PADS_STREAM_UNLOCK (mix->collect);
+
+  update_caps = GST_VIDEO_INFO_FORMAT (&mix->info) != GST_VIDEO_FORMAT_UNKNOWN;
+  GST_VIDEO_MIXER2_UNLOCK (mix);
+
+  gst_collect_pads_remove_pad (mix->collect, pad);
+
+  if (update_caps)
+    gst_videomixer2_update_src_caps (mix);
+
+  gst_element_remove_pad (element, pad);
+  return;
+error:
+  GST_VIDEO_MIXER2_UNLOCK (mix);
+}
+
+/* GObject vmethods */
+static void
+gst_videomixer2_finalize (GObject * o)
+{
+  GstVideoMixer2 *mix = GST_VIDEO_MIXER2 (o);
+
+  gst_object_unref (mix->collect);
+  g_mutex_clear (&mix->lock);
+  g_mutex_clear (&mix->setcaps_lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (o);
+}
+
+static void
+gst_videomixer2_dispose (GObject * o)
+{
+  GstVideoMixer2 *mix = GST_VIDEO_MIXER2 (o);
+  GSList *tmp;
+
+  for (tmp = mix->sinkpads; tmp; tmp = tmp->next) {
+    GstVideoMixer2Pad *mixpad = tmp->data;
+
+    if (mixpad->convert)
+      gst_video_converter_free (mixpad->convert);
+    mixpad->convert = NULL;
+  }
+
+  if (mix->pending_tags) {
+    gst_tag_list_unref (mix->pending_tags);
+    mix->pending_tags = NULL;
+  }
+
+  gst_caps_replace (&mix->current_caps, NULL);
+
+  G_OBJECT_CLASS (parent_class)->dispose (o);
+}
+
+static void
+gst_videomixer2_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstVideoMixer2 *mix = GST_VIDEO_MIXER2 (object);
+
+  switch (prop_id) {
+    case PROP_BACKGROUND:
+      g_value_set_enum (value, mix->background);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_videomixer2_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstVideoMixer2 *mix = GST_VIDEO_MIXER2 (object);
+
+  switch (prop_id) {
+    case PROP_BACKGROUND:
+      mix->background = g_value_get_enum (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* GstChildProxy implementation */
+static GObject *
+gst_videomixer2_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
+    guint index)
+{
+  GstVideoMixer2 *mix = GST_VIDEO_MIXER2 (child_proxy);
+  GObject *obj;
+
+  GST_VIDEO_MIXER2_LOCK (mix);
+  if ((obj = g_slist_nth_data (mix->sinkpads, index)))
+    g_object_ref (obj);
+  GST_VIDEO_MIXER2_UNLOCK (mix);
+  return obj;
+}
+
+static guint
+gst_videomixer2_child_proxy_get_children_count (GstChildProxy * child_proxy)
+{
+  guint count = 0;
+  GstVideoMixer2 *mix = GST_VIDEO_MIXER2 (child_proxy);
+
+  GST_VIDEO_MIXER2_LOCK (mix);
+  count = mix->numpads;
+  GST_VIDEO_MIXER2_UNLOCK (mix);
+  GST_INFO_OBJECT (mix, "Children Count: %d", count);
+  return count;
+}
+
+static void
+gst_videomixer2_child_proxy_init (gpointer g_iface, gpointer iface_data)
+{
+  GstChildProxyInterface *iface = g_iface;
+
+  GST_INFO ("intializing child proxy interface");
+  iface->get_child_by_index = gst_videomixer2_child_proxy_get_child_by_index;
+  iface->get_children_count = gst_videomixer2_child_proxy_get_children_count;
+}
+
+static void
+gst_videomixer2_constructed (GObject * obj)
+{
+  GstVideoMixer2 *mix = GST_VIDEO_MIXER2 (obj);
+  gchar *cp_name;
+
+  cp_name = g_strconcat (GST_OBJECT_NAME (obj), "-collectpads", NULL);
+  gst_object_set_name (GST_OBJECT (mix->collect), cp_name);
+  g_free (cp_name);
+
+  G_OBJECT_CLASS (gst_videomixer2_parent_class)->constructed (obj);
+}
+
+/* GObject boilerplate */
+static void
+gst_videomixer2_class_init (GstVideoMixer2Class * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->constructed = gst_videomixer2_constructed;
+  gobject_class->finalize = gst_videomixer2_finalize;
+  gobject_class->dispose = gst_videomixer2_dispose;
+
+  gobject_class->get_property = gst_videomixer2_get_property;
+  gobject_class->set_property = gst_videomixer2_set_property;
+
+  g_object_class_install_property (gobject_class, PROP_BACKGROUND,
+      g_param_spec_enum ("background", "Background", "Background type",
+          GST_TYPE_VIDEO_MIXER2_BACKGROUND,
+          DEFAULT_BACKGROUND, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstelement_class->request_new_pad =
+      GST_DEBUG_FUNCPTR (gst_videomixer2_request_new_pad);
+  gstelement_class->release_pad =
+      GST_DEBUG_FUNCPTR (gst_videomixer2_release_pad);
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_videomixer2_change_state);
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class, "Video mixer 2",
+      "Filter/Editor/Video/Compositor",
+      "Mix multiple video streams", "Wim Taymans <wim@fluendo.com>, "
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  /* Register the pad class */
+  g_type_class_ref (GST_TYPE_VIDEO_MIXER2_PAD);
+}
+
+static void
+gst_videomixer2_init (GstVideoMixer2 * mix)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (mix);
+
+  mix->srcpad =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "src"), "src");
+  gst_pad_set_query_function (GST_PAD (mix->srcpad),
+      GST_DEBUG_FUNCPTR (gst_videomixer2_src_query));
+  gst_pad_set_event_function (GST_PAD (mix->srcpad),
+      GST_DEBUG_FUNCPTR (gst_videomixer2_src_event));
+  gst_element_add_pad (GST_ELEMENT (mix), mix->srcpad);
+
+  mix->collect = gst_collect_pads_new ();
+  gst_collect_pads_set_flush_function (mix->collect,
+      (GstCollectPadsFlushFunction) gst_videomixer2_flush, mix);
+  mix->background = DEFAULT_BACKGROUND;
+  mix->current_caps = NULL;
+  mix->pending_tags = NULL;
+
+  gst_collect_pads_set_function (mix->collect,
+      (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_videomixer2_collected),
+      mix);
+  gst_collect_pads_set_event_function (mix->collect,
+      (GstCollectPadsEventFunction) gst_videomixer2_sink_event, mix);
+  gst_collect_pads_set_query_function (mix->collect,
+      (GstCollectPadsQueryFunction) gst_videomixer2_sink_query, mix);
+  gst_collect_pads_set_clip_function (mix->collect,
+      (GstCollectPadsClipFunction) gst_videomixer2_sink_clip, mix);
+
+  g_mutex_init (&mix->lock);
+  g_mutex_init (&mix->setcaps_lock);
+  /* initialize variables */
+  gst_videomixer2_reset (mix);
+}
+
+/* Element registration */
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_videomixer2_debug, "videomixer", 0,
+      "video mixer");
+
+  gst_video_mixer_init_blend ();
+
+  return gst_element_register (plugin, "videomixer", GST_RANK_PRIMARY,
+      GST_TYPE_VIDEO_MIXER2);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    videomixer,
+    "Video mixer", plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME,
+    GST_PACKAGE_ORIGIN)
diff --git a/gst/videomixer/videomixer2.h b/gst/videomixer/videomixer2.h
new file mode 100644
index 0000000..8c6a65f
--- /dev/null
+++ b/gst/videomixer/videomixer2.h
@@ -0,0 +1,133 @@
+/* Generic video mixer plugin
+ * Copyright (C) 2008 Wim Taymans <wim@fluendo.com>
+ * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+ 
+#ifndef __GST_VIDEO_MIXER2_H__
+#define __GST_VIDEO_MIXER2_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include "blend.h"
+#include <gst/base/gstcollectpads.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VIDEO_MIXER2 (gst_videomixer2_get_type())
+#define GST_VIDEO_MIXER2(obj) \
+        (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_MIXER2, GstVideoMixer2))
+#define GST_VIDEO_MIXER2_CLASS(klass) \
+        (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_MIXER2, GstVideoMixer2Class))
+#define GST_IS_VIDEO_MIXER2(obj) \
+        (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_MIXER2))
+#define GST_IS_VIDEO_MIXER2_CLASS(klass) \
+        (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_MIXER2))
+
+typedef struct _GstVideoMixer2 GstVideoMixer2;
+typedef struct _GstVideoMixer2Class GstVideoMixer2Class;
+
+/**
+ * GstVideoMixer2Background:
+ * @VIDEO_MIXER2_BACKGROUND_CHECKER: checker pattern background
+ * @VIDEO_MIXER2_BACKGROUND_BLACK: solid color black background
+ * @VIDEO_MIXER2_BACKGROUND_WHITE: solid color white background
+ * @VIDEO_MIXER2_BACKGROUND_TRANSPARENT: background is left transparent and layers are composited using "A OVER B" composition rules. This is only applicable to AYUV and ARGB (and variants) as it preserves the alpha channel and allows for further mixing.
+ *
+ * The different backgrounds videomixer can blend over.
+ */
+typedef enum
+{
+  VIDEO_MIXER2_BACKGROUND_CHECKER,
+  VIDEO_MIXER2_BACKGROUND_BLACK,
+  VIDEO_MIXER2_BACKGROUND_WHITE,
+  VIDEO_MIXER2_BACKGROUND_TRANSPARENT,
+}
+GstVideoMixer2Background;
+
+/**
+ * GstVideoMixer2:
+ *
+ * The opaque #GstVideoMixer2 structure.
+ */
+struct _GstVideoMixer2
+{
+  GstElement element;
+
+  /* < private > */
+
+  /* pad */
+  GstPad *srcpad;
+
+  /* Lock to prevent the state to change while blending */
+  GMutex lock;
+
+  /* Lock to prevent two src setcaps from happening at the same time  */
+  GMutex setcaps_lock;
+
+  /* Sink pads using Collect Pads 2*/
+  GstCollectPads *collect;
+
+  /* sinkpads, a GSList of GstVideoMixer2Pads */
+  GSList *sinkpads;
+  gint numpads;
+  /* Next available sinkpad index */
+  guint next_sinkpad;
+
+  /* Output caps */
+  GstVideoInfo info;
+
+  /* current caps */
+  GstCaps *current_caps;
+  gboolean send_caps;
+
+  gboolean newseg_pending;
+
+  GstVideoMixer2Background background;
+
+  /* Current downstream segment */
+  GstSegment segment;
+  GstClockTime ts_offset;
+  guint64 nframes;
+
+  /* QoS stuff */
+  gdouble proportion;
+  GstClockTime earliest_time;
+  guint64 qos_processed, qos_dropped;
+
+  BlendFunction blend, overlay;
+  FillCheckerFunction fill_checker;
+  FillColorFunction fill_color;
+
+  gboolean send_stream_start;
+
+  /* latency */
+  gboolean live;
+
+  GstTagList *pending_tags;
+};
+
+struct _GstVideoMixer2Class
+{
+  GstElementClass parent_class;
+};
+
+GType gst_videomixer2_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_VIDEO_MIXER2_H__ */
diff --git a/gst/videomixer/videomixer2pad.h b/gst/videomixer/videomixer2pad.h
new file mode 100644
index 0000000..37711e2
--- /dev/null
+++ b/gst/videomixer/videomixer2pad.h
@@ -0,0 +1,83 @@
+/* Generic video mixer plugin
+ * Copyright (C) 2008 Wim Taymans <wim@fluendo.com>
+ * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+ 
+#ifndef __GST_VIDEO_MIXER2_PAD_H__
+#define __GST_VIDEO_MIXER2_PAD_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include <gst/base/gstcollectpads.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VIDEO_MIXER2_PAD (gst_videomixer2_pad_get_type())
+#define GST_VIDEO_MIXER2_PAD(obj) \
+        (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_MIXER2_PAD, GstVideoMixer2Pad))
+#define GST_VIDEO_MIXER2_PAD_CLASS(klass) \
+        (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_MIXER_PAD, GstVideoMixer2PadClass))
+#define GST_IS_VIDEO_MIXER2_PAD(obj) \
+        (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_MIXER2_PAD))
+#define GST_IS_VIDEO_MIXER2_PAD_CLASS(klass) \
+        (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_MIXER2_PAD))
+
+typedef struct _GstVideoMixer2Pad GstVideoMixer2Pad;
+typedef struct _GstVideoMixer2PadClass GstVideoMixer2PadClass;
+typedef struct _GstVideoMixer2Collect GstVideoMixer2Collect;
+
+/**
+ * GstVideoMixer2Pad:
+ *
+ * The opaque #GstVideoMixer2Pad structure.
+ */
+struct _GstVideoMixer2Pad
+{
+  GstPad parent;
+
+  /* < private > */
+
+  /* caps */
+  GstVideoInfo info;
+
+  /* properties */
+  gint xpos, ypos;
+  guint zorder;
+  gdouble alpha;
+
+  GstVideoMixer2Collect *mixcol;
+
+  /* caps used for conversion if needed */
+  GstVideoInfo conversion_info;
+
+  /* Converter, if NULL no conversion is done */
+  GstVideoConverter *convert;
+
+  gboolean need_conversion_update;
+};
+
+struct _GstVideoMixer2PadClass
+{
+  GstPadClass parent_class;
+};
+
+GType gst_videomixer2_pad_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_VIDEO_MIXER2_PAD_H__ */
diff --git a/gst/videomixer/videomixerorc-dist.c b/gst/videomixer/videomixerorc-dist.c
new file mode 100644
index 0000000..dcc282b
--- /dev/null
+++ b/gst/videomixer/videomixerorc-dist.c
@@ -0,0 +1,2414 @@
+
+/* autogenerated from videomixerorc.orc */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <glib.h>
+
+#ifndef _ORC_INTEGER_TYPEDEFS_
+#define _ORC_INTEGER_TYPEDEFS_
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+typedef int8_t orc_int8;
+typedef int16_t orc_int16;
+typedef int32_t orc_int32;
+typedef int64_t orc_int64;
+typedef uint8_t orc_uint8;
+typedef uint16_t orc_uint16;
+typedef uint32_t orc_uint32;
+typedef uint64_t orc_uint64;
+#define ORC_UINT64_C(x) UINT64_C(x)
+#elif defined(_MSC_VER)
+typedef signed __int8 orc_int8;
+typedef signed __int16 orc_int16;
+typedef signed __int32 orc_int32;
+typedef signed __int64 orc_int64;
+typedef unsigned __int8 orc_uint8;
+typedef unsigned __int16 orc_uint16;
+typedef unsigned __int32 orc_uint32;
+typedef unsigned __int64 orc_uint64;
+#define ORC_UINT64_C(x) (x##Ui64)
+#define inline __inline
+#else
+#include <limits.h>
+typedef signed char orc_int8;
+typedef short orc_int16;
+typedef int orc_int32;
+typedef unsigned char orc_uint8;
+typedef unsigned short orc_uint16;
+typedef unsigned int orc_uint32;
+#if INT_MAX == LONG_MAX
+typedef long long orc_int64;
+typedef unsigned long long orc_uint64;
+#define ORC_UINT64_C(x) (x##ULL)
+#else
+typedef long orc_int64;
+typedef unsigned long orc_uint64;
+#define ORC_UINT64_C(x) (x##UL)
+#endif
+#endif
+typedef union
+{
+  orc_int16 i;
+  orc_int8 x2[2];
+} orc_union16;
+typedef union
+{
+  orc_int32 i;
+  float f;
+  orc_int16 x2[2];
+  orc_int8 x4[4];
+} orc_union32;
+typedef union
+{
+  orc_int64 i;
+  double f;
+  orc_int32 x2[2];
+  float x2f[2];
+  orc_int16 x4[4];
+} orc_union64;
+#endif
+#ifndef ORC_RESTRICT
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define ORC_RESTRICT restrict
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define ORC_RESTRICT __restrict__
+#else
+#define ORC_RESTRICT
+#endif
+#endif
+
+#ifndef ORC_INTERNAL
+#if defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#define ORC_INTERNAL __hidden
+#elif defined (__GNUC__)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#else
+#define ORC_INTERNAL
+#endif
+#endif
+
+
+#ifndef DISABLE_ORC
+#include <orc/orc.h>
+#endif
+void video_mixer_orc_splat_u32 (guint32 * ORC_RESTRICT d1, int p1, int n);
+void video_mixer_orc_memcpy_u32 (guint32 * ORC_RESTRICT d1,
+    const guint32 * ORC_RESTRICT s1, int n);
+void video_mixer_orc_blend_u8 (guint8 * ORC_RESTRICT d1, int d1_stride,
+    const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m);
+void video_mixer_orc_blend_argb (guint8 * ORC_RESTRICT d1, int d1_stride,
+    const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m);
+void video_mixer_orc_blend_bgra (guint8 * ORC_RESTRICT d1, int d1_stride,
+    const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m);
+void video_mixer_orc_overlay_argb (guint8 * ORC_RESTRICT d1, int d1_stride,
+    const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m);
+void video_mixer_orc_overlay_bgra (guint8 * ORC_RESTRICT d1, int d1_stride,
+    const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m);
+
+
+/* begin Orc C target preamble */
+#define ORC_CLAMP(x,a,b) ((x)<(a) ? (a) : ((x)>(b) ? (b) : (x)))
+#define ORC_ABS(a) ((a)<0 ? -(a) : (a))
+#define ORC_MIN(a,b) ((a)<(b) ? (a) : (b))
+#define ORC_MAX(a,b) ((a)>(b) ? (a) : (b))
+#define ORC_SB_MAX 127
+#define ORC_SB_MIN (-1-ORC_SB_MAX)
+#define ORC_UB_MAX (orc_uint8) 255
+#define ORC_UB_MIN 0
+#define ORC_SW_MAX 32767
+#define ORC_SW_MIN (-1-ORC_SW_MAX)
+#define ORC_UW_MAX (orc_uint16)65535
+#define ORC_UW_MIN 0
+#define ORC_SL_MAX 2147483647
+#define ORC_SL_MIN (-1-ORC_SL_MAX)
+#define ORC_UL_MAX 4294967295U
+#define ORC_UL_MIN 0
+#define ORC_CLAMP_SB(x) ORC_CLAMP(x,ORC_SB_MIN,ORC_SB_MAX)
+#define ORC_CLAMP_UB(x) ORC_CLAMP(x,ORC_UB_MIN,ORC_UB_MAX)
+#define ORC_CLAMP_SW(x) ORC_CLAMP(x,ORC_SW_MIN,ORC_SW_MAX)
+#define ORC_CLAMP_UW(x) ORC_CLAMP(x,ORC_UW_MIN,ORC_UW_MAX)
+#define ORC_CLAMP_SL(x) ORC_CLAMP(x,ORC_SL_MIN,ORC_SL_MAX)
+#define ORC_CLAMP_UL(x) ORC_CLAMP(x,ORC_UL_MIN,ORC_UL_MAX)
+#define ORC_SWAP_W(x) ((((x)&0xffU)<<8) | (((x)&0xff00U)>>8))
+#define ORC_SWAP_L(x) ((((x)&0xffU)<<24) | (((x)&0xff00U)<<8) | (((x)&0xff0000U)>>8) | (((x)&0xff000000U)>>24))
+#define ORC_SWAP_Q(x) ((((x)&ORC_UINT64_C(0xff))<<56) | (((x)&ORC_UINT64_C(0xff00))<<40) | (((x)&ORC_UINT64_C(0xff0000))<<24) | (((x)&ORC_UINT64_C(0xff000000))<<8) | (((x)&ORC_UINT64_C(0xff00000000))>>8) | (((x)&ORC_UINT64_C(0xff0000000000))>>24) | (((x)&ORC_UINT64_C(0xff000000000000))>>40) | (((x)&ORC_UINT64_C(0xff00000000000000))>>56))
+#define ORC_PTR_OFFSET(ptr,offset) ((void *)(((unsigned char *)(ptr)) + (offset)))
+#define ORC_DENORMAL(x) ((x) & ((((x)&0x7f800000) == 0) ? 0xff800000 : 0xffffffff))
+#define ORC_ISNAN(x) ((((x)&0x7f800000) == 0x7f800000) && (((x)&0x007fffff) != 0))
+#define ORC_DENORMAL_DOUBLE(x) ((x) & ((((x)&ORC_UINT64_C(0x7ff0000000000000)) == 0) ? ORC_UINT64_C(0xfff0000000000000) : ORC_UINT64_C(0xffffffffffffffff)))
+#define ORC_ISNAN_DOUBLE(x) ((((x)&ORC_UINT64_C(0x7ff0000000000000)) == ORC_UINT64_C(0x7ff0000000000000)) && (((x)&ORC_UINT64_C(0x000fffffffffffff)) != 0))
+#ifndef ORC_RESTRICT
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define ORC_RESTRICT restrict
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define ORC_RESTRICT __restrict__
+#else
+#define ORC_RESTRICT
+#endif
+#endif
+/* end Orc C target preamble */
+
+
+
+/* video_mixer_orc_splat_u32 */
+#ifdef DISABLE_ORC
+void
+video_mixer_orc_splat_u32 (guint32 * ORC_RESTRICT d1, int p1, int n)
+{
+  int i;
+  orc_union32 *ORC_RESTRICT ptr0;
+  orc_union32 var32;
+  orc_union32 var33;
+
+  ptr0 = (orc_union32 *) d1;
+
+  /* 0: loadpl */
+  var32.i = p1;
+
+  for (i = 0; i < n; i++) {
+    /* 1: copyl */
+    var33.i = var32.i;
+    /* 2: storel */
+    ptr0[i] = var33;
+  }
+
+}
+
+#else
+static void
+_backup_video_mixer_orc_splat_u32 (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union32 *ORC_RESTRICT ptr0;
+  orc_union32 var32;
+  orc_union32 var33;
+
+  ptr0 = (orc_union32 *) ex->arrays[0];
+
+  /* 0: loadpl */
+  var32.i = ex->params[24];
+
+  for (i = 0; i < n; i++) {
+    /* 1: copyl */
+    var33.i = var32.i;
+    /* 2: storel */
+    ptr0[i] = var33;
+  }
+
+}
+
+void
+video_mixer_orc_splat_u32 (guint32 * ORC_RESTRICT d1, int p1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 25, 118, 105, 100, 101, 111, 95, 109, 105, 120, 101, 114, 95, 111,
+        114, 99, 95, 115, 112, 108, 97, 116, 95, 117, 51, 50, 11, 4, 4, 16,
+        4, 112, 0, 24, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p, _backup_video_mixer_orc_splat_u32);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "video_mixer_orc_splat_u32");
+      orc_program_set_backup_function (p, _backup_video_mixer_orc_splat_u32);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_parameter (p, 4, "p1");
+
+      orc_program_append_2 (p, "copyl", 0, ORC_VAR_D1, ORC_VAR_P1, ORC_VAR_D1,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->params[ORC_VAR_P1] = p1;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* video_mixer_orc_memcpy_u32 */
+#ifdef DISABLE_ORC
+void
+video_mixer_orc_memcpy_u32 (guint32 * ORC_RESTRICT d1,
+    const guint32 * ORC_RESTRICT s1, int n)
+{
+  int i;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var32;
+  orc_union32 var33;
+
+  ptr0 = (orc_union32 *) d1;
+  ptr4 = (orc_union32 *) s1;
+
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var32 = ptr4[i];
+    /* 1: copyl */
+    var33.i = var32.i;
+    /* 2: storel */
+    ptr0[i] = var33;
+  }
+
+}
+
+#else
+static void
+_backup_video_mixer_orc_memcpy_u32 (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int n = ex->n;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union32 var32;
+  orc_union32 var33;
+
+  ptr0 = (orc_union32 *) ex->arrays[0];
+  ptr4 = (orc_union32 *) ex->arrays[4];
+
+
+  for (i = 0; i < n; i++) {
+    /* 0: loadl */
+    var32 = ptr4[i];
+    /* 1: copyl */
+    var33.i = var32.i;
+    /* 2: storel */
+    ptr0[i] = var33;
+  }
+
+}
+
+void
+video_mixer_orc_memcpy_u32 (guint32 * ORC_RESTRICT d1,
+    const guint32 * ORC_RESTRICT s1, int n)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 9, 26, 118, 105, 100, 101, 111, 95, 109, 105, 120, 101, 114, 95, 111,
+        114, 99, 95, 109, 101, 109, 99, 112, 121, 95, 117, 51, 50, 11, 4, 4,
+        12, 4, 4, 112, 0, 4, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p, _backup_video_mixer_orc_memcpy_u32);
+#else
+      p = orc_program_new ();
+      orc_program_set_name (p, "video_mixer_orc_memcpy_u32");
+      orc_program_set_backup_function (p, _backup_video_mixer_orc_memcpy_u32);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_source (p, 4, "s1");
+
+      orc_program_append_2 (p, "copyl", 0, ORC_VAR_D1, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* video_mixer_orc_blend_u8 */
+#ifdef DISABLE_ORC
+void
+video_mixer_orc_blend_u8 (guint8 * ORC_RESTRICT d1, int d1_stride,
+    const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
+{
+  int i;
+  int j;
+  orc_int8 *ORC_RESTRICT ptr0;
+  const orc_int8 *ORC_RESTRICT ptr4;
+  orc_int8 var34;
+  orc_int8 var35;
+  orc_union16 var36;
+  orc_int8 var37;
+  orc_union16 var38;
+  orc_union16 var39;
+  orc_union16 var40;
+  orc_union16 var41;
+  orc_union16 var42;
+  orc_union16 var43;
+  orc_union16 var44;
+
+  for (j = 0; j < m; j++) {
+    ptr0 = ORC_PTR_OFFSET (d1, d1_stride * j);
+    ptr4 = ORC_PTR_OFFSET (s1, s1_stride * j);
+
+    /* 5: loadpw */
+    var36.i = p1;
+
+    for (i = 0; i < n; i++) {
+      /* 0: loadb */
+      var34 = ptr0[i];
+      /* 1: convubw */
+      var38.i = (orc_uint8) var34;
+      /* 2: loadb */
+      var35 = ptr4[i];
+      /* 3: convubw */
+      var39.i = (orc_uint8) var35;
+      /* 4: subw */
+      var40.i = var39.i - var38.i;
+      /* 6: mullw */
+      var41.i = (var40.i * var36.i) & 0xffff;
+      /* 7: shlw */
+      var42.i = ((orc_uint16) var38.i) << 8;
+      /* 8: addw */
+      var43.i = var42.i + var41.i;
+      /* 9: shruw */
+      var44.i = ((orc_uint16) var43.i) >> 8;
+      /* 10: convsuswb */
+      var37 = ORC_CLAMP_UB (var44.i);
+      /* 11: storeb */
+      ptr0[i] = var37;
+    }
+  }
+
+}
+
+#else
+static void
+_backup_video_mixer_orc_blend_u8 (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int j;
+  int n = ex->n;
+  int m = ex->params[ORC_VAR_A1];
+  orc_int8 *ORC_RESTRICT ptr0;
+  const orc_int8 *ORC_RESTRICT ptr4;
+  orc_int8 var34;
+  orc_int8 var35;
+  orc_union16 var36;
+  orc_int8 var37;
+  orc_union16 var38;
+  orc_union16 var39;
+  orc_union16 var40;
+  orc_union16 var41;
+  orc_union16 var42;
+  orc_union16 var43;
+  orc_union16 var44;
+
+  for (j = 0; j < m; j++) {
+    ptr0 = ORC_PTR_OFFSET (ex->arrays[0], ex->params[0] * j);
+    ptr4 = ORC_PTR_OFFSET (ex->arrays[4], ex->params[4] * j);
+
+    /* 5: loadpw */
+    var36.i = ex->params[24];
+
+    for (i = 0; i < n; i++) {
+      /* 0: loadb */
+      var34 = ptr0[i];
+      /* 1: convubw */
+      var38.i = (orc_uint8) var34;
+      /* 2: loadb */
+      var35 = ptr4[i];
+      /* 3: convubw */
+      var39.i = (orc_uint8) var35;
+      /* 4: subw */
+      var40.i = var39.i - var38.i;
+      /* 6: mullw */
+      var41.i = (var40.i * var36.i) & 0xffff;
+      /* 7: shlw */
+      var42.i = ((orc_uint16) var38.i) << 8;
+      /* 8: addw */
+      var43.i = var42.i + var41.i;
+      /* 9: shruw */
+      var44.i = ((orc_uint16) var43.i) >> 8;
+      /* 10: convsuswb */
+      var37 = ORC_CLAMP_UB (var44.i);
+      /* 11: storeb */
+      ptr0[i] = var37;
+    }
+  }
+
+}
+
+void
+video_mixer_orc_blend_u8 (guint8 * ORC_RESTRICT d1, int d1_stride,
+    const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 7, 9, 24, 118, 105, 100, 101, 111, 95, 109, 105, 120, 101, 114, 95,
+        111, 114, 99, 95, 98, 108, 101, 110, 100, 95, 117, 56, 11, 1, 1, 12,
+        1, 1, 14, 1, 8, 0, 0, 0, 16, 2, 20, 2, 20, 2, 150, 32,
+        0, 150, 33, 4, 98, 33, 33, 32, 89, 33, 33, 24, 93, 32, 32, 16,
+        70, 33, 32, 33, 95, 33, 33, 16, 160, 0, 33, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p, _backup_video_mixer_orc_blend_u8);
+#else
+      p = orc_program_new ();
+      orc_program_set_2d (p);
+      orc_program_set_name (p, "video_mixer_orc_blend_u8");
+      orc_program_set_backup_function (p, _backup_video_mixer_orc_blend_u8);
+      orc_program_add_destination (p, 1, "d1");
+      orc_program_add_source (p, 1, "s1");
+      orc_program_add_constant (p, 1, 0x00000008, "c1");
+      orc_program_add_parameter (p, 2, "p1");
+      orc_program_add_temporary (p, 2, "t1");
+      orc_program_add_temporary (p, 2, "t2");
+
+      orc_program_append_2 (p, "convubw", 0, ORC_VAR_T1, ORC_VAR_D1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 0, ORC_VAR_T2, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "subw", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_T1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mullw", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "shlw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_C1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addw", 0, ORC_VAR_T2, ORC_VAR_T1, ORC_VAR_T2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "shruw", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_C1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convsuswb", 0, ORC_VAR_D1, ORC_VAR_T2,
+          ORC_VAR_D1, ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ORC_EXECUTOR_M (ex) = m;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->params[ORC_VAR_D1] = d1_stride;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  ex->params[ORC_VAR_S1] = s1_stride;
+  ex->params[ORC_VAR_P1] = p1;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* video_mixer_orc_blend_argb */
+#ifdef DISABLE_ORC
+void
+video_mixer_orc_blend_argb (guint8 * ORC_RESTRICT d1, int d1_stride,
+    const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
+{
+  int i;
+  int j;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union64 var39;
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union32 var40;
+#else
+  orc_union32 var40;
+#endif
+  orc_union32 var41;
+  orc_union16 var42;
+  orc_int8 var43;
+  orc_union32 var44;
+  orc_union64 var45;
+  orc_union64 var46;
+  orc_union64 var47;
+  orc_union64 var48;
+  orc_union32 var49;
+  orc_union64 var50;
+  orc_union64 var51;
+  orc_union64 var52;
+  orc_union64 var53;
+  orc_union64 var54;
+  orc_union32 var55;
+  orc_union32 var56;
+
+  for (j = 0; j < m; j++) {
+    ptr0 = ORC_PTR_OFFSET (d1, d1_stride * j);
+    ptr4 = ORC_PTR_OFFSET (s1, s1_stride * j);
+
+    /* 5: loadpw */
+    var39.x4[0] = p1;
+    var39.x4[1] = p1;
+    var39.x4[2] = p1;
+    var39.x4[3] = p1;
+    /* 16: loadpl */
+    var40.i = 0x000000ff;       /* 255 or 1.25987e-321f */
+
+    for (i = 0; i < n; i++) {
+      /* 0: loadl */
+      var41 = ptr4[i];
+      /* 1: convlw */
+      var42.i = var41.i;
+      /* 2: convwb */
+      var43 = var42.i;
+      /* 3: splatbl */
+      var44.i =
+          ((((orc_uint32) var43) & 0xff) << 24) | ((((orc_uint32) var43) & 0xff)
+          << 16) | ((((orc_uint32) var43) & 0xff) << 8) | (((orc_uint32) var43)
+          & 0xff);
+      /* 4: convubw */
+      var45.x4[0] = (orc_uint8) var44.x4[0];
+      var45.x4[1] = (orc_uint8) var44.x4[1];
+      var45.x4[2] = (orc_uint8) var44.x4[2];
+      var45.x4[3] = (orc_uint8) var44.x4[3];
+      /* 6: mullw */
+      var46.x4[0] = (var45.x4[0] * var39.x4[0]) & 0xffff;
+      var46.x4[1] = (var45.x4[1] * var39.x4[1]) & 0xffff;
+      var46.x4[2] = (var45.x4[2] * var39.x4[2]) & 0xffff;
+      var46.x4[3] = (var45.x4[3] * var39.x4[3]) & 0xffff;
+      /* 7: shruw */
+      var47.x4[0] = ((orc_uint16) var46.x4[0]) >> 8;
+      var47.x4[1] = ((orc_uint16) var46.x4[1]) >> 8;
+      var47.x4[2] = ((orc_uint16) var46.x4[2]) >> 8;
+      var47.x4[3] = ((orc_uint16) var46.x4[3]) >> 8;
+      /* 8: convubw */
+      var48.x4[0] = (orc_uint8) var41.x4[0];
+      var48.x4[1] = (orc_uint8) var41.x4[1];
+      var48.x4[2] = (orc_uint8) var41.x4[2];
+      var48.x4[3] = (orc_uint8) var41.x4[3];
+      /* 9: loadl */
+      var49 = ptr0[i];
+      /* 10: convubw */
+      var50.x4[0] = (orc_uint8) var49.x4[0];
+      var50.x4[1] = (orc_uint8) var49.x4[1];
+      var50.x4[2] = (orc_uint8) var49.x4[2];
+      var50.x4[3] = (orc_uint8) var49.x4[3];
+      /* 11: subw */
+      var51.x4[0] = var48.x4[0] - var50.x4[0];
+      var51.x4[1] = var48.x4[1] - var50.x4[1];
+      var51.x4[2] = var48.x4[2] - var50.x4[2];
+      var51.x4[3] = var48.x4[3] - var50.x4[3];
+      /* 12: mullw */
+      var52.x4[0] = (var51.x4[0] * var47.x4[0]) & 0xffff;
+      var52.x4[1] = (var51.x4[1] * var47.x4[1]) & 0xffff;
+      var52.x4[2] = (var51.x4[2] * var47.x4[2]) & 0xffff;
+      var52.x4[3] = (var51.x4[3] * var47.x4[3]) & 0xffff;
+      /* 13: div255w */
+      var53.x4[0] =
+          ((orc_uint16) (((orc_uint16) (var52.x4[0] + 128)) +
+              (((orc_uint16) (var52.x4[0] + 128)) >> 8))) >> 8;
+      var53.x4[1] =
+          ((orc_uint16) (((orc_uint16) (var52.x4[1] + 128)) +
+              (((orc_uint16) (var52.x4[1] + 128)) >> 8))) >> 8;
+      var53.x4[2] =
+          ((orc_uint16) (((orc_uint16) (var52.x4[2] + 128)) +
+              (((orc_uint16) (var52.x4[2] + 128)) >> 8))) >> 8;
+      var53.x4[3] =
+          ((orc_uint16) (((orc_uint16) (var52.x4[3] + 128)) +
+              (((orc_uint16) (var52.x4[3] + 128)) >> 8))) >> 8;
+      /* 14: addw */
+      var54.x4[0] = var50.x4[0] + var53.x4[0];
+      var54.x4[1] = var50.x4[1] + var53.x4[1];
+      var54.x4[2] = var50.x4[2] + var53.x4[2];
+      var54.x4[3] = var50.x4[3] + var53.x4[3];
+      /* 15: convwb */
+      var55.x4[0] = var54.x4[0];
+      var55.x4[1] = var54.x4[1];
+      var55.x4[2] = var54.x4[2];
+      var55.x4[3] = var54.x4[3];
+      /* 17: orl */
+      var56.i = var55.i | var40.i;
+      /* 18: storel */
+      ptr0[i] = var56;
+    }
+  }
+
+}
+
+#else
+static void
+_backup_video_mixer_orc_blend_argb (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int j;
+  int n = ex->n;
+  int m = ex->params[ORC_VAR_A1];
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union64 var39;
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union32 var40;
+#else
+  orc_union32 var40;
+#endif
+  orc_union32 var41;
+  orc_union16 var42;
+  orc_int8 var43;
+  orc_union32 var44;
+  orc_union64 var45;
+  orc_union64 var46;
+  orc_union64 var47;
+  orc_union64 var48;
+  orc_union32 var49;
+  orc_union64 var50;
+  orc_union64 var51;
+  orc_union64 var52;
+  orc_union64 var53;
+  orc_union64 var54;
+  orc_union32 var55;
+  orc_union32 var56;
+
+  for (j = 0; j < m; j++) {
+    ptr0 = ORC_PTR_OFFSET (ex->arrays[0], ex->params[0] * j);
+    ptr4 = ORC_PTR_OFFSET (ex->arrays[4], ex->params[4] * j);
+
+    /* 5: loadpw */
+    var39.x4[0] = ex->params[24];
+    var39.x4[1] = ex->params[24];
+    var39.x4[2] = ex->params[24];
+    var39.x4[3] = ex->params[24];
+    /* 16: loadpl */
+    var40.i = 0x000000ff;       /* 255 or 1.25987e-321f */
+
+    for (i = 0; i < n; i++) {
+      /* 0: loadl */
+      var41 = ptr4[i];
+      /* 1: convlw */
+      var42.i = var41.i;
+      /* 2: convwb */
+      var43 = var42.i;
+      /* 3: splatbl */
+      var44.i =
+          ((((orc_uint32) var43) & 0xff) << 24) | ((((orc_uint32) var43) & 0xff)
+          << 16) | ((((orc_uint32) var43) & 0xff) << 8) | (((orc_uint32) var43)
+          & 0xff);
+      /* 4: convubw */
+      var45.x4[0] = (orc_uint8) var44.x4[0];
+      var45.x4[1] = (orc_uint8) var44.x4[1];
+      var45.x4[2] = (orc_uint8) var44.x4[2];
+      var45.x4[3] = (orc_uint8) var44.x4[3];
+      /* 6: mullw */
+      var46.x4[0] = (var45.x4[0] * var39.x4[0]) & 0xffff;
+      var46.x4[1] = (var45.x4[1] * var39.x4[1]) & 0xffff;
+      var46.x4[2] = (var45.x4[2] * var39.x4[2]) & 0xffff;
+      var46.x4[3] = (var45.x4[3] * var39.x4[3]) & 0xffff;
+      /* 7: shruw */
+      var47.x4[0] = ((orc_uint16) var46.x4[0]) >> 8;
+      var47.x4[1] = ((orc_uint16) var46.x4[1]) >> 8;
+      var47.x4[2] = ((orc_uint16) var46.x4[2]) >> 8;
+      var47.x4[3] = ((orc_uint16) var46.x4[3]) >> 8;
+      /* 8: convubw */
+      var48.x4[0] = (orc_uint8) var41.x4[0];
+      var48.x4[1] = (orc_uint8) var41.x4[1];
+      var48.x4[2] = (orc_uint8) var41.x4[2];
+      var48.x4[3] = (orc_uint8) var41.x4[3];
+      /* 9: loadl */
+      var49 = ptr0[i];
+      /* 10: convubw */
+      var50.x4[0] = (orc_uint8) var49.x4[0];
+      var50.x4[1] = (orc_uint8) var49.x4[1];
+      var50.x4[2] = (orc_uint8) var49.x4[2];
+      var50.x4[3] = (orc_uint8) var49.x4[3];
+      /* 11: subw */
+      var51.x4[0] = var48.x4[0] - var50.x4[0];
+      var51.x4[1] = var48.x4[1] - var50.x4[1];
+      var51.x4[2] = var48.x4[2] - var50.x4[2];
+      var51.x4[3] = var48.x4[3] - var50.x4[3];
+      /* 12: mullw */
+      var52.x4[0] = (var51.x4[0] * var47.x4[0]) & 0xffff;
+      var52.x4[1] = (var51.x4[1] * var47.x4[1]) & 0xffff;
+      var52.x4[2] = (var51.x4[2] * var47.x4[2]) & 0xffff;
+      var52.x4[3] = (var51.x4[3] * var47.x4[3]) & 0xffff;
+      /* 13: div255w */
+      var53.x4[0] =
+          ((orc_uint16) (((orc_uint16) (var52.x4[0] + 128)) +
+              (((orc_uint16) (var52.x4[0] + 128)) >> 8))) >> 8;
+      var53.x4[1] =
+          ((orc_uint16) (((orc_uint16) (var52.x4[1] + 128)) +
+              (((orc_uint16) (var52.x4[1] + 128)) >> 8))) >> 8;
+      var53.x4[2] =
+          ((orc_uint16) (((orc_uint16) (var52.x4[2] + 128)) +
+              (((orc_uint16) (var52.x4[2] + 128)) >> 8))) >> 8;
+      var53.x4[3] =
+          ((orc_uint16) (((orc_uint16) (var52.x4[3] + 128)) +
+              (((orc_uint16) (var52.x4[3] + 128)) >> 8))) >> 8;
+      /* 14: addw */
+      var54.x4[0] = var50.x4[0] + var53.x4[0];
+      var54.x4[1] = var50.x4[1] + var53.x4[1];
+      var54.x4[2] = var50.x4[2] + var53.x4[2];
+      var54.x4[3] = var50.x4[3] + var53.x4[3];
+      /* 15: convwb */
+      var55.x4[0] = var54.x4[0];
+      var55.x4[1] = var54.x4[1];
+      var55.x4[2] = var54.x4[2];
+      var55.x4[3] = var54.x4[3];
+      /* 17: orl */
+      var56.i = var55.i | var40.i;
+      /* 18: storel */
+      ptr0[i] = var56;
+    }
+  }
+
+}
+
+void
+video_mixer_orc_blend_argb (guint8 * ORC_RESTRICT d1, int d1_stride,
+    const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 7, 9, 26, 118, 105, 100, 101, 111, 95, 109, 105, 120, 101, 114, 95,
+        111, 114, 99, 95, 98, 108, 101, 110, 100, 95, 97, 114, 103, 98, 11, 4,
+        4, 12, 4, 4, 14, 4, 255, 0, 0, 0, 14, 2, 8, 0, 0, 0,
+        16, 2, 20, 4, 20, 2, 20, 1, 20, 4, 20, 8, 20, 8, 20, 8,
+        113, 32, 4, 163, 33, 32, 157, 34, 33, 152, 35, 34, 21, 2, 150, 38,
+        35, 21, 2, 89, 38, 38, 24, 21, 2, 95, 38, 38, 17, 21, 2, 150,
+        37, 32, 113, 32, 0, 21, 2, 150, 36, 32, 21, 2, 98, 37, 37, 36,
+        21, 2, 89, 37, 37, 38, 21, 2, 80, 37, 37, 21, 2, 70, 36, 36,
+        37, 21, 2, 157, 32, 36, 123, 32, 32, 16, 128, 0, 32, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p, _backup_video_mixer_orc_blend_argb);
+#else
+      p = orc_program_new ();
+      orc_program_set_2d (p);
+      orc_program_set_name (p, "video_mixer_orc_blend_argb");
+      orc_program_set_backup_function (p, _backup_video_mixer_orc_blend_argb);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_source (p, 4, "s1");
+      orc_program_add_constant (p, 4, 0x000000ff, "c1");
+      orc_program_add_constant (p, 2, 0x00000008, "c2");
+      orc_program_add_parameter (p, 2, "p1");
+      orc_program_add_temporary (p, 4, "t1");
+      orc_program_add_temporary (p, 2, "t2");
+      orc_program_add_temporary (p, 1, "t3");
+      orc_program_add_temporary (p, 4, "t4");
+      orc_program_add_temporary (p, 8, "t5");
+      orc_program_add_temporary (p, 8, "t6");
+      orc_program_add_temporary (p, 8, "t7");
+
+      orc_program_append_2 (p, "loadl", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convlw", 0, ORC_VAR_T2, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convwb", 0, ORC_VAR_T3, ORC_VAR_T2, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "splatbl", 0, ORC_VAR_T4, ORC_VAR_T3, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T7, ORC_VAR_T4, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mullw", 2, ORC_VAR_T7, ORC_VAR_T7, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "shruw", 2, ORC_VAR_T7, ORC_VAR_T7, ORC_VAR_C2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T6, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "loadl", 0, ORC_VAR_T1, ORC_VAR_D1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T5, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "subw", 2, ORC_VAR_T6, ORC_VAR_T6, ORC_VAR_T5,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mullw", 2, ORC_VAR_T6, ORC_VAR_T6, ORC_VAR_T7,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "div255w", 2, ORC_VAR_T6, ORC_VAR_T6, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addw", 2, ORC_VAR_T5, ORC_VAR_T5, ORC_VAR_T6,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convwb", 2, ORC_VAR_T1, ORC_VAR_T5, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "orl", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_C1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "storel", 0, ORC_VAR_D1, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ORC_EXECUTOR_M (ex) = m;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->params[ORC_VAR_D1] = d1_stride;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  ex->params[ORC_VAR_S1] = s1_stride;
+  ex->params[ORC_VAR_P1] = p1;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* video_mixer_orc_blend_bgra */
+#ifdef DISABLE_ORC
+void
+video_mixer_orc_blend_bgra (guint8 * ORC_RESTRICT d1, int d1_stride,
+    const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
+{
+  int i;
+  int j;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union64 var40;
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union32 var41;
+#else
+  orc_union32 var41;
+#endif
+  orc_union32 var42;
+  orc_union32 var43;
+  orc_union16 var44;
+  orc_int8 var45;
+  orc_union32 var46;
+  orc_union64 var47;
+  orc_union64 var48;
+  orc_union64 var49;
+  orc_union64 var50;
+  orc_union32 var51;
+  orc_union64 var52;
+  orc_union64 var53;
+  orc_union64 var54;
+  orc_union64 var55;
+  orc_union64 var56;
+  orc_union32 var57;
+  orc_union32 var58;
+
+  for (j = 0; j < m; j++) {
+    ptr0 = ORC_PTR_OFFSET (d1, d1_stride * j);
+    ptr4 = ORC_PTR_OFFSET (s1, s1_stride * j);
+
+    /* 6: loadpw */
+    var40.x4[0] = p1;
+    var40.x4[1] = p1;
+    var40.x4[2] = p1;
+    var40.x4[3] = p1;
+    /* 17: loadpl */
+    var41.i = 0xff000000;       /* -16777216 or 2.11371e-314f */
+
+    for (i = 0; i < n; i++) {
+      /* 0: loadl */
+      var42 = ptr4[i];
+      /* 1: shrul */
+      var43.i = ((orc_uint32) var42.i) >> 24;
+      /* 2: convlw */
+      var44.i = var43.i;
+      /* 3: convwb */
+      var45 = var44.i;
+      /* 4: splatbl */
+      var46.i =
+          ((((orc_uint32) var45) & 0xff) << 24) | ((((orc_uint32) var45) & 0xff)
+          << 16) | ((((orc_uint32) var45) & 0xff) << 8) | (((orc_uint32) var45)
+          & 0xff);
+      /* 5: convubw */
+      var47.x4[0] = (orc_uint8) var46.x4[0];
+      var47.x4[1] = (orc_uint8) var46.x4[1];
+      var47.x4[2] = (orc_uint8) var46.x4[2];
+      var47.x4[3] = (orc_uint8) var46.x4[3];
+      /* 7: mullw */
+      var48.x4[0] = (var47.x4[0] * var40.x4[0]) & 0xffff;
+      var48.x4[1] = (var47.x4[1] * var40.x4[1]) & 0xffff;
+      var48.x4[2] = (var47.x4[2] * var40.x4[2]) & 0xffff;
+      var48.x4[3] = (var47.x4[3] * var40.x4[3]) & 0xffff;
+      /* 8: shruw */
+      var49.x4[0] = ((orc_uint16) var48.x4[0]) >> 8;
+      var49.x4[1] = ((orc_uint16) var48.x4[1]) >> 8;
+      var49.x4[2] = ((orc_uint16) var48.x4[2]) >> 8;
+      var49.x4[3] = ((orc_uint16) var48.x4[3]) >> 8;
+      /* 9: convubw */
+      var50.x4[0] = (orc_uint8) var42.x4[0];
+      var50.x4[1] = (orc_uint8) var42.x4[1];
+      var50.x4[2] = (orc_uint8) var42.x4[2];
+      var50.x4[3] = (orc_uint8) var42.x4[3];
+      /* 10: loadl */
+      var51 = ptr0[i];
+      /* 11: convubw */
+      var52.x4[0] = (orc_uint8) var51.x4[0];
+      var52.x4[1] = (orc_uint8) var51.x4[1];
+      var52.x4[2] = (orc_uint8) var51.x4[2];
+      var52.x4[3] = (orc_uint8) var51.x4[3];
+      /* 12: subw */
+      var53.x4[0] = var50.x4[0] - var52.x4[0];
+      var53.x4[1] = var50.x4[1] - var52.x4[1];
+      var53.x4[2] = var50.x4[2] - var52.x4[2];
+      var53.x4[3] = var50.x4[3] - var52.x4[3];
+      /* 13: mullw */
+      var54.x4[0] = (var53.x4[0] * var49.x4[0]) & 0xffff;
+      var54.x4[1] = (var53.x4[1] * var49.x4[1]) & 0xffff;
+      var54.x4[2] = (var53.x4[2] * var49.x4[2]) & 0xffff;
+      var54.x4[3] = (var53.x4[3] * var49.x4[3]) & 0xffff;
+      /* 14: div255w */
+      var55.x4[0] =
+          ((orc_uint16) (((orc_uint16) (var54.x4[0] + 128)) +
+              (((orc_uint16) (var54.x4[0] + 128)) >> 8))) >> 8;
+      var55.x4[1] =
+          ((orc_uint16) (((orc_uint16) (var54.x4[1] + 128)) +
+              (((orc_uint16) (var54.x4[1] + 128)) >> 8))) >> 8;
+      var55.x4[2] =
+          ((orc_uint16) (((orc_uint16) (var54.x4[2] + 128)) +
+              (((orc_uint16) (var54.x4[2] + 128)) >> 8))) >> 8;
+      var55.x4[3] =
+          ((orc_uint16) (((orc_uint16) (var54.x4[3] + 128)) +
+              (((orc_uint16) (var54.x4[3] + 128)) >> 8))) >> 8;
+      /* 15: addw */
+      var56.x4[0] = var52.x4[0] + var55.x4[0];
+      var56.x4[1] = var52.x4[1] + var55.x4[1];
+      var56.x4[2] = var52.x4[2] + var55.x4[2];
+      var56.x4[3] = var52.x4[3] + var55.x4[3];
+      /* 16: convwb */
+      var57.x4[0] = var56.x4[0];
+      var57.x4[1] = var56.x4[1];
+      var57.x4[2] = var56.x4[2];
+      var57.x4[3] = var56.x4[3];
+      /* 18: orl */
+      var58.i = var57.i | var41.i;
+      /* 19: storel */
+      ptr0[i] = var58;
+    }
+  }
+
+}
+
+#else
+static void
+_backup_video_mixer_orc_blend_bgra (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int j;
+  int n = ex->n;
+  int m = ex->params[ORC_VAR_A1];
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union64 var40;
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union32 var41;
+#else
+  orc_union32 var41;
+#endif
+  orc_union32 var42;
+  orc_union32 var43;
+  orc_union16 var44;
+  orc_int8 var45;
+  orc_union32 var46;
+  orc_union64 var47;
+  orc_union64 var48;
+  orc_union64 var49;
+  orc_union64 var50;
+  orc_union32 var51;
+  orc_union64 var52;
+  orc_union64 var53;
+  orc_union64 var54;
+  orc_union64 var55;
+  orc_union64 var56;
+  orc_union32 var57;
+  orc_union32 var58;
+
+  for (j = 0; j < m; j++) {
+    ptr0 = ORC_PTR_OFFSET (ex->arrays[0], ex->params[0] * j);
+    ptr4 = ORC_PTR_OFFSET (ex->arrays[4], ex->params[4] * j);
+
+    /* 6: loadpw */
+    var40.x4[0] = ex->params[24];
+    var40.x4[1] = ex->params[24];
+    var40.x4[2] = ex->params[24];
+    var40.x4[3] = ex->params[24];
+    /* 17: loadpl */
+    var41.i = 0xff000000;       /* -16777216 or 2.11371e-314f */
+
+    for (i = 0; i < n; i++) {
+      /* 0: loadl */
+      var42 = ptr4[i];
+      /* 1: shrul */
+      var43.i = ((orc_uint32) var42.i) >> 24;
+      /* 2: convlw */
+      var44.i = var43.i;
+      /* 3: convwb */
+      var45 = var44.i;
+      /* 4: splatbl */
+      var46.i =
+          ((((orc_uint32) var45) & 0xff) << 24) | ((((orc_uint32) var45) & 0xff)
+          << 16) | ((((orc_uint32) var45) & 0xff) << 8) | (((orc_uint32) var45)
+          & 0xff);
+      /* 5: convubw */
+      var47.x4[0] = (orc_uint8) var46.x4[0];
+      var47.x4[1] = (orc_uint8) var46.x4[1];
+      var47.x4[2] = (orc_uint8) var46.x4[2];
+      var47.x4[3] = (orc_uint8) var46.x4[3];
+      /* 7: mullw */
+      var48.x4[0] = (var47.x4[0] * var40.x4[0]) & 0xffff;
+      var48.x4[1] = (var47.x4[1] * var40.x4[1]) & 0xffff;
+      var48.x4[2] = (var47.x4[2] * var40.x4[2]) & 0xffff;
+      var48.x4[3] = (var47.x4[3] * var40.x4[3]) & 0xffff;
+      /* 8: shruw */
+      var49.x4[0] = ((orc_uint16) var48.x4[0]) >> 8;
+      var49.x4[1] = ((orc_uint16) var48.x4[1]) >> 8;
+      var49.x4[2] = ((orc_uint16) var48.x4[2]) >> 8;
+      var49.x4[3] = ((orc_uint16) var48.x4[3]) >> 8;
+      /* 9: convubw */
+      var50.x4[0] = (orc_uint8) var42.x4[0];
+      var50.x4[1] = (orc_uint8) var42.x4[1];
+      var50.x4[2] = (orc_uint8) var42.x4[2];
+      var50.x4[3] = (orc_uint8) var42.x4[3];
+      /* 10: loadl */
+      var51 = ptr0[i];
+      /* 11: convubw */
+      var52.x4[0] = (orc_uint8) var51.x4[0];
+      var52.x4[1] = (orc_uint8) var51.x4[1];
+      var52.x4[2] = (orc_uint8) var51.x4[2];
+      var52.x4[3] = (orc_uint8) var51.x4[3];
+      /* 12: subw */
+      var53.x4[0] = var50.x4[0] - var52.x4[0];
+      var53.x4[1] = var50.x4[1] - var52.x4[1];
+      var53.x4[2] = var50.x4[2] - var52.x4[2];
+      var53.x4[3] = var50.x4[3] - var52.x4[3];
+      /* 13: mullw */
+      var54.x4[0] = (var53.x4[0] * var49.x4[0]) & 0xffff;
+      var54.x4[1] = (var53.x4[1] * var49.x4[1]) & 0xffff;
+      var54.x4[2] = (var53.x4[2] * var49.x4[2]) & 0xffff;
+      var54.x4[3] = (var53.x4[3] * var49.x4[3]) & 0xffff;
+      /* 14: div255w */
+      var55.x4[0] =
+          ((orc_uint16) (((orc_uint16) (var54.x4[0] + 128)) +
+              (((orc_uint16) (var54.x4[0] + 128)) >> 8))) >> 8;
+      var55.x4[1] =
+          ((orc_uint16) (((orc_uint16) (var54.x4[1] + 128)) +
+              (((orc_uint16) (var54.x4[1] + 128)) >> 8))) >> 8;
+      var55.x4[2] =
+          ((orc_uint16) (((orc_uint16) (var54.x4[2] + 128)) +
+              (((orc_uint16) (var54.x4[2] + 128)) >> 8))) >> 8;
+      var55.x4[3] =
+          ((orc_uint16) (((orc_uint16) (var54.x4[3] + 128)) +
+              (((orc_uint16) (var54.x4[3] + 128)) >> 8))) >> 8;
+      /* 15: addw */
+      var56.x4[0] = var52.x4[0] + var55.x4[0];
+      var56.x4[1] = var52.x4[1] + var55.x4[1];
+      var56.x4[2] = var52.x4[2] + var55.x4[2];
+      var56.x4[3] = var52.x4[3] + var55.x4[3];
+      /* 16: convwb */
+      var57.x4[0] = var56.x4[0];
+      var57.x4[1] = var56.x4[1];
+      var57.x4[2] = var56.x4[2];
+      var57.x4[3] = var56.x4[3];
+      /* 18: orl */
+      var58.i = var57.i | var41.i;
+      /* 19: storel */
+      ptr0[i] = var58;
+    }
+  }
+
+}
+
+void
+video_mixer_orc_blend_bgra (guint8 * ORC_RESTRICT d1, int d1_stride,
+    const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 7, 9, 26, 118, 105, 100, 101, 111, 95, 109, 105, 120, 101, 114, 95,
+        111, 114, 99, 95, 98, 108, 101, 110, 100, 95, 98, 103, 114, 97, 11, 4,
+        4, 12, 4, 4, 14, 4, 0, 0, 0, 255, 14, 4, 24, 0, 0, 0,
+        14, 2, 8, 0, 0, 0, 16, 2, 20, 4, 20, 4, 20, 2, 20, 1,
+        20, 4, 20, 8, 20, 8, 20, 8, 113, 32, 4, 126, 33, 32, 17, 163,
+        34, 33, 157, 35, 34, 152, 36, 35, 21, 2, 150, 39, 36, 21, 2, 89,
+        39, 39, 24, 21, 2, 95, 39, 39, 18, 21, 2, 150, 38, 32, 113, 32,
+        0, 21, 2, 150, 37, 32, 21, 2, 98, 38, 38, 37, 21, 2, 89, 38,
+        38, 39, 21, 2, 80, 38, 38, 21, 2, 70, 37, 37, 38, 21, 2, 157,
+        32, 37, 123, 32, 32, 16, 128, 0, 32, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p, _backup_video_mixer_orc_blend_bgra);
+#else
+      p = orc_program_new ();
+      orc_program_set_2d (p);
+      orc_program_set_name (p, "video_mixer_orc_blend_bgra");
+      orc_program_set_backup_function (p, _backup_video_mixer_orc_blend_bgra);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_source (p, 4, "s1");
+      orc_program_add_constant (p, 4, 0xff000000, "c1");
+      orc_program_add_constant (p, 4, 0x00000018, "c2");
+      orc_program_add_constant (p, 2, 0x00000008, "c3");
+      orc_program_add_parameter (p, 2, "p1");
+      orc_program_add_temporary (p, 4, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+      orc_program_add_temporary (p, 2, "t3");
+      orc_program_add_temporary (p, 1, "t4");
+      orc_program_add_temporary (p, 4, "t5");
+      orc_program_add_temporary (p, 8, "t6");
+      orc_program_add_temporary (p, 8, "t7");
+      orc_program_add_temporary (p, 8, "t8");
+
+      orc_program_append_2 (p, "loadl", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "shrul", 0, ORC_VAR_T2, ORC_VAR_T1, ORC_VAR_C2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convlw", 0, ORC_VAR_T3, ORC_VAR_T2, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convwb", 0, ORC_VAR_T4, ORC_VAR_T3, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "splatbl", 0, ORC_VAR_T5, ORC_VAR_T4, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T8, ORC_VAR_T5, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mullw", 2, ORC_VAR_T8, ORC_VAR_T8, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "shruw", 2, ORC_VAR_T8, ORC_VAR_T8, ORC_VAR_C3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T7, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "loadl", 0, ORC_VAR_T1, ORC_VAR_D1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T6, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "subw", 2, ORC_VAR_T7, ORC_VAR_T7, ORC_VAR_T6,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mullw", 2, ORC_VAR_T7, ORC_VAR_T7, ORC_VAR_T8,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "div255w", 2, ORC_VAR_T7, ORC_VAR_T7, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addw", 2, ORC_VAR_T6, ORC_VAR_T6, ORC_VAR_T7,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convwb", 2, ORC_VAR_T1, ORC_VAR_T6, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "orl", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_C1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "storel", 0, ORC_VAR_D1, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ORC_EXECUTOR_M (ex) = m;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->params[ORC_VAR_D1] = d1_stride;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  ex->params[ORC_VAR_S1] = s1_stride;
+  ex->params[ORC_VAR_P1] = p1;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* video_mixer_orc_overlay_argb */
+#ifdef DISABLE_ORC
+void
+video_mixer_orc_overlay_argb (guint8 * ORC_RESTRICT d1, int d1_stride,
+    const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
+{
+  int i;
+  int j;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union64 var41;
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union32 var42;
+#else
+  orc_union32 var42;
+#endif
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union32 var43;
+#else
+  orc_union32 var43;
+#endif
+  orc_union32 var44;
+  orc_union16 var45;
+  orc_int8 var46;
+  orc_union32 var47;
+  orc_union64 var48;
+  orc_union64 var49;
+  orc_union64 var50;
+  orc_union64 var51;
+  orc_union64 var52;
+  orc_union32 var53;
+  orc_union64 var54;
+  orc_union64 var55;
+  orc_union32 var56;
+  orc_union16 var57;
+  orc_int8 var58;
+  orc_union32 var59;
+  orc_union64 var60;
+  orc_union64 var61;
+  orc_union64 var62;
+  orc_union64 var63;
+  orc_union64 var64;
+  orc_union64 var65;
+  orc_union64 var66;
+  orc_union64 var67;
+  orc_union32 var68;
+  orc_union32 var69;
+  orc_union32 var70;
+  orc_union32 var71;
+  orc_union32 var72;
+
+  for (j = 0; j < m; j++) {
+    ptr0 = ORC_PTR_OFFSET (d1, d1_stride * j);
+    ptr4 = ORC_PTR_OFFSET (s1, s1_stride * j);
+
+    /* 5: loadpw */
+    var41.x4[0] = p1;
+    var41.x4[1] = p1;
+    var41.x4[2] = p1;
+    var41.x4[3] = p1;
+    /* 10: loadpl */
+    var53.i = 0xffffffff;       /* -1 or 2.122e-314f */
+    /* 26: loadpl */
+    var42.i = 0xffffff00;       /* -256 or 2.122e-314f */
+    /* 29: loadpl */
+    var43.i = 0x000000ff;       /* 255 or 1.25987e-321f */
+
+    for (i = 0; i < n; i++) {
+      /* 0: loadl */
+      var44 = ptr4[i];
+      /* 1: convlw */
+      var45.i = var44.i;
+      /* 2: convwb */
+      var46 = var45.i;
+      /* 3: splatbl */
+      var47.i =
+          ((((orc_uint32) var46) & 0xff) << 24) | ((((orc_uint32) var46) & 0xff)
+          << 16) | ((((orc_uint32) var46) & 0xff) << 8) | (((orc_uint32) var46)
+          & 0xff);
+      /* 4: convubw */
+      var48.x4[0] = (orc_uint8) var47.x4[0];
+      var48.x4[1] = (orc_uint8) var47.x4[1];
+      var48.x4[2] = (orc_uint8) var47.x4[2];
+      var48.x4[3] = (orc_uint8) var47.x4[3];
+      /* 6: mullw */
+      var49.x4[0] = (var48.x4[0] * var41.x4[0]) & 0xffff;
+      var49.x4[1] = (var48.x4[1] * var41.x4[1]) & 0xffff;
+      var49.x4[2] = (var48.x4[2] * var41.x4[2]) & 0xffff;
+      var49.x4[3] = (var48.x4[3] * var41.x4[3]) & 0xffff;
+      /* 7: shruw */
+      var50.x4[0] = ((orc_uint16) var49.x4[0]) >> 8;
+      var50.x4[1] = ((orc_uint16) var49.x4[1]) >> 8;
+      var50.x4[2] = ((orc_uint16) var49.x4[2]) >> 8;
+      var50.x4[3] = ((orc_uint16) var49.x4[3]) >> 8;
+      /* 8: convubw */
+      var51.x4[0] = (orc_uint8) var44.x4[0];
+      var51.x4[1] = (orc_uint8) var44.x4[1];
+      var51.x4[2] = (orc_uint8) var44.x4[2];
+      var51.x4[3] = (orc_uint8) var44.x4[3];
+      /* 9: mullw */
+      var52.x4[0] = (var51.x4[0] * var50.x4[0]) & 0xffff;
+      var52.x4[1] = (var51.x4[1] * var50.x4[1]) & 0xffff;
+      var52.x4[2] = (var51.x4[2] * var50.x4[2]) & 0xffff;
+      var52.x4[3] = (var51.x4[3] * var50.x4[3]) & 0xffff;
+      /* 11: convubw */
+      var54.x4[0] = (orc_uint8) var53.x4[0];
+      var54.x4[1] = (orc_uint8) var53.x4[1];
+      var54.x4[2] = (orc_uint8) var53.x4[2];
+      var54.x4[3] = (orc_uint8) var53.x4[3];
+      /* 12: subw */
+      var55.x4[0] = var54.x4[0] - var50.x4[0];
+      var55.x4[1] = var54.x4[1] - var50.x4[1];
+      var55.x4[2] = var54.x4[2] - var50.x4[2];
+      var55.x4[3] = var54.x4[3] - var50.x4[3];
+      /* 13: loadl */
+      var56 = ptr0[i];
+      /* 14: convlw */
+      var57.i = var56.i;
+      /* 15: convwb */
+      var58 = var57.i;
+      /* 16: splatbl */
+      var59.i =
+          ((((orc_uint32) var58) & 0xff) << 24) | ((((orc_uint32) var58) & 0xff)
+          << 16) | ((((orc_uint32) var58) & 0xff) << 8) | (((orc_uint32) var58)
+          & 0xff);
+      /* 17: convubw */
+      var60.x4[0] = (orc_uint8) var59.x4[0];
+      var60.x4[1] = (orc_uint8) var59.x4[1];
+      var60.x4[2] = (orc_uint8) var59.x4[2];
+      var60.x4[3] = (orc_uint8) var59.x4[3];
+      /* 18: mullw */
+      var61.x4[0] = (var60.x4[0] * var55.x4[0]) & 0xffff;
+      var61.x4[1] = (var60.x4[1] * var55.x4[1]) & 0xffff;
+      var61.x4[2] = (var60.x4[2] * var55.x4[2]) & 0xffff;
+      var61.x4[3] = (var60.x4[3] * var55.x4[3]) & 0xffff;
+      /* 19: div255w */
+      var62.x4[0] =
+          ((orc_uint16) (((orc_uint16) (var61.x4[0] + 128)) +
+              (((orc_uint16) (var61.x4[0] + 128)) >> 8))) >> 8;
+      var62.x4[1] =
+          ((orc_uint16) (((orc_uint16) (var61.x4[1] + 128)) +
+              (((orc_uint16) (var61.x4[1] + 128)) >> 8))) >> 8;
+      var62.x4[2] =
+          ((orc_uint16) (((orc_uint16) (var61.x4[2] + 128)) +
+              (((orc_uint16) (var61.x4[2] + 128)) >> 8))) >> 8;
+      var62.x4[3] =
+          ((orc_uint16) (((orc_uint16) (var61.x4[3] + 128)) +
+              (((orc_uint16) (var61.x4[3] + 128)) >> 8))) >> 8;
+      /* 20: convubw */
+      var63.x4[0] = (orc_uint8) var56.x4[0];
+      var63.x4[1] = (orc_uint8) var56.x4[1];
+      var63.x4[2] = (orc_uint8) var56.x4[2];
+      var63.x4[3] = (orc_uint8) var56.x4[3];
+      /* 21: mullw */
+      var64.x4[0] = (var63.x4[0] * var62.x4[0]) & 0xffff;
+      var64.x4[1] = (var63.x4[1] * var62.x4[1]) & 0xffff;
+      var64.x4[2] = (var63.x4[2] * var62.x4[2]) & 0xffff;
+      var64.x4[3] = (var63.x4[3] * var62.x4[3]) & 0xffff;
+      /* 22: addw */
+      var65.x4[0] = var64.x4[0] + var52.x4[0];
+      var65.x4[1] = var64.x4[1] + var52.x4[1];
+      var65.x4[2] = var64.x4[2] + var52.x4[2];
+      var65.x4[3] = var64.x4[3] + var52.x4[3];
+      /* 23: addw */
+      var66.x4[0] = var62.x4[0] + var50.x4[0];
+      var66.x4[1] = var62.x4[1] + var50.x4[1];
+      var66.x4[2] = var62.x4[2] + var50.x4[2];
+      var66.x4[3] = var62.x4[3] + var50.x4[3];
+      /* 24: divluw */
+      var67.x4[0] =
+          ((var66.x4[0] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var65.x4[0]) /
+          ((orc_uint16) var66.x4[0] & 0xff));
+      var67.x4[1] =
+          ((var66.x4[1] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var65.x4[1]) /
+          ((orc_uint16) var66.x4[1] & 0xff));
+      var67.x4[2] =
+          ((var66.x4[2] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var65.x4[2]) /
+          ((orc_uint16) var66.x4[2] & 0xff));
+      var67.x4[3] =
+          ((var66.x4[3] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var65.x4[3]) /
+          ((orc_uint16) var66.x4[3] & 0xff));
+      /* 25: convwb */
+      var68.x4[0] = var67.x4[0];
+      var68.x4[1] = var67.x4[1];
+      var68.x4[2] = var67.x4[2];
+      var68.x4[3] = var67.x4[3];
+      /* 27: andl */
+      var69.i = var68.i & var42.i;
+      /* 28: convwb */
+      var70.x4[0] = var66.x4[0];
+      var70.x4[1] = var66.x4[1];
+      var70.x4[2] = var66.x4[2];
+      var70.x4[3] = var66.x4[3];
+      /* 30: andl */
+      var71.i = var70.i & var43.i;
+      /* 31: orl */
+      var72.i = var69.i | var71.i;
+      /* 32: storel */
+      ptr0[i] = var72;
+    }
+  }
+
+}
+
+#else
+static void
+_backup_video_mixer_orc_overlay_argb (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int j;
+  int n = ex->n;
+  int m = ex->params[ORC_VAR_A1];
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union64 var41;
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union32 var42;
+#else
+  orc_union32 var42;
+#endif
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union32 var43;
+#else
+  orc_union32 var43;
+#endif
+  orc_union32 var44;
+  orc_union16 var45;
+  orc_int8 var46;
+  orc_union32 var47;
+  orc_union64 var48;
+  orc_union64 var49;
+  orc_union64 var50;
+  orc_union64 var51;
+  orc_union64 var52;
+  orc_union32 var53;
+  orc_union64 var54;
+  orc_union64 var55;
+  orc_union32 var56;
+  orc_union16 var57;
+  orc_int8 var58;
+  orc_union32 var59;
+  orc_union64 var60;
+  orc_union64 var61;
+  orc_union64 var62;
+  orc_union64 var63;
+  orc_union64 var64;
+  orc_union64 var65;
+  orc_union64 var66;
+  orc_union64 var67;
+  orc_union32 var68;
+  orc_union32 var69;
+  orc_union32 var70;
+  orc_union32 var71;
+  orc_union32 var72;
+
+  for (j = 0; j < m; j++) {
+    ptr0 = ORC_PTR_OFFSET (ex->arrays[0], ex->params[0] * j);
+    ptr4 = ORC_PTR_OFFSET (ex->arrays[4], ex->params[4] * j);
+
+    /* 5: loadpw */
+    var41.x4[0] = ex->params[24];
+    var41.x4[1] = ex->params[24];
+    var41.x4[2] = ex->params[24];
+    var41.x4[3] = ex->params[24];
+    /* 10: loadpl */
+    var53.i = 0xffffffff;       /* -1 or 2.122e-314f */
+    /* 26: loadpl */
+    var42.i = 0xffffff00;       /* -256 or 2.122e-314f */
+    /* 29: loadpl */
+    var43.i = 0x000000ff;       /* 255 or 1.25987e-321f */
+
+    for (i = 0; i < n; i++) {
+      /* 0: loadl */
+      var44 = ptr4[i];
+      /* 1: convlw */
+      var45.i = var44.i;
+      /* 2: convwb */
+      var46 = var45.i;
+      /* 3: splatbl */
+      var47.i =
+          ((((orc_uint32) var46) & 0xff) << 24) | ((((orc_uint32) var46) & 0xff)
+          << 16) | ((((orc_uint32) var46) & 0xff) << 8) | (((orc_uint32) var46)
+          & 0xff);
+      /* 4: convubw */
+      var48.x4[0] = (orc_uint8) var47.x4[0];
+      var48.x4[1] = (orc_uint8) var47.x4[1];
+      var48.x4[2] = (orc_uint8) var47.x4[2];
+      var48.x4[3] = (orc_uint8) var47.x4[3];
+      /* 6: mullw */
+      var49.x4[0] = (var48.x4[0] * var41.x4[0]) & 0xffff;
+      var49.x4[1] = (var48.x4[1] * var41.x4[1]) & 0xffff;
+      var49.x4[2] = (var48.x4[2] * var41.x4[2]) & 0xffff;
+      var49.x4[3] = (var48.x4[3] * var41.x4[3]) & 0xffff;
+      /* 7: shruw */
+      var50.x4[0] = ((orc_uint16) var49.x4[0]) >> 8;
+      var50.x4[1] = ((orc_uint16) var49.x4[1]) >> 8;
+      var50.x4[2] = ((orc_uint16) var49.x4[2]) >> 8;
+      var50.x4[3] = ((orc_uint16) var49.x4[3]) >> 8;
+      /* 8: convubw */
+      var51.x4[0] = (orc_uint8) var44.x4[0];
+      var51.x4[1] = (orc_uint8) var44.x4[1];
+      var51.x4[2] = (orc_uint8) var44.x4[2];
+      var51.x4[3] = (orc_uint8) var44.x4[3];
+      /* 9: mullw */
+      var52.x4[0] = (var51.x4[0] * var50.x4[0]) & 0xffff;
+      var52.x4[1] = (var51.x4[1] * var50.x4[1]) & 0xffff;
+      var52.x4[2] = (var51.x4[2] * var50.x4[2]) & 0xffff;
+      var52.x4[3] = (var51.x4[3] * var50.x4[3]) & 0xffff;
+      /* 11: convubw */
+      var54.x4[0] = (orc_uint8) var53.x4[0];
+      var54.x4[1] = (orc_uint8) var53.x4[1];
+      var54.x4[2] = (orc_uint8) var53.x4[2];
+      var54.x4[3] = (orc_uint8) var53.x4[3];
+      /* 12: subw */
+      var55.x4[0] = var54.x4[0] - var50.x4[0];
+      var55.x4[1] = var54.x4[1] - var50.x4[1];
+      var55.x4[2] = var54.x4[2] - var50.x4[2];
+      var55.x4[3] = var54.x4[3] - var50.x4[3];
+      /* 13: loadl */
+      var56 = ptr0[i];
+      /* 14: convlw */
+      var57.i = var56.i;
+      /* 15: convwb */
+      var58 = var57.i;
+      /* 16: splatbl */
+      var59.i =
+          ((((orc_uint32) var58) & 0xff) << 24) | ((((orc_uint32) var58) & 0xff)
+          << 16) | ((((orc_uint32) var58) & 0xff) << 8) | (((orc_uint32) var58)
+          & 0xff);
+      /* 17: convubw */
+      var60.x4[0] = (orc_uint8) var59.x4[0];
+      var60.x4[1] = (orc_uint8) var59.x4[1];
+      var60.x4[2] = (orc_uint8) var59.x4[2];
+      var60.x4[3] = (orc_uint8) var59.x4[3];
+      /* 18: mullw */
+      var61.x4[0] = (var60.x4[0] * var55.x4[0]) & 0xffff;
+      var61.x4[1] = (var60.x4[1] * var55.x4[1]) & 0xffff;
+      var61.x4[2] = (var60.x4[2] * var55.x4[2]) & 0xffff;
+      var61.x4[3] = (var60.x4[3] * var55.x4[3]) & 0xffff;
+      /* 19: div255w */
+      var62.x4[0] =
+          ((orc_uint16) (((orc_uint16) (var61.x4[0] + 128)) +
+              (((orc_uint16) (var61.x4[0] + 128)) >> 8))) >> 8;
+      var62.x4[1] =
+          ((orc_uint16) (((orc_uint16) (var61.x4[1] + 128)) +
+              (((orc_uint16) (var61.x4[1] + 128)) >> 8))) >> 8;
+      var62.x4[2] =
+          ((orc_uint16) (((orc_uint16) (var61.x4[2] + 128)) +
+              (((orc_uint16) (var61.x4[2] + 128)) >> 8))) >> 8;
+      var62.x4[3] =
+          ((orc_uint16) (((orc_uint16) (var61.x4[3] + 128)) +
+              (((orc_uint16) (var61.x4[3] + 128)) >> 8))) >> 8;
+      /* 20: convubw */
+      var63.x4[0] = (orc_uint8) var56.x4[0];
+      var63.x4[1] = (orc_uint8) var56.x4[1];
+      var63.x4[2] = (orc_uint8) var56.x4[2];
+      var63.x4[3] = (orc_uint8) var56.x4[3];
+      /* 21: mullw */
+      var64.x4[0] = (var63.x4[0] * var62.x4[0]) & 0xffff;
+      var64.x4[1] = (var63.x4[1] * var62.x4[1]) & 0xffff;
+      var64.x4[2] = (var63.x4[2] * var62.x4[2]) & 0xffff;
+      var64.x4[3] = (var63.x4[3] * var62.x4[3]) & 0xffff;
+      /* 22: addw */
+      var65.x4[0] = var64.x4[0] + var52.x4[0];
+      var65.x4[1] = var64.x4[1] + var52.x4[1];
+      var65.x4[2] = var64.x4[2] + var52.x4[2];
+      var65.x4[3] = var64.x4[3] + var52.x4[3];
+      /* 23: addw */
+      var66.x4[0] = var62.x4[0] + var50.x4[0];
+      var66.x4[1] = var62.x4[1] + var50.x4[1];
+      var66.x4[2] = var62.x4[2] + var50.x4[2];
+      var66.x4[3] = var62.x4[3] + var50.x4[3];
+      /* 24: divluw */
+      var67.x4[0] =
+          ((var66.x4[0] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var65.x4[0]) /
+          ((orc_uint16) var66.x4[0] & 0xff));
+      var67.x4[1] =
+          ((var66.x4[1] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var65.x4[1]) /
+          ((orc_uint16) var66.x4[1] & 0xff));
+      var67.x4[2] =
+          ((var66.x4[2] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var65.x4[2]) /
+          ((orc_uint16) var66.x4[2] & 0xff));
+      var67.x4[3] =
+          ((var66.x4[3] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var65.x4[3]) /
+          ((orc_uint16) var66.x4[3] & 0xff));
+      /* 25: convwb */
+      var68.x4[0] = var67.x4[0];
+      var68.x4[1] = var67.x4[1];
+      var68.x4[2] = var67.x4[2];
+      var68.x4[3] = var67.x4[3];
+      /* 27: andl */
+      var69.i = var68.i & var42.i;
+      /* 28: convwb */
+      var70.x4[0] = var66.x4[0];
+      var70.x4[1] = var66.x4[1];
+      var70.x4[2] = var66.x4[2];
+      var70.x4[3] = var66.x4[3];
+      /* 30: andl */
+      var71.i = var70.i & var43.i;
+      /* 31: orl */
+      var72.i = var69.i | var71.i;
+      /* 32: storel */
+      ptr0[i] = var72;
+    }
+  }
+
+}
+
+void
+video_mixer_orc_overlay_argb (guint8 * ORC_RESTRICT d1, int d1_stride,
+    const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 7, 9, 28, 118, 105, 100, 101, 111, 95, 109, 105, 120, 101, 114, 95,
+        111, 114, 99, 95, 111, 118, 101, 114, 108, 97, 121, 95, 97, 114, 103,
+        98,
+        11, 4, 4, 12, 4, 4, 14, 4, 255, 255, 255, 255, 14, 4, 255, 0,
+        0, 0, 14, 4, 0, 255, 255, 255, 14, 2, 8, 0, 0, 0, 16, 2,
+        20, 4, 20, 2, 20, 1, 20, 8, 20, 8, 20, 8, 20, 4, 20, 8,
+        20, 8, 113, 32, 4, 163, 33, 32, 157, 34, 33, 152, 38, 34, 21, 2,
+        150, 35, 38, 21, 2, 89, 35, 35, 24, 21, 2, 95, 35, 35, 19, 21,
+        2, 150, 40, 32, 21, 2, 89, 40, 40, 35, 115, 38, 16, 21, 2, 150,
+        36, 38, 21, 2, 98, 36, 36, 35, 113, 32, 0, 163, 33, 32, 157, 34,
+        33, 152, 38, 34, 21, 2, 150, 37, 38, 21, 2, 89, 37, 37, 36, 21,
+        2, 80, 37, 37, 21, 2, 150, 39, 32, 21, 2, 89, 39, 39, 37, 21,
+        2, 70, 39, 39, 40, 21, 2, 70, 37, 37, 35, 21, 2, 81, 39, 39,
+        37, 21, 2, 157, 32, 39, 106, 32, 32, 18, 21, 2, 157, 38, 37, 106,
+        38, 38, 17, 123, 32, 32, 38, 128, 0, 32, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p, _backup_video_mixer_orc_overlay_argb);
+#else
+      p = orc_program_new ();
+      orc_program_set_2d (p);
+      orc_program_set_name (p, "video_mixer_orc_overlay_argb");
+      orc_program_set_backup_function (p, _backup_video_mixer_orc_overlay_argb);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_source (p, 4, "s1");
+      orc_program_add_constant (p, 4, 0xffffffff, "c1");
+      orc_program_add_constant (p, 4, 0x000000ff, "c2");
+      orc_program_add_constant (p, 4, 0xffffff00, "c3");
+      orc_program_add_constant (p, 2, 0x00000008, "c4");
+      orc_program_add_parameter (p, 2, "p1");
+      orc_program_add_temporary (p, 4, "t1");
+      orc_program_add_temporary (p, 2, "t2");
+      orc_program_add_temporary (p, 1, "t3");
+      orc_program_add_temporary (p, 8, "t4");
+      orc_program_add_temporary (p, 8, "t5");
+      orc_program_add_temporary (p, 8, "t6");
+      orc_program_add_temporary (p, 4, "t7");
+      orc_program_add_temporary (p, 8, "t8");
+      orc_program_add_temporary (p, 8, "t9");
+
+      orc_program_append_2 (p, "loadl", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convlw", 0, ORC_VAR_T2, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convwb", 0, ORC_VAR_T3, ORC_VAR_T2, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "splatbl", 0, ORC_VAR_T7, ORC_VAR_T3, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T4, ORC_VAR_T7, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mullw", 2, ORC_VAR_T4, ORC_VAR_T4, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "shruw", 2, ORC_VAR_T4, ORC_VAR_T4, ORC_VAR_C4,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T9, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mullw", 2, ORC_VAR_T9, ORC_VAR_T9, ORC_VAR_T4,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "loadpl", 0, ORC_VAR_T7, ORC_VAR_C1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T5, ORC_VAR_T7, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "subw", 2, ORC_VAR_T5, ORC_VAR_T5, ORC_VAR_T4,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "loadl", 0, ORC_VAR_T1, ORC_VAR_D1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convlw", 0, ORC_VAR_T2, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convwb", 0, ORC_VAR_T3, ORC_VAR_T2, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "splatbl", 0, ORC_VAR_T7, ORC_VAR_T3, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T6, ORC_VAR_T7, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mullw", 2, ORC_VAR_T6, ORC_VAR_T6, ORC_VAR_T5,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "div255w", 2, ORC_VAR_T6, ORC_VAR_T6, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T8, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mullw", 2, ORC_VAR_T8, ORC_VAR_T8, ORC_VAR_T6,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addw", 2, ORC_VAR_T8, ORC_VAR_T8, ORC_VAR_T9,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addw", 2, ORC_VAR_T6, ORC_VAR_T6, ORC_VAR_T4,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "divluw", 2, ORC_VAR_T8, ORC_VAR_T8, ORC_VAR_T6,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convwb", 2, ORC_VAR_T1, ORC_VAR_T8, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "andl", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_C3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convwb", 2, ORC_VAR_T7, ORC_VAR_T6, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "andl", 0, ORC_VAR_T7, ORC_VAR_T7, ORC_VAR_C2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "orl", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_T7,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "storel", 0, ORC_VAR_D1, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ORC_EXECUTOR_M (ex) = m;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->params[ORC_VAR_D1] = d1_stride;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  ex->params[ORC_VAR_S1] = s1_stride;
+  ex->params[ORC_VAR_P1] = p1;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
+
+
+/* video_mixer_orc_overlay_bgra */
+#ifdef DISABLE_ORC
+void
+video_mixer_orc_overlay_bgra (guint8 * ORC_RESTRICT d1, int d1_stride,
+    const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
+{
+  int i;
+  int j;
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union64 var42;
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union32 var43;
+#else
+  orc_union32 var43;
+#endif
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union32 var44;
+#else
+  orc_union32 var44;
+#endif
+  orc_union32 var45;
+  orc_union32 var46;
+  orc_union16 var47;
+  orc_int8 var48;
+  orc_union32 var49;
+  orc_union64 var50;
+  orc_union64 var51;
+  orc_union64 var52;
+  orc_union64 var53;
+  orc_union64 var54;
+  orc_union32 var55;
+  orc_union64 var56;
+  orc_union64 var57;
+  orc_union32 var58;
+  orc_union32 var59;
+  orc_union16 var60;
+  orc_int8 var61;
+  orc_union32 var62;
+  orc_union64 var63;
+  orc_union64 var64;
+  orc_union64 var65;
+  orc_union64 var66;
+  orc_union64 var67;
+  orc_union64 var68;
+  orc_union64 var69;
+  orc_union64 var70;
+  orc_union32 var71;
+  orc_union32 var72;
+  orc_union32 var73;
+  orc_union32 var74;
+  orc_union32 var75;
+
+  for (j = 0; j < m; j++) {
+    ptr0 = ORC_PTR_OFFSET (d1, d1_stride * j);
+    ptr4 = ORC_PTR_OFFSET (s1, s1_stride * j);
+
+    /* 6: loadpw */
+    var42.x4[0] = p1;
+    var42.x4[1] = p1;
+    var42.x4[2] = p1;
+    var42.x4[3] = p1;
+    /* 11: loadpl */
+    var55.i = 0xffffffff;       /* -1 or 2.122e-314f */
+    /* 28: loadpl */
+    var43.i = 0x00ffffff;       /* 16777215 or 8.28905e-317f */
+    /* 31: loadpl */
+    var44.i = 0xff000000;       /* -16777216 or 2.11371e-314f */
+
+    for (i = 0; i < n; i++) {
+      /* 0: loadl */
+      var45 = ptr4[i];
+      /* 1: shrul */
+      var46.i = ((orc_uint32) var45.i) >> 24;
+      /* 2: convlw */
+      var47.i = var46.i;
+      /* 3: convwb */
+      var48 = var47.i;
+      /* 4: splatbl */
+      var49.i =
+          ((((orc_uint32) var48) & 0xff) << 24) | ((((orc_uint32) var48) & 0xff)
+          << 16) | ((((orc_uint32) var48) & 0xff) << 8) | (((orc_uint32) var48)
+          & 0xff);
+      /* 5: convubw */
+      var50.x4[0] = (orc_uint8) var49.x4[0];
+      var50.x4[1] = (orc_uint8) var49.x4[1];
+      var50.x4[2] = (orc_uint8) var49.x4[2];
+      var50.x4[3] = (orc_uint8) var49.x4[3];
+      /* 7: mullw */
+      var51.x4[0] = (var50.x4[0] * var42.x4[0]) & 0xffff;
+      var51.x4[1] = (var50.x4[1] * var42.x4[1]) & 0xffff;
+      var51.x4[2] = (var50.x4[2] * var42.x4[2]) & 0xffff;
+      var51.x4[3] = (var50.x4[3] * var42.x4[3]) & 0xffff;
+      /* 8: shruw */
+      var52.x4[0] = ((orc_uint16) var51.x4[0]) >> 8;
+      var52.x4[1] = ((orc_uint16) var51.x4[1]) >> 8;
+      var52.x4[2] = ((orc_uint16) var51.x4[2]) >> 8;
+      var52.x4[3] = ((orc_uint16) var51.x4[3]) >> 8;
+      /* 9: convubw */
+      var53.x4[0] = (orc_uint8) var45.x4[0];
+      var53.x4[1] = (orc_uint8) var45.x4[1];
+      var53.x4[2] = (orc_uint8) var45.x4[2];
+      var53.x4[3] = (orc_uint8) var45.x4[3];
+      /* 10: mullw */
+      var54.x4[0] = (var53.x4[0] * var52.x4[0]) & 0xffff;
+      var54.x4[1] = (var53.x4[1] * var52.x4[1]) & 0xffff;
+      var54.x4[2] = (var53.x4[2] * var52.x4[2]) & 0xffff;
+      var54.x4[3] = (var53.x4[3] * var52.x4[3]) & 0xffff;
+      /* 12: convubw */
+      var56.x4[0] = (orc_uint8) var55.x4[0];
+      var56.x4[1] = (orc_uint8) var55.x4[1];
+      var56.x4[2] = (orc_uint8) var55.x4[2];
+      var56.x4[3] = (orc_uint8) var55.x4[3];
+      /* 13: subw */
+      var57.x4[0] = var56.x4[0] - var52.x4[0];
+      var57.x4[1] = var56.x4[1] - var52.x4[1];
+      var57.x4[2] = var56.x4[2] - var52.x4[2];
+      var57.x4[3] = var56.x4[3] - var52.x4[3];
+      /* 14: loadl */
+      var58 = ptr0[i];
+      /* 15: shrul */
+      var59.i = ((orc_uint32) var58.i) >> 24;
+      /* 16: convlw */
+      var60.i = var59.i;
+      /* 17: convwb */
+      var61 = var60.i;
+      /* 18: splatbl */
+      var62.i =
+          ((((orc_uint32) var61) & 0xff) << 24) | ((((orc_uint32) var61) & 0xff)
+          << 16) | ((((orc_uint32) var61) & 0xff) << 8) | (((orc_uint32) var61)
+          & 0xff);
+      /* 19: convubw */
+      var63.x4[0] = (orc_uint8) var62.x4[0];
+      var63.x4[1] = (orc_uint8) var62.x4[1];
+      var63.x4[2] = (orc_uint8) var62.x4[2];
+      var63.x4[3] = (orc_uint8) var62.x4[3];
+      /* 20: mullw */
+      var64.x4[0] = (var63.x4[0] * var57.x4[0]) & 0xffff;
+      var64.x4[1] = (var63.x4[1] * var57.x4[1]) & 0xffff;
+      var64.x4[2] = (var63.x4[2] * var57.x4[2]) & 0xffff;
+      var64.x4[3] = (var63.x4[3] * var57.x4[3]) & 0xffff;
+      /* 21: div255w */
+      var65.x4[0] =
+          ((orc_uint16) (((orc_uint16) (var64.x4[0] + 128)) +
+              (((orc_uint16) (var64.x4[0] + 128)) >> 8))) >> 8;
+      var65.x4[1] =
+          ((orc_uint16) (((orc_uint16) (var64.x4[1] + 128)) +
+              (((orc_uint16) (var64.x4[1] + 128)) >> 8))) >> 8;
+      var65.x4[2] =
+          ((orc_uint16) (((orc_uint16) (var64.x4[2] + 128)) +
+              (((orc_uint16) (var64.x4[2] + 128)) >> 8))) >> 8;
+      var65.x4[3] =
+          ((orc_uint16) (((orc_uint16) (var64.x4[3] + 128)) +
+              (((orc_uint16) (var64.x4[3] + 128)) >> 8))) >> 8;
+      /* 22: convubw */
+      var66.x4[0] = (orc_uint8) var58.x4[0];
+      var66.x4[1] = (orc_uint8) var58.x4[1];
+      var66.x4[2] = (orc_uint8) var58.x4[2];
+      var66.x4[3] = (orc_uint8) var58.x4[3];
+      /* 23: mullw */
+      var67.x4[0] = (var66.x4[0] * var65.x4[0]) & 0xffff;
+      var67.x4[1] = (var66.x4[1] * var65.x4[1]) & 0xffff;
+      var67.x4[2] = (var66.x4[2] * var65.x4[2]) & 0xffff;
+      var67.x4[3] = (var66.x4[3] * var65.x4[3]) & 0xffff;
+      /* 24: addw */
+      var68.x4[0] = var67.x4[0] + var54.x4[0];
+      var68.x4[1] = var67.x4[1] + var54.x4[1];
+      var68.x4[2] = var67.x4[2] + var54.x4[2];
+      var68.x4[3] = var67.x4[3] + var54.x4[3];
+      /* 25: addw */
+      var69.x4[0] = var65.x4[0] + var52.x4[0];
+      var69.x4[1] = var65.x4[1] + var52.x4[1];
+      var69.x4[2] = var65.x4[2] + var52.x4[2];
+      var69.x4[3] = var65.x4[3] + var52.x4[3];
+      /* 26: divluw */
+      var70.x4[0] =
+          ((var69.x4[0] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var68.x4[0]) /
+          ((orc_uint16) var69.x4[0] & 0xff));
+      var70.x4[1] =
+          ((var69.x4[1] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var68.x4[1]) /
+          ((orc_uint16) var69.x4[1] & 0xff));
+      var70.x4[2] =
+          ((var69.x4[2] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var68.x4[2]) /
+          ((orc_uint16) var69.x4[2] & 0xff));
+      var70.x4[3] =
+          ((var69.x4[3] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var68.x4[3]) /
+          ((orc_uint16) var69.x4[3] & 0xff));
+      /* 27: convwb */
+      var71.x4[0] = var70.x4[0];
+      var71.x4[1] = var70.x4[1];
+      var71.x4[2] = var70.x4[2];
+      var71.x4[3] = var70.x4[3];
+      /* 29: andl */
+      var72.i = var71.i & var43.i;
+      /* 30: convwb */
+      var73.x4[0] = var69.x4[0];
+      var73.x4[1] = var69.x4[1];
+      var73.x4[2] = var69.x4[2];
+      var73.x4[3] = var69.x4[3];
+      /* 32: andl */
+      var74.i = var73.i & var44.i;
+      /* 33: orl */
+      var75.i = var72.i | var74.i;
+      /* 34: storel */
+      ptr0[i] = var75;
+    }
+  }
+
+}
+
+#else
+static void
+_backup_video_mixer_orc_overlay_bgra (OrcExecutor * ORC_RESTRICT ex)
+{
+  int i;
+  int j;
+  int n = ex->n;
+  int m = ex->params[ORC_VAR_A1];
+  orc_union32 *ORC_RESTRICT ptr0;
+  const orc_union32 *ORC_RESTRICT ptr4;
+  orc_union64 var42;
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union32 var43;
+#else
+  orc_union32 var43;
+#endif
+#if defined(__APPLE__) && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && defined (__i386__)
+  volatile orc_union32 var44;
+#else
+  orc_union32 var44;
+#endif
+  orc_union32 var45;
+  orc_union32 var46;
+  orc_union16 var47;
+  orc_int8 var48;
+  orc_union32 var49;
+  orc_union64 var50;
+  orc_union64 var51;
+  orc_union64 var52;
+  orc_union64 var53;
+  orc_union64 var54;
+  orc_union32 var55;
+  orc_union64 var56;
+  orc_union64 var57;
+  orc_union32 var58;
+  orc_union32 var59;
+  orc_union16 var60;
+  orc_int8 var61;
+  orc_union32 var62;
+  orc_union64 var63;
+  orc_union64 var64;
+  orc_union64 var65;
+  orc_union64 var66;
+  orc_union64 var67;
+  orc_union64 var68;
+  orc_union64 var69;
+  orc_union64 var70;
+  orc_union32 var71;
+  orc_union32 var72;
+  orc_union32 var73;
+  orc_union32 var74;
+  orc_union32 var75;
+
+  for (j = 0; j < m; j++) {
+    ptr0 = ORC_PTR_OFFSET (ex->arrays[0], ex->params[0] * j);
+    ptr4 = ORC_PTR_OFFSET (ex->arrays[4], ex->params[4] * j);
+
+    /* 6: loadpw */
+    var42.x4[0] = ex->params[24];
+    var42.x4[1] = ex->params[24];
+    var42.x4[2] = ex->params[24];
+    var42.x4[3] = ex->params[24];
+    /* 11: loadpl */
+    var55.i = 0xffffffff;       /* -1 or 2.122e-314f */
+    /* 28: loadpl */
+    var43.i = 0x00ffffff;       /* 16777215 or 8.28905e-317f */
+    /* 31: loadpl */
+    var44.i = 0xff000000;       /* -16777216 or 2.11371e-314f */
+
+    for (i = 0; i < n; i++) {
+      /* 0: loadl */
+      var45 = ptr4[i];
+      /* 1: shrul */
+      var46.i = ((orc_uint32) var45.i) >> 24;
+      /* 2: convlw */
+      var47.i = var46.i;
+      /* 3: convwb */
+      var48 = var47.i;
+      /* 4: splatbl */
+      var49.i =
+          ((((orc_uint32) var48) & 0xff) << 24) | ((((orc_uint32) var48) & 0xff)
+          << 16) | ((((orc_uint32) var48) & 0xff) << 8) | (((orc_uint32) var48)
+          & 0xff);
+      /* 5: convubw */
+      var50.x4[0] = (orc_uint8) var49.x4[0];
+      var50.x4[1] = (orc_uint8) var49.x4[1];
+      var50.x4[2] = (orc_uint8) var49.x4[2];
+      var50.x4[3] = (orc_uint8) var49.x4[3];
+      /* 7: mullw */
+      var51.x4[0] = (var50.x4[0] * var42.x4[0]) & 0xffff;
+      var51.x4[1] = (var50.x4[1] * var42.x4[1]) & 0xffff;
+      var51.x4[2] = (var50.x4[2] * var42.x4[2]) & 0xffff;
+      var51.x4[3] = (var50.x4[3] * var42.x4[3]) & 0xffff;
+      /* 8: shruw */
+      var52.x4[0] = ((orc_uint16) var51.x4[0]) >> 8;
+      var52.x4[1] = ((orc_uint16) var51.x4[1]) >> 8;
+      var52.x4[2] = ((orc_uint16) var51.x4[2]) >> 8;
+      var52.x4[3] = ((orc_uint16) var51.x4[3]) >> 8;
+      /* 9: convubw */
+      var53.x4[0] = (orc_uint8) var45.x4[0];
+      var53.x4[1] = (orc_uint8) var45.x4[1];
+      var53.x4[2] = (orc_uint8) var45.x4[2];
+      var53.x4[3] = (orc_uint8) var45.x4[3];
+      /* 10: mullw */
+      var54.x4[0] = (var53.x4[0] * var52.x4[0]) & 0xffff;
+      var54.x4[1] = (var53.x4[1] * var52.x4[1]) & 0xffff;
+      var54.x4[2] = (var53.x4[2] * var52.x4[2]) & 0xffff;
+      var54.x4[3] = (var53.x4[3] * var52.x4[3]) & 0xffff;
+      /* 12: convubw */
+      var56.x4[0] = (orc_uint8) var55.x4[0];
+      var56.x4[1] = (orc_uint8) var55.x4[1];
+      var56.x4[2] = (orc_uint8) var55.x4[2];
+      var56.x4[3] = (orc_uint8) var55.x4[3];
+      /* 13: subw */
+      var57.x4[0] = var56.x4[0] - var52.x4[0];
+      var57.x4[1] = var56.x4[1] - var52.x4[1];
+      var57.x4[2] = var56.x4[2] - var52.x4[2];
+      var57.x4[3] = var56.x4[3] - var52.x4[3];
+      /* 14: loadl */
+      var58 = ptr0[i];
+      /* 15: shrul */
+      var59.i = ((orc_uint32) var58.i) >> 24;
+      /* 16: convlw */
+      var60.i = var59.i;
+      /* 17: convwb */
+      var61 = var60.i;
+      /* 18: splatbl */
+      var62.i =
+          ((((orc_uint32) var61) & 0xff) << 24) | ((((orc_uint32) var61) & 0xff)
+          << 16) | ((((orc_uint32) var61) & 0xff) << 8) | (((orc_uint32) var61)
+          & 0xff);
+      /* 19: convubw */
+      var63.x4[0] = (orc_uint8) var62.x4[0];
+      var63.x4[1] = (orc_uint8) var62.x4[1];
+      var63.x4[2] = (orc_uint8) var62.x4[2];
+      var63.x4[3] = (orc_uint8) var62.x4[3];
+      /* 20: mullw */
+      var64.x4[0] = (var63.x4[0] * var57.x4[0]) & 0xffff;
+      var64.x4[1] = (var63.x4[1] * var57.x4[1]) & 0xffff;
+      var64.x4[2] = (var63.x4[2] * var57.x4[2]) & 0xffff;
+      var64.x4[3] = (var63.x4[3] * var57.x4[3]) & 0xffff;
+      /* 21: div255w */
+      var65.x4[0] =
+          ((orc_uint16) (((orc_uint16) (var64.x4[0] + 128)) +
+              (((orc_uint16) (var64.x4[0] + 128)) >> 8))) >> 8;
+      var65.x4[1] =
+          ((orc_uint16) (((orc_uint16) (var64.x4[1] + 128)) +
+              (((orc_uint16) (var64.x4[1] + 128)) >> 8))) >> 8;
+      var65.x4[2] =
+          ((orc_uint16) (((orc_uint16) (var64.x4[2] + 128)) +
+              (((orc_uint16) (var64.x4[2] + 128)) >> 8))) >> 8;
+      var65.x4[3] =
+          ((orc_uint16) (((orc_uint16) (var64.x4[3] + 128)) +
+              (((orc_uint16) (var64.x4[3] + 128)) >> 8))) >> 8;
+      /* 22: convubw */
+      var66.x4[0] = (orc_uint8) var58.x4[0];
+      var66.x4[1] = (orc_uint8) var58.x4[1];
+      var66.x4[2] = (orc_uint8) var58.x4[2];
+      var66.x4[3] = (orc_uint8) var58.x4[3];
+      /* 23: mullw */
+      var67.x4[0] = (var66.x4[0] * var65.x4[0]) & 0xffff;
+      var67.x4[1] = (var66.x4[1] * var65.x4[1]) & 0xffff;
+      var67.x4[2] = (var66.x4[2] * var65.x4[2]) & 0xffff;
+      var67.x4[3] = (var66.x4[3] * var65.x4[3]) & 0xffff;
+      /* 24: addw */
+      var68.x4[0] = var67.x4[0] + var54.x4[0];
+      var68.x4[1] = var67.x4[1] + var54.x4[1];
+      var68.x4[2] = var67.x4[2] + var54.x4[2];
+      var68.x4[3] = var67.x4[3] + var54.x4[3];
+      /* 25: addw */
+      var69.x4[0] = var65.x4[0] + var52.x4[0];
+      var69.x4[1] = var65.x4[1] + var52.x4[1];
+      var69.x4[2] = var65.x4[2] + var52.x4[2];
+      var69.x4[3] = var65.x4[3] + var52.x4[3];
+      /* 26: divluw */
+      var70.x4[0] =
+          ((var69.x4[0] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var68.x4[0]) /
+          ((orc_uint16) var69.x4[0] & 0xff));
+      var70.x4[1] =
+          ((var69.x4[1] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var68.x4[1]) /
+          ((orc_uint16) var69.x4[1] & 0xff));
+      var70.x4[2] =
+          ((var69.x4[2] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var68.x4[2]) /
+          ((orc_uint16) var69.x4[2] & 0xff));
+      var70.x4[3] =
+          ((var69.x4[3] & 0xff) ==
+          0) ? 255 : ORC_CLAMP_UB (((orc_uint16) var68.x4[3]) /
+          ((orc_uint16) var69.x4[3] & 0xff));
+      /* 27: convwb */
+      var71.x4[0] = var70.x4[0];
+      var71.x4[1] = var70.x4[1];
+      var71.x4[2] = var70.x4[2];
+      var71.x4[3] = var70.x4[3];
+      /* 29: andl */
+      var72.i = var71.i & var43.i;
+      /* 30: convwb */
+      var73.x4[0] = var69.x4[0];
+      var73.x4[1] = var69.x4[1];
+      var73.x4[2] = var69.x4[2];
+      var73.x4[3] = var69.x4[3];
+      /* 32: andl */
+      var74.i = var73.i & var44.i;
+      /* 33: orl */
+      var75.i = var72.i | var74.i;
+      /* 34: storel */
+      ptr0[i] = var75;
+    }
+  }
+
+}
+
+void
+video_mixer_orc_overlay_bgra (guint8 * ORC_RESTRICT d1, int d1_stride,
+    const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
+{
+  OrcExecutor _ex, *ex = &_ex;
+  static volatile int p_inited = 0;
+  static OrcCode *c = 0;
+  void (*func) (OrcExecutor *);
+
+  if (!p_inited) {
+    orc_once_mutex_lock ();
+    if (!p_inited) {
+      OrcProgram *p;
+
+#if 1
+      static const orc_uint8 bc[] = {
+        1, 7, 9, 28, 118, 105, 100, 101, 111, 95, 109, 105, 120, 101, 114, 95,
+        111, 114, 99, 95, 111, 118, 101, 114, 108, 97, 121, 95, 98, 103, 114,
+        97,
+        11, 4, 4, 12, 4, 4, 14, 4, 255, 255, 255, 255, 14, 4, 0, 0,
+        0, 255, 14, 4, 255, 255, 255, 0, 14, 4, 24, 0, 0, 0, 14, 2,
+        8, 0, 0, 0, 16, 2, 20, 4, 20, 4, 20, 2, 20, 1, 20, 8,
+        20, 8, 20, 8, 20, 4, 20, 8, 20, 8, 113, 32, 4, 126, 33, 32,
+        19, 163, 34, 33, 157, 35, 34, 152, 39, 35, 21, 2, 150, 36, 39, 21,
+        2, 89, 36, 36, 24, 21, 2, 95, 36, 36, 20, 21, 2, 150, 41, 32,
+        21, 2, 89, 41, 41, 36, 115, 39, 16, 21, 2, 150, 37, 39, 21, 2,
+        98, 37, 37, 36, 113, 32, 0, 126, 33, 32, 19, 163, 34, 33, 157, 35,
+        34, 152, 39, 35, 21, 2, 150, 38, 39, 21, 2, 89, 38, 38, 37, 21,
+        2, 80, 38, 38, 21, 2, 150, 40, 32, 21, 2, 89, 40, 40, 38, 21,
+        2, 70, 40, 40, 41, 21, 2, 70, 38, 38, 36, 21, 2, 81, 40, 40,
+        38, 21, 2, 157, 32, 40, 106, 32, 32, 18, 21, 2, 157, 39, 38, 106,
+        39, 39, 17, 123, 32, 32, 39, 128, 0, 32, 2, 0,
+      };
+      p = orc_program_new_from_static_bytecode (bc);
+      orc_program_set_backup_function (p, _backup_video_mixer_orc_overlay_bgra);
+#else
+      p = orc_program_new ();
+      orc_program_set_2d (p);
+      orc_program_set_name (p, "video_mixer_orc_overlay_bgra");
+      orc_program_set_backup_function (p, _backup_video_mixer_orc_overlay_bgra);
+      orc_program_add_destination (p, 4, "d1");
+      orc_program_add_source (p, 4, "s1");
+      orc_program_add_constant (p, 4, 0xffffffff, "c1");
+      orc_program_add_constant (p, 4, 0xff000000, "c2");
+      orc_program_add_constant (p, 4, 0x00ffffff, "c3");
+      orc_program_add_constant (p, 4, 0x00000018, "c4");
+      orc_program_add_constant (p, 2, 0x00000008, "c5");
+      orc_program_add_parameter (p, 2, "p1");
+      orc_program_add_temporary (p, 4, "t1");
+      orc_program_add_temporary (p, 4, "t2");
+      orc_program_add_temporary (p, 2, "t3");
+      orc_program_add_temporary (p, 1, "t4");
+      orc_program_add_temporary (p, 8, "t5");
+      orc_program_add_temporary (p, 8, "t6");
+      orc_program_add_temporary (p, 8, "t7");
+      orc_program_add_temporary (p, 4, "t8");
+      orc_program_add_temporary (p, 8, "t9");
+      orc_program_add_temporary (p, 8, "t10");
+
+      orc_program_append_2 (p, "loadl", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "shrul", 0, ORC_VAR_T2, ORC_VAR_T1, ORC_VAR_C4,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convlw", 0, ORC_VAR_T3, ORC_VAR_T2, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convwb", 0, ORC_VAR_T4, ORC_VAR_T3, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "splatbl", 0, ORC_VAR_T8, ORC_VAR_T4, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T5, ORC_VAR_T8, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mullw", 2, ORC_VAR_T5, ORC_VAR_T5, ORC_VAR_P1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "shruw", 2, ORC_VAR_T5, ORC_VAR_T5, ORC_VAR_C5,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T10, ORC_VAR_T1,
+          ORC_VAR_D1, ORC_VAR_D1);
+      orc_program_append_2 (p, "mullw", 2, ORC_VAR_T10, ORC_VAR_T10, ORC_VAR_T5,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "loadpl", 0, ORC_VAR_T8, ORC_VAR_C1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T6, ORC_VAR_T8, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "subw", 2, ORC_VAR_T6, ORC_VAR_T6, ORC_VAR_T5,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "loadl", 0, ORC_VAR_T1, ORC_VAR_D1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "shrul", 0, ORC_VAR_T2, ORC_VAR_T1, ORC_VAR_C4,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convlw", 0, ORC_VAR_T3, ORC_VAR_T2, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convwb", 0, ORC_VAR_T4, ORC_VAR_T3, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "splatbl", 0, ORC_VAR_T8, ORC_VAR_T4, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T7, ORC_VAR_T8, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mullw", 2, ORC_VAR_T7, ORC_VAR_T7, ORC_VAR_T6,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "div255w", 2, ORC_VAR_T7, ORC_VAR_T7, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convubw", 2, ORC_VAR_T9, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "mullw", 2, ORC_VAR_T9, ORC_VAR_T9, ORC_VAR_T7,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addw", 2, ORC_VAR_T9, ORC_VAR_T9, ORC_VAR_T10,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "addw", 2, ORC_VAR_T7, ORC_VAR_T7, ORC_VAR_T5,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "divluw", 2, ORC_VAR_T9, ORC_VAR_T9, ORC_VAR_T7,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convwb", 2, ORC_VAR_T1, ORC_VAR_T9, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "andl", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_C3,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "convwb", 2, ORC_VAR_T8, ORC_VAR_T7, ORC_VAR_D1,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "andl", 0, ORC_VAR_T8, ORC_VAR_T8, ORC_VAR_C2,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "orl", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_T8,
+          ORC_VAR_D1);
+      orc_program_append_2 (p, "storel", 0, ORC_VAR_D1, ORC_VAR_T1, ORC_VAR_D1,
+          ORC_VAR_D1);
+#endif
+
+      orc_program_compile (p);
+      c = orc_program_take_code (p);
+      orc_program_free (p);
+    }
+    p_inited = TRUE;
+    orc_once_mutex_unlock ();
+  }
+  ex->arrays[ORC_VAR_A2] = c;
+  ex->program = 0;
+
+  ex->n = n;
+  ORC_EXECUTOR_M (ex) = m;
+  ex->arrays[ORC_VAR_D1] = d1;
+  ex->params[ORC_VAR_D1] = d1_stride;
+  ex->arrays[ORC_VAR_S1] = (void *) s1;
+  ex->params[ORC_VAR_S1] = s1_stride;
+  ex->params[ORC_VAR_P1] = p1;
+
+  func = c->exec;
+  func (ex);
+}
+#endif
diff --git a/gst/videomixer/videomixerorc-dist.h b/gst/videomixer/videomixerorc-dist.h
new file mode 100644
index 0000000..e0c070f
--- /dev/null
+++ b/gst/videomixer/videomixerorc-dist.h
@@ -0,0 +1,96 @@
+
+/* autogenerated from videomixerorc.orc */
+
+#ifndef _VIDEOMIXERORC_H_
+#define _VIDEOMIXERORC_H_
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#ifndef _ORC_INTEGER_TYPEDEFS_
+#define _ORC_INTEGER_TYPEDEFS_
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+typedef int8_t orc_int8;
+typedef int16_t orc_int16;
+typedef int32_t orc_int32;
+typedef int64_t orc_int64;
+typedef uint8_t orc_uint8;
+typedef uint16_t orc_uint16;
+typedef uint32_t orc_uint32;
+typedef uint64_t orc_uint64;
+#define ORC_UINT64_C(x) UINT64_C(x)
+#elif defined(_MSC_VER)
+typedef signed __int8 orc_int8;
+typedef signed __int16 orc_int16;
+typedef signed __int32 orc_int32;
+typedef signed __int64 orc_int64;
+typedef unsigned __int8 orc_uint8;
+typedef unsigned __int16 orc_uint16;
+typedef unsigned __int32 orc_uint32;
+typedef unsigned __int64 orc_uint64;
+#define ORC_UINT64_C(x) (x##Ui64)
+#define inline __inline
+#else
+#include <limits.h>
+typedef signed char orc_int8;
+typedef short orc_int16;
+typedef int orc_int32;
+typedef unsigned char orc_uint8;
+typedef unsigned short orc_uint16;
+typedef unsigned int orc_uint32;
+#if INT_MAX == LONG_MAX
+typedef long long orc_int64;
+typedef unsigned long long orc_uint64;
+#define ORC_UINT64_C(x) (x##ULL)
+#else
+typedef long orc_int64;
+typedef unsigned long orc_uint64;
+#define ORC_UINT64_C(x) (x##UL)
+#endif
+#endif
+typedef union { orc_int16 i; orc_int8 x2[2]; } orc_union16;
+typedef union { orc_int32 i; float f; orc_int16 x2[2]; orc_int8 x4[4]; } orc_union32;
+typedef union { orc_int64 i; double f; orc_int32 x2[2]; float x2f[2]; orc_int16 x4[4]; } orc_union64;
+#endif
+#ifndef ORC_RESTRICT
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define ORC_RESTRICT restrict
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define ORC_RESTRICT __restrict__
+#else
+#define ORC_RESTRICT
+#endif
+#endif
+
+#ifndef ORC_INTERNAL
+#if defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#define ORC_INTERNAL __hidden
+#elif defined (__GNUC__)
+#define ORC_INTERNAL __attribute__((visibility("hidden")))
+#else
+#define ORC_INTERNAL
+#endif
+#endif
+
+void video_mixer_orc_splat_u32 (guint32 * ORC_RESTRICT d1, int p1, int n);
+void video_mixer_orc_memcpy_u32 (guint32 * ORC_RESTRICT d1, const guint32 * ORC_RESTRICT s1, int n);
+void video_mixer_orc_blend_u8 (guint8 * ORC_RESTRICT d1, int d1_stride, const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m);
+void video_mixer_orc_blend_argb (guint8 * ORC_RESTRICT d1, int d1_stride, const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m);
+void video_mixer_orc_blend_bgra (guint8 * ORC_RESTRICT d1, int d1_stride, const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m);
+void video_mixer_orc_overlay_argb (guint8 * ORC_RESTRICT d1, int d1_stride, const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m);
+void video_mixer_orc_overlay_bgra (guint8 * ORC_RESTRICT d1, int d1_stride, const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/gst/videomixer/videomixerorc.orc b/gst/videomixer/videomixerorc.orc
new file mode 100644
index 0000000..8ba8237
--- /dev/null
+++ b/gst/videomixer/videomixerorc.orc
@@ -0,0 +1,221 @@
+.function video_mixer_orc_splat_u32
+.dest 4 d1 guint32
+.param 4 p1 guint32
+
+copyl d1, p1
+
+.function video_mixer_orc_memcpy_u32
+.dest 4 d1 guint32
+.source 4 s1 guint32
+
+copyl d1, s1
+
+.function video_mixer_orc_blend_u8
+.flags 2d
+.dest 1 d1 guint8
+.source 1 s1 guint8
+.param 2 p1
+.temp 2 t1
+.temp 2 t2
+.const 1 c1 8 
+
+convubw t1, d1
+convubw t2, s1
+subw t2, t2, t1
+mullw t2, t2, p1
+shlw t1, t1, c1
+addw t2, t1, t2
+shruw t2, t2, c1
+convsuswb d1, t2
+
+
+.function video_mixer_orc_blend_argb
+.flags 2d
+.dest 4 d guint8
+.source 4 s guint8
+.param 2 alpha
+.temp 4 t
+.temp 2 tw
+.temp 1 tb
+.temp 4 a
+.temp 8 d_wide
+.temp 8 s_wide
+.temp 8 a_wide
+.const 4 a_alpha 0x000000ff
+
+loadl t, s
+convlw tw, t
+convwb tb, tw
+splatbl a, tb
+x4 convubw a_wide, a
+x4 mullw a_wide, a_wide, alpha
+x4 shruw a_wide, a_wide, 8
+x4 convubw s_wide, t
+loadl t, d
+x4 convubw d_wide, t
+x4 subw s_wide, s_wide, d_wide
+x4 mullw s_wide, s_wide, a_wide
+x4 div255w s_wide, s_wide
+x4 addw d_wide, d_wide, s_wide
+x4 convwb t, d_wide
+orl t, t, a_alpha
+storel d, t
+
+.function video_mixer_orc_blend_bgra
+.flags 2d
+.dest 4 d guint8
+.source 4 s guint8
+.param 2 alpha
+.temp 4 t
+.temp 4 t2
+.temp 2 tw
+.temp 1 tb
+.temp 4 a
+.temp 8 d_wide
+.temp 8 s_wide
+.temp 8 a_wide
+.const 4 a_alpha 0xff000000
+
+loadl t, s
+shrul t2, t, 24
+convlw tw, t2
+convwb tb, tw
+splatbl a, tb
+x4 convubw a_wide, a
+x4 mullw a_wide, a_wide, alpha
+x4 shruw a_wide, a_wide, 8
+x4 convubw s_wide, t
+loadl t, d
+x4 convubw d_wide, t
+x4 subw s_wide, s_wide, d_wide
+x4 mullw s_wide, s_wide, a_wide
+x4 div255w s_wide, s_wide
+x4 addw d_wide, d_wide, s_wide
+x4 convwb t, d_wide
+orl t, t, a_alpha
+storel d, t
+
+
+.function video_mixer_orc_overlay_argb
+.flags 2d
+.dest 4 d guint8
+.source 4 s guint8
+.param 2 alpha
+.temp 4 t
+.temp 2 tw
+.temp 1 tb
+.temp 8 alpha_s
+.temp 8 alpha_s_inv
+.temp 8 alpha_d
+.temp 4 a
+.temp 8 d_wide
+.temp 8 s_wide
+.const 4 xfs 0xffffffff
+.const 4 a_alpha 0x000000ff
+.const 4 a_alpha_inv 0xffffff00
+
+# calc source alpha as alpha_s = alpha_s * alpha / 256
+loadl t, s
+convlw tw, t
+convwb tb, tw
+splatbl a, tb
+x4 convubw alpha_s, a
+x4 mullw alpha_s, alpha_s, alpha
+x4 shruw alpha_s, alpha_s, 8
+x4 convubw s_wide, t
+x4 mullw s_wide, s_wide, alpha_s
+
+# calc destination alpha as alpha_d = (255-alpha_s) * alpha_d / 255
+loadpl a, xfs
+x4 convubw alpha_s_inv, a
+x4 subw alpha_s_inv, alpha_s_inv, alpha_s
+loadl t, d
+convlw tw, t
+convwb tb, tw
+splatbl a, tb
+x4 convubw alpha_d, a
+x4 mullw alpha_d, alpha_d, alpha_s_inv
+x4 div255w alpha_d, alpha_d
+x4 convubw d_wide, t
+x4 mullw d_wide, d_wide, alpha_d
+
+# calc final pixel as pix_d = pix_s*alpha_s + pix_d*alpha_d*(255-alpha_s)/255
+x4 addw d_wide, d_wide, s_wide
+
+# calc the final destination alpha_d = alpha_s + alpha_d * (255-alpha_s)/255
+x4 addw alpha_d, alpha_d, alpha_s
+
+# now normalize the pix_d by the final alpha to make it associative
+x4 divluw, d_wide, d_wide, alpha_d
+
+# pack the new alpha into the correct spot
+x4 convwb t, d_wide
+andl t, t, a_alpha_inv
+x4 convwb a, alpha_d
+andl a, a, a_alpha
+orl  t, t, a
+storel d, t
+
+.function video_mixer_orc_overlay_bgra
+.flags 2d
+.dest 4 d guint8
+.source 4 s guint8
+.param 2 alpha
+.temp 4 t
+.temp 4 t2
+.temp 2 tw
+.temp 1 tb
+.temp 8 alpha_s
+.temp 8 alpha_s_inv
+.temp 8 alpha_d
+.temp 4 a
+.temp 8 d_wide
+.temp 8 s_wide
+.const 4 xfs 0xffffffff
+.const 4 a_alpha 0xff000000
+.const 4 a_alpha_inv 0x00ffffff
+
+# calc source alpha as alpha_s = alpha_s * alpha / 256
+loadl t, s
+shrul t2, t, 24
+convlw tw, t2
+convwb tb, tw
+splatbl a, tb
+x4 convubw alpha_s, a
+x4 mullw alpha_s, alpha_s, alpha
+x4 shruw alpha_s, alpha_s, 8
+x4 convubw s_wide, t
+x4 mullw s_wide, s_wide, alpha_s
+
+# calc destination alpha as alpha_d = (255-alpha_s) * alpha_d / 255
+loadpl a, xfs
+x4 convubw alpha_s_inv, a
+x4 subw alpha_s_inv, alpha_s_inv, alpha_s
+loadl t, d
+shrul t2, t, 24
+convlw tw, t2
+convwb tb, tw
+splatbl a, tb
+x4 convubw alpha_d, a
+x4 mullw alpha_d, alpha_d, alpha_s_inv
+x4 div255w alpha_d, alpha_d
+x4 convubw d_wide, t
+x4 mullw d_wide, d_wide, alpha_d
+
+# calc final pixel as pix_d = pix_s*alpha_s + pix_d*alpha_d*(255-alpha_s)/255
+x4 addw d_wide, d_wide, s_wide
+
+# calc the final destination alpha_d = alpha_s + alpha_d * (255-alpha_s)/255
+x4 addw alpha_d, alpha_d, alpha_s
+
+# now normalize the pix_d by the final alpha to make it associative
+x4 divluw, d_wide, d_wide, alpha_d
+
+# pack the new alpha into the correct spot
+x4 convwb t, d_wide
+andl t, t, a_alpha_inv
+x4 convwb a, alpha_d
+andl a, a, a_alpha
+orl  t, t, a
+storel d, t
+
diff --git a/gst/wavenc/Makefile.am b/gst/wavenc/Makefile.am
new file mode 100644
index 0000000..1ee661d
--- /dev/null
+++ b/gst/wavenc/Makefile.am
@@ -0,0 +1,16 @@
+plugin_LTLIBRARIES = libgstwavenc.la
+
+libgstwavenc_la_SOURCES = gstwavenc.c
+libgstwavenc_la_CFLAGS =  \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS)
+libgstwavenc_la_LIBADD = 	\
+	$(GST_PLUGINS_BASE_LIBS) \
+	-lgstaudio-@GST_API_VERSION@ \
+	-lgstriff-@GST_API_VERSION@ \
+	$(GST_BASE_LIBS) \
+	$(GST_LIBS)
+libgstwavenc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstwavenc.h
diff --git a/gst/wavenc/gstwavenc.c b/gst/wavenc/gstwavenc.c
new file mode 100644
index 0000000..94a8bd0
--- /dev/null
+++ b/gst/wavenc/gstwavenc.c
@@ -0,0 +1,1145 @@
+/* -*- mOde: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
+/* GStreamer .wav encoder
+ * Copyright (C) <2002> Iain Holmes <iain@prettypeople.org>
+ * Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * 
+ */
+/**
+ * SECTION:element-wavenc
+ *
+ * Format an audio stream into the wav format.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 cdparanoiasrc mode=continuous ! queue ! audioconvert ! wavenc ! filesink location=cd.wav
+ * ]| Rip a whole audio CD into a single wav file, with the track table written into a CUE sheet inside the file
+ * |[
+ * gst-launch-1.0 cdparanoiasrc track=5 ! queue ! audioconvert ! wavenc ! filesink location=track5.wav
+ * ]| Rip track 5 of an audio CD into a single wav file containing unencoded raw audio samples.
+ * </refsect2>
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include "gstwavenc.h"
+
+#include <gst/audio/audio.h>
+#include <gst/riff/riff-media.h>
+#include <gst/base/gstbytewriter.h>
+
+GST_DEBUG_CATEGORY_STATIC (wavenc_debug);
+#define GST_CAT_DEFAULT wavenc_debug
+
+typedef struct
+{
+  /* Offset Size    Description   Value
+   * 0x00   4       ID            unique identification value
+   * 0x04   4       Position      play order position
+   * 0x08   4       Data Chunk ID RIFF ID of corresponding data chunk
+   * 0x0c   4       Chunk Start   Byte Offset of Data Chunk *
+   * 0x10   4       Block Start   Byte Offset to sample of First Channel
+   * 0x14   4       Sample Offset Byte Offset to sample byte of First Channel
+   */
+  guint32 id;
+  guint32 position;
+  guint8 data_chunk_id[4];
+  guint32 chunk_start;
+  guint32 block_start;
+  guint32 sample_offset;
+} GstWavEncCue;
+
+typedef struct
+{
+  /* Offset Size    Description     Value
+   * 0x00   4       Chunk ID        "labl" (0x6C61626C) or "note" (0x6E6F7465)
+   * 0x04   4       Chunk Data Size depends on contained text
+   * 0x08   4       Cue Point ID    0 - 0xFFFFFFFF
+   * 0x0c           Text
+   */
+  guint8 chunk_id[4];
+  guint32 chunk_data_size;
+  guint32 cue_point_id;
+  gchar *text;
+} GstWavEncLabl, GstWavEncNote;
+
+/* FIXME: mono doesn't produce correct files it seems, at least mplayer xruns */
+#define SINK_CAPS \
+    "audio/x-raw, "                      \
+    "rate = (int) [ 1, MAX ], "          \
+    "channels = (int) [ 1, 65535 ], "      \
+    "format = (string) { S32LE, S24LE, S16LE, U8, F32LE, F64LE }, " \
+    "layout = (string) interleaved"      \
+    "; "                                 \
+    "audio/x-alaw, "                     \
+    "rate = (int) [ 8000, 192000 ], "    \
+    "channels = (int) [ 1, 2 ]; "        \
+    "audio/x-mulaw, "                    \
+    "rate = (int) [ 8000, 192000 ], "    \
+    "channels = (int) [ 1, 2 ]"
+
+#define SRC_CAPS \
+    "audio/x-wav; " \
+    "audio/x-rf64"
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SINK_CAPS)
+    );
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SRC_CAPS)
+    );
+
+#define gst_wavenc_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstWavEnc, gst_wavenc, GST_TYPE_ELEMENT,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL)
+    G_IMPLEMENT_INTERFACE (GST_TYPE_TOC_SETTER, NULL)
+    );
+
+static GstFlowReturn gst_wavenc_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buf);
+static gboolean gst_wavenc_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static GstStateChangeReturn gst_wavenc_change_state (GstElement * element,
+    GstStateChange transition);
+static gboolean gst_wavenc_sink_setcaps (GstPad * pad, GstCaps * caps);
+
+static void
+gst_wavenc_class_init (GstWavEncClass * klass)
+{
+  GstElementClass *element_class;
+
+  element_class = (GstElementClass *) klass;
+
+  element_class->change_state = GST_DEBUG_FUNCPTR (gst_wavenc_change_state);
+
+  gst_element_class_set_static_metadata (element_class, "WAV audio muxer",
+      "Codec/Muxer/Audio",
+      "Encode raw audio into WAV", "Iain Holmes <iain@prettypeople.org>");
+
+  gst_element_class_add_static_pad_template (element_class, &src_factory);
+  gst_element_class_add_static_pad_template (element_class, &sink_factory);
+
+  GST_DEBUG_CATEGORY_INIT (wavenc_debug, "wavenc", 0, "WAV encoder element");
+}
+
+static void
+gst_wavenc_init (GstWavEnc * wavenc)
+{
+  wavenc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
+  gst_pad_set_chain_function (wavenc->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_wavenc_chain));
+  gst_pad_set_event_function (wavenc->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_wavenc_event));
+  gst_pad_use_fixed_caps (wavenc->sinkpad);
+  gst_element_add_pad (GST_ELEMENT (wavenc), wavenc->sinkpad);
+
+  wavenc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
+  gst_pad_use_fixed_caps (wavenc->srcpad);
+  gst_element_add_pad (GST_ELEMENT (wavenc), wavenc->srcpad);
+}
+
+#define RIFF_CHUNK_LEN    12
+#define FMT_WAV_CHUNK_LEN 24
+#define FMT_EXT_CHUNK_LEN 48
+#define FACT_CHUNK_LEN    12
+#define DATA_HEADER_LEN   8
+#define DS64_CHUNK_LEN    36
+
+static gboolean
+use_format_ext (GstWavEnc * wavenc)
+{
+  return wavenc->channels > 2;
+}
+
+static gboolean
+use_fact_chunk (GstWavEnc * wavenc)
+{
+  return use_format_ext (wavenc) && !wavenc->use_rf64;
+}
+
+static int
+get_header_len (GstWavEnc * wavenc)
+{
+  int len = RIFF_CHUNK_LEN;
+
+  if (use_format_ext (wavenc))
+    len += FMT_EXT_CHUNK_LEN;
+  else
+    len += FMT_WAV_CHUNK_LEN;
+
+  if (use_fact_chunk (wavenc))
+    len += FACT_CHUNK_LEN;
+
+  if (wavenc->use_rf64)
+    len += DS64_CHUNK_LEN;
+
+  return len + DATA_HEADER_LEN;
+}
+
+static guint64
+gstmask_to_wavmask (guint64 gstmask, GstAudioChannelPosition * pos)
+{
+  const GstAudioChannelPosition valid_pos =
+      GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT |
+      GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT |
+      GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER |
+      GST_AUDIO_CHANNEL_POSITION_LFE1 |
+      GST_AUDIO_CHANNEL_POSITION_REAR_LEFT |
+      GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT |
+      GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER |
+      GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER |
+      GST_AUDIO_CHANNEL_POSITION_REAR_CENTER |
+      GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT |
+      GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT |
+      GST_AUDIO_CHANNEL_POSITION_TOP_CENTER |
+      GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT |
+      GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER |
+      GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT |
+      GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT |
+      GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER |
+      GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT;
+
+  const GstAudioChannelPosition wav_pos[] = {
+    GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+    GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+    GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+    GST_AUDIO_CHANNEL_POSITION_LFE1,
+    GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+    GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+    GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
+    GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
+    GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
+    GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+    GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+    GST_AUDIO_CHANNEL_POSITION_TOP_CENTER,
+    GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT,
+    GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER,
+    GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT,
+    GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT,
+    GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER,
+    GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT,
+  };
+  int k;
+  int chan = 0;
+  guint64 ret = 0;
+  guint64 mask = 1;
+
+  if (gstmask == 0 || ((gstmask & ~valid_pos) != 0))
+    return 0;
+
+  for (k = 0; k < G_N_ELEMENTS (wav_pos); ++k) {
+    if (gstmask & wav_pos[k]) {
+      ret |= mask;
+      pos[chan++] = wav_pos[k];
+    }
+    mask <<= 1;
+  }
+
+  return ret;
+}
+
+static guint8 *
+write_fmt_chunk (GstWavEnc * wavenc, guint8 * header)
+{
+  guint16 wBlockAlign;
+
+  wBlockAlign = (wavenc->width / 8) * wavenc->channels;
+
+  memcpy (header, "fmt ", 4);
+  /* wChannels */
+  GST_WRITE_UINT16_LE (header + 10, wavenc->channels);
+  /* dwSamplesPerSec */
+  GST_WRITE_UINT32_LE (header + 12, wavenc->rate);
+  /* dwAvgBytesPerSec */
+  GST_WRITE_UINT32_LE (header + 16, wBlockAlign * wavenc->rate);
+  /* wBlockAlign */
+  GST_WRITE_UINT16_LE (header + 20, wBlockAlign);
+  /* wBitsPerSample */
+  GST_WRITE_UINT16_LE (header + 22, wavenc->width);
+
+  if (use_format_ext (wavenc)) {
+    GST_DEBUG_OBJECT (wavenc, "Using WAVE_FORMAT_EXTENSIBLE");
+
+    GST_WRITE_UINT32_LE (header + 4, FMT_EXT_CHUNK_LEN - 8);
+
+    /* wFormatTag */
+    GST_WRITE_UINT16_LE (header + 8, 0xFFFE);
+    /* cbSize */
+    GST_WRITE_UINT16_LE (header + 24, 22);
+    /* wValidBitsPerSample */
+    GST_WRITE_UINT16_LE (header + 26, wavenc->width);
+    /* dwChannelMask */
+    GST_WRITE_UINT32_LE (header + 28, (guint32) wavenc->channel_mask);
+
+    GST_WRITE_UINT16_LE (header + 32, wavenc->format);
+
+    memcpy (header + 34,
+        "\x00\x00\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71", 14);
+
+    header += FMT_EXT_CHUNK_LEN;
+
+  } else {
+    GST_WRITE_UINT32_LE (header + 4, FMT_WAV_CHUNK_LEN - 8);
+
+    /* wFormatTag */
+    GST_WRITE_UINT16_LE (header + 8, wavenc->format);
+    header += FMT_WAV_CHUNK_LEN;
+  }
+
+  return header;
+}
+
+static guint64
+get_num_frames (GstWavEnc * wavenc)
+{
+  if (wavenc->channels == 0 || wavenc->width == 0)
+    return 0;
+  return wavenc->audio_length / (wavenc->width / 8) / wavenc->channels;
+}
+
+static guint8 *
+write_fact_chunk (GstWavEnc * wavenc, guint8 * header)
+{
+  memcpy (header, "fact", 4);
+  GST_WRITE_UINT32_LE (header + 4, FACT_CHUNK_LEN - 8);
+  /* compressed files are only supported up to 2 channels,
+   * that means we never write a fact chunk for them */
+  if (wavenc->use_rf64)
+    GST_WRITE_UINT32_LE (header + 8, 0xFFFFFFFF);
+  else
+    GST_WRITE_UINT32_LE (header + 8, (guint32) get_num_frames (wavenc));
+  return header + FACT_CHUNK_LEN;
+}
+
+static guint8 *
+write_ds64_chunk (GstWavEnc * wavenc, guint64 riffLen, guint8 * header)
+{
+  guint64 numFrames = get_num_frames (wavenc);
+
+  GST_DEBUG_OBJECT (wavenc, "riffLen=%" G_GUINT64_FORMAT
+      ", audio length=%" G_GUINT64_FORMAT ", numFrames=%" G_GUINT64_FORMAT,
+      riffLen, wavenc->audio_length, numFrames);
+
+  memcpy (header, "ds64", 4);
+  GST_WRITE_UINT32_LE (header + 4, DS64_CHUNK_LEN - 8);
+  /* riffSize */
+  GST_WRITE_UINT32_LE (header + 8, (guint32) (riffLen & 0xFFFFFFFF));
+  GST_WRITE_UINT32_LE (header + 12, (guint32) (riffLen >> 32));
+  /* dataSize */
+  GST_WRITE_UINT32_LE (header + 16,
+      (guint32) (wavenc->audio_length & 0xFFFFFFFF));
+  GST_WRITE_UINT32_LE (header + 20, (guint32) (wavenc->audio_length >> 32));
+  /* sampleCount */
+  GST_WRITE_UINT32_LE (header + 24, (guint32) (numFrames & 0xFFFFFFFF));
+  GST_WRITE_UINT32_LE (header + 28, (guint32) (numFrames >> 32));
+  /* tableLength always zero for now */
+  GST_WRITE_UINT32_LE (header + 32, 0);
+
+  return header + DS64_CHUNK_LEN;
+}
+
+static GstBuffer *
+gst_wavenc_create_header_buf (GstWavEnc * wavenc)
+{
+  GstBuffer *buf;
+  GstMapInfo map;
+  guint8 *header;
+  guint64 riffLen;
+
+  GST_DEBUG_OBJECT (wavenc, "Header size: %d", get_header_len (wavenc));
+  buf = gst_buffer_new_and_alloc (get_header_len (wavenc));
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  header = map.data;
+  memset (header, 0, get_header_len (wavenc));
+
+  riffLen = wavenc->meta_length + wavenc->audio_length
+      + get_header_len (wavenc) - 8;
+
+  /* RIFF chunk */
+  if (wavenc->use_rf64) {
+    GST_DEBUG_OBJECT (wavenc, "Using RF64");
+    memcpy (header, "RF64", 4);
+    GST_WRITE_UINT32_LE (header + 4, 0xFFFFFFFF);
+  } else {
+    memcpy (header, "RIFF", 4);
+    GST_WRITE_UINT32_LE (header + 4, (guint32) riffLen);
+  }
+  memcpy (header + 8, "WAVE", 4);
+  header += RIFF_CHUNK_LEN;
+
+  if (wavenc->use_rf64)
+    header = write_ds64_chunk (wavenc, riffLen, header);
+
+  header = write_fmt_chunk (wavenc, header);
+  if (use_fact_chunk (wavenc))
+    header = write_fact_chunk (wavenc, header);
+
+  /* data chunk */
+  memcpy (header, "data ", 4);
+  if (wavenc->use_rf64)
+    GST_WRITE_UINT32_LE (header + 4, 0xFFFFFFFF);
+  else
+    GST_WRITE_UINT32_LE (header + 4, (guint32) wavenc->audio_length);
+
+  gst_buffer_unmap (buf, &map);
+
+  return buf;
+}
+
+static GstFlowReturn
+gst_wavenc_push_header (GstWavEnc * wavenc)
+{
+  GstFlowReturn ret;
+  GstBuffer *outbuf;
+  GstSegment segment;
+
+  /* seek to beginning of file */
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  if (!gst_pad_push_event (wavenc->srcpad, gst_event_new_segment (&segment))) {
+    GST_WARNING_OBJECT (wavenc, "Seek to the beginning failed");
+    return GST_FLOW_ERROR;
+  }
+
+  GST_DEBUG_OBJECT (wavenc, "writing header, meta_size=%u, audio_size=%"
+      G_GUINT64_FORMAT, wavenc->meta_length, wavenc->audio_length);
+
+  outbuf = gst_wavenc_create_header_buf (wavenc);
+  GST_BUFFER_OFFSET (outbuf) = 0;
+
+  ret = gst_pad_push (wavenc->srcpad, outbuf);
+
+  if (ret != GST_FLOW_OK) {
+    GST_WARNING_OBJECT (wavenc, "push header failed: flow = %s",
+        gst_flow_get_name (ret));
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_wavenc_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+  GstWavEnc *wavenc;
+  GstStructure *structure;
+  const gchar *name;
+  gint chans, rate;
+  GstCaps *ccaps;
+
+  wavenc = GST_WAVENC (gst_pad_get_parent (pad));
+
+  ccaps = gst_pad_get_current_caps (pad);
+  if (wavenc->sent_header && ccaps && !gst_caps_can_intersect (caps, ccaps)) {
+    gst_caps_unref (ccaps);
+    GST_WARNING_OBJECT (wavenc, "cannot change format in middle of stream");
+    goto fail;
+  }
+  if (ccaps)
+    gst_caps_unref (ccaps);
+
+  GST_DEBUG_OBJECT (wavenc, "got caps: %" GST_PTR_FORMAT, caps);
+
+  structure = gst_caps_get_structure (caps, 0);
+  name = gst_structure_get_name (structure);
+
+  if (!gst_structure_get_int (structure, "channels", &chans) ||
+      !gst_structure_get_int (structure, "rate", &rate)) {
+    GST_WARNING_OBJECT (wavenc, "caps incomplete");
+    goto fail;
+  }
+
+  wavenc->channels = chans;
+  wavenc->rate = rate;
+  wavenc->channel_mask = 0;
+
+  if (strcmp (name, "audio/x-raw") == 0) {
+    GstAudioInfo info;
+    guint64 gstmask;
+
+    if (!gst_audio_info_from_caps (&info, caps)) {
+      GST_WARNING_OBJECT (wavenc, "Could not retrieve audio info from caps");
+      goto fail;
+    }
+    if (gst_audio_channel_positions_to_mask (info.position, wavenc->channels,
+            FALSE, &gstmask)) {
+      wavenc->channel_mask = gstmask_to_wavmask (gstmask, wavenc->destPos);
+      memcpy (wavenc->srcPos, info.position, sizeof (info.position));
+      GST_DEBUG_OBJECT (wavenc, "Channel mask input: 0x%" G_GINT64_MODIFIER "x"
+          " output: 0x%" G_GINT64_MODIFIER "x", gstmask, wavenc->channel_mask);
+    }
+    wavenc->audio_format = GST_AUDIO_INFO_FORMAT (&info);
+
+    if (GST_AUDIO_INFO_IS_INTEGER (&info))
+      wavenc->format = GST_RIFF_WAVE_FORMAT_PCM;
+    else if (GST_AUDIO_INFO_IS_FLOAT (&info))
+      wavenc->format = GST_RIFF_WAVE_FORMAT_IEEE_FLOAT;
+    else
+      goto fail;
+
+    wavenc->width = GST_AUDIO_INFO_WIDTH (&info);
+  } else if (strcmp (name, "audio/x-alaw") == 0) {
+    wavenc->format = GST_RIFF_WAVE_FORMAT_ALAW;
+    wavenc->width = 8;
+  } else if (strcmp (name, "audio/x-mulaw") == 0) {
+    wavenc->format = GST_RIFF_WAVE_FORMAT_MULAW;
+    wavenc->width = 8;
+  } else {
+    GST_WARNING_OBJECT (wavenc, "Unsupported format %s", name);
+    goto fail;
+  }
+
+  GST_LOG_OBJECT (wavenc,
+      "accepted caps: format=0x%04x chans=%u width=%u rate=%u",
+      wavenc->format, wavenc->channels, wavenc->width, wavenc->rate);
+
+  gst_object_unref (wavenc);
+  return TRUE;
+
+fail:
+  gst_object_unref (wavenc);
+  return FALSE;
+}
+
+static void
+gst_wavparse_tags_foreach (const GstTagList * tags, const gchar * tag,
+    gpointer data)
+{
+  const struct
+  {
+    guint32 fcc;
+    const gchar *tag;
+  } rifftags[] = {
+    {
+    GST_RIFF_INFO_IARL, GST_TAG_LOCATION}, {
+    GST_RIFF_INFO_IART, GST_TAG_ARTIST}, {
+    GST_RIFF_INFO_ICMT, GST_TAG_COMMENT}, {
+    GST_RIFF_INFO_ICOP, GST_TAG_COPYRIGHT}, {
+    GST_RIFF_INFO_ICRD, GST_TAG_DATE}, {
+    GST_RIFF_INFO_IGNR, GST_TAG_GENRE}, {
+    GST_RIFF_INFO_IKEY, GST_TAG_KEYWORDS}, {
+    GST_RIFF_INFO_INAM, GST_TAG_TITLE}, {
+    GST_RIFF_INFO_IPRD, GST_TAG_ALBUM}, {
+    GST_RIFF_INFO_ISBJ, GST_TAG_ALBUM_ARTIST}, {
+    GST_RIFF_INFO_ISFT, GST_TAG_ENCODER}, {
+    GST_RIFF_INFO_ISRC, GST_TAG_ISRC}, {
+    0, NULL}
+  };
+  gint n;
+  gchar *str = NULL;
+  GstByteWriter *bw = data;
+  for (n = 0; rifftags[n].fcc != 0; n++) {
+    if (!strcmp (rifftags[n].tag, tag)) {
+      if (rifftags[n].fcc == GST_RIFF_INFO_ICRD) {
+        GDate *date;
+        /* special case for the date tag */
+        if (gst_tag_list_get_date (tags, tag, &date)) {
+          str =
+              g_strdup_printf ("%04d:%02d:%02d", g_date_get_year (date),
+              g_date_get_month (date), g_date_get_day (date));
+          g_date_free (date);
+        }
+      } else {
+        gst_tag_list_get_string (tags, tag, &str);
+      }
+      if (str) {
+        gst_byte_writer_put_uint32_le (bw, rifftags[n].fcc);
+        gst_byte_writer_put_uint32_le (bw, GST_ROUND_UP_2 (strlen (str)));
+        gst_byte_writer_put_string (bw, str);
+        g_free (str);
+        str = NULL;
+        break;
+      }
+    }
+  }
+
+}
+
+static GstFlowReturn
+gst_wavenc_write_tags (GstWavEnc * wavenc)
+{
+  const GstTagList *user_tags;
+  GstTagList *tags;
+  guint size;
+  GstBuffer *buf;
+  GstByteWriter bw;
+
+  g_return_val_if_fail (wavenc != NULL, GST_FLOW_OK);
+
+  user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (wavenc));
+  if ((!wavenc->tags) && (!user_tags)) {
+    GST_DEBUG_OBJECT (wavenc, "have no tags");
+    return GST_FLOW_OK;
+  }
+  tags =
+      gst_tag_list_merge (user_tags, wavenc->tags,
+      gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (wavenc)));
+
+  GST_DEBUG_OBJECT (wavenc, "writing tags");
+
+  gst_byte_writer_init_with_size (&bw, 1024, FALSE);
+
+  /* add LIST INFO chunk */
+  gst_byte_writer_put_data (&bw, (const guint8 *) "LIST", 4);
+  gst_byte_writer_put_uint32_le (&bw, 0);
+  gst_byte_writer_put_data (&bw, (const guint8 *) "INFO", 4);
+
+  /* add tags */
+  gst_tag_list_foreach (tags, gst_wavparse_tags_foreach, &bw);
+
+  /* sets real size of LIST INFO chunk */
+  size = gst_byte_writer_get_pos (&bw);
+  gst_byte_writer_set_pos (&bw, 4);
+  gst_byte_writer_put_uint32_le (&bw, size - 8);
+
+  gst_tag_list_unref (tags);
+
+  buf = gst_byte_writer_reset_and_get_buffer (&bw);
+  wavenc->meta_length += gst_buffer_get_size (buf);
+  return gst_pad_push (wavenc->srcpad, buf);
+}
+
+static gboolean
+gst_wavenc_is_cue_id_unique (guint32 id, GList * list)
+{
+  GstWavEncCue *cue;
+
+  while (list) {
+    cue = list->data;
+    if (cue->id == id)
+      return FALSE;
+    list = g_list_next (list);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_wavenc_parse_cue (GstWavEnc * wavenc, guint32 id, GstTocEntry * entry)
+{
+  gint64 start;
+  GstWavEncCue *cue;
+
+  g_return_val_if_fail (entry != NULL, FALSE);
+
+  gst_toc_entry_get_start_stop_times (entry, &start, NULL);
+
+  cue = g_new (GstWavEncCue, 1);
+  cue->id = id;
+  cue->position = gst_util_uint64_scale_round (start, wavenc->rate, GST_SECOND);
+  memcpy (cue->data_chunk_id, "data", 4);
+  cue->chunk_start = 0;
+  cue->block_start = 0;
+  cue->sample_offset = cue->position;
+  wavenc->cues = g_list_append (wavenc->cues, cue);
+
+  return TRUE;
+}
+
+static gboolean
+gst_wavenc_parse_labl (GstWavEnc * wavenc, guint32 id, GstTocEntry * entry)
+{
+  gchar *tag;
+  GstTagList *tags;
+  GstWavEncLabl *labl;
+
+  g_return_val_if_fail (entry != NULL, FALSE);
+
+  tags = gst_toc_entry_get_tags (entry);
+  if (!tags) {
+    GST_INFO_OBJECT (wavenc, "no tags for entry: %d", id);
+    return FALSE;
+  }
+  if (!gst_tag_list_get_string (tags, GST_TAG_TITLE, &tag)) {
+    GST_INFO_OBJECT (wavenc, "no title tag for entry: %d", id);
+    return FALSE;
+  }
+
+  labl = g_new (GstWavEncLabl, 1);
+  memcpy (labl->chunk_id, "labl", 4);
+  labl->chunk_data_size = 4 + strlen (tag) + 1;
+  labl->cue_point_id = id;
+  labl->text = tag;
+
+  GST_DEBUG_OBJECT (wavenc, "got labl: '%s'", tag);
+
+  wavenc->labls = g_list_append (wavenc->labls, labl);
+
+  return TRUE;
+}
+
+static gboolean
+gst_wavenc_parse_note (GstWavEnc * wavenc, guint32 id, GstTocEntry * entry)
+{
+  gchar *tag;
+  GstTagList *tags;
+  GstWavEncNote *note;
+
+  g_return_val_if_fail (entry != NULL, FALSE);
+  tags = gst_toc_entry_get_tags (entry);
+  if (!tags) {
+    GST_INFO_OBJECT (wavenc, "no tags for entry: %d", id);
+    return FALSE;
+  }
+  if (!gst_tag_list_get_string (tags, GST_TAG_COMMENT, &tag)) {
+    GST_INFO_OBJECT (wavenc, "no comment tag for entry: %d", id);
+    return FALSE;
+  }
+
+  note = g_new (GstWavEncNote, 1);
+  memcpy (note->chunk_id, "note", 4);
+  note->chunk_data_size = 4 + strlen (tag) + 1;
+  note->cue_point_id = id;
+  note->text = tag;
+
+  GST_DEBUG_OBJECT (wavenc, "got note: '%s'", tag);
+
+  wavenc->notes = g_list_append (wavenc->notes, note);
+
+  return TRUE;
+}
+
+static gboolean
+gst_wavenc_write_cues (guint8 ** data, GList * list)
+{
+  GstWavEncCue *cue;
+
+  while (list) {
+    cue = list->data;
+    GST_WRITE_UINT32_LE (*data, cue->id);
+    GST_WRITE_UINT32_LE (*data + 4, cue->position);
+    memcpy (*data + 8, (gchar *) cue->data_chunk_id, 4);
+    GST_WRITE_UINT32_LE (*data + 12, cue->chunk_start);
+    GST_WRITE_UINT32_LE (*data + 16, cue->block_start);
+    GST_WRITE_UINT32_LE (*data + 20, cue->sample_offset);
+    *data += 24;
+    list = g_list_next (list);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_wavenc_write_labls (guint8 ** data, GList * list)
+{
+  GstWavEncLabl *labl;
+
+  while (list) {
+    labl = list->data;
+    memcpy (*data, (gchar *) labl->chunk_id, 4);
+    GST_WRITE_UINT32_LE (*data + 4, labl->chunk_data_size);
+    GST_WRITE_UINT32_LE (*data + 8, labl->cue_point_id);
+    memcpy (*data + 12, (gchar *) labl->text, strlen (labl->text));
+    *data += 8 + GST_ROUND_UP_2 (labl->chunk_data_size);
+    list = g_list_next (list);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_wavenc_write_notes (guint8 ** data, GList * list)
+{
+  GstWavEncNote *note;
+
+  while (list) {
+    note = list->data;
+    memcpy (*data, (gchar *) note->chunk_id, 4);
+    GST_WRITE_UINT32_LE (*data + 4, note->chunk_data_size);
+    GST_WRITE_UINT32_LE (*data + 8, note->cue_point_id);
+    memcpy (*data + 12, (gchar *) note->text, strlen (note->text));
+    *data += 8 + GST_ROUND_UP_2 (note->chunk_data_size);
+    list = g_list_next (list);
+  }
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_wavenc_write_toc (GstWavEnc * wavenc)
+{
+  GList *list;
+  GstToc *toc;
+  GstTocEntry *entry, *subentry;
+  GstBuffer *buf;
+  GstMapInfo map;
+  guint8 *data;
+  guint32 ncues, size, cues_size, labls_size, notes_size;
+
+  if (!wavenc->toc) {
+    GST_DEBUG_OBJECT (wavenc, "have no toc, checking toc_setter");
+    wavenc->toc = gst_toc_setter_get_toc (GST_TOC_SETTER (wavenc));
+  }
+  if (!wavenc->toc) {
+    GST_WARNING_OBJECT (wavenc, "have no toc");
+    return GST_FLOW_OK;
+  }
+
+  toc = gst_toc_ref (wavenc->toc);
+  size = 0;
+  cues_size = 0;
+  labls_size = 0;
+  notes_size = 0;
+
+  /* check if the TOC entries is valid */
+  list = gst_toc_get_entries (toc);
+  entry = list->data;
+  if (gst_toc_entry_is_alternative (entry)) {
+    list = gst_toc_entry_get_sub_entries (entry);
+    while (list) {
+      subentry = list->data;
+      if (!gst_toc_entry_is_sequence (subentry))
+        return FALSE;
+      list = g_list_next (list);
+    }
+    list = gst_toc_entry_get_sub_entries (entry);
+  }
+  if (gst_toc_entry_is_sequence (entry)) {
+    while (list) {
+      entry = list->data;
+      if (!gst_toc_entry_is_sequence (entry))
+        return FALSE;
+      list = g_list_next (list);
+    }
+    list = gst_toc_get_entries (toc);
+  }
+
+  ncues = g_list_length (list);
+  GST_DEBUG_OBJECT (wavenc, "number of cue entries: %d", ncues);
+
+  while (list) {
+    guint32 id = 0;
+    gint64 id64;
+    const gchar *uid;
+
+    entry = list->data;
+    uid = gst_toc_entry_get_uid (entry);
+    id64 = g_ascii_strtoll (uid, NULL, 0);
+    /* check if id unique compatible with guint32 else generate random */
+    if (id64 >= 0 && gst_wavenc_is_cue_id_unique (id64, wavenc->cues)) {
+      id = (guint32) id64;
+    } else {
+      do {
+        id = g_random_int ();
+      } while (!gst_wavenc_is_cue_id_unique (id, wavenc->cues));
+    }
+    gst_wavenc_parse_cue (wavenc, id, entry);
+    gst_wavenc_parse_labl (wavenc, id, entry);
+    gst_wavenc_parse_note (wavenc, id, entry);
+    list = g_list_next (list);
+  }
+
+  /* count cues size */
+  if (wavenc->cues) {
+    cues_size = 24 * g_list_length (wavenc->cues);
+    size += 12 + cues_size;
+  } else {
+    GST_WARNING_OBJECT (wavenc, "cue's not found");
+    return FALSE;
+  }
+  /* count labls size */
+  if (wavenc->labls) {
+    list = wavenc->labls;
+    while (list) {
+      GstWavEncLabl *labl;
+      labl = list->data;
+      labls_size += 8 + GST_ROUND_UP_2 (labl->chunk_data_size);
+      list = g_list_next (list);
+    }
+    size += labls_size;
+  }
+  /* count notes size */
+  if (wavenc->notes) {
+    list = wavenc->notes;
+    while (list) {
+      GstWavEncNote *note;
+      note = list->data;
+      notes_size += 8 + GST_ROUND_UP_2 (note->chunk_data_size);
+      list = g_list_next (list);
+    }
+    size += notes_size;
+  }
+  if (wavenc->labls || wavenc->notes) {
+    size += 12;
+  }
+
+  buf = gst_buffer_new_and_alloc (size);
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  data = map.data;
+  memset (data, 0, size);
+
+  /* write Cue Chunk */
+  if (wavenc->cues) {
+    memcpy (data, (gchar *) "cue ", 4);
+    GST_WRITE_UINT32_LE (data + 4, 4 + cues_size);
+    GST_WRITE_UINT32_LE (data + 8, ncues);
+    data += 12;
+    gst_wavenc_write_cues (&data, wavenc->cues);
+
+    /* write Associated Data List Chunk */
+    if (wavenc->labls || wavenc->notes) {
+      memcpy (data, (gchar *) "LIST", 4);
+      GST_WRITE_UINT32_LE (data + 4, 4 + labls_size + notes_size);
+      memcpy (data + 8, (gchar *) "adtl", 4);
+      data += 12;
+      if (wavenc->labls)
+        gst_wavenc_write_labls (&data, wavenc->labls);
+      if (wavenc->notes)
+        gst_wavenc_write_notes (&data, wavenc->notes);
+    }
+  }
+
+  /* free resources */
+  if (toc)
+    gst_toc_unref (toc);
+  if (wavenc->cues)
+    g_list_free_full (wavenc->cues, g_free);
+  if (wavenc->labls)
+    g_list_free_full (wavenc->labls, g_free);
+  if (wavenc->notes)
+    g_list_free_full (wavenc->notes, g_free);
+
+  gst_buffer_unmap (buf, &map);
+  wavenc->meta_length += gst_buffer_get_size (buf);
+
+  return gst_pad_push (wavenc->srcpad, buf);
+}
+
+static gboolean
+gst_wavenc_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  gboolean res = TRUE;
+  GstWavEnc *wavenc;
+  GstTagList *tags;
+  GstToc *toc;
+
+  wavenc = GST_WAVENC (parent);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      gst_wavenc_sink_setcaps (pad, caps);
+
+      /* have our own src caps */
+      gst_event_unref (event);
+      break;
+    }
+    case GST_EVENT_EOS:
+    {
+      GstFlowReturn flow;
+      GST_DEBUG_OBJECT (wavenc, "got EOS");
+
+      flow = gst_wavenc_write_toc (wavenc);
+      if (flow != GST_FLOW_OK) {
+        GST_WARNING_OBJECT (wavenc, "error pushing toc: %s",
+            gst_flow_get_name (flow));
+      }
+      flow = gst_wavenc_write_tags (wavenc);
+      if (flow != GST_FLOW_OK) {
+        GST_WARNING_OBJECT (wavenc, "error pushing tags: %s",
+            gst_flow_get_name (flow));
+      }
+
+      /* write header with correct length values */
+      gst_wavenc_push_header (wavenc);
+
+      /* we're done with this file */
+      wavenc->finished_properly = TRUE;
+
+      /* and forward the EOS event */
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+    }
+    case GST_EVENT_SEGMENT:
+      /* Just drop it, it's probably in TIME format
+       * anyway. We'll send our own newsegment event */
+      gst_event_unref (event);
+      break;
+    case GST_EVENT_TOC:
+      gst_event_parse_toc (event, &toc, NULL);
+      if (toc) {
+        if (wavenc->toc != toc) {
+          if (wavenc->toc)
+            gst_toc_unref (wavenc->toc);
+          wavenc->toc = toc;
+        } else {
+          gst_toc_unref (toc);
+        }
+      }
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+    case GST_EVENT_TAG:
+      gst_event_parse_tag (event, &tags);
+      if (tags) {
+        if (wavenc->tags != tags) {
+          if (wavenc->tags)
+            gst_tag_list_unref (wavenc->tags);
+          wavenc->tags = gst_tag_list_ref (tags);
+        }
+      }
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+    default:
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+
+  return res;
+}
+
+static GstFlowReturn
+gst_wavenc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstWavEnc *wavenc = GST_WAVENC (parent);
+  GstFlowReturn flow = GST_FLOW_OK;
+
+  if (wavenc->channels <= 0) {
+    GST_ERROR_OBJECT (wavenc, "Got data without caps");
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+
+  if (G_UNLIKELY (!wavenc->sent_header)) {
+    GstStructure *s;
+    GstCaps *caps = gst_pad_get_allowed_caps (wavenc->srcpad);
+
+    GST_DEBUG_OBJECT (wavenc, "allowed src caps: %" GST_PTR_FORMAT, caps);
+    if (!gst_caps_is_fixed (caps)) {
+      caps = gst_caps_truncate (caps);
+    }
+    s = gst_caps_get_structure (caps, 0);
+    wavenc->use_rf64 = gst_structure_has_name (s, "audio/x-rf64");
+
+    gst_pad_set_caps (wavenc->srcpad, caps);
+    gst_caps_unref (caps);
+
+    /* starting a file, means we have to finish it properly */
+    wavenc->finished_properly = FALSE;
+
+    /* push initial bogus header, it will be updated on EOS */
+    flow = gst_wavenc_push_header (wavenc);
+    if (flow != GST_FLOW_OK) {
+      GST_WARNING_OBJECT (wavenc, "error pushing header: %s",
+          gst_flow_get_name (flow));
+      return flow;
+    }
+    GST_DEBUG_OBJECT (wavenc, "wrote dummy header");
+    wavenc->audio_length = 0;
+    wavenc->sent_header = TRUE;
+  }
+
+  GST_LOG_OBJECT (wavenc,
+      "pushing %" G_GSIZE_FORMAT " bytes raw audio, ts=%" GST_TIME_FORMAT,
+      gst_buffer_get_size (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+
+  buf = gst_buffer_make_writable (buf);
+
+  GST_BUFFER_OFFSET (buf) = get_header_len (wavenc) + wavenc->audio_length;
+  GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
+
+  wavenc->audio_length += gst_buffer_get_size (buf);
+
+  if (wavenc->channel_mask != 0 &&
+      !gst_audio_buffer_reorder_channels (buf, wavenc->audio_format,
+          wavenc->channels, wavenc->srcPos, wavenc->destPos)) {
+    GST_WARNING_OBJECT (wavenc, "Could not reorder channels");
+  }
+
+  flow = gst_pad_push (wavenc->srcpad, buf);
+
+  return flow;
+}
+
+static GstStateChangeReturn
+gst_wavenc_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+  GstWavEnc *wavenc = GST_WAVENC (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      wavenc->format = 0;
+      wavenc->channels = 0;
+      wavenc->width = 0;
+      wavenc->rate = 0;
+      /* use bogus size initially, we'll write the real
+       * header when we get EOS and know the exact length */
+      wavenc->audio_length = 0x7FFF0000;
+      wavenc->meta_length = 0;
+      wavenc->sent_header = FALSE;
+      /* its true because we haven't writen anything */
+      wavenc->finished_properly = TRUE;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret != GST_STATE_CHANGE_SUCCESS)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      if (!wavenc->finished_properly) {
+        GST_ELEMENT_WARNING (wavenc, STREAM, MUX,
+            ("Wav stream not finished properly"),
+            ("Wav stream not finished properly, no EOS received "
+                "before shutdown"));
+      }
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      GST_DEBUG_OBJECT (wavenc, "tags: %p", wavenc->tags);
+      if (wavenc->tags) {
+        gst_tag_list_unref (wavenc->tags);
+        wavenc->tags = NULL;
+      }
+      GST_DEBUG_OBJECT (wavenc, "toc: %p", wavenc->toc);
+      if (wavenc->toc) {
+        gst_toc_unref (wavenc->toc);
+        wavenc->toc = NULL;
+      }
+      gst_tag_setter_reset_tags (GST_TAG_SETTER (wavenc));
+      gst_toc_setter_reset (GST_TOC_SETTER (wavenc));
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "wavenc", GST_RANK_PRIMARY,
+      GST_TYPE_WAVENC);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    wavenc,
+    "Encode raw audio into WAV",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/wavenc/gstwavenc.h b/gst/wavenc/gstwavenc.h
new file mode 100644
index 0000000..11b38bb
--- /dev/null
+++ b/gst/wavenc/gstwavenc.h
@@ -0,0 +1,83 @@
+/* GStreamer
+ * Copyright (C) 2002, Iain Holmes <iain@prettypeople.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_WAV_ENC_H__
+#define __GST_WAV_ENC_H__
+
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_WAVENC \
+  (gst_wavenc_get_type())
+#define GST_WAVENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAVENC,GstWavEnc))
+#define GST_WAVENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVENC,GstWavEncClass))
+#define GST_IS_WAVENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAVENC))
+#define GST_IS_WAVENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVENC))
+
+typedef struct _GstWavEnc GstWavEnc;
+typedef struct _GstWavEncClass GstWavEncClass;
+
+struct _GstWavEnc {
+  GstElement element;
+
+  GstPad    *sinkpad;
+  GstPad    *srcpad;
+
+  GstTagList *tags;
+  GstToc    *toc;
+  GList     *cues;
+  GList     *labls;
+  GList     *notes;
+
+  /* useful audio data */
+  GstAudioFormat audio_format;
+  guint16    format;
+  guint      width;
+  guint      rate;
+  guint      channels;
+  guint64    channel_mask;
+  GstAudioChannelPosition srcPos[64];
+  GstAudioChannelPosition destPos[64];
+  
+  /* data sizes */
+  guint64    audio_length;
+  guint32    meta_length;
+
+  gboolean   use_rf64;
+  gboolean   sent_header;
+  gboolean   finished_properly;
+};
+
+struct _GstWavEncClass {
+  GstElementClass parent_class;
+};
+
+GType gst_wavenc_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_WAV_ENC_H__ */
diff --git a/gst/wavenc/meson.build b/gst/wavenc/meson.build
new file mode 100644
index 0000000..98a9299
--- /dev/null
+++ b/gst/wavenc/meson.build
@@ -0,0 +1,8 @@
+gstwavenc = library('gstwavenc',
+  'gstwavenc.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstbase_dep, gstaudio_dep, gstriff_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/wavparse/.gitignore b/gst/wavparse/.gitignore
new file mode 100644
index 0000000..08f5ed3
--- /dev/null
+++ b/gst/wavparse/.gitignore
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
diff --git a/gst/wavparse/Makefile.am b/gst/wavparse/Makefile.am
new file mode 100644
index 0000000..6076c28
--- /dev/null
+++ b/gst/wavparse/Makefile.am
@@ -0,0 +1,19 @@
+plugin_LTLIBRARIES = libgstwavparse.la
+
+libgstwavparse_la_SOURCES = gstwavparse.c
+libgstwavparse_la_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS)
+libgstwavparse_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) \
+	-lgstriff-@GST_API_VERSION@ \
+	-lgstaudio-@GST_API_VERSION@ \
+	-lgsttag-@GST_API_VERSION@ \
+	-lgstpbutils-@GST_API_VERSION@ \
+	$(GST_BASE_LIBS) \
+	$(GST_LIBS) \
+	$(LIBM)
+libgstwavparse_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstwavparse.h
diff --git a/gst/wavparse/gstwavparse.c b/gst/wavparse/gstwavparse.c
new file mode 100644
index 0000000..a81701f
--- /dev/null
+++ b/gst/wavparse/gstwavparse.c
@@ -0,0 +1,2969 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2006> Nokia Corporation, Stefan Kost <stefan.kost@nokia.com>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-wavparse
+ *
+ * Parse a .wav file into raw or compressed audio.
+ *
+ * Wavparse supports both push and pull mode operations, making it possible to
+ * stream from a network source.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 filesrc location=sine.wav ! wavparse ! audioconvert ! alsasink
+ * ]| Read a wav file and output to the soundcard using the ALSA element. The
+ * wav file is assumed to contain raw uncompressed samples.
+ * |[
+ * gst-launch-1.0 gnomevfssrc location=http://www.example.org/sine.wav ! queue ! wavparse ! audioconvert ! alsasink
+ * ]| Stream data from a network url.
+ * </refsect2>
+ */
+
+/*
+ * TODO:
+ * http://replaygain.hydrogenaudio.org/file_format_wav.html
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <math.h>
+
+#include "gstwavparse.h"
+#include "gst/riff/riff-media.h"
+#include <gst/base/gsttypefindhelper.h>
+#include <gst/pbutils/descriptions.h>
+#include <gst/gst-i18n-plugin.h>
+
+GST_DEBUG_CATEGORY_STATIC (wavparse_debug);
+#define GST_CAT_DEFAULT (wavparse_debug)
+
+/* Data size chunk of RF64,
+ * see http://tech.ebu.ch/docs/tech/tech3306-2009.pdf */
+#define GST_RS64_TAG_DS64 GST_MAKE_FOURCC ('d','s','6','4')
+
+static void gst_wavparse_dispose (GObject * object);
+
+static gboolean gst_wavparse_sink_activate (GstPad * sinkpad,
+    GstObject * parent);
+static gboolean gst_wavparse_sink_activate_mode (GstPad * sinkpad,
+    GstObject * parent, GstPadMode mode, gboolean active);
+static gboolean gst_wavparse_send_event (GstElement * element,
+    GstEvent * event);
+static GstStateChangeReturn gst_wavparse_change_state (GstElement * element,
+    GstStateChange transition);
+
+static gboolean gst_wavparse_pad_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+static gboolean gst_wavparse_pad_convert (GstPad * pad, GstFormat src_format,
+    gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
+
+static GstFlowReturn gst_wavparse_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buf);
+static gboolean gst_wavparse_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static void gst_wavparse_loop (GstPad * pad);
+static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+
+static void gst_wavparse_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_wavparse_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+#define DEFAULT_IGNORE_LENGTH FALSE
+
+enum
+{
+  PROP_0,
+  PROP_IGNORE_LENGTH,
+};
+
+static GstStaticPadTemplate sink_template_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-wav")
+    );
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (wavparse_debug, "wavparse", 0, "WAV parser");
+
+#define gst_wavparse_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstWavParse, gst_wavparse, GST_TYPE_ELEMENT,
+    DEBUG_INIT);
+
+typedef struct
+{
+  /* Offset Size    Description   Value
+   * 0x00   4       ID            unique identification value
+   * 0x04   4       Position      play order position
+   * 0x08   4       Data Chunk ID RIFF ID of corresponding data chunk
+   * 0x0c   4       Chunk Start   Byte Offset of Data Chunk *
+   * 0x10   4       Block Start   Byte Offset to sample of First Channel
+   * 0x14   4       Sample Offset Byte Offset to sample byte of First Channel
+   */
+  guint32 id;
+  guint32 position;
+  guint32 data_chunk_id;
+  guint32 chunk_start;
+  guint32 block_start;
+  guint32 sample_offset;
+} GstWavParseCue;
+
+typedef struct
+{
+  /* Offset Size    Description     Value
+   * 0x08   4       Cue Point ID    0 - 0xFFFFFFFF
+   * 0x0c           Text
+   */
+  guint32 cue_point_id;
+  gchar *text;
+} GstWavParseLabl, GstWavParseNote;
+
+static void
+gst_wavparse_class_init (GstWavParseClass * klass)
+{
+  GstElementClass *gstelement_class;
+  GObjectClass *object_class;
+  GstPadTemplate *src_template;
+
+  gstelement_class = (GstElementClass *) klass;
+  object_class = (GObjectClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  object_class->dispose = gst_wavparse_dispose;
+
+  object_class->set_property = gst_wavparse_set_property;
+  object_class->get_property = gst_wavparse_get_property;
+
+  /**
+   * GstWavParse:ignore-length:
+   *
+   * This selects whether the length found in a data chunk
+   * should be ignored. This may be useful for streamed audio
+   * where the length is unknown until the end of streaming,
+   * and various software/hardware just puts some random value
+   * in there and hopes it doesn't break too much.
+   */
+  g_object_class_install_property (object_class, PROP_IGNORE_LENGTH,
+      g_param_spec_boolean ("ignore-length",
+          "Ignore length",
+          "Ignore length from the Wave header",
+          DEFAULT_IGNORE_LENGTH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
+  gstelement_class->change_state = gst_wavparse_change_state;
+  gstelement_class->send_event = gst_wavparse_send_event;
+
+  /* register pads */
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &sink_template_factory);
+
+  src_template = gst_pad_template_new ("src", GST_PAD_SRC,
+      GST_PAD_ALWAYS, gst_riff_create_audio_template_caps ());
+  gst_element_class_add_pad_template (gstelement_class, src_template);
+
+  gst_element_class_set_static_metadata (gstelement_class, "WAV audio demuxer",
+      "Codec/Demuxer/Audio",
+      "Parse a .wav file into raw audio",
+      "Erik Walthinsen <omega@cse.ogi.edu>");
+}
+
+static void
+gst_wavparse_notes_free (GstWavParseNote * note)
+{
+  if (note)
+    g_free (note->text);
+  g_free (note);
+}
+
+static void
+gst_wavparse_labls_free (GstWavParseLabl * labl)
+{
+  if (labl)
+    g_free (labl->text);
+  g_free (labl);
+}
+
+static void
+gst_wavparse_reset (GstWavParse * wav)
+{
+  wav->state = GST_WAVPARSE_START;
+
+  /* These will all be set correctly in the fmt chunk */
+  wav->depth = 0;
+  wav->rate = 0;
+  wav->width = 0;
+  wav->channels = 0;
+  wav->blockalign = 0;
+  wav->bps = 0;
+  wav->fact = 0;
+  wav->offset = 0;
+  wav->end_offset = 0;
+  wav->dataleft = 0;
+  wav->datasize = 0;
+  wav->datastart = 0;
+  wav->chunk_size = 0;
+  wav->duration = 0;
+  wav->got_fmt = FALSE;
+  wav->first = TRUE;
+
+  if (wav->seek_event)
+    gst_event_unref (wav->seek_event);
+  wav->seek_event = NULL;
+  if (wav->adapter) {
+    gst_adapter_clear (wav->adapter);
+    g_object_unref (wav->adapter);
+    wav->adapter = NULL;
+  }
+  if (wav->tags)
+    gst_tag_list_unref (wav->tags);
+  wav->tags = NULL;
+  if (wav->toc)
+    gst_toc_unref (wav->toc);
+  wav->toc = NULL;
+  if (wav->cues)
+    g_list_free_full (wav->cues, g_free);
+  wav->cues = NULL;
+  if (wav->labls)
+    g_list_free_full (wav->labls, (GDestroyNotify) gst_wavparse_labls_free);
+  wav->labls = NULL;
+  if (wav->notes)
+    g_list_free_full (wav->notes, (GDestroyNotify) gst_wavparse_notes_free);
+  wav->notes = NULL;
+  if (wav->caps)
+    gst_caps_unref (wav->caps);
+  wav->caps = NULL;
+  if (wav->start_segment)
+    gst_event_unref (wav->start_segment);
+  wav->start_segment = NULL;
+}
+
+static void
+gst_wavparse_dispose (GObject * object)
+{
+  GstWavParse *wav = GST_WAVPARSE (object);
+
+  GST_DEBUG_OBJECT (wav, "WAV: Dispose");
+  gst_wavparse_reset (wav);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_wavparse_init (GstWavParse * wavparse)
+{
+  gst_wavparse_reset (wavparse);
+
+  /* sink */
+  wavparse->sinkpad =
+      gst_pad_new_from_static_template (&sink_template_factory, "sink");
+  gst_pad_set_activate_function (wavparse->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_wavparse_sink_activate));
+  gst_pad_set_activatemode_function (wavparse->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_wavparse_sink_activate_mode));
+  gst_pad_set_chain_function (wavparse->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_wavparse_chain));
+  gst_pad_set_event_function (wavparse->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_wavparse_sink_event));
+  gst_element_add_pad (GST_ELEMENT_CAST (wavparse), wavparse->sinkpad);
+
+  /* src */
+  wavparse->srcpad =
+      gst_pad_new_from_template (gst_element_class_get_pad_template
+      (GST_ELEMENT_GET_CLASS (wavparse), "src"), "src");
+  gst_pad_use_fixed_caps (wavparse->srcpad);
+  gst_pad_set_query_function (wavparse->srcpad,
+      GST_DEBUG_FUNCPTR (gst_wavparse_pad_query));
+  gst_pad_set_event_function (wavparse->srcpad,
+      GST_DEBUG_FUNCPTR (gst_wavparse_srcpad_event));
+  gst_element_add_pad (GST_ELEMENT_CAST (wavparse), wavparse->srcpad);
+}
+
+static gboolean
+gst_wavparse_parse_file_header (GstElement * element, GstBuffer * buf)
+{
+  guint32 doctype;
+
+  if (!gst_riff_parse_file_header (element, buf, &doctype))
+    return FALSE;
+
+  if (doctype != GST_RIFF_RIFF_WAVE)
+    goto not_wav;
+
+  return TRUE;
+
+  /* ERRORS */
+not_wav:
+  {
+    GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
+        ("File is not a WAVE file: 0x%" G_GINT32_MODIFIER "x", doctype));
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_wavparse_stream_init (GstWavParse * wav)
+{
+  GstFlowReturn res;
+  GstBuffer *buf = NULL;
+
+  if ((res = gst_pad_pull_range (wav->sinkpad,
+              wav->offset, 12, &buf)) != GST_FLOW_OK)
+    return res;
+  else if (!gst_wavparse_parse_file_header (GST_ELEMENT_CAST (wav), buf))
+    return GST_FLOW_ERROR;
+
+  wav->offset += 12;
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_wavparse_time_to_bytepos (GstWavParse * wav, gint64 ts, gint64 * bytepos)
+{
+  /* -1 always maps to -1 */
+  if (ts == -1) {
+    *bytepos = -1;
+    return TRUE;
+  }
+
+  /* 0 always maps to 0 */
+  if (ts == 0) {
+    *bytepos = 0;
+    return TRUE;
+  }
+
+  if (wav->bps > 0) {
+    *bytepos = gst_util_uint64_scale_ceil (ts, (guint64) wav->bps, GST_SECOND);
+    return TRUE;
+  } else if (wav->fact) {
+    guint64 bps = gst_util_uint64_scale (wav->datasize, wav->rate, wav->fact);
+    *bytepos = gst_util_uint64_scale_ceil (ts, bps, GST_SECOND);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/* This function is used to perform seeks on the element.
+ *
+ * It also works when event is NULL, in which case it will just
+ * start from the last configured segment. This technique is
+ * used when activating the element and to perform the seek in
+ * READY.
+ */
+static gboolean
+gst_wavparse_perform_seek (GstWavParse * wav, GstEvent * event)
+{
+  gboolean res;
+  gdouble rate;
+  GstFormat format, bformat;
+  GstSeekFlags flags;
+  GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
+  gint64 cur, stop, upstream_size;
+  gboolean flush;
+  gboolean update;
+  GstSegment seeksegment = { 0, };
+  gint64 last_stop;
+  guint32 seqnum = 0;
+
+  if (event) {
+    GST_DEBUG_OBJECT (wav, "doing seek with event");
+
+    gst_event_parse_seek (event, &rate, &format, &flags,
+        &cur_type, &cur, &stop_type, &stop);
+    seqnum = gst_event_get_seqnum (event);
+
+    /* no negative rates yet */
+    if (rate < 0.0)
+      goto negative_rate;
+
+    if (format != wav->segment.format) {
+      GST_INFO_OBJECT (wav, "converting seek-event from %s to %s",
+          gst_format_get_name (format),
+          gst_format_get_name (wav->segment.format));
+      res = TRUE;
+      if (cur_type != GST_SEEK_TYPE_NONE)
+        res =
+            gst_pad_query_convert (wav->srcpad, format, cur,
+            wav->segment.format, &cur);
+      if (res && stop_type != GST_SEEK_TYPE_NONE)
+        res =
+            gst_pad_query_convert (wav->srcpad, format, stop,
+            wav->segment.format, &stop);
+      if (!res)
+        goto no_format;
+
+      format = wav->segment.format;
+    }
+  } else {
+    GST_DEBUG_OBJECT (wav, "doing seek without event");
+    flags = 0;
+    rate = 1.0;
+    cur_type = GST_SEEK_TYPE_SET;
+    stop_type = GST_SEEK_TYPE_SET;
+  }
+
+  /* in push mode, we must delegate to upstream */
+  if (wav->streaming) {
+    gboolean res = FALSE;
+
+    /* if streaming not yet started; only prepare initial newsegment */
+    if (!event || wav->state != GST_WAVPARSE_DATA) {
+      if (wav->start_segment)
+        gst_event_unref (wav->start_segment);
+      wav->start_segment = gst_event_new_segment (&wav->segment);
+      res = TRUE;
+    } else {
+      /* convert seek positions to byte positions in data sections */
+      if (format == GST_FORMAT_TIME) {
+        /* should not fail */
+        if (!gst_wavparse_time_to_bytepos (wav, cur, &cur))
+          goto no_position;
+        if (!gst_wavparse_time_to_bytepos (wav, stop, &stop))
+          goto no_position;
+      }
+      /* mind sample boundary and header */
+      if (cur >= 0) {
+        cur -= (cur % wav->bytes_per_sample);
+        cur += wav->datastart;
+      }
+      if (stop >= 0) {
+        stop -= (stop % wav->bytes_per_sample);
+        stop += wav->datastart;
+      }
+      GST_DEBUG_OBJECT (wav, "Pushing BYTE seek rate %g, "
+          "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur,
+          stop);
+      /* BYTE seek event */
+      event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur,
+          stop_type, stop);
+      gst_event_set_seqnum (event, seqnum);
+      res = gst_pad_push_event (wav->sinkpad, event);
+    }
+    return res;
+  }
+
+  /* get flush flag */
+  flush = flags & GST_SEEK_FLAG_FLUSH;
+
+  /* now we need to make sure the streaming thread is stopped. We do this by
+   * either sending a FLUSH_START event downstream which will cause the
+   * streaming thread to stop with a WRONG_STATE.
+   * For a non-flushing seek we simply pause the task, which will happen as soon
+   * as it completes one iteration (and thus might block when the sink is
+   * blocking in preroll). */
+  if (flush) {
+    GstEvent *fevent;
+    GST_DEBUG_OBJECT (wav, "sending flush start");
+
+    fevent = gst_event_new_flush_start ();
+    gst_event_set_seqnum (fevent, seqnum);
+    gst_pad_push_event (wav->sinkpad, gst_event_ref (fevent));
+    gst_pad_push_event (wav->srcpad, fevent);
+  } else {
+    gst_pad_pause_task (wav->sinkpad);
+  }
+
+  /* we should now be able to grab the streaming thread because we stopped it
+   * with the above flush/pause code */
+  GST_PAD_STREAM_LOCK (wav->sinkpad);
+
+  /* save current position */
+  last_stop = wav->segment.position;
+
+  GST_DEBUG_OBJECT (wav, "stopped streaming at %" G_GINT64_FORMAT, last_stop);
+
+  /* copy segment, we need this because we still need the old
+   * segment when we close the current segment. */
+  memcpy (&seeksegment, &wav->segment, sizeof (GstSegment));
+
+  /* configure the seek parameters in the seeksegment. We will then have the
+   * right values in the segment to perform the seek */
+  if (event) {
+    GST_DEBUG_OBJECT (wav, "configuring seek");
+    gst_segment_do_seek (&seeksegment, rate, format, flags,
+        cur_type, cur, stop_type, stop, &update);
+  }
+
+  /* figure out the last position we need to play. If it's configured (stop !=
+   * -1), use that, else we play until the total duration of the file */
+  if ((stop = seeksegment.stop) == -1)
+    stop = seeksegment.duration;
+
+  GST_DEBUG_OBJECT (wav, "cur_type =%d", cur_type);
+  if ((cur_type != GST_SEEK_TYPE_NONE)) {
+    /* bring offset to bytes, if the bps is 0, we have the segment in BYTES and
+     * we can just copy the last_stop. If not, we use the bps to convert TIME to
+     * bytes. */
+    if (!gst_wavparse_time_to_bytepos (wav, seeksegment.position,
+            (gint64 *) & wav->offset))
+      wav->offset = seeksegment.position;
+    GST_LOG_OBJECT (wav, "offset=%" G_GUINT64_FORMAT, wav->offset);
+    wav->offset -= (wav->offset % wav->bytes_per_sample);
+    GST_LOG_OBJECT (wav, "offset=%" G_GUINT64_FORMAT, wav->offset);
+    wav->offset += wav->datastart;
+    GST_LOG_OBJECT (wav, "offset=%" G_GUINT64_FORMAT, wav->offset);
+  } else {
+    GST_LOG_OBJECT (wav, "continue from offset=%" G_GUINT64_FORMAT,
+        wav->offset);
+  }
+
+  if (stop_type != GST_SEEK_TYPE_NONE) {
+    if (!gst_wavparse_time_to_bytepos (wav, stop, (gint64 *) & wav->end_offset))
+      wav->end_offset = stop;
+    GST_LOG_OBJECT (wav, "end_offset=%" G_GUINT64_FORMAT, wav->end_offset);
+    wav->end_offset -= (wav->end_offset % wav->bytes_per_sample);
+    GST_LOG_OBJECT (wav, "end_offset=%" G_GUINT64_FORMAT, wav->end_offset);
+    wav->end_offset += wav->datastart;
+    GST_LOG_OBJECT (wav, "end_offset=%" G_GUINT64_FORMAT, wav->end_offset);
+  } else {
+    GST_LOG_OBJECT (wav, "continue to end_offset=%" G_GUINT64_FORMAT,
+        wav->end_offset);
+  }
+
+  /* make sure filesize is not exceeded due to rounding errors or so,
+   * same precaution as in _stream_headers */
+  bformat = GST_FORMAT_BYTES;
+  if (gst_pad_peer_query_duration (wav->sinkpad, bformat, &upstream_size))
+    wav->end_offset = MIN (wav->end_offset, upstream_size);
+
+  if (wav->datasize > 0 && wav->end_offset > wav->datastart + wav->datasize)
+    wav->end_offset = wav->datastart + wav->datasize;
+
+  /* this is the range of bytes we will use for playback */
+  wav->offset = MIN (wav->offset, wav->end_offset);
+  wav->dataleft = wav->end_offset - wav->offset;
+
+  GST_DEBUG_OBJECT (wav,
+      "seek: rate %lf, offset %" G_GUINT64_FORMAT ", end %" G_GUINT64_FORMAT
+      ", segment %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, rate, wav->offset,
+      wav->end_offset, GST_TIME_ARGS (seeksegment.start), GST_TIME_ARGS (stop));
+
+  /* prepare for streaming again */
+  if (flush) {
+    GstEvent *fevent;
+
+    /* if we sent a FLUSH_START, we now send a FLUSH_STOP */
+    GST_DEBUG_OBJECT (wav, "sending flush stop");
+
+    fevent = gst_event_new_flush_stop (TRUE);
+    gst_event_set_seqnum (fevent, seqnum);
+    gst_pad_push_event (wav->sinkpad, gst_event_ref (fevent));
+    gst_pad_push_event (wav->srcpad, fevent);
+  }
+
+  /* now we did the seek and can activate the new segment values */
+  memcpy (&wav->segment, &seeksegment, sizeof (GstSegment));
+
+  /* if we're doing a segment seek, post a SEGMENT_START message */
+  if (wav->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+    gst_element_post_message (GST_ELEMENT_CAST (wav),
+        gst_message_new_segment_start (GST_OBJECT_CAST (wav),
+            wav->segment.format, wav->segment.position));
+  }
+
+  /* now create the newsegment */
+  GST_DEBUG_OBJECT (wav, "Creating newsegment from %" G_GINT64_FORMAT
+      " to %" G_GINT64_FORMAT, wav->segment.position, stop);
+
+  /* store the newsegment event so it can be sent from the streaming thread. */
+  if (wav->start_segment)
+    gst_event_unref (wav->start_segment);
+  wav->start_segment = gst_event_new_segment (&wav->segment);
+  gst_event_set_seqnum (wav->start_segment, seqnum);
+
+  /* mark discont if we are going to stream from another position. */
+  if (last_stop != wav->segment.position) {
+    GST_DEBUG_OBJECT (wav, "mark DISCONT, we did a seek to another position");
+    wav->discont = TRUE;
+  }
+
+  /* and start the streaming task again */
+  if (!wav->streaming) {
+    gst_pad_start_task (wav->sinkpad, (GstTaskFunction) gst_wavparse_loop,
+        wav->sinkpad, NULL);
+  }
+
+  GST_PAD_STREAM_UNLOCK (wav->sinkpad);
+
+  return TRUE;
+
+  /* ERRORS */
+negative_rate:
+  {
+    GST_DEBUG_OBJECT (wav, "negative playback rates are not supported yet.");
+    return FALSE;
+  }
+no_format:
+  {
+    GST_DEBUG_OBJECT (wav, "unsupported format given, seek aborted.");
+    return FALSE;
+  }
+no_position:
+  {
+    GST_DEBUG_OBJECT (wav,
+        "Could not determine byte position for desired time");
+    return FALSE;
+  }
+}
+
+/*
+ * gst_wavparse_peek_chunk_info:
+ * @wav Wavparse object
+ * @tag holder for tag
+ * @size holder for tag size
+ *
+ * Peek next chunk info (tag and size)
+ *
+ * Returns: %TRUE when the chunk info (header) is available
+ */
+static gboolean
+gst_wavparse_peek_chunk_info (GstWavParse * wav, guint32 * tag, guint32 * size)
+{
+  const guint8 *data = NULL;
+
+  if (gst_adapter_available (wav->adapter) < 8)
+    return FALSE;
+
+  data = gst_adapter_map (wav->adapter, 8);
+  *tag = GST_READ_UINT32_LE (data);
+  *size = GST_READ_UINT32_LE (data + 4);
+  gst_adapter_unmap (wav->adapter);
+
+  GST_DEBUG ("Next chunk size is %u bytes, type %" GST_FOURCC_FORMAT, *size,
+      GST_FOURCC_ARGS (*tag));
+
+  return TRUE;
+}
+
+/*
+ * gst_wavparse_peek_chunk:
+ * @wav Wavparse object
+ * @tag holder for tag
+ * @size holder for tag size
+ *
+ * Peek enough data for one full chunk
+ *
+ * Returns: %TRUE when the full chunk is available
+ */
+static gboolean
+gst_wavparse_peek_chunk (GstWavParse * wav, guint32 * tag, guint32 * size)
+{
+  guint32 peek_size = 0;
+  guint available;
+
+  if (!gst_wavparse_peek_chunk_info (wav, tag, size))
+    return FALSE;
+
+  /* size 0 -> empty data buffer would surprise most callers,
+   * large size -> do not bother trying to squeeze that into adapter,
+   * so we throw poor man's exception, which can be caught if caller really
+   * wants to handle 0 size chunk */
+  if (!(*size) || (*size) >= (1 << 30)) {
+    GST_INFO ("Invalid/unexpected chunk size %u for tag %" GST_FOURCC_FORMAT,
+        *size, GST_FOURCC_ARGS (*tag));
+    /* chain should give up */
+    wav->abort_buffering = TRUE;
+    return FALSE;
+  }
+  peek_size = (*size + 1) & ~1;
+  available = gst_adapter_available (wav->adapter);
+
+  if (available >= (8 + peek_size)) {
+    return TRUE;
+  } else {
+    GST_LOG ("but only %u bytes available now", available);
+    return FALSE;
+  }
+}
+
+/*
+ * gst_wavparse_calculate_duration:
+ * @wav: wavparse object
+ *
+ * Calculate duration on demand and store in @wav. Prefer bps, but use fact as a
+ * fallback.
+ *
+ * Returns: %TRUE if duration is available.
+ */
+static gboolean
+gst_wavparse_calculate_duration (GstWavParse * wav)
+{
+  if (wav->duration > 0)
+    return TRUE;
+
+  if (wav->bps > 0) {
+    GST_INFO_OBJECT (wav, "Got datasize %" G_GUINT64_FORMAT, wav->datasize);
+    wav->duration =
+        gst_util_uint64_scale_ceil (wav->datasize, GST_SECOND,
+        (guint64) wav->bps);
+    GST_INFO_OBJECT (wav, "Got duration (bps) %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (wav->duration));
+    return TRUE;
+  } else if (wav->fact) {
+    wav->duration =
+        gst_util_uint64_scale_ceil (GST_SECOND, wav->fact, wav->rate);
+    GST_INFO_OBJECT (wav, "Got duration (fact) %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (wav->duration));
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static gboolean
+gst_waveparse_ignore_chunk (GstWavParse * wav, GstBuffer * buf, guint32 tag,
+    guint32 size)
+{
+  guint flush;
+
+  if (wav->streaming) {
+    if (!gst_wavparse_peek_chunk (wav, &tag, &size))
+      return FALSE;
+  }
+  GST_DEBUG_OBJECT (wav, "Ignoring tag %" GST_FOURCC_FORMAT,
+      GST_FOURCC_ARGS (tag));
+  flush = 8 + ((size + 1) & ~1);
+  wav->offset += flush;
+  if (wav->streaming) {
+    gst_adapter_flush (wav->adapter, flush);
+  } else {
+    gst_buffer_unref (buf);
+  }
+
+  return TRUE;
+}
+
+/*
+ * gst_wavparse_cue_chunk:
+ * @wav GstWavParse object
+ * @data holder for data
+ * @size holder for data size
+ *
+ * Parse cue chunk from @data to wav->cues.
+ *
+ * Returns: %TRUE when cue chunk is available
+ */
+static gboolean
+gst_wavparse_cue_chunk (GstWavParse * wav, const guint8 * data, guint32 size)
+{
+  guint32 i, ncues;
+  GList *cues = NULL;
+  GstWavParseCue *cue;
+
+  if (wav->cues) {
+    GST_WARNING_OBJECT (wav, "found another cue's");
+    return TRUE;
+  }
+
+  ncues = GST_READ_UINT32_LE (data);
+
+  if (size < 4 + ncues * 24) {
+    GST_WARNING_OBJECT (wav, "broken file %d %d", size, ncues);
+    return FALSE;
+  }
+
+  /* parse data */
+  data += 4;
+  for (i = 0; i < ncues; i++) {
+    cue = g_new0 (GstWavParseCue, 1);
+    cue->id = GST_READ_UINT32_LE (data);
+    cue->position = GST_READ_UINT32_LE (data + 4);
+    cue->data_chunk_id = GST_READ_UINT32_LE (data + 8);
+    cue->chunk_start = GST_READ_UINT32_LE (data + 12);
+    cue->block_start = GST_READ_UINT32_LE (data + 16);
+    cue->sample_offset = GST_READ_UINT32_LE (data + 20);
+    cues = g_list_append (cues, cue);
+    data += 24;
+  }
+
+  wav->cues = cues;
+
+  return TRUE;
+}
+
+/*
+ * gst_wavparse_labl_chunk:
+ * @wav GstWavParse object
+ * @data holder for data
+ * @size holder for data size
+ *
+ * Parse labl from @data to wav->labls.
+ *
+ * Returns: %TRUE when labl chunk is available
+ */
+static gboolean
+gst_wavparse_labl_chunk (GstWavParse * wav, const guint8 * data, guint32 size)
+{
+  GstWavParseLabl *labl;
+
+  if (size < 5)
+    return FALSE;
+
+  labl = g_new0 (GstWavParseLabl, 1);
+
+  /* parse data */
+  data += 8;
+  labl->cue_point_id = GST_READ_UINT32_LE (data);
+  labl->text = g_memdup (data + 4, size - 4);
+
+  wav->labls = g_list_append (wav->labls, labl);
+
+  return TRUE;
+}
+
+/*
+ * gst_wavparse_note_chunk:
+ * @wav GstWavParse object
+ * @data holder for data
+ * @size holder for data size
+ *
+ * Parse note from @data to wav->notes.
+ *
+ * Returns: %TRUE when note chunk is available
+ */
+static gboolean
+gst_wavparse_note_chunk (GstWavParse * wav, const guint8 * data, guint32 size)
+{
+  GstWavParseNote *note;
+
+  if (size < 5)
+    return FALSE;
+
+  note = g_new0 (GstWavParseNote, 1);
+
+  /* parse data */
+  data += 8;
+  note->cue_point_id = GST_READ_UINT32_LE (data);
+  note->text = g_memdup (data + 4, size - 4);
+
+  wav->notes = g_list_append (wav->notes, note);
+
+  return TRUE;
+}
+
+/*
+ * gst_wavparse_smpl_chunk:
+ * @wav GstWavParse object
+ * @data holder for data
+ * @size holder for data size
+ *
+ * Parse smpl chunk from @data.
+ *
+ * Returns: %TRUE when cue chunk is available
+ */
+static gboolean
+gst_wavparse_smpl_chunk (GstWavParse * wav, const guint8 * data, guint32 size)
+{
+  guint32 note_number;
+
+  /*
+     manufacturer_id = GST_READ_UINT32_LE (data);
+     product_id = GST_READ_UINT32_LE (data + 4);
+     sample_period = GST_READ_UINT32_LE (data + 8);
+   */
+  note_number = GST_READ_UINT32_LE (data + 12);
+  /*
+     pitch_fraction = GST_READ_UINT32_LE (data + 16);
+     SMPTE_format = GST_READ_UINT32_LE (data + 20);
+     SMPTE_offset = GST_READ_UINT32_LE (data + 24);
+     num_sample_loops = GST_READ_UINT32_LE (data + 28);
+     List of Sample Loops, 24 bytes each
+   */
+
+  if (!wav->tags)
+    wav->tags = gst_tag_list_new_empty ();
+  gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE,
+      GST_TAG_MIDI_BASE_NOTE, (guint) note_number, NULL);
+  return TRUE;
+}
+
+/*
+ * gst_wavparse_adtl_chunk:
+ * @wav GstWavParse object
+ * @data holder for data
+ * @size holder for data size
+ *
+ * Parse adtl from @data.
+ *
+ * Returns: %TRUE when adtl chunk is available
+ */
+static gboolean
+gst_wavparse_adtl_chunk (GstWavParse * wav, const guint8 * data, guint32 size)
+{
+  guint32 ltag, lsize, offset = 0;
+
+  while (size >= 8) {
+    ltag = GST_READ_UINT32_LE (data + offset);
+    lsize = GST_READ_UINT32_LE (data + offset + 4);
+
+    if (lsize + 8 > size) {
+      GST_WARNING_OBJECT (wav, "Invalid adtl size: %u + 8 > %u", lsize, size);
+      return FALSE;
+    }
+
+    switch (ltag) {
+      case GST_RIFF_TAG_labl:
+        gst_wavparse_labl_chunk (wav, data + offset, size);
+        break;
+      case GST_RIFF_TAG_note:
+        gst_wavparse_note_chunk (wav, data + offset, size);
+        break;
+      default:
+        GST_WARNING_OBJECT (wav, "Unknowm adtl %" GST_FOURCC_FORMAT,
+            GST_FOURCC_ARGS (ltag));
+        GST_MEMDUMP_OBJECT (wav, "Unknowm adtl", &data[offset], lsize);
+        break;
+    }
+    offset += 8 + GST_ROUND_UP_2 (lsize);
+    size -= 8 + GST_ROUND_UP_2 (lsize);
+  }
+
+  return TRUE;
+}
+
+static GstTagList *
+gst_wavparse_get_tags_toc_entry (GstToc * toc, gchar * id)
+{
+  GstTagList *tags = NULL;
+  GstTocEntry *entry = NULL;
+
+  entry = gst_toc_find_entry (toc, id);
+  if (entry != NULL) {
+    tags = gst_toc_entry_get_tags (entry);
+    if (tags == NULL) {
+      tags = gst_tag_list_new_empty ();
+      gst_toc_entry_set_tags (entry, tags);
+    }
+  }
+
+  return tags;
+}
+
+/*
+ * gst_wavparse_create_toc:
+ * @wav GstWavParse object
+ *
+ * Create TOC from wav->cues and wav->labls.
+ */
+static gboolean
+gst_wavparse_create_toc (GstWavParse * wav)
+{
+  gint64 start, stop;
+  gchar *id;
+  GList *list;
+  GstWavParseCue *cue;
+  GstWavParseLabl *labl;
+  GstWavParseNote *note;
+  GstTagList *tags;
+  GstToc *toc;
+  GstTocEntry *entry = NULL, *cur_subentry = NULL, *prev_subentry = NULL;
+
+  GST_OBJECT_LOCK (wav);
+  if (wav->toc) {
+    GST_OBJECT_UNLOCK (wav);
+    GST_WARNING_OBJECT (wav, "found another TOC");
+    return FALSE;
+  }
+
+  if (!wav->cues) {
+    GST_OBJECT_UNLOCK (wav);
+    return TRUE;
+  }
+
+  /* FIXME: send CURRENT scope toc too */
+  toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
+
+  /* add cue edition */
+  entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, "cue");
+  gst_toc_entry_set_start_stop_times (entry, 0, wav->duration);
+  gst_toc_append_entry (toc, entry);
+
+  /* add tracks in cue edition */
+  list = wav->cues;
+  while (list) {
+    cue = list->data;
+    prev_subentry = cur_subentry;
+    /* previous track stop time = current track start time */
+    if (prev_subentry != NULL) {
+      gst_toc_entry_get_start_stop_times (prev_subentry, &start, NULL);
+      stop = gst_util_uint64_scale_round (cue->position, GST_SECOND, wav->rate);
+      gst_toc_entry_set_start_stop_times (prev_subentry, start, stop);
+    }
+    id = g_strdup_printf ("%08x", cue->id);
+    cur_subentry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_TRACK, id);
+    g_free (id);
+    start = gst_util_uint64_scale_round (cue->position, GST_SECOND, wav->rate);
+    stop = wav->duration;
+    gst_toc_entry_set_start_stop_times (cur_subentry, start, stop);
+    gst_toc_entry_append_sub_entry (entry, cur_subentry);
+    list = g_list_next (list);
+  }
+
+  /* add tags in tracks */
+  list = wav->labls;
+  while (list) {
+    labl = list->data;
+    id = g_strdup_printf ("%08x", labl->cue_point_id);
+    tags = gst_wavparse_get_tags_toc_entry (toc, id);
+    g_free (id);
+    if (tags != NULL) {
+      gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE, labl->text,
+          NULL);
+    }
+    list = g_list_next (list);
+  }
+  list = wav->notes;
+  while (list) {
+    note = list->data;
+    id = g_strdup_printf ("%08x", note->cue_point_id);
+    tags = gst_wavparse_get_tags_toc_entry (toc, id);
+    g_free (id);
+    if (tags != NULL) {
+      gst_tag_list_add (tags, GST_TAG_MERGE_PREPEND, GST_TAG_COMMENT,
+          note->text, NULL);
+    }
+    list = g_list_next (list);
+  }
+
+  /* send data as TOC */
+  wav->toc = toc;
+
+  /* send TOC event */
+  if (wav->toc) {
+    GST_OBJECT_UNLOCK (wav);
+    gst_pad_push_event (wav->srcpad, gst_event_new_toc (wav->toc, FALSE));
+  }
+
+  return TRUE;
+}
+
+#define MAX_BUFFER_SIZE 4096
+
+static gboolean
+parse_ds64 (GstWavParse * wav, GstBuffer * buf)
+{
+  GstMapInfo map;
+  guint32 dataSizeLow, dataSizeHigh;
+  guint32 sampleCountLow, sampleCountHigh;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  dataSizeLow = GST_READ_UINT32_LE (map.data + 2 * 4);
+  dataSizeHigh = GST_READ_UINT32_LE (map.data + 3 * 4);
+  sampleCountLow = GST_READ_UINT32_LE (map.data + 4 * 4);
+  sampleCountHigh = GST_READ_UINT32_LE (map.data + 5 * 4);
+  gst_buffer_unmap (buf, &map);
+  if (dataSizeHigh != 0xFFFFFFFF && dataSizeLow != 0xFFFFFFFF) {
+    wav->datasize = ((guint64) dataSizeHigh << 32) | dataSizeLow;
+  }
+  if (sampleCountHigh != 0xFFFFFFFF && sampleCountLow != 0xFFFFFFFF) {
+    wav->fact = ((guint64) sampleCountHigh << 32) | sampleCountLow;
+  }
+
+  GST_DEBUG_OBJECT (wav, "Got 'ds64' TAG, datasize : %" G_GINT64_FORMAT
+      " fact: %" G_GINT64_FORMAT, wav->datasize, wav->fact);
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_wavparse_stream_headers (GstWavParse * wav)
+{
+  GstFlowReturn res = GST_FLOW_OK;
+  GstBuffer *buf = NULL;
+  gst_riff_strf_auds *header = NULL;
+  guint32 tag, size;
+  gboolean gotdata = FALSE;
+  GstCaps *caps = NULL;
+  gchar *codec_name = NULL;
+  gint64 upstream_size = 0;
+  GstStructure *s;
+
+  /* search for "_fmt" chunk, which must be before "data" */
+  while (!wav->got_fmt) {
+    GstBuffer *extra;
+
+    if (wav->streaming) {
+      if (!gst_wavparse_peek_chunk (wav, &tag, &size))
+        return res;
+
+      gst_adapter_flush (wav->adapter, 8);
+      wav->offset += 8;
+
+      if (size) {
+        buf = gst_adapter_take_buffer (wav->adapter, size);
+        if (size & 1)
+          gst_adapter_flush (wav->adapter, 1);
+        wav->offset += GST_ROUND_UP_2 (size);
+      } else {
+        buf = gst_buffer_new ();
+      }
+    } else {
+      if ((res = gst_riff_read_chunk (GST_ELEMENT_CAST (wav), wav->sinkpad,
+                  &wav->offset, &tag, &buf)) != GST_FLOW_OK)
+        return res;
+    }
+
+    if (tag == GST_RS64_TAG_DS64) {
+      if (!parse_ds64 (wav, buf))
+        goto fail;
+      else
+        continue;
+    }
+
+    if (tag != GST_RIFF_TAG_fmt) {
+      GST_DEBUG_OBJECT (wav, "skipping %" GST_FOURCC_FORMAT " chunk",
+          GST_FOURCC_ARGS (tag));
+      gst_buffer_unref (buf);
+      buf = NULL;
+      continue;
+    }
+
+    if (!(gst_riff_parse_strf_auds (GST_ELEMENT_CAST (wav), buf, &header,
+                &extra)))
+      goto parse_header_error;
+
+    buf = NULL;                 /* parse_strf_auds() took ownership of buffer */
+
+    /* do sanity checks of header fields */
+    if (header->channels == 0)
+      goto no_channels;
+    if (header->rate == 0)
+      goto no_rate;
+
+    GST_DEBUG_OBJECT (wav, "creating the caps");
+
+    /* Note: gst_riff_create_audio_caps might need to fix values in
+     * the header header depending on the format, so call it first */
+    /* FIXME: Need to handle the channel reorder map */
+    caps = gst_riff_create_audio_caps (header->format, NULL, header, extra,
+        NULL, &codec_name, NULL);
+
+    if (extra)
+      gst_buffer_unref (extra);
+
+    if (!caps)
+      goto unknown_format;
+
+    /* If we got raw audio from upstream, we remove the codec_data field,
+     * which may have been added if the wav header included an extended
+     * chunk. We want to keep it for non raw audio.
+     */
+    s = gst_caps_get_structure (caps, 0);
+    if (s && gst_structure_has_name (s, "audio/x-raw")) {
+      gst_structure_remove_field (s, "codec_data");
+    }
+
+    /* do more sanity checks of header fields
+     * (these can be sanitized by gst_riff_create_audio_caps()
+     */
+    wav->format = header->format;
+    wav->rate = header->rate;
+    wav->channels = header->channels;
+    wav->blockalign = header->blockalign;
+    wav->depth = header->bits_per_sample;
+    wav->av_bps = header->av_bps;
+    wav->vbr = FALSE;
+
+    g_free (header);
+    header = NULL;
+
+    /* do format specific handling */
+    switch (wav->format) {
+      case GST_RIFF_WAVE_FORMAT_MPEGL12:
+      case GST_RIFF_WAVE_FORMAT_MPEGL3:
+      {
+        /* Note: workaround for mp2/mp3 embedded in wav, that relies on the
+         * bitrate inside the mpeg stream */
+        GST_INFO ("resetting bps from %u to 0 for mp2/3", wav->av_bps);
+        wav->bps = 0;
+        break;
+      }
+      case GST_RIFF_WAVE_FORMAT_PCM:
+        if (wav->blockalign > wav->channels * ((wav->depth + 7) / 8))
+          goto invalid_blockalign;
+        /* fall through */
+      default:
+        if (wav->av_bps > wav->blockalign * wav->rate)
+          goto invalid_bps;
+        /* use the configured bps */
+        wav->bps = wav->av_bps;
+        break;
+    }
+
+    wav->width = (wav->blockalign * 8) / wav->channels;
+    wav->bytes_per_sample = wav->channels * wav->width / 8;
+
+    if (wav->bytes_per_sample <= 0)
+      goto no_bytes_per_sample;
+
+    GST_DEBUG_OBJECT (wav, "blockalign = %u", (guint) wav->blockalign);
+    GST_DEBUG_OBJECT (wav, "width      = %u", (guint) wav->width);
+    GST_DEBUG_OBJECT (wav, "depth      = %u", (guint) wav->depth);
+    GST_DEBUG_OBJECT (wav, "av_bps     = %u", (guint) wav->av_bps);
+    GST_DEBUG_OBJECT (wav, "frequency  = %u", (guint) wav->rate);
+    GST_DEBUG_OBJECT (wav, "channels   = %u", (guint) wav->channels);
+    GST_DEBUG_OBJECT (wav, "bytes_per_sample = %u", wav->bytes_per_sample);
+
+    /* bps can be 0 when we don't have a valid bitrate (mostly for compressed
+     * formats). This will make the element output a BYTE format segment and
+     * will not timestamp the outgoing buffers.
+     */
+    GST_DEBUG_OBJECT (wav, "bps        = %u", (guint) wav->bps);
+
+    GST_DEBUG_OBJECT (wav, "caps = %" GST_PTR_FORMAT, caps);
+
+    /* create pad later so we can sniff the first few bytes
+     * of the real data and correct our caps if necessary */
+    gst_caps_replace (&wav->caps, caps);
+    gst_caps_replace (&caps, NULL);
+
+    wav->got_fmt = TRUE;
+
+    if (wav->tags == NULL)
+      wav->tags = gst_tag_list_new_empty ();
+
+    {
+      GstCaps *templ_caps = gst_pad_get_pad_template_caps (wav->sinkpad);
+      gst_pb_utils_add_codec_description_to_tag_list (wav->tags,
+          GST_TAG_CONTAINER_FORMAT, templ_caps);
+      gst_caps_unref (templ_caps);
+    }
+
+    /* If bps is nonzero, then we do have a valid bitrate that can be
+     * announced in a tag list. */
+    if (wav->bps) {
+      guint bitrate = wav->bps * 8;
+      gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE,
+          GST_TAG_BITRATE, bitrate, NULL);
+    }
+
+    if (codec_name) {
+      gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE,
+          GST_TAG_AUDIO_CODEC, codec_name, NULL);
+
+      g_free (codec_name);
+      codec_name = NULL;
+    }
+
+  }
+
+  gst_pad_peer_query_duration (wav->sinkpad, GST_FORMAT_BYTES, &upstream_size);
+  GST_DEBUG_OBJECT (wav, "upstream size %" G_GUINT64_FORMAT, upstream_size);
+
+  /* loop headers until we get data */
+  while (!gotdata) {
+    if (wav->streaming) {
+      if (!gst_wavparse_peek_chunk_info (wav, &tag, &size))
+        goto exit;
+    } else {
+      GstMapInfo map;
+
+      buf = NULL;
+      if ((res =
+              gst_pad_pull_range (wav->sinkpad, wav->offset, 8,
+                  &buf)) != GST_FLOW_OK)
+        goto header_read_error;
+      gst_buffer_map (buf, &map, GST_MAP_READ);
+      tag = GST_READ_UINT32_LE (map.data);
+      size = GST_READ_UINT32_LE (map.data + 4);
+      gst_buffer_unmap (buf, &map);
+    }
+
+    GST_INFO_OBJECT (wav,
+        "Got TAG: %" GST_FOURCC_FORMAT ", offset %" G_GUINT64_FORMAT ", size %"
+        G_GUINT32_FORMAT, GST_FOURCC_ARGS (tag), wav->offset, size);
+
+    /* Maximum valid size is INT_MAX */
+    if (size & 0x80000000) {
+      GST_WARNING_OBJECT (wav, "Invalid size, clipping to 0x7fffffff");
+      size = 0x7fffffff;
+    }
+
+    /* Clip to upstream size if known */
+    if (upstream_size > 0 && size + wav->offset > upstream_size) {
+      GST_WARNING_OBJECT (wav, "Clipping chunk size to file size");
+      g_assert (upstream_size >= wav->offset);
+      size = upstream_size - wav->offset;
+    }
+
+    /* wav is a st00pid format, we don't know for sure where data starts.
+     * So we have to go bit by bit until we find the 'data' header
+     */
+    switch (tag) {
+      case GST_RIFF_TAG_data:{
+        guint64 size64;
+
+        GST_DEBUG_OBJECT (wav, "Got 'data' TAG, size : %u", size);
+        size64 = size;
+        if (wav->ignore_length) {
+          GST_DEBUG_OBJECT (wav, "Ignoring length");
+          size64 = 0;
+        }
+        if (wav->streaming) {
+          gst_adapter_flush (wav->adapter, 8);
+          gotdata = TRUE;
+        } else {
+          gst_buffer_unref (buf);
+        }
+        wav->offset += 8;
+        wav->datastart = wav->offset;
+        /* use size from ds64 chunk if available */
+        if (size64 == -1 && wav->datasize > 0) {
+          GST_DEBUG_OBJECT (wav, "Using ds64 datasize");
+          size64 = wav->datasize;
+        }
+        wav->chunk_size = size64;
+
+        /* If size is zero, then the data chunk probably actually extends to
+           the end of the file */
+        if (size64 == 0 && upstream_size) {
+          size64 = upstream_size - wav->datastart;
+        }
+        /* Or the file might be truncated */
+        else if (upstream_size) {
+          size64 = MIN (size64, (upstream_size - wav->datastart));
+        }
+        wav->datasize = size64;
+        wav->dataleft = size64;
+        wav->end_offset = size64 + wav->datastart;
+        if (!wav->streaming) {
+          /* We will continue parsing tags 'till end */
+          wav->offset += size64;
+        }
+        GST_DEBUG_OBJECT (wav, "datasize = %" G_GUINT64_FORMAT, size64);
+        break;
+      }
+      case GST_RIFF_TAG_fact:{
+        if (wav->fact == 0 &&
+            wav->format != GST_RIFF_WAVE_FORMAT_MPEGL12 &&
+            wav->format != GST_RIFF_WAVE_FORMAT_MPEGL3) {
+          const guint data_size = 4;
+
+          GST_INFO_OBJECT (wav, "Have fact chunk");
+          if (size < data_size) {
+            if (!gst_waveparse_ignore_chunk (wav, buf, tag, size)) {
+              /* need more data */
+              goto exit;
+            }
+            GST_DEBUG_OBJECT (wav, "need %u, available %u; ignoring chunk",
+                data_size, size);
+            break;
+          }
+          /* number of samples (for compressed formats) */
+          if (wav->streaming) {
+            const guint8 *data = NULL;
+
+            if (!gst_wavparse_peek_chunk (wav, &tag, &size)) {
+              goto exit;
+            }
+            gst_adapter_flush (wav->adapter, 8);
+            data = gst_adapter_map (wav->adapter, data_size);
+            wav->fact = GST_READ_UINT32_LE (data);
+            gst_adapter_unmap (wav->adapter);
+            gst_adapter_flush (wav->adapter, GST_ROUND_UP_2 (size));
+          } else {
+            gst_buffer_unref (buf);
+            buf = NULL;
+            if ((res =
+                    gst_pad_pull_range (wav->sinkpad, wav->offset + 8,
+                        data_size, &buf)) != GST_FLOW_OK)
+              goto header_read_error;
+            gst_buffer_extract (buf, 0, &wav->fact, 4);
+            wav->fact = GUINT32_FROM_LE (wav->fact);
+            gst_buffer_unref (buf);
+          }
+          GST_DEBUG_OBJECT (wav, "have fact %" G_GUINT64_FORMAT, wav->fact);
+          wav->offset += 8 + GST_ROUND_UP_2 (size);
+          break;
+        } else {
+          if (!gst_waveparse_ignore_chunk (wav, buf, tag, size)) {
+            /* need more data */
+            goto exit;
+          }
+        }
+        break;
+      }
+      case GST_RIFF_TAG_acid:{
+        const gst_riff_acid *acid = NULL;
+        const guint data_size = sizeof (gst_riff_acid);
+        gfloat tempo;
+
+        GST_INFO_OBJECT (wav, "Have acid chunk");
+        if (size < data_size) {
+          if (!gst_waveparse_ignore_chunk (wav, buf, tag, size)) {
+            /* need more data */
+            goto exit;
+          }
+          GST_DEBUG_OBJECT (wav, "need %u, available %u; ignoring chunk",
+              data_size, size);
+          break;
+        }
+        if (wav->streaming) {
+          if (!gst_wavparse_peek_chunk (wav, &tag, &size)) {
+            goto exit;
+          }
+          gst_adapter_flush (wav->adapter, 8);
+          acid = (const gst_riff_acid *) gst_adapter_map (wav->adapter,
+              data_size);
+          tempo = acid->tempo;
+          gst_adapter_unmap (wav->adapter);
+        } else {
+          GstMapInfo map;
+          gst_buffer_unref (buf);
+          buf = NULL;
+          if ((res =
+                  gst_pad_pull_range (wav->sinkpad, wav->offset + 8,
+                      size, &buf)) != GST_FLOW_OK)
+            goto header_read_error;
+          gst_buffer_map (buf, &map, GST_MAP_READ);
+          acid = (const gst_riff_acid *) map.data;
+          tempo = acid->tempo;
+          gst_buffer_unmap (buf, &map);
+        }
+        /* send data as tags */
+        if (!wav->tags)
+          wav->tags = gst_tag_list_new_empty ();
+        gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE,
+            GST_TAG_BEATS_PER_MINUTE, tempo, NULL);
+
+        size = GST_ROUND_UP_2 (size);
+        if (wav->streaming) {
+          gst_adapter_flush (wav->adapter, size);
+        } else {
+          gst_buffer_unref (buf);
+        }
+        wav->offset += 8 + size;
+        break;
+      }
+        /* FIXME: all list tags after data are ignored in streaming mode */
+      case GST_RIFF_TAG_LIST:{
+        guint32 ltag;
+
+        if (wav->streaming) {
+          const guint8 *data = NULL;
+
+          if (gst_adapter_available (wav->adapter) < 12) {
+            goto exit;
+          }
+          data = gst_adapter_map (wav->adapter, 12);
+          ltag = GST_READ_UINT32_LE (data + 8);
+          gst_adapter_unmap (wav->adapter);
+        } else {
+          gst_buffer_unref (buf);
+          buf = NULL;
+          if ((res =
+                  gst_pad_pull_range (wav->sinkpad, wav->offset, 12,
+                      &buf)) != GST_FLOW_OK)
+            goto header_read_error;
+          gst_buffer_extract (buf, 8, &ltag, 4);
+          ltag = GUINT32_FROM_LE (ltag);
+        }
+        switch (ltag) {
+          case GST_RIFF_LIST_INFO:{
+            const gint data_size = size - 4;
+            GstTagList *new;
+
+            GST_INFO_OBJECT (wav, "Have LIST chunk INFO size %u", data_size);
+            if (wav->streaming) {
+              if (!gst_wavparse_peek_chunk (wav, &tag, &size)) {
+                goto exit;
+              }
+              gst_adapter_flush (wav->adapter, 12);
+              wav->offset += 12;
+              if (data_size > 0) {
+                buf = gst_adapter_take_buffer (wav->adapter, data_size);
+                if (data_size & 1)
+                  gst_adapter_flush (wav->adapter, 1);
+              }
+            } else {
+              wav->offset += 12;
+              gst_buffer_unref (buf);
+              buf = NULL;
+              if (data_size > 0) {
+                if ((res =
+                        gst_pad_pull_range (wav->sinkpad, wav->offset,
+                            data_size, &buf)) != GST_FLOW_OK)
+                  goto header_read_error;
+              }
+            }
+            if (data_size > 0) {
+              /* parse tags */
+              gst_riff_parse_info (GST_ELEMENT (wav), buf, &new);
+              if (new) {
+                GstTagList *old = wav->tags;
+                wav->tags =
+                    gst_tag_list_merge (old, new, GST_TAG_MERGE_REPLACE);
+                if (old)
+                  gst_tag_list_unref (old);
+                gst_tag_list_unref (new);
+              }
+              gst_buffer_unref (buf);
+              wav->offset += GST_ROUND_UP_2 (data_size);
+            }
+            break;
+          }
+          case GST_RIFF_LIST_adtl:{
+            const gint data_size = size - 4;
+
+            GST_INFO_OBJECT (wav, "Have 'adtl' LIST, size %u", data_size);
+            if (wav->streaming) {
+              const guint8 *data = NULL;
+
+              gst_adapter_flush (wav->adapter, 12);
+              wav->offset += 12;
+              data = gst_adapter_map (wav->adapter, data_size);
+              gst_wavparse_adtl_chunk (wav, data, data_size);
+              gst_adapter_unmap (wav->adapter);
+            } else {
+              GstMapInfo map;
+
+              gst_buffer_unref (buf);
+              buf = NULL;
+              wav->offset += 12;
+              if ((res =
+                      gst_pad_pull_range (wav->sinkpad, wav->offset,
+                          data_size, &buf)) != GST_FLOW_OK)
+                goto header_read_error;
+              gst_buffer_map (buf, &map, GST_MAP_READ);
+              gst_wavparse_adtl_chunk (wav, (const guint8 *) map.data,
+                  data_size);
+              gst_buffer_unmap (buf, &map);
+            }
+            wav->offset += GST_ROUND_UP_2 (data_size);
+            break;
+          }
+          default:
+            GST_WARNING_OBJECT (wav, "Ignoring LIST chunk %" GST_FOURCC_FORMAT,
+                GST_FOURCC_ARGS (ltag));
+            if (!gst_waveparse_ignore_chunk (wav, buf, tag, size))
+              /* need more data */
+              goto exit;
+            break;
+        }
+        break;
+      }
+      case GST_RIFF_TAG_cue:{
+        const guint data_size = size;
+
+        GST_DEBUG_OBJECT (wav, "Have 'cue' TAG, size : %u", data_size);
+        if (wav->streaming) {
+          const guint8 *data = NULL;
+
+          if (!gst_wavparse_peek_chunk (wav, &tag, &size)) {
+            goto exit;
+          }
+          gst_adapter_flush (wav->adapter, 8);
+          wav->offset += 8;
+          data = gst_adapter_map (wav->adapter, data_size);
+          if (!gst_wavparse_cue_chunk (wav, data, data_size)) {
+            goto header_read_error;
+          }
+          gst_adapter_unmap (wav->adapter);
+        } else {
+          GstMapInfo map;
+
+          wav->offset += 8;
+          gst_buffer_unref (buf);
+          buf = NULL;
+          if ((res =
+                  gst_pad_pull_range (wav->sinkpad, wav->offset,
+                      data_size, &buf)) != GST_FLOW_OK)
+            goto header_read_error;
+          gst_buffer_map (buf, &map, GST_MAP_READ);
+          if (!gst_wavparse_cue_chunk (wav, (const guint8 *) map.data,
+                  data_size)) {
+            goto header_read_error;
+          }
+          gst_buffer_unmap (buf, &map);
+        }
+        size = GST_ROUND_UP_2 (size);
+        if (wav->streaming) {
+          gst_adapter_flush (wav->adapter, size);
+        } else {
+          gst_buffer_unref (buf);
+        }
+        size = GST_ROUND_UP_2 (size);
+        wav->offset += size;
+        break;
+      }
+      case GST_RIFF_TAG_smpl:{
+        const gint data_size = size;
+
+        GST_DEBUG_OBJECT (wav, "Have 'smpl' TAG, size : %u", data_size);
+        if (wav->streaming) {
+          const guint8 *data = NULL;
+
+          if (!gst_wavparse_peek_chunk (wav, &tag, &size)) {
+            goto exit;
+          }
+          gst_adapter_flush (wav->adapter, 8);
+          wav->offset += 8;
+          data = gst_adapter_map (wav->adapter, data_size);
+          if (!gst_wavparse_smpl_chunk (wav, data, data_size)) {
+            goto header_read_error;
+          }
+          gst_adapter_unmap (wav->adapter);
+        } else {
+          GstMapInfo map;
+
+          wav->offset += 8;
+          gst_buffer_unref (buf);
+          buf = NULL;
+          if ((res =
+                  gst_pad_pull_range (wav->sinkpad, wav->offset,
+                      data_size, &buf)) != GST_FLOW_OK)
+            goto header_read_error;
+          gst_buffer_map (buf, &map, GST_MAP_READ);
+          if (!gst_wavparse_smpl_chunk (wav, (const guint8 *) map.data,
+                  data_size)) {
+            goto header_read_error;
+          }
+          gst_buffer_unmap (buf, &map);
+        }
+        size = GST_ROUND_UP_2 (size);
+        if (wav->streaming) {
+          gst_adapter_flush (wav->adapter, size);
+        } else {
+          gst_buffer_unref (buf);
+        }
+        size = GST_ROUND_UP_2 (size);
+        wav->offset += size;
+        break;
+      }
+      default:
+        GST_WARNING_OBJECT (wav, "Ignoring chunk %" GST_FOURCC_FORMAT,
+            GST_FOURCC_ARGS (tag));
+        if (!gst_waveparse_ignore_chunk (wav, buf, tag, size))
+          /* need more data */
+          goto exit;
+        break;
+    }
+
+    if (upstream_size && (wav->offset >= upstream_size)) {
+      /* Now we are gone through the whole file */
+      gotdata = TRUE;
+    }
+  }
+
+  GST_DEBUG_OBJECT (wav, "Finished parsing headers");
+
+  if (wav->bps <= 0 && wav->fact) {
+#if 0
+    /* not a good idea, as for embedded mp2/mp3 we set bps to 0 earlier */
+    wav->bps =
+        (guint32) gst_util_uint64_scale ((guint64) wav->rate, wav->datasize,
+        (guint64) wav->fact);
+    GST_INFO_OBJECT (wav, "calculated bps : %u, enabling VBR", wav->bps);
+#endif
+    wav->vbr = TRUE;
+  }
+
+  if (gst_wavparse_calculate_duration (wav)) {
+    gst_segment_init (&wav->segment, GST_FORMAT_TIME);
+    if (!wav->ignore_length)
+      wav->segment.duration = wav->duration;
+    if (!wav->toc)
+      gst_wavparse_create_toc (wav);
+  } else {
+    /* no bitrate, let downstream peer do the math, we'll feed it bytes. */
+    gst_segment_init (&wav->segment, GST_FORMAT_BYTES);
+    if (!wav->ignore_length)
+      wav->segment.duration = wav->datasize;
+  }
+
+  /* now we have all the info to perform a pending seek if any, if no
+   * event, this will still do the right thing and it will also send
+   * the right newsegment event downstream. */
+  gst_wavparse_perform_seek (wav, wav->seek_event);
+  /* remove pending event */
+  gst_event_replace (&wav->seek_event, NULL);
+
+  /* we just started, we are discont */
+  wav->discont = TRUE;
+
+  wav->state = GST_WAVPARSE_DATA;
+
+  /* determine reasonable max buffer size,
+   * that is, buffers not too small either size or time wise
+   * so we do not end up with too many of them */
+  /* var abuse */
+  if (gst_wavparse_time_to_bytepos (wav, 40 * GST_MSECOND, &upstream_size))
+    wav->max_buf_size = upstream_size;
+  else
+    wav->max_buf_size = 0;
+  wav->max_buf_size = MAX (wav->max_buf_size, MAX_BUFFER_SIZE);
+  if (wav->blockalign > 0)
+    wav->max_buf_size -= (wav->max_buf_size % wav->blockalign);
+
+  GST_DEBUG_OBJECT (wav, "max buffer size %u", wav->max_buf_size);
+
+  return GST_FLOW_OK;
+
+  /* ERROR */
+exit:
+  {
+    g_free (codec_name);
+    g_free (header);
+    if (caps)
+      gst_caps_unref (caps);
+    return res;
+  }
+fail:
+  {
+    res = GST_FLOW_ERROR;
+    goto exit;
+  }
+parse_header_error:
+  {
+    GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL),
+        ("Couldn't parse audio header"));
+    goto fail;
+  }
+no_channels:
+  {
+    GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
+        ("Stream claims to contain no channels - invalid data"));
+    goto fail;
+  }
+no_rate:
+  {
+    GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
+        ("Stream with sample_rate == 0 - invalid data"));
+    goto fail;
+  }
+invalid_blockalign:
+  {
+    GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
+        ("Stream claims blockalign = %u, which is more than %u - invalid data",
+            wav->blockalign, wav->channels * ((wav->depth + 7) / 8)));
+    goto fail;
+  }
+invalid_bps:
+  {
+    GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
+        ("Stream claims av_bsp = %u, which is more than %u - invalid data",
+            wav->av_bps, wav->blockalign * wav->rate));
+    goto fail;
+  }
+no_bytes_per_sample:
+  {
+    GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
+        ("Could not caluclate bytes per sample - invalid data"));
+    goto fail;
+  }
+unknown_format:
+  {
+    GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL),
+        ("No caps found for format 0x%x, %u channels, %u Hz",
+            wav->format, wav->channels, wav->rate));
+    goto fail;
+  }
+header_read_error:
+  {
+    GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL),
+        ("Couldn't read in header %d (%s)", res, gst_flow_get_name (res)));
+    goto fail;
+  }
+}
+
+/*
+ * Read WAV file tag when streaming
+ */
+static GstFlowReturn
+gst_wavparse_parse_stream_init (GstWavParse * wav)
+{
+  if (gst_adapter_available (wav->adapter) >= 12) {
+    GstBuffer *tmp;
+
+    /* _take flushes the data */
+    tmp = gst_adapter_take_buffer (wav->adapter, 12);
+
+    GST_DEBUG ("Parsing wav header");
+    if (!gst_wavparse_parse_file_header (GST_ELEMENT_CAST (wav), tmp))
+      return GST_FLOW_ERROR;
+
+    wav->offset += 12;
+    /* Go to next state */
+    wav->state = GST_WAVPARSE_HEADER;
+  }
+  return GST_FLOW_OK;
+}
+
+/* handle an event sent directly to the element.
+ *
+ * This event can be sent either in the READY state or the
+ * >READY state. The only event of interest really is the seek
+ * event.
+ *
+ * In the READY state we can only store the event and try to
+ * respect it when going to PAUSED. We assume we are in the
+ * READY state when our parsing state != GST_WAVPARSE_DATA.
+ *
+ * When we are steaming, we can simply perform the seek right
+ * away.
+ */
+static gboolean
+gst_wavparse_send_event (GstElement * element, GstEvent * event)
+{
+  GstWavParse *wav = GST_WAVPARSE (element);
+  gboolean res = FALSE;
+
+  GST_DEBUG_OBJECT (wav, "received event %s", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+      if (wav->state == GST_WAVPARSE_DATA) {
+        /* we can handle the seek directly when streaming data */
+        res = gst_wavparse_perform_seek (wav, event);
+      } else {
+        GST_DEBUG_OBJECT (wav, "queuing seek for later");
+
+        gst_event_replace (&wav->seek_event, event);
+
+        /* we always return true */
+        res = TRUE;
+      }
+      break;
+    default:
+      break;
+  }
+  gst_event_unref (event);
+  return res;
+}
+
+static gboolean
+gst_wavparse_have_dts_caps (const GstCaps * caps, GstTypeFindProbability prob)
+{
+  GstStructure *s;
+
+  s = gst_caps_get_structure (caps, 0);
+  if (!gst_structure_has_name (s, "audio/x-dts"))
+    return FALSE;
+  /* typefind behavior for DTS:
+   *  MAXIMUM: multiple frame syncs detected, certainly DTS
+   *  LIKELY: single frame sync at offset 0.  Maybe DTS?
+   *  POSSIBLE: single frame sync, not at offset 0.  Highly unlikely
+   *    to be DTS.  */
+  if (prob > GST_TYPE_FIND_LIKELY)
+    return TRUE;
+  if (prob <= GST_TYPE_FIND_POSSIBLE)
+    return FALSE;
+  /* for maybe, check for at least a valid-looking rate and channels */
+  if (!gst_structure_has_field (s, "channels"))
+    return FALSE;
+  /* and for extra assurance we could also check the rate from the DTS frame
+   * against the one in the wav header, but for now let's not do that */
+  return gst_structure_has_field (s, "rate");
+}
+
+static GstTagList *
+gst_wavparse_get_upstream_tags (GstWavParse * wav, GstTagScope scope)
+{
+  GstTagList *tags = NULL;
+  GstEvent *ev;
+  gint i;
+
+  i = 0;
+  while ((ev = gst_pad_get_sticky_event (wav->sinkpad, GST_EVENT_TAG, i++))) {
+    gst_event_parse_tag (ev, &tags);
+    if (tags != NULL && gst_tag_list_get_scope (tags) == scope) {
+      tags = gst_tag_list_copy (tags);
+      gst_tag_list_remove_tag (tags, GST_TAG_CONTAINER_FORMAT);
+      gst_event_unref (ev);
+      break;
+    }
+    tags = NULL;
+    gst_event_unref (ev);
+  }
+  return tags;
+}
+
+static void
+gst_wavparse_add_src_pad (GstWavParse * wav, GstBuffer * buf)
+{
+  GstStructure *s;
+  GstTagList *tags, *utags;
+
+  GST_DEBUG_OBJECT (wav, "adding src pad");
+
+  g_assert (wav->caps != NULL);
+
+  s = gst_caps_get_structure (wav->caps, 0);
+  if (s && gst_structure_has_name (s, "audio/x-raw") && buf != NULL) {
+    GstTypeFindProbability prob;
+    GstCaps *tf_caps;
+
+    tf_caps = gst_type_find_helper_for_buffer (GST_OBJECT (wav), buf, &prob);
+    if (tf_caps != NULL) {
+      GST_LOG ("typefind caps = %" GST_PTR_FORMAT ", P=%d", tf_caps, prob);
+      if (gst_wavparse_have_dts_caps (tf_caps, prob)) {
+        GST_INFO_OBJECT (wav, "Found DTS marker in file marked as raw PCM");
+        gst_caps_unref (wav->caps);
+        wav->caps = tf_caps;
+
+        gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE,
+            GST_TAG_AUDIO_CODEC, "dts", NULL);
+      } else {
+        GST_DEBUG_OBJECT (wav, "found caps %" GST_PTR_FORMAT " for stream "
+            "marked as raw PCM audio, but ignoring for now", tf_caps);
+        gst_caps_unref (tf_caps);
+      }
+    }
+  }
+
+  gst_pad_set_caps (wav->srcpad, wav->caps);
+
+  if (wav->start_segment) {
+    GST_DEBUG_OBJECT (wav, "Send start segment event on newpad");
+    gst_pad_push_event (wav->srcpad, wav->start_segment);
+    wav->start_segment = NULL;
+  }
+
+  /* upstream tags, e.g. from id3/ape tag before the wav file; assume for now
+   * that there'll be only one scope/type of tag list from upstream, if any */
+  utags = gst_wavparse_get_upstream_tags (wav, GST_TAG_SCOPE_GLOBAL);
+  if (utags == NULL)
+    utags = gst_wavparse_get_upstream_tags (wav, GST_TAG_SCOPE_STREAM);
+
+  /* if there's a tag upstream it's probably been added to override the
+   * tags from inside the wav header, so keep upstream tags if in doubt */
+  tags = gst_tag_list_merge (utags, wav->tags, GST_TAG_MERGE_KEEP);
+
+  if (wav->tags != NULL) {
+    gst_tag_list_unref (wav->tags);
+    wav->tags = NULL;
+  }
+
+  if (utags != NULL)
+    gst_tag_list_unref (utags);
+
+  /* send tags downstream, if any */
+  if (tags != NULL)
+    gst_pad_push_event (wav->srcpad, gst_event_new_tag (tags));
+}
+
+static GstFlowReturn
+gst_wavparse_stream_data (GstWavParse * wav)
+{
+  GstBuffer *buf = NULL;
+  GstFlowReturn res = GST_FLOW_OK;
+  guint64 desired, obtained;
+  GstClockTime timestamp, next_timestamp, duration;
+  guint64 pos, nextpos;
+
+iterate_adapter:
+  GST_LOG_OBJECT (wav,
+      "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT " , dataleft: %"
+      G_GINT64_FORMAT, wav->offset, wav->end_offset, wav->dataleft);
+
+  if ((wav->dataleft == 0 || wav->dataleft < wav->blockalign)) {
+    /* In case chunk size is not declared in the begining get size from the
+     * file size directly */
+    if (wav->chunk_size == 0) {
+      gint64 upstream_size = 0;
+
+      /* Get the size of the file   */
+      if (!gst_pad_peer_query_duration (wav->sinkpad, GST_FORMAT_BYTES,
+              &upstream_size))
+        goto found_eos;
+
+      if (upstream_size < wav->offset + wav->datastart)
+        goto found_eos;
+
+      /* If file has updated since the beggining continue reading the file */
+      wav->dataleft = upstream_size - wav->offset - wav->datastart;
+      wav->end_offset = upstream_size;
+
+      /* Get the next n bytes and output them, if we can */
+      if (wav->dataleft == 0 || wav->dataleft < wav->blockalign)
+        goto found_eos;
+    } else {
+      goto found_eos;
+    }
+  }
+
+  /* scale the amount of data by the segment rate so we get equal
+   * amounts of data regardless of the playback rate */
+  desired =
+      MIN (gst_guint64_to_gdouble (wav->dataleft),
+      wav->max_buf_size * ABS (wav->segment.rate));
+
+  if (desired >= wav->blockalign && wav->blockalign > 0)
+    desired -= (desired % wav->blockalign);
+
+  GST_LOG_OBJECT (wav, "Fetching %" G_GINT64_FORMAT " bytes of data "
+      "from the sinkpad", desired);
+
+  if (wav->streaming) {
+    guint avail = gst_adapter_available (wav->adapter);
+    guint extra;
+
+    /* flush some bytes if evil upstream sends segment that starts
+     * before data or does is not send sample aligned segment */
+    if (G_LIKELY (wav->offset >= wav->datastart)) {
+      extra = (wav->offset - wav->datastart) % wav->bytes_per_sample;
+    } else {
+      extra = wav->datastart - wav->offset;
+    }
+
+    if (G_UNLIKELY (extra)) {
+      extra = wav->bytes_per_sample - extra;
+      if (extra <= avail) {
+        GST_DEBUG_OBJECT (wav, "flushing %u bytes to sample boundary", extra);
+        gst_adapter_flush (wav->adapter, extra);
+        wav->offset += extra;
+        wav->dataleft -= extra;
+        goto iterate_adapter;
+      } else {
+        GST_DEBUG_OBJECT (wav, "flushing %u bytes", avail);
+        gst_adapter_clear (wav->adapter);
+        wav->offset += avail;
+        wav->dataleft -= avail;
+        return GST_FLOW_OK;
+      }
+    }
+
+    if (avail < desired) {
+      GST_LOG_OBJECT (wav, "Got only %u bytes of data from the sinkpad", avail);
+      return GST_FLOW_OK;
+    }
+
+    buf = gst_adapter_take_buffer (wav->adapter, desired);
+  } else {
+    if ((res = gst_pad_pull_range (wav->sinkpad, wav->offset,
+                desired, &buf)) != GST_FLOW_OK)
+      goto pull_error;
+
+    /* we may get a short buffer at the end of the file */
+    if (gst_buffer_get_size (buf) < desired) {
+      gsize size = gst_buffer_get_size (buf);
+
+      GST_LOG_OBJECT (wav, "Got only %" G_GSIZE_FORMAT " bytes of data", size);
+      if (size >= wav->blockalign) {
+        if (wav->blockalign > 0) {
+          buf = gst_buffer_make_writable (buf);
+          gst_buffer_resize (buf, 0, size - (size % wav->blockalign));
+        }
+      } else {
+        gst_buffer_unref (buf);
+        goto found_eos;
+      }
+    }
+  }
+
+  obtained = gst_buffer_get_size (buf);
+
+  /* our positions in bytes */
+  pos = wav->offset - wav->datastart;
+  nextpos = pos + obtained;
+
+  /* update offsets, does not overflow. */
+  buf = gst_buffer_make_writable (buf);
+  GST_BUFFER_OFFSET (buf) = pos / wav->bytes_per_sample;
+  GST_BUFFER_OFFSET_END (buf) = nextpos / wav->bytes_per_sample;
+
+  /* first chunk of data? create the source pad. We do this only here so
+   * we can detect broken .wav files with dts disguised as raw PCM (sigh) */
+  if (G_UNLIKELY (wav->first)) {
+    wav->first = FALSE;
+    /* this will also push the segment events */
+    gst_wavparse_add_src_pad (wav, buf);
+  } else {
+    /* If we have a pending start segment, send it now. */
+    if (G_UNLIKELY (wav->start_segment != NULL)) {
+      gst_pad_push_event (wav->srcpad, wav->start_segment);
+      wav->start_segment = NULL;
+    }
+  }
+
+  if (wav->bps > 0) {
+    /* and timestamps if we have a bitrate, be careful for overflows */
+    timestamp =
+        gst_util_uint64_scale_ceil (pos, GST_SECOND, (guint64) wav->bps);
+    next_timestamp =
+        gst_util_uint64_scale_ceil (nextpos, GST_SECOND, (guint64) wav->bps);
+    duration = next_timestamp - timestamp;
+
+    /* update current running segment position */
+    if (G_LIKELY (next_timestamp >= wav->segment.start))
+      wav->segment.position = next_timestamp;
+  } else if (wav->fact) {
+    guint64 bps =
+        gst_util_uint64_scale_int (wav->datasize, wav->rate, wav->fact);
+    /* and timestamps if we have a bitrate, be careful for overflows */
+    timestamp = gst_util_uint64_scale_ceil (pos, GST_SECOND, bps);
+    next_timestamp = gst_util_uint64_scale_ceil (nextpos, GST_SECOND, bps);
+    duration = next_timestamp - timestamp;
+  } else {
+    /* no bitrate, all we know is that the first sample has timestamp 0, all
+     * other positions and durations have unknown timestamp. */
+    if (pos == 0)
+      timestamp = 0;
+    else
+      timestamp = GST_CLOCK_TIME_NONE;
+    duration = GST_CLOCK_TIME_NONE;
+    /* update current running segment position with byte offset */
+    if (G_LIKELY (nextpos >= wav->segment.start))
+      wav->segment.position = nextpos;
+  }
+  if ((pos > 0) && wav->vbr) {
+    /* don't set timestamps for VBR files if it's not the first buffer */
+    timestamp = GST_CLOCK_TIME_NONE;
+    duration = GST_CLOCK_TIME_NONE;
+  }
+  if (wav->discont) {
+    GST_DEBUG_OBJECT (wav, "marking DISCONT");
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+    wav->discont = FALSE;
+  }
+
+  GST_BUFFER_TIMESTAMP (buf) = timestamp;
+  GST_BUFFER_DURATION (buf) = duration;
+
+  GST_LOG_OBJECT (wav,
+      "Got buffer. timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT
+      ", size:%" G_GSIZE_FORMAT, GST_TIME_ARGS (timestamp),
+      GST_TIME_ARGS (duration), gst_buffer_get_size (buf));
+
+  if ((res = gst_pad_push (wav->srcpad, buf)) != GST_FLOW_OK)
+    goto push_error;
+
+  if (obtained < wav->dataleft) {
+    wav->offset += obtained;
+    wav->dataleft -= obtained;
+  } else {
+    wav->offset += wav->dataleft;
+    wav->dataleft = 0;
+  }
+
+  /* Iterate until need more data, so adapter size won't grow */
+  if (wav->streaming) {
+    GST_LOG_OBJECT (wav,
+        "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT, wav->offset,
+        wav->end_offset);
+    goto iterate_adapter;
+  }
+  return res;
+
+  /* ERROR */
+found_eos:
+  {
+    GST_DEBUG_OBJECT (wav, "found EOS");
+    return GST_FLOW_EOS;
+  }
+pull_error:
+  {
+    /* check if we got EOS */
+    if (res == GST_FLOW_EOS)
+      goto found_eos;
+
+    GST_WARNING_OBJECT (wav,
+        "Error getting %" G_GINT64_FORMAT " bytes from the "
+        "sinkpad (dataleft = %" G_GINT64_FORMAT ")", desired, wav->dataleft);
+    return res;
+  }
+push_error:
+  {
+    GST_INFO_OBJECT (wav,
+        "Error pushing on srcpad %s:%s, reason %s, is linked? = %d",
+        GST_DEBUG_PAD_NAME (wav->srcpad), gst_flow_get_name (res),
+        gst_pad_is_linked (wav->srcpad));
+    return res;
+  }
+}
+
+static void
+gst_wavparse_loop (GstPad * pad)
+{
+  GstFlowReturn ret;
+  GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad));
+  GstEvent *event;
+  gchar *stream_id;
+
+  GST_LOG_OBJECT (wav, "process data");
+
+  switch (wav->state) {
+    case GST_WAVPARSE_START:
+      GST_INFO_OBJECT (wav, "GST_WAVPARSE_START");
+      if ((ret = gst_wavparse_stream_init (wav)) != GST_FLOW_OK)
+        goto pause;
+
+      stream_id =
+          gst_pad_create_stream_id (wav->srcpad, GST_ELEMENT_CAST (wav), NULL);
+      event = gst_event_new_stream_start (stream_id);
+      gst_event_set_group_id (event, gst_util_group_id_next ());
+      gst_pad_push_event (wav->srcpad, event);
+      g_free (stream_id);
+
+      wav->state = GST_WAVPARSE_HEADER;
+      /* fall-through */
+
+    case GST_WAVPARSE_HEADER:
+      GST_INFO_OBJECT (wav, "GST_WAVPARSE_HEADER");
+      if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK)
+        goto pause;
+
+      wav->state = GST_WAVPARSE_DATA;
+      GST_INFO_OBJECT (wav, "GST_WAVPARSE_DATA");
+      /* fall-through */
+
+    case GST_WAVPARSE_DATA:
+      if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK)
+        goto pause;
+      break;
+    default:
+      g_assert_not_reached ();
+  }
+  return;
+
+  /* ERRORS */
+pause:
+  {
+    const gchar *reason = gst_flow_get_name (ret);
+
+    GST_DEBUG_OBJECT (wav, "pausing task, reason %s", reason);
+    gst_pad_pause_task (pad);
+
+    if (ret == GST_FLOW_EOS) {
+      /* handle end-of-stream/segment */
+      /* so align our position with the end of it, if there is one
+       * this ensures a subsequent will arrive at correct base/acc time */
+      if (wav->segment.format == GST_FORMAT_TIME) {
+        if (wav->segment.rate > 0.0 &&
+            GST_CLOCK_TIME_IS_VALID (wav->segment.stop))
+          wav->segment.position = wav->segment.stop;
+        else if (wav->segment.rate < 0.0)
+          wav->segment.position = wav->segment.start;
+      }
+      if (wav->state == GST_WAVPARSE_START || !wav->caps) {
+        GST_ELEMENT_ERROR (wav, STREAM, WRONG_TYPE, (NULL),
+            ("No valid input found before end of stream"));
+        gst_pad_push_event (wav->srcpad, gst_event_new_eos ());
+      } else {
+        /* add pad before we perform EOS */
+        if (G_UNLIKELY (wav->first)) {
+          wav->first = FALSE;
+          gst_wavparse_add_src_pad (wav, NULL);
+        }
+
+        /* perform EOS logic */
+        if (wav->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+          GstClockTime stop;
+
+          if ((stop = wav->segment.stop) == -1)
+            stop = wav->segment.duration;
+
+          gst_element_post_message (GST_ELEMENT_CAST (wav),
+              gst_message_new_segment_done (GST_OBJECT_CAST (wav),
+                  wav->segment.format, stop));
+          gst_pad_push_event (wav->srcpad,
+              gst_event_new_segment_done (wav->segment.format, stop));
+        } else {
+          gst_pad_push_event (wav->srcpad, gst_event_new_eos ());
+        }
+      }
+    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
+      /* for fatal errors we post an error message, post the error
+       * first so the app knows about the error first. */
+      GST_ELEMENT_FLOW_ERROR (wav, ret);
+      gst_pad_push_event (wav->srcpad, gst_event_new_eos ());
+    }
+    return;
+  }
+}
+
+static GstFlowReturn
+gst_wavparse_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstFlowReturn ret;
+  GstWavParse *wav = GST_WAVPARSE (parent);
+
+  GST_LOG_OBJECT (wav, "adapter_push %" G_GSIZE_FORMAT " bytes",
+      gst_buffer_get_size (buf));
+
+  gst_adapter_push (wav->adapter, buf);
+
+  switch (wav->state) {
+    case GST_WAVPARSE_START:
+      GST_INFO_OBJECT (wav, "GST_WAVPARSE_START");
+      if ((ret = gst_wavparse_parse_stream_init (wav)) != GST_FLOW_OK)
+        goto done;
+
+      if (wav->state != GST_WAVPARSE_HEADER)
+        break;
+
+      /* otherwise fall-through */
+    case GST_WAVPARSE_HEADER:
+      GST_INFO_OBJECT (wav, "GST_WAVPARSE_HEADER");
+      if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK)
+        goto done;
+
+      if (!wav->got_fmt || wav->datastart == 0)
+        break;
+
+      wav->state = GST_WAVPARSE_DATA;
+      GST_INFO_OBJECT (wav, "GST_WAVPARSE_DATA");
+
+      /* fall-through */
+    case GST_WAVPARSE_DATA:
+      if (buf && GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))
+        wav->discont = TRUE;
+      if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK)
+        goto done;
+      break;
+    default:
+      g_return_val_if_reached (GST_FLOW_ERROR);
+  }
+done:
+  if (G_UNLIKELY (wav->abort_buffering)) {
+    wav->abort_buffering = FALSE;
+    ret = GST_FLOW_ERROR;
+    /* sort of demux/parse error */
+    GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL), ("unhandled buffer size"));
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_wavparse_flush_data (GstWavParse * wav)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint av;
+
+  if ((av = gst_adapter_available (wav->adapter)) > 0) {
+    ret = gst_wavparse_stream_data (wav);
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_wavparse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstWavParse *wav = GST_WAVPARSE (parent);
+  gboolean ret = TRUE;
+
+  GST_LOG_OBJECT (wav, "handling %s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      /* discard, we'll come up with proper src caps */
+      gst_event_unref (event);
+      break;
+    }
+    case GST_EVENT_SEGMENT:
+    {
+      gint64 start, stop, offset = 0, end_offset = -1;
+      GstSegment segment;
+
+      /* some debug output */
+      gst_event_copy_segment (event, &segment);
+      GST_DEBUG_OBJECT (wav, "received newsegment %" GST_SEGMENT_FORMAT,
+          &segment);
+
+      if (wav->state != GST_WAVPARSE_DATA) {
+        GST_DEBUG_OBJECT (wav, "still starting, eating event");
+        goto exit;
+      }
+
+      /* now we are either committed to TIME or BYTE format,
+       * and we only expect a BYTE segment, e.g. following a seek */
+      if (segment.format == GST_FORMAT_BYTES) {
+        /* handle (un)signed issues */
+        start = segment.start;
+        stop = segment.stop;
+        if (start > 0) {
+          offset = start;
+          start -= wav->datastart;
+          start = MAX (start, 0);
+        }
+        if (stop > 0) {
+          end_offset = stop;
+          stop -= wav->datastart;
+          stop = MAX (stop, 0);
+        }
+        if (wav->segment.format == GST_FORMAT_TIME) {
+          guint64 bps = wav->bps;
+
+          /* operating in format TIME, so we can convert */
+          if (!bps && wav->fact)
+            bps =
+                gst_util_uint64_scale_int (wav->datasize, wav->rate, wav->fact);
+          if (bps) {
+            if (start >= 0)
+              start =
+                  gst_util_uint64_scale_ceil (start, GST_SECOND,
+                  (guint64) wav->bps);
+            if (stop >= 0)
+              stop =
+                  gst_util_uint64_scale_ceil (stop, GST_SECOND,
+                  (guint64) wav->bps);
+          }
+        }
+      } else {
+        GST_DEBUG_OBJECT (wav, "unsupported segment format, ignoring");
+        goto exit;
+      }
+
+      segment.start = start;
+      segment.stop = stop;
+
+      /* accept upstream's notion of segment and distribute along */
+      segment.format = wav->segment.format;
+      segment.time = segment.position = segment.start;
+      segment.duration = wav->segment.duration;
+      segment.base = gst_segment_to_running_time (&wav->segment,
+          GST_FORMAT_TIME, wav->segment.position);
+
+      gst_segment_copy_into (&segment, &wav->segment);
+
+      /* also store the newsegment event for the streaming thread */
+      if (wav->start_segment)
+        gst_event_unref (wav->start_segment);
+      GST_DEBUG_OBJECT (wav, "Storing newseg %" GST_SEGMENT_FORMAT, &segment);
+      wav->start_segment = gst_event_new_segment (&segment);
+
+      /* stream leftover data in current segment */
+      gst_wavparse_flush_data (wav);
+      /* and set up streaming thread for next one */
+      wav->offset = offset;
+      wav->end_offset = end_offset;
+
+      if (wav->datasize > 0 && (wav->end_offset == -1
+              || wav->end_offset > wav->datastart + wav->datasize))
+        wav->end_offset = wav->datastart + wav->datasize;
+
+      if (wav->end_offset != -1) {
+        wav->dataleft = wav->end_offset - wav->offset;
+      } else {
+        /* infinity; upstream will EOS when done */
+        wav->dataleft = G_MAXUINT64;
+      }
+    exit:
+      gst_event_unref (event);
+      break;
+    }
+    case GST_EVENT_EOS:
+      if (wav->state == GST_WAVPARSE_START || !wav->caps) {
+        GST_ELEMENT_ERROR (wav, STREAM, WRONG_TYPE, (NULL),
+            ("No valid input found before end of stream"));
+      } else {
+        /* add pad if needed so EOS is seen downstream */
+        if (G_UNLIKELY (wav->first)) {
+          wav->first = FALSE;
+          gst_wavparse_add_src_pad (wav, NULL);
+        } else {
+          /* stream leftover data in current segment */
+          gst_wavparse_flush_data (wav);
+        }
+      }
+
+      /* fall-through */
+    case GST_EVENT_FLUSH_STOP:
+    {
+      GstClockTime dur;
+
+      if (wav->adapter)
+        gst_adapter_clear (wav->adapter);
+      wav->discont = TRUE;
+      dur = wav->segment.duration;
+      gst_segment_init (&wav->segment, wav->segment.format);
+      wav->segment.duration = dur;
+      /* fall-through */
+    }
+    default:
+      ret = gst_pad_event_default (wav->sinkpad, parent, event);
+      break;
+  }
+
+  return ret;
+}
+
+#if 0
+/* convert and query stuff */
+static const GstFormat *
+gst_wavparse_get_formats (GstPad * pad)
+{
+  static const GstFormat formats[] = {
+    GST_FORMAT_TIME,
+    GST_FORMAT_BYTES,
+    GST_FORMAT_DEFAULT,         /* a "frame", ie a set of samples per Hz */
+    0
+  };
+
+  return formats;
+}
+#endif
+
+static gboolean
+gst_wavparse_pad_convert (GstPad * pad,
+    GstFormat src_format, gint64 src_value,
+    GstFormat * dest_format, gint64 * dest_value)
+{
+  GstWavParse *wavparse;
+  gboolean res = TRUE;
+
+  wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad));
+
+  if (*dest_format == src_format) {
+    *dest_value = src_value;
+    return TRUE;
+  }
+
+  if ((wavparse->bps == 0) && !wavparse->fact)
+    goto no_bps_fact;
+
+  GST_INFO_OBJECT (wavparse, "converting value from %s to %s",
+      gst_format_get_name (src_format), gst_format_get_name (*dest_format));
+
+  switch (src_format) {
+    case GST_FORMAT_BYTES:
+      switch (*dest_format) {
+        case GST_FORMAT_DEFAULT:
+          *dest_value = src_value / wavparse->bytes_per_sample;
+          /* make sure we end up on a sample boundary */
+          *dest_value -= *dest_value % wavparse->bytes_per_sample;
+          break;
+        case GST_FORMAT_TIME:
+          /* src_value + datastart = offset */
+          GST_INFO_OBJECT (wavparse,
+              "src=%" G_GINT64_FORMAT ", offset=%" G_GINT64_FORMAT, src_value,
+              wavparse->offset);
+          if (wavparse->bps > 0)
+            *dest_value = gst_util_uint64_scale_ceil (src_value, GST_SECOND,
+                (guint64) wavparse->bps);
+          else if (wavparse->fact) {
+            guint64 bps = gst_util_uint64_scale_int_ceil (wavparse->datasize,
+                wavparse->rate, wavparse->fact);
+
+            *dest_value =
+                gst_util_uint64_scale_int_ceil (src_value, GST_SECOND, bps);
+          } else {
+            res = FALSE;
+          }
+          break;
+        default:
+          res = FALSE;
+          goto done;
+      }
+      break;
+
+    case GST_FORMAT_DEFAULT:
+      switch (*dest_format) {
+        case GST_FORMAT_BYTES:
+          *dest_value = src_value * wavparse->bytes_per_sample;
+          break;
+        case GST_FORMAT_TIME:
+          *dest_value = gst_util_uint64_scale (src_value, GST_SECOND,
+              (guint64) wavparse->rate);
+          break;
+        default:
+          res = FALSE;
+          goto done;
+      }
+      break;
+
+    case GST_FORMAT_TIME:
+      switch (*dest_format) {
+        case GST_FORMAT_BYTES:
+          if (wavparse->bps > 0)
+            *dest_value = gst_util_uint64_scale (src_value,
+                (guint64) wavparse->bps, GST_SECOND);
+          else {
+            guint64 bps = gst_util_uint64_scale_int (wavparse->datasize,
+                wavparse->rate, wavparse->fact);
+
+            *dest_value = gst_util_uint64_scale (src_value, bps, GST_SECOND);
+          }
+          /* make sure we end up on a sample boundary */
+          *dest_value -= *dest_value % wavparse->blockalign;
+          break;
+        case GST_FORMAT_DEFAULT:
+          *dest_value = gst_util_uint64_scale (src_value,
+              (guint64) wavparse->rate, GST_SECOND);
+          break;
+        default:
+          res = FALSE;
+          goto done;
+      }
+      break;
+
+    default:
+      res = FALSE;
+      goto done;
+  }
+
+done:
+  return res;
+
+  /* ERRORS */
+no_bps_fact:
+  {
+    GST_DEBUG_OBJECT (wavparse, "bps 0 or no fact chunk, cannot convert");
+    res = FALSE;
+    goto done;
+  }
+}
+
+/* handle queries for location and length in requested format */
+static gboolean
+gst_wavparse_pad_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  gboolean res = TRUE;
+  GstWavParse *wav = GST_WAVPARSE (parent);
+
+  /* only if we know */
+  if (wav->state != GST_WAVPARSE_DATA) {
+    return FALSE;
+  }
+
+  GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:
+    {
+      gint64 curb;
+      gint64 cur;
+      GstFormat format;
+
+      /* this is not very precise, as we have pushed severla buffer upstream for prerolling */
+      curb = wav->offset - wav->datastart;
+      gst_query_parse_position (query, &format, NULL);
+      GST_INFO_OBJECT (wav, "pos query at %" G_GINT64_FORMAT, curb);
+
+      switch (format) {
+        case GST_FORMAT_BYTES:
+          format = GST_FORMAT_BYTES;
+          cur = curb;
+          break;
+        default:
+          res = gst_wavparse_pad_convert (pad, GST_FORMAT_BYTES, curb,
+              &format, &cur);
+          break;
+      }
+      if (res)
+        gst_query_set_position (query, format, cur);
+      break;
+    }
+    case GST_QUERY_DURATION:
+    {
+      gint64 duration = 0;
+      GstFormat format;
+
+      if (wav->ignore_length) {
+        res = FALSE;
+        break;
+      }
+
+      gst_query_parse_duration (query, &format, NULL);
+
+      switch (format) {
+        case GST_FORMAT_BYTES:{
+          format = GST_FORMAT_BYTES;
+          duration = wav->datasize;
+          break;
+        }
+        case GST_FORMAT_TIME:
+          if ((res = gst_wavparse_calculate_duration (wav))) {
+            duration = wav->duration;
+          }
+          break;
+        default:
+          res = FALSE;
+          break;
+      }
+      if (res)
+        gst_query_set_duration (query, format, duration);
+      break;
+    }
+    case GST_QUERY_CONVERT:
+    {
+      gint64 srcvalue, dstvalue;
+      GstFormat srcformat, dstformat;
+
+      gst_query_parse_convert (query, &srcformat, &srcvalue,
+          &dstformat, &dstvalue);
+      res = gst_wavparse_pad_convert (pad, srcformat, srcvalue,
+          &dstformat, &dstvalue);
+      if (res)
+        gst_query_set_convert (query, srcformat, srcvalue, dstformat, dstvalue);
+      break;
+    }
+    case GST_QUERY_SEEKING:{
+      GstFormat fmt;
+      gboolean seekable = FALSE;
+
+      gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
+      if (fmt == wav->segment.format) {
+        if (wav->streaming) {
+          GstQuery *q;
+
+          q = gst_query_new_seeking (GST_FORMAT_BYTES);
+          if ((res = gst_pad_peer_query (wav->sinkpad, q))) {
+            gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
+            GST_LOG_OBJECT (wav, "upstream BYTE seekable %d", seekable);
+          }
+          gst_query_unref (q);
+        } else {
+          GST_LOG_OBJECT (wav, "looping => seekable");
+          seekable = TRUE;
+          res = TRUE;
+        }
+      } else if (fmt == GST_FORMAT_TIME) {
+        res = TRUE;
+      }
+      if (res) {
+        gst_query_set_seeking (query, fmt, seekable, 0, wav->segment.duration);
+      }
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+  return res;
+}
+
+static gboolean
+gst_wavparse_srcpad_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstWavParse *wavparse = GST_WAVPARSE (parent);
+  gboolean res = FALSE;
+
+  GST_DEBUG_OBJECT (wavparse, "%s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+      /* can only handle events when we are in the data state */
+      if (wavparse->state == GST_WAVPARSE_DATA) {
+        res = gst_wavparse_perform_seek (wavparse, event);
+      }
+      gst_event_unref (event);
+      break;
+
+    case GST_EVENT_TOC_SELECT:
+    {
+      char *uid = NULL;
+      GstTocEntry *entry = NULL;
+      GstEvent *seek_event;
+      gint64 start_pos;
+
+      if (!wavparse->toc) {
+        GST_DEBUG_OBJECT (wavparse, "no TOC to select");
+        return FALSE;
+      } else {
+        gst_event_parse_toc_select (event, &uid);
+        if (uid != NULL) {
+          GST_OBJECT_LOCK (wavparse);
+          entry = gst_toc_find_entry (wavparse->toc, uid);
+          if (entry == NULL) {
+            GST_OBJECT_UNLOCK (wavparse);
+            GST_WARNING_OBJECT (wavparse, "no TOC entry with given UID: %s",
+                uid);
+            res = FALSE;
+          } else {
+            gst_toc_entry_get_start_stop_times (entry, &start_pos, NULL);
+            GST_OBJECT_UNLOCK (wavparse);
+            seek_event = gst_event_new_seek (1.0,
+                GST_FORMAT_TIME,
+                GST_SEEK_FLAG_FLUSH,
+                GST_SEEK_TYPE_SET, start_pos, GST_SEEK_TYPE_SET, -1);
+            res = gst_wavparse_perform_seek (wavparse, seek_event);
+            gst_event_unref (seek_event);
+          }
+          g_free (uid);
+        } else {
+          GST_WARNING_OBJECT (wavparse, "received empty TOC select event");
+          res = FALSE;
+        }
+      }
+      gst_event_unref (event);
+      break;
+    }
+
+    default:
+      res = gst_pad_push_event (wavparse->sinkpad, event);
+      break;
+  }
+  return res;
+}
+
+static gboolean
+gst_wavparse_sink_activate (GstPad * sinkpad, GstObject * parent)
+{
+  GstWavParse *wav = GST_WAVPARSE (parent);
+  GstQuery *query;
+  gboolean pull_mode;
+
+  if (wav->adapter) {
+    gst_adapter_clear (wav->adapter);
+    g_object_unref (wav->adapter);
+    wav->adapter = NULL;
+  }
+
+  query = gst_query_new_scheduling ();
+
+  if (!gst_pad_peer_query (sinkpad, query)) {
+    gst_query_unref (query);
+    goto activate_push;
+  }
+
+  pull_mode = gst_query_has_scheduling_mode_with_flags (query,
+      GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
+  gst_query_unref (query);
+
+  if (!pull_mode)
+    goto activate_push;
+
+  GST_DEBUG_OBJECT (sinkpad, "activating pull");
+  wav->streaming = FALSE;
+  return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
+
+activate_push:
+  {
+    GST_DEBUG_OBJECT (sinkpad, "activating push");
+    wav->streaming = TRUE;
+    wav->adapter = gst_adapter_new ();
+    return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
+  }
+}
+
+
+static gboolean
+gst_wavparse_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
+    GstPadMode mode, gboolean active)
+{
+  gboolean res;
+
+  switch (mode) {
+    case GST_PAD_MODE_PUSH:
+      res = TRUE;
+      break;
+    case GST_PAD_MODE_PULL:
+      if (active) {
+        /* if we have a scheduler we can start the task */
+        res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_wavparse_loop,
+            sinkpad, NULL);
+      } else {
+        res = gst_pad_stop_task (sinkpad);
+      }
+      break;
+    default:
+      res = FALSE;
+      break;
+  }
+  return res;
+}
+
+static GstStateChangeReturn
+gst_wavparse_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstWavParse *wav = GST_WAVPARSE (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_wavparse_reset (wav);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_wavparse_reset (wav);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+  return ret;
+}
+
+static void
+gst_wavparse_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstWavParse *self;
+
+  g_return_if_fail (GST_IS_WAVPARSE (object));
+  self = GST_WAVPARSE (object);
+
+  switch (prop_id) {
+    case PROP_IGNORE_LENGTH:
+      self->ignore_length = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+  }
+
+}
+
+static void
+gst_wavparse_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstWavParse *self;
+
+  g_return_if_fail (GST_IS_WAVPARSE (object));
+  self = GST_WAVPARSE (object);
+
+  switch (prop_id) {
+    case PROP_IGNORE_LENGTH:
+      g_value_set_boolean (value, self->ignore_length);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+  }
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  gst_riff_init ();
+
+  return gst_element_register (plugin, "wavparse", GST_RANK_PRIMARY,
+      GST_TYPE_WAVPARSE);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    wavparse,
+    "Parse a .wav file into raw audio",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/wavparse/gstwavparse.h b/gst/wavparse/gstwavparse.h
new file mode 100644
index 0000000..f449e30
--- /dev/null
+++ b/gst/wavparse/gstwavparse.h
@@ -0,0 +1,138 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2006> Nokia Corporation, Stefan Kost <stefan.kost@nokia.com>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_WAVPARSE_H__
+#define __GST_WAVPARSE_H__
+
+
+#include <gst/gst.h>
+#include "gst/riff/riff-ids.h"
+#include "gst/riff/riff-read.h"
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_WAVPARSE \
+  (gst_wavparse_get_type())
+#define GST_WAVPARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAVPARSE,GstWavParse))
+#define GST_WAVPARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVPARSE,GstWavParseClass))
+#define GST_IS_WAVPARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAVPARSE))
+#define GST_IS_WAVPARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVPARSE))
+
+typedef enum {
+  GST_WAVPARSE_START,
+  GST_WAVPARSE_HEADER,
+  GST_WAVPARSE_DATA
+} GstWavParseState;
+
+typedef struct _GstWavParse GstWavParse;
+typedef struct _GstWavParseClass GstWavParseClass;
+
+/**
+ * GstWavParse:
+ *
+ * Opaque data structure.
+ */
+struct _GstWavParse {
+  GstElement parent;
+
+  /* pads */
+  GstPad *sinkpad,*srcpad;
+
+  /* for delayed source pad creation for when
+   * we have the first chunk of data and know
+   * the format for sure */
+  GstCaps     *caps;
+  GstTagList  *tags;
+  GstToc      *toc;
+  GList       *cues;
+  GList       *labls;
+  GList       *notes;
+  GstEvent    *start_segment;
+
+  /* WAVE decoding state */
+  GstWavParseState state;
+  gboolean abort_buffering;
+
+  /* format of audio, see defines below */
+  gint format;
+
+  /* useful audio data */
+  guint16 depth;
+  guint32 rate;
+  guint16 channels;
+  guint16 blockalign;
+  guint16 width;
+  guint32 av_bps;
+  guint64 fact;
+
+  /* real bps used or 0 when no bitrate is known */
+  guint32 bps;
+  gboolean vbr;
+
+  guint bytes_per_sample;
+  guint max_buf_size;
+
+  /* position in data part */
+  guint64	offset;
+  guint64	end_offset;
+  guint64 	dataleft;
+  /* offset/length of data part */
+  guint64 	datastart;
+  guint64 	datasize;
+  /* duration in time */
+  guint64 	duration;
+
+  /* pending seek */
+  GstEvent *seek_event;
+
+  /* For streaming */
+  GstAdapter *adapter;
+  gboolean got_fmt;
+  gboolean streaming;
+
+  /* configured segment, start/stop expressed in time or bytes */
+  GstSegment segment;
+
+  /* for late pad configuration */
+  gboolean first;
+  /* discont after seek */
+  gboolean discont;
+
+  gboolean ignore_length;
+
+  /* Size of the data as written in the chunk size */
+  guint32 chunk_size;
+};
+
+struct _GstWavParseClass {
+  GstElementClass parent_class;
+};
+
+GType gst_wavparse_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_WAVPARSE_H__ */
diff --git a/gst/wavparse/meson.build b/gst/wavparse/meson.build
new file mode 100644
index 0000000..dceba34
--- /dev/null
+++ b/gst/wavparse/meson.build
@@ -0,0 +1,9 @@
+gstwawparse = library('gstwavparse',
+  'gstwavparse.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc, libsinc],
+  dependencies : [gstbase_dep, gstpbutils_dep, gstriff_dep, gstaudio_dep,
+		  gsttag_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/gst/y4m/Makefile.am b/gst/y4m/Makefile.am
new file mode 100644
index 0000000..c6eb37b
--- /dev/null
+++ b/gst/y4m/Makefile.am
@@ -0,0 +1,9 @@
+
+plugin_LTLIBRARIES = libgsty4menc.la
+
+libgsty4menc_la_SOURCES = gsty4mencode.c
+libgsty4menc_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+libgsty4menc_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) $(GST_LIBS)
+libgsty4menc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gsty4mencode.h
diff --git a/gst/y4m/gsty4mencode.c b/gst/y4m/gsty4mencode.c
new file mode 100644
index 0000000..2a113bc
--- /dev/null
+++ b/gst/y4m/gsty4mencode.c
@@ -0,0 +1,315 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2006> Mark Nauwelaerts <mnauw@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-y4menc
+ *
+ * <refsect2>
+ * <para>
+ * Creates a YU4MPEG2 raw video stream as defined by the mjpegtools project.
+ * </para>
+ * <title>Example launch line</title>
+ * <para>
+ * (write everything in one line, without the backslash characters)
+ * <programlisting>
+ * gst-launch-1.0 videotestsrc num-buffers=250 \
+ * ! 'video/x-raw,format=(string)I420,width=320,height=240,framerate=(fraction)25/1' \
+ * ! y4menc ! filesink location=test.yuv
+ * </programlisting>
+ * </para>
+ * </refsect2>
+ *
+ */
+
+/* see mjpegtools/yuv4mpeg.h for yuv4mpeg format */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include "gsty4mencode.h"
+
+/* Filter signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0
+};
+
+static GstStaticPadTemplate y4mencode_src_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-yuv4mpeg, " "y4mversion = (int) 2")
+    );
+
+static GstStaticPadTemplate y4mencode_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ IYUV, I420, Y42B, Y41B, Y444 }"))
+    );
+
+
+static void gst_y4m_encode_reset (GstY4mEncode * filter);
+
+static GstStateChangeReturn gst_y4m_encode_change_state (GstElement * element,
+    GstStateChange transition);
+
+static GstFlowReturn
+gst_y4m_encode_handle_frame (GstVideoEncoder * encoder,
+    GstVideoCodecFrame * frame);
+static gboolean gst_y4m_encode_set_format (GstVideoEncoder * encoder,
+    GstVideoCodecState * state);
+
+#define gst_y4m_encode_parent_class parent_class
+G_DEFINE_TYPE (GstY4mEncode, gst_y4m_encode, GST_TYPE_VIDEO_ENCODER);
+
+
+static void
+gst_y4m_encode_class_init (GstY4mEncodeClass * klass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GstVideoEncoderClass *venc_class = GST_VIDEO_ENCODER_CLASS (klass);
+
+  element_class->change_state = GST_DEBUG_FUNCPTR (gst_y4m_encode_change_state);
+
+  gst_element_class_add_static_pad_template (element_class,
+      &y4mencode_src_factory);
+  gst_element_class_add_static_pad_template (element_class,
+      &y4mencode_sink_factory);
+
+  gst_element_class_set_static_metadata (element_class,
+      "YUV4MPEG video encoder", "Codec/Encoder/Video",
+      "Encodes a YUV frame into the yuv4mpeg format (mjpegtools)",
+      "Wim Taymans <wim.taymans@gmail.com>");
+  venc_class->set_format = gst_y4m_encode_set_format;
+  venc_class->handle_frame = gst_y4m_encode_handle_frame;
+
+}
+
+static void
+gst_y4m_encode_init (GstY4mEncode * filter)
+{
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_ENCODER_SINK_PAD (filter));
+
+  /* init properties */
+  gst_y4m_encode_reset (filter);
+}
+
+static void
+gst_y4m_encode_reset (GstY4mEncode * filter)
+{
+  filter->header = FALSE;
+}
+
+static gboolean
+gst_y4m_encode_set_format (GstVideoEncoder * encoder,
+    GstVideoCodecState * state)
+{
+  GstY4mEncode *y4menc;
+  GstVideoInfo *info;
+  GstVideoCodecState *output_state;
+
+  y4menc = GST_Y4M_ENCODE (encoder);
+  info = &state->info;
+
+  switch (GST_VIDEO_INFO_FORMAT (info)) {
+    case GST_VIDEO_FORMAT_I420:
+      y4menc->colorspace = "420";
+      break;
+    case GST_VIDEO_FORMAT_Y42B:
+      y4menc->colorspace = "422";
+      break;
+    case GST_VIDEO_FORMAT_Y41B:
+      y4menc->colorspace = "411";
+      break;
+    case GST_VIDEO_FORMAT_Y444:
+      y4menc->colorspace = "444";
+      break;
+    default:
+      goto invalid_format;
+  }
+
+  y4menc->info = *info;
+
+  output_state =
+      gst_video_encoder_set_output_state (encoder,
+      gst_static_pad_template_get_caps (&y4mencode_src_factory), state);
+  gst_video_codec_state_unref (output_state);
+
+  return TRUE;
+
+invalid_format:
+  {
+    GST_ERROR_OBJECT (y4menc, "Invalid format");
+    return FALSE;
+  }
+
+}
+
+static inline GstBuffer *
+gst_y4m_encode_get_stream_header (GstY4mEncode * filter, gboolean tff)
+{
+  gpointer header;
+  GstBuffer *buf;
+  gchar interlaced;
+  gsize len;
+
+  if (GST_VIDEO_INFO_IS_INTERLACED (&filter->info)) {
+    if (tff)
+      interlaced = 't';
+    else
+      interlaced = 'b';
+  } else {
+    interlaced = 'p';
+  }
+
+  header = g_strdup_printf ("YUV4MPEG2 C%s W%d H%d I%c F%d:%d A%d:%d\n",
+      filter->colorspace, GST_VIDEO_INFO_WIDTH (&filter->info),
+      GST_VIDEO_INFO_HEIGHT (&filter->info), interlaced,
+      GST_VIDEO_INFO_FPS_N (&filter->info),
+      GST_VIDEO_INFO_FPS_D (&filter->info),
+      GST_VIDEO_INFO_PAR_N (&filter->info),
+      GST_VIDEO_INFO_PAR_D (&filter->info));
+  len = strlen (header);
+
+  buf = gst_buffer_new ();
+  gst_buffer_append_memory (buf,
+      gst_memory_new_wrapped (0, header, len, 0, len, header, g_free));
+
+  return buf;
+}
+
+static inline GstBuffer *
+gst_y4m_encode_get_frame_header (GstY4mEncode * filter)
+{
+  gpointer header;
+  GstBuffer *buf;
+  gsize len;
+
+  header = g_strdup_printf ("FRAME\n");
+  len = strlen (header);
+
+  buf = gst_buffer_new ();
+  gst_buffer_append_memory (buf,
+      gst_memory_new_wrapped (0, header, len, 0, len, header, g_free));
+
+  return buf;
+}
+
+
+static GstFlowReturn
+gst_y4m_encode_handle_frame (GstVideoEncoder * encoder,
+    GstVideoCodecFrame * frame)
+{
+  GstY4mEncode *filter = GST_Y4M_ENCODE (encoder);
+  GstClockTime timestamp;
+
+  /* check we got some decent info from caps */
+  if (GST_VIDEO_INFO_FORMAT (&filter->info) == GST_VIDEO_FORMAT_UNKNOWN)
+    goto not_negotiated;
+
+  timestamp = GST_BUFFER_TIMESTAMP (frame->input_buffer);
+
+  if (G_UNLIKELY (!filter->header)) {
+    gboolean tff = FALSE;
+
+    if (GST_VIDEO_INFO_IS_INTERLACED (&filter->info)) {
+      tff =
+          GST_BUFFER_FLAG_IS_SET (frame->input_buffer,
+          GST_VIDEO_BUFFER_FLAG_TFF);
+    }
+    frame->output_buffer = gst_y4m_encode_get_stream_header (filter, tff);
+    filter->header = TRUE;
+    frame->output_buffer =
+        gst_buffer_append (frame->output_buffer,
+        gst_y4m_encode_get_frame_header (filter));
+  } else {
+    frame->output_buffer = gst_y4m_encode_get_frame_header (filter);
+  }
+
+  frame->output_buffer =
+      gst_buffer_append (frame->output_buffer,
+      gst_buffer_copy (frame->input_buffer));
+
+  /* decorate */
+  frame->output_buffer = gst_buffer_make_writable (frame->output_buffer);
+  GST_BUFFER_TIMESTAMP (frame->output_buffer) = timestamp;
+
+  return gst_video_encoder_finish_frame (encoder, frame);
+
+not_negotiated:
+  {
+    GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION, (NULL),
+        ("format wasn't negotiated"));
+
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+}
+
+static GstStateChangeReturn
+gst_y4m_encode_change_state (GstElement * element, GstStateChange transition)
+{
+  GstY4mEncode *filter = GST_Y4M_ENCODE (element);
+  GstStateChangeReturn ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
+      (element, transition), GST_STATE_CHANGE_SUCCESS);
+  if (ret != GST_STATE_CHANGE_SUCCESS)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_y4m_encode_reset (filter);
+      break;
+    default:
+      break;
+  }
+
+  return GST_STATE_CHANGE_SUCCESS;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "y4menc", GST_RANK_PRIMARY,
+      GST_TYPE_Y4M_ENCODE);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    y4menc,
+    "Encodes a YUV frame into the yuv4mpeg format (mjpegtools)",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/y4m/gsty4mencode.h b/gst/y4m/gsty4mencode.h
new file mode 100644
index 0000000..13a7a1b
--- /dev/null
+++ b/gst/y4m/gsty4mencode.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_Y4MENCODE_H__
+#define __GST_Y4MENCODE_H__
+
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_Y4M_ENCODE \
+  (gst_y4m_encode_get_type())
+#define GST_Y4M_ENCODE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_Y4M_ENCODE, GstY4mEncode))
+#define GST_Y4M_ENCODE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_Y4M_ENCODE, GstY4mEncodeClass))
+#define GST_Y4M_ENCODE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_Y4M_ENCODE, GstY4mEncodeClass))
+#define GST_IS_Y4M_ENCODE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_Y4M_ENCODE))
+#define GST_IS_Y4M_ENCODE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_Y4M_ENCODE))
+
+typedef struct _GstY4mEncode GstY4mEncode;
+typedef struct _GstY4mEncodeClass GstY4mEncodeClass;
+
+struct _GstY4mEncode {
+  GstVideoEncoder parent;
+
+  /* caps information */
+  GstVideoInfo info;
+
+  const gchar *colorspace;
+  /* state information */
+  gboolean header;
+};
+
+struct _GstY4mEncodeClass {
+  GstVideoEncoderClass parent_class;
+};
+
+GType gst_y4m_encode_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_Y4MENCODE_H__ */
diff --git a/gst/y4m/meson.build b/gst/y4m/meson.build
new file mode 100644
index 0000000..d680e7e
--- /dev/null
+++ b/gst/y4m/meson.build
@@ -0,0 +1,8 @@
+gsty4menc = library('gsty4menc',
+  'gsty4mencode.c',
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  dependencies : [gstbase_dep, gstvideo_dep],
+  install : true,
+  install_dir : plugins_install_dir,
+)
diff --git a/hooks/pre-commit.hook b/hooks/pre-commit.hook
new file mode 100755
index 0000000..3c1062b
--- /dev/null
+++ b/hooks/pre-commit.hook
@@ -0,0 +1,83 @@
+#!/bin/sh
+#
+# Check that the code follows a consistant code style
+#
+
+# Check for existence of indent, and error out if not present.
+# On some *bsd systems the binary seems to be called gnunindent,
+# so check for that first.
+
+version=`gnuindent --version 2>/dev/null`
+if test "x$version" = "x"; then
+  version=`gindent --version 2>/dev/null`
+  if test "x$version" = "x"; then
+    version=`indent --version 2>/dev/null`
+    if test "x$version" = "x"; then
+      echo "GStreamer git pre-commit hook:"
+      echo "Did not find GNU indent, please install it before continuing."
+      exit 1
+    else
+      INDENT=indent
+    fi
+  else
+    INDENT=gindent
+  fi
+else
+  INDENT=gnuindent
+fi
+
+case `$INDENT --version` in
+  GNU*)
+      ;;
+  default)
+      echo "GStreamer git pre-commit hook:"
+      echo "Did not find GNU indent, please install it before continuing."
+      echo "(Found $INDENT, but it doesn't seem to be GNU indent)"
+      exit 1
+      ;;
+esac
+
+INDENT_PARAMETERS="--braces-on-if-line \
+	--case-brace-indentation0 \
+	--case-indentation2 \
+	--braces-after-struct-decl-line \
+	--line-length80 \
+	--no-tabs \
+	--cuddle-else \
+	--dont-line-up-parentheses \
+	--continuation-indentation4 \
+	--honour-newlines \
+	--tab-size8 \
+	--indent-level2 \
+	--leave-preprocessor-space"
+
+echo "--Checking style--"
+for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep "\.c$"` ; do
+    # nf is the temporary checkout. This makes sure we check against the
+    # revision in the index (and not the checked out version).
+    nf=`git checkout-index --temp ${file} | cut -f 1`
+    newfile=`mktemp /tmp/${nf}.XXXXXX` || exit 1
+    $INDENT ${INDENT_PARAMETERS} \
+	$nf -o $newfile 2>> /dev/null
+    # FIXME: Call indent twice as it tends to do line-breaks
+    # different for every second call.
+    $INDENT ${INDENT_PARAMETERS} \
+        $newfile 2>> /dev/null
+    diff -u -p "${nf}" "${newfile}"
+    r=$?
+    rm "${newfile}"
+    rm "${nf}"
+    if [ $r != 0 ] ; then
+echo "================================================================================================="
+echo " Code style error in: $file                                                                      "
+echo "                                                                                                 "
+echo " Please fix before committing. Don't forget to run git add before trying to commit again.        "
+echo " If the whole file is to be committed, this should work (run from the top-level directory):      "
+echo "                                                                                                 "
+echo "   gst-indent $file; git add $file; git commit"
+echo "                                                                                                 "
+echo "================================================================================================="
+        exit 1
+    fi
+done
+echo "--Checking style pass--"
diff --git a/m4/.gitignore b/m4/.gitignore
new file mode 100644
index 0000000..ae2f6d8
--- /dev/null
+++ b/m4/.gitignore
@@ -0,0 +1,17 @@
+codeset.m4
+gettext.m4
+glibc21.m4
+iconv.m4
+intdiv0.m4
+inttypes-pri.m4
+inttypes.m4
+inttypes_h.m4
+isc-posix.m4
+lcmessage.m4
+lib-ld.m4
+lib-link.m4
+lib-prefix.m4
+progtest.m4
+stdint_h.m4
+uintmax_t.m4
+ulonglong.m4
diff --git a/m4/Makefile.am b/m4/Makefile.am
new file mode 100644
index 0000000..d3738ca
--- /dev/null
+++ b/m4/Makefile.am
@@ -0,0 +1,35 @@
+EXTRA_DIST = \
+	a52.m4 \
+	aalib.m4 \
+	as-ffmpeg.m4 \
+	as-liblame.m4 \
+	as-slurp-ffmpeg.m4 \
+	check-libheader.m4 \
+	codeset.m4 \
+	freetype2.m4 \
+	gettext.m4 \
+	glibc21.m4 \
+	glib.m4 \
+	gst-alsa.m4 \
+	gst-artsc.m4 \
+	gst-fionread.m4 \
+	gst-ivorbis.m4 \
+	gst-matroska.m4 \
+	gst-sdl.m4 \
+	gst-shout2.m4 \
+	gst-sid.m4 \
+	gtk.m4 \
+	iconv.m4 \
+	intdiv0.m4 \
+	inttypes_h.m4 \
+	inttypes-pri.m4 \
+	lcmessage.m4 \
+	libfame.m4 \
+	lib-ld.m4 \
+	lib-link.m4 \
+	lib-prefix.m4 \
+	ogg.m4 \
+	progtest.m4 \
+	stdint_h.m4 \
+	uintmax_t.m4 \
+	vorbis.m4
diff --git a/m4/README b/m4/README
new file mode 100644
index 0000000..f044598
--- /dev/null
+++ b/m4/README
@@ -0,0 +1,3 @@
+All aclocal .m4 files we need are put here and cat'd to acinclude.m4 in 
+the source root.  Official ones (taken from the relevant devel packages) 
+are named as-is, unofficial ones (or changed ones) get a gst-prefix.
diff --git a/m4/a52.m4 b/m4/a52.m4
new file mode 100644
index 0000000..0065dee
--- /dev/null
+++ b/m4/a52.m4
@@ -0,0 +1,125 @@
+dnl
+dnl A52_CHECK-LIBHEADER(FEATURE-NAME, LIB-NAME, LIB-FUNCTION, HEADER-NAME,
+dnl                     ACTION-IF-FOUND, ACTION-IF-NOT-FOUND,
+dnl                     EXTRA-LDFLAGS, EXTRA-CPPFLAGS)
+dnl
+dnl FEATURE-NAME        - feature name; library and header files are treated
+dnl                       as feature, which we look for
+dnl LIB-NAME            - library name as in AC_CHECK_LIB macro
+dnl LIB-FUNCTION        - library symbol as in AC_CHECK_LIB macro
+dnl HEADER-NAME         - header file name as in AC_CHECK_HEADER
+dnl ACTION-IF-FOUND     - when feature is found then execute given action
+dnl ACTION-IF-NOT-FOUND - when feature is not found then execute given action
+dnl EXTRA-LDFLAGS       - extra linker flags (-L or -l)
+dnl EXTRA-CPPFLAGS      - extra C preprocessor flags, i.e. -I/usr/X11R6/include
+dnl
+dnl Based on GST_CHECK_LIBHEADER from gstreamer plugins 0.3.1.
+dnl
+AC_DEFUN([A52_CHECK_LIBHEADER],
+[
+  AC_CHECK_LIB([$2], [$3], HAVE_[$1]=yes, HAVE_[$1]=no, [$7])
+  check_libheader_feature_name=translit([$1], A-Z, a-z)
+
+  if test "x$HAVE_[$1]" = "xyes"; then
+    check_libheader_save_CPPFLAGS=$CPPFLAGS
+    CPPFLAGS="[$8] $CPPFLAGS"
+    AC_CHECK_HEADER([$4], :, HAVE_[$1]=no)
+    CPPFLAGS=$check_libheader_save_CPPFLAGS
+  fi
+
+  if test "x$HAVE_[$1]" = "xyes"; then
+    ifelse([$5], , :, [$5])
+  else
+    ifelse([$6], , :, [$6])
+  fi
+]
+)
+
+dnl
+dnl AC_CHECK_A52DEC(ACTION-IF-FOUND, ACTION-IF-NOT-FOUND)
+dnl
+dnl ACTION-IF-FOUND     - when feature is found then execute given action
+dnl ACTION-IF-NOT-FOUND - when feature is not found then execute given action
+dnl
+dnl Defines HAVE_A52DEC to yes if liba52 is found
+dnl
+dnl CFLAGS and LDFLAGS for the library are stored in A52DEC_CFLAGS and
+dnl A52DEC_LIBS, respectively
+dnl
+dnl Based on GST_CHECK_A52DEC from gstreamer plugins 0.3.3.1
+dnl Thomas Vander Stichele <thomas@apestaart.org>, Andy Wingo <wingo@pobox.com>
+dnl
+AC_DEFUN([AC_CHECK_A52DEC], 
+[dnl
+AC_ARG_WITH(a52dec-prefix,
+    AC_HELP_STRING([--with-a52dec-prefix=PFX],
+                   [prefix where a52dec is installed (optional)]),
+    a52dec_config_prefix="$withval", a52dec_config_prefix="")
+
+if test x$a52dec_config_prefix = x ; then
+    A52_CHECK_LIBHEADER(A52DEC, a52, a52_init, a52dec/a52.h,
+        A52DEC_LIBS="-la52 -lm", , -lm)
+else
+    A52_CHECK_LIBHEADER(A52DEC, a52, a52_init, a52dec/a52.h, [
+            A52DEC_LIBS="-la52 -L$a52dec_config_prefix/lib -lm"
+            A52DEC_CFLAGS="-I$a52dec_config_prefix/include"
+        ], , -L$a52dec_config_prefix/lib, -I$a52dec_config_prefix/include)
+fi
+
+if test $HAVE_A52DEC = "yes"; then
+    ac_save_CFLAGS="$CFLAGS"
+    ac_save_LIBS="$LIBS"
+    CFLAGS="$CFLAGS $A52DEC_CFLAGS"
+    LIBS="$A52DEC_LIBS $LIBS"
+    AC_TRY_RUN([
+#include <inttypes.h>
+#include <a52dec/a52.h>
+
+int 
+main ()
+{
+  a52_state_t *state;
+  state = a52_init (0);
+  a52_free (state);
+  return 0;
+}
+        ],, HAVE_A52DEC=no, [echo $ac_n "cross compiling; assumed OK... $ac_c"])
+
+    if test HAVE_A52DEC = "no"; then
+        echo "*** Your a52dec is borked somehow. Please update to 0.7.4."
+    else
+        AC_TRY_RUN([
+#include <inttypes.h>
+#include <a52dec/a52.h>
+
+int 
+main ()
+{
+  int i = sizeof (a52_state_t);
+  if ( i )
+    return 0;
+}
+            ], HAVE_A52DEC=no,, [echo $ac_n "cross compiling; assumed OK... $ac_c"])
+
+        if test HAVE_A52DEC = "no"; then
+            echo "*** Your a52dec is too old. Please update to 0.7.4."
+        fi
+    fi
+    CFLAGS="$ac_save_CFLAGS"
+    LIBS="$ac_save_LIBS"
+fi
+
+if test HAVE_A52DEC = "no"; then
+    A52DEC_CFLAGS=""
+    A52DEC_LIBS=""
+fi
+
+if test "x$HAVE_A52DEC" = "xyes"; then
+  ifelse([$1], , :, [$1])
+else
+  ifelse([$2], , :, [$2])
+fi
+
+AC_SUBST(A52DEC_CFLAGS)
+AC_SUBST(A52DEC_LIBS)
+])
diff --git a/m4/aalib.m4 b/m4/aalib.m4
new file mode 100644
index 0000000..10e0a64
--- /dev/null
+++ b/m4/aalib.m4
@@ -0,0 +1,178 @@
+# Configure paths for AALIB
+# touched up for clean output by Thomas Vander Stichele
+# Jan Hubicka 4/22/2001
+# stolen from Sam Lantinga 9/21/99
+# stolen from Manish Singh
+# stolen back from Frank Belew
+# stolen from Manish Singh
+# Shamelessly stolen from Owen Taylor
+
+dnl AM_PATH_AALIB([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for AALIB, and define AALIB_CFLAGS and AALIB_LIBS
+dnl
+AC_DEFUN([AM_PATH_AALIB],
+[dnl 
+dnl Get the cflags and libraries from the aalib-config script
+dnl
+AC_ARG_WITH(aalib-prefix,
+  AC_HELP_STRING([--with-aalib-prefix=PFX],
+                 [prefix where AALIB is installed (optional)]),
+  aalib_prefix="$withval", aalib_prefix="")
+
+AC_ARG_WITH(aalib-exec-prefix,
+  AC_HELP_STRING([--with-aalib-exec-prefix=PFX],
+                 [exec prefix where AALIB is installed (optional)]),
+  aalib_exec_prefix="$withval", aalib_exec_prefix="")
+
+AC_ARG_ENABLE(aalibtest, 
+  AC_HELP_STRING([--disable-aalibtest],
+                 [do not try to compile and run a test AALIB program]),
+  , enable_aalibtest=yes)
+
+  if test x$aalib_exec_prefix != x ; then
+     aalib_args="$aalib_args --exec-prefix=$aalib_exec_prefix"
+     if test x${AALIB_CONFIG+set} != xset ; then
+        AALIB_CONFIG=$aalib_exec_prefix/bin/aalib-config
+     fi
+  fi
+  if test x$aalib_prefix != x ; then
+     aalib_args="$aalib_args --prefix=$aalib_prefix"
+     if test x${AALIB_CONFIG+set} != xset ; then
+        AALIB_CONFIG=$aalib_prefix/bin/aalib-config
+     fi
+  fi
+
+  AC_PATH_PROG(AALIB_CONFIG, aalib-config, no)
+  min_aalib_version=ifelse([$1], ,0.11.0,$1)
+  AC_MSG_CHECKING(for AALIB - version >= $min_aalib_version)
+  no_aalib=""
+  if test "$AALIB_CONFIG" = "no" ; then
+    no_aalib=yes
+  else
+    AALIB_CFLAGS=`$AALIB_CONFIG $aalibconf_args --cflags`
+    AALIB_LIBS=`$AALIB_CONFIG $aalibconf_args --libs`
+
+    aalib_major_version=`$AALIB_CONFIG $aalib_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    aalib_minor_version=`$AALIB_CONFIG $aalib_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    aalib_micro_version=`$AALIB_CONFIG $aalib_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+    if test "x$enable_aalibtest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $AALIB_CFLAGS"
+      LIBS="$LIBS $AALIB_LIBS"
+dnl
+dnl Now check if the installed AALIB is sufficiently new. (Also sanity
+dnl checks the results of aalib-config to some extent
+dnl
+      rm -f conf.aalibtest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "aalib.h"
+
+char*
+my_strdup (char *str)
+{
+  char *new_str;
+  
+  if (str)
+    {
+      new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char));
+      strcpy (new_str, str);
+    }
+  else
+    new_str = NULL;
+  
+  return new_str;
+}
+
+int main (int argc, char *argv[])
+{
+  int major, minor, micro;
+  char *tmp_version;
+
+  /* This hangs on some systems (?)
+  system ("touch conf.aalibtest");
+  */
+  { FILE *fp = fopen("conf.aalibtest", "a"); if ( fp ) fclose(fp); }
+
+  /* HP/UX 9 (%@#!) writes to sscanf strings */
+  tmp_version = my_strdup("$min_aalib_version");
+  if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+     printf("%s, bad version string\n", "$min_aalib_version");
+     exit(1);
+   }
+
+   if (($aalib_major_version > major) ||
+      (($aalib_major_version == major) && ($aalib_minor_version > minor)) ||
+      (($aalib_major_version == major) && ($aalib_minor_version == minor) && ($aalib_micro_version >= micro)))
+    {
+      return 0;
+    }
+  else
+    {
+      printf("\n*** 'aalib-config --version' returned %d.%d.%d, but the minimum version\n", $aalib_major_version, $aalib_minor_version, $aalib_micro_version);
+      printf("*** of AALIB required is %d.%d.%d. If aalib-config is correct, then it is\n", major, minor, micro);
+      printf("*** best to upgrade to the required version.\n");
+      printf("*** If aalib-config was wrong, set the environment variable AALIB_CONFIG\n");
+      printf("*** to point to the correct copy of aalib-config, and remove the file\n");
+      printf("*** config.cache before re-running configure\n");
+      return 1;
+    }
+}
+
+],, no_aalib=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+  fi
+  if test "x$no_aalib" = x ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$2], , :, [$2])     
+  else
+     AC_MSG_RESULT(no)
+     if test "$AALIB_CONFIG" = "no" ; then
+       echo "*** The aalib-config script installed by AALIB could not be found"
+       echo "*** If AALIB was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the AALIB_CONFIG environment variable to the"
+       echo "*** full path to aalib-config."
+     else
+       if test -f conf.aalibtest ; then
+        :
+       else
+          echo "*** Could not run AALIB test program, checking why..."
+          CFLAGS="$CFLAGS $AALIB_CFLAGS"
+          LIBS="$LIBS $AALIB_LIBS"
+          AC_TRY_LINK([
+#include <stdio.h>
+#include "AALIB.h"
+],      [ return 0; ],
+        [ echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding AALIB or finding the wrong"
+          echo "*** version of AALIB. If it is not finding AALIB, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+	  echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+        [ echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means AALIB was incorrectly installed"
+          echo "*** or that you have moved AALIB since it was installed. In the latter case, you"
+          echo "*** may want to edit the aalib-config script: $AALIB_CONFIG" ])
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+     fi
+     AALIB_CFLAGS=""
+     AALIB_LIBS=""
+     ifelse([$3], , :, [$3])
+  fi
+  AC_SUBST(AALIB_CFLAGS)
+  AC_SUBST(AALIB_LIBS)
+  rm -f conf.aalibtest
+])
diff --git a/m4/as-ffmpeg.m4 b/m4/as-ffmpeg.m4
new file mode 100644
index 0000000..fa0c38d
--- /dev/null
+++ b/m4/as-ffmpeg.m4
@@ -0,0 +1,99 @@
+# CFLAGS and library paths for FFMPEG
+# taken from Autostar Sandbox, http://autostars.sourceforge.net/
+
+dnl Usage:
+dnl AM_PATH_FFMPEG([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl FIXME: version checking does not work currently
+dnl
+dnl Example:
+dnl AM_PATH_FFMPEG(0.4.6, , AC_MSG_ERROR([*** FFMPEG >= 0.4.6 not installed)) 
+dnl
+dnl Defines FFMPEG_LIBS
+dnl FIXME: should define FFMPEG_VERSION
+dnl
+
+AC_DEFUN([AM_PATH_FFMPEG],
+[
+  dnl allow for specification of a source path (for uninstalled)
+  AC_ARG_WITH(ffmpeg-source,
+    AC_HELP_STRING([--with-ffmpeg-source=DIR],
+                   [Directory where FFmpeg source is (optional)]),
+    ffmpeg_source="$withval")
+
+  dnl save CFLAGS and LIBS here
+  CFLAGS_save=$CFLAGS
+  LIBS_save=$LIBS
+  if test "x$ffmpeg_source" != "x"; then
+    dnl uninstalled FFmpeg copy
+    AC_MSG_NOTICE([Looking for FFmpeg source in $ffmpeg_source])
+    CFLAGS="-I$ffmpeg_source/libav -I$ffmpeg_source/libavcodec"
+    LIBS="-L$ffmpeg_source/libav -L$ffmpeg_source/libavcodec"
+    AC_DEFINE_UNQUOTED(HAVE_FFMPEG_UNINSTALLED, 1,
+                       [defined if we compile against uninstalled FFmpeg])
+    FFMPEG_COMMON_INCLUDE="#include <common.h>"
+  else
+    FFMPEG_COMMON_INCLUDE="#include <ffmpeg/common.h>"
+  fi
+  
+  dnl check for libavcodec
+  AC_CHECK_LIB(avcodec, avcodec_init, HAVE_FFMPEG=yes, HAVE_FFMPEG=no)
+  
+  dnl check for avcodec.h and avformat.h
+  if test "x$ffmpeg_source" != "x"; then
+    dnl uninstalled
+    AC_CHECK_HEADER(avcodec.h, , HAVE_FFMPEG=no, [/* only compile */])
+    AC_CHECK_HEADER(avformat.h, , HAVE_FFMPEG=no, [/* only compile */])
+  else
+    AC_CHECK_HEADER(ffmpeg/avcodec.h, , HAVE_FFMPEG=no)
+    AC_CHECK_HEADER(ffmpeg/avformat.h, , HAVE_FFMPEG=no)
+  fi
+
+dnl now check if it's sufficiently new
+
+  AC_LANG_SAVE()
+  AC_LANG_C()
+
+  dnl FIXME: we use strcmp, which we know is going to break if ffmpeg ever uses
+  dnl two digits for any of their version numbers.  It makes the test so much
+  dnl easier though so let's ignore that
+  AC_TRY_RUN([
+$FFMPEG_COMMON_INCLUDE
+#include <stdio.h>
+#include <string.h>
+
+int
+main ()
+{
+  if (strcmp (FFMPEG_VERSION, "$1") == -1)
+  {
+    fprintf (stderr,
+             "ERROR: your copy of ffmpeg is too old (%s)\n", FFMPEG_VERSION);
+    return 1;
+  }
+  else
+    return 0;
+}
+], , HAVE_FFMPEG=no)
+
+dnl now do the actual "do we have it ?" test
+  if test "x$HAVE_FFMPEG" = "xyes"; then
+    FFMPEG_LIBS="$LIBS -lavcodec -lavformat"
+    FFMPEG_CFLAGS="$CFLAGS"
+    AC_MSG_NOTICE(we have ffmpeg)
+    dnl execute what we have to because it's found
+    ifelse([$2], , :, [$2])
+  else
+    FFMPEG_LIBS=""
+    FFMPEG_CFLAGS=""
+    dnl execute what we have to because it's not found
+    ifelse([$3], , :, [$3])
+  fi
+
+dnl make variables available
+  AC_SUBST(FFMPEG_LIBS)
+  AC_SUBST(FFMPEG_CFLAGS)
+  AC_SUBST(HAVE_FFMPEG)
+  AC_LANG_RESTORE()
+  CFLAGS=$CFLAGS_save
+  LIBS=$LIBS_save
+])
diff --git a/m4/as-liblame.m4 b/m4/as-liblame.m4
new file mode 100644
index 0000000..ed7070c
--- /dev/null
+++ b/m4/as-liblame.m4
@@ -0,0 +1,50 @@
+# CFLAGS and library paths for LIBLAME
+# taken from Autostar Sandbox, http://autostars.sourceforge.net/
+# inspired by xmms.m4
+
+dnl Usage:
+dnl AM_PATH_LIBLAME([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl FIXME: version checking does not work currently
+dnl
+dnl Example:
+dnl AM_PATH_LIBLAME(3.89, , AC_MSG_ERROR([*** LIBLAME >= 3.89 not installed)) 
+dnl
+dnl Defines LIBLAME_LIBS
+dnl FIXME: should define LIBLAME_VERSION
+dnl
+
+AC_DEFUN([AM_PATH_LIBLAME],
+[
+  dnl check for the library
+  AC_CHECK_LIB(mp3lame, lame_init, HAVE_LIBLAME=yes, HAVE_LIBLAME=no, -lm)
+  dnl check if lame.h is available in the standard location or not
+  HAVE_LAME_H_STD=no
+  AC_CHECK_HEADER(lame.h, HAVE_LAME_H_STD=no, :)
+  AC_CHECK_HEADER(lame/lame.h, HAVE_LAME_H_STD=yes, :)
+  AC_MSG_CHECKING(for lame.h in right location)
+  if test "x$HAVE_LAME_H_STD" = "xyes"; then
+    AC_MSG_RESULT(yes)
+  else
+    AC_MSG_RESULT(no)
+    HAVE_LIBLAME=no
+    if test "x$HAVE_LAME_H_STD"="xno"; then
+      AC_MSG_WARN(lame.h found in include dir,)
+      AC_MSG_WARN( while it should be in it's own lame/ dir !)
+    fi
+ fi
+
+  dnl now do the actual "do we have it ?" test
+  if test "x$HAVE_LIBLAME" = "xyes"; then
+    LIBLAME_LIBS="-lmp3lame -lm"
+    dnl execute what we have to because it's found
+    ifelse([$2], , :, [$2])
+  else
+    LIBLAME_LIBS=""
+    dnl execute what we have to because it's not found
+    ifelse([$3], , :, [$3])
+  fi
+
+  dnl make variables available
+  AC_SUBST(LIBLAME_LIBS)
+  AC_SUBST(HAVE_LIBLAME)
+])
diff --git a/m4/as-slurp-ffmpeg.m4 b/m4/as-slurp-ffmpeg.m4
new file mode 100644
index 0000000..fd54b42
--- /dev/null
+++ b/m4/as-slurp-ffmpeg.m4
@@ -0,0 +1,59 @@
+dnl slurp-ffmpeg.m4 0.1.1
+dnl a macro to slurp in ffmpeg's cvs source inside a project tree
+dnl taken from Autostar Sandbox, http://autostars.sourceforge.net/
+
+dnl Usage:
+dnl AS_SLURP_FFMPEG(DIRECTORY, DATE, [ACTION-IF-WORKED [, ACTION-IF-NOT-WORKED]]])
+dnl
+dnl Example:
+dnl AM_PATH_FFMPEG(lib/ffmpeg, 2002-12-14 12:00 GMT)
+dnl
+dnl make sure you have a Tag file in the dir where you check out that
+dnl is the Tag of CVS you want to have checked out
+dnl it should correspond to the DATE argument you supply, ie resolve to
+dnl the same date
+dnl (in an ideal world, cvs would understand it's own Tag file format as
+dnl a date spec)
+
+AC_DEFUN([AS_SLURP_FFMPEG],
+[
+  # save original dir
+  FAILED=""
+  DIRECTORY=`pwd`
+  # get/update cvs
+  if test ! -d $1; then mkdir -p $1; fi
+  dnl we need to check $srcdir/$1 or it will always checkout ffmpeg even if it is there
+  dnl at least when top_srcdir != top_builddir.
+  dnl FIXME: unfortunately this makes the checkout go into top_srcdir
+  cd $srcdir/$1
+
+  if test ! -e ffmpeg/README; then
+    # check out cvs code
+    AC_MSG_NOTICE(checking out ffmpeg cvs code from $2 into $1)
+    cvs -Q -z4 -d:pserver:anonymous@mplayerhq.hu:/cvsroot/ffmpeg co -D '$2' ffmpeg || FAILED=yes
+  else
+    # compare against Tag file and see if it needs updating
+    if test "`cat Tag`" == "$2"; then
+      AC_MSG_NOTICE(ffmpeg cvs code in sync)
+    else
+      cd ffmpeg 
+      AC_MSG_NOTICE(updating ffmpeg cvs code to $2)
+      cvs -Q -z4 update -dP -D '$2' || FAILED=yes
+      cd ..
+    fi
+  fi
+  if test "x$FAILED" != "xyes"; then
+    echo "$2" > Tag 
+  fi
+  
+  # now go back
+  cd $DIRECTORY
+
+  if test "x$FAILED" == "xyes"; then
+    [$4]
+    false
+  else
+    [$3]
+    true
+  fi
+])
diff --git a/m4/check-libheader.m4 b/m4/check-libheader.m4
new file mode 100644
index 0000000..a7fc5a6
--- /dev/null
+++ b/m4/check-libheader.m4
@@ -0,0 +1,39 @@
+dnl
+dnl CHECK-LIBHEADER(FEATURE-NAME, LIB-NAME, LIB-FUNCTION, HEADER-NAME,
+dnl                 ACTION-IF-FOUND, ACTION-IF-NOT-FOUND,
+dnl                 EXTRA-LDFLAGS, EXTRA-CPPFLAGS)
+dnl
+dnl FEATURE-NAME        - feature name; library and header files are treated
+dnl                       as feature, which we look for
+dnl LIB-NAME            - library name as in AC_CHECK_LIB macro
+dnl LIB-FUNCTION        - library symbol as in AC_CHECK_LIB macro
+dnl HEADER-NAME         - header file name as in AC_CHECK_HEADER
+dnl ACTION-IF-FOUND     - when feature is found then execute given action
+dnl ACTION-IF-NOT-FOUND - when feature is not found then execute given action
+dnl EXTRA-LDFLAGS       - extra linker flags (-L or -l)
+dnl EXTRA-CPPFLAGS      - extra C preprocessor flags, i.e. -I/usr/X11R6/include
+dnl
+dnl Based on GST_CHECK_LIBHEADER from gstreamer plugins 0.3.1.
+dnl
+AC_DEFUN([CHECK_LIBHEADER],
+[
+  AC_CHECK_LIB([$2], [$3], HAVE_[$1]=yes, HAVE_[$1]=no, [$7])
+  check_libheader_feature_name=translit([$1], A-Z, a-z)
+
+  if test "x$HAVE_[$1]" = "xyes"; then
+    check_libheader_save_CPPFLAGS=$CPPFLAGS
+    CPPFLAGS="[$8] $CPPFLAGS"
+    AC_CHECK_HEADER([$4], :, HAVE_[$1]=no)
+    CPPFLAGS=$check_libheader_save_CPPFLAGS
+  fi
+
+  if test "x$HAVE_[$1]" = "xyes"; then
+    ifelse([$5], , :, [$5])
+    AC_MSG_NOTICE($check_libheader_feature_name was found)
+  else
+    ifelse([$6], , :, [$6])
+    AC_MSG_WARN($check_libheader_feature_name not found)
+  fi
+  AC_SUBST(HAVE_[$1])
+]
+)
diff --git a/m4/freetype2.m4 b/m4/freetype2.m4
new file mode 100644
index 0000000..7199071
--- /dev/null
+++ b/m4/freetype2.m4
@@ -0,0 +1,143 @@
+# Configure paths for FreeType2
+# Marcelo Magallon 2001-10-26, based on gtk.m4 by Owen Taylor
+
+dnl AC_CHECK_FT2([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for FreeType2, and define FT2_CFLAGS and FT2_LIBS
+dnl
+AC_DEFUN([AC_CHECK_FT2],
+[dnl
+dnl Get the cflags and libraries from the freetype-config script
+dnl
+AC_ARG_WITH(ft-prefix,
+[  --with-ft-prefix=PREFIX
+                          Prefix where FreeType is installed (optional)],
+            ft_config_prefix="$withval", ft_config_prefix="")
+AC_ARG_WITH(ft-exec-prefix,
+[  --with-ft-exec-prefix=PREFIX
+                          Exec prefix where FreeType is installed (optional)],
+            ft_config_exec_prefix="$withval", ft_config_exec_prefix="")
+AC_ARG_ENABLE(freetypetest,
+[  --disable-freetypetest  Do not try to compile and run
+                          a test FreeType program],
+              [], enable_fttest=yes)
+
+if test x$ft_config_exec_prefix != x ; then
+  ft_config_args="$ft_config_args --exec-prefix=$ft_config_exec_prefix"
+  if test x${FT2_CONFIG+set} != xset ; then
+    FT2_CONFIG=$ft_config_exec_prefix/bin/freetype-config
+  fi
+fi
+if test x$ft_config_prefix != x ; then
+  ft_config_args="$ft_config_args --prefix=$ft_config_prefix"
+  if test x${FT2_CONFIG+set} != xset ; then
+    FT2_CONFIG=$ft_config_prefix/bin/freetype-config
+  fi
+fi
+AC_PATH_PROG(FT2_CONFIG, freetype-config, no)
+
+min_ft_version=ifelse([$1], ,6.1.0,$1)
+AC_MSG_CHECKING(for FreeType - version >= $min_ft_version)
+no_ft=""
+if test "$FT2_CONFIG" = "no" ; then
+  no_ft=yes
+else
+  FT2_CFLAGS=`$FT2_CONFIG $ft_config_args --cflags`
+  FT2_LIBS=`$FT2_CONFIG $ft_config_args --libs`
+  ft_config_major_version=`$FT2_CONFIG $ft_config_args --version | \
+         sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+  ft_config_minor_version=`$FT2_CONFIG $ft_config_args --version | \
+         sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+  ft_config_micro_version=`$FT2_CONFIG $ft_config_args --version | \
+         sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+  ft_min_major_version=`echo $min_ft_version | \
+         sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+  ft_min_minor_version=`echo $min_ft_version | \
+         sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+  ft_min_micro_version=`echo $min_ft_version | \
+         sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+  if test x$enable_fttest = xyes ; then
+    ft_config_is_lt=""
+    if test $ft_config_major_version -lt $ft_min_major_version ; then
+      ft_config_is_lt=yes
+    else
+      if test $ft_config_major_version -eq $ft_min_major_version ; then
+        if test $ft_config_minor_version -lt $ft_min_minor_version ; then
+          ft_config_is_lt=yes
+        else
+          if test $ft_config_minor_version -eq $ft_min_minor_version ; then
+            if test $ft_config_micro_version -lt $ft_min_micro_version ; then
+              ft_config_is_lt=yes
+            fi
+          fi
+        fi
+      fi
+    fi
+    if test x$ft_config_is_lt = xyes ; then
+      no_ft=yes
+    else
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $FT2_CFLAGS"
+      LIBS="$FT2_LIBS $LIBS"
+dnl
+dnl Sanity checks for the results of freetype-config to some extent
+dnl
+      AC_TRY_RUN([
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main()
+{
+  FT_Library library;
+  FT_Error error;
+
+  error = FT_Init_FreeType(&library);
+
+  if (error)
+    return 1;
+  else
+  {
+    FT_Done_FreeType(library);
+    return 0;
+  }
+}
+],, no_ft=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+      CFLAGS="$ac_save_CFLAGS"
+      LIBS="$ac_save_LIBS"
+    fi             # test $ft_config_version -lt $ft_min_version
+  fi               # test x$enable_fttest = xyes
+fi                 # test "$FT2_CONFIG" = "no"
+if test x$no_ft = x ; then
+   AC_MSG_RESULT(yes)
+   ifelse([$2], , :, [$2])
+else
+   AC_MSG_RESULT(no)
+   if test "$FT2_CONFIG" = "no" ; then
+     echo "*** The freetype-config script installed by FreeType 2 could not be found."
+     echo "*** If FreeType 2 was installed in PREFIX, make sure PREFIX/bin is in"
+     echo "*** your path, or set the FT2_CONFIG environment variable to the"
+     echo "*** full path to freetype-config."
+   else
+     if test x$ft_config_is_lt = xyes ; then
+       echo "*** Your installed version of the FreeType 2 library is too old."
+       echo "*** If you have different versions of FreeType 2, make sure that"
+       echo "*** correct values for --with-ft-prefix or --with-ft-exec-prefix"
+       echo "*** are used, or set the FT2_CONFIG environment variable to the"
+       echo "*** full path to freetype-config."
+     else
+       echo "*** The FreeType test program failed to run.  If your system uses"
+       echo "*** shared libraries and they are installed outside the normal"
+       echo "*** system library path, make sure the variable LD_LIBRARY_PATH"
+       echo "*** (or whatever is appropiate for your system) is correctly set."
+     fi
+   fi
+   FT2_CFLAGS=""
+   FT2_LIBS=""
+   ifelse([$3], , :, [$3])
+fi
+AC_SUBST(FT2_CFLAGS)
+AC_SUBST(FT2_LIBS)
+])
diff --git a/m4/glib.m4 b/m4/glib.m4
new file mode 100644
index 0000000..b3c632b
--- /dev/null
+++ b/m4/glib.m4
@@ -0,0 +1,196 @@
+# Configure paths for GLIB
+# Owen Taylor     97-11-3
+
+dnl AM_PATH_GLIB([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]])
+dnl Test for GLIB, and define GLIB_CFLAGS and GLIB_LIBS, if "gmodule" or 
+dnl gthread is specified in MODULES, pass to glib-config
+dnl
+AC_DEFUN([AM_PATH_GLIB],
+[dnl 
+dnl Get the cflags and libraries from the glib-config script
+dnl
+AC_ARG_WITH(glib-prefix,[  --with-glib-prefix=PFX   Prefix where GLIB is installed (optional)],
+            glib_config_prefix="$withval", glib_config_prefix="")
+AC_ARG_WITH(glib-exec-prefix,[  --with-glib-exec-prefix=PFX Exec prefix where GLIB is installed (optional)],
+            glib_config_exec_prefix="$withval", glib_config_exec_prefix="")
+AC_ARG_ENABLE(glibtest, [  --disable-glibtest       Do not try to compile and run a test GLIB program],
+		    , enable_glibtest=yes)
+
+  if test x$glib_config_exec_prefix != x ; then
+     glib_config_args="$glib_config_args --exec-prefix=$glib_config_exec_prefix"
+     if test x${GLIB_CONFIG+set} != xset ; then
+        GLIB_CONFIG=$glib_config_exec_prefix/bin/glib-config
+     fi
+  fi
+  if test x$glib_config_prefix != x ; then
+     glib_config_args="$glib_config_args --prefix=$glib_config_prefix"
+     if test x${GLIB_CONFIG+set} != xset ; then
+        GLIB_CONFIG=$glib_config_prefix/bin/glib-config
+     fi
+  fi
+
+  for module in . $4
+  do
+      case "$module" in
+         gmodule) 
+             glib_config_args="$glib_config_args gmodule"
+         ;;
+         gthread) 
+             glib_config_args="$glib_config_args gthread"
+         ;;
+      esac
+  done
+
+  AC_PATH_PROG(GLIB_CONFIG, glib-config, no)
+  min_glib_version=ifelse([$1], ,0.99.7,$1)
+  AC_MSG_CHECKING(for GLIB - version >= $min_glib_version)
+  no_glib=""
+  if test "$GLIB_CONFIG" = "no" ; then
+    no_glib=yes
+  else
+    GLIB_CFLAGS=`$GLIB_CONFIG $glib_config_args --cflags`
+    GLIB_LIBS=`$GLIB_CONFIG $glib_config_args --libs`
+    glib_config_major_version=`$GLIB_CONFIG $glib_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    glib_config_minor_version=`$GLIB_CONFIG $glib_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    glib_config_micro_version=`$GLIB_CONFIG $glib_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+    if test "x$enable_glibtest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $GLIB_CFLAGS"
+      LIBS="$GLIB_LIBS $LIBS"
+dnl
+dnl Now check if the installed GLIB is sufficiently new. (Also sanity
+dnl checks the results of glib-config to some extent
+dnl
+      rm -f conf.glibtest
+      AC_TRY_RUN([
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int 
+main ()
+{
+  int major, minor, micro;
+  char *tmp_version;
+
+  system ("touch conf.glibtest");
+
+  /* HP/UX 9 (%@#!) writes to sscanf strings */
+  tmp_version = g_strdup("$min_glib_version");
+  if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+     printf("%s, bad version string\n", "$min_glib_version");
+     exit(1);
+   }
+
+  if ((glib_major_version != $glib_config_major_version) ||
+      (glib_minor_version != $glib_config_minor_version) ||
+      (glib_micro_version != $glib_config_micro_version))
+    {
+      printf("\n*** 'glib-config --version' returned %d.%d.%d, but GLIB (%d.%d.%d)\n", 
+             $glib_config_major_version, $glib_config_minor_version, $glib_config_micro_version,
+             glib_major_version, glib_minor_version, glib_micro_version);
+      printf ("*** was found! If glib-config was correct, then it is best\n");
+      printf ("*** to remove the old version of GLIB. You may also be able to fix the error\n");
+      printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n");
+      printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n");
+      printf("*** required on your system.\n");
+      printf("*** If glib-config was wrong, set the environment variable GLIB_CONFIG\n");
+      printf("*** to point to the correct copy of glib-config, and remove the file config.cache\n");
+      printf("*** before re-running configure\n");
+    } 
+  else if ((glib_major_version != GLIB_MAJOR_VERSION) ||
+	   (glib_minor_version != GLIB_MINOR_VERSION) ||
+           (glib_micro_version != GLIB_MICRO_VERSION))
+    {
+      printf("*** GLIB header files (version %d.%d.%d) do not match\n",
+	     GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
+      printf("*** library (version %d.%d.%d)\n",
+	     glib_major_version, glib_minor_version, glib_micro_version);
+    }
+  else
+    {
+      if ((glib_major_version > major) ||
+        ((glib_major_version == major) && (glib_minor_version > minor)) ||
+        ((glib_major_version == major) && (glib_minor_version == minor) && (glib_micro_version >= micro)))
+      {
+        return 0;
+       }
+     else
+      {
+        printf("\n*** An old version of GLIB (%d.%d.%d) was found.\n",
+               glib_major_version, glib_minor_version, glib_micro_version);
+        printf("*** You need a version of GLIB newer than %d.%d.%d. The latest version of\n",
+	       major, minor, micro);
+        printf("*** GLIB is always available from ftp://ftp.gtk.org.\n");
+        printf("***\n");
+        printf("*** If you have already installed a sufficiently new version, this error\n");
+        printf("*** probably means that the wrong copy of the glib-config shell script is\n");
+        printf("*** being found. The easiest way to fix this is to remove the old version\n");
+        printf("*** of GLIB, but you can also set the GLIB_CONFIG environment to point to the\n");
+        printf("*** correct copy of glib-config. (In this case, you will have to\n");
+        printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+        printf("*** so that the correct libraries are found at run-time))\n");
+      }
+    }
+  return 1;
+}
+],, no_glib=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+  fi
+  if test "x$no_glib" = x ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$2], , :, [$2])     
+  else
+     AC_MSG_RESULT(no)
+     if test "$GLIB_CONFIG" = "no" ; then
+       echo "*** The glib-config script installed by GLIB could not be found"
+       echo "*** If GLIB was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the GLIB_CONFIG environment variable to the"
+       echo "*** full path to glib-config."
+     else
+       if test -f conf.glibtest ; then
+        :
+       else
+          echo "*** Could not run GLIB test program, checking why..."
+          CFLAGS="$CFLAGS $GLIB_CFLAGS"
+          LIBS="$LIBS $GLIB_LIBS"
+          AC_TRY_LINK([
+#include <glib.h>
+#include <stdio.h>
+],      [ return ((glib_major_version) || (glib_minor_version) || (glib_micro_version)); ],
+        [ echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding GLIB or finding the wrong"
+          echo "*** version of GLIB. If it is not finding GLIB, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+	  echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+          echo "***"
+          echo "*** If you have a RedHat 5.0 system, you should remove the GTK package that"
+          echo "*** came with the system with the command"
+          echo "***"
+          echo "***    rpm --erase --nodeps gtk gtk-devel" ],
+        [ echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means GLIB was incorrectly installed"
+          echo "*** or that you have moved GLIB since it was installed. In the latter case, you"
+          echo "*** may want to edit the glib-config script: $GLIB_CONFIG" ])
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+     fi
+     GLIB_CFLAGS=""
+     GLIB_LIBS=""
+     ifelse([$3], , :, [$3])
+  fi
+  AC_SUBST(GLIB_CFLAGS)
+  AC_SUBST(GLIB_LIBS)
+  rm -f conf.glibtest
+])
diff --git a/m4/gst-alsa.m4 b/m4/gst-alsa.m4
new file mode 100644
index 0000000..4141d06
--- /dev/null
+++ b/m4/gst-alsa.m4
@@ -0,0 +1,150 @@
+dnl Configure Paths for Alsa
+dnl Some modifications by Richard Boulton <richard-alsa@tartarus.org>
+dnl Christopher Lansdown <lansdoct@cs.alfred.edu>
+dnl Jaroslav Kysela <perex@suse.cz>
+dnl Last modification: alsa.m4,v 1.23 2004/01/16 18:14:22 tiwai Exp
+dnl AM_PATH_ALSA([MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for libasound, and define ALSA_CFLAGS and ALSA_LIBS as appropriate.
+dnl enables arguments --with-alsa-prefix=
+dnl                   --with-alsa-enc-prefix=
+dnl                   --disable-alsatest
+dnl
+dnl For backwards compatibility, if ACTION_IF_NOT_FOUND is not specified,
+dnl and the alsa libraries are not found, a fatal AC_MSG_ERROR() will result.
+dnl
+AC_DEFUN([AM_PATH_ALSA],
+[dnl Save the original CFLAGS, LDFLAGS, and LIBS
+alsa_save_CFLAGS="$CFLAGS"
+alsa_save_LDFLAGS="$LDFLAGS"
+alsa_save_LIBS="$LIBS"
+alsa_found=yes
+
+dnl
+dnl Get the cflags and libraries for alsa
+dnl
+AC_ARG_WITH(alsa-prefix,
+  AC_HELP_STRING([--with-alsa-prefix=PFX],
+                 [prefix where Alsa library is installed(optional)]),
+  [alsa_prefix="$withval"], [alsa_prefix=""])
+
+AC_ARG_WITH(alsa-inc-prefix,
+  AC_HELP_STRING([--with-alsa-inc-prefix=PFX],
+                 [prefix where include libraries are (optional)]),
+  [alsa_inc_prefix="$withval"], [alsa_inc_prefix=""])
+
+dnl FIXME: this is not yet implemented
+dnl AC_ARG_ENABLE(alsatest,
+dnl  AC_HELP_STRING([--disable-alsatest],
+dnl                 [do not try to compile and run a test Alsa program],
+dnl                 [enable_alsatest=no], [enable_alsatest=yes])
+
+dnl Add any special include directories
+AC_MSG_CHECKING(for ALSA CFLAGS)
+if test "$alsa_inc_prefix" != "" ; then
+	ALSA_CFLAGS="$ALSA_CFLAGS -I$alsa_inc_prefix"
+	CFLAGS="$CFLAGS -I$alsa_inc_prefix"
+fi
+AC_MSG_RESULT($ALSA_CFLAGS)
+
+dnl add any special lib dirs
+AC_MSG_CHECKING(for ALSA LDFLAGS)
+if test "$alsa_prefix" != "" ; then
+	ALSA_LIBS="$ALSA_LIBS -L$alsa_prefix"
+	LDFLAGS="$LDFLAGS $ALSA_LIBS"
+fi
+
+dnl add the alsa library
+ALSA_LIBS="$ALSA_LIBS -lasound -lm -ldl -lpthread"
+LIBS=`echo $LIBS | sed 's/-lm//'`
+LIBS=`echo $LIBS | sed 's/-ldl//'`
+LIBS=`echo $LIBS | sed 's/-lpthread//'`
+LIBS=`echo $LIBS | sed 's/  //'`
+LIBS="$ALSA_LIBS $LIBS"
+AC_MSG_RESULT($ALSA_LIBS)
+
+dnl Check for a working version of libasound that is of the right version.
+min_alsa_version=ifelse([$1], ,0.1.1,$1)
+AC_MSG_CHECKING(for libasound headers version >= $min_alsa_version)
+no_alsa=""
+    alsa_min_major_version=`echo $min_alsa_version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    alsa_min_minor_version=`echo $min_alsa_version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    alsa_min_micro_version=`echo $min_alsa_version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+
+AC_LANG_SAVE
+AC_LANG_C
+AC_TRY_COMPILE([
+#include <alsa/asoundlib.h>
+], [
+void main(void)
+{
+/* ensure backward compatibility */
+#if !defined(SND_LIB_MAJOR) && defined(SOUNDLIB_VERSION_MAJOR)
+#define SND_LIB_MAJOR SOUNDLIB_VERSION_MAJOR
+#endif
+#if !defined(SND_LIB_MINOR) && defined(SOUNDLIB_VERSION_MINOR)
+#define SND_LIB_MINOR SOUNDLIB_VERSION_MINOR
+#endif
+#if !defined(SND_LIB_SUBMINOR) && defined(SOUNDLIB_VERSION_SUBMINOR)
+#define SND_LIB_SUBMINOR SOUNDLIB_VERSION_SUBMINOR
+#endif
+
+#  if(SND_LIB_MAJOR > $alsa_min_major_version)
+  exit(0);
+#  else
+#    if(SND_LIB_MAJOR < $alsa_min_major_version)
+#       error not present
+#    endif
+
+#   if(SND_LIB_MINOR > $alsa_min_minor_version)
+  exit(0);
+#   else
+#     if(SND_LIB_MINOR < $alsa_min_minor_version)
+#          error not present
+#      endif
+
+#      if(SND_LIB_SUBMINOR < $alsa_min_micro_version)
+#        error not present
+#      endif
+#    endif
+#  endif
+exit(0);
+}
+],
+  [AC_MSG_RESULT(found.)],
+  [AC_MSG_RESULT(not present.)
+   ifelse([$3], , [AC_MSG_ERROR(Sufficiently new version of libasound not found.)])
+   alsa_found=no]
+)
+AC_LANG_RESTORE
+
+dnl Now that we know that we have the right version, let's see if we have the library and not just the headers.
+if test "x$enable_alsatest" = "xyes"; then
+AC_CHECK_LIB([asound], [snd_ctl_open],,
+	[ifelse([$3], , [AC_MSG_ERROR(No linkable libasound was found.)])
+	 alsa_found=no]
+)
+fi
+
+if test "x$alsa_found" = "xyes" ; then
+   ifelse([$2], , :, [$2])
+   LIBS=`echo $LIBS | sed 's/-lasound//g'`
+   LIBS=`echo $LIBS | sed 's/  //'`
+   LIBS="-lasound $LIBS"
+fi
+if test "x$alsa_found" = "xno" ; then
+   ifelse([$3], , :, [$3])
+   CFLAGS="$alsa_save_CFLAGS"
+   LDFLAGS="$alsa_save_LDFLAGS"
+   LIBS="$alsa_save_LIBS"
+   ALSA_CFLAGS=""
+   ALSA_LIBS=""
+fi
+
+dnl That should be it.  Now just export out symbols:
+AC_SUBST(ALSA_CFLAGS)
+AC_SUBST(ALSA_LIBS)
+])
+
diff --git a/m4/gst-artsc.m4 b/m4/gst-artsc.m4
new file mode 100644
index 0000000..4659960
--- /dev/null
+++ b/m4/gst-artsc.m4
@@ -0,0 +1,28 @@
+dnl Perform a check for existence of ARTSC
+dnl Richard Boulton <richard-alsa@tartarus.org>
+dnl Last modification: 26/06/2001
+dnl GST_CHECK_ARTSC()
+dnl
+dnl This check was written for GStreamer: it should be renamed and checked
+dnl for portability if you decide to use it elsewhere.
+dnl
+AC_DEFUN([GST_CHECK_ARTSC],
+[ 
+  AC_PATH_PROG(ARTSC_CONFIG, artsc-config, no)
+  if test "x$ARTSC_CONFIG" = "xno"; then
+    AC_MSG_WARN([Couldn't find artsc-config])
+    HAVE_ARTSC=no
+    ARTSC_LIBS=
+    ARTSC_CFLAGS=
+  else
+    ARTSC_LIBS=`artsc-config --libs`
+    ARTSC_CFLAGS=`artsc-config --cflags`
+    dnl AC_CHECK_HEADER uses CPPFLAGS, but not CFLAGS.  
+    dnl FIXME: Ensure only suitable flags result from artsc-config --cflags
+    CPPFLAGS="$CPPFLAGS $ARTSC_CFLAGS"
+    AC_CHECK_HEADER(artsc.h, HAVE_ARTSC=yes, HAVE_ARTSC=no)
+  fi
+  AC_SUBST(ARTSC_LIBS)
+  AC_SUBST(ARTSC_CFLAGS) 
+])
+
diff --git a/m4/gst-fionread.m4 b/m4/gst-fionread.m4
new file mode 100644
index 0000000..603aa45
--- /dev/null
+++ b/m4/gst-fionread.m4
@@ -0,0 +1,42 @@
+AC_DEFUN([GST_CHECK_FIONREAD], [
+
+  AC_MSG_CHECKING(for FIONREAD in sys/ioctl.h)
+  AC_CACHE_VAL(_cv_gst_fionread_in_sys_ioctl, [
+    AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/ioctl.h>
+], [
+int x = FIONREAD;
+if ( x )
+  return 0;
+    ], _cv_gst_fionread_in_sys_ioctl="yes",_cv_gst_fionread_in_sys_ioctl="no")
+  ])
+
+  AC_MSG_RESULT($_cv_gst_fionread_in_sys_ioctl)
+
+  if test "$_cv_gst_fionread_in_sys_ioctl" = "yes"; then
+    AC_DEFINE([HAVE_FIONREAD_IN_SYS_IOCTL], 1, [FIONREAD ioctl found in sys/ioclt.h])
+
+  else
+
+    AC_MSG_CHECKING(for FIONREAD in sys/filio.h)
+    AC_CACHE_VAL(_cv_gst_fionread_in_sys_filio, [
+      AC_TRY_COMPILE([
+  #include <sys/types.h>
+  #include <sys/filio.h>
+  ], [
+  int x = FIONREAD;
+  if ( x )
+    return 0;
+      ], _cv_gst_fionread_in_sys_filio="yes",_cv_gst_fionread_in_sys_filio="no")
+    ])
+
+    AC_MSG_RESULT($_cv_gst_fionread_in_sys_filio)
+
+    if test "$_cv_gst_fionread_in_sys_filio" = "yes"; then
+      AC_DEFINE([HAVE_FIONREAD_IN_SYS_FILIO], 1, [FIONREAD ioctl found in sys/filio.h])
+    fi
+
+  fi
+
+])
diff --git a/m4/gst-ivorbis.m4 b/m4/gst-ivorbis.m4
new file mode 100644
index 0000000..ae35bbb
--- /dev/null
+++ b/m4/gst-ivorbis.m4
@@ -0,0 +1,68 @@
+# Configure paths for Tremor
+
+dnl XIPH_PATH_IVORBIS([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libivorbis, and define IVORBIS_CFLAGS and IVORBIS_LIBS
+dnl
+AC_DEFUN([XIPH_PATH_IVORBIS],
+[dnl 
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(ivorbis,[  --with-ivorbis=PFX   Prefix where libivorbis is installed (optional)], ivorbis_prefix="$withval", ivorbis_prefix="")
+AC_ARG_WITH(ivorbis-libraries,[  --with-ivorbis-libraries=DIR   Directory where libivorbis library is installed (optional)], ivorbis_libraries="$withval", ivorbis_libraries="")
+AC_ARG_WITH(ivorbis-includes,[  --with-ivorbis-includes=DIR   Directory where libivorbis header files are installed (optional)], ivorbis_includes="$withval", ivorbis_includes="")
+AC_ARG_ENABLE(ivorbistest, [  --disable-ivorbistest       Do not try to compile and run a test Ivorbis program],, enable_ivorbistest=yes)
+
+  if test "x$ivorbis_libraries" != "x" ; then
+    IVORBIS_LIBS="-L$ivorbis_libraries"
+  elif test "x$ivorbis_prefix" != "x" ; then
+    IVORBIS_LIBS="-L$ivorbis_prefix/lib"
+  elif test "x$prefix" != "xNONE"; then
+    IVORBIS_LIBS="-L$prefix/lib"
+  fi
+
+  IVORBIS_LIBS="$IVORBIS_LIBS -lvorbisidec -lm"
+
+  if test "x$ivorbis_includes" != "x" ; then
+    IVORBIS_CFLAGS="-I$ivorbis_includes"
+  elif test "x$ivorbis_prefix" != "x" ; then
+    IVORBIS_CFLAGS="-I$ivorbis_prefix/include"
+  elif test "x$prefix" != "xNONE"; then
+    IVORBIS_CFLAGS="-I$prefix/include"
+  fi
+
+  AC_MSG_CHECKING(for Tremor)
+  no_ivorbis=""
+
+  if test "x$enable_ivorbistest" = "xyes" ; then
+    ac_save_CFLAGS="$CFLAGS"
+    ac_save_LIBS="$LIBS"
+    CFLAGS="$CFLAGS $IVORBIS_CFLAGS $OGG_CFLAGS"
+    LIBS="$LIBS $IVORBIS_LIBS $OGG_LIBS"
+dnl
+dnl Now check if the installed Tremor is sufficiently new.
+dnl
+      rm -f conf.ivorbistest
+      AC_TRY_COMPILE([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tremor/codec.h>
+],,, no_ivorbis=yes)
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+  fi
+
+  if test "x$no_ivorbis" = "x" ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$1], , :, [$1])     
+  else
+     AC_MSG_RESULT(no)
+     IVORBIS_CFLAGS=""
+     IVORBIS_LIBS=""
+     IVORBISFILE_LIBS=""
+     ifelse([$2], , :, [$2])
+  fi
+  AC_SUBST(IVORBIS_CFLAGS)
+  AC_SUBST(IVORBIS_LIBS)
+  AC_SUBST(IVORBISFILE_LIBS)
+])
diff --git a/m4/gst-matroska.m4 b/m4/gst-matroska.m4
new file mode 100644
index 0000000..b50caaa
--- /dev/null
+++ b/m4/gst-matroska.m4
@@ -0,0 +1,262 @@
+# Configure paths for libebml
+
+dnl PATH_EBML([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libebml, and define EBML_CFLAGS and EBML_LIBS
+dnl
+AC_DEFUN([PATH_EBML],
+[dnl 
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(ebml-prefix,[  --with-ebml-prefix=PFX        Prefix where libebml is installed (optional)], ebml_prefix="$withval", ebml_prefix="")
+AC_ARG_WITH(ebml-include,[  --with-ebml-include=DIR       Path to where the libebml include files installed (optional)], ebml_include="$withval", ebml_include="")
+AC_ARG_WITH(ebml-lib,[  --with-ebml-lib=DIR           Path to where the libebml library installed (optional)], ebml_lib="$withval", ebml_lib="")
+AC_ARG_ENABLE(ebmltest, [  --disable-ebmltest            Do not try to compile and run a test EBML program],, enable_ebmltest=yes)
+
+  if test "x$ebml_prefix" != "x"; then
+    ebml_args="$ebml_args --prefix=$ebml_prefix"
+    if test "x$ebml_include" != "x"; then
+      EBML_CFLAGS="-I$ebml_include"
+    else
+      EBML_CFLAGS="-I$ebml_prefix/include/ebml"
+    fi
+    if test "x$ebml_lib" != "x"; then
+      EBML_LIBS="-L$ebml_lib"
+    else
+      EBML_LIBS="-L$ebml_prefix/lib"
+    fi
+  elif test "x$prefix" != "xNONE"; then
+    ebml_args="$ebml_args --prefix=$prefix"
+    if test "x$ebml_include" != "x"; then
+      EBML_CFLAGS="-I$ebml_include"
+    else
+      EBML_CFLAGS="-I$prefix/include/ebml"
+    fi
+    if test "x$ebml_lib" != "x"; then
+      EBML_LIBS="-L$ebml_lib"
+    else
+      EBML_LIBS="-L$prefix/lib"
+    fi
+  else
+    if test "x$ebml_include" != "x"; then
+      EBML_CFLAGS="-I$ebml_include"
+    else
+      EBML_CFLAGS="-I/usr/include/ebml -I/usr/local/include/ebml"
+    fi
+    if test "x$ebml_lib" != "x"; then
+      EBML_LIBS="-L$ebml_lib"
+    else
+      EBML_LIBS="-L/usr/local/lib"
+    fi
+  fi
+
+  EBML_LIBS="$EBML_LIBS -lebml"
+
+  AC_MSG_CHECKING(for EBML)
+  no_ebml=""
+
+
+  if test "x$enable_ebmltest" = "xyes" ; then
+    ac_save_CFLAGS="$CFLAGS"
+    ac_save_LIBS="$LIBS"
+    CFLAGS="$CFLAGS $EBML_CFLAGS"
+    LIBS="$LIBS $EBML_LIBS"
+dnl
+dnl Now check if the installed EBML is sufficiently new.
+dnl
+      rm -f conf.ebmltest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <EbmlConfig.h>
+
+int main ()
+{
+  system("touch conf.ebmltest");
+  return 0;
+}
+
+],, no_ebml=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+  fi
+
+  if test "x$no_ebml" = "x" ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$1], , :, [$1])     
+  else
+     AC_MSG_RESULT(no)
+     if test -f conf.ebmltest ; then
+       :
+     else
+       echo "*** Could not run Ebml test program, checking why..."
+       CFLAGS="$CFLAGS $EBML_CFLAGS"
+       LIBS="$LIBS $EBML_LIBS"
+       AC_TRY_LINK([
+#include <stdio.h>
+#include <EbmlConfig.h>
+],     [ return 0; ],
+       [ echo "*** The test program compiled, but did not run. This usually means"
+       echo "*** that the run-time linker is not finding EBML or finding the wrong"
+       echo "*** version of EBML. If it is not finding EBML, you'll need to set your"
+       echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+       echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+       echo "*** is required on your system"
+       echo "***"
+       echo "*** If you have an old version installed, it is best to remove it, although"
+       echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+       [ echo "*** The test program failed to compile or link. See the file config.log for the"
+       echo "*** exact error that occured. This usually means EBML was incorrectly installed"
+       echo "*** or that you have moved EBML since it was installed." ])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+     EBML_CFLAGS=""
+     EBML_LIBS=""
+     ifelse([$2], , :, [$2])
+  fi
+  AC_SUBST(EBML_CFLAGS)
+  AC_SUBST(EBML_LIBS)
+  rm -f conf.ebmltest
+])
+
+# Configure paths for libmatroska
+
+dnl PATH_MATROSKA(MIN_VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libmatroska, and define MATROSKA_CFLAGS and MATROSKA_LIBS
+dnl
+AC_DEFUN([PATH_MATROSKA],
+[dnl 
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(matroska-prefix,[  --with-matroska-prefix=PFX    Prefix where libmatroska is installed (optional)], matroska_prefix="$withval", matroska_prefix="")
+AC_ARG_WITH(matroska-include,[  --with-matroska-include=DIR   Path to where the libmatroska include files installed (optional)], matroska_include="$withval", matroska_include="")
+AC_ARG_WITH(matroska-lib,[  --with-matroska-lib=DIR       Path to where the libmatroska library installed (optional)], matroska_lib="$withval", matroska_lib="")
+AC_ARG_ENABLE(matroskatest, [  --disable-matroskatest        Do not try to compile and run a test Matroska program],, enable_matroskatest=yes)
+
+  if test "x$matroska_prefix" != "x"; then
+    matroska_args="$matroska_args --prefix=$matroska_prefix"
+    if test "x$matroska_include" != "x"; then
+      MATROSKA_CFLAGS="-I$matroska_include"
+    else
+      MATROSKA_CFLAGS="-I$matroska_prefix/include/matroska"
+    fi
+    if test "x$matroska_lib" != "x"; then
+      MATROSKA_LIBS="-L$matroska_lib"
+    else
+      MATROSKA_LIBS="-L$matroska_prefix/lib"
+    fi
+  elif test "x$prefix" != "xNONE"; then
+    matroska_args="$matroska_args --prefix=$prefix"
+    if test "x$matroska_include" != "x"; then
+      MATROSKA_CFLAGS="-I$matroska_include"
+    else
+      MATROSKA_CFLAGS="-I$prefix/include/matroska"
+    fi
+    if test "x$matroska_lib" != "x"; then
+      MATROSKA_LIBS="-L$matroska_lib"
+    else
+      MATROSKA_LIBS="-L$prefix/lib"
+    fi
+  else
+    if test "x$matroska_include" != "x"; then
+      MATROSKA_CFLAGS="-I$matroska_include"
+    else
+      MATROSKA_CFLAGS="-I/usr/include/matroska -I/usr/local/include/matroska"
+    fi
+    if test "x$matroska_lib" != "x"; then
+      MATROSKA_LIBS="-L$matroska_lib"
+    else
+      MATROSKA_LIBS="-L/usr/local/lib"
+    fi
+  fi
+
+  MATROSKA_LIBS="$MATROSKA_LIBS -lmatroska"
+
+  AC_MSG_CHECKING(for Matroska)
+  no_matroska=""
+
+
+  if test "x$enable_matroskatest" = "xyes" ; then
+    ac_save_CXXFLAGS="$CXXFLAGS"
+    ac_save_LIBS="$LIBS"
+    CXXFLAGS="$CXXFLAGS $MATROSKA_CFLAGS $EBML_CFLAGS"
+    LIBS="$LIBS $MATROSKA_LIBS $EBML_LIBS"
+dnl
+dnl Now check if the installed Matroska is sufficiently new.
+dnl
+      rm -f conf.matroskatest
+      AC_LANG_CPLUSPLUS
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <EbmlConfig.h>
+#include <KaxVersion.h>
+
+using namespace LIBMATROSKA_NAMESPACE;
+
+int main ()
+{
+  FILE *f;
+  f = fopen("conf.matroskatest", "wb");
+  if (f == NULL)
+    return 1;
+  fprintf(f, "%s\n", KaxCodeVersion.c_str());
+  fclose(f);
+  return 0;
+}
+
+],, no_matroska=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+      AC_LANG_C
+      CXXFLAGS="$ac_save_CXXFLAGS"
+      LIBS="$ac_save_LIBS"
+  fi
+
+  if test "x$no_matroska" = "x" -a -f conf.matroskatest ; then
+    AC_MSG_RESULT(yes)
+
+    AC_MSG_CHECKING(Matroska version)
+
+    matroska_version=`cat conf.matroskatest`
+    mk_MAJVER=`echo $1 | cut -d"." -f1`
+    mk_MINVER=`echo $1 | cut -d"." -f2`
+    mk_RELVER=`echo $1 | cut -d"." -f3`
+    mver_ok=`sed 's;\.;\ ;g' < conf.matroskatest | (read -a mver
+    if test ${mver[[0]]} -gt $mk_MAJVER ; then
+      mver_ok=1
+    elif test ${mver[[0]]} -lt $mk_MAJVER ; then
+      mver_ok=0
+    else
+      if test ${mver[[1]]} -gt $mk_MINVER ; then
+        mver_ok=1
+      elif test ${mver[[1]]} -lt $mk_MINVER ; then
+        mver_ok=0
+      else
+        if test ${mver[[2]]} -ge $mk_RELVER ; then
+          mver_ok=1
+        else
+          mver_ok=0
+        fi
+      fi
+    fi
+    echo $mver_ok )`
+    if test "$mver_ok" = "1" ; then
+      AC_MSG_RESULT($matroska_version ok)
+       ifelse([$2], , :, [$2])     
+    else
+      AC_MSG_RESULT($matroska_version too old)
+      echo '*** Your Matroska version is too old. Upgrade to at least version'
+      echo '*** $1 and re-run configure.'
+       ifelse([$3], , :, [$3])     
+    fi
+
+  else
+     AC_MSG_RESULT(no)
+     ifelse([$3], , :, [$3])
+  fi
+
+  AC_SUBST(MATROSKA_CFLAGS)
+  AC_SUBST(MATROSKA_LIBS)
+  rm -f conf.matroskatest
+])
diff --git a/m4/gst-sdl.m4 b/m4/gst-sdl.m4
new file mode 100644
index 0000000..cfc3196
--- /dev/null
+++ b/m4/gst-sdl.m4
@@ -0,0 +1,184 @@
+# stuff for SDL, hope this helps if we put it here
+
+# Configure paths for SDL
+# Sam Lantinga 9/21/99
+# stolen from Manish Singh
+# stolen back from Frank Belew
+# stolen from Manish Singh
+# Shamelessly stolen from Owen Taylor
+
+dnl AM_PATH_SDL([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for SDL, and define SDL_CFLAGS and SDL_LIBS
+dnl
+AC_DEFUN([AM_PATH_SDL],
+[dnl 
+dnl Get the cflags and libraries from the sdl-config script
+dnl
+AC_ARG_WITH(sdl-prefix,
+  AC_HELP_STRING([--with-sdl-prefix=PFX],
+                 [prefix where SDL is installed (optional)]),
+  sdl_prefix="$withval", sdl_prefix="")
+
+AC_ARG_WITH(sdl-exec-prefix,
+  AC_HELP_STRING([--with-sdl-exec-prefix=PFX],
+                 [exec prefix where SDL is installed (optional)]),
+  sdl_exec_prefix="$withval", sdl_exec_prefix="")
+
+AC_ARG_ENABLE(sdltest,
+  AC_HELP_STRING([--disable-sdltest],
+                 [do not try to compile and run a test SDL program]),
+  , enable_sdltest=yes)
+
+  if test x$sdl_exec_prefix != x ; then
+     sdl_args="$sdl_args --exec-prefix=$sdl_exec_prefix"
+     if test x${SDL_CONFIG+set} != xset ; then
+        SDL_CONFIG=$sdl_exec_prefix/bin/sdl-config
+     fi
+  fi
+  if test x$sdl_prefix != x ; then
+     sdl_args="$sdl_args --prefix=$sdl_prefix"
+     if test x${SDL_CONFIG+set} != xset ; then
+        SDL_CONFIG=$sdl_prefix/bin/sdl-config
+     fi
+  fi
+
+  AC_PATH_PROG(SDL_CONFIG, sdl-config, no)
+  min_sdl_version=ifelse([$1], ,0.11.0,$1)
+  AC_MSG_CHECKING(for SDL - version >= $min_sdl_version)
+  no_sdl=""
+  if test "$SDL_CONFIG" = "no" ; then
+    no_sdl=yes
+  else
+    SDL_CFLAGS=`$SDL_CONFIG $sdlconf_args --cflags`
+    SDL_LIBS=`$SDL_CONFIG $sdlconf_args --libs`
+
+    sdl_major_version=`$SDL_CONFIG $sdl_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    sdl_minor_version=`$SDL_CONFIG $sdl_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    sdl_micro_version=`$SDL_CONFIG $sdl_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+    if test "x$enable_sdltest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $SDL_CFLAGS"
+      LIBS="$LIBS $SDL_LIBS"
+dnl
+dnl Now check if the installed SDL is sufficiently new. (Also sanity
+dnl checks the results of sdl-config to some extent
+dnl
+      rm -f conf.sdltest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "SDL.h"
+
+char*
+my_strdup (char *str)
+{
+  char *new_str;
+  
+  if (str)
+    {
+      new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char));
+      strcpy (new_str, str);
+    }
+  else
+    new_str = NULL;
+  
+  return new_str;
+}
+
+int main (int argc, char *argv[])
+{
+  int major, minor, micro;
+  char *tmp_version;
+
+  /* This hangs on some systems (?)
+  system ("touch conf.sdltest");
+  */
+  { FILE *fp = fopen("conf.sdltest", "a"); if ( fp ) fclose(fp); }
+
+  /* HP/UX 9 (%@#!) writes to sscanf strings */
+  tmp_version = my_strdup("$min_sdl_version");
+  if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+     printf("%s, bad version string\n", "$min_sdl_version");
+     exit(1);
+   }
+
+   if (($sdl_major_version > major) ||
+      (($sdl_major_version == major) && ($sdl_minor_version > minor)) ||
+      (($sdl_major_version == major) && ($sdl_minor_version == minor) && ($sdl_micro_version >= micro)))
+    {
+      return 0;
+    }
+  else
+    {
+      printf("\n*** 'sdl-config --version' returned %d.%d.%d, but the minimum version\n", $sdl_major_version, $sdl_minor_version, $sdl_micro_version);
+      printf("*** of SDL required is %d.%d.%d. If sdl-config is correct, then it is\n", major, minor, micro);
+      printf("*** best to upgrade to the required version.\n");
+      printf("*** If sdl-config was wrong, set the environment variable SDL_CONFIG\n");
+      printf("*** to point to the correct copy of sdl-config, and remove the file\n");
+      printf("*** config.cache before re-running configure\n");
+      return 1;
+    }
+}
+
+],, no_sdl=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+  fi
+  if test "x$no_sdl" = x ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$2], , :, [$2])     
+  else
+     AC_MSG_RESULT(no)
+     if test "$SDL_CONFIG" = "no" ; then
+       echo "*** The sdl-config script installed by SDL could not be found"
+       echo "*** If SDL was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the SDL_CONFIG environment variable to the"
+       echo "*** full path to sdl-config."
+     else
+       if test -f conf.sdltest ; then
+        :
+       else
+          echo "*** Could not run SDL test program, checking why..."
+          CFLAGS="$CFLAGS $SDL_CFLAGS"
+          LIBS="$LIBS $SDL_LIBS"
+          AC_TRY_LINK([
+#include <stdio.h>
+#include "SDL.h"
+
+int main(int argc, char *argv[])
+{ return 0; }
+#undef  main
+#define main K_and_R_C_main
+],      [ return 0; ],
+        [ echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding SDL or finding the wrong"
+          echo "*** version of SDL. If it is not finding SDL, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+	  echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+        [ echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means SDL was incorrectly installed"
+          echo "*** or that you have moved SDL since it was installed. In the latter case, you"
+          echo "*** may want to edit the sdl-config script: $SDL_CONFIG" ])
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+     fi
+     SDL_CFLAGS=""
+     SDL_LIBS=""
+     ifelse([$3], , :, [$3])
+  fi
+  AC_SUBST(SDL_CFLAGS)
+  AC_SUBST(SDL_LIBS)
+  rm -f conf.sdltest
+])
+
diff --git a/m4/gst-shout2.m4 b/m4/gst-shout2.m4
new file mode 100644
index 0000000..e85a767
--- /dev/null
+++ b/m4/gst-shout2.m4
@@ -0,0 +1,102 @@
+# Configure paths for libshout
+# Jack Moffitt <jack@icecast.org> 08-06-2001
+# Shamelessly stolen from Owen Taylor and Manish Singh
+
+dnl AM_PATH_SHOUT2([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libshout 2, and define SHOUT2_CFLAGS and SHOUT2_LIBS
+dnl
+AC_DEFUN([AM_PATH_SHOUT2],
+[dnl 
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(shout2-prefix,[  --with-shout2-prefix=PFX   Prefix where libshout2 is installed (optional)], shout2_prefix="$withval", shout2_prefix="")
+AC_ARG_ENABLE(shout2test, [  --disable-shout2test       Do not try to compile and run a test shout2 program],, enable_shout2test=yes)
+
+  if test "x$shout2_prefix" != "xNONE" ; then
+    SHOUT2_CFLAGS="-I$shout2_prefix/include"
+    SHOUT2_LIBS="-L$shout2_prefix/lib"
+  elif test "x$prefix" != "x"; then
+    SHOUT2_CFLAGS="-I$prefix/include"
+    SHOUT2_LIBS="-L$prefix/lib"
+  fi
+
+  SHOUT2_LIBS="$SHOUT2_LIBS -lshout -lpthread"
+
+  case $host in
+  *-*-solaris*)
+  	SHOUT2_LIBS="$SHOUT2_LIBS -lnsl -lsocket -lresolv"
+  esac
+
+  AC_MSG_CHECKING(for shout2)
+  no_shout2=""
+
+  if test "x$enable_shout2test" = "xyes" ; then
+    ac_save_CFLAGS="$CFLAGS"
+    ac_save_LIBS="$LIBS"
+    CFLAGS="$CFLAGS $SHOUT2_CFLAGS $OGG_CFLAGS $VORBIS_CFLAGS"
+    LIBS="$LIBS $SHOUT2_LIBS $OGG_LIBS $VORBIS_LIBS"
+dnl
+dnl Now check if the installed shout2 is sufficiently new.
+dnl
+      rm -f conf.shout2test
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <shout/shout.h>
+
+int main ()
+{
+  int major, minor, patch;
+
+  system("touch conf.shout2test");
+  shout_version(&major, &minor, &patch);
+  if (major < 2)
+    return 1;
+  return 0;
+}
+
+],, no_shout2=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+  fi
+
+  if test "x$no_shout2" = "x" ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$1], , :, [$1])     
+  else
+     AC_MSG_RESULT(no)
+     if test -f conf.shout2test ; then
+       :
+     else
+       echo "*** Could not run Shout2 test program, checking why..."
+       CFLAGS="$CFLAGS $SHOUT2_CFLAGS $OGG_CFLAGS $VORBIS_CFLAGS"
+       LIBS="$LIBS $SHOUT2_LIBS $OGG_LIBS $VORBIS_LIBS"
+       AC_TRY_LINK([
+#include <stdio.h>
+#include <shout/shout.h>
+],     [ return 0; ],
+       [ echo "*** The test program compiled, but did not run. This usually means"
+       echo "*** that the run-time linker is not finding Shout2 or finding the wrong"
+       echo "*** version of Shout2. If it is not finding Shout2, you'll need to set your"
+       echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+       echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+       echo "*** is required on your system"
+       echo "***"
+       echo "*** If you have an old version installed, it is best to remove it, although"
+       echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+       [ echo "*** The test program failed to compile or link. See the file config.log for the"
+       echo "*** exact error that occured. This usually means Shout2 was incorrectly installed"
+       echo "*** or that you have moved Shout2 since it was installed. In the latter case, you"
+       echo "*** may want to edit the shout-config script: $SHOUT2_CONFIG" ])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+     SHOUT2_CFLAGS=""
+     SHOUT2_LIBS=""
+     ifelse([$2], , :, [$2])
+  fi
+  AC_SUBST(SHOUT2_CFLAGS)
+  AC_SUBST(SHOUT2_LIBS)
+  rm -f conf.shout2test
+])
diff --git a/m4/gst-sid.m4 b/m4/gst-sid.m4
new file mode 100644
index 0000000..8ae2877
--- /dev/null
+++ b/m4/gst-sid.m4
@@ -0,0 +1,39 @@
+dnl check for sidplay
+
+AC_DEFUN([GST_PATH_SIDPLAY],
+[
+AC_MSG_CHECKING([for libsidplay 1.36.x])
+
+AC_LANG_PUSH(C++)
+
+AC_CHECK_HEADER(sidplay/player.h, HAVE_SIDPLAY="yes", HAVE_SIDPLAY="no")
+
+if test $HAVE_SIDPLAY = "yes"; then
+  SIDPLAY_LIBS="-lsidplay"
+
+  AC_MSG_CHECKING([whether -lsidplay works])
+  ac_libs_safe=$LIBS
+
+  LIBS="-lsidplay"
+
+  AC_TRY_RUN([
+    #include <sidplay/player.h>
+    int main()
+    { sidTune tune = sidTune(0);  }
+    ],
+    HAVE_SIDPLAY="yes",
+    HAVE_SIDPLAY="no",
+    HAVE_SIDPLAY="no")
+
+  LIBS="$ac_libs_safe"
+
+  AC_MSG_RESULT([$HAVE_SIDPLAY])
+fi
+
+SIDPLAY_CFLAGS=
+SIDPLAY_LIBS="-lsidplay"
+AC_SUBST(SIDPLAY_CFLAGS)
+AC_SUBST(SIDPLAY_LIBS)
+
+AC_LANG_POP(C++)
+])
diff --git a/m4/gtk.m4 b/m4/gtk.m4
new file mode 100644
index 0000000..f2dd472
--- /dev/null
+++ b/m4/gtk.m4
@@ -0,0 +1,194 @@
+# Configure paths for GTK+
+# Owen Taylor     97-11-3
+
+dnl AM_PATH_GTK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]])
+dnl Test for GTK, and define GTK_CFLAGS and GTK_LIBS
+dnl
+AC_DEFUN([AM_PATH_GTK],
+[dnl 
+dnl Get the cflags and libraries from the gtk-config script
+dnl
+AC_ARG_WITH(gtk-prefix,[  --with-gtk-prefix=PFX   Prefix where GTK is installed (optional)],
+            gtk_config_prefix="$withval", gtk_config_prefix="")
+AC_ARG_WITH(gtk-exec-prefix,[  --with-gtk-exec-prefix=PFX Exec prefix where GTK is installed (optional)],
+            gtk_config_exec_prefix="$withval", gtk_config_exec_prefix="")
+AC_ARG_ENABLE(gtktest, [  --disable-gtktest       Do not try to compile and run a test GTK program],
+		    , enable_gtktest=yes)
+
+  for module in . $4
+  do
+      case "$module" in
+         gthread) 
+             gtk_config_args="$gtk_config_args gthread"
+         ;;
+      esac
+  done
+
+  if test x$gtk_config_exec_prefix != x ; then
+     gtk_config_args="$gtk_config_args --exec-prefix=$gtk_config_exec_prefix"
+     if test x${GTK_CONFIG+set} != xset ; then
+        GTK_CONFIG=$gtk_config_exec_prefix/bin/gtk-config
+     fi
+  fi
+  if test x$gtk_config_prefix != x ; then
+     gtk_config_args="$gtk_config_args --prefix=$gtk_config_prefix"
+     if test x${GTK_CONFIG+set} != xset ; then
+        GTK_CONFIG=$gtk_config_prefix/bin/gtk-config
+     fi
+  fi
+
+  AC_PATH_PROG(GTK_CONFIG, gtk-config, no)
+  min_gtk_version=ifelse([$1], ,0.99.7,$1)
+  AC_MSG_CHECKING(for GTK - version >= $min_gtk_version)
+  no_gtk=""
+  if test "$GTK_CONFIG" = "no" ; then
+    no_gtk=yes
+  else
+    GTK_CFLAGS=`$GTK_CONFIG $gtk_config_args --cflags`
+    GTK_LIBS=`$GTK_CONFIG $gtk_config_args --libs`
+    gtk_config_major_version=`$GTK_CONFIG $gtk_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    gtk_config_minor_version=`$GTK_CONFIG $gtk_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    gtk_config_micro_version=`$GTK_CONFIG $gtk_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+    if test "x$enable_gtktest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $GTK_CFLAGS"
+      LIBS="$GTK_LIBS $LIBS"
+dnl
+dnl Now check if the installed GTK is sufficiently new. (Also sanity
+dnl checks the results of gtk-config to some extent
+dnl
+      rm -f conf.gtktest
+      AC_TRY_RUN([
+#include <gtk/gtk.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int 
+main ()
+{
+  int major, minor, micro;
+  char *tmp_version;
+
+  system ("touch conf.gtktest");
+
+  /* HP/UX 9 (%@#!) writes to sscanf strings */
+  tmp_version = g_strdup("$min_gtk_version");
+  if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+     printf("%s, bad version string\n", "$min_gtk_version");
+     exit(1);
+   }
+
+  if ((gtk_major_version != $gtk_config_major_version) ||
+      (gtk_minor_version != $gtk_config_minor_version) ||
+      (gtk_micro_version != $gtk_config_micro_version))
+    {
+      printf("\n*** 'gtk-config --version' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", 
+             $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version,
+             gtk_major_version, gtk_minor_version, gtk_micro_version);
+      printf ("*** was found! If gtk-config was correct, then it is best\n");
+      printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n");
+      printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n");
+      printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n");
+      printf("*** required on your system.\n");
+      printf("*** If gtk-config was wrong, set the environment variable GTK_CONFIG\n");
+      printf("*** to point to the correct copy of gtk-config, and remove the file config.cache\n");
+      printf("*** before re-running configure\n");
+    } 
+#if defined (GTK_MAJOR_VERSION) && defined (GTK_MINOR_VERSION) && defined (GTK_MICRO_VERSION)
+  else if ((gtk_major_version != GTK_MAJOR_VERSION) ||
+	   (gtk_minor_version != GTK_MINOR_VERSION) ||
+           (gtk_micro_version != GTK_MICRO_VERSION))
+    {
+      printf("*** GTK+ header files (version %d.%d.%d) do not match\n",
+	     GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
+      printf("*** library (version %d.%d.%d)\n",
+	     gtk_major_version, gtk_minor_version, gtk_micro_version);
+    }
+#endif /* defined (GTK_MAJOR_VERSION) ... */
+  else
+    {
+      if ((gtk_major_version > major) ||
+        ((gtk_major_version == major) && (gtk_minor_version > minor)) ||
+        ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro)))
+      {
+        return 0;
+       }
+     else
+      {
+        printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n",
+               gtk_major_version, gtk_minor_version, gtk_micro_version);
+        printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n",
+	       major, minor, micro);
+        printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n");
+        printf("***\n");
+        printf("*** If you have already installed a sufficiently new version, this error\n");
+        printf("*** probably means that the wrong copy of the gtk-config shell script is\n");
+        printf("*** being found. The easiest way to fix this is to remove the old version\n");
+        printf("*** of GTK+, but you can also set the GTK_CONFIG environment to point to the\n");
+        printf("*** correct copy of gtk-config. (In this case, you will have to\n");
+        printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+        printf("*** so that the correct libraries are found at run-time))\n");
+      }
+    }
+  return 1;
+}
+],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+  fi
+  if test "x$no_gtk" = x ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$2], , :, [$2])     
+  else
+     AC_MSG_RESULT(no)
+     if test "$GTK_CONFIG" = "no" ; then
+       echo "*** The gtk-config script installed by GTK could not be found"
+       echo "*** If GTK was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the GTK_CONFIG environment variable to the"
+       echo "*** full path to gtk-config."
+     else
+       if test -f conf.gtktest ; then
+        :
+       else
+          echo "*** Could not run GTK test program, checking why..."
+          CFLAGS="$CFLAGS $GTK_CFLAGS"
+          LIBS="$LIBS $GTK_LIBS"
+          AC_TRY_LINK([
+#include <gtk/gtk.h>
+#include <stdio.h>
+],      [ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ],
+        [ echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding GTK or finding the wrong"
+          echo "*** version of GTK. If it is not finding GTK, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+	  echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+          echo "***"
+          echo "*** If you have a RedHat 5.0 system, you should remove the GTK package that"
+          echo "*** came with the system with the command"
+          echo "***"
+          echo "***    rpm --erase --nodeps gtk gtk-devel" ],
+        [ echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means GTK was incorrectly installed"
+          echo "*** or that you have moved GTK since it was installed. In the latter case, you"
+          echo "*** may want to edit the gtk-config script: $GTK_CONFIG" ])
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+     fi
+     GTK_CFLAGS=""
+     GTK_LIBS=""
+     ifelse([$3], , :, [$3])
+  fi
+  AC_SUBST(GTK_CFLAGS)
+  AC_SUBST(GTK_LIBS)
+  rm -f conf.gtktest
+])
diff --git a/m4/libfame.m4 b/m4/libfame.m4
new file mode 100644
index 0000000..b570584
--- /dev/null
+++ b/m4/libfame.m4
@@ -0,0 +1,182 @@
+dnl AM_PATH_LIBFAME([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]])
+dnl Test for libfame, and define LIBFAME_CFLAGS and LIBFAME_LIBS
+dnl Vivien Chappelier 12/11/00
+dnl stolen from ORBit autoconf
+dnl
+AC_DEFUN([AM_PATH_LIBFAME],
+[dnl 
+dnl Get the cflags and libraries from the libfame-config script
+dnl
+AC_ARG_WITH(libfame-prefix,[  --with-libfame-prefix=PFX   Prefix where libfame is installed (optional)],
+            libfame_config_prefix="$withval", libfame_config_prefix="")
+AC_ARG_WITH(libfame-exec-prefix,[  --with-libfame-exec-prefix=PFX Exec prefix where libfame is installed (optional)],
+            libfame_config_exec_prefix="$withval", libfame_config_exec_prefix="")
+AC_ARG_ENABLE(libfametest, [  --disable-libfametest       Do not try to compile and run a test libfame program],
+		    , enable_libfametest=yes)
+
+  if test x$libfame_config_exec_prefix != x ; then
+     libfame_config_args="$libfame_config_args --exec-prefix=$libfame_config_exec_prefix"
+     if test x${LIBFAME_CONFIG+set} != xset ; then
+        LIBFAME_CONFIG=$libfame_config_exec_prefix/bin/libfame-config
+     fi
+  fi
+  if test x$libfame_config_prefix != x ; then
+     libfame_config_args="$libfame_config_args --prefix=$libfame_config_prefix"
+     if test x${LIBFAME_CONFIG+set} != xset ; then
+        LIBFAME_CONFIG=$libfame_config_prefix/bin/libfame-config
+     fi
+  fi
+
+  AC_PATH_PROG(LIBFAME_CONFIG, libfame-config, no)
+  min_libfame_version=ifelse([$1], , 0.9.0, $1)
+  AC_MSG_CHECKING(for libfame - version >= $min_libfame_version)
+  no_libfame=""
+  if test "$LIBFAME_CONFIG" = "no" ; then
+    no_libfame=yes
+  else
+    LIBFAME_CFLAGS=`$LIBFAME_CONFIG $libfame_config_args --cflags`
+    LIBFAME_LIBS=`$LIBFAME_CONFIG $libfame_config_args --libs`
+    libfame_config_major_version=`$LIBFAME_CONFIG $libfame_config_args --version | \
+	   sed -e 's,[[^0-9.]],,g' -e 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    libfame_config_minor_version=`$LIBFAME_CONFIG $libfame_config_args --version | \
+	   sed -e 's,[[^0-9.]],,g' -e 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    libfame_config_micro_version=`$LIBFAME_CONFIG $libfame_config_args --version | \
+	   sed -e 's,[[^0-9.]],,g' -e 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+    if test "x$enable_libfametest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $LIBFAME_CFLAGS"
+      LIBS="$LIBFAME_LIBS $LIBS"
+dnl
+dnl Now check if the installed LIBFAME is sufficiently new. (Also sanity
+dnl checks the results of libfame-config to some extent
+dnl
+      rm -f conf.libfametest
+      AC_TRY_RUN([
+#include <fame.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int 
+main ()
+{
+  int major, minor, micro;
+  char *tmp_version;
+
+  system ("touch conf.libfametest");
+
+  /* HP/UX 9 (%@#!) writes to sscanf strings */
+  tmp_version = strdup("$min_libfame_version");
+  if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+     printf("%s, bad version string\n", "$min_libfame_version");
+     exit(1);
+   }
+
+  if ((libfame_major_version != $libfame_config_major_version) ||
+      (libfame_minor_version != $libfame_config_minor_version) ||
+      (libfame_micro_version != $libfame_config_micro_version))
+    {
+      printf("\n*** 'libfame-config --version' returned %d.%d.%d, but Libfame (%d.%d.%d)\n", 
+             $libfame_config_major_version, $libfame_config_minor_version, $libfame_config_micro_version,
+             libfame_major_version, libfame_minor_version, libfame_micro_version);
+      printf ("*** was found! If libfame-config was correct, then it is best\n");
+      printf ("*** to remove the old version of libfame. You may also be able to fix the error\n");
+      printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n");
+      printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n");
+      printf("*** required on your system.\n");
+      printf("*** If libfame-config was wrong, set the environment variable LIBFAME_CONFIG\n");
+      printf("*** to point to the correct copy of libfame-config, and remove the file config.cache\n");
+      printf("*** before re-running configure\n");
+    } 
+#if defined (LIBFAME_MAJOR_VERSION) && defined (LIBFAME_MINOR_VERSION) && defined (LIBFAME_MICRO_VERSION)
+  else if ((libfame_major_version != LIBFAME_MAJOR_VERSION) ||
+	   (libfame_minor_version != LIBFAME_MINOR_VERSION) ||
+           (libfame_micro_version != LIBFAME_MICRO_VERSION))
+    {
+      printf("*** libfame header files (version %d.%d.%d) do not match\n",
+	     LIBFAME_MAJOR_VERSION, LIBFAME_MINOR_VERSION, LIBFAME_MICRO_VERSION);
+      printf("*** library (version %d.%d.%d)\n",
+	     libfame_major_version, libfame_minor_version, libfame_micro_version);
+    }
+#endif /* defined (LIBFAME_MAJOR_VERSION) ... */
+  else
+    {
+      if ((libfame_major_version > major) ||
+        ((libfame_major_version == major) && (libfame_minor_version > minor)) ||
+        ((libfame_major_version == major) && (libfame_minor_version == minor) && (libfame_micro_version >= micro)))
+      {
+        return 0;
+       }
+     else
+      {
+        printf("\n*** An old version of libfame (%d.%d.%d) was found.\n",
+               libfame_major_version, libfame_minor_version, libfame_micro_version);
+        printf("*** You need a version of libfame newer than %d.%d.%d. The latest version of\n",
+	       major, minor, micro);
+        printf("*** libfame is always available from http://www-eleves.enst-bretagne.fr/~chappeli/fame\n");
+        printf("***\n");
+        printf("*** If you have already installed a sufficiently new version, this error\n");
+        printf("*** probably means that the wrong copy of the libfame-config shell script is\n");
+        printf("*** being found. The easiest way to fix this is to remove the old version\n");
+        printf("*** of libfame, but you can also set the LIBFAME_CONFIG environment to point to the\n");
+        printf("*** correct copy of libfame-config. (In this case, you will have to\n");
+        printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+        printf("*** so that the correct libraries are found at run-time))\n");
+      }
+    }
+  return 1;
+}
+],, no_libfame=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+  fi
+  if test "x$no_libfame" = x ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$2], , :, [$2])     
+  else
+     AC_MSG_RESULT(no)
+     if test "$LIBFAME_CONFIG" = "no" ; then
+       echo "*** The libfame-config script installed by libfame could not be found"
+       echo "*** If libfame was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the LIBFAME_CONFIG environment variable to the"
+       echo "*** full path to libfame-config."
+     else
+       if test -f conf.libfametest ; then
+        :
+       else
+          echo "*** Could not run libfame test program, checking why..."
+          CFLAGS="$CFLAGS $LIBFAME_CFLAGS"
+          LIBS="$LIBS $LIBFAME_LIBS"
+          AC_TRY_LINK([
+#include <fame.h>
+#include <stdio.h>
+],      [ return ((libfame_major_version) || (libfame_minor_version) || (libfame_micro_version)); ],
+        [ echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding libfame or finding the wrong"
+          echo "*** version of LIBFAME. If it is not finding libfame, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+	  echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+          echo "***" ],
+        [ echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means libfame was incorrectly installed"
+          echo "*** or that you have moved libfame since it was installed. In the latter case, you"
+          echo "*** may want to edit the libfame-config script: $LIBFAME_CONFIG" ])
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+     fi
+     LIBFAME_CFLAGS=""
+     LIBFAME_LIBS=""
+     ifelse([$3], , :, [$3])
+  fi
+
+  AC_SUBST(LIBFAME_CFLAGS)
+  AC_SUBST(LIBFAME_LIBS)
+  rm -f conf.libfametest
+])
diff --git a/m4/ogg.m4 b/m4/ogg.m4
new file mode 100644
index 0000000..0e1f1ab
--- /dev/null
+++ b/m4/ogg.m4
@@ -0,0 +1,102 @@
+# Configure paths for libogg
+# Jack Moffitt <jack@icecast.org> 10-21-2000
+# Shamelessly stolen from Owen Taylor and Manish Singh
+
+dnl XIPH_PATH_OGG([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libogg, and define OGG_CFLAGS and OGG_LIBS
+dnl
+AC_DEFUN([XIPH_PATH_OGG],
+[dnl 
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(ogg,[  --with-ogg=PFX   Prefix where libogg is installed (optional)], ogg_prefix="$withval", ogg_prefix="")
+AC_ARG_WITH(ogg-libraries,[  --with-ogg-libraries=DIR   Directory where libogg library is installed (optional)], ogg_libraries="$withval", ogg_libraries="")
+AC_ARG_WITH(ogg-includes,[  --with-ogg-includes=DIR   Directory where libogg header files are installed (optional)], ogg_includes="$withval", ogg_includes="")
+AC_ARG_ENABLE(oggtest, [  --disable-oggtest       Do not try to compile and run a test Ogg program],, enable_oggtest=yes)
+
+  if test "x$ogg_libraries" != "x" ; then
+    OGG_LIBS="-L$ogg_libraries"
+  elif test "x$ogg_prefix" != "x" ; then
+    OGG_LIBS="-L$ogg_prefix/lib"
+  elif test "x$prefix" != "xNONE" ; then
+    OGG_LIBS="-L$prefix/lib"
+  fi
+
+  OGG_LIBS="$OGG_LIBS -logg"
+
+  if test "x$ogg_includes" != "x" ; then
+    OGG_CFLAGS="-I$ogg_includes"
+  elif test "x$ogg_prefix" != "x" ; then
+    OGG_CFLAGS="-I$ogg_prefix/include"
+  elif test "x$prefix" != "xNONE"; then
+    OGG_CFLAGS="-I$prefix/include"
+  fi
+
+  AC_MSG_CHECKING(for Ogg)
+  no_ogg=""
+
+
+  if test "x$enable_oggtest" = "xyes" ; then
+    ac_save_CFLAGS="$CFLAGS"
+    ac_save_LIBS="$LIBS"
+    CFLAGS="$CFLAGS $OGG_CFLAGS"
+    LIBS="$LIBS $OGG_LIBS"
+dnl
+dnl Now check if the installed Ogg is sufficiently new.
+dnl
+      rm -f conf.oggtest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ogg/ogg.h>
+
+int main ()
+{
+  system("touch conf.oggtest");
+  return 0;
+}
+
+],, no_ogg=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+  fi
+
+  if test "x$no_ogg" = "x" ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$1], , :, [$1])     
+  else
+     AC_MSG_RESULT(no)
+     if test -f conf.oggtest ; then
+       :
+     else
+       echo "*** Could not run Ogg test program, checking why..."
+       CFLAGS="$CFLAGS $OGG_CFLAGS"
+       LIBS="$LIBS $OGG_LIBS"
+       AC_TRY_LINK([
+#include <stdio.h>
+#include <ogg/ogg.h>
+],     [ return 0; ],
+       [ echo "*** The test program compiled, but did not run. This usually means"
+       echo "*** that the run-time linker is not finding Ogg or finding the wrong"
+       echo "*** version of Ogg. If it is not finding Ogg, you'll need to set your"
+       echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+       echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+       echo "*** is required on your system"
+       echo "***"
+       echo "*** If you have an old version installed, it is best to remove it, although"
+       echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+       [ echo "*** The test program failed to compile or link. See the file config.log for the"
+       echo "*** exact error that occured. This usually means Ogg was incorrectly installed"
+       echo "*** or that you have moved Ogg since it was installed." ])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+     OGG_CFLAGS=""
+     OGG_LIBS=""
+     ifelse([$2], , :, [$2])
+  fi
+  AC_SUBST(OGG_CFLAGS)
+  AC_SUBST(OGG_LIBS)
+  rm -f conf.oggtest
+])
diff --git a/m4/vorbis.m4 b/m4/vorbis.m4
new file mode 100644
index 0000000..6a28893
--- /dev/null
+++ b/m4/vorbis.m4
@@ -0,0 +1,128 @@
+# Configure paths for libvorbis
+# Jack Moffitt <jack@icecast.org> 10-21-2000
+# Shamelessly stolen from Owen Taylor and Manish Singh
+# thomasvs added check for vorbis_bitrate_addblock which is new in rc3
+# thomasvs added check for OV_ECTL_RATEMANAGE_SET which is new in 1.0 final
+
+dnl XIPH_PATH_VORBIS([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libvorbis, and define VORBIS_CFLAGS and VORBIS_LIBS
+dnl
+AC_DEFUN([XIPH_PATH_VORBIS],
+[dnl 
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(vorbis,[  --with-vorbis=PFX   Prefix where libvorbis is installed (optional)], vorbis_prefix="$withval", vorbis_prefix="")
+AC_ARG_WITH(vorbis-libraries,[  --with-vorbis-libraries=DIR   Directory where libvorbis library is installed (optional)], vorbis_libraries="$withval", vorbis_libraries="")
+AC_ARG_WITH(vorbis-includes,[  --with-vorbis-includes=DIR   Directory where libvorbis header files are installed (optional)], vorbis_includes="$withval", vorbis_includes="")
+AC_ARG_ENABLE(vorbistest, [  --disable-vorbistest       Do not try to compile and run a test Vorbis program],, enable_vorbistest=yes)
+
+  if test "x$vorbis_libraries" != "x" ; then
+    VORBIS_LIBS="-L$vorbis_libraries"
+  elif test "x$vorbis_prefix" != "x" ; then
+    VORBIS_LIBS="-L$vorbis_prefix/lib"
+  elif test "x$prefix" != "xNONE"; then
+    VORBIS_LIBS="-L$prefix/lib"
+  fi
+
+  VORBIS_LIBS="$VORBIS_LIBS -lvorbis -lm"
+  VORBISFILE_LIBS="-lvorbisfile"
+  VORBISENC_LIBS="-lvorbisenc"
+
+  if test "x$vorbis_includes" != "x" ; then
+    VORBIS_CFLAGS="-I$vorbis_includes"
+  elif test "x$vorbis_prefix" != "x" ; then
+    VORBIS_CFLAGS="-I$vorbis_prefix/include"
+  elif test "x$prefix" != "xNONE"; then
+    VORBIS_CFLAGS="-I$prefix/include"
+  fi
+
+
+  AC_MSG_CHECKING(for Vorbis)
+  no_vorbis=""
+
+
+  if test "x$enable_vorbistest" = "xyes" ; then
+    ac_save_CFLAGS="$CFLAGS"
+    ac_save_LIBS="$LIBS"
+    CFLAGS="$CFLAGS $VORBIS_CFLAGS $OGG_CFLAGS"
+    LIBS="$LIBS $VORBIS_LIBS $VORBISENC_LIBS $OGG_LIBS"
+dnl
+dnl Now check if the installed Vorbis is sufficiently new.
+dnl
+      rm -f conf.vorbistest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vorbis/codec.h>
+#include <vorbis/vorbisenc.h>
+
+int main ()
+{
+    vorbis_block 	vb;
+    vorbis_dsp_state	vd;
+    vorbis_info		vi;
+
+    vorbis_info_init (&vi);
+    vorbis_encode_init (&vi, 2, 44100, -1, 128000, -1);
+    vorbis_analysis_init (&vd, &vi);
+    vorbis_block_init (&vd, &vb);
+    /* this function was added in 1.0rc3, so this is what we're testing for */
+    vorbis_bitrate_addblock (&vb);
+
+    /* this define was added in 1.0 final */
+#ifdef OV_ECTL_RATEMANAGE_SET
+    system("touch conf.vorbistest");
+    return 0;
+#else
+    return -1;
+#endif
+}
+
+],, no_vorbis=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+  fi
+
+  if test "x$no_vorbis" = "x" ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$1], , :, [$1])     
+  else
+     AC_MSG_RESULT(no)
+     if test -f conf.vorbistest ; then
+       :
+     else
+       echo "*** Could not run Vorbis test program, checking why..."
+       CFLAGS="$CFLAGS $VORBIS_CFLAGS"
+       LIBS="$LIBS $VORBIS_LIBS $OGG_LIBS"
+       AC_TRY_LINK([
+#include <stdio.h>
+#include <vorbis/codec.h>
+],     [ return 0; ],
+       [ echo "*** The test program compiled, but did not run. This usually means"
+       echo "*** that the run-time linker is not finding Vorbis or finding the wrong"
+       echo "*** version of Vorbis. If it is not finding Vorbis, you'll need to set your"
+       echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+       echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+       echo "*** is required on your system"
+       echo "***"
+       echo "*** If you have an old version installed, it is best to remove it, although"
+       echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+       [ echo "*** The test program failed to compile or link. See the file config.log for the"
+       echo "*** exact error that occured. This usually means Vorbis was incorrectly installed"
+       echo "*** or that you have moved Vorbis since it was installed." ])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+     VORBIS_CFLAGS=""
+     VORBIS_LIBS=""
+     VORBISFILE_LIBS=""
+     VORBISENC_LIBS=""
+     ifelse([$2], , :, [$2])
+  fi
+  AC_SUBST(VORBIS_CFLAGS)
+  AC_SUBST(VORBIS_LIBS)
+  AC_SUBST(VORBISFILE_LIBS)
+  AC_SUBST(VORBISENC_LIBS)
+  rm -f conf.vorbistest
+])
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..d4f05aa
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,296 @@
+project('gst-plugins-good', 'c',
+  version : '1.13.0.1',
+  meson_version : '>= 0.36.0',
+  default_options : [ 'warning_level=1',
+                      'buildtype=debugoptimized' ])
+
+gst_version = meson.project_version()
+version_arr = gst_version.split('.')
+gst_version_major = version_arr[0].to_int()
+gst_version_minor = version_arr[1].to_int()
+gst_version_micro = version_arr[2].to_int()
+ if version_arr.length() == 4
+  gst_version_nano = version_arr[3].to_int()
+else
+  gst_version_nano = 0
+endif
+
+glib_req = '>= 2.40.0'
+gst_req = '>= @0@.@1@.0'.format(gst_version_major, gst_version_minor)
+
+api_version = '1.0'
+
+plugins_install_dir = '@0@/gstreamer-1.0'.format(get_option('libdir'))
+
+cc = meson.get_compiler('c')
+
+if cc.get_id() == 'msvc'
+  # Ignore several spurious warnings for things gstreamer does very commonly
+  # If a warning is completely useless and spammy, use '/wdXXXX' to suppress it
+  # If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once
+  # NOTE: Only add warnings here if you are sure they're spurious
+  add_project_arguments(
+      '/wd4018', # implicit signed/unsigned conversion
+      '/wd4146', # unary minus on unsigned (beware INT_MIN)
+      '/wd4244', # lossy type conversion (e.g. double -> int)
+      '/wd4305', # truncating type conversion (e.g. double -> float)
+      language : 'c')
+  # Disable SAFESEH with MSVC for plugins and libs that use external deps that
+  # are built with MinGW
+  noseh_link_args = ['/SAFESEH:NO']
+else
+  noseh_link_args = []
+endif
+
+# Symbol visibility
+if cc.has_argument('-fvisibility=hidden')
+  add_project_arguments('-fvisibility=hidden', language: 'c')
+endif
+
+# Disable strict aliasing
+if cc.has_argument('-fno-strict-aliasing')
+  add_project_arguments('-fno-strict-aliasing', language: 'c')
+endif
+
+cdata = configuration_data()
+
+check_headers = [
+  ['HAVE_DLFCN_H', 'dlfcn.h'],
+  ['HAVE_FCNTL_H', 'fcntl.h'],
+  ['HAVE_INTTYPES_H', 'inttypes.h'],
+  ['HAVE_MEMORY_H', 'memory.h'],
+  ['HAVE_PROCESS_H', 'process.h'],
+  ['HAVE_STDINT_H', 'stdint.h'],
+  ['HAVE_STDLIB_H', 'stdlib.h'],
+  ['HAVE_STRINGS_H', 'strings.h'],
+  ['HAVE_STRING_H', 'string.h'],
+  ['HAVE_SYS_IOCTL_H', 'sys/ioctl.h'],
+  ['HAVE_SYS_PARAM_H', 'sys/param.h'],
+  ['HAVE_SYS_SOCKET_H', 'sys/socket.h'],
+  ['HAVE_SYS_STAT_H', 'sys/stat.h'],
+  ['HAVE_SYS_TIME_H', 'sys/time.h'],
+  ['HAVE_SYS_TYPES_H', 'sys/types.h'],
+  ['HAVE_UNISTD_H', 'unistd.h'],
+]
+
+foreach h : check_headers
+  if cc.has_header(h.get(1))
+    cdata.set(h.get(0), 1)
+  endif
+endforeach
+
+check_functions = [
+  ['HAVE_ASINH', 'asinh', '#include<math.h>'],
+  ['HAVE_CLOCK_GETTIME', 'clock_gettime', '#include<time.h>'],
+  ['HAVE_COSH', 'cosh', '#include<math.h>'],
+# check token HAVE_CPU_ALPHA
+# check token HAVE_CPU_ARM
+# check token HAVE_CPU_CRIS
+# check token HAVE_CPU_CRISV32
+# check token HAVE_CPU_HPPA
+# check token HAVE_CPU_I386
+# check token HAVE_CPU_IA64
+# check token HAVE_CPU_M68K
+# check token HAVE_CPU_MIPS
+# check token HAVE_CPU_PPC
+# check token HAVE_CPU_PPC64
+# check token HAVE_CPU_S390
+# check token HAVE_CPU_SPARC
+# check token HAVE_CPU_X86_64
+  ['HAVE_DCGETTEXT', 'dcgettext', '#include<libintl.h>'],
+# check token HAVE_DIRECTSOUND
+# check token HAVE_EXPERIMENTAL
+# check token HAVE_EXTERNAL
+# check token HAVE_FPCLASS
+# check token HAVE_GCC_ASM
+  ['HAVE_GETPAGESIZE', 'getpagesize', '#include<unistd.h>'],
+# check token HAVE_GETTEXT
+# check token HAVE_GST_V4L2
+# check token HAVE_IOS
+  ['HAVE_ISINF', 'isinf', '#include<math.h>'],
+# check token HAVE_LIBV4L2
+  ['HAVE_MMAP', 'mmap', '#include<sys/mman.h>'],
+  ['HAVE_MMAP64', 'mmap64', '#include<sys/mman.h>'],
+# check token HAVE_OSX_AUDIO
+# check token HAVE_OSX_VIDEO
+# check token HAVE_RDTSC
+  ['HAVE_SINH', 'sinh', '#include<math.h>'],
+# check token HAVE_WAVEFORM
+]
+
+libm = cc.find_library('m', required : false)
+
+foreach f : check_functions
+  if cc.has_function(f.get(1), prefix : f.get(2), dependencies : libm)
+    cdata.set(f.get(0), 1)
+  endif
+endforeach
+
+cdata.set('SIZEOF_CHAR', cc.sizeof('char'))
+cdata.set('SIZEOF_INT', cc.sizeof('int'))
+cdata.set('SIZEOF_LONG', cc.sizeof('long'))
+cdata.set('SIZEOF_SHORT', cc.sizeof('short'))
+cdata.set('SIZEOF_VOIDP', cc.sizeof('void*'))
+cdata.set('SIZEOF_OFF_T', cc.sizeof('off_t'))
+
+# Here be fixmes.
+# FIXME: check if this is correct
+cdata.set('HAVE_CPU_X86_64', host_machine.cpu() == 'amd64')
+cdata.set('HAVE_GCC_ASM', cc.get_id() != 'msvc')
+cdata.set('VERSION', '"@0@"'.format(gst_version))
+cdata.set('PACKAGE_VERSION', '"@0@"'.format(gst_version))
+cdata.set('GST_LICENSE', '"LGPL"')
+cdata.set('PACKAGE', '"gst-plugins-good"')
+cdata.set('GETTEXT_PACKAGE', '"gst-plugins-good-1.0"')
+
+# GStreamer package name and origin url
+gst_package_name = get_option('with-package-name')
+if gst_package_name == ''
+  if gst_version_nano == 0
+    gst_package_name = 'GStreamer Good Plug-ins source release'
+  elif gst_version_nano == 1
+    gst_package_name = 'GStreamer Good Plug-ins git'
+  else
+    gst_package_name = 'GStreamer Good Plug-ins prerelease'
+  endif
+endif
+cdata.set_quoted('GST_PACKAGE_NAME', gst_package_name)
+cdata.set_quoted('GST_PACKAGE_ORIGIN', get_option('with-package-origin'))
+
+# Mandatory GST deps
+gst_dep = dependency('gstreamer-1.0', version : gst_req,
+  fallback : ['gstreamer', 'gst_dep'])
+gstbase_dep = dependency('gstreamer-base-1.0', version : gst_req,
+  fallback : ['gstreamer', 'gst_base_dep'])
+gstnet_dep = dependency('gstreamer-net-1.0', version : gst_req,
+  fallback : ['gstreamer', 'gst_net_dep'])
+if host_machine.system() != 'windows'
+  gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req,
+    fallback : ['gstreamer', 'gst_check_dep'])
+endif
+gstcontroller_dep = dependency('gstreamer-controller-1.0', version : gst_req,
+  fallback : ['gstreamer', 'gst_controller_dep'])
+
+gstpbutils_dep = dependency('gstreamer-pbutils-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'pbutils_dep'])
+gstallocators_dep = dependency('gstreamer-allocators-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'allocators_dep'])
+gstapp_dep = dependency('gstreamer-app-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'app_dep'])
+gstaudio_dep = dependency('gstreamer-audio-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'audio_dep'])
+gstfft_dep = dependency('gstreamer-fft-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'fft_dep'])
+gstriff_dep = dependency('gstreamer-riff-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'riff_dep'])
+gstrtp_dep = dependency('gstreamer-rtp-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'rtp_dep'])
+gstrtsp_dep = dependency('gstreamer-rtsp-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'rtsp_dep'])
+gstsdp_dep = dependency('gstreamer-sdp-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'sdp_dep'])
+gsttag_dep = dependency('gstreamer-tag-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'tag_dep'])
+gstvideo_dep = dependency('gstreamer-video-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'video_dep'])
+
+zlib_dep = dependency('zlib', required : false)
+bz2lib = cc.find_library('bz2', required : false)
+glib_deps = [dependency('glib-2.0', version : glib_req, fallback: ['glib', 'libglib_dep']),
+             dependency('gobject-2.0', fallback: ['glib', 'libgobject_dep'])]
+gio_dep = dependency('gio-2.0', fallback: ['glib', 'libgio_dep'])
+
+cdata.set('HAVE_ZLIB', zlib_dep.found())
+cdata.set('HAVE_BZ2', bz2lib.found())
+
+# Check all of the things.
+# TODO: None of these are actually used yet because
+# the build files haven't been written
+deps = [
+  ['gtk_dep','gtk+-3.0', '', ''],
+  ['gtkx_dep','gtk+-x11-3.0', '', ''],
+  ['caca_dep','caca', '', ''],
+  ['libraw1394_dep','libraw1394', '>=2.0.0', ''],
+  ['libiec61883_dep','libiec61883', '>=1.0.0', ''],
+]
+
+foreach d : deps
+  varname = d[0]
+  depname = d[1]
+  version = d[2]
+  confhname = d[3]
+  if version == ''
+    curdep = dependency(depname, required : false)
+  else
+    curdep = dependency(depname, required : false, version : version)
+  endif
+  set_variable(varname, curdep)
+  if curdep.found() and confhname != ''
+    cdata.set(confhname, 1)
+  endif
+endforeach
+
+gst_plugins_good_args = ['-DHAVE_CONFIG_H']
+configinc = include_directories('.')
+libsinc = include_directories('gst-libs')
+
+have_orcc = false
+orcc_args = []
+if get_option('use_orc') != 'no'
+  need_orc = get_option('use_orc') == 'yes'
+  # Used by various libraries/elements that use Orc code
+  orc_dep = dependency('orc-0.4', version : '>= 0.4.17', required : need_orc)
+  orcc = find_program('orcc', required : need_orc)
+  if orc_dep.found() and orcc.found()
+    have_orcc = true
+    orcc_args = [orcc, '--include', 'glib.h']
+    cdata.set('HAVE_ORC', 1)
+  else
+    message('Orc Compiler not found, will use backup C code')
+    cdata.set('DISABLE_ORC', 1)
+  endif
+else
+  cdata.set('DISABLE_ORC', 1)
+endif
+
+if gst_dep.type_name() == 'internal'
+    gst_proj = subproject('gstreamer')
+
+    if gst_proj.get_variable('disable_gst_debug')
+        message('GStreamer debug system is disabled')
+        add_project_arguments('-Wno-unused', language: 'c')
+    else
+        message('GStreamer debug system is enabled')
+    endif
+else
+    # We can't check that in the case of subprojects as we won't
+    # be able to build against an internal dependency (which is not built yet)
+    if not cc.compiles('''
+#include <gst/gstconfig.h>
+#ifdef GST_DISABLE_GST_DEBUG
+#error "debugging disabled, make compiler fail"
+#endif''' , dependencies: gst_dep)
+        message('GStreamer debug system is disabled')
+        add_project_arguments('-Wno-unused', language: 'c')
+    else
+        message('GStreamer debug system is enabled')
+    endif
+endif
+
+presetdir = join_paths(get_option('datadir'), 'gstreamer-' + api_version, 'presets')
+
+subdir('gst')
+subdir('sys')
+subdir('ext')
+subdir('tests')
+subdir('pkgconfig')
+
+# xgettext is optional (on Windows for instance)
+if find_program('xgettext', required : false).found()
+  subdir('po')
+endif
+
+configure_file(output : 'config.h', configuration : cdata)
+
+python3 = import('python3').find_python()
+run_command(python3, '-c', 'import shutil; shutil.copy("hooks/pre-commit.hook", ".git/hooks/pre-commit")')
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..dccf42e
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,10 @@
+# Enable V4L2 plugin to probe devices at plugin load
+option('v4l2-probe', type : 'boolean', value : true)
+# Use libv4l2 for some obscure format conversions
+option('with-libv4l2', type : 'boolean', value : true)
+# Whether to use orc or not (auto will autodetect, yes will error out if not found)
+option('use_orc', type : 'combo', choices : ['yes', 'no', 'auto'], value : 'auto')
+option('with-package-name', type : 'string',
+       description : 'package name to use in plugins')
+option('with-package-origin', type : 'string', value : 'Unknown package origin',
+       description : 'package origin URL to use in plugins')
diff --git a/pkgconfig/.gitignore b/pkgconfig/.gitignore
new file mode 100644
index 0000000..6fd0ef0
--- /dev/null
+++ b/pkgconfig/.gitignore
@@ -0,0 +1 @@
+*.pc
diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am
new file mode 100644
index 0000000..2d7917b
--- /dev/null
+++ b/pkgconfig/Makefile.am
@@ -0,0 +1,31 @@
+### all of the standard pc files we need to generate
+pcverfiles =  \
+	gstreamer-plugins-good-@GST_API_VERSION@.pc
+pcverfiles_uninstalled = \
+	gstreamer-plugins-good-@GST_API_VERSION@-uninstalled.pc
+
+### all-local: $(pcverfiles) $(pcverfiles_uninstalled)
+all-local: $(pcverfiles_uninstalled)
+
+cp_verbose = $(cp_verbose_$(V))
+cp_verbose_ = $(cp_verbose_$(AM_DEFAULT_VERBOSITY))
+cp_verbose_0 = @echo "  CP     $@";
+
+### how to generate versioned .pc files from .pc files in this dir
+%-@GST_API_VERSION@.pc: %.pc
+	$(cp_verbose)cp $< $@
+%-@GST_API_VERSION@-uninstalled.pc: %-uninstalled.pc
+	$(cp_verbose)cp $< $@
+
+# do not install for now
+# pkgconfigdir = $(libdir)/pkgconfig
+# pkgconfig_DATA = $(pcverfiles)
+
+CLEANFILES = $(pcverfiles) $(pcverfiles_uninstalled)
+# pcinfiles = \
+#           gstreamer-plugins-good.pc.in gstreamer-plugins-good-uninstalled.pc.in
+pcinfiles = \
+           gstreamer-plugins-good-uninstalled.pc.in
+
+DISTCLEANFILES = $(pcinfiles:.in=)
+EXTRA_DIST = $(pcinfiles)
diff --git a/pkgconfig/gstreamer-plugins-good-uninstalled.pc.in b/pkgconfig/gstreamer-plugins-good-uninstalled.pc.in
new file mode 100644
index 0000000..727a32b
--- /dev/null
+++ b/pkgconfig/gstreamer-plugins-good-uninstalled.pc.in
@@ -0,0 +1,13 @@
+prefix=
+exec_prefix=
+libdir=@abs_top_builddir@/gst-libs/gst
+includedir=@abs_top_builddir@/gst-libs
+pluginsdir=@abs_top_builddir@
+
+Name: GStreamer Good Plugins, Uninstalled
+Description: Streaming media framework, good plugins, uninstalled
+Version: @VERSION@
+Requires: gstreamer-@GST_API_VERSION@ gstreamer-plugins-base-@GST_API_VERSION@
+
+Libs: 
+Cflags: 
diff --git a/pkgconfig/meson.build b/pkgconfig/meson.build
new file mode 100644
index 0000000..b3bf0d4
--- /dev/null
+++ b/pkgconfig/meson.build
@@ -0,0 +1,24 @@
+pkgconf = configuration_data()
+
+pkgconf.set('prefix', get_option('prefix'))
+pkgconf.set('exec_prefix', '${prefix}')
+pkgconf.set('libdir', '${prefix}/@0@'.format(get_option('libdir')))
+pkgconf.set('includedir', '${prefix}/@0@'.format(get_option('includedir')))
+pkgconf.set('GST_API_VERSION', api_version)
+pkgconf.set('VERSION', gst_version)
+
+# needed for generating -uninstalled.pc files
+pkgconf.set('abs_top_builddir', join_paths(meson.current_build_dir(), '..'))
+pkgconf.set('abs_top_srcdir', join_paths(meson.current_source_dir(), '..'))
+
+pkg_install_dir = '@0@/pkgconfig'.format(get_option('libdir'))
+
+pkg_files = ['gstreamer-plugins-good']
+
+foreach p : pkg_files
+  infile = p + '-uninstalled.pc.in'
+  outfile = p + '-1.0-uninstalled.pc'
+  configure_file(input : infile,
+    output : outfile,
+    configuration : pkgconf)
+endforeach
diff --git a/po/.gitignore b/po/.gitignore
new file mode 100644
index 0000000..93d00be
--- /dev/null
+++ b/po/.gitignore
@@ -0,0 +1,17 @@
+*.gmo
+remove-potcdate.sed
+remove-potcdate.sin
+stamp-po
+POTFILES
+cat-id-tbl.c
+*.pot
+Makefile.in.in
+Makefile.in.in.orig
+Makevars.template
+Rules-quot
+boldquot.sed
+en@boldquot.header
+en@quot.header
+insert-header.sin
+quot.sed
+.pot
diff --git a/po/LINGUAS b/po/LINGUAS
new file mode 100644
index 0000000..b47eb4c
--- /dev/null
+++ b/po/LINGUAS
@@ -0,0 +1 @@
+af az bg ca cs da de el en_GB eo es eu fi fr fur gl hr hu id it ja lt lv mt nb nl or pl pt_BR ro ru sk sl sq sr sv tr uk vi zh_CN zh_HK zh_TW
diff --git a/po/Makevars b/po/Makevars
new file mode 100644
index 0000000..996fde3
--- /dev/null
+++ b/po/Makevars
@@ -0,0 +1,46 @@
+# Makefile variables for PO directory in any package using GNU gettext.
+
+# Usually the message domain is the same as the package name.
+DOMAIN = gst-plugins-good-1.0
+
+# These two variables depend on the location of this directory.
+subdir = po
+top_builddir = ..
+
+# These options get passed to xgettext.
+XGETTEXT_OPTIONS = --keyword=_ --keyword=N_
+
+# This is the copyright holder that gets inserted into the header of the
+# $(DOMAIN).pot file.  Set this to the copyright holder of the surrounding
+# package.  (Note that the msgstr strings, extracted from the package's
+# sources, belong to the copyright holder of the package.)  Translators are
+# expected to transfer the copyright for their translations to this person
+# or entity, or to disclaim their copyright.  The empty string stands for
+# the public domain; in this case the translators are expected to disclaim
+# their copyright.
+COPYRIGHT_HOLDER =
+
+# This is the email address or URL to which the translators shall report
+# bugs in the untranslated strings:
+# - Strings which are not entire sentences, see the maintainer guidelines
+#   in the GNU gettext documentation, section 'Preparing Strings'.
+# - Strings which use unclear terms or require additional context to be
+#   understood.
+# - Strings which make invalid assumptions about notation of date, time or
+#   money.
+# - Pluralisation problems.
+# - Incorrect English spelling.
+# - Incorrect formatting.
+# It can be your email address, or a mailing list address where translators
+# can write to without being subscribed, or the URL of a web page through
+# which the translators can contact you.
+MSGID_BUGS_ADDRESS = http://bugzilla.gnome.org/
+
+# This is the list of locale categories, beyond LC_MESSAGES, for which the
+# message catalogs shall be used.  It is usually empty.
+EXTRA_LOCALE_CATEGORIES =
+
+# Avoid line numbers in *.po, but keep them in *.pot.
+MSGMERGE = msgmerge --no-location
+MSGMERGE_UPDATE = msgmerge --no-location --update --backup=off
+MSGFILTER = msgfilter --no-location
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644
index 0000000..d99dfde
--- /dev/null
+++ b/po/POTFILES.in
@@ -0,0 +1,32 @@
+ext/flac/gstflacdec.c
+ext/jack/gstjackaudiosink.c
+ext/jack/gstjackaudiosrc.c
+ext/jpeg/gstjpegdec.c
+ext/lame/gstlamemp3enc.c
+ext/libpng/gstpngdec.c
+ext/pulse/pulsesink.c
+ext/shout2/gstshout2.c
+ext/soup/gstsouphttpsrc.c
+ext/twolame/gsttwolamemp2enc.c
+gst/audioparsers/gstwavpackparse.c
+gst/avi/gstavidemux.c
+gst/avi/gstavimux.c
+gst/isomp4/qtdemux.c
+gst/multifile/gstsplitmuxsrc.c
+gst/rtsp/gstrtspsrc.c
+gst/wavparse/gstwavparse.c
+sys/oss4/oss4-sink.c
+sys/oss4/oss4-source.c
+sys/oss/gstosssink.c
+sys/oss/gstosssrc.c
+sys/osxaudio/gstosxaudioringbuffer.c
+sys/v4l2/gstv4l2bufferpool.c
+sys/v4l2/gstv4l2object.c
+sys/v4l2/gstv4l2radio.c
+sys/v4l2/gstv4l2sink.c
+sys/v4l2/gstv4l2src.c
+sys/v4l2/gstv4l2transform.c
+sys/v4l2/gstv4l2videodec.c
+sys/v4l2/gstv4l2videoenc.c
+sys/v4l2/v4l2_calls.c
+sys/ximage/gstximagesrc.c
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
new file mode 100644
index 0000000..a7f30e5
--- /dev/null
+++ b/po/POTFILES.skip
@@ -0,0 +1,4 @@
+gst/goom/convolve_fx.c
+gst/goom/mmx.c
+gst/goom/xmmx.c
+gst/oldcore/gstmultifilesrc.c
diff --git a/po/af.po b/po/af.po
new file mode 100644
index 0000000..0f75652
--- /dev/null
+++ b/po/af.po
@@ -0,0 +1,621 @@
+# Translation of gstreamer plugin messages to Afrikaans. 
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# This file is put in the public domain.
+# Petri Jooste <rkwjpj@puk.ac.za>, 2004.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins 0.7.6\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2004-03-18 14:16+0200\n"
+"Last-Translator: Petri Jooste <rkwjpj@puk.ac.za>\n"
+"Language-Team: Afrikaans <i18n@af.org.za>\n"
+"Language: af\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr ""
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr ""
+
+#, fuzzy
+msgid "Could not connect to server"
+msgstr "Kon nie beheertoestel \"%s\" toemaak nie."
+
+msgid "No URL set."
+msgstr ""
+
+#, fuzzy
+msgid "Could not resolve server name."
+msgstr "Kon nie beheertoestel \"%s\" toemaak nie."
+
+#, fuzzy
+msgid "Could not establish connection to server."
+msgstr "Kon nie beheertoestel \"%s\" toemaak nie."
+
+msgid "Secure connection setup failed."
+msgstr ""
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+
+msgid "Server sent bad data."
+msgstr ""
+
+msgid "Server does not support seeking."
+msgstr ""
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Geen of ongeldige klanktoevoer, AVI-stroom sal korrup wees."
+
+msgid "This file contains no playable streams."
+msgstr ""
+
+msgid "This file is invalid and cannot be played."
+msgstr ""
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr ""
+
+msgid "Invalid atom size."
+msgstr ""
+
+msgid "This file is incomplete and cannot be played."
+msgstr ""
+
+msgid "The video in this file might not play correctly."
+msgstr ""
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+
+#, fuzzy
+msgid "Could not open audio device for playback."
+msgstr "Kon nie oudio-toestel \"%s\" oopmaak vir skryf nie."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+
+msgid "Playback is not supported by this audio device."
+msgstr ""
+
+msgid "Audio playback error."
+msgstr ""
+
+msgid "Recording is not supported by this audio device."
+msgstr ""
+
+msgid "Error recording from audio device."
+msgstr ""
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+
+#, fuzzy
+msgid "Could not open audio device for recording."
+msgstr "Kon nie CD-toestel oopmaak om te lees nie."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+#, fuzzy
+msgid "Record Source"
+msgstr "Neem op"
+
+msgid "Microphone"
+msgstr "Mikrofoon"
+
+#, fuzzy
+msgid "Line In"
+msgstr "Lyn-in"
+
+msgid "Internal CD"
+msgstr ""
+
+msgid "SPDIF In"
+msgstr ""
+
+msgid "AUX 1 In"
+msgstr ""
+
+msgid "AUX 2 In"
+msgstr ""
+
+msgid "Codec Loopback"
+msgstr ""
+
+msgid "SunVTS Loopback"
+msgstr ""
+
+msgid "Volume"
+msgstr "Volume"
+
+msgid "Gain"
+msgstr ""
+
+msgid "Monitor"
+msgstr "Monitor"
+
+#, fuzzy
+msgid "Built-in Speaker"
+msgstr "Luidspreker"
+
+msgid "Headphone"
+msgstr ""
+
+msgid "Line Out"
+msgstr ""
+
+msgid "SPDIF Out"
+msgstr ""
+
+msgid "AUX 1 Out"
+msgstr ""
+
+msgid "AUX 2 Out"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Kon nie buffers vanaf toestel \"%s\" verkry nie."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Kon nie buffers vanaf toestel \"%s\" verkry nie."
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr ""
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Device '%s' is busy"
+msgstr "Toestel \"%s\" is nie 'n vasleggingtoestel nie."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Toestel \"%s\" is nie 'n vasleggingtoestel nie."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Toestel \"%s\" is nie 'n vasleggingtoestel nie."
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Toestel \"%s\" is nie 'n vasleggingtoestel nie."
+
+#, fuzzy, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Kon nie buffers vanaf toestel \"%s\" verkry nie."
+
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+
+msgid "Video device did not provide output format."
+msgstr ""
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+
+msgid "Video device uses an unsupported pixel format."
+msgstr ""
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+msgid "Video device did not suggest any buffer size."
+msgstr ""
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Kon nie genoeg buffers vanaf toestel \"%s\" kry nie."
+
+#, fuzzy, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Kon nie buffers vanaf toestel \"%s\" verkry nie."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Toestel \"%s\" is nie 'n vasleggingtoestel nie."
+
+#, fuzzy, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Kon nie oudio-toestel \"%s\" toemaak nie."
+
+#, fuzzy, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Kon nie oudio-toestel \"%s\" toemaak nie."
+
+#, fuzzy, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Kon nie buffers vanaf toestel \"%s\" verkry nie."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+
+msgid "Failed to start decoding thread."
+msgstr ""
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Kon nie genoeg buffers vanaf toestel \"%s\" kry nie."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Kon nie skryf na toestel \"%s\" nie."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Kon nie toestel \"%s\" oopmaak vir lees en skryf nie."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Toestel \"%s\" is nie 'n vasleggingtoestel nie."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Toestel \"%s\" is nie 'n vasleggingtoestel nie."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Toestel \"%s\" is nie 'n vasleggingtoestel nie."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Kon nie toestel \"%s\" oopmaak vir lees en skryf nie."
+
+#, fuzzy, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Kon nie buffers vanaf toestel \"%s\" verkry nie."
+
+#, fuzzy, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Kon nie genoeg buffers vanaf toestel \"%s\" kry nie."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Kon nie beheertoestel \"%s\" toemaak nie."
+
+#, fuzzy, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Kon nie beheertoestel \"%s\" toemaak nie."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+
+#, fuzzy, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr "Kon nie genoeg buffers vanaf toestel \"%s\" kry nie."
+
+#, fuzzy, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Kon nie oudio-toestel \"%s\" toemaak nie."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr ""
+
+msgid "Cannot operate without a clock"
+msgstr ""
+
+#, fuzzy
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Toestel \"%s\" is nie 'n vasleggingtoestel nie."
+
+#, fuzzy
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Kon nie genoeg buffers vanaf toestel \"%s\" kry nie."
+
+#~ msgid "Bass"
+#~ msgstr "Bas"
+
+#~ msgid "Treble"
+#~ msgstr "Treble"
+
+#~ msgid "Synth"
+#~ msgstr "Sintetiseerder"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Luidspreker"
+
+#~ msgid "Line-in"
+#~ msgstr "Lyn-in"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Menger"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Neem op"
+
+#~ msgid "In-gain"
+#~ msgstr "In-versterking"
+
+#~ msgid "Out-gain"
+#~ msgstr "Uit-versterking"
+
+#~ msgid "Line-1"
+#~ msgstr "Lyn-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Lyn-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Lyn-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Digitaal-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Digitaal-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Digitaal-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Telefoon-in"
+
+#~ msgid "Phone-out"
+#~ msgstr "Telefoon-uit"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Radio"
+
+#, fuzzy
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "Kon nie oudio-toestel \"%s\" oopmaak vir skryf nie."
+
+#, fuzzy
+#~ msgid "Rear"
+#~ msgstr "Neem op"
+
+#, fuzzy
+#~ msgid "Side"
+#~ msgstr "Video"
+
+#, fuzzy
+#~ msgid "Video In"
+#~ msgstr "Video"
+
+#, fuzzy
+#~ msgid "Record Gain"
+#~ msgstr "Neem op"
+
+#, fuzzy
+#~ msgid "Output Gain"
+#~ msgstr "Uit-versterking"
+
+#, fuzzy
+#~ msgid "Microphone Boost"
+#~ msgstr "Mikrofoon"
+
+#, fuzzy
+#~ msgid "Monitor Source"
+#~ msgstr "Monitor"
+
+#, fuzzy
+#~ msgid "Microphone Gain"
+#~ msgstr "Mikrofoon"
+
+#, fuzzy
+#~ msgid "Speaker Source"
+#~ msgstr "Luidspreker"
+
+#, fuzzy
+#~ msgid "Microphone Source"
+#~ msgstr "Mikrofoon"
+
+#, fuzzy
+#~ msgid "Microphone 1"
+#~ msgstr "Mikrofoon"
+
+#, fuzzy
+#~ msgid "Microphone 2"
+#~ msgstr "Mikrofoon"
+
+#, fuzzy
+#~ msgid "Digital Out"
+#~ msgstr "Digitaal-1"
+
+#, fuzzy
+#~ msgid "Digital In"
+#~ msgstr "Digitaal-1"
+
+#, fuzzy
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Mikrofoon"
+
+#, fuzzy
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Kon nie buffers vanaf toestel \"%s\" verkry nie."
+
+#~ msgid "Could not open file \"%s\" for writing."
+#~ msgstr "Kon nie lêer \"%s\" oopmaak om in te skryf nie."
+
+#~ msgid "Error closing file \"%s\"."
+#~ msgstr "Fout tydens toemaak van lêer \"%s\"."
+
+#~ msgid "Could not open file \"%s\" for reading."
+#~ msgstr "Kon nie lêer \"%s\" oopmaak om te lees nie."
+
+#~ msgid "No filename specified."
+#~ msgstr "Geen lêernaam gespesifiseer."
+
+#~ msgid "Could not write to file \"%s\"."
+#~ msgstr "Kon nie skryf na lêer \"%s\" nie."
+
+#~ msgid "Could not open control device \"%s\" for writing."
+#~ msgstr "Kon nie beheertoestel \"%s\" oopmaak vir skryf nie."
+
+#~ msgid "Could not configure audio device \"%s\"."
+#~ msgstr "Kon nie oudio-toestel \"%s\" konfigureer nie."
+
+#~ msgid "Could not set audio device \"%s\" to %d Hz."
+#~ msgstr "Kon nie klanktoestel \"%s\" verstel na %d Hz nie."
+
+#~ msgid "Could not open video device \"%s\" for writing."
+#~ msgstr "Kon nie video-toestel \"%s\" oopmaak vir skryf nie."
+
+#~ msgid "Could not close video device \"%s\"."
+#~ msgstr "Kon nie video-toestel \"%s\" toemaak nie."
+
+#~ msgid "OSS device \"%s\" is already in use by another program."
+#~ msgstr "OSS-toestel \"%s\" is reeds in gebruik deur 'n ander program."
+
+#~ msgid "Could not access device \"%s\", check its permissions."
+#~ msgstr "Kon nie toegang kry tot toestel \"%s\" nie, kyk na toegangsregte."
+
+#~ msgid "Device \"%s\" does not exist."
+#~ msgstr "Toestel \"%s\" bestaan nie."
+
+#~ msgid "Could not open device \"%s\" for writing."
+#~ msgstr "Kon nie toestel \"%s\" oopmaak vir skryf nie."
+
+#~ msgid "Could not open device \"%s\" for reading."
+#~ msgstr "Kon nie toestel \"%s\" oopmaak vir lees nie."
+
+#~ msgid "Could not open vfs file \"%s\" for reading."
+#~ msgstr "Kon nie vfs-lêer \"%s\" oopmaak vir lees nie."
+
+#, fuzzy
+#~ msgid "No filename given."
+#~ msgstr "Geen lêernaam gespesifiseer."
+
+#, fuzzy
+#~ msgid "Could not open vfs file \"%s\" for writing: %s."
+#~ msgstr "Kon nie vfs-lêer \"%s\" oopmaak vir skryf nie."
+
+#, fuzzy
+#~ msgid "No filename given"
+#~ msgstr "Geen lêernaam gespesifiseer."
+
+#~ msgid "Could not close vfs file \"%s\"."
+#~ msgstr "Kon nie vfs-lêer \"%s\" toemaak nie."
+
+#~ msgid "No device specified."
+#~ msgstr "Geen toestel gespesifiseer"
+
+#~ msgid "Device is not open."
+#~ msgstr "Toestel is nie oop nie."
+
+#~ msgid "Device is open."
+#~ msgstr "Toestel is oop."
diff --git a/po/az.po b/po/az.po
new file mode 100644
index 0000000..38ba4e8
--- /dev/null
+++ b/po/az.po
@@ -0,0 +1,622 @@
+# Translation of 'gst-plugins' messages to Azerbaijani.
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# This file is put in the public domain.
+# Mətin Əmirov <metin@karegen.com>, 2004.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-0.8.0\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2004-03-19 18:29+0200\n"
+"Last-Translator: Metin Amiroff <metin@karegen.com>\n"
+"Language-Team: Azerbaijani <translation-team-az@lists.sourceforge.net>\n"
+"Language: az\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.0.2\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr ""
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr ""
+
+#, fuzzy
+msgid "Could not connect to server"
+msgstr "\"%s\" idarə avadanlığı bağlana bilmədi."
+
+msgid "No URL set."
+msgstr ""
+
+#, fuzzy
+msgid "Could not resolve server name."
+msgstr "\"%s\" idarə avadanlığı bağlana bilmədi."
+
+#, fuzzy
+msgid "Could not establish connection to server."
+msgstr "\"%s\" idarə avadanlığı bağlana bilmədi."
+
+msgid "Secure connection setup failed."
+msgstr ""
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+
+msgid "Server sent bad data."
+msgstr ""
+
+msgid "Server does not support seeking."
+msgstr ""
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Səhv ya da olmayan audio girişi, AVI yayımı pozulacaqdır."
+
+msgid "This file contains no playable streams."
+msgstr ""
+
+msgid "This file is invalid and cannot be played."
+msgstr ""
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr ""
+
+msgid "Invalid atom size."
+msgstr ""
+
+msgid "This file is incomplete and cannot be played."
+msgstr ""
+
+msgid "The video in this file might not play correctly."
+msgstr ""
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+
+#, fuzzy
+msgid "Could not open audio device for playback."
+msgstr "\"%s\" audio avadanlığı yazma üçün açıla bilmədi."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+
+msgid "Playback is not supported by this audio device."
+msgstr ""
+
+msgid "Audio playback error."
+msgstr ""
+
+msgid "Recording is not supported by this audio device."
+msgstr ""
+
+msgid "Error recording from audio device."
+msgstr ""
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+
+#, fuzzy
+msgid "Could not open audio device for recording."
+msgstr "CD avadanlığı oxuma üçün açıla bilmədi."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+#, fuzzy
+msgid "Record Source"
+msgstr "Qeyd"
+
+msgid "Microphone"
+msgstr "Mikrofon"
+
+#, fuzzy
+msgid "Line In"
+msgstr "Xətd-giriş"
+
+msgid "Internal CD"
+msgstr ""
+
+msgid "SPDIF In"
+msgstr ""
+
+msgid "AUX 1 In"
+msgstr ""
+
+msgid "AUX 2 In"
+msgstr ""
+
+msgid "Codec Loopback"
+msgstr ""
+
+msgid "SunVTS Loopback"
+msgstr ""
+
+msgid "Volume"
+msgstr "Səs"
+
+msgid "Gain"
+msgstr ""
+
+msgid "Monitor"
+msgstr "Monitor"
+
+#, fuzzy
+msgid "Built-in Speaker"
+msgstr "Spiker"
+
+msgid "Headphone"
+msgstr ""
+
+msgid "Line Out"
+msgstr ""
+
+msgid "SPDIF Out"
+msgstr ""
+
+msgid "AUX 1 Out"
+msgstr ""
+
+msgid "AUX 2 Out"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "\"%s\" avadanlığından bufferlər alına bilmədi."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "\"%s\" avadanlığından bufferlər alına bilmədi."
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr ""
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Device '%s' is busy"
+msgstr "\"%s\" avadanlığı capture avadanlığı deyil."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "\"%s\" avadanlığı capture avadanlığı deyil."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "\"%s\" avadanlığı capture avadanlığı deyil."
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "\"%s\" avadanlığı capture avadanlığı deyil."
+
+#, fuzzy, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "\"%s\" avadanlığından bufferlər alına bilmədi."
+
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+
+msgid "Video device did not provide output format."
+msgstr ""
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+
+msgid "Video device uses an unsupported pixel format."
+msgstr ""
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+msgid "Video device did not suggest any buffer size."
+msgstr ""
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "\"%s\" avadanlığından kifayət qədər bufferlər alına bilmədi."
+
+#, fuzzy, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "\"%s\" avadanlığından bufferlər alına bilmədi."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "\"%s\" avadanlığı capture avadanlığı deyil."
+
+#, fuzzy, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "\"%s\" audio avadanlığı bağlana bilmədi."
+
+#, fuzzy, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "\"%s\" audio avadanlığı bağlana bilmədi."
+
+#, fuzzy, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "\"%s\" avadanlığından bufferlər alına bilmədi."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+
+msgid "Failed to start decoding thread."
+msgstr ""
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "\"%s\" avadanlığından kifayət qədər bufferlər alına bilmədi."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Cannot identify device '%s'."
+msgstr "\"%s\" avadanlığına yazıla bilmədi."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "\"%s\" avadanlığı oxuma və yazma üçün açıla bilmədi."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "\"%s\" avadanlığı capture avadanlığı deyil."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a output device."
+msgstr "\"%s\" avadanlığı capture avadanlığı deyil."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "\"%s\" avadanlığı capture avadanlığı deyil."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "\"%s\" avadanlığı oxuma və yazma üçün açıla bilmədi."
+
+#, fuzzy, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "\"%s\" avadanlığından bufferlər alına bilmədi."
+
+#, fuzzy, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "\"%s\" avadanlığından kifayət qədər bufferlər alına bilmədi."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "\"%s\" idarə avadanlığı bağlana bilmədi."
+
+#, fuzzy, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "\"%s\" idarə avadanlığı bağlana bilmədi."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+
+#, fuzzy, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr "\"%s\" avadanlığından kifayət qədər bufferlər alına bilmədi."
+
+#, fuzzy, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "\"%s\" audio avadanlığı bağlana bilmədi."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr ""
+
+msgid "Cannot operate without a clock"
+msgstr ""
+
+#, fuzzy
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "\"%s\" avadanlığı capture avadanlığı deyil."
+
+#, fuzzy
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "\"%s\" avadanlığından kifayət qədər bufferlər alına bilmədi."
+
+#~ msgid "Bass"
+#~ msgstr "Bas"
+
+#~ msgid "Treble"
+#~ msgstr "İncə"
+
+#~ msgid "Synth"
+#~ msgstr "Sint"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Spiker"
+
+#~ msgid "Line-in"
+#~ msgstr "Xətd-giriş"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Mikser"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Qeyd"
+
+#~ msgid "In-gain"
+#~ msgstr "Giriş-gain"
+
+#~ msgid "Out-gain"
+#~ msgstr "Çıxış-gain"
+
+#~ msgid "Line-1"
+#~ msgstr "Xətd-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Xətd-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Xətd-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Dijital-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Dijital-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Dijital-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Telefon-girişi"
+
+#~ msgid "Phone-out"
+#~ msgstr "Telefon-çıxışı"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Radio"
+
+#, fuzzy
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "\"%s\" audio avadanlığı yazma üçün açıla bilmədi."
+
+#, fuzzy
+#~ msgid "Rear"
+#~ msgstr "Qeyd"
+
+#, fuzzy
+#~ msgid "Side"
+#~ msgstr "Video"
+
+#, fuzzy
+#~ msgid "Video In"
+#~ msgstr "Video"
+
+#, fuzzy
+#~ msgid "Record Gain"
+#~ msgstr "Qeyd"
+
+#, fuzzy
+#~ msgid "Output Gain"
+#~ msgstr "Çıxış-gain"
+
+#, fuzzy
+#~ msgid "Microphone Boost"
+#~ msgstr "Mikrofon"
+
+#, fuzzy
+#~ msgid "Monitor Source"
+#~ msgstr "Monitor"
+
+#, fuzzy
+#~ msgid "Microphone Gain"
+#~ msgstr "Mikrofon"
+
+#, fuzzy
+#~ msgid "Speaker Source"
+#~ msgstr "Spiker"
+
+#, fuzzy
+#~ msgid "Microphone Source"
+#~ msgstr "Mikrofon"
+
+#, fuzzy
+#~ msgid "Microphone 1"
+#~ msgstr "Mikrofon"
+
+#, fuzzy
+#~ msgid "Microphone 2"
+#~ msgstr "Mikrofon"
+
+#, fuzzy
+#~ msgid "Digital Out"
+#~ msgstr "Dijital-1"
+
+#, fuzzy
+#~ msgid "Digital In"
+#~ msgstr "Dijital-1"
+
+#, fuzzy
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Mikrofon"
+
+#, fuzzy
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "\"%s\" avadanlığından bufferlər alına bilmədi."
+
+#~ msgid "Could not open file \"%s\" for writing."
+#~ msgstr "\"%s\" faylı yazma üçün açıla bilmədi."
+
+#~ msgid "Error closing file \"%s\"."
+#~ msgstr "\"%s\" faylı bağlana bilmədi."
+
+#~ msgid "Could not open file \"%s\" for reading."
+#~ msgstr "\"%s\" faylı oxuma üçün açıla bilmədi."
+
+#~ msgid "No filename specified."
+#~ msgstr "Fayl adı verilməyib."
+
+#~ msgid "Could not write to file \"%s\"."
+#~ msgstr "\"%s\" faylına yazıla bilmədi."
+
+#~ msgid "Could not open control device \"%s\" for writing."
+#~ msgstr "\"%s\" idarə avadanlığı yazma üçün açıla bilmədi."
+
+#~ msgid "Could not configure audio device \"%s\"."
+#~ msgstr "\"%s\" audio avadanlığı quraşdırıla bilmədi."
+
+#~ msgid "Could not set audio device \"%s\" to %d Hz."
+#~ msgstr "\"%s\" audio avadanlığı %d Hz-ə keçirilə bilmədi."
+
+#~ msgid "Could not open video device \"%s\" for writing."
+#~ msgstr "\"%s\" video avadanlığı yazma üçün açıla bilmədi."
+
+#~ msgid "Could not close video device \"%s\"."
+#~ msgstr "\"%s\" video avadanlığı bağlana bilmədi."
+
+#~ msgid "OSS device \"%s\" is already in use by another program."
+#~ msgstr "\"%s\" OSS avadanlığı başqa bir proqram tərəfindən istifadədədir."
+
+#~ msgid "Could not access device \"%s\", check its permissions."
+#~ msgstr "\"%s\" avadanlığına yetişə bilmədi, səlahiyyətlərini yoxlayın."
+
+#~ msgid "Device \"%s\" does not exist."
+#~ msgstr "\"%s\" avadanlığı mövcud deyil."
+
+#~ msgid "Could not open device \"%s\" for writing."
+#~ msgstr "\"%s\" avadanlığı yazma üçün açıla bilmədi."
+
+#~ msgid "Could not open device \"%s\" for reading."
+#~ msgstr "\"%s\" avadanlığı oxuma üçün açıla bilmədi."
+
+#~ msgid "Could not open vfs file \"%s\" for reading."
+#~ msgstr "\"%s\" vfs faylı oxuma üçün açıla bilmədi."
+
+#, fuzzy
+#~ msgid "No filename given."
+#~ msgstr "Fayl adı verilməyib."
+
+#, fuzzy
+#~ msgid "Could not open vfs file \"%s\" for writing: %s."
+#~ msgstr "\"%s\" vfs faylı yazma üçün açıla bilmədi."
+
+#, fuzzy
+#~ msgid "No filename given"
+#~ msgstr "Fayl adı verilməyib."
+
+#~ msgid "Could not close vfs file \"%s\"."
+#~ msgstr "\"%s\" vfs faylı bağlana bilmədi."
+
+#~ msgid "No device specified."
+#~ msgstr "Avadanlıq bildirilməyib."
+
+#~ msgid "Device is not open."
+#~ msgstr "Avadanlıq açıq deyil."
+
+#~ msgid "Device is open."
+#~ msgstr "Avadanlıq açıqdır."
diff --git a/po/bg.po b/po/bg.po
new file mode 100644
index 0000000..aca45cf
--- /dev/null
+++ b/po/bg.po
@@ -0,0 +1,431 @@
+# Bulgarian translation of gst-plugins-good.
+# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2016 Free Software Foundation, Inc.
+# This file is distributed under the same license as the gst-plugins-good package.
+# Alexander Shopov <ash@kambanaria.org>, 2007, 2008, 2009, 2010, 2011, 2016.
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-02-21 21:03+0200\n"
+"Last-Translator: Alexander Shopov <ash@kambanaria.org>\n"
+"Language-Team: Bulgarian <dict@ludost.net>\n"
+"Language: bg\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+msgid "Jack server not found"
+msgstr "Сървърът Jack не е открит."
+
+msgid "Failed to decode JPEG image"
+msgstr "Неуспешно декодиране на изображение, формат JPEG."
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "„%s“ от „%s“"
+
+msgid "Could not connect to server"
+msgstr "Не може да се осъществи връзка към сървър."
+
+msgid "No URL set."
+msgstr "Не е зададен адрес."
+
+msgid "Could not resolve server name."
+msgstr "Сървърът не може да се открие по име."
+
+msgid "Could not establish connection to server."
+msgstr "Не може да се осъществи връзка към сървъра."
+
+msgid "Secure connection setup failed."
+msgstr "Неуспешно осъществяване на шифрирана връзка."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr "Възникна мрежова грешка или сървърът неочаквано прекъсна връзката."
+
+msgid "Server sent bad data."
+msgstr "Сървърът изпрати лоши данни."
+
+msgid "Server does not support seeking."
+msgstr "Сървърът не поддържа търсене."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Аудио входът липсва или е грешен. Потокът с AVI ще бъде повреден."
+
+msgid "This file contains no playable streams."
+msgstr "Този файл не съдържа изпълними потоци."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Този файл е повреден и не може да бъде изпълнен."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr "Потокът не може да се изпълни, защото е шифриран с PlayReady DRM."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Този файл е повреден и не може да бъде изпълнен."
+
+msgid "Invalid atom size."
+msgstr "Неправилен размер на атом."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Този файл е непълен и не може да бъде изпълнен."
+
+msgid "The video in this file might not play correctly."
+msgstr "Видео потокът в този файл може да не се покаже правилно."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+"Този файл съдържа прекалено много потоци. Изпълняват се само първите %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Не е открит поддържан поток. Може да трябва да инсталирате приставката на "
+"GStreamer — RTSP, който поддържа потоци на Real."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Не е открит поддържан поток. Може би трябва да разрешите повече транспортни "
+"протоколи или ви липсва правилната приставка на GStreamer за RTSP."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Аудио устройството не може да се отвори за изпълнение, използва се от друго "
+"приложение."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Аудио устройството не може да се отвори за изпълнение, нямате права за това."
+
+msgid "Could not open audio device for playback."
+msgstr "Устройството не може да се отвори за изпълнение."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Аудио устройството не може да се отвори за изпълнение. Елементът не поддържа "
+"тази версия на OSS."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Това аудио устройство не поддържа изпълнение."
+
+msgid "Audio playback error."
+msgstr "Грешка при изпълнение на аудиото."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Това аудио устройство не поддържа запис."
+
+msgid "Error recording from audio device."
+msgstr "Грешка при записа от аудио устройството."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Аудио устройството не може да се отвори за запис, нямате права за това."
+
+msgid "Could not open audio device for recording."
+msgstr "Аудио устройството не може да се отвори за запис."
+
+msgid "CoreAudio device not found"
+msgstr "Устройството CoreAudio не е открито"
+
+msgid "CoreAudio device could not be opened"
+msgstr "Устройството CoreAudio не може да се отвори"
+
+msgid "Record Source"
+msgstr "Източник за запис"
+
+msgid "Microphone"
+msgstr "Микрофон"
+
+msgid "Line In"
+msgstr "Вход"
+
+msgid "Internal CD"
+msgstr "Вътрешно CD"
+
+msgid "SPDIF In"
+msgstr "Вход SPDIF"
+
+msgid "AUX 1 In"
+msgstr "Вход AUX 1"
+
+msgid "AUX 2 In"
+msgstr "Вход AUX 2"
+
+msgid "Codec Loopback"
+msgstr "Обратна връзка на кодека"
+
+msgid "SunVTS Loopback"
+msgstr "Обратна връзка на SunVTS"
+
+msgid "Volume"
+msgstr "Сила на звука"
+
+msgid "Gain"
+msgstr "Усилване"
+
+msgid "Monitor"
+msgstr "Монитор"
+
+msgid "Built-in Speaker"
+msgstr "Вграден високоговорител"
+
+msgid "Headphone"
+msgstr "Слушалки"
+
+msgid "Line Out"
+msgstr "Изход"
+
+msgid "SPDIF Out"
+msgstr "Изход SPDIF"
+
+msgid "AUX 1 Out"
+msgstr "Изход AUX 1"
+
+msgid "AUX 2 Out"
+msgstr "Изход AUX 2"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Грешка при прочитане %d байта от устройство „%s“."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Неуспешно изброяване на поддържаните от устройството „%s“ видео формати"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Не могат да се получат буферите от устройството „%s“."
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Драйверът за устройството „%s“ не поддържа познати метода за В/И %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Драйверът за устройството „%s“ не поддържа познат метод за В/И."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Устройството „%s“ е заето"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Устройството „%s“ не може да записва с разделителна способност %d×%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Устройството „%s“ не може да записва в указания формат."
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Устройството „%s“ не поддържа несъседни равнини"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Не могат да се получат параметрите на устройството „%s“."
+
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+"Устройството за видео не приема новите настройки за честотата на кадри."
+
+msgid "Video device did not provide output format."
+msgstr "Видео устройството не указва формат."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Видео устройството върна неправилни размери"
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Видео устройството използва неподдържана презредова развивка."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Видео устройството използва неподдържан формат на пикселите."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Неуспешно настройване на вътрешните буфери."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Видео устройството не указва размер на буфера."
+
+msgid "No downstream pool to import from."
+msgstr "Няма буфери, които да се внесат."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Неуспешно получаване на настройките на тунер %d на устройство „%s“."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Грешка при получаване на възможностите на устройство „%s“."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Устройството „%s“ не е тунер."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Неуспешно получаване на радио входа на устройство „%s“."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Неуспешно задаване на вход %d на устройство „%s“."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Неуспешна смяна на заглушаването устройство „%s“."
+
+msgid "Failed to allocated required memory."
+msgstr "Неуспешно заделяне на необходимата памет."
+
+msgid "Failed to allocate required memory."
+msgstr "Неуспешно заделяне на необходимата памет."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Конверторът на устройството „%s“ не поддържа познати метод за вход."
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Конверторът на устройството „%s“ не поддържа познати метод за изход."
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Кодерът устройството „%s“ не поддържа познати метод за вход."
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Кодерът на устройството „%s“ не поддържа познати метод за изход."
+
+msgid "Failed to start decoding thread."
+msgstr "Неуспешно стартиране на нишката за декодиране."
+
+msgid "Failed to process frame."
+msgstr "Неуспешна обработка на кадър."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Грешка при получаването на възможностите на устройството „%s“: не е драйвер "
+"v4l2. Проверете дали всъщност не е драйвер v4l1."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Неуспешно запитване за атрибутите за вход %d на устройство „%s“."
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Неуспешно получаване на настройките на тунер %d на устройство „%s“."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Неуспешно запитване за нормата на устройство „%s“."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Неуспешно получаване на контролните атрибути на устройството „%s“."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Устройството „%s“ не може да се идентифицира."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "„%s“ не е устройство."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Устройството „%s“ не може да се отвори за четене и запис."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Устройството „%s“ не е устройство за запис."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Устройството „%s“ не е изходно устройство."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Устройството „%s“ не е M2M."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Устройството „%s“ не може да се дуплексира за четене и запис."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Неуспешно задаване на нормата на устройство „%s“."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+"Неуспешно получаване на текущата настройка на честотата за устройство „%s“."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Неуспешно задаване на текущата настройка на честотата на устройство „%s“ да "
+"е %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Неуспешно получаване на силата на сигнала на устройство „%s“."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Неуспешно получаване на стойността на контрол %d на устройство „%s“."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Неуспешно задаване на стойността %d на контрол %d на устройство „%s“."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Неуспешно получаване на текущия вход на устройство „%s“. Може би е радио."
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Неуспешно получаване на текущия изход на устройство „%s“. Може би е радио."
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Неуспешно задаване на изход %d на устройство „%s“."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr ""
+"Промяната на разделителната способност по време на работа все още не се "
+"поддържа."
+
+msgid "Cannot operate without a clock"
+msgstr "Работата без часовник е невъзможна."
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Вътрешна грешка на потока от данни."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Вътрешна грешка в потока с данни."
diff --git a/po/ca.po b/po/ca.po
new file mode 100644
index 0000000..ab2c753
--- /dev/null
+++ b/po/ca.po
@@ -0,0 +1,935 @@
+# Catalan translation of gst-plugins-good
+# Copyright © 2005 Free Software Foundation, Inc.
+# This file is put in the public domain.
+# Jordi Mallach <jordi@sindominio.net>, 2005.
+# Jordi Estrada <jordi.estrada@yamaha-motor.es>, 2011.
+# Gil Forcada <gforcada@gnome.org>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 0.10.28.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2012-01-01 14:19+0100\n"
+"Last-Translator: Gil Forcada <gforcada@gnome.org>\n"
+"Language-Team: Catalan <ca@dodds.net>\n"
+"Language: ca\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr "Ha fallat en descodificar la imatge JPEG"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "«%s» per «%s»"
+
+msgid "Could not connect to server"
+msgstr "No s'ha pogut connectar al servidor"
+
+msgid "No URL set."
+msgstr "No s'ha indicat cap URL."
+
+msgid "Could not resolve server name."
+msgstr "No s'ha pogut resoldre el nom del servidor."
+
+msgid "Could not establish connection to server."
+msgstr "No s'ha pogut establir la connexió al servidor."
+
+msgid "Secure connection setup failed."
+msgstr "Ha fallat la configuració de connexió segura."
+
+#, fuzzy
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"S'ha produït un error de xarxa, o el servidor ha tancat la connexió "
+"inesperadament."
+
+msgid "Server sent bad data."
+msgstr "El servidor ha enviat dades errònies."
+
+msgid "Server does not support seeking."
+msgstr "El servidor no ademet les cerques."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Manca o no és vàlida l'entrada d'àudio, el flux AVI estarà malmès."
+
+msgid "This file contains no playable streams."
+msgstr "Aquest fitxer no conté cap flux reproduïble."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Aquest fitxer no és vàlid i no es pot reproduir."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Aquest fitxer està malmès i no es pot reproduir."
+
+msgid "Invalid atom size."
+msgstr "La mida de l'àtom no és vàlida."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Aquest fitxer no està complet i no es pot reproduir."
+
+msgid "The video in this file might not play correctly."
+msgstr "El vídeo en aquest fitxer podria no reproduir-se correctament."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+"Aquest fitxer conté massa fluxos. Només s'estan reproduint els primers %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"No s'ha trobat cap flux compatible. Podríeu necessitar instal·lar un "
+"connector d'extensió RTSP del GStreamer per a fluxos de multimèdia Real."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"No s'ha trobat cap flux compatible. Podríeu necessitar permetre més "
+"protocols de transport o bé potser manca el connector d'extensió RTSP del "
+"GStreamer correcte."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"No s'ha pogut obrir el dispositiu d'àudio per a la reproducció. Una altra "
+"aplicació està utilitzant el dispositiu."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"No s'ha pogut obrir el dispositiu d'àudio per a la reproducció. No teniu "
+"permís per obrir el dispositiu."
+
+msgid "Could not open audio device for playback."
+msgstr "No s'ha pogut obrir el dispositiu d'àudio per a la reproducció."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"No s'ha pogut obrir el dispositiu d'àudio per a la reproducció. Aquesta "
+"versió de l'Open Sound System no és compatible amb aquest element."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Aquest dispositiu d'àudio no permet la reproducció."
+
+msgid "Audio playback error."
+msgstr "S'ha produït un error al reproduir l'àudio."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Aquest dispositiu d'àudio no permet l'enregistrament."
+
+msgid "Error recording from audio device."
+msgstr "S'ha produït un error a l'enregistrar des del dispositiu d'àudio."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"No s'ha pogut obrir el dispositiu d'àudio per a l'enregistrament. No teniu "
+"permís per obrir el dispositiu."
+
+msgid "Could not open audio device for recording."
+msgstr "No s'ha pogut obrir el dispositiu d'àudio per a l'enregistrament."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "Font d'enregistrament"
+
+msgid "Microphone"
+msgstr "Micròfon"
+
+msgid "Line In"
+msgstr "Línia d'entrada"
+
+msgid "Internal CD"
+msgstr "CD intern"
+
+msgid "SPDIF In"
+msgstr "Entrada SPDIF"
+
+msgid "AUX 1 In"
+msgstr "Entrada AUX 1"
+
+msgid "AUX 2 In"
+msgstr "Entrada AUX 2"
+
+#, fuzzy
+msgid "Codec Loopback"
+msgstr "Bucle local"
+
+#, fuzzy
+msgid "SunVTS Loopback"
+msgstr "Bucle local"
+
+msgid "Volume"
+msgstr "Volum"
+
+msgid "Gain"
+msgstr "Guany"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "Altaveu incorporat"
+
+msgid "Headphone"
+msgstr "Auriculars"
+
+msgid "Line Out"
+msgstr "Línia de sortida"
+
+msgid "SPDIF Out"
+msgstr "Sortida SPDIF"
+
+msgid "AUX 1 Out"
+msgstr "Sortida AUX 1"
+
+msgid "AUX 2 Out"
+msgstr "Sortida AUX 2"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "S'ha produït un error al llegir %d bytes des del dispositiu «%s»."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "No s'han pogut mapejar les memòries intermèdies del dispositiu «%s»"
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr ""
+"El controlador del dispositiu «%s» no és compatible amb cap mètode de "
+"captura conegut."
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"El controlador del dispositiu «%s» no és compatible amb cap mètode de "
+"captura conegut."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "El dispositiu «%s» no és un dispositiu de captura."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "El dispositiu «%s» no és un dispositiu de captura."
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "El dispositiu «%s» no és un dispositiu de sortida."
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "No s'han pogut obtenir els paràmetres del dispositiu «%s»"
+
+#, fuzzy
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+"El dispositiu d'entrada de vídeo no ha acceptat el paràmetre nou de "
+"fotogrames per segon."
+
+#, fuzzy
+msgid "Video device did not provide output format."
+msgstr ""
+"El dispositiu d'entrada de vídeo no ha acceptat el paràmetre nou de "
+"fotogrames per segon."
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+"El controlador del dispositiu «%s» no és compatible amb cap mètode de "
+"captura conegut."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr ""
+"El controlador del dispositiu «%s» no és compatible amb cap mètode de "
+"captura conegut."
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+#, fuzzy
+msgid "Video device did not suggest any buffer size."
+msgstr ""
+"El dispositiu d'entrada de vídeo no ha acceptat el paràmetre nou de "
+"fotogrames per segon."
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr ""
+"No s'han pogut obtenir els paràmetres del sintonitzador %d en el dispositiu "
+"«%s»."
+
+#, fuzzy, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "S'ha produït un error al llegir %d bytes des del dispositiu «%s»."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "El dispositiu «%s» no és un dispositiu de sortida."
+
+#, fuzzy, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "No s'ha pogut establir l'entrada %d en el dispositiu %s."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "No s'ha pogut establir l'entrada %d en el dispositiu %s."
+
+#, fuzzy, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "No s'ha pogut obtenir la intensitat del senyal per al dispositiu «%s»."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+"El controlador del dispositiu «%s» no és compatible amb cap mètode de "
+"captura conegut."
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+"El dispositiu d'entrada de vídeo no ha acceptat el paràmetre nou de "
+"fotogrames per segon."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+"El dispositiu d'entrada de vídeo no ha acceptat el paràmetre nou de "
+"fotogrames per segon."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+"El dispositiu d'entrada de vídeo no ha acceptat el paràmetre nou de "
+"fotogrames per segon."
+
+#, fuzzy
+msgid "Failed to start decoding thread."
+msgstr "Ha fallat en descodificar la imatge JPEG"
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"S'ha produït un error en obtenir les capacitats del dispositiu «%s»: no és "
+"un controlador v4l2. Comproveu si és un controlador v4l1."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr ""
+"S'ha produït un error en consultar els atributs de l'entrada %d en el "
+"dispositiu %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr ""
+"No s'han pogut obtenir els paràmetres del sintonitzador %d en el dispositiu "
+"«%s»."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "S'ha produït un error en consultar la norma en el dispositiu «%s»."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr ""
+"No s'ha pogut obtenir els atributs dels controls en el dispositiu «%s»."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "No es pot identificar el dispositiu «%s»."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Això no és un dispositiu «%s»."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "No s'ha pogut obrir el dispositiu «%s» per a lectura i l'escriptura."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "El dispositiu «%s» no és un dispositiu de captura."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "El dispositiu «%s» no és un dispositiu de sortida."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "El dispositiu «%s» no és un dispositiu de sortida."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "No s'ha pogut obrir el dispositiu «%s» per a lectura i l'escriptura."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "No s'ha pogut establir la norma per al dispositiu «%s»."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+"No s'ha pogut obtenir la freqüència actual del sintonitzador per al "
+"dispositiu «%s»."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"No s'ha pogut establir la freqüència actual del sintonitzador per al "
+"dispositiu «%s» a %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "No s'ha pogut obtenir la intensitat del senyal per al dispositiu «%s»."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr ""
+"No s'ha pogut obtenir el valor per al control %d en el dispositiu «%s»."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr ""
+"No s'ha pogut establir el valor %d per al control %d en el dispositiu «%s»."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"No s'ha pogut obtenir l'entrada actual en el dispositiu «%s». Potser és un "
+"dispositiu de ràdio"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"No s'ha pogut obtenir la sortida actual en el dispositiu «%s». Potser és un "
+"dispositiu de ràdio"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "No s'ha pogut establir la sortida %d en el dispositiu %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Encara no es permet el canvi de la resolució en temps d'execució."
+
+msgid "Cannot operate without a clock"
+msgstr "No es pot operar sense un rellotge"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "S'ha produït un error intern de flux de dades."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "S'ha produït un error intern de flux de dades."
+
+#, fuzzy
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "El dispositiu «%s» no és un dispositiu de sortida."
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "S'ha obtingut una mida de fotograma inesperada de %u en lloc de %u."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr ""
+#~ "S'ha produït un error en provar d'obtenir fotogrames de vídeo des del "
+#~ "dispositiu «%s»."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr ""
+#~ "Ha fallat després de %d intents. Dispositiu %s. Error de sistema: %s"
+
+#~ msgid "Bass"
+#~ msgstr "Baixos"
+
+#~ msgid "Treble"
+#~ msgstr "Aguts"
+
+#~ msgid "Synth"
+#~ msgstr "Sintetitzador"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Altaveu"
+
+#~ msgid "Line-in"
+#~ msgstr "Línia d'entrada"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Mesclador"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Enregistrament"
+
+#~ msgid "In-gain"
+#~ msgstr "Guany d'entrada"
+
+#~ msgid "Out-gain"
+#~ msgstr "Guany de sortida"
+
+#~ msgid "Line-1"
+#~ msgstr "Línia-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Línia-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Línia-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Digital-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Digital-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Digital-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Entrada del telèfon"
+
+#~ msgid "Phone-out"
+#~ msgstr "Sortida del telèfon"
+
+#~ msgid "Video"
+#~ msgstr "Vídeo"
+
+#~ msgid "Radio"
+#~ msgstr "Ràdio"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr ""
+#~ "No s'ha pogut obrir el dispositiu d'àudio per a la gestió del control del "
+#~ "mesclador."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "No s'ha pogut obrir el dispositiu d'àudio per a la gestió del control del "
+#~ "mesclador. Aquesta versió de l'Open Sound System no és compatible amb "
+#~ "aquest element."
+
+#~ msgid "Master"
+#~ msgstr "Mestre"
+
+#~ msgid "Front"
+#~ msgstr "Frontal"
+
+#~ msgid "Rear"
+#~ msgstr "Posterior"
+
+#~ msgid "Headphones"
+#~ msgstr "Auriculars"
+
+#~ msgid "Center"
+#~ msgstr "Central"
+
+#~ msgid "LFE"
+#~ msgstr "LFE (efectes de baixa freqüència)"
+
+#~ msgid "Surround"
+#~ msgstr "So envoltant"
+
+#~ msgid "Side"
+#~ msgstr "Lateral"
+
+#~ msgid "AUX Out"
+#~ msgstr "Sortida AUX"
+
+#~ msgid "3D Depth"
+#~ msgstr "Profunditat 3D"
+
+#~ msgid "3D Center"
+#~ msgstr "Centre 3D"
+
+#~ msgid "3D Enhance"
+#~ msgstr "Millora 3D"
+
+#~ msgid "Telephone"
+#~ msgstr "Telèfon"
+
+#~ msgid "Video In"
+#~ msgstr "Entrada de vídeo"
+
+#~ msgid "AUX In"
+#~ msgstr "Entrada AUX"
+
+#~ msgid "Record Gain"
+#~ msgstr "Guany d'enregistrament"
+
+#~ msgid "Output Gain"
+#~ msgstr "Guany de sortida"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Amplificació del micròfon"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Diagnòstic"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Amplificació dels baixos"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Ports de reproducció"
+
+#~ msgid "Input"
+#~ msgstr "Entrada"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Font del monitor"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "So del teclat"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Estèreo simulat"
+
+#~ msgid "Stereo"
+#~ msgstr "Estèreo"
+
+#~ msgid "Surround Sound"
+#~ msgstr "So envoltant"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Guany del micròfon"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Font de l'altaveu"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Font del micròfon"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Centre / LFE (efectes de baixa freqüència)"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Mescla estèreo"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Mescla mono"
+
+#~ msgid "Input Mix"
+#~ msgstr "Mescla d'entrada"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Micròfon 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Micròfon 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Sortida digital"
+
+#~ msgid "Digital In"
+#~ msgstr "Entrada digital"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Mòdem"
+
+#~ msgid "Handset"
+#~ msgstr "Comandament a distància"
+
+#~ msgid "Other"
+#~ msgstr "Altres"
+
+#~ msgid "None"
+#~ msgstr "Cap"
+
+#~ msgid "On"
+#~ msgstr "Encès"
+
+#~ msgid "Off"
+#~ msgstr "Apagat"
+
+#~ msgid "Mute"
+#~ msgstr "Silenci"
+
+#~ msgid "Fast"
+#~ msgstr "Ràpid"
+
+#~ msgid "Very Low"
+#~ msgstr "Molt baixa"
+
+#~ msgid "Low"
+#~ msgstr "Baixa"
+
+#~ msgid "Medium"
+#~ msgstr "Mitjana"
+
+#~ msgid "High"
+#~ msgstr "Alta"
+
+#~ msgid "Very High"
+#~ msgstr "Molt alta"
+
+#~ msgid "Production"
+#~ msgstr "Producció"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Micròfon del quadre frontal"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Línia d'entrada del quadre frontal"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Auriculars del quadre frontal"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Línia de sortida del quadre frontal"
+
+#~ msgid "Green Connector"
+#~ msgstr "Connector verd"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Connector rosa"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Connector blau"
+
+#~ msgid "White Connector"
+#~ msgstr "Connector blanc"
+
+#~ msgid "Black Connector"
+#~ msgstr "Connector negre"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Connector gris"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Connector taronja"
+
+#~ msgid "Red Connector"
+#~ msgstr "Connector vermell"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Connector groc"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Connector verd del quadre frontal"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Connector rosa del quadre frontal"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Connector blau del quadre frontal"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Connector blanc del quadre frontal"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Connector negre del quadre frontal"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Connector gris del quadre frontal"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Connector taronja del quadre frontal"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Connector vermell del quadre frontal"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Connector groc del quadre frontal"
+
+#~ msgid "Spread Output"
+#~ msgstr "Sortida de propagació"
+
+#~ msgid "Downmix"
+#~ msgstr "Downmix"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Entrada del mesclador virtual"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Sortida del mesclador virtual"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Canals del mesclador virtual"
+
+#~ msgid "%s %d Function"
+#~ msgstr "Funció %s %d"
+
+#~ msgid "%s Function"
+#~ msgstr "Funció %s"
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "No s'ha pogut establir la connexió al servidor de so"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Ha fallat en consultar les capacitats del servidor de so"
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "S'ha produït un error al llegir %d bytes en el dispositiu «%s»."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr ""
+#~ "No s'han pogut enviar a la cua les memòries intermèdies en el dispositiu "
+#~ "«%s»."
+
+#~ msgid "Describes the selected input element."
+#~ msgstr "Descriu l'element d'entrada seleccionat."
+
+#~ msgid "Describes the selected output element for Audio/Video Conferencing."
+#~ msgstr ""
+#~ "Descriu l'element de sortida seleccionat per a les conferències d'àudio/"
+#~ "vídeo."
+
+#~ msgid "Describes the selected output element for Music and Movies."
+#~ msgstr ""
+#~ "Descriu l'element de sortida seleccionat per a la música i les "
+#~ "pel·lícules."
+
+#~ msgid "Describes the selected output element."
+#~ msgstr "Descriu l'element de sortida seleccionat."
+
+#~ msgid "GStreamer audiosink for Audio/Video Conferencing"
+#~ msgstr "L'audiosink del GStreamer per a les conferències d'àudio/vídeo"
+
+#~ msgid "GStreamer audiosink for Music and Movies"
+#~ msgstr "L'audiosink del GStreamer per a la música i les pel·lícules"
+
+#~ msgid ""
+#~ "GStreamer can play audio using any number of output elements. Some "
+#~ "possible choices are osssink, esdsink and alsasink. The audiosink can be "
+#~ "a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "El GStreamer pot reproduir l'àudio utilitzant qualsevol nombre d'elements "
+#~ "de sortida. Algunes opcions possibles són l'osssink, l'esdsink i "
+#~ "l'alsasink. L'audiosink pot ser un conducte parcial en lloc d'un sol "
+#~ "element."
+
+#~ msgid ""
+#~ "GStreamer can play video using any number of output elements. Some "
+#~ "possible choices are xvimagesink, ximagesink, sdlvideosink and aasink. "
+#~ "The videosink can be a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "El GStreamer pot reproduir el vídeo utilitzant qualsevol nombre "
+#~ "d'elements de sortida. Algunes opcions possibles són el xvimagesink, el "
+#~ "ximagesink, el sdlvideosink i l'aasink. El videosink pot ser un conducte "
+#~ "parcial en lloc d'un sol element."
+
+#~ msgid ""
+#~ "GStreamer can put visualization plugins in a pipeline to transform audio "
+#~ "stream in video frames. Default is goom but more visualization plugins "
+#~ "will be ported soon. The visualization plugin can be a partial pipeline "
+#~ "instead of just one element."
+#~ msgstr ""
+#~ "El GStreamer pot posar els connectors de visualització en un conducte per "
+#~ "transformar el flux d'àudio en els fotogrames del vídeo. Per defecte és "
+#~ "el goom però aviat s'importaran més connectors de visualització. El "
+#~ "connector de visualització pot ser un conducte parcial en lloc d'un sol "
+#~ "element."
+
+#~ msgid ""
+#~ "GStreamer can record audio using any number of input elements. Some "
+#~ "possible choices are osssrc, esdsrc and alsasrc. The audio source can be "
+#~ "a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "El GStreamer pot enregistrar l'àudio utilitzant qualsevol nombre "
+#~ "d'elements d'entrada. Algunes opcions possibles són l'osssrc, l'esdsrc i "
+#~ "l'alsasrc. La font d'àudio pot ser un conducte parcial en lloc d'un sol "
+#~ "element."
+
+#~ msgid ""
+#~ "GStreamer can record video from any number of input elements. Some "
+#~ "possible choices are v4lsrc and videotestsrc. The video source can be a "
+#~ "partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "El GStreamer pot enregistrar el vídeo de qualsevol nombre d'elements "
+#~ "d'entrada. Algunes opcions possibles són el v4lsrc i el videotestsrc. La "
+#~ "font del vídeo pot ser un conducte parcial en lloc d'un sol element."
+
+#~ msgid "default GStreamer audio source"
+#~ msgstr "font d'àudio del GStreamer per defecte"
+
+#~ msgid "default GStreamer audiosink"
+#~ msgstr "audiosink del GStreamer per defecte"
+
+#~ msgid "default GStreamer video source"
+#~ msgstr "font de vídeo del GStreamer per defecte"
+
+#~ msgid "default GStreamer videosink"
+#~ msgstr "videosink del GStreamer per defecte"
+
+#~ msgid "default GStreamer visualization plugin"
+#~ msgstr "connector de visualització del GStreamer per defecte"
+
+#~ msgid "description for GStreamer audiosink for Audio/Video Conferencing"
+#~ msgstr ""
+#~ "descripció de l'audiosink del GStreamer per a les conferències d'àudio/"
+#~ "vídeo"
+
+#~ msgid "description for GStreamer audiosink for Music and Movies"
+#~ msgstr ""
+#~ "descripció de l'audiosink del GStreamer per a la música i les pel·lícules"
+
+#~ msgid "description for default GStreamer audiosink"
+#~ msgstr "descripció de l'audiosink del GStreamer per defecte"
+
+#~ msgid "description for default GStreamer audiosrc"
+#~ msgstr "descripció de l'audiosrc del GStreamer per defecte"
diff --git a/po/cs.po b/po/cs.po
new file mode 100644
index 0000000..0d71b50
--- /dev/null
+++ b/po/cs.po
@@ -0,0 +1,433 @@
+# Czech translation of gst-plugins-good.
+# Copyright (C) 2007, 2008, 2009, 2010, 2011 the author(s) of gst-plugins-good.
+# This file is put in the public domain.
+#
+# Miloslav Trmac <mitr@volny.cz>, 2004.
+# Petr Kovar <pknbe@volny.cz>, 2007, 2008, 2009, 2010, 2011.
+# Marek Černocký <marek@manet.cz>, 2013, 2015, 2016.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good-1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-02-27 16:40+0100\n"
+"Last-Translator: Marek Černocký <marek@manet.cz>\n"
+"Language-Team: Czech <translation-team-cs@lists.sourceforge.net>\n"
+"Language: cs\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
+"X-Generator: Gtranslator 2.91.6\n"
+
+msgid "Jack server not found"
+msgstr "Server Jack nebyl nalezen"
+
+msgid "Failed to decode JPEG image"
+msgstr "Selhalo dekódování obrázku JPEG"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "„%s“ od „%s“"
+
+msgid "Could not connect to server"
+msgstr "Nezdařilo se spojení se serverem"
+
+msgid "No URL set."
+msgstr "Není nastavena žádná adresa URL."
+
+msgid "Could not resolve server name."
+msgstr "Nezdařil se překlad názvu serveru."
+
+msgid "Could not establish connection to server."
+msgstr "Nezdařilo se navázání spojení se serverem."
+
+msgid "Secure connection setup failed."
+msgstr "Selhalo nastavení zabezpečeného připojení."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr "Došlo k chybě sítě nebo server neočekávaně ukončil spojení."
+
+msgid "Server sent bad data."
+msgstr "Server odeslal chybná data."
+
+msgid "Server does not support seeking."
+msgstr "Server nepodporuje přeskakování."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Žádný nebo neplatný zvukový vstup, proud AVI bude poškozen."
+
+msgid "This file contains no playable streams."
+msgstr "Tento soubor neobsahuje hratelné proudy."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Tento soubor je neplatný a nelze jej přehrát."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr "Nelze přehrát proud, protože je šifrován pomocí DRM PlayReady."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Tento soubor je poškozen a nelze jej přehrát."
+
+msgid "Invalid atom size."
+msgstr "Neplatná atomická velikost."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Tento soubor není úplný a nelze jej přehrát."
+
+msgid "The video in this file might not play correctly."
+msgstr "Video v tomto souboru se nemusí přehrát správně."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Tento soubor obsahuje příliš mnoho proudů. Přehrává se pouze první %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Nebyl nalezen žádný podporovaný proud. Bude patrně nutné nainstalovat "
+"zásuvný modul rozšíření GStreamer RTSP pro multimediální proudy Real."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Nebyl nalezen žádný podporovaný proud. Patrně bude nutné povolit více "
+"přenosových protokolů, jinak nejspíš bude scházet potřebný zásuvný modul "
+"rozšíření GStreamer RTSP."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Zvukové zařízení nelze otevřít pro přehrávání. Zařízení je používáno jinou "
+"aplikací."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Zvukové zařízení nelze otevřít pro přehrávání. Nemáte oprávnění k otevření "
+"zařízení."
+
+msgid "Could not open audio device for playback."
+msgstr "Zvukové zařízení nelze otevřít pro čtení."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Nezdařilo se otevření zvukového zařízení pro přehrávání. Tato verze Open "
+"Sound System není příslušným prvkem podporována."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Přehrávání není tímto zvukovým zařízením podporováno."
+
+msgid "Audio playback error."
+msgstr "Chyba přehrávání zvuku."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Toto zvukové zařízení nepodporuje nahrávání."
+
+msgid "Error recording from audio device."
+msgstr "Chyba při nahrávání ze zvukového zařízení."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Zvukové zařízení nelze otevřít pro nahrávání. Nemáte oprávnění k otevření "
+"zařízení."
+
+msgid "Could not open audio device for recording."
+msgstr "Zvukové zařízení nelze otevřít pro nahrávání."
+
+msgid "CoreAudio device not found"
+msgstr "Nebylo nalezeno zařízení CoreAudio"
+
+msgid "CoreAudio device could not be opened"
+msgstr "Nelze otevřít zařízení CoreAudio"
+
+msgid "Record Source"
+msgstr "Zdroj nahrávání"
+
+msgid "Microphone"
+msgstr "Mikrofon"
+
+msgid "Line In"
+msgstr "Linkový vstup"
+
+msgid "Internal CD"
+msgstr "Interní CD"
+
+msgid "SPDIF In"
+msgstr "Vstup SPDIF"
+
+msgid "AUX 1 In"
+msgstr "Vstup AUX 1"
+
+msgid "AUX 2 In"
+msgstr "Vstup AUX 2"
+
+msgid "Codec Loopback"
+msgstr "Kodeková smyčka"
+
+msgid "SunVTS Loopback"
+msgstr "Smyčka SunVTS"
+
+msgid "Volume"
+msgstr "Hlasitost"
+
+msgid "Gain"
+msgstr "Zesílení"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "Zabudovaný reproduktor"
+
+msgid "Headphone"
+msgstr "Sluchátko"
+
+msgid "Line Out"
+msgstr "Linkový výstup"
+
+msgid "SPDIF Out"
+msgstr "Výstup SPDIF"
+
+msgid "AUX 1 Out"
+msgstr "Výstup AUX 1"
+
+msgid "AUX 2 Out"
+msgstr "Výstup AUX 2"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Chyba při čtení %d bajtů na zařízení „%s“."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Selhalo vytvoření seznamu možných formátů videa, se kterými umí zařízení "
+"„%s“ pracovat"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Nezdařilo se mapování vyrovnávací paměti ze zařízení „%s“"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Ovladač zařízení „%s“ nepodporuje V/V metodu %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Ovladač zařízení „%s“ nepodporuje žádnou známou V/V metodu."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Zařízení „%s“ je zaneprázdněno"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Zařízení „%s“ neumí zachytávat v rozměru %d × %d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Zařízení „%s“ neumí zachytávat v tomto konkrétním formátu"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Zařízení „%s“ nepodporuje nesousedící složky obrazu"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Nezdařilo se zjištění parametrů na zařízení „%s“"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "Videozařízení nepřijalo nové nastavení snímkové rychlosti."
+
+msgid "Video device did not provide output format."
+msgstr "Videozařízení neposkytuje výstupní formát."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Videozařízení sdělilo neplatné rozměry."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Videozařízení používá nepodporovanou metodu prokládání."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Videozařízení používá nepodporovaný rastrový formát."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Selhalo nastavení vnitřní společné vyrovnávací paměti."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Videozařízení nedoporučuje nijakou velikost vyrovnávací paměti."
+
+msgid "No downstream pool to import from."
+msgstr "Neexistuje žádný společný proud dat, ze kterého by šlo importovat."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Selhalo zjištění nastavení tuneru %d u zařízení „%s“."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Chyba při zjišťování schopností zařízení „%s“."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Zařízení „%s“ není tuner."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Selhalo získání rádiového vstupu u zařízení „%s“."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Nezdařilo se nastavení vstupu %d u zařízení „%s“."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Selhala změna stavu zapnutí/vypnutí zvuku u zařízení „%s“."
+
+msgid "Failed to allocated required memory."
+msgstr "Selhalo přidělení požadované paměti."
+
+msgid "Failed to allocate required memory."
+msgstr "Selhalo přidělení požadované paměti."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Převodník na zařízení „%s“ nepodporuje vstupní formát"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Převodník na zařízení „%s“ nepodporuje výstupní formát"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Kodér na zařízení „%s“ nepodporuje vstupní formát"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Kodér na zařízení „%s“ nepodporuje výstupní formát"
+
+msgid "Failed to start decoding thread."
+msgstr "Selhalo spuštění vlákna dekodéru."
+
+msgid "Failed to process frame."
+msgstr "Selhalo zpracování snímku."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Chyba při získávání informací o schopnostech u zařízení „%s“: Nejedná se o "
+"ovladač v4l2. Zkontrolujte, zda se nejedná o ovladač v4l1."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Nezdařilo se dotázání na vlastnosti vstupu %d u zařízení „%s“"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Selhalo zjištění nastavení tuneru %d u zařízení „%s“."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Nezdařilo se dotázání na normu na zařízení „%s“."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Nezdařilo se zjištění vlastností ovládacích prvků u zařízení „%s“."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Nezdařilo se rozpoznat zařízení „%s“."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Toto není zařízení „%s“."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Nezdařilo se otevřít zařízení „%s“ pro čtení a zápis."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Zařízení „%s“ není zachytávacím zařízením."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Zařízení „%s“ není výstupním zařízením."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Zařízení „%s“ není zařízením M2M."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Nezdařilo se duplikovat zařízení „%s“ pro čtení a zápis."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Selhalo nastavení normy u zařízení „%s“."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Selhalo zjištění aktuální frekvence tuneru u zařízení „%s“."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr "Selhalo nastavení aktuální frekvence tuneru u zařízení „%s“ na %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Selhalo zjištění síly signálu u zařízení „%s“."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Selhalo zjištění hodnoty u ovládacího prvku %d na zařízení „%s“."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Selhalo nastavení hodnoty %d u ovládacího prvku %d na zařízení „%s“."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Selhalo získání aktuálního vstupu na zařízení „%s“. Možná se jedná o "
+"radiopřijímač."
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Selhalo získání aktuálního výstupu na zařízení „%s“. Možná se jedná o "
+"radiopřijímač"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Selhalo nastavení výstupu %d na zařízení %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Změna rozlišení za běhu zatím není podporována."
+
+msgid "Cannot operate without a clock"
+msgstr "Není možné fungovat bez hodin"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Vnitřní chyba datového proudu."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Vnitřní chyba datového toku."
diff --git a/po/da.po b/po/da.po
new file mode 100644
index 0000000..9872c21
--- /dev/null
+++ b/po/da.po
@@ -0,0 +1,438 @@
+# Danish translation of gst-plugins-good.
+# Copyright (C) 2016 gst.
+# This file is distributed under the same license as the gst-plugins-good package.
+# Mogens Jaeger <mogens@jaeger.tf>, 2007.
+# Joe Hansen <joedalton2@yahoo.dk>, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016.
+#
+# gain -> forhøjelse
+# boost -> øgning?
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good-1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-03-27 23:54+0200\n"
+"Last-Translator: Joe Hansen <joedalton2@yahoo.dk>\n"
+"Language-Team: Danish <dansk@dansk-gruppen.dk>\n"
+"Language: da\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Jack server not found"
+msgstr "Jack-server blev ikke fundet"
+
+msgid "Failed to decode JPEG image"
+msgstr "Mislykkedes i at afkode JPEG-billede"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "»%s« af »%s«"
+
+msgid "Could not connect to server"
+msgstr "Kunne ikke forbinde til server"
+
+msgid "No URL set."
+msgstr "Ingen adresse angivet."
+
+msgid "Could not resolve server name."
+msgstr "Kunne ikke slå servernavn op."
+
+msgid "Could not establish connection to server."
+msgstr "Kunne ikke skabe kontakt til serveren."
+
+msgid "Secure connection setup failed."
+msgstr "Opsætning af sikker forbindelse mislykkedes."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Der opstod en netværksfejl, eller serveren lukkede uventet forbindelsen."
+
+msgid "Server sent bad data."
+msgstr "Server sendte ugyldige data."
+
+msgid "Server does not support seeking."
+msgstr "Server understøtter ikke søgning."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Ingen eller defekt inddatalyd, AVI-sekvens vil blive ødelagt."
+
+msgid "This file contains no playable streams."
+msgstr "Denne fil indeholder ingen spilbar strøm."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Denne fil er ufuldstændig og kan ikke afspilles."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr "Kan ikke afspille strøm, da den er krypteret med PlayReady DRM."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Denne fil er ødelagt og kan ikke afspilles."
+
+msgid "Invalid atom size."
+msgstr "Ugyldig atomstørrelse."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Denne fil er ufuldstændig og kan ikke afspilles."
+
+msgid "The video in this file might not play correctly."
+msgstr "Videoen i denne fil afspilles måske ikke korrekt."
+
+# hvad er %d i dette program? Umiddelbart ville jeg tro det skulle
+# hedde, "Afpiller kun første %d" men det kommer selvfølgelig an på 
+# sammenhængen.
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Denne fil indeholder for mange strømme. Afspil først kun %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Ingen understøttet strøm blev fundet. Du skal måske installere et "
+"udvidelsesmodul for GStreamer RTSP til Real media-strømme."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Ingen understøttet strøm blev fundet. Du mangler måske at tillade yderligere "
+"transportprotokoller eller mangler måske det korrekte udvidelsesmodul til "
+"GStreamer RTSP."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Kunne ikke åbne lydenhed til afspilning. Enheden anvendes af et andet "
+"program."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Kunne ikke åbne lydenhed til afspilning. Du har ikke rettighed til at åbne "
+"enheden."
+
+msgid "Could not open audio device for playback."
+msgstr "Kunne ikke åbne enhed til afspilning."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Kunne ikke åbne lydenhed til afspilning. Denne version af Open Sound System "
+"er ikke understøttet af dette element."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Afspilning er ikke understøttet af denne lydenhed."
+
+msgid "Audio playback error."
+msgstr "Fejl ved lydafspilning."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Optagelse er ikke understøttet af denne lydenhed."
+
+msgid "Error recording from audio device."
+msgstr "Fejl ved optagelse fra lydenhed."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Kunne ikke åbne lydenhed til optagelse. Du har ikke rettighed til at åbne "
+"enheden."
+
+msgid "Could not open audio device for recording."
+msgstr "Kunne ikke åbne lydenhed til optagelse."
+
+msgid "CoreAudio device not found"
+msgstr "CoreAudio-enhed blev ikke fundet"
+
+msgid "CoreAudio device could not be opened"
+msgstr "CoreAudio-enhed kunne ikke åbnes"
+
+msgid "Record Source"
+msgstr "Optagelseskilde"
+
+msgid "Microphone"
+msgstr "Mikrofon"
+
+msgid "Line In"
+msgstr "Linje ind"
+
+msgid "Internal CD"
+msgstr "Intern cd"
+
+msgid "SPDIF In"
+msgstr "SPDIF ind"
+
+msgid "AUX 1 In"
+msgstr "AUX 1 ind"
+
+msgid "AUX 2 In"
+msgstr "AUX 2 ind"
+
+msgid "Codec Loopback"
+msgstr "Codec-loopback"
+
+msgid "SunVTS Loopback"
+msgstr "SunVTS-loopback"
+
+msgid "Volume"
+msgstr "Lydstyrke"
+
+msgid "Gain"
+msgstr "Forhøjelse"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "Indbygget højtaler"
+
+msgid "Headphone"
+msgstr "Hovedtelefon"
+
+msgid "Line Out"
+msgstr "Linje ud"
+
+msgid "SPDIF Out"
+msgstr "SPDIF ud"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1 ud"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2 ud"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Fejl ved læsning af %d byte på enhed »%s«."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Kunne ikke nummerere mulig videoformater som enhed »%s« kan fungere med"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Kunne ikke afbilde mellemlager fra enhed »%s«"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Driveren til enhed »%s« understøtter ikke IO-metoden %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Driveren til enhed »%s« understøtter ingen kendt IO-metode."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Enheden »%s« er optaget"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Enheden »%s« kan ikke optage med %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Enheden »%s« kan ikke optage i det angivne format"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Enheden »%s« understøtter ikke planer, der ikke hænger sammen"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Kunne ikke hente parametre fra enhed »%s«"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "Videoenheden accepterede ikke ny indstilling for billedrate."
+
+msgid "Video device did not provide output format."
+msgstr "Videoenheden angav ikke uddataformat."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Videoenhed returnerede ugyldige dimensioner."
+
+# http://en.wikipedia.org/wiki/Interlaced_video
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Videoenheder bruger en interlace-metode, der ikke er understøttet."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Videoenheder bruger et billedpunktsformat, der ikke er understøttet."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Kunne ikke konfigurere intern mellemlagerkø."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Videoenhed foreslog ikke en mellemlagerstørrelse."
+
+msgid "No downstream pool to import from."
+msgstr "Ingen nedstrømskø at importere fra."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Hentning af indstillinger for tuner %d på enhed »%s« fejlede."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Fejl under hentning af kapaciteter for enhed »%s«."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Enhed »%s« er ikke en tuner."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Kunne ikke hente radioinddata for enhed »%s«."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Kunne ikke sætte inddata %d for enhed %s."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Kunne ikke ændre tilstand for tænk/slut for enhed »%s«."
+
+msgid "Failed to allocated required memory."
+msgstr "Kunne ikke allokere den krævede hukommelse."
+
+msgid "Failed to allocate required memory."
+msgstr "Kunne ikke allokere den krævede hukommelse."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+"Konverteringsprogram på enhed %s har ikke et understøttet inddataformat"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Konverteringsprogram på enhed %s har ikke et understøttet uddataformat"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Koder på enhed %s har ikke et understøttet inddataformat"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Koder på enhed %s har ikke et understøttet uddataformat"
+
+msgid "Failed to start decoding thread."
+msgstr "Kunne ikke starte afkodning af tråd."
+
+msgid "Failed to process frame."
+msgstr "Kunne ikke behandle billed."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Fejl ved hentning af egenskaber for enhed »%s«: Det er ikke en v412 driver. "
+"Kontroller om det er en v411 driver."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Listning af inddata-attributter for %d i enhed %s fejlede"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Hentning af indstillinger for tuner %d på enhed »%s« fejlede."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Listning af standard på enhed »%s« fejlede."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Hentning af kontrolattributter for enhed »%s« fejlede."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Kan ikke identificere enhed »%s«."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Dette er ikke en enheds »%s«."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Kunne ikke tilgå enhed »%s«."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Enhed »%s« er ikke en optageenhed."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Enhed »%s« er ikke en uddataenhed."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Enhed »%s« er ikke en M2M-enhed."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Kunne ikke dup enhed »%s« for læsning og skrivning."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Indstilling af standard for enhed »%s« fejlede."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Kunne ikke hente nuværende tuner-frekvens for enhed »%s«."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr "Kunne ikke sætte nuværende tuner-frekvens for enhed »%s« til %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Kunne ikke hente signalstyrke for enhed »%s«."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Kunne ikke hente værdi af kontrol %d for enhed »%s«."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Kunne ikke sætte værdi %d på kontrol %d for enhed »%s«."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Kunne ikke hente nuværende inddata for enhed »%s«. Måske er det en radioenhed"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Kunne ikke hente nuværende uddata for enhed »%s«. Måske er det en radioenhed"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Kunne ikke sætte uddata %d for enhed %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Ændring af opløsning under kørsel er endnu ikke understøttet."
+
+msgid "Cannot operate without a clock"
+msgstr "Kan ikke fungere uden et ur"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Intern datastrømsfejl."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Intern datastrømsfejl."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Enheden »%s« understøtter ikke videooptagelse"
diff --git a/po/de.po b/po/de.po
new file mode 100644
index 0000000..ad3e2c6
--- /dev/null
+++ b/po/de.po
@@ -0,0 +1,837 @@
+# German translations for gst-plugins-good 1.3.90
+# Copyright (C) 2007 Free Software Foundation, Inc.
+# This file is distributed under the same license as the gst-plugins-good package.
+#
+# PCM = PCM
+# Line-in = Line-Eingang
+# Line-out = Line-Ausgang
+# Pipeline = Weiterleitung
+# Stream = Strom
+# mixer  = Mischer
+# Christian Kirbach <christian.kirbach@gmail.com>, 2010, 2011, 2012, 2013, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-02-22 23:42+0100\n"
+"Last-Translator: Christian Kirbach <christian.kirbach@gmail.com>\n"
+"Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Poedit 1.8.7\n"
+
+msgid "Jack server not found"
+msgstr "Jack-Server nicht gefunden"
+
+msgid "Failed to decode JPEG image"
+msgstr "Dekodieren des JPEG-Bildes schlug fehl"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "»%s« durch »%s«"
+
+msgid "Could not connect to server"
+msgstr "Verbindung zum Server konnte nicht hergestellt werden"
+
+msgid "No URL set."
+msgstr "Keine Adresse festgelegt."
+
+msgid "Could not resolve server name."
+msgstr "Servername konnte nicht aufgelöst werden."
+
+msgid "Could not establish connection to server."
+msgstr "Es konnte keine Verbindung zum Server hergestellt werden."
+
+msgid "Secure connection setup failed."
+msgstr "Aufbau einer sichern Verbindung ist gescheitert."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Ein Netzwerkfehler ist aufgetreten, oder der Server schloss die Verbindung "
+"unerwartet."
+
+msgid "Server sent bad data."
+msgstr "Server gab unerwartete Daten zurück."
+
+msgid "Server does not support seeking."
+msgstr "Suchlauf wird nicht vom Server unterstützt."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Kein oder ungültiger Eingabeton, der AVI-Strom wird fehlerhaft sein."
+
+msgid "This file contains no playable streams."
+msgstr "Diese Datei enthält keine abspielbaren Ströme."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Diese Datei ist ungültig und kann nicht wiedergegeben werden."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+"Der Strom kann nicht wiedergegeben werden, weil er mit PlayReady DRM "
+"verschlüsselt ist."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Diese Datei ist beschädigt und kann nicht wiedergegeben werden."
+
+msgid "Invalid atom size."
+msgstr "Ungültige Atom-Größe."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Diese Datei ist unvollständig und kann nicht wiedergegeben werden."
+
+msgid "The video in this file might not play correctly."
+msgstr "Das Video in dieser Datei wird vielleicht nicht korrekt wiedergegeben."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+"Diese Datei enthält zu viele Ströme. Es werden nur die ersten %d "
+"wiedergegeben"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Es wurde kein unterstützter Strom gefunden. Sie müssen vielleicht ein Plugin "
+"zur RTSP-Erweiterung von GStreamer für »Real«-Medienströme installieren."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Es wurde kein unterstützter Strom gefunden. Sie müssen eventuell zusätzliche "
+"Transport-Protokolle erlauben oder es fehlt vielleicht das richtige Plugin "
+"zur RTSP-Erweiterung."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Das Audio-Gerät konnte nicht zur Wiedergabe geöffnet werden. Das Gerät wird "
+"von einer anderen Anwendung verwendet."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Das Audio-Gerät konnte nicht zur Wiedergabe geöffnet werden. Sie haben nicht "
+"die Berechtigungen zum Öffnen des Gerätes."
+
+msgid "Could not open audio device for playback."
+msgstr "Das Audio-Gerät konnte nicht zur Wiedergabe geöffnet werden. "
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Das Audio-Gerät konnte nicht zur Wiedergabe geöffnet werden. Diese Version "
+"des Open Sound System (OSS) wird nicht von diesem Element unterstützt."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Wiedergabe wird von diesem Audio-Gerät nicht unterstützt."
+
+msgid "Audio playback error."
+msgstr "Fehler bei Audio-Wiedergabe."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Aufnahme wird von diesem Audio-Gerät nicht unterstützt."
+
+msgid "Error recording from audio device."
+msgstr "Fehler beim Aufnehmen vom Audio-Gerät."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Das Audio-Gerät konnte nicht zur Aufnahme geöffnet werden. Sie haben nicht "
+"die Berechtigungen zum Öffnen des Gerätes."
+
+msgid "Could not open audio device for recording."
+msgstr "Das Audio-Gerät konnte nicht zur Aufnahme geöffnet werden. "
+
+msgid "CoreAudio device not found"
+msgstr "CoreAudio-Gerät nicht gefunden"
+
+msgid "CoreAudio device could not be opened"
+msgstr "CoreAudio-Gerät konnte nicht geöffnet werden"
+
+msgid "Record Source"
+msgstr "Aufnahmequelle"
+
+msgid "Microphone"
+msgstr "Mikrofon"
+
+msgid "Line In"
+msgstr "Line-Eingang"
+
+msgid "Internal CD"
+msgstr "Interne CD"
+
+msgid "SPDIF In"
+msgstr "SPDIF-Eingang"
+
+msgid "AUX 1 In"
+msgstr "AUX-Eingang 1"
+
+msgid "AUX 2 In"
+msgstr "AUX-Eingang 2"
+
+msgid "Codec Loopback"
+msgstr "Codec-Rückschleife"
+
+msgid "SunVTS Loopback"
+msgstr "SunVTS-Rückschleife"
+
+msgid "Volume"
+msgstr "Lautstärke"
+
+msgid "Gain"
+msgstr "Pegel"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "Eingebauter Lautsprecher"
+
+msgid "Headphone"
+msgstr "Kopfhörer"
+
+# Hier ist mir noch nichts Besseres eingefallen.
+msgid "Line Out"
+msgstr "Ausgang"
+
+msgid "SPDIF Out"
+msgstr "SPDIF-Ausgang"
+
+msgid "AUX 1 Out"
+msgstr "AUX-Ausgang 1"
+
+msgid "AUX 2 Out"
+msgstr "AUX-Ausgang 2"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Fehler beim Lesen von %d Bytes von Gerät »%s«."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Aufzählen möglicher Videoformate, mit denen Gerät »%s« arbeiten kann, schlug "
+"fehl"
+
+# »Geholt« ist auch noch nicht optimal, aber »abgebildet« geht auch nicht wirklich.
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Die Puffer des Gerätes »%s« konnten nicht geholt werden."
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Der Treiber von Gerät »%s« unterstützt nicht die EA-Methode %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Der Treiber von Gerät »%s« unterstützt keine bekannte EA-Methode"
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Gerät »%s« ist belegt"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Das Gerät »%s« kann nicht bei %dx%d aufnehmen"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Das angegebene Format kann nicht vom Gerät »%s« ausgelesen werden"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Gerät »%s« unterstützt getrennte Ebenen"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Parameter konnten nicht von Gerät »%s« ausgelesen werden"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+"Das Video-Eingabegerät akzeptierte nicht die neue Einstellung zur "
+"Bildwiederholungsrate."
+
+msgid "Video device did not provide output format."
+msgstr "Das Video-Gerät gab kein Ausgabeformat an."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Das Video-Gerät gab ungültige Abmessungen zurück."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+"Video-Geräte verwendet eine nicht unterstützt Methode der "
+"Zeilenverschachtelung."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Das Video-Gerät verwendet ein nicht unterstütztes Pixelformat."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Einrichten des internen Puffer-Pools ist fehlgeschlagen."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Das Videogerät gab keine Puffer-Größe an."
+
+msgid "No downstream pool to import from."
+msgstr "Es gibt keinen Downstream-Pool, aus dem importiert werden kann."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr ""
+"Auslesen der Einstellungen von Empfänger »%d« auf Gerät »%s« schlug fehl."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Fehler beim Ermitteln der Funktionsmerkmale von Gerät »%s«."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "»%s« ist kein Empfänger."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Empfangen eines Funksignals auf Gerät »%s« schlug fehl."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Festlegen der Eingabe »%d« des Geräts »%s« schlug fehl."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Ändern des Stummzustands von Gerät »%s« schlug fehl."
+
+msgid "Failed to allocated required memory."
+msgstr "Anfordern des benötigen Arbeitsspeichers schlug fehl."
+
+msgid "Failed to allocate required memory."
+msgstr "Anfordern des benötigen Arbeitsspeichers schlug fehl."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Der Umwandler auf Gerät %s hat kein unterstütztes Eingabeformat"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Der Umwandler auf Gerät %s hat kein unterstütztes Ausgabeformat"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Der Kodierer auf Gerät %s hat kein unterstütztes Eingabeformat"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Der Kodierer auf Gerät %s hat kein unterstütztes Ausgabeformat"
+
+msgid "Failed to start decoding thread."
+msgstr "Beginn der Dekodierung des JPEG-Bildes schlug fehl"
+
+msgid "Failed to process frame."
+msgstr "Verarbeiten des Einzelbilds schlug fehl."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Fehler beim Bestimmen der Fähigkeiten des Geräts »%s«: Es ist kein »v4l2«-"
+"Treiber. Überprüfen Sie, ob es ein »v4l1«-Treiber ist."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Abfrage der Attribute der Eingabe »%d« im Gerät »%s« schlug fehl"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr ""
+"Auslesen der Einstellungen der Senderwahl »%d« auf Gerät »%s« schlug fehl."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Abfragen der Norm auf Gerät »%s« schlug fehl."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Abfrage der Kontrollattribute auf Gerät »%s« schlug fehl."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Gerät »%s« kann nicht identifiziert werden."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "»%s« ist kein Gerät."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Gerät »%s« konnte nicht zum Lesen oder Schreiben geöffnet werden."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "»%s« ist kein Aufnahmegerät."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "»%s« ist kein Wiedergabegerät."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Gerät »%s« ist kein M2M-Gerät."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Gerät »%s« konnte nicht zum Lesen oder Schreiben geöffnet werden."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Festlegen der Norm auf Gerät »%s« schlug fehl."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Auslesen der aktuellen Sendefrequenz des Geräts »%s« schlug fehl."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Festlegen der aktuellen Sendefrequenz des Geräts »%s« auf %lu Hz schlug fehl."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Auslesen der aktuellen Signalstärke des Geräts »%s« schlug fehl."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Auslesen des Wertes der Einstellung »%d« des Geräts »%s« schlug fehl."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr ""
+"Festlegen des Wertes »%d« der Einstellung »%d« des Geräts »%s« schlug fehl."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Auslesen der aktuellen Eingabe auf dem Gerät »%s« schlug fehl. Vielleicht "
+"ist es ein Funkgerät."
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Auslesen der aktuellen Ausgabe des Geräts »%s« schlug fehl. Vielleicht ist "
+"es ein Funkgerät."
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Festlegen der Ausgabe »%d« des Geräts »%s« schlug fehl."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Ein Wechsel der Auflösung zur Laufzeit wird noch nicht unterstützt."
+
+# Taktgeber klingt gut.
+msgid "Cannot operate without a clock"
+msgstr "Es kann nicht ohne einen Taktgeber gearbeitet werden."
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Interner Datenstromfehler."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Interner Datenstromfehler."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Gerät »%s« unterstützt keine Videoaufnahme"
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Es konnte keine Verbindung zum Audio-Server hergestellt werden"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Abfrage der Fähigkeiten des Audio-Servers ist fehlgeschlagen"
+
+#~ msgid "Bass"
+#~ msgstr "Bass"
+
+#~ msgid "Treble"
+#~ msgstr "Höhen"
+
+#~ msgid "Synth"
+#~ msgstr "Synth"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Lautsprecher"
+
+#~ msgid "Line-in"
+#~ msgstr "Line-Eingang"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Mischer"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM 2"
+
+#~ msgid "Record"
+#~ msgstr "Aufnahme"
+
+#~ msgid "In-gain"
+#~ msgstr "Eingangspegel"
+
+#~ msgid "Out-gain"
+#~ msgstr "Ausgangspegel"
+
+#~ msgid "Line-1"
+#~ msgstr "Eingang-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Eingang-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Eingang-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Digital-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Digital-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Digital-3"
+
+# Mikrofon? Zweifelhaft. Eher Kopfhörer oder Telefon.
+#~ msgid "Phone-in"
+#~ msgstr "Mikrofoneingang"
+
+# Ist hier Kopfhörer oder Telefon gemeint?
+#~ msgid "Phone-out"
+#~ msgstr "Mikrofonausgang"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Radio"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "Das Audio-Gerät konnte nicht für das Mischpult geöffnet werden."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Das Audio-Gerät konnte nicht für das Mischpult geöffnet werden. Diese "
+#~ "Version des Open Sound System (OSS) wird nicht unterstützt."
+
+#~ msgid "Master"
+#~ msgstr "Hauptregler"
+
+#~ msgid "Front"
+#~ msgstr "Front"
+
+#~ msgid "Rear"
+#~ msgstr "AufnahmeRückseite"
+
+#~ msgid "Headphones"
+#~ msgstr "Kopfhörer"
+
+#~ msgid "Center"
+#~ msgstr "Mitte"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Surround"
+
+#~ msgid "Side"
+#~ msgstr "Seite"
+
+#~ msgid "AUX Out"
+#~ msgstr "AUX-Ausgang"
+
+#~ msgid "3D Depth"
+#~ msgstr "3D-Tiefe"
+
+#~ msgid "3D Center"
+#~ msgstr "3D-Mitte"
+
+#~ msgid "3D Enhance"
+#~ msgstr "Erweitertes 3D"
+
+#~ msgid "Telephone"
+#~ msgstr "Telefon"
+
+#~ msgid "Video In"
+#~ msgstr "Video-Eingang"
+
+#~ msgid "AUX In"
+#~ msgstr "AUX-Eingang"
+
+#~ msgid "Record Gain"
+#~ msgstr "Aufnahmepegel"
+
+#~ msgid "Output Gain"
+#~ msgstr "Ausgangspegel"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Mikrofonverstärkung"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Zur Diagnose"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Bassverstärkung"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Wiedergabe-Ports"
+
+#~ msgid "Input"
+#~ msgstr "Eingang"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Überwachungsquelle"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Tastatur-Piepsen"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Stereo simulieren"
+
+#~ msgid "Stereo"
+#~ msgstr "Stereo"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Surround-Audio"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Mikrofonpegel"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Lautsprecherquelle"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Mikrofonquelle"
+
+#~ msgid "Jack"
+#~ msgstr "Stecker"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Mitte / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Stereo-Mischpult"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Mono-Mischpult"
+
+#~ msgid "Input Mix"
+#~ msgstr "Eingangs-Mischpult"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Mikrofon 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Mikrofon 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Digital-Ausgang"
+
+#~ msgid "Digital In"
+#~ msgstr "Digital-Eingang"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modem"
+
+#~ msgid "Handset"
+#~ msgstr "Hörer"
+
+#~ msgid "Other"
+#~ msgstr "Anderes"
+
+#~ msgid "None"
+#~ msgstr "Kein"
+
+#~ msgid "On"
+#~ msgstr "Aktiviert"
+
+#~ msgid "Off"
+#~ msgstr "Deaktiviert"
+
+#~ msgid "Mute"
+#~ msgstr "Stumm"
+
+#~ msgid "Fast"
+#~ msgstr "Schnell"
+
+#~ msgid "Very Low"
+#~ msgstr "Sehr niedrig"
+
+#~ msgid "Low"
+#~ msgstr "Niedrig"
+
+#~ msgid "Medium"
+#~ msgstr "Medium"
+
+#~ msgid "High"
+#~ msgstr "Hoch"
+
+#~ msgid "Very High"
+#~ msgstr "Sehr hoch"
+
+#~ msgid "Production"
+#~ msgstr "Produktion"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Mikrofon am Vordereingang"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Line-Eingang am Vordereingang"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Kopfhörer am Vordereingang"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Line-Ausgang am Vordereingang"
+
+#~ msgid "Green Connector"
+#~ msgstr "Grüner Stecker"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Rosa Stecker"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Blauer Stecker"
+
+#~ msgid "White Connector"
+#~ msgstr "Weißer Stecker"
+
+#~ msgid "Black Connector"
+#~ msgstr "Schwarzer Stecker"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Grauer Stecker"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Oranger Stecker"
+
+#~ msgid "Red Connector"
+#~ msgstr "Roter Stecker"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Gelber Stecker"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Grüner Stecker am Vordereingang"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Rosa Stecker am Vordereingang"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Blauer Stecker am Vordereingang"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Weißer Stecker am Vordereingang"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Schwarzer Stecker am Vordereingang"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Grauer Stecker am Vordereingang"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Oranger Stecker am Vordereingang"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Roter Stecker am Vordereingang"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Gelber Stecker am Vordereingang"
+
+#~ msgid "Spread Output"
+#~ msgstr "Ausgabe verstreuen"
+
+#~ msgid "Downmix"
+#~ msgstr "Heruntermischen"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Eingang des virtuellen Mischpults"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Ausgang des virtuellen Mischpults"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Kanäle des virtuellen Mischpults"
+
+#~ msgid "%s %d Function"
+#~ msgstr "%s %d Function"
+
+#~ msgid "%s Function"
+#~ msgstr "%s-Funktion"
+
+# »Frame« sollten wir im Zusammenhang mit Videos vielleicht besser so belassen. Habe ich in gnome-subtitles auch so gemacht.
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Unerwartete Frame-Größe von %u anstatt %u wurde erhalten."
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Fehler beim Lesen von %d Bytes auf Gerät »%s«."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Auf Gerät »%s« konnten keine Puffer eingereiht werden."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Der Versuch Videobilder von Gerät »%s« auszulesen schlug fehl."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "%d Versuche sind fehlgeschlagen. Gerät »%s«. Systemfehler: %s"
+
+#~ msgid ""
+#~ "The buffer type is not supported, or the index is out of bounds, or no "
+#~ "buffers have been allocated yet, or the userptr or length are invalid. "
+#~ "device %s"
+#~ msgstr ""
+#~ "Der Puffertyp wird nicht unterstützt, der Index ist außerhalb seiner "
+#~ "Grenzwerte, es sind bisher noch keine Puffer angefordert worden oder "
+#~ "»userptr« oder die Länge sind ungültig. Gerät »%s«"
+
+#~ msgid ""
+#~ "Failed trying to get video frames from device '%s'. Not enough memory."
+#~ msgstr ""
+#~ "Der Versuch Videobilder von Gerät »%s« auszulesen schlug fehl. Nicht "
+#~ "genug Arbeitsspeicher."
+
+# Was ist ein Zeigerpuffer?
+#, fuzzy
+#~ msgid "insufficient memory to enqueue a user pointer buffer. device %s."
+#~ msgstr ""
+#~ "Ungenügend Arbeitsspeicher, um einen Zeigerpuffer eines Benutzers "
+#~ "einzureihen. Gerät »%s«."
+
+#~ msgid "No free buffers found in the pool at index %d."
+#~ msgstr "Es wurden keine freien Puffer im Vorrat bei Index %d gefunden."
+
+#~ msgid "Could not get buffers from device '%s'."
+#~ msgstr "Die Puffer konnten nicht von Gerät »%s« ausgelesen werden."
+
+#~ msgid "Could not get enough buffers from device '%s'."
+#~ msgstr "Es konnten nicht genug Puffer von Gerät »%s« ausgelesen werden."
diff --git a/po/el.po b/po/el.po
new file mode 100644
index 0000000..8050179
--- /dev/null
+++ b/po/el.po
@@ -0,0 +1,806 @@
+# Greek translation for gst-plugins-good package of GStreamer project.
+# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 GStreamer core team
+# This file is distributed under the same license as the gst-plugins-good package.
+# Simos Xenitellis <simos.lists@googlemail.com>, 2009.
+# Michael Kotsarinis <mk73628@gmail.com>, 2010
+# Savvas Radevic <vicedar@gmail.com>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 0.10.28.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2012-05-05 19:05+0100\n"
+"Last-Translator: Savvas Radevic <vicedar@gmail.com>\n"
+"Language-Team: Greek <team@lists.gnome.gr>\n"
+"Language: el\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
+"X-Generator: Lokalize 0.3\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr "Αποτυχία αποκωδικοποίησης της εικόνας JPEG"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "'%s' από '%s'"
+
+msgid "Could not connect to server"
+msgstr "Δεν ήταν δυνατή η σύνδεση με τον διακομιστή"
+
+msgid "No URL set."
+msgstr "Δεν ορίσθηκε URL."
+
+msgid "Could not resolve server name."
+msgstr "Δεν ήταν δυνατός ο προσδιορισμός του ονόματος του διακομιστή."
+
+msgid "Could not establish connection to server."
+msgstr "Δεν ήταν δυνατή η σύνδεση με τον διακομιστή."
+
+msgid "Secure connection setup failed."
+msgstr "Αποτυχία εκκίνησης ασφαλούς σύνδεσης."
+
+#, fuzzy
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Προέκυψε ένα σφάλμα δικτύου ή ο διακομιστής έκλεισε ξαφνικά τη σύνδεση."
+
+msgid "Server sent bad data."
+msgstr "Ο διακομιστής έστειλε λάθος δεδομένα."
+
+msgid "Server does not support seeking."
+msgstr "Ο διακομιστής δεν υποστηρίζει αναζήτηση."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Καμία ή άκυρη εισαγωγή ήχου, η AVI ροή θα καταρρεύσει."
+
+msgid "This file contains no playable streams."
+msgstr "Αυτό το αρχείο δεν περιέχει αναπαραγώγιμες ροές."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Το αρχείο αυτό δεν είναι έγκυρο και δεν μπορεί να αναπαραχθεί."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Το αρχείο αυτό είναι κατεστραμμένο και δεν μπορεί να αναπαραχθεί. "
+
+msgid "Invalid atom size."
+msgstr "Άκυρο μέγεθος ατόμου."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Το αρχείο αυτό είναι ανολοκλήρωτο και δεν μπορεί να αναπαραχθεί."
+
+msgid "The video in this file might not play correctly."
+msgstr "Το βίντεο σε αυτό το αρχείο μπορεί να μην αναπαραχθεί σωστά."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Αυτό το αρχείο περιέχει πολλές ροές. Αναπαράγεται μόνο η πρώτη %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Δεν βρέθηκε καμία υποστηριζόμενη ροή. Είναι πιθανόν να πρέπει να κάνετε "
+"εγκατάσταση ένα πρόσθετο GStreamer RTSP για τις ροές Real μέσων. "
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Δεν βρέθηκε καμία υποστηριζόμενη ροή. Είναι πιθανόν να χρειασθεί να "
+"επιτρέψετε περισσότερα πρωτόκολλα μεταγωγής ή αλλιώς να σας λείπει το σωστό "
+"πρόσθετο RTSP του GStreamer."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Δεν ήταν δυνατό το άνοιγμα της συσκευής ήχου για αναπαραγωγή. Η συσκευή "
+"χρησιμοποιείται από μια άλλη εφαρμογή."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Δεν ήταν δυνατό το άνοιγμα της συσκευής ήχου για αναπαραγωγή. Δεν έχετε τα "
+"δικαιώματα να ανοίξετε την συσκευή."
+
+msgid "Could not open audio device for playback."
+msgstr "Δεν ήταν δυνατό το άνοιγμα της συσκευής ήχου για αναπαραγωγή. "
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Δεν ήταν δυνατό το άνοιγμα της συσκευής ήχου για αναπαραγωγή. Αυτή η έκδοση "
+"του Open Sound System δεν υποστηρίζεται από αυτό το στοιχείο."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Αυτή η συσκευή ήχου δεν υποστηρίζει αναπαραγωγή."
+
+msgid "Audio playback error."
+msgstr "Σφάλμα αναπαραγωγής ήχου"
+
+msgid "Recording is not supported by this audio device."
+msgstr "Αυτή η συσκευή ήχου δεν υποστηρίζει εγγραφή."
+
+msgid "Error recording from audio device."
+msgstr "Σφάλμα κατά την εγγραφή από τη συσκευή ήχου."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Δεν ήταν δυνατό το άνοιγμα της συσκευής ήχου για εγγραφή. Δεν έχετε τα "
+"δικαιώματα να ανοίξετε την συσκευή."
+
+msgid "Could not open audio device for recording."
+msgstr "Δεν ήταν δυνατό το άνοιγμα της συσκευής ήχου για εγγραφή. "
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "Πηγή εγγραφής"
+
+msgid "Microphone"
+msgstr "Μικρόφωνο"
+
+msgid "Line In"
+msgstr "Είσοδος γραμμής"
+
+msgid "Internal CD"
+msgstr "Εσωτερικό CD"
+
+msgid "SPDIF In"
+msgstr "Είσδος SPDIF"
+
+msgid "AUX 1 In"
+msgstr "Είσοδις AUX 1"
+
+msgid "AUX 2 In"
+msgstr "Είσοδος AUX 2"
+
+#, fuzzy
+msgid "Codec Loopback"
+msgstr "Ανατροφοδότηση"
+
+#, fuzzy
+msgid "SunVTS Loopback"
+msgstr "Ανατροφοδότηση"
+
+msgid "Volume"
+msgstr "Ένταση"
+
+msgid "Gain"
+msgstr "Κέρδος"
+
+msgid "Monitor"
+msgstr "Οθόνη"
+
+msgid "Built-in Speaker"
+msgstr "Ενσωματωμένο μεγάφωνο"
+
+msgid "Headphone"
+msgstr "Ακουστικό"
+
+msgid "Line Out"
+msgstr "Γραμμή εξόδου"
+
+msgid "SPDIF Out"
+msgstr "SPDIF Out"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1 Out"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2 Out"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Σφάλμα κατά την ανάγνωση %d bytes απο την συσκευή '%s'."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Αδυναμία χαρτογράφησης buffer για τη συσκευή '%s'"
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Ο οδηγός της συσκευής '%s' δεν υποστηρίζει κάποια γνωστή μέθοδο λήψης."
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Ο οδηγός της συσκευής '%s' δεν υποστηρίζει κάποια γνωστή μέθοδο λήψης."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Η συσκευή '%s' δεν είναι μια συσκευή λήψης."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Η συσκευή '%s' δεν είναι μια συσκευή λήψης."
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr ""
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Δεν ήταν δυνατή η ανάγνωση των παραμέτρων στην συσκευή '%s'"
+
+#, fuzzy
+msgid "Video device did not accept new frame rate setting."
+msgstr "Η συσκευή εισόδου βίντεο δεν αποδέχθηκε τη νέα ρύθμιση ταχύτητας καρέ."
+
+#, fuzzy
+msgid "Video device did not provide output format."
+msgstr "Η συσκευή εισόδου βίντεο δεν αποδέχθηκε τη νέα ρύθμιση ταχύτητας καρέ."
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Ο οδηγός της συσκευής '%s' δεν υποστηρίζει κάποια γνωστή μέθοδο λήψης."
+
+msgid "Video device uses an unsupported pixel format."
+msgstr ""
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+#, fuzzy
+msgid "Video device did not suggest any buffer size."
+msgstr "Η συσκευή εισόδου βίντεο δεν αποδέχθηκε τη νέα ρύθμιση ταχύτητας καρέ."
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Αποτυχία ανάγνωσης των ρυθμίσεων δέκτη %d στην συσκευή '%s'."
+
+#, fuzzy, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Σφάλμα κατά την ανάγνωση %d bytes απο την συσκευή '%s'."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Η συσκευή '%s' δεν είναι συσκευή εξόδου."
+
+#, fuzzy, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Αποτυχία ρύθμισης εισαγωγής %d στην συσκευή %s."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Αποτυχία ρύθμισης εισαγωγής %d στην συσκευή %s."
+
+#, fuzzy, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Αποτυχία ανάγνωσης ισχύς σήματος για την συσκευή '%s'."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Ο οδηγός της συσκευής '%s' δεν υποστηρίζει κάποια γνωστή μέθοδο λήψης."
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+
+#, fuzzy
+msgid "Failed to start decoding thread."
+msgstr "Αποτυχία αποκωδικοποίησης της εικόνας JPEG"
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Σφάλμα κατά τη λήψη δυνατοτήτων της συσκευής '%s': Δεν είναι οδηγός v4l2. "
+"Ελέγξτε αν είναι οδηγός v4l2."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Αποτυχία ανίχνευσης ιδιοτήτων της εισόδου %d στη συσκευή %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Αποτυχία ανάγνωσης των ρυθμίσεων δέκτη %d στην συσκευή '%s'."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Αποτυχία ανίχνευσης κανονικοποίησης στη συσκευή '%s'."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr ""
+"Αποτυχία κατά την ανάγνωση των χαρακτηριστικών ελέγχου στην συσκευή '%s'."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Δεν ήταν δυνατή η ταυτοποίηση της συσκευής '%s'."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Αυτή δεν είναι μια συκευή '%s'."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr ""
+"Δεν ήταν δυνατό το άνοιγμα της συσκευής '%s' για ανάγνωση και γράψιμο. "
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Η συσκευή '%s' δεν είναι μια συσκευή λήψης."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Η συσκευή '%s' δεν είναι συσκευή εξόδου."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Η συσκευή '%s' δεν είναι συσκευή εξόδου."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr ""
+"Δεν ήταν δυνατό το άνοιγμα της συσκευής '%s' για ανάγνωση και γράψιμο. "
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Αποτυχία ρύθμισης κανόνα για την συσκευή '%s'."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+"Αποτυχία ανάγνωσης της τρέχουσας συχνότητας δέκτη για την συσκευή '%s'."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Αποτυχία ρύθμισης τρέχουσας συχνότητας δέκτη για την συσκευή '%s' στα %lu Hz"
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Αποτυχία ανάγνωσης ισχύς σήματος για την συσκευή '%s'."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Αποτυχία ανάγνωσης τιμής για τον έλεγχο %d στην συσκευή '%s'."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Αποτυχία ρύθμισης τιμής %d για τον έλεγχο %d στην συσκευή '%s'."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Αποτυχία ανάγνωσης της τρέχουσας εισαγωγής στην συσκευή '%s'. Πιθανόν να "
+"είναι μια συσκευή ράδιο"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Αποτυχία ανάγνωσης της τρέχουσας εξόδου στην συσκευή '%s'. Πιθανόν να είναι "
+"μια συσκευή ράδιο"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Αποτυχία ορισμού εξόδου %d στην συσκευή %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr ""
+"Η αλλαγή της ανάλυσης κατά τη διάρκεια λειτουργίας δεν υποστηρίζεται ακόμα."
+
+msgid "Cannot operate without a clock"
+msgstr "Δεν είναι δυνατή η λειτουργία χωρίς ρολόι "
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Δεν ήταν δυνατή η σύνδεση με τον διακομιστή ήχου"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Αποτυχία αναζήτησης των δυνατοτήτων του διακομιστή ήχου"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Εσωτερικό σφάλμα ροής δεδομένων."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Εσωτερικό σφάλμα ροής δεδομένων."
+
+#~ msgid "Bass"
+#~ msgstr "Μπάσα"
+
+#~ msgid "Treble"
+#~ msgstr "Πρίμα (treble)"
+
+#~ msgid "Synth"
+#~ msgstr "Synth"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Μεγάφωνο"
+
+#~ msgid "Line-in"
+#~ msgstr "Γραμμή-εισόδου"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Μείκτης"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Εγγραφή"
+
+#~ msgid "In-gain"
+#~ msgstr "Κέρδος εισόδου"
+
+#~ msgid "Out-gain"
+#~ msgstr "Κέρδος εξόδου"
+
+#~ msgid "Line-1"
+#~ msgstr "Γραμμή-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Γραμμή-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Γραμμή-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Ψηφιακό-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Ψηφιακό-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Ψηφιακό-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Είσοδος τηλεφώνου"
+
+#~ msgid "Phone-out"
+#~ msgstr "Έξοδος τηλεφώνου"
+
+#~ msgid "Video"
+#~ msgstr "Βίντεο"
+
+#~ msgid "Radio"
+#~ msgstr "Ράδιο"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr ""
+#~ "Δεν ήταν δυνατό το άνοιγμα της συσκευής ήχου για χειρισμό του ελέγχου του "
+#~ "μίκτη. "
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Δεν ήταν δυνατό το άνοιγμα της συσκευής ήχου για χειρισμό του ελέγχου του "
+#~ "μίκτη. Αυτή η έκδοση του Open Sound System δεν υποστηρίζεται από αυτό οτ "
+#~ "στοιχείο."
+
+#~ msgid "Master"
+#~ msgstr "Γενικός (Master)"
+
+#~ msgid "Front"
+#~ msgstr "Μπροστά"
+
+#~ msgid "Rear"
+#~ msgstr "Πίσω"
+
+#~ msgid "Headphones"
+#~ msgstr "Ακουστικά"
+
+#~ msgid "Center"
+#~ msgstr "Κέντρο"
+
+#~ msgid "LFE"
+#~ msgstr "Χαμηλών συχνοτήτων (LFE)"
+
+#~ msgid "Surround"
+#~ msgstr "Περιβάλλων (Surround)"
+
+#~ msgid "Side"
+#~ msgstr "Πλευρικό"
+
+#~ msgid "AUX Out"
+#~ msgstr "Έξοδος AUX"
+
+#~ msgid "3D Depth"
+#~ msgstr "Βάθος 3D"
+
+#~ msgid "3D Center"
+#~ msgstr "Κέντρο 3D"
+
+#~ msgid "3D Enhance"
+#~ msgstr "Ενίσχυση 3D"
+
+#~ msgid "Telephone"
+#~ msgstr "Τηλέφωνο"
+
+#~ msgid "Video In"
+#~ msgstr "Είσοδος βίντεο"
+
+#~ msgid "AUX In"
+#~ msgstr "Είσοδος AUX"
+
+#~ msgid "Record Gain"
+#~ msgstr "Κέρδος Εγγραφής"
+
+#~ msgid "Output Gain"
+#~ msgstr "Κέρδος εξόδου"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Ενίσχυση μικροφώνου"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Διαγνωστικό"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Ενίσχυση χαμηλών"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Θύρες Αναπαραγωγής"
+
+#~ msgid "Input"
+#~ msgstr "Είσοδος"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Παρακολούθηση πηγής"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Ήχος πληκτρολογίου"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Προσομοίωση στέρεο"
+
+#~ msgid "Stereo"
+#~ msgstr "Στέρεο"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Ήχος Surround"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Κέρδος μικροφώνου"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Πηγή μεγαφώνου"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Πηγή μικροφώνου"
+
+#~ msgid "Jack"
+#~ msgstr "Βύσμα"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Κεντρικό / Χαμηλών συχνοτήτων"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Στερεοφωνική μίξη"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Μονοφωνική μίξη"
+
+#~ msgid "Input Mix"
+#~ msgstr "Μίξη εισόδου"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Μικρόφωνο 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Μικρόφωνο 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Ψηφιακή έξοδος"
+
+#~ msgid "Digital In"
+#~ msgstr "Ψηφιακή είσοδος"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modem"
+
+#~ msgid "Handset"
+#~ msgstr "Τηλεφωνική συσκευή"
+
+#~ msgid "Other"
+#~ msgstr "Άλλο"
+
+#~ msgid "None"
+#~ msgstr "Κανένα"
+
+#~ msgid "On"
+#~ msgstr "On"
+
+#~ msgid "Off"
+#~ msgstr "Off"
+
+#~ msgid "Mute"
+#~ msgstr "Σίγαση"
+
+#~ msgid "Fast"
+#~ msgstr "Γρήγορα"
+
+#~ msgid "Very Low"
+#~ msgstr "Πολύ χαμηλή"
+
+#~ msgid "Low"
+#~ msgstr "Χαμηλή"
+
+#~ msgid "Medium"
+#~ msgstr "Μεσαία"
+
+#~ msgid "High"
+#~ msgstr "Υψηλή"
+
+#~ msgid "Very High"
+#~ msgstr "Πολύ υψηλή"
+
+#~ msgid "Production"
+#~ msgstr "Παραγωγής"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Μικρόφωνο μπροστινού πάνελ"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Είσοδος γραμμής μπροστινού πάνελ"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Ακουστικά μπροστινού πάνελ"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Έξοδος γραμμής μπροστινού πάνελ"
+
+#~ msgid "Green Connector"
+#~ msgstr "Πράσινη υποδοχή"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Ροζ υποδοχή"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Μπλε υποδοχή"
+
+#~ msgid "White Connector"
+#~ msgstr "Λευκή υποδοχή"
+
+#~ msgid "Black Connector"
+#~ msgstr "Μαύρη υποδοχή"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Γκρι υποδοχή"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Πορτοκαλί υποδοχή"
+
+#~ msgid "Red Connector"
+#~ msgstr "Κόκκινη υποδοχή"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Κίτρινη υποδοχή"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Πράσινη υποδοχή μπροστινού πάνελ"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Ροζ υποδοχή μπροστινού πάνελ"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Μπλε υποδοχή μπροστινού πάνελ"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Λευκή υποδοχή μπροστινού πάνελ"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Μαύρη υποδοχή μπροστινού πάνελ"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Γκρι υποδοχή μπροστινού πάνελ"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Πορτοκαλί υποδοχή μπροστινού πάνελ"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Κόκκινη υποδοχή μπροστινού πάνελ"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Κίτρινη υποδοχή μπροστινού πάνελ"
+
+#~ msgid "Spread Output"
+#~ msgstr "Ευρεία έξοδος"
+
+#~ msgid "Downmix"
+#~ msgstr "Μίξη συγχώνευσης (Downmix)"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Είσοδος εικονικού μίκτη"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Έξοδος εικονικού μίκτη"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Κανάλια εικονικού μίκτη"
+
+#~ msgid "%s %d Function"
+#~ msgstr "Λειτουργία %s %d"
+
+#~ msgid "%s Function"
+#~ msgstr "Λειτουργία %s"
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Απροσδόκητο μέγεθος πλαισίου από %u αντί του %u"
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Σφάλμα κατά την ανάγνωση %d bytes στην συσκευή '%s'."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Αδυναμία θέσης σε σειρά των buffer στη συσκευή '%s'."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Αποτυχία ανάγνωσης πλαισίων βίντεο από την συσκευή '%s'."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr ""
+#~ "Αποτυχία έπειτα από %d προσπάθειες. συσκευή %s. σφάλμα συστήματος: %s"
+
+#~ msgid "Describes the selected input element."
+#~ msgstr "Περιγράφει το επιλεγμένο στοιχείο εισαγωγής."
+
+#~ msgid "Describes the selected output element for Audio/Video Conferencing."
+#~ msgstr ""
+#~ "Περιγράφει το επιλεγμένο στοιχείο εξόδου για το Audio/Video Conferencing."
+
+#~ msgid "Describes the selected output element for Music and Movies."
+#~ msgstr "Περιγράφει το επιλεγμένο στοιχείο εξόδου για μουσική και ταινίες."
+
+#~ msgid "Describes the selected output element."
+#~ msgstr "Περιγράφει το επιλεγμένο στοιχείο εξαγωγής."
diff --git a/po/en_GB.po b/po/en_GB.po
new file mode 100644
index 0000000..19bde81
--- /dev/null
+++ b/po/en_GB.po
@@ -0,0 +1,621 @@
+# English (British) translation.
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Gareth Owen <gowen72@yahoo.com>, 2004.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins 0.8.1\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2004-04-26 10:41-0400\n"
+"Last-Translator: Gareth Owen <gowen72@yahoo.com>\n"
+"Language-Team: English (British) <en_gb@li.org>\n"
+"Language: en_GB\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr ""
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr ""
+
+#, fuzzy
+msgid "Could not connect to server"
+msgstr "Could not close control device \"%s\"."
+
+msgid "No URL set."
+msgstr ""
+
+#, fuzzy
+msgid "Could not resolve server name."
+msgstr "Could not close control device \"%s\"."
+
+#, fuzzy
+msgid "Could not establish connection to server."
+msgstr "Could not close control device \"%s\"."
+
+msgid "Secure connection setup failed."
+msgstr ""
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+
+msgid "Server sent bad data."
+msgstr ""
+
+#, fuzzy
+msgid "Server does not support seeking."
+msgstr "Your oss device could not be probed correctly"
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "No or invalid input audio, AVI stream will be corrupt."
+
+msgid "This file contains no playable streams."
+msgstr ""
+
+msgid "This file is invalid and cannot be played."
+msgstr ""
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr ""
+
+msgid "Invalid atom size."
+msgstr ""
+
+msgid "This file is incomplete and cannot be played."
+msgstr ""
+
+msgid "The video in this file might not play correctly."
+msgstr ""
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+
+#, fuzzy
+msgid "Could not open audio device for playback."
+msgstr "Could not open audio device \"%s\" for writing."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+
+msgid "Playback is not supported by this audio device."
+msgstr ""
+
+msgid "Audio playback error."
+msgstr ""
+
+msgid "Recording is not supported by this audio device."
+msgstr ""
+
+msgid "Error recording from audio device."
+msgstr ""
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+
+#, fuzzy
+msgid "Could not open audio device for recording."
+msgstr "Could not open CD device for reading."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+#, fuzzy
+msgid "CoreAudio device could not be opened"
+msgstr "Your oss device could not be probed correctly"
+
+#, fuzzy
+msgid "Record Source"
+msgstr "Record"
+
+msgid "Microphone"
+msgstr "Microphone"
+
+#, fuzzy
+msgid "Line In"
+msgstr "Line-in"
+
+msgid "Internal CD"
+msgstr ""
+
+msgid "SPDIF In"
+msgstr ""
+
+msgid "AUX 1 In"
+msgstr ""
+
+msgid "AUX 2 In"
+msgstr ""
+
+msgid "Codec Loopback"
+msgstr ""
+
+msgid "SunVTS Loopback"
+msgstr ""
+
+msgid "Volume"
+msgstr "Volume"
+
+msgid "Gain"
+msgstr ""
+
+msgid "Monitor"
+msgstr "Monitor"
+
+#, fuzzy
+msgid "Built-in Speaker"
+msgstr "Speaker"
+
+msgid "Headphone"
+msgstr ""
+
+msgid "Line Out"
+msgstr ""
+
+msgid "SPDIF Out"
+msgstr ""
+
+msgid "AUX 1 Out"
+msgstr ""
+
+msgid "AUX 2 Out"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Could not get buffers from device \"%s\"."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Could not get buffers from device \"%s\"."
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr ""
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Device '%s' is busy"
+msgstr "Device \"%s\" is not a capture device."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Device \"%s\" is not a capture device."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Device \"%s\" is not a capture device."
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Device \"%s\" is not a capture device."
+
+#, fuzzy, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Could not get buffers from device \"%s\"."
+
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+
+msgid "Video device did not provide output format."
+msgstr ""
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+
+msgid "Video device uses an unsupported pixel format."
+msgstr ""
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+msgid "Video device did not suggest any buffer size."
+msgstr ""
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Could not get enough buffers from device \"%s\"."
+
+#, fuzzy, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Could not get buffers from device \"%s\"."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Device \"%s\" is not a capture device."
+
+#, fuzzy, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Could not close audio device \"%s\"."
+
+#, fuzzy, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Could not close audio device \"%s\"."
+
+#, fuzzy, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Could not get buffers from device \"%s\"."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+
+msgid "Failed to start decoding thread."
+msgstr ""
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Could not get enough buffers from device \"%s\"."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Could not write to device \"%s\"."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Could not open device \"%s\" for reading and writing."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Device \"%s\" is not a capture device."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Device \"%s\" is not a capture device."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Device \"%s\" is not a capture device."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Could not open device \"%s\" for reading and writing."
+
+#, fuzzy, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Could not get buffers from device \"%s\"."
+
+#, fuzzy, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Could not get enough buffers from device \"%s\"."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Could not close control device \"%s\"."
+
+#, fuzzy, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Could not close control device \"%s\"."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+
+#, fuzzy, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr "Could not get enough buffers from device \"%s\"."
+
+#, fuzzy, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Could not close audio device \"%s\"."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr ""
+
+msgid "Cannot operate without a clock"
+msgstr ""
+
+#, fuzzy
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Device \"%s\" is not a capture device."
+
+#, fuzzy
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Could not get enough buffers from device \"%s\"."
+
+#~ msgid "Bass"
+#~ msgstr "Bass"
+
+#~ msgid "Treble"
+#~ msgstr "Treble"
+
+#~ msgid "Synth"
+#~ msgstr "Synth"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Speaker"
+
+#~ msgid "Line-in"
+#~ msgstr "Line-in"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Mixer"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Record"
+
+#~ msgid "In-gain"
+#~ msgstr "In-gain"
+
+#~ msgid "Out-gain"
+#~ msgstr "Out-gain"
+
+#~ msgid "Line-1"
+#~ msgstr "Line-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Line-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Line-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Digital-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Digital-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Digital-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Phone-in"
+
+#~ msgid "Phone-out"
+#~ msgstr "Phone-out"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Radio"
+
+#, fuzzy
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "Could not open audio device \"%s\" for writing."
+
+#, fuzzy
+#~ msgid "Rear"
+#~ msgstr "Record"
+
+#, fuzzy
+#~ msgid "Side"
+#~ msgstr "Video"
+
+#, fuzzy
+#~ msgid "Video In"
+#~ msgstr "Video"
+
+#, fuzzy
+#~ msgid "Record Gain"
+#~ msgstr "Record"
+
+#, fuzzy
+#~ msgid "Output Gain"
+#~ msgstr "Out-gain"
+
+#, fuzzy
+#~ msgid "Microphone Boost"
+#~ msgstr "Microphone"
+
+#, fuzzy
+#~ msgid "Monitor Source"
+#~ msgstr "Monitor"
+
+#, fuzzy
+#~ msgid "Microphone Gain"
+#~ msgstr "Microphone"
+
+#, fuzzy
+#~ msgid "Speaker Source"
+#~ msgstr "Speaker"
+
+#, fuzzy
+#~ msgid "Microphone Source"
+#~ msgstr "Microphone"
+
+#, fuzzy
+#~ msgid "Microphone 1"
+#~ msgstr "Microphone"
+
+#, fuzzy
+#~ msgid "Microphone 2"
+#~ msgstr "Microphone"
+
+#, fuzzy
+#~ msgid "Digital Out"
+#~ msgstr "Digital-1"
+
+#, fuzzy
+#~ msgid "Digital In"
+#~ msgstr "Digital-1"
+
+#, fuzzy
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Microphone"
+
+#, fuzzy
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Could not get buffers from device \"%s\"."
+
+#~ msgid "Could not open file \"%s\" for writing."
+#~ msgstr "Could not open file \"%s\" for writing."
+
+#~ msgid "Error closing file \"%s\"."
+#~ msgstr "Error closing file \"%s\"."
+
+#~ msgid "Could not open file \"%s\" for reading."
+#~ msgstr "Could not open file \"%s\" for reading."
+
+#~ msgid "No filename specified."
+#~ msgstr "No filename specified."
+
+#~ msgid "Could not write to file \"%s\"."
+#~ msgstr "Could not write to file \"%s\"."
+
+#~ msgid "Could not open control device \"%s\" for writing."
+#~ msgstr "Could not open control device \"%s\" for writing."
+
+#~ msgid "Could not configure audio device \"%s\"."
+#~ msgstr "Could not configure audio device \"%s\"."
+
+#~ msgid "Could not set audio device \"%s\" to %d Hz."
+#~ msgstr "Could not set audio device \"%s\" to %d Hz."
+
+#~ msgid "Could not open video device \"%s\" for writing."
+#~ msgstr "Could not open video device \"%s\" for writing."
+
+#~ msgid "Could not close video device \"%s\"."
+#~ msgstr "Could not close video device \"%s\"."
+
+#~ msgid "OSS device \"%s\" is already in use by another program."
+#~ msgstr "OSS device \"%s\" is already in use by another program."
+
+#~ msgid "Could not access device \"%s\", check its permissions."
+#~ msgstr "Could not access device \"%s\", check its permissions."
+
+#~ msgid "Device \"%s\" does not exist."
+#~ msgstr "Device \"%s\" does not exist."
+
+#~ msgid "Could not open device \"%s\" for writing."
+#~ msgstr "Could not open device \"%s\" for writing."
+
+#~ msgid "Could not open device \"%s\" for reading."
+#~ msgstr "Could not open device \"%s\" for reading."
+
+#~ msgid "Could not open vfs file \"%s\" for reading."
+#~ msgstr "Could not open vfs file \"%s\" for reading."
+
+#, fuzzy
+#~ msgid "No filename given."
+#~ msgstr "No filename given"
+
+#, fuzzy
+#~ msgid "Could not open vfs file \"%s\" for writing: %s."
+#~ msgstr "Could not open vfs file \"%s\" for writing."
+
+#~ msgid "No filename given"
+#~ msgstr "No filename given"
+
+#~ msgid "Could not close vfs file \"%s\"."
+#~ msgstr "Could not close vfs file \"%s\"."
+
+#~ msgid "No device specified."
+#~ msgstr "No device specified."
+
+#~ msgid "Device is not open."
+#~ msgstr "Device is not open."
+
+#~ msgid "Device is open."
+#~ msgstr "Device is open."
diff --git a/po/eo.po b/po/eo.po
new file mode 100644
index 0000000..91a3fd9
--- /dev/null
+++ b/po/eo.po
@@ -0,0 +1,505 @@
+# Esperanto translation for gst-plugins-good.
+# Copyright (C) 2011 Free Software Foundation, Inc.
+# This file is distributed under the same license as the gst-plugins-good package.
+# Kristjan SCHMIDT <kristjan.schmidt@googlemail.com>, 2011.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 0.10.28.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2011-06-04 21:48+0100\n"
+"Last-Translator: Kristjan SCHMIDT <kristjan.schmidt@googlemail.com>\n"
+"Language-Team: Esperanto <translation-team-eo@lists.sourceforge.net>\n"
+"Language: eo\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr ""
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "'%s' de '%s'"
+
+msgid "Could not connect to server"
+msgstr "Ne eblis konekti al servilo"
+
+msgid "No URL set."
+msgstr ""
+
+msgid "Could not resolve server name."
+msgstr ""
+
+msgid "Could not establish connection to server."
+msgstr ""
+
+msgid "Secure connection setup failed."
+msgstr ""
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+
+msgid "Server sent bad data."
+msgstr ""
+
+msgid "Server does not support seeking."
+msgstr ""
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr ""
+
+msgid "This file contains no playable streams."
+msgstr ""
+
+msgid "This file is invalid and cannot be played."
+msgstr ""
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr ""
+
+msgid "Invalid atom size."
+msgstr ""
+
+msgid "This file is incomplete and cannot be played."
+msgstr ""
+
+msgid "The video in this file might not play correctly."
+msgstr ""
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Ne eblis malfermi la sonaparaton por reproduktado. Ĝi estas uzate de alia "
+"aplikaĵo."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+
+msgid "Could not open audio device for playback."
+msgstr "Ne eblis malfermi la sonaparaton por reproduktado."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+
+msgid "Playback is not supported by this audio device."
+msgstr ""
+
+msgid "Audio playback error."
+msgstr ""
+
+msgid "Recording is not supported by this audio device."
+msgstr ""
+
+msgid "Error recording from audio device."
+msgstr ""
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+
+msgid "Could not open audio device for recording."
+msgstr "Ne eblis malfermi sonaparaton por registrado."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+#, fuzzy
+msgid "Record Source"
+msgstr "Registri"
+
+msgid "Microphone"
+msgstr "Mikrofono"
+
+msgid "Line In"
+msgstr ""
+
+msgid "Internal CD"
+msgstr ""
+
+msgid "SPDIF In"
+msgstr ""
+
+msgid "AUX 1 In"
+msgstr ""
+
+msgid "AUX 2 In"
+msgstr ""
+
+msgid "Codec Loopback"
+msgstr ""
+
+msgid "SunVTS Loopback"
+msgstr ""
+
+msgid "Volume"
+msgstr "Laŭteco"
+
+msgid "Gain"
+msgstr ""
+
+msgid "Monitor"
+msgstr "Ekrano"
+
+msgid "Built-in Speaker"
+msgstr ""
+
+msgid "Headphone"
+msgstr ""
+
+msgid "Line Out"
+msgstr ""
+
+msgid "SPDIF Out"
+msgstr ""
+
+msgid "AUX 1 Out"
+msgstr ""
+
+msgid "AUX 2 Out"
+msgstr ""
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr ""
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr ""
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr ""
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr ""
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr ""
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr ""
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr ""
+
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+
+msgid "Video device did not provide output format."
+msgstr ""
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+
+msgid "Video device uses an unsupported pixel format."
+msgstr ""
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+msgid "Video device did not suggest any buffer size."
+msgstr ""
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr ""
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr ""
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr ""
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr ""
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+
+msgid "Failed to start decoding thread."
+msgstr ""
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr ""
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr ""
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Tio ne estas '%s'-aparato."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr ""
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr ""
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr ""
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Ne eblis malfermi sonaparaton por registrado."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr ""
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr ""
+
+msgid "Cannot operate without a clock"
+msgstr ""
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Interna datumflu-eraro."
+
+#~ msgid "Bass"
+#~ msgstr "Baso"
+
+#~ msgid "Synth"
+#~ msgstr "Sintezilo"
+
+#~ msgid "Speaker"
+#~ msgstr "Parolilo"
+
+#~ msgid "CD"
+#~ msgstr "KD"
+
+#~ msgid "Mixer"
+#~ msgstr "Miksilo"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Radio"
+
+#~ msgid "Master"
+#~ msgstr "Ĉefe"
+
+#~ msgid "Front"
+#~ msgstr "Antaŭe"
+
+#~ msgid "Rear"
+#~ msgstr "Malantaŭe"
+
+#~ msgid "Headphones"
+#~ msgstr "Kaptelefono"
+
+#~ msgid "Center"
+#~ msgstr "Centre"
+
+#~ msgid "Surround"
+#~ msgstr "Ĉirkaŭe"
+
+#~ msgid "Side"
+#~ msgstr "Flanke"
+
+#~ msgid "Input"
+#~ msgstr "Enigo"
+
+#~ msgid "Stereo"
+#~ msgstr "Dukanale"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Ĉirkaŭa sono"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Mikrofono 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Mikrofono 2"
+
+#~ msgid "Modem"
+#~ msgstr "Modemo"
+
+#~ msgid "Other"
+#~ msgstr "Alia"
+
+#~ msgid "None"
+#~ msgstr "Neniu"
+
+#~ msgid "On"
+#~ msgstr "Enŝaltite"
+
+#~ msgid "Off"
+#~ msgstr "Elŝaltite"
+
+#~ msgid "Mute"
+#~ msgstr "Silentigi"
+
+#~ msgid "Fast"
+#~ msgstr "Rapide"
+
+#~ msgid "Very Low"
+#~ msgstr "Tre malalte"
+
+#~ msgid "Low"
+#~ msgstr "Malalte"
+
+#~ msgid "Medium"
+#~ msgstr "Meze"
+
+#~ msgid "High"
+#~ msgstr "Alte"
+
+#~ msgid "Very High"
+#~ msgstr "Tre alte"
+
+#~ msgid "%s %d Function"
+#~ msgstr "%s %d funkcio"
+
+#~ msgid "%s Function"
+#~ msgstr "%s funcio"
diff --git a/po/es.po b/po/es.po
new file mode 100644
index 0000000..159d832
--- /dev/null
+++ b/po/es.po
@@ -0,0 +1,870 @@
+# translation of gst-plugins-good-0.10.26.2.po to Español
+# spanish translation for gst-plugins-good
+# This file is put in the public domain.
+# Jorge González González <aloriel@gmail.com>, 2007, 2008, 2009, 2010, 2011.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 0.10.26.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2011-02-12 18:30+0100\n"
+"Last-Translator: Jorge González González <aloriel@gmail.com>\n"
+"Language-Team: Spanish <es@li.org>\n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr "Falló al decodificar la imagen JPEG"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "«%s» por «%s»"
+
+msgid "Could not connect to server"
+msgstr "No se pudo conectar con el servidor"
+
+msgid "No URL set."
+msgstr "No existe un URL establecido."
+
+msgid "Could not resolve server name."
+msgstr "No se pudo resolver el nombre del servidor."
+
+msgid "Could not establish connection to server."
+msgstr "No se pudo establecer la conexión con el servidor."
+
+msgid "Secure connection setup failed."
+msgstr "Falló la configuración de la conexión segura."
+
+#, fuzzy
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Ocurrió un error de red o el servidor cerró la conexión de forma inesperada."
+
+msgid "Server sent bad data."
+msgstr "El servidor envió datos erróneos."
+
+msgid "Server does not support seeking."
+msgstr "El servidor no soporta la búsqueda."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "El audio no existe o no es válido, el flujo AVI estará corrupto."
+
+msgid "This file contains no playable streams."
+msgstr "Este archivo no contiene flujos reproducibles."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Este archivo no es válido y no se puede reproducir."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Este archivo está corrupto y no se puede reproducir."
+
+msgid "Invalid atom size."
+msgstr "El tamaño atom no es válido."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Este archivo está incompleto y no se puede reproducir."
+
+msgid "The video in this file might not play correctly."
+msgstr ""
+"Puede que el vídeo en este archivo no se pueda reproducir correctamente."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+"Este archivo contiene demasiados flujos. Sólo se reproducirá el primer %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"No se encontró un flujo soportado. Puede que necesite instalar una extensión "
+"RTSP de GStreamer para los formatos de flujo Real."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"No se encontró un flujo soportado. Puede que necesite permitir más "
+"protocolos de transporte o de otra forma puede que le falte la extensión "
+"correcta de RTSP de GStreamer."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"No se pudo abrir el dispositivo para reproducir. Otra aplicación está usando "
+"el dispositivo."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"No se pudo abrir el dispositivo de sonido para reproducir. No tiene permisos "
+"para abrir el dispositivo."
+
+msgid "Could not open audio device for playback."
+msgstr "No se pudo abrir el dispositivo para reproducir."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"No se pudo abrir el dispositivo de sonido para su gestión por el control de "
+"mezclado. Este elemento no soporta esta versión del Sistema de sonido "
+"abierto (OSS)."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Este dispositivo de sonido no soporta la reproducción."
+
+msgid "Audio playback error."
+msgstr "Error de reproducción de sonido."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Este dispositivo de sonido no soporta la grabación."
+
+msgid "Error recording from audio device."
+msgstr "Error al grabar del dispositivo de sonido."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"No se pudo abrir el dispositivo de sonido para grabar. No tiene permisos "
+"para abrir el dispositivo."
+
+msgid "Could not open audio device for recording."
+msgstr "No se pudo abrir el dispositivo para grabar."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "Origen de la grabación"
+
+msgid "Microphone"
+msgstr "Micrófono"
+
+msgid "Line In"
+msgstr "Línea de entrada"
+
+msgid "Internal CD"
+msgstr "CD interno"
+
+msgid "SPDIF In"
+msgstr "Entrada S/PDIF"
+
+msgid "AUX 1 In"
+msgstr "Entrada AUX 1"
+
+msgid "AUX 2 In"
+msgstr "Entrada AUX 2"
+
+#, fuzzy
+msgid "Codec Loopback"
+msgstr "Bucle local"
+
+#, fuzzy
+msgid "SunVTS Loopback"
+msgstr "Bucle local"
+
+msgid "Volume"
+msgstr "Volumen"
+
+msgid "Gain"
+msgstr "Ganancia"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "Altavoz integrado"
+
+msgid "Headphone"
+msgstr "Auriculares"
+
+msgid "Line Out"
+msgstr "Línea de salida"
+
+msgid "SPDIF Out"
+msgstr "Salida S/PDIF"
+
+msgid "AUX 1 Out"
+msgstr "Salida AUX 1"
+
+msgid "AUX 2 Out"
+msgstr "Salida AUX 2"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Error al leer %d bytes del dispositivo «%s»."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Falló al enumerar los posibles formatos de vídeo con los que el dispositivo "
+"«%s» puede trabajar"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "No se pudieron mapear los búferes del dispositivo «%s»"
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr ""
+"El controlador del dispositivo «%s» no soporta ningún método de captura "
+"conocido."
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"El controlador del dispositivo «%s» no soporta ningún método de captura "
+"conocido."
+
+#, fuzzy, c-format
+msgid "Device '%s' is busy"
+msgstr "El dispositivo «%s» no es un dispositivo de salida."
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "El dispositivo «%s» no puede capturar a %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "El dispositivo «%s» no puede capturar en el formato especificado"
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "El dispositivo «%s» no es un dispositivo de salida."
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "No se pudieron obtener los parámetros para el dispositivo «%s»"
+
+#, fuzzy
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+"El dispositivo de entrada de vídeo no aceptó el ajuste de la nueva tasa de "
+"fotogramas."
+
+#, fuzzy
+msgid "Video device did not provide output format."
+msgstr ""
+"El dispositivo de entrada de vídeo no aceptó el ajuste de la nueva tasa de "
+"fotogramas."
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+"El controlador del dispositivo «%s» no soporta ningún método de captura "
+"conocido."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr ""
+"El controlador del dispositivo «%s» no soporta ningún método de captura "
+"conocido."
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+#, fuzzy
+msgid "Video device did not suggest any buffer size."
+msgstr ""
+"El dispositivo de entrada de vídeo no aceptó el ajuste de la nueva tasa de "
+"fotogramas."
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr ""
+"Falló al obtener la posición del sintonizador %d en el dispositivo «%s»."
+
+#, fuzzy, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Error al leer %d bytes del dispositivo «%s»."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "El dispositivo «%s» no es un dispositivo de salida."
+
+#, fuzzy, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Falló al establecer la entrada %d en el dispositivo %s."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Falló al establecer la entrada %d en el dispositivo %s."
+
+#, fuzzy, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Falló al obtener la potencia de la señal para el dispositivo «%s»."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+"El controlador del dispositivo «%s» no soporta ningún método de captura "
+"conocido."
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+"El dispositivo de entrada de vídeo no aceptó el ajuste de la nueva tasa de "
+"fotogramas."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+"El dispositivo de entrada de vídeo no aceptó el ajuste de la nueva tasa de "
+"fotogramas."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+"El dispositivo de entrada de vídeo no aceptó el ajuste de la nueva tasa de "
+"fotogramas."
+
+#, fuzzy
+msgid "Failed to start decoding thread."
+msgstr "Falló al decodificar la imagen JPEG"
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Error al obtener las capacidades del dispositivo «%s»: No es un controlador "
+"para v4l2. Compruebe si es un controlador para v4l1."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Falló al consultar los atributos de la entrada %d en el dispositivo %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr ""
+"Falló al obtener la posición del sintonizador %d en el dispositivo «%s»."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Falló al consultar la norma para el dispositivo «%s»."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Falló al obtener los atributos de control en el dispositivo «%s»."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "No se puede identificar el dispositivo «%s»."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Esto no es un dispositivo «%s»."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "No se pudo abrir el dispositivo «%s» para lectura y escritura."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "El dispositivo «%s» no es un dispositivo de captura."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "El dispositivo «%s» no es un dispositivo de salida."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "El dispositivo «%s» no es un dispositivo de salida."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "No se pudo abrir el dispositivo «%s» para lectura y escritura."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Falló al establecer la norma para el dispositivo «%s»."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+"Falló al obtener la frecuencia actual del sintonizador para el dispositivo "
+"«%s»."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Falló al establecer la frecuencia actual del sintonizador para el "
+"dispositivo «%s» a %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Falló al obtener la potencia de la señal para el dispositivo «%s»."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Falló al obtener el valor para el control %d del dispositivo «%s»."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr ""
+"Falló al establecer el valor %ds para el control %d del dispositivo «%s»."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Falló al obtener la entrada actual en el dispositivo «%s». Quizá sea un "
+"dispositivo de radio."
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Falló al obtener la salida actual en el dispositivo «%s». Quizá sea un "
+"dispositivo de radio."
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Falló al establecer la salida %d en el dispositivo %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "El cambio de resolución durante la reproducción aún no está soportado."
+
+msgid "Cannot operate without a clock"
+msgstr "No se puede operar sin reloj"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Error interno de flujo de datos."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Error en el flujo de datos interno."
+
+#, fuzzy
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "El dispositivo «%s» no es un dispositivo de salida."
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Se obtuvo un tamaño de cuadro inesperado %u en lugar de %u."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Falló al intentar obtener cuadros de vídeo del dispositivo «%s»."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Falló después de %d intentos. Dispositivo %s. Error del sistema: %s"
+
+#~ msgid "Bass"
+#~ msgstr "Bass"
+
+#~ msgid "Treble"
+#~ msgstr "Agudos"
+
+#~ msgid "Synth"
+#~ msgstr "Sintetizador"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Altavoz"
+
+#~ msgid "Line-in"
+#~ msgstr "Línea de entrada"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Mezclador"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Grabación"
+
+#~ msgid "In-gain"
+#~ msgstr "Ganancia de entrada"
+
+#~ msgid "Out-gain"
+#~ msgstr "Ganancia de salida"
+
+#~ msgid "Line-1"
+#~ msgstr "Línea-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Línea-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Línea-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Digital-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Digital-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Digital-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Entrada de teléfono"
+
+#~ msgid "Phone-out"
+#~ msgstr "Salida de teléfono"
+
+#~ msgid "Video"
+#~ msgstr "Vídeo"
+
+#~ msgid "Radio"
+#~ msgstr "Radio"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr ""
+#~ "No se pudo abrir el dispositivo de sonido para su gestión por el control "
+#~ "de mezclado."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "No se pudo abrir el dispositivo de sonido para su gestión por el control "
+#~ "de mezclado. Este elemento no soporta esta versión del Sistema de sonido "
+#~ "abierto (OSS)."
+
+#~ msgid "Master"
+#~ msgstr "Maestro"
+
+#~ msgid "Front"
+#~ msgstr "Frontal"
+
+#~ msgid "Rear"
+#~ msgstr "Trasero"
+
+#~ msgid "Headphones"
+#~ msgstr "Auriculares"
+
+#~ msgid "Center"
+#~ msgstr "Centro"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Envolvente"
+
+#~ msgid "Side"
+#~ msgstr "Lateral"
+
+#~ msgid "AUX Out"
+#~ msgstr "Salida AUX"
+
+#~ msgid "3D Depth"
+#~ msgstr "Profundidad 3D"
+
+#~ msgid "3D Center"
+#~ msgstr "Centro 3D"
+
+#~ msgid "3D Enhance"
+#~ msgstr "Mejora 3D"
+
+#~ msgid "Telephone"
+#~ msgstr "Teléfono"
+
+#~ msgid "Video In"
+#~ msgstr "Entrada de vídeo"
+
+#~ msgid "AUX In"
+#~ msgstr "Entrada AUX"
+
+#~ msgid "Record Gain"
+#~ msgstr "Ganancia de grabación"
+
+#~ msgid "Output Gain"
+#~ msgstr "Ganancia de salida"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Aumento del micrófono"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Diagnóstico"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Aumento de bajos"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Puertos de reproducción"
+
+#~ msgid "Input"
+#~ msgstr "Entrada"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Monitor de origen"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Pitido de teclado"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Simular estéreo"
+
+#~ msgid "Stereo"
+#~ msgstr "Estéreo"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Sonido envolvente"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Ganancia del micrófono"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Altavoz de origen"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Micrófono de origen"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Centrado / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Mezclador estéreo"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Mezclador mono"
+
+#~ msgid "Input Mix"
+#~ msgstr "Mezclador de entrada"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Micrófono 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Micrófono 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Salida digital"
+
+#~ msgid "Digital In"
+#~ msgstr "Entrada digital"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Módem"
+
+#~ msgid "Handset"
+#~ msgstr "Auriculares"
+
+#~ msgid "Other"
+#~ msgstr "Otro"
+
+#~ msgid "None"
+#~ msgstr "Ninguno"
+
+#~ msgid "On"
+#~ msgstr "Encendido"
+
+#~ msgid "Off"
+#~ msgstr "Apagado"
+
+#~ msgid "Mute"
+#~ msgstr "Silenciar"
+
+#~ msgid "Fast"
+#~ msgstr "Rápido"
+
+#~ msgid "Very Low"
+#~ msgstr "Muy bajo"
+
+#~ msgid "Low"
+#~ msgstr "Bajo"
+
+#~ msgid "Medium"
+#~ msgstr "Medio"
+
+#~ msgid "High"
+#~ msgstr "Alto"
+
+#~ msgid "Very High"
+#~ msgstr "Muy alto"
+
+#~ msgid "Production"
+#~ msgstr "Producción"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Micrófono del panel frontal"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Entrada del panel frontal"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Auriculares del panel frontal"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Salida del panel frontal"
+
+#~ msgid "Green Connector"
+#~ msgstr "Conector verde"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Conector rosa"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Conector azul"
+
+#~ msgid "White Connector"
+#~ msgstr "Conector blanco"
+
+#~ msgid "Black Connector"
+#~ msgstr "Conector negro"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Conector gris"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Conector naranja"
+
+#~ msgid "Red Connector"
+#~ msgstr "Conector rojo"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Conector amarillo"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Conector verde del panel frontal"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Conector rosa del panel frontal"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Conector azul del panel frontal"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Conector blanco del panel frontal"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Conector negro del panel frontal"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Conector gris del panel frontal"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Conector naranja del panel frontal"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Conector rojo del panel frontal"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Conector amarillo del panel frontal"
+
+#~ msgid "Spread Output"
+#~ msgstr "Expandir salida"
+
+#~ msgid "Downmix"
+#~ msgstr "Reducción de canales"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Entrada del mezclador virtual"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Salida del mezclador virtual"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Canales del mezclador virtual"
+
+#~ msgid "%s %d Function"
+#~ msgstr "Función %s %d"
+
+#~ msgid "%s Function"
+#~ msgstr "Función %s"
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Error al leer %d bytes del dispositivo «%s»."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "No se pueden encolar los búferes en el dispositivo «%s»."
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "No se pudo establecer la conexión con el servidor de sonido"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Falló al preguntar al servidor de sonido sus capacidades"
+
+#~ msgid ""
+#~ "The buffer type is not supported, or the index is out of bounds, or no "
+#~ "buffers have been allocated yet, or the userptr or length are invalid. "
+#~ "device %s"
+#~ msgstr ""
+#~ "El tipo de búfer no está soportado o el índice está fuera de los límites "
+#~ "o no se han registrado búferes todavía o la longitud o el userptr son "
+#~ "inválidos. Dispositivo %s"
+
+#~ msgid ""
+#~ "Failed trying to get video frames from device '%s'. Not enough memory."
+#~ msgstr ""
+#~ "Falló al intentar obtener cuadros de vídeo del dispositivo «%s». No hay "
+#~ "memoria suficiente."
+
+#~ msgid "insufficient memory to enqueue a user pointer buffer. device %s."
+#~ msgstr ""
+#~ "Memoria insuficiente para encolar un búfer puntero de usuario. "
+#~ "Dispositivo %s."
+
+#~ msgid "No free buffers found in the pool at index %d."
+#~ msgstr "No se encontraron búferes libres en el índice %d del «pool»."
+
+#~ msgid "Could not get buffers from device '%s'."
+#~ msgstr "No se pudieron obtener búferes del dispositivo «%s»."
+
+#~ msgid "Could not get enough buffers from device '%s'."
+#~ msgstr "No se pudieron obtener búferes suficientes del dispositivo «%s»."
+
+#~ msgid "Error starting streaming capture from device '%s'."
+#~ msgstr "Error al iniciar el flujo de captura del dispositivo «%s»."
+
+#~ msgid "Error stopping streaming capture from device '%s'."
+#~ msgstr "Error al parar el flujo de captura del dispositivo «%s»."
+
+#~ msgid "Failed getting controls attributes on device '%s.'"
+#~ msgstr "Falló al obtener los atributos de control en el dispositivo «%s»."
+
+#~ msgid "Could not read from CD."
+#~ msgstr "No se pudo leer del CD."
+
+#~ msgid "Disc is not an Audio CD."
+#~ msgstr "El disco no es un CD de sonido."
+
+#~ msgid "This file is encrypted and cannot be played."
+#~ msgstr "Este archivo está cifrado y no se puede reproducir."
diff --git a/po/eu.po b/po/eu.po
new file mode 100644
index 0000000..383b906
--- /dev/null
+++ b/po/eu.po
@@ -0,0 +1,912 @@
+# translation of gst-plugins-good.master.po to Basque
+# Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 Free Software Foundation, Inc.
+# This file is distributed under the same license as the gst-plugins-good package.
+#
+# Iñaki Larrañaga Murgoitio <dooteo@euskalgnu.org>, 2009, 2010.
+# Mikel Olasagasti Uranga <hey_neken@mundurat.net>, 2009, 2010.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good-0.10.18.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2010-03-25 12:37+0100\n"
+"Last-Translator: Mikel Olasagasti Uranga <hey_neken@mundurat.net>\n"
+"Language-Team: Basque <translation-team-eu@lists.sourceforge.net>\n"
+"Language: eu\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr "Huts egin du JPEG irudia deskodetzean"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "'%s' - '%s'"
+
+msgid "Could not connect to server"
+msgstr "Ezin izan da konektatu zerbitzariarekin"
+
+msgid "No URL set."
+msgstr ""
+
+#, fuzzy
+msgid "Could not resolve server name."
+msgstr "Ezin izan da konektatu zerbitzariarekin"
+
+#, fuzzy
+msgid "Could not establish connection to server."
+msgstr "Ezin izan da konexioa ezarri soinu-zerbitzariarekin"
+
+msgid "Secure connection setup failed."
+msgstr ""
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+
+msgid "Server sent bad data."
+msgstr ""
+
+msgid "Server does not support seeking."
+msgstr ""
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr ""
+"Ez dago audio-sarrerarik, edo baliogabea da. AVI korrontea hondatua egongo "
+"da."
+
+msgid "This file contains no playable streams."
+msgstr "Fitxategi horretan ez dago erreproduzi daitekeen korronterik."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Fitxategi hau ez da baliozkoa eta ezin da erreproduzitu."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Fitxategi hau hondatua dago, eta ezin da erreproduzitu."
+
+msgid "Invalid atom size."
+msgstr ""
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Fitxategi hau osatu gabea dago, eta ezin da erreproduzitu."
+
+msgid "The video in this file might not play correctly."
+msgstr ""
+"Litekeena da fitxategi honetako bideoa ez behar bezala erreproduzitzea."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+"Fitxategi horrek korronte gehiegi ditu. Erreproduzitu soilik lehen %d(r)ak"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Ez da onartutako korronterik aurkitu. GStreamer RTSP hedapena instalatu "
+"beharko duzu Real multimediako korronteentzako."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Ez da onartutako korronterik aurkitu. Garraioko protokolo gehiago baimentzea "
+"behar da edo GStreamer RTSP hedapen egokia falta zaizu."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Ezin izan da audioaren gailua ireki erreproduzitzeko. Beste aplikazio batek "
+"darabil gailua."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Ezin izan da audioaren gailua ireki erreproduzitzeko. Ez duzu baimenik "
+"gailua irekitzeko."
+
+msgid "Could not open audio device for playback."
+msgstr "Ezin izan da audioaren gailua ireki erreproduzitzeko."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Ezin izan da audioaren gailua ireki erreproduzitzeko. Elementu honek ez du "
+"onartzen Open Sound System-en bertsio hau."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Audio gailu honek ez du erreproduzitzea onartzen."
+
+msgid "Audio playback error."
+msgstr "Errorea audioa erreproduzitzean."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Audio gailu honek ez du grabatzea onartzen."
+
+msgid "Error recording from audio device."
+msgstr "Errorea audioko gailutik grabatzean."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Ezin izan da audioaren gailua ireki grabatzeko. Ez duzu baimenik gailua "
+"irekitzeko."
+
+msgid "Could not open audio device for recording."
+msgstr "Ezin izan da audioaren gailua ireki grabatzeko."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "Grabazioaren iturburua"
+
+msgid "Microphone"
+msgstr "Mikrofonoa"
+
+msgid "Line In"
+msgstr "Sarrerako linea"
+
+msgid "Internal CD"
+msgstr "Barneko CDa"
+
+msgid "SPDIF In"
+msgstr "SPDIF sarrera"
+
+msgid "AUX 1 In"
+msgstr "1. sarrera lagungarria"
+
+msgid "AUX 2 In"
+msgstr "2. sarrera lagungarria"
+
+#, fuzzy
+msgid "Codec Loopback"
+msgstr "Atzera-begizta"
+
+#, fuzzy
+msgid "SunVTS Loopback"
+msgstr "Atzera-begizta"
+
+msgid "Volume"
+msgstr "Bolumena"
+
+msgid "Gain"
+msgstr "Irabazia"
+
+msgid "Monitor"
+msgstr "Monitorea"
+
+msgid "Built-in Speaker"
+msgstr "Barneko bozgorailua"
+
+msgid "Headphone"
+msgstr "Entzungailua"
+
+msgid "Line Out"
+msgstr "Irteerako linea"
+
+msgid "SPDIF Out"
+msgstr "SPDIF irteera"
+
+msgid "AUX 1 Out"
+msgstr "1. irteera lagungarria"
+
+msgid "AUX 2 Out"
+msgstr "2. irteera lagungarria"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Errorea gertatu da '%2$s' gailuan %1$d byte irakurtzean."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Ezin izan dira '%s' gailuaren bufferrak mapatu."
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr ""
+"'%s' gailuaren kontrolatzaileak ez du onartzen kaptura-metodo ezagunik."
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"'%s' gailuaren kontrolatzaileak ez du onartzen kaptura-metodo ezagunik."
+
+#, fuzzy, c-format
+msgid "Device '%s' is busy"
+msgstr "'%s' gailua ez da irteerako gailu bat."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "'%s' gailua ez da kaptura-gailu bat."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "'%s' gailua ez da kaptura-gailu bat."
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "'%s' gailua ez da irteerako gailu bat."
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Ezin izan dira '%s' gailuaren parametroak eskuratu"
+
+#, fuzzy
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+"Bideoaren sarrerako gailuak ez du fotograma-tamainaren ezarpen berria "
+"onartzen."
+
+#, fuzzy
+msgid "Video device did not provide output format."
+msgstr ""
+"Bideoaren sarrerako gailuak ez du fotograma-tamainaren ezarpen berria "
+"onartzen."
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+"'%s' gailuaren kontrolatzaileak ez du onartzen kaptura-metodo ezagunik."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr ""
+"'%s' gailuaren kontrolatzaileak ez du onartzen kaptura-metodo ezagunik."
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+#, fuzzy
+msgid "Video device did not suggest any buffer size."
+msgstr ""
+"Bideoaren sarrerako gailuak ez du fotograma-tamainaren ezarpen berria "
+"onartzen."
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr ""
+"Huts egin du '%2$s' gailuko %1$d. sintonizadorearen ezarpenak eskuratzean."
+
+#, fuzzy, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Errorea gertatu da '%2$s' gailuan %1$d byte irakurtzean."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "'%s' gailua ez da irteerako gailu bat."
+
+#, fuzzy, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Huts egin du '%2$s' gailuko %1$d. sarrera ezartzean."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Huts egin du '%2$s' gailuko %1$d. sarrera ezartzean."
+
+#, fuzzy, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Huts egin du '%s' gailuaren seinalearen indarra eskuratzean."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+"'%s' gailuaren kontrolatzaileak ez du onartzen kaptura-metodo ezagunik."
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+"Bideoaren sarrerako gailuak ez du fotograma-tamainaren ezarpen berria "
+"onartzen."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+"Bideoaren sarrerako gailuak ez du fotograma-tamainaren ezarpen berria "
+"onartzen."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+"Bideoaren sarrerako gailuak ez du fotograma-tamainaren ezarpen berria "
+"onartzen."
+
+#, fuzzy
+msgid "Failed to start decoding thread."
+msgstr "Huts egin du JPEG irudia deskodetzean"
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Errorea gertatu da '%s' gailuaren ahalmena eskuratzean: Ez da v4l2 "
+"kontrolatzaile bat. Begiratu v4l1 kontrolatzaile bat den."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Huts egin du %2$s gailuko %1$d. sarreraren atributuak kontsultatzean"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr ""
+"Huts egin du '%2$s' gailuko %1$d. sintonizadorearen ezarpenak eskuratzean."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Huts egin du '%s' gailuaren araua kontsultatzean."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Huts egin dut '%s' gailuaren kontrol-atributuak eskuratzean."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Ezin da '%s' gailua identifikatu."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Hau ez da '%s' gailu bat."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Ezin izan da '%s' gailua ireki irakurtzeko eta idazteko."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "'%s' gailua ez da kaptura-gailu bat."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "'%s' gailua ez da irteerako gailu bat."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "'%s' gailua ez da irteerako gailu bat."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Ezin izan da '%s' gailua ireki irakurtzeko eta idazteko."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Huts egin du '%s' gailuaren araua ezartzean."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+"Huts egin du '%s' gailuaren uneko sintonizazio-frekuentzia eskuratzean."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Huts egin du '%s' gailuaren uneko sintonizazio-frekuentzia %lu Hz-tan "
+"ezartzean."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Huts egin du '%s' gailuaren seinalearen indarra eskuratzean."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Huts egin du '%2$s' gailuko %1$d. kontrolaren balioa eskuratzean."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr ""
+"Huts egin du '%3$s' gailuko %2$d. kontrolaren %1$d. balioa eskuratzean."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Huts egin du '%s' gailuko uneko sarrera eskuratzean. Litekeena da irrati-"
+"gailu bat izatea."
+
+#, fuzzy, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Huts egin du '%s' gailuko uneko sarrera eskuratzean. Litekeena da irrati-"
+"gailu bat izatea."
+
+#, fuzzy, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Huts egin du '%2$s' gailuko %1$d. sarrera ezartzean."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Oraindik ez dago onartua exekutatu bitartean bereizmena aldatzea."
+
+msgid "Cannot operate without a clock"
+msgstr "Ezin du funtzionatu erlojurik gabe"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Datu-korrontearen barne-errorea."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Datu-fluxuaren barne-errorea."
+
+#, fuzzy
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "'%s' gailua ez da irteerako gailu bat."
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Ustekabeko fotograma-tamaina jaso da (%u), %u ordez."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Huts egin du '%s' gailutik bideo-fotogramak eskuratzen saiatzean."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Huts egin du %d saio eta gero. %s gailua. Sistema-errorea: %s"
+
+#~ msgid "Bass"
+#~ msgstr "Baxua"
+
+#~ msgid "Treble"
+#~ msgstr "Altua"
+
+#~ msgid "Synth"
+#~ msgstr "Sintetizadorea"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Bozgorailua"
+
+#~ msgid "Line-in"
+#~ msgstr "Linea-sarrera"
+
+#~ msgid "CD"
+#~ msgstr "CDa"
+
+#~ msgid "Mixer"
+#~ msgstr "Nahastailea"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Grabazioa"
+
+#~ msgid "In-gain"
+#~ msgstr "Sarrerako irabazia"
+
+#~ msgid "Out-gain"
+#~ msgstr "Irteerako irabazia"
+
+#~ msgid "Line-1"
+#~ msgstr "1. linea"
+
+#~ msgid "Line-2"
+#~ msgstr "2. linea"
+
+#~ msgid "Line-3"
+#~ msgstr "3. linea"
+
+#~ msgid "Digital-1"
+#~ msgstr "1. digitala"
+
+#~ msgid "Digital-2"
+#~ msgstr "2. digitala"
+
+#~ msgid "Digital-3"
+#~ msgstr "3. digitala"
+
+#~ msgid "Phone-in"
+#~ msgstr "Aurikularren sarrera"
+
+#~ msgid "Phone-out"
+#~ msgstr "Aurikularren irteera"
+
+#~ msgid "Video"
+#~ msgstr "Bideoa"
+
+#~ msgid "Radio"
+#~ msgstr "Irratia"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr ""
+#~ "Ezin izan da audioko gailua ireki nahastailearen kontrola kudeatzeko."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Ezin izan da audioko gailua ireki nahastailearen kontrola kudeatzeko. "
+#~ "Elementu honek ez du onartzen Open Sound System-en bertsio hau."
+
+#~ msgid "Master"
+#~ msgstr "Maisua"
+
+#~ msgid "Front"
+#~ msgstr "Aurrealdekoa"
+
+#~ msgid "Rear"
+#~ msgstr "Atzealdekoa"
+
+#~ msgid "Headphones"
+#~ msgstr "Aurikularrak"
+
+#~ msgid "Center"
+#~ msgstr "Erdikoa"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Inguratzailea"
+
+#~ msgid "Side"
+#~ msgstr "Albokoa"
+
+#~ msgid "AUX Out"
+#~ msgstr "Irteera lagungarria"
+
+#~ msgid "3D Depth"
+#~ msgstr "3D sakonera"
+
+#~ msgid "3D Center"
+#~ msgstr "3D zentrua"
+
+#~ msgid "3D Enhance"
+#~ msgstr "3D hobetua"
+
+#~ msgid "Telephone"
+#~ msgstr "Telefonoa"
+
+#~ msgid "Video In"
+#~ msgstr "Bideo-sarrera"
+
+#~ msgid "AUX In"
+#~ msgstr "Sarrera lagungarria"
+
+#~ msgid "Record Gain"
+#~ msgstr "Grabazioaren irabazia"
+
+#~ msgid "Output Gain"
+#~ msgstr "Irteeraren irabazia"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Mikrofonoaren bultzada"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Diagnostikoa"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Baxuaren bultzada"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Erreprodukzioaren atakak"
+
+#~ msgid "Input"
+#~ msgstr "Sarrera"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Monitorearen iturburua"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Teklatuaren soinua"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Simulatu estereoa"
+
+#~ msgid "Stereo"
+#~ msgstr "Estereoa"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Soinu inguratzailea"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Mikrofonoaren irabazia"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Bozgorailuaren iturburua"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Mikrofonoaren iturburua"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Zentratua / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Estereozko nahasketa"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Monozko nahasketa"
+
+#~ msgid "Input Mix"
+#~ msgstr "Sarrerako nahasketa"
+
+#~ msgid "Microphone 1"
+#~ msgstr "1. mikrofonoa"
+
+#~ msgid "Microphone 2"
+#~ msgstr "2. mikrofonoa"
+
+#~ msgid "Digital Out"
+#~ msgstr "Irteera digitala"
+
+#~ msgid "Digital In"
+#~ msgstr "Sarrera digitala"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modema"
+
+#~ msgid "Handset"
+#~ msgstr "Aurikular+mikrofonoa"
+
+#~ msgid "Other"
+#~ msgstr "Bestelakoa"
+
+#~ msgid "None"
+#~ msgstr "Bat ere ez"
+
+#~ msgid "On"
+#~ msgstr "Piztu"
+
+#~ msgid "Off"
+#~ msgstr "Itzali"
+
+#~ msgid "Mute"
+#~ msgstr "Mututu"
+
+#~ msgid "Fast"
+#~ msgstr "Bizkorra"
+
+#~ msgid "Very Low"
+#~ msgstr "Oso motela"
+
+#~ msgid "Low"
+#~ msgstr "Motela"
+
+#~ msgid "Medium"
+#~ msgstr "Tartekoa"
+
+#~ msgid "High"
+#~ msgstr "Altua"
+
+#~ msgid "Very High"
+#~ msgstr "Oso altua"
+
+#~ msgid "Production"
+#~ msgstr "Ekoizpena"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Aurrealdeko paneleko mikrofonoa"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Aurrealdeko paneleko sarrerako linea"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Aurrealdeko paneleko aurikularrak"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Aurrealdeko paneleko irteerako linea"
+
+#~ msgid "Green Connector"
+#~ msgstr "Konektore berdea"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Konektore arrosa"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Konektore urdina"
+
+#~ msgid "White Connector"
+#~ msgstr "Konektore zuria"
+
+#~ msgid "Black Connector"
+#~ msgstr "Konektore beltza"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Konektore grisa"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Konektore laranja"
+
+#~ msgid "Red Connector"
+#~ msgstr "Konektore gorria"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Konektore horia"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Aurrealdeko paneleko konektore berdea"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Aurrealdeko paneleko konektore arrosa"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Aurrealdeko paneleko konektore urdina"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Aurrealdeko paneleko konektore zuria"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Aurrealdeko paneleko konektore beltza"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Aurrealdeko paneleko konektore grisa"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Aurrealdeko paneleko konektore laranja"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Aurrealdeko paneleko konektore gorria"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Aurrealdeko paneleko konektore horia"
+
+#~ msgid "Spread Output"
+#~ msgstr "Zabaldu irteera"
+
+#~ msgid "Downmix"
+#~ msgstr "Tolestu nahasketa"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Nahastaile birtualaren sarrera"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Nahastaile birtualaren irteera"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Nahastaile birtualaren kanalak"
+
+#, fuzzy
+#~ msgid "%s %d Function"
+#~ msgstr "%s funtzioa"
+
+#~ msgid "%s Function"
+#~ msgstr "%s funtzioa"
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Errorea gertatu da '%2$s' gailuan %1$d byte irakurtzean."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Ezin izan dira bufferrak ilaran jarri '%s' gailuan."
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Ezin izan da konexioa ezarri soinu-zerbitzariarekin"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Huts egin du soinu-zerbitzariaren ahalmena kontsultatzean"
+
+#~ msgid "Describes the selected input element."
+#~ msgstr "Sarrerako elementu hautatua deskribatzen du."
+
+#~ msgid "Describes the selected output element for Audio/Video Conferencing."
+#~ msgstr ""
+#~ "Audio-/Bideo-konferentziak egiteko irteerako elementu hautatua "
+#~ "deskribatzen du."
+
+#~ msgid "Describes the selected output element for Music and Movies."
+#~ msgstr "Musikaren eta filmen irteerako elementu hautatua deskribatzen du."
+
+#~ msgid "Describes the selected output element."
+#~ msgstr "Irteerako elementu hautatua deskribatzen du."
+
+#~ msgid "GStreamer audiosink for Audio/Video Conferencing"
+#~ msgstr "Audio-/Bideo-konferentziak egiteko GStreamen audio-kolektorea"
+
+#~ msgid "GStreamer audiosink for Music and Movies"
+#~ msgstr "Musikaren eta filmen GStreamer audio-kolektorea"
+
+#~ msgid ""
+#~ "GStreamer can play audio using any number of output elements. Some "
+#~ "possible choices are osssink, esdsink and alsasink. The audiosink can be "
+#~ "a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "Hainbat irteerako elementu erabiliz erreproduzi dezake audioa GStreamer-"
+#~ "ek. Hala nola osssink, esdsink eta alsasink. Audio-kolektorea kanalizazio "
+#~ "partzial bat izan daiteke, elementu bat izan beharrean."
+
+#~ msgid ""
+#~ "GStreamer can play video using any number of output elements. Some "
+#~ "possible choices are xvimagesink, ximagesink, sdlvideosink and aasink. "
+#~ "The videosink can be a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "Hainbat irteerako elementu erabiliz erreproduzi dezake bideoa GStreamer-"
+#~ "ek. Hala nola xvimagesink, ximagesink, sdlvideosink eta aasink. Bideo-"
+#~ "kolektorea kanalizazio partzial bat izan daiteke, elementu bat izan "
+#~ "beharrean."
+
+#~ msgid ""
+#~ "GStreamer can put visualization plugins in a pipeline to transform audio "
+#~ "stream in video frames. Default is goom but more visualization plugins "
+#~ "will be ported soon. The visualization plugin can be a partial pipeline "
+#~ "instead of just one element."
+#~ msgstr ""
+#~ "Kanalizazioetan bistaratzeko pluginak jar ditzake GStreamer-ek, audio-"
+#~ "korronteak bideo-fotograma bihurtzeko. Goom da lehenetsia, baina laster "
+#~ "izango da bistaratzeko plugin gehiago. Bistaratzeko plugina kanalizazio "
+#~ "partzial bat izan daiteke, elementu bat izan beharrean."
+
+#~ msgid ""
+#~ "GStreamer can record audio using any number of input elements. Some "
+#~ "possible choices are osssrc, esdsrc and alsasrc. The audio source can be "
+#~ "a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "Hainbat sarrerako elementu erabiliz graba dezake audioa GStreamer-ek. "
+#~ "Hala nola osssrc, esdsrc eta alsasrc. Audio-iturburua kanalizazio "
+#~ "partzial bat izan daiteke, elementu bat izan beharrean."
+
+#~ msgid ""
+#~ "GStreamer can record video from any number of input elements. Some "
+#~ "possible choices are v4lsrc and videotestsrc. The video source can be a "
+#~ "partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "Hainbat sarrerako elementu erabiliz graba dezake bideoa GStreamer-ek. "
+#~ "Hala nola v4lsrc eta videotestsrc. Bideo-iturburua kanalizazio partzial "
+#~ "bat izan daiteke, elementu bat izan beharrean."
+
+#~ msgid "default GStreamer audio source"
+#~ msgstr "GStreamer audio-iturburu lehenetsia"
+
+#~ msgid "default GStreamer audiosink"
+#~ msgstr "GStreamer audio-kolektore lehenetsia"
+
+#~ msgid "default GStreamer video source"
+#~ msgstr "GStreamer bideo-iturburu lehenetsia"
+
+#~ msgid "default GStreamer videosink"
+#~ msgstr "GStreamer bideo-kolektore lehenetsia"
+
+#~ msgid "default GStreamer visualization plugin"
+#~ msgstr "GStreamer bistaratzeko plugin lehenetsia"
+
+#~ msgid "description for GStreamer audiosink for Audio/Video Conferencing"
+#~ msgstr ""
+#~ "Audio-/Bideo-konferentziak egiteko GStreamen audio-kolektorearen "
+#~ "deskribapena"
+
+#~ msgid "description for GStreamer audiosink for Music and Movies"
+#~ msgstr "Musikaren eta filmen GStreamer audio-kolektorearen deskribapena"
+
+#~ msgid "description for default GStreamer audiosink"
+#~ msgstr "GStreamer audio-kolektore lehenetsiaren deskribapena"
+
+#~ msgid "description for default GStreamer audiosrc"
+#~ msgstr "GStreamer audiosrc lehenetsiaren deskribapena"
diff --git a/po/fi.po b/po/fi.po
new file mode 100644
index 0000000..4e9a97c
--- /dev/null
+++ b/po/fi.po
@@ -0,0 +1,907 @@
+# This file is distributed under the same license as the gst-plugins-good package.
+# Finnish messages for gst-plugins-good.
+# Copyright (C) 2009-2010 Tommi Vainikainen.
+# Copyright (C) 2007 Ilkka Tuohela.
+# Suomennos: http://gnome.fi/
+#
+# Tommi Vainikainen <thv@iki.fi>, 2009-2010.
+# Ilkka Tuohela <hile@iki.fi>, 2007.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 0.10.25.3\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2010-11-17 23:03+0200\n"
+"Last-Translator: Tommi Vainikainen <Tommi.Vainikainen@iki.fi>\n"
+"Language-Team: Finnish <translation-team-fi@lists.sourceforge.net>\n"
+"Language: fi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr "JPEG-kuvan purku epäonnistui"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "”%s” artistilta ”%s”"
+
+msgid "Could not connect to server"
+msgstr "Palvelimeen ei saatu yhteyttä"
+
+msgid "No URL set."
+msgstr "Ei URL:ää asetettuna."
+
+msgid "Could not resolve server name."
+msgstr "Palvelimen nimeä ei saatu selvitettyä."
+
+msgid "Could not establish connection to server."
+msgstr "Yhteyttä palvelimeen ei voitu avata."
+
+msgid "Secure connection setup failed."
+msgstr "Turvallisen yhteyden avaus epäonnistui."
+
+#, fuzzy
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr "Tapahtui verkkovirhe tai palvelin sulki yhteyden yllättäen."
+
+msgid "Server sent bad data."
+msgstr "Palvelin lähetti virheellistä dataa."
+
+msgid "Server does not support seeking."
+msgstr "Pavelin ei tue kelausta."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr ""
+"Ääntä ei ole tai äänilähde on viallinen, AVI-virta tulee olemaan "
+"vaurioitunut."
+
+msgid "This file contains no playable streams."
+msgstr "Tiedosto ei sisällä soitettavia virtoja."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Tiedosto on virheellinen eikä sitä voida esittää."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Tiedosto on vioittunut eikä sitä voida näyttää."
+
+msgid "Invalid atom size."
+msgstr ""
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Tiedosto on vajaa eikä sitä voida esittää."
+
+msgid "The video in this file might not play correctly."
+msgstr "Tiedostossa olevaa videota ei ehkä voida näyttää oikein."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Tiedosto sisältää useita virtoja. Soitetaan vain ensimmäiset %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Tuettua virtaa ei löytynyt. Kenties sinun tarvitsee asentaa GStreamer-RTSP-"
+"laajennus käyttääksesi Real-media-virtoja."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Tuettua virtaa ei löytynyt. Sinun kenties tarvitsee sallia useampia "
+"siirtoprotokollia, tai vaihtoehtoisesti sinulta saattaa puuttua oikea "
+"GStreamer-RTSP-laajennusliitännäinen."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Äänilaitetta ei voitu avata toistettavaksi. Laite on toisen sovelluksen "
+"käytössä."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Äänilaitetta ei voitu avata toistamista varten. Laitteen avaamiseen ei ole "
+"oikeuksia."
+
+msgid "Could not open audio device for playback."
+msgstr "Äänilaitetta ei voitu avata toistettavaksi."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Äänilaitetta ei voitu avata toistamista varten. Tämä elementti ei tue tätä "
+"versiota Open Sound Systemistä."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Tämä äänilaite ei tue toistamista."
+
+msgid "Audio playback error."
+msgstr "Äänentoistovirhe."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Tämä äänilaite ei tue nauhoitusta."
+
+msgid "Error recording from audio device."
+msgstr "Virhe luettaessa äänilaitteelta."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Äänilaitetta ei voitu avata nauhoitusta varten. Laitteen avaamiseen ei ole "
+"oikeuksia."
+
+msgid "Could not open audio device for recording."
+msgstr "Äänilaitetta ei voitu avata nauhoitusta varten."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "Nauhoituslähde"
+
+msgid "Microphone"
+msgstr "Mikrofoni"
+
+msgid "Line In"
+msgstr "Linjatulo"
+
+msgid "Internal CD"
+msgstr "Sisäinen CD"
+
+msgid "SPDIF In"
+msgstr "SPDIF sisään"
+
+msgid "AUX 1 In"
+msgstr "AUX 1 sisään"
+
+msgid "AUX 2 In"
+msgstr "AUX 2 sisään"
+
+#, fuzzy
+msgid "Codec Loopback"
+msgstr "Takaisinkytkentä"
+
+#, fuzzy
+msgid "SunVTS Loopback"
+msgstr "Takaisinkytkentä"
+
+msgid "Volume"
+msgstr "Äänenvoimakkuus"
+
+msgid "Gain"
+msgstr "Herkkyys"
+
+msgid "Monitor"
+msgstr "Tarkkailu"
+
+msgid "Built-in Speaker"
+msgstr "Sisäänrakennettu kaiutin"
+
+msgid "Headphone"
+msgstr "Kuulokkeet"
+
+msgid "Line Out"
+msgstr "Linja ulos"
+
+msgid "SPDIF Out"
+msgstr "SPDIF ulos"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1 ulos"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2 ulos"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Virhe luettaessa %d tavua laitteelta ”%s”."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Puskereita laitteelta ”%s” ei voitu kartoittaa"
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Laitteen ”%s” ajuri ei tue mitään tunnettua kaappaustapaa."
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Laitteen ”%s” ajuri ei tue mitään tunnettua kaappaustapaa."
+
+#, fuzzy, c-format
+msgid "Device '%s' is busy"
+msgstr "Laite ”%s” ei ole ulostulolaite."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Laitteelta ”%s” ei voi kaapata."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Laitteelta ”%s” ei voi kaapata."
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Laite ”%s” ei ole ulostulolaite."
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Laitteelta ”%s” ei voitu saada parametreja"
+
+#, fuzzy
+msgid "Video device did not accept new frame rate setting."
+msgstr "Videosyötelaite ei hyväksy uutta kehysnopeusasetusta."
+
+#, fuzzy
+msgid "Video device did not provide output format."
+msgstr "Videosyötelaite ei hyväksy uutta kehysnopeusasetusta."
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Laitteen ”%s” ajuri ei tue mitään tunnettua kaappaustapaa."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Laitteen ”%s” ajuri ei tue mitään tunnettua kaappaustapaa."
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+#, fuzzy
+msgid "Video device did not suggest any buffer size."
+msgstr "Videosyötelaite ei hyväksy uutta kehysnopeusasetusta."
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Virittimen %d asetuksia ei voitu lukea laitteelta ”%s”."
+
+#, fuzzy, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Virhe luettaessa %d tavua laitteelta ”%s”."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Laite ”%s” ei ole ulostulolaite."
+
+#, fuzzy, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Sisääntuloa %d ei voitu asettaa laitteelle %s."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Sisääntuloa %d ei voitu asettaa laitteelle %s."
+
+#, fuzzy, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Laitteelta ”%s” ei saatu signaalinvoimakkuutta."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Laitteen ”%s” ajuri ei tue mitään tunnettua kaappaustapaa."
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Videosyötelaite ei hyväksy uutta kehysnopeusasetusta."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Videosyötelaite ei hyväksy uutta kehysnopeusasetusta."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Videosyötelaite ei hyväksy uutta kehysnopeusasetusta."
+
+#, fuzzy
+msgid "Failed to start decoding thread."
+msgstr "JPEG-kuvan purku epäonnistui"
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Virhe haettaessa laitteen ”%s” ominaisuuksia: se ei ole v4l2-ajuri.Tarkista, "
+"onko se v4l1-ajuri."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Lähteen %d ominaisuuksia laitteelta %s ei voitu kysyä"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Virittimen %d asetuksia ei voitu lukea laitteelta ”%s”."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Laitteen ”%s” videostandardia ei voitu kysyä."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Laitteen ”%s” ohjainattribuutteja ei voitu lukea."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Laitetta ”%s” ei voi tunnistaa."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Tämä ei ole laite ”%s”."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Laitetta ”%s” ei voitu avata luettavaksi ja kirjoitettavaksi."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Laitteelta ”%s” ei voi kaapata."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Laite ”%s” ei ole ulostulolaite."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Laite ”%s” ei ole ulostulolaite."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Laitetta ”%s” ei voitu avata luettavaksi ja kirjoitettavaksi."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Laitteen ”%s” videostandardia ei voitu asettaa."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Nyt viritettyä taajuutta ei voitu lukea laitteelta ”%s”."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr "Laitteen ”%s” virittimen taajutta ei voitu asettaa arvoon %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Laitteelta ”%s” ei saatu signaalinvoimakkuutta."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Ohjaimelle %d ei saatu arvoa laitteelta ”%s”."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Arvoa %d ei voitu asettaa ohjaimelle %d laitteella ”%s”."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Laitteen ”%s” tämänhetkistä sisääntuloa ei voitu lukea, se ei ehkä ole "
+"radiolaite"
+
+#, fuzzy, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Laitteen ”%s” tämänhetkistä sisääntuloa ei voitu lukea, se ei ehkä ole "
+"radiolaite"
+
+#, fuzzy, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Sisääntuloa %d ei voitu asettaa laitteelle %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Resoluution vaihto käytön aikana ei ole vielä mahdollista."
+
+msgid "Cannot operate without a clock"
+msgstr "Ei voitu toimia ilman kelloa"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Sisäisen tietovirran virhe."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Sisäisen tietovirran virhe."
+
+#, fuzzy
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Laite ”%s” ei ole ulostulolaite."
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Saatiin odottamaton kehys kooltaan %u odotetun %u sijaan."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Videoruutujen noutaminen laitteelta ”%s” epäonnistui."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Epäonnistui %d yrityksen jälkeen: laite %s, järjestelmävirhe: %s"
+
+#~ msgid "Bass"
+#~ msgstr "Basso"
+
+#~ msgid "Treble"
+#~ msgstr "Ylä-äänet"
+
+#~ msgid "Synth"
+#~ msgstr "Synth"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Kaiutin"
+
+#~ msgid "Line-in"
+#~ msgstr "Linjatulo"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Mikseri"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Nauhoitus"
+
+#~ msgid "In-gain"
+#~ msgstr "Gain-sisään"
+
+#~ msgid "Out-gain"
+#~ msgstr "Gain-ulos"
+
+#~ msgid "Line-1"
+#~ msgstr "Linja-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Linja-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Linja-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Digitaalinen-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Digitaalinen-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Digitaalinen-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Levysoitintulo"
+
+#~ msgid "Phone-out"
+#~ msgstr "Levysoitinlähtö"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Radio"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "Äänilaitetta ei voitu avata mikserinhallintaa varten."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Äänilaitetta ei voitu avata mikserinhallintaa varten. Tämä elementti ei "
+#~ "tue tätä versiota Open Sound Systemistä."
+
+#~ msgid "Master"
+#~ msgstr "Pää"
+
+#~ msgid "Front"
+#~ msgstr "Etu"
+
+#~ msgid "Rear"
+#~ msgstr "Taka"
+
+#~ msgid "Headphones"
+#~ msgstr "Kuulokkeet"
+
+#~ msgid "Center"
+#~ msgstr "Keski"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Surround"
+
+#~ msgid "Side"
+#~ msgstr "Sivu"
+
+#~ msgid "AUX Out"
+#~ msgstr "AUX ulos"
+
+#~ msgid "3D Depth"
+#~ msgstr "3D-syvyys"
+
+#~ msgid "3D Center"
+#~ msgstr "3D-keski"
+
+#~ msgid "3D Enhance"
+#~ msgstr "3D-tehostus"
+
+#~ msgid "Telephone"
+#~ msgstr "Puhelin"
+
+#~ msgid "Video In"
+#~ msgstr "Videotulo"
+
+#~ msgid "AUX In"
+#~ msgstr "AUX sisään"
+
+#~ msgid "Record Gain"
+#~ msgstr "Nauhoitusgain"
+
+#~ msgid "Output Gain"
+#~ msgstr "Gain-ulos"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Mikrofonitehostin"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Diagnosointi"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Bassotehostin"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Toistoportit"
+
+#~ msgid "Input"
+#~ msgstr "Sisään"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Tarkkailulähde"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Näppäimistöpiippaus"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Simuloitu stereo"
+
+#~ msgid "Stereo"
+#~ msgstr "Stereo"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Surround-ääni"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Mikrofoni-gain"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Kaiutinlähde"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Mikrofonilähde"
+
+#~ msgid "Jack"
+#~ msgstr "Pistoke"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Keski / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Stereo Mix"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Mono Mix"
+
+#~ msgid "Input Mix"
+#~ msgstr "Sisään Mix"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Mikrofoni 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Mikrofoni 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Digitaalinen ulos"
+
+#~ msgid "Digital In"
+#~ msgstr "Digitaalinen sisään"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modeemi"
+
+#~ msgid "Handset"
+#~ msgstr "Kuulokkeet"
+
+#~ msgid "Other"
+#~ msgstr "Muu"
+
+#~ msgid "None"
+#~ msgstr "Ei mikään"
+
+#~ msgid "On"
+#~ msgstr "Päällä"
+
+#~ msgid "Off"
+#~ msgstr "Poissa"
+
+#~ msgid "Mute"
+#~ msgstr "Vaimennettu"
+
+#~ msgid "Fast"
+#~ msgstr "Nopea"
+
+#~ msgid "Very Low"
+#~ msgstr "Erittäin matala"
+
+#~ msgid "Low"
+#~ msgstr "Matala"
+
+#~ msgid "Medium"
+#~ msgstr "Medium"
+
+#~ msgid "High"
+#~ msgstr "Korkea"
+
+#~ msgid "Very High"
+#~ msgstr "Erittäin korkea"
+
+#~ msgid "Production"
+#~ msgstr "Tuotanto"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Etupaneelin mikrofoni"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Etupaneelin linjatulo"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Etupaneelin kuulokkeet"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Etupaneelin linja ulos"
+
+#~ msgid "Green Connector"
+#~ msgstr "Vihreä liitin"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Vaaleanpunainen liitin"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Sininen liitin"
+
+#~ msgid "White Connector"
+#~ msgstr "Valkoinen liitin"
+
+#~ msgid "Black Connector"
+#~ msgstr "Musta liitin"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Harmaa liitin"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Oranssi liitin"
+
+#~ msgid "Red Connector"
+#~ msgstr "Punainen liitin"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Keltainen liitin"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Vihreä etupaneeliliitin"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Vaaleanpunainen etupaneeliliitin"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Sininen etupaneeliliitin"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Valkoinen etupaneeliliitin"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Musta etupaneeliliitin"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Harmaa etupaneeliliitin"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Oranssi etupaneeliliitin"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Punainen etupaneeliliitin"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Keltainen etupaneeliliitin"
+
+#~ msgid "Spread Output"
+#~ msgstr "Levitetty ulos"
+
+#~ msgid "Downmix"
+#~ msgstr "Alasmiksaus"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Virtuaalinen mikseritulo"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Virtuaalinen mikseri ulos"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Virtuaaliset mikserikanavat"
+
+#~ msgid "%s %d Function"
+#~ msgstr "%s %d -toiminto"
+
+#~ msgid "%s Function"
+#~ msgstr "%s -toiminto"
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Virhe luettaessa %d tavua laitteelta ”%s”."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Puskureita ei voitu laittaa jonoon laitteella ”%s”."
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Yhteyttä äänipalvelimeen ei voitu avata"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Äänipalvelimen ominaisuuksia ei voitu selvittää"
+
+#~ msgid ""
+#~ "The buffer type is not supported, or the index is out of bounds, or no "
+#~ "buffers have been allocated yet, or the userptr or length are invalid. "
+#~ "device %s"
+#~ msgstr ""
+#~ "Puskurityyppi ei ole tuettu, indeksi on rajojen ulkopuolella, puskureita "
+#~ "ei ole vielä varattu tai käyttäjän osoitin tai pituus ovat virheelliset. "
+#~ "laite %s"
+
+#~ msgid "insufficient memory to enqueue a user pointer buffer. device %s."
+#~ msgstr ""
+#~ "muisti ei riitä käyttäjän osoitinpuskurin jonoon lisäämiseen. laite %s"
+
+#~ msgid "No free buffers found in the pool at index %d."
+#~ msgstr "Vapaita puskureita ei löytynyt indeksillä %d."
+
+#~ msgid "Could not read from CD."
+#~ msgstr "CD-levyltä ei voitu lukea."
+
+#~ msgid "Disc is not an Audio CD."
+#~ msgstr "Levy ei ole ääni-CD."
+
+#~ msgid "This file is encrypted and cannot be played."
+#~ msgstr "Tiedosto on salattu eikä sitä voida näyttää."
+
+#~ msgid "Describes the selected input element."
+#~ msgstr "Kuvaa valitun lähde-elementin."
+
+#~ msgid "Describes the selected output element for Audio/Video Conferencing."
+#~ msgstr "Kuvaa ääni- ja videoneuvotteluille valitun ulostuloelementin."
+
+#~ msgid "Describes the selected output element for Music and Movies."
+#~ msgstr "Kuvaa musiikille ja elokuville valitun ulostuloelementin."
+
+#~ msgid "Describes the selected output element."
+#~ msgstr "Kuvaa valitun ulostuloelementin."
+
+#~ msgid "GStreamer audiosink for Audio/Video Conferencing"
+#~ msgstr "GStreamer-ääninielu ääni- ja videoneuvotteluille"
+
+#~ msgid "GStreamer audiosink for Music and Movies"
+#~ msgstr "GStreamer-ääninielu äänelle ja elokuville"
+
+#~ msgid ""
+#~ "GStreamer can play audio using any number of output elements. Some "
+#~ "possible choices are osssink, esdsink and alsasink. The audiosink can be "
+#~ "a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer voi soittaa ääntä käyttäen useita eri nieluelementtejä. "
+#~ "Muutamia vaihtoehtoja ovat osssink, esdsink ja alsasink. Ääninielu voi "
+#~ "olla myös liukuhihnan osa eikä vain yksi elementti."
+
+#~ msgid ""
+#~ "GStreamer can play video using any number of output elements. Some "
+#~ "possible choices are xvimagesink, ximagesink, sdlvideosink and aasink. "
+#~ "The videosink can be a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer voi toistaa videota käyttäen useita eri nieluelementtejä. "
+#~ "Muutamia vaihtoehtoja ovat xvimagesink, ximagesink, sdlvideosink ja "
+#~ "aasink. Videonielu voi olla myös liukuhihnan osa eikä vain yksi elementti."
+
+#~ msgid ""
+#~ "GStreamer can put visualization plugins in a pipeline to transform audio "
+#~ "stream in video frames. Default is goom but more visualization plugins "
+#~ "will be ported soon. The visualization plugin can be a partial pipeline "
+#~ "instead of just one element."
+#~ msgstr ""
+#~ "Gstreamer voi laittaa visualisointiliitännäisiä liukuhihnalle, jolle se "
+#~ "muuntaa äänivirran videoruuduiksi. Oletusliitännäinen on goom, mutta "
+#~ "muita ollaan lisäämässä pian. Visualisoinnin liitännäinen voi olla myös "
+#~ "liukuhihnan osa eikä vain yksi elementti."
+
+#~ msgid ""
+#~ "GStreamer can record audio using any number of input elements. Some "
+#~ "possible choices are osssrc, esdsrc and alsasrc. The audio source can be "
+#~ "a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer voi nauhoittaa ääntä käyttäen useita eri lähde-elementtejä. "
+#~ "Muutamia vaihtoehtoja ovat osssrc, esdsrc ja alsasrc. Äänilähde voi olla "
+#~ "myös liukuhihnan osa eikä vain yksi elementti."
+
+#~ msgid ""
+#~ "GStreamer can record video from any number of input elements. Some "
+#~ "possible choices are v4lsrc and videotestsrc. The video source can be a "
+#~ "partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer voi nauhoittaa videota käyttäen useita eri lähde-elementtejä. "
+#~ "Muutamia vaihtoehtoja ovat v4lsrc ja videotestsrc.. Videolähde voi olla "
+#~ "myös liukuhihnan osa eikä vain yksi elementti."
+
+#~ msgid "default GStreamer audio source"
+#~ msgstr "GStreamerin oletusäänilähde"
+
+#~ msgid "default GStreamer audiosink"
+#~ msgstr "GStreamerin oletusääninielu"
+
+#~ msgid "default GStreamer video source"
+#~ msgstr "GStreamerin oletusvideolähde"
+
+#~ msgid "default GStreamer videosink"
+#~ msgstr "GStreamerin oletusvideonielu"
+
+#~ msgid "default GStreamer visualization plugin"
+#~ msgstr "Gstreamerin visualisointien oletusliitännäinen"
+
+#~ msgid "description for GStreamer audiosink for Audio/Video Conferencing"
+#~ msgstr "kuvaus ääni- ja videoneuvottelun GStreamer-ääninielulle"
+
+#~ msgid "description for GStreamer audiosink for Music and Movies"
+#~ msgstr "kuvaus musiikin ja elokuvien GStreamer-ääninielulle"
+
+#~ msgid "description for default GStreamer audiosink"
+#~ msgstr "GStreamerin oletusääninielun kuvaus"
+
+#~ msgid "description for default GStreamer audiosrc"
+#~ msgstr "GStreamerin oletusäänilähteen kuvaus"
diff --git a/po/fr.po b/po/fr.po
new file mode 100644
index 0000000..3acd881
--- /dev/null
+++ b/po/fr.po
@@ -0,0 +1,463 @@
+# Translation of gst-plugins-good to French
+# Copyright (C) 2003-2011 GStreamer core team
+# This file is distributed under the same license as the gst-plugins-good package.
+#
+# Nicolas Velin <nicolas@velin.fr>, 2008.
+# Claude Paroz <claude@2xlibre.net>, 2008-2011.
+# Stéphane Aulery <lkppo@free.fr>, 2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-02-20 16:27+0100\n"
+"Last-Translator: Stéphane Aulery <lkppo@free.fr>\n"
+"Language-Team: French <traduc@traduc.org>\n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Jack server not found"
+msgstr "serveur Jack introuvable"
+
+msgid "Failed to decode JPEG image"
+msgstr "Échec de décodage de l’image JPEG"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "« %s » par « %s »"
+
+msgid "Could not connect to server"
+msgstr "Impossible de se connecter au serveur"
+
+msgid "No URL set."
+msgstr "Aucun URL défini."
+
+msgid "Could not resolve server name."
+msgstr "Impossible de résoudre le nom du serveur."
+
+msgid "Could not establish connection to server."
+msgstr "Impossible d’établir une connexion vers le serveur."
+
+msgid "Secure connection setup failed."
+msgstr "La configuration d’une connexion sécurisée a échoué."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Une erreur réseau s’est produite ou le serveur a fermé abruptement la "
+"connexion."
+
+msgid "Server sent bad data."
+msgstr "Le serveur a envoyé de mauvaises données."
+
+msgid "Server does not support seeking."
+msgstr "Le serveur ne gère pas la recherche."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Entrée audio absente ou non valide, le flux AVI sera corrompu."
+
+msgid "This file contains no playable streams."
+msgstr "Ce fichier ne contient aucun flux exploitable."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Ce fichier n'est pas valide et ne peut donc pas être lu."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr "Impossible de lire le flux car il est chiffré par un DRM PlayReady."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Ce fichier est corrompu et ne peut pas être lu."
+
+msgid "Invalid atom size."
+msgstr "Taille d’atome non valide."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Ce fichier n’est pas complet et ne peut donc pas être lu."
+
+msgid "The video in this file might not play correctly."
+msgstr ""
+"Il est possible que la vidéo dans ce fichier ne puisse pas être lue "
+"correctement."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Ce fichier contient trop de flux. Seuls les %d premiers seront lus"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Aucun flux pris en charge n’a été trouvé. Il faut peut-être installer un "
+"greffon d’extension GStreamer RTSP pour les flux Real media."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Aucun flux pris en charge n’a été trouvé. Il faut peut-être autoriser "
+"davantage de protocoles de transport ou il manque peut-être le bon greffon "
+"d’extension GStreamer RTSP."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Impossible d’ouvrir le périphérique audio en lecture. Le périphérique est "
+"utilisé par une autre application."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Impossible d’ouvrir le périphérique audio en lecture. Vous n’avez pas les "
+"droits nécessaires pour ouvrir le périphérique."
+
+msgid "Could not open audio device for playback."
+msgstr "Impossible d’ouvrir le périphérique audio en lecture."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Impossible d’ouvrir le périphérique audio en lecture. Cette version d’OSS "
+"(Open Sound System) n’est pas prise en charge par cet élément."
+
+msgid "Playback is not supported by this audio device."
+msgstr "La lecture n’est pas prise en charge par ce périphérique audio."
+
+msgid "Audio playback error."
+msgstr "Erreur de lecture audio."
+
+msgid "Recording is not supported by this audio device."
+msgstr "L’enregistrement n’est pas pris en charge par ce périphérique audio."
+
+msgid "Error recording from audio device."
+msgstr "Erreur lors de l’enregistrement à partir du périphérique audio."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Impossible d’ouvrir le périphérique audio pour l’enregistrement. Vous n’avez "
+"pas les droits nécessaires pour ouvrir le périphérique."
+
+msgid "Could not open audio device for recording."
+msgstr "Impossible d’ouvrir le périphérique audio pour l’enregistrement."
+
+msgid "CoreAudio device not found"
+msgstr "Périphèrique CoreAudio introuvable"
+
+msgid "CoreAudio device could not be opened"
+msgstr "Le périphèrique CoreAudio n’a pas pu être ouvert"
+
+msgid "Record Source"
+msgstr "Source d’enregistrement"
+
+msgid "Microphone"
+msgstr "Micro"
+
+msgid "Line In"
+msgstr "Entrée ligne"
+
+msgid "Internal CD"
+msgstr "CD interne"
+
+msgid "SPDIF In"
+msgstr "Entrée SPDIF"
+
+msgid "AUX 1 In"
+msgstr "Entrée AUX 1"
+
+msgid "AUX 2 In"
+msgstr "Entrée AUX 2"
+
+msgid "Codec Loopback"
+msgstr "Codec boucle interne"
+
+msgid "SunVTS Loopback"
+msgstr "SunVTS boucle interne"
+
+msgid "Volume"
+msgstr "Volume"
+
+msgid "Gain"
+msgstr "Gain"
+
+msgid "Monitor"
+msgstr "Moniteur"
+
+msgid "Built-in Speaker"
+msgstr "Haut-parleur interne"
+
+msgid "Headphone"
+msgstr "Écouteurs"
+
+msgid "Line Out"
+msgstr "Sortie ligne"
+
+msgid "SPDIF Out"
+msgstr "Sortie SPDIF"
+
+msgid "AUX 1 Out"
+msgstr "Sortie AUX 1"
+
+msgid "AUX 2 Out"
+msgstr "Sortie AUX 2"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Erreur de lecture de %d octets sur le périphérique « %s »."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Impossible d’énumérer les formats vidéo compatibles avec le périphérique "
+"« %s »"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Impossible de mapper les tampons du périphérique « %s »."
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr ""
+"Le pilote du périphérique « %s » ne prend en charge la méthode d’entrée-"
+"sortie %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"Le pilote du périphérique « %s » ne prend en charge aucune méthode d’entrée-"
+"sortie connue."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Périphérique « %s » occupé"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr ""
+"Le périphérique « %s » ne peut pas capturer avec une résolution de %d x %d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Le périphérique « %s » ne peut pas capturer dans le format spécifié"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Le périphérique « %s » ne prend pas en charge les plans non contiguës"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Impossible d’obtenir les paramètres du périphérique « %s »"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+"Le périphérique vidéo n’a pas accepté le nouveau paramètre de fréquence "
+"d’image."
+
+msgid "Video device did not provide output format."
+msgstr "Le périphérique vidéo n’a pas fourni de format de sortie."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Le périphérique vidéo a retourné une dimensions incorrecte."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+"Le périphérique vidéo utilise une méthode d’entrelacement non prise en "
+"charge."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Le périphérique vidéo utilise un format de pixel non pris en charge."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Impossible de configurer le spooler interne de tampons."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Le périphérique vidéo n’a suggéré aucune taille de cache."
+
+msgid "No downstream pool to import from."
+msgstr "No downstream pool to import from."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr ""
+"Impossible d’obtenir les paramètres du syntoniseur %d du périphérique « %s »."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Erreur d’interrogation des capacités du périphérique « %s »."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Le périphérique « %s » n'est pas un syntoniseur."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Impossible d’obtenir un flux radio depuis le périphérique %s."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Impossible de définir l’entrée %d sur le périphérique %s."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Impossible de modifier la sourdine du périphérique « %s »."
+
+msgid "Failed to allocated required memory."
+msgstr "Impossible d’allouer la mémoire nécessaire."
+
+msgid "Failed to allocate required memory."
+msgstr "Impossible d’allouer la mémoire nécessaire."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+"Le convertisseur du périphérique « %s » ne prend en charge aucun format "
+"d’entrée"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+"Le convertisseur du périphérique « %s » ne prend en charge aucun format de "
+"sortie"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+"L’encodeur du périphérique « %s » ne prend en charge aucun format d’entrée"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+"L’encodeur du périphérique « %s » ne prend en charge aucun format de sortie"
+
+msgid "Failed to start decoding thread."
+msgstr "Échec de démarrage du processus de décodage."
+
+msgid "Failed to process frame."
+msgstr "Échec du traitement de frame."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Erreur de récupération des capacités pour le périphérique « %s » : ce n’est "
+"pas un pilote v4l2. Vérifiez si c’est un pilote v4l1."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr ""
+"Impossible de récupérer les attributs de l’entrée %d du périphérique %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr ""
+"Impossible de récupérer les paramètres du syntoniseur %d du périphérique "
+"« %s »."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Impossible de récupérer la norme du périphérique « %s »."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr ""
+"Impossible de récupérer les attributs de contrôle du périphérique « %s »."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Impossible d’identifier le périphérique « %s »."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Ceci n’est pas un périphérique « %s »."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Impossible d’ouvrir le périphérique « %s » en lecture et écriture."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Le périphérique « %s » n’est pas un périphérique d’enregistrement."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Le périphérique « %s » n’est pas un périphérique de sortie."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Le périphérique « %s » n’est pas un périphérique M2M."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Impossible de dupliquer le périphérique « %s » en lecture et écriture."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "La définition de la norme du périphérique « %s » a échoué."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+"Impossible de récupérer la fréquence actuelle de syntonisation du "
+"périphérique « %s »."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Impossible de définir la fréquence de syntonisation du périphérique « %s » à "
+"%lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Impossible d’obtenir la force du signal du périphérique « %s »."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr ""
+"Impossible de récupérer la valeur du contrôle %d du périphérique « %s »."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr ""
+"Impossible de récupérer la valeur %d du contrôle %d du périphérique « %s »."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Impossible de récupérer l’entrée actuelle du périphérique « %s ». C’est peut-"
+"être un périphérique radio"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Impossible de récupérer la sortie actuelle du périphérique « %s ». C’est "
+"peut-être un périphérique radio"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Impossible de définir la sortie %d du périphérique %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr ""
+"La modification de la résolution au cours de l’exécution n’est pas encore "
+"prise en charge."
+
+msgid "Cannot operate without a clock"
+msgstr "Impossible de fonctionner sans horloge"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Erreur du flux de données interne."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Erreur du flux de données interne."
diff --git a/po/fur.po b/po/fur.po
new file mode 100644
index 0000000..92fc1e3
--- /dev/null
+++ b/po/fur.po
@@ -0,0 +1,436 @@
+# SOME DESCRIPTIVE TITLE.
+# This file is put in the public domain.
+# FABIO TOMAT <f.t.public@gmail.com>, 2017.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.10.0\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2017-02-17 10:54+0100\n"
+"Last-Translator: Fabio Tomat <f.t.public@gmail.com>\n"
+"Language-Team: Friulian <f.t.public@gmail.com>\n"
+"Language: fur\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
+"X-Generator: Poedit 1.8.11\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "Jack server not found"
+msgstr "Servidôr Jack no cjatât"
+
+msgid "Failed to decode JPEG image"
+msgstr "No si è rivâts a decodificâ la imagjin JPEG"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "'%s' di '%s'"
+
+msgid "Could not connect to server"
+msgstr "Impussibil conetisi al servidôr"
+
+msgid "No URL set."
+msgstr "Nissun URL stabilît."
+
+msgid "Could not resolve server name."
+msgstr "Impussibil risolvi il non dal servidôr."
+
+msgid "Could not establish connection to server."
+msgstr "Impussibil stabilî la conession al servidôr."
+
+msgid "Secure connection setup failed."
+msgstr "No si è rivâts a configurâ la conession sigure."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Al è capitât un erôr di rêt o il servidôr al à sierât la conession in "
+"maniere inspietade."
+
+msgid "Server sent bad data."
+msgstr "Il servidôr al à inviât dâts sbaliâts."
+
+msgid "Server does not support seeking."
+msgstr "Il servidôr nol supuarte la ricercje."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Nissun o invalit audio in jentrade, il flus AVI al sarà ruvinât."
+
+msgid "This file contains no playable streams."
+msgstr "Chest file nol conten flus riprodusibii."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Chest file nol è valit e nol pues jessi riprodot."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+"Impussibil riprodusi il flus par vie che al è cifrât cun PlayReady DRM."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Chest file al è ruvinât e nol pues jessi riprodot."
+
+msgid "Invalid atom size."
+msgstr "Dimension atom no valide."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Chest file nol è complet e nol pues jessi riprodot."
+
+msgid "The video in this file might not play correctly."
+msgstr "il video in chest file al podarès no funzionâ ben."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Chest file al conten masse flus. Si riprodusarà nome i prins %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Nissun flus supuartât al è stât cjatât. Al podarès coventâ di instalâ un "
+"plugin di estension RTSP par GStreamer pai flus Real media."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Nissun flus supuartât al è stât cjatât. Al podarès coventâ di permeti plui "
+"protocoi di traspuart o in alternative al podarès mancjâ il just plugin di "
+"estension RTSP par GStreamer."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Impussibil vierzi il dispositîf audio pe riproduzion. Il dispositîf al è "
+"doprât di une altre aplicazion."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Impussibil vierzi il dispositîf audio pe riproduzion. No si à i permès par "
+"vierzi il dispositîf."
+
+msgid "Could not open audio device for playback."
+msgstr "Impussibil vierzi il dispositîf audio pe riproduzion."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Impussibil vierzi il dispositîf audio pe riproduzion. Cheste version di Open "
+"Sound System no je supuartade di chest element."
+
+msgid "Playback is not supported by this audio device."
+msgstr "La riproduzion no je supuartade di chest dispositîf audio."
+
+msgid "Audio playback error."
+msgstr "Erôr di riproduzion audio."
+
+msgid "Recording is not supported by this audio device."
+msgstr "La regjistrazion no je supuartade di chest dispositîf audio."
+
+msgid "Error recording from audio device."
+msgstr "Erôr tal regjistrâ dal dispositîf audio."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Impussibil vierzi il dispositîf audio pe regjistrazion. No si à i permès par "
+"vierzi il dispositîf."
+
+msgid "Could not open audio device for recording."
+msgstr "Impussibil vierzi il dispositîf audio pe regjistrazion."
+
+msgid "CoreAudio device not found"
+msgstr "Dispositîf CoreAudio no cjatât"
+
+msgid "CoreAudio device could not be opened"
+msgstr "Nol è stât pussibil vierzi il dispositîf CoreAudio"
+
+msgid "Record Source"
+msgstr "Sorzint regjistrazion"
+
+msgid "Microphone"
+msgstr "Microfon"
+
+msgid "Line In"
+msgstr "Linie di jentrade"
+
+msgid "Internal CD"
+msgstr "CD interni"
+
+msgid "SPDIF In"
+msgstr "SPDIF jentrade"
+
+msgid "AUX 1 In"
+msgstr "AUX 1 jentrade"
+
+msgid "AUX 2 In"
+msgstr "AUX 2 jentrade"
+
+msgid "Codec Loopback"
+msgstr "Loopback Codec"
+
+msgid "SunVTS Loopback"
+msgstr "Loopback SunVTS"
+
+msgid "Volume"
+msgstr "Volum"
+
+msgid "Gain"
+msgstr "Vuadagn"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "Casse incorporade"
+
+msgid "Headphone"
+msgstr "Cufis"
+
+msgid "Line Out"
+msgstr "Linie di jessude"
+
+msgid "SPDIF Out"
+msgstr "SPDIF jessude"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1 jessude"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2 jessude"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Erôr tal lei %d byte dal dispositîf '%s'."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"No si è rivâts a fâ la liste dai pussibii formâts video cui cuai il "
+"dispositîf '%s' al pues lavorâ"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Impussibil mapâ i buffer dal dispositîf  '%s'"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Il driver dal dispositîf '%s' nol supuarte il metodi IO %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Il driver dal dispositîf '%s' nol supuarte nissun metodi IO cognossût."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Il dispositîf '%s' al è ocupât"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Il dispositîf '%s' nol pues caturâ a %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Il dispositîf '%s' nol pues caturâ tal formât specificât"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr ""
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Impussibil otignî i parametris sul dispositîf '%s'"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+"Il dispositîf video nol à acetât la gnove impostazion de frecuence di "
+"fotograms."
+
+msgid "Video device did not provide output format."
+msgstr "Il dispositîf video nol à furnît un formât di jessude."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Il dispositîf video al à tornât dimensions no validis."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Il dispositîf video al dopre un metodi di interlazament no supuartât"
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Il dispositîf video al dopre un formât pixel no supuartât."
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Il dispositîf video nol à sugjerît nissune dimension di buffer."
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr ""
+"No si è rivâts a vê impostazions dal sintonizadôr %d sul dispositîf '%s'."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Erôr tal otignî li funzionalitâts pal dispositîf '%s'."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Il dispositîf '%s' nol è un sintonizadôr."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "No si è rivâts a vê lis jentradis radio sul dispositîf '%s'. "
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "No si è rivâts a stabilî la jentrade %d sul dispositîf %s."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "No si è rivâts a cambiâ il stât di cidin pal dispositîf '%s'."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr "No si è rivâts a assegnâ la memorie domandade."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Il convertidôr sul dispositîf %s nol à formâts di jentrade supuartâts"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Il convertidôr sul dispositîf %s nol à formâts di jessude supuartâts"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Il codificadôr sul dispositîf %s nol à formâts di jentrade supuartâts"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Il codificadôr sul dispositîf %s nol à formâts di jessude supuartâts"
+
+msgid "Failed to start decoding thread."
+msgstr ""
+
+msgid "Failed to process frame."
+msgstr "Impussibil processâ fotogram."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Erôr tal otignî lis funzionalitâts pal dispositîf '%s': nol è un driver "
+"v4l2. Controle se al è un driver v4l1."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "No si è rivâts a interogâ i atribûts di jentrade %d tal dispositîf %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr ""
+"No si è rivâts a otignî la impostazion dal sintonizadôr %d sul dispositîf "
+"'%s'."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "No si è rivâts a interogâ la norme sul dispositîf '%s'."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "No si è rivâts a vê i atribûts dai controi sul dispositîf '%s'."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Impussibil identificâ il dispositîf '%s'."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Chest nol è un dispositîf '%s'."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Impussibil vierzi il dispositîf '%s' par lei e scrivi."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Il dispositîf '%s' nol è un dispositîf di cature."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Il dispositîf '%s' nol è un dispositîf di jessude."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Il dispositîf '%s' nol è un dispositîf M2M."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr ""
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "No si è rivâts a stabilî la norme pal dispositîf '%s'."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+"No si è rivâts a otignî la frecuence atuâl dal sintonizadôr pal dispositîf "
+"'%s'."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"No si è rivâts a meti la frecuence atuâl dal sintonizadôr pal dispositîf "
+"'%s' a %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "No si è rivâts a vê la fuarce dal segnâl pal dispositîf '%s'."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "No si è rivâts a vê il valôr pal control %d sul dispositîf '%s'."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "No si è rivâts a meti il valôr %d pal control %d sul dispositîf '%s'."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"No si è rivâts a vê la jentrade atuâl sul dispositîf '%s'. Al podarès jessi "
+"un dispositîf radio"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"No si è rivâts a vê la jessude atuâl sul dispositîf '%s'. Al podarès jessi "
+"un dispositîf radio"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "No si è rivâts a stabilî la jessude %d sul dispositîf %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Il cambiâ la risoluzion dilunc la vore nol è ancjemò supuartât."
+
+msgid "Cannot operate without a clock"
+msgstr "Impussibil operâ cence un orloi"
diff --git a/po/gl.po b/po/gl.po
new file mode 100644
index 0000000..00350e0
--- /dev/null
+++ b/po/gl.po
@@ -0,0 +1,913 @@
+# Galician translation of gst-plugins-good.
+# Copyright (C) 2009 gst-plugins-good's COPYRIGHT HOLDER
+# This file is distributed under the same license as the gst-plugins-good package.
+# Fran Diéguez <frandieguez@ubuntu.com>, 2009, 2010, 2011.
+# Fran Dieguez <frandieguez@gnome.org>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.0.3\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2012-12-15 03:46+0200\n"
+"Last-Translator: Fran Dieguez <frandieguez@ubuntu.com>\n"
+"Language-Team: Galician <proxecto@trasno.net>\n"
+"Language: gl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Virtaal 0.7.1\n"
+"X-Project-Style: gnome\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr "Produciuse un erro ao descodificar a imaxe JPEG"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "«%s» por «%s»"
+
+msgid "Could not connect to server"
+msgstr "Non foi posíbel conectarse ao servidor"
+
+msgid "No URL set."
+msgstr "No existe un URL estabelecido."
+
+msgid "Could not resolve server name."
+msgstr "Non foi posíbel resolver o nome do servidor."
+
+msgid "Could not establish connection to server."
+msgstr "Non foi posíbel estabelecer a conexión co servidor."
+
+msgid "Secure connection setup failed."
+msgstr "Produciuse un fallo de configuración da conexión segura."
+
+#, fuzzy
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Produciuse un erro de rede ou o servidor pechou a conexión de forma "
+"inesperada."
+
+msgid "Server sent bad data."
+msgstr "O servidor enviou datos erróneos."
+
+msgid "Server does not support seeking."
+msgstr "O servidor non admite a busca."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "O audio non existe ou non é válido, o fluxo AVI está corrompido."
+
+msgid "This file contains no playable streams."
+msgstr "Este ficheiro non contén ningún fluxo reproducíbel."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Este ficheiro é incorrecto e non pode reproducirse."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Este ficheiro está danado e non pode reproducirse."
+
+msgid "Invalid atom size."
+msgstr "Tamaño atom non válido."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Este ficheiro está incompleto e non pode reproducirse."
+
+msgid "The video in this file might not play correctly."
+msgstr "Este vídeo neste ficheiro podería non reproducirse correctamente."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+"Este ficheiro contén demasiados fluxos. Só se reproducirá o primeiro %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Non se encontrou un fluxo compatíbel. Pode que necesite instalar unha "
+"extensión RTSP de GStreamer para os formatos de fluxo Real."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Non se encontrou un fluxo compatíbel. Pode que necesite permitir máis "
+"protocolos de transporte ou de outra forma pode que lle falte a extensión "
+"correcta de RTSP de GStreamer."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Non foi posíbel abrir o dispositivo de son para a reprodución. O dispositivo "
+"está sendo empregado por outro aplicativo."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Non foi posíbel abrir o dispositivo de son. Vostede non ten permisos para "
+"abrir o dispositivo."
+
+msgid "Could not open audio device for playback."
+msgstr "Non foi posíbel abrir o dispositivo de son para a reprodución."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Non foi posíbel abrir o dispositivo de son para a reprodución. Esta versión "
+"do Open Sound System non está admitida por este elemento."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Este dispositivo de son non admite a reprodución."
+
+msgid "Audio playback error."
+msgstr "Erro de reprodución de son."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Este dispositivo de son non admite a gravación."
+
+msgid "Error recording from audio device."
+msgstr "Erro ao gravar do dispositivo de son."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Non foi posíbel abrir o dispositivo de son para a gravación. Vostede non ten "
+"permisos para abrir o dispositivo."
+
+msgid "Could not open audio device for recording."
+msgstr "Non foi posíbel abrir o dispositivo de son para a gravación."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "Orixe da gravación"
+
+msgid "Microphone"
+msgstr "Micrófono"
+
+msgid "Line In"
+msgstr "Liña de entrada"
+
+msgid "Internal CD"
+msgstr "CD interno"
+
+msgid "SPDIF In"
+msgstr "Entrada SPDIF"
+
+msgid "AUX 1 In"
+msgstr "Entrada AUX 1"
+
+msgid "AUX 2 In"
+msgstr "Entrada AUX 2"
+
+#, fuzzy
+msgid "Codec Loopback"
+msgstr "Bucle local"
+
+#, fuzzy
+msgid "SunVTS Loopback"
+msgstr "Bucle local"
+
+msgid "Volume"
+msgstr "Volume"
+
+msgid "Gain"
+msgstr "Ganancia"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "Altofalante interno"
+
+msgid "Headphone"
+msgstr "Cascos"
+
+msgid "Line Out"
+msgstr "Liña de saída"
+
+msgid "SPDIF Out"
+msgstr "Saída SPDIF"
+
+msgid "AUX 1 Out"
+msgstr "Saída AUX 1"
+
+msgid "AUX 2 Out"
+msgstr "Saída AUX 2"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Produciuse un erro ao ler %d bytes desde o dispositivo «%s»."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Produciuse un fallo ao enumerar os formatos de vídeo posíbeis cos que o "
+"dispositivo «%s» pode reproducir"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Non foi posíbel mapear os búferes do dispositivo «%s»"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "O controlador do dispositivo «%s» non admite o método IO %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"O controlador do dispositivo «%s» non admite calquera método IO coñecido."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "O dispositivo «%s» está ocupado"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "O dispositivo «%s» non pode capturar a %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "O dispositivo «%s» non pode capturar o formato especificado"
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "O dispositivo «%s» non admite a captura de vídeo."
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Non foi posíbel obter os parámetros para o dispositivo «%s»"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+"O dispositivo de vídeo non acepta a nova configuración de taxa de marcos."
+
+#, fuzzy
+msgid "Video device did not provide output format."
+msgstr ""
+"O dispositivo de vídeo non acepta a nova configuración de taxa de marcos."
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "O controlador do dispositivo «%s» non admite o método IO %d"
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "O controlador do dispositivo «%s» non admite o método IO %d"
+
+#, fuzzy
+msgid "Failed to configure internal buffer pool."
+msgstr "O dispositivo de vídeo non pode crear un pool de búfer."
+
+#, fuzzy
+msgid "Video device did not suggest any buffer size."
+msgstr "O dispositivo de vídeo non pode crear un pool de búfer."
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr ""
+"Produciuse un erro ao obter as configuracións do sintonizador %d no "
+"dispositivo «%s»."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Produciuse un erro ao ler as capacidades para o dispositivo «%s»."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "O dispositivo «%s» non é un sintonizador."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Produciuse un fallo ao obter a entrada do radio no dispositivo %s."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Produciuse un fallo ao estabelecer a entrada %d no dispositivo %s."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr ""
+"Produciuse un erro ao cambiar o estado de enmudecido para o dispositivo «%s»."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "O controlador do dispositivo «%s» non admite o método IO %d"
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+"O dispositivo de vídeo non acepta a nova configuración de taxa de marcos."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+"O dispositivo de vídeo non acepta a nova configuración de taxa de marcos."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+"O dispositivo de vídeo non acepta a nova configuración de taxa de marcos."
+
+#, fuzzy
+msgid "Failed to start decoding thread."
+msgstr "Produciuse un erro ao descodificar a imaxe JPEG"
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Produciuse un erro ao obter as capacidades do dispositivo «%s»: Non é un "
+"controlador v4l2. Comprobe se é un controlador v4l1."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr ""
+"Produciuse un erro ao consultar os atributos de entrada %d no dispositivo %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr ""
+"Produciuse un erro ao configurar o sintonizador %d no dispositivo «%s»."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Produciuse un erro ao consultar a norma no dispositivo «%s»."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr ""
+"Produciuse un erro ao obter os atributos de control do dispositivo «%s»."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Non foi posíbel identificar o dispositivo «%s»."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Este non é un dispositivo «%s»."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Non foi posíbel abrir o dispositivo «%s» para lectura e escritura."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "O dispositivo «%s» non é un dispositivo de captura."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "O dispositivo «%s» non é un dispositivo de captura."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "O dispositivo «%s» non é un dispositivo de captura."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Non foi posíbel abrir o dispositivo «%s» para lectura e escritura."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Produciuse un fallo ao estabelecer a norma no dispositivo «%s»."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+"Produciuse un fallo  ao obter a frecuencia actual do sintonizador para o "
+"dispositivo «%s»."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Produciuse un erro ao estabelecer a frecuencia actual do sintonizador para o "
+"dispositivo «%s» a %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr ""
+"Produciuse un erro ao obter a potencia do sinal para o dispositivo «%s»."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr ""
+"Produciuse un erro ao obter o valor para o control %d do dispositivo «%s»."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr ""
+"Produciuse un fallo ao estabelecer o valor %ds para o control %d do "
+"dispositivo «%s»."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Produciuse un fallo ao obter a entrada actual no dispositivo «%s». Cicáis "
+"sexa un dispositivo de radio."
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Produciuse un fallo ao obter a entrada actual no dispositivo «%s». Quizais "
+"sexa un dispositivo de radio"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Produciuse un fallo ao estabelecer a saída %d no dispositivo %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Aínda non se admite o cambio de resolución durante a reprodución."
+
+msgid "Cannot operate without a clock"
+msgstr "Non é posíbel operar sen reloxo"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Produciuse un erro no fluxo de datos interno."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Produciuse un erro interno no fluxo de datos."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "O dispositivo «%s» non admite a captura de vídeo."
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Non foi posíbel estabelecer a conexión co servidor de son"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Produciuse un erro ao consultar as capacidades do servidor de son"
+
+#~ msgid "Bass"
+#~ msgstr "Baixos"
+
+#~ msgid "Treble"
+#~ msgstr "Agudos"
+
+#~ msgid "Synth"
+#~ msgstr "Sintetizador"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Altofalante"
+
+#~ msgid "Line-in"
+#~ msgstr "Liña de entrada"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Misturador"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Gravar"
+
+#~ msgid "In-gain"
+#~ msgstr "Ganancia de entrada"
+
+#~ msgid "Out-gain"
+#~ msgstr "Ganancia de saída"
+
+#~ msgid "Line-1"
+#~ msgstr "Liña 1"
+
+#~ msgid "Line-2"
+#~ msgstr "Liña 2"
+
+#~ msgid "Line-3"
+#~ msgstr "Liña 3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Dixital 1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Dixital 2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Dixital 3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Entrada teléfono"
+
+#~ msgid "Phone-out"
+#~ msgstr "Saída teléfono"
+
+#~ msgid "Video"
+#~ msgstr "Vídeo"
+
+#~ msgid "Radio"
+#~ msgstr "Radio"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr ""
+#~ "Non foi posíbel abrir o dispositivo de son para a súa xestión polo "
+#~ "control de misturado."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Non foi posíbel abrir o dispositivo de son para a súa xestión polo "
+#~ "control de misturado. Este elemento non admite esta versión do Open Sound "
+#~ "System."
+
+#~ msgid "Master"
+#~ msgstr "Mestre"
+
+#~ msgid "Front"
+#~ msgstr "Frontal"
+
+#~ msgid "Rear"
+#~ msgstr "Treseiro"
+
+#~ msgid "Headphones"
+#~ msgstr "Auriculares"
+
+#~ msgid "Center"
+#~ msgstr "Centro"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Envolvente"
+
+#~ msgid "Side"
+#~ msgstr "Lateral"
+
+#~ msgid "AUX Out"
+#~ msgstr "Saída AUX"
+
+#~ msgid "3D Depth"
+#~ msgstr "Profundidade 3D"
+
+#~ msgid "3D Center"
+#~ msgstr "Centro 3D"
+
+#~ msgid "3D Enhance"
+#~ msgstr "Mellora 3D"
+
+#~ msgid "Telephone"
+#~ msgstr "Teléfono"
+
+#~ msgid "Video In"
+#~ msgstr "Entrada de vídeo"
+
+#~ msgid "AUX In"
+#~ msgstr "Entrada AUX"
+
+#~ msgid "Record Gain"
+#~ msgstr "Ganancia de gravación"
+
+#~ msgid "Output Gain"
+#~ msgstr "Ganancia de saída"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Aumento do micrófono"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Diagnóstico"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Aumento de baixos"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Portos de reprodución"
+
+#~ msgid "Input"
+#~ msgstr "Entrada"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Monitor de orixe"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Pitido de teclado"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Simular estéreo"
+
+#~ msgid "Stereo"
+#~ msgstr "Estéreo"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Son envolvente"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Ganancia do micrófono"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Altofalante de orixe"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Micrófono de orixe"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Centro / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Misturador estéreo"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Misturador mono"
+
+#~ msgid "Input Mix"
+#~ msgstr "Misturador de entrada"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Micrófono 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Micrófono 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Saída dixital"
+
+#~ msgid "Digital In"
+#~ msgstr "Entrada dixital"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Módem"
+
+#~ msgid "Handset"
+#~ msgstr "Auriculares"
+
+#~ msgid "Other"
+#~ msgstr "Outro"
+
+#~ msgid "None"
+#~ msgstr "Ningún"
+
+#~ msgid "On"
+#~ msgstr "Acendido"
+
+#~ msgid "Off"
+#~ msgstr "Apagado"
+
+#~ msgid "Mute"
+#~ msgstr "Silenciar"
+
+#~ msgid "Fast"
+#~ msgstr "Rápido"
+
+#~ msgid "Very Low"
+#~ msgstr "Moi baixo"
+
+#~ msgid "Low"
+#~ msgstr "Baixo"
+
+#~ msgid "Medium"
+#~ msgstr "Medio"
+
+#~ msgid "High"
+#~ msgstr "Alto"
+
+#~ msgid "Very High"
+#~ msgstr "Moi alto"
+
+#~ msgid "Production"
+#~ msgstr "Produción"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Micrófono do panel frontal"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Entrada do panel frontal"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Auriculares do panel frontal"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Saída do panel frontal"
+
+#~ msgid "Green Connector"
+#~ msgstr "Conectador verde"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Conectador rosa"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Conectador azul"
+
+#~ msgid "White Connector"
+#~ msgstr "Conectador branco"
+
+#~ msgid "Black Connector"
+#~ msgstr "Conectador negro"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Conectador gris"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Conectador laranxa"
+
+#~ msgid "Red Connector"
+#~ msgstr "Conectador vermello"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Conectador amarelo"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Conectador verde do panel frontal"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Conectador rosa do panel frontal"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Conectador azul do panel frontal"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Conectador branco do panel frontal"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Conectador negro do panel frontal"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Conectador gris do panel frontal"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Conectador laranxado panel frontal"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Conectador vermello do panel frontal"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Conectador amarelo do panel frontal"
+
+#~ msgid "Spread Output"
+#~ msgstr "Expandir saída"
+
+#~ msgid "Downmix"
+#~ msgstr "Redución de canles"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Entrada do misturador virtual"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Saída do misturador virtual"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Canles do misturador virtual"
+
+#~ msgid "%s %d Function"
+#~ msgstr "Función %s %d"
+
+#~ msgid "%s Function"
+#~ msgstr "Función %s"
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Obtívose un tamaño de marco de %u non esperado no lugar de %u."
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Produciuse un erro ao ler %d bytes do dispositivo «%s»."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Non é posíbel meter na cola os búferes no dispositivo «%s»."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr ""
+#~ "Produciuse un fallo ao tentar obter cadros de vídeo do dispositivo «%s»."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr ""
+#~ "Prouciuse un fallo despois de %d intentos. Dispositivo %s. Error do "
+#~ "sistema: %s"
+
+#~ msgid "Describes the selected input element."
+#~ msgstr "Describe o elemento de entrada seleccionado."
+
+#~ msgid "Describes the selected output element for Audio/Video Conferencing."
+#~ msgstr ""
+#~ "Describe o elemento de saída seleccionado para a Conferencia de Audio/"
+#~ "Vídeo."
+
+#~ msgid "Describes the selected output element for Music and Movies."
+#~ msgstr ""
+#~ "Describe o elemento de saída seleccionado para a Música e Películas."
+
+#~ msgid "Describes the selected output element."
+#~ msgstr "Describe o elemento de saída seleccionado."
+
+#~ msgid "GStreamer audiosink for Audio/Video Conferencing"
+#~ msgstr "GStreamer audiosink para a Conferencia de Audio/Video"
+
+#~ msgid "GStreamer audiosink for Music and Movies"
+#~ msgstr "GStreamer audiosink para Música e Filmes"
+
+#~ msgid ""
+#~ "GStreamer can play audio using any number of output elements. Some "
+#~ "possible choices are osssink, esdsink and alsasink. The audiosink can be "
+#~ "a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer pode reproducir audio empregando calquera número de elementos "
+#~ "de saída. Algunha elección posíbel é ossink, esdsink e alsasink. O "
+#~ "audiosink pode ser un pipeline parcial no cando de só un elemento único."
+
+#~ msgid ""
+#~ "GStreamer can play video using any number of output elements. Some "
+#~ "possible choices are xvimagesink, ximagesink, sdlvideosink and aasink. "
+#~ "The videosink can be a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer pode reproducir vídeo usando calquera número de elementos de "
+#~ "saída. As posíbeis eleccións son xvimagesink, ximagesink, sdlvideosink e "
+#~ "aasink. O videosink pode ser un pipeline parcial no lugar de un elemento "
+#~ "único."
+
+#~ msgid ""
+#~ "GStreamer can put visualization plugins in a pipeline to transform audio "
+#~ "stream in video frames. Default is goom but more visualization plugins "
+#~ "will be ported soon. The visualization plugin can be a partial pipeline "
+#~ "instead of just one element."
+#~ msgstr ""
+#~ "GStreamer pode poñer engadidos de visualización nun pipeline para "
+#~ "transformar un fluxo de audio en marcos de vídeo. Por omisión é goom pero "
+#~ "pronto convertiránse máis visualizacións. O engadido de visualización "
+#~ "pode ser un pipeline parcial no lugar de só un elemento."
+
+#~ msgid ""
+#~ "GStreamer can record audio using any number of input elements. Some "
+#~ "possible choices are osssrc, esdsrc and alsasrc. The audio source can be "
+#~ "a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer pode gravar audio usando calquera número de elementos de "
+#~ "entrada. Algunhas das posíbeis eleccións son osssrc, esdsrc e alsasrc. A "
+#~ "orixe do audio pode ser un pipeline parcial no lugar de un só elemento."
+
+#~ msgid ""
+#~ "GStreamer can record video from any number of input elements. Some "
+#~ "possible choices are v4lsrc and videotestsrc. The video source can be a "
+#~ "partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer pode gravar audio usando calquera número de elementos de "
+#~ "entrada. Algunhas das posíbeis eleccións son v4lsrc e videotestsrc. A "
+#~ "orixe do audio pode ser un pipeline parcial no lugar de un só elemento."
+
+#~ msgid "default GStreamer audio source"
+#~ msgstr "orixe de son de GStreamer predefinida"
+
+#~ msgid "default GStreamer audiosink"
+#~ msgstr "orixe do audiosink GStreamer predefinida"
+
+#~ msgid "default GStreamer video source"
+#~ msgstr "orixe do vídeo de GStreamer predefinido"
+
+#~ msgid "default GStreamer videosink"
+#~ msgstr "videosink de GStreamer predefinido"
+
+#~ msgid "default GStreamer visualization plugin"
+#~ msgstr "engadido de visualización GStreamer predefinido"
+
+#~ msgid "description for GStreamer audiosink for Audio/Video Conferencing"
+#~ msgstr ""
+#~ "descrición para o audiosink GStreamer para a conferencia de audio/vídeo"
+
+#~ msgid "description for GStreamer audiosink for Music and Movies"
+#~ msgstr "descrición para o audiosink de GStreamer para Música e Filmes"
+
+#~ msgid "description for default GStreamer audiosink"
+#~ msgstr "descrición para o audiosink de GStreamer predefinido"
+
+#~ msgid "description for default GStreamer audiosrc"
+#~ msgstr "descrición para o audiosrc de GStreamer predefinido"
diff --git a/po/hr.po b/po/hr.po
new file mode 100644
index 0000000..d687c17
--- /dev/null
+++ b/po/hr.po
@@ -0,0 +1,786 @@
+# Translation of gst-plugins-good to Croatian.
+# This file is put in the public domain.
+#
+# Tomislav Krznar <tomislav.krznar@gmail.com>, 2012.
+# Božidar Putanec <bozidarp@yahoo.com>, 2016.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good-1.10.0\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-11-19 10:22-0800\n"
+"Last-Translator: Božidar Putanec <bozidarp@yahoo.com>\n"
+"Language-Team: Croatian <lokalizacija@linux.hr>\n"
+"Language: hr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+"X-Generator: Poedit 1.8.7.1\n"
+
+msgid "Jack server not found"
+msgstr "‘Jack’ poslužitelj nije pronađen"
+
+msgid "Failed to decode JPEG image"
+msgstr "Nije uspjelo dekodirati JPEG sliku"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "‘%s’ (‘%s’)"
+
+msgid "Could not connect to server"
+msgstr "Spajanje na poslužitelj nije moguće"
+
+msgid "No URL set."
+msgstr "URL adresa nije imenovana."
+
+msgid "Could not resolve server name."
+msgstr "Nije moguće razriješiti ime poslužitelja."
+
+msgid "Could not establish connection to server."
+msgstr "Nije moguće uspostaviti vezu s poslužiteljem."
+
+msgid "Secure connection setup failed."
+msgstr "Uspostavljanje sigurne veze nije uspjelo."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Dogodila se mrežna greška, ili je poslužitelj neočekivano zatvorio vezu."
+
+msgid "Server sent bad data."
+msgstr "Poslužitelj je poslao neispravne podatke."
+
+msgid "Server does not support seeking."
+msgstr "Poslužitelj ne podržava traženje."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Nema audio ulaza ili je neispravan, AVI stream će biti iskvaren."
+
+msgid "This file contains no playable streams."
+msgstr "Ova datoteka ne sadrži nijedan upotrebljivi stream (tok podataka)."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Datoteka je neispravna i ne može se reproducirati."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+"Ovaj stream nije moguće reproducirati jer je kriptiran s PlayReady DRM."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Datoteka je iskvarena i ne može se reproducirati."
+
+msgid "Invalid atom size."
+msgstr "Veličina atoma je neispravna."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Datoteka je nepotpuna i ne može se reproducirati."
+
+msgid "The video in this file might not play correctly."
+msgstr "Video iz ove datoteke se možda neće ispravno reproducirati."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+"U ovoj datoteci ima previše streamova (streams). Samo prvih %d će se "
+"reproducirati"
+
+# https://gstreamer.freedesktop.org/documentation/rtp.html
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Nijedan podržani stream nije nađen. Možda ćete morati instalirati GStreamer "
+"RTSP dodatni plugin za Real medijske streamove."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Nijedan podržani stream nije nađen. Možda ćete morati dopustiti više "
+"prijenosnih protokola ili možda vam nedostaje odgovarajući GStreamer RTSP "
+"dodatni plugin."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Audiouređaj nije moguće otvoriti za reprodukciju. Uređaj trenutačno koristi "
+"neka druga aplikacija."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Audiouređaj nije moguće otvoriti za reprodukciju. Nemate dopuštenje za "
+"otvaranje uređaja."
+
+msgid "Could not open audio device for playback."
+msgstr "Audiouređaj nije moguće otvoriti za reprodukciju."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Audiouređaj nije moguće otvoriti za reprodukciju. Ovaj element ne podržava "
+"ovu inačicu Open Sound System."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Ovaj audiouređaj ne podržava reprodukciju."
+
+msgid "Audio playback error."
+msgstr "Greška u audio reprodukciji."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Ovaj audiouređaj ne podržava snimanje."
+
+msgid "Error recording from audio device."
+msgstr "Greška snimanja s audiouređaja."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Audiouređaj nije moguće otvoriti za snimanje. Nemate dopuštenje za otvaranje "
+"uređaja."
+
+msgid "Could not open audio device for recording."
+msgstr "Audiouređaj nije moguće otvoriti za snimanje."
+
+msgid "CoreAudio device not found"
+msgstr "CoreAudio uređaj nije pronađen"
+
+msgid "CoreAudio device could not be opened"
+msgstr "CoreAudio uređaj nije moguće otvoriti"
+
+msgid "Record Source"
+msgstr "Izvor snimanja"
+
+msgid "Microphone"
+msgstr "Mikrofon"
+
+msgid "Line In"
+msgstr "Linijski ulaz"
+
+msgid "Internal CD"
+msgstr "Interni CD"
+
+msgid "SPDIF In"
+msgstr "SPDIF ulaz"
+
+msgid "AUX 1 In"
+msgstr "AUX 1 ulaz"
+
+msgid "AUX 2 In"
+msgstr "AUX 2 ulaz"
+
+msgid "Codec Loopback"
+msgstr "Kodek-povratna petlja"
+
+msgid "SunVTS Loopback"
+msgstr "SunVTS-povratna petlja"
+
+msgid "Volume"
+msgstr "Glasnoća"
+
+msgid "Gain"
+msgstr "Pojačanje"
+
+msgid "Monitor"
+msgstr "Nadzor"
+
+msgid "Built-in Speaker"
+msgstr "Ugrađeni zvučnik"
+
+msgid "Headphone"
+msgstr "Slušalica"
+
+msgid "Line Out"
+msgstr "Linijski izlaz"
+
+msgid "SPDIF Out"
+msgstr "SPDIF izlaz"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1 izlaz"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2 izlaz"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Greška čitanja %d bajtova s uređaja ‘%s’."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Nije uspjelo nabrojati sve moguće video formate s kojima uređaj ‘%s’ može "
+"raditi"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Nije moguće preslikati (map) međuspremnike iz uređaja ‘%s’"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Upravljački program uređaja ‘%s’ ne podržava IO metodu %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"Upravljački program uređaja ‘%s’ ne podržava nijednu poznatu IO metodu."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Uređaj ‘%s’ je zauzet"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Uređaj ‘%s’ ne može snimati s razlučivosti od %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Uređaj ‘%s’ ne može snimati u specificiranom formatu."
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Device ‘%s’ ne podržava prekinute ravnine"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Parametre uređaja ‘%s’ nije moguće dobiti"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "Videouređaj nije prihvatio novu frekvenciju slika (ili poluslika)."
+
+msgid "Video device did not provide output format."
+msgstr "Videouređaj nije predočio izlazni format."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Videouređaj je uzvratio s neispravnim dimenzijama."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+"Videouređaj koristi nepodržanu metodu poluslika (prored i frekvenciju)."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Videouređaj koristi nepodržani format piksela."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Nije uspjelo konfigurirati internu zalihu međuspremnika."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Videouređaj nije predložio nijednu veličinu međuspremnika."
+
+msgid "No downstream pool to import from."
+msgstr "Nema se od nikuda uvesti ‘downstream’ zaliha."
+
+# tuner > štelanje frekvencije, mijenjanje (biranje) kanala
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Nije uspjelo dobiti postavke tunera %d na uređaj ‘%s’."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Greška pri dobivanju podataka o mogućnostima uređaja ‘%s’."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Uređaj ‘%s’ nije tuner."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Nije uspjelo dobiti radijski ulaz na uređaju ‘%s’. "
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Nije uspjelo postaviti ulaz %d na uređaj %s."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Nije uspjelo promijeniti status mute (Zvûk (da/ne) za uređaj ‘%s’."
+
+msgid "Failed to allocated required memory."
+msgstr "Nije uspjelo izdvojiti potrebnu memoriju."
+
+msgid "Failed to allocate required memory."
+msgstr "Nije uspjelo dodijeliti potrebnu memoriju."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Konverter na uređaju %s nema podržani ulazni format"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Konverter na uređaju %s nema podržani izlazni format"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Koder na uređaju %s nema podržani ulazni format"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Koder na uređaju %s nema podržani izlazni format"
+
+msgid "Failed to start decoding thread."
+msgstr "Nije uspjelo započeti dekodiranje niti (thread)."
+
+msgid "Failed to process frame."
+msgstr "Nije uspjelo obraditi sliku (polusliku)."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Greška pri dobivanja mogućnosti za uređaj ‘%s’: To nije v4l2 upravljački "
+"program. Provjerite da li je v4l1 upravljački program."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Nije uspjelo ispitati svojstva ulaza %d uređaja %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Nije uspjelo dobiti postavke tunera %d uređaja ‘%s’."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Nije uspjelo ispitati normu (standard) na uređaju ‘%s’."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Nije uspjelo dobiti upravljačka svojstva uređaja ‘%s’."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Ne može se identificirati uređaj ‘%s’."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Ovo nije uređaj ‘%s’."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Uređaj ‘%s’nije moguće otvoriti za čitanje i pisanje."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Uređaj ‘%s’ nije uređaj za snimanje."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Uređaj ‘%s’ nije izlazni uređaj."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Uređaj ‘%s’ nije M2M uređaj."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Uređaj ‘%s’nije moguće duplicirati za čitanje i pisanje."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Nije uspjelo postaviti normu (standard) za uređaj ‘%s’."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Nije uspjelo dobiti trenutačnu frekvenciju tunera za uređaj ‘%s’."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Nije uspjelo postaviti trenutačnu frekvenciju tunera za uređaj ‘%s’ na %lu "
+"Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Nije uspjelo dobiti snagu signala za uređaj ‘%s’."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Nije uspjelo dobiti vrijednost za kontrolu %d na uređaju ‘%s’."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Nije uspjelo postaviti vrijednost %d za kontrolu %d na uređaju ‘%s’."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Nije uspjelo dobiti trenutačni ulaz na uređaju ‘%s’. Možda je to radiouređaj"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Nije uspjelo dobiti trenutačni izlaz na uređaju ‘%s’. Možda je to radiouređaj"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Nije uspjelo postaviti izlaz %d na uređaj %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Promjena rezolucije u tijeku rada (runtime) još nije podržana."
+
+msgid "Cannot operate without a clock"
+msgstr "Ne mogu raditi bez takta (sata)"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Interna greška toka (stream) podataka."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Interna greška protoka podataka."
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Ne mogu ostvariti vezu prema poslužitelju zvuka"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Nisam uspio ispitati mogućnosti poslužitelja zvuka"
+
+#~ msgid "Bass"
+#~ msgstr "Niski"
+
+#~ msgid "Treble"
+#~ msgstr "Visoki"
+
+#~ msgid "Synth"
+#~ msgstr "Sintetizator"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Zvučnik"
+
+#~ msgid "Line-in"
+#~ msgstr "Ulazna linija"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Mikser"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Snimanje"
+
+#~ msgid "In-gain"
+#~ msgstr "Ulazno pojačanje"
+
+#~ msgid "Out-gain"
+#~ msgstr "Izlazno pojačanje"
+
+#~ msgid "Line-1"
+#~ msgstr "Linija 1"
+
+#~ msgid "Line-2"
+#~ msgstr "Linija 2"
+
+#~ msgid "Line-3"
+#~ msgstr "Linija 3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Digitalni 1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Digitalni 2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Digitalni 3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Telefonski ulaz"
+
+#~ msgid "Phone-out"
+#~ msgstr "Telefonski izlaz"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Radio"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "Ne mogu otvoriti zvučni uređaj za upravljanje mikserom."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Ne mogu otvoriti zvučni uređaj za upravljanje mikserom. Ovaj element ne "
+#~ "podržava ovu inačicu Open Sound System sustava."
+
+#~ msgid "Master"
+#~ msgstr "Glavni"
+
+#~ msgid "Front"
+#~ msgstr "Prednji"
+
+#~ msgid "Rear"
+#~ msgstr "Stražnji"
+
+#~ msgid "Headphones"
+#~ msgstr "Slušalice"
+
+#~ msgid "Center"
+#~ msgstr "Srednji"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Surround"
+
+#~ msgid "Side"
+#~ msgstr "Bočni"
+
+#~ msgid "AUX Out"
+#~ msgstr "AUX izlaz"
+
+#~ msgid "3D Depth"
+#~ msgstr "3D dubina"
+
+#~ msgid "3D Center"
+#~ msgstr "3D središte"
+
+#~ msgid "3D Enhance"
+#~ msgstr "3D dopuna"
+
+#~ msgid "Telephone"
+#~ msgstr "Telefon"
+
+#~ msgid "Video In"
+#~ msgstr "Video ulaz"
+
+#~ msgid "AUX In"
+#~ msgstr "AUX ulaz"
+
+#~ msgid "Record Gain"
+#~ msgstr "Pojačanje snimanja"
+
+#~ msgid "Output Gain"
+#~ msgstr "Pojačanje izlaza"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Pojačanje mikrofona"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Dijagnostika"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Pojačanje niskih"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Portovi reprodukcije"
+
+#~ msgid "Input"
+#~ msgstr "Ulaz"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Izvor nadziranja"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Tipkovnički zvuk"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Simuliraj stereo"
+
+#~ msgid "Stereo"
+#~ msgstr "Stereo"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Surround zvuk"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Pojačanje mikrofona"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Izvor zvučnika"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Izvor mikrofona"
+
+#~ msgid "Jack"
+#~ msgstr "Priključak"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Srednji / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Stereo mikser"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Mono mikser"
+
+#~ msgid "Input Mix"
+#~ msgstr "Ulazni mikser"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Mikrofon 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Mikrofon 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Digitalni izlaz"
+
+#~ msgid "Digital In"
+#~ msgstr "Digitalni ulaz"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modem"
+
+#~ msgid "Handset"
+#~ msgstr "Slušalice s mikrofonom"
+
+#~ msgid "Other"
+#~ msgstr "Ostalo"
+
+#~ msgid "None"
+#~ msgstr "Nijedan"
+
+#~ msgid "On"
+#~ msgstr "Uključen"
+
+#~ msgid "Off"
+#~ msgstr "Isključen"
+
+#~ msgid "Mute"
+#~ msgstr "Utišan"
+
+#~ msgid "Fast"
+#~ msgstr "Brzo"
+
+#~ msgid "Very Low"
+#~ msgstr "Vrlo niska"
+
+#~ msgid "Low"
+#~ msgstr "Niska"
+
+#~ msgid "Medium"
+#~ msgstr "Srednja"
+
+#~ msgid "High"
+#~ msgstr "Visoka"
+
+#~ msgid "Very High"
+#~ msgstr "Vrlo visoka"
+
+#~ msgid "Production"
+#~ msgstr "Produkcijska"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Mikrofon na prednjoj ploči"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Linijski ulaz na prednjoj ploči"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Slušalice na prednjoj ploči"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Linijski izlaz na prednjoj ploči"
+
+#~ msgid "Green Connector"
+#~ msgstr "Zelena priključnica"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Ružičasta priključnica"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Plava priključnica"
+
+#~ msgid "White Connector"
+#~ msgstr "Bijela priključnica"
+
+#~ msgid "Black Connector"
+#~ msgstr "Crna priključnica"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Siva priključnica"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Narančasta priključnica"
+
+#~ msgid "Red Connector"
+#~ msgstr "Crvena priključnica"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Žuta priključnica"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Zelena priključnica na prednjoj ploči"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Ružičasta priključnica na prednjoj ploči"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Plava priključnica na prednjoj ploči"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Bijela priključnica na prednjoj ploči"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Crna priključnica na prednjoj ploči"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Siva priključnica na prednjoj ploči"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Narančasta priključnica na prednjoj ploči"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Crvena priključnica na prednjoj ploči"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Žuta priključnica na prednjoj ploči"
+
+#~ msgid "Spread Output"
+#~ msgstr "Rašireni izlaz"
+
+#~ msgid "Downmix"
+#~ msgstr "Smanjenje broja kanala"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Ulaz virtualnog miksera"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Izlaz virtualnog miksera"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Kanali virtualnog miksera"
+
+#~ msgid "%s %d Function"
+#~ msgstr "%s %d funkcija"
+
+#~ msgid "%s Function"
+#~ msgstr "%s funkcija"
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Dobivena neočekivana veličina okvira %u umjesto %u."
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Greška čitanja %d bajtova na uređaju „%s”."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Nisam uspio dodati u red međuspremnike u uređaj „%s”."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Nisam uspio pokušavajući dobiti video okvire iz uređaja „%s”."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Nisam uspio nakon %d pokušaja. uređaj %s. greška sustava: %s"
diff --git a/po/hu.po b/po/hu.po
new file mode 100644
index 0000000..8b88e25
--- /dev/null
+++ b/po/hu.po
@@ -0,0 +1,790 @@
+# Hungarian translation for gst-plugins-good.
+# Copyright (C) 2004, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+# This file is distributed under the same license as the gst-plugins-good package.
+#
+# Laszlo Dvornik <dvornik@invitel.hu>, 2004.
+# Gabor Kelemen <kelemeng@gnome.hu>, 2007, 2008, 2009, 2010, 2012, 2014, 2016.
+# Balázs Úr <urbalazs@gmail.com>, 2014, 2015.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-03-14 18:35+0100\n"
+"Last-Translator: Gabor Kelemen <kelemeng@gnome.hu>\n"
+"Language-Team: Hungarian <translation-team-hu@lists.sourceforge.net>\n"
+"Language: hu\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Rosetta-Export-Date: 2007-07-27 19:18:15+0000\n"
+"X-Generator: Lokalize 1.5\n"
+"X-Rosetta-Export-Date: 2007-07-27 19:18:15+0000\n"
+"Plural-Forms:  nplurals=2; plural=(n != 1);\n"
+
+msgid "Jack server not found"
+msgstr "Jack kiszolgáló nem található"
+
+msgid "Failed to decode JPEG image"
+msgstr "A JPEG kép visszafejtése meghiúsult"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "„%s” ettől: „%s”"
+
+msgid "Could not connect to server"
+msgstr "Nem sikerült csatlakozni a kiszolgálóhoz"
+
+msgid "No URL set."
+msgstr "Nincs beállítva URL."
+
+msgid "Could not resolve server name."
+msgstr "Nem sikerült feloldani a kiszolgáló nevét."
+
+msgid "Could not establish connection to server."
+msgstr "Nem hozható létre kapcsolat a kiszolgálóhoz."
+
+msgid "Secure connection setup failed."
+msgstr "A biztonságos kapcsolat kialakítása meghiúsult."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Hálózati hiba történt, vagy a kiszolgáló váratlanul lezárta a kapcsolatot."
+
+msgid "Server sent bad data."
+msgstr "A kiszolgáló hibás adatokat küldött."
+
+msgid "Server does not support seeking."
+msgstr "A kiszolgáló nem támogatja a tekerést."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Nincs vagy érvénytelen bemeneti hang, az AVI-folyam sérült lesz."
+
+msgid "This file contains no playable streams."
+msgstr "A fájl nem tartalmaz lejátszható adatfolyamokat."
+
+msgid "This file is invalid and cannot be played."
+msgstr "A fájl nem érvényes és nem játszható le."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+"Nem lehet lejátszani a folyamot, mert PlayReady DRM titkosítás van rajta."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "A fájl sérült és nem játszható le."
+
+msgid "Invalid atom size."
+msgstr "Érvénytelen atom méret."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "A fájl nem teljes és nem játszható le."
+
+msgid "The video in this file might not play correctly."
+msgstr "A fájlban található videó lehet, hogy nem játszható le megfelelően."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+"A fájl túl sok adatfolyamot tartalmaz. Csak az első %d kerül lejátszásra."
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Nem található támogatott adatfolyam. Telepítse a GStreamer RTSP bővítményt a "
+"Real media adatfolyamokhoz."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Nem található támogatott adatfolyam. Lehet, hogy több átviteli protokollt "
+"kell engedélyezni, vagy hiányzik a megfelelő GStreamer RTSP bővítmény."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Nem nyitható meg hangeszköz a lejátszáshoz. Az eszközt másik alkalmazás "
+"használja."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Nem nyitható meg hangeszköz a lejátszáshoz. Nincs jogosultsága az eszköz "
+"megnyitására."
+
+msgid "Could not open audio device for playback."
+msgstr "Nem nyitható meg hangeszköz a lejátszáshoz."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Nem nyitható meg hangeszköz a lejátszáshoz. Az Open Sound System ezen "
+"verzióját az elem nem támogatja."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Ez a hangeszköz nem támogatja a lejátszást."
+
+msgid "Audio playback error."
+msgstr "Hanglejátszási hiba."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Ez a hangeszköz nem támogatja a felvételt."
+
+msgid "Error recording from audio device."
+msgstr "Hiba a hangeszközről való felvételkor."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Nem nyitható meg hangeszköz a felvételhez. Nincs jogosultsága az eszköz "
+"megnyitására."
+
+msgid "Could not open audio device for recording."
+msgstr "Nem nyitható meg hangeszköz a felvételhez."
+
+msgid "CoreAudio device not found"
+msgstr "A CoreAudio eszköz nem található"
+
+msgid "CoreAudio device could not be opened"
+msgstr "A CoreAudio eszköz nem nyitható meg"
+
+msgid "Record Source"
+msgstr "Felvétel forrása"
+
+msgid "Microphone"
+msgstr "Mikrofon"
+
+msgid "Line In"
+msgstr "Vonalbemenet"
+
+msgid "Internal CD"
+msgstr "Belső CD"
+
+msgid "SPDIF In"
+msgstr "SPDIF be"
+
+msgid "AUX 1 In"
+msgstr "1. AUX be"
+
+msgid "AUX 2 In"
+msgstr "2. AUX be"
+
+msgid "Codec Loopback"
+msgstr "Kodek visszacsatolás"
+
+msgid "SunVTS Loopback"
+msgstr "SunVTS visszacsatolás"
+
+msgid "Volume"
+msgstr "Hangerő"
+
+msgid "Gain"
+msgstr "Erősítés"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "Beépített hangszóró"
+
+msgid "Headphone"
+msgstr "Fejhallgató"
+
+msgid "Line Out"
+msgstr "Vonalkimenet"
+
+msgid "SPDIF Out"
+msgstr "SPDIF ki"
+
+msgid "AUX 1 Out"
+msgstr "1. AUX ki"
+
+msgid "AUX 2 Out"
+msgstr "2. AUX ki"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Hiba %d bájt olvasásakor a következő eszközről: „%s”."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"A(z) „%s” eszköz által kezelhető lehetséges videoformátumok felsorolása "
+"sikertelen"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Nem képezhetők le a(z) „%s” eszköz pufferei"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "A(z) „%s” eszköz illesztőprogramja nem támogatja a(z) %d. IO módot"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"A(z) „%s” eszköz illesztőprogramja nem támogat egyetlen ismert IO módot sem."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "A(z) „%s” eszköz foglalt"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "A(z) „%s” eszköz nem képes felvenni %dx%d felbontásban"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "A(z) „%s” eszköz nem képes felvenni a megadott formátumban"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "A(z) „%s” eszköz nem támogatja a nem szomszédos síkokat"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Nem kérhetők le a(z) „%s” eszköz paraméterei"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "A videoeszköz nem fogadta el az új képkockasebesség-beállítást."
+
+msgid "Video device did not provide output format."
+msgstr "A videoeszköz nem szolgáltatott kimeneti formátumot."
+
+msgid "Video device returned invalid dimensions."
+msgstr "A videoeszköz érvénytelen dimenziókkal tért vissza."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "A videoeszközök nem támogatott váltottsoros módot használnak."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "A videoeszközök nem támogatott képpontformátumot használnak."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Nem sikerült beállítani a belső puffertárolót."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "A videoeszköz nem javasolt semmilyen pufferméretet."
+
+msgid "No downstream pool to import from."
+msgstr "Nincs importálási forrásként használható alárendelt tároló."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "A(z) %d. tuner beállításának lekérése a(z) „%s” eszközön meghiúsult."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Hiba a(z) „%s” eszköz képességeinek lekérésekor."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "A(z) „%s” eszköz nem tuner."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "A rádióbemenet lekérése meghiúsult a(z) „%s” eszközön."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "A(z) %d. bemenet beállítása meghiúsult a(z) „%s” eszközön."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "A némítási állapot módosítása meghiúsult a(z) „%s” eszközön."
+
+msgid "Failed to allocated required memory."
+msgstr "Nem sikerült lefoglalni a szükséges memóriát."
+
+msgid "Failed to allocate required memory."
+msgstr "Nem sikerült lefoglalni a szükséges memóriát."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "A(z) %s eszközön lévő átalakítónak nincs támogatott bemeneti formátuma"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "A(z) %s eszközön lévő átalakítónak nincs támogatott kimeneti formátuma"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "A(z) %s eszközön lévő kódolónak nincs támogatott bemeneti formátuma"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "A(z) %s eszközön lévő kódolónak nincs támogatott kimeneti formátuma"
+
+msgid "Failed to start decoding thread."
+msgstr "Nem sikerült elindítani a dekódolási szálat."
+
+msgid "Failed to process frame."
+msgstr "Nem sikerült feldolgozni a keretet."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Hiba a(z) „%s” eszköz képességeinek lekérésekor. Ez nem egy v4l2 meghajtó. "
+"Ellenőrizze, hogy nem v4l1 meghajtó-e."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "A(z) %d bemenet attribútumainak lekérése meghiúsult a(z) %s eszközön"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "A(z) %d. tuner beállításának lekérése a(z) „%s” eszközön meghiúsult."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "A norma lekérdezése meghiúsult a(z) „%s” eszköztől."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "A vezérlőattribútumok lekérése meghiúsult a(z) „%s” eszközön."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Nem azonosítható a(z) „%s” eszköz."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Ez nem egy eszköz: „%s”."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Nem sikerült olvasásra és írásra megnyitni a(z) „%s” eszközt."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "A(z) „%s” eszköz nem rögzítőeszköz."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "A(z) „%s” eszköz nem kimeneti eszköz."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "A(z) „%s” eszköz nem M2M eszköz."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Nem sikerült duplikálni a(z) „%s” eszközt olvasásra és írásra."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "A norma beállítása meghiúsult a(z) „%s” eszközön."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+"A tuner aktuális frekvenciájának lekérdezése meghiúsult a(z) „%s” eszköztől."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"A tuner aktuális frekvenciájának beállítása meghiúsult a(z) „%s” eszközön "
+"%lu Hz-re."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "A jelerősség lekérdezése meghiúsult a(z) „%s” eszközön."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "A(z) %d. vezérlőelem értékének lekérése meghiúsult a(z) „%s” eszközön."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr ""
+"A(z) $%2d érték beállítása $%1d vezérlőelemhez meghiúsult a(z) „%s” eszközön."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Az aktuális bemenet lekérése meghiúsult a(z) „%s” eszközről. Lehet, hogy ez "
+"egy rádióeszköz."
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Az aktuális kimenet lekérése meghiúsult a(z) „%s” eszközről. Lehet, hogy ez "
+"egy rádióeszköz."
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "A(z) %d. kimenet beállítása meghiúsult a(z) „%s” eszközön."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "A felbontás módosítása futás közben még nem támogatott."
+
+msgid "Cannot operate without a clock"
+msgstr "Óra nélkül lehetetlen a működés"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Belső adatfolyam-hiba."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Belső adatfolyam-hiba."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "A(z) „%s” eszköz nem támogatja a videofelvételt"
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Nem hozható létre kapcsolat a hangkiszolgálóhoz"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "A hangkiszolgáló képességeinek lekérdezése meghiúsult"
+
+#~ msgid "Bass"
+#~ msgstr "Basszus"
+
+#~ msgid "Treble"
+#~ msgstr "Magas"
+
+#~ msgid "Synth"
+#~ msgstr "Szintet."
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Hangfal"
+
+#~ msgid "Line-in"
+#~ msgstr "Vonalbemenet"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Keverő"
+
+#~ msgid "PCM-2"
+#~ msgstr "2. PCM"
+
+#~ msgid "Record"
+#~ msgstr "Felvétel"
+
+#~ msgid "In-gain"
+#~ msgstr "Be-erősítés"
+
+#~ msgid "Out-gain"
+#~ msgstr "Ki-erősítés"
+
+#~ msgid "Line-1"
+#~ msgstr "1. vonal"
+
+#~ msgid "Line-2"
+#~ msgstr "2. vonal"
+
+#~ msgid "Line-3"
+#~ msgstr "3. vonal"
+
+#~ msgid "Digital-1"
+#~ msgstr "1. digitális"
+
+#~ msgid "Digital-2"
+#~ msgstr "2. digitális"
+
+#~ msgid "Digital-3"
+#~ msgstr "3. digitális"
+
+#~ msgid "Phone-in"
+#~ msgstr "Hang-be"
+
+#~ msgid "Phone-out"
+#~ msgstr "Hang-ki"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Rádió"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "Nem nyitható meg hangeszköz a keverővezérlő kezeléséhez."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Nem nyitható meg hangeszköz a keverővezérlő kezeléséhez. Az Open Sound "
+#~ "System ezen verzióját az elem nem támogatja."
+
+#~ msgid "Master"
+#~ msgstr "Fő hangerő"
+
+#~ msgid "Front"
+#~ msgstr "Elülső"
+
+#~ msgid "Rear"
+#~ msgstr "Hátsó"
+
+#~ msgid "Headphones"
+#~ msgstr "Fülhallgató"
+
+#~ msgid "Center"
+#~ msgstr "Középső"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Térhatású"
+
+#~ msgid "Side"
+#~ msgstr "Oldalsó"
+
+#~ msgid "AUX Out"
+#~ msgstr "AUX ki"
+
+#~ msgid "3D Depth"
+#~ msgstr "3D mély"
+
+#~ msgid "3D Center"
+#~ msgstr "3D középső"
+
+#~ msgid "3D Enhance"
+#~ msgstr "3D javítás"
+
+#~ msgid "Telephone"
+#~ msgstr "Telefon"
+
+#~ msgid "Video In"
+#~ msgstr "Video be"
+
+#~ msgid "AUX In"
+#~ msgstr "AUX be"
+
+#~ msgid "Record Gain"
+#~ msgstr "Felvételerősítés"
+
+#~ msgid "Output Gain"
+#~ msgstr "Kimeneterősítés"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Mikrofonerősítés"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Diagnosztika"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Basszuskiemelés"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Lejátszási portok"
+
+#~ msgid "Input"
+#~ msgstr "Bemenet"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Monitor forrása"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Billentyűzetcsengő"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Sztereó szimulálása"
+
+#~ msgid "Stereo"
+#~ msgstr "Sztereó"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Térhatású hang"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Mikrofonerősítés"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Hangfalforrás"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Mikrofonforrás"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Középső / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Sztereó keverés"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Monó keverés"
+
+#~ msgid "Input Mix"
+#~ msgstr "Bemeneti keverés"
+
+#~ msgid "Microphone 1"
+#~ msgstr "1. mikrofon"
+
+#~ msgid "Microphone 2"
+#~ msgstr "2. mikrofon"
+
+#~ msgid "Digital Out"
+#~ msgstr "Digitális ki"
+
+#~ msgid "Digital In"
+#~ msgstr "Digitális be"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modem"
+
+#~ msgid "Handset"
+#~ msgstr "Mobiltelefon"
+
+#~ msgid "Other"
+#~ msgstr "Egyéb"
+
+#~ msgid "None"
+#~ msgstr "Nincs"
+
+#~ msgid "On"
+#~ msgstr "Be"
+
+#~ msgid "Off"
+#~ msgstr "Ki"
+
+#~ msgid "Mute"
+#~ msgstr "Némítás"
+
+#~ msgid "Fast"
+#~ msgstr "Gyors"
+
+#~ msgid "Very Low"
+#~ msgstr "Nagyon alacsony"
+
+#~ msgid "Low"
+#~ msgstr "Alacsony"
+
+#~ msgid "Medium"
+#~ msgstr "Közepes"
+
+#~ msgid "High"
+#~ msgstr "Magas"
+
+#~ msgid "Very High"
+#~ msgstr "Nagyon magas"
+
+#~ msgid "Production"
+#~ msgstr "Éles"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Előlapi mikrofon"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Előlapi vonalbemenet"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Előlapi fülhallgató"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Előlapi vonalkimenet"
+
+#~ msgid "Green Connector"
+#~ msgstr "Zöld csatlakozó"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Rózsaszín csatlakozó"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Kék csatlakozó"
+
+#~ msgid "White Connector"
+#~ msgstr "Fehér csatlakozó"
+
+#~ msgid "Black Connector"
+#~ msgstr "Fekete csatlakozó"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Szürke csatlakozó"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Narancs csatlakozó"
+
+#~ msgid "Red Connector"
+#~ msgstr "Vörös csatlakozó"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Sárga csatlakozó"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Zöld előoldali csatlakozó"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Rózsaszín előoldali csatlakozó"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Kék előoldali csatlakozó"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Fehér előoldali csatlakozó"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Fekete előoldali csatlakozó"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Szürke előoldali csatlakozó"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Narancs előoldali csatlakozó"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Vörös előoldali csatlakozó"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Sárga előoldali csatlakozó"
+
+#~ msgid "Spread Output"
+#~ msgstr "Szóráskimenet"
+
+#~ msgid "Downmix"
+#~ msgstr "Lekeverés"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Virtuális keverőbemenet"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Virtuális keverőkimenet"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Virtuális keverőcsatornák"
+
+#~ msgid "%s %d Function"
+#~ msgstr "%s %d funkció"
+
+#~ msgid "%s Function"
+#~ msgstr "%s funkció"
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Váratlan keretméret (%u) érkezett %u helyett."
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Hiba %d bájt olvasásakor a következő eszközről: „%s”."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Nem állíthatók sorba a pufferek a(z) „%s” eszközben."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Nem sikerült videokockákat lekérni a(z) „%s” eszköztől."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Hiba %d próbálkozás után. Eszköz: %s. Rendszerhiba: %s."
diff --git a/po/id.po b/po/id.po
new file mode 100644
index 0000000..e240f83
--- /dev/null
+++ b/po/id.po
@@ -0,0 +1,433 @@
+# Indonesian translations for gst-plugins-good package.
+# This file is put in the public domain.
+#
+# Andhika Padmawan <andhika.padmawan@gmail.com>, 2011-2016.
+# Andika Triwidada <andika@gmail.com>, 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.10.0\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-11-10 22:06+0700\n"
+"Last-Translator: Andhika Padmawan <andhika.padmawan@gmail.com>\n"
+"Language-Team: Indonesian <translation-team-id@lists.sourceforge.net>\n"
+"Language: id\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+msgid "Jack server not found"
+msgstr "Server Jack tak ditemukan"
+
+msgid "Failed to decode JPEG image"
+msgstr "Gagal untuk mengawasandi citra JPEG"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "'%s' oleh '%s'"
+
+msgid "Could not connect to server"
+msgstr "Tak dapat menghubungi server"
+
+msgid "No URL set."
+msgstr "Tak ada URL yang ditentukan."
+
+msgid "Could not resolve server name."
+msgstr "Tak dapat menemukan nama server."
+
+msgid "Could not establish connection to server."
+msgstr "Tak dapat membangun koneksi ke server."
+
+msgid "Secure connection setup failed."
+msgstr "Pengaturan koneksi aman gagal."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Terjadi sebuah galat jaringan, atau server menutup koneksi secara tiba-tiba."
+
+msgid "Server sent bad data."
+msgstr "Server mengirim data rusak."
+
+msgid "Server does not support seeking."
+msgstr "Server tidak mendukung pencarian."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Masukan audio tidak ada atau tidak sah, arus AVI akan rusak."
+
+msgid "This file contains no playable streams."
+msgstr "Berkas ini tidak berisi arus yang dapat diputar."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Berkas ini tidak sah dan tak dapat diputar."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr "Tak bisa memainkan stream karena dienkripsi memakai DRM PlayReady."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Berkas ini rusak dan tak dapat diputar."
+
+msgid "Invalid atom size."
+msgstr "Ukuran atom tidak sah."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Berkas ini tidak lengkap dan tak dapat diputar."
+
+msgid "The video in this file might not play correctly."
+msgstr "Video di berkas ini mungkin tak dapat diputar dengan benar."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Berkas ini berisi terlalu banyak arus. Hanya memutar %d pertama"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Tak ada arus didukung yang ditemukan. Anda mungkin perlu menginstal plugin "
+"ekstensi GStreamer RTSP untuk arus Real media."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Tak ada arus didukung yang ditemukan. Anda mungkin ingin mengizinkan lebih "
+"banyak transportasi atau kehilangan plugin ekstensi GStreamer RTSP yang "
+"benar."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Tak dapat membuka divais audio untuk putar kembali. Divais sedang digunakan "
+"oleh aplikasi lain."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Tak dapat membuka divais audio untuk putar kembali. Anda tak memiliki hak "
+"akses untuk membuka divais."
+
+msgid "Could not open audio device for playback."
+msgstr "Tak dapat membuka divais audio untuk putar kembali."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Tak dapat membuka divais audio untuk putar kembali. Versi Open Sound System "
+"ini tidak didukung oleh elemen ini."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Putar balik tidak didukung oleh divais audio ini."
+
+msgid "Audio playback error."
+msgstr "Galat putar balik audio."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Perekaman tidak didukung oleh divais audio ini."
+
+msgid "Error recording from audio device."
+msgstr "Galat merekam dari divais audio."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Tak dapat membuka divais audio untuk merekam. Anda tak memiliki hak akses "
+"untuk membuka divais."
+
+msgid "Could not open audio device for recording."
+msgstr "Tak dapat membuka divais audio untuk merekam."
+
+msgid "CoreAudio device not found"
+msgstr "Divais CoreAudio tidak ditemukan"
+
+msgid "CoreAudio device could not be opened"
+msgstr "Divais CoreAudio tidak dapat buka"
+
+msgid "Record Source"
+msgstr "Sumber Rekaman"
+
+msgid "Microphone"
+msgstr "Mikrofon"
+
+msgid "Line In"
+msgstr "Jalur Masuk"
+
+msgid "Internal CD"
+msgstr "CD Internal"
+
+msgid "SPDIF In"
+msgstr "SPDIF Masuk"
+
+msgid "AUX 1 In"
+msgstr "AUX 1 Masuk"
+
+msgid "AUX 2 In"
+msgstr "AUX 2 Masuk"
+
+msgid "Codec Loopback"
+msgstr "Loopback Kodek"
+
+msgid "SunVTS Loopback"
+msgstr "Loopback SunVTS"
+
+msgid "Volume"
+msgstr "Volume"
+
+msgid "Gain"
+msgstr "Gain"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "Pengeras Suara Terbina"
+
+msgid "Headphone"
+msgstr "Headphone"
+
+msgid "Line Out"
+msgstr "Jalur Keluar"
+
+msgid "SPDIF Out"
+msgstr "SPDIF Keluar"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1 Keluar"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2 Keluar"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Galat membaca %d bita dari divais '%s'."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Gagal menyebutkan kemungkinan format video yang dapat bekerja dengan divais "
+"'%s'."
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Tak dapat memetakan penyangga dari divais '%s'"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Driver dari divais '%s' tak mendukung metode IO %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Driver dari divais '%s' tak mendukung metode IO apapun yang dikenal."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Divais '%s' sibuk"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Divais '%s' tak dapat menangkap di %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Divais '%s' tak dapat menangkap dalam format yang ditentukan"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Divais '%s' tak mendukung pesawat tak bersinggungan"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Tak bisa mendapatkan parameter di divais '%s'"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "Divais video tak menerima pengaturan laju bingkai baru."
+
+msgid "Video device did not provide output format."
+msgstr "Divais video tak menyediakan format keluaran."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Divais video mengembalikan dimensi tidak sah."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Divais video menggunakan metode penyilangan yang tidak didukung."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Divais video menggunakan format pixel yang tidak didukung."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Gagal mengatur pul singgahan internal."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Divais video tak menyarankan ukuran singgahan apapun."
+
+msgid "No downstream pool to import from."
+msgstr "Tak ada pul downstream untuk diimpor."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Gagal mendapatkan pengaturan tuner %d di divais '%s'."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Galat saat mengambil kapabilitas bagi divais '%s'."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Divais '%s' bukan tuner."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Gagal mendapat masukan radio pada divais '%s'."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Gagal mengatur masukan %d di divais %s."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Gagal mengubah keadaan bisu untuk divais '%s'."
+
+msgid "Failed to allocated required memory."
+msgstr "Gagal mengalokasikan memori yang diperlukan."
+
+msgid "Failed to allocate required memory."
+msgstr "Gagal mengalokasikan memori yang diperlukan."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Konverter di divais %s tidak mempunyai format masukan yang didukung"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Konverter di divais %s tidak mempunyai format keluaran yang didukung"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Penyandi di divais %s tidak mempunyai format masukan yang didukung"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Penyandi di divais %s tidak mempunyai format keluaran yang didukung"
+
+msgid "Failed to start decoding thread."
+msgstr "Gagal untuk menjalankan tali awasandi."
+
+msgid "Failed to process frame."
+msgstr "Gagal memproses bingkai."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Galat mendapatkan kemampuan untuk divais '%s': Itu bukan diver v4l2. Cek "
+"apakah itu merupakan driver v4l1."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Gagal kueri atribut masukan %d di divais %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Gagal mendapatkan pengaturan tuner %d di divais '%s'."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Gagal kueri standar di divais '%s'."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Gagal mendapatkan kendali atribut di divais '%s'."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Tak dapat mengidentifikasi divais '%s'."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Ini bukan divais '%s'."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Tak dapat membuka divais '%s' untuk dibaca dan ditulis."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Divais '%s' bukan divais penangkap."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Divais '%s' bukan divais keluaran."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Divais '%s' bukan divais M2M."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Tak dapat membuka divais '%s' untuk dibaca dan ditulis."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Gagal mengatur standar untuk divais '%s'."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Gagal untuk mendapatkan frekuensi tuner terkini untuk divais '%s'."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr "Gagal mengatur frekuensi tuner terkini untuk divais '%s' ke %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Gagal mendapatkan kekuatan sinyal untuk divais '%s'."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Gagal mendapatkan nilai untuk kendali %d di divais '%s'."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Gagal mengatur nilai %d untuk kendali %d di divais '%s'."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Gagal mendapatkan masukan terkini di divais '%s'. Mungkin itu divais radio"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Gagal mendapatkan keluaran terkini di divais '%s'. Mungkin itu divais radio"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Gagal mengatur keluaran %d di divais %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Mengubah resolusi saat waktu berjalan belum didukung."
+
+msgid "Cannot operate without a clock"
+msgstr "Tak dapat beroperasi tanpa jam"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Galat arus data internal."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Galat aliran data internal."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Divais '%s' tak mendukung penangkapan video"
diff --git a/po/it.po b/po/it.po
new file mode 100644
index 0000000..340b592
--- /dev/null
+++ b/po/it.po
@@ -0,0 +1,817 @@
+# Italian translation for gst-plugins-good package of GStreamer project.
+# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 GStreamer core team
+# This file is distributed under the same license as the gst-plugins-good package.
+#
+# Luca Ferretti <elle.uca@infinito.it>, 2004, 2005, 2006, 2007, 2008, 2009, 2010.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 0.10.25.3\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2010-10-25 10:11+0200\n"
+"Last-Translator: Luca Ferretti <elle.uca@infinito.it>\n"
+"Language-Team: Italian <tp@lists.linux.it>\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr "Decodifica dell'immagine JPEG non riuscita"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "«%s» di «%s»"
+
+msgid "Could not connect to server"
+msgstr "Impossibile connettersi al server"
+
+msgid "No URL set."
+msgstr "Nessun URL impostato."
+
+msgid "Could not resolve server name."
+msgstr "Impossibile risolvere il nome del server."
+
+msgid "Could not establish connection to server."
+msgstr "Impossibile stabilire la connessione al server."
+
+msgid "Secure connection setup failed."
+msgstr "Impostazione della connessione sicura non riuscita."
+
+#, fuzzy
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Si è verificato un errore di rete, oppure il server ha chiuso la connessione "
+"in modo inatteso."
+
+msgid "Server sent bad data."
+msgstr "In server ha inviato dati errati."
+
+msgid "Server does not support seeking."
+msgstr "Il server non supporta il posizionamento."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr ""
+"Ingresso audio assente o non valido. Lo stream AVI risulterà danneggiato."
+
+msgid "This file contains no playable streams."
+msgstr "Questo file non contiene alcuno stream riproducibile."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Questo file non è valido e non può essere riprodotto."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Questo file è alterato e non può essere riprodotto."
+
+msgid "Invalid atom size."
+msgstr ""
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Questo file è incompleto e non può essere riprodotto."
+
+msgid "The video in this file might not play correctly."
+msgstr "Il video in questo file potrebbe non essere riprodotto correttamente."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Questo file contiene troppi stream. Riprodotti solo i primi %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Non è stato trovato alcuno stream supportato. Potrebbe essere necessario "
+"installare un plugin GStreamer di tipo estensione RTSP per gli stream Real "
+"media."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Non è stato trovato alcuno stream supportato. Potrebbe essere necessario "
+"abilitare altri protocolli di trasporto oppure in alternativa potrebbe "
+"mancare il corretto plugin GStreamer di tipo estensione RTSP."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Impossibile aprire il dispositivo audio per la riproduzione. Il dispositivo "
+"è attualmente usato da un'altra applicazione."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Impossibile aprire il dispositivo audio per la riproduzione. Permessi non "
+"sufficienti per aprire il dispositivo."
+
+msgid "Could not open audio device for playback."
+msgstr "Impossibile aprire il dispositivo audio per la riproduzione."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Impossibile aprire il device audio per la riproduzione. Questa versione di "
+"Open Sound System non è supportata da questo elemento."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Questo device audio non supporta la riproduzione."
+
+msgid "Audio playback error."
+msgstr "Errore nel riprodurre l'audio."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Questo dispositivo audio non supporta la registrazione."
+
+msgid "Error recording from audio device."
+msgstr "Errore nel registrare dal dispositivo audio."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Impossibile aprire il dispositivo audio per la registrazione. Permessi non "
+"sufficienti per aprire il dispositivo."
+
+msgid "Could not open audio device for recording."
+msgstr "Impossibile aprire il dispositivo audio per la registrazione."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "Sorgente registrazione"
+
+msgid "Microphone"
+msgstr "Microfono"
+
+msgid "Line In"
+msgstr "Linea in"
+
+msgid "Internal CD"
+msgstr "CD interno"
+
+msgid "SPDIF In"
+msgstr "SPDIF in"
+
+msgid "AUX 1 In"
+msgstr "AUX 1 in"
+
+msgid "AUX 2 In"
+msgstr "AUX 2 in"
+
+#, fuzzy
+msgid "Codec Loopback"
+msgstr "Loopback"
+
+#, fuzzy
+msgid "SunVTS Loopback"
+msgstr "Loopback"
+
+msgid "Volume"
+msgstr "Volume"
+
+msgid "Gain"
+msgstr "Guadagno"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "Altop. incorporato"
+
+msgid "Headphone"
+msgstr "Cuffia"
+
+msgid "Line Out"
+msgstr "Linea out"
+
+msgid "SPDIF Out"
+msgstr "SPDIF out"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1 out"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2 out"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Errore nel leggere %d byte dal device «%s»."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Impossibile mappare dei buffer dal device «%s»."
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Il driver del device «%s» non supporta alcun metodo di cattura noto."
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Il driver del device «%s» non supporta alcun metodo di cattura noto."
+
+#, fuzzy, c-format
+msgid "Device '%s' is busy"
+msgstr "Il device «%s» non è un dispositivo di uscita."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Il device «%s» non è un dispositivo di cattura."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Il device «%s» non è un dispositivo di cattura."
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Il device «%s» non è un dispositivo di uscita."
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Impossibile ottenere i parametri sul device «%s»"
+
+#, fuzzy
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+"Il device di ingresso video non accetta la nuova impostazione sul frame rate."
+
+#, fuzzy
+msgid "Video device did not provide output format."
+msgstr ""
+"Il device di ingresso video non accetta la nuova impostazione sul frame rate."
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Il driver del device «%s» non supporta alcun metodo di cattura noto."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Il driver del device «%s» non supporta alcun metodo di cattura noto."
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+#, fuzzy
+msgid "Video device did not suggest any buffer size."
+msgstr ""
+"Il device di ingresso video non accetta la nuova impostazione sul frame rate."
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr ""
+"Recupero delle impostazioni del sintonizzatore %d sul device «%s» non "
+"riuscito."
+
+#, fuzzy, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Errore nel leggere %d byte dal device «%s»."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Il device «%s» non è un dispositivo di uscita."
+
+#, fuzzy, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Impostazione dell'ingresso %d sul device «%s» non riuscita."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Impostazione dell'ingresso %d sul device «%s» non riuscita."
+
+#, fuzzy, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Recupero dell'intensità del segnale per il device «%s» non riuscito."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Il driver del device «%s» non supporta alcun metodo di cattura noto."
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+"Il device di ingresso video non accetta la nuova impostazione sul frame rate."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+"Il device di ingresso video non accetta la nuova impostazione sul frame rate."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+"Il device di ingresso video non accetta la nuova impostazione sul frame rate."
+
+#, fuzzy
+msgid "Failed to start decoding thread."
+msgstr "Decodifica dell'immagine JPEG non riuscita"
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Errore nell'ottenere le funzionalità per il device «%s»: non è un driver "
+"v4l2. Controllare se si tratta di un driver v4l1."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr ""
+"Interrogazione degli attributi dell'input %d nel device %s non riuscita"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr ""
+"Recupero delle impostazioni del sintonizzatore %d sul device «%s» non "
+"riuscito."
+
+#  norm è un paramentro pari a ntsc o pal (e forse altro. Si evince ad esempio
+#  dal comando di Video Lan Clien
+#
+#     vlc --color  #    v4l:/dev/video2:norm=ntsc:frequency=77250:size=640x480:#    adev=/dev/dsp2:audio=0 (...)
+#
+#  Qualche idea diversa da norma?  -Luca
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Interrogazione di norm sul device «%s» non riuscita."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Recupero degli attributi dei controlli sul device «%s» non riuscito."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Impossibile identificare il device «%s»."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Questo non è un dispositivo «%s»."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Impossibile aprire il device «%s» in lettura e scrittura."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Il device «%s» non è un dispositivo di cattura."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Il device «%s» non è un dispositivo di uscita."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Il device «%s» non è un dispositivo di uscita."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Impossibile aprire il device «%s» in lettura e scrittura."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Impostazione di norm per il device «%s» non riuscita."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+"Recupero dell'attuale frequenza di sintonizzazione per il device «%s» non "
+"riuscita."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Impostazione dell'attuale frequenza di sintonizzazione per il device «%s» a "
+"%lu Hz non riuscita."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Recupero dell'intensità del segnale per il device «%s» non riuscito."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Recupero del valore per il controllo %d sul device «%s» non riuscito."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr ""
+"Impostazione al valore %d per il controllo %d sul device «%s» non riuscito."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Recupero dell'attuale ingresso sul device «%s» non riuscito. Forse è un "
+"dispositivo radio"
+
+#, fuzzy, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Recupero dell'attuale ingresso sul device «%s» non riuscito. Forse è un "
+"dispositivo radio"
+
+#, fuzzy, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Impostazione dell'ingresso %d sul device «%s» non riuscita."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr ""
+"Il cambio della risoluzione durante l'esecuzione non è ancora supportato."
+
+msgid "Cannot operate without a clock"
+msgstr "Impossibile operare senza un clock"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Errore interno nello stream dei dati."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Errore interno nel flusso di dati."
+
+#, fuzzy
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Il device «%s» non è un dispositivo di uscita."
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Ottenuta dimensione inattesa del fotogramma: %u invece di %u."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr ""
+#~ "Tentativo di ottenere fotogrammi video dal device «%s» non riuscito."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Fallito dopo %d tentativi. Device %s. Errore di sistema: %s"
+
+#~ msgid "Bass"
+#~ msgstr "Bassi"
+
+#~ msgid "Treble"
+#~ msgstr "Acuti"
+
+#~ msgid "Synth"
+#~ msgstr "Sintetiz"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Altoparl"
+
+#~ msgid "Line-in"
+#~ msgstr "Linea in"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Mixer"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Registr"
+
+#~ msgid "In-gain"
+#~ msgstr "Guad in"
+
+#~ msgid "Out-gain"
+#~ msgstr "Guad out"
+
+#~ msgid "Line-1"
+#~ msgstr "Canale 1"
+
+#~ msgid "Line-2"
+#~ msgstr "Canale 2"
+
+#~ msgid "Line-3"
+#~ msgstr "Canale 3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Digital 1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Digital 2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Digital 3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Telefono in"
+
+#~ msgid "Phone-out"
+#~ msgstr "Telefono out"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Radio"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr ""
+#~ "Impossibile aprire il device audio per la gestione della regolazione del "
+#~ "mixer."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Impossibile aprire il device audio per la gestione della regolazione del "
+#~ "mixer. Questa versione di Open Sound System non è supportata da questo "
+#~ "elemento."
+
+#~ msgid "Master"
+#~ msgstr "Principale"
+
+#~ msgid "Front"
+#~ msgstr "Fronte"
+
+#~ msgid "Rear"
+#~ msgstr "Dietro"
+
+#~ msgid "Headphones"
+#~ msgstr "Cuffie"
+
+#~ msgid "Center"
+#~ msgstr "Centrale"
+
+# NdT: lfe andrebbe tradotto come effetti a bassa frequenza e andrebbe aperto un bug per low frequency emitter che al limite è la cassa ma non il canale
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Surround"
+
+#~ msgid "Side"
+#~ msgstr "Laterale"
+
+#~ msgid "AUX Out"
+#~ msgstr "AUX out"
+
+#~ msgid "3D Depth"
+#~ msgstr "Profondità 3D"
+
+#~ msgid "3D Center"
+#~ msgstr "Centro 3D"
+
+#~ msgid "3D Enhance"
+#~ msgstr "Profondità 3D"
+
+#~ msgid "Telephone"
+#~ msgstr "Telefono"
+
+#~ msgid "Video In"
+#~ msgstr "Video in"
+
+#~ msgid "AUX In"
+#~ msgstr "AUX in"
+
+#~ msgid "Record Gain"
+#~ msgstr "Guadagno registrazione"
+
+#~ msgid "Output Gain"
+#~ msgstr "Guadagno uscita"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Incremento microfono"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Diagnostica"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Incremento bassi"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Porte riproduzione"
+
+#~ msgid "Input"
+#~ msgstr "Input"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Sorgente monitor"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Beep tastiera"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Simula stereo"
+
+#~ msgid "Stereo"
+#~ msgstr "Stereo"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Suono surround"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Guadagno microfono"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Sorgente altoparlante"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Sorgente microfono"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+# vedi prima per LFE
+#~ msgid "Center / LFE"
+#~ msgstr "Centrale / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Mix stereo"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Mix mono"
+
+#~ msgid "Input Mix"
+#~ msgstr "Mix ingresso"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Microfono 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Microfono 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Uscita digitale"
+
+#~ msgid "Digital In"
+#~ msgstr "Ingresso digitale"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modem"
+
+#~ msgid "Handset"
+#~ msgstr "Auricolare"
+
+#~ msgid "Other"
+#~ msgstr "Altro"
+
+#~ msgid "None"
+#~ msgstr "Nessuno"
+
+#~ msgid "On"
+#~ msgstr "Acceso"
+
+#~ msgid "Off"
+#~ msgstr "Spento"
+
+#~ msgid "Mute"
+#~ msgstr "Escluso"
+
+#~ msgid "Fast"
+#~ msgstr "Veloce"
+
+#~ msgid "Very Low"
+#~ msgstr "Molto lento"
+
+#~ msgid "Low"
+#~ msgstr "Lento"
+
+#~ msgid "Medium"
+#~ msgstr "Medio"
+
+#~ msgid "High"
+#~ msgstr "Alto"
+
+#~ msgid "Very High"
+#~ msgstr "Molto alto"
+
+#~ msgid "Production"
+#~ msgstr "Produzione"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Microfono pannello frontale"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Linea in pannello frontale"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Cuffie pannello frontale"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Linea out pannello frontale"
+
+#~ msgid "Green Connector"
+#~ msgstr "Connettore verde"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Connettore rosa"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Connettore blu"
+
+#~ msgid "White Connector"
+#~ msgstr "Connettore bianco"
+
+#~ msgid "Black Connector"
+#~ msgstr "Connettore nero"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Connettore grigio"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Connettore arancione"
+
+#~ msgid "Red Connector"
+#~ msgstr "Connettore rosso"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Connettore giallo"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Connettore verde pannello frontale"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Connettore rosa pannello frontale"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Connettore blu pannello frontale"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Connettore bianco pannello frontale"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Connettore nero pannello frontale"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Connettore grigio pannello frontale"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Connettore arancione pannello frontale"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Connettore rosso pannello frontale"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Connettore giallo pannello frontale"
+
+#  int spread;         /* copy front to surr/center channels */ 
+#~ msgid "Spread Output"
+#~ msgstr "Uscita diffusa"
+
+#~ msgid "Downmix"
+#~ msgstr "Downmix"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Ingresso mixer virtuale"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Uscita mixer virtuale"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Canali mixer virtuale"
+
+#~ msgid "%s %d Function"
+#~ msgstr "Funzione %s %d"
+
+#~ msgid "%s Function"
+#~ msgstr "Funzione %s"
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Errore nel leggere %d byte sul device «%s»."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Impossibile accodare i buffer nel device «%s»."
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Impossibile stabilire la connessione al server audio"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Interrogazione delle funzionalità del server audio non riuscita"
diff --git a/po/ja.po b/po/ja.po
new file mode 100644
index 0000000..7887124
--- /dev/null
+++ b/po/ja.po
@@ -0,0 +1,930 @@
+# Japanese translation for gst-plugins-good.
+# This file is put in the public domain.
+#
+# Takao Fujiwara <takao.fujiwara@sun.com>, 2006.
+# Makoto Kato <makoto.kt@gmail.com>, 2009-2011.
+# Takeshi Hamasaki <hmatrjp@users.sourceforge.jp>, 2011-2012
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.0.3\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2012-12-22 20:13+0900\n"
+"Last-Translator: Takeshi Hamasaki <hmatrjp@users.sourceforge.jp>\n"
+"Language-Team: Japanese <translation-team-ja@lists.sourceforge.net>\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.5.4\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr "JPEG画像のデコードに失敗しました"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "'%s' , '%s'"
+
+msgid "Could not connect to server"
+msgstr "サーバーへ接続できません"
+
+msgid "No URL set."
+msgstr "URLが指定されていません。"
+
+msgid "Could not resolve server name."
+msgstr "サーバー名を解決できません。"
+
+msgid "Could not establish connection to server."
+msgstr "サーバーへの接続を確立できません。"
+
+msgid "Secure connection setup failed."
+msgstr "セキュア接続のセットアップに失敗しました。"
+
+#, fuzzy
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr "ネットワークエラーが発生したか、サーバーが予期せず接続を閉じました。"
+
+msgid "Server sent bad data."
+msgstr "サーバが不正なデータを送信しました。"
+
+msgid "Server does not support seeking."
+msgstr "サーバーはシークをサポートしていません。"
+
+# SUN REVIEWED
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "入力オーディオが存在しないか無効であるため、AVI ストリームは壊れます。"
+
+msgid "This file contains no playable streams."
+msgstr "このファイルには再生不可能なストリームが含まれています"
+
+msgid "This file is invalid and cannot be played."
+msgstr "このファイルは不正なため再生することができません"
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr "このファイルは壊れているため再生することができません"
+
+msgid "Invalid atom size."
+msgstr "不正なアトムサイズ"
+
+msgid "This file is incomplete and cannot be played."
+msgstr "このファイルは正常ではないため、再生することができません"
+
+msgid "The video in this file might not play correctly."
+msgstr "このファイルの中の動画は正しく再生できないかもしれません"
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+"このファイルには多くのストリームが格納されているため、最初の %d 個のみ再生し"
+"ます"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"サポートしているストリームが見つかりません。Real メディアストリームのための"
+"GStreamer RTSP 拡張プラグインをインストールする必要があるかもしれません。"
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"サポートしているストリームが見つかりません。別の転送プロトコルをインストール"
+"する必要があるかもしれません。または、正しい GStreamer RTSP 拡張プラグインが"
+"ないのかもしれません。"
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"再生用にオーディオデバイスを開くことができませんでした。デバイスが他のアプリ"
+"ケーションで利用されています"
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"再生用にオーディオデバイスを開くことができませんでした。デバイスを開くための"
+"権限がありません。"
+
+# SUN REVIEWED
+msgid "Could not open audio device for playback."
+msgstr "音声デバイスを読み取り用に開くことができません。"
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"再生用にオーディオデバイスを開くことができませんでした。このバージョンの "
+"Open Sound System は、このエレメントによってサポートされていません。"
+
+msgid "Playback is not supported by this audio device."
+msgstr "再生はこのオーディオデバイスではサポートされていません。"
+
+msgid "Audio playback error."
+msgstr "オーディオ再生エラーです。"
+
+msgid "Recording is not supported by this audio device."
+msgstr "このオーディオデバイスによって録音はサポートされていません。"
+
+msgid "Error recording from audio device."
+msgstr "オーディオデバイスからの録音時にエラーが発生しました。"
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"録音用にオーディオデバイスを開くことができませんでした。デバイスを開くための"
+"権限がありません。"
+
+# SUN REVIEWED
+msgid "Could not open audio device for recording."
+msgstr "音声デバイスを録音用に開くことができません。"
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "録音ソース"
+
+# SUN REVIEWED
+msgid "Microphone"
+msgstr "マイクロフォン"
+
+msgid "Line In"
+msgstr "ライン入力"
+
+msgid "Internal CD"
+msgstr "内蔵CD"
+
+msgid "SPDIF In"
+msgstr "SPDIF入力"
+
+msgid "AUX 1 In"
+msgstr "AUX 1入力"
+
+msgid "AUX 2 In"
+msgstr "AUX 2入力"
+
+#, fuzzy
+msgid "Codec Loopback"
+msgstr "ループバック"
+
+#, fuzzy
+msgid "SunVTS Loopback"
+msgstr "ループバック"
+
+# SUN REVIEWED
+msgid "Volume"
+msgstr "音量"
+
+# SUN REVIEWED
+msgid "Gain"
+msgstr "ゲイン"
+
+# SUN REVIEWED
+msgid "Monitor"
+msgstr "モニター"
+
+msgid "Built-in Speaker"
+msgstr "ビルトインスピーカ"
+
+msgid "Headphone"
+msgstr "ヘッドフォン"
+
+msgid "Line Out"
+msgstr "ライン出力"
+
+msgid "SPDIF Out"
+msgstr "SPDIF出力"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1出力"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2出力"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "デバイス %2$s から %1$d バイト読み込み時にエラーが発生しました。"
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr "デバイス'%s'が作業できるビデオ形式の数え上げに失敗しました"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "デバイス '%s' からバッファをマップできません。"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "デバイス '%s' のドライバはIOメソッド%dをサポートしていません"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"デバイス '%s' のドライバは知られているいかなるIOメソッドもサポートしていませ"
+"ん。"
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "デバイス`%s'はビジー状態です"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "デバイス '%s' は %dx%d でキャプチャできません"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "デバイス '%s' は指定されたフォーマットでキャプチャできません"
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "デバイス '%s' はビデオキャプチャをサポートしていません"
+
+# SUN REVIEWED
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "デバイス '%s' 上のパラメータを取得できません。"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "ビデオデバイスが新しいフレームレート設定を受け付けません。"
+
+#, fuzzy
+msgid "Video device did not provide output format."
+msgstr "ビデオデバイスが新しいフレームレート設定を受け付けません。"
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "デバイス '%s' のドライバはIOメソッド%dをサポートしていません"
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "デバイス '%s' のドライバはIOメソッド%dをサポートしていません"
+
+#, fuzzy
+msgid "Failed to configure internal buffer pool."
+msgstr "ビデオデバイスはバッファプールを作成できませんでした。"
+
+#, fuzzy
+msgid "Video device did not suggest any buffer size."
+msgstr "ビデオデバイスはバッファプールを作成できませんでした。"
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "デバイス '%2$s' 上のチューナー %1$d の設定の取得に失敗しました。"
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "デバイス'%s' の能力を取得する時にエラーが発生しました。"
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "デバイス '%s' はチューナではありません。"
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "デバイス '%s' 上のラジオ入力の取得に失敗しました。"
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "デバイス '%2$s' 上の入力%1$d の設定に失敗しました。"
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "デバイス '%s' のミュート状態の変更に失敗しました"
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "デバイス '%s' のドライバはIOメソッド%dをサポートしていません"
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "ビデオデバイスが新しいフレームレート設定を受け付けません。"
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "ビデオデバイスが新しいフレームレート設定を受け付けません。"
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "ビデオデバイスが新しいフレームレート設定を受け付けません。"
+
+#, fuzzy
+msgid "Failed to start decoding thread."
+msgstr "JPEG画像のデコードに失敗しました"
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"デバイス '%s' の能力を取得する時にエラーが発生しました: v4l2 ドライバではあり"
+"ません。v4l1 ドライバでないか、チェックしてください。"
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "デバイス %2$s 内の入力 %1$d の属性のクエリーに失敗しました"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "デバイス '%2$s' 上のチューナー %1$d の設定の取得に失敗しました。"
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "デバイス '%s' 上のノルムの取得に失敗しました。"
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "デバイス '%s' のコントロール属性の取得に失敗しました"
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "デバイス'%s'を特定できません。"
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "これはデバイス '%s' ではありません"
+
+# SUN REVIEWED
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "デバイス '%s' を読み取り用と書き込み用に開くことができません"
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "デバイス '%s' はキャプチャデバイスではありません"
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "デバイス '%s' は出力デバイスではありません"
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "デバイス '%s' は出力デバイスではありません"
+
+# SUN REVIEWED
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "デバイス '%s' を読み取り用と書き込み用に開くことができません"
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "デバイス '%s' 上のノルムの設定に失敗しました。"
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "デバイス '%s' の現在のチューナーの周波数の取得に失敗しました"
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr "デバイス '%s' のチューナーの周波数の %lu Hz への設定に失敗しました"
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "デバイス '%s' の信号の強さの取得に失敗しました。"
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "デバイス '%2$s' 上のコントロール %1$d の値の取得に失敗しました。"
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr ""
+"デバイス '%3$s' 上のコントロール %2$d の値を %1$d へ設定することに失敗しまし"
+"た。"
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"デバイス '%s' 上の現在の入力の取得に失敗しました。ラジオデバイスかもしれませ"
+"ん"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"デバイス '%s' 上の現在の出力の取得に失敗しました。ラジオデバイスかもしれませ"
+"ん"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "出力%dをデバイス %s に設定できませんでした。"
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "実行時の解像度変更はサポートされていません。"
+
+msgid "Cannot operate without a clock"
+msgstr "クロックなしでは動作できません。"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "内部データストリームエラー"
+
+#~ msgid "Internal data flow error."
+#~ msgstr "内部データフローエラー。"
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "デバイス '%s' はビデオキャプチャをサポートしていません"
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "サウンドサーバーへの接続に失敗しました"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "サウンドサーバーのケイパビリティのクエリーに失敗しました"
+
+# SUN REVIEWED
+#~ msgid "Bass"
+#~ msgstr "低音"
+
+# SUN REVIEWED
+#~ msgid "Treble"
+#~ msgstr "高音"
+
+# SUN REVIEWED
+#~ msgid "Synth"
+#~ msgstr "シンセ"
+
+# SUN REVIEWED
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+# SUN REVIEWED
+#~ msgid "Speaker"
+#~ msgstr "スピーカ"
+
+#~ msgid "Line-in"
+#~ msgstr "ライン入力"
+
+# SUN REVIEWED
+#~ msgid "CD"
+#~ msgstr "CD"
+
+# SUN REVIEWED
+#~ msgid "Mixer"
+#~ msgstr "ミキサー"
+
+# SUN REVIEWED
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+# SUN REVIEWED
+#~ msgid "Record"
+#~ msgstr "録音"
+
+# SUN REVIEWED
+#~ msgid "In-gain"
+#~ msgstr "入力ゲイン"
+
+# SUN REVIEWED
+#~ msgid "Out-gain"
+#~ msgstr "出力ゲイン"
+
+# SUN REVIEWED
+#~ msgid "Line-1"
+#~ msgstr "ライン 1"
+
+# SUN REVIEWED
+#~ msgid "Line-2"
+#~ msgstr "ライン 2"
+
+# SUN REVIEWED
+#~ msgid "Line-3"
+#~ msgstr "ライン 3"
+
+# SUN REVIEWED
+#~ msgid "Digital-1"
+#~ msgstr "デジタル 1"
+
+# SUN REVIEWED
+#~ msgid "Digital-2"
+#~ msgstr "デジタル 2"
+
+# SUN REVIEWED
+#~ msgid "Digital-3"
+#~ msgstr "デジタル 3"
+
+# SUN REVIEWED
+#~ msgid "Phone-in"
+#~ msgstr "フォン入力"
+
+# SUN REVIEWED
+#~ msgid "Phone-out"
+#~ msgstr "フォン出力"
+
+# SUN REVIEWED
+#~ msgid "Video"
+#~ msgstr "ビデオ"
+
+# SUN REVIEWED
+#~ msgid "Radio"
+#~ msgstr "ラジオ"
+
+# SUN REVIEWED
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "音声デバイスをミキサーコントロール用に開くことができません。"
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "ミキサーコントロール用にオーディオデバイスを開くことができませんでした。"
+#~ "Open Sound Systemのこのバージョンではこの要素によってサポートされていませ"
+#~ "ん。"
+
+#~ msgid "Master"
+#~ msgstr "マスタ"
+
+#~ msgid "Front"
+#~ msgstr "フロント"
+
+#~ msgid "Rear"
+#~ msgstr "リア"
+
+#~ msgid "Headphones"
+#~ msgstr "ヘッドフォン"
+
+#~ msgid "Center"
+#~ msgstr "センター"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "サラウンド"
+
+#~ msgid "Side"
+#~ msgstr "サイド"
+
+#~ msgid "AUX Out"
+#~ msgstr "AUX出力"
+
+#, fuzzy
+#~ msgid "3D Depth"
+#~ msgstr "最大深度: "
+
+#~ msgid "3D Center"
+#~ msgstr "3Dセンター"
+
+#, fuzzy
+#~ msgid "3D Enhance"
+#~ msgstr "色を強調しています"
+
+#~ msgid "Telephone"
+#~ msgstr "電話"
+
+#~ msgid "Video In"
+#~ msgstr "ビデオ入力"
+
+#~ msgid "AUX In"
+#~ msgstr "AUX入力"
+
+#~ msgid "Record Gain"
+#~ msgstr "録音ゲイン"
+
+#~ msgid "Output Gain"
+#~ msgstr "出力ゲイン"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "マイクロフォンブースト"
+
+#~ msgid "Diagnostic"
+#~ msgstr "診断"
+
+#~ msgid "Bass Boost"
+#~ msgstr "低音ブースト"
+
+#~ msgid "Playback Ports"
+#~ msgstr "プレイバックポート"
+
+#~ msgid "Input"
+#~ msgstr "入力"
+
+#~ msgid "Monitor Source"
+#~ msgstr "モニターソース"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "キーボードビープ音"
+
+#, fuzzy
+#~ msgid "Simulate Stereo"
+#~ msgstr "彫金を表現します"
+
+#~ msgid "Stereo"
+#~ msgstr "ステレオ"
+
+#~ msgid "Surround Sound"
+#~ msgstr "サラウンドサウンド"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "マイクロフォンゲイン"
+
+#~ msgid "Speaker Source"
+#~ msgstr "スピーカソース"
+
+#~ msgid "Microphone Source"
+#~ msgstr "マイクロフォンソース"
+
+#~ msgid "Jack"
+#~ msgstr "ジャック"
+
+#~ msgid "Center / LFE"
+#~ msgstr "センター / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "ステレオミックス"
+
+#~ msgid "Mono Mix"
+#~ msgstr "モノラルミックス"
+
+#~ msgid "Input Mix"
+#~ msgstr "入力ミックス"
+
+#~ msgid "Microphone 1"
+#~ msgstr "マイクロフォン1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "マイクロフォン2"
+
+#~ msgid "Digital Out"
+#~ msgstr "デジタル出力"
+
+#~ msgid "Digital In"
+#~ msgstr "デジタル入力"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "モデム"
+
+#~ msgid "Handset"
+#~ msgstr "ヘッドセット"
+
+#~ msgid "Other"
+#~ msgstr "その他"
+
+#~ msgid "None"
+#~ msgstr "なし"
+
+#~ msgid "On"
+#~ msgstr "オン"
+
+#~ msgid "Off"
+#~ msgstr "オフ"
+
+#~ msgid "Mute"
+#~ msgstr "ミュート"
+
+#, fuzzy
+#~ msgid "Fast"
+#~ msgstr "速い"
+
+#, fuzzy
+#~ msgid "Very Low"
+#~ msgstr "低品位"
+
+#, fuzzy
+#~ msgid "Low"
+#~ msgstr "低音"
+
+#, fuzzy
+#~ msgid "Medium"
+#~ msgstr "中音"
+
+#, fuzzy
+#~ msgid "High"
+#~ msgstr "高音"
+
+#, fuzzy
+#~ msgid "Very High"
+#~ msgstr "高品位"
+
+#, fuzzy
+#~ msgid "Production"
+#~ msgstr "プロダクション"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "フロントパネルのマイクロフォン"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "フロントパネルのライン入力"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "フロントパネルのヘッドフォン"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "フロントパネルのライン出力"
+
+#~ msgid "Green Connector"
+#~ msgstr "緑色コネクタ"
+
+#~ msgid "Pink Connector"
+#~ msgstr "ピンク色コネクタ"
+
+#~ msgid "Blue Connector"
+#~ msgstr "青色コネクタ"
+
+#~ msgid "White Connector"
+#~ msgstr "白色コネクタ"
+
+#~ msgid "Black Connector"
+#~ msgstr "黒色コネクタ"
+
+#~ msgid "Gray Connector"
+#~ msgstr "グレー色コネクタ"
+
+#~ msgid "Orange Connector"
+#~ msgstr "オレンジ色コネクタ"
+
+#~ msgid "Red Connector"
+#~ msgstr "赤色コネクタ"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "黄色コネクタ"
+
+#, fuzzy
+#~ msgid "Spread Output"
+#~ msgstr "情報出力:\n"
+
+#~ msgid "Downmix"
+#~ msgstr "ダウンミックス"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "仮想ミキサー入力"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "仮想ミキサー出力"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "仮想ミキサーチャンネル"
+
+#, fuzzy
+#~ msgid "%s %d Function"
+#~ msgstr "機能"
+
+#, fuzzy
+#~ msgid "%s Function"
+#~ msgstr "機能"
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "予期しないフレームサイズ (%2$u ではなく %1$u) を取得しました。"
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr ""
+#~ "デバイス '%2$s' 上で %1$d バイトの読み込み時にエラーが発生しました。"
+
+#, fuzzy
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "デバイス '%s' からバッファをマップできません。"
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "デバイス '%s' からビデオフレームの取得に失敗しました。"
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr ""
+#~ "%d 回リトライしましたが失敗しました。デバイス %s。システムエラー: %s"
+
+#~ msgid ""
+#~ "Failed trying to get video frames from device '%s'. Not enough memory."
+#~ msgstr ""
+#~ "デバイス '%s' からビデオフレームを取得しようとしましたが失敗しました。メモ"
+#~ "リが十分にありません。"
+
+#~ msgid "No free buffers found in the pool at index %d."
+#~ msgstr "インデックス %d でプール内に空きバッファがありません。"
+
+#~ msgid "Could not get buffers from device '%s'."
+#~ msgstr "デバイス '%s' からバッファを取得できませんでした。"
+
+#~ msgid "Could not get enough buffers from device '%s'."
+#~ msgstr ""
+#~ "デバイス '%s' から十分なバッファー領域を取得することができませんでした"
+
+# SUN REVIEWED
+#, fuzzy
+#~ msgid "Could not read from CD."
+#~ msgstr "ファイル \"%s\" に書き込むことができません。"
+
+# SUN REVIEWED
+#, fuzzy
+#~ msgid "Disc is not an Audio CD."
+#~ msgstr "デバイスが開いていません。"
+
+# SUN REVIEWED
+#, fuzzy
+#~ msgid "Could not set parameters on device '%s'"
+#~ msgstr "CD デバイスを読み取り用に開くことができません。"
+
+# SUN REVIEWED
+#~ msgid ""
+#~ "GStreamer can play audio using any number of output elements. Some "
+#~ "possible choices are osssink, esdsink and alsasink. The audiosink can be "
+#~ "a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "オーディオを再生するとき、GStreamer は任意の数の出力要素を使用できます。使"
+#~ "用できる出力要素は、osssink、esdsink、および alsasink です。audiosink は単"
+#~ "なる 1 つの要素ではなく、パイプラインの一部になることができます。"
+
+# SUN REVIEWED
+#, fuzzy
+#~ msgid ""
+#~ "GStreamer can play video using any number of output elements. Some "
+#~ "possible choices are xvimagesink, ximagesink, sdlvideosink and aasink. "
+#~ "The videosink can be a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "ビデオを再生するとき、GStreamer は任意の数の出力要素を使用できます。使用で"
+#~ "きる出力要素は、xvideosink、sdlvideosink、および aasink です。videosink は"
+#~ "単なる 1 つの要素ではなく、パイプラインの一部になることができます。"
+
+# SUN REVIEWED
+#~ msgid ""
+#~ "GStreamer can put visualization plugins in a pipeline to transform audio "
+#~ "stream in video frames. Default is goom but more visualization plugins "
+#~ "will be ported soon. The visualization plugin can be a partial pipeline "
+#~ "instead of just one element."
+#~ msgstr ""
+#~ "GStreamer は視覚化プラグインをパイプラインに設定して、オーディオストリーム"
+#~ "をビデオフレームに変換できます。デフォルトは goom ですが、より多くの視覚化"
+#~ "プラグインがすぐに移植される予定です。視覚化プラグインは単なる 1 つの要素"
+#~ "ではなく、パイプラインの一部になることができます。"
+
+# SUN REVIEWED
+#~ msgid ""
+#~ "GStreamer can record audio using any number of input elements. Some "
+#~ "possible choices are osssrc, esdsrc and alsasrc. The audio source can be "
+#~ "a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "オーディオを記録するとき、GStreamer は任意の数の入力要素を使用できます。使"
+#~ "用できる入力要素は、osssrc、esdsrc、および alsasrc です。オーディオソース"
+#~ "は単なる 1 つの要素ではなく、パイプラインの一部になることができます。"
+
+# SUN REVIEWED
+#~ msgid ""
+#~ "GStreamer can record video from any number of input elements. Some "
+#~ "possible choices are v4lsrc and videotestsrc. The video source can be a "
+#~ "partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "ビデオを記録するとき、GStreamer は任意の数の入力要素を使用できます。使用で"
+#~ "きる入力要素は、v4lsrc および videotestsrc です。ビデオソースは単なる 1 つ"
+#~ "の要素ではなく、パイプラインの一部になることができます。"
+
+# SUN REVIEWED
+#~ msgid "default GStreamer audio source"
+#~ msgstr "デフォルトの GStreamer オーディオソース"
+
+# SUN REVIEWED
+#~ msgid "default GStreamer audiosink"
+#~ msgstr "デフォルトの GStreamer audiosink"
+
+# SUN REVIEWED
+#~ msgid "default GStreamer video source"
+#~ msgstr "デフォルトの GStreamer ビデオソース"
+
+# SUN REVIEWED
+#~ msgid "default GStreamer videosink"
+#~ msgstr "デフォルトの GStreamer videosink"
+
+# SUN REVIEWED
+#~ msgid "default GStreamer visualization plugin"
+#~ msgstr "デフォルトの GStreamer 視覚化プラグイン"
+
+# SUN REVIEWED
+#, fuzzy
+#~ msgid "description for default GStreamer audiosink"
+#~ msgstr "デフォルトの GStreamer audiosink"
+
+# SUN REVIEWED
+#, fuzzy
+#~ msgid "description for default GStreamer audiosrc"
+#~ msgstr "デフォルトの GStreamer オーディオソース"
+
+#~ msgid "Failed getting controls attributes on device '%s.'"
+#~ msgstr "デバイス '%s' のコントロール属性の取得に失敗しました"
diff --git a/po/ky.po b/po/ky.po
new file mode 100644
index 0000000..cd3afe7
--- /dev/null
+++ b/po/ky.po
@@ -0,0 +1,475 @@
+# Translation of 'gst-plugins-good' messages to Kirghiz.
+# Copyright (C) 2002 Free Software Foundation, Inc.
+# Ilyas Bakirov <just_ilyas@yahoo.com>, 2007.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 0.10.23\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2010-05-11 15:35+0100\n"
+"PO-Revision-Date: 2007-11-13 17:16+0600\n"
+"Last-Translator: Ilyas Bakirov <just_ilyas@yahoo.com>\n"
+"Language-Team: Kirghiz <i18n-team-ky-kyrgyz@lists.sourceforge.net>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-Language: Kyrgyz\n"
+"X-Poedit-Country: KYRGYZSTAN\n"
+
+#: sys/oss4/oss4-mixer.c:302
+#, fuzzy
+msgid "Could not open audio device for mixer control handling."
+msgstr "\"%s\"  файлы окууга ачылган жок."
+
+#: sys/oss4/oss4-mixer.c:316
+msgid ""
+"Could not open audio device for mixer control handling. This version of the "
+"Open Sound System is not supported by this element."
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:722
+msgid "Volume"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:723
+msgid "Master"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:724
+msgid "Front"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:725
+msgid "Rear"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:726
+msgid "Headphones"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:727
+msgid "Center"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:728
+msgid "LFE"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:729
+msgid "Surround"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:730
+msgid "Side"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:731
+msgid "Built-in Speaker"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:732
+msgid "AUX 1 Out"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:733
+msgid "AUX 2 Out"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:734
+msgid "AUX Out"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:735
+msgid "Bass"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:736
+msgid "Treble"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:737
+msgid "3D Depth"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:738
+msgid "3D Center"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:739
+msgid "3D Enhance"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:740
+msgid "Telephone"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:741
+msgid "Microphone"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:742
+msgid "Line Out"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:743 sys/oss4/oss4-mixer.c:744
+msgid "Line In"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:745
+msgid "Internal CD"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:746
+msgid "Video In"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:747
+msgid "AUX 1 In"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:748
+msgid "AUX 2 In"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:749
+msgid "AUX In"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:750
+msgid "PCM"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:751 sys/oss4/oss4-mixer.c:752
+msgid "Record Gain"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:753
+msgid "Output Gain"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:754
+msgid "Microphone Boost"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:755
+msgid "Loopback"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:756
+msgid "Diagnostic"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:757
+msgid "Bass Boost"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:758
+msgid "Playback Ports"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:759
+msgid "Input"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:760 sys/oss4/oss4-mixer.c:761
+msgid "Record Source"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:762
+msgid "Monitor Source"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:763
+msgid "Keyboard Beep"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:764
+msgid "Monitor"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:765
+msgid "Simulate Stereo"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:766 sys/oss4/oss4-mixer.c:786
+msgid "Stereo"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:767
+msgid "Surround Sound"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:768
+msgid "Microphone Gain"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:769
+msgid "Speaker Source"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:770
+msgid "Microphone Source"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:771
+msgid "Jack"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:772
+msgid "Center / LFE"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:773
+msgid "Stereo Mix"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:774
+msgid "Mono Mix"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:775
+msgid "Input Mix"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:776
+msgid "SPDIF In"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:777
+msgid "SPDIF Out"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:778
+msgid "Microphone 1"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:779
+msgid "Microphone 2"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:780
+msgid "Digital Out"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:781
+msgid "Digital In"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:782
+msgid "HDMI"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:783
+msgid "Modem"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:784
+msgid "Handset"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:785
+msgid "Other"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:787
+msgid "None"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:788
+msgid "On"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:789
+msgid "Off"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:790
+msgid "Mute"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:791
+msgid "Fast"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:792
+msgid "Very Low"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:793
+msgid "Low"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:794
+msgid "Medium"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:795
+msgid "High"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:796 sys/oss4/oss4-mixer.c:797
+msgid "Very High"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:798
+msgid "Production"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:799
+msgid "Front Panel Microphone"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:800
+msgid "Front Panel Line In"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:801
+msgid "Front Panel Headphones"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:802
+msgid "Front Panel Line Out"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:803
+msgid "Green Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:804
+msgid "Pink Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:805
+msgid "Blue Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:806
+msgid "White Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:807
+msgid "Black Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:808
+msgid "Gray Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:809
+msgid "Orange Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:810
+msgid "Red Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:811
+msgid "Yellow Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:812
+msgid "Green Front Panel Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:813
+msgid "Pink Front Panel Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:814
+msgid "Blue Front Panel Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:815
+msgid "White Front Panel Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:816
+msgid "Black Front Panel Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:817
+msgid "Gray Front Panel Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:818
+msgid "Orange Front Panel Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:819
+msgid "Red Front Panel Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:820
+msgid "Yellow Front Panel Connector"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:821
+msgid "Spread Output"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:822
+msgid "Downmix"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:866
+msgid "Virtual Mixer Input"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:868
+msgid "Virtual Mixer Output"
+msgstr ""
+
+#: sys/oss4/oss4-mixer.c:870
+msgid "Virtual Mixer Channels"
+msgstr ""
+
+#. TRANSLATORS: name + number of a volume mixer control
+#: sys/oss4/oss4-mixer.c:921
+#, c-format
+msgid "%s %d Function"
+msgstr ""
+
+#. TRANSLATORS: name of a volume mixer control
+#: sys/oss4/oss4-mixer.c:928
+#, c-format
+msgid "%s Function"
+msgstr ""
+
+#: sys/oss4/oss4-sink.c:498 sys/oss4/oss4-source.c:367
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+
+#: sys/oss4/oss4-sink.c:508 sys/oss4/oss4-source.c:377
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+
+#: sys/oss4/oss4-sink.c:519 sys/oss4/oss4-source.c:388
+#, fuzzy
+msgid "Could not open audio device for playback."
+msgstr "Алдын \"%s\" жабдыкты ачалган жок."
+
+#: sys/oss4/oss4-sink.c:528 sys/oss4/oss4-source.c:398
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+
+#: sys/oss4/oss4-sink.c:644
+msgid "Playback is not supported by this audio device."
+msgstr ""
+
+#: sys/oss4/oss4-sink.c:651
+msgid "Audio playback error."
+msgstr ""
+
+#: sys/oss4/oss4-source.c:520
+msgid "Recording is not supported by this audio device."
+msgstr ""
+
+#: sys/oss4/oss4-source.c:527
+msgid "Error recording from audio device."
+msgstr ""
diff --git a/po/lt.po b/po/lt.po
new file mode 100644
index 0000000..5cbd980
--- /dev/null
+++ b/po/lt.po
@@ -0,0 +1,889 @@
+# Lithuanian translation for gst-plugins-good.
+# This file is put in the public domain.
+# Gintautas Miliauskas <gintas@akl.lt>, 2008.
+# Aurimas Černius <aurisc4@gmail.com>, 2010.
+# Žygimantas Beručka <uid0@akl.lt>, 2010.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 0.10.23.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2010-07-16 19:34+0300\n"
+"Last-Translator: Žygimantas Beručka <uid0@akl.lt>\n"
+"Language-Team: Lithuanian <komp_lt@konferencijos.lt>\n"
+"Language: lt\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n"
+"%100<10 || n%100>=20) ? 1 : 2);\n"
+"X-Generator: Virtaal 0.6.1\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr "Nepavyko dekoduoti JPEG paveikslėlio"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "„%s“ atlieka „%s“"
+
+msgid "Could not connect to server"
+msgstr "Nepavyko prisijungti prie serverio"
+
+msgid "No URL set."
+msgstr ""
+
+#, fuzzy
+msgid "Could not resolve server name."
+msgstr "Nepavyko prisijungti prie serverio"
+
+#, fuzzy
+msgid "Could not establish connection to server."
+msgstr "Nepavyko prisijungti prie garso serverio"
+
+msgid "Secure connection setup failed."
+msgstr ""
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+
+msgid "Server sent bad data."
+msgstr ""
+
+msgid "Server does not support seeking."
+msgstr ""
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Nėra įvesties garso arba jis netinkamas, AVI srautas bus sugadintas."
+
+msgid "This file contains no playable streams."
+msgstr "Šiame faile nėra atkurtinų srautų."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Failas netinkamas ir negali būti atkurtas."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Failas sugadintas ir negali būti atkurtas."
+
+msgid "Invalid atom size."
+msgstr ""
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Failas nebaigtas ir negali būti atkurtas."
+
+msgid "The video in this file might not play correctly."
+msgstr "Šiame faile esantis vaizdo įrašas gali būti atkurtas nekorektiškai."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Šiame faile per daug srautų. Grojami tik pirmieji %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Nerasta palaikomų srautų. Jums gali reikėti įdiegti GStreamer RTSP "
+"papildinio įskiepį Real media srautams."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Nerasta palaikomų srautų. Jums gali reikėti leisti daugiau transporto "
+"protokolų, arba jūs neturite tinkamo GStreamer RTSP papildinio įskiepio."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Nepavyko atverti garso įrenginio grojimui. Įrenginį naudoja kita programa."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Nepavyko atverti garso įrenginio grojimui. Jūs neturite leidimo atverti "
+"įrenginį."
+
+msgid "Could not open audio device for playback."
+msgstr "Nepavyko atverti garso įrenginio grojimui. "
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Nepavyko atverti garso įrenginio grojimui. Šis elementas nepalaiko šios Open "
+"Sound System versijos."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Šis garso įrenginys nepalaiko grojimo."
+
+msgid "Audio playback error."
+msgstr "Garso grojimo klaida."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Šis garso įrenginys nepalaiko grojimo."
+
+msgid "Error recording from audio device."
+msgstr "Klaida įrašant iš garso įrenginio."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Nepavyko atverti garso įrenginio įrašymui. Jūs neturite leidimo atverti "
+"įrenginį."
+
+msgid "Could not open audio device for recording."
+msgstr "Nepavyko atverti garso įrenginio įrašymui."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "Įrašymo šaltinis"
+
+msgid "Microphone"
+msgstr "Mikrofonas"
+
+msgid "Line In"
+msgstr "Įeinanti linija"
+
+msgid "Internal CD"
+msgstr "Vidinis CD"
+
+msgid "SPDIF In"
+msgstr "SPDIF įvestis"
+
+msgid "AUX 1 In"
+msgstr "AUX 1 įvestis"
+
+msgid "AUX 2 In"
+msgstr "AUX 2 įvestis"
+
+#, fuzzy
+msgid "Codec Loopback"
+msgstr "Perduoti ratu"
+
+#, fuzzy
+msgid "SunVTS Loopback"
+msgstr "Perduoti ratu"
+
+msgid "Volume"
+msgstr "Garsumas"
+
+msgid "Gain"
+msgstr "Garsinimas"
+
+msgid "Monitor"
+msgstr "Monitorius"
+
+msgid "Built-in Speaker"
+msgstr "Integruotas garsiakalbis"
+
+msgid "Headphone"
+msgstr "Ausinės"
+
+msgid "Line Out"
+msgstr "Išeinanti linija"
+
+msgid "SPDIF Out"
+msgstr "SPDIF išvestis"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1 išvestis"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2 išvestis"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Klaida skaitant %d baitus (-ų) iš įrenginio „%s“."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Nepavyko išdėstyti buferių iš įrenginio „%s“"
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Įrenginio „%s“ tvarkyklė nepalaiko jokių žinomų įrašymo būdų."
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Įrenginio „%s“ tvarkyklė nepalaiko jokių žinomų įrašymo būdų."
+
+#, fuzzy, c-format
+msgid "Device '%s' is busy"
+msgstr "Įrenginys „%s“ nėra išvesties įrenginys."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Įrenginys „%s“ nėra įrašymo įrenginys."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Įrenginys „%s“ nėra įrašymo įrenginys."
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Įrenginys „%s“ nėra išvesties įrenginys."
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Nepavyko įrenginio „%s“ parametrų"
+
+#, fuzzy
+msgid "Video device did not accept new frame rate setting."
+msgstr "Vaizdo įvesties įrenginys nepriėmė naujų kadrų dažnio nustatymų."
+
+#, fuzzy
+msgid "Video device did not provide output format."
+msgstr "Vaizdo įvesties įrenginys nepriėmė naujų kadrų dažnio nustatymų."
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Įrenginio „%s“ tvarkyklė nepalaiko jokių žinomų įrašymo būdų."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Įrenginio „%s“ tvarkyklė nepalaiko jokių žinomų įrašymo būdų."
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+#, fuzzy
+msgid "Video device did not suggest any buffer size."
+msgstr "Vaizdo įvesties įrenginys nepriėmė naujų kadrų dažnio nustatymų."
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Nepavyko gauti derintuvo %d įrenginyje „%s“ parametrų."
+
+#, fuzzy, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Klaida skaitant %d baitus (-ų) iš įrenginio „%s“."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Įrenginys „%s“ nėra išvesties įrenginys."
+
+#, fuzzy, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Nepavyko nustatyti įvesties %d įrenginyje %s."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Nepavyko nustatyti įvesties %d įrenginyje %s."
+
+#, fuzzy, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Nepavyko gauti įrenginio „%s“ signalo stiprumo."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Įrenginio „%s“ tvarkyklė nepalaiko jokių žinomų įrašymo būdų."
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Vaizdo įvesties įrenginys nepriėmė naujų kadrų dažnio nustatymų."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Vaizdo įvesties įrenginys nepriėmė naujų kadrų dažnio nustatymų."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Vaizdo įvesties įrenginys nepriėmė naujų kadrų dažnio nustatymų."
+
+#, fuzzy
+msgid "Failed to start decoding thread."
+msgstr "Nepavyko dekoduoti JPEG paveikslėlio"
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Klaida gaunant įrenginio „%s“ funkcijas: tai nėra v4l2 tvarkyklė. "
+"Patikrinkite, ar tai v4l1 tvarkyklė."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Nepavyko užklausti įvesties %d įrenginyje %s atributų"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Nepavyko gauti derintuvo %d įrenginyje „%s“ parametrų."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Nepavyko užklausti normalės įrenginyje „%s“."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Nepavyko gauti valdymo atributų įrenginyje „%s“."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Nepavyko nustatyti įrenginio „%s“."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Tai nėra įrenginys „%s“."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Nepavyko atverti įrenginio „%s“ skaitymui ir rašymui."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Įrenginys „%s“ nėra įrašymo įrenginys."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Įrenginys „%s“ nėra išvesties įrenginys."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Įrenginys „%s“ nėra išvesties įrenginys."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Nepavyko atverti įrenginio „%s“ skaitymui ir rašymui."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Nepavyko nustatyti normalės įrenginiui „%s“."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Nepavyko gauti įrenginio „%s“ dabartinio derintuvo dažnio."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr "Nepavyko nustatyti įrenginio „%s“ derintuvo dažnio į %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Nepavyko gauti įrenginio „%s“ signalo stiprumo."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Nepavyko gauti valdiklio %d reikšmės įrenginyje „%s“."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Nepavyko nustatyti valdiklio %2$d įrenginyje „%3$s“ reikšmės %1$d."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Nepavyko gauti dabartinės įvesties įrenginyje „%s“. Galbūt tai radijo "
+"įrenginys"
+
+#, fuzzy, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Nepavyko gauti dabartinės įvesties įrenginyje „%s“. Galbūt tai radijo "
+"įrenginys"
+
+#, fuzzy, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Nepavyko nustatyti įvesties %d įrenginyje %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Galimybės keisti skiriamąją gebą operacijos vykdymo metu dar nėra."
+
+msgid "Cannot operate without a clock"
+msgstr "Negali veikti be laikrodžio"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Vidinė duomenų srauto klaida."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Vidinė duomenų srauto klaida."
+
+#, fuzzy
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Įrenginys „%s“ nėra išvesties įrenginys."
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Gautas netikėtas kadro dydis %u vietoje %u."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Nepavyko gauti vaizdo kadrų iš įrenginio „%s“."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Nepavyko po %d bandymų. Įrenginys %s. Sistemos klaida: %s"
+
+#~ msgid "Bass"
+#~ msgstr "Žemi dažniai"
+
+#~ msgid "Treble"
+#~ msgstr "Aukšti dažniai"
+
+#~ msgid "Synth"
+#~ msgstr "Sintezatorius"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Garsiakalbiai"
+
+#~ msgid "Line-in"
+#~ msgstr "Įvedimas"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Maišiklis"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Įrašymas"
+
+#~ msgid "In-gain"
+#~ msgstr "Garsinimo ribose"
+
+#~ msgid "Out-gain"
+#~ msgstr "Už garsinimo ribų"
+
+#~ msgid "Line-1"
+#~ msgstr "Linija-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Linija-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Linija-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Skaitmeninis-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Skaitmeninis-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Skaitmeninis-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Telefonas-įv"
+
+#~ msgid "Phone-out"
+#~ msgstr "Telefonas-išv"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Radijas"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "Nepavyko atverti garso įrenginio maišiklio valdymo apdorojimui."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Nepavyko atverti garso įrenginio maišiklio valdymo apdorojimui. Šis "
+#~ "elementas nepalaiko šios Open Sound System versijos."
+
+#~ msgid "Master"
+#~ msgstr "Pagrindinis"
+
+#~ msgid "Front"
+#~ msgstr "Priekinis"
+
+#~ msgid "Rear"
+#~ msgstr "Galinis"
+
+#~ msgid "Headphones"
+#~ msgstr "Ausinės"
+
+#~ msgid "Center"
+#~ msgstr "Vidurinis"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Supantis"
+
+#~ msgid "Side"
+#~ msgstr "Šoninis"
+
+#~ msgid "AUX Out"
+#~ msgstr "AUX išvestis"
+
+#~ msgid "3D Depth"
+#~ msgstr "3D giluminis"
+
+#~ msgid "3D Center"
+#~ msgstr "3D vidurinis"
+
+#~ msgid "3D Enhance"
+#~ msgstr "3D pakeltas"
+
+#~ msgid "Telephone"
+#~ msgstr "Telefonas"
+
+#~ msgid "Video In"
+#~ msgstr "Vaizdo įvestis"
+
+#~ msgid "AUX In"
+#~ msgstr "AUX įvestis"
+
+#~ msgid "Record Gain"
+#~ msgstr "Įrašymo garsinimas"
+
+#~ msgid "Output Gain"
+#~ msgstr "Išvesties garsinimas"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Mikrofono pagarsinimas"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Diagnostika"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Žemųjų dažnių sustiprinimas"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Grojimo prievadai"
+
+#~ msgid "Input"
+#~ msgstr "Įvestis"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Monitoriaus šaltinis"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Klaviatūros pypsėjimas"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Imituoti stereo"
+
+#~ msgid "Stereo"
+#~ msgstr "Stereo"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Erdvinis garsas"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Mikrofono garsinimas"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Garsiakalbio šaltinis"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Mikrofono šaltinis"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Centras / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Stereo maiša"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Mono maiša"
+
+#~ msgid "Input Mix"
+#~ msgstr "Įvesties maiša"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Mikrofonas 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Mikrofonas 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Skaitmeninė išvestis"
+
+#~ msgid "Digital In"
+#~ msgstr "Skaitmeninė įvestis"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modemas"
+
+#~ msgid "Handset"
+#~ msgstr "Ragelis"
+
+#~ msgid "Other"
+#~ msgstr "Kita"
+
+#~ msgid "None"
+#~ msgstr "Nėra"
+
+#~ msgid "On"
+#~ msgstr "Įjungta"
+
+#~ msgid "Off"
+#~ msgstr "Išjungta"
+
+#~ msgid "Mute"
+#~ msgstr "Nutildyta"
+
+#~ msgid "Fast"
+#~ msgstr "Greitas"
+
+#~ msgid "Very Low"
+#~ msgstr "Labai žema"
+
+#~ msgid "Low"
+#~ msgstr "Žema"
+
+#~ msgid "Medium"
+#~ msgstr "Vidutinė"
+
+#~ msgid "High"
+#~ msgstr "Aukšta"
+
+#~ msgid "Very High"
+#~ msgstr "Labai aukšta"
+
+#~ msgid "Production"
+#~ msgstr "Sukūrimo"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Priekinio skydelio mikrofonas"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Priekinio skydelio įeinanti linija"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Priekinio skydelio ausinės"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Priekinio skydelio išeinanti linija"
+
+#~ msgid "Green Connector"
+#~ msgstr "Žalias kištukas"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Rožinis kištukas"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Mėlynas kištukas"
+
+#~ msgid "White Connector"
+#~ msgstr "Baltas kištukas"
+
+#~ msgid "Black Connector"
+#~ msgstr "Juodas kištukas"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Pilkas kištukas"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Oranžinis kištukas"
+
+#~ msgid "Red Connector"
+#~ msgstr "Raudonas kištukas"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Geltonas kištukas"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Žalias priekinio skydelio kištukas"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Rožinis priekinio skydelio kištukas"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Mėlynas priekinio skydelio kištukas"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Baltas priekinio skydelio kištukas"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Juodas priekinio skydelio kištukas"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Pilkas priekinio skydelio kištukas"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Oranžinis priekinio skydelio kištukas"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Raudonas priekinio skydelio kištukas"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Geltonas priekinio skydelio kištukas"
+
+#~ msgid "Spread Output"
+#~ msgstr "Skleisti išvestį"
+
+#~ msgid "Downmix"
+#~ msgstr "Sumaišyti"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Virtualaus maišiklio įvestis"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Virtualaus maišiklio išvestis"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Virtualaus maišiklio kanalai"
+
+#~ msgid "%s %d Function"
+#~ msgstr "%s %d funkcija"
+
+#~ msgid "%s Function"
+#~ msgstr "%s funkcija"
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Klaida skaitant %d baitus (-ų) įrenginyje „%s“."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Nepavyko sustatyti į eilė buferių įrenginyje „%s“."
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Nepavyko prisijungti prie garso serverio"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Nepavyko užklausti garso serverio galimybių"
+
+#~ msgid "Describes the selected input element."
+#~ msgstr "Aprašo pasirinktą įvesties elementą."
+
+#~ msgid "Describes the selected output element for Audio/Video Conferencing."
+#~ msgstr "Aprašo pasirinktą išvesties elementą garso/vaizdo konferencijoms."
+
+#~ msgid "Describes the selected output element for Music and Movies."
+#~ msgstr "Aprašo pasirinktą išvesties elementą muzikai ir filmams."
+
+#~ msgid "Describes the selected output element."
+#~ msgstr "Aprašo pasirinktą išvesties elementą."
+
+#~ msgid "GStreamer audiosink for Audio/Video Conferencing"
+#~ msgstr "GStreamer garso išvesties elementas garso/vaizdo konferencijoms"
+
+#~ msgid "GStreamer audiosink for Music and Movies"
+#~ msgstr "GStreamer garso išvesties elementas muzikai ir filmams"
+
+#~ msgid ""
+#~ "GStreamer can play audio using any number of output elements. Some "
+#~ "possible choices are osssink, esdsink and alsasink. The audiosink can be "
+#~ "a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer gali groti garsą naudodamas bet kokį išvesties elementų kiekį. "
+#~ "Keletas galimų pasirinkimų: osssink, esdsink ir alsasink. Garso išvesties "
+#~ "elementą gali sudaryti dalinis konvejeris, ne tik vienas elementas."
+
+#~ msgid ""
+#~ "GStreamer can play video using any number of output elements. Some "
+#~ "possible choices are xvimagesink, ximagesink, sdlvideosink and aasink. "
+#~ "The videosink can be a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer gali groti vaizdo įrašus naudodamas bet kokį išvesties elementų "
+#~ "kiekį. Keletas galimų pasirinkimų: xvimagesink, ximagesink, sdlvideosink "
+#~ "ir aasink. Vaizdo išvesties elementą gali sudaryti dalinis konvejeris, ne "
+#~ "tik vienas elementas."
+
+#~ msgid ""
+#~ "GStreamer can put visualization plugins in a pipeline to transform audio "
+#~ "stream in video frames. Default is goom but more visualization plugins "
+#~ "will be ported soon. The visualization plugin can be a partial pipeline "
+#~ "instead of just one element."
+#~ msgstr ""
+#~ "GStreamer gali įdėti vaizdo efektų įskiepius į konvejerį, kad "
+#~ "transformuotų garso srautą vaizdo kadruose. Numatytasis įskiepis yra "
+#~ "goom, tačiau greitu metu bus realizuota daugiau vaizdo efektų įskiepių. "
+#~ "Vaizdo efekto įskiepį gali sudaryti dalinis konvejeris, ne tik vienas "
+#~ "elementas."
+
+#~ msgid ""
+#~ "GStreamer can record audio using any number of input elements. Some "
+#~ "possible choices are osssrc, esdsrc and alsasrc. The audio source can be "
+#~ "a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer gali įrašyti garsą naudodamas bet kokį įvesties elementų "
+#~ "skaičių. Keletas galimų pasirinkimų: osssrc, esdsrc ir alsasrc. Garso "
+#~ "šaltinį gali sudaryti dalinis konvejeris, ne tik vienas elementas."
+
+#~ msgid ""
+#~ "GStreamer can record video from any number of input elements. Some "
+#~ "possible choices are v4lsrc and videotestsrc. The video source can be a "
+#~ "partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer gali įrašyti vaizdą iš bet kokio skaičiaus įvesties elementų. "
+#~ "Keletas galimų pasirinkimų: v4lsrc ir videotestsrc. Vaizdo šaltinį gali "
+#~ "sudaryti dalinis konvejeris, ne tik vienas elementas."
+
+#~ msgid "default GStreamer audio source"
+#~ msgstr "numatytasis GStreamer garso šaltinis"
+
+#~ msgid "default GStreamer audiosink"
+#~ msgstr "numatytasis GStreamer garso išvesties elementas"
+
+#~ msgid "default GStreamer video source"
+#~ msgstr "numatytasis GStreamer vaizdo šaltinis"
+
+#~ msgid "default GStreamer videosink"
+#~ msgstr "numatytasis GStreamer vaizdo išvesties elementas"
+
+#~ msgid "default GStreamer visualization plugin"
+#~ msgstr "numatytasis GStreamer vaizdo efekto įskiepis"
+
+#~ msgid "description for GStreamer audiosink for Audio/Video Conferencing"
+#~ msgstr ""
+#~ "GStreamer garso išvesties elemento garso/vaizdo konferencijoms aprašymas"
+
+#~ msgid "description for GStreamer audiosink for Music and Movies"
+#~ msgstr "GStreamer garso išvesties elemento muzikai ir filmams aprašymas"
+
+#~ msgid "description for default GStreamer audiosink"
+#~ msgstr "numatytojo GStreamer garso išvesties elemento aprašymas"
+
+#~ msgid "description for default GStreamer audiosrc"
+#~ msgstr "numatytojo GStreamer garso šaltinio aprašymas"
+
+#~ msgid "This file is encrypted and cannot be played."
+#~ msgstr "Šis failas užšifruotas ir negali būti pagrotas."
+
+#~ msgid "Disc is not an Audio CD."
+#~ msgstr "Diskas nėra Audio CD"
+
+#~ msgid "Could not read from CD."
+#~ msgstr "Nepavyko skaityti iš CD."
diff --git a/po/lv.po b/po/lv.po
new file mode 100644
index 0000000..f7dac42
--- /dev/null
+++ b/po/lv.po
@@ -0,0 +1,785 @@
+# Latvian translation of gst-plugins.
+# This file is put in the public domain.
+#
+# Arvis Lācis <arvis.lacis@inbox.lv>, 2009.
+# Rihards Prieditis <rprieditis@gmail.com>, 2010.
+# Rihards Prieditis <rprieditis@gmail.com>, 2011.
+# Rūdolfs Mazurs <rudolfs.mazurs@gmail.com>, 2014.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.2.1\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2014-04-20 16:38+0300\n"
+"Last-Translator: Rihards Prieditis <rprieditis@gmail.com>\n"
+"Language-Team: Latvian <translation-team-lv@lists.sourceforge.net>\n"
+"Language: lv\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : "
+"2);\n"
+"X-Generator: Lokalize 1.5\n"
+
+msgid "Jack server not found"
+msgstr "Nav atrasts Jack serveris"
+
+msgid "Failed to decode JPEG image"
+msgstr "Neizdevās atkodēt JPEG attēlu"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "“%s” izpilda “%s”"
+
+msgid "Could not connect to server"
+msgstr "Nevarēja savienoties ar serveri"
+
+msgid "No URL set."
+msgstr "URL nav iestatīts."
+
+msgid "Could not resolve server name."
+msgstr "Nevar atrast servera nosaukumu."
+
+msgid "Could not establish connection to server."
+msgstr "Nevar izveidot savienojumu ar serveri."
+
+msgid "Secure connection setup failed."
+msgstr "Neizdevās izveidot drošo savienojumu."
+
+#, fuzzy
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr "Notika tīkla kļūda, vai serveris negaidīti aizvēra savienojumu."
+
+msgid "Server sent bad data."
+msgstr "Serveris nosūtīja sliktus datus."
+
+msgid "Server does not support seeking."
+msgstr "Serveris neatbalsta meklēšanu."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Nav vai nederīgs ievades audio, AVI straume tiks bojāta."
+
+msgid "This file contains no playable streams."
+msgstr "Šī datne nesatur nevienu atskaņojamu straumi."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Šī datne ir nederīga un to nevar atskaņot."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr "Nevar atskaņot straumi, jo tā ir šifrēta ar PlayReady DRM."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Šī datne ir bojāta un to nevar atskaņot."
+
+msgid "Invalid atom size."
+msgstr "Nederīgs atoma izmērs."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Šī datne ir nepabeigta un to nevar atskaņot."
+
+msgid "The video in this file might not play correctly."
+msgstr "Video šajā datnē varētu tikt atskaņots nepareizi."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Šī datne satur pārāk daudz straumju. Tiek atskaņota tikai pirmā %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Netika atrasta atbalstīta straume. Iespējams, jums jāinstalē GStreamer RTSP "
+"paplašinājuma spraudni Real media straumēm."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Netika atrasta atbalstīta straume. Iespējams, jums jāatļauj vairāk "
+"transporta protokoli vai arī trūkst GStreamer RTSP paplašinājuma spraudnis. "
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Nevarēja atvērt audio ierīci atskaņošanai. Ierīci pašlaik izmanto cita "
+"lietotne."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Nevar atvērt audio ierīci atskaņošanai. Jums nav nepieciešamās atļaujas, lai "
+"atvērtu ierīci."
+
+msgid "Could not open audio device for playback."
+msgstr "Nevarēja atvērt audio ierīci atskaņošanai."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Nevar atvērt audio ierīci atskaņošanai. Šī Atvērtās Skaņas Sistēmas versija "
+"neatbalsta šo elementu."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Šī audio ierīce neatbalsta atskaņošanu."
+
+msgid "Audio playback error."
+msgstr "Audio atskaņošanas kļūda."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Šī audio ierīce neatbalsta ierakstīšanu."
+
+msgid "Error recording from audio device."
+msgstr "Kļūda, ierakstot no audio ierīces."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Nevar atvērt audio ierīci ierakstīšanai. Jums nav nepieciešamo piekļuves "
+"tiesību, lai atvērtu ierīci."
+
+msgid "Could not open audio device for recording."
+msgstr "Nevarēja atvērt audio ierīci ierakstīšanai."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "Ierakstīšanas avots"
+
+msgid "Microphone"
+msgstr "Mikrofons"
+
+msgid "Line In"
+msgstr "Skaņas ieeja"
+
+msgid "Internal CD"
+msgstr "Iekšējais CD"
+
+msgid "SPDIF In"
+msgstr "SPDIF ieeja"
+
+msgid "AUX 1 In"
+msgstr "AUX 1 ieeja"
+
+msgid "AUX 2 In"
+msgstr "AUX 2 ieeja"
+
+msgid "Codec Loopback"
+msgstr "Kodeka atgriezeniskais cikls"
+
+msgid "SunVTS Loopback"
+msgstr "SunVTS atgriezeniskais cikls"
+
+msgid "Volume"
+msgstr "Skaļums"
+
+msgid "Gain"
+msgstr "Pieaugums"
+
+msgid "Monitor"
+msgstr "Monitors"
+
+msgid "Built-in Speaker"
+msgstr "Iebūvētais skaļrunis"
+
+msgid "Headphone"
+msgstr "Austiņas"
+
+msgid "Line Out"
+msgstr "Skaņas izeja"
+
+msgid "SPDIF Out"
+msgstr "SPDIF izeja"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1 izeja"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2 izeja"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Radās kļūda, nolasot %d baitus no ierīces “%s”."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr "Neizdevās uzskaitīt iespējamos video formātus, ar ko var strādāt “%s”"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Nevar izvietot buferus no ierīces “%s”"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Ierīces \"%s\" draiveris neatbalsta IO metodi %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Ierīces “%s” draiveris neatbalsta nevienu zināmo ierakstīšanas metodi."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Ierīce “%s” ir aizņemta"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Ierīce “%s” nevar tvert ar %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Ierīce “%s” nevar tvert norādītajā formātā"
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Ierīce “%s” neatbalsta video tveršanu"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Nevar nolasīt parametrus no ierīces “%s”"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "Video ierīce nepieņēma jaunos kadru ātruma iestatījumus."
+
+#, fuzzy
+msgid "Video device did not provide output format."
+msgstr "Video ierīce nepieņēma jaunos kadru ātruma iestatījumus."
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Ierīces \"%s\" draiveris neatbalsta IO metodi %d"
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Ierīces \"%s\" draiveris neatbalsta IO metodi %d"
+
+#, fuzzy
+msgid "Failed to configure internal buffer pool."
+msgstr "Video ierīce nevarēja izveidot bufera pūlu."
+
+#, fuzzy
+msgid "Video device did not suggest any buffer size."
+msgstr "Video ierīce nevarēja izveidot bufera pūlu."
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Neizdevās saņemt skaņotāja %d iestatījumus no ierīces “%s”."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Kļūda, saņemot iespējas no ierīces “%s”."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Ierīce “%s” nav skaņotājs."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Neizdevās saņemt radio ievadi uz ierīces “%s”."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Neizdevās iestatīt ievadi %d uz ierīces %s."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Neizdevās mainīt apklusināšanas stāvokli ierīcei “%s”."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Ierīces \"%s\" draiveris neatbalsta IO metodi %d"
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Video ierīce nepieņēma jaunos kadru ātruma iestatījumus."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Video ierīce nepieņēma jaunos kadru ātruma iestatījumus."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Video ierīce nepieņēma jaunos kadru ātruma iestatījumus."
+
+#, fuzzy
+msgid "Failed to start decoding thread."
+msgstr "Neizdevās atkodēt JPEG attēlu"
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Radās kļūda, saņemot ierīces “%s” iespējas: iespējams tas nav v4I2 "
+"draiveris. Pārbaudiet vai tas ir v4I1 draiveris."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Neizdevās noteikt atribūtus ievadei %d no ierīces %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Neizdevās saņemt skaņotāja %d iestatījumus no ierīces “%s”."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Neizdevās noskaidrot normu ierīcei “%s”."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Neizdevās iegūt kontroles atribūtus ierīcei “%s”."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Nevar atpazīt ierīci “%s”."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Šī nav ierīce “%s”."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Nevarēja atvērt ierīci “%s” lasīšanai vai rakstīšanai."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Ierīce “%s” nav ierakstīšanas ierīce."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Ierīce “%s” nav izvades ierīce."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Ierīce “%s” nav izvades ierīce."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Nevarēja atvērt ierīci “%s” lasīšanai vai rakstīšanai."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Neizdevās iestatīt normu ierīcei “%s”."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Neizdevās saņemt pašreizējo atskaņošanas frekvenci no ierīces “%s”."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Neizdevās iestatīt ierīces “%s” pašreizējo skaņotāja frekvenci uz %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Neizdevās saņemt signāla stiprumu no ierīces “%s”."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Neizdevās saņemt vadīklas vērtību %d ierīcei “%s”."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Neizdevās iestatīt vērtību %d vadīklai %d no ierīces “%s”."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Neizdevās saņemt pašreizējo ievadi no ierīces “%s”. Iespējams tā ir radio "
+"ierīce"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Neizdevās saņemt pašreizējo izvadu no ierīces “%s”. Iespējams tā ir radio "
+"ierīce"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Neizdevās iestatīt izvadi %d uz ierīces %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Izšķirtspējas mainīšana izpildlaikā pašlaik netiek atbalstīta."
+
+msgid "Cannot operate without a clock"
+msgstr "Nevar veikt darbības bez pulksteņa"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Iekšēja datu plūsmas kļūda."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Iekšēja datu plūsmas kļūda."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Ierīce “%s” neatbalsta video tveršanu"
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Nevar izveidot savienojumu ar skaņas serveri"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Neizdevās noskaidrot skaņas servera iespējas"
+
+#~ msgid "Bass"
+#~ msgstr "Basi"
+
+#~ msgid "Treble"
+#~ msgstr "Diskants"
+
+#~ msgid "Synth"
+#~ msgstr "Sintēze"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Skaļrunis"
+
+#~ msgid "Line-in"
+#~ msgstr "Skaņas ieeja"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Jaucējs"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Ierakstīt"
+
+#~ msgid "In-gain"
+#~ msgstr "Ievades pieaugums"
+
+#~ msgid "Out-gain"
+#~ msgstr "Izvades pieaugums"
+
+#~ msgid "Line-1"
+#~ msgstr "Līnija-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Līnija-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Līnija-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Digitālais-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Digitālais-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Digitālais-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Telefona ievade"
+
+#~ msgid "Phone-out"
+#~ msgstr "Telefona izvade"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Radio"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "Nevarēja atvērt audio ierīci miksera kontroles vadīšanai."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Nevar atvērt audio ierīci miksera kontrolas vadīšanai. Šī Atvertās Skaņas "
+#~ "Sistemas versija neatbalsta šo elementu."
+
+#~ msgid "Master"
+#~ msgstr "Galvenais"
+
+#~ msgid "Front"
+#~ msgstr "Priekšējais"
+
+#~ msgid "Rear"
+#~ msgstr "Sāni"
+
+#~ msgid "Headphones"
+#~ msgstr "Austiņas"
+
+#~ msgid "Center"
+#~ msgstr "Centrs"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Ieskaujošā"
+
+#~ msgid "Side"
+#~ msgstr "Puse"
+
+#~ msgid "AUX Out"
+#~ msgstr "AUX izeja"
+
+#~ msgid "3D Depth"
+#~ msgstr "3D dziļums"
+
+#~ msgid "3D Center"
+#~ msgstr "3D centrs"
+
+#~ msgid "3D Enhance"
+#~ msgstr "3D uzlabojums"
+
+#~ msgid "Telephone"
+#~ msgstr "Telefons"
+
+#~ msgid "Video In"
+#~ msgstr "Video ieeja"
+
+#~ msgid "AUX In"
+#~ msgstr "AUC ieeja"
+
+#~ msgid "Record Gain"
+#~ msgstr "Ierakstīta pieaugums"
+
+#~ msgid "Output Gain"
+#~ msgstr "Izvada pieaugums"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Mikrofona pastiprinājums"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Diagnostika"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Bassa pastiprinājums"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Atskaņošanas porti"
+
+#~ msgid "Input"
+#~ msgstr "Ievads"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Monitora avots"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Klaviatūras pīkstieni"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Simulēt stereo"
+
+#~ msgid "Stereo"
+#~ msgstr "Stereo"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Ieskaujošā skaņa"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Mikrofona pieaugums"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Skaļruņa avots"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Mikrofona avots"
+
+#~ msgid "Jack"
+#~ msgstr "Ligzda"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Centrs / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Stereo mikseris"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Mono miskeris"
+
+#~ msgid "Input Mix"
+#~ msgstr "Ieejas mikseris"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Mikrofons 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Mikrofons 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Digitālā izeja"
+
+#~ msgid "Digital In"
+#~ msgstr "Digitālā ieeja"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modēms"
+
+#~ msgid "Handset"
+#~ msgstr "Klausule"
+
+#~ msgid "Other"
+#~ msgstr "Cits"
+
+#~ msgid "None"
+#~ msgstr "Nekas"
+
+#~ msgid "On"
+#~ msgstr "Ieslēgts"
+
+#~ msgid "Off"
+#~ msgstr "Izslēgts"
+
+#~ msgid "Mute"
+#~ msgstr "Klusums"
+
+#~ msgid "Fast"
+#~ msgstr "Ātrs"
+
+#~ msgid "Very Low"
+#~ msgstr "Ļoti zems"
+
+#~ msgid "Low"
+#~ msgstr "Zems"
+
+#~ msgid "Medium"
+#~ msgstr "Vidējs"
+
+#~ msgid "High"
+#~ msgstr "Augsts"
+
+#~ msgid "Very High"
+#~ msgstr "Ļoti augsts"
+
+#~ msgid "Production"
+#~ msgstr "Produkcija"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Priekšējā paneļa mikrofons"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Priekšējā paneļa ieejas līnija"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Priekšējā paneļa austiņas"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Priekšējā paneļa līnijas izeja"
+
+#~ msgid "Green Connector"
+#~ msgstr "Zaļais savienotājs"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Rozā savienotājs"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Zilais savienotājs"
+
+#~ msgid "White Connector"
+#~ msgstr "Baltais savienotājs"
+
+#~ msgid "Black Connector"
+#~ msgstr "Melnais savienotājs"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Pelākais savienotājs"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Oranžais savienotājs"
+
+#~ msgid "Red Connector"
+#~ msgstr "Sarkanais savienotājs"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Dzeltains savienotājs"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Zaļais priekšējā paneļa savienotājs"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Rozā priekšējā paneļa savienotājs"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Zilais priekšējā paneļa savienotājs"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Baltais priekšējā paneļa savienotājs"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Melnais priekšējā paneļa savienotājs"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Pelēkais priekšējā paneļa savienotājs"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Oranžais priekšējā paneļa savienotājs"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Sarkanais priekšējā paneļa savienotājs"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Dzeltenais priekšējā paneļa savienotājs"
+
+#~ msgid "Spread Output"
+#~ msgstr "Izplest izvadu"
+
+#~ msgid "Downmix"
+#~ msgstr "Lejupmiksēšana"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Virtuālā miksera ievads"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Virtuālā miksera izvads"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Virtuālā miksera kanāli"
+
+#~ msgid "%s %d Function"
+#~ msgstr "%s %d funkcija"
+
+#~ msgid "%s Function"
+#~ msgstr "%s funkcija"
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Saņēmu negaidītu kadra izmēru %u, nevis %u."
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Radās kļūda nolasot %d baitus no ierīces \"%s\"."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Nevar ierindod buferus ierīcē \"%s\"."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Neizdevās saņemt video kadrus no ierīces \"%s\"."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Neveiksme pēc %d mēģinājumiem. ierīce %s. sistēmas kļūda: %s"
diff --git a/po/meson.build b/po/meson.build
new file mode 100644
index 0000000..aa11a72
--- /dev/null
+++ b/po/meson.build
@@ -0,0 +1,3 @@
+i18n = import('i18n')
+
+i18n.gettext('gst-plugins-good-1.0', preset: 'glib')
diff --git a/po/mt.po b/po/mt.po
new file mode 100644
index 0000000..fb407b9
--- /dev/null
+++ b/po/mt.po
@@ -0,0 +1,771 @@
+# Maltese translation for gst-plugins-good.
+# This file is distributed under the same license as the gst-plugins-good package.
+# NAME OF AUTHOR <michelbugeja@rabatmalta.com>, 2008.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good-0.10.10.3\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2008-10-26 19:09+0100\n"
+"Last-Translator: Michel Bugeja <michelbugeja@rabatmalta.com>\n"
+"Language-Team: Maltese <translation-team-mt@lists.sourceforge.net>\n"
+"Language: mt\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-Language: Maltese\n"
+"X-Poedit-Country: MALTA\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr "Problem fid-decoding tal-istampa JPEG"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr ""
+
+msgid "Could not connect to server"
+msgstr "Mhux possibli naqbad mas-server"
+
+msgid "No URL set."
+msgstr ""
+
+#, fuzzy
+msgid "Could not resolve server name."
+msgstr "Mhux possibli naqbad mas-server"
+
+#, fuzzy
+msgid "Could not establish connection to server."
+msgstr "Kuntatt mas-sound server ma ġiex stabbilit"
+
+msgid "Secure connection setup failed."
+msgstr ""
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+
+msgid "Server sent bad data."
+msgstr ""
+
+#, fuzzy
+msgid "Server does not support seeking."
+msgstr "Appart '%s' ma jagħmilx video capture"
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Input audio ma nstabx jew mhux validu. AVI stream jista jkun korrott."
+
+msgid "This file contains no playable streams."
+msgstr "Il-fajl ma fiħ l-ebda stream li tista tindaqq."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Il-fajl mhux validu u ma jistax jindaqq"
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Il-fajl huwa korrott u ma jistax jinfetaħ."
+
+msgid "Invalid atom size."
+msgstr ""
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Il-fajl mhux komplut u ma jistax jindaqq,"
+
+msgid "The video in this file might not play correctly."
+msgstr "Jista jkun illi l-vidjo ġo dan il-fajl ma jidhirx sewwa."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Il-fajl fiħ aktar streams milli suppost. Ser indoqq l-ewwel %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr "Audio device ma jistax jintuża. Qed jintuża minn programm ieħor."
+
+#, fuzzy
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr "Audio device ma jistax jintuża. M'għandex aċċess għalih."
+
+msgid "Could not open audio device for playback."
+msgstr "Audio device ma jistax jintuża."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Ma nistax niftaħ apparat tal-awdjo biex indoqq. Dil il-verżjoni ta' Open "
+"Sound System mhux issapportjatha minn dan l-element."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Id-daqq mhux issappartjat minn dan l-apparat tal-awdjo."
+
+msgid "Audio playback error."
+msgstr "Żball fiid-daqq tal-awdjo."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Irrekordjar mhux issapportjat minn dan l-apparat tal-awdjo."
+
+msgid "Error recording from audio device."
+msgstr "Żball fl-irrekordjar mill-apparat tal-awdjo."
+
+#, fuzzy
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Audio device ma jistax jintuża biex tirrekordja. M'għandex aċċess għalih."
+
+msgid "Could not open audio device for recording."
+msgstr "Audio device ma jistax jintuża biex tirrekordja."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+#, fuzzy
+msgid "Record Source"
+msgstr "Record"
+
+msgid "Microphone"
+msgstr "Mikrofonu"
+
+#, fuzzy
+msgid "Line In"
+msgstr "Line-in"
+
+msgid "Internal CD"
+msgstr ""
+
+msgid "SPDIF In"
+msgstr ""
+
+msgid "AUX 1 In"
+msgstr ""
+
+msgid "AUX 2 In"
+msgstr ""
+
+msgid "Codec Loopback"
+msgstr ""
+
+msgid "SunVTS Loopback"
+msgstr ""
+
+msgid "Volume"
+msgstr "Volum"
+
+msgid "Gain"
+msgstr "Gain"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+#, fuzzy
+msgid "Built-in Speaker"
+msgstr "Speaker"
+
+msgid "Headphone"
+msgstr ""
+
+msgid "Line Out"
+msgstr ""
+
+msgid "SPDIF Out"
+msgstr ""
+
+msgid "AUX 1 Out"
+msgstr ""
+
+msgid "AUX 2 Out"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Problema fil-qar()i %d bytes fid-device '%s'."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr "Failed to enumerate possible video formats device '%s' can work with"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Ma nistax nqabbel buffers mill-apparat '%s'."
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr ""
+"Id-driver tal-apparat '%s' ma jissapportja l-ebda capture method mifhum."
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"Id-driver tal-apparat '%s' ma jissapportja l-ebda capture method mifhum."
+
+#, fuzzy, c-format
+msgid "Device '%s' is busy"
+msgstr "Device '%s' mhux capture device."
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Appart '%s' ma jistax jagħmel capture bi %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Appart '%s' ma jistax jagħmel capture f'dan il-format"
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Device '%s' mhux capture device."
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Mhux possibli nġib parametri tal-apparat '%s'"
+
+#, fuzzy
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+"Apparat li jaqra video input ma aċċettax is-settings ġodda tal-frame rate."
+
+#, fuzzy
+msgid "Video device did not provide output format."
+msgstr ""
+"Apparat li jaqra video input ma aċċettax is-settings ġodda tal-frame rate."
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+"Id-driver tal-apparat '%s' ma jissapportja l-ebda capture method mifhum."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr ""
+"Id-driver tal-apparat '%s' ma jissapportja l-ebda capture method mifhum."
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+#, fuzzy
+msgid "Video device did not suggest any buffer size."
+msgstr ""
+"Apparat li jaqra video input ma aċċettax is-settings ġodda tal-frame rate."
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Problema biex inġib settings tat-tuner %d fuq l-appart '%s'"
+
+#, fuzzy, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Problema fil-qar()i %d bytes fid-device '%s'."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Device '%s' mhux capture device."
+
+#, fuzzy, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Problema biex nissettja input %d fuq apparat %s."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Problema biex nissettja input %d fuq apparat %s."
+
+#, fuzzy, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Problema biex inġib signal strength fuq l-apparat '%s'."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+"Id-driver tal-apparat '%s' ma jissapportja l-ebda capture method mifhum."
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+"Apparat li jaqra video input ma aċċettax is-settings ġodda tal-frame rate."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+"Apparat li jaqra video input ma aċċettax is-settings ġodda tal-frame rate."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+"Apparat li jaqra video input ma aċċettax is-settings ġodda tal-frame rate."
+
+#, fuzzy
+msgid "Failed to start decoding thread."
+msgstr "Problem fid-decoding tal-istampa JPEG"
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Problema biex nġib il-kapaċitajiet tal-apparat '%s': Mhux v4l2 driver. "
+"Iċċekkja jekk hux v4l1 driver. "
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Mhux possibli tfittxja għal attributi ta' input %d ġol-apparat %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Problema biex inġib settings tat-tuner %d fuq l-appart '%s'"
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Ma stajx nfittex norm fuq apparat '%s'."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "L-attributi ta' kontroll ta' device '%s' ma nqrawx."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Device '%s' mhux identifikat."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Dan mhux device %s."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Device '%s' ma nistax niftaħu biex naqra jew nikteb."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Device '%s' mhux capture device."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Device '%s' mhux capture device."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Device '%s' mhux capture device."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Device '%s' ma nistax niftaħu biex naqra jew nikteb."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Ma stajtx nissetja norm fuq apparat '%s'."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Problema biex inġib il-frekwenza li jitrażmetti fuqha apparat '%s'."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Problema biex nissettja l-frekwenza li jitrażmetti fuqha apparat '%s' għal "
+"%lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Problema biex inġib signal strength fuq l-apparat '%s'."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Problema biex inġib valur ta' control %d fuq l-apparat '%s'."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Problema biex nissetja valur %d lil control %d fuq l-apparat '%s'."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Problema biex inġib current input fuq apparat '%s'. Jista jkun li huwa "
+"apparat tar-radju."
+
+#, fuzzy, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Problema biex inġib current input fuq apparat '%s'. Jista jkun li huwa "
+"apparat tar-radju."
+
+#, fuzzy, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Problema biex nissettja input %d fuq apparat %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Ma tistax tibdel ir-resolution waqt runtime."
+
+msgid "Cannot operate without a clock"
+msgstr "Ma nistax nħaddem mingħajr arloġġ"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Problema interna fid-data stream"
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Problema interna ta' data flow"
+
+#, fuzzy
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Device '%s' mhux capture device."
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Irċivejt frame size ta' %u minflok kif kien mistenni ta' %u."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Problema biex inġib video frames mill-apparat '%s'."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr ""
+#~ "Problema wara li pruvajt %d drabi. apparat %s. żball fis-sistema: %s"
+
+#~ msgid "Bass"
+#~ msgstr "Bass"
+
+#~ msgid "Treble"
+#~ msgstr "Treble"
+
+#~ msgid "Synth"
+#~ msgstr "Synth"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Speaker"
+
+#~ msgid "Line-in"
+#~ msgstr "Line-in"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Mixer"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "In-gain"
+#~ msgstr "In-gain"
+
+#~ msgid "Out-gain"
+#~ msgstr "Out-gain"
+
+#~ msgid "Line-1"
+#~ msgstr "Line-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Line-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Line-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Digital-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Digital-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Digital-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Phone-in"
+
+#~ msgid "Phone-out"
+#~ msgstr "Phone-out"
+
+#~ msgid "Video"
+#~ msgstr "Vidjo"
+
+#~ msgid "Radio"
+#~ msgstr "Radju"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "Ma nistax niftaħ apparat tal-awdjo għal mixer control handling."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Ma nistax niftaħ apparat tal-awdjo għal mixer control handling. Din il-"
+#~ "verzjoni ta' Open Sound System mhux issapportjata minn din l-element."
+
+#, fuzzy
+#~ msgid "Master"
+#~ msgstr "Fast"
+
+#~ msgid "Front"
+#~ msgstr "Quddiem"
+
+#~ msgid "Rear"
+#~ msgstr "Wara"
+
+#~ msgid "Headphones"
+#~ msgstr "Headphones"
+
+#, fuzzy
+#~ msgid "Center"
+#~ msgstr "Center / LFE"
+
+#, fuzzy
+#~ msgid "Surround"
+#~ msgstr "Surround sound"
+
+#~ msgid "Side"
+#~ msgstr "Ġenb"
+
+#, fuzzy
+#~ msgid "Telephone"
+#~ msgstr "Headphones"
+
+#, fuzzy
+#~ msgid "Microphone Boost"
+#~ msgstr "Mikrofonu"
+
+#~ msgid "Input"
+#~ msgstr "Input"
+
+#~ msgid "Stereo"
+#~ msgstr "Stereo"
+
+#, fuzzy
+#~ msgid "Surround Sound"
+#~ msgstr "Surround sound"
+
+#, fuzzy
+#~ msgid "Microphone Gain"
+#~ msgstr "Mikrofonu"
+
+#, fuzzy
+#~ msgid "Microphone Source"
+#~ msgstr "Mikrofonu"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Center / LFE"
+
+#, fuzzy
+#~ msgid "Stereo Mix"
+#~ msgstr "Stereo"
+
+#, fuzzy
+#~ msgid "Input Mix"
+#~ msgstr "Input mix"
+
+#, fuzzy
+#~ msgid "Microphone 1"
+#~ msgstr "Mikrofonu"
+
+#, fuzzy
+#~ msgid "Microphone 2"
+#~ msgstr "Mikrofonu"
+
+#~ msgid "On"
+#~ msgstr "On"
+
+#~ msgid "Off"
+#~ msgstr "Off"
+
+#~ msgid "Fast"
+#~ msgstr "Fast"
+
+#~ msgid "Low"
+#~ msgstr "Low"
+
+#~ msgid "Medium"
+#~ msgstr "Medium"
+
+#~ msgid "High"
+#~ msgstr "High"
+
+#, fuzzy
+#~ msgid "Very High"
+#~ msgstr "Very high"
+
+#~ msgid "Production"
+#~ msgstr "Production"
+
+#, fuzzy
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Mikrofonu tal-panella ta' quddiem"
+
+#, fuzzy
+#~ msgid "Front Panel Line In"
+#~ msgstr "Front panel line-in"
+
+#, fuzzy
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Front panel headphones"
+
+#, fuzzy
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Front panel line-in"
+
+#, fuzzy
+#~ msgid "Green Connector"
+#~ msgstr "Connector aħdar"
+
+#, fuzzy
+#~ msgid "Pink Connector"
+#~ msgstr "Connector roża"
+
+#, fuzzy
+#~ msgid "Blue Connector"
+#~ msgstr "Connector Blu"
+
+#, fuzzy
+#~ msgid "White Connector"
+#~ msgstr "Connector abjad"
+
+#, fuzzy
+#~ msgid "Black Connector"
+#~ msgstr "Connector iswed"
+
+#, fuzzy
+#~ msgid "Gray Connector"
+#~ msgstr "Connector Griż"
+
+#, fuzzy
+#~ msgid "Orange Connector"
+#~ msgstr "Connector oranġjo"
+
+#, fuzzy
+#~ msgid "Red Connector"
+#~ msgstr "Connector aħmar"
+
+#, fuzzy
+#~ msgid "Yellow Connector"
+#~ msgstr "Connector isfar"
+
+#, fuzzy
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Front panel connector aħdar"
+
+#, fuzzy
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Front panel connector roża"
+
+#, fuzzy
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Front panel connector blu"
+
+#, fuzzy
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Front panel connector abjad"
+
+#, fuzzy
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Front panel connector iswed"
+
+#, fuzzy
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Front panel connector Griż"
+
+#, fuzzy
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Front Panel connector oranġjo"
+
+#, fuzzy
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Front panel connector aħmar"
+
+#, fuzzy
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Front panel connector isfar"
+
+#, fuzzy
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Virtual mixer input"
+
+#, fuzzy
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Virtual mixer output"
+
+#, fuzzy
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Virtual mixer input"
+
+#, fuzzy
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Problema fil-qar()i %d bytes fid-device '%s'."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Could not enqueue buffers in device '%s'."
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Kuntatt mas-sound server ma ġiex stabbilit"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Mhux possibli t-tfittxija għall-kapaċita tas-sound server"
+
+#~ msgid "Error stopping streaming capture from device '%s'."
+#~ msgstr "Problem biex inwaqqaf streaming capture mill-apparat '%s'."
+
+#~ msgid "Error starting streaming capture from device '%s'."
+#~ msgstr "Problem biex nibda streaming capture mill-apparat '%s'."
+
+#~ msgid "Could not get enough buffers from device '%s'."
+#~ msgstr "Ma nistax nirċievi biżżejjed buffers mill-apparat '%s'."
+
+#~ msgid "Could not get buffers from device '%s'."
+#~ msgstr "Ma nistax nirċievi buffers mill-apparat '%s'."
+
+#~ msgid "No free buffers found in the pool at index %d."
+#~ msgstr "Ma nstab l-ebda buffer free fl-indiċi %d tal-pool."
+
+#~ msgid "insufficient memory to enqueue a user pointer buffer. device %s."
+#~ msgstr "insufficient memory to enqueue a user pointer buffer. device %s."
+
+#~ msgid ""
+#~ "Failed trying to get video frames from device '%s'. Not enough memory."
+#~ msgstr ""
+#~ "Problema biex inġib video frames mill-apparat '%s'. Il-memorja allokata "
+#~ "mhijiex biżżejjed."
+
+#~ msgid ""
+#~ "The buffer type is not supported, or the index is out of bounds, or no "
+#~ "buffers have been allocated yet, or the userptr or length are invalid. "
+#~ "device %s"
+#~ msgstr ""
+#~ "The buffer type is not supported, or the index is out of bounds, or no "
+#~ "buffers have been allocated yet, or the userptr or length are invalid. "
+#~ "device %s"
+
+#~ msgid "Failed getting controls attributes on device '%s.'"
+#~ msgstr "L-attributi ta' kontroll ta' device '%s' ma nqrawx."
diff --git a/po/nb.po b/po/nb.po
new file mode 100644
index 0000000..6f7844e
--- /dev/null
+++ b/po/nb.po
@@ -0,0 +1,779 @@
+# Norwegian bokmaal translation of gst-utils.
+# This file is put in the public domain.
+#
+# Kjartan Maraas <kmaraas@gnome.org>, 2004-2010.
+# Johnny A. Solbu <johnny@solbu.net>, 2012-2016
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-08-05 23:47+0200\n"
+"Last-Translator: Johnny A. Solbu <johnny@solbu.net>\n"
+"Language-Team: Norwegian Bokmaal <i18n-nb@lister.ping.uio.no>\n"
+"Language: nb_NO\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.8.7.1\n"
+
+msgid "Jack server not found"
+msgstr "Jack-server ikke funnet"
+
+msgid "Failed to decode JPEG image"
+msgstr "Klarte ikke å dekode JPEG-bilde"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "«%s» av «%s»"
+
+msgid "Could not connect to server"
+msgstr "Kunne ikke koble til tjener."
+
+msgid "No URL set."
+msgstr "Ingen URL satt."
+
+msgid "Could not resolve server name."
+msgstr "Kunne ikke slå opp navn på tjener."
+
+msgid "Could not establish connection to server."
+msgstr "Kunne ikke etablere tilkobling til tjener."
+
+msgid "Secure connection setup failed."
+msgstr "Oppsett av sikker tilkobling feilet."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr "En nettverksfeil oppstod, eller tjeneren lukket uventet tilkoblingen."
+
+msgid "Server sent bad data."
+msgstr "Tjener sendte ugyldige data."
+
+msgid "Server does not support seeking."
+msgstr "Tjener støtter ikke søking."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Ingen eller ugyldig inndatalyd, AVI-strømmen vil bli skadet."
+
+msgid "This file contains no playable streams."
+msgstr "Filen inneholder ingen spillbare strømmer."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Filen er ugyldig og kan ikke spilles."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr "Kan ikke spille av strømmen fordi den er kryptert med PlayReady DRM."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Filen er skadet og kan ikke spilles."
+
+msgid "Invalid atom size."
+msgstr "Ugyldig atomstørrelse."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Filen er ufullstendig og kan ikke spilles."
+
+msgid "The video in this file might not play correctly."
+msgstr "Videoen i denne filen spilles kanskje ikke av korrekt."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Filen inneholder for mange strømmer. Spiller bare første %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Ingen støttet strøm ble funnet. Du må kanskje installere en GStreamer RTSP "
+"utvidelsesprogramtillegg for Real mediestrømmer."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Ingen støttet strøm ble funnet. Du må kanskje tillate flere "
+"transportprotokoller eller den kan mangle den rette GStreamer RTSP-"
+"utvidelsestillegget."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Kunne ikke åpne lydenheten for avspilling. Enheten brukes av et annet "
+"program."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Kunne ikke åpne lydenheten for avspilling. Du har ikke tillatelse til å åpne "
+"enheten."
+
+msgid "Could not open audio device for playback."
+msgstr "Kunne ikke åpne lydenhet for avspilling."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Kunne ikke åpne lydenheten for avspilling. Denne versjonen av «Open Sound "
+"System» støttes ikke av dette elementet."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Avspilling støttes ikke av denne lydenheten."
+
+msgid "Audio playback error."
+msgstr "Lydavspillingsfeil"
+
+msgid "Recording is not supported by this audio device."
+msgstr "Opptak støttes ikke av denne lydenheten."
+
+msgid "Error recording from audio device."
+msgstr "Feil ved opptak fra lydenheten."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Kunne ikke åpne lydenheten for opptak. Du har ikke tillatelse til å åpne "
+"enheten."
+
+msgid "Could not open audio device for recording."
+msgstr "Kunne ikke åpne lydenhet for opptak."
+
+msgid "CoreAudio device not found"
+msgstr "CoreAudio-enhet ikke funnet"
+
+msgid "CoreAudio device could not be opened"
+msgstr "CoreAudio-enhet kune ikke åpnes"
+
+msgid "Record Source"
+msgstr "Opptakskilde"
+
+msgid "Microphone"
+msgstr "Mikrofon"
+
+msgid "Line In"
+msgstr "Linje inn"
+
+msgid "Internal CD"
+msgstr "Intern CD"
+
+msgid "SPDIF In"
+msgstr "SPDIF Inn"
+
+msgid "AUX 1 In"
+msgstr "AUX 1 inn"
+
+msgid "AUX 2 In"
+msgstr "AUX 2 inn"
+
+msgid "Codec Loopback"
+msgstr "Kodek-Loopback"
+
+msgid "SunVTS Loopback"
+msgstr "SunVTS-Loopback"
+
+msgid "Volume"
+msgstr "Volum"
+
+msgid "Gain"
+msgstr "Styrke"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "Innebygget høyttaler"
+
+msgid "Headphone"
+msgstr "Hodetelefon"
+
+msgid "Line Out"
+msgstr "Linje ut"
+
+msgid "SPDIF Out"
+msgstr "SPDIF ut"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1 ut"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2 ut"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Feil ved lesing av% d bytes fra enheten '% s»."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr "Kunne ikke spesifisere mulige videoformater enhet «%s» kan arbeide med"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Kunne ikke tilordne buffere fra enheten «%s»."
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Driveren av enheten «%s» støtter ikke IO metoden %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Driveren av enheten «%s» støtter ikke noen kjente IO-metoder."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Enheten «%s» er opptatt"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Enhet «%s» kan ikke fange ved %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Enhet «%s» kan ikke fange i det angitte formatet"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Enhet «%s» støtter ikke ikke-sammenhengende plan"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Kunne ikke få parametere på enheten «%s»."
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "Videoenheten aksepterte ikke ny bildefrekvensinnstilling."
+
+msgid "Video device did not provide output format."
+msgstr "Videoenhet tilbød ikke utdataformat."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Videoenhet returnerte ugyldige dimensjoner."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Video-enheter bruker en ustøttet linjeflettingsmetode."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Videoenhet bruker et ustøttet pikselformat."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Klarte ikke å konfigurere internt bufferområde"
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Videoenhet foreslo ikke noen bufferstørrelse."
+
+msgid "No downstream pool to import from."
+msgstr "Ingen nedstrømsområde å importere fra."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Kunne ikke hente innstillingene fra mottakeren %d på enheten «%s»."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Feil ved henting av funksjoner for enheten «%s»."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Enheten «%s» er ikke en tuner."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Mislyktes i å få radio-inndata på enheten «%s»."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Klarte ikke å sette inngang %d på enhet %s."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Klarte ikke å endre dempe-modus for enheten «%s»."
+
+msgid "Failed to allocated required memory."
+msgstr "Kunne ikke tildele nødvendige minne."
+
+msgid "Failed to allocate required memory."
+msgstr "Kunne ikke tildele nødvendige minne."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Konverter på enhet «%s» har ingen støttede inndataformat"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Konverter på enhet «%s» har ingen støttede utdataformat"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Enkoder på enhet «%s» har ingen støttede inndataformat"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Enkoder på enhet «%s» har ingen støttede utdataformat"
+
+msgid "Failed to start decoding thread."
+msgstr "Klarte ikke å starte dekoding av tråden."
+
+msgid "Failed to process frame."
+msgstr "Kunne ikke behandle ramme."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Feil ved henting av evner for enheten «%s»: Det er ikke en v4l2 driver. "
+"Sjekk om det er en v4l1 driver."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Feil ved attributtspørring av inndata %d på enhet %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Kunne ikke hente innstillingen av mottakeren %d på enheten «%s»."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Feil ved norm-spørring på enhet %s."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Kunne ikke å få inn kontrollattributter på enhet «%s»."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Kan ikke identifisere enhet «%s»."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Dette er ikke en enhet «%s»."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Kunne ikke åpne enhet «%s» for lesing og skriving."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Enhet «%s» kan ikke fange data."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Enhet «%s» er ikke en utgangsenhet."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Enheten «%s» er ikke en M2M-enhet."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Kunne ikke åpne enhet «%s» for lesing og skriving."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Kunne ikke sette normen for enhet «%s»."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Klarte ikke å få gjeldende mottakerfrekvens for enheten «%s»."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Klarte ikke å sette gjeldende mottakerfrekvens for enheten «%s» til %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Klarte ikke å innhente signalstyrken for enheten «%s»."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Kunne ikke hente verdi for kontroll %d på enheten «%s»."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Klarte ikke å sette verdi %d for kontroll %d på enheten «%s»."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Kunne ikke hente gjeldende inndata på enheten «%s». Kanskje det er en "
+"radioenhet"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr "Kunne ikke hente utdata fra enheten «%s». Kanskje det er en radioenhet"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Klarte ikke å sette utgang %d på enhet %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Endring av oppløsning under kjøring støttes ikke enda."
+
+msgid "Cannot operate without a clock"
+msgstr "Kan ikke operere uten en klokke"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Intern feil i datastrøm."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Intern dataflytfeil."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Enhet «%s» støtter ikke videoopptak"
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Kunne ikke etablere tilkobling til lydtjener"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Klarte ikke å etterspørre lydtjenerens evner"
+
+#~ msgid "Bass"
+#~ msgstr "Bass"
+
+#~ msgid "Treble"
+#~ msgstr "Diskant"
+
+#~ msgid "Synth"
+#~ msgstr "Synth"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Høyttaler"
+
+#~ msgid "Line-in"
+#~ msgstr "Linje inn"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Mikser"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Opptak"
+
+#~ msgid "In-gain"
+#~ msgstr "Innstyrke"
+
+#~ msgid "Out-gain"
+#~ msgstr "Utstyrke"
+
+#~ msgid "Line-1"
+#~ msgstr "Linje 1"
+
+#~ msgid "Line-2"
+#~ msgstr "Linje 2"
+
+#~ msgid "Line-3"
+#~ msgstr "Linje 3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Digital 1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Digital 2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Digital 3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Telefon inn"
+
+#~ msgid "Phone-out"
+#~ msgstr "Telefon ut"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Radio"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "Kunne ikke åpne lydenheten for mikserkontrollhåndtering."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Kunne ikke åpne lydenheten for mikserkontrollhåndtering. Denne versjonen "
+#~ "av «Open Sound System» støttes ikke av dette elementet."
+
+#~ msgid "Master"
+#~ msgstr "Hovedvolum"
+
+#~ msgid "Front"
+#~ msgstr "Front"
+
+#~ msgid "Rear"
+#~ msgstr "Bak"
+
+#~ msgid "Headphones"
+#~ msgstr "Hodetelefoner"
+
+#~ msgid "Center"
+#~ msgstr "Senter"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Surround"
+
+#~ msgid "Side"
+#~ msgstr "Side"
+
+#~ msgid "AUX Out"
+#~ msgstr "AUX ut"
+
+#~ msgid "3D Depth"
+#~ msgstr "3D dybde"
+
+#~ msgid "3D Center"
+#~ msgstr "3D senter"
+
+#~ msgid "3D Enhance"
+#~ msgstr "3D-forbedring"
+
+#~ msgid "Telephone"
+#~ msgstr "Telefon"
+
+#~ msgid "Video In"
+#~ msgstr "Video inn"
+
+#~ msgid "AUX In"
+#~ msgstr "AUX inn"
+
+#~ msgid "Record Gain"
+#~ msgstr "Innspillingsstyrke"
+
+#~ msgid "Output Gain"
+#~ msgstr "Utdatastyrke"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Mikrofonforsterkning"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Diagnose"
+
+#~ msgid "Bass Boost"
+#~ msgstr "BassBoost"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Avspillingsporter:"
+
+#~ msgid "Input"
+#~ msgstr "Inngang"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Monitorkilde"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Tastaturpip"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Simulert stereo"
+
+#~ msgid "Stereo"
+#~ msgstr "Stereo"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Surroundlyd"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Mikrofonstyrke"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Høyttalerkilde"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Mikrofonkilde"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Senter / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Stereomiks"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Monomiks"
+
+#~ msgid "Input Mix"
+#~ msgstr "Inndatamiks"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Mikrofon 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Mikrofon 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Digital ut"
+
+#~ msgid "Digital In"
+#~ msgstr "Digital inn"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modem"
+
+#~ msgid "Handset"
+#~ msgstr "Håndsett"
+
+#~ msgid "Other"
+#~ msgstr "Annet"
+
+#~ msgid "None"
+#~ msgstr "Ingen"
+
+#~ msgid "On"
+#~ msgstr "På"
+
+#~ msgid "Off"
+#~ msgstr "Av"
+
+#~ msgid "Mute"
+#~ msgstr "Demp"
+
+#~ msgid "Fast"
+#~ msgstr "Rask"
+
+#~ msgid "Very Low"
+#~ msgstr "Meget lav"
+
+#~ msgid "Low"
+#~ msgstr "Lav"
+
+#~ msgid "Medium"
+#~ msgstr "Middels"
+
+#~ msgid "High"
+#~ msgstr "Høy"
+
+#~ msgid "Very High"
+#~ msgstr "Meget høy"
+
+#~ msgid "Production"
+#~ msgstr "Produksjon"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Fronpanelmikrofon"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Frontpanel innlinje"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Frontpanelhodetelefoner"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Frontpanel utlinje"
+
+#~ msgid "Green Connector"
+#~ msgstr "Grønn kontakt"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Rosa kontakt"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Blå kontakt"
+
+#~ msgid "White Connector"
+#~ msgstr "Hvit kontakt"
+
+#~ msgid "Black Connector"
+#~ msgstr "Sort kontakt"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Grå kontakt"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Oransje kontakt"
+
+#~ msgid "Red Connector"
+#~ msgstr "Rød kontakt"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Gul kontakt"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Grønn frontpanelkontakt"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Rosa frontpanelkontakt"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Blå frontpanelkontakt"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Hvit frontpanelkontakt"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Sort frontpanelkontakt"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Grå frontpanelkontakt"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Oransje frontpanelkontakt"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Rød frontpanelkontakt"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Gul frontpanelkontakt"
+
+#~ msgid "Spread Output"
+#~ msgstr "Spredningsutgang"
+
+#~ msgid "Downmix"
+#~ msgstr "Nedmiks"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Virtuell mikserinngang"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Virtuell mikserutgang"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Virtuelle mikserkanaler"
+
+#~ msgid "%s %d Function"
+#~ msgstr "%s %d Funksjon"
+
+#~ msgid "%s Function"
+#~ msgstr "%s Funksjon"
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Fikk uventet rammestørrelsen %u istedenfor %u."
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Feil ved lesing av %d byte på enheten «%s»."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Kunne ikke legge i kø buffere i enheten «%s»."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Mislyktes i å få videobilder fra enhet «%s»."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Mislyktes etter %d forsøk. Enhet %s. Systemfeil: %s"
+
+#~ msgid "Describes the selected input element."
+#~ msgstr "Beskriver valgt inndataelement."
diff --git a/po/nl.po b/po/nl.po
new file mode 100644
index 0000000..41aac1c
--- /dev/null
+++ b/po/nl.po
@@ -0,0 +1,782 @@
+# translation of gst-plugins-good.nl.po to Dutch
+# This file is put in the public domain.
+#
+# Freek de Kruijf <f.de.kruijf@gmail.com>, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-02-20 16:40+0100\n"
+"Last-Translator: Freek de Kruijf <f.de.kruijf@gmail.com>\n"
+"Language-Team: Dutch <vertaling@vrijschrift.org>\n"
+"Language: nl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Lokalize 1.5\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+msgid "Jack server not found"
+msgstr "Jack-server niet gevonden"
+
+msgid "Failed to decode JPEG image"
+msgstr "Kan de JPEG-afbeelding niet decoderen"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "'%s' door '%s'"
+
+msgid "Could not connect to server"
+msgstr "Kan geen verbinding maken met server"
+
+msgid "No URL set."
+msgstr "Geen URL ingesteld."
+
+msgid "Could not resolve server name."
+msgstr "Kan de servernaam niet opzoeken."
+
+msgid "Could not establish connection to server."
+msgstr "Kan geen verbinding maken met de server"
+
+msgid "Secure connection setup failed."
+msgstr "Beveiligde verbinding opzetten is mislukt."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Er trad een netwerkfout op of de server heeft de verbinding onverwacht "
+"afgebroken."
+
+msgid "Server sent bad data."
+msgstr "De server stuurde onjuiste gegevens."
+
+msgid "Server does not support seeking."
+msgstr "Zoeken wordt door de server niet ondersteund."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Geen of ongeldig invoergeluid, AVI-stroom zal slecht zijn."
+
+msgid "This file contains no playable streams."
+msgstr "Dit bestand bevat geen afspeelbare stromen."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Dit bestand is ongeldig en kan niet afgespeeld worden."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr "Kan stream niet afspelen omdat het versleuteld is met PlayReady DRM."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Dit bestand is beschadigd en kan niet afgespeeld worden."
+
+msgid "Invalid atom size."
+msgstr "Ongeldige \"atom\"-grootte."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Dit bestand is incompleet en kan niet afgespeeld worden."
+
+msgid "The video in this file might not play correctly."
+msgstr "De video in dit bestand zal mogelijk niet correct afgespeeld worden."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+"Dit bestand bevat te veel stromen. Alleen de eerste %d worden afgespeeld."
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Er is geen ondersteunde stroom gevonden. Misschien moet er een GStreamer "
+"RTSP extensie-plugin voor Real-media-streams geïnstalleerd worden."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Er is geen ondersteunde stroom gevonden. Misschien moet u meer "
+"overdrachtsprotocollen toestaan of anders ontbreekt de juiste GStreamer RTSP "
+"extensie-plugin."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Kan het audio-apparaat niet openen voor afspelen. Apparaat is in gebruik bij "
+"een andere applicatie."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Kan het audio-apparaat niet openen voor afspelen. U hebt geen toestemming om "
+"het apparaat te openen."
+
+msgid "Could not open audio device for playback."
+msgstr "Kan het audio-apparaat niet openen voor afspelen."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Kan het audio-apparaat niet openen voor afspelen. Deze versie van het Open "
+"Sound System wordt niet ondersteunt door dit element."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Afspelen wordt niet ondersteund door dit audio-apparaat"
+
+msgid "Audio playback error."
+msgstr "Fout in geluid afspelen."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Opnemen wordt niet ondersteund door dit audio-apparaat"
+
+msgid "Error recording from audio device."
+msgstr "Fout bij opnemen vanaf audio-apparaat."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Kan het audio-apparaat niet openen voor opnemen. U hebt geen toestemming om "
+"het apparaat te openen."
+
+msgid "Could not open audio device for recording."
+msgstr "Kan het audio-apparaat niet openen voor opnemen."
+
+msgid "CoreAudio device not found"
+msgstr "CoreAudio apparaat niet gevonden"
+
+msgid "CoreAudio device could not be opened"
+msgstr "CoreAudio apparaat kon niet geopend worden"
+
+msgid "Record Source"
+msgstr "Opnamebron"
+
+msgid "Microphone"
+msgstr "Microfoon"
+
+msgid "Line In"
+msgstr "Lijn-in"
+
+msgid "Internal CD"
+msgstr "Interne cd"
+
+msgid "SPDIF In"
+msgstr "SPDIF-in"
+
+msgid "AUX 1 In"
+msgstr "AUX 1-in"
+
+msgid "AUX 2 In"
+msgstr "AUX 2-in"
+
+msgid "Codec Loopback"
+msgstr "Codec-loopback"
+
+msgid "SunVTS Loopback"
+msgstr "SunVTS-loopback"
+
+msgid "Volume"
+msgstr "Volume"
+
+msgid "Gain"
+msgstr "Versterking"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "Ingebouwde luidspreker"
+
+msgid "Headphone"
+msgstr "Hoofdtelefoon"
+
+msgid "Line Out"
+msgstr "Line-out"
+
+msgid "SPDIF Out"
+msgstr "SPDIF-out"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1-out"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2-out"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Fout bij het lezen van %d bytes van apparaat '%s'."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr "Opnoemen van videoformaten waarmee apparaat '%s' kan werken is mislukt"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Kan de buffers van apparaat '%s' niet vinden"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Het stuurprogramma van apparaat '%s' ondersteunt de IO-methode %d niet"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"Het stuurprogramma van apparaat '%s' ondersteunt geen bekende IO-methode."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Apparaat '%s' is bezet"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Apparaat '%s' kan geen opname maken met %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Apparaat '%s' kan geen opname maken in het gespecificeerde formaat"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Apparaat '%s' ondersteunt niet-continue vlakken"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Kan de parameters op apparaat '%s' niet verkrijgen"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "Videoapparaat heeft de nieuwe frame-snelheid niet geaccepteerd."
+
+msgid "Video device did not provide output format."
+msgstr "Videoapparaat leverde geen uitvoerformaat."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Video-apparaat gaf ongeldige afmetingen terug."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+"Video-apparaat gebruikt een niet ondersteunde methode voor interlacing."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Video-apparaat gebruikt een niet ondersteund pixelformaat."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Instellen van interne bufferpool is mislukt."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Videoapparaat gaf geen suggestie voor een buffergrootte."
+
+msgid "No downstream pool to import from."
+msgstr "Geen downstream pool om van te importeren."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Instellingen van tuner %d op apparaat '%s' ophalen is mislukt."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Fout bij het ophalen de mogelijkheden van apparaat '%s'."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Apparaat '%s' is geen tuner."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Radio-invoer van apparaat '%s' ophalen is mislukt."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Kan invoer %d op apparaat '%s' niet instellen."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "De gedempte status van apparaat '%s' wijzigen is mislukt."
+
+msgid "Failed to allocated required memory."
+msgstr "Vereist geheugen toekennen is mislukt."
+
+msgid "Failed to allocate required memory."
+msgstr "Vereist geheugen toekennen is mislukt."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Converter op apparaat %s heeft geen ondersteund invoerformaat"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Converter op apparaat %s heeft geen ondersteund uitvoerformaat"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Codeerder op apparaat %s heeft geen ondersteund invoerformaat"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Codeerder op apparaat %s heeft geen ondersteund uitvoerformaat"
+
+msgid "Failed to start decoding thread."
+msgstr "Beginnen met decoderen van thread is mislukt."
+
+msgid "Failed to process frame."
+msgstr "Bewerken van frame is mislukt."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Fout bij het verkrijgen van de eigenschappen van apparaat '%s': het is geen "
+"v4l2-stuurprogramma. Controleer of het een v4l1-stuurprogramma is."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Kan eigenschappen van invoer %d op apparaat %s niet opvragen."
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Kan de instelling van tuner %d op apparaat '%s' niet verkrijgen."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Kan de norm op apparaat '%s' niet opvragen."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Kan de knopeigenschappen op apparaat '%s' niet verkrijgen."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Kan apparaat '%s' niet identificeren."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Dit is geen apparaat '%s'."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Kan apparaat '%s' niet openen voor lezen en schrijven."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Apparaat '%s' is geen opnameapparaat."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Apparaat '%s' is geen uitvoerapparaat."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Apparaat '%s' is geen M2M-apparaat."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Kan geen dup doen op apparaat '%s' voor lezen en schrijven."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Kan norm niet instellen voor apparaat '%s'."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Kan de tunerfrequentie van apparaat '%s' niet verkrijgen."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Kan de huidige tunerfrequentie voor apparaat '%s' niet instellen op %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Kan de signaalsterkte van apparaat '%s' niet verkrijgen."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Kan de waarde voor knop %d op apparaat '%s' niet verkrijgen."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Kan de waarde %d voor knop %d op apparaat '%s' niet instellen."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Kan de huidige instellingen van apparaat '%s' niet verkrijgen. Het is "
+"mogelijk een radio"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Kan de huidige uitvoer niet op apparaat '%s' krijgen. Het is mogelijk een "
+"radio"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Kan uitvoer %d op apparaat %s niet instellen."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Tijdens het draaien kan de resolutie nog niet gewijzigd worden."
+
+msgid "Cannot operate without a clock"
+msgstr "Kan niet werken zonder een klok."
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Interne fout in gegevensstroom."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Interne fout in de gegevensdoorvoer."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Apparaat '%s' ondersteunt het opnemen van video niet"
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Kan geen verbinding maken met de geluidsserver"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Kan de eigenschappen van de geluidsserver niet opvragen"
+
+#~ msgid "Bass"
+#~ msgstr "Lage tonen"
+
+#~ msgid "Treble"
+#~ msgstr "Hoge tonen"
+
+#~ msgid "Synth"
+#~ msgstr "Synth"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Luidspreker"
+
+#~ msgid "Line-in"
+#~ msgstr "Lijn-in"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Mixer"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Opname"
+
+#~ msgid "In-gain"
+#~ msgstr "Ingangsversterking"
+
+#~ msgid "Out-gain"
+#~ msgstr "Uitgangsversterking"
+
+#~ msgid "Line-1"
+#~ msgstr "Lijn-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Lijn-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Lijn-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Digitaal-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Digitaal-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Digitaal-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Telefooningang"
+
+#~ msgid "Phone-out"
+#~ msgstr "Telefoonuitgang"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Radio"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "Kan het audio-apparaat niet openen voor het besturen van de mixer."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Kan het audio-apparaat niet openen voor besturen van de mixer. Deze "
+#~ "versie van het Open Sound System wordt niet ondersteunt door dit element."
+
+#~ msgid "Master"
+#~ msgstr "Master"
+
+#~ msgid "Front"
+#~ msgstr "Voorkant"
+
+#~ msgid "Rear"
+#~ msgstr "Achterzijde"
+
+#~ msgid "Headphones"
+#~ msgstr "Hoofdtelefoons"
+
+#~ msgid "Center"
+#~ msgstr "Midden"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Surround"
+
+#~ msgid "Side"
+#~ msgstr "Zijkant"
+
+#~ msgid "AUX Out"
+#~ msgstr "AUX-uit"
+
+#~ msgid "3D Depth"
+#~ msgstr "3D-diepte"
+
+#~ msgid "3D Center"
+#~ msgstr "3D-centrum"
+
+#~ msgid "3D Enhance"
+#~ msgstr "3D-verbeteren"
+
+#~ msgid "Telephone"
+#~ msgstr "Telefoon"
+
+#~ msgid "Video In"
+#~ msgstr "Video-in"
+
+#~ msgid "AUX In"
+#~ msgstr "AUX-in"
+
+#~ msgid "Record Gain"
+#~ msgstr "Opnameversterking"
+
+#~ msgid "Output Gain"
+#~ msgstr "Uitgangsversterking"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Microfoon-boost"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Diagnose"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Bas-boost"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Afspeelpoorten"
+
+#~ msgid "Input"
+#~ msgstr "Invoer"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Monitorbron"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Toetsenbordpiep"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Stereo simuleren"
+
+#~ msgid "Stereo"
+#~ msgstr "Stereo"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Surround-geluid"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Microfoonversterking"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Luidsprekerbron"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Microfoonbron"
+
+#~ msgid "Jack"
+#~ msgstr "Plug"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Midden / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Stereo-mix"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Mono-mix"
+
+#~ msgid "Input Mix"
+#~ msgstr "Invoer-mix"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Microfoon-1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Microfoon-2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Digitaal-uit"
+
+#~ msgid "Digital In"
+#~ msgstr "Digitaal-in"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modem"
+
+#~ msgid "Handset"
+#~ msgstr "Handset"
+
+#~ msgid "Other"
+#~ msgstr "Overig"
+
+#~ msgid "None"
+#~ msgstr "Geen"
+
+#~ msgid "On"
+#~ msgstr "Aan"
+
+#~ msgid "Off"
+#~ msgstr "Uit"
+
+#~ msgid "Mute"
+#~ msgstr "Dempen"
+
+#~ msgid "Fast"
+#~ msgstr "Snel"
+
+#~ msgid "Very Low"
+#~ msgstr "Zeer laag"
+
+#~ msgid "Low"
+#~ msgstr "Laag"
+
+#~ msgid "Medium"
+#~ msgstr "Middel"
+
+#~ msgid "High"
+#~ msgstr "Hoog"
+
+#~ msgid "Very High"
+#~ msgstr "Zeer hoog"
+
+#~ msgid "Production"
+#~ msgstr "Productie"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Microfoon in frontpaneel"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Lijn-in in frontpaneel"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Hoofdtelefoons in frontpaneel"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Lijn-uit in frontpaneel"
+
+#~ msgid "Green Connector"
+#~ msgstr "Groene connector"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Roze connector"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Blauwe connector"
+
+#~ msgid "White Connector"
+#~ msgstr "Witte connector"
+
+#~ msgid "Black Connector"
+#~ msgstr "Zwarte connector"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Grijze connector"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Oranje connector"
+
+#~ msgid "Red Connector"
+#~ msgstr "Rode connector"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Gele connector"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Groene connector in frontpaneel"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Roze connector in frontpaneel"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Blauwe connector in frontpaneel"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Witte connector in frontpaneel"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Zwarte connector in frontpaneel"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Grijze connector in frontpaneel"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Oranje connector in frontpaneel"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Rode connector in frontpaneel"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Gele connector in frontpaneel"
+
+#~ msgid "Spread Output"
+#~ msgstr "Uitvoer spreiden"
+
+#~ msgid "Downmix"
+#~ msgstr "Downmix"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Virtuele mixer-invoer"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Virtuele mixer-uitvoer"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Virtuele mixer-kanalen"
+
+#~ msgid "%s %d Function"
+#~ msgstr "%s %d functie"
+
+#~ msgid "%s Function"
+#~ msgstr "%s-function"
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Onverwachte framegrootte, %u in plaats van %u."
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Fout bij het lezen van %d bytes van apparaat '%s'."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Kan geen buffers toekennen in apparaat '%s'."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Kan geen videoframes verkrijgen van apparaat '%s'."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Fout na %d pogingen. Apparaat %s. Systeemfout: %s"
diff --git a/po/or.po b/po/or.po
new file mode 100644
index 0000000..ae536fd
--- /dev/null
+++ b/po/or.po
@@ -0,0 +1,651 @@
+# Oriya translation of gst-plugins-0.8.3.pot.
+# Copyright (C) 2004, Free Software Foundation, Inc.
+# This file is distributed under the same license as the gst-plugins-0.8.3 package.
+# Gora Mohanty <gora_mohanty@yahoo.co.in>, 2004.
+# $Id: or.po,v 1.30 2008-04-23 23:18:43 thaytan Exp $
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-0.8.3\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2004-09-27 13:32+0530\n"
+"Last-Translator: Gora Mohanty <gora_mohanty@yahoo.co.in>\n"
+"Language-Team: Oriya <gora_mohanty@yahoo.co.in>\n"
+"Language: or\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr ""
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr ""
+
+#, fuzzy
+msgid "Could not connect to server"
+msgstr "\"%s\" ନିୟନ୍ତ୍ରଣ ଯନ୍ତ୍ର ବନ୍ଦ କରିହେଲା ନାହିଁ."
+
+msgid "No URL set."
+msgstr ""
+
+#, fuzzy
+msgid "Could not resolve server name."
+msgstr "\"%s\" ନିୟନ୍ତ୍ରଣ ଯନ୍ତ୍ର ବନ୍ଦ କରିହେଲା ନାହିଁ."
+
+#, fuzzy
+msgid "Could not establish connection to server."
+msgstr "\"%s\" ନିୟନ୍ତ୍ରଣ ଯନ୍ତ୍ର ବନ୍ଦ କରିହେଲା ନାହିଁ."
+
+msgid "Secure connection setup failed."
+msgstr ""
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+
+msgid "Server sent bad data."
+msgstr ""
+
+#, fuzzy
+msgid "Server does not support seeking."
+msgstr "\"%s\" ଯନ୍ତ୍ର ଗୋଟିଏ ଅନୁଲିପିକାର ନୁହେଁ."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "ନିବେଶ ଧ୍ବନି ନାହିଁ ବା ଅବୈଧ ଅଛି. ଏ.ଭି.ଆଇ. ଧାରା ଭ୍ରଷ୍ଟ ହୋଇଯିବ."
+
+msgid "This file contains no playable streams."
+msgstr ""
+
+msgid "This file is invalid and cannot be played."
+msgstr ""
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr ""
+
+msgid "Invalid atom size."
+msgstr ""
+
+msgid "This file is incomplete and cannot be played."
+msgstr ""
+
+msgid "The video in this file might not play correctly."
+msgstr ""
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+
+#, fuzzy
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr "\"%s\" ଧ୍ବନି ଯନ୍ତ୍ର ଲେଖିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ."
+
+#, fuzzy
+msgid "Could not open audio device for playback."
+msgstr "\"%s\" ଧ୍ବନି ଯନ୍ତ୍ର ଲେଖିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+
+msgid "Playback is not supported by this audio device."
+msgstr ""
+
+msgid "Audio playback error."
+msgstr ""
+
+msgid "Recording is not supported by this audio device."
+msgstr ""
+
+msgid "Error recording from audio device."
+msgstr ""
+
+#, fuzzy
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr "ସି.ଡି. ଯନ୍ତ୍ର ପଢ଼ିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ."
+
+#, fuzzy
+msgid "Could not open audio device for recording."
+msgstr "ସି.ଡି. ଯନ୍ତ୍ର ପଢ଼ିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+#, fuzzy
+msgid "CoreAudio device could not be opened"
+msgstr "ଆପଣଙ୍କର ଓ.ଏସ.ଏସ. ଯନ୍ତ୍ରର ଠିକ ଭାବରେ ଅନୁସନ୍ଧାନ କରିହେଲା ନାହିଁ."
+
+#, fuzzy
+msgid "Record Source"
+msgstr "ପ୍ରଦର୍ଶିକା"
+
+msgid "Microphone"
+msgstr "ମାଇକ୍ରୋଫୋନ୍"
+
+#, fuzzy
+msgid "Line In"
+msgstr "ଲାଇନ-ଇନ"
+
+msgid "Internal CD"
+msgstr ""
+
+msgid "SPDIF In"
+msgstr ""
+
+msgid "AUX 1 In"
+msgstr ""
+
+msgid "AUX 2 In"
+msgstr ""
+
+msgid "Codec Loopback"
+msgstr ""
+
+msgid "SunVTS Loopback"
+msgstr ""
+
+msgid "Volume"
+msgstr "ପ୍ରବଳତା"
+
+msgid "Gain"
+msgstr ""
+
+msgid "Monitor"
+msgstr "ପ୍ରଦର୍ଶିକା"
+
+#, fuzzy
+msgid "Built-in Speaker"
+msgstr "ସ୍ବରବର୍ଦ୍ଧକ ୟନ୍ତ୍ର"
+
+msgid "Headphone"
+msgstr ""
+
+msgid "Line Out"
+msgstr ""
+
+msgid "SPDIF Out"
+msgstr ""
+
+msgid "AUX 1 Out"
+msgstr ""
+
+msgid "AUX 2 Out"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "\"%s\" ଯନ୍ତ୍ରରୁ ଅସ୍ଥାୟୀ ସଞ୍ଚୟ ସ୍ଥାନ ଆଣିହେଲା ନାହିଁ."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "\"%s\" ଯନ୍ତ୍ରରୁ ଅସ୍ଥାୟୀ ସଞ୍ଚୟ ସ୍ଥାନ ଆଣିହେଲା ନାହିଁ."
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr ""
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Device '%s' is busy"
+msgstr "\"%s\" ଯନ୍ତ୍ର ଗୋଟିଏ ଅନୁଲିପିକାର ନୁହେଁ."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "\"%s\" ଯନ୍ତ୍ର ଗୋଟିଏ ଅନୁଲିପିକାର ନୁହେଁ."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "\"%s\" ଯନ୍ତ୍ର ଗୋଟିଏ ଅନୁଲିପିକାର ନୁହେଁ."
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "\"%s\" ଯନ୍ତ୍ର ଗୋଟିଏ ଅନୁଲିପିକାର ନୁହେଁ."
+
+#, fuzzy, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "\"%s\" ଯନ୍ତ୍ରରୁ ଅସ୍ଥାୟୀ ସଞ୍ଚୟ ସ୍ଥାନ ଆଣିହେଲା ନାହିଁ."
+
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+
+msgid "Video device did not provide output format."
+msgstr ""
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+
+msgid "Video device uses an unsupported pixel format."
+msgstr ""
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+msgid "Video device did not suggest any buffer size."
+msgstr ""
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "\"%s\" ଯନ୍ତ୍ରରୁ ପର୍ଯ୍ଯାପ୍ତ ଅସ୍ଥାୟୀ ସଞ୍ଚୟ ସ୍ଥାନ ଆଣିହେଲା ନାହିଁ."
+
+#, fuzzy, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "\"%s\" ଯନ୍ତ୍ରରୁ ଅସ୍ଥାୟୀ ସଞ୍ଚୟ ସ୍ଥାନ ଆଣିହେଲା ନାହିଁ."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "\"%s\" ଯନ୍ତ୍ର ଗୋଟିଏ ଅନୁଲିପିକାର ନୁହେଁ."
+
+#, fuzzy, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "\"%s\" ଧ୍ବନି ଯନ୍ତ୍ର ବନ୍ଦ କରିହେଲା ନାହିଁ."
+
+#, fuzzy, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "\"%s\" ଧ୍ବନି ଯନ୍ତ୍ର ବନ୍ଦ କରିହେଲା ନାହିଁ."
+
+#, fuzzy, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "\"%s\" ଯନ୍ତ୍ରରୁ ଅସ୍ଥାୟୀ ସଞ୍ଚୟ ସ୍ଥାନ ଆଣିହେଲା ନାହିଁ."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+
+msgid "Failed to start decoding thread."
+msgstr ""
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "\"%s\" ଯନ୍ତ୍ରରୁ ପର୍ଯ୍ଯାପ୍ତ ଅସ୍ଥାୟୀ ସଞ୍ଚୟ ସ୍ଥାନ ଆଣିହେଲା ନାହିଁ."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Cannot identify device '%s'."
+msgstr "\"%s\" ଯନ୍ତ୍ରରେ ଲେଖିହେଲା ନାହିଁ."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "\"%s\" ଯନ୍ତ୍ର ପଢ଼ିବା ଓ ଲେଖିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "\"%s\" ଯନ୍ତ୍ର ଗୋଟିଏ ଅନୁଲିପିକାର ନୁହେଁ."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a output device."
+msgstr "\"%s\" ଯନ୍ତ୍ର ଗୋଟିଏ ଅନୁଲିପିକାର ନୁହେଁ."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "\"%s\" ଯନ୍ତ୍ର ଗୋଟିଏ ଅନୁଲିପିକାର ନୁହେଁ."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "\"%s\" ଯନ୍ତ୍ର ପଢ଼ିବା ଓ ଲେଖିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ."
+
+#, fuzzy, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "\"%s\" ଯନ୍ତ୍ରରୁ ଅସ୍ଥାୟୀ ସଞ୍ଚୟ ସ୍ଥାନ ଆଣିହେଲା ନାହିଁ."
+
+#, fuzzy, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "\"%s\" ଯନ୍ତ୍ରରୁ ପର୍ଯ୍ଯାପ୍ତ ଅସ୍ଥାୟୀ ସଞ୍ଚୟ ସ୍ଥାନ ଆଣିହେଲା ନାହିଁ."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "\"%s\" ନିୟନ୍ତ୍ରଣ ଯନ୍ତ୍ର ବନ୍ଦ କରିହେଲା ନାହିଁ."
+
+#, fuzzy, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "\"%s\" ନିୟନ୍ତ୍ରଣ ଯନ୍ତ୍ର ବନ୍ଦ କରିହେଲା ନାହିଁ."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+
+#, fuzzy, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr "\"%s\" ଯନ୍ତ୍ରରୁ ପର୍ଯ୍ଯାପ୍ତ ଅସ୍ଥାୟୀ ସଞ୍ଚୟ ସ୍ଥାନ ଆଣିହେଲା ନାହିଁ."
+
+#, fuzzy, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "\"%s\" ଧ୍ବନି ଯନ୍ତ୍ର ବନ୍ଦ କରିହେଲା ନାହିଁ."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr ""
+
+msgid "Cannot operate without a clock"
+msgstr ""
+
+#, fuzzy
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "\"%s\" ଯନ୍ତ୍ର ଗୋଟିଏ ଅନୁଲିପିକାର ନୁହେଁ."
+
+#, fuzzy
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "\"%s\" ଯନ୍ତ୍ରରୁ ପର୍ଯ୍ଯାପ୍ତ ଅସ୍ଥାୟୀ ସଞ୍ଚୟ ସ୍ଥାନ ଆଣିହେଲା ନାହିଁ."
+
+#~ msgid "Bass"
+#~ msgstr "ଅନୁଚ୍ଚ ସ୍ବର"
+
+#~ msgid "Treble"
+#~ msgstr "ଉଚ୍ଚ ସ୍ବର"
+
+#~ msgid "Synth"
+#~ msgstr "ସିନ୍ଥେସାଇଜର"
+
+#~ msgid "PCM"
+#~ msgstr "ପି.ସି.ଏମ."
+
+#~ msgid "Speaker"
+#~ msgstr "ସ୍ବରବର୍ଦ୍ଧକ ୟନ୍ତ୍ର"
+
+#~ msgid "Line-in"
+#~ msgstr "ଲାଇନ-ଇନ"
+
+#~ msgid "CD"
+#~ msgstr "ସି.ଡି."
+
+#~ msgid "Mixer"
+#~ msgstr "ମିଶ୍ରଣ ଯନ୍ତ୍ର"
+
+#~ msgid "PCM-2"
+#~ msgstr "ପି.ସି.ଏମ.-୨"
+
+#~ msgid "Record"
+#~ msgstr "ଅନୁଲିପିକରଣ"
+
+#~ msgid "In-gain"
+#~ msgstr "ନିବେଶ-ବୃଦ୍ଧି"
+
+#~ msgid "Out-gain"
+#~ msgstr "ନିର୍ଗମ-ବୃଦ୍ଧି"
+
+#~ msgid "Line-1"
+#~ msgstr "ଲାଇନ-୧"
+
+#~ msgid "Line-2"
+#~ msgstr "ଲାଇନ-୨"
+
+#~ msgid "Line-3"
+#~ msgstr "ଲାଇନ-୩"
+
+#~ msgid "Digital-1"
+#~ msgstr "ସାଂଖ୍ଯିକ-୧"
+
+#~ msgid "Digital-2"
+#~ msgstr "ସାଂଖ୍ଯିକ-୨"
+
+#~ msgid "Digital-3"
+#~ msgstr "ସାଂଖ୍ଯିକ-୩"
+
+#~ msgid "Phone-in"
+#~ msgstr "ଫୋନ-ନିବେଶ"
+
+#~ msgid "Phone-out"
+#~ msgstr "ଫୋନ-ନିର୍ଗମ"
+
+#~ msgid "Video"
+#~ msgstr "ଭିଡିଓ"
+
+#~ msgid "Radio"
+#~ msgstr "ରେଡିଓ"
+
+#, fuzzy
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "\"%s\" ଧ୍ବନି ଯନ୍ତ୍ର ଲେଖିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ."
+
+#, fuzzy
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr "\"%s\" ଧ୍ବନି ଯନ୍ତ୍ର ଲେଖିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ."
+
+#, fuzzy
+#~ msgid "Rear"
+#~ msgstr "ଅନୁଲିପିକରଣ"
+
+#, fuzzy
+#~ msgid "Side"
+#~ msgstr "ଭିଡିଓ"
+
+#, fuzzy
+#~ msgid "Output Gain"
+#~ msgstr "ନିର୍ଗମ-ବୃଦ୍ଧି"
+
+#, fuzzy
+#~ msgid "Microphone Boost"
+#~ msgstr "ମାଇକ୍ରୋଫୋନ୍"
+
+#, fuzzy
+#~ msgid "Microphone Gain"
+#~ msgstr "ମାଇକ୍ରୋଫୋନ୍"
+
+#, fuzzy
+#~ msgid "Speaker Source"
+#~ msgstr "ସ୍ବରବର୍ଦ୍ଧକ ୟନ୍ତ୍ର"
+
+#, fuzzy
+#~ msgid "Microphone Source"
+#~ msgstr "ମାଇକ୍ରୋଫୋନ୍"
+
+#, fuzzy
+#~ msgid "Microphone 1"
+#~ msgstr "ମାଇକ୍ରୋଫୋନ୍"
+
+#, fuzzy
+#~ msgid "Microphone 2"
+#~ msgstr "ମାଇକ୍ରୋଫୋନ୍"
+
+#, fuzzy
+#~ msgid "Digital Out"
+#~ msgstr "ସାଂଖ୍ଯିକ-୧"
+
+#, fuzzy
+#~ msgid "Digital In"
+#~ msgstr "ସାଂଖ୍ଯିକ-୧"
+
+#, fuzzy
+#~ msgid "Front Panel Microphone"
+#~ msgstr "ମାଇକ୍ରୋଫୋନ୍"
+
+#, fuzzy
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "\"%s\" ଯନ୍ତ୍ରରୁ ଅସ୍ଥାୟୀ ସଞ୍ଚୟ ସ୍ଥାନ ଆଣିହେଲା ନାହିଁ."
+
+#, fuzzy
+#~ msgid "Could not get buffers from device '%s'."
+#~ msgstr "\"%s\" ଯନ୍ତ୍ରରୁ ଅସ୍ଥାୟୀ ସଞ୍ଚୟ ସ୍ଥାନ ଆଣିହେଲା ନାହିଁ."
+
+#, fuzzy
+#~ msgid "Could not get enough buffers from device '%s'."
+#~ msgstr "\"%s\" ଯନ୍ତ୍ରରୁ ପର୍ଯ୍ଯାପ୍ତ ଅସ୍ଥାୟୀ ସଞ୍ଚୟ ସ୍ଥାନ ଆଣିହେଲା ନାହିଁ."
+
+#, fuzzy
+#~ msgid "Could not read from CD."
+#~ msgstr "\"%s\" ଫାଇଲ ଲେଖିହେଲା ନାହିଁ."
+
+#, fuzzy
+#~ msgid "Disc is not an Audio CD."
+#~ msgstr "ଯନ୍ତ୍ର ଖୋଲାଯାଇ ନାହିଁ."
+
+#, fuzzy
+#~ msgid "Could not set parameters on device '%s'"
+#~ msgstr "\"%s\" ଯନ୍ତ୍ରରୁ ଅସ୍ଥାୟୀ ସଞ୍ଚୟ ସ୍ଥାନ ଆଣିହେଲା ନାହିଁ."
+
+#~ msgid "Could not open file \"%s\" for writing."
+#~ msgstr "\"%s\" ଫାଇଲ ଲେଖିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ."
+
+#~ msgid "Error closing file \"%s\"."
+#~ msgstr "\"%s\" ଫାଇଲ ବନ୍ଦ କରିବାରେ ତ୍ରୁଟି."
+
+#~ msgid "Could not open file \"%s\" for reading."
+#~ msgstr "\"%s\" ଫାଇଲ ପଢ଼ିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ."
+
+#~ msgid "No filename specified."
+#~ msgstr "କୌଣସି ଫାଇଲନାମ ଉଲ୍ଲେଖିତ ହୋଇ ନାହିଁ."
+
+#~ msgid "Could not open control device \"%s\" for writing."
+#~ msgstr "\"%s\" ନିୟନ୍ତ୍ରଣ ଯନ୍ତ୍ର ଲେଖିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ."
+
+#~ msgid "Could not configure audio device \"%s\"."
+#~ msgstr "\"%s\" ଧ୍ବନି ଯନ୍ତ୍ର ବିନ୍ଯାସ କରିହେଲା ନାହିଁ."
+
+#~ msgid "Could not set audio device \"%s\" to %d Hz."
+#~ msgstr "\"%s\" ଧ୍ବନି ଯନ୍ତ୍ରକୁ %d ହର୍ଜରେ ବିନ୍ଯାସ କରିହେଲା ନାହିଁ."
+
+#~ msgid "Could not open video device \"%s\" for writing."
+#~ msgstr "\"%s\" ଭିଡିଓ ଯନ୍ତ୍ର ଲେଖିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ."
+
+#~ msgid "Could not close video device \"%s\"."
+#~ msgstr "\"%s\" ଭିଡିଓ ଯନ୍ତ୍ର ବନ୍ଦ କରିହେଲା ନାହିଁ."
+
+#~ msgid "OSS device \"%s\" is already in use by another program."
+#~ msgstr "\"%s\" ଓ.ଏସ.ଏସ. ଯନ୍ତ୍ର ପୂର୍ବରୁ ଅନ୍ଯ କାରିକା ଦ୍ବାରା ବ୍ଯବହାର କରାଯାଉଛି."
+
+#~ msgid "Could not access device \"%s\", check its permissions."
+#~ msgstr "\"%s\" ଯନ୍ତ୍ର ବ୍ଯବହାର କରିହେଲା ନାହିଁ, ତାହାର ଅନୁମତି ଦେଖନ୍ତୁ."
+
+#~ msgid "Device \"%s\" does not exist."
+#~ msgstr "\"%s\" ଯନ୍ତ୍ର ଅବସ୍ଥିତ ନାହିଁ."
+
+#~ msgid "Could not open device \"%s\" for writing."
+#~ msgstr "\"%s\" ଯନ୍ତ୍ର ଲେଖିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ."
+
+#~ msgid "Could not open device \"%s\" for reading."
+#~ msgstr "\"%s\" ଯନ୍ତ୍ର ପଢ଼ିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ."
+
+#~ msgid "Could not open vfs file \"%s\" for reading."
+#~ msgstr "ଭି.ଏଫ.ଏସ. ଫାଇଲ \"%s\" ପଢ଼ିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ."
+
+#, fuzzy
+#~ msgid "No filename given."
+#~ msgstr "କୌଣସି ଫାଇଲନାମ ଦିଆଯାଇ ନାହିଁ"
+
+#~ msgid "Could not open vfs file \"%s\" for writing: %s."
+#~ msgstr "ଭି.ଏଫ.ଏସ. ଫାଇଲ \"%s\" ଲେଖିବା ପାଇଁ ଖୋଲିହେଲା ନାହିଁ: %s."
+
+#~ msgid "No filename given"
+#~ msgstr "କୌଣସି ଫାଇଲନାମ ଦିଆଯାଇ ନାହିଁ"
+
+#~ msgid "Could not close vfs file \"%s\"."
+#~ msgstr "ଭି.ଏଫ.ଏସ. ଫାଇଲ \"%s\" ବନ୍ଦ କରିହେଲା ନାହିଁ."
+
+#, fuzzy
+#~ msgid "Your OSS device doesn't support mono or stereo."
+#~ msgstr "ଆପଣଙ୍କର ଓ.ଏସ.ଏସ. ଯନ୍ତ୍ରର ଠିକ ଭାବରେ ଅନୁସନ୍ଧାନ କରିହେଲା ନାହିଁ."
+
+#~ msgid "No device specified."
+#~ msgstr "କୌଣସି ଯନ୍ତ୍ର ଉଲ୍ଲେଖିତ କରାଯାଇ ନାହିଁ."
+
+#~ msgid "Device is open."
+#~ msgstr "ଯନ୍ତ୍ର ଖୋଲାଯାଇଚ୍ଛି."
+
+#~ msgid ""
+#~ "The %s element could not be found. This element is essential for "
+#~ "playback. Please install the right plug-in and verify that it works by "
+#~ "running 'gst-inspect %s'"
+#~ msgstr ""
+#~ "%s ଉପାଦାନ ମିଳିଲା ନାହିଁ. ପୁନଃପ୍ରଦର୍ଶନ ପାଇଁ ଏହି ଉପାଦାନଟି ଆବଶ୍ଯକ. ଦୟା କରି ସଠିକ ପ୍ଲଗ୍ଇନ୍ "
+#~ "ସ୍ଥାପିତ କରନ୍ତୁ, ଓ 'gst-inspect %s' ଚଳାଇ ଯାଞ୍ଚ କରନ୍ତୁ କି ଏହା କାର୍ଯ୍ଯକାରୀ ଅଛି"
+
+#~ msgid ""
+#~ "No usable colorspace element could be found.\n"
+#~ "Please install one and restart."
+#~ msgstr ""
+#~ "କୌଣସି ବ୍ଯବହାରଯୋଗ୍ଯ ରଙ୍ଗକ୍ଷେତ୍ର ଉପାଦାନ ମିଳିଲା ନାହିଁ.\n"
+#~ "ଦୟା କରି ଗୋଟିଏ ଉପାଦାନ ସ୍ଥାପିତ କରି ପୁନଃପ୍ରାରମ୍ଭ କରନ୍ତୁ."
diff --git a/po/pl.po b/po/pl.po
new file mode 100644
index 0000000..7852d81
--- /dev/null
+++ b/po/pl.po
@@ -0,0 +1,430 @@
+# Polish translation for gst-plugins-good.
+# This file is distributed under the same license as the gst-plugins-good package.
+# Jakub Bogusz <qboosh@pld-linux.org>, 2007-2016.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-02-20 21:43+0100\n"
+"Last-Translator: Jakub Bogusz <qboosh@pld-linux.org>\n"
+"Language-Team: Polish <translation-team-pl@lists.sourceforge.net>\n"
+"Language: pl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Jack server not found"
+msgstr "Nie znaleziono serwera Jack"
+
+msgid "Failed to decode JPEG image"
+msgstr "Nie udało się zdekodować obrazu JPEG"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "'%s' autorstwa '%s'"
+
+msgid "Could not connect to server"
+msgstr "Nie udało się połączyć z serwerem"
+
+msgid "No URL set."
+msgstr "Nie ustawiono URL-a."
+
+msgid "Could not resolve server name."
+msgstr "Nie udało się rozwiązać nazwy serwera."
+
+msgid "Could not establish connection to server."
+msgstr "Nie udało się nawiązać połączenia z serwerem."
+
+msgid "Secure connection setup failed."
+msgstr "Ustanowienie bezpiecznego połączenia nie powiodło się."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr "Wystąpił błąd sieciowy lub serwer nieoczekiwanie zamknął połączenie."
+
+msgid "Server sent bad data."
+msgstr "Serwer przysłał błędne dane."
+
+msgid "Server does not support seeking."
+msgstr "Serwer nie obsługuje przewijania."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Brak lub niepoprawne wejście dźwięku, strumień AVI będzie uszkodzony."
+
+msgid "This file contains no playable streams."
+msgstr "Ten plik nie zawiera strumieni nadających się do odtworzenia."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Ten plik jest błędny i nie może być odtworzony."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+"Nie można odtwarzać strumienia, ponieważ jest zaszyfrowany DRM-em PlayReady."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Ten plik jest uszkodzony i nie może być odtworzony."
+
+msgid "Invalid atom size."
+msgstr "Błędny rozmiar atomu."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Ten plik jest niekompletny i nie może być odtworzony."
+
+msgid "The video in this file might not play correctly."
+msgstr "Obraz w tym pliku może nie być odtwarzany prawidłowo."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Ten plik zawiera zbyt dużo strumieni. Odtwarzanie tylko %d pierwszych"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Nie znaleziono obsługiwanego strumienia. Być może trzeba zainstalować "
+"wtyczkę rozszerzenia GStreamera RTSP dla strumieni Real media."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Nie znaleziono obsługiwanego strumienia. Być może trzeba zezwolić na więcej "
+"protokołów transportu, albo może brakować właściwej wtyczki rozszerzenia "
+"RTSP GStreamera."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Nie udało się otworzyć urządzenia dźwiękowego do odtwarzania. Urządzenie "
+"jest używane przez inną aplikację."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Nie udało się otworzyć urządzenia dźwiękowego do odtwarzania. Brak uprawnień "
+"do otwarcia urządzenia."
+
+msgid "Could not open audio device for playback."
+msgstr "Nie udało się otworzyć urządzenia dźwiękowego do odtwarzania."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Nie udało się otworzyć urządzenia dźwiękowego do odtwarzania. Ta wersja Open "
+"Sound System nie jest obsługiwana przez ten element."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Odtwarzanie nie jest obsługiwane przez to urządzenie dźwiękowe."
+
+msgid "Audio playback error."
+msgstr "Błąd odtwarzania dźwięku."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Nagrywanie nie jest obsługiwane przez to urządzenie dźwiękowe."
+
+msgid "Error recording from audio device."
+msgstr "Błąd nagrywania z urządzenia dźwiękowego."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Nie udało się otworzyć urządzenia dźwiękowego do nagrywania. Brak uprawnień "
+"do otwarcia urządzenia."
+
+msgid "Could not open audio device for recording."
+msgstr "Nie udało się otworzyć urządzenia dźwiękowego do nagrywania."
+
+msgid "CoreAudio device not found"
+msgstr "Nie znaleziono urządzenia CoreAudio"
+
+msgid "CoreAudio device could not be opened"
+msgstr "Nie udało się otworzyć urządzenia CoreAudio"
+
+msgid "Record Source"
+msgstr "Źródło nagrywania"
+
+msgid "Microphone"
+msgstr "Mikrofon"
+
+msgid "Line In"
+msgstr "Wejście linii"
+
+msgid "Internal CD"
+msgstr "Wewnętrzny CD"
+
+msgid "SPDIF In"
+msgstr "Wejście SPDIF"
+
+msgid "AUX 1 In"
+msgstr "Wejście AUX 1"
+
+msgid "AUX 2 In"
+msgstr "Wejście AUX 2"
+
+msgid "Codec Loopback"
+msgstr "Pętla zwrotna kodeka"
+
+msgid "SunVTS Loopback"
+msgstr "Pętla zwrotna SunVTS"
+
+msgid "Volume"
+msgstr "Głośność"
+
+msgid "Gain"
+msgstr "Wzmocnienie"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "Wbudowany głośniczek"
+
+msgid "Headphone"
+msgstr "Słuchawki"
+
+msgid "Line Out"
+msgstr "Wyjście linii"
+
+msgid "SPDIF Out"
+msgstr "Wyjście SPDIF"
+
+msgid "AUX 1 Out"
+msgstr "Wyjście AUX 1"
+
+msgid "AUX 2 Out"
+msgstr "Wyjście AUX 2"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Błąd odczytu %d bajtów z urządzenia '%s'."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Nie udało się wyliczyć dostępnych formatów obrazu, z którymi może działać "
+"urządzenie '%s'"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Nie udało się odwzorować buforów z urządzenia '%s'"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Sterownik urządzenia '%s' nie obsługuje metody we/wy %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Sterownik urządzenia '%s' nie obsługuje żadnej znanej metody we/wy."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Urządzenie '%s' jest zajęte"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Urządzenie '%s' nie potrafi przechwytywać obrazu %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Urządzenie '%s' nie potrafi przechwytywać obrazu w podanym formacie"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Urządzenie '%s' obsługuje nieciągłe powierzchnie"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Nie udało się uzyskać parametrów urządzenia '%s'"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+"Urządzenie obrazu nie przyjęło nowego ustawienia częstotliwości klatek."
+
+msgid "Video device did not provide output format."
+msgstr "Urządzenie obrazu nie przekazało formatu wyjściowego."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Urządzenie obrazu zwróciło błędne wymiary."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Urzędzenie obrazu wykorzystuje nie obsługiwany sposób przeplotu."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Urządzenie obrazu wykorzystuje nie obsługiwany format piksela."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Nie udało się skonfigurować wewnętrznej puli buforów."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Urzędzenie obrazu nie zasugerowało żadnego rozmiaru bufora."
+
+msgid "No downstream pool to import from."
+msgstr "Brak oddolnej puli do zaimportowania."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Nie udało się uzyskać ustawień tunera %d urządzenia '%s'."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Błąd podczas pobierania możliwości uządzenia '%s'."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Urządzenie '%s' nie jest tunerem."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Nie udało się uzyskać wejścia radiowego z urządzenia '%s'. "
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Nie udało się ustawić wejścia %d urządzenia %s."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Nie udało się zmienić stanu wyciszenia dla urządzenia '%s'."
+
+msgid "Failed to allocated required memory."
+msgstr "Nie udało się przydzielić wymaganej pamięci."
+
+msgid "Failed to allocate required memory."
+msgstr "Nie udało się przydzielić wymaganej pamięci."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Konwerter urządzenia %s nie ma obsługiwanego formatu wejściowego"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Konwerter urządzenia %s nie ma obsługiwanego formatu wyjściowego"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Koder urządzenia %s nie ma obsługiwanego formatu wejściowego"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Koder urządzenia %s nie ma obsługiwanego formatu wyjściowego"
+
+msgid "Failed to start decoding thread."
+msgstr "Nie udało się uruchomić wątku dekodującego."
+
+msgid "Failed to process frame."
+msgstr "Nie udało się przetworzyć ramki."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Błąd pobierania możliwości urządzenia '%s': to nie jest sterownik v4l2. "
+"Proszę sprawdzić czy to sterownik v4l1."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Nie udało się odpytać o atrybuty wejścia %d urządzenia %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Nie udało się uzyskać ustawień tunera %d urządzenia '%s'."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Nie udało się odpytać normalizacji urządzenia '%s'."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Nie udało się uzyskać atrybutów sterujących urządzenia '%s'."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Nie można zidentyfikować urządzenia '%s'."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "To nie jest urządzenie '%s'."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Nie udało się otworzyć urządzenia '%s' do odczytu i zapisu."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Urządzenie '%s' nie jest urządzeniem przechwytującym."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Urządzenie '%s' nie jest urządzeniem wyjściowym."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Urządzenie '%s' nie jest urządzeniem M2M."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Nie udało się wykonać dup urządzenia '%s' do odczytu i zapisu."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Nie udało się ustawić normalizacji dla urządzenia '%s'."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+"Nie udało się uzyskać aktualnej częstotliwości tunera dla urządzenia '%s'."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Nie udało się ustawić aktualnej częstotliwości tunera dla urządzenia '%s' na "
+"%lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Nie udało się uzyskać siły sygnału dla urządzenia '%s'."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Nie udało się uzyskać wartości sterującej %d urządzenia '%s'."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Nie udało się ustawić %d jako wartości sterującej %d urządzenia '%s'."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Nie udało się uzyskać aktualnego wejścia urządzenia '%s'. Może to radio"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Nie udało się uzyskać aktualnego wyjścia urządzenia '%s'. Może to radio"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Nie udało się ustawić wyjścia %d urządzenia %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Zmiana rozdzielczości w czasie działania nie jest jeszcze obsługiwana."
+
+msgid "Cannot operate without a clock"
+msgstr "Nie można pracować bez zegara"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Błąd wewnętrzny strumienia danych."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Błąd wewnętrzny przepływu danych."
diff --git a/po/pt_BR.po b/po/pt_BR.po
new file mode 100644
index 0000000..40a5cd7
--- /dev/null
+++ b/po/pt_BR.po
@@ -0,0 +1,801 @@
+# Brazilian Portuguese translation of gst-plugins-good.
+# This file is distributed under the same license as the gst-plugins-good package.
+# Copyright (C) 2008-2016 Free Software Foundation, Inc.
+# Fabrício Godoy <skarllot@gmail.com>, 2008-2016.
+#
+# data flow -> fluxo de dados
+# streaming -> fluxo contínuo
+# clock -> temporizador
+# plane (overlay plane) -> plano de sobreposição
+# pool -> coleção, conjunto, agrupamento
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good-1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-05-06 17:49-0300\n"
+"Last-Translator: Fabrício Godoy <skarllot@gmail.com>\n"
+"Language-Team: Brazilian Portuguese <ldpbr-translation@lists.sourceforge."
+"net>\n"
+"Language: pt_BR\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+msgid "Jack server not found"
+msgstr "Servidor Jack não encontrado"
+
+msgid "Failed to decode JPEG image"
+msgstr "Falha ao decodificar a imagem JPEG"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "\"%s\" por \"%s\""
+
+msgid "Could not connect to server"
+msgstr "Não foi possível conectar ao servidor"
+
+msgid "No URL set."
+msgstr "Nenhum URL definido."
+
+msgid "Could not resolve server name."
+msgstr "Não foi possível resolver o nome do servidor."
+
+msgid "Could not establish connection to server."
+msgstr "Não foi possível estabelecer uma conexão com servidor."
+
+msgid "Secure connection setup failed."
+msgstr "Configuração de conexão segura falhou."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Um erro de rede ocorreu, ou o servidor fechou a conexão inesperadamente."
+
+msgid "Server sent bad data."
+msgstr "O servidor enviou dados ruins."
+
+msgid "Server does not support seeking."
+msgstr "Nâo há suporte a busca pelo servidor."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Entrada de áudio nula ou inválida, o fluxo AVI pode estar corrompido."
+
+msgid "This file contains no playable streams."
+msgstr "Este arquivo não contêm fluxos reproduzíveis."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Este arquivo é inválido e não pôde ser reproduzido."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+"Não foi possível reproduzir o fluxo por estar criptografado com PlayReady "
+"DRM."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Este arquivo está corrompido e não pôde ser reproduzido."
+
+msgid "Invalid atom size."
+msgstr "Tamanho de Atom inválido."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Este arquivo está incompleto e não pôde ser reproduzido."
+
+msgid "The video in this file might not play correctly."
+msgstr "O vídeo neste arquivo pode não ser reproduzido corretamente."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Este arquivo contêm muitos fluxos. Apenas reproduzindo o primeiro %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Nenhum fluxo com suporte foi localizado. Você pode precisar instalar um plug-"
+"in de extensão GStreamer RTSP para fluxos Real media."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Nenhum fluxo com suporte foi localizado. Talvez haja necessidade de que mais "
+"protocolos de transporte sejam permitidos ou senão o plug-in de extensão "
+"GStreamer RTSP pode estar incorreto."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Não foi possível abrir o dispositivo de áudio para reprodução. O dispositivo "
+"está sendo usado por outro aplicativo."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Não foi possível abrir o dispositivo de áudio para reprodução. Você não tem "
+"permissão para abrir o dispositivo."
+
+msgid "Could not open audio device for playback."
+msgstr "Não foi possível abrir o dispositivo de áudio para reprodução."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Não foi possível abrir o dispositivo de áudio para reprodução. Não há "
+"suporte a este elemento nesta versão do Sistema Aberto de Som (OSS)."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Não há suporte a reprodução por este dispositivo de áudio."
+
+msgid "Audio playback error."
+msgstr "Erro de reprodução de áudio."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Não há suporte a gravação por este dispositivo de áudio."
+
+msgid "Error recording from audio device."
+msgstr "Erro ao gravar do dispositivo de áudio."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Não foi possível abrir o dispositivo de áudio para gravação. Você não tem "
+"permissão para abrir o dispositivo."
+
+msgid "Could not open audio device for recording."
+msgstr "Não foi possível abrir o dispositivo de áudio para gravação."
+
+msgid "CoreAudio device not found"
+msgstr "Dispositivo CoreAudio não encontrado"
+
+msgid "CoreAudio device could not be opened"
+msgstr "Dispositivo CoreAudio não pôde ser aberto"
+
+msgid "Record Source"
+msgstr "Origem de gravação"
+
+msgid "Microphone"
+msgstr "Microfone"
+
+msgid "Line In"
+msgstr "Entrada de linha"
+
+msgid "Internal CD"
+msgstr "CD interno"
+
+msgid "SPDIF In"
+msgstr "Entrada SPDIF"
+
+msgid "AUX 1 In"
+msgstr "Entrada aux. 1"
+
+msgid "AUX 2 In"
+msgstr "Entrada aux. 2"
+
+msgid "Codec Loopback"
+msgstr "CODEC Loopback"
+
+msgid "SunVTS Loopback"
+msgstr "SunVTS Loopback"
+
+msgid "Volume"
+msgstr "Volume"
+
+msgid "Gain"
+msgstr "Ganho"
+
+msgid "Monitor"
+msgstr "Monitorador"
+
+msgid "Built-in Speaker"
+msgstr "Alto-falante interno"
+
+msgid "Headphone"
+msgstr "Fone de ouvido"
+
+msgid "Line Out"
+msgstr "Saída de linha"
+
+msgid "SPDIF Out"
+msgstr "Saída SPDIF"
+
+msgid "AUX 1 Out"
+msgstr "Saída aux. 1"
+
+msgid "AUX 2 Out"
+msgstr "Saída aux. 2"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Erro ao ler %d bytes do dispositivo \"%s\"."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Falha ao relacionar os formatos de vídeo que o dispositivo \"%s\" oferece "
+"suporte"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Não foi possível mapear buffers do dispositivo \"%s\""
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "O driver do dispositivo \"%s\" não tem suporte ao método %d de E/S"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"O driver do dispositivo \"%s\" não tem suporte a nenhum método conhecido de "
+"E/S."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "O dispositivo \"%s\" está ocupado"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "O dispositivo \"%s\" não realiza captura a %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "O dispositivo \"%s\" não realiza captura no formato especificado"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr ""
+"O dispositivo \"%s\" não tem suporte a planos de sobreposição não-contínuos"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Não foi possível obter os parâmetros no dispositivo \"%s\""
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "O dispositivo de vídeo não aceita definir uma nova taxa de quadros."
+
+msgid "Video device did not provide output format."
+msgstr "O dispositivo de vídeo não forneceu um formato de saída."
+
+msgid "Video device returned invalid dimensions."
+msgstr "O dispositivo de vídeo retornou dimensões inválidas."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+"Os dispositivos de vídeo utilizam um método de entrelaçamento não suportado."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Os dispositivos de vídeo utilizam um formato para pixel não suportado."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Falha ao configurar uma coleção de buffer interno."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "O dispositivo de vídeo não sugeriu nenhum tamanho de buffer."
+
+msgid "No downstream pool to import from."
+msgstr "Nenhuma coleção de fluxo de recebimento para importar."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Falha ao obter configurações do sintonizador %d no dispositivo \"%s\"."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Erro ao obter funcionalidades do dispositivo \"%s\"."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "O dispositivo \"%s\" não é um sintonizador."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Falha ao obter a entrada de rádio do dispositivo \"%s\"."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Falha ao definir a entrada %d no dispositivo %s."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Falha ao alternar entre com e sem áudio para o dispositivo \"%s\"."
+
+msgid "Failed to allocated required memory."
+msgstr "Falha ao alocar a memória necessária."
+
+msgid "Failed to allocate required memory."
+msgstr "Falha ao alocar a memória necessária."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+"O conversor no dispositivo %s não tem um formato de entrada com suporte"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "O conversor no dispositivo %s não tem um formato de saída com suporte"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+"O codificador no dispositivo %s não tem um formato de entrada com suporte"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+"O codificador no dispositivo %s não tem um formato de saída com suporte"
+
+msgid "Failed to start decoding thread."
+msgstr "Falha ao iniciar o segmento de decodificação."
+
+msgid "Failed to process frame."
+msgstr "Falha ao processar quadro."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Erro ao obter recursos do dispositivo \"%s\": Ele não é um driver v4l2. "
+"Verifique se ele é um driver v4l1."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Falha ao examinar os atributos da entrada %d no dispositivo %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Falha ao obter configurações do sintonizador %d no dispositivo \"%s\"."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Falha ao examinar as normas no dispositivo \"%s\"."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Falha ao obter atributos de controle no dispositivo \"%s\"."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "O dispositivo \"%s\" não pôde ser identificado."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "\"%s\" não é um dispositivo."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Não foi possível abrir o dispositivo \"%s\" para leitura e gravação."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "O dispositivo \"%s\" não é um dispositivo de captura."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "O dispositivo \"%s\" não é um dispositivo de saída."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "O dispositivo \"%s\" não é um dispositivo M2M."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr ""
+"Não foi possível duplicar o dispositivo \"%s\" para leitura e gravação."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Falha ao definir as normas para o dispositivo \"%s\"."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Falha ao obter a freqüência do sintonizador para o dispositivo \"%s\"."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Falha ao definir a freqüência do sintonizador para o dispositivo \"%s\" à "
+"%lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Falha ao obter a força do sinal para o dispositivo \"%s\"."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Falha ao obter o valor para o controle %d no dispositivo \"%s\"."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Falha ao definir o valor %d para o controle %d no dispositivo \"%s\"."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Falha ao obter a entrada atual no dispositivo \"%s\". Talvez seja um "
+"dispositivo de rádio"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Falha ao obter a saída atual no dispositivo \"%s\". Talvez seja um "
+"dispositivo de rádio"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Falha ao definir a saída %d no dispositivo %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Ainda não há suporte a mudança de resolução enquanto está executando."
+
+msgid "Cannot operate without a clock"
+msgstr "Não é possível operar sem um temporizador"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Erro interno no fluxo de dados."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Erro interno no fluxo de dados."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "O dispositivo \"%s\" não tem suporte a captura de vídeo"
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Não foi possível estabelecer uma conexão com servidor de som"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Falha ao examinar os recursos do servidor de som"
+
+#~ msgid "Bass"
+#~ msgstr "Grave"
+
+#~ msgid "Treble"
+#~ msgstr "Agudo"
+
+#~ msgid "Synth"
+#~ msgstr "Sintetizador"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Alto-falante"
+
+#~ msgid "Line-in"
+#~ msgstr "Entrada de linha"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Mixer"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Gravação"
+
+#~ msgid "In-gain"
+#~ msgstr "Ganho de entrada"
+
+#~ msgid "Out-gain"
+#~ msgstr "Ganho de saída"
+
+#~ msgid "Line-1"
+#~ msgstr "Linha 1"
+
+#~ msgid "Line-2"
+#~ msgstr "Linha 2"
+
+#~ msgid "Line-3"
+#~ msgstr "Linha 3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Digital 1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Digital 2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Digital 3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Entrada de fone"
+
+#~ msgid "Phone-out"
+#~ msgstr "Saída de fone"
+
+#~ msgid "Video"
+#~ msgstr "Vídeo"
+
+#~ msgid "Radio"
+#~ msgstr "Rádio"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr ""
+#~ "Não foi possível abrir o dispositivo de áudio para manipulação do "
+#~ "controlador do mixer."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Não foi possível abrir o dispositivo de áudio para manipulação do "
+#~ "controlador do mixer. Não há suporte a este elemento com esta versão do "
+#~ "Sistema Aberto de Som (OSS)."
+
+#~ msgid "Master"
+#~ msgstr "Principal"
+
+#~ msgid "Front"
+#~ msgstr "Frontal"
+
+#~ msgid "Rear"
+#~ msgstr "Traseira"
+
+#~ msgid "Headphones"
+#~ msgstr "Fones de ouvido"
+
+#~ msgid "Center"
+#~ msgstr "Central"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Surround"
+
+#~ msgid "Side"
+#~ msgstr "Lateral"
+
+#~ msgid "AUX Out"
+#~ msgstr "Saída aux."
+
+#~ msgid "3D Depth"
+#~ msgstr "Profundidade 3D"
+
+#~ msgid "3D Center"
+#~ msgstr "3D central"
+
+#~ msgid "3D Enhance"
+#~ msgstr "Realce 3D"
+
+#~ msgid "Telephone"
+#~ msgstr "Telefone"
+
+#~ msgid "Video In"
+#~ msgstr "Entrada de vídeo"
+
+#~ msgid "AUX In"
+#~ msgstr "Entrada aux."
+
+#~ msgid "Record Gain"
+#~ msgstr "Ganho de gravação"
+
+#~ msgid "Output Gain"
+#~ msgstr "Ganho de saída"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Aumento do microfone"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Diagnóstico"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Aumento de graves"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Portas de reprodução"
+
+#~ msgid "Input"
+#~ msgstr "Entrada"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Origem de monitoração"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Bip do teclado"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Simular estéreo"
+
+#~ msgid "Stereo"
+#~ msgstr "Estéreo"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Som surround"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Ganho do microfone"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Origem do alto-falante"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Origem do microfone"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Central/LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Mixagem estéreo"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Mixagem mono"
+
+#~ msgid "Input Mix"
+#~ msgstr "Mixagem de entrada"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Microfone 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Microfone 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Saída digital"
+
+#~ msgid "Digital In"
+#~ msgstr "Entrada digital"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modem"
+
+#~ msgid "Handset"
+#~ msgstr "Monofone"
+
+#~ msgid "Other"
+#~ msgstr "Outro"
+
+#~ msgid "None"
+#~ msgstr "Nenhum"
+
+#~ msgid "On"
+#~ msgstr "Ligado"
+
+#~ msgid "Off"
+#~ msgstr "Desligado"
+
+#~ msgid "Mute"
+#~ msgstr "Mudo"
+
+#~ msgid "Fast"
+#~ msgstr "Rápido"
+
+#~ msgid "Very Low"
+#~ msgstr "Muito baixa"
+
+#~ msgid "Low"
+#~ msgstr "Baixa"
+
+#~ msgid "Medium"
+#~ msgstr "Média"
+
+#~ msgid "High"
+#~ msgstr "Alta"
+
+#~ msgid "Very High"
+#~ msgstr "Muito alta"
+
+#~ msgid "Production"
+#~ msgstr "Produção"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Microfone do painel frontal"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Entrada de linha do painel frontal"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Fones de ouvido do painel frontal"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Saída de linha do painel frontal"
+
+#~ msgid "Green Connector"
+#~ msgstr "Conector verde"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Conector rosa"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Conector azul"
+
+#~ msgid "White Connector"
+#~ msgstr "Conector branco"
+
+#~ msgid "Black Connector"
+#~ msgstr "Conector preto"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Conector cinza"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Conector laranja"
+
+#~ msgid "Red Connector"
+#~ msgstr "Conector vermelho"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Conector amarelo"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Conector verde do painel frontal"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Conector rosa do painel frontal"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Conector azul do painel frontal"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Conector branco do painel frontal"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Conector preto do painel frontal"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Conector cinza do painel frontal"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Conector laranja do painel frontal"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Conector vermelho do painel frontal"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Conector amarelo do painel frontal"
+
+#~ msgid "Spread Output"
+#~ msgstr "Saída comum"
+
+#~ msgid "Downmix"
+#~ msgstr "Mesclar canais"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Entrada do mixer virtual"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Saída do mixer virtual"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Canais do mixer virtual"
+
+#~ msgid "%s %d Function"
+#~ msgstr "%s %d"
+
+#~ msgid "%s Function"
+#~ msgstr "%s"
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Foi obtido um tamanho de quadro inesperado de %u, ao invés de %u."
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Erro ao ler %d bytes no dispositivo \"%s\"."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Não possível adicionar buffers à fila no dispositivo \"%s\"."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Falha ao tentar obter os quadros de vídeo do dispositivo \"%s\"."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Falha após %d tentativas. Dispositivo %s. Erro do sistema: %s"
diff --git a/po/ro.po b/po/ro.po
new file mode 100644
index 0000000..d4cf7d2
--- /dev/null
+++ b/po/ro.po
@@ -0,0 +1,811 @@
+# Romanian translation for gst-plugins-good
+# This file is distributed under the same license as the gst-plugins-good package.
+# Lucian Adrian Grijincu <lucian.grijincu@gmail.com>, 2010.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 0.10.23.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2010-08-16 03:22+0300\n"
+"Last-Translator: Lucian Adrian Grijincu <lucian.grijincu@gmail.com>\n"
+"Language-Team: Romanian <translation-team-ro@lists.sourceforge.net>\n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < "
+"20)) ? 1 : 2);;\n"
+"X-Generator: Virtaal 0.6.1\n"
+"X-Launchpad-Export-Date: 2010-08-16 00:08+0000\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr "Nu s-a putut decoda imaginea JPEG"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "„%s” de „%s”"
+
+msgid "Could not connect to server"
+msgstr "Nu se poate stabili o conexiune la server"
+
+msgid "No URL set."
+msgstr ""
+
+#, fuzzy
+msgid "Could not resolve server name."
+msgstr "Nu se poate stabili o conexiune la server"
+
+#, fuzzy
+msgid "Could not establish connection to server."
+msgstr "Nu se poate stabili o conexiune la serverul de sunet"
+
+msgid "Secure connection setup failed."
+msgstr ""
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+
+msgid "Server sent bad data."
+msgstr ""
+
+msgid "Server does not support seeking."
+msgstr ""
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr ""
+"Intrarea audio nu există sau este nevalidă, fluxul de date AVI va fi corupt."
+
+msgid "This file contains no playable streams."
+msgstr "Acest fișier nu conține fluxuri ce pot fi redate."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Fișierul nu este valid și nu poate fi redat."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Acest fișier este corupt și nu poate fi redat."
+
+msgid "Invalid atom size."
+msgstr ""
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Acest fișier nu este complet și nu poate fi redat."
+
+msgid "The video in this file might not play correctly."
+msgstr "Este posibil ca fișierul video să nu fie redat corect."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Fișierul conține prea multe fluxuri. Se redau doar primele %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Nu s-a găsit nici un flux suportat. Pentru fluxuri Real media s-ar putea să "
+"fie nevoie să instalați extensia GStreamer RTSP."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Nu a fost găsit niciun flux suportat. S-ar putea să necesite permiterea mai "
+"multor protocoale de transport sau de altfel s-ar putea să lipsească modulul "
+"corect de extensie GStreamer RTSP."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Nu s-a putut deschide dispozitivul audio pentru redare. Dispozitivul este "
+"folosit de o altă aplicație."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Nu s-a putut deschide dispozitivul audio pentru redare. Nu aveți permisiunea "
+"de a deschide dispozitivul."
+
+msgid "Could not open audio device for playback."
+msgstr "Nu s-a putut deschide dispozitivul audio pentru redare."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Nu s-a putut deschide dispozitivul audio pentru redare. Versiunea aceasta a "
+"OSS (Open Sound System) nu este suportată de acest element."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Redarea nu este suportată de acest dispozitiv audio."
+
+msgid "Audio playback error."
+msgstr "Eroare redare audio."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Înregistrarea nu este suportată de acest dispozitiv audio."
+
+msgid "Error recording from audio device."
+msgstr "Eroare la înregistrarea de la dispozitivul audio."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Nu s-a putut deschide dispozitivul audio pentru înregistrare Nu aveți "
+"permisiunea de a deschide dispozitivul."
+
+msgid "Could not open audio device for recording."
+msgstr "Nu s-a putut deschide dispozitivul audio pentru înregistrare."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "Sursă înregistrare"
+
+msgid "Microphone"
+msgstr "Microfon"
+
+msgid "Line In"
+msgstr "Linie intrare"
+
+msgid "Internal CD"
+msgstr "CD intern"
+
+msgid "SPDIF In"
+msgstr "Intrare SPDIF"
+
+msgid "AUX 1 In"
+msgstr "Intrare AUX 1"
+
+msgid "AUX 2 In"
+msgstr "Intrare AUX 2"
+
+#, fuzzy
+msgid "Codec Loopback"
+msgstr "Buclă"
+
+#, fuzzy
+msgid "SunVTS Loopback"
+msgstr "Buclă"
+
+msgid "Volume"
+msgstr "Volum"
+
+msgid "Gain"
+msgstr "Amplificare"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "Boxe integrate"
+
+msgid "Headphone"
+msgstr "Căști"
+
+msgid "Line Out"
+msgstr "Linie ieșire"
+
+msgid "SPDIF Out"
+msgstr "Ieșire SPDIF"
+
+msgid "AUX 1 Out"
+msgstr "Ieșire AUX 1"
+
+msgid "AUX 2 Out"
+msgstr "Ieșire AUX 2"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Eroare citire %d octeți de la dispozitivul „%s”."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Nu s-a putut mapa memoria tampon din dispozitivul „%s”"
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr ""
+"Driverul pentru dispozitivul „%s” nu suport nici o metodă de captură "
+"cunoscută."
+
+#, fuzzy, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"Driverul pentru dispozitivul „%s” nu suport nici o metodă de captură "
+"cunoscută."
+
+#, fuzzy, c-format
+msgid "Device '%s' is busy"
+msgstr "Dispozitivul „%s” nu este un dispozitiv de ieșire."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Dispozitivul „%s” nu este un dispozitiv de captură."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Dispozitivul „%s” nu este un dispozitiv de captură."
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Dispozitivul „%s” nu este un dispozitiv de ieșire."
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Nu s-au putut obține parametrii pentru dispozitivul „%s”"
+
+#, fuzzy
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+"Dispozitivul de intrare video nu a acceptat noua configurare de rate cadre."
+
+#, fuzzy
+msgid "Video device did not provide output format."
+msgstr ""
+"Dispozitivul de intrare video nu a acceptat noua configurare de rate cadre."
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+"Driverul pentru dispozitivul „%s” nu suport nici o metodă de captură "
+"cunoscută."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr ""
+"Driverul pentru dispozitivul „%s” nu suport nici o metodă de captură "
+"cunoscută."
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+#, fuzzy
+msgid "Video device did not suggest any buffer size."
+msgstr ""
+"Dispozitivul de intrare video nu a acceptat noua configurare de rate cadre."
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr ""
+"A eșuat obținerea configurării receptorului %d pentru dispozitivul „%s”."
+
+#, fuzzy, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Eroare citire %d octeți de la dispozitivul „%s”."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Dispozitivul „%s” nu este un dispozitiv de ieșire."
+
+#, fuzzy, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Definirea valorii %d pentru dispozitivul „%s” a eșuat."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Definirea valorii %d pentru dispozitivul „%s” a eșuat."
+
+#, fuzzy, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Obținerea nivelului semnalului pentru dispozitivul „%s” a eșuat."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+"Driverul pentru dispozitivul „%s” nu suport nici o metodă de captură "
+"cunoscută."
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+"Dispozitivul de intrare video nu a acceptat noua configurare de rate cadre."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+"Dispozitivul de intrare video nu a acceptat noua configurare de rate cadre."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+"Dispozitivul de intrare video nu a acceptat noua configurare de rate cadre."
+
+#, fuzzy
+msgid "Failed to start decoding thread."
+msgstr "Nu s-a putut decoda imaginea JPEG"
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Eroare la obținerea capabilităților pentru dispozitivul „%s”: Nu este un "
+"driver v4l2. Verificați dacă este un driver v4l1."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Interogarea atributelor de intrare %d pentru dispozitivul %s a eșuat"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr ""
+"A eșuat obținerea configurării receptorului %d pentru dispozitivul „%s”."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Interogarea normei pentru dispozitivul „%s” a eșuat."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Obținerea atributelor de control pentru dispozitivul „%s” a eșuat."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Dispozitivul „%s” nu poate fi identificat."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Acesta nu este un dispozitiv „%s”."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Nu se poate deschide dispozitivul „%s” pentru citire și scriere."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Dispozitivul „%s” nu este un dispozitiv de captură."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Dispozitivul „%s” nu este un dispozitiv de ieșire."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Dispozitivul „%s” nu este un dispozitiv de ieșire."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Nu se poate deschide dispozitivul „%s” pentru citire și scriere."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Definirea normei pentru dispozitivul „%s” a eșuat."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+"Obținerea frecvenței curent a receptorului pentru dispozitivul „%s” a eșuat."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Definirea frecvenței curent a receptorului pentru dispozitivul „%s” la %lu "
+"Hz a eșuat."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Obținerea nivelului semnalului pentru dispozitivul „%s” a eșuat."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Obținerea valorii %d pentru dispozitivul „%s” a eșuat."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Definirii valorii %d pentru controlul %d al dispozitivul „%s” a eșuat."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Obținerea intrări curente pentru dispozitivul „%s” a eșuat. Posibil să fie "
+"un dispozitiv radio."
+
+#, fuzzy, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Obținerea intrări curente pentru dispozitivul „%s” a eșuat. Posibil să fie "
+"un dispozitiv radio."
+
+#, fuzzy, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Definirea valorii %d pentru dispozitivul „%s” a eșuat."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Schimbarea rezoluției pe durata rulării nu este incă suportată."
+
+msgid "Cannot operate without a clock"
+msgstr "Nu se poate opera fără un ceas"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Eroare internă a fluxului de date."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Eroare internă a fluxului de date."
+
+#, fuzzy
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Dispozitivul „%s” nu este un dispozitiv de ieșire."
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "S-a obținut o dimensiune neașteptată pentru cadru, %u în loc de %u."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Obținerea cadrelor video pentru dispozitivul „%s” a eșuat."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "A eșuat după %d încercări. dispozitiv %s. eroare sistem: %s"
+
+#~ msgid "Bass"
+#~ msgstr "Bas"
+
+#~ msgid "Treble"
+#~ msgstr "Înalte"
+
+#~ msgid "Synth"
+#~ msgstr "Synth"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Difuzor"
+
+#~ msgid "Line-in"
+#~ msgstr "Linie intrare"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Mixer"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Înregistrare"
+
+#~ msgid "In-gain"
+#~ msgstr "Câștig intrare"
+
+#~ msgid "Out-gain"
+#~ msgstr "Câștig ieșire"
+
+#~ msgid "Line-1"
+#~ msgstr "Linia-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Linia-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Linia-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Digital-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Digital-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Digital-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Intrare telefon"
+
+#~ msgid "Phone-out"
+#~ msgstr "Ieșire telefon"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Radio"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr ""
+#~ "Nu s-a putut deschide dispozitivul audio pentru gestionarea controlului "
+#~ "de mixaj."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Nu s-a putut deschide dispozitivul audio pentru gestionarea controlului "
+#~ "de mixaj. Această versiune a OSS (Open Sound System) nu este suportată de "
+#~ "acest element"
+
+#~ msgid "Master"
+#~ msgstr "Principal"
+
+#~ msgid "Front"
+#~ msgstr "Față"
+
+#~ msgid "Rear"
+#~ msgstr "Spate"
+
+#~ msgid "Headphones"
+#~ msgstr "Căști"
+
+#~ msgid "Center"
+#~ msgstr "Centru"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Surround"
+
+#~ msgid "Side"
+#~ msgstr "Lateral"
+
+#~ msgid "AUX Out"
+#~ msgstr "Ieșire AUX"
+
+#~ msgid "3D Depth"
+#~ msgstr "Adâncime 3D"
+
+#~ msgid "3D Center"
+#~ msgstr "Centru 3D"
+
+#~ msgid "3D Enhance"
+#~ msgstr "Îmbunătățire 3D"
+
+#~ msgid "Telephone"
+#~ msgstr "Telefon"
+
+#~ msgid "Video In"
+#~ msgstr "Intrare video"
+
+#~ msgid "AUX In"
+#~ msgstr "Intrare AUX"
+
+#~ msgid "Record Gain"
+#~ msgstr "Câștig înregistrare"
+
+#~ msgid "Output Gain"
+#~ msgstr "Câștig ieșire"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Amplificare microfon"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Diagnostic"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Amplificare bas"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Porturi redare"
+
+#~ msgid "Input"
+#~ msgstr "Intrare"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Sursă monitor"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Bip tastatură"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Simulează stereo"
+
+#~ msgid "Stereo"
+#~ msgstr "Stereo"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Sunet surround"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Câștig microfon"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Sursă difuzor"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Sursă microfon"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Centru / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Stereo Mix"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Mono Mix"
+
+#~ msgid "Input Mix"
+#~ msgstr "Mix intrare"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Microfon 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Microfon 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Ieșire digitală"
+
+#~ msgid "Digital In"
+#~ msgstr "Intrare digitală"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modem"
+
+#~ msgid "Handset"
+#~ msgstr "Căști"
+
+#~ msgid "Other"
+#~ msgstr "Altul"
+
+#~ msgid "None"
+#~ msgstr "Niciunul"
+
+#~ msgid "On"
+#~ msgstr "Activat"
+
+#~ msgid "Off"
+#~ msgstr "Dezactivat"
+
+#~ msgid "Mute"
+#~ msgstr "Mut"
+
+#~ msgid "Fast"
+#~ msgstr "Rapid"
+
+#~ msgid "Very Low"
+#~ msgstr "Foarte scăzută"
+
+#~ msgid "Low"
+#~ msgstr "Scăzută"
+
+#~ msgid "Medium"
+#~ msgstr "Medie"
+
+#~ msgid "High"
+#~ msgstr "Ridicată"
+
+#~ msgid "Very High"
+#~ msgstr "Foarte ridicată"
+
+#~ msgid "Production"
+#~ msgstr "Producție"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Microfon panou frontal"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Linie intrare panou frontal"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Căști panou frontal"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Linie ieșire panou frontal"
+
+#~ msgid "Green Connector"
+#~ msgstr "Conector verde"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Conector roz"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Conector albastru"
+
+#~ msgid "White Connector"
+#~ msgstr "Conector alb"
+
+#~ msgid "Black Connector"
+#~ msgstr "Conector negru"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Conector gri"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Conector portocaliu"
+
+#~ msgid "Red Connector"
+#~ msgstr "Conector roșu"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Conector galben"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Conector verde panou frontal"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Conector roz panou frontal"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Conector albastru panou frontal"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Conector alb panou frontal"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Conector negru panou frontal"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Conector gri panou frontal"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Conector portocaliu panou frontal"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Conector roșu panou frontal"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Conector galben panou frontal"
+
+#~ msgid "Spread Output"
+#~ msgstr "Împarte ieșirea"
+
+#~ msgid "Downmix"
+#~ msgstr "Mixaj redus"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Intrare mixer video"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Ieșire mixer video"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Canale mixer video"
+
+#~ msgid "%s %d Function"
+#~ msgstr "Funcție %s %d"
+
+#~ msgid "%s Function"
+#~ msgstr "Funcție %s"
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Eroare citire %d octeți pe dispozitivul „%s”."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Nu s-a putut programa memoria tampon în dispozitivul „%s”."
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Nu se poate stabili o conexiune la serverul de sunet"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Interogarea capabilităților serverului de sunet a eșuat"
diff --git a/po/ru.po b/po/ru.po
new file mode 100644
index 0000000..f3e8669
--- /dev/null
+++ b/po/ru.po
@@ -0,0 +1,847 @@
+# Translation for gst-plugins-good messages to Russian
+# This file is put in the public domain.
+#
+# Артём Попов <artfwo@gmail.com>, 2009.
+# Pavel Maryanov <acid_jack@ukr.net>, 2009.
+# Yuri Kozlov <yuray@komyakino.ru>, 2011, 2012, 2013, 2014, 2015, 2016.
+# Pavel Maryanov <acid@jack.kiev.ua>, 2013.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-02-21 09:55+0300\n"
+"Last-Translator: Yuri Kozlov <yuray@komyakino.ru>\n"
+"Language-Team: Russian <gnu@d07.ru>\n"
+"Language: ru\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Lokalize 1.5\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+
+msgid "Jack server not found"
+msgstr "Сервер Jack не найден"
+
+msgid "Failed to decode JPEG image"
+msgstr "Не удалось декодировать JPEG-изображение"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "«%s», «%s»"
+
+msgid "Could not connect to server"
+msgstr "Не удалось соединиться с сервером"
+
+msgid "No URL set."
+msgstr "URL не задан."
+
+msgid "Could not resolve server name."
+msgstr "Не удалось определить имя сервера."
+
+msgid "Could not establish connection to server."
+msgstr "Не удалось установить соединение с сервером."
+
+msgid "Secure connection setup failed."
+msgstr "Не удалось настроить защищённое соединение."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr "Произошла сетевая ошибка или сервер неожиданно закрыл соединение."
+
+msgid "Server sent bad data."
+msgstr "Сервер прислал некорректные данные."
+
+msgid "Server does not support seeking."
+msgstr "Сервер не поддерживает поиск."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr ""
+"Входящие аудио-данные отсутствуют или недействительны, поток AVI будет "
+"повреждён."
+
+msgid "This file contains no playable streams."
+msgstr "Файл не содержит воспроизводимых потоков."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Файл некорректен и не может быть воспроизведён."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+"Невозможно воспроизвести поток, так как он зашифрован с помощью PlayReady "
+"DRM."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Файл повреждён и не может быть воспроизведён."
+
+msgid "Invalid atom size."
+msgstr "Неверный атомарный размер."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Файл не полон и не может быть воспроизведён."
+
+msgid "The video in this file might not play correctly."
+msgstr "Видео из этого файла может быть воспроизведено некорректно."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+"Файл содержит слишком много потоков. Будет воспроизведёно только первых %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Ни один поток не поддерживается. Возможно требуется установка "
+"дополнительного модуля GStreamer RTSP для потоков Real media."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Ни один поток не поддерживается. Возможно требуется разрешить дополнительные "
+"протоколы передачи или же отсутствует правильный модуль GStreamer RTSP."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Не удалось открыть аудио-устройство для воспроизведения. Устройство "
+"используется другим приложением."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Не удалось открыть аудио-устройство для воспроизведения. Отсутствуют права "
+"доступа к устройству."
+
+msgid "Could not open audio device for playback."
+msgstr "Не удалось открыть аудио-устройство для воспроизведения."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Не удалось открыть аудио-устройство для воспроизведения. Данная версия Open "
+"Sound System не поддерживается этим элементом."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Воспроизведение не поддерживается данным аудио-устройством."
+
+msgid "Audio playback error."
+msgstr "Ошибка воспроизведения аудио."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Запись не поддерживается данным аудио-устройством."
+
+msgid "Error recording from audio device."
+msgstr "Ошибка записи с аудио-устройства."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Не удалось открыть аудио-устройство для записи. Отсутствуют права доступа к "
+"устройству."
+
+msgid "Could not open audio device for recording."
+msgstr "Не удалось открыть аудио-устройство для записи."
+
+msgid "CoreAudio device not found"
+msgstr "Устройство CoreAudio не найдено"
+
+msgid "CoreAudio device could not be opened"
+msgstr "Невозможно открыть устройство CoreAudio"
+
+msgid "Record Source"
+msgstr "Устройство записи"
+
+msgid "Microphone"
+msgstr "Микрофон"
+
+msgid "Line In"
+msgstr "Линейный вход"
+
+msgid "Internal CD"
+msgstr "Внутренний CD"
+
+msgid "SPDIF In"
+msgstr "Вход SPDIF"
+
+msgid "AUX 1 In"
+msgstr "Вход AUX 1"
+
+msgid "AUX 2 In"
+msgstr "Вход AUX 2"
+
+msgid "Codec Loopback"
+msgstr "Петля Codec"
+
+msgid "SunVTS Loopback"
+msgstr "Петля SunVTS"
+
+msgid "Volume"
+msgstr "Уровень"
+
+msgid "Gain"
+msgstr "Уровень"
+
+msgid "Monitor"
+msgstr "Мониторинг"
+
+msgid "Built-in Speaker"
+msgstr "Внутренний динамик"
+
+msgid "Headphone"
+msgstr "Наушник"
+
+msgid "Line Out"
+msgstr "Линейный выход"
+
+msgid "SPDIF Out"
+msgstr "Выход SPDIF"
+
+msgid "AUX 1 Out"
+msgstr "Выход AUX 1"
+
+msgid "AUX 2 Out"
+msgstr "Выход AUX 2"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Ошибка чтения %d байт из устройства «%s»."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Не удалось создать список видео-форматов, с которыми может работать "
+"устройство «%s»"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Не удалось распределить буферы устройства «%s»"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Драйвер устройства «%s» не поддерживает метод ввода-вывода %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"Драйвер устройства «%s» не поддерживает ни один из известных методов ввода-"
+"вывода."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Устройство «%s» занято"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Устройство «%s» не может осуществлять захват в разрешении %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Устройство «%s» не может осуществлять захват в указанном формате"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr ""
+"Устройство «%s» поддерживает прерывистые матрицы (non-contiguous planes)"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Не удалось получить параметры устройства «%s»"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "Видео-устройство не приняло новое значение настройки кадровой частоты."
+
+msgid "Video device did not provide output format."
+msgstr "Видео-устройство не предоставило выходной формат."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Видео-устройство вернуло некорректные размеры."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Видео-устройства используют неподдерживаемый метод черезстрочности."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Видео-устройства используют неподдерживаемый формат пикселей."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Ошибка при настройке внутреннего буферного пула."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Видео-устройство не предложило какой-либо размер буфера."
+
+msgid "No downstream pool to import from."
+msgstr "Неоткуда импортировать пул нисходящего потока."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Не удалось получить настройки тюнера %d устройства «%s»."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Ошибка при получении списка возможностей устройства «%s»."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Устройство «%s» не является тюнером."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Не удалось выбрать радио-вход на устройстве «%s»."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Не удалось выбрать вход %d для устройства %s."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Не удалось изменить состояние приглушения для устройства «%s»."
+
+msgid "Failed to allocated required memory."
+msgstr "Не удалось выделить достаточно памяти."
+
+msgid "Failed to allocate required memory."
+msgstr "Не удалось выделить достаточно памяти."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Преобразователь на устройстве %s не поддерживает входной формат"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Преобразователь на устройстве %s не поддерживает выходной формат"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Кодировщик на устройстве %s не поддерживает входной формат"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Кодировщик на устройстве %s не поддерживает выходной формат"
+
+msgid "Failed to start decoding thread."
+msgstr "Не удалось запустить нить декодирования."
+
+msgid "Failed to process frame."
+msgstr "Не удалось обработать кадр."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Ошибка получения возможностей устройства «%s»: драйвер устройства "
+"несовместим с v4l2. Проверьте, не использует ли устройство драйвер v4l1."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Ошибка запроса атрибутов входа %d устройства %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Ошибка получения установок тюнера %d устройства «%s»."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Ошибка запроса стандарта устройства «%s»."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Ошибка получения атрибутов управления устройства «%s»."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Не удаётся распознать устройство «%s»."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "«%s» не является устройством."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Не удалось открыть устройство «%s» для чтения и записи."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Устройство «%s» не является устройством захвата."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Устройство «%s» не является устройством вывода."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Устройство «%s» не является устройством M2M."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Не удалось сделать дубликат устройства «%s» для чтения и записи."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Ошибка установки стандарта устройства «%s»."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Ошибка получения текущей частоты тюнера устройства «%s»."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr "Ошибка установки текущей частоты тюнера устройства «%s» в %lu Гц."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Ошибка получения мощности сигнала для устройства «%s»."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Ошибка получения значения управляющего параметра %d устройства «%s»."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr ""
+"Ошибка установки значения %d для управляющего параметра %d устройства «%s»."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Не удалось определить активный вход устройства «%s». Возможно, это радио-"
+"устройство"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Не удалось определить активный выход устройства «%s». Возможно, это радио-"
+"устройство"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Не удалось выбрать выход %d для устройства %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr ""
+"Изменение разрешения видео во время выполнения не поддерживается в настоящий "
+"момент."
+
+msgid "Cannot operate without a clock"
+msgstr "Операция невозможна без часов"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Внутренняя ошибка потока данных."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Внутренняя ошибка потока данных."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Устройство «%s» не поддерживает захват видео"
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Не удалось установить соединение с сервером звука"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Ошибка при запросе возможностей сервера звука"
+
+#~ msgid "Bass"
+#~ msgstr "Низкие"
+
+#~ msgid "Treble"
+#~ msgstr "Высокие"
+
+#~ msgid "Synth"
+#~ msgstr "Синтезатор"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Внутренний динамик"
+
+#~ msgid "Line-in"
+#~ msgstr "Линейный вход"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Микшер"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Запись"
+
+#~ msgid "In-gain"
+#~ msgstr "Усиление на входе"
+
+#~ msgid "Out-gain"
+#~ msgstr "Усиление на выходе"
+
+#~ msgid "Line-1"
+#~ msgstr "Линейный-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Линейный-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Линейный-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Цифровой-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Цифровой-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Цифровой-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Тел. вход"
+
+#~ msgid "Phone-out"
+#~ msgstr "Тел. выход"
+
+#~ msgid "Video"
+#~ msgstr "Видео"
+
+#~ msgid "Radio"
+#~ msgstr "Радио"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr ""
+#~ "Не удалось открыть аудио-устройство для обработки параметров микшера."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Не удалось открыть аудио-устройство для обработки параметров микшера. "
+#~ "Данная версия Open Sound System не поддерживается этим элементом."
+
+#~ msgid "Master"
+#~ msgstr "Общий"
+
+#~ msgid "Front"
+#~ msgstr "Фронтальные"
+
+#~ msgid "Rear"
+#~ msgstr "Тыловые"
+
+#~ msgid "Headphones"
+#~ msgstr "Наушники"
+
+#~ msgid "Center"
+#~ msgstr "Центр"
+
+#~ msgid "LFE"
+#~ msgstr "Сабвуфер"
+
+#~ msgid "Surround"
+#~ msgstr "Объёмный звук"
+
+#~ msgid "Side"
+#~ msgstr "Боковые"
+
+#~ msgid "AUX Out"
+#~ msgstr "Выход AUX"
+
+#~ msgid "3D Depth"
+#~ msgstr "3D глубина"
+
+#~ msgid "3D Center"
+#~ msgstr "3D центр"
+
+#~ msgid "3D Enhance"
+#~ msgstr "3D улучшение"
+
+#~ msgid "Telephone"
+#~ msgstr "Телефон"
+
+#~ msgid "Video In"
+#~ msgstr "Видео вход"
+
+#~ msgid "AUX In"
+#~ msgstr "Вход AUX"
+
+#~ msgid "Record Gain"
+#~ msgstr "Уровень записи"
+
+#~ msgid "Output Gain"
+#~ msgstr "Выходной уровень"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Микрофонный усилитель"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Диагностика"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Усиление баса"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Порты воспроизведения"
+
+#~ msgid "Input"
+#~ msgstr "Вход"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Устройство вывода"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Озвучка клавиатуры"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Имитация стерео"
+
+#~ msgid "Stereo"
+#~ msgstr "Стерео"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Объёмный звук"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Уровень микрофона"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Устройство динамика"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Устройство микрофона"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Центр / Сабвуфер"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Стерео микширование"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Моно микширование"
+
+#~ msgid "Input Mix"
+#~ msgstr "Микширование входа"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Микрофон 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Микрофон 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Цифровой выход"
+
+#~ msgid "Digital In"
+#~ msgstr "Цифровой вход"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Модем"
+
+#~ msgid "Handset"
+#~ msgstr "Гарнитура"
+
+#~ msgid "Other"
+#~ msgstr "Другой"
+
+#~ msgid "None"
+#~ msgstr "Ничего"
+
+#~ msgid "On"
+#~ msgstr "Вкл"
+
+#~ msgid "Off"
+#~ msgstr "Выкл"
+
+#~ msgid "Mute"
+#~ msgstr "Заглушить"
+
+#~ msgid "Fast"
+#~ msgstr "Скорость"
+
+#~ msgid "Very Low"
+#~ msgstr "Очень низкое"
+
+#~ msgid "Low"
+#~ msgstr "Низкое"
+
+#~ msgid "Medium"
+#~ msgstr "Среднее"
+
+#~ msgid "High"
+#~ msgstr "Высокое"
+
+#~ msgid "Very High"
+#~ msgstr "Очень высокое"
+
+#~ msgid "Production"
+#~ msgstr "Выдача"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Микрофон на передней панели"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Линейный вход на передней панели"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Наушники на передней панели"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Линейный выход на передней панели"
+
+#~ msgid "Green Connector"
+#~ msgstr "Зелёный разъём"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Розовый разъём"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Синий разъём"
+
+#~ msgid "White Connector"
+#~ msgstr "Белый разъём"
+
+#~ msgid "Black Connector"
+#~ msgstr "Чёрный разъём"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Серый разъём"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Оранжевый разъём"
+
+#~ msgid "Red Connector"
+#~ msgstr "Красный разъём"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Жёлтый разъём"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Зелёный разъём на передней панели"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Розовый разъём на передней панели"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Синий разъём на передней панели"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Белый разъём на передней панели"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Чёрный разъём на передней панели"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Серый разъём на передней панели"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Оранжевый разъём на передней панели"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Красный разъём на передней панели"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Жёлтый разъём на передней панели"
+
+#~ msgid "Spread Output"
+#~ msgstr "Развёрнутый вывод"
+
+#~ msgid "Downmix"
+#~ msgstr "Низведение"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Вход виртуального микшера"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Выход виртуального микшера"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Каналы виртуального микшера"
+
+#~ msgid "%s %d Function"
+#~ msgstr "Функция %s %d"
+
+#~ msgid "%s Function"
+#~ msgstr "Функция %s"
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Получен неожиданный размер кадра: %u вместо %u."
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Ошибка чтения %d байт из устройства «%s»."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Не удалось добавить в очередь буферы устройства «%s»"
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Ошибка при попытке получения кадров видео с устройства «%s»."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Ошибка после %d попыток. Устройство: %s. Системная ошибка: %s"
+
+#~ msgid ""
+#~ "The buffer type is not supported, or the index is out of bounds, or no "
+#~ "buffers have been allocated yet, or the userptr or length are invalid. "
+#~ "device %s"
+#~ msgstr ""
+#~ "Неподдерживаемый тип буфера, либо индекс вне диапазона, либо буферы не "
+#~ "были распределены, либо неверные значения длины или userptr (устройство "
+#~ "%s)"
+
+#~ msgid ""
+#~ "Failed trying to get video frames from device '%s'. Not enough memory."
+#~ msgstr ""
+#~ "Ошибка при попытке получения кадров видео с устройства «%s». Не хватает "
+#~ "памяти."
+
+#~ msgid "insufficient memory to enqueue a user pointer buffer. device %s."
+#~ msgstr ""
+#~ "не хватает памяти для постановки в очередь буфера пользовательского "
+#~ "указателя (устройство %s)"
+
+#~ msgid "No free buffers found in the pool at index %d."
+#~ msgstr "В пуле не найдено свободных буферов для индекса %d."
+
+#~ msgid "Could not get buffers from device '%s'."
+#~ msgstr "Не удалось получить буферы устройства «%s»"
+
+#~ msgid "Could not get enough buffers from device '%s'."
+#~ msgstr "Не удалось получить необходимое количество буферов устройства «%s»"
+
+#~ msgid "Error starting streaming capture from device '%s'."
+#~ msgstr "Ошибка при запуске потокового захвата с устройства «%s»."
+
+#~ msgid "Error stopping streaming capture from device '%s'."
+#~ msgstr "Ошибка при остановке потокового захвата с устройства «%s»."
+
+#~ msgid "Could not read from CD."
+#~ msgstr "Не удалось прочитать CD."
+
+#~ msgid "Disc is not an Audio CD."
+#~ msgstr "Диск не является аудио-CD."
+
+#~ msgid "This file is encrypted and cannot be played."
+#~ msgstr "Файл зашифрован и не может быть воспроизведён."
+
+#~ msgid "Failed getting controls attributes on device '%s.'"
+#~ msgstr "Ошибка получения атрибутов управления устройства «%s»."
+
+#~ msgid "Could not set parameters on device '%s'"
+#~ msgstr "Не удалось установить параметры устройства «%s»"
+
+#~ msgid "Device '%s' cannot capture at %d/%d frames per second"
+#~ msgstr ""
+#~ "Устройство «%s» не может осуществить захват при %d/%d кадрах в секунду"
diff --git a/po/sk.po b/po/sk.po
new file mode 100644
index 0000000..bdf7dd7
--- /dev/null
+++ b/po/sk.po
@@ -0,0 +1,925 @@
+# Slovak translations for gst-plugins-good.
+# This file is put in the public domain.
+#
+# Peter Tuhársky <tuharsky@misbb.sk>, 2007, 2008, 2009, 2010, 2014, 2016.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-05-20 12:31+0100\n"
+"Last-Translator: Peter Tuhársky <tuharsky@misbb.sk>\n"
+"Language-Team: Slovak <sk-i18n@lists.linux.sk>\n"
+"Language: sk\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\\n;\n"
+"X-Generator: Poedit 1.6.10\n"
+
+msgid "Jack server not found"
+msgstr "Jack server sa nenašiel"
+
+msgid "Failed to decode JPEG image"
+msgstr "Nepodarilo sa dekódovať obrázok JPEG"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "'%s' od '%s'"
+
+msgid "Could not connect to server"
+msgstr "Nepodarilo sa pripojiť k serveru"
+
+msgid "No URL set."
+msgstr "Nebolo nastavené URL."
+
+msgid "Could not resolve server name."
+msgstr "Nepodarilo sa preložiť názov servera."
+
+msgid "Could not establish connection to server."
+msgstr "Nepodarilo sa nadviazať spojenie so serverom."
+
+msgid "Secure connection setup failed."
+msgstr "Nastavenie bezpečného pripojenia zlyhalo."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr "Vyskytla sa sieťová chyba, alebo server nečakane uzavrel spojenie."
+
+msgid "Server sent bad data."
+msgstr "Server odoslal chybné údaje."
+
+msgid "Server does not support seeking."
+msgstr "Server nepodporuje zmenu pozície"
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Žiadny alebo chybný vstup zvuku, prúd údajov AVI bude poškodený."
+
+msgid "This file contains no playable streams."
+msgstr "Tento súbor neobsahuje žiadne prehrateľné prúdy údajov."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Tento súbor je chybný a nedá sa prehrať."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+"Prúd údajov sa nedá prehrať pretože je šifrovaný pomocou PlayReady DRM."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Tento súbor je poškodený a nedá sa prehrať."
+
+msgid "Invalid atom size."
+msgstr "Nesprávna atomická veľkosť."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Tento súbor je neúplný a nedá sa prehrať."
+
+msgid "The video in this file might not play correctly."
+msgstr "Video v tomto súbore možno nebude hrať korektne."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Tento súbor obsahuje príliš mnoho prúdov údajov. Prehrávam iba prvý %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Nenašiel sa žiaden podporovaný prúd údajov. Možno je potrebné nainštalovať "
+"zásuvný modul GStreamer RTSP pre prúdy Real media.."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Nenašiel sa žiaden podporovaný prúd údajov. Možno by ste mali povoliť "
+"viacero prenosových protokolov, alebo vám možno chýba správny zásuvný modul "
+"GStreamer RTSP."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Nepodarilo sa otvoriť zvukové zariadenie v režime prehrávania. Zariadenie už "
+"používa iná aplikácia."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Nepodarilo sa otvoriť zvukové zariadenie v režime prehrávania. Nemáte "
+"oprávnenie na otvorenie tohto zariadenia."
+
+msgid "Could not open audio device for playback."
+msgstr "Nepodarilo sa otvoriť zvukové zariadenie vrežime prehrávania."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Nepodarilo sa otvoriť zvukové zariadenie v režime prehrávania. Tento prvok "
+"nepodporuje túto verziu Open Sound System."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Toto zvukové zariadenie nepodporuje prehrávanie."
+
+msgid "Audio playback error."
+msgstr "Chyba prehrávania zvuku."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Toto zvukové zariadenie nepodporuje nahrávanie."
+
+msgid "Error recording from audio device."
+msgstr "Chyba pri nahrávaní zo zvukového zariadenia."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Nepodarilo sa otvoriť zvukové zariadenie v režime nahrávania. Nemáte "
+"oprávnenie na otvorenie tohto zariadenia."
+
+msgid "Could not open audio device for recording."
+msgstr "Nepodarilo sa otvoriť zvukové zariadenie v režime nahrávania."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "Zdroj záznamu"
+
+msgid "Microphone"
+msgstr "Mikrofón"
+
+msgid "Line In"
+msgstr "Linkový vstup"
+
+msgid "Internal CD"
+msgstr "Vnútorne CD"
+
+msgid "SPDIF In"
+msgstr "SPDIF vstup"
+
+msgid "AUX 1 In"
+msgstr "AUX 1 vstup"
+
+msgid "AUX 2 In"
+msgstr "AUX 2 vstup"
+
+msgid "Codec Loopback"
+msgstr "Spätná slučka kodeku"
+
+msgid "SunVTS Loopback"
+msgstr "Spätná slučka SunVTS"
+
+msgid "Volume"
+msgstr "Hlasitosť"
+
+msgid "Gain"
+msgstr "Zisk"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "PC reproduktor"
+
+msgid "Headphone"
+msgstr "Slúchadlá"
+
+msgid "Line Out"
+msgstr "Linkový výstup"
+
+msgid "SPDIF Out"
+msgstr "SPDIF výstup"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1 výstup"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2 výstup"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Chyba pri čítaní %d bajtov zo zariadenia '%s'."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Nepodarilo sa zistiť možné video formáty s ktorými by vedelo pracovať "
+"zariadenie '%s'"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Nepodarilo sa namapovať vyrovnávaciu pamäť zariadenia '%s'"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Tento ovládač zariadenia '%s' nepodporuje IO metódu %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Tento ovládač zariadenia '%s' nepodporuje žiadnu známu IO metódu."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Zariadenie '%s' je zaneprázdnené"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Zariadenie '%s' nevie nahrávať na %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Zariadenie '%s' nedokáže nahrávať v uvedenom formáte"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Zariadenie '%s' podporuje nespojité roviny"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Nepodarilo sa získať parametre zariadenia '%s'"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "Video zariadenie odmietlo nové nastavenie frekvencie snímok."
+
+msgid "Video device did not provide output format."
+msgstr "ideo zariadenie neposkytlo výstupný formát."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Video zariadenie udáva nesprávne rozmery."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Video zariadenie používa nepodporovanú metódu prekladania snímok."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Video zariadenie používa nepodporovaný formát pixelov."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Nepodarilo sa nastaviť vnútornú oblasť vyrovnávacej pamäte."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Video zariadenie neodporučilo žiadnu veľkosť vyrovnávacej pamäte."
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Nepodarilo sa získať nastavenie prijímača %d od zariadenia '%s'."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Chyba pri načítaní možností zariadena '%s'."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Zariadenie '%s' nie je prijímač."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Nepodarilo sa získať rozhlasový vstup na zariadení '%s'."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Nepodarilo sa nastaviť vstup %d na zariadení %s."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Nepodarilo sa zmeniť stav stlmenia pre zariadenie '%s'."
+
+msgid "Failed to allocated required memory."
+msgstr "Nepodarilo sa uvoľniť dostatok pamäte."
+
+msgid "Failed to allocate required memory."
+msgstr "Nepodarilo sa uvoľniť dostatok pamäte."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Konvertor na zariadení %s nepodporuje žiadny vstupný formát"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Konvertor na zariadení %s nepodporuje žiadny výstupný formát"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Enkodér na zariadení %s nepodporuje žiadny vstupný formát"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Enkodér na zariadení %s nepodporuje žiadny výstupný formát"
+
+msgid "Failed to start decoding thread."
+msgstr "Nepodarilo sa spustiť dekódovacie vlákno."
+
+msgid "Failed to process frame."
+msgstr "Nepodarilo sa spracovať snímok."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Chyba pri zisťovaní schopností zariadenia '%s': Toto nie je ovládač v4l2. "
+"Skontrolujte, či je to ovládač v4l1."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Nepodarilo sa získať atribúty vstupu %d zariadenia %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Nepodarilo sa získať nastavenie prijímača %d od zariadenia '%s'."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Zlyhala požiadavka norm na zariadení '%s'."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Nepodarilo sa získať atribúty ovládacích prvkov na zariadení '%s'."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Neviem identifikovať zariadenie '%s'."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Toto nie je zariadenie '%s'."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Nepodarilo sa otvoriť zariadenie '%s' pre čítanie a zápis."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Zariadenie '%s' nie je určené pre nahrávanie."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Zariadenie '%s' nie je určené pre výstup."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Zariadenie '%s' nie je typu M2M."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Nepodarilo sa otvoriť zariadenie '%s' pre čítanie a zápis."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Zlyhalo nastavenie norm na zariadení '%s'."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Nepodarilo sa zistiť súčasnú frekvenciu prijímača pre zariadenie '%s'."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Nepodarilo sa nastaviť súčasnú frekvenciu prijímača pre zariadenie '%s' na "
+"%lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Nepodarilo sa zistiť silu signálu pre zariadenie '%s'."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr ""
+"Nepodarilo sa zistiť hodnotu pre ovládací prvok %d pre zariadenie '%s'."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr ""
+"Nepodarilo sa nastaviť hodnotu %d pre ovládací prvok %d na zariadení '%s'."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Nepodarilo sa zistiť súčasný vstup na zariadení '%s'. Možno je to rádio."
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Nepodarilo sa zistiť súčasný výstup na zariadení '%s'. Možno je to rádio."
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Nepodarilo sa nastaviť výstup %d na zariadení %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Zmena rozlíšenia za chodu nie je zatiaľ podporovaná."
+
+msgid "Cannot operate without a clock"
+msgstr "Nemôžem fungovať bez hodín"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Vnútorná chyba prúdu údajov."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Vnútorná chyba toku údajov."
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Nepodarilo sa nadviazať spojenie so zvukovým serverom"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Nepodarilo sa zistiť schopnosti zvukového servera"
+
+#~ msgid "Bass"
+#~ msgstr "Basy"
+
+#~ msgid "Treble"
+#~ msgstr "Výšky"
+
+#~ msgid "Synth"
+#~ msgstr "Syntetizér"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Reproduktor"
+
+#~ msgid "Line-in"
+#~ msgstr "Linkový vstup"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Mixér"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Nahrávanie"
+
+#~ msgid "In-gain"
+#~ msgstr "Vstupný zisk"
+
+#~ msgid "Out-gain"
+#~ msgstr "Výstupný zisk"
+
+#~ msgid "Line-1"
+#~ msgstr "Linka-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Linka-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Linka-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Digitál-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Digitál-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Digitál-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Telefón-vstup"
+
+#~ msgid "Phone-out"
+#~ msgstr "Telefón-výstup"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Rádio"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "Nepodarilo sa otvoriť zvukové zariadenie v režime obsluhy mixéru."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Nepodarilo sa otvoriť zvukové zariadenie v režime obsluhy mixéru. Táto "
+#~ "verzia Open Sound System nie je podporovaná týmto prvkom."
+
+#~ msgid "Master"
+#~ msgstr "Hlavný"
+
+#~ msgid "Front"
+#~ msgstr "Predný"
+
+#~ msgid "Rear"
+#~ msgstr "Zadné"
+
+#~ msgid "Headphones"
+#~ msgstr "Slúchadlá"
+
+#~ msgid "Center"
+#~ msgstr "Stredný"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Priestorový"
+
+#~ msgid "Side"
+#~ msgstr "Strana"
+
+#~ msgid "AUX Out"
+#~ msgstr "AUX výstup"
+
+#~ msgid "3D Depth"
+#~ msgstr "3D hĺbka"
+
+#~ msgid "3D Center"
+#~ msgstr "3D stred"
+
+#~ msgid "3D Enhance"
+#~ msgstr "3D vylepšenie"
+
+#~ msgid "Telephone"
+#~ msgstr "Telefón"
+
+#~ msgid "Video In"
+#~ msgstr "Video vstup"
+
+#~ msgid "AUX In"
+#~ msgstr "AUX vstup"
+
+#~ msgid "Record Gain"
+#~ msgstr "Zisk záznamu"
+
+#~ msgid "Output Gain"
+#~ msgstr "Výstupný zisk"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Zosilnenie mikrofónu"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Diagnostika"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Zvýraznenie basov"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Prehrávacie porty"
+
+#~ msgid "Input"
+#~ msgstr "Vstup"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Monitor zdroja"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Pípnutie klávesnice"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Simulovať stereo"
+
+#~ msgid "Stereo"
+#~ msgstr "Stereo"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Priestorový zvuk"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Zisk mikrofónu"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Zdroj reproduktora"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Zdroj mikrofónu"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Stred / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Stereo Mix"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Mono Mix"
+
+#~ msgid "Input Mix"
+#~ msgstr "Vstup Mix"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Mikrofón 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Mikrofón 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Digitálny výstup"
+
+#~ msgid "Digital In"
+#~ msgstr "Digitálny vstup"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modem"
+
+#~ msgid "Other"
+#~ msgstr "Iné"
+
+#~ msgid "None"
+#~ msgstr "Nič"
+
+#~ msgid "On"
+#~ msgstr "Zapnuté"
+
+#~ msgid "Off"
+#~ msgstr "Vypnuté"
+
+#~ msgid "Mute"
+#~ msgstr "Stlmiť"
+
+#~ msgid "Fast"
+#~ msgstr "Rýchlo"
+
+#~ msgid "Very Low"
+#~ msgstr "Veľmi nízke"
+
+#~ msgid "Low"
+#~ msgstr "Nízke"
+
+#~ msgid "Medium"
+#~ msgstr "Stredné"
+
+#~ msgid "High"
+#~ msgstr "Vysoké"
+
+#~ msgid "Very High"
+#~ msgstr "Veľmi vysoké"
+
+#~ msgid "Production"
+#~ msgstr "Produkcia"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Mikrofón na prednom paneli"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Linkový vstup na prednom paneli"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Slúchadlá na prednom paneli"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Linkový výstup na prednom paneli"
+
+#~ msgid "Green Connector"
+#~ msgstr "Zelený konektor"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Ružový konektor"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Modrý konektor"
+
+#~ msgid "White Connector"
+#~ msgstr "Biely konektor"
+
+#~ msgid "Black Connector"
+#~ msgstr "Čierny konektor"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Šedý konektor"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Oranžový konektor"
+
+#~ msgid "Red Connector"
+#~ msgstr "Červený konektor"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Žltý konektor"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Zelený konektor na prednom paneli"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Ružový konektor na prednom paneli"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Modrý konektor na prednom paneli"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Biely konektor na prednom paneli"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Čierny konektor na prednom paneli"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Šedý konektor na prednom paneli"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Oranžový konektor na prednom paneli"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Červený konektor na prednom paneli"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Žltý konektor na prednom paneli"
+
+#~ msgid "Spread Output"
+#~ msgstr "Rozdeliť výstup"
+
+#~ msgid "Downmix"
+#~ msgstr "Zmiešanie"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Vstup virtuálneho mixéra"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Výstup virtuálneho mixéra"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Kanály virtuálneho mixéra"
+
+#~ msgid "%s %d Function"
+#~ msgstr "%s %d funkcia"
+
+#~ msgid "%s Function"
+#~ msgstr "%s funkcia"
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Nastala neočakávaná veľkosť snímky %u namiesto %u."
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Chyba pri čítaní %d bajtov na zariadení '%s'."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Nepodarilo sa zaradiť vyrovnávaciu pamäť na zariadení '%s'."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Nepodarilo sa získať videosnímky zo zariadenia '%s'."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Nepodarilo sa po %d pokusoch. Zariadenie %s. Systémová chyba: %s"
+
+#~ msgid "Failed getting controls attributes on device '%s.'"
+#~ msgstr "Nepodarilo sa získať atribúty ovládacích prvkov na zariadení '%s.'"
+
+#~ msgid ""
+#~ "The buffer type is not supported, or the index is out of bounds, or no "
+#~ "buffers have been allocated yet, or the userptr or length are invalid. "
+#~ "device %s"
+#~ msgstr ""
+#~ "Tento typ vyrovnávacej pamäte nie je podporovaný, alebo je tento index "
+#~ "mimo medzí, alebo zatiaľ nebola alokovaná žiadna vyrovnávacia pamäť, "
+#~ "alebo userptr alebo dĺžka sú chybné. Zariadenie %s"
+
+#~ msgid ""
+#~ "Failed trying to get video frames from device '%s'. Not enough memory."
+#~ msgstr ""
+#~ "Nepodarilo sa získať videosnímky zo zariadenia '%s'. Nedostatok pamäte."
+
+#~ msgid "insufficient memory to enqueue a user pointer buffer. device %s."
+#~ msgstr ""
+#~ "nedostatok pamäte pre zaradenie požiadavky na používateľskú vyrovnávaciu "
+#~ "pamäť ukazovateľa. zariadenie %s."
+
+#~ msgid "No free buffers found in the pool at index %d."
+#~ msgstr ""
+#~ "Nenašli sa žiadne voľné oblasti vyrovnávacei pamäte v bloku na indexe %d."
+
+#~ msgid "Could not get buffers from device '%s'."
+#~ msgstr "Nepodarilo sa získať vyrovnávaciu pamäť od zariadenia '%s'."
+
+#~ msgid "Could not get enough buffers from device '%s'."
+#~ msgstr ""
+#~ "Nepodarilo sa získať dostatok vyrovnávacej pamäte od zariadenia '%s'."
+
+#~ msgid "Error starting streaming capture from device '%s'."
+#~ msgstr "Chyba pri štartovaní zachytávania prúdu údajov zo zariadenia '%s'."
+
+#~ msgid "Error stopping streaming capture from device '%s'."
+#~ msgstr "Chyba pri zastavovaní zachytávania prúdu údajov zo zariadenia '%s'."
+
+#~ msgid "Could not read from CD."
+#~ msgstr "Nepodarilo sa čítať z CD."
+
+#~ msgid "Disc is not an Audio CD."
+#~ msgstr "Tento disk nie je zvukové CD."
+
+#~ msgid "This file is encrypted and cannot be played."
+#~ msgstr "Tento súbor je zašifrovaný a nedá sa prehrať."
+
+#~ msgid "Could not set parameters on device '%s'"
+#~ msgstr "Nepodarilo sa nastaviť parametre zariadeniu '%s'"
+
+#~ msgid "Device '%s' cannot capture at %d/%d frames per second"
+#~ msgstr "Zariadenie '%s' nedokáže zachytávať pri %d/%d snímkach za sekundu"
+
+#~ msgid "Could not exchange data with device '%s'."
+#~ msgstr "Nepodarila sa výmena údajov so zariadením '%s'."
+
+#~ msgid "Describes the selected input element."
+#~ msgstr "Opisuje vybraný vstupný prvok."
+
+#~ msgid "Describes the selected output element for Audio/Video Conferencing."
+#~ msgstr "Opisuje vybraný výstupný prvok pre hlasové/video konferencie."
+
+#~ msgid "Describes the selected output element for Music and Movies."
+#~ msgstr "Opisuje vybraný výstupný prvok pre hudbu a filmy."
+
+#~ msgid "Describes the selected output element."
+#~ msgstr "Opisuje vybraný výstupný prvok."
+
+#~ msgid "GStreamer audiosink for Audio/Video Conferencing"
+#~ msgstr "GStreamer audiosink pre hlasové/video konferencie"
+
+#~ msgid "GStreamer audiosink for Music and Movies"
+#~ msgstr "GStreamer audiosink pre hudbu a filmy"
+
+#~ msgid ""
+#~ "GStreamer can play audio using any number of output elements. Some "
+#~ "possible choices are osssink, esdsink and alsasink. The audiosink can be "
+#~ "a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer dokáže prehrávať zvuk pomocou ľubovoľného počtu výstupných "
+#~ "prvkov. Možnosťami sú napríklad osssink, esdsink a alsasink. Audiosink "
+#~ "môže byť čiastočne rúrou, nielen jediným prvkom."
+
+#~ msgid ""
+#~ "GStreamer can play video using any number of output elements. Some "
+#~ "possible choices are xvimagesink, ximagesink, sdlvideosink and aasink. "
+#~ "The videosink can be a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer dokáže prehrávať video pomocou ľubovoľného počtu výstupných "
+#~ "prvkov. Možnosťami sú napríklad xvimagesink, ximagesink, sdlvideosink a "
+#~ "aasink. Videosink môže byť čiastočne rúrou, nielen jediným prvkom."
+
+#~ msgid ""
+#~ "GStreamer can put visualization plugins in a pipeline to transform audio "
+#~ "stream in video frames. Default is goom but more visualization plugins "
+#~ "will be ported soon. The visualization plugin can be a partial pipeline "
+#~ "instead of just one element."
+#~ msgstr ""
+#~ "GStreamer dokáže vsunúť vizualizačné zásuvné moduly do rúry a "
+#~ "transformovať zvukový prúd údajov na videosnímky. Predvolený je goom, ale "
+#~ "čoskoro bude dostupných viacero vizualizačných zásuvných modulov. "
+#~ "Vizualizačný zásuvný modul môže byť čiastočne rúrou, nielen jediným "
+#~ "prvkom."
+
+#~ msgid ""
+#~ "GStreamer can record audio using any number of input elements. Some "
+#~ "possible choices are osssrc, esdsrc and alsasrc. The audio source can be "
+#~ "a partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer dokáže nahrávať zvuk pomocou ľubovoľného počtu vstupných "
+#~ "prvkov. Možnosťami sú napríklad osssrc, esdsrc, alsasrc. Zvukový zdroj "
+#~ "môže byť čiastočne rúrou, nielen jediným prvkom."
+
+#~ msgid ""
+#~ "GStreamer can record video from any number of input elements. Some "
+#~ "possible choices are v4lsrc and videotestsrc. The video source can be a "
+#~ "partial pipeline instead of just one element."
+#~ msgstr ""
+#~ "GStreamer dokáže nahrať video pomocou ľubovoľného počtu vstupných prvkov. "
+#~ "Možnosťami sú napríklad v4lsrc a videotestsrc. Video zdroj môže byť "
+#~ "čiastočne rúrou, nielen jediným prvkom."
+
+#~ msgid "default GStreamer audio source"
+#~ msgstr "predvolený zdroj zvuku pre GStreamer"
+
+#~ msgid "default GStreamer audiosink"
+#~ msgstr "predvolený audiosink pre GStreamer"
+
+#~ msgid "default GStreamer video source"
+#~ msgstr "predvolený zdroj videa pre GStreamer"
+
+#~ msgid "default GStreamer videosink"
+#~ msgstr "predvolený videosink pre GStreamer"
+
+#~ msgid "default GStreamer visualization plugin"
+#~ msgstr "predvolený vizualizačný zásuvný modul pre GStreamer"
+
+#~ msgid "description for GStreamer audiosink for Audio/Video Conferencing"
+#~ msgstr "popis pre audiosink pre GStreamer pre hlasové/video konferencie"
+
+#~ msgid "description for GStreamer audiosink for Music and Movies"
+#~ msgstr "popis pre audiosink pre GStreamer pre hudbu a filmy"
+
+#~ msgid "description for default GStreamer audiosink"
+#~ msgstr "popis pre predvolený audiosink pre GStreamer"
+
+#~ msgid "description for default GStreamer audiosrc"
+#~ msgstr "popis pre predvolený audiosrc pre GStreamer"
diff --git a/po/sl.po b/po/sl.po
new file mode 100644
index 0000000..d5615d6
--- /dev/null
+++ b/po/sl.po
@@ -0,0 +1,445 @@
+# Slovenian translation for gst-plugins-good.
+# This file is distributed under the same license as the gst-plugins-good package.
+# Copyright (C) 2005 - 2014 Free Software Foundation, Inc.
+#
+# Robert Horvat <robi@hipnos.net>, 2010.
+# Matej Urbančič <matej.urban@gmail.com>, 2010 - 2011.
+# Klemen Košir <klemen913@gmail.com>, 2012 - 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good-1.2.1\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2014-04-09 22:52+0100\n"
+"Last-Translator: Klemen Košir <klemen913@gmail.com>\n"
+"Language-Team: Slovenian <translation-team-sl@lists.sourceforge.net>\n"
+"Language: sl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n"
+"%100==4 ? 3 : 0);\n"
+
+msgid "Jack server not found"
+msgstr "Strežnika JACK ni mogoče najti"
+
+msgid "Failed to decode JPEG image"
+msgstr "Napaka med dekodiranjem JPEG slike"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "'%s' izvajalca '%s'"
+
+msgid "Could not connect to server"
+msgstr "Ni se mogoče povezati s strežnikom"
+
+msgid "No URL set."
+msgstr "Ni nastavljenega naslova URL."
+
+msgid "Could not resolve server name."
+msgstr "Ni mogoče razrešiti imena strežnika."
+
+msgid "Could not establish connection to server."
+msgstr "Ni mogoče vzpostaviti povezave s strežnikom."
+
+msgid "Secure connection setup failed."
+msgstr "Nastavitev varne povezave je spodletela."
+
+#, fuzzy
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Prišlo je do omrežne napake ali pa je povezava nepričakovano prekinjena."
+
+msgid "Server sent bad data."
+msgstr "Strežnik je poslal slabe podatke."
+
+msgid "Server does not support seeking."
+msgstr "Strežnik ne podpira iskanja."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Napaka vhodnega zvoka, AVI pretok bo pokvarjen."
+
+msgid "This file contains no playable streams."
+msgstr "Datoteka ne vsebuje pretokov za predvajanje."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Datoteka je napačna, zato je ni mogoče predvajati."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr "Pretoka ni mogoče predvajati, ker je šifriran s PlayReady DRM."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Datoteka je pokvarjena, zato je ni mogoče predvajati."
+
+msgid "Invalid atom size."
+msgstr "Neveljavna velikost atoma."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Datoteka ni popolna, zato je ni mogoče predvajati."
+
+msgid "The video in this file might not play correctly."
+msgstr "Video zapis v tej datoteki morda ne bo predvajan pravilno."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Datoteka vsebuje več pretokov. Predvajano bo le začetnih %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Ni mogoče najti podprtega pretoka. Najverjetneje je treba namestiti vstavek "
+"GStreamer RTSP razširitve za RealMedia pretoke."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Ni mogoče najti podprtega pretoka. Najverjetneje je treba omogočiti več "
+"protokolov prenosa, oziroma manjka ustrezen vstavek GStreamer RTSP "
+"razširitve."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Ni mogoče odpreti zvočne naprave za predvajanje. Napravo uporablja drug "
+"program."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Ni mogoče odpreti zvočne naprave za predvajanje. Ni ustreznih dovoljenj za "
+"odpiranje naprave."
+
+msgid "Could not open audio device for playback."
+msgstr "Ni mogoče odpreti zvočne naprave za predvajanje."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Ni mogoče odpreti zvočne naprave za predvajanje. Open Sound System ni podprt."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Predvajane s to zvočno napravo ni podprto."
+
+msgid "Audio playback error."
+msgstr "Med predvajanjem zvoka je prišlo do napake."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Snemanje s to zvočno napravo ni podprto."
+
+msgid "Error recording from audio device."
+msgstr "Napaka med shranjevanjem preko zvočne naprave"
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Zvočne naprave ni mogoče odpreti za snemanje. Ni ustreznih dovoljenj za "
+"odpiranje naprave."
+
+msgid "Could not open audio device for recording."
+msgstr "Zvočne naprave ni mogoče odpreti za snemanje."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "Vir snemanja"
+
+msgid "Microphone"
+msgstr "Mikrofon"
+
+msgid "Line In"
+msgstr "Analogni vhod"
+
+msgid "Internal CD"
+msgstr "Notranji CD"
+
+msgid "SPDIF In"
+msgstr "Vhod SPDIF"
+
+msgid "AUX 1 In"
+msgstr "Vhod AUX 1"
+
+msgid "AUX 2 In"
+msgstr "Vhod AUX 2"
+
+msgid "Codec Loopback"
+msgstr "Povratna zanka kodeka"
+
+msgid "SunVTS Loopback"
+msgstr "Povratna zanka SunVTS"
+
+msgid "Volume"
+msgstr "Glasnost"
+
+msgid "Gain"
+msgstr "Ojačitev"
+
+msgid "Monitor"
+msgstr "Zaslon"
+
+msgid "Built-in Speaker"
+msgstr "Vgrajeni zvočnik"
+
+msgid "Headphone"
+msgstr "Slušalke"
+
+msgid "Line Out"
+msgstr "Analogni izhod"
+
+msgid "SPDIF Out"
+msgstr "Izhod SPDIF"
+
+msgid "AUX 1 Out"
+msgstr "Izhod AUX 1"
+
+msgid "AUX 2 Out"
+msgstr "Izhod AUX 2"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Napaka med branjem %d bajtov iz naprave '%s'."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Med številčenjem oblik videa, ki jih podpira naprava \"%s\", je prišlo do "
+"napake."
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Ni mogoče preslikati medpomnilnika naprave '%s'"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Gonilnik naprave \"%s\" ne podpira nobenega načina I/O %d."
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Gonilnik naprave \"%s\" ne podpira nobenega znanega načina I/O."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Naprava \"%s\" je zaposlena."
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Naprava \"%s\" ne podpira zajemanja v ločljivosti %dx%d."
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Naprava \"%s\" ne podpira zajemanja v izbrani obliki."
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Naprava \"%s\" ne podpira zajemanja videa."
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Ni mogoče pridobiti parametrov na napravi '%s'."
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "Napravi ni mogoče določiti novih nastavitev hitrosti sličic."
+
+#, fuzzy
+msgid "Video device did not provide output format."
+msgstr "Napravi ni mogoče določiti novih nastavitev hitrosti sličic."
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Gonilnik naprave \"%s\" ne podpira nobenega načina I/O %d."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Gonilnik naprave \"%s\" ne podpira nobenega načina I/O %d."
+
+#, fuzzy
+msgid "Failed to configure internal buffer pool."
+msgstr "Naprava ne more ustvariti zaloge medpomnilnika."
+
+#, fuzzy
+msgid "Video device did not suggest any buffer size."
+msgstr "Naprava ne more ustvariti zaloge medpomnilnika."
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr ""
+"Med pridobivanjem nastavitev uglaševalnika %d na napravi \"%s\" je prišlo do "
+"napake."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Med pridobivanjem lastnosti naprave \"%s\" je prišlo do napake."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Naprava \"%s\" ni uglaševalnik."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Med pridobivanjem vhoda na napravi \"%s\" je prišlo do napake."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Napaka med določanjem vhoda %d naprave %s."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr ""
+"Med nastavljanjem stanja glasnosti na napravi \"%s\" je prišlo do napake."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Gonilnik naprave \"%s\" ne podpira nobenega načina I/O %d."
+
+#, fuzzy, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Napravi ni mogoče določiti novih nastavitev hitrosti sličic."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Napravi ni mogoče določiti novih nastavitev hitrosti sličic."
+
+#, fuzzy, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Napravi ni mogoče določiti novih nastavitev hitrosti sličic."
+
+#, fuzzy
+msgid "Failed to start decoding thread."
+msgstr "Napaka med dekodiranjem JPEG slike"
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Napaka med pridobivanjem zmožnosti naprave '%s': ni pravega gonilnika v4l2. "
+"Preverite namestitev."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Napaka med pregledovanjem atributov poizvedbe vhoda %d naprave %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Napaka med pridobivanjem nastavitev uglaševalnika %d na napravi '%s'."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Napaka med poizvedovanjem uravnanosti naprave '%s'."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Napaka med pridobivanjem atributov nadzora naprave '%s'."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Naprave \"%s\" ni mogoče določiti."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "To ni naprava \"%s\"."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Ni mogoče odpreti naprave '%s' za branje in pisanje."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Naprava '%s' ni naprava za zajemanje."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Naprava '%s' ni izhodna naprava."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Naprava '%s' ni izhodna naprava."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Ni mogoče odpreti naprave '%s' za branje in pisanje."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Med nastavljanjem naprave \"%s\" je prišlo do napake."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Napaka med pridobivanjem frekvence uglaševalnika naprave '%s'."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Napaka med nastavljanjem frekvence uglaševalnika naprave '%s' na %lu Hz.."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Napaka med pridobivanjem moči signala za napravo '%s'."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Napaka med pridobivanjem vrednosti %d na napravi '%s'."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Napaka med določanjem vrednosti %d za %d na napravi '%s'."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Napaka med pridobivanjem vhodnega signala naprave '%s'. Morda je radijska "
+"naprava."
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Napaka med pridobivanjem odvodnega signala naprave '%s'. Morda je radijska "
+"naprava."
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Napaka med določanjem odvoda %d naprave %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Spreminjanje ločljivosti med delovanjem še ni podprto."
+
+msgid "Cannot operate without a clock"
+msgstr "Izvajanje opravil brez ure ni mogoče"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Notranja napaka pretoka podatkov."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Notranja napaka pretoka podatkov."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Naprava \"%s\" ne podpira zajemanja videa."
diff --git a/po/sq.po b/po/sq.po
new file mode 100644
index 0000000..61447f8
--- /dev/null
+++ b/po/sq.po
@@ -0,0 +1,638 @@
+# Përkthimi i mesazheve të gst-plugins në shqip.
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Laurent Dhima <laurenti@alblinux.net>, 2004.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins 0.8.3\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2004-08-07 20:29+0200\n"
+"Last-Translator: Laurent Dhima <laurenti@alblinux.net>\n"
+"Language-Team: Albanian <begraj@hotmail.com>\n"
+"Language: sq\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr ""
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr ""
+
+#, fuzzy
+msgid "Could not connect to server"
+msgstr "E pamundur mbyllja e dispozitivit të kontrollit \"%s\"."
+
+msgid "No URL set."
+msgstr ""
+
+#, fuzzy
+msgid "Could not resolve server name."
+msgstr "E pamundur mbyllja e dispozitivit të kontrollit \"%s\"."
+
+#, fuzzy
+msgid "Could not establish connection to server."
+msgstr "E pamundur mbyllja e dispozitivit të kontrollit \"%s\"."
+
+msgid "Secure connection setup failed."
+msgstr ""
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+
+msgid "Server sent bad data."
+msgstr ""
+
+#, fuzzy
+msgid "Server does not support seeking."
+msgstr "Dispozitivi juaj OSS mund të mos provohet korrektësisht"
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Input audio i gabuar ose mungon, stream AVI mund të jetë i dëmtuar."
+
+msgid "This file contains no playable streams."
+msgstr ""
+
+msgid "This file is invalid and cannot be played."
+msgstr ""
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr ""
+
+msgid "Invalid atom size."
+msgstr ""
+
+msgid "This file is incomplete and cannot be played."
+msgstr ""
+
+msgid "The video in this file might not play correctly."
+msgstr ""
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+
+#, fuzzy
+msgid "Could not open audio device for playback."
+msgstr "E pamundur hapja e dispozitivit të zërit \"%s\" për shkrim."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+
+msgid "Playback is not supported by this audio device."
+msgstr ""
+
+msgid "Audio playback error."
+msgstr ""
+
+msgid "Recording is not supported by this audio device."
+msgstr ""
+
+msgid "Error recording from audio device."
+msgstr ""
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+
+#, fuzzy
+msgid "Could not open audio device for recording."
+msgstr "I pamundur hapja e dispozitivit CD për lexim."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+#, fuzzy
+msgid "CoreAudio device could not be opened"
+msgstr "Dispozitivi juaj OSS mund të mos provohet korrektësisht"
+
+#, fuzzy
+msgid "Record Source"
+msgstr "Regjistrimi"
+
+msgid "Microphone"
+msgstr "Mikrofoni"
+
+#, fuzzy
+msgid "Line In"
+msgstr "Linja-hyrje"
+
+msgid "Internal CD"
+msgstr ""
+
+msgid "SPDIF In"
+msgstr ""
+
+msgid "AUX 1 In"
+msgstr ""
+
+msgid "AUX 2 In"
+msgstr ""
+
+msgid "Codec Loopback"
+msgstr ""
+
+msgid "SunVTS Loopback"
+msgstr ""
+
+msgid "Volume"
+msgstr "Volumi"
+
+msgid "Gain"
+msgstr ""
+
+msgid "Monitor"
+msgstr "Ekrani"
+
+#, fuzzy
+msgid "Built-in Speaker"
+msgstr "Zë folës"
+
+msgid "Headphone"
+msgstr ""
+
+msgid "Line Out"
+msgstr ""
+
+msgid "SPDIF Out"
+msgstr ""
+
+msgid "AUX 1 Out"
+msgstr ""
+
+msgid "AUX 2 Out"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "E pamundur marrja e buffers nga dispozitivi \"%s\"."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "E pamundur marrja e buffers nga dispozitivi \"%s\"."
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr ""
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Device '%s' is busy"
+msgstr "Dispozitivi \"%s\" nuk është një dispozitiv marrje."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Dispozitivi \"%s\" nuk është një dispozitiv marrje."
+
+#, fuzzy, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Dispozitivi \"%s\" nuk është një dispozitiv marrje."
+
+#, fuzzy, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Dispozitivi \"%s\" nuk është një dispozitiv marrje."
+
+#, fuzzy, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "E pamundur marrja e buffers nga dispozitivi \"%s\"."
+
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+
+msgid "Video device did not provide output format."
+msgstr ""
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+
+msgid "Video device uses an unsupported pixel format."
+msgstr ""
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+msgid "Video device did not suggest any buffer size."
+msgstr ""
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "E pamundur marrja e buffers të mjaftueshëm nga dispozitivi \"%s\"."
+
+#, fuzzy, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "E pamundur marrja e buffers nga dispozitivi \"%s\"."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Dispozitivi \"%s\" nuk është një dispozitiv marrje."
+
+#, fuzzy, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "E pamundur mbyllja e dispozitivit audio \"%s\"."
+
+#, fuzzy, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "E pamundur mbyllja e dispozitivit audio \"%s\"."
+
+#, fuzzy, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "E pamundur marrja e buffers nga dispozitivi \"%s\"."
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+
+msgid "Failed to start decoding thread."
+msgstr ""
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "E pamundur marrja e buffers të mjaftueshëm nga dispozitivi \"%s\"."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Cannot identify device '%s'."
+msgstr "I pamundur shkrimi në dispozitivin \"%s\"."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "E pamundur hapja e dispozitivit \"%s\" për lexim dhe shkrim."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Dispozitivi \"%s\" nuk është një dispozitiv marrje."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Dispozitivi \"%s\" nuk është një dispozitiv marrje."
+
+#, fuzzy, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Dispozitivi \"%s\" nuk është një dispozitiv marrje."
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "E pamundur hapja e dispozitivit \"%s\" për lexim dhe shkrim."
+
+#, fuzzy, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "E pamundur marrja e buffers nga dispozitivi \"%s\"."
+
+#, fuzzy, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "E pamundur marrja e buffers të mjaftueshëm nga dispozitivi \"%s\"."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "E pamundur mbyllja e dispozitivit të kontrollit \"%s\"."
+
+#, fuzzy, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "E pamundur mbyllja e dispozitivit të kontrollit \"%s\"."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+
+#, fuzzy, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr "E pamundur marrja e buffers të mjaftueshëm nga dispozitivi \"%s\"."
+
+#, fuzzy, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "E pamundur mbyllja e dispozitivit audio \"%s\"."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr ""
+
+msgid "Cannot operate without a clock"
+msgstr ""
+
+#, fuzzy
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Dispozitivi \"%s\" nuk është një dispozitiv marrje."
+
+#, fuzzy
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "E pamundur marrja e buffers të mjaftueshëm nga dispozitivi \"%s\"."
+
+#~ msgid "Bass"
+#~ msgstr "Bas"
+
+#~ msgid "Treble"
+#~ msgstr "Treble"
+
+#~ msgid "Synth"
+#~ msgstr "Sintetizuesi"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Zë folës"
+
+#~ msgid "Line-in"
+#~ msgstr "Linja-hyrje"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Kontrolli i volumit"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Regjistrimi"
+
+#~ msgid "In-gain"
+#~ msgstr "In-gain"
+
+#~ msgid "Out-gain"
+#~ msgstr "Out-gain"
+
+#~ msgid "Line-1"
+#~ msgstr "Linja-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Linja-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Linja-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Dixhitale-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Dixhitale-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Dixhitale-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Phone-hyrja"
+
+#~ msgid "Phone-out"
+#~ msgstr "Phone-dalja"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Radio"
+#~ msgstr "Radio"
+
+#, fuzzy
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "E pamundur hapja e dispozitivit të zërit \"%s\" për shkrim."
+
+#, fuzzy
+#~ msgid "Rear"
+#~ msgstr "Regjistrimi"
+
+#, fuzzy
+#~ msgid "Side"
+#~ msgstr "Video"
+
+#, fuzzy
+#~ msgid "Video In"
+#~ msgstr "Video"
+
+#, fuzzy
+#~ msgid "Record Gain"
+#~ msgstr "Regjistrimi"
+
+#, fuzzy
+#~ msgid "Output Gain"
+#~ msgstr "Out-gain"
+
+#, fuzzy
+#~ msgid "Microphone Boost"
+#~ msgstr "Mikrofoni"
+
+#, fuzzy
+#~ msgid "Monitor Source"
+#~ msgstr "Ekrani"
+
+#, fuzzy
+#~ msgid "Microphone Gain"
+#~ msgstr "Mikrofoni"
+
+#, fuzzy
+#~ msgid "Speaker Source"
+#~ msgstr "Zë folës"
+
+#, fuzzy
+#~ msgid "Microphone Source"
+#~ msgstr "Mikrofoni"
+
+#, fuzzy
+#~ msgid "Microphone 1"
+#~ msgstr "Mikrofoni"
+
+#, fuzzy
+#~ msgid "Microphone 2"
+#~ msgstr "Mikrofoni"
+
+#, fuzzy
+#~ msgid "Digital Out"
+#~ msgstr "Dixhitale-1"
+
+#, fuzzy
+#~ msgid "Digital In"
+#~ msgstr "Dixhitale-1"
+
+#, fuzzy
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Mikrofoni"
+
+#, fuzzy
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "E pamundur marrja e buffers nga dispozitivi \"%s\"."
+
+#~ msgid ""
+#~ "No usable colorspace element could be found.\n"
+#~ "Please install one and restart."
+#~ msgstr ""
+#~ "Nuk arrin të gjehet asnjë element ngjyra e hapësirës.\n"
+#~ "Ju lutem instaloni një dhe rinisni."
+
+#~ msgid ""
+#~ "The %s element could not be found. This element is essential for "
+#~ "playback. Please install the right plug-in and verify that it works by "
+#~ "running 'gst-inspect %s'"
+#~ msgstr ""
+#~ "E pamundur gjetja e elementit %s. Ky element është thelbësor për "
+#~ "playback. Ju lutem instaloni plug-in e duhur dhe kontrollo funksionimin "
+#~ "duke ekzekutuar 'gst-inspect %s'"
+
+#~ msgid "Device is open."
+#~ msgstr "Dispozitivi është i hapur."
+
+#~ msgid "Device is not open."
+#~ msgstr "Dispozitivi nuk është hapur."
+
+#~ msgid "No device specified."
+#~ msgstr "Nuk është përcaktuar asnjë dispozitiv."
+
+#~ msgid "Could not close vfs file \"%s\"."
+#~ msgstr "E pamundur mbyllja e file vfs \"%s\"."
+
+#~ msgid "No filename given"
+#~ msgstr "Nuk është dhënë asnjë emër file"
+
+#~ msgid "Could not open vfs file \"%s\" for writing: %s."
+#~ msgstr "E pamundur hapja e file vfs \"%s\" për shkrim: %s."
+
+#, fuzzy
+#~ msgid "No filename given."
+#~ msgstr "Nuk është dhënë asnjë emër file"
+
+#~ msgid "Could not open vfs file \"%s\" for reading."
+#~ msgstr "E pamundur hapja e file vfs \"%s\" për lexim."
+
+#~ msgid "Could not open device \"%s\" for reading."
+#~ msgstr "E pamundur hapja e dispozitivit \"%s\" për lexim."
+
+#~ msgid "Could not open device \"%s\" for writing."
+#~ msgstr "E pamundur hapja e dispozitivit \"%s\" për shkrim."
+
+#~ msgid "Device \"%s\" does not exist."
+#~ msgstr "Dispozitivi \"%s\" nuk ekziston."
+
+#~ msgid "Could not access device \"%s\", check its permissions."
+#~ msgstr ""
+#~ "E pamundur futja në dispozitivin \"%s\", kontrollo të drejtat e tij."
+
+#~ msgid "OSS device \"%s\" is already in use by another program."
+#~ msgstr ""
+#~ "Dispozitivi OSS \"%s\" është duke u përdorur nga një tjetër program."
+
+#~ msgid "Could not close video device \"%s\"."
+#~ msgstr "E pamundur mbyllja e dispozitivit video \"%s\"."
+
+#~ msgid "Could not open video device \"%s\" for writing."
+#~ msgstr "E pamundur hapja e dispozitivit video \"%s\" për shkrim."
+
+#~ msgid "Could not set audio device \"%s\" to %d Hz."
+#~ msgstr "I pamundur rregullimi i dispozitivit audio \"%s\" në %d Hz."
+
+#~ msgid "Could not configure audio device \"%s\"."
+#~ msgstr "I pamundur konfigurimi i dispozitivit të zërit \"%s\"."
+
+#~ msgid "Could not open control device \"%s\" for writing."
+#~ msgstr "E pamundur hapja e dispozitivit të kontrollit \"%s\" për shkrim."
+
+#~ msgid "Could not write to file \"%s\"."
+#~ msgstr "I pamundur shkrimi tek file \"%s\"."
+
+#~ msgid "No filename specified."
+#~ msgstr "Nuk është përcaktuar emri i file."
+
+#~ msgid "Could not open file \"%s\" for reading."
+#~ msgstr "E pamundur hapja e file \"%s\" për lexim."
+
+#~ msgid "Error closing file \"%s\"."
+#~ msgstr "Gabim gjatë mbylljes së file \"%s\"."
+
+#~ msgid "Could not open file \"%s\" for writing."
+#~ msgstr "E pamundur hapja e file \"%s\" në shkrim."
diff --git a/po/sr.po b/po/sr.po
new file mode 100644
index 0000000..3ad249b
--- /dev/null
+++ b/po/sr.po
@@ -0,0 +1,434 @@
+# Serbian translation of gst-plugins
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# This file is distributed under the same license as the gst-plugins-good package.
+# Danilo Segan <dsegan@gmx.net>, 2004.
+# Мирослав Николић <miroslavnikolic@rocketmail.com>, 2011—2016.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good-1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-03-05 09:52+0200\n"
+"Last-Translator: Мирослав Николић <miroslavnikolic@rocketmail.com>\n"
+"Language-Team: Serbian <(nothing)>\n"
+"Language: sr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+
+msgid "Jack server not found"
+msgstr "Нисам пронашао сервер утичнице"
+
+msgid "Failed to decode JPEG image"
+msgstr "Нисам успео да декодирам ЈПЕГ слику"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "„%s“ изводи „%s“"
+
+msgid "Could not connect to server"
+msgstr "Не могу да се повежем са сервером"
+
+msgid "No URL set."
+msgstr "Није подешена адреса."
+
+msgid "Could not resolve server name."
+msgstr "Не могу да решим назив сервера."
+
+msgid "Could not establish connection to server."
+msgstr "Не могу да успоставим везу са сервером."
+
+msgid "Secure connection setup failed."
+msgstr "Подешавање безбедне везе није успело."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr "Дошло је до грешке на мрежи, или је сервер неочекивано затворио везу."
+
+msgid "Server sent bad data."
+msgstr "Сервер је послао лоше податке."
+
+msgid "Server does not support seeking."
+msgstr "Сервер не подржава позиционирање."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Улазног звука нема или је неисправан, АВИ ток ће бити оштећен."
+
+msgid "This file contains no playable streams."
+msgstr "Ова датотека не садржи токове за пуштање."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Ова датотека је неисправна и не може бити пуштена."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+"Не могу да пустим ток зато што је шифрован УДП-ом „Спреман за пуштање“."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Ова датотека је оштећена и не може бити пуштена."
+
+msgid "Invalid atom size."
+msgstr "Неисправна величина атома."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Ова датотека је непотпуна и не може бити пуштена."
+
+msgid "The video in this file might not play correctly."
+msgstr "Видео у овој датотеци можда неће бити пуштен исправно."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Ова датотека садржи превише токова. Пуштам само први %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Није пронађен ниједан подржани ток. Можда ћете морати да инсталирате "
+"прикључак РТСП проширења Гстримера за токове Стварног медија."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Није пронађен ниједан подржани ток. Можда ћете морати да омогућите више "
+"протокола преноса или можда на неки други начин недостаје прави прикључак "
+"РТСП проширења ГСтримера."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Не могу да покренем звучни уређај ради пуштања. Уређај користи нека друга "
+"апликација."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Не могу да покренем аудио уређај ради пуштања. Немате овлашћење за покретање "
+"уређаја."
+
+msgid "Could not open audio device for playback."
+msgstr "Не могу да покренем звучни уређај ради пуштања."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Не могу да покренем звучни уређај ради пуштања. Ово издање система отвореног "
+"звука није подржано овим елементом."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Пуштање није подржано од стране овог звучног уређаја."
+
+msgid "Audio playback error."
+msgstr "Грешка приликом пуштања звука."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Снимање није подржано од стране овог звучног уређаја."
+
+msgid "Error recording from audio device."
+msgstr "Грешка приликом снимања са звучног уређаја."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Не могу да покренем аудио уређај ради снимања. Немате овлашћење за покретање "
+"уређаја."
+
+msgid "Could not open audio device for recording."
+msgstr "Не могу да покренем звучни уређај ради снимања."
+
+msgid "CoreAudio device not found"
+msgstr "Нисам нашао кључни уређај звука"
+
+msgid "CoreAudio device could not be opened"
+msgstr "Не могу да отворим кључни уређај звука"
+
+msgid "Record Source"
+msgstr "Извор снимања"
+
+msgid "Microphone"
+msgstr "Микрофон"
+
+msgid "Line In"
+msgstr "Линијски улаз"
+
+msgid "Internal CD"
+msgstr "Унутрашњи ЦД"
+
+msgid "SPDIF In"
+msgstr "СПДИФ улаз"
+
+msgid "AUX 1 In"
+msgstr "АУХ 1 улаз"
+
+msgid "AUX 2 In"
+msgstr "АУХ 2 улаз"
+
+msgid "Codec Loopback"
+msgstr "Повратна петља кодека"
+
+msgid "SunVTS Loopback"
+msgstr "Повратна петља СанВТС-а"
+
+msgid "Volume"
+msgstr "Јачина звука"
+
+msgid "Gain"
+msgstr "Појачање"
+
+msgid "Monitor"
+msgstr "Праћење"
+
+msgid "Built-in Speaker"
+msgstr "Уграђени звучник"
+
+msgid "Headphone"
+msgstr "Слушалице"
+
+msgid "Line Out"
+msgstr "Линијски излаз"
+
+msgid "SPDIF Out"
+msgstr "СПДИФ излаз"
+
+msgid "AUX 1 Out"
+msgstr "АУХ 1 излаз"
+
+msgid "AUX 2 Out"
+msgstr "АУХ 2 излаз"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Грешка приликом читања %d бајтова са уређаја „%s“."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Нисам успео да нумеришем могући уређај записа снимка „%s“ са којим може да "
+"ради"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Не могу да мапирам помоћне меморије са уређаја „%s“"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Управљачки програм уређаја „%s“ не подржава УИ начин %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Управљачки програм уређаја „%s“ не подржава ниједан познати УИ начин."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Уређај „%s“ је заузет"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Уређај „%s“ не може да снима на %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Уређај „%s“ не може да снима у наведеном запису"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Уређај „%s“ не подржава не-непрекидне равни"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Не могу да добавим параметре на уређају „%s“"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "Видео уређај не прихвата нове поставке протока кадрова."
+
+msgid "Video device did not provide output format."
+msgstr "Видео уређај не обезбеђује излазни запис."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Видео уређај је вратио неисправне димензије."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Видео уређаји користе неподржани метод преплитања."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Видео уређаји користе неподржани запис сличице."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Нисам успео да подесим унутрашњи смештај међумеморије."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Видео уређај не предлаже величину међумеморије."
+
+msgid "No downstream pool to import from."
+msgstr "Нема смештаја доњег тока из кога увести."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Нисам успео да добавим подешавања тјунера %d на уређају „%s“."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Грешка добављања могућности за уређај „%s“."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Уређај „%s“ није тјунер."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Нисам успео да добавим радио улаз на уређају „%s“."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Нисам успео да подесим улаз %d на уређају %s."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Нисам успео да изменим стање утишаности за уређај „%s“."
+
+msgid "Failed to allocated required memory."
+msgstr "Нисам успео да доделим затражену меморију."
+
+msgid "Failed to allocate required memory."
+msgstr "Нисам успео да доделим затражену меморију."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Претварач на уређају „%s“ нема подржани улазни запис"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Претварач на уређају „%s“ нема подржани излазни запис"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Кодер на уређају „%s“ нема подржани улазни запис"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Кодер на уређају „%s“ нема подржани излазни запис"
+
+msgid "Failed to start decoding thread."
+msgstr "Нисам успео да покренем нит декодирања."
+
+msgid "Failed to process frame."
+msgstr "Нисам успео да обрадим кадар."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Грешка приликом добављања могућности за уређај „%s“: Није в4л2 управљачки "
+"програм. Проверите да ли је то в4л1 управљачки програм."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Нисам успео да пропитам својства уноса %d у уређају %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Нисам успео да добавим подешавања тјунера %d на уређају „%s“."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Нисам успео да пропитам норму на уређају „%s“."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Нисам успео да добавим својства контрола на уређају „%s“."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Не могу да распознам уређај „%s“."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Ово није уређај „%s“."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Не могу да покренем уређај „%s“ ради читања и уписа."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Уређај „%s“ није уређај за снимање."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Уређај „%s“ није излазни уређај."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Уређај „%s“ није М2М уређај."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Не могу да удвостручим уређај „%s“ ради читања и уписа."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Нисам успео да подесим норму за уређај „%s“."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Нисам успео да добавим текућу учестаност тјунера за уређај „%s“."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Нисам успео да подесим текућу учестаност тјунера за уређај „%s“ на %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Нисам успео да добавим јачину сигнала за уређај „%s“."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Нисам успео да добавим вредност за контролу %d на уређају „%s“."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Нисам успео да подесим вредност %d за контролу %d на уређају „%s“."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Нисам успео да добавим текући улаз на уређају „%s“. Можда је то радио уређај."
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Нисам успео да добавим текући излаз на уређају „%s“. Можда је то радио "
+"уређај."
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Нисам успео да подесим излаз %d на уређају %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Промена резолуције приликом извршавања још увек није подржана."
+
+msgid "Cannot operate without a clock"
+msgstr "Не могу да радим без сата"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Унутрашња грешка тока података."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Унутрaшња грешка протока података."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Уређај „%s“ не подржава видео снимање"
diff --git a/po/sv.po b/po/sv.po
new file mode 100644
index 0000000..7172627
--- /dev/null
+++ b/po/sv.po
@@ -0,0 +1,443 @@
+# Swedish messages for gst-plugins-good.
+# Copyright © 2007-2016 Free Software Foundation, Inc.
+# This file is distributed under the same license as the gst-plugins-good package.
+# Christian Rose <menthos@menthos.com>, 2004.
+# Daniel Nylander <po@danielnylander.se>, 2007, 2008, 2009, 2010, 2011.
+# Sebastian Rasmussen <sebras@gmail.com>, 2014, 2015, 2016.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-02-20 16:13+0100\n"
+"Last-Translator: Sebastian Rasmussen <sebras@gmail.com>\n"
+"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
+"Language: sv\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.8.7\n"
+
+msgid "Jack server not found"
+msgstr "Jack-server hittades ej"
+
+msgid "Failed to decode JPEG image"
+msgstr "Misslyckades med att avkoda JPEG-bild"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "\"%s\" av \"%s\""
+
+msgid "Could not connect to server"
+msgstr "Kunde inte ansluta till servern"
+
+msgid "No URL set."
+msgstr "Ingen URL inställd."
+
+msgid "Could not resolve server name."
+msgstr "Kunde inte slå upp servernamnet."
+
+msgid "Could not establish connection to server."
+msgstr "Kunde inte etablera anslutning till servern."
+
+msgid "Secure connection setup failed."
+msgstr "Säker anslutning misslyckades."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr "Ett nätverksfel inträffade eller servern stängde anslutningen oväntat."
+
+msgid "Server sent bad data."
+msgstr "Servern skickade felaktigt data."
+
+msgid "Server does not support seeking."
+msgstr "Servern stöder inte sökning/spolning."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Inget eller ogiltigt ingångsljud. AVI-strömmen kommer att skadas."
+
+msgid "This file contains no playable streams."
+msgstr "Den här filen innehåller inga uppspelningsbara strömmar."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Den här filen är ogiltig och kan inte spelas upp."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr "Kan ej spela ström då den är krypterad med PlayReady DRM."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Den här filen är skadad och kan inte spelas upp."
+
+msgid "Invalid atom size."
+msgstr "Ogiltig atomstorlek."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Den här filen är inte fullständig och kan inte spelas upp."
+
+msgid "The video in this file might not play correctly."
+msgstr "Videon i den här filen kanske inte kan spelas upp korrekt."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+"Den här filen innehåller för många strömmar. Spelar endast upp de första %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Ingen ström som stöds hittades. Du kanske behöver installera en GStreamer-"
+"insticksmodul för RTSP för Real Media-strömmar."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Ingen ström som stöds hittades. Du kanske behöver tillåta fler "
+"transportprotokoll eller så saknar du kanske det rätta GStreamer-tillägget "
+"för RTSP."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Kunde inte öppna ljudenheten för uppspelning. Enheten används av ett annat "
+"program."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Kunde inte öppna ljudenheten för uppspelning. Du har inte behörighet att "
+"öppna enheten."
+
+msgid "Could not open audio device for playback."
+msgstr "Kunde inte öppna ljudenheten för uppspelning."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Kunde inte öppna ljudenheten för uppspelning. Denna version av Open Sound "
+"System stöds inte av detta element."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Uppspelning stöds inte av denna ljudenhet."
+
+msgid "Audio playback error."
+msgstr "Fel vid ljuduppspelning."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Inspelning stöds inte av denna ljudenhet."
+
+msgid "Error recording from audio device."
+msgstr "Fel vid inspelning från ljudenheten."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Kunde inte öppna ljudenheten för inspelning. Du har inte behörighet att "
+"öppna enheten."
+
+msgid "Could not open audio device for recording."
+msgstr "Kunde inte öppna ljudenheten för inspelning."
+
+msgid "CoreAudio device not found"
+msgstr "CoreAudio-enhet hittades inte"
+
+msgid "CoreAudio device could not be opened"
+msgstr "CoreAudio-enhet kunde inte öppnas"
+
+msgid "Record Source"
+msgstr "Inspelningskälla"
+
+msgid "Microphone"
+msgstr "Mikrofon"
+
+msgid "Line In"
+msgstr "Linje-In"
+
+msgid "Internal CD"
+msgstr "Intern cd-spelare"
+
+msgid "SPDIF In"
+msgstr "SPDIF In"
+
+msgid "AUX 1 In"
+msgstr "AUX 1 In"
+
+msgid "AUX 2 In"
+msgstr "AUX 2 In"
+
+msgid "Codec Loopback"
+msgstr "Omkodar-återkopplingsslinga"
+
+msgid "SunVTS Loopback"
+msgstr "SunVTS-återkopplingsslinga"
+
+msgid "Volume"
+msgstr "Volym"
+
+msgid "Gain"
+msgstr "Förstärk"
+
+msgid "Monitor"
+msgstr "Monitor"
+
+msgid "Built-in Speaker"
+msgstr "Inbyggd högtalare"
+
+msgid "Headphone"
+msgstr "Hörlur"
+
+msgid "Line Out"
+msgstr "Linje ut"
+
+msgid "SPDIF Out"
+msgstr "SPDIF ut"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1 ut"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2 ut"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Fel vid läsning av %d byte från enheten \"%s\"."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Misslyckades med att räkna upp möjliga videoformat som enheten \"%s\" kan "
+"arbeta med"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Kunde inte mappa buffertar från enheten \"%s\"."
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Drivrutinen för enheten \"%s\" stöder inte IO-metod %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "Drivrutinen för enheten \"%s\" stöder inte någon känd IO-metod."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Enheten \"%s\" är upptagen"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Enheten \"%s\" kan inte fånga i %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Enheten \"%s\" kan inte fånga i det angivna formatet"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Enheten \"%s\" stöder inte icke-kontinuerliga plan"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Kunde inte få tag i parametrar på enheten \"%s\""
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "Videoenheten accepterade inte ny inställning för bildfrekvens."
+
+msgid "Video device did not provide output format."
+msgstr "Videoenheten tillhandahöll inget utgångsformat."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Videoenheten returnerade ogiltiga dimensioner."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Videoenheter använder en sammanflätningsmetod som ej stöds."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Videoenheter använder ett pixel-format som ej stöds."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Misslyckades med att konfigurera intern buffert-pool."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Videoenheten föreslog inte ny buffertstorlek."
+
+msgid "No downstream pool to import from."
+msgstr "Ingen nedströms-pool att importera från."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr ""
+"Misslyckades med att få tag i inställningarna för mottagare %d på enheten "
+"\"%s\"."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Fel vid läsning av förmågor för enheten \"%s\"."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Enheten \"%s\" är ingen mottagare."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Kunde inte ställa in radioingång på enheten \"%s\"."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Kunde inte ställa in ingång %d på enheten %s."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Misslyckades med att ändra på ljudlös-läge för enheten \"%s\"."
+
+msgid "Failed to allocated required memory."
+msgstr "Misslyckades att allokera begärt minne."
+
+msgid "Failed to allocate required memory."
+msgstr "Misslyckades med att allokera begärt minne."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Konvertorn på enheten %s har inget ingångsformat som stöds"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Konvertorn på enheten %s har inget utgångsformat som stöds"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Kodaren på enheten %s har inget ingångsformat som stöds"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Kodaren på enheten %s har inget utgångsformat som stöds"
+
+msgid "Failed to start decoding thread."
+msgstr "Misslyckades med att starta avkodningstråd."
+
+msgid "Failed to process frame."
+msgstr "Misslyckades att behandla ram."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Fel vid läsning av förmågor för enheten \"%s\": Det är inte en v4l2-"
+"drivrutin. Kontrollera om det är en v4l1-drivrutin."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Misslyckades med att fråga efter attribut för ingång %d i enheten %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr ""
+"Misslyckades med att få tag i inställningen för mottagare %d på enheten \"%s"
+"\"."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Misslyckades med att fråga efter norm på enheten \"%s\"."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Misslyckades med att få tag på kontrollattributen på enheten \"%s\"."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Kunde inte identifiera enheten \"%s\"."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Det här är inte en enhet \"%s\"."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Kunde inte öppna enheten \"%s\" för läsning och skrivning."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Enheten \"%s\" är ingen fångstenhet."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Enheten \"%s\" är ingen utgångsenhet."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Enheten \"%s\" är ingen M2M-enhet."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Kunde inte duplicera enheten \"%s\" för läsning och skrivning."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Misslyckades med att ställa in norm för enheten \"%s\"."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+"Misslyckades med att gå tag på aktuell mottagarfrekvens för enheten \"%s\"."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Misslyckades med att ställa in aktuell mottagarfrekvens för enheten \"%s\" "
+"till %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Misslyckades med att få tag på signalstyrka för enheten \"%s\"."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr ""
+"Misslyckades med att få tag på värdet för kontrollen %d på enheten \"%s\"."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Kunde inte ställa in värdet %d för kontrollen %d på enheten \"%s\"."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Misslyckades med att få tag på aktuell ingång på enheten \"%s\". Kan vara en "
+"radioenhet"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Misslyckades med att få tag på aktuell utgång på enheten \"%s\". Kan vara en "
+"radioenhet"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Misslyckades med att ställa in utgång %d på enheten %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Ändring av upplösning vid körtid stöds inte än."
+
+msgid "Cannot operate without a clock"
+msgstr "Kan inte fungera utan en klocka"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Internt fel i dataström."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Internt fel i dataflöde."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Enheten \"%s\" stöder inte videoinfångning."
diff --git a/po/tr.po b/po/tr.po
new file mode 100644
index 0000000..a4bba62
--- /dev/null
+++ b/po/tr.po
@@ -0,0 +1,808 @@
+# translation of gst-plugins-good-1.0.3.po to Turkish
+# This file is put in the public domain.
+# This file is distributed under the same license as the gst-plugins-good package.
+# Server Acim <serveracim@gmail.com>, 2010.
+# Server Acim <serveracim@gmail.com>, 2011.
+# Server Acim <serveracim@gmail.com>, 2013, 2015.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.4.1\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2015-01-10 21:07+0100\n"
+"Last-Translator: Volkan Gezer <volkangezer@gmail.com>\n"
+"Language-Team: Turkish <gnu-tr-u12a@lists.sourceforge.net>\n"
+"Language: tr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Generator: Lokalize 1.5\n"
+
+msgid "Jack server not found"
+msgstr "Jack sunucusu bulunamadı"
+
+msgid "Failed to decode JPEG image"
+msgstr "JPEG görüntüsünü çözümlenemedi"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "'%s' tarafından '%s'"
+
+msgid "Could not connect to server"
+msgstr "Sunucuya bağlanamıyor"
+
+msgid "No URL set."
+msgstr "Hiç bir URL ayarlanmamış."
+
+msgid "Could not resolve server name."
+msgstr "Sunucu adı çözümlenemiyor."
+
+msgid "Could not establish connection to server."
+msgstr "Sunucuyla bağlantı kurulumayor."
+
+msgid "Secure connection setup failed."
+msgstr "Güvenli bağlantı ayarı yapılamadı."
+
+#, fuzzy
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Bir ağ hatası meydana geldi, veya sunucu bağlantıyı beklenmeyen bir şekilde "
+"kesti."
+
+msgid "Server sent bad data."
+msgstr "Sunucu yetersiz veri gönderdi."
+
+msgid "Server does not support seeking."
+msgstr "Sunucu aramayı desteklemiyor."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "Geçerli bir ses girişi bulunamadı. AVI akışı kesilecek."
+
+msgid "This file contains no playable streams."
+msgstr "Dosya çalınabilir akışlar içermiyor."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Bu dosya geçersiz ve oynatılamaz."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr "Akış çalınamadı çünkü PlayReady DRM ile şifrelenmiş."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Bu dosya bozuk ve oynatılamaz."
+
+msgid "Invalid atom size."
+msgstr "Geçersiz atom boyutu"
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Dosya eksik ve oynatılamaz."
+
+msgid "The video in this file might not play correctly."
+msgstr "Bu dosyadaki vidyo doğru oynatılamıyabilir."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Bu dosya çok fazla akış içeriyor. Sadece ilki oynatılıyor %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Desteklenen bir akış bulunamadı. Real Media akışları için bir GStreamer RTSP "
+"uzantı eklentisi kurmalısınız."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Desteklenen akış bulunamadı. Daha fazla aktarım protokolüne izin vermeniz "
+"veya doğru GStreamer RTSP uzantı eklentisine onay vermeniz gerekebilir."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Çalmak için ses aygıtı açılamıyor. Aygıt başka bir uygulama tarafından "
+"kullanılıyor."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr "Çalmak için ses aygıtı açılamıyor. Aygıtı açma izniniz bulunmuyor."
+
+msgid "Could not open audio device for playback."
+msgstr "Çalmak için ses aygıtı açılamıyor."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Çalma için ses aygıtı açılamıyor. Açık Ses Sistemi'nin bu sürümü, bu öğeyi "
+"desteklemiyor."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Bu ses aygıtı çalmayı desteklemiyor."
+
+msgid "Audio playback error."
+msgstr "Ses çalma hatası."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Bu ses aygıtı kaydetmeyi desteklemiyor."
+
+msgid "Error recording from audio device."
+msgstr "Ses aygıtından kaydetmekte hata."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr "Kayıt için aygıtı açamıyor. Aygıtı açmak için yetkiniz yok."
+
+msgid "Could not open audio device for recording."
+msgstr "Aygıtı kayıt için açamıyor."
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "Kayıt Kaynağı"
+
+msgid "Microphone"
+msgstr "Mikrofon"
+
+msgid "Line In"
+msgstr "Hat Girişi"
+
+msgid "Internal CD"
+msgstr "Dahili CD"
+
+msgid "SPDIF In"
+msgstr "SPDIF Girişi"
+
+msgid "AUX 1 In"
+msgstr "AUX 1 Giriş"
+
+msgid "AUX 2 In"
+msgstr "AUX 2 Giriş"
+
+msgid "Codec Loopback"
+msgstr "Kodek Geridönüşü"
+
+msgid "SunVTS Loopback"
+msgstr "SunVTS Geridönüşü"
+
+msgid "Volume"
+msgstr "Ses Girişi"
+
+msgid "Gain"
+msgstr "Kazanç"
+
+msgid "Monitor"
+msgstr "Hoparlör"
+
+msgid "Built-in Speaker"
+msgstr "Varsayılan Hoparlör"
+
+msgid "Headphone"
+msgstr "Kulaklık"
+
+msgid "Line Out"
+msgstr "Hat Çıkışı"
+
+msgid "SPDIF Out"
+msgstr "SPDIF Çıkış"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1 Çıkış"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2 Çıkış"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "%d bayt bilgili '%s' aygıtından okumada hata."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr "Aygıtın '%s' birlikte çalışabileceği vidyo kiplerini sıralamada hata"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Aygıttan '%s' bellekler eşlenemiyor"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Bu aygıtın sürücüsü '%s' IO yöntemini desteklemiyor %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"Bu aygıtın sürücüsü '%s' bilinen IO yöntemlerinden herhangi birisini "
+"desteklemiyor."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Aygıt '%s' meşgul"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Aygıt '%s' görüntü yakalayamadı%dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Aygıt '%s' belirtilen kipte görüntü yakalayamadı"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Aygıt '%s' bitişik olmayan düzlemleri desteklemiyor"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Değiştirgeler aygıttan '%s' alınamıyor"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "Vidyo aygıtı yeni çerçeve oranı ayarlarını kabul etmedi."
+
+msgid "Video device did not provide output format."
+msgstr "Video aygıtı çıktı biçimini sağlamadı."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Video aygıtı geçersiz boyutlar döndü."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Video aygıtları desteklenmeyen bir birbirine geçme yöntemi kullanıyor."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Video aygıtları desteklenmeyen bir piksel biçimini kullanıyor."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "İç tampon bellek havuzu yapılandırılamıyor."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Video aygıtı herhangi bir tampon bellek boyutu önermedi."
+
+msgid "No downstream pool to import from."
+msgstr "İçeri aktarılacak akıntı havuzu yok."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "İstasyon ayarlarını bulma işlemi %d şu aygıtta '%s' başarılamadı."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Bu aygıt için kapasite bilgisi alınamadı '%s'."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Aygıt '%s' bir radyo değil."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Radyo giriş değeri şu aygıtta '%s' ayarlanamadı."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Giriş değeri olarak bu %d şu aygıtta %s ayarlanamadı."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Aygıt '%s' susturulmaya ayarlanamadı."
+
+msgid "Failed to allocated required memory."
+msgstr "Gerekli bellek ayrılamadı."
+
+msgid "Failed to allocate required memory."
+msgstr "Gerekli bellek ayrılamıyor."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Aygıt %s üzerindeki dönüştürücü girdi biçimini desteklemiyor"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Aygıt %s üzerindeki dönüştürücü çıktı biçimini desteklemiyor"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Aygıt %s üzerindeki kodlayıcı girdi biçimini deskteklemiyor"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Aygıt %s üzerindeki kodlayıcı çıktı biçimini deskteklemiyor"
+
+msgid "Failed to start decoding thread."
+msgstr "Çözme işi başlaması başarısız."
+
+msgid "Failed to process frame."
+msgstr "İşlem çerçevesi başarısız."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Şu aygıtın '%s' özelliklerini almada hata: O bir v4l2 sürücüsü değil. Onun "
+"bir v4l1 sürücüsü olup olmadığını denetleyin."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Giriş davranışları sorgusu %d şu aygıtta %s başarılamadı"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Radyo istasyonu ayarlarını bulma %d şu aygıtta '%s' başarılamadı."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Şu aygıtta '%s' sorgu normuna erişilemedi."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Denetim davranışları şu aygıtta '%s' bulunamadı."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Aygıt tanımlanamıyor '%s'."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Bu bir aygıt değil'%s'."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Şu aygıtı '%s' okuma ve yazma için açamıyor."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Aygıt '%s' bir yakalama aygıtı değil."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Aygıt '%s' bir çıkış aygıtı değil."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Aygıt '%s' bir M2M aygıtı değil."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Okuma ve yazma için '%s' aygıtı kopyalanamadı."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Aygıt için '%s' norm değerleri ayarlanamadı."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Aygıt için '%s' radyo frekansları ayarlanamadı."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr "Aygıt için '%s' radyo frekansı %lu Hz için yapılamadı."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Aygıt için '%s' güçlü sinyal alımı gerçekleşemedi."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Denetim değeri şuna %d bu aygıtta '%s' ayarlanamadı."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Değer %d denetim için %d şu aygıtta '%s' ayarlanamadı."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Şu aygıtta '%s' geçerli giriş elde edilemedi. O bir radyo aygıtı olabilir."
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Şu aygıtta '%s' geçerli giriş elde edilemedi. O bir radyo aygıtı olabilir."
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Çıkış değeri olarak %d şu aygıtta %s elde edilemedi."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Çalışırken çözünürlüğü değiştirmek henüz desteklenmiyor."
+
+msgid "Cannot operate without a clock"
+msgstr "Saat olmadan çalışamaz"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "İç veri akım hatası."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "İç veri akış hatası."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Aygıt '%s' video yakalamayı desteklemiyor"
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Ses sunucusuyla bağlantı kurulumayor"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Ses sunucusu olanakları sorgulanamadı"
+
+#~ msgid "Bass"
+#~ msgstr "Bas"
+
+#~ msgid "Treble"
+#~ msgstr "Tiz"
+
+#~ msgid "Synth"
+#~ msgstr "Synthisizer"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Hoparlör"
+
+#~ msgid "Line-in"
+#~ msgstr "Hat girişi"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Karıştırıcı"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Kayıt"
+
+#~ msgid "In-gain"
+#~ msgstr "Kazanç-girişi"
+
+#~ msgid "Out-gain"
+#~ msgstr "Kazanç-çıkışı"
+
+#~ msgid "Line-1"
+#~ msgstr "Hat-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Hat-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Hat-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Sayısal-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Sayısal-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Sayısal-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Fono-giriş"
+
+#~ msgid "Phone-out"
+#~ msgstr "Fono-çıkış"
+
+#~ msgid "Video"
+#~ msgstr "Vidyo"
+
+#~ msgid "Radio"
+#~ msgstr "Radyo"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "Mikser denetimi için ses aygıtı açılamıyor."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Mikser denetimi için ses aygıtı açılamıyor. Açık Ses Sisteminin bu "
+#~ "sürümü, bu öğeyi desteklemiyor."
+
+#~ msgid "Master"
+#~ msgstr "Master"
+
+#~ msgid "Front"
+#~ msgstr "Ön"
+
+#~ msgid "Rear"
+#~ msgstr "Arka"
+
+#~ msgid "Headphones"
+#~ msgstr "Kulaklıklar"
+
+#~ msgid "Center"
+#~ msgstr "Merkez"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Surround"
+
+#~ msgid "Side"
+#~ msgstr "Yan"
+
+#~ msgid "AUX Out"
+#~ msgstr "AUX Çıkış"
+
+#~ msgid "3D Depth"
+#~ msgstr "3D Derinlik"
+
+#~ msgid "3D Center"
+#~ msgstr "3D Merkez"
+
+#~ msgid "3D Enhance"
+#~ msgstr "3D Genişlik"
+
+#~ msgid "Telephone"
+#~ msgstr "Telefon"
+
+#~ msgid "Video In"
+#~ msgstr "Vidyo Girişi"
+
+#~ msgid "AUX In"
+#~ msgstr "AUX Giriş"
+
+#~ msgid "Record Gain"
+#~ msgstr "Kayıt Kazancı"
+
+#~ msgid "Output Gain"
+#~ msgstr "Çıkış Kazancı"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Mikrofon Seviye Yükseltme"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Ayarlar"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Bass Arttırım"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Çalma Portları"
+
+#~ msgid "Input"
+#~ msgstr "Giriş"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Hoparlör Kaynağı"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Klavye Biplemesi"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Stereo Simülasyonu"
+
+#~ msgid "Stereo"
+#~ msgstr "Stereo"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Surround Sesi"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Mikrofon Kazancı"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Hoparlör Kaynağı"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Mikrofon Kaynağı"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Merkez / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Stereo Mix"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Mono Mix"
+
+#~ msgid "Input Mix"
+#~ msgstr "Giriş Mix"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Mikrofon 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Mikrofon 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Sayısal Çıkış"
+
+#~ msgid "Digital In"
+#~ msgstr "Sayısal Giriş"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modem"
+
+#~ msgid "Handset"
+#~ msgstr "Ahize"
+
+#~ msgid "Other"
+#~ msgstr "Diğer"
+
+#~ msgid "None"
+#~ msgstr "Hiçbiri"
+
+#~ msgid "On"
+#~ msgstr "Açık"
+
+#~ msgid "Off"
+#~ msgstr "Kapalı"
+
+#~ msgid "Mute"
+#~ msgstr "Sustulurmuş"
+
+#~ msgid "Fast"
+#~ msgstr "Hızlı"
+
+#~ msgid "Very Low"
+#~ msgstr "Çok Kalın"
+
+#~ msgid "Low"
+#~ msgstr "D"
+
+#~ msgid "Medium"
+#~ msgstr "Orta"
+
+#~ msgid "High"
+#~ msgstr "Tiz"
+
+#~ msgid "Very High"
+#~ msgstr "Çok Tiz"
+
+#~ msgid "Production"
+#~ msgstr "Yapım"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Ön Panel Mikrofonu"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Ön Panel Hat Girişi"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Ön Panel Kulaklıklar"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Ön Panel Hat Çıkışı"
+
+#~ msgid "Green Connector"
+#~ msgstr "Yeşil Konnektör"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Pembe Konnektör"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Mavi Konnektör"
+
+#~ msgid "White Connector"
+#~ msgstr "Beyaz Konnektör"
+
+#~ msgid "Black Connector"
+#~ msgstr "Siyah Konnektör"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Gri Konnektör"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Portakal Konnektör"
+
+#~ msgid "Red Connector"
+#~ msgstr "Kırmızı Konnektör"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Sarı Konnektör"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Yeşil Ön Panel Konnektör"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Pembe Ön Panel Konnektör"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Mavi Ön Panel Konnektör"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Beyaz Ön Panel Konnektör"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Siyah Ön Panel Konnektör"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Gri Ön Panel Konnektör"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Portakal Ön Panel Konnektör"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Kırmızı Ön Panel Konnektör"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Sarı Ön Panel Konnektör"
+
+#~ msgid "Spread Output"
+#~ msgstr "Çıkışı Dağıt"
+
+#~ msgid "Downmix"
+#~ msgstr "Miks Edilmiş"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Sanal Mikser Girişi"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Sanal Mikser Çıkışı"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Sanal Mikser Kanalları"
+
+#~ msgid "%s %d Function"
+#~ msgstr "%s %d İşlev"
+
+#~ msgid "%s Function"
+#~ msgstr "%s İşlev"
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Beklenmeyen bir çerçevece boyutu %u bunun yerine %u görüntülendi."
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "%d baytı şu aygıtta '%s' okumada hata."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Aygıtta '%s' arabellek kuyruğa sokulamıyor."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Aygıttan device '%s' vidyo çerçeveleri alınamadı."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Şu denemeden sonra %d başarılamadı. aygıt %s. sistem hatası: %s"
+
+#~ msgid ""
+#~ "The buffer type is not supported, or the index is out of bounds, or no "
+#~ "buffers have been allocated yet, or the userptr or length are invalid. "
+#~ "device %s"
+#~ msgstr ""
+#~ "Arabellek türü desteklenmiyor, veya içerik bir yere ait değil, veya "
+#~ "arabellekler henüz ayrılmamış, veya userptr veya uzunluk geçersiz. aygıt. "
+#~ "%s"
+
+#~ msgid ""
+#~ "Failed trying to get video frames from device '%s'. Not enough memory."
+#~ msgstr "Vidyo çervevesi aygıttan '%s' alınamadı. Yetersiz bellek."
+
+#~ msgid "insufficient memory to enqueue a user pointer buffer. device %s."
+#~ msgstr ""
+#~ "kullanıcı arabelleğini kuyruğa sokmak için yetersiz bellek. aygıt %s."
+
+#~ msgid "No free buffers found in the pool at index %d."
+#~ msgstr "Dizindeki %d havuzda boş bellek bulunamadı."
+
+#~ msgid "Could not get buffers from device '%s'."
+#~ msgstr "Arabellek aygıttan '%s' alınamıyor."
+
+#~ msgid "Could not get enough buffers from device '%s'."
+#~ msgstr "Yeterli bellek aygıttan '%s' alınamıyor."
+
+#~ msgid "Error starting streaming capture from device '%s'."
+#~ msgstr "Aygıttan '%s' akan görüntü başlatılamadı."
+
+#~ msgid "Error stopping streaming capture from device '%s'."
+#~ msgstr "Aygıttan '%s' akan görüntü durdurulamadı."
diff --git a/po/uk.po b/po/uk.po
new file mode 100644
index 0000000..fe1cf79
--- /dev/null
+++ b/po/uk.po
@@ -0,0 +1,850 @@
+# Ukrainian translation to gst-plugins.
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# This file is distributed under the same license as the gst-plugins-good package.
+#
+# Maxim V. Dziumanenko <dziumanenko@gmail.com>, 2004-2007.
+# Yuri Chornoivan <yurchor@ukr.net>, 2011, 2012, 2013, 2014, 2015, 2016.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-02-20 17:27+0200\n"
+"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
+"Language-Team: Ukrainian <translation-team-uk@lists.sourceforge.net>\n"
+"Language: uk\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Lokalize 1.5\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+msgid "Jack server not found"
+msgstr "Не знайдено сервера Jack"
+
+msgid "Failed to decode JPEG image"
+msgstr "Помилка при декодуванні зображення JPEG"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "«%s», %s"
+
+msgid "Could not connect to server"
+msgstr "Не вдалося з'єднатись з сервером"
+
+msgid "No URL set."
+msgstr "Не вказано адресу"
+
+msgid "Could not resolve server name."
+msgstr "Не вдалося визначити адресу сервера за назвою."
+
+msgid "Could not establish connection to server."
+msgstr "Не вдалося встановити з'єднання з сервером."
+
+msgid "Secure connection setup failed."
+msgstr "Помилка під час спроби налаштування безпечного з’єднання."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+"Сталася помилка роботи з мережею або з’єднання було несподівано розірвано з "
+"боку сервера."
+
+msgid "Server sent bad data."
+msgstr "Сервером надіслано помилкові дані."
+
+msgid "Server does not support seeking."
+msgstr "Сервером не підтримується позиціювання."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr ""
+"Не вказано або вказано некоректний вхід звукових даних, AVI-потік буде "
+"пошкоджено."
+
+msgid "This file contains no playable streams."
+msgstr "Файл не містить потоків, які можна відтворити."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Файл є некоректним, його не можна відтворити."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+"Відтворення потоку даних неможливе, оскільки дані зашифровано за допомогою "
+"PlayReady DRM."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Файл пошкоджено, його не можна відтворити."
+
+msgid "Invalid atom size."
+msgstr "Некоректний розмір елементарного фрагмента."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Файл неповний, його не можна відтворити."
+
+msgid "The video in this file might not play correctly."
+msgstr ""
+"Ймовірно, відеодані цього файла не можна буде відтворити належним чином."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Файл містить надто багато потоків. Відтворюються лише перші %d"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Не знайдено підтримуваних потоків. Ймовірно, вам слід встановити модуль RTSP "
+"GStreamer для відтворення потоків Real media."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Не знайдено підтримуваних потоків. Ймовірно, вам слід увімкнути додаткові "
+"протоколи передавання даних або встановити додатковий модуль RTSP GStreamer."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Не вдалося відкрити пристрій для відтворення. Пристрій використовується "
+"сторонньою програмою."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Не вдалося відкрити пристрій для відтворення. У вас недостатньо прав для "
+"відкриття пристрою."
+
+msgid "Could not open audio device for playback."
+msgstr "Не вдалося відкрити пристрій для відтворення."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Не вдалося відкрити пристрій для відтворення. Ця версія Open Sound System не "
+"підтримується цим елементом."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Відтворення не підтримується цим звуковим пристроєм."
+
+msgid "Audio playback error."
+msgstr "Помилка відтворення звуку."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Запис не підтримується цим звуковим пристроєм."
+
+msgid "Error recording from audio device."
+msgstr "Помилка записування зі звукового пристрою."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Не вдалося відкрити пристрій для запису. У вас недостатньо прав для "
+"відкриття пристрою."
+
+msgid "Could not open audio device for recording."
+msgstr "Не вдалося відкрити пристрій для запису."
+
+msgid "CoreAudio device not found"
+msgstr "Пристрій CoreAudio не знайдено"
+
+msgid "CoreAudio device could not be opened"
+msgstr "Не вдалося відкрити пристрій CoreAudio"
+
+msgid "Record Source"
+msgstr "Запис джерела"
+
+msgid "Microphone"
+msgstr "Мікрофон"
+
+msgid "Line In"
+msgstr "Лінійний вхід"
+
+msgid "Internal CD"
+msgstr "Вбудований КД"
+
+msgid "SPDIF In"
+msgstr "Вхід SPDIF"
+
+msgid "AUX 1 In"
+msgstr "Вхід AUX 1"
+
+msgid "AUX 2 In"
+msgstr "Вхід AUX 2"
+
+msgid "Codec Loopback"
+msgstr "Петля кодека"
+
+msgid "SunVTS Loopback"
+msgstr "Петля SunVTS"
+
+msgid "Volume"
+msgstr "Гучність"
+
+msgid "Gain"
+msgstr "Підсилення"
+
+msgid "Monitor"
+msgstr "Монітор"
+
+msgid "Built-in Speaker"
+msgstr "Вбудований динамік"
+
+msgid "Headphone"
+msgstr "Навушники"
+
+msgid "Line Out"
+msgstr "Лінійний вихід"
+
+msgid "SPDIF Out"
+msgstr "Вихід SPDIF"
+
+msgid "AUX 1 Out"
+msgstr "Вихід AUX 1"
+
+msgid "AUX 2 Out"
+msgstr "Вихід AUX 2"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Помилка під час спроби читання %d байтів з пристрою «%s»."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Не вдається отримати список усіх можливих відеоформатів, які підтримує "
+"пристрій \"%s\""
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Не вдалося пов’язати буфери з пристрою «%s»."
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Драйвер пристрою «%s» не підтримує метод введення-виведення даних %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"Драйвер пристрою «%s» не підтримує жоден відомий метод введення-виведення "
+"даних."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Пристрій «%s» зайнято"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Пристрій \"%s\" не здатний захоплювати відео у форматі %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Пристрій \"%s\" не здатний захоплювати відео у вказаному форматі"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr ""
+"У пристрої «%s» не передбачено можливості використання розривних площин"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Не вдалося отримати параметри пристрою «%s»."
+
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+"Відеопристроєм не підтримується нове значення параметра частоти кадрів."
+
+msgid "Video device did not provide output format."
+msgstr "Відеопристроєм не надано даних щодо формату виведення."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Відеопристроєм повернуто некоректні розмірності."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Драйвер пристрою «%s» не підтримує метод черезрядкового виведення."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Відеопристрій використовує непідтримуваний формат пікселів."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Не вдалося налаштувати вбудований буфер."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Відеопристроєм не запропоновано жодного розміру буфера."
+
+msgid "No downstream pool to import from."
+msgstr "Немає підлеглого буфера для імпортування даних."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "Помилка під час спроби отримання даних щодо приймача %d пристрою «%s»."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Помилка під час спроби отримання даних щодо можливостей пристрою «%s»."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Пристрій «%s» не є приймачем."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Не вдалося отримати прийняті радіодані з пристрою «%s»."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Не вдалося встановити ввід %d пристрою «%s»."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Не вдалося змінити стан вимикання звуку на пристрої «%s»."
+
+msgid "Failed to allocated required memory."
+msgstr "Не вдалося отримати потрібний обсяг пам’яті."
+
+msgid "Failed to allocate required memory."
+msgstr "Не вдалося отримати потрібний обсяг пам’яті."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+"Засіб перетворення на пристрої %s не може отримувати дані у підтримуваному "
+"форматі"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+"Засіб перетворення на пристрої %s не може виводити дані у підтримуваному "
+"форматі"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+"Засіб кодування на пристрої %s не може отримувати дані у підтримуваному "
+"форматі"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+"Засіб кодування на пристрої %s не може виводити дані у підтримуваному форматі"
+
+msgid "Failed to start decoding thread."
+msgstr "Не вдалося започаткувати потік декодування."
+
+msgid "Failed to process frame."
+msgstr "Не вдалося обробити кадр."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Помилка при отриманні можливостей пристрою «%s»: драйвер не є драйвером для "
+"v4l2. Перевірте, може це драйвер типу v4l1."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Помилка при запиті атрибутів вводу %d пристрою %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "Помилка при встановленні приймача %d пристрою «%s»."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Помилка при запиті норми пристрою «%s»."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Не вдалося отримати атрибути регуляторів керування пристрою «%s»."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Не вдалося ідентифікувати пристрій «%s»."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Це не пристрій «%s»."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Не вдалося відкрити пристрій «%s» для читання та запису."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Пристрій «%s» не є пристроєм захоплення."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Пристрій «%s» не є пристроєм виведення даних."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Пристрій «%s» не є пристроєм M2M."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Не вдалося здублювати пристрій «%s» для читання та запису."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Не вдалося встановити норму пристрою «%s»."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "Не вдалося отримати поточну частоту приймача пристрою «%s»."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr "Не вдалося встановити поточну частоту приймача пристрою «%s» у %lu Гц."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Помилка при отриманні сили сигналу пристрою «%s»."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Не вдалося отримати значення від органу керування %d пристрою «%s»."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr ""
+"Не вдалося встановити значення %d для органу керування %d пристрою «%s»."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Не вдалося отримати поточний ввід пристрою «%s». Можливо цей пристрій — "
+"радіо."
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Не вдалося отримати поточний вихід пристрою «%s». Можливо цей пристрій — "
+"радіо."
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Не вдалося встановити вихід %d пристрою «%s»."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Зміна роздільної здатності при відтворенні ще не підтримується."
+
+msgid "Cannot operate without a clock"
+msgstr "Робота без годинника неможлива"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Внутрішня помилка потоку даних."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Помилка внутрішнього перенесення даних."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Пристрій «%s» не може захоплювати відеодані"
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Не вдалося встановити з'єднання із звуковим сервером."
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Помилка при запиті можливостей звукового сервера"
+
+#~ msgid "Bass"
+#~ msgstr "Низькі"
+
+#~ msgid "Treble"
+#~ msgstr "Високі"
+
+#~ msgid "Synth"
+#~ msgstr "Синтезатор"
+
+#~ msgid "PCM"
+#~ msgstr "КІМ"
+
+#~ msgid "Speaker"
+#~ msgstr "Динамік"
+
+#~ msgid "Line-in"
+#~ msgstr "Лінійний вхід"
+
+#~ msgid "CD"
+#~ msgstr "КД"
+
+#~ msgid "Mixer"
+#~ msgstr "Мікшер"
+
+#~ msgid "PCM-2"
+#~ msgstr "КІМ-2"
+
+#~ msgid "Record"
+#~ msgstr "Запис"
+
+#~ msgid "In-gain"
+#~ msgstr "Вх.підсилення"
+
+#~ msgid "Out-gain"
+#~ msgstr "Вих.підсилення"
+
+#~ msgid "Line-1"
+#~ msgstr "Лінійний-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Лінійний-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Лінійний-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Цифровий-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Цифровий-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Цифровий-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Вх.телефон"
+
+#~ msgid "Phone-out"
+#~ msgstr "Вих.телефон"
+
+#~ msgid "Video"
+#~ msgstr "Відео"
+
+#~ msgid "Radio"
+#~ msgstr "Радіо"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "Не вдалося відкрити пристрій для керування регуляторами мікшера."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Не вдалося відкрити пристрій для керування регуляторами мікшера. Ця "
+#~ "версія Open Sound System не підтримується цим елементом."
+
+#~ msgid "Master"
+#~ msgstr "Основний"
+
+#~ msgid "Front"
+#~ msgstr "Передній"
+
+#~ msgid "Rear"
+#~ msgstr "Задній"
+
+#~ msgid "Headphones"
+#~ msgstr "Навушники"
+
+#~ msgid "Center"
+#~ msgstr "Центральний"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Об'ємний"
+
+#~ msgid "Side"
+#~ msgstr "Боковий"
+
+#~ msgid "AUX Out"
+#~ msgstr "Вихід AUX"
+
+#~ msgid "3D Depth"
+#~ msgstr "Просторова глибина"
+
+#~ msgid "3D Center"
+#~ msgstr "Просторовий центр"
+
+#~ msgid "3D Enhance"
+#~ msgstr "Просторове покращення"
+
+#~ msgid "Telephone"
+#~ msgstr "Телефон"
+
+#~ msgid "Video In"
+#~ msgstr "Відеовхід"
+
+#~ msgid "AUX In"
+#~ msgstr "Вхід AUX"
+
+#~ msgid "Record Gain"
+#~ msgstr "Підсилення запису"
+
+#~ msgid "Output Gain"
+#~ msgstr "Підсилення виходу"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Підсилення мікрофона"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Діагностика"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Підсилення басів"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Порти відтворення"
+
+#~ msgid "Input"
+#~ msgstr "Вхід"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Спостереження за джерелом"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Гудок клавіатури"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Імітація стерео"
+
+#~ msgid "Stereo"
+#~ msgstr "Стерео"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Об'ємний звук"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Підсилення мікрофона"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Основний динамік"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Основний мікрофон"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Центральний/LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Стереомікшер"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Мономікшер"
+
+#~ msgid "Input Mix"
+#~ msgstr "Мікшер вх. даних"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Мікрофон 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Мікрофон 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Цифровий вихід"
+
+#~ msgid "Digital In"
+#~ msgstr "Цифровий вхід"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Модем"
+
+#~ msgid "Handset"
+#~ msgstr "Гарнітура"
+
+#~ msgid "Other"
+#~ msgstr "Інше"
+
+#~ msgid "None"
+#~ msgstr "Немає"
+
+#~ msgid "On"
+#~ msgstr "Увімкн."
+
+#~ msgid "Off"
+#~ msgstr "Вимкн."
+
+#~ msgid "Mute"
+#~ msgstr "Вимкнути звук"
+
+#~ msgid "Fast"
+#~ msgstr "Швидко"
+
+#~ msgid "Very Low"
+#~ msgstr "Дуже низька"
+
+#~ msgid "Low"
+#~ msgstr "Низька"
+
+#~ msgid "Medium"
+#~ msgstr "Середня"
+
+#~ msgid "High"
+#~ msgstr "Висока"
+
+#~ msgid "Very High"
+#~ msgstr "Дуже висока"
+
+#~ msgid "Production"
+#~ msgstr "Промислова"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Мікрофон передньої панелі"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Лінійний вхід передньої панелі"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Вихід навушників передньої панелі"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Лінійний вихід передньої панелі"
+
+#~ msgid "Green Connector"
+#~ msgstr "Зелений рознім"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Рожевий рознім"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Синій рознім"
+
+#~ msgid "White Connector"
+#~ msgstr "Білий рознім"
+
+#~ msgid "Black Connector"
+#~ msgstr "Чорний рознім"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Сірий рознім"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Помаранчевий рознім"
+
+#~ msgid "Red Connector"
+#~ msgstr "Червоний рознім"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Жовтий рознім"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Зелений рознім передньої панелі"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Рожевий рознім передньої панелі"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Синій рознім передньої панелі"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Білий рознім передньої панелі"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Чорний рознім передньої панелі"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Сірий рознім передньої панелі"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Помаранчевий рознім передньої панелі"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Червоний рознім передньої панелі"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Жовтий рознім передньої панелі"
+
+#~ msgid "Spread Output"
+#~ msgstr "Розгорнути вихід"
+
+#~ msgid "Downmix"
+#~ msgstr "Об’єднання каналів"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Вхід віртуального мікшера"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Вихід віртуального мікшера"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Канали віртуального мікшера"
+
+#~ msgid "%s %d Function"
+#~ msgstr "%s, функція %d"
+
+#~ msgid "%s Function"
+#~ msgstr "Функція %s"
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Отримано неочікуваний розмір блоку %u замість %u."
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Помилка під час спроби читання %d байтів на пристрої «%s»."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Не вдалося опитати буфери від пристрою «%s»."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Не вдалося отримати відеокадри з пристрою «%s»."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Помилка після %d спроб. Пристрій %s. Системна помилка: %s"
+
+#~ msgid "Could not read from CD."
+#~ msgstr "Не вдається прочитати з компакт-диску."
+
+#~ msgid "Disc is not an Audio CD."
+#~ msgstr "Диск не є аудіо компакт-диском."
+
+#~ msgid "This file is encrypted and cannot be played."
+#~ msgstr "Файл зашифрований та не може бути відтворений."
+
+#~ msgid "Failed getting controls attributes on device '%s.'"
+#~ msgstr "Не вдається отримати атрибути органів керування пристрою \"%s\"."
+
+#~ msgid ""
+#~ "The buffer type is not supported, or the index is out of bounds, or no "
+#~ "buffers have been allocated yet, or the userptr or length are invalid. "
+#~ "device %s"
+#~ msgstr ""
+#~ "Буфер цього типу не підтримується, або індекс поза межами діапазону, або "
+#~ "буфери ще не були виділені, або неправильні параметри userptr чи довжина. "
+#~ "Пристрій %s"
+
+#~ msgid ""
+#~ "Failed trying to get video frames from device '%s'. Not enough memory."
+#~ msgstr ""
+#~ "Не вдається отримати відеокадри з пристрою \"%s\". Недостатньо пам'яті."
+
+#~ msgid "insufficient memory to enqueue a user pointer buffer. device %s."
+#~ msgstr ""
+#~ "Недостатньо пам'яті для вставляння у чергу вказівника на буфер "
+#~ "користувача. Пристрій %s."
+
+#~ msgid "Could not exchange data with device '%s'."
+#~ msgstr "Помилка при обміні даними з пристроєм \"%s\"."
+
+#~ msgid "Could not set parameters on device '%s'"
+#~ msgstr "Не вдається встановити параметри пристрою \"%s\"."
+
+#~ msgid "Device '%s' cannot capture at %d/%d frames per second"
+#~ msgstr "Пристрій \"%s\" не здатний захоплювати %d/%d кадрів за секунду"
+
+#~ msgid "Could not get buffers from device '%s'."
+#~ msgstr "Не вдається отримати буфери від пристрою \"%s\"."
+
+#~ msgid "Could not get enough buffers from device '%s'."
+#~ msgstr "Не вдається отримати достатньо буферів від пристрою \"%s\"."
+
+#~ msgid "Error starting streaming capture from device '%s'."
+#~ msgstr "Не вдається розпочати захоплення кадрів з пристрою \"%s\"."
+
+#~ msgid "Error stopping streaming capture from device '%s'."
+#~ msgstr "Помилка при зупиненні захоплення кадрів з пристрою \"%s\"."
diff --git a/po/vi.po b/po/vi.po
new file mode 100644
index 0000000..7b2df7f
--- /dev/null
+++ b/po/vi.po
@@ -0,0 +1,791 @@
+# Vietnamese Translation for GST Plugins Good.
+# Bản dịch tiếng Việt dành cho GST Plugins Good.
+# Copyright © 2016 Free Software Foundation, Inc.
+# This file is distributed under the same license as the gst-plugins-good package.
+# Clytie Siddall <clytie@riverland.net.au>, 2005-2010.
+# Trần Ngọc Quân <vnwildman@gmail.com>, 2012-2014, 2015, 2016.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.7.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-02-21 07:25+0700\n"
+"Last-Translator: Trần Ngọc Quân <vnwildman@gmail.com>\n"
+"Language-Team: Vietnamese <translation-team-vi@lists.sourceforge.net>\n"
+"Language: vi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Language-Team-Website: <http://translationproject.org/team/vi.html>\n"
+"X-Generator: Gtranslator 2.91.7\n"
+
+msgid "Jack server not found"
+msgstr "Không tìm thấy máy phục vụ Jack"
+
+msgid "Failed to decode JPEG image"
+msgstr "Gặp lỗi khi giải mã ảnh JPEG"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "“%s” bởi “%s”"
+
+msgid "Could not connect to server"
+msgstr "Không thể kết nối tới máy phục vụ"
+
+msgid "No URL set."
+msgstr "Không có URL nào được đặt."
+
+msgid "Could not resolve server name."
+msgstr "Không thể phân giải tên máy phục vụ."
+
+msgid "Could not establish connection to server."
+msgstr "Không thể thiết lập kết nối tới máy chủ."
+
+msgid "Secure connection setup failed."
+msgstr "Gặp lỗi khi cài đặt kết nối an toàn."
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr "Có lỗi mạng đã xảy ra, hoặc máy chủ đóng kết nối bất ngờ."
+
+msgid "Server sent bad data."
+msgstr "Máy chủ gửi dữ liệu sai."
+
+msgid "Server does not support seeking."
+msgstr "Máy phục vụ không hỗ trợ di chuyển vị trí đọc."
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr ""
+"Chưa có dữ liệu âm thanh nhập, hoặc dữ liệu âm thanh nhập không hợp lệ. Vì "
+"thế luồng AVI sẽ hỏng."
+
+msgid "This file contains no playable streams."
+msgstr "Tập tin này không chứa luồng có thể phát."
+
+msgid "This file is invalid and cannot be played."
+msgstr "Tập tin này không hợp lệ nên không thể phát được."
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr "Không thể phát luồng dữ liệu bởi vì nó được mã hóa bằng PlayReady DRM."
+
+msgid "This file is corrupt and cannot be played."
+msgstr "Tập tin này bị hỏng nên không thể phát."
+
+msgid "Invalid atom size."
+msgstr "Kích thước nguyên tử (atom) không hợp lệ."
+
+msgid "This file is incomplete and cannot be played."
+msgstr "Tập tin này chưa hoàn thành nên không thể được phát."
+
+msgid "The video in this file might not play correctly."
+msgstr "Ảnh động trong tập tin này có thể không phát đúng."
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "Tập tin này chứa quá nhiều luồng nên chỉ phát %d đầu tiên"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"Không tìm thấy luồng được hỗ trợ. Người dùng có thể cần phải cài đặt một "
+"phần bổ sung RTSP Gstreamer để xử lý luồng nhạc/phim loại Real."
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"Không tìm thấy luồng dữ liệu được hỗ trợ. Người dùng có thể cần cho phép "
+"thêm giao thức truyền, hoặc chưa cài đặt phần bổ sung RTSP Gstreamer đúng."
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+"Không thể mở thiết bị âm thanh để phát lại. Thiết bị này đang được một ứng "
+"dụng khác sử dụng."
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+"Không thể mở thiết bị âm thanh để phát lại. Bạn không có đủ thẩm quyền để mở "
+"thiết bị này."
+
+msgid "Could not open audio device for playback."
+msgstr "Không thể mở thiết bị âm thanh để phát lại."
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr ""
+"Không thể mở thiết bị âm thanh để phát lại. Phiên bản Hệ thống Âm thanh Mở "
+"này không được yếu tố này hỗ trợ."
+
+msgid "Playback is not supported by this audio device."
+msgstr "Chức năng phát lại không phải được thiết bị âm thanh này hỗ trợ."
+
+msgid "Audio playback error."
+msgstr "Lỗi phát lại âm thanh."
+
+msgid "Recording is not supported by this audio device."
+msgstr "Chức năng thu không phải được thiết bị âm thanh này hỗ trợ."
+
+msgid "Error recording from audio device."
+msgstr "Gặp lỗi khi thu từ thiết bị âm thanh."
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+"Không thể mở thiết bị âm thanh để thu. Bạn không có quyền mở thiết bị này."
+
+msgid "Could not open audio device for recording."
+msgstr "Không thể mở thiết bị âm thanh để thu."
+
+msgid "CoreAudio device not found"
+msgstr "Không tìm thấy thiết bị CoreAudio"
+
+msgid "CoreAudio device could not be opened"
+msgstr "Không thể mở thiết bị CoreAudio"
+
+msgid "Record Source"
+msgstr "Ghi lưu nguồn"
+
+msgid "Microphone"
+msgstr "Micrô"
+
+msgid "Line In"
+msgstr "Đầu vào"
+
+msgid "Internal CD"
+msgstr "CD ở trong"
+
+msgid "SPDIF In"
+msgstr "SPDIF Vào"
+
+msgid "AUX 1 In"
+msgstr "AUX 1 Vào"
+
+msgid "AUX 2 In"
+msgstr "AUX 2 Vào"
+
+msgid "Codec Loopback"
+msgstr "Vòng ngược Codec"
+
+msgid "SunVTS Loopback"
+msgstr "Vòng ngược SunVTS"
+
+msgid "Volume"
+msgstr "Âm lượng"
+
+msgid "Gain"
+msgstr "Khuếch đại"
+
+msgid "Monitor"
+msgstr "Màn hình"
+
+msgid "Built-in Speaker"
+msgstr "Loa tích hợp"
+
+msgid "Headphone"
+msgstr "Tai nghe"
+
+msgid "Line Out"
+msgstr "Đầu ra"
+
+msgid "SPDIF Out"
+msgstr "SPDIF Ra"
+
+msgid "AUX 1 Out"
+msgstr "AUX 1 Ra"
+
+msgid "AUX 2 Out"
+msgstr "AUX 2 Ra"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "Gặp lỗi khi đọc %d byte từ thiết bị “%s”."
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+"Gặp lỗi khi đánh số các định dạng video có thể, mà thiết bị “%s” có thể làm "
+"việc cùng"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "Không thể ánh xạ các bộ đệm từ thiết bị “%s”."
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "Trình điều khiển của thiết bị “%s” không hỗ trợ phương pháp VR %d"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+"Trình điều khiển của thiết bị “%s” không hỗ trợ phương pháp VR đã biết nào."
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "Thiết bị “%s” đang bận"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "Thiết bị “%s” không thể chụp tại %dx%d"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "Thiết bị “%s” không thể chụp ở định dạng đã cho"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "Thiết bị “%s” không hỗ trợ chức năng “non-contiguous planes”"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "Không thể lấy các tham số về thiết bị “%s”."
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "Thiết bị video không chấp nhận cài đặt về tốc độ khung hình mới."
+
+msgid "Video device did not provide output format."
+msgstr "Thiết bị video không cung cấp định dạng xuất."
+
+msgid "Video device returned invalid dimensions."
+msgstr "Thiết bị video trả và kích thước không hợp lệ."
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "Thiết bị dùng phương pháp xen kẽ không được hỗ trợ."
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "Thiết bị video dùng định dạng điểm ảnh không được hỗ trợ."
+
+msgid "Failed to configure internal buffer pool."
+msgstr "Gặp lỗi khi cấu hình kho đệm nội tại."
+
+msgid "Video device did not suggest any buffer size."
+msgstr "Thiết bị video không đưa ra gợi ý nào về bộ đệm."
+
+msgid "No downstream pool to import from."
+msgstr "Không có bể dòng dữ liệu tải về để mà nhập vào."
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr ""
+"Gặp lỗi khi lấy các cài đặt từ thiết bị điều chỉnh cộng hưởng %d trên thiết "
+"bị “%s”."
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "Gặp lỗi khi đọc dung lượng từ thiết bị “%s”."
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "Thiết bị %s không phải thiết bị điều chỉnh cộng hưởng."
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "Gặp lỗi khi lấy đầu vào radio trên thiết bị “%s”."
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "Gặp lỗi khi đặt dữ liệu nhập %d vào thiết bị “%s”."
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "Gặp lỗi khi thay đổi trạng thái ngắt tiếng cho thiết bị “%s”."
+
+msgid "Failed to allocated required memory."
+msgstr "Gặp lỗi khi cấp phát bộ nhớ theo yêu cầu."
+
+msgid "Failed to allocate required memory."
+msgstr "Gặp lỗi khi cấp phát bộ nhớ theo yêu cầu."
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "Bộ chuyển đổi trên thiết bị %s không có định dạng đầu vào được hỗ trợ"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "Bộ chuyển đổi trên thiết bị %s không có định dạng xuất được hỗ trợ"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "Bộ mã hóa trên thiết bị “%s” không hỗ trợ định dạng đầu vào"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "Bộ giải mã trên thiết bị “%s” không hỗ trợ định dạng đầu ra"
+
+msgid "Failed to start decoding thread."
+msgstr "Gặp lỗi khi bắt đầu tiến trình giải mã."
+
+msgid "Failed to process frame."
+msgstr "Gặp lỗi khi xử lý khung."
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+"Gặp lỗi khi lấy khả năng của thiết bị “%s”. Nó không phải là trình điều "
+"khiển phiên bản 4l2. Kiểm tra xem nó có phải là trình điều khiển phiên bản "
+"4l1 không."
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "Gặp lỗi khi truy vấn các thuộc tính của đầu vào %d trong thiết bị %s"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr ""
+"Gặp lỗi khi lấy các cài đặt của bộ chỉnh cộng hưởng %d trên thiết bị “%s”."
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "Gặp lỗi khi truy vấn chỉ tiêu trên thiết bị “%s”."
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "Gặp lỗi khi lấy các thuộc tính của bộ điều khiển trên thiết bị “%s”."
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "Không thể nhận diện thiết bị “%s”."
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "Không phải là thiết bị “%s”."
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "Không thể mở thiết bị “%s” để đọc và ghi."
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "Thiết bị “%s” không phải là thiết bị ghi hình/tiếng."
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "Thiết bị “%s” không phải là thiết bị xuất ra."
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "Thiết bị “%s” không phải là thiết bị M2M."
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "Không thể nhân bản thiết bị “%s” để đọc và ghi."
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "Gặp lỗi khi đặt chỉ tiêu cho thiết bị “%s”."
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+"Gặp lỗi khi lấy tần số hiện thời của thiết bị điều chỉnh cộng hưởng cho "
+"thiết bị “%s”."
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+"Gặp lỗi khi đặt tần số hiện thời của thiết bị điều chỉnh cộng hưởng cho "
+"thiết bị “%s” là %lu Hz."
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "Gặp lỗi khi lấy biên độ tín hiệu cho thiết bị “%s”."
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "Gặp lỗi khi lấy giá trị của bộ điều khiển %d trên thiết bị “%s”."
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "Gặp lỗi khi đặt giá trị %d của bộ điều khiển %d trên thiết bị “%s”."
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+"Gặp lỗi khi lấy đầu vào hiện thời vào thiết bị “%s”. Có thể là thiết bị thu "
+"thanh."
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+"Gặp lỗi khi lấy đầu vào hiện hành trên thiết bị “%s”. Có thể nó là thiết bị "
+"vô tuyến."
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "Gặp lỗi khi đặt dữ liệu nhập %d trên thiết bị %s."
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "Chưa hỗ trợ khả năng thay đổi độ phân giải trong khi chạy."
+
+msgid "Cannot operate without a clock"
+msgstr "Không thể thao tác khi không có đồng hồ"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "Lỗi luồng dữ liệu nội bộ."
+
+#~ msgid "Internal data flow error."
+#~ msgstr "Lỗi luồng dữ liệu nội bộ."
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "Thiết bị “%s” không hỗ trợ chức năng quay video"
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "Không thể thiết lập sự kết nối tới máy phục vụ âm thanh"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "Lỗi truy vấn khả năng của máy phục vụ âm thanh"
+
+#~ msgid "Bass"
+#~ msgstr "Trầm"
+
+#~ msgid "Treble"
+#~ msgstr "Cao"
+
+#~ msgid "Synth"
+#~ msgstr "Tổng hợp"
+
+#~ msgid "PCM"
+#~ msgstr "PCM"
+
+#~ msgid "Speaker"
+#~ msgstr "Loa"
+
+#~ msgid "Line-in"
+#~ msgstr "Dây-vào"
+
+#~ msgid "CD"
+#~ msgstr "CD"
+
+#~ msgid "Mixer"
+#~ msgstr "Trộn"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "Record"
+#~ msgstr "Ghi"
+
+#~ msgid "In-gain"
+#~ msgstr "Vào-gia lượng"
+
+#~ msgid "Out-gain"
+#~ msgstr "Ra-gia lượng"
+
+#~ msgid "Line-1"
+#~ msgstr "Dây-1"
+
+#~ msgid "Line-2"
+#~ msgstr "Dây-2"
+
+#~ msgid "Line-3"
+#~ msgstr "Dây-3"
+
+#~ msgid "Digital-1"
+#~ msgstr "Đoạn biến-1"
+
+#~ msgid "Digital-2"
+#~ msgstr "Đoạn biến-2"
+
+#~ msgid "Digital-3"
+#~ msgstr "Đoạn biến-3"
+
+#~ msgid "Phone-in"
+#~ msgstr "Điện thoại-vào"
+
+#~ msgid "Phone-out"
+#~ msgstr "Điạn thoại-ra"
+
+#~ msgid "Video"
+#~ msgstr "Ảnh động"
+
+#~ msgid "Radio"
+#~ msgstr "Thu thanh"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "Không thể mở thiết bị âm thanh để quản lý điều khiển máy hòa tiếng."
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "Không thể mở thiết bị âm thanh để quản lý điều khiển máy hòa tiếng. Phiên "
+#~ "bản Hệ thống Âm thanh Mở không phải được yếu tố này hỗ trợ."
+
+#~ msgid "Master"
+#~ msgstr "Chủ"
+
+#~ msgid "Front"
+#~ msgstr "Trước"
+
+#~ msgid "Rear"
+#~ msgstr "Sau"
+
+#~ msgid "Headphones"
+#~ msgstr "Tai nghe"
+
+#~ msgid "Center"
+#~ msgstr "Tâm"
+
+#~ msgid "LFE"
+#~ msgstr "LFE"
+
+#~ msgid "Surround"
+#~ msgstr "Vòm"
+
+#~ msgid "Side"
+#~ msgstr "Bên"
+
+#~ msgid "AUX Out"
+#~ msgstr "AUX Ra"
+
+#~ msgid "3D Depth"
+#~ msgstr "Sâu ba chiều"
+
+#~ msgid "3D Center"
+#~ msgstr "Tâm ba chiều"
+
+#~ msgid "3D Enhance"
+#~ msgstr "Tăng cường ba chiều"
+
+#~ msgid "Telephone"
+#~ msgstr "Điện thoại"
+
+#~ msgid "Video In"
+#~ msgstr "Ảnh động Vào"
+
+#~ msgid "AUX In"
+#~ msgstr "AUX Vào"
+
+#~ msgid "Record Gain"
+#~ msgstr "Ghi lưu khuếch đại"
+
+#~ msgid "Output Gain"
+#~ msgstr "Khuếch đại Ra"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "Tăng máy vi âm"
+
+#~ msgid "Diagnostic"
+#~ msgstr "Chẩn đoán"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Tăng trầm"
+
+#~ msgid "Playback Ports"
+#~ msgstr "Cổng phát lại"
+
+#~ msgid "Input"
+#~ msgstr "Vào"
+
+#~ msgid "Monitor Source"
+#~ msgstr "Theo dõi nguồn"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "Bíp bàn phím"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "Mô phỏng âm lập thể"
+
+#~ msgid "Stereo"
+#~ msgstr "Âm lập thể"
+
+#~ msgid "Surround Sound"
+#~ msgstr "Âm thanh vòm"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "Khuếch đại máy vi âm"
+
+#~ msgid "Speaker Source"
+#~ msgstr "Nguồn loa"
+
+#~ msgid "Microphone Source"
+#~ msgstr "Nguồn máy vi âm"
+
+#~ msgid "Jack"
+#~ msgstr "Ổ cắm"
+
+#~ msgid "Center / LFE"
+#~ msgstr "Tâm / LFE"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "Hỏa tiếng âm lập thể"
+
+#~ msgid "Mono Mix"
+#~ msgstr "Hòa tiếng đơn nguồn"
+
+#~ msgid "Input Mix"
+#~ msgstr "Hòa tiếng đầu vào"
+
+#~ msgid "Microphone 1"
+#~ msgstr "Máy vi âm 1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "Máy vi âm 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "Điện số Ra"
+
+#~ msgid "Digital In"
+#~ msgstr "Điện số Vào"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Bộ điều giải"
+
+#~ msgid "Handset"
+#~ msgstr "Cầm tay"
+
+#~ msgid "Other"
+#~ msgstr "Khác"
+
+#~ msgid "None"
+#~ msgstr "Không có"
+
+#~ msgid "On"
+#~ msgstr "Bật"
+
+#~ msgid "Off"
+#~ msgstr "Tắt"
+
+#~ msgid "Mute"
+#~ msgstr "Câm"
+
+#~ msgid "Fast"
+#~ msgstr "Nhanh"
+
+#~ msgid "Very Low"
+#~ msgstr "Rất thấp"
+
+#~ msgid "Low"
+#~ msgstr "Thấp"
+
+#~ msgid "Medium"
+#~ msgstr "Vừa"
+
+#~ msgid "High"
+#~ msgstr "Cao"
+
+#~ msgid "Very High"
+#~ msgstr "Rất cao"
+
+#~ msgid "Production"
+#~ msgstr "Sản xuất"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "Mặt trước: Máy vi âm"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "Mặt trước: Dây Vào"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "Mặt trước: Tai nghe"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "Mặt trước: Dây Ra"
+
+#~ msgid "Green Connector"
+#~ msgstr "Đầu nối màu lục"
+
+#~ msgid "Pink Connector"
+#~ msgstr "Đầu nối màu hồng"
+
+#~ msgid "Blue Connector"
+#~ msgstr "Đầu nối màu xanh"
+
+#~ msgid "White Connector"
+#~ msgstr "Đầu nối màu trắng"
+
+#~ msgid "Black Connector"
+#~ msgstr "Đầu nối màu đen"
+
+#~ msgid "Gray Connector"
+#~ msgstr "Đầu nối màu xám"
+
+#~ msgid "Orange Connector"
+#~ msgstr "Đầu nối màu cam"
+
+#~ msgid "Red Connector"
+#~ msgstr "Đầu nối màu đỏ"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "Đầu nối màu vàng"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "Mặt trước: đầu nối màu lục"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "Mặt trước: đầu nối màu hồng"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "Mặt trước: đầu nối màu xanh"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "Mặt trước: đầu nối màu trắng"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "Mặt trước: đầu nối màu đen"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "Mặt trước: đầu nối màu xám"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "Mặt trước: đầu nối màu cam"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "Mặt trước: đầu nối màu đỏ"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Mặt trước: đầu nối màu vàng"
+
+#~ msgid "Spread Output"
+#~ msgstr "Mở rộng kết xuất"
+
+#~ msgid "Downmix"
+#~ msgstr "Hạ hòa tiếng"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "Hòa tiếng ảo : Vào"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "Hòa tiếng ảo : Ra"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "Hòa tiếng ảo : Kênh"
+
+#~ msgid "%s %d Function"
+#~ msgstr "Chức năng %s %d"
+
+#~ msgid "%s Function"
+#~ msgstr "Chức năng %s"
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "Nhận được kích cỡ khung bất thường %u, thay cho %u."
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "Gặp lỗi khi đọc %d byte trên thiết bị “%s”."
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "Không thể phụ thêm các bộ đệm vào hàng đợi trên thiết bị “%s”."
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "Lỗi khi thử lấy các khung ảnh động từ thiết bị “%s”."
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "Lỗi sau %d lần thử. Thiết bị %s. Lỗi hệ thống: %s"
diff --git a/po/zh_CN.po b/po/zh_CN.po
new file mode 100644
index 0000000..a918532
--- /dev/null
+++ b/po/zh_CN.po
@@ -0,0 +1,804 @@
+# Chinese (simplified) translation about gst-plugins-good.
+# This file is put in the public domain.
+# Funda Wang <fundawang@linux.net.cn>, 2005.
+# Ji ZhengYu <zhengyuji@gmail.com>, 2008, 2009.
+# zwpwjwtz <zwpwjwtz@126.com>, 2015.
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good 1.10.0\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2016-11-02 13:39+0800\n"
+"Last-Translator: Tianze Wang <zwpwjwtz@126.com>\n"
+"Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n"
+"Language: zh_CN\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
+"X-Generator: Poedit 1.8.9\n"
+
+msgid "Jack server not found"
+msgstr "未找到插口设备"
+
+msgid "Failed to decode JPEG image"
+msgstr "解码 JPEG 图像出错"
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr "“%2$s”的“%1$s”"
+
+msgid "Could not connect to server"
+msgstr "无法连接至服务器"
+
+msgid "No URL set."
+msgstr "未设置URL。"
+
+msgid "Could not resolve server name."
+msgstr "无法解析服务器名。"
+
+msgid "Could not establish connection to server."
+msgstr "无法建立与音频服务器的连接"
+
+msgid "Secure connection setup failed."
+msgstr "安全连接失败。"
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr "发生了网络错误,或服务器意外地关闭了连接。"
+
+msgid "Server sent bad data."
+msgstr "服务器发送了错误的数据。"
+
+msgid "Server does not support seeking."
+msgstr "设备不支持定位。"
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "没有或无效的输入音频,AVI 流将损坏。"
+
+msgid "This file contains no playable streams."
+msgstr "此文件不包含可播放的流。"
+
+msgid "This file is invalid and cannot be played."
+msgstr "此文件无效,无法播放。"
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr "无法播放流,因为它已被PlayReady DRM加密。"
+
+msgid "This file is corrupt and cannot be played."
+msgstr "此文件已损坏,无法播放。"
+
+msgid "Invalid atom size."
+msgstr "无效的原子尺寸。"
+
+msgid "This file is incomplete and cannot be played."
+msgstr "此文件不完整且无法播放。"
+
+msgid "The video in this file might not play correctly."
+msgstr "此文件中的视频可能无法正确播放。"
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr "此文件包含了太多的流。只播放前面 %d 个"
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+"未找到支持的流媒体。您可能需要安装一个 GStreamer RTSP 扩展插件来播放 Real 媒"
+"体流。"
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+"未找到支持的流媒体。您可能需要启用更多的传送协议,或者也有可能是缺少正确的 "
+"GStreamer RTSP 扩展插件。"
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr "无法打开音频设备播放音频。设备当前由另一个程序使用。"
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr "无法打开音频设备播放音频。您无权使用这一设备。"
+
+msgid "Could not open audio device for playback."
+msgstr "无法打开音频设备播放音频。"
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr "无法打开音频设备进行回放。这一版本的Open Sound System不支持此组件。"
+
+msgid "Playback is not supported by this audio device."
+msgstr "此音频设备不支持回放。"
+
+msgid "Audio playback error."
+msgstr "音频回放错误。"
+
+msgid "Recording is not supported by this audio device."
+msgstr "此音频设备不支持录音。"
+
+msgid "Error recording from audio device."
+msgstr "音频设备录音错误。"
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr "无法打开音频设备录音。您无权使用这一设备。"
+
+msgid "Could not open audio device for recording."
+msgstr "无法打开音频设备录音。"
+
+msgid "CoreAudio device not found"
+msgstr "未找到 CoreAudio 设备"
+
+msgid "CoreAudio device could not be opened"
+msgstr "无法打开 CoreAudio 设备"
+
+msgid "Record Source"
+msgstr "录音源"
+
+msgid "Microphone"
+msgstr "话筒"
+
+msgid "Line In"
+msgstr "线路输入"
+
+msgid "Internal CD"
+msgstr "内部 CD"
+
+msgid "SPDIF In"
+msgstr "SPDIF输入"
+
+msgid "AUX 1 In"
+msgstr "辅助输入 1"
+
+msgid "AUX 2 In"
+msgstr "辅助输出 2"
+
+msgid "Codec Loopback"
+msgstr "编码器回环"
+
+msgid "SunVTS Loopback"
+msgstr "SunVTS回环"
+
+msgid "Volume"
+msgstr "音量"
+
+msgid "Gain"
+msgstr "增益"
+
+msgid "Monitor"
+msgstr "监控器"
+
+msgid "Built-in Speaker"
+msgstr "内建扬声器"
+
+msgid "Headphone"
+msgstr "头戴式耳机"
+
+msgid "Line Out"
+msgstr "线路输出"
+
+msgid "SPDIF Out"
+msgstr "SPDIF输出"
+
+msgid "AUX 1 Out"
+msgstr "辅助输出 1"
+
+msgid "AUX 2 Out"
+msgstr "辅助输出 2"
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr "从设备“%2$s”中读取 %1$d 个字节时出错。"
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr "枚举设备“%s”可能支持的视频格式时出错"
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr "无法从设备“%s”中映射出缓冲区"
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr "设备“%s”的驱动不支持I/O方式 %d。"
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr "设备“%s”的驱动不支持任何已知的I/O方式。"
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr "设备“%s”正忙"
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr "设备“%s”不能在 %dx%d 处捕获"
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr "设备“%s”无法以指定格式捕获"
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr "设备“%s”不支持非连续平面"
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr "无法获取设备“%s”的参数"
+
+msgid "Video device did not accept new frame rate setting."
+msgstr "视频设备不接受新的帧率设置。"
+
+msgid "Video device did not provide output format."
+msgstr "视频设备未提供输出格式。"
+
+msgid "Video device returned invalid dimensions."
+msgstr "视频设备返回了无效的维度。"
+
+#, fuzzy
+msgid "Video device uses an unsupported interlacing method."
+msgstr "视频设备使用了不支持的隔行扫描方式。"
+
+#, fuzzy
+msgid "Video device uses an unsupported pixel format."
+msgstr "视频设备使用了不支持的像素格式。"
+
+msgid "Failed to configure internal buffer pool."
+msgstr "无法配置内部缓冲池。"
+
+msgid "Video device did not suggest any buffer size."
+msgstr "视频设备未提供任何缓冲大小。"
+
+msgid "No downstream pool to import from."
+msgstr "没有可以用于导入的下游池。"
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr "获取设备“%2$s”上微调钮“%1$d”的设置时出错。"
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr "获取设备“%s”有关信息时出错。"
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr "设备“%s”不是微调钮。"
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr "设置设备“%s”上的广播输出时出错。"
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr "设置设备 %2$s 上的输入 %1$d 时出错。"
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr "改变设备“%s”的静音状态时出错。"
+
+msgid "Failed to allocated required memory."
+msgstr "分配请求的内存失败。"
+
+msgid "Failed to allocate required memory."
+msgstr "分配请求的内存失败。"
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr "设备 %s 上的转换器没有支持的输入格式"
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr "设备 %s 上的转换器没有支持的输出格式"
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr "设备 %s 上的编码器没有支持的输入格式"
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr "设备 %s 上的编码器没有支持的输出格式"
+
+msgid "Failed to start decoding thread."
+msgstr "启动解码线程失败。"
+
+msgid "Failed to process frame."
+msgstr "处理帧失败。"
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr "获取设备“%s”的信息时出错:它不是一个 v4l2 驱动器,请检查是否为 v4l1。"
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr "查寻设备 %2$s 中的输入 %1$d 的属性时出错"
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr "获取设备 %2$s 上的微调钮 %1$d 的设置时出错"
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr "获取设备“%s”的基准时出错。"
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr "获取设备“%s”上的控制属性时出错。"
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr "无法确认设备“%s”。"
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr "不是设备“%s”。"
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr "无法打开设备“%s”读写。"
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr "“%s”不是一个捕获设备。"
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr "“%s”不是输出设备。"
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr "设备“%s”不是M2M设备。"
+
+#, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "无法复制设备“%s”来读取和写入。"
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr "设置设备“%s”的基准时出错。"
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr "获取设备“%s”的当前微调钮频率时出错。"
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr "设置设备“%s”的当前微调钮频率为 %lu Hz 时出错。"
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr "获取设备“%s”的信号长度时出错。"
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr "获取设备“%2$s”的控制器 %1$d 的值出错。"
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr "设置设备“%3$s”的控制器 %2$d 的值为 %1$d 时出错。"
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr "获取设备“%s”上的当前输入出错。也许它是一个广播设备"
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr "获取设备“%s”上的当前输入出错。它可能是一个广播设备"
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr "将输出 %d 设置到设备 %s 上失败。"
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr "尚不支持在运行时更改分辨率。"
+
+msgid "Cannot operate without a clock"
+msgstr "没有时钟的话无法操作"
+
+#~ msgid "Internal data stream error."
+#~ msgstr "内部数据流错误。"
+
+#~ msgid "Internal data flow error."
+#~ msgstr "内部数据流错误。"
+
+#~ msgid "Failed to query sound server capabilities"
+#~ msgstr "查寻音频服务器的服务失败"
+
+#~ msgid "Bass"
+#~ msgstr "低音(Bass)"
+
+#~ msgid "Treble"
+#~ msgstr "高音(Treble)"
+
+#~ msgid "Synth"
+#~ msgstr "合成器"
+
+#~ msgid "PCM"
+#~ msgstr "波形(PCM)"
+
+#~ msgid "Speaker"
+#~ msgstr "扬声器"
+
+#~ msgid "CD"
+#~ msgstr "CD 音频"
+
+#~ msgid "Mixer"
+#~ msgstr "混音器"
+
+#~ msgid "PCM-2"
+#~ msgstr "PCM-2"
+
+#~ msgid "In-gain"
+#~ msgstr "输入增益"
+
+#~ msgid "Out-gain"
+#~ msgstr "输出增益"
+
+#~ msgid "Line-1"
+#~ msgstr "线路1"
+
+#~ msgid "Line-2"
+#~ msgstr "线路2"
+
+#~ msgid "Line-3"
+#~ msgstr "线路3"
+
+#~ msgid "Digital-1"
+#~ msgstr "数字线路1"
+
+#~ msgid "Digital-2"
+#~ msgstr "数字线路2"
+
+#~ msgid "Digital-3"
+#~ msgstr "数字线路3"
+
+#~ msgid "Phone-in"
+#~ msgstr "话筒输入"
+
+#~ msgid "Phone-out"
+#~ msgstr "话筒输出"
+
+#~ msgid "Video"
+#~ msgstr "视频"
+
+#~ msgid "Radio"
+#~ msgstr "广播"
+
+#~ msgid "Got unexpected frame size of %u instead of %u."
+#~ msgstr "取得了 %u 的不需要的帧大小,而不是 %u。"
+
+#~ msgid "Error reading %d bytes on device '%s'."
+#~ msgstr "读取设备‘%2$s’中的 %1$d 字节时出错。"
+
+#~ msgid "Could not enqueue buffers in device '%s'."
+#~ msgstr "无法对设备‘%s’中的缓冲区进行排序。"
+
+#~ msgid "Failed trying to get video frames from device '%s'."
+#~ msgstr "从设备‘%s’上获取视频的尝试失败了。"
+
+#~ msgid "Failed after %d tries. device %s. system error: %s"
+#~ msgstr "在 %d 次尝试后失败。设备 %s。系统错误: %s"
+
+#~ msgid ""
+#~ "The buffer type is not supported, or the index is out of bounds, or no "
+#~ "buffers have been allocated yet, or the userptr or length are invalid. "
+#~ "device %s"
+#~ msgstr ""
+#~ "不支持的缓冲区类型,或者索引超出范围了,或是还未分配缓冲区,或非法的用户指"
+#~ "针或长度。设备 %s"
+
+#~ msgid ""
+#~ "Failed trying to get video frames from device '%s'. Not enough memory."
+#~ msgstr "从设备‘%s’上获取视频的尝试失败了。没有足够的内存。"
+
+#~ msgid "insufficient memory to enqueue a user pointer buffer. device %s."
+#~ msgstr "内存不足无法对用户指针缓冲区进行排序。设备 %s。"
+
+#~ msgid "No free buffers found in the pool at index %d."
+#~ msgstr "在内存池中 %d 处没有可分配的缓冲区。"
+
+#~ msgid "Could not get buffers from device '%s'."
+#~ msgstr "无法从设备‘%s’中获取缓冲区。"
+
+#~ msgid "Could not get enough buffers from device '%s'."
+#~ msgstr "无法从设备‘%s’中获取足够的缓冲区。"
+
+#~ msgid "Error starting streaming capture from device '%s'."
+#~ msgstr "从设备‘%s’中启用流捕获时出错。"
+
+#~ msgid "Error stopping streaming capture from device '%s'."
+#~ msgstr "从设备‘%s’中停止流捕获时出错。"
+
+#~ msgid "Failed getting controls attributes on device '%s.'"
+#~ msgstr "获取设备‘%s’上的控制属性时出错。"
+
+#~ msgid "Could not read from CD."
+#~ msgstr "无法从 CD 中读取。"
+
+#~ msgid "Disc is not an Audio CD."
+#~ msgstr "非音频 CD 盘。"
+
+#~ msgid "This file is encrypted and cannot be played."
+#~ msgstr "此文件已加密,无法播放。"
+
+#~ msgid "Device '%s' does not support video capture"
+#~ msgstr "设备“%s”不支持视频捕捉"
+
+#~ msgid "Line-in"
+#~ msgstr "线路输入"
+
+#~ msgid "Record"
+#~ msgstr "录音"
+
+#~ msgid "Could not establish connection to sound server"
+#~ msgstr "无法建立与音频服务器的连接"
+
+#~ msgid "Could not open audio device for mixer control handling."
+#~ msgstr "无法打开音频设备来进行混音器控制。"
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "无法打开音频设备来进行混音器控制。这一版本的Open Sound System不支持此组"
+#~ "件。"
+
+#~ msgid "Master"
+#~ msgstr "主"
+
+#~ msgid "Front"
+#~ msgstr "前"
+
+#~ msgid "Rear"
+#~ msgstr "后"
+
+#~ msgid "Headphones"
+#~ msgstr "头戴式耳机"
+
+#~ msgid "Center"
+#~ msgstr "中"
+
+#~ msgid "LFE"
+#~ msgstr "重低音"
+
+#~ msgid "Surround"
+#~ msgstr "环绕"
+
+#~ msgid "Side"
+#~ msgstr "侧"
+
+#~ msgid "AUX Out"
+#~ msgstr "辅助输出"
+
+#~ msgid "3D Depth"
+#~ msgstr "3D 深度"
+
+#~ msgid "3D Center"
+#~ msgstr "3D 中央"
+
+#~ msgid "3D Enhance"
+#~ msgstr "3D 增强"
+
+#~ msgid "Telephone"
+#~ msgstr "电话"
+
+#~ msgid "Video In"
+#~ msgstr "视频输入"
+
+#~ msgid "AUX In"
+#~ msgstr "辅助输出"
+
+#~ msgid "Record Gain"
+#~ msgstr "录音增益"
+
+#~ msgid "Output Gain"
+#~ msgstr "输出增益"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "麦克风增强"
+
+#~ msgid "Diagnostic"
+#~ msgstr "诊断"
+
+#~ msgid "Bass Boost"
+#~ msgstr "贝司增强"
+
+#~ msgid "Playback Ports"
+#~ msgstr "回放端口"
+
+#~ msgid "Input"
+#~ msgstr "输入"
+
+#~ msgid "Monitor Source"
+#~ msgstr "监控源"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "键盘蜂鸣"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "模拟立体声"
+
+#~ msgid "Stereo"
+#~ msgstr "立体声"
+
+#~ msgid "Surround Sound"
+#~ msgstr "环绕声"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "话筒增益"
+
+#~ msgid "Speaker Source"
+#~ msgstr "扬声器源"
+
+#~ msgid "Microphone Source"
+#~ msgstr "话筒源"
+
+#~ msgid "Jack"
+#~ msgstr "插口"
+
+#~ msgid "Center / LFE"
+#~ msgstr "中/重低音"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "立体声混音"
+
+#~ msgid "Mono Mix"
+#~ msgstr "单声道混音"
+
+#~ msgid "Input Mix"
+#~ msgstr "输入混音"
+
+#~ msgid "Microphone 1"
+#~ msgstr "话筒1"
+
+#~ msgid "Microphone 2"
+#~ msgstr "话筒2"
+
+#~ msgid "Digital Out"
+#~ msgstr "数字输出"
+
+#~ msgid "Digital In"
+#~ msgstr "数字输入"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI"
+
+#~ msgid "Modem"
+#~ msgstr "Modem"
+
+#~ msgid "Handset"
+#~ msgstr "Handset"
+
+#~ msgid "Other"
+#~ msgstr "其他"
+
+#~ msgid "None"
+#~ msgstr "无"
+
+#~ msgid "On"
+#~ msgstr "开"
+
+#~ msgid "Off"
+#~ msgstr "关"
+
+#~ msgid "Mute"
+#~ msgstr "静音"
+
+#~ msgid "Fast"
+#~ msgstr "快"
+
+#~ msgid "Very Low"
+#~ msgstr "非常低"
+
+#~ msgid "Low"
+#~ msgstr "低"
+
+#~ msgid "Medium"
+#~ msgstr "中"
+
+#~ msgid "High"
+#~ msgstr "高"
+
+#~ msgid "Very High"
+#~ msgstr "非常高"
+
+#~ msgid "Production"
+#~ msgstr "产品"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "前面板话筒"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "前面板线路输入"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "前面板头戴式耳机"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "前面板线路输出"
+
+#~ msgid "Green Connector"
+#~ msgstr "绿色插口"
+
+#~ msgid "Pink Connector"
+#~ msgstr "粉色插口"
+
+#~ msgid "Blue Connector"
+#~ msgstr "蓝色插口"
+
+#~ msgid "White Connector"
+#~ msgstr "白色插口"
+
+#~ msgid "Black Connector"
+#~ msgstr "黑色插口"
+
+#~ msgid "Gray Connector"
+#~ msgstr "灰色插口"
+
+#~ msgid "Orange Connector"
+#~ msgstr "橙色插口"
+
+#~ msgid "Red Connector"
+#~ msgstr "红色插口"
+
+#~ msgid "Yellow Connector"
+#~ msgstr "黄色插口"
+
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "前面板绿色插口"
+
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "前面板粉色插口"
+
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "前面板蓝色插口"
+
+#~ msgid "White Front Panel Connector"
+#~ msgstr "前面板白色插口"
+
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "前面板黑色插口"
+
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "前面板灰色插口"
+
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "前面板橙色插口"
+
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "前面板红色插口"
+
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "前面板黄色插口"
+
+#~ msgid "Spread Output"
+#~ msgstr "分散式输出"
+
+#~ msgid "Downmix"
+#~ msgstr "混缩"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "虚拟混音输入"
+
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "虚拟混音输出"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "虚拟混音通道"
+
+#~ msgid "%s %d Function"
+#~ msgstr "%s %d 功能"
+
+#~ msgid "%s Function"
+#~ msgstr "%s 功能"
diff --git a/po/zh_HK.po b/po/zh_HK.po
new file mode 100644
index 0000000..0504c7e
--- /dev/null
+++ b/po/zh_HK.po
@@ -0,0 +1,681 @@
+# Chinese (Hong Kong) translation of gst-plugins-good-0.10.2.
+# This file is put in the public domain.
+# Abel Cheung <abelcheung@gmail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good-0.10.2 0.10.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2006-08-29 01:08+0800\n"
+"Last-Translator: Abel Cheung <abelcheung@gmail.com>\n"
+"Language-Team: Chinese (Hong Kong) <community@linuxhall.org>\n"
+"Language: zh_HK\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr ""
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr ""
+
+msgid "Could not connect to server"
+msgstr ""
+
+msgid "No URL set."
+msgstr ""
+
+msgid "Could not resolve server name."
+msgstr ""
+
+msgid "Could not establish connection to server."
+msgstr ""
+
+msgid "Secure connection setup failed."
+msgstr ""
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+
+msgid "Server sent bad data."
+msgstr ""
+
+msgid "Server does not support seeking."
+msgstr ""
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "沒有任何輸入的音效資料或者資料無效,表示 AVI 串流出現錯誤。"
+
+msgid "This file contains no playable streams."
+msgstr ""
+
+msgid "This file is invalid and cannot be played."
+msgstr ""
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr ""
+
+msgid "Invalid atom size."
+msgstr ""
+
+msgid "This file is incomplete and cannot be played."
+msgstr ""
+
+msgid "The video in this file might not play correctly."
+msgstr ""
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+
+msgid "Could not open audio device for playback."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr "无法打开音频设备播放音频。此组件不支持开放声音系统(OSS)版本。"
+
+msgid "Playback is not supported by this audio device."
+msgstr "此音频设备不支持音频播放。"
+
+msgid "Audio playback error."
+msgstr "音频播放错误。"
+
+msgid "Recording is not supported by this audio device."
+msgstr "此音频设备不支持录音。"
+
+msgid "Error recording from audio device."
+msgstr "从音频设备录音时发生错误。"
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+
+msgid "Could not open audio device for recording."
+msgstr ""
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "录音来源"
+
+#, fuzzy
+msgid "Microphone"
+msgstr "麦克风 1"
+
+msgid "Line In"
+msgstr "线路输入"
+
+msgid "Internal CD"
+msgstr "内部 CD 音频"
+
+msgid "SPDIF In"
+msgstr "SPDIF 输入"
+
+msgid "AUX 1 In"
+msgstr "AUX 1 输入"
+
+msgid "AUX 2 In"
+msgstr "AUX 2 输入"
+
+#, fuzzy
+msgid "Codec Loopback"
+msgstr "Loopback"
+
+#, fuzzy
+msgid "SunVTS Loopback"
+msgstr "Loopback"
+
+msgid "Volume"
+msgstr ""
+
+msgid "Gain"
+msgstr ""
+
+msgid "Monitor"
+msgstr ""
+
+msgid "Built-in Speaker"
+msgstr ""
+
+msgid "Headphone"
+msgstr ""
+
+msgid "Line Out"
+msgstr ""
+
+msgid "SPDIF Out"
+msgstr ""
+
+msgid "AUX 1 Out"
+msgstr ""
+
+msgid "AUX 2 Out"
+msgstr ""
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr ""
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr ""
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr ""
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr ""
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr ""
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr ""
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr ""
+
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+
+msgid "Video device did not provide output format."
+msgstr ""
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+
+msgid "Video device uses an unsupported pixel format."
+msgstr ""
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+msgid "Video device did not suggest any buffer size."
+msgstr ""
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr ""
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr ""
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr ""
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr ""
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+
+msgid "Failed to start decoding thread."
+msgstr ""
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr ""
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr ""
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr ""
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr ""
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr ""
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "无法打开音频文件进行混音控制操作。"
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr ""
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr ""
+
+msgid "Cannot operate without a clock"
+msgstr ""
+
+#~ msgid "Internal data stream error."
+#~ msgstr "內部資料串流發生錯誤。"
+
+#, fuzzy
+#~ msgid "Internal data flow error."
+#~ msgstr "內部資料串流發生錯誤。"
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "无法打开音频设备进行音量控制操作。此部件不支持开放声音系统(OSS)的版本。"
+
+#~ msgid "Master"
+#~ msgstr "主声道"
+
+#~ msgid "Front"
+#~ msgstr "前置声道"
+
+#~ msgid "Rear"
+#~ msgstr "后置声道"
+
+#~ msgid "Headphones"
+#~ msgstr "头戴式耳机"
+
+#~ msgid "Center"
+#~ msgstr "中置"
+
+#~ msgid "LFE"
+#~ msgstr "低音炮"
+
+#~ msgid "Surround"
+#~ msgstr "立体声环绕"
+
+#~ msgid "Side"
+#~ msgstr "左右声道"
+
+#~ msgid "AUX Out"
+#~ msgstr "AUX 输出"
+
+#~ msgid "3D Depth"
+#~ msgstr "3D Depth"
+
+#~ msgid "3D Center"
+#~ msgstr "3D Center"
+
+#~ msgid "3D Enhance"
+#~ msgstr "3D Enhance"
+
+#~ msgid "Telephone"
+#~ msgstr "话筒"
+
+#~ msgid "Video In"
+#~ msgstr "视频输入"
+
+#~ msgid "AUX In"
+#~ msgstr "AUX 输入"
+
+#~ msgid "Record Gain"
+#~ msgstr "录音增益"
+
+#~ msgid "Output Gain"
+#~ msgstr "输出增益"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "麦克风增益"
+
+#, fuzzy
+#~ msgid "Diagnostic"
+#~ msgstr "采样分析"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Bass 增益"
+
+#~ msgid "Playback Ports"
+#~ msgstr "回放端口"
+
+#~ msgid "Input"
+#~ msgstr "输入"
+
+#~ msgid "Monitor Source"
+#~ msgstr "监视器来源"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "按键声音"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "模拟立体声"
+
+#~ msgid "Stereo"
+#~ msgstr "立体声"
+
+#~ msgid "Surround Sound"
+#~ msgstr "立体声环绕"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "麦克风增益"
+
+#~ msgid "Speaker Source"
+#~ msgstr "扬声器音源"
+
+#~ msgid "Microphone Source"
+#~ msgstr "麦克风音源"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+#~ msgid "Center / LFE"
+#~ msgstr "中置/低音炮"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "立体声"
+
+#~ msgid "Mono Mix"
+#~ msgstr "单声道"
+
+#~ msgid "Input Mix"
+#~ msgstr "混音输入"
+
+#~ msgid "Microphone 2"
+#~ msgstr "麦克风 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "数字输出"
+
+#~ msgid "Digital In"
+#~ msgstr "数字输入"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI(高清)"
+
+#~ msgid "Modem"
+#~ msgstr "Modem"
+
+#~ msgid "Handset"
+#~ msgstr "手持设备"
+
+#~ msgid "Other"
+#~ msgstr "其它设备"
+
+#~ msgid "None"
+#~ msgstr "无"
+
+#~ msgid "On"
+#~ msgstr "开"
+
+#~ msgid "Off"
+#~ msgstr "关"
+
+#~ msgid "Mute"
+#~ msgstr "静音"
+
+#~ msgid "Fast"
+#~ msgstr "快"
+
+#~ msgid "Very Low"
+#~ msgstr "很慢"
+
+#~ msgid "Low"
+#~ msgstr "慢"
+
+#~ msgid "Medium"
+#~ msgstr "中等"
+
+#~ msgid "High"
+#~ msgstr "高"
+
+#~ msgid "Very High"
+#~ msgstr "很高"
+
+#~ msgid "Production"
+#~ msgstr "生产商"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "麦克风面板"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "线路输入面板"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "头戴式耳机面板"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "线路输出面板"
+
+#, fuzzy
+#~ msgid "Green Connector"
+#~ msgstr "线路输出"
+
+#, fuzzy
+#~ msgid "Pink Connector"
+#~ msgstr "话筒输出"
+
+#, fuzzy
+#~ msgid "Blue Connector"
+#~ msgstr "立体声输入"
+
+#, fuzzy
+#~ msgid "White Connector"
+#~ msgstr "左/单声道"
+
+#, fuzzy
+#~ msgid "Black Connector"
+#~ msgstr "后置声道输出"
+
+#, fuzzy
+#~ msgid "Gray Connector"
+#~ msgstr "中置声道输出"
+
+#, fuzzy
+#~ msgid "Orange Connector"
+#~ msgstr "低音炮输出"
+
+#, fuzzy
+#~ msgid "Red Connector"
+#~ msgstr "右声道"
+
+#, fuzzy
+#~ msgid "Yellow Connector"
+#~ msgstr "Midi 输出/游戏摇杆"
+
+#, fuzzy
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "线路输出面板"
+
+#, fuzzy
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "话筒输出面板"
+
+#, fuzzy
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "立体声输入面板"
+
+#, fuzzy
+#~ msgid "White Front Panel Connector"
+#~ msgstr "左/单声道面板"
+
+#, fuzzy
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "后置声道输出面板"
+
+#, fuzzy
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "中置声道输出面板"
+
+#, fuzzy
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "低音炮输出面板"
+
+#, fuzzy
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "右声道面板"
+
+#, fuzzy
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Midi 输出/游戏摇杆面板"
+
+#~ msgid "Spread Output"
+#~ msgstr "Spread 输出"
+
+#~ msgid "Downmix"
+#~ msgstr "Downmix"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "模拟混音输入"
+
+#, fuzzy
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "模拟混音输出"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "模拟混音输入"
+
+#, fuzzy
+#~ msgid "%s %d Function"
+#~ msgstr "%s 功能"
+
+#~ msgid "%s Function"
+#~ msgstr "%s 功能"
diff --git a/po/zh_TW.po b/po/zh_TW.po
new file mode 100644
index 0000000..c4ae1ee
--- /dev/null
+++ b/po/zh_TW.po
@@ -0,0 +1,681 @@
+# Chinese (traditional) translation of gst-plugins-good-0.10.2.
+# This file is put in the public domain.
+# Abel Cheung <abelcheung@gmail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gst-plugins-good-0.10.2 0.10.2\n"
+"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
+"POT-Creation-Date: 2017-05-04 15:05+0300\n"
+"PO-Revision-Date: 2006-08-29 01:08+0800\n"
+"Last-Translator: Abel Cheung <abelcheung@gmail.com>\n"
+"Language-Team: Chinese (traditional) <zh-l10n@linux.org.tw>\n"
+"Language: zh_TW\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Jack server not found"
+msgstr ""
+
+msgid "Failed to decode JPEG image"
+msgstr ""
+
+#. TRANSLATORS: 'song title' by 'artist name'
+#, c-format
+msgid "'%s' by '%s'"
+msgstr ""
+
+msgid "Could not connect to server"
+msgstr ""
+
+msgid "No URL set."
+msgstr ""
+
+msgid "Could not resolve server name."
+msgstr ""
+
+msgid "Could not establish connection to server."
+msgstr ""
+
+msgid "Secure connection setup failed."
+msgstr ""
+
+msgid ""
+"A network error occurred, or the server closed the connection unexpectedly."
+msgstr ""
+
+msgid "Server sent bad data."
+msgstr ""
+
+msgid "Server does not support seeking."
+msgstr ""
+
+msgid "No or invalid input audio, AVI stream will be corrupt."
+msgstr "沒有任何輸入的音效資料或者資料無效,表示 AVI 串流出現錯誤。"
+
+msgid "This file contains no playable streams."
+msgstr ""
+
+msgid "This file is invalid and cannot be played."
+msgstr ""
+
+msgid "Cannot play stream because it is encrypted with PlayReady DRM."
+msgstr ""
+
+msgid "This file is corrupt and cannot be played."
+msgstr ""
+
+msgid "Invalid atom size."
+msgstr ""
+
+msgid "This file is incomplete and cannot be played."
+msgstr ""
+
+msgid "The video in this file might not play correctly."
+msgstr ""
+
+#, c-format
+msgid "This file contains too many streams. Only playing first %d"
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to install a GStreamer RTSP "
+"extension plugin for Real media streams."
+msgstr ""
+
+msgid ""
+"No supported stream was found. You might need to allow more transport "
+"protocols or may otherwise be missing the right GStreamer RTSP extension "
+"plugin."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. Device is being used by another "
+"application."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. You don't have permission to open "
+"the device."
+msgstr ""
+
+msgid "Could not open audio device for playback."
+msgstr ""
+
+msgid ""
+"Could not open audio device for playback. This version of the Open Sound "
+"System is not supported by this element."
+msgstr "无法打开音频设备播放音频。此组件不支持开放声音系统(OSS)版本。"
+
+msgid "Playback is not supported by this audio device."
+msgstr "此音频设备不支持音频播放。"
+
+msgid "Audio playback error."
+msgstr "音频播放错误。"
+
+msgid "Recording is not supported by this audio device."
+msgstr "此音频设备不支持录音。"
+
+msgid "Error recording from audio device."
+msgstr "从音频设备录音时发生错误。"
+
+msgid ""
+"Could not open audio device for recording. You don't have permission to open "
+"the device."
+msgstr ""
+
+msgid "Could not open audio device for recording."
+msgstr ""
+
+msgid "CoreAudio device not found"
+msgstr ""
+
+msgid "CoreAudio device could not be opened"
+msgstr ""
+
+msgid "Record Source"
+msgstr "录音来源"
+
+#, fuzzy
+msgid "Microphone"
+msgstr "麦克风 1"
+
+msgid "Line In"
+msgstr "线路输入"
+
+msgid "Internal CD"
+msgstr "内部 CD 音频"
+
+msgid "SPDIF In"
+msgstr "SPDIF 输入"
+
+msgid "AUX 1 In"
+msgstr "AUX 1 输入"
+
+msgid "AUX 2 In"
+msgstr "AUX 2 输入"
+
+#, fuzzy
+msgid "Codec Loopback"
+msgstr "Loopback"
+
+#, fuzzy
+msgid "SunVTS Loopback"
+msgstr "Loopback"
+
+msgid "Volume"
+msgstr ""
+
+msgid "Gain"
+msgstr ""
+
+msgid "Monitor"
+msgstr ""
+
+msgid "Built-in Speaker"
+msgstr ""
+
+msgid "Headphone"
+msgstr ""
+
+msgid "Line Out"
+msgstr ""
+
+msgid "SPDIF Out"
+msgstr ""
+
+msgid "AUX 1 Out"
+msgstr ""
+
+msgid "AUX 2 Out"
+msgstr ""
+
+#, c-format
+msgid "Error reading %d bytes from device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to enumerate possible video formats device '%s' can work with"
+msgstr ""
+
+#, c-format
+msgid "Could not map buffers from device '%s'"
+msgstr ""
+
+#, c-format
+msgid "The driver of device '%s' does not support the IO method %d"
+msgstr ""
+
+#, c-format
+msgid "The driver of device '%s' does not support any known IO method."
+msgstr ""
+
+#, c-format
+msgid "Device '%s' is busy"
+msgstr ""
+
+#, c-format
+msgid "Device '%s' cannot capture at %dx%d"
+msgstr ""
+
+#, c-format
+msgid "Device '%s' cannot capture in the specified format"
+msgstr ""
+
+#, c-format
+msgid "Device '%s' does support non-contiguous planes"
+msgstr ""
+
+#, c-format
+msgid "Could not get parameters on device '%s'"
+msgstr ""
+
+msgid "Video device did not accept new frame rate setting."
+msgstr ""
+
+msgid "Video device did not provide output format."
+msgstr ""
+
+msgid "Video device returned invalid dimensions."
+msgstr ""
+
+msgid "Video device uses an unsupported interlacing method."
+msgstr ""
+
+msgid "Video device uses an unsupported pixel format."
+msgstr ""
+
+msgid "Failed to configure internal buffer pool."
+msgstr ""
+
+msgid "Video device did not suggest any buffer size."
+msgstr ""
+
+msgid "No downstream pool to import from."
+msgstr ""
+
+#, c-format
+msgid "Failed to get settings of tuner %d on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Error getting capabilities for device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Device '%s' is not a tuner."
+msgstr ""
+
+#, c-format
+msgid "Failed to get radio input on device '%s'. "
+msgstr ""
+
+#, c-format
+msgid "Failed to set input %d on device %s."
+msgstr ""
+
+#, c-format
+msgid "Failed to change mute state for device '%s'."
+msgstr ""
+
+msgid "Failed to allocated required memory."
+msgstr ""
+
+msgid "Failed to allocate required memory."
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Converter on device %s has no supported output format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported input format"
+msgstr ""
+
+#, c-format
+msgid "Encoder on device %s has no supported output format"
+msgstr ""
+
+msgid "Failed to start decoding thread."
+msgstr ""
+
+msgid "Failed to process frame."
+msgstr ""
+
+#, c-format
+msgid ""
+"Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if "
+"it is a v4l1 driver."
+msgstr ""
+
+#, c-format
+msgid "Failed to query attributes of input %d in device %s"
+msgstr ""
+
+#, c-format
+msgid "Failed to get setting of tuner %d on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to query norm on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed getting controls attributes on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Cannot identify device '%s'."
+msgstr ""
+
+#, c-format
+msgid "This isn't a device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Could not open device '%s' for reading and writing."
+msgstr ""
+
+#, c-format
+msgid "Device '%s' is not a capture device."
+msgstr ""
+
+#, c-format
+msgid "Device '%s' is not a output device."
+msgstr ""
+
+#, c-format
+msgid "Device '%s' is not a M2M device."
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Could not dup device '%s' for reading and writing."
+msgstr "无法打开音频文件进行混音控制操作。"
+
+#, c-format
+msgid "Failed to set norm for device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to get current tuner frequency for device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
+msgstr ""
+
+#, c-format
+msgid "Failed to get signal strength for device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to get value for control %d on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to set value %d for control %d on device '%s'."
+msgstr ""
+
+#, c-format
+msgid "Failed to get current input on device '%s'. May be it is a radio device"
+msgstr ""
+
+#, c-format
+msgid ""
+"Failed to get current output on device '%s'. May be it is a radio device"
+msgstr ""
+
+#, c-format
+msgid "Failed to set output %d on device %s."
+msgstr ""
+
+msgid "Changing resolution at runtime is not yet supported."
+msgstr ""
+
+msgid "Cannot operate without a clock"
+msgstr ""
+
+#~ msgid "Internal data stream error."
+#~ msgstr "內部資料串流發生錯誤。"
+
+#, fuzzy
+#~ msgid "Internal data flow error."
+#~ msgstr "內部資料串流發生錯誤。"
+
+#~ msgid ""
+#~ "Could not open audio device for mixer control handling. This version of "
+#~ "the Open Sound System is not supported by this element."
+#~ msgstr ""
+#~ "无法打开音频设备进行音量控制操作。此部件不支持开放声音系统(OSS)的版本。"
+
+#~ msgid "Master"
+#~ msgstr "主声道"
+
+#~ msgid "Front"
+#~ msgstr "前置声道"
+
+#~ msgid "Rear"
+#~ msgstr "后置声道"
+
+#~ msgid "Headphones"
+#~ msgstr "头戴式耳机"
+
+#~ msgid "Center"
+#~ msgstr "中置"
+
+#~ msgid "LFE"
+#~ msgstr "低音炮"
+
+#~ msgid "Surround"
+#~ msgstr "立体声环绕"
+
+#~ msgid "Side"
+#~ msgstr "左右声道"
+
+#~ msgid "AUX Out"
+#~ msgstr "AUX 输出"
+
+#~ msgid "3D Depth"
+#~ msgstr "3D Depth"
+
+#~ msgid "3D Center"
+#~ msgstr "3D Center"
+
+#~ msgid "3D Enhance"
+#~ msgstr "3D Enhance"
+
+#~ msgid "Telephone"
+#~ msgstr "话筒"
+
+#~ msgid "Video In"
+#~ msgstr "视频输入"
+
+#~ msgid "AUX In"
+#~ msgstr "AUX 输入"
+
+#~ msgid "Record Gain"
+#~ msgstr "录音增益"
+
+#~ msgid "Output Gain"
+#~ msgstr "输出增益"
+
+#~ msgid "Microphone Boost"
+#~ msgstr "麦克风增益"
+
+#, fuzzy
+#~ msgid "Diagnostic"
+#~ msgstr "采样分析"
+
+#~ msgid "Bass Boost"
+#~ msgstr "Bass 增益"
+
+#~ msgid "Playback Ports"
+#~ msgstr "回放端口"
+
+#~ msgid "Input"
+#~ msgstr "输入"
+
+#~ msgid "Monitor Source"
+#~ msgstr "监视器来源"
+
+#~ msgid "Keyboard Beep"
+#~ msgstr "按键声音"
+
+#~ msgid "Simulate Stereo"
+#~ msgstr "模拟立体声"
+
+#~ msgid "Stereo"
+#~ msgstr "立体声"
+
+#~ msgid "Surround Sound"
+#~ msgstr "立体声环绕"
+
+#~ msgid "Microphone Gain"
+#~ msgstr "麦克风增益"
+
+#~ msgid "Speaker Source"
+#~ msgstr "扬声器音源"
+
+#~ msgid "Microphone Source"
+#~ msgstr "麦克风音源"
+
+#~ msgid "Jack"
+#~ msgstr "Jack"
+
+#~ msgid "Center / LFE"
+#~ msgstr "中置/低音炮"
+
+#~ msgid "Stereo Mix"
+#~ msgstr "立体声"
+
+#~ msgid "Mono Mix"
+#~ msgstr "单声道"
+
+#~ msgid "Input Mix"
+#~ msgstr "混音输入"
+
+#~ msgid "Microphone 2"
+#~ msgstr "麦克风 2"
+
+#~ msgid "Digital Out"
+#~ msgstr "数字输出"
+
+#~ msgid "Digital In"
+#~ msgstr "数字输入"
+
+#~ msgid "HDMI"
+#~ msgstr "HDMI(高清)"
+
+#~ msgid "Modem"
+#~ msgstr "Modem"
+
+#~ msgid "Handset"
+#~ msgstr "手持设备"
+
+#~ msgid "Other"
+#~ msgstr "其它设备"
+
+#~ msgid "None"
+#~ msgstr "无"
+
+#~ msgid "On"
+#~ msgstr "开"
+
+#~ msgid "Off"
+#~ msgstr "关"
+
+#~ msgid "Mute"
+#~ msgstr "静音"
+
+#~ msgid "Fast"
+#~ msgstr "快"
+
+#~ msgid "Very Low"
+#~ msgstr "很慢"
+
+#~ msgid "Low"
+#~ msgstr "慢"
+
+#~ msgid "Medium"
+#~ msgstr "中等"
+
+#~ msgid "High"
+#~ msgstr "高"
+
+#~ msgid "Very High"
+#~ msgstr "很高"
+
+#~ msgid "Production"
+#~ msgstr "生产商"
+
+#~ msgid "Front Panel Microphone"
+#~ msgstr "麦克风面板"
+
+#~ msgid "Front Panel Line In"
+#~ msgstr "线路输入面板"
+
+#~ msgid "Front Panel Headphones"
+#~ msgstr "头戴式耳机面板"
+
+#~ msgid "Front Panel Line Out"
+#~ msgstr "线路输出面板"
+
+#, fuzzy
+#~ msgid "Green Connector"
+#~ msgstr "线路输出"
+
+#, fuzzy
+#~ msgid "Pink Connector"
+#~ msgstr "话筒输出"
+
+#, fuzzy
+#~ msgid "Blue Connector"
+#~ msgstr "立体声输入"
+
+#, fuzzy
+#~ msgid "White Connector"
+#~ msgstr "左/单声道"
+
+#, fuzzy
+#~ msgid "Black Connector"
+#~ msgstr "后置声道输出"
+
+#, fuzzy
+#~ msgid "Gray Connector"
+#~ msgstr "中置声道输出"
+
+#, fuzzy
+#~ msgid "Orange Connector"
+#~ msgstr "低音炮输出"
+
+#, fuzzy
+#~ msgid "Red Connector"
+#~ msgstr "右声道"
+
+#, fuzzy
+#~ msgid "Yellow Connector"
+#~ msgstr "Midi 输出/游戏摇杆"
+
+#, fuzzy
+#~ msgid "Green Front Panel Connector"
+#~ msgstr "线路输出面板"
+
+#, fuzzy
+#~ msgid "Pink Front Panel Connector"
+#~ msgstr "话筒输出面板"
+
+#, fuzzy
+#~ msgid "Blue Front Panel Connector"
+#~ msgstr "立体声输入面板"
+
+#, fuzzy
+#~ msgid "White Front Panel Connector"
+#~ msgstr "左/单声道面板"
+
+#, fuzzy
+#~ msgid "Black Front Panel Connector"
+#~ msgstr "后置声道输出面板"
+
+#, fuzzy
+#~ msgid "Gray Front Panel Connector"
+#~ msgstr "中置声道输出面板"
+
+#, fuzzy
+#~ msgid "Orange Front Panel Connector"
+#~ msgstr "低音炮输出面板"
+
+#, fuzzy
+#~ msgid "Red Front Panel Connector"
+#~ msgstr "右声道面板"
+
+#, fuzzy
+#~ msgid "Yellow Front Panel Connector"
+#~ msgstr "Midi 输出/游戏摇杆面板"
+
+#~ msgid "Spread Output"
+#~ msgstr "Spread 输出"
+
+#~ msgid "Downmix"
+#~ msgstr "Downmix"
+
+#~ msgid "Virtual Mixer Input"
+#~ msgstr "模拟混音输入"
+
+#, fuzzy
+#~ msgid "Virtual Mixer Output"
+#~ msgstr "模拟混音输出"
+
+#~ msgid "Virtual Mixer Channels"
+#~ msgstr "模拟混音输入"
+
+#, fuzzy
+#~ msgid "%s %d Function"
+#~ msgstr "%s 功能"
+
+#~ msgid "%s Function"
+#~ msgstr "%s 功能"
diff --git a/sys/Makefile.am b/sys/Makefile.am
new file mode 100644
index 0000000..bf8b906
--- /dev/null
+++ b/sys/Makefile.am
@@ -0,0 +1,53 @@
+if USE_OSS
+OSS_DIR=oss
+else
+OSS_DIR=
+endif
+
+if USE_OSS4
+OSS4_DIR=oss4
+else
+OSS4_DIR=
+endif
+
+if USE_DIRECTSOUND
+DIRECTSOUND_DIR=directsound
+else
+DIRECTSOUND_DIR=
+endif
+
+if USE_WAVEFORM
+WAVEFORM_DIR=waveform
+else
+WAVEFORM_DIR=
+endif
+
+if USE_OSX_AUDIO
+OSX_AUDIO_DIR=osxaudio
+else
+OSX_AUDIO_DIR=
+endif
+
+if USE_OSX_VIDEO
+OSX_VIDEO_DIR=osxvideo
+else
+OSX_VIDEO_DIR=
+endif
+
+if USE_GST_V4L2
+V4L2_DIR=v4l2
+else
+V4L2_DIR=
+endif
+
+if USE_X
+XIMAGE_DIR=ximage
+else
+XIMAGE_DIR=
+endif
+
+SUBDIRS=$(DIRECTSOUND_DIR) $(WAVEFORM_DIR) $(OSS_DIR) $(OSS4_DIR) $(OSX_AUDIO_DIR) $(OSX_VIDEO_DIR) $(V4L2_DIR) $(XIMAGE_DIR)
+
+DIST_SUBDIRS=directsound oss oss4 osxaudio osxvideo v4l2 waveform ximage
+
+include $(top_srcdir)/common/parallel-subdirs.mak
diff --git a/sys/directsound/Makefile.am b/sys/directsound/Makefile.am
new file mode 100644
index 0000000..963a9aa
--- /dev/null
+++ b/sys/directsound/Makefile.am
@@ -0,0 +1,21 @@
+plugin_LTLIBRARIES = libgstdirectsound.la
+
+libgstdirectsound_la_SOURCES =  gstdirectsoundsink.c gstdirectsounddevice.c gstdirectsoundplugin.c
+libgstdirectsound_la_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS) \
+	$(DIRECTSOUND_CFLAGS) \
+	-DGstDirectSoundDeviceProvider=GstDirectSoundSinkDeviceProvider \
+	-DGstDirectSoundDeviceProviderClass=GstDirectSoundSinkDeviceProviderClass \
+	-DGstDirectSoundDevice=GstDirectSoundSinkDevice \
+	-DGstDirectSoundDeviceClass=GstDirectSoundSinkDeviceClass
+libgstdirectsound_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) \
+	-lgstaudio-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) \
+	$(GST_LIBS) \
+	$(DIRECTSOUND_LIBS)
+libgstdirectsound_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(DIRECTSOUND_LDFLAGS)
+
+noinst_HEADERS = gstdirectsoundsink.h gstdirectsounddevice.h
diff --git a/sys/directsound/gstdirectsounddevice.c b/sys/directsound/gstdirectsounddevice.c
new file mode 100644
index 0000000..00b021e
--- /dev/null
+++ b/sys/directsound/gstdirectsounddevice.c
@@ -0,0 +1,266 @@
+/* GStreamer
+ * Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstdirectsounddevice.h"
+
+#include <windows.h>
+#include <dsound.h>
+#include <mmsystem.h>
+#include <stdio.h>
+
+#ifdef GST_DIRECTSOUND_SRC_DEVICE_PROVIDER
+#include "gstdirectsoundsrc.h"
+#else
+#include "gstdirectsoundsink.h"
+#endif
+
+G_DEFINE_TYPE (GstDirectSoundDeviceProvider, gst_directsound_device_provider,
+    GST_TYPE_DEVICE_PROVIDER);
+
+static GList *gst_directsound_device_provider_probe (GstDeviceProvider *
+    provider);
+
+static void
+gst_directsound_device_provider_class_init (GstDirectSoundDeviceProviderClass *
+    klass)
+{
+  GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS (klass);
+
+  gst_device_provider_class_set_static_metadata (dm_class,
+#ifdef GST_DIRECTSOUND_SRC_DEVICE_PROVIDER
+      "DirectSound Source Device Provider", "Source/Audio",
+      "List DirectSound source devices",
+#else
+      "DirectSound Sink Device Provider", "Sink/Audio",
+      "List DirectSound sink devices",
+#endif
+      "Sebastian Dröge <sebastian@centricular.com>");
+
+  dm_class->probe = gst_directsound_device_provider_probe;
+}
+
+static void
+gst_directsound_device_provider_init (GstDirectSoundDeviceProvider * provider)
+{
+}
+
+static gchar *
+guid_to_string (LPGUID guid)
+{
+  gunichar2 *wstr = NULL;
+  gchar *str = NULL;
+
+  if (StringFromCLSID (guid, &wstr) == S_OK) {
+    str = g_utf16_to_utf8 (wstr, -1, NULL, NULL, NULL);
+    CoTaskMemFree (wstr);
+  }
+
+  return str;
+}
+
+typedef struct
+{
+  GstDirectSoundDeviceProvider *self;
+  GList **devices;
+} ProbeData;
+
+static BOOL CALLBACK
+gst_directsound_enum_callback (GUID * pGUID, TCHAR * strDesc,
+    TCHAR * strDrvName, VOID * pContext)
+{
+  ProbeData *probe_data = (ProbeData *) (pContext);
+  gchar *driver, *description, *guid_str;
+  GstStructure *props;
+  GstDevice *device;
+#ifdef GST_DIRECTSOUND_SRC_DEVICE_PROVIDER
+  static GstStaticCaps caps = GST_STATIC_CAPS (GST_DIRECTSOUND_SRC_CAPS);
+#else
+  static GstStaticCaps caps = GST_STATIC_CAPS (GST_DIRECTSOUND_SINK_CAPS);
+#endif
+
+  description = g_locale_to_utf8 (strDesc, -1, NULL, NULL, NULL);
+  if (!description) {
+    GST_ERROR_OBJECT (probe_data->self,
+        "Failed to convert description from locale encoding to UTF8");
+    return TRUE;
+  }
+
+  driver = g_locale_to_utf8 (strDrvName, -1, NULL, NULL, NULL);
+  if (!driver) {
+    GST_ERROR_OBJECT (probe_data->self,
+        "Failed to convert driver name from locale encoding to UTF8");
+    return TRUE;
+  }
+
+  /* NULL for the primary sound card */
+  guid_str = pGUID ? guid_to_string (pGUID) : NULL;
+
+  GST_INFO_OBJECT (probe_data->self, "sound device name: %s, %s (GUID %s)",
+      description, driver, GST_STR_NULL (guid_str));
+
+  props = gst_structure_new ("directsound-proplist",
+      "device.api", G_TYPE_STRING, "directsound",
+      "device.guid", G_TYPE_STRING, GST_STR_NULL (guid_str),
+      "directsound.device.driver", G_TYPE_STRING, driver,
+      "directsound.device.description", G_TYPE_STRING, description, NULL);
+
+#ifdef GST_DIRECTSOUND_SRC_DEVICE_PROVIDER
+  device = g_object_new (GST_TYPE_DIRECTSOUND_DEVICE, "device-guid", guid_str,
+      "display-name", description, "caps", gst_static_caps_get (&caps),
+      "device-class", "Audio/Source", "properties", props, NULL);
+#else
+  device = g_object_new (GST_TYPE_DIRECTSOUND_DEVICE, "device-guid", guid_str,
+      "display-name", description, "caps", gst_static_caps_get (&caps),
+      "device-class", "Audio/Sink", "properties", props, NULL);
+#endif
+
+  *probe_data->devices = g_list_prepend (*probe_data->devices, device);
+
+  g_free (description);
+  g_free (driver);
+  g_free (guid_str);
+
+  gst_structure_free (props);
+
+  return TRUE;
+}
+
+static GList *
+gst_directsound_device_provider_probe (GstDeviceProvider * provider)
+{
+  GstDirectSoundDeviceProvider *self =
+      GST_DIRECTSOUND_DEVICE_PROVIDER (provider);
+  GList *devices = NULL;
+  ProbeData probe_data = { self, &devices };
+  HRESULT hRes;
+
+#ifdef GST_DIRECTSOUND_SRC_DEVICE_PROVIDER
+  hRes = DirectSoundCaptureEnumerate ((LPDSENUMCALLBACK)
+      gst_directsound_enum_callback, (VOID *) & probe_data);
+#else
+  hRes = DirectSoundEnumerate ((LPDSENUMCALLBACK)
+      gst_directsound_enum_callback, (VOID *) & probe_data);
+#endif
+
+  if (FAILED (hRes))
+    GST_ERROR_OBJECT (self, "Failed to enumerate devices");
+
+  return devices;
+}
+
+enum
+{
+  PROP_DEVICE_GUID = 1,
+};
+
+G_DEFINE_TYPE (GstDirectSoundDevice, gst_directsound_device, GST_TYPE_DEVICE);
+
+static void gst_directsound_device_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+static void gst_directsound_device_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_directsound_device_finalize (GObject * object);
+static GstElement *gst_directsound_device_create_element (GstDevice * device,
+    const gchar * name);
+
+static void
+gst_directsound_device_class_init (GstDirectSoundDeviceClass * klass)
+{
+  GstDeviceClass *dev_class = GST_DEVICE_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  dev_class->create_element = gst_directsound_device_create_element;
+
+  object_class->get_property = gst_directsound_device_get_property;
+  object_class->set_property = gst_directsound_device_set_property;
+  object_class->finalize = gst_directsound_device_finalize;
+
+  g_object_class_install_property (object_class, PROP_DEVICE_GUID,
+      g_param_spec_string ("device-guid", "Device GUID",
+          "Device GUID", NULL,
+          G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gst_directsound_device_init (GstDirectSoundDevice * device)
+{
+}
+
+static void
+gst_directsound_device_finalize (GObject * object)
+{
+  GstDirectSoundDevice *device = GST_DIRECTSOUND_DEVICE (object);
+
+  g_free (device->guid);
+
+  G_OBJECT_CLASS (gst_directsound_device_parent_class)->finalize (object);
+}
+
+static GstElement *
+gst_directsound_device_create_element (GstDevice * device, const gchar * name)
+{
+  GstDirectSoundDevice *directsound_dev = GST_DIRECTSOUND_DEVICE (device);
+  GstElement *elem;
+
+#ifdef GST_DIRECTSOUND_SRC_DEVICE_PROVIDER
+  elem = gst_element_factory_make ("directsoundsrc", name);
+#else
+  elem = gst_element_factory_make ("directsoundsink", name);
+#endif
+
+  g_object_set (elem, "device", directsound_dev->guid, NULL);
+
+  return elem;
+}
+
+static void
+gst_directsound_device_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstDirectSoundDevice *device = GST_DIRECTSOUND_DEVICE_CAST (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE_GUID:
+      g_value_set_string (value, device->guid);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_directsound_device_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstDirectSoundDevice *device = GST_DIRECTSOUND_DEVICE_CAST (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE_GUID:
+      device->guid = g_value_dup_string (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/sys/directsound/gstdirectsounddevice.h b/sys/directsound/gstdirectsounddevice.h
new file mode 100644
index 0000000..5502893
--- /dev/null
+++ b/sys/directsound/gstdirectsounddevice.h
@@ -0,0 +1,74 @@
+/* GStreamer
+ * Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_DIRECTSOUND_DEVICE_H__
+#define __GST_DIRECTSOUND_DEVICE_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstDirectSoundDeviceProvider GstDirectSoundDeviceProvider;
+typedef struct _GstDirectSoundDeviceProviderClass GstDirectSoundDeviceProviderClass;
+
+#define GST_TYPE_DIRECTSOUND_DEVICE_PROVIDER                 (gst_directsound_device_provider_get_type())
+#define GST_IS_DIRECTSOUND_DEVICE_PROVIDER(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DIRECTSOUND_DEVICE_PROVIDER))
+#define GST_IS_DIRECTSOUND_DEVICE_PROVIDER_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DIRECTSOUND_DEVICE_PROVIDER))
+#define GST_DIRECTSOUND_DEVICE_PROVIDER_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DIRECTSOUND_DEVICE_PROVIDER, GstDirectSoundDeviceProviderClass))
+#define GST_DIRECTSOUND_DEVICE_PROVIDER(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DIRECTSOUND_DEVICE_PROVIDER, GstDirectSoundDeviceProvider))
+#define GST_DIRECTSOUND_DEVICE_PROVIDER_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE_PROVIDER, GstDirectSoundDeviceProviderClass))
+#define GST_DIRECTSOUND_DEVICE_PROVIDER_CAST(obj)            ((GstDirectSoundDeviceProvider *)(obj))
+
+struct _GstDirectSoundDeviceProvider {
+  GstDeviceProvider parent;
+};
+
+struct _GstDirectSoundDeviceProviderClass {
+  GstDeviceProviderClass parent_class;
+};
+
+GType gst_directsound_device_provider_get_type (void);
+
+
+typedef struct _GstDirectSoundDevice GstDirectSoundDevice;
+typedef struct _GstDirectSoundDeviceClass GstDirectSoundDeviceClass;
+
+#define GST_TYPE_DIRECTSOUND_DEVICE                 (gst_directsound_device_get_type())
+#define GST_IS_DIRECTSOUND_DEVICE(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DIRECTSOUND_DEVICE))
+#define GST_IS_DIRECTSOUND_DEVICE_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DIRECTSOUND_DEVICE))
+#define GST_DIRECTSOUND_DEVICE_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DIRECTSOUND_DEVICE, GstDirectSoundDeviceClass))
+#define GST_DIRECTSOUND_DEVICE(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DIRECTSOUND_DEVICE, GstDirectSoundDevice))
+#define GST_DIRECTSOUND_DEVICE_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE, GstDirectSoundDeviceClass))
+#define GST_DIRECTSOUND_DEVICE_CAST(obj)            ((GstDirectSoundDevice *)(obj))
+
+struct _GstDirectSoundDevice {
+  GstDevice parent;
+
+  gchar *guid;
+};
+
+struct _GstDirectSoundDeviceClass {
+  GstDeviceClass parent_class;
+};
+
+GType gst_directsound_device_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_DIRECTSOUND_DEVICE_H__ */
diff --git a/sys/directsound/gstdirectsoundplugin.c b/sys/directsound/gstdirectsoundplugin.c
new file mode 100644
index 0000000..b3a7f1c
--- /dev/null
+++ b/sys/directsound/gstdirectsoundplugin.c
@@ -0,0 +1,53 @@
+/* GStreamer
+* Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
+* Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
+*
+* gstdirectsoundplugin.c:
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Library General Public License for more details.
+*
+* You should have received a copy of the GNU Library General Public
+* License along with this library; if not, write to the
+* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+* Boston, MA 02110-1301, USA.
+* 
+*
+* The development of this code was made possible due to the involvement
+* of Pioneers of the Inevitable, the creators of the Songbird Music player
+*
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstdirectsoundsink.h"
+#include "gstdirectsounddevice.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "directsoundsink", GST_RANK_PRIMARY,
+          GST_TYPE_DIRECTSOUND_SINK))
+    return FALSE;
+
+  if (!gst_device_provider_register (plugin, "directsoundsinkdeviceprovider",
+          GST_RANK_PRIMARY, GST_TYPE_DIRECTSOUND_DEVICE_PROVIDER))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    directsound,
+    "Direct Sound plugin library",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/sys/directsound/gstdirectsoundsink.c b/sys/directsound/gstdirectsoundsink.c
new file mode 100644
index 0000000..c0da186
--- /dev/null
+++ b/sys/directsound/gstdirectsoundsink.c
@@ -0,0 +1,1050 @@
+/* GStreamer
+* Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
+* Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
+* Copyright (C) 2010 Fluendo S.A. <support@fluendo.com>
+*
+* gstdirectsoundsink.c:
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Library General Public License for more details.
+*
+* You should have received a copy of the GNU Library General Public
+* License along with this library; if not, write to the
+* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+* Boston, MA 02110-1301, USA.
+*
+*
+* The development of this code was made possible due to the involvement
+* of Pioneers of the Inevitable, the creators of the Songbird Music player
+*
+*/
+
+/**
+ * SECTION:element-directsoundsink
+ *
+ * This element lets you output sound using the DirectSound API.
+ *
+ * Note that you should almost always use generic audio conversion elements
+ * like audioconvert and audioresample in front of an audiosink to make sure
+ * your pipeline works under all circumstances (those conversion elements will
+ * act in passthrough-mode if no conversion is necessary).
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! audioconvert ! volume volume=0.1 ! directsoundsink
+ * ]| will output a sine wave (continuous beep sound) to your sound card (with
+ * a very low volume as precaution).
+ * |[
+ * gst-launch-1.0 -v filesrc location=music.ogg ! decodebin ! audioconvert ! audioresample ! directsoundsink
+ * ]| will play an Ogg/Vorbis audio file and output it.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/base/gstbasesink.h>
+#include "gstdirectsoundsink.h"
+#include <gst/audio/gstaudioiec61937.h>
+
+#include <math.h>
+
+#ifdef __CYGWIN__
+#include <unistd.h>
+#ifndef _swab
+#define _swab swab
+#endif
+#endif
+
+#define DEFAULT_MUTE FALSE
+
+GST_DEBUG_CATEGORY_STATIC (directsoundsink_debug);
+#define GST_CAT_DEFAULT directsoundsink_debug
+
+static void gst_directsound_sink_finalize (GObject * object);
+
+static void gst_directsound_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_directsound_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_directsound_sink_getcaps (GstBaseSink * bsink,
+    GstCaps * filter);
+static GstBuffer *gst_directsound_sink_payload (GstAudioBaseSink * sink,
+    GstBuffer * buf);
+static gboolean gst_directsound_sink_prepare (GstAudioSink * asink,
+    GstAudioRingBufferSpec * spec);
+static gboolean gst_directsound_sink_unprepare (GstAudioSink * asink);
+static gboolean gst_directsound_sink_open (GstAudioSink * asink);
+static gboolean gst_directsound_sink_close (GstAudioSink * asink);
+static gint gst_directsound_sink_write (GstAudioSink * asink,
+    gpointer data, guint length);
+static guint gst_directsound_sink_delay (GstAudioSink * asink);
+static void gst_directsound_sink_reset (GstAudioSink * asink);
+static GstCaps *gst_directsound_probe_supported_formats (GstDirectSoundSink *
+    dsoundsink, const GstCaps * template_caps);
+static gboolean gst_directsound_sink_query (GstBaseSink * pad,
+    GstQuery * query);
+
+static void gst_directsound_sink_set_volume (GstDirectSoundSink * sink,
+    gdouble volume, gboolean store);
+static gdouble gst_directsound_sink_get_volume (GstDirectSoundSink * sink);
+static void gst_directsound_sink_set_mute (GstDirectSoundSink * sink,
+    gboolean mute);
+static gboolean gst_directsound_sink_get_mute (GstDirectSoundSink * sink);
+static const gchar *gst_directsound_sink_get_device (GstDirectSoundSink *
+    dsoundsink);
+static void gst_directsound_sink_set_device (GstDirectSoundSink * dsoundsink,
+    const gchar * device_id);
+
+static gboolean gst_directsound_sink_is_spdif_format (GstAudioRingBufferSpec *
+    spec);
+
+static gchar *gst_hres_to_string (HRESULT hRes);
+
+static GstStaticPadTemplate directsoundsink_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_DIRECTSOUND_SINK_CAPS));
+
+enum
+{
+  PROP_0,
+  PROP_VOLUME,
+  PROP_MUTE,
+  PROP_DEVICE
+};
+
+#define gst_directsound_sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstDirectSoundSink, gst_directsound_sink,
+    GST_TYPE_AUDIO_SINK, G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL)
+    );
+
+static void
+gst_directsound_sink_finalize (GObject * object)
+{
+  GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (object);
+
+  g_free (dsoundsink->device_id);
+  dsoundsink->device_id = NULL;
+
+  g_mutex_clear (&dsoundsink->dsound_lock);
+  gst_object_unref (dsoundsink->system_clock);
+  if (dsoundsink->write_wait_clock_id != NULL) {
+    gst_clock_id_unref (dsoundsink->write_wait_clock_id);
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_directsound_sink_class_init (GstDirectSoundSinkClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
+  GstAudioSinkClass *gstaudiosink_class = GST_AUDIO_SINK_CLASS (klass);
+  GstAudioBaseSinkClass *gstaudiobasesink_class =
+      GST_AUDIO_BASE_SINK_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (directsoundsink_debug, "directsoundsink", 0,
+      "DirectSound sink");
+
+  gobject_class->finalize = gst_directsound_sink_finalize;
+  gobject_class->set_property = gst_directsound_sink_set_property;
+  gobject_class->get_property = gst_directsound_sink_get_property;
+
+  gstbasesink_class->get_caps =
+      GST_DEBUG_FUNCPTR (gst_directsound_sink_getcaps);
+
+  gstbasesink_class->query = GST_DEBUG_FUNCPTR (gst_directsound_sink_query);
+
+  gstaudiobasesink_class->payload =
+      GST_DEBUG_FUNCPTR (gst_directsound_sink_payload);
+
+  gstaudiosink_class->prepare =
+      GST_DEBUG_FUNCPTR (gst_directsound_sink_prepare);
+  gstaudiosink_class->unprepare =
+      GST_DEBUG_FUNCPTR (gst_directsound_sink_unprepare);
+  gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_directsound_sink_open);
+  gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_directsound_sink_close);
+  gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_directsound_sink_write);
+  gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_directsound_sink_delay);
+  gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_directsound_sink_reset);
+
+  g_object_class_install_property (gobject_class,
+      PROP_VOLUME,
+      g_param_spec_double ("volume", "Volume",
+          "Volume of this stream", 0.0, 1.0, 1.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_MUTE,
+      g_param_spec_boolean ("mute", "Mute",
+          "Mute state of this stream", DEFAULT_MUTE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_DEVICE,
+      g_param_spec_string ("device", "Device",
+          "DirectSound playback device as a GUID string",
+          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (element_class,
+      "Direct Sound Audio Sink", "Sink/Audio",
+      "Output to a sound card via Direct Sound",
+      "Sebastien Moutte <sebastien@moutte.net>");
+
+  gst_element_class_add_static_pad_template (element_class,
+      &directsoundsink_sink_factory);
+}
+
+static void
+gst_directsound_sink_init (GstDirectSoundSink * dsoundsink)
+{
+  dsoundsink->volume = 100;
+  dsoundsink->mute = FALSE;
+  dsoundsink->device_id = NULL;
+  dsoundsink->pDS = NULL;
+  dsoundsink->cached_caps = NULL;
+  dsoundsink->pDSBSecondary = NULL;
+  dsoundsink->current_circular_offset = 0;
+  dsoundsink->buffer_size = DSBSIZE_MIN;
+  g_mutex_init (&dsoundsink->dsound_lock);
+  dsoundsink->system_clock = gst_system_clock_obtain ();
+  dsoundsink->write_wait_clock_id = NULL;
+  dsoundsink->first_buffer_after_reset = FALSE;
+}
+
+static void
+gst_directsound_sink_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstDirectSoundSink *sink = GST_DIRECTSOUND_SINK (object);
+
+  switch (prop_id) {
+    case PROP_VOLUME:
+      gst_directsound_sink_set_volume (sink, g_value_get_double (value), TRUE);
+      break;
+    case PROP_MUTE:
+      gst_directsound_sink_set_mute (sink, g_value_get_boolean (value));
+      break;
+    case PROP_DEVICE:
+      gst_directsound_sink_set_device (sink, g_value_get_string (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_directsound_sink_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstDirectSoundSink *sink = GST_DIRECTSOUND_SINK (object);
+
+  switch (prop_id) {
+    case PROP_VOLUME:
+      g_value_set_double (value, gst_directsound_sink_get_volume (sink));
+      break;
+    case PROP_MUTE:
+      g_value_set_boolean (value, gst_directsound_sink_get_mute (sink));
+      break;
+    case PROP_DEVICE:
+      g_value_set_string (value, gst_directsound_sink_get_device (sink));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstCaps *
+gst_directsound_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
+{
+  GstElementClass *element_class;
+  GstPadTemplate *pad_template;
+  GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (bsink);
+  GstCaps *caps;
+
+  if (dsoundsink->pDS == NULL) {
+    GST_DEBUG_OBJECT (dsoundsink, "device not open, using template caps");
+    return NULL;                /* base class will get template caps for us */
+  }
+
+  if (dsoundsink->cached_caps) {
+    caps = gst_caps_ref (dsoundsink->cached_caps);
+  } else {
+    element_class = GST_ELEMENT_GET_CLASS (dsoundsink);
+    pad_template = gst_element_class_get_pad_template (element_class, "sink");
+    g_return_val_if_fail (pad_template != NULL, NULL);
+
+    caps = gst_directsound_probe_supported_formats (dsoundsink,
+        gst_pad_template_get_caps (pad_template));
+    if (caps)
+      dsoundsink->cached_caps = gst_caps_ref (caps);
+  }
+
+  if (caps && filter) {
+    GstCaps *tmp =
+        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    caps = tmp;
+  }
+
+  if (caps) {
+    gchar *caps_string = gst_caps_to_string (caps);
+    GST_DEBUG_OBJECT (dsoundsink, "returning caps %s", caps_string);
+    g_free (caps_string);
+  }
+
+  return caps;
+}
+
+static gboolean
+gst_directsound_sink_acceptcaps (GstBaseSink * sink, GstQuery * query)
+{
+  GstDirectSoundSink *dsink = GST_DIRECTSOUND_SINK (sink);
+  GstPad *pad;
+  GstCaps *caps;
+  GstCaps *pad_caps;
+  GstStructure *st;
+  gboolean ret = FALSE;
+  GstAudioRingBufferSpec spec = { 0 };
+
+  if (G_UNLIKELY (dsink == NULL))
+    return FALSE;
+
+  pad = sink->sinkpad;
+
+  gst_query_parse_accept_caps (query, &caps);
+  GST_DEBUG_OBJECT (pad, "caps %" GST_PTR_FORMAT, caps);
+
+  pad_caps = gst_pad_query_caps (pad, NULL);
+  if (pad_caps) {
+    gboolean cret = gst_caps_is_subset (caps, pad_caps);
+    gst_caps_unref (pad_caps);
+    if (!cret) {
+      GST_DEBUG_OBJECT (dsink,
+          "Caps are not a subset of the pad caps, not accepting caps");
+      goto done;
+    }
+  }
+
+  /* If we've not got fixed caps, creating a stream might fail, so let's just
+   * return from here with default acceptcaps behaviour */
+  if (!gst_caps_is_fixed (caps)) {
+    GST_DEBUG_OBJECT (dsink, "Caps are not fixed, not accepting caps");
+    goto done;
+  }
+
+  spec.latency_time = GST_SECOND;
+  if (!gst_audio_ring_buffer_parse_caps (&spec, caps)) {
+    GST_DEBUG_OBJECT (dsink, "Failed to parse caps, not accepting");
+    goto done;
+  }
+
+  /* Make sure input is framed (one frame per buffer) and can be payloaded */
+  switch (spec.type) {
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS:
+    {
+      gboolean framed = FALSE, parsed = FALSE;
+      st = gst_caps_get_structure (caps, 0);
+
+      gst_structure_get_boolean (st, "framed", &framed);
+      gst_structure_get_boolean (st, "parsed", &parsed);
+      if ((!framed && !parsed) || gst_audio_iec61937_frame_size (&spec) <= 0) {
+        GST_DEBUG_OBJECT (dsink, "Wrong AC3/DTS caps, not accepting");
+        goto done;
+      }
+    }
+    default:
+      break;
+  }
+  ret = TRUE;
+  GST_DEBUG_OBJECT (dsink, "Accepting caps");
+
+done:
+  gst_query_set_accept_caps_result (query, ret);
+  return TRUE;
+}
+
+static gboolean
+gst_directsound_sink_query (GstBaseSink * sink, GstQuery * query)
+{
+  gboolean res = TRUE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_ACCEPT_CAPS:
+      res = gst_directsound_sink_acceptcaps (sink, query);
+      break;
+    default:
+      res = GST_BASE_SINK_CLASS (parent_class)->query (sink, query);
+  }
+
+  return res;
+}
+
+static LPGUID
+string_to_guid (const gchar * str)
+{
+  HRESULT ret;
+  gunichar2 *wstr;
+  LPGUID out;
+
+  wstr = g_utf8_to_utf16 (str, -1, NULL, NULL, NULL);
+  if (!wstr)
+    return NULL;
+
+  out = g_new (GUID, 1);
+  ret = CLSIDFromString ((LPOLESTR) wstr, out);
+  g_free (wstr);
+  if (ret != NOERROR) {
+    g_free (out);
+    return NULL;
+  }
+
+  return out;
+}
+
+static gboolean
+gst_directsound_sink_open (GstAudioSink * asink)
+{
+  GstDirectSoundSink *dsoundsink;
+  HRESULT hRes;
+  LPGUID lpGuid = NULL;
+
+  dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
+  if (dsoundsink->device_id) {
+    lpGuid = string_to_guid (dsoundsink->device_id);
+    if (lpGuid == NULL) {
+      GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_READ,
+          ("device set but guid not found: %s", dsoundsink->device_id), (NULL));
+      return FALSE;
+    }
+  }
+
+  /* create and initialize a DirectSound object */
+  if (FAILED (hRes = DirectSoundCreate (lpGuid, &dsoundsink->pDS, NULL))) {
+    gchar *error_text = gst_hres_to_string (hRes);
+    GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_READ,
+        ("DirectSoundCreate: %s", error_text), (NULL));
+    g_free (lpGuid);
+    g_free (error_text);
+    return FALSE;
+  }
+
+  g_free (lpGuid);
+
+  if (FAILED (hRes = IDirectSound_SetCooperativeLevel (dsoundsink->pDS,
+              GetDesktopWindow (), DSSCL_PRIORITY))) {
+    gchar *error_text = gst_hres_to_string (hRes);
+    GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_READ,
+        ("IDirectSound_SetCooperativeLevel: %s", error_text), (NULL));
+    g_free (error_text);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_directsound_sink_is_spdif_format (GstAudioRingBufferSpec * spec)
+{
+  return spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3 ||
+      spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS;
+}
+
+static gboolean
+gst_directsound_sink_prepare (GstAudioSink * asink,
+    GstAudioRingBufferSpec * spec)
+{
+  GstDirectSoundSink *dsoundsink;
+  HRESULT hRes;
+  DSBUFFERDESC descSecondary;
+  WAVEFORMATEX wfx;
+
+  dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
+  /*save number of bytes per sample and buffer format */
+  dsoundsink->bytes_per_sample = spec->info.bpf;
+  dsoundsink->type = spec->type;
+
+  /* fill the WAVEFORMATEX structure with spec params */
+  memset (&wfx, 0, sizeof (wfx));
+  if (!gst_directsound_sink_is_spdif_format (spec)) {
+    wfx.cbSize = sizeof (wfx);
+    wfx.wFormatTag = WAVE_FORMAT_PCM;
+    wfx.nChannels = spec->info.channels;
+    wfx.nSamplesPerSec = spec->info.rate;
+    wfx.wBitsPerSample = (spec->info.bpf * 8) / wfx.nChannels;
+    wfx.nBlockAlign = spec->info.bpf;
+    wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+    /* Create directsound buffer with size based on our configured
+     * buffer_size (which is 200 ms by default) */
+    dsoundsink->buffer_size =
+        gst_util_uint64_scale_int (wfx.nAvgBytesPerSec, spec->buffer_time,
+        GST_MSECOND);
+    /* Make sure we make those numbers multiple of our sample size in bytes */
+    dsoundsink->buffer_size -= dsoundsink->buffer_size % spec->info.bpf;
+
+    spec->segsize =
+        gst_util_uint64_scale_int (wfx.nAvgBytesPerSec, spec->latency_time,
+        GST_MSECOND);
+    spec->segsize -= spec->segsize % spec->info.bpf;
+    spec->segtotal = dsoundsink->buffer_size / spec->segsize;
+  } else {
+#ifdef WAVE_FORMAT_DOLBY_AC3_SPDIF
+    wfx.cbSize = 0;
+    wfx.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
+    wfx.nChannels = 2;
+    wfx.nSamplesPerSec = 48000;
+    wfx.wBitsPerSample = 16;
+    wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
+    wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+    spec->segsize = 6144;
+    spec->segtotal = 10;
+#else
+    g_assert_not_reached ();
+#endif
+  }
+
+  // Make the final buffer size be an integer number of segments
+  dsoundsink->buffer_size = spec->segsize * spec->segtotal;
+
+  GST_INFO_OBJECT (dsoundsink, "channels: %d, rate: %d, bytes_per_sample: %d"
+      " WAVEFORMATEX.nSamplesPerSec: %ld, WAVEFORMATEX.wBitsPerSample: %d,"
+      " WAVEFORMATEX.nBlockAlign: %d, WAVEFORMATEX.nAvgBytesPerSec: %ld\n"
+      "Size of dsound circular buffer=>%d\n",
+      GST_AUDIO_INFO_CHANNELS (&spec->info), GST_AUDIO_INFO_RATE (&spec->info),
+      GST_AUDIO_INFO_BPF (&spec->info), wfx.nSamplesPerSec, wfx.wBitsPerSample,
+      wfx.nBlockAlign, wfx.nAvgBytesPerSec, dsoundsink->buffer_size);
+
+  /* create a secondary directsound buffer */
+  memset (&descSecondary, 0, sizeof (DSBUFFERDESC));
+  descSecondary.dwSize = sizeof (DSBUFFERDESC);
+  descSecondary.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;
+  if (!gst_directsound_sink_is_spdif_format (spec))
+    descSecondary.dwFlags |= DSBCAPS_CTRLVOLUME;
+
+  descSecondary.dwBufferBytes = dsoundsink->buffer_size;
+  descSecondary.lpwfxFormat = (WAVEFORMATEX *) & wfx;
+
+  hRes = IDirectSound_CreateSoundBuffer (dsoundsink->pDS, &descSecondary,
+      &dsoundsink->pDSBSecondary, NULL);
+  if (FAILED (hRes)) {
+    gchar *error_text = gst_hres_to_string (hRes);
+    GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_READ,
+        ("IDirectSound_CreateSoundBuffer: %s", error_text), (NULL));
+    g_free (error_text);
+    return FALSE;
+  }
+
+  gst_directsound_sink_set_volume (dsoundsink,
+      gst_directsound_sink_get_volume (dsoundsink), FALSE);
+  gst_directsound_sink_set_mute (dsoundsink, dsoundsink->mute);
+
+  return TRUE;
+}
+
+static gboolean
+gst_directsound_sink_unprepare (GstAudioSink * asink)
+{
+  GstDirectSoundSink *dsoundsink;
+
+  dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
+  /* release secondary DirectSound buffer */
+  if (dsoundsink->pDSBSecondary) {
+    IDirectSoundBuffer_Release (dsoundsink->pDSBSecondary);
+    dsoundsink->pDSBSecondary = NULL;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_directsound_sink_close (GstAudioSink * asink)
+{
+  GstDirectSoundSink *dsoundsink = NULL;
+
+  dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
+  /* release DirectSound object */
+  g_return_val_if_fail (dsoundsink->pDS != NULL, FALSE);
+  IDirectSound_Release (dsoundsink->pDS);
+  dsoundsink->pDS = NULL;
+
+  gst_caps_replace (&dsoundsink->cached_caps, NULL);
+
+  return TRUE;
+}
+
+static gint
+gst_directsound_sink_write (GstAudioSink * asink, gpointer data, guint length)
+{
+  GstDirectSoundSink *dsoundsink;
+  DWORD dwStatus = 0;
+  HRESULT hRes, hRes2;
+  LPVOID pLockedBuffer1 = NULL, pLockedBuffer2 = NULL;
+  DWORD dwSizeBuffer1, dwSizeBuffer2;
+  DWORD dwCurrentPlayCursor;
+
+  dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
+  GST_DSOUND_LOCK (dsoundsink);
+
+  /* get current buffer status */
+  hRes = IDirectSoundBuffer_GetStatus (dsoundsink->pDSBSecondary, &dwStatus);
+
+  /* get current play cursor position */
+  hRes2 = IDirectSoundBuffer_GetCurrentPosition (dsoundsink->pDSBSecondary,
+      &dwCurrentPlayCursor, NULL);
+
+  if (SUCCEEDED (hRes) && SUCCEEDED (hRes2) && (dwStatus & DSBSTATUS_PLAYING)) {
+    DWORD dwFreeBufferSize = 0;
+    GstClockTime sleep_time_ms = 0, sleep_until;
+    GstClockID clock_id;
+
+  calculate_freesize:
+    /* Calculate the free space in the circular buffer */
+    if (dwCurrentPlayCursor < dsoundsink->current_circular_offset)
+      dwFreeBufferSize =
+          dsoundsink->buffer_size - (dsoundsink->current_circular_offset -
+          dwCurrentPlayCursor);
+    else
+      dwFreeBufferSize =
+          dwCurrentPlayCursor - dsoundsink->current_circular_offset;
+
+    /* Not enough free space, wait for some samples to be played out. We could
+     * write out partial data, but that will result in a tight loop in the
+     * audioringbuffer write thread, and lead to high CPU usage. */
+    if (length > dwFreeBufferSize) {
+      gint rate = GST_AUDIO_BASE_SINK (asink)->ringbuffer->spec.info.rate;
+      /* Wait for a time proportional to the space needed. In reality, the
+       * directsound sink's position does not update frequently enough, so we
+       * will end up waiting for much longer. Note that Sleep() has millisecond
+       * resolution at best. */
+      sleep_time_ms = gst_util_uint64_scale_int ((length - dwFreeBufferSize),
+          1000, dsoundsink->bytes_per_sample * rate);
+      /* Make sure we don't run in a tight loop unnecessarily */
+      sleep_time_ms = MAX (sleep_time_ms, 10);
+      sleep_until = gst_clock_get_time (dsoundsink->system_clock) +
+          sleep_time_ms * GST_MSECOND;
+
+      GST_DEBUG_OBJECT (dsoundsink,
+          "length: %u, FreeBufSiz: %ld, sleep_time_ms: %" G_GUINT64_FORMAT
+          ", bps: %i, rate: %i", length, dwFreeBufferSize, sleep_time_ms,
+          dsoundsink->bytes_per_sample, rate);
+
+      if (G_UNLIKELY (dsoundsink->write_wait_clock_id == NULL ||
+              gst_clock_single_shot_id_reinit (dsoundsink->system_clock,
+                  dsoundsink->write_wait_clock_id, sleep_until) == FALSE)) {
+
+        if (dsoundsink->write_wait_clock_id != NULL) {
+          gst_clock_id_unref (dsoundsink->write_wait_clock_id);
+        }
+
+        dsoundsink->write_wait_clock_id =
+            gst_clock_new_single_shot_id (dsoundsink->system_clock,
+            sleep_until);
+      }
+
+      clock_id = dsoundsink->write_wait_clock_id;
+      dsoundsink->reset_while_sleeping = FALSE;
+
+      GST_DSOUND_UNLOCK (dsoundsink);
+
+      /* don't bother with the return value as we'll detect reset separately,
+         as reset could happen between when this returns and we obtain the lock
+         again -- so we can't use UNSCHEDULED here */
+      gst_clock_id_wait (clock_id, NULL);
+
+      GST_DSOUND_LOCK (dsoundsink);
+
+      /* if a reset occurs, exit now */
+      if (dsoundsink->reset_while_sleeping == TRUE) {
+        GST_DSOUND_UNLOCK (dsoundsink);
+        return -1;
+      }
+
+      /* May we send out? */
+      hRes = IDirectSoundBuffer_GetCurrentPosition (dsoundsink->pDSBSecondary,
+          &dwCurrentPlayCursor, NULL);
+      hRes2 =
+          IDirectSoundBuffer_GetStatus (dsoundsink->pDSBSecondary, &dwStatus);
+      if (SUCCEEDED (hRes) && SUCCEEDED (hRes2)
+          && (dwStatus & DSBSTATUS_PLAYING))
+        goto calculate_freesize;
+      else {
+        gchar *err1, *err2;
+
+        dsoundsink->first_buffer_after_reset = FALSE;
+        GST_DSOUND_UNLOCK (dsoundsink);
+
+        err1 = gst_hres_to_string (hRes);
+        err2 = gst_hres_to_string (hRes2);
+        GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_WRITE,
+            ("IDirectSoundBuffer_GetStatus %s, "
+                "IDirectSoundBuffer_GetCurrentPosition: %s, dwStatus: %lu",
+                err2, err1, dwStatus), (NULL));
+        g_free (err1);
+        g_free (err2);
+        return -1;
+      }
+    }
+  }
+
+  if (dwStatus & DSBSTATUS_BUFFERLOST) {
+    hRes = IDirectSoundBuffer_Restore (dsoundsink->pDSBSecondary);      /*need a loop waiting the buffer is restored?? */
+    dsoundsink->current_circular_offset = 0;
+  }
+
+  /* Lock a buffer of length @length for writing */
+  hRes = IDirectSoundBuffer_Lock (dsoundsink->pDSBSecondary,
+      dsoundsink->current_circular_offset, length, &pLockedBuffer1,
+      &dwSizeBuffer1, &pLockedBuffer2, &dwSizeBuffer2, 0L);
+
+  if (SUCCEEDED (hRes)) {
+    // Write to pointers without reordering.
+    memcpy (pLockedBuffer1, data, dwSizeBuffer1);
+    if (pLockedBuffer2 != NULL)
+      memcpy (pLockedBuffer2, (LPBYTE) data + dwSizeBuffer1, dwSizeBuffer2);
+
+    hRes = IDirectSoundBuffer_Unlock (dsoundsink->pDSBSecondary, pLockedBuffer1,
+        dwSizeBuffer1, pLockedBuffer2, dwSizeBuffer2);
+
+    // Update where the buffer will lock (for next time)
+    dsoundsink->current_circular_offset += dwSizeBuffer1 + dwSizeBuffer2;
+    dsoundsink->current_circular_offset %= dsoundsink->buffer_size;     /* Circular buffer */
+  }
+
+  /* if the buffer was not in playing state yet, call play on the buffer 
+     except if this buffer is the fist after a reset (base class call reset and write a buffer when setting the sink to pause) */
+  if (!(dwStatus & DSBSTATUS_PLAYING) &&
+      dsoundsink->first_buffer_after_reset == FALSE) {
+    hRes = IDirectSoundBuffer_Play (dsoundsink->pDSBSecondary, 0, 0,
+        DSBPLAY_LOOPING);
+  }
+
+  dsoundsink->first_buffer_after_reset = FALSE;
+
+  GST_DSOUND_UNLOCK (dsoundsink);
+
+  return length;
+}
+
+static guint
+gst_directsound_sink_delay (GstAudioSink * asink)
+{
+  GstDirectSoundSink *dsoundsink;
+  HRESULT hRes;
+  DWORD dwCurrentPlayCursor;
+  DWORD dwBytesInQueue = 0;
+  gint nNbSamplesInQueue = 0;
+  DWORD dwStatus;
+
+  dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
+  /* get current buffer status */
+  hRes = IDirectSoundBuffer_GetStatus (dsoundsink->pDSBSecondary, &dwStatus);
+
+  if (SUCCEEDED (hRes) && (dwStatus & DSBSTATUS_PLAYING)) {
+    /*evaluate the number of samples in queue in the circular buffer */
+    hRes = IDirectSoundBuffer_GetCurrentPosition (dsoundsink->pDSBSecondary,
+        &dwCurrentPlayCursor, NULL);
+
+    if (hRes == S_OK) {
+      if (dwCurrentPlayCursor < dsoundsink->current_circular_offset)
+        dwBytesInQueue =
+            dsoundsink->current_circular_offset - dwCurrentPlayCursor;
+      else
+        dwBytesInQueue =
+            dsoundsink->current_circular_offset + (dsoundsink->buffer_size -
+            dwCurrentPlayCursor);
+
+      nNbSamplesInQueue = dwBytesInQueue / dsoundsink->bytes_per_sample;
+    }
+  }
+
+  return nNbSamplesInQueue;
+}
+
+static void
+gst_directsound_sink_reset (GstAudioSink * asink)
+{
+  GstDirectSoundSink *dsoundsink;
+  LPVOID pLockedBuffer = NULL;
+  DWORD dwSizeBuffer = 0;
+
+  dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
+  GST_DSOUND_LOCK (dsoundsink);
+
+  if (dsoundsink->pDSBSecondary) {
+    /*stop playing */
+    HRESULT hRes = IDirectSoundBuffer_Stop (dsoundsink->pDSBSecondary);
+
+    /*reset position */
+    hRes = IDirectSoundBuffer_SetCurrentPosition (dsoundsink->pDSBSecondary, 0);
+    dsoundsink->current_circular_offset = 0;
+
+    /*reset the buffer */
+    hRes = IDirectSoundBuffer_Lock (dsoundsink->pDSBSecondary,
+        0, dsoundsink->buffer_size,
+        &pLockedBuffer, &dwSizeBuffer, NULL, NULL, 0L);
+
+    if (SUCCEEDED (hRes)) {
+      memset (pLockedBuffer, 0, dwSizeBuffer);
+
+      hRes =
+          IDirectSoundBuffer_Unlock (dsoundsink->pDSBSecondary, pLockedBuffer,
+          dwSizeBuffer, NULL, 0);
+    }
+  }
+
+  dsoundsink->reset_while_sleeping = TRUE;
+  dsoundsink->first_buffer_after_reset = TRUE;
+  if (dsoundsink->write_wait_clock_id != NULL) {
+    gst_clock_id_unschedule (dsoundsink->write_wait_clock_id);
+  }
+
+  GST_DSOUND_UNLOCK (dsoundsink);
+}
+
+/*
+ * gst_directsound_probe_supported_formats:
+ *
+ * Takes the template caps and returns the subset which is actually
+ * supported by this device.
+ *
+ */
+
+static GstCaps *
+gst_directsound_probe_supported_formats (GstDirectSoundSink * dsoundsink,
+    const GstCaps * template_caps)
+{
+  HRESULT hRes;
+  DSBUFFERDESC descSecondary;
+  WAVEFORMATEX wfx;
+  GstCaps *caps;
+  GstCaps *tmp, *tmp2;
+  LPDIRECTSOUNDBUFFER tmpBuffer;
+
+  caps = gst_caps_copy (template_caps);
+
+  /*
+   * Check availability of digital output by trying to create an SPDIF buffer
+   */
+
+#ifdef WAVE_FORMAT_DOLBY_AC3_SPDIF
+  /* fill the WAVEFORMATEX structure with some standard AC3 over SPDIF params */
+  memset (&wfx, 0, sizeof (wfx));
+  wfx.cbSize = 0;
+  wfx.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
+  wfx.nChannels = 2;
+  wfx.nSamplesPerSec = 48000;
+  wfx.wBitsPerSample = 16;
+  wfx.nBlockAlign = 4;
+  wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+  // create a secondary directsound buffer
+  memset (&descSecondary, 0, sizeof (DSBUFFERDESC));
+  descSecondary.dwSize = sizeof (DSBUFFERDESC);
+  descSecondary.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;
+  descSecondary.dwBufferBytes = 6144;
+  descSecondary.lpwfxFormat = &wfx;
+
+  hRes = IDirectSound_CreateSoundBuffer (dsoundsink->pDS, &descSecondary,
+      &tmpBuffer, NULL);
+  if (FAILED (hRes)) {
+    gchar *error_text = gst_hres_to_string (hRes);
+    GST_INFO_OBJECT (dsoundsink, "AC3 passthrough not supported "
+        "(IDirectSound_CreateSoundBuffer returned: %s)\n", error_text);
+    g_free (error_text);
+    tmp = gst_caps_new_empty_simple ("audio/x-ac3");
+    tmp2 = gst_caps_subtract (caps, tmp);
+    gst_caps_unref (tmp);
+    gst_caps_unref (caps);
+    caps = tmp2;
+    tmp = gst_caps_new_empty_simple ("audio/x-dts");
+    tmp2 = gst_caps_subtract (caps, tmp);
+    gst_caps_unref (tmp);
+    gst_caps_unref (caps);
+    caps = tmp2;
+  } else {
+    GST_INFO_OBJECT (dsoundsink, "AC3 passthrough supported");
+    hRes = IDirectSoundBuffer_Release (tmpBuffer);
+    if (FAILED (hRes)) {
+      gchar *error_text = gst_hres_to_string (hRes);
+      GST_DEBUG_OBJECT (dsoundsink,
+          "(IDirectSoundBuffer_Release returned: %s)\n", error_text);
+      g_free (error_text);
+    }
+  }
+#else
+  tmp = gst_caps_new_empty_simple ("audio/x-ac3");
+  tmp2 = gst_caps_subtract (caps, tmp);
+  gst_caps_unref (tmp);
+  gst_caps_unref (caps);
+  caps = tmp2;
+  tmp = gst_caps_new_empty_simple ("audio/x-dts");
+  tmp2 = gst_caps_subtract (caps, tmp);
+  gst_caps_unref (tmp);
+  gst_caps_unref (caps);
+  caps = tmp2;
+#endif
+
+  return caps;
+}
+
+static GstBuffer *
+gst_directsound_sink_payload (GstAudioBaseSink * sink, GstBuffer * buf)
+{
+  if (gst_directsound_sink_is_spdif_format (&sink->ringbuffer->spec)) {
+    gint framesize = gst_audio_iec61937_frame_size (&sink->ringbuffer->spec);
+    GstBuffer *out;
+    GstMapInfo infobuf, infoout;
+    gboolean success;
+
+    if (framesize <= 0)
+      return NULL;
+
+    out = gst_buffer_new_and_alloc (framesize);
+
+    if (!gst_buffer_map (buf, &infobuf, GST_MAP_READWRITE)) {
+      gst_buffer_unref (out);
+      return NULL;
+    }
+    if (!gst_buffer_map (out, &infoout, GST_MAP_READWRITE)) {
+      gst_buffer_unmap (buf, &infobuf);
+      gst_buffer_unref (out);
+      return NULL;
+    }
+    success = gst_audio_iec61937_payload (infobuf.data, infobuf.size,
+        infoout.data, infoout.size, &sink->ringbuffer->spec, G_BYTE_ORDER);
+    if (!success) {
+      gst_buffer_unmap (out, &infoout);
+      gst_buffer_unmap (buf, &infobuf);
+      gst_buffer_unref (out);
+      return NULL;
+    }
+
+    gst_buffer_copy_into (out, buf, GST_BUFFER_COPY_ALL, 0, -1);
+    /* Fix endianness */
+    _swab ((gchar *) infoout.data, (gchar *) infoout.data, infobuf.size);
+    gst_buffer_unmap (out, &infoout);
+    gst_buffer_unmap (buf, &infobuf);
+    return out;
+  } else
+    return gst_buffer_ref (buf);
+}
+
+static void
+gst_directsound_sink_set_volume (GstDirectSoundSink * dsoundsink,
+    gdouble dvolume, gboolean store)
+{
+  glong volume;
+
+  volume = dvolume * 100;
+  if (store)
+    dsoundsink->volume = volume;
+
+  if (dsoundsink->pDSBSecondary) {
+    /* DirectSound controls volume using units of 100th of a decibel,
+     * ranging from -10000 to 0. We use a linear scale of 0 - 100
+     * here, so remap.
+     */
+    long dsVolume;
+    if (volume == 0 || dsoundsink->mute)
+      dsVolume = -10000;
+    else
+      dsVolume = 100 * (long) (20 * log10 ((double) volume / 100.));
+    dsVolume = CLAMP (dsVolume, -10000, 0);
+
+    GST_DEBUG_OBJECT (dsoundsink,
+        "Setting volume on secondary buffer to %d from %d", (int) dsVolume,
+        (int) volume);
+    IDirectSoundBuffer_SetVolume (dsoundsink->pDSBSecondary, dsVolume);
+  }
+}
+
+gdouble
+gst_directsound_sink_get_volume (GstDirectSoundSink * dsoundsink)
+{
+  return (gdouble) dsoundsink->volume / 100;
+}
+
+static void
+gst_directsound_sink_set_mute (GstDirectSoundSink * dsoundsink, gboolean mute)
+{
+  if (mute) {
+    gst_directsound_sink_set_volume (dsoundsink, 0, FALSE);
+    dsoundsink->mute = TRUE;
+  } else {
+    gst_directsound_sink_set_volume (dsoundsink,
+        gst_directsound_sink_get_volume (dsoundsink), FALSE);
+    dsoundsink->mute = FALSE;
+  }
+
+}
+
+static gboolean
+gst_directsound_sink_get_mute (GstDirectSoundSink * dsoundsink)
+{
+  return dsoundsink->mute;
+}
+
+static const gchar *
+gst_directsound_sink_get_device (GstDirectSoundSink * dsoundsink)
+{
+  return dsoundsink->device_id;
+}
+
+static void
+gst_directsound_sink_set_device (GstDirectSoundSink * dsoundsink,
+    const gchar * device_id)
+{
+  g_free (dsoundsink->device_id);
+  dsoundsink->device_id = g_strdup (device_id);
+}
+
+/* Converts a HRESULT error to a text string
+ * LPTSTR is either a */
+static gchar *
+gst_hres_to_string (HRESULT hRes)
+{
+  DWORD flags;
+  gchar *ret_text;
+  LPTSTR error_text = NULL;
+
+  flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER
+      | FORMAT_MESSAGE_IGNORE_INSERTS;
+  FormatMessage (flags, NULL, hRes, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+      (LPTSTR) & error_text, 0, NULL);
+
+#ifdef UNICODE
+  /* If UNICODE is defined, LPTSTR is LPWSTR which is UTF-16 */
+  ret_text = g_utf16_to_utf8 (error_text, 0, NULL, NULL, NULL);
+#else
+  ret_text = g_strdup (error_text);
+#endif
+
+  LocalFree (error_text);
+  return ret_text;
+}
diff --git a/sys/directsound/gstdirectsoundsink.h b/sys/directsound/gstdirectsoundsink.h
new file mode 100644
index 0000000..144dfae
--- /dev/null
+++ b/sys/directsound/gstdirectsoundsink.h
@@ -0,0 +1,112 @@
+/* GStreamer
+ * Copyright (C)  2005 Sebastien Moutte <sebastien@moutte.net>
+ * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ * Copyright (C) 2010 Fluendo S.A. <support@fluendo.com>
+ *
+ * gstdirectsoundsink.h: 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * The development of this code was made possible due to the involvement
+ * of Pioneers of the Inevitable, the creators of the Songbird Music player
+ *
+ * 
+ */
+
+#ifndef __GST_DIRECTSOUNDSINK_H__
+#define __GST_DIRECTSOUNDSINK_H__
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiosink.h>
+
+#include <windows.h>
+#include <dsound.h>
+#include <mmreg.h> 
+#include <ks.h> 
+#include <ksmedia.h> 
+
+G_BEGIN_DECLS
+#define GST_TYPE_DIRECTSOUND_SINK            (gst_directsound_sink_get_type())
+#define GST_DIRECTSOUND_SINK(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DIRECTSOUND_SINK,GstDirectSoundSink))
+#define GST_DIRECTSOUND_SINK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DIRECTSOUND_SINK,GstDirectSoundSinkClass))
+#define GST_IS_DIRECTSOUND_SINK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DIRECTSOUND_SINK))
+#define GST_IS_DIRECTSOUND_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DIRECTSOUND_SINK))
+typedef struct _GstDirectSoundSink GstDirectSoundSink;
+typedef struct _GstDirectSoundSinkClass GstDirectSoundSinkClass;
+
+#define GST_DSOUND_LOCK(obj)	(g_mutex_lock (&obj->dsound_lock))
+#define GST_DSOUND_UNLOCK(obj)	(g_mutex_unlock (&obj->dsound_lock))
+
+struct _GstDirectSoundSink
+{
+  GstAudioSink sink;
+
+
+  /* directsound object interface pointer */
+  LPDIRECTSOUND pDS;
+
+  /* directsound sound object interface pointer */
+  LPDIRECTSOUNDBUFFER pDSBSecondary;
+
+  /* directSound buffer size */
+  guint buffer_size;
+
+  /* offset of the circular buffer where we must write next */
+  guint current_circular_offset;
+
+  guint bytes_per_sample;
+
+  /* current volume setup by mixer interface */
+  glong volume;
+  gboolean mute;
+  
+  /* current directsound device ID */
+  gchar * device_id;
+
+  GstCaps *cached_caps;
+  /* lock used to protect writes and resets */
+  GMutex dsound_lock;
+
+  GstClock *system_clock;
+  GstClockID write_wait_clock_id;
+  gboolean reset_while_sleeping;
+
+  gboolean first_buffer_after_reset;
+
+  GstAudioRingBufferFormatType type;
+};
+
+struct _GstDirectSoundSinkClass
+{
+  GstAudioSinkClass parent_class;
+};
+
+GType gst_directsound_sink_get_type (void);
+
+#define GST_DIRECTSOUND_SINK_CAPS "audio/x-raw, " \
+        "format = (string) S16LE, " \
+        "layout = (string) interleaved, " \
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; " \
+        "audio/x-raw, " \
+        "format = (string) U8, " \
+        "layout = (string) interleaved, " \
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ];" \
+        "audio/x-ac3, framed = (boolean) true;" \
+        "audio/x-dts, framed = (boolean) true;"
+
+G_END_DECLS
+#endif /* __GST_DIRECTSOUNDSINK_H__ */
diff --git a/sys/directsound/meson.build b/sys/directsound/meson.build
new file mode 100644
index 0000000..eed3ffd
--- /dev/null
+++ b/sys/directsound/meson.build
@@ -0,0 +1,16 @@
+directsoundsink_sources = [
+  'gstdirectsoundsink.c',
+  'gstdirectsoundplugin.c',
+]
+
+if host_machine.system() == 'windows' and cc.has_header('dsound.h')
+  directsoundsink_dep = [cc.find_library('dsound'), cc.find_library('winmm'), cc.find_library('ole32')]
+
+  gstdirectsoundsink = library('gstdirectsound',
+    directsoundsink_sources,
+    c_args : gst_plugins_good_args,
+    include_directories : [configinc],
+    dependencies : [gstaudio_dep] + directsoundsink_dep,
+    install : true,
+    install_dir : plugins_install_dir)
+endif
diff --git a/sys/meson.build b/sys/meson.build
new file mode 100644
index 0000000..031ee78
--- /dev/null
+++ b/sys/meson.build
@@ -0,0 +1,10 @@
+subdir('directsound')
+subdir('oss')
+subdir('oss4')
+subdir('v4l2')
+subdir('ximage')
+
+# FIXME: Implement these
+#subdir('osxaudio')
+#subdir('osxvideo')
+#subdir('waveform')
diff --git a/sys/oss/.gitignore b/sys/oss/.gitignore
new file mode 100644
index 0000000..cd988fb
--- /dev/null
+++ b/sys/oss/.gitignore
@@ -0,0 +1 @@
+oss_probe
diff --git a/sys/oss/Makefile.am b/sys/oss/Makefile.am
new file mode 100644
index 0000000..e9079a8
--- /dev/null
+++ b/sys/oss/Makefile.am
@@ -0,0 +1,20 @@
+plugin_LTLIBRARIES = libgstossaudio.la
+
+libgstossaudio_la_SOURCES = gstossaudio.c	 \
+		            gstosshelper.c	 \
+			    gstosssink.c	 \
+			    gstosssrc.c
+
+libgstossaudio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstossaudio_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) \
+	-lgstaudio-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) \
+	$(GST_LIBS)
+libgstossaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) 
+
+noinst_HEADERS = common.h            \
+		gstosssink.h	     \
+		gstosssrc.h	     \
+                gstosshelper.h	     \
+                gstossdmabuffer.h
diff --git a/sys/oss/common.h b/sys/oss/common.h
new file mode 100644
index 0000000..6c3632f
--- /dev/null
+++ b/sys/oss/common.h
@@ -0,0 +1,45 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2000,2005 Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/audio/audio.h>
+
+#define SET_PARAM(_oss, _name, _val, _detail)   \
+G_STMT_START {                                  \
+  int _tmp = _val;                              \
+  if (ioctl(_oss->fd, _name, &_tmp) == -1) {    \
+    GST_ELEMENT_ERROR (_oss, RESOURCE, SETTINGS,\
+        (NULL),					\
+        ("Unable to set param " _detail ": %s", \
+                   g_strerror (errno)));        \
+    return FALSE;                               \
+  }                                             \
+  GST_DEBUG_OBJECT(_oss, _detail " %d", _tmp);  \
+} G_STMT_END
+
+#define GET_PARAM(_oss, _name, _val, _detail)   \
+G_STMT_START {                                  \
+  if (ioctl(oss->fd, _name, _val) == -1) {      \
+    GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, \
+        (NULL),					\
+        ("Unable to get param " _detail ": %s", \
+                   g_strerror (errno)));        \
+    return FALSE;                               \
+  }                                             \
+} G_STMT_END
diff --git a/sys/oss/gstossaudio.c b/sys/oss/gstossaudio.c
new file mode 100644
index 0000000..7194e2e
--- /dev/null
+++ b/sys/oss/gstossaudio.c
@@ -0,0 +1,59 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gst/gst-i18n-plugin.h"
+
+#include "common.h"
+#include "gstosssink.h"
+#include "gstosssrc.h"
+
+GST_DEBUG_CATEGORY (oss_debug);
+#define GST_CAT_DEFAULT oss_debug
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "osssrc", GST_RANK_SECONDARY,
+          GST_TYPE_OSS_SRC) ||
+      !gst_element_register (plugin, "osssink", GST_RANK_SECONDARY,
+          GST_TYPE_OSSSINK)) {
+    return FALSE;
+  }
+
+  GST_DEBUG_CATEGORY_INIT (oss_debug, "oss", 0, "OSS elements");
+
+#ifdef ENABLE_NLS
+  GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
+      LOCALEDIR);
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif /* ENABLE_NLS */
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    ossaudio,
+    "OSS (Open Sound System) support for GStreamer",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/sys/oss/gstossdmabuffer.c b/sys/oss/gstossdmabuffer.c
new file mode 100644
index 0000000..38ee61d
--- /dev/null
+++ b/sys/oss/gstossdmabuffer.c
@@ -0,0 +1,333 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2005 Wim Taymans <wim@fluendo.com>
+ *
+ * gstossdmabuffer.c: 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#ifdef HAVE_OSS_INCLUDE_IN_SYS
+# include <sys/soundcard.h>
+#else
+# ifdef HAVE_OSS_INCLUDE_IN_ROOT
+#  include <soundcard.h>
+# else
+#  ifdef HAVE_OSS_INCLUDE_IN_MACHINE
+#   include <machine/soundcard.h>
+#  else
+#   error "What to include?"
+#  endif /* HAVE_OSS_INCLUDE_IN_MACHINE */
+# endif /* HAVE_OSS_INCLUDE_IN_ROOT */
+#endif /* HAVE_OSS_INCLUDE_IN_SYS */
+
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <pthread.h>
+
+#include "gstossdmabuffer.h"
+
+GST_DEBUG_CATEGORY_EXTERN (oss_debug);
+#define GST_CAT_DEFAULT oss_debug
+
+static void gst_ossdmabuffer_class_init (GstOssDMABufferClass * klass);
+static void gst_ossdmabuffer_init (GstOssDMABuffer * ossdmabuffer);
+static void gst_ossdmabuffer_dispose (GObject * object);
+static void gst_ossdmabuffer_finalize (GObject * object);
+
+static gboolean gst_ossdmabuffer_acquire (GstRingBuffer * buf,
+    GstRingBufferSpec * spec);
+static gboolean gst_ossdmabuffer_release (GstRingBuffer * buf);
+static gboolean gst_ossdmabuffer_play (GstRingBuffer * buf);
+static gboolean gst_ossdmabuffer_stop (GstRingBuffer * buf);
+
+static GstRingBufferClass *parent_class = NULL;
+
+GType
+gst_ossdmabuffer_get_type (void)
+{
+  static GType ossdmabuffer_type = 0;
+
+  if (!ossdmabuffer_type) {
+    static const GTypeInfo ossdmabuffer_info = {
+      sizeof (GstOssDMABufferClass),
+      NULL,
+      NULL,
+      (GClassInitFunc) gst_ossdmabuffer_class_init,
+      NULL,
+      NULL,
+      sizeof (GstOssDMABuffer),
+      0,
+      (GInstanceInitFunc) gst_ossdmabuffer_init,
+      NULL
+    };
+
+    ossdmabuffer_type =
+        g_type_register_static (GST_TYPE_RINGBUFFER, "GstOssDMABuffer",
+        &ossdmabuffer_info, 0);
+  }
+  return ossdmabuffer_type;
+}
+
+static void
+gst_ossdmabuffer_class_init (GstOssDMABufferClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstObjectClass *gstobject_class;
+  GstRingBufferClass *gstringbuffer_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstobject_class = (GstObjectClass *) klass;
+  gstringbuffer_class = (GstRingBufferClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->dispose = gst_ossdmabuffer_dispose;
+  gobject_class->finalize = gst_ossdmabuffer_finalize;
+
+  gstringbuffer_class->acquire = gst_ossdmabuffer_acquire;
+  gstringbuffer_class->release = gst_ossdmabuffer_release;
+  gstringbuffer_class->play = gst_ossdmabuffer_play;
+  gstringbuffer_class->stop = gst_ossdmabuffer_stop;
+}
+
+static void
+gst_ossdmabuffer_init (GstOssDMABuffer * ossdmabuffer)
+{
+  ossdmabuffer->cond = g_cond_new ();
+  ossdmabuffer->element = g_object_new (GST_TYPE_OSSELEMENT, NULL);
+}
+
+static void
+gst_ossdmabuffer_dispose (GObject * object)
+{
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_ossdmabuffer_finalize (GObject * object)
+{
+  GstOssDMABuffer *obuf = (GstOssDMABuffer *) object;
+
+  g_cond_free (obuf->cond);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_ossdmabuffer_func (GstRingBuffer * buf)
+{
+  fd_set writeset;
+  struct count_info count;
+  GstOssDMABuffer *obuf = (GstOssDMABuffer *) buf;
+
+  GST_OBJECT_LOCK (buf);
+  while (obuf->running) {
+    if (buf->state == GST_RINGBUFFER_STATE_PLAYING) {
+      int segsize;
+
+      GST_OBJECT_UNLOCK (buf);
+
+      segsize = buf->spec.segsize;
+
+      FD_ZERO (&writeset);
+      FD_SET (obuf->fd, &writeset);
+
+      select (obuf->fd + 1, NULL, &writeset, NULL, NULL);
+
+      if (ioctl (obuf->fd, SNDCTL_DSP_GETOPTR, &count) == -1) {
+        perror ("GETOPTR");
+        continue;
+      }
+
+      if (count.blocks > buf->spec.segtotal)
+        count.blocks = buf->spec.segtotal;
+
+      gst_ringbuffer_callback (buf, count.blocks);
+
+      GST_OBJECT_LOCK (buf);
+    } else {
+      GST_OSSDMABUFFER_SIGNAL (obuf);
+      GST_OSSDMABUFFER_WAIT (obuf);
+    }
+  }
+  GST_OBJECT_UNLOCK (buf);
+}
+
+static gboolean
+gst_ossdmabuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
+{
+  int tmp;
+  struct audio_buf_info info;
+  GstOssDMABuffer *obuf = (GstOssDMABuffer *) buf;
+  caddr_t mmap_buf;
+  int mode;
+  gint size;
+  gboolean parsed;
+
+  parsed = gst_osselement_parse_caps (obuf->element, spec->caps);
+  if (!parsed)
+    return FALSE;
+
+  mode = O_RDWR;
+  mode |= O_NONBLOCK;
+
+  obuf->fd = open ("/dev/dsp", mode, 0);
+  if (obuf->fd == -1) {
+    perror ("OPEN");
+    return FALSE;
+  }
+  //obuf->frag = 0x00040008;
+  obuf->frag = 0xffff000a;
+
+  tmp = obuf->element->format;
+  if (ioctl (obuf->fd, SNDCTL_DSP_SETFMT, &tmp) == -1) {
+    perror ("SETFMT");
+    return FALSE;
+  }
+
+  tmp = obuf->element->channels;
+  if (ioctl (obuf->fd, SNDCTL_DSP_STEREO, &tmp) == -1) {
+    perror ("STEREO");
+    return FALSE;
+  }
+
+  tmp = obuf->element->channels;
+  if (ioctl (obuf->fd, SNDCTL_DSP_CHANNELS, &tmp) == -1) {
+    perror ("CHANNELS");
+    return FALSE;
+  }
+
+  tmp = obuf->element->rate;
+  if (ioctl (obuf->fd, SNDCTL_DSP_SPEED, &tmp) == -1) {
+    perror ("SPEED");
+    return FALSE;
+  }
+
+  if (ioctl (obuf->fd, SNDCTL_DSP_GETCAPS, &obuf->caps) == -1) {
+    perror ("/dev/dsp");
+    fprintf (stderr, "Sorry but your sound driver is too old\n");
+    return FALSE;
+  }
+
+  if (!(obuf->caps & DSP_CAP_TRIGGER) || !(obuf->caps & DSP_CAP_MMAP)) {
+    fprintf (stderr, "Sorry but your soundcard can't do this\n");
+    return FALSE;
+  }
+
+  if (ioctl (obuf->fd, SNDCTL_DSP_SETFRAGMENT, &obuf->frag) == -1) {
+    perror ("SETFRAGMENT");
+    return FALSE;
+  }
+
+  if (ioctl (obuf->fd, SNDCTL_DSP_GETOSPACE, &info) == -1) {
+    perror ("GETOSPACE");
+    return FALSE;
+  }
+
+  buf->spec.segsize = info.fragsize;
+  buf->spec.segtotal = info.fragstotal;
+  size = info.fragsize * info.fragstotal;
+  g_print ("segsize %d, segtotal %d\n", info.fragsize, info.fragstotal);
+
+  mmap_buf = (caddr_t) mmap (NULL, size, PROT_WRITE,
+      MAP_FILE | MAP_SHARED, obuf->fd, 0);
+
+  if ((caddr_t) mmap_buf == (caddr_t) - 1) {
+    perror ("mmap (write)");
+    return FALSE;
+  }
+
+  buf->data = gst_buffer_new ();
+  GST_BUFFER_DATA (buf->data) = mmap_buf;
+  GST_BUFFER_SIZE (buf->data) = size;
+  GST_BUFFER_FLAG_SET (buf->data, GST_BUFFER_DONTFREE);
+
+  tmp = 0;
+  if (ioctl (obuf->fd, SNDCTL_DSP_SETTRIGGER, &tmp) == -1) {
+    perror ("SETTRIGGER");
+    return FALSE;
+  }
+
+  GST_OBJECT_LOCK (obuf);
+  obuf->running = TRUE;
+  obuf->thread = g_thread_create ((GThreadFunc) gst_ossdmabuffer_func,
+      buf, TRUE, NULL);
+  GST_OSSDMABUFFER_WAIT (obuf);
+  GST_OBJECT_UNLOCK (obuf);
+
+  return TRUE;
+}
+
+static gboolean
+gst_ossdmabuffer_release (GstRingBuffer * buf)
+{
+  GstOssDMABuffer *obuf = (GstOssDMABuffer *) buf;
+
+  gst_buffer_unref (buf->data);
+
+  GST_OBJECT_LOCK (obuf);
+  obuf->running = FALSE;
+  GST_OSSDMABUFFER_SIGNAL (obuf);
+  GST_OBJECT_UNLOCK (obuf);
+
+  g_thread_join (obuf->thread);
+
+  return TRUE;
+}
+
+static gboolean
+gst_ossdmabuffer_play (GstRingBuffer * buf)
+{
+  int tmp;
+  GstOssDMABuffer *obuf;
+
+  obuf = (GstOssDMABuffer *) buf;
+
+  tmp = PCM_ENABLE_OUTPUT;
+  if (ioctl (obuf->fd, SNDCTL_DSP_SETTRIGGER, &tmp) == -1) {
+    perror ("SETTRIGGER");
+  }
+  GST_OSSDMABUFFER_SIGNAL (obuf);
+
+  return TRUE;
+}
+
+static gboolean
+gst_ossdmabuffer_stop (GstRingBuffer * buf)
+{
+  int tmp;
+  GstOssDMABuffer *obuf;
+
+  obuf = (GstOssDMABuffer *) buf;
+
+  tmp = 0;
+  if (ioctl (obuf->fd, SNDCTL_DSP_SETTRIGGER, &tmp) == -1) {
+    perror ("SETTRIGGER");
+  }
+  GST_OSSDMABUFFER_WAIT (obuf);
+  buf->playseg = 0;
+
+  return TRUE;
+}
diff --git a/sys/oss/gstossdmabuffer.h b/sys/oss/gstossdmabuffer.h
new file mode 100644
index 0000000..9143b03
--- /dev/null
+++ b/sys/oss/gstossdmabuffer.h
@@ -0,0 +1,77 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2005 Wim Taymans <wim@fluendo.com>
+ *
+ * gstossdmabuffer.h: 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_OSSDMABUFFER_H__
+#define __GST_OSSDMABUFFER_H__
+
+#include <gst/gst.h>
+
+#include "gstosshelper.h"
+#include <gst/audio/gstringbuffer.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_OSSDMABUFFER            (gst_ossdmabuffer_get_type())
+#define GST_OSSDMABUFFER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSSDMABUFFER,GstOssDMABuffer))
+#define GST_OSSDMABUFFER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSSDMABUFFER,GstOssDMABufferClass))
+#define GST_IS_OSSDMABUFFER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSSDMABUFFER))
+#define GST_IS_OSSDMABUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSSDMABUFFER))
+
+#define GST_OSSELEMENT_GET(obj)  GST_OSSELEMENT (obj->element)
+
+typedef enum {
+  GST_OSSDMABUFFER_OPEN         = (1 << 0),
+} GstOssDMABufferFlags;
+
+typedef struct _GstOssDMABuffer GstOssDMABuffer;
+typedef struct _GstOssDMABufferClass GstOssDMABufferClass;
+
+#define GST_OSSDMABUFFER_THREAD(buf)   (GST_OSSDMABUFFER(buf)->thread)
+#define GST_OSSDMABUFFER_LOCK          GST_OBJECT_LOCK
+#define GST_OSSDMABUFFER_UNLOCK        GST_OBJECT_UNLOCK
+#define GST_OSSDMABUFFER_COND(buf)     (GST_OSSDMABUFFER(buf)->cond)
+#define GST_OSSDMABUFFER_SIGNAL(buf)   (g_cond_signal (GST_OSSDMABUFFER_COND (buf)))
+#define GST_OSSDMABUFFER_WAIT(buf)     (g_cond_wait (GST_OSSDMABUFFER_COND (buf), GST_OBJECT_GET_LOCK (buf)))
+
+struct _GstOssDMABuffer {
+  GstRingBuffer  buffer;
+
+  GstOssElement *element;
+
+  int            fd;
+  int            caps;
+  int            frag;
+
+  GThread       *thread;
+  GCond         *cond;
+  gboolean       running;
+};
+
+struct _GstOssDMABufferClass {
+  GstRingBufferClass parent_class;
+};
+
+GType gst_ossdmabuffer_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_OSSDMABUFFER_H__ */
diff --git a/sys/oss/gstosshelper.c b/sys/oss/gstosshelper.c
new file mode 100644
index 0000000..e649e00
--- /dev/null
+++ b/sys/oss/gstosshelper.c
@@ -0,0 +1,421 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wim.taymans@chello.be>
+ *
+ * gstosshelper.c: OSS helper routines
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gst/gst-i18n-plugin.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#ifdef HAVE_OSS_INCLUDE_IN_SYS
+# include <sys/soundcard.h>
+#else
+# ifdef HAVE_OSS_INCLUDE_IN_ROOT
+#  include <soundcard.h>
+# else
+#  ifdef HAVE_OSS_INCLUDE_IN_MACHINE
+#   include <machine/soundcard.h>
+#  else
+#   error "What to include?"
+#  endif /* HAVE_OSS_INCLUDE_IN_MACHINE */
+# endif /* HAVE_OSS_INCLUDE_IN_ROOT */
+#endif /* HAVE_OSS_INCLUDE_IN_SYS */
+
+#include "gstosshelper.h"
+
+GST_DEBUG_CATEGORY_EXTERN (oss_debug);
+#define GST_CAT_DEFAULT oss_debug
+
+typedef struct _GstOssProbe GstOssProbe;
+struct _GstOssProbe
+{
+  int fd;
+  int format;
+  int n_channels;
+  GArray *rates;
+  int min;
+  int max;
+};
+
+typedef struct _GstOssRange GstOssRange;
+struct _GstOssRange
+{
+  int min;
+  int max;
+};
+
+static GstStructure *gst_oss_helper_get_format_structure (unsigned int
+    format_bit);
+static gboolean gst_oss_helper_rate_probe_check (GstOssProbe * probe);
+static int gst_oss_helper_rate_check_rate (GstOssProbe * probe, int irate);
+static void gst_oss_helper_rate_add_range (GQueue * queue, int min, int max);
+static void gst_oss_helper_rate_add_rate (GArray * array, int rate);
+static int gst_oss_helper_rate_int_compare (gconstpointer a, gconstpointer b);
+
+GstCaps *
+gst_oss_helper_probe_caps (gint fd)
+{
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+  const guint probe_formats[] = { AFMT_S16_LE, AFMT_U16_LE, AFMT_U8, AFMT_S8 };
+#else
+  const guint probe_formats[] = { AFMT_S16_BE, AFMT_U16_BE, AFMT_U8, AFMT_S8 };
+#endif
+  GstOssProbe *probe;
+  int i, f;
+  gboolean ret;
+  GstStructure *structure;
+  GstCaps *caps;
+
+  /* FIXME test make sure we're not currently playing */
+  /* FIXME test both mono and stereo */
+
+  caps = gst_caps_new_empty ();
+
+  /* assume that the most significant bit of format_mask is 0 */
+  for (f = 0; f < G_N_ELEMENTS (probe_formats); ++f) {
+    GValue rate_value = { 0 };
+
+    probe = g_new0 (GstOssProbe, 1);
+    probe->fd = fd;
+    probe->format = probe_formats[f];
+    /* FIXME: this is not working for all cards, see bug #518474 */
+    probe->n_channels = 2;
+
+    ret = gst_oss_helper_rate_probe_check (probe);
+    if (probe->min == -1 || probe->max == -1) {
+      g_array_free (probe->rates, TRUE);
+      g_free (probe);
+      continue;
+    }
+
+    if (ret) {
+      GValue value = { 0 };
+
+      g_array_sort (probe->rates, gst_oss_helper_rate_int_compare);
+
+      g_value_init (&rate_value, GST_TYPE_LIST);
+      g_value_init (&value, G_TYPE_INT);
+
+      for (i = 0; i < probe->rates->len; i++) {
+        g_value_set_int (&value, g_array_index (probe->rates, int, i));
+
+        gst_value_list_append_value (&rate_value, &value);
+      }
+
+      g_value_unset (&value);
+    } else {
+      /* one big range */
+      g_value_init (&rate_value, GST_TYPE_INT_RANGE);
+      gst_value_set_int_range (&rate_value, probe->min, probe->max);
+    }
+
+    g_array_free (probe->rates, TRUE);
+    g_free (probe);
+
+    structure = gst_oss_helper_get_format_structure (probe_formats[f]);
+    gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
+    gst_structure_set_value (structure, "rate", &rate_value);
+    g_value_unset (&rate_value);
+
+    gst_caps_append_structure (caps, structure);
+  }
+
+  if (gst_caps_is_empty (caps)) {
+    /* fixme: make user-visible */
+    GST_WARNING ("Your OSS device could not be probed correctly");
+  } else {
+    caps = gst_caps_simplify (caps);
+  }
+
+  GST_DEBUG ("probed caps: %" GST_PTR_FORMAT, caps);
+
+  return caps;
+}
+
+static GstStructure *
+gst_oss_helper_get_format_structure (unsigned int format_bit)
+{
+  GstStructure *structure;
+  const gchar *format;
+
+  switch (format_bit) {
+    case AFMT_U8:
+      format = "U8";
+      break;
+    case AFMT_S16_LE:
+      format = "S16LE";
+      break;
+    case AFMT_S16_BE:
+      format = "S16BE";
+      break;
+    case AFMT_S8:
+      format = "S8";
+      break;
+    case AFMT_U16_LE:
+      format = "U16LE";
+      break;
+    case AFMT_U16_BE:
+      format = "U16BE";
+      break;
+    default:
+      g_assert_not_reached ();
+      return NULL;
+  }
+
+  structure = gst_structure_new ("audio/x-raw",
+      "format", G_TYPE_STRING, format,
+      "layout", G_TYPE_STRING, "interleaved", NULL);
+
+  return structure;
+}
+
+static gboolean
+gst_oss_helper_rate_probe_check (GstOssProbe * probe)
+{
+  GstOssRange *range;
+  GQueue *ranges;
+  int exact_rates = 0;
+  gboolean checking_exact_rates = TRUE;
+  int n_checks = 0;
+  gboolean result = TRUE;
+
+  ranges = g_queue_new ();
+
+  probe->rates = g_array_new (FALSE, FALSE, sizeof (int));
+
+  probe->min = gst_oss_helper_rate_check_rate (probe, 1000);
+  n_checks++;
+  probe->max = gst_oss_helper_rate_check_rate (probe, 100000);
+  /* a little bug workaround */
+  {
+    int max;
+
+    max = gst_oss_helper_rate_check_rate (probe, 48000);
+    if (max > probe->max) {
+      GST_ERROR
+          ("Driver bug recognized (driver does not round rates correctly).  Please file a bug report.");
+      probe->max = max;
+    }
+  }
+  n_checks++;
+  if (probe->min == -1 || probe->max == -1) {
+    /* This is a workaround for drivers that return -EINVAL (or another
+     * error) for rates outside of [8000,48000].  If this fails, the
+     * driver is seriously buggy, and probably doesn't work with other
+     * media libraries/apps.  */
+    probe->min = gst_oss_helper_rate_check_rate (probe, 8000);
+    probe->max = gst_oss_helper_rate_check_rate (probe, 48000);
+  }
+  if (probe->min == -1 || probe->max == -1) {
+    GST_DEBUG ("unexpected check_rate error");
+    return FALSE;
+  }
+  gst_oss_helper_rate_add_range (ranges, probe->min + 1, probe->max - 1);
+
+  while ((range = g_queue_pop_head (ranges))) {
+    int min1;
+    int max1;
+    int mid;
+    int mid_ret;
+
+    GST_DEBUG ("checking [%d,%d]", range->min, range->max);
+
+    mid = (range->min + range->max) / 2;
+    mid_ret = gst_oss_helper_rate_check_rate (probe, mid);
+    if (mid_ret == -1) {
+      /* FIXME ioctl returned an error.  do something */
+      GST_DEBUG ("unexpected check_rate error");
+    }
+    n_checks++;
+
+    if (mid == mid_ret && checking_exact_rates) {
+      int max_exact_matches = 20;
+
+      exact_rates++;
+      if (exact_rates > max_exact_matches) {
+        GST_DEBUG ("got %d exact rates, assuming all are exact",
+            max_exact_matches);
+        result = FALSE;
+        g_free (range);
+        break;
+      }
+    } else {
+      checking_exact_rates = FALSE;
+    }
+
+    /* Assume that the rate is arithmetically rounded to the nearest
+     * supported rate. */
+    if (mid == mid_ret) {
+      min1 = mid - 1;
+      max1 = mid + 1;
+    } else {
+      if (mid < mid_ret) {
+        min1 = mid - (mid_ret - mid);
+        max1 = mid_ret + 1;
+      } else {
+        min1 = mid_ret - 1;
+        max1 = mid + (mid - mid_ret);
+      }
+    }
+
+    gst_oss_helper_rate_add_range (ranges, range->min, min1);
+    gst_oss_helper_rate_add_range (ranges, max1, range->max);
+
+    g_free (range);
+  }
+
+  while ((range = g_queue_pop_head (ranges))) {
+    g_free (range);
+  }
+  g_queue_free (ranges);
+
+  return result;
+}
+
+static void
+gst_oss_helper_rate_add_range (GQueue * queue, int min, int max)
+{
+  if (min <= max) {
+    GstOssRange *range = g_new0 (GstOssRange, 1);
+
+    range->min = min;
+    range->max = max;
+
+    g_queue_push_tail (queue, range);
+    /* push_head also works, but has different probing behavior */
+    /*g_queue_push_head (queue, range); */
+  }
+}
+
+static int
+gst_oss_helper_rate_check_rate (GstOssProbe * probe, int irate)
+{
+  int rate;
+  int format;
+  int n_channels;
+  int ret;
+
+  rate = irate;
+  format = probe->format;
+  n_channels = probe->n_channels;
+
+  GST_LOG ("checking format %d, channels %d, rate %d",
+      format, n_channels, rate);
+  ret = ioctl (probe->fd, SNDCTL_DSP_SETFMT, &format);
+  if (ret < 0 || format != probe->format) {
+    GST_DEBUG ("unsupported format: %d (%d)", probe->format, format);
+    return -1;
+  }
+  ret = ioctl (probe->fd, SNDCTL_DSP_CHANNELS, &n_channels);
+  if (ret < 0 || n_channels != probe->n_channels) {
+    GST_DEBUG ("unsupported channels: %d (%d)", probe->n_channels, n_channels);
+    return -1;
+  }
+  ret = ioctl (probe->fd, SNDCTL_DSP_SPEED, &rate);
+  if (ret < 0) {
+    GST_DEBUG ("unsupported rate: %d (%d)", irate, rate);
+    return -1;
+  }
+
+  GST_DEBUG ("rate %d -> %d", irate, rate);
+
+  if (rate == irate - 1 || rate == irate + 1) {
+    rate = irate;
+  }
+  gst_oss_helper_rate_add_rate (probe->rates, rate);
+  return rate;
+}
+
+static void
+gst_oss_helper_rate_add_rate (GArray * array, int rate)
+{
+  int i;
+  int val;
+
+  for (i = 0; i < array->len; i++) {
+    val = g_array_index (array, int, i);
+
+    if (val == rate)
+      return;
+  }
+  GST_DEBUG ("supported rate: %d", rate);
+  g_array_append_val (array, rate);
+}
+
+static int
+gst_oss_helper_rate_int_compare (gconstpointer a, gconstpointer b)
+{
+  const int *va = (const int *) a;
+  const int *vb = (const int *) b;
+
+  if (*va < *vb)
+    return -1;
+  if (*va > *vb)
+    return 1;
+  return 0;
+}
+
+gchar *
+gst_oss_helper_get_card_name (const gchar * mixer_name)
+{
+#ifdef SOUND_MIXER_INFO
+  struct mixer_info minfo;
+#endif
+  gint fd;
+  gchar *name = NULL;
+
+  GST_INFO ("Opening mixer for device %s", mixer_name);
+  fd = open (mixer_name, O_RDWR);
+  if (fd == -1)
+    goto open_failed;
+
+  /* get name, not fatal */
+#ifdef SOUND_MIXER_INFO
+  if (ioctl (fd, SOUND_MIXER_INFO, &minfo) == 0) {
+    name = g_strdup (minfo.name);
+    GST_INFO ("Card name = %s", GST_STR_NULL (name));
+  } else
+#endif
+  {
+    name = g_strdup ("Unknown");
+    GST_INFO ("Unknown card name");
+  }
+
+  close (fd);
+  return name;
+
+  /* ERRORS */
+open_failed:
+  {
+    /* this is valid. OSS devices don't need to expose a mixer */
+    GST_DEBUG ("Failed to open mixer device %s, mixing disabled: %s",
+        mixer_name, strerror (errno));
+    return NULL;
+  }
+}
diff --git a/sys/oss/gstosshelper.h b/sys/oss/gstosshelper.h
new file mode 100644
index 0000000..d9f9914
--- /dev/null
+++ b/sys/oss/gstosshelper.h
@@ -0,0 +1,46 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wim.taymans@chello.be>
+ *
+ * gstosshelper.h: OSS helper routines.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_OSS_HELPER_H__
+#define __GST_OSS_HELPER_H__
+
+
+#include <gst/gst.h>
+#include <sys/types.h>
+
+#include "gstosshelper.h"
+
+
+G_BEGIN_DECLS
+
+
+GstCaps* gst_oss_helper_probe_caps (gint fd);
+
+gchar *gst_oss_helper_get_card_name (const gchar * mixer_name);
+
+
+
+G_END_DECLS
+
+
+#endif /* __GST_OSS_HELPER_H__ */
diff --git a/sys/oss/gstosssink.c b/sys/oss/gstosssink.c
new file mode 100644
index 0000000..2e6b8c5
--- /dev/null
+++ b/sys/oss/gstosssink.c
@@ -0,0 +1,556 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2000,2005 Wim Taymans <wim@fluendo.com>
+ *
+ * gstosssink.c: 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-osssink
+ *
+ * This element lets you output sound using the Open Sound System (OSS).
+ *
+ * Note that you should almost always use generic audio conversion elements
+ * like audioconvert and audioresample in front of an audiosink to make sure
+ * your pipeline works under all circumstances (those conversion elements will
+ * act in passthrough-mode if no conversion is necessary).
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! audioconvert ! volume volume=0.1 ! osssink
+ * ]| will output a sine wave (continuous beep sound) to your sound card (with
+ * a very low volume as precaution).
+ * |[
+ * gst-launch-1.0 -v filesrc location=music.ogg ! decodebin ! audioconvert ! audioresample ! osssink
+ * ]| will play an Ogg/Vorbis audio file and output it using the Open Sound System.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#ifdef HAVE_OSS_INCLUDE_IN_SYS
+# include <sys/soundcard.h>
+#else
+# ifdef HAVE_OSS_INCLUDE_IN_ROOT
+#  include <soundcard.h>
+# else
+#  ifdef HAVE_OSS_INCLUDE_IN_MACHINE
+#   include <machine/soundcard.h>
+#  else
+#   error "What to include?"
+#  endif /* HAVE_OSS_INCLUDE_IN_MACHINE */
+# endif /* HAVE_OSS_INCLUDE_IN_ROOT */
+#endif /* HAVE_OSS_INCLUDE_IN_SYS */
+
+#include "common.h"
+#include "gstosssink.h"
+
+#include <gst/gst-i18n-plugin.h>
+
+GST_DEBUG_CATEGORY_EXTERN (oss_debug);
+#define GST_CAT_DEFAULT oss_debug
+
+static void gst_oss_sink_dispose (GObject * object);
+static void gst_oss_sink_finalise (GObject * object);
+
+static void gst_oss_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_oss_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_oss_sink_getcaps (GstBaseSink * bsink, GstCaps * filter);
+
+static gboolean gst_oss_sink_open (GstAudioSink * asink);
+static gboolean gst_oss_sink_close (GstAudioSink * asink);
+static gboolean gst_oss_sink_prepare (GstAudioSink * asink,
+    GstAudioRingBufferSpec * spec);
+static gboolean gst_oss_sink_unprepare (GstAudioSink * asink);
+static gint gst_oss_sink_write (GstAudioSink * asink, gpointer data,
+    guint length);
+static guint gst_oss_sink_delay (GstAudioSink * asink);
+static void gst_oss_sink_reset (GstAudioSink * asink);
+
+/* OssSink signals and args */
+enum
+{
+  LAST_SIGNAL
+};
+
+#define DEFAULT_DEVICE  "/dev/dsp"
+enum
+{
+  PROP_0,
+  PROP_DEVICE,
+};
+
+#define FORMATS "{" GST_AUDIO_NE(S16)","GST_AUDIO_NE(U16)", S8, U8 }"
+
+static GstStaticPadTemplate osssink_sink_factory =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " FORMATS ", "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 1, MAX ], "
+        "channels = (int) 1; "
+        "audio/x-raw, "
+        "format = (string) " FORMATS ", "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 1, MAX ], "
+        "channels = (int) 2, " "channel-mask = (bitmask) 0x3")
+    );
+
+/* static guint gst_oss_sink_signals[LAST_SIGNAL] = { 0 }; */
+
+#define gst_oss_sink_parent_class parent_class
+G_DEFINE_TYPE (GstOssSink, gst_oss_sink, GST_TYPE_AUDIO_SINK);
+
+static void
+gst_oss_sink_dispose (GObject * object)
+{
+  GstOssSink *osssink = GST_OSSSINK (object);
+
+  if (osssink->probed_caps) {
+    gst_caps_unref (osssink->probed_caps);
+    osssink->probed_caps = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_oss_sink_class_init (GstOssSinkClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSinkClass *gstbasesink_class;
+  GstAudioSinkClass *gstaudiosink_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesink_class = (GstBaseSinkClass *) klass;
+  gstaudiosink_class = (GstAudioSinkClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->dispose = gst_oss_sink_dispose;
+  gobject_class->finalize = gst_oss_sink_finalise;
+  gobject_class->get_property = gst_oss_sink_get_property;
+  gobject_class->set_property = gst_oss_sink_set_property;
+
+  g_object_class_install_property (gobject_class, PROP_DEVICE,
+      g_param_spec_string ("device", "Device",
+          "OSS device (usually /dev/dspN)", DEFAULT_DEVICE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_oss_sink_getcaps);
+
+  gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_oss_sink_open);
+  gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_oss_sink_close);
+  gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_oss_sink_prepare);
+  gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_oss_sink_unprepare);
+  gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_oss_sink_write);
+  gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_oss_sink_delay);
+  gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_oss_sink_reset);
+
+  gst_element_class_set_static_metadata (gstelement_class, "Audio Sink (OSS)",
+      "Sink/Audio",
+      "Output to a sound card via OSS",
+      "Erik Walthinsen <omega@cse.ogi.edu>, "
+      "Wim Taymans <wim.taymans@chello.be>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &osssink_sink_factory);
+}
+
+static void
+gst_oss_sink_init (GstOssSink * osssink)
+{
+  const gchar *device;
+
+  GST_DEBUG_OBJECT (osssink, "initializing osssink");
+
+  device = g_getenv ("AUDIODEV");
+  if (device == NULL)
+    device = DEFAULT_DEVICE;
+  osssink->device = g_strdup (device);
+  osssink->fd = -1;
+}
+
+static void
+gst_oss_sink_finalise (GObject * object)
+{
+  GstOssSink *osssink = GST_OSSSINK (object);
+
+  g_free (osssink->device);
+
+  G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (object));
+}
+
+static void
+gst_oss_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstOssSink *sink;
+
+  sink = GST_OSSSINK (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE:
+      g_free (sink->device);
+      sink->device = g_value_dup_string (value);
+      if (sink->probed_caps) {
+        gst_caps_unref (sink->probed_caps);
+        sink->probed_caps = NULL;
+      }
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_oss_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstOssSink *sink;
+
+  sink = GST_OSSSINK (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE:
+      g_value_set_string (value, sink->device);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstCaps *
+gst_oss_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
+{
+  GstOssSink *osssink;
+  GstCaps *caps;
+
+  osssink = GST_OSSSINK (bsink);
+
+  if (osssink->fd == -1) {
+    caps = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
+  } else if (osssink->probed_caps) {
+    caps = gst_caps_ref (osssink->probed_caps);
+  } else {
+    caps = gst_oss_helper_probe_caps (osssink->fd);
+    if (caps && !gst_caps_is_empty (caps)) {
+      osssink->probed_caps = gst_caps_ref (caps);
+    }
+  }
+
+  if (filter && caps) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    return intersection;
+  } else {
+    return caps;
+  }
+}
+
+static gint
+ilog2 (gint x)
+{
+  /* well... hacker's delight explains... */
+  x = x | (x >> 1);
+  x = x | (x >> 2);
+  x = x | (x >> 4);
+  x = x | (x >> 8);
+  x = x | (x >> 16);
+  x = x - ((x >> 1) & 0x55555555);
+  x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
+  x = (x + (x >> 4)) & 0x0f0f0f0f;
+  x = x + (x >> 8);
+  x = x + (x >> 16);
+  return (x & 0x0000003f) - 1;
+}
+
+static gint
+gst_oss_sink_get_format (GstAudioRingBufferFormatType fmt, GstAudioFormat rfmt)
+{
+  gint result;
+
+  switch (fmt) {
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW:
+      result = AFMT_MU_LAW;
+      break;
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW:
+      result = AFMT_A_LAW;
+      break;
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IMA_ADPCM:
+      result = AFMT_IMA_ADPCM;
+      break;
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG:
+      result = AFMT_MPEG;
+      break;
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW:
+    {
+      switch (rfmt) {
+        case GST_AUDIO_FORMAT_U8:
+          result = AFMT_U8;
+          break;
+        case GST_AUDIO_FORMAT_S16LE:
+          result = AFMT_S16_LE;
+          break;
+        case GST_AUDIO_FORMAT_S16BE:
+          result = AFMT_S16_BE;
+          break;
+        case GST_AUDIO_FORMAT_S8:
+          result = AFMT_S8;
+          break;
+        case GST_AUDIO_FORMAT_U16LE:
+          result = AFMT_U16_LE;
+          break;
+        case GST_AUDIO_FORMAT_U16BE:
+          result = AFMT_U16_BE;
+          break;
+        default:
+          result = 0;
+          break;
+      }
+      break;
+    }
+    default:
+      result = 0;
+      break;
+  }
+  return result;
+}
+
+static gboolean
+gst_oss_sink_open (GstAudioSink * asink)
+{
+  GstOssSink *oss;
+  int mode;
+
+  oss = GST_OSSSINK (asink);
+
+  mode = O_WRONLY;
+  mode |= O_NONBLOCK;
+
+  oss->fd = open (oss->device, mode, 0);
+  if (oss->fd == -1) {
+    switch (errno) {
+      case EBUSY:
+        goto busy;
+      case EACCES:
+        goto no_permission;
+      default:
+        goto open_failed;
+    }
+  }
+
+  return TRUE;
+
+  /* ERRORS */
+busy:
+  {
+    GST_ELEMENT_ERROR (oss, RESOURCE, BUSY,
+        (_("Could not open audio device for playback. "
+                "Device is being used by another application.")), (NULL));
+    return FALSE;
+  }
+no_permission:
+  {
+    GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE,
+        (_("Could not open audio device for playback. "
+                "You don't have permission to open the device.")),
+        GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+open_failed:
+  {
+    GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE,
+        (_("Could not open audio device for playback.")), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_oss_sink_close (GstAudioSink * asink)
+{
+  close (GST_OSSSINK (asink)->fd);
+  GST_OSSSINK (asink)->fd = -1;
+  return TRUE;
+}
+
+static gboolean
+gst_oss_sink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec)
+{
+  GstOssSink *oss;
+  struct audio_buf_info info;
+  int mode;
+  int tmp;
+  guint width, rate, channels;
+
+  oss = GST_OSSSINK (asink);
+
+  /* we opened non-blocking so that we can detect if the device is available
+   * without hanging forever. We now want to remove the non-blocking flag. */
+  mode = fcntl (oss->fd, F_GETFL);
+  mode &= ~O_NONBLOCK;
+  if (fcntl (oss->fd, F_SETFL, mode) == -1) {
+    /* some drivers do no support unsetting the non-blocking flag, try to
+     * close/open the device then. This is racy but we error out properly. */
+    gst_oss_sink_close (asink);
+    if ((oss->fd = open (oss->device, O_WRONLY, 0)) == -1)
+      goto non_block;
+  }
+
+  tmp = gst_oss_sink_get_format (spec->type,
+      GST_AUDIO_INFO_FORMAT (&spec->info));
+  if (tmp == 0)
+    goto wrong_format;
+
+  width = GST_AUDIO_INFO_WIDTH (&spec->info);
+  rate = GST_AUDIO_INFO_RATE (&spec->info);
+  channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
+
+  if (width != 16 && width != 8)
+    goto dodgy_width;
+
+  SET_PARAM (oss, SNDCTL_DSP_SETFMT, tmp, "SETFMT");
+  if (channels == 2)
+    SET_PARAM (oss, SNDCTL_DSP_STEREO, 1, "STEREO");
+  SET_PARAM (oss, SNDCTL_DSP_CHANNELS, channels, "CHANNELS");
+  SET_PARAM (oss, SNDCTL_DSP_SPEED, rate, "SPEED");
+
+  tmp = ilog2 (spec->segsize);
+  tmp = ((spec->segtotal & 0x7fff) << 16) | tmp;
+  GST_DEBUG_OBJECT (oss, "set segsize: %d, segtotal: %d, value: %08x",
+      spec->segsize, spec->segtotal, tmp);
+
+  SET_PARAM (oss, SNDCTL_DSP_SETFRAGMENT, tmp, "SETFRAGMENT");
+  GET_PARAM (oss, SNDCTL_DSP_GETOSPACE, &info, "GETOSPACE");
+
+  spec->segsize = info.fragsize;
+  spec->segtotal = info.fragstotal;
+
+  oss->bytes_per_sample = GST_AUDIO_INFO_BPF (&spec->info);
+
+  GST_DEBUG_OBJECT (oss, "got segsize: %d, segtotal: %d, value: %08x",
+      spec->segsize, spec->segtotal, tmp);
+
+  return TRUE;
+
+  /* ERRORS */
+non_block:
+  {
+    GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, (NULL),
+        ("Unable to set device %s in non blocking mode: %s",
+            oss->device, g_strerror (errno)));
+    return FALSE;
+  }
+wrong_format:
+  {
+    GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, (NULL),
+        ("Unable to get format (%d, %d)", spec->type,
+            GST_AUDIO_INFO_FORMAT (&spec->info)));
+    return FALSE;
+  }
+dodgy_width:
+  {
+    GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, (NULL),
+        ("unexpected width %d", width));
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_oss_sink_unprepare (GstAudioSink * asink)
+{
+  /* could do a SNDCTL_DSP_RESET, but the OSS manual recommends a close/open */
+
+  if (!gst_oss_sink_close (asink))
+    goto couldnt_close;
+
+  if (!gst_oss_sink_open (asink))
+    goto couldnt_reopen;
+
+  return TRUE;
+
+  /* ERRORS */
+couldnt_close:
+  {
+    GST_DEBUG_OBJECT (asink, "Could not close the audio device");
+    return FALSE;
+  }
+couldnt_reopen:
+  {
+    GST_DEBUG_OBJECT (asink, "Could not reopen the audio device");
+    return FALSE;
+  }
+}
+
+static gint
+gst_oss_sink_write (GstAudioSink * asink, gpointer data, guint length)
+{
+  return write (GST_OSSSINK (asink)->fd, data, length);
+}
+
+static guint
+gst_oss_sink_delay (GstAudioSink * asink)
+{
+  GstOssSink *oss;
+  gint delay = 0;
+  gint ret;
+
+  oss = GST_OSSSINK (asink);
+
+#ifdef SNDCTL_DSP_GETODELAY
+  ret = ioctl (oss->fd, SNDCTL_DSP_GETODELAY, &delay);
+#else
+  ret = -1;
+#endif
+  if (ret < 0) {
+    audio_buf_info info;
+
+    ret = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &info);
+
+    delay = (ret < 0 ? 0 : (info.fragstotal * info.fragsize) - info.bytes);
+  }
+  return delay / oss->bytes_per_sample;
+}
+
+static void
+gst_oss_sink_reset (GstAudioSink * asink)
+{
+  /* There's nothing we can do here really: OSS can't handle access to the
+   * same device/fd from multiple threads and might deadlock or blow up in
+   * other ways if we try an ioctl SNDCTL_DSP_RESET or similar */
+}
diff --git a/sys/oss/gstosssink.h b/sys/oss/gstosssink.h
new file mode 100644
index 0000000..3174df1
--- /dev/null
+++ b/sys/oss/gstosssink.h
@@ -0,0 +1,62 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wtay@chello.be>
+ *
+ * gstosssink.h: 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_OSSSINK_H__
+#define __GST_OSSSINK_H__
+
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosink.h>
+
+#include "gstosshelper.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_OSSSINK            (gst_oss_sink_get_type())
+#define GST_OSSSINK(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSSSINK,GstOssSink))
+#define GST_OSSSINK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSSSINK,GstOssSinkClass))
+#define GST_IS_OSSSINK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSSSINK))
+#define GST_IS_OSSSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSSSINK))
+
+typedef struct _GstOssSink GstOssSink;
+typedef struct _GstOssSinkClass GstOssSinkClass;
+
+struct _GstOssSink {
+  GstAudioSink    sink;
+
+  gchar *device;
+  gint   fd;
+  gint   bytes_per_sample;
+
+  GstCaps *probed_caps;
+};
+
+struct _GstOssSinkClass {
+  GstAudioSinkClass parent_class;
+};
+
+GType gst_oss_sink_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_OSSSINK_H__ */
diff --git a/sys/oss/gstosssrc.c b/sys/oss/gstosssrc.c
new file mode 100644
index 0000000..4923ad2
--- /dev/null
+++ b/sys/oss/gstosssrc.c
@@ -0,0 +1,544 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2000,2005 Wim Taymans <wim@fluendo.com>
+ *
+ * gstosssrc.c: 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-osssrc
+ *
+ * This element lets you record sound using the Open Sound System (OSS).
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -v osssrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=mymusic.ogg
+ * ]| will record sound from your sound card using OSS and encode it to an
+ * Ogg/Vorbis file (this will only work if your mixer settings are right
+ * and the right inputs enabled etc.)
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#ifdef HAVE_OSS_INCLUDE_IN_SYS
+# include <sys/soundcard.h>
+#else
+# ifdef HAVE_OSS_INCLUDE_IN_ROOT
+#  include <soundcard.h>
+# else
+#  ifdef HAVE_OSS_INCLUDE_IN_MACHINE
+#   include <machine/soundcard.h>
+#  else
+#   error "What to include?"
+#  endif /* HAVE_OSS_INCLUDE_IN_MACHINE */
+# endif /* HAVE_OSS_INCLUDE_IN_ROOT */
+#endif /* HAVE_OSS_INCLUDE_IN_SYS */
+
+#include "common.h"
+#include "gstosssrc.h"
+
+#include <gst/gst-i18n-plugin.h>
+
+GST_DEBUG_CATEGORY_EXTERN (oss_debug);
+#define GST_CAT_DEFAULT oss_debug
+
+#define DEFAULT_DEVICE          "/dev/dsp"
+#define DEFAULT_DEVICE_NAME     ""
+
+enum
+{
+  PROP_0,
+  PROP_DEVICE,
+  PROP_DEVICE_NAME,
+};
+
+#define gst_oss_src_parent_class parent_class
+G_DEFINE_TYPE (GstOssSrc, gst_oss_src, GST_TYPE_AUDIO_SRC);
+
+static void gst_oss_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_oss_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+
+static void gst_oss_src_dispose (GObject * object);
+static void gst_oss_src_finalize (GstOssSrc * osssrc);
+
+static GstCaps *gst_oss_src_getcaps (GstBaseSrc * bsrc, GstCaps * filter);
+
+static gboolean gst_oss_src_open (GstAudioSrc * asrc);
+static gboolean gst_oss_src_close (GstAudioSrc * asrc);
+static gboolean gst_oss_src_prepare (GstAudioSrc * asrc,
+    GstAudioRingBufferSpec * spec);
+static gboolean gst_oss_src_unprepare (GstAudioSrc * asrc);
+static guint gst_oss_src_read (GstAudioSrc * asrc, gpointer data, guint length,
+    GstClockTime * timestamp);
+static guint gst_oss_src_delay (GstAudioSrc * asrc);
+static void gst_oss_src_reset (GstAudioSrc * asrc);
+
+#define FORMATS "{" GST_AUDIO_NE(S16)","GST_AUDIO_NE(U16)", S8, U8 }"
+
+static GstStaticPadTemplate osssrc_src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " FORMATS ", "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 1, MAX ], "
+        "channels = (int) 1; "
+        "audio/x-raw, "
+        "format = (string) " FORMATS ", "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 1, MAX ], "
+        "channels = (int) 2, " "channel-mask = (bitmask) 0x3")
+    );
+
+static void
+gst_oss_src_dispose (GObject * object)
+{
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_oss_src_class_init (GstOssSrcClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSrcClass *gstbasesrc_class;
+  GstAudioSrcClass *gstaudiosrc_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesrc_class = (GstBaseSrcClass *) klass;
+  gstaudiosrc_class = (GstAudioSrcClass *) klass;
+
+  gobject_class->dispose = gst_oss_src_dispose;
+  gobject_class->finalize = (GObjectFinalizeFunc) gst_oss_src_finalize;
+  gobject_class->get_property = gst_oss_src_get_property;
+  gobject_class->set_property = gst_oss_src_set_property;
+
+  gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_oss_src_getcaps);
+
+  gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_oss_src_open);
+  gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_oss_src_prepare);
+  gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_oss_src_unprepare);
+  gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_oss_src_close);
+  gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_oss_src_read);
+  gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_oss_src_delay);
+  gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_oss_src_reset);
+
+  g_object_class_install_property (gobject_class, PROP_DEVICE,
+      g_param_spec_string ("device", "Device",
+          "OSS device (usually /dev/dspN)", DEFAULT_DEVICE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
+      g_param_spec_string ("device-name", "Device name",
+          "Human-readable name of the sound device", DEFAULT_DEVICE_NAME,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+
+  gst_element_class_set_static_metadata (gstelement_class, "Audio Source (OSS)",
+      "Source/Audio",
+      "Capture from a sound card via OSS",
+      "Erik Walthinsen <omega@cse.ogi.edu>, " "Wim Taymans <wim@fluendo.com>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &osssrc_src_factory);
+}
+
+static void
+gst_oss_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstOssSrc *src;
+
+  src = GST_OSS_SRC (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE:
+      g_free (src->device);
+      src->device = g_value_dup_string (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_oss_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstOssSrc *src;
+
+  src = GST_OSS_SRC (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE:
+      g_value_set_string (value, src->device);
+      break;
+    case PROP_DEVICE_NAME:
+      g_value_set_string (value, src->device_name);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_oss_src_init (GstOssSrc * osssrc)
+{
+  const gchar *device;
+
+  GST_DEBUG ("initializing osssrc");
+
+  device = g_getenv ("AUDIODEV");
+  if (device == NULL)
+    device = DEFAULT_DEVICE;
+
+  osssrc->fd = -1;
+  osssrc->device = g_strdup (device);
+  osssrc->device_name = g_strdup (DEFAULT_DEVICE_NAME);
+  osssrc->probed_caps = NULL;
+}
+
+static void
+gst_oss_src_finalize (GstOssSrc * osssrc)
+{
+  g_free (osssrc->device);
+  g_free (osssrc->device_name);
+
+  G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (osssrc));
+}
+
+static GstCaps *
+gst_oss_src_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
+{
+  GstOssSrc *osssrc;
+  GstCaps *caps;
+
+  osssrc = GST_OSS_SRC (bsrc);
+
+  if (osssrc->fd == -1) {
+    GST_DEBUG_OBJECT (osssrc, "device not open, using template caps");
+    return NULL;                /* base class will get template caps for us */
+  }
+
+  if (osssrc->probed_caps) {
+    GST_LOG_OBJECT (osssrc, "Returning cached caps");
+    return gst_caps_ref (osssrc->probed_caps);
+  }
+
+  caps = gst_oss_helper_probe_caps (osssrc->fd);
+
+  if (caps) {
+    osssrc->probed_caps = gst_caps_ref (caps);
+  }
+
+  GST_INFO_OBJECT (osssrc, "returning caps %" GST_PTR_FORMAT, caps);
+
+  if (filter && caps) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    return intersection;
+  } else {
+    return caps;
+  }
+}
+
+static gint
+ilog2 (gint x)
+{
+  /* well... hacker's delight explains... */
+  x = x | (x >> 1);
+  x = x | (x >> 2);
+  x = x | (x >> 4);
+  x = x | (x >> 8);
+  x = x | (x >> 16);
+  x = x - ((x >> 1) & 0x55555555);
+  x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
+  x = (x + (x >> 4)) & 0x0f0f0f0f;
+  x = x + (x >> 8);
+  x = x + (x >> 16);
+  return (x & 0x0000003f) - 1;
+}
+
+static gint
+gst_oss_src_get_format (GstAudioRingBufferFormatType fmt, GstAudioFormat rfmt)
+{
+  gint result;
+
+  switch (fmt) {
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW:
+      result = AFMT_MU_LAW;
+      break;
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW:
+      result = AFMT_A_LAW;
+      break;
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IMA_ADPCM:
+      result = AFMT_IMA_ADPCM;
+      break;
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG:
+      result = AFMT_MPEG;
+      break;
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW:
+    {
+      switch (rfmt) {
+        case GST_AUDIO_FORMAT_U8:
+          result = AFMT_U8;
+          break;
+        case GST_AUDIO_FORMAT_S16LE:
+          result = AFMT_S16_LE;
+          break;
+        case GST_AUDIO_FORMAT_S16BE:
+          result = AFMT_S16_BE;
+          break;
+        case GST_AUDIO_FORMAT_S8:
+          result = AFMT_S8;
+          break;
+        case GST_AUDIO_FORMAT_U16LE:
+          result = AFMT_U16_LE;
+          break;
+        case GST_AUDIO_FORMAT_U16BE:
+          result = AFMT_U16_BE;
+          break;
+        default:
+          result = 0;
+          break;
+      }
+      break;
+    }
+    default:
+      result = 0;
+      break;
+  }
+  return result;
+}
+
+static gboolean
+gst_oss_src_open (GstAudioSrc * asrc)
+{
+  GstOssSrc *oss;
+  int mode;
+
+  oss = GST_OSS_SRC (asrc);
+
+  mode = O_RDONLY;
+  mode |= O_NONBLOCK;
+
+  oss->fd = open (oss->device, mode, 0);
+  if (oss->fd == -1) {
+    switch (errno) {
+      case EACCES:
+        goto no_permission;
+      default:
+        goto open_failed;
+    }
+  }
+
+  g_free (oss->device_name);
+  oss->device_name = gst_oss_helper_get_card_name ("/dev/mixer");
+
+  return TRUE;
+
+no_permission:
+  {
+    GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
+        (_("Could not open audio device for recording. "
+                "You don't have permission to open the device.")),
+        GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+open_failed:
+  {
+    GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
+        (_("Could not open audio device for recording.")),
+        ("Unable to open device %s for recording: %s",
+            oss->device, g_strerror (errno)));
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_oss_src_close (GstAudioSrc * asrc)
+{
+  GstOssSrc *oss;
+
+  oss = GST_OSS_SRC (asrc);
+
+  close (oss->fd);
+
+  gst_caps_replace (&oss->probed_caps, NULL);
+
+  return TRUE;
+}
+
+static gboolean
+gst_oss_src_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec)
+{
+  GstOssSrc *oss;
+  struct audio_buf_info info;
+  int mode;
+  int fmt, tmp;
+  guint width, rate, channels;
+
+  oss = GST_OSS_SRC (asrc);
+
+  mode = fcntl (oss->fd, F_GETFL);
+  mode &= ~O_NONBLOCK;
+  if (fcntl (oss->fd, F_SETFL, mode) == -1)
+    goto non_block;
+
+  fmt = gst_oss_src_get_format (spec->type,
+      GST_AUDIO_INFO_FORMAT (&spec->info));
+  if (fmt == 0)
+    goto wrong_format;
+
+  width = GST_AUDIO_INFO_WIDTH (&spec->info);
+  rate = GST_AUDIO_INFO_RATE (&spec->info);
+  channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
+
+  if (width != 16 && width != 8)
+    goto dodgy_width;
+
+  tmp = ilog2 (spec->segsize);
+  tmp = ((spec->segtotal & 0x7fff) << 16) | tmp;
+  GST_DEBUG_OBJECT (oss, "set segsize: %d, segtotal: %d, value: %08x",
+      spec->segsize, spec->segtotal, tmp);
+
+  SET_PARAM (oss, SNDCTL_DSP_SETFRAGMENT, tmp, "SETFRAGMENT");
+
+  SET_PARAM (oss, SNDCTL_DSP_RESET, 0, "RESET");
+
+  SET_PARAM (oss, SNDCTL_DSP_SETFMT, fmt, "SETFMT");
+  if (channels == 2)
+    SET_PARAM (oss, SNDCTL_DSP_STEREO, 1, "STEREO");
+  SET_PARAM (oss, SNDCTL_DSP_CHANNELS, channels, "CHANNELS");
+  SET_PARAM (oss, SNDCTL_DSP_SPEED, rate, "SPEED");
+
+  GET_PARAM (oss, SNDCTL_DSP_GETISPACE, &info, "GETISPACE");
+
+  spec->segsize = info.fragsize;
+  spec->segtotal = info.fragstotal;
+
+  oss->bytes_per_sample = GST_AUDIO_INFO_BPF (&spec->info);
+
+  GST_DEBUG_OBJECT (oss, "got segsize: %d, segtotal: %d, value: %08x",
+      spec->segsize, spec->segtotal, tmp);
+
+  return TRUE;
+
+non_block:
+  {
+    GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
+        ("Unable to set device %s in non blocking mode: %s",
+            oss->device, g_strerror (errno)), (NULL));
+    return FALSE;
+  }
+wrong_format:
+  {
+    GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
+        ("Unable to get format (%d, %d)", spec->type,
+            GST_AUDIO_INFO_FORMAT (&spec->info)), (NULL));
+    return FALSE;
+  }
+dodgy_width:
+  {
+    GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
+        ("Unexpected width %d", width), (NULL));
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_oss_src_unprepare (GstAudioSrc * asrc)
+{
+  /* could do a SNDCTL_DSP_RESET, but the OSS manual recommends a close/open */
+
+  if (!gst_oss_src_close (asrc))
+    goto couldnt_close;
+
+  if (!gst_oss_src_open (asrc))
+    goto couldnt_reopen;
+
+  return TRUE;
+
+couldnt_close:
+  {
+    GST_DEBUG_OBJECT (asrc, "Could not close the audio device");
+    return FALSE;
+  }
+couldnt_reopen:
+  {
+    GST_DEBUG_OBJECT (asrc, "Could not reopen the audio device");
+    return FALSE;
+  }
+}
+
+static guint
+gst_oss_src_read (GstAudioSrc * asrc, gpointer data, guint length,
+    GstClockTime * timestamp)
+{
+  return read (GST_OSS_SRC (asrc)->fd, data, length);
+}
+
+static guint
+gst_oss_src_delay (GstAudioSrc * asrc)
+{
+  GstOssSrc *oss;
+  gint delay = 0;
+  gint ret;
+
+  oss = GST_OSS_SRC (asrc);
+
+#ifdef SNDCTL_DSP_GETODELAY
+  ret = ioctl (oss->fd, SNDCTL_DSP_GETODELAY, &delay);
+#else
+  ret = -1;
+#endif
+  if (ret < 0) {
+    audio_buf_info info;
+
+    ret = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &info);
+
+    delay = (ret < 0 ? 0 : (info.fragstotal * info.fragsize) - info.bytes);
+  }
+  return delay / oss->bytes_per_sample;
+}
+
+static void
+gst_oss_src_reset (GstAudioSrc * asrc)
+{
+  /* There's nothing we can do here really: OSS can't handle access to the
+   * same device/fd from multiple threads and might deadlock or blow up in
+   * other ways if we try an ioctl SNDCTL_DSP_RESET or similar */
+}
diff --git a/sys/oss/gstosssrc.h b/sys/oss/gstosssrc.h
new file mode 100644
index 0000000..58995fb
--- /dev/null
+++ b/sys/oss/gstosssrc.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wtay@chello.be>
+ *
+ * gstosssrc.h: 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_OSS_SRC_H__
+#define __GST_OSS_SRC_H__
+
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosrc.h>
+
+#include "gstosshelper.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_OSS_SRC           (gst_oss_src_get_type())
+#define GST_OSS_SRC(obj)           (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS_SRC,GstOssSrc))
+#define GST_OSS_SRC_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS_SRC,GstOssSrcClass))
+#define GST_IS_OSS_SRC(obj)        (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS_SRC))
+#define GST_IS_OSS_SRC_CLASS(klas) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS_SRC))
+
+typedef struct _GstOssSrc GstOssSrc;
+typedef struct _GstOssSrcClass GstOssSrcClass;
+
+struct _GstOssSrc {
+  GstAudioSrc    src;
+
+  gint fd;
+  gint           bytes_per_sample;
+
+  gchar *device;
+  gchar *device_name;
+
+  GstCaps       *probed_caps;
+};
+
+struct _GstOssSrcClass {
+  GstAudioSrcClass parent_class;
+};
+
+GType gst_oss_src_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_OSS_SRC_H__ */
diff --git a/sys/oss/meson.build b/sys/oss/meson.build
new file mode 100644
index 0000000..1176e78
--- /dev/null
+++ b/sys/oss/meson.build
@@ -0,0 +1,28 @@
+oss_header_locations = [
+  # Linux and newer BSD versions
+  ['sys/soundcard.h', 'HAVE_OSS_INCLUDE_IN_SYS', 'OSS includes are in sys/'],
+  # Some old BSD versions and also newer OpenBSD versions
+  ['soundcard.h', 'HAVE_OSS_INCLUDE_IN_ROOT', 'OSS includes are in root'],
+  # Some old BSD versions
+  ['machine/soundcard.h', 'HAVE_OSS_INCLUDE_IN_MACHINE', 'OSS includes are in machine/'],
+]
+
+have_oss = false
+foreach hdr : oss_header_locations
+  if not have_oss
+    if cc.has_header(hdr[0])
+      cdata.set(hdr[1], 1, description: hdr[2])
+      have_oss = true
+    endif
+  endif
+endforeach
+
+if have_oss
+  library('gstossaudio',
+    'gstossaudio.c', 'gstosshelper.c', 'gstosssink.c', 'gstosssrc.c',
+    c_args : gst_plugins_good_args,
+    include_directories : [configinc, libsinc],
+    dependencies : [gstaudio_dep, gstbase_dep],
+    install : true,
+    install_dir : plugins_install_dir)
+endif
diff --git a/sys/oss/oss_probe.c b/sys/oss/oss_probe.c
new file mode 100644
index 0000000..af624fa
--- /dev/null
+++ b/sys/oss/oss_probe.c
@@ -0,0 +1,256 @@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <glib.h>
+
+#ifdef HAVE_OSS_INCLUDE_IN_SYS
+# include <sys/soundcard.h>
+#else
+# ifdef HAVE_OSS_INCLUDE_IN_ROOT
+#  include <soundcard.h>
+# else
+#  ifdef HAVE_OSS_INCLUDE_IN_MACHINE
+#   include <machine/soundcard.h>
+#  else
+#   error "What to include?"
+#  endif /* HAVE_OSS_INCLUDE_IN_MACHINE */
+# endif /* HAVE_OSS_INCLUDE_IN_ROOT */
+#endif /* HAVE_OSS_INCLUDE_IN_SYS */
+
+typedef struct _Probe Probe;
+struct _Probe
+{
+  int fd;
+  int format;
+  int n_channels;
+  GArray *rates;
+  int min;
+  int max;
+};
+
+typedef struct _Range Range;
+struct _Range
+{
+  int min;
+  int max;
+};
+
+static gboolean probe_check (Probe * probe);
+static int check_rate (Probe * probe, int irate);
+static void add_range (GQueue * queue, int min, int max);
+static void add_rate (GArray * array, int rate);
+static int int_compare (gconstpointer a, gconstpointer b);
+
+int
+main (int argc, char *argv[])
+{
+  int fd;
+  int i;
+  Probe *probe;
+
+  fd = open ("/dev/dsp", O_RDWR);
+  if (fd < 0) {
+    perror ("/dev/dsp");
+    exit (1);
+  }
+
+  probe = g_new0 (Probe, 1);
+  probe->fd = fd;
+  probe->format = AFMT_S16_LE;
+  probe->n_channels = 2;
+
+  probe_check (probe);
+  g_array_sort (probe->rates, int_compare);
+  for (i = 0; i < probe->rates->len; i++) {
+    g_print ("%d\n", g_array_index (probe->rates, int, i));
+  }
+
+  g_array_free (probe->rates, TRUE);
+  g_free (probe);
+
+#if 0
+  probe = g_new0 (Probe, 1);
+  probe->fd = fd;
+  probe->format = AFMT_S16_LE;
+  probe->n_channels = 1;
+
+  probe_check (probe);
+  for (i = 0; i < probe->rates->len; i++) {
+    g_print ("%d\n", g_array_index (probe->rates, int, i));
+  }
+
+  probe = g_new0 (Probe, 1);
+  probe->fd = fd;
+  probe->format = AFMT_U8;
+  probe->n_channels = 2;
+
+  probe_check (probe);
+  for (i = 0; i < probe->rates->len; i++) {
+    g_print ("%d\n", g_array_index (probe->rates, int, i));
+  }
+
+  probe = g_new0 (Probe, 1);
+  probe->fd = fd;
+  probe->format = AFMT_U8;
+  probe->n_channels = 1;
+
+  probe_check (probe);
+  for (i = 0; i < probe->rates->len; i++) {
+    g_print ("%d\n", g_array_index (probe->rates, int, i));
+  }
+#endif
+
+  return 0;
+}
+
+static gboolean
+probe_check (Probe * probe)
+{
+  Range *range;
+  GQueue *ranges;
+  int exact_rates = 0;
+  gboolean checking_exact_rates = TRUE;
+  int n_checks = 0;
+  gboolean result = TRUE;
+
+  ranges = g_queue_new ();
+
+  probe->rates = g_array_new (FALSE, FALSE, sizeof (int));
+
+  probe->min = check_rate (probe, 1000);
+  n_checks++;
+  probe->max = check_rate (probe, 100000);
+  n_checks++;
+  add_range (ranges, probe->min + 1, probe->max - 1);
+
+  while ((range = g_queue_pop_head (ranges))) {
+    int min1;
+    int max1;
+    int mid;
+    int mid_ret;
+
+    g_print ("checking [%d,%d]\n", range->min, range->max);
+
+    mid = (range->min + range->max) / 2;
+    mid_ret = check_rate (probe, mid);
+    n_checks++;
+
+    if (mid == mid_ret && checking_exact_rates) {
+      int max_exact_matches = 100;
+
+      exact_rates++;
+      if (exact_rates > max_exact_matches) {
+        g_print ("got %d exact rates, assuming all are exact\n",
+            max_exact_matches);
+        result = FALSE;
+        g_free (range);
+        break;
+      }
+    } else {
+      checking_exact_rates = FALSE;
+    }
+
+    /* Assume that the rate is arithmetically rounded to the nearest
+     * supported rate. */
+    if (mid == mid_ret) {
+      min1 = mid - 1;
+      max1 = mid + 1;
+    } else {
+      if (mid < mid_ret) {
+        min1 = mid - (mid_ret - mid);
+        max1 = mid_ret + 1;
+      } else {
+        min1 = mid_ret - 1;
+        max1 = mid + (mid - mid_ret);
+      }
+    }
+
+    add_range (ranges, range->min, min1);
+    add_range (ranges, max1, range->max);
+
+    g_free (range);
+  }
+
+  while ((range = g_queue_pop_head (ranges))) {
+    g_free (range);
+  }
+  g_queue_free (ranges);
+
+  return result;
+}
+
+static void
+add_range (GQueue * queue, int min, int max)
+{
+  g_print ("trying to add [%d,%d]\n", min, max);
+  if (min <= max) {
+    Range *range = g_new0 (Range, 1);
+
+    range->min = min;
+    range->max = max;
+
+    g_queue_push_tail (queue, range);
+    //g_queue_push_head (queue, range);
+  }
+}
+
+static int
+check_rate (Probe * probe, int irate)
+{
+  int rate;
+  int format;
+  int n_channels;
+
+  rate = irate;
+  format = probe->format;
+  n_channels = probe->n_channels;
+
+  ioctl (probe->fd, SNDCTL_DSP_SETFMT, &format);
+  ioctl (probe->fd, SNDCTL_DSP_CHANNELS, &n_channels);
+  ioctl (probe->fd, SNDCTL_DSP_SPEED, &rate);
+
+  g_print ("rate %d -> %d\n", irate, rate);
+
+  if (rate == irate - 1 || rate == irate + 1) {
+    rate = irate;
+  }
+  add_rate (probe->rates, rate);
+  return rate;
+}
+
+static void
+add_rate (GArray * array, int rate)
+{
+  int i;
+  int val;
+
+  for (i = 0; i < array->len; i++) {
+    val = g_array_index (array, int, i);
+
+    if (val == rate)
+      return;
+  }
+  g_print ("supported rate: %d\n", rate);
+  g_array_append_val (array, rate);
+}
+
+static int
+int_compare (gconstpointer a, gconstpointer b)
+{
+  const int *va = (const int *) a;
+  const int *vb = (const int *) b;
+
+  if (*va < *vb)
+    return -1;
+  if (*va > *vb)
+    return 1;
+  return 0;
+}
diff --git a/sys/oss4/Makefile.am b/sys/oss4/Makefile.am
new file mode 100644
index 0000000..a8f058a
--- /dev/null
+++ b/sys/oss4/Makefile.am
@@ -0,0 +1,22 @@
+plugin_LTLIBRARIES = libgstoss4.la
+
+libgstoss4_la_SOURCES = \
+	oss4-audio.c          \
+	oss4-property-probe.c \
+	oss4-sink.c           \
+	oss4-source.c
+
+libgstoss4_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+libgstoss4_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) \
+	-lgstaudio-$(GST_API_VERSION) \
+	$(GST_LIBS)
+libgstoss4_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) 
+
+noinst_HEADERS = \
+	oss4-audio.h          \
+	oss4-property-probe.h \
+	oss4-sink.h           \
+	oss4-soundcard.h      \
+	oss4-source.h
+
diff --git a/sys/oss4/meson.build b/sys/oss4/meson.build
new file mode 100644
index 0000000..491266e
--- /dev/null
+++ b/sys/oss4/meson.build
@@ -0,0 +1,23 @@
+have_oss4 = true
+message('Checking headers needed for Open Sound System 4 plugin...')
+foreach hdr : ['fcntl.h', 'sys/ioctl.h', 'sys/stat.h', 'sys/types.h']
+  if have_oss4
+    if not cc.has_header(hdr)
+      have_oss4 = false
+    endif
+  endif
+endforeach
+
+if have_oss4
+  message('Required headers found, building Open Sound System 4 plugin.')
+
+  library('gstoss4',
+    'oss4-audio.c', 'oss4-property-probe.c', 'oss4-sink.c', 'oss4-source.c',
+    c_args : gst_plugins_good_args,
+    include_directories : [configinc, libsinc],
+    dependencies : [gstaudio_dep, gstbase_dep],
+    install : true,
+    install_dir : plugins_install_dir)
+else
+  message('Not building Open Sound System 4 plugin, required headers not found.')
+endif
diff --git a/sys/oss4/oss4-audio.c b/sys/oss4/oss4-audio.c
new file mode 100644
index 0000000..0896081
--- /dev/null
+++ b/sys/oss4/oss4-audio.c
@@ -0,0 +1,781 @@
+/* GStreamer OSS4 audio plugin
+ * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gst/gst-i18n-plugin.h"
+#include <gst/audio/audio.h>
+
+#include "oss4-audio.h"
+#include "oss4-property-probe.h"
+#include "oss4-sink.h"
+#include "oss4-source.h"
+#include "oss4-soundcard.h"
+
+GST_DEBUG_CATEGORY (oss4mixer_debug);
+GST_DEBUG_CATEGORY (oss4sink_debug);
+GST_DEBUG_CATEGORY (oss4src_debug);
+GST_DEBUG_CATEGORY (oss4_debug);
+
+#define GST_CAT_DEFAULT oss4_debug
+
+typedef struct
+{
+  const GstAudioRingBufferFormatType gst_rbfmt;
+  const GstAudioFormat gst_rfmt;
+  const gint oss_fmt;
+  const gchar name[16];
+} GstOss4AudioFormat;
+
+/* *INDENT-OFF* */
+static const GstOss4AudioFormat fmt_map[] = {
+  /* note: keep sorted by preference, prefered formats first */
+  {
+  GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW, 0,
+      AFMT_MU_LAW, "audio/x-mulaw"}, {
+  GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW, 0,
+      AFMT_A_LAW, "audio/x-alaw"}, {
+  GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S32LE,
+      AFMT_S32_LE, "audio/x-raw"}, {
+  GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S32BE,
+      AFMT_S32_BE, "audio/x-raw"}, {
+  GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S24_32LE,
+      AFMT_S24_LE, "audio/x-raw"}, {
+  GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S24_32BE,
+      AFMT_S24_BE, "audio/x-raw"}, {
+  GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S24LE,
+      AFMT_S24_PACKED, "audio/x-raw"}, {
+  GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S16LE,
+      AFMT_S16_LE, "audio/x-raw"}, {
+  GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S16BE,
+      AFMT_S16_BE, "audio/x-raw"}, {
+  GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_U16LE,
+      AFMT_U16_LE, "audio/x-raw"}, {
+  GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_U16BE,
+      AFMT_U16_BE, "audio/x-raw"}, {
+  GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S8,
+      AFMT_S8, "audio/x-raw"}, {
+  GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_U8,
+      AFMT_U8, "audio/x-raw"}
+};
+/* *INDENT-ON* */
+
+/* formats we assume the OSS4 layer can always handle and convert internally */
+#define CONVERTIBLE_FORMATS (   \
+    AFMT_MU_LAW | AFMT_A_LAW |  \
+    AFMT_S32_LE | AFMT_S32_BE | \
+    AFMT_S24_LE | AFMT_S24_BE | \
+    AFMT_S24_PACKED |           \
+    AFMT_S16_LE | AFMT_S16_BE | \
+    AFMT_U16_LE | AFMT_U16_BE | \
+    AFMT_S8 | AFMT_U8 )
+
+static void
+gst_oss4_append_format_to_caps (const GstOss4AudioFormat * fmt, GstCaps * caps)
+{
+  GstStructure *s;
+
+  s = gst_structure_new_empty (fmt->name);
+  if (fmt->gst_rbfmt == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) {
+    gst_structure_set (s, "format", G_TYPE_STRING,
+        gst_audio_format_to_string (fmt->gst_rfmt),
+        "layout", G_TYPE_STRING, "interleaved", NULL);
+  }
+  gst_caps_append_structure (caps, s);
+}
+
+static gint
+gst_oss4_audio_get_oss_format (GstAudioRingBufferFormatType fmt,
+    GstAudioFormat rfmt)
+{
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (fmt_map); ++i) {
+    if (fmt_map[i].gst_rbfmt == fmt && fmt_map[i].gst_rfmt == rfmt)
+      return fmt_map[i].oss_fmt;
+  }
+  return 0;
+}
+
+/* These are pretty random */
+#define GST_OSS4_MIN_SAMPLE_RATE 1
+#define GST_OSS4_MAX_SAMPLE_RATE 192000
+
+static gboolean
+gst_oss4_audio_detect_rates (GstObject * obj, oss_audioinfo * ai,
+    GstCaps * caps)
+{
+  GValue val = { 0, };
+  int minrate, maxrate, i;
+
+  minrate = ai->min_rate;
+  maxrate = ai->max_rate;
+
+  /* sanity check */
+  if (minrate > maxrate) {
+    GST_WARNING_OBJECT (obj, "min_rate %d > max_rate %d (buggy driver?)",
+        minrate, maxrate);
+    maxrate = ai->min_rate;     /* swap */
+    minrate = ai->max_rate;
+  }
+
+  /* limit to something sensible */
+  if (minrate < GST_OSS4_MIN_SAMPLE_RATE)
+    minrate = GST_OSS4_MIN_SAMPLE_RATE;
+  if (maxrate > GST_OSS4_MAX_SAMPLE_RATE)
+    maxrate = GST_OSS4_MAX_SAMPLE_RATE;
+
+  if (maxrate < GST_OSS4_MIN_SAMPLE_RATE) {
+    GST_WARNING_OBJECT (obj, "max_rate < %d, which makes no sense",
+        GST_OSS4_MIN_SAMPLE_RATE);
+    return FALSE;
+  }
+
+  GST_LOG_OBJECT (obj, "min_rate %d, max_rate %d (originally: %d, %d)",
+      minrate, maxrate, ai->min_rate, ai->max_rate);
+
+  if ((ai->caps & PCM_CAP_FREERATE)) {
+    GST_LOG_OBJECT (obj, "device supports any sample rate between min and max");
+    if (minrate == maxrate) {
+      g_value_init (&val, G_TYPE_INT);
+      g_value_set_int (&val, maxrate);
+    } else {
+      g_value_init (&val, GST_TYPE_INT_RANGE);
+      gst_value_set_int_range (&val, minrate, maxrate);
+    }
+  } else {
+    GST_LOG_OBJECT (obj, "%d sample rates:", ai->nrates);
+    g_value_init (&val, GST_TYPE_LIST);
+    for (i = 0; i < ai->nrates; ++i) {
+      GST_LOG_OBJECT (obj, " rate: %d", ai->rates[i]);
+
+      if (ai->rates[i] >= minrate && ai->rates[i] <= maxrate) {
+        GValue rate_val = { 0, };
+
+        g_value_init (&rate_val, G_TYPE_INT);
+        g_value_set_int (&rate_val, ai->rates[i]);
+        gst_value_list_append_value (&val, &rate_val);
+        g_value_unset (&rate_val);
+      }
+    }
+
+    if (gst_value_list_get_size (&val) == 0) {
+      g_value_unset (&val);
+      return FALSE;
+    }
+  }
+
+  for (i = 0; i < gst_caps_get_size (caps); ++i) {
+    GstStructure *s;
+
+    s = gst_caps_get_structure (caps, i);
+    gst_structure_set_value (s, "rate", &val);
+  }
+
+  g_value_unset (&val);
+
+  return TRUE;
+}
+
+static void
+gst_oss4_audio_get_channel_layout (GstObject * obj, guint64 layout,
+    guint num_channels, GstAudioChannelPosition * ch_layout)
+{
+  const GstAudioChannelPosition pos_map[16] = {
+    GST_AUDIO_CHANNEL_POSITION_NONE,    /* 0 = dunno          */
+    GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,      /* 1 = left           */
+    GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,     /* 2 = right          */
+    GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,    /* 3 = center         */
+    GST_AUDIO_CHANNEL_POSITION_LFE1,    /* 4 = lfe            */
+    GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,       /* 5 = left surround  */
+    GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,      /* 6 = right surround */
+    GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,       /* 7 = left rear      */
+    GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,      /* 8 = right rear     */
+    GST_AUDIO_CHANNEL_POSITION_NONE,
+    GST_AUDIO_CHANNEL_POSITION_NONE,
+    GST_AUDIO_CHANNEL_POSITION_NONE,
+    GST_AUDIO_CHANNEL_POSITION_NONE,
+    GST_AUDIO_CHANNEL_POSITION_NONE,
+    GST_AUDIO_CHANNEL_POSITION_NONE,
+    GST_AUDIO_CHANNEL_POSITION_NONE
+  };
+  guint speaker_pos;            /* speaker position as defined by OSS */
+  guint i;
+
+  for (i = 0; i < num_channels; ++i) {
+    /* layout contains up to 16 speaker positions, with each taking up 4 bits */
+    speaker_pos = (guint) ((layout >> (i * 4)) & 0x0f);
+
+    /* if it's a channel position that's unknown to us, set all to NONE and
+     * bail out */
+    if (G_UNLIKELY (pos_map[speaker_pos] == GST_AUDIO_CHANNEL_POSITION_NONE))
+      goto no_layout;
+
+    ch_layout[i] = pos_map[speaker_pos];
+  }
+
+  return;
+
+no_layout:
+  {
+    /* only warn if it's really unknown, position 0 is ok and represents NONE
+     * (in which case we also just set all others to NONE ignoring the other
+     * positions in the OSS-given layout, because that's what we currently
+     * require in GStreamer) */
+    if (speaker_pos != 0) {
+      GST_WARNING_OBJECT (obj, "unknown OSS channel position %x", ch_layout[i]);
+    }
+    for (i = 0; i < num_channels; ++i) {
+      ch_layout[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
+    }
+    return;
+  }
+}
+
+static void
+gst_oss4_audio_set_ringbuffer_channel_layout (GstObject * obj, gint fd,
+    GstAudioRingBufferSpec * spec)
+{
+  guint num_channels;
+  guint64 layout = 0;
+  GstAudioRingBuffer *rb;
+  GstAudioChannelPosition ch_layout[8] = { 0, };
+
+  num_channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
+  if (num_channels < 3 || num_channels > 8)
+    return;
+
+  if (spec->type != GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW)
+    return;
+
+  if (GST_IS_OSS4_SINK (obj)) {
+    rb = GST_AUDIO_BASE_SINK (obj)->ringbuffer;
+  } else if (GST_IS_OSS4_SOURCE (obj)) {
+    rb = GST_AUDIO_BASE_SRC (obj)->ringbuffer;
+  } else
+    g_return_if_reached ();
+
+  /* -1 = get info for currently open device (fd). This will fail with
+   * OSS build <= 1013 because of a bug in OSS */
+  if (ioctl (fd, SNDCTL_DSP_GET_CHNORDER, &layout) == -1) {
+    GST_WARNING_OBJECT (obj, "couldn't query channel layout, assuming default");
+    layout = CHNORDER_NORMAL;
+  }
+  GST_DEBUG_OBJECT (obj, "channel layout: %08" G_GINT64_MODIFIER "x", layout);
+
+
+  gst_oss4_audio_get_channel_layout (obj, layout, num_channels, ch_layout);
+  gst_audio_ring_buffer_set_channel_positions (rb, ch_layout);
+
+  return;
+}
+
+static void
+gst_oss4_audio_add_channel_layout (GstObject * obj, guint64 layout,
+    guint num_channels, GstStructure * s)
+{
+  GstAudioChannelPosition ch_layout[8] = { 0, };
+  guint64 mask;
+
+  g_return_if_fail (num_channels <= G_N_ELEMENTS (ch_layout));
+
+  gst_oss4_audio_get_channel_layout (obj, layout, num_channels, ch_layout);
+  if (gst_audio_channel_positions_to_mask (ch_layout, num_channels, FALSE,
+          &mask))
+    gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK, mask, NULL);
+
+  return;
+}
+
+/* arbitrary max. limit */
+#define GST_OSS4_MIN_CHANNELS 1
+#define GST_OSS4_MAX_CHANNELS 4096
+
+/* takes ownership of the input caps */
+static GstCaps *
+gst_oss4_audio_detect_channels (GstObject * obj, int fd, oss_audioinfo * ai,
+    GstCaps * in_caps)
+{
+  const gchar *forced_layout;
+  GstStructure *s = NULL;
+  guint64 layout = 0;
+  GstCaps *chan_caps = NULL;
+  GstCaps *out_caps = NULL;
+  int minchans, maxchans;
+  int c, i, j;
+
+  /* GST_OSS4_CHANNEL_LAYOUT environment variable: may be used to force a
+   * particular channel layout (if it contains an odd number of channel
+   * positions it will also make us advertise a channel layout for that
+   * channel count, even if we'd usually skip it; this is especially useful
+   * for folks with 2.1 speakers, I guess) */
+  forced_layout = g_getenv ("GST_OSS4_CHANNEL_LAYOUT");
+
+  minchans = ai->min_channels;
+  maxchans = ai->max_channels;
+
+  /* sanity check */
+  if (minchans > maxchans) {
+    GST_WARNING_OBJECT (obj, "min_chans %d > max_chans %d (buggy driver?)",
+        minchans, maxchans);
+    maxchans = ai->min_channels;        /* swap */
+    minchans = ai->max_channels;
+  }
+
+  /* limit to something sensible */
+  if (minchans < GST_OSS4_MIN_CHANNELS)
+    minchans = GST_OSS4_MIN_CHANNELS;
+  if (maxchans > GST_OSS4_MAX_CHANNELS)
+    maxchans = GST_OSS4_MAX_CHANNELS;
+
+  if (maxchans < GST_OSS4_MIN_CHANNELS) {
+    GST_WARNING_OBJECT (obj, "max_chans < %d, which makes no sense",
+        GST_OSS4_MIN_CHANNELS);
+    gst_caps_unref (in_caps);
+    return NULL;
+  }
+
+  GST_LOG_OBJECT (obj, "min_channels %d, max_channels %d (originally: %d, %d)",
+      minchans, maxchans, ai->min_channels, ai->max_channels);
+
+  chan_caps = gst_caps_new_empty ();
+
+  /* first do the simple cases: mono + stereo (channel layout implied) */
+  if (minchans == 1 && maxchans == 1)
+    s = gst_structure_new ("x", "channels", G_TYPE_INT, 1, NULL);
+  else if (minchans == 2 && maxchans >= 2)
+    s = gst_structure_new ("x", "channels", G_TYPE_INT, 2, NULL);
+  else if (minchans == 1 && maxchans >= 2)
+    s = gst_structure_new ("x", "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
+  gst_caps_append_structure (chan_caps, s);
+  s = NULL;
+
+  /* TODO: we assume all drivers use a left/right layout for stereo here */
+  if (maxchans <= 2)
+    goto done;
+
+  if (ioctl (fd, SNDCTL_DSP_GET_CHNORDER, &layout) == -1) {
+    GST_WARNING_OBJECT (obj, "couldn't query channel layout, assuming default");
+    layout = CHNORDER_NORMAL;
+  }
+  GST_DEBUG_OBJECT (obj, "channel layout: %08" G_GINT64_MODIFIER "x", layout);
+
+  /* e.g. forced 2.1 layout would be GST_OSS4_CHANNEL_LAYOUT=421 */
+  if (forced_layout != NULL && *forced_layout != '\0') {
+    guint layout_len;
+
+    layout_len = strlen (forced_layout);
+    if (layout_len >= minchans && layout_len <= maxchans) {
+      layout = g_ascii_strtoull (forced_layout, NULL, 16);
+      maxchans = layout_len;
+      GST_DEBUG_OBJECT (obj, "forced channel layout: %08" G_GINT64_MODIFIER "x"
+          " ('%s'), maxchans now %d", layout, forced_layout, maxchans);
+    } else {
+      GST_WARNING_OBJECT (obj, "ignoring forced channel layout: layout has %d "
+          "channel positions but maxchans is %d", layout_len, maxchans);
+    }
+  }
+
+  /* need to advertise channel layouts for anything >2 and <=8 channels */
+  for (c = MAX (3, minchans); c <= MIN (maxchans, 8); c++) {
+    /* "The min_channels and max_channels fields define the limits for the
+     * number of channels. However some devices don't support all channels
+     * within this range. It's possible that the odd values (3, 5, 7, 9, etc).
+     * are not supported. There is currently no way to check for this other
+     * than checking if SNDCTL_DSP_CHANNELS accepts the requested value.
+     * Another approach is trying to avoid using odd number of channels."
+     *
+     * So, we don't know for sure if these odd values are supported:
+     */
+    if ((c == 3 || c == 5 || c == 7) && (c != maxchans)) {
+      GST_LOG_OBJECT (obj, "not adding layout with %d channels", c);
+      continue;
+    }
+
+    s = gst_structure_new ("x", "channels", G_TYPE_INT, c, NULL);
+    gst_oss4_audio_add_channel_layout (obj, layout, c, s);
+    GST_LOG_OBJECT (obj, "c=%u, appending struct %" GST_PTR_FORMAT, c, s);
+    gst_caps_append_structure (chan_caps, s);
+    s = NULL;
+  }
+
+  if (maxchans <= 8)
+    goto done;
+
+  /* for everything >8 channels, CHANNEL_POSITION_NONE is implied. */
+  if (minchans == maxchans || maxchans == 9) {
+    s = gst_structure_new ("x", "channels", G_TYPE_INT, maxchans, NULL);
+  } else {
+    s = gst_structure_new ("x", "channels", GST_TYPE_INT_RANGE,
+        MAX (9, minchans), maxchans, NULL);
+  }
+  gst_caps_append_structure (chan_caps, s);
+  s = NULL;
+
+done:
+
+  GST_LOG_OBJECT (obj, "channel structures: %" GST_PTR_FORMAT, chan_caps);
+
+  out_caps = gst_caps_new_empty ();
+
+  /* combine each structure in the input caps with each channel caps struct */
+  for (i = 0; i < gst_caps_get_size (in_caps); ++i) {
+    const GstStructure *in_s;
+
+    in_s = gst_caps_get_structure (in_caps, i);
+
+    for (j = 0; j < gst_caps_get_size (chan_caps); ++j) {
+      const GstStructure *chan_s;
+      const GValue *val;
+
+      s = gst_structure_copy (in_s);
+      chan_s = gst_caps_get_structure (chan_caps, j);
+      if ((val = gst_structure_get_value (chan_s, "channels")))
+        gst_structure_set_value (s, "channels", val);
+      if ((val = gst_structure_get_value (chan_s, "channel-mask")))
+        gst_structure_set_value (s, "channel-mask", val);
+
+      gst_caps_append_structure (out_caps, s);
+      s = NULL;
+    }
+  }
+
+  gst_caps_unref (in_caps);
+  gst_caps_unref (chan_caps);
+  return out_caps;
+}
+
+GstCaps *
+gst_oss4_audio_probe_caps (GstObject * obj, int fd)
+{
+  oss_audioinfo ai = { 0, };
+  gboolean output;
+  GstCaps *caps;
+  int nonnative_formats = 0;
+  int formats, i;
+
+  output = GST_IS_OSS4_SINK (obj);
+
+  /* -1 = get info for currently open device (fd). This will fail with
+   * OSS build <= 1013 because of a bug in OSS */
+  ai.dev = -1;
+  if (ioctl (fd, SNDCTL_ENGINEINFO, &ai) == -1)
+    goto engineinfo_failed;
+
+  formats = (output) ? ai.oformats : ai.iformats;
+
+  GST_LOG_OBJECT (obj, "%s formats : 0x%08x", (output) ? "out" : "in", formats);
+
+  caps = gst_caps_new_empty ();
+
+  /* first list all the formats natively supported */
+  for (i = 0; i < G_N_ELEMENTS (fmt_map); ++i) {
+    if ((formats & fmt_map[i].oss_fmt)) {
+      gst_oss4_append_format_to_caps (&fmt_map[i], caps);
+    } else if ((fmt_map[i].oss_fmt & CONVERTIBLE_FORMATS)) {
+      nonnative_formats |= fmt_map[i].oss_fmt;
+    }
+  }
+
+  GST_LOG_OBJECT (obj, "adding non-native %s formats : 0x%08x",
+      (output) ? "out" : "in", nonnative_formats);
+
+  /* now append non-native formats for which conversion would be needed */
+  for (i = 0; i < G_N_ELEMENTS (fmt_map); ++i) {
+    if ((nonnative_formats & fmt_map[i].oss_fmt)) {
+      gst_oss4_append_format_to_caps (&fmt_map[i], caps);
+    }
+  }
+
+  caps = gst_caps_simplify (caps);
+  GST_LOG_OBJECT (obj, "formats: %" GST_PTR_FORMAT, caps);
+
+  if (!gst_oss4_audio_detect_rates (obj, &ai, caps))
+    goto detect_rates_failed;
+
+  caps = gst_oss4_audio_detect_channels (obj, fd, &ai, caps);
+  if (caps == NULL)
+    goto detect_channels_failed;
+
+  GST_LOG_OBJECT (obj, "probed caps: %" GST_PTR_FORMAT, caps);
+
+  return caps;
+
+/* ERRORS */
+engineinfo_failed:
+  {
+    GST_WARNING ("ENGINEINFO supported formats probe failed: %s",
+        g_strerror (errno));
+    return NULL;
+  }
+detect_rates_failed:
+  {
+    GST_WARNING_OBJECT (obj, "failed to detect supported sample rates");
+    gst_caps_unref (caps);
+    return NULL;
+  }
+detect_channels_failed:
+  {
+    GST_WARNING_OBJECT (obj, "failed to detect supported channels");
+    gst_caps_unref (caps);
+    return NULL;
+  }
+}
+
+GstCaps *
+gst_oss4_audio_get_template_caps (void)
+{
+  GstCaps *caps;
+  gint i;
+
+  caps = gst_caps_new_empty ();
+
+  for (i = 0; i < G_N_ELEMENTS (fmt_map); ++i) {
+    gst_oss4_append_format_to_caps (&fmt_map[i], caps);
+  }
+
+  caps = gst_caps_simplify (caps);
+
+  for (i = 0; i < gst_caps_get_size (caps); ++i) {
+    GstStructure *s;
+
+    s = gst_caps_get_structure (caps, i);
+    gst_structure_set (s, "rate", GST_TYPE_INT_RANGE, GST_OSS4_MIN_SAMPLE_RATE,
+        GST_OSS4_MAX_SAMPLE_RATE, "channels", GST_TYPE_INT_RANGE,
+        GST_OSS4_MIN_CHANNELS, GST_OSS4_MAX_CHANNELS, NULL);
+  }
+
+  return caps;
+}
+
+/* called by gst_oss4_sink_prepare() and gst_oss4_source_prepare() */
+gboolean
+gst_oss4_audio_set_format (GstObject * obj, int fd,
+    GstAudioRingBufferSpec * spec)
+{
+  struct audio_buf_info info = { 0, };
+  int ofmt, fmt, chans, rate, width;
+
+  fmt = gst_oss4_audio_get_oss_format (spec->type,
+      GST_AUDIO_INFO_FORMAT (&spec->info));
+
+  if (fmt == 0)
+    goto wrong_format;
+
+  ofmt = fmt;
+  chans = GST_AUDIO_INFO_CHANNELS (&spec->info);
+  rate = GST_AUDIO_INFO_RATE (&spec->info);
+  width = GST_AUDIO_INFO_WIDTH (&spec->info);
+
+  if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW &&
+      width != 32 && width != 24 && width != 16 && width != 8) {
+    goto dodgy_width;
+  }
+
+  /* format */
+  GST_LOG_OBJECT (obj, "setting format: %d", fmt);
+  if (ioctl (fd, SNDCTL_DSP_SETFMT, &fmt) == -1)
+    goto set_format_failed;
+
+  /* channels */
+  GST_LOG_OBJECT (obj, "setting channels: %d", chans);
+  if (ioctl (fd, SNDCTL_DSP_CHANNELS, &chans) == -1)
+    goto set_channels_failed;
+
+  /* rate */
+  GST_LOG_OBJECT (obj, "setting rate: %d", rate);
+  if (ioctl (fd, SNDCTL_DSP_SPEED, &rate) == -1)
+    goto set_rate_failed;
+
+  GST_DEBUG_OBJECT (obj, "effective format   : %d", fmt);
+  GST_DEBUG_OBJECT (obj, "effective channels : %d", chans);
+  GST_DEBUG_OBJECT (obj, "effective rate     : %d", rate);
+
+  /* make sure format, channels, and rate are the ones we requested */
+  if (fmt != ofmt || chans != GST_AUDIO_INFO_CHANNELS (&spec->info) ||
+      rate != GST_AUDIO_INFO_RATE (&spec->info)) {
+    /* This shouldn't happen, but hey */
+    goto format_not_what_was_requested;
+  }
+
+  if (GST_IS_OSS4_SOURCE (obj)) {
+    if (ioctl (fd, SNDCTL_DSP_GETISPACE, &info) == -1)
+      goto get_ispace_failed;
+  } else {
+    if (ioctl (fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
+      goto get_ospace_failed;
+  }
+
+  spec->segsize = info.fragsize;
+
+  /* we add some extra fragments -- this helps us account for delays due to
+   * conversion buffer, streams queueing, etc.  It is important that these
+   * be taken into account because otherwise the delay counter can wind up
+   * being too large, and the buffer will wrap.  */
+  spec->segtotal = info.fragstotal + 4;
+
+  GST_DEBUG_OBJECT (obj, "got segsize: %d, segtotal: %d, value: %08x",
+      spec->segsize, spec->segtotal, info.fragsize);
+
+  gst_oss4_audio_set_ringbuffer_channel_layout (obj, fd, spec);
+
+  return TRUE;
+
+/* ERRORS */
+wrong_format:
+  {
+    GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
+        ("Unable to get format (%d, %d)", spec->type,
+            GST_AUDIO_INFO_FORMAT (&spec->info)));
+    return FALSE;
+  }
+dodgy_width:
+  {
+    GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
+        ("unexpected width %d", width));
+    return FALSE;
+  }
+set_format_failed:
+  {
+    GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
+        ("DSP_SETFMT(%d) failed: %s", fmt, g_strerror (errno)));
+    return FALSE;
+  }
+set_channels_failed:
+  {
+    GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
+        ("DSP_CHANNELS(%d) failed: %s", chans, g_strerror (errno)));
+    return FALSE;
+  }
+set_rate_failed:
+  {
+    GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
+        ("DSP_SPEED(%d) failed: %s", rate, g_strerror (errno)));
+    return FALSE;
+  }
+get_ospace_failed:
+  {
+    GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
+        ("DSP_GETOSPACE failed: %s", g_strerror (errno)));
+    return FALSE;
+  }
+get_ispace_failed:
+  {
+    GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
+        ("DSP_GETISPACE failed: %s", g_strerror (errno)));
+    return FALSE;
+  }
+format_not_what_was_requested:
+  {
+    GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
+        ("Format actually configured wasn't the one we requested. This is "
+            "probably either a bug in the driver or in the format probing code."));
+    return FALSE;
+  }
+}
+
+int
+gst_oss4_audio_get_version (GstObject * obj, int fd)
+{
+  gint ver = 0;
+
+  /* we use the old ioctl here on purpose instead of SNDCTL_SYSINFO */
+  if (ioctl (fd, OSS_GETVERSION, &ver) < 0) {
+    GST_LOG_OBJECT (obj, "OSS_GETVERSION failed: %s", g_strerror (errno));
+    return -1;
+  }
+  GST_LOG_OBJECT (obj, "OSS version: 0x%08x", ver);
+  return ver;
+}
+
+gboolean
+gst_oss4_audio_check_version (GstObject * obj, int fd)
+{
+  return (gst_oss4_audio_get_version (obj, fd) >= GST_MIN_OSS4_VERSION);
+}
+
+gchar *
+gst_oss4_audio_find_device (GstObject * oss)
+{
+  GValueArray *arr;
+  gchar *ret = NULL;
+
+  arr = gst_oss4_property_probe_get_values (GST_OBJECT (oss), "device");
+
+  if (arr != NULL) {
+    if (arr->n_values > 0) {
+      const GValue *val;
+
+      val = g_value_array_get_nth (arr, 0);
+      ret = g_value_dup_string (val);
+    }
+    g_value_array_free (arr);
+  }
+
+  GST_LOG_OBJECT (oss, "first device found: %s", GST_STR_NULL (ret));
+
+  return ret;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  gint rank;
+
+  GST_DEBUG_CATEGORY_INIT (oss4sink_debug, "oss4sink", 0, "OSS4 audio sink");
+  GST_DEBUG_CATEGORY_INIT (oss4src_debug, "oss4src", 0, "OSS4 audio src");
+  GST_DEBUG_CATEGORY_INIT (oss4mixer_debug, "oss4mixer", 0, "OSS4 mixer");
+  GST_DEBUG_CATEGORY_INIT (oss4_debug, "oss4", 0, "OSS4 plugin");
+
+#ifdef ENABLE_NLS
+  GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
+      LOCALEDIR);
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+
+  /* we want a higher rank than the legacy OSS elements have now */
+  rank = GST_RANK_SECONDARY + 1;
+
+  if (!gst_element_register (plugin, "oss4sink", rank, GST_TYPE_OSS4_SINK) ||
+      !gst_element_register (plugin, "oss4src", rank, GST_TYPE_OSS4_SOURCE)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    oss4,
+    "Open Sound System (OSS) version 4 support for GStreamer",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/sys/oss4/oss4-audio.h b/sys/oss4/oss4-audio.h
new file mode 100644
index 0000000..54128c0
--- /dev/null
+++ b/sys/oss4/oss4-audio.h
@@ -0,0 +1,43 @@
+/* GStreamer OSS4 audio plugin
+ * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GST_OSS4_AUDIO_H
+#define GST_OSS4_AUDIO_H
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+
+/* This is the minimum version we require */
+#define GST_MIN_OSS4_VERSION  0x040003
+
+int       gst_oss4_audio_get_version (GstObject * obj, int fd);
+
+gboolean  gst_oss4_audio_check_version (GstObject * obj, int fd);
+
+GstCaps * gst_oss4_audio_probe_caps  (GstObject * obj, int fd);
+
+gboolean  gst_oss4_audio_set_format  (GstObject * obj, int fd, GstAudioRingBufferSpec * spec);
+
+GstCaps * gst_oss4_audio_get_template_caps (void);
+
+gchar   * gst_oss4_audio_find_device (GstObject * oss);
+
+#endif /* GST_OSS4_AUDIO_H */
+
+
diff --git a/sys/oss4/oss4-property-probe.c b/sys/oss4/oss4-property-probe.c
new file mode 100644
index 0000000..4644ea1
--- /dev/null
+++ b/sys/oss4/oss4-property-probe.c
@@ -0,0 +1,345 @@
+/* GStreamer OSS4 audio property probe interface implementation
+ * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gst/gst.h>
+
+
+#define NO_LEGACY_MIXER
+#include "oss4-audio.h"
+#include "oss4-sink.h"
+#include "oss4-source.h"
+#include "oss4-soundcard.h"
+#include "oss4-property-probe.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#if 0
+
+GST_DEBUG_CATEGORY_EXTERN (oss4_debug);
+#define GST_CAT_DEFAULT oss4_debug
+
+static const GList *
+gst_oss4_property_probe_get_properties (GstPropertyProbe * probe)
+{
+  GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
+  GList *list;
+
+  GST_OBJECT_LOCK (GST_OBJECT (probe));
+
+  /* we create a new list and store it in the instance struct, since apparently
+   * we forgot to update the API for 0.10 (and why don't we mark probable
+   * properties with a flag instead anyway?). A bit hackish, but what can you
+   * do (can't really use a static variable since the pspec will be different
+   * for src and sink class); this isn't particularly pretty, but the best
+   * we can do given that we can't create a common base class (we could do
+   * fancy things with the interface, or use g_object_set_data instead, but
+   * it's not really going to make it much better) */
+  if (GST_IS_AUDIO_SINK_CLASS (klass)) {
+    list = GST_OSS4_SINK (probe)->property_probe_list;
+  } else if (GST_IS_AUDIO_SRC_CLASS (klass)) {
+    list = GST_OSS4_SOURCE (probe)->property_probe_list;
+  } else if (GST_IS_OSS4_MIXER_CLASS (klass)) {
+    list = GST_OSS4_MIXER (probe)->property_probe_list;
+  } else {
+    GST_OBJECT_UNLOCK (GST_OBJECT (probe));
+    g_return_val_if_reached (NULL);
+  }
+
+  if (list == NULL) {
+    GParamSpec *pspec;
+
+    pspec = g_object_class_find_property (klass, "device");
+    list = g_list_prepend (NULL, pspec);
+
+    if (GST_IS_AUDIO_SINK_CLASS (klass)) {
+      GST_OSS4_SINK (probe)->property_probe_list = list;
+    } else if (GST_IS_AUDIO_SRC_CLASS (klass)) {
+      GST_OSS4_SOURCE (probe)->property_probe_list = list;
+    } else if (GST_IS_OSS4_MIXER_CLASS (klass)) {
+      GST_OSS4_MIXER (probe)->property_probe_list = list;
+    }
+  }
+
+  GST_OBJECT_UNLOCK (GST_OBJECT (probe));
+
+  return list;
+}
+
+static void
+gst_oss4_property_probe_probe_property (GstPropertyProbe * probe,
+    guint prop_id, const GParamSpec * pspec)
+{
+  if (!g_str_equal (pspec->name, "device")) {
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
+  }
+}
+
+static gboolean
+gst_oss4_property_probe_needs_probe (GstPropertyProbe * probe,
+    guint prop_id, const GParamSpec * pspec)
+{
+  /* don't cache probed data */
+  return TRUE;
+}
+
+#endif
+
+/* caller must ensure LOCK is taken (e.g. if ioctls need to be serialised) */
+gboolean
+gst_oss4_property_probe_find_device_name (GstObject * obj, int fd,
+    const gchar * device_handle, gchar ** device_name)
+{
+  struct oss_sysinfo si = { {0,}, };
+  gchar *name = NULL;
+
+  if (ioctl (fd, SNDCTL_SYSINFO, &si) == 0) {
+    int i;
+
+    for (i = 0; i < si.numaudios; ++i) {
+      struct oss_audioinfo ai = { 0, };
+
+      ai.dev = i;
+      if (ioctl (fd, SNDCTL_AUDIOINFO, &ai) == -1) {
+        GST_DEBUG_OBJECT (obj, "AUDIOINFO ioctl for device %d failed", i);
+        continue;
+      }
+      if (strcmp (ai.devnode, device_handle) == 0) {
+        name = g_strdup (ai.name);
+        break;
+      }
+    }
+  } else {
+    GST_WARNING_OBJECT (obj, "SYSINFO ioctl failed: %s", g_strerror (errno));
+  }
+
+  /* try ENGINEINFO as fallback (which is better than nothing) */
+  if (name == NULL) {
+    struct oss_audioinfo ai = { 0, };
+
+    GST_LOG_OBJECT (obj, "device %s not listed in AUDIOINFO", device_handle);
+    ai.dev = -1;
+    if (ioctl (fd, SNDCTL_ENGINEINFO, &ai) == 0)
+      name = g_strdup (ai.name);
+  }
+
+  GST_DEBUG_OBJECT (obj, "Device name: %s", GST_STR_NULL (name));
+
+  if (name != NULL)
+    *device_name = name;
+
+  return (name != NULL);
+}
+
+gboolean
+gst_oss4_property_probe_find_device_name_nofd (GstObject * obj,
+    const gchar * device_handle, gchar ** device_name)
+{
+  gboolean res;
+  int fd;
+
+  fd = open ("/dev/mixer", O_RDONLY);
+  if (fd < 0)
+    return FALSE;
+
+  res = gst_oss4_property_probe_find_device_name (obj, fd, device_handle,
+      device_name);
+
+  close (fd);
+  return res;
+}
+
+static GList *
+gst_oss4_property_probe_get_audio_devices (GstObject * obj, int fd,
+    struct oss_sysinfo *si, int cap_mask)
+{
+  GList *devices = NULL;
+  int i;
+
+  GST_LOG_OBJECT (obj, "%d audio/dsp devices", si->numaudios);
+
+  for (i = 0; i < si->numaudios; ++i) {
+    struct oss_audioinfo ai = { 0, };
+
+    ai.dev = i;
+    if (ioctl (fd, SNDCTL_AUDIOINFO, &ai) == -1) {
+      GST_DEBUG_OBJECT (obj, "AUDIOINFO ioctl for device %d failed", i);
+      continue;
+    }
+
+    if ((ai.caps & cap_mask) == 0) {
+      GST_DEBUG_OBJECT (obj, "audio device %d is not an %s device", i,
+          (cap_mask == PCM_CAP_OUTPUT) ? "output" : "input");
+      continue;
+    }
+
+    if (!ai.enabled) {
+      GST_DEBUG_OBJECT (obj, "audio device %d is not usable/enabled", i);
+      continue;
+    }
+
+    GST_DEBUG_OBJECT (obj, "audio device %d looks ok: %s (\"%s\")", i,
+        ai.devnode, ai.name);
+
+    devices = g_list_prepend (devices, g_strdup (ai.devnode));
+  }
+
+  return g_list_reverse (devices);
+}
+
+GValueArray *
+gst_oss4_property_probe_get_values (GstObject * probe, const gchar * pname)
+{
+  struct oss_sysinfo si = { {0,}, };
+  GValueArray *array = NULL;
+  GstObject *obj;
+  GList *devices, *l;
+  int cap_mask, fd = -1;
+
+  if (!g_str_equal (pname, "device")) {
+    GST_WARNING_OBJECT (probe, "invalid property");
+    return NULL;
+  }
+
+  obj = GST_OBJECT (probe);
+
+  GST_OBJECT_LOCK (obj);
+
+  /* figure out whether the element is a source or sink */
+  if (GST_IS_OSS4_SINK (probe)) {
+    GST_DEBUG_OBJECT (probe, "probing available output devices");
+    cap_mask = PCM_CAP_OUTPUT;
+    fd = GST_OSS4_SINK (probe)->fd;
+  } else if (GST_IS_OSS4_SOURCE (probe)) {
+    GST_DEBUG_OBJECT (probe, "probing available input devices");
+    cap_mask = PCM_CAP_INPUT;
+    fd = GST_OSS4_SOURCE (probe)->fd;
+  } else {
+    GST_OBJECT_UNLOCK (obj);
+    g_assert_not_reached ();
+    return NULL;
+  }
+
+  /* copy fd if it's open, so we can just unconditionally close() later */
+  if (fd != -1)
+    fd = dup (fd);
+
+  /* this will also catch the unlikely case where the above dup() failed */
+  if (fd == -1) {
+    fd = open ("/dev/mixer", O_RDONLY | O_NONBLOCK, 0);
+    if (fd < 0)
+      goto open_failed;
+    else if (!gst_oss4_audio_check_version (GST_OBJECT (probe), fd))
+      goto legacy_oss;
+  }
+
+  if (ioctl (fd, SNDCTL_SYSINFO, &si) == -1)
+    goto no_sysinfo;
+
+  devices = gst_oss4_property_probe_get_audio_devices (obj, fd, &si, cap_mask);
+
+  if (devices == NULL) {
+    GST_OBJECT_UNLOCK (obj);
+    GST_DEBUG_OBJECT (obj, "No devices found");
+    goto done;
+  }
+
+  array = g_value_array_new (1);
+
+  for (l = devices; l != NULL; l = l->next) {
+    GValue val = { 0, };
+
+    g_value_init (&val, G_TYPE_STRING);
+    g_value_take_string (&val, (gchar *) l->data);
+    l->data = NULL;
+    g_value_array_append (array, &val);
+    g_value_unset (&val);
+  }
+
+  GST_OBJECT_UNLOCK (obj);
+
+  g_list_free (devices);
+
+done:
+
+  close (fd);
+
+  return array;
+
+/* ERRORS */
+open_failed:
+  {
+    GST_OBJECT_UNLOCK (GST_OBJECT (probe));
+    GST_WARNING_OBJECT (probe, "Can't open file descriptor to probe "
+        "available devices: %s", g_strerror (errno));
+    return NULL;
+  }
+legacy_oss:
+  {
+    close (fd);
+    GST_OBJECT_UNLOCK (GST_OBJECT (probe));
+    GST_DEBUG_OBJECT (probe, "Legacy OSS (ie. not OSSv4), not supported");
+    return NULL;
+  }
+no_sysinfo:
+  {
+    close (fd);
+    GST_OBJECT_UNLOCK (GST_OBJECT (probe));
+    GST_WARNING_OBJECT (probe, "Can't open file descriptor to probe "
+        "available devices: %s", g_strerror (errno));
+    return NULL;
+  }
+}
+
+#if 0
+static void
+gst_oss4_property_probe_interface_init (GstPropertyProbeInterface * iface)
+{
+  iface->get_properties = gst_oss4_property_probe_get_properties;
+  iface->probe_property = gst_oss4_property_probe_probe_property;
+  iface->needs_probe = gst_oss4_property_probe_needs_probe;
+  iface->get_values = gst_oss4_property_probe_get_values;
+}
+
+void
+gst_oss4_add_property_probe_interface (GType type)
+{
+  static const GInterfaceInfo probe_iface_info = {
+    (GInterfaceInitFunc) gst_oss4_property_probe_interface_init,
+    NULL,
+    NULL,
+  };
+
+  g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
+      &probe_iface_info);
+}
+#endif
diff --git a/sys/oss4/oss4-property-probe.h b/sys/oss4/oss4-property-probe.h
new file mode 100644
index 0000000..1f46f9a
--- /dev/null
+++ b/sys/oss4/oss4-property-probe.h
@@ -0,0 +1,45 @@
+/* GStreamer OSS4 audio property probe interface implementation
+ * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GST_OSS4_PROPERTY_PROBE_H
+#define GST_OSS4_PROPERTY_PROBE_H
+
+#if 0
+
+#include <gst/interfaces/propertyprobe.h>
+
+void      gst_oss4_add_property_probe_interface (GType type);
+
+#endif
+
+gboolean  gst_oss4_property_probe_find_device_name (GstObject   * obj,
+                                                    int           fd,
+                                                    const gchar * device_handle,
+                                                    gchar      ** device_name);
+
+gboolean  gst_oss4_property_probe_find_device_name_nofd (GstObject   * obj,
+                                                         const gchar * device_handle,
+                                                         gchar      ** device_name);
+
+GValueArray *gst_oss4_property_probe_get_values (GstObject * obj, const gchar * pname);
+
+
+#endif /* GST_OSS4_PROPERTY_PROBE_H */
+
+
diff --git a/sys/oss4/oss4-sink.c b/sys/oss4/oss4-sink.c
new file mode 100644
index 0000000..84028e7
--- /dev/null
+++ b/sys/oss4/oss4-sink.c
@@ -0,0 +1,689 @@
+/* GStreamer OSS4 audio sink
+ * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:element-oss4sink
+ *
+ * This element lets you output sound using the Open Sound System (OSS)
+ * version 4.
+ * 
+ * Note that you should almost always use generic audio conversion elements
+ * like audioconvert and audioresample in front of an audiosink to make sure
+ * your pipeline works under all circumstances (those conversion elements will
+ * act in passthrough-mode if no conversion is necessary).
+ * 
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! audioconvert ! volume volume=0.1 ! oss4sink
+ * ]| will output a sine wave (continuous beep sound) to your sound card (with
+ * a very low volume as precaution).
+ * |[
+ * gst-launch-1.0 -v filesrc location=music.ogg ! decodebin ! audioconvert ! audioresample ! oss4sink
+ * ]| will play an Ogg/Vorbis audio file and output it using the Open Sound System
+ * version 4.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <gst/gst-i18n-plugin.h>
+#include <gst/audio/streamvolume.h>
+
+#define NO_LEGACY_MIXER
+#include "oss4-audio.h"
+#include "oss4-sink.h"
+#include "oss4-property-probe.h"
+#include "oss4-soundcard.h"
+
+GST_DEBUG_CATEGORY_EXTERN (oss4sink_debug);
+#define GST_CAT_DEFAULT oss4sink_debug
+
+static void gst_oss4_sink_dispose (GObject * object);
+static void gst_oss4_sink_finalize (GObject * object);
+
+static void gst_oss4_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_oss4_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_oss4_sink_getcaps (GstBaseSink * bsink, GstCaps * filter);
+static gboolean gst_oss4_sink_open (GstAudioSink * asink,
+    gboolean silent_errors);
+static gboolean gst_oss4_sink_open_func (GstAudioSink * asink);
+static gboolean gst_oss4_sink_close (GstAudioSink * asink);
+static gboolean gst_oss4_sink_prepare (GstAudioSink * asink,
+    GstAudioRingBufferSpec * spec);
+static gboolean gst_oss4_sink_unprepare (GstAudioSink * asink);
+static gint gst_oss4_sink_write (GstAudioSink * asink, gpointer data,
+    guint length);
+static guint gst_oss4_sink_delay (GstAudioSink * asink);
+static void gst_oss4_sink_reset (GstAudioSink * asink);
+
+#define DEFAULT_DEVICE      NULL
+#define DEFAULT_DEVICE_NAME NULL
+#define DEFAULT_MUTE        FALSE
+#define DEFAULT_VOLUME      1.0
+#define MAX_VOLUME          10.0
+
+enum
+{
+  PROP_0,
+  PROP_DEVICE,
+  PROP_DEVICE_NAME,
+  PROP_VOLUME,
+  PROP_MUTE,
+  PROP_LAST
+};
+
+#define gst_oss4_sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstOss4Sink, gst_oss4_sink,
+    GST_TYPE_AUDIO_SINK, G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL));
+
+static void
+gst_oss4_sink_dispose (GObject * object)
+{
+  GstOss4Sink *osssink = GST_OSS4_SINK (object);
+
+  if (osssink->probed_caps) {
+    gst_caps_unref (osssink->probed_caps);
+    osssink->probed_caps = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_oss4_sink_class_init (GstOss4SinkClass * klass)
+{
+  GstAudioSinkClass *audiosink_class = (GstAudioSinkClass *) klass;
+  GstBaseSinkClass *basesink_class = (GstBaseSinkClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstPadTemplate *templ;
+
+  gobject_class->dispose = gst_oss4_sink_dispose;
+  gobject_class->finalize = gst_oss4_sink_finalize;
+  gobject_class->get_property = gst_oss4_sink_get_property;
+  gobject_class->set_property = gst_oss4_sink_set_property;
+
+  g_object_class_install_property (gobject_class, PROP_DEVICE,
+      g_param_spec_string ("device", "Device",
+          "OSS4 device (e.g. /dev/oss/hdaudio0/pcm0 or /dev/dspN) "
+          "(NULL = use first available playback device)",
+          DEFAULT_DEVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
+      g_param_spec_string ("device-name", "Device name",
+          "Human-readable name of the sound device", DEFAULT_DEVICE_NAME,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_VOLUME,
+      g_param_spec_double ("volume", "Volume",
+          "Linear volume of this stream, 1.0=100%", 0.0, MAX_VOLUME,
+          DEFAULT_VOLUME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_MUTE,
+      g_param_spec_boolean ("mute", "Mute",
+          "Mute state of this stream", DEFAULT_MUTE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  basesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_oss4_sink_getcaps);
+
+  audiosink_class->open = GST_DEBUG_FUNCPTR (gst_oss4_sink_open_func);
+  audiosink_class->close = GST_DEBUG_FUNCPTR (gst_oss4_sink_close);
+  audiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_oss4_sink_prepare);
+  audiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_oss4_sink_unprepare);
+  audiosink_class->write = GST_DEBUG_FUNCPTR (gst_oss4_sink_write);
+  audiosink_class->delay = GST_DEBUG_FUNCPTR (gst_oss4_sink_delay);
+  audiosink_class->reset = GST_DEBUG_FUNCPTR (gst_oss4_sink_reset);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "OSS v4 Audio Sink", "Sink/Audio",
+      "Output to a sound card via OSS version 4",
+      "Tim-Philipp Müller <tim centricular net>");
+
+  templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+      gst_oss4_audio_get_template_caps ());
+  gst_element_class_add_pad_template (gstelement_class, templ);
+}
+
+static void
+gst_oss4_sink_init (GstOss4Sink * osssink)
+{
+  const gchar *device;
+
+  device = g_getenv ("AUDIODEV");
+  if (device == NULL)
+    device = DEFAULT_DEVICE;
+  osssink->device = g_strdup (device);
+  osssink->fd = -1;
+  osssink->bytes_per_sample = 0;
+  osssink->probed_caps = NULL;
+  osssink->device_name = NULL;
+  osssink->mute_volume = 100 | (100 << 8);
+}
+
+static void
+gst_oss4_sink_finalize (GObject * object)
+{
+  GstOss4Sink *osssink = GST_OSS4_SINK (object);
+
+  g_free (osssink->device);
+  osssink->device = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_oss4_sink_set_volume (GstOss4Sink * oss, gdouble volume)
+{
+  int ivol;
+
+  volume = volume * 100.0;
+  ivol = (int) volume | ((int) volume << 8);
+  GST_OBJECT_LOCK (oss);
+  if (ioctl (oss->fd, SNDCTL_DSP_SETPLAYVOL, &ivol) < 0) {
+    GST_LOG_OBJECT (oss, "SETPLAYVOL failed");
+  }
+  GST_OBJECT_UNLOCK (oss);
+}
+
+static gdouble
+gst_oss4_sink_get_volume (GstOss4Sink * oss)
+{
+  int ivol, lvol, rvol;
+  gdouble dvol = DEFAULT_VOLUME;
+
+  GST_OBJECT_LOCK (oss);
+  if (ioctl (oss->fd, SNDCTL_DSP_GETPLAYVOL, &ivol) < 0) {
+    GST_LOG_OBJECT (oss, "GETPLAYVOL failed");
+  } else {
+    /* Return the higher of the two volume channels, if different */
+    lvol = ivol & 0xff;
+    rvol = (ivol >> 8) & 0xff;
+    dvol = MAX (lvol, rvol) / 100.0;
+  }
+  GST_OBJECT_UNLOCK (oss);
+
+  return dvol;
+}
+
+static void
+gst_oss4_sink_set_mute (GstOss4Sink * oss, gboolean mute)
+{
+  int ivol;
+
+  if (mute) {
+    /*
+     * OSSv4 does not have a per-channel mute, so simulate by setting
+     * the value to 0.  Save the volume before doing a mute so we can
+     * reset the value when the user un-mutes.
+     */
+    ivol = 0;
+
+    GST_OBJECT_LOCK (oss);
+    if (ioctl (oss->fd, SNDCTL_DSP_GETPLAYVOL, &oss->mute_volume) < 0) {
+      GST_LOG_OBJECT (oss, "GETPLAYVOL failed");
+    }
+    if (ioctl (oss->fd, SNDCTL_DSP_SETPLAYVOL, &ivol) < 0) {
+      GST_LOG_OBJECT (oss, "SETPLAYVOL failed");
+    }
+    GST_OBJECT_UNLOCK (oss);
+  } else {
+    /*
+     * If the saved volume is 0, then reset it to 100.  Otherwise the mute
+     * can get stuck.  This can happen, for example, due to rounding
+     * errors in converting from the float to an integer.
+     */
+    if (oss->mute_volume == 0) {
+      oss->mute_volume = 100 | (100 << 8);
+    }
+    GST_OBJECT_LOCK (oss);
+    if (ioctl (oss->fd, SNDCTL_DSP_SETPLAYVOL, &oss->mute_volume) < 0) {
+      GST_LOG_OBJECT (oss, "SETPLAYVOL failed");
+    }
+    GST_OBJECT_UNLOCK (oss);
+  }
+}
+
+static gboolean
+gst_oss4_sink_get_mute (GstOss4Sink * oss)
+{
+  int ivol, lvol, rvol;
+
+  GST_OBJECT_LOCK (oss);
+  if (ioctl (oss->fd, SNDCTL_DSP_GETPLAYVOL, &ivol) < 0) {
+    GST_LOG_OBJECT (oss, "GETPLAYVOL failed");
+    lvol = rvol = 100;
+  } else {
+    lvol = ivol & 0xff;
+    rvol = (ivol >> 8) & 0xff;
+  }
+  GST_OBJECT_UNLOCK (oss);
+
+  return (lvol == 0 && rvol == 0);
+}
+
+static void
+gst_oss4_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstOss4Sink *oss = GST_OSS4_SINK (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE:
+      GST_OBJECT_LOCK (oss);
+      if (oss->fd == -1) {
+        g_free (oss->device);
+        oss->device = g_value_dup_string (value);
+        if (oss->probed_caps) {
+          gst_caps_unref (oss->probed_caps);
+          oss->probed_caps = NULL;
+        }
+        g_free (oss->device_name);
+        oss->device_name = NULL;
+      } else {
+        g_warning ("%s: can't change \"device\" property while audio sink "
+            "is open", GST_OBJECT_NAME (oss));
+      }
+      GST_OBJECT_UNLOCK (oss);
+      break;
+    case PROP_VOLUME:
+      gst_oss4_sink_set_volume (oss, g_value_get_double (value));
+      break;
+    case PROP_MUTE:
+      gst_oss4_sink_set_mute (oss, g_value_get_boolean (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_oss4_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstOss4Sink *oss = GST_OSS4_SINK (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE:
+      GST_OBJECT_LOCK (oss);
+      g_value_set_string (value, oss->device);
+      GST_OBJECT_UNLOCK (oss);
+      break;
+    case PROP_DEVICE_NAME:
+      GST_OBJECT_LOCK (oss);
+      if (oss->fd == -1 && oss->device != NULL) {
+        /* If device is set, try to retrieve the name even if we're not open */
+        if (gst_oss4_sink_open (GST_AUDIO_SINK (oss), TRUE)) {
+          g_value_set_string (value, oss->device_name);
+          gst_oss4_sink_close (GST_AUDIO_SINK (oss));
+        } else {
+          gchar *name = NULL;
+
+          gst_oss4_property_probe_find_device_name_nofd (GST_OBJECT (oss),
+              oss->device, &name);
+          g_value_set_string (value, name);
+          g_free (name);
+        }
+      } else {
+        g_value_set_string (value, oss->device_name);
+      }
+      GST_OBJECT_UNLOCK (oss);
+      break;
+    case PROP_VOLUME:
+      g_value_set_double (value, gst_oss4_sink_get_volume (oss));
+      break;
+    case PROP_MUTE:
+      g_value_set_boolean (value, gst_oss4_sink_get_mute (oss));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstCaps *
+gst_oss4_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
+{
+  GstOss4Sink *oss;
+  GstCaps *caps;
+
+  oss = GST_OSS4_SINK (bsink);
+
+  if (oss->fd == -1) {
+    caps = gst_oss4_audio_get_template_caps ();
+  } else if (oss->probed_caps) {
+    caps = gst_caps_copy (oss->probed_caps);
+  } else {
+    caps = gst_oss4_audio_probe_caps (GST_OBJECT (oss), oss->fd);
+    if (caps != NULL && !gst_caps_is_empty (caps)) {
+      oss->probed_caps = gst_caps_copy (caps);
+    }
+  }
+
+  if (filter && caps) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    return intersection;
+  } else {
+    return caps;
+  }
+}
+
+/* note: we must not take the object lock here unless we fix up get_property */
+static gboolean
+gst_oss4_sink_open (GstAudioSink * asink, gboolean silent_errors)
+{
+  GstOss4Sink *oss;
+  gchar *device;
+  int mode;
+
+  oss = GST_OSS4_SINK (asink);
+
+  if (oss->device)
+    device = g_strdup (oss->device);
+  else
+    device = gst_oss4_audio_find_device (GST_OBJECT_CAST (oss));
+
+  /* desperate times, desperate measures */
+  if (device == NULL)
+    device = g_strdup ("/dev/dsp0");
+
+  GST_INFO_OBJECT (oss, "Trying to open OSS4 device '%s'", device);
+
+  /* we open in non-blocking mode even if we don't really want to do writes
+   * non-blocking because we can't be sure that this is really a genuine
+   * OSS4 device with well-behaved drivers etc. We really don't want to
+   * hang forever under any circumstances. */
+  oss->fd = open (device, O_WRONLY | O_NONBLOCK, 0);
+  if (oss->fd == -1) {
+    switch (errno) {
+      case EBUSY:
+        goto busy;
+      case EACCES:
+        goto no_permission;
+      default:
+        goto open_failed;
+    }
+  }
+
+  GST_INFO_OBJECT (oss, "Opened device '%s'", device);
+
+  /* Make sure it's OSS4. If it's old OSS, let osssink handle it */
+  if (!gst_oss4_audio_check_version (GST_OBJECT_CAST (oss), oss->fd))
+    goto legacy_oss;
+
+  /* now remove the non-blocking flag. */
+  mode = fcntl (oss->fd, F_GETFL);
+  mode &= ~O_NONBLOCK;
+  if (fcntl (oss->fd, F_SETFL, mode) < 0) {
+    /* some drivers do no support unsetting the non-blocking flag, try to
+     * close/open the device then. This is racy but we error out properly. */
+    GST_WARNING_OBJECT (oss, "failed to unset O_NONBLOCK (buggy driver?), "
+        "will try to re-open device now");
+    gst_oss4_sink_close (asink);
+    if ((oss->fd = open (device, O_WRONLY, 0)) == -1)
+      goto non_block;
+  }
+
+  oss->open_device = device;
+
+  /* not using ENGINEINFO here because it sometimes returns a different and
+   * less useful name than AUDIOINFO for the same device */
+  if (!gst_oss4_property_probe_find_device_name (GST_OBJECT (oss), oss->fd,
+          oss->open_device, &oss->device_name)) {
+    oss->device_name = NULL;
+  }
+
+  /* list output routings, for informational purposes only so far */
+  {
+    oss_mixer_enuminfo routings = { 0, };
+    guint i;
+
+    if (ioctl (oss->fd, SNDCTL_DSP_GET_PLAYTGT_NAMES, &routings) != -1) {
+      GST_LOG_OBJECT (oss, "%u output routings (static list: %d)",
+          routings.nvalues, ! !(routings.version == 0));
+      for (i = 0; i < routings.nvalues; ++i) {
+        GST_LOG_OBJECT (oss, "  output routing %d: %s", i,
+            &routings.strings[routings.strindex[i]]);
+      }
+    }
+  }
+
+  return TRUE;
+
+  /* ERRORS */
+busy:
+  {
+    if (!silent_errors) {
+      GST_ELEMENT_ERROR (oss, RESOURCE, BUSY,
+          (_("Could not open audio device for playback. "
+                  "Device is being used by another application.")), (NULL));
+    }
+    g_free (device);
+    return FALSE;
+  }
+no_permission:
+  {
+    if (!silent_errors) {
+      GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE,
+          (_("Could not open audio device for playback. "
+                  "You don't have permission to open the device.")),
+          GST_ERROR_SYSTEM);
+    }
+    g_free (device);
+    return FALSE;
+  }
+open_failed:
+  {
+    if (!silent_errors) {
+      GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE,
+          (_("Could not open audio device for playback.")), GST_ERROR_SYSTEM);
+    }
+    g_free (device);
+    return FALSE;
+  }
+legacy_oss:
+  {
+    if (!silent_errors) {
+      GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE,
+          (_("Could not open audio device for playback. "
+                  "This version of the Open Sound System is not supported by this "
+                  "element.")), ("Try the 'osssink' element instead"));
+    }
+    gst_oss4_sink_close (asink);
+    g_free (device);
+    return FALSE;
+  }
+non_block:
+  {
+    if (!silent_errors) {
+      GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, (NULL),
+          ("Unable to set device %s into non-blocking mode: %s",
+              oss->device, g_strerror (errno)));
+    }
+    g_free (device);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_oss4_sink_open_func (GstAudioSink * asink)
+{
+  if (!gst_oss4_sink_open (asink, FALSE))
+    return FALSE;
+
+  /* the initial volume might not be the property default, so notify
+   * application to make it get a reading of the current volume */
+  g_object_notify (G_OBJECT (asink), "volume");
+  return TRUE;
+}
+
+static gboolean
+gst_oss4_sink_close (GstAudioSink * asink)
+{
+  GstOss4Sink *oss = GST_OSS4_SINK (asink);
+
+  if (oss->fd != -1) {
+    GST_DEBUG_OBJECT (oss, "closing device");
+    close (oss->fd);
+    oss->fd = -1;
+  }
+
+  oss->bytes_per_sample = 0;
+  /* we keep the probed caps cached, at least until the device changes */
+
+  g_free (oss->open_device);
+  oss->open_device = NULL;
+
+  g_free (oss->device_name);
+  oss->device_name = NULL;
+
+  if (oss->probed_caps) {
+    gst_caps_unref (oss->probed_caps);
+    oss->probed_caps = NULL;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_oss4_sink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec)
+{
+  GstOss4Sink *oss;
+
+  oss = GST_OSS4_SINK (asink);
+
+  if (!gst_oss4_audio_set_format (GST_OBJECT_CAST (oss), oss->fd, spec)) {
+    GST_WARNING_OBJECT (oss, "Couldn't set requested format %" GST_PTR_FORMAT,
+        spec->caps);
+    return FALSE;
+  }
+
+  oss->bytes_per_sample = GST_AUDIO_INFO_BPF (&spec->info);
+
+  return TRUE;
+}
+
+static gboolean
+gst_oss4_sink_unprepare (GstAudioSink * asink)
+{
+  /* could do a SNDCTL_DSP_HALT, but the OSS manual recommends a close/open,
+   * since HALT won't properly reset some devices, apparently */
+
+  if (!gst_oss4_sink_close (asink))
+    goto couldnt_close;
+
+  if (!gst_oss4_sink_open_func (asink))
+    goto couldnt_reopen;
+
+  return TRUE;
+
+  /* ERRORS */
+couldnt_close:
+  {
+    GST_DEBUG_OBJECT (asink, "Couldn't close the audio device");
+    return FALSE;
+  }
+couldnt_reopen:
+  {
+    GST_DEBUG_OBJECT (asink, "Couldn't reopen the audio device");
+    return FALSE;
+  }
+}
+
+static gint
+gst_oss4_sink_write (GstAudioSink * asink, gpointer data, guint length)
+{
+  GstOss4Sink *oss;
+  int n;
+
+  oss = GST_OSS4_SINK_CAST (asink);
+
+  n = write (oss->fd, data, length);
+  GST_LOG_OBJECT (asink, "wrote %d/%d samples, %d bytes",
+      n / oss->bytes_per_sample, length / oss->bytes_per_sample, n);
+
+  if (G_UNLIKELY (n < 0)) {
+    switch (errno) {
+      case ENOTSUP:
+      case EACCES:{
+        /* This is the most likely cause, I think */
+        GST_ELEMENT_ERROR (asink, RESOURCE, WRITE,
+            (_("Playback is not supported by this audio device.")),
+            ("write: %s (device: %s) (maybe this is an input-only device?)",
+                g_strerror (errno), oss->open_device));
+        break;
+      }
+      default:{
+        GST_ELEMENT_ERROR (asink, RESOURCE, WRITE,
+            (_("Audio playback error.")),
+            ("write: %s (device: %s)", g_strerror (errno), oss->open_device));
+        break;
+      }
+    }
+  }
+
+  return n;
+}
+
+static guint
+gst_oss4_sink_delay (GstAudioSink * asink)
+{
+  GstOss4Sink *oss;
+  gint delay = -1;
+
+  oss = GST_OSS4_SINK_CAST (asink);
+
+  GST_OBJECT_LOCK (oss);
+  if (ioctl (oss->fd, SNDCTL_DSP_GETODELAY, &delay) < 0 || delay < 0) {
+    GST_LOG_OBJECT (oss, "GETODELAY failed");
+  }
+  GST_OBJECT_UNLOCK (oss);
+
+  if (G_UNLIKELY (delay < 0))   /* error case */
+    return 0;
+
+  return delay / oss->bytes_per_sample;
+}
+
+static void
+gst_oss4_sink_reset (GstAudioSink * asink)
+{
+  /* There's nothing we can do here really: OSS can't handle access to the
+   * same device/fd from multiple threads and might deadlock or blow up in
+   * other ways if we try an ioctl SNDCTL_DSP_HALT or similar */
+}
diff --git a/sys/oss4/oss4-sink.h b/sys/oss4/oss4-sink.h
new file mode 100644
index 0000000..04645fe
--- /dev/null
+++ b/sys/oss4/oss4-sink.h
@@ -0,0 +1,62 @@
+/* GStreamer OSS4 audio sink
+ * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GST_OSS4_SINK_H
+#define GST_OSS4_SINK_H
+
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosink.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_OSS4_SINK            (gst_oss4_sink_get_type())
+#define GST_OSS4_SINK(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS4_SINK,GstOss4Sink))
+#define GST_OSS4_SINK_CAST(obj)       ((GstOss4Sink *)(obj))
+#define GST_OSS4_SINK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS4_SINK,GstOss4SinkClass))
+#define GST_IS_OSS4_SINK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS4_SINK))
+#define GST_IS_OSS4_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS4_SINK))
+
+typedef struct _GstOss4Sink GstOss4Sink;
+typedef struct _GstOss4SinkClass GstOss4SinkClass;
+
+struct _GstOss4Sink {
+  GstAudioSink  audio_sink;
+
+  gchar       * device;             /* NULL if none was set      */
+  gchar       * open_device;        /* the device we opened      */
+  gchar       * device_name;        /* set if the device is open */
+  gint          fd;                 /* -1 if not open            */
+  gint          bytes_per_sample;
+  gint          mute_volume;
+
+  GstCaps     * probed_caps;
+};
+
+struct _GstOss4SinkClass {
+  GstAudioSinkClass audio_sink_class;
+};
+
+GType  gst_oss4_sink_get_type (void);
+
+G_END_DECLS
+
+#endif /* GST_OSS4_SINK_H */
+
+
diff --git a/sys/oss4/oss4-soundcard.h b/sys/oss4/oss4-soundcard.h
new file mode 100644
index 0000000..8b12489
--- /dev/null
+++ b/sys/oss4/oss4-soundcard.h
@@ -0,0 +1,2067 @@
+/*
+ * Purpose: The C/C++ header file that defines the OSS API.
+ * Description:
+ * This header file contains all the declarations required to compile OSS
+ * programs. The latest version is always installed together with OSS
+ * use of the latest version is strongly recommended.
+ *
+ * {!notice This header file contains many obsolete definitions
+ * (for compatibility with older applications that still ned them).
+ * Do not use this file as a reference manual of OSS.
+ * Please check the OSS Programmer's guide for descriptions
+ * of the supported API details (http://manuals.opensound.com/developer).}
+ */
+
+#ifndef SOUNDCARD_H
+#define SOUNDCARD_H
+
+#define COPYING40 Copyright (C) 4Front Technologies 2000-2006. Released under the BSD license.
+
+#if defined(__cplusplus)
+#define EXTERNC extern "C"
+#else
+#define EXTERNC extern
+#endif /* EXTERN_C_WRAPPERS */
+
+#define OSS_VERSION	0x040090 // Pre 4.1
+
+#define SOUND_VERSION	OSS_VERSION
+#define OPEN_SOUND_SYSTEM
+
+#if defined(__hpux) && !defined(_HPUX_SOURCE)
+#	error "-D_HPUX_SOURCE must be used when compiling OSS applications"
+#endif
+
+#ifdef __hpux
+#include <sys/ioctl.h>
+#endif
+
+#ifdef linux
+/* In Linux we need to be prepared for cross compiling */
+#include <linux/ioctl.h>
+#else
+# ifdef __FreeBSD__
+#    include <sys/ioccom.h>
+# else
+#    include <sys/ioctl.h>
+# endif
+#endif
+
+#ifndef __SIOWR
+#if defined(__hpux) || (defined(_IOWR) && (defined(_AIX) || (!defined(sun) && !defined(sparc) && !defined(__INCioctlh) && !defined(__Lynx__))))
+
+/* 
+ * Make sure the ioctl macros are compatible with the ones already used
+ * by this operating system.
+ */
+#define	SIOCPARM_MASK	IOCPARM_MASK
+#define	SIOC_VOID	IOC_VOID
+#define	SIOC_OUT	IOC_OUT
+#define	SIOC_IN		IOC_IN
+#define	SIOC_INOUT	IOC_INOUT
+#define __SIOC_SIZE	_IOC_SIZE
+#define __SIOC_DIR	_IOC_DIR
+#define __SIOC_NONE	_IOC_NONE
+#define __SIOC_READ	_IOC_READ
+#define __SIOC_WRITE	_IOC_WRITE
+#define	__SIO		_IO
+#define	__SIOR		_IOR
+#define	__SIOW		_IOW
+#define	__SIOWR		_IOWR
+#else
+
+/* #define	SIOCTYPE		(0xff<<8) */
+#define	SIOCPARM_MASK	0x1fff	/* parameters must be < 8192 bytes */
+#define	SIOC_VOID	0x00000000	/* no parameters */
+#define	SIOC_OUT	0x20000000	/* copy out parameters */
+#define	SIOC_IN		0x40000000	/* copy in parameters */
+#define	SIOC_INOUT	(SIOC_IN|SIOC_OUT)
+
+#define	__SIO(x,y)	((int)(SIOC_VOID|(x<<8)|y))
+#define	__SIOR(x,y,t)	((int)(SIOC_OUT|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y))
+#define	__SIOW(x,y,t)	((int)(SIOC_IN|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y))
+#define	__SIOWR(x,y,t)	((int)(SIOC_INOUT|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y))
+#define __SIOC_SIZE(x)	((x>>16)&SIOCPARM_MASK)
+#define __SIOC_DIR(x)	(x & 0xf0000000)
+#define __SIOC_NONE	SIOC_VOID
+#define __SIOC_READ	SIOC_OUT
+#define __SIOC_WRITE	SIOC_IN
+#  endif /* _IOWR */
+#endif /* !__SIOWR */
+
+#define OSS_LONGNAME_SIZE	64
+#define OSS_LABEL_SIZE		16
+#define OSS_DEVNODE_SIZE	32
+typedef char oss_longname_t[OSS_LONGNAME_SIZE];
+typedef char oss_label_t[OSS_LABEL_SIZE];
+typedef char oss_devnode_t[OSS_DEVNODE_SIZE];
+
+#ifndef DISABLE_SEQUENCER
+/*
+ ****************************************************************************
+ * IOCTL Commands for /dev/sequencer and /dev/music (AKA /dev/sequencer2)
+ *
+ * Note that this interface is obsolete and no longer developed. New
+ * applications should use /dev/midi instead.
+ ****************************************************************************/
+#define SNDCTL_SEQ_RESET		__SIO  ('Q', 0)
+#define SNDCTL_SEQ_SYNC			__SIO  ('Q', 1)
+#define SNDCTL_SYNTH_INFO		__SIOWR('Q', 2, struct synth_info)
+#define SNDCTL_SEQ_CTRLRATE		__SIOWR('Q', 3, int)	/* Set/get timer resolution (HZ) */
+#define SNDCTL_SEQ_GETOUTCOUNT		__SIOR ('Q', 4, int)
+#define SNDCTL_SEQ_GETINCOUNT		__SIOR ('Q', 5, int)
+#define SNDCTL_SEQ_PERCMODE		__SIOW ('Q', 6, int)
+#define SNDCTL_FM_LOAD_INSTR		__SIOW ('Q', 7, struct sbi_instrument)	/* Obsolete. Don't use!!!!!! */
+#define SNDCTL_SEQ_TESTMIDI		__SIOW ('Q', 8, int)
+#define SNDCTL_SEQ_RESETSAMPLES		__SIOW ('Q', 9, int)
+#define SNDCTL_SEQ_NRSYNTHS		__SIOR ('Q',10, int)
+#define SNDCTL_SEQ_NRMIDIS		__SIOR ('Q',11, int)
+#define SNDCTL_MIDI_INFO		__SIOWR('Q',12, struct midi_info)	/* OBSOLETE - use SNDCTL_MIDIINFO instead */
+#define SNDCTL_SEQ_THRESHOLD		__SIOW ('Q',13, int)
+#define SNDCTL_SYNTH_MEMAVL		__SIOWR('Q',14, int)	/* in=dev#, out=memsize */
+#define SNDCTL_FM_4OP_ENABLE		__SIOW ('Q',15, int)	/* in=dev# */
+#define SNDCTL_SEQ_PANIC		__SIO  ('Q',17)
+#define SNDCTL_SEQ_OUTOFBAND		__SIOW ('Q',18, struct seq_event_rec)
+#define SNDCTL_SEQ_GETTIME		__SIOR ('Q',19, int)
+#define SNDCTL_SYNTH_ID			__SIOWR('Q',20, struct synth_info)
+#define SNDCTL_SYNTH_CONTROL		__SIOWR('Q',21, struct synth_control)
+#define SNDCTL_SYNTH_REMOVESAMPLE	__SIOWR('Q',22, struct remove_sample)	/* Reserved for future use */
+#define SNDCTL_SEQ_TIMING_ENABLE	__SIO  ('Q', 23)	/* Enable incoming MIDI timing messages */
+#define SNDCTL_SEQ_ACTSENSE_ENABLE	__SIO  ('Q', 24)	/* Enable incoming active sensing messages */
+#define SNDCTL_SEQ_RT_ENABLE		__SIO  ('Q', 25)	/* Enable other incoming realtime messages */
+
+typedef struct synth_control
+{
+  int devno;			/* Synthesizer # */
+  char data[4000];		/* Device spesific command/data record */
+} synth_control;
+
+typedef struct remove_sample
+{
+  int devno;			/* Synthesizer # */
+  int bankno;			/* MIDI bank # (0=General MIDI) */
+  int instrno;			/* MIDI instrument number */
+} remove_sample;
+
+typedef struct seq_event_rec
+{
+  unsigned char arr[8];
+} seq_event_rec;
+
+#define SNDCTL_TMR_TIMEBASE		__SIOWR('T', 1, int)
+#define SNDCTL_TMR_START		__SIO  ('T', 2)
+#define SNDCTL_TMR_STOP			__SIO  ('T', 3)
+#define SNDCTL_TMR_CONTINUE		__SIO  ('T', 4)
+#define SNDCTL_TMR_TEMPO		__SIOWR('T', 5, int)
+#define SNDCTL_TMR_SOURCE		__SIOWR('T', 6, int)
+#	define TMR_INTERNAL		0x00000001
+#	define TMR_EXTERNAL		0x00000002
+#		define TMR_MODE_MIDI	0x00000010
+#		define TMR_MODE_FSK	0x00000020
+#		define TMR_MODE_CLS	0x00000040
+#		define TMR_MODE_SMPTE	0x00000080
+#define SNDCTL_TMR_METRONOME		__SIOW ('T', 7, int)
+#define SNDCTL_TMR_SELECT		__SIOW ('T', 8, int)
+
+/*
+ * Sample loading mechanism for internal synthesizers (/dev/sequencer)
+ * (for the .PAT format).
+ */
+
+struct patch_info
+{
+  unsigned short key;		/* Use WAVE_PATCH here */
+#define WAVE_PATCH	_PATCHKEY(0x04)
+#define GUS_PATCH	WAVE_PATCH
+#define WAVEFRONT_PATCH _PATCHKEY(0x06)
+
+  short device_no;		/* Synthesizer number */
+  short instr_no;		/* Midi pgm# */
+
+  unsigned int mode;
+/*
+ * The least significant byte has the same format than the GUS .PAT
+ * files
+ */
+#define WAVE_16_BITS	0x01	/* bit 0 = 8 or 16 bit wave data. */
+#define WAVE_UNSIGNED	0x02	/* bit 1 = Signed - Unsigned data. */
+#define WAVE_LOOPING	0x04	/* bit 2 = looping enabled-1. */
+#define WAVE_BIDIR_LOOP	0x08	/* bit 3 = Set is bidirectional looping. */
+#define WAVE_LOOP_BACK	0x10	/* bit 4 = Set is looping backward. */
+#define WAVE_SUSTAIN_ON	0x20	/* bit 5 = Turn sustaining on. (Env. pts. 3) */
+#define WAVE_ENVELOPES	0x40	/* bit 6 = Enable envelopes - 1 */
+#define WAVE_FAST_RELEASE 0x80	/* bit 7 = Shut off immediately after note off */
+  /*  (use the env_rate/env_offs fields). */
+/* Linux specific bits */
+#define WAVE_VIBRATO	0x00010000	/* The vibrato info is valid */
+#define WAVE_TREMOLO	0x00020000	/* The tremolo info is valid */
+#define WAVE_SCALE	0x00040000	/* The scaling info is valid */
+#define WAVE_FRACTIONS	0x00080000	/* Fraction information is valid */
+/* Reserved bits */
+#define WAVE_ROM	0x40000000	/* For future use */
+#define WAVE_MULAW	0x20000000	/* For future use */
+/* Other bits must be zeroed */
+
+  int len;			/* Size of the wave data in bytes */
+  int loop_start, loop_end;	/* Byte offsets from the beginning */
+
+/* 
+ * The base_freq and base_note fields are used when computing the
+ * playback speed for a note. The base_note defines the tone frequency
+ * which is heard if the sample is played using the base_freq as the
+ * playback speed.
+ *
+ * The low_note and high_note fields define the minimum and maximum note
+ * frequencies for which this sample is valid. It is possible to define
+ * more than one samples for an instrument number at the same time. The
+ * low_note and high_note fields are used to select the most suitable one.
+ *
+ * The fields base_note, high_note and low_note should contain
+ * the note frequency multiplied by 1000. For example value for the
+ * middle A is 440*1000.
+ */
+
+  unsigned int base_freq;
+  unsigned int base_note;
+  unsigned int high_note;
+  unsigned int low_note;
+  int panning;			/* -128=left, 127=right */
+  int detuning;
+
+  /* Envelope. Enabled by mode bit WAVE_ENVELOPES  */
+  unsigned char env_rate[6];	/* GUS HW ramping rate */
+  unsigned char env_offset[6];	/* 255 == 100% */
+
+  /* 
+   * The tremolo, vibrato and scale info are not supported yet.
+   * Enable by setting the mode bits WAVE_TREMOLO, WAVE_VIBRATO or
+   * WAVE_SCALE
+   */
+
+  unsigned char tremolo_sweep;
+  unsigned char tremolo_rate;
+  unsigned char tremolo_depth;
+
+  unsigned char vibrato_sweep;
+  unsigned char vibrato_rate;
+  unsigned char vibrato_depth;
+
+  int scale_frequency;
+  unsigned int scale_factor;	/* from 0 to 2048 or 0 to 2 */
+
+  int volume;
+  int fractions;
+  int reserved1;
+  int spare[2];
+  char data[1];			/* The waveform data starts here */
+};
+
+struct sysex_info
+{
+  short key;			/* Use SYSEX_PATCH or MAUI_PATCH here */
+#define SYSEX_PATCH	_PATCHKEY(0x05)
+#define MAUI_PATCH	_PATCHKEY(0x06)
+  short device_no;		/* Synthesizer number */
+  int len;			/* Size of the sysex data in bytes */
+  unsigned char data[1];	/* Sysex data starts here */
+};
+
+/*
+ * /dev/sequencer input events.
+ *
+ * The data written to the /dev/sequencer is a stream of events. Events
+ * are records of 4 or 8 bytes. The first byte defines the size. 
+ * Any number of events can be written with a write call. There
+ * is a set of macros for sending these events. Use these macros if you
+ * want to maximize portability of your program.
+ *
+ * Events SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO. Are also input events.
+ * (All input events are currently 4 bytes long. Be prepared to support
+ * 8 byte events also. If you receive any event having first byte >= 128,
+ * it's a 8 byte event.
+ *
+ * The events are documented at the end of this file.
+ *
+ * Normal events (4 bytes)
+ * There is also a 8 byte version of most of the 4 byte events. The
+ * 8 byte one is recommended.
+ *
+ * NOTE! All 4 byte events are now obsolete. Applications should not write
+ *       them. However 4 byte events are still used as inputs from
+ *       /dev/sequencer (/dev/music uses only 8 byte ones).
+ */
+#define SEQ_NOTEOFF		0
+#define SEQ_FMNOTEOFF		SEQ_NOTEOFF	/* Just old name */
+#define SEQ_NOTEON		1
+#define	SEQ_FMNOTEON		SEQ_NOTEON
+#define SEQ_WAIT		TMR_WAIT_ABS
+#define SEQ_PGMCHANGE		3
+#define SEQ_FMPGMCHANGE		SEQ_PGMCHANGE
+#define SEQ_SYNCTIMER		TMR_START
+#define SEQ_MIDIPUTC		5
+#define SEQ_DRUMON		6		/*** OBSOLETE ***/
+#define SEQ_DRUMOFF		7		/*** OBSOLETE ***/
+#define SEQ_ECHO		TMR_ECHO	/* For synching programs with output */
+#define SEQ_AFTERTOUCH		9
+#define SEQ_CONTROLLER		10
+#define SEQ_BALANCE		11
+#define SEQ_VOLMODE             12
+
+/************************************
+ *	Midi controller numbers	    *
+ ************************************/
+/*
+ * Controllers 0 to 31 (0x00 to 0x1f) and
+ * 32 to 63 (0x20 to 0x3f) are continuous
+ * controllers.
+ * In the MIDI 1.0 these controllers are sent using
+ * two messages. Controller numbers 0 to 31 are used
+ * to send the MSB and the controller numbers 32 to 63
+ * are for the LSB. Note that just 7 bits are used in MIDI bytes.
+ */
+
+#define	   CTL_BANK_SELECT		0x00
+#define	   CTL_MODWHEEL			0x01
+#define    CTL_BREATH			0x02
+/*		undefined		0x03 */
+#define    CTL_FOOT			0x04
+#define    CTL_PORTAMENTO_TIME		0x05
+#define    CTL_DATA_ENTRY		0x06
+#define    CTL_MAIN_VOLUME		0x07
+#define    CTL_BALANCE			0x08
+/*		undefined		0x09 */
+#define    CTL_PAN			0x0a
+#define    CTL_EXPRESSION		0x0b
+/*		undefined		0x0c */
+/*		undefined		0x0d */
+/*		undefined		0x0e */
+/*		undefined		0x0f */
+#define    CTL_GENERAL_PURPOSE1		0x10
+#define    CTL_GENERAL_PURPOSE2		0x11
+#define    CTL_GENERAL_PURPOSE3		0x12
+#define    CTL_GENERAL_PURPOSE4		0x13
+/*		undefined		0x14 - 0x1f */
+
+/*		undefined		0x20 */
+/* The controller numbers 0x21 to 0x3f are reserved for the */
+/* least significant bytes of the controllers 0x00 to 0x1f. */
+/* These controllers are not recognised by the driver. */
+
+/* Controllers 64 to 69 (0x40 to 0x45) are on/off switches. */
+/* 0=OFF and 127=ON (intermediate values are possible) */
+#define    CTL_DAMPER_PEDAL		0x40
+#define    CTL_SUSTAIN			0x40	/* Alias */
+#define    CTL_HOLD			0x40	/* Alias */
+#define    CTL_PORTAMENTO		0x41
+#define    CTL_SOSTENUTO		0x42
+#define    CTL_SOFT_PEDAL		0x43
+/*		undefined		0x44 */
+#define    CTL_HOLD2			0x45
+/*		undefined		0x46 - 0x4f */
+
+#define    CTL_GENERAL_PURPOSE5		0x50
+#define    CTL_GENERAL_PURPOSE6		0x51
+#define    CTL_GENERAL_PURPOSE7		0x52
+#define    CTL_GENERAL_PURPOSE8		0x53
+/*		undefined		0x54 - 0x5a */
+#define    CTL_EXT_EFF_DEPTH		0x5b
+#define    CTL_TREMOLO_DEPTH		0x5c
+#define    CTL_CHORUS_DEPTH		0x5d
+#define    CTL_DETUNE_DEPTH		0x5e
+#define    CTL_CELESTE_DEPTH		0x5e	/* Alias for the above one */
+#define    CTL_PHASER_DEPTH		0x5f
+#define    CTL_DATA_INCREMENT		0x60
+#define    CTL_DATA_DECREMENT		0x61
+#define    CTL_NONREG_PARM_NUM_LSB	0x62
+#define    CTL_NONREG_PARM_NUM_MSB	0x63
+#define    CTL_REGIST_PARM_NUM_LSB	0x64
+#define    CTL_REGIST_PARM_NUM_MSB	0x65
+/*		undefined		0x66 - 0x78 */
+/*		reserved		0x79 - 0x7f */
+
+/* Pseudo controllers (not midi compatible) */
+#define    CTRL_PITCH_BENDER		255
+#define    CTRL_PITCH_BENDER_RANGE	254
+#define    CTRL_EXPRESSION		253	/* Obsolete */
+#define    CTRL_MAIN_VOLUME		252	/* Obsolete */
+
+/*
+ * Volume mode defines how volumes are used
+ */
+
+#define VOL_METHOD_ADAGIO	1
+#define VOL_METHOD_LINEAR	2
+
+/*
+ * Note! SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO are used also as
+ *	 input events.
+ */
+
+/*
+ * Event codes 0xf0 to 0xfc are reserved for future extensions.
+ */
+
+#define SEQ_FULLSIZE		0xfd	/* Long events */
+/*
+ * SEQ_FULLSIZE events are used for loading patches/samples to the
+ * synthesizer devices. These events are passed directly to the driver
+ * of the associated synthesizer device. There is no limit to the size
+ * of the extended events. These events are not queued but executed
+ * immediately when the write() is called (execution can take several
+ * seconds of time). 
+ *
+ * When a SEQ_FULLSIZE message is written to the device, it must
+ * be written using exactly one write() call. Other events cannot
+ * be mixed to the same write.
+ *	
+ * For FM synths (YM3812/OPL3) use struct sbi_instrument and write it to the 
+ * /dev/sequencer. Don't write other data together with the instrument structure
+ * Set the key field of the structure to FM_PATCH. The device field is used to
+ * route the patch to the corresponding device.
+ *
+ * For wave table use struct patch_info. Initialize the key field
+ * to WAVE_PATCH.
+ */
+#define SEQ_PRIVATE		0xfe	/* Low level HW dependent events (8 bytes) */
+#define SEQ_EXTENDED		0xff	/* Extended events (8 bytes) OBSOLETE */
+
+/*
+ * Record for FM patches
+ */
+
+typedef unsigned char sbi_instr_data[32];
+
+struct sbi_instrument
+{
+  unsigned short key;		/* FM_PATCH or OPL3_PATCH */
+#define FM_PATCH	_PATCHKEY(0x01)
+#define OPL3_PATCH	_PATCHKEY(0x03)
+  short device;			/*  Synth# (0-4)    */
+  int channel;			/*  Program# to be initialized  */
+  sbi_instr_data operators;	/*  Register settings for operator cells (.SBI format)  */
+};
+
+struct synth_info
+{				/* Read only */
+  char name[30];
+  int device;			/* 0-N. INITIALIZE BEFORE CALLING */
+  int synth_type;
+#define SYNTH_TYPE_FM			0
+#define SYNTH_TYPE_SAMPLE		1
+#define SYNTH_TYPE_MIDI			2	/* Midi interface */
+
+  int synth_subtype;
+#define FM_TYPE_ADLIB			0x00
+#define FM_TYPE_OPL3			0x01
+#define MIDI_TYPE_MPU401		0x401
+
+#define SAMPLE_TYPE_BASIC		0x10
+#define SAMPLE_TYPE_GUS			SAMPLE_TYPE_BASIC
+#define SAMPLE_TYPE_WAVEFRONT   	0x11
+
+  int perc_mode;		/* No longer supported */
+  int nr_voices;
+  int nr_drums;			/* Obsolete field */
+  int instr_bank_size;
+  unsigned int capabilities;
+#define SYNTH_CAP_PERCMODE	0x00000001	/* No longer used */
+#define SYNTH_CAP_OPL3		0x00000002	/* Set if OPL3 supported */
+#define SYNTH_CAP_INPUT		0x00000004	/* Input (MIDI) device */
+  int dummies[19];		/* Reserve space */
+};
+
+struct sound_timer_info
+{
+  char name[32];
+  int caps;
+};
+
+struct midi_info		/* OBSOLETE */
+{
+  char name[30];
+  int device;			/* 0-N. INITIALIZE BEFORE CALLING */
+  unsigned int capabilities;	/* To be defined later */
+  int dev_type;
+  int dummies[18];		/* Reserve space */
+};
+
+/*
+ * Level 2 event types for /dev/sequencer
+ */
+
+/*
+ * The 4 most significant bits of byte 0 specify the class of
+ * the event: 
+ *
+ *	0x8X = system level events,
+ *	0x9X = device/port specific events, event[1] = device/port,
+ *		The last 4 bits give the subtype:
+ *			0x02	= Channel event (event[3] = chn).
+ *			0x01	= note event (event[4] = note).
+ *			(0x01 is not used alone but always with bit 0x02).
+ *	       event[2] = MIDI message code (0x80=note off etc.)
+ *
+ */
+
+#define EV_SEQ_LOCAL		0x80
+#define EV_TIMING		0x81
+#define EV_CHN_COMMON		0x92
+#define EV_CHN_VOICE		0x93
+#define EV_SYSEX		0x94
+#define EV_SYSTEM		0x95	/* MIDI system and real time messages (input only) */
+/*
+ * Event types 200 to 220 are reserved for application use.
+ * These numbers will not be used by the driver.
+ */
+
+/*
+ * Events for event type EV_CHN_VOICE
+ */
+
+#define MIDI_NOTEOFF		0x80
+#define MIDI_NOTEON		0x90
+#define MIDI_KEY_PRESSURE	0xA0
+
+/*
+ * Events for event type EV_CHN_COMMON
+ */
+
+#define MIDI_CTL_CHANGE		0xB0
+#define MIDI_PGM_CHANGE		0xC0
+#define MIDI_CHN_PRESSURE	0xD0
+#define MIDI_PITCH_BEND		0xE0
+
+#define MIDI_SYSTEM_PREFIX	0xF0
+
+/*
+ * Timer event types
+ */
+#define TMR_WAIT_REL		1	/* Time relative to the prev time */
+#define TMR_WAIT_ABS		2	/* Absolute time since TMR_START */
+#define TMR_STOP		3
+#define TMR_START		4
+#define TMR_CONTINUE		5
+#define TMR_TEMPO		6
+#define TMR_ECHO		8
+#define TMR_CLOCK		9	/* MIDI clock */
+#define TMR_SPP			10	/* Song position pointer */
+#define TMR_TIMESIG		11	/* Time signature */
+
+/*
+ *	Local event types
+ */
+#define LOCL_STARTAUDIO		1
+#define LOCL_STARTAUDIO2	2
+#define LOCL_STARTAUDIO3	3
+#define LOCL_STARTAUDIO4	4
+
+#if (!defined(__KERNEL__) && !defined(KERNEL) && !defined(INKERNEL) && !defined(_KERNEL)) || defined(USE_SEQ_MACROS)
+/*
+ * Some convenience macros to simplify programming of the
+ * /dev/sequencer interface
+ *
+ * These macros define the API which should be used when possible.
+ */
+#define SEQ_DECLAREBUF()		SEQ_USE_EXTBUF()
+
+void seqbuf_dump (void);	/* This function must be provided by programs */
+
+EXTERNC int OSS_init (int seqfd, int buflen);
+EXTERNC void OSS_seqbuf_dump (int fd, unsigned char *buf, int buflen);
+EXTERNC void OSS_seq_advbuf (int len, int fd, unsigned char *buf, int buflen);
+EXTERNC void OSS_seq_needbuf (int len, int fd, unsigned char *buf,
+			      int buflen);
+EXTERNC void OSS_patch_caching (int dev, int chn, int patch, int fd,
+				unsigned char *buf, int buflen);
+EXTERNC void OSS_drum_caching (int dev, int chn, int patch, int fd,
+			       unsigned char *buf, int buflen);
+EXTERNC void OSS_write_patch (int fd, unsigned char *buf, int len);
+EXTERNC int OSS_write_patch2 (int fd, unsigned char *buf, int len);
+
+#define SEQ_PM_DEFINES int __foo_bar___
+#ifdef OSSLIB
+#  define SEQ_USE_EXTBUF() \
+		EXTERNC unsigned char *_seqbuf; \
+		EXTERNC int _seqbuflen;EXTERNC int _seqbufptr
+#  define SEQ_DEFINEBUF(len) SEQ_USE_EXTBUF();static int _requested_seqbuflen=len
+#  define _SEQ_ADVBUF(len) OSS_seq_advbuf(len, seqfd, _seqbuf, _seqbuflen)
+#  define _SEQ_NEEDBUF(len) OSS_seq_needbuf(len, seqfd, _seqbuf, _seqbuflen)
+#  define SEQ_DUMPBUF() OSS_seqbuf_dump(seqfd, _seqbuf, _seqbuflen)
+
+#  define SEQ_LOAD_GMINSTR(dev, instr) \
+		OSS_patch_caching(dev, -1, instr, seqfd, _seqbuf, _seqbuflen)
+#  define SEQ_LOAD_GMDRUM(dev, drum) \
+		OSS_drum_caching(dev, -1, drum, seqfd, _seqbuf, _seqbuflen)
+#else /* !OSSLIB */
+
+#  define SEQ_LOAD_GMINSTR(dev, instr)
+#  define SEQ_LOAD_GMDRUM(dev, drum)
+
+#  define SEQ_USE_EXTBUF() \
+		EXTERNC unsigned char _seqbuf[]; \
+		EXTERNC int _seqbuflen;EXTERNC int _seqbufptr
+
+#ifndef USE_SIMPLE_MACROS
+/* Sample seqbuf_dump() implementation:
+ *
+ *	SEQ_DEFINEBUF (2048);	-- Defines a buffer for 2048 bytes
+ *
+ *	int seqfd;		-- The file descriptor for /dev/sequencer.
+ *
+ *	void
+ *	seqbuf_dump ()
+ *	{
+ *	  if (_seqbufptr)
+ *	    if (write (seqfd, _seqbuf, _seqbufptr) == -1)
+ *	      {
+ *		perror ("write /dev/sequencer");
+ *		exit (-1);
+ *	      }
+ *	  _seqbufptr = 0;
+ *	}
+ */
+
+#define SEQ_DEFINEBUF(len) \
+	unsigned char _seqbuf[len]; int _seqbuflen = len;int _seqbufptr = 0
+#define _SEQ_NEEDBUF(len) \
+	if ((_seqbufptr+(len)) > _seqbuflen) seqbuf_dump()
+#define _SEQ_ADVBUF(len) _seqbufptr += len
+#define SEQ_DUMPBUF seqbuf_dump
+#else
+/*
+ * This variation of the sequencer macros is used just to format one event
+ * using fixed buffer.
+ * 
+ * The program using the macro library must define the following macros before
+ * using this library.
+ *
+ * #define _seqbuf 		 name of the buffer (unsigned char[]) 
+ * #define _SEQ_ADVBUF(len)	 If the applic needs to know the exact
+ *				 size of the event, this macro can be used.
+ *				 Otherwise this must be defined as empty.
+ * #define _seqbufptr		 Define the name of index variable or 0 if
+ *				 not required. 
+ */
+#define _SEQ_NEEDBUF(len)	/* empty */
+#endif
+#endif /* !OSSLIB */
+
+#define SEQ_VOLUME_MODE(dev, mode) \
+				{_SEQ_NEEDBUF(8);\
+				_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+				_seqbuf[_seqbufptr+1] = SEQ_VOLMODE;\
+				_seqbuf[_seqbufptr+2] = (dev);\
+				_seqbuf[_seqbufptr+3] = (mode);\
+				_seqbuf[_seqbufptr+4] = 0;\
+				_seqbuf[_seqbufptr+5] = 0;\
+				_seqbuf[_seqbufptr+6] = 0;\
+				_seqbuf[_seqbufptr+7] = 0;\
+				_SEQ_ADVBUF(8);}
+
+/*
+ * Midi voice messages
+ */
+
+#define _CHN_VOICE(dev, event, chn, note, parm) \
+				{_SEQ_NEEDBUF(8);\
+				_seqbuf[_seqbufptr] = EV_CHN_VOICE;\
+				_seqbuf[_seqbufptr+1] = (dev);\
+				_seqbuf[_seqbufptr+2] = (event);\
+				_seqbuf[_seqbufptr+3] = (chn);\
+				_seqbuf[_seqbufptr+4] = (note);\
+				_seqbuf[_seqbufptr+5] = (parm);\
+				_seqbuf[_seqbufptr+6] = (0);\
+				_seqbuf[_seqbufptr+7] = 0;\
+				_SEQ_ADVBUF(8);}
+
+#define SEQ_START_NOTE(dev, chn, note, vol) \
+			_CHN_VOICE(dev, MIDI_NOTEON, chn, note, vol)
+
+#define SEQ_STOP_NOTE(dev, chn, note, vol) \
+			_CHN_VOICE(dev, MIDI_NOTEOFF, chn, note, vol)
+
+#define SEQ_KEY_PRESSURE(dev, chn, note, pressure) \
+			_CHN_VOICE(dev, MIDI_KEY_PRESSURE, chn, note, pressure)
+
+/*
+ * Midi channel messages
+ */
+
+#define _CHN_COMMON(dev, event, chn, p1, p2, w14) \
+				{_SEQ_NEEDBUF(8);\
+				_seqbuf[_seqbufptr] = EV_CHN_COMMON;\
+				_seqbuf[_seqbufptr+1] = (dev);\
+				_seqbuf[_seqbufptr+2] = (event);\
+				_seqbuf[_seqbufptr+3] = (chn);\
+				_seqbuf[_seqbufptr+4] = (p1);\
+				_seqbuf[_seqbufptr+5] = (p2);\
+				*(short *)&_seqbuf[_seqbufptr+6] = (w14);\
+				_SEQ_ADVBUF(8);}
+/*
+ * SEQ_SYSEX permits sending of sysex messages. (It may look that it permits
+ * sending any MIDI bytes but it's absolutely not possible. Trying to do
+ * so _will_ cause problems with MPU401 intelligent mode).
+ *
+ * Sysex messages are sent in blocks of 1 to 6 bytes. Longer messages must be 
+ * sent by calling SEQ_SYSEX() several times (there must be no other events
+ * between them). First sysex fragment must have 0xf0 in the first byte
+ * and the last byte (buf[len-1] of the last fragment must be 0xf7. No byte
+ * between these sysex start and end markers cannot be larger than 0x7f. Also
+ * lengths of each fragments (except the last one) must be 6.
+ *
+ * Breaking the above rules may work with some MIDI ports but is likely to
+ * cause fatal problems with some other devices (such as MPU401).
+ */
+#define SEQ_SYSEX(dev, buf, len) \
+				{int ii, ll=(len); \
+				 unsigned char *bufp=buf;\
+				 if (ll>6)ll=6;\
+				_SEQ_NEEDBUF(8);\
+				_seqbuf[_seqbufptr] = EV_SYSEX;\
+				_seqbuf[_seqbufptr+1] = (dev);\
+				for(ii=0;ii<ll;ii++)\
+				   _seqbuf[_seqbufptr+ii+2] = bufp[ii];\
+				for(ii=ll;ii<6;ii++)\
+				   _seqbuf[_seqbufptr+ii+2] = 0xff;\
+				_SEQ_ADVBUF(8);}
+
+#define SEQ_CHN_PRESSURE(dev, chn, pressure) \
+		_CHN_COMMON(dev, MIDI_CHN_PRESSURE, chn, pressure, 0, 0)
+
+#define SEQ_SET_PATCH SEQ_PGM_CHANGE
+#ifdef OSSLIB
+#   define SEQ_PGM_CHANGE(dev, chn, patch) \
+		{OSS_patch_caching(dev, chn, patch, seqfd, _seqbuf, _seqbuflen); \
+		 _CHN_COMMON(dev, MIDI_PGM_CHANGE, chn, patch, 0, 0);}
+#else
+#   define SEQ_PGM_CHANGE(dev, chn, patch) \
+		_CHN_COMMON(dev, MIDI_PGM_CHANGE, chn, patch, 0, 0)
+#endif
+
+#define SEQ_CONTROL(dev, chn, controller, value) \
+		_CHN_COMMON(dev, MIDI_CTL_CHANGE, chn, controller, 0, value)
+
+#define SEQ_BENDER(dev, chn, value) \
+		_CHN_COMMON(dev, MIDI_PITCH_BEND, chn, 0, 0, value)
+
+#define SEQ_V2_X_CONTROL(dev, voice, controller, value)	\
+				{_SEQ_NEEDBUF(8);\
+				_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+				_seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\
+				_seqbuf[_seqbufptr+2] = (dev);\
+				_seqbuf[_seqbufptr+3] = (voice);\
+				_seqbuf[_seqbufptr+4] = (controller);\
+				_seqbuf[_seqbufptr+5] = ((value)&0xff);\
+				_seqbuf[_seqbufptr+6] = ((value>>8)&0xff);\
+				_seqbuf[_seqbufptr+7] = 0;\
+				_SEQ_ADVBUF(8);}
+/*
+ * The following 5 macros are incorrectly implemented and obsolete.
+ * Use SEQ_BENDER and SEQ_CONTROL (with proper controller) instead.
+ */
+#define SEQ_PITCHBEND(dev, voice, value) \
+	SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER, value)
+#define SEQ_BENDER_RANGE(dev, voice, value) \
+	SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value)
+#define SEQ_EXPRESSION(dev, voice, value) \
+	SEQ_CONTROL(dev, voice, CTL_EXPRESSION, value*128)
+#define SEQ_MAIN_VOLUME(dev, voice, value) \
+	SEQ_CONTROL(dev, voice, CTL_MAIN_VOLUME, (value*16383)/100)
+#define SEQ_PANNING(dev, voice, pos) \
+	SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2)
+
+/*
+ * Timing and syncronization macros
+ */
+
+#define _TIMER_EVENT(ev, parm)	{_SEQ_NEEDBUF(8);\
+			 	_seqbuf[_seqbufptr+0] = EV_TIMING; \
+			 	_seqbuf[_seqbufptr+1] = (ev); \
+				_seqbuf[_seqbufptr+2] = 0;\
+				_seqbuf[_seqbufptr+3] = 0;\
+			 	*(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \
+				_SEQ_ADVBUF(8);}
+
+#define SEQ_START_TIMER()		_TIMER_EVENT(TMR_START, 0)
+#define SEQ_STOP_TIMER()		_TIMER_EVENT(TMR_STOP, 0)
+#define SEQ_CONTINUE_TIMER()		_TIMER_EVENT(TMR_CONTINUE, 0)
+#define SEQ_WAIT_TIME(ticks)		_TIMER_EVENT(TMR_WAIT_ABS, ticks)
+#define SEQ_DELTA_TIME(ticks)		_TIMER_EVENT(TMR_WAIT_REL, ticks)
+#define SEQ_ECHO_BACK(key)		_TIMER_EVENT(TMR_ECHO, key)
+#define SEQ_SET_TEMPO(value)		_TIMER_EVENT(TMR_TEMPO, value)
+#define SEQ_SONGPOS(pos)		_TIMER_EVENT(TMR_SPP, pos)
+#define SEQ_TIME_SIGNATURE(sig)		_TIMER_EVENT(TMR_TIMESIG, sig)
+
+/*
+ * Local control events
+ */
+
+#define _LOCAL_EVENT(ev, parm)		{_SEQ_NEEDBUF(8);\
+				 	_seqbuf[_seqbufptr+0] = EV_SEQ_LOCAL; \
+				 	_seqbuf[_seqbufptr+1] = (ev); \
+					_seqbuf[_seqbufptr+2] = 0;\
+					_seqbuf[_seqbufptr+3] = 0;\
+				 	*(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \
+					_SEQ_ADVBUF(8);}
+
+#define SEQ_PLAYAUDIO(devmask)		_LOCAL_EVENT(LOCL_STARTAUDIO, devmask)
+#define SEQ_PLAYAUDIO2(devmask)		_LOCAL_EVENT(LOCL_STARTAUDIO2, devmask)
+#define SEQ_PLAYAUDIO3(devmask)		_LOCAL_EVENT(LOCL_STARTAUDIO3, devmask)
+#define SEQ_PLAYAUDIO4(devmask)		_LOCAL_EVENT(LOCL_STARTAUDIO4, devmask)
+/*
+ * Events for the level 1 interface only 
+ */
+
+#define SEQ_MIDIOUT(device, byte)	{_SEQ_NEEDBUF(4);\
+					_seqbuf[_seqbufptr] = SEQ_MIDIPUTC;\
+					_seqbuf[_seqbufptr+1] = (byte);\
+					_seqbuf[_seqbufptr+2] = (device);\
+					_seqbuf[_seqbufptr+3] = 0;\
+					_SEQ_ADVBUF(4);}
+
+/*
+ * Patch loading.
+ */
+#ifdef OSSLIB
+#   define SEQ_WRPATCH(patchx, len) \
+		OSS_write_patch(seqfd, (char*)(patchx), len)
+#   define SEQ_WRPATCH2(patchx, len) \
+		OSS_write_patch2(seqfd, (char*)(patchx), len)
+#else
+#   define SEQ_WRPATCH(patchx, len) \
+		{if (_seqbufptr) SEQ_DUMPBUF();\
+		 if (write(seqfd, (char*)(patchx), len)==-1) \
+		    perror("Write patch: /dev/sequencer");}
+#   define SEQ_WRPATCH2(patchx, len) \
+		(SEQ_DUMPBUF(), write(seqfd, (char*)(patchx), len))
+#endif
+
+#endif
+#endif /* ifndef DISABLE_SEQUENCER */
+
+/*
+ ****************************************************************************
+ * ioctl commands for the /dev/midi## 
+ ****************************************************************************/
+#define SNDCTL_MIDI_PRETIME	__SIOWR('m', 0, int)
+
+#if 0
+/*
+ * The SNDCTL_MIDI_MPUMODE and SNDCTL_MIDI_MPUCMD calls
+ * are completely obsolete. The hardware device (MPU-401 "intelligent mode"
+ * and compatibles) has disappeared from the market 10 years ago so there 
+ * is no need for this stuff. The MPU-401 "UART" mode devices don't support
+ * this stuff.
+ */
+typedef struct
+{
+  unsigned char cmd;
+  char nr_args, nr_returns;
+  unsigned char data[30];
+} mpu_command_rec;
+
+#define SNDCTL_MIDI_MPUMODE	__SIOWR('m', 1, int)
+#define SNDCTL_MIDI_MPUCMD	__SIOWR('m', 2, mpu_command_rec)
+#endif
+
+/*
+ * SNDCTL_MIDI_MTCINPUT turns on a mode where OSS automatically inserts
+ * MTC quarter frame messages (F1 xx) to the input.
+ * The argument is the MTC mode:
+ *
+ * 	-1 = Turn MTC messages OFF (default)
+ *	24 = 24 FPS 
+ *	25 = 25 FPS 
+ *	29 = 30 FPS drop frame
+ *	30 = 30 FPS 
+ *
+ * Note that 25 FPS mode is probably the only mode that is supported. Other
+ * modes may be supported in the future versions of OSS, 25 FPS is handy 
+ * because it generates 25*4=100 quarter frame messages per second which
+ * matches the usual 100 HZ system timer rate).
+ *
+ * The quarter frame timer will be reset to 0:00:00:00.0 at the moment this
+ * ioctl is made.
+ */
+#define SNDCTL_MIDI_MTCINPUT	__SIOWR('m', 3, int)
+
+/*
+ * MTC/SMPTE time code record (for future use)
+ */
+typedef struct
+{
+  unsigned char hours, minutes, seconds, frames, qframes;
+  char direction;
+#define MTC_DIR_STOPPED		 0
+#define MTC_DIR_FORWARD		 1
+#define MTC_DIR_BACKWARD	-1
+  unsigned char time_code_type;
+  unsigned int flags;
+} oss_mtc_data_t;
+
+#define SNDCTL_MIDI_SETMODE	__SIOWR('m', 6, int)
+#	define MIDI_MODE_TRADITIONAL	0
+#	define MIDI_MODE_TIMED		1	/* Input times are in MIDI ticks */
+#	define MIDI_MODE_TIMED_ABS  	2	/* Input times are absolute (usecs) */
+
+/*
+ * Packet header for MIDI_MODE_TIMED and MIDI_MODE_TIMED_ABS
+ */
+typedef unsigned long long oss_midi_time_t;	/* Variable type for MIDI time (clock ticks) */
+
+typedef struct
+{
+  int magic;			/* Initialize to MIDI_HDR_MAGIC */
+#define MIDI_HDR_MAGIC	-1
+  unsigned short event_type;
+#define MIDI_EV_WRITE			0	/* Write or read (with payload) */
+#define MIDI_EV_TEMPO			1
+#define MIDI_EV_ECHO			2
+#define MIDI_EV_START			3
+#define MIDI_EV_STOP			4
+#define MIDI_EV_CONTINUE		5
+#define MIDI_EV_XPRESSWRITE		6
+#define MIDI_EV_TIMEBASE		7
+#define MIDI_EV_DEVCTL			8	/* Device control read/write */
+  unsigned short options;
+#define MIDI_OPT_NONE			0x0000
+#define MIDI_OPT_TIMED			0x0001
+#define MIDI_OPT_CONTINUATION		0x0002
+#define MIDI_OPT_USECTIME		0x0004	/* Time is absolute (in usecs) */
+#define MIDI_OPT_BUSY			0x0008	/* Reserved for internal use */
+  oss_midi_time_t time;
+  int parm;
+  int filler[3];		/* Fur future expansion - init to zeros */
+} midi_packet_header_t;
+/* 
+ * MIDI_PAYLOAD_SIZE is the maximum size of one MIDI input chunk. It must be
+ * less (or equal) than 1024 which is the read size recommended in the 
+ * documentation. TODO: Explain this better.
+ */
+#define MIDI_PAYLOAD_SIZE		1000
+
+typedef struct
+{
+  midi_packet_header_t hdr;
+  unsigned char payload[MIDI_PAYLOAD_SIZE];
+} midi_packet_t;
+
+#define SNDCTL_MIDI_TIMEBASE		__SIOWR('m', 7, int)
+#define SNDCTL_MIDI_TEMPO		__SIOWR('m', 8, int)
+/*
+ * User land MIDI servers (synths) can use SNDCTL_MIDI_SET_LATENCY
+ * to request MIDI events to be sent to them in advance. The parameter
+ * (in microseconds) tells how much before the events are submitted.
+ *
+ * This feature is only valid for loopback devices and possibly some other
+ * types of virtual devices.
+ */
+#define SNDCTL_MIDI_SET_LATENCY		__SIOW ('m', 9, int)
+/*
+ ****************************************************************************
+ * IOCTL commands for /dev/dsp
+ ****************************************************************************/
+
+#define SNDCTL_DSP_HALT			__SIO  ('P', 0)
+#define SNDCTL_DSP_RESET		SNDCTL_DSP_HALT	/* Old name */
+#define SNDCTL_DSP_SYNC			__SIO  ('P', 1)
+#define SNDCTL_DSP_SPEED		__SIOWR('P', 2, int)
+
+/* SNDCTL_DSP_STEREO is obsolete - use SNDCTL_DSP_CHANNELS instead */
+#define SNDCTL_DSP_STEREO		__SIOWR('P', 3, int)
+/* SNDCTL_DSP_STEREO is obsolete - use SNDCTL_DSP_CHANNELS instead */
+
+#define SNDCTL_DSP_GETBLKSIZE		__SIOWR('P', 4, int)
+#define SNDCTL_DSP_SAMPLESIZE		SNDCTL_DSP_SETFMT
+#define SNDCTL_DSP_CHANNELS		__SIOWR('P', 6, int)
+#define SNDCTL_DSP_POST			__SIO  ('P', 8)
+#define SNDCTL_DSP_SUBDIVIDE		__SIOWR('P', 9, int)
+#define SNDCTL_DSP_SETFRAGMENT		__SIOWR('P',10, int)
+
+/* Audio data formats (Note! U8=8 and S16_LE=16 for compatibility) */
+#define SNDCTL_DSP_GETFMTS		__SIOR ('P',11, int)	/* Returns a mask */
+#define SNDCTL_DSP_SETFMT		__SIOWR('P',5, int)	/* Selects ONE fmt */
+#	define AFMT_QUERY	0x00000000	/* Return current fmt */
+#	define AFMT_MU_LAW	0x00000001
+#	define AFMT_A_LAW	0x00000002
+#	define AFMT_IMA_ADPCM	0x00000004
+#	define AFMT_U8		0x00000008
+#	define AFMT_S16_LE	0x00000010	/* Little endian signed 16 */
+#	define AFMT_S16_BE	0x00000020	/* Big endian signed 16 */
+#	define AFMT_S8		0x00000040
+#	define AFMT_U16_LE	0x00000080	/* Little endian U16 */
+#	define AFMT_U16_BE	0x00000100	/* Big endian U16 */
+#	define AFMT_MPEG	0x00000200	/* MPEG (2) audio */
+
+/* AC3 _compressed_ bitstreams (See Programmer's Guide for details). */
+#	define AFMT_AC3		0x00000400
+/* Ogg Vorbis _compressed_ bit streams */
+#	define AFMT_VORBIS	0x00000800
+
+/* 32 bit formats (MSB aligned) formats */
+#	define AFMT_S32_LE	0x00001000
+#	define AFMT_S32_BE	0x00002000
+
+/* Reserved for _native_ endian double precision IEEE floating point */
+#	define AFMT_FLOAT	0x00004000
+
+/* 24 bit formats (LSB aligned in 32 bit word) formats */
+#	define AFMT_S24_LE	0x00008000
+#	define AFMT_S24_BE	0x00010000
+
+/*
+ * S/PDIF raw format. In this format the S/PDIF frames (including all
+ * control and user bits) are included in the data stream. Each sample
+ * is stored in a 32 bit frame (see IEC-958 for more info). This format
+ * is supported by very few devices and it's only usable for purposes
+ * where full access to the control/user bits is required (real time control).
+ */
+#	define AFMT_SPDIF_RAW	0x00020000
+
+/* 24 bit packed (3 byte) little endian format (USB compatibility) */
+#	define AFMT_S24_PACKED	0x00040000
+
+
+/*
+ * Some big endian/little endian handling macros (native endian and opposite
+ * endian formats). The usage of these macros is described in the OSS
+ * Programmer's Manual.
+ */
+
+#if defined(_AIX) || defined(AIX) || defined(sparc) || defined(__hppa) || defined(PPC) || defined(__powerpc__) && !defined(i386) && !defined(__i386) && !defined(__i386__)
+
+/* Big endian machines */
+#  define _PATCHKEY(id) (0xfd00|id)
+#  define AFMT_S16_NE AFMT_S16_BE
+#  define AFMT_U16_NE AFMT_U16_BE
+#  define AFMT_S32_NE AFMT_S32_BE
+#  define AFMT_S24_NE AFMT_S24_BE
+#  define AFMT_S16_OE AFMT_S16_LE
+#  define AFMT_S32_OE AFMT_S32_LE
+#  define AFMT_S24_OE AFMT_S24_LE
+#else
+#  define _PATCHKEY(id) ((id<<8)|0xfd)
+#  define AFMT_S16_NE AFMT_S16_LE
+#  define AFMT_U16_NE AFMT_U16_LE
+#  define AFMT_S32_NE AFMT_S32_LE
+#  define AFMT_S24_NE AFMT_S24_LE
+#  define AFMT_S16_OE AFMT_S16_BE
+#  define AFMT_S32_OE AFMT_S32_BE
+#  define AFMT_S24_OE AFMT_S24_BE
+#endif
+/*
+ * Buffer status queries.
+ */
+typedef struct audio_buf_info
+{
+  int fragments;		/* # of available fragments (partially usend ones not counted) */
+  int fragstotal;		/* Total # of fragments allocated */
+  int fragsize;			/* Size of a fragment in bytes */
+  int bytes;			/* Available space in bytes (includes partially used fragments) */
+  /* Note! 'bytes' could be more than fragments*fragsize */
+} audio_buf_info;
+
+#define SNDCTL_DSP_GETOSPACE		__SIOR ('P',12, audio_buf_info)
+#define SNDCTL_DSP_GETISPACE		__SIOR ('P',13, audio_buf_info)
+#define SNDCTL_DSP_GETCAPS		__SIOR ('P',15, int)
+#	define PCM_CAP_REVISION		0x000000ff	/* Bits for revision level (0 to 255) */
+#	define PCM_CAP_DUPLEX		0x00000100	/* Full duplex record/playback */
+#	define PCM_CAP_REALTIME		0x00000200	/* Not in use */
+#	define PCM_CAP_BATCH		0x00000400	/* Device has some kind of */
+							/* internal buffers which may */
+							/* cause some delays and */
+							/* decrease precision of timing */
+#	define PCM_CAP_COPROC		0x00000800	/* Has a coprocessor */
+							/* Sometimes it's a DSP */
+							/* but usually not */
+#	define PCM_CAP_TRIGGER		0x00001000	/* Supports SETTRIGGER */
+#	define PCM_CAP_MMAP		0x00002000	/* Supports mmap() */
+#	define PCM_CAP_MULTI		0x00004000	/* Supports multiple open */
+#	define PCM_CAP_BIND		0x00008000	/* Supports binding to front/rear/center/lfe */
+#   	define PCM_CAP_INPUT		0x00010000	/* Supports recording */
+#   	define PCM_CAP_OUTPUT		0x00020000	/* Supports playback */
+#	define PCM_CAP_VIRTUAL		0x00040000	/* Virtual device */
+/* 0x00040000 and 0x00080000 reserved for future use */
+
+/* Analog/digital control capabilities */
+#	define PCM_CAP_ANALOGOUT	0x00100000
+#	define PCM_CAP_ANALOGIN		0x00200000
+#	define PCM_CAP_DIGITALOUT	0x00400000
+#	define PCM_CAP_DIGITALIN	0x00800000
+#	define PCM_CAP_ADMASK		0x00f00000
+/*
+ * NOTE! (capabilities & PCM_CAP_ADMASK)==0 means just that the
+ * digital/analog interface control features are not supported by the 
+ * device/driver. However the device still supports analog, digital or
+ * both inputs/outputs (depending on the device). See the OSS Programmer's
+ * Guide for full details.
+ */
+#	define PCM_CAP_SHADOW		0x01000000	/* "Shadow" device */
+
+/*
+ * Preferred channel usage. These bits can be used to
+ * give recommendations to the application. Used by few drivers.
+ * For example if ((caps & DSP_CH_MASK) == DSP_CH_MONO) means that
+ * the device works best in mono mode. However it doesn't necessarily mean
+ * that the device cannot be used in stereo. These bits should only be used
+ * by special applications such as multi track hard disk recorders to find
+ * out the initial setup. However the user should be able to override this
+ * selection.
+ *
+ * To find out which modes are actually supported the application should 
+ * try to select them using SNDCTL_DSP_CHANNELS.
+ */
+#	define DSP_CH_MASK		0x06000000	/* Mask */
+#	define DSP_CH_ANY		0x00000000	/* No preferred mode */
+#	define DSP_CH_MONO		0x02000000
+#	define DSP_CH_STEREO		0x04000000
+#	define DSP_CH_MULTI		0x06000000	/* More than two channels */
+
+#	define PCM_CAP_HIDDEN		0x08000000	/* Hidden device */
+#	define PCM_CAP_FREERATE		0x10000000
+#	define PCM_CAP_MODEM		0x20000000	/* Modem device */
+#	define PCM_CAP_DEFAULT		0x40000000	/* "Default" device */
+
+/*
+ * The PCM_CAP_* capability names were known as DSP_CAP_* prior OSS 4.0
+ * so it's necessary to define the older names too.
+ */
+#define DSP_CAP_ADMASK		PCM_CAP_ADMASK
+#define DSP_CAP_ANALOGIN	PCM_CAP_ANALOGIN
+#define DSP_CAP_ANALOGOUT	PCM_CAP_ANALOGOUT
+#define DSP_CAP_BATCH		PCM_CAP_BATCH
+#define DSP_CAP_BIND		PCM_CAP_BIND
+#define DSP_CAP_COPROC		PCM_CAP_COPROC
+#define DSP_CAP_DEFAULT		PCM_CAP_DEFAULT
+#define DSP_CAP_DIGITALIN	PCM_CAP_DIGITALIN
+#define DSP_CAP_DIGITALOUT	PCM_CAP_DIGITALOUT
+#define DSP_CAP_DUPLEX		PCM_CAP_DUPLEX
+#define DSP_CAP_FREERATE	PCM_CAP_FREERATE
+#define DSP_CAP_HIDDEN		PCM_CAP_HIDDEN
+#define DSP_CAP_INPUT		PCM_CAP_INPUT
+#define DSP_CAP_MMAP		PCM_CAP_MMAP
+#define DSP_CAP_MODEM		PCM_CAP_MODEM
+#define DSP_CAP_MULTI		PCM_CAP_MULTI
+#define DSP_CAP_OUTPUT		PCM_CAP_OUTPUT
+#define DSP_CAP_REALTIME	PCM_CAP_REALTIME
+#define DSP_CAP_REVISION	PCM_CAP_REVISION
+#define DSP_CAP_SHADOW		PCM_CAP_SHADOW
+#define DSP_CAP_TRIGGER		PCM_CAP_TRIGGER
+#define DSP_CAP_VIRTUAL		PCM_CAP_VIRTUAL
+
+#define SNDCTL_DSP_GETTRIGGER		__SIOR ('P',16, int)
+#define SNDCTL_DSP_SETTRIGGER		__SIOW ('P',16, int)
+#	define PCM_ENABLE_INPUT		0x00000001
+#	define PCM_ENABLE_OUTPUT	0x00000002
+
+typedef struct count_info
+{
+  unsigned int bytes;		/* Total # of bytes processed */
+  int blocks;			/* # of fragment transitions since last time */
+  int ptr;			/* Current DMA pointer value */
+} count_info;
+
+#define SNDCTL_DSP_GETIPTR		__SIOR ('P',17, count_info)
+#define SNDCTL_DSP_GETOPTR		__SIOR ('P',18, count_info)
+
+typedef struct buffmem_desc
+{
+  unsigned *buffer;
+  int size;
+} buffmem_desc;
+#define SNDCTL_DSP_SETSYNCRO		__SIO  ('P', 21)
+#define SNDCTL_DSP_SETDUPLEX		__SIO  ('P', 22)
+
+#define SNDCTL_DSP_PROFILE		__SIOW ('P', 23, int)	/* OBSOLETE */
+#define	  APF_NORMAL	0	/* Normal applications */
+#define	  APF_NETWORK	1	/* Underruns probably caused by an "external" delay */
+#define   APF_CPUINTENS 2	/* Underruns probably caused by "overheating" the CPU */
+
+#define SNDCTL_DSP_GETODELAY		__SIOR ('P', 23, int)
+
+typedef struct audio_errinfo
+{
+  int play_underruns;
+  int rec_overruns;
+  unsigned int play_ptradjust;
+  unsigned int rec_ptradjust;
+  int play_errorcount;
+  int rec_errorcount;
+  int play_lasterror;
+  int rec_lasterror;
+  int play_errorparm;
+  int rec_errorparm;
+  int filler[16];
+} audio_errinfo;
+
+#define SNDCTL_DSP_GETPLAYVOL		__SIOR ('P', 24, int)
+#define SNDCTL_DSP_SETPLAYVOL		__SIOWR('P', 24, int)
+#define SNDCTL_DSP_GETERROR		__SIOR ('P', 25, audio_errinfo)
+/*
+ ****************************************************************************
+ * Digital interface (S/PDIF) control interface
+ */
+
+typedef struct oss_digital_control
+{
+  unsigned int caps;
+#define DIG_CBITIN_NONE			0x00000000
+#define DIG_CBITIN_LIMITED		0x00000001
+#define DIG_CBITIN_DATA 		0x00000002
+#define DIG_CBITIN_BYTE0		0x00000004
+#define DIG_CBITIN_FULL 		0x00000008
+#define DIG_CBITIN_MASK 		0x0000000f
+#define DIG_CBITOUT_NONE		0x00000000
+#define DIG_CBITOUT_LIMITED		0x00000010
+#define DIG_CBITOUT_BYTE0		0x00000020
+#define DIG_CBITOUT_FULL 		0x00000040
+#define DIG_CBITOUT_DATA 		0x00000080
+#define DIG_CBITOUT_MASK 		0x000000f0
+#define DIG_UBITIN			0x00000100
+#define DIG_UBITOUT			0x00000200
+#define DIG_VBITOUT			0x00000400
+#define DIG_OUTRATE			0x00000800
+#define DIG_INRATE			0x00001000
+#define DIG_INBITS			0x00002000
+#define DIG_OUTBITS			0x00004000
+#define DIG_EXACT			0x00010000
+#define DIG_PRO				0x00020000
+#define DIG_CONSUMER			0x00040000
+#define DIG_PASSTHROUGH			0x00080000
+#define DIG_OUTSEL			0x00100000
+
+  unsigned int valid;
+#define VAL_CBITIN			0x00000001
+#define VAL_UBITIN			0x00000002
+#define VAL_CBITOUT			0x00000004
+#define VAL_UBITOUT			0x00000008
+#define VAL_ISTATUS			0x00000010
+#define VAL_IRATE			0x00000020
+#define VAL_ORATE			0x00000040
+#define VAL_INBITS			0x00000080
+#define VAL_OUTBITS			0x00000100
+#define VAL_REQUEST			0x00000200
+#define VAL_OUTSEL			0x00000400
+
+#define VAL_OUTMASK (VAL_CBITOUT|VAL_UBITOUT|VAL_ORATE|VAL_OUTBITS|VAL_OUTSEL)
+
+  unsigned int request, param;
+#define SPD_RQ_PASSTHROUGH				1
+
+  unsigned char cbitin[24];
+  unsigned char ubitin[24];
+  unsigned char cbitout[24];
+  unsigned char ubitout[24];
+
+  unsigned int outsel;
+#define OUTSEL_DIGITAL		1
+#define OUTSEL_ANALOG		2
+#define OUTSEL_BOTH		(OUTSEL_DIGITAL|OUTSEL_ANALOG)
+
+  int in_data;			/* Audio/data if autodetectable by the receiver */
+#define IND_UNKNOWN		0
+#define IND_AUDIO		1
+#define IND_DATA		2
+
+  int in_locked;		/* Receiver locked */
+#define LOCK_NOT_INDICATED	0
+#define LOCK_UNLOCKED		1
+#define LOCK_LOCKED		2
+
+  int in_quality;		/* Input signal quality */
+#define IN_QUAL_NOT_INDICATED	0
+#define IN_QUAL_POOR		1
+#define IN_QUAL_GOOD		2
+
+  int in_vbit, out_vbit;	/* V bits */
+#define VBIT_NOT_INDICATED	0
+#define VBIT_OFF		1
+#define VBIT_ON			2
+
+  unsigned int in_errors;	/* Various input error conditions */
+#define INERR_CRC		0x0001
+#define INERR_QCODE_CRC		0x0002
+#define INERR_PARITY		0x0004
+#define INERR_BIPHASE		0x0008
+
+  int srate_in, srate_out;
+  int bits_in, bits_out;
+
+  int filler[32];
+} oss_digital_control;
+
+#define SNDCTL_DSP_READCTL		__SIOWR('P', 26, oss_digital_control)
+#define SNDCTL_DSP_WRITECTL		__SIOWR('P', 27, oss_digital_control)
+
+/*
+ ****************************************************************************
+ * Sync groups for audio devices
+ */
+typedef struct oss_syncgroup
+{
+  int id;
+  int mode;
+  int filler[16];
+} oss_syncgroup;
+
+#define SNDCTL_DSP_SYNCGROUP		__SIOWR('P', 28, oss_syncgroup)
+#define SNDCTL_DSP_SYNCSTART		__SIOW ('P', 29, int)
+
+/*
+ **************************************************************************
+ * "cooked" mode enables software based conversions for sample rate, sample
+ * format (bits) and number of channels (mono/stereo). These conversions are
+ * required with some devices that support only one sample rate or just stereo
+ * to let the applications to use other formats. The cooked mode is enabled by
+ * default. However it's necessary to disable this mode when mmap() is used or
+ * when very deterministic timing is required. SNDCTL_DSP_COOKEDMODE is an
+ * optional call introduced in OSS 3.9.6f. It's _error return must be ignored_
+ * since normally this call will return erno=EINVAL.
+ *
+ * SNDCTL_DSP_COOKEDMODE must be called immediately after open before doing
+ * anything else. Otherwise the call will not have any effect.
+ */
+#define SNDCTL_DSP_COOKEDMODE		__SIOW ('P', 30, int)
+
+/*
+ **************************************************************************
+ * SNDCTL_DSP_SILENCE and SNDCTL_DSP_SKIP are new calls in OSS 3.99.0
+ * that can be used to implement pause/continue during playback (no effect
+ * on recording).
+ */
+#define SNDCTL_DSP_SILENCE		__SIO  ('P', 31)
+#define SNDCTL_DSP_SKIP			__SIO  ('P', 32)
+/*
+ ****************************************************************************
+ * Abort transfer (reset) functions for input and output
+ */
+#define SNDCTL_DSP_HALT_INPUT		__SIO  ('P', 33)
+#define SNDCTL_DSP_RESET_INPUT	SNDCTL_DSP_HALT_INPUT	/* Old name */
+#define SNDCTL_DSP_HALT_OUTPUT		__SIO  ('P', 34)
+#define SNDCTL_DSP_RESET_OUTPUT	SNDCTL_DSP_HALT_OUTPUT	/* Old name */
+/*
+ ****************************************************************************
+ * Low water level control
+ */
+#define SNDCTL_DSP_LOW_WATER		__SIOW ('P', 34, int)
+
+/*
+ ****************************************************************************
+ * 64 bit pointer support. Only available in environments that support
+ * the 64 bit (long long) integer type.
+ */
+#ifndef OSS_NO_LONG_LONG
+typedef struct
+{
+  long long samples;
+  int fifo_samples;
+  int filler[32];		/* For future use */
+} oss_count_t;
+
+#define SNDCTL_DSP_CURRENT_IPTR		__SIOR ('P', 35, oss_count_t)
+#define SNDCTL_DSP_CURRENT_OPTR		__SIOR ('P', 36, oss_count_t)
+#endif
+
+/*
+ ****************************************************************************
+ * Interface for selecting recording sources and playback output routings.
+ */
+#define SNDCTL_DSP_GET_RECSRC_NAMES	__SIOR ('P', 37, oss_mixer_enuminfo)
+#define SNDCTL_DSP_GET_RECSRC		__SIOR ('P', 38, int)
+#define SNDCTL_DSP_SET_RECSRC		__SIOWR('P', 38, int)
+
+#define SNDCTL_DSP_GET_PLAYTGT_NAMES	__SIOR ('P', 39, oss_mixer_enuminfo)
+#define SNDCTL_DSP_GET_PLAYTGT		__SIOR ('P', 40, int)
+#define SNDCTL_DSP_SET_PLAYTGT		__SIOWR('P', 40, int)
+#define SNDCTL_DSP_GETRECVOL		__SIOR ('P', 41, int)
+#define SNDCTL_DSP_SETRECVOL		__SIOWR('P', 41, int)
+
+/*
+ ***************************************************************************
+ * Some calls for setting the channel assignment with multi channel devices
+ * (see the manual for details).
+ */
+#ifndef OSS_NO_LONG_LONG
+#define SNDCTL_DSP_GET_CHNORDER		__SIOR ('P', 42, unsigned long long)
+#define SNDCTL_DSP_SET_CHNORDER		__SIOWR('P', 42, unsigned long long)
+#	define CHID_UNDEF	0
+#	define CHID_L		1
+#	define CHID_R		2
+#	define CHID_C		3
+#	define CHID_LFE		4
+#	define CHID_LS		5
+#	define CHID_RS		6
+#	define CHID_LR		7
+#	define CHID_RR		8
+#define CHNORDER_UNDEF		0x0000000000000000ULL
+#define CHNORDER_NORMAL		0x0000000087654321ULL
+#endif
+
+#define MAX_PEAK_CHANNELS	128
+typedef unsigned short oss_peaks_t[MAX_PEAK_CHANNELS];
+#define SNDCTL_DSP_GETIPEAKS		__SIOR('P', 43, oss_peaks_t)
+#define SNDCTL_DSP_GETOPEAKS		__SIOR('P', 44, oss_peaks_t)
+
+#define SNDCTL_DSP_POLICY		__SIOW('P', 45, int)	/* See the manual */
+
+/*
+ ****************************************************************************
+ * Few ioctl calls that are not official parts of OSS. They have been used
+ * by few freeware implementations of OSS.
+ */
+#define SNDCTL_DSP_GETCHANNELMASK	__SIOWR('P', 64, int)
+#define SNDCTL_DSP_BIND_CHANNEL		__SIOWR('P', 65, int)
+#     define DSP_BIND_QUERY           0x00000000
+#     define DSP_BIND_FRONT           0x00000001
+#     define DSP_BIND_SURR            0x00000002
+#     define DSP_BIND_CENTER_LFE      0x00000004
+#     define DSP_BIND_HANDSET         0x00000008
+#     define DSP_BIND_MIC             0x00000010
+#     define DSP_BIND_MODEM1          0x00000020
+#     define DSP_BIND_MODEM2          0x00000040
+#     define DSP_BIND_I2S             0x00000080
+#     define DSP_BIND_SPDIF           0x00000100
+#     define DSP_BIND_REAR            0x00000200
+
+#ifdef sun
+/* Not part of OSS. Reserved for internal use by Solaris */
+#define X_SADA_GET_PLAYTGT_MASK	__SIOR ('P', 66, int)
+#define X_SADA_GET_PLAYTGT	__SIOR ('P', 67, int)
+#define X_SADA_SET_PLAYTGT	__SIOWR('P', 68, int)
+#endif
+
+#ifndef NO_LEGACY_MIXER
+/*
+ ****************************************************************************
+ * IOCTL commands for the "legacy " /dev/mixer API (obsolete)
+ *
+ * Mixer controls
+ *
+ * There can be up to 20 different analog mixer channels. The
+ * SOUND_MIXER_NRDEVICES gives the currently supported maximum. 
+ * The SOUND_MIXER_READ_DEVMASK returns a bitmask which tells
+ * the devices supported by the particular mixer.
+ *
+ * {!notice This "legacy" mixer API is obsolete. It has been superceded
+ * by a new one (see below).
+ */
+
+#define SOUND_MIXER_NRDEVICES	28
+#define SOUND_MIXER_VOLUME	0
+#define SOUND_MIXER_BASS	1
+#define SOUND_MIXER_TREBLE	2
+#define SOUND_MIXER_SYNTH	3
+#define SOUND_MIXER_PCM		4
+#define SOUND_MIXER_SPEAKER	5
+#define SOUND_MIXER_LINE	6
+#define SOUND_MIXER_MIC		7
+#define SOUND_MIXER_CD		8
+#define SOUND_MIXER_IMIX	9	/*  Recording monitor  */
+#define SOUND_MIXER_ALTPCM	10
+#define SOUND_MIXER_RECLEV	11	/* Recording level */
+#define SOUND_MIXER_IGAIN	12	/* Input gain */
+#define SOUND_MIXER_OGAIN	13	/* Output gain */
+/* 
+ * Some soundcards have three line level inputs (line, aux1 and aux2). 
+ * Since each card manufacturer has assigned different meanings to 
+ * these inputs, it's impractical to assign specific meanings 
+ * (eg line, cd, synth etc.) to them.
+ */
+#define SOUND_MIXER_LINE1	14	/* Input source 1  (aux1) */
+#define SOUND_MIXER_LINE2	15	/* Input source 2  (aux2) */
+#define SOUND_MIXER_LINE3	16	/* Input source 3  (line) */
+#define SOUND_MIXER_DIGITAL1	17	/* Digital I/O 1 */
+#define SOUND_MIXER_DIGITAL2	18	/* Digital I/O 2 */
+#define SOUND_MIXER_DIGITAL3	19	/* Digital I/O 3 */
+#define SOUND_MIXER_PHONE	20	/* Phone */
+#define SOUND_MIXER_MONO	21	/* Mono Output */
+#define SOUND_MIXER_VIDEO	22	/* Video/TV (audio) in */
+#define SOUND_MIXER_RADIO	23	/* Radio in */
+#define SOUND_MIXER_DEPTH	24	/* Surround depth */
+#define SOUND_MIXER_REARVOL	25	/* Rear/Surround speaker vol */
+#define SOUND_MIXER_CENTERVOL	26	/* Center/LFE speaker vol */
+#define SOUND_MIXER_SIDEVOL	27	/* Side-Surround (8speaker) vol */
+
+/*
+ * Warning: SOUND_MIXER_SURRVOL is an old name of SOUND_MIXER_SIDEVOL.
+ *          They are both assigned to the same mixer control. Don't
+ *          use both control names in the same program/driver.
+ */
+#define SOUND_MIXER_SURRVOL	SOUND_MIXER_SIDEVOL
+
+/* Some on/off settings (SOUND_SPECIAL_MIN - SOUND_SPECIAL_MAX) */
+/* Not counted to SOUND_MIXER_NRDEVICES, but use the same number space */
+#define SOUND_ONOFF_MIN		28
+#define SOUND_ONOFF_MAX		30
+
+/* Note!	Number 31 cannot be used since the sign bit is reserved */
+#define SOUND_MIXER_NONE	31
+
+/*
+ * The following unsupported macros are no longer functional.
+ * Use SOUND_MIXER_PRIVATE# macros in future.
+ */
+#define SOUND_MIXER_ENHANCE	SOUND_MIXER_NONE
+#define SOUND_MIXER_MUTE	SOUND_MIXER_NONE
+#define SOUND_MIXER_LOUD	SOUND_MIXER_NONE
+
+#define SOUND_DEVICE_LABELS \
+	{"Vol  ", "Bass ", "Treble", "Synth", "Pcm  ", "Speaker ", "Line ", \
+	 "Mic  ", "CD   ", "Mix  ", "Pcm2 ", "Rec  ", "IGain", "OGain", \
+	 "Aux1", "Aux2", "Aux3", "Digital1", "Digital2", "Digital3", \
+	 "Phone", "Mono", "Video", "Radio", "Depth", \
+	 "Rear", "Center", "Side"}
+
+#define SOUND_DEVICE_NAMES \
+	{"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \
+	 "mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \
+	 "aux1", "aux2", "aux3", "dig1", "dig2", "dig3", \
+	 "phone", "mono", "video", "radio", "depth", \
+	 "rear", "center", "side"}
+
+/*	Device bitmask identifiers	*/
+
+#define SOUND_MIXER_RECSRC	0xff	/* Arg contains a bit for each recording source */
+#define SOUND_MIXER_DEVMASK	0xfe	/* Arg contains a bit for each supported device */
+#define SOUND_MIXER_RECMASK	0xfd	/* Arg contains a bit for each supported recording source */
+#define SOUND_MIXER_CAPS	0xfc
+#	define SOUND_CAP_EXCL_INPUT	0x00000001	/* Only one recording source at a time */
+#	define SOUND_CAP_NOLEGACY	0x00000004	/* For internal use only */
+#	define SOUND_CAP_NORECSRC	0x00000008
+#define SOUND_MIXER_STEREODEVS	0xfb	/* Mixer channels supporting stereo */
+
+/* OSS/Free ONLY */
+#define SOUND_MIXER_OUTSRC    0xfa	/* Arg contains a bit for each input source to output */
+#define SOUND_MIXER_OUTMASK   0xf9	/* Arg contains a bit for each supported input source to output */
+/* OSS/Free ONLY */
+
+/*	Device mask bits	*/
+
+#define SOUND_MASK_VOLUME	(1 << SOUND_MIXER_VOLUME)
+#define SOUND_MASK_BASS		(1 << SOUND_MIXER_BASS)
+#define SOUND_MASK_TREBLE	(1 << SOUND_MIXER_TREBLE)
+#define SOUND_MASK_SYNTH	(1 << SOUND_MIXER_SYNTH)
+#define SOUND_MASK_PCM		(1 << SOUND_MIXER_PCM)
+#define SOUND_MASK_SPEAKER	(1 << SOUND_MIXER_SPEAKER)
+#define SOUND_MASK_LINE		(1 << SOUND_MIXER_LINE)
+#define SOUND_MASK_MIC		(1 << SOUND_MIXER_MIC)
+#define SOUND_MASK_CD		(1 << SOUND_MIXER_CD)
+#define SOUND_MASK_IMIX		(1 << SOUND_MIXER_IMIX)
+#define SOUND_MASK_ALTPCM	(1 << SOUND_MIXER_ALTPCM)
+#define SOUND_MASK_RECLEV	(1 << SOUND_MIXER_RECLEV)
+#define SOUND_MASK_IGAIN	(1 << SOUND_MIXER_IGAIN)
+#define SOUND_MASK_OGAIN	(1 << SOUND_MIXER_OGAIN)
+#define SOUND_MASK_LINE1	(1 << SOUND_MIXER_LINE1)
+#define SOUND_MASK_LINE2	(1 << SOUND_MIXER_LINE2)
+#define SOUND_MASK_LINE3	(1 << SOUND_MIXER_LINE3)
+#define SOUND_MASK_DIGITAL1	(1 << SOUND_MIXER_DIGITAL1)
+#define SOUND_MASK_DIGITAL2	(1 << SOUND_MIXER_DIGITAL2)
+#define SOUND_MASK_DIGITAL3	(1 << SOUND_MIXER_DIGITAL3)
+#define SOUND_MASK_MONO		(1 << SOUND_MIXER_MONO)
+#define SOUND_MASK_PHONE	(1 << SOUND_MIXER_PHONE)
+#define SOUND_MASK_RADIO	(1 << SOUND_MIXER_RADIO)
+#define SOUND_MASK_VIDEO	(1 << SOUND_MIXER_VIDEO)
+#define SOUND_MASK_DEPTH	(1 << SOUND_MIXER_DEPTH)
+#define SOUND_MASK_REARVOL	(1 << SOUND_MIXER_REARVOL)
+#define SOUND_MASK_CENTERVOL	(1 << SOUND_MIXER_CENTERVOL)
+#define SOUND_MASK_SIDEVOL	(1 << SOUND_MIXER_SIDEVOL)
+
+/* Note! SOUND_MASK_SURRVOL is alias of SOUND_MASK_SIDEVOL */
+#define SOUND_MASK_SURRVOL	(1 << SOUND_MIXER_SIDEVOL)
+
+/* Obsolete macros */
+#define SOUND_MASK_MUTE		(1 << SOUND_MIXER_MUTE)
+#define SOUND_MASK_ENHANCE	(1 << SOUND_MIXER_ENHANCE)
+#define SOUND_MASK_LOUD		(1 << SOUND_MIXER_LOUD)
+
+#define MIXER_READ(dev)			__SIOR('M', dev, int)
+#define SOUND_MIXER_READ_VOLUME		MIXER_READ(SOUND_MIXER_VOLUME)
+#define SOUND_MIXER_READ_BASS		MIXER_READ(SOUND_MIXER_BASS)
+#define SOUND_MIXER_READ_TREBLE		MIXER_READ(SOUND_MIXER_TREBLE)
+#define SOUND_MIXER_READ_SYNTH		MIXER_READ(SOUND_MIXER_SYNTH)
+#define SOUND_MIXER_READ_PCM		MIXER_READ(SOUND_MIXER_PCM)
+#define SOUND_MIXER_READ_SPEAKER	MIXER_READ(SOUND_MIXER_SPEAKER)
+#define SOUND_MIXER_READ_LINE		MIXER_READ(SOUND_MIXER_LINE)
+#define SOUND_MIXER_READ_MIC		MIXER_READ(SOUND_MIXER_MIC)
+#define SOUND_MIXER_READ_CD		MIXER_READ(SOUND_MIXER_CD)
+#define SOUND_MIXER_READ_IMIX		MIXER_READ(SOUND_MIXER_IMIX)
+#define SOUND_MIXER_READ_ALTPCM		MIXER_READ(SOUND_MIXER_ALTPCM)
+#define SOUND_MIXER_READ_RECLEV		MIXER_READ(SOUND_MIXER_RECLEV)
+#define SOUND_MIXER_READ_IGAIN		MIXER_READ(SOUND_MIXER_IGAIN)
+#define SOUND_MIXER_READ_OGAIN		MIXER_READ(SOUND_MIXER_OGAIN)
+#define SOUND_MIXER_READ_LINE1		MIXER_READ(SOUND_MIXER_LINE1)
+#define SOUND_MIXER_READ_LINE2		MIXER_READ(SOUND_MIXER_LINE2)
+#define SOUND_MIXER_READ_LINE3		MIXER_READ(SOUND_MIXER_LINE3)
+
+/* Obsolete macros */
+#define SOUND_MIXER_READ_MUTE		MIXER_READ(SOUND_MIXER_MUTE)
+#define SOUND_MIXER_READ_ENHANCE	MIXER_READ(SOUND_MIXER_ENHANCE)
+#define SOUND_MIXER_READ_LOUD		MIXER_READ(SOUND_MIXER_LOUD)
+
+#define SOUND_MIXER_READ_RECSRC		MIXER_READ(SOUND_MIXER_RECSRC)
+#define SOUND_MIXER_READ_DEVMASK	MIXER_READ(SOUND_MIXER_DEVMASK)
+#define SOUND_MIXER_READ_RECMASK	MIXER_READ(SOUND_MIXER_RECMASK)
+#define SOUND_MIXER_READ_STEREODEVS	MIXER_READ(SOUND_MIXER_STEREODEVS)
+#define SOUND_MIXER_READ_CAPS		MIXER_READ(SOUND_MIXER_CAPS)
+
+#define MIXER_WRITE(dev)		__SIOWR('M', dev, int)
+#define SOUND_MIXER_WRITE_VOLUME	MIXER_WRITE(SOUND_MIXER_VOLUME)
+#define SOUND_MIXER_WRITE_BASS		MIXER_WRITE(SOUND_MIXER_BASS)
+#define SOUND_MIXER_WRITE_TREBLE	MIXER_WRITE(SOUND_MIXER_TREBLE)
+#define SOUND_MIXER_WRITE_SYNTH		MIXER_WRITE(SOUND_MIXER_SYNTH)
+#define SOUND_MIXER_WRITE_PCM		MIXER_WRITE(SOUND_MIXER_PCM)
+#define SOUND_MIXER_WRITE_SPEAKER	MIXER_WRITE(SOUND_MIXER_SPEAKER)
+#define SOUND_MIXER_WRITE_LINE		MIXER_WRITE(SOUND_MIXER_LINE)
+#define SOUND_MIXER_WRITE_MIC		MIXER_WRITE(SOUND_MIXER_MIC)
+#define SOUND_MIXER_WRITE_CD		MIXER_WRITE(SOUND_MIXER_CD)
+#define SOUND_MIXER_WRITE_IMIX		MIXER_WRITE(SOUND_MIXER_IMIX)
+#define SOUND_MIXER_WRITE_ALTPCM	MIXER_WRITE(SOUND_MIXER_ALTPCM)
+#define SOUND_MIXER_WRITE_RECLEV	MIXER_WRITE(SOUND_MIXER_RECLEV)
+#define SOUND_MIXER_WRITE_IGAIN		MIXER_WRITE(SOUND_MIXER_IGAIN)
+#define SOUND_MIXER_WRITE_OGAIN		MIXER_WRITE(SOUND_MIXER_OGAIN)
+#define SOUND_MIXER_WRITE_LINE1		MIXER_WRITE(SOUND_MIXER_LINE1)
+#define SOUND_MIXER_WRITE_LINE2		MIXER_WRITE(SOUND_MIXER_LINE2)
+#define SOUND_MIXER_WRITE_LINE3		MIXER_WRITE(SOUND_MIXER_LINE3)
+
+/* Obsolete macros */
+#define SOUND_MIXER_WRITE_MUTE		MIXER_WRITE(SOUND_MIXER_MUTE)
+#define SOUND_MIXER_WRITE_ENHANCE	MIXER_WRITE(SOUND_MIXER_ENHANCE)
+#define SOUND_MIXER_WRITE_LOUD		MIXER_WRITE(SOUND_MIXER_LOUD)
+
+#define SOUND_MIXER_WRITE_RECSRC	MIXER_WRITE(SOUND_MIXER_RECSRC)
+
+typedef struct mixer_info	/* OBSOLETE */
+{
+  char id[16];
+  char name[32];
+  int modify_counter;
+  int card_number;
+  int port_number;
+  char handle[32];
+} mixer_info;
+
+/* SOUND_MIXER_INFO is obsolete - use SNDCTL_MIXERINFO instead */
+#define SOUND_MIXER_INFO		__SIOR ('M', 101, mixer_info)
+
+/*
+ * Two ioctls for special souncard function (OSS/Free only)
+ */
+#define SOUND_MIXER_AGC  _SIOWR('M', 103, int)
+#define SOUND_MIXER_3DSE  _SIOWR('M', 104, int)
+/*
+ * The SOUND_MIXER_PRIVATE# commands can be redefined by low level drivers.
+ * These features can be used when accessing device specific features.
+ */
+#define SOUND_MIXER_PRIVATE1		__SIOWR('M', 111, int)
+#define SOUND_MIXER_PRIVATE2		__SIOWR('M', 112, int)
+#define SOUND_MIXER_PRIVATE3		__SIOWR('M', 113, int)
+#define SOUND_MIXER_PRIVATE4		__SIOWR('M', 114, int)
+#define SOUND_MIXER_PRIVATE5		__SIOWR('M', 115, int)
+
+/* The following two controls were never implemented and they should not be used. */
+#define SOUND_MIXER_READ_MAINVOL		__SIOR ('M', 116, int)
+#define SOUND_MIXER_WRITE_MAINVOL		__SIOWR('M', 116, int)
+
+/*
+ * SOUND_MIXER_GETLEVELS and SOUND_MIXER_SETLEVELS calls can be used
+ * for querying current mixer settings from the driver and for loading
+ * default volume settings _prior_ activating the mixer (loading
+ * doesn't affect current state of the mixer hardware). These calls
+ * are for internal use by the driver software only.
+ */
+
+typedef struct mixer_vol_table
+{
+  int num;			/* Index to volume table */
+  char name[32];
+  int levels[32];
+} mixer_vol_table;
+
+#define SOUND_MIXER_GETLEVELS		__SIOWR('M', 116, mixer_vol_table)
+#define SOUND_MIXER_SETLEVELS		__SIOWR('M', 117, mixer_vol_table)
+
+#define OSS_GETVERSION			__SIOR ('M', 118, int)
+
+/*
+ * Calls to set/get the recording gain for the currently active
+ * recording source. These calls automatically map to the right control.
+ * Note that these calls are not supported by all drivers. In this case
+ * the call will return -1 with errno set to EINVAL
+ *
+ * The _MONGAIN work in similar way but set/get the monitoring gain for
+ * the currently selected recording source.
+ */
+#define SOUND_MIXER_READ_RECGAIN	__SIOR ('M', 119, int)
+#define SOUND_MIXER_WRITE_RECGAIN	__SIOWR('M', 119, int)
+#define SOUND_MIXER_READ_MONGAIN	__SIOR ('M', 120, int)
+#define SOUND_MIXER_WRITE_MONGAIN	__SIOWR('M', 120, int)
+
+/* The following call is for driver development time purposes. It's not
+ * present in any released drivers.
+ */
+typedef unsigned char oss_reserved_t[512];
+#define SOUND_MIXER_RESERVED		__SIOWR('M', 121, oss_reserved_t)
+#endif /* ifndef NO_LEGACY_MIXER */
+
+/*
+ *************************************************************************
+ * The "new" mixer API of OSS 4.0 and later.
+ *
+ * This improved mixer API makes it possible to access every possible feature
+ * of every possible device. However you should read the mixer programming
+ * section of the OSS API Developer's Manual. There is no chance that you
+ * could use this interface correctly just by examining this header.
+ */
+
+typedef struct oss_sysinfo
+{
+  char product[32];		/* For example OSS/Free, OSS/Linux or OSS/Solaris */
+  char version[32];		/* For example 4.0a */
+  int versionnum;		/* See OSS_GETVERSION */
+  char options[128];		/* Reserved */
+
+  int numaudios;		/* # of audio/dsp devices */
+  int openedaudio[8];		/* Bit mask telling which audio devices are busy */
+
+  int numsynths;		/* # of availavle synth devices */
+  int nummidis;			/* # of available MIDI ports */
+  int numtimers;		/* # of available timer devices */
+  int nummixers;		/* # of mixer devices */
+
+  int openedmidi[8];		/* Bit mask telling which midi devices are busy */
+  int numcards;			/* Number of sound cards in the system */
+  int numaudioengines;		/* Number of audio engines in the system */
+  char license[16];		/* For example "GPL" or "CDDL" */
+  int filler[236];		/* For future expansion (set to -1) */
+} oss_sysinfo;
+
+typedef struct oss_mixext
+{
+  int dev;			/* Mixer device number */
+  int ctrl;			/* Controller number */
+  int type;			/* Entry type */
+#	define MIXT_DEVROOT	 0	/* Device root entry */
+#	define MIXT_GROUP	 1	/* Controller group */
+#	define MIXT_ONOFF	 2	/* OFF (0) or ON (1) */
+#	define MIXT_ENUM	 3	/* Enumerated (0 to maxvalue) */
+#	define MIXT_MONOSLIDER	 4	/* Mono slider (0 to 255) */
+#	define MIXT_STEREOSLIDER 5	/* Stereo slider (dual 0 to 255) */
+#	define MIXT_MESSAGE	 6	/* (Readable) textual message */
+#	define MIXT_MONOVU	 7	/* VU meter value (mono) */
+#	define MIXT_STEREOVU	 8	/* VU meter value (stereo) */
+#	define MIXT_MONOPEAK	 9	/* VU meter peak value (mono) */
+#	define MIXT_STEREOPEAK	10	/* VU meter peak value (stereo) */
+#	define MIXT_RADIOGROUP	11	/* Radio button group */
+#	define MIXT_MARKER	12	/* Separator between normal and extension entries */
+#	define MIXT_VALUE	13	/* Decimal value entry */
+#	define MIXT_HEXVALUE	14	/* Hexadecimal value entry */
+#	define MIXT_MONODB	15	/* OBSOLETE */
+#	define MIXT_STEREODB	16	/* OBSOLETE */
+#	define MIXT_SLIDER	17	/* Slider (mono) with full (31 bit) postitive integer range */
+#	define MIXT_3D		18
+
+/*
+ * Sliders with range expanded to 15 bits per channel (0-32767)
+ */
+#	define MIXT_MONOSLIDER16	19
+#	define MIXT_STEREOSLIDER16	20
+#	define MIXT_MUTE	21	/* Mute=1, unmute=0 */
+
+  /**************************************************************/
+
+  /* Possible value range (minvalue to maxvalue) */
+  /* Note that maxvalue may also be smaller than minvalue */
+  int maxvalue;
+  int minvalue;
+
+  int flags;
+#	define MIXF_READABLE	0x00000001	/* Has readable value */
+#	define MIXF_WRITEABLE	0x00000002	/* Has writeable value */
+#	define MIXF_POLL	0x00000004	/* May change itself */
+#	define MIXF_HZ		0x00000008	/* Herz scale */
+#	define MIXF_STRING	0x00000010	/* Use dynamic extensions for value */
+#	define MIXF_DYNAMIC	0x00000010	/* Supports dynamic extensions */
+#	define MIXF_OKFAIL	0x00000020	/* Interpret value as 1=OK, 0=FAIL */
+#	define MIXF_FLAT	0x00000040	/* Flat vertical space requirements */
+#	define MIXF_LEGACY	0x00000080	/* Legacy mixer control group */
+#	define MIXF_CENTIBEL	0x00000100	/* Centibel (0.1 dB) step size */
+#	define MIXF_DECIBEL	0x00000200	/* Step size of 1 dB */
+#	define MIXF_MAINVOL	0x00000400	/* Main volume control */
+#	define MIXF_PCMVOL	0x00000800	/* PCM output volume control */
+#	define MIXF_RECVOL	0x00001000	/* PCM recording volume control */
+#	define MIXF_MONVOL	0x00002000	/* Input->output monitor volume */
+#	define MIXF_WIDE	0x00004000	/* Enum control has wide labels */
+#	define MIXF_DESCR	0x00008000	/* Description (tooltip) available */
+  char id[16];			/* Mnemonic ID (mainly for internal use) */
+  int parent;			/* Entry# of parent (group) node (-1 if root) */
+
+  int dummy;			/* Internal use */
+
+  int timestamp;
+
+  char data[64];		/* Misc data (entry type dependent) */
+  unsigned char enum_present[32];	/* Mask of allowed enum values */
+  int control_no;		/* SOUND_MIXER_VOLUME..SOUND_MIXER_MIDI */
+  /* (-1 means not indicated) */
+
+/*
+ * The desc field is reserved for internal purposes of OSS. It should not be 
+ * used by applications.
+ */
+  unsigned int desc;
+#define MIXEXT_SCOPE_MASK			0x0000003f
+#define MIXEXT_SCOPE_OTHER			0x00000000
+#define MIXEXT_SCOPE_INPUT			0x00000001
+#define MIXEXT_SCOPE_OUTPUT			0x00000002
+#define MIXEXT_SCOPE_MONITOR			0x00000003
+#define MIXEXT_SCOPE_RECSWITCH			0x00000004
+
+  char extname[32];
+  int update_counter;
+  int rgbcolor;		/* 0 means default color (not black) . Otherwise 24 bit RGB color */
+  int filler[6];
+} oss_mixext;
+
+/*
+ * Recommended colors to be used in the rgbcolor field. These match the
+ * colors used as the audio jack colors in HD audio motherboards.
+ */
+#define OSS_RGB_BLUE	0x7aabde		// Light blue
+#define OSS_RGB_GREEN	0xb3c98c		// Lime green
+#define OSS_RGB_PINK	0xe88c99
+#define OSS_RGB_GRAY	0xd1ccc4
+#define OSS_RGB_BLACK	0x2b2926		// Light black
+#define OSS_RGB_ORANGE	0xe89e47
+#define OSS_RGB_RED	0xff0000
+#define OSS_RGB_YELLOW	0xffff00
+#define OSS_RGB_PURPLE	0x800080
+#define OSS_RGB_WHITE	0xf8f8ff
+
+typedef struct oss_mixext_root
+{
+  char id[16];
+  char name[48];
+} oss_mixext_root;
+
+typedef struct oss_mixer_value
+{
+  int dev;
+  int ctrl;
+  int value;
+  int flags;			/* Reserved for future use. Initialize to 0 */
+  int timestamp;		/* Must be set to oss_mixext.timestamp */
+  int filler[8];		/* Reserved for future use. Initialize to 0 */
+} oss_mixer_value;
+
+#define OSS_ENUM_MAXVALUE	255
+#define OSS_ENUM_STRINGSIZE	3000
+typedef struct oss_mixer_enuminfo
+{
+  int dev;
+  int ctrl;
+  int nvalues;
+  int version;			/* Read the manual */
+  short strindex[OSS_ENUM_MAXVALUE];
+  char strings[OSS_ENUM_STRINGSIZE];
+} oss_mixer_enuminfo;
+
+#define OPEN_READ	PCM_ENABLE_INPUT
+#define OPEN_WRITE	PCM_ENABLE_OUTPUT
+#define OPEN_READWRITE	(OPEN_READ|OPEN_WRITE)
+
+typedef struct oss_audioinfo
+{
+  int dev;			/* Audio device number */
+  char name[64];
+  int busy;			/* 0, OPEN_READ, OPEN_WRITE or OPEN_READWRITE */
+  int pid;
+  int caps;			/* PCM_CAP_INPUT, PCM_CAP_OUTPUT */
+  int iformats, oformats;
+  int magic;			/* Reserved for internal use */
+  char cmd[64];			/* Command using the device (if known) */
+  int card_number;
+  int port_number;
+  int mixer_dev;
+  int legacy_device;		/* Obsolete field. Replaced by devnode */
+  int enabled;			/* 1=enabled, 0=device not ready at this moment */
+  int flags;			/* For internal use only - no practical meaning */
+  int min_rate, max_rate;	/* Sample rate limits */
+  int min_channels, max_channels;	/* Number of channels supported */
+  int binding;			/* DSP_BIND_FRONT, etc. 0 means undefined */
+  int rate_source;
+  char handle[32];
+#define OSS_MAX_SAMPLE_RATES	20	/* Cannot be changed  */
+  unsigned int nrates, rates[OSS_MAX_SAMPLE_RATES];	/* Please read the manual before using these */
+  oss_longname_t song_name;	/* Song name (if given) */
+  oss_label_t label;		/* Device label (if given) */
+  int latency;			/* In usecs, -1=unknown */
+  oss_devnode_t devnode;	/* Device special file name (absolute path) */
+  int next_play_engine;		/* Read the documentation for more info */
+  int next_rec_engine;		/* Read the documentation for more info */
+  int filler[184];
+} oss_audioinfo;
+
+typedef struct oss_mixerinfo
+{
+  int dev;
+  char id[16];
+  char name[32];
+  int modify_counter;
+  int card_number;
+  int port_number;
+  char handle[32];
+  int magic;			/* Reserved */
+  int enabled;			/* Reserved */
+  int caps;
+#define MIXER_CAP_VIRTUAL	0x00000001
+#define MIXER_CAP_LAYOUT_B	0x00000002	/* For internal use only */
+#define MIXER_CAP_NARROW	0x00000004	/* Conserve horiz space */
+  int flags;			/* Reserved */
+  int nrext;
+  /*
+   * The priority field can be used to select the default (motherboard)
+   * mixer device. The mixer with the highest priority is the
+   * most preferred one. -2 or less means that this device cannot be used
+   * as the default mixer.
+   */
+  int priority;
+  oss_devnode_t devnode;	/* Device special file name (absolute path) */
+  int legacy_device;
+  int filler[245];		/* Reserved */
+} oss_mixerinfo;
+
+typedef struct oss_midi_info
+{
+  int dev;			/* Midi device number */
+  char name[64];
+  int busy;			/* 0, OPEN_READ, OPEN_WRITE or OPEN_READWRITE */
+  int pid;
+  char cmd[64];			/* Command using the device (if known) */
+  int caps;
+#define MIDI_CAP_MPU401		0x00000001	/**** OBSOLETE ****/
+#define MIDI_CAP_INPUT		0x00000002
+#define MIDI_CAP_OUTPUT		0x00000004
+#define MIDI_CAP_INOUT		(MIDI_CAP_INPUT|MIDI_CAP_OUTPUT)
+#define MIDI_CAP_VIRTUAL	0x00000008	/* Pseudo device */
+#define MIDI_CAP_MTCINPUT	0x00000010	/* Supports SNDCTL_MIDI_MTCINPUT */
+#define MIDI_CAP_CLIENT		0x00000020	/* Virtual client side device */
+#define MIDI_CAP_SERVER		0x00000040	/* Virtual server side device */
+#define MIDI_CAP_INTERNAL	0x00000080	/* Internal (synth) device */
+#define MIDI_CAP_EXTERNAL	0x00000100	/* external (MIDI port) device */
+#define MIDI_CAP_PTOP		0x00000200	/* Point to point link to one device */
+#define MIDI_CAP_MTC		0x00000400	/* MTC/SMPTE (control) device */
+  int magic;			/* Reserved for internal use */
+  int card_number;
+  int port_number;
+  int enabled;			/* 1=enabled, 0=device not ready at this moment */
+  int flags;			/* For internal use only - no practical meaning */
+  char handle[32];
+  oss_longname_t song_name;	/* Song name (if known) */
+  oss_label_t label;		/* Device label (if given) */
+  int latency;			/* In usecs, -1=unknown */
+  oss_devnode_t devnode;	/* Device special file name (absolute path) */
+  int legacy_device;		/* Legacy device mapping */
+  int filler[235];
+} oss_midi_info;
+
+typedef struct oss_card_info
+{
+  int card;
+  char shortname[16];
+  char longname[128];
+  int flags;
+  char hw_info[400];
+  int intr_count, ack_count;
+  int filler[154];
+} oss_card_info;
+
+#define SNDCTL_SYSINFO		__SIOR ('X', 1, oss_sysinfo)
+#define OSS_SYSINFO		SNDCTL_SYSINFO	/* Old name */
+
+#define SNDCTL_MIX_NRMIX	__SIOR ('X', 2, int)
+#define SNDCTL_MIX_NREXT	__SIOWR('X', 3, int)
+#define SNDCTL_MIX_EXTINFO	__SIOWR('X', 4, oss_mixext)
+#define SNDCTL_MIX_READ		__SIOWR('X', 5, oss_mixer_value)
+#define SNDCTL_MIX_WRITE	__SIOWR('X', 6, oss_mixer_value)
+
+#define SNDCTL_AUDIOINFO	__SIOWR('X', 7, oss_audioinfo)
+#define SNDCTL_MIX_ENUMINFO	__SIOWR('X', 8, oss_mixer_enuminfo)
+#define SNDCTL_MIDIINFO		__SIOWR('X', 9, oss_midi_info)
+#define SNDCTL_MIXERINFO	__SIOWR('X',10, oss_mixerinfo)
+#define SNDCTL_CARDINFO		__SIOWR('X',11, oss_card_info)
+#define SNDCTL_ENGINEINFO	__SIOWR('X',12, oss_audioinfo)
+#define SNDCTL_AUDIOINFO_EX	__SIOWR('X',13, oss_audioinfo)
+
+#define SNDCTL_MIX_DESCRIPTION	__SIOWR('X',14, oss_mixer_enuminfo)
+
+/* ioctl codes 'X', 200-255 are reserved for internal use */
+
+/*
+ * Few more "globally" available ioctl calls.
+ */
+#define SNDCTL_SETSONG		__SIOW ('Y', 2, oss_longname_t)
+#define SNDCTL_GETSONG		__SIOR ('Y', 2, oss_longname_t)
+#define SNDCTL_SETNAME		__SIOW ('Y', 3, oss_longname_t)
+#define SNDCTL_SETLABEL		__SIOW ('Y', 4, oss_label_t)
+#define SNDCTL_GETLABEL		__SIOR ('Y', 4, oss_label_t)
+/*
+ * The "new" mixer API definitions end here.
+ ***************************************
+ */
+
+/*
+ *********************************************************
+ * Few routines that are included in -lOSSlib
+ *
+ * At this moment this interface is not used. OSSlib contains just
+ * stubs that call the related system calls directly.
+ */
+#ifdef OSSLIB
+extern int osslib_open (const char *path, int flags, int dummy);
+extern void osslib_close (int fd);
+extern int osslib_write (int fd, const void *buf, int count);
+extern int osslib_read (int fd, void *buf, int count);
+extern int osslib_ioctl (int fd, unsigned int request, void *arg);
+#else
+#  define osslib_open	open
+#  define osslib_close	close
+#  define osslib_write	write
+#  define osslib_read	read
+#  define osslib_ioctl	ioctl
+#endif
+
+#if 1
+#define SNDCTL_DSP_NONBLOCK		__SIO  ('P',14)	/* Obsolete. Not supported any more */
+#endif
+
+#if 1
+/*
+ * Some obsolete macros that are not part of Open Sound System API.
+ */
+#define SOUND_PCM_READ_RATE             SOUND_PCM_READ_RATE_is_obsolete
+#define SOUND_PCM_READ_BITS             SOUND_PCM_READ_BITS_is_obsolete
+#define SOUND_PCM_READ_CHANNELS         SOUND_PCM_READ_CHANNELS_is_obsolete
+#define SOUND_PCM_WRITE_RATE            SOUND_PCM_WRITE_RATE_is_obsolet_use_SNDCTL_DSP_SPEED_instead
+#define SOUND_PCM_WRITE_CHANNELS        SOUND_PCM_WRITE_CHANNELS_is_obsolete_use_SNDCTL_DSP_CHANNELS_instead
+#define SOUND_PCM_WRITE_BITS            SOUND_PCM_WRITE_BITS_is_obsolete_use_SNDCTL_DSP_SETFMT_instead
+#define SOUND_PCM_POST                  SOUND_PCM_POST_is_obsolete_use_SNDCTL_DSP_POST_instead
+#define SOUND_PCM_RESET                 SOUND_PCM_RESET_is_obsolete_use_SNDCTL_DSP_HALT_instead
+#define SOUND_PCM_SYNC                  SOUND_PCM_SYNC_is_obsolete_use_SNDCTL_DSP_SYNC_instead
+#define SOUND_PCM_SUBDIVIDE             SOUND_PCM_SUBDIVIDE_is_obsolete_use_SNDCTL_DSP_SUBDIVIDE_instead
+#define SOUND_PCM_SETFRAGMENT           SOUND_PCM_SETFRAGMENT_is_obsolete_use_SNDCTL_DSP_SETFRAGMENT_instead
+#define SOUND_PCM_GETFMTS               SOUND_PCM_GETFMTS_is_obsolete_use_SNDCTL_DSP_GETFMTS_instead
+#define SOUND_PCM_SETFMT                SOUND_PCM_SETFMT_is_obsolete_use_SNDCTL_DSP_SETFMT_instead
+#define SOUND_PCM_GETOSPACE             SOUND_PCM_GETOSPACE_is_obsolete_use_SNDCTL_DSP_GETOSPACE_instead
+#define SOUND_PCM_GETISPACE             SOUND_PCM_GETISPACE_is_obsolete_use_SNDCTL_DSP_GETISPACE_instead
+#define SOUND_PCM_NONBLOCK              SOUND_PCM_NONBLOCK_is_obsolete_use_SNDCTL_DSP_NONBLOCK_instead
+#define SOUND_PCM_GETCAPS               SOUND_PCM_GETCAPS_is_obsolete_use_SNDCTL_DSP_GETCAPS_instead
+#define SOUND_PCM_GETTRIGGER            SOUND_PCM_GETTRIGGER_is_obsolete_use_SNDCTL_DSP_GETTRIGGER_instead
+#define SOUND_PCM_SETTRIGGER            SOUND_PCM_SETTRIGGER_is_obsolete_use_SNDCTL_DSP_SETTRIGGER_instead
+#define SOUND_PCM_SETSYNCRO             SOUND_PCM_SETSYNCRO_is_obsolete_use_SNDCTL_DSP_SETSYNCRO_instead
+#define SOUND_PCM_GETIPTR               SOUND_PCM_GETIPTR_is_obsolete_use_SNDCTL_DSP_GETIPTR_instead
+#define SOUND_PCM_GETOPTR               SOUND_PCM_GETOPTR_is_obsolete_use_SNDCTL_DSP_GETOPTR_instead
+#define SOUND_PCM_MAPINBUF              SOUND_PCM_MAPINBUF_is_obsolete_use_SNDCTL_DSP_MAPINBUF_instead
+#define SOUND_PCM_MAPOUTBUF             SOUND_PCM_MAPOUTBUF_is_obsolete_use_SNDCTL_DSP_MAPOUTBUF_instead
+#endif
+
+#endif
diff --git a/sys/oss4/oss4-source.c b/sys/oss4/oss4-source.c
new file mode 100644
index 0000000..84b315d
--- /dev/null
+++ b/sys/oss4/oss4-source.c
@@ -0,0 +1,546 @@
+/* GStreamer OSS4 audio source
+ * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-oss4src
+ *
+ * This element lets you record sound using the Open Sound System (OSS)
+ * version 4.
+ * 
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -v oss4src ! queue ! audioconvert ! vorbisenc ! oggmux ! filesink location=mymusic.ogg
+ * ]| will record sound from your sound card using OSS4 and encode it to an
+ * Ogg/Vorbis file (this will only work if your mixer settings are right
+ * and the right inputs areenabled etc.)
+ * </refsect2>
+ */
+
+/* FIXME: make sure we're not doing ioctls from the app thread (e.g. via the
+ * mixer interface) while recording */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <gst/gst-i18n-plugin.h>
+
+#define NO_LEGACY_MIXER
+#include "oss4-audio.h"
+#include "oss4-source.h"
+#include "oss4-property-probe.h"
+#include "oss4-soundcard.h"
+
+#define GST_OSS4_SOURCE_IS_OPEN(src)  (GST_OSS4_SOURCE(src)->fd != -1)
+
+GST_DEBUG_CATEGORY_EXTERN (oss4src_debug);
+#define GST_CAT_DEFAULT oss4src_debug
+
+#define DEFAULT_DEVICE       NULL
+#define DEFAULT_DEVICE_NAME  NULL
+
+enum
+{
+  PROP_0,
+  PROP_DEVICE,
+  PROP_DEVICE_NAME
+};
+
+#define gst_oss4_source_parent_class parent_class
+G_DEFINE_TYPE (GstOss4Source, gst_oss4_source, GST_TYPE_AUDIO_SRC);
+
+static void gst_oss4_source_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_oss4_source_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+
+static void gst_oss4_source_dispose (GObject * object);
+static void gst_oss4_source_finalize (GstOss4Source * osssrc);
+
+static GstCaps *gst_oss4_source_getcaps (GstBaseSrc * bsrc, GstCaps * filter);
+
+static gboolean gst_oss4_source_open (GstAudioSrc * asrc,
+    gboolean silent_errors);
+static gboolean gst_oss4_source_open_func (GstAudioSrc * asrc);
+static gboolean gst_oss4_source_close (GstAudioSrc * asrc);
+static gboolean gst_oss4_source_prepare (GstAudioSrc * asrc,
+    GstAudioRingBufferSpec * spec);
+static gboolean gst_oss4_source_unprepare (GstAudioSrc * asrc);
+static guint gst_oss4_source_read (GstAudioSrc * asrc, gpointer data,
+    guint length, GstClockTime * timestamp);
+static guint gst_oss4_source_delay (GstAudioSrc * asrc);
+static void gst_oss4_source_reset (GstAudioSrc * asrc);
+
+static void
+gst_oss4_source_class_init (GstOss4SourceClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSrcClass *gstbasesrc_class;
+  GstAudioSrcClass *gstaudiosrc_class;
+  GstPadTemplate *templ;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesrc_class = (GstBaseSrcClass *) klass;
+  gstaudiosrc_class = (GstAudioSrcClass *) klass;
+
+  gobject_class->dispose = gst_oss4_source_dispose;
+  gobject_class->finalize = (GObjectFinalizeFunc) gst_oss4_source_finalize;
+  gobject_class->get_property = gst_oss4_source_get_property;
+  gobject_class->set_property = gst_oss4_source_set_property;
+
+  gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_oss4_source_getcaps);
+
+  gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_oss4_source_open_func);
+  gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_oss4_source_prepare);
+  gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_oss4_source_unprepare);
+  gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_oss4_source_close);
+  gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_oss4_source_read);
+  gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_oss4_source_delay);
+  gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_oss4_source_reset);
+
+  g_object_class_install_property (gobject_class, PROP_DEVICE,
+      g_param_spec_string ("device", "Device",
+          "OSS4 device (e.g. /dev/oss/hdaudio0/pcm0 or /dev/dspN) "
+          "(NULL = use first available device)",
+          DEFAULT_DEVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
+      g_param_spec_string ("device-name", "Device name",
+          "Human-readable name of the sound device", DEFAULT_DEVICE_NAME,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "OSS v4 Audio Source", "Source/Audio",
+      "Capture from a sound card via OSS version 4",
+      "Tim-Philipp Müller <tim centricular net>");
+
+  templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+      gst_oss4_audio_get_template_caps ());
+  gst_element_class_add_pad_template (gstelement_class, templ);
+}
+
+static void
+gst_oss4_source_init (GstOss4Source * osssrc)
+{
+  const gchar *device;
+
+  device = g_getenv ("AUDIODEV");
+  if (device == NULL)
+    device = DEFAULT_DEVICE;
+
+  osssrc->fd = -1;
+  osssrc->device = g_strdup (device);
+  osssrc->device_name = g_strdup (DEFAULT_DEVICE_NAME);
+  osssrc->device_name = NULL;
+}
+
+static void
+gst_oss4_source_finalize (GstOss4Source * oss)
+{
+  g_free (oss->device);
+  oss->device = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (oss));
+}
+
+static void
+gst_oss4_source_dispose (GObject * object)
+{
+  GstOss4Source *oss = GST_OSS4_SOURCE (object);
+
+  if (oss->probed_caps) {
+    gst_caps_unref (oss->probed_caps);
+    oss->probed_caps = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_oss4_source_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstOss4Source *oss;
+
+  oss = GST_OSS4_SOURCE (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE:
+      GST_OBJECT_LOCK (oss);
+      if (oss->fd == -1) {
+        g_free (oss->device);
+        oss->device = g_value_dup_string (value);
+        g_free (oss->device_name);
+        oss->device_name = NULL;
+      } else {
+        g_warning ("%s: can't change \"device\" property while audio source "
+            "is open", GST_OBJECT_NAME (oss));
+      }
+      GST_OBJECT_UNLOCK (oss);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_oss4_source_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstOss4Source *oss;
+
+  oss = GST_OSS4_SOURCE (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE:
+      GST_OBJECT_LOCK (oss);
+      g_value_set_string (value, oss->device);
+      GST_OBJECT_UNLOCK (oss);
+      break;
+    case PROP_DEVICE_NAME:
+      GST_OBJECT_LOCK (oss);
+      /* If device is set, try to retrieve the name even if we're not open */
+      if (oss->fd == -1 && oss->device != NULL) {
+        if (gst_oss4_source_open (GST_AUDIO_SRC (oss), TRUE)) {
+          g_value_set_string (value, oss->device_name);
+          gst_oss4_source_close (GST_AUDIO_SRC (oss));
+        } else {
+          gchar *name = NULL;
+
+          gst_oss4_property_probe_find_device_name_nofd (GST_OBJECT (oss),
+              oss->device, &name);
+          g_value_set_string (value, name);
+          g_free (name);
+        }
+      } else {
+        g_value_set_string (value, oss->device_name);
+      }
+
+      GST_OBJECT_UNLOCK (oss);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstCaps *
+gst_oss4_source_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
+{
+  GstOss4Source *oss;
+  GstCaps *caps;
+
+  oss = GST_OSS4_SOURCE (bsrc);
+
+  if (oss->fd == -1) {
+    caps = gst_oss4_audio_get_template_caps ();
+  } else if (oss->probed_caps) {
+    caps = gst_caps_copy (oss->probed_caps);
+  } else {
+    caps = gst_oss4_audio_probe_caps (GST_OBJECT (oss), oss->fd);
+    if (caps != NULL && !gst_caps_is_empty (caps)) {
+      oss->probed_caps = gst_caps_copy (caps);
+    }
+  }
+
+  if (filter && caps) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    return intersection;
+  } else {
+    return caps;
+  }
+}
+
+/* note: we must not take the object lock here unless we fix up get_property */
+static gboolean
+gst_oss4_source_open (GstAudioSrc * asrc, gboolean silent_errors)
+{
+  GstOss4Source *oss;
+  gchar *device;
+  int mode;
+
+  oss = GST_OSS4_SOURCE (asrc);
+
+  if (oss->device)
+    device = g_strdup (oss->device);
+  else
+    device = gst_oss4_audio_find_device (GST_OBJECT_CAST (oss));
+
+  /* desperate times, desperate measures */
+  if (device == NULL)
+    device = g_strdup ("/dev/dsp0");
+
+  GST_INFO_OBJECT (oss, "Trying to open OSS4 device '%s'", device);
+
+  /* we open in non-blocking mode even if we don't really want to do writes
+   * non-blocking because we can't be sure that this is really a genuine
+   * OSS4 device with well-behaved drivers etc. We really don't want to
+   * hang forever under any circumstances. */
+  oss->fd = open (device, O_RDONLY | O_NONBLOCK, 0);
+  if (oss->fd == -1) {
+    switch (errno) {
+      case EBUSY:
+        goto busy;
+      case EACCES:
+        goto no_permission;
+      default:
+        goto open_failed;
+    }
+  }
+
+  GST_INFO_OBJECT (oss, "Opened device");
+
+  /* Make sure it's OSS4. If it's old OSS, let osssink handle it */
+  if (!gst_oss4_audio_check_version (GST_OBJECT_CAST (oss), oss->fd))
+    goto legacy_oss;
+
+  /* now remove the non-blocking flag. */
+  mode = fcntl (oss->fd, F_GETFL);
+  mode &= ~O_NONBLOCK;
+  if (fcntl (oss->fd, F_SETFL, mode) < 0) {
+    /* some drivers do no support unsetting the non-blocking flag, try to
+     * close/open the device then. This is racy but we error out properly. */
+    GST_WARNING_OBJECT (oss, "failed to unset O_NONBLOCK (buggy driver?), "
+        "will try to re-open device now");
+    gst_oss4_source_close (asrc);
+    if ((oss->fd = open (device, O_RDONLY, 0)) == -1)
+      goto non_block;
+  }
+
+  oss->open_device = device;
+
+  /* not using ENGINEINFO here because it sometimes returns a different and
+   * less useful name than AUDIOINFO for the same device */
+  if (!gst_oss4_property_probe_find_device_name (GST_OBJECT (oss), oss->fd,
+          oss->open_device, &oss->device_name)) {
+    oss->device_name = NULL;
+  }
+
+  return TRUE;
+
+  /* ERRORS */
+busy:
+  {
+    if (!silent_errors) {
+      GST_ELEMENT_ERROR (oss, RESOURCE, BUSY,
+          (_("Could not open audio device for playback. "
+                  "Device is being used by another application.")), (NULL));
+    }
+    g_free (device);
+    return FALSE;
+  }
+no_permission:
+  {
+    if (!silent_errors) {
+      GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
+          (_("Could not open audio device for playback. "
+                  "You don't have permission to open the device.")),
+          GST_ERROR_SYSTEM);
+    }
+    g_free (device);
+    return FALSE;
+  }
+open_failed:
+  {
+    if (!silent_errors) {
+      GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
+          (_("Could not open audio device for playback.")), GST_ERROR_SYSTEM);
+    }
+    g_free (device);
+    return FALSE;
+  }
+legacy_oss:
+  {
+    gst_oss4_source_close (asrc);
+    if (!silent_errors) {
+      GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
+          (_("Could not open audio device for playback. "
+                  "This version of the Open Sound System is not supported by this "
+                  "element.")), ("Try the 'osssink' element instead"));
+    }
+    g_free (device);
+    return FALSE;
+  }
+non_block:
+  {
+    if (!silent_errors) {
+      GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, (NULL),
+          ("Unable to set device %s into non-blocking mode: %s",
+              oss->device, g_strerror (errno)));
+    }
+    g_free (device);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_oss4_source_open_func (GstAudioSrc * asrc)
+{
+  return gst_oss4_source_open (asrc, FALSE);
+}
+
+static gboolean
+gst_oss4_source_close (GstAudioSrc * asrc)
+{
+  GstOss4Source *oss;
+
+  oss = GST_OSS4_SOURCE (asrc);
+
+  if (oss->fd != -1) {
+    GST_DEBUG_OBJECT (oss, "closing device");
+    close (oss->fd);
+    oss->fd = -1;
+  }
+
+  oss->bytes_per_sample = 0;
+
+  gst_caps_replace (&oss->probed_caps, NULL);
+
+  g_free (oss->open_device);
+  oss->open_device = NULL;
+
+  g_free (oss->device_name);
+  oss->device_name = NULL;
+
+  return TRUE;
+}
+
+static gboolean
+gst_oss4_source_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec)
+{
+  GstOss4Source *oss;
+
+  oss = GST_OSS4_SOURCE (asrc);
+
+  if (!gst_oss4_audio_set_format (GST_OBJECT_CAST (oss), oss->fd, spec)) {
+    GST_WARNING_OBJECT (oss, "Couldn't set requested format %" GST_PTR_FORMAT,
+        spec->caps);
+    return FALSE;
+  }
+
+  oss->bytes_per_sample = GST_AUDIO_INFO_BPF (&spec->info);
+
+  return TRUE;
+}
+
+static gboolean
+gst_oss4_source_unprepare (GstAudioSrc * asrc)
+{
+  /* could do a SNDCTL_DSP_HALT, but the OSS manual recommends a close/open,
+   * since HALT won't properly reset some devices, apparently */
+
+  if (!gst_oss4_source_close (asrc))
+    goto couldnt_close;
+
+  if (!gst_oss4_source_open_func (asrc))
+    goto couldnt_reopen;
+
+  return TRUE;
+
+  /* ERRORS */
+couldnt_close:
+  {
+    GST_DEBUG_OBJECT (asrc, "Couldn't close the audio device");
+    return FALSE;
+  }
+couldnt_reopen:
+  {
+    GST_DEBUG_OBJECT (asrc, "Couldn't reopen the audio device");
+    return FALSE;
+  }
+}
+
+static guint
+gst_oss4_source_read (GstAudioSrc * asrc, gpointer data, guint length,
+    GstClockTime * timestamp)
+{
+  GstOss4Source *oss;
+  int n;
+
+  oss = GST_OSS4_SOURCE_CAST (asrc);
+
+  n = read (oss->fd, data, length);
+  GST_LOG_OBJECT (asrc, "%u bytes, %u samples", n, n / oss->bytes_per_sample);
+
+  if (G_UNLIKELY (n < 0)) {
+    switch (errno) {
+      case ENOTSUP:
+      case EACCES:{
+        /* This is the most likely cause, I think */
+        GST_ELEMENT_ERROR (asrc, RESOURCE, READ,
+            (_("Recording is not supported by this audio device.")),
+            ("read: %s (device: %s) (maybe this is an output-only device?)",
+                g_strerror (errno), oss->open_device));
+        break;
+      }
+      default:{
+        GST_ELEMENT_ERROR (asrc, RESOURCE, READ,
+            (_("Error recording from audio device.")),
+            ("read: %s (device: %s)", g_strerror (errno), oss->open_device));
+        break;
+      }
+    }
+  }
+
+  return (guint) n;
+}
+
+static guint
+gst_oss4_source_delay (GstAudioSrc * asrc)
+{
+  audio_buf_info info = { 0, };
+  GstOss4Source *oss;
+  guint delay;
+
+  oss = GST_OSS4_SOURCE_CAST (asrc);
+
+  if (ioctl (oss->fd, SNDCTL_DSP_GETISPACE, &info) == -1) {
+    GST_LOG_OBJECT (oss, "GETISPACE failed: %s", g_strerror (errno));
+    return 0;
+  }
+
+  delay = (info.fragstotal * info.fragsize) - info.bytes;
+  GST_LOG_OBJECT (oss, "fragstotal:%d, fragsize:%d, bytes:%d, delay:%d",
+      info.fragstotal, info.fragsize, info.bytes, delay);
+  return delay;
+}
+
+static void
+gst_oss4_source_reset (GstAudioSrc * asrc)
+{
+  /* There's nothing we can do here really: OSS can't handle access to the
+   * same device/fd from multiple threads and might deadlock or blow up in
+   * other ways if we try an ioctl SNDCTL_DSP_HALT or similar */
+}
diff --git a/sys/oss4/oss4-source.h b/sys/oss4/oss4-source.h
new file mode 100644
index 0000000..91d8f13
--- /dev/null
+++ b/sys/oss4/oss4-source.h
@@ -0,0 +1,59 @@
+/* GStreamer OSS4 audio source
+ * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GST_OSS4_SOURCE_H
+#define GST_OSS4_SOURCE_H
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosrc.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_OSS4_SOURCE            (gst_oss4_source_get_type())
+#define GST_OSS4_SOURCE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS4_SOURCE,GstOss4Source))
+#define GST_OSS4_SOURCE_CAST(obj)       ((GstOss4Source *)(obj))
+#define GST_OSS4_SOURCE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS4_SOURCE,GstOss4SourceClass))
+#define GST_IS_OSS4_SOURCE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS4_SOURCE))
+#define GST_IS_OSS4_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS4_SOURCE))
+
+typedef struct _GstOss4Source GstOss4Source;
+typedef struct _GstOss4SourceClass GstOss4SourceClass;
+
+struct _GstOss4Source {
+  GstAudioSrc     audiosrc;
+
+  gchar         * device;             /* NULL if none was set      */
+  gchar         * open_device;        /* the device we opened      */
+  gchar         * device_name;        /* set if the device is open */
+  gint            fd;                 /* -1 if not open            */
+  gint            bytes_per_sample;
+
+  GstCaps       * probed_caps;
+};
+
+struct _GstOss4SourceClass {
+  GstAudioSrcClass audiosrc_class;
+};
+
+GType  gst_oss4_source_get_type (void);
+
+G_END_DECLS
+
+#endif /* GST_OSS4_SOURCE_H */
+
diff --git a/sys/osxaudio/Makefile.am b/sys/osxaudio/Makefile.am
new file mode 100644
index 0000000..a854a38
--- /dev/null
+++ b/sys/osxaudio/Makefile.am
@@ -0,0 +1,37 @@
+plugin_LTLIBRARIES = libgstosxaudio.la
+
+libgstosxaudio_la_SOURCES = gstosxaudioringbuffer.c   \
+                            gstosxaudioelement.c \
+                            gstosxaudiosink.c    \
+                            gstosxaudiosrc.c     \
+                            gstosxcoreaudiocommon.c     \
+                            gstosxcoreaudio.c     \
+                            gstosxaudio.c
+
+libgstosxaudio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \
+    -Wno-deprecated-declarations
+libgstosxaudio_la_LIBADD = 			  \
+    -lgstaudio-@GST_API_VERSION@       \
+    $(GST_PLUGINS_BASE_LIBS)          \
+    $(GST_BASE_LIBS)                  \
+    $(GST_LIBS)
+
+libgstosxaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -Wl,-framework,CoreAudio  -Wl,-framework,AudioToolbox
+
+noinst_HEADERS = gstosxaudiosink.h	  \
+                 gstosxaudiodeviceprovider.h \
+                 gstosxaudioelement.h \
+                 gstosxaudioringbuffer.h	  \
+                 gstosxaudiosrc.h     \
+                 gstosxcoreaudiocommon.h     \
+                 gstosxcoreaudio.h
+
+EXTRA_DIST = gstosxcoreaudiohal.c \
+             gstosxcoreaudioremoteio.c
+
+if !HAVE_IOS
+libgstosxaudio_la_SOURCES += gstosxaudiodeviceprovider.c
+libgstosxaudio_la_LDFLAGS += -Wl,-framework,AudioUnit -Wl,-framework,CoreServices
+else
+EXTRA_DIST += gstosxaudiodeviceprovider.c
+endif
diff --git a/sys/osxaudio/gstosxaudio.c b/sys/osxaudio/gstosxaudio.c
new file mode 100644
index 0000000..99dfdbf
--- /dev/null
+++ b/sys/osxaudio/gstosxaudio.c
@@ -0,0 +1,61 @@
+/*
+ * GStreamer
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2007,2008 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * The development of this code was made possible due to the involvement of
+ * Pioneers of the Inevitable, the creators of the Songbird Music player
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstosxaudioelement.h"
+#include "gstosxaudiosink.h"
+#include "gstosxaudiosrc.h"
+#ifndef HAVE_IOS
+#include "gstosxaudiodeviceprovider.h"
+#endif
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "osxaudiosink", GST_RANK_PRIMARY,
+          GST_TYPE_OSX_AUDIO_SINK)) {
+    return FALSE;
+  }
+  if (!gst_element_register (plugin, "osxaudiosrc", GST_RANK_PRIMARY,
+          GST_TYPE_OSX_AUDIO_SRC)) {
+    return FALSE;
+  }
+#ifndef HAVE_IOS
+  if (!gst_device_provider_register (plugin, "osxaudiodeviceprovider",
+          GST_RANK_PRIMARY, GST_TYPE_OSX_AUDIO_DEVICE_PROVIDER))
+    return FALSE;
+#endif
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    osxaudio,
+    "OSX (Mac OS X) audio support for GStreamer",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/sys/osxaudio/gstosxaudiodeviceprovider.c b/sys/osxaudio/gstosxaudiodeviceprovider.c
new file mode 100644
index 0000000..52a222f
--- /dev/null
+++ b/sys/osxaudio/gstosxaudiodeviceprovider.c
@@ -0,0 +1,380 @@
+/* GStreamer
+ * Copyright (C) 2016 Hyunjun Ko <zzoon@igalia.com>
+ *
+ * gstosxaudiodeviceprovider.c: OSX audio device probing and monitoring
+ *
+ * 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 <gst/gst.h>
+#include <gst/audio/audio.h>
+#include "gstosxaudiosrc.h"
+#include "gstosxaudiosink.h"
+#include "gstosxaudiodeviceprovider.h"
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_OSX_AUDIO_SRC_CAPS)
+    );
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_OSX_AUDIO_SINK_CAPS)
+    );
+
+static GstOsxAudioDevice *gst_osx_audio_device_new (AudioDeviceID device_id,
+    const gchar * device_name, GstOsxAudioDeviceType type,
+    GstCoreAudio * core_audio);
+
+G_DEFINE_TYPE (GstOsxAudioDeviceProvider, gst_osx_audio_device_provider,
+    GST_TYPE_DEVICE_PROVIDER);
+
+static GList *gst_osx_audio_device_provider_probe (GstDeviceProvider *
+    provider);
+
+static void
+gst_osx_audio_device_provider_class_init (GstOsxAudioDeviceProviderClass *
+    klass)
+{
+  GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS (klass);
+
+  dm_class->probe = gst_osx_audio_device_provider_probe;
+
+  gst_device_provider_class_set_static_metadata (dm_class,
+      "OSX Audio Device Provider", "Source/Sink/Audio",
+      "List and monitor OSX audio source and sink devices",
+      "Hyunjun Ko <zzoon@igalia.com>");
+}
+
+static void
+gst_osx_audio_device_provider_init (GstOsxAudioDeviceProvider * provider)
+{
+}
+
+static GstOsxAudioDevice *
+gst_osx_audio_device_provider_probe_device (GstOsxAudioDeviceProvider *
+    provider, AudioDeviceID device_id, const gchar * device_name,
+    GstOsxAudioDeviceType type)
+{
+  GstOsxAudioDevice *device = NULL;
+  GstCoreAudio *core_audio;
+
+  core_audio = gst_core_audio_new (NULL);
+  core_audio->is_src = type == GST_OSX_AUDIO_DEVICE_TYPE_SOURCE ? TRUE : FALSE;
+  core_audio->device_id = device_id;
+
+  if (!gst_core_audio_open (core_audio)) {
+    GST_ERROR ("CoreAudio device could not be opened");
+    goto done;
+  }
+
+  device = gst_osx_audio_device_new (device_id, device_name, type, core_audio);
+
+  gst_core_audio_close (core_audio);
+
+done:
+  g_object_unref (core_audio);
+
+  return device;
+}
+
+static inline gchar *
+_audio_device_get_name (AudioDeviceID device_id, gboolean output)
+{
+  OSStatus status = noErr;
+  UInt32 propertySize = 0;
+  gchar *device_name = NULL;
+  AudioObjectPropertyScope prop_scope;
+
+  AudioObjectPropertyAddress deviceNameAddress = {
+    kAudioDevicePropertyDeviceName,
+    kAudioDevicePropertyScopeOutput,
+    kAudioObjectPropertyElementMaster
+  };
+
+  prop_scope = output ? kAudioDevicePropertyScopeOutput :
+      kAudioDevicePropertyScopeInput;
+
+  deviceNameAddress.mScope = prop_scope;
+
+  /* Get the length of the device name */
+  status = AudioObjectGetPropertyDataSize (device_id,
+      &deviceNameAddress, 0, NULL, &propertySize);
+  if (status != noErr) {
+    goto beach;
+  }
+
+  /* Get the name of the device */
+  device_name = (gchar *) g_malloc (propertySize);
+  status = AudioObjectGetPropertyData (device_id,
+      &deviceNameAddress, 0, NULL, &propertySize, device_name);
+  if (status != noErr) {
+    g_free (device_name);
+    device_name = NULL;
+  }
+
+beach:
+  return device_name;
+}
+
+static inline gboolean
+_audio_device_has_output (AudioDeviceID device_id)
+{
+  OSStatus status = noErr;
+  UInt32 propertySize;
+
+  AudioObjectPropertyAddress streamsAddress = {
+    kAudioDevicePropertyStreams,
+    kAudioDevicePropertyScopeOutput,
+    kAudioObjectPropertyElementMaster
+  };
+
+  status = AudioObjectGetPropertyDataSize (device_id,
+      &streamsAddress, 0, NULL, &propertySize);
+  if (status != noErr) {
+    return FALSE;
+  }
+  if (propertySize == 0) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static inline AudioDeviceID *
+_audio_system_get_devices (gint * ndevices)
+{
+  OSStatus status = noErr;
+  UInt32 propertySize = 0;
+  AudioDeviceID *devices = NULL;
+
+  AudioObjectPropertyAddress audioDevicesAddress = {
+    kAudioHardwarePropertyDevices,
+    kAudioObjectPropertyScopeGlobal,
+    kAudioObjectPropertyElementMaster
+  };
+
+  status = AudioObjectGetPropertyDataSize (kAudioObjectSystemObject,
+      &audioDevicesAddress, 0, NULL, &propertySize);
+  if (status != noErr) {
+    GST_WARNING ("failed getting number of devices: %d", (int) status);
+    return NULL;
+  }
+
+  *ndevices = propertySize / sizeof (AudioDeviceID);
+
+  devices = (AudioDeviceID *) g_malloc (propertySize);
+  if (devices) {
+    status = AudioObjectGetPropertyData (kAudioObjectSystemObject,
+        &audioDevicesAddress, 0, NULL, &propertySize, devices);
+    if (status != noErr) {
+      GST_WARNING ("failed getting the list of devices: %d", (int) status);
+      g_free (devices);
+      *ndevices = 0;
+      return NULL;
+    }
+  }
+
+  return devices;
+}
+
+static GList *
+gst_osx_audio_device_provider_probe (GstDeviceProvider * provider)
+{
+  GstOsxAudioDeviceProvider *self = GST_OSX_AUDIO_DEVICE_PROVIDER (provider);
+  GList *devices = NULL;
+  GstOsxAudioDevice *device = NULL;
+  AudioDeviceID *osx_devices = NULL;
+  gint i, ndevices = 0;
+
+  osx_devices = _audio_system_get_devices (&ndevices);
+
+  if (ndevices < 1) {
+    GST_WARNING ("no audio output devices found");
+    goto done;
+  }
+
+  GST_INFO ("found %d audio device(s)", ndevices);
+
+  for (i = 0; i < ndevices; i++) {
+    gchar *device_name;
+    GstOsxAudioDeviceType type = GST_OSX_AUDIO_DEVICE_TYPE_INVALID;
+
+    if ((device_name = _audio_device_get_name (osx_devices[i], FALSE))) {
+      if (!_audio_device_has_output (osx_devices[i])) {
+        GST_DEBUG ("Input Device ID: %u Name: %s",
+            (unsigned) osx_devices[i], device_name);
+        type = GST_OSX_AUDIO_DEVICE_TYPE_SOURCE;
+
+      } else {
+        GST_DEBUG ("Output Device ID: %u Name: %s",
+            (unsigned) osx_devices[i], device_name);
+        type = GST_OSX_AUDIO_DEVICE_TYPE_SINK;
+      }
+
+      device =
+          gst_osx_audio_device_provider_probe_device (self, osx_devices[i],
+          device_name, type);
+      if (device) {
+        gst_object_ref_sink (device);
+        devices = g_list_prepend (devices, device);
+      }
+
+      g_free (device_name);
+    }
+  }
+
+done:
+  g_free (osx_devices);
+
+  return devices;
+}
+
+enum
+{
+  PROP_DEVICE_ID = 1,
+};
+
+G_DEFINE_TYPE (GstOsxAudioDevice, gst_osx_audio_device, GST_TYPE_DEVICE);
+
+static void gst_osx_audio_device_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_osx_audio_device_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static GstElement *gst_osx_audio_device_create_element (GstDevice * device,
+    const gchar * name);
+
+static void
+gst_osx_audio_device_class_init (GstOsxAudioDeviceClass * klass)
+{
+  GstDeviceClass *dev_class = GST_DEVICE_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  dev_class->create_element = gst_osx_audio_device_create_element;
+
+  object_class->get_property = gst_osx_audio_device_get_property;
+  object_class->set_property = gst_osx_audio_device_set_property;
+
+  g_object_class_install_property (object_class, PROP_DEVICE_ID,
+      g_param_spec_int ("device-id", "Device ID", "Device ID of input device",
+          0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_osx_audio_device_init (GstOsxAudioDevice * device)
+{
+}
+
+static GstElement *
+gst_osx_audio_device_create_element (GstDevice * device, const gchar * name)
+{
+  GstOsxAudioDevice *osxdev = GST_OSX_AUDIO_DEVICE (device);
+  GstElement *elem;
+
+  elem = gst_element_factory_make (osxdev->element, name);
+  g_object_set (elem, "device", osxdev->device_id, NULL);
+
+  return elem;
+}
+
+static GstOsxAudioDevice *
+gst_osx_audio_device_new (AudioDeviceID device_id, const gchar * device_name,
+    GstOsxAudioDeviceType type, GstCoreAudio * core_audio)
+{
+  GstOsxAudioDevice *gstdev;
+  const gchar *element_name = NULL;
+  const gchar *klass = NULL;
+  GstCaps *template_caps, *caps;
+
+  g_return_val_if_fail (device_id > 0, NULL);
+  g_return_val_if_fail (device_name, NULL);
+
+  switch (type) {
+    case GST_OSX_AUDIO_DEVICE_TYPE_SOURCE:
+      element_name = "osxaudiosrc";
+      klass = "Audio/Source";
+
+      template_caps = gst_static_pad_template_get_caps (&src_factory);
+      caps = gst_core_audio_probe_caps (core_audio, template_caps);
+      gst_caps_unref (template_caps);
+
+      break;
+    case GST_OSX_AUDIO_DEVICE_TYPE_SINK:
+      element_name = "osxaudiosink";
+      klass = "Audio/Sink";
+
+      template_caps = gst_static_pad_template_get_caps (&sink_factory);
+      caps = gst_core_audio_probe_caps (core_audio, template_caps);
+      gst_caps_unref (template_caps);
+
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+
+  gstdev = g_object_new (GST_TYPE_OSX_AUDIO_DEVICE, "device-id",
+      device_id, "display-name", device_name, "caps", caps, "device-class",
+      klass, NULL);
+
+  gstdev->element = element_name;
+
+
+  return gstdev;
+}
+
+static void
+gst_osx_audio_device_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstOsxAudioDevice *device;
+
+  device = GST_OSX_AUDIO_DEVICE_CAST (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE_ID:
+      g_value_set_int (value, device->device_id);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+
+static void
+gst_osx_audio_device_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstOsxAudioDevice *device;
+
+  device = GST_OSX_AUDIO_DEVICE_CAST (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE_ID:
+      device->device_id = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/sys/osxaudio/gstosxaudiodeviceprovider.h b/sys/osxaudio/gstosxaudiodeviceprovider.h
new file mode 100644
index 0000000..bd54178
--- /dev/null
+++ b/sys/osxaudio/gstosxaudiodeviceprovider.h
@@ -0,0 +1,91 @@
+/* GStreamer
+ * Copyright (C) 2016 Hyunjun Ko <zzoon@igalia.com>
+ *
+ * gstosxaudiodeviceeprovider.h: OSX audio probing and monitoring
+ *
+ * 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_OSX_AUDIO_DEIVCE_PROVIDER_H__
+#define __GST_OSX_AUDIO_DEIVCE_PROVIDER_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include "gstosxcoreaudiocommon.h"
+
+G_BEGIN_DECLS
+typedef struct _GstOsxAudioDeviceProvider GstOsxAudioDeviceProvider;
+typedef struct _GstOsxAudioDeviceProviderClass GstOsxAudioDeviceProviderClass;
+
+#define GST_TYPE_OSX_AUDIO_DEVICE_PROVIDER                 (gst_osx_audio_device_provider_get_type())
+#define GST_IS_OSX_AUDIO_DEVICE_PROVIDER(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_OSX_AUDIO_DEVICE_PROVIDER))
+#define GST_IS_OSX_AUDIO_DEVICE_PROVIDER_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_OSX_AUDIO_DEVICE_PROVIDER))
+#define GST_OSX_AUDIO_DEVICE_PROVIDER_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_OSX_AUDIO_DEVICE_PROVIDER, GstOsxAudioDeviceProviderClass))
+#define GST_OSX_AUDIO_DEVICE_PROVIDER(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_OSX_AUDIO_DEVICE_PROVIDER, GstOsxAudioDeviceProvider))
+#define GST_OSX_AUDIO_DEVICE_PROVIDER_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE_PROVIDER, GstOsxAudioDeviceProviderClass))
+#define GST_OSX_AUDIO_DEVICE_PROVIDER_CAST(obj)            ((GstOsxAudioDeviceProvider *)(obj))
+
+struct _GstOsxAudioDeviceProvider
+{
+  GstDeviceProvider parent;
+};
+
+struct _GstOsxAudioDeviceProviderClass
+{
+  GstDeviceProviderClass parent_class;
+};
+
+GType gst_osx_audio_device_provider_get_type (void);
+
+typedef struct _GstOsxAudioDevice GstOsxAudioDevice;
+typedef struct _GstOsxAudioDeviceClass GstOsxAudioDeviceClass;
+
+#define GST_TYPE_OSX_AUDIO_DEVICE                 (gst_osx_audio_device_get_type())
+#define GST_IS_OSX_AUDIO_DEVICE(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_OSX_AUDIO_DEVICE))
+#define GST_IS_OSX_AUDIO_DEVICE_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_OSX_AUDIO_DEVICE))
+#define GST_OSX_AUDIO_DEVICE_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_OSX_AUDIO_DEVICE, GstOsxAudioClass))
+#define GST_OSX_AUDIO_DEVICE(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_OSX_AUDIO_DEVICE, GstOsxAudioDevice))
+#define GST_OSX_AUDIO_DEVICE_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE, GstOsxAudioDeviceClass))
+#define GST_OSX_AUDIO_DEVICE_CAST(obj)            ((GstOsxAudioDevice *)(obj))
+
+typedef enum
+{
+  GST_OSX_AUDIO_DEVICE_TYPE_INVALID = 0,
+  GST_OSX_AUDIO_DEVICE_TYPE_SOURCE,
+  GST_OSX_AUDIO_DEVICE_TYPE_SINK
+} GstOsxAudioDeviceType;
+
+struct _GstOsxAudioDevice
+{
+  GstDevice parent;
+
+  const gchar *element;
+  AudioDeviceID device_id;
+};
+
+struct _GstOsxAudioDeviceClass
+{
+  GstDeviceClass parent_class;
+};
+
+GType gst_osx_audio_device_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_OSX_AUDIO_DEIVCE_PROVIDER_H__ */
diff --git a/sys/osxaudio/gstosxaudioelement.c b/sys/osxaudio/gstosxaudioelement.c
new file mode 100644
index 0000000..bec24d1
--- /dev/null
+++ b/sys/osxaudio/gstosxaudioelement.c
@@ -0,0 +1,92 @@
+/*
+ * GStreamer
+ * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * The development of this code was made possible due to the involvement of
+ * Pioneers of the Inevitable, the creators of the Songbird Music player
+ *
+ */
+
+#include "gstosxaudioelement.h"
+#include <gst/gst.h>
+
+static void
+gst_osx_audio_element_interface_init (GstOsxAudioElementInterface * iface);
+
+GType
+gst_osx_audio_element_get_type (void)
+{
+  static GType gst_osxaudioelement_type = 0;
+
+  if (!gst_osxaudioelement_type) {
+    static const GTypeInfo gst_osxaudioelement_info = {
+      sizeof (GstOsxAudioElementInterface),
+      (GBaseInitFunc) gst_osx_audio_element_interface_init,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      0,
+      0,
+      NULL,
+      NULL
+    };
+
+    gst_osxaudioelement_type = g_type_register_static (G_TYPE_INTERFACE,
+        "GstOsxAudioElement", &gst_osxaudioelement_info, 0);
+  }
+
+  return gst_osxaudioelement_type;
+}
+
+static void
+gst_osx_audio_element_interface_init (GstOsxAudioElementInterface * iface)
+{
+  static gboolean initialized = FALSE;
+
+  if (!initialized) {
+    initialized = TRUE;
+  }
+
+  /* default virtual functions */
+  iface->io_proc = NULL;
+}
diff --git a/sys/osxaudio/gstosxaudioelement.h b/sys/osxaudio/gstosxaudioelement.h
new file mode 100644
index 0000000..3e09dc1
--- /dev/null
+++ b/sys/osxaudio/gstosxaudioelement.h
@@ -0,0 +1,92 @@
+/*
+ * GStreamer
+ * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * The development of this code was made possible due to the involvement of
+ * Pioneers of the Inevitable, the creators of the Songbird Music player
+ *
+ */
+
+#ifndef __GST_OSX_AUDIO_ELEMENT_H__
+#define __GST_OSX_AUDIO_ELEMENT_H__
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <gst/gst.h>
+#ifdef HAVE_IOS
+#include <CoreAudio/CoreAudioTypes.h>
+#else
+#include <CoreAudio/CoreAudio.h>
+#endif
+#include <AudioUnit/AudioUnit.h>
+
+G_BEGIN_DECLS
+
+#define GST_OSX_AUDIO_ELEMENT_TYPE \
+  (gst_osx_audio_element_get_type())
+#define GST_OSX_AUDIO_ELEMENT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_OSX_AUDIO_ELEMENT_TYPE,GstOsxAudioElementInterface))
+#define GST_IS_OSX_AUDIO_ELEMENT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_OSX_AUDIO_ELEMENT_TYPE))
+#define GST_OSX_AUDIO_ELEMENT_GET_INTERFACE(inst) \
+  (G_TYPE_INSTANCE_GET_INTERFACE((inst),GST_OSX_AUDIO_ELEMENT_TYPE,GstOsxAudioElementInterface))
+
+typedef struct _GstOsxAudioElementInterface GstOsxAudioElementInterface;
+
+struct _GstOsxAudioElementInterface
+{
+  GTypeInterface parent;
+
+  OSStatus (*io_proc) (void * userdata,
+      AudioUnitRenderActionFlags * ioActionFlags,
+      const AudioTimeStamp * inTimeStamp,
+      UInt32 inBusNumber, UInt32 inNumberFrames,
+      AudioBufferList * bufferList);
+};
+
+GType gst_osx_audio_element_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_OSX_AUDIO_ELEMENT_H__ */
diff --git a/sys/osxaudio/gstosxaudioringbuffer.c b/sys/osxaudio/gstosxaudioringbuffer.c
new file mode 100644
index 0000000..4201e04
--- /dev/null
+++ b/sys/osxaudio/gstosxaudioringbuffer.c
@@ -0,0 +1,318 @@
+/*
+ * GStreamer
+ * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2008 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ * Copyright (C) 2012 Fluendo S.A. <support@fluendo.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <gst/gst.h>
+#include <gst/gst-i18n-plugin.h>
+#include <gst/audio/audio-channels.h>
+#include "gstosxaudioringbuffer.h"
+#include "gstosxaudiosink.h"
+#include "gstosxaudiosrc.h"
+
+#include <unistd.h>             /* for getpid() */
+
+GST_DEBUG_CATEGORY_STATIC (osx_audio_debug);
+#define GST_CAT_DEFAULT osx_audio_debug
+
+#include "gstosxcoreaudio.h"
+
+static void gst_osx_audio_ring_buffer_dispose (GObject * object);
+static gboolean gst_osx_audio_ring_buffer_open_device (GstAudioRingBuffer *
+    buf);
+static gboolean gst_osx_audio_ring_buffer_close_device (GstAudioRingBuffer *
+    buf);
+
+static gboolean gst_osx_audio_ring_buffer_acquire (GstAudioRingBuffer * buf,
+    GstAudioRingBufferSpec * spec);
+static gboolean gst_osx_audio_ring_buffer_release (GstAudioRingBuffer * buf);
+
+static gboolean gst_osx_audio_ring_buffer_start (GstAudioRingBuffer * buf);
+static gboolean gst_osx_audio_ring_buffer_pause (GstAudioRingBuffer * buf);
+static gboolean gst_osx_audio_ring_buffer_stop (GstAudioRingBuffer * buf);
+static guint gst_osx_audio_ring_buffer_delay (GstAudioRingBuffer * buf);
+static GstAudioRingBufferClass *ring_parent_class = NULL;
+
+#define gst_osx_audio_ring_buffer_do_init \
+  GST_DEBUG_CATEGORY_INIT (osx_audio_debug, "osxaudio", 0, "OSX Audio Elements");
+
+G_DEFINE_TYPE_WITH_CODE (GstOsxAudioRingBuffer, gst_osx_audio_ring_buffer,
+    GST_TYPE_AUDIO_RING_BUFFER, gst_osx_audio_ring_buffer_do_init);
+
+static void
+gst_osx_audio_ring_buffer_class_init (GstOsxAudioRingBufferClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstAudioRingBufferClass *gstringbuffer_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstringbuffer_class = (GstAudioRingBufferClass *) klass;
+
+  ring_parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->dispose = gst_osx_audio_ring_buffer_dispose;
+
+  gstringbuffer_class->open_device =
+      GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_open_device);
+  gstringbuffer_class->close_device =
+      GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_close_device);
+  gstringbuffer_class->acquire =
+      GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_acquire);
+  gstringbuffer_class->release =
+      GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_release);
+  gstringbuffer_class->start =
+      GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_start);
+  gstringbuffer_class->pause =
+      GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_pause);
+  gstringbuffer_class->resume =
+      GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_start);
+  gstringbuffer_class->stop =
+      GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_stop);
+  gstringbuffer_class->delay =
+      GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_delay);
+
+  GST_DEBUG ("osx audio ring buffer class init");
+}
+
+static void
+gst_osx_audio_ring_buffer_init (GstOsxAudioRingBuffer * ringbuffer)
+{
+  ringbuffer->core_audio = gst_core_audio_new (GST_OBJECT (ringbuffer));
+}
+
+static void
+gst_osx_audio_ring_buffer_dispose (GObject * object)
+{
+  GstOsxAudioRingBuffer *osxbuf;
+
+  osxbuf = GST_OSX_AUDIO_RING_BUFFER (object);
+
+  if (osxbuf->core_audio) {
+    g_object_unref (osxbuf->core_audio);
+    osxbuf->core_audio = NULL;
+  }
+  G_OBJECT_CLASS (ring_parent_class)->dispose (object);
+}
+
+static gboolean
+gst_osx_audio_ring_buffer_open_device (GstAudioRingBuffer * buf)
+{
+  GstObject *osxel = GST_OBJECT_PARENT (buf);
+  GstOsxAudioRingBuffer *osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf);
+
+  if (!gst_core_audio_select_device (osxbuf->core_audio)) {
+    GST_ELEMENT_ERROR (osxel, RESOURCE, NOT_FOUND,
+        (_("CoreAudio device not found")), (NULL));
+    return FALSE;
+  }
+
+  if (!gst_core_audio_open (osxbuf->core_audio)) {
+    GST_ELEMENT_ERROR (osxel, RESOURCE, OPEN_READ,
+        (_("CoreAudio device could not be opened")), (NULL));
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_osx_audio_ring_buffer_close_device (GstAudioRingBuffer * buf)
+{
+  GstOsxAudioRingBuffer *osxbuf;
+  osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf);
+
+  return gst_core_audio_close (osxbuf->core_audio);
+}
+
+static gboolean
+gst_osx_audio_ring_buffer_acquire (GstAudioRingBuffer * buf,
+    GstAudioRingBufferSpec * spec)
+{
+  gboolean ret = FALSE, is_passthrough = FALSE;
+  GstOsxAudioRingBuffer *osxbuf;
+  AudioStreamBasicDescription format;
+
+  osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf);
+
+  if (RINGBUFFER_IS_SPDIF (spec->type)) {
+    format.mFormatID = kAudioFormat60958AC3;
+    format.mSampleRate = (double) GST_AUDIO_INFO_RATE (&spec->info);
+    format.mChannelsPerFrame = 2;
+    format.mFormatFlags = kAudioFormatFlagIsSignedInteger |
+        kAudioFormatFlagIsPacked | kAudioFormatFlagIsNonMixable;
+    format.mBytesPerFrame = 0;
+    format.mBitsPerChannel = 16;
+    format.mBytesPerPacket = 6144;
+    format.mFramesPerPacket = 1536;
+    format.mReserved = 0;
+    spec->segsize = 6144;
+    spec->segtotal = 10;
+    is_passthrough = TRUE;
+  } else {
+    int width, depth;
+    /* Fill out the audio description we're going to be using */
+    format.mFormatID = kAudioFormatLinearPCM;
+    format.mSampleRate = (double) GST_AUDIO_INFO_RATE (&spec->info);
+    format.mChannelsPerFrame = GST_AUDIO_INFO_CHANNELS (&spec->info);
+    if (GST_AUDIO_INFO_IS_FLOAT (&spec->info)) {
+      format.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
+      width = depth = GST_AUDIO_INFO_WIDTH (&spec->info);
+    } else {
+      format.mFormatFlags = kAudioFormatFlagIsSignedInteger;
+      width = GST_AUDIO_INFO_WIDTH (&spec->info);
+      depth = GST_AUDIO_INFO_DEPTH (&spec->info);
+      if (width == depth) {
+        format.mFormatFlags |= kAudioFormatFlagIsPacked;
+      } else {
+        format.mFormatFlags |= kAudioFormatFlagIsAlignedHigh;
+      }
+    }
+
+    if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&spec->info)) {
+      format.mFormatFlags |= kAudioFormatFlagIsBigEndian;
+    }
+
+    format.mBytesPerFrame = GST_AUDIO_INFO_BPF (&spec->info);
+    format.mBitsPerChannel = depth;
+    format.mBytesPerPacket = GST_AUDIO_INFO_BPF (&spec->info);
+    format.mFramesPerPacket = 1;
+    format.mReserved = 0;
+    spec->segsize =
+        (spec->latency_time * GST_AUDIO_INFO_RATE (&spec->info) /
+        G_USEC_PER_SEC) * GST_AUDIO_INFO_BPF (&spec->info);
+    spec->segtotal = spec->buffer_time / spec->latency_time;
+    is_passthrough = FALSE;
+  }
+
+  GST_DEBUG_OBJECT (osxbuf, "Format: " CORE_AUDIO_FORMAT,
+      CORE_AUDIO_FORMAT_ARGS (format));
+
+  /* gst_audio_ring_buffer_set_channel_positions is not called
+   * since the AUs perform channel reordering themselves.
+   * (see gst_core_audio_set_channel_layout) */
+
+  buf->size = spec->segtotal * spec->segsize;
+  buf->memory = g_malloc0 (buf->size);
+
+  ret = gst_core_audio_initialize (osxbuf->core_audio, format, spec->caps,
+      is_passthrough);
+
+  if (!ret) {
+    g_free (buf->memory);
+    buf->memory = NULL;
+    buf->size = 0;
+  }
+
+  osxbuf->segoffset = 0;
+
+  return ret;
+}
+
+static gboolean
+gst_osx_audio_ring_buffer_release (GstAudioRingBuffer * buf)
+{
+  GstOsxAudioRingBuffer *osxbuf;
+
+  osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf);
+
+  gst_core_audio_uninitialize (osxbuf->core_audio);
+
+  g_free (buf->memory);
+  buf->memory = NULL;
+  buf->size = 0;
+
+  return TRUE;
+}
+
+static gboolean
+gst_osx_audio_ring_buffer_start (GstAudioRingBuffer * buf)
+{
+  GstOsxAudioRingBuffer *osxbuf;
+
+  osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf);
+
+  return gst_core_audio_start_processing (osxbuf->core_audio);
+}
+
+static gboolean
+gst_osx_audio_ring_buffer_pause (GstAudioRingBuffer * buf)
+{
+  GstOsxAudioRingBuffer *osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf);
+
+  return gst_core_audio_pause_processing (osxbuf->core_audio);
+}
+
+
+static gboolean
+gst_osx_audio_ring_buffer_stop (GstAudioRingBuffer * buf)
+{
+  GstOsxAudioRingBuffer *osxbuf;
+
+  osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf);
+
+  gst_core_audio_stop_processing (osxbuf->core_audio);
+
+  return TRUE;
+}
+
+static guint
+gst_osx_audio_ring_buffer_delay (GstAudioRingBuffer * buf)
+{
+  GstOsxAudioRingBuffer *osxbuf;
+  double latency;
+  guint samples;
+
+  osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf);
+
+  if (!gst_core_audio_get_samples_and_latency (osxbuf->core_audio,
+          GST_AUDIO_INFO_RATE (&buf->spec.info), &samples, &latency)) {
+    return 0;
+  }
+  GST_DEBUG_OBJECT (buf, "Got latency: %f seconds -> %d samples",
+      latency, samples);
+  return samples;
+}
diff --git a/sys/osxaudio/gstosxaudioringbuffer.h b/sys/osxaudio/gstosxaudioringbuffer.h
new file mode 100644
index 0000000..5054fd3
--- /dev/null
+++ b/sys/osxaudio/gstosxaudioringbuffer.h
@@ -0,0 +1,98 @@
+/*
+ * GStreamer
+ * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2012 Fluendo S.A. <support@fluendo.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_OSX_RING_BUFFER_H__
+#define __GST_OSX_RING_BUFFER_H__
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudioringbuffer.h>
+#include <gstosxcoreaudio.h>
+
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_OSX_AUDIO_RING_BUFFER \
+  (gst_osx_audio_ring_buffer_get_type())
+#define GST_OSX_AUDIO_RING_BUFFER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSX_AUDIO_RING_BUFFER,GstOsxAudioRingBuffer))
+#define GST_OSX_AUDIO_RING_BUFFER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSX_AUDIO_RING_BUFFER,GstOsxAudioRingBufferClass))
+#define GST_OSX_AUDIO_RING_BUFFER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_OSX_AUDIO_RING_BUFFER,GstOsxAudioRingBufferClass))
+#define GST_IS_OSX_AUDIO_RING_BUFFER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSX_AUDIO_RING_BUFFER))
+#define GST_IS_OSX_AUDIO_RING_BUFFER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSX_AUDIO_RING_BUFFER))
+
+#define RINGBUFFER_IS_SPDIF(t) ((t) == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3 || (t) == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS)
+
+typedef struct _GstOsxAudioRingBuffer GstOsxAudioRingBuffer;
+typedef struct _GstOsxAudioRingBufferClass GstOsxAudioRingBufferClass;
+
+struct _GstOsxAudioRingBuffer
+{
+  GstAudioRingBuffer object;
+
+  GstCoreAudio *core_audio;
+
+  guint buffer_len;
+  guint segoffset;
+};
+
+struct _GstOsxAudioRingBufferClass
+{
+  GstAudioRingBufferClass parent_class;
+};
+
+GType gst_osx_audio_ring_buffer_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_OSX_AUDIO_RING_BUFFER_H__ */
+
diff --git a/sys/osxaudio/gstosxaudiosink.c b/sys/osxaudio/gstosxaudiosink.c
new file mode 100644
index 0000000..a1fd158
--- /dev/null
+++ b/sys/osxaudio/gstosxaudiosink.c
@@ -0,0 +1,573 @@
+/*
+ * GStreamer
+ * Copyright (C) 2005,2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2007,2008 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ * Copyright (C) 2012 Fluendo S.A. <support@fluendo.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * The development of this code was made possible due to the involvement of
+ * Pioneers of the Inevitable, the creators of the Songbird Music player
+ *
+ */
+
+/**
+ * SECTION:element-osxaudiosink
+ *
+ * This element renders raw audio samples using the CoreAudio api.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! osxaudiosink
+ * ]| Play an Ogg/Vorbis file.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/audio-channels.h>
+#include <gst/audio/gstaudioiec61937.h>
+
+#include "gstosxaudiosink.h"
+#include "gstosxaudioelement.h"
+
+GST_DEBUG_CATEGORY_STATIC (osx_audiosink_debug);
+#define GST_CAT_DEFAULT osx_audiosink_debug
+
+#include "gstosxcoreaudio.h"
+
+/* Filter signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  ARG_0,
+  ARG_DEVICE,
+  ARG_VOLUME
+};
+
+#define DEFAULT_VOLUME 1.0
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_OSX_AUDIO_SINK_CAPS)
+    );
+
+static void gst_osx_audio_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_osx_audio_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn
+gst_osx_audio_sink_change_state (GstElement * element,
+    GstStateChange transition);
+
+static gboolean gst_osx_audio_sink_query (GstBaseSink * base, GstQuery * query);
+
+static GstCaps *gst_osx_audio_sink_getcaps (GstBaseSink * base,
+    GstCaps * filter);
+static gboolean gst_osx_audio_sink_acceptcaps (GstOsxAudioSink * sink,
+    GstCaps * caps);
+
+static GstBuffer *gst_osx_audio_sink_sink_payload (GstAudioBaseSink * sink,
+    GstBuffer * buf);
+static GstAudioRingBuffer
+    * gst_osx_audio_sink_create_ringbuffer (GstAudioBaseSink * sink);
+static void gst_osx_audio_sink_osxelement_init (gpointer g_iface,
+    gpointer iface_data);
+static void gst_osx_audio_sink_set_volume (GstOsxAudioSink * sink);
+
+static OSStatus gst_osx_audio_sink_io_proc (GstOsxAudioRingBuffer * buf,
+    AudioUnitRenderActionFlags * ioActionFlags,
+    const AudioTimeStamp * inTimeStamp,
+    UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * bufferList);
+
+static void
+gst_osx_audio_sink_do_init (GType type)
+{
+  static const GInterfaceInfo osxelement_info = {
+    gst_osx_audio_sink_osxelement_init,
+    NULL,
+    NULL
+  };
+
+  GST_DEBUG_CATEGORY_INIT (osx_audiosink_debug, "osxaudiosink", 0,
+      "OSX Audio Sink");
+  gst_core_audio_init_debug ();
+  GST_DEBUG ("Adding static interface");
+  g_type_add_interface_static (type, GST_OSX_AUDIO_ELEMENT_TYPE,
+      &osxelement_info);
+}
+
+#define gst_osx_audio_sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstOsxAudioSink, gst_osx_audio_sink,
+    GST_TYPE_AUDIO_BASE_SINK, gst_osx_audio_sink_do_init (g_define_type_id));
+
+static void
+gst_osx_audio_sink_class_init (GstOsxAudioSinkClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSinkClass *gstbasesink_class;
+  GstAudioBaseSinkClass *gstaudiobasesink_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesink_class = (GstBaseSinkClass *) klass;
+  gstaudiobasesink_class = (GstAudioBaseSinkClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->set_property = gst_osx_audio_sink_set_property;
+  gobject_class->get_property = gst_osx_audio_sink_get_property;
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_osx_audio_sink_change_state);
+
+#ifndef HAVE_IOS
+  g_object_class_install_property (gobject_class, ARG_DEVICE,
+      g_param_spec_int ("device", "Device ID", "Device ID of output device",
+          0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#endif
+
+  gstbasesink_class->query = GST_DEBUG_FUNCPTR (gst_osx_audio_sink_query);
+
+  g_object_class_install_property (gobject_class, ARG_VOLUME,
+      g_param_spec_double ("volume", "Volume", "Volume of this stream",
+          0, 1.0, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_osx_audio_sink_getcaps);
+
+  gstaudiobasesink_class->create_ringbuffer =
+      GST_DEBUG_FUNCPTR (gst_osx_audio_sink_create_ringbuffer);
+  gstaudiobasesink_class->payload =
+      GST_DEBUG_FUNCPTR (gst_osx_audio_sink_sink_payload);
+
+  gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class, "Audio Sink (OSX)",
+      "Sink/Audio",
+      "Output to a sound card in OS X",
+      "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
+}
+
+static void
+gst_osx_audio_sink_init (GstOsxAudioSink * sink)
+{
+  GST_DEBUG ("Initialising object");
+
+  sink->device_id = kAudioDeviceUnknown;
+  sink->volume = DEFAULT_VOLUME;
+}
+
+static void
+gst_osx_audio_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (object);
+
+  switch (prop_id) {
+#ifndef HAVE_IOS
+    case ARG_DEVICE:
+      sink->device_id = g_value_get_int (value);
+      break;
+#endif
+    case ARG_VOLUME:
+      sink->volume = g_value_get_double (value);
+      gst_osx_audio_sink_set_volume (sink);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStateChangeReturn
+gst_osx_audio_sink_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstOsxAudioSink *osxsink = GST_OSX_AUDIO_SINK (element);
+  GstOsxAudioRingBuffer *ringbuffer;
+  GstStateChangeReturn ret;
+
+  switch (transition) {
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    goto out;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      /* Device has been selected, AudioUnit set up, so initialize volume */
+      gst_osx_audio_sink_set_volume (osxsink);
+
+      /* The device is open now, so fix our device_id if it changed */
+      ringbuffer =
+          GST_OSX_AUDIO_RING_BUFFER (GST_AUDIO_BASE_SINK (osxsink)->ringbuffer);
+      if (ringbuffer->core_audio->device_id != osxsink->device_id) {
+        osxsink->device_id = ringbuffer->core_audio->device_id;
+        g_object_notify (G_OBJECT (osxsink), "device");
+      }
+      break;
+
+    default:
+      break;
+  }
+
+out:
+  return ret;
+}
+
+static void
+gst_osx_audio_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (object);
+  switch (prop_id) {
+#ifndef HAVE_IOS
+    case ARG_DEVICE:
+      g_value_set_int (value, sink->device_id);
+      break;
+#endif
+    case ARG_VOLUME:
+      g_value_set_double (value, sink->volume);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_osx_audio_sink_query (GstBaseSink * base, GstQuery * query)
+{
+  GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (base);
+  gboolean ret = FALSE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_ACCEPT_CAPS:
+    {
+      GstCaps *caps = NULL;
+
+      gst_query_parse_accept_caps (query, &caps);
+      ret = gst_osx_audio_sink_acceptcaps (sink, caps);
+      gst_query_set_accept_caps_result (query, ret);
+      ret = TRUE;
+      break;
+    }
+    default:
+      ret = GST_BASE_SINK_CLASS (parent_class)->query (base, query);
+      break;
+  }
+  return ret;
+}
+
+static GstCaps *
+gst_osx_audio_sink_getcaps (GstBaseSink * sink, GstCaps * filter)
+{
+  GstOsxAudioSink *osxsink;
+  GstAudioRingBuffer *buf;
+  GstOsxAudioRingBuffer *osxbuf;
+  GstCaps *caps, *filtered_caps;
+
+  osxsink = GST_OSX_AUDIO_SINK (sink);
+
+  GST_OBJECT_LOCK (osxsink);
+  buf = GST_AUDIO_BASE_SINK (sink)->ringbuffer;
+  if (buf)
+    gst_object_ref (buf);
+  GST_OBJECT_UNLOCK (osxsink);
+
+  if (!buf) {
+    GST_DEBUG_OBJECT (sink, "no ring buffer, returning NULL caps");
+    return GST_BASE_SINK_CLASS (parent_class)->get_caps (sink, filter);
+  }
+
+  osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf);
+
+  /* protect against cached_caps going away */
+  GST_OBJECT_LOCK (buf);
+
+  if (osxbuf->core_audio->cached_caps_valid) {
+    GST_LOG_OBJECT (sink, "Returning cached caps");
+    caps = gst_caps_ref (osxbuf->core_audio->cached_caps);
+  } else if (buf->open) {
+    GstCaps *template_caps;
+
+    /* Get template caps */
+    template_caps =
+        gst_pad_get_pad_template_caps (GST_AUDIO_BASE_SINK_PAD (osxsink));
+
+    /* Device is open, let's probe its caps */
+    caps = gst_core_audio_probe_caps (osxbuf->core_audio, template_caps);
+    gst_caps_replace (&osxbuf->core_audio->cached_caps, caps);
+
+    gst_caps_unref (template_caps);
+  } else {
+    GST_DEBUG_OBJECT (sink, "ring buffer not open, returning NULL caps");
+    caps = NULL;
+  }
+
+  GST_OBJECT_UNLOCK (buf);
+
+  gst_object_unref (buf);
+
+  if (!caps)
+    return NULL;
+
+  if (!filter)
+    return caps;
+
+  /* Take care of filtered caps */
+  filtered_caps =
+      gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+  gst_caps_unref (caps);
+  return filtered_caps;
+}
+
+static gboolean
+gst_osx_audio_sink_acceptcaps (GstOsxAudioSink * sink, GstCaps * caps)
+{
+  GstCaps *pad_caps;
+  GstStructure *st;
+  gboolean ret = FALSE;
+  GstAudioRingBufferSpec spec = { 0 };
+  gchar *caps_string = NULL;
+
+  caps_string = gst_caps_to_string (caps);
+  GST_DEBUG_OBJECT (sink, "acceptcaps called with %s", caps_string);
+  g_free (caps_string);
+
+  pad_caps = gst_pad_query_caps (GST_BASE_SINK_PAD (sink), caps);
+  if (pad_caps) {
+    gboolean cret = gst_caps_can_intersect (pad_caps, caps);
+    gst_caps_unref (pad_caps);
+    if (!cret)
+      goto done;
+  }
+
+  /* If we've not got fixed caps, creating a stream might fail,
+   * so let's just return from here with default acceptcaps
+   * behaviour */
+  if (!gst_caps_is_fixed (caps))
+    goto done;
+
+  /* parse helper expects this set, so avoid nasty warning
+   * will be set properly later on anyway  */
+  spec.latency_time = GST_SECOND;
+  if (!gst_audio_ring_buffer_parse_caps (&spec, caps))
+    goto done;
+
+  /* Make sure input is framed and can be payloaded */
+  switch (spec.type) {
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
+    {
+      gboolean framed = FALSE;
+
+      st = gst_caps_get_structure (caps, 0);
+
+      gst_structure_get_boolean (st, "framed", &framed);
+      if (!framed || gst_audio_iec61937_frame_size (&spec) <= 0)
+        goto done;
+      break;
+    }
+    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS:
+    {
+      gboolean parsed = FALSE;
+
+      st = gst_caps_get_structure (caps, 0);
+
+      gst_structure_get_boolean (st, "parsed", &parsed);
+      if (!parsed || gst_audio_iec61937_frame_size (&spec) <= 0)
+        goto done;
+      break;
+    }
+    default:
+      break;
+  }
+  ret = TRUE;
+
+done:
+  return ret;
+}
+
+static GstBuffer *
+gst_osx_audio_sink_sink_payload (GstAudioBaseSink * sink, GstBuffer * buf)
+{
+  if (RINGBUFFER_IS_SPDIF (sink->ringbuffer->spec.type)) {
+    gint framesize = gst_audio_iec61937_frame_size (&sink->ringbuffer->spec);
+    GstBuffer *out;
+    GstMapInfo inmap, outmap;
+    gboolean res;
+
+    if (framesize <= 0)
+      return NULL;
+
+    out = gst_buffer_new_and_alloc (framesize);
+
+    gst_buffer_map (buf, &inmap, GST_MAP_READ);
+    gst_buffer_map (out, &outmap, GST_MAP_WRITE);
+
+    /* FIXME: the endianness needs to be queried and then set */
+    res = gst_audio_iec61937_payload (inmap.data, inmap.size,
+        outmap.data, outmap.size, &sink->ringbuffer->spec, G_BIG_ENDIAN);
+
+    gst_buffer_unmap (buf, &inmap);
+    gst_buffer_unmap (out, &outmap);
+
+    if (!res) {
+      gst_buffer_unref (out);
+      return NULL;
+    }
+
+    gst_buffer_copy_into (out, buf, GST_BUFFER_COPY_METADATA, 0, -1);
+    return out;
+
+  } else {
+    return gst_buffer_ref (buf);
+  }
+}
+
+static GstAudioRingBuffer *
+gst_osx_audio_sink_create_ringbuffer (GstAudioBaseSink * sink)
+{
+  GstOsxAudioSink *osxsink;
+  GstOsxAudioRingBuffer *ringbuffer;
+
+  osxsink = GST_OSX_AUDIO_SINK (sink);
+
+  GST_DEBUG_OBJECT (sink, "Creating ringbuffer");
+  ringbuffer = g_object_new (GST_TYPE_OSX_AUDIO_RING_BUFFER, NULL);
+  GST_DEBUG_OBJECT (sink, "osx sink %p element %p  ioproc %p", osxsink,
+      GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsink),
+      (void *) gst_osx_audio_sink_io_proc);
+
+  ringbuffer->core_audio->element =
+      GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsink);
+  ringbuffer->core_audio->is_src = FALSE;
+
+  /* By default the coreaudio instance created by the ringbuffer
+   * has device_id==kAudioDeviceUnknown. The user might have
+   * selected a different one here
+   */
+  if (ringbuffer->core_audio->device_id != osxsink->device_id)
+    ringbuffer->core_audio->device_id = osxsink->device_id;
+
+  return GST_AUDIO_RING_BUFFER (ringbuffer);
+}
+
+/* HALOutput AudioUnit will request fairly arbitrarily-sized chunks
+ * of data, not of a fixed size. So, we keep track of where in
+ * the current ringbuffer segment we are, and only advance the segment
+ * once we've read the whole thing */
+static OSStatus
+gst_osx_audio_sink_io_proc (GstOsxAudioRingBuffer * buf,
+    AudioUnitRenderActionFlags * ioActionFlags,
+    const AudioTimeStamp * inTimeStamp,
+    UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * bufferList)
+{
+  guint8 *readptr;
+  gint readseg;
+  gint len;
+  gint stream_idx = buf->core_audio->stream_idx;
+  gint remaining = bufferList->mBuffers[stream_idx].mDataByteSize;
+  gint offset = 0;
+
+  while (remaining) {
+    if (!gst_audio_ring_buffer_prepare_read (GST_AUDIO_RING_BUFFER (buf),
+            &readseg, &readptr, &len))
+      return 0;
+
+    len -= buf->segoffset;
+
+    if (len > remaining)
+      len = remaining;
+
+    memcpy ((char *) bufferList->mBuffers[stream_idx].mData + offset,
+        readptr + buf->segoffset, len);
+
+    buf->segoffset += len;
+    offset += len;
+    remaining -= len;
+
+    if ((gint) buf->segoffset == GST_AUDIO_RING_BUFFER (buf)->spec.segsize) {
+      /* clear written samples */
+      gst_audio_ring_buffer_clear (GST_AUDIO_RING_BUFFER (buf), readseg);
+
+      /* we wrote one segment */
+      gst_audio_ring_buffer_advance (GST_AUDIO_RING_BUFFER (buf), 1);
+
+      buf->segoffset = 0;
+    }
+  }
+  return 0;
+}
+
+static void
+gst_osx_audio_sink_osxelement_init (gpointer g_iface, gpointer iface_data)
+{
+  GstOsxAudioElementInterface *iface = (GstOsxAudioElementInterface *) g_iface;
+
+  iface->io_proc = (AURenderCallback) gst_osx_audio_sink_io_proc;
+}
+
+static void
+gst_osx_audio_sink_set_volume (GstOsxAudioSink * sink)
+{
+  GstOsxAudioRingBuffer *osxbuf;
+
+  osxbuf = GST_OSX_AUDIO_RING_BUFFER (GST_AUDIO_BASE_SINK (sink)->ringbuffer);
+  if (!osxbuf)
+    return;
+
+  gst_core_audio_set_volume (osxbuf->core_audio, sink->volume);
+}
diff --git a/sys/osxaudio/gstosxaudiosink.h b/sys/osxaudio/gstosxaudiosink.h
new file mode 100644
index 0000000..2f55c4d
--- /dev/null
+++ b/sys/osxaudio/gstosxaudiosink.h
@@ -0,0 +1,102 @@
+/*
+ * GStreamer
+ * Copyright (C) 2005-2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ * Copyright (C) 2012 Fluendo S.A. <support@fluendo.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * The development of this code was made possible due to the involvement of
+ * Pioneers of the Inevitable, the creators of the Songbird Music player
+ *
+ */
+
+#ifndef __GST_OSXAUDIOSINK_H__
+#define __GST_OSXAUDIOSINK_H__
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiobasesink.h>
+#include "gstosxaudioringbuffer.h"
+
+G_BEGIN_DECLS
+
+#define GST_OSX_AUDIO_SINK_CAPS "audio/x-raw, " \
+        "format = (string) " GST_AUDIO_FORMATS_ALL ", " \
+        "layout = (string) interleaved, " \
+        "rate = (int) [1, MAX], " \
+        "channels = (int) [1, 9];" \
+        "audio/x-ac3, framed = (boolean) true;" \
+        "audio/x-dts, framed = (boolean) true"
+
+#define GST_TYPE_OSX_AUDIO_SINK \
+  (gst_osx_audio_sink_get_type())
+#define GST_OSX_AUDIO_SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSX_AUDIO_SINK,GstOsxAudioSink))
+#define GST_OSX_AUDIO_SINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSX_AUDIO_SINK,GstOsxAudioSinkClass))
+#define GST_IS_OSX_AUDIO_SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSX_AUDIO_SINK))
+
+typedef struct _GstOsxAudioSink GstOsxAudioSink;
+typedef struct _GstOsxAudioSinkClass GstOsxAudioSinkClass;
+
+struct _GstOsxAudioSink
+{
+  GstAudioBaseSink sink;
+
+  AudioDeviceID device_id;
+
+  AudioUnit audiounit;
+  double volume;
+
+  guint channels;
+};
+
+struct _GstOsxAudioSinkClass
+{
+  GstAudioBaseSinkClass parent_class;
+};
+
+GType gst_osx_audio_sink_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_OSXAUDIOSINK_H__ */
+
diff --git a/sys/osxaudio/gstosxaudiosrc.c b/sys/osxaudio/gstosxaudiosrc.c
new file mode 100644
index 0000000..4e56778
--- /dev/null
+++ b/sys/osxaudio/gstosxaudiosrc.c
@@ -0,0 +1,397 @@
+/*
+ * GStreamer
+ * Copyright (C) 2005,2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2008 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-osxaudiosrc
+ *
+ * This element captures raw audio samples using the CoreAudio api.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 osxaudiosrc ! wavenc ! filesink location=audio.wav
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <gst/gst.h>
+#include "gstosxaudiosrc.h"
+#include "gstosxaudioelement.h"
+
+GST_DEBUG_CATEGORY_STATIC (osx_audiosrc_debug);
+#define GST_CAT_DEFAULT osx_audiosrc_debug
+
+/* Filter signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  ARG_0,
+  ARG_DEVICE
+};
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_OSX_AUDIO_SRC_CAPS)
+    );
+
+static void gst_osx_audio_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_osx_audio_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn
+gst_osx_audio_src_change_state (GstElement * element,
+    GstStateChange transition);
+
+static GstCaps *gst_osx_audio_src_get_caps (GstBaseSrc * src, GstCaps * filter);
+
+static GstAudioRingBuffer *gst_osx_audio_src_create_ringbuffer (GstAudioBaseSrc
+    * src);
+static void gst_osx_audio_src_osxelement_init (gpointer g_iface,
+    gpointer iface_data);
+static OSStatus gst_osx_audio_src_io_proc (GstOsxAudioRingBuffer * buf,
+    AudioUnitRenderActionFlags * ioActionFlags,
+    const AudioTimeStamp * inTimeStamp, UInt32 inBusNumber,
+    UInt32 inNumberFrames, AudioBufferList * bufferList);
+
+static void
+gst_osx_audio_src_do_init (GType type)
+{
+  static const GInterfaceInfo osxelement_info = {
+    gst_osx_audio_src_osxelement_init,
+    NULL,
+    NULL
+  };
+
+  GST_DEBUG_CATEGORY_INIT (osx_audiosrc_debug, "osxaudiosrc", 0,
+      "OSX Audio Src");
+  g_type_add_interface_static (type, GST_OSX_AUDIO_ELEMENT_TYPE,
+      &osxelement_info);
+}
+
+#define gst_osx_audio_src_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstOsxAudioSrc, gst_osx_audio_src,
+    GST_TYPE_AUDIO_BASE_SRC, gst_osx_audio_src_do_init (g_define_type_id));
+
+static void
+gst_osx_audio_src_class_init (GstOsxAudioSrcClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSrcClass *gstbasesrc_class;
+  GstAudioBaseSrcClass *gstaudiobasesrc_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesrc_class = (GstBaseSrcClass *) klass;
+  gstaudiobasesrc_class = (GstAudioBaseSrcClass *) klass;
+
+  gobject_class->set_property = gst_osx_audio_src_set_property;
+  gobject_class->get_property = gst_osx_audio_src_get_property;
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_osx_audio_src_change_state);
+
+  gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_osx_audio_src_get_caps);
+
+  g_object_class_install_property (gobject_class, ARG_DEVICE,
+      g_param_spec_int ("device", "Device ID", "Device ID of input device",
+          0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gstaudiobasesrc_class->create_ringbuffer =
+      GST_DEBUG_FUNCPTR (gst_osx_audio_src_create_ringbuffer);
+
+  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+
+  gst_element_class_set_static_metadata (gstelement_class, "Audio Source (OSX)",
+      "Source/Audio",
+      "Input from a sound card in OS X",
+      "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
+}
+
+static void
+gst_osx_audio_src_init (GstOsxAudioSrc * src)
+{
+  gst_base_src_set_live (GST_BASE_SRC (src), TRUE);
+
+  src->device_id = kAudioDeviceUnknown;
+}
+
+static void
+gst_osx_audio_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstOsxAudioSrc *src = GST_OSX_AUDIO_SRC (object);
+
+  switch (prop_id) {
+    case ARG_DEVICE:
+      src->device_id = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_osx_audio_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstOsxAudioSrc *src = GST_OSX_AUDIO_SRC (object);
+
+  switch (prop_id) {
+    case ARG_DEVICE:
+      g_value_set_int (value, src->device_id);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStateChangeReturn
+gst_osx_audio_src_change_state (GstElement * element, GstStateChange transition)
+{
+  GstOsxAudioSrc *osxsrc = GST_OSX_AUDIO_SRC (element);
+  GstOsxAudioRingBuffer *ringbuffer;
+  GstStateChangeReturn ret;
+
+  switch (transition) {
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    goto out;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      /* The device is open now, so fix our device_id if it changed */
+      ringbuffer =
+          GST_OSX_AUDIO_RING_BUFFER (GST_AUDIO_BASE_SRC (osxsrc)->ringbuffer);
+      if (ringbuffer->core_audio->device_id != osxsrc->device_id) {
+        osxsrc->device_id = ringbuffer->core_audio->device_id;
+        g_object_notify (G_OBJECT (osxsrc), "device");
+      }
+      break;
+
+    default:
+      break;
+  }
+
+out:
+  return ret;
+}
+
+static GstCaps *
+gst_osx_audio_src_get_caps (GstBaseSrc * src, GstCaps * filter)
+{
+  GstOsxAudioSrc *osxsrc;
+  GstAudioRingBuffer *buf;
+  GstOsxAudioRingBuffer *osxbuf;
+  GstCaps *caps, *filtered_caps;
+
+  osxsrc = GST_OSX_AUDIO_SRC (src);
+
+  GST_OBJECT_LOCK (osxsrc);
+  buf = GST_AUDIO_BASE_SRC (src)->ringbuffer;
+  if (buf)
+    gst_object_ref (buf);
+  GST_OBJECT_UNLOCK (osxsrc);
+
+  if (!buf) {
+    GST_DEBUG_OBJECT (src, "no ring buffer, using template caps");
+    return GST_BASE_SRC_CLASS (parent_class)->get_caps (src, filter);
+  }
+
+  osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf);
+
+  /* protect against cached_caps going away */
+  GST_OBJECT_LOCK (buf);
+
+  if (osxbuf->core_audio->cached_caps_valid) {
+    GST_LOG_OBJECT (src, "Returning cached caps");
+    caps = gst_caps_ref (osxbuf->core_audio->cached_caps);
+  } else if (buf->open) {
+    GstCaps *template_caps;
+
+    /* Get template caps */
+    template_caps =
+        gst_pad_get_pad_template_caps (GST_AUDIO_BASE_SRC_PAD (osxsrc));
+
+    /* Device is open, let's probe its caps */
+    caps = gst_core_audio_probe_caps (osxbuf->core_audio, template_caps);
+    gst_caps_replace (&osxbuf->core_audio->cached_caps, caps);
+
+    gst_caps_unref (template_caps);
+  } else {
+    GST_DEBUG_OBJECT (src, "ring buffer not open, using template caps");
+    caps = GST_BASE_SRC_CLASS (parent_class)->get_caps (src, NULL);
+  }
+
+  GST_OBJECT_UNLOCK (buf);
+
+  gst_object_unref (buf);
+
+  if (!caps)
+    return NULL;
+
+  if (!filter)
+    return caps;
+
+  /* Take care of filtered caps */
+  filtered_caps =
+      gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+  gst_caps_unref (caps);
+  return filtered_caps;
+}
+
+static GstAudioRingBuffer *
+gst_osx_audio_src_create_ringbuffer (GstAudioBaseSrc * src)
+{
+  GstOsxAudioSrc *osxsrc;
+  GstOsxAudioRingBuffer *ringbuffer;
+
+  osxsrc = GST_OSX_AUDIO_SRC (src);
+
+  GST_DEBUG_OBJECT (osxsrc, "Creating ringbuffer");
+  ringbuffer = g_object_new (GST_TYPE_OSX_AUDIO_RING_BUFFER, NULL);
+  GST_DEBUG_OBJECT (osxsrc, "osx src 0x%p element 0x%p  ioproc 0x%p", osxsrc,
+      GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsrc),
+      (void *) gst_osx_audio_src_io_proc);
+
+  ringbuffer->core_audio->element =
+      GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsrc);
+  ringbuffer->core_audio->is_src = TRUE;
+
+  /* By default the coreaudio instance created by the ringbuffer
+   * has device_id==kAudioDeviceUnknown. The user might have
+   * selected a different one here
+   */
+  if (ringbuffer->core_audio->device_id != osxsrc->device_id)
+    ringbuffer->core_audio->device_id = osxsrc->device_id;
+
+  return GST_AUDIO_RING_BUFFER (ringbuffer);
+}
+
+static OSStatus
+gst_osx_audio_src_io_proc (GstOsxAudioRingBuffer * buf,
+    AudioUnitRenderActionFlags * ioActionFlags,
+    const AudioTimeStamp * inTimeStamp,
+    UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * bufferList)
+{
+  OSStatus status;
+  guint8 *writeptr;
+  gint writeseg;
+  gint len;
+  gint remaining;
+  UInt32 n;
+  gint offset = 0;
+
+  /* Previous invoke of AudioUnitRender changed mDataByteSize into
+   * number of bytes actually read. Reset the members. */
+  for (n = 0; n < buf->core_audio->recBufferList->mNumberBuffers; ++n) {
+    buf->core_audio->recBufferList->mBuffers[n].mDataByteSize =
+        buf->core_audio->recBufferSize;
+  }
+
+  status = AudioUnitRender (buf->core_audio->audiounit, ioActionFlags,
+      inTimeStamp, inBusNumber, inNumberFrames, buf->core_audio->recBufferList);
+
+  if (status) {
+    GST_WARNING_OBJECT (buf, "AudioUnitRender returned %d", (int) status);
+    return status;
+  }
+
+  /* TODO: To support non-interleaved audio, go over all mBuffers,
+   *       not just the first one. */
+
+  remaining = buf->core_audio->recBufferList->mBuffers[0].mDataByteSize;
+
+  while (remaining) {
+    if (!gst_audio_ring_buffer_prepare_read (GST_AUDIO_RING_BUFFER (buf),
+            &writeseg, &writeptr, &len))
+      return 0;
+
+    len -= buf->segoffset;
+
+    if (len > remaining)
+      len = remaining;
+
+    memcpy (writeptr + buf->segoffset,
+        (char *) buf->core_audio->recBufferList->mBuffers[0].mData + offset,
+        len);
+
+    buf->segoffset += len;
+    offset += len;
+    remaining -= len;
+
+    if ((gint) buf->segoffset == GST_AUDIO_RING_BUFFER (buf)->spec.segsize) {
+      /* we wrote one segment */
+      gst_audio_ring_buffer_advance (GST_AUDIO_RING_BUFFER (buf), 1);
+
+      buf->segoffset = 0;
+    }
+  }
+  return 0;
+}
+
+static void
+gst_osx_audio_src_osxelement_init (gpointer g_iface, gpointer iface_data)
+{
+  GstOsxAudioElementInterface *iface = (GstOsxAudioElementInterface *) g_iface;
+
+  iface->io_proc = (AURenderCallback) gst_osx_audio_src_io_proc;
+}
diff --git a/sys/osxaudio/gstosxaudiosrc.h b/sys/osxaudio/gstosxaudiosrc.h
new file mode 100644
index 0000000..9d825b0
--- /dev/null
+++ b/sys/osxaudio/gstosxaudiosrc.h
@@ -0,0 +1,87 @@
+/*
+ * GStreamer
+ * Copyright (C) 2005-2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_OSXAUDIOSRC_H__
+#define __GST_OSXAUDIOSRC_H__
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiobasesrc.h>
+#include "gstosxaudioringbuffer.h"
+
+G_BEGIN_DECLS
+
+#define GST_OSX_AUDIO_SRC_CAPS "audio/x-raw, " \
+        "format = (string) " GST_AUDIO_FORMATS_ALL ", " \
+        "layout = (string) interleaved, " \
+        "rate = (int) [1, MAX], " "channels = (int) [1, MAX]"
+
+#define GST_TYPE_OSX_AUDIO_SRC \
+  (gst_osx_audio_src_get_type())
+#define GST_OSX_AUDIO_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSX_AUDIO_SRC,GstOsxAudioSrc))
+#define GST_OSX_AUDIO_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSX_AUDIO_SRC,GstOsxAudioSrcClass))
+#define GST_IS_OSX_AUDIO_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSX_AUDIO_SRC))
+
+typedef struct _GstOsxAudioSrc GstOsxAudioSrc;
+typedef struct _GstOsxAudioSrcClass GstOsxAudioSrcClass;
+
+struct _GstOsxAudioSrc
+{
+  GstAudioBaseSrc src;
+
+  AudioDeviceID device_id;
+};
+
+struct _GstOsxAudioSrcClass
+{
+  GstAudioBaseSrcClass parent_class;
+};
+
+GType gst_osx_audio_src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_OSXAUDIOSRC_H__ */
diff --git a/sys/osxaudio/gstosxcoreaudio.c b/sys/osxaudio/gstosxcoreaudio.c
new file mode 100644
index 0000000..5d3b882
--- /dev/null
+++ b/sys/osxaudio/gstosxcoreaudio.c
@@ -0,0 +1,676 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012-2013 Fluendo S.A. <support@fluendo.com>
+ *   Authors: Josep Torra Vallès <josep@fluendo.com>
+ *            Andoni Morales Alastruey <amorales@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "gstosxcoreaudio.h"
+#include "gstosxcoreaudiocommon.h"
+
+GST_DEBUG_CATEGORY_STATIC (osx_audio_debug);
+#define GST_CAT_DEFAULT osx_audio_debug
+
+G_DEFINE_TYPE (GstCoreAudio, gst_core_audio, G_TYPE_OBJECT);
+
+#ifdef HAVE_IOS
+#include "gstosxcoreaudioremoteio.c"
+#else
+#include "gstosxcoreaudiohal.c"
+#endif
+
+
+static void
+gst_core_audio_class_init (GstCoreAudioClass * klass)
+{
+}
+
+static void
+gst_core_audio_init (GstCoreAudio * core_audio)
+{
+  core_audio->is_passthrough = FALSE;
+  core_audio->device_id = kAudioDeviceUnknown;
+  core_audio->is_src = FALSE;
+  core_audio->audiounit = NULL;
+  core_audio->cached_caps = NULL;
+  core_audio->cached_caps_valid = FALSE;
+#ifndef HAVE_IOS
+  core_audio->hog_pid = -1;
+  core_audio->disabled_mixing = FALSE;
+#endif
+}
+
+static gboolean
+_is_outer_scope (AudioUnitScope scope, AudioUnitElement element)
+{
+  return
+      (scope == kAudioUnitScope_Input && element == 1) ||
+      (scope == kAudioUnitScope_Output && element == 0);
+}
+
+static void
+_audio_unit_property_listener (void *inRefCon, AudioUnit inUnit,
+    AudioUnitPropertyID inID, AudioUnitScope inScope,
+    AudioUnitElement inElement)
+{
+  GstCoreAudio *core_audio;
+
+  core_audio = GST_CORE_AUDIO (inRefCon);
+  g_assert (inUnit == core_audio->audiounit);
+
+  switch (inID) {
+    case kAudioUnitProperty_AudioChannelLayout:
+    case kAudioUnitProperty_StreamFormat:
+      if (_is_outer_scope (inScope, inElement)) {
+        /* We don't push gst_event_new_caps here (for src),
+         * nor gst_event_new_reconfigure (for sink), since Core Audio continues
+         * to happily function with the old format, doing conversion/resampling
+         * as needed.
+         * This merely "refreshes" our PREFERRED caps. */
+
+        /* This function is called either from a Core Audio thread
+         * or as a result of a Core Audio API (e.g. AudioUnitInitialize)
+         * from our own thread. In the latter case, osxbuf can be
+         * already locked (GStreamer's mutex is not recursive).
+         * For this reason we use a boolean flag instead of nullifying
+         * cached_caps. */
+        core_audio->cached_caps_valid = FALSE;
+      }
+      break;
+  }
+}
+
+/**************************
+ *       Public API       *
+ *************************/
+
+GstCoreAudio *
+gst_core_audio_new (GstObject * osxbuf)
+{
+  GstCoreAudio *core_audio;
+
+  core_audio = g_object_new (GST_TYPE_CORE_AUDIO, NULL);
+  core_audio->osxbuf = osxbuf;
+  core_audio->cached_caps = NULL;
+  return core_audio;
+}
+
+gboolean
+gst_core_audio_close (GstCoreAudio * core_audio)
+{
+  OSStatus status;
+
+  /* Uninitialize the AudioUnit */
+  status = AudioUnitUninitialize (core_audio->audiounit);
+  if (status) {
+    GST_ERROR_OBJECT (core_audio, "Failed to uninitialize AudioUnit: %d",
+        (int) status);
+    return FALSE;
+  }
+
+  AudioUnitRemovePropertyListenerWithUserData (core_audio->audiounit,
+      kAudioUnitProperty_AudioChannelLayout, _audio_unit_property_listener,
+      core_audio);
+  AudioUnitRemovePropertyListenerWithUserData (core_audio->audiounit,
+      kAudioUnitProperty_StreamFormat, _audio_unit_property_listener,
+      core_audio);
+
+  /* core_audio->osxbuf is already locked at this point */
+  core_audio->cached_caps_valid = FALSE;
+  gst_caps_replace (&core_audio->cached_caps, NULL);
+
+  AudioComponentInstanceDispose (core_audio->audiounit);
+  core_audio->audiounit = NULL;
+  return TRUE;
+}
+
+gboolean
+gst_core_audio_open (GstCoreAudio * core_audio)
+{
+  OSStatus status;
+
+  /* core_audio->osxbuf is already locked at this point */
+  core_audio->cached_caps_valid = FALSE;
+  gst_caps_replace (&core_audio->cached_caps, NULL);
+
+  if (!gst_core_audio_open_impl (core_audio))
+    return FALSE;
+
+  /* Add property listener */
+  status = AudioUnitAddPropertyListener (core_audio->audiounit,
+      kAudioUnitProperty_AudioChannelLayout, _audio_unit_property_listener,
+      core_audio);
+  if (status != noErr) {
+    GST_ERROR_OBJECT (core_audio, "Failed to add audio channel layout property "
+        "listener for AudioUnit: %d", (int) status);
+  }
+  status = AudioUnitAddPropertyListener (core_audio->audiounit,
+      kAudioUnitProperty_StreamFormat, _audio_unit_property_listener,
+      core_audio);
+  if (status != noErr) {
+    GST_ERROR_OBJECT (core_audio, "Failed to add stream format property "
+        "listener for AudioUnit: %d", (int) status);
+  }
+
+  /* Initialize the AudioUnit. We keep the audio unit initialized early so that
+   * we can probe the underlying device. */
+  status = AudioUnitInitialize (core_audio->audiounit);
+  if (status) {
+    GST_ERROR_OBJECT (core_audio, "Failed to initialize AudioUnit: %d",
+        (int) status);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+gboolean
+gst_core_audio_start_processing (GstCoreAudio * core_audio)
+{
+  return gst_core_audio_start_processing_impl (core_audio);
+}
+
+gboolean
+gst_core_audio_pause_processing (GstCoreAudio * core_audio)
+{
+  return gst_core_audio_pause_processing_impl (core_audio);
+}
+
+gboolean
+gst_core_audio_stop_processing (GstCoreAudio * core_audio)
+{
+  return gst_core_audio_stop_processing_impl (core_audio);
+}
+
+gboolean
+gst_core_audio_get_samples_and_latency (GstCoreAudio * core_audio,
+    gdouble rate, guint * samples, gdouble * latency)
+{
+  return gst_core_audio_get_samples_and_latency_impl (core_audio, rate,
+      samples, latency);
+}
+
+gboolean
+gst_core_audio_initialize (GstCoreAudio * core_audio,
+    AudioStreamBasicDescription format, GstCaps * caps, gboolean is_passthrough)
+{
+  guint32 frame_size;
+
+  GST_DEBUG_OBJECT (core_audio,
+      "Initializing: passthrough:%d caps:%" GST_PTR_FORMAT, is_passthrough,
+      caps);
+
+  if (!gst_core_audio_initialize_impl (core_audio, format, caps,
+          is_passthrough, &frame_size)) {
+    return FALSE;
+  }
+
+  if (core_audio->is_src) {
+    /* create AudioBufferList needed for recording */
+    core_audio->recBufferSize = frame_size * format.mBytesPerFrame;
+    core_audio->recBufferList =
+        buffer_list_alloc (format.mChannelsPerFrame, core_audio->recBufferSize,
+        /* Currently always TRUE (i.e. interleaved) */
+        !(format.mFormatFlags & kAudioFormatFlagIsNonInterleaved));
+  }
+
+  return TRUE;
+}
+
+void
+gst_core_audio_uninitialize (GstCoreAudio * core_audio)
+{
+  buffer_list_free (core_audio->recBufferList);
+  core_audio->recBufferList = NULL;
+}
+
+void
+gst_core_audio_set_volume (GstCoreAudio * core_audio, gfloat volume)
+{
+  AudioUnitSetParameter (core_audio->audiounit, kHALOutputParam_Volume,
+      kAudioUnitScope_Global, 0, (float) volume, 0);
+}
+
+gboolean
+gst_core_audio_select_device (GstCoreAudio * core_audio)
+{
+  return gst_core_audio_select_device_impl (core_audio);
+}
+
+void
+gst_core_audio_init_debug (void)
+{
+  GST_DEBUG_CATEGORY_INIT (osx_audio_debug, "osxaudio", 0,
+      "OSX Audio Elements");
+}
+
+gboolean
+gst_core_audio_audio_device_is_spdif_avail (AudioDeviceID device_id)
+{
+  return gst_core_audio_audio_device_is_spdif_avail_impl (device_id);
+}
+
+/* Does the channel have at least one positioned channel?
+ * (GStreamer is more strict than Core Audio, in that it requires either
+ * all channels to be positioned, or all unpositioned.) */
+static gboolean
+_is_core_audio_layout_positioned (AudioChannelLayout * layout)
+{
+  guint i;
+
+  g_assert (layout->mChannelLayoutTag ==
+      kAudioChannelLayoutTag_UseChannelDescriptions);
+
+  for (i = 0; i < layout->mNumberChannelDescriptions; ++i) {
+    GstAudioChannelPosition p =
+        gst_core_audio_channel_label_to_gst
+        (layout->mChannelDescriptions[i].mChannelLabel, i, FALSE);
+
+    if (p >= 0)                 /* not special positition */
+      return TRUE;
+  }
+
+  return FALSE;
+}
+
+static void
+_core_audio_parse_channel_descriptions (AudioChannelLayout * layout,
+    guint * channels, guint64 * channel_mask, GstAudioChannelPosition * pos)
+{
+  gboolean positioned;
+  guint i;
+
+  g_assert (layout->mChannelLayoutTag ==
+      kAudioChannelLayoutTag_UseChannelDescriptions);
+
+  positioned = _is_core_audio_layout_positioned (layout);
+  *channel_mask = 0;
+
+  /* Go over all labels, either taking only positioned or only
+   * unpositioned channels, up to GST_OSX_AUDIO_MAX_CHANNEL channels.
+   *
+   * The resulting 'pos' array will contain either:
+   *  - only regular (>= 0) positions
+   *  - only GST_AUDIO_CHANNEL_POSITION_NONE positions
+   * in a compact form, skipping over all unsupported positions.
+   */
+  *channels = 0;
+  for (i = 0; i < layout->mNumberChannelDescriptions; ++i) {
+    GstAudioChannelPosition p =
+        gst_core_audio_channel_label_to_gst
+        (layout->mChannelDescriptions[i].mChannelLabel, i, TRUE);
+
+    /* In positioned layouts, skip all unpositioned channels.
+     * In unpositioned layouts, skip all invalid channels. */
+    if ((positioned && p >= 0) ||
+        (!positioned && p == GST_AUDIO_CHANNEL_POSITION_NONE)) {
+
+      if (pos)
+        pos[*channels] = p;
+      *channel_mask |= G_GUINT64_CONSTANT (1) << p;
+      ++(*channels);
+
+      if (*channels == GST_OSX_AUDIO_MAX_CHANNEL)
+        break;                  /* not to overflow */
+    }
+  }
+}
+
+gboolean
+gst_core_audio_parse_channel_layout (AudioChannelLayout * layout,
+    guint * channels, guint64 * channel_mask, GstAudioChannelPosition * pos)
+{
+  g_assert (channels != NULL);
+  g_assert (channel_mask != NULL);
+  g_assert (layout != NULL);
+
+  if (layout->mChannelLayoutTag !=
+      kAudioChannelLayoutTag_UseChannelDescriptions) {
+    GST_ERROR
+        ("Only kAudioChannelLayoutTag_UseChannelDescriptions is supported.");
+    *channels = 0;
+    *channel_mask = 0;
+    return FALSE;
+  }
+
+  switch (layout->mNumberChannelDescriptions) {
+    case 0:
+      if (pos)
+        pos[0] = GST_AUDIO_CHANNEL_POSITION_NONE;
+      *channels = 0;
+      *channel_mask = 0;
+      return TRUE;
+    case 1:
+      if (pos)
+        pos[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
+      *channels = 1;
+      *channel_mask = 0;
+      return TRUE;
+    case 2:
+      if (pos) {
+        pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
+        pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
+      }
+      *channels = 2;
+      *channel_mask =
+          GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
+          GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT);
+      return TRUE;
+    default:
+      _core_audio_parse_channel_descriptions (layout, channels, channel_mask,
+          pos);
+      return TRUE;
+  }
+}
+
+/* Converts an AudioStreamBasicDescription to preferred caps.
+ *
+ * These caps will indicate the AU element's canonical format, which won't
+ * make Core Audio resample nor convert.
+ *
+ * NOTE ON MULTI-CHANNEL AUDIO:
+ *
+ * If layout is not NULL, resulting caps will only include the subset
+ * of channels supported by GStreamer. If the Core Audio layout contained
+ * ANY positioned channels, then ONLY positioned channels will be included
+ * in the resulting caps. Otherwise, resulting caps will be unpositioned,
+ * and include only unpositioned channels.
+ * (Channels with unsupported AudioChannelLabel will be skipped either way.)
+ *
+ * Naturally, the number of channels indicated by 'channels' can be lower
+ * than the AU element's total number of channels.
+ */
+GstCaps *
+gst_core_audio_asbd_to_caps (AudioStreamBasicDescription * asbd,
+    AudioChannelLayout * layout)
+{
+  GstAudioInfo info;
+  GstAudioFormat format = GST_AUDIO_FORMAT_UNKNOWN;
+  guint rate, channels, bps, endianness;
+  guint64 channel_mask;
+  gboolean sign, interleaved;
+
+  if (asbd->mFormatID != kAudioFormatLinearPCM) {
+    GST_WARNING ("Only linear PCM is supported");
+    goto error;
+  }
+
+  if (!(asbd->mFormatFlags & kAudioFormatFlagIsPacked)) {
+    GST_WARNING ("Only packed formats supported");
+    goto error;
+  }
+
+  if (asbd->mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) {
+    GST_WARNING ("Fixed point audio is unsupported");
+    goto error;
+  }
+
+  rate = asbd->mSampleRate;
+  if (rate == kAudioStreamAnyRate) {
+    GST_WARNING ("No sample rate");
+    goto error;
+  }
+
+  bps = asbd->mBitsPerChannel;
+  endianness = asbd->mFormatFlags & kAudioFormatFlagIsBigEndian ?
+      G_BIG_ENDIAN : G_LITTLE_ENDIAN;
+  sign = asbd->mFormatID & kAudioFormatFlagIsSignedInteger ? TRUE : FALSE;
+  interleaved = asbd->mFormatFlags & kAudioFormatFlagIsNonInterleaved ?
+      TRUE : FALSE;
+
+  if (asbd->mFormatFlags & kAudioFormatFlagIsFloat) {
+    if (bps == 32) {
+      if (endianness == G_LITTLE_ENDIAN)
+        format = GST_AUDIO_FORMAT_F32LE;
+      else
+        format = GST_AUDIO_FORMAT_F32BE;
+
+    } else if (bps == 64) {
+      if (endianness == G_LITTLE_ENDIAN)
+        format = GST_AUDIO_FORMAT_F64LE;
+      else
+        format = GST_AUDIO_FORMAT_F64BE;
+    }
+  } else {
+    format = gst_audio_format_build_integer (sign, endianness, bps, bps);
+  }
+
+  if (format == GST_AUDIO_FORMAT_UNKNOWN) {
+    GST_WARNING ("Unsupported sample format");
+    goto error;
+  }
+
+  if (layout) {
+    GstAudioChannelPosition pos[GST_OSX_AUDIO_MAX_CHANNEL];
+
+    if (!gst_core_audio_parse_channel_layout (layout, &channels, &channel_mask,
+            pos)) {
+      GST_WARNING ("Failed to parse channel layout");
+      goto error;
+    }
+
+    /* The AU can have arbitrary channel order, but we're using GstAudioInfo
+     * which supports only the GStreamer channel order.
+     * Also, we're eventually producing caps, which only have channel-mask
+     * (whose implied order is the GStreamer channel order). */
+    gst_audio_channel_positions_to_valid_order (pos, channels);
+
+    gst_audio_info_set_format (&info, format, rate, channels, pos);
+  } else {
+    channels = MIN (asbd->mChannelsPerFrame, GST_OSX_AUDIO_MAX_CHANNEL);
+    gst_audio_info_set_format (&info, format, rate, channels, NULL);
+  }
+
+  return gst_audio_info_to_caps (&info);
+
+error:
+  return NULL;
+}
+
+static gboolean
+_core_audio_get_property (GstCoreAudio * core_audio, gboolean outer,
+    AudioUnitPropertyID inID, void *inData, UInt32 * inDataSize)
+{
+  OSStatus status;
+  AudioUnitScope scope;
+  AudioUnitElement element;
+
+  scope = outer ?
+      CORE_AUDIO_OUTER_SCOPE (core_audio) : CORE_AUDIO_INNER_SCOPE (core_audio);
+  element = CORE_AUDIO_ELEMENT (core_audio);
+
+  status =
+      AudioUnitGetProperty (core_audio->audiounit, inID, scope, element, inData,
+      inDataSize);
+
+  return status == noErr;
+}
+
+static gboolean
+_core_audio_get_stream_format (GstCoreAudio * core_audio,
+    AudioStreamBasicDescription * asbd, gboolean outer)
+{
+  UInt32 size;
+
+  size = sizeof (AudioStreamBasicDescription);
+  return _core_audio_get_property (core_audio, outer,
+      kAudioUnitProperty_StreamFormat, asbd, &size);
+}
+
+AudioChannelLayout *
+gst_core_audio_get_channel_layout (GstCoreAudio * core_audio, gboolean outer)
+{
+  UInt32 size;
+  AudioChannelLayout *layout;
+
+  if (core_audio->is_src) {
+    GST_WARNING_OBJECT (core_audio,
+        "gst_core_audio_get_channel_layout not supported on source.");
+    return NULL;
+  }
+
+  if (!_core_audio_get_property (core_audio, outer,
+          kAudioUnitProperty_AudioChannelLayout, NULL, &size)) {
+    GST_WARNING_OBJECT (core_audio, "unable to get channel layout");
+    return NULL;
+  }
+
+  layout = g_malloc (size);
+  if (!_core_audio_get_property (core_audio, outer,
+          kAudioUnitProperty_AudioChannelLayout, layout, &size)) {
+    GST_WARNING_OBJECT (core_audio, "unable to get channel layout");
+    g_free (layout);
+    return NULL;
+  }
+
+  return layout;
+}
+
+#define STEREO_CHANNEL_MASK \
+  (GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) | \
+   GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT))
+
+GstCaps *
+gst_core_audio_probe_caps (GstCoreAudio * core_audio, GstCaps * in_caps)
+{
+  guint i, channels;
+  gboolean spdif_allowed;
+  AudioChannelLayout *layout;
+  AudioStreamBasicDescription outer_asbd;
+  gboolean got_outer_asbd;
+  GstCaps *caps = NULL;
+  guint64 channel_mask;
+
+  /* Get the ASBD of the outer scope (i.e. input scope of Input,
+   * output scope of Output).
+   * This ASBD indicates the hardware format. */
+  got_outer_asbd =
+      _core_audio_get_stream_format (core_audio, &outer_asbd, TRUE);
+
+  /* Collect info about the HW capabilites and preferences */
+  spdif_allowed =
+      gst_core_audio_audio_device_is_spdif_avail (core_audio->device_id);
+  if (!core_audio->is_src)
+    layout = gst_core_audio_get_channel_layout (core_audio, TRUE);
+  else
+    layout = NULL;              /* no supported for sources */
+
+  GST_DEBUG_OBJECT (core_audio, "Selected device ID: %u SPDIF allowed: %d",
+      (unsigned) core_audio->device_id, spdif_allowed);
+
+  if (layout) {
+    if (!gst_core_audio_parse_channel_layout (layout, &channels, &channel_mask,
+            NULL)) {
+      GST_WARNING_OBJECT (core_audio, "Failed to parse channel layout");
+      channel_mask = 0;
+    }
+
+    /* If available, start with the preferred caps. */
+    if (got_outer_asbd)
+      caps = gst_core_audio_asbd_to_caps (&outer_asbd, layout);
+
+    g_free (layout);
+  } else if (got_outer_asbd) {
+    channels = outer_asbd.mChannelsPerFrame;
+    channel_mask = 0;
+    /* If available, start with the preferred caps */
+    caps = gst_core_audio_asbd_to_caps (&outer_asbd, NULL);
+  } else {
+    GST_ERROR_OBJECT (core_audio,
+        "Unable to get any information about hardware");
+    return NULL;
+  }
+
+  /* Append the allowed subset based on the template caps  */
+  if (!caps)
+    caps = gst_caps_new_empty ();
+  for (i = 0; i < gst_caps_get_size (in_caps); i++) {
+    GstStructure *in_s;
+
+    in_s = gst_caps_get_structure (in_caps, i);
+
+    if (gst_structure_has_name (in_s, "audio/x-ac3") ||
+        gst_structure_has_name (in_s, "audio/x-dts")) {
+      if (spdif_allowed) {
+        gst_caps_append_structure (caps, gst_structure_copy (in_s));
+      }
+    } else {
+      GstStructure *out_s;
+
+      out_s = gst_structure_copy (in_s);
+      gst_structure_set (out_s, "channels", G_TYPE_INT, channels, NULL);
+      if (channel_mask != 0) {
+        /* positioned layout */
+        gst_structure_set (out_s,
+            "channel-mask", GST_TYPE_BITMASK, channel_mask, NULL);
+      } else {
+        /* unpositioned layout */
+        gst_structure_remove_field (out_s, "channel-mask");
+      }
+
+#ifndef HAVE_IOS
+      if (core_audio->is_src && got_outer_asbd
+          && outer_asbd.mSampleRate != kAudioStreamAnyRate) {
+        /* According to Core Audio engineer, AUHAL does not support sample rate conversion.
+         * on sources. Therefore, we fixate the sample rate.
+         *
+         * "You definitely cannot do rate conversion as part of getting input from AUHAL.
+         *  That's the most common cause of those "cannot do in current context" errors."
+         * http://lists.apple.com/archives/coreaudio-api/2006/Sep/msg00088.html
+         */
+        gst_structure_set (out_s, "rate", G_TYPE_INT,
+            (gint) outer_asbd.mSampleRate, NULL);
+      }
+#endif
+
+      /* Special cases for upmixing and downmixing.
+       * Other than that, the AUs don't upmix or downmix multi-channel audio,
+       * e.g. if you push 5.1-surround audio to a stereo configuration,
+       * the left and right channels will be played accordingly,
+       * and the rest will be dropped. */
+      if (channels == 1) {
+        /* If have mono, then also offer stereo since CoreAudio downmixes to it */
+        GstStructure *stereo = gst_structure_copy (out_s);
+        gst_structure_remove_field (out_s, "channel-mask");
+        gst_structure_set (stereo, "channels", G_TYPE_INT, 2,
+            "channel-mask", GST_TYPE_BITMASK, STEREO_CHANNEL_MASK, NULL);
+        gst_caps_append_structure (caps, stereo);
+        gst_caps_append_structure (caps, out_s);
+      } else if (channels == 2 && (channel_mask == 0
+              || channel_mask == STEREO_CHANNEL_MASK)) {
+        /* If have stereo channels, then also offer mono since CoreAudio
+         * upmixes it. */
+        GstStructure *mono = gst_structure_copy (out_s);
+        gst_structure_set (mono, "channels", G_TYPE_INT, 1, NULL);
+        gst_structure_remove_field (mono, "channel-mask");
+        gst_structure_set (out_s, "channel-mask", GST_TYPE_BITMASK,
+            STEREO_CHANNEL_MASK, NULL);
+
+        gst_caps_append_structure (caps, out_s);
+        gst_caps_append_structure (caps, mono);
+      } else {
+        /* Otherwhise just add the caps */
+        gst_caps_append_structure (caps, out_s);
+      }
+    }
+  }
+
+  GST_DEBUG_OBJECT (core_audio, "Probed caps:%" GST_PTR_FORMAT, caps);
+  return caps;
+}
diff --git a/sys/osxaudio/gstosxcoreaudio.h b/sys/osxaudio/gstosxcoreaudio.h
new file mode 100644
index 0000000..ee88e3c
--- /dev/null
+++ b/sys/osxaudio/gstosxcoreaudio.h
@@ -0,0 +1,167 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012 Fluendo S.A. <support@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __GST_CORE_AUDIO_H__
+#define __GST_CORE_AUDIO_H__
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <gst/gst.h>
+#include <gst/audio/audio-channels.h>
+#ifdef HAVE_IOS
+  #include <CoreAudio/CoreAudioTypes.h>
+  #define AudioDeviceID gint
+  #define kAudioDeviceUnknown 0
+#else
+  #include <CoreAudio/CoreAudio.h>
+  #include <AudioToolbox/AudioToolbox.h>
+  #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+    #include <CoreServices/CoreServices.h>
+    #define AudioComponentFindNext FindNextComponent
+    #define AudioComponentInstanceNew OpenAComponent
+    #define AudioComponentInstanceDispose CloseComponent
+    #define AudioComponent Component
+    #define AudioComponentDescription ComponentDescription
+  #endif
+#endif
+#include <AudioUnit/AudioUnit.h>
+#include "gstosxaudioelement.h"
+
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CORE_AUDIO \
+  (gst_core_audio_get_type())
+#define GST_CORE_AUDIO(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CORE_AUDIO,GstCoreAudio))
+#define GST_CORE_AUDIO_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CORE_AUDIO,GstCoreAudioClass))
+#define GST_CORE_AUDIO_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_CORE_AUDIO,GstCoreAudioClass))
+#define GST_IS_CORE_AUDIO(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CORE_AUDIO))
+#define GST_IS_CORE_AUDIO_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CORE_AUDIO))
+
+/* TODO: Consider raising to 64 */
+#define GST_OSX_AUDIO_MAX_CHANNEL (9)
+
+#define CORE_AUDIO_FORMAT_IS_SPDIF(f) ((f).mFormat.mFormatID == 'IAC3' || (f).mFormat.mFormatID == 'iac3' || (f).mFormat.mFormatID == kAudioFormat60958AC3 || (f).mFormat.mFormatID == kAudioFormatAC3)
+
+#define CORE_AUDIO_FORMAT "FormatID: %" GST_FOURCC_FORMAT " rate: %f flags: 0x%x BytesPerPacket: %u FramesPerPacket: %u BytesPerFrame: %u ChannelsPerFrame: %u BitsPerChannel: %u"
+#define CORE_AUDIO_FORMAT_ARGS(f) GST_FOURCC_ARGS((unsigned int)(f).mFormatID),(f).mSampleRate,(unsigned int)(f).mFormatFlags,(unsigned int)(f).mBytesPerPacket,(unsigned int)(f).mFramesPerPacket,(unsigned int)(f).mBytesPerFrame,(unsigned int)(f).mChannelsPerFrame,(unsigned int)(f).mBitsPerChannel
+
+#define CORE_AUDIO_INNER_SCOPE(core_audio) ((core_audio)->is_src ? kAudioUnitScope_Output : kAudioUnitScope_Input)
+#define CORE_AUDIO_OUTER_SCOPE(core_audio) ((core_audio)->is_src ? kAudioUnitScope_Input : kAudioUnitScope_Output)
+#define CORE_AUDIO_ELEMENT(core_audio) ((core_audio)->is_src ? 1 : 0)
+
+typedef struct _GstCoreAudio GstCoreAudio;
+typedef struct _GstCoreAudioClass GstCoreAudioClass;
+
+struct _GstCoreAudio
+{
+  GObject object;
+
+  GstObject *osxbuf;
+  GstOsxAudioElementInterface *element;
+
+  gboolean is_src;
+  gboolean is_passthrough;
+  AudioDeviceID device_id;
+  gboolean cached_caps_valid; /* thread-safe flag */
+  GstCaps *cached_caps;
+  gint stream_idx;
+  gboolean io_proc_active;
+  gboolean io_proc_needs_deactivation;
+
+  /* For LPCM in/out */
+  AudioUnit audiounit;
+  UInt32 recBufferSize; /* AudioUnitRender clobbers mDataByteSize */
+  AudioBufferList *recBufferList;
+
+#ifndef HAVE_IOS
+  /* For SPDIF out */
+  pid_t hog_pid;
+  gboolean disabled_mixing;
+  AudioStreamID stream_id;
+  gboolean revert_format;
+  AudioStreamBasicDescription original_format, stream_format;
+  AudioDeviceIOProcID procID;
+#endif
+};
+
+struct _GstCoreAudioClass
+{
+  GObjectClass parent_class;
+};
+
+GType gst_core_audio_get_type                                (void);
+
+void gst_core_audio_init_debug (void);
+
+GstCoreAudio * gst_core_audio_new                            (GstObject *osxbuf);
+
+gboolean gst_core_audio_open                                 (GstCoreAudio *core_audio);
+
+gboolean gst_core_audio_close                                (GstCoreAudio *core_audio);
+
+gboolean gst_core_audio_initialize                           (GstCoreAudio *core_audio,
+                                                              AudioStreamBasicDescription format,
+                                                              GstCaps *caps,
+                                                              gboolean is_passthrough);
+
+void gst_core_audio_uninitialize                             (GstCoreAudio *core_audio);
+
+gboolean gst_core_audio_start_processing                     (GstCoreAudio *core_audio);
+
+gboolean gst_core_audio_pause_processing                     (GstCoreAudio *core_audio);
+
+gboolean gst_core_audio_stop_processing                      (GstCoreAudio *core_audio);
+
+gboolean gst_core_audio_get_samples_and_latency              (GstCoreAudio * core_audio,
+                                                              gdouble rate,
+                                                              guint *samples,
+                                                              gdouble *latency);
+
+void  gst_core_audio_set_volume                              (GstCoreAudio *core_audio,
+                                                              gfloat volume);
+
+gboolean gst_core_audio_audio_device_is_spdif_avail          (AudioDeviceID device_id);
+
+
+gboolean gst_core_audio_select_device                        (GstCoreAudio * core_audio);
+
+GstCaps *
+gst_core_audio_probe_caps (GstCoreAudio * core_audio, GstCaps * in_caps);
+
+AudioChannelLayout *
+gst_core_audio_get_channel_layout (GstCoreAudio * core_audio, gboolean outer);
+
+gboolean gst_core_audio_parse_channel_layout (AudioChannelLayout * layout,
+    guint * channels, guint64 * channel_mask, GstAudioChannelPosition * pos);
+GstCaps * gst_core_audio_asbd_to_caps (AudioStreamBasicDescription * asbd,
+    AudioChannelLayout * layout);
+
+G_END_DECLS
+
+#endif /* __GST_CORE_AUDIO_H__ */
diff --git a/sys/osxaudio/gstosxcoreaudiocommon.c b/sys/osxaudio/gstosxcoreaudiocommon.c
new file mode 100644
index 0000000..39d03ac
--- /dev/null
+++ b/sys/osxaudio/gstosxcoreaudiocommon.c
@@ -0,0 +1,552 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012-2013 Fluendo S.A. <support@fluendo.com>
+ *   Authors: Josep Torra Vallès <josep@fluendo.com>
+ *            Andoni Morales Alastruey <amorales@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "gstosxcoreaudiocommon.h"
+
+void
+gst_core_audio_remove_render_callback (GstCoreAudio * core_audio)
+{
+  AURenderCallbackStruct input;
+  OSStatus status;
+
+  /* Deactivate the render callback by calling SetRenderCallback
+   * with a NULL inputProc.
+   */
+  input.inputProc = NULL;
+  input.inputProcRefCon = NULL;
+
+  status = AudioUnitSetProperty (core_audio->audiounit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0,        /* N/A for global */
+      &input, sizeof (input));
+
+  if (status) {
+    GST_WARNING_OBJECT (core_audio->osxbuf,
+        "Failed to remove render callback %d", (int) status);
+  }
+
+  /* Remove the RenderNotify too */
+  status = AudioUnitRemoveRenderNotify (core_audio->audiounit,
+      (AURenderCallback) gst_core_audio_render_notify, core_audio);
+
+  if (status) {
+    GST_WARNING_OBJECT (core_audio->osxbuf,
+        "Failed to remove render notify callback %d", (int) status);
+  }
+
+  /* We're deactivated.. */
+  core_audio->io_proc_needs_deactivation = FALSE;
+  core_audio->io_proc_active = FALSE;
+}
+
+OSStatus
+gst_core_audio_render_notify (GstCoreAudio * core_audio,
+    AudioUnitRenderActionFlags * ioActionFlags,
+    const AudioTimeStamp * inTimeStamp,
+    unsigned int inBusNumber,
+    unsigned int inNumberFrames, AudioBufferList * ioData)
+{
+  /* Before rendering a frame, we get the PreRender notification.
+   * Here, we detach the RenderCallback if we've been paused.
+   *
+   * This is necessary (rather than just directly detaching it) to
+   * work around some thread-safety issues in CoreAudio
+   */
+  if ((*ioActionFlags) & kAudioUnitRenderAction_PreRender) {
+    if (core_audio->io_proc_needs_deactivation) {
+      gst_core_audio_remove_render_callback (core_audio);
+    }
+  }
+
+  return noErr;
+}
+
+gboolean
+gst_core_audio_io_proc_start (GstCoreAudio * core_audio)
+{
+  OSStatus status;
+  AURenderCallbackStruct input;
+  AudioUnitPropertyID callback_type;
+
+  GST_DEBUG_OBJECT (core_audio->osxbuf,
+      "osx ring buffer start ioproc: %p device_id %lu",
+      core_audio->element->io_proc, (gulong) core_audio->device_id);
+  if (!core_audio->io_proc_active) {
+    callback_type = core_audio->is_src ?
+        kAudioOutputUnitProperty_SetInputCallback :
+        kAudioUnitProperty_SetRenderCallback;
+
+    input.inputProc = (AURenderCallback) core_audio->element->io_proc;
+    input.inputProcRefCon = core_audio->osxbuf;
+
+    status = AudioUnitSetProperty (core_audio->audiounit, callback_type, kAudioUnitScope_Global, 0,     /* N/A for global */
+        &input, sizeof (input));
+
+    if (status) {
+      GST_ERROR_OBJECT (core_audio->osxbuf,
+          "AudioUnitSetProperty failed: %d", (int) status);
+      return FALSE;
+    }
+    // ### does it make sense to do this notify stuff for input mode?
+    status = AudioUnitAddRenderNotify (core_audio->audiounit,
+        (AURenderCallback) gst_core_audio_render_notify, core_audio);
+
+    if (status) {
+      GST_ERROR_OBJECT (core_audio->osxbuf,
+          "AudioUnitAddRenderNotify failed %d", (int) status);
+      return FALSE;
+    }
+    core_audio->io_proc_active = TRUE;
+  }
+
+  core_audio->io_proc_needs_deactivation = FALSE;
+
+  status = AudioOutputUnitStart (core_audio->audiounit);
+  if (status) {
+    GST_ERROR_OBJECT (core_audio->osxbuf, "AudioOutputUnitStart failed: %d",
+        (int) status);
+    return FALSE;
+  }
+  return TRUE;
+}
+
+gboolean
+gst_core_audio_io_proc_stop (GstCoreAudio * core_audio)
+{
+  OSErr status;
+
+  GST_DEBUG_OBJECT (core_audio->osxbuf,
+      "osx ring buffer stop ioproc: %p device_id %lu",
+      core_audio->element->io_proc, (gulong) core_audio->device_id);
+
+  status = AudioOutputUnitStop (core_audio->audiounit);
+  if (status) {
+    GST_WARNING_OBJECT (core_audio->osxbuf,
+        "AudioOutputUnitStop failed: %d", (int) status);
+  }
+  // ###: why is it okay to directly remove from here but not from pause() ?
+  if (core_audio->io_proc_active) {
+    gst_core_audio_remove_render_callback (core_audio);
+  }
+  return TRUE;
+}
+
+AudioBufferList *
+buffer_list_alloc (UInt32 channels, UInt32 size, gboolean interleaved)
+{
+  AudioBufferList *list;
+  gsize list_size;
+  UInt32 num_buffers, n;
+
+  num_buffers = interleaved ? 1 : channels;
+  /* AudioBufferList member mBuffers is variable-length array */
+  list_size = G_STRUCT_OFFSET (AudioBufferList, mBuffers[num_buffers]);
+  list = (AudioBufferList *) g_malloc (list_size);
+
+  list->mNumberBuffers = num_buffers;
+  for (n = 0; n < num_buffers; ++n) {
+    /* See http://lists.apple.com/archives/coreaudio-api/2015/Feb/msg00027.html */
+    list->mBuffers[n].mNumberChannels = interleaved ? channels : 1;
+    /* AudioUnitRender will keep overwriting mDataByteSize */
+    list->mBuffers[n].mDataByteSize = size;
+    list->mBuffers[n].mData = g_malloc (size);
+  }
+
+  return list;
+}
+
+void
+buffer_list_free (AudioBufferList * list)
+{
+  UInt32 n;
+
+  if (list == NULL)
+    return;
+
+  for (n = 0; n < list->mNumberBuffers; ++n) {
+    g_free (list->mBuffers[n].mData);
+  }
+
+  g_free (list);
+}
+
+gboolean
+gst_core_audio_bind_device (GstCoreAudio * core_audio)
+{
+  OSStatus status;
+
+  /* Specify which device we're using. */
+  GST_DEBUG_OBJECT (core_audio->osxbuf, "Bind AudioUnit to device %d",
+      (int) core_audio->device_id);
+  status = AudioUnitSetProperty (core_audio->audiounit,
+      kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0,
+      &core_audio->device_id, sizeof (AudioDeviceID));
+  if (status) {
+    GST_ERROR_OBJECT (core_audio->osxbuf, "Failed binding to device: %d",
+        (int) status);
+    goto audiounit_error;
+  }
+  return TRUE;
+
+audiounit_error:
+  if (core_audio->recBufferList) {
+    buffer_list_free (core_audio->recBufferList);
+    core_audio->recBufferList = NULL;
+  }
+  return FALSE;
+}
+
+static gboolean
+_core_audio_set_property (GstCoreAudio * core_audio, AudioUnitPropertyID inID,
+    void *inData, UInt32 inDataSize)
+{
+  OSStatus status;
+  AudioUnitScope scope;
+  AudioUnitElement element;
+
+  scope = CORE_AUDIO_INNER_SCOPE (core_audio);
+  element = CORE_AUDIO_ELEMENT (core_audio);
+
+  status =
+      AudioUnitSetProperty (core_audio->audiounit, inID, scope, element, inData,
+      inDataSize);
+
+  if (status != noErr) {
+    GST_WARNING_OBJECT (core_audio->osxbuf,
+        "Failed to set Audio Unit property: %d", (int) status);
+    return FALSE;;
+  }
+
+  return TRUE;
+}
+
+/* The AudioUnit must be uninitialized before calling this */
+gboolean
+gst_core_audio_set_channel_layout (GstCoreAudio * core_audio,
+    gint channels, GstCaps * caps)
+{
+  AudioChannelLayout *layout = NULL;
+  gboolean ret;
+  gsize layoutSize;
+  gint i;
+  GstStructure *structure;
+  GstAudioChannelPosition positions[GST_OSX_AUDIO_MAX_CHANNEL];
+  guint64 channel_mask;
+
+  g_return_val_if_fail (channels <= GST_OSX_AUDIO_MAX_CHANNEL, FALSE);
+
+  /* Determine the channel positions */
+  structure = gst_caps_get_structure (caps, 0);
+  channel_mask = 0;
+  gst_structure_get (structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask,
+      NULL);
+
+  if (channel_mask != 0)
+    gst_audio_channel_positions_from_mask (channels, channel_mask, positions);
+
+  /* AudioChannelLayout member mChannelDescriptions is variable-length array */
+  layoutSize =
+      G_STRUCT_OFFSET (AudioChannelLayout, mChannelDescriptions[channels]);
+  layout = g_malloc (layoutSize);
+
+  /* Fill out the AudioChannelLayout */
+  layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
+  layout->mChannelBitmap = 0;   /* Not used */
+  layout->mNumberChannelDescriptions = channels;
+  for (i = 0; i < channels; i++) {
+    if (channel_mask != 0) {
+      layout->mChannelDescriptions[i].mChannelLabel =
+          gst_audio_channel_position_to_core_audio (positions[i], i);
+    } else {
+      /* Discrete channel numbers are ORed into this */
+      layout->mChannelDescriptions[i].mChannelLabel =
+          kAudioChannelLabel_Discrete_0 | i;
+    }
+
+    /* Others unused */
+    layout->mChannelDescriptions[i].mChannelFlags = kAudioChannelFlags_AllOff;
+    layout->mChannelDescriptions[i].mCoordinates[0] = 0.f;
+    layout->mChannelDescriptions[i].mCoordinates[1] = 0.f;
+    layout->mChannelDescriptions[i].mCoordinates[2] = 0.f;
+  }
+
+  /* Sets GStreamer-ordered channel layout on the inner scope.
+   * Reordering between the inner scope and outer scope is handled
+   * by the Audio Unit itself. */
+  ret = _core_audio_set_property (core_audio,
+      kAudioUnitProperty_AudioChannelLayout, layout, layoutSize);
+
+  g_free (layout);
+  return ret;
+}
+
+/* The AudioUnit must be uninitialized before calling this */
+gboolean
+gst_core_audio_set_format (GstCoreAudio * core_audio,
+    AudioStreamBasicDescription format)
+{
+  GST_DEBUG_OBJECT (core_audio->osxbuf, "Setting format for AudioUnit");
+
+  return _core_audio_set_property (core_audio, kAudioUnitProperty_StreamFormat,
+      &format, sizeof (AudioStreamBasicDescription));
+}
+
+gboolean
+gst_core_audio_open_device (GstCoreAudio * core_audio, OSType sub_type,
+    const gchar * adesc)
+{
+  AudioComponentDescription desc;
+  AudioComponent comp;
+  OSStatus status;
+  AudioUnit unit;
+  UInt32 enableIO;
+
+  desc.componentType = kAudioUnitType_Output;
+  desc.componentSubType = sub_type;
+  desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+  desc.componentFlags = 0;
+  desc.componentFlagsMask = 0;
+
+  comp = AudioComponentFindNext (NULL, &desc);
+
+  if (comp == NULL) {
+    GST_WARNING_OBJECT (core_audio->osxbuf, "Couldn't find %s component",
+        adesc);
+    return FALSE;
+  }
+
+  status = AudioComponentInstanceNew (comp, &unit);
+
+  if (status) {
+    GST_ERROR_OBJECT (core_audio->osxbuf, "Couldn't open %s component %d",
+        adesc, (int) status);
+    return FALSE;
+  }
+
+  if (core_audio->is_src) {
+    /* enable input */
+    enableIO = 1;
+    status = AudioUnitSetProperty (unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1,   /* 1 = input element */
+        &enableIO, sizeof (enableIO));
+
+    if (status) {
+      AudioComponentInstanceDispose (unit);
+      GST_WARNING_OBJECT (core_audio->osxbuf, "Failed to enable input: %d",
+          (int) status);
+      return FALSE;
+    }
+
+    /* disable output */
+    enableIO = 0;
+    status = AudioUnitSetProperty (unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0,  /* 0 = output element */
+        &enableIO, sizeof (enableIO));
+
+    if (status) {
+      AudioComponentInstanceDispose (unit);
+      GST_WARNING_OBJECT (core_audio->osxbuf, "Failed to disable output: %d",
+          (int) status);
+      return FALSE;
+    }
+  }
+
+  GST_DEBUG_OBJECT (core_audio->osxbuf, "Created %s AudioUnit: %p", adesc,
+      unit);
+  core_audio->audiounit = unit;
+  return TRUE;
+}
+
+AudioChannelLabel
+gst_audio_channel_position_to_core_audio (GstAudioChannelPosition
+    position, int channel)
+{
+  switch (position) {
+    case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT:
+      return kAudioChannelLabel_Left;
+    case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT:
+      return kAudioChannelLabel_Right;
+    case GST_AUDIO_CHANNEL_POSITION_REAR_CENTER:
+      return kAudioChannelLabel_CenterSurround;
+    case GST_AUDIO_CHANNEL_POSITION_REAR_LEFT:
+      return kAudioChannelLabel_LeftSurround;
+    case GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT:
+      return kAudioChannelLabel_RightSurround;
+    case GST_AUDIO_CHANNEL_POSITION_LFE1:
+      return kAudioChannelLabel_LFEScreen;
+    case GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER:
+      return kAudioChannelLabel_Center;
+    case GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT:
+      return kAudioChannelLabel_LeftSurroundDirect;
+    case GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT:
+      return kAudioChannelLabel_RightSurroundDirect;
+    case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
+      return kAudioChannelLabel_LeftCenter;
+    case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
+      return kAudioChannelLabel_RightCenter;
+    case GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT:
+      return kAudioChannelLabel_TopBackLeft;
+    case GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER:
+      return kAudioChannelLabel_TopBackCenter;
+    case GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT:
+      return kAudioChannelLabel_TopBackRight;
+    case GST_AUDIO_CHANNEL_POSITION_WIDE_LEFT:
+      return kAudioChannelLabel_LeftWide;
+    case GST_AUDIO_CHANNEL_POSITION_WIDE_RIGHT:
+      return kAudioChannelLabel_RightWide;
+    case GST_AUDIO_CHANNEL_POSITION_LFE2:
+      return kAudioChannelLabel_LFE2;
+    case GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT:
+      return kAudioChannelLabel_VerticalHeightLeft;
+    case GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT:
+      return kAudioChannelLabel_VerticalHeightRight;
+    case GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER:
+      return kAudioChannelLabel_VerticalHeightCenter;
+
+      /* Special position values */
+    case GST_AUDIO_CHANNEL_POSITION_NONE:
+      return kAudioChannelLabel_Discrete_0 | channel;
+    case GST_AUDIO_CHANNEL_POSITION_MONO:
+      return kAudioChannelLabel_Mono;
+
+      /* Following positions are unmapped --
+       * i.e. mapped to kAudioChannelLabel_Unknown: */
+    case GST_AUDIO_CHANNEL_POSITION_TOP_CENTER:
+    case GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_LEFT:
+    case GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_RIGHT:
+    case GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_CENTER:
+    case GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_LEFT:
+    case GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_RIGHT:
+    case GST_AUDIO_CHANNEL_POSITION_SURROUND_LEFT:
+    case GST_AUDIO_CHANNEL_POSITION_SURROUND_RIGHT:
+    default:
+      return kAudioChannelLabel_Unknown;
+  }
+}
+
+/* Performs a best-effort conversion. 'channel' is used for warnings only. */
+GstAudioChannelPosition
+gst_core_audio_channel_label_to_gst (AudioChannelLabel label,
+    int channel, gboolean warn)
+{
+  switch (label) {
+    case kAudioChannelLabel_Left:
+      return GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
+    case kAudioChannelLabel_Right:
+      return GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
+    case kAudioChannelLabel_Center:
+      return GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
+    case kAudioChannelLabel_LFEScreen:
+      return GST_AUDIO_CHANNEL_POSITION_LFE1;
+    case kAudioChannelLabel_LeftSurround:
+      return GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
+    case kAudioChannelLabel_RightSurround:
+      return GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
+    case kAudioChannelLabel_LeftSurroundDirect:
+      return GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT;
+    case kAudioChannelLabel_RightSurroundDirect:
+      return GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT;
+    case kAudioChannelLabel_CenterSurround:
+      return GST_AUDIO_CHANNEL_POSITION_REAR_CENTER;
+    case kAudioChannelLabel_LeftCenter:
+      return GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
+    case kAudioChannelLabel_RightCenter:
+      return GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
+    case kAudioChannelLabel_TopBackLeft:
+      return GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT;
+    case kAudioChannelLabel_TopBackCenter:
+      return GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER;
+    case kAudioChannelLabel_TopBackRight:
+      return GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT;
+    case kAudioChannelLabel_LeftWide:
+      return GST_AUDIO_CHANNEL_POSITION_WIDE_LEFT;
+    case kAudioChannelLabel_RightWide:
+      return GST_AUDIO_CHANNEL_POSITION_WIDE_RIGHT;
+    case kAudioChannelLabel_LFE2:
+      return GST_AUDIO_CHANNEL_POSITION_LFE2;
+    case kAudioChannelLabel_VerticalHeightLeft:
+      return GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT;
+    case kAudioChannelLabel_VerticalHeightRight:
+      return GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT;
+    case kAudioChannelLabel_VerticalHeightCenter:
+      return GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER;
+
+      /* Special position values */
+
+    case kAudioChannelLabel_Mono:
+      /* GST_AUDIO_CHANNEL_POSITION_MONO is only for 1-channel layouts */
+      return GST_AUDIO_CHANNEL_POSITION_INVALID;
+    case kAudioChannelLabel_Discrete:
+      return GST_AUDIO_CHANNEL_POSITION_NONE;
+
+      /*
+         Following labels are unmapped --
+         i.e. mapped to GST_AUDIO_CHANNEL_POSITION_INVALID:
+       */
+    case kAudioChannelLabel_RearSurroundLeft:
+    case kAudioChannelLabel_RearSurroundRight:
+    case kAudioChannelLabel_TopCenterSurround:
+    case kAudioChannelLabel_LeftTotal:
+    case kAudioChannelLabel_RightTotal:
+    case kAudioChannelLabel_HearingImpaired:
+    case kAudioChannelLabel_Narration:
+    case kAudioChannelLabel_DialogCentricMix:
+    case kAudioChannelLabel_CenterSurroundDirect:
+    case kAudioChannelLabel_Haptic:
+    default:
+      if (label >> 16 != 0) {   /* kAudioChannelLabel_Discrete_N */
+        /* no way to store discrete channel order */
+        if (warn)
+          GST_WARNING
+              ("Core Audio channel %u labeled kAudioChannelLabel_Discrete_%u -- discrete order will be lost",
+              channel, ((unsigned int) label) & 0xFFFF);
+        return GST_AUDIO_CHANNEL_POSITION_NONE;
+      } else {
+        if (warn)
+          GST_WARNING
+              ("Core Audio channel %u has unsupported label %d and will be skipped",
+              channel, (int) label);
+        return GST_AUDIO_CHANNEL_POSITION_INVALID;
+      }
+  }
+}
+
+void
+gst_core_audio_dump_channel_layout (AudioChannelLayout * channel_layout)
+{
+  UInt32 i;
+
+  GST_DEBUG ("mChannelLayoutTag: 0x%lx",
+      (unsigned long) channel_layout->mChannelLayoutTag);
+  GST_DEBUG ("mChannelBitmap: 0x%lx",
+      (unsigned long) channel_layout->mChannelBitmap);
+  GST_DEBUG ("mNumberChannelDescriptions: %lu",
+      (unsigned long) channel_layout->mNumberChannelDescriptions);
+  for (i = 0; i < channel_layout->mNumberChannelDescriptions; i++) {
+    AudioChannelDescription *channel_desc =
+        &channel_layout->mChannelDescriptions[i];
+    GST_DEBUG ("  mChannelLabel: 0x%lx mChannelFlags: 0x%lx "
+        "mCoordinates[0]: %f mCoordinates[1]: %f "
+        "mCoordinates[2]: %f",
+        (unsigned long) channel_desc->mChannelLabel,
+        (unsigned long) channel_desc->mChannelFlags,
+        channel_desc->mCoordinates[0], channel_desc->mCoordinates[1],
+        channel_desc->mCoordinates[2]);
+  }
+}
diff --git a/sys/osxaudio/gstosxcoreaudiocommon.h b/sys/osxaudio/gstosxcoreaudiocommon.h
new file mode 100644
index 0000000..c4602a6
--- /dev/null
+++ b/sys/osxaudio/gstosxcoreaudiocommon.h
@@ -0,0 +1,66 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012-2013 Fluendo S.A. <support@fluendo.com>
+ *   Authors: Josep Torra Vallès <josep@fluendo.com>
+ *            Andoni Morales Alastruey <amorales@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "gstosxcoreaudio.h"
+#include <gst/audio/audio-channels.h>
+
+typedef struct
+{
+  GMutex lock;
+  GCond cond;
+} PropertyMutex;
+
+gboolean gst_core_audio_bind_device                       (GstCoreAudio *core_audio);
+
+void gst_core_audio_dump_channel_layout                   (AudioChannelLayout * channel_layout);
+
+void gst_core_audio_remove_render_callback                (GstCoreAudio * core_audio);
+
+gboolean gst_core_audio_io_proc_start                     (GstCoreAudio * core_audio);
+
+gboolean gst_core_audio_io_proc_stop                      (GstCoreAudio * core_audio);
+
+AudioBufferList * buffer_list_alloc                       (UInt32 channels, UInt32 size, gboolean interleaved);
+
+void buffer_list_free                                     (AudioBufferList * list);
+
+gboolean gst_core_audio_set_format                        (GstCoreAudio * core_audio,
+                                                           AudioStreamBasicDescription format);
+
+gboolean gst_core_audio_set_channel_layout                (GstCoreAudio * core_audio,
+                                                           gint channels, GstCaps * caps);
+
+gboolean gst_core_audio_open_device                       (GstCoreAudio *core_audio,
+                                                           OSType sub_type,
+                                                           const gchar *adesc);
+
+OSStatus gst_core_audio_render_notify                     (GstCoreAudio * core_audio,
+                                                           AudioUnitRenderActionFlags * ioActionFlags,
+                                                           const AudioTimeStamp * inTimeStamp,
+                                                           unsigned int inBusNumber,
+                                                           unsigned int inNumberFrames,
+                                                           AudioBufferList * ioData);
+
+AudioChannelLabel gst_audio_channel_position_to_core_audio (GstAudioChannelPosition position, int channel);
+
+GstAudioChannelPosition gst_core_audio_channel_label_to_gst (AudioChannelLabel label, int channel, gboolean warn);
diff --git a/sys/osxaudio/gstosxcoreaudiohal.c b/sys/osxaudio/gstosxcoreaudiohal.c
new file mode 100644
index 0000000..4505c29
--- /dev/null
+++ b/sys/osxaudio/gstosxcoreaudiohal.c
@@ -0,0 +1,1287 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012-2013 Fluendo S.A. <support@fluendo.com>
+ *   Authors: Josep Torra Vallès <josep@fluendo.com>
+ *            Andoni Morales Alastruey <amorales@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <unistd.h>             /* for getpid */
+#include "gstosxaudiosink.h"
+
+static inline gboolean
+_audio_system_set_runloop (CFRunLoopRef runLoop)
+{
+  OSStatus status = noErr;
+
+  gboolean res = FALSE;
+
+  AudioObjectPropertyAddress runloopAddress = {
+    kAudioHardwarePropertyRunLoop,
+    kAudioObjectPropertyScopeGlobal,
+    kAudioObjectPropertyElementMaster
+  };
+
+  status = AudioObjectSetPropertyData (kAudioObjectSystemObject,
+      &runloopAddress, 0, NULL, sizeof (CFRunLoopRef), &runLoop);
+  if (status == noErr) {
+    res = TRUE;
+  } else {
+    GST_ERROR ("failed to set runloop to %p: %d", runLoop, (int) status);
+  }
+
+  return res;
+}
+
+static inline AudioDeviceID
+_audio_system_get_default_device (gboolean output)
+{
+  OSStatus status = noErr;
+  UInt32 propertySize = sizeof (AudioDeviceID);
+  AudioDeviceID device_id = kAudioDeviceUnknown;
+  AudioObjectPropertySelector prop_selector;
+
+  prop_selector = output ? kAudioHardwarePropertyDefaultOutputDevice :
+      kAudioHardwarePropertyDefaultInputDevice;
+
+  AudioObjectPropertyAddress defaultDeviceAddress = {
+    prop_selector,
+    kAudioObjectPropertyScopeGlobal,
+    kAudioObjectPropertyElementMaster
+  };
+
+  status = AudioObjectGetPropertyData (kAudioObjectSystemObject,
+      &defaultDeviceAddress, 0, NULL, &propertySize, &device_id);
+  if (status != noErr) {
+    GST_ERROR ("failed getting default output device: %d", (int) status);
+  }
+
+  GST_DEBUG ("Default device id: %u", (unsigned) device_id);
+
+  return device_id;
+}
+
+static inline AudioDeviceID *
+_audio_system_get_devices (gint * ndevices)
+{
+  OSStatus status = noErr;
+  UInt32 propertySize = 0;
+  AudioDeviceID *devices = NULL;
+
+  AudioObjectPropertyAddress audioDevicesAddress = {
+    kAudioHardwarePropertyDevices,
+    kAudioObjectPropertyScopeGlobal,
+    kAudioObjectPropertyElementMaster
+  };
+
+  status = AudioObjectGetPropertyDataSize (kAudioObjectSystemObject,
+      &audioDevicesAddress, 0, NULL, &propertySize);
+  if (status != noErr) {
+    GST_WARNING ("failed getting number of devices: %d", (int) status);
+    return NULL;
+  }
+
+  *ndevices = propertySize / sizeof (AudioDeviceID);
+
+  devices = (AudioDeviceID *) g_malloc (propertySize);
+  if (devices) {
+    status = AudioObjectGetPropertyData (kAudioObjectSystemObject,
+        &audioDevicesAddress, 0, NULL, &propertySize, devices);
+    if (status != noErr) {
+      GST_WARNING ("failed getting the list of devices: %d", (int) status);
+      g_free (devices);
+      *ndevices = 0;
+      return NULL;
+    }
+  }
+  return devices;
+}
+
+static inline gboolean
+_audio_device_is_alive (AudioDeviceID device_id, gboolean output)
+{
+  OSStatus status = noErr;
+  int alive = FALSE;
+  UInt32 propertySize = sizeof (alive);
+  AudioObjectPropertyScope prop_scope;
+
+  prop_scope = output ? kAudioDevicePropertyScopeOutput :
+      kAudioDevicePropertyScopeInput;
+
+  AudioObjectPropertyAddress audioDeviceAliveAddress = {
+    kAudioDevicePropertyDeviceIsAlive,
+    prop_scope,
+    kAudioObjectPropertyElementMaster
+  };
+
+  status = AudioObjectGetPropertyData (device_id,
+      &audioDeviceAliveAddress, 0, NULL, &propertySize, &alive);
+  if (status != noErr) {
+    alive = FALSE;
+  }
+
+  return alive;
+}
+
+static inline guint
+_audio_device_get_latency (AudioDeviceID device_id)
+{
+  OSStatus status = noErr;
+  UInt32 latency = 0;
+  UInt32 propertySize = sizeof (latency);
+
+  AudioObjectPropertyAddress audioDeviceLatencyAddress = {
+    kAudioDevicePropertyLatency,
+    kAudioDevicePropertyScopeOutput,
+    kAudioObjectPropertyElementMaster
+  };
+
+  status = AudioObjectGetPropertyData (device_id,
+      &audioDeviceLatencyAddress, 0, NULL, &propertySize, &latency);
+  if (status != noErr) {
+    GST_ERROR ("failed to get latency: %d", (int) status);
+    latency = -1;
+  }
+
+  return latency;
+}
+
+static inline pid_t
+_audio_device_get_hog (AudioDeviceID device_id)
+{
+  OSStatus status = noErr;
+  pid_t hog_pid;
+  UInt32 propertySize = sizeof (hog_pid);
+
+  AudioObjectPropertyAddress audioDeviceHogModeAddress = {
+    kAudioDevicePropertyHogMode,
+    kAudioDevicePropertyScopeOutput,
+    kAudioObjectPropertyElementMaster
+  };
+
+  status = AudioObjectGetPropertyData (device_id,
+      &audioDeviceHogModeAddress, 0, NULL, &propertySize, &hog_pid);
+  if (status != noErr) {
+    GST_ERROR ("failed to get hog: %d", (int) status);
+    hog_pid = -1;
+  }
+
+  return hog_pid;
+}
+
+static inline gboolean
+_audio_device_set_hog (AudioDeviceID device_id, pid_t hog_pid)
+{
+  OSStatus status = noErr;
+  UInt32 propertySize = sizeof (hog_pid);
+  gboolean res = FALSE;
+
+  AudioObjectPropertyAddress audioDeviceHogModeAddress = {
+    kAudioDevicePropertyHogMode,
+    kAudioDevicePropertyScopeOutput,
+    kAudioObjectPropertyElementMaster
+  };
+
+  status = AudioObjectSetPropertyData (device_id,
+      &audioDeviceHogModeAddress, 0, NULL, propertySize, &hog_pid);
+
+  if (status == noErr) {
+    res = TRUE;
+  } else {
+    GST_ERROR ("failed to set hog: %d", (int) status);
+  }
+
+  return res;
+}
+
+static inline gboolean
+_audio_device_set_mixing (AudioDeviceID device_id, gboolean enable_mix)
+{
+  OSStatus status = noErr;
+  UInt32 propertySize = 0, can_mix = enable_mix;
+  Boolean writable = FALSE;
+  gboolean res = FALSE;
+
+  AudioObjectPropertyAddress audioDeviceSupportsMixingAddress = {
+    kAudioDevicePropertySupportsMixing,
+    kAudioObjectPropertyScopeGlobal,
+    kAudioObjectPropertyElementMaster
+  };
+
+  if (AudioObjectHasProperty (device_id, &audioDeviceSupportsMixingAddress)) {
+    /* Set mixable to false if we are allowed to */
+    status = AudioObjectIsPropertySettable (device_id,
+        &audioDeviceSupportsMixingAddress, &writable);
+    if (status) {
+      GST_DEBUG ("AudioObjectIsPropertySettable: %d", (int) status);
+    }
+    status = AudioObjectGetPropertyDataSize (device_id,
+        &audioDeviceSupportsMixingAddress, 0, NULL, &propertySize);
+    if (status) {
+      GST_DEBUG ("AudioObjectGetPropertyDataSize: %d", (int) status);
+    }
+    status = AudioObjectGetPropertyData (device_id,
+        &audioDeviceSupportsMixingAddress, 0, NULL, &propertySize, &can_mix);
+    if (status) {
+      GST_DEBUG ("AudioObjectGetPropertyData: %d", (int) status);
+    }
+
+    if (status == noErr && writable) {
+      can_mix = enable_mix;
+      status = AudioObjectSetPropertyData (device_id,
+          &audioDeviceSupportsMixingAddress, 0, NULL, propertySize, &can_mix);
+      res = TRUE;
+    }
+
+    if (status != noErr) {
+      GST_ERROR ("failed to set mixmode: %d", (int) status);
+    }
+  } else {
+    GST_DEBUG ("property not found, mixing coudln't be changed");
+  }
+
+  return res;
+}
+
+static inline gchar *
+_audio_device_get_name (AudioDeviceID device_id, gboolean output)
+{
+  OSStatus status = noErr;
+  UInt32 propertySize = 0;
+  gchar *device_name = NULL;
+  AudioObjectPropertyScope prop_scope;
+
+  prop_scope = output ? kAudioDevicePropertyScopeOutput :
+      kAudioDevicePropertyScopeInput;
+
+  AudioObjectPropertyAddress deviceNameAddress = {
+    kAudioDevicePropertyDeviceName,
+    prop_scope,
+    kAudioObjectPropertyElementMaster
+  };
+
+  /* Get the length of the device name */
+  status = AudioObjectGetPropertyDataSize (device_id,
+      &deviceNameAddress, 0, NULL, &propertySize);
+  if (status != noErr) {
+    goto beach;
+  }
+
+  /* Get the name of the device */
+  device_name = (gchar *) g_malloc (propertySize);
+  status = AudioObjectGetPropertyData (device_id,
+      &deviceNameAddress, 0, NULL, &propertySize, device_name);
+  if (status != noErr) {
+    g_free (device_name);
+    device_name = NULL;
+  }
+
+beach:
+  return device_name;
+}
+
+static inline gboolean
+_audio_device_has_output (AudioDeviceID device_id)
+{
+  OSStatus status = noErr;
+  UInt32 propertySize;
+
+  AudioObjectPropertyAddress streamsAddress = {
+    kAudioDevicePropertyStreams,
+    kAudioDevicePropertyScopeOutput,
+    kAudioObjectPropertyElementMaster
+  };
+
+  status = AudioObjectGetPropertyDataSize (device_id,
+      &streamsAddress, 0, NULL, &propertySize);
+  if (status != noErr) {
+    return FALSE;
+  }
+  if (propertySize == 0) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+#ifdef GST_CORE_AUDIO_DEBUG
+static AudioChannelLayout *
+gst_core_audio_audio_device_get_channel_layout (AudioDeviceID device_id,
+    gboolean output)
+{
+  OSStatus status = noErr;
+  UInt32 propertySize = 0;
+  AudioChannelLayout *layout = NULL;
+  AudioObjectPropertyScope prop_scope;
+
+  prop_scope = output ? kAudioDevicePropertyScopeOutput :
+      kAudioDevicePropertyScopeInput;
+
+  AudioObjectPropertyAddress channelLayoutAddress = {
+    kAudioDevicePropertyPreferredChannelLayout,
+    prop_scope,
+    kAudioObjectPropertyElementMaster
+  };
+
+  /* Get the length of the default channel layout structure */
+  status = AudioObjectGetPropertyDataSize (device_id,
+      &channelLayoutAddress, 0, NULL, &propertySize);
+  if (status != noErr) {
+    GST_ERROR ("failed to get preferred layout: %d", (int) status);
+    goto beach;
+  }
+
+  /* Get the default channel layout of the device */
+  layout = (AudioChannelLayout *) g_malloc (propertySize);
+  status = AudioObjectGetPropertyData (device_id,
+      &channelLayoutAddress, 0, NULL, &propertySize, layout);
+  if (status != noErr) {
+    GST_ERROR ("failed to get preferred layout: %d", (int) status);
+    goto failed;
+  }
+
+  if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) {
+    /* bitmap defined channellayout */
+    status =
+        AudioFormatGetProperty (kAudioFormatProperty_ChannelLayoutForBitmap,
+        sizeof (UInt32), &layout->mChannelBitmap, &propertySize, layout);
+    if (status != noErr) {
+      GST_ERROR ("failed to get layout for bitmap: %d", (int) status);
+      goto failed;
+    }
+  } else if (layout->mChannelLayoutTag !=
+      kAudioChannelLayoutTag_UseChannelDescriptions) {
+    /* layouttags defined channellayout */
+    status = AudioFormatGetProperty (kAudioFormatProperty_ChannelLayoutForTag,
+        sizeof (AudioChannelLayoutTag), &layout->mChannelLayoutTag,
+        &propertySize, layout);
+    if (status != noErr) {
+      GST_ERROR ("failed to get layout for tag: %d", (int) status);
+      goto failed;
+    }
+  }
+
+  gst_core_audio_dump_channel_layout (layout);
+
+beach:
+  return layout;
+
+failed:
+  g_free (layout);
+  return NULL;
+}
+#endif
+
+static inline AudioStreamID *
+_audio_device_get_streams (AudioDeviceID device_id, gint * nstreams)
+{
+  OSStatus status = noErr;
+  UInt32 propertySize = 0;
+  AudioStreamID *streams = NULL;
+
+  AudioObjectPropertyAddress streamsAddress = {
+    kAudioDevicePropertyStreams,
+    kAudioDevicePropertyScopeOutput,
+    kAudioObjectPropertyElementMaster
+  };
+
+  status = AudioObjectGetPropertyDataSize (device_id,
+      &streamsAddress, 0, NULL, &propertySize);
+  if (status != noErr) {
+    GST_WARNING ("failed getting number of streams: %d", (int) status);
+    return NULL;
+  }
+
+  *nstreams = propertySize / sizeof (AudioStreamID);
+  streams = (AudioStreamID *) g_malloc (propertySize);
+
+  if (streams) {
+    status = AudioObjectGetPropertyData (device_id,
+        &streamsAddress, 0, NULL, &propertySize, streams);
+    if (status != noErr) {
+      GST_WARNING ("failed getting the list of streams: %d", (int) status);
+      g_free (streams);
+      *nstreams = 0;
+      return NULL;
+    }
+  }
+
+  return streams;
+}
+
+static inline guint
+_audio_stream_get_latency (AudioStreamID stream_id)
+{
+  OSStatus status = noErr;
+  UInt32 latency;
+  UInt32 propertySize = sizeof (latency);
+
+  AudioObjectPropertyAddress latencyAddress = {
+    kAudioStreamPropertyLatency,
+    kAudioObjectPropertyScopeGlobal,
+    kAudioObjectPropertyElementMaster
+  };
+
+  status = AudioObjectGetPropertyData (stream_id,
+      &latencyAddress, 0, NULL, &propertySize, &latency);
+  if (status != noErr) {
+    GST_ERROR ("failed to get latency: %d", (int) status);
+    latency = -1;
+  }
+
+  return latency;
+}
+
+static inline gboolean
+_audio_stream_get_current_format (AudioStreamID stream_id,
+    AudioStreamBasicDescription * format)
+{
+  OSStatus status = noErr;
+  UInt32 propertySize = sizeof (AudioStreamBasicDescription);
+
+  AudioObjectPropertyAddress formatAddress = {
+    kAudioStreamPropertyPhysicalFormat,
+    kAudioObjectPropertyScopeGlobal,
+    kAudioObjectPropertyElementMaster
+  };
+
+  status = AudioObjectGetPropertyData (stream_id,
+      &formatAddress, 0, NULL, &propertySize, format);
+  if (status != noErr) {
+    GST_ERROR ("failed to get current format: %d", (int) status);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static inline gboolean
+_audio_stream_set_current_format (AudioStreamID stream_id,
+    AudioStreamBasicDescription format)
+{
+  OSStatus status = noErr;
+  UInt32 propertySize = sizeof (AudioStreamBasicDescription);
+
+  AudioObjectPropertyAddress formatAddress = {
+    kAudioStreamPropertyPhysicalFormat,
+    kAudioObjectPropertyScopeGlobal,
+    kAudioObjectPropertyElementMaster
+  };
+
+  status = AudioObjectSetPropertyData (stream_id,
+      &formatAddress, 0, NULL, propertySize, &format);
+  if (status != noErr) {
+    GST_ERROR ("failed to set current format: %d", (int) status);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static inline AudioStreamRangedDescription *
+_audio_stream_get_formats (AudioStreamID stream_id, gint * nformats)
+{
+  OSStatus status = noErr;
+  UInt32 propertySize = 0;
+  AudioStreamRangedDescription *formats = NULL;
+
+  AudioObjectPropertyAddress formatsAddress = {
+    kAudioStreamPropertyAvailablePhysicalFormats,
+    kAudioObjectPropertyScopeGlobal,
+    kAudioObjectPropertyElementMaster
+  };
+
+  status = AudioObjectGetPropertyDataSize (stream_id,
+      &formatsAddress, 0, NULL, &propertySize);
+  if (status != noErr) {
+    GST_WARNING ("failed getting number of stream formats: %d", (int) status);
+    return NULL;
+  }
+
+  *nformats = propertySize / sizeof (AudioStreamRangedDescription);
+
+  formats = (AudioStreamRangedDescription *) g_malloc (propertySize);
+  if (formats) {
+    status = AudioObjectGetPropertyData (stream_id,
+        &formatsAddress, 0, NULL, &propertySize, formats);
+    if (status != noErr) {
+      GST_WARNING ("failed getting the list of stream formats: %d",
+          (int) status);
+      g_free (formats);
+      *nformats = 0;
+      return NULL;
+    }
+  }
+  return formats;
+}
+
+static inline gboolean
+_audio_stream_is_spdif_avail (AudioStreamID stream_id)
+{
+  AudioStreamRangedDescription *formats;
+  gint i, nformats = 0;
+  gboolean res = FALSE;
+
+  formats = _audio_stream_get_formats (stream_id, &nformats);
+  GST_DEBUG ("found %d stream formats", nformats);
+
+  if (formats) {
+    GST_DEBUG ("formats supported on stream ID: %u", (unsigned) stream_id);
+
+    for (i = 0; i < nformats; i++) {
+      GST_DEBUG ("  " CORE_AUDIO_FORMAT,
+          CORE_AUDIO_FORMAT_ARGS (formats[i].mFormat));
+
+      if (CORE_AUDIO_FORMAT_IS_SPDIF (formats[i])) {
+        res = TRUE;
+      }
+    }
+    g_free (formats);
+  }
+
+  return res;
+}
+
+static OSStatus
+_audio_stream_format_listener (AudioObjectID inObjectID,
+    UInt32 inNumberAddresses,
+    const AudioObjectPropertyAddress inAddresses[], void *inClientData)
+{
+  OSStatus status = noErr;
+  guint i;
+  PropertyMutex *prop_mutex = inClientData;
+
+  for (i = 0; i < inNumberAddresses; i++) {
+    if (inAddresses[i].mSelector == kAudioStreamPropertyPhysicalFormat) {
+      g_mutex_lock (&prop_mutex->lock);
+      g_cond_signal (&prop_mutex->cond);
+      g_mutex_unlock (&prop_mutex->lock);
+      break;
+    }
+  }
+  return (status);
+}
+
+static gboolean
+_audio_stream_change_format (AudioStreamID stream_id,
+    AudioStreamBasicDescription format)
+{
+  OSStatus status = noErr;
+  gint i;
+  gboolean ret = FALSE;
+  AudioStreamBasicDescription cformat;
+  PropertyMutex prop_mutex;
+
+  AudioObjectPropertyAddress formatAddress = {
+    kAudioStreamPropertyPhysicalFormat,
+    kAudioObjectPropertyScopeGlobal,
+    kAudioObjectPropertyElementMaster
+  };
+
+  GST_DEBUG ("setting stream format: " CORE_AUDIO_FORMAT,
+      CORE_AUDIO_FORMAT_ARGS (format));
+
+  /* Condition because SetProperty is asynchronous */
+  g_mutex_init (&prop_mutex.lock);
+  g_cond_init (&prop_mutex.cond);
+
+  g_mutex_lock (&prop_mutex.lock);
+
+  /* Install the property listener to serialize the operations */
+  status = AudioObjectAddPropertyListener (stream_id, &formatAddress,
+      _audio_stream_format_listener, (void *) &prop_mutex);
+  if (status != noErr) {
+    GST_ERROR ("AudioObjectAddPropertyListener failed: %d", (int) status);
+    goto done;
+  }
+
+  /* Change the format */
+  if (!_audio_stream_set_current_format (stream_id, format)) {
+    goto done;
+  }
+
+  /* The AudioObjectSetProperty is not only asynchronous
+   * it is also not atomic in its behaviour.
+   * Therefore we check 4 times before we really give up. */
+  for (i = 0; i < 4; i++) {
+    GTimeVal timeout;
+
+    g_get_current_time (&timeout);
+    g_time_val_add (&timeout, 250000);
+
+    if (!g_cond_wait_until (&prop_mutex.cond, &prop_mutex.lock, timeout.tv_sec)) {
+      GST_LOG ("timeout...");
+    }
+
+    if (_audio_stream_get_current_format (stream_id, &cformat)) {
+      GST_DEBUG ("current stream format: " CORE_AUDIO_FORMAT,
+          CORE_AUDIO_FORMAT_ARGS (cformat));
+
+      if (cformat.mSampleRate == format.mSampleRate &&
+          cformat.mFormatID == format.mFormatID &&
+          cformat.mFramesPerPacket == format.mFramesPerPacket) {
+        /* The right format is now active */
+        break;
+      }
+    }
+  }
+
+  if (cformat.mSampleRate != format.mSampleRate ||
+      cformat.mFormatID != format.mFormatID ||
+      cformat.mFramesPerPacket != format.mFramesPerPacket) {
+    goto done;
+  }
+
+  ret = TRUE;
+
+done:
+  /* Removing the property listener */
+  status = AudioObjectRemovePropertyListener (stream_id,
+      &formatAddress, _audio_stream_format_listener, (void *) &prop_mutex);
+  if (status != noErr) {
+    GST_ERROR ("AudioObjectRemovePropertyListener failed: %d", (int) status);
+  }
+  /* Destroy the lock and condition */
+  g_mutex_unlock (&prop_mutex.lock);
+  g_mutex_clear (&prop_mutex.lock);
+  g_cond_clear (&prop_mutex.cond);
+
+  return ret;
+}
+
+static OSStatus
+_audio_stream_hardware_changed_listener (AudioObjectID inObjectID,
+    UInt32 inNumberAddresses,
+    const AudioObjectPropertyAddress inAddresses[], void *inClientData)
+{
+  OSStatus status = noErr;
+  guint i;
+  GstCoreAudio *core_audio = inClientData;
+
+  for (i = 0; i < inNumberAddresses; i++) {
+    if (inAddresses[i].mSelector == kAudioDevicePropertyDeviceHasChanged) {
+      if (!gst_core_audio_audio_device_is_spdif_avail (core_audio->device_id)) {
+        GstOsxAudioSink *sink =
+            GST_OSX_AUDIO_SINK (GST_OBJECT_PARENT (core_audio->osxbuf));
+        GST_ELEMENT_ERROR (sink, RESOURCE, FAILED,
+            ("SPDIF output no longer available"),
+            ("Audio device is reporting that SPDIF output isn't available"));
+      }
+      break;
+    }
+  }
+  return (status);
+}
+
+static inline gboolean
+_monitorize_spdif (GstCoreAudio * core_audio)
+{
+  OSStatus status = noErr;
+  gboolean ret = TRUE;
+
+  AudioObjectPropertyAddress propAddress = {
+    kAudioDevicePropertyDeviceHasChanged,
+    kAudioObjectPropertyScopeGlobal,
+    kAudioObjectPropertyElementMaster
+  };
+
+  /* Install the property listener */
+  status = AudioObjectAddPropertyListener (core_audio->device_id,
+      &propAddress, _audio_stream_hardware_changed_listener,
+      (void *) core_audio);
+  if (status != noErr) {
+    GST_ERROR_OBJECT (core_audio->osxbuf,
+        "AudioObjectAddPropertyListener failed: %d", (int) status);
+    ret = FALSE;
+  }
+
+  return ret;
+}
+
+static inline gboolean
+_unmonitorize_spdif (GstCoreAudio * core_audio)
+{
+  OSStatus status = noErr;
+  gboolean ret = TRUE;
+
+  AudioObjectPropertyAddress propAddress = {
+    kAudioDevicePropertyDeviceHasChanged,
+    kAudioObjectPropertyScopeGlobal,
+    kAudioObjectPropertyElementMaster
+  };
+
+  /* Remove the property listener */
+  status = AudioObjectRemovePropertyListener (core_audio->device_id,
+      &propAddress, _audio_stream_hardware_changed_listener,
+      (void *) core_audio);
+  if (status != noErr) {
+    GST_ERROR_OBJECT (core_audio->osxbuf,
+        "AudioObjectRemovePropertyListener failed: %d", (int) status);
+    ret = FALSE;
+  }
+
+  return ret;
+}
+
+static inline gboolean
+_open_spdif (GstCoreAudio * core_audio)
+{
+  gboolean res = FALSE;
+  pid_t hog_pid, own_pid = getpid ();
+
+  /* We need the device in exclusive and disable the mixing */
+  hog_pid = _audio_device_get_hog (core_audio->device_id);
+
+  if (hog_pid != -1 && hog_pid != own_pid) {
+    GST_DEBUG_OBJECT (core_audio,
+        "device is currently in use by another application");
+    goto done;
+  }
+
+  if (_audio_device_set_hog (core_audio->device_id, own_pid)) {
+    core_audio->hog_pid = own_pid;
+  }
+
+  if (_audio_device_set_mixing (core_audio->device_id, FALSE)) {
+    GST_DEBUG_OBJECT (core_audio, "disabled mixing on the device");
+    core_audio->disabled_mixing = TRUE;
+  }
+
+  res = TRUE;
+done:
+  return res;
+}
+
+static inline gboolean
+_close_spdif (GstCoreAudio * core_audio)
+{
+  pid_t hog_pid;
+
+  _unmonitorize_spdif (core_audio);
+
+  if (core_audio->revert_format) {
+    if (!_audio_stream_change_format (core_audio->stream_id,
+            core_audio->original_format)) {
+      GST_WARNING_OBJECT (core_audio->osxbuf, "Format revert failed");
+    }
+    core_audio->revert_format = FALSE;
+  }
+
+  if (core_audio->disabled_mixing) {
+    _audio_device_set_mixing (core_audio->device_id, TRUE);
+    core_audio->disabled_mixing = FALSE;
+  }
+
+  if (core_audio->hog_pid != -1) {
+    hog_pid = _audio_device_get_hog (core_audio->device_id);
+    if (hog_pid == getpid ()) {
+      if (_audio_device_set_hog (core_audio->device_id, -1)) {
+        core_audio->hog_pid = -1;
+      }
+    }
+  }
+
+  return TRUE;
+}
+
+static OSStatus
+_io_proc_spdif (AudioDeviceID inDevice,
+    const AudioTimeStamp * inNow,
+    const void *inInputData,
+    const AudioTimeStamp * inTimestamp,
+    AudioBufferList * bufferList,
+    const AudioTimeStamp * inOutputTime, GstCoreAudio * core_audio)
+{
+  OSStatus status;
+
+  status = core_audio->element->io_proc (core_audio->osxbuf, NULL, inTimestamp,
+      0, 0, bufferList);
+
+  return status;
+}
+
+static inline gboolean
+_acquire_spdif (GstCoreAudio * core_audio, AudioStreamBasicDescription format)
+{
+  AudioStreamID *streams = NULL;
+  gint i, j, nstreams = 0;
+  gboolean ret = FALSE;
+
+  if (!_open_spdif (core_audio))
+    goto done;
+
+  streams = _audio_device_get_streams (core_audio->device_id, &nstreams);
+
+  for (i = 0; i < nstreams; i++) {
+    AudioStreamRangedDescription *formats = NULL;
+    gint nformats = 0;
+
+    formats = _audio_stream_get_formats (streams[i], &nformats);
+
+    if (formats) {
+      gboolean is_spdif = FALSE;
+
+      /* Check if one of the supported formats is a digital format */
+      for (j = 0; j < nformats; j++) {
+        if (CORE_AUDIO_FORMAT_IS_SPDIF (formats[j])) {
+          is_spdif = TRUE;
+          break;
+        }
+      }
+
+      if (is_spdif) {
+        /* if this stream supports a digital (cac3) format,
+         * then go set it. */
+        gint requested_rate_format = -1;
+        gint current_rate_format = -1;
+        gint backup_rate_format = -1;
+
+        core_audio->stream_id = streams[i];
+        core_audio->stream_idx = i;
+
+        if (!core_audio->revert_format) {
+          if (!_audio_stream_get_current_format (core_audio->stream_id,
+                  &core_audio->original_format)) {
+            GST_WARNING_OBJECT (core_audio->osxbuf,
+                "format could not be saved");
+            g_free (formats);
+            continue;
+          }
+          core_audio->revert_format = TRUE;
+        }
+
+        for (j = 0; j < nformats; j++) {
+          if (CORE_AUDIO_FORMAT_IS_SPDIF (formats[j])) {
+            GST_LOG_OBJECT (core_audio->osxbuf,
+                "found stream format: " CORE_AUDIO_FORMAT,
+                CORE_AUDIO_FORMAT_ARGS (formats[j].mFormat));
+
+            if (formats[j].mFormat.mSampleRate == format.mSampleRate) {
+              requested_rate_format = j;
+              break;
+            } else if (formats[j].mFormat.mSampleRate ==
+                core_audio->original_format.mSampleRate) {
+              current_rate_format = j;
+            } else {
+              if (backup_rate_format < 0 ||
+                  formats[j].mFormat.mSampleRate >
+                  formats[backup_rate_format].mFormat.mSampleRate) {
+                backup_rate_format = j;
+              }
+            }
+          }
+        }
+
+        if (requested_rate_format >= 0) {
+          /* We prefer to output at the rate of the original audio */
+          core_audio->stream_format = formats[requested_rate_format].mFormat;
+        } else if (current_rate_format >= 0) {
+          /* If not possible, we will try to use the current rate */
+          core_audio->stream_format = formats[current_rate_format].mFormat;
+        } else {
+          /* And if we have to, any digital format will be just
+           * fine (highest rate possible) */
+          core_audio->stream_format = formats[backup_rate_format].mFormat;
+        }
+      }
+      g_free (formats);
+    }
+  }
+  g_free (streams);
+
+  GST_DEBUG_OBJECT (core_audio,
+      "original stream format: " CORE_AUDIO_FORMAT,
+      CORE_AUDIO_FORMAT_ARGS (core_audio->original_format));
+
+  if (!_audio_stream_change_format (core_audio->stream_id,
+          core_audio->stream_format))
+    goto done;
+
+  ret = TRUE;
+
+done:
+  return ret;
+}
+
+static inline void
+_remove_render_spdif_callback (GstCoreAudio * core_audio)
+{
+  OSStatus status;
+
+  /* Deactivate the render callback by calling
+   * AudioDeviceDestroyIOProcID */
+  status =
+      AudioDeviceDestroyIOProcID (core_audio->device_id, core_audio->procID);
+  if (status != noErr) {
+    GST_ERROR_OBJECT (core_audio->osxbuf,
+        "AudioDeviceDestroyIOProcID failed: %d", (int) status);
+  }
+
+  GST_DEBUG_OBJECT (core_audio,
+      "osx ring buffer removed ioproc ID: %p device_id %lu",
+      core_audio->procID, (gulong) core_audio->device_id);
+
+  /* We're deactivated.. */
+  core_audio->procID = 0;
+  core_audio->io_proc_needs_deactivation = FALSE;
+  core_audio->io_proc_active = FALSE;
+}
+
+static inline gboolean
+_io_proc_spdif_start (GstCoreAudio * core_audio)
+{
+  OSErr status;
+
+  GST_DEBUG_OBJECT (core_audio,
+      "osx ring buffer start ioproc ID: %p device_id %lu",
+      core_audio->procID, (gulong) core_audio->device_id);
+
+  if (!core_audio->io_proc_active) {
+    /* Add IOProc callback */
+    status = AudioDeviceCreateIOProcID (core_audio->device_id,
+        (AudioDeviceIOProc) _io_proc_spdif,
+        (void *) core_audio, &core_audio->procID);
+    if (status != noErr) {
+      GST_ERROR_OBJECT (core_audio->osxbuf,
+          ":AudioDeviceCreateIOProcID failed: %d", (int) status);
+      return FALSE;
+    }
+    core_audio->io_proc_active = TRUE;
+  }
+
+  core_audio->io_proc_needs_deactivation = FALSE;
+
+  /* Start device */
+  status = AudioDeviceStart (core_audio->device_id, core_audio->procID);
+  if (status != noErr) {
+    GST_ERROR_OBJECT (core_audio->osxbuf,
+        "AudioDeviceStart failed: %d", (int) status);
+    return FALSE;
+  }
+  return TRUE;
+}
+
+static inline gboolean
+_io_proc_spdif_stop (GstCoreAudio * core_audio)
+{
+  OSErr status;
+
+  /* Stop device */
+  status = AudioDeviceStop (core_audio->device_id, core_audio->procID);
+  if (status != noErr) {
+    GST_ERROR_OBJECT (core_audio->osxbuf,
+        "AudioDeviceStop failed: %d", (int) status);
+  }
+
+  GST_DEBUG_OBJECT (core_audio,
+      "osx ring buffer stop ioproc ID: %p device_id %lu",
+      core_audio->procID, (gulong) core_audio->device_id);
+
+  if (core_audio->io_proc_active) {
+    _remove_render_spdif_callback (core_audio);
+  }
+
+  _close_spdif (core_audio);
+
+  return TRUE;
+}
+
+
+/***********************
+ *   Implementation    *
+ **********************/
+
+static gboolean
+gst_core_audio_open_impl (GstCoreAudio * core_audio)
+{
+  gboolean ret;
+
+  /* The following is needed to instruct HAL to create their own
+   * thread to handle the notifications. */
+  _audio_system_set_runloop (NULL);
+
+  /* Create a HALOutput AudioUnit.
+   * This is the lowest-level output API that is actually sensibly
+   * usable (the lower level ones require that you do
+   * channel-remapping yourself, and the CoreAudio channel mapping
+   * is sufficiently complex that doing so would be very difficult)
+   *
+   * Note that for input we request an output unit even though
+   * we will do input with it.
+   * http://developer.apple.com/technotes/tn2002/tn2091.html
+   */
+  ret = gst_core_audio_open_device (core_audio, kAudioUnitSubType_HALOutput,
+      "HALOutput");
+  if (!ret) {
+    GST_DEBUG ("Could not open device");
+    goto done;
+  }
+
+  ret = gst_core_audio_bind_device (core_audio);
+  if (!ret) {
+    GST_DEBUG ("Could not bind device");
+    goto done;
+  }
+
+done:
+  return ret;
+}
+
+static gboolean
+gst_core_audio_start_processing_impl (GstCoreAudio * core_audio)
+{
+  if (core_audio->is_passthrough) {
+    return _io_proc_spdif_start (core_audio);
+  } else {
+    return gst_core_audio_io_proc_start (core_audio);
+  }
+}
+
+static gboolean
+gst_core_audio_pause_processing_impl (GstCoreAudio * core_audio)
+{
+  if (core_audio->is_passthrough) {
+    GST_DEBUG_OBJECT (core_audio,
+        "osx ring buffer pause ioproc ID: %p device_id %lu",
+        core_audio->procID, (gulong) core_audio->device_id);
+
+    if (core_audio->io_proc_active) {
+      _remove_render_spdif_callback (core_audio);
+    }
+  } else {
+    GST_DEBUG_OBJECT (core_audio,
+        "osx ring buffer pause ioproc: %p device_id %lu",
+        core_audio->element->io_proc, (gulong) core_audio->device_id);
+    if (core_audio->io_proc_active) {
+      /* CoreAudio isn't threadsafe enough to do this here;
+       * we must deactivate the render callback elsewhere. See:
+       * http://lists.apple.com/archives/Coreaudio-api/2006/Mar/msg00010.html
+       */
+      core_audio->io_proc_needs_deactivation = TRUE;
+    }
+  }
+  return TRUE;
+}
+
+static gboolean
+gst_core_audio_stop_processing_impl (GstCoreAudio * core_audio)
+{
+  if (core_audio->is_passthrough) {
+    _io_proc_spdif_stop (core_audio);
+  } else {
+    gst_core_audio_io_proc_stop (core_audio);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_core_audio_get_samples_and_latency_impl (GstCoreAudio * core_audio,
+    gdouble rate, guint * samples, gdouble * latency)
+{
+  OSStatus status;
+  UInt32 size = sizeof (double);
+
+  if (core_audio->is_passthrough) {
+    *samples = _audio_device_get_latency (core_audio->device_id);
+    *samples += _audio_stream_get_latency (core_audio->stream_id);
+    *latency = (double) *samples / rate;
+  } else {
+    status = AudioUnitGetProperty (core_audio->audiounit, kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0,        /* N/A for global */
+        latency, &size);
+
+    if (status) {
+      GST_WARNING_OBJECT (core_audio->osxbuf, "Failed to get latency: %d",
+          (int) status);
+      *samples = 0;
+      return FALSE;
+    }
+
+    *samples = *latency * rate;
+  }
+  return TRUE;
+}
+
+static gboolean
+gst_core_audio_initialize_impl (GstCoreAudio * core_audio,
+    AudioStreamBasicDescription format, GstCaps * caps,
+    gboolean is_passthrough, guint32 * frame_size)
+{
+  gboolean ret = FALSE;
+  OSStatus status;
+
+  /* Uninitialize the AudioUnit before changing formats */
+  status = AudioUnitUninitialize (core_audio->audiounit);
+  if (status) {
+    GST_ERROR_OBJECT (core_audio, "Failed to uninitialize AudioUnit: %d",
+        (int) status);
+    return FALSE;
+  }
+
+  core_audio->is_passthrough = is_passthrough;
+  if (is_passthrough) {
+    if (!_acquire_spdif (core_audio, format))
+      goto done;
+    _monitorize_spdif (core_audio);
+  } else {
+    OSStatus status;
+    UInt32 propertySize;
+
+    core_audio->stream_idx = 0;
+    if (!gst_core_audio_set_format (core_audio, format))
+      goto done;
+
+    if (!gst_core_audio_set_channel_layout (core_audio,
+            format.mChannelsPerFrame, caps))
+      goto done;
+
+    if (core_audio->is_src) {
+      propertySize = sizeof (*frame_size);
+      status = AudioUnitGetProperty (core_audio->audiounit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0,     /* N/A for global */
+          frame_size, &propertySize);
+
+      if (status) {
+        GST_WARNING_OBJECT (core_audio->osxbuf, "Failed to get frame size: %d",
+            (int) status);
+        goto done;
+      }
+    }
+  }
+
+  ret = TRUE;
+
+done:
+  /* Format changed, initialise the AudioUnit again */
+  status = AudioUnitInitialize (core_audio->audiounit);
+  if (status) {
+    GST_ERROR_OBJECT (core_audio, "Failed to initialize AudioUnit: %d",
+        (int) status);
+    ret = FALSE;
+  }
+
+  if (ret) {
+    GST_DEBUG_OBJECT (core_audio, "osxbuf ring buffer acquired");
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_core_audio_select_device_impl (GstCoreAudio * core_audio)
+{
+  AudioDeviceID *devices = NULL;
+  AudioDeviceID device_id = core_audio->device_id;
+  AudioDeviceID default_device_id = 0;
+  gint i, ndevices = 0;
+  gboolean output = !core_audio->is_src;
+  gboolean res = FALSE;
+#ifdef GST_CORE_AUDIO_DEBUG
+  AudioChannelLayout *channel_layout;
+#endif
+
+  devices = _audio_system_get_devices (&ndevices);
+
+  if (ndevices < 1) {
+    GST_ERROR ("no audio output devices found");
+    goto done;
+  }
+
+  GST_DEBUG ("found %d audio device(s)", ndevices);
+
+#ifdef GST_CORE_AUDIO_DEBUG
+  for (i = 0; i < ndevices; i++) {
+    gchar *device_name;
+
+    if ((device_name = _audio_device_get_name (devices[i], output))) {
+      if (!_audio_device_has_output (devices[i])) {
+        GST_DEBUG ("Input Device ID: %u Name: %s",
+            (unsigned) devices[i], device_name);
+      } else {
+        GST_DEBUG ("Output Device ID: %u Name: %s",
+            (unsigned) devices[i], device_name);
+
+        channel_layout =
+            gst_core_audio_audio_device_get_channel_layout (devices[i], output);
+        if (channel_layout) {
+          gst_core_audio_dump_channel_layout (channel_layout);
+          g_free (channel_layout);
+        }
+      }
+
+      g_free (device_name);
+    }
+  }
+#endif
+
+  /* Find the ID of the default output device */
+  default_device_id = _audio_system_get_default_device (output);
+
+  /* Here we decide if selected device is valid or autoselect
+   * the default one when required */
+  if (device_id == kAudioDeviceUnknown) {
+    if (default_device_id != kAudioDeviceUnknown) {
+      device_id = default_device_id;
+      res = TRUE;
+    } else {
+      GST_ERROR ("No device of required type available");
+      res = FALSE;
+    }
+  } else {
+    for (i = 0; i < ndevices; i++) {
+      if (device_id == devices[i]) {
+        res = TRUE;
+        break;
+      }
+    }
+
+    if (res && !_audio_device_is_alive (device_id, output)) {
+      GST_ERROR ("Requested device not usable");
+      res = FALSE;
+      goto done;
+    }
+  }
+
+  if (res)
+    core_audio->device_id = device_id;
+
+done:
+  g_free (devices);
+  return res;
+}
+
+static gboolean
+gst_core_audio_audio_device_is_spdif_avail_impl (AudioDeviceID device_id)
+{
+  AudioStreamID *streams = NULL;
+  gint i, nstreams = 0;
+  gboolean res = FALSE;
+
+  streams = _audio_device_get_streams (device_id, &nstreams);
+  GST_DEBUG ("found %d streams", nstreams);
+  if (streams) {
+    for (i = 0; i < nstreams; i++) {
+      if (_audio_stream_is_spdif_avail (streams[i])) {
+        res = TRUE;
+      }
+    }
+
+    g_free (streams);
+  }
+
+  return res;
+}
diff --git a/sys/osxaudio/gstosxcoreaudioremoteio.c b/sys/osxaudio/gstosxcoreaudioremoteio.c
new file mode 100644
index 0000000..76b0eba
--- /dev/null
+++ b/sys/osxaudio/gstosxcoreaudioremoteio.c
@@ -0,0 +1,137 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012 Fluendo S.A. <support@fluendo.com>
+ *   Authors: Andoni Morales Alastruey <amorales@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#import <AudioUnit/AUComponent.h>
+
+static gboolean
+gst_core_audio_open_impl (GstCoreAudio * core_audio)
+{
+  return gst_core_audio_open_device (core_audio, kAudioUnitSubType_RemoteIO,
+      "RemoteIO");
+}
+
+static gboolean
+gst_core_audio_start_processing_impl (GstCoreAudio * core_audio)
+{
+  return gst_core_audio_io_proc_start (core_audio);
+}
+
+static gboolean
+gst_core_audio_pause_processing_impl (GstCoreAudio * core_audio)
+{
+  GST_DEBUG_OBJECT (core_audio,
+      "osx ring buffer pause ioproc: %p device_id %lu",
+      core_audio->element->io_proc, (gulong) core_audio->device_id);
+
+  if (core_audio->io_proc_active) {
+    /* CoreAudio isn't threadsafe enough to do this here;
+     * we must deactivate the render callback elsewhere. See:
+     * http://lists.apple.com/archives/Coreaudio-api/2006/Mar/msg00010.html
+     */
+    core_audio->io_proc_needs_deactivation = TRUE;
+  }
+  return TRUE;
+}
+
+static gboolean
+gst_core_audio_stop_processing_impl (GstCoreAudio * core_audio)
+{
+  gst_core_audio_io_proc_stop (core_audio);
+  return TRUE;
+}
+
+static gboolean
+gst_core_audio_get_samples_and_latency_impl (GstCoreAudio * core_audio,
+    gdouble rate, guint * samples, gdouble * latency)
+{
+  OSStatus status;
+  UInt32 size = sizeof (double);
+
+  status = AudioUnitGetProperty (core_audio->audiounit, kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0,  /* N/A for global */
+      latency, &size);
+
+  if (status) {
+    GST_WARNING_OBJECT (core_audio, "Failed to get latency: %d", (int) status);
+    *samples = 0;
+    return FALSE;
+  }
+
+  *samples = *latency * rate;
+  return TRUE;
+}
+
+static gboolean
+gst_core_audio_initialize_impl (GstCoreAudio * core_audio,
+    AudioStreamBasicDescription format, GstCaps * caps,
+    gboolean is_passthrough, guint32 * frame_size)
+{
+  gboolean ret = FALSE;
+  OSStatus status;
+
+  /* Uninitialize the AudioUnit before changing formats */
+  status = AudioUnitUninitialize (core_audio->audiounit);
+  if (status) {
+    GST_ERROR_OBJECT (core_audio, "Failed to uninitialize AudioUnit: %d",
+        (int) status);
+    return FALSE;
+  }
+
+  core_audio->is_passthrough = is_passthrough;
+  core_audio->stream_idx = 0;
+
+  if (!gst_core_audio_set_format (core_audio, format))
+    goto done;
+
+  /* FIXME: Use kAudioSessionProperty_CurrentHardwareSampleRate and
+   * kAudioSessionProperty_CurrentHardwareIOBufferDuration with property
+   * listeners to detect changes in screen locks.
+   * For now use the maximum value */
+  *frame_size = 4196;
+
+  GST_DEBUG_OBJECT (core_audio, "osxbuf ring buffer acquired");
+  ret = TRUE;
+
+done:
+  /* Format changed, initialise the AudioUnit again */
+  status = AudioUnitInitialize (core_audio->audiounit);
+  if (status) {
+    GST_ERROR_OBJECT (core_audio, "Failed to initialize AudioUnit: %d",
+        (int) status);
+    ret = FALSE;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_core_audio_select_device_impl (GstCoreAudio * core_audio)
+{
+  /* No device selection in iOS */
+  return TRUE;
+}
+
+static gboolean
+gst_core_audio_audio_device_is_spdif_avail_impl (AudioDeviceID device_id)
+{
+  /* No SPDIF in iOS */
+  return FALSE;
+}
diff --git a/sys/osxvideo/Makefile.am b/sys/osxvideo/Makefile.am
new file mode 100644
index 0000000..a9a3d76
--- /dev/null
+++ b/sys/osxvideo/Makefile.am
@@ -0,0 +1,17 @@
+
+plugin_LTLIBRARIES = libgstosxvideo.la
+
+libgstosxvideo_la_SOURCES = osxvideosink.m cocoawindow.m 
+libgstosxvideo_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
+	$(GST_PLUGINS_BASE_CFLAGS)
+libgstosxvideo_la_OBJCFLAGS = $(GST_OBJCFLAGS) $(GST_BASE_CFLAGS) \
+	$(GST_PLUGINS_BASE_CFLAGS)
+libgstosxvideo_la_LIBADD =  \
+	$(GST_LIBS) \
+	$(GST_BASE_LIBS) \
+	$(GST_PLUGINS_BASE_LIBS) \
+	-lgstvideo-$(GST_API_VERSION)
+
+libgstosxvideo_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -Wl,-framework -Wl,Cocoa -Wl,-framework -Wl,OpenGL
+
+noinst_HEADERS = osxvideosink.h cocoawindow.h
diff --git a/sys/osxvideo/cocoawindow.h b/sys/osxvideo/cocoawindow.h
new file mode 100644
index 0000000..816f1bb
--- /dev/null
+++ b/sys/osxvideo/cocoawindow.h
@@ -0,0 +1,86 @@
+/* GStreamer
+ * Copyright (C) 2004 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * The development of this code was made possible due to the involvement of Pioneers 
+ * of the Inevitable, the creators of the Songbird Music player
+ * 
+ */
+
+/* inspiration gained from looking at source of osx video out of xine and vlc 
+ * and is reflected in the code
+ */
+
+#import <Cocoa/Cocoa.h>
+#import <glib.h>
+#import <gst/video/navigation.h>
+
+struct _GstOSXImage;
+
+@interface GstGLView : NSOpenGLView
+{
+    int i_effect;
+    unsigned int pi_texture;
+    float f_x;
+    float f_y;
+    int initDone;
+    char* data;
+    int width, height;
+    BOOL fullscreen;
+    BOOL keepAspectRatio;
+    NSOpenGLContext* fullScreenContext; 
+    NSOpenGLContext* actualContext;
+    NSTrackingArea *trackingArea;
+    GstNavigation *navigation;
+    NSRect drawingBounds;
+    NSThread *mainThread;
+    NSUInteger savedModifierFlags;
+}
+- (void) drawQuad;
+- (void) drawRect: (NSRect) rect;
+- (id) initWithFrame: (NSRect) frame;
+- (void) initTextures;
+- (void) reloadTexture;
+- (void) cleanUp;
+- (void) displayTexture;
+- (char*) getTextureBuffer;
+- (void) setFullScreen: (BOOL) flag;
+- (void) setKeepAspectRatio: (BOOL) flag;
+- (void) reshape;
+- (void) setVideoSize:(int)w : (int)h;
+- (NSRect) getDrawingBounds;
+- (BOOL) haveSuperview;
+- (void) haveSuperviewReal: (NSMutableArray *)closure;
+- (void) addToSuperview: (NSView *)superview;
+- (void) removeFromSuperview: (id)unused;
+- (void) setNavigation: (GstNavigation *) nav;
+#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION
+- (void) setMainThread: (NSThread *) thread;
+#endif
+
+@end
+
+@interface GstOSXVideoSinkWindow: NSWindow {
+   int width, height;
+   GstGLView *gstview;
+}
+
+- (void) setContentSize: (NSSize) size;
+- (GstGLView *) gstView;
+- (id)initWithContentNSRect:(NSRect)contentRect styleMask:(unsigned int)styleMask backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag screen:(NSScreen *)aScreen;
+@end
diff --git a/sys/osxvideo/cocoawindow.m b/sys/osxvideo/cocoawindow.m
new file mode 100644
index 0000000..dab0425
--- /dev/null
+++ b/sys/osxvideo/cocoawindow.m
@@ -0,0 +1,836 @@
+/* GStreamer
+ * Copyright (C) 2004 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * The development of this code was made possible due to the involvement of Pioneers
+ * of the Inevitable, the creators of the Songbird Music player
+ *
+ */
+
+/* inspiration gained from looking at source of osx video out of xine and vlc
+ * and is reflected in the code
+ */
+
+
+#include <Cocoa/Cocoa.h>
+#include <gst/gst.h>
+#import "cocoawindow.h"
+#import "osxvideosink.h"
+
+#include <OpenGL/OpenGL.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+
+#include <Carbon/Carbon.h>
+
+/* Debugging category */
+#include <gst/gstinfo.h>
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
+#define NSEventTypeMouseMoved                NSMouseMoved
+#define NSEventTypeLeftMouseDown             NSLeftMouseDown
+#define NSEventTypeLeftMouseUp               NSLeftMouseUp
+#define NSEventTypeRightMouseDown            NSRightMouseDown
+#define NSEventTypeRightMouseUp              NSRightMouseUp
+#endif
+
+static
+const gchar* gst_keycode_to_keyname(gint16 keycode)
+{
+    switch (keycode)
+    {
+      case kVK_ANSI_A:
+        return "a";
+      case kVK_ANSI_S:
+        return "s";
+      case kVK_ANSI_D:
+        return "d";
+      case kVK_ANSI_F:
+        return "f";
+      case kVK_ANSI_H:
+        return "h";
+      case kVK_ANSI_G:
+        return "g";
+      case kVK_ANSI_Z:
+        return "z";
+      case kVK_ANSI_X:
+        return "x";
+      case kVK_ANSI_C:
+        return "c";
+      case kVK_ANSI_V:
+        return "v";
+      case kVK_ANSI_B:
+        return "b";
+      case kVK_ANSI_Q:
+        return "q";
+      case kVK_ANSI_W:
+        return "w";
+      case kVK_ANSI_E:
+        return "e";
+      case kVK_ANSI_R:
+        return "r";
+      case kVK_ANSI_Y:
+        return "y";
+      case kVK_ANSI_T:
+        return "t";
+      case kVK_ANSI_1:
+        return "1";
+      case kVK_ANSI_2:
+        return "2";
+      case kVK_ANSI_3:
+        return "3";
+      case kVK_ANSI_4:
+        return "4";
+      case kVK_ANSI_6:
+        return "6";
+      case kVK_ANSI_5:
+        return "5";
+      case kVK_ANSI_Equal:
+        return "equal";
+      case kVK_ANSI_9:
+        return "9";
+      case kVK_ANSI_7:
+        return "7";
+      case kVK_ANSI_Minus:
+        return "minus";
+      case kVK_ANSI_8:
+        return "8";
+      case kVK_ANSI_0:
+        return "0";
+      case kVK_ANSI_RightBracket:
+        return "bracketright";
+      case kVK_ANSI_O:
+        return "0";
+      case kVK_ANSI_U:
+        return "u";
+      case kVK_ANSI_LeftBracket:
+        return "bracketleft";
+      case kVK_ANSI_I:
+        return "i";
+      case kVK_ANSI_P:
+        return "p";
+      case kVK_ANSI_L:
+        return "l";
+      case kVK_ANSI_J:
+        return "j";
+      case kVK_ANSI_Quote:
+        return "apostrophe";
+      case kVK_ANSI_K:
+        return "k";
+      case kVK_ANSI_Semicolon:
+        return "semicolon";
+      case kVK_ANSI_Backslash:
+        return "backslash";
+      case kVK_ANSI_Comma:
+        return "comma";
+      case kVK_ANSI_Slash:
+        return "slash";
+      case kVK_ANSI_N:
+        return "n";
+      case kVK_ANSI_M:
+        return "m";
+      case kVK_ANSI_Period:
+        return "period";
+      case kVK_ANSI_Grave:
+        return "grave";
+      case kVK_ANSI_KeypadDecimal:
+        return "KP_Delete";
+      case kVK_ANSI_KeypadMultiply:
+        return "KP_Multiply";
+      case kVK_ANSI_KeypadPlus:
+        return "KP_Add";
+      case kVK_ANSI_KeypadClear:
+        return "KP_Clear";
+      case kVK_ANSI_KeypadDivide:
+        return "KP_Divide";
+      case kVK_ANSI_KeypadEnter:
+        return "KP_Enter";
+      case kVK_ANSI_KeypadMinus:
+        return "KP_Subtract";
+      case kVK_ANSI_KeypadEquals:
+        return "KP_Equals";
+      case kVK_ANSI_Keypad0:
+        return "KP_Insert";
+      case kVK_ANSI_Keypad1:
+        return "KP_End";
+      case kVK_ANSI_Keypad2:
+        return "KP_Down";
+      case kVK_ANSI_Keypad3:
+        return "KP_Next";
+      case kVK_ANSI_Keypad4:
+        return "KP_Left";
+      case kVK_ANSI_Keypad5:
+        return "KP_Begin";
+      case kVK_ANSI_Keypad6:
+        return "KP_Right";
+      case kVK_ANSI_Keypad7:
+        return "KP_Home";
+      case kVK_ANSI_Keypad8:
+        return "KP_Up";
+      case kVK_ANSI_Keypad9:
+        return "KP_Prior";
+
+    /* keycodes for keys that are independent of keyboard layout*/
+
+      case kVK_Return:
+        return "Return";
+      case kVK_Tab:
+        return "Tab";
+      case kVK_Space:
+        return "space";
+      case kVK_Delete:
+        return "Backspace";
+      case kVK_Escape:
+        return "Escape";
+      case kVK_Command:
+        return "Command";
+      case kVK_Shift:
+        return "Shift_L";
+      case kVK_CapsLock:
+        return "Caps_Lock";
+      case kVK_Option:
+        return "Option_L";
+      case kVK_Control:
+        return "Control_L";
+      case kVK_RightShift:
+        return "Shift_R";
+      case kVK_RightOption:
+        return "Option_R";
+      case kVK_RightControl:
+        return "Control_R";
+      case kVK_Function:
+        return "Function";
+      case kVK_F17:
+        return "F17";
+      case kVK_VolumeUp:
+        return "VolumeUp";
+      case kVK_VolumeDown:
+        return "VolumeDown";
+      case kVK_Mute:
+        return "Mute";
+      case kVK_F18:
+        return "F18";
+      case kVK_F19:
+        return "F19";
+      case kVK_F20:
+        return "F20";
+      case kVK_F5:
+        return "F5";
+      case kVK_F6:
+        return "F6";
+      case kVK_F7:
+        return "F7";
+      case kVK_F3:
+        return "F3";
+      case kVK_F8:
+        return "F8";
+      case kVK_F9:
+        return "F9";
+      case kVK_F11:
+        return "F11";
+      case kVK_F13:
+        return "F13";
+      case kVK_F16:
+        return "F16";
+      case kVK_F14:
+        return "F14";
+      case kVK_F10:
+        return "F10";
+      case kVK_F12:
+        return "F12";
+      case kVK_F15:
+        return "F15";
+      case kVK_Help:
+        return "Help";
+      case kVK_Home:
+        return "Home";
+      case kVK_PageUp:
+        return "Prior";
+      case kVK_ForwardDelete:
+        return "Delete";
+      case kVK_F4:
+        return "F4";
+      case kVK_End:
+        return "End";
+      case kVK_F2:
+        return "F2";
+      case kVK_PageDown:
+        return "Next";
+      case kVK_F1:
+        return "F1";
+      case kVK_LeftArrow:
+        return "Left";
+      case kVK_RightArrow:
+        return "Right";
+      case kVK_DownArrow:
+        return "Down";
+      case kVK_UpArrow:
+        return "Up";
+    default:
+        return "";
+  };
+}
+
+@ implementation GstOSXVideoSinkWindow
+
+/* The object has to be released */
+- (id) initWithContentNSRect: (NSRect) rect
+		 styleMask: (unsigned int) styleMask
+		   backing: (NSBackingStoreType) bufferingType
+		     defer: (BOOL) flag
+		    screen:(NSScreen *) aScreen
+{
+  self = [super initWithContentRect: rect
+		styleMask: styleMask
+		backing: bufferingType
+		defer: flag
+		screen:aScreen];
+
+  GST_DEBUG ("Initializing GstOSXvideoSinkWindow");
+
+  gstview = [[GstGLView alloc] initWithFrame:rect];
+
+  if (gstview)
+    [self setContentView:gstview];
+  [self setTitle:@"GStreamer Video Output"];
+
+  return self;
+}
+
+- (void) setContentSize:(NSSize) size {
+  width = size.width;
+  height = size.height;
+
+  [super setContentSize:size];
+}
+
+- (GstGLView *) gstView {
+  return gstview;
+}
+
+- (void) awakeFromNib {
+  [self setAcceptsMouseMovedEvents:YES];
+}
+
+@end
+
+
+//
+// OpenGL implementation
+//
+
+@ implementation GstGLView
+
+- (id) initWithFrame:(NSRect) frame {
+  NSOpenGLPixelFormat *fmt;
+  NSOpenGLPixelFormatAttribute attribs[] = {
+    NSOpenGLPFANoRecovery,
+    NSOpenGLPFADoubleBuffer,
+    NSOpenGLPFAColorSize, 24,
+    NSOpenGLPFAAlphaSize, 8,
+    NSOpenGLPFADepthSize, 24,
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1090
+    NSOpenGLPFAWindow,
+#endif
+    0
+  };
+
+  fmt = [[NSOpenGLPixelFormat alloc]
+	  initWithAttributes:attribs];
+
+  if (!fmt) {
+    GST_WARNING ("Cannot create NSOpenGLPixelFormat");
+    return nil;
+  }
+
+  self = [super initWithFrame: frame pixelFormat:fmt];
+  [fmt release];
+
+   actualContext = [self openGLContext];
+   [actualContext makeCurrentContext];
+   [actualContext update];
+
+  /* Black background */
+  glClearColor (0.0, 0.0, 0.0, 0.0);
+
+  pi_texture = 0;
+  data = nil;
+  width = frame.size.width;
+  height = frame.size.height;
+  drawingBounds = NSMakeRect(0, 0, width, height);
+
+  GST_LOG ("Width: %d Height: %d", width, height);
+
+  trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
+      options: (NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveInKeyWindow)
+      owner:self
+      userInfo:nil];
+
+  [self addTrackingArea:trackingArea];
+  mainThread = [NSThread mainThread];
+
+  [self initTextures];
+  return self;
+}
+
+- (NSRect) getDrawingBounds {
+  return drawingBounds;
+}
+
+- (void) reshape {
+  NSRect bounds;
+  gdouble frame_par, view_par;
+  gint view_height, view_width, c_height, c_width, c_x, c_y;
+
+
+  GST_LOG ("reshaping");
+
+  if (!initDone) {
+    return;
+  }
+
+  [actualContext makeCurrentContext];
+
+  bounds = [self bounds];
+  view_width = bounds.size.width;
+  view_height = bounds.size.height;
+
+  frame_par = (gdouble) width / height;
+  view_par = (gdouble) view_width / view_height;
+  if (!keepAspectRatio)
+    view_par = frame_par;
+
+  if (frame_par == view_par) {
+    c_height = view_height;
+    c_width = view_width;
+    c_x = 0;
+    c_y = 0;
+  } else if (frame_par < view_par) {
+    c_height = view_height;
+    c_width = c_height * frame_par;
+    c_x = (view_width - c_width) / 2;
+    c_y = 0;
+  } else {
+    c_width = view_width;
+    c_height = c_width / frame_par;
+    c_x = 0;
+    c_y = (view_height - c_height) / 2;
+  }
+
+  drawingBounds = NSMakeRect(c_x, c_y, c_width, c_height);
+  glViewport (c_x, c_y, (GLint) c_width, (GLint) c_height);
+}
+
+- (void) initTextures {
+
+  [actualContext makeCurrentContext];
+
+  /* Free previous texture if any */
+  if (pi_texture) {
+    glDeleteTextures (1, (GLuint *)&pi_texture);
+  }
+
+  if (data) {
+    data = g_realloc (data, width * height * sizeof(short)); // short or 3byte?
+  } else {
+    data = g_malloc0(width * height * sizeof(short));
+  }
+  /* Create textures */
+  glGenTextures (1, (GLuint *)&pi_texture);
+
+  glEnable (GL_TEXTURE_RECTANGLE_EXT);
+  glEnable (GL_UNPACK_CLIENT_STORAGE_APPLE);
+
+  glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+  glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
+
+  glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture);
+
+  /* Use VRAM texturing */
+  glTexParameteri (GL_TEXTURE_RECTANGLE_EXT,
+		   GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE);
+
+  /* Tell the driver not to make a copy of the texture but to use
+     our buffer */
+  glPixelStorei (GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
+
+  /* Linear interpolation */
+  glTexParameteri (GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  glTexParameteri (GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+  /* I have no idea what this exactly does, but it seems to be
+     necessary for scaling */
+  glTexParameteri (GL_TEXTURE_RECTANGLE_EXT,
+		   GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  glTexParameteri (GL_TEXTURE_RECTANGLE_EXT,
+		   GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  // glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); WHY ??
+
+  glTexImage2D (GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA,
+		width, height, 0,
+		GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, data);
+
+
+  initDone = 1;
+}
+
+- (void) reloadTexture {
+  if (!initDone) {
+    return;
+  }
+
+  GST_LOG ("Reloading Texture");
+
+  [actualContext makeCurrentContext];
+
+  glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture);
+  glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
+
+  /* glTexSubImage2D is faster than glTexImage2D
+     http://developer.apple.com/samplecode/Sample_Code/Graphics_3D/
+     TextureRange/MainOpenGLView.m.htm */
+  glTexSubImage2D (GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0,
+		   width, height,
+		   GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, data);    //FIXME
+}
+
+- (void) cleanUp {
+  initDone = 0;
+}
+
+- (void) drawQuad {
+  f_x = 1.0;
+  f_y = 1.0;
+
+  glBegin (GL_QUADS);
+  /* Top left */
+  glTexCoord2f (0.0, 0.0);
+  glVertex2f (-f_x, f_y);
+  /* Bottom left */
+  glTexCoord2f (0.0, (float) height);
+  glVertex2f (-f_x, -f_y);
+  /* Bottom right */
+  glTexCoord2f ((float) width, (float) height);
+  glVertex2f (f_x, -f_y);
+  /* Top right */
+  glTexCoord2f ((float) width, 0.0);
+  glVertex2f (f_x, f_y);
+  glEnd ();
+}
+
+- (void) drawRect:(NSRect) rect {
+  GLint params[] = { 1 };
+
+  [actualContext makeCurrentContext];
+
+  CGLSetParameter (CGLGetCurrentContext (), kCGLCPSwapInterval, params);
+
+  /* Black background */
+  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  if (!initDone) {
+    [actualContext flushBuffer];
+    return;
+  }
+
+  /* Draw */
+  glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture); // FIXME
+  [self drawQuad];
+  /* Draw */
+  [actualContext flushBuffer];
+}
+
+- (void) displayTexture {
+  if ([self lockFocusIfCanDraw]) {
+
+    [self drawRect:[self bounds]];
+    [self reloadTexture];
+
+    [self unlockFocus];
+
+  }
+
+}
+
+- (char *) getTextureBuffer {
+  return data;
+}
+
+- (void) setFullScreen:(BOOL) flag {
+  if (!fullscreen && flag) {
+    // go to full screen
+    /* Create the new pixel format */
+    NSOpenGLPixelFormat *fmt;
+    NSOpenGLPixelFormatAttribute attribs[] = {
+      NSOpenGLPFAAccelerated,
+      NSOpenGLPFANoRecovery,
+      NSOpenGLPFADoubleBuffer,
+      NSOpenGLPFAColorSize, 24,
+      NSOpenGLPFAAlphaSize, 8,
+      NSOpenGLPFADepthSize, 24,
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
+      NSOpenGLPFAFullScreen,
+#endif
+      NSOpenGLPFAScreenMask,
+      CGDisplayIDToOpenGLDisplayMask (kCGDirectMainDisplay),
+      0
+    };
+
+    fmt = [[NSOpenGLPixelFormat alloc]
+	    initWithAttributes:attribs];
+
+    if (!fmt) {
+      GST_WARNING ("Cannot create NSOpenGLPixelFormat");
+      return;
+    }
+
+    /* Create the new OpenGL context */
+    fullScreenContext = [[NSOpenGLContext alloc]
+			  initWithFormat: fmt shareContext:nil];
+    if (!fullScreenContext) {
+      GST_WARNING ("Failed to create new NSOpenGLContext");
+      return;
+    }
+
+    actualContext = fullScreenContext;
+
+    /* Capture display, switch to fullscreen */
+    if (CGCaptureAllDisplays () != CGDisplayNoErr) {
+      GST_WARNING ("CGCaptureAllDisplays() failed");
+      return;
+    }
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
+    [fullScreenContext setFullScreen];
+#endif
+    [fullScreenContext makeCurrentContext];
+
+    fullscreen = YES;
+
+    [self initTextures];
+    [self setNeedsDisplay:YES];
+
+  } else if (fullscreen && !flag) {
+    // fullscreen now and needs to go back to normal
+    initDone = NO;
+
+    actualContext = [self openGLContext];
+
+    [NSOpenGLContext clearCurrentContext];
+    [fullScreenContext clearDrawable];
+    [fullScreenContext release];
+    fullScreenContext = nil;
+
+    CGReleaseAllDisplays ();
+
+    [self reshape];
+    [self initTextures];
+
+    [self setNeedsDisplay:YES];
+
+    fullscreen = NO;
+    initDone = YES;
+  }
+}
+
+- (void) setVideoSize: (int)w : (int)h {
+  GST_LOG ("width:%d, height:%d", w, h);
+
+  width = w;
+  height = h;
+
+  [self initTextures];
+  [self reshape];
+}
+
+- (void) setKeepAspectRatio: (BOOL) flag {
+  keepAspectRatio = flag;
+  [self reshape];
+}
+
+#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION
+- (void) setMainThread: (NSThread *) thread {
+  mainThread = thread;
+}
+#endif
+
+- (void) haveSuperviewReal:(NSMutableArray *)closure {
+	BOOL haveSuperview = [self superview] != nil;
+	[closure addObject:[NSNumber numberWithBool:haveSuperview]];
+}
+
+- (BOOL) haveSuperview {
+	NSMutableArray *closure = [NSMutableArray arrayWithCapacity:1];
+	[self performSelector:@selector(haveSuperviewReal:)
+		onThread:mainThread
+		withObject:(id)closure waitUntilDone:YES];
+
+	return [[closure objectAtIndex:0] boolValue];
+}
+
+- (void) addToSuperviewReal:(NSView *)superview {
+	NSRect bounds;
+	[superview addSubview:self];
+	bounds = [superview bounds];
+	[self setFrame:bounds];
+	[self setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
+}
+
+- (void) addToSuperview: (NSView *)superview {
+	[self performSelector:@selector(addToSuperviewReal:)
+		onThread:mainThread
+		withObject:superview waitUntilDone:YES];
+}
+
+- (void) removeFromSuperview: (id)unused
+{
+	[self removeFromSuperview];
+}
+
+- (void) dealloc {
+  GST_LOG ("dealloc called");
+  if (data) g_free(data);
+
+  if (fullScreenContext) {
+    [NSOpenGLContext clearCurrentContext];
+    [fullScreenContext clearDrawable];
+    [fullScreenContext release];
+    if (actualContext == fullScreenContext) actualContext = nil;
+    fullScreenContext = nil;
+  }
+
+  [super dealloc];
+}
+
+- (void)updateTrackingAreas {
+  [self removeTrackingArea:trackingArea];
+  [trackingArea release];
+  trackingArea = [[NSTrackingArea alloc] initWithRect: [self bounds]
+      options: (NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveInKeyWindow)
+      owner:self userInfo:nil];
+  [self addTrackingArea:trackingArea];
+}
+
+- (BOOL)acceptsFirstResponder {
+    return YES;
+}
+
+- (void) setNavigation:(GstNavigation *)nav
+{
+  navigation = nav;
+}
+
+- (void)sendMouseEvent:(NSEvent *)event : (const char *)event_name
+{
+  NSPoint location;
+  gint button;
+  gdouble x, y;
+
+  if (!navigation)
+    return;
+
+  switch ([event type]) {
+    case NSEventTypeMouseMoved:
+      button = 0;
+      break;
+    case NSEventTypeLeftMouseDown:
+    case NSEventTypeLeftMouseUp:
+      button = 1;
+      break;
+    case NSEventTypeRightMouseDown:
+    case NSEventTypeRightMouseUp:
+      button = 2;
+      break;
+    default:
+      button = 3;
+      break;
+  }
+
+  location = [self convertPoint:[event locationInWindow] fromView:nil];
+
+  x = location.x;
+  y = location.y;
+  /* invert Y */
+
+  y = (1 - ((gdouble) y) / [self bounds].size.height) * [self bounds].size.height;
+
+  gst_navigation_send_mouse_event (navigation, event_name, button, x, y);
+}
+
+- (void)sendKeyEvent:(NSEvent *)event : (const char *)event_name
+{
+  if (!navigation)
+    return;
+
+  gst_navigation_send_key_event(navigation, event_name, gst_keycode_to_keyname([event keyCode]));
+}
+
+- (void)sendModifierKeyEvent:(NSEvent *)event
+{
+  NSUInteger flags = [event modifierFlags];
+  const gchar* event_name = flags > savedModifierFlags ? "key-press" : "key-release";
+  savedModifierFlags = flags;
+  [self sendKeyEvent: event: event_name];
+}
+
+- (void)keyDown:(NSEvent *) event;
+{
+  [self sendKeyEvent: event: "key-press"];
+  [super keyDown: event];
+}
+
+- (void)keyUp:(NSEvent *) event;
+{
+  [self sendKeyEvent: event: "key-release"];
+  [super keyUp: event];
+}
+
+- (void)flagsChanged:(NSEvent *) event;
+{
+  [self sendModifierKeyEvent: event];
+  [super flagsChanged: event];
+}
+
+- (void)mouseDown:(NSEvent *) event;
+{
+  [self sendMouseEvent:event: "mouse-button-press"];
+  [super mouseDown: event];
+}
+
+- (void)mouseUp:(NSEvent *) event;
+{
+  [self sendMouseEvent:event: "mouse-button-release"];
+  [super mouseUp: event];
+}
+
+- (void)mouseMoved:(NSEvent *)event;
+{
+  [self sendMouseEvent:event: "mouse-move"];
+  [super mouseMoved: event];
+}
+
+- (void)mouseEntered:(NSEvent *)event;
+{
+  [super mouseEntered: event];
+}
+
+- (void)mouseExited:(NSEvent *)event;
+{
+  [super mouseExited: event];
+}
+
+@end
diff --git a/sys/osxvideo/osxvideosink.h b/sys/osxvideo/osxvideosink.h
new file mode 100644
index 0000000..d467b0e
--- /dev/null
+++ b/sys/osxvideo/osxvideosink.h
@@ -0,0 +1,141 @@
+/* GStreamer
+ * Copyright (C) 2004-6 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *
+ * The development of this code was made possible due to the involvement of Pioneers 
+ * of the Inevitable, the creators of the Songbird Music player
+ * 
+ */
+ 
+#ifndef __GST_OSX_VIDEO_SINK_H__
+#define __GST_OSX_VIDEO_SINK_H__
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideosink.h>
+
+#include <string.h>
+#include <math.h>
+#include <objc/runtime.h>
+#include <Cocoa/Cocoa.h>
+
+#import "cocoawindow.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gst_debug_osx_video_sink);
+#define GST_CAT_DEFAULT gst_debug_osx_video_sink
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_OSX_VIDEO_SINK \
+  (gst_osx_video_sink_get_type())
+#define GST_OSX_VIDEO_SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_OSX_VIDEO_SINK, GstOSXVideoSink))
+#define GST_OSX_VIDEO_SINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_OSX_VIDEO_SINK, GstOSXVideoSinkClass))
+#define GST_IS_OSX_VIDEO_SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OSX_VIDEO_SINK))
+#define GST_IS_OSX_VIDEO_SINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_OSX_VIDEO_SINK))
+
+typedef struct _GstOSXWindow GstOSXWindow;
+
+typedef struct _GstOSXVideoSink GstOSXVideoSink;
+typedef struct _GstOSXVideoSinkClass GstOSXVideoSinkClass;
+
+#define GST_TYPE_OSXVIDEOBUFFER (gst_osxvideobuffer_get_type())
+
+typedef enum {
+  GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_NOT_RUNNING = 0,
+  GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_RUNNING = 1,
+  GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_UNKNOWN = 2,
+} GstOSXVideoSinkRunLoopState;
+
+/* OSXWindow stuff */
+struct _GstOSXWindow {
+  gint width, height;
+  gboolean closed;
+  gboolean internal;
+  GstGLView* gstview;
+  GstOSXVideoSinkWindow* win;
+};
+
+struct _GstOSXVideoSink {
+  /* Our element stuff */
+  GstVideoSink videosink;
+  GstOSXWindow *osxwindow;
+  void *osxvideosinkobject;
+  NSView *superview;
+  gboolean keep_par;
+  GstVideoInfo info;
+};
+
+struct _GstOSXVideoSinkClass {
+  GstVideoSinkClass parent_class;
+
+  GstOSXVideoSinkRunLoopState run_loop_state;
+  NSThread *ns_app_thread;
+};
+
+GType gst_osx_video_sink_get_type(void);
+
+@interface NSApplication(AppleMenu)
+- (void)setAppleMenu:(NSMenu *)menu;
+@end
+
+@interface GstBufferObject : NSObject
+{
+  @public
+  GstBuffer *buf;
+}
+
+-(id) initWithBuffer: (GstBuffer *) buf;
+@end
+
+
+@interface GstWindowDelegate : NSObject <NSWindowDelegate>
+{
+  @public
+  GstOSXVideoSink *osxvideosink;
+}
+-(id) initWithSink: (GstOSXVideoSink *) sink;
+@end
+
+@interface GstOSXVideoSinkObject : NSObject
+{
+  @public
+  GstOSXVideoSink *osxvideosink;
+}
+
+-(id) initWithSink: (GstOSXVideoSink *) sink;
+-(void) createInternalWindow;
+-(void) resize;
+-(void) destroy;
+-(void) showFrame: (GstBufferObject*) buf;
+-(void) setView: (NSView*) view;
++ (BOOL) isMainThread;
+#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION
+-(void) nsAppThread;
+-(void) checkMainRunLoop;
+#endif
+@end
+
+G_END_DECLS
+
+#endif /* __GST_OSX_VIDEO_SINK_H__ */
+
diff --git a/sys/osxvideo/osxvideosink.m b/sys/osxvideo/osxvideosink.m
new file mode 100644
index 0000000..a140d51
--- /dev/null
+++ b/sys/osxvideo/osxvideosink.m
@@ -0,0 +1,1025 @@
+/* GStreamer
+ * OSX video sink
+ * Copyright (C) 2004-6 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2007,2008,2009 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * The development of this code was made possible due to the involvement of
+ * Pioneers of the Inevitable, the creators of the Songbird Music player.
+ *
+ */
+
+/**
+ * SECTION:element-osxvideosink
+ *
+ * The OSXVideoSink renders video frames to a MacOSX window. The video output
+ * must be directed to a window embedded in an existing NSApp.
+ *
+ */
+
+#include "config.h"
+#include <gst/video/videooverlay.h>
+#include <gst/video/navigation.h>
+#include <gst/video/video.h>
+
+#include "osxvideosink.h"
+#include <unistd.h>
+#import "cocoawindow.h"
+
+GST_DEBUG_CATEGORY (gst_debug_osx_video_sink);
+#define GST_CAT_DEFAULT gst_debug_osx_video_sink
+
+#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION
+#include <pthread.h>
+extern void _CFRunLoopSetCurrent (CFRunLoopRef rl);
+extern pthread_t _CFMainPThread;
+#endif
+
+static GstStaticPadTemplate gst_osx_video_sink_sink_template_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-raw, "
+        "framerate = (fraction) [ 0, MAX ], "
+        "width = (int) [ 1, MAX ], "
+        "height = (int) [ 1, MAX ], "
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+       "format = (string) YUY2")
+#else
+        "format = (string) UYVY")
+#endif
+    );
+
+enum
+{
+  ARG_0,
+  ARG_EMBED,
+  ARG_FORCE_PAR,
+};
+
+static void gst_osx_video_sink_osxwindow_destroy (GstOSXVideoSink * osxvideosink);
+
+#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION
+static GMutex _run_loop_check_mutex;
+static GMutex _run_loop_mutex;
+static GCond _run_loop_cond;
+#endif
+
+static GstOSXVideoSinkClass *sink_class = NULL;
+static GstVideoSinkClass *parent_class = NULL;
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
+#define NSEventMaskAny                       NSAnyEventMask
+#define NSWindowStyleMaskTitled              NSTitledWindowMask
+#define NSWindowStyleMaskClosable            NSClosableWindowMask
+#define NSWindowStyleMaskResizable           NSResizableWindowMask
+#define NSWindowStyleMaskTexturedBackground  NSTexturedBackgroundWindowMask
+#define NSWindowStyleMaskMiniaturizable      NSMiniaturizableWindowMask
+#endif
+
+/* Helper to trigger calls from the main thread */
+static void
+gst_osx_video_sink_call_from_main_thread(GstOSXVideoSink *osxvideosink,
+    NSObject * object, SEL function, NSObject *data, BOOL waitUntilDone)
+{
+
+  NSThread *thread;
+  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+  if (sink_class->ns_app_thread == NULL){
+    thread = [NSThread mainThread];
+  } else {
+    thread = sink_class->ns_app_thread;
+  }
+
+  [object performSelector:function onThread:thread
+          withObject:data waitUntilDone:waitUntilDone];
+  [pool release];
+}
+
+#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION
+/* Poll for cocoa events */
+static void
+run_ns_app_loop (void) {
+  NSEvent *event;
+  NSAutoreleasePool *pool =[[NSAutoreleasePool alloc] init];
+  NSDate *pollTime = nil;
+
+  /* when running the loop in a thread we want to sleep as long as possible */
+  pollTime = [NSDate distantFuture];
+
+  do {
+      event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:pollTime
+          inMode:NSDefaultRunLoopMode dequeue:YES];
+      [NSApp sendEvent:event];
+    }
+  while (event != nil);
+  [pool release];
+}
+
+static void
+gst_osx_videosink_check_main_run_loop (GstOSXVideoSink *sink)
+{
+  /* check if the main run loop is running */
+  gboolean is_running;
+
+  /* the easy way */
+  is_running = [[NSRunLoop mainRunLoop] currentMode] != nil;
+  if (is_running) {
+    goto exit;
+  } else {
+    /* the previous check doesn't always work with main loops that run
+     * cocoa's main run loop manually, like the gdk one, giving false
+     * negatives. This check defers a call to the main thread and waits to
+     * be awaken by this function. */
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+    GstOSXVideoSinkObject * object = (GstOSXVideoSinkObject *) sink->osxvideosinkobject;
+    gint64 abstime;
+
+    g_mutex_lock (&_run_loop_mutex);
+    [object performSelectorOnMainThread:
+          @selector(checkMainRunLoop)
+          withObject:nil waitUntilDone:NO];
+    /* Wait 100 ms */
+    abstime = g_get_monotonic_time () + 100 * 1000;
+    is_running = g_cond_wait_until (&_run_loop_cond,
+        &_run_loop_mutex, abstime);
+    g_mutex_unlock (&_run_loop_mutex);
+
+    [pool release];
+  }
+
+exit:
+  {
+  GST_DEBUG_OBJECT(sink, "The main runloop %s is running",
+      is_running ? "" : " not ");
+  if (is_running) {
+    sink_class->run_loop_state = GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_RUNNING;
+    sink_class->ns_app_thread = [NSThread mainThread];
+  } else {
+    sink_class->run_loop_state = GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_NOT_RUNNING;
+  }
+  }
+}
+
+static void
+gst_osx_video_sink_run_cocoa_loop (GstOSXVideoSink * sink )
+{
+  /* Cocoa applications require a main runloop running to dispatch UI
+   * events and process deferred calls to the main thread through
+   * perfermSelectorOnMainThread.
+   * Since the sink needs to create it's own Cocoa window when no
+   * external NSView is passed to the sink through the GstVideoOverlay API,
+   * we need to run the cocoa mainloop somehow.
+   * This run loop can only be started once, by the first sink needing it
+   */
+
+  g_mutex_lock (&_run_loop_check_mutex);
+
+  if (sink_class->run_loop_state == GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_UNKNOWN) {
+    gst_osx_videosink_check_main_run_loop (sink);
+  }
+
+  if (sink_class->run_loop_state == GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_RUNNING) {
+    g_mutex_unlock (&_run_loop_check_mutex);
+    return;
+  }
+
+  if (sink_class->ns_app_thread == NULL) {
+    /* run the main runloop in a separate thread */
+
+    /* override [NSThread isMainThread] with our own implementation so that we can
+     * make it believe our dedicated thread is the main thread
+     */
+    Method origIsMainThread = class_getClassMethod([NSThread class],
+        NSSelectorFromString(@"isMainThread"));
+    Method ourIsMainThread = class_getClassMethod([GstOSXVideoSinkObject class],
+        NSSelectorFromString(@"isMainThread"));
+
+    method_exchangeImplementations(origIsMainThread, ourIsMainThread);
+
+    sink_class->ns_app_thread = [[NSThread alloc]
+        initWithTarget:sink->osxvideosinkobject
+        selector:@selector(nsAppThread) object:nil];
+    [sink_class->ns_app_thread start];
+
+    g_mutex_lock (&_run_loop_mutex);
+    g_cond_wait (&_run_loop_cond, &_run_loop_mutex);
+    g_mutex_unlock (&_run_loop_mutex);
+  }
+
+  g_mutex_unlock (&_run_loop_check_mutex);
+}
+
+static void
+gst_osx_video_sink_stop_cocoa_loop (GstOSXVideoSink * osxvideosink)
+{
+}
+#endif
+
+/* This function handles osx window creation */
+static gboolean
+gst_osx_video_sink_osxwindow_create (GstOSXVideoSink * osxvideosink, gint width,
+    gint height)
+{
+  NSRect rect;
+  GstOSXWindow *osxwindow = NULL;
+  gboolean res = TRUE;
+  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+  g_return_val_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink), FALSE);
+
+  GST_DEBUG_OBJECT (osxvideosink, "Creating new OSX window");
+
+  osxvideosink->osxwindow = osxwindow = g_new0 (GstOSXWindow, 1);
+
+  osxwindow->width = width;
+  osxwindow->height = height;
+  osxwindow->closed = FALSE;
+  osxwindow->internal = FALSE;
+
+  /* Allocate our GstGLView for the window, and then tell the application
+   * about it (hopefully it's listening...) */
+  rect.origin.x = 0.0;
+  rect.origin.y = 0.0;
+  rect.size.width = (float) osxwindow->width;
+  rect.size.height = (float) osxwindow->height;
+  osxwindow->gstview =[[GstGLView alloc] initWithFrame:rect];
+
+#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION
+  gst_osx_video_sink_run_cocoa_loop (osxvideosink);
+  [osxwindow->gstview setMainThread:sink_class->ns_app_thread];
+#endif
+
+  if (osxvideosink->superview == NULL) {
+    GST_INFO_OBJECT (osxvideosink, "emitting prepare-xwindow-id");
+    gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (osxvideosink));
+  }
+
+  if (osxvideosink->superview != NULL) {
+    /* prepare-xwindow-id was handled, we have the superview in
+     * osxvideosink->superview. We now add osxwindow->gstview to the superview
+     * from the main thread
+     */
+    GST_INFO_OBJECT (osxvideosink, "we have a superview, adding our view to it");
+    gst_osx_video_sink_call_from_main_thread(osxvideosink, osxwindow->gstview,
+        @selector(addToSuperview:), osxvideosink->superview, NO);
+
+  } else {
+    gst_osx_video_sink_call_from_main_thread(osxvideosink,
+      osxvideosink->osxvideosinkobject,
+      @selector(createInternalWindow), nil, YES);
+    GST_INFO_OBJECT (osxvideosink, "No superview, creating an internal window.");
+  }
+  [osxwindow->gstview setNavigation: GST_NAVIGATION(osxvideosink)];
+  [osxvideosink->osxwindow->gstview setKeepAspectRatio: osxvideosink->keep_par];
+
+  [pool release];
+
+  return res;
+}
+
+static void
+gst_osx_video_sink_osxwindow_destroy (GstOSXVideoSink * osxvideosink)
+{
+  NSAutoreleasePool *pool;
+
+  g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink));
+  pool = [[NSAutoreleasePool alloc] init];
+
+  GST_OBJECT_LOCK (osxvideosink);
+  gst_osx_video_sink_call_from_main_thread(osxvideosink,
+      osxvideosink->osxvideosinkobject,
+      @selector(destroy), (id) nil, YES);
+  GST_OBJECT_UNLOCK (osxvideosink);
+#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION
+  gst_osx_video_sink_stop_cocoa_loop (osxvideosink);
+#endif
+  [pool release];
+}
+
+/* This function resizes a GstXWindow */
+static void
+gst_osx_video_sink_osxwindow_resize (GstOSXVideoSink * osxvideosink,
+    GstOSXWindow * osxwindow, guint width, guint height)
+{
+  GstOSXVideoSinkObject *object = osxvideosink->osxvideosinkobject;
+
+  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+  g_return_if_fail (osxwindow != NULL);
+  g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink));
+
+  osxwindow->width = width;
+  osxwindow->height = height;
+
+  GST_DEBUG_OBJECT (osxvideosink, "Resizing window to (%d,%d)", width, height);
+
+  /* Directly resize the underlying view */
+  GST_DEBUG_OBJECT (osxvideosink, "Calling setVideoSize on %p", osxwindow->gstview);
+  gst_osx_video_sink_call_from_main_thread (osxvideosink, object,
+      @selector(resize), (id)nil, YES);
+
+  [pool release];
+}
+
+static gboolean
+gst_osx_video_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
+{
+  GstOSXVideoSink *osxvideosink;
+  GstStructure *structure;
+  gboolean res, result = FALSE;
+  gint video_width, video_height;
+
+  osxvideosink = GST_OSX_VIDEO_SINK (bsink);
+
+  GST_DEBUG_OBJECT (osxvideosink, "caps: %" GST_PTR_FORMAT, caps);
+
+  structure = gst_caps_get_structure (caps, 0);
+  res = gst_structure_get_int (structure, "width", &video_width);
+  res &= gst_structure_get_int (structure, "height", &video_height);
+
+  if (!res) {
+    goto beach;
+  }
+
+  GST_DEBUG_OBJECT (osxvideosink, "our format is: %dx%d video",
+      video_width, video_height);
+
+  GST_VIDEO_SINK_WIDTH (osxvideosink) = video_width;
+  GST_VIDEO_SINK_HEIGHT (osxvideosink) = video_height;
+
+  gst_osx_video_sink_osxwindow_resize (osxvideosink, osxvideosink->osxwindow,
+      video_width, video_height);
+
+  gst_video_info_from_caps (&osxvideosink->info, caps);
+
+  result = TRUE;
+
+beach:
+  return result;
+
+}
+
+static GstStateChangeReturn
+gst_osx_video_sink_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstOSXVideoSink *osxvideosink;
+  GstStateChangeReturn ret;
+
+  osxvideosink = GST_OSX_VIDEO_SINK (element);
+
+  GST_DEBUG_OBJECT (osxvideosink, "%s => %s",
+        gst_element_state_get_name(GST_STATE_TRANSITION_CURRENT (transition)),
+        gst_element_state_get_name(GST_STATE_TRANSITION_NEXT (transition)));
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      /* Creating our window and our image */
+      GST_VIDEO_SINK_WIDTH (osxvideosink) = 320;
+      GST_VIDEO_SINK_HEIGHT (osxvideosink) = 240;
+      if (!gst_osx_video_sink_osxwindow_create (osxvideosink,
+          GST_VIDEO_SINK_WIDTH (osxvideosink),
+          GST_VIDEO_SINK_HEIGHT (osxvideosink))) {
+        ret = GST_STATE_CHANGE_FAILURE;
+        goto done;
+      }
+      break;
+    default:
+      break;
+  }
+
+  ret = (GST_ELEMENT_CLASS (parent_class))->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      GST_VIDEO_SINK_WIDTH (osxvideosink) = 0;
+      GST_VIDEO_SINK_HEIGHT (osxvideosink) = 0;
+      gst_osx_video_sink_osxwindow_destroy (osxvideosink);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+done:
+  return ret;
+}
+
+static GstFlowReturn
+gst_osx_video_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
+{
+  GstOSXVideoSink *osxvideosink;
+  GstBufferObject* bufferobject;
+  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+  osxvideosink = GST_OSX_VIDEO_SINK (bsink);
+
+  GST_DEBUG ("show_frame");
+  bufferobject = [[GstBufferObject alloc] initWithBuffer:buf];
+  gst_osx_video_sink_call_from_main_thread(osxvideosink,
+      osxvideosink->osxvideosinkobject,
+      @selector(showFrame:), bufferobject, NO);
+  [pool release];
+  return GST_FLOW_OK;
+}
+
+/* Buffer management */
+
+
+
+/* =========================================== */
+/*                                             */
+/*              Init & Class init              */
+/*                                             */
+/* =========================================== */
+
+static void
+gst_osx_video_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstOSXVideoSink *osxvideosink;
+
+  g_return_if_fail (GST_IS_OSX_VIDEO_SINK (object));
+
+  osxvideosink = GST_OSX_VIDEO_SINK (object);
+
+  switch (prop_id) {
+    case ARG_EMBED:
+      g_warning ("The \"embed\" property of osxvideosink is deprecated and "
+          "has no effect anymore. Use the GstVideoOverlay "
+          "instead.");
+      break;
+    case ARG_FORCE_PAR:
+      osxvideosink->keep_par = g_value_get_boolean(value);
+      if (osxvideosink->osxwindow)
+        [osxvideosink->osxwindow->gstview
+            setKeepAspectRatio: osxvideosink->keep_par];
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_osx_video_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstOSXVideoSink *osxvideosink;
+
+  g_return_if_fail (GST_IS_OSX_VIDEO_SINK (object));
+
+  osxvideosink = GST_OSX_VIDEO_SINK (object);
+
+  switch (prop_id) {
+    case ARG_EMBED:
+      g_value_set_boolean (value, FALSE);
+      break;
+    case ARG_FORCE_PAR:
+      g_value_set_boolean (value, osxvideosink->keep_par);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_osx_video_sink_propose_allocation (GstBaseSink * base_sink, GstQuery * query)
+{
+    gst_query_add_allocation_meta (query,
+        GST_VIDEO_META_API_TYPE, NULL);
+
+    return TRUE;
+}
+
+static void
+gst_osx_video_sink_init (GstOSXVideoSink * sink)
+{
+  sink->osxwindow = NULL;
+  sink->superview = NULL;
+  sink->osxvideosinkobject = [[GstOSXVideoSinkObject alloc] initWithSink:sink];
+  sink->keep_par = FALSE;
+}
+
+static void
+gst_osx_video_sink_base_init (gpointer g_class)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+  gst_element_class_set_static_metadata (element_class, "OSX Video sink",
+      "Sink/Video", "OSX native videosink",
+      "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
+
+  gst_element_class_add_static_pad_template (element_class, &gst_osx_video_sink_sink_template_factory);
+}
+
+static void
+gst_osx_video_sink_finalize (GObject *object)
+{
+  GstOSXVideoSink *osxvideosink = GST_OSX_VIDEO_SINK (object);
+
+  if (osxvideosink->superview)
+    [osxvideosink->superview release];
+
+  if (osxvideosink->osxvideosinkobject)
+    [(GstOSXVideoSinkObject*)(osxvideosink->osxvideosinkobject) release];
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_osx_video_sink_class_init (GstOSXVideoSinkClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSinkClass *gstbasesink_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesink_class = (GstBaseSinkClass *) klass;
+
+  parent_class = g_type_class_ref (GST_TYPE_VIDEO_SINK);
+  sink_class = klass;
+
+  klass->run_loop_state = GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_UNKNOWN;
+  klass->ns_app_thread = NULL;
+
+  gobject_class->set_property = gst_osx_video_sink_set_property;
+  gobject_class->get_property = gst_osx_video_sink_get_property;
+  gobject_class->finalize = gst_osx_video_sink_finalize;
+
+  gstbasesink_class->set_caps = gst_osx_video_sink_setcaps;
+  gstbasesink_class->preroll = gst_osx_video_sink_show_frame;
+  gstbasesink_class->render = gst_osx_video_sink_show_frame;
+  gstbasesink_class->propose_allocation = gst_osx_video_sink_propose_allocation;
+  gstelement_class->change_state = gst_osx_video_sink_change_state;
+
+  /**
+   * GstOSXVideoSink:embed
+   *
+   * For ABI comatibility onyl, do not use
+   *
+   **/
+
+  g_object_class_install_property (gobject_class, ARG_EMBED,
+      g_param_spec_boolean ("embed", "embed", "For ABI compatiblity only, do not use",
+          FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstOSXVideoSink:force-aspect-ratio
+   *
+   * When enabled, scaling will respect original aspect ratio.
+   *
+   **/
+
+  g_object_class_install_property (gobject_class, ARG_FORCE_PAR,
+      g_param_spec_boolean ("force-aspect-ratio", "force aspect ration",
+          "When enabled, scaling will respect original aspect ration",
+          TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_osx_video_sink_navigation_send_event (GstNavigation * navigation,
+    GstStructure * structure)
+{
+  GstOSXVideoSink *osxvideosink = GST_OSX_VIDEO_SINK (navigation);
+  GstPad *peer;
+  GstEvent *event;
+  GstVideoRectangle src = { 0, };
+  GstVideoRectangle dst = { 0, };
+  GstVideoRectangle result;
+  NSRect bounds;
+  gdouble x, y, xscale = 1.0, yscale = 1.0;
+
+  peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (osxvideosink));
+
+  if (!peer || !osxvideosink->osxwindow)
+    return;
+
+  event = gst_event_new_navigation (structure);
+
+  bounds = [osxvideosink->osxwindow->gstview getDrawingBounds];
+
+  if (osxvideosink->keep_par) {
+    /* We get the frame position using the calculated geometry from _setcaps
+       that respect pixel aspect ratios */
+    src.w = GST_VIDEO_SINK_WIDTH (osxvideosink);
+    src.h = GST_VIDEO_SINK_HEIGHT (osxvideosink);
+    dst.w = bounds.size.width;
+    dst.h = bounds.size.height;
+
+    gst_video_sink_center_rect (src, dst, &result, TRUE);
+    result.x += bounds.origin.x;
+    result.y += bounds.origin.y;
+  } else {
+    result.x = bounds.origin.x;
+    result.y = bounds.origin.y;
+    result.w = bounds.size.width;
+    result.h = bounds.size.height;
+  }
+
+  /* We calculate scaling using the original video frames geometry to include
+     pixel aspect ratio scaling. */
+  xscale = (gdouble) osxvideosink->osxwindow->width / result.w;
+  yscale = (gdouble) osxvideosink->osxwindow->height / result.h;
+
+  /* Converting pointer coordinates to the non scaled geometry */
+  if (gst_structure_get_double (structure, "pointer_x", &x)) {
+    x = MIN (x, result.x + result.w);
+    x = MAX (x - result.x, 0);
+    gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
+        (gdouble) x * xscale, NULL);
+  }
+  if (gst_structure_get_double (structure, "pointer_y", &y)) {
+    y = MIN (y, result.y + result.h);
+    y = MAX (y - result.y, 0);
+    gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
+        (gdouble) y * yscale, NULL);
+  }
+
+  gst_pad_send_event (peer, event);
+  gst_object_unref (peer);
+}
+
+static void
+gst_osx_video_sink_navigation_init (GstNavigationInterface * iface)
+{
+  iface->send_event = gst_osx_video_sink_navigation_send_event;
+}
+
+static void
+gst_osx_video_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle_id)
+{
+  GstOSXVideoSink *osxvideosink = GST_OSX_VIDEO_SINK (overlay);
+  NSView *view = (NSView *) handle_id;
+
+  gst_osx_video_sink_call_from_main_thread(osxvideosink,
+      osxvideosink->osxvideosinkobject,
+      @selector(setView:), view, YES);
+}
+
+static void
+gst_osx_video_sink_xoverlay_init (GstVideoOverlayInterface * iface)
+{
+  iface->set_window_handle = gst_osx_video_sink_set_window_handle;
+  iface->expose = NULL;
+  iface->handle_events = NULL;
+}
+
+/* ============================================================= */
+/*                                                               */
+/*                       Public Methods                          */
+/*                                                               */
+/* ============================================================= */
+
+/* =========================================== */
+/*                                             */
+/*          Object typing & Creation           */
+/*                                             */
+/* =========================================== */
+
+GType
+gst_osx_video_sink_get_type (void)
+{
+  static GType osxvideosink_type = 0;
+
+  if (!osxvideosink_type) {
+    static const GTypeInfo osxvideosink_info = {
+      sizeof (GstOSXVideoSinkClass),
+      gst_osx_video_sink_base_init,
+      NULL,
+      (GClassInitFunc) gst_osx_video_sink_class_init,
+      NULL,
+      NULL,
+      sizeof (GstOSXVideoSink),
+      0,
+      (GInstanceInitFunc) gst_osx_video_sink_init,
+    };
+
+    static const GInterfaceInfo overlay_info = {
+      (GInterfaceInitFunc) gst_osx_video_sink_xoverlay_init,
+      NULL,
+      NULL,
+    };
+
+    static const GInterfaceInfo navigation_info = {
+      (GInterfaceInitFunc) gst_osx_video_sink_navigation_init,
+      NULL,
+      NULL,
+    };
+    osxvideosink_type = g_type_register_static (GST_TYPE_VIDEO_SINK,
+        "GstOSXVideoSink", &osxvideosink_info, 0);
+
+    g_type_add_interface_static (osxvideosink_type, GST_TYPE_VIDEO_OVERLAY,
+        &overlay_info);
+    g_type_add_interface_static (osxvideosink_type, GST_TYPE_NAVIGATION,
+        &navigation_info);
+  }
+
+  return osxvideosink_type;
+}
+
+@implementation GstWindowDelegate
+- (id) initWithSink: (GstOSXVideoSink *) sink
+{
+  self = [super init];
+  self->osxvideosink = sink;
+  return self;
+}
+
+- (void)windowWillClose:(NSNotification *)notification {
+  /* Only handle close events if the window was closed manually by the user
+   * and not becuase of a state change state to READY */
+  if (osxvideosink->osxwindow == NULL) {
+    return;
+  }
+  if (!osxvideosink->osxwindow->closed) {
+    osxvideosink->osxwindow->closed = TRUE;
+    GST_ELEMENT_ERROR (osxvideosink, RESOURCE, NOT_FOUND, ("Output window was closed"), (NULL));
+    gst_osx_video_sink_osxwindow_destroy(osxvideosink);
+  }
+}
+
+@end
+
+@ implementation GstOSXVideoSinkObject
+
+-(id) initWithSink: (GstOSXVideoSink*) sink
+{
+  self = [super init];
+  self->osxvideosink = gst_object_ref (sink);
+  return self;
+}
+
+-(void) dealloc {
+  gst_object_unref (osxvideosink);
+  [super dealloc];
+}
+
+-(void) createInternalWindow
+{
+  GstOSXWindow *osxwindow = osxvideosink->osxwindow;
+  NSRect rect;
+  unsigned int mask;
+
+  [NSApplication sharedApplication];
+
+  osxwindow->internal = TRUE;
+
+  mask =  NSWindowStyleMaskTitled             |
+          NSWindowStyleMaskClosable           |
+          NSWindowStyleMaskResizable          |
+          NSWindowStyleMaskTexturedBackground |
+          NSWindowStyleMaskMiniaturizable;
+
+  rect.origin.x = 100.0;
+  rect.origin.y = 100.0;
+  rect.size.width = (float) osxwindow->width;
+  rect.size.height = (float) osxwindow->height;
+
+  osxwindow->win =[[[GstOSXVideoSinkWindow alloc]
+                       initWithContentNSRect: rect
+                       styleMask: mask
+                       backing: NSBackingStoreBuffered
+                       defer: NO
+                       screen: nil] retain];
+  GST_DEBUG("VideoSinkWindow created, %p", osxwindow->win);
+  [osxwindow->win orderFrontRegardless];
+  osxwindow->gstview =[osxwindow->win gstView];
+  [osxwindow->win setDelegate:[[GstWindowDelegate alloc]
+      initWithSink:osxvideosink]];
+
+}
+
++ (BOOL) isMainThread
+{
+  /* FIXME: ideally we should return YES only for ->ns_app_thread here */
+  return YES;
+}
+
+- (void) setView: (NSView*)view
+{
+  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+  if (osxvideosink->superview) {
+    GST_INFO_OBJECT (osxvideosink, "old xwindow id %p", osxvideosink->superview);
+    if (osxvideosink->osxwindow) {
+      [osxvideosink->osxwindow->gstview removeFromSuperview];
+    }
+    [osxvideosink->superview release];
+  }
+  if (osxvideosink->osxwindow != NULL && view != NULL) {
+    if (osxvideosink->osxwindow->internal) {
+      GST_INFO_OBJECT (osxvideosink, "closing internal window");
+      osxvideosink->osxwindow->closed = TRUE;
+      [osxvideosink->osxwindow->win close];
+      [osxvideosink->osxwindow->win release];
+    }
+  }
+
+  GST_INFO_OBJECT (osxvideosink, "set xwindow id %p", view);
+  osxvideosink->superview = [view retain];
+  if (osxvideosink->osxwindow) {
+    [osxvideosink->osxwindow->gstview addToSuperview: osxvideosink->superview];
+    if (view) {
+      osxvideosink->osxwindow->internal = FALSE;
+    }
+  }
+
+  [pool release];
+}
+
+- (void) resize
+{
+  GstOSXWindow *osxwindow = osxvideosink->osxwindow;
+
+  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+  GST_INFO_OBJECT (osxvideosink, "resizing");
+  NSSize size = {osxwindow->width, osxwindow->height};
+  if (osxwindow->internal) {
+    [osxwindow->win setContentSize:size];
+  }
+  if (osxwindow->gstview) {
+      [osxwindow->gstview setVideoSize :(int)osxwindow->width :(int)osxwindow->height];
+  }
+  GST_INFO_OBJECT (osxvideosink, "done");
+
+  [pool release];
+}
+
+- (void) showFrame: (GstBufferObject *) object
+{
+  GstVideoFrame frame;
+  guint8 *data, *readp, *writep;
+  gint i, active_width, stride;
+  guint8 *texture_buffer;
+  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+  GstBuffer *buf = object->buf;
+
+  GST_OBJECT_LOCK (osxvideosink);
+  if (osxvideosink->osxwindow == NULL)
+      goto no_window;
+
+  texture_buffer = (guint8 *) [osxvideosink->osxwindow->gstview getTextureBuffer];
+  if (G_UNLIKELY (texture_buffer == NULL))
+      goto no_texture_buffer;
+
+  if (!gst_video_frame_map (&frame, &osxvideosink->info, buf, GST_MAP_READ))
+      goto no_map;
+
+  data = readp = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0);
+  stride = GST_VIDEO_FRAME_PLANE_STRIDE (&frame, 0);
+  writep = texture_buffer;
+  active_width = GST_VIDEO_SINK_WIDTH (osxvideosink) * sizeof (short);
+  for (i = 0; i < GST_VIDEO_SINK_HEIGHT (osxvideosink); i++) {
+      memcpy (writep, readp, active_width);
+      writep += active_width;
+      readp += stride;
+  }
+  [osxvideosink->osxwindow->gstview displayTexture];
+
+  gst_video_frame_unmap (&frame);
+
+out:
+  GST_OBJECT_UNLOCK (osxvideosink);
+  [object release];
+
+  [pool release];
+  return;
+
+no_map:
+  GST_WARNING_OBJECT (osxvideosink, "couldn't map frame");
+  goto out;
+
+no_window:
+  GST_WARNING_OBJECT (osxvideosink, "not showing frame since we have no window (!?)");
+  goto out;
+
+no_texture_buffer:
+  GST_ELEMENT_ERROR (osxvideosink, RESOURCE, WRITE, (NULL),
+          ("the texture buffer is NULL"));
+  goto out;
+}
+
+-(void) destroy
+{
+  NSAutoreleasePool *pool;
+  GstOSXWindow *osxwindow;
+
+  pool = [[NSAutoreleasePool alloc] init];
+
+  osxwindow = osxvideosink->osxwindow;
+  osxvideosink->osxwindow = NULL;
+
+  if (osxwindow) {
+    if (osxvideosink->superview) {
+      [osxwindow->gstview removeFromSuperview];
+    }
+    [osxwindow->gstview release];
+    if (osxwindow->internal) {
+      if (!osxwindow->closed) {
+        osxwindow->closed = TRUE;
+        [osxwindow->win close];
+        [osxwindow->win release];
+      }
+    }
+    g_free (osxwindow);
+  }
+  [pool release];
+}
+
+#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION
+-(void) nsAppThread
+{
+  NSAutoreleasePool *pool;
+
+  /* set the main runloop as the runloop for the current thread. This has the
+   * effect that calling NSApp nextEventMatchingMask:untilDate:inMode:dequeue
+   * runs the main runloop.
+   */
+  _CFRunLoopSetCurrent(CFRunLoopGetMain());
+
+  /* this is needed to make IsMainThread checks in core foundation work from the
+   * current thread
+   */
+  _CFMainPThread = pthread_self();
+
+  pool = [[NSAutoreleasePool alloc] init];
+
+  [NSApplication sharedApplication];
+  [NSApp finishLaunching];
+
+  g_mutex_lock (&_run_loop_mutex);
+  g_cond_signal (&_run_loop_cond);
+  g_mutex_unlock (&_run_loop_mutex);
+
+  /* run the loop */
+  run_ns_app_loop ();
+
+  [pool release];
+}
+
+-(void) checkMainRunLoop
+{
+  g_mutex_lock (&_run_loop_mutex);
+  g_cond_signal (&_run_loop_cond);
+  g_mutex_unlock (&_run_loop_mutex);
+}
+#endif
+
+@end
+
+@ implementation GstBufferObject
+-(id) initWithBuffer: (GstBuffer*) buffer
+{
+  self = [super init];
+  gst_buffer_ref(buffer);
+  self->buf = buffer;
+  return self;
+}
+
+-(void) dealloc{
+  gst_buffer_unref(buf);
+  [super dealloc];
+}
+@end
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+
+  if (!gst_element_register (plugin, "osxvideosink",
+          GST_RANK_MARGINAL, GST_TYPE_OSX_VIDEO_SINK))
+    return FALSE;
+
+  GST_DEBUG_CATEGORY_INIT (gst_debug_osx_video_sink, "osxvideosink", 0,
+      "osxvideosink element");
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    osxvideo,
+    "OSX native video output plugin",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/sys/v4l2/Makefile.am b/sys/v4l2/Makefile.am
new file mode 100644
index 0000000..3126c11
--- /dev/null
+++ b/sys/v4l2/Makefile.am
@@ -0,0 +1,74 @@
+plugin_LTLIBRARIES = libgstvideo4linux2.la
+
+include $(top_srcdir)/common/gst-glib-gen.mak
+
+libgstvideo4linux2_la_SOURCES = gstv4l2.c \
+				gstv4l2allocator.c \
+				gstv4l2colorbalance.c \
+				gstv4l2deviceprovider.c \
+				gstv4l2object.c \
+				gstv4l2bufferpool.c \
+				gstv4l2sink.c \
+				gstv4l2src.c \
+				gstv4l2radio.c \
+				gstv4l2tuner.c \
+				gstv4l2transform.c \
+				gstv4l2videodec.c \
+				gstv4l2videoenc.c \
+				gstv4l2h263enc.c \
+				gstv4l2h264enc.c \
+				gstv4l2mpeg4enc.c \
+				gstv4l2vidorient.c \
+				gstv4l2vp8enc.c \
+				gstv4l2vp9enc.c \
+				v4l2_calls.c \
+				v4l2-utils.c \
+				tuner.c \
+				tunerchannel.c \
+				tunernorm.c
+
+libgstvideo4linux2_la_CFLAGS =   $(GST_PLUGINS_BASE_CFLAGS) \
+				 $(GST_BASE_CFLAGS) \
+				 $(GST_CFLAGS) \
+				 $(X_CFLAGS) \
+				 $(LIBV4L2_CFLAGS) \
+				 $(GUDEV_CFLAGS)
+
+libgstvideo4linux2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstvideo4linux2_la_LIBADD =   $(GST_PLUGINS_BASE_LIBS) \
+				 -lgstallocators-$(GST_API_VERSION) \
+				 -lgstvideo-$(GST_API_VERSION) \
+				 $(GST_BASE_LIBS) \
+				 $(GST_LIBS) \
+				 $(LIBV4L2_LIBS) \
+				 $(GUDEV_LIBS) \
+				 $(LIBRT)
+
+noinst_HEADERS = \
+	ext/types-compat.h \
+	ext/v4l2-common.h \
+	ext/v4l2-controls.h \
+	ext/videodev2.h \
+	gstv4l2allocator.h \
+	gstv4l2bufferpool.h \
+	gstv4l2colorbalance.h \
+	gstv4l2deviceprovider.h \
+	gstv4l2object.h \
+	gstv4l2sink.h \
+	gstv4l2src.h \
+	gstv4l2radio.h \
+	gstv4l2tuner.h \
+	gstv4l2transform.h \
+	gstv4l2videodec.h \
+	gstv4l2videoenc.h \
+	gstv4l2h263enc.h \
+	gstv4l2h264enc.h \
+	gstv4l2mpeg4enc.h \
+	gstv4l2vidorient.h \
+	gstv4l2vp8enc.h \
+	gstv4l2vp9enc.h \
+	v4l2-utils.h \
+	tuner.h \
+	tunerchannel.h \
+	tunernorm.h
+
diff --git a/sys/v4l2/README b/sys/v4l2/README
new file mode 100644
index 0000000..e9c4ab4
--- /dev/null
+++ b/sys/v4l2/README
@@ -0,0 +1,32 @@
+v4l2 plugins
+============
+
+The idea is a bit the same as the idea for the v4l1 plugins. We want
+one generic v4l2element, and a few child objects (probably only two:
+v4l2src and v4l2sink):
+
+                /-------- v4l2src
+v4l2element ---=
+                \-------- v4l2sink
+
+Both v4l2src and v4l2sink have a uncompressed and a compressed
+recording-/playback-mode. Since this is all part of v4l2, the 'client'
+of these elements, i.e. an application using v4l2src/v4l2sink, will
+hardly notice this. All capsnego stuff is done inside, and the plugin
+knows which formats are compressed and which are not.
+
+Please note that the v4l1 and the v4l2 plugins are *not* compatible
+concerning properties. Naming has been kept the same where possible,
+but in some cases, properties had to be removed or added to make
+full use of v4l2.
+
+V4L2 API: http://linux.bytesex.org/v4l2/.
+          http://v4l2spec.bytesex.org/
+          /usr/include/linux/videodev2.h or
+
+Kernel patches available from
+          http://dl.bytesex.org/patches/.
+
+Articles:
+          http://lwn.net/Articles/203924/
+
diff --git a/sys/v4l2/ext/types-compat.h b/sys/v4l2/ext/types-compat.h
new file mode 100644
index 0000000..0126d7e
--- /dev/null
+++ b/sys/v4l2/ext/types-compat.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014 Collabora Ltd.
+ *     Author: Nicolas Dufresne <nicolas@ndufresne.ca>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <glib.h>
+
+#ifndef __TYPES_COMPAT_H__
+#define __TYPES_COMPAT_H__
+
+/* From linux/types.h */
+#ifndef __bitwise__
+#  ifdef __CHECKER__
+#    define __bitwise__ __attribute__((bitwise))
+#  else
+#    define __bitwise__
+#  endif
+#endif
+
+#ifndef __bitwise
+#  ifdef __CHECK_ENDIAN__
+#    define __bitwise __bitwise__
+#  else
+#    define __bitwise
+#  endif
+#endif
+
+#define __u64 guint64
+#define __u32 guint32
+#define __u16 guint16
+#define __u8 guint8
+#define __s64 gint64
+#define __s32 gint32
+#define __le32 guint32 __bitwise
+
+#define __user
+
+#endif /* __TYPES_COMPAT_H__ */
diff --git a/sys/v4l2/ext/v4l2-common.h b/sys/v4l2/ext/v4l2-common.h
new file mode 100644
index 0000000..2a2c88a
--- /dev/null
+++ b/sys/v4l2/ext/v4l2-common.h
@@ -0,0 +1,107 @@
+/*
+ * include/linux/v4l2-common.h
+ *
+ * Common V4L2 and V4L2 subdev definitions.
+ *
+ * Users are advised to #include this file either through videodev2.h
+ * (V4L2) or through v4l2-subdev.h (V4L2 subdev) rather than to refer
+ * to this file directly.
+ *
+ * Copyright (C) 2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  Alternatively you can redistribute this file under the terms of the
+ *  BSD license as stated below:
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *  3. The names of its contributors may not be used to endorse or promote
+ *     products derived from this software without specific prior written
+ *     permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __V4L2_COMMON__
+#define __V4L2_COMMON__
+
+#include "ext/types-compat.h"
+
+/*
+ *
+ * Selection interface definitions
+ *
+ */
+
+/* Current cropping area */
+#define V4L2_SEL_TGT_CROP		0x0000
+/* Default cropping area */
+#define V4L2_SEL_TGT_CROP_DEFAULT	0x0001
+/* Cropping bounds */
+#define V4L2_SEL_TGT_CROP_BOUNDS	0x0002
+/* Native frame size */
+#define V4L2_SEL_TGT_NATIVE_SIZE	0x0003
+/* Current composing area */
+#define V4L2_SEL_TGT_COMPOSE		0x0100
+/* Default composing area */
+#define V4L2_SEL_TGT_COMPOSE_DEFAULT	0x0101
+/* Composing bounds */
+#define V4L2_SEL_TGT_COMPOSE_BOUNDS	0x0102
+/* Current composing area plus all padding pixels */
+#define V4L2_SEL_TGT_COMPOSE_PADDED	0x0103
+
+/* Backward compatibility target definitions --- to be removed. */
+#define V4L2_SEL_TGT_CROP_ACTIVE	V4L2_SEL_TGT_CROP
+#define V4L2_SEL_TGT_COMPOSE_ACTIVE	V4L2_SEL_TGT_COMPOSE
+#define V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL	V4L2_SEL_TGT_CROP
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL V4L2_SEL_TGT_COMPOSE
+#define V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS	V4L2_SEL_TGT_CROP_BOUNDS
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS V4L2_SEL_TGT_COMPOSE_BOUNDS
+
+/* Selection flags */
+#define V4L2_SEL_FLAG_GE		(1 << 0)
+#define V4L2_SEL_FLAG_LE		(1 << 1)
+#define V4L2_SEL_FLAG_KEEP_CONFIG	(1 << 2)
+
+/* Backward compatibility flag definitions --- to be removed. */
+#define V4L2_SUBDEV_SEL_FLAG_SIZE_GE	V4L2_SEL_FLAG_GE
+#define V4L2_SUBDEV_SEL_FLAG_SIZE_LE	V4L2_SEL_FLAG_LE
+#define V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG V4L2_SEL_FLAG_KEEP_CONFIG
+
+struct v4l2_edid {
+	__u32 pad;
+	__u32 start_block;
+	__u32 blocks;
+	__u32 reserved[5];
+	__u8  *edid;
+};
+
+#endif /* __V4L2_COMMON__ */
diff --git a/sys/v4l2/ext/v4l2-controls.h b/sys/v4l2/ext/v4l2-controls.h
new file mode 100644
index 0000000..31bfc68
--- /dev/null
+++ b/sys/v4l2/ext/v4l2-controls.h
@@ -0,0 +1,987 @@
+/*
+ *  Video for Linux Two controls header file
+ *
+ *  Copyright (C) 1999-2012 the contributors
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  Alternatively you can redistribute this file under the terms of the
+ *  BSD license as stated below:
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *  3. The names of its contributors may not be used to endorse or promote
+ *     products derived from this software without specific prior written
+ *     permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  The contents of this header was split off from videodev2.h. All control
+ *  definitions should be added to this header, which is included by
+ *  videodev2.h.
+ */
+
+#ifndef __LINUX_V4L2_CONTROLS_H
+#define __LINUX_V4L2_CONTROLS_H
+
+/* Control classes */
+#define V4L2_CTRL_CLASS_USER		0x00980000	/* Old-style 'user' controls */
+#define V4L2_CTRL_CLASS_MPEG		0x00990000	/* MPEG-compression controls */
+#define V4L2_CTRL_CLASS_CAMERA		0x009a0000	/* Camera class controls */
+#define V4L2_CTRL_CLASS_FM_TX		0x009b0000	/* FM Modulator controls */
+#define V4L2_CTRL_CLASS_FLASH		0x009c0000	/* Camera flash controls */
+#define V4L2_CTRL_CLASS_JPEG		0x009d0000	/* JPEG-compression controls */
+#define V4L2_CTRL_CLASS_IMAGE_SOURCE	0x009e0000	/* Image source controls */
+#define V4L2_CTRL_CLASS_IMAGE_PROC	0x009f0000	/* Image processing controls */
+#define V4L2_CTRL_CLASS_DV		0x00a00000	/* Digital Video controls */
+#define V4L2_CTRL_CLASS_FM_RX		0x00a10000	/* FM Receiver controls */
+#define V4L2_CTRL_CLASS_RF_TUNER	0x00a20000	/* RF tuner controls */
+#define V4L2_CTRL_CLASS_DETECT		0x00a30000	/* Detection controls */
+
+/* User-class control IDs */
+
+#define V4L2_CID_BASE			(V4L2_CTRL_CLASS_USER | 0x900)
+#define V4L2_CID_USER_BASE 		V4L2_CID_BASE
+#define V4L2_CID_USER_CLASS 		(V4L2_CTRL_CLASS_USER | 1)
+#define V4L2_CID_BRIGHTNESS		(V4L2_CID_BASE+0)
+#define V4L2_CID_CONTRAST		(V4L2_CID_BASE+1)
+#define V4L2_CID_SATURATION		(V4L2_CID_BASE+2)
+#define V4L2_CID_HUE			(V4L2_CID_BASE+3)
+#define V4L2_CID_AUDIO_VOLUME		(V4L2_CID_BASE+5)
+#define V4L2_CID_AUDIO_BALANCE		(V4L2_CID_BASE+6)
+#define V4L2_CID_AUDIO_BASS		(V4L2_CID_BASE+7)
+#define V4L2_CID_AUDIO_TREBLE		(V4L2_CID_BASE+8)
+#define V4L2_CID_AUDIO_MUTE		(V4L2_CID_BASE+9)
+#define V4L2_CID_AUDIO_LOUDNESS		(V4L2_CID_BASE+10)
+#define V4L2_CID_BLACK_LEVEL		(V4L2_CID_BASE+11) /* Deprecated */
+#define V4L2_CID_AUTO_WHITE_BALANCE	(V4L2_CID_BASE+12)
+#define V4L2_CID_DO_WHITE_BALANCE	(V4L2_CID_BASE+13)
+#define V4L2_CID_RED_BALANCE		(V4L2_CID_BASE+14)
+#define V4L2_CID_BLUE_BALANCE		(V4L2_CID_BASE+15)
+#define V4L2_CID_GAMMA			(V4L2_CID_BASE+16)
+#define V4L2_CID_WHITENESS		(V4L2_CID_GAMMA) /* Deprecated */
+#define V4L2_CID_EXPOSURE		(V4L2_CID_BASE+17)
+#define V4L2_CID_AUTOGAIN		(V4L2_CID_BASE+18)
+#define V4L2_CID_GAIN			(V4L2_CID_BASE+19)
+#define V4L2_CID_HFLIP			(V4L2_CID_BASE+20)
+#define V4L2_CID_VFLIP			(V4L2_CID_BASE+21)
+
+#define V4L2_CID_POWER_LINE_FREQUENCY	(V4L2_CID_BASE+24)
+enum v4l2_power_line_frequency {
+	V4L2_CID_POWER_LINE_FREQUENCY_DISABLED	= 0,
+	V4L2_CID_POWER_LINE_FREQUENCY_50HZ	= 1,
+	V4L2_CID_POWER_LINE_FREQUENCY_60HZ	= 2,
+	V4L2_CID_POWER_LINE_FREQUENCY_AUTO	= 3,
+};
+#define V4L2_CID_HUE_AUTO			(V4L2_CID_BASE+25)
+#define V4L2_CID_WHITE_BALANCE_TEMPERATURE	(V4L2_CID_BASE+26)
+#define V4L2_CID_SHARPNESS			(V4L2_CID_BASE+27)
+#define V4L2_CID_BACKLIGHT_COMPENSATION 	(V4L2_CID_BASE+28)
+#define V4L2_CID_CHROMA_AGC                     (V4L2_CID_BASE+29)
+#define V4L2_CID_COLOR_KILLER                   (V4L2_CID_BASE+30)
+#define V4L2_CID_COLORFX			(V4L2_CID_BASE+31)
+enum v4l2_colorfx {
+	V4L2_COLORFX_NONE			= 0,
+	V4L2_COLORFX_BW				= 1,
+	V4L2_COLORFX_SEPIA			= 2,
+	V4L2_COLORFX_NEGATIVE			= 3,
+	V4L2_COLORFX_EMBOSS			= 4,
+	V4L2_COLORFX_SKETCH			= 5,
+	V4L2_COLORFX_SKY_BLUE			= 6,
+	V4L2_COLORFX_GRASS_GREEN		= 7,
+	V4L2_COLORFX_SKIN_WHITEN		= 8,
+	V4L2_COLORFX_VIVID			= 9,
+	V4L2_COLORFX_AQUA			= 10,
+	V4L2_COLORFX_ART_FREEZE			= 11,
+	V4L2_COLORFX_SILHOUETTE			= 12,
+	V4L2_COLORFX_SOLARIZATION		= 13,
+	V4L2_COLORFX_ANTIQUE			= 14,
+	V4L2_COLORFX_SET_CBCR			= 15,
+};
+#define V4L2_CID_AUTOBRIGHTNESS			(V4L2_CID_BASE+32)
+#define V4L2_CID_BAND_STOP_FILTER		(V4L2_CID_BASE+33)
+
+#define V4L2_CID_ROTATE				(V4L2_CID_BASE+34)
+#define V4L2_CID_BG_COLOR			(V4L2_CID_BASE+35)
+
+#define V4L2_CID_CHROMA_GAIN                    (V4L2_CID_BASE+36)
+
+#define V4L2_CID_ILLUMINATORS_1			(V4L2_CID_BASE+37)
+#define V4L2_CID_ILLUMINATORS_2			(V4L2_CID_BASE+38)
+
+#define V4L2_CID_MIN_BUFFERS_FOR_CAPTURE	(V4L2_CID_BASE+39)
+#define V4L2_CID_MIN_BUFFERS_FOR_OUTPUT		(V4L2_CID_BASE+40)
+
+#define V4L2_CID_ALPHA_COMPONENT		(V4L2_CID_BASE+41)
+#define V4L2_CID_COLORFX_CBCR			(V4L2_CID_BASE+42)
+
+/* last CID + 1 */
+#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+43)
+
+/* USER-class private control IDs */
+
+/* The base for the meye driver controls. See linux/meye.h for the list
+ * of controls. We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_MEYE_BASE			(V4L2_CID_USER_BASE + 0x1000)
+
+/* The base for the bttv driver controls.
+ * We reserve 32 controls for this driver. */
+#define V4L2_CID_USER_BTTV_BASE			(V4L2_CID_USER_BASE + 0x1010)
+
+
+/* The base for the s2255 driver controls.
+ * We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_S2255_BASE		(V4L2_CID_USER_BASE + 0x1030)
+
+/*
+ * The base for the si476x driver controls. See include/media/drv-intf/si476x.h
+ * for the list of controls. Total of 16 controls is reserved for this driver
+ */
+#define V4L2_CID_USER_SI476X_BASE		(V4L2_CID_USER_BASE + 0x1040)
+
+/* The base for the TI VPE driver controls. Total of 16 controls is reserved for
+ * this driver */
+#define V4L2_CID_USER_TI_VPE_BASE		(V4L2_CID_USER_BASE + 0x1050)
+
+/* The base for the saa7134 driver controls.
+ * We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_SAA7134_BASE		(V4L2_CID_USER_BASE + 0x1060)
+
+/* The base for the adv7180 driver controls.
+ * We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_ADV7180_BASE		(V4L2_CID_USER_BASE + 0x1070)
+
+/* The base for the tc358743 driver controls.
+ * We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_TC358743_BASE		(V4L2_CID_USER_BASE + 0x1080)
+
+/* The base for the max217x driver controls.
+ * We reserve 32 controls for this driver
+ */
+#define V4L2_CID_USER_MAX217X_BASE		(V4L2_CID_USER_BASE + 0x1090)
+
+/* The base for the imx driver controls.
+ * We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_IMX_BASE			(V4L2_CID_USER_BASE + 0x1090)
+
+/* MPEG-class control IDs */
+/* The MPEG controls are applicable to all codec controls
+ * and the 'MPEG' part of the define is historical */
+
+#define V4L2_CID_MPEG_BASE 			(V4L2_CTRL_CLASS_MPEG | 0x900)
+#define V4L2_CID_MPEG_CLASS 			(V4L2_CTRL_CLASS_MPEG | 1)
+
+/*  MPEG streams, specific to multiplexed streams */
+#define V4L2_CID_MPEG_STREAM_TYPE 		(V4L2_CID_MPEG_BASE+0)
+enum v4l2_mpeg_stream_type {
+	V4L2_MPEG_STREAM_TYPE_MPEG2_PS   = 0, /* MPEG-2 program stream */
+	V4L2_MPEG_STREAM_TYPE_MPEG2_TS   = 1, /* MPEG-2 transport stream */
+	V4L2_MPEG_STREAM_TYPE_MPEG1_SS   = 2, /* MPEG-1 system stream */
+	V4L2_MPEG_STREAM_TYPE_MPEG2_DVD  = 3, /* MPEG-2 DVD-compatible stream */
+	V4L2_MPEG_STREAM_TYPE_MPEG1_VCD  = 4, /* MPEG-1 VCD-compatible stream */
+	V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD = 5, /* MPEG-2 SVCD-compatible stream */
+};
+#define V4L2_CID_MPEG_STREAM_PID_PMT 		(V4L2_CID_MPEG_BASE+1)
+#define V4L2_CID_MPEG_STREAM_PID_AUDIO 		(V4L2_CID_MPEG_BASE+2)
+#define V4L2_CID_MPEG_STREAM_PID_VIDEO 		(V4L2_CID_MPEG_BASE+3)
+#define V4L2_CID_MPEG_STREAM_PID_PCR 		(V4L2_CID_MPEG_BASE+4)
+#define V4L2_CID_MPEG_STREAM_PES_ID_AUDIO 	(V4L2_CID_MPEG_BASE+5)
+#define V4L2_CID_MPEG_STREAM_PES_ID_VIDEO 	(V4L2_CID_MPEG_BASE+6)
+#define V4L2_CID_MPEG_STREAM_VBI_FMT 		(V4L2_CID_MPEG_BASE+7)
+enum v4l2_mpeg_stream_vbi_fmt {
+	V4L2_MPEG_STREAM_VBI_FMT_NONE = 0,  /* No VBI in the MPEG stream */
+	V4L2_MPEG_STREAM_VBI_FMT_IVTV = 1,  /* VBI in private packets, IVTV format */
+};
+
+/*  MPEG audio controls specific to multiplexed streams  */
+#define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ 	(V4L2_CID_MPEG_BASE+100)
+enum v4l2_mpeg_audio_sampling_freq {
+	V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0,
+	V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 = 1,
+	V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000 = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_ENCODING 		(V4L2_CID_MPEG_BASE+101)
+enum v4l2_mpeg_audio_encoding {
+	V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0,
+	V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1,
+	V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2,
+	V4L2_MPEG_AUDIO_ENCODING_AAC     = 3,
+	V4L2_MPEG_AUDIO_ENCODING_AC3     = 4,
+};
+#define V4L2_CID_MPEG_AUDIO_L1_BITRATE 		(V4L2_CID_MPEG_BASE+102)
+enum v4l2_mpeg_audio_l1_bitrate {
+	V4L2_MPEG_AUDIO_L1_BITRATE_32K  = 0,
+	V4L2_MPEG_AUDIO_L1_BITRATE_64K  = 1,
+	V4L2_MPEG_AUDIO_L1_BITRATE_96K  = 2,
+	V4L2_MPEG_AUDIO_L1_BITRATE_128K = 3,
+	V4L2_MPEG_AUDIO_L1_BITRATE_160K = 4,
+	V4L2_MPEG_AUDIO_L1_BITRATE_192K = 5,
+	V4L2_MPEG_AUDIO_L1_BITRATE_224K = 6,
+	V4L2_MPEG_AUDIO_L1_BITRATE_256K = 7,
+	V4L2_MPEG_AUDIO_L1_BITRATE_288K = 8,
+	V4L2_MPEG_AUDIO_L1_BITRATE_320K = 9,
+	V4L2_MPEG_AUDIO_L1_BITRATE_352K = 10,
+	V4L2_MPEG_AUDIO_L1_BITRATE_384K = 11,
+	V4L2_MPEG_AUDIO_L1_BITRATE_416K = 12,
+	V4L2_MPEG_AUDIO_L1_BITRATE_448K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_L2_BITRATE 		(V4L2_CID_MPEG_BASE+103)
+enum v4l2_mpeg_audio_l2_bitrate {
+	V4L2_MPEG_AUDIO_L2_BITRATE_32K  = 0,
+	V4L2_MPEG_AUDIO_L2_BITRATE_48K  = 1,
+	V4L2_MPEG_AUDIO_L2_BITRATE_56K  = 2,
+	V4L2_MPEG_AUDIO_L2_BITRATE_64K  = 3,
+	V4L2_MPEG_AUDIO_L2_BITRATE_80K  = 4,
+	V4L2_MPEG_AUDIO_L2_BITRATE_96K  = 5,
+	V4L2_MPEG_AUDIO_L2_BITRATE_112K = 6,
+	V4L2_MPEG_AUDIO_L2_BITRATE_128K = 7,
+	V4L2_MPEG_AUDIO_L2_BITRATE_160K = 8,
+	V4L2_MPEG_AUDIO_L2_BITRATE_192K = 9,
+	V4L2_MPEG_AUDIO_L2_BITRATE_224K = 10,
+	V4L2_MPEG_AUDIO_L2_BITRATE_256K = 11,
+	V4L2_MPEG_AUDIO_L2_BITRATE_320K = 12,
+	V4L2_MPEG_AUDIO_L2_BITRATE_384K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_L3_BITRATE 		(V4L2_CID_MPEG_BASE+104)
+enum v4l2_mpeg_audio_l3_bitrate {
+	V4L2_MPEG_AUDIO_L3_BITRATE_32K  = 0,
+	V4L2_MPEG_AUDIO_L3_BITRATE_40K  = 1,
+	V4L2_MPEG_AUDIO_L3_BITRATE_48K  = 2,
+	V4L2_MPEG_AUDIO_L3_BITRATE_56K  = 3,
+	V4L2_MPEG_AUDIO_L3_BITRATE_64K  = 4,
+	V4L2_MPEG_AUDIO_L3_BITRATE_80K  = 5,
+	V4L2_MPEG_AUDIO_L3_BITRATE_96K  = 6,
+	V4L2_MPEG_AUDIO_L3_BITRATE_112K = 7,
+	V4L2_MPEG_AUDIO_L3_BITRATE_128K = 8,
+	V4L2_MPEG_AUDIO_L3_BITRATE_160K = 9,
+	V4L2_MPEG_AUDIO_L3_BITRATE_192K = 10,
+	V4L2_MPEG_AUDIO_L3_BITRATE_224K = 11,
+	V4L2_MPEG_AUDIO_L3_BITRATE_256K = 12,
+	V4L2_MPEG_AUDIO_L3_BITRATE_320K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_MODE 		(V4L2_CID_MPEG_BASE+105)
+enum v4l2_mpeg_audio_mode {
+	V4L2_MPEG_AUDIO_MODE_STEREO       = 0,
+	V4L2_MPEG_AUDIO_MODE_JOINT_STEREO = 1,
+	V4L2_MPEG_AUDIO_MODE_DUAL         = 2,
+	V4L2_MPEG_AUDIO_MODE_MONO         = 3,
+};
+#define V4L2_CID_MPEG_AUDIO_MODE_EXTENSION 	(V4L2_CID_MPEG_BASE+106)
+enum v4l2_mpeg_audio_mode_extension {
+	V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4  = 0,
+	V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8  = 1,
+	V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12 = 2,
+	V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16 = 3,
+};
+#define V4L2_CID_MPEG_AUDIO_EMPHASIS 		(V4L2_CID_MPEG_BASE+107)
+enum v4l2_mpeg_audio_emphasis {
+	V4L2_MPEG_AUDIO_EMPHASIS_NONE         = 0,
+	V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS = 1,
+	V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17    = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_CRC 		(V4L2_CID_MPEG_BASE+108)
+enum v4l2_mpeg_audio_crc {
+	V4L2_MPEG_AUDIO_CRC_NONE  = 0,
+	V4L2_MPEG_AUDIO_CRC_CRC16 = 1,
+};
+#define V4L2_CID_MPEG_AUDIO_MUTE 		(V4L2_CID_MPEG_BASE+109)
+#define V4L2_CID_MPEG_AUDIO_AAC_BITRATE		(V4L2_CID_MPEG_BASE+110)
+#define V4L2_CID_MPEG_AUDIO_AC3_BITRATE		(V4L2_CID_MPEG_BASE+111)
+enum v4l2_mpeg_audio_ac3_bitrate {
+	V4L2_MPEG_AUDIO_AC3_BITRATE_32K  = 0,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_40K  = 1,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_48K  = 2,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_56K  = 3,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_64K  = 4,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_80K  = 5,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_96K  = 6,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_112K = 7,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_128K = 8,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_160K = 9,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_192K = 10,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_224K = 11,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_256K = 12,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_320K = 13,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_384K = 14,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_448K = 15,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_512K = 16,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18,
+};
+#define V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK	(V4L2_CID_MPEG_BASE+112)
+enum v4l2_mpeg_audio_dec_playback {
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO	    = 0,
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO	    = 1,
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT	    = 2,
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_RIGHT	    = 3,
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_MONO	    = 4,
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO = 5,
+};
+#define V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK (V4L2_CID_MPEG_BASE+113)
+
+/*  MPEG video controls specific to multiplexed streams */
+#define V4L2_CID_MPEG_VIDEO_ENCODING 		(V4L2_CID_MPEG_BASE+200)
+enum v4l2_mpeg_video_encoding {
+	V4L2_MPEG_VIDEO_ENCODING_MPEG_1     = 0,
+	V4L2_MPEG_VIDEO_ENCODING_MPEG_2     = 1,
+	V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC = 2,
+};
+#define V4L2_CID_MPEG_VIDEO_ASPECT 		(V4L2_CID_MPEG_BASE+201)
+enum v4l2_mpeg_video_aspect {
+	V4L2_MPEG_VIDEO_ASPECT_1x1     = 0,
+	V4L2_MPEG_VIDEO_ASPECT_4x3     = 1,
+	V4L2_MPEG_VIDEO_ASPECT_16x9    = 2,
+	V4L2_MPEG_VIDEO_ASPECT_221x100 = 3,
+};
+#define V4L2_CID_MPEG_VIDEO_B_FRAMES 		(V4L2_CID_MPEG_BASE+202)
+#define V4L2_CID_MPEG_VIDEO_GOP_SIZE 		(V4L2_CID_MPEG_BASE+203)
+#define V4L2_CID_MPEG_VIDEO_GOP_CLOSURE 	(V4L2_CID_MPEG_BASE+204)
+#define V4L2_CID_MPEG_VIDEO_PULLDOWN 		(V4L2_CID_MPEG_BASE+205)
+#define V4L2_CID_MPEG_VIDEO_BITRATE_MODE 	(V4L2_CID_MPEG_BASE+206)
+enum v4l2_mpeg_video_bitrate_mode {
+	V4L2_MPEG_VIDEO_BITRATE_MODE_VBR = 0,
+	V4L2_MPEG_VIDEO_BITRATE_MODE_CBR = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_BITRATE 		(V4L2_CID_MPEG_BASE+207)
+#define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK 	(V4L2_CID_MPEG_BASE+208)
+#define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209)
+#define V4L2_CID_MPEG_VIDEO_MUTE 		(V4L2_CID_MPEG_BASE+210)
+#define V4L2_CID_MPEG_VIDEO_MUTE_YUV 		(V4L2_CID_MPEG_BASE+211)
+#define V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE		(V4L2_CID_MPEG_BASE+212)
+#define V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER	(V4L2_CID_MPEG_BASE+213)
+#define V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB		(V4L2_CID_MPEG_BASE+214)
+#define V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE			(V4L2_CID_MPEG_BASE+215)
+#define V4L2_CID_MPEG_VIDEO_HEADER_MODE				(V4L2_CID_MPEG_BASE+216)
+enum v4l2_mpeg_video_header_mode {
+	V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE			= 0,
+	V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME	= 1,
+
+};
+#define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC			(V4L2_CID_MPEG_BASE+217)
+#define V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE		(V4L2_CID_MPEG_BASE+218)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES	(V4L2_CID_MPEG_BASE+219)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB		(V4L2_CID_MPEG_BASE+220)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE		(V4L2_CID_MPEG_BASE+221)
+enum v4l2_mpeg_video_multi_slice_mode {
+	V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE		= 0,
+	V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB		= 1,
+	V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES	= 2,
+};
+#define V4L2_CID_MPEG_VIDEO_VBV_SIZE			(V4L2_CID_MPEG_BASE+222)
+#define V4L2_CID_MPEG_VIDEO_DEC_PTS			(V4L2_CID_MPEG_BASE+223)
+#define V4L2_CID_MPEG_VIDEO_DEC_FRAME			(V4L2_CID_MPEG_BASE+224)
+#define V4L2_CID_MPEG_VIDEO_VBV_DELAY			(V4L2_CID_MPEG_BASE+225)
+#define V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER		(V4L2_CID_MPEG_BASE+226)
+#define V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE		(V4L2_CID_MPEG_BASE+227)
+#define V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE		(V4L2_CID_MPEG_BASE+228)
+#define V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME		(V4L2_CID_MPEG_BASE+229)
+
+#define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP		(V4L2_CID_MPEG_BASE+300)
+#define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP		(V4L2_CID_MPEG_BASE+301)
+#define V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP		(V4L2_CID_MPEG_BASE+302)
+#define V4L2_CID_MPEG_VIDEO_H263_MIN_QP			(V4L2_CID_MPEG_BASE+303)
+#define V4L2_CID_MPEG_VIDEO_H263_MAX_QP			(V4L2_CID_MPEG_BASE+304)
+#define V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP		(V4L2_CID_MPEG_BASE+350)
+#define V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP		(V4L2_CID_MPEG_BASE+351)
+#define V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP		(V4L2_CID_MPEG_BASE+352)
+#define V4L2_CID_MPEG_VIDEO_H264_MIN_QP			(V4L2_CID_MPEG_BASE+353)
+#define V4L2_CID_MPEG_VIDEO_H264_MAX_QP			(V4L2_CID_MPEG_BASE+354)
+#define V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM		(V4L2_CID_MPEG_BASE+355)
+#define V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE		(V4L2_CID_MPEG_BASE+356)
+#define V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE		(V4L2_CID_MPEG_BASE+357)
+enum v4l2_mpeg_video_h264_entropy_mode {
+	V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC	= 0,
+	V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC	= 1,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_I_PERIOD		(V4L2_CID_MPEG_BASE+358)
+#define V4L2_CID_MPEG_VIDEO_H264_LEVEL			(V4L2_CID_MPEG_BASE+359)
+enum v4l2_mpeg_video_h264_level {
+	V4L2_MPEG_VIDEO_H264_LEVEL_1_0	= 0,
+	V4L2_MPEG_VIDEO_H264_LEVEL_1B	= 1,
+	V4L2_MPEG_VIDEO_H264_LEVEL_1_1	= 2,
+	V4L2_MPEG_VIDEO_H264_LEVEL_1_2	= 3,
+	V4L2_MPEG_VIDEO_H264_LEVEL_1_3	= 4,
+	V4L2_MPEG_VIDEO_H264_LEVEL_2_0	= 5,
+	V4L2_MPEG_VIDEO_H264_LEVEL_2_1	= 6,
+	V4L2_MPEG_VIDEO_H264_LEVEL_2_2	= 7,
+	V4L2_MPEG_VIDEO_H264_LEVEL_3_0	= 8,
+	V4L2_MPEG_VIDEO_H264_LEVEL_3_1	= 9,
+	V4L2_MPEG_VIDEO_H264_LEVEL_3_2	= 10,
+	V4L2_MPEG_VIDEO_H264_LEVEL_4_0	= 11,
+	V4L2_MPEG_VIDEO_H264_LEVEL_4_1	= 12,
+	V4L2_MPEG_VIDEO_H264_LEVEL_4_2	= 13,
+	V4L2_MPEG_VIDEO_H264_LEVEL_5_0	= 14,
+	V4L2_MPEG_VIDEO_H264_LEVEL_5_1	= 15,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA	(V4L2_CID_MPEG_BASE+360)
+#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA	(V4L2_CID_MPEG_BASE+361)
+#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE	(V4L2_CID_MPEG_BASE+362)
+enum v4l2_mpeg_video_h264_loop_filter_mode {
+	V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED				= 0,
+	V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED				= 1,
+	V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY	= 2,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_PROFILE		(V4L2_CID_MPEG_BASE+363)
+enum v4l2_mpeg_video_h264_profile {
+	V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE			= 0,
+	V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE	= 1,
+	V4L2_MPEG_VIDEO_H264_PROFILE_MAIN			= 2,
+	V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED			= 3,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH			= 4,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10			= 5,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422			= 6,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE	= 7,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA		= 8,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA		= 9,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA		= 10,
+	V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA		= 11,
+	V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE		= 12,
+	V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH		= 13,
+	V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA	= 14,
+	V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH		= 15,
+	V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH		= 16,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT	(V4L2_CID_MPEG_BASE+364)
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH	(V4L2_CID_MPEG_BASE+365)
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE		(V4L2_CID_MPEG_BASE+366)
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC		(V4L2_CID_MPEG_BASE+367)
+enum v4l2_mpeg_video_h264_vui_sar_idc {
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED	= 0,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1		= 1,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11		= 2,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11		= 3,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11		= 4,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33		= 5,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11		= 6,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11		= 7,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11		= 8,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33		= 9,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11		= 10,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11		= 11,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33		= 12,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99		= 13,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3		= 14,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2		= 15,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1		= 16,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED	= 17,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING		(V4L2_CID_MPEG_BASE+368)
+#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0		(V4L2_CID_MPEG_BASE+369)
+#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE	(V4L2_CID_MPEG_BASE+370)
+enum v4l2_mpeg_video_h264_sei_fp_arrangement_type {
+	V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_CHECKERBOARD	= 0,
+	V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_COLUMN		= 1,
+	V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_ROW		= 2,
+	V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE	= 3,
+	V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TOP_BOTTOM		= 4,
+	V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TEMPORAL		= 5,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_FMO			(V4L2_CID_MPEG_BASE+371)
+#define V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE		(V4L2_CID_MPEG_BASE+372)
+enum v4l2_mpeg_video_h264_fmo_map_type {
+	V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES		= 0,
+	V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES		= 1,
+	V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_FOREGROUND_WITH_LEFT_OVER	= 2,
+	V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_BOX_OUT			= 3,
+	V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN			= 4,
+	V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN			= 5,
+	V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_EXPLICIT			= 6,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP	(V4L2_CID_MPEG_BASE+373)
+#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION	(V4L2_CID_MPEG_BASE+374)
+enum v4l2_mpeg_video_h264_fmo_change_dir {
+	V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT	= 0,
+	V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_LEFT	= 1,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE	(V4L2_CID_MPEG_BASE+375)
+#define V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH		(V4L2_CID_MPEG_BASE+376)
+#define V4L2_CID_MPEG_VIDEO_H264_ASO			(V4L2_CID_MPEG_BASE+377)
+#define V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER	(V4L2_CID_MPEG_BASE+378)
+#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING		(V4L2_CID_MPEG_BASE+379)
+#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE	(V4L2_CID_MPEG_BASE+380)
+enum v4l2_mpeg_video_h264_hierarchical_coding_type {
+	V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B	= 0,
+	V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P	= 1,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER	(V4L2_CID_MPEG_BASE+381)
+#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP	(V4L2_CID_MPEG_BASE+382)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP	(V4L2_CID_MPEG_BASE+400)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP	(V4L2_CID_MPEG_BASE+401)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP	(V4L2_CID_MPEG_BASE+402)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP	(V4L2_CID_MPEG_BASE+403)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP	(V4L2_CID_MPEG_BASE+404)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL		(V4L2_CID_MPEG_BASE+405)
+enum v4l2_mpeg_video_mpeg4_level {
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_0	= 0,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B	= 1,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_1	= 2,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_2	= 3,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_3	= 4,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B	= 5,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_4	= 6,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_5	= 7,
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE	(V4L2_CID_MPEG_BASE+406)
+enum v4l2_mpeg_video_mpeg4_profile {
+	V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE				= 0,
+	V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE			= 1,
+	V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE				= 2,
+	V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE			= 3,
+	V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY	= 4,
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG4_QPEL		(V4L2_CID_MPEG_BASE+407)
+
+/*  Control IDs for VP8 streams
+ *  Although VP8 is not part of MPEG we add these controls to the MPEG class
+ *  as that class is already handling other video compression standards
+ */
+#define V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS		(V4L2_CID_MPEG_BASE+500)
+enum v4l2_vp8_num_partitions {
+	V4L2_CID_MPEG_VIDEO_VPX_1_PARTITION	= 0,
+	V4L2_CID_MPEG_VIDEO_VPX_2_PARTITIONS	= 1,
+	V4L2_CID_MPEG_VIDEO_VPX_4_PARTITIONS	= 2,
+	V4L2_CID_MPEG_VIDEO_VPX_8_PARTITIONS	= 3,
+};
+#define V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4		(V4L2_CID_MPEG_BASE+501)
+#define V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES		(V4L2_CID_MPEG_BASE+502)
+enum v4l2_vp8_num_ref_frames {
+	V4L2_CID_MPEG_VIDEO_VPX_1_REF_FRAME	= 0,
+	V4L2_CID_MPEG_VIDEO_VPX_2_REF_FRAME	= 1,
+	V4L2_CID_MPEG_VIDEO_VPX_3_REF_FRAME	= 2,
+};
+#define V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL		(V4L2_CID_MPEG_BASE+503)
+#define V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS	(V4L2_CID_MPEG_BASE+504)
+#define V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD	(V4L2_CID_MPEG_BASE+505)
+#define V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL	(V4L2_CID_MPEG_BASE+506)
+enum v4l2_vp8_golden_frame_sel {
+	V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV		= 0,
+	V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_REF_PERIOD	= 1,
+};
+#define V4L2_CID_MPEG_VIDEO_VPX_MIN_QP			(V4L2_CID_MPEG_BASE+507)
+#define V4L2_CID_MPEG_VIDEO_VPX_MAX_QP			(V4L2_CID_MPEG_BASE+508)
+#define V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP		(V4L2_CID_MPEG_BASE+509)
+#define V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP		(V4L2_CID_MPEG_BASE+510)
+#define V4L2_CID_MPEG_VIDEO_VPX_PROFILE			(V4L2_CID_MPEG_BASE+511)
+
+/*  MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */
+#define V4L2_CID_MPEG_CX2341X_BASE 				(V4L2_CTRL_CLASS_MPEG | 0x1000)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE 	(V4L2_CID_MPEG_CX2341X_BASE+0)
+enum v4l2_mpeg_cx2341x_video_spatial_filter_mode {
+	V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL = 0,
+	V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO   = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER 		(V4L2_CID_MPEG_CX2341X_BASE+1)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE 	(V4L2_CID_MPEG_CX2341X_BASE+2)
+enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type {
+	V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF                  = 0,
+	V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR               = 1,
+	V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT              = 2,
+	V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE      = 3,
+	V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE = 4,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE 	(V4L2_CID_MPEG_CX2341X_BASE+3)
+enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type {
+	V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF    = 0,
+	V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE 	(V4L2_CID_MPEG_CX2341X_BASE+4)
+enum v4l2_mpeg_cx2341x_video_temporal_filter_mode {
+	V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL = 0,
+	V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO   = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER 		(V4L2_CID_MPEG_CX2341X_BASE+5)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE 		(V4L2_CID_MPEG_CX2341X_BASE+6)
+enum v4l2_mpeg_cx2341x_video_median_filter_type {
+	V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF      = 0,
+	V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR      = 1,
+	V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT     = 2,
+	V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT = 3,
+	V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG     = 4,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM 	(V4L2_CID_MPEG_CX2341X_BASE+7)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP 	(V4L2_CID_MPEG_CX2341X_BASE+8)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM	(V4L2_CID_MPEG_CX2341X_BASE+9)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP 	(V4L2_CID_MPEG_CX2341X_BASE+10)
+#define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS 	(V4L2_CID_MPEG_CX2341X_BASE+11)
+
+/*  MPEG-class control IDs specific to the Samsung MFC 5.1 driver as defined by V4L2 */
+#define V4L2_CID_MPEG_MFC51_BASE				(V4L2_CTRL_CLASS_MPEG | 0x1100)
+
+#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY		(V4L2_CID_MPEG_MFC51_BASE+0)
+#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE	(V4L2_CID_MPEG_MFC51_BASE+1)
+#define V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE			(V4L2_CID_MPEG_MFC51_BASE+2)
+enum v4l2_mpeg_mfc51_video_frame_skip_mode {
+	V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED		= 0,
+	V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT	= 1,
+	V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT		= 2,
+};
+#define V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE			(V4L2_CID_MPEG_MFC51_BASE+3)
+enum v4l2_mpeg_mfc51_video_force_frame_type {
+	V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED		= 0,
+	V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME		= 1,
+	V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED	= 2,
+};
+#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING				(V4L2_CID_MPEG_MFC51_BASE+4)
+#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV				(V4L2_CID_MPEG_MFC51_BASE+5)
+#define V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT			(V4L2_CID_MPEG_MFC51_BASE+6)
+#define V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF			(V4L2_CID_MPEG_MFC51_BASE+7)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY		(V4L2_CID_MPEG_MFC51_BASE+50)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK			(V4L2_CID_MPEG_MFC51_BASE+51)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH		(V4L2_CID_MPEG_MFC51_BASE+52)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC		(V4L2_CID_MPEG_MFC51_BASE+53)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P		(V4L2_CID_MPEG_MFC51_BASE+54)
+
+
+/*  Camera class control IDs */
+
+#define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
+#define V4L2_CID_CAMERA_CLASS 		(V4L2_CTRL_CLASS_CAMERA | 1)
+
+#define V4L2_CID_EXPOSURE_AUTO			(V4L2_CID_CAMERA_CLASS_BASE+1)
+enum  v4l2_exposure_auto_type {
+	V4L2_EXPOSURE_AUTO = 0,
+	V4L2_EXPOSURE_MANUAL = 1,
+	V4L2_EXPOSURE_SHUTTER_PRIORITY = 2,
+	V4L2_EXPOSURE_APERTURE_PRIORITY = 3
+};
+#define V4L2_CID_EXPOSURE_ABSOLUTE		(V4L2_CID_CAMERA_CLASS_BASE+2)
+#define V4L2_CID_EXPOSURE_AUTO_PRIORITY		(V4L2_CID_CAMERA_CLASS_BASE+3)
+
+#define V4L2_CID_PAN_RELATIVE			(V4L2_CID_CAMERA_CLASS_BASE+4)
+#define V4L2_CID_TILT_RELATIVE			(V4L2_CID_CAMERA_CLASS_BASE+5)
+#define V4L2_CID_PAN_RESET			(V4L2_CID_CAMERA_CLASS_BASE+6)
+#define V4L2_CID_TILT_RESET			(V4L2_CID_CAMERA_CLASS_BASE+7)
+
+#define V4L2_CID_PAN_ABSOLUTE			(V4L2_CID_CAMERA_CLASS_BASE+8)
+#define V4L2_CID_TILT_ABSOLUTE			(V4L2_CID_CAMERA_CLASS_BASE+9)
+
+#define V4L2_CID_FOCUS_ABSOLUTE			(V4L2_CID_CAMERA_CLASS_BASE+10)
+#define V4L2_CID_FOCUS_RELATIVE			(V4L2_CID_CAMERA_CLASS_BASE+11)
+#define V4L2_CID_FOCUS_AUTO			(V4L2_CID_CAMERA_CLASS_BASE+12)
+
+#define V4L2_CID_ZOOM_ABSOLUTE			(V4L2_CID_CAMERA_CLASS_BASE+13)
+#define V4L2_CID_ZOOM_RELATIVE			(V4L2_CID_CAMERA_CLASS_BASE+14)
+#define V4L2_CID_ZOOM_CONTINUOUS		(V4L2_CID_CAMERA_CLASS_BASE+15)
+
+#define V4L2_CID_PRIVACY			(V4L2_CID_CAMERA_CLASS_BASE+16)
+
+#define V4L2_CID_IRIS_ABSOLUTE			(V4L2_CID_CAMERA_CLASS_BASE+17)
+#define V4L2_CID_IRIS_RELATIVE			(V4L2_CID_CAMERA_CLASS_BASE+18)
+
+#define V4L2_CID_AUTO_EXPOSURE_BIAS		(V4L2_CID_CAMERA_CLASS_BASE+19)
+
+#define V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE	(V4L2_CID_CAMERA_CLASS_BASE+20)
+enum v4l2_auto_n_preset_white_balance {
+	V4L2_WHITE_BALANCE_MANUAL		= 0,
+	V4L2_WHITE_BALANCE_AUTO			= 1,
+	V4L2_WHITE_BALANCE_INCANDESCENT		= 2,
+	V4L2_WHITE_BALANCE_FLUORESCENT		= 3,
+	V4L2_WHITE_BALANCE_FLUORESCENT_H	= 4,
+	V4L2_WHITE_BALANCE_HORIZON		= 5,
+	V4L2_WHITE_BALANCE_DAYLIGHT		= 6,
+	V4L2_WHITE_BALANCE_FLASH		= 7,
+	V4L2_WHITE_BALANCE_CLOUDY		= 8,
+	V4L2_WHITE_BALANCE_SHADE		= 9,
+};
+
+#define V4L2_CID_WIDE_DYNAMIC_RANGE		(V4L2_CID_CAMERA_CLASS_BASE+21)
+#define V4L2_CID_IMAGE_STABILIZATION		(V4L2_CID_CAMERA_CLASS_BASE+22)
+
+#define V4L2_CID_ISO_SENSITIVITY		(V4L2_CID_CAMERA_CLASS_BASE+23)
+#define V4L2_CID_ISO_SENSITIVITY_AUTO		(V4L2_CID_CAMERA_CLASS_BASE+24)
+enum v4l2_iso_sensitivity_auto_type {
+	V4L2_ISO_SENSITIVITY_MANUAL		= 0,
+	V4L2_ISO_SENSITIVITY_AUTO		= 1,
+};
+
+#define V4L2_CID_EXPOSURE_METERING		(V4L2_CID_CAMERA_CLASS_BASE+25)
+enum v4l2_exposure_metering {
+	V4L2_EXPOSURE_METERING_AVERAGE		= 0,
+	V4L2_EXPOSURE_METERING_CENTER_WEIGHTED	= 1,
+	V4L2_EXPOSURE_METERING_SPOT		= 2,
+	V4L2_EXPOSURE_METERING_MATRIX		= 3,
+};
+
+#define V4L2_CID_SCENE_MODE			(V4L2_CID_CAMERA_CLASS_BASE+26)
+enum v4l2_scene_mode {
+	V4L2_SCENE_MODE_NONE			= 0,
+	V4L2_SCENE_MODE_BACKLIGHT		= 1,
+	V4L2_SCENE_MODE_BEACH_SNOW		= 2,
+	V4L2_SCENE_MODE_CANDLE_LIGHT		= 3,
+	V4L2_SCENE_MODE_DAWN_DUSK		= 4,
+	V4L2_SCENE_MODE_FALL_COLORS		= 5,
+	V4L2_SCENE_MODE_FIREWORKS		= 6,
+	V4L2_SCENE_MODE_LANDSCAPE		= 7,
+	V4L2_SCENE_MODE_NIGHT			= 8,
+	V4L2_SCENE_MODE_PARTY_INDOOR		= 9,
+	V4L2_SCENE_MODE_PORTRAIT		= 10,
+	V4L2_SCENE_MODE_SPORTS			= 11,
+	V4L2_SCENE_MODE_SUNSET			= 12,
+	V4L2_SCENE_MODE_TEXT			= 13,
+};
+
+#define V4L2_CID_3A_LOCK			(V4L2_CID_CAMERA_CLASS_BASE+27)
+#define V4L2_LOCK_EXPOSURE			(1 << 0)
+#define V4L2_LOCK_WHITE_BALANCE			(1 << 1)
+#define V4L2_LOCK_FOCUS				(1 << 2)
+
+#define V4L2_CID_AUTO_FOCUS_START		(V4L2_CID_CAMERA_CLASS_BASE+28)
+#define V4L2_CID_AUTO_FOCUS_STOP		(V4L2_CID_CAMERA_CLASS_BASE+29)
+#define V4L2_CID_AUTO_FOCUS_STATUS		(V4L2_CID_CAMERA_CLASS_BASE+30)
+#define V4L2_AUTO_FOCUS_STATUS_IDLE		(0 << 0)
+#define V4L2_AUTO_FOCUS_STATUS_BUSY		(1 << 0)
+#define V4L2_AUTO_FOCUS_STATUS_REACHED		(1 << 1)
+#define V4L2_AUTO_FOCUS_STATUS_FAILED		(1 << 2)
+
+#define V4L2_CID_AUTO_FOCUS_RANGE		(V4L2_CID_CAMERA_CLASS_BASE+31)
+enum v4l2_auto_focus_range {
+	V4L2_AUTO_FOCUS_RANGE_AUTO		= 0,
+	V4L2_AUTO_FOCUS_RANGE_NORMAL		= 1,
+	V4L2_AUTO_FOCUS_RANGE_MACRO		= 2,
+	V4L2_AUTO_FOCUS_RANGE_INFINITY		= 3,
+};
+
+#define V4L2_CID_PAN_SPEED			(V4L2_CID_CAMERA_CLASS_BASE+32)
+#define V4L2_CID_TILT_SPEED			(V4L2_CID_CAMERA_CLASS_BASE+33)
+
+/* FM Modulator class control IDs */
+
+#define V4L2_CID_FM_TX_CLASS_BASE		(V4L2_CTRL_CLASS_FM_TX | 0x900)
+#define V4L2_CID_FM_TX_CLASS			(V4L2_CTRL_CLASS_FM_TX | 1)
+
+#define V4L2_CID_RDS_TX_DEVIATION		(V4L2_CID_FM_TX_CLASS_BASE + 1)
+#define V4L2_CID_RDS_TX_PI			(V4L2_CID_FM_TX_CLASS_BASE + 2)
+#define V4L2_CID_RDS_TX_PTY			(V4L2_CID_FM_TX_CLASS_BASE + 3)
+#define V4L2_CID_RDS_TX_PS_NAME			(V4L2_CID_FM_TX_CLASS_BASE + 5)
+#define V4L2_CID_RDS_TX_RADIO_TEXT		(V4L2_CID_FM_TX_CLASS_BASE + 6)
+#define V4L2_CID_RDS_TX_MONO_STEREO		(V4L2_CID_FM_TX_CLASS_BASE + 7)
+#define V4L2_CID_RDS_TX_ARTIFICIAL_HEAD		(V4L2_CID_FM_TX_CLASS_BASE + 8)
+#define V4L2_CID_RDS_TX_COMPRESSED		(V4L2_CID_FM_TX_CLASS_BASE + 9)
+#define V4L2_CID_RDS_TX_DYNAMIC_PTY		(V4L2_CID_FM_TX_CLASS_BASE + 10)
+#define V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT	(V4L2_CID_FM_TX_CLASS_BASE + 11)
+#define V4L2_CID_RDS_TX_TRAFFIC_PROGRAM		(V4L2_CID_FM_TX_CLASS_BASE + 12)
+#define V4L2_CID_RDS_TX_MUSIC_SPEECH		(V4L2_CID_FM_TX_CLASS_BASE + 13)
+#define V4L2_CID_RDS_TX_ALT_FREQS_ENABLE	(V4L2_CID_FM_TX_CLASS_BASE + 14)
+#define V4L2_CID_RDS_TX_ALT_FREQS		(V4L2_CID_FM_TX_CLASS_BASE + 15)
+
+#define V4L2_CID_AUDIO_LIMITER_ENABLED		(V4L2_CID_FM_TX_CLASS_BASE + 64)
+#define V4L2_CID_AUDIO_LIMITER_RELEASE_TIME	(V4L2_CID_FM_TX_CLASS_BASE + 65)
+#define V4L2_CID_AUDIO_LIMITER_DEVIATION	(V4L2_CID_FM_TX_CLASS_BASE + 66)
+
+#define V4L2_CID_AUDIO_COMPRESSION_ENABLED	(V4L2_CID_FM_TX_CLASS_BASE + 80)
+#define V4L2_CID_AUDIO_COMPRESSION_GAIN		(V4L2_CID_FM_TX_CLASS_BASE + 81)
+#define V4L2_CID_AUDIO_COMPRESSION_THRESHOLD	(V4L2_CID_FM_TX_CLASS_BASE + 82)
+#define V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME	(V4L2_CID_FM_TX_CLASS_BASE + 83)
+#define V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME	(V4L2_CID_FM_TX_CLASS_BASE + 84)
+
+#define V4L2_CID_PILOT_TONE_ENABLED		(V4L2_CID_FM_TX_CLASS_BASE + 96)
+#define V4L2_CID_PILOT_TONE_DEVIATION		(V4L2_CID_FM_TX_CLASS_BASE + 97)
+#define V4L2_CID_PILOT_TONE_FREQUENCY		(V4L2_CID_FM_TX_CLASS_BASE + 98)
+
+#define V4L2_CID_TUNE_PREEMPHASIS		(V4L2_CID_FM_TX_CLASS_BASE + 112)
+enum v4l2_preemphasis {
+	V4L2_PREEMPHASIS_DISABLED	= 0,
+	V4L2_PREEMPHASIS_50_uS		= 1,
+	V4L2_PREEMPHASIS_75_uS		= 2,
+};
+#define V4L2_CID_TUNE_POWER_LEVEL		(V4L2_CID_FM_TX_CLASS_BASE + 113)
+#define V4L2_CID_TUNE_ANTENNA_CAPACITOR		(V4L2_CID_FM_TX_CLASS_BASE + 114)
+
+
+/* Flash and privacy (indicator) light controls */
+
+#define V4L2_CID_FLASH_CLASS_BASE		(V4L2_CTRL_CLASS_FLASH | 0x900)
+#define V4L2_CID_FLASH_CLASS			(V4L2_CTRL_CLASS_FLASH | 1)
+
+#define V4L2_CID_FLASH_LED_MODE			(V4L2_CID_FLASH_CLASS_BASE + 1)
+enum v4l2_flash_led_mode {
+	V4L2_FLASH_LED_MODE_NONE,
+	V4L2_FLASH_LED_MODE_FLASH,
+	V4L2_FLASH_LED_MODE_TORCH,
+};
+
+#define V4L2_CID_FLASH_STROBE_SOURCE		(V4L2_CID_FLASH_CLASS_BASE + 2)
+enum v4l2_flash_strobe_source {
+	V4L2_FLASH_STROBE_SOURCE_SOFTWARE,
+	V4L2_FLASH_STROBE_SOURCE_EXTERNAL,
+};
+
+#define V4L2_CID_FLASH_STROBE			(V4L2_CID_FLASH_CLASS_BASE + 3)
+#define V4L2_CID_FLASH_STROBE_STOP		(V4L2_CID_FLASH_CLASS_BASE + 4)
+#define V4L2_CID_FLASH_STROBE_STATUS		(V4L2_CID_FLASH_CLASS_BASE + 5)
+
+#define V4L2_CID_FLASH_TIMEOUT			(V4L2_CID_FLASH_CLASS_BASE + 6)
+#define V4L2_CID_FLASH_INTENSITY		(V4L2_CID_FLASH_CLASS_BASE + 7)
+#define V4L2_CID_FLASH_TORCH_INTENSITY		(V4L2_CID_FLASH_CLASS_BASE + 8)
+#define V4L2_CID_FLASH_INDICATOR_INTENSITY	(V4L2_CID_FLASH_CLASS_BASE + 9)
+
+#define V4L2_CID_FLASH_FAULT			(V4L2_CID_FLASH_CLASS_BASE + 10)
+#define V4L2_FLASH_FAULT_OVER_VOLTAGE		(1 << 0)
+#define V4L2_FLASH_FAULT_TIMEOUT		(1 << 1)
+#define V4L2_FLASH_FAULT_OVER_TEMPERATURE	(1 << 2)
+#define V4L2_FLASH_FAULT_SHORT_CIRCUIT		(1 << 3)
+#define V4L2_FLASH_FAULT_OVER_CURRENT		(1 << 4)
+#define V4L2_FLASH_FAULT_INDICATOR		(1 << 5)
+#define V4L2_FLASH_FAULT_UNDER_VOLTAGE		(1 << 6)
+#define V4L2_FLASH_FAULT_INPUT_VOLTAGE		(1 << 7)
+#define V4L2_FLASH_FAULT_LED_OVER_TEMPERATURE	(1 << 8)
+
+#define V4L2_CID_FLASH_CHARGE			(V4L2_CID_FLASH_CLASS_BASE + 11)
+#define V4L2_CID_FLASH_READY			(V4L2_CID_FLASH_CLASS_BASE + 12)
+
+
+/* JPEG-class control IDs */
+
+#define V4L2_CID_JPEG_CLASS_BASE		(V4L2_CTRL_CLASS_JPEG | 0x900)
+#define V4L2_CID_JPEG_CLASS			(V4L2_CTRL_CLASS_JPEG | 1)
+
+#define	V4L2_CID_JPEG_CHROMA_SUBSAMPLING	(V4L2_CID_JPEG_CLASS_BASE + 1)
+enum v4l2_jpeg_chroma_subsampling {
+	V4L2_JPEG_CHROMA_SUBSAMPLING_444	= 0,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_422	= 1,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_420	= 2,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_411	= 3,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_410	= 4,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY	= 5,
+};
+#define	V4L2_CID_JPEG_RESTART_INTERVAL		(V4L2_CID_JPEG_CLASS_BASE + 2)
+#define	V4L2_CID_JPEG_COMPRESSION_QUALITY	(V4L2_CID_JPEG_CLASS_BASE + 3)
+
+#define	V4L2_CID_JPEG_ACTIVE_MARKER		(V4L2_CID_JPEG_CLASS_BASE + 4)
+#define	V4L2_JPEG_ACTIVE_MARKER_APP0		(1 << 0)
+#define	V4L2_JPEG_ACTIVE_MARKER_APP1		(1 << 1)
+#define	V4L2_JPEG_ACTIVE_MARKER_COM		(1 << 16)
+#define	V4L2_JPEG_ACTIVE_MARKER_DQT		(1 << 17)
+#define	V4L2_JPEG_ACTIVE_MARKER_DHT		(1 << 18)
+
+
+/* Image source controls */
+#define V4L2_CID_IMAGE_SOURCE_CLASS_BASE	(V4L2_CTRL_CLASS_IMAGE_SOURCE | 0x900)
+#define V4L2_CID_IMAGE_SOURCE_CLASS		(V4L2_CTRL_CLASS_IMAGE_SOURCE | 1)
+
+#define V4L2_CID_VBLANK				(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 1)
+#define V4L2_CID_HBLANK				(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 2)
+#define V4L2_CID_ANALOGUE_GAIN			(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 3)
+#define V4L2_CID_TEST_PATTERN_RED		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 4)
+#define V4L2_CID_TEST_PATTERN_GREENR		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 5)
+#define V4L2_CID_TEST_PATTERN_BLUE		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 6)
+#define V4L2_CID_TEST_PATTERN_GREENB		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7)
+
+
+/* Image processing controls */
+
+#define V4L2_CID_IMAGE_PROC_CLASS_BASE		(V4L2_CTRL_CLASS_IMAGE_PROC | 0x900)
+#define V4L2_CID_IMAGE_PROC_CLASS		(V4L2_CTRL_CLASS_IMAGE_PROC | 1)
+
+#define V4L2_CID_LINK_FREQ			(V4L2_CID_IMAGE_PROC_CLASS_BASE + 1)
+#define V4L2_CID_PIXEL_RATE			(V4L2_CID_IMAGE_PROC_CLASS_BASE + 2)
+#define V4L2_CID_TEST_PATTERN			(V4L2_CID_IMAGE_PROC_CLASS_BASE + 3)
+#define V4L2_CID_DEINTERLACING_MODE		(V4L2_CID_IMAGE_PROC_CLASS_BASE + 4)
+#define V4L2_CID_DIGITAL_GAIN			(V4L2_CID_IMAGE_PROC_CLASS_BASE + 5)
+
+/*  DV-class control IDs defined by V4L2 */
+#define V4L2_CID_DV_CLASS_BASE			(V4L2_CTRL_CLASS_DV | 0x900)
+#define V4L2_CID_DV_CLASS			(V4L2_CTRL_CLASS_DV | 1)
+
+#define	V4L2_CID_DV_TX_HOTPLUG			(V4L2_CID_DV_CLASS_BASE + 1)
+#define	V4L2_CID_DV_TX_RXSENSE			(V4L2_CID_DV_CLASS_BASE + 2)
+#define	V4L2_CID_DV_TX_EDID_PRESENT		(V4L2_CID_DV_CLASS_BASE + 3)
+#define	V4L2_CID_DV_TX_MODE			(V4L2_CID_DV_CLASS_BASE + 4)
+enum v4l2_dv_tx_mode {
+	V4L2_DV_TX_MODE_DVI_D	= 0,
+	V4L2_DV_TX_MODE_HDMI	= 1,
+};
+#define V4L2_CID_DV_TX_RGB_RANGE		(V4L2_CID_DV_CLASS_BASE + 5)
+enum v4l2_dv_rgb_range {
+	V4L2_DV_RGB_RANGE_AUTO	  = 0,
+	V4L2_DV_RGB_RANGE_LIMITED = 1,
+	V4L2_DV_RGB_RANGE_FULL	  = 2,
+};
+
+#define V4L2_CID_DV_TX_IT_CONTENT_TYPE		(V4L2_CID_DV_CLASS_BASE + 6)
+enum v4l2_dv_it_content_type {
+	V4L2_DV_IT_CONTENT_TYPE_GRAPHICS  = 0,
+	V4L2_DV_IT_CONTENT_TYPE_PHOTO	  = 1,
+	V4L2_DV_IT_CONTENT_TYPE_CINEMA	  = 2,
+	V4L2_DV_IT_CONTENT_TYPE_GAME	  = 3,
+	V4L2_DV_IT_CONTENT_TYPE_NO_ITC	  = 4,
+};
+
+#define	V4L2_CID_DV_RX_POWER_PRESENT		(V4L2_CID_DV_CLASS_BASE + 100)
+#define V4L2_CID_DV_RX_RGB_RANGE		(V4L2_CID_DV_CLASS_BASE + 101)
+#define V4L2_CID_DV_RX_IT_CONTENT_TYPE		(V4L2_CID_DV_CLASS_BASE + 102)
+
+#define V4L2_CID_FM_RX_CLASS_BASE		(V4L2_CTRL_CLASS_FM_RX | 0x900)
+#define V4L2_CID_FM_RX_CLASS			(V4L2_CTRL_CLASS_FM_RX | 1)
+
+#define V4L2_CID_TUNE_DEEMPHASIS		(V4L2_CID_FM_RX_CLASS_BASE + 1)
+enum v4l2_deemphasis {
+	V4L2_DEEMPHASIS_DISABLED	= V4L2_PREEMPHASIS_DISABLED,
+	V4L2_DEEMPHASIS_50_uS		= V4L2_PREEMPHASIS_50_uS,
+	V4L2_DEEMPHASIS_75_uS		= V4L2_PREEMPHASIS_75_uS,
+};
+
+#define V4L2_CID_RDS_RECEPTION			(V4L2_CID_FM_RX_CLASS_BASE + 2)
+#define V4L2_CID_RDS_RX_PTY			(V4L2_CID_FM_RX_CLASS_BASE + 3)
+#define V4L2_CID_RDS_RX_PS_NAME			(V4L2_CID_FM_RX_CLASS_BASE + 4)
+#define V4L2_CID_RDS_RX_RADIO_TEXT		(V4L2_CID_FM_RX_CLASS_BASE + 5)
+#define V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT	(V4L2_CID_FM_RX_CLASS_BASE + 6)
+#define V4L2_CID_RDS_RX_TRAFFIC_PROGRAM		(V4L2_CID_FM_RX_CLASS_BASE + 7)
+#define V4L2_CID_RDS_RX_MUSIC_SPEECH		(V4L2_CID_FM_RX_CLASS_BASE + 8)
+
+#define V4L2_CID_RF_TUNER_CLASS_BASE		(V4L2_CTRL_CLASS_RF_TUNER | 0x900)
+#define V4L2_CID_RF_TUNER_CLASS			(V4L2_CTRL_CLASS_RF_TUNER | 1)
+
+#define V4L2_CID_RF_TUNER_BANDWIDTH_AUTO	(V4L2_CID_RF_TUNER_CLASS_BASE + 11)
+#define V4L2_CID_RF_TUNER_BANDWIDTH		(V4L2_CID_RF_TUNER_CLASS_BASE + 12)
+#define V4L2_CID_RF_TUNER_RF_GAIN		(V4L2_CID_RF_TUNER_CLASS_BASE + 32)
+#define V4L2_CID_RF_TUNER_LNA_GAIN_AUTO		(V4L2_CID_RF_TUNER_CLASS_BASE + 41)
+#define V4L2_CID_RF_TUNER_LNA_GAIN		(V4L2_CID_RF_TUNER_CLASS_BASE + 42)
+#define V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO	(V4L2_CID_RF_TUNER_CLASS_BASE + 51)
+#define V4L2_CID_RF_TUNER_MIXER_GAIN		(V4L2_CID_RF_TUNER_CLASS_BASE + 52)
+#define V4L2_CID_RF_TUNER_IF_GAIN_AUTO		(V4L2_CID_RF_TUNER_CLASS_BASE + 61)
+#define V4L2_CID_RF_TUNER_IF_GAIN		(V4L2_CID_RF_TUNER_CLASS_BASE + 62)
+#define V4L2_CID_RF_TUNER_PLL_LOCK			(V4L2_CID_RF_TUNER_CLASS_BASE + 91)
+
+
+/*  Detection-class control IDs defined by V4L2 */
+#define V4L2_CID_DETECT_CLASS_BASE		(V4L2_CTRL_CLASS_DETECT | 0x900)
+#define V4L2_CID_DETECT_CLASS			(V4L2_CTRL_CLASS_DETECT | 1)
+
+#define V4L2_CID_DETECT_MD_MODE			(V4L2_CID_DETECT_CLASS_BASE + 1)
+enum v4l2_detect_md_mode {
+	V4L2_DETECT_MD_MODE_DISABLED		= 0,
+	V4L2_DETECT_MD_MODE_GLOBAL		= 1,
+	V4L2_DETECT_MD_MODE_THRESHOLD_GRID	= 2,
+	V4L2_DETECT_MD_MODE_REGION_GRID		= 3,
+};
+#define V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD	(V4L2_CID_DETECT_CLASS_BASE + 2)
+#define V4L2_CID_DETECT_MD_THRESHOLD_GRID	(V4L2_CID_DETECT_CLASS_BASE + 3)
+#define V4L2_CID_DETECT_MD_REGION_GRID		(V4L2_CID_DETECT_CLASS_BASE + 4)
+
+#endif
diff --git a/sys/v4l2/ext/videodev2.h b/sys/v4l2/ext/videodev2.h
new file mode 100644
index 0000000..59e1f3d
--- /dev/null
+++ b/sys/v4l2/ext/videodev2.h
@@ -0,0 +1,2398 @@
+/*
+ *  Video for Linux Two header file
+ *
+ *  Copyright (C) 1999-2012 the contributors
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  Alternatively you can redistribute this file under the terms of the
+ *  BSD license as stated below:
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *  3. The names of its contributors may not be used to endorse or promote
+ *     products derived from this software without specific prior written
+ *     permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *	Header file for v4l or V4L2 drivers and applications
+ * with public API.
+ * All kernel-specific stuff were moved to media/v4l2-dev.h, so
+ * no #if __KERNEL tests are allowed here
+ *
+ *	See https://linuxtv.org for more info
+ *
+ *	Author: Bill Dirks <bill@thedirks.org>
+ *		Justin Schoeman
+ *              Hans Verkuil <hverkuil@xs4all.nl>
+ *		et al.
+ */
+#ifndef _UAPI__LINUX_VIDEODEV2_H
+#define _UAPI__LINUX_VIDEODEV2_H
+
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include "ext/types-compat.h"
+#include "ext/v4l2-common.h"
+#include "ext/v4l2-controls.h"
+
+/*
+ * Common stuff for both V4L1 and V4L2
+ * Moved from videodev.h
+ */
+#define VIDEO_MAX_FRAME               32
+#define VIDEO_MAX_PLANES               8
+
+/*
+ *	M I S C E L L A N E O U S
+ */
+
+/*  Four-character-code (FOURCC) */
+#define v4l2_fourcc(a, b, c, d)\
+	((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24))
+#define v4l2_fourcc_be(a, b, c, d)	(v4l2_fourcc(a, b, c, d) | (1 << 31))
+
+/*
+ *	E N U M S
+ */
+enum v4l2_field {
+	V4L2_FIELD_ANY           = 0, /* driver can choose from none,
+					 top, bottom, interlaced
+					 depending on whatever it thinks
+					 is approximate ... */
+	V4L2_FIELD_NONE          = 1, /* this device has no fields ... */
+	V4L2_FIELD_TOP           = 2, /* top field only */
+	V4L2_FIELD_BOTTOM        = 3, /* bottom field only */
+	V4L2_FIELD_INTERLACED    = 4, /* both fields interlaced */
+	V4L2_FIELD_SEQ_TB        = 5, /* both fields sequential into one
+					 buffer, top-bottom order */
+	V4L2_FIELD_SEQ_BT        = 6, /* same as above + bottom-top order */
+	V4L2_FIELD_ALTERNATE     = 7, /* both fields alternating into
+					 separate buffers */
+	V4L2_FIELD_INTERLACED_TB = 8, /* both fields interlaced, top field
+					 first and the top field is
+					 transmitted first */
+	V4L2_FIELD_INTERLACED_BT = 9, /* both fields interlaced, top field
+					 first and the bottom field is
+					 transmitted first */
+};
+#define V4L2_FIELD_HAS_TOP(field)	\
+	((field) == V4L2_FIELD_TOP 	||\
+	 (field) == V4L2_FIELD_INTERLACED ||\
+	 (field) == V4L2_FIELD_INTERLACED_TB ||\
+	 (field) == V4L2_FIELD_INTERLACED_BT ||\
+	 (field) == V4L2_FIELD_SEQ_TB	||\
+	 (field) == V4L2_FIELD_SEQ_BT)
+#define V4L2_FIELD_HAS_BOTTOM(field)	\
+	((field) == V4L2_FIELD_BOTTOM 	||\
+	 (field) == V4L2_FIELD_INTERLACED ||\
+	 (field) == V4L2_FIELD_INTERLACED_TB ||\
+	 (field) == V4L2_FIELD_INTERLACED_BT ||\
+	 (field) == V4L2_FIELD_SEQ_TB	||\
+	 (field) == V4L2_FIELD_SEQ_BT)
+#define V4L2_FIELD_HAS_BOTH(field)	\
+	((field) == V4L2_FIELD_INTERLACED ||\
+	 (field) == V4L2_FIELD_INTERLACED_TB ||\
+	 (field) == V4L2_FIELD_INTERLACED_BT ||\
+	 (field) == V4L2_FIELD_SEQ_TB ||\
+	 (field) == V4L2_FIELD_SEQ_BT)
+#define V4L2_FIELD_HAS_T_OR_B(field)	\
+	((field) == V4L2_FIELD_BOTTOM ||\
+	 (field) == V4L2_FIELD_TOP ||\
+	 (field) == V4L2_FIELD_ALTERNATE)
+
+enum v4l2_buf_type {
+	V4L2_BUF_TYPE_VIDEO_CAPTURE        = 1,
+	V4L2_BUF_TYPE_VIDEO_OUTPUT         = 2,
+	V4L2_BUF_TYPE_VIDEO_OVERLAY        = 3,
+	V4L2_BUF_TYPE_VBI_CAPTURE          = 4,
+	V4L2_BUF_TYPE_VBI_OUTPUT           = 5,
+	V4L2_BUF_TYPE_SLICED_VBI_CAPTURE   = 6,
+	V4L2_BUF_TYPE_SLICED_VBI_OUTPUT    = 7,
+	V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
+	V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9,
+	V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE  = 10,
+	V4L2_BUF_TYPE_SDR_CAPTURE          = 11,
+	V4L2_BUF_TYPE_SDR_OUTPUT           = 12,
+	V4L2_BUF_TYPE_META_CAPTURE         = 13,
+	/* Deprecated, do not use */
+	V4L2_BUF_TYPE_PRIVATE              = 0x80,
+};
+
+#define V4L2_TYPE_IS_MULTIPLANAR(type)			\
+	((type) == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE	\
+	 || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+
+#define V4L2_TYPE_IS_OUTPUT(type)				\
+	((type) == V4L2_BUF_TYPE_VIDEO_OUTPUT			\
+	 || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE		\
+	 || (type) == V4L2_BUF_TYPE_VIDEO_OVERLAY		\
+	 || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY	\
+	 || (type) == V4L2_BUF_TYPE_VBI_OUTPUT			\
+	 || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT		\
+	 || (type) == V4L2_BUF_TYPE_SDR_OUTPUT)
+
+enum v4l2_tuner_type {
+	V4L2_TUNER_RADIO	     = 1,
+	V4L2_TUNER_ANALOG_TV	     = 2,
+	V4L2_TUNER_DIGITAL_TV	     = 3,
+	V4L2_TUNER_SDR               = 4,
+	V4L2_TUNER_RF                = 5,
+};
+
+/* Deprecated, do not use */
+#define V4L2_TUNER_ADC  V4L2_TUNER_SDR
+
+enum v4l2_memory {
+	V4L2_MEMORY_MMAP             = 1,
+	V4L2_MEMORY_USERPTR          = 2,
+	V4L2_MEMORY_OVERLAY          = 3,
+	V4L2_MEMORY_DMABUF           = 4,
+};
+
+/* see also http://vektor.theorem.ca/graphics/ycbcr/ */
+enum v4l2_colorspace {
+	/*
+	 * Default colorspace, i.e. let the driver figure it out.
+	 * Can only be used with video capture.
+	 */
+	V4L2_COLORSPACE_DEFAULT       = 0,
+
+	/* SMPTE 170M: used for broadcast NTSC/PAL SDTV */
+	V4L2_COLORSPACE_SMPTE170M     = 1,
+
+	/* Obsolete pre-1998 SMPTE 240M HDTV standard, superseded by Rec 709 */
+	V4L2_COLORSPACE_SMPTE240M     = 2,
+
+	/* Rec.709: used for HDTV */
+	V4L2_COLORSPACE_REC709        = 3,
+
+	/*
+	 * Deprecated, do not use. No driver will ever return this. This was
+	 * based on a misunderstanding of the bt878 datasheet.
+	 */
+	V4L2_COLORSPACE_BT878         = 4,
+
+	/*
+	 * NTSC 1953 colorspace. This only makes sense when dealing with
+	 * really, really old NTSC recordings. Superseded by SMPTE 170M.
+	 */
+	V4L2_COLORSPACE_470_SYSTEM_M  = 5,
+
+	/*
+	 * EBU Tech 3213 PAL/SECAM colorspace. This only makes sense when
+	 * dealing with really old PAL/SECAM recordings. Superseded by
+	 * SMPTE 170M.
+	 */
+	V4L2_COLORSPACE_470_SYSTEM_BG = 6,
+
+	/*
+	 * Effectively shorthand for V4L2_COLORSPACE_SRGB, V4L2_YCBCR_ENC_601
+	 * and V4L2_QUANTIZATION_FULL_RANGE. To be used for (Motion-)JPEG.
+	 */
+	V4L2_COLORSPACE_JPEG          = 7,
+
+	/* For RGB colorspaces such as produces by most webcams. */
+	V4L2_COLORSPACE_SRGB          = 8,
+
+	/* AdobeRGB colorspace */
+	V4L2_COLORSPACE_ADOBERGB      = 9,
+
+	/* BT.2020 colorspace, used for UHDTV. */
+	V4L2_COLORSPACE_BT2020        = 10,
+
+	/* Raw colorspace: for RAW unprocessed images */
+	V4L2_COLORSPACE_RAW           = 11,
+
+	/* DCI-P3 colorspace, used by cinema projectors */
+	V4L2_COLORSPACE_DCI_P3        = 12,
+};
+
+/*
+ * Determine how COLORSPACE_DEFAULT should map to a proper colorspace.
+ * This depends on whether this is a SDTV image (use SMPTE 170M), an
+ * HDTV image (use Rec. 709), or something else (use sRGB).
+ */
+#define V4L2_MAP_COLORSPACE_DEFAULT(is_sdtv, is_hdtv) \
+	((is_sdtv) ? V4L2_COLORSPACE_SMPTE170M : \
+	 ((is_hdtv) ? V4L2_COLORSPACE_REC709 : V4L2_COLORSPACE_SRGB))
+
+enum v4l2_xfer_func {
+	/*
+	 * Mapping of V4L2_XFER_FUNC_DEFAULT to actual transfer functions
+	 * for the various colorspaces:
+	 *
+	 * V4L2_COLORSPACE_SMPTE170M, V4L2_COLORSPACE_470_SYSTEM_M,
+	 * V4L2_COLORSPACE_470_SYSTEM_BG, V4L2_COLORSPACE_REC709 and
+	 * V4L2_COLORSPACE_BT2020: V4L2_XFER_FUNC_709
+	 *
+	 * V4L2_COLORSPACE_SRGB, V4L2_COLORSPACE_JPEG: V4L2_XFER_FUNC_SRGB
+	 *
+	 * V4L2_COLORSPACE_ADOBERGB: V4L2_XFER_FUNC_ADOBERGB
+	 *
+	 * V4L2_COLORSPACE_SMPTE240M: V4L2_XFER_FUNC_SMPTE240M
+	 *
+	 * V4L2_COLORSPACE_RAW: V4L2_XFER_FUNC_NONE
+	 *
+	 * V4L2_COLORSPACE_DCI_P3: V4L2_XFER_FUNC_DCI_P3
+	 */
+	V4L2_XFER_FUNC_DEFAULT     = 0,
+	V4L2_XFER_FUNC_709         = 1,
+	V4L2_XFER_FUNC_SRGB        = 2,
+	V4L2_XFER_FUNC_ADOBERGB    = 3,
+	V4L2_XFER_FUNC_SMPTE240M   = 4,
+	V4L2_XFER_FUNC_NONE        = 5,
+	V4L2_XFER_FUNC_DCI_P3      = 6,
+	V4L2_XFER_FUNC_SMPTE2084   = 7,
+};
+
+/*
+ * Determine how XFER_FUNC_DEFAULT should map to a proper transfer function.
+ * This depends on the colorspace.
+ */
+#define V4L2_MAP_XFER_FUNC_DEFAULT(colsp) \
+	((colsp) == V4L2_COLORSPACE_ADOBERGB ? V4L2_XFER_FUNC_ADOBERGB : \
+	 ((colsp) == V4L2_COLORSPACE_SMPTE240M ? V4L2_XFER_FUNC_SMPTE240M : \
+	  ((colsp) == V4L2_COLORSPACE_DCI_P3 ? V4L2_XFER_FUNC_DCI_P3 : \
+	   ((colsp) == V4L2_COLORSPACE_RAW ? V4L2_XFER_FUNC_NONE : \
+	    ((colsp) == V4L2_COLORSPACE_SRGB || (colsp) == V4L2_COLORSPACE_JPEG ? \
+	     V4L2_XFER_FUNC_SRGB : V4L2_XFER_FUNC_709)))))
+
+enum v4l2_ycbcr_encoding {
+	/*
+	 * Mapping of V4L2_YCBCR_ENC_DEFAULT to actual encodings for the
+	 * various colorspaces:
+	 *
+	 * V4L2_COLORSPACE_SMPTE170M, V4L2_COLORSPACE_470_SYSTEM_M,
+	 * V4L2_COLORSPACE_470_SYSTEM_BG, V4L2_COLORSPACE_SRGB,
+	 * V4L2_COLORSPACE_ADOBERGB and V4L2_COLORSPACE_JPEG: V4L2_YCBCR_ENC_601
+	 *
+	 * V4L2_COLORSPACE_REC709 and V4L2_COLORSPACE_DCI_P3: V4L2_YCBCR_ENC_709
+	 *
+	 * V4L2_COLORSPACE_BT2020: V4L2_YCBCR_ENC_BT2020
+	 *
+	 * V4L2_COLORSPACE_SMPTE240M: V4L2_YCBCR_ENC_SMPTE240M
+	 */
+	V4L2_YCBCR_ENC_DEFAULT        = 0,
+
+	/* ITU-R 601 -- SDTV */
+	V4L2_YCBCR_ENC_601            = 1,
+
+	/* Rec. 709 -- HDTV */
+	V4L2_YCBCR_ENC_709            = 2,
+
+	/* ITU-R 601/EN 61966-2-4 Extended Gamut -- SDTV */
+	V4L2_YCBCR_ENC_XV601          = 3,
+
+	/* Rec. 709/EN 61966-2-4 Extended Gamut -- HDTV */
+	V4L2_YCBCR_ENC_XV709          = 4,
+
+#ifndef __KERNEL__
+	/*
+	 * sYCC (Y'CbCr encoding of sRGB), identical to ENC_601. It was added
+	 * originally due to a misunderstanding of the sYCC standard. It should
+	 * not be used, instead use V4L2_YCBCR_ENC_601.
+	 */
+	V4L2_YCBCR_ENC_SYCC           = 5,
+#endif
+
+	/* BT.2020 Non-constant Luminance Y'CbCr */
+	V4L2_YCBCR_ENC_BT2020         = 6,
+
+	/* BT.2020 Constant Luminance Y'CbcCrc */
+	V4L2_YCBCR_ENC_BT2020_CONST_LUM = 7,
+
+	/* SMPTE 240M -- Obsolete HDTV */
+	V4L2_YCBCR_ENC_SMPTE240M      = 8,
+};
+
+/*
+ * enum v4l2_hsv_encoding values should not collide with the ones from
+ * enum v4l2_ycbcr_encoding.
+ */
+enum v4l2_hsv_encoding {
+
+	/* Hue mapped to 0 - 179 */
+	V4L2_HSV_ENC_180		= 128,
+
+	/* Hue mapped to 0-255 */
+	V4L2_HSV_ENC_256		= 129,
+};
+
+/*
+ * Determine how YCBCR_ENC_DEFAULT should map to a proper Y'CbCr encoding.
+ * This depends on the colorspace.
+ */
+#define V4L2_MAP_YCBCR_ENC_DEFAULT(colsp) \
+	(((colsp) == V4L2_COLORSPACE_REC709 || \
+	  (colsp) == V4L2_COLORSPACE_DCI_P3) ? V4L2_YCBCR_ENC_709 : \
+	 ((colsp) == V4L2_COLORSPACE_BT2020 ? V4L2_YCBCR_ENC_BT2020 : \
+	  ((colsp) == V4L2_COLORSPACE_SMPTE240M ? V4L2_YCBCR_ENC_SMPTE240M : \
+	   V4L2_YCBCR_ENC_601)))
+
+enum v4l2_quantization {
+	/*
+	 * The default for R'G'B' quantization is always full range, except
+	 * for the BT2020 colorspace. For Y'CbCr the quantization is always
+	 * limited range, except for COLORSPACE_JPEG: this is full range.
+	 */
+	V4L2_QUANTIZATION_DEFAULT     = 0,
+	V4L2_QUANTIZATION_FULL_RANGE  = 1,
+	V4L2_QUANTIZATION_LIM_RANGE   = 2,
+};
+
+/*
+ * Determine how QUANTIZATION_DEFAULT should map to a proper quantization.
+ * This depends on whether the image is RGB or not, the colorspace and the
+ * Y'CbCr encoding.
+ */
+#define V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb_or_hsv, colsp, ycbcr_enc) \
+	(((is_rgb_or_hsv) && (colsp) == V4L2_COLORSPACE_BT2020) ? \
+	 V4L2_QUANTIZATION_LIM_RANGE : \
+	 (((is_rgb_or_hsv) || (colsp) == V4L2_COLORSPACE_JPEG) ? \
+	 V4L2_QUANTIZATION_FULL_RANGE : V4L2_QUANTIZATION_LIM_RANGE))
+
+enum v4l2_priority {
+	V4L2_PRIORITY_UNSET       = 0,  /* not initialized */
+	V4L2_PRIORITY_BACKGROUND  = 1,
+	V4L2_PRIORITY_INTERACTIVE = 2,
+	V4L2_PRIORITY_RECORD      = 3,
+	V4L2_PRIORITY_DEFAULT     = V4L2_PRIORITY_INTERACTIVE,
+};
+
+struct v4l2_rect {
+	__s32   left;
+	__s32   top;
+	__u32   width;
+	__u32   height;
+};
+
+struct v4l2_fract {
+	__u32   numerator;
+	__u32   denominator;
+};
+
+/**
+  * struct v4l2_capability - Describes V4L2 device caps returned by VIDIOC_QUERYCAP
+  *
+  * @driver:	   name of the driver module (e.g. "bttv")
+  * @card:	   name of the card (e.g. "Hauppauge WinTV")
+  * @bus_info:	   name of the bus (e.g. "PCI:" + pci_name(pci_dev) )
+  * @version:	   KERNEL_VERSION
+  * @capabilities: capabilities of the physical device as a whole
+  * @device_caps:  capabilities accessed via this particular device (node)
+  * @reserved:	   reserved fields for future extensions
+  */
+struct v4l2_capability {
+	__u8	driver[16];
+	__u8	card[32];
+	__u8	bus_info[32];
+	__u32   version;
+	__u32	capabilities;
+	__u32	device_caps;
+	__u32	reserved[3];
+};
+
+/* Values for 'capabilities' field */
+#define V4L2_CAP_VIDEO_CAPTURE		0x00000001  /* Is a video capture device */
+#define V4L2_CAP_VIDEO_OUTPUT		0x00000002  /* Is a video output device */
+#define V4L2_CAP_VIDEO_OVERLAY		0x00000004  /* Can do video overlay */
+#define V4L2_CAP_VBI_CAPTURE		0x00000010  /* Is a raw VBI capture device */
+#define V4L2_CAP_VBI_OUTPUT		0x00000020  /* Is a raw VBI output device */
+#define V4L2_CAP_SLICED_VBI_CAPTURE	0x00000040  /* Is a sliced VBI capture device */
+#define V4L2_CAP_SLICED_VBI_OUTPUT	0x00000080  /* Is a sliced VBI output device */
+#define V4L2_CAP_RDS_CAPTURE		0x00000100  /* RDS data capture */
+#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY	0x00000200  /* Can do video output overlay */
+#define V4L2_CAP_HW_FREQ_SEEK		0x00000400  /* Can do hardware frequency seek  */
+#define V4L2_CAP_RDS_OUTPUT		0x00000800  /* Is an RDS encoder */
+
+/* Is a video capture device that supports multiplanar formats */
+#define V4L2_CAP_VIDEO_CAPTURE_MPLANE	0x00001000
+/* Is a video output device that supports multiplanar formats */
+#define V4L2_CAP_VIDEO_OUTPUT_MPLANE	0x00002000
+/* Is a video mem-to-mem device that supports multiplanar formats */
+#define V4L2_CAP_VIDEO_M2M_MPLANE	0x00004000
+/* Is a video mem-to-mem device */
+#define V4L2_CAP_VIDEO_M2M		0x00008000
+
+#define V4L2_CAP_TUNER			0x00010000  /* has a tuner */
+#define V4L2_CAP_AUDIO			0x00020000  /* has audio support */
+#define V4L2_CAP_RADIO			0x00040000  /* is a radio device */
+#define V4L2_CAP_MODULATOR		0x00080000  /* has a modulator */
+
+#define V4L2_CAP_SDR_CAPTURE		0x00100000  /* Is a SDR capture device */
+#define V4L2_CAP_EXT_PIX_FORMAT		0x00200000  /* Supports the extended pixel format */
+#define V4L2_CAP_SDR_OUTPUT		0x00400000  /* Is a SDR output device */
+#define V4L2_CAP_META_CAPTURE		0x00800000  /* Is a metadata capture device */
+
+#define V4L2_CAP_READWRITE              0x01000000  /* read/write systemcalls */
+#define V4L2_CAP_ASYNCIO                0x02000000  /* async I/O */
+#define V4L2_CAP_STREAMING              0x04000000  /* streaming I/O ioctls */
+
+#define V4L2_CAP_TOUCH                  0x10000000  /* Is a touch device */
+
+#define V4L2_CAP_DEVICE_CAPS            0x80000000  /* sets device capabilities field */
+
+/*
+ *	V I D E O   I M A G E   F O R M A T
+ */
+struct v4l2_pix_format {
+	__u32         		width;
+	__u32			height;
+	__u32			pixelformat;
+	__u32			field;		/* enum v4l2_field */
+	__u32            	bytesperline;	/* for padding, zero if unused */
+	__u32          		sizeimage;
+	__u32			colorspace;	/* enum v4l2_colorspace */
+	__u32			priv;		/* private data, depends on pixelformat */
+	__u32			flags;		/* format flags (V4L2_PIX_FMT_FLAG_*) */
+	union {
+		/* enum v4l2_ycbcr_encoding */
+		__u32			ycbcr_enc;
+		/* enum v4l2_hsv_encoding */
+		__u32			hsv_enc;
+	};
+	__u32			quantization;	/* enum v4l2_quantization */
+	__u32			xfer_func;	/* enum v4l2_xfer_func */
+};
+
+/*      Pixel format         FOURCC                          depth  Description  */
+
+/* RGB formats */
+#define V4L2_PIX_FMT_RGB332  v4l2_fourcc('R', 'G', 'B', '1') /*  8  RGB-3-3-2     */
+#define V4L2_PIX_FMT_RGB444  v4l2_fourcc('R', '4', '4', '4') /* 16  xxxxrrrr ggggbbbb */
+#define V4L2_PIX_FMT_ARGB444 v4l2_fourcc('A', 'R', '1', '2') /* 16  aaaarrrr ggggbbbb */
+#define V4L2_PIX_FMT_XRGB444 v4l2_fourcc('X', 'R', '1', '2') /* 16  xxxxrrrr ggggbbbb */
+#define V4L2_PIX_FMT_RGB555  v4l2_fourcc('R', 'G', 'B', 'O') /* 16  RGB-5-5-5     */
+#define V4L2_PIX_FMT_ARGB555 v4l2_fourcc('A', 'R', '1', '5') /* 16  ARGB-1-5-5-5  */
+#define V4L2_PIX_FMT_XRGB555 v4l2_fourcc('X', 'R', '1', '5') /* 16  XRGB-1-5-5-5  */
+#define V4L2_PIX_FMT_RGB565  v4l2_fourcc('R', 'G', 'B', 'P') /* 16  RGB-5-6-5     */
+#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16  RGB-5-5-5 BE  */
+#define V4L2_PIX_FMT_ARGB555X v4l2_fourcc_be('A', 'R', '1', '5') /* 16  ARGB-5-5-5 BE */
+#define V4L2_PIX_FMT_XRGB555X v4l2_fourcc_be('X', 'R', '1', '5') /* 16  XRGB-5-5-5 BE */
+#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16  RGB-5-6-5 BE  */
+#define V4L2_PIX_FMT_BGR666  v4l2_fourcc('B', 'G', 'R', 'H') /* 18  BGR-6-6-6	  */
+#define V4L2_PIX_FMT_BGR24   v4l2_fourcc('B', 'G', 'R', '3') /* 24  BGR-8-8-8     */
+#define V4L2_PIX_FMT_RGB24   v4l2_fourcc('R', 'G', 'B', '3') /* 24  RGB-8-8-8     */
+#define V4L2_PIX_FMT_BGR32   v4l2_fourcc('B', 'G', 'R', '4') /* 32  BGR-8-8-8-8   */
+#define V4L2_PIX_FMT_ABGR32  v4l2_fourcc('A', 'R', '2', '4') /* 32  BGRA-8-8-8-8  */
+#define V4L2_PIX_FMT_XBGR32  v4l2_fourcc('X', 'R', '2', '4') /* 32  BGRX-8-8-8-8  */
+#define V4L2_PIX_FMT_RGB32   v4l2_fourcc('R', 'G', 'B', '4') /* 32  RGB-8-8-8-8   */
+#define V4L2_PIX_FMT_ARGB32  v4l2_fourcc('B', 'A', '2', '4') /* 32  ARGB-8-8-8-8  */
+#define V4L2_PIX_FMT_XRGB32  v4l2_fourcc('B', 'X', '2', '4') /* 32  XRGB-8-8-8-8  */
+
+/* Grey formats */
+#define V4L2_PIX_FMT_GREY    v4l2_fourcc('G', 'R', 'E', 'Y') /*  8  Greyscale     */
+#define V4L2_PIX_FMT_Y4      v4l2_fourcc('Y', '0', '4', ' ') /*  4  Greyscale     */
+#define V4L2_PIX_FMT_Y6      v4l2_fourcc('Y', '0', '6', ' ') /*  6  Greyscale     */
+#define V4L2_PIX_FMT_Y10     v4l2_fourcc('Y', '1', '0', ' ') /* 10  Greyscale     */
+#define V4L2_PIX_FMT_Y12     v4l2_fourcc('Y', '1', '2', ' ') /* 12  Greyscale     */
+#define V4L2_PIX_FMT_Y16     v4l2_fourcc('Y', '1', '6', ' ') /* 16  Greyscale     */
+#define V4L2_PIX_FMT_Y16_BE  v4l2_fourcc_be('Y', '1', '6', ' ') /* 16  Greyscale BE  */
+
+/* Grey bit-packed formats */
+#define V4L2_PIX_FMT_Y10BPACK    v4l2_fourcc('Y', '1', '0', 'B') /* 10  Greyscale bit-packed */
+
+/* Palette formats */
+#define V4L2_PIX_FMT_PAL8    v4l2_fourcc('P', 'A', 'L', '8') /*  8  8-bit palette */
+
+/* Chrominance formats */
+#define V4L2_PIX_FMT_UV8     v4l2_fourcc('U', 'V', '8', ' ') /*  8  UV 4:4 */
+
+/* Luminance+Chrominance formats */
+#define V4L2_PIX_FMT_YUYV    v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_YYUV    v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_YVYU    v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
+#define V4L2_PIX_FMT_UYVY    v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_VYUY    v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_Y41P    v4l2_fourcc('Y', '4', '1', 'P') /* 12  YUV 4:1:1     */
+#define V4L2_PIX_FMT_YUV444  v4l2_fourcc('Y', '4', '4', '4') /* 16  xxxxyyyy uuuuvvvv */
+#define V4L2_PIX_FMT_YUV555  v4l2_fourcc('Y', 'U', 'V', 'O') /* 16  YUV-5-5-5     */
+#define V4L2_PIX_FMT_YUV565  v4l2_fourcc('Y', 'U', 'V', 'P') /* 16  YUV-5-6-5     */
+#define V4L2_PIX_FMT_YUV32   v4l2_fourcc('Y', 'U', 'V', '4') /* 32  YUV-8-8-8-8   */
+#define V4L2_PIX_FMT_HI240   v4l2_fourcc('H', 'I', '2', '4') /*  8  8-bit color   */
+#define V4L2_PIX_FMT_HM12    v4l2_fourcc('H', 'M', '1', '2') /*  8  YUV 4:2:0 16x16 macroblocks */
+#define V4L2_PIX_FMT_M420    v4l2_fourcc('M', '4', '2', '0') /* 12  YUV 4:2:0 2 lines y, 1 line uv interleaved */
+
+/* two planes -- one Y, one Cr + Cb interleaved  */
+#define V4L2_PIX_FMT_NV12    v4l2_fourcc('N', 'V', '1', '2') /* 12  Y/CbCr 4:2:0  */
+#define V4L2_PIX_FMT_NV21    v4l2_fourcc('N', 'V', '2', '1') /* 12  Y/CrCb 4:2:0  */
+#define V4L2_PIX_FMT_NV16    v4l2_fourcc('N', 'V', '1', '6') /* 16  Y/CbCr 4:2:2  */
+#define V4L2_PIX_FMT_NV61    v4l2_fourcc('N', 'V', '6', '1') /* 16  Y/CrCb 4:2:2  */
+#define V4L2_PIX_FMT_NV24    v4l2_fourcc('N', 'V', '2', '4') /* 24  Y/CbCr 4:4:4  */
+#define V4L2_PIX_FMT_NV42    v4l2_fourcc('N', 'V', '4', '2') /* 24  Y/CrCb 4:4:4  */
+
+/* two non contiguous planes - one Y, one Cr + Cb interleaved  */
+#define V4L2_PIX_FMT_NV12M   v4l2_fourcc('N', 'M', '1', '2') /* 12  Y/CbCr 4:2:0  */
+#define V4L2_PIX_FMT_NV21M   v4l2_fourcc('N', 'M', '2', '1') /* 21  Y/CrCb 4:2:0  */
+#define V4L2_PIX_FMT_NV16M   v4l2_fourcc('N', 'M', '1', '6') /* 16  Y/CbCr 4:2:2  */
+#define V4L2_PIX_FMT_NV61M   v4l2_fourcc('N', 'M', '6', '1') /* 16  Y/CrCb 4:2:2  */
+#define V4L2_PIX_FMT_NV12MT  v4l2_fourcc('T', 'M', '1', '2') /* 12  Y/CbCr 4:2:0 64x32 macroblocks */
+#define V4L2_PIX_FMT_NV12MT_16X16 v4l2_fourcc('V', 'M', '1', '2') /* 12  Y/CbCr 4:2:0 16x16 macroblocks */
+
+/* three planes - Y Cb, Cr */
+#define V4L2_PIX_FMT_YUV410  v4l2_fourcc('Y', 'U', 'V', '9') /*  9  YUV 4:1:0     */
+#define V4L2_PIX_FMT_YVU410  v4l2_fourcc('Y', 'V', 'U', '9') /*  9  YVU 4:1:0     */
+#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') /* 12  YVU411 planar */
+#define V4L2_PIX_FMT_YUV420  v4l2_fourcc('Y', 'U', '1', '2') /* 12  YUV 4:2:0     */
+#define V4L2_PIX_FMT_YVU420  v4l2_fourcc('Y', 'V', '1', '2') /* 12  YVU 4:2:0     */
+#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16  YVU422 planar */
+
+/* three non contiguous planes - Y, Cb, Cr */
+#define V4L2_PIX_FMT_YUV420M v4l2_fourcc('Y', 'M', '1', '2') /* 12  YUV420 planar */
+#define V4L2_PIX_FMT_YVU420M v4l2_fourcc('Y', 'M', '2', '1') /* 12  YVU420 planar */
+#define V4L2_PIX_FMT_YUV422M v4l2_fourcc('Y', 'M', '1', '6') /* 16  YUV422 planar */
+#define V4L2_PIX_FMT_YVU422M v4l2_fourcc('Y', 'M', '6', '1') /* 16  YVU422 planar */
+#define V4L2_PIX_FMT_YUV444M v4l2_fourcc('Y', 'M', '2', '4') /* 24  YUV444 planar */
+#define V4L2_PIX_FMT_YVU444M v4l2_fourcc('Y', 'M', '4', '2') /* 24  YVU444 planar */
+
+/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
+#define V4L2_PIX_FMT_SBGGR8  v4l2_fourcc('B', 'A', '8', '1') /*  8  BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SGBRG8  v4l2_fourcc('G', 'B', 'R', 'G') /*  8  GBGB.. RGRG.. */
+#define V4L2_PIX_FMT_SGRBG8  v4l2_fourcc('G', 'R', 'B', 'G') /*  8  GRGR.. BGBG.. */
+#define V4L2_PIX_FMT_SRGGB8  v4l2_fourcc('R', 'G', 'G', 'B') /*  8  RGRG.. GBGB.. */
+#define V4L2_PIX_FMT_SBGGR10 v4l2_fourcc('B', 'G', '1', '0') /* 10  BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '0') /* 10  GBGB.. RGRG.. */
+#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10  GRGR.. BGBG.. */
+#define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '0') /* 10  RGRG.. GBGB.. */
+	/* 10bit raw bayer packed, 5 bytes for every 4 pixels */
+#define V4L2_PIX_FMT_SBGGR10P v4l2_fourcc('p', 'B', 'A', 'A')
+#define V4L2_PIX_FMT_SGBRG10P v4l2_fourcc('p', 'G', 'A', 'A')
+#define V4L2_PIX_FMT_SGRBG10P v4l2_fourcc('p', 'g', 'A', 'A')
+#define V4L2_PIX_FMT_SRGGB10P v4l2_fourcc('p', 'R', 'A', 'A')
+	/* 10bit raw bayer a-law compressed to 8 bits */
+#define V4L2_PIX_FMT_SBGGR10ALAW8 v4l2_fourcc('a', 'B', 'A', '8')
+#define V4L2_PIX_FMT_SGBRG10ALAW8 v4l2_fourcc('a', 'G', 'A', '8')
+#define V4L2_PIX_FMT_SGRBG10ALAW8 v4l2_fourcc('a', 'g', 'A', '8')
+#define V4L2_PIX_FMT_SRGGB10ALAW8 v4l2_fourcc('a', 'R', 'A', '8')
+	/* 10bit raw bayer DPCM compressed to 8 bits */
+#define V4L2_PIX_FMT_SBGGR10DPCM8 v4l2_fourcc('b', 'B', 'A', '8')
+#define V4L2_PIX_FMT_SGBRG10DPCM8 v4l2_fourcc('b', 'G', 'A', '8')
+#define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0')
+#define V4L2_PIX_FMT_SRGGB10DPCM8 v4l2_fourcc('b', 'R', 'A', '8')
+#define V4L2_PIX_FMT_SBGGR12 v4l2_fourcc('B', 'G', '1', '2') /* 12  BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SGBRG12 v4l2_fourcc('G', 'B', '1', '2') /* 12  GBGB.. RGRG.. */
+#define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2') /* 12  GRGR.. BGBG.. */
+#define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2') /* 12  RGRG.. GBGB.. */
+#define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16  BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SGBRG16 v4l2_fourcc('G', 'B', '1', '6') /* 16  GBGB.. RGRG.. */
+#define V4L2_PIX_FMT_SGRBG16 v4l2_fourcc('G', 'R', '1', '6') /* 16  GRGR.. BGBG.. */
+#define V4L2_PIX_FMT_SRGGB16 v4l2_fourcc('R', 'G', '1', '6') /* 16  RGRG.. GBGB.. */
+
+/* HSV formats */
+#define V4L2_PIX_FMT_HSV24 v4l2_fourcc('H', 'S', 'V', '3')
+#define V4L2_PIX_FMT_HSV32 v4l2_fourcc('H', 'S', 'V', '4')
+
+/* compressed formats */
+#define V4L2_PIX_FMT_MJPEG    v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG   */
+#define V4L2_PIX_FMT_JPEG     v4l2_fourcc('J', 'P', 'E', 'G') /* JFIF JPEG     */
+#define V4L2_PIX_FMT_DV       v4l2_fourcc('d', 'v', 's', 'd') /* 1394          */
+#define V4L2_PIX_FMT_MPEG     v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4 Multiplexed */
+#define V4L2_PIX_FMT_H264     v4l2_fourcc('H', '2', '6', '4') /* H264 with start codes */
+#define V4L2_PIX_FMT_H264_NO_SC v4l2_fourcc('A', 'V', 'C', '1') /* H264 without start codes */
+#define V4L2_PIX_FMT_H264_MVC v4l2_fourcc('M', '2', '6', '4') /* H264 MVC */
+#define V4L2_PIX_FMT_H263     v4l2_fourcc('H', '2', '6', '3') /* H263          */
+#define V4L2_PIX_FMT_MPEG1    v4l2_fourcc('M', 'P', 'G', '1') /* MPEG-1 ES     */
+#define V4L2_PIX_FMT_MPEG2    v4l2_fourcc('M', 'P', 'G', '2') /* MPEG-2 ES     */
+#define V4L2_PIX_FMT_MPEG4    v4l2_fourcc('M', 'P', 'G', '4') /* MPEG-4 part 2 ES */
+#define V4L2_PIX_FMT_XVID     v4l2_fourcc('X', 'V', 'I', 'D') /* Xvid           */
+#define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */
+#define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */
+#define V4L2_PIX_FMT_VP8      v4l2_fourcc('V', 'P', '8', '0') /* VP8 */
+#define V4L2_PIX_FMT_VP9      v4l2_fourcc('V', 'P', '9', '0') /* VP9 */
+
+/*  Vendor-specific formats   */
+#define V4L2_PIX_FMT_CPIA1    v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
+#define V4L2_PIX_FMT_WNVA     v4l2_fourcc('W', 'N', 'V', 'A') /* Winnov hw compress */
+#define V4L2_PIX_FMT_SN9C10X  v4l2_fourcc('S', '9', '1', '0') /* SN9C10x compression */
+#define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') /* SN9C20x YUV 4:2:0 */
+#define V4L2_PIX_FMT_PWC1     v4l2_fourcc('P', 'W', 'C', '1') /* pwc older webcam */
+#define V4L2_PIX_FMT_PWC2     v4l2_fourcc('P', 'W', 'C', '2') /* pwc newer webcam */
+#define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E', '6', '2', '5') /* ET61X251 compression */
+#define V4L2_PIX_FMT_SPCA501  v4l2_fourcc('S', '5', '0', '1') /* YUYV per line */
+#define V4L2_PIX_FMT_SPCA505  v4l2_fourcc('S', '5', '0', '5') /* YYUV per line */
+#define V4L2_PIX_FMT_SPCA508  v4l2_fourcc('S', '5', '0', '8') /* YUVY per line */
+#define V4L2_PIX_FMT_SPCA561  v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */
+#define V4L2_PIX_FMT_PAC207   v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */
+#define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
+#define V4L2_PIX_FMT_JL2005BCD v4l2_fourcc('J', 'L', '2', '0') /* compressed RGGB bayer */
+#define V4L2_PIX_FMT_SN9C2028 v4l2_fourcc('S', 'O', 'N', 'X') /* compressed GBRG bayer */
+#define V4L2_PIX_FMT_SQ905C   v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
+#define V4L2_PIX_FMT_PJPG     v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
+#define V4L2_PIX_FMT_OV511    v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */
+#define V4L2_PIX_FMT_OV518    v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
+#define V4L2_PIX_FMT_STV0680  v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */
+#define V4L2_PIX_FMT_TM6000   v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */
+#define V4L2_PIX_FMT_CIT_YYVYUY v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */
+#define V4L2_PIX_FMT_KONICA420  v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */
+#define V4L2_PIX_FMT_JPGL	v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */
+#define V4L2_PIX_FMT_SE401      v4l2_fourcc('S', '4', '0', '1') /* se401 janggu compressed rgb */
+#define V4L2_PIX_FMT_S5C_UYVY_JPG v4l2_fourcc('S', '5', 'C', 'I') /* S5C73M3 interleaved UYVY/JPEG */
+#define V4L2_PIX_FMT_Y8I      v4l2_fourcc('Y', '8', 'I', ' ') /* Greyscale 8-bit L/R interleaved */
+#define V4L2_PIX_FMT_Y12I     v4l2_fourcc('Y', '1', '2', 'I') /* Greyscale 12-bit L/R interleaved */
+#define V4L2_PIX_FMT_Z16      v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */
+#define V4L2_PIX_FMT_MT21C    v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode  */
+#define V4L2_PIX_FMT_INZI     v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */
+
+/* SDR formats - used only for Software Defined Radio devices */
+#define V4L2_SDR_FMT_CU8          v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */
+#define V4L2_SDR_FMT_CU16LE       v4l2_fourcc('C', 'U', '1', '6') /* IQ u16le */
+#define V4L2_SDR_FMT_CS8          v4l2_fourcc('C', 'S', '0', '8') /* complex s8 */
+#define V4L2_SDR_FMT_CS14LE       v4l2_fourcc('C', 'S', '1', '4') /* complex s14le */
+#define V4L2_SDR_FMT_RU12LE       v4l2_fourcc('R', 'U', '1', '2') /* real u12le */
+#define V4L2_SDR_FMT_PCU16BE	  v4l2_fourcc('P', 'C', '1', '6') /* planar complex u16be */
+#define V4L2_SDR_FMT_PCU18BE	  v4l2_fourcc('P', 'C', '1', '8') /* planar complex u18be */
+#define V4L2_SDR_FMT_PCU20BE	  v4l2_fourcc('P', 'C', '2', '0') /* planar complex u20be */
+
+/* Touch formats - used for Touch devices */
+#define V4L2_TCH_FMT_DELTA_TD16	v4l2_fourcc('T', 'D', '1', '6') /* 16-bit signed deltas */
+#define V4L2_TCH_FMT_DELTA_TD08	v4l2_fourcc('T', 'D', '0', '8') /* 8-bit signed deltas */
+#define V4L2_TCH_FMT_TU16	v4l2_fourcc('T', 'U', '1', '6') /* 16-bit unsigned touch data */
+#define V4L2_TCH_FMT_TU08	v4l2_fourcc('T', 'U', '0', '8') /* 8-bit unsigned touch data */
+
+/* Meta-data formats */
+#define V4L2_META_FMT_VSP1_HGO    v4l2_fourcc('V', 'S', 'P', 'H') /* R-Car VSP1 1-D Histogram */
+#define V4L2_META_FMT_VSP1_HGT    v4l2_fourcc('V', 'S', 'P', 'T') /* R-Car VSP1 2-D Histogram */
+
+/* priv field value to indicates that subsequent fields are valid. */
+#define V4L2_PIX_FMT_PRIV_MAGIC		0xfeedcafe
+
+/* Flags */
+#define V4L2_PIX_FMT_FLAG_PREMUL_ALPHA	0x00000001
+
+/*
+ *	F O R M A T   E N U M E R A T I O N
+ */
+struct v4l2_fmtdesc {
+	__u32		    index;             /* Format number      */
+	__u32		    type;              /* enum v4l2_buf_type */
+	__u32               flags;
+	__u8		    description[32];   /* Description string */
+	__u32		    pixelformat;       /* Format fourcc      */
+	__u32		    reserved[4];
+};
+
+#define V4L2_FMT_FLAG_COMPRESSED 0x0001
+#define V4L2_FMT_FLAG_EMULATED   0x0002
+
+	/* Frame Size and frame rate enumeration */
+/*
+ *	F R A M E   S I Z E   E N U M E R A T I O N
+ */
+enum v4l2_frmsizetypes {
+	V4L2_FRMSIZE_TYPE_DISCRETE	= 1,
+	V4L2_FRMSIZE_TYPE_CONTINUOUS	= 2,
+	V4L2_FRMSIZE_TYPE_STEPWISE	= 3,
+};
+
+struct v4l2_frmsize_discrete {
+	__u32			width;		/* Frame width [pixel] */
+	__u32			height;		/* Frame height [pixel] */
+};
+
+struct v4l2_frmsize_stepwise {
+	__u32			min_width;	/* Minimum frame width [pixel] */
+	__u32			max_width;	/* Maximum frame width [pixel] */
+	__u32			step_width;	/* Frame width step size [pixel] */
+	__u32			min_height;	/* Minimum frame height [pixel] */
+	__u32			max_height;	/* Maximum frame height [pixel] */
+	__u32			step_height;	/* Frame height step size [pixel] */
+};
+
+struct v4l2_frmsizeenum {
+	__u32			index;		/* Frame size number */
+	__u32			pixel_format;	/* Pixel format */
+	__u32			type;		/* Frame size type the device supports. */
+
+	union {					/* Frame size */
+		struct v4l2_frmsize_discrete	discrete;
+		struct v4l2_frmsize_stepwise	stepwise;
+	};
+
+	__u32   reserved[2];			/* Reserved space for future use */
+};
+
+/*
+ *	F R A M E   R A T E   E N U M E R A T I O N
+ */
+enum v4l2_frmivaltypes {
+	V4L2_FRMIVAL_TYPE_DISCRETE	= 1,
+	V4L2_FRMIVAL_TYPE_CONTINUOUS	= 2,
+	V4L2_FRMIVAL_TYPE_STEPWISE	= 3,
+};
+
+struct v4l2_frmival_stepwise {
+	struct v4l2_fract	min;		/* Minimum frame interval [s] */
+	struct v4l2_fract	max;		/* Maximum frame interval [s] */
+	struct v4l2_fract	step;		/* Frame interval step size [s] */
+};
+
+struct v4l2_frmivalenum {
+	__u32			index;		/* Frame format index */
+	__u32			pixel_format;	/* Pixel format */
+	__u32			width;		/* Frame width */
+	__u32			height;		/* Frame height */
+	__u32			type;		/* Frame interval type the device supports. */
+
+	union {					/* Frame interval */
+		struct v4l2_fract		discrete;
+		struct v4l2_frmival_stepwise	stepwise;
+	};
+
+	__u32	reserved[2];			/* Reserved space for future use */
+};
+
+/*
+ *	T I M E C O D E
+ */
+struct v4l2_timecode {
+	__u32	type;
+	__u32	flags;
+	__u8	frames;
+	__u8	seconds;
+	__u8	minutes;
+	__u8	hours;
+	__u8	userbits[4];
+};
+
+/*  Type  */
+#define V4L2_TC_TYPE_24FPS		1
+#define V4L2_TC_TYPE_25FPS		2
+#define V4L2_TC_TYPE_30FPS		3
+#define V4L2_TC_TYPE_50FPS		4
+#define V4L2_TC_TYPE_60FPS		5
+
+/*  Flags  */
+#define V4L2_TC_FLAG_DROPFRAME		0x0001 /* "drop-frame" mode */
+#define V4L2_TC_FLAG_COLORFRAME		0x0002
+#define V4L2_TC_USERBITS_field		0x000C
+#define V4L2_TC_USERBITS_USERDEFINED	0x0000
+#define V4L2_TC_USERBITS_8BITCHARS	0x0008
+/* The above is based on SMPTE timecodes */
+
+struct v4l2_jpegcompression {
+	int quality;
+
+	int  APPn;              /* Number of APP segment to be written,
+				 * must be 0..15 */
+	int  APP_len;           /* Length of data in JPEG APPn segment */
+	char APP_data[60];      /* Data in the JPEG APPn segment. */
+
+	int  COM_len;           /* Length of data in JPEG COM segment */
+	char COM_data[60];      /* Data in JPEG COM segment */
+
+	__u32 jpeg_markers;     /* Which markers should go into the JPEG
+				 * output. Unless you exactly know what
+				 * you do, leave them untouched.
+				 * Including less markers will make the
+				 * resulting code smaller, but there will
+				 * be fewer applications which can read it.
+				 * The presence of the APP and COM marker
+				 * is influenced by APP_len and COM_len
+				 * ONLY, not by this property! */
+
+#define V4L2_JPEG_MARKER_DHT (1<<3)    /* Define Huffman Tables */
+#define V4L2_JPEG_MARKER_DQT (1<<4)    /* Define Quantization Tables */
+#define V4L2_JPEG_MARKER_DRI (1<<5)    /* Define Restart Interval */
+#define V4L2_JPEG_MARKER_COM (1<<6)    /* Comment segment */
+#define V4L2_JPEG_MARKER_APP (1<<7)    /* App segment, driver will
+					* always use APP0 */
+};
+
+/*
+ *	M E M O R Y - M A P P I N G   B U F F E R S
+ */
+struct v4l2_requestbuffers {
+	__u32			count;
+	__u32			type;		/* enum v4l2_buf_type */
+	__u32			memory;		/* enum v4l2_memory */
+	__u32			reserved[2];
+};
+
+/**
+ * struct v4l2_plane - plane info for multi-planar buffers
+ * @bytesused:		number of bytes occupied by data in the plane (payload)
+ * @length:		size of this plane (NOT the payload) in bytes
+ * @mem_offset:		when memory in the associated struct v4l2_buffer is
+ *			V4L2_MEMORY_MMAP, equals the offset from the start of
+ *			the device memory for this plane (or is a "cookie" that
+ *			should be passed to mmap() called on the video node)
+ * @userptr:		when memory is V4L2_MEMORY_USERPTR, a userspace pointer
+ *			pointing to this plane
+ * @fd:			when memory is V4L2_MEMORY_DMABUF, a userspace file
+ *			descriptor associated with this plane
+ * @data_offset:	offset in the plane to the start of data; usually 0,
+ *			unless there is a header in front of the data
+ *
+ * Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer
+ * with two planes can have one plane for Y, and another for interleaved CbCr
+ * components. Each plane can reside in a separate memory buffer, or even in
+ * a completely separate memory node (e.g. in embedded devices).
+ */
+struct v4l2_plane {
+	__u32			bytesused;
+	__u32			length;
+	union {
+		__u32		mem_offset;
+		unsigned long	userptr;
+		__s32		fd;
+	} m;
+	__u32			data_offset;
+	__u32			reserved[11];
+};
+
+/**
+ * struct v4l2_buffer - video buffer info
+ * @index:	id number of the buffer
+ * @type:	enum v4l2_buf_type; buffer type (type == *_MPLANE for
+ *		multiplanar buffers);
+ * @bytesused:	number of bytes occupied by data in the buffer (payload);
+ *		unused (set to 0) for multiplanar buffers
+ * @flags:	buffer informational flags
+ * @field:	enum v4l2_field; field order of the image in the buffer
+ * @timestamp:	frame timestamp
+ * @timecode:	frame timecode
+ * @sequence:	sequence count of this frame
+ * @memory:	enum v4l2_memory; the method, in which the actual video data is
+ *		passed
+ * @offset:	for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP;
+ *		offset from the start of the device memory for this plane,
+ *		(or a "cookie" that should be passed to mmap() as offset)
+ * @userptr:	for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR;
+ *		a userspace pointer pointing to this buffer
+ * @fd:		for non-multiplanar buffers with memory == V4L2_MEMORY_DMABUF;
+ *		a userspace file descriptor associated with this buffer
+ * @planes:	for multiplanar buffers; userspace pointer to the array of plane
+ *		info structs for this buffer
+ * @length:	size in bytes of the buffer (NOT its payload) for single-plane
+ *		buffers (when type != *_MPLANE); number of elements in the
+ *		planes array for multi-plane buffers
+ *
+ * Contains data exchanged by application and driver using one of the Streaming
+ * I/O methods.
+ */
+struct v4l2_buffer {
+	__u32			index;
+	__u32			type;
+	__u32			bytesused;
+	__u32			flags;
+	__u32			field;
+	struct timeval		timestamp;
+	struct v4l2_timecode	timecode;
+	__u32			sequence;
+
+	/* memory location */
+	__u32			memory;
+	union {
+		__u32           offset;
+		unsigned long   userptr;
+		struct v4l2_plane *planes;
+		__s32		fd;
+	} m;
+	__u32			length;
+	__u32			reserved2;
+	__u32			reserved;
+};
+
+/*  Flags for 'flags' field */
+/* Buffer is mapped (flag) */
+#define V4L2_BUF_FLAG_MAPPED			0x00000001
+/* Buffer is queued for processing */
+#define V4L2_BUF_FLAG_QUEUED			0x00000002
+/* Buffer is ready */
+#define V4L2_BUF_FLAG_DONE			0x00000004
+/* Image is a keyframe (I-frame) */
+#define V4L2_BUF_FLAG_KEYFRAME			0x00000008
+/* Image is a P-frame */
+#define V4L2_BUF_FLAG_PFRAME			0x00000010
+/* Image is a B-frame */
+#define V4L2_BUF_FLAG_BFRAME			0x00000020
+/* Buffer is ready, but the data contained within is corrupted. */
+#define V4L2_BUF_FLAG_ERROR			0x00000040
+/* timecode field is valid */
+#define V4L2_BUF_FLAG_TIMECODE			0x00000100
+/* Buffer is prepared for queuing */
+#define V4L2_BUF_FLAG_PREPARED			0x00000400
+/* Cache handling flags */
+#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE	0x00000800
+#define V4L2_BUF_FLAG_NO_CACHE_CLEAN		0x00001000
+/* Timestamp type */
+#define V4L2_BUF_FLAG_TIMESTAMP_MASK		0x0000e000
+#define V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN		0x00000000
+#define V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC	0x00002000
+#define V4L2_BUF_FLAG_TIMESTAMP_COPY		0x00004000
+/* Timestamp sources. */
+#define V4L2_BUF_FLAG_TSTAMP_SRC_MASK		0x00070000
+#define V4L2_BUF_FLAG_TSTAMP_SRC_EOF		0x00000000
+#define V4L2_BUF_FLAG_TSTAMP_SRC_SOE		0x00010000
+/* mem2mem encoder/decoder */
+#define V4L2_BUF_FLAG_LAST			0x00100000
+
+/**
+ * struct v4l2_exportbuffer - export of video buffer as DMABUF file descriptor
+ *
+ * @index:	id number of the buffer
+ * @type:	enum v4l2_buf_type; buffer type (type == *_MPLANE for
+ *		multiplanar buffers);
+ * @plane:	index of the plane to be exported, 0 for single plane queues
+ * @flags:	flags for newly created file, currently only O_CLOEXEC is
+ *		supported, refer to manual of open syscall for more details
+ * @fd:		file descriptor associated with DMABUF (set by driver)
+ *
+ * Contains data used for exporting a video buffer as DMABUF file descriptor.
+ * The buffer is identified by a 'cookie' returned by VIDIOC_QUERYBUF
+ * (identical to the cookie used to mmap() the buffer to userspace). All
+ * reserved fields must be set to zero. The field reserved0 is expected to
+ * become a structure 'type' allowing an alternative layout of the structure
+ * content. Therefore this field should not be used for any other extensions.
+ */
+struct v4l2_exportbuffer {
+	__u32		type; /* enum v4l2_buf_type */
+	__u32		index;
+	__u32		plane;
+	__u32		flags;
+	__s32		fd;
+	__u32		reserved[11];
+};
+
+/*
+ *	O V E R L A Y   P R E V I E W
+ */
+struct v4l2_framebuffer {
+	__u32			capability;
+	__u32			flags;
+/* FIXME: in theory we should pass something like PCI device + memory
+ * region + offset instead of some physical address */
+	void                    *base;
+	struct {
+		__u32		width;
+		__u32		height;
+		__u32		pixelformat;
+		__u32		field;		/* enum v4l2_field */
+		__u32		bytesperline;	/* for padding, zero if unused */
+		__u32		sizeimage;
+		__u32		colorspace;	/* enum v4l2_colorspace */
+		__u32		priv;		/* reserved field, set to 0 */
+	} fmt;
+};
+/*  Flags for the 'capability' field. Read only */
+#define V4L2_FBUF_CAP_EXTERNOVERLAY	0x0001
+#define V4L2_FBUF_CAP_CHROMAKEY		0x0002
+#define V4L2_FBUF_CAP_LIST_CLIPPING     0x0004
+#define V4L2_FBUF_CAP_BITMAP_CLIPPING	0x0008
+#define V4L2_FBUF_CAP_LOCAL_ALPHA	0x0010
+#define V4L2_FBUF_CAP_GLOBAL_ALPHA	0x0020
+#define V4L2_FBUF_CAP_LOCAL_INV_ALPHA	0x0040
+#define V4L2_FBUF_CAP_SRC_CHROMAKEY	0x0080
+/*  Flags for the 'flags' field. */
+#define V4L2_FBUF_FLAG_PRIMARY		0x0001
+#define V4L2_FBUF_FLAG_OVERLAY		0x0002
+#define V4L2_FBUF_FLAG_CHROMAKEY	0x0004
+#define V4L2_FBUF_FLAG_LOCAL_ALPHA	0x0008
+#define V4L2_FBUF_FLAG_GLOBAL_ALPHA	0x0010
+#define V4L2_FBUF_FLAG_LOCAL_INV_ALPHA	0x0020
+#define V4L2_FBUF_FLAG_SRC_CHROMAKEY	0x0040
+
+struct v4l2_clip {
+	struct v4l2_rect        c;
+	struct v4l2_clip	__user *next;
+};
+
+struct v4l2_window {
+	struct v4l2_rect        w;
+	__u32			field;	 /* enum v4l2_field */
+	__u32			chromakey;
+	struct v4l2_clip	__user *clips;
+	__u32			clipcount;
+	void			__user *bitmap;
+	__u8                    global_alpha;
+};
+
+/*
+ *	C A P T U R E   P A R A M E T E R S
+ */
+struct v4l2_captureparm {
+	__u32		   capability;	  /*  Supported modes */
+	__u32		   capturemode;	  /*  Current mode */
+	struct v4l2_fract  timeperframe;  /*  Time per frame in seconds */
+	__u32		   extendedmode;  /*  Driver-specific extensions */
+	__u32              readbuffers;   /*  # of buffers for read */
+	__u32		   reserved[4];
+};
+
+/*  Flags for 'capability' and 'capturemode' fields */
+#define V4L2_MODE_HIGHQUALITY	0x0001	/*  High quality imaging mode */
+#define V4L2_CAP_TIMEPERFRAME	0x1000	/*  timeperframe field is supported */
+
+struct v4l2_outputparm {
+	__u32		   capability;	 /*  Supported modes */
+	__u32		   outputmode;	 /*  Current mode */
+	struct v4l2_fract  timeperframe; /*  Time per frame in seconds */
+	__u32		   extendedmode; /*  Driver-specific extensions */
+	__u32              writebuffers; /*  # of buffers for write */
+	__u32		   reserved[4];
+};
+
+/*
+ *	I N P U T   I M A G E   C R O P P I N G
+ */
+struct v4l2_cropcap {
+	__u32			type;	/* enum v4l2_buf_type */
+	struct v4l2_rect        bounds;
+	struct v4l2_rect        defrect;
+	struct v4l2_fract       pixelaspect;
+};
+
+struct v4l2_crop {
+	__u32			type;	/* enum v4l2_buf_type */
+	struct v4l2_rect        c;
+};
+
+/**
+ * struct v4l2_selection - selection info
+ * @type:	buffer type (do not use *_MPLANE types)
+ * @target:	Selection target, used to choose one of possible rectangles;
+ *		defined in v4l2-common.h; V4L2_SEL_TGT_* .
+ * @flags:	constraints flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
+ * @r:		coordinates of selection window
+ * @reserved:	for future use, rounds structure size to 64 bytes, set to zero
+ *
+ * Hardware may use multiple helper windows to process a video stream.
+ * The structure is used to exchange this selection areas between
+ * an application and a driver.
+ */
+struct v4l2_selection {
+	__u32			type;
+	__u32			target;
+	__u32                   flags;
+	struct v4l2_rect        r;
+	__u32                   reserved[9];
+};
+
+
+/*
+ *      A N A L O G   V I D E O   S T A N D A R D
+ */
+
+typedef __u64 v4l2_std_id;
+
+/* one bit for each */
+#define V4L2_STD_PAL_B          ((v4l2_std_id)0x00000001)
+#define V4L2_STD_PAL_B1         ((v4l2_std_id)0x00000002)
+#define V4L2_STD_PAL_G          ((v4l2_std_id)0x00000004)
+#define V4L2_STD_PAL_H          ((v4l2_std_id)0x00000008)
+#define V4L2_STD_PAL_I          ((v4l2_std_id)0x00000010)
+#define V4L2_STD_PAL_D          ((v4l2_std_id)0x00000020)
+#define V4L2_STD_PAL_D1         ((v4l2_std_id)0x00000040)
+#define V4L2_STD_PAL_K          ((v4l2_std_id)0x00000080)
+
+#define V4L2_STD_PAL_M          ((v4l2_std_id)0x00000100)
+#define V4L2_STD_PAL_N          ((v4l2_std_id)0x00000200)
+#define V4L2_STD_PAL_Nc         ((v4l2_std_id)0x00000400)
+#define V4L2_STD_PAL_60         ((v4l2_std_id)0x00000800)
+
+#define V4L2_STD_NTSC_M         ((v4l2_std_id)0x00001000)	/* BTSC */
+#define V4L2_STD_NTSC_M_JP      ((v4l2_std_id)0x00002000)	/* EIA-J */
+#define V4L2_STD_NTSC_443       ((v4l2_std_id)0x00004000)
+#define V4L2_STD_NTSC_M_KR      ((v4l2_std_id)0x00008000)	/* FM A2 */
+
+#define V4L2_STD_SECAM_B        ((v4l2_std_id)0x00010000)
+#define V4L2_STD_SECAM_D        ((v4l2_std_id)0x00020000)
+#define V4L2_STD_SECAM_G        ((v4l2_std_id)0x00040000)
+#define V4L2_STD_SECAM_H        ((v4l2_std_id)0x00080000)
+#define V4L2_STD_SECAM_K        ((v4l2_std_id)0x00100000)
+#define V4L2_STD_SECAM_K1       ((v4l2_std_id)0x00200000)
+#define V4L2_STD_SECAM_L        ((v4l2_std_id)0x00400000)
+#define V4L2_STD_SECAM_LC       ((v4l2_std_id)0x00800000)
+
+/* ATSC/HDTV */
+#define V4L2_STD_ATSC_8_VSB     ((v4l2_std_id)0x01000000)
+#define V4L2_STD_ATSC_16_VSB    ((v4l2_std_id)0x02000000)
+
+/* FIXME:
+   Although std_id is 64 bits, there is an issue on PPC32 architecture that
+   makes switch(__u64) to break. So, there's a hack on v4l2-common.c rounding
+   this value to 32 bits.
+   As, currently, the max value is for V4L2_STD_ATSC_16_VSB (30 bits wide),
+   it should work fine. However, if needed to add more than two standards,
+   v4l2-common.c should be fixed.
+ */
+
+/*
+ * Some macros to merge video standards in order to make live easier for the
+ * drivers and V4L2 applications
+ */
+
+/*
+ * "Common" NTSC/M - It should be noticed that V4L2_STD_NTSC_443 is
+ * Missing here.
+ */
+#define V4L2_STD_NTSC           (V4L2_STD_NTSC_M	|\
+				 V4L2_STD_NTSC_M_JP     |\
+				 V4L2_STD_NTSC_M_KR)
+/* Secam macros */
+#define V4L2_STD_SECAM_DK      	(V4L2_STD_SECAM_D	|\
+				 V4L2_STD_SECAM_K	|\
+				 V4L2_STD_SECAM_K1)
+/* All Secam Standards */
+#define V4L2_STD_SECAM		(V4L2_STD_SECAM_B	|\
+				 V4L2_STD_SECAM_G	|\
+				 V4L2_STD_SECAM_H	|\
+				 V4L2_STD_SECAM_DK	|\
+				 V4L2_STD_SECAM_L       |\
+				 V4L2_STD_SECAM_LC)
+/* PAL macros */
+#define V4L2_STD_PAL_BG		(V4L2_STD_PAL_B		|\
+				 V4L2_STD_PAL_B1	|\
+				 V4L2_STD_PAL_G)
+#define V4L2_STD_PAL_DK		(V4L2_STD_PAL_D		|\
+				 V4L2_STD_PAL_D1	|\
+				 V4L2_STD_PAL_K)
+/*
+ * "Common" PAL - This macro is there to be compatible with the old
+ * V4L1 concept of "PAL": /BGDKHI.
+ * Several PAL standards are missing here: /M, /N and /Nc
+ */
+#define V4L2_STD_PAL		(V4L2_STD_PAL_BG	|\
+				 V4L2_STD_PAL_DK	|\
+				 V4L2_STD_PAL_H		|\
+				 V4L2_STD_PAL_I)
+/* Chroma "agnostic" standards */
+#define V4L2_STD_B		(V4L2_STD_PAL_B		|\
+				 V4L2_STD_PAL_B1	|\
+				 V4L2_STD_SECAM_B)
+#define V4L2_STD_G		(V4L2_STD_PAL_G		|\
+				 V4L2_STD_SECAM_G)
+#define V4L2_STD_H		(V4L2_STD_PAL_H		|\
+				 V4L2_STD_SECAM_H)
+#define V4L2_STD_L		(V4L2_STD_SECAM_L	|\
+				 V4L2_STD_SECAM_LC)
+#define V4L2_STD_GH		(V4L2_STD_G		|\
+				 V4L2_STD_H)
+#define V4L2_STD_DK		(V4L2_STD_PAL_DK	|\
+				 V4L2_STD_SECAM_DK)
+#define V4L2_STD_BG		(V4L2_STD_B		|\
+				 V4L2_STD_G)
+#define V4L2_STD_MN		(V4L2_STD_PAL_M		|\
+				 V4L2_STD_PAL_N		|\
+				 V4L2_STD_PAL_Nc	|\
+				 V4L2_STD_NTSC)
+
+/* Standards where MTS/BTSC stereo could be found */
+#define V4L2_STD_MTS		(V4L2_STD_NTSC_M	|\
+				 V4L2_STD_PAL_M		|\
+				 V4L2_STD_PAL_N		|\
+				 V4L2_STD_PAL_Nc)
+
+/* Standards for Countries with 60Hz Line frequency */
+#define V4L2_STD_525_60		(V4L2_STD_PAL_M		|\
+				 V4L2_STD_PAL_60	|\
+				 V4L2_STD_NTSC		|\
+				 V4L2_STD_NTSC_443)
+/* Standards for Countries with 50Hz Line frequency */
+#define V4L2_STD_625_50		(V4L2_STD_PAL		|\
+				 V4L2_STD_PAL_N		|\
+				 V4L2_STD_PAL_Nc	|\
+				 V4L2_STD_SECAM)
+
+#define V4L2_STD_ATSC           (V4L2_STD_ATSC_8_VSB    |\
+				 V4L2_STD_ATSC_16_VSB)
+/* Macros with none and all analog standards */
+#define V4L2_STD_UNKNOWN        0
+#define V4L2_STD_ALL            (V4L2_STD_525_60	|\
+				 V4L2_STD_625_50)
+
+struct v4l2_standard {
+	__u32		     index;
+	v4l2_std_id          id;
+	__u8		     name[24];
+	struct v4l2_fract    frameperiod; /* Frames, not fields */
+	__u32		     framelines;
+	__u32		     reserved[4];
+};
+
+/*
+ *	D V 	B T	T I M I N G S
+ */
+
+/** struct v4l2_bt_timings - BT.656/BT.1120 timing data
+ * @width:	total width of the active video in pixels
+ * @height:	total height of the active video in lines
+ * @interlaced:	Interlaced or progressive
+ * @polarities:	Positive or negative polarities
+ * @pixelclock:	Pixel clock in HZ. Ex. 74.25MHz->74250000
+ * @hfrontporch:Horizontal front porch in pixels
+ * @hsync:	Horizontal Sync length in pixels
+ * @hbackporch:	Horizontal back porch in pixels
+ * @vfrontporch:Vertical front porch in lines
+ * @vsync:	Vertical Sync length in lines
+ * @vbackporch:	Vertical back porch in lines
+ * @il_vfrontporch:Vertical front porch for the even field
+ *		(aka field 2) of interlaced field formats
+ * @il_vsync:	Vertical Sync length for the even field
+ *		(aka field 2) of interlaced field formats
+ * @il_vbackporch:Vertical back porch for the even field
+ *		(aka field 2) of interlaced field formats
+ * @standards:	Standards the timing belongs to
+ * @flags:	Flags
+ * @picture_aspect: The picture aspect ratio (hor/vert).
+ * @cea861_vic:	VIC code as per the CEA-861 standard.
+ * @hdmi_vic:	VIC code as per the HDMI standard.
+ * @reserved:	Reserved fields, must be zeroed.
+ *
+ * A note regarding vertical interlaced timings: height refers to the total
+ * height of the active video frame (= two fields). The blanking timings refer
+ * to the blanking of each field. So the height of the total frame is
+ * calculated as follows:
+ *
+ * tot_height = height + vfrontporch + vsync + vbackporch +
+ *                       il_vfrontporch + il_vsync + il_vbackporch
+ *
+ * The active height of each field is height / 2.
+ */
+struct v4l2_bt_timings {
+	__u32	width;
+	__u32	height;
+	__u32	interlaced;
+	__u32	polarities;
+	__u64	pixelclock;
+	__u32	hfrontporch;
+	__u32	hsync;
+	__u32	hbackporch;
+	__u32	vfrontporch;
+	__u32	vsync;
+	__u32	vbackporch;
+	__u32	il_vfrontporch;
+	__u32	il_vsync;
+	__u32	il_vbackporch;
+	__u32	standards;
+	__u32	flags;
+	struct v4l2_fract picture_aspect;
+	__u8	cea861_vic;
+	__u8	hdmi_vic;
+	__u8	reserved[46];
+} __attribute__ ((packed));
+
+/* Interlaced or progressive format */
+#define	V4L2_DV_PROGRESSIVE	0
+#define	V4L2_DV_INTERLACED	1
+
+/* Polarities. If bit is not set, it is assumed to be negative polarity */
+#define V4L2_DV_VSYNC_POS_POL	0x00000001
+#define V4L2_DV_HSYNC_POS_POL	0x00000002
+
+/* Timings standards */
+#define V4L2_DV_BT_STD_CEA861	(1 << 0)  /* CEA-861 Digital TV Profile */
+#define V4L2_DV_BT_STD_DMT	(1 << 1)  /* VESA Discrete Monitor Timings */
+#define V4L2_DV_BT_STD_CVT	(1 << 2)  /* VESA Coordinated Video Timings */
+#define V4L2_DV_BT_STD_GTF	(1 << 3)  /* VESA Generalized Timings Formula */
+#define V4L2_DV_BT_STD_SDI	(1 << 4)  /* SDI Timings */
+
+/* Flags */
+
+/*
+ * CVT/GTF specific: timing uses reduced blanking (CVT) or the 'Secondary
+ * GTF' curve (GTF). In both cases the horizontal and/or vertical blanking
+ * intervals are reduced, allowing a higher resolution over the same
+ * bandwidth. This is a read-only flag.
+ */
+#define V4L2_DV_FL_REDUCED_BLANKING		(1 << 0)
+/*
+ * CEA-861 specific: set for CEA-861 formats with a framerate of a multiple
+ * of six. These formats can be optionally played at 1 / 1.001 speed.
+ * This is a read-only flag.
+ */
+#define V4L2_DV_FL_CAN_REDUCE_FPS		(1 << 1)
+/*
+ * CEA-861 specific: only valid for video transmitters, the flag is cleared
+ * by receivers.
+ * If the framerate of the format is a multiple of six, then the pixelclock
+ * used to set up the transmitter is divided by 1.001 to make it compatible
+ * with 60 Hz based standards such as NTSC and PAL-M that use a framerate of
+ * 29.97 Hz. Otherwise this flag is cleared. If the transmitter can't generate
+ * such frequencies, then the flag will also be cleared.
+ */
+#define V4L2_DV_FL_REDUCED_FPS			(1 << 2)
+/*
+ * Specific to interlaced formats: if set, then field 1 is really one half-line
+ * longer and field 2 is really one half-line shorter, so each field has
+ * exactly the same number of half-lines. Whether half-lines can be detected
+ * or used depends on the hardware.
+ */
+#define V4L2_DV_FL_HALF_LINE			(1 << 3)
+/*
+ * If set, then this is a Consumer Electronics (CE) video format. Such formats
+ * differ from other formats (commonly called IT formats) in that if RGB
+ * encoding is used then by default the RGB values use limited range (i.e.
+ * use the range 16-235) as opposed to 0-255. All formats defined in CEA-861
+ * except for the 640x480 format are CE formats.
+ */
+#define V4L2_DV_FL_IS_CE_VIDEO			(1 << 4)
+/* Some formats like SMPTE-125M have an interlaced signal with a odd
+ * total height. For these formats, if this flag is set, the first
+ * field has the extra line. If not, it is the second field.
+ */
+#define V4L2_DV_FL_FIRST_FIELD_EXTRA_LINE	(1 << 5)
+/*
+ * If set, then the picture_aspect field is valid. Otherwise assume that the
+ * pixels are square, so the picture aspect ratio is the same as the width to
+ * height ratio.
+ */
+#define V4L2_DV_FL_HAS_PICTURE_ASPECT		(1 << 6)
+/*
+ * If set, then the cea861_vic field is valid and contains the Video
+ * Identification Code as per the CEA-861 standard.
+ */
+#define V4L2_DV_FL_HAS_CEA861_VIC		(1 << 7)
+/*
+ * If set, then the hdmi_vic field is valid and contains the Video
+ * Identification Code as per the HDMI standard (HDMI Vendor Specific
+ * InfoFrame).
+ */
+#define V4L2_DV_FL_HAS_HDMI_VIC			(1 << 8)
+
+/* A few useful defines to calculate the total blanking and frame sizes */
+#define V4L2_DV_BT_BLANKING_WIDTH(bt) \
+	((bt)->hfrontporch + (bt)->hsync + (bt)->hbackporch)
+#define V4L2_DV_BT_FRAME_WIDTH(bt) \
+	((bt)->width + V4L2_DV_BT_BLANKING_WIDTH(bt))
+#define V4L2_DV_BT_BLANKING_HEIGHT(bt) \
+	((bt)->vfrontporch + (bt)->vsync + (bt)->vbackporch + \
+	 (bt)->il_vfrontporch + (bt)->il_vsync + (bt)->il_vbackporch)
+#define V4L2_DV_BT_FRAME_HEIGHT(bt) \
+	((bt)->height + V4L2_DV_BT_BLANKING_HEIGHT(bt))
+
+/** struct v4l2_dv_timings - DV timings
+ * @type:	the type of the timings
+ * @bt:	BT656/1120 timings
+ */
+struct v4l2_dv_timings {
+	__u32 type;
+	union {
+		struct v4l2_bt_timings	bt;
+		__u32	reserved[32];
+	};
+} __attribute__ ((packed));
+
+/* Values for the type field */
+#define V4L2_DV_BT_656_1120	0	/* BT.656/1120 timing type */
+
+
+/** struct v4l2_enum_dv_timings - DV timings enumeration
+ * @index:	enumeration index
+ * @pad:	the pad number for which to enumerate timings (used with
+ *		v4l-subdev nodes only)
+ * @reserved:	must be zeroed
+ * @timings:	the timings for the given index
+ */
+struct v4l2_enum_dv_timings {
+	__u32 index;
+	__u32 pad;
+	__u32 reserved[2];
+	struct v4l2_dv_timings timings;
+};
+
+/** struct v4l2_bt_timings_cap - BT.656/BT.1120 timing capabilities
+ * @min_width:		width in pixels
+ * @max_width:		width in pixels
+ * @min_height:		height in lines
+ * @max_height:		height in lines
+ * @min_pixelclock:	Pixel clock in HZ. Ex. 74.25MHz->74250000
+ * @max_pixelclock:	Pixel clock in HZ. Ex. 74.25MHz->74250000
+ * @standards:		Supported standards
+ * @capabilities:	Supported capabilities
+ * @reserved:		Must be zeroed
+ */
+struct v4l2_bt_timings_cap {
+	__u32	min_width;
+	__u32	max_width;
+	__u32	min_height;
+	__u32	max_height;
+	__u64	min_pixelclock;
+	__u64	max_pixelclock;
+	__u32	standards;
+	__u32	capabilities;
+	__u32	reserved[16];
+} __attribute__ ((packed));
+
+/* Supports interlaced formats */
+#define V4L2_DV_BT_CAP_INTERLACED	(1 << 0)
+/* Supports progressive formats */
+#define V4L2_DV_BT_CAP_PROGRESSIVE	(1 << 1)
+/* Supports CVT/GTF reduced blanking */
+#define V4L2_DV_BT_CAP_REDUCED_BLANKING	(1 << 2)
+/* Supports custom formats */
+#define V4L2_DV_BT_CAP_CUSTOM		(1 << 3)
+
+/** struct v4l2_dv_timings_cap - DV timings capabilities
+ * @type:	the type of the timings (same as in struct v4l2_dv_timings)
+ * @pad:	the pad number for which to query capabilities (used with
+ *		v4l-subdev nodes only)
+ * @bt:		the BT656/1120 timings capabilities
+ */
+struct v4l2_dv_timings_cap {
+	__u32 type;
+	__u32 pad;
+	__u32 reserved[2];
+	union {
+		struct v4l2_bt_timings_cap bt;
+		__u32 raw_data[32];
+	};
+};
+
+
+/*
+ *	V I D E O   I N P U T S
+ */
+struct v4l2_input {
+	__u32	     index;		/*  Which input */
+	__u8	     name[32];		/*  Label */
+	__u32	     type;		/*  Type of input */
+	__u32	     audioset;		/*  Associated audios (bitfield) */
+	__u32        tuner;             /*  enum v4l2_tuner_type */
+	v4l2_std_id  std;
+	__u32	     status;
+	__u32	     capabilities;
+	__u32	     reserved[3];
+};
+
+/*  Values for the 'type' field */
+#define V4L2_INPUT_TYPE_TUNER		1
+#define V4L2_INPUT_TYPE_CAMERA		2
+#define V4L2_INPUT_TYPE_TOUCH		3
+
+/* field 'status' - general */
+#define V4L2_IN_ST_NO_POWER    0x00000001  /* Attached device is off */
+#define V4L2_IN_ST_NO_SIGNAL   0x00000002
+#define V4L2_IN_ST_NO_COLOR    0x00000004
+
+/* field 'status' - sensor orientation */
+/* If sensor is mounted upside down set both bits */
+#define V4L2_IN_ST_HFLIP       0x00000010 /* Frames are flipped horizontally */
+#define V4L2_IN_ST_VFLIP       0x00000020 /* Frames are flipped vertically */
+
+/* field 'status' - analog */
+#define V4L2_IN_ST_NO_H_LOCK   0x00000100  /* No horizontal sync lock */
+#define V4L2_IN_ST_COLOR_KILL  0x00000200  /* Color killer is active */
+#define V4L2_IN_ST_NO_V_LOCK   0x00000400  /* No vertical sync lock */
+#define V4L2_IN_ST_NO_STD_LOCK 0x00000800  /* No standard format lock */
+
+/* field 'status' - digital */
+#define V4L2_IN_ST_NO_SYNC     0x00010000  /* No synchronization lock */
+#define V4L2_IN_ST_NO_EQU      0x00020000  /* No equalizer lock */
+#define V4L2_IN_ST_NO_CARRIER  0x00040000  /* Carrier recovery failed */
+
+/* field 'status' - VCR and set-top box */
+#define V4L2_IN_ST_MACROVISION 0x01000000  /* Macrovision detected */
+#define V4L2_IN_ST_NO_ACCESS   0x02000000  /* Conditional access denied */
+#define V4L2_IN_ST_VTR         0x04000000  /* VTR time constant */
+
+/* capabilities flags */
+#define V4L2_IN_CAP_DV_TIMINGS		0x00000002 /* Supports S_DV_TIMINGS */
+#define V4L2_IN_CAP_CUSTOM_TIMINGS	V4L2_IN_CAP_DV_TIMINGS /* For compatibility */
+#define V4L2_IN_CAP_STD			0x00000004 /* Supports S_STD */
+#define V4L2_IN_CAP_NATIVE_SIZE		0x00000008 /* Supports setting native size */
+
+/*
+ *	V I D E O   O U T P U T S
+ */
+struct v4l2_output {
+	__u32	     index;		/*  Which output */
+	__u8	     name[32];		/*  Label */
+	__u32	     type;		/*  Type of output */
+	__u32	     audioset;		/*  Associated audios (bitfield) */
+	__u32	     modulator;         /*  Associated modulator */
+	v4l2_std_id  std;
+	__u32	     capabilities;
+	__u32	     reserved[3];
+};
+/*  Values for the 'type' field */
+#define V4L2_OUTPUT_TYPE_MODULATOR		1
+#define V4L2_OUTPUT_TYPE_ANALOG			2
+#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY	3
+
+/* capabilities flags */
+#define V4L2_OUT_CAP_DV_TIMINGS		0x00000002 /* Supports S_DV_TIMINGS */
+#define V4L2_OUT_CAP_CUSTOM_TIMINGS	V4L2_OUT_CAP_DV_TIMINGS /* For compatibility */
+#define V4L2_OUT_CAP_STD		0x00000004 /* Supports S_STD */
+#define V4L2_OUT_CAP_NATIVE_SIZE	0x00000008 /* Supports setting native size */
+
+/*
+ *	C O N T R O L S
+ */
+struct v4l2_control {
+	__u32		     id;
+	__s32		     value;
+};
+
+struct v4l2_ext_control {
+	__u32 id;
+	__u32 size;
+	__u32 reserved2[1];
+	union {
+		__s32 value;
+		__s64 value64;
+		char __user *string;
+		__u8 __user *p_u8;
+		__u16 __user *p_u16;
+		__u32 __user *p_u32;
+		void __user *ptr;
+	};
+} __attribute__ ((packed));
+
+struct v4l2_ext_controls {
+	union {
+#ifndef __KERNEL__
+		__u32 ctrl_class;
+#endif
+		__u32 which;
+	};
+	__u32 count;
+	__u32 error_idx;
+	__u32 reserved[2];
+	struct v4l2_ext_control *controls;
+};
+
+#define V4L2_CTRL_ID_MASK      	  (0x0fffffff)
+#ifndef __KERNEL__
+#define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
+#endif
+#define V4L2_CTRL_ID2WHICH(id)    ((id) & 0x0fff0000UL)
+#define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000)
+#define V4L2_CTRL_MAX_DIMS	  (4)
+#define V4L2_CTRL_WHICH_CUR_VAL   0
+#define V4L2_CTRL_WHICH_DEF_VAL   0x0f000000
+
+enum v4l2_ctrl_type {
+	V4L2_CTRL_TYPE_INTEGER	     = 1,
+	V4L2_CTRL_TYPE_BOOLEAN	     = 2,
+	V4L2_CTRL_TYPE_MENU	     = 3,
+	V4L2_CTRL_TYPE_BUTTON	     = 4,
+	V4L2_CTRL_TYPE_INTEGER64     = 5,
+	V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
+	V4L2_CTRL_TYPE_STRING        = 7,
+	V4L2_CTRL_TYPE_BITMASK       = 8,
+	V4L2_CTRL_TYPE_INTEGER_MENU  = 9,
+
+	/* Compound types are >= 0x0100 */
+	V4L2_CTRL_COMPOUND_TYPES     = 0x0100,
+	V4L2_CTRL_TYPE_U8	     = 0x0100,
+	V4L2_CTRL_TYPE_U16	     = 0x0101,
+	V4L2_CTRL_TYPE_U32	     = 0x0102,
+};
+
+/*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
+struct v4l2_queryctrl {
+	__u32		     id;
+	__u32		     type;	/* enum v4l2_ctrl_type */
+	__u8		     name[32];	/* Whatever */
+	__s32		     minimum;	/* Note signedness */
+	__s32		     maximum;
+	__s32		     step;
+	__s32		     default_value;
+	__u32                flags;
+	__u32		     reserved[2];
+};
+
+/*  Used in the VIDIOC_QUERY_EXT_CTRL ioctl for querying extended controls */
+struct v4l2_query_ext_ctrl {
+	__u32		     id;
+	__u32		     type;
+	char		     name[32];
+	__s64		     minimum;
+	__s64		     maximum;
+	__u64		     step;
+	__s64		     default_value;
+	__u32                flags;
+	__u32                elem_size;
+	__u32                elems;
+	__u32                nr_of_dims;
+	__u32                dims[V4L2_CTRL_MAX_DIMS];
+	__u32		     reserved[32];
+};
+
+/*  Used in the VIDIOC_QUERYMENU ioctl for querying menu items */
+struct v4l2_querymenu {
+	__u32		id;
+	__u32		index;
+	union {
+		__u8	name[32];	/* Whatever */
+		__s64	value;
+	};
+	__u32		reserved;
+} __attribute__ ((packed));
+
+/*  Control flags  */
+#define V4L2_CTRL_FLAG_DISABLED		0x0001
+#define V4L2_CTRL_FLAG_GRABBED		0x0002
+#define V4L2_CTRL_FLAG_READ_ONLY 	0x0004
+#define V4L2_CTRL_FLAG_UPDATE 		0x0008
+#define V4L2_CTRL_FLAG_INACTIVE 	0x0010
+#define V4L2_CTRL_FLAG_SLIDER 		0x0020
+#define V4L2_CTRL_FLAG_WRITE_ONLY 	0x0040
+#define V4L2_CTRL_FLAG_VOLATILE		0x0080
+#define V4L2_CTRL_FLAG_HAS_PAYLOAD	0x0100
+#define V4L2_CTRL_FLAG_EXECUTE_ON_WRITE	0x0200
+#define V4L2_CTRL_FLAG_MODIFY_LAYOUT	0x0400
+
+/*  Query flags, to be ORed with the control ID */
+#define V4L2_CTRL_FLAG_NEXT_CTRL	0x80000000
+#define V4L2_CTRL_FLAG_NEXT_COMPOUND	0x40000000
+
+/*  User-class control IDs defined by V4L2 */
+#define V4L2_CID_MAX_CTRLS		1024
+/*  IDs reserved for driver specific controls */
+#define V4L2_CID_PRIVATE_BASE		0x08000000
+
+
+/*
+ *	T U N I N G
+ */
+struct v4l2_tuner {
+	__u32                   index;
+	__u8			name[32];
+	__u32			type;	/* enum v4l2_tuner_type */
+	__u32			capability;
+	__u32			rangelow;
+	__u32			rangehigh;
+	__u32			rxsubchans;
+	__u32			audmode;
+	__s32			signal;
+	__s32			afc;
+	__u32			reserved[4];
+};
+
+struct v4l2_modulator {
+	__u32			index;
+	__u8			name[32];
+	__u32			capability;
+	__u32			rangelow;
+	__u32			rangehigh;
+	__u32			txsubchans;
+	__u32			type;	/* enum v4l2_tuner_type */
+	__u32			reserved[3];
+};
+
+/*  Flags for the 'capability' field */
+#define V4L2_TUNER_CAP_LOW		0x0001
+#define V4L2_TUNER_CAP_NORM		0x0002
+#define V4L2_TUNER_CAP_HWSEEK_BOUNDED	0x0004
+#define V4L2_TUNER_CAP_HWSEEK_WRAP	0x0008
+#define V4L2_TUNER_CAP_STEREO		0x0010
+#define V4L2_TUNER_CAP_LANG2		0x0020
+#define V4L2_TUNER_CAP_SAP		0x0020
+#define V4L2_TUNER_CAP_LANG1		0x0040
+#define V4L2_TUNER_CAP_RDS		0x0080
+#define V4L2_TUNER_CAP_RDS_BLOCK_IO	0x0100
+#define V4L2_TUNER_CAP_RDS_CONTROLS	0x0200
+#define V4L2_TUNER_CAP_FREQ_BANDS	0x0400
+#define V4L2_TUNER_CAP_HWSEEK_PROG_LIM	0x0800
+#define V4L2_TUNER_CAP_1HZ		0x1000
+
+/*  Flags for the 'rxsubchans' field */
+#define V4L2_TUNER_SUB_MONO		0x0001
+#define V4L2_TUNER_SUB_STEREO		0x0002
+#define V4L2_TUNER_SUB_LANG2		0x0004
+#define V4L2_TUNER_SUB_SAP		0x0004
+#define V4L2_TUNER_SUB_LANG1		0x0008
+#define V4L2_TUNER_SUB_RDS		0x0010
+
+/*  Values for the 'audmode' field */
+#define V4L2_TUNER_MODE_MONO		0x0000
+#define V4L2_TUNER_MODE_STEREO		0x0001
+#define V4L2_TUNER_MODE_LANG2		0x0002
+#define V4L2_TUNER_MODE_SAP		0x0002
+#define V4L2_TUNER_MODE_LANG1		0x0003
+#define V4L2_TUNER_MODE_LANG1_LANG2	0x0004
+
+struct v4l2_frequency {
+	__u32	tuner;
+	__u32	type;	/* enum v4l2_tuner_type */
+	__u32	frequency;
+	__u32	reserved[8];
+};
+
+#define V4L2_BAND_MODULATION_VSB	(1 << 1)
+#define V4L2_BAND_MODULATION_FM		(1 << 2)
+#define V4L2_BAND_MODULATION_AM		(1 << 3)
+
+struct v4l2_frequency_band {
+	__u32	tuner;
+	__u32	type;	/* enum v4l2_tuner_type */
+	__u32	index;
+	__u32	capability;
+	__u32	rangelow;
+	__u32	rangehigh;
+	__u32	modulation;
+	__u32	reserved[9];
+};
+
+struct v4l2_hw_freq_seek {
+	__u32	tuner;
+	__u32	type;	/* enum v4l2_tuner_type */
+	__u32	seek_upward;
+	__u32	wrap_around;
+	__u32	spacing;
+	__u32	rangelow;
+	__u32	rangehigh;
+	__u32	reserved[5];
+};
+
+/*
+ *	R D S
+ */
+
+struct v4l2_rds_data {
+	__u8 	lsb;
+	__u8 	msb;
+	__u8 	block;
+} __attribute__ ((packed));
+
+#define V4L2_RDS_BLOCK_MSK 	 0x7
+#define V4L2_RDS_BLOCK_A 	 0
+#define V4L2_RDS_BLOCK_B 	 1
+#define V4L2_RDS_BLOCK_C 	 2
+#define V4L2_RDS_BLOCK_D 	 3
+#define V4L2_RDS_BLOCK_C_ALT 	 4
+#define V4L2_RDS_BLOCK_INVALID 	 7
+
+#define V4L2_RDS_BLOCK_CORRECTED 0x40
+#define V4L2_RDS_BLOCK_ERROR 	 0x80
+
+/*
+ *	A U D I O
+ */
+struct v4l2_audio {
+	__u32	index;
+	__u8	name[32];
+	__u32	capability;
+	__u32	mode;
+	__u32	reserved[2];
+};
+
+/*  Flags for the 'capability' field */
+#define V4L2_AUDCAP_STEREO		0x00001
+#define V4L2_AUDCAP_AVL			0x00002
+
+/*  Flags for the 'mode' field */
+#define V4L2_AUDMODE_AVL		0x00001
+
+struct v4l2_audioout {
+	__u32	index;
+	__u8	name[32];
+	__u32	capability;
+	__u32	mode;
+	__u32	reserved[2];
+};
+
+/*
+ *	M P E G   S E R V I C E S
+ */
+#if 1
+#define V4L2_ENC_IDX_FRAME_I    (0)
+#define V4L2_ENC_IDX_FRAME_P    (1)
+#define V4L2_ENC_IDX_FRAME_B    (2)
+#define V4L2_ENC_IDX_FRAME_MASK (0xf)
+
+struct v4l2_enc_idx_entry {
+	__u64 offset;
+	__u64 pts;
+	__u32 length;
+	__u32 flags;
+	__u32 reserved[2];
+};
+
+#define V4L2_ENC_IDX_ENTRIES (64)
+struct v4l2_enc_idx {
+	__u32 entries;
+	__u32 entries_cap;
+	__u32 reserved[4];
+	struct v4l2_enc_idx_entry entry[V4L2_ENC_IDX_ENTRIES];
+};
+
+
+#define V4L2_ENC_CMD_START      (0)
+#define V4L2_ENC_CMD_STOP       (1)
+#define V4L2_ENC_CMD_PAUSE      (2)
+#define V4L2_ENC_CMD_RESUME     (3)
+
+/* Flags for V4L2_ENC_CMD_STOP */
+#define V4L2_ENC_CMD_STOP_AT_GOP_END    (1 << 0)
+
+struct v4l2_encoder_cmd {
+	__u32 cmd;
+	__u32 flags;
+	union {
+		struct {
+			__u32 data[8];
+		} raw;
+	};
+};
+
+/* Decoder commands */
+#define V4L2_DEC_CMD_START       (0)
+#define V4L2_DEC_CMD_STOP        (1)
+#define V4L2_DEC_CMD_PAUSE       (2)
+#define V4L2_DEC_CMD_RESUME      (3)
+
+/* Flags for V4L2_DEC_CMD_START */
+#define V4L2_DEC_CMD_START_MUTE_AUDIO	(1 << 0)
+
+/* Flags for V4L2_DEC_CMD_PAUSE */
+#define V4L2_DEC_CMD_PAUSE_TO_BLACK	(1 << 0)
+
+/* Flags for V4L2_DEC_CMD_STOP */
+#define V4L2_DEC_CMD_STOP_TO_BLACK	(1 << 0)
+#define V4L2_DEC_CMD_STOP_IMMEDIATELY	(1 << 1)
+
+/* Play format requirements (returned by the driver): */
+
+/* The decoder has no special format requirements */
+#define V4L2_DEC_START_FMT_NONE		(0)
+/* The decoder requires full GOPs */
+#define V4L2_DEC_START_FMT_GOP		(1)
+
+/* The structure must be zeroed before use by the application
+   This ensures it can be extended safely in the future. */
+struct v4l2_decoder_cmd {
+	__u32 cmd;
+	__u32 flags;
+	union {
+		struct {
+			__u64 pts;
+		} stop;
+
+		struct {
+			/* 0 or 1000 specifies normal speed,
+			   1 specifies forward single stepping,
+			   -1 specifies backward single stepping,
+			   >1: playback at speed/1000 of the normal speed,
+			   <-1: reverse playback at (-speed/1000) of the normal speed. */
+			__s32 speed;
+			__u32 format;
+		} start;
+
+		struct {
+			__u32 data[16];
+		} raw;
+	};
+};
+#endif
+
+
+/*
+ *	D A T A   S E R V I C E S   ( V B I )
+ *
+ *	Data services API by Michael Schimek
+ */
+
+/* Raw VBI */
+struct v4l2_vbi_format {
+	__u32	sampling_rate;		/* in 1 Hz */
+	__u32	offset;
+	__u32	samples_per_line;
+	__u32	sample_format;		/* V4L2_PIX_FMT_* */
+	__s32	start[2];
+	__u32	count[2];
+	__u32	flags;			/* V4L2_VBI_* */
+	__u32	reserved[2];		/* must be zero */
+};
+
+/*  VBI flags  */
+#define V4L2_VBI_UNSYNC		(1 << 0)
+#define V4L2_VBI_INTERLACED	(1 << 1)
+
+/* ITU-R start lines for each field */
+#define V4L2_VBI_ITU_525_F1_START (1)
+#define V4L2_VBI_ITU_525_F2_START (264)
+#define V4L2_VBI_ITU_625_F1_START (1)
+#define V4L2_VBI_ITU_625_F2_START (314)
+
+/* Sliced VBI
+ *
+ *    This implements is a proposal V4L2 API to allow SLICED VBI
+ * required for some hardware encoders. It should change without
+ * notice in the definitive implementation.
+ */
+
+struct v4l2_sliced_vbi_format {
+	__u16   service_set;
+	/* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
+	   service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
+				 (equals frame lines 313-336 for 625 line video
+				  standards, 263-286 for 525 line standards) */
+	__u16   service_lines[2][24];
+	__u32   io_size;
+	__u32   reserved[2];            /* must be zero */
+};
+
+/* Teletext World System Teletext
+   (WST), defined on ITU-R BT.653-2 */
+#define V4L2_SLICED_TELETEXT_B          (0x0001)
+/* Video Program System, defined on ETS 300 231*/
+#define V4L2_SLICED_VPS                 (0x0400)
+/* Closed Caption, defined on EIA-608 */
+#define V4L2_SLICED_CAPTION_525         (0x1000)
+/* Wide Screen System, defined on ITU-R BT1119.1 */
+#define V4L2_SLICED_WSS_625             (0x4000)
+
+#define V4L2_SLICED_VBI_525             (V4L2_SLICED_CAPTION_525)
+#define V4L2_SLICED_VBI_625             (V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625)
+
+struct v4l2_sliced_vbi_cap {
+	__u16   service_set;
+	/* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
+	   service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
+				 (equals frame lines 313-336 for 625 line video
+				  standards, 263-286 for 525 line standards) */
+	__u16   service_lines[2][24];
+	__u32	type;		/* enum v4l2_buf_type */
+	__u32   reserved[3];    /* must be 0 */
+};
+
+struct v4l2_sliced_vbi_data {
+	__u32   id;
+	__u32   field;          /* 0: first field, 1: second field */
+	__u32   line;           /* 1-23 */
+	__u32   reserved;       /* must be 0 */
+	__u8    data[48];
+};
+
+/*
+ * Sliced VBI data inserted into MPEG Streams
+ */
+
+/*
+ * V4L2_MPEG_STREAM_VBI_FMT_IVTV:
+ *
+ * Structure of payload contained in an MPEG 2 Private Stream 1 PES Packet in an
+ * MPEG-2 Program Pack that contains V4L2_MPEG_STREAM_VBI_FMT_IVTV Sliced VBI
+ * data
+ *
+ * Note, the MPEG-2 Program Pack and Private Stream 1 PES packet header
+ * definitions are not included here.  See the MPEG-2 specifications for details
+ * on these headers.
+ */
+
+/* Line type IDs */
+#define V4L2_MPEG_VBI_IVTV_TELETEXT_B     (1)
+#define V4L2_MPEG_VBI_IVTV_CAPTION_525    (4)
+#define V4L2_MPEG_VBI_IVTV_WSS_625        (5)
+#define V4L2_MPEG_VBI_IVTV_VPS            (7)
+
+struct v4l2_mpeg_vbi_itv0_line {
+	__u8 id;	/* One of V4L2_MPEG_VBI_IVTV_* above */
+	__u8 data[42];	/* Sliced VBI data for the line */
+} __attribute__ ((packed));
+
+struct v4l2_mpeg_vbi_itv0 {
+	__le32 linemask[2]; /* Bitmasks of VBI service lines present */
+	struct v4l2_mpeg_vbi_itv0_line line[35];
+} __attribute__ ((packed));
+
+struct v4l2_mpeg_vbi_ITV0 {
+	struct v4l2_mpeg_vbi_itv0_line line[36];
+} __attribute__ ((packed));
+
+#define V4L2_MPEG_VBI_IVTV_MAGIC0	"itv0"
+#define V4L2_MPEG_VBI_IVTV_MAGIC1	"ITV0"
+
+struct v4l2_mpeg_vbi_fmt_ivtv {
+	__u8 magic[4];
+	union {
+		struct v4l2_mpeg_vbi_itv0 itv0;
+		struct v4l2_mpeg_vbi_ITV0 ITV0;
+	};
+} __attribute__ ((packed));
+
+/*
+ *	A G G R E G A T E   S T R U C T U R E S
+ */
+
+/**
+ * struct v4l2_plane_pix_format - additional, per-plane format definition
+ * @sizeimage:		maximum size in bytes required for data, for which
+ *			this plane will be used
+ * @bytesperline:	distance in bytes between the leftmost pixels in two
+ *			adjacent lines
+ */
+struct v4l2_plane_pix_format {
+	__u32		sizeimage;
+	__u32		bytesperline;
+	__u16		reserved[6];
+} __attribute__ ((packed));
+
+/**
+ * struct v4l2_pix_format_mplane - multiplanar format definition
+ * @width:		image width in pixels
+ * @height:		image height in pixels
+ * @pixelformat:	little endian four character code (fourcc)
+ * @field:		enum v4l2_field; field order (for interlaced video)
+ * @colorspace:		enum v4l2_colorspace; supplemental to pixelformat
+ * @plane_fmt:		per-plane information
+ * @num_planes:		number of planes for this format
+ * @flags:		format flags (V4L2_PIX_FMT_FLAG_*)
+ * @ycbcr_enc:		enum v4l2_ycbcr_encoding, Y'CbCr encoding
+ * @quantization:	enum v4l2_quantization, colorspace quantization
+ * @xfer_func:		enum v4l2_xfer_func, colorspace transfer function
+ */
+struct v4l2_pix_format_mplane {
+	__u32				width;
+	__u32				height;
+	__u32				pixelformat;
+	__u32				field;
+	__u32				colorspace;
+
+	struct v4l2_plane_pix_format	plane_fmt[VIDEO_MAX_PLANES];
+	__u8				num_planes;
+	__u8				flags;
+	 union {
+		__u8				ycbcr_enc;
+		__u8				hsv_enc;
+	};
+	__u8				quantization;
+	__u8				xfer_func;
+	__u8				reserved[7];
+} __attribute__ ((packed));
+
+/**
+ * struct v4l2_sdr_format - SDR format definition
+ * @pixelformat:	little endian four character code (fourcc)
+ * @buffersize:		maximum size in bytes required for data
+ */
+struct v4l2_sdr_format {
+	__u32				pixelformat;
+	__u32				buffersize;
+	__u8				reserved[24];
+} __attribute__ ((packed));
+
+/**
+ * struct v4l2_meta_format - metadata format definition
+ * @dataformat:		little endian four character code (fourcc)
+ * @buffersize:		maximum size in bytes required for data
+ */
+struct v4l2_meta_format {
+	__u32				dataformat;
+	__u32				buffersize;
+} __attribute__ ((packed));
+
+/**
+ * struct v4l2_format - stream data format
+ * @type:	enum v4l2_buf_type; type of the data stream
+ * @pix:	definition of an image format
+ * @pix_mp:	definition of a multiplanar image format
+ * @win:	definition of an overlaid image
+ * @vbi:	raw VBI capture or output parameters
+ * @sliced:	sliced VBI capture or output parameters
+ * @raw_data:	placeholder for future extensions and custom formats
+ */
+struct v4l2_format {
+	__u32	 type;
+	union {
+		struct v4l2_pix_format		pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
+		struct v4l2_pix_format_mplane	pix_mp;  /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
+		struct v4l2_window		win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
+		struct v4l2_vbi_format		vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */
+		struct v4l2_sliced_vbi_format	sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
+		struct v4l2_sdr_format		sdr;     /* V4L2_BUF_TYPE_SDR_CAPTURE */
+		struct v4l2_meta_format		meta;    /* V4L2_BUF_TYPE_META_CAPTURE */
+		__u8	raw_data[200];                   /* user-defined */
+	} fmt;
+};
+
+/*	Stream type-dependent parameters
+ */
+struct v4l2_streamparm {
+	__u32	 type;			/* enum v4l2_buf_type */
+	union {
+		struct v4l2_captureparm	capture;
+		struct v4l2_outputparm	output;
+		__u8	raw_data[200];  /* user-defined */
+	} parm;
+};
+
+/*
+ *	E V E N T S
+ */
+
+#define V4L2_EVENT_ALL				0
+#define V4L2_EVENT_VSYNC			1
+#define V4L2_EVENT_EOS				2
+#define V4L2_EVENT_CTRL				3
+#define V4L2_EVENT_FRAME_SYNC			4
+#define V4L2_EVENT_SOURCE_CHANGE		5
+#define V4L2_EVENT_MOTION_DET			6
+#define V4L2_EVENT_PRIVATE_START		0x08000000
+
+/* Payload for V4L2_EVENT_VSYNC */
+struct v4l2_event_vsync {
+	/* Can be V4L2_FIELD_ANY, _NONE, _TOP or _BOTTOM */
+	__u8 field;
+} __attribute__ ((packed));
+
+/* Payload for V4L2_EVENT_CTRL */
+#define V4L2_EVENT_CTRL_CH_VALUE		(1 << 0)
+#define V4L2_EVENT_CTRL_CH_FLAGS		(1 << 1)
+#define V4L2_EVENT_CTRL_CH_RANGE		(1 << 2)
+
+struct v4l2_event_ctrl {
+	__u32 changes;
+	__u32 type;
+	union {
+		__s32 value;
+		__s64 value64;
+	};
+	__u32 flags;
+	__s32 minimum;
+	__s32 maximum;
+	__s32 step;
+	__s32 default_value;
+};
+
+struct v4l2_event_frame_sync {
+	__u32 frame_sequence;
+};
+
+#define V4L2_EVENT_SRC_CH_RESOLUTION		(1 << 0)
+
+struct v4l2_event_src_change {
+	__u32 changes;
+};
+
+#define V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ	(1 << 0)
+
+/**
+ * struct v4l2_event_motion_det - motion detection event
+ * @flags:             if V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ is set, then the
+ *                     frame_sequence field is valid.
+ * @frame_sequence:    the frame sequence number associated with this event.
+ * @region_mask:       which regions detected motion.
+ */
+struct v4l2_event_motion_det {
+	__u32 flags;
+	__u32 frame_sequence;
+	__u32 region_mask;
+};
+
+struct v4l2_event {
+	__u32				type;
+	union {
+		struct v4l2_event_vsync		vsync;
+		struct v4l2_event_ctrl		ctrl;
+		struct v4l2_event_frame_sync	frame_sync;
+		struct v4l2_event_src_change	src_change;
+		struct v4l2_event_motion_det	motion_det;
+		__u8				data[64];
+	} u;
+	__u32				pending;
+	__u32				sequence;
+	struct timespec			timestamp;
+	__u32				id;
+	__u32				reserved[8];
+};
+
+#define V4L2_EVENT_SUB_FL_SEND_INITIAL		(1 << 0)
+#define V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK	(1 << 1)
+
+struct v4l2_event_subscription {
+	__u32				type;
+	__u32				id;
+	__u32				flags;
+	__u32				reserved[5];
+};
+
+/*
+ *	A D V A N C E D   D E B U G G I N G
+ *
+ *	NOTE: EXPERIMENTAL API, NEVER RELY ON THIS IN APPLICATIONS!
+ *	FOR DEBUGGING, TESTING AND INTERNAL USE ONLY!
+ */
+
+/* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */
+
+#define V4L2_CHIP_MATCH_BRIDGE      0  /* Match against chip ID on the bridge (0 for the bridge) */
+#define V4L2_CHIP_MATCH_SUBDEV      4  /* Match against subdev index */
+
+/* The following four defines are no longer in use */
+#define V4L2_CHIP_MATCH_HOST V4L2_CHIP_MATCH_BRIDGE
+#define V4L2_CHIP_MATCH_I2C_DRIVER  1  /* Match against I2C driver name */
+#define V4L2_CHIP_MATCH_I2C_ADDR    2  /* Match against I2C 7-bit address */
+#define V4L2_CHIP_MATCH_AC97        3  /* Match against ancillary AC97 chip */
+
+struct v4l2_dbg_match {
+	__u32 type; /* Match type */
+	union {     /* Match this chip, meaning determined by type */
+		__u32 addr;
+		char name[32];
+	};
+} __attribute__ ((packed));
+
+struct v4l2_dbg_register {
+	struct v4l2_dbg_match match;
+	__u32 size;	/* register size in bytes */
+	__u64 reg;
+	__u64 val;
+} __attribute__ ((packed));
+
+#define V4L2_CHIP_FL_READABLE (1 << 0)
+#define V4L2_CHIP_FL_WRITABLE (1 << 1)
+
+/* VIDIOC_DBG_G_CHIP_INFO */
+struct v4l2_dbg_chip_info {
+	struct v4l2_dbg_match match;
+	char name[32];
+	__u32 flags;
+	__u32 reserved[32];
+} __attribute__ ((packed));
+
+/**
+ * struct v4l2_create_buffers - VIDIOC_CREATE_BUFS argument
+ * @index:	on return, index of the first created buffer
+ * @count:	entry: number of requested buffers,
+ *		return: number of created buffers
+ * @memory:	enum v4l2_memory; buffer memory type
+ * @format:	frame format, for which buffers are requested
+ * @reserved:	future extensions
+ */
+struct v4l2_create_buffers {
+	__u32			index;
+	__u32			count;
+	__u32			memory;
+	struct v4l2_format	format;
+	__u32			reserved[8];
+};
+
+/*
+ *	I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
+ *
+ */
+#define VIDIOC_QUERYCAP		 _IOR('V',  0, struct v4l2_capability)
+#define VIDIOC_RESERVED		  _IO('V',  1)
+#define VIDIOC_ENUM_FMT         _IOWR('V',  2, struct v4l2_fmtdesc)
+#define VIDIOC_G_FMT		_IOWR('V',  4, struct v4l2_format)
+#define VIDIOC_S_FMT		_IOWR('V',  5, struct v4l2_format)
+#define VIDIOC_REQBUFS		_IOWR('V',  8, struct v4l2_requestbuffers)
+#define VIDIOC_QUERYBUF		_IOWR('V',  9, struct v4l2_buffer)
+#define VIDIOC_G_FBUF		 _IOR('V', 10, struct v4l2_framebuffer)
+#define VIDIOC_S_FBUF		 _IOW('V', 11, struct v4l2_framebuffer)
+#define VIDIOC_OVERLAY		 _IOW('V', 14, int)
+#define VIDIOC_QBUF		_IOWR('V', 15, struct v4l2_buffer)
+#define VIDIOC_EXPBUF		_IOWR('V', 16, struct v4l2_exportbuffer)
+#define VIDIOC_DQBUF		_IOWR('V', 17, struct v4l2_buffer)
+#define VIDIOC_STREAMON		 _IOW('V', 18, int)
+#define VIDIOC_STREAMOFF	 _IOW('V', 19, int)
+#define VIDIOC_G_PARM		_IOWR('V', 21, struct v4l2_streamparm)
+#define VIDIOC_S_PARM		_IOWR('V', 22, struct v4l2_streamparm)
+#define VIDIOC_G_STD		 _IOR('V', 23, v4l2_std_id)
+#define VIDIOC_S_STD		 _IOW('V', 24, v4l2_std_id)
+#define VIDIOC_ENUMSTD		_IOWR('V', 25, struct v4l2_standard)
+#define VIDIOC_ENUMINPUT	_IOWR('V', 26, struct v4l2_input)
+#define VIDIOC_G_CTRL		_IOWR('V', 27, struct v4l2_control)
+#define VIDIOC_S_CTRL		_IOWR('V', 28, struct v4l2_control)
+#define VIDIOC_G_TUNER		_IOWR('V', 29, struct v4l2_tuner)
+#define VIDIOC_S_TUNER		 _IOW('V', 30, struct v4l2_tuner)
+#define VIDIOC_G_AUDIO		 _IOR('V', 33, struct v4l2_audio)
+#define VIDIOC_S_AUDIO		 _IOW('V', 34, struct v4l2_audio)
+#define VIDIOC_QUERYCTRL	_IOWR('V', 36, struct v4l2_queryctrl)
+#define VIDIOC_QUERYMENU	_IOWR('V', 37, struct v4l2_querymenu)
+#define VIDIOC_G_INPUT		 _IOR('V', 38, int)
+#define VIDIOC_S_INPUT		_IOWR('V', 39, int)
+#define VIDIOC_G_EDID		_IOWR('V', 40, struct v4l2_edid)
+#define VIDIOC_S_EDID		_IOWR('V', 41, struct v4l2_edid)
+#define VIDIOC_G_OUTPUT		 _IOR('V', 46, int)
+#define VIDIOC_S_OUTPUT		_IOWR('V', 47, int)
+#define VIDIOC_ENUMOUTPUT	_IOWR('V', 48, struct v4l2_output)
+#define VIDIOC_G_AUDOUT		 _IOR('V', 49, struct v4l2_audioout)
+#define VIDIOC_S_AUDOUT		 _IOW('V', 50, struct v4l2_audioout)
+#define VIDIOC_G_MODULATOR	_IOWR('V', 54, struct v4l2_modulator)
+#define VIDIOC_S_MODULATOR	 _IOW('V', 55, struct v4l2_modulator)
+#define VIDIOC_G_FREQUENCY	_IOWR('V', 56, struct v4l2_frequency)
+#define VIDIOC_S_FREQUENCY	 _IOW('V', 57, struct v4l2_frequency)
+#define VIDIOC_CROPCAP		_IOWR('V', 58, struct v4l2_cropcap)
+#define VIDIOC_G_CROP		_IOWR('V', 59, struct v4l2_crop)
+#define VIDIOC_S_CROP		 _IOW('V', 60, struct v4l2_crop)
+#define VIDIOC_G_JPEGCOMP	 _IOR('V', 61, struct v4l2_jpegcompression)
+#define VIDIOC_S_JPEGCOMP	 _IOW('V', 62, struct v4l2_jpegcompression)
+#define VIDIOC_QUERYSTD      	 _IOR('V', 63, v4l2_std_id)
+#define VIDIOC_TRY_FMT      	_IOWR('V', 64, struct v4l2_format)
+#define VIDIOC_ENUMAUDIO	_IOWR('V', 65, struct v4l2_audio)
+#define VIDIOC_ENUMAUDOUT	_IOWR('V', 66, struct v4l2_audioout)
+#define VIDIOC_G_PRIORITY	 _IOR('V', 67, __u32) /* enum v4l2_priority */
+#define VIDIOC_S_PRIORITY	 _IOW('V', 68, __u32) /* enum v4l2_priority */
+#define VIDIOC_G_SLICED_VBI_CAP _IOWR('V', 69, struct v4l2_sliced_vbi_cap)
+#define VIDIOC_LOG_STATUS         _IO('V', 70)
+#define VIDIOC_G_EXT_CTRLS	_IOWR('V', 71, struct v4l2_ext_controls)
+#define VIDIOC_S_EXT_CTRLS	_IOWR('V', 72, struct v4l2_ext_controls)
+#define VIDIOC_TRY_EXT_CTRLS	_IOWR('V', 73, struct v4l2_ext_controls)
+#define VIDIOC_ENUM_FRAMESIZES	_IOWR('V', 74, struct v4l2_frmsizeenum)
+#define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct v4l2_frmivalenum)
+#define VIDIOC_G_ENC_INDEX       _IOR('V', 76, struct v4l2_enc_idx)
+#define VIDIOC_ENCODER_CMD      _IOWR('V', 77, struct v4l2_encoder_cmd)
+#define VIDIOC_TRY_ENCODER_CMD  _IOWR('V', 78, struct v4l2_encoder_cmd)
+
+/*
+ * Experimental, meant for debugging, testing and internal use.
+ * Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined.
+ * You must be root to use these ioctls. Never use these in applications!
+ */
+#define	VIDIOC_DBG_S_REGISTER 	 _IOW('V', 79, struct v4l2_dbg_register)
+#define	VIDIOC_DBG_G_REGISTER 	_IOWR('V', 80, struct v4l2_dbg_register)
+
+#define VIDIOC_S_HW_FREQ_SEEK	 _IOW('V', 82, struct v4l2_hw_freq_seek)
+#define	VIDIOC_S_DV_TIMINGS	_IOWR('V', 87, struct v4l2_dv_timings)
+#define	VIDIOC_G_DV_TIMINGS	_IOWR('V', 88, struct v4l2_dv_timings)
+#define	VIDIOC_DQEVENT		 _IOR('V', 89, struct v4l2_event)
+#define	VIDIOC_SUBSCRIBE_EVENT	 _IOW('V', 90, struct v4l2_event_subscription)
+#define	VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription)
+#define VIDIOC_CREATE_BUFS	_IOWR('V', 92, struct v4l2_create_buffers)
+#define VIDIOC_PREPARE_BUF	_IOWR('V', 93, struct v4l2_buffer)
+#define VIDIOC_G_SELECTION	_IOWR('V', 94, struct v4l2_selection)
+#define VIDIOC_S_SELECTION	_IOWR('V', 95, struct v4l2_selection)
+#define VIDIOC_DECODER_CMD	_IOWR('V', 96, struct v4l2_decoder_cmd)
+#define VIDIOC_TRY_DECODER_CMD	_IOWR('V', 97, struct v4l2_decoder_cmd)
+#define VIDIOC_ENUM_DV_TIMINGS  _IOWR('V', 98, struct v4l2_enum_dv_timings)
+#define VIDIOC_QUERY_DV_TIMINGS  _IOR('V', 99, struct v4l2_dv_timings)
+#define VIDIOC_DV_TIMINGS_CAP   _IOWR('V', 100, struct v4l2_dv_timings_cap)
+#define VIDIOC_ENUM_FREQ_BANDS	_IOWR('V', 101, struct v4l2_frequency_band)
+
+/*
+ * Experimental, meant for debugging, testing and internal use.
+ * Never use this in applications!
+ */
+#define VIDIOC_DBG_G_CHIP_INFO  _IOWR('V', 102, struct v4l2_dbg_chip_info)
+
+#define VIDIOC_QUERY_EXT_CTRL	_IOWR('V', 103, struct v4l2_query_ext_ctrl)
+
+/* Reminder: when adding new ioctls please add support for them to
+   drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */
+
+#define BASE_VIDIOC_PRIVATE	192		/* 192-255 are private */
+
+#endif /* _UAPI__LINUX_VIDEODEV2_H */
diff --git a/sys/v4l2/gstv4l2.c b/sys/v4l2/gstv4l2.c
new file mode 100644
index 0000000..07a2873
--- /dev/null
+++ b/sys/v4l2/gstv4l2.c
@@ -0,0 +1,272 @@
+/* GStreamer
+ *
+ * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *               2006 Edgard Lima <edgard.lima@gmail.com>
+ *
+ * gstv4l2.c: plugin for v4l2 elements
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE            /* O_CLOEXEC */
+#endif
+
+#include "gst/gst-i18n-plugin.h"
+
+#include <gst/gst.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "ext/videodev2.h"
+#include "v4l2-utils.h"
+
+#include "gstv4l2object.h"
+#include "gstv4l2src.h"
+#include "gstv4l2sink.h"
+#include "gstv4l2radio.h"
+#include "gstv4l2videodec.h"
+#include "gstv4l2h263enc.h"
+#include "gstv4l2h264enc.h"
+#include "gstv4l2mpeg4enc.h"
+#include "gstv4l2vp8enc.h"
+#include "gstv4l2vp9enc.h"
+#include "gstv4l2deviceprovider.h"
+#include "gstv4l2transform.h"
+
+/* used in gstv4l2object.c and v4l2_calls.c */
+GST_DEBUG_CATEGORY (v4l2_debug);
+#define GST_CAT_DEFAULT v4l2_debug
+
+#ifdef GST_V4L2_ENABLE_PROBE
+/* This is a minimalist probe, for speed, we only enumerate formats */
+static GstCaps *
+gst_v4l2_probe_template_caps (const gchar * device, gint video_fd,
+    enum v4l2_buf_type type)
+{
+  gint n;
+  struct v4l2_fmtdesc format;
+  GstCaps *caps;
+
+  GST_DEBUG ("Getting %s format enumerations", device);
+  caps = gst_caps_new_empty ();
+
+  for (n = 0;; n++) {
+    GstStructure *template;
+
+    memset (&format, 0, sizeof (format));
+
+    format.index = n;
+    format.type = type;
+
+    if (ioctl (video_fd, VIDIOC_ENUM_FMT, &format) < 0)
+      break;                    /* end of enumeration */
+
+    GST_LOG ("index:       %u", format.index);
+    GST_LOG ("type:        %d", format.type);
+    GST_LOG ("flags:       %08x", format.flags);
+    GST_LOG ("description: '%s'", format.description);
+    GST_LOG ("pixelformat: %" GST_FOURCC_FORMAT,
+        GST_FOURCC_ARGS (format.pixelformat));
+
+    template = gst_v4l2_object_v4l2fourcc_to_structure (format.pixelformat);
+
+    if (template) {
+      GstStructure *alt_t = NULL;
+
+      switch (format.pixelformat) {
+        case V4L2_PIX_FMT_RGB32:
+          alt_t = gst_structure_copy (template);
+          gst_structure_set (alt_t, "format", G_TYPE_STRING, "ARGB", NULL);
+          break;
+        case V4L2_PIX_FMT_BGR32:
+          alt_t = gst_structure_copy (template);
+          gst_structure_set (alt_t, "format", G_TYPE_STRING, "BGRA", NULL);
+        default:
+          break;
+      }
+
+      gst_caps_append_structure (caps, template);
+
+      if (alt_t)
+        gst_caps_append_structure (caps, alt_t);
+    }
+  }
+
+  return gst_caps_simplify (caps);
+}
+
+static gboolean
+gst_v4l2_probe_and_register (GstPlugin * plugin)
+{
+  GstV4l2Iterator *it;
+  gint video_fd = -1;
+  struct v4l2_capability vcap;
+  guint32 device_caps;
+
+  it = gst_v4l2_iterator_new ();
+
+  while (gst_v4l2_iterator_next (it)) {
+    GstCaps *src_caps, *sink_caps;
+    gchar *basename;
+
+    if (video_fd >= 0)
+      close (video_fd);
+
+    video_fd = open (it->device_path, O_RDWR | O_CLOEXEC);
+
+    if (video_fd == -1) {
+      GST_DEBUG ("Failed to open %s: %s", it->device_path, g_strerror (errno));
+      continue;
+    }
+
+    memset (&vcap, 0, sizeof (vcap));
+
+    if (ioctl (video_fd, VIDIOC_QUERYCAP, &vcap) < 0) {
+      GST_DEBUG ("Failed to get device capabilities: %s", g_strerror (errno));
+      continue;
+    }
+
+    if (vcap.capabilities & V4L2_CAP_DEVICE_CAPS)
+      device_caps = vcap.device_caps;
+    else
+      device_caps = vcap.capabilities;
+
+    if (!((device_caps & (V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE)) ||
+            /* But legacy driver may expose both CAPTURE and OUTPUT */
+            ((device_caps &
+                    (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) &&
+                (device_caps &
+                    (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE)))))
+      continue;
+
+    GST_DEBUG ("Probing '%s' located at '%s'",
+        it->device_name ? it->device_name : (const gchar *) vcap.driver,
+        it->device_path);
+
+    /* get sink supported format (no MPLANE for codec) */
+    sink_caps = gst_caps_merge (gst_v4l2_probe_template_caps (it->device_path,
+            video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT),
+        gst_v4l2_probe_template_caps (it->device_path, video_fd,
+            V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE));
+
+    /* get src supported format */
+    src_caps = gst_caps_merge (gst_v4l2_probe_template_caps (it->device_path,
+            video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE),
+        gst_v4l2_probe_template_caps (it->device_path, video_fd,
+            V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE));
+
+    /* Skip devices without any supported formats */
+    if (gst_caps_is_empty (sink_caps) || gst_caps_is_empty (src_caps)) {
+      gst_caps_unref (sink_caps);
+      gst_caps_unref (src_caps);
+      continue;
+    }
+
+    basename = g_path_get_basename (it->device_path);
+
+    if (gst_v4l2_is_video_dec (sink_caps, src_caps)) {
+      gst_v4l2_video_dec_register (plugin, basename, it->device_path,
+          sink_caps, src_caps);
+    } else if (gst_v4l2_is_video_enc (sink_caps, src_caps, NULL)) {
+      if (gst_v4l2_is_h264_enc (sink_caps, src_caps))
+        gst_v4l2_h264_enc_register (plugin, basename, it->device_path,
+            sink_caps, src_caps);
+
+      if (gst_v4l2_is_mpeg4_enc (sink_caps, src_caps))
+        gst_v4l2_mpeg4_enc_register (plugin, basename, it->device_path,
+            sink_caps, src_caps);
+
+      if (gst_v4l2_is_h263_enc (sink_caps, src_caps))
+        gst_v4l2_h263_enc_register (plugin, basename, it->device_path,
+            sink_caps, src_caps);
+
+      if (gst_v4l2_is_vp8_enc (sink_caps, src_caps))
+        gst_v4l2_vp8_enc_register (plugin, basename, it->device_path,
+            sink_caps, src_caps);
+
+      if (gst_v4l2_is_vp9_enc (sink_caps, src_caps))
+        gst_v4l2_vp9_enc_register (plugin, basename, it->device_path,
+            sink_caps, src_caps);
+    } else if (gst_v4l2_is_transform (sink_caps, src_caps)) {
+      gst_v4l2_transform_register (plugin, basename, it->device_path,
+          sink_caps, src_caps);
+    }
+    /* else if ( ... etc. */
+
+    gst_caps_unref (sink_caps);
+    gst_caps_unref (src_caps);
+    g_free (basename);
+  }
+
+  if (video_fd >= 0)
+    close (video_fd);
+
+  gst_v4l2_iterator_free (it);
+
+  return TRUE;
+}
+#endif
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  const gchar *paths[] = { "/dev", "/dev/v4l2", NULL };
+  const gchar *names[] = { "video", NULL };
+
+  GST_DEBUG_CATEGORY_INIT (v4l2_debug, "v4l2", 0, "V4L2 API calls");
+
+  /* Add some depedency, so the dynamic features get updated upon changes in
+   * /dev/video* */
+  gst_plugin_add_dependency (plugin,
+      NULL, paths, names, GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX);
+
+  if (!gst_element_register (plugin, "v4l2src", GST_RANK_PRIMARY,
+          GST_TYPE_V4L2SRC) ||
+      !gst_element_register (plugin, "v4l2sink", GST_RANK_NONE,
+          GST_TYPE_V4L2SINK) ||
+      !gst_element_register (plugin, "v4l2radio", GST_RANK_NONE,
+          GST_TYPE_V4L2RADIO) ||
+      !gst_device_provider_register (plugin, "v4l2deviceprovider",
+          GST_RANK_PRIMARY, GST_TYPE_V4L2_DEVICE_PROVIDER)
+      /* etc. */
+#ifdef GST_V4L2_ENABLE_PROBE
+      || !gst_v4l2_probe_and_register (plugin)
+#endif
+      )
+    return FALSE;
+
+#ifdef ENABLE_NLS
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif /* ENABLE_NLS */
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    video4linux2,
+    "elements for Video 4 Linux",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/sys/v4l2/gstv4l2allocator.c b/sys/v4l2/gstv4l2allocator.c
new file mode 100644
index 0000000..34a581b
--- /dev/null
+++ b/sys/v4l2/gstv4l2allocator.c
@@ -0,0 +1,1444 @@
+/*
+ * Copyright (C) 2014 Collabora Ltd.
+ *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE            /* O_CLOEXEC */
+#endif
+
+#include "ext/videodev2.h"
+
+#include "gstv4l2object.h"
+#include "gstv4l2allocator.h"
+
+#include <gst/allocators/gstdmabuf.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#define GST_V4L2_MEMORY_TYPE "V4l2Memory"
+
+#define gst_v4l2_allocator_parent_class parent_class
+G_DEFINE_TYPE (GstV4l2Allocator, gst_v4l2_allocator, GST_TYPE_ALLOCATOR);
+
+GST_DEBUG_CATEGORY_STATIC (v4l2allocator_debug);
+#define GST_CAT_DEFAULT v4l2allocator_debug
+
+#define UNSET_QUEUED(buffer) \
+    ((buffer).flags &= ~(V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))
+
+#define SET_QUEUED(buffer) ((buffer).flags |= V4L2_BUF_FLAG_QUEUED)
+
+#define IS_QUEUED(buffer) \
+    ((buffer).flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))
+
+enum
+{
+  GROUP_RELEASED,
+  LAST_SIGNAL
+};
+
+static guint gst_v4l2_allocator_signals[LAST_SIGNAL] = { 0 };
+
+static void gst_v4l2_allocator_release (GstV4l2Allocator * allocator,
+    GstV4l2Memory * mem);
+
+static const gchar *
+memory_type_to_str (guint32 memory)
+{
+  switch (memory) {
+    case V4L2_MEMORY_MMAP:
+      return "mmap";
+    case V4L2_MEMORY_USERPTR:
+      return "userptr";
+    case V4L2_MEMORY_DMABUF:
+      return "dmabuf";
+    default:
+      return "unknown";
+  }
+}
+
+/*************************************/
+/* GstV4lMemory implementation */
+/*************************************/
+
+static gpointer
+_v4l2mem_map (GstV4l2Memory * mem, gsize maxsize, GstMapFlags flags)
+{
+  gpointer data = NULL;
+
+  switch (mem->group->buffer.memory) {
+    case V4L2_MEMORY_MMAP:
+    case V4L2_MEMORY_USERPTR:
+      data = mem->data;
+      break;
+    case V4L2_MEMORY_DMABUF:
+      /* v4l2 dmabuf memory are not shared with downstream */
+      g_assert_not_reached ();
+      break;
+    default:
+      GST_WARNING ("Unknown memory type %i", mem->group->buffer.memory);
+      break;
+  }
+  return data;
+}
+
+static gboolean
+_v4l2mem_unmap (GstV4l2Memory * mem)
+{
+  gboolean ret = FALSE;
+
+  switch (mem->group->buffer.memory) {
+    case V4L2_MEMORY_MMAP:
+    case V4L2_MEMORY_USERPTR:
+      ret = TRUE;
+      break;
+    case V4L2_MEMORY_DMABUF:
+      /* v4l2 dmabuf memory are not share with downstream */
+      g_assert_not_reached ();
+      break;
+    default:
+      GST_WARNING ("Unknown memory type %i", mem->group->buffer.memory);
+      break;
+  }
+  return ret;
+}
+
+static gboolean
+_v4l2mem_dispose (GstV4l2Memory * mem)
+{
+  GstV4l2Allocator *allocator = (GstV4l2Allocator *) mem->mem.allocator;
+  GstV4l2MemoryGroup *group = mem->group;
+  gboolean ret;
+
+  if (group->mem[mem->plane]) {
+    /* We may have a dmabuf, replace it with returned original memory */
+    group->mem[mem->plane] = gst_memory_ref ((GstMemory *) mem);
+    gst_v4l2_allocator_release (allocator, mem);
+    ret = FALSE;
+  } else {
+    gst_object_ref (allocator);
+    ret = TRUE;
+  }
+
+  return ret;
+}
+
+static inline GstV4l2Memory *
+_v4l2mem_new (GstMemoryFlags flags, GstAllocator * allocator,
+    GstMemory * parent, gsize maxsize, gsize align, gsize offset, gsize size,
+    gint plane, gpointer data, int dmafd, GstV4l2MemoryGroup * group)
+{
+  GstV4l2Memory *mem;
+
+  mem = g_slice_new0 (GstV4l2Memory);
+  gst_memory_init (GST_MEMORY_CAST (mem),
+      flags, allocator, parent, maxsize, align, offset, size);
+
+  if (parent == NULL)
+    mem->mem.mini_object.dispose =
+        (GstMiniObjectDisposeFunction) _v4l2mem_dispose;
+
+  mem->plane = plane;
+  mem->data = data;
+  mem->dmafd = dmafd;
+  mem->group = group;
+
+  return mem;
+}
+
+static GstV4l2Memory *
+_v4l2mem_share (GstV4l2Memory * mem, gssize offset, gsize size)
+{
+  GstV4l2Memory *sub;
+  GstMemory *parent;
+
+  /* find the real parent */
+  if ((parent = mem->mem.parent) == NULL)
+    parent = (GstMemory *) mem;
+
+  if (size == -1)
+    size = mem->mem.size - offset;
+
+  /* the shared memory is always readonly */
+  sub = _v4l2mem_new (GST_MINI_OBJECT_FLAGS (parent) |
+      GST_MINI_OBJECT_FLAG_LOCK_READONLY, mem->mem.allocator, parent,
+      mem->mem.maxsize, mem->mem.align, offset, size, mem->plane, mem->data,
+      -1, mem->group);
+
+  return sub;
+}
+
+static gboolean
+_v4l2mem_is_span (GstV4l2Memory * mem1, GstV4l2Memory * mem2, gsize * offset)
+{
+  if (offset)
+    *offset = mem1->mem.offset - mem1->mem.parent->offset;
+
+  /* and memory is contiguous */
+  return mem1->mem.offset + mem1->mem.size == mem2->mem.offset;
+}
+
+gboolean
+gst_is_v4l2_memory (GstMemory * mem)
+{
+  return gst_memory_is_type (mem, GST_V4L2_MEMORY_TYPE);
+}
+
+GQuark
+gst_v4l2_memory_quark (void)
+{
+  static GQuark quark = 0;
+
+  if (quark == 0)
+    quark = g_quark_from_string ("GstV4l2Memory");
+
+  return quark;
+}
+
+
+/*************************************/
+/* GstV4l2MemoryGroup implementation */
+/*************************************/
+
+static void
+gst_v4l2_memory_group_free (GstV4l2MemoryGroup * group)
+{
+  gint i;
+
+  for (i = 0; i < group->n_mem; i++) {
+    GstMemory *mem = group->mem[i];
+    group->mem[i] = NULL;
+    if (mem)
+      gst_memory_unref (mem);
+  }
+
+  g_slice_free (GstV4l2MemoryGroup, group);
+}
+
+static GstV4l2MemoryGroup *
+gst_v4l2_memory_group_new (GstV4l2Allocator * allocator, guint32 index)
+{
+  GstV4l2Object *obj = allocator->obj;
+  guint32 memory = allocator->memory;
+  struct v4l2_format *format = &obj->format;
+  GstV4l2MemoryGroup *group;
+  gsize img_size, buf_size;
+
+  group = g_slice_new0 (GstV4l2MemoryGroup);
+
+  group->buffer.type = format->type;
+  group->buffer.index = index;
+  group->buffer.memory = memory;
+
+  if (V4L2_TYPE_IS_MULTIPLANAR (format->type)) {
+    group->n_mem = group->buffer.length = format->fmt.pix_mp.num_planes;
+    group->buffer.m.planes = group->planes;
+  } else {
+    group->n_mem = 1;
+  }
+
+  if (obj->ioctl (obj->video_fd, VIDIOC_QUERYBUF, &group->buffer) < 0)
+    goto querybuf_failed;
+
+  if (group->buffer.index != index) {
+    GST_ERROR_OBJECT (allocator, "Buffer index returned by VIDIOC_QUERYBUF "
+        "didn't match, this indicate the presence of a bug in your driver or "
+        "libv4l2");
+    g_slice_free (GstV4l2MemoryGroup, group);
+    return NULL;
+  }
+
+  /* Check that provided size matches the format we have negotiation. Failing
+   * there usually means a driver of libv4l bug. */
+  if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
+    gint i;
+
+    for (i = 0; i < group->n_mem; i++) {
+      img_size = obj->format.fmt.pix_mp.plane_fmt[i].sizeimage;
+      buf_size = group->planes[i].length;
+      if (buf_size < img_size)
+        goto buffer_too_short;
+    }
+  } else {
+    img_size = obj->format.fmt.pix.sizeimage;
+    buf_size = group->buffer.length;
+    if (buf_size < img_size)
+      goto buffer_too_short;
+  }
+
+  /* We save non planar buffer information into the multi-planar plane array
+   * to avoid duplicating the code later */
+  if (!V4L2_TYPE_IS_MULTIPLANAR (format->type)) {
+    group->planes[0].bytesused = group->buffer.bytesused;
+    group->planes[0].length = group->buffer.length;
+    group->planes[0].data_offset = 0;
+    g_assert (sizeof (group->planes[0].m) == sizeof (group->buffer.m));
+    memcpy (&group->planes[0].m, &group->buffer.m, sizeof (group->buffer.m));
+  }
+
+  GST_LOG_OBJECT (allocator, "Got %s buffer", memory_type_to_str (memory));
+  GST_LOG_OBJECT (allocator, "  index:     %u", group->buffer.index);
+  GST_LOG_OBJECT (allocator, "  type:      %d", group->buffer.type);
+  GST_LOG_OBJECT (allocator, "  flags:     %08x", group->buffer.flags);
+  GST_LOG_OBJECT (allocator, "  field:     %d", group->buffer.field);
+  GST_LOG_OBJECT (allocator, "  memory:    %d", group->buffer.memory);
+  GST_LOG_OBJECT (allocator, "  planes:    %d", group->n_mem);
+
+#ifndef GST_DISABLE_GST_DEBUG
+  if (memory == V4L2_MEMORY_MMAP) {
+    gint i;
+    for (i = 0; i < group->n_mem; i++) {
+      GST_LOG_OBJECT (allocator,
+          "  [%u] bytesused: %u, length: %u, offset: %u", i,
+          group->planes[i].bytesused, group->planes[i].length,
+          group->planes[i].data_offset);
+      GST_LOG_OBJECT (allocator, "  [%u] MMAP offset:  %u", i,
+          group->planes[i].m.mem_offset);
+    }
+  }
+#endif
+
+  return group;
+
+querybuf_failed:
+  {
+    GST_ERROR ("error querying buffer %d: %s", index, g_strerror (errno));
+    goto failed;
+  }
+buffer_too_short:
+  {
+    GST_ERROR ("buffer size %" G_GSIZE_FORMAT
+        " is smaller then negotiated size %" G_GSIZE_FORMAT
+        ", this is usually the result of a bug in the v4l2 driver or libv4l.",
+        buf_size, img_size);
+    goto failed;
+  }
+failed:
+  gst_v4l2_memory_group_free (group);
+  return NULL;
+}
+
+
+/*************************************/
+/* GstV4lAllocator implementation    */
+/*************************************/
+
+static void
+gst_v4l2_allocator_release (GstV4l2Allocator * allocator, GstV4l2Memory * mem)
+{
+  GstV4l2MemoryGroup *group = mem->group;
+
+  GST_LOG_OBJECT (allocator, "plane %i of buffer %u released",
+      mem->plane, group->buffer.index);
+
+  switch (allocator->memory) {
+    case V4L2_MEMORY_DMABUF:
+      close (mem->dmafd);
+      mem->dmafd = -1;
+      break;
+    case V4L2_MEMORY_USERPTR:
+      mem->data = NULL;
+      break;
+    default:
+      break;
+  }
+
+  /* When all memory are back, put the group back in the free queue */
+  if (g_atomic_int_dec_and_test (&group->mems_allocated)) {
+    GST_LOG_OBJECT (allocator, "buffer %u released", group->buffer.index);
+    gst_atomic_queue_push (allocator->free_queue, group);
+    g_signal_emit (allocator, gst_v4l2_allocator_signals[GROUP_RELEASED], 0);
+  }
+
+  /* Keep last, allocator may be freed after this call */
+  g_object_unref (allocator);
+}
+
+static void
+gst_v4l2_allocator_free (GstAllocator * gallocator, GstMemory * gmem)
+{
+  GstV4l2Allocator *allocator = (GstV4l2Allocator *) gallocator;
+  GstV4l2Object *obj = allocator->obj;
+  GstV4l2Memory *mem = (GstV4l2Memory *) gmem;
+  GstV4l2MemoryGroup *group = mem->group;
+
+  /* Only free unparented memory */
+  if (mem->mem.parent == NULL) {
+    GST_LOG_OBJECT (allocator, "freeing plane %i of buffer %u",
+        mem->plane, group->buffer.index);
+
+    if (allocator->memory == V4L2_MEMORY_MMAP) {
+      if (mem->data)
+        obj->munmap (mem->data, group->planes[mem->plane].length);
+    }
+
+    /* This apply for both mmap with expbuf, and dmabuf imported memory */
+    if (mem->dmafd >= 0)
+      close (mem->dmafd);
+  }
+
+  g_slice_free (GstV4l2Memory, mem);
+}
+
+static void
+gst_v4l2_allocator_dispose (GObject * obj)
+{
+  GstV4l2Allocator *allocator = (GstV4l2Allocator *) obj;
+  gint i;
+
+  GST_LOG_OBJECT (obj, "called");
+
+  for (i = 0; i < allocator->count; i++) {
+    GstV4l2MemoryGroup *group = allocator->groups[i];
+    allocator->groups[i] = NULL;
+    if (group)
+      gst_v4l2_memory_group_free (group);
+  }
+
+  G_OBJECT_CLASS (parent_class)->dispose (obj);
+}
+
+static void
+gst_v4l2_allocator_finalize (GObject * obj)
+{
+  GstV4l2Allocator *allocator = (GstV4l2Allocator *) obj;
+
+  GST_LOG_OBJECT (obj, "called");
+
+  gst_atomic_queue_unref (allocator->free_queue);
+  gst_object_unref (allocator->obj->element);
+
+  G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gst_v4l2_allocator_class_init (GstV4l2AllocatorClass * klass)
+{
+  GObjectClass *object_class;
+  GstAllocatorClass *allocator_class;
+
+  allocator_class = (GstAllocatorClass *) klass;
+  object_class = (GObjectClass *) klass;
+
+  allocator_class->alloc = NULL;
+  allocator_class->free = gst_v4l2_allocator_free;
+
+  object_class->dispose = gst_v4l2_allocator_dispose;
+  object_class->finalize = gst_v4l2_allocator_finalize;
+
+  gst_v4l2_allocator_signals[GROUP_RELEASED] = g_signal_new ("group-released",
+      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
+      G_TYPE_NONE, 0);
+
+  GST_DEBUG_CATEGORY_INIT (v4l2allocator_debug, "v4l2allocator", 0,
+      "V4L2 Allocator");
+}
+
+static void
+gst_v4l2_allocator_init (GstV4l2Allocator * allocator)
+{
+  GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
+
+  alloc->mem_type = GST_V4L2_MEMORY_TYPE;
+  alloc->mem_map = (GstMemoryMapFunction) _v4l2mem_map;
+  alloc->mem_unmap = (GstMemoryUnmapFunction) _v4l2mem_unmap;
+  alloc->mem_share = (GstMemoryShareFunction) _v4l2mem_share;
+  alloc->mem_is_span = (GstMemoryIsSpanFunction) _v4l2mem_is_span;
+  /* Use the default, fallback copy function */
+
+  allocator->free_queue = gst_atomic_queue_new (VIDEO_MAX_FRAME);
+
+  GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
+}
+
+#define GST_V4L2_ALLOCATOR_PROBE(obj,type) \
+    gst_v4l2_allocator_probe ((obj), V4L2_MEMORY_ ## type, \
+        GST_V4L2_ALLOCATOR_FLAG_ ## type ## _REQBUFS, \
+        GST_V4L2_ALLOCATOR_FLAG_ ## type ## _CREATE_BUFS)
+static guint32
+gst_v4l2_allocator_probe (GstV4l2Allocator * allocator, guint32 memory,
+    guint32 breq_flag, guint32 bcreate_flag)
+{
+  GstV4l2Object *obj = allocator->obj;
+  struct v4l2_requestbuffers breq = { 0 };
+  guint32 flags = 0;
+
+  breq.type = obj->type;
+  breq.count = 0;
+  breq.memory = memory;
+
+  if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) == 0) {
+    struct v4l2_create_buffers bcreate = { 0 };
+
+    flags |= breq_flag;
+
+    bcreate.memory = memory;
+    bcreate.format = obj->format;
+
+    if ((obj->ioctl (obj->video_fd, VIDIOC_CREATE_BUFS, &bcreate) == 0))
+      flags |= bcreate_flag;
+  }
+
+  return flags;
+}
+
+static GstV4l2MemoryGroup *
+gst_v4l2_allocator_create_buf (GstV4l2Allocator * allocator)
+{
+  GstV4l2Object *obj = allocator->obj;
+  struct v4l2_create_buffers bcreate = { 0 };
+  GstV4l2MemoryGroup *group = NULL;
+
+  GST_OBJECT_LOCK (allocator);
+
+  if (!g_atomic_int_get (&allocator->active))
+    goto done;
+
+  bcreate.memory = allocator->memory;
+  bcreate.format = obj->format;
+  bcreate.count = 1;
+
+  if (!allocator->can_allocate)
+    goto done;
+
+  if (obj->ioctl (obj->video_fd, VIDIOC_CREATE_BUFS, &bcreate) < 0)
+    goto create_bufs_failed;
+
+  if (allocator->groups[bcreate.index] != NULL)
+    goto create_bufs_bug;
+
+  group = gst_v4l2_memory_group_new (allocator, bcreate.index);
+
+  if (group) {
+    allocator->groups[bcreate.index] = group;
+    allocator->count++;
+  }
+
+done:
+  GST_OBJECT_UNLOCK (allocator);
+  return group;
+
+create_bufs_failed:
+  {
+    GST_WARNING_OBJECT (allocator, "error creating a new buffer: %s",
+        g_strerror (errno));
+    goto done;
+  }
+create_bufs_bug:
+  {
+    GST_ERROR_OBJECT (allocator, "created buffer has already used buffer "
+        "index %i, this means there is an bug in your driver or libv4l2",
+        bcreate.index);
+    goto done;
+  }
+}
+
+static GstV4l2MemoryGroup *
+gst_v4l2_allocator_alloc (GstV4l2Allocator * allocator)
+{
+  GstV4l2MemoryGroup *group;
+
+  if (!g_atomic_int_get (&allocator->active))
+    return NULL;
+
+  group = gst_atomic_queue_pop (allocator->free_queue);
+
+  if (group == NULL) {
+    if (allocator->can_allocate) {
+      group = gst_v4l2_allocator_create_buf (allocator);
+
+      /* Don't hammer on CREATE_BUFS */
+      if (group == NULL)
+        allocator->can_allocate = FALSE;
+    }
+  }
+
+  return group;
+}
+
+static void
+gst_v4l2_allocator_reset_size (GstV4l2Allocator * allocator,
+    GstV4l2MemoryGroup * group)
+{
+  gint i;
+  for (i = 0; i < group->n_mem; i++) {
+    group->mem[i]->maxsize = group->planes[i].length;
+    group->mem[i]->offset = 0;
+    group->mem[i]->size = group->planes[i].length;
+  }
+}
+
+static void
+_cleanup_failed_alloc (GstV4l2Allocator * allocator, GstV4l2MemoryGroup * group)
+{
+  if (group->mems_allocated > 0) {
+    gint i;
+    /* If one or more mmap worked, we need to unref the memory, otherwise
+     * they will keep a ref on the allocator and leak it. This will put back
+     * the group into the free_queue */
+    for (i = 0; i < group->n_mem; i++)
+      gst_memory_unref (group->mem[i]);
+  } else {
+    /* Otherwise, group has to be on free queue for _stop() to work */
+    gst_atomic_queue_push (allocator->free_queue, group);
+  }
+}
+
+
+
+GstV4l2Allocator *
+gst_v4l2_allocator_new (GstObject * parent, GstV4l2Object * v4l2object)
+{
+  GstV4l2Allocator *allocator;
+  guint32 flags = 0;
+  gchar *name, *parent_name;
+
+  parent_name = gst_object_get_name (parent);
+  name = g_strconcat (parent_name, ":allocator", NULL);
+  g_free (parent_name);
+
+  allocator = g_object_new (GST_TYPE_V4L2_ALLOCATOR, "name", name, NULL);
+  gst_object_ref_sink (allocator);
+  g_free (name);
+
+  /* Save everything */
+  allocator->obj = v4l2object;
+
+  /* Keep a ref on the elemnt so obj does not disapear */
+  gst_object_ref (allocator->obj->element);
+
+  flags |= GST_V4L2_ALLOCATOR_PROBE (allocator, MMAP);
+  flags |= GST_V4L2_ALLOCATOR_PROBE (allocator, USERPTR);
+  flags |= GST_V4L2_ALLOCATOR_PROBE (allocator, DMABUF);
+
+
+  if (flags == 0) {
+    /* Drivers not ported from videobuf to videbuf2 don't allow freeing buffers
+     * using REQBUFS(0). This is a workaround to still support these drivers,
+     * which are known to have MMAP support. */
+    GST_WARNING_OBJECT (allocator, "Could not probe supported memory type, "
+        "assuming MMAP is supported, this is expected for older drivers not "
+        " yet ported to videobuf2 framework");
+    flags = GST_V4L2_ALLOCATOR_FLAG_MMAP_REQBUFS;
+  }
+
+  GST_OBJECT_FLAG_SET (allocator, flags);
+
+  return allocator;
+}
+
+guint
+gst_v4l2_allocator_start (GstV4l2Allocator * allocator, guint32 count,
+    guint32 memory)
+{
+  GstV4l2Object *obj = allocator->obj;
+  struct v4l2_requestbuffers breq = { count, obj->type, memory };
+  gboolean can_allocate;
+  gint i;
+
+  g_return_val_if_fail (count != 0, 0);
+
+  GST_OBJECT_LOCK (allocator);
+
+  if (g_atomic_int_get (&allocator->active))
+    goto already_active;
+
+  if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) < 0)
+    goto reqbufs_failed;
+
+  if (breq.count < 1)
+    goto out_of_memory;
+
+  switch (memory) {
+    case V4L2_MEMORY_MMAP:
+      can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (allocator, MMAP);
+      break;
+    case V4L2_MEMORY_USERPTR:
+      can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (allocator, USERPTR);
+      break;
+    case V4L2_MEMORY_DMABUF:
+      can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (allocator, DMABUF);
+      break;
+    default:
+      can_allocate = FALSE;
+      break;
+  }
+
+  GST_DEBUG_OBJECT (allocator, "allocated %u %s buffers out of %u requested",
+      breq.count, memory_type_to_str (memory), count);
+
+  allocator->can_allocate = can_allocate;
+  allocator->count = breq.count;
+  allocator->memory = memory;
+
+  /* Create memory groups */
+  for (i = 0; i < allocator->count; i++) {
+    allocator->groups[i] = gst_v4l2_memory_group_new (allocator, i);
+    if (allocator->groups[i] == NULL)
+      goto error;
+
+    gst_atomic_queue_push (allocator->free_queue, allocator->groups[i]);
+  }
+
+  g_atomic_int_set (&allocator->active, TRUE);
+
+done:
+  GST_OBJECT_UNLOCK (allocator);
+  return breq.count;
+
+already_active:
+  {
+    GST_ERROR_OBJECT (allocator, "allocator already active");
+    goto error;
+  }
+reqbufs_failed:
+  {
+    GST_ERROR_OBJECT (allocator,
+        "error requesting %d buffers: %s", count, g_strerror (errno));
+    goto error;
+  }
+out_of_memory:
+  {
+    GST_ERROR_OBJECT (allocator, "Not enough memory to allocate buffers");
+    goto error;
+  }
+error:
+  {
+    breq.count = 0;
+    goto done;
+  }
+}
+
+GstV4l2Return
+gst_v4l2_allocator_stop (GstV4l2Allocator * allocator)
+{
+  GstV4l2Object *obj = allocator->obj;
+  struct v4l2_requestbuffers breq = { 0, obj->type, allocator->memory };
+  gint i = 0;
+  GstV4l2Return ret = GST_V4L2_OK;
+
+  GST_DEBUG_OBJECT (allocator, "stop allocator");
+
+  GST_OBJECT_LOCK (allocator);
+
+  if (!g_atomic_int_get (&allocator->active))
+    goto done;
+
+  if (gst_atomic_queue_length (allocator->free_queue) != allocator->count) {
+    GST_DEBUG_OBJECT (allocator, "allocator is still in use");
+    ret = GST_V4L2_BUSY;
+    goto done;
+  }
+
+  while (gst_atomic_queue_pop (allocator->free_queue)) {
+    /* nothing */
+  };
+
+  for (i = 0; i < allocator->count; i++) {
+    GstV4l2MemoryGroup *group = allocator->groups[i];
+    allocator->groups[i] = NULL;
+    if (group)
+      gst_v4l2_memory_group_free (group);
+  }
+
+  /* Not all drivers support rebufs(0), so warn only */
+  if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) < 0)
+    GST_WARNING_OBJECT (allocator,
+        "error releasing buffers buffers: %s", g_strerror (errno));
+
+  allocator->count = 0;
+
+  g_atomic_int_set (&allocator->active, FALSE);
+
+done:
+  GST_OBJECT_UNLOCK (allocator);
+  return ret;
+}
+
+GstV4l2MemoryGroup *
+gst_v4l2_allocator_alloc_mmap (GstV4l2Allocator * allocator)
+{
+  GstV4l2Object *obj = allocator->obj;
+  GstV4l2MemoryGroup *group;
+  gint i;
+
+  g_return_val_if_fail (allocator->memory == V4L2_MEMORY_MMAP, NULL);
+
+  group = gst_v4l2_allocator_alloc (allocator);
+
+  if (group == NULL)
+    return NULL;
+
+  for (i = 0; i < group->n_mem; i++) {
+    if (group->mem[i] == NULL) {
+      gpointer data;
+      data = obj->mmap (NULL, group->planes[i].length, PROT_READ | PROT_WRITE,
+          MAP_SHARED, obj->video_fd, group->planes[i].m.mem_offset);
+
+      if (data == MAP_FAILED)
+        goto mmap_failed;
+
+      GST_LOG_OBJECT (allocator,
+          "mmap buffer length %d, data offset %d, plane %d",
+          group->planes[i].length, group->planes[i].data_offset, i);
+
+      group->mem[i] = (GstMemory *) _v4l2mem_new (0, GST_ALLOCATOR (allocator),
+          NULL, group->planes[i].length, 0, 0, group->planes[i].length, i, data,
+          -1, group);
+    } else {
+      /* Take back the allocator reference */
+      gst_object_ref (allocator);
+    }
+
+    group->mems_allocated++;
+  }
+
+  /* Ensure group size. Unlike GST, v4l2 have size (bytesused) initially set
+   * to 0. As length might be bigger then the expected size exposed in the
+   * format, we simply set bytesused initially and reset it here for
+   * simplicity */
+  gst_v4l2_allocator_reset_size (allocator, group);
+
+  return group;
+
+mmap_failed:
+  {
+    GST_ERROR_OBJECT (allocator, "Failed to mmap buffer: %s",
+        g_strerror (errno));
+    _cleanup_failed_alloc (allocator, group);
+    return NULL;
+  }
+}
+
+GstV4l2MemoryGroup *
+gst_v4l2_allocator_alloc_dmabuf (GstV4l2Allocator * allocator,
+    GstAllocator * dmabuf_allocator)
+{
+  GstV4l2Object *obj = allocator->obj;
+  GstV4l2MemoryGroup *group;
+  gint i;
+
+  g_return_val_if_fail (allocator->memory == V4L2_MEMORY_MMAP, NULL);
+
+  group = gst_v4l2_allocator_alloc (allocator);
+
+  if (group == NULL)
+    return NULL;
+
+  for (i = 0; i < group->n_mem; i++) {
+    GstV4l2Memory *mem;
+    GstMemory *dma_mem;
+    gint dmafd;
+
+    if (group->mem[i] == NULL) {
+      struct v4l2_exportbuffer expbuf = { 0 };
+
+      expbuf.type = obj->type;
+      expbuf.index = group->buffer.index;
+      expbuf.plane = i;
+      expbuf.flags = O_CLOEXEC | O_RDWR;
+
+      if (obj->ioctl (obj->video_fd, VIDIOC_EXPBUF, &expbuf) < 0)
+        goto expbuf_failed;
+
+      GST_LOG_OBJECT (allocator, "exported DMABUF as fd %i plane %d",
+          expbuf.fd, i);
+
+      group->mem[i] = (GstMemory *) _v4l2mem_new (0, GST_ALLOCATOR (allocator),
+          NULL, group->planes[i].length, 0, group->planes[i].data_offset,
+          group->planes[i].length - group->planes[i].data_offset, i, NULL,
+          expbuf.fd, group);
+    } else {
+      /* Take back the allocator reference */
+      gst_object_ref (allocator);
+    }
+
+    group->mems_allocated++;
+
+    g_assert (gst_is_v4l2_memory (group->mem[i]));
+    mem = (GstV4l2Memory *) group->mem[i];
+
+    if ((dmafd = dup (mem->dmafd)) < 0)
+      goto dup_failed;
+
+    dma_mem = gst_dmabuf_allocator_alloc (dmabuf_allocator, dmafd,
+        group->planes[i].length);
+    gst_memory_resize (dma_mem, group->planes[i].data_offset,
+        group->planes[i].length - group->planes[i].data_offset);
+
+    gst_mini_object_set_qdata (GST_MINI_OBJECT (dma_mem),
+        GST_V4L2_MEMORY_QUARK, mem, (GDestroyNotify) gst_memory_unref);
+
+    group->mem[i] = dma_mem;
+  }
+
+  gst_v4l2_allocator_reset_size (allocator, group);
+
+  return group;
+
+expbuf_failed:
+  {
+    GST_ERROR_OBJECT (allocator, "Failed to export DMABUF: %s",
+        g_strerror (errno));
+    goto cleanup;
+  }
+dup_failed:
+  {
+    GST_ERROR_OBJECT (allocator, "Failed to dup DMABUF descriptor: %s",
+        g_strerror (errno));
+    goto cleanup;
+  }
+cleanup:
+  {
+    _cleanup_failed_alloc (allocator, group);
+    return NULL;
+  }
+}
+
+static void
+gst_v4l2_allocator_clear_dmabufin (GstV4l2Allocator * allocator,
+    GstV4l2MemoryGroup * group)
+{
+  GstV4l2Object *obj = allocator->obj;
+  GstV4l2Memory *mem;
+  gint i;
+
+  g_return_if_fail (allocator->memory == V4L2_MEMORY_DMABUF);
+
+  for (i = 0; i < group->n_mem; i++) {
+
+    mem = (GstV4l2Memory *) group->mem[i];
+
+    GST_LOG_OBJECT (allocator, "clearing DMABUF import, fd %i plane %d",
+        mem->dmafd, i);
+
+    if (mem->dmafd >= 0)
+      close (mem->dmafd);
+
+    /* Update memory */
+    mem->mem.maxsize = 0;
+    mem->mem.offset = 0;
+    mem->mem.size = 0;
+    mem->dmafd = -1;
+
+    /* Update v4l2 structure */
+    group->planes[i].length = 0;
+    group->planes[i].bytesused = 0;
+    group->planes[i].m.fd = -1;
+    group->planes[i].data_offset = 0;
+  }
+
+  if (!V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
+    group->buffer.bytesused = 0;
+    group->buffer.length = 0;
+    group->buffer.m.fd = -1;
+  }
+}
+
+GstV4l2MemoryGroup *
+gst_v4l2_allocator_alloc_dmabufin (GstV4l2Allocator * allocator)
+{
+  GstV4l2MemoryGroup *group;
+  gint i;
+
+  g_return_val_if_fail (allocator->memory == V4L2_MEMORY_DMABUF, NULL);
+
+  group = gst_v4l2_allocator_alloc (allocator);
+
+  if (group == NULL)
+    return NULL;
+
+  GST_LOG_OBJECT (allocator, "allocating empty DMABUF import group");
+
+  for (i = 0; i < group->n_mem; i++) {
+    if (group->mem[i] == NULL) {
+      group->mem[i] = (GstMemory *) _v4l2mem_new (0, GST_ALLOCATOR (allocator),
+          NULL, 0, 0, 0, 0, i, NULL, -1, group);
+    } else {
+      /* Take back the allocator reference */
+      gst_object_ref (allocator);
+    }
+
+    group->mems_allocated++;
+  }
+
+  gst_v4l2_allocator_clear_dmabufin (allocator, group);
+
+  return group;
+}
+
+static void
+gst_v4l2_allocator_clear_userptr (GstV4l2Allocator * allocator,
+    GstV4l2MemoryGroup * group)
+{
+  GstV4l2Object *obj = allocator->obj;
+  GstV4l2Memory *mem;
+  gint i;
+
+  g_return_if_fail (allocator->memory == V4L2_MEMORY_USERPTR);
+
+  for (i = 0; i < group->n_mem; i++) {
+    mem = (GstV4l2Memory *) group->mem[i];
+
+    GST_LOG_OBJECT (allocator, "clearing USERPTR %p plane %d size %"
+        G_GSIZE_FORMAT, mem->data, i, mem->mem.size);
+
+    mem->mem.maxsize = 0;
+    mem->mem.size = 0;
+    mem->data = NULL;
+
+    group->planes[i].length = 0;
+    group->planes[i].bytesused = 0;
+    group->planes[i].m.userptr = 0;
+  }
+
+  if (!V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
+    group->buffer.bytesused = 0;
+    group->buffer.length = 0;
+    group->buffer.m.userptr = 0;
+  }
+}
+
+GstV4l2MemoryGroup *
+gst_v4l2_allocator_alloc_userptr (GstV4l2Allocator * allocator)
+{
+  GstV4l2MemoryGroup *group;
+  gint i;
+
+  g_return_val_if_fail (allocator->memory == V4L2_MEMORY_USERPTR, NULL);
+
+  group = gst_v4l2_allocator_alloc (allocator);
+
+  if (group == NULL)
+    return NULL;
+
+  GST_LOG_OBJECT (allocator, "allocating empty USERPTR group");
+
+  for (i = 0; i < group->n_mem; i++) {
+
+    if (group->mem[i] == NULL) {
+      group->mem[i] = (GstMemory *) _v4l2mem_new (0, GST_ALLOCATOR (allocator),
+          NULL, 0, 0, 0, 0, i, NULL, -1, group);
+    } else {
+      /* Take back the allocator reference */
+      gst_object_ref (allocator);
+    }
+
+    group->mems_allocated++;
+  }
+
+  gst_v4l2_allocator_clear_userptr (allocator, group);
+
+  return group;
+}
+
+gboolean
+gst_v4l2_allocator_import_dmabuf (GstV4l2Allocator * allocator,
+    GstV4l2MemoryGroup * group, gint n_mem, GstMemory ** dma_mem)
+{
+  GstV4l2Object *obj = allocator->obj;
+  GstV4l2Memory *mem;
+  gint i;
+
+  g_return_val_if_fail (allocator->memory == V4L2_MEMORY_DMABUF, FALSE);
+
+  if (group->n_mem != n_mem)
+    goto n_mem_missmatch;
+
+  for (i = 0; i < group->n_mem; i++) {
+    gint dmafd;
+    gsize size, offset, maxsize;
+
+    if (!gst_is_dmabuf_memory (dma_mem[i]))
+      goto not_dmabuf;
+
+    size = gst_memory_get_sizes (dma_mem[i], &offset, &maxsize);
+
+    if ((dmafd = dup (gst_dmabuf_memory_get_fd (dma_mem[i]))) < 0)
+      goto dup_failed;
+
+    GST_LOG_OBJECT (allocator, "imported DMABUF as fd %i plane %d", dmafd, i);
+
+    mem = (GstV4l2Memory *) group->mem[i];
+
+    /* Update memory */
+    mem->mem.maxsize = maxsize;
+    mem->mem.offset = offset;
+    mem->mem.size = size;
+    mem->dmafd = dmafd;
+
+    /* Update v4l2 structure */
+    group->planes[i].length = maxsize;
+    group->planes[i].bytesused = size + offset;
+    group->planes[i].m.fd = dmafd;
+    group->planes[i].data_offset = offset;
+  }
+
+  /* Copy into buffer structure if not using planes */
+  if (!V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
+    group->buffer.bytesused = group->planes[0].bytesused;
+    group->buffer.length = group->planes[0].length;
+    group->buffer.m.fd = group->planes[0].m.userptr;
+
+    /* FIXME Check if data_offset > 0 and fail for non-multi-planar */
+    g_assert (group->planes[0].data_offset == 0);
+  } else {
+    group->buffer.length = group->n_mem;
+  }
+
+  return TRUE;
+
+n_mem_missmatch:
+  {
+    GST_ERROR_OBJECT (allocator, "Got %i dmabuf but needed %i", n_mem,
+        group->n_mem);
+    return FALSE;
+  }
+not_dmabuf:
+  {
+    GST_ERROR_OBJECT (allocator, "Memory %i is not of DMABUF", i);
+    return FALSE;
+  }
+dup_failed:
+  {
+    GST_ERROR_OBJECT (allocator, "Failed to dup DMABUF descriptor: %s",
+        g_strerror (errno));
+    return FALSE;
+  }
+}
+
+gboolean
+gst_v4l2_allocator_import_userptr (GstV4l2Allocator * allocator,
+    GstV4l2MemoryGroup * group, gsize img_size, int n_planes,
+    gpointer * data, gsize * size)
+{
+  GstV4l2Object *obj = allocator->obj;
+  GstV4l2Memory *mem;
+  gint i;
+
+  g_return_val_if_fail (allocator->memory == V4L2_MEMORY_USERPTR, FALSE);
+
+  /* TODO Support passing N plane from 1 memory to MPLANE v4l2 format */
+  if (V4L2_TYPE_IS_MULTIPLANAR (obj->type) && n_planes != group->n_mem)
+    goto n_mem_missmatch;
+
+  for (i = 0; i < group->n_mem; i++) {
+    gsize maxsize, psize;
+
+    if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
+      maxsize = group->planes[i].length;
+      psize = size[i];
+    } else {
+      maxsize = group->planes[i].length;
+      psize = img_size;
+    }
+
+    g_assert (psize <= img_size);
+
+    GST_LOG_OBJECT (allocator, "imported USERPTR %p plane %d size %"
+        G_GSIZE_FORMAT, data[i], i, psize);
+
+    mem = (GstV4l2Memory *) group->mem[i];
+
+    mem->mem.maxsize = maxsize;
+    mem->mem.size = psize;
+    mem->data = data[i];
+
+    group->planes[i].length = maxsize;
+    group->planes[i].bytesused = psize;
+    group->planes[i].m.userptr = (unsigned long) data[i];
+    group->planes[i].data_offset = 0;
+  }
+
+  /* Copy into buffer structure if not using planes */
+  if (!V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
+    group->buffer.bytesused = group->planes[0].bytesused;
+    group->buffer.length = group->planes[0].length;
+    group->buffer.m.userptr = group->planes[0].m.userptr;
+  } else {
+    group->buffer.length = group->n_mem;
+  }
+
+  return TRUE;
+
+n_mem_missmatch:
+  {
+    GST_ERROR_OBJECT (allocator, "Got %i userptr plane while driver need %i",
+        n_planes, group->n_mem);
+    return FALSE;
+  }
+}
+
+void
+gst_v4l2_allocator_flush (GstV4l2Allocator * allocator)
+{
+  gint i;
+
+  GST_OBJECT_LOCK (allocator);
+
+  if (!g_atomic_int_get (&allocator->active))
+    goto done;
+
+  for (i = 0; i < allocator->count; i++) {
+    GstV4l2MemoryGroup *group = allocator->groups[i];
+    gint n;
+
+    if (IS_QUEUED (group->buffer)) {
+      UNSET_QUEUED (group->buffer);
+
+      gst_v4l2_allocator_reset_group (allocator, group);
+
+      for (n = 0; n < group->n_mem; n++)
+        gst_memory_unref (group->mem[n]);
+    }
+  }
+
+done:
+  GST_OBJECT_UNLOCK (allocator);
+}
+
+gboolean
+gst_v4l2_allocator_qbuf (GstV4l2Allocator * allocator,
+    GstV4l2MemoryGroup * group)
+{
+  GstV4l2Object *obj = allocator->obj;
+  gboolean ret = TRUE;
+  gint i;
+
+  g_return_val_if_fail (g_atomic_int_get (&allocator->active), FALSE);
+
+  /* update sizes */
+  if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
+    for (i = 0; i < group->n_mem; i++)
+      group->planes[i].bytesused =
+          gst_memory_get_sizes (group->mem[i], NULL, NULL);
+  } else {
+    group->buffer.bytesused = gst_memory_get_sizes (group->mem[0], NULL, NULL);
+  }
+
+  /* Ensure the memory will stay around and is RO */
+  for (i = 0; i < group->n_mem; i++)
+    gst_memory_ref (group->mem[i]);
+
+  if (obj->ioctl (obj->video_fd, VIDIOC_QBUF, &group->buffer) < 0) {
+    GST_ERROR_OBJECT (allocator, "failed queueing buffer %i: %s",
+        group->buffer.index, g_strerror (errno));
+
+    /* Release the memory, possibly making it RW again */
+    for (i = 0; i < group->n_mem; i++)
+      gst_memory_unref (group->mem[i]);
+
+    ret = FALSE;
+    if (IS_QUEUED (group->buffer)) {
+      GST_DEBUG_OBJECT (allocator,
+          "driver pretends buffer is queued even if queue failed");
+      UNSET_QUEUED (group->buffer);
+    }
+    goto done;
+  }
+
+  GST_LOG_OBJECT (allocator, "queued buffer %i (flags 0x%X)",
+      group->buffer.index, group->buffer.flags);
+
+  if (!IS_QUEUED (group->buffer)) {
+    GST_DEBUG_OBJECT (allocator,
+        "driver pretends buffer is not queued even if queue succeeded");
+    SET_QUEUED (group->buffer);
+  }
+
+done:
+  return ret;
+}
+
+GstFlowReturn
+gst_v4l2_allocator_dqbuf (GstV4l2Allocator * allocator,
+    GstV4l2MemoryGroup ** group_out)
+{
+  GstV4l2Object *obj = allocator->obj;
+  struct v4l2_buffer buffer = { 0 };
+  struct v4l2_plane planes[VIDEO_MAX_PLANES] = { {0} };
+  gint i;
+
+  GstV4l2MemoryGroup *group = NULL;
+
+  g_return_val_if_fail (g_atomic_int_get (&allocator->active), GST_FLOW_ERROR);
+
+  buffer.type = obj->type;
+  buffer.memory = allocator->memory;
+
+  if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
+    buffer.length = obj->format.fmt.pix_mp.num_planes;
+    buffer.m.planes = planes;
+  }
+
+  if (obj->ioctl (obj->video_fd, VIDIOC_DQBUF, &buffer) < 0)
+    goto error;
+
+  group = allocator->groups[buffer.index];
+
+  if (!IS_QUEUED (group->buffer)) {
+    GST_ERROR_OBJECT (allocator,
+        "buffer %i was not queued, this indicate a driver bug.", buffer.index);
+    return GST_FLOW_ERROR;
+  }
+
+  group->buffer = buffer;
+
+  GST_LOG_OBJECT (allocator, "dequeued buffer %i (flags 0x%X)", buffer.index,
+      buffer.flags);
+
+  if (IS_QUEUED (group->buffer)) {
+    GST_DEBUG_OBJECT (allocator,
+        "driver pretends buffer is queued even if dequeue succeeded");
+    UNSET_QUEUED (group->buffer);
+  }
+
+  if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
+    group->buffer.m.planes = group->planes;
+    memcpy (group->planes, buffer.m.planes, sizeof (planes));
+  } else {
+    group->planes[0].bytesused = group->buffer.bytesused;
+    group->planes[0].length = group->buffer.length;
+    g_assert (sizeof (group->planes[0].m) == sizeof (group->buffer.m));
+    memcpy (&group->planes[0].m, &group->buffer.m, sizeof (group->buffer.m));
+  }
+
+  /* And update memory size */
+  if (V4L2_TYPE_IS_OUTPUT (obj->type)) {
+    gst_v4l2_allocator_reset_size (allocator, group);
+  } else {
+    /* for capture, simply read the size */
+    for (i = 0; i < group->n_mem; i++) {
+      gsize size, offset;
+
+      GST_LOG_OBJECT (allocator,
+          "Dequeued capture buffer, length: %u bytesused: %u data_offset: %u",
+          group->planes[i].length, group->planes[i].bytesused,
+          group->planes[i].data_offset);
+
+      offset = group->planes[i].data_offset;
+
+      if (group->planes[i].bytesused > group->planes[i].data_offset) {
+        size = group->planes[i].bytesused - group->planes[i].data_offset;
+      } else {
+        GST_WARNING_OBJECT (allocator, "V4L2 provided buffer has bytesused %"
+            G_GUINT32_FORMAT " which is too small to include data_offset %"
+            G_GUINT32_FORMAT, group->planes[i].bytesused,
+            group->planes[i].data_offset);
+        size = group->planes[i].bytesused;
+      }
+
+      if (G_LIKELY (size + offset <= group->mem[i]->maxsize))
+        gst_memory_resize (group->mem[i], offset, size);
+      else {
+        GST_WARNING_OBJECT (allocator,
+            "v4l2 provided buffer that is too big for the memory it was "
+            "writing into.  v4l2 claims %" G_GSIZE_FORMAT " bytes used but "
+            "memory is only %" G_GSIZE_FORMAT "B.  This is probably a driver "
+            "bug.", size, group->mem[i]->maxsize);
+        gst_memory_resize (group->mem[i], 0, group->mem[i]->maxsize);
+      }
+    }
+  }
+
+  /* Release the memory, possibly making it RW again */
+  for (i = 0; i < group->n_mem; i++)
+    gst_memory_unref (group->mem[i]);
+
+  *group_out = group;
+  return GST_FLOW_OK;
+
+error:
+  if (errno == EPIPE) {
+    GST_DEBUG_OBJECT (allocator, "broken pipe signals last buffer");
+    return GST_FLOW_EOS;
+  }
+
+  GST_ERROR_OBJECT (allocator, "failed dequeuing a %s buffer: %s",
+      memory_type_to_str (allocator->memory), g_strerror (errno));
+
+  switch (errno) {
+    case EAGAIN:
+      GST_WARNING_OBJECT (allocator,
+          "Non-blocking I/O has been selected using O_NONBLOCK and"
+          " no buffer was in the outgoing queue.");
+      break;
+    case EINVAL:
+      GST_ERROR_OBJECT (allocator,
+          "The buffer type is not supported, or the index is out of bounds, "
+          "or no buffers have been allocated yet, or the userptr "
+          "or length are invalid.");
+      break;
+    case ENOMEM:
+      GST_ERROR_OBJECT (allocator,
+          "insufficient memory to enqueue a user pointer buffer");
+      break;
+    case EIO:
+      GST_INFO_OBJECT (allocator,
+          "VIDIOC_DQBUF failed due to an internal error."
+          " Can also indicate temporary problems like signal loss."
+          " Note the driver might dequeue an (empty) buffer despite"
+          " returning an error, or even stop capturing.");
+      /* have we de-queued a buffer ? */
+      if (!IS_QUEUED (buffer)) {
+        GST_DEBUG_OBJECT (allocator, "reenqueueing buffer");
+        /* FIXME ... should we do something here? */
+      }
+      break;
+    case EINTR:
+      GST_WARNING_OBJECT (allocator, "could not sync on a buffer on device");
+      break;
+    default:
+      GST_WARNING_OBJECT (allocator,
+          "Grabbing frame got interrupted unexpectedly. %d: %s.", errno,
+          g_strerror (errno));
+      break;
+  }
+
+  return GST_FLOW_ERROR;
+}
+
+void
+gst_v4l2_allocator_reset_group (GstV4l2Allocator * allocator,
+    GstV4l2MemoryGroup * group)
+{
+  switch (allocator->memory) {
+    case V4L2_MEMORY_USERPTR:
+      gst_v4l2_allocator_clear_userptr (allocator, group);
+      break;
+    case V4L2_MEMORY_DMABUF:
+      gst_v4l2_allocator_clear_dmabufin (allocator, group);
+      break;
+    case V4L2_MEMORY_MMAP:
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+
+  gst_v4l2_allocator_reset_size (allocator, group);
+}
diff --git a/sys/v4l2/gstv4l2allocator.h b/sys/v4l2/gstv4l2allocator.h
new file mode 100644
index 0000000..9826815
--- /dev/null
+++ b/sys/v4l2/gstv4l2allocator.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2014 Collabora Ltd.
+ *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef __GST_V4L2_ALLOCATOR_H__
+#define __GST_V4L2_ALLOCATOR_H__
+
+#include "ext/videodev2.h"
+#include <gst/gst.h>
+#include <gst/gstatomicqueue.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_V4L2_ALLOCATOR                 (gst_v4l2_allocator_get_type())
+#define GST_IS_V4L2_ALLOCATOR(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_ALLOCATOR))
+#define GST_IS_V4L2_ALLOCATOR_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_ALLOCATOR))
+#define GST_V4L2_ALLOCATOR_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_V4L2_ALLOCATOR, GstV4l2AllocatorClass))
+#define GST_V4L2_ALLOCATOR(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_ALLOCATOR, GstV4l2Allocator))
+#define GST_V4L2_ALLOCATOR_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_ALLOCATOR, GstV4l2AllocatorClass))
+#define GST_V4L2_ALLOCATOR_CAST(obj)            ((GstV4l2Allocator *)(obj))
+
+#define GST_V4L2_ALLOCATOR_CAN_REQUEST(obj,type) \
+        (GST_OBJECT_FLAG_IS_SET (obj, GST_V4L2_ALLOCATOR_FLAG_ ## type ## _REQBUFS))
+#define GST_V4L2_ALLOCATOR_CAN_ALLOCATE(obj,type) \
+        (GST_OBJECT_FLAG_IS_SET (obj, GST_V4L2_ALLOCATOR_FLAG_ ## type ## _CREATE_BUFS))
+
+#define GST_V4L2_MEMORY_QUARK gst_v4l2_memory_quark ()
+
+typedef struct _GstV4l2Allocator GstV4l2Allocator;
+typedef struct _GstV4l2AllocatorClass GstV4l2AllocatorClass;
+typedef struct _GstV4l2MemoryGroup GstV4l2MemoryGroup;
+typedef struct _GstV4l2Memory GstV4l2Memory;
+typedef enum _GstV4l2Capabilities GstV4l2Capabilities;
+typedef enum _GstV4l2Return GstV4l2Return;
+typedef struct _GstV4l2Object GstV4l2Object;
+
+enum _GstV4l2AllocatorFlags
+{
+  GST_V4L2_ALLOCATOR_FLAG_MMAP_REQBUFS        = (GST_ALLOCATOR_FLAG_LAST << 0),
+  GST_V4L2_ALLOCATOR_FLAG_MMAP_CREATE_BUFS    = (GST_ALLOCATOR_FLAG_LAST << 1),
+  GST_V4L2_ALLOCATOR_FLAG_USERPTR_REQBUFS     = (GST_ALLOCATOR_FLAG_LAST << 2),
+  GST_V4L2_ALLOCATOR_FLAG_USERPTR_CREATE_BUFS = (GST_ALLOCATOR_FLAG_LAST << 3),
+  GST_V4L2_ALLOCATOR_FLAG_DMABUF_REQBUFS      = (GST_ALLOCATOR_FLAG_LAST << 4),
+  GST_V4L2_ALLOCATOR_FLAG_DMABUF_CREATE_BUFS  = (GST_ALLOCATOR_FLAG_LAST << 5),
+};
+
+enum _GstV4l2Return
+{
+  GST_V4L2_OK = 0,
+  GST_V4L2_ERROR = -1,
+  GST_V4L2_BUSY = -2
+};
+
+struct _GstV4l2Memory
+{
+  GstMemory mem;
+  gint plane;
+  GstV4l2MemoryGroup *group;
+  gpointer data;
+  gint dmafd;
+};
+
+struct _GstV4l2MemoryGroup
+{
+  gint n_mem;
+  GstMemory * mem[VIDEO_MAX_PLANES];
+  gint mems_allocated;
+  struct v4l2_buffer buffer;
+  struct v4l2_plane planes[VIDEO_MAX_PLANES];
+};
+
+struct _GstV4l2Allocator
+{
+  GstAllocator parent;
+  GstV4l2Object *obj;
+  guint32 count;
+  guint32 memory;
+  gboolean can_allocate;
+  gboolean active;
+
+  GstV4l2MemoryGroup * groups[VIDEO_MAX_FRAME];
+  GstAtomicQueue *free_queue;
+  GstAtomicQueue *pending_queue;
+
+};
+
+struct _GstV4l2AllocatorClass {
+  GstAllocatorClass parent_class;
+};
+
+GType gst_v4l2_allocator_get_type(void);
+
+gboolean             gst_is_v4l2_memory                (GstMemory * mem);
+
+GQuark               gst_v4l2_memory_quark             (void);
+
+gboolean             gst_v4l2_allocator_is_active      (GstV4l2Allocator * allocator);
+
+guint                gst_v4l2_allocator_get_size       (GstV4l2Allocator * allocator);
+
+GstV4l2Allocator*    gst_v4l2_allocator_new            (GstObject *parent, GstV4l2Object * obj);
+
+guint                gst_v4l2_allocator_start          (GstV4l2Allocator * allocator,
+                                                        guint32 count, guint32 memory);
+
+GstV4l2Return        gst_v4l2_allocator_stop           (GstV4l2Allocator * allocator);
+
+GstV4l2MemoryGroup*  gst_v4l2_allocator_alloc_mmap     (GstV4l2Allocator * allocator);
+
+GstV4l2MemoryGroup*  gst_v4l2_allocator_alloc_dmabuf   (GstV4l2Allocator * allocator,
+                                                        GstAllocator * dmabuf_allocator);
+
+GstV4l2MemoryGroup * gst_v4l2_allocator_alloc_dmabufin (GstV4l2Allocator * allocator);
+
+GstV4l2MemoryGroup * gst_v4l2_allocator_alloc_userptr  (GstV4l2Allocator * allocator);
+
+gboolean             gst_v4l2_allocator_import_dmabuf  (GstV4l2Allocator * allocator,
+                                                        GstV4l2MemoryGroup *group,
+                                                        gint n_mem, GstMemory ** dma_mem);
+
+gboolean             gst_v4l2_allocator_import_userptr (GstV4l2Allocator * allocator,
+                                                        GstV4l2MemoryGroup *group,
+                                                        gsize img_size, int n_planes,
+                                                        gpointer * data, gsize * size);
+
+void                 gst_v4l2_allocator_flush          (GstV4l2Allocator * allocator);
+
+gboolean             gst_v4l2_allocator_qbuf           (GstV4l2Allocator * allocator,
+                                                        GstV4l2MemoryGroup * group);
+
+GstFlowReturn        gst_v4l2_allocator_dqbuf          (GstV4l2Allocator * allocator,
+                                                        GstV4l2MemoryGroup ** group);
+
+void                 gst_v4l2_allocator_reset_group    (GstV4l2Allocator * allocator,
+                                                        GstV4l2MemoryGroup * group);
+
+G_END_DECLS
+
+#endif /* __GST_V4L2_ALLOCATOR_H__ */
diff --git a/sys/v4l2/gstv4l2bufferpool.c b/sys/v4l2/gstv4l2bufferpool.c
new file mode 100644
index 0000000..86d5c8b
--- /dev/null
+++ b/sys/v4l2/gstv4l2bufferpool.c
@@ -0,0 +1,2015 @@
+/* GStreamer
+ *
+ * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *               2006 Edgard Lima <edgard.lima@gmail.com>
+ *               2009 Texas Instruments, Inc - http://www.ti.com/
+ *
+ * gstv4l2bufferpool.c V4L2 buffer pool class
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE            /* O_CLOEXEC */
+#endif
+#include <fcntl.h>
+
+#include <sys/mman.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "gst/video/video.h"
+#include "gst/video/gstvideometa.h"
+#include "gst/video/gstvideopool.h"
+#include "gst/allocators/gstdmabuf.h"
+
+#include <gstv4l2bufferpool.h>
+
+#include "gstv4l2object.h"
+#include "gst/gst-i18n-plugin.h"
+#include <gst/glib-compat-private.h>
+
+GST_DEBUG_CATEGORY_STATIC (v4l2bufferpool_debug);
+GST_DEBUG_CATEGORY_STATIC (CAT_PERFORMANCE);
+#define GST_CAT_DEFAULT v4l2bufferpool_debug
+
+#define GST_V4L2_IMPORT_QUARK gst_v4l2_buffer_pool_import_quark ()
+
+
+/*
+ * GstV4l2BufferPool:
+ */
+#define gst_v4l2_buffer_pool_parent_class parent_class
+G_DEFINE_TYPE (GstV4l2BufferPool, gst_v4l2_buffer_pool, GST_TYPE_BUFFER_POOL);
+
+enum _GstV4l2BufferPoolAcquireFlags
+{
+  GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_RESURRECT =
+      GST_BUFFER_POOL_ACQUIRE_FLAG_LAST,
+  GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_LAST
+};
+
+static void gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool,
+    GstBuffer * buffer);
+
+static gboolean
+gst_v4l2_is_buffer_valid (GstBuffer * buffer, GstV4l2MemoryGroup ** out_group)
+{
+  GstMemory *mem = gst_buffer_peek_memory (buffer, 0);
+  gboolean valid = FALSE;
+
+  if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY))
+    goto done;
+
+  if (gst_is_dmabuf_memory (mem))
+    mem = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
+        GST_V4L2_MEMORY_QUARK);
+
+  if (mem && gst_is_v4l2_memory (mem)) {
+    GstV4l2Memory *vmem = (GstV4l2Memory *) mem;
+    GstV4l2MemoryGroup *group = vmem->group;
+    gint i;
+
+    if (group->n_mem != gst_buffer_n_memory (buffer))
+      goto done;
+
+    for (i = 0; i < group->n_mem; i++) {
+      if (group->mem[i] != gst_buffer_peek_memory (buffer, i))
+        goto done;
+
+      if (!gst_memory_is_writable (group->mem[i]))
+        goto done;
+    }
+
+    valid = TRUE;
+    if (out_group)
+      *out_group = group;
+  }
+
+done:
+  return valid;
+}
+
+static GstFlowReturn
+gst_v4l2_buffer_pool_copy_buffer (GstV4l2BufferPool * pool, GstBuffer * dest,
+    GstBuffer * src)
+{
+  const GstVideoFormatInfo *finfo = pool->caps_info.finfo;
+
+  GST_LOG_OBJECT (pool, "copying buffer");
+
+  if (finfo && (finfo->format != GST_VIDEO_FORMAT_UNKNOWN &&
+          finfo->format != GST_VIDEO_FORMAT_ENCODED)) {
+    GstVideoFrame src_frame, dest_frame;
+
+    GST_DEBUG_OBJECT (pool, "copy video frame");
+
+    /* we have raw video, use videoframe copy to get strides right */
+    if (!gst_video_frame_map (&src_frame, &pool->caps_info, src, GST_MAP_READ))
+      goto invalid_buffer;
+
+    if (!gst_video_frame_map (&dest_frame, &pool->caps_info, dest,
+            GST_MAP_WRITE)) {
+      gst_video_frame_unmap (&src_frame);
+      goto invalid_buffer;
+    }
+
+    gst_video_frame_copy (&dest_frame, &src_frame);
+
+    gst_video_frame_unmap (&src_frame);
+    gst_video_frame_unmap (&dest_frame);
+  } else {
+    GstMapInfo map;
+
+    GST_DEBUG_OBJECT (pool, "copy raw bytes");
+
+    if (!gst_buffer_map (src, &map, GST_MAP_READ))
+      goto invalid_buffer;
+
+    gst_buffer_fill (dest, 0, map.data, gst_buffer_get_size (src));
+
+    gst_buffer_unmap (src, &map);
+    gst_buffer_resize (dest, 0, gst_buffer_get_size (src));
+  }
+
+  gst_buffer_copy_into (dest, src,
+      GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+
+  GST_CAT_LOG_OBJECT (CAT_PERFORMANCE, pool, "slow copy into buffer %p", dest);
+
+  return GST_FLOW_OK;
+
+invalid_buffer:
+  {
+    GST_ERROR_OBJECT (pool, "could not map buffer");
+    return GST_FLOW_ERROR;
+  }
+}
+
+struct UserPtrData
+{
+  GstBuffer *buffer;
+  gboolean is_frame;
+  GstVideoFrame frame;
+  GstMapInfo map;
+};
+
+static GQuark
+gst_v4l2_buffer_pool_import_quark (void)
+{
+  static GQuark quark = 0;
+
+  if (quark == 0)
+    quark = g_quark_from_string ("GstV4l2BufferPoolUsePtrData");
+
+  return quark;
+}
+
+static void
+_unmap_userptr_frame (struct UserPtrData *data)
+{
+  if (data->is_frame)
+    gst_video_frame_unmap (&data->frame);
+  else
+    gst_buffer_unmap (data->buffer, &data->map);
+
+  if (data->buffer)
+    gst_buffer_unref (data->buffer);
+
+  g_slice_free (struct UserPtrData, data);
+}
+
+static GstFlowReturn
+gst_v4l2_buffer_pool_import_userptr (GstV4l2BufferPool * pool,
+    GstBuffer * dest, GstBuffer * src)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstV4l2MemoryGroup *group = NULL;
+  GstMapFlags flags;
+  const GstVideoFormatInfo *finfo = pool->caps_info.finfo;
+  struct UserPtrData *data = NULL;
+
+  GST_LOG_OBJECT (pool, "importing userptr");
+
+  /* get the group */
+  if (!gst_v4l2_is_buffer_valid (dest, &group))
+    goto not_our_buffer;
+
+  if (V4L2_TYPE_IS_OUTPUT (pool->obj->type))
+    flags = GST_MAP_READ;
+  else
+    flags = GST_MAP_WRITE;
+
+  data = g_slice_new0 (struct UserPtrData);
+
+  if (finfo && (finfo->format != GST_VIDEO_FORMAT_UNKNOWN &&
+          finfo->format != GST_VIDEO_FORMAT_ENCODED)) {
+    gsize size[GST_VIDEO_MAX_PLANES] = { 0, };
+    gint i;
+
+    data->is_frame = TRUE;
+
+    if (!gst_video_frame_map (&data->frame, &pool->caps_info, src, flags))
+      goto invalid_buffer;
+
+    for (i = 0; i < GST_VIDEO_FORMAT_INFO_N_PLANES (finfo); i++) {
+      if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo)) {
+        gint tinfo = GST_VIDEO_FRAME_PLANE_STRIDE (&data->frame, i);
+        gint pstride;
+        guint pheight;
+
+        pstride = GST_VIDEO_TILE_X_TILES (tinfo) <<
+            GST_VIDEO_FORMAT_INFO_TILE_WS (finfo);
+
+        pheight = GST_VIDEO_TILE_Y_TILES (tinfo) <<
+            GST_VIDEO_FORMAT_INFO_TILE_HS (finfo);
+
+        size[i] = pstride * pheight;
+      } else {
+        size[i] = GST_VIDEO_FRAME_PLANE_STRIDE (&data->frame, i) *
+            GST_VIDEO_FRAME_COMP_HEIGHT (&data->frame, i);
+      }
+    }
+
+    /* In the single planar API, planes must be contiguous in memory and
+     * therefore they must have expected size. ie: no padding.
+     * To check these conditions, we check that plane 'i' start address
+     * + plane 'i' size equals to plane 'i+1' start address */
+    if (!V4L2_TYPE_IS_MULTIPLANAR (pool->obj->type)) {
+      for (i = 0; i < (GST_VIDEO_FORMAT_INFO_N_PLANES (finfo) - 1); i++) {
+        const struct v4l2_pix_format *pix_fmt = &pool->obj->format.fmt.pix;
+        gpointer tmp;
+        gint estride = gst_v4l2_object_extrapolate_stride (finfo, i,
+            pix_fmt->bytesperline);
+        guint eheight = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i,
+            pix_fmt->height);
+
+        tmp = ((guint8 *) data->frame.data[i]) + estride * eheight;
+        if (tmp != data->frame.data[i + 1])
+          goto non_contiguous_mem;
+      }
+    }
+
+    if (!gst_v4l2_allocator_import_userptr (pool->vallocator, group,
+            data->frame.info.size, finfo->n_planes, data->frame.data, size))
+      goto import_failed;
+  } else {
+    gpointer ptr[1];
+    gsize size[1];
+
+    data->is_frame = FALSE;
+
+    if (!gst_buffer_map (src, &data->map, flags))
+      goto invalid_buffer;
+
+    ptr[0] = data->map.data;
+    size[0] = data->map.size;
+
+    if (!gst_v4l2_allocator_import_userptr (pool->vallocator, group,
+            data->map.size, 1, ptr, size))
+      goto import_failed;
+  }
+
+  data->buffer = gst_buffer_ref (src);
+
+  gst_mini_object_set_qdata (GST_MINI_OBJECT (dest), GST_V4L2_IMPORT_QUARK,
+      data, (GDestroyNotify) _unmap_userptr_frame);
+
+  gst_buffer_copy_into (dest, src,
+      GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+
+  return ret;
+
+not_our_buffer:
+  {
+    GST_ERROR_OBJECT (pool, "destination buffer invalid or not from our pool");
+    return GST_FLOW_ERROR;
+  }
+invalid_buffer:
+  {
+    GST_ERROR_OBJECT (pool, "could not map buffer");
+    g_slice_free (struct UserPtrData, data);
+    return GST_FLOW_ERROR;
+  }
+non_contiguous_mem:
+  {
+    GST_ERROR_OBJECT (pool, "memory is not contiguous or plane size mismatch");
+    _unmap_userptr_frame (data);
+    return GST_FLOW_ERROR;
+  }
+import_failed:
+  {
+    GST_ERROR_OBJECT (pool, "failed to import data");
+    _unmap_userptr_frame (data);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstFlowReturn
+gst_v4l2_buffer_pool_import_dmabuf (GstV4l2BufferPool * pool,
+    GstBuffer * dest, GstBuffer * src)
+{
+  GstV4l2MemoryGroup *group = NULL;
+  GstMemory *dma_mem[GST_VIDEO_MAX_PLANES] = { 0 };
+  guint n_mem = gst_buffer_n_memory (src);
+  gint i;
+
+  GST_LOG_OBJECT (pool, "importing dmabuf");
+
+  if (!gst_v4l2_is_buffer_valid (dest, &group))
+    goto not_our_buffer;
+
+  if (n_mem > GST_VIDEO_MAX_PLANES)
+    goto too_many_mems;
+
+  for (i = 0; i < n_mem; i++)
+    dma_mem[i] = gst_buffer_peek_memory (src, i);
+
+  if (!gst_v4l2_allocator_import_dmabuf (pool->vallocator, group, n_mem,
+          dma_mem))
+    goto import_failed;
+
+  gst_mini_object_set_qdata (GST_MINI_OBJECT (dest), GST_V4L2_IMPORT_QUARK,
+      gst_buffer_ref (src), (GDestroyNotify) gst_buffer_unref);
+
+  gst_buffer_copy_into (dest, src,
+      GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+
+  return GST_FLOW_OK;
+
+not_our_buffer:
+  {
+    GST_ERROR_OBJECT (pool, "destination buffer invalid or not from our pool");
+    return GST_FLOW_ERROR;
+  }
+too_many_mems:
+  {
+    GST_ERROR_OBJECT (pool, "could not map buffer");
+    return GST_FLOW_ERROR;
+  }
+import_failed:
+  {
+    GST_ERROR_OBJECT (pool, "failed to import dmabuf");
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstFlowReturn
+gst_v4l2_buffer_pool_prepare_buffer (GstV4l2BufferPool * pool,
+    GstBuffer * dest, GstBuffer * src)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  gboolean own_src = FALSE;
+
+  if (src == NULL) {
+    if (pool->other_pool == NULL) {
+      GST_ERROR_OBJECT (pool, "can't prepare buffer, source buffer missing");
+      return GST_FLOW_ERROR;
+    }
+
+    ret = gst_buffer_pool_acquire_buffer (pool->other_pool, &src, NULL);
+    if (ret != GST_FLOW_OK) {
+      GST_ERROR_OBJECT (pool, "failed to acquire buffer from downstream pool");
+      goto done;
+    }
+
+    own_src = TRUE;
+  }
+
+  switch (pool->obj->mode) {
+    case GST_V4L2_IO_MMAP:
+    case GST_V4L2_IO_DMABUF:
+      ret = gst_v4l2_buffer_pool_copy_buffer (pool, dest, src);
+      break;
+    case GST_V4L2_IO_USERPTR:
+      ret = gst_v4l2_buffer_pool_import_userptr (pool, dest, src);
+      break;
+    case GST_V4L2_IO_DMABUF_IMPORT:
+      ret = gst_v4l2_buffer_pool_import_dmabuf (pool, dest, src);
+      break;
+    default:
+      break;
+  }
+
+  if (own_src)
+    gst_buffer_unref (src);
+
+done:
+  return ret;
+}
+
+static GstFlowReturn
+gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
+    GstBufferPoolAcquireParams * params)
+{
+  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+  GstV4l2MemoryGroup *group = NULL;
+  GstBuffer *newbuf = NULL;
+  GstV4l2Object *obj;
+  GstVideoInfo *info;
+
+  obj = pool->obj;
+  info = &obj->info;
+
+  switch (obj->mode) {
+    case GST_V4L2_IO_RW:
+      newbuf =
+          gst_buffer_new_allocate (pool->allocator, pool->size, &pool->params);
+      break;
+    case GST_V4L2_IO_MMAP:
+      group = gst_v4l2_allocator_alloc_mmap (pool->vallocator);
+      break;
+    case GST_V4L2_IO_DMABUF:
+      group = gst_v4l2_allocator_alloc_dmabuf (pool->vallocator,
+          pool->allocator);
+      break;
+    case GST_V4L2_IO_USERPTR:
+      group = gst_v4l2_allocator_alloc_userptr (pool->vallocator);
+      break;
+    case GST_V4L2_IO_DMABUF_IMPORT:
+      group = gst_v4l2_allocator_alloc_dmabufin (pool->vallocator);
+      break;
+    default:
+      newbuf = NULL;
+      g_assert_not_reached ();
+      break;
+  }
+
+  if (group != NULL) {
+    gint i;
+    newbuf = gst_buffer_new ();
+
+    for (i = 0; i < group->n_mem; i++)
+      gst_buffer_append_memory (newbuf, group->mem[i]);
+  } else if (newbuf == NULL) {
+    goto allocation_failed;
+  }
+
+  /* add metadata to raw video buffers */
+  if (pool->add_videometa)
+    gst_buffer_add_video_meta_full (newbuf, GST_VIDEO_FRAME_FLAG_NONE,
+        GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
+        GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info),
+        info->offset, info->stride);
+
+  *buffer = newbuf;
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+allocation_failed:
+  {
+    GST_ERROR_OBJECT (pool, "failed to allocate buffer");
+    return GST_FLOW_ERROR;
+  }
+}
+
+static gboolean
+gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config)
+{
+  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+  GstV4l2Object *obj = pool->obj;
+  GstCaps *caps;
+  guint size, min_buffers, max_buffers;
+  GstAllocator *allocator;
+  GstAllocationParams params;
+  gboolean can_allocate = FALSE;
+  gboolean updated = FALSE;
+  gboolean ret;
+
+  pool->add_videometa =
+      gst_buffer_pool_config_has_option (config,
+      GST_BUFFER_POOL_OPTION_VIDEO_META);
+
+  /* parse the config and keep around */
+  if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers,
+          &max_buffers))
+    goto wrong_config;
+
+  if (!gst_buffer_pool_config_get_allocator (config, &allocator, &params))
+    goto wrong_config;
+
+  GST_DEBUG_OBJECT (pool, "config %" GST_PTR_FORMAT, config);
+
+  if (pool->allocator)
+    gst_object_unref (pool->allocator);
+  pool->allocator = NULL;
+
+  switch (obj->mode) {
+    case GST_V4L2_IO_DMABUF:
+      pool->allocator = gst_dmabuf_allocator_new ();
+      can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP);
+      break;
+    case GST_V4L2_IO_MMAP:
+      can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP);
+      break;
+    case GST_V4L2_IO_USERPTR:
+      can_allocate =
+          GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, USERPTR);
+      break;
+    case GST_V4L2_IO_DMABUF_IMPORT:
+      can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, DMABUF);
+      break;
+    case GST_V4L2_IO_RW:
+      if (allocator)
+        pool->allocator = g_object_ref (allocator);
+      pool->params = params;
+      /* No need to change the configuration */
+      goto done;
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+
+  /* libv4l2 conversion code does not handle CREATE_BUFS, and may lead to
+   * instability and crash, disable it for now */
+  if (can_allocate && obj->fmtdesc->flags & V4L2_FMT_FLAG_EMULATED) {
+    GST_WARNING_OBJECT (pool,
+        "libv4l2 converter detected, disabling CREATE_BUFS");
+    can_allocate = FALSE;
+    GST_OBJECT_FLAG_UNSET (pool->vallocator,
+        GST_V4L2_ALLOCATOR_FLAG_MMAP_CREATE_BUFS
+        | GST_V4L2_ALLOCATOR_FLAG_USERPTR_CREATE_BUFS
+        | GST_V4L2_ALLOCATOR_FLAG_DMABUF_CREATE_BUFS);
+  }
+
+  if (min_buffers < GST_V4L2_MIN_BUFFERS) {
+    updated = TRUE;
+    min_buffers = GST_V4L2_MIN_BUFFERS;
+    GST_INFO_OBJECT (pool, "increasing minimum buffers to %u", min_buffers);
+  }
+
+  /* respect driver requirements */
+  if (min_buffers < obj->min_buffers) {
+    updated = TRUE;
+    min_buffers = obj->min_buffers;
+    GST_INFO_OBJECT (pool, "increasing minimum buffers to %u", min_buffers);
+  }
+
+  if (max_buffers > VIDEO_MAX_FRAME || max_buffers == 0) {
+    updated = TRUE;
+    max_buffers = VIDEO_MAX_FRAME;
+    GST_INFO_OBJECT (pool, "reducing maximum buffers to %u", max_buffers);
+  }
+
+  if (min_buffers > max_buffers) {
+    updated = TRUE;
+    min_buffers = max_buffers;
+    GST_INFO_OBJECT (pool, "reducing minimum buffers to %u", min_buffers);
+  } else if (min_buffers != max_buffers) {
+    if (!can_allocate) {
+      updated = TRUE;
+      max_buffers = min_buffers;
+      GST_INFO_OBJECT (pool, "can't allocate, setting maximum to minimum");
+    }
+  }
+
+  if (!pool->add_videometa && obj->need_video_meta) {
+    GST_INFO_OBJECT (pool, "adding needed video meta");
+    updated = TRUE;
+    gst_buffer_pool_config_add_option (config,
+        GST_BUFFER_POOL_OPTION_VIDEO_META);
+  }
+
+  /* Always update the config to ensure the configured size matches */
+  gst_buffer_pool_config_set_params (config, caps, obj->info.size, min_buffers,
+      max_buffers);
+
+  /* keep a GstVideoInfo with defaults for the when we need to copy */
+  gst_video_info_from_caps (&pool->caps_info, caps);
+
+done:
+  ret = GST_BUFFER_POOL_CLASS (parent_class)->set_config (bpool, config);
+
+  /* If anything was changed documentation recommand to return FALSE */
+  return !updated && ret;
+
+  /* ERRORS */
+wrong_config:
+  {
+    GST_ERROR_OBJECT (pool, "invalid config %" GST_PTR_FORMAT, config);
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_v4l2_buffer_pool_resurect_buffer (GstV4l2BufferPool * pool)
+{
+  GstBufferPoolAcquireParams params = { 0 };
+  GstBuffer *buffer = NULL;
+  GstFlowReturn ret;
+
+  GST_DEBUG_OBJECT (pool, "A buffer was lost, reallocating it");
+
+  /* block recursive calls to this function */
+  g_signal_handler_block (pool->vallocator, pool->group_released_handler);
+
+  params.flags =
+      (GstBufferPoolAcquireFlags) GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_RESURRECT |
+      GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
+  ret =
+      gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (pool), &buffer, &params);
+
+  if (ret == GST_FLOW_OK)
+    gst_buffer_unref (buffer);
+
+  g_signal_handler_unblock (pool->vallocator, pool->group_released_handler);
+
+  return ret;
+}
+
+static gboolean
+gst_v4l2_buffer_pool_streamon (GstV4l2BufferPool * pool)
+{
+  GstV4l2Object *obj = pool->obj;
+
+  if (pool->streaming)
+    return TRUE;
+
+  switch (obj->mode) {
+    case GST_V4L2_IO_MMAP:
+    case GST_V4L2_IO_USERPTR:
+    case GST_V4L2_IO_DMABUF:
+    case GST_V4L2_IO_DMABUF_IMPORT:
+      if (!V4L2_TYPE_IS_OUTPUT (pool->obj->type)) {
+        /* For captures, we need to enqueue buffers before we start streaming,
+         * so the driver don't underflow immediatly. As we have put then back
+         * into the base class queue, resurect them, then releasing will queue
+         * them back. */
+        while (gst_v4l2_buffer_pool_resurect_buffer (pool) == GST_FLOW_OK)
+          continue;
+      }
+
+      if (obj->ioctl (pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0)
+        goto streamon_failed;
+
+      pool->streaming = TRUE;
+
+      GST_DEBUG_OBJECT (pool, "Started streaming");
+      break;
+    default:
+      break;
+  }
+
+  return TRUE;
+
+streamon_failed:
+  {
+    GST_ERROR_OBJECT (pool, "error with STREAMON %d (%s)", errno,
+        g_strerror (errno));
+    return FALSE;
+  }
+}
+
+/* Call with streamlock held, or when streaming threads are down */
+static void
+gst_v4l2_buffer_pool_streamoff (GstV4l2BufferPool * pool)
+{
+  GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
+  GstV4l2Object *obj = pool->obj;
+  gint i;
+
+  if (!pool->streaming)
+    return;
+
+  switch (obj->mode) {
+    case GST_V4L2_IO_MMAP:
+    case GST_V4L2_IO_USERPTR:
+    case GST_V4L2_IO_DMABUF:
+    case GST_V4L2_IO_DMABUF_IMPORT:
+
+      if (obj->ioctl (pool->video_fd, VIDIOC_STREAMOFF, &obj->type) < 0)
+        GST_WARNING_OBJECT (pool, "STREAMOFF failed with errno %d (%s)",
+            errno, g_strerror (errno));
+
+      pool->streaming = FALSE;
+
+      GST_DEBUG_OBJECT (pool, "Stopped streaming");
+
+      if (pool->vallocator)
+        gst_v4l2_allocator_flush (pool->vallocator);
+      break;
+    default:
+      break;
+  }
+
+  for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+    if (pool->buffers[i]) {
+      GstBuffer *buffer = pool->buffers[i];
+      GstBufferPool *bpool = GST_BUFFER_POOL (pool);
+
+      pool->buffers[i] = NULL;
+
+      if (V4L2_TYPE_IS_OUTPUT (pool->obj->type))
+        gst_v4l2_buffer_pool_release_buffer (bpool, buffer);
+      else                      /* Don't re-enqueue capture buffer on stop */
+        pclass->release_buffer (bpool, buffer);
+
+      g_atomic_int_add (&pool->num_queued, -1);
+    }
+  }
+}
+
+static gboolean
+gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
+{
+  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+  GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
+  GstV4l2Object *obj = pool->obj;
+  GstStructure *config;
+  GstCaps *caps;
+  guint size, min_buffers, max_buffers;
+  guint max_latency, min_latency, copy_threshold = 0;
+  gboolean can_allocate = FALSE, ret = TRUE;
+
+  GST_DEBUG_OBJECT (pool, "activating pool");
+
+  config = gst_buffer_pool_get_config (bpool);
+  if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers,
+          &max_buffers))
+    goto wrong_config;
+
+  min_latency = MAX (GST_V4L2_MIN_BUFFERS, obj->min_buffers);
+
+  switch (obj->mode) {
+    case GST_V4L2_IO_RW:
+      can_allocate = TRUE;
+#ifdef HAVE_LIBV4L2
+      /* This workaround a unfixable bug in libv4l2 when RW is emulated on top
+       * of MMAP. In this case, the first read initialize the queues, but the
+       * poll before that will always fail. Doing an empty read, forces the
+       * queue to be initialized now. We only do this if we have a streaming
+       * driver. */
+      if (obj->device_caps & V4L2_CAP_STREAMING)
+        obj->read (obj->video_fd, NULL, 0);
+#endif
+      break;
+    case GST_V4L2_IO_DMABUF:
+    case GST_V4L2_IO_MMAP:
+    {
+      guint count;
+
+      can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP);
+
+      /* first, lets request buffers, and see how many we can get: */
+      GST_DEBUG_OBJECT (pool, "requesting %d MMAP buffers", min_buffers);
+
+      count = gst_v4l2_allocator_start (pool->vallocator, min_buffers,
+          V4L2_MEMORY_MMAP);
+
+      if (count < GST_V4L2_MIN_BUFFERS) {
+        min_buffers = count;
+        goto no_buffers;
+      }
+
+      /* V4L2 buffer pool are often very limited in the amount of buffers it
+       * can offer. The copy_threshold will workaround this limitation by
+       * falling back to copy if the pipeline needed more buffers. This also
+       * prevent having to do REQBUFS(N)/REQBUFS(0) everytime configure is
+       * called. */
+      if (count != min_buffers || pool->enable_copy_threshold) {
+        GST_WARNING_OBJECT (pool,
+            "Uncertain or not enough buffers, enabling copy threshold");
+        min_buffers = count;
+        copy_threshold = min_latency;
+      }
+
+      break;
+    }
+    case GST_V4L2_IO_USERPTR:
+    {
+      guint count;
+
+      can_allocate =
+          GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, USERPTR);
+
+      GST_DEBUG_OBJECT (pool, "requesting %d USERPTR buffers", min_buffers);
+
+      count = gst_v4l2_allocator_start (pool->vallocator, min_buffers,
+          V4L2_MEMORY_USERPTR);
+
+      /* There is no rational to not get what we asked */
+      if (count < min_buffers) {
+        min_buffers = count;
+        goto no_buffers;
+      }
+
+      min_buffers = count;
+      break;
+    }
+    case GST_V4L2_IO_DMABUF_IMPORT:
+    {
+      guint count;
+
+      can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, DMABUF);
+
+      GST_DEBUG_OBJECT (pool, "requesting %d DMABUF buffers", min_buffers);
+
+      count = gst_v4l2_allocator_start (pool->vallocator, min_buffers,
+          V4L2_MEMORY_DMABUF);
+
+      /* There is no rational to not get what we asked */
+      if (count < min_buffers) {
+        min_buffers = count;
+        goto no_buffers;
+      }
+
+      min_buffers = count;
+      break;
+    }
+    default:
+      min_buffers = 0;
+      copy_threshold = 0;
+      g_assert_not_reached ();
+      break;
+  }
+
+  if (can_allocate)
+    max_latency = max_buffers;
+  else
+    max_latency = min_buffers;
+
+  pool->size = size;
+  pool->copy_threshold = copy_threshold;
+  pool->max_latency = max_latency;
+  pool->min_latency = min_latency;
+  pool->num_queued = 0;
+
+  if (max_buffers != 0 && max_buffers < min_buffers)
+    max_buffers = min_buffers;
+
+  gst_buffer_pool_config_set_params (config, caps, size, min_buffers,
+      max_buffers);
+  pclass->set_config (bpool, config);
+  gst_structure_free (config);
+
+  if (pool->other_pool)
+    if (!gst_buffer_pool_set_active (pool->other_pool, TRUE))
+      goto other_pool_failed;
+
+  /* now, allocate the buffers: */
+  if (!pclass->start (bpool))
+    goto start_failed;
+
+  if (!V4L2_TYPE_IS_OUTPUT (obj->type)) {
+    pool->group_released_handler =
+        g_signal_connect_swapped (pool->vallocator, "group-released",
+        G_CALLBACK (gst_v4l2_buffer_pool_resurect_buffer), pool);
+    ret = gst_v4l2_buffer_pool_streamon (pool);
+  }
+
+  return ret;
+
+  /* ERRORS */
+wrong_config:
+  {
+    GST_ERROR_OBJECT (pool, "invalid config %" GST_PTR_FORMAT, config);
+    gst_structure_free (config);
+    return FALSE;
+  }
+no_buffers:
+  {
+    GST_ERROR_OBJECT (pool,
+        "we received %d buffer from device '%s', we want at least %d",
+        min_buffers, obj->videodev, GST_V4L2_MIN_BUFFERS);
+    gst_structure_free (config);
+    return FALSE;
+  }
+start_failed:
+  {
+    GST_ERROR_OBJECT (pool, "allocate failed");
+    return FALSE;
+  }
+other_pool_failed:
+  {
+    GST_ERROR_OBJECT (pool, "failed to active the other pool %"
+        GST_PTR_FORMAT, pool->other_pool);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_v4l2_buffer_pool_stop (GstBufferPool * bpool)
+{
+  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+  gboolean ret;
+
+  GST_DEBUG_OBJECT (pool, "stopping pool");
+
+  if (pool->group_released_handler > 0) {
+    g_signal_handler_disconnect (pool->vallocator,
+        pool->group_released_handler);
+    pool->group_released_handler = 0;
+  }
+
+  if (pool->other_pool) {
+    gst_buffer_pool_set_active (pool->other_pool, FALSE);
+    gst_object_unref (pool->other_pool);
+    pool->other_pool = NULL;
+  }
+
+  gst_v4l2_buffer_pool_streamoff (pool);
+
+  ret = GST_BUFFER_POOL_CLASS (parent_class)->stop (bpool);
+
+  if (ret && pool->vallocator) {
+    GstV4l2Return vret;
+
+    vret = gst_v4l2_allocator_stop (pool->vallocator);
+
+    if (vret == GST_V4L2_BUSY)
+      GST_WARNING_OBJECT (pool, "some buffers are still outstanding");
+
+    ret = (vret == GST_V4L2_OK);
+  }
+
+  return ret;
+}
+
+static void
+gst_v4l2_buffer_pool_flush_start (GstBufferPool * bpool)
+{
+  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+
+  GST_DEBUG_OBJECT (pool, "start flushing");
+
+  gst_poll_set_flushing (pool->poll, TRUE);
+
+  GST_OBJECT_LOCK (pool);
+  pool->empty = FALSE;
+  g_cond_broadcast (&pool->empty_cond);
+  GST_OBJECT_UNLOCK (pool);
+
+  if (pool->other_pool)
+    gst_buffer_pool_set_flushing (pool->other_pool, TRUE);
+}
+
+static void
+gst_v4l2_buffer_pool_flush_stop (GstBufferPool * bpool)
+{
+  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+
+  GST_DEBUG_OBJECT (pool, "stop flushing");
+
+  if (pool->other_pool)
+    gst_buffer_pool_set_flushing (pool->other_pool, FALSE);
+
+  gst_poll_set_flushing (pool->poll, FALSE);
+}
+
+static GstFlowReturn
+gst_v4l2_buffer_pool_poll (GstV4l2BufferPool * pool)
+{
+  gint ret;
+
+  /* In RW mode there is no queue, hence no need to wait while the queue is
+   * empty */
+  if (pool->obj->mode != GST_V4L2_IO_RW) {
+    GST_OBJECT_LOCK (pool);
+    while (pool->empty)
+      g_cond_wait (&pool->empty_cond, GST_OBJECT_GET_LOCK (pool));
+    GST_OBJECT_UNLOCK (pool);
+  }
+
+  if (!pool->can_poll_device)
+    goto done;
+
+  GST_LOG_OBJECT (pool, "polling device");
+
+again:
+  ret = gst_poll_wait (pool->poll, GST_CLOCK_TIME_NONE);
+  if (G_UNLIKELY (ret < 0)) {
+    switch (errno) {
+      case EBUSY:
+        goto stopped;
+      case EAGAIN:
+      case EINTR:
+        goto again;
+      case ENXIO:
+        GST_WARNING_OBJECT (pool,
+            "v4l2 device doesn't support polling. Disabling"
+            " using libv4l2 in this case may cause deadlocks");
+        pool->can_poll_device = FALSE;
+        goto done;
+      default:
+        goto select_error;
+    }
+  }
+
+  if (gst_poll_fd_has_error (pool->poll, &pool->pollfd))
+    goto select_error;
+
+done:
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+stopped:
+  {
+    GST_DEBUG_OBJECT (pool, "stop called");
+    return GST_FLOW_FLUSHING;
+  }
+select_error:
+  {
+    GST_ELEMENT_ERROR (pool->obj->element, RESOURCE, READ, (NULL),
+        ("poll error %d: %s (%d)", ret, g_strerror (errno), errno));
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstFlowReturn
+gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf)
+{
+  GstV4l2MemoryGroup *group = NULL;
+  const GstV4l2Object *obj = pool->obj;
+  GstClockTime timestamp;
+  gint index;
+
+  if (!gst_v4l2_is_buffer_valid (buf, &group)) {
+    GST_ERROR_OBJECT (pool, "invalid buffer %p", buf);
+    return GST_FLOW_ERROR;
+  }
+
+  index = group->buffer.index;
+
+  if (pool->buffers[index] != NULL)
+    goto already_queued;
+
+  GST_LOG_OBJECT (pool, "queuing buffer %i", index);
+
+  if (V4L2_TYPE_IS_OUTPUT (obj->type)) {
+    enum v4l2_field field;
+
+    /* Except when field is set to alternate, buffer field is the same as
+     * the one defined in format */
+    if (V4L2_TYPE_IS_MULTIPLANAR (obj->type))
+      field = obj->format.fmt.pix_mp.field;
+    else
+      field = obj->format.fmt.pix.field;
+
+    /* NB: At this moment, we can't have alternate mode because it not handled
+     * yet */
+    if (field == V4L2_FIELD_ALTERNATE) {
+      if (GST_BUFFER_FLAG_IS_SET (buf, GST_VIDEO_FRAME_FLAG_TFF))
+        field = V4L2_FIELD_TOP;
+      else
+        field = V4L2_FIELD_BOTTOM;
+    }
+
+    group->buffer.field = field;
+  }
+
+  if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+    timestamp = GST_BUFFER_TIMESTAMP (buf);
+    GST_TIME_TO_TIMEVAL (timestamp, group->buffer.timestamp);
+  }
+
+  GST_OBJECT_LOCK (pool);
+  g_atomic_int_inc (&pool->num_queued);
+  pool->buffers[index] = buf;
+
+  if (!gst_v4l2_allocator_qbuf (pool->vallocator, group))
+    goto queue_failed;
+
+  pool->empty = FALSE;
+  g_cond_signal (&pool->empty_cond);
+  GST_OBJECT_UNLOCK (pool);
+
+  return GST_FLOW_OK;
+
+already_queued:
+  {
+    GST_ERROR_OBJECT (pool, "the buffer %i was already queued", index);
+    return GST_FLOW_ERROR;
+  }
+queue_failed:
+  {
+    GST_ERROR_OBJECT (pool, "could not queue a buffer %i", index);
+    /* Mark broken buffer to the allocator */
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_TAG_MEMORY);
+    g_atomic_int_add (&pool->num_queued, -1);
+    pool->buffers[index] = NULL;
+    GST_OBJECT_UNLOCK (pool);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstFlowReturn
+gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer)
+{
+  GstFlowReturn res;
+  GstBuffer *outbuf;
+  GstV4l2Object *obj = pool->obj;
+  GstClockTime timestamp;
+  GstV4l2MemoryGroup *group;
+  GstVideoMeta *vmeta;
+  gsize size;
+  gint i;
+
+  if ((res = gst_v4l2_buffer_pool_poll (pool)) != GST_FLOW_OK)
+    goto poll_failed;
+
+  GST_LOG_OBJECT (pool, "dequeueing a buffer");
+
+  res = gst_v4l2_allocator_dqbuf (pool->vallocator, &group);
+  if (res == GST_FLOW_EOS)
+    goto eos;
+  if (res != GST_FLOW_OK)
+    goto dqbuf_failed;
+
+  /* get our GstBuffer with that index from the pool, if the buffer was
+   * outstanding we have a serious problem.
+   */
+  outbuf = pool->buffers[group->buffer.index];
+  if (outbuf == NULL)
+    goto no_buffer;
+
+  /* mark the buffer outstanding */
+  pool->buffers[group->buffer.index] = NULL;
+  if (g_atomic_int_dec_and_test (&pool->num_queued)) {
+    GST_OBJECT_LOCK (pool);
+    pool->empty = TRUE;
+    GST_OBJECT_UNLOCK (pool);
+  }
+
+  timestamp = GST_TIMEVAL_TO_TIME (group->buffer.timestamp);
+
+  size = 0;
+  vmeta = gst_buffer_get_video_meta (outbuf);
+  for (i = 0; i < group->n_mem; i++) {
+    GST_LOG_OBJECT (pool,
+        "dequeued buffer %p seq:%d (ix=%d), mem %p used %d, plane=%d, flags %08x, ts %"
+        GST_TIME_FORMAT ", pool-queued=%d, buffer=%p", outbuf,
+        group->buffer.sequence, group->buffer.index, group->mem[i],
+        group->planes[i].bytesused, i, group->buffer.flags,
+        GST_TIME_ARGS (timestamp), pool->num_queued, outbuf);
+
+    if (vmeta) {
+      vmeta->offset[i] = size;
+      size += gst_memory_get_sizes (group->mem[i], NULL, NULL);
+    }
+  }
+
+  /* Ignore timestamp and field for OUTPUT device */
+  if (V4L2_TYPE_IS_OUTPUT (obj->type))
+    goto done;
+
+  /* Check for driver bug in reporting feild */
+  if (group->buffer.field == V4L2_FIELD_ANY) {
+    /* Only warn once to avoid the spamming */
+#ifndef GST_DISABLE_GST_DEBUG
+    if (!pool->has_warned_on_buggy_field) {
+      pool->has_warned_on_buggy_field = TRUE;
+      GST_WARNING_OBJECT (pool,
+          "Driver should never set v4l2_buffer.field to ANY");
+    }
+#endif
+
+    /* Use the value from the format (works for UVC bug) */
+    group->buffer.field = obj->format.fmt.pix.field;
+
+    /* If driver also has buggy S_FMT, assume progressive */
+    if (group->buffer.field == V4L2_FIELD_ANY) {
+#ifndef GST_DISABLE_GST_DEBUG
+      if (!pool->has_warned_on_buggy_field) {
+        pool->has_warned_on_buggy_field = TRUE;
+        GST_WARNING_OBJECT (pool,
+            "Driver should never set v4l2_format.pix.field to ANY");
+      }
+#endif
+
+      group->buffer.field = V4L2_FIELD_NONE;
+    }
+  }
+
+  /* set top/bottom field first if v4l2_buffer has the information */
+  switch (group->buffer.field) {
+    case V4L2_FIELD_NONE:
+      GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
+      GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
+      break;
+    case V4L2_FIELD_INTERLACED_TB:
+      GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
+      GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
+      break;
+    case V4L2_FIELD_INTERLACED_BT:
+      GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
+      GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
+      break;
+    case V4L2_FIELD_INTERLACED:
+      GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
+      if (obj->tv_norm == V4L2_STD_NTSC_M ||
+          obj->tv_norm == V4L2_STD_NTSC_M_JP ||
+          obj->tv_norm == V4L2_STD_NTSC_M_KR) {
+        GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
+      } else {
+        GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
+      }
+      break;
+    default:
+      GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
+      GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
+      GST_FIXME_OBJECT (pool,
+          "Unhandled enum v4l2_field %d - treating as progressive",
+          group->buffer.field);
+      break;
+  }
+
+  if (GST_VIDEO_INFO_FORMAT (&obj->info) == GST_VIDEO_FORMAT_ENCODED) {
+    if ((group->buffer.flags & V4L2_BUF_FLAG_KEYFRAME) ||
+        GST_V4L2_PIXELFORMAT (obj) == V4L2_PIX_FMT_MJPEG ||
+        GST_V4L2_PIXELFORMAT (obj) == V4L2_PIX_FMT_JPEG ||
+        GST_V4L2_PIXELFORMAT (obj) == V4L2_PIX_FMT_PJPG)
+      GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+    else
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+  }
+
+  if (group->buffer.flags & V4L2_BUF_FLAG_ERROR)
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_CORRUPTED);
+
+  GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+  GST_BUFFER_OFFSET (outbuf) = group->buffer.sequence;
+  GST_BUFFER_OFFSET_END (outbuf) = group->buffer.sequence + 1;
+
+done:
+  *buffer = outbuf;
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+poll_failed:
+  {
+    GST_DEBUG_OBJECT (pool, "poll error %s", gst_flow_get_name (res));
+    return res;
+  }
+eos:
+  {
+    return GST_FLOW_EOS;
+  }
+dqbuf_failed:
+  {
+    return GST_FLOW_ERROR;
+  }
+no_buffer:
+  {
+    GST_ERROR_OBJECT (pool, "No free buffer found in the pool at index %d.",
+        group->buffer.index);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstFlowReturn
+gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
+    GstBufferPoolAcquireParams * params)
+{
+  GstFlowReturn ret;
+  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+  GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
+  GstV4l2Object *obj = pool->obj;
+
+  GST_DEBUG_OBJECT (pool, "acquire");
+
+  /* If this is being called to resurect a lost buffer */
+  if (params && params->flags & GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_RESURRECT) {
+    ret = pclass->acquire_buffer (bpool, buffer, params);
+    goto done;
+  }
+
+  switch (obj->type) {
+    case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+    case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+      /* capture, This function should return a buffer with new captured data */
+      switch (obj->mode) {
+        case GST_V4L2_IO_RW:
+        {
+          /* take empty buffer from the pool */
+          ret = pclass->acquire_buffer (bpool, buffer, params);
+          break;
+        }
+        case GST_V4L2_IO_DMABUF:
+        case GST_V4L2_IO_MMAP:
+        case GST_V4L2_IO_USERPTR:
+        case GST_V4L2_IO_DMABUF_IMPORT:
+        {
+          /* just dequeue a buffer, we basically use the queue of v4l2 as the
+           * storage for our buffers. This function does poll first so we can
+           * interrupt it fine. */
+          ret = gst_v4l2_buffer_pool_dqbuf (pool, buffer);
+          break;
+        }
+        default:
+          ret = GST_FLOW_ERROR;
+          g_assert_not_reached ();
+          break;
+      }
+      break;
+
+
+    case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+    case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+      /* playback, This function should return an empty buffer */
+      switch (obj->mode) {
+        case GST_V4L2_IO_RW:
+          /* get an empty buffer */
+          ret = pclass->acquire_buffer (bpool, buffer, params);
+          break;
+
+        case GST_V4L2_IO_MMAP:
+        case GST_V4L2_IO_DMABUF:
+        case GST_V4L2_IO_USERPTR:
+        case GST_V4L2_IO_DMABUF_IMPORT:
+          /* get a free unqueued buffer */
+          ret = pclass->acquire_buffer (bpool, buffer, params);
+          break;
+
+        default:
+          ret = GST_FLOW_ERROR;
+          g_assert_not_reached ();
+          break;
+      }
+      break;
+
+    default:
+      ret = GST_FLOW_ERROR;
+      g_assert_not_reached ();
+      break;
+  }
+done:
+  return ret;
+}
+
+static void
+gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
+{
+  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+  GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
+  GstV4l2Object *obj = pool->obj;
+
+  GST_DEBUG_OBJECT (pool, "release buffer %p", buffer);
+
+  switch (obj->type) {
+    case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+    case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+      /* capture, put the buffer back in the queue so that we can refill it
+       * later. */
+      switch (obj->mode) {
+        case GST_V4L2_IO_RW:
+          /* release back in the pool */
+          pclass->release_buffer (bpool, buffer);
+          break;
+
+        case GST_V4L2_IO_DMABUF:
+        case GST_V4L2_IO_MMAP:
+        case GST_V4L2_IO_USERPTR:
+        case GST_V4L2_IO_DMABUF_IMPORT:
+        {
+          GstV4l2MemoryGroup *group;
+          if (gst_v4l2_is_buffer_valid (buffer, &group)) {
+            gst_v4l2_allocator_reset_group (pool->vallocator, group);
+            /* queue back in the device */
+            if (pool->other_pool)
+              gst_v4l2_buffer_pool_prepare_buffer (pool, buffer, NULL);
+            if (gst_v4l2_buffer_pool_qbuf (pool, buffer) != GST_FLOW_OK)
+              pclass->release_buffer (bpool, buffer);
+          } else {
+            /* Simply release invalide/modified buffer, the allocator will
+             * give it back later */
+            GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
+            pclass->release_buffer (bpool, buffer);
+          }
+          break;
+        }
+        default:
+          g_assert_not_reached ();
+          break;
+      }
+      break;
+
+    case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+    case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+      switch (obj->mode) {
+        case GST_V4L2_IO_RW:
+          /* release back in the pool */
+          pclass->release_buffer (bpool, buffer);
+          break;
+
+        case GST_V4L2_IO_MMAP:
+        case GST_V4L2_IO_DMABUF:
+        case GST_V4L2_IO_USERPTR:
+        case GST_V4L2_IO_DMABUF_IMPORT:
+        {
+          GstV4l2MemoryGroup *group;
+          guint index;
+
+          if (!gst_v4l2_is_buffer_valid (buffer, &group)) {
+            /* Simply release invalide/modified buffer, the allocator will
+             * give it back later */
+            GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
+            pclass->release_buffer (bpool, buffer);
+            break;
+          }
+
+          index = group->buffer.index;
+
+          if (pool->buffers[index] == NULL) {
+            GST_LOG_OBJECT (pool, "buffer %u not queued, putting on free list",
+                index);
+
+            /* Remove qdata, this will unmap any map data in userptr */
+            gst_mini_object_set_qdata (GST_MINI_OBJECT (buffer),
+                GST_V4L2_IMPORT_QUARK, NULL, NULL);
+
+            /* reset to default size */
+            gst_v4l2_allocator_reset_group (pool->vallocator, group);
+
+            /* playback, put the buffer back in the queue to refill later. */
+            pclass->release_buffer (bpool, buffer);
+          } else {
+            /* the buffer is queued in the device but maybe not played yet. We just
+             * leave it there and not make it available for future calls to acquire
+             * for now. The buffer will be dequeued and reused later. */
+            GST_LOG_OBJECT (pool, "buffer %u is queued", index);
+          }
+          break;
+        }
+
+        default:
+          g_assert_not_reached ();
+          break;
+      }
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+static void
+gst_v4l2_buffer_pool_dispose (GObject * object)
+{
+  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (object);
+
+  if (pool->vallocator)
+    gst_object_unref (pool->vallocator);
+  pool->vallocator = NULL;
+
+  if (pool->allocator)
+    gst_object_unref (pool->allocator);
+  pool->allocator = NULL;
+
+  if (pool->other_pool)
+    gst_object_unref (pool->other_pool);
+  pool->other_pool = NULL;
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_v4l2_buffer_pool_finalize (GObject * object)
+{
+  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (object);
+
+  if (pool->video_fd >= 0)
+    pool->obj->close (pool->video_fd);
+
+  gst_poll_free (pool->poll);
+
+  /* This can't be done in dispose method because we must not set pointer
+   * to NULL as it is part of the v4l2object and dispose could be called
+   * multiple times */
+  gst_object_unref (pool->obj->element);
+
+  g_cond_clear (&pool->empty_cond);
+
+  /* FIXME have we done enough here ? */
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_v4l2_buffer_pool_init (GstV4l2BufferPool * pool)
+{
+  pool->poll = gst_poll_new (TRUE);
+  pool->can_poll_device = TRUE;
+  g_cond_init (&pool->empty_cond);
+  pool->empty = TRUE;
+}
+
+static void
+gst_v4l2_buffer_pool_class_init (GstV4l2BufferPoolClass * klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GstBufferPoolClass *bufferpool_class = GST_BUFFER_POOL_CLASS (klass);
+
+  object_class->dispose = gst_v4l2_buffer_pool_dispose;
+  object_class->finalize = gst_v4l2_buffer_pool_finalize;
+
+  bufferpool_class->start = gst_v4l2_buffer_pool_start;
+  bufferpool_class->stop = gst_v4l2_buffer_pool_stop;
+  bufferpool_class->set_config = gst_v4l2_buffer_pool_set_config;
+  bufferpool_class->alloc_buffer = gst_v4l2_buffer_pool_alloc_buffer;
+  bufferpool_class->acquire_buffer = gst_v4l2_buffer_pool_acquire_buffer;
+  bufferpool_class->release_buffer = gst_v4l2_buffer_pool_release_buffer;
+  bufferpool_class->flush_start = gst_v4l2_buffer_pool_flush_start;
+  bufferpool_class->flush_stop = gst_v4l2_buffer_pool_flush_stop;
+
+  GST_DEBUG_CATEGORY_INIT (v4l2bufferpool_debug, "v4l2bufferpool", 0,
+      "V4L2 Buffer Pool");
+  GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE");
+}
+
+/**
+ * gst_v4l2_buffer_pool_new:
+ * @obj:  the v4l2 object owning the pool
+ *
+ * Construct a new buffer pool.
+ *
+ * Returns: the new pool, use gst_object_unref() to free resources
+ */
+GstBufferPool *
+gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps)
+{
+  GstV4l2BufferPool *pool;
+  GstStructure *config;
+  gchar *name, *parent_name;
+  gint fd;
+
+  fd = obj->dup (obj->video_fd);
+  if (fd < 0)
+    goto dup_failed;
+
+  /* setting a significant unique name */
+  parent_name = gst_object_get_name (GST_OBJECT (obj->element));
+  name = g_strconcat (parent_name, ":", "pool:",
+      V4L2_TYPE_IS_OUTPUT (obj->type) ? "sink" : "src", NULL);
+  g_free (parent_name);
+
+  pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL,
+      "name", name, NULL);
+  g_object_ref_sink (pool);
+  g_free (name);
+
+  gst_poll_fd_init (&pool->pollfd);
+  pool->pollfd.fd = fd;
+  gst_poll_add_fd (pool->poll, &pool->pollfd);
+  if (V4L2_TYPE_IS_OUTPUT (obj->type))
+    gst_poll_fd_ctl_write (pool->poll, &pool->pollfd, TRUE);
+  else
+    gst_poll_fd_ctl_read (pool->poll, &pool->pollfd, TRUE);
+
+  pool->video_fd = fd;
+  pool->obj = obj;
+  pool->can_poll_device = TRUE;
+
+  pool->vallocator = gst_v4l2_allocator_new (GST_OBJECT (pool), obj);
+  if (pool->vallocator == NULL)
+    goto allocator_failed;
+
+  gst_object_ref (obj->element);
+
+  config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
+  gst_buffer_pool_config_set_params (config, caps, obj->info.size, 0, 0);
+  /* This will simply set a default config, but will not configure the pool
+   * because min and max are not valid */
+  gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), config);
+
+  return GST_BUFFER_POOL (pool);
+
+  /* ERRORS */
+dup_failed:
+  {
+    GST_ERROR ("failed to dup fd %d (%s)", errno, g_strerror (errno));
+    return NULL;
+  }
+allocator_failed:
+  {
+    GST_ERROR_OBJECT (pool, "Failed to create V4L2 allocator");
+    gst_object_unref (pool);
+    return NULL;
+  }
+}
+
+static GstFlowReturn
+gst_v4l2_do_read (GstV4l2BufferPool * pool, GstBuffer * buf)
+{
+  GstFlowReturn res;
+  GstV4l2Object *obj = pool->obj;
+  gint amount;
+  GstMapInfo map;
+  gint toread;
+
+  toread = obj->info.size;
+
+  GST_LOG_OBJECT (pool, "reading %d bytes into buffer %p", toread, buf);
+
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+
+  do {
+    if ((res = gst_v4l2_buffer_pool_poll (pool)) != GST_FLOW_OK)
+      goto poll_error;
+
+    amount = obj->read (obj->video_fd, map.data, toread);
+
+    if (amount == toread) {
+      break;
+    } else if (amount == -1) {
+      if (errno == EAGAIN || errno == EINTR) {
+        continue;
+      } else
+        goto read_error;
+    } else {
+      /* short reads can happen if a signal interrupts the read */
+      continue;
+    }
+  } while (TRUE);
+
+  GST_LOG_OBJECT (pool, "read %d bytes", amount);
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_resize (buf, 0, amount);
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+poll_error:
+  {
+    GST_DEBUG ("poll error %s", gst_flow_get_name (res));
+    goto cleanup;
+  }
+read_error:
+  {
+    GST_ELEMENT_ERROR (obj->element, RESOURCE, READ,
+        (_("Error reading %d bytes from device '%s'."),
+            toread, obj->videodev), GST_ERROR_SYSTEM);
+    res = GST_FLOW_ERROR;
+    goto cleanup;
+  }
+cleanup:
+  {
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_resize (buf, 0, 0);
+    return res;
+  }
+}
+
+/**
+ * gst_v4l2_buffer_pool_process:
+ * @bpool: a #GstBufferPool
+ * @buf: a #GstBuffer, maybe be replaced
+ *
+ * Process @buf in @bpool. For capture devices, this functions fills @buf with
+ * data from the device. For output devices, this functions send the contents of
+ * @buf to the device for playback.
+ *
+ * Returns: %GST_FLOW_OK on success.
+ */
+GstFlowReturn
+gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBufferPool *bpool = GST_BUFFER_POOL_CAST (pool);
+  GstV4l2Object *obj = pool->obj;
+
+  GST_DEBUG_OBJECT (pool, "process buffer %p", buf);
+
+  if (GST_BUFFER_POOL_IS_FLUSHING (pool))
+    return GST_FLOW_FLUSHING;
+
+  switch (obj->type) {
+    case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+    case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+      /* capture */
+      switch (obj->mode) {
+        case GST_V4L2_IO_RW:
+          /* capture into the buffer */
+          ret = gst_v4l2_do_read (pool, *buf);
+          break;
+
+        case GST_V4L2_IO_MMAP:
+        case GST_V4L2_IO_DMABUF:
+        {
+          GstBuffer *tmp;
+
+          if ((*buf)->pool == bpool) {
+            guint num_queued;
+            gsize size = gst_buffer_get_size (*buf);
+
+            if (size == 0) {
+              if (GST_BUFFER_FLAG_IS_SET (*buf, GST_BUFFER_FLAG_CORRUPTED))
+                goto buffer_corrupted;
+              else
+                goto eos;
+            }
+
+            num_queued = g_atomic_int_get (&pool->num_queued);
+            GST_TRACE_OBJECT (pool, "Only %i buffer left in the capture queue.",
+                num_queued);
+
+            /* If we have no more buffer, and can allocate it time to do so */
+            if (num_queued == 0) {
+              if (GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP)) {
+                ret = gst_v4l2_buffer_pool_resurect_buffer (pool);
+                if (ret == GST_FLOW_OK)
+                  goto done;
+              }
+            }
+
+            /* start copying buffers when we are running low on buffers */
+            if (num_queued < pool->copy_threshold) {
+              GstBuffer *copy;
+
+              if (GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP)) {
+                ret = gst_v4l2_buffer_pool_resurect_buffer (pool);
+                if (ret == GST_FLOW_OK)
+                  goto done;
+              }
+
+              /* copy the buffer */
+              copy = gst_buffer_copy_region (*buf,
+                  GST_BUFFER_COPY_ALL | GST_BUFFER_COPY_DEEP, 0, -1);
+              GST_LOG_OBJECT (pool, "copy buffer %p->%p", *buf, copy);
+
+              /* and requeue so that we can continue capturing */
+              gst_buffer_unref (*buf);
+              *buf = copy;
+            }
+
+            ret = GST_FLOW_OK;
+            /* nothing, data was inside the buffer when we did _acquire() */
+            goto done;
+          }
+
+          /* buffer not from our pool, grab a frame and copy it into the target */
+          if ((ret = gst_v4l2_buffer_pool_dqbuf (pool, &tmp)) != GST_FLOW_OK)
+            goto done;
+
+          /* An empty buffer on capture indicates the end of stream */
+          if (gst_buffer_get_size (tmp) == 0) {
+            gboolean corrupted = GST_BUFFER_FLAG_IS_SET (tmp,
+                GST_BUFFER_FLAG_CORRUPTED);
+
+            gst_v4l2_buffer_pool_release_buffer (bpool, tmp);
+
+            if (corrupted)
+              goto buffer_corrupted;
+            else
+              goto eos;
+          }
+
+          ret = gst_v4l2_buffer_pool_copy_buffer (pool, *buf, tmp);
+
+          /* an queue the buffer again after the copy */
+          gst_v4l2_buffer_pool_release_buffer (bpool, tmp);
+
+          if (ret != GST_FLOW_OK)
+            goto copy_failed;
+          break;
+        }
+
+        case GST_V4L2_IO_USERPTR:
+        {
+          struct UserPtrData *data;
+          GstBuffer *tmp;
+
+          /* Replace our buffer with downstream allocated buffer */
+          data = gst_mini_object_steal_qdata (GST_MINI_OBJECT (*buf),
+              GST_V4L2_IMPORT_QUARK);
+          tmp = gst_buffer_ref (data->buffer);
+          _unmap_userptr_frame (data);
+
+          /* Now tmp is writable, copy the flags and timestamp */
+          gst_buffer_copy_into (tmp, *buf,
+              GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+
+          gst_buffer_replace (buf, tmp);
+          gst_buffer_unref (tmp);
+          break;
+        }
+
+        case GST_V4L2_IO_DMABUF_IMPORT:
+        {
+          GstBuffer *tmp;
+
+          /* Replace our buffer with downstream allocated buffer */
+          tmp = gst_mini_object_steal_qdata (GST_MINI_OBJECT (*buf),
+              GST_V4L2_IMPORT_QUARK);
+
+          gst_buffer_copy_into (tmp, *buf,
+              GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+
+          gst_buffer_replace (buf, tmp);
+          gst_buffer_unref (tmp);
+          break;
+        }
+
+        default:
+          g_assert_not_reached ();
+          break;
+      }
+      break;
+
+    case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+    case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+      /* playback */
+      switch (obj->mode) {
+        case GST_V4L2_IO_RW:
+          /* FIXME, do write() */
+          GST_WARNING_OBJECT (pool, "implement write()");
+          break;
+
+        case GST_V4L2_IO_USERPTR:
+        case GST_V4L2_IO_DMABUF_IMPORT:
+        case GST_V4L2_IO_DMABUF:
+        case GST_V4L2_IO_MMAP:
+        {
+          GstBuffer *to_queue = NULL;
+          GstV4l2MemoryGroup *group;
+          gint index;
+
+          if ((*buf)->pool != bpool)
+            goto copying;
+
+          if (!gst_v4l2_is_buffer_valid (*buf, &group))
+            goto copying;
+
+          index = group->buffer.index;
+
+          GST_LOG_OBJECT (pool, "processing buffer %i from our pool", index);
+
+          if (pool->buffers[index] != NULL) {
+            GST_LOG_OBJECT (pool, "buffer %i already queued, copying", index);
+            goto copying;
+          }
+
+          /* we can queue directly */
+          to_queue = gst_buffer_ref (*buf);
+
+        copying:
+          if (to_queue == NULL) {
+            GstBufferPoolAcquireParams params = { 0 };
+
+            GST_LOG_OBJECT (pool, "alloc buffer from our pool");
+
+            /* this can return EOS if all buffers are outstanding which would
+             * be strange because we would expect the upstream element to have
+             * allocated them and returned to us.. */
+            params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
+            ret = gst_buffer_pool_acquire_buffer (bpool, &to_queue, &params);
+            if (ret != GST_FLOW_OK)
+              goto acquire_failed;
+
+            ret = gst_v4l2_buffer_pool_prepare_buffer (pool, to_queue, *buf);
+            if (ret != GST_FLOW_OK) {
+              gst_buffer_unref (to_queue);
+              goto prepare_failed;
+            }
+          }
+
+          if ((ret = gst_v4l2_buffer_pool_qbuf (pool, to_queue)) != GST_FLOW_OK)
+            goto queue_failed;
+
+          /* if we are not streaming yet (this is the first buffer, start
+           * streaming now */
+          if (!gst_v4l2_buffer_pool_streamon (pool)) {
+            /* don't check return value because qbuf would have failed */
+            gst_v4l2_is_buffer_valid (to_queue, &group);
+
+            /* qbuf has stored to_queue buffer but we are not in
+             * streaming state, so the flush logic won't be performed.
+             * To avoid leaks, flush the allocator and restore the queued
+             * buffer as non-queued */
+            gst_v4l2_allocator_flush (pool->vallocator);
+
+            pool->buffers[group->buffer.index] = NULL;
+
+            gst_mini_object_set_qdata (GST_MINI_OBJECT (to_queue),
+                GST_V4L2_IMPORT_QUARK, NULL, NULL);
+            gst_buffer_unref (to_queue);
+            g_atomic_int_add (&pool->num_queued, -1);
+            goto start_failed;
+          }
+
+          /* Remove our ref, we will still hold this buffer in acquire as needed,
+           * otherwise the pool will think it is outstanding and will refuse to stop. */
+          gst_buffer_unref (to_queue);
+
+          if (g_atomic_int_get (&pool->num_queued) >= pool->min_latency) {
+            GstBuffer *out;
+            /* all buffers are queued, try to dequeue one and release it back
+             * into the pool so that _acquire can get to it again. */
+            ret = gst_v4l2_buffer_pool_dqbuf (pool, &out);
+            if (ret == GST_FLOW_OK && out->pool == NULL)
+              /* release the rendered buffer back into the pool. This wakes up any
+               * thread waiting for a buffer in _acquire(). */
+              gst_v4l2_buffer_pool_release_buffer (bpool, out);
+          }
+          break;
+        }
+        default:
+          g_assert_not_reached ();
+          break;
+      }
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+done:
+  return ret;
+
+  /* ERRORS */
+copy_failed:
+  {
+    GST_ERROR_OBJECT (pool, "failed to copy buffer");
+    return ret;
+  }
+buffer_corrupted:
+  {
+    GST_WARNING_OBJECT (pool, "Dropping corrupted buffer without payload");
+    gst_buffer_unref (*buf);
+    *buf = NULL;
+    return GST_V4L2_FLOW_CORRUPTED_BUFFER;
+  }
+eos:
+  {
+    GST_DEBUG_OBJECT (pool, "end of stream reached");
+    gst_buffer_unref (*buf);
+    *buf = NULL;
+    return GST_V4L2_FLOW_LAST_BUFFER;
+  }
+acquire_failed:
+  {
+    if (ret == GST_FLOW_FLUSHING)
+      GST_DEBUG_OBJECT (pool, "flushing");
+    else
+      GST_WARNING_OBJECT (pool, "failed to acquire a buffer: %s",
+          gst_flow_get_name (ret));
+    return ret;
+  }
+prepare_failed:
+  {
+    GST_ERROR_OBJECT (pool, "failed to prepare data");
+    return ret;
+  }
+queue_failed:
+  {
+    GST_ERROR_OBJECT (pool, "failed to queue buffer");
+    return ret;
+  }
+start_failed:
+  {
+    GST_ERROR_OBJECT (pool, "failed to start streaming");
+    return GST_FLOW_ERROR;
+  }
+}
+
+void
+gst_v4l2_buffer_pool_set_other_pool (GstV4l2BufferPool * pool,
+    GstBufferPool * other_pool)
+{
+  g_return_if_fail (!gst_buffer_pool_is_active (GST_BUFFER_POOL (pool)));
+
+  if (pool->other_pool)
+    gst_object_unref (pool->other_pool);
+  pool->other_pool = gst_object_ref (other_pool);
+}
+
+void
+gst_v4l2_buffer_pool_copy_at_threshold (GstV4l2BufferPool * pool, gboolean copy)
+{
+  GST_OBJECT_LOCK (pool);
+  pool->enable_copy_threshold = copy;
+  GST_OBJECT_UNLOCK (pool);
+}
+
+gboolean
+gst_v4l2_buffer_pool_flush (GstBufferPool * bpool)
+{
+  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+  gboolean ret = TRUE;
+
+  gst_v4l2_buffer_pool_streamoff (pool);
+
+  if (!V4L2_TYPE_IS_OUTPUT (pool->obj->type))
+    ret = gst_v4l2_buffer_pool_streamon (pool);
+
+  return ret;
+}
diff --git a/sys/v4l2/gstv4l2bufferpool.h b/sys/v4l2/gstv4l2bufferpool.h
new file mode 100644
index 0000000..0fffc71
--- /dev/null
+++ b/sys/v4l2/gstv4l2bufferpool.h
@@ -0,0 +1,114 @@
+/* GStreamer
+ *
+ * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *               2006 Edgard Lima <edgard.lima@gmail.com>
+ *               2009 Texas Instruments, Inc - http://www.ti.com/
+ *
+ * gstv4l2bufferpool.h V4L2 buffer pool class
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_V4L2_BUFFER_POOL_H__
+#define __GST_V4L2_BUFFER_POOL_H__
+
+#include <gst/gst.h>
+
+typedef struct _GstV4l2BufferPool GstV4l2BufferPool;
+typedef struct _GstV4l2BufferPoolClass GstV4l2BufferPoolClass;
+typedef struct _GstV4l2Meta GstV4l2Meta;
+
+#include "gstv4l2object.h"
+#include "gstv4l2allocator.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_V4L2_BUFFER_POOL      (gst_v4l2_buffer_pool_get_type())
+#define GST_IS_V4L2_BUFFER_POOL(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_BUFFER_POOL))
+#define GST_V4L2_BUFFER_POOL(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_BUFFER_POOL, GstV4l2BufferPool))
+#define GST_V4L2_BUFFER_POOL_CAST(obj) ((GstV4l2BufferPool*)(obj))
+
+/* This flow return is used to indicated that the last buffer of a
+ * drain or a resoltuion change has been found. This should normally
+ * only occure for mem-2-mem devices. */
+#define GST_V4L2_FLOW_LAST_BUFFER GST_FLOW_CUSTOM_SUCCESS
+
+/* This flow return is used to indicated that the returned buffer was marked
+ * with the error flag and had no payload. This error should be recovered by
+ * simply waiting for next buffer. */
+#define GST_V4L2_FLOW_CORRUPTED_BUFFER GST_FLOW_CUSTOM_SUCCESS_1
+
+struct _GstV4l2BufferPool
+{
+  GstBufferPool parent;
+
+  GstV4l2Object *obj;        /* the v4l2 object */
+  gint video_fd;             /* a dup(2) of the v4l2object's video_fd */
+  GstPoll *poll;             /* a poll for video_fd */
+  GstPollFD pollfd;
+  gboolean can_poll_device;
+
+  gboolean empty;
+  GCond empty_cond;
+
+  GstV4l2Allocator *vallocator;
+  GstAllocator *allocator;
+  GstAllocationParams params;
+  GstBufferPool *other_pool;
+  guint size;
+  GstVideoInfo caps_info;   /* Default video information */
+
+  gboolean add_videometa;    /* set if video meta should be added */
+  gboolean enable_copy_threshold; /* If copy_threshold should be set */
+
+  guint min_latency;         /* number of buffers we will hold */
+  guint max_latency;         /* number of buffers we can hold */
+  guint num_queued;          /* number of buffers queued in the driver */
+  guint copy_threshold;      /* when our pool runs lower, start handing out copies */
+
+  gboolean streaming;
+  gboolean flushing;
+
+  GstBuffer *buffers[VIDEO_MAX_FRAME];
+
+  /* signal handlers */
+  gulong group_released_handler;
+
+  /* Control to warn only once on buggy feild driver bug */
+  gboolean has_warned_on_buggy_field;
+};
+
+struct _GstV4l2BufferPoolClass
+{
+  GstBufferPoolClass parent_class;
+};
+
+GType gst_v4l2_buffer_pool_get_type (void);
+
+GstBufferPool *     gst_v4l2_buffer_pool_new     (GstV4l2Object *obj, GstCaps *caps);
+
+GstFlowReturn       gst_v4l2_buffer_pool_process (GstV4l2BufferPool * bpool, GstBuffer ** buf);
+
+void                gst_v4l2_buffer_pool_set_other_pool (GstV4l2BufferPool * pool,
+                                                         GstBufferPool * other_pool);
+void                gst_v4l2_buffer_pool_copy_at_threshold (GstV4l2BufferPool * pool,
+                                                            gboolean copy);
+
+gboolean            gst_v4l2_buffer_pool_flush   (GstBufferPool *pool);
+
+G_END_DECLS
+
+#endif /*__GST_V4L2_BUFFER_POOL_H__ */
diff --git a/sys/v4l2/gstv4l2colorbalance.c b/sys/v4l2/gstv4l2colorbalance.c
new file mode 100644
index 0000000..f4c6ba9
--- /dev/null
+++ b/sys/v4l2/gstv4l2colorbalance.c
@@ -0,0 +1,100 @@
+/* GStreamer
+ *
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *               2006 Edgard Lima <edgard.lima@gmail.com>
+ *
+ * gstv4l2colorbalance.c: color balance interface implementation for V4L2
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include "gstv4l2colorbalance.h"
+#include "gstv4l2object.h"
+
+#define gst_v4l2_color_balance_channel_parent_class parent_class
+G_DEFINE_TYPE (GstV4l2ColorBalanceChannel,
+    gst_v4l2_color_balance_channel, GST_TYPE_COLOR_BALANCE_CHANNEL);
+
+static void
+gst_v4l2_color_balance_channel_class_init (GstV4l2ColorBalanceChannelClass *
+    klass)
+{
+}
+
+static void
+gst_v4l2_color_balance_channel_init (GstV4l2ColorBalanceChannel * channel)
+{
+  channel->id = (guint32) - 1;
+}
+
+static G_GNUC_UNUSED gboolean
+gst_v4l2_color_balance_contains_channel (GstV4l2Object * v4l2object,
+    GstV4l2ColorBalanceChannel * v4l2channel)
+{
+  const GList *item;
+
+  for (item = v4l2object->colors; item != NULL; item = item->next)
+    if (item->data == v4l2channel)
+      return TRUE;
+
+  return FALSE;
+}
+
+const GList *
+gst_v4l2_color_balance_list_channels (GstV4l2Object * v4l2object)
+{
+  return v4l2object->colors;
+}
+
+void
+gst_v4l2_color_balance_set_value (GstV4l2Object * v4l2object,
+    GstColorBalanceChannel * channel, gint value)
+{
+
+  GstV4l2ColorBalanceChannel *v4l2channel =
+      GST_V4L2_COLOR_BALANCE_CHANNEL (channel);
+
+  /* assert that we're opened and that we're using a known item */
+  g_return_if_fail (GST_V4L2_IS_OPEN (v4l2object));
+  g_return_if_fail (gst_v4l2_color_balance_contains_channel (v4l2object,
+          v4l2channel));
+
+  gst_v4l2_set_attribute (v4l2object, v4l2channel->id, value);
+}
+
+gint
+gst_v4l2_color_balance_get_value (GstV4l2Object * v4l2object,
+    GstColorBalanceChannel * channel)
+{
+  GstV4l2ColorBalanceChannel *v4l2channel =
+      GST_V4L2_COLOR_BALANCE_CHANNEL (channel);
+  gint value;
+
+  /* assert that we're opened and that we're using a known item */
+  g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), 0);
+  g_return_val_if_fail (gst_v4l2_color_balance_contains_channel (v4l2object,
+          v4l2channel), 0);
+
+  if (!gst_v4l2_get_attribute (v4l2object, v4l2channel->id, &value))
+    return 0;
+
+  return value;
+}
diff --git a/sys/v4l2/gstv4l2colorbalance.h b/sys/v4l2/gstv4l2colorbalance.h
new file mode 100644
index 0000000..90ba7ab
--- /dev/null
+++ b/sys/v4l2/gstv4l2colorbalance.h
@@ -0,0 +1,111 @@
+/* GStreamer
+ *
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *               2006 Edgard Lima <edgard.lima@gmail.com>
+ *
+ * gstv4l2colorbalance.h: color balance interface implementation for V4L2
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_V4L2_COLOR_BALANCE_H__
+#define __GST_V4L2_COLOR_BALANCE_H__
+
+#include <gst/gst.h>
+#include <gst/video/colorbalance.h>
+
+#include "gstv4l2object.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL \
+  (gst_v4l2_color_balance_channel_get_type ())
+#define GST_V4L2_COLOR_BALANCE_CHANNEL(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, \
+                               GstV4l2ColorBalanceChannel))
+#define GST_V4L2_COLOR_BALANCE_CHANNEL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, \
+                            GstV4l2ColorBalanceChannelClass))
+#define GST_IS_V4L2_COLOR_BALANCE_CHANNEL(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL))
+#define GST_IS_V4L2_COLOR_BALANCE_CHANNEL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL))
+
+typedef struct _GstV4l2ColorBalanceChannel {
+  GstColorBalanceChannel parent;
+
+  guint32 id;
+} GstV4l2ColorBalanceChannel;
+
+typedef struct _GstV4l2ColorBalanceChannelClass {
+  GstColorBalanceChannelClass parent;
+} GstV4l2ColorBalanceChannelClass;
+
+GType gst_v4l2_color_balance_channel_get_type   (void);
+
+const GList *   gst_v4l2_color_balance_list_channels    (GstV4l2Object * v4l2object);
+
+void            gst_v4l2_color_balance_set_value        (GstV4l2Object * v4l2object,
+                                                         GstColorBalanceChannel * channel,
+                                                         gint value);
+
+gint            gst_v4l2_color_balance_get_value        (GstV4l2Object * v4l2object,
+                                                         GstColorBalanceChannel * channel);
+
+#define GST_IMPLEMENT_V4L2_COLOR_BALANCE_METHODS(Type, interface_as_function)         \
+                                                                                      \
+static const GList *                                                                  \
+interface_as_function ## _color_balance_list_channels (GstColorBalance * balance)     \
+{                                                                                     \
+  Type *this = (Type*) balance;                                                       \
+  return gst_v4l2_color_balance_list_channels(this->v4l2object);                      \
+}                                                                                     \
+                                                                                      \
+static void                                                                           \
+interface_as_function ## _color_balance_set_value (GstColorBalance * balance,         \
+                                                   GstColorBalanceChannel * channel,  \
+                                                   gint value)                        \
+{                                                                                     \
+  Type *this = (Type*) balance;                                                       \
+  gst_v4l2_color_balance_set_value(this->v4l2object, channel, value);          \
+}                                                                                     \
+                                                                                      \
+static gint                                                                           \
+interface_as_function ## _color_balance_get_value (GstColorBalance * balance,         \
+                                                   GstColorBalanceChannel * channel)  \
+{                                                                                     \
+  Type *this = (Type*) balance;                                                       \
+  return gst_v4l2_color_balance_get_value(this->v4l2object, channel);                 \
+}                                                                                     \
+                                                                                      \
+static GstColorBalanceType                                                            \
+interface_as_function ## _color_balance_get_balance_type (GstColorBalance * balance)  \
+{                                                                                     \
+  return GST_COLOR_BALANCE_HARDWARE;                                                  \
+}                                                                                     \
+                                                                                      \
+static void                                                                           \
+interface_as_function ## _color_balance_interface_init (GstColorBalanceInterface * iface) \
+{                                                                                     \
+  /* default virtual functions */                                                     \
+  iface->list_channels = interface_as_function ## _color_balance_list_channels;       \
+  iface->set_value = interface_as_function ## _color_balance_set_value;               \
+  iface->get_value = interface_as_function ## _color_balance_get_value;               \
+  iface->get_balance_type = interface_as_function ## _color_balance_get_balance_type; \
+}                                                                                     \
+
+G_END_DECLS
+#endif /* __GST_V4L2_COLOR_BALANCE_H__ */
diff --git a/sys/v4l2/gstv4l2deviceprovider.c b/sys/v4l2/gstv4l2deviceprovider.c
new file mode 100644
index 0000000..8f6e9ea
--- /dev/null
+++ b/sys/v4l2/gstv4l2deviceprovider.c
@@ -0,0 +1,601 @@
+/* GStreamer
+ * Copyright (C) 2012 Olivier Crete <olivier.crete@collabora.com>
+ *
+ * gstv4l2deviceprovider.c: V4l2 device probing and monitoring
+ *
+ * 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 "gstv4l2deviceprovider.h"
+
+#include <string.h>
+#include <sys/stat.h>
+
+#include <gst/gst.h>
+
+#include "gstv4l2object.h"
+#include "v4l2-utils.h"
+
+#ifdef HAVE_GUDEV
+#include <gudev/gudev.h>
+#endif
+
+static GstV4l2Device *gst_v4l2_device_new (const gchar * device_path,
+    const gchar * device_name, GstCaps * caps, GstV4l2DeviceType type,
+    GstStructure * props);
+
+
+G_DEFINE_TYPE (GstV4l2DeviceProvider, gst_v4l2_device_provider,
+    GST_TYPE_DEVICE_PROVIDER);
+
+static void gst_v4l2_device_provider_finalize (GObject * object);
+static GList *gst_v4l2_device_provider_probe (GstDeviceProvider * provider);
+
+#ifdef HAVE_GUDEV
+static gboolean gst_v4l2_device_provider_start (GstDeviceProvider * provider);
+static void gst_v4l2_device_provider_stop (GstDeviceProvider * provider);
+#endif
+
+
+static void
+gst_v4l2_device_provider_class_init (GstV4l2DeviceProviderClass * klass)
+{
+  GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  dm_class->probe = gst_v4l2_device_provider_probe;
+
+#ifdef HAVE_GUDEV
+  dm_class->start = gst_v4l2_device_provider_start;
+  dm_class->stop = gst_v4l2_device_provider_stop;
+#endif
+
+  gobject_class->finalize = gst_v4l2_device_provider_finalize;
+
+  gst_device_provider_class_set_static_metadata (dm_class,
+      "Video (video4linux2) Device Provider", "Source/Sink/Video",
+      "List and monitor video4linux2 source and sink devices",
+      "Olivier Crete <olivier.crete@collabora.com>");
+}
+
+static void
+gst_v4l2_device_provider_init (GstV4l2DeviceProvider * provider)
+{
+#ifdef HAVE_GUDEV
+  g_cond_init (&provider->started_cond);
+#endif
+}
+
+static void
+gst_v4l2_device_provider_finalize (GObject * object)
+{
+#ifdef HAVE_GUDEV
+  GstV4l2DeviceProvider *provider = GST_V4L2_DEVICE_PROVIDER (object);
+
+  g_cond_clear (&provider->started_cond);
+#endif
+
+  G_OBJECT_CLASS (gst_v4l2_device_provider_parent_class)->finalize (object);
+}
+
+static GstV4l2Device *
+gst_v4l2_device_provider_probe_device (GstV4l2DeviceProvider * provider,
+    const gchar * device_path, const gchar * device_name, GstStructure * props)
+{
+  GstV4l2Object *v4l2obj = NULL;
+  GstCaps *caps;
+  GstV4l2Device *device = NULL;
+  struct stat st;
+  GstV4l2DeviceType type = GST_V4L2_DEVICE_TYPE_INVALID;
+
+  g_return_val_if_fail (props != NULL, NULL);
+
+  if (stat (device_path, &st) == -1)
+    goto destroy;
+
+  if (!S_ISCHR (st.st_mode))
+    goto destroy;
+
+  v4l2obj = gst_v4l2_object_new (NULL, GST_OBJECT (provider),
+      V4L2_BUF_TYPE_VIDEO_CAPTURE, device_path, NULL, NULL, NULL);
+
+  if (!gst_v4l2_open (v4l2obj))
+    goto destroy;
+
+  gst_structure_set (props, "device.api", G_TYPE_STRING, "v4l2", NULL);
+  gst_structure_set (props, "device.path", G_TYPE_STRING, device_path, NULL);
+
+  gst_structure_set (props, "v4l2.device.driver", G_TYPE_STRING,
+      v4l2obj->vcap.driver, NULL);
+  gst_structure_set (props, "v4l2.device.card", G_TYPE_STRING,
+      v4l2obj->vcap.card, NULL);
+  gst_structure_set (props, "v4l2.device.bus_info", G_TYPE_STRING,
+      v4l2obj->vcap.bus_info, NULL);
+  gst_structure_set (props, "v4l2.device.version", G_TYPE_UINT,
+      v4l2obj->vcap.version, NULL);
+  gst_structure_set (props, "v4l2.device.capabilities", G_TYPE_UINT,
+      v4l2obj->vcap.capabilities, NULL);
+  gst_structure_set (props, "v4l2.device.device_caps", G_TYPE_UINT,
+      v4l2obj->vcap.device_caps, NULL);
+
+  if (v4l2obj->device_caps &
+      (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) {
+    /* We ignore touch sensing devices; those are't really video */
+    if (v4l2obj->device_caps & V4L2_CAP_TOUCH)
+      goto close;
+
+    type = GST_V4L2_DEVICE_TYPE_SOURCE;
+    v4l2obj->skip_try_fmt_probes = TRUE;
+  }
+
+  if (v4l2obj->device_caps &
+      (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE)) {
+    /* We ignore M2M devices that are both capture and output for now
+     * The provider is not for them */
+    if (type != GST_V4L2_DEVICE_TYPE_INVALID)
+      goto close;
+
+    type = GST_V4L2_DEVICE_TYPE_SINK;
+
+    /* We have opened as a capture as we didn't know, now that know,
+     * let's fixed it */
+    if (v4l2obj->device_caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE)
+      v4l2obj->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+    else
+      v4l2obj->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+  }
+
+  if (type == GST_V4L2_DEVICE_TYPE_INVALID)
+    goto close;
+
+  caps = gst_v4l2_object_get_caps (v4l2obj, NULL);
+
+  if (caps == NULL)
+    goto close;
+  if (gst_caps_is_empty (caps)) {
+    gst_caps_unref (caps);
+    goto close;
+  }
+
+  device = gst_v4l2_device_new (device_path,
+      device_name ? device_name : (gchar *) v4l2obj->vcap.card, caps, type,
+      props);
+  gst_caps_unref (caps);
+
+close:
+
+  gst_v4l2_close (v4l2obj);
+
+destroy:
+
+  if (v4l2obj)
+    gst_v4l2_object_destroy (v4l2obj);
+
+  if (props)
+    gst_structure_free (props);
+
+  return device;
+}
+
+
+static GList *
+gst_v4l2_device_provider_probe (GstDeviceProvider * provider)
+{
+  GstV4l2DeviceProvider *self = GST_V4L2_DEVICE_PROVIDER (provider);
+  GstV4l2Iterator *it;
+  GList *devices = NULL;
+
+  it = gst_v4l2_iterator_new ();
+
+  while (gst_v4l2_iterator_next (it)) {
+    GstStructure *props;
+    GstV4l2Device *device;
+
+    props = gst_structure_new ("v4l2-proplist", "device.path", G_TYPE_STRING,
+        it->device_path, "udev-probed", G_TYPE_BOOLEAN, FALSE, NULL);
+    device = gst_v4l2_device_provider_probe_device (self, it->device_path, NULL,
+        props);
+
+    if (device) {
+      gst_object_ref_sink (device);
+      devices = g_list_prepend (devices, device);
+    }
+  }
+
+  gst_v4l2_iterator_free (it);
+
+  return devices;
+}
+
+#ifdef HAVE_GUDEV
+
+static GstDevice *
+gst_v4l2_device_provider_device_from_udev (GstV4l2DeviceProvider * provider,
+    GUdevDevice * udev_device)
+{
+  GstV4l2Device *gstdev;
+  const gchar *device_path = g_udev_device_get_device_file (udev_device);
+  const gchar *device_name, *str;
+  GstStructure *props;
+
+  props = gst_structure_new ("v4l2deviceprovider", "udev-probed",
+      G_TYPE_BOOLEAN, TRUE, NULL);
+
+  str = g_udev_device_get_property (udev_device, "ID_PATH");
+  if (!(str && *str)) {
+    str = g_udev_device_get_sysfs_path (udev_device);
+  }
+  if (str && *str)
+    gst_structure_set (props, "device.bus_path", G_TYPE_STRING, str, NULL);
+
+  if ((str = g_udev_device_get_sysfs_path (udev_device)) && *str)
+    gst_structure_set (props, "sysfs.path", G_TYPE_STRING, str, NULL);
+
+  if ((str = g_udev_device_get_property (udev_device, "ID_ID")) && *str)
+    gst_structure_set (props, "udev.id", G_TYPE_STRING, str, NULL);
+
+  if ((str = g_udev_device_get_property (udev_device, "ID_BUS")) && *str)
+    gst_structure_set (props, "device.bus", G_TYPE_STRING, str, NULL);
+
+  if ((str = g_udev_device_get_property (udev_device, "SUBSYSTEM")) && *str)
+    gst_structure_set (props, "device.subsystem", G_TYPE_STRING, str, NULL);
+
+  if ((str = g_udev_device_get_property (udev_device, "ID_VENDOR_ID")) && *str)
+    gst_structure_set (props, "device.vendor.id", G_TYPE_STRING, str, NULL);
+
+  str = g_udev_device_get_property (udev_device, "ID_VENDOR_FROM_DATABASE");
+  if (!(str && *str)) {
+    str = g_udev_device_get_property (udev_device, "ID_VENDOR_ENC");
+    if (!(str && *str)) {
+      str = g_udev_device_get_property (udev_device, "ID_VENDOR");
+    }
+  }
+  if (str && *str)
+    gst_structure_set (props, "device.vendor.name", G_TYPE_STRING, str, NULL);
+
+  if ((str = g_udev_device_get_property (udev_device, "ID_MODEL_ID")) && *str)
+    gst_structure_set (props, "device.product.id", G_TYPE_STRING, str, NULL);
+
+  device_name = g_udev_device_get_property (udev_device, "ID_V4L_PRODUCT");
+  if (!(device_name && *device_name)) {
+    device_name =
+        g_udev_device_get_property (udev_device, "ID_MODEL_FROM_DATABASE");
+    if (!(device_name && *device_name)) {
+      device_name = g_udev_device_get_property (udev_device, "ID_MODEL_ENC");
+      if (!(device_name && *device_name)) {
+        device_name = g_udev_device_get_property (udev_device, "ID_MODEL");
+      }
+    }
+  }
+  if (device_name && *device_name)
+    gst_structure_set (props, "device.product.name", G_TYPE_STRING, device_name,
+        NULL);
+
+  if ((str = g_udev_device_get_property (udev_device, "ID_SERIAL")) && *str)
+    gst_structure_set (props, "device.serial", G_TYPE_STRING, str, NULL);
+
+  if ((str = g_udev_device_get_property (udev_device, "ID_V4L_CAPABILITIES"))
+      && *str)
+    gst_structure_set (props, "device.capabilities", G_TYPE_STRING, str, NULL);
+
+  gstdev = gst_v4l2_device_provider_probe_device (provider, device_path,
+      device_name, props);
+
+  if (gstdev)
+    gstdev->syspath = g_strdup (g_udev_device_get_sysfs_path (udev_device));
+
+  return GST_DEVICE (gstdev);
+}
+
+static void
+uevent_cb (GUdevClient * client, const gchar * action, GUdevDevice * device,
+    GstV4l2DeviceProvider * self)
+{
+  GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self);
+
+  /* Not V4L2, ignoring */
+  if (g_udev_device_get_property_as_int (device, "ID_V4L_VERSION") != 2)
+    return;
+
+  if (!strcmp (action, "add")) {
+    GstDevice *gstdev = NULL;
+
+    gstdev = gst_v4l2_device_provider_device_from_udev (self, device);
+
+    if (gstdev)
+      gst_device_provider_device_add (provider, gstdev);
+  } else if (!strcmp (action, "remove")) {
+    GstV4l2Device *gstdev = NULL;
+    GList *item;
+
+    GST_OBJECT_LOCK (self);
+    for (item = provider->devices; item; item = item->next) {
+      gstdev = item->data;
+
+      if (!strcmp (gstdev->syspath, g_udev_device_get_sysfs_path (device))) {
+        gst_object_ref (gstdev);
+        break;
+      }
+
+      gstdev = NULL;
+    }
+    GST_OBJECT_UNLOCK (provider);
+
+    if (gstdev) {
+      gst_device_provider_device_remove (provider, GST_DEVICE (gstdev));
+      g_object_unref (gstdev);
+    }
+  } else {
+    GST_WARNING ("Unhandled action %s", action);
+  }
+}
+
+static gpointer
+provider_thread (gpointer data)
+{
+  GstV4l2DeviceProvider *provider = data;
+  GMainContext *context = NULL;
+  GMainLoop *loop = NULL;
+  GUdevClient *client;
+  GList *devices;
+  static const gchar *subsystems[] = { "video4linux", NULL };
+
+  GST_OBJECT_LOCK (provider);
+  if (provider->context)
+    context = g_main_context_ref (provider->context);
+  if (provider->loop)
+    loop = g_main_loop_ref (provider->loop);
+
+  if (context == NULL || loop == NULL) {
+    provider->started = TRUE;
+    g_cond_broadcast (&provider->started_cond);
+    GST_OBJECT_UNLOCK (provider);
+    return NULL;
+  }
+  GST_OBJECT_UNLOCK (provider);
+
+  g_main_context_push_thread_default (context);
+
+  client = g_udev_client_new (subsystems);
+
+  g_signal_connect (client, "uevent", G_CALLBACK (uevent_cb), provider);
+
+  devices = g_udev_client_query_by_subsystem (client, "video4linux");
+
+  while (devices) {
+    GUdevDevice *udev_device = devices->data;
+    GstDevice *gstdev;
+
+    devices = g_list_remove (devices, udev_device);
+
+    if (g_udev_device_get_property_as_int (udev_device, "ID_V4L_VERSION") == 2) {
+      gstdev =
+          gst_v4l2_device_provider_device_from_udev (provider, udev_device);
+      if (gstdev)
+        gst_device_provider_device_add (GST_DEVICE_PROVIDER (provider), gstdev);
+    }
+
+    g_object_unref (udev_device);
+  }
+
+  GST_OBJECT_LOCK (provider);
+  provider->started = TRUE;
+  g_cond_broadcast (&provider->started_cond);
+  GST_OBJECT_UNLOCK (provider);
+
+  g_main_loop_run (loop);
+  g_main_loop_unref (loop);
+
+  g_object_unref (client);
+  g_main_context_unref (context);
+
+  gst_object_unref (provider);
+
+  return NULL;
+}
+
+static gboolean
+gst_v4l2_device_provider_start (GstDeviceProvider * provider)
+{
+  GstV4l2DeviceProvider *self = GST_V4L2_DEVICE_PROVIDER (provider);
+
+  GST_OBJECT_LOCK (self);
+  g_assert (self->context == NULL);
+
+  self->context = g_main_context_new ();
+  self->loop = g_main_loop_new (self->context, FALSE);
+
+  self->thread = g_thread_new ("v4l2-device-provider", provider_thread,
+      g_object_ref (self));
+
+  while (self->started == FALSE)
+    g_cond_wait (&self->started_cond, GST_OBJECT_GET_LOCK (self));
+
+  GST_OBJECT_UNLOCK (self);
+
+  return TRUE;
+}
+
+static void
+gst_v4l2_device_provider_stop (GstDeviceProvider * provider)
+{
+  GstV4l2DeviceProvider *self = GST_V4L2_DEVICE_PROVIDER (provider);
+  GMainContext *context;
+  GMainLoop *loop;
+  GSource *idle_stop_source;
+
+  GST_OBJECT_LOCK (self);
+  context = self->context;
+  loop = self->loop;
+  self->context = NULL;
+  self->loop = NULL;
+  GST_OBJECT_UNLOCK (self);
+
+  if (!context || !loop)
+    return;
+
+  idle_stop_source = g_idle_source_new ();
+  g_source_set_callback (idle_stop_source, (GSourceFunc) g_main_loop_quit, loop,
+      (GDestroyNotify) g_main_loop_unref);
+  g_source_attach (idle_stop_source, context);
+  g_source_unref (idle_stop_source);
+  g_main_context_unref (context);
+
+  g_thread_join (self->thread);
+  self->thread = NULL;
+  self->started = FALSE;
+}
+
+#endif
+
+enum
+{
+  PROP_DEVICE_PATH = 1,
+};
+
+G_DEFINE_TYPE (GstV4l2Device, gst_v4l2_device, GST_TYPE_DEVICE);
+
+static void gst_v4l2_device_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_v4l2_device_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_v4l2_device_finalize (GObject * object);
+static GstElement *gst_v4l2_device_create_element (GstDevice * device,
+    const gchar * name);
+
+static void
+gst_v4l2_device_class_init (GstV4l2DeviceClass * klass)
+{
+  GstDeviceClass *dev_class = GST_DEVICE_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  dev_class->create_element = gst_v4l2_device_create_element;
+
+  object_class->get_property = gst_v4l2_device_get_property;
+  object_class->set_property = gst_v4l2_device_set_property;
+  object_class->finalize = gst_v4l2_device_finalize;
+
+  g_object_class_install_property (object_class, PROP_DEVICE_PATH,
+      g_param_spec_string ("device-path", "Device Path",
+          "The Path of the device node", "",
+          G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gst_v4l2_device_init (GstV4l2Device * device)
+{
+}
+
+static void
+gst_v4l2_device_finalize (GObject * object)
+{
+  GstV4l2Device *device = GST_V4L2_DEVICE (object);
+
+  g_free (device->device_path);
+  g_free (device->syspath);
+
+  G_OBJECT_CLASS (gst_v4l2_device_parent_class)->finalize (object);
+}
+
+static GstElement *
+gst_v4l2_device_create_element (GstDevice * device, const gchar * name)
+{
+  GstV4l2Device *v4l2_dev = GST_V4L2_DEVICE (device);
+  GstElement *elem;
+
+  elem = gst_element_factory_make (v4l2_dev->element, name);
+  g_object_set (elem, "device", v4l2_dev->device_path, NULL);
+
+  return elem;
+}
+
+static GstV4l2Device *
+gst_v4l2_device_new (const gchar * device_path, const gchar * device_name,
+    GstCaps * caps, GstV4l2DeviceType type, GstStructure * props)
+{
+  GstV4l2Device *gstdev;
+  const gchar *element = NULL;
+  const gchar *klass = NULL;
+
+  g_return_val_if_fail (device_path, NULL);
+  g_return_val_if_fail (device_name, NULL);
+  g_return_val_if_fail (caps, NULL);
+
+  switch (type) {
+    case GST_V4L2_DEVICE_TYPE_SOURCE:
+      element = "v4l2src";
+      klass = "Video/Source";
+      break;
+    case GST_V4L2_DEVICE_TYPE_SINK:
+      element = "v4l2sink";
+      klass = "Video/Sink";
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+
+  gstdev = g_object_new (GST_TYPE_V4L2_DEVICE, "device-path", device_path,
+      "display-name", device_name, "caps", caps, "device-class", klass,
+      "properties", props, NULL);
+
+  gstdev->element = element;
+
+
+  return gstdev;
+}
+
+
+static void
+gst_v4l2_device_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstV4l2Device *device;
+
+  device = GST_V4L2_DEVICE_CAST (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE_PATH:
+      g_value_set_string (value, device->device_path);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+
+static void
+gst_v4l2_device_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstV4l2Device *device;
+
+  device = GST_V4L2_DEVICE_CAST (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE_PATH:
+      device->device_path = g_value_dup_string (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
diff --git a/sys/v4l2/gstv4l2deviceprovider.h b/sys/v4l2/gstv4l2deviceprovider.h
new file mode 100644
index 0000000..5e05b35
--- /dev/null
+++ b/sys/v4l2/gstv4l2deviceprovider.h
@@ -0,0 +1,101 @@
+/* GStreamer
+ * Copyright (C) 2012 Olivier Crete <olivier.crete@collabora.com>
+ *
+ * gstv4l2deviceprovider.h: V4l2 device probing and monitoring
+ *
+ * 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_V4L2_DEVICE_PROVIDER_H__
+#define __GST_V4L2_DEVICE_PROVIDER_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#ifdef HAVE_GUDEV
+#include <gudev/gudev.h>
+#endif
+
+G_BEGIN_DECLS
+
+typedef struct _GstV4l2DeviceProvider GstV4l2DeviceProvider;
+typedef struct _GstV4l2DeviceProviderClass GstV4l2DeviceProviderClass;
+
+#define GST_TYPE_V4L2_DEVICE_PROVIDER                 (gst_v4l2_device_provider_get_type())
+#define GST_IS_V4L2_DEVICE_PROVIDER(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_DEVICE_PROVIDER))
+#define GST_IS_V4L2_DEVICE_PROVIDER_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_DEVICE_PROVIDER))
+#define GST_V4L2_DEVICE_PROVIDER_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_V4L2_DEVICE_PROVIDER, GstV4l2DeviceProviderClass))
+#define GST_V4L2_DEVICE_PROVIDER(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_DEVICE_PROVIDER, GstV4l2DeviceProvider))
+#define GST_V4L2_DEVICE_PROVIDER_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE_PROVIDER, GstV4l2DeviceProviderClass))
+#define GST_V4L2_DEVICE_PROVIDER_CAST(obj)            ((GstV4l2DeviceProvider *)(obj))
+
+struct _GstV4l2DeviceProvider {
+  GstDeviceProvider         parent;
+
+#ifdef HAVE_GUDEV
+  GMainContext *context;
+  GMainLoop *loop;
+  GThread *thread;
+  gboolean started;
+  GCond started_cond;
+#endif
+};
+
+typedef enum {
+  GST_V4L2_DEVICE_TYPE_INVALID = 0,
+  GST_V4L2_DEVICE_TYPE_SOURCE,
+  GST_V4L2_DEVICE_TYPE_SINK
+} GstV4l2DeviceType;
+
+struct _GstV4l2DeviceProviderClass {
+  GstDeviceProviderClass    parent_class;
+};
+
+GType        gst_v4l2_device_provider_get_type (void);
+
+
+typedef struct _GstV4l2Device GstV4l2Device;
+typedef struct _GstV4l2DeviceClass GstV4l2DeviceClass;
+
+#define GST_TYPE_V4L2_DEVICE                 (gst_v4l2_device_get_type())
+#define GST_IS_V4L2_DEVICE(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_DEVICE))
+#define GST_IS_V4L2_DEVICE_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_DEVICE))
+#define GST_V4L2_DEVICE_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_V4L2_DEVICE, GstV4l2DeviceClass))
+#define GST_V4L2_DEVICE(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_DEVICE, GstV4l2Device))
+#define GST_V4L2_DEVICE_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE, GstV4l2DeviceClass))
+#define GST_V4L2_DEVICE_CAST(obj)            ((GstV4l2Device *)(obj))
+
+struct _GstV4l2Device {
+  GstDevice         parent;
+
+  gchar            *device_path;
+  gchar            *syspath;
+  const gchar      *element;
+};
+
+struct _GstV4l2DeviceClass {
+  GstDeviceClass    parent_class;
+};
+
+GType        gst_v4l2_device_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_V4L2_DEVICE_PROVIDER_H__ */
diff --git a/sys/v4l2/gstv4l2h263enc.c b/sys/v4l2/gstv4l2h263enc.c
new file mode 100644
index 0000000..3b63af5
--- /dev/null
+++ b/sys/v4l2/gstv4l2h263enc.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2017 Collabora Inc.
+ *    Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gstv4l2object.h"
+#include "gstv4l2h263enc.h"
+
+#include <string.h>
+#include <gst/gst-i18n-plugin.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_v4l2_h263_enc_debug);
+#define GST_CAT_DEFAULT gst_v4l2_h263_enc_debug
+
+
+static GstStaticCaps src_template_caps =
+GST_STATIC_CAPS ("video/x-h263, variant=(string) itu");
+
+enum
+{
+  PROP_0,
+  V4L2_STD_OBJECT_PROPS,
+/* TODO add H263 controls */
+};
+
+#define gst_v4l2_h263_enc_parent_class parent_class
+G_DEFINE_TYPE (GstV4l2H263Enc, gst_v4l2_h263_enc, GST_TYPE_V4L2_VIDEO_ENC);
+
+static void
+gst_v4l2_h263_enc_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  /* TODO */
+}
+
+static void
+gst_v4l2_h263_enc_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  /* TODO */
+}
+
+static void
+gst_v4l2_h263_enc_init (GstV4l2H263Enc * self)
+{
+
+}
+
+static void
+gst_v4l2_h263_enc_class_init (GstV4l2H263EncClass * klass)
+{
+  GstElementClass *element_class;
+  GObjectClass *gobject_class;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  element_class = (GstElementClass *) klass;
+  gobject_class = (GObjectClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (gst_v4l2_h263_enc_debug, "v4l2h263enc", 0,
+      "V4L2 H.263 Encoder");
+
+  gst_element_class_set_static_metadata (element_class,
+      "V4L2 H.263 Encoder",
+      "Codec/Encoder/Video",
+      "Encode H.263 video streams via V4L2 API",
+      "Nicolas Dufresne <nicolas.dufresne@collabora.com>");
+
+  gobject_class->set_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_h263_enc_set_property);
+  gobject_class->get_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_h263_enc_get_property);
+}
+
+/* Probing functions */
+gboolean
+gst_v4l2_is_h263_enc (GstCaps * sink_caps, GstCaps * src_caps)
+{
+  return gst_v4l2_is_video_enc (sink_caps, src_caps,
+      gst_static_caps_get (&src_template_caps));
+}
+
+void
+gst_v4l2_h263_enc_register (GstPlugin * plugin, const gchar * basename,
+    const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps)
+{
+  gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_H263_ENC,
+      "h263", basename, device_path, sink_caps,
+      gst_static_caps_get (&src_template_caps), src_caps);
+}
diff --git a/sys/v4l2/gstv4l2h263enc.h b/sys/v4l2/gstv4l2h263enc.h
new file mode 100644
index 0000000..fa5a356
--- /dev/null
+++ b/sys/v4l2/gstv4l2h263enc.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 Collabora Inc.
+ *    Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __GST_V4L2_H263_ENC_H__
+#define __GST_V4L2_H263_ENC_H__
+
+#include <gst/gst.h>
+#include "gstv4l2videoenc.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_V4L2_H263_ENC \
+  (gst_v4l2_h263_enc_get_type())
+#define GST_V4L2_H263_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_H263_ENC,GstV4l2H263Enc))
+#define GST_V4L2_H263_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_H263_ENC,GstV4l2H263EncClass))
+#define GST_IS_V4L2_H263_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_H263_ENC))
+#define GST_IS_V4L2_H263_ENC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_H263_ENC))
+typedef struct _GstV4l2H263Enc GstV4l2H263Enc;
+typedef struct _GstV4l2H263EncClass GstV4l2H263EncClass;
+
+struct _GstV4l2H263Enc
+{
+  GstV4l2VideoEnc parent;
+};
+
+struct _GstV4l2H263EncClass
+{
+  GstV4l2VideoEncClass parent_class;
+};
+
+GType gst_v4l2_h263_enc_get_type (void);
+
+gboolean gst_v4l2_is_h263_enc (GstCaps * sink_caps, GstCaps * src_caps);
+
+void gst_v4l2_h263_enc_register (GstPlugin * plugin, const gchar * basename,
+    const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps);
+
+G_END_DECLS
+#endif /* __GST_V4L2_H263_ENC_H__ */
diff --git a/sys/v4l2/gstv4l2h264enc.c b/sys/v4l2/gstv4l2h264enc.c
new file mode 100644
index 0000000..d1c6036
--- /dev/null
+++ b/sys/v4l2/gstv4l2h264enc.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2014 SUMOMO Computer Association
+ *     Author: ayaka <ayaka@soulik.info>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gstv4l2object.h"
+#include "gstv4l2h264enc.h"
+
+#include <string.h>
+#include <gst/gst-i18n-plugin.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_v4l2_h264_enc_debug);
+#define GST_CAT_DEFAULT gst_v4l2_h264_enc_debug
+
+
+static GstStaticCaps src_template_caps =
+GST_STATIC_CAPS ("video/x-h264, stream-format=(string) byte-stream, "
+    "alignment=(string) au");
+
+enum
+{
+  PROP_0,
+  V4L2_STD_OBJECT_PROPS,
+/* TODO add H264 controls
+ * PROP_I_FRAME_QP,
+ * PROP_P_FRAME_QP,
+ * PROP_B_FRAME_QP,
+ * PROP_MIN_QP,
+ * PROP_MAX_QP,
+ * PROP_8x8_TRANSFORM,
+ * PROP_CPB_SIZE,
+ * PROP_ENTROPY_MODE,
+ * PROP_I_PERIOD,
+ * PROP_LOOP_FILTER_ALPHA,
+ * PROP_LOOP_FILTER_BETA,
+ * PROP_LOOP_FILTER_MODE,
+ * PROP_VUI_EXT_SAR_HEIGHT,
+ * PROP_VUI_EXT_SAR_WIDTH,
+ * PROP_VUI_SAR_ENABLED,
+ * PROP_VUI_SAR_IDC,
+ * PROP_SEI_FRAME_PACKING,
+ * PROP_SEI_FP_CURRENT_FRAME_0,
+ * PROP_SEI_FP_ARRANGEMENT_TYP,
+ * ...
+ * */
+};
+
+#define gst_v4l2_h264_enc_parent_class parent_class
+G_DEFINE_TYPE (GstV4l2H264Enc, gst_v4l2_h264_enc, GST_TYPE_V4L2_VIDEO_ENC);
+
+static void
+gst_v4l2_h264_enc_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  /* TODO */
+}
+
+static void
+gst_v4l2_h264_enc_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  /* TODO */
+}
+
+static gint
+v4l2_profile_from_string (const gchar * profile)
+{
+  gint v4l2_profile = -1;
+
+  if (g_str_equal (profile, "baseline")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
+  } else if (g_str_equal (profile, "constrained-baseline")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE;
+  } else if (g_str_equal (profile, "main")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
+  } else if (g_str_equal (profile, "extended")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED;
+  } else if (g_str_equal (profile, "high")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
+  } else if (g_str_equal (profile, "high-10")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
+  } else if (g_str_equal (profile, "high-4:2:2")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422;
+  } else if (g_str_equal (profile, "high-4:4:4")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE;
+  } else if (g_str_equal (profile, "high-10-intra")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA;
+  } else if (g_str_equal (profile, "high-4:2:2-intra")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA;
+  } else if (g_str_equal (profile, "high-4:4:4-intra")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA;
+  } else if (g_str_equal (profile, "cavlc-4:4:4-intra")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA;
+  } else if (g_str_equal (profile, "scalable-baseline")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE;
+  } else if (g_str_equal (profile, "scalable-high")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH;
+  } else if (g_str_equal (profile, "scalable-high-intra")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA;
+  } else if (g_str_equal (profile, "stereo-high")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH;
+  } else if (g_str_equal (profile, "multiview-high")) {
+    v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH;
+  } else {
+    GST_WARNING ("Unsupported profile string '%s'", profile);
+  }
+
+  return v4l2_profile;
+}
+
+static const gchar *
+v4l2_profile_to_string (gint v4l2_profile)
+{
+  switch (v4l2_profile) {
+    case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+      return "baseline";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+      return "constrained-baseline";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+      return "main";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+      return "extended";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+      return "high";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
+      return "high-10";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
+      return "high-4:2:2";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
+      return "high-4:4:4";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA:
+      return "high-10-intra";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA:
+      return "high-4:2:2-intra";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA:
+      return "high-4:4:4-intra";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA:
+      return "cavlc-4:4:4-intra";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE:
+      return "scalable-baseline";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH:
+      return "scalable-high";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA:
+      return "scalable-high-intra";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH:
+      return "stereo-high";
+    case V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH:
+      return "multiview-high";
+    default:
+      GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile);
+      break;
+  }
+
+  return NULL;
+}
+
+static gint
+v4l2_level_from_string (const gchar * level)
+{
+  gint v4l2_level = -1;
+
+  if (g_str_equal (level, "1"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
+  else if (g_str_equal (level, "1b"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1B;
+  else if (g_str_equal (level, "1.1"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
+  else if (g_str_equal (level, "1.2"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_2;
+  else if (g_str_equal (level, "1.3"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_3;
+  else if (g_str_equal (level, "2"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_2_0;
+  else if (g_str_equal (level, "2.1"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
+  else if (g_str_equal (level, "2.2"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
+  else if (g_str_equal (level, "3"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_3_0;
+  else if (g_str_equal (level, "3.1"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
+  else if (g_str_equal (level, "3.2"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
+  else if (g_str_equal (level, "4"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
+  else if (g_str_equal (level, "4.1"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
+  else if (g_str_equal (level, "4.2"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
+  else if (g_str_equal (level, "5"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
+  else if (g_str_equal (level, "5.1"))
+    v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
+  else
+    GST_WARNING ("Unsupported level '%s'", level);
+
+  return v4l2_level;
+}
+
+static const gchar *
+v4l2_level_to_string (gint v4l2_level)
+{
+  switch (v4l2_level) {
+    case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+      return "1";
+    case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+      return "1b";
+    case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+      return "1.1";
+    case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+      return "1.2";
+    case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+      return "1.3";
+    case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+      return "2";
+    case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+      return "2.1";
+    case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+      return "2.2";
+    case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+      return "3.0";
+    case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+      return "3.1";
+    case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+      return "3.2";
+    case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+      return "4";
+    case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+      return "4.1";
+    case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+      return "4.2";
+    case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+      return "5";
+    case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+      return "5.1";
+    default:
+      GST_WARNING ("Unsupported V4L2 level %i", v4l2_level);
+      break;
+  }
+
+  return NULL;
+}
+
+static void
+gst_v4l2_h264_enc_init (GstV4l2H264Enc * self)
+{
+}
+
+static void
+gst_v4l2_h264_enc_class_init (GstV4l2H264EncClass * klass)
+{
+  GstElementClass *element_class;
+  GObjectClass *gobject_class;
+  GstV4l2VideoEncClass *baseclass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  element_class = (GstElementClass *) klass;
+  gobject_class = (GObjectClass *) klass;
+  baseclass = (GstV4l2VideoEncClass *) (klass);
+
+  GST_DEBUG_CATEGORY_INIT (gst_v4l2_h264_enc_debug, "v4l2h264enc", 0,
+      "V4L2 H.264 Encoder");
+
+  gst_element_class_set_static_metadata (element_class,
+      "V4L2 H.264 Encoder",
+      "Codec/Encoder/Video",
+      "Encode H.264 video streams via V4L2 API", "ayaka <ayaka@soulik.info>");
+
+  gobject_class->set_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_h264_enc_set_property);
+  gobject_class->get_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_h264_enc_get_property);
+
+  baseclass->codec_name = "H264";
+  baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
+  baseclass->profile_to_string = v4l2_profile_to_string;
+  baseclass->profile_from_string = v4l2_profile_from_string;
+  baseclass->level_cid = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
+  baseclass->level_to_string = v4l2_level_to_string;
+  baseclass->level_from_string = v4l2_level_from_string;
+}
+
+/* Probing functions */
+gboolean
+gst_v4l2_is_h264_enc (GstCaps * sink_caps, GstCaps * src_caps)
+{
+  return gst_v4l2_is_video_enc (sink_caps, src_caps,
+      gst_static_caps_get (&src_template_caps));
+}
+
+void
+gst_v4l2_h264_enc_register (GstPlugin * plugin, const gchar * basename,
+    const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps)
+{
+  gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_H264_ENC,
+      "h264", basename, device_path, sink_caps,
+      gst_static_caps_get (&src_template_caps), src_caps);
+}
diff --git a/sys/v4l2/gstv4l2h264enc.h b/sys/v4l2/gstv4l2h264enc.h
new file mode 100644
index 0000000..3bfa343
--- /dev/null
+++ b/sys/v4l2/gstv4l2h264enc.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 SUMOMO Computer Association.
+ *     Author: ayaka <ayaka@soulik.info>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __GST_V4L2_H264_ENC_H__
+#define __GST_V4L2_H264_ENC_H__
+
+#include <gst/gst.h>
+#include "gstv4l2videoenc.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_V4L2_H264_ENC \
+  (gst_v4l2_h264_enc_get_type())
+#define GST_V4L2_H264_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_H264_ENC,GstV4l2H264Enc))
+#define GST_V4L2_H264_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_H264_ENC,GstV4l2H264EncClass))
+#define GST_IS_V4L2_H264_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_H264_ENC))
+#define GST_IS_V4L2_H264_ENC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_H264_ENC))
+typedef struct _GstV4l2H264Enc GstV4l2H264Enc;
+typedef struct _GstV4l2H264EncClass GstV4l2H264EncClass;
+
+struct _GstV4l2H264Enc
+{
+  GstV4l2VideoEnc parent;
+};
+
+struct _GstV4l2H264EncClass
+{
+  GstV4l2VideoEncClass parent_class;
+};
+
+GType gst_v4l2_h264_enc_get_type (void);
+
+gboolean gst_v4l2_is_h264_enc (GstCaps * sink_caps, GstCaps * src_caps);
+
+void gst_v4l2_h264_enc_register (GstPlugin * plugin, const gchar * basename,
+    const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps);
+
+G_END_DECLS
+#endif /* __GST_V4L2_H264_ENC_H__ */
diff --git a/sys/v4l2/gstv4l2mpeg4enc.c b/sys/v4l2/gstv4l2mpeg4enc.c
new file mode 100644
index 0000000..7b0bb77
--- /dev/null
+++ b/sys/v4l2/gstv4l2mpeg4enc.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2017 Collabora Inc.
+ *    Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gstv4l2object.h"
+#include "gstv4l2mpeg4enc.h"
+
+#include <string.h>
+#include <gst/gst-i18n-plugin.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_v4l2_mpeg4_enc_debug);
+#define GST_CAT_DEFAULT gst_v4l2_mpeg4_enc_debug
+
+static GstStaticCaps src_template_caps =
+GST_STATIC_CAPS ("video/mpeg, mpegversion=(int)4, systemstream=(boolean)FALSE");
+
+enum
+{
+  PROP_0,
+  V4L2_STD_OBJECT_PROPS,
+  /* TODO */
+};
+
+#define gst_v4l2_mpeg4_enc_parent_class parent_class
+G_DEFINE_TYPE (GstV4l2Mpeg4Enc, gst_v4l2_mpeg4_enc, GST_TYPE_V4L2_VIDEO_ENC);
+
+static void
+gst_v4l2_mpeg4_enc_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  /* TODO */
+}
+
+static void
+gst_v4l2_mpeg4_enc_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  /* TODO */
+}
+
+static gint
+v4l2_profile_from_string (const gchar * profile)
+{
+  gint v4l2_profile = -1;
+
+  if (g_str_equal (profile, "simple"))
+    v4l2_profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE;
+  else if (g_str_equal (profile, "advanced-simple"))
+    v4l2_profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE;
+  else if (g_str_equal (profile, "core"))
+    v4l2_profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE;
+  else if (g_str_equal (profile, "simple-scalable"))
+    v4l2_profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE;
+  else if (g_str_equal (profile, "advanced-coding-efficiency"))
+    v4l2_profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY;
+  else
+    GST_WARNING ("Unsupported profile string '%s'", profile);
+
+  return v4l2_profile;
+}
+
+static const gchar *
+v4l2_profile_to_string (gint v4l2_profile)
+{
+  switch (v4l2_profile) {
+    case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+      return "simple";
+    case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+      return "advanced-simple";
+    case V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE:
+      return "core";
+    case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE:
+      return "simple-scalable";
+    case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY:
+      return "advanced-coding-efficiency";
+    default:
+      GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile);
+      break;
+  }
+
+  return NULL;
+}
+
+static gint
+v4l2_level_from_string (const gchar * level)
+{
+  gint v4l2_level = -1;
+
+  if (g_str_equal (level, "0"))
+    v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0;
+  else if (g_str_equal (level, "0b"))
+    v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B;
+  else if (g_str_equal (level, "1"))
+    v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_1;
+  else if (g_str_equal (level, "2"))
+    v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_2;
+  else if (g_str_equal (level, "3"))
+    v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_3;
+  else if (g_str_equal (level, "3b"))
+    v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B;
+  else if (g_str_equal (level, "4"))
+    v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_4;
+  else if (g_str_equal (level, "5"))
+    v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5;
+  else
+    GST_WARNING ("Unsupported level '%s'", level);
+
+  return v4l2_level;
+}
+
+static const gchar *
+v4l2_level_to_string (gint v4l2_level)
+{
+  switch (v4l2_level) {
+    case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0:
+      return "0";
+    case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B:
+      return "0b";
+    case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1:
+      return "1";
+    case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2:
+      return "2";
+    case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3:
+      return "3";
+    case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B:
+      return "3b";
+    case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4:
+      return "4";
+    case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5:
+      return "5";
+    default:
+      GST_WARNING ("Unsupported V4L2 level %i", v4l2_level);
+      break;
+  }
+
+  return NULL;
+}
+
+static void
+gst_v4l2_mpeg4_enc_init (GstV4l2Mpeg4Enc * self)
+{
+}
+
+static void
+gst_v4l2_mpeg4_enc_class_init (GstV4l2Mpeg4EncClass * klass)
+{
+  GstElementClass *element_class;
+  GObjectClass *gobject_class;
+  GstV4l2VideoEncClass *baseclass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  element_class = (GstElementClass *) klass;
+  gobject_class = (GObjectClass *) klass;
+  baseclass = (GstV4l2VideoEncClass *) (klass);
+
+  GST_DEBUG_CATEGORY_INIT (gst_v4l2_mpeg4_enc_debug, "v4l2mpeg4enc", 0,
+      "V4L2 MPEG4 Encoder");
+
+  gst_element_class_set_static_metadata (element_class,
+      "V4L2 MPEG4 Encoder",
+      "Codec/Encoder/Video",
+      "Encode MPEG4 video streams via V4L2 API",
+      "Nicolas Dufresne <nicolas.dufresne@collabora.com");
+
+  gobject_class->set_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_mpeg4_enc_set_property);
+  gobject_class->get_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_mpeg4_enc_get_property);
+
+  baseclass->codec_name = "MPEG4";
+  baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE;
+  baseclass->profile_to_string = v4l2_profile_to_string;
+  baseclass->profile_from_string = v4l2_profile_from_string;
+  baseclass->level_cid = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL;
+  baseclass->level_to_string = v4l2_level_to_string;
+  baseclass->level_from_string = v4l2_level_from_string;
+}
+
+/* Probing functions */
+gboolean
+gst_v4l2_is_mpeg4_enc (GstCaps * sink_caps, GstCaps * src_caps)
+{
+  return gst_v4l2_is_video_enc (sink_caps, src_caps,
+      gst_static_caps_get (&src_template_caps));
+}
+
+void
+gst_v4l2_mpeg4_enc_register (GstPlugin * plugin, const gchar * basename,
+    const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps)
+{
+  gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_MPEG4_ENC,
+      "mpeg4", basename, device_path, sink_caps,
+      gst_static_caps_get (&src_template_caps), src_caps);
+}
diff --git a/sys/v4l2/gstv4l2mpeg4enc.h b/sys/v4l2/gstv4l2mpeg4enc.h
new file mode 100644
index 0000000..8494103
--- /dev/null
+++ b/sys/v4l2/gstv4l2mpeg4enc.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 Collabora Inc.
+ *    Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __GST_V4L2_MPEG4_ENC_H__
+#define __GST_V4L2_MPEG4_ENC_H__
+
+#include <gst/gst.h>
+#include "gstv4l2videoenc.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_V4L2_MPEG4_ENC \
+  (gst_v4l2_mpeg4_enc_get_type())
+#define GST_V4L2_MPEG4_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_MPEG4_ENC,GstV4l2Mpeg4Enc))
+#define GST_V4L2_MPEG4_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_MPEG4_ENC,GstV4l2Mpeg4EncClass))
+#define GST_IS_V4L2_MPEG4_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_MPEG4_ENC))
+#define GST_IS_V4L2_MPEG4_ENC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_MPEG4_ENC))
+typedef struct _GstV4l2Mpeg4Enc GstV4l2Mpeg4Enc;
+typedef struct _GstV4l2Mpeg4EncClass GstV4l2Mpeg4EncClass;
+
+struct _GstV4l2Mpeg4Enc
+{
+  GstV4l2VideoEnc parent;
+};
+
+struct _GstV4l2Mpeg4EncClass
+{
+  GstV4l2VideoEncClass parent_class;
+};
+
+GType gst_v4l2_mpeg4_enc_get_type (void);
+
+gboolean gst_v4l2_is_mpeg4_enc (GstCaps * sink_caps, GstCaps * src_caps);
+
+void gst_v4l2_mpeg4_enc_register (GstPlugin * plugin, const gchar * basename,
+    const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps);
+
+G_END_DECLS
+#endif /* __GST_V4L2_MPEG4_ENC_H__ */
diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c
new file mode 100644
index 0000000..a5e6707
--- /dev/null
+++ b/sys/v4l2/gstv4l2object.c
@@ -0,0 +1,4485 @@
+/* GStreamer
+ *
+ * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *               2006 Edgard Lima <edgard.lima@gmail.com>
+ *
+ * gstv4l2object.c: base class for V4L2 elements
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+
+#ifdef HAVE_GUDEV
+#include <gudev/gudev.h>
+#endif
+
+#include "ext/videodev2.h"
+#include "gstv4l2object.h"
+#include "gstv4l2tuner.h"
+#include "gstv4l2colorbalance.h"
+
+#include "gst/gst-i18n-plugin.h"
+
+#include <gst/video/video.h>
+
+GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
+#define GST_CAT_DEFAULT v4l2_debug
+
+#define DEFAULT_PROP_DEVICE_NAME        NULL
+#define DEFAULT_PROP_DEVICE_FD          -1
+#define DEFAULT_PROP_FLAGS              0
+#define DEFAULT_PROP_TV_NORM            0
+#define DEFAULT_PROP_IO_MODE            GST_V4L2_IO_AUTO
+
+#define ENCODED_BUFFER_SIZE             (2 * 1024 * 1024)
+
+#if SIZEOF_OFF_T == 8 && !defined(mmap64)
+#define mmap64 mmap
+#endif
+
+enum
+{
+  PROP_0,
+  V4L2_STD_OBJECT_PROPS,
+};
+
+/*
+ * common format / caps utilities:
+ */
+typedef enum
+{
+  GST_V4L2_RAW = 1 << 0,
+  GST_V4L2_CODEC = 1 << 1,
+  GST_V4L2_TRANSPORT = 1 << 2,
+  GST_V4L2_NO_PARSE = 1 << 3,
+  GST_V4L2_ALL = 0xffff
+} GstV4L2FormatFlags;
+
+typedef struct
+{
+  guint32 format;
+  gboolean dimensions;
+  GstV4L2FormatFlags flags;
+} GstV4L2FormatDesc;
+
+static const GstV4L2FormatDesc gst_v4l2_formats[] = {
+  /* RGB formats */
+  {V4L2_PIX_FMT_RGB332, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_ARGB555, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_XRGB555, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_ARGB555X, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_XRGB555X, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_RGB565, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_RGB565X, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_BGR666, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_BGR24, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_RGB24, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_ABGR32, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_XBGR32, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_ARGB32, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_XRGB32, TRUE, GST_V4L2_RAW},
+
+  /* Deprecated Packed RGB Image Formats (alpha ambiguity) */
+  {V4L2_PIX_FMT_RGB444, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_RGB555, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_RGB555X, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_BGR32, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_RGB32, TRUE, GST_V4L2_RAW},
+
+  /* Grey formats */
+  {V4L2_PIX_FMT_GREY, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_Y4, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_Y6, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_Y10, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_Y12, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_Y16, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_Y16_BE, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_Y10BPACK, TRUE, GST_V4L2_RAW},
+
+  /* Palette formats */
+  {V4L2_PIX_FMT_PAL8, TRUE, GST_V4L2_RAW},
+
+  /* Chrominance formats */
+  {V4L2_PIX_FMT_UV8, TRUE, GST_V4L2_RAW},
+
+  /* Luminance+Chrominance formats */
+  {V4L2_PIX_FMT_YVU410, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_YVU420, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_YVU420M, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_YUYV, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_YYUV, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_YVYU, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_UYVY, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_VYUY, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_YUV422P, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_YUV411P, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_Y41P, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_YUV444, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_YUV555, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_YUV565, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_YUV32, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_YUV410, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_YUV420, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_YUV420M, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_HI240, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_HM12, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_M420, TRUE, GST_V4L2_RAW},
+
+  /* two planes -- one Y, one Cr + Cb interleaved  */
+  {V4L2_PIX_FMT_NV12, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_NV12M, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_NV12MT, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_NV12MT_16X16, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_NV21, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_NV21M, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_NV16, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_NV16M, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_NV61, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_NV61M, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_NV24, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_NV42, TRUE, GST_V4L2_RAW},
+
+  /* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
+  {V4L2_PIX_FMT_SBGGR8, TRUE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_SGBRG8, TRUE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_SGRBG8, TRUE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_SRGGB8, TRUE, GST_V4L2_CODEC},
+
+  /* compressed formats */
+  {V4L2_PIX_FMT_MJPEG, FALSE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_JPEG, FALSE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_PJPG, FALSE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_DV, FALSE, GST_V4L2_TRANSPORT},
+  {V4L2_PIX_FMT_MPEG, FALSE, GST_V4L2_TRANSPORT},
+  {V4L2_PIX_FMT_H264, FALSE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_H264_NO_SC, FALSE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_H264_MVC, FALSE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_H263, FALSE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_MPEG1, FALSE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_MPEG2, FALSE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_MPEG4, FALSE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_XVID, FALSE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_VC1_ANNEX_G, FALSE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_VC1_ANNEX_L, FALSE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_VP8, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
+  {V4L2_PIX_FMT_VP9, FALSE, GST_V4L2_CODEC | GST_V4L2_NO_PARSE},
+
+  /*  Vendor-specific formats   */
+  {V4L2_PIX_FMT_WNVA, TRUE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_SN9C10X, TRUE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_PWC1, TRUE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_PWC2, TRUE, GST_V4L2_CODEC},
+};
+
+#define GST_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_v4l2_formats))
+
+static GSList *gst_v4l2_object_get_format_list (GstV4l2Object * v4l2object);
+
+
+#define GST_TYPE_V4L2_DEVICE_FLAGS (gst_v4l2_device_get_type ())
+static GType
+gst_v4l2_device_get_type (void)
+{
+  static GType v4l2_device_type = 0;
+
+  if (v4l2_device_type == 0) {
+    static const GFlagsValue values[] = {
+      {V4L2_CAP_VIDEO_CAPTURE, "Device supports video capture", "capture"},
+      {V4L2_CAP_VIDEO_OUTPUT, "Device supports video playback", "output"},
+      {V4L2_CAP_VIDEO_OVERLAY, "Device supports video overlay", "overlay"},
+
+      {V4L2_CAP_VBI_CAPTURE, "Device supports the VBI capture", "vbi-capture"},
+      {V4L2_CAP_VBI_OUTPUT, "Device supports the VBI output", "vbi-output"},
+
+      {V4L2_CAP_TUNER, "Device has a tuner or modulator", "tuner"},
+      {V4L2_CAP_AUDIO, "Device has audio inputs or outputs", "audio"},
+
+      {0, NULL, NULL}
+    };
+
+    v4l2_device_type =
+        g_flags_register_static ("GstV4l2DeviceTypeFlags", values);
+  }
+
+  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;
+}
+
+GType
+gst_v4l2_io_mode_get_type (void)
+{
+  static GType v4l2_io_mode = 0;
+
+  if (!v4l2_io_mode) {
+    static const GEnumValue io_modes[] = {
+      {GST_V4L2_IO_AUTO, "GST_V4L2_IO_AUTO", "auto"},
+      {GST_V4L2_IO_RW, "GST_V4L2_IO_RW", "rw"},
+      {GST_V4L2_IO_MMAP, "GST_V4L2_IO_MMAP", "mmap"},
+      {GST_V4L2_IO_USERPTR, "GST_V4L2_IO_USERPTR", "userptr"},
+      {GST_V4L2_IO_DMABUF, "GST_V4L2_IO_DMABUF", "dmabuf"},
+      {GST_V4L2_IO_DMABUF_IMPORT, "GST_V4L2_IO_DMABUF_IMPORT",
+          "dmabuf-import"},
+
+      {0, NULL, NULL}
+    };
+    v4l2_io_mode = g_enum_register_static ("GstV4l2IOMode", io_modes);
+  }
+  return v4l2_io_mode;
+}
+
+void
+gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class,
+    const char *default_device)
+{
+  g_object_class_install_property (gobject_class, PROP_DEVICE,
+      g_param_spec_string ("device", "Device", "Device location",
+          default_device, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
+      g_param_spec_string ("device-name", "Device name",
+          "Name of the device", DEFAULT_PROP_DEVICE_NAME,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_DEVICE_FD,
+      g_param_spec_int ("device-fd", "File descriptor",
+          "File descriptor of the device", -1, G_MAXINT, DEFAULT_PROP_DEVICE_FD,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_FLAGS,
+      g_param_spec_flags ("flags", "Flags", "Device type flags",
+          GST_TYPE_V4L2_DEVICE_FLAGS, DEFAULT_PROP_FLAGS,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstV4l2Src:brightness:
+   *
+   * Picture brightness, or more precisely, the black level
+   */
+  g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
+      g_param_spec_int ("brightness", "Brightness",
+          "Picture brightness, or more precisely, the black level", G_MININT,
+          G_MAXINT, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  /**
+   * GstV4l2Src:contrast:
+   *
+   * Picture contrast or luma gain
+   */
+  g_object_class_install_property (gobject_class, PROP_CONTRAST,
+      g_param_spec_int ("contrast", "Contrast",
+          "Picture contrast or luma gain", G_MININT,
+          G_MAXINT, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  /**
+   * GstV4l2Src:saturation:
+   *
+   * Picture color saturation or chroma gain
+   */
+  g_object_class_install_property (gobject_class, PROP_SATURATION,
+      g_param_spec_int ("saturation", "Saturation",
+          "Picture color saturation or chroma gain", G_MININT,
+          G_MAXINT, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+  /**
+   * GstV4l2Src:hue:
+   *
+   * Hue or color balance
+   */
+  g_object_class_install_property (gobject_class, PROP_HUE,
+      g_param_spec_int ("hue", "Hue",
+          "Hue or color balance", G_MININT,
+          G_MAXINT, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
+
+  /**
+   * GstV4l2Src:norm:
+   *
+   * TV norm
+   */
+  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));
+
+  /**
+   * GstV4l2Src:io-mode:
+   *
+   * IO Mode
+   */
+  g_object_class_install_property (gobject_class, PROP_IO_MODE,
+      g_param_spec_enum ("io-mode", "IO mode",
+          "I/O mode",
+          GST_TYPE_V4L2_IO_MODE, DEFAULT_PROP_IO_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstV4l2Src:extra-controls:
+   *
+   * Additional v4l2 controls for the device. The controls are identified
+   * by the control name (lowercase with '_' for any non-alphanumeric
+   * characters).
+   *
+   * Since: 1.2
+   */
+  g_object_class_install_property (gobject_class, PROP_EXTRA_CONTROLS,
+      g_param_spec_boxed ("extra-controls", "Extra Controls",
+          "Extra v4l2 controls (CIDs) for the device",
+          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstV4l2Src:pixel-aspect-ratio:
+   *
+   * The pixel aspect ratio of the device. This overwrites the pixel aspect
+   * ratio queried from the device.
+   *
+   * Since: 1.2
+   */
+  g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
+      g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
+          "Overwrite the pixel aspect ratio of the device", "1/1",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstV4l2Src:force-aspect-ratio:
+   *
+   * When enabled, the pixel aspect ratio queried from the device or set
+   * with the pixel-aspect-ratio property will be enforced.
+   *
+   * Since: 1.2
+   */
+  g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
+      g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
+          "When enabled, the pixel aspect ratio will be enforced", TRUE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+}
+
+void
+gst_v4l2_object_install_m2m_properties_helper (GObjectClass * gobject_class)
+{
+  g_object_class_install_property (gobject_class, PROP_DEVICE,
+      g_param_spec_string ("device", "Device", "Device location",
+          NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
+      g_param_spec_string ("device-name", "Device name",
+          "Name of the device", DEFAULT_PROP_DEVICE_NAME,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DEVICE_FD,
+      g_param_spec_int ("device-fd", "File descriptor",
+          "File descriptor of the device", -1, G_MAXINT, DEFAULT_PROP_DEVICE_FD,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_OUTPUT_IO_MODE,
+      g_param_spec_enum ("output-io-mode", "Output IO mode",
+          "Output side I/O mode (matches sink pad)",
+          GST_TYPE_V4L2_IO_MODE, DEFAULT_PROP_IO_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CAPTURE_IO_MODE,
+      g_param_spec_enum ("capture-io-mode", "Capture IO mode",
+          "Capture I/O mode (matches src pad)",
+          GST_TYPE_V4L2_IO_MODE, DEFAULT_PROP_IO_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_EXTRA_CONTROLS,
+      g_param_spec_boxed ("extra-controls", "Extra Controls",
+          "Extra v4l2 controls (CIDs) for the device",
+          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+GstV4l2Object *
+gst_v4l2_object_new (GstElement * element,
+    GstObject * debug_object,
+    enum v4l2_buf_type type,
+    const char *default_device,
+    GstV4l2GetInOutFunction get_in_out_func,
+    GstV4l2SetInOutFunction set_in_out_func,
+    GstV4l2UpdateFpsFunction update_fps_func)
+{
+  GstV4l2Object *v4l2object;
+
+  /*
+   * some default values
+   */
+  v4l2object = g_new0 (GstV4l2Object, 1);
+
+  v4l2object->type = type;
+  v4l2object->formats = NULL;
+
+  v4l2object->element = element;
+  v4l2object->dbg_obj = debug_object;
+  v4l2object->get_in_out_func = get_in_out_func;
+  v4l2object->set_in_out_func = set_in_out_func;
+  v4l2object->update_fps_func = update_fps_func;
+
+  v4l2object->video_fd = -1;
+  v4l2object->active = FALSE;
+  v4l2object->videodev = g_strdup (default_device);
+
+  v4l2object->norms = NULL;
+  v4l2object->channels = NULL;
+  v4l2object->colors = NULL;
+
+  v4l2object->keep_aspect = TRUE;
+
+  v4l2object->n_v4l2_planes = 0;
+
+  v4l2object->no_initial_format = FALSE;
+
+  /* We now disable libv4l2 by default, but have an env to enable it. */
+#ifdef HAVE_LIBV4L2
+  if (g_getenv ("GST_V4L2_USE_LIBV4L2")) {
+    v4l2object->fd_open = v4l2_fd_open;
+    v4l2object->close = v4l2_close;
+    v4l2object->dup = v4l2_dup;
+    v4l2object->ioctl = v4l2_ioctl;
+    v4l2object->read = v4l2_read;
+    v4l2object->mmap = v4l2_mmap;
+    v4l2object->munmap = v4l2_munmap;
+  } else
+#endif
+  {
+    v4l2object->fd_open = NULL;
+    v4l2object->close = close;
+    v4l2object->dup = dup;
+    v4l2object->ioctl = ioctl;
+    v4l2object->read = read;
+    v4l2object->mmap = mmap;
+    v4l2object->munmap = munmap;
+  }
+
+  return v4l2object;
+}
+
+static gboolean gst_v4l2_object_clear_format_list (GstV4l2Object * v4l2object);
+
+
+void
+gst_v4l2_object_destroy (GstV4l2Object * v4l2object)
+{
+  g_return_if_fail (v4l2object != NULL);
+
+  g_free (v4l2object->videodev);
+
+  g_free (v4l2object->channel);
+
+  if (v4l2object->formats) {
+    gst_v4l2_object_clear_format_list (v4l2object);
+  }
+
+  if (v4l2object->probed_caps) {
+    gst_caps_unref (v4l2object->probed_caps);
+  }
+
+  if (v4l2object->extra_controls) {
+    gst_structure_free (v4l2object->extra_controls);
+  }
+
+  g_free (v4l2object);
+}
+
+
+static gboolean
+gst_v4l2_object_clear_format_list (GstV4l2Object * v4l2object)
+{
+  g_slist_foreach (v4l2object->formats, (GFunc) g_free, NULL);
+  g_slist_free (v4l2object->formats);
+  v4l2object->formats = NULL;
+
+  return TRUE;
+}
+
+static gint
+gst_v4l2_object_prop_to_cid (guint prop_id)
+{
+  gint cid = -1;
+
+  switch (prop_id) {
+    case PROP_BRIGHTNESS:
+      cid = V4L2_CID_BRIGHTNESS;
+      break;
+    case PROP_CONTRAST:
+      cid = V4L2_CID_CONTRAST;
+      break;
+    case PROP_SATURATION:
+      cid = V4L2_CID_SATURATION;
+      break;
+    case PROP_HUE:
+      cid = V4L2_CID_HUE;
+      break;
+    default:
+      GST_WARNING ("unmapped property id: %d", prop_id);
+  }
+  return cid;
+}
+
+
+gboolean
+gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  switch (prop_id) {
+    case PROP_DEVICE:
+      g_free (v4l2object->videodev);
+      v4l2object->videodev = g_value_dup_string (value);
+      break;
+    case PROP_BRIGHTNESS:
+    case PROP_CONTRAST:
+    case PROP_SATURATION:
+    case PROP_HUE:
+    {
+      gint cid = gst_v4l2_object_prop_to_cid (prop_id);
+
+      if (cid != -1) {
+        if (GST_V4L2_IS_OPEN (v4l2object)) {
+          gst_v4l2_set_attribute (v4l2object, cid, g_value_get_int (value));
+        }
+      }
+      return TRUE;
+    }
+      break;
+    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);
+        GstTunerChannel *channel = gst_tuner_find_channel_by_name (tuner,
+            (gchar *) g_value_get_string (value));
+
+        if (channel) {
+          /* like gst_tuner_set_channel (tuner, channel)
+             without g_object_notify */
+          gst_v4l2_tuner_set_channel (v4l2object, channel);
+        }
+      } else {
+        g_free (v4l2object->channel);
+        v4l2object->channel = g_value_dup_string (value);
+      }
+      break;
+    case PROP_FREQUENCY:
+      if (GST_V4L2_IS_OPEN (v4l2object)) {
+        GstTuner *tuner = GST_TUNER (v4l2object->element);
+        GstTunerChannel *channel = gst_tuner_get_channel (tuner);
+
+        if (channel &&
+            GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
+          /* like
+             gst_tuner_set_frequency (tuner, channel, g_value_get_ulong (value))
+             without g_object_notify */
+          gst_v4l2_tuner_set_frequency (v4l2object, channel,
+              g_value_get_ulong (value));
+        }
+      } else {
+        v4l2object->frequency = g_value_get_ulong (value);
+      }
+      break;
+#endif
+
+    case PROP_IO_MODE:
+      v4l2object->req_mode = g_value_get_enum (value);
+      break;
+    case PROP_CAPTURE_IO_MODE:
+      g_return_val_if_fail (!V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
+      v4l2object->req_mode = g_value_get_enum (value);
+      break;
+    case PROP_OUTPUT_IO_MODE:
+      g_return_val_if_fail (V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
+      v4l2object->req_mode = g_value_get_enum (value);
+      break;
+    case PROP_EXTRA_CONTROLS:{
+      const GstStructure *s = gst_value_get_structure (value);
+
+      if (v4l2object->extra_controls)
+        gst_structure_free (v4l2object->extra_controls);
+
+      v4l2object->extra_controls = s ? gst_structure_copy (s) : NULL;
+      if (GST_V4L2_IS_OPEN (v4l2object))
+        gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
+      break;
+    }
+    case PROP_PIXEL_ASPECT_RATIO:
+      if (v4l2object->par) {
+        g_value_unset (v4l2object->par);
+        g_free (v4l2object->par);
+      }
+      v4l2object->par = g_new0 (GValue, 1);
+      g_value_init (v4l2object->par, GST_TYPE_FRACTION);
+      if (!g_value_transform (value, v4l2object->par)) {
+        g_warning ("Could not transform string to aspect ratio");
+        gst_value_set_fraction (v4l2object->par, 1, 1);
+      }
+
+      GST_DEBUG_OBJECT (v4l2object->dbg_obj, "set PAR to %d/%d",
+          gst_value_get_fraction_numerator (v4l2object->par),
+          gst_value_get_fraction_denominator (v4l2object->par));
+      break;
+    case PROP_FORCE_ASPECT_RATIO:
+      v4l2object->keep_aspect = g_value_get_boolean (value);
+      break;
+    default:
+      return FALSE;
+      break;
+  }
+  return TRUE;
+}
+
+
+gboolean
+gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  switch (prop_id) {
+    case PROP_DEVICE:
+      g_value_set_string (value, v4l2object->videodev);
+      break;
+    case PROP_DEVICE_NAME:
+    {
+      const guchar *new = NULL;
+
+      if (GST_V4L2_IS_OPEN (v4l2object)) {
+        new = v4l2object->vcap.card;
+      } else if (gst_v4l2_open (v4l2object)) {
+        new = v4l2object->vcap.card;
+        gst_v4l2_close (v4l2object);
+      }
+      g_value_set_string (value, (gchar *) new);
+      break;
+    }
+    case PROP_DEVICE_FD:
+    {
+      if (GST_V4L2_IS_OPEN (v4l2object))
+        g_value_set_int (value, v4l2object->video_fd);
+      else
+        g_value_set_int (value, DEFAULT_PROP_DEVICE_FD);
+      break;
+    }
+    case PROP_FLAGS:
+    {
+      guint flags = 0;
+
+      if (GST_V4L2_IS_OPEN (v4l2object)) {
+        flags |= v4l2object->device_caps &
+            (V4L2_CAP_VIDEO_CAPTURE |
+            V4L2_CAP_VIDEO_OUTPUT |
+            V4L2_CAP_VIDEO_OVERLAY |
+            V4L2_CAP_VBI_CAPTURE |
+            V4L2_CAP_VBI_OUTPUT | V4L2_CAP_TUNER | V4L2_CAP_AUDIO);
+
+        if (v4l2object->device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
+          flags |= V4L2_CAP_VIDEO_CAPTURE;
+
+        if (v4l2object->device_caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE)
+          flags |= V4L2_CAP_VIDEO_OUTPUT;
+      }
+      g_value_set_flags (value, flags);
+      break;
+    }
+    case PROP_BRIGHTNESS:
+    case PROP_CONTRAST:
+    case PROP_SATURATION:
+    case PROP_HUE:
+    {
+      gint cid = gst_v4l2_object_prop_to_cid (prop_id);
+
+      if (cid != -1) {
+        if (GST_V4L2_IS_OPEN (v4l2object)) {
+          gint v;
+          if (gst_v4l2_get_attribute (v4l2object, cid, &v)) {
+            g_value_set_int (value, v);
+          }
+        }
+      }
+      return TRUE;
+    }
+      break;
+    case PROP_TV_NORM:
+      g_value_set_enum (value, v4l2object->tv_norm);
+      break;
+    case PROP_IO_MODE:
+      g_value_set_enum (value, v4l2object->req_mode);
+      break;
+    case PROP_CAPTURE_IO_MODE:
+      g_return_val_if_fail (!V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
+      g_value_set_enum (value, v4l2object->req_mode);
+      break;
+    case PROP_OUTPUT_IO_MODE:
+      g_return_val_if_fail (V4L2_TYPE_IS_OUTPUT (v4l2object->type), FALSE);
+      g_value_set_enum (value, v4l2object->req_mode);
+      break;
+    case PROP_EXTRA_CONTROLS:
+      gst_value_set_structure (value, v4l2object->extra_controls);
+      break;
+    case PROP_PIXEL_ASPECT_RATIO:
+      if (v4l2object->par)
+        g_value_transform (v4l2object->par, value);
+      break;
+    case PROP_FORCE_ASPECT_RATIO:
+      g_value_set_boolean (value, v4l2object->keep_aspect);
+      break;
+    default:
+      return FALSE;
+      break;
+  }
+  return TRUE;
+}
+
+static void
+gst_v4l2_get_driver_min_buffers (GstV4l2Object * v4l2object)
+{
+  struct v4l2_control control = { 0, };
+
+  g_return_if_fail (GST_V4L2_IS_OPEN (v4l2object));
+
+  if (V4L2_TYPE_IS_OUTPUT (v4l2object->type))
+    control.id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT;
+  else
+    control.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
+
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) == 0) {
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj,
+        "driver requires a minimum of %d buffers", control.value);
+    v4l2object->min_buffers = control.value;
+  } else {
+    v4l2object->min_buffers = 0;
+  }
+}
+
+static void
+gst_v4l2_set_defaults (GstV4l2Object * v4l2object)
+{
+  GstTunerNorm *norm = NULL;
+  GstTunerChannel *channel = NULL;
+  GstTuner *tuner;
+
+  if (!GST_IS_TUNER (v4l2object->element))
+    return;
+
+  tuner = GST_TUNER (v4l2object->element);
+
+  if (v4l2object->tv_norm)
+    norm = gst_v4l2_tuner_get_norm_by_std_id (v4l2object, v4l2object->tv_norm);
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "tv_norm=0x%" G_GINT64_MODIFIER "x, "
+      "norm=%p", (guint64) 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) {
+      v4l2object->tv_norm =
+          gst_v4l2_tuner_get_std_id_by_norm (v4l2object, norm);
+      gst_tuner_norm_changed (tuner, norm);
+    }
+  }
+
+  if (v4l2object->channel)
+    channel = gst_tuner_find_channel_by_name (tuner, v4l2object->channel);
+  if (channel) {
+    gst_tuner_set_channel (tuner, channel);
+  } else {
+    channel =
+        GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER
+            (v4l2object->element)));
+    if (channel) {
+      g_free (v4l2object->channel);
+      v4l2object->channel = g_strdup (channel->label);
+      gst_tuner_channel_changed (tuner, channel);
+    }
+  }
+
+  if (channel
+      && GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
+    if (v4l2object->frequency != 0) {
+      gst_tuner_set_frequency (tuner, channel, v4l2object->frequency);
+    } else {
+      v4l2object->frequency = gst_tuner_get_frequency (tuner, channel);
+      if (v4l2object->frequency == 0) {
+        /* guess */
+        gst_tuner_set_frequency (tuner, channel, 1000);
+      } else {
+      }
+    }
+  }
+}
+
+gboolean
+gst_v4l2_object_open (GstV4l2Object * v4l2object)
+{
+  if (gst_v4l2_open (v4l2object))
+    gst_v4l2_set_defaults (v4l2object);
+  else
+    return FALSE;
+
+  return TRUE;
+}
+
+gboolean
+gst_v4l2_object_open_shared (GstV4l2Object * v4l2object, GstV4l2Object * other)
+{
+  gboolean ret;
+
+  ret = gst_v4l2_dup (v4l2object, other);
+
+  return ret;
+}
+
+gboolean
+gst_v4l2_object_close (GstV4l2Object * v4l2object)
+{
+  if (!gst_v4l2_close (v4l2object))
+    return FALSE;
+
+  gst_caps_replace (&v4l2object->probed_caps, NULL);
+
+  /* reset our copy of the device caps */
+  v4l2object->device_caps = 0;
+
+  if (v4l2object->formats) {
+    gst_v4l2_object_clear_format_list (v4l2object);
+  }
+
+  if (v4l2object->par) {
+    g_value_unset (v4l2object->par);
+    g_free (v4l2object->par);
+    v4l2object->par = NULL;
+  }
+
+  return TRUE;
+}
+
+static struct v4l2_fmtdesc *
+gst_v4l2_object_get_format_from_fourcc (GstV4l2Object * v4l2object,
+    guint32 fourcc)
+{
+  struct v4l2_fmtdesc *fmt;
+  GSList *walk;
+
+  if (fourcc == 0)
+    return NULL;
+
+  walk = gst_v4l2_object_get_format_list (v4l2object);
+  while (walk) {
+    fmt = (struct v4l2_fmtdesc *) walk->data;
+    if (fmt->pixelformat == fourcc)
+      return fmt;
+    /* special case for jpeg */
+    if (fmt->pixelformat == V4L2_PIX_FMT_MJPEG ||
+        fmt->pixelformat == V4L2_PIX_FMT_JPEG ||
+        fmt->pixelformat == V4L2_PIX_FMT_PJPG) {
+      if (fourcc == V4L2_PIX_FMT_JPEG || fourcc == V4L2_PIX_FMT_MJPEG ||
+          fourcc == V4L2_PIX_FMT_PJPG) {
+        return fmt;
+      }
+    }
+    walk = g_slist_next (walk);
+  }
+
+  return NULL;
+}
+
+
+
+/* complete made up ranking, the values themselves are meaningless */
+/* These ranks MUST be X such that X<<15 fits on a signed int - see
+   the comment at the end of gst_v4l2_object_format_get_rank. */
+#define YUV_BASE_RANK     1000
+#define JPEG_BASE_RANK     500
+#define DV_BASE_RANK       200
+#define RGB_BASE_RANK      100
+#define YUV_ODD_BASE_RANK   50
+#define RGB_ODD_BASE_RANK   25
+#define BAYER_BASE_RANK     15
+#define S910_BASE_RANK      10
+#define GREY_BASE_RANK       5
+#define PWC_BASE_RANK        1
+
+static gint
+gst_v4l2_object_format_get_rank (const struct v4l2_fmtdesc *fmt)
+{
+  guint32 fourcc = fmt->pixelformat;
+  gboolean emulated = ((fmt->flags & V4L2_FMT_FLAG_EMULATED) != 0);
+  gint rank = 0;
+
+  switch (fourcc) {
+    case V4L2_PIX_FMT_MJPEG:
+    case V4L2_PIX_FMT_PJPG:
+      rank = JPEG_BASE_RANK;
+      break;
+    case V4L2_PIX_FMT_JPEG:
+      rank = JPEG_BASE_RANK + 1;
+      break;
+    case V4L2_PIX_FMT_MPEG:    /* MPEG          */
+      rank = JPEG_BASE_RANK + 2;
+      break;
+
+    case V4L2_PIX_FMT_RGB332:
+    case V4L2_PIX_FMT_ARGB555:
+    case V4L2_PIX_FMT_XRGB555:
+    case V4L2_PIX_FMT_RGB555:
+    case V4L2_PIX_FMT_ARGB555X:
+    case V4L2_PIX_FMT_XRGB555X:
+    case V4L2_PIX_FMT_RGB555X:
+    case V4L2_PIX_FMT_BGR666:
+    case V4L2_PIX_FMT_RGB565:
+    case V4L2_PIX_FMT_RGB565X:
+    case V4L2_PIX_FMT_RGB444:
+    case V4L2_PIX_FMT_Y4:
+    case V4L2_PIX_FMT_Y6:
+    case V4L2_PIX_FMT_Y10:
+    case V4L2_PIX_FMT_Y12:
+    case V4L2_PIX_FMT_Y10BPACK:
+    case V4L2_PIX_FMT_YUV555:
+    case V4L2_PIX_FMT_YUV565:
+    case V4L2_PIX_FMT_YUV32:
+    case V4L2_PIX_FMT_NV12MT_16X16:
+    case V4L2_PIX_FMT_NV42:
+    case V4L2_PIX_FMT_H264_MVC:
+      rank = RGB_ODD_BASE_RANK;
+      break;
+
+    case V4L2_PIX_FMT_RGB24:
+    case V4L2_PIX_FMT_BGR24:
+      rank = RGB_BASE_RANK - 1;
+      break;
+
+    case V4L2_PIX_FMT_RGB32:
+    case V4L2_PIX_FMT_BGR32:
+    case V4L2_PIX_FMT_ABGR32:
+    case V4L2_PIX_FMT_XBGR32:
+    case V4L2_PIX_FMT_ARGB32:
+    case V4L2_PIX_FMT_XRGB32:
+      rank = RGB_BASE_RANK;
+      break;
+
+    case V4L2_PIX_FMT_GREY:    /*  8  Greyscale     */
+      rank = GREY_BASE_RANK;
+      break;
+
+    case V4L2_PIX_FMT_NV12:    /* 12  Y/CbCr 4:2:0  */
+    case V4L2_PIX_FMT_NV12M:   /* Same as NV12      */
+    case V4L2_PIX_FMT_NV12MT:  /* NV12 64x32 tile   */
+    case V4L2_PIX_FMT_NV21:    /* 12  Y/CrCb 4:2:0  */
+    case V4L2_PIX_FMT_NV21M:   /* Same as NV21      */
+    case V4L2_PIX_FMT_YYUV:    /* 16  YUV 4:2:2     */
+    case V4L2_PIX_FMT_HI240:   /*  8  8-bit color   */
+    case V4L2_PIX_FMT_NV16:    /* 16  Y/CbCr 4:2:2  */
+    case V4L2_PIX_FMT_NV16M:   /* Same as NV16      */
+    case V4L2_PIX_FMT_NV61:    /* 16  Y/CrCb 4:2:2  */
+    case V4L2_PIX_FMT_NV61M:   /* Same as NV61      */
+    case V4L2_PIX_FMT_NV24:    /* 24  Y/CrCb 4:4:4  */
+      rank = YUV_ODD_BASE_RANK;
+      break;
+
+    case V4L2_PIX_FMT_YVU410:  /* YVU9,  9 bits per pixel */
+      rank = YUV_BASE_RANK + 3;
+      break;
+    case V4L2_PIX_FMT_YUV410:  /* YUV9,  9 bits per pixel */
+      rank = YUV_BASE_RANK + 2;
+      break;
+    case V4L2_PIX_FMT_YUV420:  /* I420, 12 bits per pixel */
+    case V4L2_PIX_FMT_YUV420M:
+      rank = YUV_BASE_RANK + 7;
+      break;
+    case V4L2_PIX_FMT_YUYV:    /* YUY2, 16 bits per pixel */
+      rank = YUV_BASE_RANK + 10;
+      break;
+    case V4L2_PIX_FMT_YVU420:  /* YV12, 12 bits per pixel */
+      rank = YUV_BASE_RANK + 6;
+      break;
+    case V4L2_PIX_FMT_UYVY:    /* UYVY, 16 bits per pixel */
+      rank = YUV_BASE_RANK + 9;
+      break;
+    case V4L2_PIX_FMT_YUV444:
+      rank = YUV_BASE_RANK + 6;
+      break;
+    case V4L2_PIX_FMT_Y41P:    /* Y41P, 12 bits per pixel */
+      rank = YUV_BASE_RANK + 5;
+      break;
+    case V4L2_PIX_FMT_YUV411P: /* Y41B, 12 bits per pixel */
+      rank = YUV_BASE_RANK + 4;
+      break;
+    case V4L2_PIX_FMT_YUV422P: /* Y42B, 16 bits per pixel */
+      rank = YUV_BASE_RANK + 8;
+      break;
+
+    case V4L2_PIX_FMT_DV:
+      rank = DV_BASE_RANK;
+      break;
+
+    case V4L2_PIX_FMT_WNVA:    /* Winnov hw compres */
+      rank = 0;
+      break;
+
+    case V4L2_PIX_FMT_SBGGR8:
+    case V4L2_PIX_FMT_SGBRG8:
+    case V4L2_PIX_FMT_SGRBG8:
+    case V4L2_PIX_FMT_SRGGB8:
+      rank = BAYER_BASE_RANK;
+      break;
+
+    case V4L2_PIX_FMT_SN9C10X:
+      rank = S910_BASE_RANK;
+      break;
+
+    case V4L2_PIX_FMT_PWC1:
+      rank = PWC_BASE_RANK;
+      break;
+    case V4L2_PIX_FMT_PWC2:
+      rank = PWC_BASE_RANK;
+      break;
+
+    default:
+      rank = 0;
+      break;
+  }
+
+  /* All ranks are below 1<<15 so a shift by 15
+   * will a) make all non-emulated formats larger
+   * than emulated and b) will not overflow
+   */
+  if (!emulated)
+    rank <<= 15;
+
+  return rank;
+}
+
+
+
+static gint
+format_cmp_func (gconstpointer a, gconstpointer b)
+{
+  const struct v4l2_fmtdesc *fa = a;
+  const struct v4l2_fmtdesc *fb = b;
+
+  if (fa->pixelformat == fb->pixelformat)
+    return 0;
+
+  return gst_v4l2_object_format_get_rank (fb) -
+      gst_v4l2_object_format_get_rank (fa);
+}
+
+/******************************************************
+ * gst_v4l2_object_fill_format_list():
+ *   create list of supported capture formats
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+static gboolean
+gst_v4l2_object_fill_format_list (GstV4l2Object * v4l2object,
+    enum v4l2_buf_type type)
+{
+  gint n;
+  struct v4l2_fmtdesc *format;
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "getting src format enumerations");
+
+  /* format enumeration */
+  for (n = 0;; n++) {
+    format = g_new0 (struct v4l2_fmtdesc, 1);
+
+    format->index = n;
+    format->type = type;
+
+    if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0) {
+      if (errno == EINVAL) {
+        g_free (format);
+        break;                  /* end of enumeration */
+      } else {
+        goto failed;
+      }
+    }
+
+    GST_LOG_OBJECT (v4l2object->dbg_obj, "index:       %u", format->index);
+    GST_LOG_OBJECT (v4l2object->dbg_obj, "type:        %d", format->type);
+    GST_LOG_OBJECT (v4l2object->dbg_obj, "flags:       %08x", format->flags);
+    GST_LOG_OBJECT (v4l2object->dbg_obj, "description: '%s'",
+        format->description);
+    GST_LOG_OBJECT (v4l2object->dbg_obj, "pixelformat: %" GST_FOURCC_FORMAT,
+        GST_FOURCC_ARGS (format->pixelformat));
+
+    /* sort formats according to our preference;  we do this, because caps
+     * are probed in the order the formats are in the list, and the order of
+     * formats in the final probed caps matters for things like fixation */
+    v4l2object->formats = g_slist_insert_sorted (v4l2object->formats, format,
+        (GCompareFunc) format_cmp_func);
+  }
+
+#ifndef GST_DISABLE_GST_DEBUG
+  {
+    GSList *l;
+
+    GST_INFO_OBJECT (v4l2object->dbg_obj, "got %d format(s):", n);
+    for (l = v4l2object->formats; l != NULL; l = l->next) {
+      format = l->data;
+
+      GST_INFO_OBJECT (v4l2object->dbg_obj,
+          "  %" GST_FOURCC_FORMAT "%s", GST_FOURCC_ARGS (format->pixelformat),
+          ((format->flags & V4L2_FMT_FLAG_EMULATED)) ? " (emulated)" : "");
+    }
+  }
+#endif
+
+  return TRUE;
+
+  /* ERRORS */
+failed:
+  {
+    g_free (format);
+
+    if (v4l2object->element)
+      return FALSE;
+
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Failed to enumerate possible video formats device '%s' can work "
+                "with"), v4l2object->videodev),
+        ("Failed to get number %d in pixelformat enumeration for %s. (%d - %s)",
+            n, v4l2object->videodev, errno, g_strerror (errno)));
+
+    return FALSE;
+  }
+}
+
+/*
+  * Get the list of supported capture formats, a list of
+  * <code>struct v4l2_fmtdesc</code>.
+  */
+static GSList *
+gst_v4l2_object_get_format_list (GstV4l2Object * v4l2object)
+{
+  if (!v4l2object->formats) {
+
+    /* check usual way */
+    gst_v4l2_object_fill_format_list (v4l2object, v4l2object->type);
+
+    /* if our driver supports multi-planar
+     * and if formats are still empty then we can workaround driver bug
+     * by also looking up formats as if our device was not supporting
+     * multiplanar */
+    if (!v4l2object->formats) {
+      switch (v4l2object->type) {
+        case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+          gst_v4l2_object_fill_format_list (v4l2object,
+              V4L2_BUF_TYPE_VIDEO_CAPTURE);
+          break;
+
+        case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+          gst_v4l2_object_fill_format_list (v4l2object,
+              V4L2_BUF_TYPE_VIDEO_OUTPUT);
+          break;
+
+        default:
+          break;
+      }
+    }
+  }
+  return v4l2object->formats;
+}
+
+static GstVideoFormat
+gst_v4l2_object_v4l2fourcc_to_video_format (guint32 fourcc)
+{
+  GstVideoFormat format;
+
+  switch (fourcc) {
+    case V4L2_PIX_FMT_GREY:    /*  8  Greyscale     */
+      format = GST_VIDEO_FORMAT_GRAY8;
+      break;
+    case V4L2_PIX_FMT_Y16:
+      format = GST_VIDEO_FORMAT_GRAY16_LE;
+      break;
+    case V4L2_PIX_FMT_Y16_BE:
+      format = GST_VIDEO_FORMAT_GRAY16_BE;
+      break;
+    case V4L2_PIX_FMT_XRGB555:
+    case V4L2_PIX_FMT_RGB555:
+      format = GST_VIDEO_FORMAT_RGB15;
+      break;
+    case V4L2_PIX_FMT_XRGB555X:
+    case V4L2_PIX_FMT_RGB555X:
+      format = GST_VIDEO_FORMAT_BGR15;
+      break;
+    case V4L2_PIX_FMT_RGB565:
+      format = GST_VIDEO_FORMAT_RGB16;
+      break;
+    case V4L2_PIX_FMT_RGB24:
+      format = GST_VIDEO_FORMAT_RGB;
+      break;
+    case V4L2_PIX_FMT_BGR24:
+      format = GST_VIDEO_FORMAT_BGR;
+      break;
+    case V4L2_PIX_FMT_XRGB32:
+    case V4L2_PIX_FMT_RGB32:
+      format = GST_VIDEO_FORMAT_xRGB;
+      break;
+    case V4L2_PIX_FMT_XBGR32:
+    case V4L2_PIX_FMT_BGR32:
+      format = GST_VIDEO_FORMAT_BGRx;
+      break;
+    case V4L2_PIX_FMT_ABGR32:
+      format = GST_VIDEO_FORMAT_BGRA;
+      break;
+    case V4L2_PIX_FMT_ARGB32:
+      format = GST_VIDEO_FORMAT_ARGB;
+      break;
+    case V4L2_PIX_FMT_NV12:
+    case V4L2_PIX_FMT_NV12M:
+      format = GST_VIDEO_FORMAT_NV12;
+      break;
+    case V4L2_PIX_FMT_NV12MT:
+      format = GST_VIDEO_FORMAT_NV12_64Z32;
+      break;
+    case V4L2_PIX_FMT_NV21:
+    case V4L2_PIX_FMT_NV21M:
+      format = GST_VIDEO_FORMAT_NV21;
+      break;
+    case V4L2_PIX_FMT_YVU410:
+      format = GST_VIDEO_FORMAT_YVU9;
+      break;
+    case V4L2_PIX_FMT_YUV410:
+      format = GST_VIDEO_FORMAT_YUV9;
+      break;
+    case V4L2_PIX_FMT_YUV420:
+    case V4L2_PIX_FMT_YUV420M:
+      format = GST_VIDEO_FORMAT_I420;
+      break;
+    case V4L2_PIX_FMT_YUYV:
+      format = GST_VIDEO_FORMAT_YUY2;
+      break;
+    case V4L2_PIX_FMT_YVU420:
+      format = GST_VIDEO_FORMAT_YV12;
+      break;
+    case V4L2_PIX_FMT_UYVY:
+      format = GST_VIDEO_FORMAT_UYVY;
+      break;
+    case V4L2_PIX_FMT_YUV411P:
+      format = GST_VIDEO_FORMAT_Y41B;
+      break;
+    case V4L2_PIX_FMT_YUV422P:
+      format = GST_VIDEO_FORMAT_Y42B;
+      break;
+    case V4L2_PIX_FMT_YVYU:
+      format = GST_VIDEO_FORMAT_YVYU;
+      break;
+    case V4L2_PIX_FMT_NV16:
+    case V4L2_PIX_FMT_NV16M:
+      format = GST_VIDEO_FORMAT_NV16;
+      break;
+    case V4L2_PIX_FMT_NV61:
+    case V4L2_PIX_FMT_NV61M:
+      format = GST_VIDEO_FORMAT_NV61;
+      break;
+    case V4L2_PIX_FMT_NV24:
+      format = GST_VIDEO_FORMAT_NV24;
+      break;
+    default:
+      format = GST_VIDEO_FORMAT_UNKNOWN;
+      break;
+  }
+
+  return format;
+}
+
+static gboolean
+gst_v4l2_object_v4l2fourcc_is_rgb (guint32 fourcc)
+{
+  gboolean ret = FALSE;
+
+  switch (fourcc) {
+    case V4L2_PIX_FMT_XRGB555:
+    case V4L2_PIX_FMT_RGB555:
+    case V4L2_PIX_FMT_XRGB555X:
+    case V4L2_PIX_FMT_RGB555X:
+    case V4L2_PIX_FMT_RGB565:
+    case V4L2_PIX_FMT_RGB24:
+    case V4L2_PIX_FMT_BGR24:
+    case V4L2_PIX_FMT_XRGB32:
+    case V4L2_PIX_FMT_RGB32:
+    case V4L2_PIX_FMT_XBGR32:
+    case V4L2_PIX_FMT_BGR32:
+    case V4L2_PIX_FMT_ABGR32:
+    case V4L2_PIX_FMT_ARGB32:
+      ret = TRUE;
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static GstStructure *
+gst_v4l2_object_v4l2fourcc_to_bare_struct (guint32 fourcc)
+{
+  GstStructure *structure = NULL;
+
+  switch (fourcc) {
+    case V4L2_PIX_FMT_MJPEG:   /* Motion-JPEG */
+    case V4L2_PIX_FMT_PJPG:    /* Progressive-JPEG */
+    case V4L2_PIX_FMT_JPEG:    /* JFIF JPEG */
+      structure = gst_structure_new_empty ("image/jpeg");
+      break;
+    case V4L2_PIX_FMT_MPEG1:
+      structure = gst_structure_new ("video/mpeg",
+          "mpegversion", G_TYPE_INT, 2, NULL);
+      break;
+    case V4L2_PIX_FMT_MPEG2:
+      structure = gst_structure_new ("video/mpeg",
+          "mpegversion", G_TYPE_INT, 2, NULL);
+      break;
+    case V4L2_PIX_FMT_MPEG4:
+    case V4L2_PIX_FMT_XVID:
+      structure = gst_structure_new ("video/mpeg",
+          "mpegversion", G_TYPE_INT, 4, "systemstream",
+          G_TYPE_BOOLEAN, FALSE, NULL);
+      break;
+    case V4L2_PIX_FMT_H263:
+      structure = gst_structure_new ("video/x-h263",
+          "variant", G_TYPE_STRING, "itu", NULL);
+      break;
+    case V4L2_PIX_FMT_H264:    /* H.264 */
+      structure = gst_structure_new ("video/x-h264",
+          "stream-format", G_TYPE_STRING, "byte-stream", "alignment",
+          G_TYPE_STRING, "au", NULL);
+      break;
+    case V4L2_PIX_FMT_H264_NO_SC:
+      structure = gst_structure_new ("video/x-h264",
+          "stream-format", G_TYPE_STRING, "avc", "alignment",
+          G_TYPE_STRING, "au", NULL);
+      break;
+    case V4L2_PIX_FMT_VC1_ANNEX_G:
+    case V4L2_PIX_FMT_VC1_ANNEX_L:
+      structure = gst_structure_new ("video/x-wmv",
+          "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
+      break;
+    case V4L2_PIX_FMT_VP8:
+      structure = gst_structure_new_empty ("video/x-vp8");
+      break;
+    case V4L2_PIX_FMT_VP9:
+      structure = gst_structure_new_empty ("video/x-vp9");
+      break;
+    case V4L2_PIX_FMT_GREY:    /*  8  Greyscale     */
+    case V4L2_PIX_FMT_Y16:
+    case V4L2_PIX_FMT_Y16_BE:
+    case V4L2_PIX_FMT_XRGB555:
+    case V4L2_PIX_FMT_RGB555:
+    case V4L2_PIX_FMT_XRGB555X:
+    case V4L2_PIX_FMT_RGB555X:
+    case V4L2_PIX_FMT_RGB565:
+    case V4L2_PIX_FMT_RGB24:
+    case V4L2_PIX_FMT_BGR24:
+    case V4L2_PIX_FMT_RGB32:
+    case V4L2_PIX_FMT_XRGB32:
+    case V4L2_PIX_FMT_ARGB32:
+    case V4L2_PIX_FMT_BGR32:
+    case V4L2_PIX_FMT_XBGR32:
+    case V4L2_PIX_FMT_ABGR32:
+    case V4L2_PIX_FMT_NV12:    /* 12  Y/CbCr 4:2:0  */
+    case V4L2_PIX_FMT_NV12M:
+    case V4L2_PIX_FMT_NV12MT:
+    case V4L2_PIX_FMT_NV21:    /* 12  Y/CrCb 4:2:0  */
+    case V4L2_PIX_FMT_NV21M:
+    case V4L2_PIX_FMT_NV16:    /* 16  Y/CbCr 4:2:2  */
+    case V4L2_PIX_FMT_NV16M:
+    case V4L2_PIX_FMT_NV61:    /* 16  Y/CrCb 4:2:2  */
+    case V4L2_PIX_FMT_NV61M:
+    case V4L2_PIX_FMT_NV24:    /* 24  Y/CrCb 4:4:4  */
+    case V4L2_PIX_FMT_YVU410:
+    case V4L2_PIX_FMT_YUV410:
+    case V4L2_PIX_FMT_YUV420:  /* I420/IYUV */
+    case V4L2_PIX_FMT_YUV420M:
+    case V4L2_PIX_FMT_YUYV:
+    case V4L2_PIX_FMT_YVU420:
+    case V4L2_PIX_FMT_UYVY:
+    case V4L2_PIX_FMT_YUV422P:
+    case V4L2_PIX_FMT_YVYU:
+    case V4L2_PIX_FMT_YUV411P:{
+      GstVideoFormat format;
+      format = gst_v4l2_object_v4l2fourcc_to_video_format (fourcc);
+      if (format != GST_VIDEO_FORMAT_UNKNOWN)
+        structure = gst_structure_new ("video/x-raw",
+            "format", G_TYPE_STRING, gst_video_format_to_string (format), NULL);
+      break;
+    }
+    case V4L2_PIX_FMT_DV:
+      structure =
+          gst_structure_new ("video/x-dv", "systemstream", G_TYPE_BOOLEAN, TRUE,
+          NULL);
+      break;
+    case V4L2_PIX_FMT_MPEG:    /* MPEG          */
+      structure = gst_structure_new ("video/mpegts",
+          "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
+      break;
+    case V4L2_PIX_FMT_WNVA:    /* Winnov hw compres */
+      break;
+    case V4L2_PIX_FMT_SBGGR8:
+    case V4L2_PIX_FMT_SGBRG8:
+    case V4L2_PIX_FMT_SGRBG8:
+    case V4L2_PIX_FMT_SRGGB8:
+      structure = gst_structure_new ("video/x-bayer", "format", G_TYPE_STRING,
+          fourcc == V4L2_PIX_FMT_SBGGR8 ? "bggr" :
+          fourcc == V4L2_PIX_FMT_SGBRG8 ? "gbrg" :
+          fourcc == V4L2_PIX_FMT_SGRBG8 ? "grbg" :
+          /* fourcc == V4L2_PIX_FMT_SRGGB8 ? */ "rggb", NULL);
+      break;
+    case V4L2_PIX_FMT_SN9C10X:
+      structure = gst_structure_new_empty ("video/x-sonix");
+      break;
+    case V4L2_PIX_FMT_PWC1:
+      structure = gst_structure_new_empty ("video/x-pwc1");
+      break;
+    case V4L2_PIX_FMT_PWC2:
+      structure = gst_structure_new_empty ("video/x-pwc2");
+      break;
+    case V4L2_PIX_FMT_RGB332:
+    case V4L2_PIX_FMT_BGR666:
+    case V4L2_PIX_FMT_ARGB555X:
+    case V4L2_PIX_FMT_RGB565X:
+    case V4L2_PIX_FMT_RGB444:
+    case V4L2_PIX_FMT_YYUV:    /* 16  YUV 4:2:2     */
+    case V4L2_PIX_FMT_HI240:   /*  8  8-bit color   */
+    case V4L2_PIX_FMT_Y4:
+    case V4L2_PIX_FMT_Y6:
+    case V4L2_PIX_FMT_Y10:
+    case V4L2_PIX_FMT_Y12:
+    case V4L2_PIX_FMT_Y10BPACK:
+    case V4L2_PIX_FMT_YUV444:
+    case V4L2_PIX_FMT_YUV555:
+    case V4L2_PIX_FMT_YUV565:
+    case V4L2_PIX_FMT_Y41P:
+    case V4L2_PIX_FMT_YUV32:
+    case V4L2_PIX_FMT_NV12MT_16X16:
+    case V4L2_PIX_FMT_NV42:
+    case V4L2_PIX_FMT_H264_MVC:
+    default:
+      GST_DEBUG ("Unsupported fourcc 0x%08x %" GST_FOURCC_FORMAT,
+          fourcc, GST_FOURCC_ARGS (fourcc));
+      break;
+  }
+
+  return structure;
+}
+
+GstStructure *
+gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc)
+{
+  GstStructure *template;
+  gint i;
+
+  template = gst_v4l2_object_v4l2fourcc_to_bare_struct (fourcc);
+
+  if (template == NULL)
+    goto done;
+
+  for (i = 0; i < GST_V4L2_FORMAT_COUNT; i++) {
+    if (gst_v4l2_formats[i].format != fourcc)
+      continue;
+
+    if (gst_v4l2_formats[i].dimensions) {
+      gst_structure_set (template,
+          "width", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
+          "height", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
+          "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
+    }
+    break;
+  }
+
+done:
+  return template;
+}
+
+
+static GstCaps *
+gst_v4l2_object_get_caps_helper (GstV4L2FormatFlags flags)
+{
+  GstStructure *structure;
+  GstCaps *caps;
+  guint i;
+
+  caps = gst_caps_new_empty ();
+  for (i = 0; i < GST_V4L2_FORMAT_COUNT; i++) {
+
+    if ((gst_v4l2_formats[i].flags & flags) == 0)
+      continue;
+
+    structure =
+        gst_v4l2_object_v4l2fourcc_to_bare_struct (gst_v4l2_formats[i].format);
+
+    if (structure) {
+      GstStructure *alt_s = NULL;
+
+      if (gst_v4l2_formats[i].dimensions) {
+        gst_structure_set (structure,
+            "width", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
+            "height", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
+            "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
+      }
+
+      switch (gst_v4l2_formats[i].format) {
+        case V4L2_PIX_FMT_RGB32:
+          alt_s = gst_structure_copy (structure);
+          gst_structure_set (alt_s, "format", G_TYPE_STRING, "ARGB", NULL);
+          break;
+        case V4L2_PIX_FMT_BGR32:
+          alt_s = gst_structure_copy (structure);
+          gst_structure_set (alt_s, "format", G_TYPE_STRING, "BGRA", NULL);
+        default:
+          break;
+      }
+
+      gst_caps_append_structure (caps, structure);
+
+      if (alt_s)
+        gst_caps_append_structure (caps, alt_s);
+    }
+  }
+
+  return gst_caps_simplify (caps);
+}
+
+GstCaps *
+gst_v4l2_object_get_all_caps (void)
+{
+  static GstCaps *caps = NULL;
+
+  if (g_once_init_enter (&caps)) {
+    GstCaps *all_caps = gst_v4l2_object_get_caps_helper (GST_V4L2_ALL);
+    GST_MINI_OBJECT_FLAG_SET (all_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
+    g_once_init_leave (&caps, all_caps);
+  }
+
+  return caps;
+}
+
+GstCaps *
+gst_v4l2_object_get_raw_caps (void)
+{
+  static GstCaps *caps = NULL;
+
+  if (g_once_init_enter (&caps)) {
+    GstCaps *raw_caps = gst_v4l2_object_get_caps_helper (GST_V4L2_RAW);
+    GST_MINI_OBJECT_FLAG_SET (raw_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
+    g_once_init_leave (&caps, raw_caps);
+  }
+
+  return caps;
+}
+
+GstCaps *
+gst_v4l2_object_get_codec_caps (void)
+{
+  static GstCaps *caps = NULL;
+
+  if (g_once_init_enter (&caps)) {
+    GstCaps *codec_caps = gst_v4l2_object_get_caps_helper (GST_V4L2_CODEC);
+    GST_MINI_OBJECT_FLAG_SET (codec_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
+    g_once_init_leave (&caps, codec_caps);
+  }
+
+  return caps;
+}
+
+/* collect data for the given caps
+ * @caps: given input caps
+ * @format: location for the v4l format
+ * @w/@h: location for width and height
+ * @fps_n/@fps_d: location for framerate
+ * @size: location for expected size of the frame or 0 if unknown
+ */
+static gboolean
+gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps,
+    struct v4l2_fmtdesc **format, GstVideoInfo * info)
+{
+  GstStructure *structure;
+  guint32 fourcc = 0, fourcc_nc = 0;
+  const gchar *mimetype;
+  struct v4l2_fmtdesc *fmt = NULL;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  mimetype = gst_structure_get_name (structure);
+
+  if (!gst_video_info_from_caps (info, caps))
+    goto invalid_format;
+
+  if (g_str_equal (mimetype, "video/x-raw")) {
+    switch (GST_VIDEO_INFO_FORMAT (info)) {
+      case GST_VIDEO_FORMAT_I420:
+        fourcc = V4L2_PIX_FMT_YUV420;
+        fourcc_nc = V4L2_PIX_FMT_YUV420M;
+        break;
+      case GST_VIDEO_FORMAT_YUY2:
+        fourcc = V4L2_PIX_FMT_YUYV;
+        break;
+      case GST_VIDEO_FORMAT_UYVY:
+        fourcc = V4L2_PIX_FMT_UYVY;
+        break;
+      case GST_VIDEO_FORMAT_YV12:
+        fourcc = V4L2_PIX_FMT_YVU420;
+        break;
+      case GST_VIDEO_FORMAT_Y41B:
+        fourcc = V4L2_PIX_FMT_YUV411P;
+        break;
+      case GST_VIDEO_FORMAT_Y42B:
+        fourcc = V4L2_PIX_FMT_YUV422P;
+        break;
+      case GST_VIDEO_FORMAT_NV12:
+        fourcc = V4L2_PIX_FMT_NV12;
+        fourcc_nc = V4L2_PIX_FMT_NV12M;
+        break;
+      case GST_VIDEO_FORMAT_NV12_64Z32:
+        fourcc_nc = V4L2_PIX_FMT_NV12MT;
+        break;
+      case GST_VIDEO_FORMAT_NV21:
+        fourcc = V4L2_PIX_FMT_NV21;
+        fourcc_nc = V4L2_PIX_FMT_NV21M;
+        break;
+      case GST_VIDEO_FORMAT_NV16:
+        fourcc = V4L2_PIX_FMT_NV16;
+        fourcc_nc = V4L2_PIX_FMT_NV16M;
+        break;
+      case GST_VIDEO_FORMAT_NV61:
+        fourcc = V4L2_PIX_FMT_NV61;
+        fourcc_nc = V4L2_PIX_FMT_NV61M;
+        break;
+      case GST_VIDEO_FORMAT_NV24:
+        fourcc = V4L2_PIX_FMT_NV24;
+        break;
+      case GST_VIDEO_FORMAT_YVYU:
+        fourcc = V4L2_PIX_FMT_YVYU;
+        break;
+      case GST_VIDEO_FORMAT_RGB15:
+        fourcc = V4L2_PIX_FMT_RGB555;
+        fourcc_nc = V4L2_PIX_FMT_XRGB555;
+        break;
+      case GST_VIDEO_FORMAT_RGB16:
+        fourcc = V4L2_PIX_FMT_RGB565;
+        break;
+      case GST_VIDEO_FORMAT_RGB:
+        fourcc = V4L2_PIX_FMT_RGB24;
+        break;
+      case GST_VIDEO_FORMAT_BGR:
+        fourcc = V4L2_PIX_FMT_BGR24;
+        break;
+      case GST_VIDEO_FORMAT_xRGB:
+        fourcc = V4L2_PIX_FMT_RGB32;
+        fourcc_nc = V4L2_PIX_FMT_XRGB32;
+        break;
+      case GST_VIDEO_FORMAT_ARGB:
+        fourcc = V4L2_PIX_FMT_RGB32;
+        fourcc_nc = V4L2_PIX_FMT_ARGB32;
+        break;
+      case GST_VIDEO_FORMAT_BGRx:
+        fourcc = V4L2_PIX_FMT_BGR32;
+        fourcc_nc = V4L2_PIX_FMT_XBGR32;
+        break;
+      case GST_VIDEO_FORMAT_BGRA:
+        fourcc = V4L2_PIX_FMT_BGR32;
+        fourcc_nc = V4L2_PIX_FMT_ABGR32;
+        break;
+      case GST_VIDEO_FORMAT_GRAY8:
+        fourcc = V4L2_PIX_FMT_GREY;
+        break;
+      case GST_VIDEO_FORMAT_GRAY16_LE:
+        fourcc = V4L2_PIX_FMT_Y16;
+        break;
+      case GST_VIDEO_FORMAT_GRAY16_BE:
+        fourcc = V4L2_PIX_FMT_Y16_BE;
+        break;
+      default:
+        break;
+    }
+  } else {
+    if (g_str_equal (mimetype, "video/mpegts")) {
+      fourcc = V4L2_PIX_FMT_MPEG;
+    } else if (g_str_equal (mimetype, "video/x-dv")) {
+      fourcc = V4L2_PIX_FMT_DV;
+    } else if (g_str_equal (mimetype, "image/jpeg")) {
+      fourcc = V4L2_PIX_FMT_JPEG;
+    } else if (g_str_equal (mimetype, "video/mpeg")) {
+      gint version;
+      if (gst_structure_get_int (structure, "mpegversion", &version)) {
+        switch (version) {
+          case 1:
+            fourcc = V4L2_PIX_FMT_MPEG1;
+            break;
+          case 2:
+            fourcc = V4L2_PIX_FMT_MPEG2;
+            break;
+          case 4:
+            fourcc = V4L2_PIX_FMT_MPEG4;
+            fourcc_nc = V4L2_PIX_FMT_XVID;
+            break;
+          default:
+            break;
+        }
+      }
+    } else if (g_str_equal (mimetype, "video/x-h263")) {
+      fourcc = V4L2_PIX_FMT_H263;
+    } else if (g_str_equal (mimetype, "video/x-h264")) {
+      const gchar *stream_format =
+          gst_structure_get_string (structure, "stream-format");
+      if (g_str_equal (stream_format, "avc"))
+        fourcc = V4L2_PIX_FMT_H264_NO_SC;
+      else
+        fourcc = V4L2_PIX_FMT_H264;
+    } else if (g_str_equal (mimetype, "video/x-vp8")) {
+      fourcc = V4L2_PIX_FMT_VP8;
+    } else if (g_str_equal (mimetype, "video/x-vp9")) {
+      fourcc = V4L2_PIX_FMT_VP9;
+    } else if (g_str_equal (mimetype, "video/x-bayer")) {
+      const gchar *format = gst_structure_get_string (structure, "format");
+      if (format) {
+        if (!g_ascii_strcasecmp (format, "bggr"))
+          fourcc = V4L2_PIX_FMT_SBGGR8;
+        else if (!g_ascii_strcasecmp (format, "gbrg"))
+          fourcc = V4L2_PIX_FMT_SGBRG8;
+        else if (!g_ascii_strcasecmp (format, "grbg"))
+          fourcc = V4L2_PIX_FMT_SGRBG8;
+        else if (!g_ascii_strcasecmp (format, "rggb"))
+          fourcc = V4L2_PIX_FMT_SRGGB8;
+      }
+    } else if (g_str_equal (mimetype, "video/x-sonix")) {
+      fourcc = V4L2_PIX_FMT_SN9C10X;
+    } else if (g_str_equal (mimetype, "video/x-pwc1")) {
+      fourcc = V4L2_PIX_FMT_PWC1;
+    } else if (g_str_equal (mimetype, "video/x-pwc2")) {
+      fourcc = V4L2_PIX_FMT_PWC2;
+    }
+  }
+
+
+  /* Prefer the non-contiguous if supported */
+  v4l2object->prefered_non_contiguous = TRUE;
+
+  if (fourcc_nc)
+    fmt = gst_v4l2_object_get_format_from_fourcc (v4l2object, fourcc_nc);
+  else if (fourcc == 0)
+    goto unhandled_format;
+
+  if (fmt == NULL) {
+    fmt = gst_v4l2_object_get_format_from_fourcc (v4l2object, fourcc);
+    v4l2object->prefered_non_contiguous = FALSE;
+  }
+
+  if (fmt == NULL)
+    goto unsupported_format;
+
+  *format = fmt;
+
+  return TRUE;
+
+  /* ERRORS */
+invalid_format:
+  {
+    GST_DEBUG_OBJECT (v4l2object, "invalid format");
+    return FALSE;
+  }
+unhandled_format:
+  {
+    GST_DEBUG_OBJECT (v4l2object, "unhandled format");
+    return FALSE;
+  }
+unsupported_format:
+  {
+    GST_DEBUG_OBJECT (v4l2object, "unsupported format");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
+    guint32 pixelformat, gint * width, gint * height);
+
+static void
+gst_v4l2_object_add_aspect_ratio (GstV4l2Object * v4l2object, GstStructure * s)
+{
+  if (v4l2object->keep_aspect && v4l2object->par)
+    gst_structure_set_value (s, "pixel-aspect-ratio", v4l2object->par);
+}
+
+/* returns TRUE if the value was changed in place, otherwise FALSE */
+static gboolean
+gst_v4l2src_value_simplify (GValue * val)
+{
+  /* simplify list of one value to one value */
+  if (GST_VALUE_HOLDS_LIST (val) && gst_value_list_get_size (val) == 1) {
+    const GValue *list_val;
+    GValue new_val = G_VALUE_INIT;
+
+    list_val = gst_value_list_get_value (val, 0);
+    g_value_init (&new_val, G_VALUE_TYPE (list_val));
+    g_value_copy (list_val, &new_val);
+    g_value_unset (val);
+    *val = new_val;
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+static gboolean
+gst_v4l2_object_get_interlace_mode (enum v4l2_field field,
+    GstVideoInterlaceMode * interlace_mode)
+{
+  /* NB: If you add new return values, please fix mode_strings in
+   * gst_v4l2_object_add_interlace_mode */
+  switch (field) {
+    case V4L2_FIELD_ANY:
+      GST_ERROR
+          ("Driver bug detected - check driver with v4l2-compliance from http://git.linuxtv.org/v4l-utils.git\n");
+      /* fallthrough */
+    case V4L2_FIELD_NONE:
+      *interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
+      return TRUE;
+    case V4L2_FIELD_INTERLACED:
+    case V4L2_FIELD_INTERLACED_TB:
+    case V4L2_FIELD_INTERLACED_BT:
+      *interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
+      return TRUE;
+    default:
+      GST_ERROR ("Unknown enum v4l2_field %d", field);
+      return FALSE;
+  }
+}
+
+static gboolean
+gst_v4l2_object_get_colorspace (struct v4l2_format *fmt,
+    GstVideoColorimetry * cinfo)
+{
+  gboolean is_rgb =
+      gst_v4l2_object_v4l2fourcc_is_rgb (fmt->fmt.pix.pixelformat);
+  enum v4l2_colorspace colorspace;
+  enum v4l2_quantization range;
+  enum v4l2_ycbcr_encoding matrix;
+  enum v4l2_xfer_func transfer;
+  gboolean ret = TRUE;
+
+  if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type)) {
+    colorspace = fmt->fmt.pix_mp.colorspace;
+    range = fmt->fmt.pix_mp.quantization;
+    matrix = fmt->fmt.pix_mp.ycbcr_enc;
+    transfer = fmt->fmt.pix_mp.xfer_func;
+  } else {
+    colorspace = fmt->fmt.pix.colorspace;
+    range = fmt->fmt.pix.quantization;
+    matrix = fmt->fmt.pix.ycbcr_enc;
+    transfer = fmt->fmt.pix.xfer_func;
+  }
+
+  /* First step, set the defaults for each primaries */
+  switch (colorspace) {
+    case V4L2_COLORSPACE_SMPTE170M:
+      cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
+      cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
+      cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
+      cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
+      break;
+    case V4L2_COLORSPACE_REC709:
+      cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
+      cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT709;
+      cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
+      cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
+      break;
+    case V4L2_COLORSPACE_SRGB:
+    case V4L2_COLORSPACE_JPEG:
+      cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
+      cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
+      cinfo->transfer = GST_VIDEO_TRANSFER_SRGB;
+      cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
+      break;
+    case V4L2_COLORSPACE_ADOBERGB:
+      cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
+      cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
+      cinfo->transfer = GST_VIDEO_TRANSFER_ADOBERGB;
+      cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_ADOBERGB;
+      break;
+    case V4L2_COLORSPACE_BT2020:
+      cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
+      cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
+      cinfo->transfer = GST_VIDEO_TRANSFER_BT2020_12;
+      cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
+      break;
+    case V4L2_COLORSPACE_SMPTE240M:
+      cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
+      cinfo->matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
+      cinfo->transfer = GST_VIDEO_TRANSFER_SMPTE240M;
+      cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE240M;
+      break;
+    case V4L2_COLORSPACE_470_SYSTEM_M:
+      cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
+      cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
+      cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
+      cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT470M;
+      break;
+    case V4L2_COLORSPACE_470_SYSTEM_BG:
+      cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
+      cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
+      cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
+      cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
+      break;
+    case V4L2_COLORSPACE_RAW:
+      /* Explicitly unknown */
+      cinfo->range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
+      cinfo->matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
+      cinfo->transfer = GST_VIDEO_TRANSFER_UNKNOWN;
+      cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
+      break;
+    default:
+      GST_DEBUG ("Unknown enum v4l2_colorspace %d", colorspace);
+      ret = FALSE;
+      break;
+  }
+
+  if (!ret)
+    goto done;
+
+  /* Second step, apply any custom variation */
+  switch (range) {
+    case V4L2_QUANTIZATION_FULL_RANGE:
+      cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
+      break;
+    case V4L2_QUANTIZATION_LIM_RANGE:
+      cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
+      break;
+    case V4L2_QUANTIZATION_DEFAULT:
+      /* replicated V4L2_MAP_QUANTIZATION_DEFAULT macro behavior */
+      if (is_rgb && colorspace == V4L2_COLORSPACE_BT2020)
+        cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
+      else if (is_rgb || matrix == V4L2_YCBCR_ENC_XV601
+          || matrix == V4L2_YCBCR_ENC_XV709
+          || colorspace == V4L2_COLORSPACE_JPEG)
+        cinfo->range = GST_VIDEO_COLOR_RANGE_0_255;
+      else
+        cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
+      break;
+    default:
+      GST_WARNING ("Unknown enum v4l2_quantization value %d", range);
+      cinfo->range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
+      break;
+  }
+
+  switch (matrix) {
+    case V4L2_YCBCR_ENC_XV601:
+    case V4L2_YCBCR_ENC_SYCC:
+      GST_FIXME ("XV601 and SYCC not defined, assuming 601");
+      /* fallthrough */
+    case V4L2_YCBCR_ENC_601:
+      cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
+      break;
+    case V4L2_YCBCR_ENC_XV709:
+      GST_FIXME ("XV709 not defined, assuming 709");
+      /* fallthrough */
+    case V4L2_YCBCR_ENC_709:
+      cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT709;
+      break;
+    case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
+      GST_FIXME ("BT2020 with constant luma is not defined, assuming BT2020");
+      /* fallthrough */
+    case V4L2_YCBCR_ENC_BT2020:
+      cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
+      break;
+    case V4L2_YCBCR_ENC_SMPTE240M:
+      cinfo->matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
+      break;
+    case V4L2_YCBCR_ENC_DEFAULT:
+      /* nothing, just use defaults for colorspace */
+      break;
+    default:
+      GST_WARNING ("Unknown enum v4l2_ycbcr_encoding value %d", matrix);
+      cinfo->matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
+      break;
+  }
+
+  /* Set identity matrix for R'G'B' formats to avoid creating
+   * confusion. This though is cosmetic as it's now properly ignored by
+   * the video info API and videoconvert. */
+  if (is_rgb)
+    cinfo->matrix = GST_VIDEO_COLOR_MATRIX_RGB;
+
+  switch (transfer) {
+    case V4L2_XFER_FUNC_709:
+      if (fmt->fmt.pix.height >= 2160)
+        cinfo->transfer = GST_VIDEO_TRANSFER_BT2020_12;
+      else
+        cinfo->transfer = GST_VIDEO_TRANSFER_BT709;
+      break;
+    case V4L2_XFER_FUNC_SRGB:
+      cinfo->transfer = GST_VIDEO_TRANSFER_SRGB;
+      break;
+    case V4L2_XFER_FUNC_ADOBERGB:
+      cinfo->transfer = GST_VIDEO_TRANSFER_ADOBERGB;
+      break;
+    case V4L2_XFER_FUNC_SMPTE240M:
+      cinfo->transfer = GST_VIDEO_TRANSFER_SMPTE240M;
+      break;
+    case V4L2_XFER_FUNC_NONE:
+      cinfo->transfer = GST_VIDEO_TRANSFER_GAMMA10;
+      break;
+    case V4L2_XFER_FUNC_DEFAULT:
+      /* nothing, just use defaults for colorspace */
+      break;
+    default:
+      GST_WARNING ("Unknown enum v4l2_xfer_func value %d", transfer);
+      cinfo->transfer = GST_VIDEO_TRANSFER_UNKNOWN;
+      break;
+  }
+
+done:
+  return ret;
+}
+
+static int
+gst_v4l2_object_try_fmt (GstV4l2Object * v4l2object,
+    struct v4l2_format *try_fmt)
+{
+  int fd = v4l2object->video_fd;
+  struct v4l2_format fmt;
+  int r;
+
+  memcpy (&fmt, try_fmt, sizeof (fmt));
+  r = v4l2object->ioctl (fd, VIDIOC_TRY_FMT, &fmt);
+
+  if (r < 0 && errno == ENOTTY) {
+    /* The driver might not implement TRY_FMT, in which case we will try
+       S_FMT to probe */
+    if (GST_V4L2_IS_ACTIVE (v4l2object))
+      goto error;
+
+    memcpy (&fmt, try_fmt, sizeof (fmt));
+    r = v4l2object->ioctl (fd, VIDIOC_S_FMT, &fmt);
+  }
+  memcpy (try_fmt, &fmt, sizeof (fmt));
+
+  return r;
+
+error:
+  memcpy (try_fmt, &fmt, sizeof (fmt));
+  GST_WARNING_OBJECT (v4l2object->dbg_obj,
+      "Unable to try format: %s", g_strerror (errno));
+  return r;
+}
+
+
+static void
+gst_v4l2_object_add_interlace_mode (GstV4l2Object * v4l2object,
+    GstStructure * s, guint32 width, guint32 height, guint32 pixelformat)
+{
+  struct v4l2_format fmt;
+  GValue interlace_formats = { 0, };
+  GstVideoInterlaceMode interlace_mode, prev = -1;
+
+  const gchar *mode_strings[] = { "progressive",
+    "interleaved",
+    "mixed"
+  };
+
+  if (!g_str_equal (gst_structure_get_name (s), "video/x-raw"))
+    return;
+
+  if (v4l2object->never_interlaced) {
+    gst_structure_set (s, "interlace-mode", G_TYPE_STRING, "progressive", NULL);
+    return;
+  }
+
+  g_value_init (&interlace_formats, GST_TYPE_LIST);
+
+  /* Try twice - once for NONE, once for INTERLACED. */
+  memset (&fmt, 0, sizeof (fmt));
+  fmt.type = v4l2object->type;
+  fmt.fmt.pix.width = width;
+  fmt.fmt.pix.height = height;
+  fmt.fmt.pix.pixelformat = pixelformat;
+  fmt.fmt.pix.field = V4L2_FIELD_NONE;
+
+  if (gst_v4l2_object_try_fmt (v4l2object, &fmt) == 0 &&
+      gst_v4l2_object_get_interlace_mode (fmt.fmt.pix.field, &interlace_mode)) {
+    GValue interlace_enum = { 0, };
+    g_value_init (&interlace_enum, G_TYPE_STRING);
+    g_value_set_string (&interlace_enum, mode_strings[interlace_mode]);
+    gst_value_list_append_and_take_value (&interlace_formats, &interlace_enum);
+    prev = interlace_mode;
+  }
+
+  memset (&fmt, 0, sizeof (fmt));
+  fmt.type = v4l2object->type;
+  fmt.fmt.pix.width = width;
+  fmt.fmt.pix.height = height;
+  fmt.fmt.pix.pixelformat = pixelformat;
+  fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+  if (gst_v4l2_object_try_fmt (v4l2object, &fmt) == 0 &&
+      gst_v4l2_object_get_interlace_mode (fmt.fmt.pix.field, &interlace_mode) &&
+      prev != interlace_mode) {
+    GValue interlace_enum = { 0, };
+    g_value_init (&interlace_enum, G_TYPE_STRING);
+    g_value_set_string (&interlace_enum, mode_strings[interlace_mode]);
+    gst_value_list_append_and_take_value (&interlace_formats, &interlace_enum);
+  }
+
+  if (gst_v4l2src_value_simplify (&interlace_formats)
+      || gst_value_list_get_size (&interlace_formats) > 0)
+    gst_structure_take_value (s, "interlace-mode", &interlace_formats);
+  else
+    GST_WARNING_OBJECT (v4l2object, "Failed to determine interlace mode");
+
+  return;
+}
+
+static void
+gst_v4l2_object_fill_colorimetry_list (GValue * list,
+    GstVideoColorimetry * cinfo)
+{
+  GValue colorimetry = G_VALUE_INIT;
+  guint size;
+  guint i;
+  gboolean found = FALSE;
+
+  g_value_init (&colorimetry, G_TYPE_STRING);
+  g_value_take_string (&colorimetry, gst_video_colorimetry_to_string (cinfo));
+
+  /* only insert if no duplicate */
+  size = gst_value_list_get_size (list);
+  for (i = 0; i < size; i++) {
+    const GValue *tmp;
+
+    tmp = gst_value_list_get_value (list, i);
+    if (gst_value_compare (&colorimetry, tmp) == GST_VALUE_EQUAL) {
+      found = TRUE;
+      break;
+    }
+  }
+
+  if (!found)
+    gst_value_list_append_and_take_value (list, &colorimetry);
+  else
+    g_value_unset (&colorimetry);
+}
+
+static void
+gst_v4l2_object_add_colorspace (GstV4l2Object * v4l2object, GstStructure * s,
+    guint32 width, guint32 height, guint32 pixelformat)
+{
+  struct v4l2_format fmt;
+  GValue list = G_VALUE_INIT;
+  GstVideoColorimetry cinfo;
+  enum v4l2_colorspace req_cspace;
+
+  memset (&fmt, 0, sizeof (fmt));
+  fmt.type = v4l2object->type;
+  fmt.fmt.pix.width = width;
+  fmt.fmt.pix.height = height;
+  fmt.fmt.pix.pixelformat = pixelformat;
+
+  g_value_init (&list, GST_TYPE_LIST);
+
+  /* step 1: get device default colorspace and insert it first as
+   * it should be the preferred one */
+  if (gst_v4l2_object_try_fmt (v4l2object, &fmt) == 0) {
+    if (gst_v4l2_object_get_colorspace (&fmt, &cinfo))
+      gst_v4l2_object_fill_colorimetry_list (&list, &cinfo);
+  }
+
+  /* step 2: probe all colorspace other than default
+   * We don't probe all colorspace, range, matrix and transfer combination to
+   * avoid ioctl flooding which could greatly increase initialization time
+   * with low-speed devices (UVC...) */
+  for (req_cspace = V4L2_COLORSPACE_SMPTE170M;
+      req_cspace <= V4L2_COLORSPACE_RAW; req_cspace++) {
+    /* V4L2_COLORSPACE_BT878 is deprecated and shall not be used, so skip */
+    if (req_cspace == V4L2_COLORSPACE_BT878)
+      continue;
+
+    if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
+      fmt.fmt.pix_mp.colorspace = req_cspace;
+    else
+      fmt.fmt.pix.colorspace = req_cspace;
+
+    if (gst_v4l2_object_try_fmt (v4l2object, &fmt) == 0) {
+      enum v4l2_colorspace colorspace;
+
+      if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
+        colorspace = fmt.fmt.pix_mp.colorspace;
+      else
+        colorspace = fmt.fmt.pix.colorspace;
+
+      if (colorspace == req_cspace) {
+        if (gst_v4l2_object_get_colorspace (&fmt, &cinfo))
+          gst_v4l2_object_fill_colorimetry_list (&list, &cinfo);
+      }
+    }
+  }
+
+  if (gst_value_list_get_size (&list) > 0)
+    gst_structure_take_value (s, "colorimetry", &list);
+  else
+    g_value_unset (&list);
+
+  return;
+}
+
+/* The frame interval enumeration code first appeared in Linux 2.6.19. */
+static GstStructure *
+gst_v4l2_object_probe_caps_for_format_and_size (GstV4l2Object * v4l2object,
+    guint32 pixelformat,
+    guint32 width, guint32 height, const GstStructure * template)
+{
+  gint fd = v4l2object->video_fd;
+  struct v4l2_frmivalenum ival;
+  guint32 num, denom;
+  GstStructure *s;
+  GValue rates = { 0, };
+
+  memset (&ival, 0, sizeof (struct v4l2_frmivalenum));
+  ival.index = 0;
+  ival.pixel_format = pixelformat;
+  ival.width = width;
+  ival.height = height;
+
+  GST_LOG_OBJECT (v4l2object->dbg_obj,
+      "get frame interval for %ux%u, %" GST_FOURCC_FORMAT, width, height,
+      GST_FOURCC_ARGS (pixelformat));
+
+  /* keep in mind that v4l2 gives us frame intervals (durations); we invert the
+   * fraction to get framerate */
+  if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0)
+    goto enum_frameintervals_failed;
+
+  if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
+    GValue rate = { 0, };
+
+    g_value_init (&rates, GST_TYPE_LIST);
+    g_value_init (&rate, GST_TYPE_FRACTION);
+
+    do {
+      num = ival.discrete.numerator;
+      denom = ival.discrete.denominator;
+
+      if (num > G_MAXINT || denom > G_MAXINT) {
+        /* let us hope we don't get here... */
+        num >>= 1;
+        denom >>= 1;
+      }
+
+      GST_LOG_OBJECT (v4l2object->dbg_obj, "adding discrete framerate: %d/%d",
+          denom, num);
+
+      /* swap to get the framerate */
+      gst_value_set_fraction (&rate, denom, num);
+      gst_value_list_append_value (&rates, &rate);
+
+      ival.index++;
+    } while (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0);
+  } else if (ival.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
+    GValue min = { 0, };
+    GValue step = { 0, };
+    GValue max = { 0, };
+    gboolean added = FALSE;
+    guint32 minnum, mindenom;
+    guint32 maxnum, maxdenom;
+
+    g_value_init (&rates, GST_TYPE_LIST);
+
+    g_value_init (&min, GST_TYPE_FRACTION);
+    g_value_init (&step, GST_TYPE_FRACTION);
+    g_value_init (&max, GST_TYPE_FRACTION);
+
+    /* get the min */
+    minnum = ival.stepwise.min.numerator;
+    mindenom = ival.stepwise.min.denominator;
+    if (minnum > G_MAXINT || mindenom > G_MAXINT) {
+      minnum >>= 1;
+      mindenom >>= 1;
+    }
+    GST_LOG_OBJECT (v4l2object->dbg_obj, "stepwise min frame interval: %d/%d",
+        minnum, mindenom);
+    gst_value_set_fraction (&min, minnum, mindenom);
+
+    /* get the max */
+    maxnum = ival.stepwise.max.numerator;
+    maxdenom = ival.stepwise.max.denominator;
+    if (maxnum > G_MAXINT || maxdenom > G_MAXINT) {
+      maxnum >>= 1;
+      maxdenom >>= 1;
+    }
+
+    GST_LOG_OBJECT (v4l2object->dbg_obj, "stepwise max frame interval: %d/%d",
+        maxnum, maxdenom);
+    gst_value_set_fraction (&max, maxnum, maxdenom);
+
+    /* get the step */
+    num = ival.stepwise.step.numerator;
+    denom = ival.stepwise.step.denominator;
+    if (num > G_MAXINT || denom > G_MAXINT) {
+      num >>= 1;
+      denom >>= 1;
+    }
+
+    if (num == 0 || denom == 0) {
+      /* in this case we have a wrong fraction or no step, set the step to max
+       * so that we only add the min value in the loop below */
+      num = maxnum;
+      denom = maxdenom;
+    }
+
+    /* since we only have gst_value_fraction_subtract and not add, negate the
+     * numerator */
+    GST_LOG_OBJECT (v4l2object->dbg_obj, "stepwise step frame interval: %d/%d",
+        num, denom);
+    gst_value_set_fraction (&step, -num, denom);
+
+    while (gst_value_compare (&min, &max) != GST_VALUE_GREATER_THAN) {
+      GValue rate = { 0, };
+
+      num = gst_value_get_fraction_numerator (&min);
+      denom = gst_value_get_fraction_denominator (&min);
+      GST_LOG_OBJECT (v4l2object->dbg_obj, "adding stepwise framerate: %d/%d",
+          denom, num);
+
+      /* invert to get the framerate */
+      g_value_init (&rate, GST_TYPE_FRACTION);
+      gst_value_set_fraction (&rate, denom, num);
+      gst_value_list_append_value (&rates, &rate);
+      added = TRUE;
+
+      /* we're actually adding because step was negated above. This is because
+       * there is no _add function... */
+      if (!gst_value_fraction_subtract (&min, &min, &step)) {
+        GST_WARNING_OBJECT (v4l2object->dbg_obj, "could not step fraction!");
+        break;
+      }
+    }
+    if (!added) {
+      /* no range was added, leave the default range from the template */
+      GST_WARNING_OBJECT (v4l2object->dbg_obj,
+          "no range added, leaving default");
+      g_value_unset (&rates);
+    }
+  } else if (ival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) {
+    guint32 maxnum, maxdenom;
+
+    g_value_init (&rates, GST_TYPE_FRACTION_RANGE);
+
+    num = ival.stepwise.min.numerator;
+    denom = ival.stepwise.min.denominator;
+    if (num > G_MAXINT || denom > G_MAXINT) {
+      num >>= 1;
+      denom >>= 1;
+    }
+
+    maxnum = ival.stepwise.max.numerator;
+    maxdenom = ival.stepwise.max.denominator;
+    if (maxnum > G_MAXINT || maxdenom > G_MAXINT) {
+      maxnum >>= 1;
+      maxdenom >>= 1;
+    }
+
+    GST_LOG_OBJECT (v4l2object->dbg_obj,
+        "continuous frame interval %d/%d to %d/%d", maxdenom, maxnum, denom,
+        num);
+
+    gst_value_set_fraction_range_full (&rates, maxdenom, maxnum, denom, num);
+  } else {
+    goto unknown_type;
+  }
+
+return_data:
+  s = gst_structure_copy (template);
+  gst_structure_set (s, "width", G_TYPE_INT, (gint) width,
+      "height", G_TYPE_INT, (gint) height, NULL);
+
+  gst_v4l2_object_add_aspect_ratio (v4l2object, s);
+
+  if (!v4l2object->skip_try_fmt_probes) {
+    gst_v4l2_object_add_interlace_mode (v4l2object, s, width, height,
+        pixelformat);
+    gst_v4l2_object_add_colorspace (v4l2object, s, width, height, pixelformat);
+  }
+
+  if (G_IS_VALUE (&rates)) {
+    gst_v4l2src_value_simplify (&rates);
+    /* only change the framerate on the template when we have a valid probed new
+     * value */
+    gst_structure_take_value (s, "framerate", &rates);
+  } else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+      v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+    gst_structure_set (s, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT,
+        1, NULL);
+  }
+  return s;
+
+  /* ERRORS */
+enum_frameintervals_failed:
+  {
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj,
+        "Unable to enumerate intervals for %" GST_FOURCC_FORMAT "@%ux%u",
+        GST_FOURCC_ARGS (pixelformat), width, height);
+    goto return_data;
+  }
+unknown_type:
+  {
+    /* I don't see how this is actually an error, we ignore the format then */
+    GST_WARNING_OBJECT (v4l2object->dbg_obj,
+        "Unknown frame interval type at %" GST_FOURCC_FORMAT "@%ux%u: %u",
+        GST_FOURCC_ARGS (pixelformat), width, height, ival.type);
+    return NULL;
+  }
+}
+
+static gint
+sort_by_frame_size (GstStructure * s1, GstStructure * s2)
+{
+  int w1, h1, w2, h2;
+
+  gst_structure_get_int (s1, "width", &w1);
+  gst_structure_get_int (s1, "height", &h1);
+  gst_structure_get_int (s2, "width", &w2);
+  gst_structure_get_int (s2, "height", &h2);
+
+  /* I think it's safe to assume that this won't overflow for a while */
+  return ((w2 * h2) - (w1 * h1));
+}
+
+static void
+gst_v4l2_object_update_and_append (GstV4l2Object * v4l2object,
+    guint32 format, GstCaps * caps, GstStructure * s)
+{
+  GstStructure *alt_s = NULL;
+
+  /* Encoded stream on output buffer need to be parsed */
+  if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+      v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+    gint i = 0;
+
+    for (; i < GST_V4L2_FORMAT_COUNT; i++) {
+      if (format == gst_v4l2_formats[i].format &&
+          gst_v4l2_formats[i].flags & GST_V4L2_CODEC &&
+          !(gst_v4l2_formats[i].flags & GST_V4L2_NO_PARSE)) {
+        gst_structure_set (s, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
+        break;
+      }
+    }
+  }
+
+  if (v4l2object->has_alpha_component &&
+      (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+          v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
+    switch (format) {
+      case V4L2_PIX_FMT_RGB32:
+        alt_s = gst_structure_copy (s);
+        gst_structure_set (alt_s, "format", G_TYPE_STRING, "ARGB", NULL);
+        break;
+      case V4L2_PIX_FMT_BGR32:
+        alt_s = gst_structure_copy (s);
+        gst_structure_set (alt_s, "format", G_TYPE_STRING, "BGRA", NULL);
+        break;
+      default:
+        break;
+    }
+  }
+
+  gst_caps_append_structure (caps, s);
+
+  if (alt_s)
+    gst_caps_append_structure (caps, alt_s);
+}
+
+static GstCaps *
+gst_v4l2_object_probe_caps_for_format (GstV4l2Object * v4l2object,
+    guint32 pixelformat, const GstStructure * template)
+{
+  GstCaps *ret = gst_caps_new_empty ();
+  GstStructure *tmp;
+  gint fd = v4l2object->video_fd;
+  struct v4l2_frmsizeenum size;
+  GList *results = NULL;
+  guint32 w, h;
+
+  if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G')) {
+    gst_caps_append_structure (ret, gst_structure_copy (template));
+    return ret;
+  }
+
+  memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
+  size.index = 0;
+  size.pixel_format = pixelformat;
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj,
+      "Enumerating frame sizes for %" GST_FOURCC_FORMAT,
+      GST_FOURCC_ARGS (pixelformat));
+
+  if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0)
+    goto enum_framesizes_failed;
+
+  if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
+    do {
+      GST_LOG_OBJECT (v4l2object->dbg_obj, "got discrete frame size %dx%d",
+          size.discrete.width, size.discrete.height);
+
+      w = MIN (size.discrete.width, G_MAXINT);
+      h = MIN (size.discrete.height, G_MAXINT);
+
+      if (w && h) {
+        tmp =
+            gst_v4l2_object_probe_caps_for_format_and_size (v4l2object,
+            pixelformat, w, h, template);
+
+        if (tmp)
+          results = g_list_prepend (results, tmp);
+      }
+
+      size.index++;
+    } while (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0);
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj,
+        "done iterating discrete frame sizes");
+  } else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
+    guint32 maxw, maxh, step_w, step_h;
+
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "we have stepwise frame sizes:");
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min width:   %d",
+        size.stepwise.min_width);
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height:  %d",
+        size.stepwise.min_height);
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "max width:   %d",
+        size.stepwise.max_width);
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height:  %d",
+        size.stepwise.max_height);
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "step width:  %d",
+        size.stepwise.step_width);
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "step height: %d",
+        size.stepwise.step_height);
+
+    w = MAX (size.stepwise.min_width, 1);
+    h = MAX (size.stepwise.min_height, 1);
+    maxw = MIN (size.stepwise.max_width, G_MAXINT);
+    maxh = MIN (size.stepwise.max_height, G_MAXINT);
+
+    step_w = MAX (size.stepwise.step_width, 1);
+    step_h = MAX (size.stepwise.step_height, 1);
+
+    /* FIXME: check for sanity and that min/max are multiples of the steps */
+
+    /* we only query details for the max width/height since it's likely the
+     * most restricted if there are any resolution-dependent restrictions */
+    tmp = gst_v4l2_object_probe_caps_for_format_and_size (v4l2object,
+        pixelformat, maxw, maxh, template);
+
+    if (tmp) {
+      GValue step_range = G_VALUE_INIT;
+
+      g_value_init (&step_range, GST_TYPE_INT_RANGE);
+      gst_value_set_int_range_step (&step_range, w, maxw, step_w);
+      gst_structure_set_value (tmp, "width", &step_range);
+
+      gst_value_set_int_range_step (&step_range, h, maxh, step_h);
+      gst_structure_take_value (tmp, "height", &step_range);
+
+      /* no point using the results list here, since there's only one struct */
+      gst_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
+    }
+  } else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
+    guint32 maxw, maxh;
+
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "we have continuous frame sizes:");
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min width:   %d",
+        size.stepwise.min_width);
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height:  %d",
+        size.stepwise.min_height);
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "max width:   %d",
+        size.stepwise.max_width);
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "min height:  %d",
+        size.stepwise.max_height);
+
+    w = MAX (size.stepwise.min_width, 1);
+    h = MAX (size.stepwise.min_height, 1);
+    maxw = MIN (size.stepwise.max_width, G_MAXINT);
+    maxh = MIN (size.stepwise.max_height, G_MAXINT);
+
+    tmp =
+        gst_v4l2_object_probe_caps_for_format_and_size (v4l2object, pixelformat,
+        w, h, template);
+    if (tmp) {
+      gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, (gint) w,
+          (gint) maxw, "height", GST_TYPE_INT_RANGE, (gint) h, (gint) maxh,
+          NULL);
+
+      /* no point using the results list here, since there's only one struct */
+      gst_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
+    }
+  } else {
+    goto unknown_type;
+  }
+
+  /* we use an intermediary list to store and then sort the results of the
+   * probing because we can't make any assumptions about the order in which
+   * the driver will give us the sizes, but we want the final caps to contain
+   * the results starting with the highest resolution and having the lowest
+   * resolution last, since order in caps matters for things like fixation. */
+  results = g_list_sort (results, (GCompareFunc) sort_by_frame_size);
+  while (results != NULL) {
+    gst_v4l2_object_update_and_append (v4l2object, pixelformat, ret,
+        results->data);
+    results = g_list_delete_link (results, results);
+  }
+
+  if (gst_caps_is_empty (ret))
+    goto enum_framesizes_no_results;
+
+  return ret;
+
+  /* ERRORS */
+enum_framesizes_failed:
+  {
+    /* I don't see how this is actually an error */
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj,
+        "Failed to enumerate frame sizes for pixelformat %" GST_FOURCC_FORMAT
+        " (%s)", GST_FOURCC_ARGS (pixelformat), g_strerror (errno));
+    goto default_frame_sizes;
+  }
+enum_framesizes_no_results:
+  {
+    /* it's possible that VIDIOC_ENUM_FRAMESIZES is defined but the driver in
+     * question doesn't actually support it yet */
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj,
+        "No results for pixelformat %" GST_FOURCC_FORMAT
+        " enumerating frame sizes, trying fallback",
+        GST_FOURCC_ARGS (pixelformat));
+    goto default_frame_sizes;
+  }
+unknown_type:
+  {
+    GST_WARNING_OBJECT (v4l2object->dbg_obj,
+        "Unknown frame sizeenum type for pixelformat %" GST_FOURCC_FORMAT
+        ": %u", GST_FOURCC_ARGS (pixelformat), size.type);
+    goto default_frame_sizes;
+  }
+
+default_frame_sizes:
+  {
+    gint min_w, max_w, min_h, max_h, fix_num = 0, fix_denom = 0;
+
+    /* This code is for Linux < 2.6.19 */
+    min_w = min_h = 1;
+    max_w = max_h = GST_V4L2_MAX_SIZE;
+    if (!gst_v4l2_object_get_nearest_size (v4l2object, pixelformat, &min_w,
+            &min_h)) {
+      GST_WARNING_OBJECT (v4l2object->dbg_obj,
+          "Could not probe minimum capture size for pixelformat %"
+          GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
+    }
+    if (!gst_v4l2_object_get_nearest_size (v4l2object, pixelformat, &max_w,
+            &max_h)) {
+      GST_WARNING_OBJECT (v4l2object->dbg_obj,
+          "Could not probe maximum capture size for pixelformat %"
+          GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
+    }
+
+    /* Since we can't get framerate directly, try to use the current norm */
+    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, current->label))
+          break;
+      }
+      /* If it's possible, set framerate to that (discrete) value */
+      if (norm) {
+        fix_num = gst_value_get_fraction_numerator (&norm->framerate);
+        fix_denom = gst_value_get_fraction_denominator (&norm->framerate);
+      }
+    }
+
+    tmp = gst_structure_copy (template);
+    if (fix_num) {
+      gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION, fix_num,
+          fix_denom, NULL);
+    } else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+        v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+      /* if norm can't be used, copy the template framerate */
+      gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1,
+          G_MAXINT, 1, NULL);
+    }
+
+    if (min_w == max_w)
+      gst_structure_set (tmp, "width", G_TYPE_INT, max_w, NULL);
+    else
+      gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, min_w, max_w, NULL);
+
+    if (min_h == max_h)
+      gst_structure_set (tmp, "height", G_TYPE_INT, max_h, NULL);
+    else
+      gst_structure_set (tmp, "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
+
+    gst_v4l2_object_add_aspect_ratio (v4l2object, tmp);
+
+    if (!v4l2object->skip_try_fmt_probes) {
+      /* We could consider setting interlace mode from min and max. */
+      gst_v4l2_object_add_interlace_mode (v4l2object, tmp, max_w, max_h,
+          pixelformat);
+      /* We could consider to check colorspace for min too, in case it depends on
+       * the size. But in this case, min and max could not be enough */
+      gst_v4l2_object_add_colorspace (v4l2object, tmp, max_w, max_h,
+          pixelformat);
+    }
+
+    gst_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
+    return ret;
+  }
+}
+
+static gboolean
+gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
+    guint32 pixelformat, gint * width, gint * height)
+{
+  struct v4l2_format fmt;
+  gboolean ret = FALSE;
+  GstVideoInterlaceMode interlace_mode;
+
+  g_return_val_if_fail (width != NULL, FALSE);
+  g_return_val_if_fail (height != NULL, FALSE);
+
+  GST_LOG_OBJECT (v4l2object->dbg_obj,
+      "getting nearest size to %dx%d with format %" GST_FOURCC_FORMAT,
+      *width, *height, GST_FOURCC_ARGS (pixelformat));
+
+  memset (&fmt, 0, sizeof (struct v4l2_format));
+
+  /* get size delimiters */
+  memset (&fmt, 0, sizeof (fmt));
+  fmt.type = v4l2object->type;
+  fmt.fmt.pix.width = *width;
+  fmt.fmt.pix.height = *height;
+  fmt.fmt.pix.pixelformat = pixelformat;
+  fmt.fmt.pix.field = V4L2_FIELD_ANY;
+
+  if (gst_v4l2_object_try_fmt (v4l2object, &fmt) < 0)
+    goto error;
+
+  GST_LOG_OBJECT (v4l2object->dbg_obj,
+      "got nearest size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
+
+  *width = fmt.fmt.pix.width;
+  *height = fmt.fmt.pix.height;
+
+  if (!gst_v4l2_object_get_interlace_mode (fmt.fmt.pix.field, &interlace_mode)) {
+    GST_WARNING_OBJECT (v4l2object->dbg_obj,
+        "Unsupported field type for %" GST_FOURCC_FORMAT "@%ux%u: %u",
+        GST_FOURCC_ARGS (pixelformat), *width, *height, fmt.fmt.pix.field);
+    goto error;
+  }
+
+  ret = TRUE;
+
+error:
+  if (!ret) {
+    GST_WARNING_OBJECT (v4l2object->dbg_obj,
+        "Unable to try format: %s", g_strerror (errno));
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_v4l2_object_is_dmabuf_supported (GstV4l2Object * v4l2object)
+{
+  gboolean ret = TRUE;
+  struct v4l2_exportbuffer expbuf = {
+    .type = v4l2object->type,
+    .index = -1,
+    .plane = -1,
+    .flags = O_CLOEXEC | O_RDWR,
+  };
+
+  /* Expected to fail, but ENOTTY tells us that it is not implemented. */
+  v4l2object->ioctl (v4l2object->video_fd, VIDIOC_EXPBUF, &expbuf);
+  if (errno == ENOTTY)
+    ret = FALSE;
+
+  return ret;
+}
+
+static gboolean
+gst_v4l2_object_setup_pool (GstV4l2Object * v4l2object, GstCaps * caps)
+{
+  GstV4l2IOMode mode;
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "initializing the %s system",
+      V4L2_TYPE_IS_OUTPUT (v4l2object->type) ? "output" : "capture");
+
+  GST_V4L2_CHECK_OPEN (v4l2object);
+  GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
+
+  /* find transport */
+  mode = v4l2object->req_mode;
+
+  if (v4l2object->device_caps & V4L2_CAP_READWRITE) {
+    if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
+      mode = GST_V4L2_IO_RW;
+  } else if (v4l2object->req_mode == GST_V4L2_IO_RW)
+    goto method_not_supported;
+
+  if (v4l2object->device_caps & V4L2_CAP_STREAMING) {
+    if (v4l2object->req_mode == GST_V4L2_IO_AUTO) {
+      if (!V4L2_TYPE_IS_OUTPUT (v4l2object->type) &&
+          gst_v4l2_object_is_dmabuf_supported (v4l2object)) {
+        mode = GST_V4L2_IO_DMABUF;
+      } else {
+        mode = GST_V4L2_IO_MMAP;
+      }
+    }
+  } else if (v4l2object->req_mode == GST_V4L2_IO_MMAP)
+    goto method_not_supported;
+
+  /* if still no transport selected, error out */
+  if (mode == GST_V4L2_IO_AUTO)
+    goto no_supported_capture_method;
+
+  GST_INFO_OBJECT (v4l2object->dbg_obj, "accessing buffers via mode %d", mode);
+  v4l2object->mode = mode;
+
+  /* If min_buffers is not set, the driver either does not support the control or
+     it has not been asked yet via propose_allocation/decide_allocation. */
+  if (!v4l2object->min_buffers)
+    gst_v4l2_get_driver_min_buffers (v4l2object);
+
+  /* Map the buffers */
+  GST_LOG_OBJECT (v4l2object->dbg_obj, "initiating buffer pool");
+
+  if (!(v4l2object->pool = gst_v4l2_buffer_pool_new (v4l2object, caps)))
+    goto buffer_pool_new_failed;
+
+  GST_V4L2_SET_ACTIVE (v4l2object);
+
+  return TRUE;
+
+  /* ERRORS */
+buffer_pool_new_failed:
+  {
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
+        (_("Could not map buffers from device '%s'"),
+            v4l2object->videodev),
+        ("Failed to create buffer pool: %s", g_strerror (errno)));
+    return FALSE;
+  }
+method_not_supported:
+  {
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
+        (_("The driver of device '%s' does not support the IO method %d"),
+            v4l2object->videodev, mode), (NULL));
+    return FALSE;
+  }
+no_supported_capture_method:
+  {
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
+        (_("The driver of device '%s' does not support any known IO "
+                "method."), v4l2object->videodev), (NULL));
+    return FALSE;
+  }
+}
+
+static void
+gst_v4l2_object_set_stride (GstVideoInfo * info, GstVideoAlignment * align,
+    gint plane, gint stride)
+{
+  const GstVideoFormatInfo *finfo = info->finfo;
+
+  if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo)) {
+    gint x_tiles, y_tiles, ws, hs, tile_height, padded_height;
+
+
+    ws = GST_VIDEO_FORMAT_INFO_TILE_WS (finfo);
+    hs = GST_VIDEO_FORMAT_INFO_TILE_HS (finfo);
+    tile_height = 1 << hs;
+
+    padded_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, plane,
+        info->height + align->padding_top + align->padding_bottom);
+    padded_height = GST_ROUND_UP_N (padded_height, tile_height);
+
+    x_tiles = stride >> ws;
+    y_tiles = padded_height >> hs;
+    info->stride[plane] = GST_VIDEO_TILE_MAKE_STRIDE (x_tiles, y_tiles);
+  } else {
+    info->stride[plane] = stride;
+  }
+}
+
+static void
+gst_v4l2_object_extrapolate_info (GstV4l2Object * v4l2object,
+    GstVideoInfo * info, GstVideoAlignment * align, gint stride)
+{
+  const GstVideoFormatInfo *finfo = info->finfo;
+  gint i, estride, padded_height;
+  gsize offs = 0;
+
+  g_return_if_fail (v4l2object->n_v4l2_planes == 1);
+
+  padded_height = info->height + align->padding_top + align->padding_bottom;
+
+  for (i = 0; i < finfo->n_planes; i++) {
+    estride = gst_v4l2_object_extrapolate_stride (finfo, i, stride);
+
+    gst_v4l2_object_set_stride (info, align, i, estride);
+
+    info->offset[i] = offs;
+    offs += estride *
+        GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i, padded_height);
+
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj,
+        "Extrapolated for plane %d with base stride %d: "
+        "stride %d, offset %" G_GSIZE_FORMAT, i, stride, info->stride[i],
+        info->offset[i]);
+  }
+
+  /* Update the image size according the amount of data we are going to
+   * read/write. This workaround bugs in driver where the sizeimage provided
+   * by TRY/S_FMT represent the buffer length (maximum size) rather then the expected
+   * bytesused (buffer size). */
+  if (offs < info->size)
+    info->size = offs;
+}
+
+static void
+gst_v4l2_object_save_format (GstV4l2Object * v4l2object,
+    struct v4l2_fmtdesc *fmtdesc, struct v4l2_format *format,
+    GstVideoInfo * info, GstVideoAlignment * align)
+{
+  const GstVideoFormatInfo *finfo = info->finfo;
+  gboolean standard_stride = TRUE;
+  gint stride, pstride, padded_width, padded_height, i;
+
+  if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_ENCODED) {
+    v4l2object->n_v4l2_planes = 1;
+    info->size = format->fmt.pix.sizeimage;
+    goto store_info;
+  }
+
+  /* adjust right padding */
+  if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type))
+    stride = format->fmt.pix_mp.plane_fmt[0].bytesperline;
+  else
+    stride = format->fmt.pix.bytesperline;
+
+  pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (finfo, 0);
+  if (pstride) {
+    padded_width = stride / pstride;
+  } else {
+    /* pstride can be 0 for complex formats */
+    GST_WARNING_OBJECT (v4l2object->element,
+        "format %s has a pstride of 0, cannot compute padded with",
+        gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
+    padded_width = stride;
+  }
+
+  if (padded_width < format->fmt.pix.width)
+    GST_WARNING_OBJECT (v4l2object->dbg_obj,
+        "Driver bug detected, stride (%d) is too small for the width (%d)",
+        padded_width, format->fmt.pix.width);
+
+  align->padding_right = padded_width - info->width - align->padding_left;
+
+  /* adjust bottom padding */
+  padded_height = format->fmt.pix.height;
+
+  if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo)) {
+    guint hs, tile_height;
+
+    hs = GST_VIDEO_FORMAT_INFO_TILE_HS (finfo);
+    tile_height = 1 << hs;
+
+    padded_height = GST_ROUND_UP_N (padded_height, tile_height);
+  }
+
+  align->padding_bottom = padded_height - info->height - align->padding_top;
+
+  /* setup the strides and offset */
+  if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type)) {
+    struct v4l2_pix_format_mplane *pix_mp = &format->fmt.pix_mp;
+
+    /* figure out the frame layout */
+    v4l2object->n_v4l2_planes = MAX (1, pix_mp->num_planes);
+    info->size = 0;
+    for (i = 0; i < v4l2object->n_v4l2_planes; i++) {
+      stride = pix_mp->plane_fmt[i].bytesperline;
+
+      if (info->stride[i] != stride)
+        standard_stride = FALSE;
+
+      gst_v4l2_object_set_stride (info, align, i, stride);
+      info->offset[i] = info->size;
+      info->size += pix_mp->plane_fmt[i].sizeimage;
+    }
+
+    /* Extrapolate stride if planar format are being set in 1 v4l2 plane */
+    if (v4l2object->n_v4l2_planes < finfo->n_planes) {
+      stride = format->fmt.pix_mp.plane_fmt[0].bytesperline;
+      gst_v4l2_object_extrapolate_info (v4l2object, info, align, stride);
+    }
+  } else {
+    /* only one plane in non-MPLANE mode */
+    v4l2object->n_v4l2_planes = 1;
+    info->size = format->fmt.pix.sizeimage;
+    stride = format->fmt.pix.bytesperline;
+
+    if (info->stride[0] != stride)
+      standard_stride = FALSE;
+
+    gst_v4l2_object_extrapolate_info (v4l2object, info, align, stride);
+  }
+
+  /* adjust the offset to take into account left and top */
+  if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo)) {
+    if ((align->padding_left + align->padding_top) > 0)
+      GST_WARNING_OBJECT (v4l2object->dbg_obj,
+          "Left and top padding is not permitted for tiled formats");
+  } else {
+    for (i = 0; i < finfo->n_planes; i++) {
+      gint vedge, hedge;
+
+      /* FIXME we assume plane as component as this is true for all supported
+       * format we support. */
+
+      hedge = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, i, align->padding_left);
+      vedge = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i, align->padding_top);
+
+      info->offset[i] += (vedge * info->stride[i]) +
+          (hedge * GST_VIDEO_INFO_COMP_PSTRIDE (info, i));
+    }
+  }
+
+store_info:
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got sizeimage %" G_GSIZE_FORMAT,
+      info->size);
+
+  /* to avoid copies we need video meta if there is padding */
+  v4l2object->need_video_meta =
+      ((align->padding_top + align->padding_left + align->padding_right +
+          align->padding_bottom) != 0);
+
+  /* ... or if stride is non "standard" */
+  if (!standard_stride)
+    v4l2object->need_video_meta = TRUE;
+
+  /* ... or also video meta if we use multiple, non-contiguous, planes */
+  if (v4l2object->n_v4l2_planes > 1)
+    v4l2object->need_video_meta = TRUE;
+
+  v4l2object->info = *info;
+  v4l2object->align = *align;
+  v4l2object->format = *format;
+  v4l2object->fmtdesc = fmtdesc;
+
+  /* if we have a framerate pre-calculate duration */
+  if (info->fps_n > 0 && info->fps_d > 0) {
+    v4l2object->duration = gst_util_uint64_scale_int (GST_SECOND, info->fps_d,
+        info->fps_n);
+  } else {
+    v4l2object->duration = GST_CLOCK_TIME_NONE;
+  }
+}
+
+gint
+gst_v4l2_object_extrapolate_stride (const GstVideoFormatInfo * finfo,
+    gint plane, gint stride)
+{
+  gint estride;
+
+  switch (finfo->format) {
+    case GST_VIDEO_FORMAT_NV12:
+    case GST_VIDEO_FORMAT_NV12_64Z32:
+    case GST_VIDEO_FORMAT_NV21:
+    case GST_VIDEO_FORMAT_NV16:
+    case GST_VIDEO_FORMAT_NV61:
+    case GST_VIDEO_FORMAT_NV24:
+      estride = (plane == 0 ? 1 : 2) *
+          GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
+      break;
+    default:
+      estride = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
+      break;
+  }
+
+  return estride;
+}
+
+static gboolean
+gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
+    gboolean try_only, GstV4l2Error * error)
+{
+  gint fd = v4l2object->video_fd;
+  struct v4l2_format format;
+  struct v4l2_streamparm streamparm;
+  enum v4l2_field field;
+  guint32 pixelformat;
+  struct v4l2_fmtdesc *fmtdesc;
+  GstVideoInfo info;
+  GstVideoAlignment align;
+  gint width, height, fps_n, fps_d;
+  gint n_v4l_planes;
+  gint i = 0;
+  gboolean is_mplane;
+  enum v4l2_colorspace colorspace = 0;
+  enum v4l2_quantization range = 0;
+  enum v4l2_ycbcr_encoding matrix = 0;
+  enum v4l2_xfer_func transfer = 0;
+  GstStructure *s;
+
+  g_return_val_if_fail (!v4l2object->skip_try_fmt_probes ||
+      gst_caps_is_writable (caps), FALSE);
+
+  GST_V4L2_CHECK_OPEN (v4l2object);
+  if (!try_only)
+    GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
+
+  is_mplane = V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type);
+
+  gst_video_info_init (&info);
+  gst_video_alignment_reset (&align);
+
+  if (!gst_v4l2_object_get_caps_info (v4l2object, caps, &fmtdesc, &info))
+    goto invalid_caps;
+
+  pixelformat = fmtdesc->pixelformat;
+  width = GST_VIDEO_INFO_WIDTH (&info);
+  height = GST_VIDEO_INFO_HEIGHT (&info);
+  fps_n = GST_VIDEO_INFO_FPS_N (&info);
+  fps_d = GST_VIDEO_INFO_FPS_D (&info);
+
+  /* if encoded format (GST_VIDEO_INFO_N_PLANES return 0)
+   * or if contiguous is prefered */
+  n_v4l_planes = GST_VIDEO_INFO_N_PLANES (&info);
+  if (!n_v4l_planes || !v4l2object->prefered_non_contiguous)
+    n_v4l_planes = 1;
+
+  if (GST_VIDEO_INFO_IS_INTERLACED (&info)) {
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "interlaced video");
+    /* ideally we would differentiate between types of interlaced video
+     * but there is not sufficient information in the caps..
+     */
+    field = V4L2_FIELD_INTERLACED;
+  } else {
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "progressive video");
+    field = V4L2_FIELD_NONE;
+  }
+
+  if (V4L2_TYPE_IS_OUTPUT (v4l2object->type)) {
+    /* We first pick th main colorspace from the primaries */
+    switch (info.colorimetry.primaries) {
+      case GST_VIDEO_COLOR_PRIMARIES_BT709:
+        /* There is two colorspaces using these primaries, use the range to
+         * differentiate */
+        if (info.colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235)
+          colorspace = V4L2_COLORSPACE_REC709;
+        else
+          colorspace = V4L2_COLORSPACE_SRGB;
+        break;
+      case GST_VIDEO_COLOR_PRIMARIES_BT2020:
+        colorspace = V4L2_COLORSPACE_BT2020;
+        break;
+      case GST_VIDEO_COLOR_PRIMARIES_BT470M:
+        colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+        break;
+      case GST_VIDEO_COLOR_PRIMARIES_BT470BG:
+        colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+        break;
+      case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M:
+        colorspace = V4L2_COLORSPACE_SMPTE170M;
+        break;
+      case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M:
+        colorspace = V4L2_COLORSPACE_SMPTE240M;
+        break;
+
+      case GST_VIDEO_COLOR_PRIMARIES_FILM:
+      case GST_VIDEO_COLOR_PRIMARIES_UNKNOWN:
+        /* We don't know, we will guess */
+        break;
+
+      default:
+        GST_WARNING_OBJECT (v4l2object->dbg_obj,
+            "Unknown colorimetry primaries %d", info.colorimetry.primaries);
+        break;
+    }
+
+    switch (info.colorimetry.range) {
+      case GST_VIDEO_COLOR_RANGE_0_255:
+        range = V4L2_QUANTIZATION_FULL_RANGE;
+        break;
+      case GST_VIDEO_COLOR_RANGE_16_235:
+        range = V4L2_QUANTIZATION_LIM_RANGE;
+        break;
+      case GST_VIDEO_COLOR_RANGE_UNKNOWN:
+        /* We let the driver pick a default one */
+        break;
+      default:
+        GST_WARNING_OBJECT (v4l2object->dbg_obj,
+            "Unknown colorimetry range %d", info.colorimetry.range);
+        break;
+    }
+
+    switch (info.colorimetry.matrix) {
+      case GST_VIDEO_COLOR_MATRIX_RGB:
+        /* Unspecified, leave to default */
+        break;
+        /* FCC is about the same as BT601 with less digit */
+      case GST_VIDEO_COLOR_MATRIX_FCC:
+      case GST_VIDEO_COLOR_MATRIX_BT601:
+        matrix = V4L2_YCBCR_ENC_601;
+        break;
+      case GST_VIDEO_COLOR_MATRIX_BT709:
+        matrix = V4L2_YCBCR_ENC_709;
+        break;
+      case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
+        matrix = V4L2_YCBCR_ENC_SMPTE240M;
+        break;
+      case GST_VIDEO_COLOR_MATRIX_BT2020:
+        matrix = V4L2_YCBCR_ENC_BT2020;
+        break;
+      case GST_VIDEO_COLOR_MATRIX_UNKNOWN:
+        /* We let the driver pick a default one */
+        break;
+      default:
+        GST_WARNING_OBJECT (v4l2object->dbg_obj,
+            "Unknown colorimetry matrix %d", info.colorimetry.matrix);
+        break;
+    }
+
+    switch (info.colorimetry.transfer) {
+      case GST_VIDEO_TRANSFER_GAMMA18:
+      case GST_VIDEO_TRANSFER_GAMMA20:
+      case GST_VIDEO_TRANSFER_GAMMA22:
+      case GST_VIDEO_TRANSFER_GAMMA28:
+        GST_WARNING_OBJECT (v4l2object->dbg_obj,
+            "GAMMA 18, 20, 22, 28 transfer functions not supported");
+        /* fallthrough */
+      case GST_VIDEO_TRANSFER_GAMMA10:
+        transfer = V4L2_XFER_FUNC_NONE;
+        break;
+      case GST_VIDEO_TRANSFER_BT2020_12:
+      case GST_VIDEO_TRANSFER_BT709:
+        transfer = V4L2_XFER_FUNC_709;
+        break;
+      case GST_VIDEO_TRANSFER_SMPTE240M:
+        transfer = V4L2_XFER_FUNC_SMPTE240M;
+        break;
+      case GST_VIDEO_TRANSFER_SRGB:
+        transfer = V4L2_XFER_FUNC_SRGB;
+        break;
+      case GST_VIDEO_TRANSFER_LOG100:
+      case GST_VIDEO_TRANSFER_LOG316:
+        GST_WARNING_OBJECT (v4l2object->dbg_obj,
+            "LOG 100, 316 transfer functions not supported");
+        /* FIXME No known sensible default, maybe AdobeRGB ? */
+        break;
+      case GST_VIDEO_TRANSFER_UNKNOWN:
+        /* We let the driver pick a default one */
+        break;
+      default:
+        GST_WARNING_OBJECT (v4l2object->dbg_obj,
+            "Unknown colorimetry tranfer %d", info.colorimetry.transfer);
+        break;
+    }
+
+    if (colorspace == 0) {
+      /* Try to guess colorspace according to pixelformat and size */
+      if (GST_VIDEO_INFO_IS_YUV (&info)) {
+        /* SD streams likely use SMPTE170M and HD streams REC709 */
+        if (width <= 720 && height <= 576)
+          colorspace = V4L2_COLORSPACE_SMPTE170M;
+        else
+          colorspace = V4L2_COLORSPACE_REC709;
+      } else if (GST_VIDEO_INFO_IS_RGB (&info)) {
+        colorspace = V4L2_COLORSPACE_SRGB;
+        transfer = V4L2_XFER_FUNC_NONE;
+      }
+    }
+  }
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired format %dx%d, format "
+      "%" GST_FOURCC_FORMAT " stride: %d", width, height,
+      GST_FOURCC_ARGS (pixelformat), GST_VIDEO_INFO_PLANE_STRIDE (&info, 0));
+
+  memset (&format, 0x00, sizeof (struct v4l2_format));
+  format.type = v4l2object->type;
+
+  if (is_mplane) {
+    format.type = v4l2object->type;
+    format.fmt.pix_mp.pixelformat = pixelformat;
+    format.fmt.pix_mp.width = width;
+    format.fmt.pix_mp.height = height;
+    format.fmt.pix_mp.field = field;
+    format.fmt.pix_mp.num_planes = n_v4l_planes;
+
+    /* try to ask our prefered stride but it's not a failure if not
+     * accepted */
+    for (i = 0; i < n_v4l_planes; i++) {
+      gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, i);
+
+      if (GST_VIDEO_FORMAT_INFO_IS_TILED (info.finfo))
+        stride = GST_VIDEO_TILE_X_TILES (stride) <<
+            GST_VIDEO_FORMAT_INFO_TILE_WS (info.finfo);
+
+      format.fmt.pix_mp.plane_fmt[i].bytesperline = stride;
+    }
+
+    if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED)
+      format.fmt.pix_mp.plane_fmt[0].sizeimage = ENCODED_BUFFER_SIZE;
+  } else {
+    gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, 0);
+
+    format.type = v4l2object->type;
+
+    format.fmt.pix.width = width;
+    format.fmt.pix.height = height;
+    format.fmt.pix.pixelformat = pixelformat;
+    format.fmt.pix.field = field;
+
+    if (GST_VIDEO_FORMAT_INFO_IS_TILED (info.finfo))
+      stride = GST_VIDEO_TILE_X_TILES (stride) <<
+          GST_VIDEO_FORMAT_INFO_TILE_WS (info.finfo);
+
+    /* try to ask our prefered stride */
+    format.fmt.pix.bytesperline = stride;
+
+    if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED)
+      format.fmt.pix.sizeimage = ENCODED_BUFFER_SIZE;
+  }
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired format is %dx%d, format "
+      "%" GST_FOURCC_FORMAT ", nb planes %d", format.fmt.pix.width,
+      format.fmt.pix_mp.height,
+      GST_FOURCC_ARGS (format.fmt.pix.pixelformat),
+      is_mplane ? format.fmt.pix_mp.num_planes : 1);
+
+#ifndef GST_DISABLE_GST_DEBUG
+  if (is_mplane) {
+    for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
+      GST_DEBUG_OBJECT (v4l2object->dbg_obj, "  stride %d",
+          format.fmt.pix_mp.plane_fmt[i].bytesperline);
+  } else {
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "  stride %d",
+        format.fmt.pix.bytesperline);
+  }
+#endif
+
+  if (V4L2_TYPE_IS_OUTPUT (v4l2object->type)) {
+    if (is_mplane) {
+      format.fmt.pix_mp.colorspace = colorspace;
+      format.fmt.pix_mp.quantization = range;
+      format.fmt.pix_mp.ycbcr_enc = matrix;
+      format.fmt.pix_mp.xfer_func = transfer;
+    } else {
+      format.fmt.pix.colorspace = colorspace;
+      format.fmt.pix.quantization = range;
+      format.fmt.pix.ycbcr_enc = matrix;
+      format.fmt.pix.xfer_func = transfer;
+    }
+
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired colorspace is %d:%d:%d:%d",
+        colorspace, range, matrix, transfer);
+  }
+
+  if (try_only) {
+    if (v4l2object->ioctl (fd, VIDIOC_TRY_FMT, &format) < 0)
+      goto try_fmt_failed;
+  } else {
+    if (v4l2object->ioctl (fd, VIDIOC_S_FMT, &format) < 0)
+      goto set_fmt_failed;
+  }
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got format of %dx%d, format "
+      "%" GST_FOURCC_FORMAT ", nb planes %d, colorspace %d",
+      format.fmt.pix.width, format.fmt.pix_mp.height,
+      GST_FOURCC_ARGS (format.fmt.pix.pixelformat),
+      is_mplane ? format.fmt.pix_mp.num_planes : 1,
+      is_mplane ? format.fmt.pix_mp.colorspace : format.fmt.pix.colorspace);
+
+#ifndef GST_DISABLE_GST_DEBUG
+  if (is_mplane) {
+    for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
+      GST_DEBUG_OBJECT (v4l2object->dbg_obj, "  stride %d, sizeimage %d",
+          format.fmt.pix_mp.plane_fmt[i].bytesperline,
+          format.fmt.pix_mp.plane_fmt[i].sizeimage);
+  } else {
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "  stride %d, sizeimage %d",
+        format.fmt.pix.bytesperline, format.fmt.pix.sizeimage);
+  }
+#endif
+
+  if (format.fmt.pix.pixelformat != pixelformat)
+    goto invalid_pixelformat;
+
+  /* Only negotiate size with raw data.
+   * For some codecs the dimensions are *not* in the bitstream, IIRC VC1
+   * in ASF mode for example, there is also not reason for a driver to
+   * change the size. */
+  if (info.finfo->format != GST_VIDEO_FORMAT_ENCODED) {
+    /* We can crop larger images */
+    if (format.fmt.pix.width < width || format.fmt.pix.height < height)
+      goto invalid_dimensions;
+
+    /* Note, this will be adjusted if upstream has non-centered cropping. */
+    align.padding_top = 0;
+    align.padding_bottom = format.fmt.pix.height - height;
+    align.padding_left = 0;
+    align.padding_right = format.fmt.pix.width - width;
+  }
+
+  if (is_mplane && format.fmt.pix_mp.num_planes != n_v4l_planes)
+    goto invalid_planes;
+
+  if ((is_mplane && format.fmt.pix_mp.field != field)
+      || format.fmt.pix.field != field)
+    goto invalid_field;
+
+  gst_v4l2_object_get_colorspace (&format, &info.colorimetry);
+
+  s = gst_caps_get_structure (caps, 0);
+  if (gst_structure_has_field (s, "colorimetry")) {
+    GstVideoColorimetry ci;
+    if (!gst_video_colorimetry_from_string (&ci,
+            gst_structure_get_string (s, "colorimetry"))
+        || !gst_video_colorimetry_is_equal (&ci, &info.colorimetry))
+      goto invalid_colorimetry;
+  }
+
+  /* In case we have skipped the try_fmt probes, we'll need to set the
+   * colorimetry and interlace-mode back into the caps. */
+  if (v4l2object->skip_try_fmt_probes) {
+    if (!gst_structure_has_field (s, "colorimetry")) {
+      gchar *str = gst_video_colorimetry_to_string (&info.colorimetry);
+      gst_structure_set (s, "colorimetry", G_TYPE_STRING, str, NULL);
+      g_free (str);
+    }
+
+    if (!gst_structure_has_field (s, "interlace-mode"))
+      gst_structure_set (s, "interlace-mode", G_TYPE_STRING,
+          gst_video_interlace_mode_to_string (info.interlace_mode), NULL);
+  }
+
+  if (try_only)                 /* good enough for trying only */
+    return TRUE;
+
+  if (GST_VIDEO_INFO_HAS_ALPHA (&info)) {
+    struct v4l2_control ctl = { 0, };
+    ctl.id = V4L2_CID_ALPHA_COMPONENT;
+    ctl.value = 0xff;
+
+    if (v4l2object->ioctl (fd, VIDIOC_S_CTRL, &ctl) < 0)
+      GST_WARNING_OBJECT (v4l2object->dbg_obj,
+          "Failed to set alpha component value");
+  }
+
+  /* Is there a reason we require the caller to always specify a framerate? */
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired framerate: %u/%u", fps_n,
+      fps_d);
+
+  memset (&streamparm, 0x00, sizeof (struct v4l2_streamparm));
+  streamparm.type = v4l2object->type;
+
+  if (v4l2object->ioctl (fd, VIDIOC_G_PARM, &streamparm) < 0)
+    goto get_parm_failed;
+
+  if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
+      || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+    GST_VIDEO_INFO_FPS_N (&info) =
+        streamparm.parm.capture.timeperframe.denominator;
+    GST_VIDEO_INFO_FPS_D (&info) =
+        streamparm.parm.capture.timeperframe.numerator;
+
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got capture framerate: %u/%u",
+        streamparm.parm.capture.timeperframe.denominator,
+        streamparm.parm.capture.timeperframe.numerator);
+
+    /* We used to skip frame rate setup if the camera was already setup
+     * with the requested frame rate. This breaks some cameras though,
+     * causing them to not output data (several models of Thinkpad cameras
+     * have this problem at least).
+     * So, don't skip. */
+    GST_LOG_OBJECT (v4l2object->dbg_obj, "Setting capture framerate to %u/%u",
+        fps_n, fps_d);
+    /* We want to change the frame rate, so check whether we can. Some cheap USB
+     * cameras don't have the capability */
+    if ((streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0) {
+      GST_DEBUG_OBJECT (v4l2object->dbg_obj,
+          "Not setting capture framerate (not supported)");
+      goto done;
+    }
+
+    /* Note: V4L2 wants the frame interval, we have the frame rate */
+    streamparm.parm.capture.timeperframe.numerator = fps_d;
+    streamparm.parm.capture.timeperframe.denominator = fps_n;
+
+    /* some cheap USB cam's won't accept any change */
+    if (v4l2object->ioctl (fd, VIDIOC_S_PARM, &streamparm) < 0)
+      goto set_parm_failed;
+
+    if (streamparm.parm.capture.timeperframe.numerator > 0 &&
+        streamparm.parm.capture.timeperframe.denominator > 0) {
+      /* get new values */
+      fps_d = streamparm.parm.capture.timeperframe.numerator;
+      fps_n = streamparm.parm.capture.timeperframe.denominator;
+
+      GST_INFO_OBJECT (v4l2object->dbg_obj, "Set capture framerate to %u/%u",
+          fps_n, fps_d);
+    } else {
+      /* fix v4l2 capture driver to provide framerate values */
+      GST_WARNING_OBJECT (v4l2object->dbg_obj,
+          "Reuse caps framerate %u/%u - fix v4l2 capture driver", fps_n, fps_d);
+    }
+
+    GST_VIDEO_INFO_FPS_N (&info) = fps_n;
+    GST_VIDEO_INFO_FPS_D (&info) = fps_d;
+  } else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT
+      || v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+    GST_VIDEO_INFO_FPS_N (&info) =
+        streamparm.parm.output.timeperframe.denominator;
+    GST_VIDEO_INFO_FPS_D (&info) =
+        streamparm.parm.output.timeperframe.numerator;
+
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got output framerate: %u/%u",
+        streamparm.parm.output.timeperframe.denominator,
+        streamparm.parm.output.timeperframe.numerator);
+
+    GST_LOG_OBJECT (v4l2object->dbg_obj, "Setting output framerate to %u/%u",
+        fps_n, fps_d);
+    if ((streamparm.parm.output.capability & V4L2_CAP_TIMEPERFRAME) == 0) {
+      GST_DEBUG_OBJECT (v4l2object->dbg_obj,
+          "Not setting output framerate (not supported)");
+      goto done;
+    }
+
+    /* Note: V4L2 wants the frame interval, we have the frame rate */
+    streamparm.parm.output.timeperframe.numerator = fps_d;
+    streamparm.parm.output.timeperframe.denominator = fps_n;
+
+    if (v4l2object->ioctl (fd, VIDIOC_S_PARM, &streamparm) < 0)
+      goto set_parm_failed;
+
+    if (streamparm.parm.output.timeperframe.numerator > 0 &&
+        streamparm.parm.output.timeperframe.denominator > 0) {
+      /* get new values */
+      fps_d = streamparm.parm.output.timeperframe.numerator;
+      fps_n = streamparm.parm.output.timeperframe.denominator;
+
+      GST_INFO_OBJECT (v4l2object->dbg_obj, "Set output framerate to %u/%u",
+          fps_n, fps_d);
+    } else {
+      /* fix v4l2 output driver to provide framerate values */
+      GST_WARNING_OBJECT (v4l2object->dbg_obj,
+          "Reuse caps framerate %u/%u - fix v4l2 output driver", fps_n, fps_d);
+    }
+
+    GST_VIDEO_INFO_FPS_N (&info) = fps_n;
+    GST_VIDEO_INFO_FPS_D (&info) = fps_d;
+  }
+
+done:
+  /* add boolean return, so we can fail on drivers bugs */
+  gst_v4l2_object_save_format (v4l2object, fmtdesc, &format, &info, &align);
+
+  /* now configure the pool */
+  if (!gst_v4l2_object_setup_pool (v4l2object, caps))
+    goto pool_failed;
+
+  return TRUE;
+
+  /* ERRORS */
+invalid_caps:
+  {
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "can't parse caps %" GST_PTR_FORMAT,
+        caps);
+    return FALSE;
+  }
+try_fmt_failed:
+  {
+    if (errno == EINVAL) {
+      GST_V4L2_ERROR (error, RESOURCE, SETTINGS,
+          (_("Device '%s' has no supported format"), v4l2object->videodev),
+          ("Call to TRY_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
+              GST_FOURCC_ARGS (pixelformat), width, height,
+              g_strerror (errno)));
+    } else {
+      GST_V4L2_ERROR (error, RESOURCE, FAILED,
+          (_("Device '%s' failed during initialization"),
+              v4l2object->videodev),
+          ("Call to TRY_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
+              GST_FOURCC_ARGS (pixelformat), width, height,
+              g_strerror (errno)));
+    }
+    return FALSE;
+  }
+set_fmt_failed:
+  {
+    if (errno == EBUSY) {
+      GST_V4L2_ERROR (error, RESOURCE, BUSY,
+          (_("Device '%s' is busy"), v4l2object->videodev),
+          ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
+              GST_FOURCC_ARGS (pixelformat), width, height,
+              g_strerror (errno)));
+    } else if (errno == EINVAL) {
+      GST_V4L2_ERROR (error, RESOURCE, SETTINGS,
+          (_("Device '%s' has no supported format"), v4l2object->videodev),
+          ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
+              GST_FOURCC_ARGS (pixelformat), width, height,
+              g_strerror (errno)));
+    } else {
+      GST_V4L2_ERROR (error, RESOURCE, FAILED,
+          (_("Device '%s' failed during initialization"),
+              v4l2object->videodev),
+          ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
+              GST_FOURCC_ARGS (pixelformat), width, height,
+              g_strerror (errno)));
+    }
+    return FALSE;
+  }
+invalid_dimensions:
+  {
+    GST_V4L2_ERROR (error, RESOURCE, SETTINGS,
+        (_("Device '%s' cannot capture at %dx%d"),
+            v4l2object->videodev, width, height),
+        ("Tried to capture at %dx%d, but device returned size %dx%d",
+            width, height, format.fmt.pix.width, format.fmt.pix.height));
+    return FALSE;
+  }
+invalid_pixelformat:
+  {
+    GST_V4L2_ERROR (error, RESOURCE, SETTINGS,
+        (_("Device '%s' cannot capture in the specified format"),
+            v4l2object->videodev),
+        ("Tried to capture in %" GST_FOURCC_FORMAT
+            ", but device returned format" " %" GST_FOURCC_FORMAT,
+            GST_FOURCC_ARGS (pixelformat),
+            GST_FOURCC_ARGS (format.fmt.pix.pixelformat)));
+    return FALSE;
+  }
+invalid_planes:
+  {
+    GST_V4L2_ERROR (error, RESOURCE, SETTINGS,
+        (_("Device '%s' does support non-contiguous planes"),
+            v4l2object->videodev),
+        ("Device wants %d planes", format.fmt.pix_mp.num_planes));
+    return FALSE;
+  }
+invalid_field:
+  {
+    enum v4l2_field wanted_field;
+
+    if (is_mplane)
+      wanted_field = format.fmt.pix_mp.field;
+    else
+      wanted_field = format.fmt.pix.field;
+
+    GST_V4L2_ERROR (error, RESOURCE, SETTINGS,
+        (_("Device '%s' does not support %s interlacing"),
+            v4l2object->videodev,
+            field == V4L2_FIELD_NONE ? "progressive" : "interleaved"),
+        ("Device wants %s interlacing",
+            wanted_field == V4L2_FIELD_NONE ? "progressive" : "interleaved"));
+    return FALSE;
+  }
+invalid_colorimetry:
+  {
+    gchar *wanted_colorimetry;
+
+    wanted_colorimetry = gst_video_colorimetry_to_string (&info.colorimetry);
+
+    GST_V4L2_ERROR (error, RESOURCE, SETTINGS,
+        (_("Device '%s' does not support %s colorimetry"),
+            v4l2object->videodev, gst_structure_get_string (s, "colorimetry")),
+        ("Device wants %s colorimetry", wanted_colorimetry));
+
+    g_free (wanted_colorimetry);
+    return FALSE;
+  }
+get_parm_failed:
+  {
+    /* it's possible that this call is not supported */
+    if (errno != EINVAL && errno != ENOTTY) {
+      GST_V4L2_ERROR (error, RESOURCE, SETTINGS,
+          (_("Could not get parameters on device '%s'"),
+              v4l2object->videodev), GST_ERROR_SYSTEM);
+    }
+    goto done;
+  }
+set_parm_failed:
+  {
+    GST_V4L2_ERROR (error, RESOURCE, SETTINGS,
+        (_("Video device did not accept new frame rate setting.")),
+        GST_ERROR_SYSTEM);
+    goto done;
+  }
+pool_failed:
+  {
+    /* setup_pool already send the error */
+    return FALSE;
+  }
+}
+
+gboolean
+gst_v4l2_object_set_format (GstV4l2Object * v4l2object, GstCaps * caps,
+    GstV4l2Error * error)
+{
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Setting format to %" GST_PTR_FORMAT,
+      caps);
+  return gst_v4l2_object_set_format_full (v4l2object, caps, FALSE, error);
+}
+
+gboolean
+gst_v4l2_object_try_format (GstV4l2Object * v4l2object, GstCaps * caps,
+    GstV4l2Error * error)
+{
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Trying format %" GST_PTR_FORMAT,
+      caps);
+  return gst_v4l2_object_set_format_full (v4l2object, caps, TRUE, error);
+}
+
+/**
+ * gst_v4l2_object_acquire_format:
+ * @v4l2object the object
+ * @info a GstVideoInfo to be filled
+ *
+ * Acquire the driver choosen format. This is useful in decoder or encoder elements where
+ * the output format is choosen by the HW.
+ *
+ * Returns: %TRUE on success, %FALSE on failure.
+ */
+gboolean
+gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, GstVideoInfo * info)
+{
+  struct v4l2_fmtdesc *fmtdesc;
+  struct v4l2_format fmt;
+  struct v4l2_crop crop;
+  struct v4l2_selection sel;
+  struct v4l2_rect *r = NULL;
+  GstVideoFormat format;
+  guint width, height;
+  GstVideoAlignment align;
+
+  gst_video_info_init (info);
+  gst_video_alignment_reset (&align);
+
+  memset (&fmt, 0x00, sizeof (struct v4l2_format));
+  fmt.type = v4l2object->type;
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_FMT, &fmt) < 0)
+    goto get_fmt_failed;
+
+  fmtdesc = gst_v4l2_object_get_format_from_fourcc (v4l2object,
+      fmt.fmt.pix.pixelformat);
+  if (fmtdesc == NULL)
+    goto unsupported_format;
+
+  /* No need to care about mplane, the four first params are the same */
+  format = gst_v4l2_object_v4l2fourcc_to_video_format (fmt.fmt.pix.pixelformat);
+
+  /* fails if we do no translate the fmt.pix.pixelformat to GstVideoFormat */
+  if (format == GST_VIDEO_FORMAT_UNKNOWN)
+    goto unsupported_format;
+
+  if (fmt.fmt.pix.width == 0 || fmt.fmt.pix.height == 0)
+    goto invalid_dimensions;
+
+  width = fmt.fmt.pix.width;
+  height = fmt.fmt.pix.height;
+
+  /* Use the default compose rectangle */
+  memset (&sel, 0, sizeof (struct v4l2_selection));
+  sel.type = v4l2object->type;
+  sel.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_SELECTION, &sel) >= 0) {
+    r = &sel.r;
+  } else {
+    /* For ancient kernels, fall back to G_CROP */
+    memset (&crop, 0, sizeof (struct v4l2_crop));
+    crop.type = v4l2object->type;
+    if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CROP, &crop) >= 0)
+      r = &crop.c;
+  }
+  if (r) {
+    align.padding_left = r->left;
+    align.padding_top = r->top;
+    align.padding_right = width - r->width - r->left;
+    align.padding_bottom = height - r->height - r->top;
+    width = r->width;
+    height = r->height;
+  }
+
+  gst_video_info_set_format (info, format, width, height);
+
+  switch (fmt.fmt.pix.field) {
+    case V4L2_FIELD_ANY:
+    case V4L2_FIELD_NONE:
+      info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
+      break;
+    case V4L2_FIELD_INTERLACED:
+    case V4L2_FIELD_INTERLACED_TB:
+    case V4L2_FIELD_INTERLACED_BT:
+      info->interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
+      break;
+    default:
+      goto unsupported_field;
+  }
+
+  gst_v4l2_object_get_colorspace (&fmt, &info->colorimetry);
+
+  gst_v4l2_object_save_format (v4l2object, fmtdesc, &fmt, info, &align);
+
+  /* Shall we setup the pool ? */
+
+  return TRUE;
+
+get_fmt_failed:
+  {
+    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Video device did not provide output format.")), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+invalid_dimensions:
+  {
+    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Video device returned invalid dimensions.")),
+        ("Expected non 0 dimensions, got %dx%d", fmt.fmt.pix.width,
+            fmt.fmt.pix.height));
+    return FALSE;
+  }
+unsupported_field:
+  {
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Video device uses an unsupported interlacing method.")),
+        ("V4L2 field type %d not supported", fmt.fmt.pix.field));
+    return FALSE;
+  }
+unsupported_format:
+  {
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Video device uses an unsupported pixel format.")),
+        ("V4L2 format %" GST_FOURCC_FORMAT " not supported",
+            GST_FOURCC_ARGS (fmt.fmt.pix.pixelformat)));
+    return FALSE;
+  }
+}
+
+gboolean
+gst_v4l2_object_set_crop (GstV4l2Object * obj)
+{
+  struct v4l2_crop crop = { 0 };
+
+  crop.type = obj->type;
+  crop.c.left = obj->align.padding_left;
+  crop.c.top = obj->align.padding_top;
+  crop.c.width = obj->info.width;
+  crop.c.height = obj->info.height;
+
+  if (obj->align.padding_left + obj->align.padding_top +
+      obj->align.padding_right + obj->align.padding_bottom == 0) {
+    GST_DEBUG_OBJECT (obj->dbg_obj, "no cropping needed");
+    return TRUE;
+  }
+
+  GST_DEBUG_OBJECT (obj->dbg_obj,
+      "Desired cropping left %u, top %u, size %ux%u", crop.c.left, crop.c.top,
+      crop.c.width, crop.c.height);
+
+  if (obj->ioctl (obj->video_fd, VIDIOC_S_CROP, &crop) < 0) {
+    GST_WARNING_OBJECT (obj->dbg_obj, "VIDIOC_S_CROP failed");
+    return FALSE;
+  }
+
+  if (obj->ioctl (obj->video_fd, VIDIOC_G_CROP, &crop) < 0) {
+    GST_WARNING_OBJECT (obj->dbg_obj, "VIDIOC_G_CROP failed");
+    return FALSE;
+  }
+
+  GST_DEBUG_OBJECT (obj->dbg_obj,
+      "Got cropping left %u, top %u, size %ux%u", crop.c.left, crop.c.top,
+      crop.c.width, crop.c.height);
+
+  return TRUE;
+}
+
+gboolean
+gst_v4l2_object_caps_equal (GstV4l2Object * v4l2object, GstCaps * caps)
+{
+  GstStructure *config;
+  GstCaps *oldcaps;
+  gboolean ret;
+
+  if (!v4l2object->pool)
+    return FALSE;
+
+  config = gst_buffer_pool_get_config (v4l2object->pool);
+  gst_buffer_pool_config_get_params (config, &oldcaps, NULL, NULL, NULL);
+
+  ret = oldcaps && gst_caps_is_equal (caps, oldcaps);
+
+  gst_structure_free (config);
+
+  return ret;
+}
+
+gboolean
+gst_v4l2_object_unlock (GstV4l2Object * v4l2object)
+{
+  gboolean ret = TRUE;
+
+  GST_LOG_OBJECT (v4l2object->dbg_obj, "start flushing");
+
+  if (v4l2object->pool && gst_buffer_pool_is_active (v4l2object->pool))
+    gst_buffer_pool_set_flushing (v4l2object->pool, TRUE);
+
+  return ret;
+}
+
+gboolean
+gst_v4l2_object_unlock_stop (GstV4l2Object * v4l2object)
+{
+  gboolean ret = TRUE;
+
+  GST_LOG_OBJECT (v4l2object->dbg_obj, "stop flushing");
+
+  if (v4l2object->pool && gst_buffer_pool_is_active (v4l2object->pool))
+    gst_buffer_pool_set_flushing (v4l2object->pool, FALSE);
+
+  return ret;
+}
+
+gboolean
+gst_v4l2_object_stop (GstV4l2Object * v4l2object)
+{
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "stopping");
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    goto done;
+  if (!GST_V4L2_IS_ACTIVE (v4l2object))
+    goto done;
+
+  if (v4l2object->pool) {
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "deactivating pool");
+    gst_buffer_pool_set_active (v4l2object->pool, FALSE);
+    gst_object_unref (v4l2object->pool);
+    v4l2object->pool = NULL;
+  }
+
+  GST_V4L2_SET_INACTIVE (v4l2object);
+
+done:
+  return TRUE;
+}
+
+GstCaps *
+gst_v4l2_object_probe_caps (GstV4l2Object * v4l2object, GstCaps * filter)
+{
+  GstCaps *ret;
+  GSList *walk;
+  GSList *formats;
+
+  formats = gst_v4l2_object_get_format_list (v4l2object);
+
+  ret = gst_caps_new_empty ();
+
+  if (v4l2object->keep_aspect && !v4l2object->par) {
+    struct v4l2_cropcap cropcap;
+
+    memset (&cropcap, 0, sizeof (cropcap));
+
+    cropcap.type = v4l2object->type;
+    if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_CROPCAP, &cropcap) < 0) {
+      if (errno != ENOTTY)
+        GST_WARNING_OBJECT (v4l2object->dbg_obj,
+            "Failed to probe pixel aspect ratio with VIDIOC_CROPCAP: %s",
+            g_strerror (errno));
+    } else {
+      v4l2object->par = g_new0 (GValue, 1);
+      g_value_init (v4l2object->par, GST_TYPE_FRACTION);
+      gst_value_set_fraction (v4l2object->par, cropcap.pixelaspect.numerator,
+          cropcap.pixelaspect.denominator);
+    }
+  }
+
+  for (walk = formats; walk; walk = walk->next) {
+    struct v4l2_fmtdesc *format;
+    GstStructure *template;
+    GstCaps *tmp;
+
+    format = (struct v4l2_fmtdesc *) walk->data;
+
+    template = gst_v4l2_object_v4l2fourcc_to_bare_struct (format->pixelformat);
+
+    if (!template) {
+      GST_DEBUG_OBJECT (v4l2object->dbg_obj,
+          "unknown format %" GST_FOURCC_FORMAT,
+          GST_FOURCC_ARGS (format->pixelformat));
+      continue;
+    }
+
+    /* If we have a filter, check if we need to probe this format or not */
+    if (filter) {
+      GstCaps *format_caps = gst_caps_new_empty ();
+
+      gst_caps_append_structure (format_caps, gst_structure_copy (template));
+
+      if (!gst_caps_can_intersect (format_caps, filter)) {
+        gst_caps_unref (format_caps);
+        gst_structure_free (template);
+        continue;
+      }
+
+      gst_caps_unref (format_caps);
+    }
+
+    tmp = gst_v4l2_object_probe_caps_for_format (v4l2object,
+        format->pixelformat, template);
+    if (tmp)
+      gst_caps_append (ret, tmp);
+
+    gst_structure_free (template);
+  }
+
+  if (filter) {
+    GstCaps *tmp;
+
+    tmp = ret;
+    ret = gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (tmp);
+  }
+
+  GST_INFO_OBJECT (v4l2object->dbg_obj, "probed caps: %" GST_PTR_FORMAT, ret);
+
+  return ret;
+}
+
+GstCaps *
+gst_v4l2_object_get_caps (GstV4l2Object * v4l2object, GstCaps * filter)
+{
+  GstCaps *ret;
+
+  if (v4l2object->probed_caps == NULL)
+    v4l2object->probed_caps = gst_v4l2_object_probe_caps (v4l2object, NULL);
+
+  if (filter) {
+    ret = gst_caps_intersect_full (filter, v4l2object->probed_caps,
+        GST_CAPS_INTERSECT_FIRST);
+  } else {
+    ret = gst_caps_ref (v4l2object->probed_caps);
+  }
+
+  return ret;
+}
+
+gboolean
+gst_v4l2_object_decide_allocation (GstV4l2Object * obj, GstQuery * query)
+{
+  GstCaps *caps;
+  GstBufferPool *pool = NULL, *other_pool = NULL;
+  GstStructure *config;
+  guint size, min, max, own_min = 0;
+  gboolean update;
+  gboolean has_video_meta;
+  gboolean can_share_own_pool, pushing_from_our_pool = FALSE;
+  GstAllocator *allocator = NULL;
+  GstAllocationParams params = { 0 };
+
+  GST_DEBUG_OBJECT (obj->dbg_obj, "decide allocation");
+
+  g_return_val_if_fail (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+      obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, FALSE);
+
+  gst_query_parse_allocation (query, &caps, NULL);
+
+  if (obj->pool == NULL) {
+    if (!gst_v4l2_object_setup_pool (obj, caps))
+      goto pool_failed;
+  }
+
+  if (gst_query_get_n_allocation_params (query) > 0)
+    gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
+
+  if (gst_query_get_n_allocation_pools (query) > 0) {
+    gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
+    update = TRUE;
+  } else {
+    pool = NULL;
+    min = max = 0;
+    size = 0;
+    update = FALSE;
+  }
+
+  GST_DEBUG_OBJECT (obj->dbg_obj, "allocation: size:%u min:%u max:%u pool:%"
+      GST_PTR_FORMAT, size, min, max, pool);
+
+  has_video_meta =
+      gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
+
+  can_share_own_pool = (has_video_meta || !obj->need_video_meta);
+
+  gst_v4l2_get_driver_min_buffers (obj);
+  /* We can't share our own pool, if it exceed V4L2 capacity */
+  if (min + obj->min_buffers + 1 > VIDEO_MAX_FRAME)
+    can_share_own_pool = FALSE;
+
+  /* select a pool */
+  switch (obj->mode) {
+    case GST_V4L2_IO_RW:
+      if (pool) {
+        /* in READ/WRITE mode, prefer a downstream pool because our own pool
+         * doesn't help much, we have to write to it as well */
+        GST_DEBUG_OBJECT (obj->dbg_obj,
+            "read/write mode: using downstream pool");
+        /* use the bigest size, when we use our own pool we can't really do any
+         * other size than what the hardware gives us but for downstream pools
+         * we can try */
+        size = MAX (size, obj->info.size);
+      } else if (can_share_own_pool) {
+        /* no downstream pool, use our own then */
+        GST_DEBUG_OBJECT (obj->dbg_obj,
+            "read/write mode: no downstream pool, using our own");
+        pool = gst_object_ref (obj->pool);
+        size = obj->info.size;
+        pushing_from_our_pool = TRUE;
+      }
+      break;
+
+    case GST_V4L2_IO_USERPTR:
+    case GST_V4L2_IO_DMABUF_IMPORT:
+      /* in importing mode, prefer our own pool, and pass the other pool to
+       * our own, so it can serve itself */
+      if (pool == NULL)
+        goto no_downstream_pool;
+      gst_v4l2_buffer_pool_set_other_pool (GST_V4L2_BUFFER_POOL (obj->pool),
+          pool);
+      other_pool = pool;
+      gst_object_unref (pool);
+      pool = gst_object_ref (obj->pool);
+      size = obj->info.size;
+      break;
+
+    case GST_V4L2_IO_MMAP:
+    case GST_V4L2_IO_DMABUF:
+      /* in streaming mode, prefer our own pool */
+      /* Check if we can use it ... */
+      if (can_share_own_pool) {
+        if (pool)
+          gst_object_unref (pool);
+        pool = gst_object_ref (obj->pool);
+        size = obj->info.size;
+        GST_DEBUG_OBJECT (obj->dbg_obj,
+            "streaming mode: using our own pool %" GST_PTR_FORMAT, pool);
+        pushing_from_our_pool = TRUE;
+      } else if (pool) {
+        GST_DEBUG_OBJECT (obj->dbg_obj,
+            "streaming mode: copying to downstream pool %" GST_PTR_FORMAT,
+            pool);
+      } else {
+        GST_DEBUG_OBJECT (obj->dbg_obj,
+            "streaming mode: no usable pool, copying to generic pool");
+        size = MAX (size, obj->info.size);
+      }
+      break;
+    case GST_V4L2_IO_AUTO:
+    default:
+      GST_WARNING_OBJECT (obj->dbg_obj, "unhandled mode");
+      break;
+  }
+
+  if (size == 0)
+    goto no_size;
+
+  /* If pushing from our own pool, configure it with queried minimum,
+   * otherwise use the minimum required */
+  if (pushing_from_our_pool) {
+    /* When pushing from our own pool, we need what downstream one, to be able
+     * to fill the pipeline, the minimum required to decoder according to the
+     * driver and 2 more, so we don't endup up with everything downstream or
+     * held by the decoder. We account 2 buffers for v4l2 so when one is being
+     * pushed downstream the other one can already be queued for the next
+     * frame. */
+    own_min = min + obj->min_buffers + 2;
+
+    /* If no allocation parameters where provided, allow for a little more
+     * buffers and enable copy threshold */
+    if (!update) {
+      own_min += 2;
+      gst_v4l2_buffer_pool_copy_at_threshold (GST_V4L2_BUFFER_POOL (pool),
+          TRUE);
+    } else {
+      gst_v4l2_buffer_pool_copy_at_threshold (GST_V4L2_BUFFER_POOL (pool),
+          FALSE);
+    }
+
+  } else {
+    /* In this case we'll have to configure two buffer pool. For our buffer
+     * pool, we'll need what the driver one, and one more, so we can dequeu */
+    own_min = obj->min_buffers + 1;
+    own_min = MAX (own_min, GST_V4L2_MIN_BUFFERS);
+
+    /* for the downstream pool, we keep what downstream wants, though ensure
+     * at least a minimum if downstream didn't suggest anything (we are
+     * expecting the base class to create a default one for the context) */
+    min = MAX (min, GST_V4L2_MIN_BUFFERS);
+
+    /* To import we need the other pool to hold at least own_min */
+    if (obj->pool == pool)
+      min += own_min;
+  }
+
+  /* Request a bigger max, if one was suggested but it's too small */
+  if (max != 0)
+    max = MAX (min, max);
+
+  /* First step, configure our own pool */
+  config = gst_buffer_pool_get_config (obj->pool);
+
+  if (obj->need_video_meta || has_video_meta) {
+    GST_DEBUG_OBJECT (obj->dbg_obj, "activate Video Meta");
+    gst_buffer_pool_config_add_option (config,
+        GST_BUFFER_POOL_OPTION_VIDEO_META);
+  }
+
+  gst_buffer_pool_config_set_allocator (config, allocator, &params);
+  gst_buffer_pool_config_set_params (config, caps, size, own_min, 0);
+
+  GST_DEBUG_OBJECT (obj->dbg_obj, "setting own pool config to %"
+      GST_PTR_FORMAT, config);
+
+  /* Our pool often need to adjust the value */
+  if (!gst_buffer_pool_set_config (obj->pool, config)) {
+    config = gst_buffer_pool_get_config (obj->pool);
+
+    GST_DEBUG_OBJECT (obj->dbg_obj, "own pool config changed to %"
+        GST_PTR_FORMAT, config);
+
+    /* our pool will adjust the maximum buffer, which we are fine with */
+    if (!gst_buffer_pool_set_config (obj->pool, config))
+      goto config_failed;
+  }
+
+  /* Now configure the other pool if different */
+  if (obj->pool != pool)
+    other_pool = pool;
+
+  if (other_pool) {
+    config = gst_buffer_pool_get_config (other_pool);
+    gst_buffer_pool_config_set_allocator (config, allocator, &params);
+    gst_buffer_pool_config_set_params (config, caps, size, min, max);
+
+    GST_DEBUG_OBJECT (obj->dbg_obj, "setting other pool config to %"
+        GST_PTR_FORMAT, config);
+
+    /* if downstream supports video metadata, add this to the pool config */
+    if (has_video_meta) {
+      GST_DEBUG_OBJECT (obj->dbg_obj, "activate Video Meta");
+      gst_buffer_pool_config_add_option (config,
+          GST_BUFFER_POOL_OPTION_VIDEO_META);
+    }
+
+    if (!gst_buffer_pool_set_config (other_pool, config)) {
+      config = gst_buffer_pool_get_config (other_pool);
+
+      if (!gst_buffer_pool_config_validate_params (config, caps, size, min,
+              max)) {
+        gst_structure_free (config);
+        goto config_failed;
+      }
+
+      if (!gst_buffer_pool_set_config (other_pool, config))
+        goto config_failed;
+    }
+  }
+
+  if (pool) {
+    /* For simplicity, simply read back the active configuration, so our base
+     * class get the right information */
+    config = gst_buffer_pool_get_config (pool);
+    gst_buffer_pool_config_get_params (config, NULL, &size, &min, &max);
+    gst_structure_free (config);
+  }
+
+  if (update)
+    gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
+  else
+    gst_query_add_allocation_pool (query, pool, size, min, max);
+
+  if (allocator)
+    gst_object_unref (allocator);
+
+  if (pool)
+    gst_object_unref (pool);
+
+  return TRUE;
+
+pool_failed:
+  {
+    /* setup_pool already send the error */
+    goto cleanup;
+  }
+config_failed:
+  {
+    GST_ELEMENT_ERROR (obj->element, RESOURCE, SETTINGS,
+        (_("Failed to configure internal buffer pool.")), (NULL));
+    goto cleanup;
+  }
+no_size:
+  {
+    GST_ELEMENT_ERROR (obj->element, RESOURCE, SETTINGS,
+        (_("Video device did not suggest any buffer size.")), (NULL));
+    goto cleanup;
+  }
+cleanup:
+  {
+    if (allocator)
+      gst_object_unref (allocator);
+
+    if (pool)
+      gst_object_unref (pool);
+    return FALSE;
+  }
+no_downstream_pool:
+  {
+    GST_ELEMENT_ERROR (obj->element, RESOURCE, SETTINGS,
+        (_("No downstream pool to import from.")),
+        ("When importing DMABUF or USERPTR, we need a pool to import from"));
+    return FALSE;
+  }
+}
+
+gboolean
+gst_v4l2_object_propose_allocation (GstV4l2Object * obj, GstQuery * query)
+{
+  GstBufferPool *pool;
+  /* we need at least 2 buffers to operate */
+  guint size, min, max;
+  GstCaps *caps;
+  gboolean need_pool;
+
+  /* Set defaults allocation parameters */
+  size = obj->info.size;
+  min = GST_V4L2_MIN_BUFFERS;
+  max = VIDEO_MAX_FRAME;
+
+  gst_query_parse_allocation (query, &caps, &need_pool);
+
+  if (caps == NULL)
+    goto no_caps;
+
+  if ((pool = obj->pool))
+    gst_object_ref (pool);
+
+  if (pool != NULL) {
+    GstCaps *pcaps;
+    GstStructure *config;
+
+    /* we had a pool, check caps */
+    config = gst_buffer_pool_get_config (pool);
+    gst_buffer_pool_config_get_params (config, &pcaps, NULL, NULL, NULL);
+
+    GST_DEBUG_OBJECT (obj->dbg_obj,
+        "we had a pool with caps %" GST_PTR_FORMAT, pcaps);
+    if (!gst_caps_is_equal (caps, pcaps)) {
+      gst_structure_free (config);
+      gst_object_unref (pool);
+      goto different_caps;
+    }
+    gst_structure_free (config);
+  }
+  gst_v4l2_get_driver_min_buffers (obj);
+
+  min = MAX (obj->min_buffers, GST_V4L2_MIN_BUFFERS);
+
+  gst_query_add_allocation_pool (query, pool, size, min, max);
+
+  /* we also support various metadata */
+  gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
+
+  if (pool)
+    gst_object_unref (pool);
+
+  return TRUE;
+
+  /* ERRORS */
+no_caps:
+  {
+    GST_DEBUG_OBJECT (obj->dbg_obj, "no caps specified");
+    return FALSE;
+  }
+different_caps:
+  {
+    /* different caps, we can't use this pool */
+    GST_DEBUG_OBJECT (obj->dbg_obj, "pool has different caps");
+    return FALSE;
+  }
+}
diff --git a/sys/v4l2/gstv4l2object.h b/sys/v4l2/gstv4l2object.h
new file mode 100644
index 0000000..73ba624
--- /dev/null
+++ b/sys/v4l2/gstv4l2object.h
@@ -0,0 +1,326 @@
+/* GStreamer
+ *
+ * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *               2006 Edgard Lima <edgard.lima@gmail.com>
+ *
+ * gstv4l2object.h: base class for V4L2 elements
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_V4L2_OBJECT_H__
+#define __GST_V4L2_OBJECT_H__
+
+#include "ext/videodev2.h"
+#ifdef HAVE_LIBV4L2
+#  include <libv4l2.h>
+#endif
+
+#include "v4l2-utils.h"
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+
+#include <gst/video/video.h>
+
+typedef struct _GstV4l2Object GstV4l2Object;
+typedef struct _GstV4l2ObjectClassHelper GstV4l2ObjectClassHelper;
+
+#include <gstv4l2bufferpool.h>
+
+/* size of v4l2 buffer pool in streaming case */
+#define GST_V4L2_MIN_BUFFERS 2
+
+/* max frame width/height */
+#define GST_V4L2_MAX_SIZE (1<<15) /* 2^15 == 32768 */
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_V4L2_IO_MODE (gst_v4l2_io_mode_get_type ())
+GType gst_v4l2_io_mode_get_type (void);
+
+#define GST_V4L2_OBJECT(obj) (GstV4l2Object *)(obj)
+
+typedef enum {
+  GST_V4L2_IO_AUTO          = 0,
+  GST_V4L2_IO_RW            = 1,
+  GST_V4L2_IO_MMAP          = 2,
+  GST_V4L2_IO_USERPTR       = 3,
+  GST_V4L2_IO_DMABUF        = 4,
+  GST_V4L2_IO_DMABUF_IMPORT = 5
+} GstV4l2IOMode;
+
+typedef gboolean  (*GstV4l2GetInOutFunction)  (GstV4l2Object * v4l2object, gint * input);
+typedef gboolean  (*GstV4l2SetInOutFunction)  (GstV4l2Object * v4l2object, gint input);
+typedef gboolean  (*GstV4l2UpdateFpsFunction) (GstV4l2Object * v4l2object);
+
+#define GST_V4L2_WIDTH(o)        (GST_VIDEO_INFO_WIDTH (&(o)->info))
+#define GST_V4L2_HEIGHT(o)       (GST_VIDEO_INFO_HEIGHT (&(o)->info))
+#define GST_V4L2_PIXELFORMAT(o)  ((o)->fmtdesc->pixelformat)
+#define GST_V4L2_FPS_N(o)        (GST_VIDEO_INFO_FPS_N (&(o)->info))
+#define GST_V4L2_FPS_D(o)        (GST_VIDEO_INFO_FPS_D (&(o)->info))
+
+/* simple check whether the device is open */
+#define GST_V4L2_IS_OPEN(o)      ((o)->video_fd > 0)
+
+/* check whether the device is 'active' */
+#define GST_V4L2_IS_ACTIVE(o)    ((o)->active)
+#define GST_V4L2_SET_ACTIVE(o)   ((o)->active = TRUE)
+#define GST_V4L2_SET_INACTIVE(o) ((o)->active = FALSE)
+
+/* checks whether the current v4lv4l2object has already been open()'ed or not */
+#define GST_V4L2_CHECK_OPEN(v4l2object)				\
+  if (!GST_V4L2_IS_OPEN(v4l2object))				\
+  {								\
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,	\
+      (_("Device is not open.")), (NULL));                      \
+    return FALSE;						\
+  }
+
+/* checks whether the current v4lv4l2object is close()'ed or whether it is still open */
+#define GST_V4L2_CHECK_NOT_OPEN(v4l2object)			\
+  if (GST_V4L2_IS_OPEN(v4l2object))				\
+  {								\
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,	\
+      (_("Device is open.")), (NULL));                          \
+    return FALSE;						\
+  }
+
+/* checks whether we're out of capture mode or not */
+#define GST_V4L2_CHECK_NOT_ACTIVE(v4l2object)			\
+  if (GST_V4L2_IS_ACTIVE(v4l2object))				\
+  {								\
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \
+      (NULL), ("Device is in streaming mode"));                 \
+    return FALSE;						\
+  }
+
+
+struct _GstV4l2Object {
+  GstElement * element;
+  GstObject * dbg_obj;
+
+  enum v4l2_buf_type type;   /* V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_OUTPUT */
+
+  /* the video device */
+  char *videodev;
+
+  /* the video-device's file descriptor */
+  gint video_fd;
+  GstV4l2IOMode mode;
+
+  gboolean active;
+  gboolean streaming;
+
+  /* the current format */
+  struct v4l2_fmtdesc *fmtdesc;
+  struct v4l2_format format;
+  GstVideoInfo info;
+  GstVideoAlignment align;
+
+  /* Features */
+  gboolean need_video_meta;
+  gboolean has_alpha_component;
+
+  /* only used if the device supports MPLANE
+   * nb planes is meaning of v4l2 planes
+   * the gstreamer equivalent is gst_buffer_n_memory
+   */
+  gint n_v4l2_planes;
+
+  /* We cache the frame duration if known */
+  GstClockTime duration;
+
+  /* if the MPLANE device support both contiguous and non contiguous
+   * it allows to select which one we want. But we prefered_non_contiguous
+   * non contiguous mode.
+   */
+  gboolean prefered_non_contiguous;
+
+  /* This will be set if supported in decide_allocation. It can be used to
+   * calculate the minimum latency. */
+  guint32 min_buffers;
+
+  /* wanted mode */
+  GstV4l2IOMode req_mode;
+
+  /* optional pool */
+  GstBufferPool *pool;
+
+  /* the video device's capabilities */
+  struct v4l2_capability vcap;
+  /* opened device specific capabilities */
+  guint32 device_caps;
+
+  /* lists... */
+  GSList *formats;              /* list of available capture formats */
+  GstCaps *probed_caps;
+
+  GList *colors;
+  GList *norms;
+  GList *channels;
+  GData *controls;
+
+  /* properties */
+  v4l2_std_id tv_norm;
+  gchar *channel;
+  gulong frequency;
+  GstStructure *extra_controls;
+  gboolean keep_aspect;
+  GValue *par;
+
+  /* funcs */
+  GstV4l2GetInOutFunction  get_in_out_func;
+  GstV4l2SetInOutFunction  set_in_out_func;
+  GstV4l2UpdateFpsFunction update_fps_func;
+
+  /* syscalls */
+  gint (*fd_open) (gint fd, gint v4l2_flags);
+  gint (*close) (gint fd);
+  gint (*dup) (gint fd);
+  gint (*ioctl) (gint fd, gulong request, ...);
+  gssize (*read) (gint fd, gpointer buffer, gsize n);
+  gpointer (*mmap) (gpointer start, gsize length, gint prot, gint flags,
+      gint fd, gint64 offset);
+  gint (*munmap) (gpointer _start, gsize length);
+
+  /* Quirks */
+  /* Skips interlacing probes */
+  gboolean never_interlaced;
+  /* Allow to skip reading initial format through G_FMT. Some devices
+   * just fails if you don't call S_FMT first. (ex: M2M decoders) */
+  gboolean no_initial_format;
+  /* Avoid any try_fmt probe. This is used by v4l2src to speedup start up time
+   * on slow USB firmwares. When this is set, gst_v4l2_set_format() will modify
+   * the caps to reflect what was negotiated during fixation */
+  gboolean skip_try_fmt_probes;
+};
+
+struct _GstV4l2ObjectClassHelper {
+  /* probed devices */
+  GList *devices;
+};
+
+GType gst_v4l2_object_get_type (void);
+
+#define V4L2_STD_OBJECT_PROPS \
+    PROP_DEVICE,              \
+    PROP_DEVICE_NAME,         \
+    PROP_DEVICE_FD,           \
+    PROP_FLAGS,               \
+    PROP_BRIGHTNESS,          \
+    PROP_CONTRAST,            \
+    PROP_SATURATION,          \
+    PROP_HUE,                 \
+    PROP_TV_NORM,             \
+    PROP_IO_MODE,             \
+    PROP_OUTPUT_IO_MODE,      \
+    PROP_CAPTURE_IO_MODE,     \
+    PROP_EXTRA_CONTROLS,      \
+    PROP_PIXEL_ASPECT_RATIO,  \
+    PROP_FORCE_ASPECT_RATIO
+
+/* create/destroy */
+GstV4l2Object*  gst_v4l2_object_new       (GstElement * element,
+                                           GstObject * dbg_obj,
+                                           enum v4l2_buf_type  type,
+                                           const char * default_device,
+                                           GstV4l2GetInOutFunction get_in_out_func,
+                                           GstV4l2SetInOutFunction set_in_out_func,
+                                           GstV4l2UpdateFpsFunction update_fps_func);
+
+void         gst_v4l2_object_destroy   (GstV4l2Object * v4l2object);
+
+/* properties */
+
+void         gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class,
+                                                        const char * default_device);
+
+void         gst_v4l2_object_install_m2m_properties_helper (GObjectClass * gobject_class);
+
+gboolean     gst_v4l2_object_set_property_helper       (GstV4l2Object * v4l2object,
+                                                        guint prop_id,
+                                                        const GValue * value,
+                                                        GParamSpec * pspec);
+gboolean     gst_v4l2_object_get_property_helper       (GstV4l2Object *v4l2object,
+                                                        guint prop_id, GValue * value,
+                                                        GParamSpec * pspec);
+/* open/close */
+gboolean     gst_v4l2_object_open            (GstV4l2Object * v4l2object);
+gboolean     gst_v4l2_object_open_shared     (GstV4l2Object * v4l2object, GstV4l2Object * other);
+gboolean     gst_v4l2_object_close           (GstV4l2Object * v4l2object);
+
+/* probing */
+
+GstCaps*     gst_v4l2_object_get_all_caps (void);
+
+GstCaps*     gst_v4l2_object_get_raw_caps (void);
+
+GstCaps*     gst_v4l2_object_get_codec_caps (void);
+
+gint         gst_v4l2_object_extrapolate_stride (const GstVideoFormatInfo * finfo,
+                                                  gint plane, gint stride);
+
+gboolean     gst_v4l2_object_set_format  (GstV4l2Object * v4l2object, GstCaps * caps, GstV4l2Error * error);
+gboolean     gst_v4l2_object_try_format  (GstV4l2Object * v4l2object, GstCaps * caps, GstV4l2Error * error);
+
+gboolean     gst_v4l2_object_caps_equal  (GstV4l2Object * v4l2object, GstCaps * caps);
+
+gboolean     gst_v4l2_object_unlock      (GstV4l2Object * v4l2object);
+gboolean     gst_v4l2_object_unlock_stop (GstV4l2Object * v4l2object);
+
+gboolean     gst_v4l2_object_stop        (GstV4l2Object * v4l2object);
+
+GstCaps *    gst_v4l2_object_probe_caps  (GstV4l2Object * v4l2object, GstCaps * filter);
+GstCaps *    gst_v4l2_object_get_caps    (GstV4l2Object * v4l2object, GstCaps * filter);
+
+gboolean     gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, GstVideoInfo * info);
+
+gboolean     gst_v4l2_object_set_crop    (GstV4l2Object * obj);
+
+gboolean     gst_v4l2_object_decide_allocation (GstV4l2Object * v4l2object, GstQuery * query);
+
+gboolean     gst_v4l2_object_propose_allocation (GstV4l2Object * obj, GstQuery * query);
+
+GstStructure * gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc);
+
+/* TODO Move to proper namespace */
+/* open/close the device */
+gboolean     gst_v4l2_open           (GstV4l2Object * v4l2object);
+gboolean     gst_v4l2_dup            (GstV4l2Object * v4l2object, GstV4l2Object * other);
+gboolean     gst_v4l2_close          (GstV4l2Object * v4l2object);
+
+/* norm/input/output */
+gboolean     gst_v4l2_get_norm       (GstV4l2Object * v4l2object, v4l2_std_id * norm);
+gboolean     gst_v4l2_set_norm       (GstV4l2Object * v4l2object, v4l2_std_id norm);
+gboolean     gst_v4l2_get_input      (GstV4l2Object * v4l2object, gint * input);
+gboolean     gst_v4l2_set_input      (GstV4l2Object * v4l2object, gint input);
+gboolean     gst_v4l2_get_output     (GstV4l2Object * v4l2object, gint * output);
+gboolean     gst_v4l2_set_output     (GstV4l2Object * v4l2object, gint output);
+
+/* frequency control */
+gboolean     gst_v4l2_get_frequency   (GstV4l2Object * v4l2object, gint tunernum, gulong * frequency);
+gboolean     gst_v4l2_set_frequency   (GstV4l2Object * v4l2object, gint tunernum, gulong frequency);
+gboolean     gst_v4l2_signal_strength (GstV4l2Object * v4l2object, gint tunernum, gulong * signal);
+
+/* attribute control */
+gboolean     gst_v4l2_get_attribute   (GstV4l2Object * v4l2object, int attribute, int * value);
+gboolean     gst_v4l2_set_attribute   (GstV4l2Object * v4l2object, int attribute, const int value);
+gboolean     gst_v4l2_set_controls    (GstV4l2Object * v4l2object, GstStructure * controls);
+
+G_END_DECLS
+
+#endif /* __GST_V4L2_OBJECT_H__ */
diff --git a/sys/v4l2/gstv4l2radio.c b/sys/v4l2/gstv4l2radio.c
new file mode 100644
index 0000000..6bfbefb
--- /dev/null
+++ b/sys/v4l2/gstv4l2radio.c
@@ -0,0 +1,582 @@
+/* GStreamer v4l2 radio tuner element
+ * Copyright (C) 2010, 2011 Alexey Chernov <4ernov@gmail.com>
+ *
+ * gstv4l2radio.c - V4L2 radio tuner element
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-v4l2radio
+ *
+ * v4l2radio can be used to control radio device
+ * and to tune it to different radiostations.
+ *
+ * <refsect2>
+ * <title>Example launch lines</title>
+ * |[
+ * gst-launch-1.0 v4l2radio device=/dev/radio0 frequency=101200000
+ * gst-launch-1.0 alsasrc device=hw:1 ! audioconvert ! audioresample ! alsasink
+ * ]|
+ * First pipeline tunes the radio device /dev/radio0 to station 101.2 MHz,
+ * second pipeline connects digital audio out (hw:1) to default sound card.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "gst/gst-i18n-plugin.h"
+
+#include "gstv4l2object.h"
+#include "gstv4l2tuner.h"
+#include "gstv4l2radio.h"
+
+GST_DEBUG_CATEGORY_STATIC (v4l2radio_debug);
+#define GST_CAT_DEFAULT v4l2radio_debug
+
+#define DEFAULT_PROP_DEVICE "/dev/radio0"
+#define MIN_FREQUENCY		 87500000
+#define DEFAULT_FREQUENCY	100000000
+#define MAX_FREQUENCY		108000000
+
+enum
+{
+  ARG_0,
+  ARG_DEVICE,
+  ARG_FREQUENCY
+};
+
+static gboolean
+gst_v4l2radio_fill_channel_list (GstV4l2Radio * radio)
+{
+  int res;
+  struct v4l2_tuner vtun;
+  struct v4l2_capability vc;
+  GstV4l2TunerChannel *v4l2channel;
+  GstTunerChannel *channel;
+
+  GstElement *e;
+
+  GstV4l2Object *v4l2object;
+
+  e = GST_ELEMENT (radio);
+  v4l2object = radio->v4l2object;
+
+  GST_DEBUG_OBJECT (e, "getting audio enumeration");
+  GST_V4L2_CHECK_OPEN (v4l2object);
+
+  GST_DEBUG_OBJECT (e, "  audio input");
+
+  memset (&vc, 0, sizeof (vc));
+
+  res = v4l2object->ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &vc);
+  if (res < 0)
+    goto caps_failed;
+
+  if (vc.capabilities & V4L2_CAP_DEVICE_CAPS)
+    v4l2object->device_caps = vc.device_caps;
+  else
+    v4l2object->device_caps = vc.capabilities;
+
+  if (!(v4l2object->device_caps & V4L2_CAP_TUNER))
+    goto not_a_tuner;
+
+  /* getting audio input */
+  memset (&vtun, 0, sizeof (vtun));
+  vtun.index = 0;
+
+  res = v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun);
+  if (res < 0)
+    goto tuner_failed;
+
+  GST_LOG_OBJECT (e, "   index:     %d", vtun.index);
+  GST_LOG_OBJECT (e, "   name:      '%s'", vtun.name);
+  GST_LOG_OBJECT (e, "   type:      %016x", (guint) vtun.type);
+  GST_LOG_OBJECT (e, "   caps:      %016x", (guint) vtun.capability);
+  GST_LOG_OBJECT (e, "   rlow:      %016x", (guint) vtun.rangelow);
+  GST_LOG_OBJECT (e, "   rhigh:     %016x", (guint) vtun.rangehigh);
+  GST_LOG_OBJECT (e, "   audmode:   %016x", (guint) vtun.audmode);
+
+  v4l2channel = g_object_new (GST_TYPE_V4L2_TUNER_CHANNEL, NULL);
+  channel = GST_TUNER_CHANNEL (v4l2channel);
+  channel->label = g_strdup ((const gchar *) vtun.name);
+  channel->flags = GST_TUNER_CHANNEL_FREQUENCY | GST_TUNER_CHANNEL_AUDIO;
+  v4l2channel->index = 0;
+  v4l2channel->tuner = 0;
+
+  channel->freq_multiplicator =
+      62.5 * ((vtun.capability & V4L2_TUNER_CAP_LOW) ? 1 : 1000);
+  channel->min_frequency = vtun.rangelow * channel->freq_multiplicator;
+  channel->max_frequency = vtun.rangehigh * channel->freq_multiplicator;
+  channel->min_signal = 0;
+  channel->max_signal = 0xffff;
+
+  v4l2object->channels =
+      g_list_prepend (v4l2object->channels, (gpointer) channel);
+
+  v4l2object->channels = g_list_reverse (v4l2object->channels);
+
+  GST_DEBUG_OBJECT (e, "done");
+  return TRUE;
+
+  /* ERRORS */
+tuner_failed:
+  {
+    GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
+        (_("Failed to get settings of tuner %d on device '%s'."),
+            vtun.index, v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+caps_failed:
+  {
+    GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
+        (_("Error getting capabilities for device '%s'."),
+            v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+not_a_tuner:
+  {
+    GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
+        (_("Device '%s' is not a tuner."),
+            v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_v4l2radio_get_input (GstV4l2Object * v4l2object, gint * input)
+{
+  GST_DEBUG_OBJECT (v4l2object->element, "trying to get radio input");
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  if (!v4l2object->channels)
+    goto input_failed;
+
+  *input = 0;
+
+  GST_DEBUG_OBJECT (v4l2object->element, "input: %d", 0);
+
+  return TRUE;
+
+  /* ERRORS */
+input_failed:
+  {
+    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Failed to get radio input on device '%s'. "),
+            v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_v4l2radio_set_input (GstV4l2Object * v4l2object, gint input)
+{
+  GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input);
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  if (!v4l2object->channels)
+    goto input_failed;
+
+  return TRUE;
+
+  /* ERRORS */
+input_failed:
+  {
+    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Failed to set input %d on device %s."),
+            input, v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_v4l2radio_set_mute_on (GstV4l2Radio * radio, gboolean on)
+{
+  gint res;
+  struct v4l2_control vctrl;
+
+  GST_DEBUG_OBJECT (radio, "setting current tuner mute state: %d", on);
+
+  if (!GST_V4L2_IS_OPEN (radio->v4l2object))
+    return FALSE;
+
+  memset (&vctrl, 0, sizeof (vctrl));
+  vctrl.id = V4L2_CID_AUDIO_MUTE;
+  vctrl.value = on;
+
+  GST_DEBUG_OBJECT (radio, "radio fd: %d", radio->v4l2object->video_fd);
+
+  res = ioctl (radio->v4l2object->video_fd, VIDIOC_S_CTRL, &vctrl);
+  GST_DEBUG_OBJECT (radio, "mute state change result: %d", res);
+  if (res < 0)
+    goto freq_failed;
+
+  return TRUE;
+
+  /* ERRORS */
+freq_failed:
+  {
+    GST_ELEMENT_WARNING (radio, RESOURCE, SETTINGS,
+        (_("Failed to change mute state for device '%s'."),
+            radio->v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_v4l2radio_set_mute (GstV4l2Radio * radio)
+{
+  return gst_v4l2radio_set_mute_on (radio, TRUE);
+}
+
+static gboolean
+gst_v4l2radio_set_unmute (GstV4l2Radio * radio)
+{
+  return gst_v4l2radio_set_mute_on (radio, FALSE);
+}
+
+GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Radio, gst_v4l2radio);
+
+static void gst_v4l2radio_uri_handler_init (gpointer g_iface,
+    gpointer iface_data);
+
+static void
+gst_v4l2radio_tuner_interface_reinit (GstTunerInterface * iface)
+{
+  gst_v4l2radio_tuner_interface_init (iface);
+}
+
+#define gst_v4l2radio_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstV4l2Radio, gst_v4l2radio, GST_TYPE_ELEMENT,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
+        gst_v4l2radio_uri_handler_init);
+    G_IMPLEMENT_INTERFACE (GST_TYPE_TUNER,
+        gst_v4l2radio_tuner_interface_reinit));
+
+static void gst_v4l2radio_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_v4l2radio_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_v4l2radio_finalize (GstV4l2Radio * radio);
+static void gst_v4l2radio_dispose (GObject * object);
+static GstStateChangeReturn gst_v4l2radio_change_state (GstElement * element,
+    GstStateChange transition);
+
+static void
+gst_v4l2radio_class_init (GstV4l2RadioClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->dispose = gst_v4l2radio_dispose;
+  gobject_class->finalize = (GObjectFinalizeFunc) gst_v4l2radio_finalize;
+  gobject_class->set_property = gst_v4l2radio_set_property;
+  gobject_class->get_property = gst_v4l2radio_get_property;
+
+  g_object_class_install_property (gobject_class, ARG_DEVICE,
+      g_param_spec_string ("device", "Radio device location",
+          "Video4Linux2 radio device location",
+          DEFAULT_PROP_DEVICE, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, ARG_FREQUENCY,
+      g_param_spec_int ("frequency", "Station frequency",
+          "Station frequency in Hz",
+          MIN_FREQUENCY, MAX_FREQUENCY, DEFAULT_FREQUENCY, G_PARAM_READWRITE));
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_v4l2radio_change_state);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Radio (video4linux2) Tuner",
+      "Tuner",
+      "Controls a Video4Linux2 radio device",
+      "Alexey Chernov <4ernov@gmail.com>");
+
+  klass->v4l2_class_devices = NULL;
+
+  GST_DEBUG_CATEGORY_INIT (v4l2radio_debug, "v4l2radio", 0,
+      "V4l2 radio element");
+}
+
+static void
+gst_v4l2radio_init (GstV4l2Radio * filter)
+{
+  filter->v4l2object = gst_v4l2_object_new (GST_ELEMENT (filter),
+      GST_OBJECT (filter), V4L2_BUF_TYPE_VIDEO_CAPTURE, DEFAULT_PROP_DEVICE,
+      gst_v4l2radio_get_input, gst_v4l2radio_set_input, NULL);
+
+  filter->v4l2object->frequency = DEFAULT_FREQUENCY;
+  g_free (filter->v4l2object->videodev);
+  filter->v4l2object->videodev = g_strdup (DEFAULT_PROP_DEVICE);
+}
+
+static void
+gst_v4l2radio_dispose (GObject * object)
+{
+  GstV4l2Radio *radio = GST_V4L2RADIO (object);
+  gst_v4l2_close (radio->v4l2object);
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_v4l2radio_finalize (GstV4l2Radio * radio)
+{
+  gst_v4l2_object_destroy (radio->v4l2object);
+  G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (radio));
+}
+
+static gboolean
+gst_v4l2radio_open (GstV4l2Radio * radio)
+{
+  GstV4l2Object *v4l2object;
+
+  v4l2object = radio->v4l2object;
+  if (gst_v4l2_open (v4l2object))
+    return gst_v4l2radio_fill_channel_list (radio);
+  else
+    return FALSE;
+}
+
+static void
+gst_v4l2radio_set_defaults (GstV4l2Radio * radio)
+{
+  GstV4l2Object *v4l2object;
+  GstTunerChannel *channel = NULL;
+  GstTuner *tuner;
+
+  v4l2object = radio->v4l2object;
+
+  if (!GST_IS_TUNER (v4l2object->element))
+    return;
+
+  tuner = GST_TUNER (v4l2object->element);
+
+  if (v4l2object->channel)
+    channel = gst_tuner_find_channel_by_name (tuner, v4l2object->channel);
+  if (channel) {
+    gst_tuner_set_channel (tuner, channel);
+  } else {
+    channel =
+        GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER
+            (v4l2object->element)));
+    if (channel) {
+      g_free (v4l2object->channel);
+      v4l2object->channel = g_strdup (channel->label);
+      gst_tuner_channel_changed (tuner, channel);
+    }
+  }
+
+  if (channel
+      && GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
+    if (v4l2object->frequency != 0) {
+      gst_tuner_set_frequency (tuner, channel, v4l2object->frequency);
+    } else {
+      v4l2object->frequency = gst_tuner_get_frequency (tuner, channel);
+      if (v4l2object->frequency == 0) {
+        /* guess */
+        gst_tuner_set_frequency (tuner, channel, MIN_FREQUENCY);
+      } else {
+      }
+    }
+  }
+}
+
+static gboolean
+gst_v4l2radio_start (GstV4l2Radio * radio)
+{
+  if (!gst_v4l2radio_open (radio))
+    return FALSE;
+
+  gst_v4l2radio_set_defaults (radio);
+
+  return TRUE;
+}
+
+static gboolean
+gst_v4l2radio_stop (GstV4l2Radio * radio)
+{
+  if (!gst_v4l2_object_close (radio->v4l2object))
+    return FALSE;
+
+  return TRUE;
+}
+
+static GstStateChangeReturn
+gst_v4l2radio_change_state (GstElement * element, GstStateChange transition)
+{
+  GstV4l2Radio *radio;
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+  radio = GST_V4L2RADIO (element);
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      /*start radio */
+      if (!gst_v4l2radio_start (radio))
+        ret = GST_STATE_CHANGE_FAILURE;
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      /*unmute radio */
+      if (!gst_v4l2radio_set_unmute (radio))
+        ret = GST_STATE_CHANGE_FAILURE;
+      break;
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      /*mute radio */
+      if (!gst_v4l2radio_set_mute (radio))
+        ret = GST_STATE_CHANGE_FAILURE;
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      /*stop radio */
+      if (!gst_v4l2radio_stop (radio))
+        ret = GST_STATE_CHANGE_FAILURE;
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_v4l2radio_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstV4l2Radio *radio = GST_V4L2RADIO (object);
+  gint frequency;
+  switch (prop_id) {
+    case ARG_DEVICE:
+      g_free (radio->v4l2object->videodev);
+      radio->v4l2object->videodev =
+          g_strdup ((gchar *) g_value_get_string (value));
+      break;
+    case ARG_FREQUENCY:
+      frequency = g_value_get_int (value);
+      if (frequency >= MIN_FREQUENCY && frequency <= MAX_FREQUENCY) {
+        radio->v4l2object->frequency = frequency;
+        gst_v4l2_set_frequency (radio->v4l2object, 0,
+            radio->v4l2object->frequency);
+      }
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_v4l2radio_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstV4l2Radio *radio = GST_V4L2RADIO (object);
+
+  switch (prop_id) {
+    case ARG_DEVICE:
+      g_value_set_string (value, radio->v4l2object->videodev);
+      break;
+    case ARG_FREQUENCY:
+      if (gst_v4l2_get_frequency (radio->v4l2object,
+              0, &(radio->v4l2object->frequency)))
+        g_value_set_int (value, radio->v4l2object->frequency);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* GstURIHandler interface */
+static GstURIType
+gst_v4l2radio_uri_get_type (GType type)
+{
+  return GST_URI_SRC;
+}
+
+static const gchar *const *
+gst_v4l2radio_uri_get_protocols (GType type)
+{
+  static const gchar *protocols[] = { "radio", NULL };
+
+  return protocols;
+}
+
+static gchar *
+gst_v4l2radio_uri_get_uri (GstURIHandler * handler)
+{
+  GstV4l2Radio *radio = GST_V4L2RADIO (handler);
+
+  if (radio->v4l2object->videodev != NULL) {
+    if (gst_v4l2_get_frequency (radio->v4l2object,
+            0, &(radio->v4l2object->frequency))) {
+      return g_strdup_printf ("radio://%4.1f",
+          radio->v4l2object->frequency / 1e6);
+    }
+  }
+
+  return g_strdup ("radio://");
+}
+
+static gboolean
+gst_v4l2radio_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+    GError ** error)
+{
+  GstV4l2Radio *radio = GST_V4L2RADIO (handler);
+  gdouble dfreq;
+  gint ifreq;
+  const gchar *freq;
+  gchar *end;
+
+  if (strcmp (uri, "radio://") != 0) {
+    freq = uri + 8;
+
+    dfreq = g_ascii_strtod (freq, &end);
+
+    if (errno || strlen (end))
+      goto uri_failed;
+
+    ifreq = dfreq * 1e6;
+    g_object_set (radio, "frequency", ifreq, NULL);
+
+  } else
+    goto uri_failed;
+
+  return TRUE;
+
+uri_failed:
+  g_set_error_literal (error, GST_URI_ERROR, GST_URI_ERROR_BAD_REFERENCE,
+      "Bad radio URI, could not parse frequency");
+  return FALSE;
+}
+
+static void
+gst_v4l2radio_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+  iface->get_type = gst_v4l2radio_uri_get_type;
+  iface->get_protocols = gst_v4l2radio_uri_get_protocols;
+  iface->get_uri = gst_v4l2radio_uri_get_uri;
+  iface->set_uri = gst_v4l2radio_uri_set_uri;
+}
diff --git a/sys/v4l2/gstv4l2radio.h b/sys/v4l2/gstv4l2radio.h
new file mode 100644
index 0000000..2fda4fb
--- /dev/null
+++ b/sys/v4l2/gstv4l2radio.h
@@ -0,0 +1,67 @@
+/* GStreamer v4l2 radio tuner element
+ * Copyright (C) 2010, 2011 Alexey Chernov <4ernov@gmail.com>
+ *
+ * gstv4l2radio.h - V4L2 radio tuner element
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_V4L2RADIO_H__
+#define __GST_V4L2RADIO_H__
+
+#include "gstv4l2object.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_V4L2RADIO \
+  (gst_v4l2radio_get_type())
+#define GST_V4L2RADIO(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2RADIO,GstV4l2Radio))
+#define GST_V4L2RADIO_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2RADIO,GstV4l2RadioClass))
+#define GST_IS_V4L2RADIO(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2RADIO))
+#define GST_IS_V4L2RADIO_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2RADIO))
+
+typedef struct _GstV4l2Radio      GstV4l2Radio;
+typedef struct _GstV4l2RadioClass GstV4l2RadioClass;
+
+/**
+ * GstV4l2Radio:
+ *
+ * Opaque video4linux2 radio tuner element
+ */
+struct _GstV4l2Radio
+{
+  GstElement element;
+
+  /*< private >*/
+  GstV4l2Object * v4l2object;
+};
+
+struct _GstV4l2RadioClass
+{
+  GstElementClass parent_class;
+
+  GList *v4l2_class_devices;
+};
+
+GType gst_v4l2radio_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_V4L2RADIO_H__ */
diff --git a/sys/v4l2/gstv4l2sink.c b/sys/v4l2/gstv4l2sink.c
new file mode 100644
index 0000000..8739218
--- /dev/null
+++ b/sys/v4l2/gstv4l2sink.c
@@ -0,0 +1,646 @@
+/* GStreamer
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc - http://www.ti.com/
+ *
+ * Description: V4L2 sink element
+ *  Created on: Jul 2, 2009
+ *      Author: Rob Clark <rob@ti.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-v4l2sink
+ *
+ * v4l2sink can be used to display video to v4l2 devices (screen overlays
+ * provided by the graphics hardware, tv-out, etc)
+ *
+ * <refsect2>
+ * <title>Example launch lines</title>
+ * |[
+ * gst-launch-1.0 videotestsrc ! v4l2sink device=/dev/video1
+ * ]| This pipeline displays a test pattern on /dev/video1
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! navigationtest ! v4l2sink
+ * ]| A pipeline to test navigation events.
+ * While moving the mouse pointer over the test signal you will see a black box
+ * following the mouse pointer. If you press the mouse button somewhere on the
+ * video and release it somewhere else a green box will appear where you pressed
+ * the button and a red one where you released it. (The navigationtest element
+ * is part of gst-plugins-good.) You can observe here that even if the images
+ * are scaled through hardware the pointer coordinates are converted back to the
+ * original video frame geometry so that the box can be drawn to the correct
+ * position. This also handles borders correctly, limiting coordinates to the
+ * image area
+ * </refsect2>
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gst/video/gstvideometa.h"
+
+#include "gstv4l2colorbalance.h"
+#include "gstv4l2tuner.h"
+#include "gstv4l2vidorient.h"
+
+#include "gstv4l2sink.h"
+#include "gst/gst-i18n-plugin.h"
+
+#include <string.h>
+
+GST_DEBUG_CATEGORY (v4l2sink_debug);
+#define GST_CAT_DEFAULT v4l2sink_debug
+
+#define DEFAULT_PROP_DEVICE   "/dev/video1"
+
+enum
+{
+  PROP_0,
+  V4L2_STD_OBJECT_PROPS,
+  PROP_OVERLAY_TOP,
+  PROP_OVERLAY_LEFT,
+  PROP_OVERLAY_WIDTH,
+  PROP_OVERLAY_HEIGHT,
+  PROP_CROP_TOP,
+  PROP_CROP_LEFT,
+  PROP_CROP_WIDTH,
+  PROP_CROP_HEIGHT,
+};
+
+
+GST_IMPLEMENT_V4L2_COLOR_BALANCE_METHODS (GstV4l2Sink, gst_v4l2sink);
+GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Sink, gst_v4l2sink);
+GST_IMPLEMENT_V4L2_VIDORIENT_METHODS (GstV4l2Sink, gst_v4l2sink);
+
+#define gst_v4l2sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstV4l2Sink, gst_v4l2sink, GST_TYPE_VIDEO_SINK,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_TUNER, gst_v4l2sink_tuner_interface_init);
+    G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
+        gst_v4l2sink_color_balance_interface_init);
+    G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_ORIENTATION,
+        gst_v4l2sink_video_orientation_interface_init));
+
+
+static void gst_v4l2sink_finalize (GstV4l2Sink * v4l2sink);
+
+/* GObject methods: */
+static void gst_v4l2sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_v4l2sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+/* GstElement methods: */
+static GstStateChangeReturn gst_v4l2sink_change_state (GstElement * element,
+    GstStateChange transition);
+
+/* GstBaseSink methods: */
+static gboolean gst_v4l2sink_propose_allocation (GstBaseSink * bsink,
+    GstQuery * query);
+static GstCaps *gst_v4l2sink_get_caps (GstBaseSink * bsink, GstCaps * filter);
+static gboolean gst_v4l2sink_set_caps (GstBaseSink * bsink, GstCaps * caps);
+static GstFlowReturn gst_v4l2sink_show_frame (GstVideoSink * bsink,
+    GstBuffer * buf);
+static gboolean gst_v4l2sink_unlock (GstBaseSink * sink);
+static gboolean gst_v4l2sink_unlock_stop (GstBaseSink * sink);
+
+static void
+gst_v4l2sink_class_init (GstV4l2SinkClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+  GstBaseSinkClass *basesink_class;
+  GstVideoSinkClass *videosink_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  element_class = GST_ELEMENT_CLASS (klass);
+  basesink_class = GST_BASE_SINK_CLASS (klass);
+  videosink_class = GST_VIDEO_SINK_CLASS (klass);
+
+  gobject_class->finalize = (GObjectFinalizeFunc) gst_v4l2sink_finalize;
+  gobject_class->set_property = gst_v4l2sink_set_property;
+  gobject_class->get_property = gst_v4l2sink_get_property;
+
+  element_class->change_state = gst_v4l2sink_change_state;
+
+  gst_v4l2_object_install_properties_helper (gobject_class,
+      DEFAULT_PROP_DEVICE);
+
+  g_object_class_install_property (gobject_class, PROP_OVERLAY_TOP,
+      g_param_spec_int ("overlay-top", "Overlay top",
+          "The topmost (y) coordinate of the video overlay; top left corner of screen is 0,0",
+          G_MININT, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_OVERLAY_LEFT,
+      g_param_spec_int ("overlay-left", "Overlay left",
+          "The leftmost (x) coordinate of the video overlay; top left corner of screen is 0,0",
+          G_MININT, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_OVERLAY_WIDTH,
+      g_param_spec_uint ("overlay-width", "Overlay width",
+          "The width of the video overlay; default is equal to negotiated image width",
+          0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_OVERLAY_HEIGHT,
+      g_param_spec_uint ("overlay-height", "Overlay height",
+          "The height of the video overlay; default is equal to negotiated image height",
+          0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CROP_TOP,
+      g_param_spec_int ("crop-top", "Crop top",
+          "The topmost (y) coordinate of the video crop; top left corner of image is 0,0",
+          0x80000000, 0x7fffffff, 0, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class, PROP_CROP_LEFT,
+      g_param_spec_int ("crop-left", "Crop left",
+          "The leftmost (x) coordinate of the video crop; top left corner of image is 0,0",
+          0x80000000, 0x7fffffff, 0, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class, PROP_CROP_WIDTH,
+      g_param_spec_uint ("crop-width", "Crop width",
+          "The width of the video crop; default is equal to negotiated image width",
+          0, 0xffffffff, 0, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class, PROP_CROP_HEIGHT,
+      g_param_spec_uint ("crop-height", "Crop height",
+          "The height of the video crop; default is equal to negotiated image height",
+          0, 0xffffffff, 0, G_PARAM_READWRITE));
+
+  gst_element_class_set_static_metadata (element_class,
+      "Video (video4linux2) Sink", "Sink/Video",
+      "Displays frames on a video4linux2 device", "Rob Clark <rob@ti.com>,");
+
+  gst_element_class_add_pad_template (element_class,
+      gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+          gst_v4l2_object_get_all_caps ()));
+
+  basesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_v4l2sink_get_caps);
+  basesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_v4l2sink_set_caps);
+  basesink_class->propose_allocation =
+      GST_DEBUG_FUNCPTR (gst_v4l2sink_propose_allocation);
+  basesink_class->unlock = GST_DEBUG_FUNCPTR (gst_v4l2sink_unlock);
+  basesink_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_v4l2sink_unlock_stop);
+
+  videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_v4l2sink_show_frame);
+
+  klass->v4l2_class_devices = NULL;
+
+  GST_DEBUG_CATEGORY_INIT (v4l2sink_debug, "v4l2sink", 0, "V4L2 sink element");
+
+}
+
+static void
+gst_v4l2sink_init (GstV4l2Sink * v4l2sink)
+{
+  v4l2sink->v4l2object = gst_v4l2_object_new (GST_ELEMENT (v4l2sink),
+      GST_OBJECT (GST_BASE_SINK_PAD (v4l2sink)), V4L2_BUF_TYPE_VIDEO_OUTPUT,
+      DEFAULT_PROP_DEVICE, gst_v4l2_get_output, gst_v4l2_set_output, NULL);
+
+  /* same default value for video output device as is used for
+   * v4l2src/capture is no good..  so lets set a saner default
+   * (which can be overridden by the one creating the v4l2sink
+   * after the constructor returns)
+   */
+  g_object_set (v4l2sink, "device", "/dev/video1", NULL);
+
+  v4l2sink->overlay_fields_set = 0;
+  v4l2sink->crop_fields_set = 0;
+}
+
+
+static void
+gst_v4l2sink_finalize (GstV4l2Sink * v4l2sink)
+{
+  gst_v4l2_object_destroy (v4l2sink->v4l2object);
+
+  G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (v4l2sink));
+}
+
+
+/*
+ * flags to indicate which overlay/crop properties the user has set (and
+ * therefore which ones should override the defaults from the driver)
+ */
+enum
+{
+  RECT_TOP_SET = 0x01,
+  RECT_LEFT_SET = 0x02,
+  RECT_WIDTH_SET = 0x04,
+  RECT_HEIGHT_SET = 0x08
+};
+
+static void
+gst_v4l2sink_sync_overlay_fields (GstV4l2Sink * v4l2sink)
+{
+  if (!v4l2sink->overlay_fields_set)
+    return;
+
+  if (GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) {
+
+    GstV4l2Object *obj = v4l2sink->v4l2object;
+    struct v4l2_format format;
+
+    memset (&format, 0x00, sizeof (struct v4l2_format));
+    if (obj->device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
+      format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY;
+    else
+      format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
+
+    if (obj->ioctl (obj->video_fd, VIDIOC_G_FMT, &format) < 0) {
+      GST_WARNING_OBJECT (v4l2sink, "VIDIOC_G_FMT failed");
+      return;
+    }
+
+    GST_DEBUG_OBJECT (v4l2sink,
+        "setting overlay: overlay_fields_set=0x%02x, top=%d, left=%d, width=%d, height=%d",
+        v4l2sink->overlay_fields_set,
+        v4l2sink->overlay.top, v4l2sink->overlay.left,
+        v4l2sink->overlay.width, v4l2sink->overlay.height);
+
+    if (v4l2sink->overlay_fields_set & RECT_TOP_SET)
+      format.fmt.win.w.top = v4l2sink->overlay.top;
+    if (v4l2sink->overlay_fields_set & RECT_LEFT_SET)
+      format.fmt.win.w.left = v4l2sink->overlay.left;
+    if (v4l2sink->overlay_fields_set & RECT_WIDTH_SET)
+      format.fmt.win.w.width = v4l2sink->overlay.width;
+    if (v4l2sink->overlay_fields_set & RECT_HEIGHT_SET)
+      format.fmt.win.w.height = v4l2sink->overlay.height;
+
+    if (obj->ioctl (obj->video_fd, VIDIOC_S_FMT, &format) < 0) {
+      GST_WARNING_OBJECT (v4l2sink, "VIDIOC_S_FMT failed");
+      return;
+    }
+
+    v4l2sink->overlay_fields_set = 0;
+    v4l2sink->overlay = format.fmt.win.w;
+  }
+}
+
+static void
+gst_v4l2sink_sync_crop_fields (GstV4l2Sink * v4l2sink)
+{
+  if (!v4l2sink->crop_fields_set)
+    return;
+
+  if (GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) {
+
+    GstV4l2Object *obj = v4l2sink->v4l2object;
+    struct v4l2_crop crop;
+
+    memset (&crop, 0x00, sizeof (struct v4l2_crop));
+    crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+    if (obj->ioctl (obj->video_fd, VIDIOC_G_CROP, &crop) < 0) {
+      GST_WARNING_OBJECT (v4l2sink, "VIDIOC_G_CROP failed");
+      return;
+    }
+
+    GST_DEBUG_OBJECT (v4l2sink,
+        "setting crop: crop_fields_set=0x%02x, top=%d, left=%d, width=%d, height=%d",
+        v4l2sink->crop_fields_set,
+        v4l2sink->crop.top, v4l2sink->crop.left,
+        v4l2sink->crop.width, v4l2sink->crop.height);
+
+    if (v4l2sink->crop_fields_set & RECT_TOP_SET)
+      crop.c.top = v4l2sink->crop.top;
+    if (v4l2sink->crop_fields_set & RECT_LEFT_SET)
+      crop.c.left = v4l2sink->crop.left;
+    if (v4l2sink->crop_fields_set & RECT_WIDTH_SET)
+      crop.c.width = v4l2sink->crop.width;
+    if (v4l2sink->crop_fields_set & RECT_HEIGHT_SET)
+      crop.c.height = v4l2sink->crop.height;
+
+    if (obj->ioctl (obj->video_fd, VIDIOC_S_CROP, &crop) < 0) {
+      GST_WARNING_OBJECT (v4l2sink, "VIDIOC_S_CROP failed");
+      return;
+    }
+
+    if (obj->ioctl (obj->video_fd, VIDIOC_G_CROP, &crop) < 0) {
+      GST_WARNING_OBJECT (v4l2sink, "VIDIOC_G_CROP failed");
+      return;
+    }
+
+    v4l2sink->crop_fields_set = 0;
+    v4l2sink->crop = crop.c;
+  }
+}
+
+
+static void
+gst_v4l2sink_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstV4l2Sink *v4l2sink = GST_V4L2SINK (object);
+
+  if (!gst_v4l2_object_set_property_helper (v4l2sink->v4l2object,
+          prop_id, value, pspec)) {
+    switch (prop_id) {
+      case PROP_OVERLAY_TOP:
+        v4l2sink->overlay.top = g_value_get_int (value);
+        v4l2sink->overlay_fields_set |= RECT_TOP_SET;
+        gst_v4l2sink_sync_overlay_fields (v4l2sink);
+        break;
+      case PROP_OVERLAY_LEFT:
+        v4l2sink->overlay.left = g_value_get_int (value);
+        v4l2sink->overlay_fields_set |= RECT_LEFT_SET;
+        gst_v4l2sink_sync_overlay_fields (v4l2sink);
+        break;
+      case PROP_OVERLAY_WIDTH:
+        v4l2sink->overlay.width = g_value_get_uint (value);
+        v4l2sink->overlay_fields_set |= RECT_WIDTH_SET;
+        gst_v4l2sink_sync_overlay_fields (v4l2sink);
+        break;
+      case PROP_OVERLAY_HEIGHT:
+        v4l2sink->overlay.height = g_value_get_uint (value);
+        v4l2sink->overlay_fields_set |= RECT_HEIGHT_SET;
+        gst_v4l2sink_sync_overlay_fields (v4l2sink);
+        break;
+      case PROP_CROP_TOP:
+        v4l2sink->crop.top = g_value_get_int (value);
+        v4l2sink->crop_fields_set |= RECT_TOP_SET;
+        gst_v4l2sink_sync_crop_fields (v4l2sink);
+        break;
+      case PROP_CROP_LEFT:
+        v4l2sink->crop.left = g_value_get_int (value);
+        v4l2sink->crop_fields_set |= RECT_LEFT_SET;
+        gst_v4l2sink_sync_crop_fields (v4l2sink);
+        break;
+      case PROP_CROP_WIDTH:
+        v4l2sink->crop.width = g_value_get_uint (value);
+        v4l2sink->crop_fields_set |= RECT_WIDTH_SET;
+        gst_v4l2sink_sync_crop_fields (v4l2sink);
+        break;
+      case PROP_CROP_HEIGHT:
+        v4l2sink->crop.height = g_value_get_uint (value);
+        v4l2sink->crop_fields_set |= RECT_HEIGHT_SET;
+        gst_v4l2sink_sync_crop_fields (v4l2sink);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+  }
+}
+
+
+static void
+gst_v4l2sink_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstV4l2Sink *v4l2sink = GST_V4L2SINK (object);
+
+  if (!gst_v4l2_object_get_property_helper (v4l2sink->v4l2object,
+          prop_id, value, pspec)) {
+    switch (prop_id) {
+      case PROP_OVERLAY_TOP:
+        g_value_set_int (value, v4l2sink->overlay.top);
+        break;
+      case PROP_OVERLAY_LEFT:
+        g_value_set_int (value, v4l2sink->overlay.left);
+        break;
+      case PROP_OVERLAY_WIDTH:
+        g_value_set_uint (value, v4l2sink->overlay.width);
+        break;
+      case PROP_OVERLAY_HEIGHT:
+        g_value_set_uint (value, v4l2sink->overlay.height);
+        break;
+      case PROP_CROP_TOP:
+        g_value_set_int (value, v4l2sink->crop.top);
+        break;
+      case PROP_CROP_LEFT:
+        g_value_set_int (value, v4l2sink->crop.left);
+        break;
+      case PROP_CROP_WIDTH:
+        g_value_set_uint (value, v4l2sink->crop.width);
+        break;
+      case PROP_CROP_HEIGHT:
+        g_value_set_uint (value, v4l2sink->crop.height);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+  }
+}
+
+static GstStateChangeReturn
+gst_v4l2sink_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+  GstV4l2Sink *v4l2sink = GST_V4L2SINK (element);
+
+  GST_DEBUG_OBJECT (v4l2sink, "%d -> %d",
+      GST_STATE_TRANSITION_CURRENT (transition),
+      GST_STATE_TRANSITION_NEXT (transition));
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      /* open the device */
+      if (!gst_v4l2_object_open (v4l2sink->v4l2object))
+        return GST_STATE_CHANGE_FAILURE;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      if (!gst_v4l2_object_stop (v4l2sink->v4l2object))
+        return GST_STATE_CHANGE_FAILURE;
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      /* we need to call stop here too */
+      if (!gst_v4l2_object_stop (v4l2sink->v4l2object))
+        return GST_STATE_CHANGE_FAILURE;
+      /* close the device */
+      if (!gst_v4l2_object_close (v4l2sink->v4l2object))
+        return GST_STATE_CHANGE_FAILURE;
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+
+static GstCaps *
+gst_v4l2sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
+{
+  GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink);
+
+  if (!GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) {
+    /* FIXME: copy? */
+    GST_DEBUG_OBJECT (v4l2sink, "device is not open");
+    return gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (v4l2sink));
+  }
+
+
+  return gst_v4l2_object_get_caps (v4l2sink->v4l2object, filter);
+}
+
+static gboolean
+gst_v4l2sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
+{
+  GstV4l2Error error = GST_V4L2_ERROR_INIT;
+  GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink);
+  GstV4l2Object *obj = v4l2sink->v4l2object;
+
+  GST_DEBUG_OBJECT (v4l2sink, "caps: %" GST_PTR_FORMAT, caps);
+
+  if (!GST_V4L2_IS_OPEN (obj)) {
+    GST_DEBUG_OBJECT (v4l2sink, "device is not open");
+    return FALSE;
+  }
+
+  /* make sure the caps changed before doing anything */
+  if (gst_v4l2_object_caps_equal (obj, caps))
+    return TRUE;
+
+  if (!gst_v4l2_object_stop (obj))
+    goto stop_failed;
+
+  if (!gst_v4l2_object_set_format (obj, caps, &error))
+    goto invalid_format;
+
+  gst_v4l2sink_sync_overlay_fields (v4l2sink);
+  gst_v4l2sink_sync_crop_fields (v4l2sink);
+
+  GST_INFO_OBJECT (v4l2sink, "outputting buffers via mode %u", obj->mode);
+
+  v4l2sink->video_width = GST_V4L2_WIDTH (obj);
+  v4l2sink->video_height = GST_V4L2_HEIGHT (obj);
+
+  /* TODO: videosink width/height should be scaled according to
+   * pixel-aspect-ratio
+   */
+  GST_VIDEO_SINK_WIDTH (v4l2sink) = v4l2sink->video_width;
+  GST_VIDEO_SINK_HEIGHT (v4l2sink) = v4l2sink->video_height;
+
+  return TRUE;
+
+  /* ERRORS */
+stop_failed:
+  {
+    GST_DEBUG_OBJECT (v4l2sink, "failed to stop streaming");
+    return FALSE;
+  }
+invalid_format:
+  {
+    /* error already posted */
+    gst_v4l2_error (v4l2sink, &error);
+    GST_DEBUG_OBJECT (v4l2sink, "can't set format");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_v4l2sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
+{
+  GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink);
+  gboolean last_sample_enabled;
+
+  if (!gst_v4l2_object_propose_allocation (v4l2sink->v4l2object, query))
+    return FALSE;
+
+  g_object_get (bsink, "enable-last-sample", &last_sample_enabled, NULL);
+
+  if (last_sample_enabled) {
+    GstBufferPool *pool;
+    guint size, min, max;
+
+    gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
+
+    /* we need 1 more, otherwise we'll run out of buffers at preroll */
+    min++;
+    if (max < min)
+      max = min;
+
+    gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
+    gst_object_unref (pool);
+  }
+
+  return TRUE;
+}
+
+/* called after A/V sync to render frame */
+static GstFlowReturn
+gst_v4l2sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
+{
+  GstFlowReturn ret;
+  GstV4l2Sink *v4l2sink = GST_V4L2SINK (vsink);
+  GstV4l2Object *obj = v4l2sink->v4l2object;
+  GstBufferPool *bpool = GST_BUFFER_POOL (obj->pool);
+
+  GST_DEBUG_OBJECT (v4l2sink, "render buffer: %p", buf);
+
+  if (G_UNLIKELY (obj->pool == NULL))
+    goto not_negotiated;
+
+  if (G_UNLIKELY (!gst_buffer_pool_is_active (bpool))) {
+    GstStructure *config;
+
+    /* this pool was not activated, configure and activate */
+    GST_DEBUG_OBJECT (v4l2sink, "activating pool");
+
+    config = gst_buffer_pool_get_config (bpool);
+    gst_buffer_pool_config_add_option (config,
+        GST_BUFFER_POOL_OPTION_VIDEO_META);
+    gst_buffer_pool_set_config (bpool, config);
+
+    if (!gst_buffer_pool_set_active (bpool, TRUE))
+      goto activate_failed;
+  }
+
+  gst_buffer_ref (buf);
+again:
+  ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL_CAST (obj->pool),
+      &buf);
+  if (ret == GST_FLOW_FLUSHING) {
+    ret = gst_base_sink_wait_preroll (GST_BASE_SINK (vsink));
+    if (ret == GST_FLOW_OK)
+      goto again;
+  }
+  gst_buffer_unref (buf);
+
+  return ret;
+
+  /* ERRORS */
+not_negotiated:
+  {
+    GST_ERROR_OBJECT (v4l2sink, "not negotiated");
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+activate_failed:
+  {
+    GST_ELEMENT_ERROR (v4l2sink, RESOURCE, SETTINGS,
+        (_("Failed to allocated required memory.")),
+        ("Buffer pool activation failed"));
+    return GST_FLOW_ERROR;
+  }
+}
+
+static gboolean
+gst_v4l2sink_unlock (GstBaseSink * sink)
+{
+  GstV4l2Sink *v4l2sink = GST_V4L2SINK (sink);
+  return gst_v4l2_object_unlock (v4l2sink->v4l2object);
+}
+
+static gboolean
+gst_v4l2sink_unlock_stop (GstBaseSink * sink)
+{
+  GstV4l2Sink *v4l2sink = GST_V4L2SINK (sink);
+  return gst_v4l2_object_unlock_stop (v4l2sink->v4l2object);
+}
diff --git a/sys/v4l2/gstv4l2sink.h b/sys/v4l2/gstv4l2sink.h
new file mode 100644
index 0000000..33e97fb
--- /dev/null
+++ b/sys/v4l2/gstv4l2sink.h
@@ -0,0 +1,81 @@
+/* GStreamer
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc - http://www.ti.com/
+ *
+ * Description: V4L2 sink element
+ *  Created on: Jul 2, 2009
+ *      Author: Rob Clark <rob@ti.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GSTV4L2SINK_H__
+#define __GSTV4L2SINK_H__
+
+#include <gst/video/gstvideosink.h>
+#include <gstv4l2object.h>
+#include <gstv4l2bufferpool.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_V4L2SINK \
+  (gst_v4l2sink_get_type())
+#define GST_V4L2SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_V4L2SINK, GstV4l2Sink))
+#define GST_V4L2SINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_V4L2SINK, GstV4l2SinkClass))
+#define GST_IS_V4L2SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_V4L2SINK))
+#define GST_IS_V4L2SINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_V4L2SINK))
+
+typedef struct _GstV4l2Sink GstV4l2Sink;
+typedef struct _GstV4l2SinkClass GstV4l2SinkClass;
+
+
+struct _GstV4l2Sink {
+  GstVideoSink videosink;
+
+  /*< private >*/
+  GstV4l2Object * v4l2object;
+
+  gint video_width, video_height;      /* original (unscaled) video w/h */
+
+  /*
+   * field to store requested overlay and crop top/left/width/height props:
+   * note, could maybe be combined with 'vwin' field in GstV4l2Object?
+   */
+  struct v4l2_rect overlay, crop;
+
+  /*
+   * bitmask to track which overlay and crop fields user has requested by
+   * setting properties:
+   */
+  guint8 overlay_fields_set, crop_fields_set;
+};
+
+struct _GstV4l2SinkClass {
+  GstVideoSinkClass parent_class;
+
+  GList *v4l2_class_devices;
+};
+
+GType gst_v4l2sink_get_type(void);
+
+G_END_DECLS
+
+
+#endif /* __GSTV4L2SINK_H__ */
diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c
new file mode 100644
index 0000000..552e0d6
--- /dev/null
+++ b/sys/v4l2/gstv4l2src.c
@@ -0,0 +1,1064 @@
+/* GStreamer
+ *
+ * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *               2006 Edgard Lima <edgard.lima@gmail.com>
+ *
+ * gstv4l2src.c: Video4Linux2 source element
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-v4l2src
+ *
+ * v4l2src can be used to capture video from v4l2 devices, like webcams and tv
+ * cards.
+ *
+ * <refsect2>
+ * <title>Example launch lines</title>
+ * |[
+ * gst-launch-1.0 v4l2src ! xvimagesink
+ * ]| This pipeline shows the video captured from /dev/video0 tv card and for
+ * webcams.
+ * |[
+ * gst-launch-1.0 v4l2src ! jpegdec ! xvimagesink
+ * ]| This pipeline shows the video captured from a webcam that delivers jpeg
+ * images.
+ * </refsect2>
+ *
+ * Since 1.14, the use of libv4l2 has been disabled due to major bugs in the
+ * emulation layer. To enable usage of this library, set the environment
+ * variable GST_V4L2_USE_LIBV4L2=1.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <gst/video/gstvideometa.h>
+#include <gst/video/gstvideopool.h>
+
+#include "gstv4l2src.h"
+
+#include "gstv4l2colorbalance.h"
+#include "gstv4l2tuner.h"
+#include "gstv4l2vidorient.h"
+
+#include "gst/gst-i18n-plugin.h"
+
+GST_DEBUG_CATEGORY (v4l2src_debug);
+#define GST_CAT_DEFAULT v4l2src_debug
+
+#define DEFAULT_PROP_DEVICE   "/dev/video0"
+
+enum
+{
+  PROP_0,
+  V4L2_STD_OBJECT_PROPS,
+  PROP_LAST
+};
+
+/* signals and args */
+enum
+{
+  SIGNAL_PRE_SET_FORMAT,
+  LAST_SIGNAL
+};
+
+static guint gst_v4l2_signals[LAST_SIGNAL] = { 0 };
+
+GST_IMPLEMENT_V4L2_COLOR_BALANCE_METHODS (GstV4l2Src, gst_v4l2src);
+GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Src, gst_v4l2src);
+GST_IMPLEMENT_V4L2_VIDORIENT_METHODS (GstV4l2Src, gst_v4l2src);
+
+static void gst_v4l2src_uri_handler_init (gpointer g_iface,
+    gpointer iface_data);
+
+#define gst_v4l2src_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstV4l2Src, gst_v4l2src, GST_TYPE_PUSH_SRC,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_v4l2src_uri_handler_init);
+    G_IMPLEMENT_INTERFACE (GST_TYPE_TUNER, gst_v4l2src_tuner_interface_init);
+    G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
+        gst_v4l2src_color_balance_interface_init);
+    G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_ORIENTATION,
+        gst_v4l2src_video_orientation_interface_init));
+
+static void gst_v4l2src_finalize (GstV4l2Src * v4l2src);
+
+/* element methods */
+static GstStateChangeReturn gst_v4l2src_change_state (GstElement * element,
+    GstStateChange transition);
+
+/* basesrc methods */
+static gboolean gst_v4l2src_start (GstBaseSrc * src);
+static gboolean gst_v4l2src_unlock (GstBaseSrc * src);
+static gboolean gst_v4l2src_unlock_stop (GstBaseSrc * src);
+static gboolean gst_v4l2src_stop (GstBaseSrc * src);
+static GstCaps *gst_v4l2src_get_caps (GstBaseSrc * src, GstCaps * filter);
+static gboolean gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query);
+static gboolean gst_v4l2src_decide_allocation (GstBaseSrc * src,
+    GstQuery * query);
+static GstFlowReturn gst_v4l2src_create (GstPushSrc * src, GstBuffer ** out);
+static GstCaps *gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps,
+    GstStructure * pref_s);
+static gboolean gst_v4l2src_negotiate (GstBaseSrc * basesrc);
+
+static void gst_v4l2src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_v4l2src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void
+gst_v4l2src_class_init (GstV4l2SrcClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+  GstBaseSrcClass *basesrc_class;
+  GstPushSrcClass *pushsrc_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  element_class = GST_ELEMENT_CLASS (klass);
+  basesrc_class = GST_BASE_SRC_CLASS (klass);
+  pushsrc_class = GST_PUSH_SRC_CLASS (klass);
+
+  gobject_class->finalize = (GObjectFinalizeFunc) gst_v4l2src_finalize;
+  gobject_class->set_property = gst_v4l2src_set_property;
+  gobject_class->get_property = gst_v4l2src_get_property;
+
+  element_class->change_state = gst_v4l2src_change_state;
+
+  gst_v4l2_object_install_properties_helper (gobject_class,
+      DEFAULT_PROP_DEVICE);
+
+  /**
+   * GstV4l2Src::prepare-format:
+   * @v4l2src: the v4l2src instance
+   * @fd: the file descriptor of the current device
+   * @caps: the caps of the format being set
+   *
+   * This signal gets emitted before calling the v4l2 VIDIOC_S_FMT ioctl
+   * (set format). This allows for any custom configuration of the device to
+   * happen prior to the format being set.
+   * This is mostly useful for UVC H264 encoding cameras which need the H264
+   * Probe & Commit to happen prior to the normal Probe & Commit.
+   *
+   * Since: 0.10.32
+   */
+  gst_v4l2_signals[SIGNAL_PRE_SET_FORMAT] = g_signal_new ("prepare-format",
+      G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST,
+      0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_INT, GST_TYPE_CAPS);
+
+  gst_element_class_set_static_metadata (element_class,
+      "Video (video4linux2) Source", "Source/Video",
+      "Reads frames from a Video4Linux2 device",
+      "Edgard Lima <edgard.lima@gmail.com>, "
+      "Stefan Kost <ensonic@users.sf.net>");
+
+  gst_element_class_add_pad_template
+      (element_class,
+      gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+          gst_v4l2_object_get_all_caps ()));
+
+  basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_v4l2src_get_caps);
+  basesrc_class->start = GST_DEBUG_FUNCPTR (gst_v4l2src_start);
+  basesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_v4l2src_unlock);
+  basesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_v4l2src_unlock_stop);
+  basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2src_stop);
+  basesrc_class->query = GST_DEBUG_FUNCPTR (gst_v4l2src_query);
+  basesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_v4l2src_negotiate);
+  basesrc_class->decide_allocation =
+      GST_DEBUG_FUNCPTR (gst_v4l2src_decide_allocation);
+
+  pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_v4l2src_create);
+
+  klass->v4l2_class_devices = NULL;
+
+  GST_DEBUG_CATEGORY_INIT (v4l2src_debug, "v4l2src", 0, "V4L2 source element");
+}
+
+static void
+gst_v4l2src_init (GstV4l2Src * v4l2src)
+{
+  /* fixme: give an update_fps_function */
+  v4l2src->v4l2object = gst_v4l2_object_new (GST_ELEMENT (v4l2src),
+      GST_OBJECT (GST_BASE_SRC_PAD (v4l2src)), V4L2_BUF_TYPE_VIDEO_CAPTURE,
+      DEFAULT_PROP_DEVICE, gst_v4l2_get_input, gst_v4l2_set_input, NULL);
+
+  /* Avoid the slow probes */
+  v4l2src->v4l2object->skip_try_fmt_probes = TRUE;
+
+  gst_base_src_set_format (GST_BASE_SRC (v4l2src), GST_FORMAT_TIME);
+  gst_base_src_set_live (GST_BASE_SRC (v4l2src), TRUE);
+}
+
+
+static void
+gst_v4l2src_finalize (GstV4l2Src * v4l2src)
+{
+  gst_v4l2_object_destroy (v4l2src->v4l2object);
+
+  G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (v4l2src));
+}
+
+
+static void
+gst_v4l2src_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstV4l2Src *v4l2src = GST_V4L2SRC (object);
+
+  if (!gst_v4l2_object_set_property_helper (v4l2src->v4l2object,
+          prop_id, value, pspec)) {
+    switch (prop_id) {
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+  }
+}
+
+static void
+gst_v4l2src_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstV4l2Src *v4l2src = GST_V4L2SRC (object);
+
+  if (!gst_v4l2_object_get_property_helper (v4l2src->v4l2object,
+          prop_id, value, pspec)) {
+    switch (prop_id) {
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+  }
+}
+
+struct PreferedCapsInfo
+{
+  gint width;
+  gint height;
+  gint fps_n;
+  gint fps_d;
+};
+
+static gboolean
+gst_vl42_src_fixate_fields (GQuark field_id, GValue * value, gpointer user_data)
+{
+  GstStructure *s = user_data;
+
+  if (field_id == g_quark_from_string ("interlace-mode"))
+    return TRUE;
+
+  if (field_id == g_quark_from_string ("colorimetry"))
+    return TRUE;
+
+  gst_structure_fixate_field (s, g_quark_to_string (field_id));
+
+  return TRUE;
+}
+
+static void
+gst_v4l2_src_fixate_struct_with_preference (GstStructure * s,
+    struct PreferedCapsInfo *pref)
+{
+  if (gst_structure_has_field (s, "width"))
+    gst_structure_fixate_field_nearest_int (s, "width", pref->width);
+
+  if (gst_structure_has_field (s, "height"))
+    gst_structure_fixate_field_nearest_int (s, "height", pref->height);
+
+  if (gst_structure_has_field (s, "framerate"))
+    gst_structure_fixate_field_nearest_fraction (s, "framerate", pref->fps_n,
+        pref->fps_d);
+
+  /* Finally, fixate everything else except the interlace-mode and colorimetry
+   * which still need further negotiation as it wasn't probed */
+  gst_structure_map_in_place (s, gst_vl42_src_fixate_fields, s);
+}
+
+static void
+gst_v4l2_src_parse_fixed_struct (GstStructure * s,
+    gint * width, gint * height, gint * fps_n, gint * fps_d)
+{
+  if (gst_structure_has_field (s, "width") && width)
+    gst_structure_get_int (s, "width", width);
+
+  if (gst_structure_has_field (s, "height") && height)
+    gst_structure_get_int (s, "height", height);
+
+  if (gst_structure_has_field (s, "framerate") && fps_n && fps_d)
+    gst_structure_get_fraction (s, "framerate", fps_n, fps_d);
+}
+
+/* TODO Consider framerate */
+static gint
+gst_v4l2src_fixed_caps_compare (GstStructure * a, GstStructure * b,
+    struct PreferedCapsInfo *pref)
+{
+  gint aw = G_MAXINT, ah = G_MAXINT, ad = G_MAXINT;
+  gint bw = G_MAXINT, bh = G_MAXINT, bd = G_MAXINT;
+  gint ret;
+
+  gst_v4l2_src_parse_fixed_struct (a, &aw, &ah, NULL, NULL);
+  gst_v4l2_src_parse_fixed_struct (b, &bw, &bh, NULL, NULL);
+
+  /* When both are smaller then pref, just append to the end */
+  if ((bw < pref->width || bh < pref->height)
+      && (aw < pref->width || ah < pref->height)) {
+    ret = 1;
+    goto done;
+  }
+
+  /* If a is smaller then pref and not b, then a goes after b */
+  if (aw < pref->width || ah < pref->height) {
+    ret = 1;
+    goto done;
+  }
+
+  /* If b is smaller then pref and not a, then a goes before b */
+  if (bw < pref->width || bh < pref->height) {
+    ret = -1;
+    goto done;
+  }
+
+  /* Both are larger or equal to the preference, prefer the smallest */
+  ad = MAX (1, aw - pref->width) * MAX (1, ah - pref->height);
+  bd = MAX (1, bw - pref->width) * MAX (1, bh - pref->height);
+
+  /* Adjust slightly in case width/height matched the preference */
+  if (aw == pref->width)
+    ad -= 1;
+
+  if (ah == pref->height)
+    ad -= 1;
+
+  if (bw == pref->width)
+    bd -= 1;
+
+  if (bh == pref->height)
+    bd -= 1;
+
+  /* If the choices are equivalent, maintain the order */
+  if (ad == bd)
+    ret = 1;
+  else
+    ret = ad - bd;
+
+done:
+  GST_TRACE ("Placing %ix%i (%s) %s %ix%i (%s)", aw, ah,
+      gst_structure_get_string (a, "format"), ret > 0 ? "after" : "before", bw,
+      bh, gst_structure_get_string (b, "format"));
+  return ret;
+}
+
+static gboolean
+gst_v4l2src_set_format (GstV4l2Src * v4l2src, GstCaps * caps,
+    GstV4l2Error * error)
+{
+  GstV4l2Object *obj;
+
+  obj = v4l2src->v4l2object;
+
+  /* make sure we stop capturing and dealloc buffers */
+  if (!gst_v4l2_object_stop (obj))
+    return FALSE;
+
+  g_signal_emit (v4l2src, gst_v4l2_signals[SIGNAL_PRE_SET_FORMAT], 0,
+      v4l2src->v4l2object->video_fd, caps);
+
+  return gst_v4l2_object_set_format (obj, caps, error);
+}
+
+static GstCaps *
+gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps, GstStructure * pref_s)
+{
+  /* Let's prefer a good resolutiion as of today's standard. */
+  struct PreferedCapsInfo pref = {
+    3840, 2160, 120, 1
+  };
+  GstV4l2Src *v4l2src = GST_V4L2SRC (basesrc);
+  GstV4l2Object *obj = v4l2src->v4l2object;
+  GList *caps_list = NULL;
+  GstStructure *s;
+  gint i = G_MAXINT;
+  GstV4l2Error error = GST_V4L2_ERROR_INIT;
+  GstCaps *fcaps = NULL;
+
+  GST_DEBUG_OBJECT (basesrc, "fixating caps %" GST_PTR_FORMAT, caps);
+
+  caps = gst_caps_make_writable (caps);
+
+  /* We consider the first structure from peercaps to be a preference. This is
+   * useful for matching a reported native display, or simply to avoid
+   * transformation to happen downstream. */
+  if (pref_s) {
+    pref_s = gst_structure_copy (pref_s);
+    gst_v4l2_src_fixate_struct_with_preference (pref_s, &pref);
+    gst_v4l2_src_parse_fixed_struct (pref_s, &pref.width, &pref.height,
+        &pref.fps_n, &pref.fps_d);
+    gst_structure_free (pref_s);
+  }
+
+  GST_DEBUG_OBJECT (basesrc, "Prefered size %ix%i", pref.width, pref.height);
+
+  /* Sort the structures to get the caps that is nearest to our preferences,
+   * first */
+  while ((s = gst_caps_steal_structure (caps, 0))) {
+    gst_v4l2_src_fixate_struct_with_preference (s, &pref);
+    caps_list = g_list_insert_sorted_with_data (caps_list, s,
+        (GCompareDataFunc) gst_v4l2src_fixed_caps_compare, &pref);
+  }
+
+  while (caps_list) {
+    s = caps_list->data;
+    caps_list = g_list_delete_link (caps_list, caps_list);
+    gst_caps_append_structure (caps, s);
+  }
+
+  GST_DEBUG_OBJECT (basesrc, "sorted and normalized caps %" GST_PTR_FORMAT,
+      caps);
+
+  /* Each structure in the caps has been fixated, except for the
+   * interlace-mode and colorimetry. Now normalize the caps so we can
+   * enumerate the possibilities */
+  caps = gst_caps_normalize (caps);
+
+  for (i = 0; i < gst_caps_get_size (caps); ++i) {
+    gst_v4l2_clear_error (&error);
+    if (fcaps)
+      gst_caps_unref (fcaps);
+
+    fcaps = gst_caps_copy_nth (caps, i);
+
+    if (GST_V4L2_IS_ACTIVE (obj)) {
+      /* Just check if the format is acceptable, once we know
+       * no buffers should be outstanding we try S_FMT.
+       *
+       * Basesrc will do an allocation query that
+       * should indirectly reclaim buffers, after that we can
+       * set the format and then configure our pool */
+      if (gst_v4l2_object_try_format (obj, fcaps, &error)) {
+        /* make sure the caps changed before doing anything */
+        if (gst_v4l2_object_caps_equal (obj, fcaps))
+          break;
+
+        v4l2src->renegotiation_adjust = v4l2src->offset + 1;
+        v4l2src->pending_set_fmt = TRUE;
+        break;
+      }
+    } else {
+      if (gst_v4l2src_set_format (v4l2src, fcaps, &error))
+        break;
+    }
+
+    /* Only EIVAL make sense, report any other errors, this way we don't keep
+     * probing if the device got disconnected, or if it's firmware stopped
+     * responding */
+    if (error.error->code != GST_RESOURCE_ERROR_SETTINGS) {
+      i = G_MAXINT;
+      break;
+    }
+  }
+
+  if (i >= gst_caps_get_size (caps)) {
+    gst_v4l2_error (v4l2src, &error);
+    if (fcaps)
+      gst_caps_unref (fcaps);
+    gst_caps_unref (caps);
+    return NULL;
+  }
+
+  gst_caps_unref (caps);
+
+  GST_DEBUG_OBJECT (basesrc, "fixated caps %" GST_PTR_FORMAT, fcaps);
+
+  return fcaps;
+}
+
+static gboolean
+gst_v4l2src_negotiate (GstBaseSrc * basesrc)
+{
+  GstCaps *thiscaps;
+  GstCaps *caps = NULL;
+  GstCaps *peercaps = NULL;
+  gboolean result = FALSE;
+
+  /* first see what is possible on our source pad */
+  thiscaps = gst_pad_query_caps (GST_BASE_SRC_PAD (basesrc), NULL);
+  GST_DEBUG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps);
+
+  /* nothing or anything is allowed, we're done */
+  if (thiscaps == NULL || gst_caps_is_any (thiscaps))
+    goto no_nego_needed;
+
+  /* get the peer caps without a filter as we'll filter ourselves later on */
+  peercaps = gst_pad_peer_query_caps (GST_BASE_SRC_PAD (basesrc), NULL);
+  GST_DEBUG_OBJECT (basesrc, "caps of peer: %" GST_PTR_FORMAT, peercaps);
+  if (peercaps && !gst_caps_is_any (peercaps)) {
+    /* Prefer the first caps we are compatible with that the peer proposed */
+    caps = gst_caps_intersect_full (peercaps, thiscaps,
+        GST_CAPS_INTERSECT_FIRST);
+
+    GST_DEBUG_OBJECT (basesrc, "intersect: %" GST_PTR_FORMAT, caps);
+
+    gst_caps_unref (thiscaps);
+  } else {
+    /* no peer or peer have ANY caps, work with our own caps then */
+    caps = thiscaps;
+  }
+
+  if (caps) {
+    /* now fixate */
+    if (!gst_caps_is_empty (caps)) {
+      GstStructure *pref = NULL;
+
+      if (peercaps && !gst_caps_is_any (peercaps))
+        pref = gst_caps_get_structure (peercaps, 0);
+
+      caps = gst_v4l2src_fixate (basesrc, caps, pref);
+
+      /* Fixating may fail as we now set the selected format */
+      if (!caps) {
+        result = FALSE;
+        goto done;
+      }
+
+      GST_DEBUG_OBJECT (basesrc, "fixated to: %" GST_PTR_FORMAT, caps);
+
+      if (gst_caps_is_any (caps)) {
+        /* hmm, still anything, so element can do anything and
+         * nego is not needed */
+        result = TRUE;
+      } else if (gst_caps_is_fixed (caps)) {
+        /* yay, fixed caps, use those then */
+        result = gst_base_src_set_caps (basesrc, caps);
+      }
+    }
+    gst_caps_unref (caps);
+  }
+
+done:
+  if (peercaps)
+    gst_caps_unref (peercaps);
+
+  return result;
+
+no_nego_needed:
+  {
+    GST_DEBUG_OBJECT (basesrc, "no negotiation needed");
+    if (thiscaps)
+      gst_caps_unref (thiscaps);
+    return TRUE;
+  }
+}
+
+static GstCaps *
+gst_v4l2src_get_caps (GstBaseSrc * src, GstCaps * filter)
+{
+  GstV4l2Src *v4l2src;
+  GstV4l2Object *obj;
+
+  v4l2src = GST_V4L2SRC (src);
+  obj = v4l2src->v4l2object;
+
+  if (!GST_V4L2_IS_OPEN (obj)) {
+    return gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (v4l2src));
+  }
+
+  return gst_v4l2_object_get_caps (obj, filter);
+}
+
+static gboolean
+gst_v4l2src_decide_allocation (GstBaseSrc * bsrc, GstQuery * query)
+{
+  GstV4l2Src *src = GST_V4L2SRC (bsrc);
+  gboolean ret = TRUE;
+
+  if (src->pending_set_fmt) {
+    GstCaps *caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (bsrc));
+    GstV4l2Error error = GST_V4L2_ERROR_INIT;
+
+    caps = gst_caps_make_writable (caps);
+    if (!(ret = gst_v4l2src_set_format (src, caps, &error)))
+      gst_v4l2_error (src, &error);
+
+    gst_caps_unref (caps);
+    src->pending_set_fmt = FALSE;
+  } else if (gst_buffer_pool_is_active (src->v4l2object->pool)) {
+    /* Trick basesrc into not deactivating the active pool. Renegotiating here
+     * would otherwise turn off and on the camera. */
+    GstAllocator *allocator;
+    GstAllocationParams params;
+    GstBufferPool *pool;
+
+    gst_base_src_get_allocator (bsrc, &allocator, &params);
+    pool = gst_base_src_get_buffer_pool (bsrc);
+
+    if (gst_query_get_n_allocation_params (query))
+      gst_query_set_nth_allocation_param (query, 0, allocator, &params);
+    else
+      gst_query_add_allocation_param (query, allocator, &params);
+
+    if (gst_query_get_n_allocation_pools (query))
+      gst_query_set_nth_allocation_pool (query, 0, pool,
+          src->v4l2object->info.size, 1, 0);
+    else
+      gst_query_add_allocation_pool (query, pool, src->v4l2object->info.size, 1,
+          0);
+
+    if (pool)
+      gst_object_unref (pool);
+    if (allocator)
+      gst_object_unref (allocator);
+
+    return GST_BASE_SRC_CLASS (parent_class)->decide_allocation (bsrc, query);
+  }
+
+  if (ret) {
+    ret = gst_v4l2_object_decide_allocation (src->v4l2object, query);
+    if (ret)
+      ret = GST_BASE_SRC_CLASS (parent_class)->decide_allocation (bsrc, query);
+  }
+
+  if (ret) {
+    if (!gst_buffer_pool_set_active (src->v4l2object->pool, TRUE))
+      goto activate_failed;
+  }
+
+  return ret;
+
+activate_failed:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
+        (_("Failed to allocate required memory.")),
+        ("Buffer pool activation failed"));
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query)
+{
+  GstV4l2Src *src;
+  GstV4l2Object *obj;
+  gboolean res = FALSE;
+
+  src = GST_V4L2SRC (bsrc);
+  obj = src->v4l2object;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_LATENCY:{
+      GstClockTime min_latency, max_latency;
+      guint32 fps_n, fps_d;
+      guint num_buffers = 0;
+
+      /* device must be open */
+      if (!GST_V4L2_IS_OPEN (obj)) {
+        GST_WARNING_OBJECT (src,
+            "Can't give latency since device isn't open !");
+        goto done;
+      }
+
+      fps_n = GST_V4L2_FPS_N (obj);
+      fps_d = GST_V4L2_FPS_D (obj);
+
+      /* we must have a framerate */
+      if (fps_n <= 0 || fps_d <= 0) {
+        GST_WARNING_OBJECT (src,
+            "Can't give latency since framerate isn't fixated !");
+        goto done;
+      }
+
+      /* min latency is the time to capture one frame */
+      min_latency = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
+
+      /* max latency is total duration of the frame buffer */
+      if (obj->pool != NULL)
+        num_buffers = GST_V4L2_BUFFER_POOL_CAST (obj->pool)->max_latency;
+
+      if (num_buffers == 0)
+        max_latency = -1;
+      else
+        max_latency = num_buffers * min_latency;
+
+      GST_DEBUG_OBJECT (bsrc,
+          "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
+
+      /* we are always live, the min latency is 1 frame and the max latency is
+       * the complete buffer of frames. */
+      gst_query_set_latency (query, TRUE, min_latency, max_latency);
+
+      res = TRUE;
+      break;
+    }
+    default:
+      res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
+      break;
+  }
+
+done:
+
+  return res;
+}
+
+/* start and stop are not symmetric -- start will open the device, but not start
+ * capture. it's setcaps that will start capture, which is called via basesrc's
+ * negotiate method. stop will both stop capture and close the device.
+ */
+static gboolean
+gst_v4l2src_start (GstBaseSrc * src)
+{
+  GstV4l2Src *v4l2src = GST_V4L2SRC (src);
+
+  v4l2src->offset = 0;
+  v4l2src->renegotiation_adjust = 0;
+
+  /* activate settings for first frame */
+  v4l2src->ctrl_time = 0;
+  gst_object_sync_values (GST_OBJECT (src), v4l2src->ctrl_time);
+
+  v4l2src->has_bad_timestamp = FALSE;
+  v4l2src->last_timestamp = 0;
+
+  return TRUE;
+}
+
+static gboolean
+gst_v4l2src_unlock (GstBaseSrc * src)
+{
+  GstV4l2Src *v4l2src = GST_V4L2SRC (src);
+  return gst_v4l2_object_unlock (v4l2src->v4l2object);
+}
+
+static gboolean
+gst_v4l2src_unlock_stop (GstBaseSrc * src)
+{
+  GstV4l2Src *v4l2src = GST_V4L2SRC (src);
+
+  v4l2src->last_timestamp = 0;
+
+  return gst_v4l2_object_unlock_stop (v4l2src->v4l2object);
+}
+
+static gboolean
+gst_v4l2src_stop (GstBaseSrc * src)
+{
+  GstV4l2Src *v4l2src = GST_V4L2SRC (src);
+  GstV4l2Object *obj = v4l2src->v4l2object;
+
+  if (GST_V4L2_IS_ACTIVE (obj)) {
+    if (!gst_v4l2_object_stop (obj))
+      return FALSE;
+  }
+
+  v4l2src->pending_set_fmt = FALSE;
+
+  return TRUE;
+}
+
+static GstStateChangeReturn
+gst_v4l2src_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+  GstV4l2Src *v4l2src = GST_V4L2SRC (element);
+  GstV4l2Object *obj = v4l2src->v4l2object;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      /* open the device */
+      if (!gst_v4l2_object_open (obj))
+        return GST_STATE_CHANGE_FAILURE;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      /* close the device */
+      if (!gst_v4l2_object_close (obj))
+        return GST_STATE_CHANGE_FAILURE;
+
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf)
+{
+  GstV4l2Src *v4l2src = GST_V4L2SRC (src);
+  GstV4l2Object *obj = v4l2src->v4l2object;
+  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL_CAST (obj->pool);
+  GstFlowReturn ret;
+  GstClock *clock;
+  GstClockTime abs_time, base_time, timestamp, duration;
+  GstClockTime delay;
+  GstMessage *qos_msg;
+
+  do {
+    ret = GST_BASE_SRC_CLASS (parent_class)->alloc (GST_BASE_SRC (src), 0,
+        obj->info.size, buf);
+
+    if (G_UNLIKELY (ret != GST_FLOW_OK))
+      goto alloc_failed;
+
+    ret = gst_v4l2_buffer_pool_process (pool, buf);
+
+  } while (ret == GST_V4L2_FLOW_CORRUPTED_BUFFER);
+
+  if (G_UNLIKELY (ret != GST_FLOW_OK))
+    goto error;
+
+  timestamp = GST_BUFFER_TIMESTAMP (*buf);
+  duration = obj->duration;
+
+  /* timestamps, LOCK to get clock and base time. */
+  /* FIXME: element clock and base_time is rarely changing */
+  GST_OBJECT_LOCK (v4l2src);
+  if ((clock = GST_ELEMENT_CLOCK (v4l2src))) {
+    /* we have a clock, get base time and ref clock */
+    base_time = GST_ELEMENT (v4l2src)->base_time;
+    gst_object_ref (clock);
+  } else {
+    /* no clock, can't set timestamps */
+    base_time = GST_CLOCK_TIME_NONE;
+  }
+  GST_OBJECT_UNLOCK (v4l2src);
+
+  /* sample pipeline clock */
+  if (clock) {
+    abs_time = gst_clock_get_time (clock);
+    gst_object_unref (clock);
+  } else {
+    abs_time = GST_CLOCK_TIME_NONE;
+  }
+
+retry:
+  if (!v4l2src->has_bad_timestamp && timestamp != GST_CLOCK_TIME_NONE) {
+    struct timespec now;
+    GstClockTime gstnow;
+
+    /* v4l2 specs say to use the system time although many drivers switched to
+     * the more desirable monotonic time. We first try to use the monotonic time
+     * and see how that goes */
+    clock_gettime (CLOCK_MONOTONIC, &now);
+    gstnow = GST_TIMESPEC_TO_TIME (now);
+
+    if (timestamp > gstnow || (gstnow - timestamp) > (10 * GST_SECOND)) {
+      GTimeVal now;
+
+      /* very large diff, fall back to system time */
+      g_get_current_time (&now);
+      gstnow = GST_TIMEVAL_TO_TIME (now);
+    }
+
+    /* Detect buggy drivers here, and stop using their timestamp. Failing any
+     * of these condition would imply a very buggy driver:
+     *   - Timestamp in the future
+     *   - Timestamp is going backward compare to last seen timestamp
+     *   - Timestamp is jumping forward for less then a frame duration
+     *   - Delay is bigger then the actual timestamp
+     * */
+    if (timestamp > gstnow) {
+      GST_WARNING_OBJECT (v4l2src,
+          "Timestamp in the future detected, ignoring driver timestamps");
+      v4l2src->has_bad_timestamp = TRUE;
+      goto retry;
+    }
+
+    if (v4l2src->last_timestamp > timestamp) {
+      GST_WARNING_OBJECT (v4l2src,
+          "Timestamp going backward, ignoring driver timestamps");
+      v4l2src->has_bad_timestamp = TRUE;
+      goto retry;
+    }
+
+    delay = gstnow - timestamp;
+
+    if (delay > timestamp) {
+      GST_WARNING_OBJECT (v4l2src,
+          "Timestamp does not correlate with any clock, ignoring driver timestamps");
+      v4l2src->has_bad_timestamp = TRUE;
+      goto retry;
+    }
+
+    /* Save last timestamp for sanity checks */
+    v4l2src->last_timestamp = timestamp;
+
+    GST_DEBUG_OBJECT (v4l2src, "ts: %" GST_TIME_FORMAT " now %" GST_TIME_FORMAT
+        " delay %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp),
+        GST_TIME_ARGS (gstnow), GST_TIME_ARGS (delay));
+  } else {
+    /* we assume 1 frame latency otherwise */
+    if (GST_CLOCK_TIME_IS_VALID (duration))
+      delay = duration;
+    else
+      delay = 0;
+  }
+
+  /* set buffer metadata */
+
+  if (G_LIKELY (abs_time != GST_CLOCK_TIME_NONE)) {
+    /* the time now is the time of the clock minus the base time */
+    timestamp = abs_time - base_time;
+
+    /* adjust for delay in the device */
+    if (timestamp > delay)
+      timestamp -= delay;
+    else
+      timestamp = 0;
+  } else {
+    timestamp = GST_CLOCK_TIME_NONE;
+  }
+
+  /* activate settings for next frame */
+  if (GST_CLOCK_TIME_IS_VALID (duration)) {
+    v4l2src->ctrl_time += duration;
+  } else {
+    /* this is not very good (as it should be the next timestamp),
+     * still good enough for linear fades (as long as it is not -1)
+     */
+    v4l2src->ctrl_time = timestamp;
+  }
+  gst_object_sync_values (GST_OBJECT (src), v4l2src->ctrl_time);
+
+  GST_INFO_OBJECT (src, "sync to %" GST_TIME_FORMAT " out ts %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (v4l2src->ctrl_time), GST_TIME_ARGS (timestamp));
+
+  /* use generated offset values only if there are not already valid ones
+   * set by the v4l2 device */
+  if (!GST_BUFFER_OFFSET_IS_VALID (*buf)
+      || !GST_BUFFER_OFFSET_END_IS_VALID (*buf)) {
+    GST_BUFFER_OFFSET (*buf) = v4l2src->offset++;
+    GST_BUFFER_OFFSET_END (*buf) = v4l2src->offset;
+  } else {
+    /* adjust raw v4l2 device sequence, will restart at null in case of renegotiation
+     * (streamoff/streamon) */
+    GST_BUFFER_OFFSET (*buf) += v4l2src->renegotiation_adjust;
+    GST_BUFFER_OFFSET_END (*buf) += v4l2src->renegotiation_adjust;
+    /* check for frame loss with given (from v4l2 device) buffer offset */
+    if ((v4l2src->offset != 0)
+        && (GST_BUFFER_OFFSET (*buf) != (v4l2src->offset + 1))) {
+      guint64 lost_frame_count = GST_BUFFER_OFFSET (*buf) - v4l2src->offset - 1;
+      GST_WARNING_OBJECT (v4l2src,
+          "lost frames detected: count = %" G_GUINT64_FORMAT " - ts: %"
+          GST_TIME_FORMAT, lost_frame_count, GST_TIME_ARGS (timestamp));
+
+      qos_msg = gst_message_new_qos (GST_OBJECT_CAST (v4l2src), TRUE,
+          GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, timestamp,
+          GST_CLOCK_TIME_IS_VALID (duration) ? lost_frame_count *
+          duration : GST_CLOCK_TIME_NONE);
+      gst_element_post_message (GST_ELEMENT_CAST (v4l2src), qos_msg);
+
+    }
+    v4l2src->offset = GST_BUFFER_OFFSET (*buf);
+  }
+
+  GST_BUFFER_TIMESTAMP (*buf) = timestamp;
+  GST_BUFFER_DURATION (*buf) = duration;
+
+  return ret;
+
+  /* ERROR */
+alloc_failed:
+  {
+    if (ret != GST_FLOW_FLUSHING)
+      GST_ELEMENT_ERROR (src, RESOURCE, NO_SPACE_LEFT,
+          ("Failed to allocate a buffer"), (NULL));
+    return ret;
+  }
+error:
+  {
+    gst_buffer_replace (buf, NULL);
+    if (ret == GST_V4L2_FLOW_LAST_BUFFER) {
+      GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
+          ("Driver returned a buffer with no payload, this most likely "
+              "indicate a bug in the driver."), (NULL));
+      ret = GST_FLOW_ERROR;
+    } else {
+      GST_DEBUG_OBJECT (src, "error processing buffer %d (%s)", ret,
+          gst_flow_get_name (ret));
+    }
+    return ret;
+  }
+}
+
+
+/* GstURIHandler interface */
+static GstURIType
+gst_v4l2src_uri_get_type (GType type)
+{
+  return GST_URI_SRC;
+}
+
+static const gchar *const *
+gst_v4l2src_uri_get_protocols (GType type)
+{
+  static const gchar *protocols[] = { "v4l2", NULL };
+
+  return protocols;
+}
+
+static gchar *
+gst_v4l2src_uri_get_uri (GstURIHandler * handler)
+{
+  GstV4l2Src *v4l2src = GST_V4L2SRC (handler);
+
+  if (v4l2src->v4l2object->videodev != NULL) {
+    return g_strdup_printf ("v4l2://%s", v4l2src->v4l2object->videodev);
+  }
+
+  return g_strdup ("v4l2://");
+}
+
+static gboolean
+gst_v4l2src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+    GError ** error)
+{
+  GstV4l2Src *v4l2src = GST_V4L2SRC (handler);
+  const gchar *device = DEFAULT_PROP_DEVICE;
+
+  if (strcmp (uri, "v4l2://") != 0) {
+    device = uri + 7;
+  }
+  g_object_set (v4l2src, "device", device, NULL);
+
+  return TRUE;
+}
+
+
+static void
+gst_v4l2src_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+  iface->get_type = gst_v4l2src_uri_get_type;
+  iface->get_protocols = gst_v4l2src_uri_get_protocols;
+  iface->get_uri = gst_v4l2src_uri_get_uri;
+  iface->set_uri = gst_v4l2src_uri_set_uri;
+}
diff --git a/sys/v4l2/gstv4l2src.h b/sys/v4l2/gstv4l2src.h
new file mode 100644
index 0000000..cb7f751
--- /dev/null
+++ b/sys/v4l2/gstv4l2src.h
@@ -0,0 +1,83 @@
+/* GStreamer
+ *
+ * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *               2006 Edgard Lima <edgard.lima@gmail.com>
+ *
+ * gstv4l2src.h: BT8x8/V4L2 source element
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_V4L2SRC_H__
+#define __GST_V4L2SRC_H__
+
+#include <gstv4l2object.h>
+#include <gstv4l2bufferpool.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_V4L2SRC \
+  (gst_v4l2src_get_type())
+#define GST_V4L2SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2SRC,GstV4l2Src))
+#define GST_V4L2SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2SRC,GstV4l2SrcClass))
+#define GST_IS_V4L2SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2SRC))
+#define GST_IS_V4L2SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2SRC))
+
+typedef struct _GstV4l2Src GstV4l2Src;
+typedef struct _GstV4l2SrcClass GstV4l2SrcClass;
+
+/**
+ * GstV4l2Src:
+ *
+ * Opaque object.
+ */
+struct _GstV4l2Src
+{
+  GstPushSrc pushsrc;
+
+  /*< private >*/
+  GstV4l2Object * v4l2object;
+
+  guint64 offset;
+
+  /* offset adjust after renegotiation */
+  guint64 renegotiation_adjust;
+
+  GstClockTime ctrl_time;
+
+  gboolean pending_set_fmt;
+
+  /* Timestamp sanity check */
+  GstClockTime last_timestamp;
+  gboolean has_bad_timestamp;
+};
+
+struct _GstV4l2SrcClass
+{
+  GstPushSrcClass parent_class;
+
+  GList *v4l2_class_devices;
+};
+
+GType gst_v4l2src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_V4L2SRC_H__ */
diff --git a/sys/v4l2/gstv4l2transform.c b/sys/v4l2/gstv4l2transform.c
new file mode 100644
index 0000000..33052a8
--- /dev/null
+++ b/sys/v4l2/gstv4l2transform.c
@@ -0,0 +1,1204 @@
+/*
+ * Copyright (C) 2014 Collabora Ltd.
+ *     Author: Nicolas Dufresne <nicolas.dufresne@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gstv4l2object.h"
+#include "gstv4l2transform.h"
+
+#include <string.h>
+#include <gst/gst-i18n-plugin.h>
+
+#define DEFAULT_PROP_DEVICE "/dev/video10"
+
+#define V4L2_TRANSFORM_QUARK \
+	g_quark_from_static_string("gst-v4l2-transform-info")
+
+GST_DEBUG_CATEGORY_STATIC (gst_v4l2_transform_debug);
+#define GST_CAT_DEFAULT gst_v4l2_transform_debug
+
+
+enum
+{
+  PROP_0,
+  V4L2_STD_OBJECT_PROPS
+};
+
+typedef struct
+{
+  gchar *device;
+  GstCaps *sink_caps;
+  GstCaps *src_caps;
+} GstV4l2TransformCData;
+
+#define gst_v4l2_transform_parent_class parent_class
+G_DEFINE_ABSTRACT_TYPE (GstV4l2Transform, gst_v4l2_transform,
+    GST_TYPE_BASE_TRANSFORM);
+
+static void
+gst_v4l2_transform_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstV4l2Transform *self = GST_V4L2_TRANSFORM (object);
+
+  switch (prop_id) {
+    case PROP_OUTPUT_IO_MODE:
+      gst_v4l2_object_set_property_helper (self->v4l2output, prop_id, value,
+          pspec);
+      break;
+    case PROP_CAPTURE_IO_MODE:
+      gst_v4l2_object_set_property_helper (self->v4l2capture, prop_id, value,
+          pspec);
+      break;
+
+      /* By default, only set on output */
+    default:
+      if (!gst_v4l2_object_set_property_helper (self->v4l2output,
+              prop_id, value, pspec)) {
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      }
+      break;
+  }
+}
+
+static void
+gst_v4l2_transform_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstV4l2Transform *self = GST_V4L2_TRANSFORM (object);
+
+  switch (prop_id) {
+    case PROP_OUTPUT_IO_MODE:
+      gst_v4l2_object_get_property_helper (self->v4l2output, prop_id, value,
+          pspec);
+      break;
+    case PROP_CAPTURE_IO_MODE:
+      gst_v4l2_object_get_property_helper (self->v4l2capture, prop_id, value,
+          pspec);
+      break;
+
+      /* By default read from output */
+    default:
+      if (!gst_v4l2_object_get_property_helper (self->v4l2output,
+              prop_id, value, pspec)) {
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      }
+      break;
+  }
+}
+
+static gboolean
+gst_v4l2_transform_open (GstV4l2Transform * self)
+{
+  GST_DEBUG_OBJECT (self, "Opening");
+
+  if (!gst_v4l2_object_open (self->v4l2output))
+    goto failure;
+
+  if (!gst_v4l2_object_open_shared (self->v4l2capture, self->v4l2output))
+    goto failure;
+
+  self->probed_sinkcaps = gst_v4l2_object_get_caps (self->v4l2output,
+      gst_v4l2_object_get_raw_caps ());
+
+  if (gst_caps_is_empty (self->probed_sinkcaps))
+    goto no_input_format;
+
+  self->probed_srccaps = gst_v4l2_object_get_caps (self->v4l2capture,
+      gst_v4l2_object_get_raw_caps ());
+
+  if (gst_caps_is_empty (self->probed_srccaps))
+    goto no_output_format;
+
+  return TRUE;
+
+no_input_format:
+  GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+      (_("Converter on device %s has no supported input format"),
+          self->v4l2output->videodev), (NULL));
+  goto failure;
+
+
+no_output_format:
+  GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+      (_("Converter on device %s has no supported output format"),
+          self->v4l2output->videodev), (NULL));
+  goto failure;
+
+failure:
+  if (GST_V4L2_IS_OPEN (self->v4l2output))
+    gst_v4l2_object_close (self->v4l2output);
+
+  if (GST_V4L2_IS_OPEN (self->v4l2capture))
+    gst_v4l2_object_close (self->v4l2capture);
+
+  gst_caps_replace (&self->probed_srccaps, NULL);
+  gst_caps_replace (&self->probed_sinkcaps, NULL);
+
+  return FALSE;
+}
+
+static void
+gst_v4l2_transform_close (GstV4l2Transform * self)
+{
+  GST_DEBUG_OBJECT (self, "Closing");
+
+  gst_v4l2_object_close (self->v4l2output);
+  gst_v4l2_object_close (self->v4l2capture);
+
+  gst_caps_replace (&self->probed_srccaps, NULL);
+  gst_caps_replace (&self->probed_sinkcaps, NULL);
+}
+
+static gboolean
+gst_v4l2_transform_stop (GstBaseTransform * trans)
+{
+  GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
+
+  GST_DEBUG_OBJECT (self, "Stop");
+
+  gst_v4l2_object_stop (self->v4l2output);
+  gst_v4l2_object_stop (self->v4l2capture);
+  gst_caps_replace (&self->incaps, NULL);
+  gst_caps_replace (&self->outcaps, NULL);
+
+  return TRUE;
+}
+
+static gboolean
+gst_v4l2_transform_set_caps (GstBaseTransform * trans, GstCaps * incaps,
+    GstCaps * outcaps)
+{
+  GstV4l2Error error = GST_V4L2_ERROR_INIT;
+  GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
+
+  if (self->incaps && self->outcaps) {
+    if (gst_caps_is_equal (incaps, self->incaps) &&
+        gst_caps_is_equal (outcaps, self->outcaps)) {
+      GST_DEBUG_OBJECT (trans, "Caps did not changed");
+      return TRUE;
+    }
+  }
+
+  /* TODO Add renegotiation support */
+  g_return_val_if_fail (!GST_V4L2_IS_ACTIVE (self->v4l2output), FALSE);
+  g_return_val_if_fail (!GST_V4L2_IS_ACTIVE (self->v4l2capture), FALSE);
+
+  gst_caps_replace (&self->incaps, incaps);
+  gst_caps_replace (&self->outcaps, outcaps);
+
+  if (!gst_v4l2_object_set_format (self->v4l2output, incaps, &error))
+    goto incaps_failed;
+
+  if (!gst_v4l2_object_set_format (self->v4l2capture, outcaps, &error))
+    goto outcaps_failed;
+
+  /* FIXME implement fallback if crop not supported */
+  if (!gst_v4l2_object_set_crop (self->v4l2output))
+    goto failed;
+
+  if (!gst_v4l2_object_set_crop (self->v4l2capture))
+    goto failed;
+
+  return TRUE;
+
+incaps_failed:
+  {
+    GST_ERROR_OBJECT (self, "failed to set input caps: %" GST_PTR_FORMAT,
+        incaps);
+    gst_v4l2_error (self, &error);
+    goto failed;
+  }
+outcaps_failed:
+  {
+    gst_v4l2_object_stop (self->v4l2output);
+    GST_ERROR_OBJECT (self, "failed to set output caps: %" GST_PTR_FORMAT,
+        outcaps);
+    gst_v4l2_error (self, &error);
+    goto failed;
+  }
+failed:
+  return FALSE;
+}
+
+static gboolean
+gst_v4l2_transform_query (GstBaseTransform * trans, GstPadDirection direction,
+    GstQuery * query)
+{
+  GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
+  gboolean ret = TRUE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:{
+      GstCaps *filter, *caps = NULL, *result = NULL;
+      GstPad *pad, *otherpad;
+
+      gst_query_parse_caps (query, &filter);
+
+      if (direction == GST_PAD_SRC) {
+        pad = GST_BASE_TRANSFORM_SRC_PAD (trans);
+        otherpad = GST_BASE_TRANSFORM_SINK_PAD (trans);
+        if (self->probed_srccaps)
+          caps = gst_caps_ref (self->probed_srccaps);
+      } else {
+        pad = GST_BASE_TRANSFORM_SINK_PAD (trans);
+        otherpad = GST_BASE_TRANSFORM_SRC_PAD (trans);
+        if (self->probed_sinkcaps)
+          caps = gst_caps_ref (self->probed_sinkcaps);
+      }
+
+      if (!caps)
+        caps = gst_pad_get_pad_template_caps (pad);
+
+      if (filter) {
+        GstCaps *tmp = caps;
+        caps = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
+        gst_caps_unref (tmp);
+      }
+
+      result = gst_pad_peer_query_caps (otherpad, caps);
+      result = gst_caps_make_writable (result);
+      gst_caps_append (result, caps);
+
+      GST_DEBUG_OBJECT (self, "Returning %s caps %" GST_PTR_FORMAT,
+          GST_PAD_NAME (pad), result);
+
+      gst_query_set_caps_result (query, result);
+      gst_caps_unref (result);
+      break;
+    }
+
+    default:
+      ret = GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
+          query);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_v4l2_transform_decide_allocation (GstBaseTransform * trans,
+    GstQuery * query)
+{
+  GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
+  gboolean ret = FALSE;
+
+  GST_DEBUG_OBJECT (self, "called");
+
+  if (gst_v4l2_object_decide_allocation (self->v4l2capture, query)) {
+    GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2capture->pool);
+
+    ret = GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans,
+        query);
+
+    if (!gst_buffer_pool_set_active (pool, TRUE))
+      goto activate_failed;
+  }
+
+  return ret;
+
+activate_failed:
+  GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+      ("failed to activate bufferpool"), ("failed to activate bufferpool"));
+  return TRUE;
+}
+
+static gboolean
+gst_v4l2_transform_propose_allocation (GstBaseTransform * trans,
+    GstQuery * decide_query, GstQuery * query)
+{
+  GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
+  gboolean ret = FALSE;
+
+  GST_DEBUG_OBJECT (self, "called");
+
+  if (decide_query == NULL)
+    ret = TRUE;
+  else
+    ret = gst_v4l2_object_propose_allocation (self->v4l2output, query);
+
+  if (ret)
+    ret = GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans,
+        decide_query, query);
+
+  return ret;
+}
+
+/* copies the given caps */
+static GstCaps *
+gst_v4l2_transform_caps_remove_format_info (GstCaps * caps)
+{
+  GstStructure *st;
+  GstCapsFeatures *f;
+  gint i, n;
+  GstCaps *res;
+
+  res = gst_caps_new_empty ();
+
+  n = gst_caps_get_size (caps);
+  for (i = 0; i < n; i++) {
+    st = gst_caps_get_structure (caps, i);
+    f = gst_caps_get_features (caps, i);
+
+    /* If this is already expressed by the existing caps
+     * skip this structure */
+    if (i > 0 && gst_caps_is_subset_structure_full (res, st, f))
+      continue;
+
+    st = gst_structure_copy (st);
+    /* Only remove format info for the cases when we can actually convert */
+    if (!gst_caps_features_is_any (f)
+        && gst_caps_features_is_equal (f,
+            GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY))
+      gst_structure_remove_fields (st, "format", "colorimetry", "chroma-site",
+          "width", "height", "pixel-aspect-ratio", NULL);
+
+    gst_caps_append_structure_full (res, st, gst_caps_features_copy (f));
+  }
+
+  return res;
+}
+
+/* The caps can be transformed into any other caps with format info removed.
+ * However, we should prefer passthrough, so if passthrough is possible,
+ * put it first in the list. */
+static GstCaps *
+gst_v4l2_transform_transform_caps (GstBaseTransform * btrans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
+{
+  GstCaps *tmp, *tmp2;
+  GstCaps *result;
+
+  /* Get all possible caps that we can transform to */
+  tmp = gst_v4l2_transform_caps_remove_format_info (caps);
+
+  if (filter) {
+    tmp2 = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (tmp);
+    tmp = tmp2;
+  }
+
+  result = tmp;
+
+  GST_DEBUG_OBJECT (btrans, "transformed %" GST_PTR_FORMAT " into %"
+      GST_PTR_FORMAT, caps, result);
+
+  return result;
+}
+
+static GstCaps *
+gst_v4l2_transform_fixate_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
+{
+  GstStructure *ins, *outs;
+  const GValue *from_par, *to_par;
+  GValue fpar = { 0, }, tpar = {
+  0,};
+
+  othercaps = gst_caps_truncate (othercaps);
+  othercaps = gst_caps_make_writable (othercaps);
+
+  GST_DEBUG_OBJECT (trans, "trying to fixate othercaps %" GST_PTR_FORMAT
+      " based on caps %" GST_PTR_FORMAT, othercaps, caps);
+
+  ins = gst_caps_get_structure (caps, 0);
+  outs = gst_caps_get_structure (othercaps, 0);
+
+  {
+    const gchar *in_format;
+
+    in_format = gst_structure_get_string (ins, "format");
+    if (in_format) {
+      /* Try to set output format for pass through */
+      gst_structure_fixate_field_string (outs, "format", in_format);
+    }
+
+  }
+
+  from_par = gst_structure_get_value (ins, "pixel-aspect-ratio");
+  to_par = gst_structure_get_value (outs, "pixel-aspect-ratio");
+
+  /* If we're fixating from the sinkpad we always set the PAR and
+   * assume that missing PAR on the sinkpad means 1/1 and
+   * missing PAR on the srcpad means undefined
+   */
+  if (direction == GST_PAD_SINK) {
+    if (!from_par) {
+      g_value_init (&fpar, GST_TYPE_FRACTION);
+      gst_value_set_fraction (&fpar, 1, 1);
+      from_par = &fpar;
+    }
+    if (!to_par) {
+      g_value_init (&tpar, GST_TYPE_FRACTION_RANGE);
+      gst_value_set_fraction_range_full (&tpar, 1, G_MAXINT, G_MAXINT, 1);
+      to_par = &tpar;
+    }
+  } else {
+    if (!to_par) {
+      g_value_init (&tpar, GST_TYPE_FRACTION);
+      gst_value_set_fraction (&tpar, 1, 1);
+      to_par = &tpar;
+
+      gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
+          NULL);
+    }
+    if (!from_par) {
+      g_value_init (&fpar, GST_TYPE_FRACTION);
+      gst_value_set_fraction (&fpar, 1, 1);
+      from_par = &fpar;
+    }
+  }
+
+  /* we have both PAR but they might not be fixated */
+  {
+    gint from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d;
+    gint w = 0, h = 0;
+    gint from_dar_n, from_dar_d;
+    gint num, den;
+
+    /* from_par should be fixed */
+    g_return_val_if_fail (gst_value_is_fixed (from_par), othercaps);
+
+    from_par_n = gst_value_get_fraction_numerator (from_par);
+    from_par_d = gst_value_get_fraction_denominator (from_par);
+
+    gst_structure_get_int (ins, "width", &from_w);
+    gst_structure_get_int (ins, "height", &from_h);
+
+    gst_structure_get_int (outs, "width", &w);
+    gst_structure_get_int (outs, "height", &h);
+
+    /* if both width and height are already fixed, we can't do anything
+     * about it anymore */
+    if (w && h) {
+      guint n, d;
+
+      GST_DEBUG_OBJECT (trans, "dimensions already set to %dx%d, not fixating",
+          w, h);
+      if (!gst_value_is_fixed (to_par)) {
+        if (gst_video_calculate_display_ratio (&n, &d, from_w, from_h,
+                from_par_n, from_par_d, w, h)) {
+          GST_DEBUG_OBJECT (trans, "fixating to_par to %dx%d", n, d);
+          if (gst_structure_has_field (outs, "pixel-aspect-ratio"))
+            gst_structure_fixate_field_nearest_fraction (outs,
+                "pixel-aspect-ratio", n, d);
+          else if (n != d)
+            gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+                n, d, NULL);
+        }
+      }
+      goto done;
+    }
+
+    /* Calculate input DAR */
+    if (!gst_util_fraction_multiply (from_w, from_h, from_par_n, from_par_d,
+            &from_dar_n, &from_dar_d)) {
+      GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
+          ("Error calculating the output scaled size - integer overflow"));
+      goto done;
+    }
+
+    GST_DEBUG_OBJECT (trans, "Input DAR is %d/%d", from_dar_n, from_dar_d);
+
+    /* If either width or height are fixed there's not much we
+     * can do either except choosing a height or width and PAR
+     * that matches the DAR as good as possible
+     */
+    if (h) {
+      GstStructure *tmp;
+      gint set_w, set_par_n, set_par_d;
+
+      GST_DEBUG_OBJECT (trans, "height is fixed (%d)", h);
+
+      /* If the PAR is fixed too, there's not much to do
+       * except choosing the width that is nearest to the
+       * width with the same DAR */
+      if (gst_value_is_fixed (to_par)) {
+        to_par_n = gst_value_get_fraction_numerator (to_par);
+        to_par_d = gst_value_get_fraction_denominator (to_par);
+
+        GST_DEBUG_OBJECT (trans, "PAR is fixed %d/%d", to_par_n, to_par_d);
+
+        if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d,
+                to_par_n, &num, &den)) {
+          GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
+              ("Error calculating the output scaled size - integer overflow"));
+          goto done;
+        }
+
+        w = (guint) gst_util_uint64_scale_int (h, num, den);
+        gst_structure_fixate_field_nearest_int (outs, "width", w);
+
+        goto done;
+      }
+
+      /* The PAR is not fixed and it's quite likely that we can set
+       * an arbitrary PAR. */
+
+      /* Check if we can keep the input width */
+      tmp = gst_structure_copy (outs);
+      gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
+      gst_structure_get_int (tmp, "width", &set_w);
+
+      /* Might have failed but try to keep the DAR nonetheless by
+       * adjusting the PAR */
+      if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, h, set_w,
+              &to_par_n, &to_par_d)) {
+        GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
+            ("Error calculating the output scaled size - integer overflow"));
+        gst_structure_free (tmp);
+        goto done;
+      }
+
+      if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
+        gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
+      gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
+          to_par_n, to_par_d);
+      gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
+          &set_par_d);
+      gst_structure_free (tmp);
+
+      /* Check if the adjusted PAR is accepted */
+      if (set_par_n == to_par_n && set_par_d == to_par_d) {
+        if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+            set_par_n != set_par_d)
+          gst_structure_set (outs, "width", G_TYPE_INT, set_w,
+              "pixel-aspect-ratio", GST_TYPE_FRACTION, set_par_n, set_par_d,
+              NULL);
+        goto done;
+      }
+
+      /* Otherwise scale the width to the new PAR and check if the
+       * adjusted with is accepted. If all that fails we can't keep
+       * the DAR */
+      if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
+              set_par_n, &num, &den)) {
+        GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
+            ("Error calculating the output scaled size - integer overflow"));
+        goto done;
+      }
+
+      w = (guint) gst_util_uint64_scale_int (h, num, den);
+      gst_structure_fixate_field_nearest_int (outs, "width", w);
+      if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+          set_par_n != set_par_d)
+        gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+            set_par_n, set_par_d, NULL);
+
+      goto done;
+    } else if (w) {
+      GstStructure *tmp;
+      gint set_h, set_par_n, set_par_d;
+
+      GST_DEBUG_OBJECT (trans, "width is fixed (%d)", w);
+
+      /* If the PAR is fixed too, there's not much to do
+       * except choosing the height that is nearest to the
+       * height with the same DAR */
+      if (gst_value_is_fixed (to_par)) {
+        to_par_n = gst_value_get_fraction_numerator (to_par);
+        to_par_d = gst_value_get_fraction_denominator (to_par);
+
+        GST_DEBUG_OBJECT (trans, "PAR is fixed %d/%d", to_par_n, to_par_d);
+
+        if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d,
+                to_par_n, &num, &den)) {
+          GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
+              ("Error calculating the output scaled size - integer overflow"));
+          goto done;
+        }
+
+        h = (guint) gst_util_uint64_scale_int (w, den, num);
+        gst_structure_fixate_field_nearest_int (outs, "height", h);
+
+        goto done;
+      }
+
+      /* The PAR is not fixed and it's quite likely that we can set
+       * an arbitrary PAR. */
+
+      /* Check if we can keep the input height */
+      tmp = gst_structure_copy (outs);
+      gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
+      gst_structure_get_int (tmp, "height", &set_h);
+
+      /* Might have failed but try to keep the DAR nonetheless by
+       * adjusting the PAR */
+      if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_h, w,
+              &to_par_n, &to_par_d)) {
+        GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
+            ("Error calculating the output scaled size - integer overflow"));
+        gst_structure_free (tmp);
+        goto done;
+      }
+      if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
+        gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
+      gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
+          to_par_n, to_par_d);
+      gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
+          &set_par_d);
+      gst_structure_free (tmp);
+
+      /* Check if the adjusted PAR is accepted */
+      if (set_par_n == to_par_n && set_par_d == to_par_d) {
+        if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+            set_par_n != set_par_d)
+          gst_structure_set (outs, "height", G_TYPE_INT, set_h,
+              "pixel-aspect-ratio", GST_TYPE_FRACTION, set_par_n, set_par_d,
+              NULL);
+        goto done;
+      }
+
+      /* Otherwise scale the height to the new PAR and check if the
+       * adjusted with is accepted. If all that fails we can't keep
+       * the DAR */
+      if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
+              set_par_n, &num, &den)) {
+        GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
+            ("Error calculating the output scaled size - integer overflow"));
+        goto done;
+      }
+
+      h = (guint) gst_util_uint64_scale_int (w, den, num);
+      gst_structure_fixate_field_nearest_int (outs, "height", h);
+      if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+          set_par_n != set_par_d)
+        gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+            set_par_n, set_par_d, NULL);
+
+      goto done;
+    } else if (gst_value_is_fixed (to_par)) {
+      GstStructure *tmp;
+      gint set_h, set_w, f_h, f_w;
+
+      to_par_n = gst_value_get_fraction_numerator (to_par);
+      to_par_d = gst_value_get_fraction_denominator (to_par);
+
+      GST_DEBUG_OBJECT (trans, "PAR is fixed %d/%d", to_par_n, to_par_d);
+
+      /* Calculate scale factor for the PAR change */
+      if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d,
+              to_par_n, &num, &den)) {
+        GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
+            ("Error calculating the output scaled size - integer overflow"));
+        goto done;
+      }
+
+      /* Try to keep the input height (because of interlacing) */
+      tmp = gst_structure_copy (outs);
+      gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
+      gst_structure_get_int (tmp, "height", &set_h);
+
+      /* This might have failed but try to scale the width
+       * to keep the DAR nonetheless */
+      w = (guint) gst_util_uint64_scale_int (set_h, num, den);
+      gst_structure_fixate_field_nearest_int (tmp, "width", w);
+      gst_structure_get_int (tmp, "width", &set_w);
+      gst_structure_free (tmp);
+
+      /* We kept the DAR and the height is nearest to the original height */
+      if (set_w == w) {
+        gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
+            G_TYPE_INT, set_h, NULL);
+        goto done;
+      }
+
+      f_h = set_h;
+      f_w = set_w;
+
+      /* If the former failed, try to keep the input width at least */
+      tmp = gst_structure_copy (outs);
+      gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
+      gst_structure_get_int (tmp, "width", &set_w);
+
+      /* This might have failed but try to scale the width
+       * to keep the DAR nonetheless */
+      h = (guint) gst_util_uint64_scale_int (set_w, den, num);
+      gst_structure_fixate_field_nearest_int (tmp, "height", h);
+      gst_structure_get_int (tmp, "height", &set_h);
+      gst_structure_free (tmp);
+
+      /* We kept the DAR and the width is nearest to the original width */
+      if (set_h == h) {
+        gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
+            G_TYPE_INT, set_h, NULL);
+        goto done;
+      }
+
+      /* If all this failed, keep the height that was nearest to the orignal
+       * height and the nearest possible width. This changes the DAR but
+       * there's not much else to do here.
+       */
+      gst_structure_set (outs, "width", G_TYPE_INT, f_w, "height", G_TYPE_INT,
+          f_h, NULL);
+      goto done;
+    } else {
+      GstStructure *tmp;
+      gint set_h, set_w, set_par_n, set_par_d, tmp2;
+
+      /* width, height and PAR are not fixed but passthrough is not possible */
+
+      /* First try to keep the height and width as good as possible
+       * and scale PAR */
+      tmp = gst_structure_copy (outs);
+      gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
+      gst_structure_get_int (tmp, "height", &set_h);
+      gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
+      gst_structure_get_int (tmp, "width", &set_w);
+
+      if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_h, set_w,
+              &to_par_n, &to_par_d)) {
+        GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
+            ("Error calculating the output scaled size - integer overflow"));
+        gst_structure_free (tmp);
+        goto done;
+      }
+
+      if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
+        gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
+      gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
+          to_par_n, to_par_d);
+      gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
+          &set_par_d);
+      gst_structure_free (tmp);
+
+      if (set_par_n == to_par_n && set_par_d == to_par_d) {
+        gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
+            G_TYPE_INT, set_h, NULL);
+
+        if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+            set_par_n != set_par_d)
+          gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+              set_par_n, set_par_d, NULL);
+        goto done;
+      }
+
+      /* Otherwise try to scale width to keep the DAR with the set
+       * PAR and height */
+      if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
+              set_par_n, &num, &den)) {
+        GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
+            ("Error calculating the output scaled size - integer overflow"));
+        goto done;
+      }
+
+      w = (guint) gst_util_uint64_scale_int (set_h, num, den);
+      tmp = gst_structure_copy (outs);
+      gst_structure_fixate_field_nearest_int (tmp, "width", w);
+      gst_structure_get_int (tmp, "width", &tmp2);
+      gst_structure_free (tmp);
+
+      if (tmp2 == w) {
+        gst_structure_set (outs, "width", G_TYPE_INT, tmp2, "height",
+            G_TYPE_INT, set_h, NULL);
+        if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+            set_par_n != set_par_d)
+          gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+              set_par_n, set_par_d, NULL);
+        goto done;
+      }
+
+      /* ... or try the same with the height */
+      h = (guint) gst_util_uint64_scale_int (set_w, den, num);
+      tmp = gst_structure_copy (outs);
+      gst_structure_fixate_field_nearest_int (tmp, "height", h);
+      gst_structure_get_int (tmp, "height", &tmp2);
+      gst_structure_free (tmp);
+
+      if (tmp2 == h) {
+        gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
+            G_TYPE_INT, tmp2, NULL);
+        if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+            set_par_n != set_par_d)
+          gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+              set_par_n, set_par_d, NULL);
+        goto done;
+      }
+
+      /* If all fails we can't keep the DAR and take the nearest values
+       * for everything from the first try */
+      gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
+          G_TYPE_INT, set_h, NULL);
+      if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+          set_par_n != set_par_d)
+        gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+            set_par_n, set_par_d, NULL);
+    }
+  }
+
+done:
+  GST_DEBUG_OBJECT (trans, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
+
+  if (from_par == &fpar)
+    g_value_unset (&fpar);
+  if (to_par == &tpar)
+    g_value_unset (&tpar);
+
+  /* fixate remaining fields */
+  othercaps = gst_caps_fixate (othercaps);
+
+  if (direction == GST_PAD_SINK) {
+    if (gst_caps_is_subset (caps, othercaps)) {
+      gst_caps_replace (&othercaps, caps);
+    }
+  }
+
+  return othercaps;
+}
+
+static GstFlowReturn
+gst_v4l2_transform_prepare_output_buffer (GstBaseTransform * trans,
+    GstBuffer * inbuf, GstBuffer ** outbuf)
+{
+  GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
+  GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool);
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBaseTransformClass *bclass = GST_BASE_TRANSFORM_CLASS (parent_class);
+
+  if (gst_base_transform_is_passthrough (trans)) {
+    GST_DEBUG_OBJECT (self, "Passthrough, no need to do anything");
+    *outbuf = inbuf;
+    goto beach;
+  }
+
+  /* Ensure input internal pool is active */
+  if (!gst_buffer_pool_is_active (pool)) {
+    GstStructure *config = gst_buffer_pool_get_config (pool);
+    gint min = self->v4l2output->min_buffers == 0 ? GST_V4L2_MIN_BUFFERS :
+        self->v4l2output->min_buffers;
+    gst_buffer_pool_config_set_params (config, self->incaps,
+        self->v4l2output->info.size, min, min);
+
+    /* There is no reason to refuse this config */
+    if (!gst_buffer_pool_set_config (pool, config))
+      goto activate_failed;
+
+    if (!gst_buffer_pool_set_active (pool, TRUE))
+      goto activate_failed;
+  }
+
+  GST_DEBUG_OBJECT (self, "Queue input buffer");
+  ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (pool), &inbuf);
+  if (G_UNLIKELY (ret != GST_FLOW_OK))
+    goto beach;
+
+  do {
+    pool = gst_base_transform_get_buffer_pool (trans);
+
+    if (!gst_buffer_pool_set_active (pool, TRUE))
+      goto activate_failed;
+
+    GST_DEBUG_OBJECT (self, "Dequeue output buffer");
+    ret = gst_buffer_pool_acquire_buffer (pool, outbuf, NULL);
+    g_object_unref (pool);
+
+    if (ret != GST_FLOW_OK)
+      goto alloc_failed;
+
+    pool = self->v4l2capture->pool;
+    ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (pool), outbuf);
+
+  } while (ret == GST_V4L2_FLOW_CORRUPTED_BUFFER);
+
+  if (ret != GST_FLOW_OK) {
+    gst_buffer_unref (*outbuf);
+    *outbuf = NULL;
+  }
+
+  if (bclass->copy_metadata)
+    if (!bclass->copy_metadata (trans, inbuf, *outbuf)) {
+      /* something failed, post a warning */
+      GST_ELEMENT_WARNING (self, STREAM, NOT_IMPLEMENTED,
+          ("could not copy metadata"), (NULL));
+    }
+
+beach:
+  return ret;
+
+activate_failed:
+  GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+      ("failed to activate bufferpool"), ("failed to activate bufferpool"));
+  g_object_unref (pool);
+  return GST_FLOW_ERROR;
+
+alloc_failed:
+  GST_DEBUG_OBJECT (self, "could not allocate buffer from pool");
+  return ret;
+}
+
+static GstFlowReturn
+gst_v4l2_transform_transform (GstBaseTransform * trans, GstBuffer * inbuf,
+    GstBuffer * outbuf)
+{
+  /* Nothing to do */
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_v4l2_transform_sink_event (GstBaseTransform * trans, GstEvent * event)
+{
+  GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
+  gboolean ret;
+
+  /* Nothing to flush in passthrough */
+  if (gst_base_transform_is_passthrough (trans))
+    return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      GST_DEBUG_OBJECT (self, "flush start");
+      gst_v4l2_object_unlock (self->v4l2output);
+      gst_v4l2_object_unlock (self->v4l2capture);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      /* Buffer should be back now */
+      GST_DEBUG_OBJECT (self, "flush stop");
+      gst_v4l2_object_unlock_stop (self->v4l2capture);
+      gst_v4l2_object_unlock_stop (self->v4l2output);
+      gst_v4l2_buffer_pool_flush (self->v4l2output->pool);
+      gst_v4l2_buffer_pool_flush (self->v4l2capture->pool);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static GstStateChangeReturn
+gst_v4l2_transform_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstV4l2Transform *self = GST_V4L2_TRANSFORM (element);
+  GstStateChangeReturn ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      if (!gst_v4l2_transform_open (self))
+        return GST_STATE_CHANGE_FAILURE;
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_v4l2_object_unlock (self->v4l2output);
+      gst_v4l2_object_unlock (self->v4l2capture);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      gst_v4l2_transform_close (self);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_v4l2_transform_dispose (GObject * object)
+{
+  GstV4l2Transform *self = GST_V4L2_TRANSFORM (object);
+
+  gst_caps_replace (&self->probed_sinkcaps, NULL);
+  gst_caps_replace (&self->probed_srccaps, NULL);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_v4l2_transform_finalize (GObject * object)
+{
+  GstV4l2Transform *self = GST_V4L2_TRANSFORM (object);
+
+  gst_v4l2_object_destroy (self->v4l2capture);
+  gst_v4l2_object_destroy (self->v4l2output);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_v4l2_transform_init (GstV4l2Transform * self)
+{
+  /* V4L2 object are created in subinstance_init */
+  /* enable QoS */
+  gst_base_transform_set_qos_enabled (GST_BASE_TRANSFORM (self), TRUE);
+}
+
+static void
+gst_v4l2_transform_subinstance_init (GTypeInstance * instance, gpointer g_class)
+{
+  GstV4l2TransformClass *klass = GST_V4L2_TRANSFORM_CLASS (g_class);
+  GstV4l2Transform *self = GST_V4L2_TRANSFORM (instance);
+
+  self->v4l2output = gst_v4l2_object_new (GST_ELEMENT (self),
+      GST_OBJECT (GST_BASE_TRANSFORM_SINK_PAD (self)),
+      V4L2_BUF_TYPE_VIDEO_OUTPUT, klass->default_device,
+      gst_v4l2_get_output, gst_v4l2_set_output, NULL);
+  self->v4l2output->no_initial_format = TRUE;
+  self->v4l2output->keep_aspect = FALSE;
+
+  self->v4l2capture = gst_v4l2_object_new (GST_ELEMENT (self),
+      GST_OBJECT (GST_BASE_TRANSFORM_SRC_PAD (self)),
+      V4L2_BUF_TYPE_VIDEO_CAPTURE, klass->default_device,
+      gst_v4l2_get_input, gst_v4l2_set_input, NULL);
+  self->v4l2capture->no_initial_format = TRUE;
+  self->v4l2output->keep_aspect = FALSE;
+}
+
+static void
+gst_v4l2_transform_class_init (GstV4l2TransformClass * klass)
+{
+  GstElementClass *element_class;
+  GObjectClass *gobject_class;
+  GstBaseTransformClass *base_transform_class;
+
+  element_class = (GstElementClass *) klass;
+  gobject_class = (GObjectClass *) klass;
+  base_transform_class = (GstBaseTransformClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (gst_v4l2_transform_debug, "v4l2transform", 0,
+      "V4L2 Converter");
+
+  gst_element_class_set_static_metadata (element_class,
+      "V4L2 Video Converter",
+      "Filter/Converter/Video/Scaler",
+      "Transform streams via V4L2 API",
+      "Nicolas Dufresne <nicolas.dufresne@collabora.com>");
+
+  gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_v4l2_transform_dispose);
+  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_v4l2_transform_finalize);
+  gobject_class->set_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_transform_set_property);
+  gobject_class->get_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_transform_get_property);
+
+  base_transform_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2_transform_stop);
+  base_transform_class->set_caps =
+      GST_DEBUG_FUNCPTR (gst_v4l2_transform_set_caps);
+  base_transform_class->query = GST_DEBUG_FUNCPTR (gst_v4l2_transform_query);
+  base_transform_class->sink_event =
+      GST_DEBUG_FUNCPTR (gst_v4l2_transform_sink_event);
+  base_transform_class->decide_allocation =
+      GST_DEBUG_FUNCPTR (gst_v4l2_transform_decide_allocation);
+  base_transform_class->propose_allocation =
+      GST_DEBUG_FUNCPTR (gst_v4l2_transform_propose_allocation);
+  base_transform_class->transform_caps =
+      GST_DEBUG_FUNCPTR (gst_v4l2_transform_transform_caps);
+  base_transform_class->fixate_caps =
+      GST_DEBUG_FUNCPTR (gst_v4l2_transform_fixate_caps);
+  base_transform_class->prepare_output_buffer =
+      GST_DEBUG_FUNCPTR (gst_v4l2_transform_prepare_output_buffer);
+  base_transform_class->transform =
+      GST_DEBUG_FUNCPTR (gst_v4l2_transform_transform);
+
+  base_transform_class->passthrough_on_same_caps = TRUE;
+
+  element_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_v4l2_transform_change_state);
+
+  gst_v4l2_object_install_m2m_properties_helper (gobject_class);
+}
+
+static void
+gst_v4l2_transform_subclass_init (gpointer g_class, gpointer data)
+{
+  GstV4l2TransformClass *klass = GST_V4L2_TRANSFORM_CLASS (g_class);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+  GstV4l2TransformCData *cdata = data;
+
+  klass->default_device = cdata->device;
+
+  /* Note: gst_pad_template_new() take the floating ref from the caps */
+  gst_element_class_add_pad_template (element_class,
+      gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+          cdata->sink_caps));
+  gst_element_class_add_pad_template (element_class,
+      gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+          cdata->src_caps));
+
+  g_free (cdata);
+}
+
+/* Probing functions */
+gboolean
+gst_v4l2_is_transform (GstCaps * sink_caps, GstCaps * src_caps)
+{
+  gboolean ret = FALSE;
+
+  if (gst_caps_is_subset (sink_caps, gst_v4l2_object_get_raw_caps ())
+      && gst_caps_is_subset (src_caps, gst_v4l2_object_get_raw_caps ()))
+    ret = TRUE;
+
+  return ret;
+}
+
+void
+gst_v4l2_transform_register (GstPlugin * plugin, const gchar * basename,
+    const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps)
+{
+  GTypeQuery type_query;
+  GTypeInfo type_info = { 0, };
+  GType type, subtype;
+  gchar *type_name;
+  GstV4l2TransformCData *cdata;
+
+  cdata = g_new0 (GstV4l2TransformCData, 1);
+  cdata->device = g_strdup (device_path);
+  cdata->sink_caps = gst_caps_ref (sink_caps);
+  cdata->src_caps = gst_caps_ref (src_caps);
+
+  type = gst_v4l2_transform_get_type ();
+  g_type_query (type, &type_query);
+  memset (&type_info, 0, sizeof (type_info));
+  type_info.class_size = type_query.class_size;
+  type_info.instance_size = type_query.instance_size;
+  type_info.class_init = gst_v4l2_transform_subclass_init;
+  type_info.class_data = cdata;
+  type_info.instance_init = gst_v4l2_transform_subinstance_init;
+
+  type_name = g_strdup_printf ("v4l2%sconvert", basename);
+  subtype = g_type_register_static (type, type_name, &type_info, 0);
+
+  if (!gst_element_register (plugin, type_name, GST_RANK_NONE, subtype))
+    GST_WARNING ("Failed to register plugin '%s'", type_name);
+
+  g_free (type_name);
+}
diff --git a/sys/v4l2/gstv4l2transform.h b/sys/v4l2/gstv4l2transform.h
new file mode 100644
index 0000000..ea6b9a5
--- /dev/null
+++ b/sys/v4l2/gstv4l2transform.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 Collabora Ltd.
+ *     Author: Nicolas Dufresne <nicolas.dufresne@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __GST_V4L2_TRANSFORM_H__
+#define __GST_V4L2_TRANSFORM_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+
+#include <gstv4l2object.h>
+#include <gstv4l2bufferpool.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_V4L2_TRANSFORM \
+  (gst_v4l2_transform_get_type())
+#define GST_V4L2_TRANSFORM(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_TRANSFORM,GstV4l2Transform))
+#define GST_V4L2_TRANSFORM_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_TRANSFORM,GstV4l2TransformClass))
+#define GST_IS_V4L2_TRANSFORM(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_TRANSFORM))
+#define GST_IS_V4L2_TRANSFORM_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_TRANSFORM))
+#define GST_V4L2_TRANSFORM_GET_CLASS(inst) \
+  (G_TYPE_INSTANCE_GET_CLASS ((inst),GST_TYPE_V4L2_TRANSFORM,GstV4l2TransformClass))
+
+typedef struct _GstV4l2Transform GstV4l2Transform;
+typedef struct _GstV4l2TransformClass GstV4l2TransformClass;
+
+struct _GstV4l2Transform
+{
+  GstBaseTransform parent;
+
+  /* < private > */
+  GstV4l2Object * v4l2output;
+  GstV4l2Object * v4l2capture;
+
+  /* pads */
+  GstCaps *probed_srccaps;
+  GstCaps *probed_sinkcaps;
+
+  /* Selected caps */
+  GstCaps *incaps;
+  GstCaps *outcaps;
+};
+
+struct _GstV4l2TransformClass
+{
+  GstBaseTransformClass parent_class;
+  gchar *default_device;
+};
+
+GType gst_v4l2_transform_get_type (void);
+
+gboolean gst_v4l2_is_transform       (GstCaps * sink_caps, GstCaps * src_caps);
+void     gst_v4l2_transform_register (GstPlugin * plugin,
+                                      const gchar *basename,
+                                      const gchar *device_path,
+                                      GstCaps * sink_caps, GstCaps * src_caps);
+
+G_END_DECLS
+
+#endif /* __GST_V4L2_TRANSFORM_H__ */
diff --git a/sys/v4l2/gstv4l2tuner.c b/sys/v4l2/gstv4l2tuner.c
new file mode 100644
index 0000000..66cc2c1
--- /dev/null
+++ b/sys/v4l2/gstv4l2tuner.c
@@ -0,0 +1,303 @@
+/* GStreamer
+ *
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *               2006 Edgard Lima <edgard.lima@gmail.com>
+ *
+ * gstv4l2tuner.c: tuner interface implementation for V4L2
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "gstv4l2object.h"
+#include "gstv4l2tuner.h"
+#include "gstv4l2object.h"
+
+G_DEFINE_TYPE (GstV4l2TunerChannel, gst_v4l2_tuner_channel,
+    GST_TYPE_TUNER_CHANNEL);
+
+G_DEFINE_TYPE (GstV4l2TunerNorm, gst_v4l2_tuner_norm, GST_TYPE_TUNER_NORM);
+
+
+static void
+gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass * klass)
+{
+}
+
+static void
+gst_v4l2_tuner_channel_init (GstV4l2TunerChannel * channel)
+{
+  channel->index = (guint32) - 1;
+  channel->tuner = (guint32) - 1;
+  channel->audio = (guint32) - 1;
+}
+
+static void
+gst_v4l2_tuner_norm_class_init (GstV4l2TunerNormClass * klass)
+{
+}
+
+static void
+gst_v4l2_tuner_norm_init (GstV4l2TunerNorm * norm)
+{
+  norm->index = 0;
+}
+
+static G_GNUC_UNUSED gboolean
+gst_v4l2_tuner_contains_channel (GstV4l2Object * v4l2object,
+    GstV4l2TunerChannel * v4l2channel)
+{
+  const GList *item;
+
+  for (item = v4l2object->channels; item != NULL; item = item->next)
+    if (item->data == v4l2channel)
+      return TRUE;
+
+  return FALSE;
+}
+
+const GList *
+gst_v4l2_tuner_list_channels (GstV4l2Object * v4l2object)
+{
+  return v4l2object->channels;
+}
+
+gboolean
+gst_v4l2_tuner_set_channel (GstV4l2Object * v4l2object,
+    GstTunerChannel * channel)
+{
+  GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
+
+  /* assert that we're opened and that we're using a known item */
+  g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), FALSE);
+  g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object,
+          v4l2channel), FALSE);
+
+  if (v4l2object->set_in_out_func (v4l2object, v4l2channel->index)) {
+    gst_tuner_channel_changed (GST_TUNER (v4l2object->element), channel);
+    /* can FPS change here? */
+    return TRUE;
+  }
+
+  return FALSE;
+
+}
+
+GstTunerChannel *
+gst_v4l2_tuner_get_channel (GstV4l2Object * v4l2object)
+{
+  GList *item;
+  gint channel;
+
+  /* assert that we're opened and that we're using a known item */
+  g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), NULL);
+
+  if (v4l2object->get_in_out_func (v4l2object, &channel)) {
+
+    for (item = v4l2object->channels; item != NULL; item = item->next) {
+      if (channel == GST_V4L2_TUNER_CHANNEL (item->data)->index)
+        return (GstTunerChannel *) item->data;
+    }
+
+  }
+
+  return NULL;
+}
+
+static G_GNUC_UNUSED gboolean
+gst_v4l2_tuner_contains_norm (GstV4l2Object * v4l2object,
+    GstV4l2TunerNorm * v4l2norm)
+{
+  const GList *item;
+
+  for (item = v4l2object->norms; item != NULL; item = item->next)
+    if (item->data == v4l2norm)
+      return TRUE;
+
+  return FALSE;
+}
+
+const GList *
+gst_v4l2_tuner_list_norms (GstV4l2Object * v4l2object)
+{
+  return v4l2object->norms;
+}
+
+void
+gst_v4l2_tuner_set_norm_and_notify (GstV4l2Object * v4l2object,
+    GstTunerNorm * norm)
+{
+  if (gst_v4l2_tuner_set_norm (v4l2object, norm)) {
+#if 0
+    g_object_notify (G_OBJECT (v4l2object->element), "norm");
+#endif
+  }
+}
+
+gboolean
+gst_v4l2_tuner_set_norm (GstV4l2Object * v4l2object, GstTunerNorm * norm)
+{
+  GstV4l2TunerNorm *v4l2norm = GST_V4L2_TUNER_NORM (norm);
+
+  /* assert that we're opened and that we're using a known item */
+  g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), FALSE);
+  g_return_val_if_fail (gst_v4l2_tuner_contains_norm (v4l2object, v4l2norm),
+      FALSE);
+
+  if (gst_v4l2_set_norm (v4l2object, v4l2norm->index)) {
+    gst_tuner_norm_changed (GST_TUNER (v4l2object->element), norm);
+    if (v4l2object->update_fps_func)
+      v4l2object->update_fps_func (v4l2object);
+    return TRUE;
+  }
+
+  return FALSE;
+
+}
+
+GstTunerNorm *
+gst_v4l2_tuner_get_norm (GstV4l2Object * v4l2object)
+{
+  v4l2_std_id norm;
+
+  /* assert that we're opened and that we're using a known item */
+  g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), NULL);
+
+  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;
+  }
+
+  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)
+{
+  if (gst_v4l2_tuner_set_frequency (v4l2object, channel, frequency)) {
+#if 0
+    g_object_notify (G_OBJECT (v4l2object->element), "frequency");
+#endif
+  }
+}
+
+gboolean
+gst_v4l2_tuner_set_frequency (GstV4l2Object * v4l2object,
+    GstTunerChannel * channel, gulong frequency)
+{
+  GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
+  gint chan;
+
+  /* assert that we're opened and that we're using a known item */
+  g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), FALSE);
+  g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
+          GST_TUNER_CHANNEL_FREQUENCY), FALSE);
+  g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object,
+          v4l2channel), FALSE);
+
+  if (v4l2object->get_in_out_func (v4l2object, &chan)) {
+    if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index &&
+        GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
+      if (gst_v4l2_set_frequency (v4l2object, v4l2channel->tuner, frequency)) {
+        gst_tuner_frequency_changed (GST_TUNER (v4l2object->element), channel,
+            frequency);
+        return TRUE;
+      }
+    }
+  }
+
+  return FALSE;
+}
+
+gulong
+gst_v4l2_tuner_get_frequency (GstV4l2Object * v4l2object,
+    GstTunerChannel * channel)
+{
+  GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
+  gint chan;
+  gulong frequency = 0;
+
+  /* assert that we're opened and that we're using a known item */
+  g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), 0);
+  g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
+          GST_TUNER_CHANNEL_FREQUENCY), 0);
+  g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object,
+          v4l2channel), 0);
+
+  if (v4l2object->get_in_out_func (v4l2object, &chan)) {
+    if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index &&
+        GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
+      gst_v4l2_get_frequency (v4l2object, v4l2channel->tuner, &frequency);
+    }
+  }
+
+  return frequency;
+}
+
+gint
+gst_v4l2_tuner_signal_strength (GstV4l2Object * v4l2object,
+    GstTunerChannel * channel)
+{
+  GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
+  gint chan;
+  gulong signal = 0;
+
+  /* assert that we're opened and that we're using a known item */
+  g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), 0);
+  g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
+          GST_TUNER_CHANNEL_FREQUENCY), 0);
+  g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object,
+          v4l2channel), 0);
+
+  if (v4l2object->get_in_out_func (v4l2object, &chan)) {
+    if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index &&
+        GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
+      gst_v4l2_signal_strength (v4l2object, v4l2channel->tuner, &signal);
+    }
+  }
+
+  return signal;
+}
diff --git a/sys/v4l2/gstv4l2tuner.h b/sys/v4l2/gstv4l2tuner.h
new file mode 100644
index 0000000..5105657
--- /dev/null
+++ b/sys/v4l2/gstv4l2tuner.h
@@ -0,0 +1,200 @@
+/* GStreamer
+ *
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *               2006 Edgard Lima <edgard.lima@gmail.com>
+ *
+ * gstv4l2tuner.h: tuner interface implementation for V4L2
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_V4L2_TUNER_H__
+#define __GST_V4L2_TUNER_H__
+
+#include <gst/gst.h>
+
+#include "tuner.h"
+#include "gstv4l2object.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_V4L2_TUNER_CHANNEL \
+  (gst_v4l2_tuner_channel_get_type ())
+#define GST_V4L2_TUNER_CHANNEL(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_TUNER_CHANNEL, \
+          GstV4l2TunerChannel))
+#define GST_V4L2_TUNER_CHANNEL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_TUNER_CHANNEL, \
+       GstV4l2TunerChannelClass))
+#define GST_IS_V4L2_TUNER_CHANNEL(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_TUNER_CHANNEL))
+#define GST_IS_V4L2_TUNER_CHANNEL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_TUNER_CHANNEL))
+
+typedef struct _GstV4l2TunerChannel {
+  GstTunerChannel parent;
+
+  guint32         index;
+  guint32         tuner;
+  guint32         audio;
+} GstV4l2TunerChannel;
+
+typedef struct _GstV4l2TunerChannelClass {
+  GstTunerChannelClass parent;
+} GstV4l2TunerChannelClass;
+
+#define GST_TYPE_V4L2_TUNER_NORM \
+  (gst_v4l2_tuner_norm_get_type ())
+#define GST_V4L2_TUNER_NORM(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_TUNER_NORM, \
+          GstV4l2TunerNorm))
+#define GST_V4L2_TUNER_NORM_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_TUNER_NORM, \
+       GstV4l2TunerNormClass))
+#define GST_IS_V4L2_TUNER_NORM(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_TUNER_NORM))
+#define GST_IS_V4L2_TUNER_NORM_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_TUNER_NORM))
+
+typedef struct _GstV4l2TunerNorm {
+  GstTunerNorm parent;
+
+  v4l2_std_id  index;
+} GstV4l2TunerNorm;
+
+typedef struct _GstV4l2TunerNormClass {
+  GstTunerNormClass parent;
+} GstV4l2TunerNormClass;
+
+GType gst_v4l2_tuner_channel_get_type (void);
+GType gst_v4l2_tuner_norm_get_type (void);
+
+/* channels */
+const GList*      gst_v4l2_tuner_list_channels            (GstV4l2Object * v4l2object);
+GstTunerChannel*  gst_v4l2_tuner_get_channel              (GstV4l2Object * v4l2object);
+gboolean          gst_v4l2_tuner_set_channel              (GstV4l2Object * v4l2object,
+		                                           GstTunerChannel * channel);
+/* norms */
+const GList*      gst_v4l2_tuner_list_norms               (GstV4l2Object * v4l2object);
+void              gst_v4l2_tuner_set_norm_and_notify      (GstV4l2Object * v4l2object,
+		                                           GstTunerNorm * norm);
+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, 
+							   gulong frequency);
+gint              gst_v4l2_tuner_signal_strength          (GstV4l2Object * v4l2object,
+		                                           GstTunerChannel * channel);
+gulong            gst_v4l2_tuner_get_frequency            (GstV4l2Object * v4l2object,
+		                                           GstTunerChannel * channel);
+gboolean          gst_v4l2_tuner_set_frequency            (GstV4l2Object * v4l2object,
+                                                           GstTunerChannel * channel, 
+							   gulong frequency);
+
+#define GST_IMPLEMENT_V4L2_TUNER_METHODS(Type, interface_as_function)                 \
+                                                                                      \
+static const GList *                                                                  \
+interface_as_function ## _tuner_list_channels (GstTuner * mixer)                      \
+{                                                                                     \
+  Type *this = (Type*) mixer;                                                         \
+  return gst_v4l2_tuner_list_channels (this->v4l2object);                             \
+}                                                                                     \
+                                                                                      \
+static void                                                                           \
+interface_as_function ## _tuner_set_channel (GstTuner * mixer,                        \
+                                             GstTunerChannel * channel)               \
+{                                                                                     \
+  Type *this = (Type*) mixer;                                                         \
+  gst_v4l2_tuner_set_channel (this->v4l2object, channel);                             \
+}                                                                                     \
+static GstTunerChannel *                                                              \
+interface_as_function ## _tuner_get_channel (GstTuner * mixer)                        \
+{                                                                                     \
+  Type *this = (Type*) mixer;                                                         \
+  return gst_v4l2_tuner_get_channel (this->v4l2object);                               \
+}                                                                                     \
+static const GList *                                                                  \
+interface_as_function ## _tuner_list_norms (GstTuner * mixer)                         \
+{                                                                                     \
+  Type *this = (Type*) mixer;                                                         \
+  return gst_v4l2_tuner_list_norms (this->v4l2object);                                \
+}                                                                                     \
+static void                                                                           \
+interface_as_function ## _tuner_set_norm_and_notify (GstTuner * mixer,                \
+                                                     GstTunerNorm * norm)             \
+{                                                                                     \
+  Type *this = (Type*) mixer;                                                         \
+  gst_v4l2_tuner_set_norm_and_notify (this->v4l2object, norm);                        \
+}                                                                                     \
+static GstTunerNorm *                                                                 \
+interface_as_function ## _tuner_get_norm (GstTuner * mixer)                           \
+{                                                                                     \
+  Type *this = (Type*) mixer;                                                         \
+  return gst_v4l2_tuner_get_norm (this->v4l2object);                                  \
+}                                                                                     \
+                                                                                      \
+static void                                                                           \
+interface_as_function ## _tuner_set_frequency_and_notify (GstTuner * mixer,           \
+                                                          GstTunerChannel * channel,  \
+                                                          gulong frequency)           \
+{                                                                                     \
+  Type *this = (Type*) mixer;                                                         \
+  gst_v4l2_tuner_set_frequency_and_notify (this->v4l2object, channel, frequency);     \
+}                                                                                     \
+                                                                                      \
+static gulong                                                                         \
+interface_as_function ## _tuner_get_frequency (GstTuner * mixer,                      \
+                                               GstTunerChannel * channel)             \
+{                                                                                     \
+  Type *this = (Type*) mixer;                                                         \
+  return gst_v4l2_tuner_get_frequency (this->v4l2object, channel);                    \
+}                                                                                     \
+                                                                                      \
+static gint                                                                           \
+interface_as_function ## _tuner_signal_strength (GstTuner * mixer,                    \
+                                                 GstTunerChannel * channel)           \
+{                                                                                     \
+  Type *this = (Type*) mixer;                                                         \
+  return gst_v4l2_tuner_signal_strength (this->v4l2object, channel);                  \
+}                                                                                     \
+                                                                                      \
+static void                                                                           \
+interface_as_function ## _tuner_interface_init (GstTunerInterface * iface)                \
+{                                                                                     \
+  /* default virtual functions */                                                     \
+  iface->list_channels = interface_as_function ## _tuner_list_channels;               \
+  iface->set_channel = interface_as_function ## _tuner_set_channel;                   \
+  iface->get_channel = interface_as_function ## _tuner_get_channel;                   \
+                                                                                      \
+  iface->list_norms = interface_as_function ## _tuner_list_norms;                     \
+  iface->set_norm = interface_as_function ## _tuner_set_norm_and_notify;              \
+  iface->get_norm = interface_as_function ## _tuner_get_norm;                         \
+                                                                                      \
+  iface->set_frequency = interface_as_function ## _tuner_set_frequency_and_notify;    \
+  iface->get_frequency = interface_as_function ## _tuner_get_frequency;               \
+  iface->signal_strength = interface_as_function ## _tuner_signal_strength;           \
+}                                                                                     \
+
+G_END_DECLS
+
+#endif /* __GST_V4L2_TUNER_H__ */
diff --git a/sys/v4l2/gstv4l2videodec.c b/sys/v4l2/gstv4l2videodec.c
new file mode 100644
index 0000000..dc06774
--- /dev/null
+++ b/sys/v4l2/gstv4l2videodec.c
@@ -0,0 +1,1166 @@
+/*
+ * Copyright (C) 2014 Collabora Ltd.
+ *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gstv4l2object.h"
+#include "gstv4l2videodec.h"
+
+#include <string.h>
+#include <gst/gst-i18n-plugin.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_v4l2_video_dec_debug);
+#define GST_CAT_DEFAULT gst_v4l2_video_dec_debug
+
+typedef struct
+{
+  gchar *device;
+  GstCaps *sink_caps;
+  GstCaps *src_caps;
+  const gchar *longname;
+  const gchar *description;
+} GstV4l2VideoDecCData;
+
+enum
+{
+  PROP_0,
+  V4L2_STD_OBJECT_PROPS
+};
+
+#define gst_v4l2_video_dec_parent_class parent_class
+G_DEFINE_ABSTRACT_TYPE (GstV4l2VideoDec, gst_v4l2_video_dec,
+    GST_TYPE_VIDEO_DECODER);
+
+static GstFlowReturn gst_v4l2_video_dec_finish (GstVideoDecoder * decoder);
+
+static void
+gst_v4l2_video_dec_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (object);
+
+  switch (prop_id) {
+    case PROP_CAPTURE_IO_MODE:
+      if (!gst_v4l2_object_set_property_helper (self->v4l2capture,
+              prop_id, value, pspec)) {
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      }
+      break;
+
+      /* By default, only set on output */
+    default:
+      if (!gst_v4l2_object_set_property_helper (self->v4l2output,
+              prop_id, value, pspec)) {
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      }
+      break;
+  }
+}
+
+static void
+gst_v4l2_video_dec_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (object);
+
+  switch (prop_id) {
+    case PROP_CAPTURE_IO_MODE:
+      if (!gst_v4l2_object_get_property_helper (self->v4l2capture,
+              prop_id, value, pspec)) {
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      }
+      break;
+
+      /* By default read from output */
+    default:
+      if (!gst_v4l2_object_get_property_helper (self->v4l2output,
+              prop_id, value, pspec)) {
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      }
+      break;
+  }
+}
+
+static gboolean
+gst_v4l2_video_dec_open (GstVideoDecoder * decoder)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+  GstCaps *codec_caps;
+
+  GST_DEBUG_OBJECT (self, "Opening");
+
+  if (!gst_v4l2_object_open (self->v4l2output))
+    goto failure;
+
+  if (!gst_v4l2_object_open_shared (self->v4l2capture, self->v4l2output))
+    goto failure;
+
+  codec_caps = gst_pad_get_pad_template_caps (decoder->sinkpad);
+  self->probed_sinkcaps = gst_v4l2_object_probe_caps (self->v4l2output,
+      codec_caps);
+  gst_caps_unref (codec_caps);
+
+  if (gst_caps_is_empty (self->probed_sinkcaps))
+    goto no_encoded_format;
+
+  self->probed_srccaps = gst_v4l2_object_probe_caps (self->v4l2capture,
+      gst_v4l2_object_get_raw_caps ());
+
+  if (gst_caps_is_empty (self->probed_srccaps))
+    goto no_raw_format;
+
+  return TRUE;
+
+no_encoded_format:
+  GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+      (_("Encoder on device %s has no supported input format"),
+          self->v4l2output->videodev), (NULL));
+  goto failure;
+
+
+no_raw_format:
+  GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+      (_("Encoder on device %s has no supported output format"),
+          self->v4l2output->videodev), (NULL));
+  goto failure;
+
+failure:
+  if (GST_V4L2_IS_OPEN (self->v4l2output))
+    gst_v4l2_object_close (self->v4l2output);
+
+  if (GST_V4L2_IS_OPEN (self->v4l2capture))
+    gst_v4l2_object_close (self->v4l2capture);
+
+  gst_caps_replace (&self->probed_srccaps, NULL);
+  gst_caps_replace (&self->probed_sinkcaps, NULL);
+
+  return FALSE;
+}
+
+static gboolean
+gst_v4l2_video_dec_close (GstVideoDecoder * decoder)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+
+  GST_DEBUG_OBJECT (self, "Closing");
+
+  gst_v4l2_object_close (self->v4l2output);
+  gst_v4l2_object_close (self->v4l2capture);
+  gst_caps_replace (&self->probed_srccaps, NULL);
+  gst_caps_replace (&self->probed_sinkcaps, NULL);
+
+  return TRUE;
+}
+
+static gboolean
+gst_v4l2_video_dec_start (GstVideoDecoder * decoder)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+
+  GST_DEBUG_OBJECT (self, "Starting");
+
+  gst_v4l2_object_unlock (self->v4l2output);
+  g_atomic_int_set (&self->active, TRUE);
+  self->output_flow = GST_FLOW_OK;
+
+  return TRUE;
+}
+
+static gboolean
+gst_v4l2_video_dec_stop (GstVideoDecoder * decoder)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+
+  GST_DEBUG_OBJECT (self, "Stopping");
+
+  gst_v4l2_object_unlock (self->v4l2output);
+  gst_v4l2_object_unlock (self->v4l2capture);
+
+  /* Wait for capture thread to stop */
+  gst_pad_stop_task (decoder->srcpad);
+
+  GST_VIDEO_DECODER_STREAM_LOCK (decoder);
+  self->output_flow = GST_FLOW_OK;
+  GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
+
+  /* Should have been flushed already */
+  g_assert (g_atomic_int_get (&self->active) == FALSE);
+
+  gst_v4l2_object_stop (self->v4l2output);
+  gst_v4l2_object_stop (self->v4l2capture);
+
+  if (self->input_state) {
+    gst_video_codec_state_unref (self->input_state);
+    self->input_state = NULL;
+  }
+
+  GST_DEBUG_OBJECT (self, "Stopped");
+
+  return TRUE;
+}
+
+static gboolean
+gst_v4l2_video_dec_set_format (GstVideoDecoder * decoder,
+    GstVideoCodecState * state)
+{
+  GstV4l2Error error = GST_V4L2_ERROR_INIT;
+  gboolean ret = TRUE;
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+
+  GST_DEBUG_OBJECT (self, "Setting format: %" GST_PTR_FORMAT, state->caps);
+
+  if (self->input_state) {
+    if (gst_v4l2_object_caps_equal (self->v4l2output, state->caps)) {
+      GST_DEBUG_OBJECT (self, "Compatible caps");
+      goto done;
+    }
+    gst_video_codec_state_unref (self->input_state);
+    self->input_state = NULL;
+
+    gst_v4l2_video_dec_finish (decoder);
+    gst_v4l2_object_stop (self->v4l2output);
+
+    /* The renegotiation flow don't blend with the base class flow. To
+     * properly stop the capture pool we need to reclaim our buffers, which
+     * will happend through the allocation query. The allocation query is
+     * triggered by gst_video_decoder_negotiate() which requires the output
+     * caps to be set, but we can't know this information as we rely on the
+     * decoder, which requires the capture queue to be stopped.
+     *
+     * To workaround this issue, we simply run an allocation query with the
+     * old negotiated caps in order to drain/reclaim our buffers. That breaks
+     * the complexity and should not have much impact in performance since the
+     * following allocation query will happen on a drained pipeline and won't
+     * block. */
+    {
+      GstCaps *caps = gst_pad_get_current_caps (decoder->srcpad);
+      GstQuery *query = gst_query_new_allocation (caps, FALSE);
+      gst_pad_peer_query (decoder->srcpad, query);
+      gst_query_unref (query);
+      gst_caps_unref (caps);
+    }
+
+    gst_v4l2_object_stop (self->v4l2capture);
+    self->output_flow = GST_FLOW_OK;
+  }
+
+  ret = gst_v4l2_object_set_format (self->v4l2output, state->caps, &error);
+
+  if (ret)
+    self->input_state = gst_video_codec_state_ref (state);
+  else
+    gst_v4l2_error (self, &error);
+
+done:
+  return ret;
+}
+
+static gboolean
+gst_v4l2_video_dec_flush (GstVideoDecoder * decoder)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+
+  GST_DEBUG_OBJECT (self, "Flushed");
+
+  /* Ensure the processing thread has stopped for the reverse playback
+   * discount case */
+  if (gst_pad_get_task_state (decoder->srcpad) == GST_TASK_STARTED) {
+    GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
+
+    gst_v4l2_object_unlock (self->v4l2output);
+    gst_v4l2_object_unlock (self->v4l2capture);
+    gst_pad_stop_task (decoder->srcpad);
+    GST_VIDEO_DECODER_STREAM_LOCK (decoder);
+  }
+
+  self->output_flow = GST_FLOW_OK;
+
+  if (self->v4l2output->pool)
+    gst_v4l2_buffer_pool_flush (self->v4l2output->pool);
+
+  if (self->v4l2capture->pool)
+    gst_v4l2_buffer_pool_flush (self->v4l2capture->pool);
+
+  gst_v4l2_object_unlock_stop (self->v4l2output);
+  gst_v4l2_object_unlock_stop (self->v4l2capture);
+
+  return TRUE;
+}
+
+static gboolean
+gst_v4l2_video_dec_negotiate (GstVideoDecoder * decoder)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+
+  /* We don't allow renegotiation without carefull disabling the pool */
+  if (self->v4l2capture->pool &&
+      gst_buffer_pool_is_active (GST_BUFFER_POOL (self->v4l2capture->pool)))
+    return TRUE;
+
+  return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
+}
+
+static gboolean
+gst_v4l2_decoder_cmd (GstV4l2Object * v4l2object, guint cmd, guint flags)
+{
+  struct v4l2_decoder_cmd dcmd = { 0, };
+
+  GST_DEBUG_OBJECT (v4l2object->element,
+      "sending v4l2 decoder command %u with flags %u", cmd, flags);
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  dcmd.cmd = cmd;
+  dcmd.flags = flags;
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_DECODER_CMD, &dcmd) < 0)
+    goto dcmd_failed;
+
+  return TRUE;
+
+dcmd_failed:
+  if (errno == ENOTTY) {
+    GST_INFO_OBJECT (v4l2object->element,
+        "Failed to send decoder command %u with flags %u for '%s'. (%s)",
+        cmd, flags, v4l2object->videodev, g_strerror (errno));
+  } else {
+    GST_ERROR_OBJECT (v4l2object->element,
+        "Failed to send decoder command %u with flags %u for '%s'. (%s)",
+        cmd, flags, v4l2object->videodev, g_strerror (errno));
+  }
+  return FALSE;
+}
+
+static GstFlowReturn
+gst_v4l2_video_dec_finish (GstVideoDecoder * decoder)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBuffer *buffer;
+
+  if (gst_pad_get_task_state (decoder->srcpad) != GST_TASK_STARTED)
+    goto done;
+
+  GST_DEBUG_OBJECT (self, "Finishing decoding");
+
+  GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
+
+  if (gst_v4l2_decoder_cmd (self->v4l2output, V4L2_DEC_CMD_STOP, 0)) {
+    GstTask *task = decoder->srcpad->task;
+
+    /* If the decoder stop command succeeded, just wait until processing is
+     * finished */
+    GST_OBJECT_LOCK (task);
+    while (GST_TASK_STATE (task) == GST_TASK_STARTED)
+      GST_TASK_WAIT (task);
+    GST_OBJECT_UNLOCK (task);
+    ret = GST_FLOW_FLUSHING;
+  } else {
+    /* otherwise keep queuing empty buffers until the processing thread has
+     * stopped, _pool_process() will return FLUSHING when that happened */
+    while (ret == GST_FLOW_OK) {
+      buffer = gst_buffer_new ();
+      ret =
+          gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
+              v4l2output->pool), &buffer);
+      gst_buffer_unref (buffer);
+    }
+  }
+
+  /* and ensure the processing thread has stopped in case another error
+   * occured. */
+  gst_v4l2_object_unlock (self->v4l2capture);
+  gst_pad_stop_task (decoder->srcpad);
+  GST_VIDEO_DECODER_STREAM_LOCK (decoder);
+
+  if (ret == GST_FLOW_FLUSHING)
+    ret = self->output_flow;
+
+  GST_DEBUG_OBJECT (decoder, "Done draining buffers");
+
+  /* TODO Shall we cleanup any reffed frame to workaround broken decoders ? */
+
+done:
+  return ret;
+}
+
+static gboolean
+gst_v4l2_video_dec_drain (GstVideoDecoder * decoder)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+
+  GST_DEBUG_OBJECT (self, "Draining...");
+  gst_v4l2_video_dec_finish (decoder);
+  gst_v4l2_video_dec_flush (decoder);
+
+  return TRUE;
+}
+
+static GstVideoCodecFrame *
+gst_v4l2_video_dec_get_oldest_frame (GstVideoDecoder * decoder)
+{
+  GstVideoCodecFrame *frame = NULL;
+  GList *frames, *l;
+  gint count = 0;
+
+  frames = gst_video_decoder_get_frames (decoder);
+
+  for (l = frames; l != NULL; l = l->next) {
+    GstVideoCodecFrame *f = l->data;
+
+    if (!frame || frame->pts > f->pts)
+      frame = f;
+
+    count++;
+  }
+
+  if (frame) {
+    GST_LOG_OBJECT (decoder,
+        "Oldest frame is %d %" GST_TIME_FORMAT " and %d frames left",
+        frame->system_frame_number, GST_TIME_ARGS (frame->pts), count - 1);
+    gst_video_codec_frame_ref (frame);
+  }
+
+  g_list_free_full (frames, (GDestroyNotify) gst_video_codec_frame_unref);
+
+  return frame;
+}
+
+static void
+gst_v4l2_video_dec_loop (GstVideoDecoder * decoder)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+  GstV4l2BufferPool *v4l2_pool = GST_V4L2_BUFFER_POOL (self->v4l2capture->pool);
+  GstBufferPool *pool;
+  GstVideoCodecFrame *frame;
+  GstBuffer *buffer = NULL;
+  GstFlowReturn ret;
+
+  GST_LOG_OBJECT (decoder, "Allocate output buffer");
+
+  self->output_flow = GST_FLOW_OK;
+  do {
+    /* We cannot use the base class allotate helper since it taking the internal
+     * stream lock. we know that the acquire may need to poll until more frames
+     * comes in and holding this lock would prevent that.
+     */
+    pool = gst_video_decoder_get_buffer_pool (decoder);
+
+    /* Pool may be NULL if we started going to READY state */
+    if (pool == NULL) {
+      ret = GST_FLOW_FLUSHING;
+      goto beach;
+    }
+
+    ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
+    g_object_unref (pool);
+
+    if (ret != GST_FLOW_OK)
+      goto beach;
+
+    GST_LOG_OBJECT (decoder, "Process output buffer");
+    ret = gst_v4l2_buffer_pool_process (v4l2_pool, &buffer);
+
+  } while (ret == GST_V4L2_FLOW_CORRUPTED_BUFFER);
+
+  if (ret != GST_FLOW_OK)
+    goto beach;
+
+  frame = gst_v4l2_video_dec_get_oldest_frame (decoder);
+
+  if (frame) {
+    frame->output_buffer = buffer;
+    buffer = NULL;
+    ret = gst_video_decoder_finish_frame (decoder, frame);
+
+    if (ret != GST_FLOW_OK)
+      goto beach;
+  } else {
+    GST_WARNING_OBJECT (decoder, "Decoder is producing too many buffers");
+    gst_buffer_unref (buffer);
+  }
+
+  return;
+
+beach:
+  GST_DEBUG_OBJECT (decoder, "Leaving output thread: %s",
+      gst_flow_get_name (ret));
+
+  gst_buffer_replace (&buffer, NULL);
+  self->output_flow = ret;
+  gst_v4l2_object_unlock (self->v4l2output);
+  gst_pad_pause_task (decoder->srcpad);
+}
+
+static gboolean
+gst_v4l2_video_remove_padding (GstCapsFeatures * features,
+    GstStructure * structure, gpointer user_data)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (user_data);
+  GstVideoAlignment *align = &self->v4l2capture->align;
+  GstVideoInfo *info = &self->v4l2capture->info;
+  int width, height;
+
+  if (!gst_structure_get_int (structure, "width", &width))
+    return TRUE;
+
+  if (!gst_structure_get_int (structure, "height", &height))
+    return TRUE;
+
+  if (align->padding_left != 0 || align->padding_top != 0 ||
+      height != info->height + align->padding_bottom)
+    return TRUE;
+
+  if (height == info->height + align->padding_bottom) {
+    /* Some drivers may round up width to the padded with */
+    if (width == info->width + align->padding_right)
+      gst_structure_set (structure,
+          "width", G_TYPE_INT, width - align->padding_right,
+          "height", G_TYPE_INT, height - align->padding_bottom, NULL);
+    /* Some drivers may keep visible width and only round up bytesperline */
+    else if (width == info->width)
+      gst_structure_set (structure,
+          "height", G_TYPE_INT, height - align->padding_bottom, NULL);
+  }
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
+    GstVideoCodecFrame * frame)
+{
+  GstV4l2Error error = GST_V4L2_ERROR_INIT;
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+  GstFlowReturn ret = GST_FLOW_OK;
+  gboolean processed = FALSE;
+  GstBuffer *tmp;
+  GstTaskState task_state;
+
+  GST_DEBUG_OBJECT (self, "Handling frame %d", frame->system_frame_number);
+
+  if (G_UNLIKELY (!g_atomic_int_get (&self->active)))
+    goto flushing;
+
+  if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2output))) {
+    if (!self->input_state)
+      goto not_negotiated;
+    if (!gst_v4l2_object_set_format (self->v4l2output, self->input_state->caps,
+            &error))
+      goto not_negotiated;
+  }
+
+  if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2capture))) {
+    GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool);
+    GstVideoInfo info;
+    GstVideoCodecState *output_state;
+    GstBuffer *codec_data;
+    GstCaps *acquired_caps, *available_caps, *caps, *filter;
+    GstStructure *st;
+
+    GST_DEBUG_OBJECT (self, "Sending header");
+
+    codec_data = self->input_state->codec_data;
+
+    /* We are running in byte-stream mode, so we don't know the headers, but
+     * we need to send something, otherwise the decoder will refuse to
+     * intialize.
+     */
+    if (codec_data) {
+      gst_buffer_ref (codec_data);
+    } else {
+      codec_data = gst_buffer_ref (frame->input_buffer);
+      processed = TRUE;
+    }
+
+    /* Ensure input internal pool is active */
+    if (!gst_buffer_pool_is_active (pool)) {
+      GstStructure *config = gst_buffer_pool_get_config (pool);
+      gst_buffer_pool_config_set_params (config, self->input_state->caps,
+          self->v4l2output->info.size, 2, 2);
+
+      /* There is no reason to refuse this config */
+      if (!gst_buffer_pool_set_config (pool, config))
+        goto activate_failed;
+
+      if (!gst_buffer_pool_set_active (pool, TRUE))
+        goto activate_failed;
+    }
+
+    GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
+    ret =
+        gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
+            v4l2output->pool), &codec_data);
+    GST_VIDEO_DECODER_STREAM_LOCK (decoder);
+
+    gst_buffer_unref (codec_data);
+
+    /* For decoders G_FMT returns coded size, G_SELECTION returns visible size
+     * in the compose rectangle. gst_v4l2_object_acquire_format() checks both
+     * and returns the visible size as with/height and the coded size as
+     * padding. */
+    if (!gst_v4l2_object_acquire_format (self->v4l2capture, &info))
+      goto not_negotiated;
+
+    /* Create caps from the acquired format, remove the format field */
+    acquired_caps = gst_video_info_to_caps (&info);
+    GST_DEBUG_OBJECT (self, "Acquired caps: %" GST_PTR_FORMAT, acquired_caps);
+    st = gst_caps_get_structure (acquired_caps, 0);
+    gst_structure_remove_field (st, "format");
+
+    /* Probe currently available pixel formats */
+    available_caps = gst_v4l2_object_probe_caps (self->v4l2capture, NULL);
+    available_caps = gst_caps_make_writable (available_caps);
+    GST_DEBUG_OBJECT (self, "Available caps: %" GST_PTR_FORMAT, available_caps);
+
+    /* Replace coded size with visible size, we want to negotiate visible size
+     * with downstream, not coded size. */
+    gst_caps_map_in_place (available_caps, gst_v4l2_video_remove_padding, self);
+
+    filter = gst_caps_intersect_full (available_caps, acquired_caps,
+        GST_CAPS_INTERSECT_FIRST);
+    GST_DEBUG_OBJECT (self, "Filtered caps: %" GST_PTR_FORMAT, filter);
+    gst_caps_unref (acquired_caps);
+    gst_caps_unref (available_caps);
+    caps = gst_pad_peer_query_caps (decoder->srcpad, filter);
+    gst_caps_unref (filter);
+
+    GST_DEBUG_OBJECT (self, "Possible decoded caps: %" GST_PTR_FORMAT, caps);
+    if (gst_caps_is_empty (caps)) {
+      gst_caps_unref (caps);
+      goto not_negotiated;
+    }
+
+    /* Fixate pixel format */
+    caps = gst_caps_fixate (caps);
+
+    GST_DEBUG_OBJECT (self, "Chosen decoded caps: %" GST_PTR_FORMAT, caps);
+
+    /* Try to set negotiated format, on success replace acquired format */
+    if (gst_v4l2_object_set_format (self->v4l2capture, caps, &error))
+      gst_video_info_from_caps (&info, caps);
+    else
+      gst_v4l2_clear_error (&error);
+    gst_caps_unref (caps);
+
+    output_state = gst_video_decoder_set_output_state (decoder,
+        info.finfo->format, info.width, info.height, self->input_state);
+
+    /* Copy the rest of the information, there might be more in the future */
+    output_state->info.interlace_mode = info.interlace_mode;
+    gst_video_codec_state_unref (output_state);
+
+    if (!gst_video_decoder_negotiate (decoder)) {
+      if (GST_PAD_IS_FLUSHING (decoder->srcpad))
+        goto flushing;
+      else
+        goto not_negotiated;
+    }
+
+    /* Ensure our internal pool is activated */
+    if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (self->v4l2capture->pool),
+            TRUE))
+      goto activate_failed;
+  }
+
+  task_state = gst_pad_get_task_state (GST_VIDEO_DECODER_SRC_PAD (self));
+  if (task_state == GST_TASK_STOPPED || task_state == GST_TASK_PAUSED) {
+    /* It's possible that the processing thread stopped due to an error */
+    if (self->output_flow != GST_FLOW_OK &&
+        self->output_flow != GST_FLOW_FLUSHING) {
+      GST_DEBUG_OBJECT (self, "Processing loop stopped with error, leaving");
+      ret = self->output_flow;
+      goto drop;
+    }
+
+    GST_DEBUG_OBJECT (self, "Starting decoding thread");
+
+    /* Start the processing task, when it quits, the task will disable input
+     * processing to unlock input if draining, or prevent potential block */
+    self->output_flow = GST_FLOW_FLUSHING;
+    if (!gst_pad_start_task (decoder->srcpad,
+            (GstTaskFunction) gst_v4l2_video_dec_loop, self, NULL))
+      goto start_task_failed;
+  }
+
+  if (!processed) {
+    GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
+    ret =
+        gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->v4l2output->
+            pool), &frame->input_buffer);
+    GST_VIDEO_DECODER_STREAM_LOCK (decoder);
+
+    if (ret == GST_FLOW_FLUSHING) {
+      if (gst_pad_get_task_state (GST_VIDEO_DECODER_SRC_PAD (self)) !=
+          GST_TASK_STARTED)
+        ret = self->output_flow;
+      goto drop;
+    } else if (ret != GST_FLOW_OK) {
+      goto process_failed;
+    }
+  }
+
+  /* No need to keep input arround */
+  tmp = frame->input_buffer;
+  frame->input_buffer = gst_buffer_new ();
+  gst_buffer_copy_into (frame->input_buffer, tmp,
+      GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
+      GST_BUFFER_COPY_META, 0, 0);
+  gst_buffer_unref (tmp);
+
+  gst_video_codec_frame_unref (frame);
+  return ret;
+
+  /* ERRORS */
+not_negotiated:
+  {
+    GST_ERROR_OBJECT (self, "not negotiated");
+    ret = GST_FLOW_NOT_NEGOTIATED;
+    gst_v4l2_error (self, &error);
+    goto drop;
+  }
+activate_failed:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+        (_("Failed to allocate required memory.")),
+        ("Buffer pool activation failed"));
+    ret = GST_FLOW_ERROR;
+    goto drop;
+  }
+flushing:
+  {
+    ret = GST_FLOW_FLUSHING;
+    goto drop;
+  }
+
+start_task_failed:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
+        (_("Failed to start decoding thread.")), (NULL));
+    ret = GST_FLOW_ERROR;
+    goto drop;
+  }
+process_failed:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
+        (_("Failed to process frame.")),
+        ("Maybe be due to not enough memory or failing driver"));
+    ret = GST_FLOW_ERROR;
+    goto drop;
+  }
+drop:
+  {
+    gst_video_decoder_drop_frame (decoder, frame);
+    return ret;
+  }
+}
+
+static gboolean
+gst_v4l2_video_dec_decide_allocation (GstVideoDecoder * decoder,
+    GstQuery * query)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+  GstClockTime latency;
+  gboolean ret = FALSE;
+
+  if (gst_v4l2_object_decide_allocation (self->v4l2capture, query))
+    ret = GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (decoder,
+        query);
+
+  if (GST_CLOCK_TIME_IS_VALID (self->v4l2capture->duration)) {
+    latency = self->v4l2capture->min_buffers * self->v4l2capture->duration;
+    GST_DEBUG_OBJECT (self, "Setting latency: %" GST_TIME_FORMAT " (%"
+        G_GUINT32_FORMAT " * %" G_GUINT64_FORMAT, GST_TIME_ARGS (latency),
+        self->v4l2capture->min_buffers, self->v4l2capture->duration);
+    gst_video_decoder_set_latency (decoder, latency, latency);
+  } else {
+    GST_WARNING_OBJECT (self, "Duration invalid, not setting latency");
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_v4l2_video_dec_src_query (GstVideoDecoder * decoder, GstQuery * query)
+{
+  gboolean ret = TRUE;
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:{
+      GstCaps *filter, *result = NULL;
+      GstPad *pad = GST_VIDEO_DECODER_SRC_PAD (decoder);
+
+      gst_query_parse_caps (query, &filter);
+
+      if (self->probed_srccaps)
+        result = gst_caps_ref (self->probed_srccaps);
+      else
+        result = gst_pad_get_pad_template_caps (pad);
+
+      if (filter) {
+        GstCaps *tmp = result;
+        result =
+            gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
+        gst_caps_unref (tmp);
+      }
+
+      GST_DEBUG_OBJECT (self, "Returning src caps %" GST_PTR_FORMAT, result);
+
+      gst_query_set_caps_result (query, result);
+      gst_caps_unref (result);
+      break;
+    }
+
+    default:
+      ret = GST_VIDEO_DECODER_CLASS (parent_class)->src_query (decoder, query);
+      break;
+  }
+
+  return ret;
+}
+
+static GstCaps *
+gst_v4l2_video_dec_sink_getcaps (GstVideoDecoder * decoder, GstCaps * filter)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+  GstCaps *result;
+
+  result = gst_video_decoder_proxy_getcaps (decoder, self->probed_sinkcaps,
+      filter);
+
+  GST_DEBUG_OBJECT (self, "Returning sink caps %" GST_PTR_FORMAT, result);
+
+  return result;
+}
+
+static gboolean
+gst_v4l2_video_dec_sink_event (GstVideoDecoder * decoder, GstEvent * event)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+  gboolean ret;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      GST_DEBUG_OBJECT (self, "flush start");
+      gst_v4l2_object_unlock (self->v4l2output);
+      gst_v4l2_object_unlock (self->v4l2capture);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (decoder, event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      /* The processing thread should stop now, wait for it */
+      gst_pad_stop_task (decoder->srcpad);
+      GST_DEBUG_OBJECT (self, "flush start done");
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static GstStateChangeReturn
+gst_v4l2_video_dec_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (element);
+  GstVideoDecoder *decoder = GST_VIDEO_DECODER (element);
+
+  if (transition == GST_STATE_CHANGE_PAUSED_TO_READY) {
+    g_atomic_int_set (&self->active, FALSE);
+    gst_v4l2_object_unlock (self->v4l2output);
+    gst_v4l2_object_unlock (self->v4l2capture);
+    gst_pad_stop_task (decoder->srcpad);
+  }
+
+  return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+}
+
+static void
+gst_v4l2_video_dec_dispose (GObject * object)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (object);
+
+  gst_caps_replace (&self->probed_sinkcaps, NULL);
+  gst_caps_replace (&self->probed_srccaps, NULL);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_v4l2_video_dec_finalize (GObject * object)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (object);
+
+  gst_v4l2_object_destroy (self->v4l2capture);
+  gst_v4l2_object_destroy (self->v4l2output);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_v4l2_video_dec_init (GstV4l2VideoDec * self)
+{
+  /* V4L2 object are created in subinstance_init */
+}
+
+static void
+gst_v4l2_video_dec_subinstance_init (GTypeInstance * instance, gpointer g_class)
+{
+  GstV4l2VideoDecClass *klass = GST_V4L2_VIDEO_DEC_CLASS (g_class);
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (instance);
+  GstVideoDecoder *decoder = GST_VIDEO_DECODER (instance);
+
+  gst_video_decoder_set_packetized (decoder, TRUE);
+
+  self->v4l2output = gst_v4l2_object_new (GST_ELEMENT (self),
+      GST_OBJECT (GST_VIDEO_DECODER_SINK_PAD (self)),
+      V4L2_BUF_TYPE_VIDEO_OUTPUT, klass->default_device,
+      gst_v4l2_get_output, gst_v4l2_set_output, NULL);
+  self->v4l2output->no_initial_format = TRUE;
+  self->v4l2output->keep_aspect = FALSE;
+
+  self->v4l2capture = gst_v4l2_object_new (GST_ELEMENT (self),
+      GST_OBJECT (GST_VIDEO_DECODER_SRC_PAD (self)),
+      V4L2_BUF_TYPE_VIDEO_CAPTURE, klass->default_device,
+      gst_v4l2_get_input, gst_v4l2_set_input, NULL);
+  self->v4l2capture->no_initial_format = TRUE;
+  self->v4l2output->keep_aspect = FALSE;
+}
+
+static void
+gst_v4l2_video_dec_class_init (GstV4l2VideoDecClass * klass)
+{
+  GstElementClass *element_class;
+  GObjectClass *gobject_class;
+  GstVideoDecoderClass *video_decoder_class;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  element_class = (GstElementClass *) klass;
+  gobject_class = (GObjectClass *) klass;
+  video_decoder_class = (GstVideoDecoderClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (gst_v4l2_video_dec_debug, "v4l2videodec", 0,
+      "V4L2 Video Decoder");
+
+  gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_dispose);
+  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_finalize);
+  gobject_class->set_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_set_property);
+  gobject_class->get_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_get_property);
+
+  video_decoder_class->open = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_open);
+  video_decoder_class->close = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_close);
+  video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_start);
+  video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_stop);
+  video_decoder_class->finish = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_finish);
+  video_decoder_class->flush = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_flush);
+  video_decoder_class->drain = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_drain);
+  video_decoder_class->set_format =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_set_format);
+  video_decoder_class->negotiate =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_negotiate);
+  video_decoder_class->decide_allocation =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_decide_allocation);
+  /* FIXME propose_allocation or not ? */
+  video_decoder_class->handle_frame =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_handle_frame);
+  video_decoder_class->getcaps =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_sink_getcaps);
+  video_decoder_class->src_query =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_src_query);
+  video_decoder_class->sink_event =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_sink_event);
+
+  element_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_change_state);
+
+  gst_v4l2_object_install_m2m_properties_helper (gobject_class);
+}
+
+static void
+gst_v4l2_video_dec_subclass_init (gpointer g_class, gpointer data)
+{
+  GstV4l2VideoDecClass *klass = GST_V4L2_VIDEO_DEC_CLASS (g_class);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+  GstV4l2VideoDecCData *cdata = data;
+
+  klass->default_device = cdata->device;
+
+  /* Note: gst_pad_template_new() take the floating ref from the caps */
+  gst_element_class_add_pad_template (element_class,
+      gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+          cdata->sink_caps));
+  gst_element_class_add_pad_template (element_class,
+      gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+          cdata->src_caps));
+
+  gst_element_class_set_static_metadata (element_class, cdata->longname,
+      "Codec/Decoder/Video", cdata->description,
+      "Nicolas Dufresne <nicolas.dufresne@collabora.com>");
+
+  gst_caps_unref (cdata->sink_caps);
+  gst_caps_unref (cdata->src_caps);
+  g_free (cdata);
+}
+
+/* Probing functions */
+gboolean
+gst_v4l2_is_video_dec (GstCaps * sink_caps, GstCaps * src_caps)
+{
+  gboolean ret = FALSE;
+
+  if (gst_caps_is_subset (sink_caps, gst_v4l2_object_get_codec_caps ())
+      && gst_caps_is_subset (src_caps, gst_v4l2_object_get_raw_caps ()))
+    ret = TRUE;
+
+  return ret;
+}
+
+static gchar *
+gst_v4l2_video_dec_set_metadata (GstStructure * s, GstV4l2VideoDecCData * cdata,
+    const gchar * basename)
+{
+  gchar *codec_name = NULL;
+  gchar *type_name = NULL;
+
+#define SET_META(codec) \
+G_STMT_START { \
+  cdata->longname = "V4L2 " codec " Decoder"; \
+  cdata->description = "Decodes " codec " streams via V4L2 API"; \
+  codec_name = g_ascii_strdown (codec, -1); \
+} G_STMT_END
+
+  if (gst_structure_has_name (s, "image/jpeg")) {
+    SET_META ("JPEG");
+  } else if (gst_structure_has_name (s, "video/mpeg")) {
+    gint mpegversion = 0;
+    gst_structure_get_int (s, "mpegversion", &mpegversion);
+
+    if (mpegversion == 2) {
+      SET_META ("MPEG2");
+    } else {
+      SET_META ("MPEG4");
+    }
+  } else if (gst_structure_has_name (s, "video/x-h263")) {
+    SET_META ("H263");
+  } else if (gst_structure_has_name (s, "video/x-h264")) {
+    SET_META ("H264");
+  } else if (gst_structure_has_name (s, "video/x-wmv")) {
+    SET_META ("VC1");
+  } else if (gst_structure_has_name (s, "video/x-vp8")) {
+    SET_META ("VP8");
+  } else if (gst_structure_has_name (s, "video/x-vp9")) {
+    SET_META ("VP9");
+  } else if (gst_structure_has_name (s, "video/x-bayer")) {
+    SET_META ("BAYER");
+  } else if (gst_structure_has_name (s, "video/x-sonix")) {
+    SET_META ("SONIX");
+  } else if (gst_structure_has_name (s, "video/x-pwc1")) {
+    SET_META ("PWC1");
+  } else if (gst_structure_has_name (s, "video/x-pwc2")) {
+    SET_META ("PWC2");
+  } else {
+    /* This code should be kept on sync with the exposed CODEC type of format
+     * from gstv4l2object.c. This warning will only occure in case we forget
+     * to also add a format here. */
+    gchar *s_str = gst_structure_to_string (s);
+    g_warning ("Missing fixed name mapping for caps '%s', this is a GStreamer "
+        "bug, please report at https://bugs.gnome.org", s_str);
+    g_free (s_str);
+  }
+
+  if (codec_name) {
+    type_name = g_strdup_printf ("v4l2%sdec", codec_name);
+    if (g_type_from_name (type_name) != 0) {
+      g_free (type_name);
+      type_name = g_strdup_printf ("v4l2%s%sdec", basename, codec_name);
+    }
+
+    g_free (codec_name);
+  }
+
+  return type_name;
+#undef SET_META
+}
+
+void
+gst_v4l2_video_dec_register (GstPlugin * plugin, const gchar * basename,
+    const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps)
+{
+  gint i;
+
+  for (i = 0; i < gst_caps_get_size (sink_caps); i++) {
+    GstV4l2VideoDecCData *cdata;
+    GstStructure *s;
+    GTypeQuery type_query;
+    GTypeInfo type_info = { 0, };
+    GType type, subtype;
+    gchar *type_name;
+
+    s = gst_caps_get_structure (sink_caps, i);
+
+    cdata = g_new0 (GstV4l2VideoDecCData, 1);
+    cdata->device = g_strdup (device_path);
+    cdata->sink_caps = gst_caps_new_empty ();
+    gst_caps_append_structure (cdata->sink_caps, gst_structure_copy (s));
+    cdata->src_caps = gst_caps_ref (src_caps);
+    type_name = gst_v4l2_video_dec_set_metadata (s, cdata, basename);
+
+    /* Skip over if we hit an unmapped type */
+    if (!type_name) {
+      g_free (cdata);
+      continue;
+    }
+
+    type = gst_v4l2_video_dec_get_type ();
+    g_type_query (type, &type_query);
+    memset (&type_info, 0, sizeof (type_info));
+    type_info.class_size = type_query.class_size;
+    type_info.instance_size = type_query.instance_size;
+    type_info.class_init = gst_v4l2_video_dec_subclass_init;
+    type_info.class_data = cdata;
+    type_info.instance_init = gst_v4l2_video_dec_subinstance_init;
+
+    subtype = g_type_register_static (type, type_name, &type_info, 0);
+    if (!gst_element_register (plugin, type_name, GST_RANK_PRIMARY + 1,
+            subtype))
+      GST_WARNING ("Failed to register plugin '%s'", type_name);
+
+    g_free (type_name);
+  }
+}
diff --git a/sys/v4l2/gstv4l2videodec.h b/sys/v4l2/gstv4l2videodec.h
new file mode 100644
index 0000000..be97d10
--- /dev/null
+++ b/sys/v4l2/gstv4l2videodec.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2014 Collabora Ltd.
+ *     Author: Nicolas Dufresne <nicolas.dufresne@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __GST_V4L2_VIDEO_DEC_H__
+#define __GST_V4L2_VIDEO_DEC_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideodecoder.h>
+#include <gst/video/gstvideometa.h>
+
+#include <gstv4l2object.h>
+#include <gstv4l2bufferpool.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_V4L2_VIDEO_DEC \
+  (gst_v4l2_video_dec_get_type())
+#define GST_V4L2_VIDEO_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_VIDEO_DEC,GstV4l2VideoDec))
+#define GST_V4L2_VIDEO_DEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_VIDEO_DEC,GstV4l2VideoDecClass))
+#define GST_IS_V4L2_VIDEO_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_VIDEO_DEC))
+#define GST_IS_V4L2_VIDEO_DEC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_VIDEO_DEC))
+
+typedef struct _GstV4l2VideoDec GstV4l2VideoDec;
+typedef struct _GstV4l2VideoDecClass GstV4l2VideoDecClass;
+
+struct _GstV4l2VideoDec
+{
+  GstVideoDecoder parent;
+
+  /* < private > */
+  GstV4l2Object * v4l2output;
+  GstV4l2Object * v4l2capture;
+
+  /* pads */
+  GstCaps *probed_srccaps;
+  GstCaps *probed_sinkcaps;
+
+  /* State */
+  GstVideoCodecState *input_state;
+  gboolean active;
+  GstFlowReturn output_flow;
+};
+
+struct _GstV4l2VideoDecClass
+{
+  GstVideoDecoderClass parent_class;
+
+  gchar *default_device;
+};
+
+GType gst_v4l2_video_dec_get_type (void);
+
+gboolean gst_v4l2_is_video_dec       (GstCaps * sink_caps, GstCaps * src_caps);
+void     gst_v4l2_video_dec_register (GstPlugin * plugin,
+                                      const gchar *basename,
+                                      const gchar *device_path,
+                                      GstCaps * sink_caps, GstCaps * src_caps);
+
+G_END_DECLS
+
+#endif /* __GST_V4L2_VIDEO_DEC_H__ */
diff --git a/sys/v4l2/gstv4l2videoenc.c b/sys/v4l2/gstv4l2videoenc.c
new file mode 100644
index 0000000..d365a25
--- /dev/null
+++ b/sys/v4l2/gstv4l2videoenc.c
@@ -0,0 +1,1189 @@
+/*
+ * Copyright (C) 2014-2017 SUMOMO Computer Association
+ *     Authors Ayaka <ayaka@soulik.info>
+ * Copyright (C) 2017 Collabora Ltd.
+ *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gstv4l2object.h"
+#include "gstv4l2videoenc.h"
+
+#include <string.h>
+#include <gst/gst-i18n-plugin.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_v4l2_video_enc_debug);
+#define GST_CAT_DEFAULT gst_v4l2_video_enc_debug
+
+typedef struct
+{
+  gchar *device;
+  GstCaps *sink_caps;
+  GstCaps *src_caps;
+} GstV4l2VideoEncCData;
+
+enum
+{
+  PROP_0,
+  V4L2_STD_OBJECT_PROPS,
+};
+
+#define gst_v4l2_video_enc_parent_class parent_class
+G_DEFINE_ABSTRACT_TYPE (GstV4l2VideoEnc, gst_v4l2_video_enc,
+    GST_TYPE_VIDEO_ENCODER);
+
+static void
+gst_v4l2_video_enc_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (object);
+
+  switch (prop_id) {
+    case PROP_CAPTURE_IO_MODE:
+      if (!gst_v4l2_object_set_property_helper (self->v4l2capture,
+              prop_id, value, pspec)) {
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      }
+      break;
+
+      /* By default, only set on output */
+    default:
+      if (!gst_v4l2_object_set_property_helper (self->v4l2output,
+              prop_id, value, pspec)) {
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      }
+      break;
+  }
+}
+
+static void
+gst_v4l2_video_enc_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (object);
+
+  switch (prop_id) {
+    case PROP_CAPTURE_IO_MODE:
+      if (!gst_v4l2_object_get_property_helper (self->v4l2capture,
+              prop_id, value, pspec)) {
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      }
+      break;
+
+      /* By default read from output */
+    default:
+      if (!gst_v4l2_object_get_property_helper (self->v4l2output,
+              prop_id, value, pspec)) {
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      }
+      break;
+  }
+}
+
+static gboolean
+gst_v4l2_video_enc_open (GstVideoEncoder * encoder)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
+  GstCaps *codec_caps;
+
+  GST_DEBUG_OBJECT (self, "Opening");
+
+  if (!gst_v4l2_object_open (self->v4l2output))
+    goto failure;
+
+  if (!gst_v4l2_object_open_shared (self->v4l2capture, self->v4l2output))
+    goto failure;
+
+  self->probed_sinkcaps = gst_v4l2_object_probe_caps (self->v4l2output,
+      gst_v4l2_object_get_raw_caps ());
+
+  if (gst_caps_is_empty (self->probed_sinkcaps))
+    goto no_raw_format;
+
+  codec_caps = gst_pad_get_pad_template_caps (encoder->srcpad);
+  self->probed_srccaps = gst_v4l2_object_probe_caps (self->v4l2capture,
+      codec_caps);
+  gst_caps_unref (codec_caps);
+
+  if (gst_caps_is_empty (self->probed_srccaps))
+    goto no_encoded_format;
+
+  return TRUE;
+
+no_encoded_format:
+  GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+      (_("Encoder on device %s has no supported output format"),
+          self->v4l2output->videodev), (NULL));
+  goto failure;
+
+
+no_raw_format:
+  GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+      (_("Encoder on device %s has no supported input format"),
+          self->v4l2output->videodev), (NULL));
+  goto failure;
+
+failure:
+  if (GST_V4L2_IS_OPEN (self->v4l2output))
+    gst_v4l2_object_close (self->v4l2output);
+
+  if (GST_V4L2_IS_OPEN (self->v4l2capture))
+    gst_v4l2_object_close (self->v4l2capture);
+
+  gst_caps_replace (&self->probed_srccaps, NULL);
+  gst_caps_replace (&self->probed_sinkcaps, NULL);
+
+  return FALSE;
+}
+
+static gboolean
+gst_v4l2_video_enc_close (GstVideoEncoder * encoder)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
+
+  GST_DEBUG_OBJECT (self, "Closing");
+
+  gst_v4l2_object_close (self->v4l2output);
+  gst_v4l2_object_close (self->v4l2capture);
+  gst_caps_replace (&self->probed_srccaps, NULL);
+  gst_caps_replace (&self->probed_sinkcaps, NULL);
+
+  return TRUE;
+}
+
+static gboolean
+gst_v4l2_video_enc_start (GstVideoEncoder * encoder)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
+
+  GST_DEBUG_OBJECT (self, "Starting");
+
+  gst_v4l2_object_unlock (self->v4l2output);
+  g_atomic_int_set (&self->active, TRUE);
+  self->output_flow = GST_FLOW_OK;
+
+  return TRUE;
+}
+
+static gboolean
+gst_v4l2_video_enc_stop (GstVideoEncoder * encoder)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
+
+  GST_DEBUG_OBJECT (self, "Stopping");
+
+  gst_v4l2_object_unlock (self->v4l2output);
+  gst_v4l2_object_unlock (self->v4l2capture);
+
+  /* Wait for capture thread to stop */
+  gst_pad_stop_task (encoder->srcpad);
+
+  GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
+  self->output_flow = GST_FLOW_OK;
+  GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
+
+  /* Should have been flushed already */
+  g_assert (g_atomic_int_get (&self->active) == FALSE);
+  g_assert (g_atomic_int_get (&self->processing) == FALSE);
+
+  gst_v4l2_object_stop (self->v4l2output);
+  gst_v4l2_object_stop (self->v4l2capture);
+
+  if (self->input_state) {
+    gst_video_codec_state_unref (self->input_state);
+    self->input_state = NULL;
+  }
+
+  GST_DEBUG_OBJECT (self, "Stopped");
+
+  return TRUE;
+}
+
+static gboolean
+gst_v4l2_encoder_cmd (GstV4l2Object * v4l2object, guint cmd, guint flags)
+{
+  struct v4l2_encoder_cmd ecmd = { 0, };
+
+  GST_DEBUG_OBJECT (v4l2object->element,
+      "sending v4l2 encoder command %u with flags %u", cmd, flags);
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  ecmd.cmd = cmd;
+  ecmd.flags = flags;
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_ENCODER_CMD, &ecmd) < 0)
+    goto ecmd_failed;
+
+  return TRUE;
+
+ecmd_failed:
+  if (errno == ENOTTY) {
+    GST_INFO_OBJECT (v4l2object->element,
+        "Failed to send encoder command %u with flags %u for '%s'. (%s)",
+        cmd, flags, v4l2object->videodev, g_strerror (errno));
+  } else {
+    GST_ERROR_OBJECT (v4l2object->element,
+        "Failed to send encoder command %u with flags %u for '%s'. (%s)",
+        cmd, flags, v4l2object->videodev, g_strerror (errno));
+  }
+  return FALSE;
+}
+
+static GstFlowReturn
+gst_v4l2_video_enc_finish (GstVideoEncoder * encoder)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  if (gst_pad_get_task_state (encoder->srcpad) != GST_TASK_STARTED)
+    goto done;
+
+  GST_DEBUG_OBJECT (self, "Finishing encoding");
+
+  /* drop the stream lock while draining, so remaining buffers can be
+   * pushed from the src pad task thread */
+  GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
+
+  if (gst_v4l2_encoder_cmd (self->v4l2capture, V4L2_ENC_CMD_STOP, 0)) {
+    GstTask *task = encoder->srcpad->task;
+
+    /* Wait for the task to be drained */
+    GST_OBJECT_LOCK (task);
+    while (GST_TASK_STATE (task) == GST_TASK_STARTED)
+      GST_TASK_WAIT (task);
+    GST_OBJECT_UNLOCK (task);
+    ret = GST_FLOW_FLUSHING;
+  }
+
+  /* and ensure the processing thread has stopped in case another error
+   * occured. */
+  gst_v4l2_object_unlock (self->v4l2capture);
+  gst_pad_stop_task (encoder->srcpad);
+  GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
+
+  if (ret == GST_FLOW_FLUSHING)
+    ret = self->output_flow;
+
+  GST_DEBUG_OBJECT (encoder, "Done draining buffers");
+
+done:
+  return ret;
+}
+
+static gboolean
+gst_v4l2_video_enc_set_format (GstVideoEncoder * encoder,
+    GstVideoCodecState * state)
+{
+  gboolean ret = TRUE;
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
+  GstV4l2Error error = GST_V4L2_ERROR_INIT;
+  GstCaps *outcaps;
+  GstVideoCodecState *output;
+
+  GST_DEBUG_OBJECT (self, "Setting format: %" GST_PTR_FORMAT, state->caps);
+
+  if (self->input_state) {
+    if (gst_v4l2_object_caps_equal (self->v4l2output, state->caps)) {
+      GST_DEBUG_OBJECT (self, "Compatible caps");
+      return TRUE;
+    }
+
+    if (gst_v4l2_video_enc_finish (encoder) != GST_FLOW_OK)
+      return FALSE;
+
+    gst_v4l2_object_stop (self->v4l2output);
+    gst_v4l2_object_stop (self->v4l2capture);
+
+    gst_video_codec_state_unref (self->input_state);
+    self->input_state = NULL;
+  }
+
+  outcaps = gst_pad_get_pad_template_caps (encoder->srcpad);
+  outcaps = gst_caps_make_writable (outcaps);
+  output = gst_video_encoder_set_output_state (encoder, outcaps, state);
+  gst_video_codec_state_unref (output);
+
+  if (!gst_video_encoder_negotiate (encoder))
+    return FALSE;
+
+  if (!gst_v4l2_object_set_format (self->v4l2output, state->caps, &error)) {
+    gst_v4l2_error (self, &error);
+    return FALSE;
+  }
+
+  /* activating a capture pool will also call STREAMON. CODA driver will
+   * refuse to configure the output if the capture is stremaing. */
+  if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (self->v4l2capture->pool),
+          TRUE)) {
+    GST_WARNING_OBJECT (self, "Could not activate capture buffer pool.");
+    return FALSE;
+  }
+
+  self->input_state = gst_video_codec_state_ref (state);
+
+  GST_DEBUG_OBJECT (self, "output caps: %" GST_PTR_FORMAT, state->caps);
+
+  return ret;
+}
+
+static gboolean
+gst_v4l2_video_enc_flush (GstVideoEncoder * encoder)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
+
+  GST_DEBUG_OBJECT (self, "Flushing");
+
+  /* Ensure the processing thread has stopped for the reverse playback
+   * iscount case */
+  if (g_atomic_int_get (&self->processing)) {
+    GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
+
+    gst_v4l2_object_unlock_stop (self->v4l2output);
+    gst_v4l2_object_unlock_stop (self->v4l2capture);
+    gst_pad_stop_task (encoder->srcpad);
+
+    GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
+
+  }
+
+  self->output_flow = GST_FLOW_OK;
+
+  gst_v4l2_object_unlock_stop (self->v4l2output);
+  gst_v4l2_object_unlock_stop (self->v4l2capture);
+
+  return TRUE;
+}
+
+struct ProfileLevelCtx
+{
+  GstV4l2VideoEnc *self;
+  const gchar *profile;
+  const gchar *level;
+};
+
+static gboolean
+get_string_list (GstStructure * s, const gchar * field, GQueue * queue)
+{
+  const GValue *value;
+
+  value = gst_structure_get_value (s, field);
+
+  if (!value)
+    return FALSE;
+
+  if (GST_VALUE_HOLDS_LIST (value)) {
+    guint i;
+
+    if (gst_value_list_get_size (value) == 0)
+      return FALSE;
+
+    for (i = 0; i < gst_value_list_get_size (value); i++) {
+      const GValue *item = gst_value_list_get_value (value, i);
+
+      if (G_VALUE_HOLDS_STRING (item))
+        g_queue_push_tail (queue, g_value_dup_string (item));
+    }
+  } else if (G_VALUE_HOLDS_STRING (value)) {
+    g_queue_push_tail (queue, g_value_dup_string (value));
+  }
+
+  return TRUE;
+}
+
+static gboolean
+negotiate_profile_and_level (GstCapsFeatures * features, GstStructure * s,
+    gpointer user_data)
+{
+  struct ProfileLevelCtx *ctx = user_data;
+  GstV4l2VideoEncClass *klass = GST_V4L2_VIDEO_ENC_GET_CLASS (ctx->self);
+  GstV4l2Object *v4l2object = GST_V4L2_VIDEO_ENC (ctx->self)->v4l2output;
+  GQueue profiles = G_QUEUE_INIT;
+  GQueue levels = G_QUEUE_INIT;
+  gboolean failed = FALSE;
+
+  if (klass->profile_cid && get_string_list (s, "profile", &profiles)) {
+    GList *l;
+
+    for (l = profiles.head; l; l = l->next) {
+      struct v4l2_control control = { 0, };
+      gint v4l2_profile;
+      const gchar *profile = l->data;
+
+      GST_TRACE_OBJECT (ctx->self, "Trying profile %s", profile);
+
+      control.id = klass->profile_cid;
+      control.value = v4l2_profile = klass->profile_from_string (profile);
+
+      if (control.value < 0)
+        continue;
+
+      if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) {
+        GST_WARNING_OBJECT (ctx->self, "Failed to set %s profile: '%s'",
+            klass->codec_name, g_strerror (errno));
+        break;
+      }
+
+      profile = klass->profile_to_string (control.value);
+
+      if (control.value == v4l2_profile) {
+        ctx->profile = profile;
+        break;
+      }
+
+      if (g_list_find_custom (l, profile, g_str_equal)) {
+        ctx->profile = profile;
+        break;
+      }
+    }
+
+    if (profiles.length && !ctx->profile)
+      failed = TRUE;
+
+    g_queue_foreach (&profiles, (GFunc) g_free, NULL);
+    g_queue_clear (&profiles);
+  }
+
+  if (!failed && klass->level_cid && get_string_list (s, "level", &levels)) {
+    GList *l;
+
+    for (l = levels.head; l; l = l->next) {
+      struct v4l2_control control = { 0, };
+      gint v4l2_level;
+      const gchar *level = l->data;
+
+      GST_TRACE_OBJECT (ctx->self, "Trying level %s", level);
+
+      control.id = klass->level_cid;
+      control.value = v4l2_level = klass->level_from_string (level);
+
+      if (control.value < 0)
+        continue;
+
+      if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) {
+        GST_WARNING_OBJECT (ctx->self, "Failed to set %s level: '%s'",
+            klass->codec_name, g_strerror (errno));
+        break;
+      }
+
+      level = klass->level_to_string (control.value);
+
+      if (control.value == v4l2_level) {
+        ctx->level = level;
+        break;
+      }
+
+      if (g_list_find_custom (l, level, g_str_equal)) {
+        ctx->level = level;
+        break;
+      }
+    }
+
+    if (levels.length && !ctx->level)
+      failed = TRUE;
+
+    g_queue_foreach (&levels, (GFunc) g_free, NULL);
+    g_queue_clear (&levels);
+  }
+
+  /* If it failed, we continue */
+  return failed;
+}
+
+static gboolean
+gst_v4l2_video_enc_negotiate (GstVideoEncoder * encoder)
+{
+  GstV4l2VideoEncClass *klass = GST_V4L2_VIDEO_ENC_GET_CLASS (encoder);
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
+  GstV4l2Object *v4l2object = self->v4l2output;
+  GstCaps *allowed_caps;
+  struct ProfileLevelCtx ctx = { self, NULL, NULL };
+  GstVideoCodecState *state;
+  GstStructure *s;
+
+  GST_DEBUG_OBJECT (self, "Negotiating %s profile and level.",
+      klass->codec_name);
+
+  allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
+
+  if (allowed_caps) {
+
+    if (gst_caps_is_empty (allowed_caps))
+      goto not_negotiated;
+
+    allowed_caps = gst_caps_make_writable (allowed_caps);
+
+    /* negotiate_profile_and_level() will return TRUE on failure to keep
+     * iterating, if gst_caps_foreach() returns TRUE it means there was no
+     * compatible profile and level in any of the structure */
+    if (gst_caps_foreach (allowed_caps, negotiate_profile_and_level, &ctx)) {
+      goto no_profile_level;
+    }
+  }
+
+  if (klass->profile_cid && !ctx.profile) {
+    struct v4l2_control control = { 0, };
+
+    control.id = klass->profile_cid;
+
+    if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
+      goto g_ctrl_failed;
+
+    ctx.profile = klass->profile_to_string (control.value);
+  }
+
+  if (klass->level_cid && !ctx.level) {
+    struct v4l2_control control = { 0, };
+
+    control.id = klass->level_cid;
+
+    if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
+      goto g_ctrl_failed;
+
+    ctx.level = klass->level_to_string (control.value);
+  }
+
+  GST_DEBUG_OBJECT (self, "Selected %s profile %s at level %s",
+      klass->codec_name, ctx.profile, ctx.level);
+
+  state = gst_video_encoder_get_output_state (encoder);
+  s = gst_caps_get_structure (state->caps, 0);
+
+  if (klass->profile_cid)
+    gst_structure_set (s, "profile", G_TYPE_STRING, ctx.profile, NULL);
+
+  if (klass->level_cid)
+    gst_structure_set (s, "level", G_TYPE_STRING, ctx.level, NULL);
+
+  if (!GST_VIDEO_ENCODER_CLASS (parent_class)->negotiate (encoder))
+    return FALSE;
+
+  return TRUE;
+
+g_ctrl_failed:
+  GST_WARNING_OBJECT (self, "Failed to get %s profile and level: '%s'",
+      klass->codec_name, g_strerror (errno));
+  goto not_negotiated;
+
+no_profile_level:
+  GST_WARNING_OBJECT (self, "No compatible level and profile in caps: %"
+      GST_PTR_FORMAT, allowed_caps);
+  goto not_negotiated;
+
+not_negotiated:
+  if (allowed_caps)
+    gst_caps_unref (allowed_caps);
+  return FALSE;
+}
+
+static GstVideoCodecFrame *
+gst_v4l2_video_enc_get_oldest_frame (GstVideoEncoder * encoder)
+{
+  GstVideoCodecFrame *frame = NULL;
+  GList *frames, *l;
+  gint count = 0;
+
+  frames = gst_video_encoder_get_frames (encoder);
+
+  for (l = frames; l != NULL; l = l->next) {
+    GstVideoCodecFrame *f = l->data;
+
+    if (!frame || frame->pts > f->pts)
+      frame = f;
+
+    count++;
+  }
+
+  if (frame) {
+    GST_LOG_OBJECT (encoder,
+        "Oldest frame is %d %" GST_TIME_FORMAT
+        " and %d frames left",
+        frame->system_frame_number, GST_TIME_ARGS (frame->pts), count - 1);
+    gst_video_codec_frame_ref (frame);
+  }
+
+  g_list_free_full (frames, (GDestroyNotify) gst_video_codec_frame_unref);
+
+  return frame;
+}
+
+static void
+gst_v4l2_video_enc_loop (GstVideoEncoder * encoder)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
+  GstVideoCodecFrame *frame;
+  GstBuffer *buffer = NULL;
+  GstFlowReturn ret;
+
+  GST_LOG_OBJECT (encoder, "Allocate output buffer");
+
+  buffer = gst_video_encoder_allocate_output_buffer (encoder,
+      self->v4l2capture->info.size);
+
+  if (NULL == buffer) {
+    ret = GST_FLOW_FLUSHING;
+    goto beach;
+  }
+
+
+  /* FIXME Check if buffer isn't the last one here */
+
+  GST_LOG_OBJECT (encoder, "Process output buffer");
+  ret =
+      gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL
+      (self->v4l2capture->pool), &buffer);
+
+  if (ret != GST_FLOW_OK)
+    goto beach;
+
+  frame = gst_v4l2_video_enc_get_oldest_frame (encoder);
+
+  if (frame) {
+    frame->output_buffer = buffer;
+    buffer = NULL;
+    ret = gst_video_encoder_finish_frame (encoder, frame);
+
+    if (ret != GST_FLOW_OK)
+      goto beach;
+  } else {
+    GST_WARNING_OBJECT (encoder, "Encoder is producing too many buffers");
+    gst_buffer_unref (buffer);
+  }
+
+  return;
+
+beach:
+  GST_DEBUG_OBJECT (encoder, "Leaving output thread");
+
+  gst_buffer_replace (&buffer, NULL);
+  self->output_flow = ret;
+  g_atomic_int_set (&self->processing, FALSE);
+  gst_v4l2_object_unlock (self->v4l2output);
+  gst_pad_pause_task (encoder->srcpad);
+}
+
+static void
+gst_v4l2_video_enc_loop_stopped (GstV4l2VideoEnc * self)
+{
+  if (g_atomic_int_get (&self->processing)) {
+    GST_DEBUG_OBJECT (self, "Early stop of encoding thread");
+    self->output_flow = GST_FLOW_FLUSHING;
+    g_atomic_int_set (&self->processing, FALSE);
+  }
+
+  GST_DEBUG_OBJECT (self, "Encoding task destroyed: %s",
+      gst_flow_get_name (self->output_flow));
+
+}
+
+static GstFlowReturn
+gst_v4l2_video_enc_handle_frame (GstVideoEncoder * encoder,
+    GstVideoCodecFrame * frame)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstTaskState task_state;
+
+  GST_DEBUG_OBJECT (self, "Handling frame %d", frame->system_frame_number);
+
+  if (G_UNLIKELY (!g_atomic_int_get (&self->active)))
+    goto flushing;
+
+  task_state = gst_pad_get_task_state (GST_VIDEO_DECODER_SRC_PAD (self));
+  if (task_state == GST_TASK_STOPPED || task_state == GST_TASK_PAUSED) {
+    GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool);
+
+    /* It possible that the processing thread stopped due to an error */
+    if (self->output_flow != GST_FLOW_OK &&
+        self->output_flow != GST_FLOW_FLUSHING) {
+      GST_DEBUG_OBJECT (self, "Processing loop stopped with error, leaving");
+      ret = self->output_flow;
+      goto drop;
+    }
+
+    /* Ensure input internal pool is active */
+    if (!gst_buffer_pool_is_active (pool)) {
+      GstStructure *config = gst_buffer_pool_get_config (pool);
+      guint min = MAX (self->v4l2output->min_buffers, GST_V4L2_MIN_BUFFERS);
+
+      gst_buffer_pool_config_set_params (config, self->input_state->caps,
+          self->v4l2output->info.size, min, min);
+
+      /* There is no reason to refuse this config */
+      if (!gst_buffer_pool_set_config (pool, config))
+        goto activate_failed;
+
+      if (!gst_buffer_pool_set_active (pool, TRUE))
+        goto activate_failed;
+    }
+
+    GST_DEBUG_OBJECT (self, "Starting encoding thread");
+
+    /* Start the processing task, when it quits, the task will disable input
+     * processing to unlock input if draining, or prevent potential block */
+    if (!gst_pad_start_task (encoder->srcpad,
+            (GstTaskFunction) gst_v4l2_video_enc_loop, self,
+            (GDestroyNotify) gst_v4l2_video_enc_loop_stopped))
+      goto start_task_failed;
+  }
+
+  if (frame->input_buffer) {
+    GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
+    ret =
+        gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL
+        (self->v4l2output->pool), &frame->input_buffer);
+    GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
+
+    if (ret == GST_FLOW_FLUSHING) {
+      if (gst_pad_get_task_state (GST_VIDEO_DECODER_SRC_PAD (self)) !=
+          GST_TASK_STARTED)
+        ret = self->output_flow;
+      goto drop;
+    } else if (ret != GST_FLOW_OK) {
+      goto process_failed;
+    }
+  }
+
+  gst_video_codec_frame_unref (frame);
+  return ret;
+
+  /* ERRORS */
+activate_failed:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+        (_("Failed to allocate required memory.")),
+        ("Buffer pool activation failed"));
+    return GST_FLOW_ERROR;
+
+  }
+flushing:
+  {
+    ret = GST_FLOW_FLUSHING;
+    goto drop;
+  }
+start_task_failed:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
+        (_("Failed to start encoding thread.")), (NULL));
+    g_atomic_int_set (&self->processing, FALSE);
+    ret = GST_FLOW_ERROR;
+    goto drop;
+  }
+process_failed:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
+        (_("Failed to process frame.")),
+        ("Maybe be due to not enough memory or failing driver"));
+    ret = GST_FLOW_ERROR;
+    goto drop;
+  }
+drop:
+  {
+    gst_video_encoder_finish_frame (encoder, frame);
+    return ret;
+  }
+}
+
+static gboolean
+gst_v4l2_video_enc_decide_allocation (GstVideoEncoder *
+    encoder, GstQuery * query)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
+  GstVideoCodecState *state = gst_video_encoder_get_output_state (encoder);
+  GstV4l2Error error = GST_V4L2_ERROR_INIT;
+  GstClockTime latency;
+  gboolean ret = FALSE;
+
+  /* We need to set the format here, since this is called right after
+   * GstVideoEncoder have set the width, height and framerate into the state
+   * caps. These are needed by the driver to calculate the buffer size and to
+   * implement bitrate adaptation. */
+  if (!gst_v4l2_object_set_format (self->v4l2capture, state->caps, &error)) {
+    gst_v4l2_error (self, &error);
+    ret = FALSE;
+    goto done;
+  }
+
+  if (gst_v4l2_object_decide_allocation (self->v4l2capture, query)) {
+    GstVideoEncoderClass *enc_class = GST_VIDEO_ENCODER_CLASS (parent_class);
+    ret = enc_class->decide_allocation (encoder, query);
+  }
+
+  /* FIXME This may not be entirely correct, as encoder may keep some
+   * observation withouth delaying the encoding. Linux Media API need some
+   * more work to explicitly expressed the decoder / encoder latency. This
+   * value will then become max latency, and the reported driver latency would
+   * become the min latency. */
+  latency = self->v4l2capture->min_buffers * self->v4l2capture->duration;
+  gst_video_encoder_set_latency (encoder, latency, latency);
+
+done:
+  gst_video_codec_state_unref (state);
+  return ret;
+}
+
+static gboolean
+gst_v4l2_video_enc_propose_allocation (GstVideoEncoder *
+    encoder, GstQuery * query)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
+  gboolean ret = FALSE;
+
+  GST_DEBUG_OBJECT (self, "called");
+
+  if (query == NULL)
+    ret = TRUE;
+  else
+    ret = gst_v4l2_object_propose_allocation (self->v4l2output, query);
+
+  if (ret)
+    ret = GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
+        query);
+
+  return ret;
+}
+
+static gboolean
+gst_v4l2_video_enc_src_query (GstVideoEncoder * encoder, GstQuery * query)
+{
+  gboolean ret = TRUE;
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:{
+      GstCaps *filter, *result = NULL;
+      GstPad *pad = GST_VIDEO_ENCODER_SRC_PAD (encoder);
+
+      gst_query_parse_caps (query, &filter);
+
+      /* FIXME Try and not probe the entire encoder, but only the implement
+       * subclass format */
+      if (self->probed_srccaps) {
+        GstCaps *tmpl = gst_pad_get_pad_template_caps (pad);
+        result = gst_caps_intersect (tmpl, self->probed_srccaps);
+        gst_caps_unref (tmpl);
+      } else
+        result = gst_pad_get_pad_template_caps (pad);
+
+      if (filter) {
+        GstCaps *tmp = result;
+        result =
+            gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
+        gst_caps_unref (tmp);
+      }
+
+      GST_DEBUG_OBJECT (self, "Returning src caps %" GST_PTR_FORMAT, result);
+
+      gst_query_set_caps_result (query, result);
+      gst_caps_unref (result);
+      break;
+    }
+
+    default:
+      ret = GST_VIDEO_ENCODER_CLASS (parent_class)->src_query (encoder, query);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_v4l2_video_enc_sink_query (GstVideoEncoder * encoder, GstQuery * query)
+{
+  gboolean ret = TRUE;
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:{
+      GstCaps *filter, *result = NULL;
+      GstPad *pad = GST_VIDEO_ENCODER_SINK_PAD (encoder);
+
+      gst_query_parse_caps (query, &filter);
+
+      if (self->probed_sinkcaps)
+        result = gst_caps_ref (self->probed_sinkcaps);
+      else
+        result = gst_pad_get_pad_template_caps (pad);
+
+      if (filter) {
+        GstCaps *tmp = result;
+        result =
+            gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
+        gst_caps_unref (tmp);
+      }
+
+      GST_DEBUG_OBJECT (self, "Returning sink caps %" GST_PTR_FORMAT, result);
+
+      gst_query_set_caps_result (query, result);
+      gst_caps_unref (result);
+      break;
+    }
+
+    default:
+      ret = GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (encoder, query);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_v4l2_video_enc_sink_event (GstVideoEncoder * encoder, GstEvent * event)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
+  gboolean ret;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      GST_DEBUG_OBJECT (self, "flush start");
+      gst_v4l2_object_unlock (self->v4l2output);
+      gst_v4l2_object_unlock (self->v4l2capture);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_VIDEO_ENCODER_CLASS (parent_class)->sink_event (encoder, event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      gst_pad_stop_task (encoder->srcpad);
+      GST_DEBUG_OBJECT (self, "flush start done");
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static GstStateChangeReturn
+gst_v4l2_video_enc_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (element);
+
+  if (transition == GST_STATE_CHANGE_PAUSED_TO_READY) {
+    g_atomic_int_set (&self->active, FALSE);
+    gst_v4l2_object_unlock (self->v4l2output);
+    gst_v4l2_object_unlock (self->v4l2capture);
+  }
+
+  return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+}
+
+
+static void
+gst_v4l2_video_enc_dispose (GObject * object)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (object);
+
+  gst_caps_replace (&self->probed_sinkcaps, NULL);
+  gst_caps_replace (&self->probed_srccaps, NULL);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_v4l2_video_enc_finalize (GObject * object)
+{
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (object);
+
+  gst_v4l2_object_destroy (self->v4l2capture);
+  gst_v4l2_object_destroy (self->v4l2output);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gst_v4l2_video_enc_init (GstV4l2VideoEnc * self)
+{
+  /* V4L2 object are created in subinstance_init */
+}
+
+static void
+gst_v4l2_video_enc_subinstance_init (GTypeInstance * instance, gpointer g_class)
+{
+  GstV4l2VideoEncClass *klass = GST_V4L2_VIDEO_ENC_CLASS (g_class);
+  GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (instance);
+
+  self->v4l2output = gst_v4l2_object_new (GST_ELEMENT (self),
+      GST_OBJECT (GST_VIDEO_ENCODER_SINK_PAD (self)),
+      V4L2_BUF_TYPE_VIDEO_OUTPUT, klass->default_device,
+      gst_v4l2_get_output, gst_v4l2_set_output, NULL);
+  self->v4l2output->no_initial_format = TRUE;
+  self->v4l2output->keep_aspect = FALSE;
+
+  self->v4l2capture = gst_v4l2_object_new (GST_ELEMENT (self),
+      GST_OBJECT (GST_VIDEO_ENCODER_SRC_PAD (self)),
+      V4L2_BUF_TYPE_VIDEO_CAPTURE, klass->default_device,
+      gst_v4l2_get_input, gst_v4l2_set_input, NULL);
+  self->v4l2capture->no_initial_format = TRUE;
+  self->v4l2output->keep_aspect = FALSE;
+}
+
+static void
+gst_v4l2_video_enc_class_init (GstV4l2VideoEncClass * klass)
+{
+  GstElementClass *element_class;
+  GObjectClass *gobject_class;
+  GstVideoEncoderClass *video_encoder_class;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  element_class = (GstElementClass *) klass;
+  gobject_class = (GObjectClass *) klass;
+  video_encoder_class = (GstVideoEncoderClass *) klass;
+
+  GST_DEBUG_CATEGORY_INIT (gst_v4l2_video_enc_debug, "v4l2videoenc", 0,
+      "V4L2 Video Encoder");
+
+  gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_dispose);
+  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_finalize);
+  gobject_class->set_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_set_property);
+  gobject_class->get_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_get_property);
+
+  video_encoder_class->open = GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_open);
+  video_encoder_class->close = GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_close);
+  video_encoder_class->start = GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_start);
+  video_encoder_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_stop);
+  video_encoder_class->finish = GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_finish);
+  video_encoder_class->flush = GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_flush);
+  video_encoder_class->set_format =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_set_format);
+  video_encoder_class->negotiate =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_negotiate);
+  video_encoder_class->decide_allocation =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_decide_allocation);
+  video_encoder_class->propose_allocation =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_propose_allocation);
+  video_encoder_class->sink_query =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_sink_query);
+  video_encoder_class->src_query =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_src_query);
+  video_encoder_class->sink_event =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_sink_event);
+  video_encoder_class->handle_frame =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_handle_frame);
+
+  element_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_v4l2_video_enc_change_state);
+
+  gst_v4l2_object_install_m2m_properties_helper (gobject_class);
+}
+
+static void
+gst_v4l2_video_enc_subclass_init (gpointer g_class, gpointer data)
+{
+  GstV4l2VideoEncClass *klass = GST_V4L2_VIDEO_ENC_CLASS (g_class);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+  GstV4l2VideoEncCData *cdata = data;
+
+  klass->default_device = cdata->device;
+
+  /* Note: gst_pad_template_new() take the floating ref from the caps */
+  gst_element_class_add_pad_template (element_class,
+      gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+          cdata->sink_caps));
+  gst_element_class_add_pad_template (element_class,
+      gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+          cdata->src_caps));
+
+  gst_caps_unref (cdata->sink_caps);
+  gst_caps_unref (cdata->src_caps);
+  g_free (cdata);
+}
+
+/* Probing functions */
+gboolean
+gst_v4l2_is_video_enc (GstCaps * sink_caps, GstCaps * src_caps,
+    GstCaps * codec_caps)
+{
+  gboolean ret = FALSE;
+  gboolean (*check_caps) (const GstCaps *, const GstCaps *);
+
+  if (codec_caps) {
+    check_caps = gst_caps_can_intersect;
+  } else {
+    codec_caps = gst_v4l2_object_get_codec_caps ();
+    check_caps = gst_caps_is_subset;
+  }
+
+  if (gst_caps_is_subset (sink_caps, gst_v4l2_object_get_raw_caps ())
+      && check_caps (src_caps, codec_caps))
+    ret = TRUE;
+
+  return ret;
+}
+
+void
+gst_v4l2_video_enc_register (GstPlugin * plugin, GType type,
+    const char *codec, const gchar * basename, const gchar * device_path,
+    GstCaps * sink_caps, GstCaps * codec_caps, GstCaps * src_caps)
+{
+  GstCaps *filtered_caps;
+  GTypeQuery type_query;
+  GTypeInfo type_info = { 0, };
+  GType subtype;
+  gchar *type_name;
+  GstV4l2VideoEncCData *cdata;
+
+  filtered_caps = gst_caps_intersect (src_caps, codec_caps);
+
+  cdata = g_new0 (GstV4l2VideoEncCData, 1);
+  cdata->device = g_strdup (device_path);
+  cdata->sink_caps = gst_caps_ref (sink_caps);
+  cdata->src_caps = gst_caps_ref (filtered_caps);
+
+  g_type_query (type, &type_query);
+  memset (&type_info, 0, sizeof (type_info));
+  type_info.class_size = type_query.class_size;
+  type_info.instance_size = type_query.instance_size;
+  type_info.class_init = gst_v4l2_video_enc_subclass_init;
+  type_info.class_data = cdata;
+  type_info.instance_init = gst_v4l2_video_enc_subinstance_init;
+
+  /* The first encoder to be registered should use a constant name, like
+   * v4l2h264enc, for any additional encoders, we create unique names. Encoder
+   * names may change between boots, so this should help gain stable names for
+   * the most common use cases. */
+  type_name = g_strdup_printf ("v4l2%senc", codec);
+
+  if (g_type_from_name (type_name) != 0) {
+    g_free (type_name);
+    type_name = g_strdup_printf ("v4l2%s%senc", basename, codec);
+  }
+
+  subtype = g_type_register_static (type, type_name, &type_info, 0);
+
+  if (!gst_element_register (plugin, type_name, GST_RANK_PRIMARY + 1, subtype))
+    GST_WARNING ("Failed to register plugin '%s'", type_name);
+
+  g_free (type_name);
+}
diff --git a/sys/v4l2/gstv4l2videoenc.h b/sys/v4l2/gstv4l2videoenc.h
new file mode 100644
index 0000000..f03acd5
--- /dev/null
+++ b/sys/v4l2/gstv4l2videoenc.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 SUMOMO Computer Association.
+ *     Author: ayaka <ayaka@soulik.info>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __GST_V4L2_VIDEO_ENC_H__
+#define __GST_V4L2_VIDEO_ENC_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideoencoder.h>
+#include <gst/video/gstvideometa.h>
+
+#include <gstv4l2object.h>
+#include <gstv4l2bufferpool.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_V4L2_VIDEO_ENC \
+  (gst_v4l2_video_enc_get_type())
+#define GST_V4L2_VIDEO_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_VIDEO_ENC,GstV4l2VideoEnc))
+#define GST_V4L2_VIDEO_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_VIDEO_ENC,GstV4l2VideoEncClass))
+#define GST_IS_V4L2_VIDEO_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_VIDEO_ENC))
+#define GST_IS_V4L2_VIDEO_ENC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_VIDEO_ENC))
+#define GST_V4L2_VIDEO_ENC_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_V4L2_VIDEO_ENC, GstV4l2VideoEncClass))
+
+typedef struct _GstV4l2VideoEnc GstV4l2VideoEnc;
+typedef struct _GstV4l2VideoEncClass GstV4l2VideoEncClass;
+
+struct _GstV4l2VideoEnc
+{
+  GstVideoEncoder parent;
+
+  /* < private > */
+  GstV4l2Object *v4l2output;
+  GstV4l2Object *v4l2capture;
+
+  /* pads */
+  GstCaps *probed_srccaps;
+  GstCaps *probed_sinkcaps;
+
+  /* State */
+  GstVideoCodecState *input_state;
+  gboolean active;
+  gboolean processing;
+  GstFlowReturn output_flow;
+
+};
+
+struct _GstV4l2VideoEncClass
+{
+  GstVideoEncoderClass parent_class;
+
+  gchar *default_device;
+  const char *codec_name;
+
+  guint32 profile_cid;
+  const gchar * (*profile_to_string) (gint v4l2_profile);
+  gint (*profile_from_string) (const gchar * profile);
+
+  guint32 level_cid;
+  const gchar * (*level_to_string) (gint v4l2_level);
+  gint (*level_from_string) (const gchar * level);
+};
+
+GType gst_v4l2_video_enc_get_type (void);
+
+
+gboolean gst_v4l2_is_video_enc (GstCaps * sink_caps, GstCaps * src_caps,
+    GstCaps * codec_caps);
+
+void gst_v4l2_video_enc_register (GstPlugin * plugin, GType type,
+    const char *codec, const gchar * basename, const gchar * device_path,
+    GstCaps * sink_caps, GstCaps *codec_caps, GstCaps * src_caps);
+
+G_END_DECLS
+#endif /* __GST_V4L2_VIDEO_ENC_H__ */
diff --git a/sys/v4l2/gstv4l2vidorient.c b/sys/v4l2/gstv4l2vidorient.c
new file mode 100644
index 0000000..9ccb455
--- /dev/null
+++ b/sys/v4l2/gstv4l2vidorient.c
@@ -0,0 +1,97 @@
+/* GStreamer
+ *
+ * Copyright (C) 2006 Edgard Lima <edgard.lima@gmail.com>
+ *
+ * gstv4l2vidorient.c: video orientation interface implementation for V4L2
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "gstv4l2object.h"
+#include "gstv4l2vidorient.h"
+#include "gstv4l2object.h"
+
+GST_DEBUG_CATEGORY_STATIC (v4l2vo_debug);
+#define GST_CAT_DEFAULT v4l2vo_debug
+
+void
+gst_v4l2_video_orientation_interface_init (GstVideoOrientationInterface * iface)
+{
+  GST_DEBUG_CATEGORY_INIT (v4l2vo_debug, "v4l2vo", 0,
+      "V4L2 VideoOrientation interface debugging");
+}
+
+
+gboolean
+gst_v4l2_video_orientation_get_hflip (GstV4l2Object * v4l2object,
+    gboolean * flip)
+{
+
+  return gst_v4l2_get_attribute (v4l2object, V4L2_CID_HFLIP, flip);
+}
+
+gboolean
+gst_v4l2_video_orientation_get_vflip (GstV4l2Object * v4l2object,
+    gboolean * flip)
+{
+  return gst_v4l2_get_attribute (v4l2object, V4L2_CID_VFLIP, flip);
+}
+
+/* named hcenter because of historical v4l2 naming */
+gboolean
+gst_v4l2_video_orientation_get_hcenter (GstV4l2Object * v4l2object,
+    gint * center)
+{
+  return gst_v4l2_get_attribute (v4l2object, V4L2_CID_PAN_RESET, center);
+}
+
+/* named vcenter because of historical v4l2 naming */
+gboolean
+gst_v4l2_video_orientation_get_vcenter (GstV4l2Object * v4l2object,
+    gint * center)
+{
+  return gst_v4l2_get_attribute (v4l2object, V4L2_CID_TILT_RESET, center);
+}
+
+gboolean
+gst_v4l2_video_orientation_set_hflip (GstV4l2Object * v4l2object, gboolean flip)
+{
+  return gst_v4l2_set_attribute (v4l2object, V4L2_CID_HFLIP, flip);
+}
+
+gboolean
+gst_v4l2_video_orientation_set_vflip (GstV4l2Object * v4l2object, gboolean flip)
+{
+  return gst_v4l2_set_attribute (v4l2object, V4L2_CID_VFLIP, flip);
+}
+
+gboolean
+gst_v4l2_video_orientation_set_hcenter (GstV4l2Object * v4l2object, gint center)
+{
+  return gst_v4l2_set_attribute (v4l2object, V4L2_CID_PAN_RESET, center);
+}
+
+gboolean
+gst_v4l2_video_orientation_set_vcenter (GstV4l2Object * v4l2object, gint center)
+{
+  return gst_v4l2_set_attribute (v4l2object, V4L2_CID_TILT_RESET, center);
+}
diff --git a/sys/v4l2/gstv4l2vidorient.h b/sys/v4l2/gstv4l2vidorient.h
new file mode 100644
index 0000000..102ae8a
--- /dev/null
+++ b/sys/v4l2/gstv4l2vidorient.h
@@ -0,0 +1,118 @@
+/* GStreamer
+ *
+ * Copyright (C) 2006 Edgard Lima <edgard.lima@gmail.com>
+ *
+ * gstv4l2vidorient.h: video orientation interface implementation for V4L2
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_V4L2_VIDORIENT_H__
+#define __GST_V4L2_VIDORIENT_H__
+
+#include <gst/gst.h>
+#include <gst/video/videoorientation.h>
+
+#include "gstv4l2object.h"
+
+G_BEGIN_DECLS
+
+void     gst_v4l2_video_orientation_interface_init (GstVideoOrientationInterface * iface);
+
+gboolean gst_v4l2_video_orientation_get_hflip 	(GstV4l2Object *v4l2object, gboolean *flip);
+gboolean gst_v4l2_video_orientation_get_vflip 	(GstV4l2Object *v4l2object, gboolean *flip);
+gboolean gst_v4l2_video_orientation_get_hcenter (GstV4l2Object *v4l2object, gint *center);
+gboolean gst_v4l2_video_orientation_get_vcenter (GstV4l2Object *v4l2object, gint *center);
+
+gboolean gst_v4l2_video_orientation_set_hflip 	(GstV4l2Object *v4l2object, gboolean flip);
+gboolean gst_v4l2_video_orientation_set_vflip 	(GstV4l2Object *v4l2object, gboolean flip);
+gboolean gst_v4l2_video_orientation_set_hcenter (GstV4l2Object *v4l2object, gint center);
+gboolean gst_v4l2_video_orientation_set_vcenter (GstV4l2Object *v4l2object, gint center);
+
+#define GST_IMPLEMENT_V4L2_VIDORIENT_METHODS(Type, interface_as_function)                         \
+                                                                                                  \
+  static gboolean                                                                                 \
+  interface_as_function ## _video_orientation_get_hflip (GstVideoOrientation *vo, gboolean *flip)       \
+  {                                                                                               \
+    Type *this = (Type*) vo;                                                                      \
+    return gst_v4l2_video_orientation_get_hflip (this->v4l2object, flip);		          \
+  }                                                                                               \
+                                                                                                  \
+  static gboolean                                                                                 \
+  interface_as_function ## _video_orientation_get_vflip (GstVideoOrientation *vo, gboolean *flip)       \
+  {                                                                                               \
+    Type *this = (Type*) vo;                                                                      \
+    return gst_v4l2_video_orientation_get_vflip (this->v4l2object, flip);		          \
+  }                                                                                               \
+                                                                                                  \
+  static gboolean                                                                                 \
+  interface_as_function ## _video_orientation_get_hcenter (GstVideoOrientation *vo, gint *center)       \
+  {                                                                                               \
+    Type *this = (Type*) vo;                                                                      \
+    return gst_v4l2_video_orientation_get_hcenter (this->v4l2object, center);		          \
+  }                                                                                               \
+                                                                                                  \
+  static gboolean                                                                                 \
+  interface_as_function ## _video_orientation_get_vcenter (GstVideoOrientation *vo, gint *center)       \
+  {                                                                                               \
+    Type *this = (Type*) vo;                                                                      \
+    return gst_v4l2_video_orientation_get_vcenter (this->v4l2object, center);		          \
+  }                                                                                               \
+                                                                                                  \
+  static gboolean                                                                                 \
+  interface_as_function ## _video_orientation_set_hflip (GstVideoOrientation *vo, gboolean flip)        \
+  {                                                                                               \
+    Type *this = (Type*) vo;                                                                      \
+    return gst_v4l2_video_orientation_set_hflip (this->v4l2object, flip);		          \
+  }                                                                                               \
+                                                                                                  \
+  static gboolean                                                                                 \
+  interface_as_function ## _video_orientation_set_vflip (GstVideoOrientation *vo, gboolean flip)        \
+  {                                                                                               \
+    Type *this = (Type*) vo;                                                                      \
+    return gst_v4l2_video_orientation_set_vflip (this->v4l2object, flip);		          \
+  }                                                                                               \
+                                                                                                  \
+  static gboolean                                                                                 \
+  interface_as_function ## _video_orientation_set_hcenter (GstVideoOrientation *vo, gint center)        \
+  {                                                                                               \
+    Type *this = (Type*) vo;                                                                      \
+    return gst_v4l2_video_orientation_set_hcenter (this->v4l2object, center);		          \
+  }                                                                                               \
+                                                                                                  \
+  static gboolean                                                                                 \
+  interface_as_function ## _video_orientation_set_vcenter (GstVideoOrientation *vo, gint center)        \
+  {                                                                                               \
+    Type *this = (Type*) vo;                                                                      \
+    return gst_v4l2_video_orientation_set_vcenter (this->v4l2object, center);		          \
+  }                                                                                               \
+                                                                                                  \
+  static void                                                                                     \
+  interface_as_function ## _video_orientation_interface_init (GstVideoOrientationInterface * iface)          \
+  {                                                                                               \
+    /* default virtual functions */                                                               \
+    iface->get_hflip   = interface_as_function ## _video_orientation_get_hflip;                   \
+    iface->get_vflip   = interface_as_function ## _video_orientation_get_vflip;                   \
+    iface->get_hcenter = interface_as_function ## _video_orientation_get_hcenter;                 \
+    iface->get_vcenter = interface_as_function ## _video_orientation_get_vcenter;                 \
+    iface->set_hflip   = interface_as_function ## _video_orientation_set_hflip;                   \
+    iface->set_vflip   = interface_as_function ## _video_orientation_set_vflip;                   \
+    iface->set_hcenter = interface_as_function ## _video_orientation_set_hcenter;                 \
+    iface->set_vcenter = interface_as_function ## _video_orientation_set_vcenter;                 \
+  }
+
+G_END_DECLS
+#endif /* __GST_V4L2_VIDORIENT_H__ */
diff --git a/sys/v4l2/gstv4l2vp8enc.c b/sys/v4l2/gstv4l2vp8enc.c
new file mode 100644
index 0000000..cf3eb06
--- /dev/null
+++ b/sys/v4l2/gstv4l2vp8enc.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2017 Collabora Inc.
+ *    Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gstv4l2object.h"
+#include "gstv4l2vp8enc.h"
+
+#include <string.h>
+#include <gst/gst-i18n-plugin.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_v4l2_vp8_enc_debug);
+#define GST_CAT_DEFAULT gst_v4l2_vp8_enc_debug
+
+static GstStaticCaps src_template_caps =
+GST_STATIC_CAPS ("video/x-vp8, profile=(string) { 0, 1, 2, 3 }");
+
+enum
+{
+  PROP_0,
+  V4L2_STD_OBJECT_PROPS,
+  /* TODO */
+};
+
+#define gst_v4l2_vp8_enc_parent_class parent_class
+G_DEFINE_TYPE (GstV4l2Vp8Enc, gst_v4l2_vp8_enc, GST_TYPE_V4L2_VIDEO_ENC);
+
+static void
+gst_v4l2_vp8_enc_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  /* TODO */
+}
+
+static void
+gst_v4l2_vp8_enc_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  /* TODO */
+}
+
+static gint
+v4l2_profile_from_string (const gchar * profile)
+{
+  gint v4l2_profile = -1;
+
+  if (g_str_equal (profile, "0"))
+    v4l2_profile = 0;
+  else if (g_str_equal (profile, "1"))
+    v4l2_profile = 1;
+  else if (g_str_equal (profile, "2"))
+    v4l2_profile = 2;
+  else if (g_str_equal (profile, "3"))
+    v4l2_profile = 3;
+  else
+    GST_WARNING ("Unsupported profile string '%s'", profile);
+
+  return v4l2_profile;
+}
+
+static const gchar *
+v4l2_profile_to_string (gint v4l2_profile)
+{
+  switch (v4l2_profile) {
+    case 0:
+      return "0";
+    case 1:
+      return "1";
+    case 2:
+      return "2";
+    case 3:
+      return "3";
+    default:
+      GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile);
+      break;
+  }
+
+  return NULL;
+}
+
+static void
+gst_v4l2_vp8_enc_init (GstV4l2Vp8Enc * self)
+{
+}
+
+static void
+gst_v4l2_vp8_enc_class_init (GstV4l2Vp8EncClass * klass)
+{
+  GstElementClass *element_class;
+  GObjectClass *gobject_class;
+  GstV4l2VideoEncClass *baseclass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  element_class = (GstElementClass *) klass;
+  gobject_class = (GObjectClass *) klass;
+  baseclass = (GstV4l2VideoEncClass *) (klass);
+
+
+  GST_DEBUG_CATEGORY_INIT (gst_v4l2_vp8_enc_debug, "v4l2vp8enc", 0,
+      "V4L2 VP8 Encoder");
+
+  gst_element_class_set_static_metadata (element_class,
+      "V4L2 VP8 Encoder",
+      "Codec/Encoder/Video",
+      "Encode VP8 video streams via V4L2 API",
+      "Nicolas Dufresne <nicolas.dufresne@collabora.com");
+
+  gobject_class->set_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_vp8_enc_set_property);
+  gobject_class->get_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_vp8_enc_get_property);
+
+  baseclass->codec_name = "VP8";
+  baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_VPX_PROFILE;
+  baseclass->profile_to_string = v4l2_profile_to_string;
+  baseclass->profile_from_string = v4l2_profile_from_string;
+}
+
+/* Probing functions */
+gboolean
+gst_v4l2_is_vp8_enc (GstCaps * sink_caps, GstCaps * src_caps)
+{
+  return gst_v4l2_is_video_enc (sink_caps, src_caps,
+      gst_static_caps_get (&src_template_caps));
+}
+
+void
+gst_v4l2_vp8_enc_register (GstPlugin * plugin, const gchar * basename,
+    const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps)
+{
+  gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_VP8_ENC,
+      "vp8", basename, device_path, sink_caps,
+      gst_static_caps_get (&src_template_caps), src_caps);
+}
diff --git a/sys/v4l2/gstv4l2vp8enc.h b/sys/v4l2/gstv4l2vp8enc.h
new file mode 100644
index 0000000..3e82b4b
--- /dev/null
+++ b/sys/v4l2/gstv4l2vp8enc.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 Collabora Inc.
+ *    Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __GST_V4L2_VP8_ENC_H__
+#define __GST_V4L2_VP8_ENC_H__
+
+#include <gst/gst.h>
+#include "gstv4l2videoenc.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_V4L2_VP8_ENC \
+  (gst_v4l2_vp8_enc_get_type())
+#define GST_V4L2_VP8_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_VP8_ENC,GstV4l2Vp8Enc))
+#define GST_V4L2_VP8_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_VP8_ENC,GstV4l2Vp8EncClass))
+#define GST_IS_V4L2_VP8_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_VP8_ENC))
+#define GST_IS_V4L2_VP8_ENC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_VP8_ENC))
+typedef struct _GstV4l2Vp8Enc GstV4l2Vp8Enc;
+typedef struct _GstV4l2Vp8EncClass GstV4l2Vp8EncClass;
+
+struct _GstV4l2Vp8Enc
+{
+  GstV4l2VideoEnc parent;
+};
+
+struct _GstV4l2Vp8EncClass
+{
+  GstV4l2VideoEncClass parent_class;
+};
+
+GType gst_v4l2_vp8_enc_get_type (void);
+
+gboolean gst_v4l2_is_vp8_enc (GstCaps * sink_caps, GstCaps * src_caps);
+
+void gst_v4l2_vp8_enc_register (GstPlugin * plugin, const gchar * basename,
+    const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps);
+
+G_END_DECLS
+#endif /* __GST_V4L2_VP8_ENC_H__ */
diff --git a/sys/v4l2/gstv4l2vp9enc.c b/sys/v4l2/gstv4l2vp9enc.c
new file mode 100644
index 0000000..e938d78
--- /dev/null
+++ b/sys/v4l2/gstv4l2vp9enc.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2017 Collabora Inc.
+ *    Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gstv4l2object.h"
+#include "gstv4l2vp9enc.h"
+
+#include <string.h>
+#include <gst/gst-i18n-plugin.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_v4l2_vp9_enc_debug);
+#define GST_CAT_DEFAULT gst_v4l2_vp9_enc_debug
+
+static GstStaticCaps src_template_caps =
+GST_STATIC_CAPS ("video/x-vp9, profile=(string) { 0, 1, 2, 3 }");
+
+enum
+{
+  PROP_0,
+  V4L2_STD_OBJECT_PROPS,
+  /* TODO */
+};
+
+#define gst_v4l2_vp9_enc_parent_class parent_class
+G_DEFINE_TYPE (GstV4l2Vp9Enc, gst_v4l2_vp9_enc, GST_TYPE_V4L2_VIDEO_ENC);
+
+static void
+gst_v4l2_vp9_enc_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  /* TODO */
+}
+
+static void
+gst_v4l2_vp9_enc_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  /* TODO */
+}
+
+static gint
+v4l2_profile_from_string (const gchar * profile)
+{
+  gint v4l2_profile = -1;
+
+  if (g_str_equal (profile, "0"))
+    v4l2_profile = 0;
+  else if (g_str_equal (profile, "1"))
+    v4l2_profile = 1;
+  else if (g_str_equal (profile, "2"))
+    v4l2_profile = 2;
+  else if (g_str_equal (profile, "3"))
+    v4l2_profile = 3;
+  else
+    GST_WARNING ("Unsupported profile string '%s'", profile);
+
+  return v4l2_profile;
+}
+
+static const gchar *
+v4l2_profile_to_string (gint v4l2_profile)
+{
+  switch (v4l2_profile) {
+    case 0:
+      return "0";
+    case 1:
+      return "1";
+    case 2:
+      return "2";
+    case 3:
+      return "3";
+    default:
+      GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile);
+      break;
+  }
+
+  return NULL;
+}
+
+static void
+gst_v4l2_vp9_enc_init (GstV4l2Vp9Enc * self)
+{
+}
+
+static void
+gst_v4l2_vp9_enc_class_init (GstV4l2Vp9EncClass * klass)
+{
+  GstElementClass *element_class;
+  GObjectClass *gobject_class;
+  GstV4l2VideoEncClass *baseclass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  element_class = (GstElementClass *) klass;
+  gobject_class = (GObjectClass *) klass;
+  baseclass = (GstV4l2VideoEncClass *) (klass);
+
+  GST_DEBUG_CATEGORY_INIT (gst_v4l2_vp9_enc_debug, "v4l2vp9enc", 0,
+      "V4L2 VP9 Encoder");
+
+  gst_element_class_set_static_metadata (element_class,
+      "V4L2 VP9 Encoder",
+      "Codec/Encoder/Video",
+      "Encode VP9 video streams via V4L2 API",
+      "Nicolas Dufresne <nicolas.dufresne@collabora.com");
+
+  gobject_class->set_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_vp9_enc_set_property);
+  gobject_class->get_property =
+      GST_DEBUG_FUNCPTR (gst_v4l2_vp9_enc_get_property);
+
+  baseclass->codec_name = "VP9";
+  baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_VPX_PROFILE;
+  baseclass->profile_to_string = v4l2_profile_to_string;
+  baseclass->profile_from_string = v4l2_profile_from_string;
+}
+
+/* Probing functions */
+gboolean
+gst_v4l2_is_vp9_enc (GstCaps * sink_caps, GstCaps * src_caps)
+{
+  return gst_v4l2_is_video_enc (sink_caps, src_caps,
+      gst_static_caps_get (&src_template_caps));
+}
+
+void
+gst_v4l2_vp9_enc_register (GstPlugin * plugin, const gchar * basename,
+    const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps)
+{
+  gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_VP9_ENC,
+      "vp9", basename, device_path, sink_caps,
+      gst_static_caps_get (&src_template_caps), src_caps);
+}
diff --git a/sys/v4l2/gstv4l2vp9enc.h b/sys/v4l2/gstv4l2vp9enc.h
new file mode 100644
index 0000000..b768cce
--- /dev/null
+++ b/sys/v4l2/gstv4l2vp9enc.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 Collabora Inc.
+ *    Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __GST_V4L2_VP9_ENC_H__
+#define __GST_V4L2_VP9_ENC_H__
+
+#include <gst/gst.h>
+#include "gstv4l2videoenc.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_V4L2_VP9_ENC \
+  (gst_v4l2_vp9_enc_get_type())
+#define GST_V4L2_VP9_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_VP9_ENC,GstV4l2Vp9Enc))
+#define GST_V4L2_VP9_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_VP9_ENC,GstV4l2Vp9EncClass))
+#define GST_IS_V4L2_VP9_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_VP9_ENC))
+#define GST_IS_V4L2_VP9_ENC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_VP9_ENC))
+typedef struct _GstV4l2Vp9Enc GstV4l2Vp9Enc;
+typedef struct _GstV4l2Vp9EncClass GstV4l2Vp9EncClass;
+
+struct _GstV4l2Vp9Enc
+{
+  GstV4l2VideoEnc parent;
+};
+
+struct _GstV4l2Vp9EncClass
+{
+  GstV4l2VideoEncClass parent_class;
+};
+
+GType gst_v4l2_vp9_enc_get_type (void);
+
+gboolean gst_v4l2_is_vp9_enc (GstCaps * sink_caps, GstCaps * src_caps);
+
+void gst_v4l2_vp9_enc_register (GstPlugin * plugin, const gchar * basename,
+    const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps);
+
+G_END_DECLS
+#endif /* __GST_V4L2_VP9_ENC_H__ */
diff --git a/sys/v4l2/meson.build b/sys/v4l2/meson.build
new file mode 100644
index 0000000..83ecc02
--- /dev/null
+++ b/sys/v4l2/meson.build
@@ -0,0 +1,54 @@
+v4l2_sources = [
+  'gstv4l2.c',
+  'gstv4l2allocator.c',
+  'gstv4l2colorbalance.c',
+  'gstv4l2deviceprovider.c',
+  'gstv4l2object.c',
+  'gstv4l2bufferpool.c',
+  'gstv4l2sink.c',
+  'gstv4l2src.c',
+  'gstv4l2radio.c',
+  'gstv4l2tuner.c',
+  'gstv4l2transform.c',
+  'gstv4l2videodec.c',
+  'gstv4l2videoenc.c',
+  'gstv4l2h263enc.c',
+  'gstv4l2h264enc.c',
+  'gstv4l2mpeg4enc.c',
+  'gstv4l2vidorient.c',
+  'gstv4l2vp8enc.c',
+  'gstv4l2vp9enc.c',
+  'v4l2_calls.c',
+  'v4l2-utils.c',
+  'tuner.c',
+  'tunerchannel.c',
+  'tunernorm.c'
+]
+
+cdata.set('GST_V4L2_ENABLE_PROBE', get_option('v4l2-probe'))
+
+if cc.has_header('linux/videodev2.h') or cc.has_header('sys/videodev2.h') or cc.has_header('sys/videoio.h')
+  message('building v4l2 plugin')
+  cdata.set('HAVE_GST_V4L2', true)
+  gudev_dep = dependency('gudev-1.0', version : '>=147', required : false)
+  cdata.set('HAVE_GUDEV', gudev_dep.found())
+
+  # libv4l2 is only needed for converting some obscure formats
+  # FIXME: Add a full list of the formats here
+  if get_option('with-libv4l2')
+    libv4l2_dep = dependency('libv4l2', required : false)
+    cdata.set('HAVE_LIBV4L2', libv4l2_dep.found())
+    libv4l2_deps = [libv4l2_dep]
+  else
+    libv4l2_deps = []
+  endif
+
+  gstv4l2 = library('gstvideo4linux2',
+    v4l2_sources,
+    c_args : gst_plugins_good_args,
+    include_directories : [configinc, libsinc],
+    dependencies : [gstbase_dep, gstvideo_dep, gstallocators_dep, gudev_dep] + libv4l2_deps,
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/sys/v4l2/tuner.c b/sys/v4l2/tuner.c
new file mode 100644
index 0000000..b6b3fe9
--- /dev/null
+++ b/sys/v4l2/tuner.c
@@ -0,0 +1,551 @@
+/* GStreamer Tuner
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * tuner.c: tuner design virtual class function wrappers
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tuner.h"
+
+#include <string.h>
+
+/**
+ * SECTION:gsttuner
+ * @short_description: Interface for elements providing tuner operations
+ * 
+ * <refsect2>
+ * <para>
+ * The GstTuner interface is provided by elements that have the ability to
+ * tune into multiple input signals, for example TV or radio capture cards.
+ * </para><para>
+ * The interpretation of 'tuning into' an input stream depends on the element
+ * implementing the interface. For v4lsrc, it might imply selection of an
+ * input source and/or frequency to be configured on a TV card. Another 
+ * GstTuner implementation might be to allow selection of an active input pad
+ * from multiple input pads.
+ * </para><para>
+ * That said, the GstTuner interface functions are biased toward the
+ * TV capture scenario.
+ * </para><para>
+ * The general parameters provided are for configuration are:
+ * <itemizedlist>
+ * <listitem>Selection of a current #GstTunerChannel. The current channel
+ * represents the input source (e.g. Composite, S-Video etc for TV capture).
+ * </listitem>
+ * <listitem>The #GstTunerNorm for the channel. The norm chooses the
+ * interpretation of the incoming signal for the current channel. For example,
+ * PAL or NTSC, or more specific variants there-of.
+ * </listitem>
+ * <listitem>Channel frequency. If the current channel has the ability to tune
+ * between multiple frequencies (if it has the GST_TUNER_CHANNEL_FREQUENCY flag)
+ * then the frequency can be changed/retrieved via the
+ * gst_tuner_set_frequency() and gst_tuner_get_frequency() methods.
+ * </listitem>
+ * </itemizedlist>
+ * </para>
+ * <para>
+ * Where applicable, the signal strength can be retrieved and/or monitored
+ * via a signal.
+ * </para>
+ * </refsect2>
+ */
+
+/* FIXME 0.11: check if we need to add API for sometimes-supportedness
+ * (aka making up for GstImplementsInterface removal) */
+
+/* FIXME 0.11: replace signals with messages (+ make API thread-safe) */
+
+enum
+{
+  NORM_CHANGED,
+  CHANNEL_CHANGED,
+  FREQUENCY_CHANGED,
+  SIGNAL_CHANGED,
+  LAST_SIGNAL
+};
+
+static guint gst_tuner_signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_INTERFACE (GstTuner, gst_tuner, G_TYPE_INVALID);
+
+static void
+gst_tuner_default_init (GstTunerInterface * iface)
+{
+  static gboolean initialized = FALSE;
+
+  if (!initialized) {
+    /**
+     * GstTuner::norm-changed:
+     * @tuner: The element providing the GstTuner interface
+     * @norm: The new configured norm.
+     *
+     * Reports that the current #GstTunerNorm has changed.
+     */
+    gst_tuner_signals[NORM_CHANGED] =
+        g_signal_new ("norm-changed",
+        GST_TYPE_TUNER, G_SIGNAL_RUN_LAST,
+        G_STRUCT_OFFSET (GstTunerInterface, norm_changed),
+        NULL, NULL,
+        g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_TUNER_NORM);
+    /**
+     * GstTuner::channel-changed:
+     * @tuner: The element providing the GstTuner interface
+     * @channel: The new configured channel.
+     *
+     * Reports that the current #GstTunerChannel has changed.
+     */
+    gst_tuner_signals[CHANNEL_CHANGED] =
+        g_signal_new ("channel-changed",
+        GST_TYPE_TUNER, G_SIGNAL_RUN_LAST,
+        G_STRUCT_OFFSET (GstTunerInterface, channel_changed),
+        NULL, NULL,
+        g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+        GST_TYPE_TUNER_CHANNEL);
+    /**
+     * GstTuner::frequency-changed:
+     * @tuner: The element providing the GstTuner interface
+     * @frequency: The new frequency (an unsigned long)
+     *
+     * Reports that the current frequency has changed.
+     */
+    gst_tuner_signals[FREQUENCY_CHANGED] =
+        g_signal_new ("frequency-changed",
+        GST_TYPE_TUNER, G_SIGNAL_RUN_LAST,
+        G_STRUCT_OFFSET (GstTunerInterface, frequency_changed),
+        NULL, NULL,
+        g_cclosure_marshal_generic, G_TYPE_NONE, 2, GST_TYPE_TUNER_CHANNEL,
+        G_TYPE_ULONG);
+    /**
+     * GstTuner::signal-changed:
+     * @tuner: The element providing the GstTuner interface
+     * @channel: The current #GstTunerChannel
+     * @signal: The new signal strength (an integer)
+     *
+     * Reports that the signal strength has changed.
+     *
+     * See Also: gst_tuner_signal_strength()
+     */
+    gst_tuner_signals[SIGNAL_CHANGED] =
+        g_signal_new ("signal-changed",
+        GST_TYPE_TUNER, G_SIGNAL_RUN_LAST,
+        G_STRUCT_OFFSET (GstTunerInterface, signal_changed),
+        NULL, NULL,
+        g_cclosure_marshal_generic, G_TYPE_NONE, 2, GST_TYPE_TUNER_CHANNEL,
+        G_TYPE_INT);
+
+    initialized = TRUE;
+  }
+
+  /* default virtual functions */
+  iface->list_channels = NULL;
+  iface->set_channel = NULL;
+  iface->get_channel = NULL;
+
+  iface->list_norms = NULL;
+  iface->set_norm = NULL;
+  iface->get_norm = NULL;
+
+  iface->set_frequency = NULL;
+  iface->get_frequency = NULL;
+  iface->signal_strength = NULL;
+}
+
+/**
+ * gst_tuner_list_channels:
+ * @tuner: the #GstTuner (a #GstElement) to get the channels from.
+ *
+ * Retrieve a #GList of #GstTunerChannels available
+ * (e.g. 'composite', 's-video', ...) from the given tuner object.
+ *
+ * Returns: A list of channels available on this tuner. The list is
+ *          owned by the GstTuner and must not be freed.
+ */
+const GList *
+gst_tuner_list_channels (GstTuner * tuner)
+{
+  GstTunerInterface *iface;
+
+  g_return_val_if_fail (GST_IS_TUNER (tuner), NULL);
+
+  iface = GST_TUNER_GET_INTERFACE (tuner);
+  if (iface->list_channels) {
+    return iface->list_channels (tuner);
+  }
+
+  return NULL;
+}
+
+/**
+ * gst_tuner_set_channel:
+ * @tuner: the #GstTuner (a #GstElement) that owns the channel.
+ * @channel: the channel to tune to.
+ *
+ * Tunes the object to the given channel, which should be one of the
+ * channels returned by gst_tuner_list_channels().
+ */
+
+void
+gst_tuner_set_channel (GstTuner * tuner, GstTunerChannel * channel)
+{
+  GstTunerInterface *iface;
+
+  g_return_if_fail (GST_IS_TUNER (tuner));
+
+  iface = GST_TUNER_GET_INTERFACE (tuner);
+  if (iface->set_channel) {
+    iface->set_channel (tuner, channel);
+  }
+}
+
+/**
+ * gst_tuner_get_channel:
+ * @tuner: the #GstTuner (a #GstElement) to get the current channel from.
+ *
+ * Retrieve the current channel from the tuner.
+ *
+ * Returns: the current channel of the tuner object.
+ */
+
+GstTunerChannel *
+gst_tuner_get_channel (GstTuner * tuner)
+{
+  GstTunerInterface *iface;
+
+  g_return_val_if_fail (GST_IS_TUNER (tuner), NULL);
+
+  iface = GST_TUNER_GET_INTERFACE (tuner);
+  if (iface->get_channel) {
+    return iface->get_channel (tuner);
+  }
+
+  return NULL;
+}
+
+/**
+ * gst_tuner_list_norms:
+ * @tuner: the #GstTuner (*a #GstElement) to get the list of norms from.
+ *
+ * Retrieve a GList of available #GstTunerNorm settings for the currently
+ * tuned channel on the given tuner object.
+ *
+ * Returns: A list of norms available on the current channel for this
+ *          tuner object. The list is owned by the GstTuner and must not
+ *          be freed.
+ */
+
+const GList *
+gst_tuner_list_norms (GstTuner * tuner)
+{
+  GstTunerInterface *iface;
+
+  g_return_val_if_fail (GST_IS_TUNER (tuner), NULL);
+
+  iface = GST_TUNER_GET_INTERFACE (tuner);
+  if (iface->list_norms) {
+    return iface->list_norms (tuner);
+  }
+
+  return NULL;
+}
+
+/**
+ * gst_tuner_set_norm:
+ * @tuner: the #GstTuner (a #GstElement) to set the norm on.
+ * @norm: the norm to use for the current channel.
+ *
+ * Changes the video norm on this tuner to the given norm, which should be
+ * one of the norms returned by gst_tuner_list_norms().
+ */
+
+void
+gst_tuner_set_norm (GstTuner * tuner, GstTunerNorm * norm)
+{
+  GstTunerInterface *iface;
+
+  g_return_if_fail (GST_IS_TUNER (tuner));
+
+  iface = GST_TUNER_GET_INTERFACE (tuner);
+  if (iface->set_norm) {
+    iface->set_norm (tuner, norm);
+  }
+}
+
+/**
+ * gst_tuner_get_norm:
+ * @tuner: the #GstTuner (a #GstElement) to get the current norm from.
+ *
+ * Get the current video norm from the given tuner object for the
+ * currently selected channel.
+ *
+ * Returns: the current norm.
+ */
+
+GstTunerNorm *
+gst_tuner_get_norm (GstTuner * tuner)
+{
+  GstTunerInterface *iface;
+
+  g_return_val_if_fail (GST_IS_TUNER (tuner), NULL);
+
+  iface = GST_TUNER_GET_INTERFACE (tuner);
+  if (iface->get_norm) {
+    return iface->get_norm (tuner);
+  }
+
+  return NULL;
+}
+
+/**
+ * gst_tuner_set_frequency:
+ * @tuner: The #GstTuner (a #GstElement) that owns the given channel.
+ * @channel: The #GstTunerChannel to set the frequency on.
+ * @frequency: The frequency to tune in to.
+ *
+ * Sets a tuning frequency on the given tuner/channel. Note that this
+ * requires the given channel to be a "tuning" channel, which can be
+ * checked using GST_TUNER_CHANNEL_HAS_FLAG (), with the proper flag
+ * being GST_TUNER_CHANNEL_FREQUENCY.
+ *
+ * The frequency is in Hz, with minimum steps indicated by the 
+ * frequency_multiplicator provided in the #GstTunerChannel. The
+ * valid range is provided in the min_frequency and max_frequency properties
+ * of the #GstTunerChannel.
+ */
+
+void
+gst_tuner_set_frequency (GstTuner * tuner,
+    GstTunerChannel * channel, gulong frequency)
+{
+  GstTunerInterface *iface;
+
+  g_return_if_fail (GST_IS_TUNER (tuner));
+  g_return_if_fail (GST_IS_TUNER_CHANNEL (channel));
+  g_return_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
+          GST_TUNER_CHANNEL_FREQUENCY));
+
+  iface = GST_TUNER_GET_INTERFACE (tuner);
+  if (iface->set_frequency) {
+    iface->set_frequency (tuner, channel, frequency);
+  }
+}
+
+/**
+ * gst_tuner_get_frequency:
+ * @tuner: The #GstTuner (a #GstElement) that owns the given channel.
+ * @channel: The #GstTunerChannel to retrieve the frequency from.
+ *
+ * Retrieve the current frequency from the given channel. As for
+ * gst_tuner_set_frequency(), the #GstTunerChannel must support frequency
+ * operations, as indicated by the GST_TUNER_CHANNEL_FREQUENCY flag.
+ *
+ * Returns: The current frequency, or 0 on error.
+ */
+
+gulong
+gst_tuner_get_frequency (GstTuner * tuner, GstTunerChannel * channel)
+{
+  GstTunerInterface *iface;
+
+  g_return_val_if_fail (GST_IS_TUNER (tuner), 0);
+  g_return_val_if_fail (GST_IS_TUNER_CHANNEL (channel), 0);
+  g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
+          GST_TUNER_CHANNEL_FREQUENCY), 0);
+
+  iface = GST_TUNER_GET_INTERFACE (tuner);
+
+  if (iface->get_frequency) {
+    return iface->get_frequency (tuner, channel);
+  }
+
+  return 0;
+}
+
+/**
+ * gst_tuner_signal_strength:
+ * @tuner: the #GstTuner (a #GstElement) that owns the given channel.
+ * @channel: the #GstTunerChannel to get the signal strength from.
+ *
+ * Get the strength of the signal on this channel. Note that this
+ * requires the current channel to be a "tuning" channel, i.e. a
+ * channel on which frequency can be set. This can be checked using
+ * GST_TUNER_CHANNEL_HAS_FLAG (), and the appropriate flag to check
+ * for is GST_TUNER_CHANNEL_FREQUENCY.
+ *
+ * The valid range of the signal strength is indicated in the 
+ * min_signal and max_signal properties of the #GstTunerChannel.
+ *
+ * Returns: Signal strength, or 0 on error.
+ */
+gint
+gst_tuner_signal_strength (GstTuner * tuner, GstTunerChannel * channel)
+{
+  GstTunerInterface *iface;
+
+  g_return_val_if_fail (GST_IS_TUNER (tuner), 0);
+  g_return_val_if_fail (GST_IS_TUNER_CHANNEL (channel), 0);
+  g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
+          GST_TUNER_CHANNEL_FREQUENCY), 0);
+
+  iface = GST_TUNER_GET_INTERFACE (tuner);
+  if (iface->signal_strength) {
+    return iface->signal_strength (tuner, channel);
+  }
+
+  return 0;
+}
+
+/**
+ * gst_tuner_find_norm_by_name:
+ * @tuner: A #GstTuner instance
+ * @norm: A string containing the name of a #GstTunerNorm
+ * 
+ * Look up a #GstTunerNorm by name.
+ *
+ * Returns: A #GstTunerNorm, or NULL if no norm with the provided name
+ * is available.
+ */
+GstTunerNorm *
+gst_tuner_find_norm_by_name (GstTuner * tuner, gchar * norm)
+{
+  GList *walk;
+
+  g_return_val_if_fail (GST_IS_TUNER (tuner), NULL);
+  g_return_val_if_fail (norm != NULL, NULL);
+
+  walk = (GList *) gst_tuner_list_norms (tuner);
+  while (walk) {
+    if (strcmp (GST_TUNER_NORM (walk->data)->label, norm) == 0)
+      return GST_TUNER_NORM (walk->data);
+    walk = g_list_next (walk);
+  }
+  return NULL;
+}
+
+/**
+ * gst_tuner_find_channel_by_name:
+ * @tuner: A #GstTuner instance
+ * @channel: A string containing the name of a #GstTunerChannel
+ * 
+ * Look up a #GstTunerChannel by name.
+ *
+ * Returns: A #GstTunerChannel, or NULL if no channel with the provided name
+ * is available.
+ */
+GstTunerChannel *
+gst_tuner_find_channel_by_name (GstTuner * tuner, gchar * channel)
+{
+  GList *walk;
+
+  g_return_val_if_fail (GST_IS_TUNER (tuner), NULL);
+  g_return_val_if_fail (channel != NULL, NULL);
+
+  walk = (GList *) gst_tuner_list_channels (tuner);
+  while (walk) {
+    if (strcmp (GST_TUNER_CHANNEL (walk->data)->label, channel) == 0)
+      return GST_TUNER_CHANNEL (walk->data);
+    walk = g_list_next (walk);
+  }
+  return NULL;
+}
+
+/**
+ * gst_tuner_channel_changed:
+ * @tuner: A #GstTuner instance
+ * @channel: A #GstTunerChannel instance
+ *
+ * Called by elements implementing the #GstTuner interface when the
+ * current channel changes. Fires the #GstTuner::channel-changed signal.
+ */
+void
+gst_tuner_channel_changed (GstTuner * tuner, GstTunerChannel * channel)
+{
+  g_return_if_fail (GST_IS_TUNER (tuner));
+  g_return_if_fail (GST_IS_TUNER_CHANNEL (channel));
+
+  g_signal_emit (G_OBJECT (tuner),
+      gst_tuner_signals[CHANNEL_CHANGED], 0, channel);
+}
+
+/**
+ * gst_tuner_norm_changed:
+ * @tuner: A #GstTuner instance
+ * @norm: A #GstTunerNorm instance
+ *
+ * Called by elements implementing the #GstTuner interface when the
+ * current norm changes. Fires the #GstTuner::norm-changed signal.
+ * 
+ */
+void
+gst_tuner_norm_changed (GstTuner * tuner, GstTunerNorm * norm)
+{
+  g_return_if_fail (GST_IS_TUNER (tuner));
+  g_return_if_fail (GST_IS_TUNER_NORM (norm));
+
+  g_signal_emit (G_OBJECT (tuner), gst_tuner_signals[NORM_CHANGED], 0, norm);
+}
+
+/**
+ * gst_tuner_frequency_changed:
+ * @tuner: A #GstTuner instance
+ * @channel: The current #GstTunerChannel
+ * @frequency: The new frequency setting
+ *
+ * Called by elements implementing the #GstTuner interface when the
+ * configured frequency changes. Fires the #GstTuner::frequency-changed
+ * signal on the tuner, and the #GstTunerChannel::frequency-changed signal
+ * on the channel.
+ */
+void
+gst_tuner_frequency_changed (GstTuner * tuner,
+    GstTunerChannel * channel, gulong frequency)
+{
+  g_return_if_fail (GST_IS_TUNER (tuner));
+  g_return_if_fail (GST_IS_TUNER_CHANNEL (channel));
+
+  g_signal_emit (G_OBJECT (tuner),
+      gst_tuner_signals[FREQUENCY_CHANGED], 0, channel, frequency);
+
+  g_signal_emit_by_name (G_OBJECT (channel), "frequency_changed", frequency);
+}
+
+/**
+ * gst_tuner_signal_changed:
+ * @tuner: A #GstTuner instance
+ * @channel: The current #GstTunerChannel
+ * @signal: The new signal strength
+ *
+ * Called by elements implementing the #GstTuner interface when the
+ * incoming signal strength changes. Fires the #GstTuner::signal-changed
+ * signal on the tuner and the #GstTunerChannel::signal-changed signal on 
+ * the channel.
+ */
+void
+gst_tuner_signal_changed (GstTuner * tuner,
+    GstTunerChannel * channel, gint signal)
+{
+  g_return_if_fail (GST_IS_TUNER (tuner));
+  g_return_if_fail (GST_IS_TUNER_CHANNEL (channel));
+
+  g_signal_emit (G_OBJECT (tuner),
+      gst_tuner_signals[SIGNAL_CHANGED], 0, channel, signal);
+
+  g_signal_emit_by_name (G_OBJECT (channel), "signal_changed", signal);
+}
diff --git a/sys/v4l2/tuner.h b/sys/v4l2/tuner.h
new file mode 100644
index 0000000..7297e4b
--- /dev/null
+++ b/sys/v4l2/tuner.h
@@ -0,0 +1,141 @@
+/* GStreamer Tuner
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * tuner.h: tuner interface design
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_TUNER_H__
+#define __GST_TUNER_H__
+
+#include <gst/gst.h>
+
+#include "tunernorm.h"
+#include "tunerchannel.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_TUNER \
+  (gst_tuner_get_type ())
+#define GST_TUNER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TUNER, GstTuner))
+#define GST_IS_TUNER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TUNER))
+#define GST_TUNER_GET_INTERFACE(inst) \
+  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_TUNER, GstTunerInterface))
+
+typedef struct _GstTuner GstTuner;
+typedef struct _GstTunerInterface GstTunerInterface;
+
+/**
+ * GstTunerInterface:
+ * @iface: the parent interface
+ * @list_channels: list available channels
+ * @set_channel: set to a channel
+ * @get_channel: return the current channel
+ * @list_norms: list available norms
+ * @set_norm: set a norm
+ * @get_norm: return the current norm
+ * @set_frequency: set the frequency
+ * @get_frequency: return the current frequency
+ * @signal_strength: get the signal strength
+ * @channel_changed: default handler for channel changed notification
+ * @norm_changed: default handler for norm changed notification
+ * @frequency_changed: default handler for frequency changed notification
+ * @signal_changed: default handler for signal-strength changed notification
+ *
+ * Tuner interface.
+ */
+struct _GstTunerInterface {
+  GTypeInterface iface;
+
+  /* virtual functions */
+  const GList * (* list_channels)   (GstTuner        *tuner);
+  void          (* set_channel)     (GstTuner        *tuner,
+                                     GstTunerChannel *channel);
+  GstTunerChannel *
+                (* get_channel)     (GstTuner        *tuner);
+
+  const GList * (* list_norms)      (GstTuner        *tuner);
+  void          (* set_norm)        (GstTuner        *tuner,
+                                     GstTunerNorm    *norm);
+  GstTunerNorm *(* get_norm)        (GstTuner        *tuner);
+
+  void          (* set_frequency)   (GstTuner        *tuner,
+                                     GstTunerChannel *channel,
+                                     gulong           frequency);
+  gulong        (* get_frequency)   (GstTuner        *tuner,
+                                     GstTunerChannel *channel);
+  gint          (* signal_strength) (GstTuner        *tuner,
+                                     GstTunerChannel *channel);
+
+  /* signals */
+  void (*channel_changed)   (GstTuner        *tuner,
+                             GstTunerChannel *channel);
+  void (*norm_changed)      (GstTuner        *tuner,
+                             GstTunerNorm    *norm);
+  void (*frequency_changed) (GstTuner        *tuner,
+                             GstTunerChannel *channel,
+                             gulong           frequency);
+  void (*signal_changed)    (GstTuner        *tuner,
+                             GstTunerChannel *channel,
+                             gint             signal);
+};
+
+GType           gst_tuner_get_type              (void);
+
+/* virtual class function wrappers */
+const GList *   gst_tuner_list_channels         (GstTuner        *tuner);
+void            gst_tuner_set_channel           (GstTuner        *tuner,
+                                                 GstTunerChannel *channel);
+GstTunerChannel *
+                gst_tuner_get_channel           (GstTuner        *tuner);
+
+const GList *   gst_tuner_list_norms            (GstTuner        *tuner);
+void            gst_tuner_set_norm              (GstTuner        *tuner,
+                                                 GstTunerNorm    *norm);
+GstTunerNorm *  gst_tuner_get_norm              (GstTuner        *tuner);
+
+void            gst_tuner_set_frequency         (GstTuner        *tuner,
+                                                 GstTunerChannel *channel,
+                                                 gulong           frequency);
+gulong          gst_tuner_get_frequency         (GstTuner        *tuner,
+                                                 GstTunerChannel *channel);
+gint            gst_tuner_signal_strength       (GstTuner        *tuner,
+                                                 GstTunerChannel *channel);
+
+/* helper functions */
+GstTunerNorm *  gst_tuner_find_norm_by_name     (GstTuner        *tuner,
+                                                 gchar           *norm);
+GstTunerChannel *gst_tuner_find_channel_by_name (GstTuner        *tuner,
+                                                 gchar           *channel);
+
+/* trigger signals */
+void            gst_tuner_channel_changed       (GstTuner        *tuner,
+                                                 GstTunerChannel *channel);
+void            gst_tuner_norm_changed          (GstTuner        *tuner,
+                                                 GstTunerNorm    *norm);
+void            gst_tuner_frequency_changed     (GstTuner        *tuner,
+                                                 GstTunerChannel *channel,
+                                                 gulong           frequency);
+void            gst_tuner_signal_changed        (GstTuner        *tuner,
+                                                 GstTunerChannel *channel,
+                                                 gint             signal);
+
+G_END_DECLS
+
+#endif /* __GST_TUNER_H__ */
diff --git a/sys/v4l2/tunerchannel.c b/sys/v4l2/tunerchannel.c
new file mode 100644
index 0000000..6e45696
--- /dev/null
+++ b/sys/v4l2/tunerchannel.c
@@ -0,0 +1,117 @@
+/* GStreamer Tuner
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * tunerchannel.c: tuner channel object design
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tunerchannel.h"
+
+/**
+ * SECTION:gsttunerchannel
+ * @short_description: A channel from an element implementing the #GstTuner
+ * interface.
+ *
+ * <refsect2>
+ * <para>The #GstTunerChannel object is provided by an element implementing
+ * the #GstTuner interface.
+ * </para>
+ * <para>
+ * GstTunerChannel provides a name and flags to determine the type and
+ * capabilities of the channel. If the GST_TUNER_CHANNEL_FREQUENCY flag is
+ * set, then the channel also information about the minimum and maximum
+ * frequency, and range of the reported signal strength.
+ * </para>
+ * </refsect2>
+ */
+
+enum
+{
+  /* FILL ME */
+  SIGNAL_FREQUENCY_CHANGED,
+  SIGNAL_SIGNAL_CHANGED,
+  LAST_SIGNAL
+};
+
+G_DEFINE_TYPE (GstTunerChannel, gst_tuner_channel, G_TYPE_OBJECT);
+
+static void gst_tuner_channel_dispose (GObject * object);
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+gst_tuner_channel_class_init (GstTunerChannelClass * klass)
+{
+  GObjectClass *object_klass = (GObjectClass *) klass;
+
+  /**
+   * GstTunerChannel::frequency-changed:
+   * @tunerchannel: The #GstTunerChannel
+   * @frequency: The new frequency (an unsigned long)
+   *
+   * Reports that the current frequency has changed.
+   */
+  signals[SIGNAL_FREQUENCY_CHANGED] =
+      g_signal_new ("frequency-changed", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstTunerChannelClass,
+          frequency_changed),
+      NULL, NULL, g_cclosure_marshal_VOID__ULONG, G_TYPE_NONE, 1, G_TYPE_ULONG);
+  /**
+   * GstTunerChannel::signal-changed:
+   * @tunerchannel: The #GstTunerChannel
+   * @signal: The new signal strength (an integer)
+   *
+   * Reports that the signal strength has changed.
+   *
+   * See Also: gst_tuner_signal_strength()
+   */
+  signals[SIGNAL_SIGNAL_CHANGED] =
+      g_signal_new ("signal-changed", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstTunerChannelClass,
+          signal_changed),
+      NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
+
+  object_klass->dispose = gst_tuner_channel_dispose;
+}
+
+static void
+gst_tuner_channel_init (GstTunerChannel * channel)
+{
+  channel->label = NULL;
+  channel->flags = 0;
+  channel->min_frequency = channel->max_frequency = 0;
+  channel->min_signal = channel->max_signal = 0;
+}
+
+static void
+gst_tuner_channel_dispose (GObject * object)
+{
+  GstTunerChannel *channel = GST_TUNER_CHANNEL (object);
+
+  if (channel->label) {
+    g_free (channel->label);
+    channel->label = NULL;
+  }
+
+  G_OBJECT_CLASS (gst_tuner_channel_parent_class)->dispose (object);
+}
diff --git a/sys/v4l2/tunerchannel.h b/sys/v4l2/tunerchannel.h
new file mode 100644
index 0000000..0080c73
--- /dev/null
+++ b/sys/v4l2/tunerchannel.h
@@ -0,0 +1,116 @@
+/* GStreamer Tuner
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * tunerchannel.h: tuner channel object design
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_TUNER_CHANNEL_H__
+#define __GST_TUNER_CHANNEL_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_TUNER_CHANNEL \
+  (gst_tuner_channel_get_type ())
+#define GST_TUNER_CHANNEL(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TUNER_CHANNEL, \
+                               GstTunerChannel))
+#define GST_TUNER_CHANNEL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TUNER_CHANNEL, \
+                            GstTunerChannelClass))
+#define GST_IS_TUNER_CHANNEL(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TUNER_CHANNEL))
+#define GST_IS_TUNER_CHANNEL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TUNER_CHANNEL))
+
+typedef struct _GstTunerChannel GstTunerChannel;
+typedef struct _GstTunerChannelClass GstTunerChannelClass;
+
+/**
+ * GstTunerChannelFlags:
+ * @GST_TUNER_CHANNEL_INPUT: The channel is for input
+ * @GST_TUNER_CHANNEL_OUTPUT: The channel is for output
+ * @GST_TUNER_CHANNEL_FREQUENCY: The channel has a frequency setting
+ *                               and signal strength.
+ * @GST_TUNER_CHANNEL_AUDIO: The channel carries audio.
+ *
+ * An enumeration for flags indicating the available capabilities
+ * of a #GstTunerChannel.
+ */
+typedef enum {
+  GST_TUNER_CHANNEL_INPUT     = (1<<0),
+  GST_TUNER_CHANNEL_OUTPUT    = (1<<1),
+  GST_TUNER_CHANNEL_FREQUENCY = (1<<2),
+  GST_TUNER_CHANNEL_AUDIO     = (1<<3)
+} GstTunerChannelFlags;
+
+/**
+ * GST_TUNER_CHANNEL_HAS_FLAG:
+ * @channel: A #GstTunerChannel
+ * @flag: The flag to check for
+ *
+ * Macro to check if the given flag is set on a channel
+ */
+#define GST_TUNER_CHANNEL_HAS_FLAG(channel, flag) \
+  ((channel)->flags & flag)
+
+/**
+ * GstTunerChannel:
+ * @label: A string containing a descriptive name for this channel
+ * @flags: A set of #GstTunerChannelFlags for this channel
+ * @freq_multiplicator: The step size (in Hz) for the frequency setting.
+ * @min_frequency: Minimum valid frequency setting (in Hz).
+ * @max_frequency: Maximum valid frequency setting (in Hz).
+ * @min_signal: Minimum reported signal strength value.
+ * @max_signal: Maximum reported signal strength value.
+ */
+struct _GstTunerChannel {
+  GObject              parent;
+
+  /*< public >*/
+  gchar               *label;
+  GstTunerChannelFlags flags;
+  gfloat               freq_multiplicator;
+  gulong               min_frequency;
+  gulong               max_frequency;
+  gint                 min_signal;
+  gint                 max_signal;
+
+  /*< private >*/
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+struct _GstTunerChannelClass {
+  GObjectClass parent;
+
+  /*< private >*/
+  /* signals */
+  void (*frequency_changed) (GstTunerChannel *channel,
+                             gulong           frequency);
+  void (*signal_changed)    (GstTunerChannel *channel,
+                             gint             signal);
+
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+GType           gst_tuner_channel_get_type      (void);
+
+G_END_DECLS
+
+#endif /* __GST_TUNER_CHANNEL_H__ */
diff --git a/sys/v4l2/tunernorm.c b/sys/v4l2/tunernorm.c
new file mode 100644
index 0000000..5c57ffb
--- /dev/null
+++ b/sys/v4l2/tunernorm.c
@@ -0,0 +1,81 @@
+/* GStreamer Tuner
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * tunernorm.c: tuner norm object design
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tunernorm.h"
+
+/**
+ * SECTION:gsttunernorm
+ * @short_description: Encapsulates information about the data format(s)
+ * for a #GstTunerChannel.
+ *
+ * <refsect2>
+ * <para>The #GstTunerNorm object is created by an element implementing the
+ * #GstTuner interface and encapsulates the selection of a capture/output format
+ * for a selected #GstTunerChannel.
+ * </para>
+ * </refsect2>
+ */
+
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+G_DEFINE_TYPE (GstTunerNorm, gst_tuner_norm, G_TYPE_OBJECT);
+
+static void gst_tuner_norm_dispose (GObject * object);
+
+
+/*static guint signals[LAST_SIGNAL] = { 0 };*/
+
+static void
+gst_tuner_norm_class_init (GstTunerNormClass * klass)
+{
+  GObjectClass *object_klass = (GObjectClass *) klass;
+
+
+  object_klass->dispose = gst_tuner_norm_dispose;
+}
+
+static void
+gst_tuner_norm_init (GstTunerNorm * norm)
+{
+  norm->label = NULL;
+  g_value_init (&norm->framerate, GST_TYPE_FRACTION);
+}
+
+static void
+gst_tuner_norm_dispose (GObject * object)
+{
+  GstTunerNorm *norm = GST_TUNER_NORM (object);
+
+  if (norm->label) {
+    g_free (norm->label);
+    norm->label = NULL;
+  }
+
+  G_OBJECT_CLASS (gst_tuner_norm_parent_class)->dispose (object);
+}
diff --git a/sys/v4l2/tunernorm.h b/sys/v4l2/tunernorm.h
new file mode 100644
index 0000000..94da22c
--- /dev/null
+++ b/sys/v4l2/tunernorm.h
@@ -0,0 +1,70 @@
+/* GStreamer Tuner
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * tunernorm.h: tuner norm object design
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_TUNER_NORM_H__
+#define __GST_TUNER_NORM_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_TUNER_NORM \
+  (gst_tuner_norm_get_type ())
+#define GST_TUNER_NORM(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TUNER_NORM, GstTunerNorm))
+#define GST_TUNER_NORM_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TUNER_NORM, GstTunerNormClass))
+#define GST_IS_TUNER_NORM(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TUNER_NORM))
+#define GST_IS_TUNER_NORM_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TUNER_NORM))
+
+typedef struct _GstTunerNorm GstTunerNorm;
+typedef struct _GstTunerNormClass GstTunerNormClass;
+
+/**
+ * GstTunerNorm:
+ * @label: A string containing a descriptive name for the norm
+ * @framerate: A GValue containing the framerate associated with this norm,
+ *             if any. (May be unset).
+ */
+struct _GstTunerNorm {
+  GObject parent;
+
+  /*< public >*/
+  gchar  *label;
+  GValue  framerate;
+
+  /*< private >*/
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+struct _GstTunerNormClass {
+  GObjectClass parent;
+
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+GType           gst_tuner_norm_get_type         (void);
+
+G_END_DECLS
+
+#endif /* __GST_TUNER_NORM_H__ */
diff --git a/sys/v4l2/v4l2-utils.c b/sys/v4l2/v4l2-utils.c
new file mode 100644
index 0000000..260c5df
--- /dev/null
+++ b/sys/v4l2/v4l2-utils.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2014 Collabora Ltd.
+ *     Author: Nicolas Dufresne <nicolas.dufresne@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "v4l2-utils.h"
+
+/**************************/
+/* Common device iterator */
+/**************************/
+
+#ifdef HAVE_GUDEV
+#include <gudev/gudev.h>
+
+struct _GstV4l2GUdevIterator
+{
+  GstV4l2Iterator parent;
+  GList *devices;
+  GUdevDevice *device;
+  GUdevClient *client;
+};
+
+GstV4l2Iterator *
+gst_v4l2_iterator_new (void)
+{
+  static const gchar *subsystems[] = { "video4linux", NULL };
+  struct _GstV4l2GUdevIterator *it;
+
+  it = g_slice_new0 (struct _GstV4l2GUdevIterator);
+
+  it->client = g_udev_client_new (subsystems);
+  it->devices = g_udev_client_query_by_subsystem (it->client, "video4linux");
+
+  return (GstV4l2Iterator *) it;
+}
+
+gboolean
+gst_v4l2_iterator_next (GstV4l2Iterator * _it)
+{
+  struct _GstV4l2GUdevIterator *it = (struct _GstV4l2GUdevIterator *) _it;
+  const gchar *device_name;
+
+  if (it->device)
+    g_object_unref (it->device);
+
+  it->device = NULL;
+  it->parent.device_path = NULL;
+  it->parent.device_name = NULL;
+
+  if (it->devices == NULL)
+    return FALSE;
+
+  it->device = it->devices->data;
+  it->devices = g_list_delete_link (it->devices, it->devices);
+
+  device_name = g_udev_device_get_property (it->device, "ID_V4L_PRODUCT");
+  if (!device_name)
+    device_name = g_udev_device_get_property (it->device, "ID_MODEL_ENC");
+  if (!device_name)
+    device_name = g_udev_device_get_property (it->device, "ID_MODEL");
+
+  it->parent.device_path = g_udev_device_get_device_file (it->device);
+  it->parent.device_name = device_name;
+  it->parent.sys_path = g_udev_device_get_sysfs_path (it->device);
+
+  return TRUE;
+}
+
+void
+gst_v4l2_iterator_free (GstV4l2Iterator * _it)
+{
+  struct _GstV4l2GUdevIterator *it = (struct _GstV4l2GUdevIterator *) _it;
+  g_list_free_full (it->devices, g_object_unref);
+  gst_object_unref (it->client);
+  g_slice_free (struct _GstV4l2GUdevIterator, it);
+}
+
+#else /* No GUDEV */
+
+struct _GstV4l2FsIterator
+{
+  GstV4l2Iterator parent;
+  gint base_idx;
+  gint video_idx;
+  gchar *device;
+};
+
+GstV4l2Iterator *
+gst_v4l2_iterator_new (void)
+{
+  struct _GstV4l2FsIterator *it;
+
+  it = g_slice_new0 (struct _GstV4l2FsIterator);
+  it->base_idx = 0;
+  it->video_idx = -1;
+  it->device = NULL;
+
+  return (GstV4l2Iterator *) it;
+}
+
+gboolean
+gst_v4l2_iterator_next (GstV4l2Iterator * _it)
+{
+  struct _GstV4l2FsIterator *it = (struct _GstV4l2FsIterator *) _it;
+  static const gchar *dev_base[] = { "/dev/video", "/dev/v4l2/video", NULL };
+  gchar *device = NULL;
+
+  g_free ((gchar *) it->parent.device_path);
+  it->parent.device_path = NULL;
+
+  while (device == NULL) {
+    it->video_idx++;
+
+    if (it->video_idx >= 64) {
+      it->video_idx = 0;
+      it->base_idx++;
+    }
+
+    if (dev_base[it->base_idx] == NULL) {
+      it->video_idx = 0;
+      break;
+    }
+
+    device = g_strdup_printf ("%s%d", dev_base[it->base_idx], it->video_idx);
+
+    if (g_file_test (device, G_FILE_TEST_EXISTS)) {
+      it->parent.device_path = device;
+      break;
+    }
+
+    g_free (device);
+    device = NULL;
+  }
+
+  return it->parent.device_path != NULL;
+}
+
+void
+gst_v4l2_iterator_free (GstV4l2Iterator * _it)
+{
+  struct _GstV4l2FsIterator *it = (struct _GstV4l2FsIterator *) _it;
+  g_free ((gchar *) it->parent.device_path);
+  g_slice_free (struct _GstV4l2FsIterator, it);
+}
+
+#endif
+
+void
+gst_v4l2_clear_error (GstV4l2Error * v4l2err)
+{
+  if (v4l2err) {
+    g_clear_error (&v4l2err->error);
+    g_free (v4l2err->dbg_message);
+    v4l2err->dbg_message = NULL;
+  }
+}
+
+void
+gst_v4l2_error (gpointer element, GstV4l2Error * v4l2err)
+{
+  GError *error;
+
+  if (!v4l2err || !v4l2err->error)
+    return;
+
+  error = v4l2err->error;
+
+  if (error->message)
+    GST_WARNING_OBJECT (element, "error: %s", error->message);
+
+  if (v4l2err->dbg_message)
+    GST_WARNING_OBJECT (element, "error: %s", v4l2err->dbg_message);
+
+  gst_element_message_full (GST_ELEMENT (element), GST_MESSAGE_ERROR,
+      error->domain, error->code, error->message, v4l2err->dbg_message,
+      v4l2err->file, v4l2err->func, v4l2err->line);
+
+  error->message = NULL;
+  v4l2err->dbg_message = NULL;
+
+  gst_v4l2_clear_error (v4l2err);
+}
diff --git a/sys/v4l2/v4l2-utils.h b/sys/v4l2/v4l2-utils.h
new file mode 100644
index 0000000..1bc0062
--- /dev/null
+++ b/sys/v4l2/v4l2-utils.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 Collabora Ltd.
+ *     Author: Nicolas Dufresne <nicolas.dufresne@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __V4L2_UTILS_H__
+#define __V4L2_UTILS_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_V4L2_ERROR_INIT { NULL, NULL }
+#define GST_V4L2_ERROR(v4l2err,domain,code,msg,dbg) \
+{\
+  if (v4l2err) { \
+    gchar *_msg = _gst_element_error_printf msg; \
+    v4l2err->error = g_error_new_literal (GST_##domain##_ERROR, \
+        GST_##domain##_ERROR_##code, _msg); \
+    g_free (_msg); \
+    v4l2err->dbg_message = _gst_element_error_printf dbg; \
+    v4l2err->file = __FILE__; \
+    v4l2err->func = GST_FUNCTION; \
+    v4l2err->line = __LINE__; \
+  } \
+}
+
+typedef struct _GstV4l2Iterator GstV4l2Iterator;
+typedef struct _GstV4l2Error GstV4l2Error;
+
+struct _GstV4l2Iterator
+{
+    const gchar *device_path;
+    const gchar *device_name;
+    const gchar *sys_path;
+};
+
+struct _GstV4l2Error
+{
+    GError *error;
+    gchar *dbg_message;
+    const gchar *file;
+    const gchar *func;
+    gint line;
+};
+
+GstV4l2Iterator *  gst_v4l2_iterator_new (void);
+gboolean           gst_v4l2_iterator_next (GstV4l2Iterator *it);
+void               gst_v4l2_iterator_free (GstV4l2Iterator *it);
+
+const gchar *      gst_v4l2_iterator_get_device_path (GstV4l2Iterator *it);
+const gchar *      gst_v4l2_iterator_get_device_name (GstV4l2Iterator *it);
+const gchar *      gst_v4l2_iterator_get_sys_path (GstV4l2Iterator *it);
+
+void               gst_v4l2_clear_error (GstV4l2Error *error);
+void               gst_v4l2_error (gpointer element, GstV4l2Error *error);
+
+G_END_DECLS
+
+#endif /* __V4L2_UTILS_H__ */
+
+
diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c
new file mode 100644
index 0000000..12fc821
--- /dev/null
+++ b/sys/v4l2/v4l2_calls.c
@@ -0,0 +1,1139 @@
+/* GStreamer
+ *
+ * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *               2006 Edgard Lima <edgard.lima@gmail.com>
+ *
+ * v4l2_calls.c - generic V4L2 calls handling
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#ifdef __sun
+/* Needed on older Solaris Nevada builds (72 at least) */
+#include <stropts.h>
+#include <sys/ioccom.h>
+#endif
+#include "gstv4l2object.h"
+#include "gstv4l2tuner.h"
+#include "gstv4l2colorbalance.h"
+
+#include "gstv4l2src.h"
+#include "gstv4l2sink.h"
+#include "gstv4l2videodec.h"
+
+#include "gst/gst-i18n-plugin.h"
+
+GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
+#define GST_CAT_DEFAULT v4l2_debug
+
+/******************************************************
+ * gst_v4l2_get_capabilities():
+ *   get the device's capturing capabilities
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+static gboolean
+gst_v4l2_get_capabilities (GstV4l2Object * v4l2object)
+{
+  GstElement *e;
+
+  e = v4l2object->element;
+
+  GST_DEBUG_OBJECT (e, "getting capabilities");
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP,
+          &v4l2object->vcap) < 0)
+    goto cap_failed;
+
+  if (v4l2object->vcap.capabilities & V4L2_CAP_DEVICE_CAPS)
+    v4l2object->device_caps = v4l2object->vcap.device_caps;
+  else
+    v4l2object->device_caps = v4l2object->vcap.capabilities;
+
+  GST_LOG_OBJECT (e, "driver:      '%s'", v4l2object->vcap.driver);
+  GST_LOG_OBJECT (e, "card:        '%s'", v4l2object->vcap.card);
+  GST_LOG_OBJECT (e, "bus_info:    '%s'", v4l2object->vcap.bus_info);
+  GST_LOG_OBJECT (e, "version:     %08x", v4l2object->vcap.version);
+  GST_LOG_OBJECT (e, "capabilites: %08x", v4l2object->device_caps);
+
+  return TRUE;
+
+  /* ERRORS */
+cap_failed:
+  {
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Error getting capabilities for device '%s': "
+                "It isn't a v4l2 driver. Check if it is a v4l1 driver."),
+            v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+}
+
+/******************************************************
+ * The video4linux command line tool v4l2-ctrl
+ * normalises the names of the controls received from
+ * the kernel like:
+ *
+ *     "Exposure (absolute)" -> "exposure_absolute"
+ *
+ * We follow their lead here.  @name is modified
+ * in-place.
+ ******************************************************/
+static void
+gst_v4l2_normalise_control_name (gchar * name)
+{
+  int i, j;
+  for (i = 0, j = 0; name[j]; ++j) {
+    if (g_ascii_isalnum (name[j])) {
+      if (i > 0 && !g_ascii_isalnum (name[j - 1]))
+        name[i++] = '_';
+      name[i++] = g_ascii_tolower (name[j]);
+    }
+  }
+  name[i++] = '\0';
+}
+
+/******************************************************
+ * gst_v4l2_empty_lists() and gst_v4l2_fill_lists():
+ *   fill/empty the lists of enumerations
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+static gboolean
+gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
+{
+  gint n, next;
+  struct v4l2_queryctrl control = { 0, };
+
+  GstElement *e;
+
+  e = v4l2object->element;
+
+  GST_DEBUG_OBJECT (e, "getting enumerations");
+  GST_V4L2_CHECK_OPEN (v4l2object);
+
+  GST_DEBUG_OBJECT (e, "  channels");
+  /* and now, the channels */
+  for (n = 0;; n++) {
+    struct v4l2_input input;
+    GstV4l2TunerChannel *v4l2channel;
+    GstTunerChannel *channel;
+
+    memset (&input, 0, sizeof (input));
+
+    input.index = n;
+    if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_ENUMINPUT, &input) < 0) {
+      if (errno == EINVAL || errno == ENOTTY)
+        break;                  /* end of enumeration */
+      else {
+        GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
+            (_("Failed to query attributes of input %d in device %s"),
+                n, v4l2object->videodev),
+            ("Failed to get %d in input enumeration for %s. (%d - %s)",
+                n, v4l2object->videodev, errno, strerror (errno)));
+        return FALSE;
+      }
+    }
+
+    GST_LOG_OBJECT (e, "   index:     %d", input.index);
+    GST_LOG_OBJECT (e, "   name:      '%s'", input.name);
+    GST_LOG_OBJECT (e, "   type:      %08x", input.type);
+    GST_LOG_OBJECT (e, "   audioset:  %08x", input.audioset);
+    GST_LOG_OBJECT (e, "   std:       %016" G_GINT64_MODIFIER "x",
+        (guint64) input.std);
+    GST_LOG_OBJECT (e, "   status:    %08x", input.status);
+
+    v4l2channel = g_object_new (GST_TYPE_V4L2_TUNER_CHANNEL, NULL);
+    channel = GST_TUNER_CHANNEL (v4l2channel);
+    channel->label = g_strdup ((const gchar *) input.name);
+    channel->flags = GST_TUNER_CHANNEL_INPUT;
+    v4l2channel->index = n;
+
+    if (input.type == V4L2_INPUT_TYPE_TUNER) {
+      struct v4l2_tuner vtun;
+
+      v4l2channel->tuner = input.tuner;
+      channel->flags |= GST_TUNER_CHANNEL_FREQUENCY;
+
+      vtun.index = input.tuner;
+      if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun) < 0) {
+        GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
+            (_("Failed to get setting of tuner %d on device '%s'."),
+                input.tuner, v4l2object->videodev), GST_ERROR_SYSTEM);
+        g_object_unref (G_OBJECT (channel));
+        return FALSE;
+      }
+
+      channel->freq_multiplicator =
+          62.5 * ((vtun.capability & V4L2_TUNER_CAP_LOW) ? 1 : 1000);
+      channel->min_frequency = vtun.rangelow * channel->freq_multiplicator;
+      channel->max_frequency = vtun.rangehigh * channel->freq_multiplicator;
+      channel->min_signal = 0;
+      channel->max_signal = 0xffff;
+    }
+    if (input.audioset) {
+      /* we take the first. We don't care for
+       * the others for now */
+      while (!(input.audioset & (1 << v4l2channel->audio)))
+        v4l2channel->audio++;
+      channel->flags |= GST_TUNER_CHANNEL_AUDIO;
+    }
+
+    v4l2object->channels =
+        g_list_prepend (v4l2object->channels, (gpointer) channel);
+  }
+  v4l2object->channels = g_list_reverse (v4l2object->channels);
+
+  GST_DEBUG_OBJECT (e, "  norms");
+  /* norms... */
+  for (n = 0;; n++) {
+    struct v4l2_standard standard = { 0, };
+    GstV4l2TunerNorm *v4l2norm;
+
+    GstTunerNorm *norm;
+
+    /* fill in defaults */
+    standard.frameperiod.numerator = 1;
+    standard.frameperiod.denominator = 0;
+    standard.index = n;
+
+    if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
+      if (errno == EINVAL || errno == ENOTTY)
+        break;                  /* end of enumeration */
+#ifdef ENODATA
+      else if (errno == ENODATA)
+        break;                  /* end of enumeration, as of Linux 3.7-rc1 */
+#endif
+      else {
+        GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
+            (_("Failed to query norm on device '%s'."),
+                v4l2object->videodev),
+            ("Failed to get attributes for norm %d on devide '%s'. (%d - %s)",
+                n, v4l2object->videodev, errno, strerror (errno)));
+        return FALSE;
+      }
+    }
+
+    GST_DEBUG_OBJECT (e, "    '%s', fps: %d / %d",
+        standard.name, standard.frameperiod.denominator,
+        standard.frameperiod.numerator);
+
+    v4l2norm = g_object_new (GST_TYPE_V4L2_TUNER_NORM, NULL);
+    norm = GST_TUNER_NORM (v4l2norm);
+    norm->label = g_strdup ((const gchar *) standard.name);
+    gst_value_set_fraction (&norm->framerate,
+        standard.frameperiod.denominator, standard.frameperiod.numerator);
+    v4l2norm->index = standard.id;
+
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "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);
+
+  GST_DEBUG_OBJECT (e, "  controls+menus");
+
+  /* and lastly, controls+menus (if appropriate) */
+  next = V4L2_CTRL_FLAG_NEXT_CTRL;
+  n = 0;
+  control.id = next;
+
+  while (TRUE) {
+    GstV4l2ColorBalanceChannel *v4l2channel;
+    GstColorBalanceChannel *channel;
+
+    if (!next)
+      n++;
+
+  retry:
+    /* when we reached the last official CID, continue with private CIDs */
+    if (n == V4L2_CID_LASTP1) {
+      GST_DEBUG_OBJECT (e, "checking private CIDs");
+      n = V4L2_CID_PRIVATE_BASE;
+    }
+    GST_DEBUG_OBJECT (e, "checking control %08x", n);
+
+    control.id = n | next;
+    if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_QUERYCTRL,
+            &control) < 0) {
+      if (next) {
+        if (n > 0) {
+          GST_DEBUG_OBJECT (e, "controls finished");
+          break;
+        } else {
+          GST_DEBUG_OBJECT (e, "V4L2_CTRL_FLAG_NEXT_CTRL not supported.");
+          next = 0;
+          n = V4L2_CID_BASE;
+          goto retry;
+        }
+      }
+      if (errno == EINVAL || errno == ENOTTY || errno == EIO || errno == ENOENT) {
+        if (n < V4L2_CID_PRIVATE_BASE) {
+          GST_DEBUG_OBJECT (e, "skipping control %08x", n);
+          /* continue so that we also check private controls */
+          n = V4L2_CID_PRIVATE_BASE - 1;
+          continue;
+        } else {
+          GST_DEBUG_OBJECT (e, "controls finished");
+          break;
+        }
+      } else {
+        GST_WARNING_OBJECT (e, "Failed querying control %d on device '%s'. "
+            "(%d - %s)", n, v4l2object->videodev, errno, strerror (errno));
+        continue;
+      }
+    }
+    /* bogus driver might mess with id in unexpected ways (e.g. set to 0), so
+     * make sure to simply try all if V4L2_CTRL_FLAG_NEXT_CTRL not supported */
+    if (next)
+      n = control.id;
+    if (control.flags & V4L2_CTRL_FLAG_DISABLED) {
+      GST_DEBUG_OBJECT (e, "skipping disabled control");
+      continue;
+    }
+
+    if (control.type == V4L2_CTRL_TYPE_CTRL_CLASS) {
+      GST_DEBUG_OBJECT (e, "starting control class '%s'", control.name);
+      continue;
+    }
+
+    switch (control.type) {
+      case V4L2_CTRL_TYPE_INTEGER:
+      case V4L2_CTRL_TYPE_BOOLEAN:
+      case V4L2_CTRL_TYPE_MENU:
+      case V4L2_CTRL_TYPE_INTEGER_MENU:
+      case V4L2_CTRL_TYPE_BITMASK:
+      case V4L2_CTRL_TYPE_BUTTON:{
+        control.name[31] = '\0';
+        gst_v4l2_normalise_control_name ((gchar *) control.name);
+        g_datalist_id_set_data (&v4l2object->controls,
+            g_quark_from_string ((const gchar *) control.name),
+            GINT_TO_POINTER (n));
+        break;
+      }
+      default:
+        GST_DEBUG_OBJECT (e,
+            "Control type for '%s' not suppored for extra controls.",
+            control.name);
+        break;
+    }
+
+    switch (n) {
+      case V4L2_CID_BRIGHTNESS:
+      case V4L2_CID_CONTRAST:
+      case V4L2_CID_SATURATION:
+      case V4L2_CID_HUE:
+      case V4L2_CID_BLACK_LEVEL:
+      case V4L2_CID_AUTO_WHITE_BALANCE:
+      case V4L2_CID_DO_WHITE_BALANCE:
+      case V4L2_CID_RED_BALANCE:
+      case V4L2_CID_BLUE_BALANCE:
+      case V4L2_CID_GAMMA:
+      case V4L2_CID_EXPOSURE:
+      case V4L2_CID_AUTOGAIN:
+      case V4L2_CID_GAIN:
+      case V4L2_CID_SHARPNESS:
+        /* we only handle these for now (why?) */
+        break;
+      case V4L2_CID_HFLIP:
+      case V4L2_CID_VFLIP:
+      case V4L2_CID_PAN_RESET:
+      case V4L2_CID_TILT_RESET:
+        /* not handled here, handled by VideoOrientation interface */
+        control.id++;
+        break;
+      case V4L2_CID_AUDIO_VOLUME:
+      case V4L2_CID_AUDIO_BALANCE:
+      case V4L2_CID_AUDIO_BASS:
+      case V4L2_CID_AUDIO_TREBLE:
+      case V4L2_CID_AUDIO_MUTE:
+      case V4L2_CID_AUDIO_LOUDNESS:
+        /* FIXME: We should implement GstMixer interface instead */
+        /* but let's not be pedantic and make element more useful for now */
+        break;
+      case V4L2_CID_ALPHA_COMPONENT:
+        v4l2object->has_alpha_component = TRUE;
+        break;
+      default:
+        GST_DEBUG_OBJECT (e,
+            "ControlID %s (%x) unhandled, FIXME", control.name, n);
+        control.id++;
+        break;
+    }
+    if (n != control.id)
+      continue;
+
+    GST_DEBUG_OBJECT (e, "Adding ControlID %s (%x)", control.name, n);
+    v4l2channel = g_object_new (GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, NULL);
+    channel = GST_COLOR_BALANCE_CHANNEL (v4l2channel);
+    channel->label = g_strdup ((const gchar *) control.name);
+    v4l2channel->id = n;
+
+#if 0
+    /* FIXME: it will be need just when handling private controls
+     *(currently none of base controls are of this type) */
+    if (control.type == V4L2_CTRL_TYPE_MENU) {
+      struct v4l2_querymenu menu, *mptr;
+
+      int i;
+
+      menu.id = n;
+      for (i = 0;; i++) {
+        menu.index = i;
+        if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_QUERYMENU,
+                &menu) < 0) {
+          if (errno == EINVAL)
+            break;              /* end of enumeration */
+          else {
+            GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
+                (_("Failed getting controls attributes on device '%s'."),
+                    v4l2object->videodev),
+                ("Failed to get %d in menu enumeration for %s. (%d - %s)",
+                    n, v4l2object->videodev, errno, strerror (errno)));
+            return FALSE;
+          }
+        }
+        mptr = g_malloc (sizeof (menu));
+        memcpy (mptr, &menu, sizeof (menu));
+        menus = g_list_append (menus, mptr);
+      }
+    }
+    v4l2object->menus = g_list_append (v4l2object->menus, menus);
+#endif
+
+    switch (control.type) {
+      case V4L2_CTRL_TYPE_INTEGER:
+        channel->min_value = control.minimum;
+        channel->max_value = control.maximum;
+        break;
+      case V4L2_CTRL_TYPE_BOOLEAN:
+        channel->min_value = FALSE;
+        channel->max_value = TRUE;
+        break;
+      default:
+        /* FIXME we should find out how to handle V4L2_CTRL_TYPE_BUTTON.
+           BUTTON controls like V4L2_CID_DO_WHITE_BALANCE can just be set (1) or
+           unset (0), but can't be queried */
+        GST_DEBUG_OBJECT (e,
+            "Control with non supported type %s (%x), type=%d",
+            control.name, n, control.type);
+        channel->min_value = channel->max_value = 0;
+        break;
+    }
+
+    v4l2object->colors =
+        g_list_prepend (v4l2object->colors, (gpointer) channel);
+  }
+  v4l2object->colors = g_list_reverse (v4l2object->colors);
+
+  GST_DEBUG_OBJECT (e, "done");
+  return TRUE;
+}
+
+
+static void
+gst_v4l2_empty_lists (GstV4l2Object * v4l2object)
+{
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "deleting enumerations");
+
+  g_list_foreach (v4l2object->channels, (GFunc) g_object_unref, NULL);
+  g_list_free (v4l2object->channels);
+  v4l2object->channels = NULL;
+
+  g_list_foreach (v4l2object->norms, (GFunc) g_object_unref, NULL);
+  g_list_free (v4l2object->norms);
+  v4l2object->norms = NULL;
+
+  g_list_foreach (v4l2object->colors, (GFunc) g_object_unref, NULL);
+  g_list_free (v4l2object->colors);
+  v4l2object->colors = NULL;
+
+  g_datalist_clear (&v4l2object->controls);
+}
+
+static void
+gst_v4l2_adjust_buf_type (GstV4l2Object * v4l2object)
+{
+  /* when calling gst_v4l2_object_new the user decides the initial type
+   * so adjust it if multi-planar is supported
+   * the driver should make it exclusive. So the driver should
+   * not support both MPLANE and non-PLANE.
+   * Because even when using MPLANE it still possibles to use it
+   * in a contiguous manner. In this case the first v4l2 plane
+   * contains all the gst planes.
+   */
+  switch (v4l2object->type) {
+    case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+      if (v4l2object->device_caps &
+          (V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE)) {
+        GST_DEBUG ("adjust type to multi-planar output");
+        v4l2object->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+      }
+      break;
+    case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+      if (v4l2object->device_caps &
+          (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE)) {
+        GST_DEBUG ("adjust type to multi-planar capture");
+        v4l2object->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+      }
+      break;
+    default:
+      break;
+  }
+}
+
+/******************************************************
+ * gst_v4l2_open():
+ *   open the video device (v4l2object->videodev)
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2_open (GstV4l2Object * v4l2object)
+{
+  struct stat st;
+  int libv4l2_fd = -1;
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Trying to open device %s",
+      v4l2object->videodev);
+
+  GST_V4L2_CHECK_NOT_OPEN (v4l2object);
+  GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
+
+  /* be sure we have a device */
+  if (!v4l2object->videodev)
+    v4l2object->videodev = g_strdup ("/dev/video");
+
+  /* check if it is a device */
+  if (stat (v4l2object->videodev, &st) == -1)
+    goto stat_failed;
+
+  if (!S_ISCHR (st.st_mode))
+    goto no_device;
+
+  /* open the device */
+  v4l2object->video_fd =
+      open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ );
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    goto not_open;
+
+#ifdef HAVE_LIBV4L2
+  if (v4l2object->fd_open)
+    libv4l2_fd = v4l2object->fd_open (v4l2object->video_fd,
+        V4L2_ENABLE_ENUM_FMT_EMULATION);
+#endif
+
+  /* Note the v4l2_xxx functions are designed so that if they get passed an
+     unknown fd, the will behave exactly as their regular xxx counterparts, so
+     if v4l2_fd_open fails, we continue as normal (missing the libv4l2 custom
+     cam format to normal formats conversion). Chances are big we will still
+     fail then though, as normally v4l2_fd_open only fails if the device is not
+     a v4l2 device. */
+  if (libv4l2_fd != -1)
+    v4l2object->video_fd = libv4l2_fd;
+
+  /* get capabilities, error will be posted */
+  if (!gst_v4l2_get_capabilities (v4l2object))
+    goto error;
+
+  /* do we need to be a capture device? */
+  if (GST_IS_V4L2SRC (v4l2object->element) &&
+      !(v4l2object->device_caps & (V4L2_CAP_VIDEO_CAPTURE |
+              V4L2_CAP_VIDEO_CAPTURE_MPLANE)))
+    goto not_capture;
+
+  if (GST_IS_V4L2SINK (v4l2object->element) &&
+      !(v4l2object->device_caps & (V4L2_CAP_VIDEO_OUTPUT |
+              V4L2_CAP_VIDEO_OUTPUT_MPLANE)))
+    goto not_output;
+
+  if (GST_IS_V4L2_VIDEO_DEC (v4l2object->element) &&
+      /* Today's M2M device only expose M2M */
+      !((v4l2object->device_caps & (V4L2_CAP_VIDEO_M2M |
+                  V4L2_CAP_VIDEO_M2M_MPLANE)) ||
+          /* But legacy driver may expose both CAPTURE and OUTPUT */
+          ((v4l2object->device_caps &
+                  (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) &&
+              (v4l2object->device_caps &
+                  (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE)))))
+    goto not_m2m;
+
+  gst_v4l2_adjust_buf_type (v4l2object);
+
+  /* create enumerations, posts errors. */
+  if (!gst_v4l2_fill_lists (v4l2object))
+    goto error;
+
+  GST_INFO_OBJECT (v4l2object->dbg_obj,
+      "Opened device '%s' (%s) successfully",
+      v4l2object->vcap.card, v4l2object->videodev);
+
+  if (v4l2object->extra_controls)
+    gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
+
+  /* UVC devices are never interlaced, and doing VIDIOC_TRY_FMT on them
+   * causes expensive and slow USB IO, so don't probe them for interlaced
+   */
+  if (!strcmp ((char *) v4l2object->vcap.driver, "uvcusb") ||
+      !strcmp ((char *) v4l2object->vcap.driver, "uvcvideo")) {
+    v4l2object->never_interlaced = TRUE;
+  }
+
+  return TRUE;
+
+  /* ERRORS */
+stat_failed:
+  {
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
+        (_("Cannot identify device '%s'."), v4l2object->videodev),
+        GST_ERROR_SYSTEM);
+    goto error;
+  }
+no_device:
+  {
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
+        (_("This isn't a device '%s'."), v4l2object->videodev),
+        GST_ERROR_SYSTEM);
+    goto error;
+  }
+not_open:
+  {
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ_WRITE,
+        (_("Could not open device '%s' for reading and writing."),
+            v4l2object->videodev), GST_ERROR_SYSTEM);
+    goto error;
+  }
+not_capture:
+  {
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
+        (_("Device '%s' is not a capture device."),
+            v4l2object->videodev),
+        ("Capabilities: 0x%x", v4l2object->device_caps));
+    goto error;
+  }
+not_output:
+  {
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
+        (_("Device '%s' is not a output device."),
+            v4l2object->videodev),
+        ("Capabilities: 0x%x", v4l2object->device_caps));
+    goto error;
+  }
+not_m2m:
+  {
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
+        (_("Device '%s' is not a M2M device."),
+            v4l2object->videodev),
+        ("Capabilities: 0x%x", v4l2object->device_caps));
+    goto error;
+  }
+error:
+  {
+    if (GST_V4L2_IS_OPEN (v4l2object)) {
+      /* close device */
+      v4l2object->close (v4l2object->video_fd);
+      v4l2object->video_fd = -1;
+    }
+    /* empty lists */
+    gst_v4l2_empty_lists (v4l2object);
+
+    return FALSE;
+  }
+}
+
+gboolean
+gst_v4l2_dup (GstV4l2Object * v4l2object, GstV4l2Object * other)
+{
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Trying to dup device %s",
+      other->videodev);
+
+  GST_V4L2_CHECK_OPEN (other);
+  GST_V4L2_CHECK_NOT_OPEN (v4l2object);
+  GST_V4L2_CHECK_NOT_ACTIVE (other);
+  GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
+
+  v4l2object->vcap = other->vcap;
+  v4l2object->device_caps = other->device_caps;
+  gst_v4l2_adjust_buf_type (v4l2object);
+
+  v4l2object->video_fd = v4l2object->dup (other->video_fd);
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    goto not_open;
+
+  g_free (v4l2object->videodev);
+  v4l2object->videodev = g_strdup (other->videodev);
+
+  GST_INFO_OBJECT (v4l2object->dbg_obj,
+      "Cloned device '%s' (%s) successfully",
+      v4l2object->vcap.card, v4l2object->videodev);
+
+  v4l2object->never_interlaced = other->never_interlaced;
+
+  return TRUE;
+
+not_open:
+  {
+    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ_WRITE,
+        (_("Could not dup device '%s' for reading and writing."),
+            v4l2object->videodev), GST_ERROR_SYSTEM);
+
+    return FALSE;
+  }
+}
+
+
+/******************************************************
+ * gst_v4l2_close():
+ *   close the video device (v4l2object->video_fd)
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2_close (GstV4l2Object * v4l2object)
+{
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Trying to close %s",
+      v4l2object->videodev);
+
+  GST_V4L2_CHECK_OPEN (v4l2object);
+  GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
+
+  /* close device */
+  v4l2object->close (v4l2object->video_fd);
+  v4l2object->video_fd = -1;
+
+  /* empty lists */
+  gst_v4l2_empty_lists (v4l2object);
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2_get_norm()
+ *   Get the norm of the current device
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2_get_norm (GstV4l2Object * v4l2object, v4l2_std_id * norm)
+{
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "getting norm");
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_STD, norm) < 0)
+    goto std_failed;
+
+  return TRUE;
+
+  /* ERRORS */
+std_failed:
+  {
+    GST_DEBUG ("Failed to get the current norm for device %s",
+        v4l2object->videodev);
+    return FALSE;
+  }
+}
+
+
+/******************************************************
+ * gst_v4l2_set_norm()
+ *   Set the norm of the current device
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm)
+{
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "trying to set norm to "
+      "%" G_GINT64_MODIFIER "x", (guint64) norm);
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_STD, &norm) < 0)
+    goto std_failed;
+
+  return TRUE;
+
+  /* ERRORS */
+std_failed:
+  {
+    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Failed to set norm for device '%s'."),
+            v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+}
+
+/******************************************************
+ * gst_v4l2_get_frequency():
+ *   get the current frequency
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2_get_frequency (GstV4l2Object * v4l2object,
+    gint tunernum, gulong * frequency)
+{
+  struct v4l2_frequency freq = { 0, };
+
+  GstTunerChannel *channel;
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "getting current tuner frequency");
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element));
+
+  freq.tuner = tunernum;
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0)
+    goto freq_failed;
+
+  *frequency = freq.frequency * channel->freq_multiplicator;
+
+  return TRUE;
+
+  /* ERRORS */
+freq_failed:
+  {
+    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Failed to get current tuner frequency for device '%s'."),
+            v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+}
+
+
+/******************************************************
+ * gst_v4l2_set_frequency():
+ *   set frequency
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2_set_frequency (GstV4l2Object * v4l2object,
+    gint tunernum, gulong frequency)
+{
+  struct v4l2_frequency freq = { 0, };
+
+  GstTunerChannel *channel;
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj,
+      "setting current tuner frequency to %lu", frequency);
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element));
+
+  freq.tuner = tunernum;
+  /* fill in type - ignore error */
+  (void) v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq);
+  freq.frequency = frequency / channel->freq_multiplicator;
+
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0)
+    goto freq_failed;
+
+  return TRUE;
+
+  /* ERRORS */
+freq_failed:
+  {
+    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Failed to set current tuner frequency for device '%s' to %lu Hz."),
+            v4l2object->videodev, frequency), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+}
+
+/******************************************************
+ * gst_v4l2_signal_strength():
+ *   get the strength of the signal on the current input
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2_signal_strength (GstV4l2Object * v4l2object,
+    gint tunernum, gulong * signal_strength)
+{
+  struct v4l2_tuner tuner = { 0, };
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "trying to get signal strength");
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  tuner.index = tunernum;
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &tuner) < 0)
+    goto tuner_failed;
+
+  *signal_strength = tuner.signal;
+
+  return TRUE;
+
+  /* ERRORS */
+tuner_failed:
+  {
+    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Failed to get signal strength for device '%s'."),
+            v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+}
+
+/******************************************************
+ * gst_v4l2_get_attribute():
+ *   try to get the value of one specific attribute
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2_get_attribute (GstV4l2Object * v4l2object,
+    int attribute_num, int *value)
+{
+  struct v4l2_control control = { 0, };
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "getting value of attribute %d",
+      attribute_num);
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  control.id = attribute_num;
+
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
+    goto ctrl_failed;
+
+  *value = control.value;
+
+  return TRUE;
+
+  /* ERRORS */
+ctrl_failed:
+  {
+    GST_WARNING_OBJECT (v4l2object,
+        _("Failed to get value for control %d on device '%s'."),
+        attribute_num, v4l2object->videodev);
+    return FALSE;
+  }
+}
+
+
+/******************************************************
+ * gst_v4l2_set_attribute():
+ *   try to set the value of one specific attribute
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2_set_attribute (GstV4l2Object * v4l2object,
+    int attribute_num, const int value)
+{
+  struct v4l2_control control = { 0, };
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "setting value of attribute %d to %d",
+      attribute_num, value);
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  control.id = attribute_num;
+  control.value = value;
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0)
+    goto ctrl_failed;
+
+  return TRUE;
+
+  /* ERRORS */
+ctrl_failed:
+  {
+    GST_WARNING_OBJECT (v4l2object,
+        _("Failed to set value %d for control %d on device '%s'."),
+        value, attribute_num, v4l2object->videodev);
+    return FALSE;
+  }
+}
+
+static gboolean
+set_control (GQuark field_id, const GValue * value, gpointer user_data)
+{
+  GstV4l2Object *v4l2object = user_data;
+  GQuark normalised_field_id;
+  gpointer *d;
+
+  /* 32 bytes is the maximum size for a control name according to v4l2 */
+  gchar name[32];
+
+  /* Backwards compatibility: in the past GStreamer would normalise strings in
+     a subtly different way to v4l2-ctl.  e.g. the kernel's "Focus (absolute)"
+     would become "focus__absolute_" whereas now it becomes "focus_absolute".
+     Please remove the following in GStreamer 1.5 for 1.6 */
+  strncpy (name, g_quark_to_string (field_id), sizeof (name));
+  name[31] = '\0';
+  gst_v4l2_normalise_control_name (name);
+  normalised_field_id = g_quark_from_string (name);
+  if (normalised_field_id != field_id)
+    g_warning ("In GStreamer 1.4 the way V4L2 control names were normalised "
+        "changed.  Instead of setting \"%s\" please use \"%s\".  The former is "
+        "deprecated and will be removed in a future version of GStreamer",
+        g_quark_to_string (field_id), name);
+  field_id = normalised_field_id;
+
+  d = g_datalist_id_get_data (&v4l2object->controls, field_id);
+  if (!d) {
+    GST_WARNING_OBJECT (v4l2object,
+        "Control '%s' does not exist or has an unsupported type.",
+        g_quark_to_string (field_id));
+    return TRUE;
+  }
+  if (!G_VALUE_HOLDS (value, G_TYPE_INT)) {
+    GST_WARNING_OBJECT (v4l2object,
+        "'int' value expected for control '%s'.", g_quark_to_string (field_id));
+    return TRUE;
+  }
+  gst_v4l2_set_attribute (v4l2object, GPOINTER_TO_INT (d),
+      g_value_get_int (value));
+  return TRUE;
+}
+
+gboolean
+gst_v4l2_set_controls (GstV4l2Object * v4l2object, GstStructure * controls)
+{
+  return gst_structure_foreach (controls, set_control, v4l2object);
+}
+
+gboolean
+gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input)
+{
+  gint n;
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "trying to get input");
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_INPUT, &n) < 0)
+    goto input_failed;
+
+  *input = n;
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "input: %d", n);
+
+  return TRUE;
+
+  /* ERRORS */
+input_failed:
+  if (v4l2object->device_caps & V4L2_CAP_TUNER) {
+    /* only give a warning message if driver actually claims to have tuner
+     * support
+     */
+    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Failed to get current input on device '%s'. May be it is a radio device"), v4l2object->videodev), GST_ERROR_SYSTEM);
+  }
+  return FALSE;
+}
+
+gboolean
+gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input)
+{
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "trying to set input to %d", input);
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_INPUT, &input) < 0)
+    goto input_failed;
+
+  return TRUE;
+
+  /* ERRORS */
+input_failed:
+  if (v4l2object->device_caps & V4L2_CAP_TUNER) {
+    /* only give a warning message if driver actually claims to have tuner
+     * support
+     */
+    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Failed to set input %d on device %s."),
+            input, v4l2object->videodev), GST_ERROR_SYSTEM);
+  }
+  return FALSE;
+}
+
+gboolean
+gst_v4l2_get_output (GstV4l2Object * v4l2object, gint * output)
+{
+  gint n;
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "trying to get output");
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_OUTPUT, &n) < 0)
+    goto output_failed;
+
+  *output = n;
+
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "output: %d", n);
+
+  return TRUE;
+
+  /* ERRORS */
+output_failed:
+  if (v4l2object->device_caps & V4L2_CAP_TUNER) {
+    /* only give a warning message if driver actually claims to have tuner
+     * support
+     */
+    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Failed to get current output on device '%s'. May be it is a radio device"), v4l2object->videodev), GST_ERROR_SYSTEM);
+  }
+  return FALSE;
+}
+
+gboolean
+gst_v4l2_set_output (GstV4l2Object * v4l2object, gint output)
+{
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "trying to set output to %d", output);
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_OUTPUT, &output) < 0)
+    goto output_failed;
+
+  return TRUE;
+
+  /* ERRORS */
+output_failed:
+  if (v4l2object->device_caps & V4L2_CAP_TUNER) {
+    /* only give a warning message if driver actually claims to have tuner
+     * support
+     */
+    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Failed to set output %d on device %s."),
+            output, v4l2object->videodev), GST_ERROR_SYSTEM);
+  }
+  return FALSE;
+}
diff --git a/sys/waveform/Makefile.am b/sys/waveform/Makefile.am
new file mode 100644
index 0000000..7ab161c
--- /dev/null
+++ b/sys/waveform/Makefile.am
@@ -0,0 +1,15 @@
+plugin_LTLIBRARIES = libgstwaveform.la
+
+libgstwaveform_la_SOURCES =  gstwaveformsink.c gstwaveformplugin.c
+libgstwaveform_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
+        $(GST_PLUGINS_BASE_CFLAGS)
+libgstwaveform_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) \
+        -lgstaudio-$(GST_API_VERSION) \
+        $(GST_BASE_LIBS) \
+	$(GST_LIBS) \
+	-lwinmm
+libgstwaveform_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstwaveformsink.h
+
diff --git a/sys/waveform/gstwaveformplugin.c b/sys/waveform/gstwaveformplugin.c
new file mode 100644
index 0000000..d00c4c2
--- /dev/null
+++ b/sys/waveform/gstwaveformplugin.c
@@ -0,0 +1,42 @@
+/* GStreamer
+* Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
+*
+* gstwaveformplugin.c:
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Library General Public License for more details.
+*
+* You should have received a copy of the GNU Library General Public
+* License along with this library; if not, write to the
+* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+* Boston, MA 02110-1301, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstwaveformsink.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "waveformsink", GST_RANK_PRIMARY,
+          GST_TYPE_WAVEFORM_SINK))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    waveform,
+    "WaveForm win32 API plugin",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/sys/waveform/gstwaveformsink.c b/sys/waveform/gstwaveformsink.c
new file mode 100644
index 0000000..b670a5f
--- /dev/null
+++ b/sys/waveform/gstwaveformsink.c
@@ -0,0 +1,566 @@
+/* GStreamer
+* Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
+*
+* gstwaveformsink.c:
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Library General Public License for more details.
+*
+* You should have received a copy of the GNU Library General Public
+* License along with this library; if not, write to the
+* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+* Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * SECTION:element-waveformsink
+ *
+ * This element lets you output sound using the Windows WaveForm API.
+ *
+ * Note that you should almost always use generic audio conversion elements
+ * like audioconvert and audioresample in front of an audiosink to make sure
+ * your pipeline works under all circumstances (those conversion elements will
+ * act in passthrough-mode if no conversion is necessary).
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! audioconvert ! volume volume=0.1 ! waveformsink
+ * ]| will output a sine wave (continuous beep sound) to your sound card (with
+ * a very low volume as precaution).
+ * |[
+ * gst-launch-1.0 -v filesrc location=music.ogg ! decodebin ! audioconvert ! audioresample ! waveformsink
+ * ]| will play an Ogg/Vorbis audio file and output it.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstwaveformsink.h"
+
+GST_DEBUG_CATEGORY_STATIC (waveformsink_debug);
+
+static void gst_waveform_sink_finalise (GObject * object);
+static void gst_waveform_sink_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_waveform_sink_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+static GstCaps *gst_waveform_sink_getcaps (GstBaseSink * bsink,
+    GstCaps * filter);
+
+/************************************************************************/
+/* GstAudioSink functions                                               */
+/************************************************************************/
+static gboolean gst_waveform_sink_prepare (GstAudioSink * asink,
+    GstAudioRingBufferSpec * spec);
+static gboolean gst_waveform_sink_unprepare (GstAudioSink * asink);
+static gboolean gst_waveform_sink_open (GstAudioSink * asink);
+static gboolean gst_waveform_sink_close (GstAudioSink * asink);
+static gint gst_waveform_sink_write (GstAudioSink * asink, gpointer data,
+    guint length);
+static guint gst_waveform_sink_delay (GstAudioSink * asink);
+static void gst_waveform_sink_reset (GstAudioSink * asink);
+
+/************************************************************************/
+/* Utils                                                                */
+/************************************************************************/
+GstCaps *gst_waveform_sink_create_caps (gint rate, gint channels,
+    const gchar * format);
+WAVEHDR *bufferpool_get_buffer (GstWaveFormSink * wfsink, gpointer data,
+    guint length);
+void CALLBACK waveOutProc (HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
+    DWORD_PTR dwParam1, DWORD_PTR dwParam2);
+
+static GstStaticPadTemplate waveformsink_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) { " GST_AUDIO_NE (S16) ", S8 }, "
+        "layout = (string) interleaved, "
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]"));
+
+#define gst_waveform_sink_parent_class parent_class
+G_DEFINE_TYPE (GstWaveFormSink, gst_waveform_sink, GST_TYPE_AUDIO_SINK);
+
+static void
+gst_waveform_sink_class_init (GstWaveFormSinkClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstBaseSinkClass *gstbasesink_class;
+  GstAudioSinkClass *gstaudiosink_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstbasesink_class = (GstBaseSinkClass *) klass;
+  gstaudiosink_class = (GstAudioSinkClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gst_waveform_sink_finalise;
+  gobject_class->get_property = gst_waveform_sink_get_property;
+  gobject_class->set_property = gst_waveform_sink_set_property;
+
+  gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_waveform_sink_getcaps);
+
+  gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_waveform_sink_prepare);
+  gstaudiosink_class->unprepare =
+      GST_DEBUG_FUNCPTR (gst_waveform_sink_unprepare);
+  gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_waveform_sink_open);
+  gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_waveform_sink_close);
+  gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_waveform_sink_write);
+  gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_waveform_sink_delay);
+  gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_waveform_sink_reset);
+
+  GST_DEBUG_CATEGORY_INIT (waveformsink_debug, "waveformsink", 0,
+      "Waveform sink");
+
+  gst_element_class_set_static_metadata (element_class, "WaveForm Audio Sink",
+      "Sink/Audio",
+      "Output to a sound card via WaveForm API",
+      "Sebastien Moutte <sebastien@moutte.net>");
+
+  gst_element_class_add_static_pad_template (element_class,
+      &waveformsink_sink_factory);
+}
+
+static void
+gst_waveform_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  /* GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object); */
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_waveform_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  /* GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object); */
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_waveform_sink_init (GstWaveFormSink * wfsink)
+{
+  /* initialize members */
+  wfsink->hwaveout = NULL;
+  wfsink->cached_caps = NULL;
+  wfsink->wave_buffers = NULL;
+  wfsink->write_buffer = 0;
+  wfsink->buffer_count = BUFFER_COUNT;
+  wfsink->buffer_size = BUFFER_SIZE;
+  wfsink->free_buffers_count = wfsink->buffer_count;
+  wfsink->bytes_in_queue = 0;
+
+  InitializeCriticalSection (&wfsink->critic_wave);
+}
+
+static void
+gst_waveform_sink_finalise (GObject * object)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object);
+
+  if (wfsink->cached_caps) {
+    gst_caps_unref (wfsink->cached_caps);
+    wfsink->cached_caps = NULL;
+  }
+
+  DeleteCriticalSection (&wfsink->critic_wave);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstCaps *
+gst_waveform_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (bsink);
+  MMRESULT mmresult;
+  WAVEOUTCAPS wocaps;
+  GstCaps *caps, *caps_temp;
+
+  /* return the cached caps if already defined */
+  if (wfsink->cached_caps) {
+    return gst_caps_ref (wfsink->cached_caps);
+  }
+
+  /* get the default device caps */
+  mmresult = waveOutGetDevCaps (WAVE_MAPPER, &wocaps, sizeof (wocaps));
+  if (mmresult != MMSYSERR_NOERROR) {
+    waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
+    GST_ELEMENT_ERROR (wfsink, RESOURCE, SETTINGS,
+        ("gst_waveform_sink_getcaps: waveOutGetDevCaps failed error=>%s",
+            wfsink->error_string), (NULL));
+    return NULL;
+  }
+
+  caps = gst_caps_new_empty ();
+
+  /* create a caps for all wave formats supported by the device 
+     starting by the best quality format */
+  if (wocaps.dwFormats & WAVE_FORMAT_96S16) {
+    caps_temp = gst_waveform_sink_create_caps (96000, 2, GST_AUDIO_NE (S16));
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_96S08) {
+    caps_temp = gst_waveform_sink_create_caps (96000, 2, "S8");
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_96M16) {
+    caps_temp = gst_waveform_sink_create_caps (96000, 1, GST_AUDIO_NE (S16));
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_96M08) {
+    caps_temp = gst_waveform_sink_create_caps (96000, 1, "S8");
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_4S16) {
+    caps_temp = gst_waveform_sink_create_caps (44100, 2, GST_AUDIO_NE (S16));
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_4S08) {
+    caps_temp = gst_waveform_sink_create_caps (44100, 2, "S8");
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_4M16) {
+    caps_temp = gst_waveform_sink_create_caps (44100, 1, GST_AUDIO_NE (S16));
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_4M08) {
+    caps_temp = gst_waveform_sink_create_caps (44100, 1, "S8");
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_2S16) {
+    caps_temp = gst_waveform_sink_create_caps (22050, 2, GST_AUDIO_NE (S16));
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_2S08) {
+    caps_temp = gst_waveform_sink_create_caps (22050, 2, "S8");
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_2M16) {
+    caps_temp = gst_waveform_sink_create_caps (22050, 1, GST_AUDIO_NE (S16));
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_2M08) {
+    caps_temp = gst_waveform_sink_create_caps (22050, 1, "S8");
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_1S16) {
+    caps_temp = gst_waveform_sink_create_caps (11025, 2, GST_AUDIO_NE (S16));
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_1S08) {
+    caps_temp = gst_waveform_sink_create_caps (11025, 2, "S8");
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_1M16) {
+    caps_temp = gst_waveform_sink_create_caps (11025, 1, GST_AUDIO_NE (S16));
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+  if (wocaps.dwFormats & WAVE_FORMAT_1M08) {
+    caps_temp = gst_waveform_sink_create_caps (11025, 1, "S8");
+    if (caps_temp) {
+      gst_caps_append (caps, caps_temp);
+    }
+  }
+
+  if (gst_caps_is_empty (caps)) {
+    gst_caps_unref (caps);
+    caps = NULL;
+  } else {
+    wfsink->cached_caps = gst_caps_ref (caps);
+  }
+
+  GST_CAT_LOG_OBJECT (waveformsink_debug, wfsink,
+      "Returning caps %" GST_PTR_FORMAT, caps);
+
+  return caps;
+}
+
+static gboolean
+gst_waveform_sink_open (GstAudioSink * asink)
+{
+  /* GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink); */
+
+  /* nothing to do here as the device needs to be opened with the format we will use */
+
+  return TRUE;
+}
+
+static gboolean
+gst_waveform_sink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
+  WAVEFORMATEX wfx;
+  MMRESULT mmresult;
+  guint index;
+
+  /* setup waveformex struture with the input ringbuffer specs */
+  memset (&wfx, 0, sizeof (wfx));
+  wfx.cbSize = 0;
+  wfx.wFormatTag = WAVE_FORMAT_PCM;
+  wfx.nChannels = spec->info.channels;
+  wfx.nSamplesPerSec = spec->info.rate;
+  wfx.wBitsPerSample = (spec->info.bpf * 8) / wfx.nChannels;
+  wfx.nBlockAlign = spec->info.bpf;
+  wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+  /* save bytes per sample to use it in delay */
+  wfsink->bytes_per_sample = spec->info.bpf;
+
+  /* open the default audio device with the given caps */
+  mmresult = waveOutOpen (&wfsink->hwaveout, WAVE_MAPPER,
+      &wfx, (DWORD_PTR) waveOutProc, (DWORD_PTR) wfsink, CALLBACK_FUNCTION);
+  if (mmresult != MMSYSERR_NOERROR) {
+    waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
+    GST_ELEMENT_ERROR (wfsink, RESOURCE, OPEN_WRITE,
+        ("gst_waveform_sink_prepare: waveOutOpen failed error=>%s",
+            wfsink->error_string), (NULL));
+    return FALSE;
+  }
+
+  /* evaluate the buffer size and the number of buffers needed */
+  wfsink->free_buffers_count = wfsink->buffer_count;
+
+  /* allocate wave buffers */
+  wfsink->wave_buffers = (WAVEHDR *) g_new0 (WAVEHDR, wfsink->buffer_count);
+  if (!wfsink->wave_buffers) {
+    GST_ELEMENT_ERROR (wfsink, RESOURCE, OPEN_WRITE,
+        ("gst_waveform_sink_prepare: Failed to allocate wave buffer headers (buffer count=%d)",
+            wfsink->buffer_count), (NULL));
+    return FALSE;
+  }
+  memset (wfsink->wave_buffers, 0, sizeof (WAVEHDR) * wfsink->buffer_count);
+
+  /* setup headers */
+  for (index = 0; index < wfsink->buffer_count; index++) {
+    wfsink->wave_buffers[index].dwBufferLength = wfsink->buffer_size;
+    wfsink->wave_buffers[index].lpData = g_new0 (gchar, wfsink->buffer_size);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_waveform_sink_unprepare (GstAudioSink * asink)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
+
+  /* free wave buffers */
+  if (wfsink->wave_buffers) {
+    guint index;
+
+    for (index = 0; index < wfsink->buffer_count; index++) {
+      if (wfsink->wave_buffers[index].dwFlags & WHDR_PREPARED) {
+        MMRESULT mmresult = waveOutUnprepareHeader (wfsink->hwaveout,
+            &wfsink->wave_buffers[index], sizeof (WAVEHDR));
+        if (mmresult != MMSYSERR_NOERROR) {
+          waveOutGetErrorText (mmresult, wfsink->error_string,
+              ERROR_LENGTH - 1);
+          GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
+              "gst_waveform_sink_unprepare: Error unpreparing buffer => %s",
+              wfsink->error_string);
+        }
+      }
+      g_free (wfsink->wave_buffers[index].lpData);
+    }
+    g_free (wfsink->wave_buffers);
+    wfsink->wave_buffers = NULL;
+  }
+
+  /* close waveform-audio output device */
+  if (wfsink->hwaveout) {
+    waveOutClose (wfsink->hwaveout);
+    wfsink->hwaveout = NULL;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_waveform_sink_close (GstAudioSink * asink)
+{
+  /* GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink); */
+
+  return TRUE;
+}
+
+static gint
+gst_waveform_sink_write (GstAudioSink * asink, gpointer data, guint length)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
+  WAVEHDR *waveheader;
+  MMRESULT mmresult;
+  guint bytes_to_write = length;
+  guint remaining_length = length;
+
+  wfsink->bytes_in_queue += length;
+
+  while (remaining_length > 0) {
+    if (wfsink->free_buffers_count == 0) {
+      /* no free buffer available, wait for one */
+      Sleep (10);
+      continue;
+    }
+
+    /* get the current write buffer header */
+    waveheader = &wfsink->wave_buffers[wfsink->write_buffer];
+
+    /* unprepare the header if needed */
+    if (waveheader->dwFlags & WHDR_PREPARED) {
+      mmresult =
+          waveOutUnprepareHeader (wfsink->hwaveout, waveheader,
+          sizeof (WAVEHDR));
+      if (mmresult != MMSYSERR_NOERROR) {
+        waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
+        GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
+            "Error unpreparing buffer => %s", wfsink->error_string);
+      }
+    }
+
+    if (wfsink->buffer_size - waveheader->dwUser >= remaining_length)
+      bytes_to_write = remaining_length;
+    else
+      bytes_to_write = wfsink->buffer_size - waveheader->dwUser;
+
+    memcpy (waveheader->lpData + waveheader->dwUser, data, bytes_to_write);
+    waveheader->dwUser += bytes_to_write;
+    remaining_length -= bytes_to_write;
+    data = (guint8 *) data + bytes_to_write;
+
+    if (waveheader->dwUser == wfsink->buffer_size) {
+      /* we have filled a buffer, let's prepare it and next write it to the device */
+      mmresult =
+          waveOutPrepareHeader (wfsink->hwaveout, waveheader, sizeof (WAVEHDR));
+      if (mmresult != MMSYSERR_NOERROR) {
+        waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
+        GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
+            "gst_waveform_sink_write: Error preparing header => %s",
+            wfsink->error_string);
+      }
+      mmresult = waveOutWrite (wfsink->hwaveout, waveheader, sizeof (WAVEHDR));
+      if (mmresult != MMSYSERR_NOERROR) {
+        waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
+        GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
+            "gst_waveform_sink_write: Error writting buffer to the device => %s",
+            wfsink->error_string);
+      }
+
+      EnterCriticalSection (&wfsink->critic_wave);
+      wfsink->free_buffers_count--;
+      LeaveCriticalSection (&wfsink->critic_wave);
+
+      wfsink->write_buffer++;
+      wfsink->write_buffer %= wfsink->buffer_count;
+      waveheader->dwUser = 0;
+      wfsink->bytes_in_queue = 0;
+      GST_CAT_LOG_OBJECT (waveformsink_debug, wfsink,
+          "gst_waveform_sink_write: Writting a buffer to the device (free buffers remaining=%d, write buffer=%d)",
+          wfsink->free_buffers_count, wfsink->write_buffer);
+    }
+  }
+
+  return length;
+}
+
+static guint
+gst_waveform_sink_delay (GstAudioSink * asink)
+{
+  /* return the number of samples in queue (device+internal queue) */
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
+  guint bytes_in_device =
+      (wfsink->buffer_count - wfsink->free_buffers_count) * wfsink->buffer_size;
+  guint delay =
+      (bytes_in_device + wfsink->bytes_in_queue) / wfsink->bytes_per_sample;
+  return delay;
+}
+
+static void
+gst_waveform_sink_reset (GstAudioSink * asink)
+{
+  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
+  MMRESULT mmresult = waveOutReset (wfsink->hwaveout);
+
+  if (mmresult != MMSYSERR_NOERROR) {
+    waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
+    GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
+        "gst_waveform_sink_reset: Error reseting waveform-audio device => %s",
+        wfsink->error_string);
+  }
+}
+
+GstCaps *
+gst_waveform_sink_create_caps (gint rate, gint channels, const gchar * format)
+{
+  GstCaps *caps = NULL;
+
+  caps = gst_caps_new_simple ("audio/x-raw",
+      "format", G_TYPE_STRING, format,
+      "layout", G_TYPE_STRING, "interleaved",
+      "channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, rate, NULL);
+  return caps;
+}
+
+void CALLBACK
+waveOutProc (HWAVEOUT hwo,
+    UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
+{
+  GstWaveFormSink *wfsink = (GstWaveFormSink *) dwInstance;
+
+  if (uMsg == WOM_DONE) {
+    EnterCriticalSection (&wfsink->critic_wave);
+    wfsink->free_buffers_count++;
+    LeaveCriticalSection (&wfsink->critic_wave);
+  }
+}
diff --git a/sys/waveform/gstwaveformsink.h b/sys/waveform/gstwaveformsink.h
new file mode 100644
index 0000000..340dfc3
--- /dev/null
+++ b/sys/waveform/gstwaveformsink.h
@@ -0,0 +1,108 @@
+/* GStreamer
+ * Copyright (C)  2005 Sebastien Moutte <sebastien@moutte.net>
+ *
+ * gstwaveformsink.h: 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_WAVEFORMSINK_H__
+#define __GST_WAVEFORMSINK_H__
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiosink.h>
+
+#include <windows.h>
+#include <mmsystem.h>
+
+#ifndef WAVE_FORMAT_96M08
+#define WAVE_FORMAT_96M08       0x00001000       /* 96   kHz, Mono,   8-bit  */
+#endif
+
+#ifndef WAVE_FORMAT_96S08
+#define WAVE_FORMAT_96S08       0x00002000       /* 96   kHz, Stereo, 8-bit  */
+#endif
+
+#ifndef WAVE_FORMAT_96M16
+#define WAVE_FORMAT_96M16       0x00004000       /* 96   kHz, Mono,   16-bit */
+#endif
+
+#ifndef WAVE_FORMAT_96S16
+#define WAVE_FORMAT_96S16       0x00008000       /* 96   kHz, Stereo, 16-bit */
+#endif
+
+#define ERROR_LENGTH MAXERRORLENGTH+50
+#define BUFFER_COUNT 20
+#define BUFFER_SIZE 8192
+
+G_BEGIN_DECLS
+#define GST_TYPE_WAVEFORM_SINK                (gst_waveform_sink_get_type())
+#define GST_WAVEFORM_SINK(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAVEFORM_SINK,GstWaveFormSink))
+#define GST_WAVEFORM_SINK_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVEFORM_SINK,GstWaveFormSinkClass))
+#define GST_IS_WAVEFORM_SINK(obj)             (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAVEFORM_SINK))
+#define GST_IS_WAVEFORM_SINK_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVEFORM_SINK))
+typedef struct _GstWaveFormSink GstWaveFormSink;
+typedef struct _GstWaveFormSinkClass GstWaveFormSinkClass;
+
+struct _GstWaveFormSink
+{
+  /* parent object */
+  GstAudioSink sink;
+
+  /* supported caps */
+  GstCaps *cached_caps;
+  
+  /* handle to the waveform-audio output device */
+  HWAVEOUT hwaveout;
+  
+  /* table of buffer headers */
+  WAVEHDR *wave_buffers;
+
+  /* critical section protecting access to the number of free buffers */
+  CRITICAL_SECTION critic_wave;
+
+  /* number of free buffers available */
+  guint free_buffers_count;
+  
+  /* current free buffer where you have to write incoming data */
+  guint write_buffer;
+  
+  /* size of buffers streamed to the device */
+  guint buffer_size;
+
+  /* number of buffers streamed to the device */
+  guint buffer_count;
+
+  /* total of bytes in queue before they are written to the device */
+  guint bytes_in_queue;
+
+  /* bytes per sample from setcaps used to evaluate the number samples returned by delay */
+  guint bytes_per_sample;
+
+  /* wave form error string */
+  gchar error_string[ERROR_LENGTH];
+};
+
+struct _GstWaveFormSinkClass
+{
+  GstAudioSinkClass parent_class;
+};
+
+GType gst_waveform_sink_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_WAVEFORMSINK_H__ */
diff --git a/sys/ximage/Makefile.am b/sys/ximage/Makefile.am
new file mode 100644
index 0000000..646b35e
--- /dev/null
+++ b/sys/ximage/Makefile.am
@@ -0,0 +1,15 @@
+plugin_LTLIBRARIES = libgstximagesrc.la
+
+libgstximagesrc_la_SOURCES = gstximagesrc.c ximageutil.c
+libgstximagesrc_la_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) \
+	$(GST_CFLAGS) \
+	$(X_CFLAGS) $(XFIXES_CFLAGS) $(XDAMAGE_CFLAGS)
+libgstximagesrc_la_LIBADD = \
+	$(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) \
+	$(X_LIBS) $(XSHM_LIBS) $(XFIXES_LIBS) $(XDAMAGE_LIBS) 
+libgstximagesrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstximagesrc.h ximageutil.h
diff --git a/sys/ximage/gstximagesrc.c b/sys/ximage/gstximagesrc.c
new file mode 100644
index 0000000..8aad4e2
--- /dev/null
+++ b/sys/ximage/gstximagesrc.c
@@ -0,0 +1,1336 @@
+/* GStreamer
+ *
+ * Copyright (C) 2006 Zaheer Merali <zaheerabbas at merali dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-ximagesrc
+ *
+ * This element captures your X Display and creates raw RGB video.  It uses
+ * the XDamage extension if available to only capture areas of the screen that
+ * have changed since the last frame.  It uses the XFixes extension if
+ * available to also capture your mouse pointer.  By default it will fixate to
+ * 25 frames per second.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch-1.0 ximagesrc ! video/x-raw,framerate=5/1 ! videoconvert ! theoraenc ! oggmux ! filesink location=desktop.ogg
+ * ]| Encodes your X display to an Ogg theora video at 5 frames per second.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "gstximagesrc.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <gst/gst.h>
+#include <gst/gst-i18n-plugin.h>
+#include <gst/video/video.h>
+
+#include "gst/glib-compat-private.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_debug_ximage_src);
+#define GST_CAT_DEFAULT gst_debug_ximage_src
+
+static GstStaticPadTemplate t =
+GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-raw, "
+        "framerate = (fraction) [ 0, MAX ], "
+        "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ], "
+        "pixel-aspect-ratio = (fraction) [ 0, MAX ]"));
+
+enum
+{
+  PROP_0,
+  PROP_DISPLAY_NAME,
+  PROP_SHOW_POINTER,
+  PROP_USE_DAMAGE,
+  PROP_STARTX,
+  PROP_STARTY,
+  PROP_ENDX,
+  PROP_ENDY,
+  PROP_REMOTE,
+  PROP_XID,
+  PROP_XNAME,
+};
+
+#define gst_ximage_src_parent_class parent_class
+G_DEFINE_TYPE (GstXImageSrc, gst_ximage_src, GST_TYPE_PUSH_SRC);
+
+static GstCaps *gst_ximage_src_fixate (GstBaseSrc * bsrc, GstCaps * caps);
+static void gst_ximage_src_clear_bufpool (GstXImageSrc * ximagesrc);
+
+/* Called when a buffer is returned from the pipeline */
+static gboolean
+gst_ximage_src_return_buf (GstXImageSrc * ximagesrc, GstBuffer * ximage)
+{
+  GstMetaXImage *meta = GST_META_XIMAGE_GET (ximage);
+  /* True will make dispose free the buffer, while false will keep it */
+  gboolean ret = TRUE;
+
+  /* If our geometry changed we can't reuse that image. */
+  if ((meta->width != ximagesrc->width) || (meta->height != ximagesrc->height)) {
+    GST_DEBUG_OBJECT (ximagesrc,
+        "destroy image %p as its size changed %dx%d vs current %dx%d",
+        ximage, meta->width, meta->height, ximagesrc->width, ximagesrc->height);
+    g_mutex_lock (&ximagesrc->x_lock);
+    gst_ximageutil_ximage_destroy (ximagesrc->xcontext, ximage);
+    g_mutex_unlock (&ximagesrc->x_lock);
+  } else {
+    /* In that case we can reuse the image and add it to our image pool. */
+    GST_LOG_OBJECT (ximagesrc, "recycling image %p in pool", ximage);
+    /* need to increment the refcount again to recycle */
+    gst_buffer_ref (ximage);
+    g_mutex_lock (&ximagesrc->pool_lock);
+    GST_BUFFER_FLAGS (GST_BUFFER (ximage)) = 0; /* clear out any flags from the previous use */
+    ximagesrc->buffer_pool = g_slist_prepend (ximagesrc->buffer_pool, ximage);
+    g_mutex_unlock (&ximagesrc->pool_lock);
+    ret = FALSE;
+  }
+
+  return ret;
+}
+
+static Window
+gst_ximage_src_find_window (GstXImageSrc * src, Window root, const char *name)
+{
+  Window *children;
+  Window window = 0, root_return, parent_return;
+  unsigned int nchildren;
+  char *tmpname;
+  int n, status;
+
+  status = XFetchName (src->xcontext->disp, root, &tmpname);
+  if (status && !strcmp (name, tmpname))
+    return root;
+
+  status =
+      XQueryTree (src->xcontext->disp, root, &root_return, &parent_return,
+      &children, &nchildren);
+  if (!status || !children)
+    return (Window) 0;
+
+  for (n = 0; n < nchildren; ++n) {
+    window = gst_ximage_src_find_window (src, children[n], name);
+    if (window != 0)
+      break;
+  }
+
+  XFree (children);
+  return window;
+}
+
+static gboolean
+gst_ximage_src_open_display (GstXImageSrc * s, const gchar * name)
+{
+  g_return_val_if_fail (GST_IS_XIMAGE_SRC (s), FALSE);
+
+  if (s->xcontext != NULL)
+    return TRUE;
+
+  g_mutex_lock (&s->x_lock);
+  s->xcontext = ximageutil_xcontext_get (GST_ELEMENT (s), name);
+  if (s->xcontext == NULL) {
+    g_mutex_unlock (&s->x_lock);
+    GST_ELEMENT_ERROR (s, RESOURCE, OPEN_READ,
+        ("Could not open X display for reading"),
+        ("NULL returned from getting xcontext"));
+    return FALSE;
+  }
+  s->width = s->xcontext->width;
+  s->height = s->xcontext->height;
+
+  s->xwindow = s->xcontext->root;
+  if (s->xid != 0 || s->xname) {
+    int status;
+    XWindowAttributes attrs;
+    Window window;
+    int x, y;
+    Window child;
+    Bool coord_translated;
+
+    if (s->xid != 0) {
+      status = XGetWindowAttributes (s->xcontext->disp, s->xid, &attrs);
+      if (status) {
+        GST_DEBUG_OBJECT (s, "Found window XID %" G_GUINT64_FORMAT, s->xid);
+        s->xwindow = s->xid;
+        goto window_found;
+      } else {
+        GST_WARNING_OBJECT (s, "Failed to get window %" G_GUINT64_FORMAT
+            " attributes", s->xid);
+      }
+    }
+
+    if (s->xname) {
+      GST_DEBUG_OBJECT (s, "Looking for window %s", s->xname);
+      window = gst_ximage_src_find_window (s, s->xcontext->root, s->xname);
+      if (window != 0) {
+        GST_DEBUG_OBJECT (s, "Found window named %s, ", s->xname);
+        status = XGetWindowAttributes (s->xcontext->disp, window, &attrs);
+        if (status) {
+          s->xwindow = window;
+          goto window_found;
+        } else {
+          GST_WARNING_OBJECT (s, "Failed to get window attributes for "
+              "window named %s", s->xname);
+        }
+      }
+    }
+
+    GST_INFO_OBJECT (s, "Using root window");
+    goto use_root_window;
+
+  window_found:
+    g_assert (s->xwindow != 0);
+    s->width = attrs.width;
+    s->height = attrs.height;
+
+    coord_translated = XTranslateCoordinates (s->xcontext->disp, s->xwindow,
+        s->xcontext->root, 0, 0, &x, &y, &child);
+    if (coord_translated) {
+      s->x = x;
+      s->y = y;
+    } else {
+      s->x = 0;
+      s->y = 0;
+    }
+
+    GST_INFO_OBJECT (s, "Using default window size of %dx%d at location %d,%d",
+        s->width, s->height, s->x, s->y);
+  }
+use_root_window:
+
+#ifdef HAVE_XFIXES
+  /* check if xfixes supported */
+  {
+    int error_base;
+
+    if (XFixesQueryExtension (s->xcontext->disp, &s->fixes_event_base,
+            &error_base)) {
+      s->have_xfixes = TRUE;
+      GST_DEBUG_OBJECT (s, "X Server supports XFixes");
+    } else {
+
+      GST_DEBUG_OBJECT (s, "X Server does not support XFixes");
+    }
+  }
+
+#ifdef HAVE_XDAMAGE
+  /* check if xdamage is supported */
+  {
+    int error_base;
+    long evmask = NoEventMask;
+
+    s->have_xdamage = FALSE;
+    s->damage = None;
+    s->damage_copy_gc = None;
+    s->damage_region = None;
+
+    if (XDamageQueryExtension (s->xcontext->disp, &s->damage_event_base,
+            &error_base)) {
+      s->damage =
+          XDamageCreate (s->xcontext->disp, s->xwindow, XDamageReportNonEmpty);
+      if (s->damage != None) {
+        s->damage_region = XFixesCreateRegion (s->xcontext->disp, NULL, 0);
+        if (s->damage_region != None) {
+          XGCValues values;
+
+          GST_DEBUG_OBJECT (s, "Using XDamage extension");
+          values.subwindow_mode = IncludeInferiors;
+          s->damage_copy_gc = XCreateGC (s->xcontext->disp,
+              s->xwindow, GCSubwindowMode, &values);
+          XSelectInput (s->xcontext->disp, s->xwindow, evmask);
+
+          s->have_xdamage = TRUE;
+        } else {
+          XDamageDestroy (s->xcontext->disp, s->damage);
+          s->damage = None;
+        }
+      } else
+        GST_DEBUG_OBJECT (s, "Could not attach to XDamage");
+    } else {
+      GST_DEBUG_OBJECT (s, "X Server does not have XDamage extension");
+    }
+  }
+#endif
+#endif
+
+  g_mutex_unlock (&s->x_lock);
+
+  if (s->xcontext == NULL)
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+gst_ximage_src_start (GstBaseSrc * basesrc)
+{
+  GstXImageSrc *s = GST_XIMAGE_SRC (basesrc);
+
+  s->last_frame_no = -1;
+#ifdef HAVE_XDAMAGE
+  if (s->last_ximage)
+    gst_buffer_unref (GST_BUFFER_CAST (s->last_ximage));
+  s->last_ximage = NULL;
+#endif
+  return gst_ximage_src_open_display (s, s->display_name);
+}
+
+static gboolean
+gst_ximage_src_stop (GstBaseSrc * basesrc)
+{
+  GstXImageSrc *src = GST_XIMAGE_SRC (basesrc);
+
+#ifdef HAVE_XDAMAGE
+  if (src->last_ximage)
+    gst_buffer_unref (GST_BUFFER_CAST (src->last_ximage));
+  src->last_ximage = NULL;
+#endif
+
+  gst_ximage_src_clear_bufpool (src);
+
+#ifdef HAVE_XFIXES
+  if (src->cursor_image)
+    XFree (src->cursor_image);
+  src->cursor_image = NULL;
+#endif
+
+  if (src->xcontext) {
+    g_mutex_lock (&src->x_lock);
+
+#ifdef HAVE_XDAMAGE
+    if (src->damage_copy_gc != None) {
+      XFreeGC (src->xcontext->disp, src->damage_copy_gc);
+      src->damage_copy_gc = None;
+    }
+    if (src->damage_region != None) {
+      XFixesDestroyRegion (src->xcontext->disp, src->damage_region);
+      src->damage_region = None;
+    }
+    if (src->damage != None) {
+      XDamageDestroy (src->xcontext->disp, src->damage);
+      src->damage = None;
+    }
+#endif
+
+    ximageutil_xcontext_clear (src->xcontext);
+    src->xcontext = NULL;
+    g_mutex_unlock (&src->x_lock);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_ximage_src_unlock (GstBaseSrc * basesrc)
+{
+  GstXImageSrc *src = GST_XIMAGE_SRC (basesrc);
+
+  /* Awaken the create() func if it's waiting on the clock */
+  GST_OBJECT_LOCK (src);
+  if (src->clock_id) {
+    GST_DEBUG_OBJECT (src, "Waking up waiting clock");
+    gst_clock_id_unschedule (src->clock_id);
+  }
+  GST_OBJECT_UNLOCK (src);
+
+  return TRUE;
+}
+
+static gboolean
+gst_ximage_src_recalc (GstXImageSrc * src)
+{
+  if (!src->xcontext)
+    return FALSE;
+
+  /* Maybe later we can check the display hasn't changed size */
+  /* We could use XQueryPointer to get only the current window. */
+  return TRUE;
+}
+
+#ifdef HAVE_XFIXES
+static gboolean
+gst_ximage_is_pointer_in_region (GstXImageSrc * src)
+{
+  Window window_returned;
+  int root_x, root_y;
+  int win_x, win_y;
+  unsigned int mask_return;
+  Bool on_window;
+
+  on_window = XQueryPointer (src->xcontext->disp, src->xwindow,
+      &window_returned, &window_returned, &root_x, &root_y, &win_x, &win_y,
+      &mask_return);
+
+  return (on_window && (win_x >= src->startx) && (win_y >= src->starty) &&
+      (win_x < src->endx) && (win_y < src->endy));
+}
+#endif
+
+#ifdef HAVE_XFIXES
+static void
+composite_pixel (GstXContext * xcontext, guchar * dest, guchar * src)
+{
+  guint8 r = src[2];
+  guint8 g = src[1];
+  guint8 b = src[0];
+  guint8 a = src[3];
+  guint8 dr, dg, db;
+  guint32 color;
+  gint r_shift, r_max, r_shift_out;
+  gint g_shift, g_max, g_shift_out;
+  gint b_shift, b_max, b_shift_out;
+
+  switch (xcontext->bpp) {
+    case 8:
+      color = *dest;
+      break;
+    case 16:
+      color = GUINT16_FROM_LE (*(guint16 *) (dest));
+      break;
+    case 32:
+      color = GUINT32_FROM_LE (*(guint32 *) (dest));
+      break;
+    default:
+      /* Should not reach here */
+      g_return_if_reached ();
+  }
+
+  /* possible optimisation:
+   * move the code that finds shift and max in the _link function */
+  for (r_shift = 0; !(xcontext->visual->red_mask & (1 << r_shift)); r_shift++);
+  for (g_shift = 0; !(xcontext->visual->green_mask & (1 << g_shift));
+      g_shift++);
+  for (b_shift = 0; !(xcontext->visual->blue_mask & (1 << b_shift)); b_shift++);
+
+  for (r_shift_out = 0; !(xcontext->visual->red_mask & (1 << r_shift_out));
+      r_shift_out++);
+  for (g_shift_out = 0; !(xcontext->visual->green_mask & (1 << g_shift_out));
+      g_shift_out++);
+  for (b_shift_out = 0; !(xcontext->visual->blue_mask & (1 << b_shift_out));
+      b_shift_out++);
+
+
+  r_max = (xcontext->visual->red_mask >> r_shift);
+  b_max = (xcontext->visual->blue_mask >> b_shift);
+  g_max = (xcontext->visual->green_mask >> g_shift);
+
+#define RGBXXX_R(x)  (((x)>>r_shift) & (r_max))
+#define RGBXXX_G(x)  (((x)>>g_shift) & (g_max))
+#define RGBXXX_B(x)  (((x)>>b_shift) & (b_max))
+
+  dr = (RGBXXX_R (color) * 255) / r_max;
+  dg = (RGBXXX_G (color) * 255) / g_max;
+  db = (RGBXXX_B (color) * 255) / b_max;
+
+  dr = (r * a + (0xff - a) * dr) / 0xff;
+  dg = (g * a + (0xff - a) * dg) / 0xff;
+  db = (b * a + (0xff - a) * db) / 0xff;
+
+  color = (((dr * r_max) / 255) << r_shift_out) +
+      (((dg * g_max) / 255) << g_shift_out) +
+      (((db * b_max) / 255) << b_shift_out);
+
+  switch (xcontext->bpp) {
+    case 8:
+      *dest = color;
+      break;
+    case 16:
+      *(guint16 *) (dest) = color;
+      break;
+    case 32:
+      *(guint32 *) (dest) = color;
+      break;
+    default:
+      g_warning ("bpp %d not supported\n", xcontext->bpp);
+  }
+}
+#endif
+
+#ifdef HAVE_XDAMAGE
+static void
+copy_buffer (GstBuffer * dest, GstBuffer * src)
+{
+  GstMapInfo map;
+
+  gst_buffer_map (src, &map, GST_MAP_READ);
+  gst_buffer_fill (dest, 0, map.data, map.size);
+  gst_buffer_unmap (src, &map);
+}
+#endif
+
+/* Retrieve an XImageSrcBuffer, preferably from our
+ * pool of existing images and populate it from the window */
+static GstBuffer *
+gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc)
+{
+  GstBuffer *ximage = NULL;
+  GstMetaXImage *meta;
+
+  g_mutex_lock (&ximagesrc->pool_lock);
+  while (ximagesrc->buffer_pool != NULL) {
+    ximage = ximagesrc->buffer_pool->data;
+
+    meta = GST_META_XIMAGE_GET (ximage);
+
+    ximagesrc->buffer_pool = g_slist_delete_link (ximagesrc->buffer_pool,
+        ximagesrc->buffer_pool);
+
+    if ((meta->width == ximagesrc->width) ||
+        (meta->height == ximagesrc->height))
+      break;
+
+    gst_ximage_buffer_free (ximage);
+    ximage = NULL;
+  }
+  g_mutex_unlock (&ximagesrc->pool_lock);
+
+  if (ximage == NULL) {
+    GST_DEBUG_OBJECT (ximagesrc, "creating image (%dx%d)",
+        ximagesrc->width, ximagesrc->height);
+
+    g_mutex_lock (&ximagesrc->x_lock);
+    ximage = gst_ximageutil_ximage_new (ximagesrc->xcontext,
+        GST_ELEMENT (ximagesrc), ximagesrc->width, ximagesrc->height,
+        (BufferReturnFunc) (gst_ximage_src_return_buf));
+    if (ximage == NULL) {
+      GST_ELEMENT_ERROR (ximagesrc, RESOURCE, WRITE, (NULL),
+          ("could not create a %dx%d ximage", ximagesrc->width,
+              ximagesrc->height));
+      g_mutex_unlock (&ximagesrc->x_lock);
+      return NULL;
+    }
+
+    g_mutex_unlock (&ximagesrc->x_lock);
+  }
+
+  g_return_val_if_fail (GST_IS_XIMAGE_SRC (ximagesrc), NULL);
+
+  meta = GST_META_XIMAGE_GET (ximage);
+
+#ifdef HAVE_XDAMAGE
+  if (ximagesrc->have_xdamage && ximagesrc->use_damage &&
+      ximagesrc->last_ximage != NULL) {
+    XEvent ev;
+    gboolean have_damage = FALSE;
+
+    /* have_frame is TRUE when either the entire screen has been
+     * grabbed or when the last image has been copied */
+    gboolean have_frame = FALSE;
+
+    GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XDamage");
+
+    do {
+      XDamageNotifyEvent *damage_ev = (XDamageNotifyEvent *) (&ev);
+
+      XNextEvent (ximagesrc->xcontext->disp, &ev);
+
+      if (ev.type == ximagesrc->damage_event_base + XDamageNotify &&
+          damage_ev->level == XDamageReportNonEmpty) {
+
+        XDamageSubtract (ximagesrc->xcontext->disp, ximagesrc->damage, None,
+            ximagesrc->damage_region);
+        have_damage = TRUE;
+      }
+    } while (XPending (ximagesrc->xcontext->disp));
+
+    if (have_damage) {
+      XRectangle *rects;
+      int nrects;
+
+      /* Now copy out all of the damaged rectangles. */
+      rects =
+          XFixesFetchRegion (ximagesrc->xcontext->disp,
+          ximagesrc->damage_region, &nrects);
+      if (rects != NULL) {
+        int i;
+
+        if (!have_frame) {
+          GST_LOG_OBJECT (ximagesrc,
+              "Copying from last frame ximage->size: %" G_GSIZE_FORMAT,
+              gst_buffer_get_size (ximage));
+          copy_buffer (ximage, ximagesrc->last_ximage);
+          have_frame = TRUE;
+        }
+        for (i = 0; i < nrects; i++) {
+          GST_LOG_OBJECT (ximagesrc,
+              "Damaged sub-region @ %d,%d size %dx%d reported",
+              rects[i].x, rects[i].y, rects[i].width, rects[i].height);
+
+          /* if we only want a small area, clip this damage region to
+           * area we want */
+          if (ximagesrc->endx > ximagesrc->startx &&
+              ximagesrc->endy > ximagesrc->starty) {
+            /* see if damage area intersects */
+            if (rects[i].x + rects[i].width - 1 < ximagesrc->startx ||
+                rects[i].x > ximagesrc->endx) {
+              /* trivial reject */
+            } else if (rects[i].y + rects[i].height - 1 < ximagesrc->starty ||
+                rects[i].y > ximagesrc->endy) {
+              /* trivial reject */
+            } else {
+              /* find intersect region */
+              int startx, starty, width, height;
+
+              startx = (rects[i].x < ximagesrc->startx) ? ximagesrc->startx :
+                  rects[i].x;
+              starty = (rects[i].y < ximagesrc->starty) ? ximagesrc->starty :
+                  rects[i].y;
+              width = (rects[i].x + rects[i].width - 1 < ximagesrc->endx) ?
+                  rects[i].x + rects[i].width - startx :
+                  ximagesrc->endx - startx + 1;
+              height = (rects[i].y + rects[i].height - 1 < ximagesrc->endy) ?
+                  rects[i].y + rects[i].height - starty : ximagesrc->endy -
+                  starty + 1;
+
+              GST_LOG_OBJECT (ximagesrc,
+                  "Retrieving damaged sub-region @ %d,%d size %dx%d as intersect region",
+                  startx, starty, width, height);
+              XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
+                  startx, starty, width, height, AllPlanes, ZPixmap,
+                  meta->ximage, startx - ximagesrc->startx,
+                  starty - ximagesrc->starty);
+            }
+          } else {
+
+            GST_LOG_OBJECT (ximagesrc,
+                "Retrieving damaged sub-region @ %d,%d size %dx%d",
+                rects[i].x, rects[i].y, rects[i].width, rects[i].height);
+
+            XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
+                rects[i].x, rects[i].y,
+                rects[i].width, rects[i].height,
+                AllPlanes, ZPixmap, meta->ximage, rects[i].x, rects[i].y);
+          }
+        }
+        XFree (rects);
+      }
+    }
+    if (!have_frame) {
+      GST_LOG_OBJECT (ximagesrc,
+          "Copying from last frame ximage->size: %" G_GSIZE_FORMAT,
+          gst_buffer_get_size (ximage));
+      copy_buffer (ximage, ximagesrc->last_ximage);
+    }
+#ifdef HAVE_XFIXES
+    /* re-get area where last mouse pointer was  but only if in our clipping
+     * bounds */
+    if (ximagesrc->cursor_image) {
+      gint x, y, width, height;
+
+      x = ximagesrc->cursor_image->x - ximagesrc->cursor_image->xhot -
+          ximagesrc->x;
+      y = ximagesrc->cursor_image->y - ximagesrc->cursor_image->yhot -
+          ximagesrc->y;
+      width = ximagesrc->cursor_image->width;
+      height = ximagesrc->cursor_image->height;
+
+      /* bounds checking */
+      if (x < 0)
+        x = 0;
+      if (y < 0)
+        y = 0;
+      if (x + width > ximagesrc->xcontext->width)
+        width = ximagesrc->xcontext->width - x;
+      if (y + height > ximagesrc->xcontext->height)
+        height = ximagesrc->xcontext->height - y;
+      g_assert (x >= 0);
+      g_assert (y >= 0);
+      GST_DEBUG_OBJECT (ximagesrc,
+          "Cursor was at (%d,%d) width: %d, height: %d and our range is: (%d,%d) - (%d,%d)",
+          x, y, width, height, ximagesrc->startx, ximagesrc->starty,
+          ximagesrc->endx, ximagesrc->endy);
+      /* only get where cursor last was, if it is in our range */
+      if (ximagesrc->endx > ximagesrc->startx &&
+          ximagesrc->endy > ximagesrc->starty) {
+        /* check bounds */
+        if (x + width < ximagesrc->startx || x > ximagesrc->endx) {
+          /* trivial reject */
+        } else if (y + height < ximagesrc->starty || y > ximagesrc->endy) {
+          /* trivial reject */
+        } else {
+          /* find intersect region */
+          int startx, starty, iwidth, iheight;
+
+          startx = (x < ximagesrc->startx) ? ximagesrc->startx : x;
+          starty = (y < ximagesrc->starty) ? ximagesrc->starty : y;
+          iwidth = (x + width < ximagesrc->endx) ?
+              x + width - startx : ximagesrc->endx - startx;
+          iheight = (y + height < ximagesrc->endy) ?
+              y + height - starty : ximagesrc->endy - starty;
+          GST_DEBUG_OBJECT (ximagesrc, "Removing cursor from %d,%d", x, y);
+          XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
+              startx, starty, iwidth, iheight, AllPlanes, ZPixmap,
+              meta->ximage, startx - ximagesrc->startx,
+              starty - ximagesrc->starty);
+        }
+      } else {
+
+        GST_DEBUG_OBJECT (ximagesrc, "Removing cursor from %d,%d", x, y);
+        XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
+            x, y, width, height, AllPlanes, ZPixmap, meta->ximage, x, y);
+      }
+    }
+#endif
+
+
+  } else {
+#endif
+
+#ifdef HAVE_XSHM
+    if (ximagesrc->xcontext->use_xshm) {
+      GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XShm");
+      XShmGetImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
+          meta->ximage, ximagesrc->startx, ximagesrc->starty, AllPlanes);
+
+    } else
+#endif /* HAVE_XSHM */
+    {
+      GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XGetImage");
+      if (ximagesrc->remote) {
+        XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
+            ximagesrc->startx, ximagesrc->starty, ximagesrc->width,
+            ximagesrc->height, AllPlanes, ZPixmap, meta->ximage, 0, 0);
+      } else {
+        meta->ximage =
+            XGetImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
+            ximagesrc->startx, ximagesrc->starty, ximagesrc->width,
+            ximagesrc->height, AllPlanes, ZPixmap);
+      }
+    }
+#ifdef HAVE_XDAMAGE
+  }
+#endif
+
+#ifdef HAVE_XFIXES
+  if (ximagesrc->show_pointer && ximagesrc->have_xfixes
+      && gst_ximage_is_pointer_in_region (ximagesrc)) {
+
+    GST_DEBUG_OBJECT (ximagesrc, "Using XFixes to draw cursor");
+    /* get cursor */
+    if (ximagesrc->cursor_image)
+      XFree (ximagesrc->cursor_image);
+    ximagesrc->cursor_image = XFixesGetCursorImage (ximagesrc->xcontext->disp);
+    if (ximagesrc->cursor_image != NULL) {
+      int cx, cy, i, j, count;
+      int startx, starty, iwidth, iheight;
+      gboolean cursor_in_image = TRUE;
+
+      cx = ximagesrc->cursor_image->x - ximagesrc->cursor_image->xhot -
+          ximagesrc->x;
+      cy = ximagesrc->cursor_image->y - ximagesrc->cursor_image->yhot -
+          ximagesrc->y;
+      count = ximagesrc->cursor_image->width * ximagesrc->cursor_image->height;
+
+      /* only get where cursor last was, if it is in our range */
+      if (ximagesrc->endx > ximagesrc->startx &&
+          ximagesrc->endy > ximagesrc->starty) {
+        /* check bounds */
+        if (cx + ximagesrc->cursor_image->width < (int) ximagesrc->startx ||
+            cx > (int) ximagesrc->endx) {
+          /* trivial reject */
+          cursor_in_image = FALSE;
+        } else if (cy + ximagesrc->cursor_image->height <
+            (int) ximagesrc->starty || cy > (int) ximagesrc->endy) {
+          /* trivial reject */
+          cursor_in_image = FALSE;
+        } else {
+          /* find intersect region */
+
+          startx = (cx < (int) ximagesrc->startx) ? ximagesrc->startx : cx;
+          starty = (cy < (int) ximagesrc->starty) ? ximagesrc->starty : cy;
+          iwidth = (cx + ximagesrc->cursor_image->width < ximagesrc->endx) ?
+              cx + ximagesrc->cursor_image->width - startx :
+              ximagesrc->endx - startx;
+          iheight =
+              (cy + ximagesrc->cursor_image->height <
+              ximagesrc->endy) ? cy + ximagesrc->cursor_image->height -
+              starty : ximagesrc->endy - starty;
+        }
+      } else {
+        startx = cx;
+        starty = cy;
+        iwidth = ximagesrc->cursor_image->width;
+        iheight = ximagesrc->cursor_image->height;
+      }
+
+      if (cursor_in_image) {
+        GST_DEBUG_OBJECT (ximagesrc, "Cursor is in image so trying to draw it");
+        for (i = 0; i < count; i++)
+          ximagesrc->cursor_image->pixels[i] =
+              GUINT_TO_LE (ximagesrc->cursor_image->pixels[i]);
+        /* copy those pixels across */
+        for (j = starty;
+            j < starty + iheight
+            && j < ximagesrc->starty + ximagesrc->height; j++) {
+          for (i = startx;
+              i < startx + iwidth
+              && i < ximagesrc->startx + ximagesrc->width; i++) {
+            guint8 *src, *dest;
+
+            src =
+                (guint8 *) & (ximagesrc->cursor_image->pixels[((j -
+                            cy) * ximagesrc->cursor_image->width + (i - cx))]);
+            dest =
+                (guint8 *) & (meta->ximage->data[((j -
+                            ximagesrc->starty) * ximagesrc->width + (i -
+                            ximagesrc->startx)) *
+                    (ximagesrc->xcontext->bpp / 8)]);
+
+            composite_pixel (ximagesrc->xcontext, (guint8 *) dest,
+                (guint8 *) src);
+          }
+        }
+      }
+    }
+  }
+#endif
+#ifdef HAVE_XDAMAGE
+  if (ximagesrc->have_xdamage && ximagesrc->use_damage) {
+    /* need to ref ximage to put in last_ximage */
+    gst_buffer_ref (ximage);
+    if (ximagesrc->last_ximage) {
+      gst_buffer_unref (ximagesrc->last_ximage);
+    }
+    ximagesrc->last_ximage = ximage;
+    GST_LOG_OBJECT (ximagesrc, "reffing current buffer for last_ximage");
+  }
+#endif
+  return ximage;
+}
+
+static GstFlowReturn
+gst_ximage_src_create (GstPushSrc * bs, GstBuffer ** buf)
+{
+  GstXImageSrc *s = GST_XIMAGE_SRC (bs);
+  GstBuffer *image;
+  GstClockTime base_time;
+  GstClockTime next_capture_ts;
+  GstClockTime dur;
+  gint64 next_frame_no;
+
+  if (!gst_ximage_src_recalc (s)) {
+    GST_ELEMENT_ERROR (s, RESOURCE, FAILED,
+        (_("Changing resolution at runtime is not yet supported.")), (NULL));
+    return GST_FLOW_ERROR;
+  }
+
+  if (s->fps_n <= 0 || s->fps_d <= 0)
+    return GST_FLOW_NOT_NEGOTIATED;     /* FPS must be > 0 */
+
+  /* Now, we might need to wait for the next multiple of the fps
+   * before capturing */
+
+  GST_OBJECT_LOCK (s);
+  if (GST_ELEMENT_CLOCK (s) == NULL) {
+    GST_OBJECT_UNLOCK (s);
+    GST_ELEMENT_ERROR (s, RESOURCE, FAILED,
+        (_("Cannot operate without a clock")), (NULL));
+    return GST_FLOW_ERROR;
+  }
+
+  base_time = GST_ELEMENT_CAST (s)->base_time;
+  next_capture_ts = gst_clock_get_time (GST_ELEMENT_CLOCK (s));
+  next_capture_ts -= base_time;
+
+  /* Figure out which 'frame number' position we're at, based on the cur time
+   * and frame rate */
+  next_frame_no = gst_util_uint64_scale (next_capture_ts,
+      s->fps_n, GST_SECOND * s->fps_d);
+  if (next_frame_no == s->last_frame_no) {
+    GstClockID id;
+    GstClockReturn ret;
+
+    /* Need to wait for the next frame */
+    next_frame_no += 1;
+
+    /* Figure out what the next frame time is */
+    next_capture_ts = gst_util_uint64_scale (next_frame_no,
+        s->fps_d * GST_SECOND, s->fps_n);
+
+    id = gst_clock_new_single_shot_id (GST_ELEMENT_CLOCK (s),
+        next_capture_ts + base_time);
+    s->clock_id = id;
+
+    /* release the object lock while waiting */
+    GST_OBJECT_UNLOCK (s);
+
+    GST_DEBUG_OBJECT (s, "Waiting for next frame time %" G_GUINT64_FORMAT,
+        next_capture_ts);
+    ret = gst_clock_id_wait (id, NULL);
+    GST_OBJECT_LOCK (s);
+
+    gst_clock_id_unref (id);
+    s->clock_id = NULL;
+    if (ret == GST_CLOCK_UNSCHEDULED) {
+      /* Got woken up by the unlock function */
+      GST_OBJECT_UNLOCK (s);
+      return GST_FLOW_FLUSHING;
+    }
+    /* Duration is a complete 1/fps frame duration */
+    dur = gst_util_uint64_scale_int (GST_SECOND, s->fps_d, s->fps_n);
+  } else {
+    GstClockTime next_frame_ts;
+
+    GST_DEBUG_OBJECT (s, "No need to wait for next frame time %"
+        G_GUINT64_FORMAT " next frame = %" G_GINT64_FORMAT " prev = %"
+        G_GINT64_FORMAT, next_capture_ts, next_frame_no, s->last_frame_no);
+    next_frame_ts = gst_util_uint64_scale (next_frame_no + 1,
+        s->fps_d * GST_SECOND, s->fps_n);
+    /* Frame duration is from now until the next expected capture time */
+    dur = next_frame_ts - next_capture_ts;
+  }
+  s->last_frame_no = next_frame_no;
+  GST_OBJECT_UNLOCK (s);
+
+  image = gst_ximage_src_ximage_get (s);
+  if (!image)
+    return GST_FLOW_ERROR;
+
+  *buf = image;
+  GST_BUFFER_DTS (*buf) = GST_CLOCK_TIME_NONE;
+  GST_BUFFER_PTS (*buf) = next_capture_ts;
+  GST_BUFFER_DURATION (*buf) = dur;
+
+  return GST_FLOW_OK;
+}
+
+static void
+gst_ximage_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstXImageSrc *src = GST_XIMAGE_SRC (object);
+
+  switch (prop_id) {
+    case PROP_DISPLAY_NAME:
+
+      g_free (src->display_name);
+      src->display_name = g_strdup (g_value_get_string (value));
+      break;
+    case PROP_SHOW_POINTER:
+      src->show_pointer = g_value_get_boolean (value);
+      break;
+    case PROP_USE_DAMAGE:
+      src->use_damage = g_value_get_boolean (value);
+      break;
+    case PROP_STARTX:
+      src->startx = g_value_get_uint (value);
+      break;
+    case PROP_STARTY:
+      src->starty = g_value_get_uint (value);
+      break;
+    case PROP_ENDX:
+      src->endx = g_value_get_uint (value);
+      break;
+    case PROP_ENDY:
+      src->endy = g_value_get_uint (value);
+      break;
+    case PROP_REMOTE:
+      src->remote = g_value_get_boolean (value);
+      break;
+    case PROP_XID:
+      if (src->xcontext != NULL) {
+        g_warning ("ximagesrc window ID must be set before opening display");
+        break;
+      }
+      src->xid = g_value_get_uint64 (value);
+      break;
+    case PROP_XNAME:
+      if (src->xcontext != NULL) {
+        g_warning ("ximagesrc window name must be set before opening display");
+        break;
+      }
+      g_free (src->xname);
+      src->xname = g_strdup (g_value_get_string (value));
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_ximage_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstXImageSrc *src = GST_XIMAGE_SRC (object);
+
+  switch (prop_id) {
+    case PROP_DISPLAY_NAME:
+      if (src->xcontext)
+        g_value_set_string (value, DisplayString (src->xcontext->disp));
+      else
+        g_value_set_string (value, src->display_name);
+
+      break;
+    case PROP_SHOW_POINTER:
+      g_value_set_boolean (value, src->show_pointer);
+      break;
+    case PROP_USE_DAMAGE:
+      g_value_set_boolean (value, src->use_damage);
+      break;
+    case PROP_STARTX:
+      g_value_set_uint (value, src->startx);
+      break;
+    case PROP_STARTY:
+      g_value_set_uint (value, src->starty);
+      break;
+    case PROP_ENDX:
+      g_value_set_uint (value, src->endx);
+      break;
+    case PROP_ENDY:
+      g_value_set_uint (value, src->endy);
+      break;
+    case PROP_REMOTE:
+      g_value_set_boolean (value, src->remote);
+      break;
+    case PROP_XID:
+      g_value_set_uint64 (value, src->xid);
+      break;
+    case PROP_XNAME:
+      g_value_set_string (value, src->xname);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_ximage_src_clear_bufpool (GstXImageSrc * ximagesrc)
+{
+  g_mutex_lock (&ximagesrc->pool_lock);
+  while (ximagesrc->buffer_pool != NULL) {
+    GstBuffer *ximage = ximagesrc->buffer_pool->data;
+
+    gst_ximage_buffer_free (ximage);
+
+    ximagesrc->buffer_pool = g_slist_delete_link (ximagesrc->buffer_pool,
+        ximagesrc->buffer_pool);
+  }
+  g_mutex_unlock (&ximagesrc->pool_lock);
+}
+
+static void
+gst_ximage_src_dispose (GObject * object)
+{
+  /* Drop references in the buffer_pool */
+  gst_ximage_src_clear_bufpool (GST_XIMAGE_SRC (object));
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_ximage_src_finalize (GObject * object)
+{
+  GstXImageSrc *src = GST_XIMAGE_SRC (object);
+
+  if (src->xcontext)
+    ximageutil_xcontext_clear (src->xcontext);
+
+  g_free (src->xname);
+  g_mutex_clear (&src->pool_lock);
+  g_mutex_clear (&src->x_lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstCaps *
+gst_ximage_src_get_caps (GstBaseSrc * bs, GstCaps * filter)
+{
+  GstXImageSrc *s = GST_XIMAGE_SRC (bs);
+  GstXContext *xcontext;
+  gint width, height;
+  GstVideoFormat format;
+  guint32 alpha_mask;
+
+  if ((!s->xcontext) && (!gst_ximage_src_open_display (s, s->display_name)))
+    return gst_pad_get_pad_template_caps (GST_BASE_SRC (s)->srcpad);
+
+  if (!gst_ximage_src_recalc (s))
+    return gst_pad_get_pad_template_caps (GST_BASE_SRC (s)->srcpad);
+
+  xcontext = s->xcontext;
+  width = s->xcontext->width;
+  height = s->xcontext->height;
+  if (s->xwindow != 0) {
+    XWindowAttributes attrs;
+    int status = XGetWindowAttributes (s->xcontext->disp, s->xwindow, &attrs);
+    if (status) {
+      width = attrs.width;
+      height = attrs.height;
+    }
+  }
+
+  /* property comments say 0 means right/bottom, means we can't capture
+     the top left pixel alone */
+  if (s->endx == 0)
+    s->endx = width - 1;
+  if (s->endy == 0)
+    s->endy = height - 1;
+
+  if (s->endx >= s->startx && s->endy >= s->starty) {
+    /* this means user has put in values */
+    if (s->startx < xcontext->width && s->endx < xcontext->width &&
+        s->starty < xcontext->height && s->endy < xcontext->height) {
+      /* values are fine */
+      s->width = width = s->endx - s->startx + 1;
+      s->height = height = s->endy - s->starty + 1;
+    } else {
+      GST_WARNING
+          ("User put in co-ordinates overshooting the X resolution, setting to full screen");
+      s->startx = 0;
+      s->starty = 0;
+      s->endx = width - 1;
+      s->endy = height - 1;
+    }
+  } else {
+    GST_WARNING ("User put in bogus co-ordinates, setting to full screen");
+    s->startx = 0;
+    s->starty = 0;
+    s->endx = width - 1;
+    s->endy = height - 1;
+  }
+  GST_DEBUG ("width = %d, height=%d", width, height);
+
+  /* extrapolate alpha mask */
+  if (xcontext->depth == 32) {
+    alpha_mask = ~(xcontext->r_mask_output
+        | xcontext->g_mask_output | xcontext->b_mask_output);
+  } else {
+    alpha_mask = 0;
+  }
+
+  format =
+      gst_video_format_from_masks (xcontext->depth, xcontext->bpp,
+      xcontext->endianness, xcontext->r_mask_output,
+      xcontext->g_mask_output, xcontext->b_mask_output, alpha_mask);
+
+  return gst_caps_new_simple ("video/x-raw",
+      "format", G_TYPE_STRING, gst_video_format_to_string (format),
+      "width", G_TYPE_INT, width,
+      "height", G_TYPE_INT, height,
+      "framerate", GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1,
+      "pixel-aspect-ratio", GST_TYPE_FRACTION, xcontext->par_n,
+      xcontext->par_d, NULL);
+}
+
+static gboolean
+gst_ximage_src_set_caps (GstBaseSrc * bs, GstCaps * caps)
+{
+  GstXImageSrc *s = GST_XIMAGE_SRC (bs);
+  GstStructure *structure;
+  const GValue *new_fps;
+
+  /* If not yet opened, disallow setcaps until later */
+  if (!s->xcontext)
+    return FALSE;
+
+  /* The only thing that can change is the framerate downstream wants */
+  structure = gst_caps_get_structure (caps, 0);
+  new_fps = gst_structure_get_value (structure, "framerate");
+  if (!new_fps)
+    return FALSE;
+
+  /* Store this FPS for use when generating buffers */
+  s->fps_n = gst_value_get_fraction_numerator (new_fps);
+  s->fps_d = gst_value_get_fraction_denominator (new_fps);
+
+  GST_DEBUG_OBJECT (s, "peer wants %d/%d fps", s->fps_n, s->fps_d);
+
+  return TRUE;
+}
+
+static GstCaps *
+gst_ximage_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
+{
+  gint i;
+  GstStructure *structure;
+
+  caps = gst_caps_make_writable (caps);
+
+  for (i = 0; i < gst_caps_get_size (caps); ++i) {
+    structure = gst_caps_get_structure (caps, i);
+
+    gst_structure_fixate_field_nearest_fraction (structure, "framerate", 25, 1);
+  }
+  caps = GST_BASE_SRC_CLASS (parent_class)->fixate (bsrc, caps);
+
+  return caps;
+}
+
+static void
+gst_ximage_src_class_init (GstXImageSrcClass * klass)
+{
+  GObjectClass *gc = G_OBJECT_CLASS (klass);
+  GstElementClass *ec = GST_ELEMENT_CLASS (klass);
+  GstBaseSrcClass *bc = GST_BASE_SRC_CLASS (klass);
+  GstPushSrcClass *push_class = GST_PUSH_SRC_CLASS (klass);
+
+  gc->set_property = gst_ximage_src_set_property;
+  gc->get_property = gst_ximage_src_get_property;
+  gc->dispose = gst_ximage_src_dispose;
+  gc->finalize = gst_ximage_src_finalize;
+
+  g_object_class_install_property (gc, PROP_DISPLAY_NAME,
+      g_param_spec_string ("display-name", "Display", "X Display Name",
+          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gc, PROP_SHOW_POINTER,
+      g_param_spec_boolean ("show-pointer", "Show Mouse Pointer",
+          "Show mouse pointer (if XFixes extension enabled)", TRUE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstXImageSrc:use-damage:
+   *
+   * Use XDamage (if the XDamage extension is enabled)
+   */
+  g_object_class_install_property (gc, PROP_USE_DAMAGE,
+      g_param_spec_boolean ("use-damage", "Use XDamage",
+          "Use XDamage (if XDamage extension enabled)", TRUE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstXImageSrc:startx:
+   *
+   * X coordinate of top left corner of area to be recorded
+   * (0 for top left of screen)
+   */
+  g_object_class_install_property (gc, PROP_STARTX,
+      g_param_spec_uint ("startx", "Start X co-ordinate",
+          "X coordinate of top left corner of area to be recorded (0 for top left of screen)",
+          0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstXImageSrc:starty:
+   *
+   * Y coordinate of top left corner of area to be recorded
+   * (0 for top left of screen)
+   */
+  g_object_class_install_property (gc, PROP_STARTY,
+      g_param_spec_uint ("starty", "Start Y co-ordinate",
+          "Y coordinate of top left corner of area to be recorded (0 for top left of screen)",
+          0, G_MAXINT, 0, G_PARAM_READWRITE));
+  /**
+   * GstXImageSrc:endx:
+   *
+   * X coordinate of bottom right corner of area to be recorded
+   * (0 for bottom right of screen)
+   */
+  g_object_class_install_property (gc, PROP_ENDX,
+      g_param_spec_uint ("endx", "End X",
+          "X coordinate of bottom right corner of area to be recorded (0 for bottom right of screen)",
+          0, G_MAXINT, 0, G_PARAM_READWRITE));
+  /**
+   * GstXImageSrc:endy:
+   *
+   * Y coordinate of bottom right corner of area to be recorded
+   * (0 for bottom right of screen)
+   */
+  g_object_class_install_property (gc, PROP_ENDY,
+      g_param_spec_uint ("endy", "End Y",
+          "Y coordinate of bottom right corner of area to be recorded (0 for bottom right of screen)",
+          0, G_MAXINT, 0, G_PARAM_READWRITE));
+
+  /**
+   * GstXImageSrc:remote:
+   *
+   * Whether the X display is remote. The element will try to use alternate calls
+   * known to work better with remote displays.
+   */
+  g_object_class_install_property (gc, PROP_REMOTE,
+      g_param_spec_boolean ("remote", "Remote dispay",
+          "Whether the display is remote", FALSE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstXImageSrc:xid:
+   *
+   * The XID of the window to capture. 0 for the root window (default).
+   */
+  g_object_class_install_property (gc, PROP_XID,
+      g_param_spec_uint64 ("xid", "Window XID",
+          "Window XID to capture from", 0, G_MAXUINT64, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstXImageSrc:xname:
+   *
+   * The name of the window to capture, if any.
+   */
+  g_object_class_install_property (gc, PROP_XNAME,
+      g_param_spec_string ("xname", "Window name",
+          "Window name to capture from", NULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_static_metadata (ec, "Ximage video source",
+      "Source/Video",
+      "Creates a screenshot video stream",
+      "Lutz Mueller <lutz@users.sourceforge.net>, "
+      "Jan Schmidt <thaytan@mad.scientist.com>, "
+      "Zaheer Merali <zaheerabbas at merali dot org>");
+  gst_element_class_add_static_pad_template (ec, &t);
+
+  bc->fixate = gst_ximage_src_fixate;
+  bc->get_caps = gst_ximage_src_get_caps;
+  bc->set_caps = gst_ximage_src_set_caps;
+  bc->start = gst_ximage_src_start;
+  bc->stop = gst_ximage_src_stop;
+  bc->unlock = gst_ximage_src_unlock;
+  push_class->create = gst_ximage_src_create;
+}
+
+static void
+gst_ximage_src_init (GstXImageSrc * ximagesrc)
+{
+  gst_base_src_set_format (GST_BASE_SRC (ximagesrc), GST_FORMAT_TIME);
+  gst_base_src_set_live (GST_BASE_SRC (ximagesrc), TRUE);
+
+  g_mutex_init (&ximagesrc->pool_lock);
+  g_mutex_init (&ximagesrc->x_lock);
+  ximagesrc->show_pointer = TRUE;
+  ximagesrc->use_damage = TRUE;
+  ximagesrc->startx = 0;
+  ximagesrc->starty = 0;
+  ximagesrc->endx = 0;
+  ximagesrc->endy = 0;
+  ximagesrc->remote = FALSE;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  gboolean ret;
+
+  GST_DEBUG_CATEGORY_INIT (gst_debug_ximage_src, "ximagesrc", 0,
+      "ximagesrc element debug");
+
+  ret = gst_element_register (plugin, "ximagesrc", GST_RANK_NONE,
+      GST_TYPE_XIMAGE_SRC);
+
+  return ret;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    ximagesrc,
+    "X11 video input plugin using standard Xlib calls",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/sys/ximage/gstximagesrc.h b/sys/ximage/gstximagesrc.h
new file mode 100644
index 0000000..e43447a
--- /dev/null
+++ b/sys/ximage/gstximagesrc.h
@@ -0,0 +1,114 @@
+/* screenshotsrc: Screenshot plugin for GStreamer
+ * 
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_XIMAGE_SRC_H__
+#define __GST_XIMAGE_SRC_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+#include "ximageutil.h"
+
+#ifdef HAVE_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif
+#ifdef HAVE_XDAMAGE
+#include <X11/extensions/Xdamage.h>
+#endif
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_XIMAGE_SRC (gst_ximage_src_get_type())
+#define GST_XIMAGE_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XIMAGE_SRC,GstXImageSrc))
+#define GST_XIMAGE_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_XIMAGE_SRC,GstXImageSrc))
+#define GST_IS_XIMAGE_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_XIMAGE_SRC))
+#define GST_IS_XIMAGE_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_XIMAGE_SRC))
+
+typedef struct _GstXImageSrc GstXImageSrc;
+typedef struct _GstXImageSrcClass GstXImageSrcClass;
+
+GType gst_ximage_src_get_type (void) G_GNUC_CONST;
+
+struct _GstXImageSrc
+{
+  GstPushSrc parent;
+
+  /* Information on display */
+  GstXContext *xcontext;
+  gint x;
+  gint y;
+  gint width;
+  gint height;
+
+  Window xwindow;
+  gchar *display_name;
+
+  /* Window selection */
+  guint64 xid;
+  gchar *xname;
+
+  /* Desired output framerate */
+  gint fps_n;
+  gint fps_d;
+
+  /* for framerate sync */
+  GstClockID clock_id;
+  gint64 last_frame_no;
+
+  /* Protect X Windows calls */
+  GMutex  x_lock;
+
+  /* Gathered pool of emitted buffers */
+  GMutex  pool_lock;
+  GSList *buffer_pool;
+
+  /* XFixes and XDamage support */
+  gboolean have_xfixes;
+  gboolean have_xdamage;
+  gboolean show_pointer;
+  gboolean use_damage;
+
+  /* co-ordinates for start and end */
+  guint startx;
+  guint starty;
+  guint endx;
+  guint endy;
+
+  /* whether to use remote friendly calls */
+  gboolean remote;
+
+#ifdef HAVE_XFIXES
+  int fixes_event_base;
+  XFixesCursorImage *cursor_image;
+#endif
+#ifdef HAVE_XDAMAGE
+  Damage damage;
+  int damage_event_base;
+  XserverRegion damage_region;
+  GC damage_copy_gc;
+  GstBuffer *last_ximage;
+#endif
+};
+
+struct _GstXImageSrcClass
+{
+  GstPushSrcClass parent_class;
+};
+
+G_END_DECLS
+
+#endif /* __GST_XIMAGE_SRC_H__ */
diff --git a/sys/ximage/meson.build b/sys/ximage/meson.build
new file mode 100644
index 0000000..36ec21e
--- /dev/null
+++ b/sys/ximage/meson.build
@@ -0,0 +1,30 @@
+x11_dep = dependency('x11', required : false)
+
+if x11_dep.found()
+  x_args = []
+  # FIXME: Need to check for XShmAttach inside libXext
+  xshm_dep = dependency('xext', required : false)
+  if xshm_dep.found()
+    x_args += ['-DHAVE_XSHM']
+  endif
+
+  xfixes_dep = dependency('xfixes', required : false)
+  if xfixes_dep.found()
+    x_args += ['-DHAVE_XFIXES']
+  endif
+
+  xdamage_dep = dependency('xdamage', required : false)
+  if xdamage_dep.found()
+    x_args += ['-DHAVE_XDAMAGE']
+  endif
+
+  gstximagesrc = library('gstximagesrc',
+    'gstximagesrc.c', 'ximageutil.c',
+    c_args : gst_plugins_good_args + x_args,
+    include_directories : [configinc, libsinc],
+    dependencies : [gstbase_dep, gstvideo_dep, x11_dep,
+                    xshm_dep, xfixes_dep, xdamage_dep],
+    install : true,
+    install_dir : plugins_install_dir,
+  )
+endif
diff --git a/sys/ximage/ximageutil.c b/sys/ximage/ximageutil.c
new file mode 100644
index 0000000..57c9392
--- /dev/null
+++ b/sys/ximage/ximageutil.c
@@ -0,0 +1,500 @@
+/* GStreamer
+ * Copyright (C) <2005> Luca Ognibene <luogni@tin.it>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ximageutil.h"
+
+GType
+gst_meta_ximage_api_get_type (void)
+{
+  static volatile GType type;
+  static const gchar *tags[] = { "memory", NULL };
+
+  if (g_once_init_enter (&type)) {
+    GType _type = gst_meta_api_type_register ("GstMetaXImageSrcAPI", tags);
+    g_once_init_leave (&type, _type);
+  }
+  return type;
+}
+
+static gboolean
+gst_meta_ximage_init (GstMeta * meta, gpointer params, GstBuffer * buffer)
+{
+  GstMetaXImage *emeta = (GstMetaXImage *) meta;
+
+  emeta->parent = NULL;
+  emeta->ximage = NULL;
+#ifdef HAVE_XSHM
+  emeta->SHMInfo.shmaddr = ((void *) -1);
+  emeta->SHMInfo.shmid = -1;
+  emeta->SHMInfo.readOnly = TRUE;
+#endif
+  emeta->width = emeta->height = emeta->size = 0;
+  emeta->return_func = NULL;
+
+  return TRUE;
+}
+
+const GstMetaInfo *
+gst_meta_ximage_get_info (void)
+{
+  static const GstMetaInfo *meta_ximage_info = NULL;
+
+  if (g_once_init_enter (&meta_ximage_info)) {
+    const GstMetaInfo *meta =
+        gst_meta_register (gst_meta_ximage_api_get_type (), "GstMetaXImageSrc",
+        sizeof (GstMetaXImage), (GstMetaInitFunction) gst_meta_ximage_init,
+        (GstMetaFreeFunction) NULL, (GstMetaTransformFunction) NULL);
+    g_once_init_leave (&meta_ximage_info, meta);
+  }
+  return meta_ximage_info;
+}
+
+#ifdef HAVE_XSHM
+static gboolean error_caught = FALSE;
+
+static int
+ximageutil_handle_xerror (Display * display, XErrorEvent * xevent)
+{
+  char error_msg[1024];
+
+  XGetErrorText (display, xevent->error_code, error_msg, 1024);
+  GST_DEBUG ("ximageutil failed to use XShm calls. error: %s", error_msg);
+  error_caught = TRUE;
+  return 0;
+}
+
+/* This function checks that it is actually really possible to create an image
+   using XShm */
+gboolean
+ximageutil_check_xshm_calls (GstXContext * xcontext)
+{
+  XImage *ximage;
+  XShmSegmentInfo SHMInfo;
+  size_t size;
+  int (*handler) (Display *, XErrorEvent *);
+  gboolean result = FALSE;
+  gboolean did_attach = FALSE;
+
+  g_return_val_if_fail (xcontext != NULL, FALSE);
+
+  /* Sync to ensure any older errors are already processed */
+  XSync (xcontext->disp, FALSE);
+
+  /* Set defaults so we don't free these later unnecessarily */
+  SHMInfo.shmaddr = ((void *) -1);
+  SHMInfo.shmid = -1;
+
+  /* Setting an error handler to catch failure */
+  error_caught = FALSE;
+  handler = XSetErrorHandler (ximageutil_handle_xerror);
+
+  /* Trying to create a 1x1 ximage */
+  GST_DEBUG ("XShmCreateImage of 1x1");
+
+  ximage = XShmCreateImage (xcontext->disp, xcontext->visual,
+      xcontext->depth, ZPixmap, NULL, &SHMInfo, 1, 1);
+
+  /* Might cause an error, sync to ensure it is noticed */
+  XSync (xcontext->disp, FALSE);
+  if (!ximage || error_caught) {
+    GST_WARNING ("could not XShmCreateImage a 1x1 image");
+    goto beach;
+  }
+  size = ximage->height * ximage->bytes_per_line;
+
+  SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
+  if (SHMInfo.shmid == -1) {
+    GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
+        size);
+    goto beach;
+  }
+
+  SHMInfo.shmaddr = shmat (SHMInfo.shmid, 0, 0);
+  if (SHMInfo.shmaddr == ((void *) -1)) {
+    GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
+    goto beach;
+  }
+
+  /* Delete the SHM segment. It will actually go away automatically
+   * when we detach now */
+  shmctl (SHMInfo.shmid, IPC_RMID, 0);
+
+  ximage->data = SHMInfo.shmaddr;
+  SHMInfo.readOnly = FALSE;
+
+  if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
+    GST_WARNING ("Failed to XShmAttach");
+    goto beach;
+  }
+
+  /* Sync to ensure we see any errors we caused */
+  XSync (xcontext->disp, FALSE);
+
+  if (!error_caught) {
+    did_attach = TRUE;
+    /* store whether we succeeded in result */
+    result = TRUE;
+  }
+beach:
+  /* Sync to ensure we swallow any errors we caused and reset error_caught */
+  XSync (xcontext->disp, FALSE);
+  error_caught = FALSE;
+  XSetErrorHandler (handler);
+
+  if (did_attach) {
+    XShmDetach (xcontext->disp, &SHMInfo);
+    XSync (xcontext->disp, FALSE);
+  }
+  if (SHMInfo.shmaddr != ((void *) -1))
+    shmdt (SHMInfo.shmaddr);
+  if (ximage)
+    XDestroyImage (ximage);
+  return result;
+}
+#endif /* HAVE_XSHM */
+
+/* This function gets the X Display and global info about it. Everything is
+   stored in our object and will be cleaned when the object is disposed. Note
+   here that caps for supported format are generated without any window or
+   image creation */
+GstXContext *
+ximageutil_xcontext_get (GstElement * parent, const gchar * display_name)
+{
+  GstXContext *xcontext = NULL;
+  XPixmapFormatValues *px_formats = NULL;
+  gint nb_formats = 0, i;
+
+  xcontext = g_new0 (GstXContext, 1);
+
+  xcontext->disp = XOpenDisplay (display_name);
+  GST_DEBUG_OBJECT (parent, "opened display %p", xcontext->disp);
+  if (!xcontext->disp) {
+    g_free (xcontext);
+    return NULL;
+  }
+  xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
+  xcontext->visual = DefaultVisualOfScreen (xcontext->screen);
+  xcontext->root = RootWindowOfScreen (xcontext->screen);
+  xcontext->white = WhitePixelOfScreen (xcontext->screen);
+  xcontext->black = BlackPixelOfScreen (xcontext->screen);
+  xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
+
+  xcontext->width = WidthOfScreen (xcontext->screen);
+  xcontext->height = HeightOfScreen (xcontext->screen);
+
+  xcontext->widthmm = WidthMMOfScreen (xcontext->screen);
+  xcontext->heightmm = HeightMMOfScreen (xcontext->screen);
+
+  xcontext->caps = NULL;
+
+  GST_DEBUG_OBJECT (parent, "X reports %dx%d pixels and %d mm x %d mm",
+      xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
+  ximageutil_calculate_pixel_aspect_ratio (xcontext);
+
+  /* We get supported pixmap formats at supported depth */
+  px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
+
+  if (!px_formats) {
+    XCloseDisplay (xcontext->disp);
+    g_free (xcontext);
+    return NULL;
+  }
+
+  /* We get bpp value corresponding to our running depth */
+  for (i = 0; i < nb_formats; i++) {
+    if (px_formats[i].depth == xcontext->depth)
+      xcontext->bpp = px_formats[i].bits_per_pixel;
+  }
+
+  XFree (px_formats);
+
+  xcontext->endianness =
+      (ImageByteOrder (xcontext->disp) ==
+      LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
+
+#ifdef HAVE_XSHM
+  /* Search for XShm extension support */
+  if (XShmQueryExtension (xcontext->disp) &&
+      ximageutil_check_xshm_calls (xcontext)) {
+    xcontext->use_xshm = TRUE;
+    GST_DEBUG ("ximageutil is using XShm extension");
+  } else {
+    xcontext->use_xshm = FALSE;
+    GST_DEBUG ("ximageutil is not using XShm extension");
+  }
+#endif /* HAVE_XSHM */
+
+  /* our caps system handles 24/32bpp RGB as big-endian. */
+  if ((xcontext->bpp == 24 || xcontext->bpp == 32) &&
+      xcontext->endianness == G_LITTLE_ENDIAN) {
+    xcontext->endianness = G_BIG_ENDIAN;
+    xcontext->r_mask_output = GUINT32_TO_BE (xcontext->visual->red_mask);
+    xcontext->g_mask_output = GUINT32_TO_BE (xcontext->visual->green_mask);
+    xcontext->b_mask_output = GUINT32_TO_BE (xcontext->visual->blue_mask);
+    if (xcontext->bpp == 24) {
+      xcontext->r_mask_output >>= 8;
+      xcontext->g_mask_output >>= 8;
+      xcontext->b_mask_output >>= 8;
+    }
+  } else {
+    xcontext->r_mask_output = xcontext->visual->red_mask;
+    xcontext->g_mask_output = xcontext->visual->green_mask;
+    xcontext->b_mask_output = xcontext->visual->blue_mask;
+  }
+
+  return xcontext;
+}
+
+/* This function cleans the X context. Closing the Display and unrefing the
+   caps for supported formats. */
+void
+ximageutil_xcontext_clear (GstXContext * xcontext)
+{
+  g_return_if_fail (xcontext != NULL);
+
+  if (xcontext->caps != NULL)
+    gst_caps_unref (xcontext->caps);
+
+  XCloseDisplay (xcontext->disp);
+
+  g_free (xcontext);
+}
+
+/* This function calculates the pixel aspect ratio based on the properties
+ * in the xcontext structure and stores it there. */
+void
+ximageutil_calculate_pixel_aspect_ratio (GstXContext * xcontext)
+{
+  gint par[][2] = {
+    {1, 1},                     /* regular screen */
+    {16, 15},                   /* PAL TV */
+    {11, 10},                   /* 525 line Rec.601 video */
+    {54, 59}                    /* 625 line Rec.601 video */
+  };
+  gint i;
+  gint index;
+  gdouble ratio;
+  gdouble delta;
+
+#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
+
+  /* first calculate the "real" ratio based on the X values;
+   * which is the "physical" w/h divided by the w/h in pixels of the display */
+  ratio = (gdouble) (xcontext->widthmm * xcontext->height)
+      / (xcontext->heightmm * xcontext->width);
+
+  /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
+   * override here */
+  if (xcontext->width == 720 && xcontext->height == 576) {
+    ratio = 4.0 * 576 / (3.0 * 720);
+  }
+  GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
+
+  /* now find the one from par[][2] with the lowest delta to the real one */
+  delta = DELTA (0);
+  index = 0;
+
+  for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
+    gdouble this_delta = DELTA (i);
+
+    if (this_delta < delta) {
+      index = i;
+      delta = this_delta;
+    }
+  }
+
+  GST_DEBUG ("Decided on index %d (%d/%d)", index,
+      par[index][0], par[index][1]);
+
+  xcontext->par_n = par[index][0];
+  xcontext->par_d = par[index][1];
+  GST_DEBUG ("set xcontext PAR to %d/%d\n", xcontext->par_n, xcontext->par_d);
+}
+
+static gboolean
+gst_ximagesrc_buffer_dispose (GstBuffer * ximage)
+{
+  GstElement *parent;
+  GstMetaXImage *meta;
+  gboolean ret = TRUE;
+
+  meta = GST_META_XIMAGE_GET (ximage);
+
+  parent = meta->parent;
+  if (parent == NULL) {
+    g_warning ("XImageSrcBuffer->ximagesrc == NULL");
+    goto beach;
+  }
+
+  if (meta->return_func)
+    ret = meta->return_func (parent, ximage);
+
+beach:
+  return ret;
+}
+
+void
+gst_ximage_buffer_free (GstBuffer * ximage)
+{
+  GstMetaXImage *meta;
+
+  meta = GST_META_XIMAGE_GET (ximage);
+
+  /* make sure it is not recycled */
+  meta->width = -1;
+  meta->height = -1;
+  gst_buffer_unref (ximage);
+}
+
+/* This function handles GstXImageSrcBuffer creation depending on XShm availability */
+GstBuffer *
+gst_ximageutil_ximage_new (GstXContext * xcontext,
+    GstElement * parent, int width, int height, BufferReturnFunc return_func)
+{
+  GstBuffer *ximage = NULL;
+  GstMetaXImage *meta;
+  gboolean succeeded = FALSE;
+
+  ximage = gst_buffer_new ();
+  GST_MINI_OBJECT_CAST (ximage)->dispose =
+      (GstMiniObjectDisposeFunction) gst_ximagesrc_buffer_dispose;
+
+  meta = GST_META_XIMAGE_ADD (ximage);
+  meta->width = width;
+  meta->height = height;
+
+#ifdef HAVE_XSHM
+  meta->SHMInfo.shmaddr = ((void *) -1);
+  meta->SHMInfo.shmid = -1;
+
+  if (xcontext->use_xshm) {
+    meta->ximage = XShmCreateImage (xcontext->disp,
+        xcontext->visual, xcontext->depth,
+        ZPixmap, NULL, &meta->SHMInfo, meta->width, meta->height);
+    if (!meta->ximage) {
+      GST_WARNING_OBJECT (parent,
+          "could not XShmCreateImage a %dx%d image", meta->width, meta->height);
+
+      /* Retry without XShm */
+      xcontext->use_xshm = FALSE;
+      goto no_xshm;
+    }
+
+    /* we have to use the returned bytes_per_line for our shm size */
+    meta->size = meta->ximage->bytes_per_line * meta->ximage->height;
+    meta->SHMInfo.shmid = shmget (IPC_PRIVATE, meta->size, IPC_CREAT | 0777);
+    if (meta->SHMInfo.shmid == -1)
+      goto beach;
+
+    meta->SHMInfo.shmaddr = shmat (meta->SHMInfo.shmid, 0, 0);
+    if (meta->SHMInfo.shmaddr == ((void *) -1))
+      goto beach;
+
+    /* Delete the SHM segment. It will actually go away automatically
+     * when we detach now */
+    shmctl (meta->SHMInfo.shmid, IPC_RMID, 0);
+
+    meta->ximage->data = meta->SHMInfo.shmaddr;
+    meta->SHMInfo.readOnly = FALSE;
+
+    if (XShmAttach (xcontext->disp, &meta->SHMInfo) == 0)
+      goto beach;
+
+    XSync (xcontext->disp, FALSE);
+  } else
+  no_xshm:
+#endif /* HAVE_XSHM */
+  {
+    meta->ximage = XCreateImage (xcontext->disp,
+        xcontext->visual,
+        xcontext->depth,
+        ZPixmap, 0, NULL, meta->width, meta->height, xcontext->bpp, 0);
+    if (!meta->ximage)
+      goto beach;
+
+    /* we have to use the returned bytes_per_line for our image size */
+    meta->size = meta->ximage->bytes_per_line * meta->ximage->height;
+    meta->ximage->data = g_malloc (meta->size);
+
+    XSync (xcontext->disp, FALSE);
+  }
+  succeeded = TRUE;
+
+  gst_buffer_append_memory (ximage,
+      gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, meta->ximage->data,
+          meta->size, 0, meta->size, NULL, NULL));
+
+  /* Keep a ref to our src */
+  meta->parent = gst_object_ref (parent);
+  meta->return_func = return_func;
+beach:
+  if (!succeeded) {
+    gst_ximage_buffer_free (ximage);
+    ximage = NULL;
+  }
+
+  return ximage;
+}
+
+/* This function destroys a GstXImageBuffer handling XShm availability */
+void
+gst_ximageutil_ximage_destroy (GstXContext * xcontext, GstBuffer * ximage)
+{
+  GstMetaXImage *meta;
+
+  meta = GST_META_XIMAGE_GET (ximage);
+
+  /* We might have some buffers destroyed after changing state to NULL */
+  if (!xcontext)
+    goto beach;
+
+  g_return_if_fail (ximage != NULL);
+
+#ifdef HAVE_XSHM
+  if (xcontext->use_xshm) {
+    if (meta->SHMInfo.shmaddr != ((void *) -1)) {
+      XShmDetach (xcontext->disp, &meta->SHMInfo);
+      XSync (xcontext->disp, 0);
+      shmdt (meta->SHMInfo.shmaddr);
+    }
+    if (meta->ximage)
+      XDestroyImage (meta->ximage);
+
+  } else
+#endif /* HAVE_XSHM */
+  {
+    if (meta->ximage) {
+      XDestroyImage (meta->ximage);
+    }
+  }
+
+  XSync (xcontext->disp, FALSE);
+beach:
+  if (meta->parent) {
+    /* Release the ref to our parent */
+    gst_object_unref (meta->parent);
+    meta->parent = NULL;
+  }
+
+  return;
+}
diff --git a/sys/ximage/ximageutil.h b/sys/ximage/ximageutil.h
new file mode 100644
index 0000000..3476861
--- /dev/null
+++ b/sys/ximage/ximageutil.h
@@ -0,0 +1,181 @@
+/* GStreamer
+ * Copyright (C) <2005> Luca Ognibene <luogni@tin.it>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_XIMAGEUTIL_H__
+#define __GST_XIMAGEUTIL_H__
+
+#include <gst/gst.h>
+
+#ifdef HAVE_XSHM
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#endif /* HAVE_XSHM */
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#ifdef HAVE_XSHM
+#include <X11/extensions/XShm.h>
+#endif /* HAVE_XSHM */
+
+#include <string.h>
+#include <math.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstXContext GstXContext;
+typedef struct _GstXWindow GstXWindow;
+typedef struct _GstXImage GstXImage;
+typedef struct _GstMetaXImage GstMetaXImage;
+
+/* Global X Context stuff */
+/**
+ * GstXContext:
+ * @disp: the X11 Display of this context
+ * @screen: the default Screen of Display @disp
+ * @visual: the default Visual of Screen @screen
+ * @root: the root Window of Display @disp
+ * @white: the value of a white pixel on Screen @screen
+ * @black: the value of a black pixel on Screen @screen
+ * @depth: the color depth of Display @disp
+ * @bpp: the number of bits per pixel on Display @disp
+ * @endianness: the endianness of image bytes on Display @disp
+ * @width: the width in pixels of Display @disp
+ * @height: the height in pixels of Display @disp
+ * @widthmm: the width in millimeters of Display @disp
+ * @heightmm: the height in millimeters of Display @disp
+ * @par_n: the pixel aspect ratio numerator calculated from @width, @widthmm
+ * and @height,
+ * @par_d: the pixel aspect ratio denumerator calculated from @width, @widthmm
+ * and @height,
+ * @heightmm ratio
+ * @use_xshm: used to known wether of not XShm extension is usable or not even
+ * if the Extension is present
+ * @caps: the #GstCaps that Display @disp can accept
+ *
+ * Structure used to store various informations collected/calculated for a
+ * Display.
+ */
+struct _GstXContext {
+  Display *disp;
+
+  Screen *screen;
+
+  Visual *visual;
+
+  Window root;
+
+  gulong white, black;
+
+  gint depth;
+  gint bpp;
+  gint endianness;
+
+  gint width, height;
+  gint widthmm, heightmm;
+
+  /* these are the output masks
+   * for buffers from ximagesrc
+   * and are in big endian */
+  guint32 r_mask_output, g_mask_output, b_mask_output;
+
+  guint par_n;                  /* calculated pixel aspect ratio numerator */
+  guint par_d;                  /* calculated pixel aspect ratio denumerator */
+
+  gboolean use_xshm;
+
+  GstCaps *caps;
+};
+
+/**
+ * GstXWindow:
+ * @win: the Window ID of this X11 window
+ * @width: the width in pixels of Window @win
+ * @height: the height in pixels of Window @win
+ * @internal: used to remember if Window @win was created internally or passed
+ * through the #GstXOverlay interface
+ * @gc: the Graphical Context of Window @win
+ *
+ * Structure used to store informations about a Window.
+ */
+struct _GstXWindow {
+  Window win;
+  gint width, height;
+  gboolean internal;
+  GC gc;
+};
+
+gboolean ximageutil_check_xshm_calls (GstXContext * xcontext);
+
+GstXContext *ximageutil_xcontext_get (GstElement *parent, 
+    const gchar *display_name);
+void ximageutil_xcontext_clear (GstXContext *xcontext);
+void ximageutil_calculate_pixel_aspect_ratio (GstXContext * xcontext);
+
+/* custom ximagesrc buffer, copied from ximagesink */
+
+/* BufferReturnFunc is called when a buffer is finalised */
+typedef gboolean (*BufferReturnFunc) (GstElement *parent, GstBuffer *buf);
+
+/**
+ * GstMetaXImage:
+ * @parent: a reference to the element we belong to
+ * @ximage: the XImage of this buffer
+ * @width: the width in pixels of XImage @ximage
+ * @height: the height in pixels of XImage @ximage
+ * @size: the size in bytes of XImage @ximage
+ *
+ * Extra data attached to buffers containing additional information about an XImage.
+ */
+struct _GstMetaXImage {
+  GstMeta meta;
+
+  /* Reference to the ximagesrc we belong to */
+  GstElement *parent;
+
+  XImage *ximage;
+
+#ifdef HAVE_XSHM
+  XShmSegmentInfo SHMInfo;
+#endif /* HAVE_XSHM */
+
+  gint width, height;
+  size_t size;
+
+  BufferReturnFunc return_func;
+};
+
+GType gst_meta_ximage_api_get_type (void);
+const GstMetaInfo * gst_meta_ximage_get_info (void);
+#define GST_META_XIMAGE_GET(buf) ((GstMetaXImage *)gst_buffer_get_meta(buf,gst_meta_ximage_api_get_type()))
+#define GST_META_XIMAGE_ADD(buf) ((GstMetaXImage *)gst_buffer_add_meta(buf,gst_meta_ximage_get_info(),NULL))
+
+GstBuffer *gst_ximageutil_ximage_new (GstXContext *xcontext,
+  GstElement *parent, int width, int height, BufferReturnFunc return_func);
+
+void gst_ximageutil_ximage_destroy (GstXContext *xcontext, 
+  GstBuffer * ximage);
+  
+/* Call to manually release a buffer */
+void gst_ximage_buffer_free (GstBuffer *ximage);
+
+G_END_DECLS 
+
+#endif /* __GST_XIMAGEUTIL_H__ */
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..5f10e8f
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,22 @@
+if HAVE_GST_CHECK
+SUBDIRS_CHECK = check files
+else
+SUBDIRS_CHECK =
+endif
+
+if USE_X
+SUBDIRS_ICLES = icles
+else
+SUBDIRS_ICLES =
+endif
+
+if BUILD_EXAMPLES
+SUBDIR_EXAMPLES = examples
+else
+SUBDIR_EXAMPLES =
+endif
+
+SUBDIRS = $(SUBDIRS_CHECK) $(SUBDIRS_ICLES) $(SUBDIR_EXAMPLES)
+
+DIST_SUBDIRS = check icles examples files
+
diff --git a/tests/check/.gitignore b/tests/check/.gitignore
new file mode 100644
index 0000000..789588b
--- /dev/null
+++ b/tests/check/.gitignore
@@ -0,0 +1,2 @@
+test-registry.*
+orc
diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am
new file mode 100644
index 0000000..d850bc5
--- /dev/null
+++ b/tests/check/Makefile.am
@@ -0,0 +1,663 @@
+include $(top_srcdir)/common/check.mak
+
+CHECK_REGISTRY = $(top_builddir)/tests/check/test-registry.reg
+TEST_FILES_DIRECTORY = $(top_srcdir)/tests/files
+
+REGISTRY_ENVIRONMENT = \
+	GST_REGISTRY_1_0=$(CHECK_REGISTRY)
+
+AM_TESTS_ENVIRONMENT += \
+	$(REGISTRY_ENVIRONMENT)					\
+	GST_PLUGIN_SYSTEM_PATH_1_0=				\
+	GST_PLUGIN_PATH_1_0=$(top_builddir)/gst:$(top_builddir)/ext:$(top_builddir)/sys:$(GSTPB_PLUGINS_DIR):$(GST_PLUGINS_DIR)			\
+	GST_PLUGIN_LOADING_WHITELIST="gstreamer@$(GST_PLUGINS_DIR):gst-plugins-base@$(GSTPB_PLUGINS_DIR):gst-plugins-good@$(top_builddir)"	\
+	GST_STATE_IGNORE_ELEMENTS="aasink autoaudiosrc autoaudiosink autovideosrc autovideosink \
+		cacasink cairotextoverlay \
+		halaudiosrc halaudiosink jackaudiosrc jackaudiosink \
+		osssrc osssink osxaudiosink osxaudiosrc osxvideosrc osxvideosink \
+		pulsesink pulsesrc pulsemixer v4l2src" \
+	GSETTINGS_BACKEND="memory"
+
+# fake device drivers: we could run hardware element tests against dummy drivers
+# v4l2: vivo (part of normal kernel)
+#   modprobe vivo;
+#   gst-launch v4l2src device="/dev/video1" ! xvimagesink;
+#   rmmod vivo
+#
+# alsa: snd-dummy (part of normal alsa, not removable)
+#   modprobe snd-dummy;
+#   gst-launch alsasrc device="hw:2" ! fakesink
+#   gst-launch fakesrc ! alsasink device="hw:2"
+#
+# need a way to figure out value for the device property
+
+# the core dumps of some machines have PIDs appended
+CLEANFILES = core.* test-registry.*
+
+clean-local: clean-local-check
+distclean-local: distclean-local-orc
+
+if USE_PLUGIN_ALPHA
+check_alpha = \
+	elements/alphacolor \
+	elements/alpha
+else
+check_alpha =
+endif
+
+if USE_PLUGIN_AUDIOFX
+check_audiofx = \
+	elements/audioamplify \
+	elements/audiochebband \
+	elements/audiocheblimit \
+	elements/audiodynamic \
+	elements/audioecho \
+	elements/audiofirfilter \
+	elements/audioiirfilter \
+	elements/audioinvert \
+	elements/audiopanorama \
+	elements/audiowsincband \
+	elements/audiowsinclimit
+else
+check_audiofx =
+endif
+
+if USE_PLUGIN_AUDIOPARSERS
+check_audioparsers = \
+	elements/aacparse \
+	elements/ac3parse \
+	elements/amrparse \
+	elements/flacparse \
+	elements/mpegaudioparse \
+	elements/wavpackparse
+else
+check_audioparsers =
+endif
+
+if USE_PLUGIN_AUTODETECT
+check_autodetect = elements/autodetect
+else
+check_autodetect =
+endif
+
+if USE_PLUGIN_AVI
+check_avi = \
+  elements/avimux \
+  elements/avisubtitle
+else
+check_avi =
+endif
+
+if USE_PLUGIN_DEBUGUTILS
+check_debugutils = elements/capssetter
+else
+check_debugutils =
+endif
+
+if USE_PLUGIN_DEINTERLACE
+check_deinterlace = elements/deinterlace
+else
+check_deinterlace =
+endif
+
+if USE_PLUGIN_DTMF
+check_dtmf = elements/dtmf
+else
+check_dtmf =
+endif
+
+if USE_PLUGIN_EFFECTV
+check_effectv = pipelines/effectv
+else
+check_effectv =
+endif
+
+if USE_PLUGIN_EQUALIZER
+check_equalizer = elements/equalizer
+else
+check_equalizer =
+endif
+
+if USE_FLAC
+check_flac = pipelines/flacdec
+else
+check_flac =
+endif
+
+if USE_PLUGIN_FLV
+check_flv = \
+        elements/flvdemux \
+        elements/flvmux
+else
+check_flv =
+endif
+
+if USE_PLUGIN_ISOMP4
+check_isomp4 = \
+	elements/qtmux \
+	elements/qtdemux
+else
+check_isomp4 =
+endif
+
+if USE_PLUGIN_LAW
+check_law = \
+	elements/mulawdec \
+	elements/mulawenc
+else
+check_law =
+endif
+
+if USE_GDK_PIXBUF
+check_gdkpixbuf = elements/gdkpixbufsink elements/gdkpixbufoverlay
+else
+check_gdkpixbuf =
+endif
+
+if USE_PLUGIN_ICYDEMUX
+check_icydemux = elements/icydemux
+else
+check_icydemux =
+endif
+
+if USE_PLUGIN_ID3DEMUX
+check_id3demux = elements/id3demux
+else
+check_id3demux =
+endif
+
+if USE_PLUGIN_IMAGEFREEZE
+check_imagefreeze = elements/imagefreeze
+else
+check_imagefreeze =
+endif
+
+if USE_PLUGIN_INTERLEAVE
+check_interleave = \
+        elements/deinterleave \
+        elements/interleave
+else
+check_interleave =
+endif
+
+if USE_JPEG
+check_jpeg = \
+        elements/jpegdec \
+        elements/jpegenc
+else
+check_jpeg =
+endif
+
+if USE_LAME
+check_lame = pipelines/lame
+else
+check_lame =
+endif
+
+if USE_PLUGIN_LEVEL
+check_level = elements/level
+else
+check_level =
+endif
+
+if USE_PLUGIN_MATROSKA
+check_matroska = \
+	elements/matroskademux \
+	elements/matroskamux \
+	elements/matroskaparse
+else
+check_matroska =
+endif
+
+if USE_MPG123
+check_mpg123 = elements/mpg123audiodec
+else
+check_mpg123 =
+endif
+
+if USE_PLUGIN_MULTIFILE
+check_multifile = elements/multifile elements/splitmux
+else
+check_multifile =
+endif
+
+if USE_PLUGIN_REPLAYGAIN
+check_replaygain = \
+	elements/rganalysis \
+	elements/rglimiter \
+	elements/rgvolume
+else
+check_replaygain =
+endif
+
+if USE_PLUGIN_RTP
+check_rtp = \
+	elements/rtp-payloading \
+	elements/rtph261 \
+	elements/rtph263 \
+	elements/rtph264 \
+	elements/rtpvp9
+else
+check_rtp =
+endif
+
+if USE_PLUGIN_RTPMANAGER
+check_rtpmanager = \
+	elements/rtpaux \
+	elements/rtpbin \
+	elements/rtpbin_buffer_list \
+	elements/rtpbundle \
+	elements/rtpcollision \
+	elements/rtpjitterbuffer \
+	elements/rtpmux \
+	elements/rtprtx \
+	elements/rtpsession
+else
+check_rtpmanager =
+endif
+
+if USE_SOUP
+check_soup = elements/souphttpsrc
+else
+check_soup =
+endif
+
+if USE_PLUGIN_SPECTRUM
+check_spectrum = elements/spectrum
+else
+check_spectrum =
+endif
+
+if USE_PLUGIN_SHAPEWIPE
+check_shapewipe = elements/shapewipe
+else
+check_shapewipe =
+endif
+
+if USE_TAGLIB
+check_taglib = \
+	elements/id3v2mux \
+	elements/apev2mux
+else
+check_taglib =
+endif
+
+if USE_TWOLAME
+check_twolame = pipelines/twolame
+else
+check_twolame =
+endif
+
+if USE_PLUGIN_UDP
+check_udp = \
+        elements/udpsink \
+        elements/udpsrc
+else
+check_udp =
+endif
+
+if USE_PLUGIN_VIDEOBOX
+check_videobox = elements/videobox
+else
+check_videobox =
+endif
+
+if USE_PLUGIN_VIDEOCROP
+check_videocrop = \
+	elements/aspectratiocrop \
+	elements/videocrop
+else
+check_videocrop =
+endif
+
+if USE_PLUGIN_VIDEOFILTER
+check_videofilter = elements/videofilter
+else
+check_videofilter =
+endif
+
+if USE_PLUGIN_VIDEOMIXER
+check_videomixer = elements/videomixer
+else
+check_videomixer =
+endif
+
+if USE_VPX
+check_vpx=elements/vp8enc elements/vp8dec elements/vp9enc
+else
+check_vpx=
+endif
+
+if USE_PLUGIN_WAVENC
+check_wavenc = pipelines/wavenc
+else
+check_wavenc =
+endif
+
+if USE_WAVPACK
+check_wavpack = \
+       elements/wavpackdec \
+       elements/wavpackenc \
+       pipelines/wavpack
+else
+check_wavpack =
+endif
+
+if USE_PLUGIN_WAVPARSE
+check_wavparse = elements/wavparse
+else
+check_wavparse =
+endif
+
+if USE_PLUGIN_Y4M
+check_y4m = elements/y4menc
+else
+check_y4m =
+endif
+
+if HAVE_ORC
+check_orc = orc/deinterlace orc/videomixer orc/videobox
+else
+check_orc =
+endif
+
+
+check_PROGRAMS = \
+	generic/states \
+	pipelines/simple-launch-lines \
+	pipelines/tagschecking \
+	$(check_alpha) \
+	$(check_audiofx) \
+	$(check_audioparsers) \
+	$(check_autodetect) \
+	$(check_avi) \
+	$(check_debugutils) \
+	$(check_deinterlace) \
+	$(check_dtmf) \
+	$(check_effectv) \
+	$(check_equalizer) \
+	$(check_flac) \
+	$(check_flv) \
+	$(check_gdkpixbuf) \
+	$(check_isomp4) \
+	$(check_icydemux) \
+	$(check_id3demux) \
+	$(check_imagefreeze) \
+	$(check_interleave) \
+	$(check_jpeg) \
+	$(check_lame) \
+	$(check_law) \
+	$(check_level) \
+	$(check_matroska) \
+	$(check_mpg123) \
+	$(check_multifile) \
+	$(check_replaygain) \
+	$(check_rtp) \
+	$(check_rtpmanager) \
+	$(check_shapewipe) \
+	$(check_soup) \
+	$(check_spectrum) \
+	$(check_taglib) \
+	$(check_twolame) \
+	$(check_udp) \
+	$(check_videobox) \
+	$(check_videocrop) \
+	$(check_videofilter) \
+	$(check_videomixer) \
+	$(check_vpx) \
+	$(check_wavenc) \
+	$(check_wavpack) \
+	$(check_wavparse) \
+	$(check_y4m) \
+	$(check_orc)
+
+VALGRIND_TO_FIX = \
+	elements/rtp-payloading
+
+TESTS = $(check_PROGRAMS)
+
+AM_CFLAGS = $(GST_OBJ_CFLAGS) $(GST_CHECK_CFLAGS) $(CHECK_CFLAGS) \
+	$(GST_OPTION_CFLAGS) $(GST_CFLAGS) -DGST_TEST_FILES_PATH="\"$(TEST_FILES_DIRECTORY)\"" \
+	-DGST_CHECK_TEST_ENVIRONMENT_BEACON="\"GST_PLUGIN_LOADING_WHITELIST\"" \
+	-UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS $(PTHREAD_CFLAGS)
+LDADD = $(GST_OBJ_LIBS) $(GST_CHECK_LIBS) $(CHECK_LIBS)
+
+# valgrind testing
+# videocrop disabled since it takes way too long in valgrind
+VALGRIND_TESTS_DISABLE = \
+	elements/videocrop \
+	$(VALGRIND_TO_FIX)
+
+SUPPRESSIONS = $(top_srcdir)/common/gst.supp $(srcdir)/gst-plugins-good.supp
+
+# parser unit test convenience lib
+noinst_LTLIBRARIES = libparser.la
+libparser_la_SOURCES = elements/parser.c elements/parser.h
+libparser_la_CFLAGS = \
+	-I$(top_srcdir)/tests/check \
+	$(AM_CFLAGS) -DGST_USE_UNSTABLE_API
+
+elements_aacparse_LDADD = libparser.la $(LDADD)
+
+elements_ac3parse_LDADD = libparser.la $(LDADD)
+
+elements_amrparse_LDADD = libparser.la $(LDADD)
+
+elements_flacparse_LDADD = libparser.la $(LDADD)
+
+elements_flvdemux_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_flvdemux_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_API_VERSION) $(LDADD)
+
+elements_mpegaudioparse_LDADD = libparser.la $(LDADD)
+
+elements_aspectratiocrop_LDADD = $(LDADD)
+elements_aspectratiocrop_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+
+elements_audioamplify_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_audioamplify_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD)
+
+elements_audiochebband_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_audiochebband_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD) $(LIBM)
+
+elements_audiocheblimit_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_audiocheblimit_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD) $(LIBM)
+
+elements_audiodynamic_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_audiodynamic_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD)
+
+elements_audioecho_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_audioecho_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD)
+
+elements_audioinvert_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_audioinvert_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD)
+
+elements_audiopanorama_LDADD = \
+	$(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(GST_BASE_LIBS) \
+	$(GST_CONTROLLER_LIBS) $(LDADD)
+
+elements_audiopanorama_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CONTROLLER_CFLAGS) \
+	$(CFLAGS) $(AM_CFLAGS)
+
+elements_audiowsincband_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_audiowsincband_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD) $(LIBM)
+
+elements_audiowsinclimit_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_audiowsinclimit_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD) $(LIBM)
+
+elements_autodetect_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_autodetect_LDADD = $(GST_BASE_LIBS) $(LDADD)
+
+elements_equalizer_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_equalizer_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD) $(LIBM)
+
+elements_rganalysis_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_rganalysis_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD)
+elements_rglimiter_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_rglimiter_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD)
+elements_rgvolume_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_rgvolume_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD) $(LIBM)
+
+elements_rtp_payloading_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_rtp_payloading_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(GST_BASE_LIBS) $(LDADD)
+
+elements_spectrum_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_spectrum_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD)
+
+elements_alphacolor_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_alpha_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+
+elements_deinterlace_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_deinterlace_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) $(LDADD)
+
+elements_dtmf_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS)
+elements_dtmf_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-@GST_API_VERSION@ \
+    $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD)
+
+elements_deinterleave_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_deinterleave_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD)
+elements_interleave_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_interleave_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD)
+
+elements_level_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_level_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD)
+
+elements_imagefreeze_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS)
+elements_imagefreeze_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) $(GST_BASE_LIBS) $(LDADD)
+
+elements_jpegdec_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GIO_CFLAGS) $(AM_CFLAGS)
+elements_jpegdec_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstapp-$(GST_API_VERSION) -lgstpbutils-$(GST_API_VERSION) $(GST_BASE_LIBS) $(GIO_LIBS) $(LDADD)
+
+elements_jpegenc_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS)
+elements_jpegenc_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstapp-$(GST_API_VERSION) $(GST_BASE_LIBS) $(LDADD)
+
+elements_matroskamux_LDADD = $(GST_BASE_LIBS) $(LDADD) $(LIBM)
+
+elements_mpg123audiodec_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS)
+elements_mpg123audiodec_LDADD = \
+	$(GST_PLUGINS_BASE_LIBS) -lgstaudio-@GST_API_VERSION@ -lgstfft-@GST_API_VERSION@ \
+	-lgstapp-@GST_API_VERSION@ $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD)
+
+elements_mulawdec_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS)
+
+elements_mulawenc_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS)
+
+elements_multifile_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS)
+elements_multifile_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) $(GST_LIBS) $(LDADD) $(LIBM)
+
+elements_splitmux_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS)
+elements_splitmux_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstapp-$(GST_API_VERSION) $(GST_LIBS) $(LDADD) $(LIBM)
+
+elements_qtmux_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS)
+elements_qtmux_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstpbutils-@GST_API_VERSION@ \
+             $(GST_BASE_LIBS) $(GST_LIBS) $(GST_CHECK_LIBS)
+
+elements_rtpbin_buffer_list_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \
+	$(WARNING_CFLAGS) $(ERROR_CFLAGS) $(GST_CHECK_CFLAGS) $(AM_CFLAGS)
+elements_rtpbin_buffer_list_LDADD = $(GST_PLUGINS_BASE_LIBS) \
+             -lgstrtp-$(GST_API_VERSION) \
+             $(GST_BASE_LIBS) $(GST_LIBS) $(GST_CHECK_LIBS) $(LDADD)
+elements_rtpbin_buffer_list_SOURCES = elements/rtpbin_buffer_list.c
+
+elements_rtpbin_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) \
+	$(WARNING_CFLAGS) $(ERROR_CFLAGS) $(GST_CHECK_CFLAGS) $(AM_CFLAGS)
+elements_rtpbin_LDADD = $(GST_PLUGINS_BASE_LIBS) \
+             -lgstrtp-$(GST_API_VERSION) \
+             $(GST_BASE_LIBS) $(GST_LIBS) $(GST_CHECK_LIBS) $(LDADD)
+
+elements_rtph261_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS)
+elements_rtph261_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-$(GST_API_VERSION) $(GST_BASE_LIBS) $(LDADD)
+
+elements_rtph263_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS)
+elements_rtph263_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-$(GST_API_VERSION) $(GST_BASE_LIBS) $(LDADD)
+
+elements_rtph264_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS)
+elements_rtph264_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstapp-$(GST_API_VERSION) $(GST_BASE_LIBS) $(LDADD)
+
+elements_rtpmux_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS)
+elements_rtpmux_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-$(GST_API_VERSION) $(GST_BASE_LIBS) $(LDADD)
+
+elements_souphttpsrc_CFLAGS = $(SOUP_CFLAGS) $(AM_CFLAGS)
+elements_souphttpsrc_LDADD = $(SOUP_LIBS) $(LDADD)
+
+elements_udpsink_CFLAGS = $(AM_CFLAGS) $(GIO_CFLAGS)
+elements_udpsink_LDADD = $(LDADD) $(GIO_LIBS)
+
+elements_udpsrc_CFLAGS = $(AM_CFLAGS) $(GIO_CFLAGS)
+elements_udpsrc_LDADD = $(LDADD) $(GIO_LIBS)
+
+elements_videocrop_LDADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) $(LDADD)
+elements_videocrop_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+
+elements_videofilter_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_videofilter_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) $(LDADD)
+
+elements_rtpjitterbuffer_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_rtpjitterbuffer_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-$(GST_API_VERSION) $(LDADD)
+
+elements_rtprtx_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_rtprtx_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-$(GST_API_VERSION) $(LDADD)
+
+elements_rtpsession_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_rtpsession_LDADD = $(GST_PLUGINS_BASE_LIBS) $(GST_NET_LIBS) -lgstrtp-$(GST_API_VERSION) $(GIO_LIBS) $(LDADD)
+
+elements_rtpcollision_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_rtpcollision_LDADD = $(GST_PLUGINS_BASE_LIBS) $(GST_NET_LIBS) -lgstrtp-$(GST_API_VERSION) $(GIO_LIBS) $(LDADD)
+
+elements_rtpaux_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_rtpaux_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-$(GST_API_VERSION) $(LDADD)
+
+elements_rtpbundle_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_rtpbundle_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-$(GST_API_VERSION) $(LDADD)
+
+# FIXME: configure should check for gdk-pixbuf not gtk
+# only need video.h header, not the lib
+elements_gdkpixbufsink_CFLAGS = \
+	$(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS) $(GDK_PIXBUF_CFLAGS)
+elements_gdkpixbufsink_LDADD = \
+	$(LDADD) $(GDK_PIXBUF_LIBS)
+
+elements_videomixer_LDADD = $(LDADD)  $(GST_BASE_LIBS)
+elements_videomixer_CFLAGS = $(GST_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+
+pipelines_flacdec_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+pipelines_flacdec_LDADD  = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD)
+
+elements_vp9enc_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_vp9enc_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) $(LDADD)
+
+pipelines_wavenc_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+pipelines_wavenc_LDADD  = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD)
+
+pipelines_wavpack_LDADD = $(LDADD) $(GST_BASE_LIBS)
+pipelines_wavpack_CFLAGS = $(GST_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+
+orc_deinterlace_CFLAGS = $(ORC_CFLAGS)
+orc_deinterlace_LDADD = $(ORC_LIBS) -lorc-test-0.4
+nodist_orc_deinterlace_SOURCES = orc/deinterlace.c
+orc_videomixer_CFLAGS = $(ORC_CFLAGS)
+orc_videomixer_LDADD = $(ORC_LIBS) -lorc-test-0.4
+nodist_orc_videomixer_SOURCES = orc/videomixer.c
+orc_videobox_CFLAGS = $(ORC_CFLAGS)
+orc_videobox_LDADD = $(ORC_LIBS) -lorc-test-0.4
+nodist_orc_videobox_SOURCES = orc/videobox.c
+
+orc/deinterlace.c: $(top_srcdir)/gst/deinterlace/tvtime.orc
+	$(MKDIR_P) orc/
+	$(ORCC) --test -o $@ $<
+
+orc/videomixer.c: $(top_srcdir)/gst/videomixer/videomixerorc.orc
+	$(MKDIR_P) orc/
+	$(ORCC) --test -o $@ $<
+
+orc/videobox.c: $(top_srcdir)/gst/videobox/gstvideoboxorc.orc
+	$(MKDIR_P) orc/
+	$(ORCC) --test -o $@ $<
+
+distclean-local-orc:
+	rm -rf orc
+
+EXTRA_DIST = \
+	gst-plugins-good.supp	\
+	elements/qtdemux.h
diff --git a/tests/check/elements/.gitignore b/tests/check/elements/.gitignore
new file mode 100644
index 0000000..9632475
--- /dev/null
+++ b/tests/check/elements/.gitignore
@@ -0,0 +1,85 @@
+.dirstamp
+aacparse
+ac3parse
+alpha
+alphacolor
+amrparse
+apev2mux
+aspectratiocrop
+audioamplify
+audiochebband
+audiocheblimit
+audioecho
+audiowsincband
+audiowsinclimit
+audiodynamic
+audiofirfilter
+audioinvert
+audioiirfilter
+audiopanorama
+autodetect
+avimux
+avisubtitle
+capssetter
+deinterlace
+deinterleave
+dtmf
+equalizer
+gdkpixbufoverlay
+gdkpixbufsink
+flacparse
+flvdemux
+flvmux
+icydemux
+id3demux
+id3v2mux
+imagefreeze
+interleave
+jpegdec
+jpegenc
+level
+matroskademux
+matroskamux
+matroskaparse
+mpegaudioparse
+mpg123audiodec
+mulawdec
+mulawenc
+multifile
+qtdemux
+qtmux
+rganalysis
+rglimiter
+rgvolume
+rtp-payloading
+rtpaux
+rtpbin
+rtpbin_buffer_list
+rtpbundle
+rtpcollision
+rtph261
+rtph263
+rtph264
+rtpjitterbuffer
+rtpsession
+rtpmux
+rtprtx
+rtpvp9
+shapewipe
+souphttpsrc
+spectrum
+splitmux
+udpsink
+udpsrc
+videocrop
+videobox
+videofilter
+videomixer
+vp8dec
+vp8enc
+vp9enc
+wavpackdec
+wavparse
+wavpackenc
+wavpackparse
+y4menc
diff --git a/tests/check/elements/aacparse.c b/tests/check/elements/aacparse.c
new file mode 100644
index 0000000..ea9fd7e
--- /dev/null
+++ b/tests/check/elements/aacparse.c
@@ -0,0 +1,318 @@
+/*
+ * GStreamer
+ *
+ * unit test for aacparse
+ *
+ * Copyright (C) 2008 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/check/check.h>
+#include "parser.h"
+
+#define SRC_CAPS_CDATA "audio/mpeg, mpegversion=(int)4, framed=(boolean)false, codec_data=(buffer)1190"
+#define SRC_CAPS_TMPL  "audio/mpeg, framed=(boolean)false, mpegversion=(int){2,4}"
+#define SRC_CAPS_RAW   "audio/mpeg, mpegversion=(int)4, framed=(boolean)true, stream-format=(string)raw, rate=(int)48000, channels=(int)2, codec_data=(buffer)1190"
+
+#define SINK_CAPS \
+    "audio/mpeg, framed=(boolean)true"
+#define SINK_CAPS_MPEG2 \
+    "audio/mpeg, framed=(boolean)true, mpegversion=2, rate=48000, channels=2"
+#define SINK_CAPS_MPEG4 \
+    "audio/mpeg, framed=(boolean)true, mpegversion=4, rate=96000, channels=2"
+#define SINK_CAPS_TMPL  "audio/mpeg, framed=(boolean)true, mpegversion=(int){2,4}"
+
+GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SINK_CAPS_TMPL)
+    );
+
+GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SRC_CAPS_TMPL)
+    );
+
+/* some data */
+static guint8 adif_header[] = {
+  'A', 'D', 'I', 'F'
+};
+
+static guint8 adts_frame_mpeg2[] = {
+  0xff, 0xf9, 0x4c, 0x80, 0x01, 0xff, 0xfc, 0x21, 0x10, 0xd3, 0x20, 0x0c,
+  0x32, 0x00, 0xc7
+};
+
+static guint8 adts_frame_mpeg4[] = {
+  0xff, 0xf1, 0x4c, 0x80, 0x01, 0xff, 0xfc, 0x21, 0x10, 0xd3, 0x20, 0x0c,
+  0x32, 0x00, 0xc7
+};
+
+static guint8 garbage_frame[] = {
+  0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static guint8 raw_frame_short[] = {
+  0x27, 0x00, 0x03, 0x20, 0x64, 0x1c
+};
+
+/*
+ * Test if the parser pushes data with ADIF header properly and detects the
+ * stream to MPEG4 properly.
+ */
+GST_START_TEST (test_parse_adif_normal)
+{
+  GstParserTest ptest;
+
+  /* ADIF header */
+  gst_parser_test_init (&ptest, adif_header, sizeof (adif_header), 1);
+  /* well, no garbage, followed by random data */
+  ptest.series[2].size = 100;
+  ptest.series[2].num = 3;
+  /* and we do not really expect output frames */
+  ptest.framed = FALSE;
+  /* Check that the negotiated caps are as expected */
+  /* For ADIF parser assumes that data is always version 4 */
+  ptest.sink_caps =
+      gst_caps_from_string (SINK_CAPS_MPEG4 ", stream-format=(string)adif");
+
+  gst_parser_test_run (&ptest, NULL);
+
+  gst_caps_unref (ptest.sink_caps);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_adts_normal)
+{
+  gst_parser_test_normal (adts_frame_mpeg4, sizeof (adts_frame_mpeg4));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_adts_drain_single)
+{
+  gst_parser_test_drain_single (adts_frame_mpeg4, sizeof (adts_frame_mpeg4));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_adts_drain_garbage)
+{
+  gst_parser_test_drain_garbage (adts_frame_mpeg4, sizeof (adts_frame_mpeg4),
+      garbage_frame, sizeof (garbage_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_adts_split)
+{
+  gst_parser_test_split (adts_frame_mpeg4, sizeof (adts_frame_mpeg4));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_adts_skip_garbage)
+{
+  gst_parser_test_skip_garbage (adts_frame_mpeg4, sizeof (adts_frame_mpeg4),
+      garbage_frame, sizeof (garbage_frame));
+}
+
+GST_END_TEST;
+
+
+/*
+ * Test if the src caps are set according to stream format (MPEG version).
+ */
+GST_START_TEST (test_parse_adts_detect_mpeg_version)
+{
+  gst_parser_test_output_caps (adts_frame_mpeg2, sizeof (adts_frame_mpeg2),
+      NULL,
+      SINK_CAPS_MPEG2
+      ", stream-format=(string)adts, level=(string)2, profile=(string)lc");
+}
+
+GST_END_TEST;
+
+/*
+ * Test if the parser correctly handles short raw frames and doesn't
+ * concatenate them.
+ */
+GST_START_TEST (test_parse_raw_short)
+{
+  GstHarness *h = gst_harness_new ("aacparse");
+  GstBuffer *in_buf;
+
+  g_object_set (h->element, "disable-passthrough", TRUE, NULL);
+  gst_harness_set_src_caps_str (h, SRC_CAPS_RAW);
+
+  in_buf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+      raw_frame_short, sizeof raw_frame_short, 0, sizeof raw_frame_short,
+      NULL, NULL);
+
+  gst_harness_push (h, gst_buffer_ref (in_buf));
+  fail_unless_equals_int (gst_harness_buffers_received (h), 1);
+
+  gst_harness_push (h, in_buf);
+  fail_unless_equals_int (gst_harness_buffers_received (h), 2);
+
+  gst_harness_push_event (h, gst_event_new_eos ());
+  fail_unless_equals_int (gst_harness_buffers_received (h), 2);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+#define structure_get_int(s,f) \
+    (g_value_get_int(gst_structure_get_value(s,f)))
+#define fail_unless_structure_field_int_equals(s,field,num) \
+    fail_unless_equals_int (structure_get_int(s,field), num)
+/*
+ * Test if the parser handles raw stream and codec_data info properly.
+ */
+GST_START_TEST (test_parse_handle_codec_data)
+{
+  GstCaps *caps;
+  GstStructure *s;
+  const gchar *stream_format;
+
+  /* Push random data. It should get through since the parser should be
+   * initialized because it got codec_data in the caps */
+  caps = gst_parser_test_get_output_caps (NULL, 100, SRC_CAPS_CDATA);
+  fail_unless (caps != NULL);
+
+  /* Check that the negotiated caps are as expected */
+  /* When codec_data is present, parser assumes that data is version 4 */
+  GST_LOG ("aac output caps: %" GST_PTR_FORMAT, caps);
+  s = gst_caps_get_structure (caps, 0);
+  fail_unless (gst_structure_has_name (s, "audio/mpeg"));
+  fail_unless_structure_field_int_equals (s, "mpegversion", 4);
+  fail_unless_structure_field_int_equals (s, "channels", 2);
+  fail_unless_structure_field_int_equals (s, "rate", 48000);
+  fail_unless (gst_structure_has_field (s, "codec_data"));
+  fail_unless (gst_structure_has_field (s, "stream-format"));
+  stream_format = gst_structure_get_string (s, "stream-format");
+  fail_unless (strcmp (stream_format, "raw") == 0);
+
+  gst_caps_unref (caps);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_parse_proxy_constraints)
+{
+  GstCaps *caps, *resultcaps;
+  GstElement *parse, *filter;
+  GstPad *sinkpad;
+  GstStructure *s;
+
+  parse = gst_element_factory_make ("aacparse", NULL);
+  filter = gst_element_factory_make ("capsfilter", NULL);
+
+  /* constraint on rate and version */
+  caps = gst_caps_from_string ("audio/mpeg,mpegversion=2,rate=44100");
+  g_object_set (filter, "caps", caps, NULL);
+  gst_caps_unref (caps);
+
+  gst_element_link (parse, filter);
+
+  sinkpad = gst_element_get_static_pad (parse, "sink");
+  caps = gst_pad_query_caps (sinkpad, NULL);
+  GST_LOG ("caps %" GST_PTR_FORMAT, caps);
+
+  fail_unless (gst_caps_get_size (caps) == 1);
+
+  /* getcaps should proxy the rate constraint */
+  s = gst_caps_get_structure (caps, 0);
+  fail_unless (gst_structure_has_name (s, "audio/mpeg"));
+  fail_unless_structure_field_int_equals (s, "rate", 44100);
+  gst_caps_unref (caps);
+
+  /* should accept without the constraint */
+  caps = gst_caps_from_string ("audio/mpeg,mpegversion=2");
+  resultcaps = gst_pad_query_caps (sinkpad, caps);
+  fail_if (gst_caps_is_empty (resultcaps));
+  gst_caps_unref (resultcaps);
+  gst_caps_unref (caps);
+
+  /* should not accept with conflicting version */
+  caps = gst_caps_from_string ("audio/mpeg,mpegversion=4");
+  resultcaps = gst_pad_query_caps (sinkpad, caps);
+  fail_unless (gst_caps_is_empty (resultcaps));
+  gst_caps_unref (resultcaps);
+  gst_caps_unref (caps);
+
+  gst_object_unref (sinkpad);
+
+  gst_object_unref (filter);
+  gst_object_unref (parse);
+}
+
+GST_END_TEST;
+
+static Suite *
+aacparse_suite (void)
+{
+  Suite *s = suite_create ("aacparse");
+  TCase *tc_chain = tcase_create ("general");
+
+  /* init test context */
+  ctx_factory = "aacparse";
+  ctx_sink_template = &sinktemplate;
+  ctx_src_template = &srctemplate;
+
+  suite_add_tcase (s, tc_chain);
+  /* ADIF tests */
+  tcase_add_test (tc_chain, test_parse_adif_normal);
+
+  /* ADTS tests */
+  tcase_add_test (tc_chain, test_parse_adts_normal);
+  tcase_add_test (tc_chain, test_parse_adts_drain_single);
+  tcase_add_test (tc_chain, test_parse_adts_drain_garbage);
+  tcase_add_test (tc_chain, test_parse_adts_split);
+  tcase_add_test (tc_chain, test_parse_adts_skip_garbage);
+  tcase_add_test (tc_chain, test_parse_adts_detect_mpeg_version);
+
+  /* Raw tests */
+  tcase_add_test (tc_chain, test_parse_raw_short);
+
+  /* Other tests */
+  tcase_add_test (tc_chain, test_parse_handle_codec_data);
+
+  /* caps tests */
+  tcase_add_test (tc_chain, test_parse_proxy_constraints);
+
+  return s;
+}
+
+
+/*
+ * TODO:
+ *   - Both push- and pull-modes need to be tested
+ *      * Pull-mode & EOS
+ */
+GST_CHECK_MAIN (aacparse);
diff --git a/tests/check/elements/ac3parse.c b/tests/check/elements/ac3parse.c
new file mode 100644
index 0000000..1bbe59b
--- /dev/null
+++ b/tests/check/elements/ac3parse.c
@@ -0,0 +1,147 @@
+/*
+ * GStreamer
+ *
+ * unit test for ac3parse
+ *
+ * Copyright (C) 2008 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include "parser.h"
+
+#define SRC_CAPS_TMPL   "audio/x-ac3, framed=(boolean)false"
+#define SINK_CAPS_TMPL  "audio/x-ac3, framed=(boolean)true"
+
+GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SINK_CAPS_TMPL)
+    );
+
+GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SRC_CAPS_TMPL)
+    );
+
+/* some data */
+
+static guint8 ac3_frame[512] = {
+  0x0b, 0x77, 0xb6, 0xa8, 0x10, 0x40, 0x2f, 0x84,
+  0x29, 0xcb, 0xfe, 0x75, 0x7c, 0xf9, 0xf3, 0xe7,
+  0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf,
+  0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f,
+  0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e,
+  0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c,
+  0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9,
+  0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3,
+  0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7,
+  0xcf, 0x9f, 0x3e, 0x32, 0xd3, 0xff, 0xc0, 0x06,
+  0xe9, 0x40, 0x00, 0x6e, 0x94, 0x00, 0x06, 0xe9,
+  0x40, 0x00, 0x6e, 0x94, 0x00, 0x06, 0xe9, 0x40,
+  0x00, 0x6e, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static guint8 garbage_frame[] = {
+  0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+
+GST_START_TEST (test_parse_normal)
+{
+  gst_parser_test_normal (ac3_frame, sizeof (ac3_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_drain_single)
+{
+  gst_parser_test_drain_single (ac3_frame, sizeof (ac3_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_drain_garbage)
+{
+  gst_parser_test_drain_garbage (ac3_frame, sizeof (ac3_frame),
+      garbage_frame, sizeof (garbage_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_split)
+{
+  gst_parser_test_split (ac3_frame, sizeof (ac3_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_skip_garbage)
+{
+  gst_parser_test_skip_garbage (ac3_frame, sizeof (ac3_frame),
+      garbage_frame, sizeof (garbage_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_detect_stream)
+{
+  gst_parser_test_output_caps (ac3_frame, sizeof (ac3_frame),
+      NULL, SINK_CAPS_TMPL ",channels=1,rate=48000,alignment=frame");
+}
+
+GST_END_TEST;
+
+
+static Suite *
+ac3parse_suite (void)
+{
+  Suite *s = suite_create ("ac3parse");
+  TCase *tc_chain = tcase_create ("general");
+
+  /* init test context */
+  ctx_factory = "ac3parse";
+  ctx_sink_template = &sinktemplate;
+  ctx_src_template = &srctemplate;
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_parse_normal);
+  tcase_add_test (tc_chain, test_parse_drain_single);
+  tcase_add_test (tc_chain, test_parse_drain_garbage);
+  tcase_add_test (tc_chain, test_parse_split);
+  tcase_add_test (tc_chain, test_parse_skip_garbage);
+  tcase_add_test (tc_chain, test_parse_detect_stream);
+
+  return s;
+}
+
+
+/*
+ * TODO:
+ *   - Both push- and pull-modes need to be tested
+ *      * Pull-mode & EOS
+ */
+GST_CHECK_MAIN (ac3parse);
diff --git a/tests/check/elements/alpha.c b/tests/check/elements/alpha.c
new file mode 100644
index 0000000..7c03bc1
--- /dev/null
+++ b/tests/check/elements/alpha.c
@@ -0,0 +1,265 @@
+/* GStreamer unit test for the alpha element
+ *
+ * Copyright (C) 2007 Ravi Kiran K N <ravi.kiran@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/video/video.h>
+
+
+GstPad *srcpad, *sinkpad;
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("AYUV"))
+    );
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, "
+            "ARGB, BGRA, ABGR, RGBA, Y444, xRGB, BGRx, xBGR, "
+            "RGBx, RGB, BGR, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B } "))
+    );
+
+
+typedef enum
+{
+  FILL_GREEN,
+  FILL_BLUE
+}
+FillColor;
+
+static GstElement *
+setup_alpha (void)
+{
+  GstElement *alpha;
+
+  alpha = gst_check_setup_element ("alpha");
+  srcpad = gst_check_setup_src_pad (alpha, &srctemplate);
+  sinkpad = gst_check_setup_sink_pad (alpha, &sinktemplate);
+
+  gst_pad_set_active (srcpad, TRUE);
+  gst_pad_set_active (sinkpad, TRUE);
+
+  return alpha;
+}
+
+static void
+cleanup_alpha (GstElement * alpha)
+{
+  gst_pad_set_active (srcpad, FALSE);
+  gst_pad_set_active (sinkpad, FALSE);
+  gst_check_teardown_src_pad (alpha);
+  gst_check_teardown_sink_pad (alpha);
+  gst_check_teardown_element (alpha);
+}
+
+#define WIDTH 3
+#define HEIGHT 4
+
+static GstCaps *
+create_caps_rgba32 (void)
+{
+  GstCaps *caps;
+
+  caps = gst_caps_new_simple ("video/x-raw",
+      "width", G_TYPE_INT, WIDTH,
+      "height", G_TYPE_INT, HEIGHT,
+      "framerate", GST_TYPE_FRACTION, 0, 1,
+      "format", G_TYPE_STRING, "RGBA", NULL);
+
+  return caps;
+}
+
+static GstBuffer *
+create_buffer_rgba32 (FillColor color)
+{
+  guint8 rgba32_img[HEIGHT * WIDTH * 4];
+  guint32 *rgba32 = (guint32 *) rgba32_img;
+
+  GstBuffer *buf;
+  GstMapInfo map;
+  guint32 rgba_col;
+  int i;
+
+  if (color == FILL_GREEN)
+    rgba_col = 0xff00ff00;      /* GREEN */
+  else
+    rgba_col = 0xffff0000;      /* BLUE */
+
+  for (i = 0; i < HEIGHT * WIDTH; i++)
+    rgba32[i] = rgba_col;
+
+  buf = gst_buffer_new_and_alloc (HEIGHT * WIDTH * 4);
+  gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+  fail_unless_equals_int (map.size, sizeof (rgba32_img));
+  memcpy (map.data, rgba32_img, sizeof (rgba32_img));
+
+  gst_buffer_unmap (buf, &map);
+
+  return buf;
+}
+
+
+GST_START_TEST (test_chromakeying)
+{
+  GstElement *alpha;
+  GstBuffer *inbuffer;
+  GstBuffer *outbuffer;
+  GstCaps *incaps;
+  guint8 *ayuv;
+  guint outlength;
+  GstMapInfo map;
+  int i;
+
+  incaps = create_caps_rgba32 ();
+
+  alpha = setup_alpha ();
+
+  g_object_set (alpha, "method", 1, NULL);      /* Chroma-keying GREEN */
+
+  fail_unless_equals_int (gst_element_set_state (alpha, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_SUCCESS);
+
+  gst_check_setup_events (srcpad, alpha, incaps, GST_FORMAT_TIME);
+
+  inbuffer = create_buffer_rgba32 (FILL_GREEN);
+  GST_DEBUG ("Created buffer of %" G_GSIZE_FORMAT " bytes",
+      gst_buffer_get_size (inbuffer));
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  fail_unless_equals_int (gst_pad_push (srcpad, inbuffer), GST_FLOW_OK);
+
+  fail_unless (g_list_length (buffers) == 1);
+  outbuffer = (GstBuffer *) buffers->data;
+  fail_if (outbuffer == NULL);
+  fail_unless (GST_IS_BUFFER (outbuffer));
+
+  ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
+  outlength = WIDTH * HEIGHT * 4;       /* output is AYUV */
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  fail_unless_equals_int (map.size, outlength);
+
+  ayuv = map.data;
+
+  /* check chroma keying GREEN */
+  for (i = 0; i < HEIGHT * WIDTH; i += 4)
+    fail_unless_equals_int (ayuv[i], 0x00);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  buffers = g_list_remove (buffers, outbuffer);
+  gst_buffer_unref (outbuffer);
+
+  fail_unless_equals_int (gst_element_set_state (alpha, GST_STATE_NULL),
+      GST_STATE_CHANGE_SUCCESS);
+
+  /* cleanup */
+  cleanup_alpha (alpha);
+  ASSERT_CAPS_REFCOUNT (incaps, "incaps", 1);
+  gst_caps_unref (incaps);
+
+}
+
+GST_END_TEST;
+
+
+
+GST_START_TEST (test_alpha)
+{
+  GstElement *alpha;
+  GstBuffer *inbuffer;
+  GstBuffer *outbuffer;
+  GstCaps *incaps;
+  guint8 *ayuv;
+  guint outlength;
+  GstMapInfo map;
+  int i;
+
+  incaps = create_caps_rgba32 ();
+
+  alpha = setup_alpha ();
+
+  g_object_set (alpha, "alpha", 0.5, NULL);     /* Alpha value 0.5 */
+
+  fail_unless_equals_int (gst_element_set_state (alpha, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_SUCCESS);
+
+  gst_check_setup_events (srcpad, alpha, incaps, GST_FORMAT_TIME);
+
+  inbuffer = create_buffer_rgba32 (FILL_BLUE);
+  GST_DEBUG ("Created buffer of %" G_GSIZE_FORMAT " bytes",
+      gst_buffer_get_size (inbuffer));
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away reference */
+  GST_DEBUG ("push it");
+  fail_unless_equals_int (gst_pad_push (srcpad, inbuffer), GST_FLOW_OK);
+  GST_DEBUG ("pushed it");
+
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) == 1);
+  outbuffer = (GstBuffer *) buffers->data;
+  fail_if (outbuffer == NULL);
+  fail_unless (GST_IS_BUFFER (outbuffer));
+
+  ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
+  outlength = WIDTH * HEIGHT * 4;       /* output is AYUV */
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  fail_unless_equals_int (map.size, outlength);
+
+  ayuv = map.data;
+
+  for (i = 0; i < HEIGHT * WIDTH; i += 4)
+    fail_unless_equals_int (ayuv[i], 0x7F);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  buffers = g_list_remove (buffers, outbuffer);
+  gst_buffer_unref (outbuffer);
+
+  fail_unless_equals_int (gst_element_set_state (alpha, GST_STATE_NULL),
+      GST_STATE_CHANGE_SUCCESS);
+
+  /* cleanup */
+  GST_DEBUG ("cleanup alpha");
+  cleanup_alpha (alpha);
+  GST_DEBUG ("cleanup, unref incaps");
+  ASSERT_CAPS_REFCOUNT (incaps, "incaps", 1);
+  gst_caps_unref (incaps);
+
+}
+
+GST_END_TEST;
+
+
+static Suite *
+alpha_suite (void)
+{
+  Suite *s = suite_create ("alpha");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_alpha);
+  tcase_add_test (tc_chain, test_chromakeying);
+
+  return s;
+}
+
+GST_CHECK_MAIN (alpha);
diff --git a/tests/check/elements/alphacolor.c b/tests/check/elements/alphacolor.c
new file mode 100644
index 0000000..15496d8
--- /dev/null
+++ b/tests/check/elements/alphacolor.c
@@ -0,0 +1,288 @@
+/* GStreamer unit test for the alphacolor element
+ *
+ * Copyright (C) 2007 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/video/video.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *mysrcpad, *mysinkpad;
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("AYUV"))
+    );
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBA, RGB }"))
+    );
+
+static GstElement *
+setup_alphacolor (void)
+{
+  GstElement *alphacolor;
+
+  alphacolor = gst_check_setup_element ("alphacolor");
+  mysrcpad = gst_check_setup_src_pad (alphacolor, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (alphacolor, &sinktemplate);
+
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return alphacolor;
+}
+
+static void
+cleanup_alphacolor (GstElement * alphacolor)
+{
+  GST_DEBUG ("cleaning up");
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (alphacolor);
+  gst_check_teardown_sink_pad (alphacolor);
+  gst_check_teardown_element (alphacolor);
+}
+
+#define WIDTH 3
+#define HEIGHT 4
+
+static GstCaps *
+create_caps_rgb24 (void)
+{
+  GstCaps *caps;
+
+  caps = gst_caps_new_simple ("video/x-raw",
+      "width", G_TYPE_INT, 3,
+      "height", G_TYPE_INT, 4,
+      "framerate", GST_TYPE_FRACTION, 0, 1,
+      "format", G_TYPE_STRING, "RGB", NULL);
+
+  return caps;
+}
+
+static GstCaps *
+create_caps_rgba32 (void)
+{
+  GstCaps *caps;
+
+  caps = gst_caps_new_simple ("video/x-raw",
+      "width", G_TYPE_INT, 3,
+      "height", G_TYPE_INT, 4,
+      "framerate", GST_TYPE_FRACTION, 0, 1,
+      "format", G_TYPE_STRING, "RGBA", NULL);
+
+  return caps;
+}
+
+static GstBuffer *
+create_buffer_rgb24_3x4 (void)
+{
+  /* stride is rounded up to multiple of 4, so 3 bytes padding for each row */
+  const guint8 rgb24_3x4_img[HEIGHT * GST_ROUND_UP_4 (WIDTH * 3)] = {
+    0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+    0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00
+  };
+  guint rowstride = GST_ROUND_UP_4 (WIDTH * 3);
+  GstBuffer *buf;
+  GstMapInfo info;
+
+  buf = gst_buffer_new_and_alloc (HEIGHT * rowstride);
+  gst_buffer_map (buf, &info, GST_MAP_READWRITE);
+  fail_unless_equals_int (info.size, sizeof (rgb24_3x4_img));
+  memcpy (info.data, rgb24_3x4_img, sizeof (rgb24_3x4_img));
+
+  gst_buffer_unmap (buf, &info);
+
+  return buf;
+}
+
+static GstBuffer *
+create_buffer_rgba32_3x4 (void)
+{
+  /* stride is rounded up to multiple of 4, so 3 bytes padding for each row */
+  /* should be:  RED     BLUE    WHITE    where 'nothing' is fully transparent
+   *             GREEN   RED     BLUE     and all other colours are fully
+   *             NOTHING GREEN   RED      opaque.
+   *             BLACK   NOTHING GREEN
+   */
+  const guint8 rgba32_3x4_img[HEIGHT * WIDTH * 4] = {
+    0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+    0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff
+  };
+  guint rowstride = WIDTH * 4;
+  GstBuffer *buf;
+  GstMapInfo map;
+
+  buf = gst_buffer_new_and_alloc (HEIGHT * rowstride);
+  gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+  fail_unless_equals_int (map.size, sizeof (rgba32_3x4_img));
+  memcpy (map.data, rgba32_3x4_img, sizeof (rgba32_3x4_img));
+
+  gst_buffer_unmap (buf, &map);
+
+  return buf;
+}
+
+GST_START_TEST (test_rgb24)
+{
+  GstElement *alphacolor;
+  GstBuffer *inbuffer;
+  GstCaps *incaps;
+
+  incaps = create_caps_rgb24 ();
+  alphacolor = setup_alphacolor ();
+
+  fail_unless_equals_int (gst_element_set_state (alphacolor, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_SUCCESS);
+
+  gst_check_setup_events (mysrcpad, alphacolor, incaps, GST_FORMAT_TIME);
+
+  inbuffer = create_buffer_rgb24_3x4 ();
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away reference; this should error out with a not-negotiated
+   * error, alphacolor should only accept RGBA caps, not but plain RGB24 caps */
+  GST_DEBUG ("push it");
+  fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer),
+      GST_FLOW_NOT_NEGOTIATED);
+  GST_DEBUG ("pushed it");
+
+  fail_unless (g_list_length (buffers) == 0);
+
+  fail_unless_equals_int (gst_element_set_state (alphacolor, GST_STATE_NULL),
+      GST_STATE_CHANGE_SUCCESS);
+
+  /* cleanup */
+  GST_DEBUG ("cleanup alphacolor");
+  cleanup_alphacolor (alphacolor);
+  GST_DEBUG ("cleanup, unref incaps");
+  ASSERT_CAPS_REFCOUNT (incaps, "incaps", 1);
+  gst_caps_unref (incaps);
+}
+
+GST_END_TEST;
+
+/* these macros assume WIDTH and HEIGHT is fixed to what's defined above */
+#define fail_unless_ayuv_pixel_has_alpha(ayuv,x,y,a) \
+    { \
+        guint8 *pixel; \
+        pixel = ((guint8*)(ayuv) + ((WIDTH * 4) * (y)) + ((x) * 4)); \
+        fail_unless_equals_int (pixel[0], a); \
+    }
+
+GST_START_TEST (test_rgba32)
+{
+  GstElement *alphacolor;
+  GstBuffer *inbuffer;
+  GstBuffer *outbuffer;
+  GstCaps *incaps;
+  guint8 *ayuv;
+  guint outlength;
+  GstMapInfo map;
+
+  incaps = create_caps_rgba32 ();
+  alphacolor = setup_alphacolor ();
+
+  fail_unless_equals_int (gst_element_set_state (alphacolor, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_SUCCESS);
+
+  gst_check_setup_events (mysrcpad, alphacolor, incaps, GST_FORMAT_TIME);
+
+  inbuffer = create_buffer_rgba32_3x4 ();
+  GST_DEBUG ("Created buffer of %" G_GSIZE_FORMAT " bytes",
+      gst_buffer_get_size (inbuffer));
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away reference */
+  GST_DEBUG ("push it");
+  fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
+  GST_DEBUG ("pushed it");
+
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) == 1);
+  outbuffer = (GstBuffer *) buffers->data;
+  fail_if (outbuffer == NULL);
+  fail_unless (GST_IS_BUFFER (outbuffer));
+
+  ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
+  outlength = WIDTH * HEIGHT * 4;       /* output is AYUV */
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  fail_unless_equals_int (map.size, outlength);
+
+  ayuv = map.data;
+
+  /* check alpha values (0x00 = totally transparent, 0xff = totally opaque) */
+  fail_unless_ayuv_pixel_has_alpha (ayuv, 0, 0, 0xff);
+  fail_unless_ayuv_pixel_has_alpha (ayuv, 1, 0, 0xff);
+  fail_unless_ayuv_pixel_has_alpha (ayuv, 2, 0, 0xff);
+  fail_unless_ayuv_pixel_has_alpha (ayuv, 0, 1, 0xff);
+  fail_unless_ayuv_pixel_has_alpha (ayuv, 1, 1, 0xff);
+  fail_unless_ayuv_pixel_has_alpha (ayuv, 2, 1, 0xff);
+  fail_unless_ayuv_pixel_has_alpha (ayuv, 0, 2, 0x00);
+  fail_unless_ayuv_pixel_has_alpha (ayuv, 1, 2, 0xff);
+  fail_unless_ayuv_pixel_has_alpha (ayuv, 2, 2, 0xff);
+  fail_unless_ayuv_pixel_has_alpha (ayuv, 0, 3, 0xff);
+  fail_unless_ayuv_pixel_has_alpha (ayuv, 1, 3, 0x00);
+  fail_unless_ayuv_pixel_has_alpha (ayuv, 2, 3, 0xff);
+
+  /* we don't check the YUV data, because apparently results differ slightly
+   * depending on whether we run in valgrind or not */
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  buffers = g_list_remove (buffers, outbuffer);
+  gst_buffer_unref (outbuffer);
+
+  fail_unless_equals_int (gst_element_set_state (alphacolor, GST_STATE_NULL),
+      GST_STATE_CHANGE_SUCCESS);
+
+  /* cleanup */
+  GST_DEBUG ("cleanup alphacolor");
+  cleanup_alphacolor (alphacolor);
+  GST_DEBUG ("cleanup, unref incaps");
+  ASSERT_CAPS_REFCOUNT (incaps, "incaps", 1);
+  gst_caps_unref (incaps);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+alphacolor_suite (void)
+{
+  Suite *s = suite_create ("alphacolor");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_rgb24);
+  tcase_add_test (tc_chain, test_rgba32);
+
+  return s;
+}
+
+GST_CHECK_MAIN (alphacolor);
diff --git a/tests/check/elements/amrparse.c b/tests/check/elements/amrparse.c
new file mode 100644
index 0000000..29fffa3
--- /dev/null
+++ b/tests/check/elements/amrparse.c
@@ -0,0 +1,306 @@
+/*
+ * GStreamer
+ *
+ * unit test for amrparse
+ *
+ * Copyright (C) 2008 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include "parser.h"
+
+#define SRC_CAPS_NB  "audio/x-amr-nb-sh"
+#define SRC_CAPS_WB  "audio/x-amr-wb-sh"
+#define SRC_CAPS_ANY "ANY"
+
+#define SINK_CAPS_NB  "audio/AMR, rate=8000 , channels=1"
+#define SINK_CAPS_WB  "audio/AMR-WB, rate=16000 , channels=1"
+#define SINK_CAPS_ANY "ANY"
+
+#define AMR_FRAME_DURATION (GST_SECOND/50)
+
+static GstStaticPadTemplate sinktemplate_nb = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SINK_CAPS_NB)
+    );
+
+static GstStaticPadTemplate sinktemplate_wb = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SINK_CAPS_WB)
+    );
+
+static GstStaticPadTemplate srctemplate_nb = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SRC_CAPS_NB)
+    );
+
+static GstStaticPadTemplate srctemplate_wb = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SRC_CAPS_WB)
+    );
+
+static GstCaps *input_caps = NULL;
+
+/* some data */
+
+static guint8 frame_data_nb[] = {
+  0x0c, 0x56, 0x3c, 0x52, 0xe0, 0x61, 0xbc, 0x45,
+  0x0f, 0x98, 0x2e, 0x01, 0x42, 0x02
+};
+
+static guint8 frame_data_wb[] = {
+  0x08, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+  0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+  0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16
+};
+
+static guint8 frame_hdr_nb[] = {
+  '#', '!', 'A', 'M', 'R', '\n'
+};
+
+static guint8 frame_hdr_wb[] = {
+  '#', '!', 'A', 'M', 'R', '-', 'W', 'B', '\n'
+};
+
+static guint8 garbage_frame[] = {
+  0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static void
+setup_amrnb (void)
+{
+  ctx_factory = "amrparse";
+  ctx_sink_template = &sinktemplate_nb;
+  ctx_src_template = &srctemplate_nb;
+  input_caps = gst_caps_from_string (SRC_CAPS_NB);
+  g_assert (input_caps);
+  ctx_input_caps = input_caps;
+}
+
+static void
+setup_amrwb (void)
+{
+  ctx_factory = "amrparse";
+  ctx_sink_template = &sinktemplate_wb;
+  ctx_src_template = &srctemplate_wb;
+  input_caps = gst_caps_from_string (SRC_CAPS_WB);
+  g_assert (input_caps);
+  ctx_input_caps = input_caps;
+}
+
+static void
+teardown (void)
+{
+  gst_caps_unref (input_caps);
+}
+
+GST_START_TEST (test_parse_nb_normal)
+{
+  gst_parser_test_normal (frame_data_nb, sizeof (frame_data_nb));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_nb_drain_single)
+{
+  gst_parser_test_drain_single (frame_data_nb, sizeof (frame_data_nb));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_nb_drain_garbage)
+{
+  gst_parser_test_drain_garbage (frame_data_nb, sizeof (frame_data_nb),
+      garbage_frame, sizeof (garbage_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_nb_split)
+{
+  gst_parser_test_split (frame_data_nb, sizeof (frame_data_nb));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_nb_skip_garbage)
+{
+  gst_parser_test_skip_garbage (frame_data_nb, sizeof (frame_data_nb),
+      garbage_frame, sizeof (garbage_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_nb_detect_stream)
+{
+  GstParserTest ptest;
+  GstCaps *old_ctx_caps;
+
+  /* no input caps, override ctx */
+  old_ctx_caps = ctx_input_caps;
+  ctx_input_caps = NULL;
+
+  /* AMR-NB header */
+  gst_parser_test_init (&ptest, frame_hdr_nb, sizeof (frame_hdr_nb), 1);
+  /* well, no garbage, followed by real data */
+  ptest.series[2].data = frame_data_nb;
+  ptest.series[2].size = sizeof (frame_data_nb);
+  ptest.series[2].num = 10;
+  /* header gets dropped, so ... */
+  /* buffer count will not match */
+  ptest.framed = FALSE;
+  /* total size a bit less */
+  ptest.dropped = sizeof (frame_hdr_nb);
+
+  /* Check that the negotiated caps are as expected */
+  ptest.sink_caps = gst_caps_from_string (SINK_CAPS_NB);
+
+  gst_parser_test_run (&ptest, NULL);
+
+  gst_caps_unref (ptest.sink_caps);
+
+  ctx_input_caps = old_ctx_caps;
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_wb_normal)
+{
+  gst_parser_test_normal (frame_data_wb, sizeof (frame_data_wb));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_wb_drain_single)
+{
+  gst_parser_test_drain_single (frame_data_wb, sizeof (frame_data_wb));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_wb_drain_garbage)
+{
+  gst_parser_test_drain_garbage (frame_data_wb, sizeof (frame_data_wb),
+      garbage_frame, sizeof (garbage_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_wb_split)
+{
+  gst_parser_test_split (frame_data_wb, sizeof (frame_data_wb));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_wb_skip_garbage)
+{
+  gst_parser_test_skip_garbage (frame_data_wb, sizeof (frame_data_wb),
+      garbage_frame, sizeof (garbage_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_wb_detect_stream)
+{
+  GstParserTest ptest;
+  GstCaps *old_ctx_caps;
+
+  /* no input caps, override ctx */
+  old_ctx_caps = ctx_input_caps;
+  ctx_input_caps = NULL;
+
+  /* AMR-WB header */
+  gst_parser_test_init (&ptest, frame_hdr_wb, sizeof (frame_hdr_wb), 1);
+  /* well, no garbage, followed by real data */
+  ptest.series[2].data = frame_data_wb;
+  ptest.series[2].size = sizeof (frame_data_wb);
+  ptest.series[2].num = 10;
+  /* header gets dropped, so ... */
+  /* buffer count will not match */
+  ptest.framed = FALSE;
+  /* total size a bit less */
+  ptest.dropped = sizeof (frame_hdr_wb);
+
+  /* Check that the negotiated caps are as expected */
+  ptest.sink_caps = gst_caps_from_string (SINK_CAPS_WB);
+
+  gst_parser_test_run (&ptest, NULL);
+
+  gst_caps_unref (ptest.sink_caps);
+
+  ctx_input_caps = old_ctx_caps;
+}
+
+GST_END_TEST;
+
+/*
+ * TODO:
+ *   - Both push- and pull-modes need to be tested
+ *      * Pull-mode & EOS
+ */
+
+static Suite *
+amrparse_suite (void)
+{
+  Suite *s = suite_create ("amrparse");
+  TCase *tc_chain;
+
+  /* AMR-NB tests */
+  tc_chain = tcase_create ("amrnb");
+  tcase_add_checked_fixture (tc_chain, setup_amrnb, teardown);
+  tcase_add_test (tc_chain, test_parse_nb_normal);
+  tcase_add_test (tc_chain, test_parse_nb_drain_single);
+  tcase_add_test (tc_chain, test_parse_nb_drain_garbage);
+  tcase_add_test (tc_chain, test_parse_nb_split);
+  tcase_add_test (tc_chain, test_parse_nb_detect_stream);
+  tcase_add_test (tc_chain, test_parse_nb_skip_garbage);
+  suite_add_tcase (s, tc_chain);
+
+  /* AMR-WB tests */
+  tc_chain = tcase_create ("amrwb");
+  tcase_add_checked_fixture (tc_chain, setup_amrwb, teardown);
+  tcase_add_test (tc_chain, test_parse_wb_normal);
+  tcase_add_test (tc_chain, test_parse_wb_drain_single);
+  tcase_add_test (tc_chain, test_parse_wb_drain_garbage);
+  tcase_add_test (tc_chain, test_parse_wb_split);
+  tcase_add_test (tc_chain, test_parse_wb_detect_stream);
+  tcase_add_test (tc_chain, test_parse_wb_skip_garbage);
+  suite_add_tcase (s, tc_chain);
+
+  return s;
+}
+
+GST_CHECK_MAIN (amrparse)
diff --git a/tests/check/elements/apev2mux.c b/tests/check/elements/apev2mux.c
new file mode 100644
index 0000000..ef1907e
--- /dev/null
+++ b/tests/check/elements/apev2mux.c
@@ -0,0 +1,411 @@
+/* GStreamer
+ *
+ * unit test for the taglib-based apev2mux element
+ *
+ * Copyright (C) 2006 Tim-Philipp Müller  <tim centricular net>
+ * Copyright (C) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+
+#include <gst/gst.h>
+#include <string.h>
+
+#define TEST_ARTIST           "Ar T\303\255st"
+#define TEST_TITLE            "M\303\274llermilch!"
+#define TEST_ALBUM            "Boom"
+#define TEST_DATE             g_date_new_dmy(1,1,2006)
+#define TEST_TRACK_NUMBER     7
+#define TEST_TRACK_COUNT      19
+#define TEST_TRACK_GAIN       1.45
+#define TEST_ALBUM_GAIN       0.78
+
+/* for dummy mp3 frame sized MP3_FRAME_SIZE bytes,
+ * start: ff fb b0 44 00 00 08 00  00 4b 00 00 00 00 00 00 */
+static const guint8 mp3_dummyhdr[] = { 0xff, 0xfb, 0xb0, 0x44, 0x00, 0x00,
+  0x08, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00
+};
+
+#define MP3_FRAME_SIZE 626
+
+static GstTagList *
+test_taglib_apev2mux_create_tags (guint32 mask)
+{
+  GstTagList *tags;
+
+  tags = gst_tag_list_new_empty ();
+
+  if (mask & (1 << 0)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_ARTIST, TEST_ARTIST, NULL);
+  }
+  if (mask & (1 << 1)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_TITLE, TEST_TITLE, NULL);
+  }
+  if (mask & (1 << 2)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_ALBUM, TEST_ALBUM, NULL);
+  }
+  if (mask & (1 << 3)) {
+    GDate *date;
+
+    date = TEST_DATE;
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_DATE, date, NULL);
+    g_date_free (date);
+  }
+  if (mask & (1 << 4)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_TRACK_NUMBER, TEST_TRACK_NUMBER, NULL);
+  }
+  if (mask & (1 << 5)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_TRACK_COUNT, TEST_TRACK_COUNT, NULL);
+  }
+  if (mask & (1 << 6)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_TRACK_GAIN, TEST_TRACK_GAIN, NULL);
+  }
+  if (mask & (1 << 7)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_ALBUM_GAIN, TEST_ALBUM_GAIN, NULL);
+  }
+  if (mask & (1 << 8)) {
+  }
+  if (mask & (1 << 9)) {
+  }
+  if (mask & (1 << 10)) {
+  }
+  if (mask & (1 << 11)) {
+  }
+  if (mask & (1 << 12)) {
+  }
+  if (mask & (1 << 13)) {
+  }
+  return tags;
+}
+
+static void
+test_taglib_apev2mux_check_tags (GstTagList * tags, guint32 mask)
+{
+  if (mask & (1 << 0)) {
+    gchar *s = NULL;
+
+    fail_unless (gst_tag_list_get_string (tags, GST_TAG_ARTIST, &s));
+    fail_unless (g_str_equal (s, TEST_ARTIST));
+    g_free (s);
+  }
+  if (mask & (1 << 1)) {
+    gchar *s = NULL;
+
+    fail_unless (gst_tag_list_get_string (tags, GST_TAG_TITLE, &s));
+    fail_unless (g_str_equal (s, TEST_TITLE));
+    g_free (s);
+  }
+  if (mask & (1 << 2)) {
+    gchar *s = NULL;
+
+    fail_unless (gst_tag_list_get_string (tags, GST_TAG_ALBUM, &s));
+    fail_unless (g_str_equal (s, TEST_ALBUM));
+    g_free (s);
+  }
+  if (mask & (1 << 3)) {
+    GDate *shouldbe, *date = NULL;
+
+    shouldbe = TEST_DATE;
+    fail_unless (gst_tag_list_get_date (tags, GST_TAG_DATE, &date));
+    fail_unless (g_date_compare (shouldbe, date) == 0);
+    g_date_free (shouldbe);
+    g_date_free (date);
+  }
+  if (mask & (1 << 4)) {
+    guint num;
+
+    fail_unless (gst_tag_list_get_uint (tags, GST_TAG_TRACK_NUMBER, &num));
+    fail_unless (num == TEST_TRACK_NUMBER);
+  }
+  if (mask & (1 << 5)) {
+    guint count;
+
+    fail_unless (gst_tag_list_get_uint (tags, GST_TAG_TRACK_COUNT, &count));
+    fail_unless (count == TEST_TRACK_COUNT);
+  }
+  if (mask & (1 << 6)) {
+    gdouble gain;
+
+    fail_unless (gst_tag_list_get_double (tags, GST_TAG_TRACK_GAIN, &gain));
+    fail_unless (gain == TEST_TRACK_GAIN);
+  }
+  if (mask & (1 << 7)) {
+    gdouble gain;
+
+    fail_unless (gst_tag_list_get_double (tags, GST_TAG_ALBUM_GAIN, &gain));
+    fail_unless (gain == TEST_ALBUM_GAIN);
+  }
+  if (mask & (1 << 8)) {
+  }
+  if (mask & (1 << 9)) {
+  }
+  if (mask & (1 << 10)) {
+  }
+  if (mask & (1 << 11)) {
+  }
+  if (mask & (1 << 12)) {
+  }
+  if (mask & (1 << 13)) {
+  }
+}
+
+static void
+fill_mp3_buffer (GstElement * fakesrc, GstBuffer * buf, GstPad * pad,
+    guint64 * p_offset)
+{
+  gsize size;
+
+  size = gst_buffer_get_size (buf);
+
+  fail_unless (size == MP3_FRAME_SIZE);
+
+  GST_LOG ("filling buffer with fake mp3 data, offset = %" G_GUINT64_FORMAT,
+      *p_offset);
+
+  gst_buffer_fill (buf, 0, mp3_dummyhdr, sizeof (mp3_dummyhdr));
+
+#if 0
+  /* can't use gst_buffer_set_caps() here because the metadata isn't writable
+   * because of the extra refcounts taken by the signal emission mechanism;
+   * we know it's fine to use GST_BUFFER_CAPS() here though */
+  GST_BUFFER_CAPS (buf) = gst_caps_new_simple ("audio/mpeg", "mpegversion",
+      G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, NULL);
+#endif
+
+  GST_BUFFER_OFFSET (buf) = *p_offset;
+  *p_offset += size;
+}
+
+static void
+got_buffer (GstElement * fakesink, GstBuffer * buf, GstPad * pad,
+    GstBuffer ** p_buf)
+{
+  gint64 off;
+  GstMapInfo map;
+
+  off = GST_BUFFER_OFFSET (buf);
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  GST_LOG ("size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT, map.size, off);
+
+  fail_unless (GST_BUFFER_OFFSET_IS_VALID (buf));
+
+  if (*p_buf == NULL || (off + map.size) > gst_buffer_get_size (*p_buf)) {
+    GstBuffer *newbuf;
+
+    /* not very elegant, but who cares */
+    newbuf = gst_buffer_new_and_alloc (off + map.size);
+    if (*p_buf) {
+      GstMapInfo pmap;
+
+      gst_buffer_map (*p_buf, &pmap, GST_MAP_READ);
+      gst_buffer_fill (newbuf, 0, pmap.data, pmap.size);
+      gst_buffer_unmap (*p_buf, &pmap);
+    }
+    gst_buffer_fill (newbuf, off, map.data, map.size);
+    if (*p_buf)
+      gst_buffer_unref (*p_buf);
+    *p_buf = newbuf;
+  } else {
+    gst_buffer_fill (*p_buf, off, map.data, map.size);
+  }
+  gst_buffer_unmap (buf, &map);
+}
+
+static void
+test_taglib_apev2mux_check_output_buffer (GstBuffer * buf)
+{
+  GstMapInfo map;
+  guint off;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  g_assert (map.size % MP3_FRAME_SIZE == 0);
+
+  for (off = 0; off < map.size; off += MP3_FRAME_SIZE) {
+    fail_unless (memcmp (map.data + off, mp3_dummyhdr,
+            sizeof (mp3_dummyhdr)) == 0);
+  }
+  gst_buffer_unmap (buf, &map);
+}
+
+static void
+test_taglib_apev2mux_with_tags (GstTagList * tags, guint32 mask)
+{
+  GstMessage *msg;
+  GstTagList *tags_read = NULL;
+  GstElement *pipeline, *apev2mux, *apedemux, *fakesrc, *fakesink;
+  GstBus *bus;
+  guint64 offset;
+  GstBuffer *outbuf = NULL;
+
+  pipeline = gst_pipeline_new ("pipeline");
+  g_assert (pipeline != NULL);
+
+  fakesrc = gst_element_factory_make ("fakesrc", "fakesrc");
+  g_assert (fakesrc != NULL);
+
+  apev2mux = gst_element_factory_make ("apev2mux", "apev2mux");
+  g_assert (apev2mux != NULL);
+
+  apedemux = gst_element_factory_make ("apedemux", "apedemux");
+  g_assert (apedemux != NULL);
+
+  fakesink = gst_element_factory_make ("fakesink", "fakesink");
+  g_assert (fakesink != NULL);
+
+  /* set up sink */
+  outbuf = NULL;
+  g_object_set (fakesink, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (fakesink, "handoff", G_CALLBACK (got_buffer), &outbuf);
+
+  gst_bin_add (GST_BIN (pipeline), fakesrc);
+  gst_bin_add (GST_BIN (pipeline), apev2mux);
+  gst_bin_add (GST_BIN (pipeline), apedemux);
+  gst_bin_add (GST_BIN (pipeline), fakesink);
+
+  gst_tag_setter_merge_tags (GST_TAG_SETTER (apev2mux), tags,
+      GST_TAG_MERGE_APPEND);
+
+  gst_element_link_many (fakesrc, apev2mux, apedemux, fakesink, NULL);
+
+  /* set up source */
+  g_object_set (fakesrc, "signal-handoffs", TRUE, "can-activate-pull", FALSE,
+      "filltype", 2, "sizetype", 2, "sizemax", MP3_FRAME_SIZE,
+      "num-buffers", 16, NULL);
+
+  offset = 0;
+  g_signal_connect (fakesrc, "handoff", G_CALLBACK (fill_mp3_buffer), &offset);
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  fail_unless (gst_element_get_state (pipeline, NULL, NULL,
+          -1) == GST_STATE_CHANGE_SUCCESS);
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+
+  GST_LOG ("Waiting for tag ...");
+  msg =
+      gst_bus_poll (bus, GST_MESSAGE_TAG | GST_MESSAGE_EOS | GST_MESSAGE_ERROR,
+      -1);
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
+    GError *err;
+    gchar *dbg;
+
+    gst_message_parse_error (msg, &err, &dbg);
+    g_printerr ("ERROR from element %s: %s\n%s\n",
+        GST_OBJECT_NAME (msg->src), err->message, GST_STR_NULL (dbg));
+    g_error_free (err);
+    g_free (dbg);
+  } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) {
+    g_printerr ("EOS message, but were waiting for TAGS!\n");
+  }
+  fail_unless (msg->type == GST_MESSAGE_TAG);
+
+  gst_message_parse_tag (msg, &tags_read);
+  gst_message_unref (msg);
+
+  GST_LOG ("Got tags: %" GST_PTR_FORMAT, tags_read);
+  test_taglib_apev2mux_check_tags (tags_read, mask);
+  gst_tag_list_unref (tags_read);
+
+  GST_LOG ("Waiting for EOS ...");
+  msg = gst_bus_poll (bus, GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
+    GError *err;
+    gchar *dbg;
+
+    gst_message_parse_error (msg, &err, &dbg);
+    g_printerr ("ERROR from element %s: %s\n%s\n",
+        GST_OBJECT_NAME (msg->src), err->message, GST_STR_NULL (dbg));
+    g_error_free (err);
+    g_free (dbg);
+  }
+  fail_unless (msg->type == GST_MESSAGE_EOS);
+  gst_message_unref (msg);
+
+  gst_object_unref (bus);
+
+  GST_LOG ("Got EOS, shutting down ...");
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+
+  test_taglib_apev2mux_check_output_buffer (outbuf);
+  gst_buffer_unref (outbuf);
+
+  GST_LOG ("Done");
+}
+
+GST_START_TEST (test_apev2mux)
+{
+  GstTagList *tags;
+  gint i;
+
+  g_random_set_seed (247166295);
+
+  /* internal consistency check */
+  tags = test_taglib_apev2mux_create_tags (0xFFFFFFFF);
+  test_taglib_apev2mux_check_tags (tags, 0xFFFFFFFF);
+  gst_tag_list_unref (tags);
+
+  /* now the real tests */
+  for (i = 0; i < 50; ++i) {
+    guint32 mask;
+
+    mask = g_random_int ();
+    GST_LOG ("tag mask = %08x (i=%d)", mask, i);
+
+    if (mask == 0)
+      continue;
+
+    /* create tags */
+    tags = test_taglib_apev2mux_create_tags (mask);
+    GST_LOG ("tags for mask %08x = %" GST_PTR_FORMAT, mask, tags);
+
+    /* double-check for internal consistency */
+    test_taglib_apev2mux_check_tags (tags, mask);
+
+    /* test with pipeline */
+    test_taglib_apev2mux_with_tags (tags, mask);
+
+    /* free tags */
+    gst_tag_list_unref (tags);
+  }
+}
+
+GST_END_TEST;
+
+static Suite *
+apev2mux_suite (void)
+{
+  Suite *s = suite_create ("apev2mux");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_apev2mux);
+
+  return s;
+}
+
+GST_CHECK_MAIN (apev2mux);
diff --git a/tests/check/elements/aspectratiocrop.c b/tests/check/elements/aspectratiocrop.c
new file mode 100644
index 0000000..83d6fb4
--- /dev/null
+++ b/tests/check/elements/aspectratiocrop.c
@@ -0,0 +1,175 @@
+/* GStreamer unit test for the aspectratiocrop element
+ * Copyright (C) 2009 Thijs Vermeir <thijsvermeir@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/check/gstcheck.h>
+
+#define ASPECT_RATIO_CROP_CAPS                      \
+  GST_VIDEO_CAPS_MAKE ("{ RGBx, xRGB, BGRx, xBGR, " \
+      "RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, "    \
+      "YUY2, YVYU, UYVY, GRAY8, I420, YV12, RGB16, " \
+      "RGB15 }")
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (ASPECT_RATIO_CROP_CAPS)
+    );
+
+static void
+check_aspectratiocrop (const gchar * in_string, const gchar * out_string,
+    gint in_size, gint out_size, gint ar_n, gint ar_d)
+{
+  GstElement *element;
+  GstPad *pad_peer;
+  GstPad *sink_pad = NULL;
+  GstPad *src_pad;
+  GstBuffer *new;
+  GstBuffer *buffer;
+  GstBuffer *buffer_out;
+  GstCaps *incaps;
+  GstCaps *outcaps;
+
+  incaps = gst_caps_from_string (in_string);
+  buffer = gst_buffer_new_and_alloc (in_size);
+  outcaps = gst_caps_from_string (out_string);
+  buffer_out = gst_buffer_new_and_alloc (out_size);
+
+  /* check that there are no buffers waiting */
+  gst_check_drop_buffers ();
+
+  /* create the element */
+  element = gst_check_setup_element ("aspectratiocrop");
+
+  /* set the requested aspect ratio */
+  g_object_set (G_OBJECT (element), "aspect-ratio", ar_n, ar_d, NULL);
+
+  /* create the src pad */
+  src_pad = gst_pad_new (NULL, GST_PAD_SRC);
+  gst_pad_set_active (src_pad, TRUE);
+  GST_DEBUG ("setting caps %s %" GST_PTR_FORMAT, in_string, incaps);
+  gst_check_setup_events (src_pad, element, incaps, GST_FORMAT_TIME);
+
+  pad_peer = gst_element_get_static_pad (element, "sink");
+  fail_if (pad_peer == NULL);
+  fail_unless (gst_pad_link (src_pad, pad_peer) == GST_PAD_LINK_OK,
+      "Could not link source and %s sink pads", GST_ELEMENT_NAME (element));
+  gst_object_unref (pad_peer);
+
+  /* create the sink pad */
+  pad_peer = gst_element_get_static_pad (element, "src");
+  sink_pad = gst_pad_new_from_static_template (&sinktemplate, "sink");
+  fail_unless (gst_pad_link (pad_peer, sink_pad) == GST_PAD_LINK_OK,
+      "Could not link sink and %s source pads", GST_ELEMENT_NAME (element));
+  gst_object_unref (pad_peer);
+  gst_pad_set_chain_function (sink_pad, gst_check_chain_func);
+  gst_pad_set_active (sink_pad, TRUE);
+
+  /* configure the sink pad */
+  fail_unless (gst_element_set_state (element,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  fail_unless (gst_pad_push (src_pad, buffer) == GST_FLOW_OK,
+      "Failed to push buffer");
+  fail_unless (gst_element_set_state (element,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+
+  /* check the result */
+  fail_unless (g_list_length (buffers) == 1);
+  new = GST_BUFFER (buffers->data);
+  buffers = g_list_remove (buffers, new);
+  fail_unless (gst_buffer_get_size (buffer_out) == gst_buffer_get_size (new),
+      "size of the buffers are not the same");
+  {
+    GstCaps *sinkpad_caps;
+
+    sinkpad_caps = gst_pad_get_current_caps (sink_pad);
+
+    gst_check_caps_equal (sinkpad_caps, outcaps);
+
+    gst_caps_unref (sinkpad_caps);
+  }
+  gst_buffer_unref (new);
+  gst_buffer_unref (buffer_out);
+  gst_caps_unref (outcaps);
+  gst_caps_unref (incaps);
+
+  /* teardown the element and pads */
+  gst_pad_set_active (src_pad, FALSE);
+  gst_check_teardown_src_pad (element);
+  gst_pad_set_active (sink_pad, FALSE);
+  gst_check_teardown_sink_pad (element);
+  gst_check_teardown_element (element);
+}
+
+GST_START_TEST (test_no_cropping)
+{
+  check_aspectratiocrop
+      ("video/x-raw, format=(string)YUY2, width=(int)320, height=(int)240, framerate=(fraction)30/1",
+      "video/x-raw, format=(string)YUY2, width=(int)320, height=(int)240, framerate=(fraction)30/1",
+      153600, 153600, 4, 3);
+  check_aspectratiocrop
+      ("video/x-raw, format=(string)YUY2, width=(int)320, height=(int)320, framerate=(fraction)30/1, pixel-aspect-ratio=(fraction)4/3",
+      "video/x-raw, format=(string)YUY2, width=(int)320, height=(int)320, framerate=(fraction)30/1, pixel-aspect-ratio=(fraction)4/3",
+      204800, 204800, 4, 3);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_autocropping)
+{
+  check_aspectratiocrop
+      ("video/x-raw, format=(string)YUY2, width=(int)320, height=(int)240, framerate=(fraction)30/1, pixel-aspect-ratio=(fraction)4/3",
+      "video/x-raw, format=(string)YUY2, width=(int)240, height=(int)240, framerate=(fraction)30/1, pixel-aspect-ratio=(fraction)4/3",
+      153600, 115200, 4, 3);
+
+  check_aspectratiocrop
+      ("video/x-raw, format=(string)YUY2, width=(int)320, height=(int)240, framerate=(fraction)30/1, pixel-aspect-ratio=(fraction)16/9",
+      "video/x-raw, format=(string)YUY2, width=(int)180, height=(int)240, framerate=(fraction)30/1, pixel-aspect-ratio=(fraction)16/9",
+      153600, 86400, 4, 3);
+
+  check_aspectratiocrop
+      ("video/x-raw, format=(string)YUY2, width=(int)320, height=(int)240, framerate=(fraction)30/1, pixel-aspect-ratio=(fraction)16/15",
+      "video/x-raw, format=(string)YUY2, width=(int)320, height=(int)192, framerate=(fraction)30/1, pixel-aspect-ratio=(fraction)16/15",
+      153600, 122880, 16, 9);
+
+}
+
+GST_END_TEST;
+
+static Suite *
+aspectratiocrop_suite (void)
+{
+  Suite *s = suite_create ("aspectratiocrop");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_no_cropping);
+  tcase_add_test (tc_chain, test_autocropping);
+
+  return s;
+}
+
+GST_CHECK_MAIN (aspectratiocrop);
diff --git a/tests/check/elements/audioamplify.c b/tests/check/elements/audioamplify.c
new file mode 100644
index 0000000..a6e3c2d
--- /dev/null
+++ b/tests/check/elements/audioamplify.c
@@ -0,0 +1,467 @@
+/* GStreamer
+ *
+ * unit test for audioamplify
+ *
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * Greatly based on the audiopanorama unit test
+ * Copyright (C) 2006 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gst/base/gstbasetransform.h>
+#include <gst/check/gstcheck.h>
+#include <gst/audio/audio.h>
+
+gboolean have_eos = FALSE;
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *mysrcpad, *mysinkpad;
+
+
+#define AMPLIFY_CAPS_STRING    \
+    "audio/x-raw, "                     \
+    "channels = (int) 1, "              \
+    "rate = (int) 44100, "              \
+    "layout = (string) interleaved, "   \
+    "format = (string) " GST_AUDIO_NE(S16)
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "channels = (int) 1, "
+        "rate = (int) [ 1,  MAX ], "
+        "layout = (string) interleaved, "
+        "format = (string) " GST_AUDIO_NE (S16)));
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "channels = (int) 1, "
+        "rate = (int) [ 1,  MAX ], "
+        "layout = (string) interleaved, "
+        "format = (string) " GST_AUDIO_NE (S16)));
+
+static GstElement *
+setup_amplify (void)
+{
+  GstElement *amplify;
+
+  GST_DEBUG ("setup_amplify");
+  amplify = gst_check_setup_element ("audioamplify");
+  mysrcpad = gst_check_setup_src_pad (amplify, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (amplify, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return amplify;
+}
+
+static void
+cleanup_amplify (GstElement * amplify)
+{
+  GST_DEBUG ("cleanup_amplify");
+
+  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (amplify);
+  gst_check_teardown_sink_pad (amplify);
+  gst_check_teardown_element (amplify);
+}
+
+GST_START_TEST (test_passthrough)
+{
+  GstElement *amplify;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[6] = { 24576, -16384, 256, -128, 0, -24576 };
+  gint16 res[6];
+
+  amplify = setup_amplify ();
+  fail_unless (gst_element_set_state (amplify,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  caps = gst_caps_from_string (AMPLIFY_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, amplify, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  inbuffer =
+      gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, in, 12, 0, 12,
+      NULL, NULL);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 12) == 0);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... but it ends up being collected on the global buffer list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res, 12) == 12);
+  GST_INFO
+      ("expected %+5d %+5d %+5d %+5d %+5d %+5d real %+5d %+5d %+5d %+5d %+5d %+5d",
+      in[0], in[1], in[2], in[3], in[4], in[5], res[0], res[1], res[2], res[3],
+      res[4], res[5]);
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, in, 12) == 0);
+
+  /* cleanup */
+  cleanup_amplify (amplify);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_zero)
+{
+  GstElement *amplify;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[6] = { 24576, -16384, 256, -128, 0, -24576 };
+  gint16 out[6] = { 0, 0, 0, 0, 0, 0 };
+  gint16 res[6];
+
+  amplify = setup_amplify ();
+  g_object_set (G_OBJECT (amplify), "amplification", 0.0, NULL);
+  fail_unless (gst_element_set_state (amplify,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  caps = gst_caps_from_string (AMPLIFY_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, amplify, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  inbuffer =
+      gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, in, 12, 0, 12,
+      NULL, NULL);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 12) == 0);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res, 12) == 12);
+  GST_INFO
+      ("expected %+5d %+5d %+5d %+5d %+5d %+5d real %+5d %+5d %+5d %+5d %+5d %+5d",
+      out[0], out[1], out[2], out[3], out[4], out[5], res[0], res[1], res[2],
+      res[3], res[4], res[5]);
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, out, 12) == 0);
+
+  /* cleanup */
+  cleanup_amplify (amplify);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_050_clip)
+{
+  GstElement *amplify;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[6] = { 24576, -16384, 256, -128, 0, -24576 };
+  gint16 out[6] = { 12288, -8192, 128, -64, 0, -12288 };
+  gint16 res[6];
+
+  amplify = setup_amplify ();
+  g_object_set (G_OBJECT (amplify), "amplification", 0.5, NULL);
+  fail_unless (gst_element_set_state (amplify,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  caps = gst_caps_from_string (AMPLIFY_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, amplify, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  inbuffer =
+      gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, in, 12, 0, 12,
+      NULL, NULL);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 12) == 0);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res, 12) == 12);
+  GST_INFO
+      ("expected %+5d %+5d %+5d %+5d %+5d %+5d real %+5d %+5d %+5d %+5d %+5d %+5d",
+      out[0], out[1], out[2], out[3], out[4], out[5], res[0], res[1], res[2],
+      res[3], res[4], res[5]);
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, out, 12) == 0);
+
+  /* cleanup */
+  cleanup_amplify (amplify);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_200_clip)
+{
+  GstElement *amplify;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[6] = { 24576, -16384, 256, -128, 0, -24576 };
+  gint16 out[6] = { G_MAXINT16, -32768, 512, -256, 0, G_MININT16 };
+  gint16 res[6];
+
+  amplify = setup_amplify ();
+  g_object_set (G_OBJECT (amplify), "amplification", 2.0, NULL);
+  fail_unless (gst_element_set_state (amplify,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  caps = gst_caps_from_string (AMPLIFY_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, amplify, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  inbuffer =
+      gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, in, 12, 0, 12,
+      NULL, NULL);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 12) == 0);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res, 12) == 12);
+  GST_INFO
+      ("expected %+5d %+5d %+5d %+5d %+5d %+5d real %+5d %+5d %+5d %+5d %+5d %+5d",
+      out[0], out[1], out[2], out[3], out[4], out[5], res[0], res[1], res[2],
+      res[3], res[4], res[5]);
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, out, 12) == 0);
+
+  /* cleanup */
+  cleanup_amplify (amplify);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_050_wrap_negative)
+{
+  GstElement *amplify;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[6] = { 24576, -16384, 256, -128, 0, -24576 };
+  gint16 out[6] = { 12288, -8192, 128, -64, 0, -12288 };
+  gint16 res[6];
+
+  amplify = setup_amplify ();
+  g_object_set (G_OBJECT (amplify), "amplification", 0.5, NULL);
+  g_object_set (G_OBJECT (amplify), "clipping-method", 1, NULL);
+  fail_unless (gst_element_set_state (amplify,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  caps = gst_caps_from_string (AMPLIFY_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, amplify, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  inbuffer =
+      gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, in, 12, 0, 12,
+      NULL, NULL);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 12) == 0);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res, 12) == 12);
+  GST_INFO
+      ("expected %+5d %+5d %+5d %+5d %+5d %+5d real %+5d %+5d %+5d %+5d %+5d %+5d",
+      out[0], out[1], out[2], out[3], out[4], out[5], res[0], res[1], res[2],
+      res[3], res[4], res[5]);
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, out, 12) == 0);
+
+  /* cleanup */
+  cleanup_amplify (amplify);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_200_wrap_negative)
+{
+  GstElement *amplify;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[6] = { 24576, -16384, 256, -128, 0, -24576 };
+  gint16 out[6] = { -16384, -32768, 512, -256, 0, 16384 };
+  gint16 res[6];
+
+  amplify = setup_amplify ();
+  g_object_set (G_OBJECT (amplify), "amplification", 2.0, NULL);
+  g_object_set (G_OBJECT (amplify), "clipping-method", 1, NULL);
+  fail_unless (gst_element_set_state (amplify,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  caps = gst_caps_from_string (AMPLIFY_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, amplify, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  inbuffer =
+      gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, in, 12, 0, 12,
+      NULL, NULL);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 12) == 0);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res, 12) == 12);
+  GST_INFO
+      ("expected %+5d %+5d %+5d %+5d %+5d %+5d real %+5d %+5d %+5d %+5d %+5d %+5d",
+      out[0], out[1], out[2], out[3], out[4], out[5], res[0], res[1], res[2],
+      res[3], res[4], res[5]);
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, out, 12) == 0);
+
+  /* cleanup */
+  cleanup_amplify (amplify);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_050_wrap_positive)
+{
+  GstElement *amplify;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[6] = { 24576, -16384, 256, -128, 0, -24576 };
+  gint16 out[6] = { 12288, -8192, 128, -64, 0, -12288 };
+  gint16 res[6];
+
+  amplify = setup_amplify ();
+  g_object_set (G_OBJECT (amplify), "amplification", 0.5, NULL);
+  g_object_set (G_OBJECT (amplify), "clipping-method", 2, NULL);
+  fail_unless (gst_element_set_state (amplify,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  caps = gst_caps_from_string (AMPLIFY_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, amplify, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  inbuffer =
+      gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, in, 12, 0, 12,
+      NULL, NULL);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 12) == 0);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res, 12) == 12);
+  GST_INFO
+      ("expected %+5d %+5d %+5d %+5d %+5d %+5d real %+5d %+5d %+5d %+5d %+5d %+5d",
+      out[0], out[1], out[2], out[3], out[4], out[5], res[0], res[1], res[2],
+      res[3], res[4], res[5]);
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, out, 12) == 0);
+
+  /* cleanup */
+  cleanup_amplify (amplify);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_200_wrap_positive)
+{
+  GstElement *amplify;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[6] = { 24576, -16384, 256, -128, 0, -24576 };
+  gint16 out[6] = { 16382, -32768, 512, -256, 0, -16384 };
+  gint16 res[6];
+
+  amplify = setup_amplify ();
+  g_object_set (G_OBJECT (amplify), "amplification", 2.0, NULL);
+  g_object_set (G_OBJECT (amplify), "clipping-method", 2, NULL);
+  fail_unless (gst_element_set_state (amplify,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  caps = gst_caps_from_string (AMPLIFY_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, amplify, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  inbuffer =
+      gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, in, 12, 0, 12,
+      NULL, NULL);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 12) == 0);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res, 12) == 12);
+  GST_INFO
+      ("expected %+5d %+5d %+5d %+5d %+5d %+5d real %+5d %+5d %+5d %+5d %+5d %+5d",
+      out[0], out[1], out[2], out[3], out[4], out[5], res[0], res[1], res[2],
+      res[3], res[4], res[5]);
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, out, 12) == 0);
+
+  /* cleanup */
+  cleanup_amplify (amplify);
+}
+
+GST_END_TEST;
+
+static Suite *
+amplify_suite (void)
+{
+  Suite *s = suite_create ("amplify");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_passthrough);
+  tcase_add_test (tc_chain, test_zero);
+  tcase_add_test (tc_chain, test_050_clip);
+  tcase_add_test (tc_chain, test_200_clip);
+  tcase_add_test (tc_chain, test_050_wrap_negative);
+  tcase_add_test (tc_chain, test_200_wrap_negative);
+  tcase_add_test (tc_chain, test_050_wrap_positive);
+  tcase_add_test (tc_chain, test_200_wrap_positive);
+  return s;
+}
+
+GST_CHECK_MAIN (amplify);
diff --git a/tests/check/elements/audiochebband.c b/tests/check/elements/audiochebband.c
new file mode 100644
index 0000000..a636e20
--- /dev/null
+++ b/tests/check/elements/audiochebband.c
@@ -0,0 +1,1670 @@
+/* GStreamer
+ *
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * audiochebband.c: Unit test for the audiochebband element
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/check/gstcheck.h>
+
+#include <math.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *mysrcpad, *mysinkpad;
+
+#define BUFFER_CAPS_STRING_32           \
+    "audio/x-raw, "                     \
+    "channels = (int) 1, "              \
+    "rate = (int) 44100, "              \
+    "layout = (string) interleaved, "   \
+    "format = (string) " GST_AUDIO_NE(F32)
+
+#define BUFFER_CAPS_STRING_64           \
+    "audio/x-raw, "                     \
+    "channels = (int) 1, "              \
+    "rate = (int) 44100, "              \
+    "layout = (string) interleaved, "   \
+    "format = (string) " GST_AUDIO_NE(F64)
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "channels = (int) 1, "
+        "rate = (int) 44100, "
+        "layout = (string) interleaved, "
+        "format = (string) { "
+        GST_AUDIO_NE (F32) ", " GST_AUDIO_NE (F64) " }"));
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "channels = (int) 1, "
+        "rate = (int) 44100, "
+        "layout = (string) interleaved, "
+        "format = (string) { "
+        GST_AUDIO_NE (F32) ", " GST_AUDIO_NE (F64) " }"));
+
+static GstElement *
+setup_audiochebband (void)
+{
+  GstElement *audiochebband;
+
+  GST_DEBUG ("setup_audiochebband");
+  audiochebband = gst_check_setup_element ("audiochebband");
+  mysrcpad = gst_check_setup_src_pad (audiochebband, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (audiochebband, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return audiochebband;
+}
+
+static void
+cleanup_audiochebband (GstElement * audiochebband)
+{
+  GST_DEBUG ("cleanup_audiochebband");
+
+  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (audiochebband);
+  gst_check_teardown_sink_pad (audiochebband);
+  gst_check_teardown_element (audiochebband);
+}
+
+/* Test if data containing only one frequency component
+ * at 0 is erased with bandpass mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type1_32_bp_0hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiochebband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 1024 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at band center is preserved with bandpass mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type1_32_bp_11025hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiochebband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 1024 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i += 4) {
+    in[i] = 0.0;
+    in[i + 1] = 1.0;
+    in[i + 2] = 0.0;
+    in[i + 3] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms >= 0.6);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is erased with bandpass mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type1_32_bp_22050hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiochebband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 1024 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is preserved with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type1_32_br_0hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiochebband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 1024 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at band center is erased with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type1_32_br_11025hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiochebband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 1024 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i += 4) {
+    in[i] = 0.0;
+    in[i + 1] = 1.0;
+    in[i + 2] = 0.0;
+    in[i + 3] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is preserved with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type1_32_br_22050hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiochebband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 1024 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is erased with bandpass mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type1_64_bp_0hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiochebband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at band center is preserved with bandpass mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type1_64_bp_11025hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiochebband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i += 4) {
+    in[i] = 0.0;
+    in[i + 1] = 1.0;
+    in[i + 2] = 0.0;
+    in[i + 3] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms >= 0.6);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is erased with bandpass mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type1_64_bp_22050hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiochebband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is preserved with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type1_64_br_0hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiochebband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at band center is erased with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type1_64_br_11025hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiochebband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i += 4) {
+    in[i] = 0.0;
+    in[i + 1] = 1.0;
+    in[i + 2] = 0.0;
+    in[i + 3] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is preserved with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type1_64_br_22050hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiochebband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is erased with bandpass mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type2_32_bp_0hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiochebband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 1024 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at band center is preserved with bandpass mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type2_32_bp_11025hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiochebband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 1024 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i += 4) {
+    in[i] = 0.0;
+    in[i + 1] = 1.0;
+    in[i + 2] = 0.0;
+    in[i + 3] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms >= 0.6);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is erased with bandpass mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type2_32_bp_22050hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiochebband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 1024 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is preserved with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type2_32_br_0hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiochebband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 1024 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at band center is erased with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type2_32_br_11025hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiochebband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 1024 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i += 4) {
+    in[i] = 0.0;
+    in[i + 1] = 1.0;
+    in[i + 2] = 0.0;
+    in[i + 3] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is preserved with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type2_32_br_22050hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiochebband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 1024 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is erased with bandpass mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type2_64_bp_0hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiochebband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at band center is preserved with bandpass mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type2_64_bp_11025hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiochebband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i += 4) {
+    in[i] = 0.0;
+    in[i + 1] = 1.0;
+    in[i + 2] = 0.0;
+    in[i + 3] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms >= 0.6);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is erased with bandpass mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type2_64_bp_22050hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiochebband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is preserved with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type2_64_br_0hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiochebband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at band center is erased with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type2_64_br_11025hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiochebband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i += 4) {
+    in[i] = 0.0;
+    in[i + 1] = 1.0;
+    in[i + 2] = 0.0;
+    in[i + 3] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is preserved with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_type2_64_br_22050hz)
+{
+  GstElement *audiochebband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiochebband = setup_audiochebband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiochebband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiochebband), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiochebband), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiochebband), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiochebband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiochebband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiochebband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiochebband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 1024.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiochebband (audiochebband);
+}
+
+GST_END_TEST;
+
+static Suite *
+audiochebband_suite (void)
+{
+  Suite *s = suite_create ("audiochebband");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_type1_32_bp_0hz);
+  tcase_add_test (tc_chain, test_type1_32_bp_11025hz);
+  tcase_add_test (tc_chain, test_type1_32_bp_22050hz);
+  tcase_add_test (tc_chain, test_type1_32_br_0hz);
+  tcase_add_test (tc_chain, test_type1_32_br_11025hz);
+  tcase_add_test (tc_chain, test_type1_32_br_22050hz);
+  tcase_add_test (tc_chain, test_type1_64_bp_0hz);
+  tcase_add_test (tc_chain, test_type1_64_bp_11025hz);
+  tcase_add_test (tc_chain, test_type1_64_bp_22050hz);
+  tcase_add_test (tc_chain, test_type1_64_br_0hz);
+  tcase_add_test (tc_chain, test_type1_64_br_11025hz);
+  tcase_add_test (tc_chain, test_type1_64_br_22050hz);
+  tcase_add_test (tc_chain, test_type2_32_bp_0hz);
+  tcase_add_test (tc_chain, test_type2_32_bp_11025hz);
+  tcase_add_test (tc_chain, test_type2_32_bp_22050hz);
+  tcase_add_test (tc_chain, test_type2_32_br_0hz);
+  tcase_add_test (tc_chain, test_type2_32_br_11025hz);
+  tcase_add_test (tc_chain, test_type2_32_br_22050hz);
+  tcase_add_test (tc_chain, test_type2_64_bp_0hz);
+  tcase_add_test (tc_chain, test_type2_64_bp_11025hz);
+  tcase_add_test (tc_chain, test_type2_64_bp_22050hz);
+  tcase_add_test (tc_chain, test_type2_64_br_0hz);
+  tcase_add_test (tc_chain, test_type2_64_br_11025hz);
+  tcase_add_test (tc_chain, test_type2_64_br_22050hz);
+
+  return s;
+}
+
+GST_CHECK_MAIN (audiochebband);
diff --git a/tests/check/elements/audiocheblimit.c b/tests/check/elements/audiocheblimit.c
new file mode 100644
index 0000000..039eab5
--- /dev/null
+++ b/tests/check/elements/audiocheblimit.c
@@ -0,0 +1,1086 @@
+/* GStreamer
+ *
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * audiocheblimit.c: Unit test for the audiocheblimit element
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/check/gstcheck.h>
+
+#include <math.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *mysrcpad, *mysinkpad;
+
+#define BUFFER_CAPS_STRING_32           \
+    "audio/x-raw, "                     \
+    "channels = (int) 1, "              \
+    "rate = (int) 44100, "              \
+    "layout = (string) interleaved, "   \
+    "format = (string) " GST_AUDIO_NE(F32)
+
+#define BUFFER_CAPS_STRING_64           \
+    "audio/x-raw, "                     \
+    "channels = (int) 1, "              \
+    "rate = (int) 44100, "              \
+    "layout = (string) interleaved, "   \
+    "format = (string) " GST_AUDIO_NE(F64)
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "channels = (int) 1, "
+        "rate = (int) 44100, "
+        "layout = (string) interleaved, "
+        "format = (string) { "
+        GST_AUDIO_NE (F32) ", " GST_AUDIO_NE (F64) " }"));
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "channels = (int) 1, "
+        "rate = (int) 44100, "
+        "layout = (string) interleaved, "
+        "format = (string) { "
+        GST_AUDIO_NE (F32) ", " GST_AUDIO_NE (F64) " }"));
+
+static GstElement *
+setup_audiocheblimit (void)
+{
+  GstElement *audiocheblimit;
+
+  GST_DEBUG ("setup_audiocheblimit");
+  audiocheblimit = gst_check_setup_element ("audiocheblimit");
+  mysrcpad = gst_check_setup_src_pad (audiocheblimit, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (audiocheblimit, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return audiocheblimit;
+}
+
+static void
+cleanup_audiocheblimit (GstElement * audiocheblimit)
+{
+  GST_DEBUG ("cleanup_audiocheblimit");
+
+  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (audiocheblimit);
+  gst_check_teardown_sink_pad (audiocheblimit);
+  gst_check_teardown_element (audiocheblimit);
+}
+
+/* Test if data containing only one frequency component
+ * at 0 is preserved with lowpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type1_32_lp_0hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to lowpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 128 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 128; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is erased with lowpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type1_32_lp_22050hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to lowpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 128 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 128; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is erased with highpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type1_32_hp_0hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to highpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 128 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 128; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is preserved with highpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type1_32_hp_22050hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to highpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 128 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 128; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is preserved with lowpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type1_64_lp_0hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to lowpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 128 * sizeof (gdouble), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 128; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is erased with lowpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type1_64_lp_22050hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to lowpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 128 * sizeof (gdouble), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 128; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is erased with highpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type1_64_hp_0hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to highpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 128 * sizeof (gdouble), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 128; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is preserved with highpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type1_64_hp_22050hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to highpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 0.25, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 128 * sizeof (gdouble), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 128; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is preserved with lowpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type2_32_lp_0hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to lowpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 128 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 128; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is erased with lowpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type2_32_lp_22050hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to lowpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 128 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 128; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is erased with highpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type2_32_hp_0hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to highpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 128 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 128; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is preserved with highpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type2_32_hp_22050hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to highpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_allocate (NULL, 128 * sizeof (gfloat), NULL);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 128; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gfloat *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is preserved with lowpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type2_64_lp_0hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to lowpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (128 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 128; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is erased with lowpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type2_64_lp_22050hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to lowpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (128 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 128; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is erased with highpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type2_64_hp_0hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to highpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (128 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 128; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms <= 0.1);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is preserved with highpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_type2_64_hp_22050hz)
+{
+  GstElement *audiocheblimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+
+  audiocheblimit = setup_audiocheblimit ();
+  /* Set to highpass */
+  g_object_set (G_OBJECT (audiocheblimit), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "poles", 8, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "type", 2, NULL);
+  g_object_set (G_OBJECT (audiocheblimit), "ripple", 40.0, NULL);
+
+  fail_unless (gst_element_set_state (audiocheblimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiocheblimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (128 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 128; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (BUFFER_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiocheblimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms = 0.0;
+  for (i = 0; i < 128; i++)
+    rms += res[i] * res[i];
+  rms = sqrt (rms / 128.0);
+  fail_unless (rms >= 0.9);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  /* cleanup */
+  cleanup_audiocheblimit (audiocheblimit);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+audiocheblimit_suite (void)
+{
+  Suite *s = suite_create ("audiocheblimit");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_type1_32_lp_0hz);
+  tcase_add_test (tc_chain, test_type1_32_lp_22050hz);
+  tcase_add_test (tc_chain, test_type1_32_hp_0hz);
+  tcase_add_test (tc_chain, test_type1_32_hp_22050hz);
+  tcase_add_test (tc_chain, test_type1_64_lp_0hz);
+  tcase_add_test (tc_chain, test_type1_64_lp_22050hz);
+  tcase_add_test (tc_chain, test_type1_64_hp_0hz);
+  tcase_add_test (tc_chain, test_type1_64_hp_22050hz);
+  tcase_add_test (tc_chain, test_type2_32_lp_0hz);
+  tcase_add_test (tc_chain, test_type2_32_lp_22050hz);
+  tcase_add_test (tc_chain, test_type2_32_hp_0hz);
+  tcase_add_test (tc_chain, test_type2_32_hp_22050hz);
+  tcase_add_test (tc_chain, test_type2_64_lp_0hz);
+  tcase_add_test (tc_chain, test_type2_64_lp_22050hz);
+  tcase_add_test (tc_chain, test_type2_64_hp_0hz);
+  tcase_add_test (tc_chain, test_type2_64_hp_22050hz);
+  return s;
+}
+
+GST_CHECK_MAIN (audiocheblimit);
diff --git a/tests/check/elements/audiodynamic.c b/tests/check/elements/audiodynamic.c
new file mode 100644
index 0000000..5b82a03
--- /dev/null
+++ b/tests/check/elements/audiodynamic.c
@@ -0,0 +1,442 @@
+/* GStreamer
+ *
+ * unit test for audiodynamic
+ *
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * Greatly based on the audiopanorama unit test
+ * Copyright (C) 2006 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gst/audio/audio.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/check/gstcheck.h>
+
+gboolean have_eos = FALSE;
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *mysrcpad, *mysinkpad;
+
+
+#define DYNAMIC_CAPS_STRING    \
+    "audio/x-raw, "                     \
+    "channels = (int) 1, "              \
+    "rate = (int) 44100, "              \
+    "layout = (string) interleaved, "   \
+    "format = (string) " GST_AUDIO_NE(S16)
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "channels = (int) 1, "
+        "rate = (int) [ 1,  MAX ], "
+        "layout = (string) interleaved, "
+        "format = (string)" GST_AUDIO_NE (S16)));
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "channels = (int) 1, "
+        "rate = (int) [ 1,  MAX ], "
+        "layout = (string) interleaved, "
+        "format = (string) " GST_AUDIO_NE (S16)));
+
+static GstElement *
+setup_dynamic (void)
+{
+  GstElement *dynamic;
+
+  GST_DEBUG ("setup_dynamic");
+  dynamic = gst_check_setup_element ("audiodynamic");
+  mysrcpad = gst_check_setup_src_pad (dynamic, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (dynamic, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return dynamic;
+}
+
+static void
+cleanup_dynamic (GstElement * dynamic)
+{
+  GST_DEBUG ("cleanup_dynamic");
+
+  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (dynamic);
+  gst_check_teardown_sink_pad (dynamic);
+  gst_check_teardown_element (dynamic);
+}
+
+GST_START_TEST (test_passthrough)
+{
+  GstElement *dynamic;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[6] = { 24576, -16384, 256, -128, 0, -24576 };
+  gint16 res[6];
+
+  dynamic = setup_dynamic ();
+  fail_unless (gst_element_set_state (dynamic,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer =
+      gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, in, 12, 0, 12,
+      NULL, NULL);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 12) == 0);
+  caps = gst_caps_from_string (DYNAMIC_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, dynamic, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... but it ends up being collected on the global buffer list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res, 12) == 12);
+  GST_INFO
+      ("expected %+5d %+5d %+5d %+5d %+5d %+5d real %+5d %+5d %+5d %+5d %+5d %+5d",
+      in[0], in[1], in[2], in[3], in[4], in[5], res[0], res[1], res[2], res[3],
+      res[4], res[5]);
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, in, 12) == 0);
+
+  /* cleanup */
+  cleanup_dynamic (dynamic);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_compress_hard_50_50)
+{
+  GstElement *dynamic;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[8] = { -30000, 24576, -16384, 256, -128, 0, -24576, 30000 };
+  gint16 res[8];
+
+  dynamic = setup_dynamic ();
+  g_object_set (G_OBJECT (dynamic), "mode", 0, NULL);
+  g_object_set (G_OBJECT (dynamic), "characteristics", 0, NULL);
+  g_object_set (G_OBJECT (dynamic), "ratio", 0.5, NULL);
+  g_object_set (G_OBJECT (dynamic), "threshold", 0.5, NULL);
+  fail_unless (gst_element_set_state (dynamic,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (16);
+  gst_buffer_fill (inbuffer, 0, in, 16);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 16) == 0);
+  caps = gst_caps_from_string (DYNAMIC_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, dynamic, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res, 16) == 16);
+
+  fail_unless (res[0] > in[0]);
+  fail_unless (res[1] < in[1]);
+  fail_unless (res[2] == in[2]);
+  fail_unless (res[3] == in[3]);
+  fail_unless (res[4] == in[4]);
+  fail_unless (res[5] == in[5]);
+  fail_unless (res[6] > in[6]);
+  fail_unless (res[7] < in[7]);
+
+  /* cleanup */
+  cleanup_dynamic (dynamic);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_compress_soft_50_50)
+{
+  GstElement *dynamic;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[8] = { -30000, 24576, -16384, 256, -128, 0, -24576, 30000 };
+  gint16 res[8];
+
+  dynamic = setup_dynamic ();
+  g_object_set (G_OBJECT (dynamic), "mode", 0, NULL);
+  g_object_set (G_OBJECT (dynamic), "characteristics", 1, NULL);
+  g_object_set (G_OBJECT (dynamic), "ratio", 0.5, NULL);
+  g_object_set (G_OBJECT (dynamic), "threshold", 0.5, NULL);
+  fail_unless (gst_element_set_state (dynamic,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (16);
+  gst_buffer_fill (inbuffer, 0, in, 16);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 16) == 0);
+  caps = gst_caps_from_string (DYNAMIC_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, dynamic, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res, 16) == 16);
+
+  fail_unless (res[0] > in[0]);
+  fail_unless (res[1] < in[1]);
+  fail_unless (res[2] == in[2]);
+  fail_unless (res[3] == in[3]);
+  fail_unless (res[4] == in[4]);
+  fail_unless (res[5] == in[5]);
+  fail_unless (res[6] > in[6]);
+  fail_unless (res[7] < in[7]);
+
+  /* cleanup */
+  cleanup_dynamic (dynamic);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_compress_hard_100_50)
+{
+  GstElement *dynamic;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[8] = { -30000, 24576, -16384, 256, -128, 0, -24576, 30000 };
+  gint16 res[8];
+
+  dynamic = setup_dynamic ();
+  g_object_set (G_OBJECT (dynamic), "mode", 0, NULL);
+  g_object_set (G_OBJECT (dynamic), "characteristics", 0, NULL);
+  g_object_set (G_OBJECT (dynamic), "ratio", 0.5, NULL);
+  g_object_set (G_OBJECT (dynamic), "threshold", 1.0, NULL);
+  fail_unless (gst_element_set_state (dynamic,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (16);
+  gst_buffer_fill (inbuffer, 0, in, 16);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 16) == 0);
+  caps = gst_caps_from_string (DYNAMIC_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, dynamic, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res, 16) == 16);
+
+  fail_unless (res[0] == in[0]);
+  fail_unless (res[1] == in[1]);
+  fail_unless (res[2] == in[2]);
+  fail_unless (res[3] == in[3]);
+  fail_unless (res[4] == in[4]);
+  fail_unless (res[5] == in[5]);
+  fail_unless (res[6] == in[6]);
+  fail_unless (res[7] == in[7]);
+
+  /* cleanup */
+  cleanup_dynamic (dynamic);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_expand_hard_50_200)
+{
+  GstElement *dynamic;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[8] = { -30000, 24576, -16383, 256, -128, 0, -24576, 30000 };
+  gint16 res[8];
+
+  dynamic = setup_dynamic ();
+  g_object_set (G_OBJECT (dynamic), "mode", 1, NULL);
+  g_object_set (G_OBJECT (dynamic), "characteristics", 0, NULL);
+  g_object_set (G_OBJECT (dynamic), "ratio", 2.0, NULL);
+  g_object_set (G_OBJECT (dynamic), "threshold", 0.5, NULL);
+  fail_unless (gst_element_set_state (dynamic,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (16);
+  gst_buffer_fill (inbuffer, 0, in, 16);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 16) == 0);
+  caps = gst_caps_from_string (DYNAMIC_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, dynamic, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res, 16) == 16);
+
+  fail_unless (res[0] == in[0]);
+  fail_unless (res[1] == in[1]);
+  fail_unless (res[2] > in[2]);
+  fail_unless (res[3] < in[3]);
+  fail_unless (res[4] > in[4]);
+  fail_unless (res[5] == in[5]);
+  fail_unless (res[6] == in[6]);
+  fail_unless (res[7] == in[7]);
+
+  /* cleanup */
+  cleanup_dynamic (dynamic);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_expand_soft_50_200)
+{
+  GstElement *dynamic;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[8] = { -30000, 24576, -16383, 256, -128, 0, -24576, 30000 };
+  gint16 res[8];
+
+  dynamic = setup_dynamic ();
+  g_object_set (G_OBJECT (dynamic), "mode", 1, NULL);
+  g_object_set (G_OBJECT (dynamic), "characteristics", 1, NULL);
+  g_object_set (G_OBJECT (dynamic), "ratio", 2.0, NULL);
+  g_object_set (G_OBJECT (dynamic), "threshold", 0.5, NULL);
+  fail_unless (gst_element_set_state (dynamic,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (16);
+  gst_buffer_fill (inbuffer, 0, in, 16);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 16) == 0);
+  caps = gst_caps_from_string (DYNAMIC_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, dynamic, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res, 16) == 16);
+
+  fail_unless (res[0] == in[0]);
+  fail_unless (res[1] == in[1]);
+  fail_unless (res[2] > in[2]);
+  fail_unless (res[3] < in[3]);
+  fail_unless (res[4] > in[4]);
+  fail_unless (res[5] == in[5]);
+  fail_unless (res[6] == in[6]);
+  fail_unless (res[7] == in[7]);
+
+  /* cleanup */
+  cleanup_dynamic (dynamic);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_expand_hard_0_200)
+{
+  GstElement *dynamic;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[8] = { -30000, 24576, -16383, 256, -128, 0, -24576, 30000 };
+  gint16 res[8];
+
+  dynamic = setup_dynamic ();
+  g_object_set (G_OBJECT (dynamic), "mode", 1, NULL);
+  g_object_set (G_OBJECT (dynamic), "characteristics", 0, NULL);
+  g_object_set (G_OBJECT (dynamic), "ratio", 2.0, NULL);
+  g_object_set (G_OBJECT (dynamic), "threshold", 0.0, NULL);
+  fail_unless (gst_element_set_state (dynamic,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (16);
+  gst_buffer_fill (inbuffer, 0, in, 16);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 16) == 0);
+  caps = gst_caps_from_string (DYNAMIC_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, dynamic, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res, 16) == 16);
+
+  fail_unless (res[0] == in[0]);
+  fail_unless (res[1] == in[1]);
+  fail_unless (res[2] == in[2]);
+  fail_unless (res[3] == in[3]);
+  fail_unless (res[4] == in[4]);
+  fail_unless (res[5] == in[5]);
+  fail_unless (res[6] == in[6]);
+  fail_unless (res[7] == in[7]);
+
+  /* cleanup */
+  cleanup_dynamic (dynamic);
+}
+
+GST_END_TEST;
+
+static Suite *
+dynamic_suite (void)
+{
+  Suite *s = suite_create ("dynamic");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_passthrough);
+  tcase_add_test (tc_chain, test_compress_hard_50_50);
+  tcase_add_test (tc_chain, test_compress_soft_50_50);
+  tcase_add_test (tc_chain, test_compress_hard_100_50);
+  tcase_add_test (tc_chain, test_expand_hard_50_200);
+  tcase_add_test (tc_chain, test_expand_soft_50_200);
+  tcase_add_test (tc_chain, test_expand_hard_0_200);
+  return s;
+}
+
+GST_CHECK_MAIN (dynamic);
diff --git a/tests/check/elements/audioecho.c b/tests/check/elements/audioecho.c
new file mode 100644
index 0000000..025b710
--- /dev/null
+++ b/tests/check/elements/audioecho.c
@@ -0,0 +1,240 @@
+/* GStreamer
+ *
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/audio/audio.h>
+
+gboolean have_eos = FALSE;
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *mysrcpad, *mysinkpad;
+
+#define ECHO_CAPS_STRING    \
+    "audio/x-raw, "               \
+    "channels = (int) 2, "              \
+    "channel-mask = (bitmask) 3, "      \
+    "rate = (int) 100000, "             \
+    "layout = (string) interleaved, "   \
+    "format = (string) " GST_AUDIO_NE(F64)
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "channels = (int) [ 1, 2 ], "
+        "rate = (int) [ 1,  MAX ], "
+        "format = (string) { "
+        GST_AUDIO_NE (F32) ", " GST_AUDIO_NE (F64) " }"));
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "channels = (int) [ 1, 2 ], "
+        "rate = (int) [ 1,  MAX ], "
+        "format = (string) { "
+        GST_AUDIO_NE (F32) ", " GST_AUDIO_NE (F64) " }"));
+
+static GstElement *
+setup_echo (void)
+{
+  GstElement *echo;
+
+  GST_DEBUG ("setup_echo");
+  echo = gst_check_setup_element ("audioecho");
+  mysrcpad = gst_check_setup_src_pad (echo, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (echo, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return echo;
+}
+
+static void
+cleanup_echo (GstElement * echo)
+{
+  GST_DEBUG ("cleanup_echo");
+
+  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (echo);
+  gst_check_teardown_sink_pad (echo);
+  gst_check_teardown_element (echo);
+}
+
+GST_START_TEST (test_passthrough)
+{
+  GstElement *echo;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble in[] = { 1.0, -1.0, 0.0, 0.5, -0.5, 0.0 };
+  gdouble res[6];
+
+  echo = setup_echo ();
+  g_object_set (G_OBJECT (echo), "delay", (GstClockTime) 1, "intensity", 0.0,
+      "feedback", 0.0, NULL);
+  fail_unless (gst_element_set_state (echo,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  caps = gst_caps_from_string (ECHO_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, echo, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  inbuffer =
+      gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, in, sizeof (in), 0,
+      sizeof (in), NULL, NULL);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, sizeof (in)) == 0);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... but it ends up being collected on the global buffer list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res,
+          sizeof (res)) == sizeof (res));
+  GST_INFO
+      ("expected %+lf %+lf %+lf %+lf %+lf %+lf real %+lf %+lf %+lf %+lf %+lf %+lf",
+      in[0], in[1], in[2], in[3], in[4], in[5], res[0], res[1], res[2], res[3],
+      res[4], res[5]);
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, in, sizeof (in)) == 0);
+
+  /* cleanup */
+  cleanup_echo (echo);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_echo)
+{
+  GstElement *echo;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble in[] = { 1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, };
+  gdouble out[] = { 1.0, -1.0, 0.0, 0.0, 1.0, -1.0, 0.0, 0.0, 0.0, 0.0 };
+  gdouble res[10];
+
+  echo = setup_echo ();
+  g_object_set (G_OBJECT (echo), "delay", (GstClockTime) 20000, "intensity",
+      1.0, "feedback", 0.0, NULL);
+  fail_unless (gst_element_set_state (echo,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  caps = gst_caps_from_string (ECHO_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, echo, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  inbuffer =
+      gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, in, sizeof (in), 0,
+      sizeof (in), NULL, NULL);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, sizeof (in)) == 0);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... but it ends up being collected on the global buffer list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res,
+          sizeof (res)) == sizeof (res));
+  GST_INFO
+      ("expected %+lf %+lf %+lf %+lf %+lf %+lf %+lf %+lf %+lf %+lf real %+lf %+lf %+lf %+lf %+lf %+lf %+lf %+lf %+lf %+lf",
+      out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7], out[8],
+      out[9], res[0], res[1], res[2], res[3], res[4], res[5], res[6], res[7],
+      res[8], res[9]);
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, out, sizeof (out)) == 0);
+
+  /* cleanup */
+  cleanup_echo (echo);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_feedback)
+{
+  GstElement *echo;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble in[] = { 1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, };
+  gdouble out[] = { 1.0, -1.0, 0.0, 0.0, 1.0, -1.0, 0.0, 0.0, 1.0, -1.0 };
+  gdouble res[10];
+
+  echo = setup_echo ();
+  g_object_set (G_OBJECT (echo), "delay", (GstClockTime) 20000, "intensity",
+      1.0, "feedback", 1.0, NULL);
+  fail_unless (gst_element_set_state (echo,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  caps = gst_caps_from_string (ECHO_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, echo, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  inbuffer =
+      gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, in, sizeof (in), 0,
+      sizeof (in), NULL, NULL);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, sizeof (in)) == 0);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... but it ends up being collected on the global buffer list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  fail_unless (gst_buffer_extract (outbuffer, 0, res,
+          sizeof (res)) == sizeof (res));
+  GST_INFO
+      ("expected %+lf %+lf %+lf %+lf %+lf %+lf %+lf %+lf %+lf %+lf real %+lf %+lf %+lf %+lf %+lf %+lf %+lf %+lf %+lf %+lf",
+      out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7], out[8],
+      out[9], res[0], res[1], res[2], res[3], res[4], res[5], res[6], res[7],
+      res[8], res[9]);
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, out, sizeof (out)) == 0);
+
+  /* cleanup */
+  cleanup_echo (echo);
+}
+
+GST_END_TEST;
+
+static Suite *
+audioecho_suite (void)
+{
+  Suite *s = suite_create ("audioecho");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_passthrough);
+  tcase_add_test (tc_chain, test_echo);
+  tcase_add_test (tc_chain, test_feedback);
+
+  return s;
+}
+
+GST_CHECK_MAIN (audioecho);
diff --git a/tests/check/elements/audiofirfilter.c b/tests/check/elements/audiofirfilter.c
new file mode 100644
index 0000000..d8b452c
--- /dev/null
+++ b/tests/check/elements/audiofirfilter.c
@@ -0,0 +1,193 @@
+/* GStreamer
+ *
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <gst/gst.h>
+#include <gst/check/gstcheck.h>
+
+static gboolean have_eos = FALSE;
+
+static gboolean
+on_message (GstBus * bus, GstMessage * message, gpointer user_data)
+{
+  GMainLoop *loop = (GMainLoop *) user_data;
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_ERROR:
+    case GST_MESSAGE_WARNING:
+      g_assert_not_reached ();
+      g_main_loop_quit (loop);
+      break;
+
+    case GST_MESSAGE_EOS:
+      have_eos = TRUE;
+      g_main_loop_quit (loop);
+      break;
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+static void
+on_rate_changed (GstElement * element, gint rate, gpointer user_data)
+{
+  GValueArray *va;
+  GValue v = { 0, };
+
+  fail_unless (rate > 0);
+
+  va = g_value_array_new (6);
+
+  g_value_init (&v, G_TYPE_DOUBLE);
+  g_value_set_double (&v, 0.0);
+  g_value_array_append (va, &v);
+  g_value_reset (&v);
+  g_value_set_double (&v, 0.0);
+  g_value_array_append (va, &v);
+  g_value_reset (&v);
+  g_value_set_double (&v, 0.0);
+  g_value_array_append (va, &v);
+  g_value_reset (&v);
+  g_value_set_double (&v, 0.0);
+  g_value_array_append (va, &v);
+  g_value_reset (&v);
+  g_value_set_double (&v, 0.0);
+  g_value_array_append (va, &v);
+  g_value_reset (&v);
+  g_value_set_double (&v, 1.0);
+  g_value_array_append (va, &v);
+  g_value_reset (&v);
+
+  g_object_set (G_OBJECT (element), "kernel", va, NULL);
+
+  g_value_array_free (va);
+}
+
+static gboolean have_data = FALSE;
+
+static void
+on_handoff (GstElement * object, GstBuffer * buffer, GstPad * pad,
+    gpointer user_data)
+{
+  if (!have_data) {
+    GstMapInfo map;
+    gdouble *data;
+
+    gst_buffer_map (buffer, &map, GST_MAP_READ);
+    data = (gdouble *) map.data;
+
+    fail_unless (map.size > 5 * sizeof (gdouble));
+    fail_unless (data[0] == 0.0);
+    fail_unless (data[1] == 0.0);
+    fail_unless (data[2] == 0.0);
+    fail_unless (data[3] == 0.0);
+    fail_unless (data[4] == 0.0);
+    fail_unless (data[5] != 0.0);
+
+    gst_buffer_unmap (buffer, &map);
+    have_data = TRUE;
+  }
+}
+
+GST_START_TEST (test_pipeline)
+{
+  GstElement *pipeline, *src, *cfilter, *filter, *sink;
+  GstCaps *caps;
+  GstBus *bus;
+  GMainLoop *loop;
+
+  have_data = FALSE;
+  have_eos = FALSE;
+
+  pipeline = gst_element_factory_make ("pipeline", NULL);
+  fail_unless (pipeline != NULL);
+
+  src = gst_element_factory_make ("audiotestsrc", NULL);
+  fail_unless (src != NULL);
+  g_object_set (G_OBJECT (src), "num-buffers", 1000, NULL);
+
+  cfilter = gst_element_factory_make ("capsfilter", NULL);
+  fail_unless (cfilter != NULL);
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+  caps = gst_caps_new_simple ("audio/x-raw",
+      "format", G_TYPE_STRING, "F64BE", NULL);
+#else
+  caps = gst_caps_new_simple ("audio/x-raw",
+      "format", G_TYPE_STRING, "F64LE", NULL);
+#endif
+  g_object_set (G_OBJECT (cfilter), "caps", caps, NULL);
+  gst_caps_unref (caps);
+
+  filter = gst_element_factory_make ("audiofirfilter", NULL);
+  fail_unless (filter != NULL);
+  g_signal_connect (G_OBJECT (filter), "rate-changed",
+      G_CALLBACK (on_rate_changed), NULL);
+
+  sink = gst_element_factory_make ("fakesink", NULL);
+  fail_unless (sink != NULL);
+  g_object_set (G_OBJECT (sink), "signal-handoffs", TRUE, NULL);
+  g_signal_connect (G_OBJECT (sink), "handoff", G_CALLBACK (on_handoff), NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, cfilter, filter, sink, NULL);
+  fail_unless (gst_element_link_many (src, cfilter, filter, sink, NULL));
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+  gst_bus_add_signal_watch (bus);
+  g_signal_connect (G_OBJECT (bus), "message", G_CALLBACK (on_message), loop);
+
+  fail_if (gst_element_set_state (pipeline,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
+
+  g_main_loop_run (loop);
+
+  fail_unless (have_data);
+  fail_unless (have_eos);
+
+  fail_unless (gst_element_set_state (pipeline,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
+
+  gst_bus_remove_signal_watch (bus);
+  gst_object_unref (GST_OBJECT (bus));
+  g_main_loop_unref (loop);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
+static Suite *
+audiofirfilter_suite (void)
+{
+  Suite *s = suite_create ("audiofirfilter");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_pipeline);
+
+  return s;
+}
+
+GST_CHECK_MAIN (audiofirfilter);
diff --git a/tests/check/elements/audioiirfilter.c b/tests/check/elements/audioiirfilter.c
new file mode 100644
index 0000000..af2c9d3
--- /dev/null
+++ b/tests/check/elements/audioiirfilter.c
@@ -0,0 +1,190 @@
+/* GStreamer
+ *
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <gst/gst.h>
+#include <gst/check/gstcheck.h>
+
+static gboolean have_eos = FALSE;
+
+static gboolean
+on_message (GstBus * bus, GstMessage * message, gpointer user_data)
+{
+  GMainLoop *loop = (GMainLoop *) user_data;
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_ERROR:
+    case GST_MESSAGE_WARNING:
+      g_assert_not_reached ();
+      g_main_loop_quit (loop);
+      break;
+
+    case GST_MESSAGE_EOS:
+      have_eos = TRUE;
+      g_main_loop_quit (loop);
+      break;
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+static void
+on_rate_changed (GstElement * element, gint rate, gpointer user_data)
+{
+  GValueArray *va;
+  GValue v = { 0, };
+
+  fail_unless (rate > 0);
+
+  va = g_value_array_new (6);
+
+  g_value_init (&v, G_TYPE_DOUBLE);
+  g_value_set_double (&v, 0.0);
+  g_value_array_append (va, &v);
+  g_value_reset (&v);
+  g_value_set_double (&v, 0.0);
+  g_value_array_append (va, &v);
+  g_value_reset (&v);
+  g_value_set_double (&v, 0.0);
+  g_value_array_append (va, &v);
+  g_value_reset (&v);
+  g_value_set_double (&v, 0.0);
+  g_value_array_append (va, &v);
+  g_value_reset (&v);
+  g_value_set_double (&v, 0.0);
+  g_value_array_append (va, &v);
+  g_value_reset (&v);
+  g_value_set_double (&v, 1.0);
+  g_value_array_append (va, &v);
+  g_value_reset (&v);
+
+  g_object_set (G_OBJECT (element), "b", va, NULL);
+
+  g_value_array_free (va);
+
+  va = g_value_array_new (6);
+
+  g_value_set_double (&v, 1.0);
+  g_value_array_append (va, &v);
+  g_value_reset (&v);
+
+  g_object_set (G_OBJECT (element), "a", va, NULL);
+
+  g_value_array_free (va);
+}
+
+static gboolean have_data = FALSE;
+
+static void
+on_handoff (GstElement * object, GstBuffer * buffer, GstPad * pad,
+    gpointer user_data)
+{
+  if (!have_data) {
+    GstMapInfo map;
+    gfloat *data;
+
+    fail_unless (gst_buffer_map (buffer, &map, GST_MAP_READ));
+    data = (gfloat *) map.data;
+
+    fail_unless (map.size > 5 * sizeof (gdouble));
+    fail_unless (data[0] == 0.0);
+    fail_unless (data[1] == 0.0);
+    fail_unless (data[2] == 0.0);
+    fail_unless (data[3] == 0.0);
+    fail_unless (data[4] == 0.0);
+    fail_unless (data[5] != 0.0);
+
+    gst_buffer_unmap (buffer, &map);
+    have_data = TRUE;
+  }
+}
+
+GST_START_TEST (test_pipeline)
+{
+  GstElement *pipeline, *src, *filter, *sink;
+  GstBus *bus;
+  GMainLoop *loop;
+
+  have_data = FALSE;
+  have_eos = FALSE;
+
+  pipeline = gst_element_factory_make ("pipeline", NULL);
+  fail_unless (pipeline != NULL);
+
+  src = gst_element_factory_make ("audiotestsrc", NULL);
+  fail_unless (src != NULL);
+  g_object_set (G_OBJECT (src), "num-buffers", 1000, NULL);
+
+  filter = gst_element_factory_make ("audioiirfilter", NULL);
+  fail_unless (filter != NULL);
+  g_signal_connect (G_OBJECT (filter), "rate-changed",
+      G_CALLBACK (on_rate_changed), NULL);
+
+  sink = gst_element_factory_make ("fakesink", NULL);
+  fail_unless (sink != NULL);
+  g_object_set (G_OBJECT (sink), "signal-handoffs", TRUE, NULL);
+  g_signal_connect (G_OBJECT (sink), "handoff", G_CALLBACK (on_handoff), NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, filter, sink, NULL);
+  fail_unless (gst_element_link_many (src, filter, sink, NULL));
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+  gst_bus_add_signal_watch (bus);
+  g_signal_connect (G_OBJECT (bus), "message", G_CALLBACK (on_message), loop);
+
+  fail_if (gst_element_set_state (pipeline,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
+
+  g_main_loop_run (loop);
+
+  fail_unless (have_data);
+  fail_unless (have_eos);
+
+  fail_unless (gst_element_set_state (pipeline,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
+
+  gst_bus_remove_signal_watch (bus);
+  gst_object_unref (GST_OBJECT (bus));
+  g_main_loop_unref (loop);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
+static Suite *
+audioiirfilter_suite (void)
+{
+  Suite *s = suite_create ("audioiirfilter");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_pipeline);
+
+  return s;
+}
+
+GST_CHECK_MAIN (audioiirfilter);
diff --git a/tests/check/elements/audioinvert.c b/tests/check/elements/audioinvert.c
new file mode 100644
index 0000000..d121fdd
--- /dev/null
+++ b/tests/check/elements/audioinvert.c
@@ -0,0 +1,284 @@
+/* GStreamer
+ *
+ * unit test for audioinvert
+ *
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * Greatly based on the audiopanorama unit test
+ * Copyright (C) 2006 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gst/audio/audio.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/check/gstcheck.h>
+
+gboolean have_eos = FALSE;
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *mysrcpad, *mysinkpad;
+
+
+#define INVERT_CAPS_STRING    \
+    "audio/x-raw, "                             \
+    "format = (string) "GST_AUDIO_NE(S16)", "   \
+    "layout = (string) interleaved, "           \
+    "channels = (int) 1, "                      \
+    "rate = (int) 44100"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (S16) ", "
+        "layout = (string) interleaved, "
+        "channels = (int) 1, " "rate = (int) [ 1,  MAX ]")
+    );
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (S16) ", "
+        "layout = (string) interleaved, "
+        "channels = (int) 1, " "rate = (int) [ 1,  MAX ]")
+    );
+
+static GstElement *
+setup_invert (void)
+{
+  GstElement *invert;
+
+  GST_DEBUG ("setup_invert");
+  invert = gst_check_setup_element ("audioinvert");
+  mysrcpad = gst_check_setup_src_pad (invert, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (invert, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return invert;
+}
+
+static void
+cleanup_invert (GstElement * invert)
+{
+  GST_DEBUG ("cleanup_invert");
+
+  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (invert);
+  gst_check_teardown_sink_pad (invert);
+  gst_check_teardown_element (invert);
+}
+
+GST_START_TEST (test_passthrough)
+{
+  GstElement *invert;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[4] = { 16384, -256, 128, -512 };
+  gint16 *res;
+  GstMapInfo map;
+
+  invert = setup_invert ();
+  fail_unless (gst_element_set_state (invert,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (8);
+  gst_buffer_fill (inbuffer, 0, in, 8);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 8) == 0);
+  caps = gst_caps_from_string (INVERT_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, invert, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... but it ends up being collected on the global buffer list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gint16 *) map.data;
+  GST_INFO ("expected %+5d %+5d %+5d %+5d real %+5d %+5d %+5d %+5d",
+      in[0], in[1], in[2], in[3], res[0], res[1], res[2], res[3]);
+  gst_buffer_unmap (outbuffer, &map);
+
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, in, 8) == 0);
+
+  /* cleanup */
+  cleanup_invert (invert);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_zero)
+{
+  GstElement *invert;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[4] = { 16384, -256, 128, -512 };
+  gint16 out[4] = { 0, 0, 0, 0 };
+  gint16 *res;
+  GstMapInfo map;
+
+  invert = setup_invert ();
+  g_object_set (G_OBJECT (invert), "degree", 0.5, NULL);
+  fail_unless (gst_element_set_state (invert,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (8);
+  gst_buffer_fill (inbuffer, 0, in, 8);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 8) == 0);
+  caps = gst_caps_from_string (INVERT_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, invert, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gint16 *) map.data;
+  GST_INFO ("expected %+5d %+5d %+5d %+5d real %+5d %+5d %+5d %+5d",
+      out[0], out[1], out[2], out[3], res[0], res[1], res[2], res[3]);
+  gst_buffer_unmap (outbuffer, &map);
+
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, out, 8) == 0);
+
+  /* cleanup */
+  cleanup_invert (invert);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_full_inverse)
+{
+  GstElement *invert;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[4] = { 16384, -256, 128, -512 };
+  gint16 out[4] = { -16385, 255, -129, 511 };
+  gint16 *res;
+  GstMapInfo map;
+
+  invert = setup_invert ();
+  g_object_set (G_OBJECT (invert), "degree", 1.0, NULL);
+  fail_unless (gst_element_set_state (invert,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (8);
+  gst_buffer_fill (inbuffer, 0, in, 8);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 8) == 0);
+  caps = gst_caps_from_string (INVERT_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, invert, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gint16 *) map.data;
+  GST_INFO ("expected %+5d %+5d %+5d %+5d real %+5d %+5d %+5d %+5d",
+      out[0], out[1], out[2], out[3], res[0], res[1], res[2], res[3]);
+  gst_buffer_unmap (outbuffer, &map);
+
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, out, 8) == 0);
+
+  /* cleanup */
+  cleanup_invert (invert);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_25_inverse)
+{
+  GstElement *invert;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gint16 in[4] = { 16384, -256, 128, -512 };
+  gint16 out[4] = { 8191, -128, 63, -256 };
+  gint16 *res;
+  GstMapInfo map;
+
+  invert = setup_invert ();
+  g_object_set (G_OBJECT (invert), "degree", 0.25, NULL);
+  fail_unless (gst_element_set_state (invert,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (8);
+  gst_buffer_fill (inbuffer, 0, in, 8);
+  fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 8) == 0);
+  caps = gst_caps_from_string (INVERT_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, invert, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... and puts a new buffer on the global list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+  res = (gint16 *) map.data;
+  GST_INFO ("expected %+5d %+5d %+5d %+5d real %+5d %+5d %+5d %+5d",
+      out[0], out[1], out[2], out[3], res[0], res[1], res[2], res[3]);
+  gst_buffer_unmap (outbuffer, &map);
+
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, out, 8) == 0);
+
+  /* cleanup */
+  cleanup_invert (invert);
+}
+
+GST_END_TEST;
+
+static Suite *
+invert_suite (void)
+{
+  Suite *s = suite_create ("invert");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_passthrough);
+  tcase_add_test (tc_chain, test_zero);
+  tcase_add_test (tc_chain, test_full_inverse);
+  tcase_add_test (tc_chain, test_25_inverse);
+
+  return s;
+}
+
+GST_CHECK_MAIN (invert);
diff --git a/tests/check/elements/audiopanorama.c b/tests/check/elements/audiopanorama.c
new file mode 100644
index 0000000..3857119
--- /dev/null
+++ b/tests/check/elements/audiopanorama.c
@@ -0,0 +1,818 @@
+/* GStreamer
+ *
+ * unit test for audiopanorama
+ *
+ * Copyright (C) 2006 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gst/audio/audio.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/check/gstcheck.h>
+
+gboolean have_eos = FALSE;
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *mysrcpad, *mysinkpad;
+
+
+#define PANORAMA_S16_MONO_CAPS_STRING   \
+    "audio/x-raw, "                     \
+    "channels = (int) 1, "              \
+    "rate = (int) 44100, "              \
+    "layout = (string) interleaved, "   \
+    "format = (string) " GST_AUDIO_NE(S16)
+
+#define PANORAMA_S16_STEREO_CAPS_STRING \
+    "audio/x-raw, "                     \
+    "channels = (int) 2, "              \
+    "channel-mask = (bitmask) 3, "      \
+    "rate = (int) 44100, "              \
+    "layout = (string) interleaved, "   \
+    "format = (string) " GST_AUDIO_NE(S16)
+
+#define PANORAMA_F32_MONO_CAPS_STRING   \
+    "audio/x-raw, "                     \
+    "channels = (int) 1, "              \
+    "rate = (int) 44100, "              \
+    "layout = (string) interleaved, "   \
+    "format = (string) " GST_AUDIO_NE(F32)
+
+#define PANORAMA_F32_STEREO_CAPS_STRING \
+    "audio/x-raw, "                     \
+    "channels = (int) 2, "              \
+    "channel-mask = (bitmask) 3, "      \
+    "rate = (int) 44100, "              \
+    "layout = (string) interleaved, "   \
+    "format = (string) " GST_AUDIO_NE(F32)
+
+#define PANORAMA_WRONG_CAPS_STRING  \
+    "audio/x-raw, "                     \
+    "channels = (int) 5, "              \
+    "rate = (int) 44100, "              \
+    "layout = (string) interleaved, "   \
+    "format = (string) " GST_AUDIO_NE(U16)
+
+
+static GstStaticPadTemplate sinktemplate[2] = {
+  GST_STATIC_PAD_TEMPLATE ("sink",
+      GST_PAD_SINK,
+      GST_PAD_ALWAYS,
+      GST_STATIC_CAPS ("audio/x-raw, "
+          "channels = (int) 2, "
+          "rate = (int) [ 1,  MAX ], "
+          "layout = (string) interleaved, "
+          "format = (string) " GST_AUDIO_NE (S16))
+      ),
+  GST_STATIC_PAD_TEMPLATE ("sink",
+      GST_PAD_SINK,
+      GST_PAD_ALWAYS,
+      GST_STATIC_CAPS ("audio/x-raw, "
+          "channels = (int) 2, "
+          "rate = (int) [ 1,  MAX ], "
+          "layout = (string) interleaved, "
+          "format = (string) " GST_AUDIO_NE (F32))
+      ),
+};
+
+static GstStaticPadTemplate msrctemplate[2] = {
+  GST_STATIC_PAD_TEMPLATE ("src",
+      GST_PAD_SRC,
+      GST_PAD_ALWAYS,
+      GST_STATIC_CAPS ("audio/x-raw, "
+          "channels = (int) 1, "
+          "rate = (int) [ 1,  MAX ], "
+          "layout = (string) interleaved, "
+          "format = (string) " GST_AUDIO_NE (S16))
+      ),
+  GST_STATIC_PAD_TEMPLATE ("src",
+      GST_PAD_SRC,
+      GST_PAD_ALWAYS,
+      GST_STATIC_CAPS ("audio/x-raw, "
+          "channels = (int) 1, "
+          "rate = (int) [ 1,  MAX ], "
+          "layout = (string) interleaved, "
+          "format = (string) " GST_AUDIO_NE (F32))
+      ),
+};
+
+static GstStaticPadTemplate ssrctemplate[2] = {
+  GST_STATIC_PAD_TEMPLATE ("src",
+      GST_PAD_SRC,
+      GST_PAD_ALWAYS,
+      GST_STATIC_CAPS ("audio/x-raw, "
+          "channels = (int) 2, "
+          "rate = (int) [ 1,  MAX ], "
+          "layout = (string) interleaved, "
+          "format = (string) " GST_AUDIO_NE (S16))
+      ),
+  GST_STATIC_PAD_TEMPLATE ("src",
+      GST_PAD_SRC,
+      GST_PAD_ALWAYS,
+      GST_STATIC_CAPS ("audio/x-raw, "
+          "channels = (int) 2, "
+          "rate = (int) [ 1,  MAX ], "
+          "layout = (string) interleaved, "
+          "format = (string) " GST_AUDIO_NE (F32))
+      ),
+};
+
+static GstElement *
+setup_panorama (GstStaticPadTemplate * srctemplate, gint fmt,
+    const gchar * caps_str)
+{
+  GstElement *panorama;
+
+  GST_DEBUG ("setup_panorama");
+  panorama = gst_check_setup_element ("audiopanorama");
+  mysrcpad = gst_check_setup_src_pad (panorama, &srctemplate[fmt]);
+  mysinkpad = gst_check_setup_sink_pad (panorama, &sinktemplate[fmt]);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  if (caps_str) {
+    GstCaps *caps = gst_caps_from_string (caps_str);
+    gst_check_setup_events (mysrcpad, panorama, caps, GST_FORMAT_TIME);
+    gst_caps_unref (caps);
+  }
+  return panorama;
+}
+
+static GstElement *
+setup_panorama_s16_m (gint method, gfloat pan)
+{
+  GstElement *panorama;
+  panorama = setup_panorama (msrctemplate, 0, PANORAMA_S16_MONO_CAPS_STRING);
+  g_object_set (G_OBJECT (panorama), "method", method, "panorama", pan, NULL);
+  gst_element_set_state (panorama, GST_STATE_PLAYING);
+  GST_DEBUG ("panorama(mono) ready");
+
+  return panorama;
+}
+
+static GstElement *
+setup_panorama_f32_m (gint method, gfloat pan)
+{
+  GstElement *panorama;
+  panorama = setup_panorama (msrctemplate, 1, PANORAMA_F32_MONO_CAPS_STRING);
+  g_object_set (G_OBJECT (panorama), "method", method, "panorama", pan, NULL);
+  gst_element_set_state (panorama, GST_STATE_PLAYING);
+  GST_DEBUG ("panorama(mono) ready");
+
+  return panorama;
+}
+
+static GstElement *
+setup_panorama_s16_s (gint method, gfloat pan)
+{
+  GstElement *panorama;
+  panorama = setup_panorama (ssrctemplate, 0, PANORAMA_S16_STEREO_CAPS_STRING);
+  g_object_set (G_OBJECT (panorama), "method", method, "panorama", pan, NULL);
+  gst_element_set_state (panorama, GST_STATE_PLAYING);
+  GST_DEBUG ("panorama(stereo) ready");
+
+  return panorama;
+}
+
+static GstElement *
+setup_panorama_f32_s (gint method, gfloat pan)
+{
+  GstElement *panorama;
+  panorama = setup_panorama (ssrctemplate, 1, PANORAMA_F32_STEREO_CAPS_STRING);
+  g_object_set (G_OBJECT (panorama), "method", method, "panorama", pan, NULL);
+  gst_element_set_state (panorama, GST_STATE_PLAYING);
+  GST_DEBUG ("panorama(stereo) ready");
+
+  return panorama;
+}
+
+static void
+cleanup_panorama (GstElement * panorama)
+{
+  GST_DEBUG ("cleaning up");
+  gst_element_set_state (panorama, GST_STATE_NULL);
+
+  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (panorama);
+  gst_check_teardown_sink_pad (panorama);
+  gst_check_teardown_element (panorama);
+}
+
+static GstBuffer *
+setup_buffer (gpointer data, gsize size)
+{
+  return gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, data, size, 0,
+      size, NULL, NULL);
+}
+
+static void
+do_panorama (gpointer in_data, gsize in_size, gpointer out_data, gsize out_size)
+{
+  GstBuffer *in, *out;
+
+  in = setup_buffer (in_data, in_size);
+  fail_unless (gst_pad_push (mysrcpad, in) == GST_FLOW_OK);
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((out = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (gst_buffer_extract (out, 0, out_data, out_size) == out_size);
+}
+
+/* the tests */
+
+GST_START_TEST (test_ref_counts)
+{
+  GstElement *panorama;
+  GstBuffer *inbuffer, *outbuffer;
+  gint16 in[2] = { 16384, -256 };
+
+  panorama = setup_panorama (msrctemplate, 0, PANORAMA_S16_MONO_CAPS_STRING);
+  fail_unless (gst_element_set_state (panorama,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = setup_buffer (in, sizeof (in));
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... but it ends up being collected on the global buffer list */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_if (inbuffer == outbuffer);
+
+  /* cleanup */
+  fail_unless (gst_element_set_state (panorama,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+  ASSERT_OBJECT_REFCOUNT (panorama, "panorama", 1);
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_wrong_caps)
+{
+  GstElement *panorama;
+  GstBuffer *inbuffer;
+  gint16 in[2] = { 16384, -256 };
+  GstBus *bus;
+  GstMessage *message;
+  GstCaps *caps;
+
+  panorama = setup_panorama (msrctemplate, 0, NULL);
+  bus = gst_bus_new ();
+  gst_element_set_state (panorama, GST_STATE_PLAYING);
+
+  inbuffer = setup_buffer (in, sizeof (in));
+  gst_buffer_ref (inbuffer);
+
+  /* set a bus here so we avoid getting state change messages */
+  gst_element_set_bus (panorama, bus);
+
+  caps = gst_caps_from_string (PANORAMA_WRONG_CAPS_STRING);
+  /* this actually succeeds, because the caps event is sticky */
+  gst_check_setup_events (mysrcpad, panorama, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  /* pushing gives an error because it can't negotiate with wrong caps */
+  fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer),
+      GST_FLOW_NOT_NEGOTIATED);
+  /* ... and the buffer would have been lost if we didn't ref it ourselves */
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+  gst_buffer_unref (inbuffer);
+  fail_unless_equals_int (g_list_length (buffers), 0);
+
+  /* panorama_set_caps should not have been called since basetransform caught
+   * the negotiation problem */
+  fail_if ((message = gst_bus_pop (bus)) != NULL);
+
+  /* cleanup */
+  gst_element_set_bus (panorama, NULL);
+  gst_object_unref (GST_OBJECT (bus));
+  gst_element_set_state (panorama, GST_STATE_NULL);
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+/* processing for method=psy */
+
+GST_START_TEST (test_s16_mono_middle)
+{
+  gint16 in[2] = { 16384, -256 };
+  gint16 out[4] = { 8192, 8192, -128, -128 };
+  gint16 res[4];
+  GstElement *panorama = setup_panorama_s16_m (0, 0.0);
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+5d %+5d %+5d %+5d", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+5d %+5d %+5d %+5d", res[0], res[1], res[2], res[3]);
+  fail_unless (memcmp (res, out, sizeof (res)) == 0);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_s16_mono_left)
+{
+  gint16 in[2] = { 16384, -256 };
+  gint16 out[4] = { 16384, 0, -256, 0 };
+  gint16 res[4];
+  GstElement *panorama = setup_panorama_s16_m (0, -1.0);
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+5d %+5d %+5d %+5d", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+5d %+5d %+5d %+5d", res[0], res[1], res[2], res[3]);
+  fail_unless (memcmp (res, out, sizeof (res)) == 0);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_s16_mono_right)
+{
+  gint16 in[2] = { 16384, -256 };
+  gint16 out[4] = { 0, 16384, 0, -256 };
+  gint16 res[4];
+  GstElement *panorama = setup_panorama_s16_m (0, 1.0);
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+5d %+5d %+5d %+5d", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+5d %+5d %+5d %+5d", res[0], res[1], res[2], res[3]);
+  fail_unless (memcmp (res, out, sizeof (res)) == 0);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_s16_stereo_middle)
+{
+  gint16 in[4] = { 16384, -256, 8192, 128 };
+  gint16 res[4];
+  GstElement *panorama = setup_panorama_s16_s (0, 0.0);
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+5d %+5d %+5d %+5d", in[0], in[1], in[2], in[3]);
+  GST_INFO ("real %+5d %+5d %+5d %+5d", res[0], res[1], res[2], res[3]);
+  fail_unless (memcmp (res, in, sizeof (res)) == 0);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_s16_stereo_left)
+{
+  gint16 in[4] = { 16384, -256, 8192, 128 };
+  gint16 out[4] = { 16384 - 256, 0, 8192 + 128, 0 };
+  gint16 res[4];
+  GstElement *panorama = setup_panorama_s16_s (0, -1.0);
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+5d %+5d %+5d %+5d", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+5d %+5d %+5d %+5d", res[0], res[1], res[2], res[3]);
+  fail_unless (memcmp (res, out, sizeof (res)) == 0);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_s16_stereo_right)
+{
+  gint16 in[4] = { 16384, -256, 8192, 128 };
+  gint16 out[4] = { 0, -256 + 16384, 0, 128 + 8192 };
+  gint16 res[4];
+  GstElement *panorama = setup_panorama_s16_s (0, 1.0);
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+5d %+5d %+5d %+5d", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+5d %+5d %+5d %+5d", res[0], res[1], res[2], res[3]);
+  fail_unless (memcmp (res, out, sizeof (res)) == 0);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_f32_mono_middle)
+{
+  gfloat in[2] = { 0.5, -0.2 };
+  gfloat out[4] = { 0.25, 0.25, -0.1, -0.1 };
+  gfloat res[4];
+  GstElement *panorama = setup_panorama_f32_m (0, 0.0);
+  gint i;
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+4.2f %+4.2f %+4.2f %+4.2f", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+4.2f %+4.2f %+4.2f %+4.2f", res[0], res[1], res[2], res[3]);
+  for (i = 0; i < 4; i++)
+    fail_unless (res[i] == out[i], "difference at pos=%d", i);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_f32_mono_left)
+{
+  gfloat in[2] = { 0.5, -0.2 };
+  gfloat out[4] = { 0.5, 0.0, -0.2, 0.0 };
+  gfloat res[4];
+  GstElement *panorama = setup_panorama_f32_m (0, -1.0);
+  gint i;
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+4.2f %+4.2f %+4.2f %+4.2f", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+4.2f %+4.2f %+4.2f %+4.2f", res[0], res[1], res[2], res[3]);
+  for (i = 0; i < 4; i++)
+    fail_unless (res[i] == out[i], "difference at pos=%d", i);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_f32_mono_right)
+{
+  gfloat in[2] = { 0.5, -0.2 };
+  gfloat out[4] = { 0.0, 0.5, 0.0, -0.2 };
+  gfloat res[4];
+  GstElement *panorama = setup_panorama_f32_m (0, 1.0);
+  gint i;
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+4.2f %+4.2f %+4.2f %+4.2f", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+4.2f %+4.2f %+4.2f %+4.2f", res[0], res[1], res[2], res[3]);
+  for (i = 0; i < 4; i++)
+    fail_unless (res[i] == out[i], "difference at pos=%d", i);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_f32_stereo_middle)
+{
+  gfloat in[4] = { 0.5, -0.2, 0.25, 0.1 };
+  gfloat res[4];
+  GstElement *panorama = setup_panorama_f32_s (0, 0.0);
+  gint i;
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+4.2f %+4.2f %+4.2f %+4.2f", in[0], in[1], in[2], in[3]);
+  GST_INFO ("real %+4.2f %+4.2f %+4.2f %+4.2f", res[0], res[1], res[2], res[3]);
+  for (i = 0; i < 4; i++)
+    fail_unless (res[i] == in[i], "difference at pos=%d", i);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_f32_stereo_left)
+{
+  gfloat in[4] = { 0.5, -0.2, 0.25, 0.1 };
+  gfloat out[4] = { 0.5 - 0.2, 0.0, 0.25 + 0.1, 0.0 };
+  gfloat res[4];
+  GstElement *panorama = setup_panorama_f32_s (0, -1.0);
+  gint i;
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+4.2f %+4.2f %+4.2f %+4.2f", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+4.2f %+4.2f %+4.2f %+4.2f", res[0], res[1], res[2], res[3]);
+  for (i = 0; i < 4; i++)
+    fail_unless (res[i] == out[i], "difference at pos=%d", i);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_f32_stereo_right)
+{
+  gfloat in[4] = { 0.5, -0.2, 0.25, 0.1 };
+  gfloat out[4] = { 0.0, -0.2 + 0.5, 0.0, 0.1 + 0.25 };
+  gfloat res[4];
+  GstElement *panorama = setup_panorama_f32_s (0, 1.0);
+  gint i;
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+4.2f %+4.2f %+4.2f %+4.2f", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+4.2f %+4.2f %+4.2f %+4.2f", res[0], res[1], res[2], res[3]);
+  for (i = 0; i < 4; i++)
+    fail_unless (res[i] == out[i], "difference at pos=%d", i);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+/* processing for method=simple */
+
+GST_START_TEST (test_s16_mono_middle_simple)
+{
+  gint16 in[2] = { 16384, -256 };
+  gint16 out[4] = { 16384, 16384, -256, -256 };
+  gint16 res[4];
+  GstElement *panorama = setup_panorama_s16_m (1, 0.0);
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+5d %+5d %+5d %+5d", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+5d %+5d %+5d %+5d", res[0], res[1], res[2], res[3]);
+  fail_unless (memcmp (res, out, sizeof (res)) == 0);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_s16_mono_left_simple)
+{
+  gint16 in[2] = { 16384, -256 };
+  gint16 out[4] = { 16384, 0, -256, 0 };
+  gint16 res[4];
+  GstElement *panorama = setup_panorama_s16_m (1, -1.0);
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+5d %+5d %+5d %+5d", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+5d %+5d %+5d %+5d", res[0], res[1], res[2], res[3]);
+  fail_unless (memcmp (res, out, sizeof (res)) == 0);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_s16_mono_right_simple)
+{
+  gint16 in[2] = { 16384, -256 };
+  gint16 out[4] = { 0, 16384, 0, -256 };
+  gint16 res[4];
+  GstElement *panorama = setup_panorama_s16_m (1, 1.0);
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+5d %+5d %+5d %+5d", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+5d %+5d %+5d %+5d", res[0], res[1], res[2], res[3]);
+  fail_unless (memcmp (res, out, sizeof (res)) == 0);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_s16_stereo_middle_simple)
+{
+  gint16 in[4] = { 16384, -256, 8192, 128 };
+  gint16 res[4];
+  GstElement *panorama = setup_panorama_s16_s (1, 0.0);
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+5d %+5d %+5d %+5d", in[0], in[1], in[2], in[3]);
+  GST_INFO ("real %+5d %+5d %+5d %+5d", res[0], res[1], res[2], res[3]);
+  fail_unless (memcmp (res, in, sizeof (res)) == 0);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_s16_stereo_left_simple)
+{
+  gint16 in[4] = { 16384, -256, 8192, 128 };
+  gint16 out[4] = { 16384, 0, 8192, 0 };
+  gint16 res[4];
+  GstElement *panorama = setup_panorama_s16_s (1, -1.0);
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+5d %+5d %+5d %+5d", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+5d %+5d %+5d %+5d", res[0], res[1], res[2], res[3]);
+  fail_unless (memcmp (res, out, sizeof (res)) == 0);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_s16_stereo_right_simple)
+{
+  gint16 in[4] = { 16384, -256, 8192, 128 };
+  gint16 out[4] = { 0, -256, 0, 128 };
+  gint16 res[4];
+  GstElement *panorama = setup_panorama_s16_s (1, 1.0);
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+5d %+5d %+5d %+5d", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+5d %+5d %+5d %+5d", res[0], res[1], res[2], res[3]);
+  fail_unless (memcmp (res, out, sizeof (res)) == 0);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+//-----------------------------------------------------------------------------
+
+GST_START_TEST (test_f32_mono_middle_simple)
+{
+  gfloat in[2] = { 0.5, -0.2 };
+  gfloat out[4] = { 0.5, 0.5, -0.2, -0.2 };
+  gfloat res[4];
+  GstElement *panorama = setup_panorama_f32_m (1, 0.0);
+  gint i;
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+4.2f %+4.2f %+4.2f %+4.2f", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+4.2f %+4.2f %+4.2f %+4.2f", res[0], res[1], res[2], res[3]);
+  for (i = 0; i < 4; i++)
+    fail_unless (res[i] == out[i], "difference at pos=%d", i);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_f32_mono_left_simple)
+{
+  gfloat in[2] = { 0.5, -0.2 };
+  gfloat out[4] = { 0.5, 0.0, -0.2, 0.0 };
+  gfloat res[4];
+  GstElement *panorama = setup_panorama_f32_m (1, -1.0);
+  gint i;
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+4.2f %+4.2f %+4.2f %+4.2f", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+4.2f %+4.2f %+4.2f %+4.2f", res[0], res[1], res[2], res[3]);
+  for (i = 0; i < 4; i++)
+    fail_unless (res[i] == out[i], "difference at pos=%d", i);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_f32_mono_right_simple)
+{
+  gfloat in[2] = { 0.5, -0.2 };
+  gfloat out[4] = { 0.0, 0.5, 0.0, -0.2 };
+  gfloat res[4];
+  GstElement *panorama = setup_panorama_f32_m (1, 1.0);
+  gint i;
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+4.2f %+4.2f %+4.2f %+4.2f", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+4.2f %+4.2f %+4.2f %+4.2f", res[0], res[1], res[2], res[3]);
+  for (i = 0; i < 4; i++)
+    fail_unless (res[i] == out[i], "difference at pos=%d", i);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_f32_stereo_middle_simple)
+{
+  gfloat in[4] = { 0.5, -0.2, 0.25, 0.1 };
+  gfloat res[4];
+  GstElement *panorama = setup_panorama_f32_s (1, 0.0);
+  gint i;
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+4.2f %+4.2f %+4.2f %+4.2f", in[0], in[1], in[2], in[3]);
+  GST_INFO ("real %+4.2f %+4.2f %+4.2f %+4.2f", res[0], res[1], res[2], res[3]);
+  for (i = 0; i < 4; i++)
+    fail_unless (res[i] == in[i], "difference at pos=%d", i);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_f32_stereo_left_simple)
+{
+  gfloat in[4] = { 0.5, -0.2, 0.25, 0.1 };
+  gfloat out[4] = { 0.5, 0.0, 0.25, 0.0 };
+  gfloat res[4];
+  GstElement *panorama = setup_panorama_f32_s (1, -1.0);
+  gint i;
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+4.2f %+4.2f %+4.2f %+4.2f", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+4.2f %+4.2f %+4.2f %+4.2f", res[0], res[1], res[2], res[3]);
+  for (i = 0; i < 4; i++)
+    fail_unless (res[i] == out[i], "difference at pos=%d", i);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_f32_stereo_right_simple)
+{
+  gfloat in[4] = { 0.5, -0.2, 0.25, 0.1 };
+  gfloat out[4] = { 0.0, -0.2, 0.0, 0.1 };
+  gfloat res[4];
+  GstElement *panorama = setup_panorama_f32_s (1, 1.0);
+  gint i;
+
+  do_panorama (in, sizeof (in), res, sizeof (res));
+
+  GST_INFO ("exp. %+4.2f %+4.2f %+4.2f %+4.2f", out[0], out[1], out[2], out[3]);
+  GST_INFO ("real %+4.2f %+4.2f %+4.2f %+4.2f", res[0], res[1], res[2], res[3]);
+  for (i = 0; i < 4; i++)
+    fail_unless (res[i] == out[i], "difference at pos=%d", i);
+
+  cleanup_panorama (panorama);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+panorama_suite (void)
+{
+  Suite *s = suite_create ("panorama");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_ref_counts);
+  tcase_add_test (tc_chain, test_wrong_caps);
+  /* processing for method=psy */
+  tcase_add_test (tc_chain, test_s16_mono_middle);
+  tcase_add_test (tc_chain, test_s16_mono_left);
+  tcase_add_test (tc_chain, test_s16_mono_right);
+  tcase_add_test (tc_chain, test_s16_stereo_middle);
+  tcase_add_test (tc_chain, test_s16_stereo_left);
+  tcase_add_test (tc_chain, test_s16_stereo_right);
+  tcase_add_test (tc_chain, test_f32_mono_middle);
+  tcase_add_test (tc_chain, test_f32_mono_left);
+  tcase_add_test (tc_chain, test_f32_mono_right);
+  tcase_add_test (tc_chain, test_f32_stereo_middle);
+  tcase_add_test (tc_chain, test_f32_stereo_left);
+  tcase_add_test (tc_chain, test_f32_stereo_right);
+  /* processing for method=simple */
+  tcase_add_test (tc_chain, test_s16_mono_middle_simple);
+  tcase_add_test (tc_chain, test_s16_mono_left_simple);
+  tcase_add_test (tc_chain, test_s16_mono_right_simple);
+  tcase_add_test (tc_chain, test_s16_stereo_middle_simple);
+  tcase_add_test (tc_chain, test_s16_stereo_left_simple);
+  tcase_add_test (tc_chain, test_s16_stereo_right_simple);
+  tcase_add_test (tc_chain, test_f32_mono_middle_simple);
+  tcase_add_test (tc_chain, test_f32_mono_left_simple);
+  tcase_add_test (tc_chain, test_f32_mono_right_simple);
+  tcase_add_test (tc_chain, test_f32_stereo_middle_simple);
+  tcase_add_test (tc_chain, test_f32_stereo_left_simple);
+  tcase_add_test (tc_chain, test_f32_stereo_right_simple);
+
+  return s;
+}
+
+GST_CHECK_MAIN (panorama);
diff --git a/tests/check/elements/audiowsincband.c b/tests/check/elements/audiowsincband.c
new file mode 100644
index 0000000..2235abe
--- /dev/null
+++ b/tests/check/elements/audiowsincband.c
@@ -0,0 +1,1137 @@
+/* GStreamer
+ *
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * audiowsincband.c: Unit test for the audiowsincband element
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/check/gstcheck.h>
+
+#include <math.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *mysrcpad, *mysinkpad;
+
+#define AUDIO_WSINC_BAND_CAPS_STRING_32          \
+    "audio/x-raw, "                              \
+    "format = (string) " GST_AUDIO_NE (F32) ", " \
+    "layout = (string) interleaved, "            \
+    "channels = (int) 1, "                       \
+    "rate = (int) 44100"
+
+#define AUDIO_WSINC_BAND_CAPS_STRING_64          \
+    "audio/x-raw, "                              \
+    "format = (string) " GST_AUDIO_NE (F64) ", " \
+    "layout = (string) interleaved, "            \
+    "channels = (int) 1, "                       \
+    "rate = (int) 44100"
+
+#define FORMATS "{ "GST_AUDIO_NE (F32)","GST_AUDIO_NE (F64)" }"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " FORMATS ", "
+        "layout = (string) interleaved, "
+        "channels = (int) 1, " "rate = (int) 44100")
+    );
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " FORMATS ", "
+        "layout = (string) interleaved, "
+        "channels = (int) 1, " "rate = (int) 44100")
+    );
+
+static GstElement *
+setup_audiowsincband (void)
+{
+  GstElement *audiowsincband;
+
+  GST_DEBUG ("setup_audiowsincband");
+  audiowsincband = gst_check_setup_element ("audiowsincband");
+  mysrcpad = gst_check_setup_src_pad (audiowsincband, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (audiowsincband, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return audiowsincband;
+}
+
+static void
+cleanup_audiowsincband (GstElement * audiowsincband)
+{
+  GST_DEBUG ("cleanup_audiowsincband");
+
+  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (audiowsincband);
+  gst_check_teardown_sink_pad (audiowsincband);
+  gst_check_teardown_element (audiowsincband);
+}
+
+/* Test if data containing only one frequency component
+ * at rate/2 is erased with bandpass mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_32_bp_0hz)
+{
+  GstElement *audiowsincband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsincband = setup_audiowsincband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiowsincband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "length", 31, NULL);
+
+  fail_unless (gst_element_set_state (audiowsincband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsincband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gfloat));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_BAND_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiowsincband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gfloat *) map.data;
+    buffer_length = map.size / sizeof (gfloat);
+
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    fail_unless (rms <= 0.1);
+
+    gst_buffer_unmap (outbuffer, &map);
+  }
+
+  /* cleanup */
+  cleanup_audiowsincband (audiowsincband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at the band center is preserved with bandreject mode
+ * and a 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_32_bp_11025hz)
+{
+  GstElement *audiowsincband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsincband = setup_audiowsincband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiowsincband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "length", 31, NULL);
+
+  fail_unless (gst_element_set_state (audiowsincband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsincband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gfloat));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i += 4) {
+    in[i] = 0.0;
+    in[i + 1] = 1.0;
+    in[i + 2] = 0.0;
+    in[i + 3] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_BAND_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiowsincband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gfloat *) map.data;
+    buffer_length = map.size / sizeof (gfloat);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    fail_unless (rms >= 0.4);
+    gst_buffer_unmap (outbuffer, &map);
+  }
+
+  /* cleanup */
+  cleanup_audiowsincband (audiowsincband);
+}
+
+GST_END_TEST;
+
+
+/* Test if data containing only one frequency component
+ * at rate/2 is erased with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_32_bp_22050hz)
+{
+  GstElement *audiowsincband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsincband = setup_audiowsincband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiowsincband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "length", 31, NULL);
+
+  fail_unless (gst_element_set_state (audiowsincband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsincband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gfloat));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_BAND_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiowsincband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gfloat *) map.data;
+    buffer_length = map.size / sizeof (gfloat);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    fail_unless (rms <= 0.3);
+    gst_buffer_unmap (outbuffer, &map);
+  }
+
+  /* cleanup */
+  cleanup_audiowsincband (audiowsincband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is preserved with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_32_br_0hz)
+{
+  GstElement *audiowsincband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsincband = setup_audiowsincband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiowsincband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "length", 31, NULL);
+
+  fail_unless (gst_element_set_state (audiowsincband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsincband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gfloat));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_BAND_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiowsincband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gfloat *) map.data;
+    buffer_length = map.size / sizeof (gfloat);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    fail_unless (rms >= 0.9);
+    gst_buffer_unmap (outbuffer, &map);
+  }
+
+  /* cleanup */
+  cleanup_audiowsincband (audiowsincband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at the band center is erased with bandreject mode
+ * and a 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_32_br_11025hz)
+{
+  GstElement *audiowsincband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsincband = setup_audiowsincband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiowsincband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "length", 31, NULL);
+
+  fail_unless (gst_element_set_state (audiowsincband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsincband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gfloat));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+
+  for (i = 0; i < 1024; i += 4) {
+    in[i] = 0.0;
+    in[i + 1] = 1.0;
+    in[i + 2] = 0.0;
+    in[i + 3] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_BAND_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiowsincband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gfloat *) map.data;
+    buffer_length = map.size / sizeof (gfloat);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    fail_unless (rms <= 0.35);
+    gst_buffer_unmap (outbuffer, &map);
+  }
+
+  /* cleanup */
+  cleanup_audiowsincband (audiowsincband);
+}
+
+GST_END_TEST;
+
+
+/* Test if data containing only one frequency component
+ * at rate/2 is preserved with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_32_br_22050hz)
+{
+  GstElement *audiowsincband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsincband = setup_audiowsincband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiowsincband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "length", 31, NULL);
+
+  fail_unless (gst_element_set_state (audiowsincband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsincband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gfloat));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 1024; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_BAND_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiowsincband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gfloat *) map.data;
+    buffer_length = map.size / sizeof (gfloat);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    fail_unless (rms >= 0.9);
+    gst_buffer_unmap (outbuffer, &map);
+  }
+
+  /* cleanup */
+  cleanup_audiowsincband (audiowsincband);
+}
+
+GST_END_TEST;
+
+/* Test if buffers smaller than the kernel size are handled
+ * correctly without accessing wrong memory areas */
+GST_START_TEST (test_32_small_buffer)
+{
+  GstElement *audiowsincband;
+  GstBuffer *inbuffer;
+  GstCaps *caps;
+  gfloat *in;
+  gint i;
+  GstMapInfo map;
+  GstSegment segment;
+
+  audiowsincband = setup_audiowsincband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiowsincband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "length", 101, NULL);
+
+  fail_unless (gst_element_set_state (audiowsincband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsincband), "lower-frequency",
+      44100 / 4.0 - 44100 / 16.0, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "upper-frequency",
+      44100 / 4.0 + 44100 / 16.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (20 * sizeof (gfloat));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 20; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_BAND_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiowsincband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  /* cleanup */
+  cleanup_audiowsincband (audiowsincband);
+}
+
+GST_END_TEST;
+
+
+
+
+
+
+
+
+
+/* Test if data containing only one frequency component
+ * at rate/2 is erased with bandpass mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_64_bp_0hz)
+{
+  GstElement *audiowsincband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsincband = setup_audiowsincband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiowsincband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "length", 31, NULL);
+
+  fail_unless (gst_element_set_state (audiowsincband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsincband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_BAND_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiowsincband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gdouble *) map.data;
+    buffer_length = map.size / sizeof (gdouble);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    fail_unless (rms <= 0.1);
+    gst_buffer_unmap (outbuffer, &map);
+  }
+
+  /* cleanup */
+  cleanup_audiowsincband (audiowsincband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at the band center is preserved with bandreject mode
+ * and a 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_64_bp_11025hz)
+{
+  GstElement *audiowsincband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsincband = setup_audiowsincband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiowsincband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "length", 31, NULL);
+
+  fail_unless (gst_element_set_state (audiowsincband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsincband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i += 4) {
+    in[i] = 0.0;
+    in[i + 1] = 1.0;
+    in[i + 2] = 0.0;
+    in[i + 3] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_BAND_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiowsincband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gdouble *) map.data;
+    buffer_length = map.size / sizeof (gdouble);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    fail_unless (rms >= 0.4);
+    gst_buffer_unmap (outbuffer, &map);
+  }
+
+  /* cleanup */
+  cleanup_audiowsincband (audiowsincband);
+}
+
+GST_END_TEST;
+
+
+/* Test if data containing only one frequency component
+ * at rate/2 is erased with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_64_bp_22050hz)
+{
+  GstElement *audiowsincband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsincband = setup_audiowsincband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiowsincband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "length", 31, NULL);
+
+  fail_unless (gst_element_set_state (audiowsincband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsincband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_BAND_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiowsincband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gdouble *) map.data;
+    buffer_length = map.size / sizeof (gdouble);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    fail_unless (rms <= 0.3);
+    gst_buffer_unmap (outbuffer, &map);
+  }
+
+  /* cleanup */
+  cleanup_audiowsincband (audiowsincband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is preserved with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_64_br_0hz)
+{
+  GstElement *audiowsincband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsincband = setup_audiowsincband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiowsincband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "length", 31, NULL);
+
+  fail_unless (gst_element_set_state (audiowsincband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsincband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_BAND_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiowsincband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gdouble *) map.data;
+    buffer_length = map.size / sizeof (gdouble);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    fail_unless (rms >= 0.9);
+    gst_buffer_unmap (outbuffer, &map);
+  }
+
+  /* cleanup */
+  cleanup_audiowsincband (audiowsincband);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at the band center is erased with bandreject mode
+ * and a 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_64_br_11025hz)
+{
+  GstElement *audiowsincband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsincband = setup_audiowsincband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiowsincband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "length", 31, NULL);
+
+  fail_unless (gst_element_set_state (audiowsincband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsincband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+
+  for (i = 0; i < 1024; i += 4) {
+    in[i] = 0.0;
+    in[i + 1] = 1.0;
+    in[i + 2] = 0.0;
+    in[i + 3] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_BAND_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiowsincband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gdouble *) map.data;
+    buffer_length = map.size / sizeof (gdouble);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    fail_unless (rms <= 0.35);
+    gst_buffer_unmap (outbuffer, &map);
+  }
+
+  /* cleanup */
+  cleanup_audiowsincband (audiowsincband);
+}
+
+GST_END_TEST;
+
+
+/* Test if data containing only one frequency component
+ * at rate/2 is preserved with bandreject mode and a 
+ * 2000Hz frequency band around rate/4 */
+GST_START_TEST (test_64_br_22050hz)
+{
+  GstElement *audiowsincband;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsincband = setup_audiowsincband ();
+  /* Set to bandreject */
+  g_object_set (G_OBJECT (audiowsincband), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "length", 31, NULL);
+
+  fail_unless (gst_element_set_state (audiowsincband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsincband), "lower-frequency",
+      44100 / 4.0 - 1000, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "upper-frequency",
+      44100 / 4.0 + 1000, NULL);
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_BAND_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiowsincband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gdouble *) map.data;
+    buffer_length = map.size / sizeof (gdouble);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    fail_unless (rms >= 0.9);
+    gst_buffer_unmap (outbuffer, &map);
+  }
+
+  /* cleanup */
+  cleanup_audiowsincband (audiowsincband);
+}
+
+GST_END_TEST;
+
+/* Test if buffers smaller than the kernel size are handled
+ * correctly without accessing wrong memory areas */
+GST_START_TEST (test_64_small_buffer)
+{
+  GstElement *audiowsincband;
+  GstBuffer *inbuffer;
+  GstCaps *caps;
+  gdouble *in;
+  gint i;
+  GstMapInfo map;
+  GstSegment segment;
+
+  audiowsincband = setup_audiowsincband ();
+  /* Set to bandpass */
+  g_object_set (G_OBJECT (audiowsincband), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "length", 101, NULL);
+
+  fail_unless (gst_element_set_state (audiowsincband,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsincband), "lower-frequency",
+      44100 / 4.0 - 44100 / 16.0, NULL);
+  g_object_set (G_OBJECT (audiowsincband), "upper-frequency",
+      44100 / 4.0 + 44100 / 16.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (20 * sizeof (gdouble));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 20; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_BAND_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiowsincband, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  /* cleanup */
+  cleanup_audiowsincband (audiowsincband);
+}
+
+GST_END_TEST;
+
+static Suite *
+audiowsincband_suite (void)
+{
+  Suite *s = suite_create ("audiowsincband");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_32_bp_0hz);
+  tcase_add_test (tc_chain, test_32_bp_11025hz);
+  tcase_add_test (tc_chain, test_32_bp_22050hz);
+  tcase_add_test (tc_chain, test_32_br_0hz);
+  tcase_add_test (tc_chain, test_32_br_11025hz);
+  tcase_add_test (tc_chain, test_32_br_22050hz);
+  tcase_add_test (tc_chain, test_32_small_buffer);
+  tcase_add_test (tc_chain, test_64_bp_0hz);
+  tcase_add_test (tc_chain, test_64_bp_11025hz);
+  tcase_add_test (tc_chain, test_64_bp_22050hz);
+  tcase_add_test (tc_chain, test_64_br_0hz);
+  tcase_add_test (tc_chain, test_64_br_11025hz);
+  tcase_add_test (tc_chain, test_64_br_22050hz);
+  tcase_add_test (tc_chain, test_64_small_buffer);
+
+  return s;
+}
+
+GST_CHECK_MAIN (audiowsincband);
diff --git a/tests/check/elements/audiowsinclimit.c b/tests/check/elements/audiowsinclimit.c
new file mode 100644
index 0000000..3263cf9
--- /dev/null
+++ b/tests/check/elements/audiowsinclimit.c
@@ -0,0 +1,788 @@
+/* GStreamer
+ *
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * audiowsinclimit.c: Unit test for the audiowsinclimit element
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/check/gstcheck.h>
+
+#include <math.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *mysrcpad, *mysinkpad;
+
+#define AUDIO_WSINC_LIMIT_CAPS_STRING_32           \
+    "audio/x-raw, "                                \
+    "format = (string) " GST_AUDIO_NE (F32) ", "   \
+    "layout = (string) interleaved, "              \
+    "channels = (int) 1, "                         \
+    "rate = (int) 44100"
+
+#define AUDIO_WSINC_LIMIT_CAPS_STRING_64           \
+    "audio/x-raw, "                                \
+    "format = (string) " GST_AUDIO_NE (F64) ", "   \
+    "layout = (string) interleaved, "              \
+    "channels = (int) 1, "                         \
+    "rate = (int) 44100"
+
+#define FORMATS "{ "GST_AUDIO_NE (F32)","GST_AUDIO_NE (F64)" }"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " FORMATS ", "
+        "layout = (string) interleaved, "
+        "channels = (int) 1, " "rate = (int) 44100")
+    );
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " FORMATS ", "
+        "layout = (string) interleaved, "
+        "channels = (int) 1, " "rate = (int) 44100")
+    );
+
+static GstElement *
+setup_audiowsinclimit (void)
+{
+  GstElement *audiowsinclimit;
+
+  GST_DEBUG ("setup_audiowsinclimit");
+  audiowsinclimit = gst_check_setup_element ("audiowsinclimit");
+  mysrcpad = gst_check_setup_src_pad (audiowsinclimit, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (audiowsinclimit, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return audiowsinclimit;
+}
+
+static void
+cleanup_audiowsinclimit (GstElement * audiowsinclimit)
+{
+  GST_DEBUG ("cleanup_audiowsinclimit");
+
+  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (audiowsinclimit);
+  gst_check_teardown_sink_pad (audiowsinclimit);
+  gst_check_teardown_element (audiowsinclimit);
+}
+
+/* Test if data containing only one frequency component
+ * at 0 is preserved with lowpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_32_lp_0hz)
+{
+  GstElement *audiowsinclimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsinclimit = setup_audiowsinclimit ();
+  /* Set to lowpass */
+  g_object_set (G_OBJECT (audiowsinclimit), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiowsinclimit), "length", 21, NULL);
+
+  fail_unless (gst_element_set_state (audiowsinclimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  /* cutoff = sampling rate / 4, data = 0 */
+  g_object_set (G_OBJECT (audiowsinclimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (128 * sizeof (gfloat));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 128; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_LIMIT_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiowsinclimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gfloat *) map.data;
+    buffer_length = map.size / sizeof (gfloat);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    gst_buffer_unmap (outbuffer, &map);
+    fail_unless (rms >= 0.9);
+  }
+
+  /* cleanup */
+  cleanup_audiowsinclimit (audiowsinclimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is erased with lowpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_32_lp_22050hz)
+{
+  GstElement *audiowsinclimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsinclimit = setup_audiowsinclimit ();
+  /* Set to lowpass */
+  g_object_set (G_OBJECT (audiowsinclimit), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiowsinclimit), "length", 21, NULL);
+
+  fail_unless (gst_element_set_state (audiowsinclimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsinclimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (128 * sizeof (gfloat));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 128; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_LIMIT_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiowsinclimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gfloat *) map.data;
+    buffer_length = map.size / sizeof (gfloat);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    gst_buffer_unmap (outbuffer, &map);
+    fail_unless (rms <= 0.1);
+  }
+
+  /* cleanup */
+  cleanup_audiowsinclimit (audiowsinclimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is erased with highpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_32_hp_0hz)
+{
+  GstElement *audiowsinclimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsinclimit = setup_audiowsinclimit ();
+  /* Set to highpass */
+  g_object_set (G_OBJECT (audiowsinclimit), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiowsinclimit), "length", 21, NULL);
+
+  fail_unless (gst_element_set_state (audiowsinclimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsinclimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (128 * sizeof (gfloat));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 128; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_LIMIT_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiowsinclimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gfloat *) map.data;
+    buffer_length = map.size / sizeof (gfloat);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    gst_buffer_unmap (outbuffer, &map);
+    fail_unless (rms <= 0.1);
+  }
+
+  /* cleanup */
+  cleanup_audiowsinclimit (audiowsinclimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is preserved with highpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_32_hp_22050hz)
+{
+  GstElement *audiowsinclimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsinclimit = setup_audiowsinclimit ();
+  /* Set to highpass */
+  g_object_set (G_OBJECT (audiowsinclimit), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiowsinclimit), "length", 21, NULL);
+
+  fail_unless (gst_element_set_state (audiowsinclimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsinclimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (128 * sizeof (gfloat));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 128; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_LIMIT_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiowsinclimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gfloat *) map.data;
+    buffer_length = map.size / sizeof (gfloat);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    gst_buffer_unmap (outbuffer, &map);
+    fail_unless (rms >= 0.9);
+  }
+
+  /* cleanup */
+  cleanup_audiowsinclimit (audiowsinclimit);
+}
+
+GST_END_TEST;
+
+/* Test if buffers smaller than the kernel size are handled
+ * correctly without accessing wrong memory areas */
+GST_START_TEST (test_32_small_buffer)
+{
+  GstElement *audiowsinclimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gfloat *in;
+  gint i;
+  GstMapInfo map;
+  GstSegment segment;
+
+  audiowsinclimit = setup_audiowsinclimit ();
+  /* Set to lowpass */
+  g_object_set (G_OBJECT (audiowsinclimit), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiowsinclimit), "length", 101, NULL);
+
+  fail_unless (gst_element_set_state (audiowsinclimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsinclimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (20 * sizeof (gfloat));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gfloat *) map.data;
+  for (i = 0; i < 20; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_LIMIT_CAPS_STRING_32);
+  gst_check_setup_events (mysrcpad, audiowsinclimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  /* cleanup */
+  cleanup_audiowsinclimit (audiowsinclimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is preserved with lowpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_64_lp_0hz)
+{
+  GstElement *audiowsinclimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsinclimit = setup_audiowsinclimit ();
+  /* Set to lowpass */
+  g_object_set (G_OBJECT (audiowsinclimit), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiowsinclimit), "length", 21, NULL);
+
+  fail_unless (gst_element_set_state (audiowsinclimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  /* cutoff = sampling rate / 4, data = 0 */
+  g_object_set (G_OBJECT (audiowsinclimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (128 * sizeof (gdouble));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 128; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_LIMIT_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiowsinclimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gdouble *) map.data;
+    buffer_length = map.size / sizeof (gdouble);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    gst_buffer_unmap (outbuffer, &map);
+    fail_unless (rms >= 0.9);
+  }
+
+  /* cleanup */
+  cleanup_audiowsinclimit (audiowsinclimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is erased with lowpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_64_lp_22050hz)
+{
+  GstElement *audiowsinclimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsinclimit = setup_audiowsinclimit ();
+  /* Set to lowpass */
+  g_object_set (G_OBJECT (audiowsinclimit), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiowsinclimit), "length", 21, NULL);
+
+  fail_unless (gst_element_set_state (audiowsinclimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsinclimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (128 * sizeof (gdouble));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 128; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_LIMIT_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiowsinclimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gdouble *) map.data;
+    buffer_length = map.size / sizeof (gdouble);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    gst_buffer_unmap (outbuffer, &map);
+    fail_unless (rms <= 0.1);
+  }
+
+  /* cleanup */
+  cleanup_audiowsinclimit (audiowsinclimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at 0 is erased with highpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_64_hp_0hz)
+{
+  GstElement *audiowsinclimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsinclimit = setup_audiowsinclimit ();
+  /* Set to highpass */
+  g_object_set (G_OBJECT (audiowsinclimit), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiowsinclimit), "length", 21, NULL);
+
+  fail_unless (gst_element_set_state (audiowsinclimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsinclimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (128 * sizeof (gdouble));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 128; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_LIMIT_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiowsinclimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gdouble *) map.data;
+    buffer_length = map.size / sizeof (gdouble);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    gst_buffer_unmap (outbuffer, &map);
+    fail_unless (rms <= 0.1);
+  }
+
+  /* cleanup */
+  cleanup_audiowsinclimit (audiowsinclimit);
+}
+
+GST_END_TEST;
+
+/* Test if data containing only one frequency component
+ * at rate/2 is preserved with highpass mode and a cutoff
+ * at rate/4 */
+GST_START_TEST (test_64_hp_22050hz)
+{
+  GstElement *audiowsinclimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms;
+  gint i;
+  GstMapInfo map;
+  GList *node;
+  GstSegment segment;
+
+  audiowsinclimit = setup_audiowsinclimit ();
+  /* Set to highpass */
+  g_object_set (G_OBJECT (audiowsinclimit), "mode", 1, NULL);
+  g_object_set (G_OBJECT (audiowsinclimit), "length", 21, NULL);
+
+  fail_unless (gst_element_set_state (audiowsinclimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsinclimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (128 * sizeof (gdouble));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 128; i += 2) {
+    in[i] = 1.0;
+    in[i + 1] = -1.0;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_LIMIT_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiowsinclimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  for (node = buffers; node; node = node->next) {
+    gint buffer_length;
+
+    fail_if ((outbuffer = (GstBuffer *) node->data) == NULL);
+
+    gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+    res = (gdouble *) map.data;
+    buffer_length = map.size / sizeof (gdouble);
+    rms = 0.0;
+    for (i = 0; i < buffer_length; i++)
+      rms += res[i] * res[i];
+    rms = sqrt (rms / buffer_length);
+    gst_buffer_unmap (outbuffer, &map);
+    fail_unless (rms >= 0.9);
+  }
+
+  /* cleanup */
+  cleanup_audiowsinclimit (audiowsinclimit);
+}
+
+GST_END_TEST;
+
+/* Test if buffers smaller than the kernel size are handled
+ * correctly without accessing wrong memory areas */
+GST_START_TEST (test_64_small_buffer)
+{
+  GstElement *audiowsinclimit;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  gdouble *in;
+  gint i;
+  GstMapInfo map;
+  GstSegment segment;
+
+  audiowsinclimit = setup_audiowsinclimit ();
+  /* Set to lowpass */
+  g_object_set (G_OBJECT (audiowsinclimit), "mode", 0, NULL);
+  g_object_set (G_OBJECT (audiowsinclimit), "length", 101, NULL);
+
+  fail_unless (gst_element_set_state (audiowsinclimit,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (G_OBJECT (audiowsinclimit), "cutoff", 44100 / 4.0, NULL);
+  inbuffer = gst_buffer_new_and_alloc (20 * sizeof (gdouble));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 20; i++)
+    in[i] = 1.0;
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (AUDIO_WSINC_LIMIT_CAPS_STRING_64);
+  gst_check_setup_events (mysrcpad, audiowsinclimit, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) >= 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+
+  /* cleanup */
+  cleanup_audiowsinclimit (audiowsinclimit);
+}
+
+GST_END_TEST;
+
+static Suite *
+audiowsinclimit_suite (void)
+{
+  Suite *s = suite_create ("audiowsinclimit");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_32_lp_0hz);
+  tcase_add_test (tc_chain, test_32_lp_22050hz);
+  tcase_add_test (tc_chain, test_32_hp_0hz);
+  tcase_add_test (tc_chain, test_32_hp_22050hz);
+  tcase_add_test (tc_chain, test_32_small_buffer);
+  tcase_add_test (tc_chain, test_64_lp_0hz);
+  tcase_add_test (tc_chain, test_64_lp_22050hz);
+  tcase_add_test (tc_chain, test_64_hp_0hz);
+  tcase_add_test (tc_chain, test_64_hp_22050hz);
+  tcase_add_test (tc_chain, test_64_small_buffer);
+
+  return s;
+}
+
+GST_CHECK_MAIN (audiowsinclimit);
diff --git a/tests/check/elements/autodetect.c b/tests/check/elements/autodetect.c
new file mode 100644
index 0000000..4e0f1c7
--- /dev/null
+++ b/tests/check/elements/autodetect.c
@@ -0,0 +1,226 @@
+/* GStreamer unit test for the autodetect elements
+ *
+ * Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gst/audio/audio.h>
+#include <gst/base/gstbasesink.h>
+#include <gst/check/gstcheck.h>
+#include <gst/video/video.h>
+
+/* dummy sink elements */
+
+#define GST_TYPE_FAKE_AUDIO_SINK (gst_fake_audio_sink_get_type ())
+typedef GstBaseSink GstFakeAudioSink;
+typedef GstBaseSinkClass GstFakeAudioSinkClass;
+GType gst_fake_audio_sink_get_type (void);
+G_DEFINE_TYPE (GstFakeAudioSink, gst_fake_audio_sink, GST_TYPE_BASE_SINK);
+
+static void
+gst_fake_audio_sink_class_init (GstFakeAudioSinkClass * klass)
+{
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  static GstStaticPadTemplate pad_template = GST_STATIC_PAD_TEMPLATE ("sink",
+      GST_PAD_SINK, GST_PAD_ALWAYS,
+      GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL) "; "));
+
+  gst_element_class_set_static_metadata (gstelement_class, "Fake Audio Sink",
+      "Sink/Audio", "Audio sink fake for testing", "Stefan Sauer");
+  gst_element_class_add_static_pad_template (gstelement_class, &pad_template);
+}
+
+static void
+gst_fake_audio_sink_init (GstFakeAudioSink * sink)
+{
+}
+
+#define GST_TYPE_FAKE_VIDEO_SINK (gst_fake_video_sink_get_type ())
+typedef GstBaseSink GstFakeVideoSink;
+typedef GstBaseSinkClass GstFakeVideoSinkClass;
+GType gst_fake_video_sink_get_type (void);
+G_DEFINE_TYPE (GstFakeVideoSink, gst_fake_video_sink, GST_TYPE_BASE_SINK);
+
+static void
+gst_fake_video_sink_class_init (GstFakeVideoSinkClass * klass)
+{
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  static GstStaticPadTemplate pad_template = GST_STATIC_PAD_TEMPLATE ("sink",
+      GST_PAD_SINK, GST_PAD_ALWAYS,
+      GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) "; "));
+
+  gst_element_class_set_static_metadata (gstelement_class, "Fake Video Sink",
+      "Sink/Video", "Video sink fake for testing", "Stefan Sauer");
+  gst_element_class_add_static_pad_template (gstelement_class, &pad_template);
+}
+
+static void
+gst_fake_video_sink_init (GstFakeVideoSink * sink)
+{
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "fakeaudiosink", G_MAXINT,
+          GST_TYPE_FAKE_AUDIO_SINK))
+    return FALSE;
+  if (!gst_element_register (plugin, "fakevideosink", G_MAXINT,
+          GST_TYPE_FAKE_VIDEO_SINK))
+    return FALSE;
+  return TRUE;
+}
+
+/* tests */
+
+static void
+test_plugs_best (GstElement * sink, GType expected)
+{
+  GstStateChangeReturn state_ret;
+  GList *child;
+
+  state_ret = gst_element_set_state (sink, GST_STATE_READY);
+  fail_unless (state_ret == GST_STATE_CHANGE_SUCCESS, NULL);
+
+  child = GST_BIN_CHILDREN (sink);
+  fail_unless (child != NULL, "no elements plugged");
+  ck_assert_int_eq (g_list_length (child), 1);
+  fail_unless (G_OBJECT_TYPE (child), expected);
+
+  /* clean up */
+  gst_element_set_state (sink, GST_STATE_NULL);
+  gst_object_unref (sink);
+}
+
+GST_START_TEST (test_autovideosink_plugs_best)
+{
+  GstElement *sink = gst_element_factory_make ("autovideosink", NULL);
+
+  test_plugs_best (sink, GST_TYPE_FAKE_VIDEO_SINK);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_autoaudiosink_plugs_best)
+{
+  GstElement *sink = gst_element_factory_make ("autoaudiosink", NULL);
+
+  test_plugs_best (sink, GST_TYPE_FAKE_AUDIO_SINK);
+}
+
+GST_END_TEST;
+
+static void
+test_ghostpad_error_case (GstCaps * caps, GstElement * sink,
+    const gchar * fake_sink_name)
+{
+  GstStateChangeReturn state_ret;
+  GstElement *pipeline, *src, *filter, *fakesink;
+
+  pipeline = gst_pipeline_new ("pipeline");
+  src = gst_element_factory_make ("fakesrc", NULL);
+  filter = gst_element_factory_make ("capsfilter", NULL);
+
+  g_object_set (filter, "caps", caps, NULL);
+  gst_caps_unref (caps);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, filter, sink, NULL);
+
+  fail_unless (gst_element_link (src, filter), "Failed to link src to filter");
+  fail_unless (gst_element_link (filter, sink),
+      "Failed to link filter to sink");
+
+  /* this should fail, there's no such format */
+  state_ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
+  if (state_ret == GST_STATE_CHANGE_ASYNC) {
+    /* make sure we wait for the actual success/failure to happen */
+    GstState state;
+    state_ret =
+        gst_element_get_state (pipeline, &state, &state, GST_CLOCK_TIME_NONE);
+  }
+  fakesink = gst_bin_get_by_name (GST_BIN (sink), fake_sink_name);
+  if (fakesink != NULL) {
+    /* no real sink available */
+    fail_unless (state_ret == GST_STATE_CHANGE_SUCCESS,
+        "pipeline _set_state() to PAUSED failed");
+    gst_object_unref (fakesink);
+  } else {
+    /* autovideosink contains a real video sink */
+    fail_unless (state_ret == GST_STATE_CHANGE_FAILURE,
+        "pipeline _set_state() to PAUSED succeeded but should have failed");
+
+    /* so, we hit an error and try to shut down the pipeline; this shouldn't
+     * deadlock or block anywhere when autovideosink resets the ghostpad
+     * targets etc. */
+  }
+  state_ret = gst_element_set_state (pipeline, GST_STATE_NULL);
+  fail_unless (state_ret == GST_STATE_CHANGE_SUCCESS,
+      "State change on pipeline failed");
+
+  /* clean up */
+  gst_object_unref (pipeline);
+}
+
+GST_START_TEST (test_autovideosink_ghostpad_error_case)
+{
+  GstElement *sink = gst_element_factory_make ("autovideosink", NULL);
+  GstCaps *caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING,
+      "ABCD", NULL);
+
+  test_ghostpad_error_case (caps, sink, "fake-video-sink");
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_autoaudiosink_ghostpad_error_case)
+{
+  GstElement *sink = gst_element_factory_make ("autoaudiosink", NULL);
+  GstCaps *caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING,
+      "ABCD", NULL);
+
+  test_ghostpad_error_case (caps, sink, "fake-audio-sink");
+}
+
+GST_END_TEST;
+
+static Suite *
+autodetect_suite (void)
+{
+  Suite *s = suite_create ("autodetect");
+  TCase *tc_chain = tcase_create ("general");
+
+  gst_plugin_register_static (GST_VERSION_MAJOR,
+      GST_VERSION_MINOR,
+      "autodetect-test",
+      "autodetect test elements",
+      plugin_init,
+      VERSION, "LGPL", PACKAGE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_autovideosink_plugs_best);
+  tcase_add_test (tc_chain, test_autoaudiosink_plugs_best);
+  tcase_add_test (tc_chain, test_autovideosink_ghostpad_error_case);
+  tcase_add_test (tc_chain, test_autoaudiosink_ghostpad_error_case);
+
+  return s;
+}
+
+GST_CHECK_MAIN (autodetect);
diff --git a/tests/check/elements/avimux.c b/tests/check/elements/avimux.c
new file mode 100644
index 0000000..1bd27fb
--- /dev/null
+++ b/tests/check/elements/avimux.c
@@ -0,0 +1,269 @@
+/* GStreamer
+ *
+ * unit test for avimux
+ *
+ * Copyright (C) <2006> Mark Nauwelaerts <manauw@skynet.be>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+static GstPad *mysrcpad, *mysinkpad;
+
+#define AUDIO_CAPS_STRING "audio/x-ac3, " \
+                        "channels = (int) 1, " \
+                        "rate = (int) 8000"
+#define VIDEO_CAPS_STRING "video/mpeg, mpegversion = (int) 4, " \
+                           "systemstream = (bool) false, " \
+                           "width = (int) 384, " \
+                           "height = (int) 288, " \
+                           "framerate = (fraction) 25/1"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-msvideo"));
+static GstStaticPadTemplate srcvideotemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (VIDEO_CAPS_STRING));
+
+static GstStaticPadTemplate srcaudiotemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (AUDIO_CAPS_STRING));
+
+
+/* setup and teardown needs some special handling for muxer */
+static GstPad *
+setup_src_pad (GstElement * element,
+    GstStaticPadTemplate * template, GstCaps * caps, const gchar * sinkname)
+{
+  GstPad *srcpad, *sinkpad;
+
+  GST_DEBUG_OBJECT (element, "setting up sending pad");
+  /* sending pad */
+  srcpad = gst_pad_new_from_static_template (template, "src");
+  fail_if (srcpad == NULL, "Could not create a srcpad");
+  ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1);
+
+  if (!(sinkpad = gst_element_get_static_pad (element, sinkname)))
+    sinkpad = gst_element_get_request_pad (element, sinkname);
+  fail_if (sinkpad == NULL, "Could not get sink pad from %s",
+      GST_ELEMENT_NAME (element));
+  /* references are owned by: 1) us, 2) avimux, 3) collect pads */
+  ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3);
+  if (caps)
+    fail_unless (gst_pad_set_caps (srcpad, caps));
+  fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK,
+      "Could not link source and %s sink pads", GST_ELEMENT_NAME (element));
+  gst_object_unref (sinkpad);   /* because we got it higher up */
+
+  /* references are owned by: 1) avimux, 2) collect pads */
+  ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
+
+  return srcpad;
+}
+
+static void
+teardown_src_pad (GstElement * element, const gchar * sinkname)
+{
+  GstPad *srcpad, *sinkpad;
+  gchar *padname;
+
+  /* clean up floating src pad */
+  padname = g_strdup (sinkname);
+  memcpy (strchr (padname, '%'), "0", 2);
+  if (!(sinkpad = gst_element_get_static_pad (element, padname)))
+    sinkpad = gst_element_get_request_pad (element, padname);
+  g_free (padname);
+  /* pad refs held by 1) avimux 2) collectpads and 3) us (through _get) */
+  ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3);
+  srcpad = gst_pad_get_peer (sinkpad);
+
+  gst_pad_unlink (srcpad, sinkpad);
+
+  /* after unlinking, pad refs still held by
+   * 1) avimux and 2) collectpads and 3) us (through _get) */
+  ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3);
+  gst_object_unref (sinkpad);
+  /* one more ref is held by element itself */
+
+  /* pad refs held by both creator and this function (through _get_peer) */
+  ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2);
+  gst_object_unref (srcpad);
+  gst_object_unref (srcpad);
+
+}
+
+static GstElement *
+setup_avimux (GstStaticPadTemplate * srctemplate, const gchar * sinkname)
+{
+  GstElement *avimux;
+
+  GST_DEBUG ("setup_avimux");
+  avimux = gst_check_setup_element ("avimux");
+  mysrcpad = setup_src_pad (avimux, srctemplate, NULL, sinkname);
+  mysinkpad = gst_check_setup_sink_pad (avimux, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return avimux;
+}
+
+static void
+cleanup_avimux (GstElement * avimux, const gchar * sinkname)
+{
+  GST_DEBUG ("cleanup_avimux");
+  gst_element_set_state (avimux, GST_STATE_NULL);
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  teardown_src_pad (avimux, sinkname);
+  gst_check_teardown_sink_pad (avimux);
+  gst_check_teardown_element (avimux);
+}
+
+static void
+check_avimux_pad (GstStaticPadTemplate * srctemplate,
+    const gchar * src_caps_string, const gchar * chunk_id,
+    const gchar * sinkname)
+{
+  GstElement *avimux;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  int num_buffers;
+  int i;
+  guint8 data0[4] = "RIFF";
+  guint8 data1[8] = "AVI LIST";
+  guint8 data2[8] = "hdrlavih";
+  guint8 data3[4] = "LIST";
+  guint8 data4[8] = "strlstrh";
+  guint8 data5[4] = "strf";
+  guint8 data6[4] = "LIST";
+  guint8 data7[4] = "movi";
+
+  avimux = setup_avimux (srctemplate, sinkname);
+  fail_unless (gst_element_set_state (avimux,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (1);
+  caps = gst_caps_from_string (src_caps_string);
+  gst_check_setup_events (mysrcpad, avimux, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  num_buffers = g_list_length (buffers);
+  /* at least expect avi header, chunk header, chunk and padding */
+  fail_unless (num_buffers >= 4);
+
+  for (i = 0; i < num_buffers; ++i) {
+    outbuffer = GST_BUFFER (buffers->data);
+    fail_if (outbuffer == NULL);
+    buffers = g_list_remove (buffers, outbuffer);
+
+    switch (i) {
+      case 0:{                 /* check riff header */
+        /* avi header */
+        GstMapInfo map;
+        gsize size;
+        guint8 *data;
+
+        gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+        data = map.data;
+        size = map.size;
+
+        fail_unless (memcmp (data, data0, sizeof (data0)) == 0);
+        fail_unless (memcmp (data + 8, data1, sizeof (data1)) == 0);
+        fail_unless (memcmp (data + 20, data2, sizeof (data2)) == 0);
+        /* video or audio header */
+        data += 32 + 56;
+        fail_unless (memcmp (data, data3, sizeof (data3)) == 0);
+        fail_unless (memcmp (data + 8, data4, sizeof (data4)) == 0);
+        fail_unless (memcmp (data + 76, data5, sizeof (data5)) == 0);
+        /* avi data header */
+        data = map.data;
+        data += size - 12;
+        fail_unless (memcmp (data, data6, sizeof (data6)) == 0);
+        data += 8;
+        fail_unless (memcmp (data, data7, sizeof (data7)) == 0);
+        gst_buffer_unmap (outbuffer, &map);
+        break;
+      }
+      case 1:                  /* chunk header */
+        fail_unless (gst_buffer_get_size (outbuffer) == 8);
+        fail_unless (gst_buffer_memcmp (outbuffer, 0, chunk_id, 4) == 0);
+        break;
+      case 2:
+        fail_unless (gst_buffer_get_size (outbuffer) == 1);
+        break;
+      case 3:                  /* buffer we put in, must be padded to even size */
+        fail_unless (gst_buffer_get_size (outbuffer) == 1);
+        break;
+      default:
+        break;
+    }
+
+    ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
+    gst_buffer_unref (outbuffer);
+    outbuffer = NULL;
+  }
+
+  cleanup_avimux (avimux, sinkname);
+  g_list_free (buffers);
+  buffers = NULL;
+}
+
+
+GST_START_TEST (test_video_pad)
+{
+  check_avimux_pad (&srcvideotemplate, VIDEO_CAPS_STRING, "00db", "video_%u");
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_audio_pad)
+{
+  check_avimux_pad (&srcaudiotemplate, AUDIO_CAPS_STRING, "00wb", "audio_%u");
+}
+
+GST_END_TEST;
+
+
+static Suite *
+avimux_suite (void)
+{
+  Suite *s = suite_create ("avimux");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_video_pad);
+  tcase_add_test (tc_chain, test_audio_pad);
+
+  return s;
+}
+
+GST_CHECK_MAIN (avimux);
diff --git a/tests/check/elements/avisubtitle.c b/tests/check/elements/avisubtitle.c
new file mode 100644
index 0000000..1b00b15
--- /dev/null
+++ b/tests/check/elements/avisubtitle.c
@@ -0,0 +1,263 @@
+/* GStreamer
+ *
+ * unit test for avisubtitle
+ *
+ * Copyright (C) <2007> Thijs Vermeir <thijsvermeir@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/* Element-Checklist-Version: 5 */
+
+#include <unistd.h>
+
+#include <gst/gst.h>
+#include <gst/check/gstcheck.h>
+
+GstPad *mysinkpad;
+GstPad *mysrcpad;
+
+guint8 avisub_utf_8_with_bom[] = {
+  0x47, 0x41, 0x42, 0x32, 0x00, 0x02, 0x00, 0x10,
+  0x00, 0x00, 0x00, 0x45, 0x00, 0x6e, 0x00, 0x67,
+  0x00, 0x6c, 0x00, 0x69, 0x00, 0x73, 0x00, 0x68,
+  0x00, 0x00, 0x00, 0x04, 0x00, 0x8e, 0x00, 0x00,
+  0x00, 0xef, 0xbb, 0xbf, 0x31, 0x0d, 0x0a, 0x30,
+  0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x2c,
+  0x31, 0x30, 0x30, 0x20, 0x2d, 0x2d, 0x3e, 0x20,
+  0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x32,
+  0x2c, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x3c, 0x62,
+  0x3e, 0x41, 0x6e, 0x20, 0x55, 0x54, 0x46, 0x38,
+  0x20, 0x53, 0x75, 0x62, 0x74, 0x69, 0x74, 0x6c,
+  0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x42,
+  0x4f, 0x4d, 0x3c, 0x2f, 0x62, 0x3e, 0x0d, 0x0a,
+  0x0d, 0x0a, 0x32, 0x0d, 0x0a, 0x30, 0x30, 0x3a,
+  0x30, 0x30, 0x3a, 0x30, 0x32, 0x2c, 0x31, 0x30,
+  0x30, 0x20, 0x2d, 0x2d, 0x3e, 0x20, 0x30, 0x30,
+  0x3a, 0x30, 0x30, 0x3a, 0x30, 0x34, 0x2c, 0x30,
+  0x30, 0x30, 0x0d, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
+  0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x6f,
+  0x6e, 0x41, 0x53, 0x43, 0x49, 0x49, 0x20, 0x2d,
+  0x20, 0xc2, 0xb5, 0xc3, 0xb6, 0xc3, 0xa4, 0xc3,
+  0xbc, 0xc3, 0x9f, 0x0d, 0x0a, 0x0d, 0x0a
+};
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-subtitle")
+    );
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-subtitle-avi")
+    );
+
+static GstElement *
+setup_avisubtitle (void)
+{
+  GstElement *avisubtitle;
+  GstCaps *srccaps;
+
+  GST_DEBUG ("setup_avisubtitle");
+  avisubtitle = gst_check_setup_element ("avisubtitle");
+  mysinkpad = gst_check_setup_sink_pad (avisubtitle, &sink_template);
+  mysrcpad = gst_check_setup_src_pad (avisubtitle, &src_template);
+  gst_pad_set_active (mysinkpad, TRUE);
+  gst_pad_set_active (mysrcpad, TRUE);
+  srccaps = gst_caps_new_empty_simple ("application/x-subtitle-avi");
+  gst_check_setup_events (mysrcpad, avisubtitle, srccaps, GST_FORMAT_TIME);
+  gst_caps_unref (srccaps);
+  return avisubtitle;
+}
+
+static void
+cleanup_avisubtitle (GstElement * avisubtitle)
+{
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_check_teardown_sink_pad (avisubtitle);
+  gst_check_teardown_src_pad (avisubtitle);
+  gst_check_teardown_element (avisubtitle);
+}
+
+static void
+check_wrong_buffer (guint8 * data, guint length)
+{
+  GstBuffer *buffer = gst_buffer_new_allocate (NULL, length, 0);
+  GstElement *avisubtitle = setup_avisubtitle ();
+
+  gst_buffer_fill (buffer, 0, data, length);
+  fail_unless (gst_element_set_state (avisubtitle,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+  gst_buffer_ref (buffer);
+  ASSERT_BUFFER_REFCOUNT (buffer, "inbuffer", 2);
+  /* push the broken buffer */
+  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_ERROR,
+      "accepted a broken buffer");
+  /* check if we have unreffed this buffer on failure */
+  ASSERT_BUFFER_REFCOUNT (buffer, "inbuffer", 1);
+  gst_buffer_unref (buffer);
+  fail_unless (gst_element_set_state (avisubtitle,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+  cleanup_avisubtitle (avisubtitle);
+}
+
+static void
+check_correct_buffer (guint8 * src_data, guint src_size, guint8 * dst_data,
+    guint dst_size)
+{
+  GstBuffer *buffer = gst_buffer_new_allocate (NULL, src_size, 0);
+  GstBuffer *newBuffer;
+  GstElement *avisubtitle = setup_avisubtitle ();
+  GstEvent *event;
+
+  fail_unless (g_list_length (buffers) == 0, "Buffers list needs to be empty");
+  gst_buffer_fill (buffer, 0, src_data, src_size);
+  fail_unless (gst_element_set_state (avisubtitle,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+  ASSERT_BUFFER_REFCOUNT (buffer, "inbuffer", 1);
+  event = gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
+      GST_SEEK_TYPE_SET, 2 * GST_SECOND, GST_SEEK_TYPE_SET, 5 * GST_SECOND);
+  fail_unless (gst_element_send_event (avisubtitle, event) == FALSE,
+      "Seeking is not possible when there is no buffer yet");
+  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK,
+      "not accepted a correct buffer");
+  /* we gave away our reference to the buffer, don't assume anything */
+  buffer = NULL;
+  /* a new buffer is created in the list */
+  fail_unless (g_list_length (buffers) == 1,
+      "No new buffer in the buffers list");
+  event = gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
+      GST_SEEK_TYPE_SET, 2 * GST_SECOND, GST_SEEK_TYPE_SET, 5 * GST_SECOND);
+  fail_unless (gst_element_send_event (avisubtitle, event) == TRUE,
+      "seeking should be working now");
+  fail_unless (g_list_length (buffers) == 2,
+      "After seeking we need another buffer in the buffers");
+  newBuffer = GST_BUFFER (buffers->data);
+  buffers = g_list_remove (buffers, newBuffer);
+  fail_unless (g_list_length (buffers) == 1, "Buffers list needs to be empty");
+  fail_unless (gst_buffer_get_size (newBuffer) == dst_size,
+      "size of the new buffer is wrong ( %d != %d)",
+      gst_buffer_get_size (newBuffer), dst_size);
+  fail_unless (gst_buffer_memcmp (newBuffer, 0, dst_data, dst_size) == 0,
+      "data of the buffer is not correct");
+  gst_buffer_unref (newBuffer);
+  /* free the buffer from seeking */
+  gst_buffer_unref (GST_BUFFER (buffers->data));
+  buffers = g_list_remove (buffers, buffers->data);
+  fail_unless (gst_element_set_state (avisubtitle,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+  cleanup_avisubtitle (avisubtitle);
+}
+
+
+GST_START_TEST (test_avisubtitle_negative)
+{
+  guint8 wrong_magic[] =
+      { 0x47, 0x41, 0x41, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00
+  };
+  guint8 wrong_fixed_word_2[] = {
+    0x47, 0x41, 0x42, 0x32, 0x00, 0x02, 0x01, 0x10,
+    0x00, 0x00, 0x00, 0x45, 0x00, 0x6e, 0x00, 0x67,
+    0x00, 0x6c, 0x00, 0x69, 0x00, 0x73, 0x00, 0x68
+  };
+  guint8 wrong_length_after_name[] = {
+    0x47, 0x41, 0x42, 0x32, 0x00, 0x02, 0x00, 0x10,
+    0x00, 0x00, 0x00, 0x45, 0x00, 0x6e, 0x00, 0x67,
+    0x00, 0x6c, 0x00, 0x69, 0x00, 0x73, 0x00, 0x68
+  };
+  guint8 wrong_fixed_word_4[] = {
+    0x47, 0x41, 0x42, 0x32, 0x00, 0x02, 0x00, 0x10,
+    0x00, 0x00, 0x00, 0x45, 0x00, 0x6e, 0x00, 0x67,
+    0x00, 0x6c, 0x00, 0x69, 0x00, 0x73, 0x00, 0x68,
+    0x00, 0x00, 0x00, 0x04, 0x01, 0x8e, 0x00, 0x00,
+    0x00, 0xef, 0xbb, 0xbf, 0x31, 0x0d, 0x0a, 0x30
+  };
+  guint8 wrong_total_length[] = {
+    0x47, 0x41, 0x42, 0x32, 0x00, 0x02, 0x00, 0x10,
+    0x00, 0x00, 0x00, 0x45, 0x00, 0x6e, 0x00, 0x67,
+    0x00, 0x6c, 0x00, 0x69, 0x00, 0x73, 0x00, 0x68,
+    0x00, 0x00, 0x00, 0x04, 0x00, 0x8e, 0x00, 0x00,
+    0x00, 0xef, 0xbb, 0xbf, 0x31, 0x0d, 0x0a, 0x30
+  };
+  /* size of the buffer must be larger than 11 */
+  check_wrong_buffer (avisub_utf_8_with_bom, 11);
+  /* buffer must start with 'GAB2\0' */
+  check_wrong_buffer (wrong_magic, 14);
+  /* next word must be 2 */
+  check_wrong_buffer (wrong_fixed_word_2, 24);
+  /* length must be larger than the length of the name + 17 */
+  check_wrong_buffer (wrong_length_after_name, 24);
+  /* next word must be 4 */
+  check_wrong_buffer (wrong_fixed_word_4, 36);
+  /* check wrong total length */
+  check_wrong_buffer (wrong_total_length, 36);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_avisubtitle_positive)
+{
+  guint8 avisub_utf_8_without_bom[] = {
+    0x47, 0x41, 0x42, 0x32, 0x00, 0x02, 0x00, 0x10,
+    0x00, 0x00, 0x00, 0x45, 0x00, 0x6e, 0x00, 0x67,
+    0x00, 0x6c, 0x00, 0x69, 0x00, 0x73, 0x00, 0x68,
+    0x00, 0x00, 0x00, 0x04, 0x00, 0x8b, 0x00, 0x00,
+    0x00, 0x31, 0x0d, 0x0a, 0x30,
+    0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x2c,
+    0x31, 0x30, 0x30, 0x20, 0x2d, 0x2d, 0x3e, 0x20,
+    0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x32,
+    0x2c, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x3c, 0x62,
+    0x3e, 0x41, 0x6e, 0x20, 0x55, 0x54, 0x46, 0x38,
+    0x20, 0x53, 0x75, 0x62, 0x74, 0x69, 0x74, 0x6c,
+    0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x42,
+    0x4f, 0x4d, 0x3c, 0x2f, 0x62, 0x3e, 0x0d, 0x0a,
+    0x0d, 0x0a, 0x32, 0x0d, 0x0a, 0x30, 0x30, 0x3a,
+    0x30, 0x30, 0x3a, 0x30, 0x32, 0x2c, 0x31, 0x30,
+    0x30, 0x20, 0x2d, 0x2d, 0x3e, 0x20, 0x30, 0x30,
+    0x3a, 0x30, 0x30, 0x3a, 0x30, 0x34, 0x2c, 0x30,
+    0x30, 0x30, 0x0d, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
+    0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x6f,
+    0x6e, 0x41, 0x53, 0x43, 0x49, 0x49, 0x20, 0x2d,
+    0x20, 0xc2, 0xb5, 0xc3, 0xb6, 0xc3, 0xa4, 0xc3,
+    0xbc, 0xc3, 0x9f, 0x0d, 0x0a, 0x0d, 0x0a
+  };
+  check_correct_buffer (avisub_utf_8_with_bom, 175, avisub_utf_8_with_bom + 36,
+      139);
+  check_correct_buffer (avisub_utf_8_without_bom, 172,
+      avisub_utf_8_without_bom + 33, 139);
+}
+
+GST_END_TEST;
+
+static Suite *
+avisubtitle_suite (void)
+{
+  Suite *s = suite_create ("avisubtitle");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_avisubtitle_negative);
+  tcase_add_test (tc_chain, test_avisubtitle_positive);
+
+  return s;
+}
+
+GST_CHECK_MAIN (avisubtitle);
diff --git a/tests/check/elements/capssetter.c b/tests/check/elements/capssetter.c
new file mode 100644
index 0000000..afaad41
--- /dev/null
+++ b/tests/check/elements/capssetter.c
@@ -0,0 +1,232 @@
+/* GStreamer
+ *
+ * unit test for capssetter
+ *
+ * Copyright (C) <2009> Mark Nauwelaerts <mnauw@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+static GstPad *mysrcpad, *mysinkpad;
+
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static GstElement *
+setup_capssetter (void)
+{
+  GstElement *capssetter;
+
+  GST_DEBUG ("setup_capssetter");
+
+  capssetter = gst_check_setup_element ("capssetter");
+  mysrcpad = gst_check_setup_src_pad (capssetter, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (capssetter, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return capssetter;
+}
+
+static void
+cleanup_capssetter (GstElement * capssetter)
+{
+  GST_DEBUG ("cleanup_capssetter");
+
+  gst_check_drop_buffers ();
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (capssetter);
+  gst_check_teardown_sink_pad (capssetter);
+  gst_check_teardown_element (capssetter);
+}
+
+static void
+push_and_test (GstCaps * prop_caps, gboolean join, gboolean replace,
+    GstCaps * in_caps, GstCaps * out_caps)
+{
+  GstElement *capssetter;
+  GstBuffer *buffer;
+  GstCaps *current_out;
+
+  capssetter = setup_capssetter ();
+  fail_unless (gst_element_set_state (capssetter,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  g_object_set (capssetter, "join", join, NULL);
+  g_object_set (capssetter, "replace", replace, NULL);
+  g_object_set (capssetter, "caps", prop_caps, NULL);
+  gst_caps_unref (prop_caps);
+
+  buffer = gst_buffer_new_and_alloc (4);
+  ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1);
+  gst_buffer_fill (buffer, 0, "data", 4);
+
+  gst_check_setup_events (mysrcpad, capssetter, in_caps, GST_FORMAT_TIME);
+  gst_caps_unref (in_caps);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK,
+      "Failed pushing buffer to capssetter");
+
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE);
+
+  /* ... but it should end up being collected on the global buffer list */
+  fail_unless (g_list_length (buffers) == 1);
+  buffer = g_list_first (buffers)->data;
+  ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1);
+
+  current_out = gst_pad_get_current_caps (mysinkpad);
+  fail_unless (gst_caps_is_equal (out_caps, current_out));
+  gst_caps_unref (current_out);
+  gst_caps_unref (out_caps);
+
+  /* cleanup */
+  cleanup_capssetter (capssetter);
+}
+
+#define SRC_WIDTH   8
+#define SRC_HEIGHT 12
+
+static GstCaps *
+make_src_caps (void)
+{
+  return gst_caps_new_simple ("video/x-foo", "width", G_TYPE_INT, SRC_WIDTH,
+      "height", G_TYPE_INT, SRC_HEIGHT, NULL);
+}
+
+/* don't try these caps mutations at home, folks */
+
+GST_START_TEST (test_n_join_n_replace)
+{
+  GstCaps *in_caps, *prop_caps, *out_caps;
+
+  in_caps = make_src_caps ();
+  prop_caps = gst_caps_new_simple ("video/x-bar",
+      "width", G_TYPE_INT, 2 * SRC_WIDTH, NULL);
+  out_caps = gst_caps_new_simple ("video/x-bar",
+      "width", G_TYPE_INT, 2 * SRC_WIDTH,
+      "height", G_TYPE_INT, SRC_HEIGHT, NULL);
+  push_and_test (prop_caps, FALSE, FALSE, in_caps, out_caps);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_n_join_replace)
+{
+  GstCaps *in_caps, *prop_caps, *out_caps;
+
+  in_caps = make_src_caps ();
+  prop_caps = gst_caps_new_simple ("video/x-bar",
+      "width", G_TYPE_INT, 2 * SRC_WIDTH, NULL);
+  out_caps = gst_caps_copy (prop_caps);
+  push_and_test (prop_caps, FALSE, TRUE, in_caps, out_caps);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_join_n_replace_n_match)
+{
+  GstCaps *in_caps, *prop_caps, *out_caps;
+
+  /* non joining caps */
+  in_caps = make_src_caps ();
+  prop_caps = gst_caps_new_simple ("video/x-bar",
+      "width", G_TYPE_INT, 2 * SRC_WIDTH, NULL);
+  out_caps = gst_caps_copy (in_caps);
+  push_and_test (prop_caps, TRUE, FALSE, in_caps, out_caps);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_join_n_replace_match)
+{
+  GstCaps *in_caps, *prop_caps, *out_caps;
+
+  /* joining caps */
+  in_caps = make_src_caps ();
+  prop_caps = gst_caps_new_simple ("video/x-foo",
+      "width", G_TYPE_INT, 2 * SRC_WIDTH, NULL);
+  out_caps = gst_caps_new_simple ("video/x-foo",
+      "width", G_TYPE_INT, 2 * SRC_WIDTH,
+      "height", G_TYPE_INT, SRC_HEIGHT, NULL);
+  push_and_test (prop_caps, TRUE, FALSE, in_caps, out_caps);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_join_replace_n_match)
+{
+  GstCaps *in_caps, *prop_caps, *out_caps;
+
+  /* non joining caps */
+  in_caps = make_src_caps ();
+  prop_caps = gst_caps_new_simple ("video/x-bar",
+      "width", G_TYPE_INT, 2 * SRC_WIDTH, NULL);
+  out_caps = gst_caps_copy (in_caps);
+  push_and_test (prop_caps, TRUE, TRUE, in_caps, out_caps);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_join_replace_match)
+{
+  GstCaps *in_caps, *prop_caps, *out_caps;
+
+  /* joining caps */
+  in_caps = make_src_caps ();
+  prop_caps = gst_caps_new_simple ("video/x-foo",
+      "width", G_TYPE_INT, 2 * SRC_WIDTH, NULL);
+  out_caps = gst_caps_copy (prop_caps);
+  push_and_test (prop_caps, TRUE, TRUE, in_caps, out_caps);
+}
+
+GST_END_TEST;
+
+static Suite *
+capssetter_suite (void)
+{
+  Suite *s = suite_create ("capssetter");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_n_join_n_replace);
+  tcase_add_test (tc_chain, test_n_join_replace);
+  tcase_add_test (tc_chain, test_join_n_replace_n_match);
+  tcase_add_test (tc_chain, test_join_n_replace_match);
+  tcase_add_test (tc_chain, test_join_replace_n_match);
+  tcase_add_test (tc_chain, test_join_replace_match);
+
+  return s;
+}
+
+GST_CHECK_MAIN (capssetter);
diff --git a/tests/check/elements/deinterlace.c b/tests/check/elements/deinterlace.c
new file mode 100644
index 0000000..b2db1a5
--- /dev/null
+++ b/tests/check/elements/deinterlace.c
@@ -0,0 +1,1052 @@
+/* GStreamer unit tests for the deinterlace element
+ * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <gst/check/gstcheck.h>
+#include <gst/video/video.h>
+
+static gboolean
+gst_caps_is_interlaced (GstCaps * caps)
+{
+  GstVideoInfo info;
+
+  fail_unless (gst_caps_is_fixed (caps));
+  fail_unless (gst_video_info_from_caps (&info, caps));
+
+  return GST_VIDEO_INFO_IS_INTERLACED (&info);
+}
+
+GST_START_TEST (test_create_and_unref)
+{
+  GstElement *deinterlace;
+
+  deinterlace = gst_element_factory_make ("deinterlace", NULL);
+  fail_unless (deinterlace != NULL);
+
+  gst_element_set_state (deinterlace, GST_STATE_NULL);
+  gst_object_unref (deinterlace);
+}
+
+GST_END_TEST;
+
+#define CAPS_VIDEO_COMMON \
+    "width=(int)800, height=(int)600, framerate=(fraction)15/1"
+
+#define CAPS_IMAGE_COMMON \
+    "width=(int)3200, height=(int)3400, framerate=(fraction)0/1"
+
+#define CAPS_YUY2 \
+    "video/x-raw, " \
+    CAPS_VIDEO_COMMON ", " \
+    "format=(string)YUY2"
+
+#define CAPS_YUY2_INTERLACED \
+    CAPS_YUY2 ", " \
+    "interlace-mode=interleaved"
+
+#define CAPS_YVYU \
+    "video/x-raw, " \
+    CAPS_VIDEO_COMMON ", " \
+    "format=(string)YVYU"
+
+#define CAPS_YVYU_INTERLACED \
+    CAPS_YVYU ", " \
+    "interlace-mode=interleaved"
+
+#define CAPS_YUY2_IMAGE \
+    "video/x-raw, " \
+    CAPS_IMAGE_COMMON ", " \
+    "format=(string)YUY2"
+
+#define CAPS_YUY2_INTERLACED_IMAGE \
+    CAPS_YUY2_IMAGE ", " \
+    "interlace-mode=interleaved"
+
+#define CAPS_YVYU_IMAGE \
+    "video/x-raw, " \
+    CAPS_IMAGE_COMMON ", " \
+    "format=(string)YVYU"
+
+#define CAPS_YVYU_INTERLACED_IMAGE \
+    CAPS_YVYU_IMAGE ", " \
+    "interlace-mode=interleaved"
+
+static GstElement *deinterlace;
+static GstPad *srcpad;
+static GstPad *sinkpad;
+
+static GstElement *pipeline;
+
+/* sets up deinterlace and shortcut pointers to its pads */
+static void
+setup_deinterlace (void)
+{
+  deinterlace = gst_element_factory_make ("deinterlace", NULL);
+  fail_unless (deinterlace != NULL);
+
+  sinkpad = gst_element_get_static_pad (deinterlace, "sink");
+  fail_unless (sinkpad != NULL);
+  srcpad = gst_element_get_static_pad (deinterlace, "src");
+  fail_unless (srcpad != NULL);
+}
+
+/* sets up a basic test pipeline containing:
+ *
+ * videotestsrc ! capsfilter ! deinterlace ! fakesink
+ *
+ * The parameters set the capsfilter caps and the num-buffers
+ * property of videotestsrc
+ *
+ * It is useful for adding buffer probes to deinterlace pads
+ * and validating inputs/outputs
+ */
+static void
+setup_test_pipeline (gint mode, GstCaps * infiltercaps, GstCaps * outfiltercaps,
+    gint numbuffers)
+{
+  GstElement *src;
+  GstElement *infilter;
+  GstElement *outfilter;
+  GstElement *sink;
+
+  setup_deinterlace ();
+
+  pipeline = gst_pipeline_new ("pipeline");
+  src = gst_element_factory_make ("videotestsrc", NULL);
+  infilter = gst_element_factory_make ("capsfilter", "infilter");
+  outfilter = gst_element_factory_make ("capsfilter", "outfilter");
+  sink = gst_element_factory_make ("fakesink", NULL);
+  fail_if (src == NULL);
+  fail_if (infilter == NULL);
+  fail_if (outfilter == NULL);
+  fail_if (sink == NULL);
+
+  fail_unless (gst_bin_add (GST_BIN (pipeline), src));
+  fail_unless (gst_bin_add (GST_BIN (pipeline), infilter));
+  fail_unless (gst_bin_add (GST_BIN (pipeline), deinterlace));
+  fail_unless (gst_bin_add (GST_BIN (pipeline), outfilter));
+  fail_unless (gst_bin_add (GST_BIN (pipeline), sink));
+
+  /* set the properties */
+  g_object_set (deinterlace, "mode", mode, NULL);
+  if (numbuffers > 0)
+    g_object_set (src, "num-buffers", numbuffers, NULL);
+  if (infiltercaps)
+    g_object_set (infilter, "caps", infiltercaps, NULL);
+  if (outfiltercaps)
+    g_object_set (outfilter, "caps", outfiltercaps, NULL);
+
+  fail_unless (gst_element_link_many (src, infilter, deinterlace, outfilter,
+          sink, NULL));
+  if (infiltercaps)
+    gst_caps_unref (infiltercaps);
+  if (outfiltercaps)
+    gst_caps_unref (outfiltercaps);
+}
+
+/*
+ * Checks if 2 buffers are equal
+ *
+ * Equals means same data
+ */
+static gboolean
+test_buffer_equals (GstBuffer * buf_a, GstBuffer * buf_b)
+{
+  GstMapInfo m1, m2;
+  gboolean res = FALSE;
+
+  gst_buffer_map (buf_a, &m1, GST_MAP_READ);
+  gst_buffer_map (buf_b, &m2, GST_MAP_READ);
+
+  if (m1.size == m2.size) {
+    res = memcmp (m1.data, m2.data, m1.size) == 0;
+  }
+  gst_buffer_unmap (buf_a, &m1);
+  gst_buffer_unmap (buf_b, &m2);
+
+  return res;
+}
+
+static GstPadProbeReturn
+sinkpad_enqueue_buffer (GstPad * pad, GstPadProbeInfo * info, gpointer data)
+{
+  GQueue *queue = (GQueue *) data;
+  GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER (info);
+
+  /* enqueue a copy for being compared later */
+  g_queue_push_tail (queue, gst_buffer_copy (buf));
+
+  return GST_PAD_PROBE_OK;
+}
+
+/*
+ * pad buffer probe that compares the buffer with the top one
+ * in the GQueue passed as the user data
+ */
+static GstPadProbeReturn
+srcpad_dequeue_and_compare_buffer (GstPad * pad, GstPadProbeInfo * info,
+    gpointer data)
+{
+  GQueue *queue = (GQueue *) data;
+  GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER (info);
+  GstBuffer *queue_buf;
+
+  queue_buf = (GstBuffer *) g_queue_pop_head (queue);
+  fail_if (queue_buf == NULL);
+
+  fail_unless (test_buffer_equals (buf, queue_buf));
+
+  gst_buffer_unref (queue_buf);
+
+  return GST_PAD_PROBE_OK;
+}
+
+/*
+ * Utility function that sets up a pipeline with deinterlace for
+ * validating that it operates in passthrough mode when receiving
+ * data with 'infiltercaps' as the input caps and operating in 'mode' mode
+ */
+static void
+deinterlace_check_passthrough (gint mode, const gchar * infiltercaps)
+{
+  GstMessage *msg;
+  GQueue *queue;
+  GstCaps *incaps = NULL;
+
+  if (infiltercaps)
+    incaps = gst_caps_from_string (infiltercaps);
+
+  setup_test_pipeline (mode, incaps, NULL, 20);
+
+  queue = g_queue_new ();
+
+  /* set up probes for testing */
+  gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BUFFER, sinkpad_enqueue_buffer,
+      queue, NULL);
+  gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_BUFFER,
+      srcpad_dequeue_and_compare_buffer, queue, NULL);
+
+  fail_unless (gst_element_set_state (pipeline, GST_STATE_PLAYING) !=
+      GST_STATE_CHANGE_FAILURE);
+
+  msg = gst_bus_poll (GST_ELEMENT_BUS (pipeline),
+      GST_MESSAGE_ERROR | GST_MESSAGE_EOS, -1);
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
+    GST_ERROR ("ERROR: %" GST_PTR_FORMAT, msg);
+    fail ("Unexpected error message");
+  }
+  gst_message_unref (msg);
+
+  /* queue should be empty */
+  fail_unless (g_queue_is_empty (queue));
+
+  fail_unless (gst_element_set_state (pipeline, GST_STATE_NULL) ==
+      GST_STATE_CHANGE_SUCCESS);
+  gst_object_unref (pipeline);
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+  g_queue_free (queue);
+}
+
+/*
+ * Sets the caps on deinterlace sinkpad and validates the
+ * caps that is set on the srcpad
+ */
+static void
+deinterlace_set_caps_and_check (GstCaps * input, gboolean must_deinterlace)
+{
+  GstCaps *othercaps = NULL;
+  GstSegment segment;
+
+  gst_pad_send_event (sinkpad, gst_event_new_stream_start ("test"));
+  fail_unless (gst_pad_set_caps (sinkpad, input));
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  gst_pad_send_event (sinkpad, gst_event_new_segment (&segment));
+
+  g_object_get (srcpad, "caps", &othercaps, NULL);
+
+  if (must_deinterlace) {
+    fail_if (gst_caps_is_interlaced (othercaps));
+  } else {
+    GstStructure *s;
+
+    fail_unless (gst_caps_is_interlaced (input) ==
+        gst_caps_is_interlaced (othercaps));
+
+    othercaps = gst_caps_make_writable (othercaps);
+    s = gst_caps_get_structure (othercaps, 0);
+    gst_structure_remove_field (s, "interlace-mode");
+
+    input = gst_caps_make_writable (input);
+    s = gst_caps_get_structure (input, 0);
+    gst_structure_remove_field (s, "interlace-mode");
+
+    fail_unless (gst_caps_is_equal (input, othercaps));
+  }
+  gst_caps_unref (input);
+  gst_caps_unref (othercaps);
+}
+
+static void
+deinterlace_set_string_caps_and_check (const gchar * input,
+    gboolean must_deinterlace)
+{
+  deinterlace_set_caps_and_check (gst_caps_from_string (input),
+      must_deinterlace);
+}
+
+GST_START_TEST (test_mode_auto_accept_caps)
+{
+  setup_deinterlace ();
+
+  /* auto mode */
+  g_object_set (deinterlace, "mode", 0, NULL);
+  fail_unless (gst_element_set_state (deinterlace, GST_STATE_PLAYING) ==
+      GST_STATE_CHANGE_SUCCESS);
+
+  /* try to set non interlaced caps */
+  deinterlace_set_string_caps_and_check (CAPS_YVYU, FALSE);
+  deinterlace_set_string_caps_and_check (CAPS_YUY2, FALSE);
+  deinterlace_set_string_caps_and_check (CAPS_YVYU_IMAGE, FALSE);
+  deinterlace_set_string_caps_and_check (CAPS_YUY2_IMAGE, FALSE);
+
+  /* now try to set interlaced caps */
+  deinterlace_set_string_caps_and_check (CAPS_YVYU_INTERLACED, TRUE);
+  deinterlace_set_string_caps_and_check (CAPS_YUY2_INTERLACED, TRUE);
+  deinterlace_set_string_caps_and_check (CAPS_YVYU_INTERLACED_IMAGE, TRUE);
+  deinterlace_set_string_caps_and_check (CAPS_YUY2_INTERLACED_IMAGE, TRUE);
+
+  /* cleanup */
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+  fail_unless (gst_element_set_state (deinterlace, GST_STATE_NULL) ==
+      GST_STATE_CHANGE_SUCCESS);
+  gst_object_unref (deinterlace);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_mode_forced_accept_caps)
+{
+  setup_deinterlace ();
+
+  /* forced mode */
+  g_object_set (deinterlace, "mode", 1, NULL);
+  fail_unless (gst_element_set_state (deinterlace, GST_STATE_PLAYING) ==
+      GST_STATE_CHANGE_SUCCESS);
+
+  /* try to set non interlaced caps */
+  deinterlace_set_string_caps_and_check (CAPS_YVYU, TRUE);
+  deinterlace_set_string_caps_and_check (CAPS_YUY2, TRUE);
+  deinterlace_set_string_caps_and_check (CAPS_YVYU_IMAGE, TRUE);
+  deinterlace_set_string_caps_and_check (CAPS_YUY2_IMAGE, TRUE);
+
+  /* now try to set interlaced caps */
+  deinterlace_set_string_caps_and_check (CAPS_YVYU_INTERLACED, TRUE);
+  deinterlace_set_string_caps_and_check (CAPS_YUY2_INTERLACED, TRUE);
+  deinterlace_set_string_caps_and_check (CAPS_YVYU_INTERLACED_IMAGE, TRUE);
+  deinterlace_set_string_caps_and_check (CAPS_YUY2_INTERLACED_IMAGE, TRUE);
+
+  /* cleanup */
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+  fail_unless (gst_element_set_state (deinterlace, GST_STATE_NULL) ==
+      GST_STATE_CHANGE_SUCCESS);
+  gst_object_unref (deinterlace);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_mode_disabled_accept_caps)
+{
+  setup_deinterlace ();
+
+  /* disabled mode */
+  g_object_set (deinterlace, "mode", 2, NULL);
+  fail_unless (gst_element_set_state (deinterlace, GST_STATE_PLAYING) ==
+      GST_STATE_CHANGE_SUCCESS);
+
+  /* try to set non interlaced caps */
+  deinterlace_set_string_caps_and_check (CAPS_YVYU, FALSE);
+  deinterlace_set_string_caps_and_check (CAPS_YUY2, FALSE);
+  deinterlace_set_string_caps_and_check (CAPS_YVYU_IMAGE, FALSE);
+  deinterlace_set_string_caps_and_check (CAPS_YUY2_IMAGE, FALSE);
+
+  /* now try to set interlaced caps */
+  deinterlace_set_string_caps_and_check (CAPS_YVYU_INTERLACED, FALSE);
+  deinterlace_set_string_caps_and_check (CAPS_YUY2_INTERLACED, FALSE);
+  deinterlace_set_string_caps_and_check (CAPS_YVYU_INTERLACED_IMAGE, FALSE);
+  deinterlace_set_string_caps_and_check (CAPS_YUY2_INTERLACED_IMAGE, FALSE);
+
+  /* cleanup */
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+  fail_unless (gst_element_set_state (deinterlace, GST_STATE_NULL) ==
+      GST_STATE_CHANGE_SUCCESS);
+  gst_object_unref (deinterlace);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_mode_disabled_passthrough)
+{
+  /* 2 is disabled mode */
+  deinterlace_check_passthrough (2, CAPS_YUY2_INTERLACED);
+  deinterlace_check_passthrough (2, CAPS_YVYU_INTERLACED);
+  deinterlace_check_passthrough (2, CAPS_YUY2);
+  deinterlace_check_passthrough (2, CAPS_YVYU);
+
+  deinterlace_check_passthrough (2, CAPS_YUY2_INTERLACED_IMAGE);
+  deinterlace_check_passthrough (2, CAPS_YVYU_INTERLACED_IMAGE);
+  deinterlace_check_passthrough (2, CAPS_YUY2_IMAGE);
+  deinterlace_check_passthrough (2, CAPS_YVYU_IMAGE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_mode_auto_deinterlaced_passthrough)
+{
+  /* 0 is auto mode */
+  deinterlace_check_passthrough (0, CAPS_YUY2);
+  deinterlace_check_passthrough (0, CAPS_YVYU);
+  deinterlace_check_passthrough (0, CAPS_YUY2_IMAGE);
+  deinterlace_check_passthrough (0, CAPS_YVYU_IMAGE);
+}
+
+GST_END_TEST;
+
+static GstPadProbeReturn
+catch_caps_event (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
+{
+  GstCaps **outcaps = user_data;
+
+  if (GST_EVENT_TYPE (info->data) == GST_EVENT_CAPS) {
+    g_assert (*outcaps == NULL);
+
+    gst_event_parse_caps (GST_EVENT (info->data), outcaps);
+    gst_caps_ref (*outcaps);
+  }
+
+  return GST_PAD_PROBE_OK;
+}
+
+static void
+deinterlace_set_caps_with_filter_and_check_result (gint mode, gint fields,
+    const gchar * input_caps, const gchar * filter_caps,
+    const gchar * output_caps)
+{
+  GstElement *deinterlace, *capsfilter;
+  GstPad *sinkpad, *srcpad;
+  GstCaps *caps, *outcaps_actual = NULL;
+  GstCaps *outcaps_expected = NULL;
+
+  deinterlace = gst_element_factory_make ("deinterlace", NULL);
+  fail_unless (deinterlace != NULL);
+  g_object_set (deinterlace, "mode", mode, "fields", fields, NULL);
+
+  caps = gst_caps_from_string (filter_caps);
+  fail_unless (caps != NULL);
+  capsfilter = gst_element_factory_make ("capsfilter", NULL);
+  g_object_set (capsfilter, "caps", caps, NULL);
+  gst_caps_unref (caps);
+
+  fail_unless (gst_element_link (deinterlace, capsfilter));
+
+  sinkpad = gst_element_get_static_pad (deinterlace, "sink");
+  fail_unless (sinkpad);
+
+  srcpad = gst_element_get_static_pad (capsfilter, "src");
+  fail_unless (srcpad);
+
+  gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
+      catch_caps_event, &outcaps_actual, NULL);
+
+  if (output_caps) {
+    outcaps_expected = gst_caps_from_string (output_caps);
+    fail_unless (outcaps_expected != NULL);
+  }
+
+  fail_unless (gst_element_set_state (deinterlace,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
+  fail_unless (gst_element_set_state (capsfilter,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
+
+  caps = gst_caps_from_string (input_caps);
+  fail_unless (caps != NULL);
+  gst_pad_send_event (sinkpad, gst_event_new_caps (caps));
+  gst_caps_unref (caps);
+
+  if (output_caps) {
+    gchar *actual;
+
+    fail_if (outcaps_actual == NULL, "Expected %s, got no caps", output_caps);
+    actual = gst_caps_to_string (outcaps_actual);
+    fail_unless (gst_caps_is_equal (outcaps_actual, outcaps_expected),
+        "Expected %s, got %s", output_caps, actual);
+    g_free (actual);
+  } else {
+    gchar *actual;
+
+    actual = gst_caps_to_string (outcaps_actual);
+    fail_if (outcaps_actual != NULL, "Expected negotiation failure, got %s",
+        actual);
+    g_free (actual);
+  }
+
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+
+  fail_unless (gst_element_set_state (deinterlace,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
+  fail_unless (gst_element_set_state (capsfilter,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
+  gst_object_unref (deinterlace);
+  gst_object_unref (capsfilter);
+
+  if (outcaps_expected)
+    gst_caps_unref (outcaps_expected);
+  if (outcaps_actual)
+    gst_caps_unref (outcaps_actual);
+}
+
+GST_START_TEST (test_mode_disabled_expected_caps)
+{
+  deinterlace_set_caps_with_filter_and_check_result (2, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (2, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (2, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (2, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (2, 0,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw(ANY)",
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (2, 0,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw(ANY)",
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (2, 1,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw(ANY)",
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (2, 1,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw(ANY)",
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (2, 0,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (2, 0,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (2, 1,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (2, 1,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (2, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (2, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (2, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (2, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_mode_interlaced_expected_caps)
+{
+  deinterlace_set_caps_with_filter_and_check_result (1, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=40/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (1, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=40/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (1, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (1, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (1, 0,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1", "video/x-raw(ANY)", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (1, 0,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1", "video/x-raw(ANY)", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (1, 1,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1", "video/x-raw(ANY)", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (1, 1,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1", "video/x-raw(ANY)", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (1, 0,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1", "video/x-raw", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (1, 0,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1", "video/x-raw", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (1, 1,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1", "video/x-raw", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (1, 1,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1", "video/x-raw", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (1, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (1, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (1, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (1, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_mode_auto_expected_caps)
+{
+  deinterlace_set_caps_with_filter_and_check_result (0, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=40/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 0,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw(ANY)",
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 0,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw(ANY)",
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 1,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw(ANY)",
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 1,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw(ANY)",
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 0,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 0,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 1,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 1,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 0,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 0,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved",
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 1,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 1,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved",
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_mode_auto_strict_expected_caps)
+{
+  deinterlace_set_caps_with_filter_and_check_result (3, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=40/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 0,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw(ANY)",
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 0,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1", "video/x-raw(ANY)", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 1,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw(ANY)",
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 1,
+      "video/x-raw(memory:SomeMemory), format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1", "video/x-raw(ANY)", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 0,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 0,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1", "video/x-raw", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 1,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw",
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 1,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1", "video/x-raw", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 0,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 1,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 0,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 0,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 1,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+
+  deinterlace_set_caps_with_filter_and_check_result (3, 1,
+      "video/x-raw, format=v210, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=interleaved", NULL);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_fields_auto_expected_caps)
+{
+  deinterlace_set_caps_with_filter_and_check_result (0, 3,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=progressive, framerate=20/1",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=20/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 3,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=progressive, framerate=40/1",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=40/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 3,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=progressive",
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=progressive, framerate=40/1");
+
+  deinterlace_set_caps_with_filter_and_check_result (0, 3,
+      "video/x-raw, format=I420, width=320, height=240, "
+      "interlace-mode=interleaved, framerate=20/1",
+      "video/x-raw, interlace-mode=progressive, framerate=15/1", NULL);
+}
+
+GST_END_TEST;
+
+
+
+static Suite *
+deinterlace_suite (void)
+{
+  Suite *s = suite_create ("deinterlace");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_set_timeout (tc_chain, 180);
+
+  if (!gst_registry_check_feature_version (gst_registry_get (), "deinterlace",
+          GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO)) {
+    GST_ERROR ("FIXME: port deinterlace element");
+    return s;
+  }
+
+  tcase_add_test (tc_chain, test_create_and_unref);
+  tcase_add_test (tc_chain, test_mode_auto_accept_caps);
+  tcase_add_test (tc_chain, test_mode_forced_accept_caps);
+  tcase_add_test (tc_chain, test_mode_disabled_accept_caps);
+  tcase_add_test (tc_chain, test_mode_disabled_passthrough);
+  tcase_add_test (tc_chain, test_mode_auto_deinterlaced_passthrough);
+
+  tcase_add_test (tc_chain, test_mode_disabled_expected_caps);
+  tcase_add_test (tc_chain, test_mode_interlaced_expected_caps);
+  tcase_add_test (tc_chain, test_mode_auto_expected_caps);
+  tcase_add_test (tc_chain, test_mode_auto_strict_expected_caps);
+  tcase_add_test (tc_chain, test_fields_auto_expected_caps);
+
+  return s;
+}
+
+GST_CHECK_MAIN (deinterlace);
diff --git a/tests/check/elements/deinterleave.c b/tests/check/elements/deinterleave.c
new file mode 100644
index 0000000..b246105
--- /dev/null
+++ b/tests/check/elements/deinterleave.c
@@ -0,0 +1,657 @@
+/* GStreamer unit tests for the interleave element
+ * Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <gst/audio/audio.h>
+#include <gst/check/gstcheck.h>
+#include <gst/audio/audio.h>
+
+GST_START_TEST (test_create_and_unref)
+{
+  GstElement *deinterleave;
+
+  deinterleave = gst_element_factory_make ("deinterleave", NULL);
+  fail_unless (deinterleave != NULL);
+
+  gst_element_set_state (deinterleave, GST_STATE_NULL);
+  gst_object_unref (deinterleave);
+}
+
+GST_END_TEST;
+
+static GstPad *mysrcpad, **mysinkpads;
+static gint nsinkpads;
+static GstBus *bus;
+static GstElement *deinterleave;
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (F32) ", "
+        "channels = (int) 1, layout = (string) {interleaved, non-interleaved}, rate = (int) {32000, 48000}"));
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (F32) ", "
+        "channels = (int) { 2, 3 }, layout = (string) interleaved, rate = (int) {32000, 48000}"));
+
+#define CAPS_32khz \
+        "audio/x-raw, " \
+        "format = (string) "GST_AUDIO_NE (F32) ", " \
+        "channels = (int) 2, layout = (string) interleaved, " \
+        "rate = (int) 32000"
+
+#define CAPS_48khz \
+        "audio/x-raw, " \
+        "format = (string) "GST_AUDIO_NE (F32) ", " \
+        "channels = (int) 2, layout = (string) interleaved, " \
+        "rate = (int) 48000"
+
+#define CAPS_48khz_3CH \
+        "audio/x-raw, " \
+        "format = (string) "GST_AUDIO_NE (F32) ", " \
+        "channels = (int) 3, layout = (string) interleaved, " \
+        "rate = (int) 48000"
+
+static GstFlowReturn
+deinterleave_chain_func (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  gint i;
+  GstMapInfo map;
+  gfloat *indata;
+
+  fail_unless (GST_IS_BUFFER (buffer));
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  indata = (gfloat *) map.data;
+  fail_unless_equals_int (map.size, 48000 * sizeof (gfloat));
+  fail_unless (indata != NULL);
+
+  if (strcmp (GST_PAD_NAME (pad), "sink0") == 0) {
+    for (i = 0; i < 48000; i++)
+      fail_unless_equals_float (indata[i], -1.0);
+  } else if (strcmp (GST_PAD_NAME (pad), "sink1") == 0) {
+    for (i = 0; i < 48000; i++)
+      fail_unless_equals_float (indata[i], 1.0);
+  } else {
+    g_assert_not_reached ();
+  }
+  gst_buffer_unmap (buffer, &map);
+  gst_buffer_unref (buffer);
+
+  return GST_FLOW_OK;
+}
+
+static void
+deinterleave_pad_added (GstElement * src, GstPad * pad, gpointer data)
+{
+  gchar *name;
+  gint link = GPOINTER_TO_INT (data);
+
+  if (nsinkpads >= link)
+    return;
+
+  name = g_strdup_printf ("sink%d", nsinkpads);
+
+  mysinkpads[nsinkpads] =
+      gst_pad_new_from_static_template (&sinktemplate, name);
+  g_free (name);
+  fail_if (mysinkpads[nsinkpads] == NULL);
+
+  gst_pad_set_chain_function (mysinkpads[nsinkpads], deinterleave_chain_func);
+  fail_unless (gst_pad_link (pad, mysinkpads[nsinkpads]) == GST_PAD_LINK_OK);
+  gst_pad_set_active (mysinkpads[nsinkpads], TRUE);
+  nsinkpads++;
+}
+
+GST_START_TEST (test_2_channels)
+{
+  GstPad *sinkpad;
+  gint i;
+  GstBuffer *inbuf;
+  GstCaps *caps;
+  gfloat *indata;
+  GstMapInfo map;
+  guint64 channel_mask = 0;
+
+  mysinkpads = g_new0 (GstPad *, 2);
+  nsinkpads = 0;
+
+  deinterleave = gst_element_factory_make ("deinterleave", NULL);
+  fail_unless (deinterleave != NULL);
+
+  mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src");
+  fail_unless (mysrcpad != NULL);
+  gst_pad_set_active (mysrcpad, TRUE);
+
+  caps = gst_caps_from_string (CAPS_48khz);
+  channel_mask |=
+      G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
+  channel_mask |=
+      G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
+  gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, channel_mask,
+      NULL);
+
+  gst_check_setup_events (mysrcpad, deinterleave, caps, GST_FORMAT_TIME);
+
+  sinkpad = gst_element_get_static_pad (deinterleave, "sink");
+  fail_unless (sinkpad != NULL);
+  fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK);
+  g_object_unref (sinkpad);
+
+  g_signal_connect (deinterleave, "pad-added",
+      G_CALLBACK (deinterleave_pad_added), GINT_TO_POINTER (2));
+
+  bus = gst_bus_new ();
+  gst_element_set_bus (deinterleave, bus);
+
+  fail_unless (gst_element_set_state (deinterleave,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
+
+  inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat));
+  inbuf = gst_buffer_make_writable (inbuf);
+  gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
+  indata = (gfloat *) map.data;
+  for (i = 0; i < 2 * 48000; i += 2) {
+    indata[i] = -1.0;
+    indata[i + 1] = 1.0;
+  }
+  gst_buffer_unmap (inbuf, &map);
+
+  fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
+
+  fail_unless (gst_element_set_state (deinterleave,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
+
+  for (i = 0; i < nsinkpads; i++)
+    g_object_unref (mysinkpads[i]);
+  g_free (mysinkpads);
+  mysinkpads = NULL;
+
+  g_object_unref (deinterleave);
+  gst_bus_set_flushing (bus, TRUE);
+  g_object_unref (bus);
+  gst_caps_unref (caps);
+  gst_object_unref (mysrcpad);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_2_channels_1_linked)
+{
+  GstPad *sinkpad;
+  gint i;
+  GstBuffer *inbuf;
+  GstCaps *caps;
+  gfloat *indata;
+  GstMapInfo map;
+  guint64 channel_mask = 0;
+
+  nsinkpads = 0;
+  mysinkpads = g_new0 (GstPad *, 2);
+
+  deinterleave = gst_element_factory_make ("deinterleave", NULL);
+  fail_unless (deinterleave != NULL);
+
+  mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src");
+  fail_unless (mysrcpad != NULL);
+  gst_pad_set_active (mysrcpad, TRUE);
+
+  caps = gst_caps_from_string (CAPS_48khz);
+  channel_mask |=
+      G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
+  channel_mask |=
+      G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
+  gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, channel_mask,
+      NULL);
+
+  gst_check_setup_events (mysrcpad, deinterleave, caps, GST_FORMAT_TIME);
+
+  sinkpad = gst_element_get_static_pad (deinterleave, "sink");
+  fail_unless (sinkpad != NULL);
+  fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK);
+  g_object_unref (sinkpad);
+
+  g_signal_connect (deinterleave, "pad-added",
+      G_CALLBACK (deinterleave_pad_added), GINT_TO_POINTER (1));
+
+  bus = gst_bus_new ();
+  gst_element_set_bus (deinterleave, bus);
+
+  fail_unless (gst_element_set_state (deinterleave,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
+
+  inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat));
+  inbuf = gst_buffer_make_writable (inbuf);
+  gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
+  indata = (gfloat *) map.data;
+  for (i = 0; i < 2 * 48000; i += 2) {
+    indata[i] = -1.0;
+    indata[i + 1] = 1.0;
+  }
+  gst_buffer_unmap (inbuf, &map);
+
+  fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
+
+  fail_unless (gst_element_set_state (deinterleave,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
+
+  for (i = 0; i < nsinkpads; i++)
+    g_object_unref (mysinkpads[i]);
+  g_free (mysinkpads);
+  mysinkpads = NULL;
+
+  g_object_unref (deinterleave);
+  gst_bus_set_flushing (bus, TRUE);
+  g_object_unref (bus);
+  gst_caps_unref (caps);
+  gst_object_unref (mysrcpad);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_2_channels_caps_change)
+{
+  GstPad *sinkpad;
+  GstCaps *caps, *caps2;
+  GstCaps *ret_caps;
+  gint i;
+  GstBuffer *inbuf;
+  gfloat *indata;
+  GstMapInfo map;
+  guint64 channel_mask;
+
+  nsinkpads = 0;
+  mysinkpads = g_new0 (GstPad *, 2);
+
+  deinterleave = gst_element_factory_make ("deinterleave", NULL);
+  fail_unless (deinterleave != NULL);
+
+  mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src");
+  fail_unless (mysrcpad != NULL);
+
+  gst_pad_set_active (mysrcpad, TRUE);
+
+  caps = gst_caps_from_string (CAPS_48khz);
+  channel_mask = 0;
+  channel_mask |=
+      G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
+  channel_mask |=
+      G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
+  gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, channel_mask,
+      NULL);
+
+  sinkpad = gst_element_get_static_pad (deinterleave, "sink");
+  fail_unless (sinkpad != NULL);
+  fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK);
+  g_object_unref (sinkpad);
+
+  ret_caps = gst_pad_peer_query_caps (mysrcpad, caps);
+  fail_if (gst_caps_is_empty (ret_caps));
+  fail_unless (gst_pad_peer_query_accept_caps (mysrcpad, caps));
+  gst_caps_unref (ret_caps);
+  gst_check_setup_events (mysrcpad, deinterleave, caps, GST_FORMAT_TIME);
+
+  g_signal_connect (deinterleave, "pad-added",
+      G_CALLBACK (deinterleave_pad_added), GINT_TO_POINTER (2));
+
+  bus = gst_bus_new ();
+  gst_element_set_bus (deinterleave, bus);
+
+  fail_unless (gst_element_set_state (deinterleave,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
+
+  inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat));
+  inbuf = gst_buffer_make_writable (inbuf);
+  gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
+  indata = (gfloat *) map.data;
+  for (i = 0; i < 2 * 48000; i += 2) {
+    indata[i] = -1.0;
+    indata[i + 1] = 1.0;
+  }
+  gst_buffer_unmap (inbuf, &map);
+
+  fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
+
+  caps2 = gst_caps_from_string (CAPS_32khz);
+  channel_mask = 0;
+  channel_mask |=
+      G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
+  channel_mask |=
+      G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
+  gst_caps_set_simple (caps2, "channel-mask", GST_TYPE_BITMASK, channel_mask,
+      NULL);
+  ret_caps = gst_pad_peer_query_caps (mysrcpad, caps2);
+  fail_if (gst_caps_is_empty (ret_caps));
+  fail_unless (gst_pad_peer_query_accept_caps (mysrcpad, caps2));
+  gst_caps_unref (ret_caps);
+  gst_pad_set_caps (mysrcpad, caps2);
+
+  inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat));
+  inbuf = gst_buffer_make_writable (inbuf);
+  gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
+  indata = (gfloat *) map.data;
+  for (i = 0; i < 2 * 48000; i += 2) {
+    indata[i] = -1.0;
+    indata[i + 1] = 1.0;
+  }
+  gst_buffer_unmap (inbuf, &map);
+
+  /* Should work fine because the caps changed in a compatible way */
+  fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
+
+  gst_caps_unref (caps2);
+
+  caps2 = gst_caps_from_string (CAPS_48khz_3CH);
+  channel_mask = 0;
+  channel_mask |=
+      G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
+  channel_mask |=
+      G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
+  channel_mask |=
+      G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
+  gst_caps_set_simple (caps2, "channel-mask", GST_TYPE_BITMASK, channel_mask,
+      NULL);
+  ret_caps = gst_pad_peer_query_caps (mysrcpad, caps2);
+  fail_unless (gst_caps_is_empty (ret_caps));
+  gst_caps_unref (ret_caps);
+  fail_if (gst_pad_peer_query_accept_caps (mysrcpad, caps2));
+  gst_pad_set_caps (mysrcpad, caps2);
+
+  inbuf = gst_buffer_new_and_alloc (3 * 48000 * sizeof (gfloat));
+  inbuf = gst_buffer_make_writable (inbuf);
+  gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
+  indata = (gfloat *) map.data;
+  for (i = 0; i < 3 * 48000; i += 3) {
+    indata[i] = -1.0;
+    indata[i + 1] = 1.0;
+    indata[i + 2] = 0.0;
+  }
+  gst_buffer_unmap (inbuf, &map);
+
+  /* Should break because the caps changed in an incompatible way */
+  fail_if (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
+
+  fail_unless (gst_element_set_state (deinterleave,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
+
+  for (i = 0; i < nsinkpads; i++)
+    g_object_unref (mysinkpads[i]);
+  g_free (mysinkpads);
+  mysinkpads = NULL;
+
+  g_object_unref (deinterleave);
+  gst_bus_set_flushing (bus, TRUE);
+  g_object_unref (bus);
+  gst_caps_unref (caps);
+  gst_caps_unref (caps2);
+  gst_object_unref (mysrcpad);
+}
+
+GST_END_TEST;
+
+
+#define SAMPLES_PER_BUFFER  10
+#define NUM_CHANNELS        8
+#define SAMPLE_RATE         44100
+
+static guint pads_created;
+
+static void
+set_channel_positions (GstCaps * caps, int channels,
+    GstAudioChannelPosition * channelpositions)
+{
+  int c;
+  guint64 channel_mask = 0;
+
+  for (c = 0; c < channels; c++)
+    channel_mask |= G_GUINT64_CONSTANT (1) << channelpositions[c];
+
+  gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, channel_mask,
+      NULL);
+}
+
+static void
+src_handoff_float32_8ch (GstElement * src, GstBuffer * buf, GstPad * pad,
+    gpointer user_data)
+{
+  gfloat *data, *p;
+  guint size, i, c;
+
+  size = sizeof (gfloat) * SAMPLES_PER_BUFFER * NUM_CHANNELS;
+  data = p = (gfloat *) g_malloc (size);
+
+  for (i = 0; i < SAMPLES_PER_BUFFER; ++i) {
+    for (c = 0; c < NUM_CHANNELS; ++c) {
+      *p = (gfloat) ((i * NUM_CHANNELS) + c);
+      ++p;
+    }
+  }
+
+  if (gst_buffer_n_memory (buf)) {
+    gst_buffer_replace_memory_range (buf, 0, -1,
+        gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
+  } else {
+    gst_buffer_insert_memory (buf, 0,
+        gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
+  }
+  GST_BUFFER_OFFSET (buf) = 0;
+  GST_BUFFER_TIMESTAMP (buf) = 0;
+}
+
+static GstPadProbeReturn
+src_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer userdata)
+{
+  GstAudioChannelPosition layout[NUM_CHANNELS];
+  GstCaps *caps;
+  guint i;
+
+  if ((info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)
+      && GST_EVENT_TYPE (info->data) == GST_EVENT_STREAM_START) {
+    gst_pad_remove_probe (pad, info->id);
+
+    caps = gst_caps_new_simple ("audio/x-raw",
+        "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
+        "channels", G_TYPE_INT, NUM_CHANNELS,
+        "layout", G_TYPE_STRING, "interleaved",
+        "rate", G_TYPE_INT, SAMPLE_RATE, NULL);
+
+    for (i = 0; i < NUM_CHANNELS; ++i)
+      layout[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT + i;
+
+    set_channel_positions (caps, NUM_CHANNELS, layout);
+    gst_pad_set_caps (pad, caps);
+    gst_caps_unref (caps);
+  }
+
+  return GST_PAD_PROBE_OK;
+}
+
+static GstPadProbeReturn
+float_buffer_check_probe (GstPad * pad, GstPadProbeInfo * info,
+    gpointer userdata)
+{
+  GstMapInfo map;
+  gfloat *data;
+  guint padnum, numpads;
+  guint num, i;
+  GstCaps *caps;
+  GstStructure *s;
+  GstAudioChannelPosition *pos;
+  gint channels;
+  GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
+  GstAudioInfo audio_info;
+  guint pad_id = GPOINTER_TO_UINT (userdata);
+
+  fail_unless_equals_int (sscanf (GST_PAD_NAME (pad), "src_%u", &padnum), 1);
+
+  numpads = pads_created;
+
+  /* Check caps */
+  caps = gst_pad_get_current_caps (pad);
+  fail_unless (caps != NULL);
+  s = gst_caps_get_structure (caps, 0);
+  fail_unless (gst_structure_get_int (s, "channels", &channels));
+  fail_unless_equals_int (channels, 1);
+
+  gst_audio_info_init (&audio_info);
+  fail_unless (gst_audio_info_from_caps (&audio_info, caps));
+
+  pos = audio_info.position;
+  fail_unless (pos != NULL
+      && pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT + pad_id);
+  gst_caps_unref (caps);
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  data = (gfloat *) map.data;
+  num = map.size / sizeof (gfloat);
+
+  /* Check buffer content */
+  for (i = 0; i < num; ++i) {
+    guint val, rest;
+
+    val = (guint) data[i];
+    GST_LOG ("%s[%u]: %8f", GST_PAD_NAME (pad), i, data[i]);
+    /* can't use the modulo operator in the assertion statement, since due to
+     * the way it gets expanded it would be interpreted as a printf operator
+     * in the failure case, which will result in segfaults */
+    rest = val % numpads;
+    /* check that the first channel is on pad src0, the second on src1 etc. */
+    fail_unless_equals_int (rest, padnum);
+  }
+  gst_buffer_unmap (buffer, &map);
+
+  return GST_PAD_PROBE_OK;      /* don't drop data */
+}
+
+static void
+pad_added_setup_data_check_float32_8ch_cb (GstElement * deinterleave,
+    GstPad * pad, GstElement * pipeline)
+{
+  GstElement *queue, *sink;
+  GstPad *sinkpad;
+
+  queue = gst_element_factory_make ("queue", NULL);
+  fail_unless (queue != NULL);
+
+  sink = gst_element_factory_make ("fakesink", NULL);
+  fail_unless (sink != NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), queue, sink, NULL);
+  gst_element_link_pads_full (queue, "src", sink, "sink",
+      GST_PAD_LINK_CHECK_NOTHING);
+
+  sinkpad = gst_element_get_static_pad (queue, "sink");
+
+  fail_unless_equals_int (gst_pad_link (pad, sinkpad), GST_PAD_LINK_OK);
+  gst_object_unref (sinkpad);
+
+  gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, float_buffer_check_probe,
+      GUINT_TO_POINTER (pads_created), NULL);
+
+  gst_element_set_state (sink, GST_STATE_PLAYING);
+  gst_element_set_state (queue, GST_STATE_PLAYING);
+
+  GST_LOG ("new pad: %s", GST_PAD_NAME (pad));
+  ++pads_created;
+}
+
+static GstElement *
+make_fake_src_8chans_float32 (void)
+{
+  GstElement *src;
+  GstPad *pad;
+
+  src = gst_element_factory_make ("fakesrc", "src");
+  fail_unless (src != NULL, "failed to create fakesrc element");
+
+  g_object_set (src, "num-buffers", 1, NULL);
+  g_object_set (src, "signal-handoffs", TRUE, NULL);
+
+  g_signal_connect (src, "handoff", G_CALLBACK (src_handoff_float32_8ch), NULL);
+
+  pad = gst_element_get_static_pad (src, "src");
+  gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, src_event_probe,
+      NULL, NULL);
+  gst_object_unref (pad);
+
+  return src;
+}
+
+GST_START_TEST (test_8_channels_float32)
+{
+  GstElement *pipeline, *src, *deinterleave;
+  GstMessage *msg;
+
+  pipeline = (GstElement *) gst_pipeline_new ("pipeline");
+  fail_unless (pipeline != NULL, "failed to create pipeline");
+
+  src = make_fake_src_8chans_float32 ();
+
+  deinterleave = gst_element_factory_make ("deinterleave", "deinterleave");
+  fail_unless (deinterleave != NULL, "failed to create deinterleave element");
+  g_object_set (deinterleave, "keep-positions", TRUE, NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, deinterleave, NULL);
+
+  fail_unless (gst_element_link (src, deinterleave),
+      "failed to link src <=> deinterleave");
+
+  g_signal_connect (deinterleave, "pad-added",
+      G_CALLBACK (pad_added_setup_data_check_float32_8ch_cb), pipeline);
+
+  pads_created = 0;
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  msg = gst_bus_poll (GST_ELEMENT_BUS (pipeline), GST_MESSAGE_EOS, -1);
+  gst_message_unref (msg);
+
+  fail_unless_equals_int (pads_created, NUM_CHANNELS);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
+static Suite *
+deinterleave_suite (void)
+{
+  Suite *s = suite_create ("deinterleave");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_set_timeout (tc_chain, 180);
+  tcase_add_test (tc_chain, test_create_and_unref);
+  tcase_add_test (tc_chain, test_2_channels);
+  tcase_add_test (tc_chain, test_2_channels_1_linked);
+  tcase_add_test (tc_chain, test_2_channels_caps_change);
+  tcase_add_test (tc_chain, test_8_channels_float32);
+
+  return s;
+}
+
+GST_CHECK_MAIN (deinterleave);
diff --git a/tests/check/elements/dtmf.c b/tests/check/elements/dtmf.c
new file mode 100644
index 0000000..c2ae36d
--- /dev/null
+++ b/tests/check/elements/dtmf.c
@@ -0,0 +1,588 @@
+/* GStreamer
+ *
+ * unit test for dtmf elements
+ * Copyright (C) 2013 Collabora Ltd
+ *   @author: Olivier Crete <olivier.crete@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/check/gstcheck.h>
+#include <gst/check/gsttestclock.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+
+/* Include this from the plugin to get the defines */
+
+#include "../../gst/dtmf/gstdtmfcommon.h"
+
+#define END_BIT (1<<7)
+
+static GstStaticPadTemplate audio_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) \"" GST_AUDIO_NE (S16) "\", "
+        "rate = " GST_AUDIO_RATE_RANGE ", " "channels = (int) 1")
+    );
+
+static GstStaticPadTemplate rtp_dtmf_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) [ 0, MAX ], "
+        "encoding-name = (string) \"TELEPHONE-EVENT\"")
+    );
+
+
+static void
+check_get_dtmf_event_message (GstBus * bus, gint number, gint volume)
+{
+  GstMessage *message;
+  gboolean have_message = FALSE;
+
+  while (!have_message &&
+      (message = gst_bus_pop_filtered (bus, GST_MESSAGE_ELEMENT)) != NULL) {
+    if (gst_message_has_name (message, "dtmf-event")) {
+      const GstStructure *s = gst_message_get_structure (message);
+      gint stype, snumber, smethod, svolume;
+
+      fail_unless (gst_structure_get (s,
+              "type", G_TYPE_INT, &stype,
+              "number", G_TYPE_INT, &snumber,
+              "method", G_TYPE_INT, &smethod,
+              "volume", G_TYPE_INT, &svolume, NULL));
+
+      fail_unless (stype == 1);
+      fail_unless (smethod == 1);
+      fail_unless (snumber == number);
+      fail_unless (svolume == volume);
+      have_message = TRUE;
+    }
+    gst_message_unref (message);
+  }
+
+  fail_unless (have_message);
+}
+
+static void
+check_no_dtmf_event_message (GstBus * bus)
+{
+  GstMessage *message;
+  gboolean have_message = FALSE;
+
+  while (!have_message &&
+      (message = gst_bus_pop_filtered (bus, GST_MESSAGE_ELEMENT)) != NULL) {
+    if (gst_message_has_name (message, "dtmf-event") ||
+        gst_message_has_name (message, "dtmf-event-processed") ||
+        gst_message_has_name (message, "dtmf-event-dropped")) {
+      have_message = TRUE;
+    }
+    gst_message_unref (message);
+  }
+
+  fail_unless (!have_message);
+}
+
+static void
+check_buffers_duration (GstClockTime expected_duration)
+{
+  GstClockTime duration = 0;
+
+  while (buffers) {
+    GstBuffer *buf = buffers->data;
+
+    buffers = g_list_delete_link (buffers, buffers);
+
+    fail_unless (GST_BUFFER_DURATION_IS_VALID (buf));
+    duration += GST_BUFFER_DURATION (buf);
+    gst_buffer_unref (buf);
+  }
+
+  fail_unless (duration == expected_duration);
+}
+
+static void
+send_rtp_packet (GstPad * src, guint timestamp, gboolean marker, gboolean end,
+    guint number, guint volume, guint duration)
+{
+  GstBuffer *buf;
+  GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT;
+  gchar *payload;
+  static guint seqnum = 1;
+
+  buf = gst_rtp_buffer_new_allocate (4, 0, 0);
+  fail_unless (gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtpbuf));
+  gst_rtp_buffer_set_seq (&rtpbuf, seqnum++);
+  gst_rtp_buffer_set_timestamp (&rtpbuf, timestamp);
+  gst_rtp_buffer_set_marker (&rtpbuf, marker);
+  payload = gst_rtp_buffer_get_payload (&rtpbuf);
+  payload[0] = number;
+  payload[1] = volume | (end ? END_BIT : 0);
+  GST_WRITE_UINT16_BE (payload + 2, duration);
+  gst_rtp_buffer_unmap (&rtpbuf);
+  fail_unless (gst_pad_push (src, buf) == GST_FLOW_OK);
+}
+
+GST_START_TEST (test_rtpdtmfdepay)
+{
+  GstElement *dtmfdepay;
+  GstPad *src, *sink;
+  GstBus *bus;
+  GstCaps *caps_in;
+  GstCaps *expected_caps_out;
+  GstCaps *caps_out;
+
+  dtmfdepay = gst_check_setup_element ("rtpdtmfdepay");
+  sink = gst_check_setup_sink_pad (dtmfdepay, &audio_sink_template);
+  src = gst_check_setup_src_pad (dtmfdepay, &rtp_dtmf_src_template);
+
+  bus = gst_bus_new ();
+  gst_element_set_bus (dtmfdepay, bus);
+
+  gst_pad_set_active (src, TRUE);
+  gst_pad_set_active (sink, TRUE);
+  gst_element_set_state (dtmfdepay, GST_STATE_PLAYING);
+
+
+  caps_in = gst_caps_new_simple ("application/x-rtp",
+      "encoding-name", G_TYPE_STRING, "TELEPHONE-EVENT",
+      "media", G_TYPE_STRING, "audio",
+      "clock-rate", G_TYPE_INT, 1000, "payload", G_TYPE_INT, 99, NULL);
+  gst_check_setup_events (src, dtmfdepay, caps_in, GST_FORMAT_TIME);
+  gst_caps_unref (caps_in);
+
+  caps_out = gst_pad_get_current_caps (sink);
+  expected_caps_out = gst_caps_new_simple ("audio/x-raw",
+      "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
+      "rate", G_TYPE_INT, 1000, "channels", G_TYPE_INT, 1, NULL);
+  fail_unless (gst_caps_is_equal_fixed (caps_out, expected_caps_out));
+  gst_caps_unref (expected_caps_out);
+  gst_caps_unref (caps_out);
+
+  /* Single packet DTMF */
+  send_rtp_packet (src, 200, TRUE, TRUE, 1, 5, 250);
+  check_get_dtmf_event_message (bus, 1, 5);
+  check_buffers_duration (250 * GST_MSECOND);
+
+  /* Two packet DTMF */
+  send_rtp_packet (src, 800, TRUE, FALSE, 1, 5, 200);
+  send_rtp_packet (src, 800, FALSE, TRUE, 1, 5, 400);
+  check_buffers_duration (400 * GST_MSECOND);
+  check_get_dtmf_event_message (bus, 1, 5);
+
+  /* Long DTMF */
+  send_rtp_packet (src, 3000, TRUE, FALSE, 1, 5, 200);
+  check_get_dtmf_event_message (bus, 1, 5);
+  check_buffers_duration (200 * GST_MSECOND);
+  send_rtp_packet (src, 3000, FALSE, FALSE, 1, 5, 400);
+  check_no_dtmf_event_message (bus);
+  check_buffers_duration (200 * GST_MSECOND);
+  send_rtp_packet (src, 3000, FALSE, FALSE, 1, 5, 600);
+  check_no_dtmf_event_message (bus);
+  check_buffers_duration (200 * GST_MSECOND);
+
+  /* New without end to last */
+  send_rtp_packet (src, 4000, TRUE, TRUE, 1, 5, 250);
+  check_get_dtmf_event_message (bus, 1, 5);
+  check_buffers_duration (250 * GST_MSECOND);
+
+  check_no_dtmf_event_message (bus);
+  fail_unless (buffers == NULL);
+  gst_element_set_bus (dtmfdepay, NULL);
+  gst_object_unref (bus);
+
+  gst_pad_set_active (src, FALSE);
+  gst_pad_set_active (sink, FALSE);
+  gst_check_teardown_sink_pad (dtmfdepay);
+  gst_check_teardown_src_pad (dtmfdepay);
+  gst_check_teardown_element (dtmfdepay);
+}
+
+GST_END_TEST;
+
+
+static GstStaticPadTemplate rtp_dtmf_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) 99, "
+        "clock-rate = (int) 1000, "
+        "seqnum-offset = (uint) 333, "
+        "timestamp-offset = (uint) 666, "
+        "ssrc = (uint) 999, "
+        "maxptime = (uint) 20, encoding-name = (string) \"TELEPHONE-EVENT\"")
+    );
+
+GstElement *dtmfsrc;
+GstPad *sink;
+GstClock *testclock;
+GstBus *bus;
+
+static void
+check_message_structure (GstStructure * expected_s)
+{
+  GstMessage *message;
+  gboolean have_message = FALSE;
+
+  while (!have_message &&
+      (message = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
+              GST_MESSAGE_ELEMENT)) != NULL) {
+    if (gst_message_has_name (message, gst_structure_get_name (expected_s))) {
+      const GstStructure *s = gst_message_get_structure (message);
+
+      fail_unless (gst_structure_is_equal (s, expected_s));
+      have_message = TRUE;
+    }
+    gst_message_unref (message);
+  }
+
+  fail_unless (have_message);
+
+  gst_structure_free (expected_s);
+}
+
+static void
+check_rtp_buffer (GstClockTime ts, GstClockTime duration, gboolean start,
+    gboolean end, guint rtpts, guint ssrc, guint volume, guint number,
+    guint rtpduration)
+{
+  GstBuffer *buffer;
+  GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
+  gchar *payload;
+
+  g_mutex_lock (&check_mutex);
+  while (buffers == NULL)
+    g_cond_wait (&check_cond, &check_mutex);
+  g_mutex_unlock (&check_mutex);
+  fail_unless (buffers != NULL);
+
+  buffer = buffers->data;
+  buffers = g_list_delete_link (buffers, buffers);
+
+  fail_unless (GST_BUFFER_PTS (buffer) == ts);
+  fail_unless (GST_BUFFER_DURATION (buffer) == duration);
+
+  fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtpbuffer));
+  fail_unless (gst_rtp_buffer_get_marker (&rtpbuffer) == start);
+  fail_unless (gst_rtp_buffer_get_timestamp (&rtpbuffer) == rtpts);
+  payload = gst_rtp_buffer_get_payload (&rtpbuffer);
+
+  fail_unless (payload[0] == number);
+  fail_unless ((payload[1] & 0x7F) == volume);
+  fail_unless (! !(payload[1] & 0x80) == end);
+  fail_unless (GST_READ_UINT16_BE (payload + 2) == rtpduration);
+
+  gst_rtp_buffer_unmap (&rtpbuffer);
+  gst_buffer_unref (buffer);
+}
+
+gint method;
+
+static void
+setup_rtpdtmfsrc (void)
+{
+  testclock = gst_test_clock_new ();
+  bus = gst_bus_new ();
+
+  method = 1;
+  dtmfsrc = gst_check_setup_element ("rtpdtmfsrc");
+  sink = gst_check_setup_sink_pad (dtmfsrc, &rtp_dtmf_sink_template);
+  gst_element_set_bus (dtmfsrc, bus);
+  fail_unless (gst_element_set_clock (dtmfsrc, testclock));
+
+  gst_pad_set_active (sink, TRUE);
+  fail_unless (gst_element_set_state (dtmfsrc, GST_STATE_PLAYING) ==
+      GST_STATE_CHANGE_SUCCESS);
+}
+
+static void
+teardown_dtmfsrc (void)
+{
+  gst_object_unref (testclock);
+  gst_pad_set_active (sink, FALSE);
+  gst_element_set_bus (dtmfsrc, NULL);
+  gst_object_unref (bus);
+  gst_check_teardown_sink_pad (dtmfsrc);
+  gst_check_teardown_element (dtmfsrc);
+}
+
+GST_START_TEST (test_dtmfsrc_invalid_events)
+{
+  GstStructure *s;
+
+  /* Missing start */
+  s = gst_structure_new ("dtmf-event",
+      "type", G_TYPE_INT, 1, "number", G_TYPE_INT, 3,
+      "method", G_TYPE_INT, method, "volume", G_TYPE_INT, 8, NULL);
+  fail_unless (gst_pad_push_event (sink,
+          gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, s)) == FALSE);
+
+  /* Missing volume */
+  s = gst_structure_new ("dtmf-event",
+      "type", G_TYPE_INT, 1, "number", G_TYPE_INT, 3,
+      "method", G_TYPE_INT, method, "start", G_TYPE_BOOLEAN, TRUE, NULL);
+  fail_unless (gst_pad_push_event (sink,
+          gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, s)) == FALSE);
+
+  /* Missing number */
+  s = gst_structure_new ("dtmf-event",
+      "type", G_TYPE_INT, 1, "method", G_TYPE_INT, method,
+      "volume", G_TYPE_INT, 8, "start", G_TYPE_BOOLEAN, TRUE, NULL);
+  fail_unless (gst_pad_push_event (sink,
+          gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, s)) == FALSE);
+
+  /* Missing type */
+  s = gst_structure_new ("dtmf-event",
+      "number", G_TYPE_INT, 3, "method", G_TYPE_INT, method,
+      "volume", G_TYPE_INT, 8, "start", G_TYPE_BOOLEAN, TRUE, NULL);
+  fail_unless (gst_pad_push_event (sink,
+          gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, s)) == FALSE);
+
+  /* Stop before start */
+  s = gst_structure_new ("dtmf-event",
+      "type", G_TYPE_INT, 1, "number", G_TYPE_INT, 3,
+      "method", G_TYPE_INT, method, "volume", G_TYPE_INT, 8,
+      "start", G_TYPE_BOOLEAN, FALSE, NULL);
+  fail_unless (gst_pad_push_event (sink,
+          gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, s)) == FALSE);
+
+  gst_element_set_state (dtmfsrc, GST_STATE_NULL);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtpdtmfsrc_min_duration)
+{
+  GstStructure *s;
+  GstClockID id;
+  guint timestamp = 0;
+  GstCaps *expected_caps, *caps;
+
+  /* Minimum duration dtmf */
+
+  s = gst_structure_new ("dtmf-event",
+      "type", G_TYPE_INT, 1, "number", G_TYPE_INT, 3,
+      "method", G_TYPE_INT, 1, "volume", G_TYPE_INT, 8,
+      "start", G_TYPE_BOOLEAN, TRUE, NULL);
+  fail_unless (gst_pad_push_event (sink,
+          gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+              gst_structure_copy (s))));
+  check_no_dtmf_event_message (bus);
+  gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (testclock), NULL);
+  fail_unless (buffers == NULL);
+  id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (testclock));
+  fail_unless (gst_clock_id_get_time (id) == 0);
+  gst_clock_id_unref (id);
+  gst_structure_set_name (s, "dtmf-event-processed");
+  check_message_structure (s);
+
+  s = gst_structure_new ("dtmf-event",
+      "type", G_TYPE_INT, 1, "method", G_TYPE_INT, 1,
+      "start", G_TYPE_BOOLEAN, FALSE, NULL);
+  fail_unless (gst_pad_push_event (sink,
+          gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+              gst_structure_copy (s))));
+
+  check_rtp_buffer (0, 20 * GST_MSECOND, TRUE, FALSE, 666, 999, 8, 3, 20);
+
+  for (timestamp = 20; timestamp < MIN_PULSE_DURATION + 20; timestamp += 20) {
+    gst_test_clock_advance_time (GST_TEST_CLOCK (testclock),
+        20 * GST_MSECOND + 1);
+    gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (testclock), NULL);
+    fail_unless (buffers == NULL);
+    id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (testclock));
+    fail_unless (gst_clock_id_get_time (id) == timestamp * GST_MSECOND);
+    gst_clock_id_unref (id);
+
+    if (timestamp < MIN_PULSE_DURATION) {
+      check_rtp_buffer (timestamp * GST_MSECOND, 20 * GST_MSECOND, FALSE,
+          FALSE, 666, 999, 8, 3, timestamp + 20);
+      check_no_dtmf_event_message (bus);
+    } else {
+      gst_structure_set_name (s, "dtmf-event-processed");
+      check_message_structure (s);
+      check_rtp_buffer (timestamp * GST_MSECOND,
+          (20 + MIN_INTER_DIGIT_INTERVAL) * GST_MSECOND, FALSE, TRUE, 666,
+          999, 8, 3, timestamp + 20);
+    }
+
+    fail_unless (buffers == NULL);
+  }
+
+
+  fail_unless (gst_test_clock_peek_id_count (GST_TEST_CLOCK (testclock)) == 0);
+
+  /* caps check */
+
+  expected_caps = gst_caps_new_simple ("application/x-rtp",
+      "encoding-name", G_TYPE_STRING, "TELEPHONE-EVENT",
+      "media", G_TYPE_STRING, "audio",
+      "clock-rate", G_TYPE_INT, 1000, "payload", G_TYPE_INT, 99,
+      "seqnum-offset", G_TYPE_UINT, 333,
+      "timestamp-offset", G_TYPE_UINT, 666,
+      "ssrc", G_TYPE_UINT, 999, "ptime", G_TYPE_UINT, 20, NULL);
+  caps = gst_pad_get_current_caps (sink);
+  fail_unless (gst_caps_can_intersect (caps, expected_caps));
+  gst_caps_unref (caps);
+  gst_caps_unref (expected_caps);
+
+  gst_element_set_state (dtmfsrc, GST_STATE_NULL);
+
+  check_no_dtmf_event_message (bus);
+}
+
+GST_END_TEST;
+
+static GstStaticPadTemplate audio_dtmfsrc_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) \"" GST_AUDIO_NE (S16) "\", "
+        "rate = (int) 8003, " "channels = (int) 1")
+    );
+static void
+setup_dtmfsrc (void)
+{
+  testclock = gst_test_clock_new ();
+  bus = gst_bus_new ();
+
+  method = 2;
+  dtmfsrc = gst_check_setup_element ("dtmfsrc");
+  sink = gst_check_setup_sink_pad (dtmfsrc, &audio_dtmfsrc_sink_template);
+  gst_element_set_bus (dtmfsrc, bus);
+  fail_unless (gst_element_set_clock (dtmfsrc, testclock));
+
+  gst_pad_set_active (sink, TRUE);
+  fail_unless (gst_element_set_state (dtmfsrc, GST_STATE_PLAYING) ==
+      GST_STATE_CHANGE_SUCCESS);
+}
+
+
+GST_START_TEST (test_dtmfsrc_min_duration)
+{
+  GstStructure *s;
+  GstClockID id;
+  GstClockTime timestamp = 0;
+  GstCaps *expected_caps, *caps;
+  guint interval;
+
+  g_object_get (dtmfsrc, "interval", &interval, NULL);
+  fail_unless (interval == 50);
+
+  /* Minimum duration dtmf */
+  gst_test_clock_set_time (GST_TEST_CLOCK (testclock), 0);
+
+  s = gst_structure_new ("dtmf-event",
+      "type", G_TYPE_INT, 1, "number", G_TYPE_INT, 3,
+      "method", G_TYPE_INT, 2, "volume", G_TYPE_INT, 8,
+      "start", G_TYPE_BOOLEAN, TRUE, NULL);
+  fail_unless (gst_pad_push_event (sink,
+          gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+              gst_structure_copy (s))));
+
+  gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (testclock), NULL);
+  id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (testclock));
+  fail_unless (gst_clock_id_get_time (id) == 0);
+  gst_clock_id_unref (id);
+
+  gst_structure_set_name (s, "dtmf-event-processed");
+  check_message_structure (s);
+
+  s = gst_structure_new ("dtmf-event",
+      "type", G_TYPE_INT, 1, "method", G_TYPE_INT, 2,
+      "start", G_TYPE_BOOLEAN, FALSE, NULL);
+  fail_unless (gst_pad_push_event (sink,
+          gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+              gst_structure_copy (s))));
+
+  for (timestamp = interval * GST_MSECOND;
+      timestamp < (MIN_PULSE_DURATION + MIN_INTER_DIGIT_INTERVAL) *
+      GST_MSECOND; timestamp += GST_MSECOND * interval) {
+    gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (testclock), NULL);
+    gst_test_clock_advance_time (GST_TEST_CLOCK (testclock),
+        interval * GST_MSECOND);
+
+    id = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (testclock));
+    fail_unless (gst_clock_id_get_time (id) == timestamp);
+    gst_clock_id_unref (id);
+  }
+
+  gst_structure_set_name (s, "dtmf-event-processed");
+  check_message_structure (s);
+
+  check_buffers_duration ((MIN_PULSE_DURATION + MIN_INTER_DIGIT_INTERVAL) *
+      GST_MSECOND);
+
+  fail_unless (gst_test_clock_peek_id_count (GST_TEST_CLOCK (testclock)) == 0);
+
+  /* caps check */
+
+  expected_caps = gst_caps_new_simple ("audio/x-raw",
+      "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
+      "rate", G_TYPE_INT, 8003, "channels", G_TYPE_INT, 1, NULL);
+  caps = gst_pad_get_current_caps (sink);
+  fail_unless (gst_caps_can_intersect (caps, expected_caps));
+  gst_caps_unref (caps);
+  gst_caps_unref (expected_caps);
+
+  gst_element_set_state (dtmfsrc, GST_STATE_NULL);
+
+  check_no_dtmf_event_message (bus);
+}
+
+GST_END_TEST;
+
+static Suite *
+dtmf_suite (void)
+{
+  Suite *s = suite_create ("dtmf");
+  TCase *tc;
+
+  tc = tcase_create ("rtpdtmfdepay");
+  tcase_add_test (tc, test_rtpdtmfdepay);
+  suite_add_tcase (s, tc);
+
+  tc = tcase_create ("rtpdtmfsrc");
+  tcase_add_checked_fixture (tc, setup_rtpdtmfsrc, teardown_dtmfsrc);
+  tcase_add_test (tc, test_dtmfsrc_invalid_events);
+  tcase_add_test (tc, test_rtpdtmfsrc_min_duration);
+  suite_add_tcase (s, tc);
+
+  tc = tcase_create ("dtmfsrc");
+  tcase_add_checked_fixture (tc, setup_dtmfsrc, teardown_dtmfsrc);
+  tcase_add_test (tc, test_dtmfsrc_invalid_events);
+  tcase_add_test (tc, test_dtmfsrc_min_duration);
+  suite_add_tcase (s, tc);
+
+  return s;
+}
+
+
+GST_CHECK_MAIN (dtmf);
diff --git a/tests/check/elements/equalizer.c b/tests/check/elements/equalizer.c
new file mode 100644
index 0000000..2869bea
--- /dev/null
+++ b/tests/check/elements/equalizer.c
@@ -0,0 +1,380 @@
+/* GStreamer
+ *
+ * Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * equalizer.c: Unit test for the equalizer element
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/check/gstcheck.h>
+
+#include <math.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *mysrcpad, *mysinkpad;
+
+#define EQUALIZER_CAPS_STRING                     \
+    "audio/x-raw, "                               \
+    "format = (string) "GST_AUDIO_NE (F64) ", "   \
+    "layout = (string) interleaved, "             \
+    "channels = (int) 1, "                        \
+    "rate = (int) 48000"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (F64) ", "
+        "layout = (string) interleaved, "
+        "channels = (int) 1, " "rate = (int) 48000")
+    );
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (F64) ", "
+        "layout = (string) interleaved, "
+        "channels = (int) 1, " "rate = (int) 48000")
+    );
+
+static GstElement *
+setup_equalizer (void)
+{
+  GstElement *equalizer;
+
+  GST_DEBUG ("setup_equalizer");
+  equalizer = gst_check_setup_element ("equalizer-nbands");
+  mysrcpad = gst_check_setup_src_pad (equalizer, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (equalizer, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return equalizer;
+}
+
+static void
+cleanup_equalizer (GstElement * equalizer)
+{
+  GST_DEBUG ("cleanup_equalizer");
+
+  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (equalizer);
+  gst_check_teardown_sink_pad (equalizer);
+  gst_check_teardown_element (equalizer);
+}
+
+GST_START_TEST (test_equalizer_5bands_passthrough)
+{
+  GstElement *equalizer;
+  GstBuffer *inbuffer;
+  GstCaps *caps;
+  gdouble *in, *res;
+  gint i;
+  GstMapInfo map;
+
+  equalizer = setup_equalizer ();
+  g_object_set (G_OBJECT (equalizer), "num-bands", 5, NULL);
+
+  fail_unless_equals_int (gst_child_proxy_get_children_count (GST_CHILD_PROXY
+          (equalizer)), 5);
+
+  fail_unless (gst_element_set_state (equalizer,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i++)
+    in[i] = g_random_double_range (-1.0, 1.0);
+  gst_buffer_unmap (inbuffer, &map);
+
+  caps = gst_caps_from_string (EQUALIZER_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, equalizer, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) == 1);
+
+  gst_buffer_map (GST_BUFFER (buffers->data), &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  for (i = 0; i < 1024; i++)
+    fail_unless_equals_float (in[i], res[i]);
+  gst_buffer_unmap (GST_BUFFER (buffers->data), &map);
+
+  /* cleanup */
+  cleanup_equalizer (equalizer);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_equalizer_5bands_minus_24)
+{
+  GstElement *equalizer;
+  GstBuffer *inbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms_in, rms_out;
+  gint i;
+  GstMapInfo map;
+
+  equalizer = setup_equalizer ();
+  g_object_set (G_OBJECT (equalizer), "num-bands", 5, NULL);
+
+  fail_unless_equals_int (gst_child_proxy_get_children_count (GST_CHILD_PROXY
+          (equalizer)), 5);
+
+  for (i = 0; i < 5; i++) {
+    GObject *band =
+        gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (equalizer), i);
+    fail_unless (band != NULL);
+
+    g_object_set (band, "gain", -24.0, NULL);
+    g_object_unref (band);
+  }
+
+  fail_unless (gst_element_set_state (equalizer,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i++)
+    in[i] = g_random_double_range (-1.0, 1.0);
+  gst_buffer_unmap (inbuffer, &map);
+
+  rms_in = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms_in += in[i] * in[i];
+  rms_in = sqrt (rms_in / 1024);
+
+  caps = gst_caps_from_string (EQUALIZER_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, equalizer, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) == 1);
+
+  gst_buffer_map (GST_BUFFER (buffers->data), &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms_out = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms_out += res[i] * res[i];
+  rms_out = sqrt (rms_out / 1024);
+  gst_buffer_unmap (GST_BUFFER (buffers->data), &map);
+
+  fail_unless (rms_in > rms_out);
+
+  /* cleanup */
+  cleanup_equalizer (equalizer);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_equalizer_5bands_plus_12)
+{
+  GstElement *equalizer;
+  GstBuffer *inbuffer;
+  GstCaps *caps;
+  gdouble *in, *res, rms_in, rms_out;
+  gint i;
+  GstMapInfo map;
+
+  equalizer = setup_equalizer ();
+  g_object_set (G_OBJECT (equalizer), "num-bands", 5, NULL);
+
+  fail_unless_equals_int (gst_child_proxy_get_children_count (GST_CHILD_PROXY
+          (equalizer)), 5);
+
+  for (i = 0; i < 5; i++) {
+    GObject *band =
+        gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (equalizer), i);
+    fail_unless (band != NULL);
+
+    g_object_set (band, "gain", 12.0, NULL);
+    g_object_unref (band);
+  }
+
+  fail_unless (gst_element_set_state (equalizer,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  in = (gdouble *) map.data;
+  for (i = 0; i < 1024; i++)
+    in[i] = g_random_double_range (-1.0, 1.0);
+  gst_buffer_unmap (inbuffer, &map);
+
+  rms_in = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms_in += in[i] * in[i];
+  rms_in = sqrt (rms_in / 1024);
+
+  caps = gst_caps_from_string (EQUALIZER_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, equalizer, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+  /* ... and puts a new buffer on the global list */
+  fail_unless (g_list_length (buffers) == 1);
+
+  gst_buffer_map (GST_BUFFER (buffers->data), &map, GST_MAP_READ);
+  res = (gdouble *) map.data;
+
+  rms_out = 0.0;
+  for (i = 0; i < 1024; i++)
+    rms_out += res[i] * res[i];
+  rms_out = sqrt (rms_out / 1024);
+  gst_buffer_unmap (GST_BUFFER (buffers->data), &map);
+
+  fail_unless (rms_in < rms_out);
+
+  /* cleanup */
+  cleanup_equalizer (equalizer);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_equalizer_band_number_changing)
+{
+  GstElement *equalizer;
+  gint i;
+
+  equalizer = setup_equalizer ();
+
+  g_object_set (G_OBJECT (equalizer), "num-bands", 5, NULL);
+  fail_unless_equals_int (gst_child_proxy_get_children_count (GST_CHILD_PROXY
+          (equalizer)), 5);
+
+  for (i = 0; i < 5; i++) {
+    GObject *band;
+
+    band = gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (equalizer), i);
+    fail_unless (band != NULL);
+    g_object_unref (band);
+  }
+
+  g_object_set (G_OBJECT (equalizer), "num-bands", 10, NULL);
+  fail_unless_equals_int (gst_child_proxy_get_children_count (GST_CHILD_PROXY
+          (equalizer)), 10);
+
+  for (i = 0; i < 10; i++) {
+    GObject *band;
+
+    band = gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (equalizer), i);
+    fail_unless (band != NULL);
+    g_object_unref (band);
+  }
+
+  /* cleanup */
+  cleanup_equalizer (equalizer);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_equalizer_presets)
+{
+  GstElement *eq1, *eq2;
+  gint type;
+  gdouble gain, freq;
+
+  eq1 = gst_check_setup_element ("equalizer-nbands");
+  g_object_set (G_OBJECT (eq1), "num-bands", 3, NULL);
+
+  /* set properties to non-defaults */
+  gst_child_proxy_set ((GstChildProxy *) eq1,
+      "band0::type", 0, "band0::gain", -3.0, "band0::freq", 100.0,
+      "band1::type", 1, "band1::gain", +3.0, "band1::freq", 1000.0,
+      "band2::type", 2, "band2::gain", +9.0, "band2::freq", 10000.0, NULL);
+
+  /* save preset */
+  gst_preset_save_preset ((GstPreset *) eq1, "_testpreset_");
+  GST_INFO_OBJECT (eq1, "Preset saved");
+
+  eq2 = gst_check_setup_element ("equalizer-nbands");
+  g_object_set (G_OBJECT (eq2), "num-bands", 3, NULL);
+
+  /* load preset */
+  gst_preset_load_preset ((GstPreset *) eq2, "_testpreset_");
+  GST_INFO_OBJECT (eq1, "Preset loaded");
+
+  /* compare properties */
+  gst_child_proxy_get ((GstChildProxy *) eq2,
+      "band0::type", &type, "band0::gain", &gain, "band0::freq", &freq, NULL);
+  ck_assert_int_eq (type, 0);
+  fail_unless (gain == -3.0, NULL);
+  fail_unless (freq == 100.0, NULL);
+  gst_child_proxy_get ((GstChildProxy *) eq2,
+      "band1::type", &type, "band1::gain", &gain, "band1::freq", &freq, NULL);
+  ck_assert_int_eq (type, 1);
+  fail_unless (gain == +3.0, NULL);
+  fail_unless (freq == 1000.0, NULL);
+  gst_child_proxy_get ((GstChildProxy *) eq2,
+      "band2::type", &type, "band2::gain", &gain, "band2::freq", &freq, NULL);
+  ck_assert_int_eq (type, 2);
+  fail_unless (gain == +9.0, NULL);
+  fail_unless (freq == 10000.0, NULL);
+
+  gst_preset_delete_preset ((GstPreset *) eq1, "_testpreset_");
+  gst_check_teardown_element (eq1);
+  gst_check_teardown_element (eq2);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+equalizer_suite (void)
+{
+  Suite *s = suite_create ("equalizer");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_equalizer_5bands_passthrough);
+  tcase_add_test (tc_chain, test_equalizer_5bands_minus_24);
+  tcase_add_test (tc_chain, test_equalizer_5bands_plus_12);
+  tcase_add_test (tc_chain, test_equalizer_band_number_changing);
+  tcase_add_test (tc_chain, test_equalizer_presets);
+
+  return s;
+}
+
+GST_CHECK_MAIN (equalizer);
diff --git a/tests/check/elements/flacparse.c b/tests/check/elements/flacparse.c
new file mode 100644
index 0000000..86b6c2b
--- /dev/null
+++ b/tests/check/elements/flacparse.c
@@ -0,0 +1,285 @@
+/*
+ * GStreamer
+ *
+ * unit test for flacparse
+ *
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include "parser.h"
+
+#define SRC_CAPS_TMPL  "audio/x-flac, framed=(boolean)false"
+#define SINK_CAPS_TMPL  "audio/x-flac, framed=(boolean)true"
+
+GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SINK_CAPS_TMPL)
+    );
+
+GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SRC_CAPS_TMPL)
+    );
+
+/* some data */
+static guint8 streaminfo_header[] = {
+  0x7f, 0x46, 0x4c, 0x41, 0x43, 0x01, 0x00, 0x00,
+  0x02, 0x66, 0x4c, 0x61, 0x43, 0x00, 0x00, 0x00,
+  0x22, 0x12, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0a, 0xc4, 0x40, 0xf0, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00
+};
+
+static guint8 comment_header[] = {
+  0x84, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00
+};
+
+static guint8 flac_frame[] = {
+  0xff, 0xf8, 0xa9, 0x08, 0x00, 0x50, 0x18, 0x06,
+  0x6a, 0x0c, 0xce, 0x13, 0x24, 0x19, 0x68, 0x00,
+  0x46, 0x23, 0x08, 0xca, 0xcb, 0x58, 0x9c, 0x26,
+  0x92, 0x30, 0xa6, 0x29, 0x8a, 0xca, 0xd1, 0x18,
+  0xae, 0x26, 0x5c, 0x90, 0x60, 0xbf, 0x11, 0xad,
+  0x43, 0x02, 0x06, 0x26, 0xbd, 0x35, 0xdd, 0xa3,
+  0x11, 0xa6, 0x4d, 0x18, 0x8c, 0x9a, 0xe4, 0x62,
+  0xd9, 0x23, 0x11, 0x8b, 0xcb, 0x56, 0x55, 0x45,
+  0xc2, 0x18, 0x56, 0xa2, 0xe2, 0xe1, 0x18, 0x99,
+  0x54, 0x98, 0x46, 0x4d, 0x08, 0x70, 0x9a, 0x64,
+  0xc4, 0x18, 0x4f, 0x27, 0x64, 0x31, 0x66, 0x27,
+  0x79, 0x19, 0x3c, 0x8c, 0x8c, 0xa3, 0x44, 0x18,
+  0x23, 0xd2, 0x6b, 0x8b, 0x64, 0x8c, 0x21, 0x84,
+  0xd6, 0x23, 0x13, 0x13, 0x2d, 0x44, 0xca, 0x5a,
+  0x23, 0x09, 0x93, 0x25, 0x18, 0x10, 0x61, 0x38,
+  0xb4, 0x60, 0x8f, 0x2c, 0x8d, 0x26, 0xb4, 0xc9,
+  0xd9, 0x19, 0x19, 0x34, 0xd7, 0x31, 0x06, 0x10,
+  0xc4, 0x30, 0x83, 0x17, 0xe2, 0x0c, 0x2c, 0xc4,
+  0xc8, 0xc9, 0x3c, 0x5e, 0x93, 0x11, 0x8a, 0x62,
+  0x64, 0x8c, 0x26, 0x23, 0x22, 0x30, 0x9a, 0x58,
+  0x86, 0x04, 0x18, 0x4c, 0xab, 0x2b, 0x26, 0x5c,
+  0x46, 0x88, 0xcb, 0xb1, 0x0d, 0x26, 0xbb, 0x5e,
+  0x8c, 0xa7, 0x64, 0x31, 0x3d, 0x31, 0x06, 0x26,
+  0x43, 0x17, 0xa3, 0x08, 0x61, 0x06, 0x17, 0xc4,
+  0x62, 0xec, 0x4d, 0x4b, 0x2e, 0x2d, 0x4a, 0x94,
+  0xa4, 0xc2, 0x31, 0x4c, 0x4c, 0x20, 0xc0, 0x83,
+  0x14, 0x8c, 0x27, 0x8b, 0x31, 0x23, 0x2f, 0x23,
+  0x11, 0x91, 0x94, 0x65, 0x1a, 0x20, 0xc2, 0x18,
+  0x86, 0x51, 0x88, 0x62, 0x7c, 0x43, 0x2e, 0xa3,
+  0x04, 0x18, 0x8c, 0x20, 0xc2, 0xf5, 0xaa, 0x94,
+  0xc2, 0x31, 0x32, 0xd2, 0xb2, 0xa2, 0x30, 0xba,
+  0x10, 0xc2, 0xb5, 0x89, 0xa5, 0x18, 0x10, 0x62,
+  0x9a, 0x10, 0x61, 0x19, 0x72, 0x71, 0x1a, 0xb9,
+  0x0c, 0x23, 0x46, 0x10, 0x62, 0x78, 0x81, 0x82,
+  0x3d, 0x75, 0xea, 0x6b, 0x51, 0x8b, 0x61, 0x06,
+  0x08, 0x62, 0x32, 0x5e, 0x84, 0x18, 0x27, 0x25,
+  0xc2, 0x6a, 0x4b, 0x51, 0x31, 0x34, 0x5e, 0x29,
+  0xa1, 0x3c, 0x4d, 0x26, 0x23, 0x10, 0xc2, 0x6b,
+  0xb1, 0x0d, 0x11, 0xae, 0x46, 0x88, 0x31, 0x35,
+  0xb1, 0x06, 0x08, 0x79, 0x7e, 0x4f, 0x53, 0x23,
+  0x29, 0xa4, 0x30, 0x20, 0x30, 0x23, 0x5a, 0xb2,
+  0xc8, 0x60, 0x9c, 0x93, 0x13, 0x17, 0x92, 0x98,
+  0x46, 0x13, 0x54, 0x53, 0x08, 0xcb, 0x13, 0xa1,
+  0x1a, 0x89, 0xe5, 0x46, 0x08, 0x18, 0x10, 0x30,
+  0x9d, 0x68, 0xc2, 0x1c, 0x46, 0x46, 0xae, 0x62,
+  0x1a, 0x46, 0x4e, 0x4d, 0x34, 0x8c, 0xbd, 0x26,
+  0xc0, 0x40, 0x62, 0xc9, 0xa9, 0x31, 0x74, 0xa8,
+  0x99, 0x52, 0xb0, 0x8c, 0xa9, 0x29, 0x84, 0x61,
+  0x19, 0x54, 0x43, 0x02, 0x06, 0x04, 0x32, 0xe5,
+  0x18, 0x21, 0x91, 0x8b, 0xf2, 0xcc, 0x10, 0x30,
+  0x8e, 0x23, 0xc4, 0x76, 0x43, 0x08, 0x30, 0x83,
+  0x08, 0x62, 0x6c, 0x4e, 0xe2, 0x35, 0x96, 0xd0,
+  0x8e, 0x89, 0x97, 0x42, 0x18, 0x91, 0x84, 0x61,
+  0x3c, 0x26, 0xa5, 0x2c, 0x4e, 0x17, 0x94, 0xb8,
+  0xb5, 0xa4, 0xcb, 0x88, 0xc9, 0x84, 0x18, 0xb9,
+  0x84, 0x19, 0x23, 0x2d, 0xa4, 0x64, 0x62, 0x18,
+  0x86, 0x53, 0x93, 0xcb, 0x30, 0x8f, 0x2f, 0x93,
+  0x55, 0xc4, 0xd7, 0x08, 0x62, 0xb8, 0x46, 0x84,
+  0x68, 0xa3, 0x02, 0xaf, 0x33
+};
+
+static guint8 garbage_frame[] = {
+  0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+
+GST_START_TEST (test_parse_flac_normal)
+{
+  gst_parser_test_normal (flac_frame, sizeof (flac_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_flac_drain_single)
+{
+  gst_parser_test_drain_single (flac_frame, sizeof (flac_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_flac_drain_garbage)
+{
+  /* We always output the after frame garbage too because we
+   * have no way of detecting it
+   */
+#if 0
+  gst_parser_test_drain_garbage (flac_frame, sizeof (flac_frame),
+      garbage_frame, sizeof (garbage_frame));
+#endif
+  guint8 frame[sizeof (flac_frame) + sizeof (garbage_frame)];
+
+  memcpy (frame, flac_frame, sizeof (flac_frame));
+  memcpy (frame + sizeof (flac_frame), garbage_frame, sizeof (garbage_frame));
+
+  gst_parser_test_drain_single (frame, sizeof (frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_flac_split)
+{
+  gst_parser_test_split (flac_frame, sizeof (flac_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_flac_skip_garbage)
+{
+  /* We always include the garbage into the frame because
+   * we have no easy way for finding the real end of the
+   * frame. The decoder will later skip the garbage
+   */
+#if 0
+  gst_parser_test_skip_garbage (flac_frame, sizeof (flac_frame),
+      garbage_frame, sizeof (garbage_frame));
+#endif
+  guint8 frame[sizeof (flac_frame) + sizeof (garbage_frame)];
+
+  memcpy (frame, flac_frame, sizeof (flac_frame));
+  memcpy (frame + sizeof (flac_frame), garbage_frame, sizeof (garbage_frame));
+
+  gst_parser_test_normal (frame, sizeof (frame));
+}
+
+GST_END_TEST;
+
+
+#define structure_get_int(s,f) \
+    (g_value_get_int(gst_structure_get_value(s,f)))
+#define fail_unless_structure_field_int_equals(s,field,num) \
+    fail_unless_equals_int (structure_get_int(s,field), num)
+/*
+ * Test if the parser handles raw stream and codec_data info properly.
+ */
+GST_START_TEST (test_parse_flac_detect_stream)
+{
+  GstCaps *caps;
+  GstStructure *s;
+  const GValue *streamheader;
+  GArray *bufarr;
+  gint i;
+
+  /* Push random data. It should get through since the parser should be
+   * initialized because it got codec_data in the caps */
+  caps = gst_parser_test_get_output_caps (flac_frame, sizeof (flac_frame),
+      SRC_CAPS_TMPL);
+  fail_unless (caps != NULL);
+
+  /* Check that the negotiated caps are as expected */
+  /* When codec_data is present, parser assumes that data is version 4 */
+  GST_LOG ("flac output caps: %" GST_PTR_FORMAT, caps);
+  s = gst_caps_get_structure (caps, 0);
+  fail_unless (gst_structure_has_name (s, "audio/x-flac"));
+  fail_unless_structure_field_int_equals (s, "channels", 1);
+  fail_unless_structure_field_int_equals (s, "rate", 44100);
+  fail_unless (gst_structure_has_field (s, "streamheader"));
+  streamheader = gst_structure_get_value (s, "streamheader");
+  fail_unless (G_VALUE_TYPE (streamheader) == GST_TYPE_ARRAY);
+  bufarr = g_value_peek_pointer (streamheader);
+  fail_unless (bufarr->len == 2);
+  for (i = 0; i < bufarr->len; i++) {
+    GstBuffer *buf;
+    GValue *bufval = &g_array_index (bufarr, GValue, i);
+
+    fail_unless (G_VALUE_TYPE (bufval) == GST_TYPE_BUFFER);
+    buf = g_value_peek_pointer (bufval);
+    if (i == 0) {
+      fail_unless (gst_buffer_get_size (buf) == sizeof (streaminfo_header));
+      fail_unless (gst_buffer_memcmp (buf, 0, streaminfo_header,
+              sizeof (streaminfo_header)) == 0);
+    } else if (i == 1) {
+      fail_unless (gst_buffer_get_size (buf) == sizeof (comment_header));
+      fail_unless (gst_buffer_memcmp (buf, 0, comment_header,
+              sizeof (comment_header)) == 0);
+    }
+  }
+
+  gst_caps_unref (caps);
+}
+
+GST_END_TEST;
+
+static Suite *
+flacparse_suite (void)
+{
+  Suite *s = suite_create ("flacparse");
+  TCase *tc_chain = tcase_create ("general");
+
+
+  /* init test context */
+  ctx_factory = "flacparse";
+  ctx_sink_template = &sinktemplate;
+  ctx_src_template = &srctemplate;
+  ctx_discard = 3;
+  ctx_headers[0].data = streaminfo_header;
+  ctx_headers[0].size = sizeof (streaminfo_header);
+  ctx_headers[1].data = comment_header;
+  ctx_headers[1].size = sizeof (comment_header);
+
+  /* custom offsets, and ts always repeatedly 0 */
+  ctx_no_metadata = TRUE;
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_parse_flac_normal);
+  tcase_add_test (tc_chain, test_parse_flac_drain_single);
+  tcase_add_test (tc_chain, test_parse_flac_drain_garbage);
+  tcase_add_test (tc_chain, test_parse_flac_split);
+  tcase_add_test (tc_chain, test_parse_flac_skip_garbage);
+
+  /* Other tests */
+  tcase_add_test (tc_chain, test_parse_flac_detect_stream);
+
+  return s;
+}
+
+
+/*
+ * TODO:
+ *   - Both push- and pull-modes need to be tested
+ *      * Pull-mode & EOS
+ */
+GST_CHECK_MAIN (flacparse);
diff --git a/tests/check/elements/flvdemux.c b/tests/check/elements/flvdemux.c
new file mode 100644
index 0000000..b8955bf
--- /dev/null
+++ b/tests/check/elements/flvdemux.c
@@ -0,0 +1,544 @@
+/* GStreamer unit tests for flvdemux
+ *
+ * Copyright (C) 2009 Tim-Philipp Müller  <tim centricular net>
+ * Copyright (C) 2016 Havard Graff        <havard@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/check/gstharness.h>
+
+#include <gst/gst.h>
+#include <gst/tag/tag.h>
+
+static void
+pad_added_cb (GstElement * flvdemux, GstPad * pad, GstBin * pipeline)
+{
+  GstElement *sink;
+
+  sink = gst_bin_get_by_name (pipeline, "fakesink");
+  fail_unless (gst_element_link (flvdemux, sink));
+  gst_object_unref (sink);
+
+  gst_element_set_state (sink, GST_STATE_PAUSED);
+}
+
+static GstBusSyncReply
+error_cb (GstBus * bus, GstMessage * msg, gpointer user_data)
+{
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
+    const gchar *file = (const gchar *) user_data;
+    GError *err = NULL;
+    gchar *dbg = NULL;
+
+    gst_message_parse_error (msg, &err, &dbg);
+    g_error ("ERROR for %s: %s\n%s\n", file, err->message, dbg);
+  }
+
+  return GST_BUS_PASS;
+}
+
+static void
+handoff_cb (GstElement * element, GstBuffer * buf, GstPad * pad,
+    gint * p_counter)
+{
+  *p_counter += 1;
+  GST_LOG ("counter = %d", *p_counter);
+}
+
+static void
+process_file (const gchar * file, gboolean push_mode, gint repeat,
+    gint num_buffers)
+{
+  GstElement *src, *sep, *sink, *flvdemux, *pipeline;
+  GstBus *bus;
+  gchar *path;
+  gint counter;
+
+  pipeline = gst_pipeline_new ("pipeline");
+  fail_unless (pipeline != NULL, "Failed to create pipeline!");
+
+  bus = gst_element_get_bus (pipeline);
+
+  /* kids, don't use a sync handler for this at home, really; we do because
+   * we just want to abort and nothing else */
+  gst_bus_set_sync_handler (bus, error_cb, (gpointer) file, NULL);
+
+  src = gst_element_factory_make ("filesrc", "filesrc");
+  fail_unless (src != NULL, "Failed to create 'filesrc' element!");
+
+  if (push_mode) {
+    sep = gst_element_factory_make ("queue", "queue");
+    fail_unless (sep != NULL, "Failed to create 'queue' element");
+  } else {
+    sep = gst_element_factory_make ("identity", "identity");
+    fail_unless (sep != NULL, "Failed to create 'identity' element");
+  }
+
+  flvdemux = gst_element_factory_make ("flvdemux", "flvdemux");
+  fail_unless (flvdemux != NULL, "Failed to create 'flvdemux' element!");
+
+  sink = gst_element_factory_make ("fakesink", "fakesink");
+  fail_unless (sink != NULL, "Failed to create 'fakesink' element!");
+
+  g_object_set (sink, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (sink, "handoff", G_CALLBACK (handoff_cb), &counter);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, sep, flvdemux, sink, NULL);
+
+  fail_unless (gst_element_link (src, sep));
+  fail_unless (gst_element_link (sep, flvdemux));
+
+  /* can't link flvdemux and sink yet, do that later */
+  g_signal_connect (flvdemux, "pad-added", G_CALLBACK (pad_added_cb), pipeline);
+
+  path = g_build_filename (GST_TEST_FILES_PATH, file, NULL);
+  GST_LOG ("processing file '%s'", path);
+  g_object_set (src, "location", path, NULL);
+
+  do {
+    GstStateChangeReturn state_ret;
+    GstMessage *msg;
+
+    GST_LOG ("repeat=%d", repeat);
+
+    counter = 0;
+
+    state_ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
+    fail_unless (state_ret != GST_STATE_CHANGE_FAILURE);
+
+    if (state_ret == GST_STATE_CHANGE_ASYNC) {
+      GST_LOG ("waiting for pipeline to reach PAUSED state");
+      state_ret = gst_element_get_state (pipeline, NULL, NULL, -1);
+      fail_unless_equals_int (state_ret, GST_STATE_CHANGE_SUCCESS);
+    }
+
+    GST_LOG ("PAUSED, let's read all of it");
+
+    state_ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
+    fail_unless (state_ret != GST_STATE_CHANGE_FAILURE);
+
+    msg = gst_bus_poll (bus, GST_MESSAGE_EOS, -1);
+    fail_unless (msg != NULL, "Expected EOS message on bus! (%s)", file);
+
+    gst_message_unref (msg);
+
+    if (num_buffers >= 0) {
+      fail_unless_equals_int (counter, num_buffers);
+    }
+
+    fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
+        GST_STATE_CHANGE_SUCCESS);
+
+    --repeat;
+  } while (repeat > 0);
+
+  gst_object_unref (bus);
+  gst_object_unref (pipeline);
+
+  g_free (path);
+}
+
+GST_START_TEST (test_reuse_pull)
+{
+  process_file ("pcm16sine.flv", FALSE, 3, 129);
+  gst_task_cleanup_all ();
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_reuse_push)
+{
+  process_file ("pcm16sine.flv", TRUE, 3, 129);
+  gst_task_cleanup_all ();
+}
+
+GST_END_TEST;
+
+static GstBuffer *
+create_buffer (guint8 * data, gsize size)
+{
+  GstBuffer *buf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+      data, size, 0, size, NULL, NULL);
+  GST_BUFFER_PTS (buf) = GST_CLOCK_TIME_NONE;
+  GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
+  GST_BUFFER_DURATION (buf) = GST_CLOCK_TIME_NONE;
+  GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
+  GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
+  return buf;
+}
+
+static void
+flvdemux_pad_added (GstElement * flvdemux, GstPad * srcpad, GstHarness * h)
+{
+  GstCaps *caps;
+  (void) flvdemux;
+
+  caps = gst_pad_get_current_caps (srcpad);
+  fail_unless (caps != NULL);
+  gst_caps_unref (caps);
+  gst_harness_add_element_src_pad (h, srcpad);
+}
+
+GST_START_TEST (test_speex)
+{
+  guint8 flv_header0[] = {
+    0x46, 0x4c, 0x56, 0x01, 0x04, 0x00, 0x00, 0x00,
+    0x09, 0x00, 0x00, 0x00, 0x00
+  };
+
+  guint8 flv_header1[] = {
+    0x12, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x02, 0x00, 0x0a, 0x6f, 0x6e,
+    0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61,
+    0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x61,
+    0x75, 0x64, 0x69, 0x6f, 0x63, 0x6f, 0x64, 0x65,
+    0x63, 0x69, 0x64, 0x00, 0x40, 0x26, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x6d, 0x65,
+    0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x63, 0x72,
+    0x65, 0x61, 0x74, 0x6f, 0x72, 0x02, 0x00, 0x13,
+    0x47, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65,
+    0x72, 0x20, 0x46, 0x4c, 0x56, 0x20, 0x6d, 0x75,
+    0x78, 0x65, 0x72, 0x00, 0x0c, 0x63, 0x72, 0x65,
+    0x61, 0x74, 0x69, 0x6f, 0x6e, 0x64, 0x61, 0x74,
+    0x65, 0x02, 0x00, 0x18, 0x57, 0x65, 0x64, 0x20,
+    0x53, 0x65, 0x70, 0x20, 0x32, 0x33, 0x20, 0x31,
+    0x30, 0x3a, 0x34, 0x39, 0x3a, 0x35, 0x36, 0x20,
+    0x32, 0x30, 0x31, 0x35, 0x00, 0x00, 0x09, 0x00,
+    0x00, 0x00, 0x87,
+  };
+
+  guint8 speex_header0[] = {
+    0x08, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xb2, 0x53, 0x70, 0x65, 0x65,
+    0x78, 0x20, 0x20, 0x20, 0x31, 0x2e, 0x32, 0x72,
+    0x63, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+    0x80, 0x3e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0xff, 0xff, 0xff, 0xff, 0x40, 0x01, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c,
+  };
+
+  guint8 speex_header1[] = {
+    0x08, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xb2, 0x1f, 0x00, 0x00, 0x00,
+    0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20,
+    0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x53, 0x74,
+    0x72, 0x65, 0x61, 0x6d, 0x65, 0x72, 0x20, 0x53,
+    0x70, 0x65, 0x65, 0x78, 0x65, 0x6e, 0x63, 0x00,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x34,
+  };
+
+  guint8 buffer[] = {
+    0x08, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xb2, 0x36, 0x9d, 0x1b, 0x9a,
+    0x20, 0x00, 0x01, 0x68, 0xe8, 0xe8, 0xe8, 0xe8,
+    0xe8, 0xe8, 0xe8, 0x84, 0x00, 0xb4, 0x74, 0x74,
+    0x74, 0x74, 0x74, 0x74, 0x74, 0x42, 0x00, 0x5a,
+    0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x21,
+    0x00, 0x2d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+    0x1d, 0x1b, 0x3b, 0x60, 0xab, 0xab, 0xab, 0xab,
+    0xab, 0x0a, 0xba, 0xba, 0xba, 0xba, 0xb0, 0xab,
+    0xab, 0xab, 0xab, 0xab, 0x0a, 0xba, 0xba, 0xba,
+    0xba, 0xb7, 0x00, 0x00, 0x00, 0x52,
+  };
+
+  GstHarness *h = gst_harness_new_with_padnames ("flvdemux", "sink", NULL);
+  gst_harness_set_src_caps_str (h, "video/x-flv");
+
+  g_signal_connect (h->element, "pad-added",
+      G_CALLBACK (flvdemux_pad_added), h);
+
+  gst_harness_push (h, create_buffer (flv_header0, sizeof (flv_header0)));
+  gst_harness_push (h, create_buffer (flv_header1, sizeof (flv_header1)));
+  gst_harness_push (h, create_buffer (speex_header0, sizeof (speex_header0)));
+  gst_harness_push (h, create_buffer (speex_header1, sizeof (speex_header1)));
+  gst_harness_push (h, create_buffer (buffer, sizeof (buffer)));
+
+  {
+    GstCaps *caps;
+    const GstStructure *s;
+    const GValue *streamheader;
+    const GValue *header;
+    const GValue *vorbiscomment;
+    GstBuffer *buf;
+    GstTagList *list;
+    gint rate;
+    gint channels;
+
+    caps = gst_pad_get_current_caps (h->sinkpad);
+    s = gst_caps_get_structure (caps, 0);
+
+    fail_unless (gst_structure_has_name (s, "audio/x-speex"));
+
+    streamheader = gst_structure_get_value (s, "streamheader");
+    fail_unless (streamheader != NULL);
+    fail_unless (G_VALUE_HOLDS (streamheader, GST_TYPE_ARRAY));
+    fail_unless_equals_int (2, gst_value_array_get_size (streamheader));
+
+    header = gst_value_array_get_value (streamheader, 0);
+    fail_unless (header != NULL);
+    fail_unless (G_VALUE_HOLDS (header, GST_TYPE_BUFFER));
+    buf = gst_value_get_buffer (header);
+
+    vorbiscomment = gst_value_array_get_value (streamheader, 1);
+    fail_unless (header != NULL);
+    fail_unless (G_VALUE_HOLDS (header, GST_TYPE_BUFFER));
+    buf = gst_value_get_buffer (vorbiscomment);
+    list = gst_tag_list_from_vorbiscomment_buffer (buf, NULL, 0, NULL);
+    fail_unless (list != NULL);
+    gst_tag_list_unref (list);
+
+    gst_structure_get_int (s, "rate", &rate);
+    fail_unless_equals_int (16000, rate);
+
+    gst_structure_get_int (s, "channels", &channels);
+    fail_unless_equals_int (1, channels);
+
+    gst_caps_unref (caps);
+  }
+
+  /* we should have gotten 2x speex-headers, and one encoded buffer */
+  fail_unless_equals_int (3, gst_harness_buffers_in_queue (h));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_aac)
+{
+  guint8 flv_header[] = {
+    0x46, 0x4c, 0x56, 0x01, 0x04, 0x00, 0x00, 0x00,
+    0x09, 0x00, 0x00, 0x00, 0x00,
+    0x12, 0x00, 0x00, 0x2d,     /* script tag */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+    0x00, 0x0a, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61,
+    0x44, 0x61, 0x74, 0x61, 0x03, 0x00, 0x06, 0x53,
+    0x65, 0x72, 0x76, 0x65, 0x72, 0x02, 0x00, 0x11,
+    0x50, 0x65, 0x78, 0x69, 0x70, 0x20, 0x52, 0x54,
+    0x4d, 0x50, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65,
+    0x72, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x38,
+  };
+
+  guint8 aac_header[] = {
+    0x08, 0x00, 0x00, 0x04,     /* audio tag */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf,
+    0x00, 0x13, 0x10, 0x00, 0x00, 0x00, 0x0f,
+  };
+
+  guint8 aac_buffer[] = {
+    0x08, 0x00, 0x01, 0x57,     /* audio tag */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf,
+    0x01, 0x21, 0x21, 0x45, 0x00, 0x14, 0x50, 0x01,
+    0x46, 0xf0, 0x4d, 0xfb, 0x01, 0x3c, 0x08, 0x40,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x07, 0x0e, 0x00, 0x0d, 0xff, 0xe2, 0x14,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+    0xb4, 0xb4, 0xb4, 0xbb, 0xc6, 0x84, 0x29, 0x69,
+    0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+    0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+    0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+    0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+    0x69, 0x69, 0x69, 0x69, 0x69, 0x78, 0x00, 0x00,
+    0x01, 0x62
+  };
+
+  GstHarness *h = gst_harness_new_with_padnames ("flvdemux", "sink", NULL);
+  gst_harness_set_src_caps_str (h, "video/x-flv");
+
+  g_signal_connect (h->element, "pad-added",
+      G_CALLBACK (flvdemux_pad_added), h);
+
+  gst_harness_push (h, create_buffer (flv_header, sizeof (flv_header)));
+  gst_harness_push (h, create_buffer (aac_header, sizeof (aac_header)));
+  gst_harness_push (h, create_buffer (aac_buffer, sizeof (aac_buffer)));
+
+  {
+    GstCaps *caps;
+    const GstStructure *s;
+    gint mpegversion;
+    gboolean framed;
+    const gchar *stream_format;
+    gint rate;
+    gint channels;
+    const GValue *codec_data;
+
+    caps = gst_pad_get_current_caps (h->sinkpad);
+    s = gst_caps_get_structure (caps, 0);
+
+    fail_unless (gst_structure_has_name (s, "audio/mpeg"));
+
+    gst_structure_get_int (s, "mpegversion", &mpegversion);
+    fail_unless_equals_int (4, mpegversion);
+
+    gst_structure_get_boolean (s, "framed", &framed);
+    fail_unless (framed == TRUE);
+
+    stream_format = gst_structure_get_string (s, "stream-format");
+    fail_unless_equals_string ("raw", stream_format);
+
+    gst_structure_get_int (s, "rate", &rate);
+    fail_unless_equals_int (24000, rate);
+
+    gst_structure_get_int (s, "channels", &channels);
+    fail_unless_equals_int (2, channels);
+
+    codec_data = gst_structure_get_value (s, "codec_data");
+    fail_unless (codec_data != NULL);
+    fail_unless (G_VALUE_HOLDS (codec_data, GST_TYPE_BUFFER));
+
+    gst_caps_unref (caps);
+  }
+
+  /* we should have gotten one encoded buffer */
+  fail_unless_equals_int (1, gst_harness_buffers_in_queue (h));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_h264)
+{
+  guint8 flv_header[] = {
+    0x46, 0x4c, 0x56, 0x01, 0x01, 0x00, 0x00, 0x00,
+    0x09, 0x00, 0x00, 0x00, 0x00,
+    0x12, 0x00, 0x00, 0x2d,     /* script tag */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+    0x00, 0x0a, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61,
+    0x44, 0x61, 0x74, 0x61, 0x03, 0x00, 0x06, 0x53,
+    0x65, 0x72, 0x76, 0x65, 0x72, 0x02, 0x00, 0x11,
+    0x50, 0x65, 0x78, 0x69, 0x70, 0x20, 0x52, 0x54,
+    0x4d, 0x50, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65,
+    0x72, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x38,
+  };
+
+  guint8 h264_packet0[] = {
+    0x09, 0x00, 0x00, 0x1e,     /* video tag */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17,
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x42, 0xc0, 0x1e,
+    0xff, 0xe1, 0x00, 0x0a, 0x67, 0x42, 0xc0, 0x1e,
+    0x95, 0xa0, 0x28, 0x0b, 0xde, 0x54, 0x01, 0x00,
+    0x04, 0x68, 0xce, 0x3c, 0x80, 0x00, 0x00, 0x00,
+    0x29
+  };
+
+  guint8 h264_packet1[] = {
+    0x09, 0x00, 0x00, 0x1b,     /* video tag */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
+    0x67, 0x42, 0xc0, 0x1e, 0x95, 0xa0, 0x28, 0x0b,
+    0xde, 0x54, 0x00, 0x00, 0x00, 0x04, 0x68, 0xce,
+    0x3c, 0x80, 0x00, 0x00, 0x00, 0x26
+  };
+
+  GstHarness *h = gst_harness_new_with_padnames ("flvdemux", "sink", NULL);
+  gst_harness_set_src_caps_str (h, "video/x-flv");
+
+  g_signal_connect (h->element, "pad-added",
+      G_CALLBACK (flvdemux_pad_added), h);
+
+  gst_harness_push (h, create_buffer (flv_header, sizeof (flv_header)));
+  gst_harness_push (h, create_buffer (h264_packet0, sizeof (h264_packet0)));
+  gst_harness_push (h, create_buffer (h264_packet1, sizeof (h264_packet1)));
+
+  {
+    GstCaps *caps;
+    const GstStructure *s;
+    const gchar *stream_format;
+    const GValue *codec_data;
+
+    caps = gst_pad_get_current_caps (h->sinkpad);
+    s = gst_caps_get_structure (caps, 0);
+
+    fail_unless (gst_structure_has_name (s, "video/x-h264"));
+
+    stream_format = gst_structure_get_string (s, "stream-format");
+    fail_unless_equals_string ("avc", stream_format);
+
+    codec_data = gst_structure_get_value (s, "codec_data");
+    fail_unless (codec_data != NULL);
+    fail_unless (G_VALUE_HOLDS (codec_data, GST_TYPE_BUFFER));
+
+    gst_caps_unref (caps);
+  }
+
+  /* we should have gotten one encoded buffer */
+  fail_unless_equals_int (1, gst_harness_buffers_in_queue (h));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+flvdemux_suite (void)
+{
+  Suite *s = suite_create ("flvdemux");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_reuse_push);
+  tcase_add_test (tc_chain, test_reuse_pull);
+
+  tcase_add_test (tc_chain, test_speex);
+  tcase_add_test (tc_chain, test_aac);
+  tcase_add_test (tc_chain, test_h264);
+
+  return s;
+}
+
+GST_CHECK_MAIN (flvdemux)
diff --git a/tests/check/elements/flvmux.c b/tests/check/elements/flvmux.c
new file mode 100644
index 0000000..0cf9b99
--- /dev/null
+++ b/tests/check/elements/flvmux.c
@@ -0,0 +1,448 @@
+/* GStreamer unit tests for flvmux
+ *
+ * Copyright (C) 2009 Tim-Philipp Müller  <tim centricular net>
+ * Copyright (C) 2016 Havard Graff <havard@pexip.com>
+ * Copyright (C) 2016 David Buchmann <david@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_VALGRIND
+# include <valgrind/valgrind.h>
+#endif
+
+#include <gst/check/gstcheck.h>
+#include <gst/check/gstharness.h>
+
+#include <gst/gst.h>
+
+static GstBusSyncReply
+error_cb (GstBus * bus, GstMessage * msg, gpointer user_data)
+{
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
+    GError *err = NULL;
+    gchar *dbg = NULL;
+
+    gst_message_parse_error (msg, &err, &dbg);
+    g_error ("ERROR: %s\n%s\n", err->message, dbg);
+  }
+
+  return GST_BUS_PASS;
+}
+
+static void
+handoff_cb (GstElement * element, GstBuffer * buf, GstPad * pad,
+    gint * p_counter)
+{
+  *p_counter += 1;
+  GST_LOG ("counter = %d", *p_counter);
+}
+
+static void
+mux_pcm_audio (guint num_buffers, guint repeat)
+{
+  GstElement *src, *sink, *flvmux, *conv, *pipeline;
+  GstPad *sinkpad, *srcpad;
+  gint counter;
+
+  GST_LOG ("num_buffers = %u", num_buffers);
+
+  pipeline = gst_pipeline_new ("pipeline");
+  fail_unless (pipeline != NULL, "Failed to create pipeline!");
+
+  /* kids, don't use a sync handler for this at home, really; we do because
+   * we just want to abort and nothing else */
+  gst_bus_set_sync_handler (GST_ELEMENT_BUS (pipeline), error_cb, NULL, NULL);
+
+  src = gst_element_factory_make ("audiotestsrc", "audiotestsrc");
+  fail_unless (src != NULL, "Failed to create 'audiotestsrc' element!");
+
+  g_object_set (src, "num-buffers", num_buffers, NULL);
+
+  conv = gst_element_factory_make ("audioconvert", "audioconvert");
+  fail_unless (conv != NULL, "Failed to create 'audioconvert' element!");
+
+  flvmux = gst_element_factory_make ("flvmux", "flvmux");
+  fail_unless (flvmux != NULL, "Failed to create 'flvmux' element!");
+
+  sink = gst_element_factory_make ("fakesink", "fakesink");
+  fail_unless (sink != NULL, "Failed to create 'fakesink' element!");
+
+  g_object_set (sink, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (sink, "handoff", G_CALLBACK (handoff_cb), &counter);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, conv, flvmux, sink, NULL);
+
+  fail_unless (gst_element_link (src, conv));
+  fail_unless (gst_element_link (flvmux, sink));
+
+  /* now link the elements */
+  sinkpad = gst_element_get_request_pad (flvmux, "audio");
+  fail_unless (sinkpad != NULL, "Could not get audio request pad");
+
+  srcpad = gst_element_get_static_pad (conv, "src");
+  fail_unless (srcpad != NULL, "Could not get audioconvert's source pad");
+
+  fail_unless_equals_int (gst_pad_link (srcpad, sinkpad), GST_PAD_LINK_OK);
+
+  gst_object_unref (srcpad);
+  gst_object_unref (sinkpad);
+
+  do {
+    GstStateChangeReturn state_ret;
+    GstMessage *msg;
+
+    GST_LOG ("repeat=%d", repeat);
+
+    counter = 0;
+
+    state_ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
+    fail_unless (state_ret != GST_STATE_CHANGE_FAILURE);
+
+    if (state_ret == GST_STATE_CHANGE_ASYNC) {
+      GST_LOG ("waiting for pipeline to reach PAUSED state");
+      state_ret = gst_element_get_state (pipeline, NULL, NULL, -1);
+      fail_unless_equals_int (state_ret, GST_STATE_CHANGE_SUCCESS);
+    }
+
+    GST_LOG ("PAUSED, let's do the rest of it");
+
+    state_ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
+    fail_unless (state_ret != GST_STATE_CHANGE_FAILURE);
+
+    msg = gst_bus_poll (GST_ELEMENT_BUS (pipeline), GST_MESSAGE_EOS, -1);
+    fail_unless (msg != NULL, "Expected EOS message on bus!");
+
+    GST_LOG ("EOS");
+    gst_message_unref (msg);
+
+    /* should have some output */
+    fail_unless (counter > 2);
+
+    fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
+        GST_STATE_CHANGE_SUCCESS);
+
+    /* repeat = test re-usability */
+    --repeat;
+  } while (repeat > 0);
+
+  gst_object_unref (pipeline);
+}
+
+GST_START_TEST (test_index_writing)
+{
+  /* note: there's a magic 128 value in flvmux when doing index writing */
+  if ((__i__ % 33) == 1)
+    mux_pcm_audio (__i__, 2);
+}
+
+GST_END_TEST;
+
+static GstBuffer *
+create_buffer (guint8 * data, gsize size,
+    GstClockTime timestamp, GstClockTime duration)
+{
+  GstBuffer *buf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+      data, size, 0, size, NULL, NULL);
+  GST_BUFFER_PTS (buf) = timestamp;
+  GST_BUFFER_DTS (buf) = timestamp;
+  GST_BUFFER_DURATION (buf) = duration;
+  GST_BUFFER_OFFSET (buf) = 0;
+  GST_BUFFER_OFFSET_END (buf) = 0;
+  return buf;
+}
+
+GST_START_TEST (test_speex_streamable)
+{
+  GstBuffer *buf;
+  GstMapInfo map = GST_MAP_INFO_INIT;
+
+  guint8 header0[] = {
+    0x53, 0x70, 0x65, 0x65, 0x78, 0x20, 0x20, 0x20,
+    0x31, 0x2e, 0x32, 0x72, 0x63, 0x31, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x50, 0x00, 0x00, 0x00, 0x80, 0x3e, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+    0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
+
+  guint8 header1[] = {
+    0x1f, 0x00, 0x00, 0x00, 0x45, 0x6e, 0x63, 0x6f,
+    0x64, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68,
+    0x20, 0x47, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d,
+    0x65, 0x72, 0x20, 0x53, 0x70, 0x65, 0x65, 0x78,
+    0x65, 0x6e, 0x63, 0x00, 0x00, 0x00, 0x00, 0x01
+  };
+
+  guint8 buffer[] = {
+    0x36, 0x9d, 0x1b, 0x9a, 0x20, 0x00, 0x01, 0x68,
+    0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0x84,
+    0x00, 0xb4, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74,
+    0x74, 0x42, 0x00, 0x5a, 0x3a, 0x3a, 0x3a, 0x3a,
+    0x3a, 0x3a, 0x3a, 0x21, 0x00, 0x2d, 0x1d, 0x1d,
+    0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1b, 0x3b, 0x60,
+    0xab, 0xab, 0xab, 0xab, 0xab, 0x0a, 0xba, 0xba,
+    0xba, 0xba, 0xb0, 0xab, 0xab, 0xab, 0xab, 0xab,
+    0x0a, 0xba, 0xba, 0xba, 0xba, 0xb7
+  };
+
+  GstCaps *caps = gst_caps_new_simple ("audio/x-speex",
+      "rate", G_TYPE_INT, 16000,
+      "channels", G_TYPE_INT, 1,
+      NULL);
+
+  const GstClockTime base_time = 123456789;
+  const GstClockTime duration_ms = 20;
+  const GstClockTime duration = duration_ms * GST_MSECOND;
+
+  GstHarness *h = gst_harness_new_with_padnames ("flvmux", "audio", "src");
+  gst_harness_set_src_caps (h, caps);
+  g_object_set (h->element, "streamable", 1, NULL);
+
+  /* push speex header0 */
+  gst_harness_push (h, create_buffer (header0, sizeof (header0), base_time, 0));
+
+  /* push speex header1 */
+  gst_harness_push (h, create_buffer (header1, sizeof (header1), base_time, 0));
+
+  /* push speex data */
+  gst_harness_push (h, create_buffer (buffer, sizeof (buffer),
+          base_time, duration));
+
+  /* push speex data 2 */
+  gst_harness_push (h, create_buffer (buffer, sizeof (buffer),
+          base_time + duration, duration));
+
+  /* pull out stream-start event */
+  gst_event_unref (gst_harness_pull_event (h));
+
+  /* pull out caps event */
+  gst_event_unref (gst_harness_pull_event (h));
+
+  /* pull out segment event and verify we are using GST_FORMAT_TIME */
+  {
+    GstEvent *event = gst_harness_pull_event (h);
+    const GstSegment *segment;
+    gst_event_parse_segment (event, &segment);
+    fail_unless_equals_int (GST_FORMAT_TIME, segment->format);
+    gst_event_unref (event);
+  }
+
+  /* pull FLV header buffer */
+  buf = gst_harness_pull (h);
+  gst_buffer_unref (buf);
+
+  /* pull Metadata buffer */
+  buf = gst_harness_pull (h);
+  gst_buffer_unref (buf);
+
+  /* pull header0 */
+  buf = gst_harness_pull (h);
+  fail_unless_equals_uint64 (base_time, GST_BUFFER_PTS (buf));
+  fail_unless_equals_uint64 (base_time, GST_BUFFER_DTS (buf));
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  /* 0x08 means it is audio */
+  fail_unless_equals_int (0x08, map.data[0]);
+  /* timestamp should be starting from 0 */
+  fail_unless_equals_int (0x00, map.data[6]);
+  /* 0xb2 means Speex, 16000Hz, Mono */
+  fail_unless_equals_int (0xb2, map.data[11]);
+  /* verify content is intact */
+  fail_unless_equals_int (0, memcmp (&map.data[12], header0, sizeof (header0)));
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+
+  /* pull header1 */
+  buf = gst_harness_pull (h);
+  fail_unless_equals_uint64 (base_time, GST_BUFFER_PTS (buf));
+  fail_unless_equals_uint64 (base_time, GST_BUFFER_DTS (buf));
+  fail_unless_equals_uint64 (0, GST_BUFFER_DURATION (buf));
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  /* 0x08 means it is audio */
+  fail_unless_equals_int (0x08, map.data[0]);
+  /* timestamp should be starting from 0 */
+  fail_unless_equals_int (0x00, map.data[6]);
+  /* 0xb2 means Speex, 16000Hz, Mono */
+  fail_unless_equals_int (0xb2, map.data[11]);
+  /* verify content is intact */
+  fail_unless_equals_int (0, memcmp (&map.data[12], header1, sizeof (header1)));
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+
+  /* pull data */
+  buf = gst_harness_pull (h);
+  fail_unless_equals_uint64 (base_time, GST_BUFFER_PTS (buf));
+  fail_unless_equals_uint64 (base_time, GST_BUFFER_DTS (buf));
+  fail_unless_equals_uint64 (duration, GST_BUFFER_DURATION (buf));
+  fail_unless_equals_uint64 (GST_BUFFER_OFFSET_NONE, GST_BUFFER_OFFSET (buf));
+  fail_unless_equals_uint64 (GST_BUFFER_OFFSET_NONE,
+      GST_BUFFER_OFFSET_END (buf));
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  /* 0x08 means it is audio */
+  fail_unless_equals_int (0x08, map.data[0]);
+  /* timestamp should be starting from 0 */
+  fail_unless_equals_int (0x00, map.data[6]);
+  /* 0xb2 means Speex, 16000Hz, Mono */
+  fail_unless_equals_int (0xb2, map.data[11]);
+  /* verify content is intact */
+  fail_unless_equals_int (0, memcmp (&map.data[12], buffer, sizeof (buffer)));
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+
+  /* pull data */
+  buf = gst_harness_pull (h);
+  fail_unless_equals_uint64 (base_time + duration, GST_BUFFER_PTS (buf));
+  fail_unless_equals_uint64 (base_time + duration, GST_BUFFER_DTS (buf));
+  fail_unless_equals_uint64 (duration, GST_BUFFER_DURATION (buf));
+  fail_unless_equals_uint64 (GST_BUFFER_OFFSET_NONE, GST_BUFFER_OFFSET (buf));
+  fail_unless_equals_uint64 (GST_BUFFER_OFFSET_NONE,
+      GST_BUFFER_OFFSET_END (buf));
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  /* 0x08 means it is audio */
+  fail_unless_equals_int (0x08, map.data[0]);
+  /* timestamp should reflect the duration_ms */
+  fail_unless_equals_int (duration_ms, map.data[6]);
+  /* 0xb2 means Speex, 16000Hz, Mono */
+  fail_unless_equals_int (0xb2, map.data[11]);
+  /* verify content is intact */
+  fail_unless_equals_int (0, memcmp (&map.data[12], buffer, sizeof (buffer)));
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+static void
+check_buf_type_timestamp (GstBuffer * buf, gint packet_type, gint timestamp)
+{
+  GstMapInfo map = GST_MAP_INFO_INIT;
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  fail_unless_equals_int (packet_type, map.data[0]);
+  fail_unless_equals_int (timestamp, map.data[6]);
+  gst_buffer_unmap (buf, &map);
+  gst_buffer_unref (buf);
+}
+
+GST_START_TEST (test_increasing_timestamp_when_pts_none)
+{
+  const gint AUDIO = 0x08;
+  const gint VIDEO = 0x09;
+  gint timestamp = 3;
+  GstClockTime base_time = 42 * GST_SECOND;
+  GstPad *audio_sink, *video_sink, *audio_src, *video_src;
+  GstHarness *h, *audio, *video, *audio_q, *video_q;
+  GstCaps *audio_caps, *video_caps;
+  GstBuffer *buf;
+
+  h = gst_harness_new_with_padnames ("flvmux", NULL, "src");
+  audio = gst_harness_new_with_element (h->element, "audio", NULL);
+  video = gst_harness_new_with_element (h->element, "video", NULL);
+  audio_q = gst_harness_new ("queue");
+  video_q = gst_harness_new ("queue");
+
+  audio_sink = GST_PAD_PEER (audio->srcpad);
+  video_sink = GST_PAD_PEER (video->srcpad);
+  audio_src = GST_PAD_PEER (audio_q->sinkpad);
+  video_src = GST_PAD_PEER (video_q->sinkpad);
+
+  gst_pad_unlink (audio->srcpad, audio_sink);
+  gst_pad_unlink (video->srcpad, video_sink);
+  gst_pad_unlink (audio_src, audio_q->sinkpad);
+  gst_pad_unlink (video_src, video_q->sinkpad);
+  gst_pad_link (audio_src, audio_sink);
+  gst_pad_link (video_src, video_sink);
+
+  audio_caps = gst_caps_new_simple ("audio/x-speex",
+      "rate", G_TYPE_INT, 16000, "channels", G_TYPE_INT, 1, NULL);
+  gst_harness_set_src_caps (audio_q, audio_caps);
+  video_caps = gst_caps_new_simple ("video/x-h264",
+      "stream-format", G_TYPE_STRING, "avc", NULL);
+  gst_harness_set_src_caps (video_q, video_caps);
+
+  /* Push audio + video + audio with increasing DTS, but PTS for video is
+   * GST_CLOCK_TIME_NONE
+   */
+  buf = gst_buffer_new ();
+  GST_BUFFER_DTS (buf) = timestamp * GST_MSECOND + base_time;
+  GST_BUFFER_PTS (buf) = timestamp * GST_MSECOND + base_time;
+  gst_harness_push (audio_q, buf);
+
+  buf = gst_buffer_new ();
+  GST_BUFFER_DTS (buf) = (timestamp + 1) * GST_MSECOND + base_time;
+  GST_BUFFER_PTS (buf) = GST_CLOCK_TIME_NONE;
+  gst_harness_push (video_q, buf);
+
+  buf = gst_buffer_new ();
+  GST_BUFFER_DTS (buf) = (timestamp + 2) * GST_MSECOND + base_time;
+  GST_BUFFER_PTS (buf) = (timestamp + 2) * GST_MSECOND + base_time;
+  gst_harness_push (audio_q, buf);
+
+  /* Pull two metadata packets out */
+  gst_buffer_unref (gst_harness_pull (h));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* Check that we receive the packets in monotonically increasing order and
+   * that their timestamps are correct (should start at 0)
+   */
+  buf = gst_harness_pull (h);
+  check_buf_type_timestamp (buf, AUDIO, 0);
+  buf = gst_harness_pull (h);
+  check_buf_type_timestamp (buf, VIDEO, 1);
+
+  /* teardown */
+  gst_harness_teardown (h);
+  gst_harness_teardown (audio);
+  gst_harness_teardown (video);
+  gst_harness_teardown (audio_q);
+  gst_harness_teardown (video_q);
+}
+
+GST_END_TEST;
+
+static Suite *
+flvmux_suite (void)
+{
+  Suite *s = suite_create ("flvmux");
+  TCase *tc_chain = tcase_create ("general");
+  gint loop = 499;
+
+  suite_add_tcase (s, tc_chain);
+
+#ifdef HAVE_VALGRIND
+  if (RUNNING_ON_VALGRIND) {
+    loop = 140;
+  }
+#endif
+
+  tcase_add_loop_test (tc_chain, test_index_writing, 1, loop);
+
+  tcase_add_test (tc_chain, test_speex_streamable);
+  tcase_add_test (tc_chain, test_increasing_timestamp_when_pts_none);
+
+  return s;
+}
+
+GST_CHECK_MAIN (flvmux)
diff --git a/tests/check/elements/gdkpixbufoverlay.c b/tests/check/elements/gdkpixbufoverlay.c
new file mode 100644
index 0000000..bc45554
--- /dev/null
+++ b/tests/check/elements/gdkpixbufoverlay.c
@@ -0,0 +1,80 @@
+/* GStreamer unit test for the gdkpixbufoverlay element
+ * Copyright (C) 2015 Tim-Philipp Müller <tim centricular com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/check/gstcheck.h>
+
+GST_START_TEST (test_simple_overlay)
+{
+  GstElement *pipeline, *src, *overlay, *sink;
+  GstMessage *msg;
+  GstBus *bus;
+
+  src = gst_element_factory_make ("videotestsrc", NULL);
+  fail_unless (src != NULL);
+  g_object_set (src, "num-buffers", 3, NULL);
+
+  overlay = gst_element_factory_make ("gdkpixbufoverlay", NULL);
+  fail_unless (overlay != NULL);
+
+#define IMAGE_PATH GST_TEST_FILES_PATH G_DIR_SEPARATOR_S "image.jpg"
+  g_object_set (overlay, "location", IMAGE_PATH, NULL);
+
+  sink = gst_element_factory_make ("fakesink", NULL);
+  fail_unless (sink != NULL);
+
+  pipeline = gst_pipeline_new (NULL);
+  gst_bin_add_many (GST_BIN (pipeline), src, overlay, sink, NULL);
+  gst_element_link_many (src, overlay, sink, NULL);
+
+  /* start prerolling */
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_ASYNC);
+
+  bus = gst_element_get_bus (pipeline);
+
+  /* wait for EOS */
+  msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS);
+  gst_message_unref (msg);
+
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
+      GST_STATE_CHANGE_SUCCESS);
+
+  gst_object_unref (bus);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
+static Suite *
+gdkpixbufoverlay_suite (void)
+{
+  Suite *s = suite_create ("gdkpixbufoverlay");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_simple_overlay);
+
+  return s;
+}
+
+GST_CHECK_MAIN (gdkpixbufoverlay);
diff --git a/tests/check/elements/gdkpixbufsink.c b/tests/check/elements/gdkpixbufsink.c
new file mode 100644
index 0000000..1183ccb
--- /dev/null
+++ b/tests/check/elements/gdkpixbufsink.c
@@ -0,0 +1,293 @@
+/* GStreamer unit test for the gdkpixbufsink element
+ * Copyright (C) 2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/check/gstcheck.h>
+#include <gst/video/video.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define CAPS_RGB "video/x-raw, format=RGB"
+#define CAPS_RGBA "video/x-raw, format=RGBA"
+#define WxH ",width=(int)319,height=(int)241"
+
+#define N_BUFFERS 5
+
+typedef struct
+{
+  GstElement *pipe;
+  GstElement *src;
+  GstElement *filter;
+  GstElement *sink;
+} GstGdkPixbufSinkTestContext;
+
+static void
+gdkpixbufsink_init_test_context (GstGdkPixbufSinkTestContext * ctx,
+    const gchar * filter_caps_string, gint num_buffers)
+{
+  GstCaps *caps;
+
+  fail_unless (ctx != NULL);
+
+  ctx->pipe = gst_pipeline_new ("pipeline");
+  fail_unless (ctx->pipe != NULL);
+  ctx->src = gst_element_factory_make ("videotestsrc", "src");
+  fail_unless (ctx->src != NULL, "Failed to create videotestsrc element");
+  ctx->filter = gst_element_factory_make ("capsfilter", "filter");
+  fail_unless (ctx->filter != NULL, "Failed to create capsfilter element");
+  ctx->sink = gst_element_factory_make ("gdkpixbufsink", "sink");
+  fail_unless (ctx->sink != NULL, "Failed to create gdkpixbufsink element");
+
+  caps = gst_caps_from_string (filter_caps_string);
+  fail_unless (caps != NULL);
+  g_object_set (ctx->filter, "caps", caps, NULL);
+  gst_caps_unref (caps);
+
+  if (num_buffers > 0)
+    g_object_set (ctx->src, "num-buffers", num_buffers, NULL);
+
+  fail_unless (gst_bin_add (GST_BIN (ctx->pipe), ctx->src));
+  fail_unless (gst_bin_add (GST_BIN (ctx->pipe), ctx->filter));
+  fail_unless (gst_bin_add (GST_BIN (ctx->pipe), ctx->sink));
+  fail_unless (gst_element_link (ctx->src, ctx->filter));
+  fail_unless (gst_element_link (ctx->filter, ctx->sink));
+}
+
+static void
+gdkpixbufsink_unset_test_context (GstGdkPixbufSinkTestContext * ctx)
+{
+  gst_element_set_state (ctx->pipe, GST_STATE_NULL);
+  gst_object_unref (ctx->pipe);
+  memset (ctx, 0, sizeof (GstGdkPixbufSinkTestContext));
+}
+
+static gboolean
+check_last_pixbuf (GstGdkPixbufSinkTestContext * ctx, gpointer pixbuf)
+{
+  gpointer last_pb = NULL;
+  gboolean ret;
+
+  g_object_get (ctx->sink, "last-pixbuf", &last_pb, NULL);
+
+  ret = (last_pb == pixbuf);
+
+  if (last_pb)
+    g_object_unref (last_pb);
+
+  return ret;
+}
+
+/* doesn't return a ref to the pixbuf */
+static GdkPixbuf *
+check_message_pixbuf (GstMessage * msg, const gchar * name, gint channels,
+    gboolean has_alpha)
+{
+  GdkPixbuf *pixbuf;
+  const GstStructure *s;
+
+  fail_unless (gst_message_get_structure (msg) != NULL);
+
+  s = gst_message_get_structure (msg);
+  fail_unless_equals_string (gst_structure_get_name (s), name);
+
+  fail_unless (gst_structure_has_field (s, "pixbuf"));
+  fail_unless (gst_structure_has_field_typed (s, "pixel-aspect-ratio",
+          GST_TYPE_FRACTION));
+  pixbuf =
+      GDK_PIXBUF (g_value_get_object (gst_structure_get_value (s, "pixbuf")));
+  fail_unless (GDK_IS_PIXBUF (pixbuf));
+  fail_unless_equals_int (gdk_pixbuf_get_n_channels (pixbuf), channels);
+  fail_unless_equals_int (gdk_pixbuf_get_has_alpha (pixbuf), has_alpha);
+  fail_unless_equals_int (gdk_pixbuf_get_width (pixbuf), 319);
+  fail_unless_equals_int (gdk_pixbuf_get_height (pixbuf), 241);
+
+  return pixbuf;
+}
+
+GST_START_TEST (test_rgb)
+{
+  GstGdkPixbufSinkTestContext ctx;
+  GstMessage *msg;
+  GdkPixbuf *pixbuf;
+  GstBus *bus;
+  gint i;
+
+  gdkpixbufsink_init_test_context (&ctx, CAPS_RGB WxH, N_BUFFERS);
+
+  fail_unless (check_last_pixbuf (&ctx, NULL));
+
+  /* start prerolling */
+  fail_unless_equals_int (gst_element_set_state (ctx.pipe, GST_STATE_PAUSED),
+      GST_STATE_CHANGE_ASYNC);
+
+  /* wait until prerolled */
+  fail_unless_equals_int (gst_element_get_state (ctx.pipe, NULL, NULL, -1),
+      GST_STATE_CHANGE_SUCCESS);
+
+  bus = gst_element_get_bus (ctx.pipe);
+
+  /* find element message from our gdkpixbufsink, ignore element messages from
+   * other elemements (which just seems prudent to do, we don't expect any) */
+  while (1) {
+    msg = gst_bus_pop_filtered (bus, GST_MESSAGE_ELEMENT);
+    fail_if (msg == NULL, "Expected element message from gdkpixbufsink");
+
+    if (msg->src == GST_OBJECT (ctx.sink))
+      break;
+  }
+
+  pixbuf = check_message_pixbuf (msg, "preroll-pixbuf", 3, FALSE);
+  fail_unless (check_last_pixbuf (&ctx, pixbuf));
+  gst_message_unref (msg);
+  pixbuf = NULL;
+
+  /* and go! */
+  fail_unless_equals_int (gst_element_set_state (ctx.pipe, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_SUCCESS);
+
+  /* This is racy, supposed to make sure locking and refcounting works at
+   * least to some extent */
+  for (i = 0; i < 10000; ++i) {
+    gpointer obj = NULL;
+
+    g_object_get (ctx.sink, "last-pixbuf", &obj, NULL);
+    fail_unless (obj == NULL || GDK_IS_PIXBUF (obj));
+    if (obj)
+      g_object_unref (obj);
+  }
+
+  /* there should be as many pixbuf messages as buffers */
+  for (i = 0; i < N_BUFFERS; ++i) {
+    /* find element message from our gdkpixbufsink, ignore element messages from
+     * other elemements (which just seems prudent to do, we don't expect any) */
+    while (1) {
+      msg = gst_bus_timed_pop_filtered (bus, -1, GST_MESSAGE_ELEMENT);
+      fail_if (msg == NULL, "Expected element message from gdkpixbufsink");
+      if (msg->src == GST_OBJECT (ctx.sink))
+        break;
+    }
+
+    pixbuf = check_message_pixbuf (msg, "pixbuf", 3, FALSE);
+    gst_message_unref (msg);
+  }
+
+  /* note: we don't hold a ref to pixbuf any longer here, but it should be ok */
+  fail_unless (check_last_pixbuf (&ctx, pixbuf));
+  pixbuf = NULL;
+
+  gdkpixbufsink_unset_test_context (&ctx);
+  gst_object_unref (bus);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rgba)
+{
+  GstGdkPixbufSinkTestContext ctx;
+  GstMessage *msg;
+  GdkPixbuf *pixbuf;
+  GstBus *bus;
+  gint i;
+
+  gdkpixbufsink_init_test_context (&ctx, CAPS_RGBA WxH, N_BUFFERS);
+
+  fail_unless (check_last_pixbuf (&ctx, NULL));
+
+  /* start prerolling */
+  fail_unless_equals_int (gst_element_set_state (ctx.pipe, GST_STATE_PAUSED),
+      GST_STATE_CHANGE_ASYNC);
+
+  /* wait until prerolled */
+  fail_unless_equals_int (gst_element_get_state (ctx.pipe, NULL, NULL, -1),
+      GST_STATE_CHANGE_SUCCESS);
+
+  bus = gst_element_get_bus (ctx.pipe);
+
+  /* find element message from our gdkpixbufsink, ignore element messages from
+   * other elemements (which just seems prudent to do, we don't expect any) */
+  while (1) {
+    msg = gst_bus_pop_filtered (bus, GST_MESSAGE_ELEMENT);
+    fail_if (msg == NULL, "Expected element message from gdkpixbufsink");
+
+    if (msg->src == GST_OBJECT (ctx.sink))
+      break;
+  }
+
+  pixbuf = check_message_pixbuf (msg, "preroll-pixbuf", 4, TRUE);
+  fail_unless (check_last_pixbuf (&ctx, pixbuf));
+  gst_message_unref (msg);
+  pixbuf = NULL;
+
+  /* and go! */
+  fail_unless_equals_int (gst_element_set_state (ctx.pipe, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_SUCCESS);
+
+  /* This is racy, supposed to make sure locking and refcounting works at
+   * least to some extent */
+  for (i = 0; i < 10000; ++i) {
+    gpointer obj = NULL;
+
+    g_object_get (ctx.sink, "last-pixbuf", &obj, NULL);
+    fail_unless (obj == NULL || GDK_IS_PIXBUF (obj));
+    if (obj)
+      g_object_unref (obj);
+  }
+
+  /* there should be as many pixbuf messages as buffers */
+  for (i = 0; i < N_BUFFERS; ++i) {
+    /* find element message from our gdkpixbufsink, ignore element messages from
+     * other elemements (which just seems prudent to do, we don't expect any) */
+    while (1) {
+      msg = gst_bus_timed_pop_filtered (bus, -1, GST_MESSAGE_ELEMENT);
+      fail_if (msg == NULL, "Expected element message from gdkpixbufsink");
+      if (msg->src == GST_OBJECT (ctx.sink))
+        break;
+    }
+
+    pixbuf = check_message_pixbuf (msg, "pixbuf", 4, TRUE);
+    gst_message_unref (msg);
+  }
+
+  /* note: we don't hold a ref to pixbuf any longer here, but it should be ok */
+  fail_unless (check_last_pixbuf (&ctx, pixbuf));
+  pixbuf = NULL;
+
+  gdkpixbufsink_unset_test_context (&ctx);
+  gst_object_unref (bus);
+}
+
+GST_END_TEST;
+
+static Suite *
+gdkpixbufsink_suite (void)
+{
+  Suite *s = suite_create ("gdkpixbufsink");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_rgb);
+  tcase_add_test (tc_chain, test_rgba);
+
+  return s;
+}
+
+GST_CHECK_MAIN (gdkpixbufsink);
diff --git a/tests/check/elements/icydemux.c b/tests/check/elements/icydemux.c
new file mode 100644
index 0000000..b5e43b4
--- /dev/null
+++ b/tests/check/elements/icydemux.c
@@ -0,0 +1,378 @@
+/*
+ * icydemux.c - Test icydemux element
+ * Copyright (C) 2006 Michael Smith <msmith@fluendo.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/check/gstcheck.h>
+
+/* Chunk of data: 8 bytes, followed by a metadata-length byte of 2, followed by
+ * some metadata (32 bytes), then some more data.
+ */
+#define TEST_METADATA \
+    "Test metadata"
+#define ICY_METADATA \
+    "StreamTitle='" TEST_METADATA "';\0\0\0\0"
+
+#define EMPTY_ICY_STREAM_TITLE_METADATA \
+    "StreamTitle='';\0"
+
+#define ICY_DATA \
+    "aaaaaaaa" \
+    "\x02" \
+    ICY_METADATA \
+    "bbbbbbbb"
+
+#define ICY_DATA_EMPTY_METADATA \
+    ICY_DATA \
+    "\x00" \
+    "dddddddd" \
+    "\x01" \
+    EMPTY_ICY_STREAM_TITLE_METADATA \
+    "cccccccc"
+
+#define ICYCAPS "application/x-icy, metadata-interval = (int)8"
+
+#define SRC_CAPS "application/x-icy, metadata-interval = (int)[0, MAX]"
+#define SINK_CAPS  "ANY"
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SRC_CAPS)
+    );
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SINK_CAPS)
+    );
+
+static GstElement *icydemux;
+static GstBus *bus;
+GstPad *srcpad, *sinkpad;
+
+static GstStaticCaps typefind_caps =
+GST_STATIC_CAPS ("application/octet-stream");
+
+static gboolean fake_typefind_caps;     /* FALSE */
+
+static void
+typefind_succeed (GstTypeFind * tf, gpointer private)
+{
+  if (fake_typefind_caps) {
+    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM,
+        gst_static_caps_get (&typefind_caps));
+  }
+}
+
+static gboolean
+test_event_func (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GST_LOG_OBJECT (pad, "%s event: %" GST_PTR_FORMAT,
+      GST_EVENT_TYPE_NAME (event), event);
+
+  /* a sink would post tag events as messages, so do the same here,
+   * esp. since we're polling on the bus waiting for TAG messages.. */
+  if (GST_EVENT_TYPE (event) == GST_EVENT_TAG) {
+    GstTagList *taglist;
+
+    gst_event_parse_tag (event, &taglist);
+
+    gst_bus_post (bus, gst_message_new_tag (GST_OBJECT (pad),
+            gst_tag_list_copy (taglist)));
+  }
+
+  gst_event_unref (event);
+  return TRUE;
+}
+
+static void
+icydemux_found_pad (GstElement * src, GstPad * pad, gpointer data)
+{
+  GST_DEBUG ("got new pad %" GST_PTR_FORMAT, pad);
+
+  /* Turns out that this asserts a refcount which is wrong for this
+   * case (adding the pad from a pad-added callback), so just do the same
+   * thing inline... */
+  /* sinkpad = gst_check_setup_sink_pad (icydemux, &sinktemplate, NULL); */
+  sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");
+  fail_if (sinkpad == NULL, "Couldn't create sinkpad");
+  srcpad = gst_element_get_static_pad (icydemux, "src");
+  fail_if (srcpad == NULL, "Failed to get srcpad from icydemux");
+  gst_pad_set_chain_function (sinkpad, gst_check_chain_func);
+  gst_pad_set_event_function (sinkpad, test_event_func);
+
+  GST_DEBUG ("checking srcpad %p refcount", srcpad);
+  /* 1 from element, 1 from signal, 1 from us */
+  ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 3);
+
+  GST_DEBUG ("linking srcpad");
+  fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK,
+      "Failed to link pads");
+  gst_object_unref (srcpad);
+
+  gst_pad_set_active (sinkpad, TRUE);
+}
+
+static GstElement *
+create_icydemux (void)
+{
+  icydemux = gst_check_setup_element ("icydemux");
+  srcpad = gst_check_setup_src_pad (icydemux, &srctemplate);
+
+  gst_pad_set_active (srcpad, TRUE);
+
+  g_signal_connect (icydemux, "pad-added", G_CALLBACK (icydemux_found_pad),
+      NULL);
+
+  bus = gst_bus_new ();
+  gst_element_set_bus (icydemux, bus);
+
+  fail_unless (gst_element_set_state (icydemux, GST_STATE_PLAYING) !=
+      GST_STATE_CHANGE_FAILURE, "could not set to playing");
+
+  return icydemux;
+}
+
+static void
+cleanup_icydemux (void)
+{
+  gst_bus_set_flushing (bus, TRUE);
+  gst_object_unref (bus);
+  bus = NULL;
+
+  gst_check_drop_buffers ();
+  gst_check_teardown_src_pad (icydemux);
+  if (sinkpad)
+    gst_check_teardown_sink_pad (icydemux);
+  gst_check_teardown_element (icydemux);
+
+  srcpad = NULL;
+  sinkpad = NULL;
+  icydemux = NULL;
+}
+
+static void
+push_data (const guint8 * data, int len, gint64 offset)
+{
+  GstFlowReturn res;
+  GstBuffer *buffer = gst_buffer_new_and_alloc (len);
+
+  gst_buffer_fill (buffer, 0, data, len);
+
+  GST_BUFFER_OFFSET (buffer) = offset;
+
+  res = gst_pad_push (srcpad, buffer);
+
+  fail_unless (res == GST_FLOW_OK, "Failed pushing buffer: %d", res);
+}
+
+GST_START_TEST (test_demux)
+{
+  GstMessage *message;
+  GstTagList *tags;
+  const GValue *tag_val;
+  const gchar *tag;
+  GstCaps *caps;
+
+  fail_unless (gst_type_find_register (NULL, "success", GST_RANK_PRIMARY,
+          typefind_succeed, NULL, gst_static_caps_get (&typefind_caps), NULL,
+          NULL));
+
+  fake_typefind_caps = TRUE;
+
+  caps = gst_caps_from_string (ICYCAPS);
+
+  create_icydemux ();
+  gst_check_setup_events (srcpad, icydemux, caps, GST_FORMAT_TIME);
+
+  push_data ((guint8 *) ICY_DATA, sizeof (ICY_DATA), -1);
+
+  message = gst_bus_poll (bus, GST_MESSAGE_TAG, -1);
+  fail_unless (message != NULL);
+
+  gst_message_parse_tag (message, &tags);
+  fail_unless (tags != NULL);
+
+  tag_val = gst_tag_list_get_value_index (tags, GST_TAG_TITLE, 0);
+  fail_unless (tag_val != NULL);
+
+  tag = g_value_get_string (tag_val);
+  fail_unless (tag != NULL);
+
+  fail_unless_equals_string (TEST_METADATA, (char *) tag);
+
+  gst_tag_list_unref (tags);
+  gst_message_unref (message);
+  gst_caps_unref (caps);
+
+  cleanup_icydemux ();
+
+  fake_typefind_caps = FALSE;
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_demux_empty_data)
+{
+  GstMessage *message;
+  GstTagList *tags;
+  const GValue *tag_val;
+  const gchar *tag;
+  GstCaps *caps;
+
+  fail_unless (gst_type_find_register (NULL, "success", GST_RANK_PRIMARY,
+          typefind_succeed, NULL, gst_static_caps_get (&typefind_caps), NULL,
+          NULL));
+
+  fake_typefind_caps = TRUE;
+
+  caps = gst_caps_from_string (ICYCAPS);
+
+  create_icydemux ();
+  gst_check_setup_events (srcpad, icydemux, caps, GST_FORMAT_TIME);
+
+  push_data ((guint8 *) ICY_DATA_EMPTY_METADATA,
+      sizeof (ICY_DATA_EMPTY_METADATA), -1);
+
+  message = gst_bus_poll (bus, GST_MESSAGE_TAG, -1);
+  fail_unless (message != NULL);
+
+  gst_message_parse_tag (message, &tags);
+  fail_unless (tags != NULL);
+
+  tag_val = gst_tag_list_get_value_index (tags, GST_TAG_TITLE, 0);
+  fail_unless (tag_val != NULL);
+
+  tag = g_value_get_string (tag_val);
+  fail_unless (tag != NULL);
+
+  fail_unless_equals_string (TEST_METADATA, (char *) tag);
+
+  gst_tag_list_unref (tags);
+  gst_message_unref (message);
+
+  message = gst_bus_poll (bus, GST_MESSAGE_TAG, -1);
+  fail_unless (message != NULL);
+
+  gst_message_parse_tag (message, &tags);
+  fail_unless (tags != NULL);
+
+  tag_val = gst_tag_list_get_value_index (tags, GST_TAG_TITLE, 0);
+  fail_unless (tag_val == NULL);
+
+  gst_message_unref (message);
+
+  /* Ensure that no further tag messages are received, i.e. the empty ICY tag
+   * is skipped */
+  message = gst_bus_poll (bus, GST_MESSAGE_TAG, 100000000);
+  fail_unless (message == NULL);
+
+  gst_tag_list_unref (tags);
+  gst_caps_unref (caps);
+
+  cleanup_icydemux ();
+
+  fake_typefind_caps = FALSE;
+}
+
+GST_END_TEST;
+
+/* run this test first before the custom typefind function is set up */
+GST_START_TEST (test_first_buf_offset_when_merged_for_typefinding)
+{
+  const guint8 buf1[] = { 'M' };
+  const guint8 buf2[] = { 'P', '+', 0xff, 0xfb, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
+  GstCaps *icy_caps;
+  GstPad *icy_srcpad;
+
+  fake_typefind_caps = FALSE;
+
+  create_icydemux ();
+
+  icy_caps = gst_caps_from_string (ICYCAPS);
+
+  gst_check_setup_events (srcpad, icydemux, icy_caps, GST_FORMAT_TIME);
+
+  push_data (buf1, G_N_ELEMENTS (buf1), 0);
+
+  /* one byte isn't really enough for typefinding, can't have a srcpad yet */
+  fail_unless (gst_element_get_static_pad (icydemux, "src") == NULL);
+
+  push_data (buf2, G_N_ELEMENTS (buf2), -1);
+
+  /* should have been enough to create a audio/x-musepack source pad .. */
+  icy_srcpad = gst_element_get_static_pad (icydemux, "src");
+  fail_unless (icy_srcpad != NULL);
+  gst_object_unref (icy_srcpad);
+
+  fail_unless (g_list_length (buffers) > 0);
+
+  /* first buffer should have offset 0 even after it was merged with 2nd buf */
+  fail_unless (GST_BUFFER_OFFSET (GST_BUFFER_CAST (buffers->data)) == 0);
+
+  gst_caps_unref (icy_caps);
+
+  cleanup_icydemux ();
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_not_negotiated)
+{
+  GstBuffer *buf;
+  GstSegment segment;
+
+  create_icydemux ();
+
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  gst_pad_push_event (srcpad, gst_event_new_stream_start ("test"));
+  gst_pad_push_event (srcpad, gst_event_new_segment (&segment));
+
+  buf = gst_buffer_new_and_alloc (0);
+  GST_BUFFER_OFFSET (buf) = 0;
+
+  fail_unless_equals_int (gst_pad_push (srcpad, buf), GST_FLOW_NOT_NEGOTIATED);
+  buf = NULL;
+
+  cleanup_icydemux ();
+}
+
+GST_END_TEST;
+
+static Suite *
+icydemux_suite (void)
+{
+  Suite *s = suite_create ("icydemux");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_demux);
+  tcase_add_test (tc_chain, test_demux_empty_data);
+  tcase_add_test (tc_chain, test_first_buf_offset_when_merged_for_typefinding);
+  tcase_add_test (tc_chain, test_not_negotiated);
+
+  return s;
+}
+
+GST_CHECK_MAIN (icydemux)
diff --git a/tests/check/elements/id3demux.c b/tests/check/elements/id3demux.c
new file mode 100644
index 0000000..17b524d
--- /dev/null
+++ b/tests/check/elements/id3demux.c
@@ -0,0 +1,283 @@
+/* GStreamer unit tests for id3demux
+ *
+ * Copyright (C) 2007 Tim-Philipp Müller  <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+
+#include <gst/gst.h>
+
+typedef void (CheckTagsFunc) (const GstTagList * tags, const gchar * file);
+
+static GstBusSyncReply
+error_cb (GstBus * bus, GstMessage * msg, gpointer user_data)
+{
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
+    const gchar *file = (const gchar *) user_data;
+    GError *err = NULL;
+    gchar *dbg = NULL;
+
+    gst_message_parse_error (msg, &err, &dbg);
+    g_error ("ERROR for %s: %s\n%s\n", file, err->message, dbg);
+  }
+
+  return GST_BUS_PASS;
+}
+
+static GstTagList *
+read_tags_from_file (const gchar * file, gboolean push_mode)
+{
+  GstStateChangeReturn state_ret;
+  GstTagList *tags = NULL;
+  GstMessage *msg;
+  GstElement *src, *sep, *sink, *id3demux, *pipeline;
+  GstBus *bus;
+  gchar *path;
+
+  pipeline = gst_pipeline_new ("pipeline");
+  fail_unless (pipeline != NULL, "Failed to create pipeline!");
+
+  bus = gst_element_get_bus (pipeline);
+
+  /* kids, don't use a sync handler for this at home, really; we do because
+   * we just want to abort and nothing else */
+  gst_bus_set_sync_handler (bus, error_cb, (gpointer) file, NULL);
+
+  src = gst_element_factory_make ("filesrc", "filesrc");
+  fail_unless (src != NULL, "Failed to create 'filesrc' element!");
+
+  if (push_mode) {
+    sep = gst_element_factory_make ("queue", "queue");
+    fail_unless (sep != NULL, "Failed to create 'queue' element");
+  } else {
+    sep = gst_element_factory_make ("identity", "identity");
+    fail_unless (sep != NULL, "Failed to create 'identity' element");
+  }
+
+  id3demux = gst_element_factory_make ("id3demux", "id3demux");
+  fail_unless (id3demux != NULL, "Failed to create 'id3demux' element!");
+
+  sink = gst_element_factory_make ("fakesink", "fakesink");
+  fail_unless (sink != NULL, "Failed to create 'fakesink' element!");
+
+  gst_bin_add_many (GST_BIN (pipeline), src, sep, id3demux, sink, NULL);
+
+  fail_unless (gst_element_link (src, sep));
+  fail_unless (gst_element_link (sep, id3demux));
+  fail_unless (gst_element_link (id3demux, sink));
+
+  path = g_build_filename (GST_TEST_FILES_PATH, file, NULL);
+  GST_LOG ("reading file '%s'", path);
+  g_object_set (src, "location", path, NULL);
+
+  state_ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
+  fail_unless (state_ret != GST_STATE_CHANGE_FAILURE);
+
+  if (state_ret == GST_STATE_CHANGE_ASYNC) {
+    GST_LOG ("waiting for pipeline to reach PAUSED state");
+    state_ret = gst_element_get_state (pipeline, NULL, NULL, -1);
+    fail_unless_equals_int (state_ret, GST_STATE_CHANGE_SUCCESS);
+  }
+
+  GST_LOG ("PAUSED, let's retrieve our tags");
+
+  msg = gst_bus_poll (bus, GST_MESSAGE_TAG, -1);
+  fail_unless (msg != NULL, "Expected TAG message on bus! (%s)", file);
+
+  gst_message_parse_tag (msg, &tags);
+  fail_unless (tags != NULL, "TAG message did not contain taglist! (%s)", file);
+
+  gst_message_unref (msg);
+  gst_object_unref (bus);
+
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
+      GST_STATE_CHANGE_SUCCESS);
+  gst_object_unref (pipeline);
+
+  g_free (path);
+
+  GST_INFO ("%s: tags = %" GST_PTR_FORMAT, file, tags);
+  return tags;
+}
+
+static void
+run_check_for_file (const gchar * filename, CheckTagsFunc * check_func)
+{
+  GstTagList *tags;
+
+  /* first, pull-based */
+  tags = read_tags_from_file (filename, FALSE);
+  fail_unless (tags != NULL, "Failed to extract tags from '%s'", filename);
+  check_func (tags, filename);
+  gst_tag_list_unref (tags);
+
+  /* FIXME: need to fix id3demux for short content in push mode */
+#if 0
+  /* now try push-based */
+  tags = read_tags_from_file (filename, TRUE);
+  fail_unless (tags != NULL, "Failed to extract tags from '%s'", filename);
+  check_func (tags, filename);
+  gst_tag_list_unref (tags);
+#endif
+}
+
+static void
+check_date_1977_06_23 (const GstTagList * tags, const gchar * file)
+{
+  GstDateTime *date = NULL;
+
+  gst_tag_list_get_date_time (tags, GST_TAG_DATE_TIME, &date);
+  fail_unless (date != NULL,
+      "Tags from %s should contain a GST_TAG_DATE_TIME tag");
+  fail_unless_equals_int (gst_date_time_get_year (date), 1977);
+  fail_unless_equals_int (gst_date_time_get_month (date), 6);
+  fail_unless_equals_int (gst_date_time_get_day (date), 23);
+  gst_date_time_unref (date);
+}
+
+GST_START_TEST (test_tdat_tyer)
+{
+  run_check_for_file ("id3-407349-1.tag", check_date_1977_06_23);
+  run_check_for_file ("id3-407349-2.tag", check_date_1977_06_23);
+}
+
+GST_END_TEST;
+
+static void
+check_wcop (const GstTagList * tags, const gchar * file)
+{
+  gchar *copyright = NULL;
+  gchar *uri = NULL;
+
+  fail_unless (gst_tag_list_get_string (tags, GST_TAG_LICENSE_URI, &uri));
+  fail_unless (uri != NULL);
+  fail_unless_equals_string (uri,
+      "http://creativecommons.org/licenses/by/3.0/");
+  g_free (uri);
+
+  fail_unless (gst_tag_list_get_string (tags, GST_TAG_COPYRIGHT, &copyright));
+  fail_unless (copyright != NULL);
+  fail_unless_equals_string (copyright,
+      " Steadman. Licensed to the public under http://creativecommons.org/licenses/by/3.0/ verify at http://test.com");
+  g_free (copyright);
+}
+
+GST_START_TEST (test_wcop)
+{
+  run_check_for_file ("id3-447000-wcop.tag", check_wcop);
+}
+
+GST_END_TEST;
+
+static void
+check_unsync_v23 (const GstTagList * tags, const gchar * file)
+{
+  gchar *album = NULL;
+  gchar *title = NULL;
+  gchar *artist = NULL;
+
+  fail_unless (gst_tag_list_get_string (tags, GST_TAG_TITLE, &title));
+  fail_unless (title != NULL);
+  fail_unless_equals_string (title, "ARTIST");  /* sic */
+  g_free (title);
+
+  fail_unless (gst_tag_list_get_string (tags, GST_TAG_ALBUM, &album));
+  fail_unless (album != NULL);
+  fail_unless_equals_string (album, "Album");
+  g_free (album);
+
+  fail_unless (gst_tag_list_get_string (tags, GST_TAG_ARTIST, &artist));
+  fail_unless (artist != NULL);
+  fail_unless_equals_string (artist, "藝人");
+  g_free (artist);
+}
+
+GST_START_TEST (test_unsync_v23)
+{
+  run_check_for_file ("id3-577468-unsynced-tag.tag", check_unsync_v23);
+}
+
+GST_END_TEST;
+
+static void
+check_unsync_v24 (const GstTagList * tags, const gchar * file)
+{
+  const GValue *val;
+  GstSample *sample;
+  GstBuffer *buf;
+  gchar *album = NULL;
+  gchar *title = NULL;
+  gchar *artist = NULL;
+  GstMapInfo map;
+
+  fail_unless (gst_tag_list_get_string (tags, GST_TAG_TITLE, &title));
+  fail_unless (title != NULL);
+  fail_unless_equals_string (title, "Starlight");
+  g_free (title);
+
+  fail_unless (gst_tag_list_get_string (tags, GST_TAG_ALBUM, &album));
+  fail_unless (album != NULL);
+  fail_unless_equals_string (album, "L'albumRockVol.4 CD1");
+  g_free (album);
+
+  fail_unless (gst_tag_list_get_string (tags, GST_TAG_ARTIST, &artist));
+  fail_unless (artist != NULL);
+  fail_unless_equals_string (artist, "Muse");
+  g_free (artist);
+
+  val = gst_tag_list_get_value_index (tags, GST_TAG_IMAGE, 0);
+  fail_unless (val != NULL);
+  fail_unless (GST_VALUE_HOLDS_SAMPLE (val));
+  sample = gst_value_get_sample (val);
+  fail_unless (sample != NULL);
+  fail_unless (gst_sample_get_caps (sample) != NULL);
+  buf = gst_sample_get_buffer (sample);
+  fail_unless (buf != NULL);
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  fail_unless_equals_int (map.size, 38022);
+  /* check for jpeg start/end markers */
+  fail_unless_equals_int (map.data[0], 0xff);
+  fail_unless_equals_int (map.data[1], 0xd8);
+  fail_unless_equals_int (map.data[38020], 0xff);
+  fail_unless_equals_int (map.data[38021], 0xd9);
+  gst_buffer_unmap (buf, &map);
+}
+
+GST_START_TEST (test_unsync_v24)
+{
+  run_check_for_file ("id3-588148-unsynced-v24.tag", check_unsync_v24);
+}
+
+GST_END_TEST;
+
+static Suite *
+id3demux_suite (void)
+{
+  Suite *s = suite_create ("id3demux");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_tdat_tyer);
+  tcase_add_test (tc_chain, test_wcop);
+  tcase_add_test (tc_chain, test_unsync_v23);
+  tcase_add_test (tc_chain, test_unsync_v24);
+
+  return s;
+}
+
+GST_CHECK_MAIN (id3demux)
diff --git a/tests/check/elements/id3v2mux.c b/tests/check/elements/id3v2mux.c
new file mode 100644
index 0000000..0a47f1d
--- /dev/null
+++ b/tests/check/elements/id3v2mux.c
@@ -0,0 +1,521 @@
+/* GStreamer
+ *
+ * unit test for the taglib-based id3v2mux element
+ *
+ * Copyright (C) 2006 Tim-Philipp Müller  <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+
+#include <gst/gst.h>
+#include <string.h>
+
+#define TEST_ARTIST           "Ar T\303\255st"
+#define TEST_TITLE            "M\303\274llermilch!"
+#define TEST_ALBUM            "Boom"
+#define TEST_DATE             g_date_new_dmy(1,1,2006)
+#define TEST_TRACK_NUMBER     7
+#define TEST_TRACK_COUNT      19
+#define TEST_VOLUME_NUMBER    2
+#define TEST_VOLUME_COUNT     3
+#define TEST_TRACK_GAIN      1.45
+#define TEST_ALBUM_GAIN      0.78
+#define TEST_TRACK_PEAK      0.83
+#define TEST_ALBUM_PEAK      0.18
+#define TEST_BPM             113.0
+
+/* for dummy mp3 frame sized MP3_FRAME_SIZE bytes,
+ * start: ff fb b0 44 00 00 08 00  00 4b 00 00 00 00 00 00 */
+static const guint8 mp3_dummyhdr[] = { 0xff, 0xfb, 0xb0, 0x44, 0x00, 0x00,
+  0x08, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00
+};
+
+#define MP3_FRAME_SIZE 626
+
+/* the peak and gain values are stored pretty roughly, so check that they're
+ * within 2% of the expected value.
+ */
+#define fail_unless_sorta_equals_float(a, b)				\
+G_STMT_START {								\
+  double first = a;							\
+  double second = b;							\
+  fail_unless(fabs (first - second) < (0.02 * fabs (first)),		\
+      "'" #a "' (%g) is not equal to '" #b "' (%g)", first, second);	\
+} G_STMT_END;
+
+
+static GstTagList *
+test_taglib_id3mux_create_tags (guint32 mask)
+{
+  GstTagList *tags;
+
+  tags = gst_tag_list_new_empty ();
+
+  if (mask & (1 << 0)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_ARTIST, TEST_ARTIST, NULL);
+  }
+  if (mask & (1 << 1)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_TITLE, TEST_TITLE, NULL);
+  }
+  if (mask & (1 << 2)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_ALBUM, TEST_ALBUM, NULL);
+  }
+  if (mask & (1 << 3)) {
+    GDate *date;
+
+    date = TEST_DATE;
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_DATE, date, NULL);
+    g_date_free (date);
+  }
+  if (mask & (1 << 4)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_TRACK_NUMBER, TEST_TRACK_NUMBER, NULL);
+  }
+  if (mask & (1 << 5)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_TRACK_COUNT, TEST_TRACK_COUNT, NULL);
+  }
+  if (mask & (1 << 6)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_ALBUM_VOLUME_NUMBER, TEST_VOLUME_NUMBER, NULL);
+  }
+  if (mask & (1 << 7)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_ALBUM_VOLUME_COUNT, TEST_VOLUME_COUNT, NULL);
+  }
+  if (mask & (1 << 8)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_TRACK_GAIN, TEST_TRACK_GAIN, NULL);
+  }
+  if (mask & (1 << 9)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_ALBUM_GAIN, TEST_ALBUM_GAIN, NULL);
+  }
+  if (mask & (1 << 10)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_TRACK_PEAK, TEST_TRACK_PEAK, NULL);
+  }
+  if (mask & (1 << 11)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_ALBUM_PEAK, TEST_ALBUM_PEAK, NULL);
+  }
+  if (mask & (1 << 12)) {
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP,
+        GST_TAG_BEATS_PER_MINUTE, TEST_BPM, NULL);
+  }
+  if (mask & (1 << 13)) {
+  }
+  return tags;
+}
+
+static gboolean
+utf8_string_in_buf (GstBuffer * buf, const gchar * s)
+{
+  gint i, len;
+  GstMapInfo map;
+
+  len = strlen (s);
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  for (i = 0; i < (map.size - len); ++i) {
+    if (memcmp (map.data + i, s, len) == 0) {
+      gst_buffer_unmap (buf, &map);
+      return TRUE;
+    }
+  }
+  gst_buffer_unmap (buf, &map);
+
+  return FALSE;
+}
+
+static void
+test_taglib_id3mux_check_tag_buffer (GstBuffer * buf, guint32 mask)
+{
+  /* make sure our UTF-8 string hasn't been put into the tag as ISO-8859-1 */
+  if (mask & (1 << 0)) {
+    fail_unless (utf8_string_in_buf (buf, TEST_ARTIST));
+  }
+  /* make sure our UTF-8 string hasn't been put into the tag as ISO-8859-1 */
+  if (mask & (1 << 1)) {
+    fail_unless (utf8_string_in_buf (buf, TEST_TITLE));
+  }
+  /* make sure our UTF-8 string hasn't been put into the tag as ISO-8859-1 */
+  if (mask & (1 << 2)) {
+    fail_unless (utf8_string_in_buf (buf, TEST_ALBUM));
+  }
+}
+
+static void
+test_taglib_id3mux_check_tags (GstTagList * tags, guint32 mask)
+{
+  if (mask & (1 << 0)) {
+    gchar *s = NULL;
+
+    fail_unless (gst_tag_list_get_string (tags, GST_TAG_ARTIST, &s));
+    fail_unless (g_str_equal (s, TEST_ARTIST));
+    g_free (s);
+  }
+  if (mask & (1 << 1)) {
+    gchar *s = NULL;
+
+    fail_unless (gst_tag_list_get_string (tags, GST_TAG_TITLE, &s));
+    fail_unless (g_str_equal (s, TEST_TITLE));
+    g_free (s);
+  }
+  if (mask & (1 << 2)) {
+    gchar *s = NULL;
+
+    fail_unless (gst_tag_list_get_string (tags, GST_TAG_ALBUM, &s));
+    fail_unless (g_str_equal (s, TEST_ALBUM));
+    g_free (s);
+  }
+  if (mask & (1 << 3)) {
+    GDate *shouldbe, *date = NULL;
+
+    shouldbe = TEST_DATE;
+    fail_unless (gst_tag_list_get_date (tags, GST_TAG_DATE, &date));
+    fail_unless (g_date_compare (shouldbe, date) == 0);
+    g_date_free (shouldbe);
+    g_date_free (date);
+  }
+  if (mask & (1 << 4)) {
+    guint num;
+
+    fail_unless (gst_tag_list_get_uint (tags, GST_TAG_TRACK_NUMBER, &num));
+    fail_unless (num == TEST_TRACK_NUMBER);
+  }
+  if (mask & (1 << 5)) {
+    guint count;
+
+    fail_unless (gst_tag_list_get_uint (tags, GST_TAG_TRACK_COUNT, &count));
+    fail_unless (count == TEST_TRACK_COUNT);
+  }
+  if (mask & (1 << 6)) {
+    guint num;
+
+    fail_unless (gst_tag_list_get_uint (tags, GST_TAG_ALBUM_VOLUME_NUMBER,
+            &num));
+    fail_unless (num == TEST_VOLUME_NUMBER);
+  }
+  if (mask & (1 << 7)) {
+    guint count;
+
+    fail_unless (gst_tag_list_get_uint (tags, GST_TAG_ALBUM_VOLUME_COUNT,
+            &count));
+    fail_unless (count == TEST_VOLUME_COUNT);
+  }
+  if (mask & (1 << 8)) {
+    gdouble gain;
+
+    fail_unless (gst_tag_list_get_double (tags, GST_TAG_TRACK_GAIN, &gain));
+    fail_unless_sorta_equals_float (gain, TEST_TRACK_GAIN);
+  }
+  if (mask & (1 << 9)) {
+    gdouble gain;
+
+    fail_unless (gst_tag_list_get_double (tags, GST_TAG_ALBUM_GAIN, &gain));
+    fail_unless_sorta_equals_float (gain, TEST_ALBUM_GAIN);
+  }
+  if (mask & (1 << 10)) {
+    gdouble peak;
+
+    fail_unless (gst_tag_list_get_double (tags, GST_TAG_TRACK_PEAK, &peak));
+    fail_unless_sorta_equals_float (peak, TEST_TRACK_PEAK);
+  }
+  if (mask & (1 << 11)) {
+    gdouble peak;
+
+    fail_unless (gst_tag_list_get_double (tags, GST_TAG_ALBUM_PEAK, &peak));
+    fail_unless_sorta_equals_float (peak, TEST_ALBUM_PEAK);
+  }
+  if (mask & (1 << 12)) {
+    gdouble bpm;
+
+    fail_unless (gst_tag_list_get_double (tags, GST_TAG_BEATS_PER_MINUTE,
+            &bpm));
+    fail_unless_sorta_equals_float (bpm, TEST_BPM);
+  }
+  if (mask & (1 << 13)) {
+  }
+}
+
+static void
+fill_mp3_buffer (GstElement * fakesrc, GstBuffer * buf, GstPad * pad,
+    guint64 * p_offset)
+{
+  gsize size;
+
+  size = gst_buffer_get_size (buf);
+
+  fail_unless (size == MP3_FRAME_SIZE);
+
+  GST_LOG ("filling buffer with fake mp3 data, offset = %" G_GUINT64_FORMAT,
+      *p_offset);
+
+  gst_buffer_fill (buf, 0, mp3_dummyhdr, sizeof (mp3_dummyhdr));
+
+#if 0
+  /* can't use gst_buffer_set_caps() here because the metadata isn't writable
+   * because of the extra refcounts taken by the signal emission mechanism;
+   * we know it's fine to use GST_BUFFER_CAPS() here though */
+  GST_BUFFER_CAPS (buf) = gst_caps_new_simple ("audio/mpeg", "mpegversion",
+      G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, NULL);
+#endif
+
+  GST_BUFFER_OFFSET (buf) = *p_offset;
+  *p_offset += size;
+}
+
+static void
+got_buffer (GstElement * fakesink, GstBuffer * buf, GstPad * pad,
+    GstBuffer ** p_buf)
+{
+  gint64 off;
+  GstMapInfo map;
+
+  off = GST_BUFFER_OFFSET (buf);
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  GST_LOG ("size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT, map.size, off);
+
+  fail_unless (GST_BUFFER_OFFSET_IS_VALID (buf));
+
+  if (*p_buf == NULL || (off + map.size) > gst_buffer_get_size (*p_buf)) {
+    GstBuffer *newbuf;
+
+    /* not very elegant, but who cares */
+    newbuf = gst_buffer_new_and_alloc (off + map.size);
+    if (*p_buf) {
+      GstMapInfo pmap;
+
+      gst_buffer_map (*p_buf, &pmap, GST_MAP_READ);
+      gst_buffer_fill (newbuf, 0, pmap.data, pmap.size);
+      gst_buffer_unmap (*p_buf, &pmap);
+    }
+    gst_buffer_fill (newbuf, off, map.data, map.size);
+
+    if (*p_buf)
+      gst_buffer_unref (*p_buf);
+    *p_buf = newbuf;
+  } else {
+    gst_buffer_fill (*p_buf, off, map.data, map.size);
+  }
+  gst_buffer_unmap (buf, &map);
+}
+
+static void
+test_taglib_id3mux_check_output_buffer (GstBuffer * buf)
+{
+  GstMapInfo map;
+  guint off;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  g_assert (map.size % MP3_FRAME_SIZE == 0);
+
+  for (off = 0; off < map.size; off += MP3_FRAME_SIZE) {
+    fail_unless (memcmp (map.data + off, mp3_dummyhdr,
+            sizeof (mp3_dummyhdr)) == 0);
+  }
+  gst_buffer_unmap (buf, &map);
+}
+
+static void
+identity_cb (GstElement * identity, GstBuffer * buf, GstBuffer ** p_tagbuf)
+{
+  if (*p_tagbuf == NULL) {
+    *p_tagbuf = gst_buffer_ref (buf);
+  }
+}
+
+static void
+test_taglib_id3mux_with_tags (GstTagList * tags, guint32 mask)
+{
+  GstMessage *msg;
+  GstTagList *tags_read = NULL;
+  GstElement *pipeline, *id3mux, *id3demux, *fakesrc, *identity, *fakesink;
+  GstBus *bus;
+  guint64 offset;
+  GstBuffer *outbuf = NULL;
+  GstBuffer *tagbuf = NULL;
+  GstStateChangeReturn state_result;
+
+  pipeline = gst_pipeline_new ("pipeline");
+  g_assert (pipeline != NULL);
+
+  fakesrc = gst_element_factory_make ("fakesrc", "fakesrc");
+  g_assert (fakesrc != NULL);
+
+  id3mux = gst_element_factory_make ("id3v2mux", "id3v2mux");
+  g_assert (id3mux != NULL);
+
+  identity = gst_element_factory_make ("identity", "identity");
+  g_assert (identity != NULL);
+
+  id3demux = gst_element_factory_make ("id3demux", "id3demux");
+  g_assert (id3demux != NULL);
+
+  fakesink = gst_element_factory_make ("fakesink", "fakesink");
+  g_assert (fakesink != NULL);
+
+  /* set up sink */
+  outbuf = NULL;
+  g_object_set (fakesink, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (fakesink, "handoff", G_CALLBACK (got_buffer), &outbuf);
+
+  gst_bin_add (GST_BIN (pipeline), fakesrc);
+  gst_bin_add (GST_BIN (pipeline), id3mux);
+  gst_bin_add (GST_BIN (pipeline), identity);
+  gst_bin_add (GST_BIN (pipeline), id3demux);
+  gst_bin_add (GST_BIN (pipeline), fakesink);
+
+  gst_tag_setter_merge_tags (GST_TAG_SETTER (id3mux), tags,
+      GST_TAG_MERGE_APPEND);
+
+  gst_element_link_many (fakesrc, id3mux, identity, id3demux, fakesink, NULL);
+
+  /* set up source */
+  g_object_set (fakesrc, "signal-handoffs", TRUE, "can-activate-pull", FALSE,
+      "filltype", 2, "sizetype", 2, "sizemax", MP3_FRAME_SIZE,
+      "num-buffers", 16, NULL);
+
+  offset = 0;
+  g_signal_connect (fakesrc, "handoff", G_CALLBACK (fill_mp3_buffer), &offset);
+
+  /* set up identity to catch tag buffer */
+  g_signal_connect (identity, "handoff", G_CALLBACK (identity_cb), &tagbuf);
+
+  GST_LOG ("setting and getting state ...");
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  state_result = gst_element_get_state (pipeline, NULL, NULL, -1);
+  fail_unless (state_result == GST_STATE_CHANGE_SUCCESS,
+      "Unexpected result from get_state(). Expected success, got %d",
+      state_result);
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+
+  GST_LOG ("Waiting for tag ...");
+  msg =
+      gst_bus_poll (bus, GST_MESSAGE_TAG | GST_MESSAGE_EOS | GST_MESSAGE_ERROR,
+      -1);
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
+    GError *err;
+    gchar *dbg;
+
+    gst_message_parse_error (msg, &err, &dbg);
+    g_printerr ("ERROR from element %s: %s\n%s\n",
+        GST_OBJECT_NAME (msg->src), err->message, GST_STR_NULL (dbg));
+    g_error_free (err);
+    g_free (dbg);
+  } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) {
+    g_printerr ("EOS message, but were waiting for TAGS!\n");
+  }
+  fail_unless (msg->type == GST_MESSAGE_TAG);
+
+  gst_message_parse_tag (msg, &tags_read);
+  gst_message_unref (msg);
+
+  GST_LOG ("Got tags: %" GST_PTR_FORMAT, tags_read);
+  test_taglib_id3mux_check_tags (tags_read, mask);
+  gst_tag_list_unref (tags_read);
+
+  fail_unless (tagbuf != NULL);
+  test_taglib_id3mux_check_tag_buffer (tagbuf, mask);
+  gst_buffer_unref (tagbuf);
+
+  GST_LOG ("Waiting for EOS ...");
+  msg = gst_bus_poll (bus, GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
+    GError *err;
+    gchar *dbg;
+
+    gst_message_parse_error (msg, &err, &dbg);
+    g_printerr ("ERROR from element %s: %s\n%s\n",
+        GST_OBJECT_NAME (msg->src), err->message, GST_STR_NULL (dbg));
+    g_error_free (err);
+    g_free (dbg);
+  }
+  fail_unless (msg->type == GST_MESSAGE_EOS);
+  gst_message_unref (msg);
+
+  gst_object_unref (bus);
+
+  GST_LOG ("Got EOS, shutting down ...");
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+
+  test_taglib_id3mux_check_output_buffer (outbuf);
+  gst_buffer_unref (outbuf);
+
+  GST_LOG ("Done");
+}
+
+GST_START_TEST (test_id3v2mux)
+{
+  GstTagList *tags;
+  gint i;
+
+  g_random_set_seed (247166295);
+
+  /* internal consistency check */
+  tags = test_taglib_id3mux_create_tags (0xFFFFFFFF);
+  test_taglib_id3mux_check_tags (tags, 0xFFFFFFFF);
+  gst_tag_list_unref (tags);
+
+  /* now the real tests */
+  for (i = 0; i < 50; ++i) {
+    guint32 mask;
+
+    mask = g_random_int ();
+    GST_LOG ("tag mask = %08x (i=%d)", mask, i);
+
+    if (mask == 0)
+      continue;
+
+    /* create tags */
+    tags = test_taglib_id3mux_create_tags (mask);
+    GST_LOG ("tags for mask %08x = %" GST_PTR_FORMAT, mask, tags);
+
+    /* double-check for internal consistency */
+    test_taglib_id3mux_check_tags (tags, mask);
+
+    /* test with pipeline */
+    test_taglib_id3mux_with_tags (tags, mask);
+
+    /* free tags */
+    gst_tag_list_unref (tags);
+  }
+}
+
+GST_END_TEST;
+
+static Suite *
+id3v2mux_suite (void)
+{
+  Suite *s = suite_create ("id3v2mux");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_id3v2mux);
+
+  return s;
+}
+
+GST_CHECK_MAIN (id3v2mux);
diff --git a/tests/check/elements/imagefreeze.c b/tests/check/elements/imagefreeze.c
new file mode 100644
index 0000000..cfeff37
--- /dev/null
+++ b/tests/check/elements/imagefreeze.c
@@ -0,0 +1,586 @@
+/* GStreamer
+ * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+
+#include <gst/check/gstcheck.h>
+#include <gst/video/video.h>
+
+static gboolean
+bus_handler (GstBus * bus, GstMessage * message, gpointer data)
+{
+  GMainLoop *loop = (GMainLoop *) data;
+
+  switch (message->type) {
+    case GST_MESSAGE_EOS:
+      g_main_loop_quit (loop);
+      break;
+    case GST_MESSAGE_WARNING:
+    case GST_MESSAGE_ERROR:{
+      GError *gerror;
+      gchar *debug;
+
+      if (message->type == GST_MESSAGE_WARNING)
+        gst_message_parse_warning (message, &gerror, &debug);
+      else
+        gst_message_parse_error (message, &gerror, &debug);
+      g_error ("error from %s: %s (%s)\n",
+          GST_ELEMENT_NAME (GST_MESSAGE_SRC (message)), gerror->message,
+          GST_STR_NULL (debug));
+      g_error_free (gerror);
+      g_free (debug);
+      g_main_loop_quit (loop);
+      break;
+    }
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+static GstElement *
+setup_imagefreeze (const GstCaps * caps1, const GstCaps * caps2,
+    GCallback sink_handoff, gpointer sink_handoff_data)
+{
+  GstElement *pipeline;
+  GstElement *videotestsrc, *capsfilter1, *imagefreeze, *capsfilter2, *fakesink;
+
+  pipeline = gst_pipeline_new ("pipeline");
+  fail_unless (pipeline != NULL);
+
+  videotestsrc = gst_element_factory_make ("videotestsrc", "src");
+  fail_unless (videotestsrc != NULL);
+  g_object_set (videotestsrc, "num-buffers", 1, NULL);
+
+  capsfilter1 = gst_element_factory_make ("capsfilter", "filter1");
+  fail_unless (capsfilter1 != NULL);
+  g_object_set (capsfilter1, "caps", caps1, NULL);
+
+  imagefreeze = gst_element_factory_make ("imagefreeze", "freeze");
+  fail_unless (imagefreeze != NULL);
+
+  capsfilter2 = gst_element_factory_make ("capsfilter", "filter2");
+  fail_unless (capsfilter2 != NULL);
+  g_object_set (capsfilter2, "caps", caps2, NULL);
+
+  fakesink = gst_element_factory_make ("fakesink", "sink");
+  fail_unless (fakesink != NULL);
+  g_object_set (fakesink, "signal-handoffs", TRUE, "async", FALSE, NULL);
+
+  if (sink_handoff)
+    g_signal_connect (fakesink, "handoff", sink_handoff, sink_handoff_data);
+
+  gst_bin_add_many (GST_BIN (pipeline), videotestsrc, capsfilter1, imagefreeze,
+      capsfilter2, fakesink, NULL);
+
+  fail_unless (gst_element_link_pads (videotestsrc, "src", capsfilter1,
+          "sink"));
+  fail_unless (gst_element_link_pads (capsfilter1, "src", imagefreeze, "sink"));
+  fail_unless (gst_element_link_pads (imagefreeze, "src", capsfilter2, "sink"));
+  fail_unless (gst_element_link_pads (capsfilter2, "src", fakesink, "sink"));
+
+  return pipeline;
+}
+
+static void
+sink_handoff_cb_0_1 (GstElement * object, GstBuffer * buffer, GstPad * pad,
+    gpointer user_data)
+{
+  guint *n_buffers = (guint *) user_data;
+
+  if (*n_buffers == G_MAXUINT)
+    return;
+
+  fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buffer), 0);
+  fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer), GST_CLOCK_TIME_NONE);
+  fail_unless_equals_uint64 (GST_BUFFER_OFFSET (buffer), 0);
+  fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (buffer), 1);
+
+  *n_buffers = *n_buffers + 1;
+}
+
+GST_START_TEST (test_imagefreeze_0_1)
+{
+  GstElement *pipeline;
+  GstCaps *caps1, *caps2;
+  GstBus *bus;
+  GMainLoop *loop;
+  guint n_buffers = G_MAXUINT;
+  guint bus_watch = 0;
+  GstVideoInfo i1, i2;
+
+  gst_video_info_init (&i1);
+  gst_video_info_set_format (&i1, GST_VIDEO_FORMAT_xRGB, 640, 480);
+  i1.fps_n = 25;
+  i1.fps_d = 1;
+  caps1 = gst_video_info_to_caps (&i1);
+
+  gst_video_info_init (&i2);
+  gst_video_info_set_format (&i2, GST_VIDEO_FORMAT_xRGB, 640, 480);
+  caps2 = gst_video_info_to_caps (&i2);
+
+  pipeline =
+      setup_imagefreeze (caps1, caps2, G_CALLBACK (sink_handoff_cb_0_1),
+      &n_buffers);
+
+  loop = g_main_loop_new (NULL, TRUE);
+  fail_unless (loop != NULL);
+
+  bus = gst_element_get_bus (pipeline);
+  fail_unless (bus != NULL);
+  bus_watch = gst_bus_add_watch (bus, bus_handler, loop);
+  gst_object_unref (bus);
+
+  n_buffers = 0;
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_SUCCESS);
+
+  g_main_loop_run (loop);
+
+  fail_unless_equals_int (n_buffers, 1);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  gst_object_unref (pipeline);
+  g_main_loop_unref (loop);
+  gst_caps_unref (caps1);
+  gst_caps_unref (caps2);
+  g_source_remove (bus_watch);
+}
+
+GST_END_TEST;
+
+static void
+sink_handoff_cb_25_1_0ms_400ms (GstElement * object, GstBuffer * buffer,
+    GstPad * pad, gpointer user_data)
+{
+  guint *n_buffers = (guint *) user_data;
+
+  if (*n_buffers == G_MAXUINT)
+    return;
+
+  fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buffer),
+      *n_buffers * 40 * GST_MSECOND);
+  fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer), 40 * GST_MSECOND);
+  fail_unless_equals_uint64 (GST_BUFFER_OFFSET (buffer), *n_buffers);
+  fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (buffer), *n_buffers + 1);
+
+  *n_buffers = *n_buffers + 1;
+}
+
+GST_START_TEST (test_imagefreeze_25_1_0ms_400ms)
+{
+  GstElement *pipeline;
+  GstCaps *caps1, *caps2;
+  GstBus *bus;
+  GMainLoop *loop;
+  guint n_buffers = G_MAXUINT;
+  guint bus_watch = 0;
+  GstVideoInfo i1, i2;
+
+  gst_video_info_init (&i1);
+  gst_video_info_set_format (&i1, GST_VIDEO_FORMAT_xRGB, 640, 480);
+  i1.fps_n = 25;
+  i1.fps_d = 1;
+  caps1 = gst_video_info_to_caps (&i1);
+
+  gst_video_info_init (&i2);
+  gst_video_info_set_format (&i2, GST_VIDEO_FORMAT_xRGB, 640, 480);
+  i2.fps_n = 25;
+  i2.fps_d = 1;
+  caps2 = gst_video_info_to_caps (&i2);
+
+  pipeline =
+      setup_imagefreeze (caps1, caps2,
+      G_CALLBACK (sink_handoff_cb_25_1_0ms_400ms), &n_buffers);
+
+  loop = g_main_loop_new (NULL, TRUE);
+  fail_unless (loop != NULL);
+
+  bus = gst_element_get_bus (pipeline);
+  fail_unless (bus != NULL);
+  bus_watch = gst_bus_add_watch (bus, bus_handler, loop);
+  gst_object_unref (bus);
+
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PAUSED),
+      GST_STATE_CHANGE_SUCCESS);
+
+  fail_unless (gst_element_seek (pipeline, 1.0, GST_FORMAT_TIME,
+          GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET,
+          400 * GST_MSECOND));
+
+  n_buffers = 0;
+
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_SUCCESS);
+
+  g_main_loop_run (loop);
+
+  fail_unless_equals_int (n_buffers, 10);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  gst_object_unref (pipeline);
+  g_main_loop_unref (loop);
+  gst_caps_unref (caps1);
+  gst_caps_unref (caps2);
+  g_source_remove (bus_watch);
+}
+
+GST_END_TEST;
+
+static void
+sink_handoff_cb_25_1_200ms_400ms (GstElement * object, GstBuffer * buffer,
+    GstPad * pad, gpointer user_data)
+{
+  guint *n_buffers = (guint *) user_data;
+
+  if (*n_buffers == G_MAXUINT)
+    return;
+
+  fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buffer),
+      200 * GST_MSECOND + *n_buffers * 40 * GST_MSECOND);
+  fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer), 40 * GST_MSECOND);
+  fail_unless_equals_uint64 (GST_BUFFER_OFFSET (buffer), 5 + *n_buffers);
+  fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (buffer),
+      5 + *n_buffers + 1);
+
+  *n_buffers = *n_buffers + 1;
+}
+
+GST_START_TEST (test_imagefreeze_25_1_200ms_400ms)
+{
+  GstElement *pipeline;
+  GstCaps *caps1, *caps2;
+  GstBus *bus;
+  GMainLoop *loop;
+  guint n_buffers = G_MAXUINT;
+  guint bus_watch = 0;
+  GstVideoInfo i1, i2;
+
+  gst_video_info_init (&i1);
+  gst_video_info_set_format (&i1, GST_VIDEO_FORMAT_xRGB, 640, 480);
+  i1.fps_n = 25;
+  i1.fps_d = 1;
+  caps1 = gst_video_info_to_caps (&i1);
+
+  gst_video_info_init (&i2);
+  gst_video_info_set_format (&i2, GST_VIDEO_FORMAT_xRGB, 640, 480);
+  i2.fps_n = 25;
+  i2.fps_d = 1;
+  caps2 = gst_video_info_to_caps (&i2);
+
+  pipeline =
+      setup_imagefreeze (caps1, caps2,
+      G_CALLBACK (sink_handoff_cb_25_1_200ms_400ms), &n_buffers);
+
+  loop = g_main_loop_new (NULL, TRUE);
+  fail_unless (loop != NULL);
+
+  bus = gst_element_get_bus (pipeline);
+  fail_unless (bus != NULL);
+  bus_watch = gst_bus_add_watch (bus, bus_handler, loop);
+  gst_object_unref (bus);
+
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PAUSED),
+      GST_STATE_CHANGE_SUCCESS);
+
+  fail_unless (gst_element_seek (pipeline, 1.0, GST_FORMAT_TIME,
+          GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 200 * GST_MSECOND,
+          GST_SEEK_TYPE_SET, 400 * GST_MSECOND));
+
+  n_buffers = 0;
+
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_SUCCESS);
+
+  g_main_loop_run (loop);
+
+  fail_unless_equals_int (n_buffers, 5);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  gst_object_unref (pipeline);
+  g_main_loop_unref (loop);
+  gst_caps_unref (caps1);
+  gst_caps_unref (caps2);
+  g_source_remove (bus_watch);
+}
+
+GST_END_TEST;
+
+static void
+sink_handoff_cb_25_1_400ms_0ms (GstElement * object, GstBuffer * buffer,
+    GstPad * pad, gpointer user_data)
+{
+  guint *n_buffers = (guint *) user_data;
+
+  if (*n_buffers == G_MAXUINT)
+    return;
+
+  fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buffer),
+      400 * GST_MSECOND - (*n_buffers + 1) * 40 * GST_MSECOND);
+  fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer), 40 * GST_MSECOND);
+  fail_unless_equals_uint64 (GST_BUFFER_OFFSET (buffer), 10 - (*n_buffers + 1));
+  fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (buffer),
+      10 - (*n_buffers + 1) + 1);
+
+  *n_buffers = *n_buffers + 1;
+}
+
+GST_START_TEST (test_imagefreeze_25_1_400ms_0ms)
+{
+  GstElement *pipeline;
+  GstCaps *caps1, *caps2;
+  GstBus *bus;
+  GMainLoop *loop;
+  guint n_buffers = G_MAXUINT;
+  guint bus_watch = 0;
+  GstVideoInfo i1, i2;
+
+  gst_video_info_init (&i1);
+  gst_video_info_set_format (&i1, GST_VIDEO_FORMAT_xRGB, 640, 480);
+  i1.fps_n = 25;
+  i1.fps_d = 1;
+  caps1 = gst_video_info_to_caps (&i1);
+
+  gst_video_info_init (&i2);
+  gst_video_info_set_format (&i2, GST_VIDEO_FORMAT_xRGB, 640, 480);
+  i2.fps_n = 25;
+  i2.fps_d = 1;
+  caps2 = gst_video_info_to_caps (&i2);
+
+  pipeline =
+      setup_imagefreeze (caps1, caps2,
+      G_CALLBACK (sink_handoff_cb_25_1_400ms_0ms), &n_buffers);
+
+  loop = g_main_loop_new (NULL, TRUE);
+  fail_unless (loop != NULL);
+
+  bus = gst_element_get_bus (pipeline);
+  fail_unless (bus != NULL);
+  bus_watch = gst_bus_add_watch (bus, bus_handler, loop);
+  gst_object_unref (bus);
+
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PAUSED),
+      GST_STATE_CHANGE_SUCCESS);
+
+  fail_unless (gst_element_seek (pipeline, -1.0, GST_FORMAT_TIME,
+          GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET,
+          400 * GST_MSECOND));
+
+  n_buffers = 0;
+
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_SUCCESS);
+
+  g_main_loop_run (loop);
+
+  fail_unless_equals_int (n_buffers, 10);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  gst_object_unref (pipeline);
+  g_main_loop_unref (loop);
+  gst_caps_unref (caps1);
+  gst_caps_unref (caps2);
+  g_source_remove (bus_watch);
+}
+
+GST_END_TEST;
+
+static void
+sink_handoff_cb_25_1_220ms_380ms (GstElement * object, GstBuffer * buffer,
+    GstPad * pad, gpointer user_data)
+{
+  guint *n_buffers = (guint *) user_data;
+
+  if (*n_buffers == G_MAXUINT)
+    return;
+
+  if (*n_buffers == 0) {
+    fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buffer),
+        220 * GST_MSECOND);
+    fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer), 20 * GST_MSECOND);
+  } else if (*n_buffers == 4) {
+    fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buffer),
+        360 * GST_MSECOND);
+    fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer), 20 * GST_MSECOND);
+  } else {
+    fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buffer),
+        200 * GST_MSECOND + *n_buffers * 40 * GST_MSECOND);
+    fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer), 40 * GST_MSECOND);
+  }
+
+  fail_unless_equals_uint64 (GST_BUFFER_OFFSET (buffer), 5 + *n_buffers);
+  fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (buffer),
+      5 + *n_buffers + 1);
+
+  *n_buffers = *n_buffers + 1;
+}
+
+GST_START_TEST (test_imagefreeze_25_1_220ms_380ms)
+{
+  GstElement *pipeline;
+  GstCaps *caps1, *caps2;
+  GstBus *bus;
+  GMainLoop *loop;
+  guint n_buffers = G_MAXUINT;
+  guint bus_watch = 0;
+  GstVideoInfo i1, i2;
+
+  gst_video_info_init (&i1);
+  gst_video_info_set_format (&i1, GST_VIDEO_FORMAT_xRGB, 640, 480);
+  i1.fps_n = 25;
+  i1.fps_d = 1;
+  caps1 = gst_video_info_to_caps (&i1);
+
+  gst_video_info_init (&i2);
+  gst_video_info_set_format (&i2, GST_VIDEO_FORMAT_xRGB, 640, 480);
+  i2.fps_n = 25;
+  i2.fps_d = 1;
+  caps2 = gst_video_info_to_caps (&i2);
+
+  pipeline =
+      setup_imagefreeze (caps1, caps2,
+      G_CALLBACK (sink_handoff_cb_25_1_220ms_380ms), &n_buffers);
+
+  loop = g_main_loop_new (NULL, TRUE);
+  fail_unless (loop != NULL);
+
+  bus = gst_element_get_bus (pipeline);
+  fail_unless (bus != NULL);
+  bus_watch = gst_bus_add_watch (bus, bus_handler, loop);
+  gst_object_unref (bus);
+
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PAUSED),
+      GST_STATE_CHANGE_SUCCESS);
+
+  fail_unless (gst_element_seek (pipeline, 1.0, GST_FORMAT_TIME,
+          GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 220 * GST_MSECOND,
+          GST_SEEK_TYPE_SET, 380 * GST_MSECOND));
+
+  n_buffers = 0;
+
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_SUCCESS);
+
+  g_main_loop_run (loop);
+
+  fail_unless_equals_int (n_buffers, 5);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  gst_object_unref (pipeline);
+  g_main_loop_unref (loop);
+  gst_caps_unref (caps1);
+  gst_caps_unref (caps2);
+  g_source_remove (bus_watch);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_imagefreeze_eos)
+{
+  GstElement *pipeline;
+  GstElement *src;
+  GstCaps *caps1, *caps2;
+  GstBus *bus;
+  GMainLoop *loop;
+  GstFormat fmt = GST_FORMAT_TIME;
+  gint64 position;
+  guint bus_watch = 0;
+  GstVideoInfo i1, i2;
+
+  gst_video_info_init (&i1);
+  gst_video_info_set_format (&i1, GST_VIDEO_FORMAT_xRGB, 640, 480);
+  i1.fps_n = 25;
+  i1.fps_d = 1;
+  caps1 = gst_video_info_to_caps (&i1);
+
+  gst_video_info_init (&i2);
+  gst_video_info_set_format (&i2, GST_VIDEO_FORMAT_xRGB, 640, 480);
+  i2.fps_n = 25;
+  i2.fps_d = 1;
+  caps2 = gst_video_info_to_caps (&i2);
+
+  pipeline = setup_imagefreeze (caps1, caps2, NULL, NULL);
+
+  src = gst_bin_get_by_name (GST_BIN (pipeline), "src");
+  fail_unless (src != NULL);
+  g_object_set (src, "num-buffers", 100, NULL);
+
+  loop = g_main_loop_new (NULL, TRUE);
+  fail_unless (loop != NULL);
+
+  bus = gst_element_get_bus (pipeline);
+  fail_unless (bus != NULL);
+  bus_watch = gst_bus_add_watch (bus, bus_handler, loop);
+  gst_object_unref (bus);
+
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PAUSED),
+      GST_STATE_CHANGE_SUCCESS);
+
+  fail_unless (gst_element_seek (pipeline, 1.0, GST_FORMAT_TIME,
+          GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET,
+          400 * GST_MSECOND));
+
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_SUCCESS);
+
+  g_main_loop_run (loop);
+
+  fail_unless (gst_element_query_position (src, fmt, &position));
+  fail_unless_equals_uint64 (position, 40 * GST_MSECOND);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  gst_object_unref (src);
+  gst_object_unref (pipeline);
+  g_main_loop_unref (loop);
+  gst_caps_unref (caps1);
+  gst_caps_unref (caps2);
+  g_source_remove (bus_watch);
+}
+
+GST_END_TEST;
+
+static Suite *
+imagefreeze_suite (void)
+{
+  Suite *s = suite_create ("imagefreeze");
+  TCase *tc_chain = tcase_create ("linear");
+
+  /* time out after 120s, not the default 3 */
+  tcase_set_timeout (tc_chain, 120);
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_imagefreeze_0_1);
+  tcase_add_test (tc_chain, test_imagefreeze_25_1_0ms_400ms);
+  tcase_add_test (tc_chain, test_imagefreeze_25_1_200ms_400ms);
+  tcase_add_test (tc_chain, test_imagefreeze_25_1_400ms_0ms);
+  tcase_add_test (tc_chain, test_imagefreeze_25_1_220ms_380ms);
+
+  tcase_add_test (tc_chain, test_imagefreeze_eos);
+
+  return s;
+}
+
+GST_CHECK_MAIN (imagefreeze);
diff --git a/tests/check/elements/interleave.c b/tests/check/elements/interleave.c
new file mode 100644
index 0000000..0d9d562
--- /dev/null
+++ b/tests/check/elements/interleave.c
@@ -0,0 +1,826 @@
+/* GStreamer unit tests for the interleave element
+ * Copyright (C) 2007 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_VALGRIND
+# include <valgrind/valgrind.h>
+#endif
+
+#include <gst/check/gstcheck.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/audio-enumtypes.h>
+
+static void
+gst_check_setup_events_interleave (GstPad * srcpad, GstElement * element,
+    GstCaps * caps, GstFormat format, const gchar * stream_id)
+{
+  GstSegment segment;
+
+  gst_segment_init (&segment, format);
+
+  fail_unless (gst_pad_push_event (srcpad,
+          gst_event_new_stream_start (stream_id)));
+  if (caps)
+    fail_unless (gst_pad_push_event (srcpad, gst_event_new_caps (caps)));
+  fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&segment)));
+}
+
+GST_START_TEST (test_create_and_unref)
+{
+  GstElement *interleave;
+
+  interleave = gst_element_factory_make ("interleave", NULL);
+  fail_unless (interleave != NULL);
+
+  gst_element_set_state (interleave, GST_STATE_NULL);
+  gst_object_unref (interleave);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_request_pads)
+{
+  GstElement *interleave;
+  GstPad *pad1, *pad2;
+
+  interleave = gst_element_factory_make ("interleave", NULL);
+  fail_unless (interleave != NULL);
+
+  pad1 = gst_element_get_request_pad (interleave, "sink_%u");
+  fail_unless (pad1 != NULL);
+  fail_unless_equals_string (GST_OBJECT_NAME (pad1), "sink_0");
+
+  pad2 = gst_element_get_request_pad (interleave, "sink_%u");
+  fail_unless (pad2 != NULL);
+  fail_unless_equals_string (GST_OBJECT_NAME (pad2), "sink_1");
+
+  gst_element_release_request_pad (interleave, pad2);
+  gst_object_unref (pad2);
+  gst_element_release_request_pad (interleave, pad1);
+  gst_object_unref (pad1);
+
+  gst_element_set_state (interleave, GST_STATE_NULL);
+  gst_object_unref (interleave);
+}
+
+GST_END_TEST;
+
+static GstPad **mysrcpads, *mysinkpad;
+static GstBus *bus;
+static GstElement *interleave;
+static gint have_data;
+static gfloat input[2];
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (F32) ", "
+        "channels = (int) 2, layout = (string) {interleaved, non-interleaved}, rate = (int) 48000"));
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " GST_AUDIO_NE (F32) ", "
+        "channels = (int) 1, layout = (string) interleaved, rate = (int) 48000"));
+
+#define CAPS_48khz \
+        "audio/x-raw, " \
+        "format = (string) " GST_AUDIO_NE (F32) ", " \
+        "channels = (int) 1, layout = (string) non-interleaved," \
+        "rate = (int) 48000"
+
+static GstFlowReturn
+interleave_chain_func (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  GstMapInfo map;
+  gfloat *outdata;
+  gint i;
+
+  fail_unless (GST_IS_BUFFER (buffer));
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  outdata = (gfloat *) map.data;
+  fail_unless_equals_int (map.size, 48000 * 2 * sizeof (gfloat));
+  fail_unless (outdata != NULL);
+
+#ifdef HAVE_VALGRIND
+  if (!(RUNNING_ON_VALGRIND))
+#endif
+    for (i = 0; i < 48000 * 2; i += 2) {
+      fail_unless_equals_float (outdata[i], input[0]);
+      fail_unless_equals_float (outdata[i + 1], input[1]);
+    }
+  gst_buffer_unmap (buffer, &map);
+  gst_buffer_unref (buffer);
+
+  have_data++;
+
+  return GST_FLOW_OK;
+}
+
+GST_START_TEST (test_interleave_2ch)
+{
+  GstElement *queue;
+  GstPad *sink0, *sink1, *src, *tmp;
+  GstCaps *caps;
+  gint i;
+  GstBuffer *inbuf;
+  gfloat *indata;
+  GstMapInfo map;
+
+  mysrcpads = g_new0 (GstPad *, 2);
+
+  have_data = 0;
+
+  interleave = gst_element_factory_make ("interleave", NULL);
+  fail_unless (interleave != NULL);
+
+  queue = gst_element_factory_make ("queue", "queue");
+  fail_unless (queue != NULL);
+
+  sink0 = gst_element_get_request_pad (interleave, "sink_%u");
+  fail_unless (sink0 != NULL);
+  fail_unless_equals_string (GST_OBJECT_NAME (sink0), "sink_0");
+
+  sink1 = gst_element_get_request_pad (interleave, "sink_%u");
+  fail_unless (sink1 != NULL);
+  fail_unless_equals_string (GST_OBJECT_NAME (sink1), "sink_1");
+
+  mysrcpads[0] = gst_pad_new_from_static_template (&srctemplate, "src0");
+  fail_unless (mysrcpads[0] != NULL);
+
+  caps = gst_caps_from_string (CAPS_48khz);
+  gst_pad_set_active (mysrcpads[0], TRUE);
+  gst_check_setup_events_interleave (mysrcpads[0], interleave, caps,
+      GST_FORMAT_TIME, "0");
+  gst_pad_use_fixed_caps (mysrcpads[0]);
+
+  mysrcpads[1] = gst_pad_new_from_static_template (&srctemplate, "src1");
+  fail_unless (mysrcpads[1] != NULL);
+
+  gst_pad_set_active (mysrcpads[1], TRUE);
+  gst_check_setup_events_interleave (mysrcpads[1], interleave, caps,
+      GST_FORMAT_TIME, "1");
+  gst_pad_use_fixed_caps (mysrcpads[1]);
+
+  tmp = gst_element_get_static_pad (queue, "sink");
+  fail_unless (gst_pad_link (mysrcpads[0], tmp) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+  tmp = gst_element_get_static_pad (queue, "src");
+  fail_unless (gst_pad_link (tmp, sink0) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+
+  fail_unless (gst_pad_link (mysrcpads[1], sink1) == GST_PAD_LINK_OK);
+
+  mysinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");
+  fail_unless (mysinkpad != NULL);
+  gst_pad_set_chain_function (mysinkpad, interleave_chain_func);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  src = gst_element_get_static_pad (interleave, "src");
+  fail_unless (src != NULL);
+  fail_unless (gst_pad_link (src, mysinkpad) == GST_PAD_LINK_OK);
+  gst_object_unref (src);
+
+  bus = gst_bus_new ();
+  gst_element_set_bus (interleave, bus);
+
+  fail_unless (gst_element_set_state (interleave,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
+  fail_unless (gst_element_set_state (queue,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
+
+  input[0] = -1.0;
+  inbuf = gst_buffer_new_and_alloc (48000 * sizeof (gfloat));
+  gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
+  indata = (gfloat *) map.data;
+  for (i = 0; i < 48000; i++)
+    indata[i] = -1.0;
+  gst_buffer_unmap (inbuf, &map);
+  fail_unless (gst_pad_push (mysrcpads[0], inbuf) == GST_FLOW_OK);
+
+  input[1] = 1.0;
+  inbuf = gst_buffer_new_and_alloc (48000 * sizeof (gfloat));
+  gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
+  indata = (gfloat *) map.data;
+  for (i = 0; i < 48000; i++)
+    indata[i] = 1.0;
+  gst_buffer_unmap (inbuf, &map);
+  fail_unless (gst_pad_push (mysrcpads[1], inbuf) == GST_FLOW_OK);
+
+  inbuf = gst_buffer_new_and_alloc (48000 * sizeof (gfloat));
+  gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
+  indata = (gfloat *) map.data;
+  for (i = 0; i < 48000; i++)
+    indata[i] = -1.0;
+  gst_buffer_unmap (inbuf, &map);
+  fail_unless (gst_pad_push (mysrcpads[0], inbuf) == GST_FLOW_OK);
+
+  inbuf = gst_buffer_new_and_alloc (48000 * sizeof (gfloat));
+  gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
+  indata = (gfloat *) map.data;
+  for (i = 0; i < 48000; i++)
+    indata[i] = 1.0;
+  gst_buffer_unmap (inbuf, &map);
+  fail_unless (gst_pad_push (mysrcpads[1], inbuf) == GST_FLOW_OK);
+
+  fail_unless (have_data == 2);
+
+  gst_bus_set_flushing (bus, TRUE);
+  gst_element_set_state (interleave, GST_STATE_NULL);
+  gst_element_set_state (queue, GST_STATE_NULL);
+
+  gst_object_unref (mysrcpads[0]);
+  gst_object_unref (mysrcpads[1]);
+  gst_object_unref (mysinkpad);
+
+  gst_element_release_request_pad (interleave, sink0);
+  gst_object_unref (sink0);
+  gst_element_release_request_pad (interleave, sink1);
+  gst_object_unref (sink1);
+
+  gst_object_unref (interleave);
+  gst_object_unref (queue);
+  gst_object_unref (bus);
+  gst_caps_unref (caps);
+
+  g_free (mysrcpads);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_interleave_2ch_1eos)
+{
+  GstElement *queue;
+  GstPad *sink0, *sink1, *src, *tmp;
+  GstCaps *caps;
+  gint i;
+  GstBuffer *inbuf;
+  gfloat *indata;
+  GstMapInfo map;
+
+  mysrcpads = g_new0 (GstPad *, 2);
+
+  have_data = 0;
+
+  interleave = gst_element_factory_make ("interleave", NULL);
+  fail_unless (interleave != NULL);
+
+  queue = gst_element_factory_make ("queue", "queue");
+  fail_unless (queue != NULL);
+
+  sink0 = gst_element_get_request_pad (interleave, "sink_%u");
+  fail_unless (sink0 != NULL);
+  fail_unless_equals_string (GST_OBJECT_NAME (sink0), "sink_0");
+
+  sink1 = gst_element_get_request_pad (interleave, "sink_%u");
+  fail_unless (sink1 != NULL);
+  fail_unless_equals_string (GST_OBJECT_NAME (sink1), "sink_1");
+
+  mysrcpads[0] = gst_pad_new_from_static_template (&srctemplate, "src0");
+  fail_unless (mysrcpads[0] != NULL);
+
+  caps = gst_caps_from_string (CAPS_48khz);
+  gst_pad_set_active (mysrcpads[0], TRUE);
+  gst_check_setup_events_interleave (mysrcpads[0], interleave, caps,
+      GST_FORMAT_TIME, "0");
+  gst_pad_use_fixed_caps (mysrcpads[0]);
+
+  mysrcpads[1] = gst_pad_new_from_static_template (&srctemplate, "src1");
+  fail_unless (mysrcpads[1] != NULL);
+
+  gst_pad_set_active (mysrcpads[1], TRUE);
+  gst_check_setup_events_interleave (mysrcpads[1], interleave, caps,
+      GST_FORMAT_TIME, "1");
+  gst_pad_use_fixed_caps (mysrcpads[1]);
+
+  tmp = gst_element_get_static_pad (queue, "sink");
+  fail_unless (gst_pad_link (mysrcpads[0], tmp) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+  tmp = gst_element_get_static_pad (queue, "src");
+  fail_unless (gst_pad_link (tmp, sink0) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+
+  fail_unless (gst_pad_link (mysrcpads[1], sink1) == GST_PAD_LINK_OK);
+
+  mysinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");
+  fail_unless (mysinkpad != NULL);
+  gst_pad_set_chain_function (mysinkpad, interleave_chain_func);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  src = gst_element_get_static_pad (interleave, "src");
+  fail_unless (src != NULL);
+  fail_unless (gst_pad_link (src, mysinkpad) == GST_PAD_LINK_OK);
+  gst_object_unref (src);
+
+  bus = gst_bus_new ();
+  gst_element_set_bus (interleave, bus);
+
+  fail_unless (gst_element_set_state (interleave,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
+  fail_unless (gst_element_set_state (queue,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
+
+  input[0] = -1.0;
+  inbuf = gst_buffer_new_and_alloc (48000 * sizeof (gfloat));
+  gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
+  indata = (gfloat *) map.data;
+  for (i = 0; i < 48000; i++)
+    indata[i] = -1.0;
+  gst_buffer_unmap (inbuf, &map);
+  fail_unless (gst_pad_push (mysrcpads[0], inbuf) == GST_FLOW_OK);
+
+  input[1] = 1.0;
+  inbuf = gst_buffer_new_and_alloc (48000 * sizeof (gfloat));
+  gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
+  indata = (gfloat *) map.data;
+  for (i = 0; i < 48000; i++)
+    indata[i] = 1.0;
+  gst_buffer_unmap (inbuf, &map);
+  fail_unless (gst_pad_push (mysrcpads[1], inbuf) == GST_FLOW_OK);
+
+  input[0] = 0.0;
+  gst_pad_push_event (mysrcpads[0], gst_event_new_eos ());
+
+  input[1] = 1.0;
+  inbuf = gst_buffer_new_and_alloc (48000 * sizeof (gfloat));
+  gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
+  indata = (gfloat *) map.data;
+  for (i = 0; i < 48000; i++)
+    indata[i] = 1.0;
+  gst_buffer_unmap (inbuf, &map);
+  fail_unless (gst_pad_push (mysrcpads[1], inbuf) == GST_FLOW_OK);
+
+  fail_unless (have_data == 2);
+
+  gst_bus_set_flushing (bus, TRUE);
+  gst_element_set_state (interleave, GST_STATE_NULL);
+  gst_element_set_state (queue, GST_STATE_NULL);
+
+  gst_object_unref (mysrcpads[0]);
+  gst_object_unref (mysrcpads[1]);
+  gst_object_unref (mysinkpad);
+
+  gst_element_release_request_pad (interleave, sink0);
+  gst_object_unref (sink0);
+  gst_element_release_request_pad (interleave, sink1);
+  gst_object_unref (sink1);
+
+  gst_object_unref (interleave);
+  gst_object_unref (queue);
+  gst_object_unref (bus);
+  gst_caps_unref (caps);
+
+  g_free (mysrcpads);
+}
+
+GST_END_TEST;
+
+static void
+src_handoff_float32 (GstElement * element, GstBuffer * buffer, GstPad * pad,
+    gboolean interleaved, gpointer user_data)
+{
+  gint n = GPOINTER_TO_INT (user_data);
+  gfloat *data;
+  gint i;
+  gsize size;
+  GstCaps *caps;
+  guint64 mask;
+  GstAudioChannelPosition pos;
+
+  switch (n) {
+    case 0:
+    case 1:
+    case 2:
+      pos = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
+      break;
+    case 3:
+      pos = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
+      break;
+    default:
+      pos = GST_AUDIO_CHANNEL_POSITION_INVALID;
+      break;
+  }
+
+  mask = G_GUINT64_CONSTANT (1) << pos;
+
+  caps = gst_caps_new_simple ("audio/x-raw",
+      "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
+      "channels", G_TYPE_INT, 1,
+      "layout", G_TYPE_STRING, interleaved ? "interleaved" : "non-interleaved",
+      "channel-mask", GST_TYPE_BITMASK, mask, "rate", G_TYPE_INT, 48000, NULL);
+
+  gst_pad_set_caps (pad, caps);
+  gst_caps_unref (caps);
+
+  size = 48000 * sizeof (gfloat);
+  data = g_malloc (size);
+  for (i = 0; i < 48000; i++)
+    data[i] = (n % 2 == 0) ? -1.0 : 1.0;
+
+  gst_buffer_append_memory (buffer, gst_memory_new_wrapped (0, data,
+          size, 0, size, data, g_free));
+
+  GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE;
+  GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
+  GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE;
+  GST_BUFFER_DURATION (buffer) = GST_SECOND;
+}
+
+static void
+src_handoff_float32_interleaved (GstElement * element, GstBuffer * buffer,
+    GstPad * pad, gpointer user_data)
+{
+  src_handoff_float32 (element, buffer, pad, TRUE, user_data);
+}
+
+static void
+src_handoff_float32_non_interleaved (GstElement * element, GstBuffer * buffer,
+    GstPad * pad, gpointer user_data)
+{
+  src_handoff_float32 (element, buffer, pad, FALSE, user_data);
+}
+
+static void
+sink_handoff_float32 (GstElement * element, GstBuffer * buffer, GstPad * pad,
+    gpointer user_data)
+{
+  gint i;
+  GstMapInfo map;
+  gfloat *data;
+  GstCaps *caps, *ccaps;
+  gint n = GPOINTER_TO_INT (user_data);
+  guint64 mask;
+
+  fail_unless (GST_IS_BUFFER (buffer));
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  data = (gfloat *) map.data;
+
+  fail_unless_equals_int (map.size, 48000 * 2 * sizeof (gfloat));
+  fail_unless_equals_int (GST_BUFFER_DURATION (buffer), GST_SECOND);
+
+  if (n == 0) {
+    GstAudioChannelPosition pos[2] =
+        { GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE };
+    gst_audio_channel_positions_to_mask (pos, 2, FALSE, &mask);
+  } else if (n == 1) {
+    GstAudioChannelPosition pos[2] = { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+      GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT
+    };
+    gst_audio_channel_positions_to_mask (pos, 2, FALSE, &mask);
+  } else if (n == 2) {
+    GstAudioChannelPosition pos[2] = { GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+      GST_AUDIO_CHANNEL_POSITION_REAR_CENTER
+    };
+    gst_audio_channel_positions_to_mask (pos, 2, FALSE, &mask);
+  } else {
+    g_assert_not_reached ();
+  }
+
+  caps = gst_caps_new_simple ("audio/x-raw",
+      "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
+      "channels", G_TYPE_INT, 2, "rate", G_TYPE_INT, 48000,
+      "layout", G_TYPE_STRING, "interleaved",
+      "channel-mask", GST_TYPE_BITMASK, mask, NULL);
+
+  ccaps = gst_pad_get_current_caps (pad);
+  fail_unless (gst_caps_is_equal (caps, ccaps));
+  gst_caps_unref (ccaps);
+  gst_caps_unref (caps);
+
+#ifdef HAVE_VALGRIND
+  if (!(RUNNING_ON_VALGRIND))
+#endif
+    for (i = 0; i < 48000 * 2; i += 2) {
+      fail_unless_equals_float (data[i], -1.0);
+      fail_unless_equals_float (data[i + 1], 1.0);
+    }
+  gst_buffer_unmap (buffer, &map);
+
+  have_data++;
+}
+
+static void
+test_interleave_2ch_pipeline (gboolean interleaved)
+{
+  GstElement *pipeline, *queue, *src1, *src2, *interleave, *sink;
+  GstPad *sinkpad0, *sinkpad1, *tmp, *tmp2;
+  GstMessage *msg;
+  void *src_handoff_float32 =
+      interleaved ? &src_handoff_float32_interleaved :
+      &src_handoff_float32_non_interleaved;
+
+  have_data = 0;
+
+  pipeline = (GstElement *) gst_pipeline_new ("pipeline");
+  fail_unless (pipeline != NULL);
+
+  src1 = gst_element_factory_make ("fakesrc", "src1");
+  fail_unless (src1 != NULL);
+  g_object_set (src1, "num-buffers", 4, NULL);
+  g_object_set (src1, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (src1, "handoff", G_CALLBACK (src_handoff_float32),
+      GINT_TO_POINTER (0));
+  gst_bin_add (GST_BIN (pipeline), src1);
+
+  src2 = gst_element_factory_make ("fakesrc", "src2");
+  fail_unless (src2 != NULL);
+  g_object_set (src2, "num-buffers", 4, NULL);
+  g_object_set (src2, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (src2, "handoff", G_CALLBACK (src_handoff_float32),
+      GINT_TO_POINTER (1));
+  gst_bin_add (GST_BIN (pipeline), src2);
+
+  queue = gst_element_factory_make ("queue", "queue");
+  fail_unless (queue != NULL);
+  gst_bin_add (GST_BIN (pipeline), queue);
+
+  interleave = gst_element_factory_make ("interleave", "interleave");
+  fail_unless (interleave != NULL);
+  gst_bin_add (GST_BIN (pipeline), gst_object_ref (interleave));
+
+  sinkpad0 = gst_element_get_request_pad (interleave, "sink_%u");
+  fail_unless (sinkpad0 != NULL);
+  tmp = gst_element_get_static_pad (src1, "src");
+  fail_unless (gst_pad_link (tmp, sinkpad0) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+
+  sinkpad1 = gst_element_get_request_pad (interleave, "sink_%u");
+  fail_unless (sinkpad1 != NULL);
+  tmp = gst_element_get_static_pad (src2, "src");
+  tmp2 = gst_element_get_static_pad (queue, "sink");
+  fail_unless (gst_pad_link (tmp, tmp2) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+  gst_object_unref (tmp2);
+  tmp = gst_element_get_static_pad (queue, "src");
+  fail_unless (gst_pad_link (tmp, sinkpad1) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+
+  sink = gst_element_factory_make ("fakesink", "sink");
+  fail_unless (sink != NULL);
+  g_object_set (sink, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (sink, "handoff", G_CALLBACK (sink_handoff_float32),
+      GINT_TO_POINTER (0));
+  gst_bin_add (GST_BIN (pipeline), sink);
+  tmp = gst_element_get_static_pad (interleave, "src");
+  tmp2 = gst_element_get_static_pad (sink, "sink");
+  fail_unless (gst_pad_link (tmp, tmp2) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+  gst_object_unref (tmp2);
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  msg = gst_bus_poll (GST_ELEMENT_BUS (pipeline), GST_MESSAGE_EOS, -1);
+  gst_message_unref (msg);
+
+  fail_unless (have_data == 4);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_element_release_request_pad (interleave, sinkpad0);
+  gst_object_unref (sinkpad0);
+  gst_element_release_request_pad (interleave, sinkpad1);
+  gst_object_unref (sinkpad1);
+  gst_object_unref (interleave);
+  gst_object_unref (pipeline);
+}
+
+GST_START_TEST (test_interleave_2ch_pipeline_interleaved)
+{
+  test_interleave_2ch_pipeline (TRUE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_interleave_2ch_pipeline_non_interleaved)
+{
+  test_interleave_2ch_pipeline (FALSE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_interleave_2ch_pipeline_input_chanpos)
+{
+  GstElement *pipeline, *queue, *src1, *src2, *interleave, *sink;
+  GstPad *sinkpad0, *sinkpad1, *tmp, *tmp2;
+  GstMessage *msg;
+
+  have_data = 0;
+
+  pipeline = (GstElement *) gst_pipeline_new ("pipeline");
+  fail_unless (pipeline != NULL);
+
+  src1 = gst_element_factory_make ("fakesrc", "src1");
+  fail_unless (src1 != NULL);
+  g_object_set (src1, "num-buffers", 4, NULL);
+  g_object_set (src1, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (src1, "handoff",
+      G_CALLBACK (src_handoff_float32_interleaved), GINT_TO_POINTER (2));
+  gst_bin_add (GST_BIN (pipeline), src1);
+
+  src2 = gst_element_factory_make ("fakesrc", "src2");
+  fail_unless (src2 != NULL);
+  g_object_set (src2, "num-buffers", 4, NULL);
+  g_object_set (src2, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (src2, "handoff",
+      G_CALLBACK (src_handoff_float32_interleaved), GINT_TO_POINTER (3));
+  gst_bin_add (GST_BIN (pipeline), src2);
+
+  queue = gst_element_factory_make ("queue", "queue");
+  fail_unless (queue != NULL);
+  gst_bin_add (GST_BIN (pipeline), queue);
+
+  interleave = gst_element_factory_make ("interleave", "interleave");
+  fail_unless (interleave != NULL);
+  g_object_set (interleave, "channel-positions-from-input", TRUE, NULL);
+  gst_bin_add (GST_BIN (pipeline), gst_object_ref (interleave));
+
+  sinkpad0 = gst_element_get_request_pad (interleave, "sink_%u");
+  fail_unless (sinkpad0 != NULL);
+  tmp = gst_element_get_static_pad (src1, "src");
+  fail_unless (gst_pad_link (tmp, sinkpad0) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+
+  sinkpad1 = gst_element_get_request_pad (interleave, "sink_%u");
+  fail_unless (sinkpad1 != NULL);
+  tmp = gst_element_get_static_pad (src2, "src");
+  tmp2 = gst_element_get_static_pad (queue, "sink");
+  fail_unless (gst_pad_link (tmp, tmp2) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+  gst_object_unref (tmp2);
+  tmp = gst_element_get_static_pad (queue, "src");
+  fail_unless (gst_pad_link (tmp, sinkpad1) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+
+  sink = gst_element_factory_make ("fakesink", "sink");
+  fail_unless (sink != NULL);
+  g_object_set (sink, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (sink, "handoff", G_CALLBACK (sink_handoff_float32),
+      GINT_TO_POINTER (1));
+  gst_bin_add (GST_BIN (pipeline), sink);
+  tmp = gst_element_get_static_pad (interleave, "src");
+  tmp2 = gst_element_get_static_pad (sink, "sink");
+  fail_unless (gst_pad_link (tmp, tmp2) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+  gst_object_unref (tmp2);
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  msg = gst_bus_poll (GST_ELEMENT_BUS (pipeline), GST_MESSAGE_EOS, -1);
+  gst_message_unref (msg);
+
+  fail_unless (have_data == 4);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_element_release_request_pad (interleave, sinkpad0);
+  gst_object_unref (sinkpad0);
+  gst_element_release_request_pad (interleave, sinkpad1);
+  gst_object_unref (sinkpad1);
+  gst_object_unref (interleave);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_interleave_2ch_pipeline_custom_chanpos)
+{
+  GstElement *pipeline, *queue, *src1, *src2, *interleave, *sink;
+  GstPad *sinkpad0, *sinkpad1, *tmp, *tmp2;
+  GstMessage *msg;
+  GValueArray *arr;
+  GValue val = { 0, };
+
+  have_data = 0;
+
+  pipeline = (GstElement *) gst_pipeline_new ("pipeline");
+  fail_unless (pipeline != NULL);
+
+  src1 = gst_element_factory_make ("fakesrc", "src1");
+  fail_unless (src1 != NULL);
+  g_object_set (src1, "num-buffers", 4, NULL);
+  g_object_set (src1, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (src1, "handoff",
+      G_CALLBACK (src_handoff_float32_interleaved), GINT_TO_POINTER (0));
+  gst_bin_add (GST_BIN (pipeline), src1);
+
+  src2 = gst_element_factory_make ("fakesrc", "src2");
+  fail_unless (src2 != NULL);
+  g_object_set (src2, "num-buffers", 4, NULL);
+  g_object_set (src2, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (src2, "handoff",
+      G_CALLBACK (src_handoff_float32_interleaved), GINT_TO_POINTER (1));
+  gst_bin_add (GST_BIN (pipeline), src2);
+
+  queue = gst_element_factory_make ("queue", "queue");
+  fail_unless (queue != NULL);
+  gst_bin_add (GST_BIN (pipeline), queue);
+
+  interleave = gst_element_factory_make ("interleave", "interleave");
+  fail_unless (interleave != NULL);
+  g_object_set (interleave, "channel-positions-from-input", FALSE, NULL);
+  arr = g_value_array_new (2);
+
+  g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION);
+  g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER);
+  g_value_array_append (arr, &val);
+  g_value_reset (&val);
+  g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER);
+  g_value_array_append (arr, &val);
+  g_value_unset (&val);
+
+  g_object_set (interleave, "channel-positions", arr, NULL);
+  g_value_array_free (arr);
+  gst_bin_add (GST_BIN (pipeline), gst_object_ref (interleave));
+
+  sinkpad0 = gst_element_get_request_pad (interleave, "sink_%u");
+  fail_unless (sinkpad0 != NULL);
+  tmp = gst_element_get_static_pad (src1, "src");
+  fail_unless (gst_pad_link (tmp, sinkpad0) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+
+  sinkpad1 = gst_element_get_request_pad (interleave, "sink_%u");
+  fail_unless (sinkpad1 != NULL);
+  tmp = gst_element_get_static_pad (src2, "src");
+  tmp2 = gst_element_get_static_pad (queue, "sink");
+  fail_unless (gst_pad_link (tmp, tmp2) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+  gst_object_unref (tmp2);
+  tmp = gst_element_get_static_pad (queue, "src");
+  fail_unless (gst_pad_link (tmp, sinkpad1) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+
+  sink = gst_element_factory_make ("fakesink", "sink");
+  fail_unless (sink != NULL);
+  g_object_set (sink, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (sink, "handoff", G_CALLBACK (sink_handoff_float32),
+      GINT_TO_POINTER (2));
+  gst_bin_add (GST_BIN (pipeline), sink);
+  tmp = gst_element_get_static_pad (interleave, "src");
+  tmp2 = gst_element_get_static_pad (sink, "sink");
+  fail_unless (gst_pad_link (tmp, tmp2) == GST_PAD_LINK_OK);
+  gst_object_unref (tmp);
+  gst_object_unref (tmp2);
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  msg = gst_bus_poll (GST_ELEMENT_BUS (pipeline), GST_MESSAGE_EOS, -1);
+  gst_message_unref (msg);
+
+  fail_unless (have_data == 4);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_element_release_request_pad (interleave, sinkpad0);
+  gst_object_unref (sinkpad0);
+  gst_element_release_request_pad (interleave, sinkpad1);
+  gst_object_unref (sinkpad1);
+  gst_object_unref (interleave);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
+static Suite *
+interleave_suite (void)
+{
+  Suite *s = suite_create ("interleave");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_set_timeout (tc_chain, 180);
+  tcase_add_test (tc_chain, test_create_and_unref);
+  tcase_add_test (tc_chain, test_request_pads);
+  tcase_add_test (tc_chain, test_interleave_2ch);
+  tcase_add_test (tc_chain, test_interleave_2ch_1eos);
+  tcase_add_test (tc_chain, test_interleave_2ch_pipeline_interleaved);
+  tcase_add_test (tc_chain, test_interleave_2ch_pipeline_non_interleaved);
+  tcase_add_test (tc_chain, test_interleave_2ch_pipeline_input_chanpos);
+  tcase_add_test (tc_chain, test_interleave_2ch_pipeline_custom_chanpos);
+
+  return s;
+}
+
+GST_CHECK_MAIN (interleave);
diff --git a/tests/check/elements/jpegdec.c b/tests/check/elements/jpegdec.c
new file mode 100644
index 0000000..f6ac523
--- /dev/null
+++ b/tests/check/elements/jpegdec.c
@@ -0,0 +1,141 @@
+/* GStreamer
+ * unit test for jpegdec
+ * Copyright (C) <2010> Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+ * Copyright (C) <2012> Mathias Hasselmann <mathias@openismus.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gio/gio.h>
+#include <gst/check/gstcheck.h>
+#include <gst/app/gstappsink.h>
+#include <gst/pbutils/gstdiscoverer.h>
+
+/* Verify jpegdec is working when explictly requested by a pipeline. */
+GST_START_TEST (test_jpegdec_explicit)
+{
+  GstElement *pipeline, *source, *dec, *sink;
+  GstSample *sample;
+
+  /* construct a pipeline that explicitly uses jpegdec */
+  pipeline = gst_pipeline_new (NULL);
+  source = gst_element_factory_make ("filesrc", NULL);
+  dec = gst_element_factory_make ("jpegdec", NULL);
+  sink = gst_element_factory_make ("appsink", NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), source, dec, sink, NULL);
+  gst_element_link_many (source, dec, sink, NULL);
+
+  /* point that pipeline to our test image */
+  {
+    char *filename = g_build_filename (GST_TEST_FILES_PATH, "image.jpg", NULL);
+    g_object_set (G_OBJECT (source), "location", filename, NULL);
+    g_free (filename);
+  }
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  sample = gst_app_sink_pull_sample (GST_APP_SINK (sink));
+  fail_unless (GST_IS_SAMPLE (sample));
+
+  /* do some basic checks to verify image decoding */
+  {
+    GstCaps *decoded;
+    GstCaps *expected;
+
+    decoded = gst_sample_get_caps (sample);
+    expected = gst_caps_from_string ("video/x-raw, width=120, height=160");
+
+    fail_unless (gst_caps_is_always_compatible (decoded, expected));
+
+    gst_caps_unref (expected);
+  }
+  gst_sample_unref (sample);
+
+  /* wait for EOS */
+  sample = gst_app_sink_pull_sample (GST_APP_SINK (sink));
+  fail_unless (sample == NULL);
+  fail_unless (gst_app_sink_is_eos (GST_APP_SINK (sink)));
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
+/* Verify JPEG discovery is working. Right now jpegdec would be used,
+ * but I have no idea how to actually verify this. */
+GST_START_TEST (test_jpegdec_discover)
+{
+  GstDiscoverer *disco;
+  GError *error = NULL;
+  char *uri;
+  GstDiscovererInfo *info;
+  GstDiscovererVideoInfo *video;
+
+  disco = gst_discoverer_new (5 * GST_SECOND, &error);
+
+  fail_unless (GST_IS_DISCOVERER (disco));
+  fail_unless (error == NULL, "%s", (error ? error->message : ""));
+
+  {
+    GFile *testdir = g_file_new_for_path (GST_TEST_FILES_PATH);
+    GFile *testfile = g_file_resolve_relative_path (testdir, "image.jpg");
+    uri = g_file_get_uri (testfile);
+    g_object_unref (testfile);
+    g_object_unref (testdir);
+  }
+
+  info = gst_discoverer_discover_uri (disco, uri, &error);
+  fail_unless (GST_IS_DISCOVERER_INFO (info));
+  fail_unless (error == NULL, "%s: %s", uri, (error ? error->message : ""));
+
+  fail_unless_equals_string (gst_discoverer_info_get_uri (info), uri);
+  fail_unless_equals_int (gst_discoverer_info_get_result (info),
+      GST_DISCOVERER_OK);
+
+  video =
+      GST_DISCOVERER_VIDEO_INFO (gst_discoverer_info_get_stream_info (info));
+  fail_unless (video != NULL);
+
+  fail_unless (gst_discoverer_video_info_is_image (video));
+  fail_unless_equals_int (gst_discoverer_video_info_get_width (video), 120);
+  fail_unless_equals_int (gst_discoverer_video_info_get_height (video), 160);
+
+  gst_discoverer_info_unref (video);
+  gst_discoverer_info_unref (info);
+  g_free (uri);
+  g_object_unref (disco);
+}
+
+GST_END_TEST;
+
+static Suite *
+jpegdec_suite (void)
+{
+  Suite *s = suite_create ("jpegdec");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_jpegdec_explicit);
+  tcase_add_test (tc_chain, test_jpegdec_discover);
+
+  return s;
+}
+
+GST_CHECK_MAIN (jpegdec);
diff --git a/tests/check/elements/jpegenc.c b/tests/check/elements/jpegenc.c
new file mode 100644
index 0000000..c191a7e
--- /dev/null
+++ b/tests/check/elements/jpegenc.c
@@ -0,0 +1,240 @@
+/* GStreamer
+ *
+ * unit test for jpegenc
+ *
+ * Copyright (C) <2010> Thiago Santos <thiago.sousa.santos@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+#include <gst/app/gstappsink.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+static GstPad *mysinkpad;
+static GstPad *mysrcpad;
+
+#define JPEG_CAPS_STRING "image/jpeg"
+
+#define JPEG_CAPS_RESTRICTIVE "image/jpeg, " \
+    "width = (int) [100, 200], " \
+    "framerate = (fraction) 25/1, " \
+    "extraparameter = (string) { abc, def }"
+
+static GstStaticPadTemplate jpeg_sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (JPEG_CAPS_STRING));
+
+static GstStaticPadTemplate any_sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate jpeg_restrictive_sinktemplate =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (JPEG_CAPS_RESTRICTIVE));
+
+static GstStaticPadTemplate any_srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+
+static GstElement *
+setup_jpegenc (GstStaticPadTemplate * sinktemplate)
+{
+  GstElement *jpegenc;
+
+  GST_DEBUG ("setup_jpegenc");
+  jpegenc = gst_check_setup_element ("jpegenc");
+  mysinkpad = gst_check_setup_sink_pad (jpegenc, sinktemplate);
+  mysrcpad = gst_check_setup_src_pad (jpegenc, &any_srctemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return jpegenc;
+}
+
+static void
+cleanup_jpegenc (GstElement * jpegenc)
+{
+  GST_DEBUG ("cleanup_jpegenc");
+  gst_element_set_state (jpegenc, GST_STATE_NULL);
+
+  gst_check_drop_buffers ();
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_sink_pad (jpegenc);
+  gst_check_teardown_src_pad (jpegenc);
+  gst_check_teardown_element (jpegenc);
+}
+
+static GstBuffer *
+create_video_buffer (GstCaps * caps)
+{
+  GstElement *pipeline;
+  GstElement *cf;
+  GstElement *sink;
+  GstSample *sample;
+  GstBuffer *buffer;
+
+  pipeline =
+      gst_parse_launch
+      ("videotestsrc num-buffers=1 ! capsfilter name=cf ! appsink name=sink",
+      NULL);
+  g_assert (pipeline != NULL);
+
+  cf = gst_bin_get_by_name (GST_BIN (pipeline), "cf");
+  sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
+
+  g_object_set (G_OBJECT (cf), "caps", caps, NULL);
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  sample = gst_app_sink_pull_sample (GST_APP_SINK (sink));
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+  gst_object_unref (sink);
+  gst_object_unref (cf);
+
+  buffer = gst_sample_get_buffer (sample);
+  gst_buffer_ref (buffer);
+
+  gst_sample_unref (sample);
+
+  return buffer;
+}
+
+
+GST_START_TEST (test_jpegenc_getcaps)
+{
+  GstElement *jpegenc;
+  GstPad *sinkpad;
+  GstCaps *caps;
+  GstStructure *structure;
+  gint fps_n;
+  gint fps_d;
+  const GValue *value;
+
+  /* we are going to do some get caps to confirm it doesn't return non-subset
+   * caps */
+
+  jpegenc = setup_jpegenc (&any_sinktemplate);
+  sinkpad = gst_element_get_static_pad (jpegenc, "sink");
+  /* this should assert if non-subset */
+  caps = gst_pad_query_caps (sinkpad, NULL);
+  gst_caps_unref (caps);
+  gst_object_unref (sinkpad);
+  cleanup_jpegenc (jpegenc);
+
+  jpegenc = setup_jpegenc (&jpeg_sinktemplate);
+  sinkpad = gst_element_get_static_pad (jpegenc, "sink");
+  /* this should assert if non-subset */
+  caps = gst_pad_query_caps (sinkpad, NULL);
+  gst_caps_unref (caps);
+  gst_object_unref (sinkpad);
+  cleanup_jpegenc (jpegenc);
+
+  /* now use a more restricted one and check the resulting caps */
+  jpegenc = setup_jpegenc (&jpeg_restrictive_sinktemplate);
+  sinkpad = gst_element_get_static_pad (jpegenc, "sink");
+  /* this should assert if non-subset */
+  caps = gst_pad_query_caps (sinkpad, NULL);
+  structure = gst_caps_get_structure (caps, 0);
+
+  /* check the width */
+  value = gst_structure_get_value (structure, "width");
+  fail_unless (gst_value_get_int_range_min (value) == 100);
+  fail_unless (gst_value_get_int_range_max (value) == 200);
+
+  fail_unless (gst_structure_get_fraction (structure, "framerate", &fps_n,
+          &fps_d));
+  fail_unless (fps_n == 25);
+  fail_unless (fps_d == 1);
+
+  gst_caps_unref (caps);
+  gst_object_unref (sinkpad);
+  cleanup_jpegenc (jpegenc);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_jpegenc_different_caps)
+{
+  GstElement *jpegenc;
+  GstBuffer *buffer;
+  GstCaps *caps;
+  GstCaps *allowed_caps;
+
+  /* now use a more restricted one and check the resulting caps */
+  jpegenc = setup_jpegenc (&any_sinktemplate);
+  gst_element_set_state (jpegenc, GST_STATE_PLAYING);
+
+  /* push first buffer with 800x600 resolution */
+  caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
+      800, "height", G_TYPE_INT, 600, "framerate",
+      GST_TYPE_FRACTION, 1, 1, "format", G_TYPE_STRING, "I420", NULL);
+  gst_check_setup_events (mysrcpad, jpegenc, caps, GST_FORMAT_TIME);
+  fail_unless ((buffer = create_video_buffer (caps)) != NULL);
+  gst_caps_unref (caps);
+  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+
+  /* check the allowed caps to see if a second buffer with a different
+   * caps could be negotiated */
+  allowed_caps = gst_pad_get_allowed_caps (mysrcpad);
+
+  /* the caps we want to negotiate to */
+  caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
+      640, "height", G_TYPE_INT, 480, "framerate",
+      GST_TYPE_FRACTION, 1, 1, "format", G_TYPE_STRING, "I420", NULL);
+  fail_unless (gst_caps_can_intersect (allowed_caps, caps));
+  fail_unless (gst_pad_set_caps (mysrcpad, caps));
+
+  /* push second buffer with 640x480 resolution */
+  buffer = create_video_buffer (caps);
+  gst_caps_unref (caps);
+  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+
+  gst_caps_unref (allowed_caps);
+  gst_element_set_state (jpegenc, GST_STATE_NULL);
+  cleanup_jpegenc (jpegenc);
+}
+
+GST_END_TEST;
+
+static Suite *
+jpegenc_suite (void)
+{
+  Suite *s = suite_create ("jpegenc");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_jpegenc_getcaps);
+  tcase_add_test (tc_chain, test_jpegenc_different_caps);
+
+  return s;
+}
+
+GST_CHECK_MAIN (jpegenc);
diff --git a/tests/check/elements/level.c b/tests/check/elements/level.c
new file mode 100644
index 0000000..96de0e2
--- /dev/null
+++ b/tests/check/elements/level.c
@@ -0,0 +1,612 @@
+/* GStreamer
+ *
+ * unit test for level
+ *
+ * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+/* suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <gst/audio/audio.h>
+#include <gst/check/gstcheck.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+static GstPad *mysrcpad, *mysinkpad;
+
+#define LEVEL_CAPS_TEMPLATE_STRING \
+  "audio/x-raw, " \
+    "format = (string) { "GST_AUDIO_NE(S16)", "GST_AUDIO_NE(F32)" }, " \
+    "layout = (string) interleaved, " \
+    "rate = (int) [ 1, MAX ], " \
+    "channels = (int) [ 1, 8 ]"
+
+/* we use rate = 1000 here for easy buffer size calculations */
+#define LEVEL_S16_CAPS_STRING \
+  "audio/x-raw, " \
+    "format = (string) "GST_AUDIO_NE(S16)", " \
+    "layout = (string) interleaved, " \
+    "rate = (int) 1000, " \
+    "channels = (int) 2, "  \
+    "channel-mask = (bitmask) 3"
+
+#define LEVEL_F32_CAPS_STRING \
+  "audio/x-raw, " \
+    "format = (string) "GST_AUDIO_NE(F32)", " \
+    "layout = (string) interleaved, " \
+    "rate = (int) 1000, " \
+    "channels = (int) 2, "  \
+    "channel-mask = (bitmask) 3"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (LEVEL_CAPS_TEMPLATE_STRING)
+    );
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (LEVEL_CAPS_TEMPLATE_STRING)
+    );
+
+/* takes over reference for outcaps */
+static GstElement *
+setup_level (const gchar * caps_str)
+{
+  GstElement *level;
+  GstCaps *caps;
+
+  GST_DEBUG ("setup_level");
+  level = gst_check_setup_element ("level");
+  mysrcpad = gst_check_setup_src_pad (level, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (level, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  caps = gst_caps_from_string (caps_str);
+  gst_check_setup_events (mysrcpad, level, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  return level;
+}
+
+static void
+cleanup_level (GstElement * level)
+{
+  GST_DEBUG ("cleanup_level");
+
+  gst_check_drop_buffers ();
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (level);
+  gst_check_teardown_sink_pad (level);
+  gst_check_teardown_element (level);
+}
+
+/* create a 0.1 sec buffer stereo buffer */
+static GstBuffer *
+create_s16_buffer (gint16 val_l, gint16 val_r)
+{
+  GstBuffer *buf = gst_buffer_new_and_alloc (2 * 100 * sizeof (gint16));
+  GstMapInfo map;
+  gint j;
+  gint16 *data;
+
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  data = (gint16 *) map.data;
+  for (j = 0; j < 100; ++j) {
+    *(data++) = val_l;
+    *(data++) = val_r;
+  }
+  gst_buffer_unmap (buf, &map);
+  GST_BUFFER_TIMESTAMP (buf) = G_GUINT64_CONSTANT (0);
+  return buf;
+}
+
+static GstBuffer *
+create_f32_buffer (gfloat val_l, gfloat val_r)
+{
+  GstBuffer *buf = gst_buffer_new_and_alloc (2 * 100 * sizeof (gfloat));
+  GstMapInfo map;
+  gint j;
+  gfloat *data;
+
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  data = (gfloat *) map.data;
+  for (j = 0; j < 100; ++j) {
+    *(data++) = val_l;
+    *(data++) = val_r;
+  }
+  gst_buffer_unmap (buf, &map);
+  GST_BUFFER_TIMESTAMP (buf) = G_GUINT64_CONSTANT (0);
+  return buf;
+}
+
+/* tests */
+
+GST_START_TEST (test_ref_counts)
+{
+  GstElement *level;
+  GstBuffer *inbuffer, *outbuffer;
+  GstBus *bus;
+  GstMessage *message;
+
+  level = setup_level (LEVEL_S16_CAPS_STRING);
+  g_object_set (level, "post-messages", TRUE,
+      "interval", (guint64) GST_SECOND / 10, NULL);
+  fail_unless (gst_element_set_state (level,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+  /* create a bus to get the level message on */
+  bus = gst_bus_new ();
+  ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
+  gst_element_set_bus (level, bus);
+  ASSERT_OBJECT_REFCOUNT (bus, "bus", 2);
+
+  /* create a fake 0.1 sec buffer with a half-amplitude block signal */
+  inbuffer = create_s16_buffer (16536, 16536);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... but it ends up being collected on the global buffer list */
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (inbuffer == outbuffer);
+
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
+  ASSERT_OBJECT_REFCOUNT (message, "message", 1);
+
+  fail_unless (message != NULL);
+  fail_unless (GST_MESSAGE_SRC (message) == GST_OBJECT (level));
+  fail_unless (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT);
+
+  /* clean up */
+  /* flush current messages,and future state change messages */
+  gst_bus_set_flushing (bus, TRUE);
+
+  /* message has a ref to the element */
+  ASSERT_OBJECT_REFCOUNT (level, "level", 2);
+  gst_message_unref (message);
+  ASSERT_OBJECT_REFCOUNT (level, "level", 1);
+
+  gst_element_set_bus (level, NULL);
+  ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
+  gst_object_unref (bus);
+  fail_unless (gst_element_set_state (level,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+  ASSERT_OBJECT_REFCOUNT (level, "level", 1);
+  cleanup_level (level);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_message_is_valid)
+{
+  GstElement *level;
+  GstBuffer *inbuffer;
+  GstBus *bus;
+  GstMessage *message;
+  const GstStructure *structure;
+  GstClockTime endtime, ts, duration;
+
+  level = setup_level (LEVEL_S16_CAPS_STRING);
+  g_object_set (level, "post-messages", TRUE,
+      "interval", (guint64) GST_SECOND / 10, NULL);
+  gst_element_set_state (level, GST_STATE_PLAYING);
+  /* create a bus to get the level message on */
+  bus = gst_bus_new ();
+  gst_element_set_bus (level, bus);
+
+  /* create a fake 0.1 sec buffer with a half-amplitude block signal and push */
+  inbuffer = create_s16_buffer (16536, 16536);
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
+  fail_unless (message != NULL);
+  structure = gst_message_get_structure (message);
+  fail_if (structure == NULL);
+  fail_unless_equals_string (gst_structure_get_name (structure), "level");
+  fail_unless (gst_structure_get_clock_time (structure, "endtime", &endtime));
+  fail_unless (gst_structure_get_clock_time (structure, "timestamp", &ts));
+  fail_unless (gst_structure_get_clock_time (structure, "duration", &duration));
+
+  /* clean up */
+  /* flush current messages,and future state change messages */
+  gst_bus_set_flushing (bus, TRUE);
+  gst_message_unref (message);
+  gst_element_set_bus (level, NULL);
+  gst_object_unref (bus);
+  gst_element_set_state (level, GST_STATE_NULL);
+  cleanup_level (level);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_int16)
+{
+  GstElement *level;
+  GstBuffer *inbuffer, *outbuffer;
+  GstBus *bus;
+  GstMessage *message;
+  const GstStructure *structure;
+  gint i, j;
+  const GValue *list, *value;
+  gdouble dB;
+  const gchar *fields[3] = { "rms", "peak", "decay" };
+
+  level = setup_level (LEVEL_S16_CAPS_STRING);
+  g_object_set (level, "post-messages", TRUE,
+      "interval", (guint64) GST_SECOND / 10, NULL);
+  gst_element_set_state (level, GST_STATE_PLAYING);
+  /* create a bus to get the level message on */
+  bus = gst_bus_new ();
+  gst_element_set_bus (level, bus);
+
+  /* create a fake 0.1 sec buffer with a half-amplitude block signal */
+  inbuffer = create_s16_buffer (16536, 16536);
+
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (inbuffer == outbuffer);
+
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
+  structure = gst_message_get_structure (message);
+
+  /* block wave of half amplitude has -5.94 dB for rms, peak and decay */
+  for (i = 0; i < 2; ++i) {
+    for (j = 0; j < 3; ++j) {
+      GValueArray *arr;
+
+      list = gst_structure_get_value (structure, fields[j]);
+      arr = g_value_get_boxed (list);
+      value = g_value_array_get_nth (arr, i);
+      dB = g_value_get_double (value);
+      GST_DEBUG ("%s is %lf", fields[j], dB);
+      fail_if (dB < -6.1);
+      fail_if (dB > -5.9);
+    }
+  }
+
+  /* clean up */
+  /* flush current messages,and future state change messages */
+  gst_bus_set_flushing (bus, TRUE);
+  gst_message_unref (message);
+  gst_element_set_bus (level, NULL);
+  gst_object_unref (bus);
+  gst_element_set_state (level, GST_STATE_NULL);
+  cleanup_level (level);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_int16_panned)
+{
+  GstElement *level;
+  GstBuffer *inbuffer, *outbuffer;
+  GstBus *bus;
+  GstMessage *message;
+  const GstStructure *structure;
+  gint i, j;
+  const GValue *list, *value;
+  gdouble dB;
+  const gchar *fields[3] = { "rms", "peak", "decay" };
+
+  level = setup_level (LEVEL_S16_CAPS_STRING);
+  g_object_set (level, "post-messages", TRUE,
+      "interval", (guint64) GST_SECOND / 30, NULL);
+  gst_element_set_state (level, GST_STATE_PLAYING);
+  /* create a bus to get the level message on */
+  bus = gst_bus_new ();
+  gst_element_set_bus (level, bus);
+
+  /* create a fake 0.1 sec buffer with a half-amplitude block signal */
+  inbuffer = create_s16_buffer (0, 16536);
+
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (inbuffer == outbuffer);
+
+  /* do multiple messages per buffer, to verify that the inner loop in level
+   * advances the read-index correctly, see
+   * https://bugzilla.gnome.org/show_bug.cgi?id=754144
+   */
+  for (i = 0; i < 3; i++) {
+    GST_DEBUG ("get message number %d", i);
+    message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
+    structure = gst_message_get_structure (message);
+
+    /* silence has 0 dB for rms, peak and decay */
+    for (j = 0; j < 3; ++j) {
+      GValueArray *arr;
+
+      list = gst_structure_get_value (structure, fields[j]);
+      arr = g_value_get_boxed (list);
+      value = g_value_array_get_nth (arr, 0);
+      dB = g_value_get_double (value);
+      GST_DEBUG ("%s[0] is %lf", fields[j], dB);
+#ifdef HAVE_ISINF
+      fail_unless (isinf (dB));
+#elif defined (HAVE_FPCLASS)
+      fail_unless (fpclass (dB) == FP_NINF);
+#endif
+    }
+    /* block wave of half amplitude has -5.94 dB for rms, peak and decay */
+    for (j = 0; j < 3; ++j) {
+      GValueArray *arr;
+
+      list = gst_structure_get_value (structure, fields[j]);
+      arr = g_value_get_boxed (list);
+      value = g_value_array_get_nth (arr, 1);
+      dB = g_value_get_double (value);
+      GST_DEBUG ("%s[1] is %lf", fields[j], dB);
+      fail_if (dB < -6.1);
+      fail_if (dB > -5.9);
+    }
+    gst_message_unref (message);
+  }
+
+  /* clean up */
+  /* flush current messages,and future state change messages */
+  gst_bus_set_flushing (bus, TRUE);
+  gst_element_set_bus (level, NULL);
+  gst_object_unref (bus);
+  gst_element_set_state (level, GST_STATE_NULL);
+  cleanup_level (level);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_float)
+{
+  GstElement *level;
+  GstBuffer *inbuffer, *outbuffer;
+  GstBus *bus;
+  GstMessage *message;
+  const GstStructure *structure;
+  gint i, j;
+  const GValue *list, *value;
+  gdouble dB;
+  const gchar *fields[3] = { "rms", "peak", "decay" };
+
+  level = setup_level (LEVEL_F32_CAPS_STRING);
+  g_object_set (level, "post-messages", TRUE,
+      "interval", (guint64) GST_SECOND / 10, NULL);
+  gst_element_set_state (level, GST_STATE_PLAYING);
+  /* create a bus to get the level message on */
+  bus = gst_bus_new ();
+  gst_element_set_bus (level, bus);
+
+  /* create a fake 0.1 sec buffer with a half-amplitude block signal */
+  inbuffer = create_f32_buffer (0.5, 0.5);
+
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (inbuffer == outbuffer);
+
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
+  structure = gst_message_get_structure (message);
+
+  /* block wave of half amplitude has -5.94 dB for rms, peak and decay */
+  for (i = 0; i < 2; ++i) {
+    for (j = 0; j < 3; ++j) {
+      GValueArray *arr;
+
+      list = gst_structure_get_value (structure, fields[j]);
+      arr = g_value_get_boxed (list);
+      value = g_value_array_get_nth (arr, i);
+      dB = g_value_get_double (value);
+      GST_DEBUG ("%s is %lf", fields[j], dB);
+      fail_if (dB < -6.1);
+      fail_if (dB > -5.9);
+    }
+  }
+
+  /* clean up */
+  /* flush current messages,and future state change messages */
+  gst_bus_set_flushing (bus, TRUE);
+  gst_message_unref (message);
+  gst_element_set_bus (level, NULL);
+  gst_object_unref (bus);
+  gst_element_set_state (level, GST_STATE_NULL);
+  cleanup_level (level);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_message_on_eos)
+{
+  GstElement *level;
+  GstBuffer *inbuffer, *outbuffer;
+  GstEvent *event;
+  GstBus *bus;
+  GstMessage *message;
+  const GstStructure *structure;
+  gint i, j;
+  const GValue *list, *value;
+  gdouble dB;
+
+  level = setup_level (LEVEL_S16_CAPS_STRING);
+  g_object_set (level, "post-messages", TRUE,
+      "interval", (guint64) GST_SECOND / 5, NULL);
+  gst_element_set_state (level, GST_STATE_PLAYING);
+  /* create a bus to get the level message on */
+  bus = gst_bus_new ();
+  gst_element_set_bus (level, bus);
+
+  /* create a fake 0.1 sec buffer with a half-amplitude block signal */
+  inbuffer = create_s16_buffer (16536, 16536);
+
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (inbuffer == outbuffer);
+
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, 0);
+
+  event = gst_event_new_eos ();
+  fail_unless (gst_pad_push_event (mysrcpad, event) == TRUE);
+
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, 0);
+  fail_unless (message != NULL);
+  structure = gst_message_get_structure (message);
+  fail_unless_equals_string (gst_structure_get_name (structure), "level");
+
+  /* block wave of half amplitude has -5.94 dB for rms, peak and decay */
+  for (i = 0; i < 2; ++i) {
+    const gchar *fields[3] = { "rms", "peak", "decay" };
+    for (j = 0; j < 3; ++j) {
+      GValueArray *arr;
+
+      list = gst_structure_get_value (structure, fields[j]);
+      arr = g_value_get_boxed (list);
+      value = g_value_array_get_nth (arr, i);
+      dB = g_value_get_double (value);
+      GST_DEBUG ("%s is %lf", fields[j], dB);
+      fail_if (dB < -6.1);
+      fail_if (dB > -5.9);
+    }
+  }
+
+  /* clean up */
+  /* flush current messages,and future state change messages */
+  gst_bus_set_flushing (bus, TRUE);
+  gst_message_unref (message);
+  gst_element_set_bus (level, NULL);
+  gst_object_unref (bus);
+  gst_element_set_state (level, GST_STATE_NULL);
+  cleanup_level (level);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_message_count)
+{
+  GstElement *level;
+  GstBuffer *inbuffer, *outbuffer;
+  GstBus *bus;
+  GstMessage *message;
+
+  level = setup_level (LEVEL_S16_CAPS_STRING);
+  g_object_set (level, "post-messages", TRUE,
+      "interval", (guint64) GST_SECOND / 20, NULL);
+  gst_element_set_state (level, GST_STATE_PLAYING);
+  /* create a bus to get the level message on */
+  bus = gst_bus_new ();
+  gst_element_set_bus (level, bus);
+
+  /* create a fake 0.1 sec buffer with a half-amplitude block signal */
+  inbuffer = create_s16_buffer (16536, 16536);
+
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (inbuffer == outbuffer);
+
+  /* we should get two messages per buffer */
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
+  fail_unless (message != NULL);
+  gst_message_unref (message);
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
+  fail_unless (message != NULL);
+  gst_message_unref (message);
+
+  gst_element_set_bus (level, NULL);
+  gst_object_unref (bus);
+  gst_element_set_state (level, GST_STATE_NULL);
+  cleanup_level (level);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_message_timestamps)
+{
+  GstElement *level;
+  GstBuffer *inbuffer, *outbuffer;
+  GstBus *bus;
+  GstMessage *message;
+  const GstStructure *structure;
+  GstClockTime ts1, dur1, ts2;
+
+  level = setup_level (LEVEL_S16_CAPS_STRING);
+  g_object_set (level, "post-messages", TRUE,
+      "interval", (guint64) GST_SECOND / 20, NULL);
+  gst_element_set_state (level, GST_STATE_PLAYING);
+  /* create a bus to get the level message on */
+  bus = gst_bus_new ();
+  gst_element_set_bus (level, bus);
+
+  /* create a fake 0.1 sec buffer with a half-amplitude block signal */
+  inbuffer = create_s16_buffer (16536, 16536);
+
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (inbuffer == outbuffer);
+
+  /* check that timestamp + duration is contigous to the next timestamp */
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
+  structure = gst_message_get_structure (message);
+  gst_structure_get_clock_time (structure, "timestamp", &ts1);
+  gst_structure_get_clock_time (structure, "duration", &dur1);
+  gst_message_unref (message);
+
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
+  structure = gst_message_get_structure (message);
+  gst_structure_get_clock_time (structure, "timestamp", &ts2);
+  gst_message_unref (message);
+
+  fail_unless_equals_int64 (ts1 + dur1, ts2);
+
+  gst_element_set_bus (level, NULL);
+  gst_object_unref (bus);
+  gst_element_set_state (level, GST_STATE_NULL);
+  cleanup_level (level);
+}
+
+GST_END_TEST;
+
+static Suite *
+level_suite (void)
+{
+  Suite *s = suite_create ("level");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_ref_counts);
+  tcase_add_test (tc_chain, test_message_is_valid);
+  tcase_add_test (tc_chain, test_int16);
+  tcase_add_test (tc_chain, test_int16_panned);
+  tcase_add_test (tc_chain, test_float);
+  tcase_add_test (tc_chain, test_message_on_eos);
+  tcase_add_test (tc_chain, test_message_count);
+  tcase_add_test (tc_chain, test_message_timestamps);
+
+  return s;
+}
+
+GST_CHECK_MAIN (level);
diff --git a/tests/check/elements/matroskademux.c b/tests/check/elements/matroskademux.c
new file mode 100644
index 0000000..5081c84
--- /dev/null
+++ b/tests/check/elements/matroskademux.c
@@ -0,0 +1,323 @@
+/* GStreamer unit test for matroskademux
+ * Copyright (C) 2015 Tim-Philipp Müller <tim@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/check/gstharness.h>
+
+const gchar mkv_sub_base64[] =
+    "GkXfowEAAAAAAAAUQoKJbWF0cm9za2EAQoeBAkKFgQIYU4BnAQAAAAAAAg0RTZt0AQAAAAAAAIxN"
+    "uwEAAAAAAAASU6uEFUmpZlOsiAAAAAAAAACYTbsBAAAAAAAAElOrhBZUrmtTrIgAAAAAAAABEuya"
+    "AQAAAAAAABJTq4QQQ6dwU6yI///////////smgEAAAAAAAASU6uEHFO7a1OsiP//////////TbsB"
+    "AAAAAAAAElOrhBJUw2dTrIgAAAAAAAAB9xVJqWYBAAAAAAAAbnOkkDylQZJlrLziQo8+gsrZVtUq"
+    "17GDD0JARImIQNGUAAAAAABNgJ9HU3RyZWFtZXIgcGx1Z2luIHZlcnNpb24gMS40LjUAV0GZR1N0"
+    "cmVhbWVyIE1hdHJvc2thIG11eGVyAERhiAZfU0rcEwgAFlSuawEAAAAAAAA0rgEAAAAAAAAr14EB"
+    "g4ERc8WIoWF8pYlELidTbolTdWJ0aXRsZQCGjFNfVEVYVC9VVEY4AB9DtnUBAAAAAAAAmeeCA+ig"
+    "AQAAAAAAAA2bggfQoYeBAAAAZm9voAEAAAAAAAAUm4IH0KGOgQu4ADxpPmJhcjwvaT6gAQAAAAAA"
+    "AA2bggfQoYeBF3AAYmF6oAEAAAAAAAAOm4IH0KGIgScQAGbDtgCgAQAAAAAAABWbggfQoY+BMsgA"
+    "PGk+YmFyPC9pPgCgAQAAAAAAAA6bggfQoYiBPoAAYuR6ABJUw2cBAAAAAAAACnNzAQAAAAAAAAA=";
+
+const gchar mkv_toc_base64[] =
+    "GkXfowEAAAAAAAAUQoKJbWF0cm9za2EAQoeBAUKFgQEYU4BnAQAAAAAABUoRTZt0AQAAAAAAAIxN"
+    "uwEAAAAAAAASU6uEFUmpZlOsiAAAAAAAAACYTbsBAAAAAAAAElOrhBZUrmtTrIgAAAAAAAABGk27"
+    "AQAAAAAAABJTq4QQQ6dwU6yIAAAAAAAAAWFNuwEAAAAAAAASU6uEHFO7a1OsiAAAAAAAAANrTbsB"
+    "AAAAAAAAElOrhBJUw2dTrIgAAAAAAAADkxVJqWYBAAAAAAAAdnOkkFdJrZAH7YY5MCvJGPwl5E4q"
+    "17GDD0JARImIP/AAAAAAAABNgKdHU3RyZWFtZXIgbWF0cm9za2FtdXggdmVyc2lvbiAxLjEzLjAu"
+    "MQBXQZlHU3RyZWFtZXIgTWF0cm9za2EgbXV4ZXIARGGIB2iH12N5DgAWVK5rAQAAAAAAADuuAQAA"
+    "AAAAADLXgQGDgQJzxYgJixQa+ZhvPSPjg4MPQkBTboZBdWRpbwDhAQAAAAAAAACGhkFfQUMzABBD"
+    "p3ABAAAAAAAB30W5AQAAAAAAAdVFvIi3DuS4TWeFXUW9gQBF24EARd2BALYBAAAAAAAA1HPEiOV0"
+    "L8eev+wgVlSGdWlkLjEAkYEAkoMehICYgQBFmIEBgAEAAAAAAAAQhYdjaGFwLjEAQ3yEdW5kALYB"
+    "AAAAAAAAQnPEiCW5ajpHRzyzVlSIdWlkLjEuMQCRgQCSgw9CQJiBAEWYgQGAAQAAAAAAABSFi25l"
+    "c3RlZC4xLjEAQ3yEdW5kALYBAAAAAAAARHPEiA9klFqtGkBoVlSIdWlkLjEuMgCRgw9CQJKDHoSA"
+    "mIEARZiBAYABAAAAAAAAFIWLbmVzdGVkLzEuMgBDfIR1bmQAtgEAAAAAAADYc8SIeu4QRrjscdtW"
+    "VIZ1aWQuMgCRgx6EgJKDPQkAmIEARZiBAYABAAAAAAAAEIWHY2hhcC4yAEN8hHVuZAC2AQAAAAAA"
+    "AERzxIik77DMKqRyzFZUiHVpZC4yLjEAkYMehICSgy3GwJiBAEWYgQGAAQAAAAAAABSFi25lc3Rl"
+    "ZC4yLjEAQ3yEdW5kALYBAAAAAAAARHPEiDvwt+5+V1ktVlSIdWlkLjIuMgCRgy3GwJKDPQkAmIEA"
+    "RZiBAYABAAAAAAAAFIWLbmVzdGVkLzIuMgBDfIR1bmQAH0O2dQEAAAAAAAAT54EAoAEAAAAAAAAH"
+    "oYWBAAAAABxTu2sBAAAAAAAAHLsBAAAAAAAAE7OBALcBAAAAAAAAB/eBAfGCA0wSVMNnAQAAAAAA"
+    "AatzcwEAAAAAAAAxY8ABAAAAAAAAC2PJiLcO5LhNZ4VdZ8gBAAAAAAAAEkWjiUNPTU1FTlRTAESH"
+    "g0VkAHNzAQAAAAAAADJjwAEAAAAAAAALY8SI5XQvx56/7CBnyAEAAAAAAAATRaOHQVJUSVNUAESH"
+    "hmFydC4xAHNzAQAAAAAAADRjwAEAAAAAAAALY8SIJblqOkdHPLNnyAEAAAAAAAAVRaOHQVJUSVNU"
+    "AESHiGFydC4xLjEAc3MBAAAAAAAANGPAAQAAAAAAAAtjxIgPZJRarRpAaGfIAQAAAAAAABVFo4dB"
+    "UlRJU1QARIeIYXJ0LjEuMgBzcwEAAAAAAAAyY8ABAAAAAAAAC2PEiHruEEa47HHbZ8gBAAAAAAAA"
+    "E0Wjh0FSVElTVABEh4ZhcnQuMgBzcwEAAAAAAAA0Y8ABAAAAAAAAC2PEiKTvsMwqpHLMZ8gBAAAA"
+    "AAAAFUWjh0FSVElTVABEh4hhcnQuMi4xAHNzAQAAAAAAADRjwAEAAAAAAAALY8SIO/C37n5XWS1n"
+    "yAEAAAAAAAAVRaOHQVJUSVNUAESHiGFydC4yLjIA";
+
+static void
+pad_added_cb (GstElement * matroskademux, GstPad * pad, gpointer user_data)
+{
+  GstHarness *h = user_data;
+
+  GST_LOG_OBJECT (pad, "got new source pad");
+  gst_harness_add_element_src_pad (h, pad);
+}
+
+static void
+pull_and_check_buffer (GstHarness * h, GstClockTime pts, GstClockTime duration,
+    const gchar * output)
+{
+  GstMapInfo map;
+  GstBuffer *buf;
+
+  /* wait for buffer */
+  buf = gst_harness_pull (h);
+
+  /* Make sure there's no 0-terminator in there */
+  fail_unless (gst_buffer_map (buf, &map, GST_MAP_READ));
+  GST_MEMDUMP ("subtitle buffer", map.data, map.size);
+  fail_unless (map.size > 0);
+  fail_unless (map.data[map.size - 1] != '\0');
+  if (output != NULL && memcmp (map.data, output, map.size) != 0) {
+    g_printerr ("Got:\n");
+    gst_util_dump_mem (map.data, map.size);;
+    g_printerr ("Wanted:\n");
+    gst_util_dump_mem ((guint8 *) output, strlen (output));
+    g_error ("Did not get output expected.");
+  }
+
+  gst_buffer_unmap (buf, &map);
+
+  fail_unless_equals_int64 (pts, GST_BUFFER_PTS (buf));
+  fail_unless_equals_int64 (duration, GST_BUFFER_DURATION (buf));
+
+  gst_buffer_unref (buf);
+}
+
+GST_START_TEST (test_sub_terminator)
+{
+  GstHarness *h;
+  GstBuffer *buf;
+  guchar *mkv_data;
+  gsize mkv_size;
+
+  h = gst_harness_new_with_padnames ("matroskademux", "sink", NULL);
+
+  g_signal_connect (h->element, "pad-added", G_CALLBACK (pad_added_cb), h);
+
+  mkv_data = g_base64_decode (mkv_sub_base64, &mkv_size);
+  fail_unless (mkv_data != NULL);
+
+  gst_harness_set_src_caps_str (h, "video/x-matroska");
+
+  buf = gst_buffer_new_wrapped (mkv_data, mkv_size);
+  GST_BUFFER_OFFSET (buf) = 0;
+
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, buf));
+  gst_harness_push_event (h, gst_event_new_eos ());
+
+  pull_and_check_buffer (h, 1 * GST_SECOND, 2 * GST_SECOND, "foo");
+  pull_and_check_buffer (h, 4 * GST_SECOND, 2 * GST_SECOND, "<i>bar</i>");
+  pull_and_check_buffer (h, 7 * GST_SECOND, 2 * GST_SECOND, "baz");
+  pull_and_check_buffer (h, 11 * GST_SECOND, 2 * GST_SECOND, "f\303\266");
+  pull_and_check_buffer (h, 14 * GST_SECOND, 2 * GST_SECOND, "<i>bar</i>");
+  /* The input is invalid UTF-8 here, what happens might depend on locale */
+  pull_and_check_buffer (h, 17 * GST_SECOND, 2 * GST_SECOND, NULL);
+
+  fail_unless (gst_harness_try_pull (h) == NULL);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+/* Recursively compare 2 toc entries */
+static void
+check_toc_entries (const GstTocEntry * original, const GstTocEntry * other)
+{
+  gint64 start, stop, other_start, other_stop;
+  GstTocEntryType original_type, other_type;
+  const gchar *original_string_uid = NULL, *other_string_uid = NULL;
+  GstTagList *original_tags, *other_tags;
+  GList *cur, *other_cur;
+
+  original_type = gst_toc_entry_get_entry_type (original);
+  other_type = gst_toc_entry_get_entry_type (other);
+  fail_unless (original_type == other_type);
+
+  if (original_type != GST_TOC_ENTRY_TYPE_EDITION) {
+    original_string_uid = gst_toc_entry_get_uid (original);
+    other_string_uid = gst_toc_entry_get_uid (other);
+    fail_unless (g_strcmp0 (original_string_uid, other_string_uid) == 0);
+  }
+
+  if (original_type != GST_TOC_ENTRY_TYPE_EDITION) {
+    gst_toc_entry_get_start_stop_times (original, &start, &stop);
+    gst_toc_entry_get_start_stop_times (other, &other_start, &other_stop);
+
+    fail_unless (start == other_start && stop == other_stop);
+  }
+
+  /* tags */
+  original_tags = gst_toc_entry_get_tags (original);
+  other_tags = gst_toc_entry_get_tags (other);
+  fail_unless (gst_tag_list_is_equal (original_tags, other_tags));
+
+  other_cur = gst_toc_entry_get_sub_entries (other);
+  for (cur = gst_toc_entry_get_sub_entries (original); cur != NULL;
+      cur = cur->next) {
+    fail_unless (other_cur != NULL);
+
+    check_toc_entries (cur->data, other_cur->data);
+
+    other_cur = other_cur->next;
+  }
+}
+
+/* Create a new chapter */
+static GstTocEntry *
+new_chapter (const guint chapter_nb, const gint64 start, const gint64 stop)
+{
+  GstTocEntry *toc_entry, *toc_sub_entry;
+  GstTagList *tags;
+  gchar title[32];
+  gchar artist[32];
+  gchar str_uid[32];
+
+  g_snprintf (str_uid, sizeof (str_uid), "uid.%d", chapter_nb);
+  toc_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, str_uid);
+  gst_toc_entry_set_start_stop_times (toc_entry, start, stop);
+
+  g_snprintf (title, sizeof (title), "chap.%d", chapter_nb);
+  g_snprintf (artist, sizeof (artist), "art.%d", chapter_nb);
+  tags = gst_tag_list_new (GST_TAG_TITLE, title, GST_TAG_ARTIST, artist, NULL);
+  gst_toc_entry_set_tags (toc_entry, tags);
+
+  g_snprintf (str_uid, sizeof (str_uid), "uid.%d.1", chapter_nb);
+  toc_sub_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, str_uid);
+  gst_toc_entry_set_start_stop_times (toc_sub_entry, start, (start + stop) / 2);
+
+  g_snprintf (title, sizeof (title), "nested.%d.1", chapter_nb);
+  g_snprintf (artist, sizeof (artist), "art.%d.1", chapter_nb);
+  tags = gst_tag_list_new (GST_TAG_TITLE, title, GST_TAG_ARTIST, artist, NULL);
+  gst_toc_entry_set_tags (toc_sub_entry, tags);
+
+  gst_toc_entry_append_sub_entry (toc_entry, toc_sub_entry);
+
+  g_snprintf (str_uid, sizeof (str_uid), "uid.%d.2", chapter_nb);
+  toc_sub_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, str_uid);
+  gst_toc_entry_set_start_stop_times (toc_sub_entry, (start + stop) / 2, stop);
+
+  g_snprintf (title, sizeof (title), "nested/%d.2", chapter_nb);
+  g_snprintf (artist, sizeof (artist), "art.%d.2", chapter_nb);
+  tags = gst_tag_list_new (GST_TAG_TITLE, title, GST_TAG_ARTIST, artist, NULL);
+  gst_toc_entry_set_tags (toc_sub_entry, tags);
+
+  gst_toc_entry_append_sub_entry (toc_entry, toc_sub_entry);
+
+  return toc_entry;
+}
+
+/* Create a reference toc which matches what is expected in mkv_toc_base64 */
+static GstToc *
+new_reference_toc (void)
+{
+  GstToc *ref_toc;
+  GstTocEntry *toc_edition_entry, *toc_entry;
+  GstTagList *tags;
+
+  ref_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
+
+  toc_edition_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, "00");
+  tags = gst_tag_list_new (GST_TAG_COMMENT, "Ed", NULL);
+  gst_toc_entry_set_tags (toc_edition_entry, tags);
+
+  toc_entry = new_chapter (1, 0 * GST_MSECOND, 2 * GST_MSECOND);
+  gst_toc_entry_append_sub_entry (toc_edition_entry, toc_entry);
+
+  toc_entry = new_chapter (2, 2 * GST_MSECOND, 4 * GST_MSECOND);
+  gst_toc_entry_append_sub_entry (toc_edition_entry, toc_entry);
+
+  gst_toc_append_entry (ref_toc, toc_edition_entry);
+
+  return ref_toc;
+}
+
+GST_START_TEST (test_toc_demux)
+{
+  GstHarness *h;
+  GstBuffer *buf;
+  guchar *mkv_data;
+  gsize mkv_size;
+  GstEvent *event;
+  gboolean update;
+  GstToc *ref_toc, *demuxed_toc = NULL;
+  GList *ref_cur, *demuxed_cur;
+
+  h = gst_harness_new_with_padnames ("matroskademux", "sink", NULL);
+
+  g_signal_connect (h->element, "pad-added", G_CALLBACK (pad_added_cb), h);
+
+  mkv_data = g_base64_decode (mkv_toc_base64, &mkv_size);
+  fail_unless (mkv_data != NULL);
+
+  gst_harness_set_src_caps_str (h, "audio/x-matroska");
+
+  buf = gst_buffer_new_wrapped (mkv_data, mkv_size);
+  GST_BUFFER_OFFSET (buf) = 0;
+
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, buf));
+  gst_harness_push_event (h, gst_event_new_eos ());
+
+  event = gst_harness_try_pull_event (h);
+  fail_unless (event != NULL);
+
+  while (event != NULL) {
+    if (event->type == GST_EVENT_TOC) {
+      gst_event_parse_toc (event, &demuxed_toc, &update);
+      gst_event_unref (event);
+      break;
+    }
+    gst_event_unref (event);
+    event = gst_harness_try_pull_event (h);
+  }
+
+  fail_unless (demuxed_toc != NULL);
+  ref_toc = new_reference_toc ();
+
+  demuxed_cur = gst_toc_get_entries (demuxed_toc);
+  for (ref_cur = gst_toc_get_entries (ref_toc); ref_cur != NULL;
+      ref_cur = ref_cur->next) {
+    fail_unless (demuxed_cur != NULL);
+
+    check_toc_entries (ref_cur->data, demuxed_cur->data);
+    demuxed_cur = demuxed_cur->next;
+  }
+
+  gst_toc_unref (ref_toc);
+  gst_toc_unref (demuxed_toc);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+static Suite *
+matroskademux_suite (void)
+{
+  Suite *s = suite_create ("matroskademux");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_sub_terminator);
+  tcase_add_test (tc_chain, test_toc_demux);
+
+  return s;
+}
+
+GST_CHECK_MAIN (matroskademux);
diff --git a/tests/check/elements/matroskamux.c b/tests/check/elements/matroskamux.c
new file mode 100644
index 0000000..bf804bb
--- /dev/null
+++ b/tests/check/elements/matroskamux.c
@@ -0,0 +1,1019 @@
+/* GStreamer
+ *
+ * unit test for matroskamux
+ *
+ * Copyright (C) <2005> Michal Benes <michal.benes@xeris.cz>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+#include <gst/base/gstadapter.h>
+#include <gst/check/gstharness.h>
+
+#define AC3_CAPS_STRING "audio/x-ac3, " \
+                        "channels = (int) 1, " \
+                        "rate = (int) 8000"
+#define VORBIS_TMPL_CAPS_STRING "audio/x-vorbis, " \
+                                "channels = (int) 1, " \
+                                "rate = (int) 8000, " \
+                                "streamheader=(buffer)<10, 2020, 303030>"
+
+static GstHarness *
+setup_matroskamux_harness (const gchar * src_pad_str)
+{
+  GstHarness *h;
+
+  h = gst_harness_new_with_padnames ("matroskamux", "audio_%u", "src");
+  gst_harness_set_src_caps_str (h, src_pad_str);
+  gst_harness_set_sink_caps_str (h, "video/x-matroska; audio/x-matroska");
+
+  return h;
+}
+
+static gboolean
+seekable_sinkpad_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  gboolean ret = FALSE;
+
+  if (GST_QUERY_TYPE (query) == GST_QUERY_SEEKING) {
+    gst_query_set_seeking (query, GST_FORMAT_BYTES, TRUE, 0, -1);
+    ret = TRUE;
+  }
+
+  return ret;
+}
+
+#define compare_buffer_to_data(buffer, data, data_size)             \
+G_STMT_START {                                                      \
+fail_unless_equals_int (data_size, gst_buffer_get_size (buffer));   \
+fail_unless (gst_buffer_memcmp (buffer, 0, data, data_size) == 0);  \
+} G_STMT_END
+
+static void
+test_ebml_header_with_version (gint version,
+    gconstpointer data, gsize data_size)
+{
+  GstHarness *h;
+  GstBuffer *inbuffer, *outbuffer;
+
+  h = setup_matroskamux_harness (AC3_CAPS_STRING);
+  g_object_set (h->element, "version", version, NULL);
+
+  inbuffer = gst_harness_create_buffer (h, 1);
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer));
+  fail_unless_equals_int (2, gst_harness_buffers_received (h));
+
+  outbuffer = gst_harness_pull (h);
+  compare_buffer_to_data (outbuffer, data, data_size);
+  gst_buffer_unref (outbuffer);
+
+  gst_harness_teardown (h);
+}
+
+GST_START_TEST (test_ebml_header_v1)
+{
+  guint8 data_v1[] = {
+    0x1a, 0x45, 0xdf, 0xa3,     /* master ID */
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14,
+    0x42, 0x82,                 /* doctype */
+    0x89,                       /* 9 bytes */
+    0x6d, 0x61, 0x74, 0x72, 0x6f, 0x73, 0x6b, 0x61, 0x00,       /* "matroska" */
+    0x42, 0x87,                 /* doctypeversion */
+    0x81,                       /* 1 byte */
+    0x01,                       /* 1 */
+    0x42, 0x85,                 /* doctypereadversion */
+    0x81,                       /* 1 byte */
+    0x01,                       /* 1 */
+  };
+
+  test_ebml_header_with_version (1, data_v1, sizeof (data_v1));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_ebml_header_v2)
+{
+  guint8 data_v2[] = {
+    0x1a, 0x45, 0xdf, 0xa3,     /* master ID */
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14,
+    0x42, 0x82,                 /* doctype */
+    0x89,                       /* 9 bytes */
+    0x6d, 0x61, 0x74, 0x72, 0x6f, 0x73, 0x6b, 0x61, 0x00,       /* "matroska" */
+    0x42, 0x87,                 /* doctypeversion */
+    0x81,                       /* 1 byte */
+    0x02,                       /* 2 */
+    0x42, 0x85,                 /* doctypereadversion */
+    0x81,                       /* 1 byte */
+    0x02,                       /* 2 */
+  };
+
+  test_ebml_header_with_version (2, data_v2, sizeof (data_v2));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_vorbis_header)
+{
+  GstHarness *h;
+  GstBuffer *inbuffer, *outbuffer;
+  gboolean vorbis_header_found = FALSE;
+  gint j;
+  gsize buffer_size;
+  guint8 data[] =
+      { 0x63, 0xa2, 0x89, 0x02, 0x01, 0x02, 0x10, 0x20, 0x20, 0x30, 0x30,
+    0x30
+  };
+
+  h = setup_matroskamux_harness (VORBIS_TMPL_CAPS_STRING);
+
+  inbuffer = gst_harness_create_buffer (h, 1);
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer));
+
+  outbuffer = gst_harness_pull (h);
+  while (outbuffer != NULL) {
+    buffer_size = gst_buffer_get_size (outbuffer);
+
+    if (!vorbis_header_found && buffer_size >= sizeof (data)) {
+      for (j = 0; j <= buffer_size - sizeof (data); j++) {
+        if (gst_buffer_memcmp (outbuffer, j, data, sizeof (data)) == 0) {
+          vorbis_header_found = TRUE;
+          break;
+        }
+      }
+    }
+
+    ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
+    gst_buffer_unref (outbuffer);
+
+    outbuffer = gst_harness_try_pull (h);
+  }
+
+  fail_unless (vorbis_header_found);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+
+static void
+test_block_group_with_version (gint version,
+    gconstpointer data0, gsize data0_size)
+{
+  GstHarness *h;
+  GstBuffer *inbuffer, *outbuffer;
+  guint8 data1[] = { 0x42 };
+
+  h = setup_matroskamux_harness (AC3_CAPS_STRING);
+  g_object_set (h->element, "version", version, NULL);
+
+  /* Generate the header */
+  inbuffer = gst_harness_create_buffer (h, 1);
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer));
+  fail_unless_equals_int (5, gst_harness_buffers_received (h));
+
+  outbuffer = gst_harness_pull (h);
+  fail_unless (outbuffer != NULL);
+  while (outbuffer != NULL) {
+    gst_buffer_unref (outbuffer);
+    outbuffer = gst_harness_try_pull (h);
+  }
+
+  /* Now push a buffer */
+  inbuffer = gst_harness_create_buffer (h, 1);
+  gst_buffer_fill (inbuffer, 0, data1, sizeof (data1));
+  GST_BUFFER_TIMESTAMP (inbuffer) = 1000000;
+
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer));
+
+  outbuffer = gst_harness_pull (h);
+  compare_buffer_to_data (outbuffer, data0, data0_size);
+  gst_buffer_unref (outbuffer);
+
+  outbuffer = gst_harness_pull (h);
+  compare_buffer_to_data (outbuffer, data1, sizeof (data1));
+  gst_buffer_unref (outbuffer);
+
+  gst_harness_teardown (h);
+}
+
+GST_START_TEST (test_block_group_v1)
+{
+  guint8 data0_v1[] = { 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+    0xa1, 0x85,
+    0x81, 0x00, 0x01, 0x00
+  };
+
+  test_block_group_with_version (1, data0_v1, sizeof (data0_v1));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_block_group_v2)
+{
+  guint8 data0_v2[] = { 0xa3, 0x85, 0x81, 0x00, 0x01, 0x00 };
+
+  test_block_group_with_version (2, data0_v2, sizeof (data0_v2));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_reset)
+{
+  GstHarness *h;
+  GstBuffer *inbuffer;
+  GstBuffer *outbuffer;
+
+  h = setup_matroskamux_harness (AC3_CAPS_STRING);
+
+  inbuffer = gst_harness_create_buffer (h, 1);
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer));
+  fail_unless_equals_int (5, gst_harness_buffers_received (h));
+
+  outbuffer = gst_harness_pull (h);
+  fail_unless (outbuffer != NULL);
+  while (outbuffer != NULL) {
+    gst_buffer_unref (outbuffer);
+    outbuffer = gst_harness_try_pull (h);
+  }
+
+  fail_unless_equals_int (GST_STATE_CHANGE_SUCCESS,
+      gst_element_set_state (h->element, GST_STATE_NULL));
+
+  gst_harness_play (h);
+
+  inbuffer = gst_harness_create_buffer (h, 1);
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer));
+
+  outbuffer = gst_harness_pull (h);
+  fail_unless (outbuffer != NULL);
+  while (outbuffer != NULL) {
+    gst_buffer_unref (outbuffer);
+    outbuffer = gst_harness_try_pull (h);
+  }
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_link_webmmux_webm_sink)
+{
+  GstHarness *h;
+
+  h = gst_harness_new_with_padnames ("webmmux", "audio_%u", "src");
+  fail_unless (h != NULL);
+
+  gst_harness_set_sink_caps_str (h, "video/webm; audio/webm");
+
+  gst_harness_play (h);
+
+  fail_unless_equals_int (GST_STATE_CHANGE_SUCCESS,
+      gst_element_set_state (h->element, GST_STATE_NULL));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+static gint64 timecodescales[] = {
+  GST_USECOND,
+  GST_MSECOND,
+  GST_MSECOND * 10,
+  GST_MSECOND * 100,
+  GST_MSECOND * 400,
+  /* FAILS: ? GST_MSECOND * 500, a bug? */
+};
+
+GST_START_TEST (test_timecodescale)
+{
+  GstBuffer *inbuffer, *outbuffer;
+  guint8 data_h0[] = {
+    0xa3, 0x85, 0x81, 0x00, 0x00, 0x00,
+  };
+  guint8 data_h1[] = {
+    0xa3, 0x85, 0x81, 0x00, 0x01, 0x00,
+  };
+
+  GstHarness *h = setup_matroskamux_harness (AC3_CAPS_STRING);
+  gint64 timecodescale = timecodescales[__i__];
+
+  g_object_set (h->element, "timecodescale", timecodescale, NULL);
+  g_object_set (h->element, "version", 2, NULL);
+
+  /* Buffer 0 */
+  inbuffer = gst_harness_create_buffer (h, 1);
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer));
+
+  /* pull out headers */
+  gst_buffer_unref (gst_harness_pull (h));
+  gst_buffer_unref (gst_harness_pull (h));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* verify header and drop the data */
+  outbuffer = gst_harness_pull (h);
+  compare_buffer_to_data (outbuffer, data_h0, sizeof (data_h0));
+  gst_buffer_unref (outbuffer);
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* Buffer 1 */
+  inbuffer = gst_harness_create_buffer (h, 1);
+  GST_BUFFER_TIMESTAMP (inbuffer) = timecodescale;
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer));
+
+  /* verify header and drop the data */
+  outbuffer = gst_harness_pull (h);
+  compare_buffer_to_data (outbuffer, data_h1, sizeof (data_h1));
+  gst_buffer_unref (outbuffer);
+  gst_buffer_unref (gst_harness_pull (h));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+/* Create a new chapter */
+static GstTocEntry *
+new_chapter (const guint chapter_nb, const gint64 start, const gint64 stop)
+{
+  GstTocEntry *toc_entry, *toc_sub_entry;
+  GstTagList *tags;
+  gchar title[32];
+  gchar artist[32];
+  gchar str_uid[32];
+
+  g_snprintf (str_uid, sizeof (str_uid), "uid.%d", chapter_nb);
+  toc_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, str_uid);
+  gst_toc_entry_set_start_stop_times (toc_entry, start, stop);
+
+  g_snprintf (title, sizeof (title), "chap.%d", chapter_nb);
+  g_snprintf (artist, sizeof (artist), "art.%d", chapter_nb);
+  tags = gst_tag_list_new (GST_TAG_TITLE, title, GST_TAG_ARTIST, artist, NULL);
+  gst_toc_entry_set_tags (toc_entry, tags);
+
+  g_snprintf (str_uid, sizeof (str_uid), "uid.%d.1", chapter_nb);
+  toc_sub_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, str_uid);
+  gst_toc_entry_set_start_stop_times (toc_sub_entry, start, (start + stop) / 2);
+
+  g_snprintf (title, sizeof (title), "nested.%d.1", chapter_nb);
+  g_snprintf (artist, sizeof (artist), "art.%d.1", chapter_nb);
+  tags = gst_tag_list_new (GST_TAG_TITLE, title, GST_TAG_ARTIST, artist, NULL);
+  gst_toc_entry_set_tags (toc_sub_entry, tags);
+
+  gst_toc_entry_append_sub_entry (toc_entry, toc_sub_entry);
+
+  g_snprintf (str_uid, sizeof (str_uid), "uid.%d.2", chapter_nb);
+  toc_sub_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, str_uid);
+  gst_toc_entry_set_start_stop_times (toc_sub_entry, (start + stop) / 2, stop);
+
+  g_snprintf (title, sizeof (title), "nested/%d.2", chapter_nb);
+  g_snprintf (artist, sizeof (artist), "art.%d.2", chapter_nb);
+  tags = gst_tag_list_new (GST_TAG_TITLE, title, GST_TAG_ARTIST, artist, NULL);
+  gst_toc_entry_set_tags (toc_sub_entry, tags);
+
+  gst_toc_entry_append_sub_entry (toc_entry, toc_sub_entry);
+
+  return toc_entry;
+}
+
+/* Create a reference toc which includes a master edition entry */
+static GstToc *
+new_reference_toc (void)
+{
+  GstToc *ref_toc;
+  GstTocEntry *toc_edition_entry, *toc_entry;
+  GstTagList *tags;
+
+  ref_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
+
+  toc_edition_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, "00");
+  tags = gst_tag_list_new (GST_TAG_COMMENT, "Ed", NULL);
+  gst_toc_entry_set_tags (toc_edition_entry, tags);
+
+  toc_entry = new_chapter (1, 0 * GST_MSECOND, 2 * GST_MSECOND);
+  gst_toc_entry_append_sub_entry (toc_edition_entry, toc_entry);
+
+  toc_entry = new_chapter (2, 2 * GST_MSECOND, 4 * GST_MSECOND);
+  gst_toc_entry_append_sub_entry (toc_edition_entry, toc_entry);
+
+  gst_toc_append_entry (ref_toc, toc_edition_entry);
+
+  return ref_toc;
+}
+
+/* Create a toc which includes chapters without edition entry */
+static GstToc *
+new_no_edition_toc (void)
+{
+  GstToc *ref_toc;
+  GstTocEntry *toc_entry;
+
+  ref_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
+
+  toc_entry = new_chapter (1, 0 * GST_MSECOND, 2 * GST_MSECOND);
+  gst_toc_append_entry (ref_toc, toc_entry);
+
+  toc_entry = new_chapter (2, 2 * GST_MSECOND, 4 * GST_MSECOND);
+  gst_toc_append_entry (ref_toc, toc_entry);
+
+  return ref_toc;
+}
+
+static guint64
+read_integer (GstMapInfo * info, gsize * index, guint64 len)
+{
+  guint64 total = 0;
+
+  for (; len > 0; --len) {
+    total = (total << 8) | GST_READ_UINT8 (info->data + *index);
+    ++(*index);
+  }
+
+  return total;
+}
+
+static guint64
+read_length (GstMapInfo * info, gsize * index)
+{
+  gint len_mask = 0x80, read = 1;
+  guint64 total;
+  guint8 b;
+
+  b = GST_READ_UINT8 (info->data + *index);
+  ++(*index);
+  total = (guint64) b;
+  while (read <= 8 && !(total & len_mask)) {
+    read++;
+    len_mask >>= 1;
+  }
+  total &= (len_mask - 1);
+
+  for (; read > 1; --read) {
+    total = (total << 8) | GST_READ_UINT8 (info->data + *index);
+    ++(*index);
+  }
+
+  return total;
+}
+
+static gboolean
+check_id (GstMapInfo * info, gsize * index,
+    guint8 * tag, gint tag_len, guint64 * len)
+{
+  if (memcmp (info->data + *index, tag, tag_len) == 0) {
+    *index += tag_len;
+    *len = read_length (info, index);
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+static gboolean
+check_id_read_int (GstMapInfo * info, gsize * index,
+    guint8 * tag, gint tag_len, guint64 * value)
+{
+  guint64 len;
+
+  if (check_id (info, index, tag, tag_len, &len)) {
+    *value = read_integer (info, index, len);
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+/* Check the toc entry against the muxed buffer
+ * Returns the internal UID */
+static void
+check_chapter (GstTocEntry * toc_entry, GstTocEntry * internal_toc_entry,
+    GstMapInfo * info, gsize * index, gint last_offset)
+{
+  guint64 len, value, uid;
+  gint64 start_ref, end_ref;
+  gchar s_uid[32];
+  const gchar *str_uid;
+  GstTocEntry *internal_chapter;
+  GList *cur_sub_chap;
+  GstTagList *tags;
+  gchar *title;
+
+  guint8 chapter_atom[] = { 0xb6 };
+  guint8 chapter_uid[] = { 0x73, 0xc4 };
+  guint8 chapter_str_uid[] = { 0x56, 0x54 };
+  guint8 chapter_start[] = { 0x91 };
+  guint8 chapter_end[] = { 0x92 };
+  guint8 chapter_flag_hidden[] = { 0x98 };
+  guint8 chapter_flag_enabled[] = { 0x45, 0x98 };
+  guint8 chapter_segment_uid[] = { 0x6e, 0x67 };
+  guint8 chapter_segment_edition_uid[] = { 0x6e, 0xbc };
+  guint8 chapter_physical_equiv[] = { 0x63, 0xc3 };
+  guint8 chapter_track[] = { 0x8f };
+  guint8 chapter_track_nb[] = { 0x89 };
+  guint8 chapter_display[] = { 0x80 };
+  guint8 chapter_string[] = { 0x85 };
+  guint8 chapter_language[] = { 0x43, 0x7c };
+
+  fail_unless (check_id (info, index, chapter_atom,
+          sizeof (chapter_atom), &len));
+
+  fail_unless (check_id_read_int (info, index, chapter_uid,
+          sizeof (chapter_uid), &uid));
+
+  /* optional StringUID */
+  if (check_id (info, index, chapter_str_uid, sizeof (chapter_str_uid), &len)) {
+    str_uid = gst_toc_entry_get_uid (toc_entry);
+    fail_unless (memcmp (info->data + *index, str_uid, strlen (str_uid)) == 0);
+    *index += len;
+  }
+
+  gst_toc_entry_get_start_stop_times (toc_entry, &start_ref, &end_ref);
+
+  fail_unless (check_id_read_int (info, index, chapter_start,
+          sizeof (chapter_start), &value));
+  fail_unless_equals_int (start_ref, value);
+
+  /* optional chapter end */
+  if (check_id_read_int (info, index, chapter_end,
+          sizeof (chapter_end), &value)) {
+    fail_unless_equals_int (end_ref, value);
+  }
+
+  fail_unless (check_id_read_int (info, index, chapter_flag_hidden,
+          sizeof (chapter_flag_hidden), &value));
+
+  fail_unless (check_id_read_int (info, index, chapter_flag_enabled,
+          sizeof (chapter_flag_enabled), &value));
+
+  /* optional segment UID */
+  check_id_read_int (info, index, chapter_segment_uid,
+      sizeof (chapter_segment_uid), &value);
+
+  /* optional segment edition UID */
+  check_id_read_int (info, index, chapter_segment_edition_uid,
+      sizeof (chapter_segment_edition_uid), &value);
+
+  /* optional physical equiv */
+  check_id_read_int (info, index, chapter_physical_equiv,
+      sizeof (chapter_physical_equiv), &value);
+
+  /* optional chapter track */
+  if (check_id (info, index, chapter_track, sizeof (chapter_track), &len)) {
+    fail_unless (check_id_read_int (info, index, chapter_track_nb,
+            sizeof (chapter_track_nb), &value));
+  }
+
+  /* FIXME: there can be several chapter displays */
+  if (check_id (info, index, chapter_display, sizeof (chapter_display), &len)) {
+    /* chapter display */
+    fail_unless (check_id (info, index, chapter_string,
+            sizeof (chapter_string), &len));
+
+    tags = gst_toc_entry_get_tags (toc_entry);
+    if (gst_tag_list_get_tag_size (tags, GST_TAG_TITLE) > 0) {
+      gst_tag_list_get_string_index (tags, GST_TAG_TITLE, 0, &title);
+      fail_unless (memcmp (info->data + *index, title, strlen (title)) == 0);
+      g_free (title);
+    }
+    *index += len;
+
+    fail_unless (check_id (info, index, chapter_language,
+            sizeof (chapter_language), &len));
+    /* TODO: define language - always "und" ATM */
+    *index += len;
+  }
+
+  /* TODO: add remaining fields (not used in current matroska-mux) */
+
+  g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT, uid);
+  internal_chapter = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, s_uid);
+  gst_toc_entry_append_sub_entry (internal_toc_entry, internal_chapter);
+
+  cur_sub_chap = gst_toc_entry_get_sub_entries (toc_entry);
+  while (cur_sub_chap != NULL && *index < last_offset) {
+    check_chapter (cur_sub_chap->data, internal_chapter, info,
+        index, last_offset);
+    cur_sub_chap = cur_sub_chap->next;
+  }
+
+  fail_unless (cur_sub_chap == NULL);
+}
+
+/* Check the reference toc against the muxed buffer */
+static void
+check_toc (GstToc * ref_toc, GstToc * internal_toc,
+    GstMapInfo * info, gsize * index)
+{
+  guint64 len, value, uid;
+  gchar s_uid[32];
+  gint last_offset;
+  GList *cur_entry, *cur_chapter;
+  GstTocEntry *internal_edition;
+
+  guint8 edition_entry[] = { 0x45, 0xb9 };
+  guint8 edition_uid[] = { 0x45, 0xbc };
+  guint8 edition_flag_hidden[] = { 0x45, 0xbd };
+  guint8 edition_flag_default[] = { 0x45, 0xdb };
+  guint8 edition_flag_ordered[] = { 0x45, 0xdd };
+
+  /* edition entry */
+  fail_unless (check_id (info, index, edition_entry,
+          sizeof (edition_entry), &len));
+  last_offset = *index + (gint) len;
+
+  cur_entry = gst_toc_get_entries (ref_toc);
+  while (cur_entry != NULL && *index < last_offset) {
+    uid = 0;
+    check_id_read_int (info, index, edition_uid, sizeof (edition_uid), &uid);
+    g_snprintf (s_uid, sizeof (s_uid), "%" G_GINT64_FORMAT, uid);
+    internal_edition = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, s_uid);
+    gst_toc_append_entry (internal_toc, internal_edition);
+
+    fail_unless (check_id_read_int (info, index, edition_flag_hidden,
+            sizeof (edition_flag_hidden), &value));
+
+    fail_unless (check_id_read_int (info, index, edition_flag_default,
+            sizeof (edition_flag_default), &value));
+
+    /* optional */
+    check_id_read_int (info, index, edition_flag_ordered,
+        sizeof (edition_flag_ordered), &value);
+
+    cur_chapter = gst_toc_entry_get_sub_entries (cur_entry->data);
+    while (cur_chapter != NULL && *index < last_offset) {
+      check_chapter (cur_chapter->data, internal_edition, info,
+          index, last_offset);
+      cur_chapter = cur_chapter->next;
+    }
+    fail_unless (cur_chapter == NULL);
+
+    cur_entry = cur_entry->next;
+  }
+
+  fail_unless (cur_entry == NULL && *index == last_offset);
+}
+
+static GstTocEntry *
+find_toc_entry (GstTocEntry * ref_toc_entry, GstTocEntry * internal_toc_entry,
+    guint64 uid)
+{
+  GList *cur_ref_entry, *cur_internal_entry;
+  guint64 internal_uid;
+  GstTocEntry *result = NULL;
+
+  internal_uid = g_ascii_strtoull (gst_toc_entry_get_uid (internal_toc_entry),
+      NULL, 10);
+  if (uid == internal_uid) {
+    result = ref_toc_entry;
+  } else {
+    cur_ref_entry = gst_toc_entry_get_sub_entries (ref_toc_entry);
+    cur_internal_entry = gst_toc_entry_get_sub_entries (internal_toc_entry);
+    while (cur_ref_entry != NULL && cur_internal_entry != NULL) {
+      result = find_toc_entry (cur_ref_entry->data, cur_internal_entry->data,
+          uid);
+
+      if (result != NULL) {
+        break;
+      }
+
+      cur_ref_entry = cur_ref_entry->next;
+      cur_internal_entry = cur_internal_entry->next;
+    }
+  }
+
+  return result;
+}
+
+static void
+find_and_check_tags (GstToc * ref_toc, GstToc * internal_toc, GstMapInfo * info,
+    guint64 uid, gchar * tag_name, gchar * tag_string)
+{
+  GList *cur_ref_entry, *cur_internal_entry;
+  GstTocEntry *ref_toc_entry = NULL;
+  GstTagList *tags;
+  const gchar *tag_type;
+  gchar *cur_tag_string;
+
+  /* find the reference toc entry matching the UID */
+  cur_ref_entry = gst_toc_get_entries (ref_toc);
+  cur_internal_entry = gst_toc_get_entries (internal_toc);
+  while (cur_ref_entry != NULL && cur_internal_entry != NULL) {
+    ref_toc_entry = find_toc_entry (cur_ref_entry->data,
+        cur_internal_entry->data, uid);
+
+    if (ref_toc_entry != NULL) {
+      break;
+    }
+
+    cur_ref_entry = cur_ref_entry->next;
+    cur_internal_entry = cur_internal_entry->next;
+  }
+
+  fail_unless (ref_toc_entry != NULL);
+
+  if (g_strcmp0 (tag_name, "ARTIST") == 0) {
+    tag_type = GST_TAG_ARTIST;
+  } else if (g_strcmp0 (tag_name, "COMMENTS") == 0) {
+    tag_type = GST_TAG_COMMENT;
+  } else {
+    tag_type = NULL;
+  }
+
+  fail_unless (tag_type != NULL);
+
+  tags = gst_toc_entry_get_tags (ref_toc_entry);
+  fail_unless (gst_tag_list_get_tag_size (tags, tag_type) > 0);
+  gst_tag_list_get_string_index (tags, tag_type, 0, &cur_tag_string);
+  fail_unless (g_strcmp0 (cur_tag_string, tag_string) == 0);
+  g_free (cur_tag_string);
+}
+
+static void
+check_tags (GstToc * ref_toc, GstToc * internal_toc,
+    GstMapInfo * info, gsize * index)
+{
+  gboolean found_tags = FALSE, must_check_tag = FALSE;
+  guint64 len, value, uid;
+  gsize last_offset, next_tag;
+  gchar *tag_name_str, *tag_string_str;
+  guint8 tags[] = { 0x12, 0x54, 0xc3, 0x67 };
+  guint8 tag[] = { 0x73, 0x73 };
+  guint8 tag_targets[] = { 0x63, 0xc0 };
+  guint8 tag_target_type_value[] = { 0x68, 0xca };
+  guint8 tag_target_type[] = { 0x63, 0xca };
+  guint8 tag_edition_uid[] = { 0x63, 0xc9 };
+  guint8 tag_chapter_uid[] = { 0x63, 0xc4 };
+  guint8 simple_tag[] = { 0x67, 0xc8 };
+  guint8 tag_name[] = { 0x45, 0xa3 };
+  guint8 tag_string[] = { 0x44, 0x87 };
+
+  if (info->size > *index + sizeof (tags)) {
+    for (; *index < info->size - sizeof (tags); ++(*index)) {
+      if (memcmp (info->data + *index, tags, sizeof (tags)) == 0) {
+        *index += sizeof (tags);
+
+        len = read_length (info, index);
+        last_offset = *index + len;
+
+        found_tags = TRUE;
+        break;
+      }
+    }
+  }
+
+  fail_unless (found_tags);
+
+  while (*index < last_offset) {
+    fail_unless (check_id (info, index, tag, sizeof (tag), &len));
+    next_tag = *index + len;
+
+    fail_unless (check_id (info, index, tag_targets,
+            sizeof (tag_targets), &len));
+
+    must_check_tag = FALSE;
+    check_id_read_int (info, index, tag_target_type_value,
+        sizeof (tag_target_type_value), &value);
+
+    if (check_id (info, index, tag_target_type, sizeof (tag_target_type), &len)) {
+      *index += len;
+    }
+
+    if (check_id_read_int (info, index, tag_chapter_uid,
+            sizeof (tag_chapter_uid), &uid)) {
+      must_check_tag = TRUE;
+    } else if (check_id_read_int (info, index, tag_edition_uid,
+            sizeof (tag_edition_uid), &uid)) {
+      must_check_tag = TRUE;
+    }
+
+    if (must_check_tag) {
+      fail_unless (check_id (info, index, simple_tag,
+              sizeof (simple_tag), &len));
+
+      fail_unless (check_id (info, index, tag_name, sizeof (tag_name), &len));
+      tag_name_str = g_strndup ((gchar *) info->data + *index, len);
+      *index += len;
+
+      fail_unless (check_id (info, index, tag_string, sizeof (tag_string),
+              &len));
+      tag_string_str = g_strndup ((gchar *) info->data + *index, len);
+      *index += len;
+
+      find_and_check_tags (ref_toc, internal_toc, info, uid,
+          tag_name_str, tag_string_str);
+
+      g_free (tag_name_str);
+      g_free (tag_string_str);
+    }
+
+    *index = next_tag;
+  }
+}
+
+static void
+check_segment (GstToc * ref_toc, GstToc * internal_toc,
+    GstMapInfo * info, gsize * index)
+{
+  guint8 matroska_segment[] = { 0x18, 0x53, 0x80, 0x67 };
+  guint8 matroska_seek_id_chapters[] = { 0x53, 0xab, 0x84,
+    0x10, 0x43, 0xA7, 0x70
+  };
+  guint8 matroska_seek_id_tags[] = { 0x53, 0xab, 0x84,
+    0x12, 0x54, 0xc3, 0x67
+  };
+  guint8 matroska_seek_pos[] = { 0x53, 0xac };
+  guint8 matroska_chapters[] = { 0x10, 0x43, 0xA7, 0x70 };
+
+  guint64 len, value, segment_offset, chapters_offset, tags_offset;
+  gboolean found_chapters_declaration = FALSE, found_tags_declaration = FALSE;
+
+  /* Segment */
+  fail_unless (info->size > sizeof (matroska_segment));
+  fail_unless (check_id (info, index, matroska_segment,
+          sizeof (matroska_segment), &len));
+
+  segment_offset = *index;
+
+  /* Search chapter declaration in seek head */
+  for (; *index < len - sizeof (matroska_seek_id_chapters); ++(*index)) {
+    if (memcmp (info->data + *index, matroska_seek_id_chapters,
+            sizeof (matroska_seek_id_chapters)) == 0) {
+      *index += sizeof (matroska_seek_id_chapters);
+
+      if (check_id_read_int (info, index, matroska_seek_pos,
+              sizeof (matroska_seek_pos), &value)) {
+        /* found chapter declaration */
+        found_chapters_declaration = TRUE;
+        chapters_offset = segment_offset + value;
+        break;
+      }
+    }
+  }
+
+  fail_unless (found_chapters_declaration);
+
+  *index = chapters_offset;
+  if (check_id (info, index, matroska_chapters,
+          sizeof (matroska_chapters), &len)) {
+    check_toc (ref_toc, internal_toc, info, index);
+  }
+
+  /* Search tags declaration in seek head */
+  for (*index = segment_offset; *index < len - sizeof (matroska_seek_id_tags);
+      ++(*index)) {
+    if (memcmp (info->data + *index, matroska_seek_id_tags,
+            sizeof (matroska_seek_id_tags)) == 0) {
+      *index += sizeof (matroska_seek_id_tags);
+
+      if (check_id_read_int (info, index, matroska_seek_pos,
+              sizeof (matroska_seek_pos), &value)) {
+        /* found tags declaration */
+        found_tags_declaration = TRUE;
+        tags_offset = segment_offset + value;
+        break;
+      }
+    }
+  }
+
+  fail_unless (found_tags_declaration);
+
+  *index = tags_offset;
+  check_tags (ref_toc, internal_toc, info, index);
+}
+
+static void
+test_toc (gboolean with_edition)
+{
+  GstHarness *h;
+  GstBuffer *inbuffer, *outbuffer, *merged_buffer;
+  GstMapInfo info;
+  guint64 len;
+  gsize index;
+  GstTocSetter *toc_setter;
+  GstToc *test_toc, *ref_toc, *internal_toc;
+
+  guint8 ebml_header[] = { 0x1a, 0x45, 0xdf, 0xa3 };
+
+  h = setup_matroskamux_harness (AC3_CAPS_STRING);
+
+  /* Make element seekable */
+  gst_pad_set_query_function (h->sinkpad, seekable_sinkpad_query);
+
+  toc_setter = GST_TOC_SETTER (h->element);
+  fail_unless (toc_setter != NULL);
+
+  if (with_edition) {
+    test_toc = new_reference_toc ();
+  } else {
+    test_toc = new_no_edition_toc ();
+  }
+  gst_toc_setter_set_toc (toc_setter, test_toc);
+  gst_toc_unref (test_toc);
+
+  inbuffer = gst_harness_create_buffer (h, 1);
+  gst_buffer_memset (inbuffer, 0, 0, 1);
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  GST_BUFFER_DURATION (inbuffer) = 1 * GST_MSECOND;
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, inbuffer));
+
+  /* send eos to ensure everything is written */
+  fail_unless (gst_harness_push_event (h, gst_event_new_eos ()));
+  ASSERT_MINI_OBJECT_REFCOUNT (test_toc, "test_toc", 1);
+
+  outbuffer = gst_harness_pull (h);
+  fail_unless (outbuffer != NULL);
+
+  /* Merge buffers */
+  merged_buffer = gst_buffer_new ();
+  while (outbuffer != NULL) {
+    if (outbuffer->offset == gst_buffer_get_size (merged_buffer)) {
+      gst_buffer_append_memory (merged_buffer,
+          gst_buffer_get_all_memory (outbuffer));
+    } else {
+      fail_unless (gst_buffer_map (outbuffer, &info, GST_MAP_READ));
+      gst_buffer_fill (merged_buffer, outbuffer->offset, info.data, info.size);
+      gst_buffer_unmap (outbuffer, &info);
+    }
+
+    gst_buffer_unref (outbuffer);
+    outbuffer = gst_harness_try_pull (h);
+  }
+
+  fail_unless (gst_buffer_map (merged_buffer, &info, GST_MAP_READ));
+  index = 0;
+
+  fail_unless (check_id (&info, &index, ebml_header,
+          sizeof (ebml_header), &len));
+  /* skip header */
+  index += len;
+
+  ref_toc = new_reference_toc ();
+  internal_toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
+  check_segment (ref_toc, internal_toc, &info, &index);
+  gst_toc_unref (internal_toc);
+  gst_toc_unref (ref_toc);
+
+  gst_buffer_unmap (merged_buffer, &info);
+  gst_buffer_unref (merged_buffer);
+  gst_harness_teardown (h);
+}
+
+GST_START_TEST (test_toc_with_edition)
+{
+  test_toc (TRUE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_toc_without_edition)
+{
+  test_toc (FALSE);
+}
+
+GST_END_TEST;
+
+static Suite *
+matroskamux_suite (void)
+{
+  Suite *s = suite_create ("matroskamux");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_ebml_header_v1);
+  tcase_add_test (tc_chain, test_ebml_header_v2);
+  tcase_add_test (tc_chain, test_vorbis_header);
+  tcase_add_test (tc_chain, test_block_group_v1);
+  tcase_add_test (tc_chain, test_block_group_v2);
+
+  tcase_add_test (tc_chain, test_reset);
+  tcase_add_test (tc_chain, test_link_webmmux_webm_sink);
+  tcase_add_loop_test (tc_chain, test_timecodescale,
+      0, G_N_ELEMENTS (timecodescales));
+
+  tcase_add_test (tc_chain, test_toc_with_edition);
+  tcase_add_test (tc_chain, test_toc_without_edition);
+  return s;
+}
+
+GST_CHECK_MAIN (matroskamux);
diff --git a/tests/check/elements/matroskaparse.c b/tests/check/elements/matroskaparse.c
new file mode 100644
index 0000000..13ef8d8
--- /dev/null
+++ b/tests/check/elements/matroskaparse.c
@@ -0,0 +1,130 @@
+/* GStreamer unit tests for matroskaparse
+ * Copyright (C) 2011 Tim-Philipp Müller  <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+
+#include <gst/gst.h>
+
+static void
+run_check_for_file (const gchar * file_name, gboolean push_mode)
+{
+  GstStateChangeReturn state_ret;
+  GstMessage *msg;
+  GstElement *src, *sep, *sink, *matroskaparse, *pipeline;
+  GstBus *bus;
+  gchar *path;
+
+  pipeline = gst_pipeline_new ("pipeline");
+  fail_unless (pipeline != NULL, "Failed to create pipeline!");
+
+  bus = gst_element_get_bus (pipeline);
+
+  src = gst_element_factory_make ("filesrc", "filesrc");
+  fail_unless (src != NULL, "Failed to create 'filesrc' element!");
+
+  if (push_mode) {
+    sep = gst_element_factory_make ("queue", "queue");
+    fail_unless (sep != NULL, "Failed to create 'queue' element");
+  } else {
+    sep = gst_element_factory_make ("identity", "identity");
+    fail_unless (sep != NULL, "Failed to create 'identity' element");
+  }
+
+  matroskaparse = gst_element_factory_make ("matroskaparse", "matroskaparse");
+  fail_unless (matroskaparse != NULL, "Failed to create matroskaparse element");
+
+  sink = gst_element_factory_make ("fakesink", "fakesink");
+  fail_unless (sink != NULL, "Failed to create 'fakesink' element!");
+
+  gst_bin_add_many (GST_BIN (pipeline), src, sep, matroskaparse, sink, NULL);
+
+  fail_unless (gst_element_link (src, sep));
+  fail_unless (gst_element_link (sep, matroskaparse));
+  fail_unless (gst_element_link (matroskaparse, sink));
+
+  path = g_build_filename (GST_TEST_FILES_PATH, file_name, NULL);
+  GST_LOG ("reading file '%s'", path);
+  g_object_set (src, "location", path, NULL);
+
+  state_ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
+  fail_unless (state_ret != GST_STATE_CHANGE_FAILURE);
+
+  if (state_ret == GST_STATE_CHANGE_ASYNC) {
+    GST_LOG ("waiting for pipeline to reach PAUSED state");
+    state_ret = gst_element_get_state (pipeline, NULL, NULL, -1);
+    fail_unless_equals_int (state_ret, GST_STATE_CHANGE_SUCCESS);
+  }
+
+  GST_LOG ("PAUSED, let's play a little..");
+  state_ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  fail_unless (state_ret != GST_STATE_CHANGE_FAILURE);
+
+  msg = gst_bus_poll (bus, GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
+    GError *err;
+    gchar *dbg;
+
+    gst_message_parse_error (msg, &err, &dbg);
+    gst_object_default_error (GST_MESSAGE_SRC (msg), err, dbg);
+    g_error ("%s (%s)", err->message, dbg);
+    g_error_free (err);
+    g_free (dbg);
+  }
+  gst_message_unref (msg);
+  gst_object_unref (bus);
+
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
+      GST_STATE_CHANGE_SUCCESS);
+  gst_object_unref (pipeline);
+
+  g_free (path);
+}
+
+#if 0
+GST_START_TEST (test_parse_file_pull)
+{
+  run_check_for_file ("pinknoise-vorbis.mkv", TRUE);
+}
+
+GST_END_TEST;
+#endif
+
+GST_START_TEST (test_parse_file_push)
+{
+  run_check_for_file ("pinknoise-vorbis.mkv", FALSE);
+}
+
+GST_END_TEST;
+
+static Suite *
+matroskaparse_suite (void)
+{
+  Suite *s = suite_create ("matroskaparse");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+#if 0
+  tcase_add_test (tc_chain, test_parse_file_pull);
+#endif
+  tcase_add_test (tc_chain, test_parse_file_push);
+
+  return s;
+}
+
+GST_CHECK_MAIN (matroskaparse)
diff --git a/tests/check/elements/mpegaudioparse.c b/tests/check/elements/mpegaudioparse.c
new file mode 100644
index 0000000..c144e95
--- /dev/null
+++ b/tests/check/elements/mpegaudioparse.c
@@ -0,0 +1,155 @@
+/*
+ * GStreamer
+ *
+ * unit test for aacparse
+ *
+ * Copyright (C) 2008 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include "parser.h"
+
+#define SRC_CAPS_TMPL   "audio/mpeg, parsed=(boolean)false, mpegversion=(int)1"
+#define SINK_CAPS_TMPL  "audio/mpeg, parsed=(boolean)true, mpegversion=(int)1"
+
+GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SINK_CAPS_TMPL)
+    );
+
+GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SRC_CAPS_TMPL)
+    );
+
+/* some data */
+static guint8 mp3_frame[384] = {
+  0xff, 0xfb, 0x94, 0xc4, 0xff, 0x83, 0xc0, 0x00,
+  0x01, 0xa4, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+  0x34, 0x80, 0x00, 0x00, 0x04, 0x00,
+};
+
+static guint8 garbage_frame[] = {
+  0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+
+GST_START_TEST (test_parse_normal)
+{
+  gst_parser_test_normal (mp3_frame, sizeof (mp3_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_drain_single)
+{
+  gst_parser_test_drain_single (mp3_frame, sizeof (mp3_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_drain_garbage)
+{
+  gst_parser_test_drain_garbage (mp3_frame, sizeof (mp3_frame),
+      garbage_frame, sizeof (garbage_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_split)
+{
+  gst_parser_test_split (mp3_frame, sizeof (mp3_frame));
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_parse_skip_garbage)
+{
+  gst_parser_test_skip_garbage (mp3_frame, sizeof (mp3_frame),
+      garbage_frame, sizeof (garbage_frame));
+}
+
+GST_END_TEST;
+
+
+#define structure_get_int(s,f) \
+    (g_value_get_int(gst_structure_get_value(s,f)))
+#define fail_unless_structure_field_int_equals(s,field,num) \
+    fail_unless_equals_int (structure_get_int(s,field), num)
+
+GST_START_TEST (test_parse_detect_stream)
+{
+  GstStructure *s;
+  GstCaps *caps;
+
+  caps = gst_parser_test_get_output_caps (mp3_frame, sizeof (mp3_frame), NULL);
+
+  fail_unless (caps != NULL);
+
+  GST_LOG ("mpegaudio output caps: %" GST_PTR_FORMAT, caps);
+  s = gst_caps_get_structure (caps, 0);
+  fail_unless (gst_structure_has_name (s, "audio/mpeg"));
+  fail_unless_structure_field_int_equals (s, "mpegversion", 1);
+  fail_unless_structure_field_int_equals (s, "layer", 3);
+  fail_unless_structure_field_int_equals (s, "channels", 1);
+  fail_unless_structure_field_int_equals (s, "rate", 48000);
+
+  gst_caps_unref (caps);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+mpegaudioparse_suite (void)
+{
+  Suite *s = suite_create ("mpegaudioparse");
+  TCase *tc_chain = tcase_create ("general");
+
+
+  /* init test context */
+  ctx_factory = "mpegaudioparse";
+  ctx_sink_template = &sinktemplate;
+  ctx_src_template = &srctemplate;
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_parse_normal);
+  tcase_add_test (tc_chain, test_parse_drain_single);
+  tcase_add_test (tc_chain, test_parse_drain_garbage);
+  tcase_add_test (tc_chain, test_parse_split);
+  tcase_add_test (tc_chain, test_parse_skip_garbage);
+  tcase_add_test (tc_chain, test_parse_detect_stream);
+
+  return s;
+}
+
+
+/*
+ * TODO:
+ *   - Both push- and pull-modes need to be tested
+ *      * Pull-mode & EOS
+ */
+GST_CHECK_MAIN (mpegaudioparse);
diff --git a/tests/check/elements/mpg123audiodec.c b/tests/check/elements/mpg123audiodec.c
new file mode 100644
index 0000000..20d6e77
--- /dev/null
+++ b/tests/check/elements/mpg123audiodec.c
@@ -0,0 +1,534 @@
+/* GStreamer
+ *
+ * unit test for mpg123audiodec
+ *
+ * Copyright (c) 2012 Carlos Rafael Giani <dv@pseudoterminal.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+#include <gst/audio/audio.h>
+
+#include <gst/fft/gstfft.h>
+#include <gst/fft/gstffts16.h>
+#include <gst/fft/gstffts32.h>
+#include <gst/fft/gstfftf32.h>
+#include <gst/fft/gstfftf64.h>
+
+#include <gst/app/gstappsink.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+static GstPad *mysrcpad, *mysinkpad;
+
+
+#define MP2_STREAM_FILENAME "stream.mp2"
+#define MP3_CBR_STREAM_FILENAME "cbr_stream.mp3"
+#define MP3_VBR_STREAM_FILENAME "vbr_stream.mp3"
+
+
+/* mpeg 1 layer 2 stream created with:
+ * gst-launch-1.0 -v audiotestsrc wave=sine freq=440 volume=1 num-buffers=32 ! \
+ *   "audio/x-raw, format=(string)S16LE, layout=(string)interleaved, rate=(int)44100, channels=(int)1" ! \
+ *   avenc_mp2 bitrate=32000 ! tee name=t \
+ *   t. ! queue ! fakesink silent=false \
+ *   t. ! queue ! filesink location=test.mp2
+ *
+ * mpeg 1 layer 3 CBR stream created with:
+ * gst-launch-1.0 -v audiotestsrc wave=sine freq=440 volume=1 num-buffers=32 ! \
+ *   "audio/x-raw, format=(string)S16LE, layout=(string)interleaved, rate=(int)44100, channels=(int)1" ! \
+ *   lamemp3enc encoding-engine-quality=high cbr=true target=bitrate bitrate=32 ! \
+ *   "audio/mpeg, rate=(int)44100, channels=(int)1" ! tee name=t \
+ *   t. ! queue ! fakesink silent=false \
+ *   t. ! queue ! filesink location=test.mp3
+ *
+ * mpeg 1 layer 3 VBR stream created with:
+ * gst-launch-1.0 -v audiotestsrc wave=sine freq=440 volume=1 num-buffers=32 ! \
+ *   "audio/x-raw, format=(string)S16LE, layout=(string)interleaved, rate=(int)44100, channels=(int)1" ! \
+ *   lamemp3enc encoding-engine-quality=high cbr=false target=quality quality=7 ! \
+ *   "audio/mpeg, rate=(int)44100, channels=(int)1" ! tee name=t \
+ *   t. ! queue ! fakesink silent=false \
+ *   t. ! queue ! filesink location=test.mp3
+ */
+
+
+/* FFT test helpers taken from gst-plugins-base tests/check/audioresample.c */
+
+#define FFT_HELPERS(type,ffttag,ffttag2,scale)                                \
+static gdouble magnitude##ffttag (const GstFFT##ffttag##Complex *c)           \
+{                                                                             \
+  gdouble mag = (gdouble) c->r * (gdouble) c->r;                              \
+  mag += (gdouble) c->i * (gdouble) c->i;                                     \
+  mag /= scale * scale;                                                       \
+  mag = 10.0 * log10 (mag);                                                   \
+  return mag;                                                                 \
+}                                                                             \
+static gdouble find_main_frequency_spot_##ffttag (                            \
+    const GstFFT##ffttag##Complex *v, int elements)                           \
+{                                                                             \
+  int i;                                                                      \
+  gdouble maxmag = -9999;                                                     \
+  int maxidx = 0;                                                             \
+  for (i=0; i<elements; ++i) {                                                \
+    gdouble mag = magnitude##ffttag (v+i);                                    \
+    if (mag > maxmag) {                                                       \
+      maxmag = mag;                                                           \
+      maxidx = i;                                                             \
+    }                                                                         \
+  }                                                                           \
+  return maxidx / (gdouble) elements;                                         \
+}                                                                             \
+static gboolean is_zero_except_##ffttag (const GstFFT##ffttag##Complex *v,    \
+    int elements, gdouble spot)                                               \
+{                                                                             \
+  int i;                                                                      \
+  for (i=0; i<elements; ++i) {                                                \
+    gdouble pos = i / (gdouble) elements;                                     \
+    gdouble mag = magnitude##ffttag (v+i);                                    \
+    if (fabs (pos - spot) > 0.01) {                                           \
+      if (mag > -35.0) {                                                      \
+        GST_LOG("Found magnitude at %f : %f (peak at %f)\n", pos, mag, spot); \
+        return FALSE;                                                         \
+      }                                                                       \
+    }                                                                         \
+  }                                                                           \
+  return TRUE;                                                                \
+}                                                                             \
+static void check_main_frequency_spot_##ffttag (GstBuffer *buffer, gdouble    \
+    expected_spot)                                                            \
+{                                                                             \
+  GstMapInfo map;                                                             \
+  int num_samples;                                                            \
+  gdouble actual_spot;                                                        \
+  GstFFT##ffttag *ctx;                                                        \
+  GstFFT##ffttag##Complex *fftdata;                                           \
+                                                                              \
+  gst_buffer_map (buffer, &map, GST_MAP_READ);                                \
+                                                                              \
+  num_samples = map.size / sizeof(type) & ~1;                                 \
+  ctx = gst_fft_##ffttag2##_new (num_samples, FALSE);                         \
+  fftdata = g_new (GstFFT##ffttag##Complex, num_samples / 2 + 1);             \
+                                                                              \
+  gst_fft_##ffttag2##_window (ctx, (type*)map.data,                           \
+    GST_FFT_WINDOW_HAMMING);                                                  \
+  gst_fft_##ffttag2##_fft (ctx, (type*)map.data, fftdata);                    \
+                                                                              \
+  actual_spot = find_main_frequency_spot_##ffttag (fftdata,                   \
+    num_samples / 2 + 1);                                                     \
+  GST_LOG ("Expected spot: %.3f actual: %.3f %f", expected_spot, actual_spot, \
+    fabs (expected_spot - actual_spot));                                      \
+  fail_unless (fabs (expected_spot - actual_spot) < 0.05,                     \
+    "Actual main frequency spot is too far away from expected one");          \
+  fail_unless (is_zero_except_##ffttag (fftdata, num_samples / 2 + 1,         \
+    actual_spot), "One secondary peak in spectrum exceeds threshold");        \
+                                                                              \
+  gst_buffer_unmap (buffer, &map);                                            \
+                                                                              \
+  gst_fft_##ffttag2##_free (ctx);                                             \
+  g_free (fftdata);                                                           \
+}
+FFT_HELPERS (gint32, S32, s32, 2147483647.0);
+
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, format = (string) " GST_AUDIO_NE (S32))
+    );
+static GstStaticPadTemplate layer2_srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+static GstStaticPadTemplate layer3_srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+
+static void
+setup_input_pipeline (gchar const *stream_filename, GstElement ** pipeline,
+    GstElement ** appsink)
+{
+  GstElement *source, *parser;
+
+  *pipeline = gst_pipeline_new (NULL);
+  source = gst_element_factory_make ("filesrc", NULL);
+  parser = gst_element_factory_make ("mpegaudioparse", NULL);
+  *appsink = gst_element_factory_make ("appsink", NULL);
+
+  gst_bin_add_many (GST_BIN (*pipeline), source, parser, *appsink, NULL);
+  gst_element_link_many (source, parser, *appsink, NULL);
+
+  {
+    char *full_filename =
+        g_build_filename (GST_TEST_FILES_PATH, stream_filename, NULL);
+    g_object_set (G_OBJECT (source), "location", full_filename, NULL);
+    g_free (full_filename);
+  }
+
+  gst_element_set_state (*pipeline, GST_STATE_PLAYING);
+}
+
+static void
+cleanup_input_pipeline (GstElement * pipeline)
+{
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+}
+
+static GstElement *
+setup_mpeg1layer2dec (void)
+{
+  GstElement *mpg123audiodec;
+  GstCaps *caps;
+
+  GST_DEBUG ("setup_mpeg1layer2dec");
+  mpg123audiodec = gst_check_setup_element ("mpg123audiodec");
+  mysrcpad = gst_check_setup_src_pad (mpg123audiodec, &layer2_srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (mpg123audiodec, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  /* This is necessary to trigger a set_format call in the decoder;
+   * fixed caps don't trigger it */
+  caps = gst_caps_new_simple ("audio/mpeg",
+      "mpegversion", G_TYPE_INT, 1,
+      "layer", G_TYPE_INT, 2,
+      "rate", G_TYPE_INT, 44100,
+      "channels", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
+  gst_check_setup_events (mysrcpad, mpg123audiodec, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  return mpg123audiodec;
+}
+
+static GstElement *
+setup_mpeg1layer3dec (void)
+{
+  GstElement *mpg123audiodec;
+  GstCaps *caps;
+
+  GST_DEBUG ("setup_mpeg1layer3dec");
+  mpg123audiodec = gst_check_setup_element ("mpg123audiodec");
+  mysrcpad = gst_check_setup_src_pad (mpg123audiodec, &layer3_srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (mpg123audiodec, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  /* This is necessary to trigger a set_format call in the decoder;
+   * fixed caps don't trigger it */
+  caps = gst_caps_new_simple ("audio/mpeg",
+      "mpegversion", G_TYPE_INT, 1,
+      "layer", G_TYPE_INT, 3,
+      "rate", G_TYPE_INT, 44100,
+      "channels", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
+  gst_check_setup_events (mysrcpad, mpg123audiodec, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  return mpg123audiodec;
+}
+
+static void
+cleanup_mpg123audiodec (GstElement * mpg123audiodec)
+{
+  GST_DEBUG ("cleanup_mpeg1layer2dec");
+  gst_element_set_state (mpg123audiodec, GST_STATE_NULL);
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (mpg123audiodec);
+  gst_check_teardown_sink_pad (mpg123audiodec);
+  gst_check_teardown_element (mpg123audiodec);
+}
+
+static void
+run_decoding_test (GstElement * mpg123audiodec, gchar const *filename)
+{
+  GstBus *bus;
+  unsigned int num_input_buffers, num_decoded_buffers;
+  gint expected_size;
+  GstCaps *out_caps, *caps;
+  GstAudioInfo audioinfo;
+  GstElement *input_pipeline, *input_appsink;
+  int i;
+  GstBuffer *outbuffer;
+
+  /* 440 Hz = frequency of sine wave in audio data
+   * 44100 Hz = sample rate
+   * (44100 / 2) Hz = Nyquist frequency */
+  static double const expected_frequency_spot = 440.0 / (44100.0 / 2.0);
+
+  fail_unless (gst_element_set_state (mpg123audiodec,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+  bus = gst_bus_new ();
+
+  gst_element_set_bus (mpg123audiodec, bus);
+
+  setup_input_pipeline (filename, &input_pipeline, &input_appsink);
+
+  num_input_buffers = 0;
+  while (TRUE) {
+    GstSample *sample;
+    GstBuffer *input_buffer;
+
+    sample = gst_app_sink_pull_sample (GST_APP_SINK (input_appsink));
+    if (sample == NULL)
+      break;
+
+    fail_unless (GST_IS_SAMPLE (sample));
+
+    input_buffer = gst_sample_get_buffer (sample);
+    fail_if (input_buffer == NULL);
+
+    /* This is done to be on the safe side - docs say lifetime of the input buffer
+     * depends *solely* on the sample */
+    input_buffer = gst_buffer_copy (input_buffer);
+
+    fail_unless_equals_int (gst_pad_push (mysrcpad, input_buffer), GST_FLOW_OK);
+
+    ++num_input_buffers;
+
+    gst_sample_unref (sample);
+  }
+
+  num_decoded_buffers = g_list_length (buffers);
+
+  /* check number of decoded buffers */
+  fail_unless_equals_int (num_decoded_buffers, num_input_buffers - 2);
+
+  caps = gst_pad_get_current_caps (mysinkpad);
+  GST_LOG ("output caps %" GST_PTR_FORMAT, caps);
+  fail_unless (gst_audio_info_from_caps (&audioinfo, caps),
+      "Getting audio info from caps failed");
+
+  /* check caps */
+  out_caps = gst_caps_new_simple ("audio/x-raw",
+      "format", G_TYPE_STRING, GST_AUDIO_NE (S32),
+      "layout", G_TYPE_STRING, "interleaved",
+      "rate", G_TYPE_INT, 44100, "channels", G_TYPE_INT, 1, NULL);
+
+  fail_unless (gst_caps_is_equal_fixed (caps, out_caps), "Incorrect out caps");
+
+  gst_caps_unref (out_caps);
+  gst_caps_unref (caps);
+
+  /* here, test if decoded data is a sine tone, and if the sine frequency is at the
+   * right spot in the spectrum */
+  for (i = 0; i < num_decoded_buffers; ++i) {
+    outbuffer = GST_BUFFER (buffers->data);
+    fail_if (outbuffer == NULL, "Invalid buffer retrieved");
+
+    /* MPEG 1 layer 2 uses 1152 samples per frame */
+    expected_size = 1152 * GST_AUDIO_INFO_BPF (&audioinfo);
+    fail_unless_equals_int (gst_buffer_get_size (outbuffer), expected_size);
+
+    check_main_frequency_spot_S32 (outbuffer, expected_frequency_spot);
+
+    buffers = g_list_remove (buffers, outbuffer);
+    gst_buffer_unref (outbuffer);
+    outbuffer = NULL;
+  }
+
+  g_list_free (buffers);
+  buffers = NULL;
+
+  cleanup_input_pipeline (input_pipeline);
+  gst_bus_set_flushing (bus, TRUE);
+  gst_element_set_bus (mpg123audiodec, NULL);
+  gst_object_unref (GST_OBJECT (bus));
+}
+
+
+GST_START_TEST (test_decode_mpeg1layer2)
+{
+  GstElement *mpg123audiodec;
+  mpg123audiodec = setup_mpeg1layer2dec ();
+  run_decoding_test (mpg123audiodec, MP2_STREAM_FILENAME);
+  cleanup_mpg123audiodec (mpg123audiodec);
+  mpg123audiodec = NULL;
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_decode_mpeg1layer3_cbr)
+{
+  GstElement *mpg123audiodec;
+  mpg123audiodec = setup_mpeg1layer3dec ();
+  run_decoding_test (mpg123audiodec, MP3_CBR_STREAM_FILENAME);
+  cleanup_mpg123audiodec (mpg123audiodec);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_decode_mpeg1layer3_vbr)
+{
+  GstElement *mpg123audiodec;
+  mpg123audiodec = setup_mpeg1layer3dec ();
+  run_decoding_test (mpg123audiodec, MP3_VBR_STREAM_FILENAME);
+  cleanup_mpg123audiodec (mpg123audiodec);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_decode_garbage_mpeg1layer2)
+{
+  GstElement *mpg123audiodec;
+  GstBuffer *inbuffer;
+  GstBus *bus;
+  int i, num_buffers;
+  guint32 *tmpbuf;
+
+  mpg123audiodec = setup_mpeg1layer2dec ();
+
+  fail_unless (gst_element_set_state (mpg123audiodec,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+  bus = gst_bus_new ();
+
+  /* initialize the buffer with something that is no mpeg2 */
+  tmpbuf = g_new (guint32, 4096);
+  for (i = 0; i < 4096; i++) {
+    tmpbuf[i] = i;
+  }
+  inbuffer = gst_buffer_new_wrapped (tmpbuf, 4096 * sizeof (guint32));
+
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  gst_element_set_bus (mpg123audiodec, bus);
+
+  /* should be possible to push without problems but nothing gets decoded */
+  fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
+
+  num_buffers = g_list_length (buffers);
+
+  /* should be 0 buffers as decoding should've been impossible */
+  fail_unless_equals_int (num_buffers, 0);
+
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_bus_set_flushing (bus, TRUE);
+  gst_element_set_bus (mpg123audiodec, NULL);
+  gst_object_unref (GST_OBJECT (bus));
+  cleanup_mpg123audiodec (mpg123audiodec);
+  mpg123audiodec = NULL;
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_decode_garbage_mpeg1layer3)
+{
+  GstElement *mpg123audiodec;
+  GstBuffer *inbuffer;
+  GstBus *bus;
+  int i, num_buffers;
+  guint32 *tmpbuf;
+
+  mpg123audiodec = setup_mpeg1layer3dec ();
+
+  fail_unless (gst_element_set_state (mpg123audiodec,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+  bus = gst_bus_new ();
+
+  /* initialize the buffer with something that is no mpeg2 */
+  tmpbuf = g_new (guint32, 4096);
+  for (i = 0; i < 4096; i++) {
+    tmpbuf[i] = i;
+  }
+  inbuffer = gst_buffer_new_wrapped (tmpbuf, 4096 * sizeof (guint32));
+
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  gst_element_set_bus (mpg123audiodec, bus);
+
+  /* should be possible to push without problems but nothing gets decoded */
+  fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
+
+  num_buffers = g_list_length (buffers);
+
+  /* should be 0 buffers as decoding should've been impossible */
+  fail_unless_equals_int (num_buffers, 0);
+
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_bus_set_flushing (bus, TRUE);
+  gst_element_set_bus (mpg123audiodec, NULL);
+  gst_object_unref (GST_OBJECT (bus));
+  cleanup_mpg123audiodec (mpg123audiodec);
+  mpg123audiodec = NULL;
+}
+
+GST_END_TEST;
+
+
+static gboolean
+is_test_file_available (gchar const *filename)
+{
+  gboolean ret;
+  gchar *full_filename;
+  gchar *cwd;
+
+  cwd = g_get_current_dir ();
+  full_filename = g_build_filename (cwd, GST_TEST_FILES_PATH, filename, NULL);
+  ret =
+      g_file_test (full_filename, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS);
+  g_free (full_filename);
+  g_free (cwd);
+  return ret;
+}
+
+static Suite *
+mpg123audiodec_suite (void)
+{
+  GstRegistry *registry;
+  Suite *s = suite_create ("mpg123audiodec");
+  TCase *tc_chain = tcase_create ("general");
+
+  registry = gst_registry_get ();
+
+  suite_add_tcase (s, tc_chain);
+  if (gst_registry_check_feature_version (registry, "filesrc",
+          GST_VERSION_MAJOR, GST_VERSION_MINOR, 0) &&
+      gst_registry_check_feature_version (registry, "mpegaudioparse",
+          GST_VERSION_MAJOR, GST_VERSION_MINOR, 0) &&
+      gst_registry_check_feature_version (registry, "appsrc",
+          GST_VERSION_MAJOR, GST_VERSION_MINOR, 0)) {
+    if (is_test_file_available (MP2_STREAM_FILENAME))
+      tcase_add_test (tc_chain, test_decode_mpeg1layer2);
+    if (is_test_file_available (MP3_CBR_STREAM_FILENAME))
+      tcase_add_test (tc_chain, test_decode_mpeg1layer3_cbr);
+    if (is_test_file_available (MP3_VBR_STREAM_FILENAME))
+      tcase_add_test (tc_chain, test_decode_mpeg1layer3_vbr);
+  }
+  tcase_add_test (tc_chain, test_decode_garbage_mpeg1layer2);
+  tcase_add_test (tc_chain, test_decode_garbage_mpeg1layer3);
+
+  return s;
+}
+
+
+GST_CHECK_MAIN (mpg123audiodec)
diff --git a/tests/check/elements/mulawdec.c b/tests/check/elements/mulawdec.c
new file mode 100644
index 0000000..cb6f036
--- /dev/null
+++ b/tests/check/elements/mulawdec.c
@@ -0,0 +1,126 @@
+/* GStreamer MulawDec unit tests
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/check/gstcheck.h>
+#include <gst/audio/audio.h>
+#include <string.h>
+
+static GstPad *mysrcpad, *mysinkpad;
+static GstElement *mulawdec = NULL;
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw,"
+        "format = (string) " GST_AUDIO_NE (S16) ", "
+        "rate = (int) 8000, "
+        "channels = (int) 1, " "layout = (string)interleaved")
+    );
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-mulaw," "rate = (int) 8000," "channels = (int) 1")
+    );
+
+static void
+mulawdec_setup (void)
+{
+  GstCaps *src_caps;
+
+  src_caps =
+      gst_caps_from_string ("audio/x-mulaw," "rate = (int) 8000,"
+      "channels = (int) 1");
+
+  GST_DEBUG ("%s", __FUNCTION__);
+
+  mulawdec = gst_check_setup_element ("mulawdec");
+
+  mysrcpad = gst_check_setup_src_pad (mulawdec, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (mulawdec, &sinktemplate);
+
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  gst_check_setup_events (mysrcpad, mulawdec, src_caps, GST_FORMAT_TIME);
+
+  gst_caps_unref (src_caps);
+}
+
+static void
+buffer_unref (void *buffer, void *user_data)
+{
+  gst_buffer_unref (GST_BUFFER (buffer));
+}
+
+static void
+mulawdec_teardown (void)
+{
+  /* free decoded buffers */
+  g_list_foreach (buffers, buffer_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (mulawdec);
+  gst_check_teardown_sink_pad (mulawdec);
+  gst_check_teardown_element (mulawdec);
+  mulawdec = NULL;
+}
+
+GST_START_TEST (test_one_buffer)
+{
+  GstBuffer *buffer;
+  gint buf_size = 4096;
+  guint8 *dp;
+
+  fail_unless (gst_element_set_state (mulawdec, GST_STATE_PLAYING) ==
+      GST_STATE_CHANGE_SUCCESS, "could not change state to playing");
+
+  buffer = gst_buffer_new ();
+  dp = g_malloc0 (buf_size);
+  gst_buffer_append_memory (buffer,
+      gst_memory_new_wrapped (0, dp, buf_size, 0, buf_size, dp, g_free));
+  ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1);
+
+  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+
+  fail_unless (g_list_length (buffers) == 1);
+  fail_unless (gst_buffer_get_size (GST_BUFFER (g_list_first (buffers)->data)));
+}
+
+GST_END_TEST;
+
+static Suite *
+mulawdec_suite (void)
+{
+  Suite *s = suite_create ("mulawdec");
+  TCase *tc_chain = tcase_create ("mulawdec");
+
+  tcase_add_checked_fixture (tc_chain, mulawdec_setup, mulawdec_teardown);
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_one_buffer);
+  return s;
+}
+
+GST_CHECK_MAIN (mulawdec)
diff --git a/tests/check/elements/mulawenc.c b/tests/check/elements/mulawenc.c
new file mode 100644
index 0000000..757f3ee
--- /dev/null
+++ b/tests/check/elements/mulawenc.c
@@ -0,0 +1,176 @@
+/* GStreamer MulawEnc unit tests
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/check/gstcheck.h>
+#include <gst/audio/audio.h>
+#include <string.h>
+
+static GstPad *mysrcpad, *mysinkpad;
+static GstElement *mulawenc = NULL;
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-mulaw," "rate = (int) 8000," "channels = (int) 1")
+    );
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw,"
+        "format = (string) " GST_AUDIO_NE (S16) ", "
+        "rate = (int) 8000, "
+        "channels = (int) 1, " "layout = (string)interleaved")
+    );
+
+static void
+mulawenc_setup (void)
+{
+  GstCaps *src_caps;
+
+  src_caps = gst_caps_from_string ("audio/x-raw,"
+      "format = (string) " GST_AUDIO_NE (S16) ", "
+      "rate = (int) 8000, "
+      "channels = (int) 1, " "layout = (string)interleaved");
+
+  GST_DEBUG ("%s", __FUNCTION__);
+
+  mulawenc = gst_check_setup_element ("mulawenc");
+
+  mysrcpad = gst_check_setup_src_pad (mulawenc, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (mulawenc, &sinktemplate);
+
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  gst_check_setup_events (mysrcpad, mulawenc, src_caps, GST_FORMAT_TIME);
+  gst_caps_unref (src_caps);
+}
+
+static void
+buffer_unref (void *buffer, void *user_data)
+{
+  gst_buffer_unref (GST_BUFFER (buffer));
+}
+
+static void
+mulawenc_teardown (void)
+{
+  /* free encoded buffers */
+  g_list_foreach (buffers, buffer_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (mulawenc);
+  gst_check_teardown_sink_pad (mulawenc);
+  gst_check_teardown_element (mulawenc);
+  mulawenc = NULL;
+}
+
+static gboolean
+check_for_maximum_bitrate (GstPad * pad, GstEvent ** eventp, gpointer user_data)
+{
+  gboolean *found_maximum_bitrate = (gboolean *) user_data;
+  GstEvent *event = *eventp;
+
+  if (event->type == GST_EVENT_TAG) {
+    GstTagList *taglist = NULL;
+    guint value = 0;
+    gst_event_parse_tag (event, &taglist);
+
+    fail_unless (taglist != NULL);
+
+    fail_unless (gst_tag_list_get_uint (taglist, GST_TAG_MAXIMUM_BITRATE,
+            &value));
+
+    /* bitrate needs to be exactly sample rate * channels * 8 */
+    fail_unless (value == 8000 * 1 * 8);
+
+    *found_maximum_bitrate = TRUE;
+  }
+
+  return TRUE;
+}
+
+GST_START_TEST (test_one_buffer)
+{
+  GstBuffer *buffer;
+  gint buf_size = 4096;
+  guint8 *dp;
+
+  fail_unless (gst_element_set_state (mulawenc, GST_STATE_PLAYING) ==
+      GST_STATE_CHANGE_SUCCESS, "could not change state to playing");
+
+  buffer = gst_buffer_new ();
+  dp = g_malloc0 (buf_size);
+  gst_buffer_append_memory (buffer,
+      gst_memory_new_wrapped (0, dp, buf_size, 0, buf_size, dp, g_free));
+  ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1);
+
+  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+
+  fail_unless (g_list_length (buffers) == 1);
+  fail_unless (gst_buffer_get_size (GST_BUFFER (g_list_first (buffers)->data)));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_tags)
+{
+  GstBuffer *buffer;
+  gint buf_size = 4096;
+  guint8 *dp;
+  gboolean found_maximum_bitrate = FALSE;
+
+  fail_unless (gst_element_set_state (mulawenc, GST_STATE_PLAYING) ==
+      GST_STATE_CHANGE_SUCCESS, "could not change state to playing");
+
+  buffer = gst_buffer_new ();
+  dp = g_malloc0 (buf_size);
+  gst_buffer_append_memory (buffer,
+      gst_memory_new_wrapped (0, dp, buf_size, 0, buf_size, dp, g_free));
+  ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1);
+
+  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+  gst_pad_sticky_events_foreach (mysinkpad, check_for_maximum_bitrate,
+      &found_maximum_bitrate);
+  fail_unless (found_maximum_bitrate);
+}
+
+GST_END_TEST;
+
+static Suite *
+mulawenc_suite (void)
+{
+  Suite *s = suite_create ("mulawenc");
+  TCase *tc_chain = tcase_create ("mulawenc");
+
+  tcase_add_checked_fixture (tc_chain, mulawenc_setup, mulawenc_teardown);
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_one_buffer);
+  tcase_add_test (tc_chain, test_tags);
+  return s;
+}
+
+GST_CHECK_MAIN (mulawenc)
diff --git a/tests/check/elements/multifile.c b/tests/check/elements/multifile.c
new file mode 100644
index 0000000..e7abffe
--- /dev/null
+++ b/tests/check/elements/multifile.c
@@ -0,0 +1,399 @@
+/* GStreamer unit test for multifile plugin
+ *
+ * Copyright (C) 2007 David A. Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <glib/gstdio.h>
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+#include <gst/video/video.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static GList *mfs_messages = NULL;
+
+static void
+mfs_check_next_message (const gchar * filename)
+{
+  GstMessage *msg;
+  const gchar *msg_filename;
+  const GstStructure *structure;
+
+  fail_unless (mfs_messages != NULL);
+
+  msg = mfs_messages->data;
+  mfs_messages = g_list_delete_link (mfs_messages, mfs_messages);
+
+  structure = gst_message_get_structure (msg);
+
+  msg_filename = gst_structure_get_string (structure, "filename");
+
+  fail_unless (strcmp (filename, msg_filename) == 0);
+
+  gst_message_unref (msg);
+}
+
+static void
+run_pipeline (GstElement * pipeline)
+{
+  GstMessage *msg;
+  GstBus *bus;
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+
+  gst_element_set_state (pipeline, GST_STATE_PAUSED);
+  gst_element_get_state (pipeline, NULL, NULL, -1);
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  while (1) {
+    msg =
+        gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
+        GST_MESSAGE_EOS | GST_MESSAGE_ERROR | GST_MESSAGE_ELEMENT);
+
+    fail_unless (msg != NULL);
+    if (msg) {
+      if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
+        if (gst_message_has_name (msg, "GstMultiFileSink"))
+          mfs_messages = g_list_append (mfs_messages, msg);
+        else
+          gst_message_unref (msg);
+
+        continue;
+      }
+
+      fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
+      gst_message_unref (msg);
+    }
+    break;
+  }
+
+  gst_object_unref (bus);
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+}
+
+GST_START_TEST (test_multifilesink_key_frame)
+{
+  GstElement *pipeline;
+  GstElement *mfs;
+  int i;
+  const gchar *tmpdir;
+  gchar *my_tmpdir;
+  gchar *template;
+  gchar *mfs_pattern;
+
+  tmpdir = g_get_tmp_dir ();
+  template = g_build_filename (tmpdir, "multifile-test-XXXXXX", NULL);
+  my_tmpdir = g_mkdtemp (template);
+  fail_if (my_tmpdir == NULL);
+
+  pipeline =
+      gst_parse_launch
+      ("videotestsrc num-buffers=10 ! video/x-raw,format=(string)I420,width=320,height=240 ! multifilesink name=mfs",
+      NULL);
+  fail_if (pipeline == NULL);
+  mfs = gst_bin_get_by_name (GST_BIN (pipeline), "mfs");
+  fail_if (mfs == NULL);
+  mfs_pattern = g_build_filename (my_tmpdir, "%05d", NULL);
+  g_object_set (G_OBJECT (mfs), "location", mfs_pattern, "post-messages", TRUE,
+      NULL);
+  g_object_unref (mfs);
+  run_pipeline (pipeline);
+  gst_object_unref (pipeline);
+
+  for (i = 0; i < 10; i++) {
+    char *s;
+
+    s = g_strdup_printf (mfs_pattern, i);
+    fail_if (g_remove (s) != 0);
+
+    mfs_check_next_message (s);
+
+    g_free (s);
+  }
+  fail_if (g_remove (my_tmpdir) != 0);
+
+  fail_unless (mfs_messages == NULL);
+  g_free (mfs_pattern);
+  g_free (my_tmpdir);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_multifilesink_max_files)
+{
+  GstElement *pipeline;
+  GstElement *mfs;
+  int i;
+  const gchar *tmpdir;
+  gchar *my_tmpdir;
+  gchar *template;
+  gchar *mfs_pattern;
+
+  tmpdir = g_get_tmp_dir ();
+  template = g_build_filename (tmpdir, "multifile-test-XXXXXX", NULL);
+  my_tmpdir = g_mkdtemp (template);
+  fail_if (my_tmpdir == NULL);
+
+  pipeline =
+      gst_parse_launch
+      ("videotestsrc num-buffers=10 ! video/x-raw,format=(string)I420,width=320,height=240 ! multifilesink name=mfs",
+      NULL);
+  fail_if (pipeline == NULL);
+  mfs = gst_bin_get_by_name (GST_BIN (pipeline), "mfs");
+  fail_if (mfs == NULL);
+  mfs_pattern = g_build_filename (my_tmpdir, "%05d", NULL);
+  g_object_set (G_OBJECT (mfs), "location", mfs_pattern, "max-files", 3, NULL);
+  g_object_unref (mfs);
+  run_pipeline (pipeline);
+  gst_object_unref (pipeline);
+
+  for (i = 0; i < 7; i++) {
+    char *s;
+
+    s = g_strdup_printf (mfs_pattern, i);
+    fail_unless (g_remove (s) != 0);
+    g_free (s);
+  }
+  for (i = 7; i < 10; i++) {
+    char *s;
+
+    s = g_strdup_printf (mfs_pattern, i);
+    fail_if (g_remove (s) != 0);
+    g_free (s);
+  }
+  fail_if (g_remove (my_tmpdir) != 0);
+
+  g_free (mfs_pattern);
+  g_free (my_tmpdir);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_multifilesink_key_unit)
+{
+  GstElement *mfs;
+  int i;
+  const gchar *tmpdir;
+  gchar *my_tmpdir;
+  gchar *template;
+  gchar *mfs_pattern;
+  GstBuffer *buf;
+  GstPad *sink;
+  GstSegment segment;
+  GstBus *bus;
+
+  tmpdir = g_get_tmp_dir ();
+  template = g_build_filename (tmpdir, "multifile-test-XXXXXX", NULL);
+  my_tmpdir = g_mkdtemp (template);
+  fail_if (my_tmpdir == NULL);
+
+  mfs = gst_element_factory_make ("multifilesink", NULL);
+  fail_if (mfs == NULL);
+  mfs_pattern = g_build_filename (my_tmpdir, "%05d", NULL);
+  g_object_set (G_OBJECT (mfs), "location", mfs_pattern, "next-file", 3,
+      "post-messages", TRUE, NULL);
+  bus = gst_bus_new ();
+  gst_element_set_bus (mfs, bus);
+  fail_if (gst_element_set_state (mfs,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
+
+  sink = gst_element_get_static_pad (mfs, "sink");
+
+  gst_pad_send_event (sink, gst_event_new_stream_start ("test"));
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  gst_pad_send_event (sink, gst_event_new_segment (&segment));
+
+  buf = gst_buffer_new_and_alloc (4);
+
+  gst_buffer_fill (buf, 0, "foo", 4);
+  fail_if (gst_pad_chain (sink, gst_buffer_copy (buf)) != GST_FLOW_OK);
+
+  gst_buffer_fill (buf, 0, "bar", 4);
+  fail_if (gst_pad_chain (sink, gst_buffer_copy (buf)) != GST_FLOW_OK);
+
+  fail_unless (gst_pad_send_event (sink,
+          gst_video_event_new_downstream_force_key_unit (GST_CLOCK_TIME_NONE,
+              GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, TRUE, 1)));
+
+  gst_buffer_fill (buf, 0, "baz", 4);
+  fail_if (gst_pad_chain (sink, buf) != GST_FLOW_OK);
+
+  gst_pad_send_event (sink, gst_event_new_eos ());
+
+  fail_if (gst_element_set_state (mfs,
+          GST_STATE_NULL) == GST_STATE_CHANGE_FAILURE);
+  gst_element_set_bus (mfs, NULL);
+
+  for (i = 0; i < 2; i++) {
+    char *s;
+    GstMessage *msg;
+
+    s = g_strdup_printf (mfs_pattern, i);
+    fail_if (g_remove (s) != 0);
+
+    msg = gst_bus_pop_filtered (bus, GST_MESSAGE_ELEMENT);
+    fail_unless (msg != NULL);
+    fail_unless (gst_message_has_name (msg, "GstMultiFileSink"));
+    fail_unless (strcmp (s,
+            gst_structure_get_string (gst_message_get_structure (msg),
+                "filename")) == 0);
+
+    gst_message_unref (msg);
+    g_free (s);
+  }
+  fail_if (g_remove (my_tmpdir) != 0);
+
+  gst_object_unref (bus);
+  g_free (mfs_pattern);
+  g_free (my_tmpdir);
+  gst_object_unref (sink);
+  gst_object_unref (mfs);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_multifilesrc)
+{
+  GstElement *pipeline;
+  GstElement *mfs;
+  int i;
+  const gchar *tmpdir;
+  gchar *my_tmpdir;
+  gchar *template;
+  gchar *mfs_pattern;
+
+  tmpdir = g_get_tmp_dir ();
+  template = g_build_filename (tmpdir, "multifile-test-XXXXXX", NULL);
+  my_tmpdir = g_mkdtemp (template);
+  fail_if (my_tmpdir == NULL);
+
+  pipeline =
+      gst_parse_launch
+      ("videotestsrc num-buffers=10 ! video/x-raw,format=(string)I420,width=320,height=240 ! multifilesink name=mfs",
+      NULL);
+  fail_if (pipeline == NULL);
+  mfs = gst_bin_get_by_name (GST_BIN (pipeline), "mfs");
+  fail_if (mfs == NULL);
+  mfs_pattern = g_build_filename (my_tmpdir, "%05d", NULL);
+  g_object_set (G_OBJECT (mfs), "location", mfs_pattern, NULL);
+  g_free (mfs_pattern);
+  g_object_unref (mfs);
+  run_pipeline (pipeline);
+  gst_object_unref (pipeline);
+
+  pipeline =
+      gst_parse_launch
+      ("multifilesrc ! video/x-raw,format=(string)I420,width=320,height=240,framerate=10/1 ! fakesink",
+      NULL);
+  fail_if (pipeline == NULL);
+  mfs = gst_bin_get_by_name (GST_BIN (pipeline), "multifilesrc0");
+  fail_if (mfs == NULL);
+  mfs_pattern = g_build_filename (my_tmpdir, "%05d", NULL);
+  g_object_set (G_OBJECT (mfs), "location", mfs_pattern, NULL);
+  g_object_unref (mfs);
+  run_pipeline (pipeline);
+  gst_object_unref (pipeline);
+
+  for (i = 0; i < 10; i++) {
+    char *s;
+
+    s = g_strdup_printf (mfs_pattern, i);
+    fail_if (g_remove (s) != 0);
+    g_free (s);
+  }
+  fail_if (g_remove (my_tmpdir) != 0);
+
+  g_free (mfs_pattern);
+  g_free (my_tmpdir);
+}
+
+GST_END_TEST;
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+/* make sure stop_index is honoured even if the next target file exists */
+GST_START_TEST (test_multifilesrc_stop_index)
+{
+  GstElement *src;
+  GstEvent *event;
+  GstPad *sinkpad;
+  gchar *fn;
+
+  src = gst_check_setup_element ("multifilesrc");
+  fail_unless (src != NULL);
+
+  fn = g_build_filename (GST_TEST_FILES_PATH, "image.jpg", NULL);
+  g_object_set (src, "location", fn, NULL);
+  g_free (fn);
+
+  g_object_set (src, "stop-index", 5, NULL);
+
+  sinkpad = gst_check_setup_sink_pad_by_name (src, &sinktemplate, "src");
+  fail_unless (sinkpad != NULL);
+  gst_pad_set_active (sinkpad, TRUE);
+
+  gst_element_set_state (src, GST_STATE_PLAYING);
+
+  gst_element_get_state (src, NULL, NULL, -1);
+
+  /* busy-loop for EOS */
+  do {
+    g_usleep (G_USEC_PER_SEC / 10);
+    event = gst_pad_get_sticky_event (sinkpad, GST_EVENT_EOS, 0);
+  } while (event == NULL);
+  gst_event_unref (event);
+
+  /* Range appears to be [ start, stop ] */
+  fail_unless_equals_int (g_list_length (buffers), 5 + 1);
+
+  gst_element_set_state (src, GST_STATE_NULL);
+
+  gst_check_drop_buffers ();
+  gst_check_teardown_pad_by_name (src, "src");
+  gst_check_teardown_element (src);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+multifile_suite (void)
+{
+  Suite *s = suite_create ("multifile");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_multifilesink_key_frame);
+  tcase_add_test (tc_chain, test_multifilesink_max_files);
+  tcase_add_test (tc_chain, test_multifilesink_key_unit);
+  tcase_add_test (tc_chain, test_multifilesrc);
+  tcase_add_test (tc_chain, test_multifilesrc_stop_index);
+
+  return s;
+}
+
+GST_CHECK_MAIN (multifile);
diff --git a/tests/check/elements/parser.c b/tests/check/elements/parser.c
new file mode 100644
index 0000000..52ffed8
--- /dev/null
+++ b/tests/check/elements/parser.c
@@ -0,0 +1,435 @@
+/*
+ * GStreamer
+ *
+ * unit test for (audio) parser
+ *
+ * Copyright (C) 2008 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include "elements/parser.h"
+
+
+/* context state variables */
+const gchar *ctx_factory;
+GstStaticPadTemplate *ctx_sink_template;
+GstStaticPadTemplate *ctx_src_template;
+GstCaps *ctx_input_caps;
+GstCaps *ctx_output_caps;
+guint ctx_discard = 0;
+datablob ctx_headers[MAX_HEADERS] = { {NULL, 0}, };
+
+gboolean ctx_no_metadata = FALSE;
+
+/* helper variables */
+GList *current_buf = NULL;
+
+GstPad *srcpad, *sinkpad;
+guint dataoffset = 0;
+GstClockTime ts_counter = 0;
+gint64 offset_counter = 0;
+guint buffer_counter = 0;
+
+typedef struct
+{
+  guint discard;
+  guint buffers_before_offset_skip;
+  guint offset_skip_amount;
+  const guint8 *data_to_verify;
+  guint data_to_verify_size;
+  GstCaps *caps;
+  gboolean no_metadata;
+} buffer_verify_data_s;
+
+/* takes a copy of the passed buffer data */
+static GstBuffer *
+buffer_new (const unsigned char *buffer_data, guint size)
+{
+  GstBuffer *buffer;
+
+  buffer = gst_buffer_new_and_alloc (size);
+  if (buffer_data) {
+    gst_buffer_fill (buffer, 0, buffer_data, size);
+  } else {
+    guint i;
+    GstMapInfo map;
+
+    gst_buffer_map (buffer, &map, GST_MAP_WRITE);
+    /* Create a recognizable pattern (loop 0x00 -> 0xff) in the data block */
+    for (i = 0; i < map.size; i++) {
+      map.data[i] = i % 0x100;
+    }
+    gst_buffer_unmap (buffer, &map);
+  }
+
+  /* gst_buffer_set_caps (buffer, GST_PAD_CAPS (srcpad)); */
+  GST_BUFFER_OFFSET (buffer) = dataoffset;
+  dataoffset += size;
+  return buffer;
+}
+
+/*
+ * Adds buffer sizes together.
+ */
+static void
+buffer_count_size (void *buffer, void *user_data)
+{
+  guint *sum = (guint *) user_data;
+  *sum += gst_buffer_get_size (buffer);
+}
+
+/*
+ * Verify that given buffer contains predefined ADTS frame.
+ */
+static void
+buffer_verify_data (void *buffer, void *user_data)
+{
+  buffer_verify_data_s *vdata;
+
+  if (!user_data) {
+    return;
+  }
+
+  vdata = (buffer_verify_data_s *) user_data;
+
+  GST_DEBUG ("discard: %d", vdata->discard);
+  if (vdata->discard) {
+    buffer_counter++;
+    if (buffer_counter == vdata->discard) {
+      buffer_counter = 0;
+      vdata->discard = 0;
+    }
+    return;
+  }
+
+  fail_unless (gst_buffer_get_size (buffer) == vdata->data_to_verify_size);
+  fail_unless (gst_buffer_memcmp (buffer, 0, vdata->data_to_verify,
+          vdata->data_to_verify_size) == 0);
+
+  if (vdata->buffers_before_offset_skip) {
+    /* This is for skipping the garbage in some test cases */
+    if (buffer_counter == vdata->buffers_before_offset_skip) {
+      offset_counter += vdata->offset_skip_amount;
+    }
+  }
+  if (!vdata->no_metadata) {
+    fail_unless (GST_BUFFER_TIMESTAMP (buffer) == ts_counter);
+    fail_unless (GST_BUFFER_DURATION (buffer) != 0);
+    fail_unless (GST_BUFFER_OFFSET (buffer) == offset_counter);
+  }
+
+  ts_counter += GST_BUFFER_DURATION (buffer);
+  offset_counter += gst_buffer_get_size (buffer);
+  buffer_counter++;
+}
+
+static GstElement *
+setup_element (const gchar * factory, GstStaticPadTemplate * sink_template,
+    GstCaps * sink_caps, GstStaticPadTemplate * src_template,
+    GstCaps * src_caps)
+{
+  GstElement *element;
+  GstBus *bus;
+  gchar *caps_str = NULL;
+
+  element = gst_check_setup_element (factory);
+  srcpad = gst_check_setup_src_pad (element, src_template);
+  if (sink_caps) {
+    caps_str = gst_caps_to_string (sink_caps);
+    sink_template->static_caps.string = caps_str;
+  }
+  sinkpad = gst_check_setup_sink_pad (element, sink_template);
+  gst_pad_set_active (srcpad, TRUE);
+  gst_check_setup_events (srcpad, element, src_caps, GST_FORMAT_BYTES);
+  gst_pad_set_active (sinkpad, TRUE);
+
+  bus = gst_bus_new ();
+  gst_element_set_bus (element, bus);
+
+  fail_unless (gst_element_set_state (element,
+          GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE,
+      "could not set to playing");
+
+  ts_counter = offset_counter = buffer_counter = 0;
+  buffers = NULL;
+  g_free (caps_str);
+  return element;
+}
+
+static void
+cleanup_element (GstElement * element)
+{
+  GstBus *bus;
+
+  /* Free parsed buffers */
+  gst_check_drop_buffers ();
+
+  bus = GST_ELEMENT_BUS (element);
+  gst_bus_set_flushing (bus, TRUE);
+  gst_object_unref (bus);
+
+  gst_pad_set_active (srcpad, FALSE);
+  gst_pad_set_active (sinkpad, FALSE);
+  gst_check_teardown_src_pad (element);
+  gst_check_teardown_sink_pad (element);
+  gst_check_teardown_element (element);
+}
+
+/* inits a standard test */
+void
+gst_parser_test_init (GstParserTest * ptest, guint8 * data, guint size,
+    guint num)
+{
+  /* need these */
+  fail_unless (ctx_factory != NULL);
+  fail_unless (ctx_src_template != NULL);
+  fail_unless (ctx_sink_template != NULL);
+
+  /* basics */
+  memset (ptest, 0, sizeof (*ptest));
+  ptest->factory = ctx_factory;
+  ptest->sink_template = ctx_sink_template;
+  ptest->src_template = ctx_src_template;
+  ptest->framed = TRUE;
+  /* could be NULL if not relevant/needed */
+  ptest->src_caps = ctx_input_caps;
+  ptest->sink_caps = ctx_output_caps;
+  memcpy (ptest->headers, ctx_headers, sizeof (ptest->headers));
+  ptest->discard = ctx_discard;
+  /* some data that pleases caller */
+  ptest->series[0].data = data;
+  ptest->series[0].size = size;
+  ptest->series[0].num = num;
+  ptest->series[0].fpb = 1;
+  ptest->series[1].fpb = 1;
+  ptest->series[2].fpb = 1;
+  ptest->no_metadata = ctx_no_metadata;
+}
+
+/*
+ * Test if the parser pushes clean data properly.
+ */
+void
+gst_parser_test_run (GstParserTest * test, GstCaps ** out_caps)
+{
+  buffer_verify_data_s vdata = { 0, 0, 0, NULL, 0, NULL, FALSE };
+  GstElement *element;
+  GstBuffer *buffer = NULL;
+  GstCaps *src_caps;
+  guint i, j, k;
+  guint frames = 0, size = 0;
+
+  element = setup_element (test->factory, test->sink_template, NULL,
+      test->src_template, test->src_caps);
+
+  /* push some setup headers */
+  for (j = 0; j < G_N_ELEMENTS (test->headers) && test->headers[j].data; j++) {
+    buffer = buffer_new (test->headers[j].data, test->headers[j].size);
+    fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
+  }
+
+  for (j = 0; j < 3; j++) {
+    for (i = 0; i < test->series[j].num; i++) {
+      /* sanity enforcing */
+      for (k = 0; k < MAX (1, test->series[j].fpb); k++) {
+        if (!k)
+          buffer = buffer_new (test->series[j].data, test->series[j].size);
+        else {
+          buffer = gst_buffer_append (buffer,
+              buffer_new (test->series[j].data, test->series[j].size));
+        }
+      }
+      fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
+      if (j == 0)
+        vdata.buffers_before_offset_skip++;
+      else if (j == 1)
+        vdata.offset_skip_amount += test->series[j].size * test->series[j].fpb;
+      if (j != 1) {
+        frames += test->series[j].fpb;
+        size += test->series[j].size * test->series[j].fpb;
+      }
+    }
+  }
+  gst_pad_push_event (srcpad, gst_event_new_eos ());
+
+  if (G_LIKELY (test->framed))
+    fail_unless_equals_int (g_list_length (buffers) - test->discard, frames);
+
+  /* if all frames are identical, do extended test,
+   * otherwise only verify total data size */
+  if (test->series[0].data && (!test->series[2].size ||
+          (test->series[0].size == test->series[2].size && test->series[2].data
+              && !memcmp (test->series[0].data, test->series[2].data,
+                  test->series[0].size)))) {
+    vdata.data_to_verify = test->series[0].data;
+    vdata.data_to_verify_size = test->series[0].size;
+    vdata.caps = test->sink_caps;
+    vdata.discard = test->discard;
+    vdata.no_metadata = test->no_metadata;
+    g_list_foreach (buffers, buffer_verify_data, &vdata);
+  } else {
+    guint datasum = 0;
+
+    g_list_foreach (buffers, buffer_count_size, &datasum);
+    size -= test->dropped;
+    fail_unless_equals_int (datasum, size);
+  }
+
+  src_caps = gst_pad_get_current_caps (sinkpad);
+  GST_LOG ("output caps: %" GST_PTR_FORMAT, src_caps);
+
+  if (test->sink_caps) {
+    GST_LOG ("%" GST_PTR_FORMAT " = %" GST_PTR_FORMAT " ?", src_caps,
+        test->sink_caps);
+    fail_unless (gst_caps_is_equal (src_caps, test->sink_caps));
+  }
+
+  if (out_caps)
+    *out_caps = src_caps;
+  else
+    gst_caps_unref (src_caps);
+
+  cleanup_element (element);
+}
+
+/*
+ * Test if the parser pushes clean data properly.
+ */
+void
+gst_parser_test_normal (guint8 * data, guint size)
+{
+  GstParserTest ptest;
+
+  gst_parser_test_init (&ptest, data, size, 10);
+  gst_parser_test_run (&ptest, NULL);
+}
+
+/*
+ * Test if parser drains its buffers properly. Even one single frame
+ * should be drained and pushed forward when EOS occurs. This single frame
+ * case is special, since normally the parser needs more data to be sure
+ * about stream format. But it should still push the frame forward in EOS.
+ */
+void
+gst_parser_test_drain_single (guint8 * data, guint size)
+{
+  GstParserTest ptest;
+
+  gst_parser_test_init (&ptest, data, size, 1);
+  gst_parser_test_run (&ptest, NULL);
+}
+
+/*
+ * Make sure that parser does not drain garbage when EOS occurs.
+ */
+void
+gst_parser_test_drain_garbage (guint8 * data, guint size, guint8 * garbage,
+    guint gsize)
+{
+  GstParserTest ptest;
+
+  /* provide enough initial frames since it may take some parsers some
+   * time to be convinced of proper sync */
+  gst_parser_test_init (&ptest, data, size, 10);
+  ptest.series[1].data = garbage;
+  ptest.series[1].size = gsize;
+  ptest.series[1].num = 1;
+  gst_parser_test_run (&ptest, NULL);
+}
+
+/*
+ * Test if parser splits a buffer that contains two frames into two
+ * separate buffers properly.
+ */
+void
+gst_parser_test_split (guint8 * data, guint size)
+{
+  GstParserTest ptest;
+
+  gst_parser_test_init (&ptest, data, size, 10);
+  ptest.series[0].fpb = 2;
+  gst_parser_test_run (&ptest, NULL);
+}
+
+/*
+ * Test if the parser skips garbage between frames properly.
+ */
+void
+gst_parser_test_skip_garbage (guint8 * data, guint size, guint8 * garbage,
+    guint gsize)
+{
+  GstParserTest ptest;
+
+  gst_parser_test_init (&ptest, data, size, 10);
+  ptest.series[1].data = garbage;
+  ptest.series[1].size = gsize;
+  ptest.series[1].num = 1;
+  ptest.series[2].data = data;
+  ptest.series[2].size = size;
+  ptest.series[2].num = 10;
+  gst_parser_test_run (&ptest, NULL);
+}
+
+/*
+ * Test if the src caps are set according to stream format.
+ */
+void
+gst_parser_test_output_caps (guint8 * data, guint size,
+    const gchar * input_caps, const gchar * output_caps)
+{
+  GstParserTest ptest;
+
+  gst_parser_test_init (&ptest, data, size, 10);
+  if (input_caps) {
+    ptest.src_caps = gst_caps_from_string (input_caps);
+    fail_unless (ptest.src_caps != NULL);
+  }
+  if (output_caps) {
+    ptest.sink_caps = gst_caps_from_string (output_caps);
+    fail_unless (ptest.sink_caps != NULL);
+  }
+  gst_parser_test_run (&ptest, NULL);
+  if (ptest.sink_caps)
+    gst_caps_unref (ptest.sink_caps);
+  if (ptest.src_caps)
+    gst_caps_unref (ptest.src_caps);
+}
+
+/*
+ * Test if the src caps are set according to stream format.
+ */
+GstCaps *
+gst_parser_test_get_output_caps (guint8 * data, guint size,
+    const gchar * input_caps)
+{
+  GstParserTest ptest;
+  GstCaps *out_caps;
+
+  gst_parser_test_init (&ptest, data, size, 10);
+  if (input_caps) {
+    ptest.src_caps = gst_caps_from_string (input_caps);
+    fail_unless (ptest.src_caps != NULL);
+  }
+  gst_parser_test_run (&ptest, &out_caps);
+  if (ptest.src_caps)
+    gst_caps_unref (ptest.src_caps);
+
+  return out_caps;
+}
diff --git a/tests/check/elements/parser.h b/tests/check/elements/parser.h
new file mode 100644
index 0000000..c4867cd
--- /dev/null
+++ b/tests/check/elements/parser.h
@@ -0,0 +1,95 @@
+/*
+ * GStreamer
+ *
+ * unit test for (audio) parser
+ *
+ * Copyright (C) 2008 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+
+#define MAX_HEADERS 10
+
+typedef struct {
+    guint8     *data;
+    guint       size;
+} datablob;
+
+/* context state variables; to be set by test using this helper */
+/* mandatory */
+extern const gchar *ctx_factory;
+extern GstStaticPadTemplate *ctx_sink_template;
+extern GstStaticPadTemplate *ctx_src_template;
+/* optional */
+extern GstCaps *ctx_input_caps;
+extern GstCaps *ctx_output_caps;
+extern guint ctx_discard;
+extern datablob ctx_headers[MAX_HEADERS];
+extern gboolean ctx_no_metadata;
+
+/* no refs taken/kept, all up to caller */
+typedef struct
+{
+  const gchar          *factory;
+  GstStaticPadTemplate *sink_template;
+  GstStaticPadTemplate *src_template;
+  /* caps that go into element */
+  GstCaps              *src_caps;
+  /* optional: output caps to verify */
+  GstCaps              *sink_caps;
+  /* initial headers */
+  datablob              headers[MAX_HEADERS];
+  /* initial (header) output to forego checking */
+  guint                 discard;
+  /* series of buffers; middle series considered garbage */
+  struct {
+    /* data and size */
+    guint8     *data;
+    guint      size;
+    /* num of frames with above data per buffer */
+    guint      fpb;
+    /* num of buffers */
+    guint      num;
+  } series[3];
+  /* sigh, weird cases */
+  gboolean              framed;
+  guint                 dropped;
+  gboolean              no_metadata;
+} GstParserTest;
+
+void gst_parser_test_init (GstParserTest * ptest, guint8 * data, guint size, guint num);
+
+void gst_parser_test_run (GstParserTest * test, GstCaps ** out_caps);
+
+void gst_parser_test_normal (guint8 *data, guint size);
+
+void gst_parser_test_drain_single (guint8 *data, guint size);
+
+void gst_parser_test_drain_garbage (guint8 *data, guint size, guint8 *garbage, guint gsize);
+
+void gst_parser_test_split (guint8 *data, guint size);
+
+void gst_parser_test_skip_garbage (guint8 *data, guint size, guint8 *garbage, guint gsize);
+
+void gst_parser_test_output_caps (guint8 *data, guint size, const gchar * input_caps,
+                                  const gchar * output_caps);
+
+GstCaps *gst_parser_test_get_output_caps (guint8 *data, guint size, const gchar * input_caps);
+
diff --git a/tests/check/elements/qtdemux.c b/tests/check/elements/qtdemux.c
new file mode 100644
index 0000000..56b6693
--- /dev/null
+++ b/tests/check/elements/qtdemux.c
@@ -0,0 +1,154 @@
+/* GStreamer
+ *
+ * unit test for qtdemux
+ *
+ * Copyright (C) <2016> Edward Hervey <edward@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "qtdemux.h"
+
+typedef struct
+{
+  GstPad *srcpad;
+  guint expected_size;
+  GstClockTime expected_time;
+} CommonTestData;
+
+static GstPadProbeReturn
+qtdemux_probe (GstPad * pad, GstPadProbeInfo * info, CommonTestData * data)
+{
+  GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER (info);
+
+  fail_unless_equals_int (gst_buffer_get_size (buf), data->expected_size);
+  fail_unless_equals_uint64 (GST_BUFFER_PTS (buf), data->expected_time);
+  gst_buffer_unref (buf);
+  return GST_PAD_PROBE_HANDLED;
+}
+
+static void
+qtdemux_pad_added_cb (GstElement * element, GstPad * pad, CommonTestData * data)
+{
+  data->srcpad = pad;
+  gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
+      (GstPadProbeCallback) qtdemux_probe, data, NULL);
+}
+
+GST_START_TEST (test_qtdemux_input_gap)
+{
+  GstElement *qtdemux;
+  GstPad *sinkpad;
+  CommonTestData data = { 0, };
+  GstBuffer *inbuf;
+  GstSegment segment;
+  GstEvent *event;
+  guint i, offset;
+  GstClockTime pts;
+
+  /* The goal of this test is to check that qtdemux can properly handle
+   * fragmented input from dashdemux, with gaps in it.
+   *
+   * Input segment :
+   *   - TIME
+   * Input buffers :
+   *   - The offset is set on buffers, it corresponds to the offset
+   *     within the current fragment.
+   *   - Buffer of the beginning of a fragment has the PTS set, others
+   *     don't.
+   *   - By extension, the beginning of a fragment also has an offset
+   *     of 0.
+   */
+
+  qtdemux = gst_element_factory_make ("qtdemux", NULL);
+  gst_element_set_state (qtdemux, GST_STATE_PLAYING);
+  sinkpad = gst_element_get_static_pad (qtdemux, "sink");
+
+  /* We'll want to know when the source pad is added */
+  g_signal_connect (qtdemux, "pad-added", (GCallback) qtdemux_pad_added_cb,
+      &data);
+
+  /* Send the initial STREAM_START and segment (TIME) event */
+  event = gst_event_new_stream_start ("TEST");
+  GST_DEBUG ("Pushing stream-start event");
+  fail_unless (gst_pad_send_event (sinkpad, event) == TRUE);
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  event = gst_event_new_segment (&segment);
+  GST_DEBUG ("Pushing segment event");
+  fail_unless (gst_pad_send_event (sinkpad, event) == TRUE);
+
+  /* Feed the init buffer, should create the source pad */
+  inbuf = gst_buffer_new_and_alloc (init_mp4_len);
+  gst_buffer_fill (inbuf, 0, init_mp4, init_mp4_len);
+  GST_BUFFER_PTS (inbuf) = 0;
+  GST_BUFFER_OFFSET (inbuf) = 0;
+  GST_DEBUG ("Pushing header buffer");
+  fail_unless (gst_pad_chain (sinkpad, inbuf) == GST_FLOW_OK);
+
+  /* Now send the trun of the first fragment */
+  inbuf = gst_buffer_new_and_alloc (seg_1_moof_size);
+  gst_buffer_fill (inbuf, 0, seg_1_m4f, seg_1_moof_size);
+  GST_BUFFER_PTS (inbuf) = 0;
+  GST_BUFFER_OFFSET (inbuf) = 0;
+  /* We are simulating that this fragment can happen at any point */
+  GST_BUFFER_FLAG_SET (inbuf, GST_BUFFER_FLAG_DISCONT);
+  GST_DEBUG ("Pushing trun buffer");
+  fail_unless (gst_pad_chain (sinkpad, inbuf) == GST_FLOW_OK);
+  fail_if (data.srcpad == NULL);
+
+  /* We are now ready to send some buffers with gaps */
+  offset = seg_1_sample_0_offset;
+  pts = 0;
+
+  GST_DEBUG ("Pushing gap'ed buffers");
+  for (i = 0; i < 129; i++) {
+    /* Let's send one every 3 */
+    if ((i % 3) == 0) {
+      GST_DEBUG ("Pushing buffer #%d offset:%" G_GUINT32_FORMAT, i, offset);
+      inbuf = gst_buffer_new_and_alloc (seg_1_sample_sizes[i]);
+      gst_buffer_fill (inbuf, 0, seg_1_m4f + offset, seg_1_sample_sizes[i]);
+      GST_BUFFER_OFFSET (inbuf) = offset;
+      GST_BUFFER_FLAG_SET (inbuf, GST_BUFFER_FLAG_DISCONT);
+      data.expected_time =
+          gst_util_uint64_scale (pts, GST_SECOND, seg_1_timescale);
+      data.expected_size = seg_1_sample_sizes[i];
+      fail_unless (gst_pad_chain (sinkpad, inbuf) == GST_FLOW_OK);
+    }
+    /* Finally move offset forward */
+    offset += seg_1_sample_sizes[i];
+    pts += seg_1_sample_duration;
+  }
+
+  gst_object_unref (sinkpad);
+  gst_element_set_state (qtdemux, GST_STATE_NULL);
+  gst_object_unref (qtdemux);
+}
+
+GST_END_TEST;
+
+static Suite *
+qtdemux_suite (void)
+{
+  Suite *s = suite_create ("qtdemux");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_qtdemux_input_gap);
+
+  return s;
+}
+
+GST_CHECK_MAIN (qtdemux)
diff --git a/tests/check/elements/qtdemux.h b/tests/check/elements/qtdemux.h
new file mode 100644
index 0000000..b8425f0
--- /dev/null
+++ b/tests/check/elements/qtdemux.h
@@ -0,0 +1,4251 @@
+/* GStreamer
+ *
+ * unit test for qtdemux
+ *
+ * Copyright (C) <2016> Edward Hervey <edward@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <glib/gstdio.h>
+
+#include <gst/check/gstcheck.h>
+
+/* Fragments taken from http://www.bok.net/dash/tears_of_steel/cleartext/stream.mpd
+ *
+ * Audio stream (aac)
+ * Header + first fragment
+ */
+
+/* http://www.bok.net/dash/tears_of_steel/cleartext/audio/en/init.mp4 */
+static guint8 init_mp4[] = {
+  0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70, 0x69, 0x73, 0x6f, 0x6d,
+  0x00, 0x00, 0x02, 0x00, 0x69, 0x73, 0x6f, 0x6d, 0x69, 0x73, 0x6f, 0x32,
+  0x61, 0x76, 0x63, 0x31, 0x6d, 0x70, 0x34, 0x31, 0x00, 0x00, 0x02, 0x50,
+  0x6d, 0x6f, 0x6f, 0x76, 0x00, 0x00, 0x00, 0x6c, 0x6d, 0x76, 0x68, 0x64,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x03, 0xe8, 0x00, 0x0b, 0x33, 0xd7, 0x00, 0x01, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0xa4, 0x74, 0x72, 0x61, 0x6b,
+  0x00, 0x00, 0x00, 0x5c, 0x74, 0x6b, 0x68, 0x64, 0x00, 0x00, 0x00, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x33, 0xbc, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40,
+  0x6d, 0x64, 0x69, 0x61, 0x00, 0x00, 0x00, 0x20, 0x6d, 0x64, 0x68, 0x64,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xac, 0x44, 0x00, 0x00, 0x00, 0x00, 0x15, 0xc7, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x35, 0x68, 0x64, 0x6c, 0x72, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x73, 0x6f, 0x75, 0x6e, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x65, 0x6e, 0x74,
+  0x6f, 0x34, 0x20, 0x53, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x48, 0x61, 0x6e,
+  0x64, 0x6c, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x6d, 0x69, 0x6e,
+  0x66, 0x00, 0x00, 0x00, 0x10, 0x73, 0x6d, 0x68, 0x64, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x64, 0x69, 0x6e,
+  0x66, 0x00, 0x00, 0x00, 0x1c, 0x64, 0x72, 0x65, 0x66, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x75, 0x72, 0x6c,
+  0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa7, 0x73, 0x74, 0x62,
+  0x6c, 0x00, 0x00, 0x00, 0x5b, 0x73, 0x74, 0x73, 0x64, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4b, 0x6d, 0x70, 0x34,
+  0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x00, 0xac, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x65, 0x73, 0x64,
+  0x73, 0x00, 0x00, 0x00, 0x00, 0x03, 0x19, 0x00, 0x00, 0x00, 0x04, 0x11,
+  0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf4, 0x01, 0x00, 0x01, 0xf4,
+  0x01, 0x05, 0x02, 0x12, 0x10, 0x06, 0x01, 0x02, 0x00, 0x00, 0x00, 0x14,
+  0x73, 0x74, 0x73, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x73, 0x74, 0x73, 0x63,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  0x73, 0x74, 0x74, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x10, 0x73, 0x74, 0x63, 0x6f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6d, 0x76, 0x65, 0x78,
+  0x00, 0x00, 0x00, 0x10, 0x6d, 0x65, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x0b, 0x33, 0xd7, 0x00, 0x00, 0x00, 0x20, 0x74, 0x72, 0x65, 0x78,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+guint init_mp4_len = 624;
+
+/* http://www.bok.net/dash/tears_of_steel/cleartext/audio/en/seg-1.m4f */
+static const guint8 seg_1_m4f[] = {
+  0x00, 0x00, 0x04, 0x60, 0x6d, 0x6f, 0x6f, 0x66, 0x00, 0x00, 0x00, 0x10,
+  0x6d, 0x66, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x00, 0x00, 0x04, 0x48, 0x74, 0x72, 0x61, 0x66, 0x00, 0x00, 0x00, 0x10,
+  0x74, 0x66, 0x68, 0x64, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x00, 0x00, 0x00, 0x14, 0x74, 0x66, 0x64, 0x74, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x1c,
+  0x74, 0x72, 0x75, 0x6e, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x81,
+  0x00, 0x00, 0x04, 0x68, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x73,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x74, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0xdd, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x12,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xe9, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0xce, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xb9,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xa5, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0xa4, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x9a,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x92, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x7d,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x82, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x82,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x71, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x72, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x6a,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x5a, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x65, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x63,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x78, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x55,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x66, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x6a,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x4d, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x9f, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x82,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x58, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x82,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x66, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x6d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x94,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x56, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x69, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x6e,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x69, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x86,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x5c, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x6e, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x67,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x65, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x68, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x5d,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x6d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x89,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x61, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x81, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x7d,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x5c, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x59, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x9e,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x74, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x71, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x91,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x87, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x4d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x53,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xa7, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x57, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xbd,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xa9, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0xa6, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x9f,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x96, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x85, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x8b,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x77, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xba,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x87, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x81,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x53, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x15, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x25,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x3c, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x47, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x35,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x85, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x67, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xab,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0xa4, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x97,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x3c, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x6a, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xa3,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x5d, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x83, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x46,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x48, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x6f, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x58,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xa9, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x49, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x7b,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x93, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x3a, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x8d,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x70, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x85, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x7c,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x75, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x56, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x57,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x70, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x67,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x60, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x69, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x6e,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0xa3, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x4b,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xaa, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x91, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x7e,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x9b, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x6c,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x52, 0x00, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x01, 0x59, 0x00, 0x00, 0xbd, 0x32, 0x6d, 0x64, 0x61, 0x74,
+  0x21, 0x11, 0x45, 0x00, 0x14, 0x50, 0x01, 0x46, 0xff, 0xf1, 0x0a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5d, 0xe9, 0x82, 0x14, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+  0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+  0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+  0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+  0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+  0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+  0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+  0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xbc, 0x21,
+  0x1a, 0x93, 0xa9, 0x04, 0x3e, 0xa3, 0x59, 0x41, 0x67, 0xa6, 0x1c, 0x02,
+  0x81, 0x4a, 0x3d, 0x3e, 0x5d, 0x30, 0x1f, 0x5b, 0x59, 0x41, 0x49, 0xde,
+  0x22, 0x1e, 0x81, 0x0b, 0x3f, 0xf6, 0xff, 0xf1, 0x0a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+  0x5d, 0xe6, 0xc2, 0x14, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+  0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+  0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+  0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+  0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+  0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xbc, 0x21,
+  0x1a, 0x93, 0x85, 0x9a, 0x92, 0xc6, 0x41, 0x30, 0x91, 0x8c, 0x45, 0x08,
+  0xa4, 0xc5, 0x45, 0x20, 0xcc, 0xd6, 0x22, 0x84, 0xa1, 0x02, 0x53, 0x1a,
+  0xc8, 0x9a, 0x50, 0x21, 0x89, 0xfe, 0x70, 0x24, 0x76, 0x64, 0x5c, 0xee,
+  0x1e, 0x76, 0x20, 0x03, 0x90, 0x52, 0x88, 0x20, 0xb8, 0xf0, 0x58, 0xf0,
+  0x1f, 0xd8, 0xeb, 0x14, 0x9b, 0x1f, 0xdf, 0xf1, 0xe8, 0xce, 0xa8, 0xf3,
+  0x93, 0xa7, 0x34, 0x9a, 0x26, 0x92, 0x9b, 0xb7, 0xbe, 0x40, 0xcb, 0xf0,
+  0xcc, 0x8f, 0x36, 0x98, 0x48, 0x18, 0xe6, 0x17, 0x61, 0x56, 0x23, 0x0e,
+  0x33, 0x2a, 0xc2, 0x32, 0x01, 0x57, 0xdb, 0x6e, 0x05, 0x22, 0x56, 0xcd,
+  0x69, 0x9b, 0xb6, 0x2e, 0x12, 0xbf, 0x4a, 0x76, 0x24, 0x60, 0xc0, 0xe8,
+  0xdd, 0x2b, 0x57, 0x4d, 0x2e, 0xd3, 0x18, 0x4e, 0x10, 0x64, 0xcb, 0xb6,
+  0x74, 0xb0, 0x9b, 0xd4, 0xd9, 0x83, 0x11, 0xb6, 0x14, 0xb8, 0xee, 0xc0,
+  0xde, 0x35, 0xc5, 0xb4, 0x1e, 0x52, 0xa2, 0xa6, 0x74, 0x07, 0x25, 0x9d,
+  0xa7, 0x52, 0xa4, 0xc6, 0x45, 0x03, 0xad, 0xb4, 0x03, 0xd4, 0x0b, 0xc6,
+  0x12, 0x4b, 0xdf, 0x5d, 0x64, 0xea, 0xea, 0xda, 0x84, 0x00, 0x6f, 0x46,
+  0xe4, 0x39, 0x16, 0xf2, 0xca, 0x8f, 0xd0, 0x29, 0x0d, 0xee, 0x47, 0x32,
+  0xbe, 0x51, 0x6b, 0xef, 0x59, 0x15, 0xe5, 0x13, 0x0b, 0x77, 0x92, 0x15,
+  0x7f, 0x04, 0x5d, 0xea, 0xca, 0xc0, 0x40, 0x39, 0xa5, 0x12, 0x15, 0x7d,
+  0xea, 0x12, 0xe7, 0x25, 0xf2, 0x94, 0xb1, 0x2e, 0x7d, 0x57, 0xdc, 0x99,
+  0xae, 0xa2, 0xea, 0x33, 0xba, 0xa1, 0xcb, 0xc1, 0x54, 0x3b, 0x06, 0xe3,
+  0x34, 0x50, 0xba, 0x89, 0xec, 0xaa, 0xec, 0x47, 0xe6, 0xdc, 0x3b, 0xfa,
+  0x1a, 0xe1, 0xe9, 0xc7, 0x46, 0x40, 0x1c, 0xa1, 0x89, 0x98, 0x23, 0x84,
+  0x6e, 0xe8, 0xba, 0x8c, 0xcb, 0x01, 0x48, 0xa8, 0x28, 0x16, 0xa8, 0x6b,
+  0x22, 0x69, 0x40, 0x86, 0x20, 0x79, 0x83, 0x21, 0x7b, 0x6f, 0x6d, 0xb4,
+  0xda, 0x6e, 0x31, 0x2a, 0x26, 0x12, 0xa5, 0xb7, 0x4a, 0x91, 0x30, 0x55,
+  0xb4, 0xe6, 0x99, 0x6a, 0xa6, 0x12, 0x1f, 0x72, 0xdb, 0x65, 0xdc, 0xbe,
+  0x17, 0x15, 0x6b, 0xc0, 0x9e, 0x55, 0x20, 0x8c, 0xf5, 0x27, 0x3c, 0x09,
+  0x42, 0xcc, 0x78, 0x8d, 0x24, 0x37, 0xb9, 0x45, 0xdd, 0x14, 0xa5, 0x99,
+  0xde, 0x15, 0xa0, 0x5a, 0x3e, 0xfe, 0x8c, 0xd7, 0x2a, 0x14, 0x52, 0xef,
+  0x6e, 0x87, 0x9c, 0x22, 0x9d, 0x08, 0x65, 0x59, 0xb5, 0x60, 0x78, 0xfd,
+  0xc3, 0x2e, 0x6a, 0x88, 0x13, 0xc2, 0x4f, 0x72, 0x6c, 0x92, 0x02, 0x4c,
+  0x88, 0xd4, 0xc4, 0x80, 0xc1, 0x48, 0x56, 0x4c, 0x39, 0x98, 0x5d, 0x9d,
+  0x31, 0x35, 0x81, 0x47, 0x72, 0x4d, 0xe5, 0x77, 0x54, 0xf8, 0x88, 0xe4,
+  0x07, 0xad, 0xa1, 0xa6, 0xa1, 0xe9, 0x69, 0x16, 0xad, 0x33, 0x88, 0x86,
+  0xee, 0x18, 0xea, 0x37, 0xca, 0x8d, 0xd8, 0x5f, 0x95, 0x04, 0xc3, 0x55,
+  0x76, 0x45, 0xf7, 0xd5, 0x9c, 0x32, 0x4e, 0x80, 0x80, 0xd0, 0x9c, 0x41,
+  0xa7, 0x54, 0xbc, 0x36, 0x90, 0xb3, 0xcf, 0xc0, 0x70, 0x46, 0x45, 0x34,
+  0xca, 0x93, 0x3c, 0x6b, 0xa6, 0xed, 0x40, 0x8a, 0x98, 0x29, 0x12, 0x78,
+  0xd9, 0x6c, 0x37, 0x04, 0xad, 0xf3, 0x09, 0x6e, 0x6e, 0xce, 0xe9, 0x1c,
+  0x29, 0x05, 0x06, 0x08, 0x63, 0x7e, 0x43, 0x3a, 0x2e, 0x2e, 0xef, 0x85,
+  0xb7, 0x89, 0xc0, 0xf5, 0xf5, 0x72, 0x90, 0x1c, 0x21, 0x1a, 0x88, 0x07,
+  0xff, 0xff, 0xff, 0xfe, 0xef, 0x66, 0xa3, 0x31, 0x11, 0x6c, 0x44, 0x13,
+  0x12, 0x88, 0xe1, 0x0e, 0x18, 0xe3, 0x70, 0xa0, 0x14, 0x2a, 0xe9, 0x28,
+  0x82, 0x44, 0xe4, 0x68, 0x38, 0x21, 0x08, 0x2c, 0xa4, 0xd9, 0x1e, 0xc4,
+  0x79, 0x28, 0x10, 0x2e, 0xe4, 0x78, 0x52, 0x24, 0x21, 0x11, 0x83, 0xf6,
+  0xba, 0xd5, 0xa8, 0xe4, 0xbc, 0xf1, 0x3c, 0x65, 0x25, 0x7a, 0xb4, 0x5c,
+  0x89, 0xce, 0x14, 0xb2, 0x8e, 0x93, 0x52, 0xf3, 0x82, 0x4c, 0x4d, 0x42,
+  0x68, 0xb5, 0xc8, 0x15, 0xea, 0xd1, 0x1d, 0xa6, 0xf3, 0x83, 0xf4, 0x1f,
+  0x18, 0x97, 0xb7, 0x98, 0xfd, 0x9c, 0x13, 0x5c, 0x90, 0xe1, 0x7d, 0x88,
+  0xaf, 0x4f, 0x16, 0x8e, 0x7e, 0xfe, 0x99, 0x74, 0x80, 0x25, 0xea, 0x96,
+  0x13, 0x20, 0x3d, 0xdf, 0x79, 0x3e, 0x93, 0xdb, 0x74, 0x9a, 0x11, 0x4e,
+  0xe9, 0xd8, 0x40, 0x1a, 0x1c, 0x0c, 0x04, 0x44, 0x8e, 0x1e, 0x86, 0x34,
+  0x42, 0x68, 0x68, 0x0e, 0xf9, 0xc2, 0x12, 0x4b, 0x0e, 0x57, 0x10, 0xd4,
+  0x80, 0xc2, 0xd0, 0xe8, 0x8c, 0xc2, 0xb2, 0x97, 0x99, 0xdd, 0xcd, 0x08,
+  0xaa, 0x6b, 0x46, 0xab, 0x6c, 0xaf, 0x97, 0x4b, 0x6f, 0x8b, 0x62, 0x81,
+  0x25, 0xed, 0x44, 0x90, 0x2b, 0x71, 0xdb, 0x12, 0x4c, 0x6d, 0x08, 0xb5,
+  0x8b, 0x4b, 0x12, 0x92, 0x28, 0x83, 0xbb, 0xb4, 0x54, 0x2d, 0x17, 0xbc,
+  0x25, 0x67, 0xb5, 0xf2, 0x06, 0x20, 0x8d, 0x47, 0x7d, 0x5d, 0x23, 0x89,
+  0xa8, 0x9d, 0x94, 0x6e, 0x3c, 0xc9, 0x46, 0x12, 0x60, 0x46, 0x2c, 0x4c,
+  0xb6, 0xeb, 0x4b, 0x51, 0xf6, 0xd2, 0x4d, 0x7c, 0x7d, 0x07, 0x49, 0xb5,
+  0x30, 0xc0, 0xc3, 0x53, 0x62, 0x1f, 0xf4, 0xa2, 0xb6, 0x76, 0xd2, 0x35,
+  0xd1, 0xaa, 0xb1, 0xf5, 0x9a, 0x8c, 0x83, 0xde, 0x6c, 0xa9, 0x35, 0xbc,
+  0xcf, 0x2d, 0xad, 0x2b, 0xf1, 0xf7, 0x79, 0xff, 0x48, 0x1f, 0xb1, 0xfa,
+  0x0e, 0x2e, 0x07, 0x57, 0x7c, 0xed, 0x76, 0x70, 0xf9, 0x7a, 0xfc, 0x9e,
+  0x17, 0x9c, 0x01, 0xdb, 0xd0, 0xc6, 0x46, 0xb0, 0x50, 0x6c, 0x14, 0x1b,
+  0x0a, 0x88, 0xe1, 0xc0, 0xa9, 0x9a, 0x32, 0x2a, 0xae, 0xaa, 0xd5, 0x50,
+  0x46, 0x5c, 0xc2, 0x25, 0x5b, 0x05, 0x67, 0xd8, 0xd7, 0xcf, 0xa9, 0x49,
+  0xa6, 0x6b, 0x90, 0x2f, 0xb8, 0xa7, 0x16, 0x1c, 0xae, 0x05, 0xbd, 0x14,
+  0x6a, 0xb2, 0x64, 0x7c, 0xd8, 0x1a, 0xff, 0x67, 0xc4, 0xb4, 0x4f, 0x3f,
+  0x49, 0xe4, 0xdc, 0x02, 0x68, 0x90, 0x15, 0x62, 0xda, 0x17, 0xaf, 0x24,
+  0x19, 0xbb, 0x8c, 0x5d, 0x18, 0x7c, 0x9d, 0x63, 0x85, 0xfa, 0xad, 0xba,
+  0x10, 0xb6, 0x05, 0x64, 0x00, 0x4f, 0x8f, 0x5c, 0xcd, 0xb8, 0x4a, 0xd6,
+  0x8e, 0x2e, 0x02, 0x3b, 0xee, 0xe6, 0x43, 0xca, 0xca, 0x28, 0x2d, 0x24,
+  0x47, 0x11, 0xda, 0x1a, 0x03, 0xdd, 0xf2, 0xbd, 0x3b, 0x89, 0x8d, 0x54,
+  0x8e, 0xb3, 0xb1, 0x21, 0x8d, 0xfa, 0xad, 0xa6, 0x58, 0x5d, 0x13, 0x39,
+  0x3d, 0xc6, 0xfe, 0xd3, 0xec, 0xf2, 0x55, 0xf9, 0x9b, 0x25, 0x22, 0x06,
+  0x80, 0xbc, 0x93, 0x77, 0x7b, 0x46, 0xb3, 0x33, 0xa3, 0x7a, 0xf2, 0x83,
+  0xa4, 0x17, 0x2b, 0x14, 0x5a, 0x74, 0xc4, 0x62, 0xf4, 0xba, 0x78, 0xa6,
+  0xb6, 0xbf, 0x62, 0x03, 0xed, 0xc2, 0x75, 0xa7, 0xb7, 0x8c, 0x8f, 0x02,
+  0x14, 0x71, 0x81, 0xaa, 0xb7, 0xaa, 0xb0, 0x79, 0x4e, 0x1f, 0x3d, 0x47,
+  0x55, 0xaa, 0x41, 0x48, 0x42, 0xc9, 0x5b, 0xeb, 0xba, 0x7d, 0x3d, 0x4d,
+  0x35, 0x71, 0x7a, 0xd6, 0x4e, 0x2c, 0xaf, 0x04, 0x43, 0xc8, 0x63, 0x1e,
+  0xf1, 0xa0, 0x1b, 0x57, 0x07, 0x95, 0xa6, 0xc3, 0xe3, 0x2e, 0xa6, 0x6e,
+  0x41, 0x5a, 0xae, 0x3c, 0xce, 0xb0, 0xbf, 0xa3, 0x71, 0xe8, 0xbe, 0xf3,
+  0xef, 0x7d, 0x5f, 0x1f, 0xa3, 0xa3, 0xb4, 0xf3, 0x00, 0x70, 0x21, 0x1a,
+  0x93, 0x9d, 0x89, 0x90, 0x9a, 0x61, 0x50, 0xdc, 0x20, 0xa5, 0x46, 0x10,
+  0xc8, 0x4d, 0xe8, 0x05, 0x40, 0x4b, 0xa0, 0x12, 0x99, 0x8b, 0x27, 0x05,
+  0xc4, 0x96, 0x5f, 0xc3, 0x7a, 0x86, 0xcc, 0xed, 0x25, 0x8a, 0x2a, 0x90,
+  0x1e, 0x99, 0xd0, 0x46, 0x2c, 0x1f, 0x2f, 0x53, 0xec, 0x7d, 0x03, 0xd7,
+  0xc7, 0x6f, 0xc9, 0x64, 0x1c, 0x8a, 0xfd, 0xb5, 0x2b, 0x63, 0x89, 0xf9,
+  0x3e, 0x16, 0xc0, 0xb0, 0xb7, 0xbc, 0x3b, 0xa4, 0xda, 0x6e, 0xab, 0x46,
+  0x7c, 0xf7, 0x92, 0x5f, 0xf0, 0xda, 0xe6, 0xfc, 0x56, 0x1a, 0x24, 0xf0,
+  0xca, 0xf7, 0xa5, 0xa5, 0x7b, 0x70, 0x70, 0xaf, 0x8b, 0xcd, 0x18, 0xed,
+  0xc3, 0x7a, 0x4a, 0x26, 0x7d, 0xfb, 0x22, 0x94, 0x92, 0xd9, 0xcd, 0x98,
+  0xd3, 0x3a, 0x1e, 0x43, 0x74, 0x2b, 0xfd, 0x07, 0x8d, 0x2b, 0xad, 0xfe,
+  0xe9, 0xae, 0xa4, 0x1d, 0xa1, 0x2f, 0xa7, 0xb3, 0x59, 0xf4, 0x5c, 0x6e,
+  0x3e, 0xf8, 0x82, 0x3b, 0x49, 0xeb, 0xa9, 0xf5, 0xf7, 0xb7, 0x83, 0x05,
+  0xae, 0x75, 0x54, 0x01, 0x71, 0xd4, 0xa5, 0x00, 0x8a, 0x86, 0x81, 0x7b,
+  0xd0, 0x07, 0x77, 0xba, 0x44, 0xc4, 0x94, 0x3e, 0x6f, 0x5d, 0x2a, 0x75,
+  0x2a, 0x5b, 0x39, 0x4c, 0x68, 0x32, 0x65, 0x82, 0x6e, 0x9c, 0xff, 0x35,
+  0xd0, 0x78, 0x73, 0xb3, 0xb7, 0x7f, 0xa2, 0xc3, 0x90, 0xcc, 0x83, 0x90,
+  0x78, 0x69, 0xd5, 0xf2, 0xbb, 0x9d, 0x75, 0x4f, 0x1e, 0xe3, 0xb0, 0x7b,
+  0x80, 0xef, 0x62, 0x92, 0x32, 0xae, 0x02, 0xda, 0x92, 0x9c, 0x6b, 0x1b,
+  0x7f, 0x0e, 0xc7, 0x4a, 0xc3, 0x4f, 0x5b, 0x08, 0xd2, 0xac, 0x22, 0x7b,
+  0xa5, 0x10, 0x90, 0xa9, 0x55, 0x2b, 0x86, 0xfc, 0x3f, 0xc4, 0xf9, 0x5f,
+  0x7f, 0xde, 0x72, 0xbf, 0x9f, 0xda, 0x00, 0x74, 0xb1, 0x32, 0x92, 0xcc,
+  0x4a, 0x1c, 0x84, 0x10, 0xe7, 0x40, 0xa3, 0x2c, 0x03, 0x7a, 0x00, 0xb0,
+  0x2e, 0xa1, 0x69, 0x3a, 0x69, 0x6a, 0x52, 0x02, 0x42, 0x9e, 0xda, 0x67,
+  0xf2, 0xe2, 0x11, 0x3d, 0x27, 0x65, 0x21, 0x70, 0x61, 0x92, 0xfe, 0x33,
+  0xc3, 0x9f, 0x87, 0x86, 0xef, 0x12, 0x35, 0xc8, 0x6b, 0x21, 0xde, 0x72,
+  0xb4, 0xe4, 0xff, 0x87, 0x52, 0x2a, 0xa4, 0x83, 0x99, 0xd4, 0x6c, 0x5f,
+  0xac, 0x67, 0xb5, 0x27, 0x2e, 0xed, 0x58, 0x08, 0x00, 0xaf, 0xc0, 0x6b,
+  0x8a, 0xd7, 0xb7, 0x81, 0xbc, 0x5b, 0x4a, 0x27, 0xce, 0x15, 0x70, 0xac,
+  0x9f, 0xf2, 0xba, 0x39, 0xd4, 0x9d, 0xe7, 0xb8, 0xc4, 0xd9, 0x37, 0x5e,
+  0x9b, 0xaa, 0xf0, 0xf6, 0x51, 0x9b, 0x50, 0xf1, 0xb7, 0x27, 0xbd, 0xa7,
+  0x75, 0x9f, 0x92, 0x10, 0x3c, 0xa3, 0x7c, 0x38, 0x2e, 0x5f, 0x99, 0xfc,
+  0xbd, 0x3f, 0x03, 0x5a, 0xcd, 0xd7, 0xfe, 0xc0, 0x3e, 0x36, 0x8d, 0x73,
+  0xdc, 0xf6, 0x82, 0x0d, 0x72, 0x42, 0xb4, 0xd3, 0x38, 0xba, 0xa9, 0x16,
+  0x0c, 0x8c, 0xaf, 0x95, 0x02, 0xbb, 0xe5, 0x54, 0x7b, 0xdc, 0x5d, 0xc9,
+  0xd4, 0xdd, 0x12, 0xd6, 0xba, 0x89, 0x6c, 0xb5, 0xfb, 0x6f, 0x9c, 0xab,
+  0x38, 0x7e, 0xda, 0x54, 0x1d, 0xbc, 0x67, 0xeb, 0xf2, 0xfd, 0xad, 0x44,
+  0xd2, 0x9a, 0x86, 0x6a, 0x0c, 0x36, 0x00, 0xcd, 0x18, 0xee, 0x90, 0x5e,
+  0x05, 0x32, 0x0c, 0x9b, 0x35, 0x78, 0x85, 0x62, 0x22, 0x65, 0x06, 0x17,
+  0x04, 0xf0, 0x89, 0x79, 0xd3, 0x41, 0x9b, 0xc7, 0x9f, 0xbd, 0x2b, 0x67,
+  0x75, 0x7f, 0x06, 0xf9, 0xa5, 0x6d, 0x9c, 0xff, 0x07, 0xc3, 0xe7, 0x7f,
+  0x1b, 0xf3, 0x2d, 0x2f, 0xa7, 0x00, 0xe0, 0x21, 0x1a, 0x93, 0xa5, 0x21,
+  0x90, 0x85, 0x22, 0xa2, 0x58, 0x50, 0x41, 0x09, 0xac, 0xcd, 0x64, 0x54,
+  0x02, 0xb1, 0x7b, 0x0b, 0x50, 0x52, 0xc8, 0x9f, 0xb0, 0x98, 0x3f, 0xd7,
+  0xe3, 0x79, 0x76, 0xd1, 0x9b, 0xde, 0x98, 0x38, 0x60, 0x7b, 0xa8, 0xf1,
+  0x09, 0x11, 0x36, 0x8a, 0x4a, 0xe2, 0xb3, 0xa5, 0x29, 0x75, 0x66, 0x93,
+  0xc1, 0xa4, 0xcd, 0x6d, 0x0c, 0xd9, 0x02, 0x35, 0x43, 0xf5, 0x61, 0xb6,
+  0xa4, 0x76, 0x29, 0x06, 0x71, 0x70, 0x8f, 0xbf, 0xe8, 0x70, 0xc9, 0x95,
+  0x9e, 0xfc, 0xf8, 0xc2, 0x13, 0xe3, 0x49, 0x95, 0x61, 0x1b, 0x79, 0x24,
+  0xe0, 0x58, 0x80, 0x8a, 0x80, 0xd1, 0x59, 0xa7, 0x91, 0x02, 0x11, 0xd3,
+  0x5d, 0x2a, 0x80, 0xaf, 0xdf, 0x90, 0xe8, 0xe4, 0xbc, 0x47, 0xbd, 0x28,
+  0x82, 0x02, 0xd4, 0xbd, 0xce, 0xad, 0x08, 0xf0, 0x0b, 0x4f, 0xdc, 0x39,
+  0x50, 0x15, 0xb7, 0x6a, 0xe5, 0x4f, 0x94, 0x7e, 0x7a, 0x41, 0xd9, 0xe2,
+  0x1d, 0x2b, 0xd7, 0x80, 0xcf, 0x8a, 0x28, 0xbd, 0x6c, 0x97, 0xc8, 0xe3,
+  0x56, 0x7e, 0xab, 0xb6, 0x09, 0xd7, 0xb6, 0x9b, 0xe9, 0xcc, 0x59, 0x73,
+  0x95, 0x5e, 0xa4, 0x2d, 0xea, 0x70, 0x19, 0xdd, 0x66, 0x87, 0xa0, 0xab,
+  0x1a, 0xd1, 0x39, 0x70, 0x26, 0xb7, 0x3a, 0x27, 0x87, 0x70, 0x3b, 0x77,
+  0x47, 0xca, 0x8e, 0x38, 0xb8, 0x95, 0xc7, 0xb6, 0x9b, 0x8a, 0x26, 0x68,
+  0x8f, 0xbb, 0xdf, 0x19, 0x18, 0xc8, 0x77, 0xca, 0x94, 0x2c, 0x94, 0x6e,
+  0xa5, 0x38, 0xde, 0xd6, 0x6f, 0x75, 0x5b, 0x59, 0xbb, 0xd8, 0xf5, 0x69,
+  0x54, 0xd0, 0xd8, 0xc7, 0x57, 0x8b, 0xb1, 0xe7, 0x67, 0xbd, 0xf9, 0x03,
+  0xba, 0x60, 0x8a, 0x87, 0x82, 0xb8, 0x4e, 0x00, 0x29, 0x50, 0x01, 0x58,
+  0x20, 0x94, 0x90, 0x50, 0x5f, 0xe7, 0xfa, 0x2f, 0xeb, 0xdf, 0x51, 0x07,
+  0xfe, 0xb7, 0xd7, 0x73, 0x91, 0x1e, 0x8f, 0xa6, 0x3f, 0xb8, 0xe9, 0xa5,
+  0x31, 0x1f, 0x0f, 0xc1, 0x1c, 0xf2, 0x6f, 0xf6, 0x28, 0xb5, 0x8c, 0x9c,
+  0x80, 0x3a, 0x1e, 0x87, 0xf6, 0x7e, 0x21, 0x75, 0x80, 0x43, 0xb4, 0x28,
+  0xfc, 0x07, 0x8f, 0x10, 0x02, 0x00, 0x45, 0x6d, 0xcd, 0x7e, 0x2b, 0xad,
+  0xcf, 0xb1, 0x95, 0xdd, 0xe5, 0xb3, 0x7a, 0x4b, 0xff, 0xcc, 0xa7, 0xaa,
+  0x51, 0x4a, 0xab, 0x9b, 0x1b, 0x3c, 0x6b, 0xa5, 0x58, 0xb0, 0xad, 0x2b,
+  0x62, 0x6d, 0x7e, 0x98, 0x42, 0x1a, 0x84, 0xcf, 0xf4, 0x71, 0x55, 0x89,
+  0x48, 0xab, 0xea, 0x00, 0x00, 0xa2, 0x10, 0x6a, 0x8d, 0xe8, 0xed, 0x39,
+  0x70, 0x66, 0xd4, 0x1b, 0xcd, 0x77, 0x30, 0x3f, 0x9c, 0x75, 0x7f, 0xd6,
+  0xfb, 0x66, 0x28, 0x16, 0xbf, 0x1e, 0x8a, 0x2b, 0x44, 0x48, 0x57, 0xa1,
+  0x67, 0xbf, 0x80, 0x77, 0xd7, 0x1c, 0x63, 0x9d, 0x61, 0x30, 0x86, 0x9d,
+  0x18, 0x5f, 0x1c, 0xf2, 0xc2, 0xfd, 0x34, 0xa1, 0x8d, 0x1a, 0xfd, 0x56,
+  0x14, 0x63, 0x82, 0xa1, 0xed, 0x5c, 0xd9, 0x45, 0x05, 0x86, 0xca, 0x81,
+  0x1c, 0x9c, 0x8d, 0x1d, 0x67, 0xbd, 0x51, 0xa0, 0xa7, 0x64, 0x0d, 0xf9,
+  0x44, 0x6d, 0xa8, 0x62, 0x22, 0x37, 0x52, 0xd2, 0xd6, 0x33, 0xd2, 0xc5,
+  0xd2, 0xb7, 0x33, 0x7a, 0x76, 0x36, 0xee, 0x37, 0x63, 0x9f, 0x33, 0x1f,
+  0x2e, 0xaf, 0xc6, 0xeb, 0xf7, 0x76, 0x5e, 0x1f, 0x2f, 0x9b, 0xcc, 0x01,
+  0xc0, 0x21, 0x1a, 0x93, 0x95, 0x15, 0x94, 0x8d, 0x22, 0x21, 0x60, 0x82,
+  0x14, 0x6f, 0x5b, 0x8d, 0xc5, 0xd3, 0x76, 0xa5, 0x00, 0x02, 0x11, 0x51,
+  0xf6, 0x1a, 0x05, 0x0a, 0x96, 0xb8, 0xfb, 0x3b, 0xf7, 0x3c, 0xf9, 0xb3,
+  0xc7, 0x4f, 0xbe, 0x9c, 0xb4, 0x2d, 0xbf, 0x3e, 0x35, 0xc4, 0x0e, 0x54,
+  0x68, 0xb0, 0x64, 0xc6, 0xa9, 0xcd, 0x0e, 0xda, 0x09, 0x50, 0x53, 0xe6,
+  0x67, 0xcb, 0x46, 0xbe, 0x2d, 0x48, 0x2a, 0x06, 0xb1, 0x1f, 0x64, 0x45,
+  0x25, 0x22, 0x8e, 0x29, 0xcd, 0x60, 0x7a, 0x8c, 0xb4, 0xfa, 0xe5, 0x55,
+  0x82, 0x99, 0x37, 0xb1, 0xc2, 0x2b, 0xb9, 0x42, 0x57, 0xde, 0x8b, 0xde,
+  0x1d, 0x66, 0x5d, 0xf5, 0xe7, 0x91, 0x78, 0x63, 0x31, 0x3f, 0x7a, 0x2f,
+  0xf5, 0xbd, 0x56, 0xf8, 0xf6, 0x99, 0xbf, 0x5a, 0xf0, 0x15, 0xb6, 0xbc,
+  0x47, 0xc9, 0xce, 0x84, 0x65, 0x57, 0x57, 0x7a, 0x94, 0x64, 0x3b, 0x31,
+  0x5d, 0xd5, 0x81, 0x9f, 0x87, 0xf2, 0x79, 0x7d, 0x3e, 0x79, 0x85, 0x84,
+  0x93, 0xd1, 0x2f, 0xc1, 0xd1, 0xfb, 0x0e, 0x8c, 0x0c, 0xdd, 0x91, 0x57,
+  0xf8, 0x8e, 0x8d, 0xab, 0xf4, 0x5d, 0x03, 0xa3, 0x77, 0x39, 0xb6, 0xd6,
+  0xe8, 0x86, 0x43, 0x18, 0xf0, 0xad, 0x50, 0x01, 0x97, 0xa2, 0xde, 0xc8,
+  0x98, 0x0a, 0x8b, 0x6d, 0x47, 0x12, 0x92, 0xe2, 0x8e, 0xc1, 0xcb, 0x6b,
+  0x8f, 0x05, 0x3a, 0x88, 0xb2, 0xe8, 0x4f, 0x6a, 0xd9, 0x20, 0xf7, 0xee,
+  0x3e, 0x15, 0x6b, 0xa3, 0xbd, 0x8d, 0xbf, 0x14, 0x82, 0x8d, 0xa6, 0xc6,
+  0xe0, 0xbe, 0x53, 0x1a, 0x3d, 0xfc, 0x9f, 0x67, 0x8a, 0x39, 0x01, 0xc9,
+  0x8a, 0x91, 0x23, 0x22, 0x18, 0x50, 0x37, 0x0b, 0x22, 0xb2, 0x5d, 0x29,
+  0x56, 0x14, 0x2a, 0x80, 0x10, 0x42, 0x50, 0xc7, 0xf2, 0x4e, 0x5b, 0xe9,
+  0xcc, 0xab, 0xc3, 0x9a, 0xe9, 0xee, 0x0b, 0x93, 0x59, 0xc5, 0xd8, 0x4d,
+  0x72, 0xdd, 0x83, 0xb3, 0x0b, 0xd7, 0xdb, 0x9d, 0x1a, 0x75, 0x6c, 0xfc,
+  0x39, 0x78, 0x8c, 0x96, 0x32, 0x68, 0xc1, 0x0a, 0x00, 0x21, 0x72, 0x16,
+  0x04, 0x7b, 0xf6, 0x55, 0x46, 0x85, 0x78, 0x06, 0xd4, 0x83, 0x51, 0xe3,
+  0xa4, 0xdb, 0x50, 0x96, 0x3e, 0x16, 0x0c, 0x17, 0xe0, 0x94, 0xdd, 0x68,
+  0xe1, 0xf8, 0xe1, 0x87, 0x8f, 0x22, 0xb3, 0x65, 0x57, 0xa9, 0x0a, 0x22,
+  0x5c, 0x64, 0xc9, 0xa3, 0xc9, 0x6b, 0xb5, 0x61, 0x31, 0xb8, 0xf0, 0x6a,
+  0x2a, 0xbd, 0x13, 0x2f, 0xe7, 0xdd, 0x18, 0x0c, 0x6a, 0x9f, 0x71, 0x79,
+  0x00, 0x11, 0x56, 0x31, 0x0d, 0xee, 0xb6, 0x34, 0xd5, 0x81, 0xe3, 0xe8,
+  0x5b, 0xd8, 0x20, 0x1b, 0x3d, 0xe6, 0x53, 0x1a, 0xa2, 0xb3, 0x49, 0x65,
+  0x35, 0x95, 0x8f, 0x64, 0xc1, 0x72, 0xee, 0x9d, 0xff, 0x3a, 0x2d, 0xdf,
+  0xb7, 0x17, 0xeb, 0xdf, 0x85, 0x0e, 0x75, 0x7b, 0x12, 0xe5, 0xe0, 0x9f,
+  0x11, 0xa3, 0x16, 0x7e, 0x9f, 0x1d, 0x72, 0x47, 0x3c, 0xae, 0x06, 0x40,
+  0x81, 0x63, 0x85, 0x04, 0x0d, 0x1e, 0x4b, 0x7d, 0x3e, 0xa6, 0x9a, 0xc6,
+  0x45, 0x5f, 0x93, 0xde, 0xf7, 0x0b, 0xc3, 0xaf, 0xd1, 0x78, 0x7e, 0xe4,
+  0xab, 0xea, 0xf8, 0x11, 0xe1, 0x76, 0xda, 0xde, 0xd0, 0x07, 0x21, 0x1a,
+  0x88, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xed, 0x65, 0xa3, 0x41, 0x49, 0xe8,
+  0x68, 0x23, 0x85, 0x2a, 0xcc, 0xde, 0xa4, 0x0a, 0xd8, 0x02, 0x00, 0x12,
+  0x50, 0x30, 0xff, 0x46, 0x8c, 0x66, 0xd8, 0xeb, 0xe2, 0x27, 0xd1, 0x59,
+  0x7d, 0xd7, 0xc6, 0x1d, 0x26, 0x43, 0x34, 0xca, 0xf0, 0x0a, 0xed, 0x71,
+  0xbe, 0x82, 0x03, 0x18, 0xe2, 0x88, 0xb4, 0xd3, 0x2c, 0x68, 0x1e, 0x2b,
+  0xd4, 0xc6, 0xe7, 0xb5, 0x65, 0x00, 0x65, 0xbc, 0xb5, 0x87, 0xe5, 0xf1,
+  0x16, 0x70, 0xf4, 0x25, 0xf3, 0x3c, 0x46, 0x72, 0x4e, 0x0b, 0x73, 0x10,
+  0x20, 0x16, 0xc7, 0x7d, 0xbe, 0x98, 0x7b, 0x1b, 0xa5, 0x25, 0x7a, 0xfa,
+  0x77, 0xe4, 0x87, 0x20, 0xe9, 0x4e, 0x48, 0xf1, 0x3b, 0x42, 0xcb, 0x57,
+  0xc1, 0x8b, 0xa4, 0xcc, 0xab, 0xba, 0x7f, 0x5e, 0xfb, 0x81, 0x93, 0xe4,
+  0xa8, 0xb5, 0xb0, 0xcc, 0x4e, 0x5b, 0xa2, 0xd7, 0xb7, 0x38, 0x06, 0x9a,
+  0x64, 0x9d, 0xfa, 0x15, 0x33, 0x1f, 0x46, 0x52, 0xd1, 0x11, 0x0a, 0x02,
+  0xbe, 0x74, 0xad, 0x3a, 0x02, 0x78, 0x05, 0xfa, 0x5c, 0xe4, 0xa7, 0x97,
+  0x4b, 0x26, 0x01, 0x33, 0x09, 0xa0, 0xc8, 0xfe, 0xac, 0xba, 0x8e, 0x5b,
+  0x83, 0x03, 0xa1, 0x46, 0xf8, 0xcc, 0x29, 0xd1, 0xcb, 0xb0, 0x86, 0xd0,
+  0xb8, 0x5f, 0x46, 0xef, 0xa1, 0x41, 0x8d, 0xab, 0x56, 0x82, 0x46, 0x2a,
+  0xa1, 0x44, 0x44, 0x0b, 0x7a, 0x16, 0x50, 0x7f, 0x50, 0xfb, 0x33, 0x84,
+  0xfb, 0xee, 0x9e, 0x8c, 0xf6, 0x49, 0xf1, 0x56, 0x4e, 0x95, 0x85, 0x82,
+  0x7e, 0x7e, 0x3f, 0x99, 0xe8, 0xfd, 0x2f, 0x57, 0x5c, 0xc0, 0x0f, 0x3e,
+  0xb6, 0x1a, 0x3c, 0x8a, 0x83, 0x61, 0x40, 0x8c, 0x3b, 0xba, 0xa9, 0x4a,
+  0x92, 0xba, 0xc8, 0x0d, 0xc0, 0x00, 0x15, 0x68, 0xe4, 0x39, 0x27, 0x27,
+  0x44, 0xa8, 0xa0, 0x2a, 0x36, 0xaa, 0x39, 0x1f, 0xb7, 0xac, 0x52, 0x03,
+  0x40, 0x13, 0x63, 0x1e, 0x2d, 0x45, 0x82, 0x7a, 0x26, 0x8b, 0x9a, 0x08,
+  0xa5, 0x7b, 0xb6, 0x39, 0x4e, 0x96, 0x56, 0xa8, 0x65, 0x13, 0xf7, 0xc5,
+  0xf4, 0x4a, 0x38, 0xad, 0x4d, 0x24, 0x9d, 0x6f, 0x73, 0x23, 0x61, 0x74,
+  0xde, 0x0b, 0x2f, 0x5c, 0xb3, 0x3b, 0x36, 0xf6, 0xda, 0x9b, 0xf3, 0xe9,
+  0xf8, 0xad, 0xce, 0x4e, 0xc5, 0xc9, 0x63, 0xec, 0xd1, 0xd2, 0xdb, 0xf1,
+  0xc2, 0xe6, 0x14, 0x9d, 0x3d, 0xda, 0x78, 0x5a, 0x19, 0x6a, 0xe4, 0xed,
+  0x69, 0xf5, 0x5d, 0x1f, 0x56, 0xbe, 0x7c, 0x91, 0x28, 0xde, 0x0f, 0x54,
+  0xf7, 0xd0, 0x6a, 0x1a, 0x11, 0x02, 0x06, 0xe8, 0x15, 0x8e, 0x23, 0x4f,
+  0xc5, 0x33, 0x58, 0x6c, 0xa3, 0x21, 0x82, 0x87, 0xc1, 0xc3, 0x2f, 0x1b,
+  0x13, 0x3d, 0x86, 0x2d, 0xec, 0xe2, 0x37, 0x65, 0xe9, 0x2d, 0x93, 0xdc,
+  0x5d, 0x3b, 0x7b, 0x9a, 0xf6, 0x98, 0xc4, 0x22, 0x9d, 0x24, 0x10, 0x99,
+  0x93, 0x0d, 0x5a, 0x51, 0xf7, 0x97, 0xb1, 0x62, 0xa5, 0x8a, 0x92, 0x50,
+  0xb7, 0xf7, 0xaf, 0x1e, 0x5f, 0xdb, 0xbf, 0xb4, 0xfc, 0xc8, 0x70, 0x21,
+  0x1a, 0x88, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xf3, 0x65, 0xa5, 0xa0, 0x88,
+  0xea, 0x44, 0x21, 0x09, 0x05, 0x04, 0x10, 0xb3, 0x88, 0x6e, 0x56, 0xa0,
+  0x06, 0xc0, 0x09, 0x42, 0x55, 0xa5, 0x7b, 0x89, 0xb7, 0x8b, 0xe1, 0xd3,
+  0x20, 0x3b, 0x16, 0x0e, 0x93, 0xef, 0x7b, 0xaa, 0xe3, 0xfa, 0x9f, 0xca,
+  0x90, 0xc5, 0x6c, 0x5b, 0x6e, 0x4d, 0x0d, 0xd7, 0x76, 0xa4, 0x69, 0x23,
+  0x92, 0x56, 0x65, 0x4b, 0xe9, 0x6a, 0x0a, 0x36, 0x29, 0x65, 0x87, 0xcf,
+  0xbb, 0x00, 0x06, 0x0c, 0x4f, 0x52, 0xde, 0xf4, 0x4b, 0x67, 0xcb, 0x25,
+  0xfc, 0xcd, 0xae, 0xbb, 0x37, 0x19, 0x90, 0x2b, 0x03, 0x69, 0x6f, 0xb2,
+  0xa1, 0x2c, 0x63, 0x11, 0x2d, 0xef, 0x24, 0x9b, 0x61, 0xca, 0x24, 0x88,
+  0xd2, 0xe4, 0x83, 0x61, 0x62, 0xa6, 0x53, 0x03, 0x75, 0x12, 0xb7, 0x30,
+  0xea, 0x4d, 0x2a, 0xa6, 0x71, 0x67, 0x6a, 0x26, 0x88, 0x6f, 0x48, 0x72,
+  0x4b, 0x25, 0x8a, 0xc8, 0x9d, 0xc5, 0x0c, 0x5d, 0xd5, 0xd2, 0x6f, 0xc8,
+  0x72, 0x96, 0x1c, 0x4f, 0xd6, 0xc9, 0x54, 0x68, 0x2f, 0x99, 0x33, 0x99,
+  0xb0, 0xcb, 0xb2, 0x02, 0x1a, 0xf4, 0x0c, 0xce, 0x88, 0xee, 0x6e, 0xef,
+  0x65, 0xe0, 0x41, 0x02, 0x2c, 0x01, 0x35, 0xa2, 0x62, 0x9e, 0x4c, 0x32,
+  0x24, 0x46, 0x61, 0x3b, 0xd6, 0xf3, 0x8b, 0x89, 0x64, 0x4b, 0xf2, 0xa9,
+  0x00, 0xf3, 0xa9, 0x3d, 0xc6, 0x19, 0x9c, 0x23, 0x4a, 0xdf, 0xc1, 0x55,
+  0x46, 0xd8, 0x9b, 0xd8, 0x2f, 0xdb, 0x46, 0xbb, 0x4a, 0x92, 0x75, 0x40,
+  0xa2, 0x3b, 0x2d, 0xeb, 0x72, 0x17, 0xdf, 0x17, 0xc6, 0x20, 0xf1, 0xeb,
+  0x46, 0x11, 0x11, 0x70, 0x37, 0x0e, 0xd5, 0x01, 0x53, 0x8a, 0x83, 0x65,
+  0x45, 0x00, 0x40, 0x90, 0x04, 0xa7, 0x8d, 0x2f, 0xfb, 0xbf, 0xac, 0xec,
+  0x5a, 0x01, 0x2c, 0xd1, 0xf9, 0x9a, 0x8b, 0x25, 0x4a, 0x3e, 0x7a, 0xba,
+  0x74, 0x73, 0xb0, 0x4f, 0x09, 0xe3, 0xb3, 0xa6, 0x3c, 0x8c, 0x38, 0x4c,
+  0x7d, 0x48, 0xdc, 0x32, 0x05, 0xeb, 0x27, 0xcc, 0xc6, 0x03, 0xcb, 0x84,
+  0x50, 0xf3, 0x75, 0xe0, 0xea, 0x34, 0xd9, 0x41, 0x0b, 0x91, 0x94, 0xd9,
+  0xe7, 0x55, 0xd3, 0x46, 0x29, 0x88, 0x6d, 0x72, 0x56, 0x3d, 0xdc, 0x3a,
+  0x0b, 0x8a, 0x98, 0x45, 0xb5, 0x17, 0x45, 0x0d, 0x73, 0xe5, 0xf5, 0x02,
+  0x91, 0x58, 0x62, 0xd3, 0xc0, 0xd4, 0xe8, 0x5c, 0xf4, 0x2a, 0xe9, 0x89,
+  0xf3, 0x68, 0x95, 0xcb, 0x13, 0xa1, 0xe4, 0xce, 0x78, 0x89, 0x12, 0x47,
+  0xfe, 0xcf, 0xb1, 0x5f, 0xf2, 0x52, 0xf8, 0xde, 0xef, 0xd2, 0x7f, 0x75,
+  0xb9, 0xf0, 0x08, 0x40, 0x34, 0x0e, 0xe4, 0xf1, 0x1a, 0x42, 0x83, 0xbd,
+  0x5e, 0xfc, 0x49, 0x37, 0x11, 0x46, 0x9a, 0x6c, 0x3d, 0xd2, 0x9a, 0x17,
+  0x9a, 0x73, 0x57, 0xb6, 0xf5, 0x53, 0x89, 0x67, 0xc2, 0xb2, 0x6a, 0xf4,
+  0xaf, 0xf0, 0x08, 0xae, 0xd8, 0x6d, 0xac, 0x72, 0xac, 0xef, 0xe2, 0x8b,
+  0xf3, 0x79, 0x7c, 0x1f, 0x53, 0xd6, 0xfa, 0xbf, 0x12, 0x00, 0x38, 0x21,
+  0x1a, 0x88, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0xed, 0x6d, 0x61, 0xa1, 0x89,
+  0xac, 0x48, 0x12, 0x84, 0x01, 0x51, 0x95, 0x2a, 0x03, 0x77, 0x00, 0x08,
+  0x24, 0xd8, 0x93, 0xc1, 0x2a, 0x88, 0x91, 0x54, 0x42, 0x28, 0x64, 0xe2,
+  0x10, 0x4c, 0x3a, 0x8e, 0x26, 0x04, 0x1e, 0xe8, 0xb3, 0xc2, 0x3e, 0x0e,
+  0x7e, 0x6d, 0xfd, 0x1d, 0x6b, 0x4c, 0x69, 0xef, 0xfe, 0x46, 0x53, 0x7c,
+  0x3a, 0xd2, 0xc6, 0xd4, 0xb8, 0x38, 0x61, 0x06, 0xa3, 0x5e, 0x7e, 0x0a,
+  0x0b, 0xd1, 0x34, 0x5e, 0x96, 0x8c, 0x28, 0x12, 0x5a, 0xc8, 0x20, 0xa4,
+  0xc6, 0x2b, 0x00, 0x8f, 0x23, 0xb6, 0x06, 0xe7, 0xe3, 0x80, 0x91, 0x88,
+  0xdf, 0x30, 0xa5, 0x8d, 0x9a, 0x55, 0x82, 0xf0, 0x31, 0x8d, 0x47, 0x0b,
+  0x16, 0xbf, 0x45, 0x92, 0x94, 0xc6, 0x98, 0x21, 0xf3, 0xd5, 0x07, 0xd9,
+  0xcc, 0x71, 0xe3, 0x27, 0x5a, 0x5a, 0xb1, 0xf1, 0x81, 0xfc, 0x2a, 0x07,
+  0xfd, 0x45, 0xf8, 0x65, 0x39, 0x8e, 0x88, 0x54, 0xff, 0x7d, 0x74, 0x45,
+  0x0f, 0x8b, 0x35, 0x21, 0xf4, 0x59, 0xed, 0xfb, 0xa6, 0x76, 0x7c, 0x8d,
+  0x95, 0x14, 0xe9, 0x90, 0x8a, 0xf3, 0x68, 0x27, 0x80, 0x35, 0x30, 0xa2,
+  0x4c, 0x8c, 0x1a, 0x10, 0xea, 0xc8, 0x8c, 0xc8, 0xe5, 0xb6, 0x22, 0x1e,
+  0xe6, 0xb1, 0x4b, 0x10, 0x9c, 0xa4, 0xdf, 0xcc, 0x03, 0xe0, 0xd1, 0x3e,
+  0xfb, 0x65, 0x3d, 0x0d, 0x20, 0x78, 0x95, 0x2e, 0x8c, 0x83, 0x32, 0xef,
+  0xcd, 0x83, 0x09, 0x14, 0x22, 0x97, 0x8d, 0x4b, 0x21, 0x1d, 0x6e, 0x8e,
+  0xf3, 0x35, 0x13, 0xa1, 0x46, 0x95, 0x86, 0x7f, 0x7f, 0x87, 0x1f, 0x4e,
+  0x73, 0x00, 0x0f, 0x3e, 0xc5, 0x29, 0x45, 0x06, 0xc1, 0x81, 0xb8, 0x76,
+  0x00, 0xa4, 0x54, 0x00, 0x01, 0x00, 0x58, 0x36, 0x74, 0x34, 0xd6, 0xb4,
+  0xa2, 0x28, 0x1f, 0x4c, 0xdd, 0x72, 0xce, 0xae, 0xb0, 0x74, 0x76, 0xec,
+  0x6b, 0x50, 0xef, 0xa5, 0x99, 0x11, 0x64, 0x3e, 0x4f, 0xae, 0x77, 0x7b,
+  0xfd, 0xf1, 0xbe, 0x9e, 0xa6, 0x68, 0x4f, 0xb4, 0x4a, 0x2c, 0x3b, 0xcf,
+  0x0d, 0xd8, 0xa8, 0xe2, 0x88, 0x83, 0x14, 0x4b, 0x30, 0xc6, 0x97, 0x7b,
+  0x62, 0xb8, 0x03, 0x21, 0x58, 0x5d, 0x73, 0x8b, 0x71, 0x01, 0xb5, 0x76,
+  0x23, 0xe6, 0xbc, 0x75, 0xaf, 0xa1, 0xce, 0x37, 0xea, 0xbd, 0xe1, 0x4c,
+  0xf5, 0x42, 0x0d, 0x71, 0x5b, 0xc2, 0xc6, 0x3d, 0xd9, 0xc5, 0x1a, 0x93,
+  0x73, 0xfd, 0x9f, 0xd8, 0x33, 0xe2, 0x25, 0x10, 0x7b, 0xb4, 0xbd, 0x60,
+  0xf7, 0x19, 0x31, 0xca, 0x86, 0x97, 0x71, 0xaa, 0x6b, 0x89, 0x45, 0x85,
+  0x96, 0xd5, 0xed, 0x41, 0x30, 0x80, 0xa2, 0x42, 0x88, 0xbb, 0xc9, 0xd5,
+  0xed, 0xcb, 0x48, 0x64, 0x60, 0x4e, 0xa6, 0xfd, 0xa3, 0xf2, 0xf6, 0x13,
+  0x74, 0x8d, 0xe7, 0x41, 0x51, 0x8f, 0x75, 0x8d, 0xaf, 0xd9, 0x16, 0xb1,
+  0xa7, 0x57, 0xc0, 0xfa, 0xb9, 0xf0, 0xfc, 0xfe, 0xeb, 0x8d, 0xb4, 0x03,
+  0x07, 0x21, 0x1a, 0x8c, 0x00, 0x01, 0xff, 0xff, 0xfe, 0xed, 0x6f, 0x62,
+  0x8a, 0x10, 0x84, 0x34, 0x14, 0x11, 0x42, 0x62, 0xaa, 0xf3, 0x81, 0x88,
+  0x28, 0x50, 0x20, 0x04, 0x91, 0x83, 0x32, 0x31, 0x11, 0x30, 0x28, 0x78,
+  0xda, 0x4b, 0xfa, 0xb6, 0x71, 0x89, 0xa8, 0x1e, 0x93, 0x61, 0xcd, 0x9c,
+  0x53, 0x72, 0x73, 0x79, 0xf6, 0x1f, 0x24, 0x58, 0xf3, 0x5b, 0x65, 0xa7,
+  0x9b, 0x23, 0xc8, 0x72, 0xb9, 0x8e, 0x88, 0x11, 0x65, 0x47, 0xa7, 0x8f,
+  0x88, 0x68, 0xf9, 0x15, 0xc4, 0x95, 0x26, 0xcd, 0x0d, 0xa8, 0x5f, 0x16,
+  0xd8, 0xec, 0xc6, 0xa7, 0x38, 0x0b, 0x0c, 0x0b, 0x23, 0x0a, 0x9b, 0xa2,
+  0xcf, 0xc7, 0x0d, 0x3d, 0x37, 0x8f, 0x7a, 0x7d, 0x57, 0xd5, 0x59, 0x36,
+  0x62, 0x84, 0xba, 0xde, 0xf2, 0x64, 0x77, 0xe7, 0xa6, 0x95, 0x4d, 0x73,
+  0x3c, 0x07, 0x9a, 0xb9, 0xe4, 0x66, 0x21, 0xc1, 0x1e, 0x71, 0x13, 0x60,
+  0x7b, 0x24, 0xad, 0x4b, 0x61, 0x47, 0x40, 0xf4, 0xea, 0xf2, 0xc6, 0xcd,
+  0x05, 0x5c, 0x42, 0x9e, 0x6e, 0xbe, 0x1a, 0x4b, 0xab, 0x90, 0xb5, 0x29,
+  0x87, 0x51, 0x9e, 0x69, 0x77, 0xed, 0x68, 0x32, 0xb6, 0xbe, 0xa3, 0x93,
+  0x9a, 0x67, 0xc2, 0xd3, 0xc7, 0x17, 0x84, 0xf0, 0x61, 0x88, 0x74, 0xd6,
+  0x51, 0x90, 0x5b, 0x40, 0x84, 0x36, 0x67, 0x40, 0xa4, 0xcf, 0x6e, 0xdd,
+  0x36, 0x5b, 0xa8, 0xde, 0xa4, 0x5c, 0xfb, 0xcf, 0xf7, 0xe5, 0x26, 0x84,
+  0x5d, 0x46, 0xba, 0x64, 0x8d, 0x83, 0x00, 0xa9, 0xba, 0xd2, 0xd8, 0xbc,
+  0x8d, 0xc6, 0xbc, 0xdd, 0xad, 0x59, 0xfb, 0x52, 0x7f, 0xed, 0x21, 0xcd,
+  0xdb, 0xb1, 0xd9, 0xfc, 0xfd, 0x3d, 0x78, 0xf9, 0x7b, 0x78, 0x00, 0x3b,
+  0xb0, 0x7e, 0x25, 0x14, 0x14, 0x11, 0x42, 0xe6, 0x29, 0x25, 0x54, 0xab,
+  0xaa, 0x58, 0x30, 0x08, 0xa1, 0x11, 0x14, 0x29, 0xbd, 0xe3, 0x7a, 0x5a,
+  0x13, 0x99, 0xaf, 0x0e, 0xc7, 0x3a, 0x69, 0x40, 0x65, 0x02, 0xb3, 0x41,
+  0xda, 0xbf, 0x51, 0xb9, 0x27, 0xd0, 0xc0, 0x30, 0x67, 0x30, 0x38, 0xc8,
+  0x0f, 0x0a, 0x04, 0x3c, 0x95, 0x0f, 0x91, 0x96, 0x28, 0x7e, 0x5f, 0x54,
+  0x49, 0x13, 0x20, 0xd3, 0xd0, 0x48, 0xbb, 0xae, 0x12, 0x02, 0x95, 0xa1,
+  0xc1, 0x5a, 0x67, 0xd9, 0x4b, 0x79, 0x50, 0x28, 0x53, 0xc9, 0x01, 0x0b,
+  0xae, 0xfb, 0xf0, 0x5d, 0xa1, 0x67, 0xa3, 0xc2, 0x47, 0x36, 0x9f, 0x77,
+  0xa8, 0x42, 0x4a, 0xd4, 0xed, 0xdc, 0x6d, 0x2c, 0x70, 0xc8, 0x19, 0xc2,
+  0x42, 0xde, 0x04, 0xd8, 0x84, 0x11, 0x78, 0xf1, 0xda, 0x9e, 0xba, 0x4e,
+  0x49, 0xcc, 0x89, 0x00, 0xdc, 0x34, 0x8a, 0x10, 0xa6, 0xca, 0x12, 0x05,
+  0x71, 0x58, 0x44, 0x88, 0x53, 0x4f, 0xbf, 0x8e, 0x81, 0xa3, 0x1a, 0x46,
+  0xaa, 0xfd, 0xf1, 0xd9, 0xc8, 0x04, 0x8d, 0x76, 0x69, 0x1f, 0x77, 0xa3,
+  0x9f, 0xbf, 0xf0, 0xf4, 0xe6, 0x40, 0x38, 0x21, 0x1a, 0x88, 0x00, 0x3f,
+  0xff, 0xff, 0xfe, 0xff, 0x6c, 0x81, 0xa1, 0x0a, 0x08, 0x26, 0x14, 0x09,
+  0x42, 0xd0, 0xb6, 0x5a, 0xe6, 0xf4, 0x01, 0x80, 0x40, 0x2a, 0xea, 0xe8,
+  0x2d, 0x8e, 0x2a, 0xfa, 0xae, 0x01, 0x1b, 0x36, 0xc3, 0xed, 0xd6, 0x65,
+  0x40, 0xc2, 0xb9, 0x27, 0x8c, 0xf2, 0x36, 0x49, 0xc3, 0xf5, 0xa6, 0x19,
+  0x7e, 0xb8, 0xf4, 0x85, 0x31, 0x23, 0x9f, 0x7e, 0x2f, 0xaa, 0xe1, 0xe1,
+  0x07, 0x40, 0x52, 0xd1, 0x28, 0xc8, 0x07, 0xfe, 0xc6, 0x5c, 0x7f, 0x34,
+  0x70, 0xba, 0x74, 0xec, 0x87, 0xe1, 0x89, 0x74, 0x09, 0x8f, 0xe8, 0x7e,
+  0xfa, 0xfc, 0x4d, 0xfc, 0x66, 0x02, 0xf6, 0xb2, 0x62, 0x86, 0x38, 0xc9,
+  0x8c, 0x03, 0x23, 0x02, 0x48, 0x04, 0x12, 0x56, 0x12, 0x74, 0x20, 0xd9,
+  0x0e, 0xb3, 0xbd, 0x6a, 0x29, 0x08, 0xf1, 0xf6, 0xc8, 0x9a, 0x28, 0xfc,
+  0xde, 0x14, 0x60, 0xbe, 0x66, 0x39, 0x64, 0x6a, 0x38, 0xdd, 0xd1, 0x1e,
+  0xba, 0xd7, 0x6a, 0xf1, 0x7a, 0xa9, 0x5f, 0xb3, 0x6f, 0x34, 0x2a, 0x2f,
+  0x27, 0x75, 0xf0, 0xee, 0x69, 0x2c, 0xc8, 0xfb, 0xd2, 0x1a, 0xf1, 0x7e,
+  0xda, 0xf5, 0xeb, 0x30, 0xe3, 0xf9, 0xcc, 0x13, 0x8a, 0xb5, 0xcb, 0x9d,
+  0x4c, 0x90, 0x2e, 0x31, 0xb2, 0x61, 0x2a, 0x3d, 0xdd, 0x9c, 0xfb, 0xeb,
+  0xc6, 0x81, 0xa1, 0xa9, 0x92, 0xeb, 0x6c, 0x8c, 0xa9, 0x6c, 0xce, 0xb9,
+  0x2b, 0x02, 0x14, 0x43, 0x86, 0x22, 0x28, 0x14, 0x9c, 0x49, 0x79, 0x72,
+  0x9e, 0xb2, 0x91, 0xa0, 0x4a, 0x64, 0x9d, 0xba, 0x25, 0xd6, 0x7a, 0xbd,
+  0x1f, 0x97, 0xcf, 0xe1, 0xc8, 0x01, 0xe3, 0xda, 0xa6, 0x28, 0xa0, 0xa0,
+  0x6e, 0x1d, 0x80, 0x4a, 0x88, 0x28, 0x00, 0x00, 0x44, 0x60, 0x56, 0x9e,
+  0xee, 0xc5, 0x55, 0xcd, 0x29, 0x82, 0x55, 0x78, 0xed, 0xd5, 0xb3, 0x29,
+  0x09, 0x3a, 0xd7, 0x0c, 0x06, 0x72, 0x15, 0x0f, 0x9e, 0x08, 0xbc, 0xe7,
+  0xb5, 0xd3, 0x46, 0x84, 0x42, 0x73, 0xa2, 0xda, 0x31, 0xa9, 0x27, 0x6f,
+  0x4b, 0xf6, 0xb3, 0xac, 0xc3, 0x9e, 0xb4, 0xd5, 0xf8, 0xbb, 0x9f, 0xbd,
+  0x91, 0x22, 0xb5, 0xfd, 0xba, 0x91, 0xc1, 0x6e, 0xb0, 0xd5, 0x70, 0x38,
+  0x62, 0x3b, 0x06, 0x20, 0xdc, 0x62, 0xcd, 0x1f, 0x67, 0xd9, 0xf1, 0xf2,
+  0xfa, 0x00, 0xb2, 0x31, 0x02, 0x1f, 0x3e, 0xdf, 0x97, 0x25, 0xa6, 0xe1,
+  0x51, 0xba, 0x37, 0x4c, 0x12, 0x1d, 0x4c, 0x3a, 0xbe, 0x41, 0xc4, 0x3b,
+  0x24, 0x9f, 0x5f, 0xf9, 0xaa, 0x7b, 0xdd, 0x5c, 0xa8, 0x46, 0x77, 0xa1,
+  0x4a, 0xf4, 0x24, 0xd1, 0xac, 0x46, 0x4c, 0xdb, 0xeb, 0x82, 0x98, 0x33,
+  0x33, 0x8d, 0x62, 0x40, 0x98, 0xc1, 0x3a, 0xe3, 0x11, 0xac, 0x2e, 0x97,
+  0x6f, 0x6d, 0x91, 0xc6, 0xc8, 0x62, 0x97, 0x19, 0x86, 0xdd, 0x7b, 0x8d,
+  0xaf, 0xb3, 0xdf, 0xf0, 0xf8, 0x1d, 0x48, 0x03, 0x07, 0x21, 0x1a, 0x88,
+  0x00, 0x00, 0xff, 0xff, 0xfe, 0xf1, 0x6a, 0xa3, 0xa1, 0xc0, 0x24, 0x84,
+  0x23, 0x06, 0x06, 0xa1, 0x00, 0x10, 0x18, 0x00, 0x10, 0x12, 0x54, 0xd8,
+  0xc0, 0xc5, 0xf2, 0xa4, 0x8a, 0x79, 0x40, 0x84, 0x63, 0xb8, 0x8a, 0x1b,
+  0x84, 0x11, 0x31, 0x67, 0x78, 0x24, 0x8a, 0x0c, 0xaa, 0x2c, 0x86, 0x2b,
+  0x70, 0x14, 0xb5, 0xe5, 0xb9, 0xb0, 0x9b, 0x2a, 0x4f, 0x16, 0x8d, 0x8f,
+  0x80, 0xa8, 0xe3, 0x0d, 0x3c, 0xaf, 0x67, 0x0f, 0xaa, 0xe4, 0x92, 0x24,
+  0x28, 0xfc, 0x0f, 0x3b, 0x2c, 0x77, 0x55, 0x73, 0x21, 0x8b, 0x2d, 0x07,
+  0xc2, 0x02, 0xa9, 0x7e, 0x47, 0xec, 0xb8, 0x25, 0xc8, 0x20, 0x8d, 0xb1,
+  0x22, 0xc2, 0xda, 0x93, 0x4d, 0x3a, 0xca, 0xbd, 0x8c, 0xd3, 0x14, 0xea,
+  0x4c, 0xd3, 0x16, 0x26, 0x5c, 0xa8, 0x41, 0x9b, 0xa5, 0x0c, 0x5b, 0xd6,
+  0x06, 0x2a, 0xda, 0x6b, 0xad, 0x46, 0x5a, 0x44, 0x66, 0x60, 0x40, 0x00,
+  0x3c, 0x41, 0xd5, 0x45, 0xd6, 0x5c, 0x48, 0xf6, 0x5a, 0xc8, 0xa0, 0xa5,
+  0x16, 0x45, 0x96, 0x30, 0x49, 0x10, 0xd3, 0xd3, 0xd4, 0x98, 0x4d, 0xb7,
+  0xa4, 0x89, 0x9a, 0xde, 0xb7, 0xc8, 0x8b, 0x64, 0x0d, 0x59, 0x81, 0x04,
+  0x5e, 0xef, 0x7e, 0x61, 0x14, 0xc2, 0xb5, 0x71, 0xd1, 0x16, 0x54, 0x9a,
+  0x48, 0x97, 0xcb, 0x25, 0xba, 0xba, 0xea, 0xa6, 0x82, 0x45, 0x0e, 0x38,
+  0x62, 0x4c, 0x86, 0x82, 0xed, 0x52, 0x2d, 0x16, 0x15, 0x6b, 0x34, 0x96,
+  0x18, 0xb1, 0x8e, 0x09, 0x58, 0x88, 0x78, 0xa4, 0x9a, 0xd7, 0x2e, 0x3b,
+  0x37, 0x96, 0x85, 0x55, 0xee, 0xee, 0x8e, 0x1c, 0x3e, 0x1f, 0x1f, 0xa2,
+  0x00, 0x1e, 0x7e, 0x65, 0x28, 0x22, 0x87, 0x60, 0x0a, 0x81, 0x57, 0x88,
+  0x50, 0x00, 0x2e, 0x55, 0x05, 0x28, 0x62, 0x3a, 0x0c, 0xc5, 0xad, 0xd3,
+  0x38, 0x67, 0xae, 0x2d, 0xa6, 0x00, 0x31, 0x9e, 0xbc, 0x6a, 0x24, 0x14,
+  0xae, 0xb1, 0x64, 0xef, 0x33, 0x14, 0xa8, 0x0c, 0x29, 0x33, 0x2d, 0x20,
+  0xbe, 0x50, 0x33, 0x6d, 0x67, 0x03, 0xb2, 0x37, 0x42, 0x92, 0x17, 0x49,
+  0x48, 0x4a, 0x52, 0x41, 0xad, 0x4c, 0x9d, 0xb5, 0x79, 0xdc, 0x85, 0x04,
+  0x32, 0x0a, 0x8c, 0xa6, 0x37, 0x32, 0x78, 0x78, 0x11, 0x8f, 0xd4, 0xc1,
+  0x99, 0xf6, 0x59, 0xa0, 0xcd, 0x06, 0xaf, 0x7f, 0xf2, 0x9a, 0xc0, 0x34,
+  0x26, 0x02, 0x6a, 0x69, 0x81, 0x02, 0x40, 0xf3, 0x08, 0x64, 0xa4, 0xf4,
+  0xfb, 0x36, 0x4b, 0x97, 0xe2, 0xa7, 0x81, 0xb9, 0x42, 0x94, 0xca, 0x52,
+  0x5e, 0x5d, 0x07, 0x01, 0x73, 0x5c, 0xde, 0xc1, 0x24, 0xad, 0xe1, 0x45,
+  0x2c, 0x0f, 0xbf, 0x19, 0xc9, 0x1d, 0x12, 0x5a, 0x52, 0x88, 0xbf, 0x57,
+  0x2f, 0x8f, 0x46, 0xbe, 0xf0, 0x07, 0x21, 0x1a, 0x88, 0x00, 0x00, 0xff,
+  0xff, 0xfe, 0xfd, 0x6b, 0xa2, 0x31, 0x05, 0x44, 0x64, 0x13, 0x11, 0x42,
+  0x10, 0xe1, 0x22, 0xa5, 0x2a, 0xa5, 0x00, 0x80, 0x22, 0x25, 0x60, 0xfa,
+  0x12, 0x01, 0x15, 0xf1, 0xe3, 0xbf, 0xb9, 0xc0, 0x85, 0x3f, 0x9f, 0x20,
+  0x8f, 0xf2, 0x67, 0xba, 0xcb, 0xe1, 0x23, 0xfa, 0x6b, 0x37, 0x6b, 0x9c,
+  0x6e, 0x8a, 0xa8, 0x07, 0xa3, 0x37, 0xaf, 0x78, 0x7a, 0x6b, 0x57, 0x17,
+  0xb6, 0x47, 0x74, 0x88, 0x18, 0xe7, 0xf8, 0xd5, 0x06, 0x99, 0xc8, 0xfc,
+  0xfd, 0x33, 0x87, 0x72, 0x6f, 0xb6, 0x51, 0x97, 0xbd, 0x8c, 0xae, 0x30,
+  0x94, 0x34, 0xd1, 0x02, 0x3b, 0xab, 0x3e, 0xee, 0xd3, 0xff, 0xb5, 0x70,
+  0xc9, 0x2c, 0xb6, 0x85, 0x9b, 0x57, 0x91, 0x00, 0x30, 0xd5, 0x8d, 0x86,
+  0x4c, 0xb3, 0x74, 0x8e, 0xc5, 0xf4, 0x56, 0xc6, 0x95, 0x33, 0x4e, 0x1b,
+  0x6c, 0x23, 0xca, 0x22, 0x71, 0x84, 0x0d, 0x06, 0xba, 0x24, 0xf5, 0x5b,
+  0x0c, 0x81, 0x44, 0x1b, 0x55, 0x1d, 0x84, 0x94, 0xb7, 0xe8, 0x3d, 0x21,
+  0xcd, 0xa7, 0xfe, 0x0e, 0xca, 0x58, 0xb0, 0xb3, 0xda, 0xe4, 0xb1, 0xec,
+  0x0c, 0x56, 0x25, 0x9d, 0x2d, 0xbf, 0x7d, 0xc7, 0x00, 0x8b, 0x12, 0x5b,
+  0xd3, 0xf1, 0xc4, 0xb2, 0xb6, 0x85, 0x9f, 0xc3, 0x46, 0xad, 0xdf, 0x49,
+  0xbe, 0xdb, 0xae, 0x9c, 0x8b, 0xc3, 0x0f, 0x36, 0xf7, 0xcb, 0xbb, 0x2a,
+  0x7c, 0x9e, 0xbf, 0xf7, 0xef, 0x8e, 0xc2, 0x68, 0xf6, 0xda, 0x5a, 0x6a,
+  0xc5, 0x11, 0x75, 0x0e, 0x7b, 0xae, 0xf8, 0xf6, 0x61, 0xd5, 0xdd, 0xdf,
+  0xec, 0xfb, 0xeb, 0xa2, 0x40, 0x1e, 0x7e, 0x64, 0xd4, 0x19, 0x8a, 0x08,
+  0xe1, 0xd8, 0x00, 0xa8, 0x88, 0x00, 0x00, 0x2d, 0x01, 0xad, 0x0c, 0x89,
+  0x80, 0x2e, 0x30, 0x8a, 0x00, 0xbc, 0x21, 0x07, 0x0e, 0x05, 0x5e, 0x7b,
+  0xf5, 0x95, 0x69, 0x5f, 0x6b, 0x8c, 0x41, 0x9e, 0x43, 0x80, 0x91, 0x71,
+  0x00, 0x30, 0x70, 0xc8, 0x60, 0x5d, 0x2a, 0x81, 0xe8, 0xc1, 0xb0, 0xed,
+  0x51, 0x1d, 0x73, 0xac, 0x3b, 0xea, 0xa5, 0x83, 0x65, 0x65, 0xf0, 0x6c,
+  0x29, 0xf3, 0xf7, 0x96, 0x89, 0xa7, 0xae, 0xa0, 0xdc, 0x71, 0x53, 0x72,
+  0x3a, 0x1c, 0xeb, 0xb6, 0x50, 0xc2, 0x6b, 0x4b, 0xd3, 0x37, 0x2f, 0xb8,
+  0xc2, 0xc9, 0x44, 0xbe, 0x43, 0xf0, 0x0e, 0xe9, 0x0a, 0xa1, 0x24, 0x42,
+  0xef, 0x24, 0x72, 0xee, 0xb8, 0x8e, 0xa0, 0x0c, 0x65, 0xd0, 0xaa, 0xbc,
+  0x57, 0x1d, 0x79, 0x72, 0x30, 0x35, 0x82, 0xc2, 0x7d, 0x94, 0xbe, 0x1e,
+  0x4d, 0x3b, 0x00, 0x10, 0xcc, 0x8d, 0x91, 0x4c, 0xa0, 0xd4, 0xfd, 0x36,
+  0xc1, 0x76, 0x5c, 0x52, 0x28, 0x39, 0x7c, 0xbf, 0xf2, 0x75, 0x1a, 0x1e,
+  0x26, 0xc0, 0x0e, 0x21, 0x1a, 0x88, 0x00, 0x3f, 0xff, 0xff, 0xfe, 0xfd,
+  0x6c, 0xa2, 0xa2, 0x04, 0xea, 0x66, 0x1a, 0x84, 0x21, 0x67, 0x00, 0xa5,
+  0x00, 0x00, 0x0b, 0x28, 0x77, 0xbf, 0xd9, 0xf9, 0xe7, 0xd0, 0xff, 0xd0,
+  0x48, 0x01, 0x26, 0x40, 0x54, 0x07, 0xc7, 0x3d, 0xe1, 0xdd, 0x7b, 0xf7,
+  0xeb, 0xda, 0xef, 0x87, 0xcf, 0x5b, 0x4b, 0x57, 0xc9, 0xa0, 0xde, 0x1d,
+  0xdb, 0xb8, 0x39, 0x27, 0xff, 0x3a, 0x7f, 0x75, 0xe8, 0x32, 0x80, 0x2a,
+  0xb8, 0xdc, 0x64, 0x83, 0xca, 0x53, 0x4e, 0x7f, 0x3b, 0x7c, 0x61, 0xf1,
+  0x2b, 0x18, 0x60, 0x97, 0x3b, 0x72, 0xb9, 0x37, 0x1c, 0x2d, 0xe9, 0x99,
+  0x6d, 0x95, 0x21, 0x3e, 0xf8, 0xe3, 0x06, 0x77, 0xb1, 0xaf, 0xed, 0xaa,
+  0xd2, 0x05, 0x66, 0x13, 0x59, 0xa9, 0xf0, 0xaa, 0xcd, 0x18, 0xea, 0x9e,
+  0x32, 0xc7, 0xce, 0x7e, 0x95, 0x70, 0xc6, 0xb5, 0xa7, 0xe9, 0x08, 0x57,
+  0xb5, 0xbc, 0xb4, 0x96, 0xf1, 0x2f, 0x1e, 0x38, 0xad, 0xb3, 0x56, 0x37,
+  0x2d, 0xd3, 0x6e, 0x5e, 0x10, 0xce, 0x36, 0xec, 0x82, 0x8d, 0xc1, 0x0d,
+  0xd5, 0xc9, 0xbd, 0xae, 0xe8, 0xa3, 0x0a, 0x24, 0xc4, 0xe5, 0x33, 0x51,
+  0x46, 0xc2, 0xe3, 0x8e, 0xdc, 0xe8, 0x4e, 0x33, 0x1b, 0x2a, 0xf3, 0x55,
+  0xd5, 0x7d, 0xa2, 0xef, 0x57, 0xdd, 0xe1, 0x24, 0x87, 0xe1, 0xe1, 0xa0,
+  0xf9, 0xd9, 0x19, 0xe2, 0xd6, 0x1d, 0xd4, 0x6d, 0xef, 0x0a, 0xf2, 0xbb,
+  0xef, 0xf7, 0xf4, 0xbc, 0xf4, 0x7c, 0x57, 0x8d, 0xed, 0x35, 0x96, 0xfd,
+  0xe7, 0x27, 0xb2, 0x4e, 0x73, 0x72, 0xed, 0xd7, 0xeb, 0x8f, 0x5e, 0x7c,
+  0x79, 0x00, 0x3c, 0xfb, 0x54, 0x62, 0xd2, 0x3a, 0x0a, 0x06, 0xa1, 0xdc,
+  0xa0, 0x54, 0x00, 0x00, 0x00, 0x12, 0x26, 0x0c, 0x56, 0x5e, 0x55, 0xb9,
+  0xbc, 0x64, 0x62, 0x8d, 0x74, 0xc1, 0xa7, 0xa2, 0x39, 0x55, 0x6e, 0xec,
+  0xc3, 0x3b, 0xc7, 0x84, 0x67, 0x75, 0x57, 0xa4, 0x76, 0x93, 0xfc, 0xb3,
+  0x78, 0x61, 0x81, 0xe3, 0xcf, 0xe3, 0x44, 0xdc, 0xdc, 0x6f, 0xb5, 0x9a,
+  0x39, 0xdd, 0xd1, 0x01, 0xea, 0xee, 0xad, 0x15, 0x86, 0x43, 0x30, 0x39,
+  0x0a, 0x52, 0x9c, 0x7d, 0x2c, 0x86, 0xc3, 0xd0, 0xb0, 0x81, 0x4a, 0xd2,
+  0xc5, 0x18, 0xdf, 0x51, 0x52, 0x84, 0x9d, 0xde, 0x15, 0x51, 0x31, 0x54,
+  0x0f, 0x29, 0xfc, 0xdf, 0x0c, 0xe7, 0xd7, 0x48, 0xb4, 0x50, 0xed, 0xcb,
+  0xee, 0xdb, 0xc7, 0x19, 0xc2, 0x64, 0xc1, 0xdc, 0x95, 0x05, 0x1a, 0x2c,
+  0x56, 0xcd, 0x20, 0xf4, 0x0c, 0x5b, 0x54, 0x8f, 0x96, 0x89, 0x9d, 0x5b,
+  0x00, 0x30, 0x8c, 0x17, 0xd0, 0x86, 0xd2, 0x62, 0x76, 0x42, 0x39, 0x76,
+  0x52, 0xda, 0xa2, 0xd7, 0x5b, 0x73, 0x3f, 0x1b, 0xa7, 0xcb, 0x1f, 0x57,
+  0x3e, 0x5d, 0x1c, 0x00, 0x38, 0x21, 0x1a, 0x88, 0x00, 0x03, 0xff, 0xff,
+  0xfe, 0xfd, 0x68, 0xa4, 0x30, 0x90, 0x44, 0xd4, 0x2c, 0x0d, 0xc2, 0x02,
+  0x12, 0x4b, 0xa2, 0x84, 0x00, 0x02, 0x21, 0x43, 0xdb, 0x48, 0xa4, 0xd5,
+  0xbb, 0x89, 0x11, 0x5f, 0xc4, 0xe6, 0x72, 0x48, 0x3f, 0x3d, 0xd4, 0xc5,
+  0xe3, 0x69, 0x94, 0x50, 0xfd, 0x5d, 0xd9, 0x3f, 0x90, 0xa7, 0x7c, 0xad,
+  0x57, 0xe3, 0x5a, 0x5d, 0xa8, 0xea, 0xac, 0x73, 0x69, 0x1d, 0x2e, 0xcf,
+  0x39, 0x4d, 0xab, 0xbf, 0x2b, 0x9e, 0x70, 0x57, 0x9a, 0xd2, 0x0d, 0x7d,
+  0xaa, 0x3f, 0xaf, 0x42, 0x8a, 0xfb, 0x1c, 0xeb, 0xbe, 0x21, 0xf8, 0x11,
+  0x6d, 0xba, 0x38, 0x8c, 0xc3, 0x3a, 0x66, 0x69, 0xf6, 0x5b, 0xea, 0xe8,
+  0xa5, 0x87, 0x8e, 0xde, 0xe2, 0x48, 0x07, 0xe6, 0x4a, 0x07, 0x03, 0xa5,
+  0x85, 0xc5, 0x7c, 0x09, 0x01, 0x8c, 0x40, 0xe9, 0x07, 0x44, 0x97, 0xbc,
+  0x41, 0x11, 0x9d, 0xdf, 0x43, 0xa5, 0x64, 0x01, 0x9c, 0x3f, 0x6f, 0x92,
+  0x56, 0xe7, 0x00, 0x87, 0x16, 0x37, 0x20, 0xa2, 0xb1, 0xe8, 0x4b, 0x77,
+  0xa8, 0x80, 0x30, 0x6a, 0xbd, 0x56, 0x08, 0x42, 0xba, 0xe9, 0x70, 0xa6,
+  0xa5, 0x60, 0xfe, 0x5d, 0xed, 0x27, 0xda, 0xab, 0xd2, 0x25, 0xa1, 0xcb,
+  0x61, 0x53, 0x5b, 0x15, 0xf7, 0xbf, 0x23, 0xd1, 0xcd, 0x48, 0xa9, 0x00,
+  0x5a, 0x46, 0xde, 0xb8, 0x21, 0x12, 0x24, 0xed, 0x08, 0x64, 0x24, 0x63,
+  0x02, 0x4d, 0x85, 0x74, 0x37, 0xaf, 0xc1, 0xa7, 0x4e, 0x0d, 0x75, 0xeb,
+  0xe5, 0x5d, 0x29, 0x8a, 0x73, 0xe5, 0x13, 0x21, 0x98, 0xe7, 0xde, 0xbd,
+  0xd6, 0x7d, 0xec, 0x38, 0xdd, 0x3d, 0x4c, 0x00, 0x3d, 0xfc, 0x49, 0x22,
+  0x52, 0x22, 0x0e, 0x06, 0xe1, 0xd8, 0x09, 0x43, 0x2d, 0x56, 0x02, 0x81,
+  0x03, 0x35, 0x0a, 0x13, 0x10, 0xda, 0x5c, 0x61, 0x5b, 0x1d, 0x82, 0x83,
+  0x3e, 0x67, 0x16, 0x09, 0x8b, 0x00, 0x82, 0xa7, 0x3f, 0x77, 0xea, 0x75,
+  0x73, 0xa4, 0x8f, 0x6b, 0xa5, 0x3c, 0xb7, 0x43, 0x45, 0x1a, 0x5b, 0xbe,
+  0x54, 0x4d, 0x41, 0x12, 0x78, 0x6b, 0x59, 0x55, 0x33, 0x31, 0x6d, 0x31,
+  0xb6, 0x99, 0x2d, 0x21, 0x69, 0xe2, 0xe3, 0xd0, 0xe7, 0x3d, 0x81, 0xd9,
+  0xe3, 0xde, 0xa5, 0x86, 0x4d, 0x31, 0xda, 0xc6, 0x1a, 0x18, 0x76, 0xb7,
+  0xe2, 0x7a, 0x2f, 0x05, 0xf7, 0x3e, 0x3e, 0x4d, 0x7a, 0x9a, 0xbc, 0xbf,
+  0xb4, 0xea, 0x3e, 0xc3, 0xff, 0xf9, 0x0d, 0xea, 0x0f, 0x13, 0x2e, 0xd0,
+  0x9a, 0xb8, 0x1f, 0xac, 0x0e, 0xa4, 0xb5, 0x14, 0x93, 0x15, 0x01, 0x42,
+  0xd5, 0xc6, 0x42, 0x35, 0xb6, 0x0b, 0xc8, 0x80, 0xa8, 0x6d, 0xa4, 0xda,
+  0x5d, 0x5c, 0xad, 0x10, 0x35, 0x2d, 0x03, 0xd7, 0x7a, 0x59, 0xfb, 0xde,
+  0xaf, 0xe2, 0xb7, 0xfb, 0xe9, 0x00, 0xe0, 0x21, 0x1a, 0x88, 0x00, 0x00,
+  0xff, 0xff, 0xff, 0x01, 0x6a, 0xa4, 0xa0, 0x85, 0xc8, 0x26, 0x0c, 0x0c,
+  0xc2, 0x05, 0xe5, 0xe9, 0x2e, 0xab, 0x54, 0x18, 0x00, 0x0b, 0x25, 0x4e,
+  0x45, 0x78, 0x40, 0xc4, 0xca, 0xe3, 0x21, 0x2c, 0xbb, 0xeb, 0x9d, 0x7a,
+  0xe6, 0x83, 0x1e, 0x93, 0xf7, 0xf2, 0x0f, 0x1b, 0x37, 0xac, 0x9d, 0x0d,
+  0xad, 0xb7, 0x73, 0xbf, 0xbf, 0xfc, 0x6f, 0xa2, 0xb3, 0xde, 0xab, 0xf7,
+  0x8e, 0xdf, 0x5e, 0xd5, 0xe5, 0x55, 0x99, 0x26, 0x51, 0x4a, 0xd4, 0x9f,
+  0xce, 0xd6, 0x1b, 0xde, 0xef, 0x34, 0x12, 0x54, 0x8c, 0x6a, 0x16, 0x50,
+  0x84, 0x5c, 0xa0, 0xa4, 0x83, 0xa9, 0x8e, 0x24, 0x21, 0x0e, 0xfe, 0xd9,
+  0xac, 0x67, 0xb0, 0x1d, 0x09, 0x5e, 0xdd, 0x3c, 0xf5, 0xc8, 0x56, 0x34,
+  0xbc, 0x2d, 0x49, 0xc4, 0xa9, 0x48, 0xcd, 0x3b, 0x30, 0xad, 0x3c, 0x92,
+  0x42, 0x36, 0xb0, 0xa4, 0x5d, 0xb8, 0x72, 0x95, 0xd7, 0xba, 0x32, 0x97,
+  0x84, 0x92, 0x93, 0xa4, 0x0b, 0x49, 0x79, 0x5e, 0xc7, 0x75, 0x23, 0x7a,
+  0xda, 0x59, 0xa5, 0xf3, 0x8c, 0x3b, 0x99, 0x10, 0x10, 0xf6, 0x5c, 0x7f,
+  0x0a, 0xec, 0x3c, 0xbc, 0x1b, 0xe4, 0xc5, 0x21, 0x19, 0x92, 0xe5, 0x51,
+  0x69, 0x2e, 0x1d, 0xf9, 0xcc, 0x65, 0xa6, 0x33, 0x3f, 0x44, 0x74, 0xa8,
+  0x07, 0x22, 0xd2, 0xae, 0x94, 0x58, 0x2f, 0x94, 0x8a, 0x0d, 0x92, 0x71,
+  0x27, 0x7b, 0x5c, 0x81, 0x25, 0xcf, 0xaf, 0xaa, 0x04, 0x6c, 0x32, 0x8f,
+  0x82, 0x4d, 0x06, 0x12, 0xbb, 0x2d, 0xdb, 0x1f, 0x4c, 0xf3, 0x9f, 0xd0,
+  0xf2, 0x81, 0xeb, 0xe6, 0x4f, 0x31, 0xb0, 0xe0, 0x2a, 0x1d, 0x82, 0xa0,
+  0xa8, 0x2a, 0x48, 0x00, 0x00, 0x84, 0xd8, 0x3a, 0x33, 0x55, 0xb7, 0x9b,
+  0x2d, 0x0a, 0x10, 0x21, 0x63, 0xc1, 0x75, 0xb1, 0xf9, 0x3a, 0xd7, 0xe4,
+  0x96, 0x03, 0x92, 0x15, 0xb5, 0x66, 0x31, 0x9d, 0x2e, 0xf3, 0x0b, 0x62,
+  0x51, 0x14, 0x0a, 0x6c, 0xc9, 0x61, 0xd6, 0x07, 0x88, 0x56, 0xf0, 0x01,
+  0xa2, 0x3b, 0x88, 0x1d, 0x4a, 0xab, 0xd1, 0xab, 0x36, 0xbf, 0xdd, 0x1a,
+  0x53, 0x19, 0xfb, 0x55, 0x28, 0x1f, 0xac, 0x63, 0xcd, 0x34, 0x68, 0x56,
+  0x15, 0x97, 0xa1, 0xeb, 0xbd, 0x44, 0x19, 0x77, 0x5d, 0x13, 0x8c, 0x76,
+  0xd2, 0x72, 0xa5, 0x32, 0x19, 0x49, 0x73, 0xbf, 0x56, 0x76, 0x60, 0x68,
+  0xd8, 0xe3, 0x33, 0x10, 0xd3, 0xed, 0x92, 0xa1, 0x97, 0xb6, 0x4b, 0xe9,
+  0x33, 0x0a, 0x6d, 0x91, 0xc4, 0x4e, 0xb6, 0xe9, 0xd3, 0x89, 0xc2, 0x6a,
+  0xfc, 0x6a, 0x0c, 0x11, 0x09, 0x20, 0x7a, 0xe7, 0xed, 0xe7, 0xcf, 0xdb,
+  0xaf, 0xf1, 0xa0, 0x07, 0x21, 0x1a, 0x88, 0x00, 0x00, 0xff, 0xff, 0xff,
+  0x03, 0x6a, 0xa2, 0x58, 0xa0, 0x68, 0x42, 0x6b, 0x0e, 0x04, 0x61, 0x10,
+  0xe8, 0x34, 0xa4, 0xa9, 0x92, 0xa0, 0x04, 0x0c, 0xb4, 0x39, 0x19, 0x72,
+  0xb3, 0x37, 0xe1, 0x72, 0x60, 0xfa, 0x57, 0xa6, 0x69, 0x7d, 0xd5, 0xab,
+  0x3d, 0xc7, 0xc5, 0x73, 0x4d, 0xde, 0xaf, 0xa8, 0x4e, 0xec, 0xa2, 0x4d,
+  0x8f, 0xcb, 0xe3, 0x93, 0xb1, 0xaa, 0x00, 0xeb, 0x18, 0x9d, 0x25, 0x7f,
+  0x48, 0xfc, 0xf5, 0x3e, 0x46, 0x01, 0xa2, 0xdc, 0xc8, 0x6c, 0x6b, 0x2b,
+  0x2c, 0xfe, 0x07, 0x86, 0xb5, 0xd7, 0x23, 0xf2, 0x0e, 0x76, 0xfe, 0x12,
+  0xdb, 0xb7, 0x67, 0x15, 0xe6, 0x08, 0x91, 0x5a, 0xda, 0x9e, 0x59, 0x73,
+  0xa5, 0x85, 0xdf, 0x55, 0xe9, 0x8b, 0x80, 0xbf, 0x87, 0x4f, 0x16, 0xb3,
+  0x23, 0xcd, 0xa4, 0x36, 0x54, 0x27, 0x14, 0xe8, 0x3d, 0x8c, 0x35, 0xc2,
+  0xc5, 0x62, 0x1f, 0x51, 0xd0, 0x2e, 0x58, 0x7d, 0x9e, 0x11, 0xae, 0x13,
+  0xb0, 0xe0, 0x25, 0x0b, 0x03, 0xe6, 0x94, 0xab, 0xd1, 0x73, 0xf8, 0xcb,
+  0xf3, 0x4e, 0xf5, 0xa9, 0x7e, 0x1d, 0x10, 0x29, 0x65, 0x90, 0x17, 0x54,
+  0xda, 0x79, 0x95, 0x99, 0x65, 0xc7, 0xdb, 0x45, 0x3e, 0x9f, 0x97, 0x5a,
+  0x31, 0x86, 0xcd, 0x15, 0x1c, 0x01, 0xb8, 0xc2, 0xa0, 0x1b, 0x94, 0x4c,
+  0x33, 0x92, 0xbb, 0x62, 0xb0, 0xa8, 0xb2, 0x79, 0xea, 0x89, 0xf3, 0xc2,
+  0xad, 0xba, 0x75, 0x61, 0x9c, 0xd3, 0x13, 0x55, 0xfa, 0xc6, 0x6e, 0xf5,
+  0x38, 0xb3, 0x67, 0xc2, 0xd6, 0x8e, 0x9a, 0x48, 0x12, 0xd6, 0x08, 0xe9,
+  0xbe, 0xc0, 0xe4, 0x97, 0xc2, 0x14, 0x42, 0x4a, 0x91, 0x61, 0x8b, 0x18,
+  0x8f, 0xfa, 0xcf, 0x7d, 0xff, 0x5b, 0xea, 0xe0, 0xf7, 0xf3, 0x19, 0x30,
+  0xe0, 0x2e, 0x1d, 0x80, 0x0a, 0x42, 0xaa, 0x00, 0x00, 0x23, 0x34, 0x0a,
+  0x5f, 0x94, 0xa9, 0x06, 0xe8, 0x57, 0xf4, 0x1e, 0x64, 0x50, 0xcd, 0x2c,
+  0x76, 0x92, 0xf1, 0x51, 0x74, 0xf0, 0x6a, 0x55, 0x9e, 0xe4, 0x91, 0xd5,
+  0x2a, 0x91, 0xed, 0x68, 0x90, 0x2b, 0x05, 0xb2, 0x55, 0xaa, 0x13, 0x6b,
+  0x92, 0xb8, 0xe1, 0x59, 0xe7, 0x22, 0xbe, 0xde, 0x45, 0xe2, 0xc9, 0xf4,
+  0x81, 0x0a, 0x4b, 0x31, 0x42, 0x29, 0x0f, 0xe8, 0x89, 0x14, 0x9a, 0x1e,
+  0xb0, 0xb7, 0x88, 0xae, 0x4e, 0xbf, 0x4d, 0x34, 0x6f, 0xb2, 0xf9, 0x44,
+  0x02, 0xea, 0x19, 0xa8, 0xd3, 0x68, 0x95, 0x1a, 0x6c, 0xde, 0xa0, 0x00,
+  0x62, 0x0d, 0x7a, 0x03, 0xb7, 0x53, 0x06, 0x31, 0x2f, 0x02, 0x57, 0x0f,
+  0x8f, 0x13, 0x49, 0x97, 0xa9, 0xa9, 0xc6, 0xf0, 0xb3, 0xe9, 0xec, 0x24,
+  0x03, 0x07, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x07, 0x6a,
+  0xa4, 0x31, 0x10, 0x44, 0x94, 0x2c, 0x0d, 0x42, 0x01, 0x5c, 0x4b, 0xd5,
+  0x2e, 0xae, 0xaf, 0x21, 0x40, 0x02, 0x52, 0xd8, 0x35, 0xf7, 0xa7, 0xf8,
+  0x19, 0x14, 0x0f, 0xef, 0xb9, 0x4e, 0xe9, 0x1d, 0xa6, 0x2e, 0xfe, 0x98,
+  0xfd, 0x13, 0xb8, 0x22, 0xba, 0xb9, 0xf9, 0x1a, 0xe2, 0x51, 0x4e, 0x5b,
+  0xed, 0xdb, 0x8f, 0x5b, 0xbc, 0xf0, 0x39, 0xe6, 0x75, 0x4b, 0xe8, 0x1e,
+  0xf8, 0x7b, 0x2f, 0x27, 0xb1, 0xc7, 0x99, 0xc7, 0xff, 0x1c, 0x8a, 0xc0,
+  0xe9, 0x9b, 0x56, 0xd4, 0x2a, 0x57, 0x7b, 0x34, 0xfb, 0x65, 0x09, 0x34,
+  0xb5, 0x95, 0x7d, 0x20, 0x96, 0x1d, 0x71, 0xb2, 0x68, 0x71, 0xae, 0xb6,
+  0x5b, 0x2c, 0x31, 0xba, 0x25, 0x5c, 0x2c, 0xf8, 0x25, 0x00, 0x96, 0xa3,
+  0x49, 0x1a, 0x39, 0xd3, 0xa1, 0x07, 0x52, 0xd3, 0x3a, 0xd6, 0xb1, 0x54,
+  0xe1, 0x71, 0x24, 0x08, 0x94, 0x15, 0xe2, 0x7c, 0x26, 0xb5, 0xc6, 0x13,
+  0x09, 0x58, 0xc8, 0xb7, 0x8c, 0x48, 0x03, 0x6a, 0xcc, 0xd5, 0x13, 0x47,
+  0xc6, 0xb7, 0x79, 0x70, 0x62, 0x41, 0x0a, 0xb1, 0xd7, 0xf0, 0x8b, 0xe5,
+  0x6b, 0xd0, 0xc9, 0xe1, 0x73, 0x8c, 0x67, 0x06, 0x75, 0x1c, 0x1d, 0xac,
+  0xa2, 0xa9, 0xa7, 0xd3, 0xa7, 0x0c, 0x0d, 0xee, 0x86, 0x5f, 0xd3, 0x95,
+  0x78, 0xc1, 0xae, 0x00, 0x23, 0x53, 0x9d, 0x98, 0x2c, 0xdb, 0x65, 0x86,
+  0xd0, 0x0b, 0x6e, 0x70, 0xab, 0xa7, 0xd8, 0xca, 0x65, 0xd6, 0x34, 0x26,
+  0x27, 0x28, 0xf5, 0x55, 0x3a, 0x0a, 0x58, 0x52, 0x28, 0x6d, 0x15, 0x84,
+  0x87, 0x10, 0x95, 0xfc, 0xa1, 0x66, 0x4d, 0x2d, 0x3f, 0xaf, 0xaa, 0xf1,
+  0xf2, 0xee, 0xfa, 0x64, 0x01, 0xef, 0xec, 0x2f, 0x62, 0x28, 0x76, 0x00,
+  0x05, 0x44, 0x95, 0x50, 0x00, 0x08, 0xaa, 0x09, 0xee, 0x99, 0xfb, 0x7f,
+  0x69, 0x9a, 0x6c, 0x82, 0x6d, 0x74, 0x1d, 0xe4, 0xb1, 0xc6, 0x41, 0xa5,
+  0x6e, 0x02, 0x13, 0x21, 0x2d, 0x59, 0xc4, 0xf0, 0xda, 0xd6, 0x49, 0xe8,
+  0xac, 0xf6, 0xa7, 0xea, 0xfd, 0x59, 0x37, 0xe0, 0x2b, 0xe6, 0xbe, 0x15,
+  0xf9, 0xbd, 0xff, 0xb5, 0xe7, 0x6e, 0xa3, 0xee, 0xb9, 0x9d, 0x6b, 0x5a,
+  0xdf, 0xad, 0xc0, 0x00, 0x9a, 0x8e, 0x68, 0xd9, 0xea, 0x96, 0xc8, 0xee,
+  0xa1, 0x13, 0xc6, 0xb4, 0xae, 0xab, 0xf8, 0x33, 0xd7, 0x34, 0xfb, 0xde,
+  0x9a, 0x58, 0x37, 0x02, 0x88, 0x80, 0x28, 0x68, 0x3a, 0x87, 0x9e, 0x70,
+  0xe2, 0x7b, 0x69, 0xbe, 0xe0, 0x06, 0x8c, 0xbd, 0x3f, 0x3e, 0xdc, 0xf6,
+  0xc6, 0x24, 0x03, 0x07, 0x21, 0x1a, 0x88, 0x00, 0x00, 0xff, 0xff, 0xff,
+  0x09, 0x6f, 0x82, 0x21, 0x45, 0x88, 0x16, 0x1c, 0x05, 0x42, 0x22, 0x4c,
+  0x3d, 0x8b, 0x82, 0x50, 0xa5, 0x10, 0x04, 0x95, 0x26, 0x0b, 0xf5, 0x98,
+  0x3f, 0x1b, 0xf1, 0x42, 0x60, 0x05, 0x76, 0x4f, 0x26, 0xe9, 0xbd, 0x09,
+  0xff, 0xfb, 0x77, 0x98, 0x3b, 0xc2, 0x90, 0xca, 0x6e, 0x8b, 0xc2, 0x0d,
+  0xa2, 0x0e, 0xf3, 0x6e, 0xba, 0xed, 0x7e, 0x4a, 0xcb, 0x55, 0x52, 0x8d,
+  0x25, 0xbd, 0x54, 0x1a, 0x5d, 0x2b, 0xa1, 0x54, 0xcb, 0x54, 0xa2, 0x6a,
+  0xb3, 0x42, 0x3a, 0xdb, 0xdf, 0x4a, 0x56, 0xd5, 0x0f, 0x32, 0x08, 0x72,
+  0x2b, 0x2c, 0x49, 0x46, 0x26, 0xe5, 0x90, 0x28, 0xae, 0x02, 0x1d, 0x22,
+  0x56, 0x31, 0x48, 0x7f, 0xdc, 0xc8, 0x76, 0xa7, 0x4b, 0xaf, 0x36, 0xa1,
+  0x22, 0xe1, 0xab, 0x57, 0x72, 0xf5, 0x46, 0xb2, 0x56, 0x45, 0x00, 0x2e,
+  0xc7, 0x7d, 0x94, 0x52, 0x53, 0x94, 0xeb, 0x7c, 0xf4, 0x55, 0x5c, 0xa7,
+  0xb9, 0x54, 0x0c, 0x3f, 0x0a, 0xde, 0x9e, 0x8b, 0xdd, 0x92, 0x72, 0xad,
+  0xa9, 0x8f, 0x65, 0x2d, 0xd2, 0xac, 0xa2, 0xea, 0x42, 0x95, 0x96, 0x55,
+  0x03, 0xd4, 0x38, 0x43, 0xa0, 0x8a, 0xcd, 0x8a, 0xbb, 0xe1, 0x39, 0xa0,
+  0xa6, 0x8d, 0x51, 0x63, 0x69, 0x2a, 0x86, 0x59, 0xae, 0x97, 0xf0, 0xdd,
+  0x56, 0x4f, 0x53, 0x31, 0xe2, 0x06, 0x5c, 0x6b, 0xa3, 0x61, 0xc9, 0xac,
+  0x42, 0xda, 0x2a, 0x22, 0xb6, 0x81, 0x2b, 0xbb, 0x9f, 0x53, 0x52, 0xca,
+  0x4d, 0x11, 0xaa, 0xb3, 0x63, 0xe7, 0xf5, 0x74, 0xd7, 0x67, 0xd5, 0x9e,
+  0x00, 0x0f, 0x5f, 0x33, 0x81, 0x09, 0x88, 0xe1, 0xd8, 0x00, 0x54, 0x95,
+  0x56, 0x05, 0xb0, 0x01, 0x10, 0x03, 0x40, 0xb9, 0x28, 0x68, 0x0c, 0xe0,
+  0xbc, 0x4b, 0xfc, 0x1b, 0xa3, 0x22, 0x4a, 0xab, 0x69, 0x05, 0x13, 0x5e,
+  0x4e, 0xd1, 0xb7, 0x12, 0xf2, 0x28, 0x82, 0xd1, 0x88, 0x53, 0x1b, 0x0e,
+  0x0e, 0x1a, 0x99, 0xa7, 0xa8, 0x11, 0x97, 0x38, 0x1a, 0x3d, 0x54, 0xe9,
+  0x3b, 0x58, 0xef, 0x48, 0xea, 0xd4, 0x05, 0x9f, 0x53, 0x6e, 0x18, 0x23,
+  0x50, 0x82, 0x49, 0x4b, 0x32, 0x1b, 0xed, 0x7a, 0x00, 0x2c, 0xbb, 0xa9,
+  0xae, 0xb7, 0x46, 0xbe, 0xd7, 0x36, 0xfd, 0x60, 0x34, 0xff, 0x51, 0x2c,
+  0x76, 0xe0, 0x09, 0xd8, 0xab, 0x68, 0xc2, 0xdd, 0x49, 0xd2, 0xdb, 0xa6,
+  0x54, 0xba, 0x8a, 0xba, 0xba, 0xfe, 0x4f, 0x57, 0xd7, 0xb8, 0xba, 0x3e,
+  0x70, 0x0e, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x11, 0x6f,
+  0xa1, 0xb1, 0x10, 0x62, 0xc6, 0x20, 0x85, 0xad, 0xe9, 0x67, 0xc0, 0xb5,
+  0x2d, 0xbb, 0x03, 0x02, 0x02, 0x43, 0xb0, 0xc5, 0xdf, 0xd3, 0x1f, 0x63,
+  0xf1, 0x52, 0x1b, 0x2f, 0x1f, 0x82, 0x83, 0x15, 0x08, 0x32, 0xf8, 0xab,
+  0x1c, 0xfd, 0x4f, 0xce, 0x34, 0x87, 0x8a, 0xc6, 0xb9, 0x0e, 0x37, 0xf1,
+  0xa5, 0x31, 0x7f, 0x7a, 0x3c, 0x9a, 0x3a, 0x56, 0x60, 0x7e, 0xaf, 0x18,
+  0x73, 0x6f, 0x90, 0x34, 0xf5, 0x8e, 0x63, 0x8f, 0x35, 0xdd, 0x76, 0x17,
+  0xe2, 0x8d, 0x51, 0x8c, 0x9f, 0x58, 0xb3, 0x19, 0x84, 0xca, 0x9c, 0xc9,
+  0xbc, 0xc0, 0x56, 0xca, 0x12, 0x6f, 0x8c, 0xee, 0xa3, 0x7d, 0x97, 0x45,
+  0x59, 0x32, 0x9a, 0xc5, 0x2f, 0x5b, 0x39, 0x57, 0x40, 0xf7, 0xc1, 0xfd,
+  0xfd, 0x13, 0x19, 0xb8, 0xee, 0x8a, 0xab, 0xd4, 0xcc, 0x63, 0xbd, 0x38,
+  0xea, 0x8d, 0x70, 0xa4, 0x40, 0x8c, 0xe1, 0x89, 0xd4, 0x50, 0x23, 0x7c,
+  0x88, 0x8c, 0xe1, 0x62, 0x8b, 0x2c, 0xb6, 0xca, 0x4d, 0x81, 0xf6, 0x66,
+  0xb6, 0xac, 0xdb, 0xe8, 0xef, 0xaa, 0xfe, 0x8a, 0x3a, 0x79, 0x62, 0x86,
+  0x4a, 0xfe, 0xd9, 0xdd, 0xeb, 0xc1, 0xd9, 0xa5, 0x01, 0x02, 0x84, 0x96,
+  0x8b, 0x14, 0x41, 0x9c, 0x9a, 0x8f, 0x26, 0x3d, 0xae, 0xdc, 0xac, 0xee,
+  0x8b, 0x17, 0xde, 0xbf, 0xa9, 0x4c, 0xec, 0xc3, 0xdd, 0x3f, 0xe0, 0x24,
+  0x97, 0x4c, 0xb1, 0x0b, 0x53, 0x62, 0xfe, 0x5e, 0x13, 0x48, 0x42, 0x78,
+  0xfc, 0xa7, 0x9f, 0xce, 0x7f, 0xbf, 0x9f, 0xf3, 0xc8, 0x0f, 0x5f, 0x44,
+  0x20, 0xb1, 0x04, 0xc2, 0x80, 0xb8, 0x76, 0x00, 0x05, 0x2f, 0x2e, 0xc0,
+  0x60, 0x02, 0xea, 0xf0, 0x58, 0x75, 0x7e, 0xc3, 0x54, 0xd2, 0x80, 0x9a,
+  0x71, 0x68, 0x70, 0x55, 0xf8, 0x4c, 0xf5, 0x38, 0x5a, 0xd2, 0xae, 0x48,
+  0x85, 0x16, 0xb7, 0x79, 0xd1, 0x69, 0x95, 0xca, 0x21, 0x23, 0x74, 0x62,
+  0xbc, 0xf3, 0x28, 0xa4, 0x30, 0xd0, 0xa7, 0xd9, 0xfa, 0xc1, 0x02, 0x36,
+  0xd7, 0x7b, 0x7c, 0x8b, 0x61, 0xbf, 0xaa, 0x80, 0xc0, 0xa7, 0x81, 0x17,
+  0x7c, 0xaa, 0x2a, 0xd3, 0x5a, 0xf9, 0xc7, 0x88, 0x26, 0x07, 0xca, 0xf4,
+  0x0e, 0xae, 0x98, 0x23, 0xb1, 0x36, 0xce, 0x3e, 0xcb, 0xbd, 0x5c, 0xe5,
+  0x33, 0x13, 0xd0, 0xfa, 0xdd, 0xc0, 0x6c, 0x94, 0x81, 0xb0, 0xdb, 0x84,
+  0x6a, 0x8c, 0x4d, 0x9c, 0xd9, 0x1b, 0x70, 0x8f, 0x27, 0x36, 0x41, 0x0a,
+  0xc9, 0xca, 0xd4, 0xbe, 0x56, 0x3e, 0x27, 0xc7, 0xe0, 0x80, 0x38, 0x21,
+  0x1a, 0x88, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x05, 0x6a, 0xa2, 0x58, 0x68,
+  0x8c, 0x42, 0x11, 0x94, 0x88, 0x84, 0x61, 0x40, 0x4c, 0x20, 0x38, 0x17,
+  0x60, 0x01, 0x44, 0x40, 0x12, 0xa7, 0x63, 0x26, 0x0b, 0x05, 0x95, 0xf4,
+  0x72, 0xfc, 0x0a, 0x90, 0x55, 0xd3, 0xff, 0x82, 0x49, 0x64, 0x84, 0x5d,
+  0x40, 0xe8, 0xca, 0x10, 0x92, 0x78, 0x39, 0x8b, 0xbf, 0xbb, 0x47, 0x3c,
+  0xfa, 0xbd, 0xbc, 0xda, 0x18, 0xbd, 0xd3, 0xe5, 0x76, 0x2a, 0x17, 0xde,
+  0x8e, 0xff, 0xdd, 0x53, 0x6f, 0x5f, 0x0f, 0xd2, 0x63, 0x72, 0x70, 0xd9,
+  0x1e, 0x97, 0xc4, 0x31, 0x3a, 0x44, 0x5d, 0x27, 0xf8, 0x61, 0xdf, 0xa6,
+  0xe4, 0xe1, 0x16, 0x27, 0x05, 0xf9, 0x71, 0xb0, 0x6c, 0x26, 0x8a, 0x1c,
+  0xb4, 0x59, 0x9a, 0x38, 0x99, 0x15, 0xb3, 0x12, 0x46, 0x28, 0x4a, 0x8a,
+  0x35, 0x85, 0xc1, 0x7c, 0xe0, 0x8a, 0xf5, 0x72, 0xf1, 0xd8, 0x7a, 0xd4,
+  0xea, 0xd4, 0x56, 0xa4, 0x11, 0x25, 0x1c, 0x22, 0xb4, 0x4c, 0xed, 0xfd,
+  0x7a, 0x5a, 0x75, 0xd5, 0xb9, 0xe3, 0xa9, 0x87, 0x21, 0x82, 0xa1, 0xf1,
+  0x0b, 0x5f, 0x40, 0x1d, 0xfc, 0x2e, 0x42, 0xfc, 0x18, 0xb8, 0x89, 0x7e,
+  0xac, 0x37, 0xba, 0xf0, 0xe5, 0xac, 0x2d, 0x54, 0x52, 0x48, 0x80, 0x76,
+  0x42, 0x43, 0xce, 0x94, 0x13, 0x23, 0xda, 0x36, 0x61, 0x29, 0xe9, 0xf2,
+  0xfd, 0x7d, 0xdb, 0xab, 0xc4, 0xd7, 0x5f, 0x40, 0x52, 0x26, 0xcb, 0x67,
+  0x8d, 0xc6, 0xd8, 0xd4, 0xdc, 0xf0, 0xa9, 0x37, 0xd2, 0x7d, 0xe6, 0x62,
+  0x76, 0xde, 0x7c, 0x47, 0xb8, 0xea, 0x16, 0x71, 0x05, 0xfa, 0xf8, 0x2b,
+  0x1b, 0xc0, 0x5b, 0x1b, 0x98, 0xf2, 0x38, 0xbe, 0xf4, 0xf1, 0x7c, 0x88,
+  0x3d, 0xfd, 0xc5, 0xa8, 0x26, 0x1b, 0x87, 0x60, 0x00, 0x04, 0x4a, 0x68,
+  0x6c, 0x16, 0x22, 0x80, 0x0f, 0x34, 0x77, 0xcd, 0x79, 0x89, 0x72, 0x48,
+  0x41, 0x79, 0x72, 0x1a, 0x8c, 0x62, 0x9b, 0xa5, 0x85, 0x26, 0xd1, 0x64,
+  0xc6, 0x35, 0xea, 0x9d, 0x4b, 0x62, 0x35, 0xa5, 0x8f, 0x23, 0x82, 0x27,
+  0x88, 0x54, 0x9a, 0x9f, 0xa2, 0x84, 0x14, 0x9b, 0xa3, 0x74, 0x42, 0xf0,
+  0x1a, 0xed, 0x9a, 0xa2, 0x93, 0x90, 0xf7, 0xa1, 0x5d, 0x12, 0x66, 0xe7,
+  0xf9, 0x59, 0x7b, 0xf2, 0xcb, 0xc2, 0x69, 0x81, 0x0f, 0xf3, 0x72, 0x65,
+  0xed, 0x21, 0x0f, 0x80, 0xec, 0x42, 0x5a, 0xe7, 0x96, 0xa2, 0xaf, 0xbc,
+  0x2f, 0xc7, 0x15, 0x33, 0xbf, 0x3c, 0xe4, 0xeb, 0xd5, 0xe4, 0xea, 0xe9,
+  0xf9, 0xfa, 0xee, 0xcb, 0x68, 0x07, 0x21, 0x1a, 0x88, 0x00, 0x00, 0xff,
+  0xff, 0xff, 0x09, 0x6f, 0xa2, 0x21, 0x49, 0x88, 0x26, 0x1a, 0x84, 0x0b,
+  0x1d, 0x2e, 0xa2, 0xd3, 0x99, 0x56, 0x00, 0x0b, 0xcd, 0x53, 0x07, 0x2b,
+  0x92, 0x30, 0x2e, 0xb2, 0x63, 0xc2, 0x64, 0x21, 0x12, 0x3b, 0xec, 0xc6,
+  0xd4, 0x60, 0xe9, 0x2f, 0xf4, 0xc6, 0x58, 0x21, 0xb5, 0x6e, 0xf7, 0xce,
+  0xc5, 0xea, 0x8e, 0xce, 0xc6, 0x4a, 0x62, 0xdc, 0x5a, 0x13, 0x83, 0x2f,
+  0x90, 0x78, 0xa7, 0x57, 0xe8, 0x1a, 0x21, 0xf1, 0xa4, 0x2f, 0x96, 0x22,
+  0x9b, 0x74, 0xfc, 0xf7, 0xf3, 0xfb, 0x22, 0x6d, 0xb9, 0x60, 0xa5, 0xaf,
+  0xb4, 0x79, 0xaf, 0x6b, 0xe9, 0x16, 0xe8, 0xa3, 0x1e, 0x1e, 0x2a, 0x0a,
+  0xd3, 0x5a, 0x9b, 0x0e, 0x1a, 0xcf, 0xb0, 0xe6, 0x71, 0xa1, 0x90, 0x64,
+  0x88, 0x39, 0xb6, 0x34, 0xe4, 0xfc, 0x94, 0xfa, 0x91, 0x23, 0x0b, 0x40,
+  0xcc, 0x53, 0x14, 0xd9, 0x02, 0x54, 0xa6, 0x40, 0x60, 0x4c, 0x30, 0x3d,
+  0x6e, 0x5b, 0x9c, 0xe1, 0x59, 0x16, 0xa0, 0xb1, 0x7c, 0x22, 0xb1, 0x50,
+  0x1e, 0x42, 0x92, 0x02, 0xf0, 0x98, 0xd4, 0x71, 0xd0, 0x9c, 0xc9, 0x53,
+  0x14, 0xdf, 0x81, 0xfd, 0x09, 0x89, 0x13, 0x46, 0x4a, 0x98, 0x7a, 0x2f,
+  0xbb, 0xc4, 0x00, 0x9c, 0x28, 0x45, 0x10, 0x84, 0x32, 0x71, 0x21, 0x01,
+  0x27, 0x53, 0xcf, 0x1a, 0x83, 0xbd, 0x94, 0x7f, 0xf4, 0xee, 0xb9, 0xb9,
+  0xf5, 0xc7, 0xa1, 0x7f, 0xdf, 0xf9, 0x6f, 0xcb, 0x85, 0x1b, 0xf2, 0x0e,
+  0x34, 0x74, 0xba, 0xcb, 0xe8, 0xa6, 0x6e, 0xd3, 0xc7, 0x54, 0x83, 0x62,
+  0x88, 0xf7, 0xbd, 0x9d, 0x8d, 0x3b, 0x5b, 0xdb, 0x89, 0x68, 0xc7, 0xd9,
+  0xbe, 0xaf, 0xe5, 0xf0, 0xb0, 0x03, 0xd7, 0xcc, 0xe4, 0xc2, 0x81, 0x28,
+  0x76, 0x00, 0xa8, 0x09, 0x50, 0x02, 0x80, 0x22, 0xea, 0x85, 0x9b, 0x8d,
+  0x68, 0xc7, 0x9b, 0x9a, 0xb4, 0x97, 0xcc, 0x3a, 0x9d, 0xb8, 0x42, 0x31,
+  0x5e, 0x85, 0x30, 0xf1, 0x40, 0x2c, 0xb4, 0x67, 0x98, 0x0b, 0xd6, 0x0d,
+  0xcc, 0x46, 0x58, 0xa6, 0xcc, 0xbd, 0xc0, 0x35, 0x69, 0x44, 0x05, 0x23,
+  0xbf, 0x89, 0xa1, 0x8d, 0x3e, 0xaa, 0xb4, 0x9e, 0x1c, 0x4a, 0x6b, 0xe5,
+  0xf1, 0xf8, 0xa5, 0xe3, 0xaf, 0xdb, 0xe8, 0xf5, 0x30, 0x68, 0x72, 0x35,
+  0xb6, 0x00, 0x2e, 0x77, 0x82, 0x95, 0xd6, 0x3b, 0xac, 0x5c, 0xc3, 0x7f,
+  0x09, 0x3c, 0xc9, 0xbe, 0x88, 0x9e, 0xda, 0x77, 0x6b, 0x80, 0xb7, 0xa5,
+  0x16, 0x34, 0x4b, 0xba, 0x05, 0x86, 0x09, 0x00, 0xd9, 0x97, 0xf8, 0xf7,
+  0xc7, 0x68, 0xa0, 0x06, 0xde, 0x8c, 0xec, 0x98, 0x8d, 0xca, 0x80, 0x84,
+  0x64, 0x73, 0xfa, 0xbc, 0xbd, 0xd5, 0xe7, 0x5e, 0x00, 0x1c, 0x21, 0x1a,
+  0x88, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x0b, 0x6a, 0xa4, 0xb0, 0xd0, 0x42,
+  0xb4, 0x1b, 0x0d, 0xc2, 0x08, 0x79, 0x0b, 0xa7, 0x02, 0x99, 0x60, 0x00,
+  0x91, 0x41, 0x4c, 0xd4, 0x41, 0xc7, 0x88, 0xe5, 0x4a, 0xc0, 0x76, 0x20,
+  0xa5, 0xf3, 0xc7, 0x39, 0x4a, 0x54, 0x0d, 0xc9, 0xd9, 0xfd, 0x9b, 0x61,
+  0x44, 0x34, 0xc4, 0xae, 0xcb, 0x7c, 0x04, 0x0c, 0x99, 0x58, 0x9f, 0x60,
+  0x63, 0xef, 0x2e, 0x59, 0xf4, 0x8a, 0xfe, 0x0f, 0xdc, 0x18, 0xe9, 0x4f,
+  0xdb, 0x52, 0x68, 0x1b, 0x17, 0xcf, 0xde, 0x66, 0xb5, 0x4b, 0x9a, 0x87,
+  0x84, 0xa3, 0xb1, 0xd2, 0xd4, 0x77, 0x09, 0x8d, 0x83, 0x8d, 0xb0, 0x69,
+  0x5b, 0x48, 0xa9, 0x80, 0x11, 0xe2, 0x99, 0xf9, 0xc9, 0x2e, 0x28, 0x8c,
+  0x59, 0x0e, 0x2e, 0x76, 0x4b, 0x46, 0x5f, 0xa4, 0xab, 0x70, 0xa3, 0x4b,
+  0x72, 0xac, 0x3f, 0xd6, 0x65, 0x34, 0xb2, 0x45, 0xd2, 0x9c, 0x12, 0x05,
+  0x25, 0x6c, 0xe8, 0x9d, 0x73, 0xc5, 0x81, 0x6f, 0xd2, 0x86, 0x1b, 0x61,
+  0x68, 0xa2, 0x33, 0xa4, 0xf0, 0xde, 0x8c, 0x57, 0x3c, 0x19, 0xfe, 0x59,
+  0x0c, 0x9e, 0x3e, 0x54, 0xdc, 0x87, 0x0e, 0x50, 0x2d, 0x62, 0x97, 0x1d,
+  0x09, 0xf3, 0xbd, 0x2c, 0x14, 0x1c, 0xdd, 0x87, 0x47, 0xdb, 0xca, 0xe8,
+  0xda, 0x00, 0xc7, 0x3d, 0xcb, 0x32, 0x03, 0x8d, 0xb5, 0x4c, 0xab, 0x95,
+  0x47, 0xed, 0xea, 0x09, 0x7f, 0x32, 0x26, 0x14, 0xcd, 0x67, 0x3a, 0xec,
+  0xc3, 0xa9, 0x3a, 0x7c, 0xbf, 0xb1, 0xd1, 0x65, 0x85, 0x4f, 0x85, 0x2a,
+  0x18, 0x20, 0x87, 0x3e, 0x57, 0xc4, 0xe3, 0x63, 0xab, 0xe1, 0xcf, 0x38,
+  0x03, 0xe7, 0xdc, 0x5c, 0xc4, 0x00, 0xec, 0x00, 0x02, 0x28, 0x96, 0x32,
+  0xca, 0x05, 0xa8, 0x28, 0x8d, 0xf6, 0x4a, 0xd6, 0x94, 0xa6, 0xa6, 0xf8,
+  0x68, 0x92, 0x31, 0xf8, 0x8a, 0x00, 0x9b, 0x52, 0x93, 0x10, 0x45, 0x97,
+  0xd0, 0x9d, 0xe8, 0x98, 0x26, 0xac, 0x19, 0x21, 0x6c, 0xae, 0xdc, 0x1b,
+  0x2b, 0x14, 0xe1, 0x66, 0x94, 0x75, 0x05, 0x52, 0x32, 0xe6, 0xfb, 0xd2,
+  0xdf, 0x90, 0x72, 0xa0, 0x43, 0x52, 0xc8, 0x0e, 0xb4, 0x11, 0x65, 0x94,
+  0xfe, 0x1e, 0xda, 0xa1, 0xce, 0xb9, 0x7b, 0x39, 0x17, 0x5e, 0x96, 0xe8,
+  0x57, 0xd7, 0x3c, 0xe8, 0x82, 0x14, 0xe2, 0xc0, 0xd6, 0xf6, 0x75, 0x56,
+  0x24, 0x13, 0x69, 0xf8, 0x87, 0xce, 0x47, 0xdd, 0x9d, 0x5c, 0x21, 0x1a,
+  0x88, 0x00, 0x00, 0x03, 0xff, 0xff, 0x0f, 0x6a, 0xa4, 0xb1, 0x85, 0x24,
+  0x36, 0x22, 0x84, 0x5a, 0xea, 0x2b, 0xa6, 0x98, 0xd4, 0x10, 0xa0, 0x00,
+  0x90, 0xa1, 0x10, 0x22, 0xa0, 0x7c, 0x91, 0x06, 0x8b, 0x53, 0x72, 0x4f,
+  0xb0, 0x65, 0x42, 0x64, 0x10, 0xfe, 0x4f, 0x71, 0x4d, 0x38, 0x7e, 0x7a,
+  0xd9, 0x5b, 0xb7, 0x3d, 0x52, 0x72, 0x78, 0x22, 0xfe, 0xc7, 0xdc, 0xab,
+  0xb5, 0x8a, 0x76, 0x37, 0x5e, 0xf2, 0xc3, 0x83, 0xb0, 0x53, 0xf0, 0x5c,
+  0x72, 0xe5, 0x56, 0xf6, 0x5e, 0x5b, 0x93, 0x34, 0xf3, 0x96, 0x8e, 0xe6,
+  0x37, 0x19, 0x5d, 0x31, 0x00, 0x0d, 0x2b, 0xd4, 0x9b, 0xfb, 0xce, 0x74,
+  0x94, 0x93, 0x23, 0xd2, 0x77, 0x5f, 0x68, 0x10, 0xa9, 0x1e, 0x96, 0xdd,
+  0xa3, 0x45, 0x18, 0xcb, 0xc4, 0x17, 0x7f, 0x2b, 0x40, 0x2d, 0xbe, 0x32,
+  0x2a, 0x1a, 0xc1, 0x44, 0x50, 0x3b, 0x91, 0x04, 0x11, 0x3a, 0x38, 0x65,
+  0xea, 0x8b, 0x9c, 0x27, 0x1e, 0x06, 0xc5, 0x62, 0xad, 0x94, 0xb4, 0x27,
+  0x5d, 0x2a, 0x79, 0x54, 0xe7, 0x53, 0x08, 0x05, 0x55, 0x68, 0x5a, 0xff,
+  0xa1, 0x28, 0xd3, 0x63, 0xb4, 0xa2, 0xb5, 0x7c, 0x30, 0x39, 0xcc, 0xb6,
+  0x1e, 0x67, 0x3c, 0xc9, 0x80, 0xaf, 0x54, 0x55, 0xcc, 0xd2, 0x41, 0x4d,
+  0x5e, 0xe6, 0xba, 0xc6, 0x16, 0x6c, 0xe8, 0x3c, 0x29, 0x99, 0x36, 0x57,
+  0x66, 0xf2, 0x19, 0xff, 0x38, 0xf6, 0x2e, 0x78, 0x55, 0x3d, 0x7a, 0x24,
+  0x17, 0x9a, 0xab, 0x5e, 0xe0, 0xee, 0x7d, 0x56, 0x0f, 0x51, 0xa6, 0x1a,
+  0xdc, 0xeb, 0xcb, 0x54, 0xf2, 0xed, 0xf2, 0xcf, 0xc3, 0x3e, 0x8f, 0xfa,
+  0xbf, 0xcc, 0x01, 0xef, 0xf2, 0x2b, 0x41, 0x30, 0xcc, 0x3b, 0x00, 0x00,
+  0x12, 0xa4, 0x58, 0x50, 0x4a, 0x2a, 0x02, 0x7d, 0xd9, 0xe3, 0x8f, 0x6f,
+  0x6b, 0x5f, 0xfa, 0x93, 0x16, 0x13, 0xdb, 0x12, 0x35, 0xfc, 0x52, 0xb6,
+  0x91, 0x04, 0xeb, 0x10, 0xa4, 0xfd, 0x65, 0xd7, 0x53, 0x8f, 0x2a, 0xe6,
+  0x4f, 0x46, 0x0d, 0xf1, 0xea, 0xb6, 0x08, 0xbf, 0x94, 0xd2, 0xb0, 0xbb,
+  0x38, 0x5c, 0x7d, 0xce, 0x87, 0x33, 0xc2, 0x45, 0x8e, 0xfe, 0x91, 0x1f,
+  0xff, 0xe5, 0xae, 0x54, 0x22, 0x88, 0xeb, 0xb6, 0x97, 0xb1, 0x45, 0xc4,
+  0xce, 0xcc, 0x56, 0x60, 0x00, 0xb0, 0x72, 0xa0, 0x40, 0x11, 0x90, 0xf3,
+  0xc3, 0x56, 0x9c, 0x4b, 0x0a, 0x33, 0xb4, 0x31, 0xaf, 0xdf, 0x9f, 0xd4,
+  0x7e, 0xbc, 0x38, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x07, 0xff, 0xff, 0x0f,
+  0x70, 0xa1, 0xb1, 0x48, 0x62, 0x64, 0x08, 0x8d, 0x85, 0x02, 0x50, 0x82,
+  0x47, 0x92, 0xd6, 0x44, 0x09, 0xb0, 0x10, 0x16, 0x9b, 0x12, 0x70, 0xbc,
+  0x72, 0xcf, 0x07, 0x28, 0x54, 0xa1, 0xe7, 0x4c, 0xaa, 0xc7, 0xde, 0xc6,
+  0x68, 0xbd, 0xe7, 0xad, 0x03, 0xc3, 0xba, 0xc5, 0xdc, 0x49, 0x40, 0xf2,
+  0xbc, 0xa8, 0x0d, 0x3f, 0x54, 0xe6, 0x99, 0x21, 0xd3, 0x8a, 0x77, 0x8e,
+  0x9d, 0x9c, 0x31, 0xd6, 0x62, 0x31, 0xdd, 0x1f, 0x48, 0xd2, 0x34, 0x75,
+  0x3b, 0x83, 0xd9, 0x2f, 0x19, 0x22, 0x93, 0xdb, 0xd6, 0x05, 0x95, 0x03,
+  0x27, 0xd5, 0x86, 0x8c, 0xe6, 0x57, 0x4d, 0xe0, 0x97, 0xd2, 0x71, 0xdb,
+  0xf7, 0xd3, 0x07, 0x40, 0xf6, 0x76, 0x3d, 0xfd, 0x1e, 0x8b, 0x28, 0xda,
+  0x75, 0xd5, 0xd8, 0xb8, 0x59, 0x51, 0xb9, 0xff, 0xd8, 0xe9, 0x2c, 0x5c,
+  0x59, 0xd9, 0xd7, 0xdd, 0x66, 0x5a, 0x2e, 0xfd, 0xa6, 0xc4, 0xd8, 0x5d,
+  0x6b, 0x3b, 0x0f, 0x4d, 0x2b, 0x62, 0x09, 0x72, 0xf7, 0x1d, 0x97, 0xaf,
+  0xf4, 0x4e, 0x64, 0xac, 0xa2, 0xf7, 0x6c, 0xec, 0xda, 0xaa, 0xaa, 0x4a,
+  0x3f, 0x19, 0xdd, 0x1d, 0xdc, 0xde, 0x6b, 0x7c, 0x6a, 0x44, 0x4d, 0xe3,
+  0x8a, 0x43, 0x5f, 0x83, 0xcb, 0x2d, 0x8d, 0xb0, 0x6f, 0xc8, 0x53, 0x2c,
+  0x27, 0x6c, 0x22, 0x6a, 0x42, 0x88, 0x46, 0xa4, 0xc5, 0xc8, 0x8e, 0x71,
+  0xc4, 0xfb, 0x78, 0xd9, 0x6c, 0x92, 0x7b, 0x87, 0x56, 0xda, 0xf2, 0xc1,
+  0x86, 0x5a, 0x11, 0xb1, 0x06, 0x6d, 0x4b, 0xe8, 0x1c, 0x6d, 0x92, 0x2a,
+  0xbc, 0xaa, 0x15, 0x31, 0x29, 0x78, 0xd9, 0xd9, 0x4f, 0x3a, 0xae, 0x63,
+  0xe5, 0x9b, 0x97, 0x67, 0x55, 0xe3, 0xe5, 0xe1, 0xc8, 0x01, 0xef, 0xf0,
+  0x2c, 0x41, 0x30, 0xd4, 0x3b, 0x00, 0x00, 0x26, 0x48, 0x80, 0xa1, 0x05,
+  0x9b, 0x1b, 0xb0, 0x08, 0x2e, 0x9c, 0xd4, 0x6a, 0x04, 0xa4, 0xa2, 0xf4,
+  0x06, 0x2b, 0xaf, 0x48, 0x4a, 0x24, 0xee, 0x9c, 0x87, 0x15, 0x68, 0x55,
+  0x12, 0x85, 0x45, 0x66, 0x85, 0x38, 0xec, 0xfb, 0xee, 0xdb, 0xa8, 0xf9,
+  0x2e, 0xc6, 0x7b, 0x2d, 0xbe, 0xdc, 0xa1, 0xe9, 0x00, 0xfb, 0x91, 0x2f,
+  0xd9, 0x01, 0x5f, 0x28, 0xb1, 0xb7, 0xbf, 0x4d, 0xbd, 0x7d, 0x12, 0xc5,
+  0xc6, 0xee, 0xea, 0x3a, 0x78, 0x63, 0xba, 0xe6, 0x7c, 0xb2, 0xe3, 0xd1,
+  0x3e, 0x46, 0x10, 0xbf, 0xd7, 0x63, 0x9f, 0x67, 0x7b, 0xa7, 0xf9, 0xf2,
+  0xe5, 0x55, 0x7f, 0x0d, 0xbf, 0x0e, 0x51, 0x9e, 0xdf, 0x54, 0xf4, 0x40,
+  0x07, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x07, 0xff, 0xff, 0x0f, 0x70, 0xa2,
+  0x30, 0xcd, 0xc8, 0x18, 0x19, 0x84, 0x17, 0x70, 0xb9, 0xa2, 0xe2, 0xa6,
+  0x5d, 0x50, 0x02, 0x09, 0x13, 0x91, 0xf4, 0x8c, 0xec, 0x2a, 0x00, 0x18,
+  0x04, 0x32, 0x23, 0x05, 0xac, 0x32, 0x63, 0x8f, 0xb3, 0xbb, 0x59, 0x5b,
+  0x23, 0x6e, 0xbc, 0x57, 0xd7, 0x26, 0x2d, 0x55, 0x47, 0xd5, 0x19, 0x0c,
+  0xa8, 0x38, 0xa2, 0x22, 0xef, 0xf6, 0xce, 0x25, 0xd0, 0xb6, 0x46, 0xfc,
+  0xd3, 0x5a, 0x4f, 0x2d, 0xe1, 0xfb, 0x5e, 0x23, 0x71, 0x55, 0x5f, 0xf5,
+  0xf3, 0x08, 0xac, 0x4c, 0xe7, 0x4f, 0x9d, 0x6b, 0xc9, 0xeb, 0xfb, 0x6d,
+  0x6f, 0x17, 0x41, 0x1a, 0xa4, 0x6b, 0x9b, 0x1c, 0xda, 0x4d, 0x9a, 0x4b,
+  0xa3, 0x2c, 0x81, 0x10, 0x81, 0x40, 0x62, 0x81, 0x15, 0x93, 0xeb, 0xbd,
+  0xe6, 0x97, 0x78, 0x49, 0xa5, 0x68, 0x0f, 0x0b, 0x36, 0x27, 0x9e, 0xbb,
+  0x7b, 0xb8, 0xe3, 0x2d, 0x84, 0x80, 0xd8, 0x8b, 0x14, 0x69, 0x98, 0x8d,
+  0x13, 0x64, 0x9f, 0x10, 0x1a, 0x2b, 0xd6, 0x08, 0x5d, 0x64, 0x91, 0x5d,
+  0x2e, 0x1c, 0xf0, 0x9c, 0xee, 0xb5, 0x73, 0x66, 0xf8, 0x33, 0xa6, 0x42,
+  0x50, 0xd2, 0xc2, 0xa1, 0x05, 0x15, 0xd8, 0xc7, 0x45, 0x99, 0xb8, 0xb5,
+  0xb2, 0xf6, 0xbc, 0x3c, 0x5c, 0x83, 0xbf, 0x06, 0xf4, 0x76, 0xaf, 0xb1,
+  0x81, 0xea, 0x08, 0x02, 0xfc, 0x36, 0x24, 0x3d, 0x3d, 0x2b, 0x3b, 0xd6,
+  0xb7, 0xd0, 0x1b, 0x43, 0x12, 0x6c, 0x5f, 0x7c, 0xc9, 0x58, 0x37, 0x48,
+  0xb8, 0x57, 0x89, 0x61, 0x16, 0x55, 0x6d, 0x49, 0xa6, 0x66, 0x51, 0xb0,
+  0xc0, 0xd5, 0x3c, 0xad, 0x9f, 0xce, 0xfc, 0xb7, 0xba, 0x0f, 0x7f, 0x81,
+  0x6b, 0x06, 0x06, 0xa1, 0xd8, 0x00, 0x00, 0x85, 0x40, 0xa0, 0x84, 0x86,
+  0xc4, 0x00, 0xc2, 0xdd, 0xc2, 0x90, 0x3e, 0xa6, 0x55, 0x45, 0xbc, 0xe5,
+  0x9a, 0x80, 0x8a, 0x8b, 0x8b, 0xad, 0xbd, 0x96, 0xaa, 0x33, 0xc9, 0x36,
+  0x2e, 0xf1, 0x91, 0x94, 0xbc, 0xfe, 0x0f, 0x6e, 0x1e, 0x18, 0x1b, 0x84,
+  0x69, 0xa0, 0xb4, 0xb1, 0x98, 0x70, 0x78, 0x42, 0x58, 0x0b, 0x94, 0xde,
+  0xe3, 0x73, 0x94, 0xb4, 0xcd, 0x38, 0xee, 0x50, 0x34, 0x51, 0xab, 0x42,
+  0xc9, 0x2b, 0x99, 0xc6, 0xfd, 0xf1, 0x8d, 0x6c, 0xbc, 0x6d, 0x49, 0xac,
+  0x1f, 0x51, 0x6d, 0xb1, 0x10, 0x7a, 0x1c, 0xba, 0x88, 0x70, 0x81, 0x82,
+  0x5a, 0x89, 0x8a, 0x30, 0x82, 0x54, 0x8f, 0x4f, 0x7d, 0xeb, 0xf1, 0xef,
+  0x9e, 0x40, 0x1c, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x07, 0xff, 0xff, 0x07,
+  0x73, 0x62, 0x98, 0x49, 0x68, 0x26, 0x19, 0x84, 0x06, 0x99, 0x6d, 0x05,
+  0xdb, 0x20, 0x20, 0x28, 0x44, 0xa0, 0xe7, 0xe2, 0x62, 0xa7, 0xf4, 0xf2,
+  0x21, 0x0e, 0x57, 0x25, 0xbc, 0xda, 0xc8, 0x94, 0x58, 0xbe, 0x03, 0x98,
+  0xfe, 0x8f, 0xc1, 0x15, 0xfd, 0xa3, 0x44, 0xcc, 0x5e, 0xe3, 0x8e, 0x3e,
+  0xf8, 0xa1, 0x50, 0x83, 0xb1, 0xef, 0x2a, 0x6f, 0x65, 0x89, 0x4f, 0x99,
+  0x36, 0x5c, 0xf2, 0x54, 0x6a, 0xdf, 0x92, 0x23, 0xd6, 0xff, 0x4d, 0xf3,
+  0x8c, 0x5e, 0x3e, 0x98, 0x66, 0x28, 0x34, 0x4a, 0x72, 0x97, 0x08, 0x14,
+  0xb8, 0xcd, 0x14, 0x3d, 0x44, 0xb7, 0x6f, 0x85, 0x73, 0x98, 0x75, 0x45,
+  0x76, 0x66, 0xe3, 0x09, 0x89, 0xc5, 0x21, 0xf3, 0xba, 0x98, 0xd6, 0x84,
+  0xf3, 0xe3, 0x9d, 0x31, 0xb3, 0x9c, 0xb6, 0xa8, 0x50, 0x8c, 0x45, 0x8d,
+  0x3f, 0x46, 0xdd, 0x49, 0x56, 0x4e, 0xa4, 0x0d, 0xc6, 0x17, 0x0e, 0xc6,
+  0xfb, 0x24, 0x7e, 0xcb, 0x7c, 0x1a, 0x94, 0x20, 0x4f, 0x57, 0x1a, 0xc5,
+  0xa6, 0x00, 0xb9, 0xb9, 0xfc, 0x54, 0x0e, 0x13, 0xe0, 0x75, 0x9b, 0x22,
+  0x79, 0x7e, 0xbc, 0x85, 0x1d, 0xea, 0xa7, 0xbf, 0xd5, 0x8d, 0xec, 0xac,
+  0x82, 0xa9, 0x4c, 0xa0, 0xf3, 0x0c, 0x4f, 0x3b, 0xe1, 0xe6, 0x31, 0x83,
+  0x4e, 0x55, 0xb1, 0x1e, 0x93, 0xd9, 0xe0, 0xa4, 0xce, 0x9e, 0xaf, 0x0b,
+  0x45, 0xb7, 0x70, 0x7a, 0x55, 0x12, 0x14, 0xdb, 0x14, 0x92, 0xa7, 0x18,
+  0x1e, 0x69, 0x7c, 0x9b, 0x32, 0x00, 0x3f, 0x7f, 0x66, 0xa9, 0xb8, 0x7d,
+  0x69, 0xd1, 0xdf, 0x46, 0x95, 0xd7, 0x46, 0xd9, 0xab, 0x7c, 0xbe, 0x9d,
+  0xf9, 0xb9, 0xf7, 0x74, 0x88, 0xff, 0xd5, 0x40, 0x1e, 0xbf, 0x02, 0xd6,
+  0x22, 0x87, 0x60, 0x01, 0x28, 0x2a, 0x5d, 0x10, 0x14, 0x08, 0x8c, 0x00,
+  0x34, 0x4c, 0x73, 0xa4, 0xfc, 0x37, 0x92, 0x84, 0xe0, 0xce, 0x76, 0xa4,
+  0x33, 0xd6, 0xf4, 0xd0, 0x9f, 0x8a, 0xaa, 0xea, 0x86, 0x89, 0x16, 0xbc,
+  0x34, 0x6b, 0x23, 0x09, 0xa5, 0x2d, 0xf3, 0xb7, 0xf9, 0x47, 0x2a, 0xdf,
+  0x5d, 0x39, 0x5c, 0x30, 0x53, 0x0a, 0x69, 0x5d, 0x4d, 0x67, 0x78, 0xda,
+  0x3e, 0x5d, 0x66, 0x94, 0x8a, 0x43, 0x60, 0x0b, 0x98, 0xcd, 0xab, 0x54,
+  0x05, 0x06, 0x81, 0x8d, 0xb5, 0xa1, 0x99, 0xbc, 0x8d, 0xa1, 0x64, 0xd1,
+  0x76, 0x7d, 0x25, 0xd3, 0x47, 0xa2, 0xca, 0x64, 0xf2, 0x51, 0xd3, 0x7d,
+  0x36, 0x75, 0x69, 0x9b, 0xc1, 0x62, 0x23, 0x2c, 0x43, 0xdd, 0x9b, 0xe9,
+  0xe8, 0xdf, 0xd2, 0x00, 0xe0, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x03, 0xff,
+  0xff, 0x13, 0x6f, 0xa2, 0x31, 0x85, 0x8c, 0x43, 0x08, 0x68, 0x9d, 0x12,
+  0xe3, 0x2e, 0xca, 0x5e, 0x5e, 0x00, 0x05, 0xd5, 0xe0, 0xd6, 0x5f, 0x4c,
+  0xbb, 0xc6, 0x40, 0x65, 0xfd, 0x56, 0xdf, 0xfa, 0x77, 0x5d, 0xe0, 0x00,
+  0xd6, 0xec, 0x53, 0xa0, 0x27, 0x8d, 0x83, 0xc3, 0xf7, 0x1f, 0xf5, 0x79,
+  0xc3, 0x3b, 0xb3, 0xcb, 0x66, 0xf5, 0x9a, 0xbe, 0x08, 0x82, 0x33, 0x86,
+  0x7f, 0xf5, 0x24, 0x93, 0x8e, 0x56, 0xe2, 0xb9, 0xf9, 0x32, 0x5a, 0xec,
+  0x52, 0xc9, 0xf1, 0xc3, 0x1e, 0x83, 0xed, 0x5e, 0x35, 0xbe, 0xef, 0x01,
+  0xa5, 0xd5, 0x39, 0x0c, 0x78, 0x31, 0xa5, 0x00, 0xdf, 0xc5, 0x59, 0x1f,
+  0x0f, 0x12, 0xfc, 0xb3, 0x69, 0xce, 0xb7, 0x30, 0xb1, 0x0f, 0x91, 0x93,
+  0x16, 0x53, 0x6a, 0xe5, 0xb7, 0x71, 0xd8, 0x35, 0x96, 0x8b, 0xa8, 0x11,
+  0x3b, 0x81, 0x2e, 0xbc, 0xa1, 0x2c, 0x89, 0x56, 0x5c, 0xb5, 0xa6, 0x77,
+  0x29, 0x7b, 0xac, 0x08, 0x96, 0xf1, 0x42, 0xdc, 0x45, 0x16, 0xf6, 0x1d,
+  0x5e, 0x24, 0x15, 0xfd, 0x0c, 0x59, 0x44, 0xa1, 0x6a, 0xd5, 0xd2, 0x51,
+  0x8e, 0x33, 0xa4, 0x42, 0xd6, 0x5d, 0xd0, 0xf2, 0x94, 0xfa, 0x4f, 0x76,
+  0xfe, 0x03, 0xdb, 0x49, 0x78, 0x7a, 0xa2, 0x9b, 0xa3, 0x0d, 0xa4, 0xc5,
+  0x43, 0xb2, 0xaa, 0x5b, 0x2d, 0xad, 0x5f, 0x1b, 0xa5, 0x6c, 0xb5, 0xd9,
+  0x30, 0xd0, 0x98, 0xc9, 0x90, 0xcf, 0xa7, 0x4a, 0x89, 0x91, 0x9b, 0x04,
+  0x05, 0x36, 0xdb, 0x85, 0x3d, 0xf7, 0x67, 0xe6, 0xc3, 0x6c, 0x78, 0x67,
+  0xff, 0xfd, 0xfd, 0x5b, 0xe6, 0xff, 0x50, 0x0f, 0x9f, 0x93, 0x63, 0x10,
+  0xc3, 0xb0, 0x00, 0x02, 0xaa, 0xe1, 0x60, 0xa0, 0x48, 0xac, 0x06, 0xde,
+  0x02, 0x19, 0x30, 0x14, 0xdb, 0x64, 0xa2, 0xf8, 0x62, 0x6d, 0xd6, 0x12,
+  0x12, 0x5c, 0xa9, 0x73, 0x74, 0x55, 0x2a, 0xc4, 0xd5, 0xa3, 0x72, 0xad,
+  0xd3, 0xb6, 0xfa, 0x50, 0x4b, 0xd6, 0x8d, 0xd7, 0x68, 0x32, 0x85, 0xa9,
+  0xcd, 0x4f, 0x61, 0x10, 0x00, 0x02, 0x3c, 0xd8, 0xd9, 0x98, 0x24, 0x9e,
+  0x04, 0xd4, 0x41, 0x01, 0x24, 0xfa, 0xd0, 0x76, 0xea, 0x33, 0xf0, 0xee,
+  0x11, 0x04, 0x26, 0xa2, 0x45, 0xf3, 0x1a, 0xaa, 0x88, 0xaa, 0x8a, 0x82,
+  0x44, 0x7c, 0xf4, 0xc5, 0xfd, 0x53, 0xf6, 0x7f, 0xa9, 0xea, 0x7d, 0x5f,
+  0x6c, 0x38, 0x21, 0x1a, 0x88, 0x00, 0x03, 0xff, 0xff, 0xff, 0x09, 0x73,
+  0x63, 0x12, 0x10, 0x8c, 0x28, 0x12, 0x84, 0x16, 0x45, 0xe7, 0x4e, 0x5a,
+  0xf3, 0x59, 0x5a, 0x52, 0x80, 0x58, 0x25, 0x05, 0xa0, 0x6c, 0x98, 0x1c,
+  0x54, 0x80, 0x95, 0x29, 0x00, 0x83, 0xdd, 0x82, 0x1f, 0x1e, 0x1e, 0xc4,
+  0x49, 0x04, 0x8a, 0xd6, 0x51, 0x32, 0xc3, 0x99, 0x47, 0xb5, 0xbd, 0x8b,
+  0x10, 0xd1, 0x1b, 0xf7, 0x20, 0x12, 0x5a, 0x1f, 0x33, 0x75, 0xbe, 0xaa,
+  0xdf, 0x78, 0x87, 0x52, 0x42, 0x27, 0x9a, 0x1c, 0x8e, 0xdd, 0xf4, 0xe1,
+  0xe4, 0x2e, 0x29, 0x0e, 0x4a, 0xd5, 0xfe, 0xe3, 0x04, 0x56, 0x88, 0x65,
+  0xd3, 0x57, 0x3a, 0xd3, 0x8a, 0x7d, 0xdd, 0x14, 0xbf, 0xbf, 0x1a, 0xda,
+  0xe2, 0xfc, 0xf3, 0x71, 0xa9, 0x9e, 0x28, 0x56, 0xca, 0x25, 0x62, 0x95,
+  0x90, 0x9d, 0x3a, 0x4b, 0xe9, 0x4c, 0xe6, 0x8c, 0x92, 0x9d, 0x4f, 0x8f,
+  0xbb, 0xc3, 0xf4, 0x09, 0x2f, 0x4b, 0xdd, 0x2a, 0x86, 0xb9, 0x49, 0x68,
+  0x52, 0x11, 0x42, 0x27, 0x8e, 0x60, 0x55, 0x2c, 0xab, 0x25, 0x00, 0x8e,
+  0xc1, 0x05, 0xad, 0x08, 0x13, 0xda, 0x12, 0x83, 0x25, 0x17, 0x61, 0x02,
+  0x7a, 0xd4, 0x07, 0x41, 0xba, 0x00, 0x1a, 0xc1, 0x92, 0x20, 0x8a, 0x04,
+  0x6a, 0x4c, 0x43, 0x21, 0xb8, 0x92, 0x0d, 0xd7, 0xe1, 0xb4, 0xc5, 0x24,
+  0xc7, 0xc0, 0x9d, 0x9a, 0x99, 0x50, 0xa4, 0x32, 0x44, 0x37, 0x7d, 0xb3,
+  0xdc, 0x71, 0xc7, 0x9c, 0xbe, 0x72, 0x10, 0x94, 0xf2, 0xdc, 0x97, 0x4d,
+  0x00, 0xb6, 0x4a, 0xd6, 0x4d, 0x87, 0xb1, 0x07, 0x94, 0x4b, 0x2a, 0xe1,
+  0xe7, 0xa4, 0xa7, 0x18, 0xd9, 0xf2, 0x5a, 0x85, 0xab, 0x6a, 0x43, 0x29,
+  0x61, 0x4d, 0x82, 0x28, 0xa6, 0x84, 0x3b, 0xf2, 0x97, 0x6c, 0x09, 0x53,
+  0x68, 0x5f, 0x08, 0x46, 0x53, 0xfe, 0xf3, 0xe9, 0xdf, 0xd3, 0xdf, 0xf8,
+  0x80, 0x3d, 0x7c, 0x58, 0x44, 0x71, 0x4a, 0x09, 0x87, 0x01, 0x70, 0xec,
+  0x00, 0x2a, 0x24, 0xa4, 0x05, 0x00, 0x2c, 0x40, 0x69, 0x68, 0x96, 0x23,
+  0x2e, 0x57, 0x42, 0x22, 0xd1, 0xc9, 0xa4, 0x3b, 0xe1, 0x81, 0x73, 0xd6,
+  0x22, 0x73, 0x9c, 0x12, 0x29, 0x90, 0x30, 0x8a, 0x12, 0xde, 0x44, 0x44,
+  0xe0, 0x25, 0xa1, 0xed, 0x4d, 0x67, 0xc6, 0x93, 0xce, 0x8c, 0x08, 0x99,
+  0xb4, 0x4d, 0x3a, 0x5a, 0xfe, 0x52, 0x90, 0x5d, 0x3f, 0x1c, 0x56, 0x65,
+  0xe7, 0xaf, 0x91, 0x0a, 0xe8, 0xcb, 0x93, 0xe9, 0x3b, 0x72, 0x4a, 0x76,
+  0xd1, 0xa0, 0xbc, 0xb0, 0xe5, 0x0a, 0x77, 0x0c, 0x0c, 0x88, 0x26, 0xc2,
+  0xc4, 0x92, 0xbd, 0xd6, 0x12, 0x95, 0x36, 0x4a, 0x94, 0xc5, 0xe8, 0xf2,
+  0x8c, 0xd7, 0xca, 0x93, 0xcf, 0x54, 0x9d, 0x5d, 0xc2, 0x74, 0xef, 0xbe,
+  0xbc, 0x2d, 0x9f, 0x9d, 0xb7, 0xc2, 0xf3, 0xdd, 0xae, 0xd2, 0x50, 0x6e,
+  0x1c, 0x28, 0xcf, 0xc7, 0x8c, 0xc6, 0x19, 0xf6, 0xda, 0x9a, 0xb6, 0xbc,
+  0x17, 0x2b, 0xa8, 0xf1, 0xf6, 0x71, 0xf6, 0x80, 0x70, 0x21, 0x1a, 0x88,
+  0x00, 0x00, 0x7f, 0xff, 0xff, 0x0b, 0x6f, 0xa1, 0xd8, 0x58, 0xa8, 0x22,
+  0x2a, 0x19, 0x85, 0x02, 0x50, 0x80, 0x0f, 0x65, 0x8d, 0x2a, 0x5d, 0x4c,
+  0x20, 0x00, 0x93, 0x63, 0x1f, 0x84, 0x9c, 0x71, 0x11, 0x45, 0x32, 0x30,
+  0x47, 0x45, 0x10, 0x98, 0x49, 0x5b, 0x30, 0x98, 0x03, 0x6e, 0x83, 0xf3,
+  0xd2, 0xe8, 0xc8, 0x04, 0x1a, 0x8e, 0x56, 0x2f, 0x27, 0x61, 0x90, 0x7e,
+  0x77, 0xed, 0x3b, 0x14, 0x11, 0x9d, 0x37, 0x09, 0xa6, 0x2f, 0x4c, 0xff,
+  0xcb, 0xd9, 0xd0, 0x76, 0x56, 0x45, 0xd6, 0x95, 0x44, 0x3a, 0x99, 0xc7,
+  0x30, 0x7d, 0xcf, 0x2c, 0x9e, 0x9c, 0xca, 0x7b, 0x2c, 0x96, 0x4a, 0x7b,
+  0x6a, 0x85, 0x90, 0x6d, 0x07, 0xd1, 0xad, 0xfe, 0x69, 0x04, 0x95, 0xb5,
+  0xc7, 0x82, 0xac, 0xa6, 0x0f, 0x2c, 0xaf, 0x8b, 0xff, 0x5a, 0x72, 0x52,
+  0xd4, 0xbb, 0xf7, 0x73, 0x6e, 0x98, 0x53, 0xfd, 0x5b, 0xbb, 0xef, 0x86,
+  0x7e, 0xea, 0xf5, 0xec, 0xf0, 0xa7, 0xa5, 0xa6, 0xb9, 0x44, 0xde, 0x9c,
+  0x01, 0x6f, 0xd3, 0x59, 0x50, 0x28, 0x63, 0x7c, 0x56, 0x93, 0x15, 0x6a,
+  0x25, 0x3e, 0xac, 0x8f, 0xf0, 0x21, 0x56, 0xab, 0x1b, 0x09, 0xa9, 0xd9,
+  0xd8, 0x2c, 0xf6, 0x4f, 0xfd, 0x12, 0x35, 0x15, 0x1a, 0x69, 0xa7, 0x96,
+  0x43, 0x15, 0xc8, 0x51, 0xe5, 0x44, 0x98, 0x2b, 0x67, 0xf1, 0x26, 0x64,
+  0xfd, 0xd9, 0x1a, 0x32, 0x38, 0x1a, 0xb2, 0x54, 0xeb, 0x8d, 0x26, 0x03,
+  0x88, 0xd8, 0x60, 0x6d, 0x03, 0xc5, 0xd0, 0xce, 0x3d, 0x68, 0x31, 0x0a,
+  0x0a, 0xcc, 0xf8, 0x36, 0x19, 0xce, 0x00, 0x55, 0x46, 0x11, 0x85, 0x72,
+  0x4c, 0x27, 0x90, 0xdd, 0xd5, 0xbc, 0xdb, 0xc3, 0x3d, 0xb4, 0x63, 0x56,
+  0xe0, 0x51, 0x9f, 0x28, 0x7c, 0x45, 0xd6, 0x85, 0xe9, 0xf3, 0x26, 0x3c,
+  0x78, 0xf1, 0x69, 0x6d, 0x29, 0x6f, 0xdc, 0xd7, 0xda, 0xdd, 0x5f, 0x8b,
+  0x9f, 0x8f, 0x8f, 0x18, 0xdd, 0x5f, 0x4f, 0xd9, 0xaf, 0xf9, 0xfb, 0x3e,
+  0x60, 0x08, 0x0f, 0xa0, 0xc9, 0x04, 0xc1, 0x10, 0xec, 0x00, 0x00, 0x1d,
+  0x21, 0x32, 0xe8, 0x30, 0x65, 0xf2, 0x00, 0x27, 0x0d, 0x5f, 0xa7, 0x09,
+  0x2f, 0xf9, 0xef, 0x45, 0x6a, 0xde, 0x32, 0x88, 0x2a, 0x2c, 0xa4, 0x09,
+  0x86, 0x7d, 0x17, 0xc1, 0xc0, 0xce, 0x34, 0x05, 0xd5, 0x8d, 0xfe, 0x5f,
+  0xe3, 0xb7, 0x8f, 0x10, 0x54, 0xbf, 0xee, 0x96, 0xd3, 0xb7, 0x9c, 0x1f,
+  0x9d, 0x9c, 0x05, 0xe3, 0x28, 0xa9, 0xb3, 0x65, 0xf1, 0xf0, 0xb7, 0x4b,
+  0xfb, 0x74, 0xb1, 0x77, 0x59, 0xfd, 0xef, 0xaa, 0xd6, 0x26, 0x4b, 0xb2,
+  0x31, 0xfe, 0x6f, 0x75, 0x9c, 0x7a, 0x20, 0x15, 0x72, 0x88, 0x5b, 0x24,
+  0xf7, 0x3d, 0x44, 0x20, 0x0f, 0xd5, 0xc3, 0x1f, 0xb6, 0x01, 0xc0, 0x21,
+  0x1a, 0x88, 0x00, 0x00, 0x00, 0xff, 0xff, 0x11, 0x72, 0x83, 0x20, 0xc9,
+  0x4c, 0x45, 0x08, 0x03, 0x35, 0xf0, 0x95, 0xa3, 0x40, 0xa0, 0x00, 0x95,
+  0x26, 0xc7, 0xbc, 0xfe, 0xce, 0x77, 0x67, 0x15, 0xe7, 0x51, 0xd0, 0x22,
+  0x93, 0xc7, 0xa0, 0x56, 0x68, 0xfc, 0x7d, 0x79, 0xd1, 0x5e, 0xe5, 0xef,
+  0x7f, 0x3e, 0xc5, 0xa1, 0xa1, 0xfd, 0xe1, 0x9f, 0x9e, 0x2f, 0xf8, 0x45,
+  0x27, 0xb8, 0x3d, 0x72, 0x49, 0xfc, 0x97, 0xe3, 0x53, 0xf0, 0x77, 0x4f,
+  0x24, 0x55, 0x17, 0x9a, 0x9f, 0x69, 0xcc, 0x85, 0x86, 0xba, 0x61, 0x95,
+  0x5d, 0x83, 0xa9, 0xa9, 0x86, 0xac, 0xd3, 0x91, 0xe7, 0x32, 0x3d, 0xe4,
+  0xb4, 0xf1, 0x15, 0xd3, 0x72, 0xff, 0x0d, 0x96, 0x4b, 0x5b, 0xd3, 0x77,
+  0xc9, 0x21, 0x51, 0xf2, 0x53, 0x2d, 0x39, 0x49, 0xad, 0x19, 0xce, 0x6e,
+  0xed, 0x3a, 0xb0, 0x01, 0x30, 0xcf, 0x95, 0x4e, 0xaa, 0xd6, 0xca, 0x7a,
+  0x09, 0x37, 0x7e, 0x34, 0x6f, 0x99, 0x5d, 0xda, 0x45, 0x35, 0x6d, 0x7d,
+  0x92, 0x68, 0xd5, 0x71, 0x2f, 0x57, 0xce, 0x13, 0x52, 0xb8, 0x03, 0xce,
+  0x69, 0x64, 0xea, 0x6d, 0x6a, 0x57, 0xd0, 0xe8, 0x4e, 0x60, 0x3c, 0x84,
+  0xdc, 0xc3, 0x22, 0x6a, 0x3d, 0x20, 0x52, 0xfd, 0x60, 0x24, 0x3a, 0xee,
+  0xbf, 0xc0, 0xa6, 0x03, 0x77, 0xba, 0x72, 0x64, 0x4d, 0xa4, 0xdf, 0x3c,
+  0x3a, 0x73, 0x99, 0x63, 0x41, 0xe2, 0xf6, 0xf1, 0xfb, 0x0e, 0xde, 0x2e,
+  0x6b, 0x34, 0xf1, 0xd8, 0x30, 0xe2, 0x53, 0x4a, 0xa0, 0x4e, 0x79, 0xd0,
+  0x90, 0xf7, 0x9a, 0xcc, 0x43, 0x9e, 0x16, 0x34, 0xe5, 0x59, 0x6f, 0xd0,
+  0xd8, 0x0d, 0xb6, 0x8e, 0x36, 0x76, 0x4a, 0x9c, 0x6c, 0x18, 0xbd, 0xbd,
+  0x3e, 0x6d, 0xcd, 0x45, 0x5e, 0x6a, 0xda, 0xbc, 0x66, 0x2e, 0xbc, 0x7f,
+  0x1e, 0x3b, 0xe9, 0xd7, 0xd9, 0xe0, 0x00, 0xf9, 0xfb, 0x14, 0xa0, 0x98,
+  0x6a, 0x1d, 0x80, 0x00, 0x24, 0xa4, 0xa2, 0xb4, 0x30, 0x08, 0x60, 0x84,
+  0x96, 0xad, 0x8d, 0x8b, 0x55, 0xed, 0xb9, 0x5a, 0xa1, 0x0e, 0xd0, 0x80,
+  0x10, 0x41, 0x01, 0xcc, 0xac, 0x71, 0x19, 0xed, 0xbe, 0x5c, 0xd1, 0xa6,
+  0x32, 0x9a, 0xc5, 0xa6, 0x9c, 0xa5, 0x42, 0x99, 0x60, 0x15, 0x35, 0x74,
+  0xcf, 0x1e, 0x64, 0x09, 0x7e, 0x38, 0x2e, 0xa8, 0xa4, 0x0b, 0x2e, 0x09,
+  0x68, 0x9f, 0x6c, 0xf8, 0xe3, 0xd7, 0xd5, 0x34, 0x90, 0x6a, 0x09, 0x5e,
+  0x03, 0xdf, 0xb6, 0xab, 0xb0, 0xc1, 0xca, 0xea, 0xe5, 0x51, 0xaa, 0x79,
+  0x80, 0x74, 0x6e, 0xca, 0xcc, 0xa6, 0xf5, 0x7c, 0x7c, 0xf3, 0xea, 0xc7,
+  0xbf, 0x80, 0x07, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x07, 0xff, 0xff, 0x0f,
+  0x70, 0xa2, 0x31, 0x0d, 0x04, 0x56, 0x21, 0x84, 0x02, 0x3a, 0x5e, 0x81,
+  0xa5, 0x4a, 0xc0, 0x40, 0x22, 0x36, 0x39, 0x10, 0x82, 0xa0, 0x6d, 0x2a,
+  0xd0, 0xd2, 0xfb, 0x70, 0x58, 0x57, 0x72, 0xab, 0x06, 0xff, 0x1f, 0xd4,
+  0x3b, 0x3a, 0xb5, 0x21, 0x6a, 0x3c, 0x6f, 0x5e, 0x1d, 0xd6, 0x3d, 0xc7,
+  0x61, 0xcc, 0xc8, 0xd6, 0xfc, 0xc7, 0xe8, 0x39, 0xa7, 0xaa, 0x7a, 0x02,
+  0x53, 0x04, 0x8b, 0x8b, 0xc4, 0x6e, 0x56, 0xdd, 0x78, 0xae, 0xf9, 0xa6,
+  0xab, 0x18, 0x37, 0x87, 0x81, 0x6e, 0x08, 0x1f, 0xbd, 0xaa, 0x18, 0x73,
+  0xd0, 0x0b, 0x2c, 0x3d, 0xbe, 0x00, 0xd5, 0x90, 0x8d, 0x17, 0x00, 0xfc,
+  0xf0, 0x89, 0x49, 0x92, 0xf3, 0xcf, 0x77, 0xca, 0xbd, 0x9b, 0x37, 0x23,
+  0xcb, 0x38, 0xf9, 0x12, 0xa5, 0xd3, 0xf6, 0x9b, 0xd9, 0xa3, 0xf1, 0xdf,
+  0x8c, 0x54, 0xf8, 0xd3, 0xc5, 0xaa, 0xd5, 0x0d, 0x57, 0x76, 0x3d, 0xa2,
+  0x5c, 0xcd, 0x3a, 0xcc, 0xb8, 0x4e, 0x51, 0xd5, 0x20, 0x47, 0x44, 0x04,
+  0x23, 0xb0, 0x76, 0xd1, 0x8d, 0xab, 0x3a, 0x4d, 0x15, 0xa9, 0x75, 0xc5,
+  0x03, 0x53, 0x6e, 0x90, 0x39, 0x50, 0x98, 0x67, 0x00, 0x89, 0x3c, 0xc4,
+  0x64, 0x31, 0x73, 0xb0, 0xf5, 0x18, 0x7a, 0x38, 0xc4, 0xa3, 0x86, 0x78,
+  0xc3, 0x58, 0xc4, 0xea, 0x00, 0x61, 0x32, 0x18, 0x66, 0x45, 0x25, 0xf4,
+  0x82, 0xf7, 0xad, 0x26, 0xee, 0xdb, 0x9c, 0x6c, 0xc2, 0xa0, 0x8e, 0x54,
+  0x5d, 0xaa, 0xa8, 0xb6, 0x9c, 0xfb, 0xa5, 0xc3, 0xdf, 0xbe, 0x0b, 0xcc,
+  0x4a, 0x47, 0x77, 0x87, 0x66, 0xe5, 0xc7, 0xe3, 0xfe, 0x91, 0xea, 0xdf,
+  0x3a, 0x0f, 0x7f, 0x81, 0x62, 0x09, 0x86, 0xa1, 0xd8, 0x25, 0x00, 0x11,
+  0x52, 0xac, 0x00, 0x12, 0x00, 0x05, 0x20, 0x45, 0x27, 0x32, 0x10, 0x4f,
+  0x80, 0x13, 0x9a, 0x13, 0xb3, 0x48, 0x56, 0x53, 0x56, 0x11, 0x4b, 0x65,
+  0xc2, 0x2b, 0xc4, 0x46, 0x8b, 0xfd, 0x3f, 0xc1, 0x7e, 0x62, 0x8c, 0x72,
+  0x00, 0x77, 0xb3, 0xd9, 0x48, 0x24, 0x22, 0x01, 0xb6, 0x74, 0xf2, 0xee,
+  0x46, 0x83, 0xbe, 0xf3, 0x40, 0x22, 0x50, 0x91, 0xdd, 0x6e, 0x48, 0x54,
+  0x49, 0x70, 0x63, 0xf7, 0xa8, 0x22, 0x10, 0xaa, 0xbf, 0xca, 0x20, 0x58,
+  0x57, 0x9f, 0x7c, 0xd5, 0xed, 0xe1, 0xe8, 0xa6, 0xf9, 0x27, 0x76, 0xcb,
+  0x7e, 0xee, 0xff, 0x3f, 0xf1, 0x8c, 0xfd, 0x9c, 0xf8, 0x00, 0x70, 0x21,
+  0x1a, 0x88, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x13, 0x73, 0x62, 0x92, 0xd0,
+  0x4c, 0x28, 0x11, 0x84, 0x1c, 0x0b, 0x69, 0xd0, 0x59, 0x49, 0x80, 0x80,
+  0x42, 0x6c, 0x79, 0x3e, 0x06, 0x5a, 0x84, 0x44, 0x69, 0x97, 0x7b, 0x7b,
+  0x9c, 0x9a, 0x72, 0x66, 0x14, 0x0b, 0xe4, 0x3a, 0x17, 0x68, 0xf0, 0x49,
+  0xd4, 0x3e, 0xfc, 0xe7, 0x10, 0x90, 0x76, 0x25, 0xa4, 0x5e, 0x6c, 0x8a,
+  0xed, 0xe1, 0x72, 0x2f, 0xa4, 0xbe, 0x2e, 0x90, 0x75, 0x9b, 0xff, 0x83,
+  0x37, 0x2f, 0x38, 0x96, 0x7c, 0xd8, 0x9e, 0x2d, 0x6a, 0x42, 0xf6, 0x89,
+  0x60, 0x17, 0x97, 0x42, 0x75, 0x4e, 0x69, 0x73, 0xd3, 0xef, 0xf7, 0xc8,
+  0xcb, 0x38, 0x9b, 0xb0, 0xe3, 0xe9, 0x36, 0x53, 0x7e, 0xc4, 0x1d, 0xe7,
+  0xb2, 0xf3, 0x1d, 0x6d, 0xc7, 0x64, 0x4f, 0x7e, 0x8f, 0x31, 0x86, 0x9e,
+  0x59, 0x15, 0x47, 0xc3, 0xdc, 0x3e, 0x7b, 0xe9, 0xb6, 0x4b, 0xb9, 0x1f,
+  0x6d, 0x24, 0x2c, 0xc3, 0xa7, 0xc2, 0x40, 0x3a, 0x50, 0xb2, 0x03, 0xc1,
+  0x23, 0x04, 0x2a, 0x50, 0x7a, 0xbe, 0x76, 0x85, 0x44, 0x95, 0xc8, 0xc0,
+  0xab, 0xc5, 0x8e, 0x1c, 0x1c, 0x15, 0xd4, 0xf4, 0x42, 0xd1, 0x84, 0xe7,
+  0xc9, 0xa5, 0x7f, 0xad, 0x3d, 0x6b, 0x01, 0x76, 0x03, 0x94, 0xc8, 0xee,
+  0x16, 0x6a, 0xdd, 0x1e, 0x1b, 0x37, 0x42, 0x94, 0x1d, 0xfd, 0xaa, 0x62,
+  0xe1, 0xca, 0x2b, 0x28, 0x9c, 0x18, 0x2a, 0xea, 0x6c, 0x72, 0x6b, 0xee,
+  0x83, 0x26, 0xa8, 0x8b, 0x0a, 0x11, 0x94, 0x88, 0xa8, 0xe0, 0x00, 0xf4,
+  0xcf, 0xa5, 0x4a, 0xe4, 0xba, 0x96, 0x5b, 0x51, 0x21, 0x70, 0xd2, 0x9d,
+  0x72, 0x37, 0x9d, 0xe2, 0xc2, 0x31, 0xe6, 0x98, 0x52, 0x4a, 0x3a, 0x08,
+  0x92, 0x03, 0xc5, 0x92, 0xd3, 0x3f, 0x3d, 0xfd, 0x7f, 0xc4, 0x7f, 0xf7,
+  0x03, 0xe7, 0xd1, 0x08, 0x28, 0x22, 0xa0, 0x60, 0x6a, 0x1d, 0x80, 0x00,
+  0xa8, 0xad, 0x00, 0xc1, 0x01, 0x67, 0x21, 0x6b, 0x49, 0x77, 0x95, 0x97,
+  0x65, 0x15, 0xa9, 0xa1, 0xbf, 0x86, 0x57, 0x2a, 0x82, 0xee, 0x33, 0xa2,
+  0xd7, 0x97, 0xe0, 0x9e, 0xab, 0xb0, 0x46, 0xb5, 0xc8, 0x13, 0x71, 0x13,
+  0x03, 0x54, 0xf2, 0x91, 0x23, 0x41, 0x1e, 0x77, 0x2f, 0xe9, 0x50, 0x86,
+  0xc3, 0x13, 0x1d, 0x55, 0xa2, 0x59, 0x4e, 0x95, 0xb1, 0x54, 0x86, 0x03,
+  0x26, 0x8c, 0x2b, 0xe3, 0x52, 0x58, 0x7e, 0x7f, 0x93, 0x1c, 0x3a, 0x51,
+  0x1b, 0x61, 0xdc, 0xf2, 0x72, 0x98, 0xa9, 0xa9, 0x09, 0xd7, 0x22, 0xc9,
+  0xf3, 0x33, 0x93, 0xc5, 0x51, 0x53, 0x05, 0x44, 0xba, 0x73, 0x98, 0x00,
+  0xad, 0x8c, 0x67, 0x42, 0xfc, 0x9a, 0xb4, 0x8a, 0x74, 0x8d, 0xf1, 0x80,
+  0x4a, 0x2c, 0xb2, 0x3c, 0x68, 0xcd, 0xd6, 0xb3, 0x5d, 0x75, 0xe7, 0x00,
+  0x1c, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x0d, 0x6f, 0xa2,
+  0x41, 0x18, 0x48, 0x31, 0x4b, 0x11, 0xc2, 0x00, 0xbb, 0x58, 0xe0, 0x45,
+  0xd6, 0x2f, 0x08, 0x04, 0x26, 0x0b, 0x40, 0x24, 0x64, 0xd0, 0x26, 0x68,
+  0xa4, 0x2d, 0xc1, 0x24, 0xc9, 0xe4, 0x05, 0x20, 0x88, 0x01, 0xfb, 0xb9,
+  0x7d, 0x53, 0x30, 0x7e, 0xd9, 0xfb, 0xe2, 0x02, 0x06, 0xf2, 0xf2, 0x7c,
+  0x14, 0x3f, 0x5f, 0x45, 0x77, 0x86, 0xc0, 0x90, 0x72, 0x4f, 0x31, 0xc2,
+  0x77, 0x1c, 0x97, 0xb7, 0x27, 0x42, 0x75, 0x1a, 0x3d, 0xd9, 0x94, 0xf1,
+  0xaf, 0xe8, 0x9d, 0x3b, 0x4f, 0x56, 0x05, 0x75, 0xb4, 0xc1, 0xee, 0xfa,
+  0x42, 0xbd, 0x1e, 0x7b, 0xec, 0x39, 0x95, 0x41, 0xf3, 0x0f, 0x4d, 0x57,
+  0x53, 0x6a, 0xd7, 0x2c, 0xe0, 0x21, 0x30, 0xd9, 0x4f, 0x9c, 0xc7, 0xbe,
+  0x59, 0x05, 0x06, 0x00, 0x41, 0x98, 0xc8, 0xa8, 0x42, 0x06, 0x50, 0xac,
+  0x91, 0x51, 0xb4, 0xd2, 0x44, 0x3d, 0xcf, 0xdd, 0xe6, 0x0b, 0x0c, 0x41,
+  0xaa, 0x37, 0x91, 0xe0, 0x09, 0x14, 0xc0, 0x5d, 0xb5, 0xeb, 0xcf, 0x66,
+  0xfa, 0x0d, 0x91, 0xf6, 0x17, 0x68, 0x4a, 0x86, 0x48, 0xa4, 0xb7, 0xb1,
+  0x81, 0x69, 0x32, 0xf6, 0xd9, 0xbf, 0x44, 0xec, 0x33, 0xa1, 0xc9, 0x4c,
+  0xdd, 0xaf, 0x04, 0xe3, 0xf6, 0xe1, 0x59, 0xb9, 0xd7, 0x2c, 0x2f, 0xa3,
+  0x5d, 0xb3, 0xc8, 0x96, 0x25, 0x64, 0xac, 0x78, 0x53, 0xe7, 0x2f, 0x13,
+  0x8e, 0xd6, 0x80, 0x47, 0x40, 0x8a, 0x4e, 0x6a, 0xd4, 0xec, 0xef, 0xd8,
+  0xaf, 0x95, 0x96, 0x0d, 0x45, 0x35, 0xe8, 0x07, 0x0d, 0x29, 0x5e, 0xe7,
+  0xab, 0x8a, 0x89, 0x3d, 0xa2, 0xc1, 0x48, 0xa6, 0x03, 0x95, 0x12, 0x0e,
+  0x79, 0xf0, 0xab, 0xf9, 0xdb, 0x7f, 0xd7, 0xaa, 0xeb, 0x34, 0xfa, 0x7c,
+  0xba, 0x7a, 0xd2, 0x00, 0xf9, 0xfc, 0x14, 0xb1, 0x14, 0x3b, 0x00, 0x01,
+  0x2a, 0x54, 0xa1, 0x13, 0x45, 0x60, 0x59, 0x30, 0x6d, 0x8f, 0x38, 0x55,
+  0x33, 0x64, 0x3a, 0x43, 0x5d, 0x6b, 0x62, 0xff, 0x48, 0xc6, 0x34, 0x4f,
+  0xe8, 0xe7, 0xf8, 0xc6, 0x29, 0x40, 0x52, 0xbb, 0x94, 0x01, 0x2b, 0x8f,
+  0xf2, 0xae, 0xf2, 0x52, 0x97, 0xda, 0x53, 0x47, 0x3a, 0xb3, 0xc2, 0x34,
+  0x13, 0x0c, 0xe0, 0x41, 0x72, 0x80, 0x51, 0x82, 0xca, 0x34, 0x2c, 0xd5,
+  0xd4, 0xeb, 0x47, 0x5b, 0x4a, 0x57, 0x94, 0xdc, 0x22, 0x80, 0x25, 0xa0,
+  0xa5, 0xc6, 0xa8, 0xe1, 0xfb, 0xb0, 0xb5, 0x9d, 0x32, 0xd9, 0x37, 0xeb,
+  0xa6, 0x3f, 0x2d, 0xfb, 0x78, 0x7a, 0xf7, 0x18, 0xe4, 0x01, 0xc0, 0x21,
+  0x1a, 0x88, 0x00, 0x00, 0x00, 0xff, 0xff, 0x13, 0x72, 0x83, 0x21, 0x49,
+  0x0c, 0x45, 0x08, 0x13, 0x50, 0xe1, 0x15, 0xc1, 0xa2, 0x94, 0x00, 0x10,
+  0x9b, 0x15, 0xa1, 0xc8, 0x10, 0xbd, 0xda, 0x42, 0x90, 0xe8, 0x01, 0xe3,
+  0xc2, 0xf3, 0x31, 0x23, 0x8a, 0xd1, 0x37, 0xd4, 0x31, 0x9f, 0x3e, 0xd8,
+  0xa4, 0x33, 0x57, 0xb0, 0xfd, 0xfd, 0x50, 0x80, 0xc9, 0xaa, 0x20, 0x9f,
+  0x03, 0x4b, 0xd9, 0x30, 0x4f, 0x4b, 0xe3, 0x79, 0xf8, 0xae, 0x5d, 0x0f,
+  0x12, 0xcd, 0xad, 0x76, 0x1e, 0x91, 0x82, 0x59, 0x54, 0x21, 0xa7, 0x27,
+  0x2c, 0x24, 0x57, 0x13, 0x91, 0x24, 0x97, 0x4a, 0xaa, 0x2a, 0xa5, 0xe3,
+  0x78, 0xf9, 0xb4, 0xdf, 0x6f, 0x77, 0x8f, 0xfe, 0x8c, 0x7f, 0xd7, 0x3b,
+  0xc4, 0x4d, 0x02, 0xb3, 0x5b, 0x2c, 0xa2, 0xf2, 0xf8, 0x64, 0xd3, 0xb8,
+  0x6b, 0xb3, 0xa0, 0x13, 0xd8, 0x51, 0x3d, 0xc2, 0x12, 0xa2, 0xd2, 0x72,
+  0x33, 0xee, 0x6b, 0x20, 0x29, 0x65, 0x01, 0x49, 0x3a, 0x2e, 0xc8, 0x2e,
+  0x0d, 0x29, 0x5a, 0x6b, 0xe8, 0xd7, 0x59, 0xa3, 0x55, 0xde, 0xd5, 0xd3,
+  0x91, 0x84, 0x79, 0x72, 0x4a, 0x4e, 0x11, 0x1d, 0xa2, 0x90, 0xcc, 0x54,
+  0xc6, 0x92, 0x91, 0xb2, 0xd3, 0xa8, 0xc3, 0xb2, 0x14, 0x98, 0xc3, 0x74,
+  0xea, 0x32, 0xdf, 0x93, 0x80, 0x91, 0x75, 0x42, 0x84, 0xa5, 0x69, 0xd4,
+  0x01, 0x46, 0x28, 0xbb, 0xf8, 0x55, 0x24, 0xe3, 0x98, 0xee, 0xc9, 0xc6,
+  0xf7, 0x9a, 0x6e, 0x09, 0x9d, 0xe0, 0x2a, 0x57, 0x5a, 0x6d, 0xba, 0x72,
+  0x90, 0x66, 0x8a, 0x2c, 0x79, 0xb2, 0x6a, 0x86, 0x11, 0x2c, 0xc1, 0xf4,
+  0x47, 0x6e, 0x0b, 0x72, 0xd9, 0x6b, 0x01, 0xda, 0xe8, 0x00, 0x18, 0xe7,
+  0x83, 0x79, 0x5e, 0x36, 0x49, 0x4e, 0x1f, 0xd7, 0x1f, 0x7c, 0xe3, 0x7c,
+  0x7a, 0x40, 0x0f, 0x7f, 0xb1, 0x52, 0x0a, 0x04, 0xe1, 0xd8, 0x00, 0x09,
+  0x46, 0x5c, 0x54, 0x90, 0x50, 0x0b, 0xa0, 0x8d, 0xab, 0xa4, 0xc3, 0x34,
+  0x14, 0x95, 0xeb, 0x86, 0xfc, 0xe6, 0xa4, 0x44, 0x2a, 0xa2, 0x82, 0xc9,
+  0xec, 0x19, 0x33, 0x3b, 0xf0, 0xfc, 0x5a, 0x5b, 0xb9, 0x79, 0x9f, 0x5e,
+  0xb7, 0x77, 0xc3, 0x4b, 0xea, 0x29, 0x69, 0x71, 0x8f, 0x1a, 0x88, 0x7c,
+  0x73, 0x3d, 0x76, 0x4e, 0xf2, 0x83, 0x30, 0x11, 0xe1, 0x49, 0xf6, 0x7d,
+  0x15, 0x0e, 0x8f, 0x70, 0xc1, 0xde, 0xc3, 0x3e, 0x94, 0xe8, 0x5d, 0x00,
+  0xde, 0xbf, 0xbe, 0xd1, 0xbc, 0x4d, 0x0c, 0x6b, 0x98, 0x39, 0x48, 0xe1,
+  0x4e, 0x34, 0x61, 0x42, 0xf0, 0x7c, 0x4f, 0x1b, 0x4f, 0x57, 0xc4, 0xd1,
+  0xd2, 0xd8, 0x01, 0xc0, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x7f, 0xff, 0xff,
+  0x11, 0x6f, 0xa2, 0xc1, 0x08, 0xc8, 0x51, 0x0b, 0x12, 0x02, 0xa1, 0x00,
+  0x9a, 0x4d, 0x45, 0xaf, 0x38, 0xa4, 0xaa, 0x55, 0x80, 0x25, 0x49, 0x82,
+  0xa2, 0x05, 0x05, 0x52, 0x6f, 0x22, 0x70, 0x10, 0x21, 0x67, 0xe4, 0x90,
+  0x87, 0x0e, 0x8b, 0x5f, 0x59, 0x6a, 0xd9, 0x70, 0x1b, 0xc2, 0xa7, 0x1e,
+  0xe2, 0xe6, 0x8b, 0xac, 0x5b, 0x4d, 0xd6, 0x4d, 0x06, 0xb4, 0xcd, 0x18,
+  0xf2, 0xee, 0x71, 0xc1, 0x89, 0x35, 0x92, 0x33, 0x86, 0x73, 0x73, 0xbb,
+  0x76, 0x3a, 0x1c, 0xb9, 0x72, 0xcd, 0x35, 0x2e, 0xe6, 0x99, 0x4d, 0xef,
+  0x2b, 0xcf, 0x8e, 0xda, 0x67, 0xb1, 0x62, 0xd5, 0xbb, 0x1d, 0x4d, 0x6d,
+  0x96, 0xa1, 0xbc, 0xd5, 0x33, 0xb5, 0xdb, 0x43, 0xba, 0xc3, 0x90, 0xe0,
+  0x59, 0x8a, 0x6a, 0xe0, 0x45, 0x28, 0x54, 0xa8, 0xe3, 0x14, 0x68, 0x92,
+  0xa6, 0x47, 0x2a, 0x06, 0xea, 0x3f, 0x2d, 0x1b, 0x0c, 0x7e, 0x62, 0x18,
+  0xe2, 0x3b, 0x70, 0x33, 0x08, 0xd9, 0x0d, 0x50, 0xab, 0xb3, 0x33, 0xca,
+  0x26, 0xef, 0xf3, 0xc5, 0x78, 0xa1, 0x69, 0x80, 0x8e, 0x7a, 0x90, 0xc0,
+  0x8c, 0x18, 0x6e, 0x9e, 0x75, 0x3a, 0xc4, 0x31, 0xbb, 0x0d, 0x9e, 0xd8,
+  0x52, 0xcb, 0xf6, 0x1f, 0xc5, 0x86, 0x4b, 0xcf, 0x38, 0xe4, 0x14, 0xb0,
+  0x68, 0xbe, 0x0a, 0x60, 0x45, 0xf1, 0x10, 0xb0, 0xc9, 0x77, 0x3e, 0x69,
+  0x68, 0x20, 0x38, 0xa6, 0x63, 0xb3, 0x32, 0x0d, 0xc7, 0x76, 0x72, 0x40,
+  0x27, 0x22, 0x67, 0x31, 0xa4, 0x11, 0xa9, 0x7a, 0x2b, 0x46, 0xe6, 0xeb,
+  0x2b, 0x4a, 0x36, 0x98, 0xd2, 0xd2, 0xd8, 0x0d, 0x95, 0x54, 0x36, 0x3c,
+  0x2f, 0xea, 0x97, 0xb2, 0x83, 0xb8, 0xd5, 0xe8, 0xc4, 0x24, 0x39, 0x7b,
+  0x1e, 0x88, 0x93, 0xb2, 0x06, 0x45, 0xcf, 0x7e, 0xe5, 0x99, 0x52, 0x26,
+  0x37, 0x6b, 0x19, 0xea, 0xfa, 0x79, 0x7b, 0x2b, 0xa7, 0xd9, 0x00, 0x0f,
+  0x7f, 0x40, 0x0a, 0x10, 0x56, 0xa3, 0x81, 0x38, 0x76, 0x00, 0x02, 0x55,
+  0x44, 0x00, 0x00, 0x90, 0x22, 0x20, 0xc4, 0xd0, 0x6a, 0x50, 0x3d, 0xa2,
+  0x70, 0xfa, 0x38, 0x8d, 0x77, 0x99, 0x98, 0x00, 0x55, 0xf9, 0xf8, 0xe7,
+  0x42, 0x90, 0x2b, 0x8d, 0xca, 0x6b, 0xdd, 0x3a, 0xca, 0xbe, 0x62, 0xd4,
+  0x24, 0x4e, 0x8f, 0xc5, 0xfb, 0x52, 0xd0, 0xdb, 0x79, 0xee, 0x69, 0xa6,
+  0xee, 0xdd, 0x8b, 0x54, 0xef, 0xc5, 0xf8, 0xef, 0x45, 0x13, 0x3d, 0x6b,
+  0xa6, 0xee, 0x3b, 0x0b, 0x11, 0x98, 0xab, 0x94, 0x4c, 0x77, 0xab, 0xa2,
+  0xaf, 0x37, 0x6e, 0xda, 0x93, 0xed, 0x81, 0xc7, 0xcb, 0xaa, 0x75, 0xab,
+  0x8a, 0x24, 0x84, 0xc6, 0x3a, 0xd6, 0xb7, 0x39, 0xe8, 0x25, 0xe3, 0xb2,
+  0xc5, 0x9e, 0x5d, 0x16, 0x64, 0x66, 0x34, 0xdd, 0x54, 0xd3, 0x5c, 0x43,
+  0x2a, 0xf7, 0x1b, 0x93, 0xf7, 0xdc, 0x8d, 0x1e, 0xa7, 0x8b, 0x00, 0x1c,
+  0x21, 0x1a, 0x88, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x15, 0x6f, 0xa2, 0x41,
+  0x50, 0x82, 0x96, 0x22, 0x84, 0x1d, 0x04, 0x70, 0x2c, 0xbb, 0xaa, 0xba,
+  0xa0, 0x14, 0x5a, 0x6e, 0xc3, 0x78, 0xc9, 0xe2, 0xf0, 0xfb, 0x36, 0x31,
+  0x17, 0x82, 0xde, 0x31, 0x39, 0x01, 0xe1, 0x60, 0xd4, 0x80, 0xf4, 0x39,
+  0xf8, 0x34, 0x32, 0xbb, 0x0e, 0xce, 0x45, 0xd4, 0x2e, 0x76, 0xf1, 0x46,
+  0xaa, 0x90, 0x58, 0x77, 0x32, 0xf4, 0x56, 0x6a, 0xc9, 0x71, 0x8f, 0xa1,
+  0x43, 0xfc, 0x2c, 0xf3, 0x91, 0x92, 0xe5, 0x1a, 0x32, 0x11, 0x5f, 0xb1,
+  0xda, 0x40, 0xa1, 0x08, 0x93, 0x2f, 0xef, 0xdc, 0x63, 0x26, 0x46, 0x93,
+  0x5f, 0xb8, 0x5d, 0xbc, 0x50, 0xcc, 0x7e, 0x19, 0xf5, 0x77, 0x23, 0x4c,
+  0x98, 0xc2, 0x2f, 0x1a, 0xf3, 0xc4, 0x26, 0x1e, 0x0c, 0x6b, 0x74, 0x83,
+  0x17, 0x49, 0x25, 0x11, 0x3c, 0x17, 0x8d, 0x6c, 0x8d, 0xe7, 0x6e, 0x20,
+  0x33, 0xd4, 0x22, 0x3d, 0x24, 0xb8, 0xef, 0x42, 0x57, 0xf5, 0x9f, 0x07,
+  0x8b, 0x9c, 0x35, 0x43, 0xde, 0x9a, 0x85, 0x48, 0x97, 0x84, 0x61, 0x26,
+  0x4e, 0xd5, 0xce, 0xbd, 0xa4, 0xa7, 0x85, 0x06, 0x94, 0x3c, 0xc9, 0xa3,
+  0x62, 0x3e, 0x4a, 0xfa, 0xf2, 0x76, 0x5e, 0x77, 0x32, 0xfa, 0xab, 0x05,
+  0xe6, 0xe1, 0x79, 0xfe, 0x34, 0x88, 0x60, 0x64, 0x13, 0xda, 0x75, 0x08,
+  0x49, 0x6f, 0x16, 0x49, 0x4a, 0x59, 0x63, 0xd9, 0xd8, 0xd1, 0x4e, 0x19,
+  0x8c, 0xd6, 0x68, 0x03, 0x0b, 0xa9, 0x5a, 0x93, 0xc3, 0x68, 0xb5, 0x24,
+  0x17, 0xba, 0x82, 0x4a, 0x4e, 0x20, 0xa8, 0xf4, 0x00, 0xd8, 0x68, 0x14,
+  0xac, 0x53, 0x84, 0x5a, 0x91, 0x53, 0x44, 0xb1, 0x3e, 0x7a, 0xba, 0xab,
+  0xa7, 0xdf, 0xf1, 0x00, 0x3e, 0x7f, 0x05, 0x28, 0x26, 0x12, 0x87, 0x60,
+  0x00, 0x02, 0x52, 0x29, 0x2c, 0x18, 0x44, 0x50, 0xc5, 0x80, 0xb5, 0x38,
+  0x53, 0x97, 0x3a, 0x5a, 0x37, 0x9a, 0xb6, 0xc9, 0x47, 0x48, 0xab, 0xfd,
+  0x29, 0x9e, 0xb6, 0x45, 0xa9, 0x0b, 0x58, 0x2a, 0x9b, 0xf0, 0x60, 0x00,
+  0x99, 0x6f, 0xd9, 0xcf, 0x7a, 0xb0, 0x7c, 0xca, 0x5e, 0x49, 0x4f, 0xa4,
+  0xd0, 0x9a, 0x52, 0x8e, 0xae, 0x47, 0xe9, 0xd2, 0x49, 0xfc, 0x58, 0xd0,
+  0x14, 0xed, 0x78, 0x1a, 0x77, 0x63, 0x2f, 0x2d, 0xb4, 0x4f, 0x76, 0xbb,
+  0xac, 0xeb, 0xb3, 0x09, 0xac, 0x9f, 0x05, 0xa2, 0xdb, 0x6e, 0xf5, 0xf3,
+  0xec, 0xf8, 0x6f, 0x68, 0x00, 0xe0, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x00,
+  0xff, 0xff, 0x11, 0x6f, 0xa4, 0xa0, 0xc9, 0x4c, 0x43, 0x08, 0x05, 0xb4,
+  0x97, 0x6d, 0xf5, 0x51, 0x69, 0x80, 0x4a, 0x08, 0xa9, 0xb1, 0x5a, 0x34,
+  0x81, 0x00, 0x4c, 0xb1, 0x65, 0x39, 0xe4, 0x48, 0x1a, 0x0c, 0x33, 0x34,
+  0x4f, 0xb1, 0x7d, 0x81, 0xd3, 0x67, 0xa3, 0xb0, 0x7a, 0x4f, 0x57, 0xca,
+  0x83, 0xdd, 0x7c, 0x97, 0x46, 0x13, 0x20, 0x25, 0x11, 0xbe, 0xb2, 0xb8,
+  0xb6, 0x77, 0xe5, 0xc4, 0xbc, 0xaf, 0x2d, 0xe1, 0x98, 0x9a, 0xef, 0xef,
+  0xd7, 0xa5, 0x97, 0xa5, 0x4f, 0x06, 0xac, 0x50, 0xa9, 0xf8, 0x0b, 0x07,
+  0xb6, 0x55, 0x20, 0xf4, 0x91, 0xae, 0x29, 0xf5, 0xd8, 0xeb, 0x4d, 0x1e,
+  0x90, 0x93, 0x49, 0xe3, 0x06, 0xee, 0x95, 0x3b, 0x4e, 0xba, 0xf2, 0x81,
+  0x0f, 0x8b, 0x14, 0x06, 0x78, 0x67, 0xa4, 0x70, 0x69, 0x62, 0xcc, 0x54,
+  0xa5, 0xf1, 0xb3, 0xab, 0x99, 0x6a, 0xcd, 0x03, 0x91, 0xba, 0x52, 0xf6,
+  0xad, 0xfc, 0x76, 0x66, 0x1e, 0xc3, 0xfe, 0xaf, 0xa2, 0xee, 0x6a, 0x23,
+  0x48, 0x70, 0x3f, 0x45, 0x37, 0x65, 0xe3, 0x43, 0x10, 0x0d, 0x19, 0x86,
+  0x58, 0xc9, 0x37, 0x18, 0x0a, 0xcd, 0xa5, 0x25, 0x8a, 0xd6, 0x06, 0xf3,
+  0x2c, 0x1c, 0xc0, 0x81, 0xdd, 0x93, 0x87, 0x54, 0x17, 0xfd, 0xc9, 0x37,
+  0x05, 0x24, 0x18, 0x28, 0x96, 0xcc, 0xe7, 0x3c, 0x07, 0x94, 0xc6, 0xb8,
+  0xc2, 0x5a, 0xee, 0x77, 0xe6, 0x52, 0xa1, 0x21, 0xed, 0x27, 0xf9, 0x3e,
+  0x67, 0x56, 0xa3, 0x2a, 0x2b, 0x94, 0x45, 0x39, 0x0b, 0x9b, 0x38, 0xd7,
+  0x40, 0xd7, 0x5e, 0x0d, 0x52, 0xd1, 0x1c, 0x56, 0x45, 0x2a, 0x82, 0xc9,
+  0x26, 0x28, 0x66, 0xb1, 0x8a, 0x6d, 0x9d, 0x14, 0x67, 0xb2, 0x80, 0x21,
+  0x79, 0x83, 0x82, 0xee, 0xde, 0xdf, 0xff, 0x7b, 0xff, 0xb9, 0xf2, 0x20,
+  0xf9, 0xfb, 0x15, 0x20, 0x58, 0x66, 0x1d, 0x80, 0x94, 0x00, 0x15, 0x75,
+  0x2a, 0x00, 0x12, 0x56, 0x02, 0x75, 0xa1, 0x36, 0x87, 0x32, 0x31, 0x48,
+  0x9a, 0xc3, 0x32, 0xf2, 0x0b, 0xc0, 0xa5, 0x9d, 0x78, 0x62, 0xae, 0x8c,
+  0xd7, 0x4a, 0xeb, 0x16, 0x6e, 0xfd, 0x65, 0x0e, 0x56, 0xbc, 0x65, 0x38,
+  0xf5, 0x6b, 0xf1, 0xb7, 0xd7, 0x0a, 0x54, 0x3a, 0xf3, 0xaa, 0x44, 0x4f,
+  0x19, 0x05, 0xec, 0xe0, 0xdd, 0xd9, 0xcf, 0x58, 0x62, 0x1b, 0x0a, 0xd8,
+  0xba, 0xbc, 0x78, 0xf0, 0xe1, 0x62, 0xe7, 0x2c, 0xba, 0x3a, 0xa8, 0xa7,
+  0x30, 0x09, 0x4b, 0xc1, 0x26, 0x50, 0x92, 0xca, 0x47, 0x1a, 0x67, 0xff,
+  0xac, 0xff, 0x7b, 0xd1, 0xb6, 0x03, 0x07, 0x21, 0x1a, 0x88, 0x00, 0x00,
+  0x07, 0xff, 0xff, 0x17, 0x73, 0x82, 0xa0, 0x49, 0x6c, 0x54, 0x08, 0x0d,
+  0x2e, 0x5b, 0xa5, 0x38, 0x2d, 0x4a, 0x05, 0x02, 0xc5, 0x50, 0x91, 0x2e,
+  0xe8, 0x7d, 0x63, 0x95, 0x1a, 0x41, 0x48, 0xf1, 0xeb, 0xe2, 0x65, 0x4d,
+  0x88, 0x2e, 0xd4, 0xd9, 0x39, 0x08, 0x2e, 0x4e, 0xd9, 0xc8, 0xff, 0x47,
+  0xe1, 0xd9, 0x86, 0xcc, 0x25, 0x39, 0x55, 0xd2, 0x3b, 0x82, 0x8d, 0x43,
+  0xe9, 0xe9, 0xa4, 0xe1, 0x6a, 0x48, 0xe6, 0x9c, 0x58, 0xd5, 0xdc, 0x51,
+  0xbd, 0xfc, 0x33, 0x2d, 0x4b, 0xae, 0xf6, 0x2f, 0xb4, 0xeb, 0xbd, 0x71,
+  0xb0, 0x70, 0xa9, 0x0a, 0xa8, 0xcf, 0xb9, 0xed, 0xfc, 0xe8, 0x8d, 0xd5,
+  0x96, 0xe2, 0xb7, 0x36, 0x9b, 0xcd, 0xd9, 0xea, 0x14, 0xa1, 0x5b, 0x00,
+  0x5b, 0x64, 0x6d, 0x72, 0x0a, 0xd3, 0x48, 0xc4, 0xb7, 0xbb, 0xcc, 0xba,
+  0xac, 0xda, 0x17, 0x89, 0x4b, 0x95, 0x57, 0x05, 0x63, 0x7e, 0x3c, 0xaa,
+  0x75, 0xb8, 0x12, 0x44, 0xba, 0xc6, 0xd9, 0x36, 0xb9, 0xfb, 0x14, 0x78,
+  0x4e, 0x85, 0x2b, 0x73, 0xfc, 0xf6, 0x25, 0xde, 0x52, 0x7b, 0x75, 0x51,
+  0xb5, 0x3f, 0xeb, 0xd4, 0x0e, 0x88, 0x22, 0x42, 0x01, 0xe9, 0xd0, 0x56,
+  0xa9, 0x09, 0x31, 0x84, 0x9d, 0x67, 0xbd, 0x87, 0x08, 0x32, 0x50, 0xb9,
+  0xb1, 0x38, 0x10, 0x10, 0xeb, 0x75, 0x40, 0x44, 0x3d, 0x29, 0xfd, 0xb4,
+  0x6b, 0xd5, 0x7a, 0x55, 0x2c, 0xe6, 0x7d, 0x10, 0x9d, 0x0c, 0x4c, 0xd0,
+  0x6b, 0x32, 0x86, 0x40, 0x05, 0xaa, 0xd3, 0x10, 0x99, 0x82, 0x18, 0x1b,
+  0xa9, 0xdf, 0x2b, 0x2a, 0x04, 0x89, 0x45, 0xe6, 0x23, 0x42, 0x92, 0xae,
+  0xa4, 0xa6, 0x53, 0xb8, 0xe5, 0x98, 0x8c, 0xb9, 0xdd, 0x9a, 0x60, 0x45,
+  0x6d, 0x08, 0x52, 0x65, 0x23, 0x19, 0x96, 0xeb, 0xb0, 0xff, 0xe8, 0x9f,
+  0xfe, 0x51, 0xa7, 0x77, 0x77, 0xcf, 0xc0, 0x08, 0x56, 0x81, 0x61, 0x98,
+  0x76, 0x00, 0x00, 0x8a, 0x25, 0x80, 0xc2, 0x44, 0xc1, 0xf9, 0x77, 0xb6,
+  0xa6, 0xf5, 0xd1, 0x86, 0xe1, 0x56, 0x80, 0xd0, 0xa2, 0xa8, 0x27, 0xf4,
+  0xac, 0x5c, 0x42, 0x32, 0x8c, 0xca, 0x7a, 0x33, 0xec, 0xf3, 0x6c, 0xd0,
+  0x2d, 0x39, 0xca, 0x66, 0x84, 0x43, 0x1d, 0x3f, 0x03, 0x2d, 0xc5, 0xa2,
+  0x3e, 0x36, 0x2f, 0xe8, 0xc3, 0x37, 0x04, 0xe2, 0x74, 0x53, 0xae, 0x2d,
+  0x4d, 0x59, 0x4b, 0x6c, 0xad, 0x09, 0xa9, 0x02, 0xfb, 0x5d, 0x56, 0xe1,
+  0x6c, 0x77, 0xe4, 0xfd, 0x9d, 0x2c, 0xa3, 0xa2, 0x02, 0xe1, 0xeb, 0x80,
+  0x6e, 0x53, 0x53, 0xf3, 0xfb, 0xa7, 0xff, 0xfa, 0xfc, 0x9f, 0xfb, 0x10,
+  0xe0, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x07, 0xff, 0xff, 0x15, 0x73, 0x82,
+  0xaa, 0x08, 0xac, 0x43, 0x08, 0x0b, 0xb3, 0x4b, 0x89, 0xc5, 0x48, 0xab,
+  0xac, 0x00, 0x84, 0x4c, 0xd8, 0x26, 0x38, 0x17, 0x4c, 0x0b, 0xa4, 0x16,
+  0xe4, 0x9a, 0x20, 0x9f, 0x67, 0xc1, 0xcf, 0x51, 0x8b, 0xb2, 0xae, 0x82,
+  0x7a, 0x96, 0x46, 0xc4, 0x78, 0x7e, 0x1f, 0x28, 0x87, 0x8c, 0xb7, 0xb4,
+  0xae, 0x3f, 0xc4, 0x2d, 0x74, 0xe2, 0xb6, 0xc7, 0xec, 0x7e, 0x48, 0x98,
+  0x78, 0xaf, 0x46, 0x38, 0xd3, 0xa1, 0xaf, 0x5d, 0x79, 0x8e, 0x3b, 0x91,
+  0x28, 0x45, 0x37, 0x76, 0x3e, 0x8b, 0xa3, 0x29, 0xc4, 0xad, 0xa7, 0x6d,
+  0xe4, 0x89, 0xb1, 0x10, 0x68, 0x9b, 0xdd, 0xb3, 0xcc, 0x69, 0xfd, 0x0d,
+  0x4e, 0xb6, 0xd9, 0x0f, 0xef, 0x59, 0x2c, 0x34, 0xb7, 0xa8, 0xb2, 0xce,
+  0x6d, 0xcd, 0x0d, 0x94, 0x58, 0xf8, 0xb7, 0x95, 0xcb, 0xba, 0x54, 0x55,
+  0x25, 0x9f, 0x51, 0x20, 0xcd, 0xd4, 0x70, 0x8b, 0xc5, 0xfd, 0x64, 0xc4,
+  0x4e, 0xd7, 0xa3, 0xb5, 0xd9, 0xd7, 0xc2, 0x65, 0x29, 0xe1, 0x59, 0x1a,
+  0xd9, 0x69, 0xb2, 0x2e, 0x58, 0x4b, 0x17, 0x4c, 0x37, 0x4b, 0x46, 0xd6,
+  0xad, 0xae, 0x82, 0xc9, 0x40, 0x52, 0x97, 0x48, 0x64, 0x95, 0x95, 0x50,
+  0x0d, 0x42, 0x18, 0x6e, 0xb1, 0x78, 0x73, 0x24, 0xce, 0xb0, 0x10, 0x0c,
+  0x14, 0xc0, 0x5c, 0xaa, 0x3d, 0xb8, 0xae, 0x54, 0x19, 0x53, 0x67, 0xed,
+  0x1c, 0x29, 0x17, 0x8c, 0x6d, 0x0c, 0x8a, 0x2d, 0x12, 0x14, 0x3c, 0xb2,
+  0xb1, 0x33, 0x95, 0x4a, 0x08, 0xb6, 0xd6, 0xce, 0xe2, 0x11, 0x7f, 0x0b,
+  0x16, 0x86, 0xc7, 0x5b, 0xea, 0xaf, 0x05, 0xfd, 0xe5, 0x49, 0x3e, 0x13,
+  0x4b, 0xde, 0xa9, 0x95, 0x0a, 0x73, 0xd2, 0x27, 0x12, 0x47, 0x37, 0xc0,
+  0xe2, 0x5f, 0xeb, 0x36, 0x3e, 0x05, 0xc1, 0xf7, 0xf0, 0x2b, 0x21, 0xb0,
+  0xcc, 0x3b, 0x00, 0x00, 0x2a, 0x0b, 0x00, 0x02, 0xb5, 0xc8, 0xe1, 0x39,
+  0x30, 0xfb, 0x91, 0x85, 0x8b, 0xa3, 0xbe, 0x8e, 0xf6, 0x20, 0x77, 0xa6,
+  0x76, 0xf2, 0x62, 0x42, 0x2d, 0x76, 0x9d, 0x80, 0x5e, 0xb0, 0x6f, 0xd8,
+  0xbd, 0x2b, 0xc8, 0x0e, 0x96, 0xbd, 0x04, 0x69, 0xf2, 0xd4, 0x90, 0x82,
+  0x17, 0x8b, 0xed, 0x39, 0x05, 0xfb, 0x6d, 0xd2, 0x81, 0xd3, 0xb7, 0xe1,
+  0xb5, 0x29, 0x80, 0xc2, 0xd9, 0x28, 0x2b, 0x51, 0x40, 0xac, 0x24, 0x53,
+  0x79, 0xa0, 0x89, 0x22, 0xa7, 0x34, 0x52, 0xf0, 0xd5, 0xf7, 0xca, 0x26,
+  0xd6, 0xfc, 0x66, 0xcb, 0xf1, 0xfa, 0xc2, 0xec, 0x76, 0xfe, 0xe7, 0xfa,
+  0x20, 0xe0, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x01, 0xff, 0xff, 0x19, 0x6f,
+  0xa1, 0xc1, 0xd0, 0x44, 0x45, 0x09, 0x15, 0x88, 0x61, 0x04, 0x96, 0x70,
+  0x95, 0x73, 0x53, 0x38, 0xab, 0x14, 0x00, 0x10, 0xc1, 0x82, 0x92, 0x5c,
+  0x77, 0x31, 0x73, 0x06, 0x4e, 0x11, 0x17, 0xb2, 0xcf, 0x37, 0xe7, 0x30,
+  0x30, 0x7e, 0x02, 0xf5, 0xe2, 0x37, 0xbe, 0x33, 0xed, 0x3f, 0x1a, 0xb5,
+  0xb2, 0x6a, 0x40, 0x79, 0x84, 0xba, 0x4b, 0x6e, 0xf3, 0xda, 0xf6, 0x0b,
+  0x5e, 0xaf, 0xcc, 0x38, 0xe1, 0xb8, 0xee, 0xab, 0xe0, 0x0f, 0xe5, 0x2a,
+  0x4b, 0x45, 0x4b, 0x23, 0x53, 0x80, 0xce, 0x99, 0xab, 0xbe, 0x26, 0xea,
+  0x39, 0x8b, 0x37, 0xbc, 0x6a, 0x4e, 0x1b, 0x23, 0x00, 0xcf, 0x76, 0x5f,
+  0x14, 0x66, 0xeb, 0xf8, 0x2f, 0xec, 0xc8, 0x9d, 0x23, 0x0c, 0x7a, 0xf2,
+  0xd7, 0x6f, 0x42, 0x7f, 0x8e, 0x7c, 0xdb, 0x18, 0x9e, 0x36, 0xb2, 0x38,
+  0xae, 0x67, 0x00, 0x74, 0x0b, 0x64, 0x8c, 0xd0, 0x63, 0xd1, 0x2e, 0x75,
+  0xb9, 0x45, 0x01, 0xf8, 0xe0, 0x33, 0xcb, 0x2e, 0x93, 0x63, 0xa1, 0x14,
+  0x89, 0x19, 0x3e, 0xaf, 0x36, 0xc3, 0xf9, 0x02, 0xf3, 0xe0, 0x95, 0x77,
+  0xab, 0x99, 0xa6, 0xc7, 0x54, 0xe0, 0x58, 0xb8, 0xa0, 0x83, 0x22, 0xd0,
+  0xa5, 0x82, 0x5b, 0x28, 0x44, 0xaf, 0xa2, 0xc9, 0xff, 0x56, 0x73, 0xa9,
+  0x14, 0xcc, 0x3d, 0x45, 0x80, 0xe3, 0xa4, 0x6d, 0x36, 0x26, 0x17, 0xa8,
+  0x05, 0x52, 0xa3, 0xf4, 0xa6, 0x74, 0xdc, 0xa5, 0x1c, 0x74, 0x83, 0x20,
+  0x21, 0x33, 0x8a, 0x1e, 0x20, 0x16, 0x19, 0x89, 0x26, 0x05, 0xca, 0xeb,
+  0x6c, 0x6d, 0x52, 0xf5, 0x1b, 0x5d, 0xcf, 0xaa, 0x48, 0x96, 0x8b, 0x12,
+  0x6a, 0x80, 0xae, 0xee, 0xb2, 0x97, 0x53, 0x64, 0x10, 0xc2, 0x1a, 0xc9,
+  0x9a, 0xac, 0xfe, 0x17, 0xe0, 0x3a, 0x9e, 0xe0, 0x3f, 0x7e, 0x85, 0x68,
+  0x43, 0x0e, 0xc0, 0x02, 0x51, 0x2a, 0xa0, 0x93, 0x40, 0x28, 0x32, 0x06,
+  0xd6, 0x85, 0xa9, 0x41, 0x41, 0x21, 0x1b, 0x57, 0x7a, 0xf2, 0x90, 0xa3,
+  0x3a, 0x8d, 0x51, 0xab, 0x52, 0xb0, 0x78, 0x29, 0xd8, 0x4e, 0x87, 0x5c,
+  0x98, 0x69, 0x55, 0x96, 0xcd, 0x58, 0x96, 0x33, 0x29, 0xfb, 0x37, 0xd3,
+  0x91, 0x8d, 0xe2, 0xa6, 0xf7, 0x1e, 0x28, 0xb8, 0xa7, 0x1a, 0xb7, 0x3d,
+  0x23, 0xf7, 0xef, 0x8a, 0x82, 0xc7, 0x16, 0xc7, 0xc4, 0x11, 0xd4, 0x06,
+  0x53, 0xda, 0x93, 0x2f, 0x9b, 0xf6, 0x4a, 0x4e, 0x2c, 0x2f, 0x4b, 0xe3,
+  0x3f, 0x3f, 0x50, 0xe0, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x3f, 0xff, 0xff,
+  0x1d, 0x73, 0x82, 0xa0, 0xc9, 0x28, 0x26, 0x1a, 0x84, 0x2e, 0xd3, 0xab,
+  0x21, 0x1c, 0x25, 0xd4, 0x9b, 0x00, 0x05, 0xab, 0x07, 0xdc, 0xc9, 0x42,
+  0x2d, 0x40, 0x1a, 0x04, 0x92, 0xfa, 0x39, 0x7e, 0x55, 0x13, 0x8b, 0x43,
+  0x58, 0x83, 0xe1, 0xd8, 0x20, 0xec, 0x0f, 0xd4, 0xc9, 0x5d, 0x2b, 0xd2,
+  0x3f, 0x94, 0x27, 0x38, 0xd9, 0xd5, 0x12, 0x0e, 0xb7, 0xed, 0x5b, 0x25,
+  0xf5, 0xab, 0xa2, 0x5b, 0xa3, 0xbd, 0xa3, 0x1c, 0xe5, 0x91, 0xdb, 0xf8,
+  0x5b, 0xb6, 0x8c, 0x9b, 0xa6, 0x52, 0x39, 0xa3, 0x96, 0x28, 0x64, 0xc5,
+  0x65, 0x68, 0x0d, 0x5a, 0x32, 0x30, 0xc9, 0x34, 0xc0, 0x8e, 0x85, 0xab,
+  0xee, 0xe7, 0xf0, 0xc8, 0x91, 0xc7, 0x03, 0x79, 0xbd, 0xfb, 0x3b, 0x72,
+  0xb8, 0xd0, 0xd2, 0x4f, 0xde, 0xe9, 0x5d, 0xc9, 0xaa, 0x7d, 0xb9, 0x83,
+  0x5e, 0xa2, 0x51, 0x15, 0x6d, 0xea, 0x6b, 0xb2, 0x3b, 0xbe, 0xc6, 0xbf,
+  0x6b, 0x54, 0xd6, 0xd3, 0x22, 0x48, 0x11, 0xd6, 0x3b, 0xd6, 0x1a, 0xeb,
+  0xbc, 0xc3, 0x9b, 0x07, 0x05, 0xd3, 0xcc, 0x78, 0x66, 0x30, 0x5e, 0x6b,
+  0xc0, 0x18, 0x18, 0xcd, 0xde, 0x26, 0x1b, 0x56, 0x17, 0xee, 0x0f, 0x19,
+  0x1c, 0xe7, 0xa5, 0xcb, 0x18, 0x47, 0x61, 0xb0, 0x65, 0xba, 0x4e, 0x4e,
+  0x21, 0x5f, 0x7e, 0xf2, 0x6e, 0xaf, 0x30, 0x13, 0x2f, 0x90, 0xee, 0xb1,
+  0x99, 0xcd, 0x6a, 0x0f, 0xce, 0x0d, 0xd4, 0x80, 0x10, 0x02, 0xab, 0xc6,
+  0x58, 0x7b, 0xba, 0x32, 0x86, 0x79, 0x2c, 0x55, 0xf3, 0xfe, 0x99, 0x03,
+  0x79, 0x7a, 0x48, 0x57, 0x7c, 0xc7, 0xa0, 0x52, 0xed, 0x2f, 0x87, 0x9a,
+  0xc6, 0xf3, 0x0d, 0xa5, 0x2c, 0xd9, 0xc9, 0x9f, 0xb9, 0xff, 0x58, 0x87,
+  0x66, 0x22, 0x21, 0x32, 0x48, 0x3a, 0x3e, 0x9a, 0x69, 0x95, 0xae, 0xd7,
+  0x5c, 0xe3, 0x97, 0x4f, 0x68, 0x01, 0xef, 0xea, 0x83, 0x16, 0xb1, 0x1c,
+  0x3b, 0x00, 0x00, 0xa8, 0xa0, 0x00, 0x10, 0x8a, 0x17, 0xa3, 0x62, 0xcc,
+  0x8b, 0xf2, 0x6d, 0x27, 0xc9, 0xc9, 0x40, 0x2f, 0x2b, 0x27, 0xc8, 0xba,
+  0x32, 0x90, 0x1b, 0x96, 0x8a, 0xd8, 0x6c, 0xa5, 0xca, 0x2f, 0x7a, 0x44,
+  0x1d, 0x93, 0x9a, 0x4a, 0x8d, 0x0d, 0x6e, 0x71, 0x92, 0xc5, 0x3c, 0x1a,
+  0x89, 0xfa, 0xa1, 0x08, 0xdf, 0x76, 0x8d, 0x59, 0xb4, 0x7d, 0x83, 0x1a,
+  0x39, 0x6d, 0x9f, 0xd7, 0xbb, 0xf6, 0x41, 0xa6, 0x04, 0x26, 0x71, 0x38,
+  0x5f, 0x3d, 0x46, 0x33, 0xb9, 0x3c, 0xc2, 0x5b, 0x20, 0xcc, 0xec, 0xfc,
+  0x53, 0x5b, 0x59, 0xa8, 0xa6, 0xc7, 0xc9, 0x26, 0x2f, 0x76, 0x0b, 0x45,
+  0x92, 0xc9, 0xfc, 0xa6, 0x42, 0x19, 0x74, 0xa6, 0x25, 0x3e, 0xe1, 0xbf,
+  0x67, 0x6f, 0x6b, 0xe8, 0x6b, 0x5b, 0x4e, 0x33, 0x80, 0x0e, 0x21, 0x1a,
+  0x88, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x19, 0x73, 0x82, 0x30, 0xd0, 0x66,
+  0x22, 0x32, 0x05, 0x86, 0xa1, 0x05, 0x69, 0x4b, 0xf8, 0x14, 0xe1, 0x68,
+  0x28, 0x00, 0x22, 0x04, 0xfa, 0xb9, 0xfc, 0xdc, 0xef, 0xf9, 0xfc, 0x1d,
+  0xad, 0x64, 0xa1, 0x1b, 0xc0, 0x36, 0x45, 0x1f, 0x4d, 0xcb, 0x62, 0xa7,
+  0x73, 0xa0, 0x2c, 0x1f, 0x84, 0xd5, 0x94, 0xef, 0x74, 0x6a, 0x1c, 0xe5,
+  0xcc, 0xfb, 0x0c, 0x59, 0xb2, 0xe8, 0x05, 0x0a, 0x0a, 0x89, 0x9e, 0x83,
+  0xb1, 0x65, 0x32, 0x28, 0x53, 0x1a, 0x41, 0x49, 0xab, 0xb8, 0xac, 0x45,
+  0xcd, 0xbf, 0x99, 0xa6, 0x2c, 0xbd, 0x48, 0xe2, 0xc6, 0x26, 0x5c, 0x03,
+  0xb4, 0xa7, 0x73, 0xb5, 0xee, 0xca, 0x6b, 0x9c, 0xe1, 0x6c, 0x4a, 0x93,
+  0x4a, 0x82, 0x93, 0xb2, 0x66, 0xd8, 0x66, 0x0c, 0x86, 0xde, 0x6b, 0x37,
+  0x17, 0x4e, 0x94, 0x71, 0xa7, 0x1e, 0xef, 0x53, 0x86, 0x65, 0x4d, 0x50,
+  0x97, 0xaa, 0x6e, 0x4f, 0x5d, 0xbc, 0x1a, 0x77, 0xb6, 0xda, 0x31, 0x4a,
+  0x1d, 0xa7, 0x9e, 0xd0, 0x22, 0x38, 0x58, 0x68, 0x7a, 0x01, 0x15, 0x95,
+  0x5c, 0xc5, 0x9d, 0xd2, 0xae, 0xdb, 0xb1, 0x54, 0x9e, 0xcb, 0x2e, 0x23,
+  0xb5, 0x96, 0xd5, 0xd2, 0x5a, 0x91, 0xea, 0xcf, 0x23, 0x46, 0x85, 0xeb,
+  0xd1, 0xbc, 0x67, 0xbf, 0x14, 0x7a, 0x9f, 0xac, 0xa5, 0x31, 0x80, 0x3e,
+  0x10, 0x7c, 0x76, 0x21, 0xe9, 0x55, 0x02, 0x0d, 0x22, 0xd4, 0x80, 0xac,
+  0x00, 0x8b, 0x1a, 0x92, 0x84, 0xe1, 0xb5, 0x39, 0x8c, 0xc9, 0x6f, 0x00,
+  0x7f, 0x61, 0xbe, 0xb6, 0x1c, 0xc2, 0x0d, 0xf4, 0x02, 0xac, 0xcc, 0x00,
+  0x5c, 0x18, 0x2a, 0x60, 0x42, 0x7b, 0x2c, 0x11, 0xc7, 0xf0, 0x44, 0x56,
+  0x37, 0x3e, 0xa9, 0xf9, 0x51, 0xc3, 0x66, 0xb9, 0x83, 0xb7, 0x1e, 0x9f,
+  0x9a, 0x24, 0x00, 0xfb, 0xfc, 0x14, 0xa0, 0x58, 0x66, 0x1d, 0x80, 0x00,
+  0x54, 0xa9, 0x2a, 0x54, 0x99, 0x61, 0x82, 0xc0, 0x2b, 0x1a, 0x7e, 0xba,
+  0xa9, 0x7b, 0x44, 0x5d, 0x15, 0x21, 0xae, 0x4b, 0x41, 0x25, 0xb4, 0x48,
+  0x70, 0xe8, 0x72, 0x99, 0x7b, 0x2a, 0x41, 0x72, 0x49, 0x3c, 0x32, 0xb8,
+  0x87, 0x80, 0x5a, 0x48, 0xe3, 0x0c, 0x74, 0xb7, 0xf2, 0x06, 0xc9, 0x44,
+  0x3d, 0x2c, 0xd5, 0x8d, 0x06, 0x38, 0xc4, 0x53, 0x42, 0xa5, 0xd7, 0xda,
+  0x2e, 0x16, 0x45, 0x8a, 0xf2, 0xb0, 0xd2, 0x97, 0x64, 0x66, 0x18, 0xa3,
+  0xc0, 0x6a, 0x09, 0xc3, 0xef, 0xdd, 0x5c, 0x3c, 0x80, 0xe0, 0x21, 0x1a,
+  0x88, 0x00, 0x00, 0x00, 0xff, 0xff, 0x19, 0x6f, 0xa4, 0xa1, 0x09, 0x2c,
+  0x43, 0x09, 0x1c, 0xf0, 0x54, 0xea, 0x5a, 0xd2, 0xda, 0x54, 0x94, 0x28,
+  0x10, 0x25, 0x60, 0xdd, 0x35, 0x84, 0x9f, 0xbf, 0xe2, 0xd7, 0x35, 0x57,
+  0x2b, 0x9c, 0x8c, 0x35, 0x5e, 0x53, 0xd4, 0xb2, 0x22, 0x20, 0x0e, 0x29,
+  0xd5, 0x75, 0xb8, 0xff, 0x07, 0xf0, 0xaf, 0x7c, 0x0d, 0xb3, 0xcb, 0x5e,
+  0x7d, 0xc3, 0xda, 0x73, 0xe3, 0x93, 0xc8, 0x79, 0xbf, 0xd8, 0x66, 0x29,
+  0x1a, 0xff, 0xa4, 0xd2, 0xc7, 0xd7, 0xd7, 0xe5, 0xac, 0xd5, 0xbd, 0xe6,
+  0x7c, 0xaf, 0x15, 0xf7, 0x93, 0xb7, 0x28, 0x2e, 0xcf, 0x01, 0x43, 0x26,
+  0xa3, 0x8e, 0xf0, 0x38, 0xaa, 0xdf, 0xc4, 0x24, 0x1e, 0x72, 0xfd, 0x8b,
+  0x25, 0x20, 0x81, 0x7f, 0x3a, 0xc2, 0xaf, 0x32, 0x30, 0xb1, 0x13, 0x93,
+  0x49, 0x1b, 0x7b, 0x8a, 0x61, 0x0b, 0x28, 0xa4, 0x49, 0x22, 0x1d, 0xa4,
+  0x3d, 0x48, 0xd3, 0x7a, 0xd3, 0x20, 0xaf, 0x84, 0x33, 0xa0, 0x37, 0x9f,
+  0x44, 0x4e, 0xb3, 0xd4, 0x7e, 0xed, 0x62, 0x8b, 0xa9, 0xd0, 0x7f, 0xb7,
+  0xc8, 0xaf, 0xa0, 0xb6, 0xc9, 0x05, 0xe0, 0x69, 0x3d, 0x40, 0x0e, 0x82,
+  0x41, 0x50, 0xc2, 0x37, 0x07, 0x30, 0xa9, 0xff, 0x47, 0xd6, 0x75, 0x33,
+  0xf7, 0x67, 0x5c, 0x37, 0x18, 0x0a, 0xde, 0x84, 0x99, 0x7d, 0x29, 0x08,
+  0x33, 0xc0, 0xcf, 0x09, 0xbf, 0x3a, 0x22, 0x3b, 0x5a, 0xf3, 0xfa, 0x03,
+  0xde, 0xc7, 0xa4, 0xd5, 0x3f, 0x34, 0xbd, 0x6a, 0xfe, 0xfe, 0xbb, 0x35,
+  0x10, 0x58, 0x04, 0x25, 0x00, 0x22, 0xce, 0x6d, 0xb5, 0xc0, 0x23, 0xbe,
+  0x94, 0xdf, 0xa8, 0x0a, 0xca, 0x15, 0x2a, 0x27, 0xe7, 0xde, 0x99, 0x61,
+  0x31, 0x35, 0xe9, 0xda, 0x15, 0xd8, 0xf8, 0x31, 0xd8, 0x5c, 0xf2, 0xc0,
+  0xb6, 0xcb, 0x18, 0x86, 0x19, 0x3c, 0xa7, 0xc7, 0xbd, 0x00, 0x3f, 0x7e,
+  0xc5, 0x04, 0x36, 0x18, 0x87, 0x60, 0x00, 0x04, 0xa1, 0x6c, 0xd0, 0x01,
+  0x0e, 0x42, 0x3d, 0x40, 0x66, 0x95, 0xd4, 0xb8, 0x11, 0xb1, 0xbf, 0xbb,
+  0xa2, 0xcc, 0x1c, 0xab, 0xd1, 0x2b, 0xa1, 0xf3, 0x13, 0x22, 0xcd, 0xdb,
+  0x14, 0x77, 0x5d, 0x7d, 0x8e, 0x81, 0x7f, 0x41, 0xbc, 0x61, 0xe5, 0xfe,
+  0x39, 0xd7, 0xcf, 0x0b, 0xbe, 0x4f, 0x72, 0xfa, 0x8f, 0xf1, 0xba, 0x59,
+  0xde, 0xca, 0xbc, 0xb3, 0x2b, 0x7a, 0xa7, 0x8a, 0xad, 0x92, 0x54, 0x48,
+  0x4b, 0xb7, 0xf8, 0x35, 0x71, 0xaf, 0x67, 0x76, 0xcc, 0x2f, 0x7b, 0x3b,
+  0xa7, 0x07, 0x0d, 0x94, 0x49, 0x5c, 0xe9, 0x8f, 0xf3, 0xae, 0x27, 0xfd,
+  0xbf, 0x86, 0x10, 0xe0, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x01, 0xff, 0xff,
+  0x19, 0x6f, 0xa4, 0xb0, 0x88, 0xe8, 0x46, 0x21, 0x84, 0x04, 0xaf, 0x26,
+  0x70, 0xa9, 0xd3, 0xa5, 0x54, 0x40, 0xa1, 0x29, 0x6a, 0x9b, 0x16, 0x81,
+  0x2e, 0xa5, 0xcb, 0x81, 0x20, 0x94, 0xe7, 0x65, 0x5d, 0xc1, 0x9d, 0x11,
+  0x72, 0x7d, 0x13, 0x9a, 0x25, 0x68, 0x0b, 0x91, 0xb8, 0x76, 0x7b, 0x68,
+  0xb6, 0xe9, 0x12, 0x01, 0x3c, 0xce, 0x3e, 0x35, 0xc5, 0x7c, 0x8b, 0x55,
+  0xd8, 0x1a, 0x42, 0x99, 0xe1, 0xb1, 0xc3, 0x85, 0xdf, 0x20, 0xde, 0x69,
+  0x5c, 0xb1, 0xd6, 0x7a, 0x97, 0x02, 0xae, 0xc6, 0xc3, 0x4e, 0xfd, 0xac,
+  0x59, 0x4c, 0xc0, 0x62, 0x39, 0x5e, 0xdd, 0x20, 0xde, 0xdf, 0x5f, 0x61,
+  0xd5, 0xd6, 0xbe, 0x1a, 0x15, 0x2e, 0x8a, 0xc0, 0xe9, 0xa4, 0xf8, 0xac,
+  0x9a, 0x5a, 0x8d, 0x42, 0x3b, 0x1e, 0xd0, 0xc1, 0x5b, 0xa2, 0x94, 0x5c,
+  0xac, 0x52, 0x2f, 0x31, 0x85, 0x4d, 0x13, 0x45, 0x07, 0x39, 0x94, 0x84,
+  0x26, 0x9d, 0xfc, 0x67, 0x18, 0x1c, 0xda, 0x52, 0x6b, 0x89, 0x5f, 0xa1,
+  0x52, 0x0a, 0x2f, 0x9c, 0xa9, 0x55, 0x5d, 0xff, 0x29, 0x60, 0x2b, 0x28,
+  0xf5, 0x2b, 0x60, 0x72, 0x9c, 0x22, 0xae, 0x6a, 0xe8, 0xa1, 0x82, 0xba,
+  0x2b, 0x6b, 0xfd, 0xc0, 0x3c, 0xca, 0x94, 0xa1, 0xf5, 0x73, 0xef, 0xec,
+  0x8f, 0x57, 0x28, 0xbd, 0xab, 0x0b, 0x3f, 0x33, 0x03, 0xf7, 0x78, 0x0c,
+  0xa1, 0x15, 0xc4, 0x31, 0x46, 0xd8, 0x82, 0x2e, 0x1f, 0x0d, 0x3b, 0x1b,
+  0x2c, 0xe3, 0x51, 0xf3, 0xf5, 0xdd, 0x76, 0xc5, 0xa3, 0xad, 0x68, 0xf9,
+  0x86, 0xe8, 0x0a, 0xa4, 0x0b, 0xe5, 0xa8, 0x1b, 0x35, 0xa2, 0x7b, 0xad,
+  0xad, 0x86, 0x95, 0x9a, 0x56, 0xe1, 0xd8, 0x12, 0xf3, 0xed, 0x4c, 0xf4,
+  0x61, 0x65, 0x36, 0x18, 0x15, 0xd3, 0xac, 0xb4, 0x41, 0xae, 0x49, 0x4f,
+  0x85, 0x37, 0x26, 0x43, 0x4d, 0x9e, 0x69, 0xf2, 0xfe, 0xf5, 0xd3, 0xbf,
+  0xc1, 0xe5, 0x81, 0xff, 0xf4, 0x03, 0x14, 0x20, 0x58, 0x66, 0x1d, 0x80,
+  0x00, 0x09, 0x48, 0x70, 0x60, 0x41, 0xb0, 0xbd, 0x55, 0x2a, 0xb1, 0x29,
+  0x7a, 0xbf, 0xcb, 0xbc, 0xab, 0xb4, 0x0e, 0x8a, 0x50, 0x94, 0x38, 0x0c,
+  0xf0, 0xb1, 0x7c, 0x32, 0xda, 0x00, 0x29, 0xad, 0x5e, 0x62, 0x4b, 0x75,
+  0x8e, 0x5d, 0x52, 0xf3, 0xb7, 0x03, 0xa2, 0x00, 0x0f, 0x4a, 0xa8, 0x5c,
+  0xaa, 0x1a, 0xac, 0x1b, 0x85, 0x27, 0x59, 0x3b, 0x8a, 0xaa, 0x00, 0x30,
+  0x21, 0x32, 0xae, 0x51, 0x4a, 0x06, 0x4b, 0xa8, 0xd0, 0xf4, 0x7d, 0xcf,
+  0xb9, 0x69, 0x87, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x25,
+  0x73, 0x83, 0x21, 0x48, 0x88, 0x46, 0x19, 0x85, 0x04, 0xe9, 0x67, 0x4d,
+  0x0b, 0x5a, 0xea, 0x4c, 0x80, 0x05, 0x59, 0x43, 0x4b, 0x60, 0xe0, 0xf6,
+  0x4e, 0xb8, 0xae, 0x89, 0xf8, 0x4e, 0x25, 0x51, 0x14, 0xec, 0x46, 0x9f,
+  0xb8, 0x77, 0xad, 0x94, 0x49, 0x03, 0xb0, 0x7e, 0xd1, 0xd7, 0x5d, 0x47,
+  0x28, 0x86, 0x93, 0xef, 0xd7, 0x0d, 0xb7, 0xa1, 0x74, 0x6c, 0x13, 0xce,
+  0x24, 0x27, 0xf6, 0xec, 0x45, 0x0e, 0xb0, 0x62, 0x51, 0x8f, 0xc1, 0x50,
+  0xab, 0xdc, 0x92, 0x06, 0x46, 0xc5, 0xe1, 0xf4, 0xad, 0x39, 0x6d, 0xe8,
+  0xd5, 0x28, 0x05, 0xf3, 0x49, 0xc1, 0x63, 0x0a, 0xfe, 0x23, 0x78, 0x26,
+  0x5b, 0x6f, 0xa5, 0xa8, 0x92, 0xec, 0x74, 0xe0, 0x41, 0xf6, 0xb5, 0x09,
+  0x23, 0x3c, 0xdd, 0x17, 0x99, 0xa3, 0xad, 0xd3, 0x75, 0x38, 0x5b, 0xe5,
+  0x79, 0xda, 0x0e, 0xcb, 0x1a, 0xcf, 0xeb, 0x9f, 0x24, 0x45, 0xa5, 0xc5,
+  0x45, 0xe9, 0x39, 0x64, 0x5c, 0xe5, 0x0d, 0xe4, 0x88, 0x3f, 0xe5, 0x00,
+  0x2c, 0xfb, 0x43, 0x15, 0xa8, 0x01, 0x8b, 0xe5, 0x4a, 0xe3, 0x76, 0xdf,
+  0x1f, 0xe4, 0xea, 0xdf, 0x81, 0x06, 0x67, 0x65, 0x85, 0x4e, 0x9f, 0xf0,
+  0xea, 0x36, 0x4a, 0x05, 0x96, 0x72, 0xf3, 0x49, 0x2e, 0xed, 0x3f, 0x36,
+  0xd0, 0xfe, 0xf5, 0x62, 0xb4, 0xef, 0x74, 0x7f, 0xb7, 0x4a, 0x92, 0x35,
+  0x47, 0xfb, 0x4e, 0x43, 0x91, 0xec, 0xa8, 0xf8, 0xdc, 0xb7, 0xd9, 0x6d,
+  0x3a, 0x37, 0x27, 0x7f, 0x78, 0x39, 0x60, 0x9a, 0x28, 0x96, 0x23, 0xd8,
+  0xb2, 0x96, 0x0a, 0x80, 0x28, 0x52, 0x70, 0x3e, 0x66, 0x2d, 0xd4, 0x64,
+  0xa2, 0xbe, 0xb6, 0xa8, 0x5a, 0xdd, 0x38, 0x55, 0x9b, 0xef, 0x49, 0x27,
+  0xed, 0xcd, 0xc9, 0x52, 0x82, 0x8d, 0x87, 0x13, 0x75, 0xd5, 0x4d, 0x17,
+  0x51, 0x26, 0x53, 0xe5, 0x3b, 0xd1, 0x2f, 0xd2, 0xbf, 0xfd, 0xbf, 0xdd,
+  0x3c, 0xd0, 0x7d, 0xfe, 0x8a, 0x10, 0x8a, 0x1d, 0x80, 0x09, 0x41, 0x31,
+  0x78, 0x89, 0x97, 0x61, 0x80, 0x02, 0x34, 0xdb, 0xb3, 0x43, 0x2a, 0x09,
+  0x58, 0x8c, 0xc9, 0x15, 0xad, 0x16, 0x31, 0x0f, 0x41, 0x68, 0x2a, 0x02,
+  0xba, 0x78, 0x55, 0xc2, 0x49, 0x54, 0x42, 0x3d, 0x2d, 0x76, 0xc5, 0xe6,
+  0x08, 0x2c, 0xb2, 0x71, 0x43, 0xb1, 0xfc, 0x77, 0xac, 0x6d, 0x7e, 0x4e,
+  0x11, 0x57, 0xc6, 0xd4, 0xdd, 0x28, 0x56, 0x92, 0x07, 0xec, 0xee, 0x8f,
+  0x0c, 0xe5, 0x02, 0x11, 0x9d, 0xce, 0x67, 0xdd, 0xcf, 0xaa, 0x00, 0x1c,
+  0x21, 0x1a, 0x88, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x19, 0x6f, 0xa2, 0xc1,
+  0x58, 0x64, 0x44, 0x33, 0x0d, 0x42, 0x07, 0x1b, 0x97, 0x66, 0x95, 0xc1,
+  0xab, 0xa9, 0x2a, 0x14, 0x00, 0x95, 0x03, 0x3f, 0xd4, 0xc8, 0xb1, 0x9c,
+  0x4a, 0x5b, 0x36, 0x66, 0x3c, 0x21, 0x09, 0xe8, 0xed, 0x9e, 0xac, 0xd8,
+  0xda, 0x9b, 0x45, 0xd9, 0x7e, 0x16, 0xce, 0x0c, 0xb2, 0x16, 0xc4, 0xca,
+  0x0b, 0x30, 0x19, 0x17, 0x34, 0xe5, 0xed, 0xdf, 0x7c, 0x76, 0x5f, 0x34,
+  0x66, 0xa8, 0x94, 0x01, 0x42, 0xe6, 0xa4, 0x6f, 0x9c, 0x2d, 0xfc, 0x8f,
+  0xe7, 0xa8, 0x13, 0x2b, 0x28, 0xc8, 0x72, 0x63, 0x69, 0xab, 0xb9, 0x0b,
+  0x24, 0xf6, 0x7d, 0x43, 0x21, 0x84, 0xae, 0x54, 0x35, 0x5c, 0xfc, 0xc0,
+  0x1a, 0x72, 0x59, 0x48, 0x8c, 0xd5, 0x36, 0x51, 0xd0, 0x9d, 0x4c, 0x4f,
+  0x5a, 0xda, 0xd5, 0x4b, 0x45, 0x75, 0x01, 0x11, 0x1a, 0x78, 0xed, 0xed,
+  0x3b, 0xa5, 0xab, 0x81, 0x4b, 0x62, 0xfc, 0x8a, 0x5b, 0xac, 0x45, 0x0f,
+  0x44, 0x3e, 0x36, 0x4a, 0x4c, 0x09, 0x08, 0xce, 0xf7, 0xea, 0x1c, 0x2b,
+  0xb3, 0x20, 0xa4, 0xc4, 0xe5, 0xb5, 0x6d, 0x8b, 0x2a, 0xac, 0xac, 0x25,
+  0x53, 0x3b, 0x2c, 0x9a, 0x88, 0xcd, 0xc0, 0x8f, 0xe3, 0x53, 0xf5, 0x93,
+  0x06, 0x3f, 0x64, 0xfd, 0x64, 0x45, 0xae, 0x7f, 0xd9, 0x36, 0xa3, 0xf1,
+  0x1d, 0xce, 0xa7, 0x3b, 0xa1, 0x65, 0x83, 0xf1, 0xc2, 0x40, 0xd0, 0xa7,
+  0x10, 0xe3, 0x6a, 0x80, 0x44, 0x75, 0x46, 0xca, 0x0f, 0x3e, 0x4a, 0x5b,
+  0x32, 0xa6, 0x62, 0x10, 0x65, 0x60, 0x47, 0x1c, 0x94, 0xcc, 0xa9, 0x43,
+  0x9b, 0xbe, 0xb1, 0xc6, 0x55, 0x09, 0x30, 0xfc, 0x3e, 0x2c, 0xdd, 0x94,
+  0x5f, 0xd5, 0x66, 0x38, 0x42, 0xd5, 0x43, 0xce, 0x02, 0xf7, 0xb8, 0x95,
+  0xce, 0xf4, 0xc1, 0x0c, 0x8f, 0x6b, 0x5e, 0x85, 0x3d, 0xb6, 0xc8, 0xb3,
+  0xd2, 0xad, 0x57, 0x84, 0xb9, 0x74, 0xf5, 0xf3, 0xfb, 0x38, 0xef, 0x7e,
+  0x00, 0x10, 0x1f, 0xc1, 0x4a, 0x09, 0x47, 0xb0, 0x00, 0x94, 0x2a, 0xe8,
+  0x25, 0x1d, 0x18, 0x01, 0xb0, 0x02, 0x32, 0xea, 0x9e, 0x77, 0xe1, 0xaf,
+  0x29, 0x3c, 0x42, 0x94, 0xb4, 0xd6, 0xb1, 0x01, 0x52, 0xe4, 0xb1, 0x2f,
+  0x16, 0x7b, 0x92, 0x66, 0x27, 0x28, 0x2b, 0x13, 0x82, 0xb5, 0x20, 0x50,
+  0xcd, 0xb9, 0x97, 0xaf, 0xdc, 0x0b, 0x63, 0xc4, 0xcf, 0x7b, 0x44, 0x7d,
+  0x75, 0x37, 0x7f, 0x72, 0xe6, 0xee, 0x25, 0xd8, 0xc5, 0x1b, 0xd6, 0xbe,
+  0x51, 0x0e, 0xce, 0xbb, 0x9e, 0x9d, 0x4d, 0x73, 0x98, 0x98, 0x80, 0x0e,
+  0x21, 0x1a, 0x88, 0x00, 0x00, 0x01, 0xff, 0xff, 0x15, 0x6f, 0xa2, 0x41,
+  0xc8, 0xc8, 0x11, 0x23, 0x05, 0x04, 0xa2, 0x00, 0x38, 0x3a, 0xde, 0x96,
+  0xbb, 0xa2, 0xea, 0x80, 0x15, 0x78, 0x98, 0x24, 0xf4, 0xe4, 0xea, 0x93,
+  0xf4, 0xdb, 0x1a, 0x11, 0x10, 0x9f, 0x2a, 0x86, 0x82, 0x81, 0xbc, 0xbc,
+  0x93, 0xf8, 0x8e, 0xcb, 0x10, 0x9d, 0xa3, 0x90, 0xc7, 0x44, 0x1b, 0xbb,
+  0x79, 0x8b, 0x38, 0x93, 0x18, 0x7b, 0x02, 0xd0, 0x0f, 0x50, 0x4f, 0x51,
+  0xc5, 0xcb, 0xa9, 0xe2, 0xfd, 0x97, 0x9a, 0x63, 0xaa, 0x45, 0x52, 0xf3,
+  0xa6, 0xe0, 0xd7, 0xaf, 0x0e, 0x96, 0x06, 0xed, 0x4f, 0xe9, 0x1f, 0x47,
+  0x86, 0x18, 0x29, 0xcf, 0xae, 0xe3, 0xb9, 0xcd, 0x17, 0xc7, 0xc1, 0x46,
+  0x47, 0x72, 0x15, 0x4e, 0xdd, 0x26, 0x71, 0x18, 0x49, 0x32, 0xac, 0xa5,
+  0xe6, 0x48, 0x68, 0xf8, 0x8c, 0xc5, 0xbb, 0x85, 0x8a, 0xf9, 0x7b, 0x2e,
+  0x0b, 0xca, 0xed, 0x62, 0x5a, 0xe2, 0x72, 0xa6, 0x56, 0x5d, 0xdd, 0x4c,
+  0xde, 0xbf, 0x1e, 0x5d, 0x84, 0xf4, 0xb3, 0x27, 0x1c, 0xa2, 0x05, 0x03,
+  0x94, 0x05, 0x16, 0xd3, 0x8b, 0x4c, 0x68, 0x83, 0xb9, 0x2a, 0x39, 0xeb,
+  0x84, 0xc8, 0xcb, 0x84, 0xbe, 0x4c, 0xe6, 0x59, 0x05, 0xed, 0xbb, 0xb3,
+  0x59, 0x5e, 0x7e, 0xe7, 0xdd, 0xf9, 0xd0, 0xde, 0x32, 0x55, 0x46, 0x48,
+  0xc1, 0x4d, 0x43, 0xf2, 0xe3, 0xe8, 0x65, 0x91, 0xb7, 0x4f, 0x4d, 0x27,
+  0x3a, 0x63, 0xd3, 0xc3, 0xd3, 0x0e, 0xa8, 0xc2, 0xea, 0x66, 0xa6, 0x6c,
+  0x9e, 0x5f, 0x6e, 0xc3, 0x82, 0x87, 0x23, 0x21, 0x64, 0x34, 0x14, 0x94,
+  0xf5, 0xba, 0xc9, 0x67, 0x4c, 0x36, 0x9c, 0xe4, 0x6b, 0xaf, 0x6e, 0xe9,
+  0x74, 0xf5, 0x22, 0x79, 0xc5, 0xfb, 0x40, 0x91, 0xca, 0xfd, 0x58, 0x9f,
+  0x8f, 0x45, 0xfa, 0x60, 0xd2, 0x7b, 0xab, 0x1b, 0xed, 0x80, 0x08, 0x0f,
+  0xd0, 0x08, 0x52, 0x81, 0x61, 0x98, 0x76, 0x00, 0x00, 0x42, 0x91, 0xc0,
+  0x22, 0x90, 0xec, 0x28, 0x23, 0x9a, 0x41, 0x79, 0xc0, 0x45, 0x3b, 0xcc,
+  0x21, 0x35, 0x99, 0x0b, 0x9c, 0x52, 0x0a, 0xd2, 0x36, 0xf7, 0xed, 0xcb,
+  0x1b, 0x82, 0x10, 0x4c, 0x92, 0x95, 0x7b, 0x26, 0x78, 0x44, 0xce, 0xcf,
+  0xb4, 0x16, 0x68, 0x6c, 0xaf, 0x94, 0x45, 0x68, 0x15, 0xa2, 0xe6, 0xa2,
+  0xcb, 0xd8, 0x1e, 0x64, 0xaf, 0x42, 0x54, 0x93, 0xe5, 0x54, 0x9d, 0xc2,
+  0x00, 0x75, 0x9e, 0xea, 0x92, 0x0f, 0xba, 0x77, 0xde, 0xc7, 0xf4, 0xe8,
+  0x87, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x17, 0x6f, 0xa4,
+  0xb0, 0x90, 0xe4, 0x44, 0x13, 0x08, 0x42, 0x01, 0x69, 0x7c, 0x0d, 0x33,
+  0x57, 0x51, 0x1c, 0xe8, 0x00, 0x87, 0x22, 0xd5, 0x0d, 0xa6, 0xf2, 0x09,
+  0x65, 0x4f, 0x18, 0x98, 0x20, 0x12, 0x8f, 0x02, 0xa2, 0x93, 0x59, 0x94,
+  0x82, 0x45, 0x90, 0x5d, 0xc6, 0xfc, 0x9d, 0xe5, 0xb5, 0x00, 0x26, 0x29,
+  0x50, 0x35, 0x4e, 0x17, 0xd8, 0x0f, 0x1e, 0xaf, 0x9b, 0x9b, 0xbf, 0xcf,
+  0x92, 0xb6, 0x66, 0x8e, 0xdd, 0x32, 0x35, 0xc9, 0x98, 0x2e, 0x3a, 0xb6,
+  0xaa, 0x8d, 0x24, 0x1d, 0xd1, 0x2e, 0x96, 0x22, 0xb5, 0xc6, 0x64, 0x70,
+  0xf9, 0x37, 0x9f, 0x8d, 0xe4, 0x0f, 0xb8, 0xa6, 0xaf, 0xf5, 0x89, 0x1e,
+  0x2e, 0x3a, 0xbe, 0x53, 0x56, 0x01, 0xd4, 0x80, 0x16, 0x09, 0x50, 0xca,
+  0xe9, 0x08, 0x3e, 0x04, 0xc2, 0x86, 0xd4, 0x80, 0x69, 0xe6, 0x88, 0xdd,
+  0xe0, 0x7b, 0xbc, 0x60, 0x2c, 0xe0, 0x8b, 0x39, 0x7b, 0xd0, 0xf1, 0xf4,
+  0x27, 0x19, 0x0c, 0xbd, 0x18, 0x9d, 0x38, 0x21, 0xda, 0xfd, 0xf4, 0xe2,
+  0xed, 0x0a, 0x74, 0x3a, 0x8c, 0x3d, 0x99, 0xe2, 0x5e, 0x72, 0xe0, 0x02,
+  0xc6, 0x53, 0x49, 0x56, 0x69, 0xaf, 0x2f, 0x34, 0xb3, 0x55, 0x95, 0x87,
+  0x56, 0x10, 0xe5, 0x50, 0x2f, 0x2a, 0x4a, 0x78, 0x74, 0x38, 0x5d, 0xdb,
+  0x47, 0x58, 0xac, 0xae, 0x79, 0x56, 0x1c, 0xc2, 0x6c, 0x6c, 0xa7, 0x4a,
+  0xe4, 0x53, 0xe8, 0x7d, 0x34, 0x55, 0x9a, 0x60, 0x82, 0xfe, 0x4c, 0x4f,
+  0x44, 0x39, 0x8c, 0xc0, 0x1d, 0x6b, 0xc6, 0x57, 0xcc, 0x63, 0x17, 0x0d,
+  0x19, 0xda, 0x67, 0xad, 0x06, 0x7e, 0x53, 0xe8, 0x50, 0x8b, 0xd1, 0xed,
+  0xf4, 0x40, 0x07, 0xa6, 0xd9, 0x30, 0x1b, 0xea, 0xd9, 0x28, 0xdc, 0x3c,
+  0x2a, 0x9e, 0xd4, 0x14, 0x53, 0xc2, 0x8b, 0xec, 0x1b, 0xae, 0xbb, 0x5f,
+  0x6f, 0x96, 0x10, 0x7f, 0xfe, 0x0a, 0x98, 0x66, 0x1d, 0x80, 0x05, 0x40,
+  0x2a, 0x2a, 0x4c, 0xea, 0xb0, 0x06, 0xa9, 0xc8, 0xfb, 0xab, 0xfd, 0x34,
+  0xe5, 0xd0, 0x91, 0xb2, 0x4a, 0xab, 0xd8, 0x5a, 0x08, 0xa7, 0x72, 0xf1,
+  0x20, 0x02, 0xc5, 0x5d, 0x05, 0xe0, 0xae, 0xd8, 0x5a, 0x23, 0x41, 0x61,
+  0x64, 0xb6, 0xca, 0x78, 0xff, 0xa6, 0x7a, 0xed, 0xa0, 0xb6, 0x4d, 0x5a,
+  0x77, 0x85, 0xd9, 0x77, 0xe4, 0xb9, 0xe3, 0x69, 0x0c, 0x5b, 0x44, 0xd4,
+  0x4e, 0x04, 0x95, 0x5c, 0x32, 0x9d, 0x0f, 0x78, 0xe4, 0x19, 0x08, 0xeb,
+  0xa6, 0xb5, 0x21, 0xf6, 0xdd, 0x12, 0x18, 0x43, 0x07, 0x21, 0x1a, 0x88,
+  0x00, 0x00, 0x00, 0x3f, 0xff, 0x1d, 0x6f, 0xa4, 0xb1, 0x10, 0xa2, 0x34,
+  0x13, 0x0c, 0xc2, 0x06, 0x92, 0x3a, 0x0e, 0x22, 0x59, 0x74, 0x28, 0x28,
+  0xb4, 0x36, 0x2a, 0x08, 0x64, 0x60, 0x82, 0x39, 0x75, 0x65, 0x73, 0xfc,
+  0x27, 0x2c, 0x56, 0xe1, 0xfe, 0xdd, 0x55, 0x0e, 0xe6, 0x7e, 0x6b, 0x47,
+  0x84, 0x76, 0x6d, 0x60, 0x39, 0xb4, 0x98, 0x07, 0xce, 0x17, 0x05, 0xc9,
+  0x19, 0xe8, 0xaf, 0xc5, 0x6e, 0x9d, 0x81, 0xec, 0x3c, 0xad, 0x96, 0x64,
+  0x7c, 0xe5, 0xc1, 0x9e, 0x75, 0x8c, 0xd9, 0xcc, 0xd6, 0xa9, 0x1f, 0x19,
+  0x68, 0x4c, 0xfb, 0x63, 0xa5, 0xd7, 0x33, 0x8d, 0x15, 0x7b, 0x98, 0xd0,
+  0xa4, 0xa8, 0x73, 0x67, 0xf6, 0x3f, 0x22, 0xa9, 0x35, 0x23, 0x37, 0xf7,
+  0x6a, 0x6f, 0xb4, 0xed, 0xd4, 0x28, 0x7c, 0x19, 0x1d, 0x33, 0xf6, 0x11,
+  0xe6, 0x0d, 0x8a, 0xdd, 0xdd, 0xab, 0x9c, 0x3a, 0xc9, 0xda, 0x94, 0x95,
+  0x6d, 0x53, 0xf5, 0xfb, 0x5a, 0x73, 0x9d, 0x48, 0x36, 0x5a, 0x2c, 0xf6,
+  0xfa, 0x0a, 0xee, 0x39, 0x9f, 0x14, 0x9d, 0xef, 0xd3, 0x80, 0x4f, 0x24,
+  0x39, 0xe3, 0x3c, 0x2a, 0xd5, 0x73, 0x95, 0x60, 0x08, 0x98, 0xaa, 0xdd,
+  0x78, 0x8b, 0x3d, 0x06, 0xaf, 0xae, 0x65, 0xb6, 0xa5, 0xf5, 0xce, 0x12,
+  0x8b, 0x07, 0xad, 0x4f, 0x08, 0x13, 0x74, 0x97, 0x71, 0x26, 0xf2, 0x55,
+  0x7a, 0xab, 0xab, 0x89, 0x75, 0x18, 0x00, 0x51, 0xe6, 0x72, 0x65, 0x77,
+  0x12, 0xbe, 0xb8, 0xd9, 0xdc, 0x66, 0x60, 0xe1, 0xa6, 0xf2, 0x3c, 0xed,
+  0xb9, 0x0c, 0x70, 0x0f, 0x8f, 0xfb, 0x1c, 0x48, 0x40, 0x25, 0x0e, 0x38,
+  0xfd, 0xbf, 0xcd, 0x4b, 0x41, 0x9d, 0x38, 0x96, 0x87, 0xec, 0xf9, 0x60,
+  0xe7, 0x34, 0xf4, 0x6f, 0x20, 0x35, 0x6b, 0x19, 0x9d, 0x83, 0x0b, 0x86,
+  0xfa, 0x2e, 0x2f, 0x6a, 0xcf, 0x4d, 0x1a, 0x7a, 0xb5, 0xdb, 0xb3, 0x8b,
+  0x5d, 0xd9, 0xa7, 0xfe, 0xa3, 0xb1, 0xf9, 0x4f, 0x57, 0x07, 0xdf, 0xe8,
+  0xa5, 0x86, 0x61, 0xd8, 0x00, 0x15, 0x02, 0xa5, 0x12, 0x2c, 0xc1, 0x2a,
+  0xc0, 0xe1, 0x5a, 0xa1, 0xf9, 0x1c, 0xba, 0xce, 0x97, 0x87, 0x00, 0x9d,
+  0x65, 0x3b, 0x0d, 0xca, 0xe1, 0x05, 0x13, 0xa0, 0x33, 0x31, 0x8b, 0x73,
+  0x30, 0x59, 0x1d, 0x3b, 0xa1, 0xeb, 0xf5, 0x53, 0x9f, 0x36, 0x3f, 0xad,
+  0xa6, 0xac, 0x75, 0xb4, 0xac, 0xcb, 0x3e, 0x79, 0x30, 0xe0, 0x18, 0xc4,
+  0xc9, 0x68, 0xdb, 0x7c, 0xc8, 0x15, 0x0f, 0x39, 0x9e, 0x46, 0x3b, 0x91,
+  0x2f, 0xac, 0xce, 0xcb, 0xfa, 0x68, 0xc5, 0xbb, 0x9f, 0x86, 0xfc, 0xe7,
+  0x20, 0x38, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x01, 0xff, 0xff, 0x17, 0x70,
+  0xa4, 0xa3, 0x18, 0x86, 0x10, 0x0b, 0x38, 0x68, 0xd5, 0x3a, 0x4a, 0x55,
+  0x58, 0x02, 0x96, 0x60, 0x24, 0x10, 0x12, 0x8c, 0xb2, 0x4a, 0x29, 0x2c,
+  0x1b, 0xc8, 0x21, 0x37, 0x7c, 0xbb, 0x42, 0x8e, 0x04, 0x3f, 0xd3, 0x7e,
+  0x93, 0x98, 0x6b, 0x40, 0x68, 0xfe, 0xf7, 0xd4, 0x3b, 0x9e, 0x8b, 0x2d,
+  0xd6, 0x79, 0x70, 0xbd, 0xc5, 0xe2, 0x7b, 0x67, 0xbd, 0x9b, 0xb6, 0xfc,
+  0x35, 0x97, 0x49, 0x46, 0x1c, 0xd5, 0xc7, 0xd0, 0xad, 0x99, 0x39, 0x72,
+  0x43, 0x2a, 0x24, 0x51, 0x2b, 0xed, 0xdd, 0x6e, 0x35, 0xe1, 0xc5, 0x7d,
+  0xbb, 0xab, 0x56, 0xab, 0xbb, 0x57, 0x93, 0x97, 0x6d, 0x0e, 0xaf, 0x9b,
+  0xc9, 0x7f, 0x2d, 0xa9, 0x8e, 0x8c, 0x5c, 0x3e, 0xbe, 0xe9, 0x62, 0xcb,
+  0x85, 0x6d, 0x22, 0x99, 0x2b, 0x3c, 0x89, 0x39, 0x94, 0x0d, 0x62, 0x54,
+  0x34, 0x6a, 0x58, 0x86, 0xbb, 0x4f, 0x7d, 0x87, 0x7c, 0x63, 0x65, 0x5f,
+  0x8c, 0x9c, 0x9f, 0x87, 0x3a, 0x6c, 0x28, 0x2d, 0xce, 0x3e, 0x50, 0xe7,
+  0x04, 0xe1, 0xd4, 0xcd, 0x40, 0x18, 0x80, 0x0d, 0xa1, 0x3e, 0x0e, 0x17,
+  0xed, 0x55, 0x23, 0xe3, 0xa5, 0x38, 0x0f, 0xad, 0x69, 0x57, 0xbe, 0x83,
+  0x68, 0x40, 0x96, 0xce, 0xb7, 0x06, 0x68, 0x3c, 0x72, 0x1e, 0x51, 0xf3,
+  0x91, 0x5a, 0xd1, 0x30, 0xfa, 0xe0, 0x2b, 0x3a, 0xc0, 0x8b, 0x0d, 0x76,
+  0xa1, 0x67, 0x51, 0x55, 0x7c, 0xbd, 0xe2, 0x78, 0x9c, 0x90, 0x65, 0x0b,
+  0x7a, 0xb5, 0x02, 0x30, 0x5e, 0xdb, 0x39, 0x95, 0xea, 0x30, 0x74, 0x21,
+  0xd9, 0xde, 0xb0, 0x03, 0x13, 0xd7, 0x18, 0xd1, 0x1c, 0xb9, 0x0d, 0xa0,
+  0x00, 0xac, 0x08, 0x12, 0x24, 0x91, 0x7e, 0x86, 0x3d, 0xed, 0x2c, 0x61,
+  0x3a, 0x62, 0x20, 0x0f, 0x12, 0x9b, 0xe7, 0x98, 0x9e, 0xc0, 0x36, 0xd7,
+  0x53, 0x7f, 0x93, 0x4c, 0x57, 0xdf, 0xf5, 0x8b, 0xac, 0x9b, 0x2a, 0xa8,
+  0x6a, 0x26, 0x92, 0x3c, 0x25, 0xff, 0xed, 0x3b, 0x6f, 0xd3, 0xff, 0xee,
+  0x07, 0xff, 0xd0, 0x90, 0x8e, 0xc4, 0x10, 0xec, 0x00, 0x2a, 0x52, 0x09,
+  0x45, 0x34, 0x04, 0x10, 0xec, 0x01, 0x55, 0xce, 0xa8, 0x21, 0x34, 0xa2,
+  0x00, 0x74, 0x82, 0xc1, 0x0a, 0x49, 0xc8, 0x44, 0x16, 0x7c, 0x12, 0xe2,
+  0x42, 0x18, 0xdc, 0x69, 0x70, 0x05, 0x82, 0xac, 0xea, 0x3a, 0x93, 0xd8,
+  0x1f, 0xd3, 0xd2, 0xfe, 0xa9, 0xa7, 0x6c, 0xd2, 0x33, 0xf1, 0x8a, 0x60,
+  0xb1, 0x60, 0x68, 0x08, 0x4d, 0x50, 0x35, 0x06, 0x77, 0x0d, 0xe3, 0x9c,
+  0xad, 0x34, 0x45, 0xb3, 0x33, 0x05, 0x34, 0x26, 0x2a, 0xea, 0x58, 0x4c,
+  0xe5, 0x5d, 0x0a, 0x77, 0x05, 0xee, 0xb3, 0x24, 0xbf, 0x8c, 0x64, 0x7d,
+  0x09, 0x2a, 0x6a, 0xb3, 0xcb, 0x3f, 0x5f, 0xcb, 0xdd, 0x00, 0xe0, 0x21,
+  0x1a, 0x88, 0x00, 0x00, 0x00, 0x03, 0xff, 0x21, 0x73, 0x82, 0xa2, 0xc4,
+  0x28, 0x26, 0x1a, 0x84, 0x1c, 0x2c, 0xb7, 0x0a, 0x71, 0x52, 0xec, 0x52,
+  0x41, 0x18, 0x10, 0xc1, 0x5c, 0x8a, 0x66, 0x87, 0x94, 0x31, 0xf8, 0x6d,
+  0xbc, 0x18, 0xdc, 0x4c, 0x99, 0xc7, 0xdb, 0x5e, 0xf3, 0x6f, 0xe0, 0xa7,
+  0xf2, 0x69, 0x64, 0x18, 0xef, 0x2b, 0x0b, 0x43, 0x7e, 0x08, 0x9a, 0x19,
+  0xf9, 0x4d, 0xdd, 0xcd, 0x19, 0x2e, 0xe6, 0x81, 0xe2, 0xfa, 0xab, 0xb4,
+  0xfc, 0x0b, 0xc8, 0xba, 0xe2, 0x0f, 0x11, 0x3a, 0x5b, 0xfb, 0xcd, 0xa8,
+  0x53, 0xb3, 0x92, 0xdc, 0x5c, 0x68, 0xd5, 0x15, 0x7d, 0xc8, 0x1c, 0x89,
+  0x4e, 0xd3, 0x93, 0x73, 0x04, 0x49, 0x0b, 0x8e, 0x90, 0xd4, 0x07, 0xd2,
+  0xb9, 0x8a, 0xda, 0x60, 0x04, 0x16, 0x06, 0xee, 0x01, 0x54, 0xbe, 0xe6,
+  0x95, 0xab, 0x5d, 0x18, 0x34, 0x04, 0x99, 0x1d, 0xcc, 0xcb, 0x10, 0x7c,
+  0xdc, 0x6d, 0x8f, 0x83, 0xcf, 0x0d, 0x3c, 0x8c, 0x00, 0x46, 0xfa, 0x81,
+  0x35, 0x75, 0xc3, 0xf4, 0xc2, 0xa9, 0x06, 0x53, 0xd1, 0x17, 0x12, 0x47,
+  0x5b, 0x56, 0x0d, 0x94, 0xf3, 0x7e, 0x25, 0x4e, 0x4f, 0xf7, 0x30, 0x9e,
+  0xff, 0x9e, 0x0e, 0xf5, 0x5c, 0x3a, 0x87, 0x21, 0xba, 0xf6, 0xaa, 0x4b,
+  0x3a, 0xb8, 0x1e, 0xaf, 0x26, 0xa0, 0x03, 0x6b, 0x7e, 0xe9, 0x44, 0xfc,
+  0xf0, 0x16, 0x5d, 0x78, 0x83, 0x5b, 0x7d, 0x1b, 0x9d, 0xf1, 0xb4, 0x77,
+  0x02, 0x3e, 0xd0, 0x1a, 0xc4, 0x2b, 0x9a, 0x90, 0xe9, 0xde, 0xa5, 0xd0,
+  0x88, 0xd7, 0x9e, 0x2b, 0xf2, 0x96, 0xd8, 0x2b, 0xd5, 0x9a, 0x31, 0xc3,
+  0xf0, 0xb5, 0x11, 0xa8, 0x13, 0x4e, 0xad, 0x87, 0x91, 0xb3, 0x64, 0x6c,
+  0x0c, 0x6a, 0xa8, 0x0b, 0x59, 0x60, 0xd4, 0xc2, 0xac, 0x8b, 0x3a, 0x29,
+  0x58, 0x18, 0xda, 0x01, 0x21, 0x22, 0x57, 0x5d, 0xdb, 0x51, 0xa0, 0x5e,
+  0x73, 0xc7, 0x1c, 0x39, 0x77, 0xf6, 0x00, 0x1f, 0x7f, 0xe2, 0x11, 0xa0,
+  0xd8, 0x46, 0x1d, 0x80, 0x04, 0xa2, 0xa2, 0xa2, 0xae, 0xa5, 0x4a, 0x49,
+  0x14, 0x2d, 0x80, 0x84, 0xd5, 0x64, 0x8f, 0x1b, 0xc8, 0x4b, 0x85, 0xd7,
+  0xe1, 0x06, 0xec, 0x6c, 0x55, 0xd8, 0x90, 0x31, 0x1c, 0xec, 0xd4, 0x6f,
+  0x8e, 0xe2, 0xc4, 0x9b, 0xaf, 0x41, 0xa9, 0xcb, 0x2d, 0x94, 0xf9, 0xd4,
+  0xaa, 0x06, 0xdb, 0x96, 0x9e, 0x8f, 0x46, 0x54, 0xf2, 0xeb, 0xae, 0x63,
+  0x9e, 0x9d, 0xd2, 0x76, 0x61, 0x14, 0x1b, 0xe7, 0x23, 0xe3, 0xcd, 0xe4,
+  0x62, 0xf2, 0xe1, 0xc0, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x00, 0x7f, 0xff,
+  0x1f, 0x73, 0x83, 0x23, 0x58, 0x66, 0x10, 0x47, 0x1d, 0xd7, 0xe0, 0xea,
+  0x96, 0xab, 0xb5, 0x5b, 0x2c, 0x4a, 0xc8, 0x4a, 0xbc, 0x94, 0x35, 0xfe,
+  0x41, 0x1c, 0x98, 0x79, 0x3c, 0x59, 0x09, 0xa4, 0x4a, 0x4f, 0xda, 0xd8,
+  0xcb, 0xad, 0x87, 0xf6, 0x9b, 0xdb, 0xa7, 0xee, 0x19, 0x07, 0x98, 0x3e,
+  0xa1, 0x8e, 0xe6, 0x1c, 0xe2, 0xe7, 0xd7, 0xd7, 0x0f, 0xa6, 0x70, 0xdc,
+  0x47, 0xa8, 0xed, 0x61, 0x7b, 0x6c, 0x8d, 0x13, 0xa7, 0xf6, 0x26, 0x2f,
+  0xf9, 0xce, 0xa2, 0xf1, 0xa9, 0x30, 0x32, 0xcc, 0x49, 0xa6, 0x8f, 0x7d,
+  0x72, 0xfb, 0xfa, 0x6e, 0x8e, 0xbb, 0x0f, 0x55, 0x55, 0xf2, 0x04, 0x62,
+  0xab, 0xa1, 0xe9, 0xe7, 0xf2, 0xd7, 0xa1, 0xa8, 0x40, 0x9c, 0x27, 0x24,
+  0xe5, 0x5c, 0xd8, 0x12, 0xd7, 0xa0, 0x67, 0x91, 0xb9, 0xb0, 0x40, 0xbe,
+  0x4f, 0x44, 0x7e, 0x48, 0x49, 0xed, 0xbb, 0x9c, 0x73, 0x4d, 0xf1, 0x6d,
+  0x5a, 0xd2, 0x55, 0x65, 0x6f, 0xe9, 0x50, 0x46, 0xe2, 0x74, 0x57, 0xac,
+  0x9d, 0x1e, 0x32, 0x57, 0x87, 0x09, 0x67, 0x8d, 0x36, 0xfa, 0x93, 0x29,
+  0x36, 0xcf, 0x2b, 0xeb, 0xdb, 0x9f, 0xb3, 0xbe, 0xe6, 0x77, 0xc3, 0x74,
+  0x50, 0x40, 0x35, 0xe2, 0xb2, 0x94, 0xf8, 0x22, 0xd4, 0x69, 0xae, 0x37,
+  0xe4, 0x17, 0x4f, 0x4a, 0x4e, 0x25, 0xdd, 0x7d, 0x70, 0x13, 0xf8, 0xc1,
+  0xbf, 0x10, 0xf7, 0x1a, 0x2c, 0xc9, 0xa3, 0x5e, 0x83, 0x01, 0x67, 0x2f,
+  0xdb, 0x2d, 0x27, 0xb2, 0x74, 0x75, 0xf2, 0x5c, 0x00, 0x91, 0xf5, 0xcc,
+  0x71, 0xd3, 0x41, 0xf3, 0xe6, 0xe3, 0xb3, 0xb1, 0x51, 0x84, 0xe1, 0x36,
+  0x54, 0x0a, 0xe8, 0xdd, 0x72, 0xf4, 0x4d, 0x68, 0xd3, 0x52, 0xeb, 0x94,
+  0xb0, 0x74, 0x23, 0xb4, 0x28, 0x78, 0x91, 0xa2, 0x4c, 0x71, 0xb3, 0x09,
+  0x96, 0x89, 0xf7, 0xa0, 0x18, 0xca, 0x12, 0x35, 0xf6, 0x50, 0x96, 0x60,
+  0x73, 0x50, 0xb7, 0xdc, 0xf4, 0xbc, 0xf2, 0xd7, 0x33, 0xfd, 0xa8, 0xe5,
+  0x4f, 0xff, 0x27, 0x07, 0x42, 0xf2, 0xe0, 0xf9, 0xfc, 0x14, 0x21, 0x18,
+  0x2a, 0x1d, 0x80, 0x54, 0x0a, 0x95, 0x00, 0xbc, 0x80, 0x04, 0x40, 0x11,
+  0xf1, 0x00, 0x15, 0x32, 0x45, 0x62, 0x70, 0xb5, 0x08, 0xec, 0x94, 0xab,
+  0xfb, 0x42, 0x9d, 0xe7, 0x14, 0xee, 0xc1, 0x34, 0xf2, 0x5f, 0xc2, 0x9a,
+  0xbc, 0x2d, 0xde, 0x38, 0xc7, 0xac, 0x72, 0x97, 0xae, 0x67, 0x85, 0xb5,
+  0xe9, 0x15, 0xa1, 0x0f, 0xba, 0xc7, 0xa2, 0x71, 0xfe, 0xa5, 0xab, 0xf9,
+  0xf8, 0x15, 0x29, 0xba, 0x0f, 0x1d, 0x1e, 0x45, 0x7b, 0x3f, 0x85, 0x12,
+  0xe3, 0x4a, 0x4b, 0x10, 0xab, 0x94, 0xd8, 0xc6, 0x2d, 0xef, 0xe3, 0xac,
+  0x7d, 0xfd, 0x6e, 0x00, 0x1c, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x03, 0xff,
+  0xff, 0x21, 0x73, 0xa3, 0x23, 0x98, 0x46, 0x10, 0x34, 0xd3, 0x86, 0x6b,
+  0x4d, 0x1a, 0x52, 0xe6, 0x54, 0x08, 0xa4, 0x0c, 0x13, 0xe9, 0x48, 0x24,
+  0xf5, 0xa4, 0x7f, 0xd2, 0xe3, 0xd2, 0xfc, 0x86, 0xb6, 0xb3, 0x99, 0xfa,
+  0xec, 0x6d, 0x25, 0xbc, 0x2e, 0x5c, 0x71, 0xf6, 0x2d, 0x1f, 0x16, 0x4b,
+  0x45, 0x9d, 0xcf, 0xae, 0xa6, 0x73, 0x79, 0xc6, 0xb6, 0xc8, 0xf0, 0x0b,
+  0x2b, 0xb0, 0x39, 0x5d, 0xb3, 0x4b, 0xb9, 0x55, 0x1c, 0x98, 0xcc, 0xc1,
+  0xea, 0x12, 0xa3, 0xb5, 0x22, 0xde, 0xe6, 0xd0, 0xee, 0x26, 0xc4, 0xe3,
+  0x9c, 0x9a, 0x5c, 0xda, 0xf2, 0x6c, 0x56, 0xc7, 0x31, 0x1b, 0x0b, 0x2e,
+  0x78, 0x61, 0x50, 0x96, 0x35, 0xf3, 0xf6, 0x73, 0x76, 0xf0, 0x66, 0x04,
+  0xce, 0xf2, 0x51, 0x4d, 0x8c, 0x50, 0x6a, 0xaa, 0xae, 0x14, 0xc8, 0xcf,
+  0x54, 0x31, 0x7b, 0x06, 0x3d, 0x6d, 0x61, 0xec, 0x7f, 0x2a, 0x7d, 0x67,
+  0x0d, 0x95, 0x4e, 0x19, 0x84, 0x50, 0xb8, 0xd2, 0xb5, 0x8f, 0xf0, 0xb2,
+  0xd9, 0x4c, 0x24, 0x28, 0x7c, 0xd0, 0x10, 0xc3, 0x0a, 0x00, 0xf0, 0x85,
+  0x0a, 0x49, 0x52, 0xac, 0xf7, 0x3a, 0x23, 0xe7, 0x21, 0x18, 0x2b, 0x95,
+  0x92, 0xbd, 0x08, 0xa9, 0xd6, 0x49, 0x7d, 0x43, 0xf3, 0x3f, 0x4a, 0x24,
+  0x00, 0x16, 0x57, 0x8e, 0xcf, 0xc8, 0x14, 0x45, 0x15, 0xba, 0x17, 0x5f,
+  0x78, 0xd1, 0x1b, 0x63, 0x46, 0xe5, 0xd3, 0xc9, 0x6a, 0x60, 0x9d, 0xa3,
+  0xc2, 0x87, 0xeb, 0x2d, 0xa9, 0xc7, 0x9d, 0x83, 0x86, 0x86, 0xb5, 0xbe,
+  0x4c, 0x08, 0xd7, 0x75, 0xf4, 0x3c, 0x1e, 0x35, 0xfe, 0xdc, 0x47, 0x44,
+  0x44, 0x4c, 0x0e, 0x72, 0x9d, 0xc6, 0xe1, 0x8a, 0x5b, 0x8f, 0xde, 0x28,
+  0x69, 0x3f, 0x90, 0x74, 0x7f, 0x83, 0xd2, 0x28, 0x12, 0x52, 0x21, 0x95,
+  0xec, 0x75, 0xcd, 0xdf, 0x5c, 0xfc, 0x30, 0xb1, 0x2b, 0xdb, 0x45, 0xc4,
+  0x25, 0x62, 0x71, 0x1e, 0x85, 0xd2, 0xbf, 0x63, 0x96, 0x0f, 0xbf, 0x91,
+  0x5a, 0x09, 0x86, 0x61, 0xd8, 0x00, 0x14, 0x2d, 0x52, 0x80, 0x40, 0x55,
+  0xa6, 0xc3, 0xf7, 0x58, 0x0b, 0x6d, 0x29, 0x7a, 0x9a, 0xc1, 0xb9, 0x54,
+  0x50, 0x00, 0x13, 0x0b, 0x6f, 0xba, 0x10, 0xb7, 0x2e, 0x94, 0x5a, 0x70,
+  0xbc, 0xfc, 0xc3, 0xf5, 0x9a, 0x34, 0x89, 0x0d, 0xcf, 0x4c, 0x77, 0x16,
+  0xaf, 0x72, 0x99, 0x88, 0x5f, 0x37, 0x8b, 0x9a, 0x54, 0x0b, 0xa8, 0x98,
+  0xe0, 0xa0, 0x5c, 0x95, 0xd4, 0xcd, 0x12, 0xa2, 0x37, 0x09, 0x2b, 0x41,
+  0x76, 0xad, 0x2c, 0xae, 0x1c, 0x8b, 0x28, 0xca, 0x2c, 0xdd, 0x67, 0x09,
+  0x2a, 0xbb, 0x04, 0xe0, 0xbd, 0xf8, 0x75, 0xd9, 0xc5, 0xb9, 0xd0, 0xf4,
+  0x61, 0xc0, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x00, 0x03, 0xff, 0x19, 0x6f,
+  0xa4, 0xb0, 0xd1, 0x02, 0x14, 0x23, 0x04, 0xc2, 0x02, 0x53, 0xcc, 0x0d,
+  0x26, 0xa0, 0x80, 0x0c, 0x42, 0x4d, 0x8d, 0x78, 0x49, 0x6b, 0x94, 0x12,
+  0x42, 0xd9, 0x25, 0x39, 0x74, 0x1a, 0x49, 0x3c, 0x04, 0x63, 0x84, 0x98,
+  0xdd, 0xc5, 0xf9, 0x8e, 0xc5, 0x26, 0x84, 0xa0, 0x87, 0xfa, 0x1d, 0x27,
+  0xa4, 0xae, 0x3f, 0xd4, 0x1f, 0xc8, 0xf9, 0xfb, 0xef, 0x30, 0x5e, 0x0f,
+  0x55, 0x73, 0x4f, 0x30, 0x66, 0x49, 0x27, 0x74, 0x43, 0x99, 0x7e, 0x6d,
+  0x34, 0xd3, 0x4f, 0x50, 0x86, 0xa4, 0x33, 0x2e, 0x02, 0xc5, 0xa4, 0x98,
+  0xfa, 0xbb, 0x5d, 0x8e, 0x4e, 0xc4, 0xc9, 0x3f, 0x5a, 0xb9, 0x47, 0x17,
+  0xe7, 0x75, 0x56, 0xa6, 0xc0, 0x64, 0xae, 0x3d, 0x72, 0x89, 0x18, 0x0b,
+  0x32, 0xa2, 0x01, 0x36, 0x65, 0xee, 0xe3, 0x34, 0x17, 0x49, 0xaa, 0xb7,
+  0xf7, 0xc0, 0x5f, 0xa1, 0x84, 0x8f, 0x37, 0x1d, 0x77, 0x59, 0x48, 0xc6,
+  0x96, 0xa3, 0x08, 0x9c, 0xdf, 0xd3, 0xaf, 0x85, 0x57, 0x14, 0xb0, 0x94,
+  0x2e, 0x82, 0xce, 0x0c, 0x6a, 0xa2, 0x22, 0xd4, 0x47, 0x27, 0x3a, 0x5b,
+  0x1a, 0xe5, 0x97, 0x66, 0xa1, 0x5b, 0x06, 0x00, 0x28, 0xfd, 0xbb, 0x8e,
+  0x5c, 0x80, 0x30, 0x5a, 0x7b, 0xbd, 0xfd, 0x47, 0x2d, 0x09, 0x8a, 0xbf,
+  0x5d, 0xd1, 0x70, 0xd7, 0x6d, 0x53, 0x73, 0x2c, 0x15, 0xcc, 0xb9, 0x5a,
+  0x73, 0xc1, 0xf7, 0xbe, 0x2c, 0x16, 0x5f, 0x47, 0xdc, 0xbf, 0xc2, 0xdf,
+  0xa1, 0x79, 0x59, 0xd3, 0x3b, 0x09, 0x06, 0x20, 0x43, 0x8e, 0x19, 0xbd,
+  0xa0, 0x97, 0xa1, 0x23, 0x29, 0x50, 0xd7, 0xad, 0x96, 0x31, 0x64, 0xcd,
+  0x3f, 0x67, 0xe9, 0x12, 0x08, 0x60, 0x58, 0x03, 0x4c, 0x6b, 0x70, 0xc1,
+  0xde, 0xbe, 0x37, 0xa4, 0x32, 0x5e, 0xcc, 0x4d, 0x9b, 0x57, 0xd5, 0x13,
+  0xea, 0x37, 0xb8, 0x75, 0x17, 0x54, 0xb6, 0xf8, 0x75, 0x3f, 0xff, 0x57,
+  0x9e, 0x7b, 0x20, 0x7e, 0xff, 0x88, 0x44, 0x43, 0x40, 0xb0, 0x84, 0x3b,
+  0x00, 0x00, 0x94, 0x52, 0x02, 0x54, 0xa4, 0x08, 0xc0, 0x00, 0xb2, 0xb4,
+  0x50, 0x83, 0xa7, 0xb8, 0xc6, 0x88, 0x33, 0x46, 0xec, 0x48, 0x2d, 0x2f,
+  0xf2, 0xc1, 0x0f, 0xd5, 0xc3, 0x3d, 0x19, 0xa9, 0x77, 0x34, 0x0d, 0xc6,
+  0x26, 0x84, 0x24, 0x37, 0xc8, 0x0a, 0xc2, 0x93, 0x9d, 0xa3, 0x2d, 0x6a,
+  0x11, 0x35, 0x83, 0x12, 0x45, 0xaa, 0x94, 0x63, 0x97, 0xd3, 0x37, 0x5c,
+  0x21, 0xc0, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x31, 0x72,
+  0x84, 0x23, 0x18, 0x6a, 0x16, 0xa2, 0xea, 0xfa, 0x3d, 0x91, 0x8e, 0x95,
+  0x72, 0x54, 0xd5, 0x05, 0x20, 0x08, 0x18, 0x9f, 0x3e, 0xe8, 0xad, 0x17,
+  0xef, 0x6d, 0xe0, 0x7c, 0xc4, 0x37, 0x25, 0x73, 0xcd, 0xcd, 0x9b, 0x23,
+  0x2b, 0xde, 0x76, 0x25, 0xcd, 0x2d, 0x1a, 0x62, 0xee, 0x3c, 0x2b, 0x1d,
+  0xe5, 0xbe, 0x35, 0xd2, 0x37, 0x41, 0x2d, 0x30, 0xee, 0x1e, 0xb6, 0xbd,
+  0x5f, 0x94, 0x9d, 0xf3, 0xb1, 0x38, 0x65, 0xfe, 0x73, 0xcb, 0x1e, 0xcb,
+  0x7a, 0xa6, 0x5b, 0x72, 0xc9, 0x65, 0x64, 0x7c, 0xf1, 0xa4, 0xf3, 0xe6,
+  0x15, 0x71, 0x28, 0xd2, 0xd1, 0xeb, 0xc7, 0x07, 0xdc, 0xac, 0x5d, 0xca,
+  0x74, 0x6d, 0xa1, 0x78, 0x3b, 0x99, 0xd3, 0x70, 0x57, 0x8f, 0x8c, 0x24,
+  0x6b, 0xc4, 0xc3, 0x47, 0xb1, 0xe2, 0xaf, 0x8d, 0x16, 0xb6, 0x5e, 0x46,
+  0xee, 0x5e, 0x7f, 0x95, 0x30, 0x74, 0x2c, 0x36, 0x4c, 0x1a, 0xe1, 0x37,
+  0xda, 0x04, 0xbc, 0x2d, 0x40, 0xfa, 0xcf, 0x42, 0x68, 0x56, 0xb4, 0x5c,
+  0x82, 0x96, 0x60, 0x4f, 0xef, 0x7d, 0x83, 0x28, 0xcb, 0xb2, 0x00, 0x2c,
+  0x0b, 0xf3, 0xe3, 0xc8, 0xb8, 0x5c, 0x35, 0xbd, 0x75, 0x6f, 0x6c, 0x09,
+  0x23, 0x45, 0xea, 0xa8, 0x05, 0x4e, 0x42, 0x0c, 0x99, 0x00, 0x5f, 0x21,
+  0x08, 0xaf, 0x8b, 0x97, 0x31, 0x84, 0x1b, 0xaf, 0xec, 0x36, 0x72, 0x1b,
+  0xef, 0xf7, 0x84, 0x4b, 0x41, 0x93, 0x88, 0x62, 0x8b, 0xc1, 0xef, 0xb1,
+  0x96, 0xdf, 0xc5, 0x77, 0x38, 0x6a, 0x0a, 0x3a, 0x75, 0xbb, 0xb8, 0x1f,
+  0x84, 0xb0, 0x61, 0x9d, 0x63, 0xb6, 0x43, 0x7f, 0x9e, 0x8b, 0xf5, 0xde,
+  0x12, 0xb2, 0x44, 0xa8, 0x87, 0x75, 0x25, 0x73, 0x8d, 0xae, 0x75, 0x4b,
+  0x70, 0x95, 0xcb, 0x1a, 0x56, 0xc5, 0x66, 0x0a, 0xb4, 0xd0, 0xba, 0x59,
+  0xe8, 0x9d, 0xac, 0x8e, 0x39, 0x59, 0x9c, 0xfd, 0x76, 0x8a, 0xd5, 0x36,
+  0x3b, 0x57, 0x3c, 0x7a, 0x37, 0xc7, 0xbf, 0xfd, 0x00, 0x0f, 0x9f, 0xf3,
+  0x20, 0x58, 0x6a, 0x1d, 0x80, 0x0a, 0x40, 0x02, 0x65, 0xd0, 0x8a, 0x95,
+  0x0a, 0x0a, 0x2f, 0x85, 0xbd, 0x48, 0x58, 0x15, 0x0a, 0xcc, 0xc8, 0x28,
+  0x89, 0xa7, 0x0e, 0x30, 0xd8, 0xd3, 0x5a, 0x5d, 0x77, 0x6d, 0x35, 0xd1,
+  0x49, 0x2d, 0x76, 0x35, 0x55, 0xb4, 0x06, 0xaa, 0x46, 0x04, 0x98, 0x96,
+  0x2b, 0x49, 0x97, 0xe5, 0xa4, 0x47, 0xdd, 0xf2, 0xe0, 0x01, 0xc0, 0x21,
+  0x1a, 0x88, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1d, 0x71, 0xa4, 0x30, 0x50,
+  0x8c, 0x14, 0x33, 0x11, 0x02, 0x05, 0xeb, 0x6e, 0x9a, 0xb1, 0x1d, 0x15,
+  0xa3, 0x26, 0x58, 0x2a, 0xca, 0xbe, 0x45, 0x62, 0x62, 0x10, 0x25, 0x93,
+  0x38, 0xbb, 0x8a, 0x57, 0x6f, 0x9e, 0x13, 0x97, 0x37, 0xf1, 0x5d, 0x85,
+  0x90, 0x99, 0xaa, 0x30, 0x22, 0x70, 0x83, 0xaf, 0x96, 0xb4, 0xc6, 0xa3,
+  0xc6, 0x54, 0x84, 0x9b, 0xaa, 0x8d, 0x43, 0xde, 0xdc, 0x3a, 0x4a, 0xe4,
+  0xbe, 0xbd, 0x9c, 0x7a, 0xcb, 0xd8, 0x3c, 0xe2, 0xf0, 0x9b, 0x21, 0xfb,
+  0x42, 0x46, 0x93, 0x0d, 0x44, 0xbb, 0x83, 0x57, 0x02, 0xc6, 0xee, 0xb9,
+  0xe5, 0xc5, 0x8a, 0xd2, 0x7c, 0x31, 0x8b, 0x08, 0x38, 0xb7, 0xf9, 0x8d,
+  0x49, 0x37, 0x4f, 0xae, 0xab, 0x94, 0x62, 0xa8, 0xa0, 0x32, 0xec, 0x10,
+  0x6f, 0xf9, 0x2a, 0xc3, 0x47, 0xc1, 0x72, 0xee, 0x39, 0xa0, 0x3d, 0x54,
+  0xf2, 0x57, 0x00, 0x24, 0x30, 0x79, 0x29, 0x57, 0x36, 0x25, 0xd5, 0x3c,
+  0xc1, 0x42, 0xcd, 0x5a, 0x04, 0x9d, 0x66, 0xcd, 0x62, 0xda, 0x1d, 0x19,
+  0x92, 0x69, 0x5d, 0x40, 0xb6, 0x40, 0x90, 0x6d, 0x77, 0x9b, 0x4e, 0xab,
+  0x2c, 0x66, 0x38, 0xff, 0x05, 0x46, 0xad, 0xbe, 0x1a, 0x43, 0x6c, 0xd7,
+  0xf6, 0x8f, 0xeb, 0x8f, 0xc7, 0x47, 0x74, 0x31, 0x01, 0xd1, 0xda, 0x76,
+  0xb4, 0x7d, 0x06, 0x69, 0xb9, 0xe3, 0x9b, 0xa8, 0xb8, 0x94, 0x39, 0x40,
+  0x3f, 0x65, 0x49, 0x8d, 0x8d, 0x31, 0xd6, 0xd3, 0x36, 0xc8, 0x5f, 0xc9,
+  0xb6, 0xca, 0x82, 0x39, 0x4f, 0x59, 0x9d, 0x52, 0xb9, 0x8f, 0xca, 0xf7,
+  0x45, 0xde, 0x6f, 0x01, 0x50, 0xd5, 0x15, 0x41, 0x33, 0xae, 0x6e, 0x18,
+  0x01, 0x4a, 0x48, 0x17, 0x6f, 0x88, 0x1a, 0xbe, 0xbf, 0x78, 0xdb, 0xfc,
+  0x16, 0x1c, 0xf8, 0x3b, 0x38, 0x67, 0x7c, 0x47, 0x96, 0x89, 0x6e, 0x85,
+  0x09, 0x2d, 0x15, 0x92, 0x66, 0xc2, 0xe8, 0x7b, 0x62, 0x1d, 0xce, 0x61,
+  0x61, 0x39, 0x80, 0xaf, 0xa4, 0xa7, 0x29, 0x0b, 0x56, 0x2f, 0x17, 0x68,
+  0xc7, 0xc7, 0xfa, 0xf3, 0xdd, 0xdb, 0x6f, 0x7e, 0xf9, 0xf1, 0x1f, 0xad,
+  0x7d, 0xd1, 0xdd, 0xdd, 0xf3, 0xf6, 0x29, 0x41, 0x30, 0xd4, 0x3b, 0x00,
+  0x0a, 0x84, 0xc8, 0xa9, 0x51, 0x60, 0x08, 0x4a, 0x0a, 0x7d, 0xa3, 0x85,
+  0x32, 0x73, 0xfb, 0xd2, 0x15, 0xb5, 0x9d, 0x62, 0x25, 0x5c, 0x13, 0xc8,
+  0xfd, 0xda, 0xb8, 0x10, 0x8e, 0x4c, 0xd8, 0xe8, 0xad, 0xa1, 0x3a, 0xbc,
+  0x37, 0x6e, 0xc9, 0xc2, 0x08, 0x15, 0x26, 0xc7, 0x78, 0x4e, 0xde, 0x93,
+  0xd5, 0xa4, 0x84, 0x80, 0xd0, 0xba, 0x0c, 0xdf, 0xa9, 0xde, 0xb0, 0x15,
+  0xb2, 0xfd, 0xc6, 0x34, 0xd1, 0x43, 0xc4, 0x95, 0x89, 0xd2, 0x42, 0xb4,
+  0xab, 0x21, 0x55, 0x74, 0xf5, 0xe2, 0xce, 0x73, 0x6b, 0x8c, 0xa6, 0x00,
+  0x01, 0x98, 0xd2, 0xc1, 0x79, 0xe6, 0xa1, 0x4d, 0xfe, 0xff, 0x67, 0x46,
+  0x39, 0x70, 0xed, 0x80, 0x0e, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x00, 0xff,
+  0xff, 0x1d, 0x6c, 0xa6, 0x30, 0xd0, 0xe4, 0x34, 0x0b, 0x0c, 0xc2, 0x01,
+  0xa5, 0xdb, 0x8f, 0x57, 0xae, 0x1a, 0x45, 0xee, 0xf2, 0x12, 0x92, 0x89,
+  0x2a, 0x6c, 0x5a, 0x46, 0x24, 0xd1, 0x91, 0x4a, 0xec, 0x42, 0x65, 0x65,
+  0x50, 0xa8, 0x99, 0x42, 0x4d, 0x50, 0x78, 0x1b, 0xf7, 0xb5, 0x3e, 0xa3,
+  0xc5, 0x7a, 0xc2, 0xa3, 0x17, 0x44, 0x64, 0x00, 0xb9, 0x7f, 0x3f, 0x3d,
+  0x47, 0x7d, 0x93, 0x58, 0x0e, 0x97, 0xea, 0x28, 0xdf, 0x13, 0xff, 0xb5,
+  0x9f, 0xd4, 0xfe, 0x7e, 0x8b, 0xcf, 0x75, 0xac, 0xf5, 0xac, 0x97, 0xb0,
+  0x54, 0x09, 0x9b, 0x91, 0xb7, 0xcf, 0x74, 0xda, 0xfe, 0x23, 0x37, 0xd8,
+  0x7c, 0x6d, 0x9e, 0x1e, 0x05, 0xe6, 0x2f, 0x38, 0xd9, 0x59, 0x40, 0x26,
+  0x26, 0xb9, 0x03, 0x81, 0xa7, 0xd1, 0xc5, 0x25, 0x5f, 0x4e, 0x2a, 0xd0,
+  0x1d, 0xd8, 0x3c, 0x78, 0x5b, 0x70, 0xf8, 0xf9, 0xe9, 0xe8, 0x2c, 0xae,
+  0xe5, 0x6e, 0x49, 0x13, 0xed, 0xfd, 0x52, 0x9a, 0x41, 0xe0, 0xd0, 0xb5,
+  0xb6, 0xf2, 0x25, 0x82, 0x1c, 0x82, 0x83, 0x25, 0x98, 0x2a, 0xe7, 0x8d,
+  0x08, 0xd0, 0x24, 0x8c, 0x04, 0xa5, 0x74, 0x4a, 0x84, 0x6b, 0x82, 0x27,
+  0x84, 0xeb, 0x45, 0xb3, 0x79, 0x5c, 0x7e, 0x58, 0x5c, 0x5e, 0x2f, 0x1c,
+  0x45, 0x80, 0x35, 0x7e, 0x04, 0x31, 0xef, 0x67, 0x82, 0x30, 0xfc, 0xa5,
+  0xbc, 0xee, 0x2f, 0x47, 0x63, 0x43, 0x6d, 0x36, 0x4e, 0x59, 0xc0, 0x21,
+  0xe1, 0xba, 0x84, 0x75, 0x6c, 0xa8, 0x21, 0x21, 0x96, 0x24, 0x70, 0xde,
+  0x4f, 0xb8, 0x10, 0x84, 0x0c, 0x17, 0x87, 0x09, 0x82, 0xce, 0x99, 0xee,
+  0xeb, 0x21, 0x7b, 0xa5, 0xad, 0xa8, 0x69, 0x96, 0xf3, 0x3b, 0xe7, 0x79,
+  0x88, 0x78, 0xb4, 0x8c, 0xf3, 0x63, 0x34, 0xe0, 0xfb, 0x03, 0x73, 0x18,
+  0xa1, 0x5c, 0xd7, 0x15, 0xd2, 0xf7, 0x86, 0xbe, 0xfe, 0xde, 0x17, 0x11,
+  0x7d, 0x1e, 0x1c, 0xbe, 0x78, 0x3e, 0x7e, 0xc5, 0x28, 0x36, 0x12, 0x87,
+  0x60, 0x00, 0x54, 0x15, 0x15, 0x6c, 0x00, 0x04, 0x0d, 0x8b, 0xd8, 0x98,
+  0x0b, 0xa4, 0x29, 0x6a, 0x22, 0xaa, 0xe0, 0x05, 0x6d, 0xaf, 0x77, 0xbd,
+  0x19, 0xf6, 0xbc, 0xa5, 0x5d, 0x2d, 0xb6, 0x0c, 0x33, 0x9b, 0x16, 0xe7,
+  0x0a, 0xf4, 0x5d, 0xe7, 0xc2, 0x45, 0x04, 0xcd, 0x56, 0x3b, 0xd7, 0x03,
+  0x59, 0xc7, 0xfd, 0x9a, 0x74, 0x3f, 0x7d, 0x57, 0xf8, 0x80, 0x6e, 0x78,
+  0x4e, 0xc6, 0x33, 0x6f, 0x5c, 0x28, 0x5b, 0x25, 0xb7, 0x4c, 0xcd, 0x20,
+  0xce, 0x67, 0x7e, 0x52, 0x59, 0x14, 0xd3, 0x6e, 0xf8, 0x6d, 0xb9, 0xcf,
+  0x7f, 0xb7, 0xa7, 0x80, 0x07, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x00, 0x7f,
+  0xff, 0x21, 0x6f, 0xa3, 0xc0, 0xd8, 0x68, 0xa6, 0x1a, 0x84, 0x13, 0xc8,
+  0x27, 0x14, 0xe1, 0x5a, 0x8a, 0xd4, 0xa8, 0xc4, 0xc5, 0x84, 0x30, 0x6b,
+  0xf2, 0x61, 0x95, 0x83, 0xb6, 0xde, 0x25, 0x0c, 0x0c, 0xa8, 0xaa, 0x84,
+  0x4b, 0x1c, 0xdf, 0xcb, 0x38, 0x57, 0xf7, 0x2c, 0x22, 0x11, 0x87, 0xf4,
+  0x04, 0xd4, 0xae, 0xe2, 0xfb, 0x36, 0x00, 0x89, 0x69, 0x17, 0x85, 0x08,
+  0x1e, 0x49, 0x43, 0x98, 0xe7, 0xb9, 0x1b, 0xa7, 0xaf, 0xb8, 0xfa, 0x44,
+  0x6b, 0xc2, 0x35, 0xfe, 0x8c, 0xb0, 0xf8, 0x65, 0x00, 0xb8, 0x66, 0x6f,
+  0xd8, 0x7a, 0x05, 0xd3, 0xc6, 0x63, 0xdc, 0x3b, 0x84, 0x75, 0xaa, 0xa3,
+  0x5b, 0xe8, 0x5a, 0xe6, 0x35, 0xcf, 0xf4, 0xde, 0xd7, 0x1a, 0x81, 0x6f,
+  0x96, 0x4c, 0x9b, 0x19, 0x52, 0xc5, 0x3a, 0x9b, 0x0c, 0xf8, 0xd1, 0xa2,
+  0xc7, 0x0c, 0x2c, 0x95, 0xdc, 0x28, 0xaf, 0x65, 0x66, 0xe8, 0x34, 0x1e,
+  0x02, 0x9f, 0x6a, 0x0a, 0x60, 0x4e, 0x9e, 0x26, 0xb3, 0x2b, 0x67, 0x5c,
+  0x19, 0xb6, 0x02, 0x02, 0x4c, 0x68, 0xd3, 0x24, 0xf3, 0xc2, 0x88, 0x3a,
+  0x80, 0xbf, 0x0c, 0x63, 0x81, 0x09, 0x6f, 0xaa, 0xa2, 0x3a, 0xb4, 0x74,
+  0xed, 0x88, 0x0b, 0x02, 0x9b, 0x75, 0x5d, 0x2f, 0x37, 0x8f, 0x37, 0x01,
+  0x75, 0x2d, 0xeb, 0x5a, 0x86, 0xbb, 0xb8, 0xfe, 0x9b, 0x13, 0x66, 0xd2,
+  0x52, 0x04, 0x26, 0x6c, 0x9d, 0x2b, 0x2f, 0xa9, 0x03, 0xd1, 0xc7, 0x1b,
+  0x23, 0x78, 0x2b, 0x88, 0x49, 0x90, 0x02, 0x47, 0xbd, 0xdb, 0xcd, 0x5d,
+  0x3e, 0x21, 0xc4, 0x47, 0x90, 0x1f, 0x95, 0x91, 0x51, 0xa1, 0xcd, 0xf5,
+  0xc7, 0x80, 0x02, 0x05, 0x18, 0x6c, 0x11, 0xe7, 0x58, 0xc4, 0x0d, 0x07,
+  0xeb, 0x0b, 0xaf, 0x7e, 0x6f, 0xc7, 0x09, 0x95, 0x4a, 0xf3, 0x6b, 0x8c,
+  0x00, 0x09, 0x3b, 0xc6, 0x46, 0x50, 0x9d, 0xbd, 0x71, 0xd7, 0xbb, 0x8a,
+  0x09, 0x63, 0x67, 0x77, 0x50, 0xe3, 0xdf, 0x85, 0x25, 0x12, 0x74, 0x63,
+  0x1c, 0xfd, 0x9d, 0x95, 0x00, 0x0f, 0x9f, 0xc0, 0x28, 0x91, 0x02, 0xc3,
+  0x50, 0xec, 0xa9, 0x51, 0x28, 0xa8, 0x05, 0x49, 0x49, 0x80, 0x20, 0x39,
+  0x4c, 0xda, 0xc9, 0xb5, 0x6a, 0x94, 0x7f, 0x3a, 0x72, 0xbb, 0x8d, 0x6b,
+  0xca, 0x8c, 0x99, 0xa7, 0xe5, 0xc1, 0x32, 0x03, 0x7b, 0xd6, 0x8c, 0x3c,
+  0xce, 0x4d, 0x29, 0xec, 0x9e, 0x60, 0x15, 0x16, 0x64, 0xbe, 0x40, 0x02,
+  0x69, 0x45, 0xe7, 0x3c, 0x6c, 0xbb, 0x2c, 0x96, 0xc2, 0x17, 0x61, 0xea,
+  0xb5, 0x0f, 0x84, 0x91, 0x4d, 0xad, 0x37, 0x87, 0x73, 0x96, 0xf5, 0xec,
+  0x90, 0x0e, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1b, 0x6f,
+  0xa5, 0x30, 0x91, 0x6c, 0x33, 0x08, 0x05, 0xd9, 0xc1, 0x1a, 0x6a, 0x93,
+  0x54, 0x05, 0x10, 0x48, 0xc1, 0x58, 0x1b, 0xd7, 0xb2, 0x1d, 0x1c, 0x7a,
+  0xde, 0x92, 0x26, 0x41, 0x79, 0x15, 0x0f, 0x74, 0x80, 0x90, 0x49, 0x20,
+  0x98, 0x2e, 0xf5, 0xd7, 0x43, 0x95, 0x4d, 0xd4, 0x7f, 0xe8, 0xe3, 0xdc,
+  0xa0, 0x4d, 0xa8, 0x97, 0x51, 0xe7, 0x7f, 0xa4, 0xfa, 0x0f, 0xcf, 0xb8,
+  0xf0, 0x99, 0x1f, 0x9c, 0xa9, 0x5e, 0xf3, 0xed, 0x5d, 0xfc, 0xe8, 0xf9,
+  0x5c, 0xf5, 0xbf, 0x31, 0x29, 0x50, 0xd1, 0x5c, 0x27, 0x61, 0xff, 0x73,
+  0xcf, 0x82, 0xdb, 0xb3, 0x6e, 0x6d, 0x7f, 0xb1, 0x6d, 0x4f, 0x8a, 0xb2,
+  0x59, 0x0d, 0x53, 0xe2, 0x32, 0x4d, 0xcd, 0x98, 0xa3, 0xb8, 0xd8, 0xb6,
+  0x3d, 0x3a, 0xdb, 0x08, 0x30, 0xb2, 0x40, 0xaa, 0x04, 0xfc, 0x35, 0x9a,
+  0x16, 0xa1, 0x80, 0x46, 0xa3, 0x1b, 0xb7, 0xae, 0xa9, 0xd4, 0x5d, 0xe6,
+  0xd5, 0x54, 0xe9, 0x68, 0xf5, 0xe7, 0x99, 0x6a, 0xd4, 0xbc, 0x3f, 0xd1,
+  0xbc, 0x4c, 0x4d, 0x3e, 0xf8, 0x02, 0xe5, 0x97, 0x1f, 0xf3, 0x5d, 0x93,
+  0x98, 0x9d, 0x31, 0x6c, 0xa8, 0x31, 0x2a, 0xd7, 0x50, 0xd2, 0xeb, 0x38,
+  0x54, 0x75, 0x5e, 0xf6, 0xc1, 0x70, 0x54, 0x21, 0x92, 0x51, 0xe5, 0x66,
+  0xac, 0x63, 0x3e, 0x90, 0xb4, 0x86, 0x65, 0xeb, 0x43, 0xc5, 0xff, 0x7a,
+  0x0c, 0x37, 0x1c, 0xf3, 0xb7, 0x23, 0x2b, 0x57, 0x9d, 0x5f, 0x8b, 0x10,
+  0xa2, 0x41, 0x22, 0x00, 0x99, 0x0c, 0x62, 0x06, 0x3e, 0x5b, 0xe3, 0x34,
+  0xa0, 0x5a, 0xec, 0x38, 0x04, 0x61, 0x26, 0x7d, 0x9d, 0xfd, 0x65, 0xbc,
+  0x9b, 0x7f, 0x1c, 0x0f, 0x4c, 0x9f, 0xdf, 0x6a, 0xa0, 0x75, 0x06, 0x77,
+  0x33, 0xb7, 0x56, 0x64, 0xda, 0xaa, 0x5b, 0x64, 0xae, 0xfe, 0xf1, 0xae,
+  0xe7, 0x77, 0xbb, 0x0d, 0xe1, 0xa6, 0x27, 0xf2, 0x3c, 0xbe, 0x13, 0xec,
+  0xa3, 0xa7, 0xa6, 0xb2, 0x57, 0xfe, 0xba, 0xf7, 0xea, 0xea, 0xd9, 0xd5,
+  0x5d, 0xd5, 0x71, 0x5e, 0xfd, 0x79, 0x0f, 0xd3, 0x7c, 0x9f, 0xdc, 0x9f,
+  0x04, 0x1f, 0x7f, 0x62, 0x72, 0x1a, 0x09, 0x84, 0xa1, 0xe6, 0x0a, 0x89,
+  0x42, 0xa0, 0x15, 0x2a, 0x20, 0x08, 0x10, 0x0f, 0x0c, 0x40, 0x37, 0x2e,
+  0x00, 0xef, 0xa5, 0xea, 0xac, 0xa7, 0x22, 0xb5, 0x1a, 0x6b, 0xb6, 0x50,
+  0x8e, 0xeb, 0xe0, 0xd6, 0x2b, 0xa1, 0xa9, 0x82, 0x3b, 0x84, 0xb5, 0xa4,
+  0xc2, 0x60, 0x47, 0xf4, 0x71, 0x75, 0xee, 0x90, 0x7e, 0xff, 0xf0, 0x2e,
+  0x8c, 0xf1, 0x25, 0xfe, 0x30, 0x91, 0xb6, 0x9c, 0xb3, 0x66, 0xb8, 0x03,
+  0xaa, 0xa4, 0x93, 0x37, 0x77, 0x02, 0xda, 0x8d, 0x7b, 0xce, 0xab, 0x3b,
+  0x57, 0xdf, 0x24, 0xde, 0x14, 0xa8, 0x1e, 0xcb, 0xea, 0x9d, 0xf5, 0xd3,
+  0x9e, 0xaf, 0x9f, 0xa7, 0xbb, 0x80, 0x07, 0x21, 0x1a, 0x88, 0x00, 0x00,
+  0x00, 0xff, 0xff, 0x27, 0x6f, 0xa5, 0x30, 0x90, 0x6c, 0x14, 0x3b, 0x0d,
+  0x42, 0x04, 0xd5, 0xac, 0xf3, 0x97, 0x5a, 0x9c, 0x5f, 0x7a, 0x6a, 0x90,
+  0x52, 0x23, 0x7a, 0x60, 0x4a, 0x40, 0xca, 0xc6, 0xb9, 0x30, 0x50, 0x11,
+  0x2a, 0xbb, 0x3f, 0x3a, 0x97, 0xec, 0xde, 0x21, 0xcd, 0x35, 0x67, 0xe5,
+  0x66, 0x0e, 0x6b, 0xfa, 0x7c, 0xf5, 0xe0, 0xba, 0x22, 0x54, 0x1e, 0xec,
+  0xae, 0x46, 0x3d, 0x35, 0xd6, 0x49, 0xb0, 0x82, 0xf4, 0xac, 0x3a, 0x9b,
+  0xa7, 0x23, 0x89, 0x8a, 0xf9, 0xd1, 0x6d, 0xa9, 0xb2, 0x58, 0x2e, 0x88,
+  0xda, 0x11, 0xbb, 0x3b, 0xe6, 0xd7, 0x3d, 0x6e, 0xb8, 0x1f, 0xb5, 0xbe,
+  0xb5, 0xd7, 0x9a, 0x65, 0xb9, 0x0e, 0x87, 0x76, 0xfc, 0xda, 0xf3, 0x65,
+  0x7c, 0xad, 0x9a, 0xd1, 0xc3, 0xbc, 0x43, 0x3c, 0x47, 0x49, 0x0d, 0x20,
+  0xb6, 0x41, 0x79, 0x0e, 0xf4, 0x74, 0x91, 0x2c, 0xd5, 0x32, 0x99, 0xdb,
+  0x66, 0x95, 0x03, 0x47, 0x5a, 0x82, 0xa5, 0x83, 0x14, 0x74, 0x57, 0x0b,
+  0x3e, 0x68, 0x6b, 0x65, 0x41, 0xdc, 0x49, 0xc5, 0x7e, 0x94, 0x21, 0x63,
+  0x85, 0x42, 0x72, 0x9c, 0x95, 0x0c, 0xb6, 0xd0, 0x95, 0x41, 0x56, 0xf1,
+  0xd5, 0xe9, 0x73, 0x1e, 0x28, 0x77, 0xa0, 0xfe, 0x81, 0x2b, 0xe0, 0xba,
+  0x7f, 0x8d, 0x84, 0x77, 0x12, 0xda, 0x4d, 0x0e, 0xa8, 0x27, 0xa5, 0xa9,
+  0xa6, 0x01, 0x5c, 0xa9, 0x3d, 0xb3, 0x25, 0x47, 0x0a, 0x1b, 0xee, 0xf1,
+  0x5a, 0xcd, 0x4c, 0x23, 0x5c, 0x41, 0x44, 0x95, 0x63, 0x05, 0x38, 0xe7,
+  0x67, 0xcb, 0xb2, 0xc0, 0xe6, 0xbb, 0xbc, 0xbe, 0xff, 0x10, 0xb2, 0x7c,
+  0x7e, 0xdb, 0x85, 0x00, 0x36, 0xbd, 0xaf, 0x67, 0xad, 0xfe, 0x29, 0xfe,
+  0x25, 0xf6, 0x9d, 0x63, 0x77, 0x79, 0xe5, 0x7f, 0xba, 0x7d, 0x55, 0xf5,
+  0x0b, 0xd4, 0x43, 0xef, 0x57, 0x46, 0x21, 0x0d, 0x74, 0x9c, 0x69, 0xd1,
+  0x5d, 0x32, 0xaf, 0x3f, 0x24, 0xe5, 0x25, 0x37, 0x31, 0xe6, 0xcc, 0xb1,
+  0x74, 0x82, 0xd2, 0x67, 0x35, 0xd4, 0xc1, 0x9b, 0x5c, 0x68, 0xba, 0xdb,
+  0xef, 0x8b, 0x45, 0xd7, 0x8f, 0x47, 0x3f, 0x6e, 0x7a, 0xa0, 0x01, 0xfb,
+  0xf6, 0x2b, 0x61, 0xa8, 0x76, 0x54, 0xa8, 0x15, 0x2a, 0x29, 0x13, 0x25,
+  0x25, 0x00, 0x10, 0xa0, 0x00, 0xac, 0x15, 0x90, 0x02, 0x80, 0x85, 0x85,
+  0x05, 0x9e, 0x74, 0x0e, 0x02, 0x08, 0xa9, 0x18, 0xc5, 0x54, 0xd0, 0x84,
+  0x3f, 0x5d, 0xb5, 0x93, 0x1c, 0x59, 0xd4, 0x0f, 0xce, 0x3c, 0xde, 0x49,
+  0x78, 0x41, 0xc9, 0xe4, 0x59, 0xf3, 0xc0, 0x1a, 0x0d, 0x12, 0xdb, 0x8a,
+  0x4b, 0x96, 0x78, 0xb6, 0xb7, 0x10, 0xb9, 0x29, 0x7a, 0xd4, 0x11, 0x9a,
+  0xa1, 0x8a, 0x49, 0x6d, 0x40, 0x9e, 0xfb, 0x71, 0xee, 0xf8, 0x5f, 0x08,
+  0x00, 0xe0, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x23, 0x71,
+  0xa1, 0xc1, 0x52, 0x02, 0x10, 0x12, 0xe4, 0xb4, 0x9a, 0xb3, 0x49, 0x57,
+  0x29, 0x39, 0xe0, 0x32, 0xd4, 0x8e, 0x47, 0x8c, 0xe5, 0x76, 0x7c, 0xae,
+  0x3f, 0x2e, 0x3e, 0x49, 0x16, 0x12, 0xde, 0x25, 0x64, 0x4c, 0x43, 0xa7,
+  0xfe, 0xbf, 0x51, 0x1b, 0xa4, 0x36, 0xcd, 0x4b, 0xdd, 0xbc, 0x13, 0x47,
+  0xfe, 0xdf, 0x4c, 0xb1, 0x72, 0xc7, 0x1a, 0x53, 0x01, 0xd5, 0x46, 0x73,
+  0x04, 0x4d, 0xb1, 0x57, 0x67, 0x1d, 0x3e, 0x95, 0x6a, 0x8c, 0xb0, 0xba,
+  0x10, 0x98, 0xe5, 0xf9, 0x31, 0x22, 0x72, 0x71, 0x1a, 0x7b, 0xea, 0xf9,
+  0x9d, 0x68, 0xc7, 0xd6, 0xf1, 0xa7, 0xe3, 0xa9, 0xbb, 0x0f, 0x58, 0xb5,
+  0x0e, 0x6c, 0x02, 0x16, 0x33, 0xe0, 0x9c, 0x56, 0x94, 0xf9, 0xd1, 0x76,
+  0xca, 0x35, 0xd6, 0x6f, 0x69, 0x4b, 0xb3, 0x99, 0x83, 0x67, 0x2d, 0x9d,
+  0xfe, 0x1f, 0xe1, 0x93, 0x2b, 0xb2, 0x6b, 0x6c, 0xdd, 0x1b, 0x27, 0xcb,
+  0x98, 0xc2, 0x77, 0x7b, 0x91, 0xa4, 0x17, 0x45, 0x66, 0x3e, 0xef, 0xda,
+  0x6e, 0x41, 0xbf, 0xb9, 0x3c, 0x5b, 0x10, 0xd4, 0xb1, 0x65, 0x36, 0xb1,
+  0x0c, 0x03, 0x2a, 0x3c, 0x0e, 0xd7, 0x7b, 0x61, 0xc5, 0x7c, 0x48, 0x12,
+  0x2d, 0xf4, 0x7b, 0x17, 0xc5, 0x8c, 0xd2, 0x80, 0xdc, 0xd0, 0x50, 0x2f,
+  0x71, 0x5a, 0x6a, 0x3f, 0xd8, 0x21, 0xbf, 0x02, 0xf3, 0x7e, 0xf6, 0xf8,
+  0xbc, 0xc4, 0x05, 0xe3, 0xb5, 0xb2, 0x20, 0x16, 0xcf, 0x18, 0x59, 0x9c,
+  0xff, 0x0d, 0x76, 0x5c, 0x06, 0x67, 0x5c, 0xbb, 0x83, 0xd4, 0xd9, 0x89,
+  0x9b, 0x20, 0xfb, 0x28, 0xce, 0xb5, 0x2f, 0x89, 0xc0, 0x55, 0x23, 0xd7,
+  0x98, 0x76, 0x6b, 0x48, 0x2c, 0x3c, 0x34, 0xf5, 0x93, 0x86, 0x00, 0x77,
+  0x38, 0xf1, 0x0f, 0x96, 0xb7, 0x12, 0xb5, 0x96, 0x97, 0x83, 0x5d, 0x6d,
+  0x9a, 0x12, 0x5e, 0x84, 0xce, 0xb4, 0xf9, 0x9f, 0xff, 0x6f, 0xda, 0xf0,
+  0xc8, 0x0f, 0xff, 0xf3, 0x21, 0x14, 0x3b, 0x54, 0xa8, 0xa4, 0x54, 0x99,
+  0x28, 0x8a, 0x44, 0x94, 0xc8, 0x99, 0x73, 0x25, 0x58, 0x10, 0x3d, 0xaf,
+  0x06, 0x00, 0x92, 0x49, 0x66, 0x33, 0x98, 0x40, 0x9c, 0x13, 0x1f, 0x54,
+  0x34, 0xfd, 0x19, 0xb4, 0x63, 0x76, 0xfe, 0xd4, 0xe7, 0x42, 0xd3, 0x3f,
+  0x92, 0x03, 0xd3, 0x7a, 0xe9, 0x9f, 0x5e, 0x6b, 0x8c, 0x80, 0x70, 0x21,
+  0x1a, 0x88, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x70, 0xa2, 0x41, 0x58,
+  0x48, 0xd6, 0x08, 0x84, 0x00, 0xe3, 0x56, 0x44, 0xbb, 0xa8, 0x97, 0x50,
+  0x00, 0xa9, 0x53, 0xb1, 0x83, 0x22, 0xdd, 0x0e, 0x56, 0x35, 0x15, 0x58,
+  0x81, 0x55, 0xe7, 0x44, 0x98, 0x3f, 0x3f, 0xf9, 0x2a, 0xc8, 0x7f, 0xa2,
+  0x4c, 0x01, 0x99, 0x01, 0x9a, 0xff, 0x15, 0xe6, 0xbc, 0x6d, 0x20, 0x73,
+  0x02, 0x3c, 0xce, 0xd2, 0x34, 0xc1, 0xad, 0x34, 0x6f, 0xfb, 0x5d, 0x42,
+  0xeb, 0x5e, 0x65, 0xe4, 0xc6, 0xd4, 0xf1, 0xcf, 0xb3, 0xdd, 0xf2, 0xff,
+  0x97, 0x0b, 0x55, 0xec, 0xa8, 0x1b, 0xb3, 0xef, 0x4b, 0xf4, 0xad, 0x37,
+  0x51, 0x93, 0xa8, 0xf4, 0x1a, 0x5c, 0x53, 0x3a, 0x83, 0x0e, 0x56, 0xf1,
+  0x8e, 0x5e, 0xff, 0x22, 0xf0, 0xff, 0x5a, 0xd3, 0x50, 0x3d, 0x62, 0x8b,
+  0x0a, 0x33, 0x1a, 0x2e, 0x8a, 0x0f, 0xd4, 0x65, 0x46, 0x2b, 0x2a, 0xbf,
+  0x5c, 0x5f, 0xe3, 0x71, 0x74, 0x44, 0x59, 0x7b, 0x99, 0x41, 0x89, 0xa1,
+  0xc2, 0x06, 0x54, 0x14, 0x2d, 0xe1, 0x64, 0x87, 0xef, 0x48, 0x77, 0x48,
+  0x72, 0x92, 0xb0, 0x31, 0xbb, 0x8d, 0xa9, 0x20, 0x06, 0xb4, 0x92, 0x6d,
+  0x1d, 0x1f, 0x2c, 0x06, 0xd6, 0x3c, 0x43, 0x3d, 0xf3, 0x88, 0xfe, 0x10,
+  0x8d, 0x6c, 0xc8, 0xc1, 0x26, 0xac, 0xb8, 0x45, 0x1f, 0x15, 0x42, 0x28,
+  0x3f, 0x0f, 0x1a, 0xb5, 0xf1, 0xe1, 0x0b, 0xe8, 0xbe, 0x48, 0x86, 0x02,
+  0x76, 0x6f, 0xcb, 0x7c, 0x2f, 0xd5, 0xf1, 0xad, 0xbb, 0xa1, 0x00, 0x7d,
+  0x9a, 0x14, 0x6d, 0xc1, 0x4a, 0xef, 0xa7, 0x7b, 0xc8, 0x68, 0x97, 0x1f,
+  0x45, 0xa1, 0x44, 0x6c, 0x05, 0x3e, 0xd6, 0x2b, 0xe7, 0x44, 0x8d, 0x57,
+  0xd3, 0x1f, 0x6c, 0x6f, 0xb5, 0x13, 0xa3, 0xb5, 0xcf, 0xe4, 0x4f, 0x1c,
+  0x3c, 0x18, 0x38, 0x73, 0x48, 0x3b, 0xa1, 0x22, 0xc2, 0x74, 0xf7, 0x40,
+  0xd0, 0x5d, 0xdd, 0x6f, 0xb1, 0xcc, 0x8b, 0xa8, 0xd2, 0xd6, 0x7a, 0x1d,
+  0x1d, 0x92, 0x5c, 0x4c, 0x56, 0xc1, 0x3e, 0x4d, 0x3c, 0x5b, 0x5c, 0x9f,
+  0x5f, 0xcf, 0x6d, 0xc1, 0xfb, 0xfe, 0x74, 0x26, 0xd1, 0x55, 0x2a, 0x2a,
+  0x51, 0x00, 0x10, 0xa1, 0x51, 0x52, 0x42, 0x81, 0x6a, 0xe3, 0xb7, 0xfe,
+  0x31, 0xf7, 0x01, 0x3f, 0x22, 0x20, 0x60, 0x52, 0x99, 0x70, 0x06, 0x80,
+  0x43, 0xad, 0x6a, 0x3d, 0x37, 0x1e, 0xc2, 0x45, 0x17, 0x0a, 0x69, 0xdd,
+  0xdf, 0x07, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x07, 0xff, 0xff, 0x2b, 0x6f,
+  0xa5, 0x30, 0x50, 0x8c, 0x54, 0x1b, 0x0d, 0x42, 0x0e, 0x35, 0x6d, 0x2d,
+  0x69, 0x75, 0xa9, 0x63, 0x55, 0x42, 0x03, 0x2d, 0x57, 0x43, 0xbf, 0x70,
+  0x62, 0x52, 0xb5, 0x92, 0xbe, 0x83, 0xf4, 0xb0, 0x49, 0x50, 0x3c, 0xa9,
+  0x70, 0xa1, 0xd8, 0x35, 0xed, 0xcb, 0xdb, 0xfe, 0x05, 0xe3, 0x3e, 0x10,
+  0x99, 0x0b, 0x32, 0x0f, 0x4b, 0xfe, 0x8f, 0xd2, 0x78, 0xc7, 0x48, 0xe1,
+  0x4c, 0x5f, 0x17, 0xaa, 0x79, 0x97, 0x83, 0xc6, 0x9d, 0x31, 0xa4, 0xa3,
+  0x2a, 0x5b, 0xb9, 0xe5, 0xc4, 0xc8, 0x2e, 0x70, 0x52, 0xd9, 0x0e, 0xcd,
+  0x27, 0xfe, 0x3e, 0x48, 0x67, 0x7a, 0x6d, 0x62, 0xc2, 0xbf, 0x45, 0xea,
+  0x12, 0x0b, 0xe3, 0x74, 0x50, 0xd7, 0x3f, 0x43, 0x03, 0x0f, 0x38, 0x41,
+  0xb7, 0x9d, 0x1e, 0x9a, 0x10, 0x88, 0x4d, 0xfb, 0x95, 0x34, 0xae, 0x42,
+  0x41, 0x48, 0x67, 0x3c, 0x5d, 0x28, 0x1d, 0x4f, 0x3e, 0xc5, 0x70, 0xb0,
+  0xf7, 0x2b, 0xa9, 0x66, 0x1d, 0xaa, 0x12, 0x02, 0xbc, 0x64, 0xeb, 0x6b,
+  0x64, 0x49, 0x92, 0x46, 0x13, 0x4d, 0x65, 0xdc, 0x52, 0x9d, 0x89, 0x4c,
+  0x4b, 0x56, 0x33, 0x84, 0x83, 0x13, 0x89, 0xe2, 0x40, 0x59, 0x4a, 0x47,
+  0xbd, 0xd0, 0xd8, 0x79, 0xe9, 0xe9, 0xfb, 0xf7, 0xc0, 0x76, 0xeb, 0xb6,
+  0x0b, 0xac, 0x22, 0x80, 0xdd, 0x74, 0xae, 0x54, 0x46, 0x43, 0x73, 0x23,
+  0xd4, 0xc2, 0x0c, 0x09, 0x7c, 0x91, 0x51, 0x33, 0x83, 0x9e, 0x1c, 0x54,
+  0x86, 0x53, 0x29, 0x6e, 0x46, 0xbd, 0x09, 0x4a, 0x44, 0x66, 0x96, 0xb0,
+  0xc1, 0xc6, 0x2d, 0x3a, 0xd9, 0xe0, 0xb8, 0x2c, 0x01, 0xa3, 0x05, 0x86,
+  0x10, 0xf1, 0x7a, 0x5b, 0x4d, 0xf2, 0xe4, 0x51, 0x7d, 0x7b, 0x4c, 0x36,
+  0xe0, 0x66, 0x7b, 0xb2, 0x38, 0x10, 0xfc, 0x19, 0xde, 0x5a, 0x66, 0x8f,
+  0xa6, 0x44, 0x52, 0xe8, 0x70, 0x9e, 0x74, 0xae, 0xeb, 0x9c, 0xb9, 0x00,
+  0x03, 0xb9, 0x45, 0x62, 0x6d, 0x20, 0xa9, 0x09, 0x5f, 0x3e, 0x1d, 0xff,
+  0x5c, 0x67, 0x2d, 0x58, 0xcf, 0x94, 0xb3, 0x5f, 0x7f, 0xb7, 0xed, 0xf4,
+  0xc7, 0xd1, 0xdb, 0xdb, 0xe0, 0x00, 0xfb, 0xf8, 0x36, 0x10, 0x98, 0x66,
+  0x1d, 0x94, 0x84, 0xa5, 0x45, 0x5e, 0x42, 0x92, 0x80, 0x40, 0x22, 0x6c,
+  0x6d, 0x4f, 0x14, 0x90, 0x9d, 0x61, 0x2d, 0x80, 0x12, 0x82, 0x84, 0x02,
+  0xf6, 0x43, 0x54, 0xbc, 0x34, 0xef, 0x66, 0x38, 0xf3, 0xed, 0x0d, 0x8c,
+  0x4e, 0xae, 0xf4, 0x68, 0x46, 0xd8, 0x36, 0x2f, 0xa9, 0x39, 0xd7, 0x76,
+  0xb5, 0xb7, 0xb4, 0xb6, 0x3f, 0xdc, 0x5b, 0x6e, 0x53, 0x74, 0xec, 0x64,
+  0xb8, 0x51, 0xe9, 0x85, 0xa7, 0x3a, 0xac, 0x45, 0xd5, 0x72, 0x78, 0x29,
+  0xde, 0x7f, 0x79, 0x4c, 0x8e, 0x44, 0xba, 0x5b, 0x85, 0x4e, 0x66, 0xe6,
+  0x60, 0xd6, 0x90, 0x27, 0x1a, 0x6a, 0xa8, 0xb7, 0x64, 0xc8, 0xd3, 0x65,
+  0xca, 0x89, 0x4f, 0x83, 0xcb, 0x5e, 0x76, 0x4c, 0x52, 0x69, 0xfb, 0x8f,
+  0x9f, 0xf4, 0xde, 0x48, 0x70, 0x21, 0x1a, 0x88, 0x00, 0x00, 0x00, 0x03,
+  0xff, 0x23, 0x6f, 0xa5, 0x22, 0x08, 0x68, 0x60, 0x43, 0xac, 0xb7, 0x01,
+  0xc2, 0xd1, 0x2e, 0x92, 0x91, 0x41, 0x29, 0x30, 0x5a, 0x4a, 0x9d, 0xd7,
+  0x76, 0x28, 0x91, 0xd3, 0x5c, 0x43, 0xc7, 0xa7, 0x9f, 0x4f, 0x58, 0x1a,
+  0xd4, 0x46, 0xf7, 0x9e, 0xed, 0x22, 0x63, 0xa8, 0xf3, 0xa4, 0x34, 0x27,
+  0x4d, 0xd8, 0x1c, 0x89, 0xcc, 0x5a, 0x86, 0x8e, 0xed, 0xde, 0xb2, 0x85,
+  0x57, 0xd5, 0x4c, 0x73, 0x46, 0xf4, 0x1c, 0xf6, 0xef, 0x82, 0x66, 0xbd,
+  0xa9, 0x64, 0x6c, 0xfa, 0x24, 0x9b, 0x63, 0x76, 0xff, 0x2a, 0xbf, 0xda,
+  0x6a, 0x0f, 0xb6, 0xb2, 0x5d, 0x48, 0xdf, 0x0d, 0xd4, 0x69, 0xe4, 0xb8,
+  0xdb, 0x69, 0x8e, 0x0a, 0x33, 0x7a, 0xa8, 0x8d, 0x5e, 0x75, 0xa7, 0x01,
+  0x81, 0xca, 0x4c, 0x55, 0xd3, 0xa5, 0x90, 0x65, 0x5a, 0xd3, 0x0d, 0x54,
+  0x85, 0x62, 0xc1, 0x33, 0xd0, 0x98, 0x89, 0xfc, 0x31, 0x86, 0x60, 0x31,
+  0x5c, 0x59, 0x2e, 0x1a, 0x42, 0x18, 0x2c, 0x03, 0x9a, 0xcc, 0x18, 0x7d,
+  0x7f, 0xf5, 0xbe, 0x65, 0x8f, 0xa2, 0x93, 0x49, 0xe8, 0xb6, 0x15, 0xea,
+  0xe7, 0xb5, 0x8b, 0x7e, 0x41, 0x3f, 0x14, 0xf4, 0x74, 0xc0, 0x7f, 0x95,
+  0x1a, 0x0c, 0xbc, 0xc1, 0x3c, 0xe0, 0x8d, 0x4b, 0x67, 0x40, 0x98, 0x2b,
+  0x96, 0xe8, 0x73, 0x0a, 0x06, 0xec, 0x02, 0xfb, 0x9b, 0x87, 0x04, 0x06,
+  0xfd, 0x53, 0x4b, 0xf8, 0x5f, 0x07, 0xdd, 0xd9, 0xbb, 0x49, 0xea, 0x85,
+  0xa0, 0xf0, 0xfe, 0x1d, 0x03, 0xa6, 0xe8, 0x09, 0xa3, 0x25, 0x77, 0x19,
+  0xf1, 0xa0, 0xfe, 0x81, 0x80, 0x83, 0x5e, 0x24, 0x71, 0xd9, 0x62, 0xe5,
+  0x20, 0x2a, 0xe8, 0xce, 0x8f, 0xf4, 0x8a, 0xf8, 0x66, 0xf7, 0xd1, 0xeb,
+  0x62, 0xd4, 0x0a, 0xe5, 0xe3, 0x7d, 0x8a, 0xad, 0xea, 0xaa, 0x1d, 0xa5,
+  0x41, 0xc1, 0xa2, 0x3b, 0xc8, 0x37, 0x8a, 0x57, 0x10, 0x1d, 0x77, 0x77,
+  0x7e, 0xff, 0x88, 0x48, 0x82, 0x61, 0x18, 0x79, 0xba, 0x04, 0x55, 0x25,
+  0x25, 0x42, 0xa2, 0x55, 0x44, 0xa5, 0x81, 0x01, 0x3f, 0xfd, 0x5d, 0x52,
+  0xc9, 0x05, 0xef, 0x35, 0x9d, 0x28, 0x8c, 0xb9, 0xa2, 0xa8, 0x02, 0xaa,
+  0x63, 0x21, 0xaa, 0xa5, 0xa2, 0xad, 0x0a, 0x9e, 0x0e, 0x3a, 0x9e, 0x61,
+  0x22, 0x95, 0x45, 0x86, 0xf3, 0xdc, 0x15, 0xb2, 0x03, 0x99, 0x9d, 0x84,
+  0x04, 0x74, 0xd5, 0x41, 0x0d, 0xa9, 0xe5, 0x36, 0x3d, 0x9e, 0xd0, 0x70,
+  0x21, 0x1a, 0x8f, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0x19, 0x6f, 0xa4, 0xb1,
+  0x11, 0x6c, 0x25, 0x08, 0x15, 0x5d, 0x25, 0xca, 0xab, 0x5d, 0x71, 0x65,
+  0xa8, 0x22, 0x81, 0x57, 0x54, 0x28, 0x95, 0x77, 0x89, 0x25, 0x28, 0x92,
+  0x46, 0x4c, 0x24, 0x20, 0x91, 0x5d, 0x83, 0xe3, 0xb3, 0xbe, 0xbb, 0x65,
+  0xd6, 0x61, 0xfb, 0x5f, 0x66, 0x51, 0x9e, 0xe7, 0x4d, 0x3f, 0xa5, 0xc0,
+  0x7f, 0x6e, 0x90, 0xca, 0x81, 0x8d, 0x3e, 0xe1, 0x61, 0xe1, 0x1c, 0xa9,
+  0x0d, 0xf5, 0x08, 0x96, 0x84, 0xfa, 0xd7, 0x17, 0x69, 0x2c, 0x27, 0x78,
+  0xba, 0xe3, 0x9a, 0xc0, 0xcf, 0xfc, 0xe7, 0x21, 0xba, 0xf5, 0x9e, 0x34,
+  0xf5, 0xb5, 0xf1, 0x96, 0xb3, 0x9f, 0x6e, 0x08, 0xa9, 0x38, 0x41, 0x7a,
+  0x83, 0xf5, 0x2a, 0xd8, 0x49, 0xf2, 0xf2, 0x55, 0x52, 0xab, 0xea, 0x5f,
+  0x95, 0x31, 0x5f, 0x4e, 0x5d, 0x36, 0x32, 0xbd, 0x8f, 0xae, 0x45, 0x38,
+  0x75, 0xc9, 0x56, 0xa1, 0xb4, 0x52, 0xce, 0x47, 0xc1, 0x57, 0xdc, 0xa7,
+  0xb3, 0x60, 0x1e, 0x1b, 0xc5, 0x0b, 0x96, 0xfd, 0x05, 0xa2, 0xcc, 0xe5,
+  0xdf, 0x7f, 0x3a, 0x58, 0xb3, 0x17, 0x87, 0x57, 0x59, 0x61, 0xd1, 0x29,
+  0x70, 0x24, 0xb5, 0x81, 0xc0, 0x41, 0x55, 0xc8, 0x3a, 0xd6, 0xb2, 0x0f,
+  0x37, 0xf3, 0xa1, 0xe0, 0x77, 0xe0, 0x09, 0x53, 0x85, 0xb9, 0x1e, 0xe2,
+  0xbf, 0x37, 0xe7, 0x64, 0x6a, 0xea, 0x3e, 0x3d, 0xef, 0xfd, 0x1c, 0x13,
+  0xe8, 0x22, 0xc2, 0xf4, 0x07, 0x41, 0xd4, 0xba, 0xe7, 0x59, 0x54, 0x5b,
+  0x74, 0xd5, 0x08, 0x6c, 0xbd, 0x56, 0x59, 0x67, 0xa9, 0x67, 0xa9, 0x31,
+  0x81, 0xde, 0xfc, 0x21, 0x45, 0x75, 0x58, 0xb5, 0x63, 0x7e, 0xe8, 0x8e,
+  0xc2, 0x3e, 0x32, 0x53, 0x17, 0x10, 0xae, 0xda, 0xdf, 0x1b, 0xf6, 0x3c,
+  0x76, 0xa7, 0x50, 0x5f, 0xd5, 0xa0, 0x3b, 0x82, 0x4e, 0xf6, 0xfa, 0x7b,
+  0x4e, 0x13, 0xa9, 0xcd, 0x75, 0xd4, 0x51, 0x8b, 0x03, 0xec, 0xc2, 0x52,
+  0x40, 0x76, 0x14, 0xa6, 0x50, 0xa5, 0x02, 0xfb, 0x51, 0x3a, 0x7d, 0x5f,
+  0x3c, 0xf7, 0xec, 0x00, 0x8c, 0xb2, 0x52, 0xbc, 0xc8, 0x53, 0x73, 0x08,
+  0xc2, 0x01, 0xb4, 0xf8, 0xd3, 0x98, 0x8c, 0xb8, 0x58, 0x00, 0x2b, 0x54,
+  0x1b, 0x27, 0x74, 0x7c, 0x14, 0x7d, 0xb8, 0xf1, 0x4e, 0x68, 0xfa, 0xcd,
+  0x74, 0x89, 0x0c, 0x5e, 0x81, 0x5c, 0xcb, 0xdd, 0x39, 0x94, 0x11, 0xc6,
+  0x01, 0x30, 0x19, 0x88, 0x57, 0x1a, 0xa3, 0x6a, 0xa6, 0xad, 0x25, 0x92,
+  0xbf, 0xf5, 0xf3, 0xfa, 0xb8, 0xf3, 0x13, 0xf1, 0x2f, 0xc2, 0x00, 0x79,
+  0xd5, 0x34, 0x09, 0x9b, 0xa0, 0xa5, 0x0c, 0xdd, 0xb5, 0xe9, 0x2a, 0xf6,
+  0x8e, 0x59, 0x92, 0x83, 0x88, 0x05, 0xe9, 0x81, 0x0b, 0xa7, 0x55, 0xc6,
+  0xdd, 0x89, 0x0a, 0x4d, 0xd9, 0xc8, 0x2d, 0xb3, 0x30, 0x08, 0x52, 0x02,
+  0x85, 0x13, 0xcb, 0xc5, 0x12, 0x13, 0x87, 0x62, 0x10, 0x4e, 0xba, 0x6a,
+  0xb8, 0xb1, 0xd2, 0x3c, 0xcc, 0xee, 0x66, 0xa9, 0xdf, 0xe9, 0xda, 0xfc,
+  0xa4, 0xb1, 0x18, 0x6e, 0x58, 0x44, 0x6c, 0x67, 0xa5, 0x54, 0x45, 0xe9,
+  0x53, 0x4e, 0xa1, 0x32, 0x82, 0x7c, 0xd7, 0x83, 0xec, 0xfa, 0x9b, 0x41,
+  0xc0, 0x21, 0x1a, 0x8f, 0xf0, 0x07, 0xff, 0xff, 0xff, 0x1d, 0x6f, 0xa4,
+  0xb0, 0xd1, 0xac, 0x17, 0x08, 0x12, 0xa8, 0xf2, 0xb4, 0x70, 0x95, 0x6d,
+  0x28, 0x82, 0x92, 0x89, 0x50, 0x09, 0x09, 0x64, 0x9c, 0xda, 0x89, 0x84,
+  0x02, 0x32, 0x61, 0xab, 0x77, 0x86, 0xa4, 0x49, 0x0a, 0x6e, 0x24, 0x21,
+  0x70, 0x5c, 0x4b, 0xdb, 0x3f, 0x3f, 0x84, 0xf5, 0xaf, 0xd4, 0x3b, 0x22,
+  0x9f, 0xf1, 0x0b, 0x93, 0xc0, 0x72, 0x36, 0xbc, 0x7c, 0xfd, 0xa3, 0x9b,
+  0xd5, 0x21, 0x17, 0xaf, 0x5e, 0xd2, 0x6d, 0xdc, 0xb9, 0x31, 0x3c, 0x4c,
+  0x7c, 0x8f, 0x58, 0x26, 0xa8, 0x70, 0x76, 0x2f, 0x16, 0xbd, 0x93, 0x7b,
+  0x16, 0xc1, 0x5d, 0x62, 0xe9, 0xa4, 0x8e, 0xf7, 0x89, 0x55, 0xb2, 0xc0,
+  0x92, 0xa6, 0xab, 0x1a, 0xbe, 0x31, 0x80, 0xe1, 0xac, 0xb6, 0x0a, 0x64,
+  0x74, 0xf5, 0x7b, 0x1b, 0xb6, 0xf1, 0x28, 0x79, 0xbe, 0x97, 0x24, 0xff,
+  0x23, 0x56, 0xd1, 0x3e, 0x38, 0x87, 0x63, 0x35, 0xd4, 0xd5, 0x35, 0xa5,
+  0x55, 0xbb, 0x56, 0x71, 0x5e, 0xfe, 0xb9, 0x38, 0x51, 0x1c, 0xaf, 0x27,
+  0x0c, 0xce, 0x62, 0x37, 0xa9, 0xc2, 0x24, 0x73, 0x94, 0xe9, 0x6c, 0xed,
+  0x4d, 0xe0, 0x31, 0x4f, 0x53, 0xdd, 0xaf, 0x43, 0x53, 0x97, 0x0d, 0xd5,
+  0x12, 0x83, 0x7e, 0x99, 0x39, 0x96, 0x2e, 0x49, 0xa1, 0x5d, 0xae, 0xdc,
+  0x06, 0x3c, 0x77, 0x82, 0xe3, 0x06, 0xb4, 0x83, 0x58, 0x6d, 0x1e, 0x90,
+  0x1f, 0xd0, 0xcd, 0x22, 0x44, 0x72, 0xdb, 0x7d, 0xf7, 0xaa, 0xfa, 0xfb,
+  0x0a, 0x04, 0x24, 0x7f, 0x5f, 0xfe, 0x21, 0x3d, 0x26, 0x6f, 0xa9, 0xa5,
+  0x8d, 0x1d, 0xf7, 0xaa, 0x90, 0x80, 0xc4, 0x39, 0x01, 0x12, 0x38, 0x19,
+  0xd2, 0xc8, 0x68, 0x3c, 0x8d, 0x77, 0xa0, 0xbb, 0x3a, 0xf3, 0x16, 0x03,
+  0x7d, 0xcf, 0xf8, 0x67, 0xd9, 0xda, 0x00, 0x34, 0x17, 0x46, 0x79, 0xcc,
+  0x9c, 0xad, 0x11, 0x2a, 0x09, 0x27, 0xb0, 0xa5, 0x47, 0x5e, 0x0f, 0x0a,
+  0xeb, 0x78, 0x1e, 0x0e, 0x8f, 0x30, 0x04, 0x85, 0x9f, 0xd2, 0xc7, 0x12,
+  0x80, 0x85, 0x08, 0x31, 0x08, 0x1e, 0xdb, 0x4a, 0x45, 0x65, 0xf5, 0x56,
+  0x16, 0x09, 0x41, 0x6a, 0xe4, 0x5b, 0x5b, 0x3b, 0x82, 0x43, 0x3e, 0x7e,
+  0x3f, 0xe2, 0x8a, 0xc0, 0x0e, 0xe6, 0x4f, 0xad, 0x53, 0xc8, 0xdf, 0xd9,
+  0xae, 0xbb, 0xdd, 0xf5, 0xff, 0xcf, 0x14, 0xed, 0xcf, 0x71, 0x5e, 0x1b,
+  0x27, 0xdd, 0xc6, 0xf1, 0x56, 0x46, 0x86, 0x99, 0x86, 0xb8, 0x91, 0xe8,
+  0x58, 0x69, 0xde, 0x81, 0x11, 0x95, 0xf2, 0x78, 0x7e, 0x30, 0x87, 0xaa,
+  0xa9, 0xd7, 0x9c, 0x45, 0x99, 0xa2, 0xb6, 0x49, 0xb6, 0x69, 0x65, 0x95,
+  0x95, 0x46, 0x91, 0x22, 0xe9, 0x67, 0xef, 0x39, 0x65, 0xb6, 0x50, 0x12,
+  0xfd, 0xc0, 0x04, 0x77, 0x89, 0xa8, 0x34, 0x2d, 0x23, 0xfa, 0xf4, 0xdf,
+  0xa7, 0xfb, 0xfd, 0x99, 0xea, 0x51, 0x2f, 0xf4, 0x45, 0x1a, 0x12, 0x9f,
+  0x93, 0x82, 0x7c, 0xe4, 0x24, 0xdf, 0xcb, 0xf4, 0x7c, 0xfd, 0x83, 0x4f,
+  0x6f, 0x0d, 0xd4, 0xf0, 0x6a, 0x07, 0x21, 0x1a, 0x8f, 0xe0, 0x2f, 0x7f,
+  0xff, 0xff, 0x1d, 0x6f, 0xa2, 0xc1, 0x52, 0x06, 0x10, 0x06, 0x8d, 0x2a,
+  0xeb, 0x89, 0x75, 0x6b, 0x55, 0x42, 0x54, 0x50, 0x45, 0x02, 0x22, 0x59,
+  0x38, 0xa8, 0xc8, 0x45, 0x27, 0x2e, 0xbe, 0x06, 0x58, 0x31, 0x00, 0x3a,
+  0xdd, 0x9f, 0x5a, 0x8e, 0x5c, 0x16, 0x04, 0x1c, 0x08, 0x7d, 0x73, 0xfd,
+  0x7c, 0xaa, 0x3f, 0x9f, 0xda, 0xb8, 0x71, 0x31, 0x97, 0xf3, 0x2c, 0x0b,
+  0x66, 0x12, 0xcb, 0x86, 0xd8, 0x5d, 0x01, 0x8b, 0xda, 0xa1, 0x98, 0x24,
+  0x2d, 0xbd, 0x9f, 0x24, 0x49, 0x2a, 0x6f, 0xdd, 0x72, 0xa8, 0x67, 0x88,
+  0x15, 0x73, 0x13, 0xac, 0x3d, 0xe4, 0x1b, 0xcf, 0xc0, 0x6b, 0x84, 0xa2,
+  0x5f, 0x27, 0x3e, 0xf3, 0xd6, 0x39, 0x3a, 0x8b, 0x09, 0x3d, 0x38, 0xe4,
+  0x26, 0x83, 0x78, 0x7a, 0x5c, 0xd1, 0xb8, 0xd6, 0x64, 0xdc, 0xd1, 0xbf,
+  0xd6, 0x20, 0x6e, 0xd2, 0x47, 0x43, 0x4c, 0x39, 0x38, 0x34, 0x74, 0x63,
+  0x87, 0xf1, 0x6e, 0xea, 0xd3, 0x0c, 0xfb, 0x71, 0x4e, 0x2c, 0x24, 0x28,
+  0x70, 0xb2, 0xaf, 0xd7, 0xa9, 0x6f, 0x54, 0x2e, 0x1b, 0xca, 0xb5, 0x7b,
+  0x6b, 0x5b, 0x90, 0x11, 0x96, 0x28, 0xd4, 0x5e, 0xdc, 0x3a, 0xe6, 0x54,
+  0x23, 0x1f, 0x21, 0x8c, 0x0c, 0x97, 0xba, 0xb0, 0x84, 0x3c, 0x8a, 0xdd,
+  0x5e, 0xd4, 0xd9, 0x0f, 0x0e, 0x9a, 0xbb, 0xe6, 0x2a, 0xb1, 0x90, 0x3b,
+  0x47, 0xe8, 0xf3, 0x41, 0x0d, 0xe3, 0x56, 0x5d, 0x94, 0x5b, 0xd4, 0x43,
+  0x73, 0x3f, 0x71, 0x79, 0xda, 0x1e, 0xab, 0x6d, 0x61, 0x55, 0xec, 0x76,
+  0x54, 0x6a, 0xb7, 0x63, 0x41, 0x3d, 0x30, 0x72, 0xf7, 0xa7, 0x05, 0x8e,
+  0x99, 0x9a, 0xad, 0x71, 0x1d, 0x25, 0xbf, 0xd4, 0x86, 0x99, 0x6e, 0x70,
+  0x10, 0x15, 0x37, 0x4b, 0xd6, 0xdd, 0x35, 0xf0, 0x24, 0x9c, 0x5b, 0xb6,
+  0xfe, 0xfa, 0x02, 0xdc, 0xd9, 0xf7, 0x9e, 0xd6, 0x00, 0x93, 0xb3, 0xf9,
+  0xa8, 0x50, 0x74, 0x18, 0x84, 0x04, 0x2a, 0x41, 0x88, 0x43, 0x46, 0x4a,
+  0xca, 0x9f, 0x10, 0xb8, 0xe0, 0x41, 0x03, 0x6b, 0x25, 0x09, 0x16, 0xe7,
+  0x9b, 0xbd, 0xbe, 0x0e, 0xdd, 0x84, 0x61, 0xb7, 0x2e, 0x58, 0x74, 0x43,
+  0xbd, 0xfc, 0x55, 0xd8, 0x72, 0x14, 0x3b, 0x5f, 0xaa, 0xf3, 0xd6, 0xa8,
+  0xd5, 0x40, 0x21, 0xcc, 0x3d, 0x20, 0xba, 0xc0, 0x4f, 0x1a, 0x50, 0x4b,
+  0x98, 0x5c, 0x54, 0x3e, 0x78, 0xd1, 0xcc, 0xe8, 0x1a, 0xde, 0x62, 0xb8,
+  0xb6, 0xc4, 0x8b, 0x05, 0x32, 0x1b, 0xc5, 0xf9, 0x45, 0xfb, 0x92, 0x49,
+  0x66, 0x4e, 0x10, 0x3c, 0xf8, 0x5a, 0xb2, 0xac, 0xba, 0xb4, 0x37, 0xd1,
+  0x7e, 0xd3, 0x00, 0x84, 0xbc, 0xfa, 0x33, 0x89, 0x7e, 0x68, 0x96, 0x00,
+  0x57, 0x83, 0x81, 0xd2, 0x18, 0xbe, 0x74, 0x4b, 0x8b, 0x8d, 0x6e, 0x00,
+  0x44, 0x69, 0x62, 0xa6, 0x3d, 0xb9, 0xb2, 0xd0, 0x50, 0xd7, 0x15, 0xc5,
+  0x73, 0x77, 0x70, 0x95, 0x3d, 0xa1, 0xb7, 0x07, 0x1e, 0x39, 0xc4, 0x84,
+  0x20, 0xf8, 0x6a, 0xb5, 0xbf, 0xaf, 0xdc, 0x38, 0x21, 0x1a, 0x94, 0x75,
+  0xbe, 0x92, 0xc1, 0x44, 0x11, 0x10, 0xa0, 0x47, 0x04, 0x17, 0x13, 0x55,
+  0x5a, 0x8c, 0x84, 0x14, 0x80, 0xa1, 0x59, 0x0e, 0x66, 0x1c, 0x46, 0xa7,
+  0xab, 0x9d, 0x23, 0x65, 0x68, 0x96, 0x8a, 0xe8, 0x20, 0xd9, 0xe5, 0x9f,
+  0xd5, 0x83, 0x96, 0x9f, 0xcc, 0x7f, 0x7f, 0xd9, 0x3b, 0x25, 0x2d, 0x9a,
+  0x62, 0x10, 0x09, 0x98, 0xe2, 0xfd, 0xa5, 0xad, 0x3a, 0x1b, 0xb8, 0xe6,
+  0x1c, 0xf9, 0xdf, 0xf4, 0xca, 0x74, 0xd0, 0x6b, 0xfd, 0xb0, 0xf1, 0x8d,
+  0xa3, 0xe5, 0x40, 0x3f, 0xb4, 0x3e, 0x9b, 0x0f, 0x41, 0x07, 0xac, 0xd7,
+  0x31, 0x59, 0x55, 0x64, 0xb9, 0x9a, 0x81, 0x1a, 0x29, 0x55, 0xf1, 0x8a,
+  0x5c, 0xdb, 0x06, 0x92, 0x9d, 0x68, 0xd0, 0xab, 0x18, 0x12, 0x64, 0x18,
+  0x31, 0xa8, 0xdf, 0x14, 0x9b, 0x36, 0x60, 0x3b, 0xa2, 0xcc, 0xa9, 0xf5,
+  0xd9, 0x0a, 0x9d, 0x5e, 0x45, 0x38, 0xa0, 0xbc, 0x1d, 0x06, 0xa6, 0x1c,
+  0xdf, 0xa9, 0xbc, 0x39, 0xd6, 0xee, 0x17, 0x9a, 0x30, 0x62, 0xeb, 0x5d,
+  0xdb, 0xd0, 0x87, 0x2d, 0xd9, 0x9c, 0xc8, 0xe1, 0x27, 0x5a, 0x0e, 0x12,
+  0x09, 0x6d, 0xb8, 0xa9, 0xa0, 0x90, 0xb2, 0x15, 0xb5, 0xb2, 0x7b, 0xcc,
+  0x66, 0x91, 0xb0, 0x3a, 0x25, 0x54, 0x80, 0xda, 0x84, 0xd6, 0xb9, 0xa9,
+  0xbb, 0x72, 0xda, 0x74, 0x55, 0xea, 0xe7, 0x63, 0x27, 0x42, 0xbc, 0x03,
+  0x9f, 0x6a, 0x5e, 0x83, 0x2b, 0x75, 0x24, 0xc9, 0xc8, 0xae, 0xde, 0x6e,
+  0x97, 0x07, 0x1b, 0xc8, 0xe3, 0xb2, 0xfe, 0x51, 0x25, 0x8c, 0x2d, 0xeb,
+  0x1c, 0x19, 0x4b, 0xfb, 0x58, 0x3e, 0x1d, 0xd4, 0x5a, 0xd0, 0x19, 0x25,
+  0x90, 0x3d, 0x44, 0x9d, 0xd7, 0x6d, 0xcd, 0x8c, 0x3f, 0x6f, 0xc8, 0xb8,
+  0x7f, 0xee, 0x16, 0xe4, 0x9a, 0x9d, 0x7a, 0x6a, 0xb3, 0xbb, 0xbc, 0x8d,
+  0x8e, 0x99, 0x08, 0x12, 0x01, 0x04, 0xe8, 0x31, 0x08, 0x17, 0x75, 0x38,
+  0x41, 0x23, 0xa2, 0xa1, 0x00, 0x42, 0x83, 0xfa, 0x94, 0x50, 0xe4, 0xee,
+  0x0d, 0xc7, 0xd9, 0x16, 0x57, 0xbe, 0x8b, 0xdf, 0xb4, 0xae, 0xd0, 0xa0,
+  0xa7, 0xd5, 0x18, 0x9a, 0x44, 0x4c, 0x58, 0x1d, 0xd4, 0xb4, 0x2d, 0x39,
+  0x31, 0xfa, 0x9d, 0x1a, 0x7a, 0xb4, 0x98, 0xcb, 0xd9, 0x27, 0xf2, 0xc4,
+  0xac, 0x5f, 0x4c, 0x51, 0x63, 0xbf, 0x56, 0x1a, 0xe4, 0x77, 0x8c, 0xfc,
+  0xa1, 0x57, 0xb6, 0x68, 0x66, 0xea, 0xb3, 0xea, 0x6a, 0xcb, 0x8d, 0x2f,
+  0x7f, 0x8e, 0x44, 0xe0, 0x32, 0x40, 0x8c, 0x5a, 0x2a, 0x2d, 0xe5, 0xb8,
+  0xc9, 0x21, 0x09, 0xfb, 0xca, 0x79, 0x34, 0x47, 0xb0, 0x90, 0x94, 0x6f,
+  0xde, 0x91, 0x12, 0x1e, 0xd5, 0x15, 0x82, 0x69, 0x4e, 0xf0, 0x70, 0x0a,
+  0xcc, 0x47, 0x50, 0x02, 0x4b, 0xf8, 0xae, 0xf1, 0x12, 0xc5, 0xc6, 0xee,
+  0x73, 0x21, 0x0d, 0x3e, 0xaf, 0x33, 0x59, 0x44, 0x5b, 0x33, 0xe7, 0xde,
+  0xc5, 0xdd, 0x05, 0xfd, 0x9e, 0x5d, 0x1b, 0x52, 0xbe, 0xe9, 0xe2, 0xe6,
+  0x93, 0x48, 0x70, 0x21, 0x1a, 0x94, 0x95, 0xbe, 0x8b, 0x05, 0x41, 0x92,
+  0xd8, 0x46, 0x10, 0x5f, 0x41, 0x70, 0x68, 0xe3, 0x12, 0xc0, 0x00, 0x2f,
+  0x91, 0x93, 0x42, 0x40, 0x45, 0xee, 0xd2, 0x6f, 0x83, 0xb4, 0x2c, 0xd1,
+  0x10, 0x10, 0xfe, 0xc5, 0xa4, 0x3f, 0x1b, 0x92, 0x32, 0x51, 0x29, 0x2a,
+  0xba, 0x5d, 0xfc, 0x5b, 0x44, 0x16, 0x6b, 0xff, 0x37, 0x03, 0x33, 0xee,
+  0x35, 0xc5, 0x75, 0xae, 0x15, 0xd2, 0x30, 0xd6, 0x5d, 0xe0, 0xe6, 0x8c,
+  0x72, 0x2b, 0x99, 0x54, 0x66, 0xa9, 0xeb, 0x5f, 0xcb, 0x02, 0xc7, 0x3b,
+  0xa1, 0x1c, 0x4a, 0x84, 0xf6, 0xfb, 0x3a, 0x4b, 0x76, 0x83, 0x2f, 0xa4,
+  0x60, 0x81, 0x48, 0x46, 0x71, 0x93, 0x74, 0x50, 0xec, 0xa9, 0xf8, 0xe5,
+  0x56, 0x09, 0xbb, 0x7a, 0x94, 0xc0, 0x8c, 0xf6, 0x99, 0x7c, 0xd5, 0x35,
+  0x04, 0x45, 0x46, 0x40, 0x34, 0x92, 0xc4, 0xa1, 0xc1, 0x32, 0x61, 0x50,
+  0x67, 0xde, 0xbc, 0xdb, 0xd2, 0x85, 0x2e, 0x01, 0x42, 0xa3, 0x29, 0x77,
+  0xc1, 0xa5, 0x42, 0xe4, 0x84, 0x84, 0x55, 0x38, 0x10, 0xdd, 0x98, 0x6c,
+  0xf5, 0xae, 0xf9, 0xe8, 0x84, 0x72, 0x9b, 0xec, 0xb9, 0x1f, 0xa2, 0x07,
+  0x42, 0xa5, 0xbe, 0x73, 0x69, 0x7b, 0x1c, 0xd4, 0xf7, 0x19, 0x4d, 0x2b,
+  0x62, 0x4b, 0x44, 0xe6, 0xa5, 0x66, 0xab, 0xfc, 0xaa, 0x63, 0x3c, 0xb1,
+  0xe2, 0x62, 0xa4, 0xd7, 0xcb, 0x2e, 0xe8, 0x80, 0x7d, 0x0c, 0xb6, 0x68,
+  0xc0, 0xc7, 0xf4, 0xfb, 0x81, 0x65, 0xb4, 0x6f, 0x58, 0xb2, 0x11, 0xd8,
+  0x7f, 0x63, 0xdd, 0x57, 0x13, 0xb4, 0x23, 0x58, 0x44, 0x36, 0x88, 0x90,
+  0xae, 0xc1, 0x4c, 0x0e, 0xc7, 0x10, 0x25, 0xc3, 0x07, 0x69, 0x25, 0x0c,
+  0x9c, 0x7c, 0xdf, 0x74, 0x24, 0x6d, 0x10, 0xe1, 0x92, 0x04, 0x42, 0x0a,
+  0x90, 0xe3, 0x82, 0x93, 0x4d, 0x31, 0x08, 0xe3, 0x94, 0x10, 0xc5, 0xe0,
+  0xa6, 0x74, 0x43, 0xa7, 0xbc, 0xe7, 0x8c, 0x55, 0xd9, 0x8e, 0xed, 0x88,
+  0xaf, 0x6b, 0x58, 0x81, 0xf2, 0xdd, 0x2b, 0x11, 0x69, 0xd6, 0x93, 0x6e,
+  0xfc, 0xde, 0x1d, 0x4d, 0x1e, 0xaf, 0x95, 0x43, 0x32, 0x4c, 0x3c, 0x3c,
+  0xae, 0x5e, 0xbf, 0x5d, 0xab, 0xcb, 0xfb, 0xa8, 0xdd, 0xaf, 0x04, 0x6c,
+  0xa5, 0x54, 0xc2, 0x9e, 0x8d, 0x0e, 0xef, 0x57, 0x2e, 0x8d, 0xd9, 0xb6,
+  0x14, 0xdb, 0x5b, 0x1a, 0x0f, 0x6e, 0x75, 0xc8, 0x99, 0xd4, 0x08, 0xb4,
+  0x62, 0xc0, 0x76, 0x0b, 0x41, 0x47, 0x33, 0x6f, 0x67, 0xcf, 0x56, 0x36,
+  0x8c, 0x37, 0x00, 0x50, 0x4c, 0x02, 0x5d, 0x3b, 0x68, 0xc6, 0xd6, 0x04,
+  0x00, 0x16, 0x8c, 0x98, 0x43, 0x3d, 0xb8, 0xf4, 0xac, 0x85, 0x29, 0x0b,
+  0xc4, 0x9a, 0xe0, 0x26, 0x34, 0x1c, 0xb9, 0x7b, 0xa6, 0x62, 0xc9, 0xd5,
+  0x82, 0x7f, 0x3d, 0x3e, 0x38, 0x46, 0x22, 0xdf, 0x6d, 0x6c, 0x0f, 0x3f,
+  0xcc, 0x3d, 0x75, 0x7f, 0x04, 0x90, 0x96, 0xb9, 0xe4, 0x3b, 0xad, 0x10,
+  0x70, 0x21, 0x1a, 0x94, 0xad, 0xbe, 0x8c, 0xc4, 0x22, 0x98, 0x89, 0x41,
+  0x5d, 0x1d, 0x0e, 0x80, 0xe1, 0x56, 0x00, 0x00, 0x06, 0xbe, 0xa9, 0xc5,
+  0xdd, 0xb4, 0x39, 0x68, 0x23, 0x56, 0xa3, 0xef, 0x3c, 0xff, 0xbd, 0x75,
+  0x6c, 0xf8, 0xc8, 0x27, 0xe5, 0x23, 0x9f, 0x21, 0x8e, 0xec, 0xd1, 0xee,
+  0x5d, 0xeb, 0xd2, 0x78, 0x5d, 0x97, 0xd1, 0x96, 0x16, 0x21, 0x94, 0x1e,
+  0xb0, 0xca, 0xc0, 0x22, 0xe9, 0x0f, 0x0c, 0xaa, 0xb2, 0xc4, 0xc1, 0xc7,
+  0x91, 0xac, 0xb2, 0x8b, 0x06, 0x94, 0xe9, 0x17, 0xbf, 0x1a, 0x9b, 0x8c,
+  0x19, 0xac, 0xde, 0xa9, 0x64, 0x25, 0xd9, 0x28, 0x16, 0x36, 0x2d, 0x45,
+  0x96, 0x19, 0xef, 0x0d, 0xd0, 0x5e, 0x9e, 0x1f, 0x74, 0xad, 0x01, 0x9d,
+  0x2a, 0x9a, 0xbb, 0xe5, 0xb9, 0xe9, 0xef, 0xf7, 0xbb, 0xd7, 0xfc, 0x3f,
+  0x87, 0x17, 0xd6, 0xbd, 0x97, 0xf2, 0xed, 0xe7, 0x9c, 0xf9, 0x3c, 0xc5,
+  0x9a, 0x38, 0x39, 0x9b, 0xab, 0xe4, 0x1a, 0x6c, 0xca, 0xbd, 0x86, 0x38,
+  0x90, 0xc7, 0xc6, 0x15, 0xe0, 0x8f, 0x24, 0x93, 0x69, 0x02, 0xbe, 0x94,
+  0x20, 0xfb, 0x83, 0xe8, 0xcc, 0x47, 0xe6, 0x2d, 0x2a, 0x23, 0x05, 0x89,
+  0x76, 0x5a, 0x09, 0x96, 0x2d, 0xa6, 0x5d, 0x24, 0x6a, 0x5c, 0x81, 0x8d,
+  0x99, 0x54, 0x91, 0xd6, 0x61, 0x7a, 0x62, 0x68, 0xc1, 0x64, 0x50, 0x0a,
+  0xe5, 0x23, 0x3e, 0xb4, 0x6f, 0x33, 0x3a, 0x80, 0x00, 0x60, 0x30, 0x76,
+  0xde, 0xef, 0x44, 0xc0, 0x73, 0xa9, 0x33, 0xbe, 0x64, 0xa6, 0xae, 0x82,
+  0x6d, 0x80, 0x01, 0x1f, 0x67, 0xa4, 0x41, 0xd4, 0x63, 0x10, 0x02, 0x49,
+  0xa6, 0x5d, 0xb4, 0xcb, 0x5a, 0x52, 0x20, 0xc1, 0x96, 0x17, 0x35, 0x9e,
+  0x06, 0x75, 0x91, 0x26, 0x61, 0xff, 0x76, 0xc7, 0x0e, 0x7a, 0xb8, 0xea,
+  0x70, 0x13, 0x2b, 0xc9, 0x20, 0x39, 0x3c, 0x3e, 0x45, 0x8c, 0xb0, 0xc2,
+  0xd5, 0x4c, 0x8f, 0x01, 0xa0, 0x4e, 0xd8, 0xf4, 0x3a, 0x3e, 0x1f, 0x5f,
+  0x3c, 0x85, 0xef, 0xf7, 0x5b, 0x5d, 0xcf, 0x4f, 0xd4, 0xea, 0x89, 0xe7,
+  0xc3, 0x45, 0x0f, 0xc2, 0xae, 0x72, 0x98, 0x56, 0x3c, 0xfc, 0x75, 0x0e,
+  0xef, 0x76, 0xcd, 0x50, 0x58, 0xda, 0xfd, 0xec, 0x3b, 0x75, 0x4d, 0xe3,
+  0x4a, 0xb9, 0x44, 0x42, 0x58, 0xca, 0x60, 0x00, 0x72, 0xf9, 0xe5, 0x77,
+  0x4a, 0x5f, 0x2a, 0x96, 0x86, 0xe3, 0x01, 0x32, 0x0e, 0x6b, 0xde, 0xc9,
+  0x15, 0x15, 0x45, 0x54, 0x26, 0x2e, 0x45, 0x40, 0x5e, 0xcb, 0x29, 0xd5,
+  0x95, 0x4d, 0x2a, 0x08, 0x22, 0xf9, 0x5e, 0x74, 0xe8, 0xe1, 0x25, 0x27,
+  0xf0, 0x62, 0x95, 0x93, 0x4a, 0x0a, 0x2c, 0x26, 0xac, 0xd0, 0x68, 0x60,
+  0x95, 0xd9, 0x1b, 0x7f, 0x3b, 0xac, 0x0a, 0x77, 0xf0, 0x21, 0xe5, 0xc6,
+  0x7e, 0x5d, 0x7c, 0x7e, 0x70, 0xe0, 0x21, 0x1a, 0x8d, 0xcf, 0x90, 0x1f,
+  0xff, 0xff, 0x2d, 0x6f, 0x82, 0x31, 0x50, 0x46, 0xb2, 0x1a, 0x04, 0x42,
+  0x1e, 0x63, 0x9b, 0xb6, 0xa2, 0xc9, 0x69, 0xbe, 0x10, 0x04, 0xa1, 0x00,
+  0x2a, 0x49, 0xe1, 0x74, 0x7a, 0xf7, 0x71, 0xfd, 0x25, 0xc5, 0xf8, 0x32,
+  0x01, 0x17, 0x63, 0xac, 0x49, 0xa4, 0xbe, 0xe9, 0xd8, 0x9f, 0xf3, 0xf5,
+  0xa4, 0xf5, 0x89, 0xb9, 0x72, 0xe5, 0xb0, 0xc5, 0x88, 0x69, 0x19, 0xc4,
+  0x43, 0x57, 0xc7, 0x33, 0x8a, 0xa6, 0x72, 0xda, 0xb6, 0x15, 0x9c, 0xb3,
+  0x7c, 0xb0, 0x6c, 0x26, 0x10, 0x86, 0x5e, 0x75, 0x56, 0xa3, 0x80, 0x4b,
+  0xaf, 0xca, 0xf9, 0xa3, 0xc4, 0x9d, 0x6f, 0xec, 0x4e, 0x68, 0x68, 0x58,
+  0xb9, 0x44, 0x37, 0x6c, 0x76, 0x80, 0x09, 0x84, 0xa1, 0x7c, 0xa3, 0x1d,
+  0xf4, 0xd6, 0x83, 0x85, 0xd7, 0x79, 0x04, 0x73, 0x82, 0x0d, 0x08, 0xc6,
+  0x98, 0x15, 0xb2, 0xf9, 0x94, 0x63, 0x07, 0xa5, 0x6e, 0x19, 0x34, 0xd7,
+  0x4c, 0xbe, 0x91, 0x6b, 0xce, 0x31, 0x9b, 0x5a, 0x13, 0xc8, 0x16, 0x84,
+  0x6e, 0xd1, 0xd6, 0xb6, 0xcd, 0xa3, 0x3b, 0xc8, 0xdd, 0x64, 0xef, 0xf5,
+  0x08, 0x75, 0x7a, 0x50, 0xb1, 0x77, 0x2e, 0x92, 0xc1, 0xd8, 0xaa, 0x83,
+  0x14, 0x11, 0x88, 0x5b, 0x42, 0x57, 0x52, 0x52, 0xf9, 0xba, 0xa8, 0x31,
+  0xeb, 0x82, 0x81, 0x3d, 0x29, 0x37, 0x7d, 0x38, 0x48, 0xab, 0x0d, 0xa3,
+  0x50, 0x2b, 0x28, 0xcd, 0x29, 0xfc, 0x46, 0xf3, 0x39, 0x65, 0x58, 0x24,
+  0x6c, 0xf4, 0x5b, 0x15, 0x21, 0x04, 0x2e, 0x22, 0x00, 0x68, 0x80, 0xd4,
+  0x5c, 0x68, 0xb1, 0x42, 0x61, 0x00, 0x39, 0xba, 0xef, 0x4e, 0xe2, 0xea,
+  0xbe, 0x61, 0xc7, 0x5e, 0x26, 0xde, 0xe2, 0x82, 0x2e, 0x41, 0x22, 0xa8,
+  0x89, 0x93, 0xe5, 0xce, 0xef, 0xe9, 0x94, 0xd0, 0xd0, 0x36, 0x09, 0x76,
+  0x1e, 0xd9, 0x9d, 0xeb, 0xec, 0x67, 0xd1, 0xeb, 0x9c, 0xbb, 0x92, 0x36,
+  0x3f, 0xa2, 0x53, 0x71, 0x34, 0xe4, 0x8d, 0x2a, 0xcc, 0xef, 0xcf, 0xb9,
+  0x24, 0xd6, 0xca, 0x1c, 0xcf, 0xeb, 0xe5, 0x70, 0x1f, 0x4e, 0xd6, 0xfd,
+  0x4d, 0xb0, 0x6e, 0xba, 0x34, 0xf2, 0x31, 0xef, 0x1b, 0x14, 0x26, 0x8a,
+  0x3d, 0xca, 0xaa, 0x27, 0xf7, 0xf5, 0x06, 0x1e, 0x4d, 0x66, 0xae, 0xc1,
+  0x48, 0x07, 0x4e, 0xb4, 0x37, 0xc1, 0x40, 0x33, 0x55, 0x3f, 0x14, 0xdd,
+  0x02, 0x8b, 0x13, 0x9b, 0x94, 0x60, 0x04, 0x3c, 0x15, 0xb8, 0x9d, 0x50,
+  0x8f, 0x31, 0x7b, 0x05, 0xa3, 0x68, 0x29, 0xaa, 0xbf, 0x39, 0x7d, 0xed,
+  0x28, 0x11, 0x4b, 0x3a, 0xa7, 0x0d, 0x3c, 0x7d, 0xe3, 0x7a, 0x48, 0xa6,
+  0x16, 0xaa, 0xe8, 0x25, 0x11, 0x7b, 0x5a, 0xab, 0x4d, 0xed, 0x0c, 0x5e,
+  0x67, 0x6e, 0x28, 0x84, 0xf4, 0x2b, 0x18, 0x38, 0x56, 0x21, 0xea, 0x34,
+  0x2d, 0x56, 0xc0, 0x00, 0xe0, 0x21, 0x1a, 0x8f, 0xce, 0x18, 0x1f, 0xff,
+  0xff, 0x2d, 0x70, 0x81, 0xb1, 0x88, 0x82, 0xa3, 0x1b, 0x58, 0xb8, 0xd4,
+  0x2e, 0xb8, 0x11, 0x2c, 0xb0, 0x00, 0x05, 0x07, 0x2f, 0xa9, 0x71, 0xff,
+  0xd4, 0x31, 0xf8, 0xf7, 0x9f, 0x42, 0x70, 0x0b, 0x9e, 0x95, 0xa4, 0x33,
+  0x45, 0xcb, 0xde, 0x78, 0x4e, 0x17, 0xec, 0xbc, 0xdd, 0xf8, 0x8e, 0x3f,
+  0xb2, 0xe2, 0xf0, 0xf3, 0xfb, 0x77, 0x34, 0xa2, 0xa4, 0x71, 0x8f, 0xb6,
+  0x39, 0xc6, 0x98, 0x91, 0x1b, 0xaf, 0xfe, 0x7b, 0x97, 0x50, 0xe3, 0xd0,
+  0xb0, 0x78, 0x3b, 0x2b, 0xcd, 0xc4, 0x5d, 0xab, 0xe4, 0xe3, 0x55, 0x5d,
+  0xca, 0xe9, 0x6c, 0xe3, 0x41, 0x79, 0x89, 0xf6, 0x54, 0x32, 0xb3, 0xa4,
+  0x60, 0x7b, 0xe7, 0x32, 0x76, 0xf2, 0xd2, 0x25, 0x55, 0xa5, 0x61, 0xd4,
+  0x9a, 0xe7, 0xca, 0x4c, 0xd6, 0xa2, 0x08, 0xba, 0xf8, 0x8a, 0x2b, 0xb0,
+  0xc4, 0x0a, 0x48, 0xe1, 0xb9, 0x44, 0x5c, 0x81, 0x90, 0xa4, 0x20, 0x1d,
+  0x47, 0x2b, 0x1c, 0xce, 0x65, 0xa0, 0x65, 0xf8, 0xcc, 0xe1, 0x77, 0x9e,
+  0x6b, 0x12, 0xaf, 0xad, 0xb9, 0x47, 0xfe, 0xcd, 0x38, 0x7b, 0xa7, 0x60,
+  0x86, 0xe4, 0xb7, 0x66, 0x8c, 0x60, 0x8a, 0x48, 0xa1, 0x96, 0x53, 0xc8,
+  0x27, 0xb7, 0xdf, 0xa7, 0x0a, 0x5a, 0x51, 0xa4, 0xa0, 0xe1, 0x6e, 0x71,
+  0x63, 0xbd, 0xab, 0x5f, 0xeb, 0xe1, 0xa0, 0x9a, 0x58, 0xbb, 0x28, 0x6e,
+  0x34, 0x36, 0xeb, 0x38, 0x04, 0xb5, 0xba, 0x90, 0x66, 0x17, 0x24, 0x1b,
+  0xbb, 0xd1, 0x76, 0x85, 0x96, 0xb6, 0xa1, 0x44, 0xa5, 0x00, 0x14, 0x6c,
+  0x26, 0x17, 0x47, 0x1b, 0xc1, 0xf4, 0x93, 0x5b, 0xaa, 0xa9, 0xfd, 0x44,
+  0xab, 0x1a, 0x5a, 0x26, 0x28, 0x74, 0xf3, 0xb8, 0x47, 0x64, 0x22, 0x27,
+  0xaf, 0x58, 0xe3, 0x8b, 0x07, 0x9f, 0x50, 0xe4, 0x8e, 0xe6, 0xed, 0xe9,
+  0x0d, 0x7f, 0xde, 0x5d, 0xae, 0xd9, 0x02, 0x61, 0x15, 0x5b, 0x34, 0x6c,
+  0x20, 0x2d, 0x39, 0x35, 0x69, 0x3b, 0xde, 0xe1, 0x61, 0xc8, 0xdc, 0xb0,
+  0x75, 0x37, 0x82, 0x4a, 0x82, 0xdd, 0xa8, 0x39, 0x85, 0x47, 0x80, 0x4b,
+  0x48, 0xbe, 0xda, 0xf4, 0xc5, 0x79, 0x82, 0x92, 0xbf, 0x0a, 0x84, 0x9d,
+  0x66, 0x58, 0x3f, 0xd6, 0xc0, 0xe3, 0xd7, 0xe0, 0xe1, 0x1c, 0x66, 0x08,
+  0xd5, 0x49, 0x94, 0x69, 0x00, 0x2d, 0x3c, 0x61, 0x61, 0x21, 0x14, 0x4c,
+  0xe9, 0x2a, 0x1d, 0x4c, 0xd7, 0xd9, 0x07, 0xd4, 0x42, 0x09, 0xb5, 0x47,
+  0xba, 0x77, 0x86, 0x52, 0xa2, 0xa8, 0x5e, 0xa5, 0x6b, 0x40, 0x6a, 0x73,
+  0x47, 0x2e, 0x0c, 0x2b, 0x4b, 0x87, 0xbf, 0x65, 0x1f, 0xd6, 0x44, 0xf7,
+  0x2b, 0x4e, 0x9f, 0x69, 0xff, 0x0c, 0x57, 0x0e, 0x21, 0x2a, 0x8f, 0x87,
+  0x5d, 0x3b, 0xff, 0xff, 0x25, 0x67, 0xa6, 0x40, 0xd8, 0x62, 0xb2, 0x28,
+  0x84, 0x19, 0xa5, 0xaf, 0x3a, 0x55, 0x6a, 0x22, 0xc8, 0x04, 0xa1, 0x00,
+  0x21, 0xd5, 0x00, 0x33, 0x01, 0x28, 0x46, 0x24, 0x13, 0xdd, 0x6e, 0x97,
+  0x49, 0xd0, 0x96, 0x13, 0x4d, 0x19, 0x4d, 0xfb, 0x8e, 0x50, 0xb5, 0x74,
+  0x59, 0x0f, 0x94, 0xde, 0xdf, 0x6c, 0xd8, 0x9e, 0x5b, 0xbb, 0x54, 0x81,
+  0x34, 0xf5, 0x60, 0xb0, 0xdb, 0x6f, 0xed, 0x72, 0x33, 0xf9, 0xdf, 0xf0,
+  0xfb, 0xe6, 0x8b, 0x62, 0x8b, 0x2c, 0x7e, 0x78, 0x4c, 0x6c, 0x8b, 0xa6,
+  0x15, 0xb8, 0x09, 0xf5, 0x74, 0xee, 0xb3, 0x40, 0x94, 0x9f, 0x5d, 0x11,
+  0x03, 0x7c, 0x4f, 0x1d, 0xb2, 0xc9, 0x68, 0x4b, 0x5e, 0xfe, 0x1d, 0x00,
+  0xe4, 0x13, 0x73, 0xac, 0xfb, 0xe6, 0xbe, 0x75, 0x14, 0x7e, 0xf2, 0x9c,
+  0xe4, 0x09, 0xe6, 0x11, 0x4b, 0x66, 0x34, 0x4e, 0xf0, 0xfd, 0x22, 0x8b,
+  0xa6, 0x7c, 0x60, 0xf5, 0xc2, 0x5d, 0xa6, 0xe7, 0x6b, 0x4a, 0x31, 0x41,
+  0xa6, 0x6d, 0x32, 0x92, 0x42, 0xdf, 0x3b, 0xd5, 0xda, 0x5d, 0xbd, 0xbc,
+  0xe9, 0xbd, 0x09, 0x87, 0x6e, 0x28, 0xb1, 0x52, 0x15, 0xb2, 0x94, 0xa1,
+  0x24, 0x41, 0xbc, 0x5d, 0x5e, 0x6c, 0x3f, 0xa0, 0xc0, 0x4a, 0xcb, 0x9c,
+  0x53, 0x7c, 0x92, 0x53, 0xe9, 0x31, 0xbe, 0x7f, 0xe5, 0x46, 0xd8, 0x91,
+  0x5b, 0x6a, 0xea, 0xcb, 0x3f, 0x11, 0xe6, 0x6b, 0xe0, 0x12, 0xf6, 0x8a,
+  0x69, 0x98, 0x04, 0x2d, 0x33, 0x4e, 0x88, 0xb5, 0xd1, 0x6b, 0x4a, 0xd2,
+  0x34, 0x28, 0x8d, 0xd8, 0x06, 0xaa, 0x09, 0xaf, 0xa0, 0x5a, 0x7c, 0x90,
+  0xa9, 0xbc, 0x75, 0xdd, 0xa6, 0x9c, 0x0c, 0xe4, 0x27, 0x0e, 0x5d, 0x5e,
+  0x88, 0xdf, 0x2a, 0x89, 0x5e, 0x23, 0xd4, 0x9d, 0xaa, 0x97, 0xb7, 0xe7,
+  0xfc, 0xfe, 0x71, 0x1e, 0xde, 0x4e, 0x32, 0xcd, 0x8d, 0xf4, 0x6f, 0x37,
+  0x57, 0x8c, 0x0a, 0xaa, 0xea, 0x18, 0xa3, 0x70, 0x8e, 0x18, 0x17, 0xc8,
+  0x41, 0x4c, 0xcc, 0xa8, 0x68, 0x14, 0xab, 0xcc, 0x01, 0x32, 0x35, 0xf1,
+  0xf1, 0xbe, 0x61, 0xa3, 0x8e, 0x81, 0xd3, 0xbb, 0x76, 0xee, 0x9e, 0xf3,
+  0x6e, 0x1c, 0x6d, 0xf0, 0xc7, 0x16, 0xdb, 0x3c, 0x40, 0x52, 0x2b, 0xcd,
+  0x48, 0xb8, 0xa0, 0x33, 0x9d, 0x81, 0x48, 0xb1, 0x28, 0x10, 0x56, 0xf7,
+  0x2f, 0x0b, 0x80, 0x52, 0x09, 0x41, 0x91, 0x65, 0x6e, 0x00, 0x0b, 0x4b,
+  0x1a, 0xd9, 0xf1, 0x41, 0x74, 0x54, 0xa7, 0x91, 0xa7, 0xdc, 0x1a, 0xf5,
+  0xc9, 0x3e, 0x41, 0xc0, 0x21, 0x4c, 0xd8, 0xfb, 0xff, 0x5f, 0xff, 0xff,
+  0x00, 0xc6, 0xda, 0xa4, 0xc8, 0x75, 0xb8, 0x68, 0x8a, 0x5c, 0x44, 0x3a,
+  0xf0, 0xe7, 0xb3, 0x87, 0x00, 0x7e, 0x8e, 0x3a, 0xb6, 0x90, 0xaf, 0xe1,
+  0xd6, 0x9a, 0x15, 0xa7, 0xb9, 0xc1, 0x61, 0x42, 0xd5, 0x3f, 0x98, 0xf2,
+  0x2f, 0xc0, 0x65, 0x70, 0xfd, 0x76, 0x6c, 0x6e, 0xdd, 0x86, 0xc7, 0x7c,
+  0x4f, 0x8d, 0x36, 0xf5, 0x6c, 0x0c, 0x59, 0x1a, 0xb2, 0x0f, 0x5f, 0x1e,
+  0x39, 0x27, 0x5c, 0x08, 0xad, 0x32, 0x28, 0x14, 0x94, 0x0d, 0x1f, 0x31,
+  0x06, 0xf8, 0x2e, 0x86, 0x19, 0xdd, 0x2f, 0x4f, 0xba, 0x6d, 0x15, 0xa6,
+  0x38, 0x2a, 0x94, 0xee, 0x2a, 0xaa, 0x0b, 0xea, 0x42, 0xc0, 0x99, 0x6b,
+  0x16, 0x73, 0x7c, 0xaa, 0xa6, 0x95, 0x2e, 0x2b, 0x01, 0x4f, 0xab, 0xf7,
+  0xb5, 0x91, 0x78, 0x62, 0xbc, 0x9e, 0xb3, 0xd5, 0x22, 0x62, 0x03, 0x38,
+  0xa2, 0xb3, 0x65, 0xc9, 0x2c, 0x8a, 0xca, 0x86, 0x82, 0xfc, 0xe6, 0xd2,
+  0x6c, 0x22, 0x7e, 0x5b, 0x46, 0x2e, 0x7c, 0xf8, 0x5c, 0xd7, 0x6b, 0x66,
+  0x99, 0x85, 0x6c, 0x9c, 0x5f, 0x66, 0xd7, 0x0f, 0x8c, 0x59, 0x5e, 0xee,
+  0x73, 0x57, 0x12, 0xa1, 0xcf, 0xd6, 0x8e, 0xf6, 0x5b, 0xea, 0xd4, 0x29,
+  0xf5, 0x7e, 0x55, 0xa6, 0x52, 0x03, 0x6a, 0xc0, 0xe9, 0x8c, 0xc3, 0xd7,
+  0x49, 0x1c, 0x3b, 0x0d, 0x47, 0x09, 0x90, 0x96, 0xdc, 0x3b, 0x17, 0x3b,
+  0xb7, 0x01, 0x45, 0x95, 0x55, 0x64, 0x7a, 0x45, 0x95, 0xe7, 0x93, 0x7c,
+  0x2e, 0x32, 0xbc, 0xa4, 0x26, 0xea, 0x9b, 0x6d, 0x8c, 0xe0, 0xea, 0xc0,
+  0x55, 0x79, 0xc5, 0x4e, 0xf5, 0x86, 0xb7, 0xb9, 0x3f, 0xaf, 0x18, 0xa2,
+  0xac, 0xc4, 0x52, 0x3a, 0xcc, 0x53, 0xd7, 0x07, 0x9b, 0xb5, 0x8c, 0xa4,
+  0xf2, 0xd3, 0x46, 0x3f, 0xab, 0xae, 0x1f, 0x54, 0x52, 0xfe, 0x40, 0xfa,
+  0xa6, 0xdd, 0x83, 0xca, 0x41, 0x01, 0x4a, 0x65, 0x72, 0xe0, 0x41, 0xdb,
+  0xb4, 0xbe, 0xc7, 0xfe, 0x6a, 0x56, 0x22, 0x95, 0x77, 0x1f, 0x62, 0x44,
+  0xc4, 0x6d, 0xca, 0x6c, 0x32, 0x60, 0xc3, 0x56, 0x40, 0x35, 0xc4, 0x60,
+  0xb7, 0x82, 0xf5, 0x08, 0xea, 0x12, 0x04, 0x62, 0x09, 0x9b, 0xdc, 0xd1,
+  0x30, 0xa4, 0xe5, 0x41, 0x3a, 0x82, 0xb4, 0x2f, 0x01, 0x28, 0xac, 0xae,
+  0x43, 0xd4, 0x5d, 0x7e, 0xc1, 0xa7, 0xa7, 0x2d, 0x36, 0x02, 0x45, 0x59,
+  0x76, 0x4e, 0xd3, 0xb4, 0x97, 0x69, 0x5d, 0xd7, 0xd3, 0xd8, 0x04, 0xe2,
+  0x08, 0x96, 0xf8, 0xdc, 0x21, 0x36, 0x92, 0xaa, 0xf1, 0xf1, 0xe5, 0xc6,
+  0x08, 0xdd, 0xc1, 0x86, 0x98, 0x80, 0x45, 0x30, 0xb2, 0x21, 0x59, 0xc7,
+  0x24, 0x6e, 0x5b, 0xf1, 0x31, 0x75, 0xb3, 0x39, 0x9b, 0x51, 0x64, 0x19,
+  0x79, 0xd4, 0x36, 0xd6, 0x5f, 0x61, 0x6e, 0x0a, 0x8e, 0x00, 0xa2, 0xb2,
+  0x65, 0x14, 0xb0, 0xb5, 0x44, 0x49, 0x2f, 0x5a, 0x4e, 0xf7, 0x8c, 0xda,
+  0x5f, 0x29, 0x83, 0x83, 0xa1, 0xbf, 0xf1, 0xb5, 0x18, 0x51, 0xb8, 0xe9,
+  0x6a, 0x1a, 0x0a, 0x80, 0xeb, 0xe2, 0x30, 0xee, 0x7d, 0xb8, 0xd1, 0x93,
+  0x84, 0x3b, 0x1c, 0xdb, 0x35, 0x6a, 0xd7, 0x1e, 0xa3, 0xec, 0xff, 0x1d,
+  0xab, 0x07, 0x21, 0x4c, 0x6c, 0xc0, 0x00, 0xbf, 0xc0, 0x04, 0x1f, 0xc6,
+  0xdc, 0x46, 0x36, 0xf1, 0xeb, 0x50, 0x8d, 0x8d, 0xb6, 0x50, 0x6b, 0x48,
+  0xd7, 0x91, 0x8f, 0xda, 0xe9, 0xed, 0x79, 0x2d, 0x6f, 0xeb, 0xc6, 0xad,
+  0x77, 0xd3, 0x31, 0xfb, 0x6a, 0x9f, 0x0e, 0x27, 0x00, 0x10, 0x21, 0x64,
+  0xe4, 0xe6, 0x35, 0x2d, 0x3d, 0xde, 0x89, 0x8e, 0xae, 0xd7, 0x97, 0x5b,
+  0x97, 0x55, 0x3a, 0xbc, 0x71, 0x33, 0xc5, 0x73, 0xaa, 0xf5, 0xb7, 0x19,
+  0x44, 0xb2, 0x08, 0x33, 0xc2, 0x59, 0xe9, 0x33, 0x93, 0x0b, 0xee, 0x17,
+  0xa6, 0x76, 0xe0, 0x71, 0xe1, 0x69, 0x1f, 0x82, 0x70, 0xba, 0xae, 0xb2,
+  0xf6, 0x13, 0xb1, 0xad, 0x22, 0x3c, 0x9a, 0x0e, 0xca, 0x7c, 0x34, 0xd2,
+  0x49, 0xe7, 0x0a, 0xb9, 0x6f, 0x70, 0x77, 0x3e, 0x85, 0x3a, 0x79, 0x68,
+  0xdf, 0x1d, 0xfa, 0xd0, 0x20, 0x49, 0x10, 0x22, 0xd4, 0xeb, 0xb6, 0xf7,
+  0xa0, 0x8e, 0x91, 0x02, 0xf6, 0x2e, 0x02, 0x8e, 0xb6, 0x2d, 0x8d, 0xf3,
+  0xf9, 0x5a, 0xa2, 0xe4, 0x9a, 0x5e, 0xab, 0xdc, 0x06, 0xd0, 0xa5, 0xf3,
+  0xa3, 0x32, 0x7f, 0x8a, 0x70, 0x4e, 0x41, 0x5d, 0x83, 0x67, 0xa6, 0x57,
+  0xe3, 0xef, 0x16, 0x25, 0x86, 0x9b, 0xba, 0x68, 0xbf, 0x28, 0xd2, 0x3d,
+  0x23, 0x3c, 0xfa, 0x02, 0xe6, 0xde, 0xca, 0x09, 0x87, 0x32, 0x82, 0x13,
+  0x3f, 0xb0, 0xf9, 0x85, 0x9e, 0x52, 0x3b, 0x9b, 0xd1, 0xf3, 0x4e, 0x65,
+  0x28, 0x89, 0xc2, 0xbf, 0xf7, 0x5f, 0xd7, 0xd2, 0x49, 0x5e, 0x64, 0x52,
+  0xeb, 0x90, 0x43, 0x2e, 0xb1, 0x1d, 0x74, 0x98, 0xc2, 0x9c, 0x5d, 0xf1,
+  0x96, 0x7e, 0x4f, 0x39, 0xe7, 0xd9, 0x1f, 0xd0, 0x9c, 0x69, 0xa0, 0xfc,
+  0x9d, 0x1f, 0x82, 0xd1, 0xa5, 0x08, 0x85, 0x28, 0xa6, 0x92, 0x21, 0xdb,
+  0x8b, 0xe2, 0x7d, 0x09, 0xca, 0xa4, 0xcc, 0x9a, 0xe0, 0x95, 0xc8, 0x38,
+  0x75, 0x27, 0x0d, 0x7d, 0x2f, 0x59, 0xaf, 0xcc, 0xe3, 0x2b, 0x57, 0x44,
+  0x1a, 0xbe, 0x3a, 0x25, 0x49, 0xd1, 0x68, 0x17, 0x08, 0xdb, 0xf6, 0x51,
+  0xc9, 0x8a, 0xcb, 0x24, 0x80, 0x0f, 0xbc, 0x92, 0x8d, 0x0e, 0xee, 0x6b,
+  0x8b, 0x53, 0x4f, 0x24, 0x98, 0x7e, 0xa2, 0xd2, 0x1e, 0xc0, 0xf1, 0x73,
+  0x41, 0xa0, 0xaf, 0x22, 0x8a, 0x24, 0x93, 0xdb, 0xb6, 0xcb, 0xb9, 0x20,
+  0xbd, 0xee, 0x47, 0x6b, 0x64, 0x09, 0x4f, 0x05, 0x81, 0x5b, 0x20, 0x0a,
+  0xc1, 0x14, 0xc5, 0xa0, 0x40, 0x06, 0x1d, 0xca, 0xd8, 0x84, 0x2a, 0x30,
+  0xd1, 0xeb, 0x07, 0x16, 0x11, 0xcd, 0xa4, 0xc0, 0x25, 0xc7, 0x98, 0x9f,
+  0x96, 0x83, 0xee, 0x93, 0x08, 0x7b, 0x3f, 0xe8, 0x3d, 0x61, 0xfb, 0x65,
+  0xc3, 0x59, 0x08, 0xfa, 0x16, 0x3b, 0x23, 0x00, 0xf8, 0x52, 0x07, 0xad,
+  0xae, 0xa8, 0x86, 0x0f, 0x35, 0x0f, 0x47, 0xe2, 0xa8, 0xef, 0x7b, 0xe8,
+  0xf5, 0xdc, 0x85, 0xf8, 0xda, 0xf0, 0xa8, 0x46, 0x75, 0x97, 0x05, 0x8c,
+  0x02, 0x63, 0x56, 0x4f, 0x56, 0xfb, 0x08, 0x90, 0x1e, 0x1a, 0xc4, 0xdb,
+  0x4a, 0x3e, 0x1b, 0x39, 0xb9, 0xe2, 0x71, 0x35, 0x41, 0xa0, 0xd1, 0x39,
+  0x58, 0xe0, 0x21, 0x4c, 0xd9, 0x46, 0x5c, 0x44, 0x3a, 0xea, 0x21, 0xb7,
+  0x29, 0xa4, 0x03, 0x7a, 0x93, 0x23, 0x47, 0xb0, 0xb5, 0xa3, 0xf8, 0xd3,
+  0x8e, 0x01, 0x7d, 0x7f, 0x01, 0xc4, 0x54, 0x7e, 0x47, 0xb1, 0x73, 0x62,
+  0x05, 0x29, 0x92, 0xc6, 0x57, 0xa7, 0x63, 0xe0, 0xcb, 0xc5, 0x95, 0xcb,
+  0x9e, 0x3f, 0x74, 0x5b, 0xfd, 0x8e, 0x2a, 0xa5, 0xc6, 0x66, 0xe8, 0x89,
+  0x0a, 0x9e, 0x82, 0x39, 0x2f, 0xc3, 0x30, 0xbb, 0xe9, 0x2d, 0x97, 0xaa,
+  0x07, 0x99, 0x75, 0x9b, 0x49, 0xd3, 0x49, 0x52, 0x85, 0x86, 0x54, 0x95,
+  0xdd, 0x68, 0x05, 0x57, 0x81, 0xda, 0x0e, 0xe9, 0xc1, 0xa5, 0x84, 0x22,
+  0x88, 0xf2, 0xdd, 0x1f, 0xb7, 0x6c, 0xf0, 0xdb, 0xe3, 0xc4, 0xa9, 0xb9,
+  0x2f, 0x79, 0x93, 0x10, 0xb4, 0x64, 0xf7, 0xa4, 0xe7, 0xbf, 0xf8, 0x7d,
+  0xf9, 0xfb, 0xa6, 0xd6, 0x35, 0x47, 0xcd, 0x55, 0x5b, 0x43, 0x93, 0x96,
+  0x13, 0x5f, 0xec, 0x85, 0x89, 0x18, 0xa7, 0x7e, 0x0b, 0xa8, 0xbf, 0x68,
+  0x48, 0x21, 0x8c, 0xdc, 0xbd, 0x3b, 0x2e, 0xb2, 0x50, 0x48, 0x48, 0x0b,
+  0x9f, 0x10, 0x21, 0xf2, 0x65, 0x00, 0x1d, 0xbc, 0x4e, 0x5a, 0x5f, 0xbb,
+  0x22, 0x23, 0xf0, 0x04, 0x08, 0x9c, 0xd1, 0x20, 0x41, 0x0a, 0xea, 0x02,
+  0x49, 0xcf, 0xae, 0x94, 0x61, 0x4f, 0x50, 0x00, 0xcd, 0x9f, 0xf0, 0x00,
+  0x06, 0xad, 0xc9, 0xf5, 0xe5, 0x9d, 0xae, 0x4c, 0xef, 0x24, 0x11, 0xca,
+  0xad, 0x26, 0x74, 0xcb, 0x6f, 0xe5, 0xcf, 0xcf, 0xe1, 0xf5, 0xb0, 0xbd,
+  0x76, 0x47, 0x50, 0xf6, 0xaa, 0xd8, 0xe9, 0x61, 0x89, 0x54, 0xa7, 0x13,
+  0xa3, 0x01, 0x64, 0xfb, 0xdb, 0xfd, 0xd7, 0x94, 0x50, 0x8c, 0xb5, 0x08,
+  0xf9, 0xba, 0x48, 0x6d, 0xa5, 0xa1, 0x69, 0x87, 0x4d, 0x38, 0x34, 0xb2,
+  0xbf, 0x6d, 0x38, 0xb5, 0xb4, 0x9a, 0xfe, 0xc1, 0xd3, 0xd0, 0x81, 0x4a,
+  0x64, 0xd7, 0xf3, 0xf9, 0x36, 0x74, 0xba, 0xaf, 0xa5, 0x53, 0xf6, 0x6a,
+  0x56, 0x29, 0xd3, 0xd2, 0x01, 0xed, 0x5b, 0x08, 0x43, 0x29, 0xe6, 0x74,
+  0x68, 0xd2, 0x3f, 0x9b, 0xd1, 0x7e, 0x07, 0xa2, 0xf8, 0x28, 0x63, 0x93,
+  0x59, 0x7a, 0xda, 0xb5, 0x01, 0x30, 0xb9, 0x41, 0x64, 0x13, 0xa5, 0x4b,
+  0x04, 0x02, 0x25, 0x4a, 0x51, 0xfd, 0x8a, 0x3a, 0x7a, 0x1f, 0x39, 0xb7,
+  0xd5, 0xb4, 0x41, 0x00, 0x0f, 0xe3, 0xea, 0xdb, 0x61, 0xf1, 0xf6, 0x7f,
+  0xb4, 0xb5, 0x0a, 0xdb, 0x8b, 0xfd, 0xf7, 0x1c, 0xbd, 0x52, 0x29, 0xc4,
+  0x6c, 0xc5, 0xd1, 0x39, 0x77, 0x8d, 0xa5, 0x70, 0xee, 0xea, 0xc8, 0x12,
+  0xb0, 0x29, 0xa0, 0xbc, 0xd3, 0x46, 0xe8, 0x04, 0x4a, 0x9b, 0x62, 0xef,
+  0x92, 0xe0, 0x49, 0x15, 0x33, 0xe6, 0xd1, 0xf1, 0x5c, 0xb7, 0x3e, 0x85,
+  0xb0, 0xc2, 0x0c, 0xcb, 0xe5, 0xd2, 0x22, 0x58, 0x1c, 0x21, 0x4c, 0x6d,
+  0x49, 0xdf, 0x08, 0xc5, 0x5d, 0x82, 0x88, 0x65, 0xaa, 0x6c, 0x4a, 0x0a,
+  0xba, 0x8c, 0x62, 0xf9, 0x7d, 0x70, 0x74, 0x3f, 0x49, 0x4e, 0xbc, 0xe9,
+  0x57, 0xbd, 0x7f, 0x06, 0xb8, 0xea, 0x25, 0xd6, 0xfd, 0x06, 0xb4, 0x58,
+  0x3b, 0x73, 0x63, 0xdd, 0x61, 0xb6, 0xa1, 0xbd, 0xab, 0xfc, 0x1d, 0xc5,
+  0xaa, 0xb2, 0x4b, 0x75, 0xef, 0x3a, 0x8b, 0xaa, 0x5f, 0x26, 0xb9, 0x95,
+  0xbf, 0x1b, 0x5a, 0xda, 0x1a, 0x70, 0x29, 0x2d, 0xee, 0x85, 0x11, 0x54,
+  0x04, 0x20, 0x40, 0xf4, 0x4e, 0xd7, 0x9f, 0xc1, 0xc8, 0xd0, 0x2c, 0xf7,
+  0xdd, 0xd4, 0x6f, 0x13, 0xd6, 0x7e, 0x52, 0x45, 0xac, 0xb0, 0x63, 0xeb,
+  0x94, 0x89, 0x41, 0x62, 0x87, 0x64, 0xb1, 0x68, 0xcf, 0x57, 0xb2, 0x6f,
+  0x15, 0x6b, 0x20, 0x67, 0xc8, 0xd9, 0x34, 0xa9, 0x3f, 0x47, 0x55, 0xf7,
+  0x13, 0x67, 0x7b, 0x74, 0x57, 0x42, 0xe3, 0x75, 0xdb, 0xe4, 0xd3, 0x93,
+  0x52, 0xc8, 0x93, 0x20, 0x54, 0x88, 0x94, 0x3d, 0xbd, 0xd9, 0xbd, 0xac,
+  0x36, 0x00, 0xac, 0x4e, 0x19, 0xce, 0x1b, 0x4f, 0x9e, 0x73, 0x64, 0x14,
+  0x56, 0x21, 0xf9, 0x2d, 0xf9, 0xc8, 0xbb, 0x37, 0xaa, 0x71, 0x18, 0x9b,
+  0xaf, 0xdd, 0xa3, 0xfd, 0xbf, 0x80, 0x63, 0xd2, 0x61, 0xae, 0xbf, 0x3b,
+  0x6b, 0xf8, 0x8b, 0x36, 0xa3, 0x55, 0x5f, 0x7f, 0xbc, 0xae, 0xaf, 0x94,
+  0x55, 0x22, 0x52, 0xb7, 0x5d, 0xc8, 0xfb, 0x68, 0xbe, 0x4e, 0x35, 0x07,
+  0x49, 0x21, 0x86, 0x07, 0x60, 0xae, 0x48, 0x73, 0xe2, 0xfe, 0x77, 0x79,
+  0xd7, 0x57, 0x1d, 0x22, 0x77, 0xdb, 0x5c, 0x95, 0x00, 0xa4, 0x8b, 0xba,
+  0x37, 0xf4, 0x2e, 0x6b, 0x97, 0xa5, 0x2e, 0x69, 0x31, 0xb6, 0x22, 0xf6,
+  0xc4, 0x9f, 0x7e, 0x50, 0xeb, 0xa5, 0xa9, 0x16, 0xd7, 0x3e, 0x59, 0xe4,
+  0x44, 0x8b, 0xa4, 0x1c, 0x8a, 0xa8, 0x3c, 0xd1, 0x5a, 0x30, 0x15, 0x40,
+  0xc2, 0x8f, 0xc3, 0xfb, 0xd9, 0xd6, 0xbc, 0xb4, 0x3f, 0xa0, 0xf3, 0xec,
+  0xb3, 0xfb, 0x70, 0x7f, 0x21, 0xc0, 0x7e, 0x69, 0xf4, 0x88, 0xc0, 0xee,
+  0x6f, 0x96, 0xf3, 0x7b, 0x63, 0x1a, 0x37, 0x61, 0xb7, 0xc0, 0x65, 0xa4,
+  0xb0, 0x7c, 0x8e, 0x34, 0x74, 0x43, 0xdd, 0x94, 0xb1, 0x07, 0x7d, 0xbd,
+  0xd1, 0x8a, 0x2c, 0x35, 0xf1, 0x0d, 0x77, 0x03, 0xe9, 0xd2, 0x72, 0xaa,
+  0x14, 0xcf, 0x37, 0xc8, 0x18, 0x5e, 0x58, 0x82, 0x56, 0x88, 0xa0, 0xf0,
+  0x1e, 0xd5, 0x3b, 0x49, 0xc8, 0xab, 0x44, 0xf0, 0x7c, 0xf7, 0xa7, 0x5e,
+  0xb5, 0x1d, 0xaa, 0xf6, 0x3d, 0x4f, 0xa2, 0x1b, 0x18, 0x62, 0x26, 0x38,
+  0x91, 0x73, 0xf0, 0xd4, 0xa4, 0x02, 0x73, 0x99, 0x68, 0x0b, 0x84, 0xa6,
+  0x15, 0xbc, 0x41, 0x64, 0x1c, 0xac, 0x86, 0xc5, 0xc3, 0x07, 0x21, 0x4c,
+  0x37, 0x47, 0x5d, 0x64, 0x76, 0xe5, 0x35, 0xb7, 0x21, 0x31, 0x38, 0x06,
+  0xec, 0x23, 0xa4, 0x48, 0xb5, 0xba, 0xfd, 0x28, 0x49, 0x9a, 0x5b, 0xe4,
+  0x57, 0x5a, 0x9a, 0x3e, 0xc2, 0xf5, 0x7a, 0x94, 0xe9, 0xa5, 0xb1, 0x94,
+  0x91, 0x52, 0x58, 0x3f, 0xbb, 0xac, 0x16, 0x70, 0x96, 0xdc, 0xca, 0x0f,
+  0xc5, 0x6f, 0x1a, 0x72, 0x0b, 0xa2, 0x5d, 0x2e, 0x36, 0xf9, 0x67, 0xfe,
+  0x05, 0x0e, 0x9f, 0xd3, 0xf7, 0x1c, 0x8a, 0xcd, 0xdb, 0x8e, 0x86, 0xe8,
+  0xca, 0x37, 0x0b, 0x26, 0x64, 0xda, 0x14, 0x08, 0xc7, 0x6d, 0x8f, 0x17,
+  0xa1, 0xb5, 0x1b, 0x17, 0xf5, 0x79, 0xc6, 0x6f, 0xa7, 0xae, 0xaa, 0xe1,
+  0xe7, 0x20, 0xea, 0xac, 0xcf, 0x77, 0xca, 0xf5, 0xe3, 0x57, 0x70, 0x41,
+  0x02, 0x9d, 0x4d, 0x07, 0xd3, 0x18, 0xb7, 0x19, 0x5b, 0xe0, 0x89, 0x57,
+  0x00, 0xf3, 0xae, 0xf2, 0x98, 0x63, 0x9e, 0x3a, 0x3d, 0x66, 0xf9, 0xb1,
+  0xc1, 0x56, 0x10, 0x10, 0xac, 0x61, 0x66, 0xbb, 0x0a, 0xa5, 0x0e, 0x9b,
+  0xea, 0xc5, 0x7a, 0xd5, 0x97, 0xf8, 0x3b, 0x99, 0x12, 0x9a, 0x6b, 0x6a,
+  0x05, 0x34, 0x01, 0xfc, 0x32, 0x4b, 0xa8, 0x42, 0x68, 0x80, 0x3f, 0x4f,
+  0xc2, 0x8c, 0x50, 0xcd, 0xf7, 0xe9, 0xaa, 0x69, 0xfc, 0x53, 0xa5, 0x7d,
+  0x16, 0xcc, 0xf1, 0x3f, 0x05, 0x9c, 0x28, 0x7c, 0x57, 0x26, 0xed, 0xd9,
+  0x87, 0xea, 0x3b, 0x12, 0xaf, 0x49, 0xb9, 0xf9, 0xe5, 0xc9, 0xc3, 0xfc,
+  0xc6, 0x51, 0x0f, 0xcc, 0x54, 0xc3, 0xe9, 0xeb, 0x54, 0x33, 0x15, 0x06,
+  0x59, 0xf4, 0xdc, 0x5d, 0xd3, 0x5d, 0xd3, 0xe2, 0x83, 0xa5, 0x5b, 0x46,
+  0xda, 0x3c, 0x6f, 0x6f, 0xb1, 0x93, 0x93, 0x5a, 0x12, 0x9f, 0x38, 0x64,
+  0xbf, 0x06, 0x04, 0x42, 0x49, 0x96, 0xe7, 0x2b, 0xe4, 0xa3, 0xd5, 0x47,
+  0x64, 0xb5, 0x80, 0xd7, 0xea, 0x7e, 0x5d, 0x98, 0x36, 0x00, 0x14, 0x17,
+  0x02, 0x3e, 0x20, 0x73, 0x10, 0x39, 0x84, 0x68, 0x39, 0x82, 0x6c, 0x38,
+  0x12, 0x66, 0x5d, 0xf7, 0xc0, 0xe4, 0x3f, 0xea, 0xd2, 0xd8, 0xca, 0x48,
+  0xa9, 0x2c, 0x1c, 0x9f, 0xdb, 0x47, 0x6c, 0x90, 0xdc, 0x4f, 0xa9, 0xdd,
+  0x57, 0x16, 0xb0, 0x2e, 0xbe, 0xab, 0xd1, 0xb1, 0xdd, 0x74, 0xae, 0x5a,
+  0x19, 0x20, 0x51, 0xc4, 0xba, 0xdf, 0x6f, 0xa2, 0x3e, 0xff, 0x16, 0xb6,
+  0xcf, 0x71, 0xf0, 0xea, 0x3a, 0x47, 0x1f, 0xae, 0x1f, 0x61, 0xe9, 0xa1,
+  0xc0, 0x21, 0x7a, 0x94, 0xd5, 0x55, 0x88, 0x31, 0x51, 0x2a, 0x70, 0xd8,
+  0xe5, 0x47, 0x0b, 0x75, 0x2a, 0xd3, 0x8d, 0x45, 0x50, 0xe0, 0x85, 0xb2,
+  0x66, 0x6e, 0x39, 0x6a, 0x93, 0xbf, 0x13, 0xe3, 0xee, 0x38, 0xbf, 0xf8,
+  0xa4, 0xbc, 0x56, 0xad, 0x8b, 0xf3, 0x2e, 0x9b, 0x60, 0xf6, 0xcc, 0x6e,
+  0x8b, 0x8c, 0x01, 0x94, 0x4a, 0x51, 0xb1, 0xdb, 0x75, 0x57, 0xec, 0xcb,
+  0x84, 0xda, 0x34, 0xd3, 0x7c, 0xe8, 0x57, 0x12, 0x19, 0x8b, 0xe3, 0x5a,
+  0x31, 0xa1, 0xba, 0xee, 0x7d, 0x73, 0xe7, 0x78, 0x38, 0xdf, 0x7e, 0xf4,
+  0x0a, 0x5b, 0xd2, 0xfe, 0xdd, 0x87, 0xa9, 0x7f, 0x53, 0x64, 0xe5, 0x13,
+  0xac, 0x92, 0xdf, 0x48, 0x2d, 0xe4, 0x92, 0xbd, 0x3c, 0xc9, 0x64, 0x21,
+  0xa3, 0x36, 0x55, 0xa7, 0xb1, 0x67, 0x9d, 0x37, 0x65, 0x96, 0x5d, 0x54,
+  0x25, 0xbd, 0xf9, 0x4e, 0x79, 0xd4, 0xf7, 0x0c, 0xb5, 0xac, 0xf0, 0x22,
+  0xe2, 0x27, 0x4f, 0x6f, 0xd6, 0xb5, 0x97, 0x2e, 0x92, 0xee, 0x94, 0x24,
+  0x05, 0x26, 0xa4, 0xe7, 0xd3, 0x5f, 0x20, 0x85, 0xe7, 0x30, 0xc7, 0x32,
+  0xf2, 0x5d, 0x7a, 0x46, 0x85, 0xc7, 0x2a, 0xd5, 0x00, 0x64, 0x98, 0xa7,
+  0x0b, 0x40, 0x24, 0xa8, 0x6e, 0xe5, 0x4a, 0x2e, 0x48, 0x85, 0x2f, 0x8e,
+  0x5b, 0x4a, 0xaf, 0xad, 0x83, 0xe9, 0xcb, 0x04, 0x76, 0x63, 0x6b, 0x47,
+  0x18, 0x4a, 0xd9, 0xd8, 0x80, 0x7a, 0x08, 0x30, 0x56, 0x00, 0x1f, 0xc9,
+  0x08, 0x0b, 0x65, 0x8d, 0xdf, 0x80, 0x00, 0x00, 0xa9, 0xc9, 0xb7, 0x64,
+  0xe8, 0xed, 0x0a, 0xfd, 0xfa, 0x75, 0xff, 0x0a, 0x9e, 0x7e, 0xf9, 0xd7,
+  0x32, 0xd0, 0x9d, 0xd8, 0x96, 0x74, 0x6e, 0xbe, 0xb9, 0x92, 0x02, 0x39,
+  0x01, 0x7d, 0x79, 0x53, 0x7a, 0x20, 0x18, 0x98, 0xe8, 0x01, 0x42, 0xb9,
+  0xa3, 0x8f, 0x18, 0x09, 0x5e, 0x4b, 0x8e, 0x75, 0x18, 0x2f, 0xe9, 0x89,
+  0xae, 0xbc, 0xee, 0x5c, 0xa4, 0x40, 0xbe, 0xa3, 0xa7, 0xef, 0x29, 0x4c,
+  0xc4, 0x0e, 0x21, 0x1a, 0x94, 0xad, 0x96, 0x95, 0x62, 0xa4, 0x11, 0x05,
+  0xa0, 0x37, 0x15, 0x82, 0x85, 0xde, 0xb5, 0x56, 0xd6, 0x8e, 0x2b, 0x6d,
+  0x02, 0xcb, 0x64, 0x8b, 0xc7, 0xba, 0x62, 0xdb, 0xf8, 0x6f, 0x55, 0xd2,
+  0x3f, 0x6e, 0xc4, 0x7f, 0x5b, 0x62, 0x02, 0x3f, 0xf7, 0xfc, 0xd3, 0x94,
+  0xb7, 0x55, 0x75, 0x4b, 0x96, 0x66, 0x54, 0xb8, 0x9b, 0x58, 0xda, 0xac,
+  0xcf, 0xcd, 0x58, 0x92, 0x6c, 0xfc, 0x77, 0x29, 0xde, 0x78, 0x98, 0x5c,
+  0xc2, 0xdd, 0x96, 0x74, 0xec, 0x2d, 0xc7, 0x98, 0xb4, 0x77, 0x15, 0xcb,
+  0x42, 0xcb, 0x5f, 0x5f, 0x9d, 0x85, 0xca, 0x5c, 0x33, 0xbf, 0x68, 0xf6,
+  0xef, 0xa9, 0xe6, 0x0a, 0x31, 0x50, 0x5f, 0xff, 0x3d, 0x17, 0x90, 0x48,
+  0xb1, 0xef, 0x14, 0x33, 0x16, 0x0f, 0xdd, 0x59, 0xfe, 0x4a, 0x02, 0xae,
+  0xfb, 0x71, 0x46, 0x16, 0x46, 0x36, 0x34, 0xc9, 0x92, 0x41, 0x24, 0x93,
+  0x8e, 0x04, 0x14, 0x47, 0x62, 0x2a, 0x59, 0xdc, 0x4d, 0xa5, 0x8a, 0xa2,
+  0xc5, 0x65, 0x11, 0xe3, 0x15, 0x6b, 0x83, 0xe1, 0x67, 0x4e, 0x87, 0x7d,
+  0xc4, 0x3d, 0xd2, 0x51, 0x5b, 0x6e, 0x5d, 0x61, 0x05, 0xa9, 0x3e, 0x90,
+  0x11, 0x1a, 0x26, 0xbd, 0x0b, 0x92, 0x9e, 0x0b, 0x65, 0x02, 0x8a, 0xa8,
+  0x4a, 0x65, 0xd5, 0x3a, 0x3f, 0x6b, 0xf7, 0x14, 0x9d, 0x12, 0xb4, 0xe0,
+  0xac, 0x0b, 0x48, 0xe1, 0xba, 0x6e, 0xd0, 0x89, 0x73, 0xa5, 0xc9, 0xde,
+  0x0c, 0xb2, 0xf4, 0x67, 0x73, 0x6d, 0x8c, 0xc2, 0x4a, 0xd6, 0x07, 0xb0,
+  0x82, 0x85, 0xa7, 0x36, 0xba, 0x07, 0xf2, 0x0a, 0x01, 0x6c, 0x91, 0x78,
+  0xf7, 0x48, 0x4c, 0x3b, 0x1b, 0x2f, 0xcd, 0x9a, 0x2a, 0x45, 0xc4, 0x1d,
+  0xef, 0xfa, 0x63, 0x9b, 0xf0, 0x60, 0x2c, 0xcc, 0x6b, 0x27, 0x2f, 0xc7,
+  0x1b, 0x05, 0x1a, 0x5a, 0x81, 0x40, 0x22, 0xbe, 0xb1, 0xbf, 0xc2, 0x61,
+  0xd8, 0x00, 0xaa, 0xc3, 0x31, 0x9e, 0xe0, 0x00, 0xba, 0x06, 0x5a, 0xa4,
+  0x8c, 0x0a, 0x12, 0xb2, 0x51, 0xfc, 0x8b, 0xcc, 0x4e, 0x82, 0xa6, 0x00,
+  0x49, 0x70, 0x3d, 0xb9, 0x0a, 0x03, 0x07, 0x21, 0x1a, 0x94, 0xc5, 0xb2,
+  0x94, 0xc4, 0x41, 0x09, 0x08, 0x42, 0x52, 0x10, 0x05, 0xb8, 0xa9, 0x2f,
+  0x81, 0xe1, 0x84, 0xae, 0xb5, 0x77, 0x77, 0xab, 0x41, 0x28, 0x0b, 0x1c,
+  0xcd, 0xc7, 0xbd, 0xbc, 0x72, 0x60, 0xfb, 0x9f, 0x31, 0x2d, 0xdc, 0xb2,
+  0x23, 0xeb, 0xa6, 0x2b, 0xe4, 0xd4, 0x9b, 0x14, 0xf6, 0x26, 0xc3, 0xe3,
+  0xdd, 0xeb, 0xb3, 0x28, 0xdb, 0x67, 0xc4, 0xbb, 0x56, 0x64, 0x0e, 0x59,
+  0x17, 0x68, 0xae, 0x7c, 0xed, 0xdf, 0xb4, 0x66, 0x3b, 0x6d, 0x6e, 0xa3,
+  0xf2, 0xf6, 0xd8, 0x77, 0x8d, 0xab, 0xc9, 0x7e, 0xe3, 0x94, 0xf1, 0x8a,
+  0x88, 0x5c, 0x1c, 0x86, 0xdf, 0xf2, 0xd4, 0x19, 0xbf, 0xd4, 0x36, 0xa0,
+  0xc5, 0xad, 0x61, 0x61, 0xca, 0x6f, 0x56, 0xb0, 0x72, 0xea, 0xae, 0xa9,
+  0x3b, 0xab, 0x13, 0x97, 0x56, 0x2f, 0x0f, 0x57, 0xef, 0xe6, 0x44, 0x9e,
+  0xc9, 0xf9, 0xca, 0xd7, 0x5d, 0xc9, 0x63, 0xe5, 0x87, 0xdf, 0x0a, 0x53,
+  0xa9, 0xeb, 0xf9, 0x5b, 0xe6, 0x9f, 0x6a, 0xba, 0xe3, 0xa6, 0x79, 0x60,
+  0x56, 0x08, 0x1d, 0x03, 0x68, 0xb1, 0x3d, 0x36, 0x57, 0x5e, 0x85, 0x02,
+  0x5a, 0x4a, 0xd9, 0xf8, 0x65, 0x64, 0xb3, 0x73, 0xc7, 0x24, 0x4e, 0xd2,
+  0x13, 0x2d, 0x33, 0x3e, 0x54, 0x65, 0xcc, 0xb9, 0x52, 0xcd, 0x2b, 0x54,
+  0xfb, 0xd4, 0x73, 0x1b, 0xe4, 0x8e, 0x1c, 0xad, 0x40, 0x68, 0x94, 0xea,
+  0x89, 0x0a, 0xfe, 0x90, 0xad, 0xef, 0x45, 0x3e, 0x1b, 0xdb, 0x5b, 0xf7,
+  0x94, 0x84, 0xed, 0xf7, 0x42, 0xd6, 0xd2, 0x62, 0x12, 0x3f, 0xdd, 0xb6,
+  0xc8, 0xa6, 0x3c, 0xa5, 0x9d, 0x88, 0x07, 0x70, 0x81, 0xc6, 0x00, 0x37,
+  0x6a, 0xaf, 0xf2, 0xd6, 0x0b, 0xda, 0xd4, 0xc0, 0xd1, 0x51, 0xcf, 0xa7,
+  0x30, 0xf1, 0x47, 0xaf, 0xf8, 0x93, 0x05, 0xe7, 0x87, 0xe2, 0x3d, 0xa3,
+  0x0f, 0x88, 0xb2, 0x52, 0xd1, 0x20, 0xa6, 0x12, 0x07, 0x5b, 0xed, 0xe2,
+  0xd4, 0xfa, 0x80, 0x29, 0xe5, 0xb6, 0x7b, 0x3a, 0x5a, 0xcd, 0x80, 0x80,
+  0x01, 0x14, 0x94, 0x4a, 0x21, 0x68, 0xde, 0x90, 0xdb, 0x4f, 0x50, 0x48,
+  0x48, 0x91, 0x55, 0x65, 0xef, 0x21, 0xa1, 0xea, 0xf2, 0x31, 0xc5, 0x71,
+  0xb5, 0xe4, 0xc3, 0x41, 0x4f, 0xa4, 0x5d, 0x80, 0xb8, 0x54, 0x1c, 0x21,
+  0x1a, 0x94, 0xb5, 0xa2, 0x9c, 0xc4, 0x41, 0x12, 0x04, 0xc0, 0x11, 0x55,
+  0x59, 0x51, 0x4d, 0x75, 0xc6, 0xa9, 0xc2, 0xd6, 0x01, 0x40, 0x6b, 0xc9,
+  0x49, 0xa4, 0x02, 0x3a, 0x7e, 0xa3, 0x1d, 0x12, 0x8f, 0xf9, 0x7d, 0xc4,
+  0x3d, 0xf5, 0x35, 0x43, 0x8b, 0xb4, 0x1d, 0x77, 0x1f, 0x3d, 0xe5, 0x4b,
+  0x3b, 0x66, 0x08, 0xb7, 0xdc, 0x15, 0x57, 0x6c, 0xe4, 0xf4, 0xae, 0xa1,
+  0x9a, 0x58, 0xb1, 0x73, 0x09, 0xea, 0x08, 0xf4, 0x7a, 0xce, 0x23, 0x30,
+  0xe7, 0xfe, 0x86, 0x37, 0x60, 0xf3, 0xbe, 0xf9, 0xc4, 0x6a, 0x46, 0x01,
+  0x9e, 0x82, 0x37, 0x39, 0xc6, 0x78, 0xbe, 0x55, 0x9e, 0x66, 0x01, 0xbb,
+  0x4b, 0xc9, 0x47, 0x5b, 0xa8, 0x74, 0xfa, 0xcb, 0x25, 0x38, 0x1a, 0x37,
+  0x8b, 0x3e, 0x98, 0x58, 0x76, 0x8d, 0x97, 0x31, 0xef, 0xd3, 0x8f, 0xdf,
+  0xb8, 0x6e, 0xa2, 0x94, 0xcc, 0xed, 0xf8, 0xe8, 0xe9, 0x87, 0xe8, 0x72,
+  0xee, 0xbf, 0xc1, 0x24, 0x11, 0x4c, 0xa6, 0xad, 0x6c, 0xbe, 0xc7, 0x88,
+  0xa1, 0x20, 0x00, 0x8d, 0xb4, 0xc2, 0x28, 0xdd, 0xee, 0xec, 0x23, 0x52,
+  0x72, 0x2f, 0xb5, 0x75, 0x79, 0x57, 0x4d, 0x91, 0xa0, 0x1d, 0x69, 0xb0,
+  0xf3, 0x62, 0x3d, 0x9e, 0x40, 0x43, 0x4a, 0xab, 0x62, 0xbc, 0x5b, 0x39,
+  0x22, 0x99, 0xc0, 0x78, 0x9e, 0x4a, 0x60, 0xb7, 0xc3, 0x4e, 0xf4, 0x18,
+  0x61, 0xdc, 0x8f, 0x16, 0x33, 0xa8, 0xc0, 0xae, 0x86, 0x17, 0x2d, 0x88,
+  0x9c, 0xbb, 0x4d, 0x5b, 0x49, 0xb3, 0xf0, 0xd4, 0x4e, 0x8a, 0x25, 0x6c,
+  0xe5, 0x18, 0x39, 0x21, 0xc1, 0xc7, 0x5d, 0x66, 0x13, 0x34, 0x94, 0x30,
+  0x0d, 0xc2, 0x03, 0x10, 0x80, 0xc4, 0x20, 0x21, 0x6a, 0x58, 0x2e, 0x8a,
+  0x63, 0xef, 0xe7, 0x82, 0x85, 0x9b, 0xd0, 0x24, 0xc3, 0x71, 0x86, 0xfd,
+  0xee, 0x33, 0xc9, 0xe2, 0xb8, 0x66, 0x7f, 0xe1, 0xfd, 0xee, 0xb7, 0xda,
+  0x1d, 0xdf, 0xd3, 0x03, 0xa0, 0xba, 0x5d, 0xc6, 0xbe, 0xb6, 0xab, 0x6b,
+  0xbf, 0x84, 0xa1, 0x5e, 0x93, 0xbf, 0xae, 0xd1, 0x59, 0xca, 0xda, 0xbc,
+  0x69, 0xc0, 0x43, 0xf7, 0x00, 0x04, 0xb4, 0x47, 0x87, 0x35, 0x82, 0x75,
+  0x54, 0x42, 0xdc, 0xa2, 0x09, 0x44, 0xb9, 0x9e, 0x60, 0x06, 0x37, 0x4b,
+  0xc6, 0x73, 0xa1, 0x72, 0xcc, 0xc1, 0x97, 0x35, 0x3f, 0xbe, 0xae, 0xb0,
+  0xa0, 0x07, 0x21, 0x2a, 0x94, 0xad, 0xd9, 0x03, 0x02, 0x61, 0x20, 0x85,
+  0xa0, 0x45, 0xec, 0xc5, 0x62, 0xeb, 0x5c, 0x69, 0x77, 0x20, 0xb1, 0x83,
+  0x4d, 0x86, 0xc7, 0xa8, 0x4b, 0x4d, 0x59, 0xad, 0x26, 0x71, 0xfe, 0x52,
+  0xb8, 0x47, 0x8f, 0xe1, 0x72, 0x98, 0x21, 0xd7, 0x48, 0xb8, 0xcf, 0xc3,
+  0xf8, 0xfe, 0x7b, 0xc2, 0x7a, 0xc2, 0x92, 0x69, 0x81, 0xe4, 0x9e, 0xfe,
+  0xda, 0x77, 0x0c, 0x7b, 0x96, 0xb9, 0x0f, 0x6a, 0xe6, 0x87, 0x14, 0x3b,
+  0x8b, 0xd6, 0xfb, 0xa5, 0xd1, 0x98, 0x34, 0x74, 0x73, 0xe2, 0x7b, 0x47,
+  0x2f, 0x61, 0x59, 0xb9, 0x53, 0x7e, 0xf6, 0xaf, 0xd7, 0xa0, 0xdd, 0x0b,
+  0x4e, 0x60, 0xc3, 0xa7, 0xc8, 0x88, 0x33, 0x67, 0x67, 0x65, 0xbc, 0xc1,
+  0x4b, 0xe1, 0xbb, 0x47, 0xa7, 0xac, 0xab, 0x8f, 0x1c, 0xc1, 0xad, 0xbc,
+  0xa7, 0x4e, 0x5e, 0x58, 0xd4, 0x39, 0xae, 0x07, 0x18, 0xc4, 0x15, 0xf4,
+  0x12, 0x92, 0xf3, 0x39, 0xdb, 0x0a, 0x10, 0x81, 0x53, 0x7a, 0xe2, 0xa8,
+  0xd4, 0x6a, 0x7a, 0xba, 0x96, 0xbe, 0xd6, 0x10, 0xc0, 0x55, 0xcd, 0xae,
+  0x7e, 0x62, 0x6c, 0x78, 0xee, 0xed, 0x19, 0x98, 0xe9, 0xc4, 0x30, 0x70,
+  0x03, 0xbd, 0xa8, 0x1b, 0xec, 0xd9, 0xff, 0xa8, 0x2d, 0xd3, 0x41, 0x79,
+  0x0d, 0x7c, 0xe2, 0x6a, 0x40, 0x3b, 0x52, 0x29, 0x42, 0x54, 0x54, 0xdc,
+  0xaa, 0xcf, 0xdf, 0x3f, 0xaa, 0xb2, 0x85, 0x15, 0xf3, 0x42, 0x3c, 0x62,
+  0xc8, 0x2c, 0x45, 0x18, 0x26, 0x48, 0x17, 0x4d, 0x5b, 0x04, 0xf0, 0x12,
+  0x9b, 0xd8, 0x67, 0x85, 0xd3, 0x12, 0x28, 0xa5, 0xac, 0x04, 0xa5, 0xa5,
+  0x08, 0x05, 0xa0, 0x80, 0xc4, 0x20, 0x61, 0x50, 0x0c, 0x01, 0x81, 0xd7,
+  0xee, 0xa0, 0x5e, 0x08, 0xbf, 0x30, 0xcf, 0x5d, 0x73, 0xce, 0x7f, 0x74,
+  0xf4, 0xcf, 0x27, 0xce, 0x51, 0xa7, 0x81, 0xf7, 0x96, 0x5d, 0xdb, 0xad,
+  0x28, 0xd6, 0x06, 0x01, 0xee, 0x10, 0x91, 0x2f, 0xb0, 0xde, 0x40, 0x01,
+  0x12, 0x79, 0xa4, 0xbb, 0x8b, 0xc5, 0x70, 0xde, 0xb6, 0x4e, 0xdc, 0x33,
+  0x92, 0x41, 0xe1, 0x42, 0x28, 0x2b, 0x88, 0x85, 0xea, 0x70, 0x26, 0x86,
+  0xf5, 0x80, 0x18, 0xef, 0x10, 0xb8, 0x33, 0x35, 0x5b, 0x10, 0x0e, 0x21,
+  0x4c, 0xc7, 0x47, 0x5d, 0x62, 0x3a, 0xe4, 0x41, 0x97, 0x9a, 0x1a, 0xbe,
+  0x5d, 0x89, 0x4c, 0xb9, 0xe7, 0x56, 0x1f, 0xc0, 0x79, 0xf2, 0x32, 0xff,
+  0x8a, 0x3c, 0x9d, 0x4d, 0x63, 0xf6, 0x52, 0xfc, 0xde, 0x95, 0xa2, 0x05,
+  0x25, 0x4e, 0xb8, 0xb3, 0x85, 0x83, 0x17, 0xfa, 0x3e, 0x53, 0xf6, 0x4b,
+  0xe3, 0x86, 0x52, 0x31, 0x0a, 0x3f, 0xcf, 0x1f, 0xc7, 0xf1, 0x0a, 0x80,
+  0x11, 0xdc, 0xaa, 0x5a, 0x6f, 0x22, 0x78, 0x4a, 0xb6, 0x74, 0x17, 0xd3,
+  0xa6, 0x20, 0x7f, 0xb2, 0xa3, 0x59, 0xe4, 0xd3, 0x54, 0xbc, 0xe7, 0x1d,
+  0x57, 0x77, 0x4f, 0x92, 0x1d, 0x6f, 0xc6, 0x5a, 0x21, 0xbc, 0xb2, 0x71,
+  0xa0, 0x86, 0x42, 0x37, 0x9c, 0xa7, 0xb7, 0x69, 0x19, 0xbb, 0x47, 0x7a,
+  0xc1, 0x03, 0xf3, 0x16, 0x61, 0x3d, 0x5e, 0xbd, 0xbe, 0xb2, 0x47, 0xe0,
+  0x3e, 0x62, 0x9f, 0xe1, 0x95, 0x68, 0x03, 0xd5, 0xfb, 0x7b, 0x76, 0xdf,
+  0x00, 0x10, 0x71, 0x27, 0xe2, 0x98, 0x89, 0xd5, 0xdf, 0xf6, 0xaf, 0xe0,
+  0xd9, 0xd1, 0x59, 0xdc, 0x6a, 0x9d, 0xcd, 0x9f, 0x20, 0x2b, 0x94, 0xe9,
+  0xdb, 0x0f, 0x61, 0x25, 0xbc, 0x73, 0x91, 0x00, 0x16, 0xdc, 0x93, 0xc7,
+  0xa7, 0xa3, 0xf6, 0xba, 0xdf, 0xa4, 0x72, 0x48, 0x17, 0xae, 0xcd, 0xfa,
+  0x4f, 0x79, 0xf5, 0x9e, 0xb3, 0x1a, 0x35, 0xf0, 0x7f, 0x27, 0x92, 0x7b,
+  0xaa, 0xa0, 0x1e, 0xef, 0xca, 0xc1, 0xa9, 0xc2, 0xee, 0xf6, 0xfa, 0x91,
+  0xf3, 0x3c, 0x09, 0xf8, 0xf6, 0x70, 0x2c, 0x18, 0xdf, 0x09, 0xb9, 0x39,
+  0xaa, 0x99, 0x31, 0x4a, 0xd1, 0x06, 0xfa, 0xdf, 0xbd, 0x81, 0x1b, 0x40,
+  0x7b, 0x29, 0x73, 0xca, 0x8b, 0x09, 0x57, 0x79, 0xb9, 0xbe, 0x36, 0xcd,
+  0x37, 0x33, 0x68, 0xb4, 0x23, 0x94, 0x59, 0x5a, 0x77, 0xfd, 0xe9, 0x04,
+  0x8a, 0xa8, 0x14, 0x59, 0x0c, 0x60, 0x15, 0x84, 0xd5, 0xdf, 0xab, 0x52,
+  0xf1, 0xeb, 0x40, 0xe0, 0x75, 0x3a, 0x3d, 0x77, 0x57, 0xe0, 0xc6, 0x59,
+  0x4e, 0xae, 0x88, 0x1f, 0xec, 0xe5, 0xf4, 0xcc, 0x30, 0xc8, 0x02, 0x58,
+  0xbe, 0x91, 0x50, 0x04, 0x95, 0x14, 0x50, 0x4f, 0x02, 0xa4, 0xe8, 0x39,
+  0x98, 0x1c, 0xd1, 0x62, 0x06, 0x08, 0x21, 0x41, 0x05, 0xfc, 0x3d, 0xad,
+  0x5f, 0xd9, 0xcd, 0x85, 0x97, 0xe5, 0x02, 0x92, 0xa3, 0x1c, 0xaf, 0x3a,
+  0x80, 0xdf, 0x71, 0x7d, 0x26, 0xf5, 0xdd, 0x66, 0xa6, 0x95, 0x6f, 0x0c,
+  0x80, 0x66, 0xfc, 0x2f, 0x47, 0x3c, 0x68, 0xa8, 0xe6, 0xa2, 0x21, 0x34,
+  0x82, 0x3a, 0x75, 0x08, 0x4a, 0x76, 0xc8, 0x19, 0x0f, 0xc8, 0x15, 0x0b,
+  0x3b, 0x7f, 0x4a, 0xf4, 0xd9, 0x6e, 0x9b, 0xe2, 0x66, 0x5f, 0x9a, 0xe5,
+  0x3e, 0x8b, 0x76, 0x98, 0xd3, 0x54, 0x4a, 0x24, 0x61, 0x3e, 0x71, 0xba,
+  0x11, 0x05, 0x98, 0x07, 0x21, 0x7a, 0x94, 0xc5, 0xda, 0x08, 0x83, 0x16,
+  0xb3, 0x81, 0x4e, 0x12, 0x9b, 0x09, 0xa2, 0xfc, 0x8b, 0x40, 0x00, 0x0e,
+  0x7d, 0x61, 0x9e, 0xfa, 0x5b, 0x34, 0xfb, 0xcb, 0x8f, 0x8d, 0x2d, 0x50,
+  0x6c, 0x1c, 0x5b, 0xcb, 0xf9, 0x4e, 0x2d, 0x0d, 0x7c, 0xfa, 0x0f, 0x82,
+  0xee, 0xbc, 0x23, 0x31, 0x63, 0xa9, 0x0c, 0xe7, 0x33, 0xd2, 0x3c, 0x6d,
+  0xd7, 0x59, 0x93, 0xe8, 0x32, 0x8e, 0x73, 0xc7, 0x33, 0xc3, 0xce, 0xe6,
+  0xec, 0x3b, 0x0b, 0x73, 0x55, 0x1e, 0xf2, 0x1b, 0x68, 0x83, 0xea, 0x35,
+  0xa8, 0xfd, 0x33, 0xf0, 0xdb, 0x81, 0x8e, 0x09, 0xa1, 0xac, 0x1d, 0x9f,
+  0x44, 0x8b, 0x51, 0xc8, 0x39, 0xb6, 0xe7, 0xee, 0xbd, 0x45, 0xcc, 0xf0,
+  0x5a, 0xa3, 0xa0, 0xf6, 0x55, 0x5f, 0x91, 0xa7, 0xa9, 0xc5, 0x3b, 0xd8,
+  0xb1, 0xae, 0xcd, 0x5a, 0x89, 0x38, 0x9f, 0x4a, 0x0c, 0x84, 0x24, 0x95,
+  0xb9, 0x15, 0x99, 0xc9, 0x5e, 0x66, 0x52, 0x75, 0x7d, 0xfc, 0x5e, 0x2b,
+  0x38, 0xdb, 0x1c, 0x6a, 0x84, 0x63, 0xe8, 0x5b, 0x9d, 0x23, 0x2d, 0xf4,
+  0x06, 0x28, 0x06, 0xb2, 0x21, 0x08, 0x13, 0x80, 0x76, 0x5a, 0x6f, 0x0a,
+  0x5b, 0xc8, 0x9e, 0x97, 0x82, 0xbd, 0xe7, 0x33, 0x81, 0xb5, 0x54, 0x37,
+  0xb2, 0x51, 0xf0, 0xc7, 0x81, 0x92, 0x93, 0xbf, 0x18, 0xd2, 0xb3, 0xaf,
+  0x56, 0x5b, 0xe3, 0x97, 0xb2, 0x1f, 0x3f, 0xd6, 0xa9, 0xc6, 0x91, 0xb1,
+  0xd2, 0x37, 0xc3, 0xc6, 0x36, 0xe3, 0xdd, 0xca, 0x70, 0xac, 0xe9, 0x9f,
+  0xa4, 0x63, 0xd9, 0x6a, 0xd2, 0xfb, 0xd3, 0x34, 0xdf, 0x94, 0x61, 0x1c,
+  0xaa, 0x55, 0x4a, 0xb4, 0xea, 0x84, 0x11, 0x5d, 0xfc, 0x9a, 0x6d, 0x18,
+  0xca, 0x07, 0xf0, 0x04, 0xad, 0x9e, 0x08, 0x84, 0x11, 0xd8, 0x8e, 0xc1,
+  0x90, 0xb1, 0x80, 0x0f, 0x86, 0x96, 0x58, 0x21, 0x60, 0x0e, 0xee, 0x88,
+  0xe6, 0x41, 0x1d, 0x3a, 0x7b, 0x91, 0xb9, 0x9f, 0xb5, 0x16, 0x23, 0xf2,
+  0x8a, 0x37, 0xa4, 0x68, 0x1b, 0xb1, 0xa6, 0x28, 0x4b, 0x4e, 0x60, 0x2c,
+  0x89, 0x66, 0x53, 0x4c, 0x54, 0x0e, 0x1f, 0xdf, 0x99, 0x69, 0x86, 0x65,
+  0xb9, 0xb4, 0x2a, 0xca, 0x51, 0x4a, 0x28, 0x00, 0x4f, 0x6a, 0x51, 0x06,
+  0xf7, 0x47, 0xca, 0x74, 0x9e, 0xaf, 0xd4, 0xb6, 0x20, 0x24, 0xdd, 0xf4,
+  0x4d, 0x10, 0x07, 0x10, 0x2d, 0x52, 0x8c, 0x0c, 0xf5, 0x00, 0x02, 0x7c,
+  0x76, 0x89, 0x04, 0xee, 0x2d, 0x10, 0x58, 0x90, 0x51, 0x52, 0xe4, 0xb1,
+  0x11, 0xac, 0x16, 0x8d, 0x52, 0x84, 0xf1, 0x00, 0x00, 0x39, 0x0d, 0xe9,
+  0x6d, 0x10, 0xe0, 0x21, 0x1a, 0x94, 0xd5, 0xce, 0x8b, 0x61, 0x81, 0x30,
+  0x88, 0x68, 0x51, 0x19, 0x04, 0x02, 0x85, 0xa3, 0x2e, 0x0c, 0x11, 0xae,
+  0x2f, 0x80, 0x2c, 0x83, 0x1a, 0x2d, 0x95, 0xa9, 0x52, 0x38, 0x00, 0x74,
+  0x97, 0xdf, 0xfd, 0xfb, 0xa4, 0xf7, 0x46, 0xea, 0x71, 0x78, 0xb7, 0xd4,
+  0xba, 0x13, 0x51, 0x6d, 0x1b, 0xbc, 0x55, 0xeb, 0xff, 0x42, 0x3a, 0x29,
+  0xdb, 0xdb, 0xa0, 0x28, 0x30, 0xf8, 0x25, 0x66, 0x5f, 0xc0, 0x47, 0xdb,
+  0xf7, 0x22, 0x29, 0xf3, 0x76, 0x79, 0xba, 0x42, 0xd3, 0xd4, 0x5f, 0xd6,
+  0x67, 0xf0, 0xaf, 0x9e, 0x9e, 0xf9, 0x99, 0xf0, 0xf8, 0x28, 0xc8, 0x00,
+  0xf6, 0x07, 0xd2, 0x7e, 0x6b, 0xad, 0x73, 0x03, 0xea, 0x95, 0xb8, 0x29,
+  0xf9, 0x34, 0x91, 0xcf, 0xb7, 0xe5, 0xe9, 0x7c, 0x5a, 0x2f, 0x0b, 0xb7,
+  0xc7, 0xd9, 0x4a, 0xbb, 0x79, 0x51, 0xdb, 0x0e, 0x67, 0x95, 0x7a, 0x46,
+  0x7d, 0x4b, 0x98, 0x1a, 0xf3, 0xd9, 0x38, 0x1b, 0xb4, 0xf5, 0x58, 0xfb,
+  0x0c, 0x07, 0x06, 0xfb, 0x8e, 0x9d, 0xa0, 0x86, 0xb8, 0xd7, 0x9f, 0xb3,
+  0x9a, 0x87, 0x6e, 0xfd, 0x4f, 0x52, 0xe1, 0xac, 0xb6, 0x9a, 0x28, 0x1f,
+  0xdd, 0xa8, 0x83, 0x51, 0x87, 0xed, 0x12, 0xf0, 0x3d, 0x86, 0x4a, 0x6b,
+  0x8c, 0x71, 0x35, 0xdd, 0x7e, 0xe3, 0xbf, 0xc1, 0x94, 0x16, 0xa2, 0xe0,
+  0x7f, 0x37, 0xb2, 0xb3, 0x60, 0xb4, 0xcd, 0x03, 0xe4, 0xa4, 0x27, 0xa0,
+  0x14, 0x5a, 0x77, 0x32, 0x11, 0x17, 0x33, 0x2d, 0x60, 0xae, 0x8e, 0x0e,
+  0x46, 0x1c, 0xf9, 0xa6, 0x85, 0x60, 0x72, 0xfd, 0xac, 0x10, 0x4b, 0xae,
+  0xd6, 0x03, 0x46, 0x9b, 0xb3, 0xb7, 0xef, 0xba, 0x65, 0xfd, 0xda, 0xee,
+  0x19, 0x03, 0x57, 0x59, 0x2e, 0xc1, 0x6c, 0xae, 0x0e, 0x39, 0x81, 0x1c,
+  0xc4, 0x85, 0x82, 0x77, 0xbc, 0x84, 0x68, 0x98, 0xda, 0xb6, 0xb3, 0xeb,
+  0x2a, 0x40, 0xe3, 0xb3, 0xc8, 0xdc, 0x0c, 0xc0, 0x2c, 0x28, 0x3e, 0x3b,
+  0x7f, 0xa7, 0xdc, 0x7f, 0xf7, 0xec, 0xd9, 0x69, 0xab, 0xb2, 0x62, 0x8e,
+  0xc8, 0x01, 0xc8, 0x80, 0x62, 0x16, 0x19, 0x0c, 0x46, 0x02, 0x13, 0x99,
+  0x70, 0x20, 0x17, 0xec, 0xd0, 0xd0, 0x1c, 0x60, 0xb6, 0x52, 0xa7, 0x40,
+  0x00, 0x13, 0xde, 0xab, 0x7f, 0x99, 0x85, 0x40, 0x6a, 0xb5, 0x41, 0x23,
+  0xb6, 0x09, 0xf7, 0x97, 0x99, 0x04, 0xb3, 0x99, 0x72, 0xba, 0x85, 0xa0,
+  0xa9, 0x99, 0x82, 0x05, 0x92, 0x84, 0x09, 0x4a, 0x2a, 0xb1, 0xaf, 0xcd,
+  0xbd, 0xf7, 0x66, 0x9c, 0x26, 0xe3, 0xf3, 0x07, 0x6f, 0x3f, 0x2f, 0xe3,
+  0xfc, 0xfe, 0x39, 0xf1, 0xc3, 0xaf, 0x67, 0x92, 0xf9, 0xf0, 0xd7, 0x3c,
+  0x8c, 0x8e, 0x2d, 0x6d, 0x53, 0x56, 0x74, 0x03, 0xb3, 0xcd, 0x65, 0xe5,
+  0x6b, 0x8a, 0x4e, 0x9e, 0x8e, 0x78, 0xc0, 0x24, 0xec, 0x9a, 0xa6, 0x01,
+  0x75, 0x41, 0x9a, 0x3b, 0x3e, 0x3c, 0x24, 0xd1, 0x69, 0x1e, 0xcc, 0xcc,
+  0x2f, 0x94, 0x25, 0xc1, 0x6f, 0x95, 0x9b, 0x6c, 0x33, 0x00, 0x4a, 0xc0,
+  0xcb, 0x2f, 0x8a, 0x3e, 0x58, 0x09, 0x15, 0x79, 0x40, 0x1c, 0x21, 0x1a,
+  0x94, 0xcd, 0x9e, 0x9e, 0xc3, 0x41, 0x12, 0x04, 0xe6, 0x48, 0xd3, 0x2c,
+  0x53, 0x63, 0x8b, 0xe2, 0xf4, 0x96, 0x5a, 0x00, 0x58, 0x5f, 0x78, 0xac,
+  0x07, 0x8a, 0xf6, 0xb3, 0xab, 0x0c, 0xf0, 0x1e, 0xf6, 0xbc, 0xaf, 0xeb,
+  0x5c, 0xbd, 0x65, 0xf0, 0xb6, 0x7b, 0xca, 0xbe, 0x8e, 0xbb, 0x13, 0x7d,
+  0xaf, 0x0e, 0xcf, 0x32, 0xaf, 0xe6, 0xf2, 0x0c, 0xe9, 0x33, 0xb0, 0x76,
+  0x08, 0x5a, 0xff, 0x97, 0x66, 0xde, 0xc9, 0x45, 0xc6, 0xf7, 0xac, 0x87,
+  0x91, 0xdf, 0xff, 0x77, 0x9c, 0x7e, 0x93, 0xae, 0xe4, 0xe4, 0xb9, 0x05,
+  0x57, 0x7b, 0xf3, 0xb3, 0x5a, 0x21, 0xef, 0x4d, 0xb1, 0x14, 0x97, 0x1b,
+  0x99, 0x35, 0x9d, 0xb5, 0xa6, 0x6c, 0xe1, 0x6d, 0x19, 0x55, 0x0a, 0x43,
+  0x0c, 0x8d, 0x20, 0x4b, 0xd7, 0x2c, 0x64, 0x02, 0x54, 0x77, 0x4b, 0x6f,
+  0x55, 0x51, 0x77, 0xc0, 0xfe, 0xbd, 0xde, 0xfd, 0x2a, 0xf6, 0xce, 0x03,
+  0x78, 0x1d, 0x74, 0x54, 0xce, 0x1a, 0x79, 0x77, 0xa0, 0xa6, 0x71, 0x5d,
+  0xd1, 0xe2, 0xa9, 0x7d, 0x31, 0x48, 0x00, 0x25, 0x22, 0x50, 0x46, 0x63,
+  0x4d, 0x2d, 0x59, 0xce, 0x70, 0xa5, 0xd4, 0xb1, 0x83, 0x76, 0x74, 0x16,
+  0x29, 0x5f, 0x70, 0x2f, 0xe7, 0xdb, 0xba, 0xe6, 0xc3, 0xe1, 0x46, 0xc0,
+  0xb9, 0xda, 0x3f, 0x7d, 0x8b, 0xf4, 0x67, 0x8b, 0xd6, 0xf3, 0x62, 0x8f,
+  0x13, 0xe7, 0xf2, 0x01, 0xf2, 0x9f, 0xc7, 0x94, 0x41, 0x46, 0x77, 0xcb,
+  0xb5, 0x63, 0xf3, 0x87, 0xe1, 0xfd, 0x72, 0x5b, 0x75, 0x42, 0x5a, 0x94,
+  0x85, 0x01, 0xb8, 0x86, 0x08, 0x10, 0x10, 0x8d, 0x41, 0xbe, 0xaa, 0x6d,
+  0x4b, 0x70, 0x5b, 0x5a, 0xb5, 0xdc, 0x06, 0x98, 0x18, 0x1a, 0x49, 0xbf,
+  0xeb, 0xa6, 0x8c, 0xb6, 0x6b, 0xf0, 0x57, 0x2c, 0x2f, 0xeb, 0xbb, 0x2d,
+  0x51, 0x41, 0x65, 0x4d, 0x6e, 0x6a, 0x4b, 0xe3, 0xc2, 0x8c, 0xb4, 0x81,
+  0x5c, 0x02, 0x45, 0x37, 0xe9, 0xfe, 0x4e, 0x85, 0xb1, 0x80, 0x20, 0x5c,
+  0x00, 0x88, 0x22, 0xa2, 0x49, 0x50, 0x02, 0x82, 0xc2, 0xe6, 0x1a, 0x47,
+  0x7d, 0x22, 0x58, 0x5a, 0x1e, 0x5b, 0xa1, 0x59, 0x27, 0x9e, 0xf0, 0x04,
+  0x46, 0x88, 0x05, 0xfa, 0x67, 0x98, 0x15, 0x43, 0x51, 0x1f, 0x58, 0x56,
+  0x67, 0xcb, 0xf8, 0xf8, 0x40, 0x07, 0x7d, 0xca, 0x56, 0x39, 0x83, 0x07,
+  0x21, 0x1a, 0x94, 0xad, 0xc6, 0x89, 0x07, 0x47, 0x00, 0x16, 0x1b, 0xa4,
+  0xe9, 0xad, 0x4c, 0xea, 0x49, 0x60, 0xa4, 0x05, 0xb2, 0x77, 0x12, 0x47,
+  0xec, 0xba, 0x40, 0xcb, 0xf3, 0x72, 0x6d, 0x3d, 0x6c, 0x9d, 0x6d, 0x2d,
+  0xb6, 0x4c, 0x57, 0xfb, 0xe7, 0x89, 0xb7, 0x4a, 0xf8, 0x3e, 0x50, 0x60,
+  0x71, 0x66, 0xcb, 0xf4, 0x42, 0x31, 0xd0, 0x31, 0x17, 0xec, 0x8d, 0x92,
+  0x29, 0x58, 0xae, 0x7c, 0x90, 0xbc, 0xeb, 0x3f, 0xe9, 0xfd, 0x5b, 0x84,
+  0xc0, 0x28, 0x71, 0x70, 0xa7, 0xab, 0xbe, 0xd9, 0xd6, 0xfd, 0x63, 0xe0,
+  0xb4, 0xc6, 0x5c, 0xd5, 0x58, 0x96, 0x2f, 0xc5, 0x17, 0xf9, 0x8e, 0x16,
+  0x32, 0xbf, 0xd0, 0xbd, 0x8f, 0x95, 0x53, 0x72, 0xa5, 0xef, 0xfa, 0x8d,
+  0x5a, 0x33, 0xa1, 0xed, 0x3a, 0x76, 0x79, 0xbd, 0x0d, 0x7e, 0x55, 0x18,
+  0x73, 0x3b, 0x2a, 0xec, 0x60, 0x85, 0x12, 0x37, 0xe6, 0x0c, 0x79, 0x6f,
+  0x26, 0xcc, 0x2d, 0xc6, 0xa0, 0x32, 0x0a, 0x4f, 0x76, 0x38, 0xb4, 0xdf,
+  0x61, 0x6f, 0xa5, 0x11, 0x31, 0xd4, 0x45, 0xc7, 0x81, 0x82, 0xdb, 0x40,
+  0x84, 0xdf, 0x40, 0x86, 0xdf, 0x00, 0x13, 0x28, 0x80, 0xa6, 0xf9, 0x06,
+  0x2c, 0x48, 0x22, 0xd8, 0x88, 0x09, 0x68, 0x24, 0xee, 0xc8, 0x58, 0x64,
+  0xb4, 0x95, 0x5f, 0xc9, 0x02, 0xc7, 0x3c, 0x1c, 0x76, 0x3c, 0xaa, 0x0a,
+  0x65, 0x75, 0x2b, 0xca, 0x08, 0x4f, 0x1b, 0xd2, 0xcf, 0xea, 0xcc, 0x0a,
+  0x5e, 0x6b, 0x3f, 0x51, 0x5f, 0xef, 0x37, 0xcd, 0x22, 0xe4, 0x20, 0xea,
+  0xaf, 0xcd, 0x1c, 0x81, 0xbb, 0x50, 0x9c, 0xb7, 0x9b, 0x62, 0x90, 0x8d,
+  0x60, 0x58, 0x05, 0x86, 0x61, 0x9a, 0x1b, 0x30, 0x56, 0xa6, 0x4e, 0xd0,
+  0x10, 0x3f, 0x6e, 0x0a, 0x69, 0x72, 0xb3, 0x85, 0xec, 0x2d, 0x35, 0x99,
+  0x31, 0xff, 0x25, 0x88, 0xb6, 0x38, 0x45, 0x55, 0x58, 0xd5, 0x45, 0x6e,
+  0x71, 0x00, 0xa0, 0xb5, 0x9e, 0x4a, 0x7e, 0xa3, 0xbb, 0xbc, 0xa5, 0x9d,
+  0x90, 0x03, 0x72, 0x80, 0x50, 0xa2, 0x74, 0x08, 0x08, 0x46, 0x01, 0x52,
+  0xa8, 0x85, 0xbd, 0x9c, 0x5a, 0xe0, 0x00, 0x22, 0x9e, 0xb1, 0xcc, 0xbc,
+  0x57, 0xd3, 0x59, 0x63, 0xc7, 0xbc, 0x63, 0x4c, 0xe6, 0x5a, 0x73, 0x3d,
+  0xd6, 0x20, 0x49, 0xf5, 0x4b, 0x04, 0x70, 0xb0, 0xa8, 0x63, 0x46, 0xb4,
+  0xc8, 0x10, 0x92, 0x21, 0x38, 0x18, 0xd5, 0xce, 0x3f, 0x37, 0xbd, 0xc5,
+  0x09, 0x02, 0x00, 0x29, 0x04, 0x96, 0xe0, 0x38, 0x89, 0x6f, 0xff, 0x7c,
+  0xb3, 0x4b, 0xf2, 0x0a, 0xf5, 0x37, 0x73, 0x07, 0xfa, 0x4c, 0xcc, 0x37,
+  0x91, 0x66, 0x0b, 0x5d, 0xb1, 0x55, 0xb3, 0xa5, 0x6d, 0xe7, 0xce, 0x84,
+  0x6d, 0x8c, 0xc4, 0xf1, 0xac, 0x64, 0x72, 0x85, 0x31, 0xe8, 0xbc, 0x7e,
+  0x90, 0xbb, 0x04, 0x67, 0xa2, 0x0b, 0xbc, 0x74, 0xa2, 0x00, 0xfb, 0x79,
+  0x3f, 0x5e, 0xbd, 0xb9, 0x3e, 0xe2, 0x9b, 0xee, 0x8e, 0xe6, 0xd2, 0x9c,
+  0x88, 0xae, 0xbf, 0x50, 0xa5, 0xb9, 0xfa, 0xf9, 0x69, 0xe9, 0xb0, 0x38,
+  0x21, 0x1a, 0x94, 0xd5, 0x9e, 0xa6, 0xc3, 0x44, 0x09, 0x55, 0x22, 0xa5,
+  0xb5, 0x59, 0x79, 0xc9, 0x35, 0xa6, 0xb8, 0x94, 0x9a, 0xb9, 0x2a, 0xaf,
+  0x08, 0x51, 0xac, 0x9d, 0x42, 0x90, 0x0a, 0x05, 0x53, 0xc3, 0xae, 0x6e,
+  0xbd, 0x97, 0x7a, 0xe1, 0xfb, 0x98, 0x7f, 0x0f, 0x24, 0xc6, 0x18, 0x95,
+  0x27, 0xa5, 0x93, 0xd7, 0xfb, 0x16, 0xce, 0xd7, 0x7b, 0x7e, 0xab, 0x69,
+  0x19, 0x5b, 0xed, 0x5e, 0xc1, 0x6e, 0xbd, 0x5c, 0xbc, 0xdb, 0x98, 0x56,
+  0x29, 0xdf, 0xfb, 0xa7, 0xb2, 0x78, 0x34, 0xdb, 0xe5, 0x86, 0x17, 0x05,
+  0xeb, 0xe8, 0xf2, 0xe9, 0xdc, 0x85, 0x50, 0x1a, 0xed, 0x1a, 0xb9, 0x16,
+  0xa2, 0x76, 0x4f, 0x51, 0xf6, 0xbd, 0x8d, 0x5e, 0x10, 0x1f, 0xdb, 0xd5,
+  0xd5, 0xc7, 0xb2, 0xb2, 0x5e, 0x2e, 0x16, 0x05, 0x05, 0x54, 0x88, 0x5a,
+  0xac, 0x34, 0x5d, 0x08, 0x62, 0x07, 0x6b, 0xda, 0xd0, 0xe0, 0x3a, 0x05,
+  0x56, 0xa7, 0xf9, 0xbe, 0xb7, 0x52, 0xe3, 0x99, 0x64, 0xad, 0x0f, 0x95,
+  0xc5, 0xf5, 0x56, 0x5a, 0xa7, 0x42, 0xc8, 0xde, 0x32, 0x53, 0x6c, 0x26,
+  0x9f, 0x9e, 0x5c, 0x26, 0x09, 0x68, 0x06, 0x87, 0x9a, 0x50, 0x82, 0x2a,
+  0xa5, 0x92, 0x28, 0x0b, 0x85, 0x16, 0xe7, 0x4d, 0x72, 0x1c, 0xf7, 0x50,
+  0x87, 0x2e, 0x65, 0x45, 0xd3, 0xe4, 0xd9, 0xa9, 0x83, 0xcd, 0x0b, 0xcd,
+  0x74, 0x06, 0x02, 0x55, 0x5d, 0x73, 0xd0, 0xb6, 0x92, 0xe6, 0xb3, 0x1a,
+  0xaf, 0x0d, 0x99, 0xe5, 0xdc, 0x57, 0xa7, 0xec, 0xe4, 0x06, 0xcb, 0xd9,
+  0x74, 0xca, 0x7a, 0xee, 0x80, 0x0c, 0x1a, 0xec, 0x88, 0xfc, 0x7b, 0x3d,
+  0xe6, 0x06, 0xe2, 0x5c, 0x50, 0xca, 0xa4, 0xcb, 0x11, 0x6e, 0x3e, 0x28,
+  0x61, 0xb4, 0xe1, 0x92, 0xe4, 0xee, 0x9b, 0x88, 0x01, 0x68, 0x3f, 0x2b,
+  0x45, 0x40, 0x3d, 0x1a, 0xa1, 0x6b, 0x80, 0x96, 0xa3, 0xb2, 0x00, 0x6a,
+  0x21, 0x23, 0x10, 0x52, 0x02, 0x11, 0xab, 0x2e, 0x6f, 0x4c, 0xb1, 0x41,
+  0xe6, 0xd2, 0x43, 0xcc, 0xa0, 0x58, 0xd6, 0x58, 0x91, 0x17, 0x24, 0x00,
+  0x3a, 0x05, 0x53, 0xc3, 0xb3, 0x6e, 0x07, 0x7d, 0xf1, 0x9a, 0xd6, 0x30,
+  0xe3, 0xbc, 0x5a, 0xd8, 0x78, 0x9a, 0x83, 0x1c, 0xf9, 0x3b, 0x0e, 0xcb,
+  0xd8, 0xa0, 0x44, 0x52, 0x27, 0x03, 0x54, 0xbd, 0x57, 0x37, 0x42, 0xf5,
+  0xfa, 0xf5, 0xca, 0x40, 0x7e, 0x1c, 0xf8, 0x0a, 0x7d, 0xcf, 0x89, 0xcb,
+  0xb6, 0xf9, 0x9e, 0xae, 0xbb, 0x70, 0xa7, 0x8f, 0x74, 0xbd, 0x71, 0x85,
+  0x93, 0x5b, 0x83, 0x25, 0x6b, 0x4a, 0x3b, 0xb2, 0x3a, 0x9a, 0x10, 0xb2,
+  0x3a, 0xb4, 0x38, 0x21, 0x09, 0x80, 0xf9, 0xce, 0x61, 0x74, 0xcb, 0x76,
+  0x0a, 0x41, 0x49, 0xa3, 0xbb, 0x35, 0xff, 0x8e, 0xe9, 0xfb, 0xeb, 0x81,
+  0x97, 0x1a, 0x87, 0x4f, 0xa9, 0xd3, 0x07, 0x4f, 0x76, 0x1f, 0x47, 0x4f,
+  0x74, 0x88, 0x22, 0xd5, 0x01, 0x94, 0x00, 0x05, 0x7f, 0x88, 0x38, 0x21,
+  0x1a, 0x94, 0xc5, 0xce, 0x8c, 0xc3, 0x24, 0x89, 0x40, 0x1a, 0xca, 0x14,
+  0x13, 0xa0, 0xbb, 0x97, 0xaa, 0xa0, 0xb8, 0xa3, 0x59, 0x62, 0x92, 0x1c,
+  0x73, 0xc7, 0x28, 0x11, 0x2c, 0xa6, 0x78, 0xb7, 0xc5, 0x4d, 0xbe, 0xbe,
+  0xd1, 0xd8, 0xbe, 0x25, 0x83, 0x98, 0xf7, 0x25, 0xe9, 0x82, 0x67, 0x1c,
+  0x98, 0x0b, 0xb0, 0x9b, 0xb7, 0x2b, 0x82, 0x34, 0x8b, 0xe7, 0x0a, 0xab,
+  0x86, 0x6d, 0xd8, 0x7d, 0x3d, 0xff, 0x69, 0xe6, 0xf5, 0xf0, 0x0d, 0x25,
+  0x65, 0xb4, 0xe2, 0x36, 0xd6, 0xa3, 0xb0, 0x61, 0xd2, 0x37, 0x30, 0x52,
+  0x8e, 0x16, 0xbe, 0xfb, 0x6c, 0xec, 0x7e, 0x4a, 0xca, 0x59, 0xcc, 0xce,
+  0x22, 0xf9, 0x8d, 0xee, 0x1b, 0x48, 0x3e, 0x2f, 0xba, 0x96, 0x2f, 0x0c,
+  0x58, 0xab, 0x2a, 0x35, 0xda, 0x7c, 0x2b, 0x14, 0xcc, 0xd9, 0x2b, 0x7d,
+  0x11, 0x6e, 0xcd, 0x73, 0x85, 0xe5, 0xef, 0x75, 0xa8, 0x61, 0x8b, 0x9d,
+  0x62, 0x12, 0xab, 0x12, 0xbb, 0xf9, 0xd7, 0xd4, 0xd1, 0xd6, 0x2b, 0xf8,
+  0xab, 0xab, 0x26, 0x3d, 0xb2, 0xa5, 0xb5, 0x42, 0x0a, 0x54, 0xa6, 0x6a,
+  0x3e, 0x32, 0x06, 0x87, 0x4a, 0x8e, 0xe7, 0xa5, 0x06, 0x77, 0x51, 0x1c,
+  0x62, 0x55, 0x71, 0xa0, 0xd9, 0xd4, 0x5d, 0x6a, 0xa1, 0x29, 0x52, 0x77,
+  0xdb, 0x86, 0x7c, 0x69, 0x64, 0x31, 0xcf, 0x4b, 0x14, 0x66, 0x36, 0x2b,
+  0x59, 0x76, 0x61, 0x28, 0x40, 0x03, 0xce, 0xc0, 0x8e, 0x8c, 0x72, 0xa3,
+  0x38, 0x13, 0x06, 0x10, 0xa2, 0x08, 0x79, 0x87, 0x39, 0xf0, 0xf5, 0x58,
+  0x79, 0x0d, 0x78, 0xfd, 0xca, 0x66, 0xd3, 0x2b, 0x5c, 0xe4, 0x17, 0x1f,
+  0xba, 0x7b, 0xf8, 0x9c, 0x1f, 0x21, 0x12, 0x37, 0xf1, 0xbf, 0x96, 0x4d,
+  0x72, 0xd7, 0xf1, 0x1d, 0xca, 0xcd, 0x10, 0x4c, 0xd2, 0x50, 0xc0, 0x34,
+  0x10, 0x44, 0x4a, 0xba, 0x66, 0xe4, 0xb0, 0x0f, 0xf1, 0x34, 0x8d, 0x65,
+  0x8a, 0x48, 0x71, 0xcf, 0x1c, 0xa0, 0x44, 0xb2, 0x97, 0xd6, 0x38, 0xf6,
+  0xb3, 0x8c, 0xf2, 0x5e, 0xa6, 0xdb, 0x7e, 0xbd, 0xbc, 0x33, 0x3c, 0xb2,
+  0x47, 0x1e, 0xf6, 0x3c, 0x40, 0x0c, 0x3c, 0x02, 0xd4, 0xdf, 0x3f, 0xfe,
+  0xfb, 0xb8, 0xff, 0xa7, 0x87, 0xad, 0xe0, 0x00, 0x36, 0x80, 0x96, 0x80,
+  0x00, 0x69, 0x0e, 0x21, 0x2a, 0x94, 0xb5, 0xa2, 0x8f, 0x64, 0x81, 0xb1,
+  0x88, 0x88, 0x22, 0x40, 0x0b, 0x65, 0xef, 0x52, 0x85, 0xcd, 0x38, 0x67,
+  0x13, 0x40, 0x00, 0x0d, 0x27, 0xea, 0x1d, 0x57, 0xc9, 0x04, 0x50, 0x7e,
+  0xeb, 0xa7, 0x49, 0x09, 0x13, 0xf1, 0x9c, 0x9c, 0x51, 0xf6, 0x6f, 0x58,
+  0xe6, 0x6f, 0x74, 0xe2, 0xaa, 0xf4, 0x1f, 0x5b, 0x91, 0xdb, 0x2a, 0x21,
+  0x58, 0xd9, 0xeb, 0x56, 0xdc, 0xde, 0x48, 0x3a, 0x07, 0x51, 0xda, 0x1e,
+  0xfb, 0x58, 0xbe, 0xd2, 0x24, 0x54, 0xec, 0xad, 0x9b, 0xc8, 0x2c, 0x2a,
+  0x33, 0x43, 0xfa, 0xab, 0x87, 0x0a, 0xaa, 0xa2, 0x56, 0x1b, 0x82, 0xfa,
+  0x31, 0xf1, 0x84, 0xee, 0x3c, 0xd4, 0x97, 0xce, 0x66, 0xdb, 0xde, 0x2d,
+  0x9b, 0x4d, 0x9f, 0x6d, 0x78, 0x58, 0x4f, 0xf3, 0x23, 0x48, 0xd0, 0x00,
+  0x96, 0xae, 0xe5, 0xc0, 0xbf, 0x9f, 0xb0, 0xde, 0x7c, 0x57, 0x7f, 0x75,
+  0x5a, 0xa5, 0x91, 0xd2, 0xf3, 0x52, 0xac, 0xd0, 0xe9, 0xc7, 0x17, 0x7b,
+  0x26, 0x07, 0x12, 0xae, 0xb9, 0x01, 0x00, 0x88, 0x8d, 0x8d, 0x98, 0xc2,
+  0x0b, 0x07, 0x62, 0x78, 0x18, 0x43, 0x9e, 0xdd, 0xcf, 0xcd, 0xe0, 0x41,
+  0xcf, 0x19, 0x42, 0x48, 0x34, 0xea, 0xa9, 0xff, 0x19, 0x59, 0xf7, 0x87,
+  0xd2, 0x11, 0x78, 0x47, 0xba, 0x4d, 0xed, 0x92, 0xa5, 0x96, 0xce, 0xfd,
+  0x30, 0x8a, 0xf6, 0x04, 0xae, 0x6f, 0x86, 0x45, 0xe4, 0xb2, 0xe7, 0xfc,
+  0x7b, 0xc3, 0x61, 0x01, 0x66, 0xb0, 0xed, 0xdf, 0x2e, 0x0e, 0xfc, 0x00,
+  0xa4, 0x63, 0x5c, 0x2b, 0xc7, 0x61, 0x30, 0x02, 0xf5, 0x68, 0x73, 0x7a,
+  0x1b, 0x6b, 0x6d, 0x74, 0xf7, 0xfd, 0xb9, 0x75, 0x97, 0xc6, 0x6f, 0xc3,
+  0xa0, 0x00, 0x25, 0x2c, 0xd0, 0x64, 0x18, 0xec, 0x00, 0x32, 0x02, 0xde,
+  0xd0, 0x74, 0x58, 0x08, 0xa0, 0x61, 0xfd, 0xc4, 0x82, 0xf5, 0xda, 0xbd,
+  0x05, 0x05, 0xf8, 0x67, 0xf5, 0xb3, 0xf4, 0xb9, 0x35, 0x1e, 0xdf, 0xc5,
+  0xc5, 0x67, 0xbd, 0x41, 0x27, 0x49, 0x6c, 0x43, 0xad, 0x7a, 0xdc, 0xfe,
+  0xa1, 0x9a, 0xaa, 0xbf, 0x9a, 0x54, 0xf2, 0x7e, 0x31, 0xd9, 0xae, 0xf6,
+  0xe3, 0x08, 0xb0, 0x1e, 0x4f, 0x16, 0xdf, 0xbd, 0xde, 0xe8, 0x01, 0x93,
+  0x00, 0x05, 0x46, 0xee, 0x21, 0x28, 0x00, 0x4a, 0x9d, 0x0c, 0x08, 0x40,
+  0x11, 0x5c, 0x4a, 0x55, 0xdb, 0x6b, 0x78, 0xb2, 0x11, 0x22, 0x7f, 0xd0,
+  0x0c, 0x19, 0x13, 0xd1, 0xa9, 0x73, 0x8c, 0x30, 0xd2, 0xb5, 0x9f, 0x08,
+  0x94, 0xfb, 0xed, 0x86, 0xd8, 0x15, 0x29, 0x13, 0xc9, 0x75, 0x42, 0xc3,
+  0x2c, 0x0a, 0x7a, 0xf0, 0x07, 0x21, 0x4c, 0xcd, 0x46, 0xdd, 0x62, 0x3a,
+  0xea, 0x31, 0x96, 0xaa, 0x23, 0x17, 0x78, 0x71, 0x6e, 0xb8, 0x25, 0x1f,
+  0xc2, 0xdd, 0x3a, 0x21, 0xfd, 0x27, 0xb5, 0x79, 0xd4, 0x41, 0xfc, 0x5d,
+  0x9e, 0x69, 0x7a, 0xb0, 0xa2, 0x43, 0xc8, 0x6b, 0x77, 0xd8, 0xe6, 0x24,
+  0x29, 0x56, 0x91, 0x91, 0x61, 0xea, 0x38, 0x4d, 0x5f, 0x9f, 0x69, 0xf5,
+  0xa5, 0x9b, 0x86, 0x98, 0xa5, 0x56, 0x8f, 0xf3, 0x0b, 0xea, 0x2f, 0xf2,
+  0xec, 0x2b, 0x1c, 0x46, 0x3d, 0xf5, 0xf8, 0x9a, 0xcb, 0x63, 0xcb, 0x7f,
+  0x09, 0x7e, 0x3d, 0x95, 0x02, 0x0c, 0xde, 0xeb, 0x94, 0x2e, 0x94, 0x68,
+  0xbd, 0x3a, 0xf5, 0x22, 0x09, 0x59, 0x40, 0x31, 0x0d, 0xa2, 0x03, 0x07,
+  0x0e, 0xc5, 0xbe, 0x3d, 0xb3, 0xcb, 0x32, 0xdc, 0x8a, 0xd5, 0x9a, 0xdc,
+  0x5f, 0x76, 0x78, 0x4a, 0x29, 0x4c, 0x96, 0x83, 0x82, 0xeb, 0x40, 0xe0,
+  0xb1, 0x69, 0xe4, 0x98, 0xdd, 0x3b, 0x12, 0x80, 0x8d, 0x69, 0x02, 0x79,
+  0xac, 0x48, 0x9d, 0x35, 0xff, 0x7e, 0xfe, 0xf7, 0xeb, 0xaf, 0xd2, 0x71,
+  0x3c, 0xae, 0x13, 0xa2, 0xa9, 0xca, 0xb6, 0xec, 0xfe, 0xbd, 0x02, 0xff,
+  0xb7, 0x2d, 0x7d, 0x40, 0xb0, 0x4c, 0x1a, 0x4c, 0xe2, 0xea, 0x65, 0x64,
+  0x3d, 0x2f, 0xde, 0xfb, 0xa3, 0xbc, 0x69, 0x56, 0xbb, 0xd4, 0x32, 0xbe,
+  0x7c, 0x7d, 0xb6, 0x39, 0x23, 0x17, 0xc9, 0xf2, 0x6b, 0xb4, 0xaa, 0xbc,
+  0x29, 0x36, 0x3a, 0x7a, 0x24, 0x58, 0x5d, 0x00, 0x10, 0x5c, 0x42, 0x68,
+  0x26, 0x8a, 0xb2, 0x3a, 0x52, 0x25, 0x91, 0x9c, 0x6b, 0x4f, 0x0f, 0x25,
+  0x2f, 0x2a, 0x5a, 0xc9, 0x4d, 0x18, 0xa3, 0x3b, 0x2c, 0x47, 0xda, 0x66,
+  0x38, 0x0d, 0xe1, 0xd6, 0xda, 0x0d, 0xb3, 0x50, 0x78, 0x45, 0xf1, 0xc5,
+  0xf0, 0x3f, 0xb2, 0x9f, 0x71, 0xa6, 0x9f, 0xd9, 0xc3, 0xad, 0x71, 0x4b,
+  0x3f, 0x61, 0xec, 0x79, 0x01, 0x15, 0xf2, 0xdd, 0xfb, 0xe9, 0x52, 0x70,
+  0x38, 0xcd, 0xfe, 0x3b, 0x01, 0xf6, 0xb0, 0xe3, 0x28, 0x8d, 0x28, 0x62,
+  0x08, 0x32, 0xde, 0x4a, 0xc8, 0x9c, 0x05, 0x33, 0x91, 0x5d, 0x24, 0x54,
+  0x46, 0x1e, 0x46, 0xe5, 0x6f, 0xef, 0xd0, 0xe2, 0x69, 0x9d, 0xa7, 0x22,
+  0x6a, 0xa1, 0xbe, 0xcb, 0xe7, 0xcc, 0x3f, 0xea, 0xfc, 0x97, 0x08, 0x7e,
+  0x27, 0xd8, 0x8a, 0xa7, 0x4f, 0x1d, 0x2e, 0x92, 0x46, 0xd3, 0x90, 0xca,
+  0x90, 0x3d, 0xc7, 0x43, 0x90, 0x3c, 0x79, 0x1e, 0x5f, 0xa3, 0x6e, 0x8b,
+  0x12, 0xa2, 0x8c, 0xdb, 0x6a, 0x5c, 0xd3, 0x4c, 0xba, 0x0d, 0x58, 0x39,
+  0xc1, 0x82, 0x86, 0xd4, 0xde, 0xfd, 0xbd, 0x0c, 0xf8, 0xcc, 0x6d, 0x38,
+  0x85, 0x11, 0x59, 0x9c, 0xd2, 0x8d, 0x36, 0x25, 0xe5, 0x7d, 0xc9, 0x54,
+  0x37, 0x6b, 0x94, 0xb8, 0x5a, 0xce, 0x84, 0x6a, 0x5e, 0xb8, 0xe9, 0xa2,
+  0x33, 0x14, 0xda, 0x80, 0x44, 0xa4, 0x80, 0xba, 0x6b, 0xdd, 0x0d, 0xd7,
+  0x55, 0x8a, 0x31, 0x42, 0x0c, 0xfd, 0x0c, 0x04, 0x79, 0xcd, 0x5b, 0xa3,
+  0x48, 0x63, 0x64, 0x38, 0x21, 0x7a, 0x8c, 0x00, 0x7f, 0xff, 0xff, 0xff,
+  0x2d, 0x6d, 0xa4, 0xb0, 0xc8, 0x82, 0xd0, 0x82, 0xa3, 0x55, 0x92, 0xb7,
+  0x7a, 0x9c, 0x1a, 0xad, 0x00, 0x40, 0x50, 0x13, 0x12, 0x32, 0x1a, 0xb1,
+  0xfa, 0x48, 0x05, 0xdf, 0x5b, 0xfa, 0xf1, 0x21, 0x43, 0xf7, 0x5a, 0x89,
+  0x15, 0x10, 0xf7, 0xd4, 0xac, 0x0c, 0x37, 0xdc, 0x1f, 0x12, 0x56, 0xa6,
+  0x8c, 0xfb, 0xfd, 0xb7, 0x70, 0xb7, 0xdb, 0x39, 0x89, 0xd9, 0x98, 0x5f,
+  0xba, 0xc3, 0x94, 0xb9, 0x8f, 0x88, 0xc1, 0xf5, 0x6e, 0x47, 0x57, 0xae,
+  0xd7, 0xe7, 0x33, 0xbf, 0x17, 0xd7, 0x58, 0x7e, 0x8a, 0x47, 0xca, 0xed,
+  0x1d, 0xe7, 0x8d, 0x61, 0x39, 0xe9, 0x45, 0x18, 0x69, 0xef, 0x71, 0xb6,
+  0xf8, 0xb0, 0x19, 0x7f, 0x2c, 0xea, 0xb7, 0x87, 0xee, 0x03, 0x17, 0xe4,
+  0x49, 0xda, 0x37, 0x2a, 0xc3, 0xe5, 0x77, 0x07, 0x5d, 0x6e, 0xd1, 0xfc,
+  0x62, 0xea, 0x43, 0xd9, 0x0c, 0x00, 0x2a, 0xad, 0x49, 0x45, 0xeb, 0x91,
+  0xa6, 0x55, 0x21, 0x40, 0x90, 0x4b, 0x7a, 0x4a, 0x64, 0x7c, 0x92, 0x97,
+  0xc9, 0x94, 0xe0, 0xae, 0x78, 0x40, 0x5d, 0xf0, 0x9d, 0x45, 0x7e, 0x69,
+  0x40, 0x15, 0x64, 0x76, 0x5b, 0x7a, 0xb2, 0x49, 0x65, 0xae, 0x56, 0xc1,
+  0x11, 0x99, 0x66, 0xdd, 0xd1, 0x91, 0x38, 0x02, 0xf6, 0x15, 0x84, 0xe2,
+  0x46, 0x16, 0x8a, 0x80, 0xf5, 0x11, 0xcc, 0x4c, 0x56, 0xf0, 0xa2, 0x63,
+  0x8d, 0x41, 0x37, 0x6c, 0x82, 0x10, 0xc0, 0x28, 0x51, 0x8a, 0x30, 0x26,
+  0x91, 0x6e, 0xda, 0xae, 0xaf, 0xc8, 0x5d, 0x8b, 0x00, 0x09, 0xbe, 0x17,
+  0xef, 0x77, 0x44, 0xa5, 0x0c, 0x8c, 0x98, 0x84, 0x9f, 0x2c, 0x94, 0x68,
+  0x3c, 0x71, 0xdd, 0x4f, 0xfd, 0xa9, 0x50, 0x75, 0x31, 0x7d, 0x07, 0xd7,
+  0xb5, 0x8e, 0xfc, 0xe6, 0xaf, 0xa4, 0xec, 0xce, 0xe2, 0x9b, 0x77, 0xae,
+  0xb2, 0xe6, 0x2c, 0xf3, 0xad, 0x64, 0x8b, 0x56, 0x25, 0x60, 0x27, 0x26,
+  0xa5, 0xfb, 0x68, 0x66, 0xd6, 0xa9, 0xa1, 0x19, 0xa3, 0x51, 0x95, 0x95,
+  0xcf, 0xb2, 0x95, 0x6c, 0x81, 0x1a, 0x2d, 0x31, 0x4e, 0x2a, 0x6d, 0x40,
+  0xd0, 0xaf, 0x0b, 0xd8, 0x1a, 0x24, 0xb6, 0x97, 0x58, 0xb0, 0x3a, 0xc0,
+  0x10, 0xaa, 0x75, 0x22, 0x13, 0x88, 0x00, 0x0c, 0x48, 0xe5, 0x36, 0x81,
+  0x28, 0x61, 0x42, 0x01, 0xc1, 0x30, 0xaf, 0x72, 0xf6, 0xc9, 0xa6, 0x80,
+  0x82, 0xf6, 0xa2, 0x89, 0x4c, 0x96, 0xbb, 0x67, 0x40, 0x34, 0xad, 0x82,
+  0x01, 0x87, 0x24, 0x03, 0x07, 0x21, 0x1a, 0x94, 0xb5, 0xce, 0x8a, 0xc2,
+  0x23, 0x20, 0x48, 0x68, 0x32, 0x19, 0x85, 0xf4, 0x51, 0x0a, 0x45, 0xaf,
+  0x84, 0xb8, 0x40, 0x01, 0x83, 0x60, 0xdb, 0x81, 0xd0, 0xd3, 0x1c, 0xae,
+  0x22, 0x30, 0x51, 0x50, 0xc0, 0x99, 0x17, 0x26, 0x97, 0xe0, 0x25, 0x61,
+  0x7e, 0xf4, 0x98, 0x8b, 0x52, 0xa3, 0x92, 0xbe, 0x5a, 0x5b, 0x37, 0xda,
+  0xb3, 0x66, 0x68, 0xbc, 0xf3, 0x2d, 0x37, 0x7b, 0xff, 0xda, 0x7b, 0xe7,
+  0xeb, 0x26, 0x38, 0x7e, 0x69, 0x2e, 0x1f, 0xf8, 0x5d, 0x31, 0x5f, 0xf7,
+  0xe7, 0x49, 0x3a, 0x74, 0x5e, 0x9b, 0xc7, 0x52, 0x98, 0x2e, 0x1f, 0x18,
+  0xa1, 0x0f, 0x9c, 0x2c, 0x71, 0x7c, 0xd7, 0x75, 0xd9, 0x36, 0x98, 0xba,
+  0xd7, 0x14, 0xe6, 0xfa, 0x47, 0x1c, 0x66, 0xaf, 0x95, 0x90, 0xb6, 0x6f,
+  0xf4, 0xbd, 0x7d, 0x0f, 0xaa, 0xe8, 0x3a, 0xaf, 0x38, 0xda, 0xce, 0xe8,
+  0xc2, 0xb2, 0xf3, 0xda, 0x76, 0xa5, 0x43, 0xd3, 0x0a, 0x21, 0x88, 0x34,
+  0x44, 0x02, 0x6b, 0x90, 0x15, 0x29, 0x49, 0x76, 0xcc, 0xfa, 0x60, 0x68,
+  0x89, 0xfd, 0x7d, 0xe3, 0xad, 0xa0, 0xad, 0x85, 0xa2, 0x2b, 0xb2, 0x52,
+  0x34, 0x42, 0x78, 0xb9, 0x36, 0x4d, 0x02, 0x90, 0xce, 0xc3, 0x95, 0xbd,
+  0x79, 0x75, 0x9e, 0x1e, 0xdd, 0x94, 0x72, 0xd3, 0x61, 0xca, 0x81, 0xe4,
+  0xd9, 0x76, 0xd6, 0xd9, 0xd1, 0xe4, 0x68, 0xd1, 0xfa, 0x34, 0x49, 0x6b,
+  0xfd, 0xae, 0x5a, 0x94, 0xd6, 0x36, 0x94, 0xf4, 0x20, 0x06, 0x40, 0x3e,
+  0x6e, 0x75, 0x85, 0x8c, 0xad, 0xaa, 0xc4, 0x26, 0x33, 0xd5, 0x9b, 0x3f,
+  0x53, 0x02, 0xe9, 0xb2, 0xc2, 0xac, 0x05, 0xa5, 0x8c, 0x39, 0x4b, 0x8a,
+  0x93, 0xd2, 0xc2, 0xdf, 0x24, 0x92, 0x2c, 0x12, 0x5e, 0x35, 0x76, 0xfb,
+  0xa1, 0xe5, 0x6c, 0x2e, 0x96, 0xba, 0x0e, 0xbb, 0x1d, 0xde, 0x00, 0x13,
+  0x56, 0x88, 0x42, 0x18, 0x5e, 0x02, 0x11, 0xba, 0xa3, 0x38, 0x65, 0xca,
+  0xab, 0x60, 0xe1, 0x71, 0xd3, 0x84, 0x15, 0x2a, 0xae, 0x80, 0xc3, 0x8c,
+  0x82, 0x74, 0x87, 0xe4, 0xb2, 0x13, 0xe7, 0xe1, 0xeb, 0x7e, 0x92, 0xca,
+  0x7c, 0x06, 0x11, 0xe9, 0x95, 0x57, 0x54, 0xfc, 0xaf, 0x63, 0xbf, 0x13,
+  0xa1, 0x86, 0xee, 0x6e, 0x14, 0xe0, 0x8a, 0xb2, 0x0c, 0x9d, 0xd3, 0xed,
+  0x0c, 0xf8, 0x19, 0x6e, 0x31, 0x9f, 0x20, 0x02, 0x3d, 0xd0, 0xb7, 0x35,
+  0xfc, 0xf2, 0xef, 0x1c, 0xa8, 0x12, 0x69, 0x1a, 0x2f, 0xcf, 0x1f, 0xa8,
+  0xb8, 0x54, 0xb0, 0x69, 0x49, 0x31, 0x53, 0x8f, 0xc4, 0xe8, 0x01, 0xb1,
+  0x96, 0xd0, 0xd2, 0xc7, 0xd0, 0xda, 0xb1, 0x52, 0xb4, 0x00, 0x20, 0x36,
+  0xd5, 0x39, 0x45, 0x28, 0x88, 0xd6, 0xe0, 0x88, 0x0a, 0xfb, 0xa3, 0xa8,
+  0x25, 0x11, 0x64, 0x0a, 0x5c, 0x14, 0x70, 0x0e, 0x21, 0x1a, 0x94, 0xbd,
+  0xd6, 0x07, 0x41, 0x21, 0x8b, 0x83, 0x7b, 0xea, 0xef, 0x7a, 0x54, 0x65,
+  0x74, 0x27, 0x96, 0x97, 0x40, 0x00, 0x0c, 0xe3, 0x95, 0x89, 0xfa, 0x9f,
+  0xd6, 0xf5, 0xff, 0x77, 0x8e, 0xb5, 0x0e, 0x1d, 0x1e, 0xbd, 0xe4, 0x4a,
+  0x72, 0xf2, 0xde, 0x7d, 0x69, 0x1d, 0x71, 0x96, 0xa7, 0xa7, 0xa7, 0xbc,
+  0x45, 0xd9, 0xd6, 0x13, 0xc5, 0x53, 0x98, 0x92, 0x64, 0x98, 0xcf, 0x7f,
+  0xc6, 0xef, 0x1d, 0x11, 0x96, 0xa0, 0xbf, 0x0f, 0xa3, 0x5b, 0xd1, 0x1d,
+  0xa9, 0xa1, 0xf9, 0x5e, 0xda, 0xfb, 0x8f, 0x30, 0xb9, 0x73, 0x94, 0xdd,
+  0x9a, 0x31, 0x1d, 0x6d, 0x3a, 0x13, 0x30, 0x91, 0x5a, 0x7f, 0x9d, 0xf5,
+  0x64, 0x76, 0x24, 0x2a, 0x03, 0xb0, 0xb1, 0x6b, 0x25, 0x3c, 0x5f, 0x40,
+  0x98, 0x26, 0x87, 0x17, 0xb4, 0x31, 0xf8, 0x94, 0xfc, 0xc9, 0xca, 0x59,
+  0x33, 0x52, 0x61, 0x86, 0xe2, 0xa9, 0xb6, 0xd2, 0x14, 0x52, 0x97, 0xaa,
+  0x16, 0x4e, 0x2d, 0x5e, 0xf9, 0x5a, 0x83, 0x64, 0x01, 0xb0, 0x82, 0x43,
+  0x46, 0x82, 0x63, 0x78, 0xf6, 0xe7, 0x81, 0x0e, 0x4b, 0x31, 0xd6, 0x74,
+  0xe8, 0xf9, 0xf2, 0x6e, 0x69, 0x9f, 0x2a, 0xd8, 0x0a, 0x43, 0x34, 0x39,
+  0xc3, 0x4b, 0xba, 0x98, 0x48, 0x42, 0x49, 0x43, 0x3b, 0x98, 0x47, 0x6e,
+  0x91, 0x32, 0x92, 0x45, 0x24, 0xe4, 0xbd, 0xa6, 0xb9, 0x65, 0x57, 0x51,
+  0x3b, 0x2a, 0x4e, 0xc7, 0x0a, 0x79, 0x34, 0x15, 0xc7, 0xb1, 0xb7, 0x9b,
+  0x9a, 0x14, 0x47, 0x70, 0x4c, 0x5a, 0x18, 0xe6, 0x80, 0x18, 0xc0, 0x92,
+  0xa1, 0x45, 0x5e, 0xec, 0x87, 0x49, 0xf8, 0x16, 0x2d, 0xc8, 0x04, 0x62,
+  0xe6, 0x76, 0xd3, 0x5c, 0x36, 0x4d, 0x26, 0xe4, 0xa3, 0x6a, 0xde, 0x69,
+  0xfc, 0x97, 0xd4, 0x79, 0xe1, 0xca, 0xaa, 0xc3, 0xd6, 0xb3, 0x30, 0xce,
+  0xb8, 0xd5, 0x07, 0xbe, 0x82, 0x7a, 0x60, 0x20, 0x35, 0xc8, 0x6e, 0x1d,
+  0x8e, 0xd7, 0xdf, 0x5d, 0xb5, 0x12, 0x95, 0x70, 0x65, 0xe5, 0x29, 0x30,
+  0x87, 0xe2, 0xef, 0x50, 0x02, 0xeb, 0xc6, 0xf0, 0xde, 0x0b, 0x3f, 0xdc,
+  0x69, 0x08, 0x6e, 0xc0, 0x00, 0x84, 0xb2, 0x56, 0x75, 0xdf, 0xa6, 0xb5,
+  0x80, 0xf1, 0x3d, 0xdc, 0x7c, 0x79, 0x2b, 0x6a, 0x80, 0x07, 0xb8, 0x2a,
+  0x09, 0xcb, 0x63, 0x28, 0xda, 0x00, 0x14, 0xc2, 0x00, 0x38, 0x21, 0x1a,
+  0x94, 0xa5, 0xd2, 0x0a, 0x81, 0x18, 0x02, 0xaa, 0x26, 0x95, 0x88, 0x38,
+  0x5d, 0xcd, 0x00, 0x00, 0x07, 0xff, 0xc4, 0xcd, 0x3b, 0x27, 0x8e, 0xcd,
+  0x49, 0x30, 0x0f, 0x1e, 0x16, 0xd3, 0x6f, 0x12, 0xe1, 0xfe, 0x25, 0xb9,
+  0xbe, 0xe7, 0x40, 0x11, 0x2b, 0xed, 0xa5, 0xdb, 0x73, 0xd3, 0x99, 0xbe,
+  0x0d, 0xa3, 0x7d, 0x71, 0x4a, 0xd1, 0x13, 0x5e, 0x5c, 0xa5, 0x66, 0xfa,
+  0xf6, 0x96, 0x9e, 0xe0, 0x6f, 0x7d, 0xa5, 0x8e, 0xf9, 0x2f, 0xb5, 0x18,
+  0x12, 0x41, 0xa4, 0x3e, 0xea, 0xc5, 0xa5, 0xe1, 0x74, 0x7f, 0xd5, 0xfc,
+  0x07, 0xd0, 0x24, 0x57, 0x5c, 0x67, 0x57, 0xcd, 0x98, 0xb6, 0xc3, 0xd2,
+  0x67, 0x65, 0x40, 0x59, 0x5c, 0x19, 0x8a, 0x79, 0x77, 0x5c, 0xfb, 0x1e,
+  0x37, 0x37, 0xeb, 0x5f, 0xb2, 0x96, 0x34, 0x9f, 0x65, 0xff, 0xd0, 0xef,
+  0x8a, 0x21, 0x4a, 0x5c, 0x75, 0x49, 0x59, 0x76, 0xeb, 0x0d, 0x37, 0xe3,
+  0xdd, 0xef, 0x15, 0x6c, 0x80, 0xe8, 0xd3, 0x61, 0xc5, 0xae, 0x0f, 0xdf,
+  0xd0, 0x41, 0x8d, 0x39, 0xbe, 0x9c, 0x2d, 0x7d, 0x9b, 0x2f, 0x1d, 0x0a,
+  0xd3, 0xde, 0x9d, 0xb9, 0xcb, 0x7e, 0x99, 0x5e, 0x3c, 0xd1, 0x1b, 0x6d,
+  0x6a, 0x9c, 0xd6, 0x07, 0xe7, 0x63, 0x45, 0xf0, 0x54, 0x76, 0x2b, 0xbc,
+  0x65, 0x4e, 0x96, 0x2d, 0x43, 0x34, 0x57, 0x9e, 0x75, 0x99, 0x24, 0xbd,
+  0xef, 0x38, 0xef, 0x42, 0x1f, 0x6e, 0xac, 0x2d, 0xda, 0x6f, 0x9e, 0xf0,
+  0xbd, 0xd7, 0x8c, 0x31, 0xe1, 0x7c, 0x26, 0x01, 0x33, 0x6b, 0x61, 0xaa,
+  0x80, 0x62, 0xd0, 0x12, 0x54, 0xb8, 0xb5, 0x4a, 0x6c, 0x1c, 0x3c, 0x9f,
+  0x00, 0xd3, 0x28, 0x08, 0x36, 0x45, 0xc4, 0xe2, 0x10, 0xf8, 0xa3, 0xe8,
+  0xfc, 0x43, 0x23, 0xd3, 0x7e, 0xd9, 0x79, 0x31, 0xc7, 0x8d, 0xad, 0xb6,
+  0x72, 0xaa, 0xc9, 0x69, 0xf2, 0xaa, 0xc7, 0x84, 0x93, 0xdb, 0xb3, 0x89,
+  0x56, 0xc4, 0x37, 0xf1, 0xf1, 0xe4, 0xd0, 0x0b, 0xcd, 0x6e, 0x28, 0x0a,
+  0x67, 0x5b, 0x89, 0x90, 0xee, 0xbc, 0x5e, 0x5a, 0xdc, 0x93, 0x17, 0x28,
+  0x58, 0x0b, 0x1c, 0xd9, 0x94, 0xdc, 0x89, 0x38, 0x22, 0x02, 0x14, 0x1c,
+  0xdb, 0xcb, 0xc9, 0x09, 0x41, 0x10, 0xbf, 0x5d, 0x95, 0xa7, 0xe7, 0x65,
+  0x92, 0xd6, 0xa0, 0x54, 0xaa, 0x96, 0x2d, 0x60, 0x10, 0xb0, 0x00, 0x1a,
+  0xe0, 0x70, 0x21, 0x1a, 0x94, 0xd5, 0xce, 0x87, 0x03, 0x40, 0x91, 0x94,
+  0x82, 0x61, 0x5d, 0x16, 0x9a, 0x15, 0x42, 0x5d, 0xdd, 0xad, 0x00, 0x4c,
+  0x0b, 0x12, 0x78, 0xb6, 0x26, 0xe7, 0xca, 0xe3, 0xd0, 0x26, 0x3c, 0xbf,
+  0xa9, 0x34, 0x37, 0xe4, 0x33, 0xec, 0x89, 0x4d, 0x3b, 0x62, 0x34, 0xf7,
+  0x25, 0xe6, 0xde, 0xc2, 0xd2, 0x1d, 0x93, 0xf3, 0x51, 0xcf, 0x95, 0x6c,
+  0x9e, 0x9b, 0xfd, 0x5f, 0x83, 0x6b, 0x6e, 0x28, 0x6e, 0x38, 0xf8, 0x95,
+  0x7f, 0x72, 0xa9, 0xe6, 0xbe, 0xdd, 0xf1, 0x9c, 0x77, 0xd8, 0x19, 0x00,
+  0x3c, 0xbd, 0x4b, 0x65, 0x50, 0x7e, 0xd3, 0x3c, 0x6b, 0x9e, 0x67, 0xe2,
+  0xde, 0x74, 0xe6, 0x9d, 0x6d, 0xe7, 0x3e, 0x21, 0x54, 0x5e, 0x9f, 0xa3,
+  0x64, 0x6c, 0xaf, 0xe1, 0xdb, 0x0b, 0xb5, 0xd9, 0x39, 0xc4, 0x9f, 0x29,
+  0xdb, 0xf2, 0xdb, 0xe9, 0x38, 0xc8, 0xec, 0x4e, 0xd2, 0x65, 0xd2, 0xd3,
+  0x51, 0xe0, 0x9d, 0x24, 0xc8, 0xc6, 0x44, 0x02, 0x29, 0x8e, 0x38, 0xef,
+  0xb5, 0x86, 0x1c, 0xf0, 0x9e, 0x7a, 0x64, 0x00, 0x91, 0x23, 0xf6, 0x90,
+  0xaa, 0x7c, 0x96, 0xf6, 0x31, 0x45, 0xeb, 0x1d, 0x4b, 0xfb, 0xe9, 0x66,
+  0x3c, 0xcf, 0x42, 0xa6, 0x97, 0x39, 0x9b, 0x58, 0x79, 0x64, 0x1d, 0x03,
+  0x29, 0x5b, 0x68, 0xed, 0x13, 0x24, 0x1a, 0xa5, 0x7c, 0x3b, 0xcc, 0xa3,
+  0xa3, 0x08, 0x53, 0x73, 0x6b, 0x28, 0x46, 0xb7, 0x92, 0x49, 0x30, 0x61,
+  0x68, 0x27, 0x34, 0x95, 0x49, 0x19, 0xca, 0x36, 0x88, 0xa5, 0x10, 0x21,
+  0x38, 0xe0, 0x58, 0xc7, 0xf6, 0x9b, 0xe4, 0x75, 0x66, 0xa5, 0x1d, 0xaf,
+  0x8f, 0xaa, 0x08, 0xec, 0xbe, 0x0f, 0x0d, 0x3c, 0xbf, 0xef, 0x6e, 0x80,
+  0x99, 0xa7, 0x30, 0x90, 0xc2, 0x20, 0x10, 0xc1, 0x68, 0xde, 0xa2, 0xb8,
+  0xb3, 0xc0, 0x69, 0xd3, 0x5d, 0x0b, 0x02, 0x80, 0x73, 0xbb, 0xee, 0xe3,
+  0xed, 0x75, 0xe2, 0x6d, 0x54, 0x72, 0x7f, 0x57, 0xce, 0x2f, 0x36, 0xf3,
+  0x3d, 0x52, 0xa5, 0x4a, 0xf1, 0x63, 0x33, 0x97, 0xd3, 0x3a, 0x7b, 0x7f,
+  0xd8, 0xbe, 0xf3, 0x79, 0xe2, 0x79, 0x77, 0x1a, 0xd7, 0x68, 0x6d, 0xf6,
+  0x62, 0x9b, 0x85, 0x4b, 0x33, 0x2c, 0x02, 0x50, 0x2f, 0x84, 0xd0, 0x56,
+  0xbc, 0x26, 0xa5, 0xf0, 0x92, 0x6d, 0x74, 0x78, 0xd9, 0x65, 0x19, 0x26,
+  0xb8, 0xa4, 0x7b, 0xad, 0x19, 0x10, 0x98, 0x04, 0xc0, 0x6a, 0x15, 0x43,
+  0xf7, 0x00, 0xa2, 0x2e, 0x70, 0x9c, 0xa8, 0x0b, 0xd2, 0x0b, 0x95, 0x21,
+  0x14, 0x4b, 0xc1, 0x48, 0x5f, 0x92, 0x7a, 0x42, 0x72, 0xa2, 0xb0, 0x7a,
+  0x26, 0x02, 0x91, 0x80, 0x19, 0x7e, 0x66, 0x40, 0x38, 0x21, 0x1a, 0x94,
+  0xb5, 0xce, 0x86, 0xc3, 0x42, 0x0b, 0x48, 0x17, 0x22, 0xa8, 0x09, 0x7c,
+  0x2e, 0x68, 0x00, 0x00, 0x63, 0x8c, 0x98, 0x2a, 0xd4, 0xce, 0x6f, 0xe8,
+  0xe0, 0xe8, 0xc1, 0x83, 0x40, 0x99, 0xbe, 0xb3, 0x7f, 0xe2, 0xba, 0xc4,
+  0x11, 0x7f, 0xce, 0xd8, 0x74, 0x77, 0xb4, 0xec, 0x8c, 0xcd, 0x98, 0xe2,
+  0x5e, 0x5e, 0x1f, 0x51, 0xf0, 0x75, 0x6e, 0xa8, 0xd2, 0xae, 0x48, 0x26,
+  0xbb, 0x57, 0x9d, 0x01, 0x31, 0xfd, 0x67, 0x2e, 0xfd, 0x27, 0xcc, 0x9c,
+  0x5d, 0xfb, 0x33, 0x27, 0x16, 0xe9, 0x9c, 0x82, 0x1f, 0xb0, 0x70, 0x4c,
+  0xa5, 0x93, 0x45, 0xe1, 0x56, 0x96, 0xb8, 0x3b, 0xf3, 0x64, 0x7f, 0x9b,
+  0xd2, 0xfd, 0x67, 0x30, 0xec, 0x0f, 0x8a, 0xb9, 0x4e, 0x7a, 0x8e, 0x7b,
+  0xc1, 0x73, 0xf9, 0xee, 0x4f, 0x5d, 0x82, 0x87, 0xab, 0xa9, 0xd7, 0x31,
+  0xf2, 0x52, 0x94, 0x29, 0x97, 0x1b, 0xa8, 0x02, 0x39, 0x96, 0xab, 0xa7,
+  0x50, 0xf0, 0x7f, 0x47, 0x87, 0x9f, 0xa8, 0x7f, 0x34, 0xb2, 0xc2, 0x0f,
+  0x17, 0xf8, 0x4a, 0x15, 0xb4, 0x63, 0x42, 0xce, 0xee, 0xa6, 0x21, 0xcb,
+  0x21, 0x4f, 0x2d, 0xac, 0xa6, 0xc8, 0x86, 0x56, 0x67, 0xe1, 0x70, 0xf1,
+  0xb2, 0x8f, 0xf5, 0xfe, 0x6c, 0x70, 0xf0, 0xed, 0xcc, 0xee, 0x25, 0x9a,
+  0x58, 0x7b, 0xc2, 0xd7, 0x81, 0x37, 0x31, 0x1f, 0xe3, 0xba, 0x51, 0x71,
+  0xb5, 0x14, 0x96, 0xdf, 0x56, 0x61, 0x27, 0xb0, 0x0a, 0xb2, 0x8d, 0xb7,
+  0xc9, 0x74, 0x5b, 0xa5, 0x49, 0x2e, 0xa6, 0xbf, 0x7c, 0x23, 0xe8, 0xa7,
+  0xf6, 0xa5, 0xe3, 0xb6, 0x01, 0x2f, 0x68, 0x83, 0x81, 0x04, 0x48, 0x21,
+  0x08, 0x08, 0x60, 0xb2, 0x0c, 0x92, 0xa0, 0x7b, 0x5b, 0x8e, 0x28, 0xab,
+  0x18, 0x20, 0x2a, 0xb0, 0x70, 0xd7, 0x13, 0x7e, 0x39, 0xbe, 0x3b, 0x06,
+  0x6f, 0xea, 0xe3, 0xf7, 0x40, 0xf8, 0xcd, 0x93, 0x14, 0x1c, 0x33, 0xf7,
+  0x0a, 0xd1, 0xa4, 0xd6, 0xce, 0x14, 0x6c, 0xb3, 0xb6, 0xd5, 0xec, 0x06,
+  0x25, 0x9c, 0x22, 0x26, 0x28, 0x81, 0x69, 0xfd, 0x46, 0x8c, 0x05, 0xaf,
+  0x5e, 0x81, 0xfc, 0xaa, 0xeb, 0x28, 0x81, 0x18, 0x38, 0x3c, 0x34, 0xc3,
+  0xf9, 0xec, 0x02, 0xd8, 0x80, 0x80, 0x58, 0x05, 0x4a, 0xa5, 0x02, 0xd0,
+  0x4c, 0x94, 0x12, 0x56, 0xb6, 0x82, 0x20, 0x01, 0x1b, 0x40, 0x42, 0x41,
+  0x41, 0x23, 0xf8, 0xbc, 0x90, 0x94, 0x6e, 0x3f, 0x7f, 0xac, 0x6d, 0xa3,
+  0xc0, 0x5a, 0x79, 0x15, 0x0e, 0x21, 0x1a, 0x94, 0xdd, 0xce, 0x89, 0x63,
+  0xa1, 0xa1, 0x98, 0x24, 0x62, 0x4b, 0x56, 0x70, 0xb6, 0x46, 0xec, 0xd5,
+  0xf4, 0xe9, 0xab, 0x9b, 0xa0, 0x93, 0x00, 0x1c, 0x1e, 0xb3, 0xe9, 0xb6,
+  0xe8, 0xb7, 0x47, 0xe7, 0xfc, 0x4b, 0x0e, 0xfa, 0x85, 0x06, 0x1a, 0x80,
+  0x3a, 0xff, 0xf1, 0x7f, 0x6b, 0x58, 0x88, 0xcc, 0xe0, 0x71, 0x41, 0xe1,
+  0x59, 0x7a, 0x88, 0x27, 0xa7, 0xf6, 0x06, 0x06, 0x0a, 0x7a, 0xc2, 0xf7,
+  0x6c, 0x26, 0x50, 0x07, 0xa3, 0xfd, 0x93, 0xa7, 0xff, 0x3d, 0xf8, 0x5f,
+  0x1f, 0xee, 0x8c, 0xd1, 0xcc, 0xf9, 0xff, 0x24, 0x69, 0xb9, 0x19, 0x64,
+  0x89, 0x44, 0x49, 0x01, 0xc0, 0x51, 0xf9, 0x7f, 0x5c, 0xf2, 0x3c, 0xc2,
+  0x8a, 0x1f, 0xe6, 0x59, 0x73, 0xab, 0xb9, 0xb2, 0x1b, 0xab, 0xae, 0x7b,
+  0xc7, 0xe5, 0x61, 0xb3, 0xbd, 0x40, 0xd2, 0x94, 0x98, 0x9e, 0x85, 0x65,
+  0x47, 0xe8, 0xa4, 0x37, 0x7f, 0x60, 0xe5, 0xfa, 0x0d, 0x5a, 0x76, 0xbc,
+  0xd6, 0x08, 0xb9, 0x4b, 0xae, 0x36, 0x2d, 0xfa, 0xea, 0x80, 0xe8, 0x8e,
+  0xe3, 0xf4, 0x0d, 0x6f, 0xfe, 0xdd, 0x6d, 0xfe, 0x5f, 0xff, 0xb2, 0xa8,
+  0xbf, 0x4d, 0x68, 0x87, 0x8e, 0x03, 0xa6, 0xfb, 0x53, 0xc5, 0xfa, 0xa3,
+  0xa0, 0xaa, 0x50, 0x7e, 0xdb, 0xe0, 0x7a, 0x5b, 0xf6, 0x78, 0x66, 0xc7,
+  0xa4, 0x35, 0x3e, 0x85, 0xcd, 0x59, 0x87, 0xe3, 0xb3, 0x5c, 0x16, 0x1d,
+  0xa5, 0xeb, 0x1b, 0xaf, 0x6b, 0xb9, 0x96, 0x46, 0xd9, 0xb1, 0xe8, 0x1a,
+  0x9f, 0xd2, 0xed, 0xdb, 0x6d, 0x7a, 0xa3, 0x64, 0xc5, 0xdc, 0x23, 0xa4,
+  0x6b, 0xd3, 0x52, 0x2b, 0x50, 0xe4, 0xc8, 0xc1, 0x92, 0x59, 0x0e, 0x5c,
+  0x21, 0xcd, 0xab, 0x2d, 0x52, 0x3d, 0x2c, 0xaf, 0xec, 0xb5, 0x88, 0xdd,
+  0xce, 0x32, 0xf7, 0x83, 0x1f, 0xd2, 0x8a, 0xd8, 0xf2, 0x23, 0xbc, 0xd8,
+  0xcf, 0x8c, 0xbc, 0xa9, 0x81, 0xd1, 0x34, 0x97, 0xd7, 0xe2, 0xd5, 0x02,
+  0x7a, 0xdf, 0x59, 0x3f, 0xa1, 0x81, 0x0b, 0xfd, 0x66, 0x9a, 0xce, 0x79,
+  0x29, 0xf2, 0x6b, 0xae, 0xcd, 0x18, 0x35, 0xb7, 0xdc, 0xff, 0xaa, 0x8e,
+  0x61, 0x20, 0x17, 0x1c, 0xbe, 0x40, 0x06, 0x82, 0x48, 0xbc, 0xe1, 0xb3,
+  0xd3, 0x42, 0x03, 0xab, 0x7d, 0x26, 0xbd, 0x7e, 0xe3, 0x69, 0xe7, 0xdb,
+  0x56, 0x74, 0x00, 0x04, 0xc5, 0xb1, 0x88, 0x63, 0x41, 0x88, 0x80, 0x62,
+  0x10, 0x40, 0x98, 0x23, 0x73, 0x52, 0x98, 0x81, 0x6f, 0x2b, 0xf6, 0x58,
+  0x05, 0x8d, 0x83, 0x4a, 0xf6, 0xed, 0x85, 0x19, 0xd3, 0x4e, 0xa8, 0xdb,
+  0xd2, 0xfe, 0x97, 0xce, 0x8c, 0x11, 0xa3, 0xe1, 0x0e, 0x11, 0x20, 0x28,
+  0xb9, 0xe3, 0xf9, 0x1d, 0x22, 0x2d, 0xc0, 0x0c, 0xa1, 0x76, 0xfc, 0x42,
+  0x58, 0x72, 0x86, 0xd2, 0x22, 0xf0, 0xc4, 0x7f, 0x6f, 0xda, 0x02, 0x5c,
+  0xfe, 0x66, 0x33, 0x70, 0x89, 0xd7, 0x88, 0x19, 0xcb, 0x2c, 0x95, 0x44,
+  0xf2, 0x01, 0x4c, 0xbe, 0xe5, 0xc5, 0x45, 0x36, 0xac, 0x28, 0x5f, 0xef,
+  0x83, 0x2f, 0xcf, 0xaf, 0xef, 0x7f, 0x15, 0xe5, 0x70, 0xe0, 0x21, 0x1a,
+  0x94, 0xb5, 0xaa, 0x95, 0x05, 0x41, 0x8b, 0x80, 0x52, 0xf0, 0xc5, 0x54,
+  0x79, 0x4e, 0x32, 0x5d, 0x9a, 0x18, 0x68, 0xa1, 0xac, 0x9d, 0xa0, 0x12,
+  0x0a, 0x05, 0x69, 0xe0, 0xae, 0xa7, 0x54, 0x26, 0x97, 0xcd, 0xfa, 0xed,
+  0x8d, 0x69, 0x9c, 0x91, 0xc9, 0x1a, 0x6d, 0xcf, 0x68, 0xa2, 0x8f, 0x95,
+  0x0b, 0xfb, 0xee, 0x4b, 0xb6, 0xfc, 0x8b, 0x5b, 0xab, 0x5e, 0x9c, 0x5d,
+  0xa5, 0x3c, 0x3a, 0xab, 0x4e, 0x5e, 0xb7, 0x9e, 0xd3, 0xb0, 0x3c, 0x1a,
+  0xfc, 0x50, 0xee, 0x58, 0xef, 0x09, 0x24, 0x0e, 0xa7, 0x3f, 0x2a, 0xe3,
+  0xbd, 0x69, 0x19, 0xa5, 0xc1, 0x36, 0x65, 0xad, 0x2e, 0xcd, 0xf0, 0xba,
+  0x93, 0xed, 0xcf, 0x39, 0xc3, 0xb9, 0x72, 0xe5, 0xff, 0x75, 0x81, 0xd0,
+  0x36, 0x6b, 0xfc, 0x8f, 0x16, 0x46, 0xa5, 0xa8, 0xd6, 0xfa, 0x7c, 0xc5,
+  0x30, 0x5a, 0xcc, 0x93, 0x4c, 0xa6, 0x98, 0x81, 0xb4, 0x90, 0xc3, 0xc3,
+  0x4e, 0x59, 0x6d, 0xbe, 0xb3, 0xa6, 0xf3, 0x14, 0x28, 0x4c, 0x40, 0xce,
+  0xd7, 0xff, 0xb7, 0x3f, 0x70, 0xc5, 0xb6, 0x65, 0x5e, 0xbd, 0x9a, 0x40,
+  0xc5, 0xa1, 0xeb, 0x82, 0x4b, 0x63, 0x75, 0x01, 0xe0, 0x9a, 0xd4, 0xa8,
+  0xac, 0x45, 0xad, 0xd9, 0x96, 0xa8, 0xec, 0xd5, 0x4b, 0xa7, 0x3f, 0x50,
+  0xa0, 0xa4, 0xcb, 0xd2, 0x60, 0x90, 0x7f, 0xfb, 0x4f, 0x90, 0xd9, 0x70,
+  0x6b, 0xd6, 0x59, 0x53, 0xdc, 0x6b, 0x0c, 0x4a, 0x46, 0x8c, 0x22, 0x37,
+  0x88, 0x4a, 0xd9, 0xe8, 0xe8, 0x81, 0x10, 0x14, 0x48, 0x02, 0x13, 0x80,
+  0x11, 0xe1, 0x80, 0xf6, 0x35, 0xf8, 0xb3, 0x17, 0x41, 0xac, 0x9d, 0xa0,
+  0x12, 0x0a, 0x05, 0x68, 0xfc, 0xbc, 0x4a, 0x8f, 0xbc, 0xfe, 0xf5, 0x1b,
+  0xe2, 0x7a, 0x3f, 0xcf, 0x16, 0xfb, 0x23, 0xb3, 0x49, 0x88, 0x73, 0x28,
+  0x3a, 0x31, 0xef, 0x09, 0x80, 0xbd, 0xe3, 0xc2, 0xbb, 0xc4, 0xd6, 0xee,
+  0x3b, 0xeb, 0x4e, 0x7b, 0x6e, 0x18, 0x33, 0x20, 0x19, 0x04, 0xa5, 0xde,
+  0x69, 0x90, 0xd0, 0x38, 0x3c, 0x4d, 0x55, 0x4e, 0x3a, 0x64, 0xcf, 0xae,
+  0xd7, 0xda, 0x20, 0x51, 0xdb, 0xf6, 0x38, 0x4f, 0xe7, 0x0b, 0xf2, 0x09,
+  0x5c, 0x0f, 0x08, 0x00, 0x8d, 0xd4, 0x9d, 0xae, 0x56, 0xe9, 0x2b, 0x20,
+  0x06, 0x46, 0x00, 0x31, 0xc0, 0x34, 0x32, 0xa5, 0x61, 0x7a, 0x45, 0x93,
+  0x10, 0x03, 0x07, 0x21, 0x1a, 0x94, 0xc5, 0xba, 0x96, 0x83, 0x13, 0x90,
+  0x84, 0xa2, 0x23, 0x77, 0x6b, 0x36, 0xc9, 0x1e, 0x65, 0xaa, 0xec, 0x81,
+  0x9c, 0x06, 0x04, 0x9a, 0x02, 0x43, 0x3f, 0xf0, 0x7d, 0x07, 0xff, 0x2b,
+  0xa5, 0x3e, 0xb7, 0x6c, 0x7d, 0xbf, 0xb5, 0x2d, 0x24, 0x5d, 0xc1, 0xbe,
+  0x2b, 0x50, 0x67, 0xd4, 0xfb, 0x26, 0x48, 0xf3, 0xb5, 0xbe, 0xeb, 0x99,
+  0x81, 0xa5, 0xe7, 0xf1, 0xcc, 0xe1, 0xfa, 0x97, 0x4d, 0x56, 0xc3, 0xc9,
+  0x7e, 0xed, 0xff, 0x94, 0x61, 0x1e, 0x71, 0xfe, 0x8f, 0xb2, 0xb9, 0x34,
+  0xde, 0x22, 0x3e, 0x7a, 0xf7, 0x53, 0xeb, 0x3b, 0xcf, 0xc2, 0xfb, 0xf7,
+  0x5a, 0xf2, 0xaa, 0x85, 0xdd, 0x79, 0x35, 0x5b, 0xaa, 0x7f, 0xba, 0x7a,
+  0xcd, 0x56, 0x37, 0x7d, 0x77, 0x65, 0xc6, 0xe3, 0x6b, 0x3b, 0x6e, 0x26,
+  0x33, 0x24, 0xa1, 0x4b, 0xb9, 0xda, 0xcd, 0xa6, 0x14, 0x62, 0x97, 0x1e,
+  0xe6, 0x5b, 0x90, 0x58, 0xb5, 0x6b, 0x12, 0x66, 0xd8, 0xac, 0x54, 0x70,
+  0x66, 0x5a, 0xd9, 0x49, 0x6a, 0xd5, 0x49, 0x90, 0x86, 0x64, 0xa8, 0xad,
+  0x17, 0xc0, 0x82, 0x93, 0x7c, 0xad, 0x89, 0xa8, 0x41, 0x68, 0x6b, 0xa3,
+  0xb7, 0xc1, 0x4d, 0x26, 0x6b, 0x2f, 0xbd, 0x54, 0xdb, 0x77, 0x48, 0x9c,
+  0xe6, 0x42, 0x5f, 0xa9, 0xb2, 0x9a, 0xe2, 0x25, 0x58, 0x46, 0xab, 0x94,
+  0x45, 0x7d, 0x51, 0xb4, 0x14, 0x48, 0x89, 0xd6, 0x65, 0x34, 0xe1, 0x9d,
+  0xa5, 0x25, 0xca, 0x28, 0x99, 0x55, 0x9e, 0xa5, 0x8b, 0x98, 0xa4, 0x9d,
+  0x8b, 0xd1, 0x8a, 0x33, 0x9a, 0x11, 0x41, 0x72, 0xd1, 0x04, 0xd5, 0xbc,
+  0xd2, 0x44, 0x17, 0x04, 0x6a, 0xaa, 0xed, 0x4a, 0x54, 0x5b, 0x81, 0xae,
+  0x0e, 0x00, 0x01, 0x6c, 0xad, 0x58, 0x0e, 0x78, 0x00, 0xa3, 0x9c, 0x2a,
+  0x22, 0xbf, 0x4e, 0xb8, 0xda, 0x94, 0x2d, 0xba, 0x4e, 0x22, 0xd3, 0x87,
+  0xfc, 0x6e, 0x53, 0x91, 0xe1, 0x54, 0x7c, 0x4e, 0xe6, 0xcc, 0xdc, 0x46,
+  0x38, 0xfe, 0x04, 0xb0, 0x16, 0xcb, 0xfe, 0x45, 0x1d, 0xca, 0xec, 0x9b,
+  0xea, 0xff, 0x38, 0xe6, 0xc9, 0x81, 0xa9, 0x51, 0x22, 0xa1, 0xfd, 0x9f,
+  0xab, 0xe3, 0xe6, 0xd4, 0x73, 0x77, 0x9b, 0xbe, 0x7f, 0x0d, 0xed, 0xbf,
+  0x8f, 0x4d, 0xa8, 0x00, 0xf7, 0x87, 0xe3, 0xe3, 0xcf, 0x40, 0x58, 0x00,
+  0x31, 0x39, 0xcb, 0x26, 0x67, 0x7d, 0xcb, 0x26, 0x68, 0x7d, 0x11, 0x1d,
+  0xd4, 0x55, 0x52, 0xbb, 0x1e, 0x17, 0xd6, 0x09, 0xda, 0x1f, 0x8c, 0x90,
+  0xb7, 0xd7, 0xa7, 0x6a, 0xd9, 0x71, 0x91, 0x5e, 0x9e, 0x2b, 0xf1, 0x9c,
+  0xa1, 0x4c, 0x79, 0x40, 0x3c, 0x5a, 0x8b, 0x54, 0xb1, 0x40, 0x00, 0xed,
+  0x9b, 0x2a, 0x81, 0x9e, 0x9a, 0xd3, 0x4a, 0x0c, 0xf0, 0x0e, 0x21, 0x1a,
+  0x8e, 0xca, 0x1f, 0xff, 0x6f, 0xff, 0x35, 0x65, 0xa8, 0x41, 0x90, 0xa4,
+  0x71, 0x18, 0x0a, 0x55, 0x33, 0x42, 0xa5, 0xde, 0xac, 0xd7, 0x15, 0xaa,
+  0xb0, 0x00, 0xd6, 0x48, 0x86, 0x7a, 0x05, 0x7b, 0x20, 0xbb, 0x8d, 0xca,
+  0xe5, 0x8d, 0x6b, 0x12, 0x90, 0x08, 0x09, 0x94, 0xb8, 0xf4, 0x3e, 0x71,
+  0x6e, 0x23, 0xd5, 0x39, 0x8b, 0x79, 0x76, 0xcc, 0x64, 0x1e, 0x6b, 0xaa,
+  0xf4, 0xaa, 0xe6, 0x20, 0xa6, 0x8f, 0x95, 0x65, 0x0e, 0xcd, 0x1c, 0x68,
+  0x09, 0xab, 0x27, 0x2a, 0x9b, 0x5e, 0x69, 0xb8, 0xe6, 0x5c, 0xb7, 0x2e,
+  0x80, 0x87, 0x4f, 0xe3, 0x5c, 0x71, 0xda, 0xa4, 0xa8, 0xcb, 0xc3, 0xd6,
+  0x71, 0x5b, 0xc8, 0x65, 0x2a, 0x80, 0x2d, 0xbb, 0xdd, 0x5d, 0x44, 0x52,
+  0x19, 0x9c, 0xe3, 0x76, 0x4d, 0x5d, 0x71, 0x04, 0x20, 0x5a, 0xd3, 0x2d,
+  0x08, 0x44, 0x8a, 0x48, 0xb5, 0x26, 0x37, 0x11, 0x6c, 0x2a, 0x1c, 0x16,
+  0x35, 0x51, 0x73, 0x82, 0x90, 0x44, 0x63, 0x84, 0x40, 0x6d, 0x88, 0x52,
+  0x20, 0xb6, 0x13, 0x82, 0x4c, 0x0b, 0x82, 0x15, 0x28, 0x25, 0x3d, 0x3a,
+  0xa5, 0xab, 0xcd, 0x68, 0x6e, 0xa6, 0xef, 0x55, 0xb3, 0x36, 0x78, 0x30,
+  0x2a, 0xbc, 0x75, 0xf6, 0x91, 0x27, 0x3d, 0x6c, 0xd5, 0xcb, 0x2c, 0x55,
+  0x6a, 0xdd, 0xd6, 0x4d, 0xdf, 0x14, 0xf2, 0x37, 0x95, 0x4f, 0x6f, 0x1c,
+  0xfc, 0x8e, 0x48, 0x84, 0xfb, 0x38, 0xd7, 0x9f, 0xce, 0x1c, 0x40, 0x5f,
+  0xeb, 0xab, 0xe4, 0xe4, 0xff, 0xce, 0xee, 0xe6, 0xe6, 0xd3, 0xfc, 0x9c,
+  0xe7, 0x5a, 0xe8, 0x6c, 0x87, 0x21, 0xb3, 0x59, 0xc1, 0x8a, 0xd5, 0x92,
+  0x16, 0x48, 0x59, 0xcc, 0xf5, 0xd5, 0x97, 0x75, 0x0f, 0xff, 0x74, 0x39,
+  0x70, 0x11, 0xfa, 0x84, 0xc5, 0xae, 0x8a, 0xc5, 0x22, 0x00, 0x85, 0xe3,
+  0x74, 0x56, 0xc2, 0xd9, 0x49, 0xad, 0x34, 0x71, 0xad, 0x52, 0xe2, 0x22,
+  0x0b, 0x65, 0x2f, 0x7f, 0x82, 0x07, 0x46, 0x71, 0x55, 0x38, 0x0e, 0xcd,
+  0xeb, 0x08, 0x3f, 0x3a, 0x46, 0x38, 0x18, 0x26, 0x44, 0x7d, 0x73, 0xfa,
+  0x1c, 0x3d, 0x23, 0x05, 0x81, 0xc8, 0x54, 0x9e, 0xf3, 0x8e, 0x0e, 0x0e,
+  0xa3, 0x20, 0xa0, 0xff, 0x43, 0x86, 0xf8, 0x8d, 0xcf, 0x60, 0x83, 0xb3,
+  0x62, 0x55, 0x89, 0xf5, 0xe3, 0x1e, 0x2f, 0xe0, 0x12, 0x95, 0x29, 0x7c,
+  0x51, 0x72, 0x0c, 0xe8, 0x44, 0x53, 0x9f, 0x7b, 0x54, 0x81, 0x7e, 0x7d,
+  0x08, 0xa7, 0xbf, 0x75, 0x37, 0x34, 0xbb, 0x63, 0xaf, 0x6f, 0x51, 0x6c,
+  0x3c, 0x5d, 0xc1, 0xfe, 0x2a, 0x25, 0x2a, 0x7f, 0x6c, 0x3d, 0x5d, 0xa3,
+  0x1b, 0x10, 0x4c, 0xa5, 0xa8, 0xbd, 0xcf, 0x4e, 0x7f, 0xc3, 0x3d, 0xaf,
+  0x2f, 0xfa, 0x05, 0x11, 0x00, 0xcd, 0x4c, 0xc0, 0x90, 0xa1, 0x79, 0xa7,
+  0x11, 0x41, 0x69, 0xa7, 0x6e, 0xba, 0x13, 0x00, 0x0b, 0x6c, 0x50, 0x4a,
+  0xd5, 0x1b, 0x60, 0x2c, 0x1c, 0x21, 0x1a, 0x8d, 0x08, 0x5f, 0x34, 0x07,
+  0xfd, 0x37, 0x54, 0x61, 0x0c, 0x40, 0x6c, 0xae, 0x0a, 0x85, 0x57, 0x34,
+  0x1a, 0x5c, 0xb1, 0xe6, 0xda, 0x5e, 0x11, 0x5a, 0x5b, 0x2a, 0x42, 0xe0,
+  0x70, 0x7f, 0x7b, 0x4e, 0xb3, 0x87, 0xbd, 0x7e, 0xee, 0xc1, 0x96, 0x62,
+  0x7f, 0x55, 0x58, 0x5d, 0x6d, 0xec, 0x0f, 0x3e, 0xd9, 0x1f, 0x0e, 0x6b,
+  0x0f, 0x18, 0xe5, 0xad, 0xae, 0x36, 0x3a, 0xb8, 0xbc, 0xf5, 0xcb, 0x5b,
+  0xbc, 0x1b, 0x89, 0x29, 0xa3, 0xf8, 0xc5, 0x18, 0x6b, 0xd4, 0x9d, 0x93,
+  0x5e, 0xda, 0xa2, 0xae, 0xe6, 0x5d, 0xf3, 0x76, 0x46, 0xb6, 0x1b, 0x27,
+  0x2b, 0x75, 0x7a, 0x04, 0xa3, 0x23, 0x14, 0xa4, 0xa3, 0x78, 0xb7, 0x23,
+  0xf9, 0xd3, 0xb3, 0x3c, 0xab, 0x60, 0x87, 0x9f, 0xfd, 0x5a, 0x26, 0xae,
+  0xb3, 0x6f, 0xb9, 0x10, 0xb8, 0x09, 0xa8, 0x54, 0x13, 0xc5, 0x5a, 0x62,
+  0xb4, 0x57, 0x02, 0x6c, 0x32, 0x0b, 0x52, 0x32, 0x8c, 0x34, 0x29, 0x68,
+  0x30, 0x5f, 0x7f, 0x52, 0xd2, 0x9d, 0xe3, 0x64, 0x9b, 0x65, 0x85, 0x74,
+  0x16, 0x42, 0xe1, 0x70, 0x09, 0x27, 0x38, 0x6d, 0x9d, 0xb6, 0x42, 0x86,
+  0x86, 0xeb, 0x31, 0xc6, 0x72, 0xd4, 0x68, 0x0f, 0x25, 0x86, 0x9a, 0xb9,
+  0x68, 0xb0, 0x16, 0x44, 0x46, 0xe6, 0x63, 0x73, 0x4f, 0x1c, 0x15, 0xd9,
+  0x8b, 0xb6, 0xff, 0x07, 0xce, 0xad, 0x0e, 0x36, 0xc4, 0xc3, 0x4f, 0xa5,
+  0x5b, 0xbe, 0x8e, 0x36, 0xe8, 0x40, 0xe2, 0x1e, 0xf1, 0x39, 0xf2, 0x14,
+  0x20, 0xf8, 0xcf, 0x86, 0x81, 0x53, 0xcc, 0x80, 0x0a, 0x3a, 0xca, 0x71,
+  0x06, 0x09, 0xa1, 0x09, 0x15, 0x2a, 0x9f, 0x40, 0x92, 0x01, 0xaa, 0x26,
+  0xab, 0x9d, 0x25, 0xe8, 0xbd, 0x85, 0xdc, 0x4f, 0xf3, 0x8e, 0x41, 0xef,
+  0x23, 0x02, 0x96, 0xba, 0xcc, 0xa4, 0x9f, 0x9f, 0x3a, 0xfb, 0x58, 0xdc,
+  0x3d, 0x58, 0xff, 0xcc, 0x3e, 0x5c, 0x60, 0x4e, 0xc2, 0xff, 0x84, 0xe5,
+  0x5e, 0xa4, 0x8d, 0x3f, 0xbb, 0x66, 0x6b, 0xc0, 0x20, 0xda, 0x5e, 0x4c,
+  0xd3, 0xcf, 0xb2, 0x74, 0x13, 0x04, 0xa7, 0x31, 0xc9, 0x7c, 0x30, 0xd3,
+  0x0a, 0x14, 0xa5, 0xb1, 0x92, 0x3c, 0x25, 0x2e, 0x98, 0x6d, 0x14, 0x5e,
+  0x3c, 0x3e, 0x40, 0x16, 0x02, 0x60, 0x1c, 0x21, 0x1a, 0x8f, 0x80, 0x1e,
+  0x0c, 0x00, 0x5f, 0x3f, 0x67, 0xa7, 0xb0, 0xc6, 0x24, 0x9c, 0x31, 0x2a,
+  0xa8, 0x52, 0x4e, 0x92, 0xd1, 0xab, 0x34, 0x12, 0x85, 0x96, 0xc9, 0x92,
+  0xb0, 0x3c, 0xe3, 0x9e, 0x35, 0xfe, 0x94, 0xf9, 0xee, 0x6e, 0x81, 0x3a,
+  0xbb, 0xbb, 0x99, 0x31, 0x3c, 0x3b, 0x8c, 0x1a, 0xf2, 0xd1, 0xb3, 0x89,
+  0x55, 0xca, 0x8d, 0x82, 0x7d, 0xc2, 0x32, 0xe3, 0xab, 0x8c, 0xd7, 0x4a,
+  0xb7, 0x64, 0x60, 0xae, 0x89, 0x7e, 0xad, 0xb8, 0xe4, 0x15, 0xee, 0xd7,
+  0x9e, 0x3f, 0x39, 0xc0, 0x41, 0x63, 0xb5, 0xb9, 0x29, 0x72, 0xb4, 0xdb,
+  0x0a, 0xfb, 0xd4, 0xe8, 0xe4, 0xc8, 0x55, 0xb7, 0xdc, 0x16, 0x67, 0x09,
+  0x1d, 0x3b, 0x7c, 0x43, 0x5b, 0x30, 0x62, 0x47, 0x19, 0x49, 0x11, 0x87,
+  0x24, 0x8d, 0x68, 0x83, 0xb4, 0x48, 0x92, 0x05, 0xd5, 0x71, 0xee, 0xb1,
+  0xab, 0xc7, 0xcf, 0xb6, 0x71, 0xa2, 0xbb, 0xe2, 0x45, 0xa6, 0x12, 0x6c,
+  0x09, 0xe4, 0x8a, 0x89, 0xa5, 0x8b, 0x75, 0x49, 0x28, 0x8c, 0x40, 0x60,
+  0x9a, 0x2b, 0x68, 0x16, 0x50, 0xd1, 0x4f, 0x45, 0xe1, 0x01, 0x18, 0x9b,
+  0xe1, 0x8e, 0x50, 0xf5, 0x28, 0xe5, 0x46, 0x1a, 0x17, 0xbb, 0xf1, 0xb2,
+  0xf3, 0x8d, 0xa8, 0x4c, 0x4a, 0xc5, 0xa1, 0x40, 0x51, 0x72, 0x1b, 0xeb,
+  0x6a, 0xf4, 0x83, 0xc7, 0x04, 0x81, 0x3f, 0x6d, 0xa4, 0xb0, 0x90, 0xc2,
+  0xc5, 0x20, 0x02, 0x58, 0xe4, 0xbd, 0x7d, 0x6f, 0x65, 0x92, 0xe1, 0xe7,
+  0x7c, 0x2e, 0x82, 0x74, 0x4d, 0xf5, 0xcb, 0x9e, 0x62, 0xd3, 0x89, 0xe7,
+  0x06, 0x54, 0x2c, 0x8c, 0x08, 0x5c, 0x89, 0x99, 0x30, 0xa7, 0xff, 0x33,
+  0xf3, 0xe6, 0x81, 0x74, 0x97, 0x99, 0xab, 0x70, 0x63, 0xd0, 0x73, 0x1f,
+  0xec, 0x90, 0x12, 0x9c, 0xdf, 0x8a, 0xf4, 0x9a, 0x33, 0xce, 0xbe, 0x99,
+  0x25, 0xcc, 0xea, 0x77, 0xb6, 0x14, 0x13, 0xec, 0x72, 0xc4, 0x60, 0x89,
+  0x30, 0x42, 0xe7, 0x82, 0x56, 0x30, 0x19, 0x83, 0x15, 0xf6, 0xde, 0x55,
+  0x20, 0xf5, 0x7b, 0xc0, 0xa2, 0xee, 0x1e, 0x29, 0xdb, 0xe7, 0x87, 0x90,
+  0x7c, 0xd8, 0xab, 0xec, 0x99, 0x74, 0x04, 0xbe, 0x2c, 0x08, 0x95, 0x10,
+  0x00, 0x98, 0xe9, 0x18, 0x1c, 0x63, 0x2e, 0x06, 0x17, 0x43, 0xbe, 0xad,
+  0x1e, 0x7b, 0xaf, 0x50, 0xa0, 0xc0, 0xae, 0x96, 0xbd, 0x48, 0x32, 0xb3,
+  0xc1, 0x5c, 0xb9, 0x22, 0x38, 0xa0, 0xac, 0x11, 0x53, 0xa1, 0xe2, 0x02,
+  0xc5, 0x6b, 0x36, 0xaa, 0xac, 0x60, 0xd2, 0x45, 0x19, 0x57, 0x3e, 0x97,
+  0x32, 0x47, 0xda, 0x3e, 0x74, 0x11, 0x7c, 0x28, 0xbe, 0xc5, 0x38, 0xe9,
+  0xd4, 0x9f, 0xf9, 0xb5, 0x51, 0x5c, 0x1b, 0x6a, 0x9b, 0x05, 0x65, 0x97,
+  0x56, 0x1d, 0xf1, 0xf6, 0x53, 0x58, 0x77, 0x2c, 0xa2, 0x50, 0xa9, 0xf0,
+  0xa3, 0x87, 0x3f, 0x5e, 0xdc, 0x49, 0x81, 0xc0, 0x21, 0x2a, 0x8e, 0x80,
+  0x04, 0x00, 0x00, 0x1f, 0x3b, 0x66, 0xa7, 0x30, 0x90, 0x63, 0x15, 0xc1,
+  0x32, 0x18, 0x0e, 0x11, 0xad, 0x34, 0xb2, 0x50, 0xb8, 0x6c, 0x0e, 0x47,
+  0x9b, 0xfe, 0x37, 0xc5, 0x6d, 0x00, 0x13, 0x18, 0x31, 0xc4, 0xb8, 0x2c,
+  0x23, 0x5d, 0x6d, 0x08, 0x6f, 0x65, 0xc2, 0xd1, 0xf0, 0x79, 0x08, 0xfc,
+  0xed, 0xbc, 0x7c, 0x75, 0x82, 0x89, 0x4c, 0x6c, 0x8d, 0x70, 0x09, 0xe7,
+  0xe4, 0x91, 0x58, 0x97, 0x9b, 0x63, 0x69, 0xbb, 0x52, 0xda, 0x0e, 0xc8,
+  0xfa, 0x5c, 0xee, 0x19, 0x2c, 0x0a, 0x75, 0xc1, 0xc3, 0x00, 0x44, 0x64,
+  0x6c, 0xa9, 0x78, 0x4a, 0x1b, 0xe4, 0xc4, 0xaf, 0x23, 0x0c, 0xb2, 0xba,
+  0x84, 0x46, 0xe3, 0x08, 0x97, 0x86, 0x55, 0x10, 0x76, 0xc4, 0xc6, 0xb1,
+  0x44, 0x31, 0xbe, 0x8b, 0x44, 0xab, 0xd7, 0x8a, 0x95, 0xb6, 0x45, 0x45,
+  0x29, 0x08, 0x56, 0xee, 0x08, 0x05, 0x6f, 0x90, 0x88, 0x04, 0xe2, 0x03,
+  0x3c, 0x3d, 0xdc, 0x48, 0x48, 0x12, 0x0a, 0xb3, 0x6b, 0x44, 0x92, 0xd4,
+  0x9c, 0xce, 0x98, 0x27, 0xe5, 0xa3, 0x90, 0x31, 0xdb, 0x78, 0xd2, 0x20,
+  0x6b, 0xf8, 0xb6, 0x5f, 0x5f, 0x6a, 0x66, 0xd0, 0xb5, 0x00, 0x13, 0x97,
+  0x08, 0x33, 0x0d, 0x0a, 0x2c, 0x2a, 0x98, 0x65, 0x2d, 0x13, 0x5b, 0x4c,
+  0xd7, 0x06, 0x6a, 0xac, 0x1a, 0x27, 0x98, 0xd0, 0xa3, 0xd8, 0x5c, 0xb6,
+  0x0e, 0x1c, 0xf4, 0xb7, 0x17, 0xfb, 0xa5, 0x12, 0x8e, 0x07, 0x3b, 0x3e,
+  0x52, 0x06, 0x3d, 0x2e, 0x04, 0x1e, 0x9a, 0xbc, 0x23, 0x1c, 0x27, 0xae,
+  0x76, 0x2d, 0x64, 0x0c, 0xf9, 0x75, 0x0e, 0x99, 0xa7, 0xae, 0x91, 0x6d,
+  0xbc, 0x56, 0xfa, 0x50, 0xe3, 0x59, 0x8b, 0x43, 0x46, 0xb9, 0x7b, 0x59,
+  0xf5, 0x35, 0x2f, 0xa8, 0x3b, 0xad, 0x37, 0x74, 0x3a, 0x25, 0x34, 0xf7,
+  0x5a, 0x14, 0xf6, 0xb2, 0xed, 0xb1, 0x2c, 0x1a, 0xee, 0x29, 0xc8, 0xfc,
+  0x9a, 0x4d, 0x65, 0xd5, 0x29, 0x57, 0x00, 0x67, 0x87, 0x32, 0x6f, 0xf6,
+  0x4a, 0xda, 0x82, 0x5c, 0x6c, 0xe9, 0x13, 0xe8, 0x2f, 0x1d, 0x25, 0xca,
+  0x9a, 0xc9, 0x0d, 0x59, 0x85, 0xe6, 0xa6, 0x94, 0xb2, 0xa6, 0x99, 0x8a,
+  0x2c, 0xab, 0x68, 0xc3, 0xb5, 0x3c, 0x6b, 0xab, 0xcc, 0xe9, 0xf4, 0x29,
+  0x28, 0xe0, 0xca, 0xab, 0x5f, 0x3a, 0x6f, 0xa5, 0xce, 0xd5, 0xf9, 0xca,
+  0x3c, 0xbc, 0x99, 0xb1, 0x7d, 0x35, 0xd6, 0x1b, 0x08, 0x3c, 0xd2, 0x82,
+  0xc3, 0x20, 0xe6, 0x0b, 0x0a, 0xda, 0xf0, 0xda, 0xfa, 0xc6, 0xa4, 0x2c,
+  0x03, 0x68, 0x0a, 0x0b, 0x0b, 0x01, 0x49, 0xd2, 0x4b, 0xc1, 0xa2, 0x71,
+  0x5a, 0xd8, 0x00, 0x70, 0x21, 0x4c, 0x36, 0x80, 0x0c, 0xa0, 0xdf, 0xbf,
+  0xff, 0xca, 0xd5, 0x44, 0x36, 0xa3, 0x33, 0xb7, 0x21, 0x22, 0x16, 0x06,
+  0xec, 0x24, 0x22, 0xc0, 0x87, 0x9d, 0x7c, 0x18, 0x7f, 0x75, 0x4b, 0xe8,
+  0xfa, 0xc7, 0x5f, 0xdd, 0x2a, 0x69, 0xa1, 0xe0, 0x2e, 0xc0, 0x7c, 0xef,
+  0x70, 0x5c, 0xfc, 0xaa, 0xb7, 0xa2, 0x70, 0x32, 0xfe, 0xfd, 0x90, 0x3c,
+  0xb9, 0x10, 0x82, 0x54, 0xb1, 0xcc, 0x76, 0x4d, 0xb9, 0xc1, 0xe6, 0x28,
+  0x67, 0xc6, 0x86, 0x95, 0x3b, 0xff, 0xdc, 0x91, 0x43, 0x9e, 0x4d, 0x3e,
+  0xb3, 0xe2, 0x17, 0x2e, 0x3b, 0x2b, 0xc9, 0x2e, 0x0c, 0xe8, 0x6b, 0xcf,
+  0xef, 0x2a, 0x4d, 0x9c, 0x41, 0x56, 0xda, 0xab, 0xe0, 0x5f, 0xdd, 0x99,
+  0x47, 0xaa, 0x70, 0xef, 0x62, 0x9d, 0x88, 0x9f, 0x27, 0x91, 0xd2, 0xdd,
+  0x98, 0xb4, 0x7a, 0x38, 0xf1, 0x59, 0x4e, 0x3b, 0xdf, 0xea, 0xcc, 0x7b,
+  0x0d, 0x1c, 0x90, 0x02, 0xfb, 0xfb, 0x37, 0x43, 0xfd, 0x55, 0x28, 0x02,
+  0xbf, 0x0e, 0x45, 0x0b, 0x27, 0xd4, 0x79, 0xc0, 0xa6, 0x4f, 0xed, 0x6c,
+  0xb7, 0x43, 0x5e, 0x60, 0x68, 0x1f, 0x3a, 0x5a, 0xc1, 0xf9, 0xd8, 0xb5,
+  0x9c, 0x7d, 0x35, 0xb5, 0xbb, 0x7b, 0x17, 0xec, 0x4e, 0xdf, 0x86, 0xf1,
+  0x5f, 0x45, 0x43, 0x5a, 0xbb, 0x4b, 0xa1, 0x13, 0xd1, 0x60, 0x60, 0xde,
+  0x7a, 0xcd, 0xc0, 0xda, 0xbc, 0xa4, 0x36, 0xc4, 0x11, 0x86, 0xea, 0x78,
+  0x4c, 0x67, 0x8f, 0x2e, 0x35, 0x11, 0xc4, 0x88, 0x82, 0x64, 0xa4, 0x22,
+  0xd9, 0xc9, 0x9a, 0x67, 0x73, 0xa5, 0x26, 0xf5, 0x3b, 0x26, 0xb5, 0x24,
+  0x1f, 0x6f, 0x64, 0xa3, 0xb8, 0x50, 0x98, 0x25, 0xef, 0x0e, 0xba, 0x05,
+  0x10, 0xcb, 0x54, 0x90, 0x8c, 0x07, 0x66, 0x9b, 0x11, 0x21, 0x84, 0x96,
+  0x3c, 0xbe, 0x3f, 0xa0, 0x4e, 0x17, 0xae, 0xbf, 0xb5, 0x15, 0x7a, 0x5f,
+  0x6a, 0xab, 0x34, 0xd4, 0x73, 0x00, 0x71, 0xcc, 0xf0, 0x65, 0x44, 0xfb,
+  0xb3, 0x87, 0x69, 0xee, 0x8f, 0x48, 0x8b, 0x32, 0x42, 0x29, 0xd1, 0x35,
+  0x75, 0xaa, 0xa7, 0xbb, 0x42, 0xc2, 0xe7, 0x4c, 0x47, 0x72, 0x83, 0xea,
+  0x36, 0xcd, 0x08, 0x98, 0xaa, 0x70, 0x77, 0xfa, 0xce, 0xce, 0xa9, 0xc7,
+  0x70, 0x56, 0x57, 0xfc, 0xbb, 0x88, 0x92, 0x57, 0x42, 0xba, 0xaa, 0x32,
+  0x5c, 0x7e, 0x9d, 0xb8, 0x28, 0xa1, 0x3a, 0x3e, 0x22, 0xb2, 0x15, 0xad,
+  0x05, 0x22, 0xbe, 0x5e, 0xfd, 0x5d, 0xea, 0xaf, 0x25, 0x6d, 0x0d, 0x9d,
+  0x31, 0xda, 0x77, 0xcc, 0x0e, 0xc0, 0x79, 0xc0, 0x0d, 0x53, 0x46, 0x15,
+  0x70, 0x78, 0x5d, 0x3b, 0x10, 0xd6, 0x54, 0x48, 0xb9, 0x21, 0x75, 0x1e,
+  0x79, 0xaf, 0x8a, 0x19, 0x3c, 0x0c, 0x33, 0x2c, 0xe5, 0x68, 0x1a, 0xe1,
+  0xd5, 0x43, 0x56, 0xbb, 0x4b, 0x5c, 0x19, 0x8a, 0xf0, 0x21, 0x7a, 0x8d,
+  0x88, 0x05, 0x3f, 0x41, 0xbf, 0x39, 0x68, 0x86, 0xa1, 0x46, 0x07, 0x3c,
+  0x19, 0x92, 0x2a, 0x14, 0xcb, 0xbb, 0xcd, 0x12, 0xba, 0x97, 0xd3, 0x91,
+  0xa8, 0x43, 0x59, 0x52, 0xb8, 0x3f, 0xf0, 0x3a, 0x03, 0x58, 0xe8, 0x5f,
+  0xd4, 0x2f, 0xbc, 0x3c, 0x47, 0x0f, 0x92, 0xf3, 0x2f, 0x37, 0xe1, 0xfa,
+  0xeb, 0x44, 0xd2, 0xd2, 0x2e, 0x99, 0x57, 0x67, 0x49, 0xbb, 0xc7, 0xd5,
+  0x2b, 0xf4, 0x8d, 0xb0, 0x92, 0xd6, 0x1c, 0x09, 0x8a, 0x45, 0x3a, 0xf6,
+  0x6e, 0x60, 0xd6, 0xef, 0xce, 0xde, 0x67, 0x88, 0x3c, 0x21, 0xdb, 0x66,
+  0x00, 0x88, 0x5e, 0x89, 0x22, 0xeb, 0x64, 0x9c, 0x45, 0x99, 0x48, 0x1c,
+  0xa4, 0x02, 0x38, 0xef, 0x42, 0x00, 0x77, 0x1a, 0xd4, 0x97, 0xaf, 0x7b,
+  0x00, 0xf3, 0xe9, 0x3d, 0xde, 0x2b, 0x69, 0x02, 0xbf, 0x6a, 0xf0, 0x49,
+  0xb3, 0x5f, 0xbf, 0xc3, 0xf8, 0x0d, 0x20, 0x81, 0x09, 0x3f, 0x5b, 0x4a,
+  0x21, 0xa7, 0x55, 0x66, 0xbf, 0xaa, 0x73, 0x07, 0x3d, 0x20, 0xbd, 0xa9,
+  0xb5, 0xa6, 0xfb, 0x40, 0x3b, 0x8a, 0x70, 0xbc, 0x68, 0xbb, 0x45, 0x4b,
+  0xd8, 0xda, 0xb4, 0x93, 0xb8, 0xa1, 0x39, 0x9c, 0xe9, 0x44, 0x1b, 0xc0,
+  0x39, 0x24, 0x4d, 0x2d, 0x73, 0x0d, 0x5f, 0xc0, 0x13, 0xb6, 0xea, 0x3a,
+  0x04, 0x4a, 0x87, 0x14, 0x2c, 0xed, 0xcf, 0x1b, 0x92, 0x37, 0xc2, 0xa2,
+  0xe4, 0x16, 0xf6, 0x2e, 0x2f, 0x6b, 0x97, 0x28, 0x07, 0x70, 0x41, 0xe3,
+  0xdb, 0x9e, 0x09, 0x79, 0xb8, 0xad, 0x13, 0xe6, 0xae, 0x33, 0xf4, 0x54,
+  0xf7, 0x03, 0x89, 0x25, 0x42, 0x0f, 0xfa, 0x45, 0x3c, 0x5a, 0xf2, 0x6a,
+  0x9e, 0xf2, 0xd4, 0x0a, 0xf6, 0xd3, 0x11, 0x9e, 0x42, 0x0f, 0x62, 0xd2,
+  0xfe, 0x69, 0xfa, 0x7e, 0x57, 0xe4, 0x2f, 0x19, 0xc6, 0x3f, 0x5d, 0xab,
+  0xdf, 0x59, 0xf1, 0x99, 0x7b, 0xdd, 0x7b, 0x06, 0x5e, 0xbd, 0xf2, 0xbf,
+  0x1e, 0xa5, 0xef, 0x66, 0x5a, 0x95, 0xd4, 0x42, 0x01, 0x3b, 0x6c, 0xd5,
+  0x0d, 0x52, 0x4b, 0xa9, 0xb3, 0x78, 0x8f, 0x51, 0xa2, 0x19, 0xda, 0x78,
+  0xbd, 0x40, 0x41, 0xc4, 0xb7, 0xf1, 0xfe, 0xf4, 0x36, 0x53, 0xd7, 0x08,
+  0x88, 0xd1, 0xac, 0xf7, 0xc0, 0xde, 0x8d, 0xb2, 0x87, 0xc5, 0x80, 0x9c,
+  0x30, 0x5b, 0xe0, 0x25, 0xa1, 0x16, 0xa1, 0x31, 0x5a, 0x79, 0x2a, 0xbf,
+  0x7a, 0xa1, 0x42, 0x4c, 0x60, 0x14, 0x9a, 0xaf, 0x92, 0x2e, 0xa5, 0x4c,
+  0x33, 0xad, 0x8c, 0xe3, 0xa7, 0xc0, 0x77, 0x0f, 0x79, 0x11, 0x52, 0x60,
+  0xa4, 0x8a, 0x0b, 0x4d, 0x68, 0x0b, 0x3f, 0xce, 0xbf, 0x77, 0x5f, 0x13,
+  0x5f, 0x5c, 0x82, 0x44, 0xb9, 0x5a, 0x4e, 0x12, 0xb2, 0x29, 0x5a, 0xa0,
+  0x52, 0x83, 0x61, 0x60, 0xe0, 0x21, 0x1a, 0x8f, 0xf0, 0x00, 0x1f, 0x67,
+  0x8b, 0x39, 0x69, 0x86, 0xa9, 0x4d, 0xe5, 0x56, 0x84, 0x2b, 0x06, 0xf5,
+  0xa1, 0x11, 0x6b, 0x9e, 0xd5, 0x98, 0x27, 0x9a, 0x03, 0xb3, 0x0e, 0x88,
+  0x40, 0x79, 0x6e, 0xe2, 0xb9, 0x97, 0x79, 0x2d, 0x8e, 0x65, 0x6f, 0xd5,
+  0xf4, 0x03, 0xcc, 0x1b, 0x5a, 0xc6, 0xb6, 0x46, 0xa3, 0x5d, 0x4a, 0xcf,
+  0x63, 0x58, 0x8d, 0x77, 0x49, 0x35, 0xe8, 0x20, 0x97, 0x20, 0x88, 0xfb,
+  0xa6, 0x93, 0xdb, 0x20, 0x5e, 0xaa, 0x25, 0xcc, 0x69, 0x7d, 0x5a, 0x01,
+  0xd2, 0x1a, 0x0d, 0xc1, 0x14, 0xbf, 0x49, 0xf2, 0xb4, 0x43, 0x42, 0xbe,
+  0x31, 0x14, 0xc4, 0xa9, 0xab, 0x4c, 0xa0, 0x9f, 0x46, 0x8a, 0x9e, 0x33,
+  0x8d, 0x7b, 0xe9, 0xa7, 0x43, 0x8f, 0x27, 0x16, 0xfb, 0x61, 0xd7, 0x53,
+  0x8c, 0xeb, 0x1d, 0x0f, 0x28, 0xd6, 0xcf, 0x3e, 0x9c, 0xfc, 0xac, 0x9c,
+  0xf3, 0xad, 0xe2, 0x9b, 0x9b, 0xd9, 0xd7, 0xd6, 0x6b, 0x90, 0x57, 0x41,
+  0x4d, 0x32, 0x00, 0xbf, 0x3e, 0x42, 0x81, 0x56, 0x34, 0xb9, 0x79, 0x2b,
+  0xb8, 0xd0, 0xd7, 0xc1, 0xb2, 0x2e, 0xbb, 0xb6, 0x25, 0x83, 0xbd, 0xd8,
+  0x46, 0x17, 0x8d, 0xcc, 0xa0, 0xb0, 0x2a, 0x01, 0x41, 0x11, 0xa5, 0x11,
+  0x14, 0x4d, 0x72, 0x90, 0xc8, 0x04, 0xf4, 0x1e, 0xcf, 0x48, 0x12, 0xa0,
+  0x44, 0x48, 0x11, 0x5b, 0x4a, 0xe7, 0x83, 0xd2, 0x4b, 0x19, 0x76, 0x4e,
+  0x03, 0x57, 0x74, 0xd5, 0x98, 0x79, 0xd8, 0x19, 0x08, 0x2b, 0xfc, 0xba,
+  0x56, 0x3f, 0xab, 0x77, 0xa7, 0x7c, 0x19, 0xfe, 0x19, 0x28, 0x11, 0xbc,
+  0x47, 0x2d, 0xfc, 0xae, 0x81, 0x92, 0x9d, 0x33, 0xc9, 0xf7, 0xc6, 0x51,
+  0x9b, 0x34, 0xe7, 0x7c, 0x6a, 0xe4, 0xd9, 0xdf, 0x67, 0xc0, 0x01, 0xc5,
+  0xc4, 0x96, 0x0a, 0x91, 0xbe, 0xc7, 0xe4, 0xf4, 0x8e, 0xc7, 0x27, 0xc3,
+  0x59, 0x2b, 0xb0, 0x71, 0xfa, 0xbe, 0x65, 0x64, 0xbb, 0xcb, 0x35, 0x2d,
+  0x33, 0x1c, 0xd2, 0x26, 0xf4, 0xfa, 0xd5, 0x87, 0xa2, 0x51, 0x1a, 0xa9,
+  0xc7, 0xcc, 0x54, 0x83, 0xb1, 0x6c, 0xc4, 0x04, 0xab, 0x9f, 0x09, 0xfe,
+  0x86, 0x51, 0xbf, 0xe5, 0xd7, 0xdd, 0x1e, 0x14, 0xff, 0xaa, 0xd2, 0xd4,
+  0x58, 0x09, 0x84, 0x93, 0xf1, 0x6d, 0x73, 0x5f, 0xaa, 0x37, 0x12, 0xca,
+  0x16, 0x94, 0x00, 0x06, 0x7f, 0xdd, 0x0c, 0x6a, 0x0c, 0x12, 0xdb, 0xa6,
+  0xcc, 0xb5, 0xef, 0x34, 0x53, 0x92, 0x65, 0x79, 0xd7, 0x2d, 0x60, 0x0c,
+  0xf7, 0xcb, 0x0c, 0x20, 0x13, 0xe3, 0xaf, 0x6a, 0x9e, 0x4b, 0xcf, 0xdf,
+  0x96, 0xf2, 0xd4, 0x82, 0xbf, 0xe6, 0xfb, 0x88, 0x14, 0x46, 0xd5, 0x94,
+  0x7c, 0x9d, 0xd2, 0x11, 0x01, 0xc0, 0x21, 0x1a, 0x94, 0xed, 0xba, 0x98,
+  0xc3, 0x32, 0xa0, 0x84, 0xcb, 0xa4, 0x20, 0x2b, 0x2d, 0x1c, 0x19, 0xc1,
+  0x62, 0xe8, 0x26, 0xac, 0x09, 0xad, 0x4a, 0x0d, 0xd7, 0xad, 0xfe, 0xbf,
+  0x35, 0x8f, 0xb5, 0x47, 0x52, 0x79, 0x96, 0xad, 0xe3, 0xa6, 0xe2, 0x8f,
+  0x39, 0xfb, 0x6e, 0xc5, 0x72, 0xf6, 0x14, 0xd6, 0x92, 0x76, 0x9d, 0x85,
+  0xe6, 0xd9, 0xc4, 0xe7, 0x08, 0xdb, 0x75, 0xb7, 0x03, 0x4a, 0x35, 0x83,
+  0x4e, 0x5f, 0x18, 0xf8, 0x15, 0x0c, 0xbf, 0x95, 0x4e, 0x36, 0x7e, 0xaa,
+  0x61, 0x7b, 0xf3, 0xe7, 0xc6, 0xc7, 0x56, 0x36, 0x4c, 0xb9, 0xef, 0x77,
+  0xba, 0x99, 0x5c, 0x9e, 0xac, 0xf3, 0xbc, 0xa2, 0xfb, 0xd8, 0x59, 0x6c,
+  0x5a, 0x05, 0x52, 0xbf, 0x33, 0x48, 0xd5, 0xf3, 0x97, 0x86, 0xfd, 0xd7,
+  0x15, 0x5b, 0xe5, 0xe6, 0x04, 0x04, 0xf1, 0x8d, 0xa3, 0x10, 0x01, 0xba,
+  0xa7, 0xa3, 0x1b, 0x4b, 0x6e, 0xae, 0xaf, 0x2f, 0x05, 0x06, 0xdf, 0x2b,
+  0xd2, 0x1b, 0x89, 0xc9, 0x8e, 0xca, 0x19, 0x2a, 0xaa, 0xd2, 0x58, 0x77,
+  0x4b, 0x23, 0x5b, 0x1c, 0x61, 0x04, 0x7a, 0xe1, 0xbd, 0x47, 0x78, 0xcd,
+  0x9c, 0xf6, 0x55, 0xf5, 0xa6, 0xb6, 0x60, 0x92, 0x2e, 0x26, 0x08, 0x15,
+  0x83, 0x30, 0x16, 0x50, 0x21, 0x5c, 0x0f, 0xfd, 0x06, 0xd5, 0x08, 0x80,
+  0x34, 0x44, 0xd5, 0x56, 0x79, 0xaa, 0x82, 0x16, 0x57, 0x6b, 0x3e, 0x3c,
+  0xfa, 0xec, 0x60, 0xbf, 0x36, 0x39, 0x78, 0xc5, 0xdc, 0xdd, 0x23, 0xe9,
+  0x62, 0x75, 0x97, 0x74, 0x0d, 0xeb, 0xe3, 0x68, 0x98, 0x2d, 0xc2, 0x97,
+  0x5e, 0x69, 0x72, 0xd1, 0xb2, 0x33, 0xa7, 0x7c, 0x7a, 0x51, 0x95, 0x41,
+  0x39, 0x4d, 0xb1, 0x41, 0xc1, 0x04, 0x10, 0x38, 0x84, 0x04, 0x21, 0x25,
+  0xd5, 0x45, 0x94, 0xa0, 0x48, 0xff, 0x40, 0x17, 0xc8, 0x6a, 0x73, 0xfc,
+  0x5c, 0x75, 0x4b, 0x39, 0x79, 0x56, 0xab, 0xd4, 0x3d, 0x8b, 0xad, 0x58,
+  0xb1, 0xd9, 0x83, 0xf3, 0xcc, 0xe1, 0xb9, 0xb6, 0x45, 0xc5, 0xdd, 0x31,
+  0x63, 0xc7, 0x4c, 0x1b, 0x67, 0x91, 0x2e, 0x7e, 0x9f, 0xa9, 0x45, 0x23,
+  0xf1, 0x1c, 0x72, 0x9e, 0x23, 0x6a, 0xc3, 0x12, 0x88, 0x73, 0x23, 0x33,
+  0xe0, 0xd6, 0x08, 0x86, 0x40, 0x3a, 0x4e, 0x8e, 0xc4, 0xba, 0x35, 0x22,
+  0x72, 0x9a, 0x2a, 0x55, 0x50, 0x56, 0x06, 0x49, 0x21, 0x37, 0x2a, 0x25,
+  0xf5, 0x61, 0xc0, 0xfd, 0x9e, 0xed, 0x17, 0x5c, 0x51, 0x1c, 0x61, 0xc0,
+  0x21, 0x1a, 0x94, 0xcd, 0xa2, 0x89, 0x69, 0xa2, 0xb0, 0xd4, 0x48, 0x61,
+  0x28, 0x62, 0x32, 0xe4, 0x4a, 0x41, 0xa2, 0x25, 0x5d, 0xa0, 0xcb, 0x2c,
+  0x0c, 0x4a, 0x80, 0x27, 0x06, 0xc0, 0x47, 0x01, 0xcc, 0x55, 0x10, 0x7d,
+  0x4a, 0xea, 0x66, 0x80, 0xe9, 0xca, 0x81, 0x54, 0x89, 0x62, 0x91, 0x2a,
+  0x4c, 0x2f, 0x08, 0xaa, 0xe5, 0x05, 0x0e, 0x46, 0x53, 0x54, 0x57, 0x19,
+  0xb9, 0x65, 0x61, 0x64, 0xad, 0x61, 0x38, 0x70, 0xed, 0xed, 0x95, 0x1b,
+  0x47, 0xf0, 0xc8, 0xfb, 0x37, 0x3b, 0xa6, 0x0a, 0x94, 0x5d, 0x97, 0x34,
+  0x94, 0xc1, 0x84, 0xcf, 0x1a, 0xdd, 0xba, 0x8e, 0xb0, 0x04, 0x03, 0x4b,
+  0xd1, 0x4b, 0x77, 0x5f, 0xb6, 0x52, 0xbe, 0xe8, 0x90, 0xe0, 0x71, 0xbc,
+  0x81, 0x84, 0x68, 0x5f, 0x94, 0xfc, 0x47, 0xe7, 0x39, 0xb3, 0x5a, 0x66,
+  0x55, 0x2b, 0x66, 0xa3, 0xa5, 0x72, 0x7a, 0x12, 0xe4, 0x26, 0x5d, 0xa4,
+  0x4b, 0x34, 0xca, 0xaa, 0x37, 0xb4, 0xc2, 0x8c, 0xd0, 0x0b, 0x9c, 0x13,
+  0x4f, 0x8f, 0x9d, 0x1b, 0xd1, 0x3b, 0x37, 0x23, 0xc7, 0xb0, 0x55, 0x8c,
+  0x9e, 0x5e, 0xed, 0x81, 0xbe, 0x0a, 0xcd, 0x50, 0x79, 0x2d, 0x5a, 0xc0,
+  0xe0, 0xd7, 0x67, 0x16, 0x91, 0x93, 0x4b, 0x56, 0xa6, 0xb9, 0x80, 0x5e,
+  0x2a, 0xa0, 0x2c, 0x2b, 0x57, 0x0b, 0x4a, 0x51, 0x91, 0x2d, 0x53, 0x9e,
+  0x6c, 0x72, 0xf2, 0xbb, 0xde, 0x80, 0x10, 0x01, 0x60, 0x3b, 0x16, 0x3b,
+  0x55, 0x6b, 0xa8, 0xb2, 0x16, 0xea, 0x81, 0x3b, 0x91, 0x4d, 0x1c, 0x0f,
+  0x94, 0xe6, 0x81, 0xd2, 0x51, 0x91, 0x9c, 0x1a, 0xd5, 0x08, 0xd3, 0x76,
+  0x3d, 0x07, 0xbf, 0xab, 0x5c, 0xb6, 0x25, 0x23, 0x90, 0xf4, 0x23, 0x64,
+  0x8d, 0x10, 0x92, 0x17, 0x90, 0x23, 0x0b, 0x6b, 0x88, 0x6a, 0xbd, 0xf7,
+  0x0a, 0x46, 0x60, 0x99, 0xa7, 0xb1, 0x28, 0x48, 0x10, 0xa1, 0x2b, 0x7a,
+  0x4a, 0x96, 0xda, 0x55, 0x13, 0xae, 0x45, 0x16, 0x92, 0xea, 0xd3, 0x09,
+  0x72, 0xaf, 0x50, 0x68, 0xef, 0xf2, 0x58, 0x1d, 0xea, 0x60, 0xb0, 0x89,
+  0x8b, 0x5d, 0x63, 0x09, 0xe2, 0xd3, 0x7f, 0xb5, 0xf1, 0xf8, 0x79, 0x33,
+  0x7a, 0x23, 0x06, 0x2b, 0x2c, 0xbd, 0x47, 0x6d, 0x92, 0x35, 0x31, 0x74,
+  0x8a, 0x69, 0x74, 0x94, 0xc5, 0x69, 0x10, 0x44, 0xd1, 0x72, 0x35, 0x62,
+  0x96, 0x6d, 0x9b, 0x79, 0xff, 0xdb, 0xfd, 0xff, 0xdf, 0xfe, 0x6f, 0xcf,
+  0xf1, 0xfa, 0x3c, 0x33, 0xb8, 0x31, 0xc0, 0x21, 0x1a, 0x8f, 0x78, 0x4e,
+  0x0f, 0xcf, 0xff, 0x3b, 0x4f, 0xb0, 0xd1, 0x18, 0xc4, 0x21, 0x72, 0x19,
+  0x9e, 0x72, 0x65, 0xe5, 0x55, 0x92, 0xa2, 0xe5, 0x49, 0x5a, 0x6b, 0xad,
+  0xe0, 0x69, 0xd5, 0x85, 0x93, 0xfe, 0x0f, 0xf2, 0x73, 0x7f, 0xa2, 0xe9,
+  0x5f, 0xd0, 0xfb, 0xdf, 0xff, 0xfa, 0x29, 0xae, 0x47, 0x5b, 0x83, 0xfe,
+  0xbc, 0x32, 0xf7, 0xfa, 0x77, 0x96, 0xc7, 0xc9, 0xba, 0xb0, 0xa6, 0x96,
+  0x54, 0x6d, 0xae, 0x6a, 0xf5, 0x06, 0x6e, 0x05, 0xc5, 0x74, 0x5b, 0x88,
+  0xd5, 0xd8, 0xee, 0xf0, 0x75, 0xe0, 0xcc, 0x2e, 0x31, 0x35, 0x4d, 0x26,
+  0x5b, 0x50, 0xa0, 0xd6, 0xde, 0xed, 0x2c, 0xe5, 0x55, 0xee, 0xa2, 0x94,
+  0x69, 0x77, 0xb9, 0x82, 0xab, 0x64, 0x2c, 0xe6, 0xd2, 0xf2, 0x50, 0x07,
+  0x53, 0x14, 0x3c, 0xce, 0x0c, 0xad, 0x83, 0x09, 0xac, 0x93, 0xf7, 0xd7,
+  0xf5, 0x2f, 0x0f, 0x8f, 0x9b, 0xbe, 0xc3, 0xda, 0x91, 0x60, 0x14, 0x12,
+  0x98, 0xfe, 0x60, 0xbb, 0xc9, 0x28, 0x53, 0x5b, 0x57, 0xca, 0x30, 0xc7,
+  0x1d, 0xb9, 0x74, 0x23, 0x39, 0x78, 0x42, 0x00, 0xa7, 0xd3, 0x41, 0x6b,
+  0xfe, 0xf2, 0x8e, 0x77, 0x38, 0x50, 0x58, 0x10, 0xe5, 0xad, 0xfb, 0xaa,
+  0xef, 0x91, 0x34, 0xb3, 0x56, 0x91, 0x98, 0xaa, 0xf6, 0x90, 0x11, 0x00,
+  0x14, 0x44, 0x31, 0x72, 0xdf, 0xb7, 0x94, 0x18, 0x6f, 0x00, 0x99, 0xa4,
+  0x59, 0xd8, 0x76, 0x44, 0x08, 0x10, 0x82, 0x01, 0x40, 0x90, 0x80, 0x24,
+  0x10, 0x10, 0x98, 0x46, 0x46, 0x37, 0x7c, 0xd7, 0xb7, 0x68, 0x8d, 0x57,
+  0xc5, 0x3c, 0x9a, 0x68, 0x16, 0xce, 0x99, 0x70, 0xc7, 0x6e, 0x19, 0x2d,
+  0xe3, 0xbc, 0xd7, 0xac, 0x9e, 0x2e, 0xa2, 0xaf, 0x6c, 0xc1, 0x61, 0x3f,
+  0x2f, 0xf0, 0xf6, 0x38, 0x3e, 0xc7, 0x8b, 0xd3, 0x73, 0x7b, 0x2f, 0xae,
+  0xc9, 0x80, 0xf5, 0xc7, 0xc2, 0x92, 0x06, 0x43, 0xa4, 0x7c, 0x59, 0x08,
+  0x6d, 0xbe, 0x7b, 0xb2, 0xc8, 0x00, 0x1f, 0x1c, 0xb6, 0xbc, 0xf4, 0x6c,
+  0x49, 0xf6, 0x73, 0x0b, 0x37, 0xcc, 0x19, 0x29, 0x63, 0xb1, 0xdf, 0x7f,
+  0x94, 0xc4, 0x38, 0xc7, 0xff, 0x72, 0xc0, 0x35, 0xd7, 0x64, 0x3b, 0x10,
+  0xf4, 0xc4, 0x73, 0xcc, 0x70, 0x3c, 0xc1, 0xc8, 0x29, 0xcc, 0xc3, 0x49,
+  0xb9, 0xb7, 0xe6, 0x11, 0xa3, 0xe9, 0xa5, 0xea, 0x8e, 0x5b, 0xd9, 0xbc,
+  0x76, 0x7c, 0xe3, 0x70, 0x62, 0x33, 0xef, 0x03, 0x15, 0x0d, 0xf7, 0x57,
+  0x70, 0x2b, 0xd5, 0x75, 0x49, 0x30, 0x08, 0x78, 0xdd, 0x92, 0x20, 0x5d,
+  0xfa, 0xc6, 0xe3, 0x6a, 0xe2, 0x60, 0x00, 0x62, 0x00, 0xd7, 0xb5, 0xa8,
+  0xa4, 0x03, 0x07, 0x21, 0x1a, 0x8f, 0xd0, 0x07, 0x0a, 0x00, 0x0f, 0x43,
+  0x4b, 0x83, 0xd0, 0x98, 0xc3, 0x07, 0x0a, 0xe7, 0x4b, 0x8a, 0x72, 0xb8,
+  0x46, 0x85, 0x5d, 0xad, 0xe7, 0x18, 0x3a, 0x74, 0x0e, 0x7b, 0xcd, 0x73,
+  0x6f, 0x2c, 0xf5, 0xd2, 0x5d, 0x77, 0xe8, 0xbf, 0x7b, 0xc9, 0x85, 0xdb,
+  0x6d, 0x23, 0x75, 0x47, 0x55, 0x5b, 0x80, 0x90, 0xcb, 0x5d, 0x85, 0x48,
+  0xdb, 0xc9, 0x8d, 0x55, 0xc7, 0x5d, 0xa3, 0xb7, 0xa5, 0xe0, 0xc0, 0xfc,
+  0xeb, 0x06, 0xd1, 0xed, 0x3f, 0xed, 0x36, 0xdb, 0xaf, 0xba, 0xdf, 0x43,
+  0x87, 0xb9, 0xc5, 0x7d, 0xf4, 0x07, 0x1d, 0xc7, 0x79, 0x4a, 0x9d, 0x25,
+  0x18, 0x8d, 0x1d, 0xd7, 0xa7, 0x3d, 0x92, 0x37, 0x75, 0x20, 0x9a, 0x85,
+  0xd0, 0xe9, 0x94, 0x06, 0xe4, 0xac, 0xe6, 0xae, 0x96, 0xfd, 0x55, 0x77,
+  0xf3, 0x71, 0x0b, 0x1c, 0xe4, 0x3a, 0x1e, 0xdf, 0xee, 0xc6, 0xd0, 0x20,
+  0x1c, 0x1e, 0x0c, 0x7a, 0x7f, 0x6c, 0xfb, 0xb3, 0xf2, 0x9c, 0xd4, 0xbd,
+  0x85, 0x9f, 0xcb, 0x2f, 0xdb, 0x81, 0x10, 0x8d, 0xd2, 0x00, 0x4b, 0x47,
+  0x3d, 0x2f, 0xde, 0x3d, 0x3a, 0xdf, 0x88, 0x17, 0x85, 0x69, 0xe2, 0x32,
+  0xd7, 0xfd, 0xb6, 0x10, 0x56, 0x70, 0x42, 0xab, 0x45, 0xd2, 0xdc, 0x05,
+  0xe6, 0x00, 0x7c, 0xb4, 0x2f, 0x66, 0xdf, 0xbc, 0x5f, 0x2f, 0xd7, 0xfc,
+  0x44, 0x02, 0x6a, 0xe1, 0x46, 0x81, 0xb1, 0x50, 0xc2, 0x61, 0xb7, 0x76,
+  0xc9, 0x8b, 0xc4, 0x8b, 0x5a, 0x6b, 0x26, 0x90, 0x01, 0xaf, 0xa8, 0x19,
+  0x13, 0x4a, 0xc0, 0xb1, 0x01, 0x1d, 0x67, 0xe6, 0x36, 0xd6, 0x5f, 0xd8,
+  0x7b, 0xce, 0x92, 0x45, 0xb7, 0x32, 0xdc, 0x67, 0x9e, 0xac, 0x98, 0xcd,
+  0x97, 0xa2, 0xd2, 0x7f, 0x3f, 0xb6, 0x22, 0x8a, 0xb7, 0xe6, 0xe6, 0xab,
+  0x8e, 0x63, 0x4a, 0xaf, 0xf6, 0xbf, 0x13, 0xbc, 0xe5, 0x42, 0x6d, 0xf8,
+  0xdb, 0xa1, 0xba, 0x85, 0x41, 0xae, 0xb4, 0x40, 0x23, 0x00, 0x8a, 0x61,
+  0x47, 0x18, 0x71, 0x40, 0x9e, 0x27, 0x3a, 0xfd, 0x4f, 0x5d, 0xbc, 0xef,
+  0x1c, 0x7b, 0x09, 0xc6, 0xae, 0x6f, 0x98, 0xaa, 0xa3, 0x01, 0xf0, 0x9a,
+  0x86, 0x81, 0x95, 0xb3, 0xca, 0xd6, 0xb1, 0x22, 0x88, 0x90, 0x25, 0xf6,
+  0x5b, 0x0a, 0x4b, 0x71, 0x40, 0x21, 0xb5, 0x6c, 0xd2, 0x91, 0x27, 0x8c,
+  0x44, 0xce, 0x5a, 0x64, 0x81, 0x6d, 0x06, 0x30, 0x0a, 0x81, 0x94, 0x1f,
+  0x78, 0x6c, 0x7e, 0x81, 0x3f, 0xf4, 0xb7, 0x53, 0x53, 0xd3, 0x2c, 0x97,
+  0x94, 0xb6, 0x15, 0xe1, 0x86, 0xbc, 0x3a, 0x5f, 0xc3, 0x6f, 0x8c, 0xad,
+  0x67, 0xe3, 0x8b, 0x69, 0x9e, 0x7b, 0x1d, 0xda, 0x2c, 0x0a, 0x2c, 0xab,
+  0xca, 0xaf, 0xfd, 0xf2, 0xe3, 0xf7, 0xdd, 0x34, 0xc3, 0x76, 0xd7, 0xd5,
+  0xdf, 0xe3, 0x9d, 0xbb, 0xe2, 0xc9, 0x02, 0x3d, 0xda, 0x57, 0xe8, 0xd9,
+  0x43, 0x64, 0xf7, 0x2c, 0xec, 0x4e, 0x7d, 0x8c, 0xc2, 0xee, 0x58, 0x60,
+  0x30, 0x9e, 0x07, 0xea, 0x2d, 0xa7, 0x09, 0x7a, 0xf1, 0xb5, 0x48, 0x70,
+  0x5d, 0xab, 0x6a, 0x6d, 0x61, 0xb7, 0xfe, 0xc0, 0x07, 0xce, 0x01, 0xf2,
+  0xfd, 0x62, 0xf9, 0xbf, 0xa0, 0x03, 0x07, 0x21, 0x1a, 0x8b, 0xc8, 0x07,
+  0x0c, 0x00, 0x01, 0x3d, 0x66, 0xa6, 0xa9, 0x18, 0x43, 0x15, 0x56, 0xf3,
+  0xe8, 0x06, 0xe8, 0x16, 0x43, 0x81, 0xfa, 0xf6, 0xa2, 0xf4, 0x68, 0x16,
+  0xb6, 0x76, 0x15, 0xf3, 0x34, 0xc4, 0xe1, 0x5e, 0x78, 0xc3, 0x10, 0x99,
+  0x3b, 0x0a, 0x17, 0x28, 0xd5, 0x20, 0xe3, 0xb3, 0xa5, 0xc6, 0x4d, 0x1a,
+  0x4d, 0x4f, 0x1b, 0x02, 0x98, 0xb0, 0x32, 0xc3, 0x65, 0x61, 0xcc, 0x3a,
+  0xcf, 0x90, 0x6f, 0x2c, 0x00, 0x34, 0xa5, 0xeb, 0xb4, 0xa3, 0xf0, 0x37,
+  0x49, 0x19, 0x20, 0x2e, 0xe7, 0x78, 0x06, 0x16, 0x10, 0x27, 0x35, 0x4a,
+  0xf3, 0x85, 0xf2, 0x77, 0x74, 0xb3, 0x6f, 0xaf, 0x2c, 0xca, 0xc8, 0x97,
+  0x18, 0x4a, 0x61, 0x5a, 0x9f, 0x51, 0x25, 0x94, 0xa9, 0xc5, 0x72, 0xbe,
+  0x1a, 0x83, 0x1e, 0x7c, 0xd9, 0x91, 0xb5, 0xa2, 0x47, 0x21, 0x86, 0x49,
+  0xd8, 0x27, 0x95, 0x10, 0x38, 0x8e, 0x18, 0x98, 0x82, 0xf6, 0x8c, 0x78,
+  0xd4, 0xb2, 0xc8, 0xee, 0xa8, 0x84, 0xbb, 0xf6, 0xd6, 0x9d, 0x65, 0x49,
+  0xf7, 0x9e, 0x11, 0x27, 0x83, 0x94, 0x14, 0x92, 0xb4, 0x80, 0x00, 0x00,
+  0x93, 0x51, 0x56, 0x8c, 0x0d, 0xad, 0xbb, 0x02, 0x6e, 0xe0, 0xc3, 0x82,
+  0x00, 0x50, 0xa4, 0x31, 0x50, 0x9e, 0x1c, 0xd8, 0x4d, 0xea, 0xb2, 0xd0,
+  0xbd, 0x64, 0xb0, 0x22, 0x69, 0xd0, 0x1f, 0x6e, 0x49, 0x2b, 0x54, 0xc7,
+  0x98, 0xdd, 0x6b, 0x4f, 0xaa, 0x62, 0x52, 0x89, 0xf3, 0xb1, 0xa0, 0x39,
+  0xc8, 0x45, 0x45, 0xbd, 0x72, 0xc5, 0x10, 0xbd, 0xad, 0xba, 0x63, 0xba,
+  0xb0, 0x51, 0x67, 0x99, 0xb1, 0x34, 0x77, 0xe4, 0xb6, 0x78, 0x1c, 0x35,
+  0x08, 0xfb, 0xfa, 0x01, 0x72, 0x61, 0x95, 0x38, 0x3c, 0x5b, 0xc0, 0x34,
+  0x36, 0xda, 0xfe, 0x4b, 0x88, 0xde, 0x99, 0x4a, 0x6d, 0x30, 0x0a, 0x8d,
+  0x65, 0x3f, 0x7e, 0xaa, 0x4f, 0x43, 0x0c, 0x18, 0xb0, 0x4c, 0x32, 0x84,
+  0x72, 0x73, 0xf6, 0x03, 0xdc, 0xf9, 0x08, 0xb2, 0x03, 0x22, 0xcc, 0xa1,
+  0x07, 0x63, 0xb3, 0x45, 0x85, 0x35, 0xf1, 0x3f, 0xb1, 0xa1, 0x50, 0x6b,
+  0x75, 0x0f, 0x0a, 0x1a, 0x88, 0x9f, 0x5b, 0x4d, 0xda, 0xe2, 0x22, 0x75,
+  0xce, 0x09, 0xdf, 0xaf, 0x40, 0xb7, 0xef, 0x47, 0x6a, 0x48, 0x43, 0x7e,
+  0xa7, 0x0a, 0xd1, 0x51, 0xe3, 0xa5, 0xbc, 0x8b, 0x1b, 0x9f, 0x82, 0x85,
+  0xd0, 0x41, 0x05, 0xb0, 0x83, 0xa2, 0x30, 0x73, 0x02, 0x44, 0x00, 0x8e,
+  0x2b, 0xf1, 0xbc, 0xca, 0x82, 0xd8, 0x76, 0xad, 0x11, 0x4f, 0x45, 0xf1,
+  0x7f, 0x8f, 0x43, 0xdc, 0x00, 0xe0, 0x21, 0x1a, 0x8b, 0xc0, 0x0f, 0x8f,
+  0x41, 0xcf, 0x43, 0x52, 0x64, 0x10, 0xc5, 0xaa, 0xe3, 0x16, 0x25, 0x15,
+  0x06, 0x6a, 0xc2, 0xcb, 0x3e, 0xb3, 0x05, 0xba, 0xc0, 0x07, 0xcc, 0xa8,
+  0x32, 0x3c, 0x0e, 0xfe, 0x36, 0xe3, 0xd8, 0xb9, 0x62, 0x4f, 0x41, 0xc2,
+  0x60, 0x97, 0x99, 0x91, 0xf4, 0x2e, 0x27, 0xa0, 0xcb, 0x42, 0xa8, 0xc9,
+  0xd3, 0x30, 0xd9, 0xd3, 0xcb, 0x33, 0x00, 0x53, 0x3c, 0x63, 0xc5, 0x21,
+  0x0b, 0xf8, 0x3b, 0x80, 0x56, 0x59, 0x06, 0x76, 0xaa, 0x45, 0x97, 0x08,
+  0xf6, 0x6d, 0xfc, 0x87, 0x6f, 0x6f, 0xa5, 0x1a, 0xac, 0x7a, 0x2c, 0x72,
+  0xdd, 0x54, 0x7a, 0x71, 0xd0, 0xf8, 0x78, 0xcf, 0x7d, 0xaa, 0x97, 0x9a,
+  0xc8, 0x05, 0xbc, 0x0d, 0x10, 0xe6, 0x1a, 0xef, 0x3e, 0xcf, 0xc5, 0xb3,
+  0xdc, 0x32, 0xbb, 0x63, 0xc0, 0x07, 0x41, 0x4f, 0xc0, 0xef, 0x38, 0x69,
+  0x8d, 0x58, 0x72, 0x6f, 0xc0, 0xca, 0x24, 0x03, 0xe0, 0xa0, 0x45, 0x92,
+  0xd4, 0x49, 0x28, 0xd8, 0x00, 0x16, 0x61, 0x94, 0x2c, 0xcd, 0x24, 0xff,
+  0x94, 0xfe, 0x39, 0xa5, 0x42, 0x23, 0xe7, 0x2d, 0x16, 0xb4, 0xff, 0x55,
+  0x77, 0xfe, 0xf7, 0xc1, 0xa6, 0x8e, 0x26, 0xf0, 0x85, 0xe8, 0x00, 0x05,
+  0xb9, 0xe4, 0x0e, 0x3e, 0x11, 0x80, 0x52, 0xe0, 0x4f, 0xdc, 0x10, 0x90,
+  0x31, 0x22, 0x04, 0x46, 0x42, 0x14, 0x9a, 0x73, 0x9a, 0x37, 0x74, 0x43,
+  0x77, 0xc5, 0x20, 0xe0, 0x59, 0x3a, 0x0d, 0x68, 0x15, 0x2d, 0xa7, 0xa4,
+  0x59, 0xec, 0x75, 0xaa, 0x73, 0x78, 0x17, 0xdd, 0x31, 0xd7, 0xc6, 0xe9,
+  0x09, 0xbd, 0xf4, 0x79, 0x62, 0x1f, 0x72, 0x4e, 0x6f, 0xbb, 0xa0, 0x53,
+  0xc5, 0x4c, 0x68, 0x3d, 0x6e, 0x7d, 0x57, 0x23, 0xc7, 0x32, 0xb4, 0x36,
+  0xec, 0x2f, 0x0a, 0xf1, 0xda, 0x73, 0x99, 0xbf, 0xcd, 0x19, 0x39, 0x8c,
+  0x4c, 0x20, 0xae, 0xf5, 0x40, 0x85, 0xda, 0x32, 0xb7, 0xf4, 0x68, 0x3e,
+  0x98, 0x94, 0x4c, 0x12, 0x1f, 0xa4, 0xf6, 0x04, 0x57, 0x47, 0x1b, 0xca,
+  0xfa, 0xa8, 0x8d, 0x98, 0x4c, 0x99, 0x92, 0xc9, 0x92, 0x10, 0x0b, 0x09,
+  0x0c, 0xab, 0xe9, 0x75, 0xd7, 0x94, 0x81, 0xac, 0x45, 0x87, 0xf0, 0xc4,
+  0xac, 0x75, 0xb4, 0xc5, 0x3b, 0x45, 0x8e, 0xdc, 0x94, 0xe5, 0xd2, 0x65,
+  0xc3, 0xe9, 0xee, 0x9c, 0x40, 0x25, 0xb5, 0x19, 0x12, 0x68, 0xd8, 0x9d,
+  0xa2, 0x45, 0x84, 0x22, 0x14, 0x8d, 0x47, 0x28, 0xe9, 0x7b, 0xaa, 0x6b,
+  0x5b, 0xc2, 0x34, 0x8c, 0xe0, 0x60, 0x0a, 0x8c, 0x77, 0x07, 0x21, 0x1a,
+  0x8f, 0xd6, 0x1f, 0xcf, 0xe7, 0xfb, 0x37, 0x66, 0xa5, 0x58, 0x68, 0x50,
+  0x74, 0x11, 0xb9, 0x4a, 0x73, 0x3a, 0xad, 0xdd, 0xa9, 0x0a, 0xd5, 0x4b,
+  0x55, 0xc2, 0x17, 0x83, 0x4e, 0xa0, 0x6a, 0xfc, 0xbc, 0xda, 0xe0, 0xfe,
+  0x97, 0xd5, 0x12, 0x68, 0x1c, 0x1b, 0xdf, 0x9d, 0x21, 0x18, 0x7d, 0xa5,
+  0x75, 0xc4, 0x6a, 0x2a, 0x0a, 0x78, 0x43, 0x0d, 0xd1, 0x92, 0x49, 0x00,
+  0xb1, 0x94, 0x6e, 0xa0, 0x4a, 0x6d, 0x84, 0x94, 0x9b, 0xfc, 0xd3, 0x53,
+  0xaf, 0x1c, 0xf4, 0xee, 0x32, 0xe5, 0x2c, 0x01, 0x41, 0xc5, 0x19, 0xbb,
+  0x80, 0xab, 0xdb, 0xb2, 0x5e, 0x73, 0x0b, 0x91, 0xb4, 0x88, 0xc6, 0xe1,
+  0x59, 0x75, 0x77, 0x9d, 0xb1, 0x74, 0x4e, 0xab, 0x64, 0x6a, 0xd1, 0x37,
+  0xad, 0x90, 0xc3, 0x8b, 0x28, 0x6c, 0x2a, 0x90, 0x9d, 0xbc, 0x42, 0x94,
+  0x20, 0xc0, 0xa4, 0xbc, 0x69, 0xd0, 0x9e, 0x95, 0xfd, 0x1a, 0x64, 0x29,
+  0xeb, 0xa4, 0xc6, 0x8b, 0xf1, 0x43, 0x10, 0x50, 0x11, 0x79, 0x07, 0xdf,
+  0xfb, 0xe7, 0x53, 0x7b, 0x58, 0x26, 0x73, 0x08, 0x63, 0xa7, 0x1e, 0x5e,
+  0xe5, 0x98, 0xd5, 0x97, 0xaf, 0xdb, 0xf6, 0x1c, 0xc0, 0x00, 0x05, 0x46,
+  0xdc, 0xf0, 0x4e, 0xfb, 0x7a, 0x85, 0x11, 0x09, 0x39, 0x77, 0x86, 0x07,
+  0x13, 0x8e, 0x9d, 0xad, 0xa9, 0x52, 0x35, 0x40, 0x0a, 0x00, 0x03, 0x34,
+  0x52, 0xc6, 0x4f, 0x0b, 0xa3, 0x72, 0xf2, 0xe1, 0x00, 0x4d, 0xdb, 0x98,
+  0xa0, 0x18, 0x19, 0x10, 0x46, 0x81, 0x11, 0x80, 0xc4, 0x60, 0x25, 0x53,
+  0x95, 0xa8, 0x68, 0xa6, 0x74, 0x8d, 0x21, 0x7a, 0x34, 0xd3, 0x41, 0x4d,
+  0x41, 0xe5, 0xa5, 0xa6, 0x19, 0x8d, 0xce, 0x50, 0x25, 0x3f, 0x4e, 0xbb,
+  0xc8, 0xdb, 0x2e, 0x0b, 0x4c, 0xae, 0x59, 0x35, 0x5a, 0x61, 0xa7, 0x67,
+  0x40, 0xfe, 0xed, 0xc4, 0x3d, 0xda, 0x3a, 0x0e, 0x1d, 0x25, 0xe2, 0x39,
+  0x34, 0x3b, 0x4b, 0x0d, 0xcc, 0x3e, 0x93, 0xa5, 0xfa, 0xfc, 0x3a, 0x51,
+  0x5c, 0x9b, 0x1e, 0xb5, 0xa9, 0x02, 0xd0, 0x42, 0xb2, 0xcc, 0x5e, 0x78,
+  0x41, 0x9e, 0x08, 0xc7, 0x0c, 0xcf, 0xe5, 0x43, 0xbd, 0xa9, 0xd5, 0x03,
+  0xa5, 0xb6, 0xd1, 0x94, 0x18, 0x30, 0x18, 0xcd, 0x9d, 0xfc, 0xf9, 0x3e,
+  0x16, 0xa6, 0x94, 0xd2, 0xda, 0x58, 0x20, 0x62, 0xe7, 0x3e, 0x8c, 0x60,
+  0x60, 0x28, 0x89, 0x13, 0x05, 0xeb, 0x25, 0xdb, 0x76, 0xc4, 0xba, 0x12,
+  0xf4, 0xf9, 0x3b, 0x5e, 0xba, 0x64, 0xb9, 0xc6, 0xcd, 0xb2, 0xd5, 0xe8,
+  0x97, 0x99, 0x12, 0x6f, 0x1f, 0xe8, 0x00, 0x04, 0xb7, 0x60, 0x0e, 0x21,
+  0x1a, 0x94, 0xcd, 0xc6, 0x8f, 0x03, 0x41, 0x99, 0x10, 0x62, 0x51, 0xce,
+  0xd6, 0xb8, 0x71, 0xc8, 0xb4, 0x5a, 0xd2, 0x2c, 0xbc, 0x16, 0xe0, 0x0d,
+  0xfb, 0xf0, 0xbb, 0xac, 0x88, 0x03, 0xde, 0xb5, 0xf7, 0xe1, 0xa0, 0x1b,
+  0xae, 0xf1, 0x5a, 0xed, 0xdd, 0xbe, 0x76, 0x9c, 0xe2, 0xe8, 0x64, 0xd9,
+  0x3c, 0xf5, 0xb0, 0xea, 0x7e, 0x7e, 0x4e, 0xb1, 0x7c, 0x3d, 0xd5, 0x3e,
+  0x02, 0x5e, 0x9d, 0xca, 0x5f, 0xa3, 0x5c, 0x83, 0x7d, 0xf3, 0x33, 0x03,
+  0x56, 0xf2, 0x9c, 0x0b, 0xdc, 0x71, 0x15, 0x7c, 0xdf, 0x06, 0xa3, 0xbe,
+  0x0d, 0x8e, 0x13, 0xa3, 0xb3, 0x2d, 0x35, 0xcd, 0x67, 0x6a, 0xec, 0x33,
+  0xfb, 0xef, 0x98, 0x50, 0x18, 0xfb, 0x04, 0xb1, 0x4c, 0x80, 0xc4, 0xdd,
+  0xa5, 0x7b, 0xab, 0x83, 0xb0, 0xc1, 0x40, 0x1b, 0xe9, 0x8f, 0xb0, 0x34,
+  0xea, 0x09, 0x06, 0x55, 0x4c, 0x90, 0xaf, 0xcc, 0x44, 0x88, 0x60, 0x44,
+  0xa0, 0xad, 0x98, 0x94, 0x9e, 0x99, 0x42, 0xd7, 0xe8, 0xbb, 0x8e, 0xba,
+  0x8a, 0xce, 0xe9, 0x81, 0x5a, 0xd8, 0xcd, 0xcd, 0x68, 0xad, 0x9b, 0x6c,
+  0x57, 0x5e, 0x86, 0xd1, 0x25, 0x3c, 0x36, 0xa0, 0x03, 0xd1, 0x14, 0x57,
+  0x97, 0x89, 0xd2, 0xa5, 0x72, 0xf8, 0x27, 0xd4, 0xbe, 0xe7, 0xe7, 0xeb,
+  0x57, 0x43, 0xf8, 0xbd, 0x1f, 0xb9, 0xab, 0x11, 0x30, 0x58, 0xe0, 0xa9,
+  0x6b, 0x56, 0xbd, 0x74, 0xfb, 0x19, 0xf5, 0x34, 0xf9, 0xcd, 0xbe, 0x9f,
+  0x9b, 0x03, 0x5a, 0x57, 0x9d, 0xa3, 0xa0, 0xb0, 0xb5, 0xc8, 0x78, 0xd8,
+  0x5d, 0xce, 0x43, 0x7e, 0xce, 0x38, 0x81, 0xb3, 0x73, 0xaa, 0xa8, 0xe1,
+  0x2c, 0x04, 0x85, 0x4d, 0x42, 0xf1, 0x82, 0xa1, 0x29, 0xed, 0x0a, 0x6f,
+  0x0d, 0x59, 0x8c, 0xd9, 0xd6, 0x00, 0x26, 0x69, 0x36, 0x48, 0x2a, 0x94,
+  0x06, 0x41, 0x01, 0x88, 0x80, 0xc2, 0x46, 0xe3, 0x6d, 0x63, 0x8a, 0x28,
+  0x07, 0x0e, 0xba, 0x74, 0x05, 0xbd, 0x3b, 0x3b, 0xce, 0x83, 0x6e, 0x9b,
+  0xfc, 0x55, 0x62, 0xb5, 0xe6, 0xfa, 0x8a, 0xb6, 0x1c, 0x74, 0xb4, 0x72,
+  0xc7, 0xd3, 0x56, 0xe2, 0x9d, 0x11, 0x76, 0x5d, 0xea, 0xc7, 0x2d, 0xbe,
+  0x2a, 0x06, 0xa6, 0x71, 0x54, 0xe0, 0x9f, 0x8d, 0xc4, 0x39, 0xb6, 0x94,
+  0x1d, 0xf0, 0x20, 0x70, 0xec, 0x63, 0x9d, 0x75, 0x40, 0x5c, 0x31, 0x4e,
+  0x64, 0xb2, 0xd5, 0xa2, 0x33, 0x83, 0x7a, 0x4e, 0xa1, 0x7d, 0x33, 0x15,
+  0xcb, 0xfd, 0xe3, 0xe1, 0xd5, 0xb0, 0x5e, 0xd4, 0xa3, 0xa1, 0x1e, 0x35,
+  0x01, 0xbe, 0x6a, 0x11, 0x21, 0xc3, 0x54, 0x8b, 0x0f, 0xdf, 0xba, 0xc5,
+  0x2d, 0x14, 0x13, 0x00, 0xe0, 0x21, 0x1a, 0x94, 0xdd, 0xca, 0x12, 0x83,
+  0x11, 0x11, 0x04, 0xc4, 0x6c, 0xdf, 0x18, 0xe9, 0x50, 0x15, 0x72, 0xa6,
+  0x9a, 0x3a, 0xe4, 0xa3, 0x50, 0x06, 0xaa, 0x98, 0x71, 0x7f, 0xae, 0x73,
+  0x27, 0x79, 0xf7, 0x56, 0xbd, 0xb4, 0x4c, 0x76, 0x0d, 0x6e, 0x0f, 0x94,
+  0x9e, 0x18, 0x37, 0x3b, 0xbb, 0x55, 0xb9, 0xfd, 0x36, 0xf3, 0x5d, 0x72,
+  0xe4, 0x08, 0x5b, 0x1a, 0x7b, 0x85, 0x90, 0x04, 0x08, 0xe3, 0x97, 0x5d,
+  0x1e, 0x1d, 0xa3, 0x63, 0x59, 0xe9, 0x62, 0x0e, 0xfc, 0xc2, 0x7c, 0x63,
+  0x96, 0x5f, 0x92, 0x5f, 0x0d, 0xec, 0xee, 0x36, 0xd9, 0xb8, 0xbe, 0xa8,
+  0x8b, 0xac, 0x35, 0x74, 0xa7, 0xfb, 0xff, 0xbe, 0x9f, 0x73, 0xbb, 0xe9,
+  0x6e, 0x6a, 0xf4, 0xcd, 0xb1, 0xe4, 0x8d, 0xd1, 0x22, 0x2b, 0xf0, 0x0e,
+  0xc3, 0x93, 0x37, 0x10, 0xb2, 0x7e, 0x35, 0x26, 0xdc, 0xd9, 0x71, 0xe6,
+  0x8c, 0xb0, 0xa6, 0x14, 0xc1, 0x1a, 0x2c, 0xb4, 0x36, 0xf4, 0xf5, 0xd4,
+  0x32, 0xf0, 0x61, 0x63, 0x4f, 0xa0, 0x7a, 0x72, 0x08, 0xc8, 0x1d, 0x7a,
+  0x65, 0xc7, 0xda, 0xcb, 0x4a, 0x3c, 0x82, 0x64, 0x18, 0x65, 0xb9, 0xc5,
+  0xad, 0x5f, 0xbe, 0xd8, 0xb4, 0x01, 0x59, 0xbb, 0x6e, 0xeb, 0xeb, 0x1f,
+  0x4c, 0x9c, 0xba, 0x11, 0x62, 0xff, 0x3a, 0x38, 0x1e, 0x5c, 0x9d, 0xd5,
+  0x8e, 0x71, 0x9b, 0x9e, 0x60, 0xf4, 0xb1, 0x5c, 0x9e, 0xee, 0x76, 0x57,
+  0x96, 0x28, 0xb8, 0x82, 0x62, 0x54, 0x00, 0xe6, 0x90, 0xff, 0x5e, 0x67,
+  0xd4, 0x8c, 0x75, 0x33, 0xab, 0xaa, 0x70, 0xc8, 0x0b, 0xdd, 0x09, 0x4f,
+  0x0d, 0x92, 0x0c, 0xe0, 0x20, 0xd6, 0x59, 0x70, 0x94, 0xec, 0x13, 0xd6,
+  0xf7, 0x23, 0x0c, 0x82, 0x02, 0x11, 0x00, 0xc4, 0x20, 0x71, 0x22, 0x75,
+  0x8c, 0x65, 0xc2, 0x50, 0x09, 0x77, 0x3e, 0x3a, 0xab, 0x05, 0xd1, 0xfa,
+  0x9b, 0x93, 0x48, 0x75, 0xf7, 0xf6, 0x98, 0xe7, 0x3b, 0x28, 0xa9, 0xdc,
+  0x2f, 0xf2, 0xd4, 0xb9, 0x61, 0xa1, 0xc3, 0x47, 0x5b, 0xc3, 0xe5, 0x46,
+  0xd7, 0x49, 0x64, 0xf9, 0xb6, 0x4b, 0x28, 0x66, 0x0e, 0xb4, 0x6e, 0xe6,
+  0xdf, 0xf8, 0x0c, 0x23, 0xb3, 0x15, 0x44, 0x59, 0xe9, 0xec, 0xbf, 0x7d,
+  0x2c, 0x7b, 0xc9, 0x9f, 0x26, 0x77, 0x1d, 0x33, 0x51, 0x54, 0x30, 0xe2,
+  0x4d, 0x42, 0x20, 0xb8, 0x52, 0x6c, 0x4b, 0x8f, 0xe8, 0xae, 0xa0, 0x12,
+  0x30, 0xa5, 0x12, 0x52, 0x01, 0x9c, 0x89, 0x23, 0x6b, 0x23, 0x11, 0x61,
+  0xc4, 0xfc, 0x73, 0xa8, 0x94, 0x00, 0x38, 0x21, 0x1a, 0x8d, 0x24, 0x0f,
+  0xff, 0x85, 0xff, 0x37, 0x6b, 0xa2, 0x58, 0x68, 0xb0, 0x46, 0x18, 0xb8,
+  0x6f, 0x2d, 0xc5, 0x24, 0xdc, 0x11, 0xc0, 0xa5, 0xb4, 0x75, 0x59, 0xb1,
+  0xd5, 0x81, 0x64, 0xd3, 0xff, 0x5d, 0xdd, 0x39, 0xa2, 0x86, 0x05, 0x23,
+  0x0c, 0x74, 0xc8, 0x4c, 0x78, 0x10, 0x21, 0x90, 0xc7, 0x46, 0x23, 0xa5,
+  0x5a, 0x18, 0x1d, 0x09, 0xd5, 0xb6, 0xa6, 0xd1, 0x36, 0x34, 0x28, 0x71,
+  0xeb, 0x1d, 0x5e, 0xd4, 0x32, 0xd6, 0xda, 0xd9, 0x3c, 0xf6, 0xc7, 0x87,
+  0xe4, 0x96, 0x4e, 0xca, 0x28, 0x0f, 0x1c, 0x73, 0x51, 0xeb, 0xf4, 0xeb,
+  0x36, 0x5b, 0x5c, 0xdf, 0x41, 0xac, 0x97, 0xcb, 0x3a, 0x6d, 0x6b, 0x63,
+  0x22, 0x15, 0x3f, 0xa3, 0x33, 0xd0, 0xdf, 0x2a, 0x95, 0x1d, 0x65, 0xb5,
+  0xef, 0x0e, 0x26, 0xad, 0xb6, 0xe8, 0x4d, 0xc7, 0xb8, 0x99, 0xa7, 0x10,
+  0x7c, 0x66, 0x18, 0xca, 0x43, 0x88, 0xf0, 0x64, 0x15, 0x85, 0x87, 0xf4,
+  0xeb, 0x88, 0x2a, 0xe2, 0xa6, 0x65, 0xc1, 0xd9, 0x93, 0xfb, 0x1a, 0x8f,
+  0x68, 0xc6, 0xe6, 0xae, 0xb1, 0x69, 0xd6, 0xd9, 0x8e, 0xd0, 0x28, 0x91,
+  0x22, 0x41, 0xa4, 0xe1, 0x57, 0x34, 0x55, 0x9e, 0x2f, 0x5c, 0xb0, 0xf9,
+  0x63, 0x8f, 0x6c, 0x61, 0x61, 0x18, 0x43, 0xd4, 0x4a, 0xa5, 0xfc, 0x22,
+  0x34, 0xfc, 0x73, 0x6c, 0xe7, 0xbb, 0xc9, 0x98, 0x39, 0x08, 0x27, 0x92,
+  0xa8, 0xcb, 0xb6, 0x0c, 0x7f, 0x38, 0xe0, 0x4a, 0x3a, 0x09, 0x89, 0x5a,
+  0xa0, 0x9a, 0xb5, 0x26, 0xaa, 0x12, 0xa1, 0x2a, 0x58, 0x21, 0xb6, 0xbe,
+  0x3b, 0x02, 0x6e, 0xdf, 0x03, 0x62, 0xa2, 0x44, 0x28, 0x11, 0x42, 0x63,
+  0x00, 0x20, 0x88, 0xe1, 0x4b, 0x5a, 0x4d, 0x0b, 0x2e, 0x5e, 0x05, 0x14,
+  0xda, 0x45, 0xfe, 0xba, 0x62, 0xc3, 0xf0, 0x72, 0xd0, 0x01, 0xf8, 0x08,
+  0xcb, 0x6e, 0xda, 0x82, 0x82, 0x66, 0xca, 0x90, 0x0f, 0xc6, 0xc7, 0x4d,
+  0xd4, 0x05, 0xd9, 0xd2, 0x14, 0xa0, 0x4b, 0x4e, 0x36, 0x27, 0x1d, 0xfe,
+  0x52, 0xd3, 0x5d, 0xa6, 0x4f, 0x18, 0xfb, 0xc3, 0x82, 0x7b, 0x8c, 0xbc,
+  0xee, 0x91, 0xd0, 0x9d, 0xd3, 0xbe, 0xbd, 0xe6, 0xb8, 0x8f, 0xd4, 0xa3,
+  0x8e, 0x7c, 0x43, 0x0f, 0x54, 0x01, 0x9f, 0xed, 0x42, 0x4f, 0x76, 0x70,
+  0xb3, 0xda, 0x72, 0x85, 0x0b, 0x21, 0x02, 0xf2, 0xfa, 0x74, 0x2f, 0x8e,
+  0x8d, 0x36, 0xf5, 0x28, 0x91, 0xa8, 0x24, 0x1e, 0xe7, 0xc4, 0xb6, 0x64,
+  0x41, 0x24, 0x7d, 0x7c, 0x73, 0x2c, 0x8d, 0x2a, 0x38, 0x1f, 0x1f, 0x59,
+  0xf0, 0x75, 0x58, 0x8d, 0x6e, 0x1c, 0x8f, 0x4e, 0x47, 0xaa, 0x78, 0xa4,
+  0x67, 0x03, 0xae, 0xc1, 0x8d, 0x4a, 0x51, 0xa4, 0xaf, 0x45, 0x24, 0xb5,
+  0x2b, 0x81, 0xf5, 0x43, 0xc0, 0x42, 0x34, 0xb2, 0x1a, 0x45, 0x74, 0x89,
+  0xa7, 0xdb, 0x80, 0x0e, 0x46, 0xe7, 0x60, 0xa5, 0x44, 0x03, 0x4c, 0xf6,
+  0x3e, 0xef, 0xcc, 0x00, 0x90, 0x5d, 0x44, 0xc5, 0x44, 0xf6, 0x83, 0xe7,
+  0x0b, 0xdf, 0x13, 0x3d, 0x80, 0x70, 0x21, 0x1a, 0x8f, 0xf0, 0x07, 0xcf,
+  0x1e, 0xff, 0x3f, 0x66, 0xa6, 0xb1, 0x86, 0x26, 0x56, 0x93, 0xaa, 0x55,
+  0x28, 0x04, 0x82, 0xba, 0xd5, 0xde, 0xd0, 0x97, 0xc0, 0x5b, 0x2a, 0x49,
+  0x24, 0xff, 0xc1, 0x3b, 0xb6, 0x0c, 0x5b, 0x1c, 0xc2, 0xa1, 0xb9, 0xa7,
+  0x34, 0xdb, 0xc7, 0x6e, 0x49, 0x79, 0xd4, 0x6c, 0x6c, 0x0a, 0xb7, 0xeb,
+  0x55, 0x62, 0x7a, 0xd1, 0x57, 0x42, 0x1a, 0x46, 0xaa, 0xf7, 0x81, 0x55,
+  0xcd, 0x14, 0xa9, 0x14, 0xcb, 0xfa, 0x65, 0x16, 0x65, 0xe6, 0x64, 0xce,
+  0x91, 0x77, 0x45, 0xec, 0x9b, 0xec, 0x17, 0x4b, 0xb8, 0x31, 0x49, 0x5a,
+  0x53, 0x8e, 0xab, 0xc9, 0x49, 0xd7, 0x1c, 0x93, 0xf8, 0x1f, 0x25, 0x12,
+  0x35, 0x7b, 0x34, 0x89, 0x5f, 0x9f, 0x27, 0x61, 0x0a, 0xdc, 0x2b, 0x00,
+  0x77, 0x02, 0x65, 0x62, 0xa5, 0xe8, 0xa3, 0xb7, 0x0d, 0xfc, 0xee, 0xa6,
+  0x79, 0x82, 0xc6, 0x3f, 0xa7, 0x3c, 0x56, 0xf0, 0xd6, 0x80, 0xc8, 0xdd,
+  0x71, 0x33, 0x23, 0x6b, 0x82, 0xd1, 0x05, 0xc9, 0x84, 0x80, 0x13, 0x85,
+  0xd4, 0xa8, 0x85, 0x85, 0x20, 0x6a, 0x25, 0x75, 0x3b, 0x1a, 0xdd, 0xe5,
+  0x4c, 0x90, 0x2a, 0x0b, 0x85, 0xad, 0xb0, 0x50, 0x2d, 0x29, 0xbc, 0x2b,
+  0x45, 0xaf, 0x7d, 0x3c, 0x00, 0x9c, 0xb8, 0x99, 0x18, 0x43, 0x31, 0x55,
+  0x95, 0x4b, 0x00, 0x44, 0xb1, 0x66, 0xbd, 0x92, 0xaa, 0xe4, 0x97, 0x50,
+  0x3d, 0x55, 0xae, 0x68, 0x6e, 0xda, 0x6b, 0xdd, 0xb5, 0xe7, 0xee, 0x7b,
+  0x03, 0x5d, 0x0a, 0x9a, 0x25, 0x92, 0xe7, 0x2e, 0xc6, 0xe4, 0xb8, 0x48,
+  0x2b, 0x8b, 0xc9, 0xe5, 0xaa, 0x12, 0x33, 0x2d, 0x21, 0x63, 0x42, 0x54,
+  0x77, 0x41, 0x7b, 0xd7, 0xa3, 0x28, 0x60, 0xe1, 0x9c, 0xa8, 0xbd, 0xc1,
+  0xdd, 0x29, 0xdc, 0x98, 0x54, 0x8e, 0x85, 0x6c, 0x47, 0x83, 0x37, 0x75,
+  0xeb, 0xef, 0xc3, 0xa1, 0xe3, 0xf0, 0xd0, 0x78, 0xee, 0x34, 0xb3, 0x63,
+  0x55, 0xb2, 0xe2, 0x00, 0x52, 0x70, 0x75, 0xd5, 0xff, 0xa1, 0x00, 0x23,
+  0x00, 0xd9, 0x7c, 0xbe, 0xca, 0xda, 0x93, 0x32, 0xa8, 0xd6, 0x2e, 0x88,
+  0x9a, 0xeb, 0x27, 0x40, 0xa0, 0x7b, 0x64, 0x2d, 0x12, 0x33, 0xb3, 0xd5,
+  0xed, 0xea, 0xc5, 0xe8, 0x7b, 0x1a, 0x4c, 0x02, 0x35, 0xa4, 0x80, 0xb5,
+  0xd0, 0x98, 0x10, 0x2a, 0xeb, 0x42, 0x8b, 0xb7, 0x2a, 0x52, 0x4d, 0x30,
+  0x0e, 0x21, 0x1a, 0x8f, 0xc0, 0x00, 0x06, 0x00, 0xff, 0x35, 0x6b, 0xa5,
+  0xb1, 0x06, 0x00, 0x46, 0x94, 0xda, 0x17, 0x97, 0xc5, 0xa3, 0x2e, 0xda,
+  0x04, 0x40, 0x1f, 0x74, 0xf4, 0x4e, 0x2e, 0xf8, 0x3a, 0x57, 0x52, 0x77,
+  0xf5, 0xa4, 0x6a, 0x9c, 0x52, 0xc9, 0xf8, 0x27, 0xe9, 0xa7, 0x96, 0x07,
+  0xfc, 0x42, 0xe7, 0x42, 0x73, 0x3f, 0x45, 0x69, 0x5f, 0xde, 0xea, 0xcd,
+  0xeb, 0xea, 0xa9, 0x7e, 0x76, 0xc1, 0x2f, 0x59, 0x5c, 0xfd, 0x9a, 0xd5,
+  0xb0, 0x5c, 0x27, 0xc1, 0x5c, 0x5b, 0x09, 0x3c, 0xb7, 0x6d, 0xda, 0x73,
+  0xfa, 0xc6, 0xc5, 0x65, 0xc4, 0x60, 0x78, 0xe6, 0x2a, 0x3e, 0x5d, 0xba,
+  0xb4, 0x54, 0x2b, 0x18, 0x18, 0xd7, 0x95, 0x22, 0xa0, 0x9a, 0x38, 0xd4,
+  0x32, 0xa4, 0x09, 0x36, 0xf3, 0x22, 0xe1, 0x03, 0xc2, 0x40, 0x84, 0x13,
+  0x47, 0x37, 0x65, 0x36, 0xaf, 0x75, 0x5d, 0xd8, 0x7b, 0x66, 0xfb, 0xcd,
+  0x8e, 0x3a, 0x3a, 0xe1, 0x8a, 0xb9, 0x30, 0x19, 0x04, 0x00, 0xd2, 0x98,
+  0x69, 0xa5, 0xcb, 0xc2, 0xf2, 0x6f, 0x8f, 0x20, 0xbb, 0x13, 0xed, 0xe5,
+  0x0a, 0x73, 0x90, 0x4c, 0x17, 0x52, 0x2d, 0x38, 0x83, 0x7e, 0xf8, 0xd3,
+  0x14, 0x71, 0x17, 0x84, 0x6d, 0x6b, 0xde, 0x02, 0x2f, 0x34, 0x37, 0x66,
+  0x93, 0x91, 0x0a, 0x27, 0x1e, 0x38, 0x62, 0x84, 0x6c, 0xa0, 0x52, 0xd7,
+  0xa4, 0xe2, 0x94, 0xce, 0x83, 0x69, 0xb6, 0x18, 0x02, 0x76, 0xe7, 0x43,
+  0x61, 0x10, 0x98, 0x48, 0x12, 0x30, 0x9d, 0x60, 0x00, 0x22, 0xe6, 0x4f,
+  0x2b, 0x43, 0x4a, 0x3a, 0xc2, 0xe0, 0x37, 0x10, 0x3f, 0xe4, 0x36, 0xb8,
+  0x44, 0x53, 0xb1, 0xf9, 0x53, 0x51, 0xd6, 0xa8, 0x25, 0x06, 0x70, 0xbd,
+  0x50, 0xec, 0xde, 0xfb, 0xaf, 0x80, 0xca, 0xc0, 0xf3, 0x9c, 0xd1, 0xc9,
+  0x33, 0x2d, 0x02, 0x52, 0x83, 0xc5, 0x7b, 0x5a, 0x67, 0x43, 0xf8, 0xff,
+  0x52, 0x36, 0xac, 0xd2, 0x64, 0xe1, 0x92, 0x38, 0x7a, 0xa2, 0xec, 0x5d,
+  0x8a, 0x3c, 0x08, 0x2e, 0x8e, 0x36, 0xec, 0x8e, 0x62, 0x51, 0x82, 0xe6,
+  0xce, 0x53, 0x88, 0xdb, 0x72, 0xd0, 0x3a, 0x7b, 0x8b, 0xde, 0xbf, 0x1f,
+  0x0a, 0x89, 0x1c, 0xc5, 0xab, 0xc8, 0xa5, 0x59, 0xbd, 0x1b, 0xb5, 0xfc,
+  0xa9, 0x99, 0x23, 0xf1, 0x17, 0x2d, 0xbe, 0xc4, 0xf5, 0x9c, 0x4d, 0xe3,
+  0x7b, 0x2c, 0x9b, 0x65, 0x8f, 0x5f, 0xe3, 0x13, 0x90, 0x08, 0xad, 0x38,
+  0xad, 0xd4, 0xde, 0x5b, 0xbd, 0xf9, 0x32, 0x7c, 0x13, 0xeb, 0xe6, 0xe7,
+  0xb6, 0x1a, 0x21, 0x69, 0xc6, 0x2f, 0x24, 0x6b, 0x08, 0x29, 0xd1, 0x4c,
+  0x34, 0xd1, 0x31, 0x88, 0x84, 0x3d, 0xa9, 0xf0, 0xe9, 0x59, 0xa1, 0x19,
+  0x97, 0x4e, 0x79, 0xcd, 0xeb, 0xcb, 0x9e, 0x27, 0x4b, 0x23, 0x32, 0x23,
+  0xa6, 0x6d, 0x06, 0x08, 0xb0, 0xe8, 0x53, 0x82, 0x70, 0xaa, 0x32, 0x39,
+  0x80, 0xef, 0x16, 0x82, 0xdc, 0xee, 0x7f, 0x70, 0x70, 0x4a, 0xd1, 0xcb,
+  0x4e, 0x94, 0x2a, 0x4b, 0x2a, 0x57, 0x05, 0x45, 0x46, 0x1c, 0x67, 0x02,
+  0x2f, 0xd3, 0x18, 0xf2, 0x92, 0x03, 0x07, 0x21, 0x1a, 0x8d, 0x00, 0x00,
+  0x0e, 0x01, 0xff, 0x37, 0x64, 0xa7, 0xb2, 0x48, 0x42, 0x44, 0x10, 0x98,
+  0x24, 0x83, 0x25, 0x58, 0xbb, 0xba, 0xb4, 0x34, 0xb8, 0x00, 0x58, 0x6c,
+  0xee, 0xdf, 0xfa, 0x8d, 0x10, 0x2f, 0x1b, 0xc4, 0x49, 0x80, 0xba, 0xef,
+  0xce, 0xdb, 0xf8, 0x7d, 0x3b, 0x1b, 0x6a, 0xca, 0xfd, 0x92, 0x6b, 0x5f,
+  0x25, 0xab, 0x62, 0xf0, 0x26, 0x14, 0x3c, 0x47, 0x95, 0x48, 0x36, 0x8a,
+  0x82, 0x75, 0x4c, 0x6f, 0x81, 0xe6, 0xbd, 0x23, 0x17, 0x33, 0x0f, 0x4c,
+  0xfb, 0x25, 0x5c, 0x26, 0x1e, 0x2b, 0xa7, 0x87, 0xfc, 0x94, 0xcd, 0x2e,
+  0x43, 0x63, 0x40, 0xd0, 0xf4, 0xaf, 0xfe, 0x0f, 0xe6, 0x4d, 0x8d, 0x66,
+  0x9e, 0xfc, 0x73, 0xae, 0xea, 0x3c, 0x64, 0xa2, 0xca, 0xa7, 0x51, 0xa6,
+  0xae, 0xab, 0x1f, 0x66, 0x61, 0x60, 0xdd, 0x9c, 0xbb, 0xdb, 0xb3, 0x0f,
+  0x8f, 0x67, 0x7d, 0x3c, 0x38, 0xa2, 0x67, 0x12, 0xef, 0xbe, 0x49, 0xf3,
+  0x80, 0x8c, 0xe1, 0x9d, 0x9d, 0x25, 0x40, 0x37, 0x9d, 0x61, 0x4a, 0x99,
+  0x27, 0xce, 0x0c, 0x80, 0x60, 0xf8, 0xfe, 0xdb, 0x1c, 0xaf, 0xa3, 0xfb,
+  0x34, 0xe8, 0x04, 0x0b, 0x29, 0xf5, 0x8a, 0x74, 0x43, 0x84, 0x62, 0x52,
+  0x39, 0xf8, 0x05, 0xa2, 0xd6, 0x61, 0xd7, 0x14, 0x87, 0xe8, 0xe5, 0x53,
+  0x46, 0x5e, 0x1d, 0x29, 0x1b, 0x5e, 0xa5, 0x44, 0x96, 0xed, 0xa7, 0x38,
+  0x21, 0x41, 0xb5, 0x41, 0x6b, 0xd8, 0x2a, 0x4d, 0x40, 0xbf, 0x9f, 0x89,
+  0x2d, 0x65, 0x6e, 0x13, 0xf6, 0xfa, 0x3b, 0x85, 0x0a, 0x2e, 0x71, 0x4c,
+  0x00, 0x64, 0xb2, 0xe5, 0x3f, 0x0b, 0xf0, 0x8e, 0x09, 0xc1, 0x60, 0x11,
+  0x29, 0xd5, 0x3a, 0x65, 0x4c, 0xe6, 0x2e, 0xa1, 0x26, 0x93, 0x0b, 0xb7,
+  0xc1, 0x3f, 0x86, 0x6f, 0xa8, 0xcc, 0x49, 0x80, 0xd1, 0x50, 0xaa, 0xec,
+  0x5e, 0x2d, 0x3d, 0x78, 0xc6, 0x4f, 0x3e, 0xcc, 0xc8, 0xa4, 0x00, 0xcf,
+  0xf9, 0x78, 0x77, 0xc0, 0x46, 0x8e, 0x47, 0xf6, 0x9e, 0xf9, 0x8d, 0x46,
+  0xb7, 0x87, 0xcb, 0x16, 0xcf, 0x35, 0xea, 0xd5, 0x7b, 0x07, 0x64, 0xae,
+  0x70, 0x18, 0xdd, 0x58, 0xbc, 0xf2, 0xf7, 0xa8, 0x49, 0x07, 0x26, 0x9c,
+  0xcb, 0x44, 0x5f, 0x15, 0x73, 0xf1, 0xb6, 0xcb, 0x05, 0xe9, 0xe6, 0xbe,
+  0x60, 0xdd, 0xce, 0xd9, 0x07, 0x65, 0xd1, 0xf4, 0xc9, 0x69, 0x2a, 0x42,
+  0x9b, 0xf0, 0xf4, 0x89, 0x14, 0x43, 0x56, 0xf6, 0xd9, 0x23, 0x46, 0xb2,
+  0xf3, 0x80, 0xa7, 0x2d, 0x81, 0x79, 0x92, 0x4c, 0xf7, 0x16, 0x32, 0xf1,
+  0xb6, 0x2d, 0x7b, 0x13, 0x9f, 0xda, 0xab, 0x5e, 0x41, 0x36, 0xb5, 0x57,
+  0x8c, 0x13, 0xff, 0xda, 0xe7, 0x7a, 0x4a, 0xd5, 0xac, 0xd0, 0x40, 0xab,
+  0x88, 0xb4, 0x11, 0x0e, 0x00, 0x01, 0x52, 0x45, 0x1f, 0xad, 0x82, 0x65,
+  0x29, 0x9b, 0xc9, 0xea, 0xe4, 0x9b, 0x9d, 0x4e, 0x74, 0x11, 0x44, 0x0e,
+  0x21, 0x1a, 0x8f, 0x80, 0x00, 0x00, 0x00, 0xff, 0x31, 0x68, 0xa2, 0xc1,
+  0xd0, 0xa3, 0x10, 0x09, 0x56, 0x6f, 0x4b, 0x25, 0x6a, 0x0d, 0x58, 0xcd,
+  0x5d, 0x53, 0x7c, 0x32, 0xc5, 0x00, 0x09, 0x34, 0x7b, 0xe6, 0xa3, 0x1f,
+  0xc4, 0x4a, 0xc1, 0xba, 0x16, 0xf1, 0xff, 0x2c, 0x75, 0x30, 0xf0, 0x5e,
+  0x68, 0xcf, 0x7a, 0xa2, 0x23, 0x69, 0x71, 0x59, 0x5b, 0xf7, 0xf4, 0x37,
+  0x06, 0x75, 0xc8, 0xa4, 0x2c, 0xcf, 0xcd, 0xe4, 0x59, 0xdc, 0xcd, 0x59,
+  0xae, 0x34, 0x7c, 0x2c, 0x36, 0xbb, 0x94, 0xc1, 0xdb, 0x70, 0xe6, 0xf3,
+  0x04, 0x9b, 0x09, 0x5e, 0x94, 0xc9, 0x2d, 0xd9, 0x23, 0x78, 0xf7, 0x9a,
+  0x49, 0xcd, 0xa2, 0x8d, 0xf5, 0xab, 0x5c, 0x27, 0x5f, 0x8c, 0xaf, 0xd3,
+  0x4f, 0x9a, 0x00, 0xca, 0xf5, 0x55, 0x79, 0x77, 0x89, 0x80, 0xa9, 0x45,
+  0xe9, 0x02, 0x05, 0xc1, 0x02, 0xb7, 0x51, 0x42, 0x10, 0x01, 0x2b, 0x7e,
+  0xa6, 0xa1, 0x42, 0xa9, 0x96, 0x8c, 0xa7, 0x32, 0x51, 0x5b, 0x40, 0x39,
+  0x00, 0x05, 0x95, 0xf3, 0x56, 0x7d, 0x6a, 0xc7, 0x81, 0xce, 0x5d, 0x80,
+  0x09, 0xd5, 0x20, 0x4d, 0xdd, 0xd0, 0x4c, 0x14, 0x20, 0xb1, 0x2b, 0x29,
+  0x97, 0x14, 0x9c, 0xf1, 0x6b, 0x0d, 0x38, 0xb4, 0x0b, 0x3a, 0x08, 0x0e,
+  0xc6, 0xfc, 0x16, 0x63, 0xf7, 0xa9, 0x9c, 0x8a, 0x7f, 0x31, 0xd1, 0xff,
+  0x65, 0xa9, 0x89, 0xac, 0x2d, 0xd5, 0x4c, 0x31, 0x1e, 0x91, 0xc7, 0xcb,
+  0xaa, 0xa4, 0x9a, 0xcc, 0x98, 0xef, 0x54, 0x93, 0x10, 0x70, 0x13, 0x70,
+  0x0d, 0x91, 0x77, 0x9b, 0xb8, 0xf1, 0xd7, 0x26, 0x7f, 0xf1, 0x97, 0xae,
+  0xdb, 0x57, 0xdf, 0x8d, 0xca, 0xa0, 0xe6, 0x6d, 0xd1, 0xb2, 0xb1, 0x5c,
+  0x5f, 0x2c, 0x3b, 0xb5, 0xbe, 0xb1, 0xd5, 0x94, 0x18, 0x31, 0x3d, 0xad,
+  0x4f, 0x36, 0x3b, 0x23, 0x17, 0xd0, 0xac, 0xe6, 0x28, 0xee, 0xe3, 0xc3,
+  0xa2, 0xb1, 0x4d, 0xb9, 0x37, 0xe4, 0x57, 0x34, 0x31, 0x56, 0x29, 0x89,
+  0xe7, 0xd8, 0x8b, 0x65, 0xb5, 0x70, 0xdb, 0x38, 0x46, 0x65, 0x59, 0xc2,
+  0x90, 0x8a, 0xbc, 0xc2, 0x8c, 0x35, 0x3e, 0x0e, 0x5a, 0x61, 0x1a, 0xdb,
+  0x30, 0xa2, 0x50, 0x77, 0x3b, 0x75, 0x2a, 0x1b, 0xaa, 0xf2, 0x31, 0xba,
+  0x83, 0x93, 0x8a, 0xba, 0x82, 0x4e, 0x6c, 0x57, 0x86, 0x96, 0xd9, 0x59,
+  0xb2, 0xc7, 0x45, 0xd1, 0xeb, 0x51, 0x39, 0xe6, 0xbd, 0xdc, 0x70, 0xd3,
+  0xc2, 0x17, 0xa5, 0x29, 0xcf, 0x19, 0xf1, 0xf1, 0x62, 0x8b, 0x25, 0x7f,
+  0xbc, 0x0b, 0x29, 0x78, 0xa1, 0xf6, 0xc5, 0xb2, 0xf7, 0x5f, 0xcb, 0x84,
+  0xb8, 0xdc, 0x1b, 0x73, 0x58, 0x1a, 0x33, 0x4c, 0xaa, 0x55, 0x2c, 0xae,
+  0x4a, 0x32, 0x25, 0x19, 0x83, 0x81, 0xa7, 0x2a, 0x40, 0xe0, 0x21, 0x1a,
+  0x8f, 0x80, 0x00, 0x00, 0x0f, 0xff, 0x3f, 0x6a, 0x84, 0xa0, 0x86, 0xa9,
+  0xb7, 0xc1, 0x15, 0x2a, 0x95, 0xa1, 0x5a, 0x38, 0x69, 0xab, 0xa3, 0x03,
+  0x80, 0x19, 0x6b, 0x72, 0x7e, 0x65, 0x7c, 0xb6, 0xe3, 0xe8, 0x9c, 0x66,
+  0xbc, 0xe1, 0x41, 0x73, 0xea, 0x42, 0xdc, 0x4f, 0xdc, 0x35, 0xfd, 0x73,
+  0xcf, 0x48, 0xeb, 0xfb, 0xb7, 0xe0, 0x22, 0x8b, 0x7f, 0x9b, 0x40, 0x89,
+  0x38, 0x09, 0x4f, 0x86, 0x1b, 0x02, 0x9f, 0x17, 0x88, 0x9b, 0x0d, 0xa5,
+  0xe0, 0x39, 0x2b, 0xc6, 0x22, 0x45, 0x62, 0x37, 0xe4, 0x43, 0x2d, 0xb8,
+  0x8d, 0xc0, 0x6f, 0x5f, 0x6e, 0xec, 0x7c, 0xbb, 0x94, 0x20, 0x8b, 0xc9,
+  0x9f, 0x94, 0x2c, 0x15, 0xaa, 0xb1, 0x02, 0x62, 0x27, 0x12, 0x79, 0xe4,
+  0x04, 0x00, 0x9d, 0x66, 0xcb, 0x7a, 0xfc, 0x5e, 0x99, 0xc4, 0x4c, 0x59,
+  0x18, 0xa8, 0x81, 0xd8, 0x5b, 0xaa, 0x80, 0x00, 0x55, 0x64, 0xf6, 0x01,
+  0x97, 0x21, 0x0f, 0x6a, 0xf9, 0x7e, 0x74, 0x50, 0xc8, 0xb2, 0xe0, 0x14,
+  0x16, 0xfa, 0x39, 0x14, 0x5e, 0x90, 0x1d, 0xad, 0x1c, 0x01, 0xad, 0xfb,
+  0x21, 0x71, 0xd1, 0x68, 0x8a, 0x07, 0xa6, 0x42, 0x3c, 0x24, 0x6d, 0x55,
+  0x2f, 0x7f, 0x72, 0xf1, 0xaa, 0xc8, 0x3e, 0xbf, 0x42, 0x80, 0x95, 0x73,
+  0x37, 0x3b, 0xa1, 0xc7, 0x06, 0xd7, 0x7c, 0xad, 0xeb, 0xf9, 0xdc, 0x7d,
+  0xf1, 0x41, 0x03, 0x47, 0xf7, 0xf7, 0x4f, 0x71, 0xf7, 0xe7, 0x72, 0x9e,
+  0x93, 0xe5, 0x8c, 0x8d, 0xb7, 0x37, 0x3d, 0xe3, 0xcf, 0x3c, 0xab, 0x33,
+  0x07, 0xa8, 0xf5, 0xee, 0x38, 0xce, 0x3b, 0xf9, 0x3c, 0xda, 0x73, 0xe1,
+  0xb1, 0x2a, 0x6a, 0x59, 0x7b, 0x0c, 0xa2, 0x40, 0x1a, 0xb5, 0xc5, 0xbd,
+  0xb2, 0x7f, 0x5d, 0x36, 0xe0, 0x9d, 0x8c, 0xae, 0x0a, 0x30, 0xdc, 0xb6,
+  0x17, 0x4e, 0xf1, 0x6f, 0xa2, 0x50, 0xaa, 0x23, 0xa8, 0xe0, 0x47, 0x27,
+  0x0d, 0xef, 0x49, 0x4f, 0xdf, 0xb4, 0xc9, 0xd1, 0x3a, 0xbe, 0x11, 0x42,
+  0xa5, 0x38, 0xad, 0xd6, 0xd0, 0x8f, 0xa0, 0x93, 0x89, 0x0e, 0xfd, 0x14,
+  0xd8, 0x86, 0x08, 0xf0, 0x81, 0xba, 0x95, 0x52, 0x6c, 0xcc, 0x8a, 0x0b,
+  0xda, 0x62, 0x10, 0x04, 0x50, 0x2b, 0xda, 0xe4, 0xce, 0x62, 0x12, 0xa4,
+  0x00, 0x83, 0x72, 0x81, 0x02, 0x96, 0xb2, 0xa9, 0x21, 0x10, 0x00, 0x38,
+  0x21, 0x1a, 0x8a, 0x00, 0x00, 0x00, 0x01, 0xff, 0x37, 0x65, 0xa4, 0xd8,
+  0xe8, 0x6c, 0x3a, 0x13, 0x08, 0x5e, 0x0b, 0xd5, 0x64, 0xaa, 0xd5, 0x54,
+  0xd1, 0x1a, 0x5c, 0x0b, 0x01, 0x0e, 0x02, 0x47, 0xef, 0x0f, 0x26, 0xc9,
+  0xa0, 0xc1, 0x81, 0x36, 0x65, 0x73, 0x52, 0xd8, 0xac, 0x42, 0x5f, 0x8a,
+  0xe6, 0x3b, 0x57, 0xea, 0xef, 0x38, 0x5b, 0x1d, 0x62, 0x33, 0x45, 0x26,
+  0x95, 0xa3, 0xa5, 0x99, 0x76, 0x4f, 0xf7, 0x7f, 0x9b, 0xe6, 0x55, 0xca,
+  0x29, 0xbe, 0x0a, 0xe1, 0x8c, 0x31, 0xa0, 0x12, 0x34, 0x58, 0x56, 0x17,
+  0xa4, 0xf5, 0x67, 0x66, 0x69, 0x0c, 0x55, 0x15, 0x9f, 0x98, 0x52, 0xe3,
+  0x6b, 0xfc, 0x3d, 0x1d, 0x86, 0xd1, 0x86, 0xc2, 0xfd, 0xf6, 0xf3, 0x20,
+  0xa4, 0x8a, 0x1b, 0x25, 0xf8, 0x2f, 0x74, 0xad, 0xdb, 0xae, 0xe8, 0x83,
+  0x5b, 0x1e, 0x79, 0xdd, 0x5a, 0x3e, 0x34, 0x21, 0x9c, 0xfb, 0x72, 0xa0,
+  0x1f, 0x2c, 0x05, 0xd7, 0xec, 0xf4, 0xea, 0xc8, 0x60, 0x90, 0xc6, 0x9c,
+  0xc4, 0xb9, 0x51, 0x3d, 0x79, 0xd3, 0x6d, 0xb4, 0x26, 0x79, 0xd8, 0x45,
+  0x08, 0x82, 0x15, 0xb7, 0x39, 0x72, 0x4c, 0x18, 0x93, 0xbc, 0x52, 0x12,
+  0x5a, 0x05, 0x2d, 0x2b, 0xca, 0xe1, 0x22, 0x84, 0xaf, 0x6b, 0x25, 0x71,
+  0x9a, 0x57, 0x5d, 0xc7, 0xd7, 0x78, 0xff, 0x45, 0x48, 0xd1, 0x28, 0xda,
+  0x69, 0x98, 0x07, 0x52, 0xa0, 0x00, 0x8f, 0xe5, 0x7b, 0xed, 0x6e, 0x67,
+  0x00, 0x9b, 0xb8, 0xd1, 0x58, 0xa2, 0xf5, 0x46, 0xfc, 0x2e, 0xd6, 0xaa,
+  0xeb, 0x34, 0x17, 0x77, 0x22, 0x1a, 0xa3, 0xa2, 0xcb, 0x06, 0xec, 0xf1,
+  0x12, 0xb0, 0x6e, 0x66, 0xce, 0xd1, 0xa7, 0xa4, 0xd2, 0x4c, 0x34, 0xb7,
+  0x32, 0x6a, 0x7d, 0x47, 0xd6, 0x5a, 0x97, 0x08, 0x20, 0x30, 0xf4, 0xd7,
+  0x9b, 0x4a, 0x91, 0x37, 0x07, 0x12, 0xe6, 0x0e, 0x62, 0xf2, 0xbe, 0xb2,
+  0xab, 0x3e, 0x6e, 0x07, 0xc7, 0x9f, 0x19, 0xeb, 0xc9, 0x7c, 0x8f, 0x52,
+  0xc8, 0x9c, 0xc3, 0x99, 0x9f, 0x73, 0x16, 0xa1, 0x2a, 0x9a, 0xf8, 0x5a,
+  0x47, 0xc3, 0x20, 0x17, 0xbb, 0x27, 0x6a, 0x4f, 0xe4, 0xfc, 0xac, 0x4d,
+  0xaf, 0xaa, 0xbf, 0xf2, 0xc4, 0xd2, 0x2a, 0xbc, 0x6b, 0x7e, 0x9f, 0x4d,
+  0x96, 0xe0, 0x0d, 0xdc, 0xb1, 0xcf, 0xb0, 0x78, 0x3a, 0xe3, 0x56, 0x8e,
+  0x91, 0x13, 0xd3, 0xf6, 0x59, 0x61, 0x00, 0xf8, 0x4b, 0xa4, 0x72, 0xcb,
+  0x26, 0xdb, 0x66, 0x74, 0x65, 0xd5, 0xa2, 0x71, 0xb1, 0x44, 0x65, 0x47,
+  0x06, 0xc9, 0x73, 0x1b, 0xa2, 0x96, 0x03, 0xa4, 0x60, 0xa0, 0x88, 0xde,
+  0x38, 0x75, 0xf6, 0xf6, 0xe5, 0xd6, 0xda, 0xe1, 0x5b, 0xda, 0x97, 0x10,
+  0x4f, 0xa6, 0x6c, 0x31, 0xdf, 0x2c, 0x1b, 0x97, 0x50, 0xb1, 0x78, 0xcd,
+  0xba, 0xfd, 0x10, 0xa3, 0x92, 0x43, 0x1a, 0x66, 0xa3, 0x21, 0x11, 0x10,
+  0x2a, 0x8a, 0x94, 0xd0, 0x2d, 0xd3, 0x12, 0xeb, 0x80, 0x9c, 0x77, 0x38,
+  0xc1, 0x30, 0x0e, 0x21, 0x1a, 0x8e, 0x80, 0x04, 0x0f, 0x01, 0xbf, 0x33,
+  0x67, 0xa3, 0xd8, 0x60, 0xa8, 0x36, 0x18, 0xc0, 0x11, 0xe2, 0x5c, 0xc6,
+  0xa5, 0x62, 0xe2, 0xd1, 0x6b, 0xd6, 0xa1, 0x85, 0xc0, 0x1c, 0x18, 0x88,
+  0x91, 0xa4, 0x3e, 0x3b, 0x9b, 0xb9, 0xd7, 0x21, 0x07, 0xbc, 0x34, 0x47,
+  0x8e, 0xf6, 0x56, 0x9d, 0x84, 0x6c, 0xfc, 0x1b, 0x16, 0x05, 0x71, 0xaa,
+  0x12, 0x53, 0x3d, 0x5b, 0xc4, 0xa4, 0x9b, 0xbb, 0xb9, 0xd8, 0x7f, 0xd0,
+  0x6c, 0x8d, 0x8b, 0x84, 0xdf, 0xf3, 0xe7, 0x5b, 0x68, 0x33, 0x4f, 0x41,
+  0xaa, 0xca, 0xbf, 0x6f, 0xbc, 0x95, 0x1c, 0x37, 0xa2, 0xd4, 0xd0, 0xce,
+  0x25, 0x57, 0x43, 0xb9, 0x4f, 0x53, 0xc5, 0x93, 0x04, 0xe2, 0xba, 0x39,
+  0x68, 0xd1, 0xfe, 0x0a, 0xaa, 0xb3, 0xa8, 0xd9, 0x30, 0xbd, 0x9a, 0x67,
+  0x0b, 0x6c, 0x29, 0xef, 0x08, 0x4d, 0x51, 0x82, 0x93, 0x32, 0xce, 0x82,
+  0x00, 0xa8, 0x07, 0x83, 0x77, 0x6a, 0xc1, 0x23, 0x50, 0x0b, 0x45, 0x25,
+  0x60, 0x1e, 0x68, 0x01, 0x75, 0xa4, 0x4b, 0x33, 0xad, 0x1e, 0x9f, 0xd0,
+  0x01, 0x6e, 0xb1, 0xbc, 0x27, 0x44, 0x5b, 0xae, 0x08, 0xdf, 0x32, 0x4a,
+  0xd2, 0x3c, 0xb0, 0x01, 0x38, 0xee, 0x13, 0xa6, 0x99, 0x2d, 0x1d, 0x83,
+  0x73, 0x13, 0x74, 0x6a, 0xdd, 0xa8, 0x26, 0xed, 0xd4, 0x84, 0x08, 0x0c,
+  0x54, 0x41, 0x12, 0x99, 0x8d, 0x89, 0x16, 0xa9, 0x15, 0xc4, 0x8e, 0x85,
+  0xb8, 0x97, 0x0b, 0x4a, 0x0d, 0xc8, 0xc5, 0xd9, 0x1b, 0xb3, 0x2e, 0x34,
+  0x8b, 0xf3, 0x67, 0xc7, 0xd6, 0x83, 0xe1, 0xdb, 0x9a, 0xb7, 0x27, 0xd4,
+  0x74, 0x63, 0xe3, 0x75, 0xf6, 0x54, 0xca, 0x3e, 0x65, 0xa7, 0xdd, 0x98,
+  0x6d, 0xb5, 0x8a, 0x61, 0xaf, 0xeb, 0x6b, 0x9d, 0xa5, 0xd0, 0xf3, 0xfe,
+  0xd1, 0x8c, 0xf7, 0xe7, 0xd9, 0xfd, 0x32, 0xcb, 0xf6, 0x6b, 0x6e, 0xd6,
+  0x61, 0xed, 0xb6, 0x01, 0x69, 0x1d, 0xd1, 0xf2, 0x1c, 0xc6, 0xca, 0xaf,
+  0x0d, 0x1d, 0xc6, 0xae, 0x78, 0xf8, 0xdc, 0x3f, 0x29, 0xc0, 0xf9, 0x16,
+  0x70, 0x5a, 0xdc, 0x3f, 0x63, 0xac, 0xc0, 0xd9, 0x97, 0x57, 0xf3, 0x8c,
+  0x4c, 0x16, 0x71, 0x42, 0xb5, 0x57, 0xc3, 0x70, 0x89, 0x52, 0xe4, 0x11,
+  0xf5, 0x5e, 0xff, 0x85, 0x3f, 0x7d, 0xeb, 0xc7, 0x26, 0xc9, 0x95, 0x12,
+  0x2b, 0x4e, 0x33, 0x26, 0x02, 0x7d, 0x48, 0xbb, 0x64, 0x7f, 0x1e, 0xd6,
+  0x14, 0xe9, 0x40, 0x94, 0x92, 0x4a, 0x45, 0xed, 0x24, 0x37, 0x76, 0xb5,
+  0xfe, 0xc8, 0xb9, 0x91, 0x11, 0xd3, 0x68, 0x74, 0x6c, 0x73, 0x88, 0x46,
+  0x4a, 0x50, 0x8a, 0xf3, 0x82, 0xc0, 0xe0, 0x21, 0x1a, 0x8e, 0x00, 0x9e,
+  0x0f, 0x1f, 0xff, 0x33, 0x65, 0xa7, 0x31, 0x86, 0x20, 0x55, 0xa9, 0xce,
+  0x32, 0xd9, 0xd1, 0x68, 0x4b, 0xf3, 0x70, 0x09, 0x6b, 0x2d, 0x94, 0x38,
+  0x02, 0x47, 0x2e, 0x64, 0x9d, 0x01, 0xf5, 0x6b, 0x1c, 0x76, 0x31, 0x48,
+  0x30, 0xf9, 0x7f, 0x1e, 0x9b, 0x00, 0x0a, 0x49, 0xb4, 0xf8, 0x6a, 0x07,
+  0xda, 0xa5, 0x6e, 0x0e, 0xf1, 0x9b, 0xd5, 0x97, 0xee, 0x86, 0xe2, 0x96,
+  0x35, 0x86, 0x21, 0xc0, 0x6e, 0x78, 0x4f, 0x0d, 0x21, 0x6a, 0x74, 0xce,
+  0x79, 0xc0, 0xde, 0x68, 0x8b, 0xaa, 0xea, 0xf1, 0xe2, 0x94, 0x18, 0xa8,
+  0x3b, 0x65, 0x58, 0x10, 0xcb, 0xf8, 0x7e, 0x2a, 0x13, 0xc5, 0xf5, 0xa4,
+  0x66, 0xa3, 0x3c, 0xe6, 0xa2, 0x04, 0x84, 0x04, 0xa8, 0x48, 0x57, 0xb8,
+  0x64, 0xa7, 0x26, 0x56, 0xe3, 0x22, 0xdc, 0x00, 0xa5, 0x00, 0x7f, 0x7a,
+  0xdc, 0x46, 0x51, 0x85, 0xec, 0x56, 0x65, 0x4d, 0xa7, 0xd6, 0xff, 0x87,
+  0xef, 0xa0, 0xb0, 0x84, 0x04, 0xd5, 0x26, 0x46, 0x69, 0xb8, 0x9f, 0xdc,
+  0xcc, 0x23, 0x7a, 0x41, 0x2d, 0x28, 0x53, 0x37, 0xc9, 0x9e, 0x8a, 0x2d,
+  0x24, 0xa0, 0x69, 0x2c, 0x28, 0x44, 0xca, 0x0a, 0x02, 0x2c, 0x88, 0x65,
+  0xdb, 0x44, 0xe4, 0xb0, 0x52, 0x5b, 0xa9, 0x0c, 0x10, 0x22, 0x08, 0x5a,
+  0xf6, 0x3c, 0x50, 0x5e, 0x81, 0x34, 0x35, 0xe6, 0xda, 0x85, 0x90, 0x80,
+  0x60, 0x31, 0x4d, 0xf5, 0x5f, 0xe2, 0x1d, 0xee, 0x0e, 0x32, 0xc3, 0xbe,
+  0xa7, 0x78, 0xfa, 0x64, 0xcc, 0x16, 0x54, 0x9b, 0x8f, 0xa9, 0xf3, 0x4d,
+  0xb3, 0x14, 0x58, 0x32, 0x1c, 0xc9, 0x29, 0xf3, 0xdc, 0x95, 0x03, 0x92,
+  0xb4, 0x3c, 0x5d, 0xbd, 0x11, 0xfb, 0x2b, 0x62, 0xa1, 0x66, 0xbc, 0xb8,
+  0x71, 0x02, 0xe0, 0x62, 0x83, 0x89, 0xc8, 0xd1, 0x16, 0x55, 0x0f, 0xb8,
+  0x7c, 0x04, 0x6c, 0xd7, 0xae, 0x02, 0x3e, 0xb2, 0x93, 0xaf, 0x2f, 0xcb,
+  0x4c, 0x36, 0x85, 0x32, 0xf1, 0x0c, 0xac, 0xb0, 0x5a, 0xd5, 0x5e, 0x87,
+  0xe0, 0xe5, 0x29, 0x56, 0xc5, 0xab, 0xc2, 0x43, 0xf5, 0x81, 0x3c, 0x07,
+  0x88, 0x45, 0x05, 0xb8, 0x18, 0x67, 0xf0, 0xfb, 0xfe, 0xbe, 0x60, 0x8a,
+  0x35, 0x44, 0x51, 0xbc, 0x5d, 0x5a, 0x54, 0x98, 0x98, 0x39, 0x4e, 0x96,
+  0x5d, 0x24, 0xe7, 0x23, 0x15, 0x4a, 0xc2, 0x6a, 0x24, 0x5b, 0x74, 0x80,
+  0x80, 0x22, 0x23, 0x14, 0x97, 0x79, 0xbf, 0x50, 0x07, 0x21, 0x1a, 0x8f,
+  0xc0, 0x3e, 0x3f, 0xfe, 0xff, 0x3b, 0x68, 0xa3, 0x58, 0xe0, 0xec, 0x24,
+  0x10, 0xb8, 0xdf, 0x15, 0x2e, 0x77, 0xc2, 0x29, 0x4b, 0x2e, 0x4a, 0x59,
+  0x1c, 0x23, 0x0e, 0x0b, 0x2d, 0x94, 0xbc, 0x00, 0x97, 0x1c, 0xe2, 0x7f,
+  0x48, 0x1f, 0x23, 0x98, 0xe4, 0x8f, 0x5b, 0x72, 0x5b, 0x72, 0x03, 0x7b,
+  0x47, 0x2d, 0x53, 0xb4, 0xdf, 0x96, 0x90, 0xba, 0xe5, 0x01, 0x62, 0xd3,
+  0x5a, 0x97, 0x95, 0xae, 0xd3, 0x2a, 0x4b, 0x75, 0x3b, 0x39, 0xa4, 0x32,
+  0xf5, 0xbc, 0xe6, 0xe7, 0xca, 0x4b, 0x56, 0xe0, 0x3b, 0x77, 0x52, 0xb8,
+  0xe6, 0x64, 0xa9, 0x78, 0xde, 0x86, 0x87, 0x4a, 0xc2, 0x7d, 0x8f, 0x22,
+  0x37, 0xbd, 0xb9, 0x77, 0xec, 0xd7, 0x6f, 0x65, 0xd4, 0xec, 0xd8, 0x50,
+  0x92, 0x28, 0x15, 0x35, 0x93, 0x6d, 0xf9, 0xf5, 0xd7, 0x90, 0xb4, 0x28,
+  0xc6, 0x25, 0xc3, 0x3a, 0xd9, 0x21, 0xeb, 0x69, 0xf7, 0xed, 0x76, 0x95,
+  0xb6, 0xd3, 0xdf, 0xc1, 0x4e, 0xb2, 0xd3, 0x60, 0x51, 0x5d, 0x00, 0x57,
+  0x55, 0x97, 0x36, 0x5a, 0xd6, 0x27, 0x22, 0xa1, 0x51, 0x83, 0xe1, 0xc9,
+  0x02, 0x0c, 0x06, 0x93, 0xc9, 0x1d, 0xe2, 0xf5, 0x90, 0x02, 0x44, 0x00,
+  0x8d, 0xa5, 0xf4, 0x9d, 0x33, 0x64, 0xc9, 0xbe, 0x22, 0xc1, 0x5b, 0xf9,
+  0x4c, 0x31, 0x77, 0xdb, 0x18, 0xcd, 0x2b, 0x8a, 0xa0, 0x05, 0x3b, 0x2a,
+  0x17, 0x2a, 0x05, 0xe5, 0xbe, 0x51, 0xab, 0x9f, 0x49, 0x74, 0x6a, 0xb8,
+  0x4e, 0x5a, 0xa8, 0x6c, 0x5a, 0x1a, 0x04, 0x0c, 0x23, 0x01, 0xa0, 0x40,
+  0x62, 0x42, 0x9b, 0x52, 0xd7, 0x4a, 0x35, 0x75, 0x6b, 0xfc, 0x22, 0xec,
+  0x5b, 0x29, 0x78, 0x01, 0x2e, 0x39, 0x12, 0x27, 0x8a, 0x76, 0x47, 0x3f,
+  0xac, 0x91, 0xdc, 0x70, 0xea, 0x33, 0xca, 0x26, 0x60, 0xe6, 0xee, 0x8a,
+  0x76, 0xc9, 0xa1, 0xa8, 0x83, 0xde, 0x5c, 0xc3, 0x71, 0xdb, 0x52, 0x6d,
+  0x2f, 0x9a, 0x8f, 0x0c, 0x96, 0x93, 0x59, 0xd4, 0x31, 0x1e, 0xa1, 0x79,
+  0x73, 0x14, 0xcb, 0x95, 0xc4, 0xaa, 0xf7, 0x94, 0xd3, 0x52, 0x7d, 0xfe,
+  0x8f, 0x50, 0xf2, 0x8e, 0x39, 0x8c, 0xac, 0x40, 0x40, 0x92, 0xef, 0x72,
+  0xe8, 0x19, 0x72, 0x36, 0xb5, 0x8c, 0x6e, 0x30, 0x3f, 0x79, 0xef, 0x47,
+  0xb5, 0xe5, 0xbf, 0x57, 0xf8, 0x94, 0x80, 0x11, 0x12, 0x9d, 0xa2, 0xe4,
+  0xbf, 0x84, 0xa3, 0xeb, 0x68, 0x3b, 0x4f, 0xae, 0x58, 0x73, 0xf5, 0x63,
+  0x0c, 0x60, 0x11, 0x94, 0x60, 0x1c
+};
+
+guint seg_1_m4f_len = 49554;
+guint seg_1_moof_size = 1120;
+guint seg_1_sample_0_offset = 1128;
+
+static const guint seg_1_sample_sizes[] = {
+  371, 372, 477, 530, 489, 462, 441, 421, 420, 410, 402, 398, 381, 381, 386,
+  386, 369, 370, 362, 346, 357, 355, 376, 336, 341, 358, 350, 362, 333, 415,
+  386, 364, 344, 386, 358, 365, 404, 342, 361, 366, 361, 350, 390, 348, 366,
+  359, 357, 360, 349, 356, 365, 393, 353, 385, 381, 348, 345, 414, 372, 369,
+  401, 391, 333, 339, 423, 343, 445, 425, 422, 415, 406, 389, 395, 375, 356,
+  442, 432, 391, 385, 339, 277, 293, 316, 327, 309, 389, 359, 427, 326, 420,
+  407, 316, 362, 419, 349, 387, 326, 328, 367, 344, 425, 329, 379, 403, 314,
+  397, 368, 389, 380, 373, 342, 343, 368, 436, 359, 352, 361, 366, 350, 419,
+  331, 426, 401, 382, 326, 411, 364, 338, 345
+};
+
+/* in timescale */
+GstClockTime seg_1_sample_duration = 1024;
+guint32 seg_1_timescale = 44100;
diff --git a/tests/check/elements/qtmux.c b/tests/check/elements/qtmux.c
new file mode 100644
index 0000000..642b409
--- /dev/null
+++ b/tests/check/elements/qtmux.c
@@ -0,0 +1,1628 @@
+/* GStreamer
+ *
+ * unit test for qtmux
+ *
+ * Copyright (C) <2008> Mark Nauwelaerts <mnauw@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <glib/gstdio.h>
+
+#include <gst/check/gstcheck.h>
+#include <gst/pbutils/encoding-profile.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+static GstPad *mysrcpad, *mysinkpad;
+
+#define VIDEO_RAW_CAPS_STRING "video/x-raw"
+
+#define AUDIO_CAPS_STRING "audio/mpeg, " \
+                        "mpegversion = (int) 1, " \
+                        "layer = (int) 3, " \
+                        "channels = (int) 2, " \
+                        "rate = (int) 48000"
+
+#define AUDIO_AAC_TMPL_CAPS_STRING "audio/mpeg, " \
+                                   "mpegversion=(int)4, " \
+                                   "channels=(int)1, " \
+                                   "rate=(int)44100, " \
+                                   "stream-format=(string)raw, " \
+                                   "level=(string)2, " \
+                                   "base-profile=(string)lc, " \
+                                   "profile=(string)lc"
+/* codec_data shouldn't be in the template caps, only in the actual caps */
+#define AUDIO_AAC_CAPS_STRING AUDIO_AAC_TMPL_CAPS_STRING \
+                              ", codec_data=(buffer)1208"
+
+#define VIDEO_CAPS_STRING "video/mpeg, " \
+                           "mpegversion = (int) 4, " \
+                           "systemstream = (boolean) false, " \
+                           "width = (int) 384, " \
+                           "height = (int) 288, " \
+                           "framerate = (fraction) 25/1"
+
+#define VIDEO_TMPL_CAPS_H264_STRING "video/x-h264, " \
+                                    "width=(int)320, " \
+                                    "height=(int)240, " \
+                                    "framerate=(fraction)30/1, " \
+                                    "pixel-aspect-ratio=(fraction)1/1, " \
+                                    "stream-format=(string)avc, " \
+                                    "alignment=(string)au, " \
+                                    "level=(string)2, " \
+                                    "profile=(string)high"
+/* codec_data shouldn't be in the template caps, only in the actual caps */
+#define VIDEO_CAPS_H264_STRING VIDEO_TMPL_CAPS_H264_STRING \
+                               ", codec_data=(buffer)01640014ffe1001867640014a" \
+                                   "cd94141fb0110000003001773594000f14299600" \
+                                   "1000568ebecb22c"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/quicktime"));
+
+static GstStaticPadTemplate srcvideotemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (VIDEO_CAPS_STRING));
+
+static GstStaticPadTemplate srcvideoh264template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (VIDEO_TMPL_CAPS_H264_STRING));
+
+static GstStaticPadTemplate srcvideorawtemplate =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (VIDEO_RAW_CAPS_STRING));
+
+static GstStaticPadTemplate srcaudiotemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (AUDIO_CAPS_STRING));
+
+static GstStaticPadTemplate srcaudioaactemplate =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (AUDIO_AAC_TMPL_CAPS_STRING));
+
+/* setup and teardown needs some special handling for muxer */
+static GstPad *
+setup_src_pad (GstElement * element,
+    GstStaticPadTemplate * template, const gchar * sinkname)
+{
+  GstPad *srcpad, *sinkpad;
+
+  GST_DEBUG_OBJECT (element, "setting up sending pad");
+  /* sending pad */
+  srcpad = gst_pad_new_from_static_template (template, "src");
+  fail_if (srcpad == NULL, "Could not create a srcpad");
+  ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1);
+
+  if (!(sinkpad = gst_element_get_static_pad (element, sinkname)))
+    sinkpad = gst_element_get_request_pad (element, sinkname);
+  fail_if (sinkpad == NULL, "Could not get sink pad from %s",
+      GST_ELEMENT_NAME (element));
+  /* references are owned by: 1) us, 2) qtmux, 3) collect pads */
+  ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3);
+  fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK,
+      "Could not link source and %s sink pads", GST_ELEMENT_NAME (element));
+  gst_object_unref (sinkpad);   /* because we got it higher up */
+
+  /* references are owned by: 1) qtmux, 2) collect pads */
+  ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
+
+  return srcpad;
+}
+
+static void
+teardown_src_pad (GstPad * srcpad)
+{
+  GstPad *sinkpad;
+
+  /* clean up floating src pad */
+  sinkpad = gst_pad_get_peer (srcpad);
+  fail_if (sinkpad == NULL);
+  /* pad refs held by 1) qtmux 2) collectpads and 3) us (through _get_peer) */
+  ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3);
+
+  gst_pad_unlink (srcpad, sinkpad);
+
+  /* after unlinking, pad refs still held by
+   * 1) qtmux and 2) collectpads and 3) us (through _get_peer) */
+  ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3);
+  gst_object_unref (sinkpad);
+  /* one more ref is held by element itself */
+
+  /* pad refs held by creator */
+  ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1);
+  gst_object_unref (srcpad);
+}
+
+gboolean downstream_is_seekable;
+static gboolean
+qtmux_sinkpad_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  gboolean ret = FALSE;
+
+  if (GST_QUERY_TYPE (query) == GST_QUERY_SEEKING) {
+    gst_query_set_seeking (query, GST_FORMAT_BYTES, downstream_is_seekable, 0,
+        -1);
+    ret = TRUE;
+  }
+
+  return ret;
+}
+
+static GstElement *
+setup_qtmux (GstStaticPadTemplate * srctemplate, const gchar * sinkname,
+    gboolean seekable)
+{
+  GstElement *qtmux;
+
+  GST_DEBUG ("setup_qtmux");
+  qtmux = gst_check_setup_element ("qtmux");
+  mysrcpad = setup_src_pad (qtmux, srctemplate, sinkname);
+  mysinkpad = gst_check_setup_sink_pad (qtmux, &sinktemplate);
+
+  downstream_is_seekable = seekable;
+  gst_pad_set_query_function (mysinkpad, qtmux_sinkpad_query);
+
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return qtmux;
+}
+
+static void
+cleanup_qtmux (GstElement * qtmux, const gchar * sinkname)
+{
+  GST_DEBUG ("cleanup_qtmux");
+  gst_element_set_state (qtmux, GST_STATE_NULL);
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  teardown_src_pad (mysrcpad);
+  gst_check_teardown_sink_pad (qtmux);
+  gst_check_teardown_element (qtmux);
+}
+
+static void
+check_qtmux_pad (GstStaticPadTemplate * srctemplate, const gchar * sinkname,
+    guint32 dts_method)
+{
+  GstElement *qtmux;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  int num_buffers;
+  int i;
+  guint8 data0[12] = "\000\000\000\024ftypqt  ";
+  guint8 data1[16] = "\000\000\000\010free\000\000\000\000mdat";
+  guint8 data2[4] = "moov";
+  GstSegment segment;
+
+  qtmux = setup_qtmux (srctemplate, sinkname, TRUE);
+  g_object_set (qtmux, "dts-method", dts_method, NULL);
+  fail_unless (gst_element_set_state (qtmux,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test"));
+
+  caps = gst_pad_get_pad_template_caps (mysrcpad);
+  gst_pad_set_caps (mysrcpad, caps);
+  gst_caps_unref (caps);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  inbuffer = gst_buffer_new_and_alloc (1);
+  gst_buffer_memset (inbuffer, 0, 0, 1);
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  GST_BUFFER_DURATION (inbuffer) = 40 * GST_MSECOND;
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+
+  /* send eos to have moov written */
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE);
+
+  num_buffers = g_list_length (buffers);
+  /* at least expect ftyp, mdat header, buffer chunk and moov */
+  fail_unless (num_buffers >= 4);
+
+  /* clean up first to clear any pending refs in sticky caps */
+  cleanup_qtmux (qtmux, sinkname);
+
+  for (i = 0; i < num_buffers; ++i) {
+    outbuffer = GST_BUFFER (buffers->data);
+    fail_if (outbuffer == NULL);
+    buffers = g_list_remove (buffers, outbuffer);
+
+    switch (i) {
+      case 0:
+      {
+        /* ftyp header */
+        fail_unless (gst_buffer_get_size (outbuffer) >= 20);
+        fail_unless (gst_buffer_memcmp (outbuffer, 0, data0,
+                sizeof (data0)) == 0);
+        fail_unless (gst_buffer_memcmp (outbuffer, 16, data0 + 8, 4) == 0);
+        break;
+      }
+      case 1:                  /* mdat header */
+        fail_unless (gst_buffer_get_size (outbuffer) == 16);
+        fail_unless (gst_buffer_memcmp (outbuffer, 0, data1, sizeof (data1))
+            == 0);
+        break;
+      case 2:                  /* buffer we put in */
+        fail_unless (gst_buffer_get_size (outbuffer) == 1);
+        break;
+      case 3:                  /* moov */
+        fail_unless (gst_buffer_get_size (outbuffer) > 8);
+        fail_unless (gst_buffer_memcmp (outbuffer, 4, data2,
+                sizeof (data2)) == 0);
+        break;
+      default:
+        break;
+    }
+
+    ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
+    gst_buffer_unref (outbuffer);
+    outbuffer = NULL;
+  }
+
+  g_list_free (buffers);
+  buffers = NULL;
+}
+
+static void
+check_qtmux_pad_fragmented (GstStaticPadTemplate * srctemplate,
+    const gchar * sinkname, guint32 dts_method, gboolean streamable)
+{
+  GstElement *qtmux;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  int num_buffers;
+  int i;
+  guint8 data0[12] = "\000\000\000\024ftypqt  ";
+  guint8 data1[4] = "mdat";
+  guint8 data2[4] = "moov";
+  guint8 data3[4] = "moof";
+  guint8 data4[4] = "mfra";
+  GstSegment segment;
+
+  qtmux = setup_qtmux (srctemplate, sinkname, !streamable);
+  g_object_set (qtmux, "dts-method", dts_method, NULL);
+  g_object_set (qtmux, "fragment-duration", 2000, NULL);
+  g_object_set (qtmux, "streamable", streamable, NULL);
+  fail_unless (gst_element_set_state (qtmux,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test"));
+
+  caps = gst_pad_get_pad_template_caps (mysrcpad);
+  gst_pad_set_caps (mysrcpad, caps);
+  gst_caps_unref (caps);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  inbuffer = gst_buffer_new_and_alloc (1);
+  gst_buffer_memset (inbuffer, 0, 0, 1);
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  GST_BUFFER_DURATION (inbuffer) = 40 * GST_MSECOND;
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+
+  /* send eos to have all written */
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE);
+
+  num_buffers = g_list_length (buffers);
+  /* at least expect ftyp, moov, moof, mdat header, buffer chunk
+   * and optionally mfra */
+  fail_unless (num_buffers >= 5);
+
+  /* clean up first to clear any pending refs in sticky caps */
+  cleanup_qtmux (qtmux, sinkname);
+
+  for (i = 0; i < num_buffers; ++i) {
+    outbuffer = GST_BUFFER (buffers->data);
+    fail_if (outbuffer == NULL);
+    buffers = g_list_remove (buffers, outbuffer);
+
+    switch (i) {
+      case 0:
+      {
+        /* ftyp header */
+        fail_unless (gst_buffer_get_size (outbuffer) >= 20);
+        fail_unless (gst_buffer_memcmp (outbuffer, 0, data0,
+                sizeof (data0)) == 0);
+        fail_unless (gst_buffer_memcmp (outbuffer, 16, data0 + 8, 4) == 0);
+        break;
+      }
+      case 1:                  /* moov */
+        fail_unless (gst_buffer_get_size (outbuffer) > 8);
+        fail_unless (gst_buffer_memcmp (outbuffer, 4, data2,
+                sizeof (data2)) == 0);
+        break;
+      case 2:                  /* moof */
+        fail_unless (gst_buffer_get_size (outbuffer) > 8);
+        fail_unless (gst_buffer_memcmp (outbuffer, 4, data3,
+                sizeof (data3)) == 0);
+        break;
+      case 3:                  /* mdat header */
+        fail_unless (gst_buffer_get_size (outbuffer) == 8);
+        fail_unless (gst_buffer_memcmp (outbuffer, 4, data1,
+                sizeof (data1)) == 0);
+        break;
+      case 4:                  /* buffer we put in */
+        fail_unless (gst_buffer_get_size (outbuffer) == 1);
+        break;
+      case 5:                  /* mfra */
+        fail_unless (gst_buffer_get_size (outbuffer) > 8);
+        fail_unless (gst_buffer_memcmp (outbuffer, 4, data4,
+                sizeof (data4)) == 0);
+        break;
+      default:
+        break;
+    }
+
+    ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
+    gst_buffer_unref (outbuffer);
+    outbuffer = NULL;
+  }
+
+  g_list_free (buffers);
+  buffers = NULL;
+}
+
+/* dts-method dd */
+
+GST_START_TEST (test_video_pad_dd)
+{
+  check_qtmux_pad (&srcvideotemplate, "video_%u", 0);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_audio_pad_dd)
+{
+  check_qtmux_pad (&srcaudiotemplate, "audio_%u", 0);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_video_pad_frag_dd)
+{
+  check_qtmux_pad_fragmented (&srcvideotemplate, "video_%u", 0, FALSE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_audio_pad_frag_dd)
+{
+  check_qtmux_pad_fragmented (&srcaudiotemplate, "audio_%u", 0, FALSE);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_video_pad_frag_dd_streamable)
+{
+  check_qtmux_pad_fragmented (&srcvideotemplate, "video_%u", 0, TRUE);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_audio_pad_frag_dd_streamable)
+{
+  check_qtmux_pad_fragmented (&srcaudiotemplate, "audio_%u", 0, TRUE);
+}
+
+GST_END_TEST;
+
+/* dts-method reorder */
+
+GST_START_TEST (test_video_pad_reorder)
+{
+  check_qtmux_pad (&srcvideotemplate, "video_%u", 1);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_audio_pad_reorder)
+{
+  check_qtmux_pad (&srcaudiotemplate, "audio_%u", 1);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_video_pad_frag_reorder)
+{
+  check_qtmux_pad_fragmented (&srcvideotemplate, "video_%u", 1, FALSE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_audio_pad_frag_reorder)
+{
+  check_qtmux_pad_fragmented (&srcaudiotemplate, "audio_%u", 1, FALSE);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_video_pad_frag_reorder_streamable)
+{
+  check_qtmux_pad_fragmented (&srcvideotemplate, "video_%u", 1, TRUE);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_audio_pad_frag_reorder_streamable)
+{
+  check_qtmux_pad_fragmented (&srcaudiotemplate, "audio_%u", 1, TRUE);
+}
+
+GST_END_TEST;
+
+/* dts-method asc */
+
+GST_START_TEST (test_video_pad_asc)
+{
+  check_qtmux_pad (&srcvideotemplate, "video_%u", 2);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_audio_pad_asc)
+{
+  check_qtmux_pad (&srcaudiotemplate, "audio_%u", 2);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_video_pad_frag_asc)
+{
+  check_qtmux_pad_fragmented (&srcvideotemplate, "video_%u", 2, FALSE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_audio_pad_frag_asc)
+{
+  check_qtmux_pad_fragmented (&srcaudiotemplate, "audio_%u", 2, FALSE);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_video_pad_frag_asc_streamable)
+{
+  check_qtmux_pad_fragmented (&srcvideotemplate, "video_%u", 2, TRUE);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_audio_pad_frag_asc_streamable)
+{
+  check_qtmux_pad_fragmented (&srcaudiotemplate, "audio_%u", 2, TRUE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_reuse)
+{
+  GstElement *qtmux = setup_qtmux (&srcvideotemplate, "video_%u", TRUE);
+  GstBuffer *inbuffer;
+  GstCaps *caps;
+  GstSegment segment;
+
+  gst_element_set_state (qtmux, GST_STATE_PLAYING);
+  gst_element_set_state (qtmux, GST_STATE_NULL);
+  gst_element_set_state (qtmux, GST_STATE_PLAYING);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test"));
+
+  caps = gst_pad_get_pad_template_caps (mysrcpad);
+  gst_pad_set_caps (mysrcpad, caps);
+  gst_caps_unref (caps);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  inbuffer = gst_buffer_new_and_alloc (1);
+  fail_unless (inbuffer != NULL);
+  gst_buffer_memset (inbuffer, 0, 0, 1);
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  GST_BUFFER_DURATION (inbuffer) = 40 * GST_MSECOND;
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+
+  /* send eos to have all written */
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE);
+
+  cleanup_qtmux (qtmux, "video_%u");
+  gst_check_drop_buffers ();
+}
+
+GST_END_TEST;
+
+static GstEncodingContainerProfile *
+create_qtmux_profile (const gchar * variant)
+{
+  GstEncodingContainerProfile *cprof;
+  GstCaps *caps;
+
+  if (variant == NULL) {
+    caps = gst_caps_new_empty_simple ("video/quicktime");
+  } else {
+    caps = gst_caps_new_simple ("video/quicktime",
+        "variant", G_TYPE_STRING, variant, NULL);
+  }
+
+  cprof = gst_encoding_container_profile_new ("Name", "blah", caps, NULL);
+  gst_caps_unref (caps);
+
+  caps = gst_caps_new_simple ("audio/x-raw",
+      "format", G_TYPE_STRING, "S16BE",
+      "channels", G_TYPE_INT, 2, "rate", G_TYPE_INT, 44100, NULL);
+  gst_encoding_container_profile_add_profile (cprof,
+      GST_ENCODING_PROFILE (gst_encoding_audio_profile_new (caps, NULL, NULL,
+              1)));
+  gst_caps_unref (caps);
+
+  return cprof;
+}
+
+GST_START_TEST (test_encodebin_qtmux)
+{
+  GstEncodingContainerProfile *cprof;
+  GstElement *enc;
+  GstPad *pad;
+
+  enc = gst_element_factory_make ("encodebin", NULL);
+  if (enc == NULL)
+    return;
+
+  /* Make sure encodebin finds a muxer for a profile with a variant field .. */
+  cprof = create_qtmux_profile ("apple");
+  g_object_set (enc, "profile", cprof, NULL);
+  gst_encoding_profile_unref (cprof);
+
+  /* should have created a pad after setting the profile */
+  pad = gst_element_get_static_pad (enc, "audio_0");
+  fail_unless (pad != NULL);
+  gst_object_unref (pad);
+  gst_object_unref (enc);
+
+  /* ... and for a profile without a variant field */
+  enc = gst_element_factory_make ("encodebin", NULL);
+  cprof = create_qtmux_profile (NULL);
+  g_object_set (enc, "profile", cprof, NULL);
+  gst_encoding_profile_unref (cprof);
+
+  /* should have created a pad after setting the profile */
+  pad = gst_element_get_static_pad (enc, "audio_0");
+  fail_unless (pad != NULL);
+  gst_object_unref (pad);
+  gst_object_unref (enc);
+}
+
+GST_END_TEST;
+
+/* Fake mp3 encoder for test */
+typedef GstElement TestMp3Enc;
+typedef GstElementClass TestMp3EncClass;
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/mpeg, mpegversion=1, layer=[1,3]")
+    );
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw")
+    );
+
+static GType test_mp3_enc_get_type (void);
+static void test_input_push_segment_start (gpointer user_data,
+    GstClockTime start);
+
+G_DEFINE_TYPE (TestMp3Enc, test_mp3_enc, GST_TYPE_ELEMENT);
+
+static void
+test_mp3_enc_class_init (TestMp3EncClass * klass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+
+  gst_element_class_set_metadata (element_class, "MPEG1 Audio Encoder",
+      "Codec/Encoder/Audio", "Pretends to encode mp3", "Foo Bar <foo@bar.com>");
+}
+
+static void
+test_mp3_enc_init (TestMp3Enc * mp3enc)
+{
+  GstPad *pad;
+
+  pad = gst_pad_new_from_static_template (&sink_template, "sink");
+  gst_element_add_pad (mp3enc, pad);
+
+  pad = gst_pad_new_from_static_template (&src_template, "src");
+  gst_element_add_pad (mp3enc, pad);
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "testmp3enc", GST_RANK_NONE,
+      test_mp3_enc_get_type ());
+}
+
+static GstEncodingContainerProfile *
+create_mp4mux_profile (void)
+{
+  GstEncodingContainerProfile *cprof;
+  GstCaps *caps;
+
+  caps = gst_caps_new_simple ("video/quicktime",
+      "variant", G_TYPE_STRING, "iso", NULL);
+
+  cprof = gst_encoding_container_profile_new ("Name", "blah", caps, NULL);
+  gst_caps_unref (caps);
+
+  caps = gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1,
+      "layer", G_TYPE_INT, 3, "channels", G_TYPE_INT, 2, "rate", G_TYPE_INT,
+      44100, NULL);
+  gst_encoding_container_profile_add_profile (cprof,
+      GST_ENCODING_PROFILE (gst_encoding_audio_profile_new (caps, NULL, NULL,
+              1)));
+  gst_caps_unref (caps);
+
+  return cprof;
+}
+
+GST_START_TEST (test_encodebin_mp4mux)
+{
+  GstEncodingContainerProfile *cprof;
+  GstPluginFeature *feature;
+  GstElement *enc, *mux;
+  GstPad *pad;
+
+  /* need a fake mp3 encoder because mp4 only accepts encoded formats */
+  gst_plugin_register_static (GST_VERSION_MAJOR, GST_VERSION_MINOR,
+      "fakemp3enc", "fakemp3enc", plugin_init, VERSION, "LGPL",
+      "gst-plugins-good", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
+
+  feature = gst_registry_find_feature (gst_registry_get (), "testmp3enc",
+      GST_TYPE_ELEMENT_FACTORY);
+  gst_plugin_feature_set_rank (feature, GST_RANK_PRIMARY + 100);
+
+  enc = gst_element_factory_make ("encodebin", NULL);
+  if (enc == NULL)
+    return;
+
+  /* Make sure encodebin finds mp4mux even though qtmux outputs a superset */
+  cprof = create_mp4mux_profile ();
+  g_object_set (enc, "profile", cprof, NULL);
+  gst_encoding_profile_unref (cprof);
+
+  /* should have created a pad after setting the profile */
+  pad = gst_element_get_static_pad (enc, "audio_0");
+  fail_unless (pad != NULL);
+  gst_object_unref (pad);
+
+  mux = gst_bin_get_by_interface (GST_BIN (enc), GST_TYPE_TAG_SETTER);
+  fail_unless (mux != NULL);
+  {
+    GstElementFactory *f = gst_element_get_factory (mux);
+
+    /* make sure we got mp4mux for variant=iso */
+    GST_INFO ("muxer: %s", G_OBJECT_TYPE_NAME (mux));
+    fail_unless_equals_string (GST_OBJECT_NAME (f), "mp4mux");
+  }
+  gst_object_unref (mux);
+  gst_object_unref (enc);
+
+  gst_plugin_feature_set_rank (feature, GST_RANK_NONE);
+  gst_object_unref (feature);
+}
+
+GST_END_TEST;
+
+static gboolean
+extract_tags (const gchar * location, GstTagList ** taglist)
+{
+  gboolean ret = TRUE;
+  GstElement *src;
+  GstBus *bus;
+  GstElement *pipeline =
+      gst_parse_launch ("filesrc name=src ! qtdemux ! fakesink", NULL);
+
+  src = gst_bin_get_by_name (GST_BIN (pipeline), "src");
+  g_object_set (src, "location", location, NULL);
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+  fail_unless (gst_element_set_state (pipeline, GST_STATE_PLAYING)
+      != GST_STATE_CHANGE_FAILURE);
+
+  if (*taglist == NULL) {
+    *taglist = gst_tag_list_new_empty ();
+  }
+
+  while (1) {
+    GstMessage *msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
+        GST_MESSAGE_TAG | GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
+
+    if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) {
+      gst_message_unref (msg);
+      break;
+    } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
+      ret = FALSE;
+      gst_message_unref (msg);
+      break;
+    } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_TAG) {
+      GstTagList *tags;
+
+      gst_message_parse_tag (msg, &tags);
+      gst_tag_list_insert (*taglist, tags, GST_TAG_MERGE_REPLACE);
+      gst_tag_list_unref (tags);
+    }
+    gst_message_unref (msg);
+  }
+
+  gst_object_unref (bus);
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (src);
+  gst_object_unref (pipeline);
+  return ret;
+}
+
+static void
+test_average_bitrate_custom (const gchar * elementname,
+    GstStaticPadTemplate * tmpl, const gchar * caps_str,
+    const gchar * sinkpadname)
+{
+  gchar *location;
+  GstElement *qtmux;
+  GstElement *filesink;
+  GstBuffer *inbuffer;
+  GstCaps *caps;
+  int i;
+  gint bytes[] = { 16, 22, 12 };
+  gint64 durations[] = { GST_SECOND * 3, GST_SECOND * 5, GST_SECOND * 2 };
+  gint64 total_bytes = 0;
+  GstClockTime total_duration = 0;
+  GstSegment segment;
+
+  location = g_strdup_printf ("%s/%s-%d", g_get_tmp_dir (), "qtmuxtest",
+      g_random_int ());
+  GST_INFO ("Using location %s for bitrate test", location);
+  qtmux = gst_check_setup_element (elementname);
+  filesink = gst_element_factory_make ("filesink", NULL);
+  g_object_set (filesink, "location", location, NULL);
+  gst_element_link (qtmux, filesink);
+  mysrcpad = setup_src_pad (qtmux, tmpl, sinkpadname);
+  fail_unless (mysrcpad != NULL);
+  gst_pad_set_active (mysrcpad, TRUE);
+
+
+  fail_unless (gst_element_set_state (filesink,
+          GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE,
+      "could not set filesink to playing");
+  fail_unless (gst_element_set_state (qtmux,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test"));
+
+  caps = gst_caps_from_string (caps_str);
+  gst_pad_set_caps (mysrcpad, caps);
+  gst_caps_unref (caps);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  for (i = 0; i < 3; i++) {
+    inbuffer = gst_buffer_new_and_alloc (bytes[i]);
+    gst_buffer_memset (inbuffer, 0, 0, bytes[i]);
+    GST_BUFFER_TIMESTAMP (inbuffer) = total_duration;
+    GST_BUFFER_DURATION (inbuffer) = (GstClockTime) durations[i];
+    ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+    total_bytes += gst_buffer_get_size (inbuffer);
+    total_duration += GST_BUFFER_DURATION (inbuffer);
+    fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  }
+
+  /* send eos to have moov written */
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE);
+
+  gst_element_set_state (qtmux, GST_STATE_NULL);
+  gst_element_set_state (filesink, GST_STATE_NULL);
+
+  gst_check_drop_buffers ();
+  gst_pad_set_active (mysrcpad, FALSE);
+  teardown_src_pad (mysrcpad);
+  gst_object_unref (filesink);
+  gst_check_teardown_element (qtmux);
+
+  /* check the bitrate tag */
+  {
+    GstTagList *taglist = NULL;
+    guint bitrate = 0;
+    guint expected;
+
+    fail_unless (extract_tags (location, &taglist));
+
+    fail_unless (gst_tag_list_get_uint (taglist, GST_TAG_BITRATE, &bitrate));
+
+    expected =
+        (guint) gst_util_uint64_scale_round ((guint64) total_bytes,
+        (guint64) 8 * GST_SECOND, (guint64) total_duration);
+    fail_unless (bitrate == expected);
+    gst_tag_list_unref (taglist);
+  }
+
+  /* delete file */
+  g_unlink (location);
+  g_free (location);
+}
+
+GST_START_TEST (test_average_bitrate)
+{
+  test_average_bitrate_custom ("mp4mux", &srcaudioaactemplate,
+      AUDIO_AAC_CAPS_STRING, "audio_%u");
+  test_average_bitrate_custom ("mp4mux", &srcvideoh264template,
+      VIDEO_CAPS_H264_STRING, "video_%u");
+
+  test_average_bitrate_custom ("qtmux", &srcaudioaactemplate,
+      AUDIO_AAC_CAPS_STRING, "audio_%u");
+  test_average_bitrate_custom ("qtmux", &srcvideoh264template,
+      VIDEO_CAPS_H264_STRING, "video_%u");
+}
+
+GST_END_TEST;
+
+struct TestInputData
+{
+  GstPad *srcpad;
+  GstSegment segment;
+  GList *input;
+  GThread *thread;
+
+  /* When comparing ts, the input will be subtracted from this */
+  gint64 ts_offset;
+  /* Due to DTS, the segment start might be shifted so this list
+   * is used to vefity each received segments */
+  GList *expected_segment_start;
+
+  GstClockTime expected_gap_ts;
+  GstClockTime expected_gap_duration;
+  gboolean gap_received;
+
+  GstPad *sinkpad;
+
+  GList *output_iter;
+};
+
+static void
+test_input_data_init (struct TestInputData *data)
+{
+  data->ts_offset = 0;
+  data->expected_segment_start = NULL;
+  data->expected_gap_ts = 0;
+  data->expected_gap_duration = 0;
+  data->gap_received = FALSE;
+  data->srcpad = NULL;
+  data->sinkpad = NULL;
+  data->input = NULL;
+  data->thread = NULL;
+
+  test_input_push_segment_start (data, 0);
+}
+
+static void
+test_input_data_clean (struct TestInputData *data)
+{
+  g_list_free_full (data->input, (GDestroyNotify) gst_mini_object_unref);
+
+  if (data->sinkpad) {
+    gst_pad_set_active (data->sinkpad, FALSE);
+    gst_object_unref (data->sinkpad);
+  }
+
+  gst_pad_set_active (data->srcpad, FALSE);
+  teardown_src_pad (data->srcpad);
+}
+
+static gpointer
+test_input_push_data (gpointer user_data)
+{
+  struct TestInputData *data = user_data;
+  GList *iter;
+  GstFlowReturn flow;
+
+  for (iter = data->input; iter; iter = g_list_next (iter)) {
+    if (GST_IS_BUFFER (iter->data)) {
+      GST_INFO ("Pushing buffer %" GST_PTR_FORMAT " on pad: %s:%s", iter->data,
+          GST_DEBUG_PAD_NAME (data->srcpad));
+      flow =
+          gst_pad_push (data->srcpad,
+          gst_buffer_ref ((GstBuffer *) iter->data));
+      fail_unless (flow == GST_FLOW_OK);
+    } else {
+      GST_INFO_OBJECT (data->srcpad, "Pushing event: %"
+          GST_PTR_FORMAT, iter->data);
+      fail_unless (gst_pad_push_event (data->srcpad,
+              gst_event_ref ((GstEvent *) iter->data)) == TRUE);
+    }
+  }
+  return NULL;
+}
+
+static void
+test_input_push_segment_start (gpointer user_data, GstClockTime start)
+{
+  struct TestInputData *data = user_data;
+  GstClockTime *start_data = g_malloc (sizeof (GstClockTime));
+
+  *start_data = start;
+  data->expected_segment_start = g_list_append (data->expected_segment_start,
+      start_data);
+}
+
+static GstClockTime
+test_input_pop_segment_start (gpointer user_data)
+{
+  struct TestInputData *data = user_data;
+  GstClockTime start = GST_CLOCK_TIME_NONE;
+  GstClockTime *start_data;
+
+  if (data->expected_segment_start) {
+    start_data = data->expected_segment_start->data;
+    data->expected_segment_start =
+        g_list_delete_link (data->expected_segment_start,
+        data->expected_segment_start);
+    start = *start_data;
+    g_free (start_data);
+  }
+
+  return start;
+}
+
+static GstBuffer *
+create_buffer (GstClockTime pts, GstClockTime dts, GstClockTime duration,
+    guint bytes)
+{
+  GstBuffer *buf;
+  guint8 *data;
+
+  data = g_malloc0 (bytes);
+  buf = gst_buffer_new_wrapped (data, bytes);
+  GST_BUFFER_PTS (buf) = pts;
+  GST_BUFFER_DTS (buf) = dts;
+  GST_BUFFER_DURATION (buf) = duration;
+  return buf;
+}
+
+static GstFlowReturn
+_test_sink_pad_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  struct TestInputData *test_data = g_object_get_qdata (G_OBJECT (pad),
+      g_quark_from_static_string ("test-mux-pad"));
+  GstBuffer *expected_buffer;
+
+  fail_unless (test_data->output_iter);
+  fail_unless (GST_IS_BUFFER (test_data->output_iter->data));
+  expected_buffer = test_data->output_iter->data;
+
+  fail_unless (GST_BUFFER_PTS (buffer) ==
+      (GST_BUFFER_PTS_IS_VALID (expected_buffer) ?
+          GST_BUFFER_PTS (expected_buffer) -
+          test_data->ts_offset : GST_BUFFER_PTS (expected_buffer)));
+  fail_unless (GST_BUFFER_DTS (buffer) ==
+      (GST_BUFFER_DTS_IS_VALID (expected_buffer) ?
+          GST_BUFFER_DTS (expected_buffer) -
+          test_data->ts_offset : GST_BUFFER_DTS (buffer)));
+  fail_unless (GST_BUFFER_DURATION (buffer) ==
+      GST_BUFFER_DURATION (expected_buffer));
+
+  test_data->output_iter = g_list_next (test_data->output_iter);
+
+  gst_buffer_unref (buffer);
+  return GST_FLOW_OK;
+}
+
+static void
+compare_event (GstEvent * event, GstEvent * expected)
+{
+  fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_TYPE (expected));
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:{
+      GstCaps *caps, *expected_caps;
+
+      gst_event_parse_caps (event, &caps);
+      gst_event_parse_caps (expected, &expected_caps);
+      fail_unless (gst_caps_can_intersect (caps, expected_caps));
+    }
+      break;
+    default:
+      break;
+  }
+}
+
+static gboolean
+_test_sink_pad_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  struct TestInputData *test_data = g_object_get_qdata (G_OBJECT (pad),
+      g_quark_from_static_string ("test-mux-pad"));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_STREAM_START:
+    case GST_EVENT_CAPS:
+    case GST_EVENT_EOS:
+      fail_unless (test_data->output_iter);
+      fail_unless (GST_IS_EVENT (test_data->output_iter->data));
+      compare_event (event, test_data->output_iter->data);
+      test_data->output_iter = g_list_next (test_data->output_iter);
+      break;
+    case GST_EVENT_SEGMENT:{
+      const GstSegment *segment;
+
+      fail_unless (test_data->output_iter);
+      fail_unless (GST_IS_EVENT (test_data->output_iter->data));
+      gst_event_parse_segment (event, &segment);
+      fail_unless (segment->start == test_input_pop_segment_start (test_data));
+      test_data->output_iter = g_list_next (test_data->output_iter);
+      break;
+    }
+    case GST_EVENT_GAP:{
+      GstClockTime timestamp;
+      GstClockTime duration;
+      gst_event_parse_gap (event, &timestamp, &duration);
+      fail_unless (timestamp == test_data->expected_gap_ts);
+      fail_unless (duration == test_data->expected_gap_duration);
+      test_data->gap_received = TRUE;
+      break;
+    }
+    case GST_EVENT_TAG:
+      /* ignore this event */
+      break;
+    default:
+      GST_ERROR_OBJECT (pad, "Unexpected event: %" GST_PTR_FORMAT, event);
+      fail ("Unexpected event received %s", GST_EVENT_TYPE_NAME (event));
+      break;
+  }
+
+  gst_event_unref (event);
+  return TRUE;
+}
+
+static void
+_test_pad_added_cb (GstElement * element, GstPad * pad, gpointer udata)
+{
+  GstCaps *caps;
+  struct TestInputData **inputs = udata;
+  gint i = -1;
+  const gchar *name;
+  const gchar *strname;
+
+  caps = gst_pad_get_current_caps (pad);
+  strname = gst_structure_get_name (gst_caps_get_structure (caps, 0));
+  if (g_str_has_prefix (strname, "video/")) {
+    i = 0;                      /* video is 0, audio is 1 */
+    name = "videosink";
+  } else {
+    i = 1;
+    name = "audiosink";
+  }
+  gst_caps_unref (caps);
+
+  fail_unless (i != -1);
+  fail_unless (inputs[i]->sinkpad == NULL);
+  inputs[i]->sinkpad = gst_pad_new (name, GST_PAD_SINK);
+  inputs[i]->output_iter = inputs[i]->input;
+  g_object_set_qdata (G_OBJECT (inputs[i]->sinkpad),
+      g_quark_from_static_string ("test-mux-pad"), inputs[i]);
+  gst_pad_set_chain_function (inputs[i]->sinkpad, _test_sink_pad_chain);
+  gst_pad_set_event_function (inputs[i]->sinkpad, _test_sink_pad_event);
+  gst_pad_set_active (inputs[i]->sinkpad, TRUE);
+  fail_unless (gst_pad_link (pad, inputs[i]->sinkpad) == GST_PAD_LINK_OK);
+}
+
+static void
+check_output (const gchar * location, struct TestInputData *input1,
+    struct TestInputData *input2)
+{
+  GstElement *filesrc;
+  GstElement *demux;
+  struct TestInputData *inputs[2] = { input1, input2 };
+
+  filesrc = gst_element_factory_make ("filesrc", NULL);
+  demux = gst_element_factory_make ("qtdemux", NULL);
+
+  fail_unless (gst_element_link (filesrc, demux));
+
+  g_object_set (filesrc, "location", location, NULL);
+  g_signal_connect (demux, "pad-added", (GCallback) _test_pad_added_cb, inputs);
+
+  fail_unless (gst_element_set_state (demux,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
+  fail_unless (gst_element_set_state (filesrc,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
+
+  /* FIXME use a main loop */
+  g_usleep (2 * G_USEC_PER_SEC);
+
+  fail_unless (gst_element_set_state (demux,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
+  fail_unless (gst_element_set_state (filesrc,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
+  gst_object_unref (filesrc);
+  gst_object_unref (demux);
+}
+
+/* Muxes a file with qtmux using the inputs provided and
+ * then verifies that the generated file corresponds to the
+ * data in the inputs */
+static void
+run_muxing_test (struct TestInputData *input1, struct TestInputData *input2)
+{
+  gchar *location;
+  GstElement *qtmux;
+  GstElement *filesink;
+
+  location = g_strdup_printf ("%s/%s-%d", g_get_tmp_dir (), "qtmuxtest",
+      g_random_int ());
+  qtmux = gst_check_setup_element ("qtmux");
+  filesink = gst_element_factory_make ("filesink", NULL);
+  g_object_set (filesink, "location", location, NULL);
+  gst_element_link (qtmux, filesink);
+
+  input1->srcpad = setup_src_pad (qtmux, &srcvideorawtemplate, "video_%u");
+  fail_unless (input1->srcpad != NULL);
+  gst_pad_set_active (input1->srcpad, TRUE);
+
+  input2->srcpad = setup_src_pad (qtmux, &srcaudioaactemplate, "audio_%u");
+  fail_unless (input2->srcpad != NULL);
+  gst_pad_set_active (input2->srcpad, TRUE);
+
+  fail_unless (gst_element_set_state (filesink,
+          GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE,
+      "could not set filesink to playing");
+  fail_unless (gst_element_set_state (qtmux,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  input1->thread =
+      g_thread_new ("test-push-data-1", test_input_push_data, input1);
+  input2->thread =
+      g_thread_new ("test-push-data-2", test_input_push_data, input2);
+
+  /* FIXME set a mainloop and wait for EOS */
+
+  g_thread_join (input1->thread);
+  g_thread_join (input2->thread);
+  input1->thread = NULL;
+  input2->thread = NULL;
+
+  gst_element_set_state (qtmux, GST_STATE_NULL);
+  gst_element_set_state (filesink, GST_STATE_NULL);
+
+  check_output (location, input1, input2);
+
+  gst_object_unref (filesink);
+  test_input_data_clean (input1);
+  test_input_data_clean (input2);
+  gst_check_teardown_element (qtmux);
+
+  /* delete file */
+  g_unlink (location);
+  g_free (location);
+}
+
+GST_START_TEST (test_muxing)
+{
+  struct TestInputData input1, input2;
+  GstCaps *caps;
+
+  test_input_data_init (&input1);
+  test_input_data_init (&input2);
+
+  /* Create the inputs, after calling the run below, all this data is
+   * transfered to it and we have no need to clean up */
+  input1.input = NULL;
+  input1.input =
+      g_list_append (input1.input, gst_event_new_stream_start ("test-1"));
+  caps = gst_caps_from_string
+      ("video/x-raw, width=(int)800, height=(int)600, "
+      "framerate=(fraction)1/1, format=(string)RGB");
+  input1.input = g_list_append (input1.input, gst_event_new_caps (caps));
+  gst_caps_unref (caps);
+  gst_segment_init (&input1.segment, GST_FORMAT_TIME);
+  input1.input =
+      g_list_append (input1.input, gst_event_new_segment (&input1.segment));
+  input1.input =
+      g_list_append (input1.input, create_buffer (0, GST_CLOCK_TIME_NONE,
+          GST_SECOND, 800 * 600 * 3));
+  input1.input =
+      g_list_append (input1.input, create_buffer (1 * GST_SECOND,
+          GST_CLOCK_TIME_NONE, GST_SECOND, 800 * 600 * 3));
+  input1.input =
+      g_list_append (input1.input, create_buffer (2 * GST_SECOND,
+          GST_CLOCK_TIME_NONE, GST_SECOND, 800 * 600 * 3));
+  input1.input = g_list_append (input1.input, gst_event_new_eos ());
+
+  input2.input = NULL;
+  input2.input =
+      g_list_append (input2.input, gst_event_new_stream_start ("test-2"));
+  caps = gst_caps_from_string (AUDIO_AAC_CAPS_STRING);
+  input2.input = g_list_append (input2.input, gst_event_new_caps (caps));
+  gst_caps_unref (caps);
+  gst_segment_init (&input2.segment, GST_FORMAT_TIME);
+  input2.input =
+      g_list_append (input2.input, gst_event_new_segment (&input2.segment));
+  input2.input =
+      g_list_append (input2.input, create_buffer (0, 0, GST_SECOND, 4096));
+  input2.input =
+      g_list_append (input2.input, create_buffer (1 * GST_SECOND,
+          1 * GST_SECOND, GST_SECOND, 4096));
+  input2.input =
+      g_list_append (input2.input, create_buffer (2 * GST_SECOND,
+          2 * GST_SECOND, GST_SECOND, 4096));
+  input2.input = g_list_append (input2.input, gst_event_new_eos ());
+
+  run_muxing_test (&input1, &input2);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_muxing_non_zero_segment)
+{
+  struct TestInputData input1, input2;
+  GstCaps *caps;
+
+  test_input_data_init (&input1);
+  test_input_data_init (&input2);
+
+  /* Create the inputs, after calling the run below, all this data is
+   * transfered to it and we have no need to clean up */
+  input1.input = NULL;
+  input1.input =
+      g_list_append (input1.input, gst_event_new_stream_start ("test-1"));
+  caps = gst_caps_from_string
+      ("video/x-raw, width=(int)800, height=(int)600, "
+      "framerate=(fraction)1/1, format=(string)RGB");
+  input1.input = g_list_append (input1.input, gst_event_new_caps (caps));
+  gst_caps_unref (caps);
+  gst_segment_init (&input1.segment, GST_FORMAT_TIME);
+  input1.segment.start = 10 * GST_SECOND;
+  input1.input =
+      g_list_append (input1.input, gst_event_new_segment (&input1.segment));
+  input1.input =
+      g_list_append (input1.input, create_buffer (10 * GST_SECOND,
+          GST_CLOCK_TIME_NONE, GST_SECOND, 800 * 600 * 3));
+  input1.input =
+      g_list_append (input1.input, create_buffer (11 * GST_SECOND,
+          GST_CLOCK_TIME_NONE, GST_SECOND, 800 * 600 * 3));
+  input1.input =
+      g_list_append (input1.input, create_buffer (12 * GST_SECOND,
+          GST_CLOCK_TIME_NONE, GST_SECOND, 800 * 600 * 3));
+  input1.input = g_list_append (input1.input, gst_event_new_eos ());
+  input1.ts_offset = GST_SECOND * 10;
+
+  input2.input = NULL;
+  input2.input =
+      g_list_append (input2.input, gst_event_new_stream_start ("test-2"));
+  caps = gst_caps_from_string (AUDIO_AAC_CAPS_STRING);
+  input2.input = g_list_append (input2.input, gst_event_new_caps (caps));
+  gst_caps_unref (caps);
+  gst_segment_init (&input2.segment, GST_FORMAT_TIME);
+  input2.segment.start = 10 * GST_SECOND;
+  input2.input =
+      g_list_append (input2.input, gst_event_new_segment (&input2.segment));
+  input2.input =
+      g_list_append (input2.input, create_buffer (10 * GST_SECOND,
+          10 * GST_SECOND, GST_SECOND, 4096));
+  input2.input =
+      g_list_append (input2.input, create_buffer (11 * GST_SECOND,
+          11 * GST_SECOND, GST_SECOND, 4096));
+  input2.input =
+      g_list_append (input2.input, create_buffer (12 * GST_SECOND,
+          12 * GST_SECOND, GST_SECOND, 4096));
+  input2.input = g_list_append (input2.input, gst_event_new_eos ());
+  input2.ts_offset = GST_SECOND * 10;
+
+  run_muxing_test (&input1, &input2);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_muxing_non_zero_segment_different)
+{
+  struct TestInputData input1, input2;
+  GstCaps *caps;
+
+  test_input_data_init (&input1);
+  test_input_data_init (&input2);
+
+  /* Create the inputs, after calling the run below, all this data is
+   * transfered to it and we have no need to clean up */
+  input1.input = NULL;
+  input1.input =
+      g_list_append (input1.input, gst_event_new_stream_start ("test-1"));
+  caps = gst_caps_from_string
+      ("video/x-raw, width=(int)800, height=(int)600, "
+      "framerate=(fraction)1/1, format=(string)RGB");
+  input1.input = g_list_append (input1.input, gst_event_new_caps (caps));
+  gst_caps_unref (caps);
+  gst_segment_init (&input1.segment, GST_FORMAT_TIME);
+  input1.segment.start = 5 * GST_SECOND;
+  input1.input =
+      g_list_append (input1.input, gst_event_new_segment (&input1.segment));
+  input1.input =
+      g_list_append (input1.input, create_buffer (5 * GST_SECOND,
+          GST_CLOCK_TIME_NONE, GST_SECOND, 800 * 600 * 3));
+  input1.input =
+      g_list_append (input1.input, create_buffer (6 * GST_SECOND,
+          GST_CLOCK_TIME_NONE, GST_SECOND, 800 * 600 * 3));
+  input1.input =
+      g_list_append (input1.input, create_buffer (7 * GST_SECOND,
+          GST_CLOCK_TIME_NONE, GST_SECOND, 800 * 600 * 3));
+  input1.input = g_list_append (input1.input, gst_event_new_eos ());
+  input1.ts_offset = GST_SECOND * 5;
+
+  input2.input = NULL;
+  input2.input =
+      g_list_append (input2.input, gst_event_new_stream_start ("test-2"));
+  caps = gst_caps_from_string (AUDIO_AAC_CAPS_STRING);
+  input2.input = g_list_append (input2.input, gst_event_new_caps (caps));
+  gst_caps_unref (caps);
+  gst_segment_init (&input2.segment, GST_FORMAT_TIME);
+  input2.segment.start = 10 * GST_SECOND;
+  input2.input =
+      g_list_append (input2.input, gst_event_new_segment (&input2.segment));
+  input2.input =
+      g_list_append (input2.input, create_buffer (10 * GST_SECOND,
+          10 * GST_SECOND, GST_SECOND, 4096));
+  input2.input =
+      g_list_append (input2.input, create_buffer (11 * GST_SECOND,
+          11 * GST_SECOND, GST_SECOND, 4096));
+  input2.input =
+      g_list_append (input2.input, create_buffer (12 * GST_SECOND,
+          12 * GST_SECOND, GST_SECOND, 4096));
+  input2.input = g_list_append (input2.input, gst_event_new_eos ());
+  input2.ts_offset = GST_SECOND * 10;
+
+  run_muxing_test (&input1, &input2);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_muxing_dts_outside_segment)
+{
+  struct TestInputData input1, input2;
+  GstCaps *caps;
+
+  test_input_data_init (&input1);
+  test_input_data_init (&input2);
+
+  /* Create the inputs, after calling the run below, all this data is
+   * transfered to it and we have no need to clean up */
+  input1.input = NULL;
+  input1.input =
+      g_list_append (input1.input, gst_event_new_stream_start ("test-1"));
+  caps = gst_caps_from_string
+      ("video/x-h264, width=(int)800, height=(int)600, "
+      "framerate=(fraction)1/1, stream-format=(string)avc, codec_data=(buffer)0000,"
+      " alignment=(string)au, level=(int)2, profile=(string)high");
+  input1.input = g_list_append (input1.input, gst_event_new_caps (caps));
+  gst_caps_unref (caps);
+  gst_segment_init (&input1.segment, GST_FORMAT_TIME);
+  input1.segment.start = 1 * GST_SECOND;
+  input1.input =
+      g_list_append (input1.input, gst_event_new_segment (&input1.segment));
+  input1.input =
+      g_list_append (input1.input, create_buffer (1 * GST_SECOND,
+          0, GST_SECOND, 4096));
+  input1.input =
+      g_list_append (input1.input, create_buffer (2 * GST_SECOND,
+          1 * GST_SECOND, GST_SECOND, 4096));
+  input1.input =
+      g_list_append (input1.input, create_buffer (3 * GST_SECOND,
+          2 * GST_SECOND, GST_SECOND, 4096));
+  input1.input = g_list_append (input1.input, gst_event_new_eos ());
+  /* First DTS is 0, first PTS is 1s. The segment start being 1, this means
+   * running time -1s and 0. So the output segment should start from 1s to keep
+   * the same running time */
+  test_input_pop_segment_start (&input1);
+  test_input_push_segment_start (&input1, GST_SECOND);
+
+  input2.input = NULL;
+  input2.input =
+      g_list_append (input2.input, gst_event_new_stream_start ("test-2"));
+  caps = gst_caps_from_string (AUDIO_AAC_CAPS_STRING);
+  input2.input = g_list_append (input2.input, gst_event_new_caps (caps));
+  gst_caps_unref (caps);
+  gst_segment_init (&input2.segment, GST_FORMAT_TIME);
+  input2.input =
+      g_list_append (input2.input, gst_event_new_segment (&input2.segment));
+  input2.input =
+      g_list_append (input2.input, create_buffer (0, 0, GST_SECOND,
+          44100 * 4 * 2));
+  input2.input =
+      g_list_append (input2.input, create_buffer (GST_SECOND, GST_SECOND,
+          GST_SECOND, 44100 * 4 * 2));
+  input2.input =
+      g_list_append (input2.input, create_buffer (2 * GST_SECOND,
+          2 * GST_SECOND, GST_SECOND, 44100 * 4 * 2));
+  input2.input = g_list_append (input2.input, gst_event_new_eos ());
+
+  run_muxing_test (&input1, &input2);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_muxing_initial_gap)
+{
+  struct TestInputData input1, input2;
+  GstCaps *caps;
+
+  test_input_data_init (&input1);
+  test_input_data_init (&input2);
+
+  /* Create the inputs, after calling the run below, all this data is
+   * transfered to it and we have no need to clean up */
+  input1.input = NULL;
+  input1.input =
+      g_list_append (input1.input, gst_event_new_stream_start ("test-1"));
+  caps = gst_caps_from_string
+      ("video/x-h264, width=(int)800, height=(int)600, "
+      "framerate=(fraction)1/1, stream-format=(string)avc, codec_data=(buffer)0000,"
+      " alignment=(string)au, level=(int)2, profile=(string)high");
+  input1.input = g_list_append (input1.input, gst_event_new_caps (caps));
+  gst_caps_unref (caps);
+  gst_segment_init (&input1.segment, GST_FORMAT_TIME);
+  input1.input =
+      g_list_append (input1.input, gst_event_new_segment (&input1.segment));
+  /* Duplicate the segment to please the harness */
+  input1.input =
+      g_list_append (input1.input, gst_event_new_segment (&input1.segment));
+  input1.input =
+      g_list_append (input1.input, create_buffer (1 * GST_SECOND,
+          0, GST_SECOND, 4096));
+  input1.input =
+      g_list_append (input1.input, create_buffer (2 * GST_SECOND,
+          1 * GST_SECOND, GST_SECOND, 4096));
+  input1.input =
+      g_list_append (input1.input, create_buffer (3 * GST_SECOND,
+          2 * GST_SECOND, GST_SECOND, 4096));
+  input1.input = g_list_append (input1.input, gst_event_new_eos ());
+
+  /* We expect a 1s gap at the start */
+  input1.expected_gap_duration = GST_SECOND;
+  /* There will be two segments, first is 0, so leave it there, second should
+   * match the first CTTS (PTS - DTS) */
+  test_input_push_segment_start (&input1, GST_SECOND);
+
+  input2.input = NULL;
+  input2.input =
+      g_list_append (input2.input, gst_event_new_stream_start ("test-2"));
+  caps = gst_caps_from_string (AUDIO_AAC_CAPS_STRING);
+  input2.input = g_list_append (input2.input, gst_event_new_caps (caps));
+  gst_caps_unref (caps);
+  gst_segment_init (&input2.segment, GST_FORMAT_TIME);
+  input2.input =
+      g_list_append (input2.input, gst_event_new_segment (&input2.segment));
+  input2.input =
+      g_list_append (input2.input, create_buffer (0, 0, GST_SECOND,
+          44100 * 4 * 2));
+  input2.input =
+      g_list_append (input2.input, create_buffer (GST_SECOND, GST_SECOND,
+          GST_SECOND, 44100 * 4 * 2));
+  input2.input =
+      g_list_append (input2.input, create_buffer (2 * GST_SECOND,
+          2 * GST_SECOND, GST_SECOND, 44100 * 4 * 2));
+  input2.input = g_list_append (input2.input, gst_event_new_eos ());
+
+  run_muxing_test (&input1, &input2);
+
+  fail_unless (input1.gap_received);
+}
+
+GST_END_TEST;
+
+static Suite *
+qtmux_suite (void)
+{
+  Suite *s = suite_create ("qtmux");
+  TCase *tc_chain = tcase_create ("general");
+
+  /* avoid glib warnings when setting deprecated dts-method property */
+  g_setenv ("G_ENABLE_DIAGNOSTIC", "0", TRUE);
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_video_pad_dd);
+  tcase_add_test (tc_chain, test_audio_pad_dd);
+  tcase_add_test (tc_chain, test_video_pad_frag_dd);
+  tcase_add_test (tc_chain, test_audio_pad_frag_dd);
+  tcase_add_test (tc_chain, test_video_pad_frag_dd_streamable);
+  tcase_add_test (tc_chain, test_audio_pad_frag_dd_streamable);
+
+  tcase_add_test (tc_chain, test_video_pad_reorder);
+  tcase_add_test (tc_chain, test_audio_pad_reorder);
+  tcase_add_test (tc_chain, test_video_pad_frag_reorder);
+  tcase_add_test (tc_chain, test_audio_pad_frag_reorder);
+  tcase_add_test (tc_chain, test_video_pad_frag_reorder_streamable);
+  tcase_add_test (tc_chain, test_audio_pad_frag_reorder_streamable);
+
+  tcase_add_test (tc_chain, test_video_pad_asc);
+  tcase_add_test (tc_chain, test_audio_pad_asc);
+  tcase_add_test (tc_chain, test_video_pad_frag_asc);
+  tcase_add_test (tc_chain, test_audio_pad_frag_asc);
+  tcase_add_test (tc_chain, test_video_pad_frag_asc_streamable);
+  tcase_add_test (tc_chain, test_audio_pad_frag_asc_streamable);
+
+  tcase_add_test (tc_chain, test_average_bitrate);
+
+  tcase_add_test (tc_chain, test_reuse);
+  tcase_add_test (tc_chain, test_encodebin_qtmux);
+  tcase_add_test (tc_chain, test_encodebin_mp4mux);
+
+  tcase_add_test (tc_chain, test_muxing);
+  tcase_add_test (tc_chain, test_muxing_non_zero_segment);
+  tcase_add_test (tc_chain, test_muxing_non_zero_segment_different);
+  tcase_add_test (tc_chain, test_muxing_dts_outside_segment);
+  tcase_add_test (tc_chain, test_muxing_initial_gap);
+
+  return s;
+}
+
+GST_CHECK_MAIN (qtmux)
diff --git a/tests/check/elements/rganalysis.c b/tests/check/elements/rganalysis.c
new file mode 100644
index 0000000..9ebbba6
--- /dev/null
+++ b/tests/check/elements/rganalysis.c
@@ -0,0 +1,1979 @@
+/* GStreamer ReplayGain analysis
+ *
+ * Copyright (C) 2006 Rene Stadler <mail@renestadler.de>
+ *
+ * rganalysis.c: Unit test for the rganalysis element
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+/* Some things to note about the RMS window length of the analysis algorithm and
+ * thus the implementation used in the element: Processing divides input data
+ * into 50ms windows at some point.  Some details about this that normally do
+ * not matter:
+ *
+ *  1. At the end of a stream, the remainder of data that did not fill up the
+ *     last 50ms window is simply discarded.
+ *
+ *  2. If the sample rate changes during a stream, the currently running window
+ *     is discarded and the equal loudness filter gets reset as if a new stream
+ *     started.
+ *
+ *  3. For the album gain, it is not entirely correct to think of obtaining it
+ *     like "as if all the tracks are analyzed as one track".  There isn't a
+ *     separate window being tracked for album processing, so at stream (track)
+ *     end, the remaining unfilled window does not contribute to the album gain
+ *     either.
+ *
+ *  4. If a waveform with a result gain G is concatenated to itself and the
+ *     result processed as a track, the gain can be different from G if and only
+ *     if the duration of the original waveform is not an integer multiple of
+ *     50ms.  If the original waveform gets processed as a single track and then
+ *     the same data again as a subsequent track, the album result gain will
+ *     always match G (this is implied by 3.).
+ *
+ *  5. A stream shorter than 50ms cannot be analyzed.  At 8000 and 48000 Hz,
+ *     this corresponds to 400 resp. 2400 frames.  If a stream is shorter than
+ *     50ms, the element will not generate tags at EOS (only if an album
+ *     finished, but only album tags are generated then).  This is not an
+ *     erroneous condition, the element should behave normally.
+ *
+ * The limitations outlined in 1.-4. do not apply to the peak values.  Every
+ * single sample is accounted for when looking for the peak.  Thus the album
+ * peak is guaranteed to be the maximum value of all track peaks.
+ *
+ * In normal day-to-day use, these little facts are unlikely to be relevant, but
+ * they have to be kept in mind for writing the tests here.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/audio/audio.h>
+
+/* For ease of programming we use globals to keep refs for our floating src and
+ * sink pads we create; otherwise we always have to do get_pad, get_peer, and
+ * then remove references in every test function */
+static GstPad *mysrcpad, *mysinkpad;
+static GstBus *mybus;
+
+/* Mapping from supported sample rates to the correct result gain for the
+ * following test waveform: 20 * 512 samples with a quarter-full amplitude of
+ * toggling sign, changing every 48 samples and starting with the positive
+ * value.
+ *
+ * Even if we would generate a wave describing a signal with the same frequency
+ * at each sampling rate, the results would vary (slightly).  Hence the simple
+ * generation method, since we cannot use a constant value as expected result
+ * anyways.  For all sample rates, changing the sign every 48 frames gives a
+ * sane frequency.  Buffers containing data that forms such a waveform is
+ * created using the test_buffer_square_{float,int16}_{mono,stereo} functions
+ * below.
+ *
+ * The results have been checked against what the metaflac and wavegain programs
+ * generate for such a stream.  If you want to verify these, be sure that the
+ * metaflac program does not produce incorrect results in your environment: I
+ * found a strange bug in the (defacto) reference code for the analysis that
+ * sometimes leads to incorrect RMS window lengths. */
+
+struct rate_test
+{
+  guint sample_rate;
+  gdouble gain;
+};
+
+static const struct rate_test supported_rates[] = {
+  {8000, -0.91},
+  {11025, -2.80},
+  {12000, -3.13},
+  {16000, -4.26},
+  {22050, -5.64},
+  {24000, -5.87},
+  {32000, -6.03},
+  {44100, -6.20},
+  {48000, -6.14}
+};
+
+/* Lookup the correct gain adjustment result in above array. */
+
+static gdouble
+get_expected_gain (guint sample_rate)
+{
+  gint i;
+
+  for (i = G_N_ELEMENTS (supported_rates); i--;)
+    if (supported_rates[i].sample_rate == sample_rate)
+      return supported_rates[i].gain;
+  g_return_val_if_reached (0.0);
+}
+
+#define SILENCE_GAIN 64.82
+
+#define REPLAY_GAIN_CAPS                                \
+  "channels = (int) { 1, 2 }, "                         \
+  "rate = (int) { 8000, 11025, 12000, 16000, 22050, "   \
+  "24000, 32000, 44100, 48000 }"
+
+#define RG_ANALYSIS_CAPS_TEMPLATE_STRING      \
+  "audio/x-raw, "                             \
+  "format = (string) "GST_AUDIO_NE (F32) ", " \
+  "layout = (string) interleaved, "           \
+  REPLAY_GAIN_CAPS                            \
+  "; "                                        \
+  "audio/x-raw, "                             \
+  "format = (string) "GST_AUDIO_NE (S16) ", " \
+  "layout = (string) interleaved, "           \
+  REPLAY_GAIN_CAPS
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (RG_ANALYSIS_CAPS_TEMPLATE_STRING)
+    );
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (RG_ANALYSIS_CAPS_TEMPLATE_STRING)
+    );
+
+static gboolean
+mysink_event_func (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GST_LOG_OBJECT (pad, "%s event: %" GST_PTR_FORMAT,
+      GST_EVENT_TYPE_NAME (event), event);
+
+  /* a sink would post tag events as messages, so do the same here,
+   * esp. since we're polling on the bus waiting for TAG messages.. */
+  if (GST_EVENT_TYPE (event) == GST_EVENT_TAG) {
+    GstTagList *taglist;
+
+    gst_event_parse_tag (event, &taglist);
+
+    gst_bus_post (mybus, gst_message_new_tag (GST_OBJECT (mysinkpad),
+            gst_tag_list_copy (taglist)));
+  }
+
+  gst_event_unref (event);
+  return TRUE;
+}
+
+static GstElement *
+setup_rganalysis (void)
+{
+  GstElement *analysis;
+  GstBus *bus;
+
+  GST_DEBUG ("setup_rganalysis");
+  analysis = gst_check_setup_element ("rganalysis");
+  mysrcpad = gst_check_setup_src_pad (analysis, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (analysis, &sinktemplate);
+  gst_pad_set_event_function (mysinkpad, mysink_event_func);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  bus = gst_bus_new ();
+  gst_element_set_bus (analysis, bus);
+
+  mybus = bus;                  /* keep ref */
+
+  return analysis;
+}
+
+static void
+cleanup_rganalysis (GstElement * element)
+{
+  GST_DEBUG ("cleanup_rganalysis");
+
+  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_object_unref (mybus);
+  mybus = NULL;
+
+  /* The bus owns references to the element: */
+  gst_element_set_bus (element, NULL);
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (element);
+  gst_check_teardown_sink_pad (element);
+  gst_check_teardown_element (element);
+}
+
+static void
+set_playing_state (GstElement * element)
+{
+  fail_unless (gst_element_set_state (element,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "Could not set state to PLAYING");
+}
+
+static void
+send_flush_events (GstElement * element)
+{
+  gboolean res;
+  GstPad *pad;
+
+  pad = mysrcpad;
+  res = gst_pad_push_event (pad, gst_event_new_flush_start ());
+  fail_unless (res, "flush-start even not handledt");
+  res = gst_pad_push_event (pad, gst_event_new_flush_stop (TRUE));
+  fail_unless (res, "flush-stop event not handled");
+}
+
+static void
+send_stream_start_event (GstElement * element)
+{
+  gboolean res;
+  GstPad *pad;
+
+  pad = mysrcpad;
+  res = gst_pad_push_event (pad, gst_event_new_stream_start ("test"));
+  fail_unless (res, "STREAM_START event not handled");
+}
+
+static void
+send_caps_event (const gchar * format, gint sample_rate, gint channels)
+{
+  GstCaps *caps;
+
+  caps = gst_caps_new_simple ("audio/x-raw",
+      "format", G_TYPE_STRING, format,
+      "rate", G_TYPE_INT, sample_rate, "channels", G_TYPE_INT, channels,
+      "layout", G_TYPE_STRING, "interleaved", NULL);
+  if (channels == 2) {
+    gst_caps_set_simple (caps,
+        "channel-mask", GST_TYPE_BITMASK,
+        G_GUINT64_CONSTANT (0x0000000000000003), NULL);
+  }
+  gst_pad_set_caps (mysrcpad, caps);
+  gst_caps_unref (caps);
+}
+
+static void
+send_segment_event (GstElement * element)
+{
+  GstSegment segment;
+  gboolean res;
+  GstPad *pad;
+
+  pad = mysrcpad;
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  res = gst_pad_push_event (pad, gst_event_new_segment (&segment));
+  fail_unless (res, "SEGMENT event not handled");
+}
+
+static void
+send_eos_event (GstElement * element)
+{
+  GstBus *bus = gst_element_get_bus (element);
+  GstPad *pad = mysrcpad;
+  gboolean res;
+
+  res = gst_pad_push_event (pad, gst_event_new_eos ());
+  fail_unless (res, "EOS event not handled");
+
+  /* There is no sink element, so _we_ post the EOS message on the bus here.  Of
+   * course we generate any EOS ourselves, but this allows us to poll for the
+   * EOS message in poll_eos if we expect the element to _not_ generate a TAG
+   * message.  That's better than waiting for a timeout to lapse. */
+  fail_unless (gst_bus_post (bus, gst_message_new_eos (NULL)));
+
+  gst_object_unref (bus);
+}
+
+static void
+send_tag_event (GstElement * element, GstTagList * tag_list)
+{
+  GstPad *pad = mysrcpad;
+  GstEvent *event = gst_event_new_tag (tag_list);
+
+  fail_unless (gst_pad_push_event (pad, event),
+      "Cannot send TAG event: Not handled.");
+}
+
+static void
+poll_eos (GstElement * element)
+{
+  GstBus *bus = gst_element_get_bus (element);
+  GstMessage *message;
+
+  message = gst_bus_poll (bus, GST_MESSAGE_EOS | GST_MESSAGE_TAG, GST_SECOND);
+  fail_unless (message != NULL, "Could not poll for EOS message: Timed out");
+  fail_unless (message->type == GST_MESSAGE_EOS,
+      "Could not poll for eos message: got message of type %s instead",
+      gst_message_type_get_name (message->type));
+
+  gst_message_unref (message);
+  gst_object_unref (bus);
+}
+
+static GstTagList *
+poll_tags_only (GstElement * element)
+{
+  GstBus *bus = gst_element_get_bus (element);
+  GstTagList *tag_list;
+  GstMessage *message;
+
+  message = gst_bus_poll (bus, GST_MESSAGE_TAG, GST_SECOND);
+  fail_unless (message != NULL, "Could not poll for TAG message: Timed out");
+
+  gst_message_parse_tag (message, &tag_list);
+  gst_message_unref (message);
+  gst_object_unref (bus);
+
+  return tag_list;
+}
+
+/* This also polls for EOS since the TAG message comes right before the end of
+ * streams. */
+
+static GstTagList *
+poll_tags_followed_by_eos (GstElement * element)
+{
+  GstTagList *tag_list = poll_tags_only (element);
+
+  poll_eos (element);
+
+  return tag_list;
+}
+
+#define MATCH_PEAK(p1, p2) ((p1 < p2 + 1e-6) && (p2 < p1 + 1e-6))
+#define MATCH_GAIN(g1, g2) ((g1 < g2 + 1e-13) && (g2 < g1 + 1e-13))
+
+static void
+fail_unless_track_gain (const GstTagList * tag_list, gdouble gain)
+{
+  gdouble result;
+
+  fail_unless (gst_tag_list_get_double (tag_list, GST_TAG_TRACK_GAIN, &result),
+      "Tag list contains no track gain value");
+  fail_unless (MATCH_GAIN (gain, result),
+      "Track gain %+.2f does not match, expected %+.2f", result, gain);
+}
+
+static void
+fail_unless_track_peak (const GstTagList * tag_list, gdouble peak)
+{
+  gdouble result;
+
+  fail_unless (gst_tag_list_get_double (tag_list, GST_TAG_TRACK_PEAK, &result),
+      "Tag list contains no track peak value");
+  fail_unless (MATCH_PEAK (peak, result),
+      "Track peak %f does not match, expected %f", result, peak);
+}
+
+static void
+fail_unless_album_gain (const GstTagList * tag_list, gdouble gain)
+{
+  gdouble result;
+
+  fail_unless (gst_tag_list_get_double (tag_list, GST_TAG_ALBUM_GAIN, &result),
+      "Tag list contains no album gain value");
+  fail_unless (MATCH_GAIN (result, gain),
+      "Album gain %+.2f does not match, expected %+.2f", result, gain);
+}
+
+static void
+fail_unless_album_peak (const GstTagList * tag_list, gdouble peak)
+{
+  gdouble result;
+
+  fail_unless (gst_tag_list_get_double (tag_list, GST_TAG_ALBUM_PEAK, &result),
+      "Tag list contains no album peak value");
+  fail_unless (MATCH_PEAK (peak, result),
+      "Album peak %f does not match, expected %f", result, peak);
+}
+
+static void
+fail_if_track_tags (const GstTagList * tag_list)
+{
+  gdouble result;
+
+  fail_if (gst_tag_list_get_double (tag_list, GST_TAG_TRACK_GAIN, &result),
+      "Tag list contains track gain value (but should not)");
+  fail_if (gst_tag_list_get_double (tag_list, GST_TAG_TRACK_PEAK, &result),
+      "Tag list contains track peak value (but should not)");
+}
+
+static void
+fail_if_album_tags (const GstTagList * tag_list)
+{
+  gdouble result;
+
+  fail_if (gst_tag_list_get_double (tag_list, GST_TAG_ALBUM_GAIN, &result),
+      "Tag list contains album gain value (but should not)");
+  fail_if (gst_tag_list_get_double (tag_list, GST_TAG_ALBUM_PEAK, &result),
+      "Tag list contains album peak value (but should not)");
+}
+
+static void
+fail_unless_num_tracks (GstElement * element, guint num_tracks)
+{
+  guint current;
+
+  g_object_get (element, "num-tracks", &current, NULL);
+  fail_unless (current == num_tracks,
+      "num-tracks property has incorrect value %u, expected %u",
+      current, num_tracks);
+}
+
+/* Functions that create buffers with constant sample values, for peak
+ * tests. */
+
+static GstBuffer *
+test_buffer_const_float_mono (gint sample_rate, gsize n_frames, gfloat value)
+{
+  GstBuffer *buf = gst_buffer_new_and_alloc (n_frames * sizeof (gfloat));
+  GstMapInfo map;
+  gfloat *data;
+  gint i;
+
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  data = (gfloat *) map.data;
+  for (i = n_frames; i--;)
+    *data++ = value;
+  gst_buffer_unmap (buf, &map);
+
+  ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
+
+  return buf;
+}
+
+static GstBuffer *
+test_buffer_const_float_stereo (gint sample_rate, gsize n_frames,
+    gfloat value_l, gfloat value_r)
+{
+  GstBuffer *buf = gst_buffer_new_and_alloc (n_frames * sizeof (gfloat) * 2);
+  GstMapInfo map;
+  gfloat *data;
+  gint i;
+
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  data = (gfloat *) map.data;
+  for (i = n_frames; i--;) {
+    *data++ = value_l;
+    *data++ = value_r;
+  }
+  gst_buffer_unmap (buf, &map);
+
+  ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
+
+  return buf;
+}
+
+static GstBuffer *
+test_buffer_const_int16_mono (gint sample_rate, gint depth, gsize n_frames,
+    gint16 value)
+{
+  GstBuffer *buf = gst_buffer_new_and_alloc (n_frames * sizeof (gint16));
+  gint16 *data;
+  GstMapInfo map;
+  gint i;
+
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  data = (gint16 *) map.data;
+  for (i = n_frames; i--;)
+    *data++ = value;
+  gst_buffer_unmap (buf, &map);
+
+  ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
+
+  return buf;
+}
+
+static GstBuffer *
+test_buffer_const_int16_stereo (gint sample_rate, gint depth, gsize n_frames,
+    gint16 value_l, gint16 value_r)
+{
+  GstBuffer *buf = gst_buffer_new_and_alloc (n_frames * sizeof (gint16) * 2);
+  gint16 *data;
+  GstMapInfo map;
+  gint i;
+
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  data = (gint16 *) map.data;
+  for (i = n_frames; i--;) {
+    *data++ = value_l;
+    *data++ = value_r;
+  }
+  gst_buffer_unmap (buf, &map);
+
+  ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
+
+  return buf;
+}
+
+/* Functions that create data buffers containing square signal
+ * waveforms. */
+
+static GstBuffer *
+test_buffer_square_float_mono (gint * accumulator, gint sample_rate,
+    gsize n_frames, gfloat value)
+{
+  GstBuffer *buf = gst_buffer_new_and_alloc (n_frames * sizeof (gfloat));
+  gfloat *data;
+  GstMapInfo map;
+  gint i;
+
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  data = (gfloat *) map.data;
+  for (i = n_frames; i--;) {
+    *accumulator += 1;
+    *accumulator %= 96;
+
+    if (*accumulator < 48)
+      *data++ = value;
+    else
+      *data++ = -value;
+  }
+  gst_buffer_unmap (buf, &map);
+
+  ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
+
+  return buf;
+}
+
+static GstBuffer *
+test_buffer_square_float_stereo (gint * accumulator, gint sample_rate,
+    gsize n_frames, gfloat value_l, gfloat value_r)
+{
+  GstBuffer *buf = gst_buffer_new_and_alloc (n_frames * sizeof (gfloat) * 2);
+  gfloat *data;
+  GstMapInfo map;
+  gint i;
+
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  data = (gfloat *) map.data;
+  for (i = n_frames; i--;) {
+    *accumulator += 1;
+    *accumulator %= 96;
+
+    if (*accumulator < 48) {
+      *data++ = value_l;
+      *data++ = value_r;
+    } else {
+      *data++ = -value_l;
+      *data++ = -value_r;
+    }
+  }
+  gst_buffer_unmap (buf, &map);
+
+  ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
+
+  return buf;
+}
+
+static GstBuffer *
+test_buffer_square_int16_mono (gint * accumulator, gint sample_rate,
+    gint depth, gsize n_frames, gint16 value)
+{
+  GstBuffer *buf = gst_buffer_new_and_alloc (n_frames * sizeof (gint16));
+  gint16 *data;
+  GstMapInfo map;
+  gint i;
+
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  data = (gint16 *) map.data;
+  for (i = n_frames; i--;) {
+    *accumulator += 1;
+    *accumulator %= 96;
+
+    if (*accumulator < 48)
+      *data++ = value;
+    else
+      *data++ = -MAX (value, -32767);
+  }
+  gst_buffer_unmap (buf, &map);
+
+  ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
+
+  return buf;
+}
+
+static GstBuffer *
+test_buffer_square_int16_stereo (gint * accumulator, gint sample_rate,
+    gint depth, gsize n_frames, gint16 value_l, gint16 value_r)
+{
+  GstBuffer *buf = gst_buffer_new_and_alloc (n_frames * sizeof (gint16) * 2);
+  gint16 *data;
+  GstMapInfo map;
+  gint i;
+
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  data = (gint16 *) map.data;
+  for (i = n_frames; i--;) {
+    *accumulator += 1;
+    *accumulator %= 96;
+
+    if (*accumulator < 48) {
+      *data++ = value_l;
+      *data++ = value_r;
+    } else {
+      *data++ = -MAX (value_l, -32767);
+      *data++ = -MAX (value_r, -32767);
+    }
+  }
+  gst_buffer_unmap (buf, &map);
+
+  ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
+
+  return buf;
+}
+
+static void
+push_buffer (GstBuffer * buf)
+{
+  /* gst_pad_push steals a reference. */
+  fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
+  ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
+}
+
+/*** Start of the tests. ***/
+
+/* This test looks redundant, but early versions of the element
+ * crashed when doing, well, nothing: */
+
+GST_START_TEST (test_no_buffer)
+{
+  GstElement *element = setup_rganalysis ();
+
+  set_playing_state (element);
+  send_eos_event (element);
+  poll_eos (element);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_no_buffer_album_1)
+{
+  GstElement *element = setup_rganalysis ();
+
+  set_playing_state (element);
+
+  /* Single track: */
+  send_stream_start_event (element);
+  send_segment_event (element);
+  send_eos_event (element);
+  poll_eos (element);
+
+  /* First album: */
+  g_object_set (element, "num-tracks", 3, NULL);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  send_eos_event (element);
+  poll_eos (element);
+  fail_unless_num_tracks (element, 2);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  send_eos_event (element);
+  poll_eos (element);
+  fail_unless_num_tracks (element, 1);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  send_eos_event (element);
+  poll_eos (element);
+  fail_unless_num_tracks (element, 0);
+
+  /* Second album: */
+  g_object_set (element, "num-tracks", 2, NULL);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  send_eos_event (element);
+  poll_eos (element);
+  fail_unless_num_tracks (element, 1);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  send_eos_event (element);
+  poll_eos (element);
+  fail_unless_num_tracks (element, 0);
+
+  /* Single track: */
+  send_flush_events (element);
+  send_segment_event (element);
+  send_eos_event (element);
+  poll_eos (element);
+  fail_unless_num_tracks (element, 0);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_no_buffer_album_2)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+  gint accumulator = 0;
+  gint i;
+
+  g_object_set (element, "num-tracks", 3, NULL);
+  set_playing_state (element);
+
+  /* No buffer for the first track. */
+  send_stream_start_event (element);
+  send_segment_event (element);
+  send_eos_event (element);
+  /* No tags should be posted, there was nothing to analyze: */
+  poll_eos (element);
+  fail_unless_num_tracks (element, 2);
+
+  /* A test waveform with known gain result as second track: */
+
+  send_flush_events (element);
+  send_caps_event (GST_AUDIO_NE (F32), 44100, 1);
+  send_segment_event (element);
+  for (i = 20; i--;)
+    push_buffer (test_buffer_square_float_mono (&accumulator, 44100, 512,
+            0.25));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.25);
+  fail_unless_track_gain (tag_list, -6.20);
+  /* Album is not finished yet: */
+  fail_if_album_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+  fail_unless_num_tracks (element, 1);
+
+  /* No buffer for the last track. */
+
+  send_flush_events (element);
+  send_segment_event (element);
+  send_eos_event (element);
+
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_album_peak (tag_list, 0.25);
+  fail_unless_album_gain (tag_list, -6.20);
+  /* No track tags should be posted, as there was no data for it: */
+  fail_if_track_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+  fail_unless_num_tracks (element, 0);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_empty_buffers)
+{
+  GstElement *element = setup_rganalysis ();
+
+  set_playing_state (element);
+
+  /* Single track: */
+  send_stream_start_event (element);
+  send_caps_event (GST_AUDIO_NE (F32), 44100, 2);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_stereo (44100, 0, 0.0, 0.0));
+  send_eos_event (element);
+  poll_eos (element);
+
+  /* First album: */
+  g_object_set (element, "num-tracks", 2, NULL);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_stereo (44100, 0, 0.0, 0.0));
+  send_eos_event (element);
+  poll_eos (element);
+  fail_unless_num_tracks (element, 1);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_stereo (44100, 0, 0.0, 0.0));
+  send_eos_event (element);
+  poll_eos (element);
+  fail_unless_num_tracks (element, 0);
+
+  /* Second album, with a single track: */
+  g_object_set (element, "num-tracks", 1, NULL);
+  send_flush_events (element);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_stereo (44100, 0, 0.0, 0.0));
+  send_eos_event (element);
+  poll_eos (element);
+  fail_unless_num_tracks (element, 0);
+
+  /* Single track: */
+  send_flush_events (element);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_stereo (44100, 0, 0.0, 0.0));
+  send_eos_event (element);
+  poll_eos (element);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+/* Tests for correctness of the peak values. */
+
+/* Float peak test.  For stereo, one channel has the constant value of -1.369,
+ * the other one 0.0.  This tests many things: The result peak value should
+ * occur on any channel.  The peak is of course the absolute amplitude, so 1.369
+ * should be the result.  This will also detect if the code uses the absolute
+ * value during the comparison.  If it is buggy it will return 0.0 since 0.0 >
+ * -1.369.  Furthermore, this makes sure that there is no problem with headroom
+ * (exceeding 0dBFS).  In the wild you get float samples > 1.0 from stuff like
+ * vorbis. */
+
+GST_START_TEST (test_peak_float)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+
+  set_playing_state (element);
+  send_stream_start_event (element);
+  send_caps_event (GST_AUDIO_NE (F32), 8000, 2);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_stereo (8000, 512, -1.369, 0.0));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 1.369);
+  gst_tag_list_unref (tag_list);
+
+  /* Swapped channels. */
+  send_flush_events (element);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_stereo (8000, 512, 0.0, -1.369));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 1.369);
+  gst_tag_list_unref (tag_list);
+
+  /* Mono. */
+  send_flush_events (element);
+  send_caps_event (GST_AUDIO_NE (F32), 8000, 1);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_mono (8000, 512, -1.369));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 1.369);
+  gst_tag_list_unref (tag_list);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_peak_int16_16)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+
+  set_playing_state (element);
+
+  /* Half amplitude. */
+  send_stream_start_event (element);
+  send_caps_event (GST_AUDIO_NE (S16), 8000, 2);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_int16_stereo (8000, 16, 512, 1 << 14, 0));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.5);
+  gst_tag_list_unref (tag_list);
+
+  /* Swapped channels. */
+  send_flush_events (element);
+  send_caps_event (GST_AUDIO_NE (S16), 8000, 2);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_int16_stereo (8000, 16, 512, 0, 1 << 14));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.5);
+  gst_tag_list_unref (tag_list);
+
+  /* Mono. */
+  send_flush_events (element);
+  send_caps_event (GST_AUDIO_NE (S16), 8000, 1);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_int16_mono (8000, 16, 512, 1 << 14));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.5);
+  gst_tag_list_unref (tag_list);
+
+  /* Half amplitude, negative variant. */
+  send_flush_events (element);
+  send_caps_event (GST_AUDIO_NE (S16), 8000, 2);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_int16_stereo (8000, 16, 512, -(1 << 14), 0));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.5);
+  gst_tag_list_unref (tag_list);
+
+  /* Swapped channels. */
+  send_flush_events (element);
+  send_caps_event (GST_AUDIO_NE (S16), 8000, 2);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_int16_stereo (8000, 16, 512, 0, -(1 << 14)));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.5);
+  gst_tag_list_unref (tag_list);
+
+  /* Mono. */
+  send_flush_events (element);
+  send_caps_event (GST_AUDIO_NE (S16), 8000, 1);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_int16_mono (8000, 16, 512, -(1 << 14)));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.5);
+  gst_tag_list_unref (tag_list);
+
+
+  /* Now check for correct normalization of the peak value: Sample
+   * values of this format range from -32768 to 32767.  So for the
+   * highest positive amplitude we do not reach 1.0, only for
+   * -32768! */
+
+  send_flush_events (element);
+  send_caps_event (GST_AUDIO_NE (S16), 8000, 2);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_int16_stereo (8000, 16, 512, 32767, 0));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 32767. / 32768.);
+  gst_tag_list_unref (tag_list);
+
+  /* Swapped channels. */
+  send_flush_events (element);
+  send_caps_event (GST_AUDIO_NE (S16), 8000, 2);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_int16_stereo (8000, 16, 512, 0, 32767));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 32767. / 32768.);
+  gst_tag_list_unref (tag_list);
+
+  /* Mono. */
+  send_flush_events (element);
+  send_caps_event (GST_AUDIO_NE (S16), 8000, 1);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_int16_mono (8000, 16, 512, 32767));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 32767. / 32768.);
+  gst_tag_list_unref (tag_list);
+
+
+  /* Negative variant, reaching 1.0. */
+  send_flush_events (element);
+  send_caps_event (GST_AUDIO_NE (S16), 8000, 2);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_int16_stereo (8000, 16, 512, -32768, 0));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 1.0);
+  gst_tag_list_unref (tag_list);
+
+  /* Swapped channels. */
+  send_flush_events (element);
+  send_caps_event (GST_AUDIO_NE (S16), 8000, 2);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_int16_stereo (8000, 16, 512, 0, -32768));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 1.0);
+  gst_tag_list_unref (tag_list);
+
+  /* Mono. */
+  send_flush_events (element);
+  send_caps_event (GST_AUDIO_NE (S16), 8000, 1);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_int16_mono (8000, 16, 512, -32768));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 1.0);
+  gst_tag_list_unref (tag_list);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_peak_album)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+
+  g_object_set (element, "num-tracks", 2, NULL);
+  set_playing_state (element);
+
+  send_stream_start_event (element);
+  send_caps_event (GST_AUDIO_NE (F32), 8000, 2);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_stereo (8000, 1024, 1.0, 0.0));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 1.0);
+  fail_if_album_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+  fail_unless_num_tracks (element, 1);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_stereo (8000, 1024, 0.0, 0.5));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.5);
+  fail_unless_album_peak (tag_list, 1.0);
+  gst_tag_list_unref (tag_list);
+  fail_unless_num_tracks (element, 0);
+
+  /* Try a second album: */
+  g_object_set (element, "num-tracks", 3, NULL);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_stereo (8000, 1024, 0.4, 0.4));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.4);
+  fail_if_album_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+  fail_unless_num_tracks (element, 2);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_stereo (8000, 1024, 0.45, 0.45));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.45);
+  fail_if_album_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+  fail_unless_num_tracks (element, 1);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_stereo (8000, 1024, 0.2, 0.2));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.2);
+  fail_unless_album_peak (tag_list, 0.45);
+  gst_tag_list_unref (tag_list);
+  fail_unless_num_tracks (element, 0);
+
+  /* And now a single track, not in album mode (num-tracks is 0
+   * now): */
+  send_flush_events (element);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_stereo (8000, 1024, 0.1, 0.1));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.1);
+  fail_if_album_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+/* Switching from track to album mode. */
+
+GST_START_TEST (test_peak_track_album)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+
+  set_playing_state (element);
+
+  send_stream_start_event (element);
+  send_caps_event (GST_AUDIO_NE (F32), 8000, 1);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_mono (8000, 1024, 1.0));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 1.0);
+  fail_if_album_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+
+  g_object_set (element, "num-tracks", 1, NULL);
+  send_flush_events (element);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_mono (8000, 1024, 0.5));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.5);
+  fail_unless_album_peak (tag_list, 0.5);
+  gst_tag_list_unref (tag_list);
+  fail_unless_num_tracks (element, 0);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+/* Disabling album processing before the end of the album.  Probably a rare edge
+ * case and applications should not rely on this to work.  They need to send the
+ * element to the READY state to clear up after an aborted album anyway since
+ * they might need to process another album afterwards. */
+
+GST_START_TEST (test_peak_album_abort_to_track)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+
+  g_object_set (element, "num-tracks", 2, NULL);
+  set_playing_state (element);
+
+  send_stream_start_event (element);
+  send_caps_event (GST_AUDIO_NE (F32), 8000, 2);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_stereo (8000, 1024, 1.0, 0.0));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 1.0);
+  fail_if_album_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+  fail_unless_num_tracks (element, 1);
+
+  g_object_set (element, "num-tracks", 0, NULL);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  push_buffer (test_buffer_const_float_stereo (8000, 1024, 0.0, 0.5));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.5);
+  fail_if_album_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_gain_album)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+  gint accumulator;
+  gint i;
+
+  g_object_set (element, "num-tracks", 3, NULL);
+  set_playing_state (element);
+
+  /* The three tracks are constructed such that if any of these is in fact
+   * ignored for the album gain, the album gain will differ. */
+  send_stream_start_event (element);
+  send_caps_event (GST_AUDIO_NE (F32), 44100, 2);
+  send_segment_event (element);
+  accumulator = 0;
+  for (i = 8; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 44100, 512,
+            0.75, 0.75));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.75);
+  fail_unless_track_gain (tag_list, -15.70);
+  fail_if_album_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  accumulator = 0;
+  for (i = 12; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 44100, 512,
+            0.5, 0.5));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.5);
+  fail_unless_track_gain (tag_list, -12.22);
+  fail_if_album_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  accumulator = 0;
+  for (i = 180; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 44100, 512,
+            0.25, 0.25));
+  send_eos_event (element);
+
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.25);
+  fail_unless_track_gain (tag_list, -6.20);
+  fail_unless_album_peak (tag_list, 0.75);
+  /* Strangely, wavegain reports -12.17 for the album, but the fixed
+   * metaflac agrees to us.  Could be a 32767 vs. 32768 issue. */
+  fail_unless_album_gain (tag_list, -12.18);
+  gst_tag_list_unref (tag_list);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+/* Checks ensuring that the "forced" property works as advertised. */
+
+GST_START_TEST (test_forced)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+  gint accumulator = 0;
+  gint i;
+
+  g_object_set (element, "forced", FALSE, NULL);
+  set_playing_state (element);
+
+  send_stream_start_event (element);
+  send_caps_event (GST_AUDIO_NE (F32), 44100, 2);
+  send_segment_event (element);
+  tag_list = gst_tag_list_new_empty ();
+  /* Provided values are totally arbitrary. */
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
+      GST_TAG_TRACK_PEAK, 1.0, GST_TAG_TRACK_GAIN, 2.21, NULL);
+  send_tag_event (element, tag_list);
+
+  for (i = 20; i--;)
+    push_buffer (test_buffer_const_float_stereo (44100, 512, 0.5, 0.5));
+  send_eos_event (element);
+
+  /* This fails if a tag message is generated: */
+  /* Same values as above */
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_gain (tag_list, 2.21);
+  fail_unless_track_peak (tag_list, 1.0);
+  gst_tag_list_unref (tag_list);
+
+  /* Now back to a track without tags. */
+  send_flush_events (element);
+  send_segment_event (element);
+  for (i = 20; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 44100, 512,
+            0.25, 0.25));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.25);
+  fail_unless_track_gain (tag_list, get_expected_gain (44100));
+  gst_tag_list_unref (tag_list);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+/* Sending track gain and peak in separate tag lists. */
+
+GST_START_TEST (test_forced_separate)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+  gint accumulator = 0;
+  gint i;
+
+  g_object_set (element, "forced", FALSE, NULL);
+  set_playing_state (element);
+
+  send_stream_start_event (element);
+  send_caps_event (GST_AUDIO_NE (F32), 44100, 2);
+  send_segment_event (element);
+  tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND, GST_TAG_TRACK_GAIN, 2.21,
+      NULL);
+  send_tag_event (element, tag_list);
+
+  tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND, GST_TAG_TRACK_PEAK, 1.0,
+      NULL);
+  send_tag_event (element, tag_list);
+
+  for (i = 20; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 44100, 512,
+            0.5, 0.5));
+  send_eos_event (element);
+
+  /* Same values as above */
+  tag_list = poll_tags_only (element);
+  fail_unless_track_gain (tag_list, 2.21);
+  gst_tag_list_unref (tag_list);
+
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 1.0);
+  gst_tag_list_unref (tag_list);
+
+  /* Now a track without tags. */
+  send_flush_events (element);
+  send_segment_event (element);
+  accumulator = 0;
+  for (i = 20; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 44100, 512,
+            0.25, 0.25));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.25);
+  fail_unless_track_gain (tag_list, get_expected_gain (44100));
+  fail_if_album_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+/* A TAG event is sent _after_ data has already been processed.  In real
+ * pipelines, this could happen if there is more than one rganalysis element (by
+ * accident).  While it would have analyzed all the data prior to receiving the
+ * event, I expect it to not post its results if not forced.  This test is
+ * almost equivalent to test_forced. */
+
+GST_START_TEST (test_forced_after_data)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+  gint accumulator = 0;
+  gint i;
+
+  g_object_set (element, "forced", FALSE, NULL);
+  set_playing_state (element);
+
+  send_stream_start_event (element);
+  send_caps_event (GST_AUDIO_NE (F32), 8000, 2);
+  send_segment_event (element);
+  for (i = 20; i--;)
+    push_buffer (test_buffer_const_float_stereo (8000, 512, 0.5, 0.5));
+
+  tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
+      GST_TAG_TRACK_PEAK, 1.0, GST_TAG_TRACK_GAIN, 2.21, NULL);
+  send_tag_event (element, tag_list);
+
+  send_eos_event (element);
+
+  /* Same values as above */
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_gain (tag_list, 2.21);
+  fail_unless_track_peak (tag_list, 1.0);
+  gst_tag_list_unref (tag_list);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  /* Now back to a normal track, this one has no tags: */
+  for (i = 20; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 8000, 512, 0.25,
+            0.25));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.25);
+  fail_unless_track_gain (tag_list, get_expected_gain (8000));
+  gst_tag_list_unref (tag_list);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+/* Like test_forced, but *analyze* an album afterwards.  The two tests following
+ * this one check the *skipping* of albums. */
+
+GST_START_TEST (test_forced_album)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+  gint accumulator;
+  gint i;
+
+  g_object_set (element, "forced", FALSE, NULL);
+  set_playing_state (element);
+
+  send_stream_start_event (element);
+  send_caps_event (GST_AUDIO_NE (F32), 44100, 2);
+  send_segment_event (element);
+  tag_list = gst_tag_list_new_empty ();
+  /* Provided values are totally arbitrary. */
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
+      GST_TAG_TRACK_PEAK, 1.0, GST_TAG_TRACK_GAIN, 2.21, NULL);
+  send_tag_event (element, tag_list);
+
+  accumulator = 0;
+  for (i = 20; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 44100, 512,
+            0.5, 0.5));
+  send_eos_event (element);
+
+  /* Same values as above */
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_gain (tag_list, 2.21);
+  fail_unless_track_peak (tag_list, 1.0);
+  gst_tag_list_unref (tag_list);
+
+  /* Now an album without tags. */
+  g_object_set (element, "num-tracks", 2, NULL);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  accumulator = 0;
+  for (i = 20; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 44100, 512,
+            0.25, 0.25));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.25);
+  fail_unless_track_gain (tag_list, get_expected_gain (44100));
+  fail_if_album_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+  fail_unless_num_tracks (element, 1);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  accumulator = 0;
+  for (i = 20; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 44100, 512,
+            0.25, 0.25));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.25);
+  fail_unless_track_gain (tag_list, get_expected_gain (44100));
+  fail_unless_album_peak (tag_list, 0.25);
+  fail_unless_album_gain (tag_list, get_expected_gain (44100));
+  gst_tag_list_unref (tag_list);
+  fail_unless_num_tracks (element, 0);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_forced_album_skip)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+  gint accumulator = 0;
+  gint i;
+
+  g_object_set (element, "forced", FALSE, "num-tracks", 2, NULL);
+  set_playing_state (element);
+
+  send_stream_start_event (element);
+  send_caps_event (GST_AUDIO_NE (F32), 8000, 2);
+  send_segment_event (element);
+  tag_list = gst_tag_list_new_empty ();
+  /* Provided values are totally arbitrary. */
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
+      GST_TAG_TRACK_PEAK, 0.75, GST_TAG_TRACK_GAIN, 2.21,
+      GST_TAG_ALBUM_PEAK, 0.80, GST_TAG_ALBUM_GAIN, -0.11, NULL);
+  send_tag_event (element, tag_list);
+
+  for (i = 20; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 8000, 512, 0.25,
+            0.25));
+  send_eos_event (element);
+
+  /* Same values as above */
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_gain (tag_list, 2.21);
+  fail_unless_track_peak (tag_list, 0.75);
+  gst_tag_list_unref (tag_list);
+
+  fail_unless_num_tracks (element, 1);
+
+  /* This track has no tags, but needs to be skipped anyways since we
+   * are in album processing mode. */
+  send_flush_events (element);
+  send_segment_event (element);
+  for (i = 20; i--;)
+    push_buffer (test_buffer_const_float_stereo (8000, 512, 0.0, 0.0));
+  send_eos_event (element);
+  poll_eos (element);
+  fail_unless_num_tracks (element, 0);
+
+  /* Normal track after the album.  Of course not to be skipped. */
+  send_flush_events (element);
+  send_segment_event (element);
+  accumulator = 0;
+  for (i = 20; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 8000, 512, 0.25,
+            0.25));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.25);
+  fail_unless_track_gain (tag_list, get_expected_gain (8000));
+  fail_if_album_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_forced_album_no_skip)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+  gint accumulator = 0;
+  gint i;
+
+  g_object_set (element, "forced", FALSE, "num-tracks", 2, NULL);
+  set_playing_state (element);
+
+  send_stream_start_event (element);
+  send_caps_event (GST_AUDIO_NE (F32), 8000, 2);
+  send_segment_event (element);
+  for (i = 20; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 8000, 512, 0.25,
+            0.25));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.25);
+  fail_unless_track_gain (tag_list, get_expected_gain (8000));
+  fail_if_album_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+  fail_unless_num_tracks (element, 1);
+
+  /* The second track has indeed full tags, but although being not forced, this
+   * one has to be processed because album processing is on. */
+  send_flush_events (element);
+  send_segment_event (element);
+  tag_list = gst_tag_list_new_empty ();
+  /* Provided values are totally arbitrary. */
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
+      GST_TAG_TRACK_PEAK, 0.75, GST_TAG_TRACK_GAIN, 2.21,
+      GST_TAG_ALBUM_PEAK, 0.80, GST_TAG_ALBUM_GAIN, -0.11, NULL);
+  send_tag_event (element, tag_list);
+  for (i = 20; i--;)
+    push_buffer (test_buffer_const_float_stereo (8000, 512, 0.0, 0.0));
+  send_eos_event (element);
+
+  /* the first batch from the tags */
+  tag_list = poll_tags_only (element);
+  fail_unless_track_peak (tag_list, 0.75);
+  fail_unless_track_gain (tag_list, 2.21);
+  gst_tag_list_unref (tag_list);
+
+  /* the second from the processing */
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.0);
+  fail_unless_track_gain (tag_list, SILENCE_GAIN);
+  /* Second track was just silence so the album peak equals the first
+   * track's peak. */
+  fail_unless_album_peak (tag_list, 0.25);
+  /* Statistical processing leads to the second track being
+   * ignored for the gain (because it is so short): */
+  fail_unless_album_gain (tag_list, get_expected_gain (8000));
+  gst_tag_list_unref (tag_list);
+  fail_unless_num_tracks (element, 0);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_forced_abort_album_no_skip)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+  gint accumulator = 0;
+  gint i;
+
+  g_object_set (element, "forced", FALSE, "num-tracks", 2, NULL);
+  set_playing_state (element);
+
+  send_stream_start_event (element);
+  send_caps_event (GST_AUDIO_NE (F32), 8000, 2);
+  send_segment_event (element);
+  for (i = 20; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 8000, 512, 0.25,
+            0.25));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.25);
+  fail_unless_track_gain (tag_list, get_expected_gain (8000));
+  fail_if_album_tags (tag_list);
+  gst_tag_list_unref (tag_list);
+  fail_unless_num_tracks (element, 1);
+
+  /* Disabling album processing before end of album: */
+  g_object_set (element, "num-tracks", 0, NULL);
+
+  send_flush_events (element);
+  send_segment_event (element);
+
+  /* Processing a track that has to be skipped. */
+  tag_list = gst_tag_list_new_empty ();
+  /* Provided values are totally arbitrary. */
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
+      GST_TAG_TRACK_PEAK, 0.75, GST_TAG_TRACK_GAIN, 2.21,
+      GST_TAG_ALBUM_PEAK, 0.80, GST_TAG_ALBUM_GAIN, -0.11, NULL);
+  send_tag_event (element, tag_list);
+  for (i = 20; i--;)
+    push_buffer (test_buffer_const_float_stereo (8000, 512, 0.0, 0.0));
+  send_eos_event (element);
+
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.75);
+  fail_unless_track_gain (tag_list, 2.21);
+  gst_tag_list_unref (tag_list);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_reference_level)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+  gdouble ref_level;
+  gint accumulator = 0;
+  gint i;
+
+  set_playing_state (element);
+
+  send_stream_start_event (element);
+  send_caps_event (GST_AUDIO_NE (F32), 44100, 2);
+  send_segment_event (element);
+  for (i = 20; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 44100, 512,
+            0.25, 0.25));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.25);
+  fail_unless_track_gain (tag_list, get_expected_gain (44100));
+  fail_if_album_tags (tag_list);
+  fail_unless (gst_tag_list_get_double (tag_list, GST_TAG_REFERENCE_LEVEL,
+          &ref_level) && MATCH_GAIN (ref_level, 89.),
+      "Incorrect reference level tag");
+  gst_tag_list_unref (tag_list);
+
+  g_object_set (element, "reference-level", 83., "num-tracks", 2, NULL);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  for (i = 20; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 44100, 512,
+            0.25, 0.25));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.25);
+  fail_unless_track_gain (tag_list, get_expected_gain (44100) - 6.);
+  fail_if_album_tags (tag_list);
+  fail_unless (gst_tag_list_get_double (tag_list, GST_TAG_REFERENCE_LEVEL,
+          &ref_level) && MATCH_GAIN (ref_level, 83.),
+      "Incorrect reference level tag");
+  gst_tag_list_unref (tag_list);
+
+  send_flush_events (element);
+  send_segment_event (element);
+  accumulator = 0;
+  for (i = 20; i--;)
+    push_buffer (test_buffer_square_float_stereo (&accumulator, 44100, 512,
+            0.25, 0.25));
+  send_eos_event (element);
+  tag_list = poll_tags_followed_by_eos (element);
+  fail_unless_track_peak (tag_list, 0.25);
+  fail_unless_track_gain (tag_list, get_expected_gain (44100) - 6.);
+  fail_unless_album_peak (tag_list, 0.25);
+  /* We provided the same waveform twice, with a reset separating
+   * them.  Therefore, the album gain matches the track gain. */
+  fail_unless_album_gain (tag_list, get_expected_gain (44100) - 6.);
+  fail_unless (gst_tag_list_get_double (tag_list, GST_TAG_REFERENCE_LEVEL,
+          &ref_level) && MATCH_GAIN (ref_level, 83.),
+      "Incorrect reference level tag");
+  gst_tag_list_unref (tag_list);
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_all_formats)
+{
+  GstElement *element = setup_rganalysis ();
+  GstTagList *tag_list;
+  gint accumulator = 0;
+  gint i, j;
+
+  set_playing_state (element);
+  send_stream_start_event (element);
+  for (i = G_N_ELEMENTS (supported_rates); i--;) {
+    send_flush_events (element);
+    send_caps_event (GST_AUDIO_NE (F32), supported_rates[i].sample_rate, 2);
+    send_segment_event (element);
+    accumulator = 0;
+    for (j = 0; j < 4; j++)
+      push_buffer (test_buffer_square_float_stereo (&accumulator,
+              supported_rates[i].sample_rate, 512, 0.25, 0.25));
+    send_caps_event (GST_AUDIO_NE (F32), supported_rates[i].sample_rate, 1);
+    for (j = 0; j < 3; j++)
+      push_buffer (test_buffer_square_float_mono (&accumulator,
+              supported_rates[i].sample_rate, 512, 0.25));
+    send_caps_event (GST_AUDIO_NE (S16), supported_rates[i].sample_rate, 2);
+    for (j = 0; j < 4; j++)
+      push_buffer (test_buffer_square_int16_stereo (&accumulator,
+              supported_rates[i].sample_rate, 16, 512, 1 << 13, 1 << 13));
+    send_caps_event (GST_AUDIO_NE (S16), supported_rates[i].sample_rate, 1);
+    for (j = 0; j < 3; j++)
+      push_buffer (test_buffer_square_int16_mono (&accumulator,
+              supported_rates[i].sample_rate, 16, 512, 1 << 13));
+    send_eos_event (element);
+    tag_list = poll_tags_followed_by_eos (element);
+    fail_unless_track_peak (tag_list, 0.25);
+    fail_unless_track_gain (tag_list, supported_rates[i].gain);
+    gst_tag_list_unref (tag_list);
+  }
+
+  cleanup_rganalysis (element);
+}
+
+GST_END_TEST;
+
+/* Checks ensuring all advertised supported sample rates are really
+ * accepted, for integer and float, mono and stereo.  This also
+ * verifies that the correct gain is computed for all formats (except
+ * odd bit depths). */
+
+#define MAKE_GAIN_TEST_FLOAT_MONO(sample_rate)                        \
+  GST_START_TEST (test_gain_float_mono_##sample_rate)                 \
+{                                                                     \
+  GstElement *element = setup_rganalysis ();                          \
+  GstTagList *tag_list;                                               \
+  gint accumulator = 0;                                               \
+  gint i;                                                             \
+                                                                      \
+  set_playing_state (element);                                        \
+  send_stream_start_event (element);                                  \
+  send_caps_event (GST_AUDIO_NE (F32), sample_rate, 1);               \
+  send_segment_event (element);                                       \
+                                                                      \
+  for (i = 0; i < 20; i++)                                            \
+    push_buffer (test_buffer_square_float_mono (&accumulator,         \
+            sample_rate, 512, 0.25));                                 \
+  send_eos_event (element);                                           \
+  tag_list = poll_tags_followed_by_eos (element);                                     \
+  fail_unless_track_peak (tag_list, 0.25);                            \
+  fail_unless_track_gain (tag_list,                                   \
+      get_expected_gain (sample_rate));                               \
+  gst_tag_list_unref (tag_list);                                       \
+                                                                      \
+  cleanup_rganalysis (element);                                       \
+}                                                                     \
+                                                                      \
+GST_END_TEST;
+
+#define MAKE_GAIN_TEST_FLOAT_STEREO(sample_rate)                      \
+  GST_START_TEST (test_gain_float_stereo_##sample_rate)               \
+{                                                                     \
+  GstElement *element = setup_rganalysis ();                          \
+  GstTagList *tag_list;                                               \
+  gint accumulator = 0;                                               \
+  gint i;                                                             \
+                                                                      \
+  set_playing_state (element);                                        \
+  send_stream_start_event (element);                                  \
+  send_caps_event (GST_AUDIO_NE (F32), sample_rate, 2);               \
+  send_segment_event (element);                                       \
+                                                                      \
+  for (i = 0; i < 20; i++)                                            \
+    push_buffer (test_buffer_square_float_stereo (&accumulator,       \
+            sample_rate, 512, 0.25, 0.25));                           \
+  send_eos_event (element);                                           \
+  tag_list = poll_tags_followed_by_eos (element);                                     \
+  fail_unless_track_peak (tag_list, 0.25);                            \
+  fail_unless_track_gain (tag_list,                                   \
+      get_expected_gain (sample_rate));                               \
+  gst_tag_list_unref (tag_list);                                       \
+                                                                      \
+  cleanup_rganalysis (element);                                       \
+}                                                                     \
+                                                                      \
+GST_END_TEST;
+
+#define MAKE_GAIN_TEST_INT16_MONO(sample_rate, depth)                 \
+  GST_START_TEST (test_gain_int16_##depth##_mono_##sample_rate)       \
+{                                                                     \
+  GstElement *element = setup_rganalysis ();                          \
+  GstTagList *tag_list;                                               \
+  gint accumulator = 0;                                               \
+  gint i;                                                             \
+                                                                      \
+  set_playing_state (element);                                        \
+  send_stream_start_event (element);                                  \
+  send_caps_event (GST_AUDIO_NE (S16), sample_rate, 1);               \
+  send_segment_event (element);                                       \
+                                                                      \
+  for (i = 0; i < 20; i++)                                            \
+    push_buffer (test_buffer_square_int16_mono (&accumulator,         \
+            sample_rate, depth, 512, 1 << (13 + depth - 16)));        \
+                                                                      \
+  send_eos_event (element);                                           \
+  tag_list = poll_tags_followed_by_eos (element);                                     \
+  fail_unless_track_peak (tag_list, 0.25);                            \
+  fail_unless_track_gain (tag_list,                                   \
+      get_expected_gain (sample_rate));                               \
+  gst_tag_list_unref (tag_list);                                       \
+                                                                      \
+  cleanup_rganalysis (element);                                       \
+}                                                                     \
+                                                                      \
+GST_END_TEST;
+
+#define MAKE_GAIN_TEST_INT16_STEREO(sample_rate, depth)               \
+  GST_START_TEST (test_gain_int16_##depth##_stereo_##sample_rate)     \
+{                                                                     \
+  GstElement *element = setup_rganalysis ();                          \
+  GstTagList *tag_list;                                               \
+  gint accumulator = 0;                                               \
+  gint i;                                                             \
+                                                                      \
+  set_playing_state (element);                                        \
+  send_stream_start_event (element);                                  \
+  send_caps_event (GST_AUDIO_NE (S16), sample_rate, 2);               \
+  send_segment_event (element);                                       \
+                                                                      \
+  for (i = 0; i < 20; i++)                                            \
+    push_buffer (test_buffer_square_int16_stereo (&accumulator,       \
+            sample_rate, depth, 512, 1 << (13 + depth - 16),          \
+            1 << (13 + depth - 16)));                                 \
+  send_eos_event (element);                                           \
+  tag_list = poll_tags_followed_by_eos (element);                                     \
+  fail_unless_track_peak (tag_list, 0.25);                            \
+  fail_unless_track_gain (tag_list,                                   \
+      get_expected_gain (sample_rate));                               \
+  gst_tag_list_unref (tag_list);                                       \
+                                                                      \
+  cleanup_rganalysis (element);                                       \
+}                                                                     \
+                                                                      \
+GST_END_TEST;
+
+MAKE_GAIN_TEST_FLOAT_MONO (8000);
+MAKE_GAIN_TEST_FLOAT_MONO (11025);
+MAKE_GAIN_TEST_FLOAT_MONO (12000);
+MAKE_GAIN_TEST_FLOAT_MONO (16000);
+MAKE_GAIN_TEST_FLOAT_MONO (22050);
+MAKE_GAIN_TEST_FLOAT_MONO (24000);
+MAKE_GAIN_TEST_FLOAT_MONO (32000);
+MAKE_GAIN_TEST_FLOAT_MONO (44100);
+MAKE_GAIN_TEST_FLOAT_MONO (48000);
+
+MAKE_GAIN_TEST_FLOAT_STEREO (8000);
+MAKE_GAIN_TEST_FLOAT_STEREO (11025);
+MAKE_GAIN_TEST_FLOAT_STEREO (12000);
+MAKE_GAIN_TEST_FLOAT_STEREO (16000);
+MAKE_GAIN_TEST_FLOAT_STEREO (22050);
+MAKE_GAIN_TEST_FLOAT_STEREO (24000);
+MAKE_GAIN_TEST_FLOAT_STEREO (32000);
+MAKE_GAIN_TEST_FLOAT_STEREO (44100);
+MAKE_GAIN_TEST_FLOAT_STEREO (48000);
+
+MAKE_GAIN_TEST_INT16_MONO (8000, 16);
+MAKE_GAIN_TEST_INT16_MONO (11025, 16);
+MAKE_GAIN_TEST_INT16_MONO (12000, 16);
+MAKE_GAIN_TEST_INT16_MONO (16000, 16);
+MAKE_GAIN_TEST_INT16_MONO (22050, 16);
+MAKE_GAIN_TEST_INT16_MONO (24000, 16);
+MAKE_GAIN_TEST_INT16_MONO (32000, 16);
+MAKE_GAIN_TEST_INT16_MONO (44100, 16);
+MAKE_GAIN_TEST_INT16_MONO (48000, 16);
+
+MAKE_GAIN_TEST_INT16_STEREO (8000, 16);
+MAKE_GAIN_TEST_INT16_STEREO (11025, 16);
+MAKE_GAIN_TEST_INT16_STEREO (12000, 16);
+MAKE_GAIN_TEST_INT16_STEREO (16000, 16);
+MAKE_GAIN_TEST_INT16_STEREO (22050, 16);
+MAKE_GAIN_TEST_INT16_STEREO (24000, 16);
+MAKE_GAIN_TEST_INT16_STEREO (32000, 16);
+MAKE_GAIN_TEST_INT16_STEREO (44100, 16);
+MAKE_GAIN_TEST_INT16_STEREO (48000, 16);
+
+static Suite *
+rganalysis_suite (void)
+{
+  Suite *s = suite_create ("rganalysis");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_no_buffer);
+  tcase_add_test (tc_chain, test_no_buffer_album_1);
+  tcase_add_test (tc_chain, test_no_buffer_album_2);
+  tcase_add_test (tc_chain, test_empty_buffers);
+
+  tcase_add_test (tc_chain, test_peak_float);
+  tcase_add_test (tc_chain, test_peak_int16_16);
+
+  tcase_add_test (tc_chain, test_peak_album);
+  tcase_add_test (tc_chain, test_peak_track_album);
+  tcase_add_test (tc_chain, test_peak_album_abort_to_track);
+
+  tcase_add_test (tc_chain, test_gain_album);
+
+  tcase_add_test (tc_chain, test_forced);
+  tcase_add_test (tc_chain, test_forced_separate);
+  tcase_add_test (tc_chain, test_forced_after_data);
+  tcase_add_test (tc_chain, test_forced_album);
+  tcase_add_test (tc_chain, test_forced_album_skip);
+  tcase_add_test (tc_chain, test_forced_album_no_skip);
+  tcase_add_test (tc_chain, test_forced_abort_album_no_skip);
+
+  tcase_add_test (tc_chain, test_reference_level);
+
+  tcase_add_test (tc_chain, test_all_formats);
+
+  tcase_add_test (tc_chain, test_gain_float_mono_8000);
+  tcase_add_test (tc_chain, test_gain_float_mono_11025);
+  tcase_add_test (tc_chain, test_gain_float_mono_12000);
+  tcase_add_test (tc_chain, test_gain_float_mono_16000);
+  tcase_add_test (tc_chain, test_gain_float_mono_22050);
+  tcase_add_test (tc_chain, test_gain_float_mono_24000);
+  tcase_add_test (tc_chain, test_gain_float_mono_32000);
+  tcase_add_test (tc_chain, test_gain_float_mono_44100);
+  tcase_add_test (tc_chain, test_gain_float_mono_48000);
+
+  tcase_add_test (tc_chain, test_gain_float_stereo_8000);
+  tcase_add_test (tc_chain, test_gain_float_stereo_11025);
+  tcase_add_test (tc_chain, test_gain_float_stereo_12000);
+  tcase_add_test (tc_chain, test_gain_float_stereo_16000);
+  tcase_add_test (tc_chain, test_gain_float_stereo_22050);
+  tcase_add_test (tc_chain, test_gain_float_stereo_24000);
+  tcase_add_test (tc_chain, test_gain_float_stereo_32000);
+  tcase_add_test (tc_chain, test_gain_float_stereo_44100);
+  tcase_add_test (tc_chain, test_gain_float_stereo_48000);
+
+  tcase_add_test (tc_chain, test_gain_int16_16_mono_8000);
+  tcase_add_test (tc_chain, test_gain_int16_16_mono_11025);
+  tcase_add_test (tc_chain, test_gain_int16_16_mono_12000);
+  tcase_add_test (tc_chain, test_gain_int16_16_mono_16000);
+  tcase_add_test (tc_chain, test_gain_int16_16_mono_22050);
+  tcase_add_test (tc_chain, test_gain_int16_16_mono_24000);
+  tcase_add_test (tc_chain, test_gain_int16_16_mono_32000);
+  tcase_add_test (tc_chain, test_gain_int16_16_mono_44100);
+  tcase_add_test (tc_chain, test_gain_int16_16_mono_48000);
+
+  tcase_add_test (tc_chain, test_gain_int16_16_stereo_8000);
+  tcase_add_test (tc_chain, test_gain_int16_16_stereo_11025);
+  tcase_add_test (tc_chain, test_gain_int16_16_stereo_12000);
+  tcase_add_test (tc_chain, test_gain_int16_16_stereo_16000);
+  tcase_add_test (tc_chain, test_gain_int16_16_stereo_22050);
+  tcase_add_test (tc_chain, test_gain_int16_16_stereo_24000);
+  tcase_add_test (tc_chain, test_gain_int16_16_stereo_32000);
+  tcase_add_test (tc_chain, test_gain_int16_16_stereo_44100);
+  tcase_add_test (tc_chain, test_gain_int16_16_stereo_48000);
+
+  return s;
+}
+
+GST_CHECK_MAIN (rganalysis);
diff --git a/tests/check/elements/rglimiter.c b/tests/check/elements/rglimiter.c
new file mode 100644
index 0000000..22ce227
--- /dev/null
+++ b/tests/check/elements/rglimiter.c
@@ -0,0 +1,275 @@
+/* GStreamer ReplayGain limiter
+ *
+ * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
+ *
+ * rglimiter.c: Unit test for the rglimiter element
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/audio/audio.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+static GstPad *mysrcpad, *mysinkpad;
+
+#define RG_LIMITER_CAPS_TEMPLATE_STRING       \
+  "audio/x-raw, "                             \
+  "format = (string) "GST_AUDIO_NE (F32) ", " \
+  "layout = (string) interleaved, "           \
+  "channels = (int) [ 1, MAX ], "             \
+  "rate = (int) [ 1, MAX ]"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (RG_LIMITER_CAPS_TEMPLATE_STRING)
+    );
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (RG_LIMITER_CAPS_TEMPLATE_STRING)
+    );
+
+static GstElement *
+setup_rglimiter (void)
+{
+  GstElement *element;
+
+  GST_DEBUG ("setup_rglimiter");
+  element = gst_check_setup_element ("rglimiter");
+  mysrcpad = gst_check_setup_src_pad (element, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (element, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return element;
+}
+
+static void
+cleanup_rglimiter (GstElement * element)
+{
+  GST_DEBUG ("cleanup_rglimiter");
+
+  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_check_teardown_src_pad (element);
+  gst_check_teardown_sink_pad (element);
+  gst_check_teardown_element (element);
+}
+
+static void
+set_playing_state (GstElement * element)
+{
+  fail_unless (gst_element_set_state (element,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "Could not set state to PLAYING");
+}
+
+static const gfloat test_input[] = {
+  -2.0, -1.0, -0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75, 1.0, 2.0
+};
+
+static const gfloat test_output[] = {
+  -0.99752737684336523,         /* -2.0  */
+  -0.88079707797788243,         /* -1.0  */
+  -0.7310585786300049,          /* -0.75 */
+  -0.5, -0.25, 0.0, 0.25, 0.5,
+  0.7310585786300049,           /* 0.75 */
+  0.88079707797788243,          /* 1.0  */
+  0.99752737684336523,          /* 2.0  */
+};
+
+static void
+setup_events (GstElement * element)
+{
+  GstCaps *caps;
+
+  caps = gst_caps_new_simple ("audio/x-raw",
+      "rate", G_TYPE_INT, 44100, "channels", G_TYPE_INT, 1,
+      "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
+      "layout", G_TYPE_STRING, "interleaved", NULL);
+
+  gst_check_setup_events (mysrcpad, element, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+}
+
+static GstBuffer *
+create_test_buffer (void)
+{
+  GstBuffer *buf = gst_buffer_new_and_alloc (sizeof (test_input));
+
+  gst_buffer_fill (buf, 0, test_input, sizeof (test_input));
+
+  ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
+
+  return buf;
+}
+
+static void
+verify_test_buffer (GstBuffer * buf)
+{
+  GstMapInfo map;
+  gfloat *output;
+  gint i;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  output = (gfloat *) map.data;
+  fail_unless (map.size == sizeof (test_output));
+
+  for (i = 0; i < G_N_ELEMENTS (test_input); i++)
+    fail_unless (ABS (output[i] - test_output[i]) < 1.e-6,
+        "Incorrect output value %.6f for input %.2f, expected %.6f",
+        output[i], test_input[i], test_output[i]);
+
+  gst_buffer_unmap (buf, &map);
+}
+
+/* Start of tests. */
+
+GST_START_TEST (test_no_buffer)
+{
+  GstElement *element = setup_rglimiter ();
+
+  set_playing_state (element);
+
+  cleanup_rglimiter (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_disabled)
+{
+  GstElement *element = setup_rglimiter ();
+  GstBuffer *buf, *out_buf;
+
+  g_object_set (element, "enabled", FALSE, NULL);
+  set_playing_state (element);
+  setup_events (element);
+
+  buf = create_test_buffer ();
+  fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
+  fail_unless (g_list_length (buffers) == 1);
+  out_buf = buffers->data;
+  fail_if (out_buf == NULL);
+  buffers = g_list_remove (buffers, out_buf);
+  ASSERT_BUFFER_REFCOUNT (out_buf, "out_buf", 1);
+  fail_unless (buf == out_buf);
+  gst_buffer_unref (out_buf);
+
+  cleanup_rglimiter (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_limiting)
+{
+  GstElement *element = setup_rglimiter ();
+  GstBuffer *buf, *out_buf;
+
+  set_playing_state (element);
+  setup_events (element);
+
+  /* Mutable variant. */
+  buf = create_test_buffer ();
+  GST_DEBUG ("push mutable buffer");
+  fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
+  fail_unless (g_list_length (buffers) == 1);
+  out_buf = buffers->data;
+  fail_if (out_buf == NULL);
+  ASSERT_BUFFER_REFCOUNT (out_buf, "out_buf", 1);
+  verify_test_buffer (out_buf);
+
+  /* Immutable variant. */
+  buf = create_test_buffer ();
+  /* Extra ref: */
+  gst_buffer_ref (buf);
+  ASSERT_BUFFER_REFCOUNT (buf, "buf", 2);
+  GST_DEBUG ("push immutable buffer");
+  fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
+  ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
+  fail_unless (g_list_length (buffers) == 2);
+  out_buf = g_list_last (buffers)->data;
+  fail_if (out_buf == NULL);
+  ASSERT_BUFFER_REFCOUNT (out_buf, "out_buf", 1);
+  fail_unless (buf != out_buf);
+  /* Drop our extra ref: */
+  gst_buffer_unref (buf);
+  verify_test_buffer (out_buf);
+
+  cleanup_rglimiter (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_gap)
+{
+  GstElement *element = setup_rglimiter ();
+  GstBuffer *buf, *out_buf;
+  GstMapInfo m1, m2;
+
+  set_playing_state (element);
+  setup_events (element);
+
+  buf = create_test_buffer ();
+  GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_GAP);
+  fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
+  fail_unless (g_list_length (buffers) == 1);
+  out_buf = buffers->data;
+  fail_if (out_buf == NULL);
+  ASSERT_BUFFER_REFCOUNT (out_buf, "out_buf", 1);
+
+  /* Verify that the baseclass does not lift the GAP flag: */
+  fail_unless (GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_GAP));
+
+  gst_buffer_map (out_buf, &m1, GST_MAP_READ);
+  gst_buffer_map (buf, &m2, GST_MAP_READ);
+
+  g_assert (m1.size == m2.size);
+  /* We cheated by passing an input buffer with non-silence that has the GAP
+   * flag set.  The element cannot know that however and must have skipped
+   * adjusting the buffer because of the flag, which we can easily verify: */
+  fail_if (memcmp (m1.data, m2.data, m1.size) != 0);
+
+  gst_buffer_unmap (out_buf, &m1);
+  gst_buffer_unmap (buf, &m2);
+
+  cleanup_rglimiter (element);
+}
+
+GST_END_TEST;
+
+static Suite *
+rglimiter_suite (void)
+{
+  Suite *s = suite_create ("rglimiter");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_no_buffer);
+  tcase_add_test (tc_chain, test_disabled);
+  tcase_add_test (tc_chain, test_limiting);
+  tcase_add_test (tc_chain, test_gap);
+
+  return s;
+}
+
+GST_CHECK_MAIN (rglimiter);
diff --git a/tests/check/elements/rgvolume.c b/tests/check/elements/rgvolume.c
new file mode 100644
index 0000000..c8ae8bc
--- /dev/null
+++ b/tests/check/elements/rgvolume.c
@@ -0,0 +1,678 @@
+/* GStreamer ReplayGain volume adjustment
+ *
+ * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
+ *
+ * rgvolume.c: Unit test for the rgvolume element
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/audio/audio.h>
+
+#include <math.h>
+
+static GList *events = NULL;
+
+/* For ease of programming we use globals to keep refs for our floating src and
+ * sink pads we create; otherwise we always have to do get_pad, get_peer, and
+ * then remove references in every test function */
+static GstPad *mysrcpad, *mysinkpad;
+
+#define RG_VOLUME_CAPS_TEMPLATE_STRING        \
+  "audio/x-raw, "                             \
+  "format = (string) "GST_AUDIO_NE (F32) ", " \
+  "layout = (string) interleaved, "           \
+  "channels = (int) [ 1, MAX ], "             \
+  "rate = (int) [ 1, MAX ]"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (RG_VOLUME_CAPS_TEMPLATE_STRING)
+    );
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (RG_VOLUME_CAPS_TEMPLATE_STRING)
+    );
+
+static GstBuffer *test_buffer_new (gfloat value);
+
+/* gstcheck sets up a chain function that appends buffers to a global list.
+ * This is our equivalent of that for event handling. */
+static gboolean
+event_func (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GST_DEBUG ("received event %p (%s)", event, GST_EVENT_TYPE_NAME (event));
+  events = g_list_append (events, event);
+
+  return TRUE;
+}
+
+static GstElement *
+setup_rgvolume (void)
+{
+  GstElement *element;
+
+  GST_DEBUG ("setup_rgvolume");
+  element = gst_check_setup_element ("rgvolume");
+  mysrcpad = gst_check_setup_src_pad (element, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (element, &sinktemplate);
+
+  /* Capture events, to test tag filtering behavior: */
+  gst_pad_set_event_function (mysinkpad, event_func);
+
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return element;
+}
+
+static void
+send_empty_buffer (void)
+{
+  GstBuffer *buf;
+
+  buf = test_buffer_new (0.0);
+  gst_buffer_resize (buf, 0, 0);
+  GST_BUFFER_DURATION (buf) = 0;
+  GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET (buf);
+  fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
+
+  fail_unless (g_list_length (buffers) == 1);
+  fail_unless (buffers->data == buf);
+  gst_mini_object_unref ((GstMiniObject *) buffers->data);
+  buffers = g_list_remove (buffers, buf);
+}
+
+static void
+cleanup_rgvolume (GstElement * element)
+{
+  GST_DEBUG ("cleanup_rgvolume");
+
+  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  g_list_foreach (events, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (events);
+  events = NULL;
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (element);
+  gst_check_teardown_sink_pad (element);
+  gst_check_teardown_element (element);
+}
+
+static void
+set_playing_state (GstElement * element)
+{
+  fail_unless (gst_element_set_state (element,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "Could not set state to PLAYING");
+}
+
+static void
+set_null_state (GstElement * element)
+{
+  fail_unless (gst_element_set_state (element,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS,
+      "Could not set state to NULL");
+}
+
+static void
+send_flush_events (GstElement * element)
+{
+  gboolean res;
+
+  res = gst_pad_push_event (mysrcpad, gst_event_new_flush_start ());
+  fail_unless (res, "flush-start even not handled");
+
+  res = gst_pad_push_event (mysrcpad, gst_event_new_flush_stop (TRUE));
+  fail_unless (res, "flush-stop event not handled");
+}
+
+static void
+send_stream_start_event (GstElement * element)
+{
+  gboolean res;
+
+  res = gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test"));
+  fail_unless (res, "STREAM_START event not handled");
+}
+
+static void
+send_caps_event (GstElement * element)
+{
+  GstCaps *caps;
+  gboolean res;
+
+  caps = gst_caps_from_string ("audio/x-raw, format = " GST_AUDIO_NE (F32) ", "
+      "layout = interleaved, rate = 8000, channels = 1");
+  res = gst_pad_push_event (mysrcpad, gst_event_new_caps (caps));
+  fail_unless (res, "CAPS event not handled");
+  gst_caps_unref (caps);
+}
+
+static void
+send_segment_event (GstElement * element)
+{
+  GstSegment segment;
+  gboolean res;
+
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  res = gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment));
+  fail_unless (res, "SEGMENT event not handled");
+}
+
+static void
+send_eos_event (GstElement * element)
+{
+  GstEvent *event = gst_event_new_eos ();
+
+  fail_unless (gst_pad_push_event (mysrcpad, event),
+      "Pushing EOS event failed");
+}
+
+static GstEvent *
+send_tag_event (GstElement * element, GstEvent * event)
+{
+  GList *l;
+  GstTagList *tag_list;
+  gdouble dummy;
+
+  g_return_val_if_fail (event->type == GST_EVENT_TAG, NULL);
+
+  fail_unless (gst_pad_push_event (mysrcpad, event),
+      "Pushing tag event failed");
+
+  event = NULL;
+
+  for (l = g_list_last (events); l; l = l->prev) {
+    if (GST_EVENT_TYPE (l->data) == GST_EVENT_TAG) {
+      event = l->data;
+      events = g_list_delete_link (events, l);
+      break;
+    }
+  }
+
+  /* Event got filtered out */
+  if (event == NULL)
+    return NULL;
+
+  fail_unless (event->type == GST_EVENT_TAG);
+  gst_event_parse_tag (event, &tag_list);
+
+  /* The element is supposed to filter out ReplayGain related tags. */
+  fail_if (gst_tag_list_get_double (tag_list, GST_TAG_TRACK_GAIN, &dummy),
+      "tag event still contains track gain tag");
+  fail_if (gst_tag_list_get_double (tag_list, GST_TAG_TRACK_PEAK, &dummy),
+      "tag event still contains track peak tag");
+  fail_if (gst_tag_list_get_double (tag_list, GST_TAG_ALBUM_GAIN, &dummy),
+      "tag event still contains album gain tag");
+  fail_if (gst_tag_list_get_double (tag_list, GST_TAG_ALBUM_PEAK, &dummy),
+      "tag event still contains album peak tag");
+
+  return event;
+}
+
+static GstBuffer *
+test_buffer_new (gfloat value)
+{
+  GstBuffer *buf;
+  GstMapInfo map;
+  gfloat *data;
+  gint i;
+
+  buf = gst_buffer_new_and_alloc (8 * sizeof (gfloat));
+  gst_buffer_map (buf, &map, GST_MAP_WRITE);
+  data = (gfloat *) map.data;
+  for (i = 0; i < 8; i++)
+    data[i] = value;
+  gst_buffer_unmap (buf, &map);
+
+
+  ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
+
+  return buf;
+}
+
+#define MATCH_GAIN(g1, g2) ((g1 < g2 + 1e-6) && (g2 < g1 + 1e-6))
+
+static void
+fail_unless_target_gain (GstElement * element, gdouble expected_gain)
+{
+  gdouble prop_gain;
+
+  g_object_get (element, "target-gain", &prop_gain, NULL);
+
+  fail_unless (MATCH_GAIN (prop_gain, expected_gain),
+      "Target gain is %.2f dB, expected %.2f dB", prop_gain, expected_gain);
+}
+
+static void
+fail_unless_result_gain (GstElement * element, gdouble expected_gain)
+{
+  GstBuffer *input_buf, *output_buf;
+  gfloat *data;
+  gfloat input_sample, output_sample;
+  gdouble gain, prop_gain;
+  gboolean is_passthrough, expect_passthrough;
+  gint i;
+  GstMapInfo map;
+
+  fail_unless (g_list_length (buffers) == 0);
+
+  input_sample = 1.0;
+  input_buf = test_buffer_new (input_sample);
+
+  /* We keep an extra reference to detect passthrough mode. */
+  gst_buffer_ref (input_buf);
+  /* Pushing steals a reference. */
+  fail_unless (gst_pad_push (mysrcpad, input_buf) == GST_FLOW_OK);
+  gst_buffer_unref (input_buf);
+
+  /* The output buffer ends up on the global buffer list. */
+  fail_unless (g_list_length (buffers) == 1);
+  output_buf = buffers->data;
+  fail_if (output_buf == NULL);
+
+  buffers = g_list_remove (buffers, output_buf);
+  ASSERT_BUFFER_REFCOUNT (output_buf, "output_buf", 1);
+
+  fail_unless_equals_int (gst_buffer_get_size (output_buf),
+      8 * sizeof (gfloat));
+
+  gst_buffer_map (output_buf, &map, GST_MAP_READ);
+  data = (gfloat *) map.data;
+
+  output_sample = *data;
+  fail_if (output_sample == 0.0, "First output sample is zero");
+  for (i = 1; i < 8; i++) {
+    fail_unless (output_sample == data[i], "Output samples not uniform");
+  };
+  gst_buffer_unmap (output_buf, &map);
+
+  gain = 20. * log10 (output_sample / input_sample);
+  fail_unless (MATCH_GAIN (gain, expected_gain),
+      "Applied gain is %.2f dB, expected %.2f dB", gain, expected_gain);
+  g_object_get (element, "result-gain", &prop_gain, NULL);
+  fail_unless (MATCH_GAIN (prop_gain, expected_gain),
+      "Result gain is %.2f dB, expected %.2f dB", prop_gain, expected_gain);
+
+  is_passthrough = (output_buf == input_buf);
+  expect_passthrough = MATCH_GAIN (expected_gain, +0.00);
+  fail_unless (is_passthrough == expect_passthrough,
+      expect_passthrough
+      ? "Expected operation in passthrough mode"
+      : "Incorrect passthrough behaviour");
+
+  gst_buffer_unref (output_buf);
+}
+
+static void
+fail_unless_gain (GstElement * element, gdouble expected_gain)
+{
+  fail_unless_target_gain (element, expected_gain);
+  fail_unless_result_gain (element, expected_gain);
+}
+
+/* Start of tests. */
+
+GST_START_TEST (test_no_buffer)
+{
+  GstElement *element = setup_rgvolume ();
+
+  set_playing_state (element);
+  set_null_state (element);
+  set_playing_state (element);
+  send_eos_event (element);
+
+  cleanup_rgvolume (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_events)
+{
+  GstElement *element = setup_rgvolume ();
+  GstEvent *event;
+  GstEvent *new_event;
+  GstTagList *tag_list;
+  gchar *artist;
+
+  set_playing_state (element);
+  send_stream_start_event (element);
+  send_caps_event (element);
+  send_segment_event (element);
+
+  send_empty_buffer ();
+
+  tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
+      GST_TAG_TRACK_GAIN, +4.95, GST_TAG_TRACK_PEAK, 0.59463,
+      GST_TAG_ALBUM_GAIN, -1.54, GST_TAG_ALBUM_PEAK, 0.693415,
+      GST_TAG_ARTIST, "Foobar", NULL);
+  event = gst_event_new_tag (tag_list);
+  new_event = send_tag_event (element, event);
+  gst_event_parse_tag (new_event, &tag_list);
+  fail_unless (gst_tag_list_get_string (tag_list, GST_TAG_ARTIST, &artist));
+  fail_unless (g_str_equal (artist, "Foobar"));
+  g_free (artist);
+  gst_event_unref (new_event);
+
+  /* Same as above, but with a non-writable event. */
+
+  tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
+      GST_TAG_TRACK_GAIN, +4.95, GST_TAG_TRACK_PEAK, 0.59463,
+      GST_TAG_ALBUM_GAIN, -1.54, GST_TAG_ALBUM_PEAK, 0.693415,
+      GST_TAG_ARTIST, "Foobar", NULL);
+  gst_tag_list_ref (tag_list);
+  event = gst_event_new_tag (tag_list);
+  new_event = send_tag_event (element, event);
+
+  /* Make sure our tags weren't modified in place while we still got a ref */
+  fail_unless_equals_int (5, gst_tag_list_n_tags (tag_list));
+  gst_tag_list_unref (tag_list);
+
+  gst_event_parse_tag (new_event, &tag_list);
+  fail_unless (gst_tag_list_get_string (tag_list, GST_TAG_ARTIST, &artist));
+  fail_unless (g_str_equal (artist, "Foobar"));
+  g_free (artist);
+  gst_event_unref (new_event);
+
+  cleanup_rgvolume (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_simple)
+{
+  GstElement *element = setup_rgvolume ();
+  GstTagList *tag_list;
+
+  g_object_set (element, "album-mode", FALSE, "headroom", +0.00,
+      "pre-amp", -6.00, "fallback-gain", +1.23, NULL);
+  set_playing_state (element);
+  send_stream_start_event (element);
+  send_caps_event (element);
+  send_segment_event (element);
+
+  send_empty_buffer ();
+
+  tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
+      GST_TAG_TRACK_GAIN, -3.45, GST_TAG_TRACK_PEAK, 1.0,
+      GST_TAG_ALBUM_GAIN, +2.09, GST_TAG_ALBUM_PEAK, 1.0, NULL);
+  fail_unless (send_tag_event (element, gst_event_new_tag (tag_list)) == NULL);
+  fail_unless_gain (element, -9.45);    /* pre-amp + track gain */
+  send_eos_event (element);
+
+  g_object_set (element, "album-mode", TRUE, NULL);
+
+  send_flush_events (element);
+  send_segment_event (element);
+
+  tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
+      GST_TAG_TRACK_GAIN, -3.45, GST_TAG_TRACK_PEAK, 1.0,
+      GST_TAG_ALBUM_GAIN, +2.09, GST_TAG_ALBUM_PEAK, 1.0, NULL);
+  fail_unless (send_tag_event (element, gst_event_new_tag (tag_list)) == NULL);
+  fail_unless_gain (element, -3.91);    /* pre-amp + album gain */
+
+  /* Switching back to track mode in the middle of a stream: */
+  g_object_set (element, "album-mode", FALSE, NULL);
+  fail_unless_gain (element, -9.45);    /* pre-amp + track gain */
+  send_eos_event (element);
+
+  cleanup_rgvolume (element);
+}
+
+GST_END_TEST;
+
+/* If there are no gain tags at all, the fallback gain is used. */
+
+GST_START_TEST (test_fallback_gain)
+{
+  GstElement *element = setup_rgvolume ();
+  GstTagList *tag_list;
+
+  /* First some track where fallback does _not_ apply. */
+
+  g_object_set (element, "album-mode", FALSE, "headroom", 10.00,
+      "pre-amp", -6.00, "fallback-gain", -3.00, NULL);
+  set_playing_state (element);
+  send_stream_start_event (element);
+  send_caps_event (element);
+  send_segment_event (element);
+
+  send_empty_buffer ();
+
+  tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
+      GST_TAG_TRACK_GAIN, +3.5, GST_TAG_TRACK_PEAK, 1.0,
+      GST_TAG_ALBUM_GAIN, -0.5, GST_TAG_ALBUM_PEAK, 1.0, NULL);
+  fail_unless (send_tag_event (element, gst_event_new_tag (tag_list)) == NULL);
+  fail_unless_gain (element, -2.50);    /* pre-amp + track gain */
+  send_eos_event (element);
+
+  /* Now a track completely missing tags. */
+  send_flush_events (element);
+  send_segment_event (element);
+
+  fail_unless_gain (element, -9.00);    /* pre-amp + fallback-gain */
+
+  /* Changing the fallback gain in the middle of a stream, going to pass-through
+   * mode: */
+  g_object_set (element, "fallback-gain", +6.00, NULL);
+  fail_unless_gain (element, +0.00);    /* pre-amp + fallback-gain */
+  send_eos_event (element);
+
+  /* Verify that result gain is set to +0.00 with pre-amp + fallback-gain >
+   * +0.00 and no headroom. */
+  send_flush_events (element);
+  send_segment_event (element);
+
+  g_object_set (element, "fallback-gain", +12.00, "headroom", +0.00, NULL);
+  fail_unless_target_gain (element, +6.00);     /* pre-amp + fallback-gain */
+  fail_unless_result_gain (element, +0.00);
+  send_eos_event (element);
+
+  cleanup_rgvolume (element);
+}
+
+GST_END_TEST;
+
+/* If album gain is to be preferred but not available, the track gain is to be
+ * taken instead. */
+
+GST_START_TEST (test_fallback_track)
+{
+  GstElement *element = setup_rgvolume ();
+  GstTagList *tag_list;
+
+  g_object_set (element, "album-mode", TRUE, "headroom", +0.00,
+      "pre-amp", -6.00, "fallback-gain", +1.23, NULL);
+  set_playing_state (element);
+  send_stream_start_event (element);
+  send_caps_event (element);
+  send_segment_event (element);
+
+  send_empty_buffer ();
+
+  tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
+      GST_TAG_TRACK_GAIN, +2.11, GST_TAG_TRACK_PEAK, 1.0, NULL);
+  fail_unless (send_tag_event (element, gst_event_new_tag (tag_list)) == NULL);
+  fail_unless_gain (element, -3.89);    /* pre-amp + track gain */
+
+  send_eos_event (element);
+
+  cleanup_rgvolume (element);
+}
+
+GST_END_TEST;
+
+/* If track gain is to be preferred but not available, the album gain is to be
+ * taken instead. */
+
+GST_START_TEST (test_fallback_album)
+{
+  GstElement *element = setup_rgvolume ();
+  GstTagList *tag_list;
+
+  g_object_set (element, "album-mode", FALSE, "headroom", +0.00,
+      "pre-amp", -6.00, "fallback-gain", +1.23, NULL);
+  set_playing_state (element);
+  send_stream_start_event (element);
+  send_caps_event (element);
+  send_segment_event (element);
+
+  send_empty_buffer ();
+
+  tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
+      GST_TAG_ALBUM_GAIN, +3.73, GST_TAG_ALBUM_PEAK, 1.0, NULL);
+  fail_unless (send_tag_event (element, gst_event_new_tag (tag_list)) == NULL);
+  fail_unless_gain (element, -2.27);    /* pre-amp + album gain */
+
+  send_eos_event (element);
+
+  cleanup_rgvolume (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_headroom)
+{
+  GstElement *element = setup_rgvolume ();
+  GstTagList *tag_list;
+
+  g_object_set (element, "album-mode", FALSE, "headroom", +0.00,
+      "pre-amp", +0.00, "fallback-gain", +1.23, NULL);
+  set_playing_state (element);
+  send_stream_start_event (element);
+  send_caps_event (element);
+  send_segment_event (element);
+
+  send_empty_buffer ();
+
+  tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
+      GST_TAG_TRACK_GAIN, +3.50, GST_TAG_TRACK_PEAK, 1.0, NULL);
+  fail_unless (send_tag_event (element, gst_event_new_tag (tag_list)) == NULL);
+  fail_unless_target_gain (element, +3.50);     /* pre-amp + track gain */
+  fail_unless_result_gain (element, +0.00);
+  send_eos_event (element);
+
+  send_flush_events (element);
+  send_segment_event (element);
+
+  g_object_set (element, "headroom", +2.00, NULL);
+  tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
+      GST_TAG_TRACK_GAIN, +9.18, GST_TAG_TRACK_PEAK, 0.687149, NULL);
+  fail_unless (send_tag_event (element, gst_event_new_tag (tag_list)) == NULL);
+  fail_unless_target_gain (element, +9.18);     /* pre-amp + track gain */
+  /* Result is 20. * log10 (1. / peak) + headroom. */
+  fail_unless_result_gain (element, 5.2589816238303335);
+  send_eos_event (element);
+
+  send_flush_events (element);
+  send_segment_event (element);
+
+  g_object_set (element, "album-mode", TRUE, NULL);
+  tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
+      GST_TAG_ALBUM_GAIN, +5.50, GST_TAG_ALBUM_PEAK, 1.0, NULL);
+  fail_unless (send_tag_event (element, gst_event_new_tag (tag_list)) == NULL);
+  fail_unless_target_gain (element, +5.50);     /* pre-amp + album gain */
+  fail_unless_result_gain (element, +2.00);     /* headroom */
+  send_eos_event (element);
+
+  cleanup_rgvolume (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_reference_level)
+{
+  GstElement *element = setup_rgvolume ();
+  GstTagList *tag_list;
+
+  g_object_set (element,
+      "album-mode", FALSE,
+      "headroom", +0.00, "pre-amp", +0.00, "fallback-gain", +1.23, NULL);
+  set_playing_state (element);
+
+  send_stream_start_event (element);
+  send_caps_event (element);
+  send_segment_event (element);
+
+  send_empty_buffer ();
+
+  tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
+      GST_TAG_TRACK_GAIN, 0.00, GST_TAG_TRACK_PEAK, 0.2,
+      GST_TAG_REFERENCE_LEVEL, 83., NULL);
+  fail_unless (send_tag_event (element, gst_event_new_tag (tag_list)) == NULL);
+  /* Because our authorative reference is 89 dB, we bump it up by +6 dB. */
+  fail_unless_gain (element, +6.00);    /* pre-amp + track gain */
+  send_eos_event (element);
+
+  g_object_set (element, "album-mode", TRUE, NULL);
+
+  /* Same as above, but with album gain. */
+  send_flush_events (element);
+  send_segment_event (element);
+
+  tag_list = gst_tag_list_new_empty ();
+  gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
+      GST_TAG_TRACK_GAIN, 1.23, GST_TAG_TRACK_PEAK, 0.1,
+      GST_TAG_ALBUM_GAIN, 0.00, GST_TAG_ALBUM_PEAK, 0.2,
+      GST_TAG_REFERENCE_LEVEL, 83., NULL);
+  fail_unless (send_tag_event (element, gst_event_new_tag (tag_list)) == NULL);
+  fail_unless_gain (element, +6.00);    /* pre-amp + album gain */
+
+  cleanup_rgvolume (element);
+}
+
+GST_END_TEST;
+
+static Suite *
+rgvolume_suite (void)
+{
+  Suite *s = suite_create ("rgvolume");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_no_buffer);
+  tcase_add_test (tc_chain, test_events);
+  tcase_add_test (tc_chain, test_simple);
+  tcase_add_test (tc_chain, test_fallback_gain);
+  tcase_add_test (tc_chain, test_fallback_track);
+  tcase_add_test (tc_chain, test_fallback_album);
+  tcase_add_test (tc_chain, test_headroom);
+  tcase_add_test (tc_chain, test_reference_level);
+
+  return s;
+}
+
+GST_CHECK_MAIN (rgvolume);
diff --git a/tests/check/elements/rtp-payloading.c b/tests/check/elements/rtp-payloading.c
new file mode 100644
index 0000000..e952207
--- /dev/null
+++ b/tests/check/elements/rtp-payloading.c
@@ -0,0 +1,1682 @@
+/* GStreamer RTP payloader unit tests
+ * Copyright (C) 2008 Nokia Corporation and its subsidary(-ies)
+ *               contact: <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <gst/check/gstcheck.h>
+#include <gst/check/gstharness.h>
+#include <gst/audio/audio.h>
+#include <gst/base/base.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define RELEASE_ELEMENT(x) if(x) {gst_object_unref(x); x = NULL;}
+
+#define LOOP_COUNT 1
+
+/*
+ * RTP pipeline structure to store the required elements.
+ */
+typedef struct
+{
+  GstElement *pipeline;
+  GstElement *appsrc;
+  GstElement *rtppay;
+  GstElement *rtpdepay;
+  GstElement *fakesink;
+  const guint8 *frame_data;
+  int frame_data_size;
+  int frame_count;
+  GstEvent *custom_event;
+} rtp_pipeline;
+
+/*
+ * Number of bytes received in the chain list function when using buffer lists
+ */
+static guint chain_list_bytes_received;
+
+/*
+ * Chain list function for testing buffer lists
+ */
+static GstFlowReturn
+rtp_pipeline_chain_list (GstPad * pad, GstObject * parent, GstBufferList * list)
+{
+  guint i, len;
+
+  fail_if (!list);
+  /*
+   * Count the size of the payload in the buffer list.
+   */
+  len = gst_buffer_list_length (list);
+  GST_LOG ("list length %u", len);
+
+  /* Loop through all groups */
+  for (i = 0; i < len; i++) {
+    GstBuffer *paybuf;
+    GstMemory *mem;
+    gint size;
+
+    paybuf = gst_buffer_list_get (list, i);
+    /* only count real data which is expected in last memory block */
+    GST_LOG ("n_memory %d", gst_buffer_n_memory (paybuf));
+    fail_unless (gst_buffer_n_memory (paybuf) > 1);
+    mem = gst_buffer_get_memory_range (paybuf, gst_buffer_n_memory (paybuf) - 1,
+        1);
+    size = gst_memory_get_sizes (mem, NULL, NULL);
+    gst_memory_unref (mem);
+    chain_list_bytes_received += size;
+    GST_LOG ("size %d, total %u", size, chain_list_bytes_received);
+  }
+  gst_buffer_list_unref (list);
+
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+rtp_pipeline_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+  GstBufferList *list;
+
+  list = gst_buffer_list_new_sized (1);
+  gst_buffer_list_add (list, buf);
+  return rtp_pipeline_chain_list (pad, parent, list);
+}
+
+/*
+ * RTP bus callback.
+ */
+static gboolean
+rtp_bus_callback (GstBus * bus, GstMessage * message, gpointer data)
+{
+  GMainLoop *mainloop = (GMainLoop *) data;
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_ERROR:
+    {
+      GError *err;
+
+      gchar *debug;
+
+      gchar *element_name;
+
+      element_name = (message->src) ? gst_object_get_name (message->src) : NULL;
+      gst_message_parse_error (message, &err, &debug);
+      g_print ("\nError from element %s: %s\n%s\n\n",
+          GST_STR_NULL (element_name), err->message, (debug) ? debug : "");
+      g_error_free (err);
+      g_free (debug);
+      g_free (element_name);
+
+      fail_if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR);
+
+      g_main_loop_quit (mainloop);
+    }
+      break;
+
+    case GST_MESSAGE_EOS:
+    {
+      g_main_loop_quit (mainloop);
+    }
+      break;
+      break;
+
+    default:
+    {
+    }
+      break;
+  }
+
+  return TRUE;
+}
+
+/*
+ * Creates a RTP pipeline for one test.
+ * @param frame_data Pointer to the frame data which is used to pass thru pay/depayloaders.
+ * @param frame_data_size Frame data size in bytes.
+ * @param frame_count Frame count.
+ * @param filtercaps Caps filters.
+ * @param pay Payloader name.
+ * @param depay Depayloader name.
+ * @return
+ * Returns pointer to the RTP pipeline.
+ * The user must free the RTP pipeline when it's not used anymore.
+ */
+static rtp_pipeline *
+rtp_pipeline_create (const guint8 * frame_data, int frame_data_size,
+    int frame_count, const char *filtercaps, const char *pay, const char *depay)
+{
+  gchar *pipeline_name;
+  rtp_pipeline *p;
+  GstCaps *caps;
+
+  /* Check parameters. */
+  if (!frame_data || !pay || !depay) {
+    return NULL;
+  }
+
+  /* Allocate memory for the RTP pipeline. */
+  p = (rtp_pipeline *) malloc (sizeof (rtp_pipeline));
+
+  p->frame_data = frame_data;
+  p->frame_data_size = frame_data_size;
+  p->frame_count = frame_count;
+  p->custom_event = NULL;
+
+  /* Create elements. */
+  pipeline_name = g_strdup_printf ("%s-%s-pipeline", pay, depay);
+  p->pipeline = gst_pipeline_new (pipeline_name);
+  g_free (pipeline_name);
+  p->appsrc = gst_element_factory_make ("appsrc", NULL);
+  p->rtppay = gst_element_factory_make (pay, NULL);
+  p->rtpdepay = gst_element_factory_make (depay, NULL);
+  p->fakesink = gst_element_factory_make ("fakesink", NULL);
+
+  /* One or more elements are not created successfully or failed to create p? */
+  if (!p->pipeline || !p->appsrc || !p->rtppay || !p->rtpdepay || !p->fakesink) {
+    /* Release created elements. */
+    RELEASE_ELEMENT (p->pipeline);
+    RELEASE_ELEMENT (p->appsrc);
+    RELEASE_ELEMENT (p->rtppay);
+    RELEASE_ELEMENT (p->rtpdepay);
+    RELEASE_ELEMENT (p->fakesink);
+
+    /* Release allocated memory. */
+    free (p);
+
+    return NULL;
+  }
+
+  /* Set src properties. */
+  caps = gst_caps_from_string (filtercaps);
+  g_object_set (p->appsrc, "do-timestamp", TRUE, "caps", caps,
+      "format", GST_FORMAT_TIME, NULL);
+  gst_caps_unref (caps);
+
+  /* Add elements to the pipeline. */
+  gst_bin_add (GST_BIN (p->pipeline), p->appsrc);
+  gst_bin_add (GST_BIN (p->pipeline), p->rtppay);
+  gst_bin_add (GST_BIN (p->pipeline), p->rtpdepay);
+  gst_bin_add (GST_BIN (p->pipeline), p->fakesink);
+
+  /* Link elements. */
+  gst_element_link (p->appsrc, p->rtppay);
+  gst_element_link (p->rtppay, p->rtpdepay);
+  gst_element_link (p->rtpdepay, p->fakesink);
+
+  return p;
+}
+
+/*
+ * Destroys the RTP pipeline.
+ * @param p Pointer to the RTP pipeline.
+ */
+static void
+rtp_pipeline_destroy (rtp_pipeline * p)
+{
+  /* Check parameters. */
+  if (p == NULL) {
+    return;
+  }
+
+  /* Release pipeline. */
+  RELEASE_ELEMENT (p->pipeline);
+
+  /* Release allocated memory. */
+  free (p);
+}
+
+static GstPadProbeReturn
+pay_event_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
+{
+  rtp_pipeline *p = (rtp_pipeline *) user_data;
+  GstEvent *event = GST_PAD_PROBE_INFO_DATA (info);
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_DOWNSTREAM) {
+    const GstStructure *s0 = gst_event_get_structure (p->custom_event);
+    const GstStructure *s1 = gst_event_get_structure (event);
+    if (gst_structure_is_equal (s0, s1)) {
+      return GST_PAD_PROBE_DROP;
+    }
+  }
+
+  return GST_PAD_PROBE_OK;
+}
+
+static GstPadProbeReturn
+depay_event_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
+{
+  rtp_pipeline *p = (rtp_pipeline *) user_data;
+  GstEvent *event = GST_PAD_PROBE_INFO_DATA (info);
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_DOWNSTREAM) {
+    const GstStructure *s0 = gst_event_get_structure (p->custom_event);
+    const GstStructure *s1 = gst_event_get_structure (event);
+    if (gst_structure_is_equal (s0, s1)) {
+      gst_event_unref (p->custom_event);
+      p->custom_event = NULL;
+    }
+  }
+
+  return GST_PAD_PROBE_OK;
+}
+
+/*
+ * Runs the RTP pipeline.
+ * @param p Pointer to the RTP pipeline.
+ */
+static void
+rtp_pipeline_run (rtp_pipeline * p)
+{
+  GstFlowReturn flow_ret;
+  GMainLoop *mainloop = NULL;
+  GstBus *bus;
+  gint i, j;
+
+  /* Check parameters. */
+  if (p == NULL) {
+    return;
+  }
+
+  /* Create mainloop. */
+  mainloop = g_main_loop_new (NULL, FALSE);
+  if (!mainloop) {
+    return;
+  }
+
+  /* Add bus callback. */
+  bus = gst_pipeline_get_bus (GST_PIPELINE (p->pipeline));
+
+  gst_bus_add_watch (bus, rtp_bus_callback, (gpointer) mainloop);
+
+  /* Set pipeline to PLAYING. */
+  gst_element_set_state (p->pipeline, GST_STATE_PLAYING);
+
+  /* Push custom event into the pipeline */
+  if (p->custom_event) {
+    GstPad *srcpad;
+
+    /* Install a probe to drop the event after it being serialized */
+    srcpad = gst_element_get_static_pad (p->rtppay, "src");
+    gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
+        pay_event_probe_cb, p, NULL);
+    gst_object_unref (srcpad);
+
+    /* Install a probe to trace the deserialized event after depayloading */
+    srcpad = gst_element_get_static_pad (p->rtpdepay, "src");
+    gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
+        depay_event_probe_cb, p, NULL);
+    gst_object_unref (srcpad);
+    /* Send the event */
+    gst_element_send_event (p->appsrc, gst_event_ref (p->custom_event));
+  }
+
+  /* Push data into the pipeline */
+  for (i = 0; i < LOOP_COUNT; i++) {
+    const guint8 *data = p->frame_data;
+
+    for (j = 0; j < p->frame_count; j++) {
+      GstBuffer *buf;
+
+      buf =
+          gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+          (guint8 *) data, p->frame_data_size, 0, p->frame_data_size, NULL,
+          NULL);
+
+      g_signal_emit_by_name (p->appsrc, "push-buffer", buf, &flow_ret);
+      fail_unless_equals_int (flow_ret, GST_FLOW_OK);
+      data += p->frame_data_size;
+
+      gst_buffer_unref (buf);
+    }
+  }
+
+  g_signal_emit_by_name (p->appsrc, "end-of-stream", &flow_ret);
+
+  /* Run mainloop. */
+  g_main_loop_run (mainloop);
+
+  /* Set pipeline to NULL. */
+  gst_element_set_state (p->pipeline, GST_STATE_NULL);
+
+  /* Release mainloop. */
+  g_main_loop_unref (mainloop);
+
+  gst_bus_remove_watch (bus);
+  gst_object_unref (bus);
+
+  fail_if (p->custom_event);
+}
+
+/*
+ * Enables buffer lists and adds a chain_list_function to the depayloader.
+ * @param p Pointer to the RTP pipeline.
+ */
+static void
+rtp_pipeline_enable_lists (rtp_pipeline * p)
+{
+  GstPad *pad;
+
+  /* Add chain list function for the buffer list tests */
+  pad = gst_element_get_static_pad (p->rtpdepay, "sink");
+  gst_pad_set_chain_list_function (pad,
+      GST_DEBUG_FUNCPTR (rtp_pipeline_chain_list));
+  /* .. to satisfy this silly test code in case someone dares push a buffer */
+  gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (rtp_pipeline_chain));
+  gst_object_unref (pad);
+}
+
+/*
+ * Creates the RTP pipeline and runs the test using the pipeline.
+ * @param frame_data Pointer to the frame data which is used to pass thru pay/depayloaders.
+ * @param frame_data_size Frame data size in bytes.
+ * @param frame_count Frame count.
+ * @param filtercaps Caps filters.
+ * @param pay Payloader name.
+ * @param depay Depayloader name.
+ * @bytes_sent bytes that will be sent, used when testing buffer lists
+ * @mtu_size set mtu size when testing lists
+ * @use_lists enable buffer lists
+ */
+static void
+rtp_pipeline_test (const guint8 * frame_data, int frame_data_size,
+    int frame_count, const char *filtercaps, const char *pay, const char *depay,
+    guint bytes_sent, guint mtu_size, gboolean use_lists)
+{
+  /* Create RTP pipeline. */
+  rtp_pipeline *p =
+      rtp_pipeline_create (frame_data, frame_data_size, frame_count, filtercaps,
+      pay, depay);
+
+  if (p == NULL) {
+    return;
+  }
+
+  /* set mtu size if needed */
+  if (mtu_size > 0) {
+    g_object_set (p->rtppay, "mtu", mtu_size, NULL);
+  }
+
+  if (use_lists) {
+    rtp_pipeline_enable_lists (p);
+    chain_list_bytes_received = 0;
+  }
+
+  /* Run RTP pipeline. */
+  rtp_pipeline_run (p);
+
+  /* Destroy RTP pipeline. */
+  rtp_pipeline_destroy (p);
+
+  if (use_lists) {
+    /* 'next NAL' indicator is 4 bytes */
+    fail_unless_equals_int (chain_list_bytes_received, bytes_sent * LOOP_COUNT);
+  }
+}
+
+static const guint8 rtp_ilbc_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_ilbc_frame_data_size = 20;
+
+static int rtp_ilbc_frame_count = 1;
+
+GST_START_TEST (rtp_ilbc)
+{
+  rtp_pipeline_test (rtp_ilbc_frame_data, rtp_ilbc_frame_data_size,
+      rtp_ilbc_frame_count, "audio/x-iLBC,mode=20", "rtpilbcpay",
+      "rtpilbcdepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_gsm_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_gsm_frame_data_size = 20;
+
+static int rtp_gsm_frame_count = 1;
+
+GST_START_TEST (rtp_gsm)
+{
+  rtp_pipeline_test (rtp_gsm_frame_data, rtp_gsm_frame_data_size,
+      rtp_gsm_frame_count, "audio/x-gsm,rate=8000,channels=1", "rtpgsmpay",
+      "rtpgsmdepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_amr_frame_data[] =
+    { 0x3c, 0x24, 0x03, 0xb3, 0x48, 0x10, 0x68, 0x46, 0x6c, 0xec, 0x03,
+  0x7a, 0x37, 0x16, 0x41, 0x41, 0xc0, 0x00, 0x0d, 0xcd, 0x12, 0xed,
+  0xad, 0x80, 0x00, 0x00, 0x11, 0x31, 0x00, 0x00, 0x0d, 0xa0
+};
+
+static int rtp_amr_frame_data_size = 32;
+
+static int rtp_amr_frame_count = 1;
+
+GST_START_TEST (rtp_amr)
+{
+  rtp_pipeline_test (rtp_amr_frame_data, rtp_amr_frame_data_size,
+      rtp_amr_frame_count, "audio/AMR,channels=1,rate=8000", "rtpamrpay",
+      "rtpamrdepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_pcma_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_pcma_frame_data_size = 20;
+
+static int rtp_pcma_frame_count = 1;
+
+GST_START_TEST (rtp_pcma)
+{
+  rtp_pipeline_test (rtp_pcma_frame_data, rtp_pcma_frame_data_size,
+      rtp_pcma_frame_count, "audio/x-alaw,channels=1,rate=8000", "rtppcmapay",
+      "rtppcmadepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_pcmu_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_pcmu_frame_data_size = 20;
+
+static int rtp_pcmu_frame_count = 1;
+
+GST_START_TEST (rtp_pcmu)
+{
+  rtp_pipeline_test (rtp_pcmu_frame_data, rtp_pcmu_frame_data_size,
+      rtp_pcmu_frame_count, "audio/x-mulaw,channels=1,rate=8000", "rtppcmupay",
+      "rtppcmudepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_mpa_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_mpa_frame_data_size = 20;
+
+static int rtp_mpa_frame_count = 1;
+
+GST_START_TEST (rtp_mpa)
+{
+  rtp_pipeline_test (rtp_mpa_frame_data, rtp_mpa_frame_data_size,
+      rtp_mpa_frame_count, "audio/mpeg,mpegversion=1", "rtpmpapay",
+      "rtpmpadepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+
+static const guint8 rtp_h261_frame_data[] = {
+  0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x11, 0x00, 0x00, 0x4c, 0x40, 0x00,
+  0x15, 0x10,
+};
+
+static int rtp_h261_frame_data_size = 14;
+static int rtp_h261_frame_count = 1;
+
+GST_START_TEST (rtp_h261)
+{
+  rtp_pipeline_test (rtp_h261_frame_data, rtp_h261_frame_data_size,
+      rtp_h261_frame_count, "video/x-h261", "rtph261pay", "rtph261depay",
+      0, 0, FALSE);
+}
+
+GST_END_TEST;
+
+static const guint8 rtp_h263_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_h263_frame_data_size = 20;
+
+static int rtp_h263_frame_count = 1;
+
+GST_START_TEST (rtp_h263)
+{
+  rtp_pipeline_test (rtp_h263_frame_data, rtp_h263_frame_data_size,
+      rtp_h263_frame_count,
+      "video/x-h263,variant=(string)itu,h263version=h263",
+      "rtph263pay", "rtph263depay", 0, 0, FALSE);
+  rtp_pipeline_test (rtp_h263_frame_data, rtp_h263_frame_data_size,
+      rtp_h263_frame_count,
+      "video/x-h263,variant=(string)itu,h263version=h263,width=10,height=20",
+      "rtph263pay", "rtph263depay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_h263p_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_h263p_frame_data_size = 20;
+
+static int rtp_h263p_frame_count = 1;
+
+GST_START_TEST (rtp_h263p)
+{
+  rtp_pipeline_test (rtp_h263p_frame_data, rtp_h263p_frame_data_size,
+      rtp_h263p_frame_count, "video/x-h263,variant=(string)itu,"
+      "h263version=(string)h263", "rtph263ppay", "rtph263pdepay", 0, 0, FALSE);
+
+  /* payloader should accept any input that matches the template caps
+   * if there's just a udpsink or fakesink downstream */
+  rtp_pipeline_test (rtp_h263p_frame_data, rtp_h263p_frame_data_size,
+      rtp_h263p_frame_count, "video/x-h263,variant=(string)itu,"
+      "h263version=(string)h263", "rtph263ppay", "identity", 0, 0, FALSE);
+
+  /* default output of avenc_h263p */
+  rtp_pipeline_test (rtp_h263p_frame_data, rtp_h263p_frame_data_size,
+      rtp_h263p_frame_count, "video/x-h263,variant=(string)itu,"
+      "h263version=(string)h263p, annex-f=(boolean)true, "
+      "annex-j=(boolean)true, annex-i=(boolean)true, annex-t=(boolean)true",
+      "rtph263ppay", "identity", 0, 0, FALSE);
+
+  /* pay ! depay should also work with any input */
+  rtp_pipeline_test (rtp_h263p_frame_data, rtp_h263p_frame_data_size,
+      rtp_h263p_frame_count, "video/x-h263,variant=(string)itu,"
+      "h263version=(string)h263p, annex-f=(boolean)true, "
+      "annex-j=(boolean)true, annex-i=(boolean)true, annex-t=(boolean)true",
+      "rtph263ppay", "rtph263pdepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_h264_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_h264_frame_data_size = 20;
+
+static int rtp_h264_frame_count = 1;
+
+GST_START_TEST (rtp_h264)
+{
+  /* FIXME 0.11: fully specify h264 caps (and make payloader check) */
+  rtp_pipeline_test (rtp_h264_frame_data, rtp_h264_frame_data_size,
+      rtp_h264_frame_count,
+      "video/x-h264,stream-format=(string)byte-stream,alignment=(string)nal",
+      "rtph264pay", "rtph264depay", 0, 0, FALSE);
+
+  /* config-interval property used to be of uint type, was changed to int,
+   * make sure old GValue stuff still works */
+  {
+    GValue val = G_VALUE_INIT;
+    GstElement *rtph264pay;
+    GParamSpec *pspec;
+
+
+    rtph264pay = gst_element_factory_make ("rtph264pay", NULL);
+    pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (rtph264pay),
+        "config-interval");
+    fail_unless (pspec->value_type == G_TYPE_INT);
+    g_value_init (&val, G_TYPE_UINT);
+    g_value_set_uint (&val, 10);
+    g_object_set_property (G_OBJECT (rtph264pay), "config-interval", &val);
+    g_value_set_uint (&val, 0);
+    g_object_get_property (G_OBJECT (rtph264pay), "config-interval", &val);
+    fail_unless_equals_int (10, g_value_get_uint (&val));
+    g_object_set (G_OBJECT (rtph264pay), "config-interval", -1, NULL);
+    g_object_get_property (G_OBJECT (rtph264pay), "config-interval", &val);
+    fail_unless (g_value_get_uint (&val) == G_MAXUINT);
+    g_value_unset (&val);
+    gst_object_unref (rtph264pay);
+  }
+}
+
+GST_END_TEST;
+
+/* H264 data generated with:
+ * videotestsrc pattern=black ! video/x-raw,width=16,height=16 ! openh264enc */
+static const guint8 h264_16x16_black_bs[] = {
+  0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xd0, 0x0b,
+  0x8c, 0x8d, 0x4e, 0x40, 0x3c, 0x22, 0x11, 0xa8,
+  0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x3c, 0x80,
+  0x00, 0x00, 0x00, 0x01, 0x65, 0xb8, 0x00, 0x04,
+  0x00, 0x00, 0x09, 0xe4, 0xc5, 0x00, 0x01, 0x19,
+  0xfc
+};
+
+static GstSample *
+rtp_h264depay_run (const gchar * stream_format)
+{
+  GstHarness *h;
+  GstSample *sample;
+  GstBuffer *buf;
+  GstEvent *e;
+  GstCaps *out_caps;
+  GstCaps *in_caps;
+  gboolean seen_caps = FALSE;
+  gsize size;
+
+  h = gst_harness_new_parse ("rtph264pay ! rtph264depay");
+
+  /* Our input data is in byte-stream format (not that it matters) */
+  in_caps = gst_caps_new_simple ("video/x-h264",
+      "stream-format", G_TYPE_STRING, "byte-stream",
+      "alignment", G_TYPE_STRING, "au",
+      "profile", G_TYPE_STRING, "baseline",
+      "width", G_TYPE_INT, 16,
+      "height", G_TYPE_INT, 16, "framerate", GST_TYPE_FRACTION, 30, 1, NULL);
+
+  /* Force rtph264depay to output format as requested */
+  out_caps = gst_caps_new_simple ("video/x-h264",
+      "stream-format", G_TYPE_STRING, stream_format,
+      "alignment", G_TYPE_STRING, "au", NULL);
+
+  gst_harness_set_caps (h, in_caps, out_caps);
+  in_caps = NULL;
+  out_caps = NULL;
+
+  gst_harness_play (h);
+
+  size = sizeof (h264_16x16_black_bs);
+  buf = gst_buffer_new_wrapped (g_memdup (h264_16x16_black_bs, size), size);
+  fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
+  fail_unless (gst_harness_push_event (h, gst_event_new_eos ()));
+
+  while ((e = gst_harness_try_pull_event (h))) {
+    if (GST_EVENT_TYPE (e) == GST_EVENT_CAPS) {
+      GstCaps *caps = NULL;
+
+      gst_event_parse_caps (e, &caps);
+      gst_caps_replace (&out_caps, caps);
+      seen_caps = TRUE;
+    }
+    gst_event_unref (e);
+  }
+  fail_unless (seen_caps);
+
+  buf = gst_harness_pull (h);
+  sample = gst_sample_new (buf, out_caps, NULL, NULL);
+  gst_buffer_unref (buf);
+  gst_caps_replace (&out_caps, NULL);
+
+  gst_harness_teardown (h);
+  return sample;
+}
+
+GST_START_TEST (rtp_h264depay_avc)
+{
+  const GValue *val;
+  GstStructure *st;
+  GstMapInfo map = GST_MAP_INFO_INIT;
+  GstBuffer *buf;
+  GstSample *s;
+  GstCaps *caps;
+
+  s = rtp_h264depay_run ("avc");
+
+  /* must have codec_data in output caps */
+  caps = gst_sample_get_caps (s);
+  st = gst_caps_get_structure (caps, 0);
+  GST_LOG ("caps: %" GST_PTR_FORMAT, caps);
+  fail_unless (gst_structure_has_field (st, "stream-format"));
+  fail_unless (gst_structure_has_field (st, "alignment"));
+  fail_unless (gst_structure_has_field (st, "level"));
+  fail_unless (gst_structure_has_field (st, "profile"));
+  val = gst_structure_get_value (st, "codec_data");
+  fail_unless (val != NULL);
+  fail_unless (GST_VALUE_HOLDS_BUFFER (val));
+  /* check codec_data, shouldn't contain trailing zeros */
+  buf = gst_value_get_buffer (val);
+  fail_unless (gst_buffer_map (buf, &map, GST_MAP_READ));
+  {
+    guint num_sps, num_pps, len;
+    guint8 *data;
+
+    GST_MEMDUMP ("H.264 codec_data", map.data, map.size);
+    fail_unless_equals_int (map.data[0], 1);
+    num_sps = map.data[5] & 0x1f;
+    data = map.data + 6;
+    fail_unless_equals_int (num_sps, 1);
+    len = GST_READ_UINT16_BE (data);
+    data += 2;
+    /* make sure there are no trailing zeros in the SPS */
+    fail_unless (data[len - 1] != 0);
+    data += len;
+    num_pps = *data++;
+    fail_unless_equals_int (num_pps, 1);
+    len = GST_READ_UINT16_BE (data);
+    data += 2;
+    /* make sure there are no trailing zeros in the PPS */
+    fail_unless (data[len - 1] != 0);
+  }
+  gst_buffer_unmap (buf, &map);
+
+  buf = gst_sample_get_buffer (s);
+  fail_unless (gst_buffer_map (buf, &map, GST_MAP_READ));
+  GST_MEMDUMP ("H.264 AVC frame", map.data, map.size);
+  fail_unless (map.size >= 4 + 13);
+  /* Want IDR slice as very first thing.
+   * We assume nal size markers are 4 bytes here. */
+  fail_unless_equals_int (map.data[4] & 0x1f, 5);
+  gst_buffer_unmap (buf, &map);
+
+  gst_sample_unref (s);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (rtp_h264depay_bytestream)
+{
+  GstByteReader br;
+  GstStructure *st;
+  GstMapInfo map = GST_MAP_INFO_INIT;
+  GstBuffer *buf;
+  GstSample *s;
+  GstCaps *caps;
+  guint32 dw;
+  guint8 b;
+  guint off, left;
+
+  s = rtp_h264depay_run ("byte-stream");
+
+  /* must not have codec_data in output caps */
+  caps = gst_sample_get_caps (s);
+  st = gst_caps_get_structure (caps, 0);
+  GST_LOG ("caps: %" GST_PTR_FORMAT, caps);
+  fail_if (gst_structure_has_field (st, "codec_data"));
+
+  buf = gst_sample_get_buffer (s);
+  fail_unless (gst_buffer_map (buf, &map, GST_MAP_READ));
+  GST_MEMDUMP ("H.264 byte-stream frame", map.data, map.size);
+  fail_unless (map.size > 40);
+  gst_byte_reader_init (&br, map.data, map.size);
+  /* We assume nal sync markers are 4 bytes... */
+  fail_unless (gst_byte_reader_get_uint32_be (&br, &dw));
+  fail_unless_equals_int (dw, 0x00000001);
+  /* Want SPS as very first thing */
+  fail_unless (gst_byte_reader_get_uint8 (&br, &b));
+  fail_unless_equals_int (b & 0x1f, 7);
+  /* Then, we want the PPS */
+  left = gst_byte_reader_get_remaining (&br);
+  off = gst_byte_reader_masked_scan_uint32 (&br, 0xffffffff, 1, 0, left);
+  fail_if (off == (guint) - 1);
+  gst_byte_reader_skip (&br, off + 4);
+  fail_unless (gst_byte_reader_get_uint8 (&br, &b));
+  fail_unless_equals_int (b & 0x1f, 8);
+  /* FIXME: looks like we get two sets of SPS/PPS ?! */
+  left = gst_byte_reader_get_remaining (&br);
+  off = gst_byte_reader_masked_scan_uint32 (&br, 0xffffffff, 1, 0, left);
+  fail_if (off == (guint) - 1);
+  gst_byte_reader_skip (&br, off + 4);
+  left = gst_byte_reader_get_remaining (&br);
+  off = gst_byte_reader_masked_scan_uint32 (&br, 0xffffffff, 1, 0, left);
+  fail_if (off == (guint) - 1);
+  gst_byte_reader_skip (&br, off + 4);
+  /* Finally, we want an IDR slice */
+  left = gst_byte_reader_get_remaining (&br);
+  off = gst_byte_reader_masked_scan_uint32 (&br, 0xffffffff, 1, 0, left);
+  fail_if (off == (guint) - 1);
+  gst_byte_reader_skip (&br, off + 4);
+  fail_unless (gst_byte_reader_get_uint8 (&br, &b));
+  fail_unless_equals_int (b & 0x1f, 5);
+  gst_buffer_unmap (buf, &map);
+
+  gst_sample_unref (s);
+}
+
+GST_END_TEST;
+
+static const guint8 rtp_h264_list_lt_mtu_frame_data[] =
+    /* not packetized, next NAL starts with 0001 */
+{ 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+  0xad, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x10
+};
+
+static int rtp_h264_list_lt_mtu_frame_data_size = 16;
+
+static int rtp_h264_list_lt_mtu_frame_count = 2;
+
+/* NAL = 4 bytes */
+/* also 2 bytes FU-A header each time */
+static int rtp_h264_list_lt_mtu_bytes_sent = 2 * (16 - 4);
+
+static int rtp_h264_list_lt_mtu_mtu_size = 1024;
+
+GST_START_TEST (rtp_h264_list_lt_mtu)
+{
+  /* FIXME 0.11: fully specify h264 caps (and make payloader check) */
+  rtp_pipeline_test (rtp_h264_list_lt_mtu_frame_data,
+      rtp_h264_list_lt_mtu_frame_data_size, rtp_h264_list_lt_mtu_frame_count,
+      "video/x-h264,stream-format=(string)byte-stream,alignment=(string)nal",
+      "rtph264pay", "rtph264depay",
+      rtp_h264_list_lt_mtu_bytes_sent, rtp_h264_list_lt_mtu_mtu_size, TRUE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_h264_list_lt_mtu_frame_data_avc[] =
+    /* packetized data */
+{ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
+  0xad, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0d, 0x00
+};
+
+/* NAL = 4 bytes */
+static int rtp_h264_list_lt_mtu_bytes_sent_avc = 2 * (16 - 2 * 4);
+
+//static int rtp_h264_list_lt_mtu_mtu_size = 1024;
+
+GST_START_TEST (rtp_h264_list_lt_mtu_avc)
+{
+  /* FIXME 0.11: fully specify h264 caps (and make payloader check) */
+  rtp_pipeline_test (rtp_h264_list_lt_mtu_frame_data_avc,
+      rtp_h264_list_lt_mtu_frame_data_size, rtp_h264_list_lt_mtu_frame_count,
+      "video/x-h264,stream-format=(string)avc,alignment=(string)au,"
+      "codec_data=(buffer)01640014ffe1001867640014acd94141fb0110000003001773594000f142996001000568ebecb22c",
+      "rtph264pay", "rtph264depay",
+      rtp_h264_list_lt_mtu_bytes_sent_avc, rtp_h264_list_lt_mtu_mtu_size, TRUE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_h264_list_gt_mtu_frame_data[] =
+    /* not packetized, next NAL starts with 0001 */
+{ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
+};
+
+static int rtp_h264_list_gt_mtu_frame_data_size = 64;
+
+static int rtp_h264_list_gt_mtu_frame_count = 1;
+
+/* NAL = 4 bytes. When data does not fit into 1 mtu, 1 byte will be skipped */
+static int rtp_h264_list_gt_mtu_bytes_sent = 1 * (64 - 4) - 1;
+
+static int rtp_h264_list_gt_mtu_mty_size = 28;
+
+GST_START_TEST (rtp_h264_list_gt_mtu)
+{
+  /* FIXME 0.11: fully specify h264 caps (and make payloader check) */
+  rtp_pipeline_test (rtp_h264_list_gt_mtu_frame_data,
+      rtp_h264_list_gt_mtu_frame_data_size, rtp_h264_list_gt_mtu_frame_count,
+      "video/x-h264,stream-format=(string)byte-stream,alignment=(string)nal",
+      "rtph264pay", "rtph264depay",
+      rtp_h264_list_gt_mtu_bytes_sent, rtp_h264_list_gt_mtu_mty_size, TRUE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_h264_list_gt_mtu_frame_data_avc[] =
+    /* packetized data */
+{ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* NAL = 4 bytes. When data does not fit into 1 mtu, 1 byte will be skipped */
+static int rtp_h264_list_gt_mtu_bytes_sent_avc = 1 * (64 - 2 * 4 - 2 * 1);
+
+GST_START_TEST (rtp_h264_list_gt_mtu_avc)
+{
+  /* FIXME 0.11: fully specify h264 caps (and make payloader check) */
+  rtp_pipeline_test (rtp_h264_list_gt_mtu_frame_data_avc,
+      rtp_h264_list_gt_mtu_frame_data_size, rtp_h264_list_gt_mtu_frame_count,
+      "video/x-h264,stream-format=(string)avc,alignment=(string)au,"
+      "codec_data=(buffer)01640014ffe1001867640014acd94141fb0110000003001773594000f142996001000568ebecb22c",
+      "rtph264pay", "rtph264depay",
+      rtp_h264_list_gt_mtu_bytes_sent_avc, rtp_h264_list_gt_mtu_mty_size, TRUE);
+}
+
+GST_END_TEST;
+
+static const guint8 rtp_h265_frame_data[] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_h265_frame_data_size = 20;
+
+static int rtp_h265_frame_count = 1;
+
+GST_START_TEST (rtp_h265)
+{
+  rtp_pipeline_test (rtp_h265_frame_data, rtp_h265_frame_data_size,
+      rtp_h265_frame_count,
+      "video/x-h265,stream-format=(string)byte-stream,alignment=(string)nal",
+      "rtph265pay", "rtph265depay", 0, 0, FALSE);
+
+  /* config-interval property used to be of uint type, was changed to int,
+   * make sure old GValue stuff still works */
+  {
+    GValue val = G_VALUE_INIT;
+    GstElement *rtph265pay;
+    GParamSpec *pspec;
+
+
+    rtph265pay = gst_element_factory_make ("rtph265pay", NULL);
+    pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (rtph265pay),
+        "config-interval");
+    fail_unless (pspec->value_type == G_TYPE_INT);
+    g_value_init (&val, G_TYPE_UINT);
+    g_value_set_uint (&val, 10);
+    g_object_set_property (G_OBJECT (rtph265pay), "config-interval", &val);
+    g_value_set_uint (&val, 0);
+    g_object_get_property (G_OBJECT (rtph265pay), "config-interval", &val);
+    fail_unless_equals_int (10, g_value_get_uint (&val));
+    g_object_set (G_OBJECT (rtph265pay), "config-interval", -1, NULL);
+    g_object_get_property (G_OBJECT (rtph265pay), "config-interval", &val);
+    fail_unless (g_value_get_uint (&val) == G_MAXUINT);
+    g_value_unset (&val);
+    gst_object_unref (rtph265pay);
+  }
+}
+
+GST_END_TEST;
+static const guint8 rtp_h265_list_lt_mtu_frame_data[] = {
+  /* not packetized, next NALU starts with 0x00000001 */
+  0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x10
+};
+
+static int rtp_h265_list_lt_mtu_frame_data_size = 16;
+
+static int rtp_h265_list_lt_mtu_frame_count = 2;
+
+/* 3 bytes start code prefixed with one zero byte, NALU header is in payload */
+static int rtp_h265_list_lt_mtu_bytes_sent = 2 * (16 - 3 - 1);
+
+static int rtp_h265_list_lt_mtu_mtu_size = 1024;
+
+GST_START_TEST (rtp_h265_list_lt_mtu)
+{
+  rtp_pipeline_test (rtp_h265_list_lt_mtu_frame_data,
+      rtp_h265_list_lt_mtu_frame_data_size, rtp_h265_list_lt_mtu_frame_count,
+      "video/x-h265,stream-format=(string)byte-stream,alignment=(string)nal",
+      "rtph265pay", "rtph265depay", rtp_h265_list_lt_mtu_bytes_sent,
+      rtp_h265_list_lt_mtu_mtu_size, TRUE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_h265_list_lt_mtu_frame_data_hvc1[] = {
+  /* packetized data */
+  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* length size is 3 bytes */
+static int rtp_h265_list_lt_mtu_bytes_sent_hvc1 = 2 * (16 - 2 * 3);
+
+
+GST_START_TEST (rtp_h265_list_lt_mtu_hvc1)
+{
+  rtp_pipeline_test (rtp_h265_list_lt_mtu_frame_data_hvc1,
+      rtp_h265_list_lt_mtu_frame_data_size, rtp_h265_list_lt_mtu_frame_count,
+      "video/x-h265,stream-format=(string)hvc1,alignment=(string)au,"
+      "codec_data=(buffer)0101c000000080000000000099f000fcfdf8f800000203a000010"
+      "01840010c01ffff01c000000300800000030000030099ac0900a10001003042010101c00"
+      "0000300800000030000030099a00a080f1fe36bbb5377725d602dc040404100000300010"
+      "00003000a0800a2000100074401c172b02240",
+      "rtph265pay", "rtph265depay", rtp_h265_list_lt_mtu_bytes_sent_hvc1,
+      rtp_h265_list_lt_mtu_mtu_size, TRUE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_h265_list_gt_mtu_frame_data[] = {
+  /* not packetized, next NAL starts with 0x000001 */
+  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x10
+};
+
+static const int rtp_h265_list_gt_mtu_frame_data_size = 62;
+
+static const int rtp_h265_list_gt_mtu_frame_count = 1;
+
+/* start code is 3 bytes, NALU header is 2 bytes */
+static int rtp_h265_list_gt_mtu_bytes_sent = 1 * (62 - 3 - 2);
+
+static int rtp_h265_list_gt_mtu_mtu_size = 28;
+
+GST_START_TEST (rtp_h265_list_gt_mtu)
+{
+  rtp_pipeline_test (rtp_h265_list_gt_mtu_frame_data,
+      rtp_h265_list_gt_mtu_frame_data_size, rtp_h265_list_gt_mtu_frame_count,
+      "video/x-h265,stream-format=(string)byte-stream,alignment=(string)nal",
+      "rtph265pay", "rtph265depay", rtp_h265_list_gt_mtu_bytes_sent,
+      rtp_h265_list_gt_mtu_mtu_size, TRUE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_h265_list_gt_mtu_frame_data_hvc1[] = {
+  /* packetized data */
+  0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* length size is 3 bytes, NALU header is 2 bytes */
+static int rtp_h265_list_gt_mtu_bytes_sent_hvc1 = 1 * (62 - 2 * 3 - 2 * 2);
+
+GST_START_TEST (rtp_h265_list_gt_mtu_hvc1)
+{
+  rtp_pipeline_test (rtp_h265_list_gt_mtu_frame_data_hvc1,
+      rtp_h265_list_gt_mtu_frame_data_size, rtp_h265_list_gt_mtu_frame_count,
+      "video/x-h265,stream-format=(string)hvc1,alignment=(string)au,"
+      "codec_data=(buffer)0101c000000080000000000099f000fcfdf8f800000203a000010"
+      "01840010c01ffff01c000000300800000030000030099ac0900a10001003042010101c00"
+      "0000300800000030000030099a00a080f1fe36bbb5377725d602dc040404100000300010"
+      "00003000a0800a2000100074401c172b02240",
+      "rtph265pay", "rtph265depay", rtp_h265_list_gt_mtu_bytes_sent_hvc1,
+      rtp_h265_list_gt_mtu_mtu_size, TRUE);
+}
+
+GST_END_TEST;
+
+/* KLV data from Day_Flight.mpg */
+static const guint8 rtp_KLV_frame_data[] = {
+  0x06, 0x0e, 0x2b, 0x34, 0x02, 0x0b, 0x01, 0x01,
+  0x0e, 0x01, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00,
+  0x81, 0x91, 0x02, 0x08, 0x00, 0x04, 0x6c, 0x8e,
+  0x20, 0x03, 0x83, 0x85, 0x41, 0x01, 0x01, 0x05,
+  0x02, 0x3d, 0x3b, 0x06, 0x02, 0x15, 0x80, 0x07,
+  0x02, 0x01, 0x52, 0x0b, 0x03, 0x45, 0x4f, 0x4e,
+  0x0c, 0x0e, 0x47, 0x65, 0x6f, 0x64, 0x65, 0x74,
+  0x69, 0x63, 0x20, 0x57, 0x47, 0x53, 0x38, 0x34,
+  0x0d, 0x04, 0x4d, 0xc4, 0xdc, 0xbb, 0x0e, 0x04,
+  0xb1, 0xa8, 0x6c, 0xfe, 0x0f, 0x02, 0x1f, 0x4a,
+  0x10, 0x02, 0x00, 0x85, 0x11, 0x02, 0x00, 0x4b,
+  0x12, 0x04, 0x20, 0xc8, 0xd2, 0x7d, 0x13, 0x04,
+  0xfc, 0xdd, 0x02, 0xd8, 0x14, 0x04, 0xfe, 0xb8,
+  0xcb, 0x61, 0x15, 0x04, 0x00, 0x8f, 0x3e, 0x61,
+  0x16, 0x04, 0x00, 0x00, 0x01, 0xc9, 0x17, 0x04,
+  0x4d, 0xdd, 0x8c, 0x2a, 0x18, 0x04, 0xb1, 0xbe,
+  0x9e, 0xf4, 0x19, 0x02, 0x0b, 0x85, 0x28, 0x04,
+  0x4d, 0xdd, 0x8c, 0x2a, 0x29, 0x04, 0xb1, 0xbe,
+  0x9e, 0xf4, 0x2a, 0x02, 0x0b, 0x85, 0x38, 0x01,
+  0x2e, 0x39, 0x04, 0x00, 0x8d, 0xd4, 0x29, 0x01,
+  0x02, 0x1c, 0x5f
+};
+
+GST_START_TEST (rtp_klv)
+{
+  rtp_pipeline_test (rtp_KLV_frame_data, G_N_ELEMENTS (rtp_KLV_frame_data), 1,
+      "meta/x-klv, parsed=(bool)true", "rtpklvpay", "rtpklvdepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (rtp_klv_fragmented)
+{
+  /* force super-small mtu of 60 to fragment KLV unit */
+  rtp_pipeline_test (rtp_KLV_frame_data, sizeof (rtp_KLV_frame_data), 1,
+      "meta/x-klv, parsed=(bool)true", "rtpklvpay", "rtpklvdepay",
+      sizeof (rtp_KLV_frame_data), 60, FALSE);
+}
+
+GST_END_TEST;
+
+static const guint8 rtp_L16_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_L16_frame_data_size = 20;
+
+static int rtp_L16_frame_count = 1;
+
+GST_START_TEST (rtp_L16)
+{
+  rtp_pipeline_test (rtp_L16_frame_data, rtp_L16_frame_data_size,
+      rtp_L16_frame_count,
+      "audio/x-raw,format=S16BE,rate=1,channels=1,layout=(string)interleaved",
+      "rtpL16pay", "rtpL16depay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+
+static const guint8 rtp_L24_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_L24_frame_data_size = 24;
+
+static int rtp_L24_frame_count = 1;
+
+GST_START_TEST (rtp_L24)
+{
+  rtp_pipeline_test (rtp_L24_frame_data, rtp_L24_frame_data_size,
+      rtp_L24_frame_count,
+      "audio/x-raw,format=S24BE,rate=1,channels=1,layout=(string)interleaved",
+      "rtpL24pay", "rtpL24depay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_mp2t_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_mp2t_frame_data_size = 20;
+
+static int rtp_mp2t_frame_count = 1;
+
+GST_START_TEST (rtp_mp2t)
+{
+  rtp_pipeline_test (rtp_mp2t_frame_data, rtp_mp2t_frame_data_size,
+      rtp_mp2t_frame_count, "video/mpegts,packetsize=188,systemstream=true",
+      "rtpmp2tpay", "rtpmp2tdepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_mp4v_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_mp4v_frame_data_size = 20;
+
+static int rtp_mp4v_frame_count = 1;
+
+GST_START_TEST (rtp_mp4v)
+{
+  rtp_pipeline_test (rtp_mp4v_frame_data, rtp_mp4v_frame_data_size,
+      rtp_mp4v_frame_count, "video/mpeg,mpegversion=4,systemstream=false",
+      "rtpmp4vpay", "rtpmp4vdepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_mp4v_list_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_mp4v_list_frame_data_size = 20;
+
+static int rtp_mp4v_list_frame_count = 1;
+
+static int rtp_mp4v_list_bytes_sent = 1 * 20;
+
+GST_START_TEST (rtp_mp4v_list)
+{
+  rtp_pipeline_test (rtp_mp4v_list_frame_data, rtp_mp4v_list_frame_data_size,
+      rtp_mp4v_list_frame_count,
+      "video/mpeg,mpegversion=4,systemstream=false,codec_data=(buffer)000001b001",
+      "rtpmp4vpay", "rtpmp4vdepay", rtp_mp4v_list_bytes_sent, 0, TRUE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_mp4g_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_mp4g_frame_data_size = 20;
+
+static int rtp_mp4g_frame_count = 1;
+
+GST_START_TEST (rtp_mp4g)
+{
+  rtp_pipeline_test (rtp_mp4g_frame_data, rtp_mp4g_frame_data_size,
+      rtp_mp4g_frame_count,
+      "video/mpeg,mpegversion=4,systemstream=false,codec_data=(buffer)000001b001",
+      "rtpmp4gpay", "rtpmp4gdepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_theora_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_theora_frame_data_size = 20;
+
+static int rtp_theora_frame_count = 1;
+
+GST_START_TEST (rtp_theora)
+{
+  rtp_pipeline_test (rtp_theora_frame_data, rtp_theora_frame_data_size,
+      rtp_theora_frame_count, "video/x-theora", "rtptheorapay",
+      "rtptheoradepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_vorbis_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_vorbis_frame_data_size = 20;
+
+static int rtp_vorbis_frame_count = 1;
+
+GST_START_TEST (rtp_vorbis)
+{
+  rtp_pipeline_test (rtp_vorbis_frame_data, rtp_vorbis_frame_data_size,
+      rtp_vorbis_frame_count, "audio/x-vorbis", "rtpvorbispay",
+      "rtpvorbisdepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+static const guint8 rtp_jpeg_frame_data[] =
+    { /* SOF */ 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0x08, 0x00, 0x08,
+  0x03, 0x00, 0x21, 0x08, 0x01, 0x11, 0x08, 0x02, 0x11, 0x08,
+  /* DQT */ 0xFF, 0xDB, 0x00, 0x43, 0x08,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  /* DATA */ 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_jpeg_frame_data_size = sizeof (rtp_jpeg_frame_data);
+
+static int rtp_jpeg_frame_count = 1;
+
+GST_START_TEST (rtp_jpeg)
+{
+  rtp_pipeline_test (rtp_jpeg_frame_data, rtp_jpeg_frame_data_size,
+      rtp_jpeg_frame_count, "video/x-jpeg,height=640,width=480", "rtpjpegpay",
+      "rtpjpegdepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (rtp_jpeg_width_greater_than_2040)
+{
+  rtp_pipeline_test (rtp_jpeg_frame_data, rtp_jpeg_frame_data_size,
+      rtp_jpeg_frame_count, "video/x-jpeg,height=2048,width=480", "rtpjpegpay",
+      "rtpjpegdepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (rtp_jpeg_height_greater_than_2040)
+{
+  rtp_pipeline_test (rtp_jpeg_frame_data, rtp_jpeg_frame_data_size,
+      rtp_jpeg_frame_count, "video/x-jpeg,height=640,width=2048", "rtpjpegpay",
+      "rtpjpegdepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (rtp_jpeg_width_and_height_greater_than_2040)
+{
+  rtp_pipeline_test (rtp_jpeg_frame_data, rtp_jpeg_frame_data_size,
+      rtp_jpeg_frame_count, "video/x-jpeg,height=2048,width=2048", "rtpjpegpay",
+      "rtpjpegdepay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+
+static const guint8 rtp_jpeg_list_frame_data[] =
+    { /* SOF */ 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0x08, 0x00, 0x08,
+  0x03, 0x00, 0x21, 0x08, 0x01, 0x11, 0x08, 0x02, 0x11, 0x08,
+  /* DQT */ 0xFF, 0xDB, 0x00, 0x43, 0x08,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  /* DATA */ 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_jpeg_list_frame_data_size = sizeof (rtp_jpeg_list_frame_data);
+
+static int rtp_jpeg_list_frame_count = 1;
+
+static int rtp_jpeg_list_bytes_sent = 1 * sizeof (rtp_jpeg_list_frame_data);
+
+GST_START_TEST (rtp_jpeg_list)
+{
+  rtp_pipeline_test (rtp_jpeg_list_frame_data, rtp_jpeg_list_frame_data_size,
+      rtp_jpeg_list_frame_count, "video/x-jpeg,height=640,width=480",
+      "rtpjpegpay", "rtpjpegdepay", rtp_jpeg_list_bytes_sent, 0, TRUE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (rtp_jpeg_list_width_greater_than_2040)
+{
+  rtp_pipeline_test (rtp_jpeg_list_frame_data, rtp_jpeg_list_frame_data_size,
+      rtp_jpeg_list_frame_count, "video/x-jpeg,height=2048,width=480",
+      "rtpjpegpay", "rtpjpegdepay", rtp_jpeg_list_bytes_sent, 0, TRUE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (rtp_jpeg_list_height_greater_than_2040)
+{
+  rtp_pipeline_test (rtp_jpeg_list_frame_data, rtp_jpeg_list_frame_data_size,
+      rtp_jpeg_list_frame_count, "video/x-jpeg,height=640,width=2048",
+      "rtpjpegpay", "rtpjpegdepay", rtp_jpeg_list_bytes_sent, 0, TRUE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (rtp_jpeg_list_width_and_height_greater_than_2040)
+{
+  rtp_pipeline_test (rtp_jpeg_list_frame_data, rtp_jpeg_list_frame_data_size,
+      rtp_jpeg_list_frame_count, "video/x-jpeg,height=2048,width=2048",
+      "rtpjpegpay", "rtpjpegdepay", rtp_jpeg_list_bytes_sent, 0, TRUE);
+}
+
+GST_END_TEST;
+
+static void
+rtp_jpeg_do_packet_loss (gdouble prob, gint num_expected)
+{
+  GstHarness *h;
+  gboolean eos = FALSE;
+  gchar *s;
+  guint i, buffer_count;
+
+  s = g_strdup_printf ("videotestsrc pattern=ball num-buffers=100 ! "
+      "jpegenc quality=50 ! rtpjpegpay ! identity drop-probability=%g ! "
+      "rtpjpegdepay", prob);
+  GST_INFO ("running pipeline %s", s);
+  h = gst_harness_new_parse (s);
+  g_free (s);
+
+  gst_harness_play (h);
+
+  do {
+    GstEvent *event;
+
+    event = gst_harness_pull_event (h);
+    eos = (GST_EVENT_TYPE (event) == GST_EVENT_EOS);
+    gst_event_unref (event);
+  } while (!eos);
+
+  buffer_count = gst_harness_buffers_received (h);
+  GST_INFO ("Got %u buffers", buffer_count);
+
+  if (num_expected >= 0) {
+    fail_unless_equals_int (num_expected, buffer_count);
+  }
+
+  for (i = 0; i < buffer_count; ++i) {
+    GstBuffer *buf;
+    GstMapInfo map;
+    guint16 soi, eoi;
+
+    buf = gst_harness_pull (h);
+    fail_unless (buf != NULL);
+
+    fail_unless (gst_buffer_map (buf, &map, GST_MAP_READ));
+    GST_MEMDUMP ("jpeg frame", map.data, map.size);
+    fail_unless (map.size > 4);
+    soi = GST_READ_UINT16_BE (map.data);
+    fail_unless (soi == 0xffd8, "expected JPEG frame start FFD8 not %02X", soi);
+    eoi = GST_READ_UINT16_BE (map.data + map.size - 2);
+    fail_unless (eoi == 0xffd9, "expected JPEG frame end FFD9 not %02X", eoi);
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_unref (buf);
+  }
+
+  gst_harness_teardown (h);
+}
+
+GST_START_TEST (rtp_jpeg_packet_loss)
+{
+  gdouble probabilities[] = { 0.0, 0.001, 0.01, 0.1, 0.2, 0.5, 1.0 };
+  gint num_expected[] = { 100, -1, -1, -1, -1, -1, 0 };
+
+  GST_INFO ("Start iteration %d", __i__);
+  fail_unless (__i__ < G_N_ELEMENTS (probabilities));
+  rtp_jpeg_do_packet_loss (probabilities[__i__], num_expected[__i__]);
+  GST_INFO ("Done with iteration %d", __i__);
+}
+
+GST_END_TEST;
+
+static const guint8 rtp_g729_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_g729_frame_data_size = 22;
+
+static int rtp_g729_frame_count = 1;
+
+GST_START_TEST (rtp_g729)
+{
+  rtp_pipeline_test (rtp_g729_frame_data, rtp_g729_frame_data_size,
+      rtp_g729_frame_count, "audio/G729,rate=8000,channels=1", "rtpg729pay",
+      "rtpg729depay", 0, 0, FALSE);
+}
+
+GST_END_TEST;
+
+static const guint8 rtp_gst_frame_data[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int rtp_gst_frame_data_size = 22;
+
+static int rtp_gst_frame_count = 1;
+
+GST_START_TEST (rtp_gst_custom_event)
+{
+  /* Create RTP pipeline. */
+  rtp_pipeline *p =
+      rtp_pipeline_create (rtp_gst_frame_data, rtp_gst_frame_data_size,
+      rtp_gst_frame_count, "application/x-test",
+      "rtpgstpay", "rtpgstdepay");
+
+  if (p == NULL) {
+    return;
+  }
+
+  p->custom_event =
+      gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
+      gst_structure_new ("test", "foo", G_TYPE_INT, 1, NULL));
+
+  /* Run RTP pipeline. */
+  rtp_pipeline_run (p);
+
+  /* Destroy RTP pipeline. */
+  rtp_pipeline_destroy (p);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (rtp_vorbis_renegotiate)
+{
+  GstElement *pipeline;
+  GstElement *enc, *pay, *depay, *dec, *sink;
+  GstPad *sinkpad, *srcpad;
+  GstCaps *templcaps, *caps, *filter, *srccaps;
+  GstSegment segment;
+  GstBuffer *buffer;
+  GstMapInfo map;
+  GstAudioInfo info;
+
+  pipeline = gst_pipeline_new (NULL);
+  enc = gst_element_factory_make ("vorbisenc", NULL);
+  pay = gst_element_factory_make ("rtpvorbispay", NULL);
+  depay = gst_element_factory_make ("rtpvorbisdepay", NULL);
+  dec = gst_element_factory_make ("vorbisdec", NULL);
+  sink = gst_element_factory_make ("fakesink", NULL);
+  g_object_set (sink, "async", FALSE, NULL);
+  gst_bin_add_many (GST_BIN (pipeline), enc, pay, depay, dec, sink, NULL);
+  fail_unless (gst_element_link_many (enc, pay, depay, dec, sink, NULL));
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_SUCCESS);
+
+  sinkpad = gst_element_get_static_pad (enc, "sink");
+  srcpad = gst_element_get_static_pad (dec, "src");
+
+  templcaps = gst_pad_get_pad_template_caps (sinkpad);
+  filter =
+      gst_caps_new_simple ("audio/x-raw", "channels", G_TYPE_INT, 2, "rate",
+      G_TYPE_INT, 44100, NULL);
+  caps = gst_caps_intersect (templcaps, filter);
+  caps = gst_caps_fixate (caps);
+
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_send_event (sinkpad,
+          gst_event_new_stream_start ("test")));
+  fail_unless (gst_pad_send_event (sinkpad, gst_event_new_caps (caps)));
+  fail_unless (gst_pad_send_event (sinkpad, gst_event_new_segment (&segment)));
+
+  gst_audio_info_from_caps (&info, caps);
+  buffer = gst_buffer_new_and_alloc (44100 * info.bpf);
+  gst_buffer_map (buffer, &map, GST_MAP_WRITE);
+  gst_audio_format_fill_silence (info.finfo, map.data, map.size);
+  gst_buffer_unmap (buffer, &map);
+  GST_BUFFER_PTS (buffer) = 0;
+  GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
+
+  fail_unless_equals_int (gst_pad_chain (sinkpad, buffer), GST_FLOW_OK);
+
+  srccaps = gst_pad_get_current_caps (srcpad);
+  fail_unless (gst_caps_can_intersect (srccaps, caps));
+  gst_caps_unref (srccaps);
+
+  gst_caps_unref (caps);
+  gst_caps_unref (filter);
+  filter =
+      gst_caps_new_simple ("audio/x-raw", "channels", G_TYPE_INT, 2, "rate",
+      G_TYPE_INT, 48000, NULL);
+  caps = gst_caps_intersect (templcaps, filter);
+  caps = gst_caps_fixate (caps);
+
+  fail_unless (gst_pad_send_event (sinkpad, gst_event_new_caps (caps)));
+
+  gst_audio_info_from_caps (&info, caps);
+  buffer = gst_buffer_new_and_alloc (48000 * info.bpf);
+  gst_buffer_map (buffer, &map, GST_MAP_WRITE);
+  gst_audio_format_fill_silence (info.finfo, map.data, map.size);
+  gst_buffer_unmap (buffer, &map);
+  GST_BUFFER_PTS (buffer) = 0;
+  GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
+  GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
+
+  fail_unless_equals_int (gst_pad_chain (sinkpad, buffer), GST_FLOW_OK);
+
+  srccaps = gst_pad_get_current_caps (srcpad);
+  fail_unless (gst_caps_can_intersect (srccaps, caps));
+  gst_caps_unref (srccaps);
+
+  gst_caps_unref (caps);
+  gst_caps_unref (filter);
+  gst_caps_unref (templcaps);
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
+/*
+ * Creates the test suite.
+ *
+ * Returns: pointer to the test suite.
+ */
+static Suite *
+rtp_payloading_suite (void)
+{
+  GstRegistry *registry = gst_registry_get ();
+  Suite *s = suite_create ("rtp_data_test");
+
+  TCase *tc_chain = tcase_create ("linear");
+
+  /* Set timeout to 60 seconds. */
+  tcase_set_timeout (tc_chain, 60);
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, rtp_ilbc);
+  tcase_add_test (tc_chain, rtp_gsm);
+  tcase_add_test (tc_chain, rtp_amr);
+  tcase_add_test (tc_chain, rtp_pcma);
+  tcase_add_test (tc_chain, rtp_pcmu);
+  tcase_add_test (tc_chain, rtp_mpa);
+  tcase_add_test (tc_chain, rtp_h261);
+  tcase_add_test (tc_chain, rtp_h263);
+  tcase_add_test (tc_chain, rtp_h263p);
+  tcase_add_test (tc_chain, rtp_h264);
+  tcase_add_test (tc_chain, rtp_h264depay_avc);
+  tcase_add_test (tc_chain, rtp_h264depay_bytestream);
+  tcase_add_test (tc_chain, rtp_h264_list_lt_mtu);
+  tcase_add_test (tc_chain, rtp_h264_list_lt_mtu_avc);
+  tcase_add_test (tc_chain, rtp_h264_list_gt_mtu);
+  tcase_add_test (tc_chain, rtp_h264_list_gt_mtu_avc);
+  tcase_add_test (tc_chain, rtp_h265);
+  tcase_add_test (tc_chain, rtp_h265_list_lt_mtu);
+  tcase_add_test (tc_chain, rtp_h265_list_lt_mtu_hvc1);
+  tcase_add_test (tc_chain, rtp_h265_list_gt_mtu);
+  tcase_add_test (tc_chain, rtp_h265_list_gt_mtu_hvc1);
+  tcase_add_test (tc_chain, rtp_klv);
+  tcase_add_test (tc_chain, rtp_klv_fragmented);
+  tcase_add_test (tc_chain, rtp_L16);
+  tcase_add_test (tc_chain, rtp_L24);
+  tcase_add_test (tc_chain, rtp_mp2t);
+  tcase_add_test (tc_chain, rtp_mp4v);
+  tcase_add_test (tc_chain, rtp_mp4v_list);
+  tcase_add_test (tc_chain, rtp_mp4g);
+  tcase_add_test (tc_chain, rtp_theora);
+  tcase_add_test (tc_chain, rtp_vorbis);
+  tcase_add_test (tc_chain, rtp_jpeg);
+  tcase_add_test (tc_chain, rtp_jpeg_width_greater_than_2040);
+  tcase_add_test (tc_chain, rtp_jpeg_height_greater_than_2040);
+  tcase_add_test (tc_chain, rtp_jpeg_width_and_height_greater_than_2040);
+  tcase_add_test (tc_chain, rtp_jpeg_list);
+  tcase_add_test (tc_chain, rtp_jpeg_list_width_greater_than_2040);
+  tcase_add_test (tc_chain, rtp_jpeg_list_height_greater_than_2040);
+  tcase_add_test (tc_chain, rtp_jpeg_list_width_and_height_greater_than_2040);
+  if (gst_registry_check_feature_version (registry, "jpegenc", 1, 0, 0)
+      && gst_registry_check_feature_version (registry, "videotestsrc", 1, 0, 0))
+    tcase_add_loop_test (tc_chain, rtp_jpeg_packet_loss, 0, 7);
+  tcase_add_test (tc_chain, rtp_g729);
+  tcase_add_test (tc_chain, rtp_gst_custom_event);
+  tcase_add_test (tc_chain, rtp_vorbis_renegotiate);
+  return s;
+}
+
+GST_CHECK_MAIN (rtp_payloading)
diff --git a/tests/check/elements/rtpaux.c b/tests/check/elements/rtpaux.c
new file mode 100644
index 0000000..236e276
--- /dev/null
+++ b/tests/check/elements/rtpaux.c
@@ -0,0 +1,418 @@
+/* GStreamer
+ *
+ * Copyright (C) 2013 Collabora Ltd.
+ *   @author Julien Isorce <julien.isorce@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/check/gstconsistencychecker.h>
+#include <gst/check/gsttestclock.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+static gboolean send_pipeline_eos = FALSE;
+static gboolean receive_pipeline_eos = FALSE;
+
+static void
+message_received (GstBus * bus, GstMessage * message, GstPipeline * bin)
+{
+  GST_INFO ("bus message from \"%" GST_PTR_FORMAT "\": %" GST_PTR_FORMAT,
+      GST_MESSAGE_SRC (message), message);
+
+  switch (message->type) {
+    case GST_MESSAGE_EOS:
+      if (!strcmp ("pipeline_send",
+              GST_OBJECT_NAME (GST_MESSAGE_SRC (message))))
+        send_pipeline_eos = TRUE;
+      else if (!strcmp ("pipeline_receive",
+              GST_OBJECT_NAME (GST_MESSAGE_SRC (message))))
+        receive_pipeline_eos = TRUE;
+      else
+        fail ("Unknown pipeline: %s",
+            GST_OBJECT_NAME (GST_MESSAGE_SRC (message)));
+      break;
+    case GST_MESSAGE_WARNING:{
+      GError *gerror;
+      gchar *debug;
+
+      gst_message_parse_warning (message, &gerror, &debug);
+      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+      g_error_free (gerror);
+      g_free (debug);
+      break;
+    }
+    case GST_MESSAGE_ERROR:{
+      GError *gerror;
+      gchar *debug;
+
+      gst_message_parse_error (message, &gerror, &debug);
+      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+      g_error_free (gerror);
+      g_free (debug);
+      fail ("Error!");
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+typedef struct
+{
+  guint count;
+  guint nb_packets;
+  guint drop_every_n_packets;
+} RTXSendData;
+
+static GstPadProbeReturn
+rtprtxsend_srcpad_probe (GstPad * pad, GstPadProbeInfo * info,
+    gpointer user_data)
+{
+  GstPadProbeReturn ret = GST_PAD_PROBE_OK;
+
+  if (info->type == (GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_PUSH)) {
+    GstBuffer *buffer = GST_BUFFER (info->data);
+    RTXSendData *rtxdata = (RTXSendData *) user_data;
+    GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+    guint payload_type = 0;
+
+    gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp);
+    payload_type = gst_rtp_buffer_get_payload_type (&rtp);
+
+    /* main stream packets */
+    if (payload_type == 96) {
+      /* count packets of the main stream */
+      ++rtxdata->nb_packets;
+      /* drop some packets */
+      if (rtxdata->count < rtxdata->drop_every_n_packets) {
+        ++rtxdata->count;
+      } else {
+        /* drop a packet every 'rtxdata->count' packets */
+        rtxdata->count = 1;
+        ret = GST_PAD_PROBE_DROP;
+      }
+    } else {
+      /* retransmission packets */
+    }
+
+    gst_rtp_buffer_unmap (&rtp);
+  }
+
+  return ret;
+}
+
+static void
+on_rtpbinreceive_pad_added (GstElement * element, GstPad * newPad,
+    gpointer data)
+{
+  GstElement *rtpdepayloader = GST_ELEMENT (data);
+
+  gchar *padName = gst_pad_get_name (newPad);
+  if (g_str_has_prefix (padName, "recv_rtp_src_")) {
+    GstPad *sinkpad = gst_element_get_static_pad (rtpdepayloader, "sink");
+    gst_pad_link (newPad, sinkpad);
+    gst_object_unref (sinkpad);
+  }
+  g_free (padName);
+}
+
+static gboolean
+on_timeout (gpointer data)
+{
+  GstEvent *eos = gst_event_new_eos ();
+  if (!gst_element_send_event (GST_ELEMENT (data), eos)) {
+    GST_ERROR ("failed to send end of stream event");
+    gst_event_unref (eos);
+  }
+
+  return FALSE;
+}
+
+static GstElement *
+request_aux_receive (GstElement * rtpbin, guint sessid, GstElement * receive)
+{
+  GstElement *bin;
+  GstPad *pad;
+
+  GST_INFO ("creating AUX receiver");
+  bin = gst_bin_new (NULL);
+  gst_bin_add (GST_BIN (bin), receive);
+
+  pad = gst_element_get_static_pad (receive, "src");
+  gst_element_add_pad (bin, gst_ghost_pad_new ("src_0", pad));
+  gst_object_unref (pad);
+  pad = gst_element_get_static_pad (receive, "sink");
+  gst_element_add_pad (bin, gst_ghost_pad_new ("sink_0", pad));
+  gst_object_unref (pad);
+
+  return bin;
+}
+
+static GstElement *
+request_aux_send (GstElement * rtpbin, guint sessid, GstElement * send)
+{
+  GstElement *bin;
+  GstPad *pad;
+
+  GST_INFO ("creating AUX sender");
+  bin = gst_bin_new (NULL);
+  gst_bin_add (GST_BIN (bin), send);
+
+  pad = gst_element_get_static_pad (send, "src");
+  gst_element_add_pad (bin, gst_ghost_pad_new ("src_0", pad));
+  gst_object_unref (pad);
+  pad = gst_element_get_static_pad (send, "sink");
+  gst_element_add_pad (bin, gst_ghost_pad_new ("sink_0", pad));
+  gst_object_unref (pad);
+
+  return bin;
+}
+
+
+GST_START_TEST (test_simple_rtpbin_aux)
+{
+  GstElement *binsend, *rtpbinsend, *src, *encoder, *rtppayloader,
+      *rtprtxsend, *sendrtp_udpsink, *sendrtcp_udpsink, *sendrtcp_udpsrc;
+  GstElement *binreceive, *rtpbinreceive, *recvrtp_udpsrc, *recvrtcp_udpsrc,
+      *recvrtcp_udpsink, *rtprtxreceive, *rtpdepayloader, *decoder, *converter,
+      *sink;
+  GstBus *bussend;
+  GstBus *busreceive;
+  gboolean res;
+  GstCaps *rtpcaps = NULL;
+  GstStructure *pt_map;
+  GstStateChangeReturn state_res = GST_STATE_CHANGE_FAILURE;
+  GstPad *srcpad = NULL;
+  guint nb_rtx_send_packets = 0;
+  guint nb_rtx_recv_packets = 0;
+  RTXSendData send_rtxdata;
+  send_rtxdata.count = 1;
+  send_rtxdata.nb_packets = 0;
+  send_rtxdata.drop_every_n_packets = 25;
+
+  GST_INFO ("preparing test");
+
+  /* build pipeline */
+  binsend = gst_pipeline_new ("pipeline_send");
+  bussend = gst_element_get_bus (binsend);
+  gst_bus_add_signal_watch_full (bussend, G_PRIORITY_HIGH);
+
+  binreceive = gst_pipeline_new ("pipeline_receive");
+  busreceive = gst_element_get_bus (binreceive);
+  gst_bus_add_signal_watch_full (busreceive, G_PRIORITY_HIGH);
+
+  rtpbinsend = gst_element_factory_make ("rtpbin", "rtpbinsend");
+  g_object_set (rtpbinsend, "latency", 200, "do-retransmission", TRUE, NULL);
+  src = gst_element_factory_make ("audiotestsrc", "src");
+  encoder = gst_element_factory_make ("alawenc", "encoder");
+  rtppayloader = gst_element_factory_make ("rtppcmapay", "rtppayloader");
+  rtprtxsend = gst_element_factory_make ("rtprtxsend", "rtprtxsend");
+  sendrtp_udpsink = gst_element_factory_make ("udpsink", "sendrtp_udpsink");
+  g_object_set (sendrtp_udpsink, "host", "127.0.0.1", NULL);
+  g_object_set (sendrtp_udpsink, "port", 5006, NULL);
+  sendrtcp_udpsink = gst_element_factory_make ("udpsink", "sendrtcp_udpsink");
+  g_object_set (sendrtcp_udpsink, "host", "127.0.0.1", NULL);
+  g_object_set (sendrtcp_udpsink, "port", 5007, NULL);
+  g_object_set (sendrtcp_udpsink, "sync", FALSE, NULL);
+  g_object_set (sendrtcp_udpsink, "async", FALSE, NULL);
+  sendrtcp_udpsrc = gst_element_factory_make ("udpsrc", "sendrtcp_udpsrc");
+  g_object_set (sendrtcp_udpsrc, "port", 5009, NULL);
+
+  rtpbinreceive = gst_element_factory_make ("rtpbin", "rtpbinreceive");
+  g_object_set (rtpbinreceive, "latency", 200, "do-retransmission", TRUE, NULL);
+  recvrtp_udpsrc = gst_element_factory_make ("udpsrc", "recvrtp_udpsrc");
+  g_object_set (recvrtp_udpsrc, "port", 5006, NULL);
+  rtpcaps =
+      gst_caps_from_string
+      ("application/x-rtp,media=(string)audio,clock-rate=(int)8000,encoding-name=(string)PCMA,payload=(int)96");
+  g_object_set (recvrtp_udpsrc, "caps", rtpcaps, NULL);
+  gst_caps_unref (rtpcaps);
+  recvrtcp_udpsrc = gst_element_factory_make ("udpsrc", "recvrtcp_udpsrc");
+  g_object_set (recvrtcp_udpsrc, "port", 5007, NULL);
+  recvrtcp_udpsink = gst_element_factory_make ("udpsink", "recvrtcp_udpsink");
+  g_object_set (recvrtcp_udpsink, "host", "127.0.0.1", NULL);
+  g_object_set (recvrtcp_udpsink, "port", 5009, NULL);
+  g_object_set (recvrtcp_udpsink, "sync", FALSE, NULL);
+  g_object_set (recvrtcp_udpsink, "async", FALSE, NULL);
+  rtprtxreceive = gst_element_factory_make ("rtprtxreceive", "rtprtxreceive");
+  rtpdepayloader = gst_element_factory_make ("rtppcmadepay", "rtpdepayloader");
+  decoder = gst_element_factory_make ("alawdec", "decoder");
+  converter = gst_element_factory_make ("identity", "converter");
+  sink = gst_element_factory_make ("fakesink", "sink");
+  g_object_set (sink, "sync", TRUE, NULL);
+
+  gst_bin_add_many (GST_BIN (binsend), rtpbinsend, src, encoder, rtppayloader,
+      sendrtp_udpsink, sendrtcp_udpsink, sendrtcp_udpsrc, NULL);
+
+  gst_bin_add_many (GST_BIN (binreceive), rtpbinreceive,
+      recvrtp_udpsrc, recvrtcp_udpsrc, recvrtcp_udpsink,
+      rtpdepayloader, decoder, converter, sink, NULL);
+
+  g_signal_connect (rtpbinreceive, "pad-added",
+      G_CALLBACK (on_rtpbinreceive_pad_added), rtpdepayloader);
+
+  pt_map = gst_structure_new ("application/x-rtp-pt-map",
+      "96", G_TYPE_UINT, 99, NULL);
+  g_object_set (rtppayloader, "pt", 96, NULL);
+  g_object_set (rtppayloader, "seqnum-offset", 1, NULL);
+  g_object_set (rtprtxsend, "payload-type-map", pt_map, NULL);
+  g_object_set (rtprtxreceive, "payload-type-map", pt_map, NULL);
+  gst_structure_free (pt_map);
+
+  /* set rtp aux receive */
+  g_signal_connect (rtpbinreceive, "request-aux-receiver", (GCallback)
+      request_aux_receive, rtprtxreceive);
+  /* set rtp aux send */
+  g_signal_connect (rtpbinsend, "request-aux-sender", (GCallback)
+      request_aux_send, rtprtxsend);
+
+  /* gst-launch-1.0 rtpbin name=rtpbin audiotestsrc ! amrnbenc ! rtpamrpay ! \
+   * rtpbin.send_rtp_sink_1 rtpbin.send_rtp_src_1 ! udpsink host="127.0.0.1" \
+   * port=5002 rtpbin.send_rtcp_src_1 ! udpsink host="127.0.0.1" port=5003 \
+   * sync=false async=false  udpsrc port=5007 ! rtpbin.recv_rtcp_sink_1
+   */
+
+  res = gst_element_link (src, encoder);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link (encoder, rtppayloader);
+  fail_unless (res == TRUE, NULL);
+  res =
+      gst_element_link_pads_full (rtppayloader, "src", rtpbinsend,
+      "send_rtp_sink_0", GST_PAD_LINK_CHECK_NOTHING);
+  fail_unless (res == TRUE, NULL);
+  res =
+      gst_element_link_pads_full (rtpbinsend, "send_rtp_src_0", sendrtp_udpsink,
+      "sink", GST_PAD_LINK_CHECK_NOTHING);
+  fail_unless (res == TRUE, NULL);
+  res =
+      gst_element_link_pads_full (rtpbinsend, "send_rtcp_src_0",
+      sendrtcp_udpsink, "sink", GST_PAD_LINK_CHECK_NOTHING);
+  fail_unless (res == TRUE, NULL);
+  res =
+      gst_element_link_pads_full (sendrtcp_udpsrc, "src", rtpbinsend,
+      "recv_rtcp_sink_0", GST_PAD_LINK_CHECK_NOTHING);
+  fail_unless (res == TRUE, NULL);
+
+  srcpad = gst_element_get_static_pad (rtpbinsend, "send_rtp_src_0");
+  gst_pad_add_probe (srcpad,
+      (GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_PUSH),
+      (GstPadProbeCallback) rtprtxsend_srcpad_probe, &send_rtxdata, NULL);
+  gst_object_unref (srcpad);
+
+  /* gst-launch-1.0 rtpbin name=rtpbin udpsrc caps="application/x-rtp,media=(string)audio, \
+   * clock-rate=(int)8000,encoding-name=(string)AMR,encoding-params=(string)1,o
+   * ctet-align=(string)1" port=5002 ! rtpbin.recv_rtp_sink_1 rtpbin. ! rtpamrdepay ! \
+   * amrnbdec ! fakesink sync=True  udpsrc port=5003 ! rtpbin.recv_rtcp_sink_1 \
+   * rtpbin.send_rtcp_src_1 ! udpsink host="127.0.0.1" port=5007 sync=false async=false
+   */
+
+  res =
+      gst_element_link_pads_full (recvrtp_udpsrc, "src", rtpbinreceive,
+      "recv_rtp_sink_0", GST_PAD_LINK_CHECK_NOTHING);
+  fail_unless (res == TRUE, NULL);
+  res =
+      gst_element_link_pads_full (rtpdepayloader, "src", decoder, "sink",
+      GST_PAD_LINK_CHECK_NOTHING);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link (decoder, converter);
+  fail_unless (res == TRUE, NULL);
+  res =
+      gst_element_link_pads_full (converter, "src", sink, "sink",
+      GST_PAD_LINK_CHECK_NOTHING);
+  fail_unless (res == TRUE, NULL);
+  res =
+      gst_element_link_pads_full (recvrtcp_udpsrc, "src", rtpbinreceive,
+      "recv_rtcp_sink_0", GST_PAD_LINK_CHECK_NOTHING);
+  fail_unless (res == TRUE, NULL);
+  res =
+      gst_element_link_pads_full (rtpbinreceive, "send_rtcp_src_0",
+      recvrtcp_udpsink, "sink", GST_PAD_LINK_CHECK_NOTHING);
+  fail_unless (res == TRUE, NULL);
+
+  g_signal_connect (bussend, "message::error", (GCallback) message_received,
+      binsend);
+  g_signal_connect (bussend, "message::warning", (GCallback) message_received,
+      binsend);
+  g_signal_connect (bussend, "message::eos", (GCallback) message_received,
+      binsend);
+
+  g_signal_connect (busreceive, "message::error", (GCallback) message_received,
+      binreceive);
+  g_signal_connect (busreceive, "message::warning",
+      (GCallback) message_received, binreceive);
+  g_signal_connect (busreceive, "message::eos", (GCallback) message_received,
+      binreceive);
+
+  state_res = gst_element_set_state (binreceive, GST_STATE_PLAYING);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  state_res = gst_element_set_state (binsend, GST_STATE_PLAYING);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  g_timeout_add (5000, on_timeout, binsend);
+  g_timeout_add (5000, on_timeout, binreceive);
+
+  GST_INFO ("enter mainloop");
+  while (!send_pipeline_eos && !receive_pipeline_eos)
+    g_main_context_iteration (NULL, TRUE);
+  GST_INFO ("exit mainloop");
+
+  /* check that FB NACK is working */
+  g_object_get (G_OBJECT (rtprtxsend), "num-rtx-requests", &nb_rtx_send_packets,
+      NULL);
+  g_object_get (G_OBJECT (rtprtxreceive), "num-rtx-requests",
+      &nb_rtx_recv_packets, NULL);
+
+  state_res = gst_element_set_state (binsend, GST_STATE_NULL);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  state_res = gst_element_set_state (binreceive, GST_STATE_NULL);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  GST_INFO ("nb_rtx_send_packets %d", nb_rtx_send_packets);
+  GST_INFO ("nb_rtx_recv_packets %d", nb_rtx_recv_packets);
+  fail_if (nb_rtx_send_packets < 1);
+  fail_if (nb_rtx_recv_packets < 1);
+
+  /* cleanup */
+  gst_bus_remove_signal_watch (bussend);
+  gst_object_unref (bussend);
+  gst_object_unref (binsend);
+
+  gst_bus_remove_signal_watch (busreceive);
+  gst_object_unref (busreceive);
+  gst_object_unref (binreceive);
+}
+
+GST_END_TEST;
+
+static Suite *
+rtpaux_suite (void)
+{
+  Suite *s = suite_create ("rtpaux");
+  TCase *tc_chain = tcase_create ("general");
+
+  tcase_set_timeout (tc_chain, 10000);
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_simple_rtpbin_aux);
+
+  return s;
+}
+
+GST_CHECK_MAIN (rtpaux);
diff --git a/tests/check/elements/rtpbin.c b/tests/check/elements/rtpbin.c
new file mode 100644
index 0000000..981cd64
--- /dev/null
+++ b/tests/check/elements/rtpbin.c
@@ -0,0 +1,924 @@
+/* GStreamer
+ *
+ * unit test for gstrtpbin
+ *
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/check/gsttestclock.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/rtp/gstrtcpbuffer.h>
+
+GST_START_TEST (test_pads)
+{
+  GstElement *element;
+  GstPad *pad;
+
+  element = gst_element_factory_make ("rtpsession", NULL);
+
+  pad = gst_element_get_request_pad (element, "recv_rtcp_sink");
+  gst_object_unref (pad);
+  gst_object_unref (element);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_cleanup_send)
+{
+  GstElement *rtpbin;
+  GstPad *rtp_sink, *rtp_src, *rtcp_src;
+  GObject *session;
+  gint count = 2;
+
+  rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
+
+  while (count--) {
+    /* request session 0 */
+    rtp_sink = gst_element_get_request_pad (rtpbin, "send_rtp_sink_0");
+    fail_unless (rtp_sink != NULL);
+    ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
+
+    /* this static pad should be created automatically now */
+    rtp_src = gst_element_get_static_pad (rtpbin, "send_rtp_src_0");
+    fail_unless (rtp_src != NULL);
+    ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 2);
+
+    /* we should be able to get an internal session 0 now */
+    g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
+    fail_unless (session != NULL);
+    g_object_unref (session);
+
+    /* get the send RTCP pad too */
+    rtcp_src = gst_element_get_request_pad (rtpbin, "send_rtcp_src_0");
+    fail_unless (rtcp_src != NULL);
+    ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtcp_src", 2);
+
+    gst_element_release_request_pad (rtpbin, rtp_sink);
+    /* we should only have our refs to the pads now */
+    ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 1);
+    ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 1);
+    ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtp_src", 2);
+
+    /* the other pad should be gone now */
+    fail_unless (gst_element_get_static_pad (rtpbin, "send_rtp_src_0") == NULL);
+
+    /* internal session should still be there */
+    g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
+    fail_unless (session != NULL);
+    g_object_unref (session);
+
+    /* release the RTCP pad */
+    gst_element_release_request_pad (rtpbin, rtcp_src);
+    /* we should only have our refs to the pads now */
+    ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 1);
+    ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 1);
+    ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtp_src", 1);
+
+    /* the session should be gone now */
+    g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
+    fail_unless (session == NULL);
+
+    /* unref the request pad and the static pad */
+    gst_object_unref (rtp_sink);
+    gst_object_unref (rtp_src);
+    gst_object_unref (rtcp_src);
+  }
+
+  gst_object_unref (rtpbin);
+}
+
+GST_END_TEST;
+
+typedef struct
+{
+  guint16 seqnum;
+  gboolean pad_added;
+  GstPad *pad;
+  GMutex lock;
+  GCond cond;
+  GstPad *sinkpad;
+  GList *pads;
+  GstCaps *caps;
+} CleanupData;
+
+static void
+init_data (CleanupData * data)
+{
+  data->seqnum = 10;
+  data->pad_added = FALSE;
+  g_mutex_init (&data->lock);
+  g_cond_init (&data->cond);
+  data->pads = NULL;
+  data->caps = NULL;
+}
+
+static void
+clean_data (CleanupData * data)
+{
+  g_list_foreach (data->pads, (GFunc) gst_object_unref, NULL);
+  g_list_free (data->pads);
+  g_mutex_clear (&data->lock);
+  g_cond_clear (&data->cond);
+  if (data->caps)
+    gst_caps_unref (data->caps);
+}
+
+static guint8 rtp_packet[] = { 0x80, 0x60, 0x94, 0xbc, 0x8f, 0x37, 0x4e, 0xb8,
+  0x44, 0xa8, 0xf3, 0x7c, 0x06, 0x6a, 0x0c, 0xce,
+  0x13, 0x25, 0x19, 0x69, 0x1f, 0x93, 0x25, 0x9d,
+  0x2b, 0x82, 0x31, 0x3b, 0x36, 0xc1, 0x3c, 0x13
+};
+
+static GstFlowReturn
+chain_rtp_packet (GstPad * pad, CleanupData * data)
+{
+  GstFlowReturn res;
+  GstSegment segment;
+  GstBuffer *buffer;
+  GstMapInfo map;
+
+  if (data->caps == NULL) {
+    data->caps = gst_caps_from_string ("application/x-rtp,"
+        "media=(string)audio, clock-rate=(int)44100, "
+        "encoding-name=(string)L16, encoding-params=(string)1, channels=(int)1");
+    data->seqnum = 0;
+  }
+
+  gst_pad_send_event (pad, gst_event_new_stream_start (GST_OBJECT_NAME (pad)));
+  gst_pad_send_event (pad, gst_event_new_caps (data->caps));
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  gst_pad_send_event (pad, gst_event_new_segment (&segment));
+
+  buffer = gst_buffer_new_and_alloc (sizeof (rtp_packet));
+  gst_buffer_map (buffer, &map, GST_MAP_WRITE);
+  memcpy (map.data, rtp_packet, sizeof (rtp_packet));
+
+  map.data[2] = (data->seqnum >> 8) & 0xff;
+  map.data[3] = data->seqnum & 0xff;
+
+  data->seqnum++;
+  gst_buffer_unmap (buffer, &map);
+
+  res = gst_pad_chain (pad, buffer);
+
+  return res;
+}
+
+static GstFlowReturn
+dummy_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  gst_buffer_unref (buffer);
+
+  return GST_FLOW_OK;
+}
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp"));
+
+
+static GstPad *
+make_sinkpad (CleanupData * data)
+{
+  GstPad *pad;
+
+  pad = gst_pad_new_from_static_template (&sink_factory, "sink");
+
+  gst_pad_set_chain_function (pad, dummy_chain);
+  gst_pad_set_active (pad, TRUE);
+
+  data->pads = g_list_prepend (data->pads, pad);
+
+  return pad;
+}
+
+static void
+pad_added_cb (GstElement * rtpbin, GstPad * pad, CleanupData * data)
+{
+  GstPad *sinkpad;
+
+  GST_DEBUG ("pad added %s:%s\n", GST_DEBUG_PAD_NAME (pad));
+
+  if (GST_PAD_IS_SINK (pad))
+    return;
+
+  fail_unless (data->pad_added == FALSE);
+
+  sinkpad = make_sinkpad (data);
+  fail_unless (gst_pad_link (pad, sinkpad) == GST_PAD_LINK_OK);
+
+  g_mutex_lock (&data->lock);
+  data->pad_added = TRUE;
+  data->pad = pad;
+  g_cond_signal (&data->cond);
+  g_mutex_unlock (&data->lock);
+}
+
+static void
+pad_removed_cb (GstElement * rtpbin, GstPad * pad, CleanupData * data)
+{
+  GST_DEBUG ("pad removed %s:%s\n", GST_DEBUG_PAD_NAME (pad));
+
+  if (data->pad != pad)
+    return;
+
+  fail_unless (data->pad_added == TRUE);
+
+  g_mutex_lock (&data->lock);
+  data->pad_added = FALSE;
+  g_cond_signal (&data->cond);
+  g_mutex_unlock (&data->lock);
+}
+
+GST_START_TEST (test_cleanup_recv)
+{
+  GstElement *rtpbin;
+  GstPad *rtp_sink;
+  CleanupData data;
+  GstStateChangeReturn ret;
+  GstFlowReturn res;
+  gint count = 2;
+
+  init_data (&data);
+
+  rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
+
+  g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added_cb, &data);
+  g_signal_connect (rtpbin, "pad-removed", (GCallback) pad_removed_cb, &data);
+
+  ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
+  fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
+
+  while (count--) {
+    /* request session 0 */
+    rtp_sink = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_0");
+    fail_unless (rtp_sink != NULL);
+    ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
+
+    /* no sourcepads are created yet */
+    fail_unless (rtpbin->numsinkpads == 1);
+    fail_unless (rtpbin->numsrcpads == 0);
+
+    res = chain_rtp_packet (rtp_sink, &data);
+    GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
+    fail_unless (res == GST_FLOW_OK);
+
+    res = chain_rtp_packet (rtp_sink, &data);
+    GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
+    fail_unless (res == GST_FLOW_OK);
+
+    /* we wait for the new pad to appear now */
+    g_mutex_lock (&data.lock);
+    while (!data.pad_added)
+      g_cond_wait (&data.cond, &data.lock);
+    g_mutex_unlock (&data.lock);
+
+    /* sourcepad created now */
+    fail_unless (rtpbin->numsinkpads == 1);
+    fail_unless (rtpbin->numsrcpads == 1);
+
+    /* remove the session */
+    gst_element_release_request_pad (rtpbin, rtp_sink);
+    gst_object_unref (rtp_sink);
+
+    /* pad should be gone now */
+    g_mutex_lock (&data.lock);
+    while (data.pad_added)
+      g_cond_wait (&data.cond, &data.lock);
+    g_mutex_unlock (&data.lock);
+
+    /* nothing left anymore now */
+    fail_unless (rtpbin->numsinkpads == 0);
+    fail_unless (rtpbin->numsrcpads == 0);
+  }
+
+  ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
+  fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
+
+  gst_object_unref (rtpbin);
+
+  clean_data (&data);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_cleanup_recv2)
+{
+  GstElement *rtpbin;
+  GstPad *rtp_sink;
+  CleanupData data;
+  GstStateChangeReturn ret;
+  GstFlowReturn res;
+  gint count = 2;
+
+  init_data (&data);
+
+  rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
+
+  g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added_cb, &data);
+  g_signal_connect (rtpbin, "pad-removed", (GCallback) pad_removed_cb, &data);
+
+  ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
+  fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
+
+  /* request session 0 */
+  rtp_sink = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_0");
+  fail_unless (rtp_sink != NULL);
+  ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
+
+  while (count--) {
+    /* no sourcepads are created yet */
+    fail_unless (rtpbin->numsinkpads == 1);
+    fail_unless (rtpbin->numsrcpads == 0);
+
+    res = chain_rtp_packet (rtp_sink, &data);
+    GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
+    fail_unless (res == GST_FLOW_OK);
+
+    res = chain_rtp_packet (rtp_sink, &data);
+    GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
+    fail_unless (res == GST_FLOW_OK);
+
+    /* we wait for the new pad to appear now */
+    g_mutex_lock (&data.lock);
+    while (!data.pad_added)
+      g_cond_wait (&data.cond, &data.lock);
+    g_mutex_unlock (&data.lock);
+
+    /* sourcepad created now */
+    fail_unless (rtpbin->numsinkpads == 1);
+    fail_unless (rtpbin->numsrcpads == 1);
+
+    /* change state */
+    ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
+    fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
+
+    /* pad should be gone now */
+    g_mutex_lock (&data.lock);
+    while (data.pad_added)
+      g_cond_wait (&data.cond, &data.lock);
+    g_mutex_unlock (&data.lock);
+
+    /* back to playing for the next round */
+    ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
+    fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
+  }
+
+  /* remove the session */
+  gst_element_release_request_pad (rtpbin, rtp_sink);
+  gst_object_unref (rtp_sink);
+
+  /* nothing left anymore now */
+  fail_unless (rtpbin->numsinkpads == 0);
+  fail_unless (rtpbin->numsrcpads == 0);
+
+  ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
+  fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
+
+  gst_object_unref (rtpbin);
+
+  clean_data (&data);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_request_pad_by_template_name)
+{
+  GstElement *rtpbin;
+  GstPad *rtp_sink1, *rtp_sink2, *rtp_sink3;
+
+  rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
+  rtp_sink1 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%u");
+  fail_unless (rtp_sink1 != NULL);
+  fail_unless_equals_string (GST_PAD_NAME (rtp_sink1), "recv_rtp_sink_0");
+  ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink1", 2);
+
+  rtp_sink2 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%u");
+  fail_unless (rtp_sink2 != NULL);
+  fail_unless_equals_string (GST_PAD_NAME (rtp_sink2), "recv_rtp_sink_1");
+  ASSERT_OBJECT_REFCOUNT (rtp_sink2, "rtp_sink2", 2);
+
+  rtp_sink3 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%u");
+  fail_unless (rtp_sink3 != NULL);
+  fail_unless_equals_string (GST_PAD_NAME (rtp_sink3), "recv_rtp_sink_2");
+  ASSERT_OBJECT_REFCOUNT (rtp_sink3, "rtp_sink3", 2);
+
+
+  gst_element_release_request_pad (rtpbin, rtp_sink2);
+  gst_element_release_request_pad (rtpbin, rtp_sink1);
+  gst_element_release_request_pad (rtpbin, rtp_sink3);
+  ASSERT_OBJECT_REFCOUNT (rtp_sink3, "rtp_sink3", 1);
+  ASSERT_OBJECT_REFCOUNT (rtp_sink2, "rtp_sink2", 1);
+  ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink", 1);
+  gst_object_unref (rtp_sink1);
+  gst_object_unref (rtp_sink2);
+  gst_object_unref (rtp_sink3);
+
+  gst_object_unref (rtpbin);
+}
+
+GST_END_TEST;
+
+static GstElement *
+encoder_cb (GstElement * rtpbin, guint sessid, GstElement * bin)
+{
+  GstPad *srcpad, *sinkpad;
+
+  fail_unless (sessid == 2);
+
+  GST_DEBUG ("making encoder");
+  sinkpad = gst_ghost_pad_new_no_target ("rtp_sink_2", GST_PAD_SINK);
+  srcpad = gst_ghost_pad_new_no_target ("rtp_src_2", GST_PAD_SRC);
+
+  gst_element_add_pad (bin, sinkpad);
+  gst_element_add_pad (bin, srcpad);
+
+  return gst_object_ref (bin);
+}
+
+static GstElement *
+encoder_cb2 (GstElement * rtpbin, guint sessid, GstElement * bin)
+{
+  GstPad *srcpad, *sinkpad;
+
+  fail_unless (sessid == 3);
+
+  GST_DEBUG ("making encoder");
+  sinkpad = gst_ghost_pad_new_no_target ("rtp_sink_3", GST_PAD_SINK);
+  srcpad = gst_ghost_pad_new_no_target ("rtp_src_3", GST_PAD_SRC);
+
+  gst_element_add_pad (bin, sinkpad);
+  gst_element_add_pad (bin, srcpad);
+
+  return gst_object_ref (bin);
+}
+
+GST_START_TEST (test_encoder)
+{
+  GstElement *rtpbin, *bin;
+  GstPad *rtp_sink1, *rtp_sink2;
+  gulong id;
+
+  bin = gst_bin_new ("rtpenc");
+
+  rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
+
+  id = g_signal_connect (rtpbin, "request-rtp-encoder", (GCallback) encoder_cb,
+      bin);
+
+  rtp_sink1 = gst_element_get_request_pad (rtpbin, "send_rtp_sink_2");
+  fail_unless (rtp_sink1 != NULL);
+  fail_unless_equals_string (GST_PAD_NAME (rtp_sink1), "send_rtp_sink_2");
+  ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink1", 2);
+
+  g_signal_handler_disconnect (rtpbin, id);
+
+  id = g_signal_connect (rtpbin, "request-rtp-encoder", (GCallback) encoder_cb2,
+      bin);
+
+  rtp_sink2 = gst_element_get_request_pad (rtpbin, "send_rtp_sink_3");
+  fail_unless (rtp_sink2 != NULL);
+
+  /* remove the session */
+  gst_element_release_request_pad (rtpbin, rtp_sink1);
+  gst_object_unref (rtp_sink1);
+
+  gst_element_release_request_pad (rtpbin, rtp_sink2);
+  gst_object_unref (rtp_sink2);
+
+  /* nothing left anymore now */
+  fail_unless (rtpbin->numsinkpads == 0);
+  fail_unless (rtpbin->numsrcpads == 0);
+
+  gst_object_unref (rtpbin);
+  gst_object_unref (bin);
+}
+
+GST_END_TEST;
+
+static GstElement *
+decoder_cb (GstElement * rtpbin, guint sessid, gpointer user_data)
+{
+  GstElement *bin;
+  GstPad *srcpad, *sinkpad;
+
+  bin = gst_bin_new (NULL);
+
+  GST_DEBUG ("making decoder");
+  sinkpad = gst_ghost_pad_new_no_target ("rtp_sink", GST_PAD_SINK);
+  srcpad = gst_ghost_pad_new_no_target ("rtp_src", GST_PAD_SRC);
+
+  gst_element_add_pad (bin, sinkpad);
+  gst_element_add_pad (bin, srcpad);
+
+  return bin;
+}
+
+GST_START_TEST (test_decoder)
+{
+  GstElement *rtpbin;
+  GstPad *rtp_sink1, *rtp_sink2;
+  gulong id;
+
+
+  rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
+
+  id = g_signal_connect (rtpbin, "request-rtp-decoder", (GCallback) decoder_cb,
+      NULL);
+
+  rtp_sink1 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_2");
+  fail_unless (rtp_sink1 != NULL);
+  fail_unless_equals_string (GST_PAD_NAME (rtp_sink1), "recv_rtp_sink_2");
+  ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink1", 2);
+
+  rtp_sink2 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_3");
+  fail_unless (rtp_sink2 != NULL);
+
+  g_signal_handler_disconnect (rtpbin, id);
+
+  /* remove the session */
+  gst_element_release_request_pad (rtpbin, rtp_sink1);
+  gst_object_unref (rtp_sink1);
+
+  gst_element_release_request_pad (rtpbin, rtp_sink2);
+  gst_object_unref (rtp_sink2);
+
+  /* nothing left anymore now */
+  fail_unless (rtpbin->numsinkpads == 0);
+  fail_unless (rtpbin->numsrcpads == 0);
+
+  gst_object_unref (rtpbin);
+}
+
+GST_END_TEST;
+
+static GstElement *
+aux_sender_cb (GstElement * rtpbin, guint sessid, gpointer user_data)
+{
+  GstElement *bin;
+  GstPad *srcpad, *sinkpad;
+
+  bin = (GstElement *) user_data;
+
+  GST_DEBUG ("making AUX sender");
+  sinkpad = gst_ghost_pad_new_no_target ("sink_2", GST_PAD_SINK);
+  gst_element_add_pad (bin, sinkpad);
+
+  srcpad = gst_ghost_pad_new_no_target ("src_2", GST_PAD_SRC);
+  gst_element_add_pad (bin, srcpad);
+  srcpad = gst_ghost_pad_new_no_target ("src_1", GST_PAD_SRC);
+  gst_element_add_pad (bin, srcpad);
+  srcpad = gst_ghost_pad_new_no_target ("src_3", GST_PAD_SRC);
+  gst_element_add_pad (bin, srcpad);
+
+  return bin;
+}
+
+GST_START_TEST (test_aux_sender)
+{
+  GstElement *rtpbin;
+  GstPad *rtp_sink1, *rtp_src, *rtcp_src;
+  gulong id;
+  GstElement *aux_sender = gst_object_ref_sink (gst_bin_new ("aux-sender"));
+
+  gst_object_ref (aux_sender);
+
+  rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
+
+  id = g_signal_connect (rtpbin, "request-aux-sender",
+      (GCallback) aux_sender_cb, aux_sender);
+
+  rtp_sink1 = gst_element_get_request_pad (rtpbin, "send_rtp_sink_2");
+  fail_unless (rtp_sink1 != NULL);
+  fail_unless_equals_string (GST_PAD_NAME (rtp_sink1), "send_rtp_sink_2");
+  ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink1", 2);
+
+  g_signal_handler_disconnect (rtpbin, id);
+
+  rtp_src = gst_element_get_static_pad (rtpbin, "send_rtp_src_2");
+  fail_unless (rtp_src != NULL);
+  gst_object_unref (rtp_src);
+
+  rtp_src = gst_element_get_static_pad (rtpbin, "send_rtp_src_1");
+  fail_unless (rtp_src != NULL);
+  gst_object_unref (rtp_src);
+
+  rtcp_src = gst_element_get_request_pad (rtpbin, "send_rtcp_src_1");
+  fail_unless (rtcp_src != NULL);
+  gst_element_release_request_pad (rtpbin, rtcp_src);
+  gst_object_unref (rtcp_src);
+
+  rtp_src = gst_element_get_static_pad (rtpbin, "send_rtp_src_3");
+  fail_unless (rtp_src != NULL);
+  gst_object_unref (rtp_src);
+
+  /* remove the session */
+  gst_element_release_request_pad (rtpbin, rtp_sink1);
+  gst_object_unref (rtp_sink1);
+
+  /* We have sinked the initial reference before returning it
+   * in the request callback, the ref count should now be 1 because
+   * the return of the signal is transfer full, and rtpbin should
+   * have released that reference by now, but we had taken an
+   * extra reference to perform this check
+   */
+  ASSERT_OBJECT_REFCOUNT (aux_sender, "aux-sender", 1);
+
+  gst_object_unref (aux_sender);
+  gst_object_unref (rtpbin);
+}
+
+GST_END_TEST;
+
+static GstElement *
+aux_receiver_cb (GstElement * rtpbin, guint sessid, gpointer user_data)
+{
+  GstElement *bin;
+  GstPad *srcpad, *sinkpad;
+
+  bin = gst_bin_new (NULL);
+
+  GST_DEBUG ("making AUX receiver");
+  srcpad = gst_ghost_pad_new_no_target ("src_2", GST_PAD_SRC);
+  gst_element_add_pad (bin, srcpad);
+
+  sinkpad = gst_ghost_pad_new_no_target ("sink_2", GST_PAD_SINK);
+  gst_element_add_pad (bin, sinkpad);
+  sinkpad = gst_ghost_pad_new_no_target ("sink_1", GST_PAD_SINK);
+  gst_element_add_pad (bin, sinkpad);
+  sinkpad = gst_ghost_pad_new_no_target ("sink_3", GST_PAD_SINK);
+  gst_element_add_pad (bin, sinkpad);
+
+  return bin;
+}
+
+GST_START_TEST (test_aux_receiver)
+{
+  GstElement *rtpbin;
+  GstPad *rtp_sink1, *rtp_sink2, *rtcp_sink;
+  gulong id;
+
+  rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
+
+  id = g_signal_connect (rtpbin, "request-aux-receiver",
+      (GCallback) aux_receiver_cb, NULL);
+
+  rtp_sink1 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_2");
+  fail_unless (rtp_sink1 != NULL);
+
+  rtp_sink2 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_1");
+  fail_unless (rtp_sink2 != NULL);
+
+  g_signal_handler_disconnect (rtpbin, id);
+
+  rtcp_sink = gst_element_get_request_pad (rtpbin, "recv_rtcp_sink_1");
+  fail_unless (rtcp_sink != NULL);
+  gst_element_release_request_pad (rtpbin, rtcp_sink);
+  gst_object_unref (rtcp_sink);
+
+  /* remove the session */
+  gst_element_release_request_pad (rtpbin, rtp_sink1);
+  gst_object_unref (rtp_sink1);
+  gst_element_release_request_pad (rtpbin, rtp_sink2);
+  gst_object_unref (rtp_sink2);
+
+  gst_object_unref (rtpbin);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_sender_eos)
+{
+  GstElement *rtpsession;
+  GstBuffer *rtp_buffer;
+  GstBuffer *rtcp_buffer;
+  GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT;
+  GstRTCPBuffer rtcpbuf = GST_RTCP_BUFFER_INIT;
+  GstRTCPPacket rtcppacket;
+  static GstStaticPadTemplate recv_tmpl =
+      GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+      GST_STATIC_CAPS ("ANY"));
+  GstPad *send_rtp_sink;
+  GstPad *recv_rtcp_sink;
+  GstCaps *caps;
+  GstSegment segment;
+  GstPad *rtp_sink, *rtcp_sink;
+  GstClock *clock;
+  GstTestClock *tclock;
+  GstStructure *s;
+  guint ssrc = 1;
+  guint32 ssrc_in, packet_count, octet_count;
+  gboolean got_bye = FALSE;
+
+  clock = gst_test_clock_new ();
+  gst_system_clock_set_default (clock);
+  tclock = GST_TEST_CLOCK (clock);
+  gst_test_clock_set_time (tclock, 0);
+
+  rtpsession = gst_element_factory_make ("rtpsession", NULL);
+  send_rtp_sink = gst_element_get_request_pad (rtpsession, "send_rtp_sink");
+  recv_rtcp_sink = gst_element_get_request_pad (rtpsession, "recv_rtcp_sink");
+
+
+  rtp_sink = gst_check_setup_sink_pad_by_name (rtpsession, &recv_tmpl,
+      "send_rtp_src");
+  rtcp_sink = gst_check_setup_sink_pad_by_name (rtpsession, &recv_tmpl,
+      "send_rtcp_src");
+
+  gst_pad_set_active (rtp_sink, TRUE);
+  gst_pad_set_active (rtcp_sink, TRUE);
+
+  gst_element_set_state (rtpsession, GST_STATE_PLAYING);
+
+  /* Send initial events */
+
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_send_event (send_rtp_sink,
+          gst_event_new_stream_start ("id")));
+  fail_unless (gst_pad_send_event (send_rtp_sink,
+          gst_event_new_segment (&segment)));
+
+  fail_unless (gst_pad_send_event (recv_rtcp_sink,
+          gst_event_new_stream_start ("id")));
+  fail_unless (gst_pad_send_event (recv_rtcp_sink,
+          gst_event_new_segment (&segment)));
+
+  /* Get the suggested SSRC from the rtpsession */
+
+  caps = gst_pad_query_caps (send_rtp_sink, NULL);
+  s = gst_caps_get_structure (caps, 0);
+  gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL);
+  gst_caps_unref (caps);
+
+  /* Send a RTP packet */
+
+  rtp_buffer = gst_rtp_buffer_new_allocate (10, 0, 0);
+  gst_rtp_buffer_map (rtp_buffer, GST_MAP_READWRITE, &rtpbuf);
+  gst_rtp_buffer_set_ssrc (&rtpbuf, 1);
+  gst_rtp_buffer_set_seq (&rtpbuf, 0);
+  gst_rtp_buffer_unmap (&rtpbuf);
+
+  fail_unless (gst_pad_chain (send_rtp_sink, rtp_buffer) == GST_FLOW_OK);
+
+  /* Make sure it went through */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_unless_equals_pointer (buffers->data, rtp_buffer);
+  gst_check_drop_buffers ();
+
+  /* Advance time and send a packet to prevent source sender timeout */
+  gst_test_clock_set_time (tclock, 1 * GST_SECOND);
+
+  /* Just send a send packet to prevent timeout */
+  rtp_buffer = gst_rtp_buffer_new_allocate (10, 0, 0);
+  gst_rtp_buffer_map (rtp_buffer, GST_MAP_READWRITE, &rtpbuf);
+  gst_rtp_buffer_set_ssrc (&rtpbuf, 1);
+  gst_rtp_buffer_set_seq (&rtpbuf, 1);
+  gst_rtp_buffer_set_timestamp (&rtpbuf, 10);
+  gst_rtp_buffer_unmap (&rtpbuf);
+
+  fail_unless (gst_pad_chain (send_rtp_sink, rtp_buffer) == GST_FLOW_OK);
+
+  /* Make sure it went through */
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_unless_equals_pointer (buffers->data, rtp_buffer);
+  gst_check_drop_buffers ();
+
+  /* Advance clock twice and we shoudl have one RTCP packet at least */
+  gst_test_clock_crank (tclock);
+  gst_test_clock_crank (tclock);
+
+  g_mutex_lock (&check_mutex);
+  while (buffers == NULL)
+    g_cond_wait (&check_cond, &check_mutex);
+
+  fail_unless (gst_rtcp_buffer_map (buffers->data, GST_MAP_READ, &rtcpbuf));
+
+  fail_unless (gst_rtcp_buffer_get_first_packet (&rtcpbuf, &rtcppacket));
+
+  fail_unless_equals_int (gst_rtcp_packet_get_type (&rtcppacket),
+      GST_RTCP_TYPE_SR);
+  gst_rtcp_packet_sr_get_sender_info (&rtcppacket, &ssrc_in, NULL, NULL,
+      &packet_count, &octet_count);
+  fail_unless_equals_int (packet_count, 2);
+  fail_unless_equals_int (octet_count, 20);
+
+  fail_unless (gst_rtcp_packet_move_to_next (&rtcppacket));
+  fail_unless_equals_int (gst_rtcp_packet_get_type (&rtcppacket),
+      GST_RTCP_TYPE_SDES);
+
+  gst_rtcp_buffer_unmap (&rtcpbuf);
+  gst_check_drop_buffers ();
+
+  g_mutex_unlock (&check_mutex);
+
+
+  /* Create and send a valid RTCP reply packet */
+  rtcp_buffer = gst_rtcp_buffer_new (1500);
+  gst_rtcp_buffer_map (rtcp_buffer, GST_MAP_READWRITE, &rtcpbuf);
+  gst_rtcp_buffer_add_packet (&rtcpbuf, GST_RTCP_TYPE_RR, &rtcppacket);
+  gst_rtcp_packet_rr_set_ssrc (&rtcppacket, ssrc + 1);
+  gst_rtcp_packet_add_rb (&rtcppacket, ssrc, 0, 0, 0, 0, 0, 0);
+  gst_rtcp_buffer_add_packet (&rtcpbuf, GST_RTCP_TYPE_SDES, &rtcppacket);
+  gst_rtcp_packet_sdes_add_item (&rtcppacket, ssrc + 1);
+  gst_rtcp_packet_sdes_add_entry (&rtcppacket, GST_RTCP_SDES_CNAME, 3,
+      (guint8 *) "a@a");
+  gst_rtcp_packet_sdes_add_entry (&rtcppacket, GST_RTCP_SDES_NAME, 2,
+      (guint8 *) "aa");
+  gst_rtcp_packet_sdes_add_entry (&rtcppacket, GST_RTCP_SDES_END, 0,
+      (guint8 *) "");
+  gst_rtcp_buffer_unmap (&rtcpbuf);
+  fail_unless (gst_pad_chain (recv_rtcp_sink, rtcp_buffer) == GST_FLOW_OK);
+
+
+  /* Send a EOS to trigger sending a BYE message */
+  fail_unless (gst_pad_send_event (send_rtp_sink, gst_event_new_eos ()));
+
+  /* Crank to process EOS and wait for BYE */
+  for (;;) {
+    gst_test_clock_crank (tclock);
+    g_mutex_lock (&check_mutex);
+    while (buffers == NULL)
+      g_cond_wait (&check_cond, &check_mutex);
+
+    fail_unless (gst_rtcp_buffer_map (g_list_last (buffers)->data, GST_MAP_READ,
+            &rtcpbuf));
+    fail_unless (gst_rtcp_buffer_get_first_packet (&rtcpbuf, &rtcppacket));
+
+    while (gst_rtcp_packet_move_to_next (&rtcppacket)) {
+      if (gst_rtcp_packet_get_type (&rtcppacket) == GST_RTCP_TYPE_BYE) {
+        got_bye = TRUE;
+        break;
+      }
+    }
+    g_mutex_unlock (&check_mutex);
+    gst_rtcp_buffer_unmap (&rtcpbuf);
+
+    if (got_bye)
+      break;
+  }
+
+  gst_check_drop_buffers ();
+
+
+  fail_unless (GST_PAD_IS_EOS (rtp_sink));
+  fail_unless (GST_PAD_IS_EOS (rtcp_sink));
+
+  gst_pad_set_active (rtp_sink, FALSE);
+  gst_pad_set_active (rtcp_sink, FALSE);
+
+  gst_check_teardown_pad_by_name (rtpsession, "send_rtp_src");
+  gst_check_teardown_pad_by_name (rtpsession, "send_rtcp_src");
+  gst_element_release_request_pad (rtpsession, send_rtp_sink);
+  gst_object_unref (send_rtp_sink);
+  gst_element_release_request_pad (rtpsession, recv_rtcp_sink);
+  gst_object_unref (recv_rtcp_sink);
+
+  gst_check_teardown_element (rtpsession);
+
+  gst_system_clock_set_default (NULL);
+  gst_object_unref (clock);
+
+}
+
+GST_END_TEST;
+
+static Suite *
+rtpbin_suite (void)
+{
+  Suite *s = suite_create ("rtpbin");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_pads);
+  tcase_add_test (tc_chain, test_cleanup_send);
+  tcase_add_test (tc_chain, test_cleanup_recv);
+  tcase_add_test (tc_chain, test_cleanup_recv2);
+  tcase_add_test (tc_chain, test_request_pad_by_template_name);
+  tcase_add_test (tc_chain, test_encoder);
+  tcase_add_test (tc_chain, test_decoder);
+  tcase_add_test (tc_chain, test_aux_sender);
+  tcase_add_test (tc_chain, test_aux_receiver);
+  tcase_add_test (tc_chain, test_sender_eos);
+
+  return s;
+}
+
+GST_CHECK_MAIN (rtpbin);
diff --git a/tests/check/elements/rtpbin_buffer_list.c b/tests/check/elements/rtpbin_buffer_list.c
new file mode 100644
index 0000000..b6a7793
--- /dev/null
+++ b/tests/check/elements/rtpbin_buffer_list.c
@@ -0,0 +1,335 @@
+/* GStreamer
+ *
+ * Unit test for gstrtpbin sending rtp packets using GstBufferList.
+ * Copyright (C) 2009 Branko Subasic <branko dot subasic at axis dot com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+
+#if 0
+
+/* This test makes sure that RTP packets sent as buffer lists are sent through
+ * the rtpbin as they are supposed to, and not corrupted in any way.
+ */
+
+
+#define TEST_CAPS \
+  "application/x-rtp, "                \
+  "media=(string)video, "              \
+  "clock-rate=(int)90000, "            \
+  "encoding-name=(string)H264, "       \
+  "profile-level-id=(string)4d4015, "  \
+  "payload=(int)96, "                  \
+  "ssrc=(guint)2633237432, "           \
+  "clock-base=(guint)1868267015, "     \
+  "seqnum-base=(guint)54229"
+
+
+/* RTP headers and the first 2 bytes of the payload (FU indicator and FU header)
+ */
+static const guint8 rtp_header[2][14] = {
+  {0x80, 0x60, 0xbb, 0xb7, 0x5c, 0xe9, 0x09,
+      0x0d, 0xf5, 0x9c, 0x43, 0x55, 0x1c, 0x86},
+  {0x80, 0x60, 0xbb, 0xb8, 0x5c, 0xe9, 0x09,
+      0x0d, 0xf5, 0x9c, 0x43, 0x55, 0x1c, 0x46}
+};
+
+static const guint rtp_header_len[] = {
+  sizeof rtp_header[0],
+  sizeof rtp_header[1]
+};
+
+static GstBuffer *header_buffer[2] = { NULL, NULL };
+
+
+/* Some payload.
+ */
+static const char *payload =
+    "0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
+    "0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
+    "0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
+    "0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
+    "0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
+    "0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
+    "0123456789ABSDEF0123456";
+
+static const guint payload_offset[] = {
+  0, 498
+};
+
+static const guint payload_len[] = {
+  498, 5
+};
+
+
+static GstBuffer *original_buffer = NULL;
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp"));
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp"));
+
+
+static GstBuffer *
+_create_original_buffer (void)
+{
+  GstCaps *caps;
+
+  if (original_buffer != NULL)
+    return original_buffer;
+
+  original_buffer = gst_buffer_new ();
+  fail_unless (original_buffer != NULL);
+
+  gst_buffer_set_data (original_buffer, (guint8 *) payload, strlen (payload));
+  GST_BUFFER_TIMESTAMP (original_buffer) =
+      gst_clock_get_internal_time (gst_system_clock_obtain ());
+
+  caps = gst_caps_from_string (TEST_CAPS);
+  fail_unless (caps != NULL);
+  gst_buffer_set_caps (original_buffer, caps);
+  gst_caps_unref (caps);
+
+  return original_buffer;
+}
+
+static GstBufferList *
+_create_buffer_list (void)
+{
+  GstBufferList *list;
+  GstBufferListIterator *it;
+  GstBuffer *orig_buffer;
+  GstBuffer *buffer;
+
+  orig_buffer = _create_original_buffer ();
+  fail_if (orig_buffer == NULL);
+
+  list = gst_buffer_list_new ();
+  fail_if (list == NULL);
+
+  it = gst_buffer_list_iterate (list);
+  fail_if (it == NULL);
+
+  /*** First group, i.e. first packet. **/
+  gst_buffer_list_iterator_add_group (it);
+
+  /* Create buffer with RTP header and add it to the 1st group */
+  buffer = gst_buffer_new ();
+  GST_BUFFER_MALLOCDATA (buffer) = g_memdup (&rtp_header[0], rtp_header_len[0]);
+  GST_BUFFER_DATA (buffer) = GST_BUFFER_MALLOCDATA (buffer);
+  GST_BUFFER_SIZE (buffer) = rtp_header_len[0];
+  gst_buffer_copy_metadata (buffer, orig_buffer, GST_BUFFER_COPY_ALL);
+  header_buffer[0] = buffer;
+  gst_buffer_list_iterator_add (it, buffer);
+
+  /* Create the payload buffer and add it to the 1st group
+   */
+  buffer =
+      gst_buffer_create_sub (orig_buffer, payload_offset[0], payload_len[0]);
+  fail_if (buffer == NULL);
+  gst_buffer_list_iterator_add (it, buffer);
+
+
+  /***  Second group, i.e. second packet. ***/
+
+  /* Create a new group to hold the rtp header and the payload */
+  gst_buffer_list_iterator_add_group (it);
+
+  /* Create buffer with RTP header and add it to the 2nd group */
+  buffer = gst_buffer_new ();
+  GST_BUFFER_MALLOCDATA (buffer) = g_memdup (&rtp_header[1], rtp_header_len[1]);
+  GST_BUFFER_DATA (buffer) = GST_BUFFER_MALLOCDATA (buffer);
+  GST_BUFFER_SIZE (buffer) = rtp_header_len[1];
+  gst_buffer_copy_metadata (buffer, orig_buffer, GST_BUFFER_COPY_ALL);
+  header_buffer[1] = buffer;
+
+  /* Add the rtp header to the buffer list */
+  gst_buffer_list_iterator_add (it, buffer);
+
+  /* Create the payload buffer and add it to the 2d group
+   */
+  buffer =
+      gst_buffer_create_sub (orig_buffer, payload_offset[1], payload_len[1]);
+  fail_if (buffer == NULL);
+  gst_buffer_list_iterator_add (it, buffer);
+
+  gst_buffer_list_iterator_free (it);
+
+  return list;
+}
+
+
+static void
+_check_header (GstBuffer * buffer, guint index)
+{
+  guint8 *data;
+
+  fail_if (buffer == NULL);
+  fail_unless (index < 2);
+
+  fail_unless (GST_BUFFER_SIZE (buffer) == rtp_header_len[index]);
+
+  /* Can't do a memcmp() on the whole header, cause the SSRC (bytes 8-11) will
+   * most likely be changed in gstrtpbin.
+   */
+  fail_unless ((data = GST_BUFFER_DATA (buffer)) != NULL);
+  fail_unless_equals_uint64 (*(guint64 *) data, *(guint64 *) rtp_header[index]);
+  fail_unless (*(guint16 *) (data + 12) ==
+      *(guint16 *) (rtp_header[index] + 12));
+}
+
+
+static void
+_check_payload (GstBuffer * buffer, guint index)
+{
+  fail_if (buffer == NULL);
+  fail_unless (index < 2);
+
+  fail_unless (GST_BUFFER_SIZE (buffer) == payload_len[index]);
+  fail_if (GST_BUFFER_DATA (buffer) !=
+      (gpointer) (payload + payload_offset[index]));
+  fail_if (memcmp (GST_BUFFER_DATA (buffer), payload + payload_offset[index],
+          payload_len[index]));
+}
+
+
+static void
+_check_group (GstBufferListIterator * it, guint index, GstCaps * caps)
+{
+  GstBuffer *buffer;
+
+  fail_unless (it != NULL);
+  fail_unless (gst_buffer_list_iterator_n_buffers (it) == 2);
+  fail_unless (caps != NULL);
+
+  fail_unless ((buffer = gst_buffer_list_iterator_next (it)) != NULL);
+
+  fail_unless (GST_BUFFER_TIMESTAMP (buffer) ==
+      GST_BUFFER_TIMESTAMP (original_buffer));
+
+  fail_unless (gst_caps_is_equal (GST_BUFFER_CAPS (original_buffer),
+          GST_BUFFER_CAPS (buffer)));
+
+  _check_header (buffer, index);
+
+  fail_unless ((buffer = gst_buffer_list_iterator_next (it)) != NULL);
+  _check_payload (buffer, index);
+}
+
+
+static GstFlowReturn
+_sink_chain_list (GstPad * pad, GstBufferList * list)
+{
+  GstCaps *caps;
+  GstBufferListIterator *it;
+
+  caps = gst_caps_from_string (TEST_CAPS);
+  fail_unless (caps != NULL);
+
+  fail_unless (GST_IS_BUFFER_LIST (list));
+  fail_unless (gst_buffer_list_n_groups (list) == 2);
+
+  it = gst_buffer_list_iterate (list);
+  fail_if (it == NULL);
+
+  fail_unless (gst_buffer_list_iterator_next_group (it));
+  _check_group (it, 0, caps);
+
+  fail_unless (gst_buffer_list_iterator_next_group (it));
+  _check_group (it, 1, caps);
+
+  gst_caps_unref (caps);
+  gst_buffer_list_iterator_free (it);
+
+  gst_buffer_list_unref (list);
+
+  return GST_FLOW_OK;
+}
+
+
+static void
+_set_chain_functions (GstPad * pad)
+{
+  gst_pad_set_chain_list_function (pad, _sink_chain_list);
+}
+
+
+GST_START_TEST (test_bufferlist)
+{
+  GstElement *rtpbin;
+  GstPad *sinkpad;
+  GstPad *srcpad;
+  GstBufferList *list;
+
+  list = _create_buffer_list ();
+  fail_unless (list != NULL);
+
+  rtpbin = gst_check_setup_element ("gstrtpbin");
+
+  srcpad =
+      gst_check_setup_src_pad_by_name (rtpbin, &srctemplate, "send_rtp_sink_0");
+  fail_if (srcpad == NULL);
+  sinkpad =
+      gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate,
+      "send_rtp_src_0");
+  fail_if (sinkpad == NULL);
+
+  _set_chain_functions (sinkpad);
+
+  gst_pad_set_active (sinkpad, TRUE);
+  gst_element_set_state (rtpbin, GST_STATE_PLAYING);
+  fail_unless (gst_pad_push_list (srcpad, list) == GST_FLOW_OK);
+  gst_pad_set_active (sinkpad, FALSE);
+
+  gst_check_teardown_pad_by_name (rtpbin, "send_rtp_src_0");
+  gst_check_teardown_pad_by_name (rtpbin, "send_rtp_sink_0");
+  gst_check_teardown_element (rtpbin);
+}
+
+GST_END_TEST;
+
+#endif
+
+
+static Suite *
+bufferlist_suite (void)
+{
+  Suite *s = suite_create ("BufferList");
+
+  TCase *tc_chain = tcase_create ("general");
+
+  /* time out after 30s. */
+  tcase_set_timeout (tc_chain, 10);
+
+  suite_add_tcase (s, tc_chain);
+#if 0
+  tcase_add_test (tc_chain, test_bufferlist);
+#endif
+
+  return s;
+}
+
+GST_CHECK_MAIN (bufferlist);
diff --git a/tests/check/elements/rtpbundle.c b/tests/check/elements/rtpbundle.c
new file mode 100644
index 0000000..9b477e1
--- /dev/null
+++ b/tests/check/elements/rtpbundle.c
@@ -0,0 +1,390 @@
+/* GStreamer
+ *
+ * Copyright (C) 2016 Igalia S.L.
+ *   @author Philippe Normand <philn@igalia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/check/gstconsistencychecker.h>
+#include <gst/check/gsttestclock.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+static GMainLoop *main_loop;
+
+static void
+message_received (GstBus * bus, GstMessage * message, GstPipeline * bin)
+{
+  GST_INFO ("bus message from \"%" GST_PTR_FORMAT "\": %" GST_PTR_FORMAT,
+      GST_MESSAGE_SRC (message), message);
+
+  switch (message->type) {
+    case GST_MESSAGE_EOS:
+      g_main_loop_quit (main_loop);
+      break;
+    case GST_MESSAGE_WARNING:{
+      GError *gerror;
+      gchar *debug;
+
+      gst_message_parse_warning (message, &gerror, &debug);
+      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+      g_error_free (gerror);
+      g_free (debug);
+      break;
+    }
+    case GST_MESSAGE_ERROR:{
+      GError *gerror;
+      gchar *debug;
+
+      gst_message_parse_error (message, &gerror, &debug);
+      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+      g_error_free (gerror);
+      g_free (debug);
+      fail ("Error!");
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+static void
+on_rtpbinreceive_pad_added (GstElement * element, GstPad * new_pad,
+    gpointer data)
+{
+  GstElement *pipeline = GST_ELEMENT (data);
+  gchar *pad_name = gst_pad_get_name (new_pad);
+
+  if (g_str_has_prefix (pad_name, "recv_rtp_src_")) {
+    GstCaps *caps = gst_pad_get_current_caps (new_pad);
+    GstStructure *s = gst_caps_get_structure (caps, 0);
+    const gchar *media_type = gst_structure_get_string (s, "media");
+    gchar *depayloader_name = g_strdup_printf ("%s_rtpdepayloader", media_type);
+    GstElement *rtpdepayloader =
+        gst_bin_get_by_name (GST_BIN (pipeline), depayloader_name);
+    GstPad *sinkpad;
+
+    g_free (depayloader_name);
+    fail_unless (rtpdepayloader != NULL, NULL);
+
+    sinkpad = gst_element_get_static_pad (rtpdepayloader, "sink");
+    gst_pad_link (new_pad, sinkpad);
+    gst_object_unref (sinkpad);
+    gst_object_unref (rtpdepayloader);
+
+    gst_caps_unref (caps);
+  }
+  g_free (pad_name);
+}
+
+static guint
+on_bundled_ssrc (GstElement * rtpbin, guint ssrc, gpointer user_data)
+{
+  static gboolean create_session = FALSE;
+  guint session_id = 0;
+
+  if (create_session) {
+    session_id = 1;
+  } else {
+    create_session = TRUE;
+    /* use existing session 0, a new session will be created for the next discovered bundled SSRC */
+  }
+  return session_id;
+}
+
+static GstCaps *
+on_request_pt_map (GstElement * rtpbin, guint session_id, guint pt,
+    gpointer user_data)
+{
+  GstCaps *caps = NULL;
+  if (pt == 96) {
+    caps =
+        gst_caps_from_string
+        ("application/x-rtp,media=(string)audio,encoding-name=(string)PCMA,clock-rate=(int)8000");
+  } else if (pt == 100) {
+    caps =
+        gst_caps_from_string
+        ("application/x-rtp,media=(string)video,encoding-name=(string)RAW,clock-rate=(int)90000,sampling=(string)\"YCbCr-4:2:0\",depth=(string)8,width=(string)320,height=(string)240");
+  }
+  return caps;
+}
+
+
+static GstElement *
+create_pipeline (gboolean send)
+{
+  GstElement *pipeline, *rtpbin, *audiosrc, *audio_encoder,
+      *audio_rtppayloader, *sendrtp_udpsink, *recv_rtp_udpsrc,
+      *send_rtcp_udpsink, *recv_rtcp_udpsrc, *sendrtcp_funnel, *sendrtp_funnel;
+  GstElement *audio_rtpdepayloader, *audio_decoder, *audio_sink;
+  GstElement *videosrc, *video_rtppayloader, *video_rtpdepayloader, *video_sink;
+  gboolean res;
+  GstPad *funnel_pad, *rtp_src_pad;
+  GstCaps *rtpcaps;
+  gint rtp_udp_port = 5001;
+  gint rtcp_udp_port = 5002;
+
+  pipeline = gst_pipeline_new (send ? "pipeline_send" : "pipeline_receive");
+
+  rtpbin =
+      gst_element_factory_make ("rtpbin",
+      send ? "rtpbin_send" : "rtpbin_receive");
+  g_object_set (rtpbin, "latency", 200, NULL);
+
+  if (!send) {
+    g_signal_connect (rtpbin, "on-bundled-ssrc",
+        G_CALLBACK (on_bundled_ssrc), NULL);
+    g_signal_connect (rtpbin, "request-pt-map",
+        G_CALLBACK (on_request_pt_map), NULL);
+  }
+
+  g_signal_connect (rtpbin, "pad-added",
+      G_CALLBACK (on_rtpbinreceive_pad_added), pipeline);
+
+  gst_bin_add (GST_BIN (pipeline), rtpbin);
+
+  if (send) {
+    audiosrc = gst_element_factory_make ("audiotestsrc", NULL);
+    audio_encoder = gst_element_factory_make ("alawenc", NULL);
+    audio_rtppayloader = gst_element_factory_make ("rtppcmapay", NULL);
+    g_object_set (audio_rtppayloader, "pt", 96, NULL);
+    g_object_set (audio_rtppayloader, "seqnum-offset", 1, NULL);
+
+    videosrc = gst_element_factory_make ("videotestsrc", NULL);
+    video_rtppayloader = gst_element_factory_make ("rtpvrawpay", NULL);
+    g_object_set (video_rtppayloader, "pt", 100, "seqnum-offset", 1, NULL);
+
+    g_object_set (audiosrc, "num-buffers", 5, NULL);
+    g_object_set (videosrc, "num-buffers", 5, NULL);
+
+    /* muxed rtcp */
+    sendrtcp_funnel = gst_element_factory_make ("funnel", "send_rtcp_funnel");
+    send_rtcp_udpsink = gst_element_factory_make ("udpsink", NULL);
+    g_object_set (send_rtcp_udpsink, "host", "127.0.0.1", NULL);
+    g_object_set (send_rtcp_udpsink, "port", rtcp_udp_port, NULL);
+    g_object_set (send_rtcp_udpsink, "sync", FALSE, NULL);
+    g_object_set (send_rtcp_udpsink, "async", FALSE, NULL);
+
+    /* outgoing bundled stream */
+    sendrtp_funnel = gst_element_factory_make ("funnel", "send_rtp_funnel");
+    sendrtp_udpsink = gst_element_factory_make ("udpsink", NULL);
+    g_object_set (sendrtp_udpsink, "host", "127.0.0.1", NULL);
+    g_object_set (sendrtp_udpsink, "port", rtp_udp_port, NULL);
+
+    gst_bin_add_many (GST_BIN (pipeline), audiosrc, audio_encoder,
+        audio_rtppayloader, sendrtp_udpsink, send_rtcp_udpsink,
+        sendrtp_funnel, sendrtcp_funnel, videosrc, video_rtppayloader, NULL);
+
+    res = gst_element_link (audiosrc, audio_encoder);
+    fail_unless (res == TRUE, NULL);
+    res = gst_element_link (audio_encoder, audio_rtppayloader);
+    fail_unless (res == TRUE, NULL);
+    res =
+        gst_element_link_pads_full (audio_rtppayloader, "src", rtpbin,
+        "send_rtp_sink_0", GST_PAD_LINK_CHECK_NOTHING);
+    fail_unless (res == TRUE, NULL);
+
+    res = gst_element_link (videosrc, video_rtppayloader);
+    fail_unless (res == TRUE, NULL);
+    res =
+        gst_element_link_pads_full (video_rtppayloader, "src", rtpbin,
+        "send_rtp_sink_1", GST_PAD_LINK_CHECK_NOTHING);
+    fail_unless (res == TRUE, NULL);
+
+    res =
+        gst_element_link_pads_full (sendrtp_funnel, "src", sendrtp_udpsink,
+        "sink", GST_PAD_LINK_CHECK_NOTHING);
+    fail_unless (res == TRUE, NULL);
+
+    funnel_pad = gst_element_get_request_pad (sendrtp_funnel, "sink_%u");
+    rtp_src_pad = gst_element_get_static_pad (rtpbin, "send_rtp_src_0");
+    res = gst_pad_link (rtp_src_pad, funnel_pad);
+    gst_object_unref (funnel_pad);
+    gst_object_unref (rtp_src_pad);
+
+    funnel_pad = gst_element_get_request_pad (sendrtp_funnel, "sink_%u");
+    rtp_src_pad = gst_element_get_static_pad (rtpbin, "send_rtp_src_1");
+    res = gst_pad_link (rtp_src_pad, funnel_pad);
+    gst_object_unref (funnel_pad);
+    gst_object_unref (rtp_src_pad);
+
+    res =
+        gst_element_link_pads_full (sendrtcp_funnel, "src", send_rtcp_udpsink,
+        "sink", GST_PAD_LINK_CHECK_NOTHING);
+    fail_unless (res == TRUE, NULL);
+
+    funnel_pad = gst_element_get_request_pad (sendrtcp_funnel, "sink_%u");
+    rtp_src_pad = gst_element_get_request_pad (rtpbin, "send_rtcp_src_0");
+    res =
+        gst_pad_link_full (rtp_src_pad, funnel_pad, GST_PAD_LINK_CHECK_NOTHING);
+    gst_object_unref (funnel_pad);
+    gst_object_unref (rtp_src_pad);
+
+    funnel_pad = gst_element_get_request_pad (sendrtcp_funnel, "sink_%u");
+    rtp_src_pad = gst_element_get_request_pad (rtpbin, "send_rtcp_src_1");
+    res =
+        gst_pad_link_full (rtp_src_pad, funnel_pad, GST_PAD_LINK_CHECK_NOTHING);
+    gst_object_unref (funnel_pad);
+    gst_object_unref (rtp_src_pad);
+
+  } else {
+    recv_rtp_udpsrc = gst_element_factory_make ("udpsrc", NULL);
+    g_object_set (recv_rtp_udpsrc, "port", rtp_udp_port, NULL);
+    rtpcaps = gst_caps_from_string ("application/x-rtp");
+    g_object_set (recv_rtp_udpsrc, "caps", rtpcaps, NULL);
+    gst_caps_unref (rtpcaps);
+
+    recv_rtcp_udpsrc = gst_element_factory_make ("udpsrc", NULL);
+    g_object_set (recv_rtcp_udpsrc, "port", rtcp_udp_port, NULL);
+
+    audio_rtpdepayloader =
+        gst_element_factory_make ("rtppcmadepay", "audio_rtpdepayloader");
+    audio_decoder = gst_element_factory_make ("alawdec", NULL);
+    audio_sink = gst_element_factory_make ("fakesink", NULL);
+    g_object_set (audio_sink, "sync", TRUE, NULL);
+
+    video_rtpdepayloader =
+        gst_element_factory_make ("rtpvrawdepay", "video_rtpdepayloader");
+    video_sink = gst_element_factory_make ("fakesink", NULL);
+    g_object_set (video_sink, "sync", TRUE, NULL);
+
+    gst_bin_add_many (GST_BIN (pipeline), recv_rtp_udpsrc, recv_rtcp_udpsrc,
+        audio_rtpdepayloader, audio_decoder, audio_sink, video_rtpdepayloader,
+        video_sink, NULL);
+
+    res =
+        gst_element_link_pads_full (audio_rtpdepayloader, "src", audio_decoder,
+        "sink", GST_PAD_LINK_CHECK_NOTHING);
+    fail_unless (res == TRUE, NULL);
+    res = gst_element_link (audio_decoder, audio_sink);
+    fail_unless (res == TRUE, NULL);
+
+    res =
+        gst_element_link_pads_full (video_rtpdepayloader, "src", video_sink,
+        "sink", GST_PAD_LINK_CHECK_NOTHING);
+    fail_unless (res == TRUE, NULL);
+
+    /* request a single receiving RTP session. */
+    res =
+        gst_element_link_pads_full (recv_rtcp_udpsrc, "src", rtpbin,
+        "recv_rtcp_sink_0", GST_PAD_LINK_CHECK_NOTHING);
+    fail_unless (res == TRUE, NULL);
+    res =
+        gst_element_link_pads_full (recv_rtp_udpsrc, "src", rtpbin,
+        "recv_rtp_sink_0", GST_PAD_LINK_CHECK_NOTHING);
+    fail_unless (res == TRUE, NULL);
+  }
+
+  return pipeline;
+}
+
+GST_START_TEST (test_simple_rtpbin_bundle)
+{
+  GstElement *send_pipeline, *recv_pipeline;
+  GstBus *send_bus, *recv_bus;
+  GstStateChangeReturn state_res = GST_STATE_CHANGE_FAILURE;
+  GstElement *rtpbin_receive;
+  GObject *rtp_session;
+
+  main_loop = g_main_loop_new (NULL, FALSE);
+
+  send_pipeline = create_pipeline (TRUE);
+  recv_pipeline = create_pipeline (FALSE);
+
+  send_bus = gst_element_get_bus (send_pipeline);
+  gst_bus_add_signal_watch_full (send_bus, G_PRIORITY_HIGH);
+
+  g_signal_connect (send_bus, "message::error", (GCallback) message_received,
+      send_pipeline);
+  g_signal_connect (send_bus, "message::warning", (GCallback) message_received,
+      send_pipeline);
+  g_signal_connect (send_bus, "message::eos", (GCallback) message_received,
+      send_pipeline);
+
+  recv_bus = gst_element_get_bus (recv_pipeline);
+  gst_bus_add_signal_watch_full (recv_bus, G_PRIORITY_HIGH);
+
+  g_signal_connect (recv_bus, "message::error", (GCallback) message_received,
+      recv_pipeline);
+  g_signal_connect (recv_bus, "message::warning", (GCallback) message_received,
+      recv_pipeline);
+  g_signal_connect (recv_bus, "message::eos", (GCallback) message_received,
+      recv_pipeline);
+
+  state_res = gst_element_set_state (recv_pipeline, GST_STATE_PLAYING);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  state_res = gst_element_set_state (send_pipeline, GST_STATE_PLAYING);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  GST_INFO ("enter mainloop");
+  g_main_loop_run (main_loop);
+  GST_INFO ("exit mainloop");
+
+  rtpbin_receive =
+      gst_bin_get_by_name (GST_BIN (recv_pipeline), "rtpbin_receive");
+  fail_if (rtpbin_receive == NULL, NULL);
+
+  /* Check that 2 RTP sessions where created while only one was explicitely requested. */
+  g_signal_emit_by_name (rtpbin_receive, "get-internal-session", 0,
+      &rtp_session);
+  fail_if (rtp_session == NULL, NULL);
+  g_object_unref (rtp_session);
+  g_signal_emit_by_name (rtpbin_receive, "get-internal-session", 1,
+      &rtp_session);
+  fail_if (rtp_session == NULL, NULL);
+  g_object_unref (rtp_session);
+
+  gst_object_unref (rtpbin_receive);
+
+  state_res = gst_element_set_state (send_pipeline, GST_STATE_NULL);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  state_res = gst_element_set_state (recv_pipeline, GST_STATE_NULL);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  /* cleanup */
+  g_main_loop_unref (main_loop);
+
+  gst_bus_remove_signal_watch (send_bus);
+  gst_object_unref (send_bus);
+  gst_object_unref (send_pipeline);
+
+  gst_bus_remove_signal_watch (recv_bus);
+  gst_object_unref (recv_bus);
+  gst_object_unref (recv_pipeline);
+
+}
+
+GST_END_TEST;
+
+static Suite *
+rtpbundle_suite (void)
+{
+  Suite *s = suite_create ("rtpbundle");
+  TCase *tc_chain = tcase_create ("general");
+
+  tcase_set_timeout (tc_chain, 10000);
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_simple_rtpbin_bundle);
+
+  return s;
+}
+
+GST_CHECK_MAIN (rtpbundle);
diff --git a/tests/check/elements/rtpcollision.c b/tests/check/elements/rtpcollision.c
new file mode 100644
index 0000000..16f665f
--- /dev/null
+++ b/tests/check/elements/rtpcollision.c
@@ -0,0 +1,462 @@
+/* GStreamer
+ *
+ * Copyright (C) 2013 Collabora Ltd.
+ *   @author Julien Isorce <julien.isorce@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/net/gstnetaddressmeta.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/rtp/gstrtcpbuffer.h>
+
+static GMainLoop *main_loop;
+static GstPad *srcpad;
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtcp")
+    );
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtcp")
+    );
+
+static void
+message_received (GstBus * bus, GstMessage * message, GstPipeline * bin)
+{
+  GST_INFO ("bus message from \"%" GST_PTR_FORMAT "\": %" GST_PTR_FORMAT,
+      GST_MESSAGE_SRC (message), message);
+
+  switch (message->type) {
+    case GST_MESSAGE_EOS:
+      g_main_loop_quit (main_loop);
+      break;
+    case GST_MESSAGE_WARNING:{
+      GError *gerror;
+      gchar *debug;
+
+      gst_message_parse_warning (message, &gerror, &debug);
+      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+      g_error_free (gerror);
+      g_free (debug);
+      break;
+    }
+    case GST_MESSAGE_ERROR:{
+      GError *gerror;
+      gchar *debug;
+
+      gst_message_parse_error (message, &gerror, &debug);
+      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+      g_error_free (gerror);
+      g_free (debug);
+      g_main_loop_quit (main_loop);
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+static GstBuffer *
+create_rtcp_app (guint32 ssrc, guint count)
+{
+  GInetAddress *inet_addr_0;
+  guint16 port = 5678 + count;
+  GSocketAddress *socket_addr_0;
+  GstBuffer *rtcp_buffer;
+  GstRTCPPacket *rtcp_packet = NULL;
+  GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
+
+  inet_addr_0 = g_inet_address_new_from_string ("192.168.1.1");
+  socket_addr_0 = g_inet_socket_address_new (inet_addr_0, port);
+  g_object_unref (inet_addr_0);
+
+  rtcp_buffer = gst_rtcp_buffer_new (1400);
+  gst_buffer_add_net_address_meta (rtcp_buffer, socket_addr_0);
+  g_object_unref (socket_addr_0);
+
+  /* need to begin with rr */
+  gst_rtcp_buffer_map (rtcp_buffer, GST_MAP_READWRITE, &rtcp);
+  rtcp_packet = g_slice_new0 (GstRTCPPacket);
+  gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_RR, rtcp_packet);
+  gst_rtcp_packet_rr_set_ssrc (rtcp_packet, ssrc);
+  g_slice_free (GstRTCPPacket, rtcp_packet);
+
+  /* useful to make the rtcp buffer valid */
+  rtcp_packet = g_slice_new0 (GstRTCPPacket);
+  gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_APP, rtcp_packet);
+  g_slice_free (GstRTCPPacket, rtcp_packet);
+  gst_rtcp_buffer_unmap (&rtcp);
+
+  return rtcp_buffer;
+}
+
+static guint nb_ssrc_changes;
+static guint ssrc_prev;
+
+static GstPadProbeReturn
+rtpsession_sinkpad_probe (GstPad * pad, GstPadProbeInfo * info,
+    gpointer user_data)
+{
+  GstPadProbeReturn ret = GST_PAD_PROBE_OK;
+
+  if (info->type == (GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_PUSH)) {
+    GstBuffer *buffer = GST_BUFFER (info->data);
+    GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+    GstBuffer *rtcp_buffer = 0;
+    guint ssrc = 0;
+
+    /* retrieve current ssrc */
+    gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp);
+    ssrc = gst_rtp_buffer_get_ssrc (&rtp);
+    gst_rtp_buffer_unmap (&rtp);
+
+    /* if not first buffer, check that our ssrc has changed */
+    if (ssrc_prev != -1 && ssrc != ssrc_prev)
+      ++nb_ssrc_changes;
+
+    /* update prev ssrc */
+    ssrc_prev = ssrc;
+
+    /* feint a collision on recv_rtcp_sink pad of gstrtpsession
+     * (note that after being marked as collied the rtpsession ignores
+     * all non bye packets)
+     */
+    rtcp_buffer = create_rtcp_app (ssrc, nb_ssrc_changes);
+
+    /* push collied packet on recv_rtcp_sink */
+    gst_pad_push (srcpad, rtcp_buffer);
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+fake_udp_sink_chain_func (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  gst_buffer_unref (buffer);
+  return GST_FLOW_OK;
+}
+
+/* This test build the pipeline audiotestsrc ! alawenc ! rtppcmapay ! \
+ * rtpsession ! fakesink
+ * It manually pushs buffer into rtpsession with same ssrc but different
+ * ip so that collision can be detected
+ * The test checks that the payloader change their ssrc
+ */
+GST_START_TEST (test_master_ssrc_collision)
+{
+  GstElement *bin, *src, *encoder, *rtppayloader, *rtpsession, *sink;
+  GstBus *bus = NULL;
+  gboolean res = FALSE;
+  GstSegment segment;
+  GstPad *sinkpad = NULL;
+  GstPad *rtcp_sinkpad = NULL;
+  GstPad *fake_udp_sinkpad = NULL;
+  GstPad *rtcp_srcpad = NULL;
+  GstStateChangeReturn state_res = GST_STATE_CHANGE_FAILURE;
+
+  GST_INFO ("preparing test");
+
+  nb_ssrc_changes = 0;
+  ssrc_prev = -1;
+
+  /* build pipeline */
+  bin = gst_pipeline_new ("pipeline");
+  bus = gst_element_get_bus (bin);
+  gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
+
+  src = gst_element_factory_make ("audiotestsrc", "src");
+  g_object_set (src, "num-buffers", 5, NULL);
+  encoder = gst_element_factory_make ("alawenc", NULL);
+  rtppayloader = gst_element_factory_make ("rtppcmapay", NULL);
+  g_object_set (rtppayloader, "pt", 8, NULL);
+  rtpsession = gst_element_factory_make ("rtpsession", NULL);
+  sink = gst_element_factory_make ("fakesink", "sink");
+  gst_bin_add_many (GST_BIN (bin), src, encoder, rtppayloader,
+      rtpsession, sink, NULL);
+
+  /* link elements */
+  res = gst_element_link (src, encoder);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link (encoder, rtppayloader);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link_pads_full (rtppayloader, "src",
+      rtpsession, "send_rtp_sink", GST_PAD_LINK_CHECK_NOTHING);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link_pads_full (rtpsession, "send_rtp_src",
+      sink, "sink", GST_PAD_LINK_CHECK_NOTHING);
+  fail_unless (res == TRUE, NULL);
+
+  /* add probe on rtpsession sink pad to induce collision */
+  sinkpad = gst_element_get_static_pad (rtpsession, "send_rtp_sink");
+  gst_pad_add_probe (sinkpad,
+      (GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_PUSH),
+      (GstPadProbeCallback) rtpsession_sinkpad_probe, NULL, NULL);
+  gst_object_unref (sinkpad);
+
+  /* setup rtcp link */
+  srcpad = gst_pad_new_from_static_template (&srctemplate, "src");
+  rtcp_sinkpad = gst_element_get_request_pad (rtpsession, "recv_rtcp_sink");
+  fail_unless (gst_pad_link (srcpad, rtcp_sinkpad) == GST_PAD_LINK_OK, NULL);
+  gst_object_unref (rtcp_sinkpad);
+  res = gst_pad_set_active (srcpad, TRUE);
+  fail_if (res == FALSE);
+  res =
+      gst_pad_push_event (srcpad,
+      gst_event_new_stream_start ("my_rtcp_stream_id"));
+  fail_if (res == FALSE);
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  res = gst_pad_push_event (srcpad, gst_event_new_segment (&segment));
+  fail_if (res == FALSE);
+
+  fake_udp_sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");
+  gst_pad_set_chain_function (fake_udp_sinkpad, fake_udp_sink_chain_func);
+  rtcp_srcpad = gst_element_get_request_pad (rtpsession, "send_rtcp_src");
+  fail_unless (gst_pad_link (rtcp_srcpad, fake_udp_sinkpad) == GST_PAD_LINK_OK,
+      NULL);
+  gst_object_unref (rtcp_srcpad);
+  res = gst_pad_set_active (fake_udp_sinkpad, TRUE);
+  fail_if (res == FALSE);
+
+  /* connect messages */
+  main_loop = g_main_loop_new (NULL, FALSE);
+  g_signal_connect (bus, "message::error", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::warning", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::eos", (GCallback) message_received, bin);
+
+  state_res = gst_element_set_state (bin, GST_STATE_PLAYING);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  GST_INFO ("running main loop");
+  g_main_loop_run (main_loop);
+
+  state_res = gst_element_set_state (bin, GST_STATE_NULL);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  /* cleanup */
+  gst_object_unref (srcpad);
+  gst_object_unref (fake_udp_sinkpad);
+  g_main_loop_unref (main_loop);
+  gst_bus_remove_signal_watch (bus);
+  gst_object_unref (bus);
+  gst_object_unref (bin);
+
+  /* check results */
+  fail_unless_equals_int (nb_ssrc_changes, 4);
+}
+
+GST_END_TEST;
+
+static guint ssrc_before;
+static guint ssrc_after;
+static guint rtx_ssrc_before;
+static guint rtx_ssrc_after;
+
+static GstPadProbeReturn
+rtpsession_sinkpad_probe2 (GstPad * pad, GstPadProbeInfo * info,
+    gpointer user_data)
+{
+  GstPadProbeReturn ret = GST_PAD_PROBE_OK;
+
+  if (info->type == (GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_PUSH)) {
+    GstBuffer *buffer = GST_BUFFER (info->data);
+    GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+    guint payload_type = 0;
+
+    static gint i = 0;
+
+    /* retrieve current ssrc for retransmission stream only */
+    gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp);
+    payload_type = gst_rtp_buffer_get_payload_type (&rtp);
+    if (payload_type == 99) {
+      if (i < 3)
+        rtx_ssrc_before = gst_rtp_buffer_get_ssrc (&rtp);
+      else
+        rtx_ssrc_after = gst_rtp_buffer_get_ssrc (&rtp);
+    } else {
+      /* ask to retransmit every packet */
+      GstEvent *event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+          gst_structure_new ("GstRTPRetransmissionRequest",
+              "seqnum", G_TYPE_UINT, gst_rtp_buffer_get_seq (&rtp),
+              "ssrc", G_TYPE_UINT, gst_rtp_buffer_get_ssrc (&rtp),
+              NULL));
+      gst_pad_push_event (pad, event);
+
+      if (i < 3)
+        ssrc_before = gst_rtp_buffer_get_ssrc (&rtp);
+      else
+        ssrc_after = gst_rtp_buffer_get_ssrc (&rtp);
+    }
+    gst_rtp_buffer_unmap (&rtp);
+
+    /* feint a collision on recv_rtcp_sink pad of gstrtpsession
+     * (note that after being marked as collied the rtpsession ignores
+     * all non bye packets)
+     */
+    if (i == 2) {
+      GstBuffer *rtcp_buffer = create_rtcp_app (rtx_ssrc_before, 0);
+
+      /* push collied packet on recv_rtcp_sink */
+      gst_pad_push (srcpad, rtcp_buffer);
+    }
+
+    ++i;
+  }
+
+  return ret;
+}
+
+/* This test build the pipeline audiotestsrc ! alawenc ! rtppcmapay ! \
+ * rtprtxsend ! rtpsession ! fakesink
+ * It manually pushs buffer into rtpsession with same ssrc than rtx stream
+ * but different ip so that collision can be detected
+ * The test checks that the rtx elements changes its ssrc whereas
+ * the payloader keeps its master ssrc
+ */
+GST_START_TEST (test_rtx_ssrc_collision)
+{
+  GstElement *bin, *src, *encoder, *rtppayloader, *rtprtxsend, *rtpsession,
+      *sink;
+  GstBus *bus = NULL;
+  gboolean res = FALSE;
+  GstSegment segment;
+  GstPad *sinkpad = NULL;
+  GstPad *rtcp_sinkpad = NULL;
+  GstPad *fake_udp_sinkpad = NULL;
+  GstPad *rtcp_srcpad = NULL;
+  GstStateChangeReturn state_res = GST_STATE_CHANGE_FAILURE;
+  GstStructure *pt_map;
+
+  GST_INFO ("preparing test");
+
+  /* build pipeline */
+  bin = gst_pipeline_new ("pipeline");
+  bus = gst_element_get_bus (bin);
+  gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
+
+  src = gst_element_factory_make ("audiotestsrc", "src");
+  g_object_set (src, "num-buffers", 5, NULL);
+  encoder = gst_element_factory_make ("alawenc", NULL);
+  rtppayloader = gst_element_factory_make ("rtppcmapay", NULL);
+  g_object_set (rtppayloader, "pt", 8, NULL);
+  rtprtxsend = gst_element_factory_make ("rtprtxsend", NULL);
+  pt_map = gst_structure_new ("application/x-rtp-pt-map",
+      "8", G_TYPE_UINT, 99, NULL);
+  g_object_set (rtprtxsend, "payload-type-map", pt_map, NULL);
+  gst_structure_free (pt_map);
+  rtpsession = gst_element_factory_make ("rtpsession", NULL);
+  sink = gst_element_factory_make ("fakesink", "sink");
+  gst_bin_add_many (GST_BIN (bin), src, encoder, rtppayloader, rtprtxsend,
+      rtpsession, sink, NULL);
+
+  /* link elements */
+  res = gst_element_link (src, encoder);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link (encoder, rtppayloader);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link (rtppayloader, rtprtxsend);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link_pads_full (rtprtxsend, "src",
+      rtpsession, "send_rtp_sink", GST_PAD_LINK_CHECK_NOTHING);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link_pads_full (rtpsession, "send_rtp_src",
+      sink, "sink", GST_PAD_LINK_CHECK_NOTHING);
+  fail_unless (res == TRUE, NULL);
+
+  /* add probe on rtpsession sink pad to induce collision */
+  sinkpad = gst_element_get_static_pad (rtpsession, "send_rtp_sink");
+  gst_pad_add_probe (sinkpad,
+      (GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_PUSH),
+      (GstPadProbeCallback) rtpsession_sinkpad_probe2, NULL, NULL);
+  gst_object_unref (sinkpad);
+
+  /* setup rtcp link */
+  srcpad = gst_pad_new_from_static_template (&srctemplate, "src");
+  rtcp_sinkpad = gst_element_get_request_pad (rtpsession, "recv_rtcp_sink");
+  fail_unless (gst_pad_link (srcpad, rtcp_sinkpad) == GST_PAD_LINK_OK, NULL);
+  gst_object_unref (rtcp_sinkpad);
+  res = gst_pad_set_active (srcpad, TRUE);
+  fail_if (res == FALSE);
+  res =
+      gst_pad_push_event (srcpad,
+      gst_event_new_stream_start ("my_rtcp_stream_id"));
+  fail_if (res == FALSE);
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  res = gst_pad_push_event (srcpad, gst_event_new_segment (&segment));
+  fail_if (res == FALSE);
+
+  fake_udp_sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");
+  gst_pad_set_chain_function (fake_udp_sinkpad, fake_udp_sink_chain_func);
+  rtcp_srcpad = gst_element_get_request_pad (rtpsession, "send_rtcp_src");
+  fail_unless (gst_pad_link (rtcp_srcpad, fake_udp_sinkpad) == GST_PAD_LINK_OK,
+      NULL);
+  gst_object_unref (rtcp_srcpad);
+  res = gst_pad_set_active (fake_udp_sinkpad, TRUE);
+  fail_if (res == FALSE);
+
+  /* connect messages */
+  main_loop = g_main_loop_new (NULL, FALSE);
+  g_signal_connect (bus, "message::error", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::warning", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::eos", (GCallback) message_received, bin);
+
+  state_res = gst_element_set_state (bin, GST_STATE_PLAYING);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  GST_INFO ("running main loop");
+  g_main_loop_run (main_loop);
+
+  state_res = gst_element_set_state (bin, GST_STATE_NULL);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  /* cleanup */
+  gst_object_unref (srcpad);
+  gst_object_unref (fake_udp_sinkpad);
+  g_main_loop_unref (main_loop);
+  gst_bus_remove_signal_watch (bus);
+  gst_object_unref (bus);
+  gst_object_unref (bin);
+
+  /* check results */
+  fail_if (rtx_ssrc_before == rtx_ssrc_after);
+  fail_if (ssrc_before != ssrc_after);
+}
+
+GST_END_TEST;
+
+static Suite *
+rtpcollision_suite (void)
+{
+  Suite *s = suite_create ("rtpcollision");
+  TCase *tc_chain = tcase_create ("general");
+
+  tcase_set_timeout (tc_chain, 10);
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_master_ssrc_collision);
+  tcase_add_test (tc_chain, test_rtx_ssrc_collision);
+
+  return s;
+}
+
+GST_CHECK_MAIN (rtpcollision);
diff --git a/tests/check/elements/rtph261.c b/tests/check/elements/rtph261.c
new file mode 100644
index 0000000..7c34d37
--- /dev/null
+++ b/tests/check/elements/rtph261.c
@@ -0,0 +1,142 @@
+#include <gst/check/check.h>
+#include <gst/check/gstharness.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#define H261_RTP_CAPS_STR                                               \
+  "application/x-rtp,media=video,encoding-name=H261,clock-rate=90000,payload=31"
+
+typedef struct _GstRtpH261PayHeader
+{
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+  unsigned int v:1;             /* Motion vector flag */
+  unsigned int i:1;             /* Intra encoded data */
+  unsigned int ebit:3;          /* End position */
+  unsigned int sbit:3;          /* Start position */
+
+  unsigned int mbap1:4;         /* MB address predictor - part1 */
+  unsigned int gobn:4;          /* GOB number */
+
+  unsigned int hmvd1:2;         /* Horizontal motion vector data - part1 */
+  unsigned int quant:5;         /* Quantizer */
+  unsigned int mbap2:1;         /* MB address predictor - part2 */
+
+  unsigned int vmvd:5;          /* Horizontal motion vector data - part1 */
+  unsigned int hmvd2:3;         /* Vertical motion vector data */
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+  unsigned int sbit:3;          /* Start position */
+  unsigned int ebit:3;          /* End position */
+  unsigned int i:1;             /* Intra encoded data */
+  unsigned int v:1;             /* Motion vector flag */
+
+  unsigned int gobn:4;          /* GOB number */
+  unsigned int mbap1:4;         /* MB address predictor - part1 */
+
+  unsigned int mbap2:1;         /* MB address predictor - part2 */
+  unsigned int quant:5;         /* Quantizer */
+  unsigned int hmvd1:2;         /* Horizontal motion vector data - part1 */
+
+  unsigned int hmvd2:3;         /* Vertical motion vector data */
+  unsigned int vmvd:5;          /* Horizontal motion vector data - part1 */
+#else
+#error "G_BYTE_ORDER should be big or little endian."
+#endif
+} GstRtpH261PayHeader;
+
+#define GST_RTP_H261_PAYLOAD_HEADER_LEN 4
+
+static guint8 *
+create_h261_payload (gint sbit, gint ebit, gint psc, gsize size)
+{
+  GstRtpH261PayHeader header;
+  const gint header_len = 4;
+  guint8 *data = g_malloc0 (size);
+
+  memset (&header, 0x00, sizeof (header));
+
+  header.sbit = sbit;
+  header.ebit = ebit;
+
+  memset (data, 0xff, size);
+  memcpy (data, &header, header_len);
+
+  if (psc) {
+    guint32 word = 0x000100ff >> sbit;
+    data[header_len + 0] = (word >> 24) & 0xff;
+    data[header_len + 1] = (word >> 16) & 0xff;
+    data[header_len + 2] = (word >> 8) & 0xff;
+    data[header_len + 3] = (word >> 0) & 0xff;
+  }
+
+  return data;
+}
+
+static GstBuffer *
+create_rtp_copy_payload (const guint8 * data, gsize size, guint ts, guint16 seq,
+    gboolean marker, guint csrcs)
+{
+  GstBuffer *buf = gst_rtp_buffer_new_allocate (size, 0, csrcs);
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+
+  gst_rtp_buffer_map (buf, GST_MAP_WRITE, &rtp);
+
+  gst_rtp_buffer_set_seq (&rtp, seq);
+  gst_rtp_buffer_set_marker (&rtp, marker);
+  memcpy (gst_rtp_buffer_get_payload (&rtp), data, size);
+
+  GST_BUFFER_PTS (buf) = (ts) * (GST_SECOND / 30);
+  GST_BUFFER_DURATION (buf) = (GST_SECOND / 30);
+
+  gst_rtp_buffer_unmap (&rtp);
+
+  return buf;
+}
+
+GST_START_TEST (test_h263depay_empty_payload)
+{
+  GstHarness *h = gst_harness_new ("rtph261depay");
+  gint sbit = 4;
+  gint ebit = 4;
+  gsize size;
+  guint8 *payload;
+  guint seq = 0;
+
+  gst_harness_set_src_caps_str (h, H261_RTP_CAPS_STR);
+
+  /* First send a proper packet with picture start code */
+  size = 100;
+  payload = create_h261_payload (sbit, ebit, TRUE, size);
+  gst_harness_push (h, create_rtp_copy_payload (payload, size, 0, seq++, FALSE,
+          0));
+  g_free (payload);
+
+  /* Not a complete frame */
+  fail_unless_equals_int (gst_harness_buffers_received (h), 0);
+
+  /* Second buffer has invalid empty payload */
+  size = GST_RTP_H261_PAYLOAD_HEADER_LEN;
+  payload = create_h261_payload (sbit, ebit, FALSE, size);
+  gst_harness_push (h, create_rtp_copy_payload (payload, size, 0, seq++, TRUE,
+          0));
+  g_free (payload);
+
+  /* Invalid payload should be dropped */
+  fail_unless_equals_int (gst_harness_buffers_received (h), 0);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+static Suite *
+rtph261_suite (void)
+{
+  Suite *s = suite_create ("rtph261");
+  TCase *tc_chain;
+
+  suite_add_tcase (s, (tc_chain = tcase_create ("h261depay")));
+  tcase_add_test (tc_chain, test_h263depay_empty_payload);
+
+  return s;
+}
+
+GST_CHECK_MAIN (rtph261);
diff --git a/tests/check/elements/rtph263.c b/tests/check/elements/rtph263.c
new file mode 100644
index 0000000..28c0198
--- /dev/null
+++ b/tests/check/elements/rtph263.c
@@ -0,0 +1,338 @@
+/* GStreamer
+ *
+ * Copyright (C) 2015 Pexip AS
+ *   @author Stian Selnes <stian@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/check.h>
+#include <gst/check/gstharness.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#define RTP_H263_CAPS_STR(p)                                            \
+  "application/x-rtp,media=video,encoding-name=H263,clock-rate=90000,"  \
+  "payload=" G_STRINGIFY(p)
+
+#define H263P_RTP_CAPS_STR(p)                                           \
+  "application/x-rtp,media=video,encoding-name=H263-1998,clock-rate=90000," \
+  "payload="G_STRINGIFY(p)
+
+static gboolean
+have_element (const gchar * element_name)
+{
+  GstElement *element;
+  gboolean ret;
+
+  element = gst_element_factory_make (element_name, NULL);
+  ret = element != NULL;
+
+  if (element)
+    gst_object_unref (element);
+
+  return ret;
+}
+
+static GstBuffer *
+create_rtp_buffer (guint8 * data, gsize size, guint ts, gint seqnum)
+{
+  GstBuffer *buf = gst_rtp_buffer_new_copy_data (data, size);
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+
+  GST_BUFFER_PTS (buf) = (ts) * (GST_SECOND / 30);
+
+  gst_rtp_buffer_map (buf, GST_MAP_WRITE, &rtp);
+  gst_rtp_buffer_set_seq (&rtp, seqnum);
+  gst_rtp_buffer_unmap (&rtp);
+
+  return buf;
+}
+
+GST_START_TEST (test_h263depay_start_packet_too_small_mode_a)
+{
+  GstHarness *h = gst_harness_new ("rtph263depay");
+  guint8 packet[] = {
+    0x80, 0xa2, 0x17, 0x62, 0x57, 0xbb, 0x48, 0x98, 0x4a, 0x59, 0xe8, 0xdc,
+    0x00, 0x00, 0x80, 0x00
+  };
+
+  gst_harness_set_src_caps_str (h, RTP_H263_CAPS_STR (34));
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, create_rtp_buffer (packet, sizeof (packet), 0, 0)));
+
+  /* Packet should be dropped and depayloader not crash */
+  fail_unless_equals_int (0, gst_harness_buffers_received (h));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_h263depay_start_packet_too_small_mode_b)
+{
+  GstHarness *h = gst_harness_new ("rtph263depay");
+  guint8 packet[] = {
+    0x80, 0xa2, 0x17, 0x62, 0x57, 0xbb, 0x48, 0x98, 0x4a, 0x59, 0xe8, 0xdc,
+    0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
+
+  gst_harness_set_src_caps_str (h, RTP_H263_CAPS_STR (34));
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, create_rtp_buffer (packet, sizeof (packet), 0, 0)));
+
+  /* Packet should be dropped and depayloader not crash */
+  fail_unless_equals_int (0, gst_harness_buffers_received (h));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_h263depay_start_packet_too_small_mode_c)
+{
+  GstHarness *h = gst_harness_new ("rtph263depay");
+  guint8 packet[] = {
+    0x80, 0xa2, 0x17, 0x62, 0x57, 0xbb, 0x48, 0x98, 0x4a, 0x59, 0xe8, 0xdc,
+    0xc0, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
+
+  gst_harness_set_src_caps_str (h, RTP_H263_CAPS_STR (34));
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, create_rtp_buffer (packet, sizeof (packet), 0, 0)));
+
+  /* Packet should be dropped and depayloader not crash */
+  fail_unless_equals_int (0, gst_harness_buffers_received (h));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_h263pay_mode_b_snow)
+{
+  /* Payloading one large frame (like snow) is more likely to use mode b and
+   * trigger issues in valgrind seen previously like double free, invalid read
+   * etc. */
+  GstHarness *h;
+  guint frames = 1;
+  guint i;
+
+  if (!have_element ("avenc_h263"))
+    return;
+
+  h = gst_harness_new_parse
+      ("avenc_h263 rtp-payload-size=1 ! rtph263pay mtu=1350 ");
+  gst_harness_add_src_parse (h,
+      "videotestsrc pattern=snow is-live=1 ! "
+      "capsfilter caps=\"video/x-raw,format=I420,width=176,height=144\"", TRUE);
+
+  for (i = 0; i < frames; i++)
+    gst_harness_push_from_src (h);
+  fail_unless (gst_harness_buffers_received (h) >= frames);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+/* gst_rtp_buffer_get_payload() may return a copy of the payload. This test
+ * makes sure that the rtph263pdepay also produces the correct output in this
+ * case. */
+GST_START_TEST (test_h263pdepay_fragmented_memory_non_writable_buffer)
+{
+  GstHarness *h;
+  GstBuffer *header_buf, *payload_buf, *buf;
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+  guint8 header[] = {
+    0x04, 0x00
+  };
+  guint8 payload[] = {
+    0x80, 0x02, 0x1c, 0xb8, 0x01, 0x00, 0x11, 0xe0, 0x44, 0xc4
+  };
+  guint8 frame[] = {
+    0x00, 0x00, 0x80, 0x02, 0x1c, 0xb8, 0x01, 0x00, 0x11, 0xe0, 0x44, 0xc4
+  };
+
+  h = gst_harness_new ("rtph263pdepay");
+  gst_harness_set_src_caps_str (h, "application/x-rtp, media=video, "
+      "clock-rate=90000, encoding-name=H263-1998");
+
+  /* Packet with M=1, P=1 */
+  header_buf = gst_rtp_buffer_new_allocate (sizeof (header), 0, 0);
+  gst_rtp_buffer_map (header_buf, GST_MAP_WRITE, &rtp);
+  gst_rtp_buffer_set_marker (&rtp, TRUE);
+  memcpy (gst_rtp_buffer_get_payload (&rtp), header, sizeof (header));
+  gst_rtp_buffer_unmap (&rtp);
+
+  payload_buf = gst_buffer_new_allocate (NULL, sizeof (payload), NULL);
+  gst_buffer_fill (payload_buf, 0, payload, sizeof (payload));
+  buf = gst_buffer_append (header_buf, payload_buf);
+
+  gst_harness_push (h, gst_buffer_ref (buf));
+  gst_buffer_unref (buf);
+
+  buf = gst_harness_pull (h);
+  fail_unless (gst_buffer_memcmp (buf, 0, frame, sizeof (frame)) == 0);
+  gst_buffer_unref (buf);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+/* gst_rtp_buffer_get_payload() may return a copy of the payload. This test
+ * makes sure that the rtph263pdepay also produces the correct output in this
+ * case. */
+GST_START_TEST
+    (test_h263pdepay_fragmented_memory_non_writable_buffer_split_frame) {
+  GstHarness *h;
+  GstBuffer *header_buf, *payload_buf, *buf;
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+  guint8 header[] = {
+    0x04, 0x00
+  };
+  guint8 payload[] = {
+    0x80, 0x02, 0x1c, 0xb8, 0x01, 0x00, 0x11, 0xe0, 0x44, 0xc4
+  };
+  guint8 frame[] = {
+    0x00, 0x00, 0x80, 0x02, 0x1c, 0xb8, 0x01, 0x00, 0x11, 0xe0, 0x44, 0xc4
+  };
+
+  h = gst_harness_new ("rtph263pdepay");
+  gst_harness_set_src_caps_str (h, "application/x-rtp, media=video, "
+      "clock-rate=90000, encoding-name=H263-1998");
+
+  /* First packet, M=0, P=1 */
+  header_buf = gst_rtp_buffer_new_allocate (sizeof (header), 0, 0);
+  gst_rtp_buffer_map (header_buf, GST_MAP_WRITE, &rtp);
+  gst_rtp_buffer_set_marker (&rtp, FALSE);
+  gst_rtp_buffer_set_seq (&rtp, 0);
+  memcpy (gst_rtp_buffer_get_payload (&rtp), header, sizeof (header));
+  gst_rtp_buffer_unmap (&rtp);
+
+  payload_buf = gst_buffer_new_allocate (NULL, sizeof (payload), NULL);
+  gst_buffer_fill (payload_buf, 0, payload, sizeof (payload));
+  buf = gst_buffer_append (header_buf, payload_buf);
+
+  gst_harness_push (h, gst_buffer_ref (buf));
+  gst_buffer_unref (buf);
+  fail_unless_equals_int (gst_harness_buffers_received (h), 0);
+
+  /* Second packet, M=1, P=1 */
+  header_buf = gst_rtp_buffer_new_allocate (sizeof (header), 0, 0);
+  gst_rtp_buffer_map (header_buf, GST_MAP_WRITE, &rtp);
+  gst_rtp_buffer_set_marker (&rtp, TRUE);
+  gst_rtp_buffer_set_seq (&rtp, 1);
+  memcpy (gst_rtp_buffer_get_payload (&rtp), header, sizeof (header));
+  gst_rtp_buffer_unmap (&rtp);
+
+  payload_buf = gst_buffer_new_allocate (NULL, sizeof (payload), NULL);
+  gst_buffer_memset (payload_buf, 0, 0, 10);
+  buf = gst_buffer_append (header_buf, payload_buf);
+
+  gst_harness_push (h, gst_buffer_ref (buf));
+  gst_buffer_unref (buf);
+  fail_unless_equals_int (gst_harness_buffers_received (h), 1);
+
+  buf = gst_harness_pull (h);
+  fail_unless (gst_buffer_memcmp (buf, 0, frame, sizeof (frame)) == 0);
+  gst_buffer_unref (buf);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_h263pdepay_dont_push_empty_frame)
+{
+  GstHarness *h = gst_harness_new ("rtph263pdepay");
+
+  /* Packet that only contains header information and an extra picture header
+   * (PLEN > 0). Partly handcrafted packet. Originally this packet did not
+   * have P=1 (hence it was not start of a picture). With both P=1 and M=1 we
+   * only need one packet to reproduce the issue where trying to push an empty
+   * frame when PLEN is set */
+  guint8 packet[] = {
+    0x80, 0xe8, 0xbc, 0xaa, 0x14, 0x12, 0x16, 0x5c, 0xb8, 0x4e, 0x39, 0x04,
+    0x25, 0x00, 0x54, 0x39, 0xd0, 0x12, 0x06, 0x9e, 0xb5, 0x0a, 0xf5, 0xe8,
+    0x32, 0xeb, 0xd0, 0x6b, 0xd6, 0xa2, 0xfa, 0xd4, 0x3d, 0xd7, 0xa0, 0x2b,
+    0x24, 0x97, 0xc3, 0xbf, 0xc0, 0xbb, 0xd7, 0xa0,
+  };
+
+  gst_harness_set_src_caps_str (h, H263P_RTP_CAPS_STR (100));
+
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          create_rtp_buffer (packet, sizeof (packet), 0, 0)));
+
+  fail_unless_equals_int (gst_harness_buffers_received (h), 0);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_h263ppay_non_fixed_caps)
+{
+  GstHarness *h;
+  guint8 frame[] = {
+    0x00, 0x00, 0x80, 0x06, 0x1c, 0xa8, 0x01, 0x04, 0x91, 0xe0, 0x37, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  };
+
+  h = gst_harness_new_parse ("rtph263ppay");
+
+  /* Set non-fixed caps after payloader */
+  gst_harness_set_caps_str (h, "video/x-h263, variant=(string)itu",
+      "application/x-rtp, clock-rate=[1, MAX]");
+
+  gst_harness_push (h, gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+          frame, sizeof (frame), 0, sizeof (frame), NULL, NULL));
+
+  fail_unless_equals_int (1, gst_harness_buffers_received (h));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+static Suite *
+rtph263_suite (void)
+{
+  Suite *s = suite_create ("rtph263");
+  TCase *tc_chain;
+
+  suite_add_tcase (s, (tc_chain = tcase_create ("h263depay")));
+  tcase_add_test (tc_chain, test_h263depay_start_packet_too_small_mode_a);
+  tcase_add_test (tc_chain, test_h263depay_start_packet_too_small_mode_b);
+  tcase_add_test (tc_chain, test_h263depay_start_packet_too_small_mode_c);
+
+  suite_add_tcase (s, (tc_chain = tcase_create ("h263pay")));
+  tcase_add_test (tc_chain, test_h263pay_mode_b_snow);
+
+  suite_add_tcase (s, (tc_chain = tcase_create ("h263pdepay")));
+  tcase_add_test (tc_chain,
+      test_h263pdepay_fragmented_memory_non_writable_buffer);
+  tcase_add_test (tc_chain,
+      test_h263pdepay_fragmented_memory_non_writable_buffer_split_frame);
+  tcase_add_test (tc_chain, test_h263pdepay_dont_push_empty_frame);
+
+  suite_add_tcase (s, (tc_chain = tcase_create ("h263ppay")));
+  tcase_add_test (tc_chain, test_h263ppay_non_fixed_caps);
+
+  return s;
+}
+
+GST_CHECK_MAIN (rtph263);
diff --git a/tests/check/elements/rtph264.c b/tests/check/elements/rtph264.c
new file mode 100644
index 0000000..323e1bf
--- /dev/null
+++ b/tests/check/elements/rtph264.c
@@ -0,0 +1,311 @@
+/* GStreamer RTP H.264 unit test
+ *
+ * Copyright (C) 2017 Centricular Ltd
+ *   @author: Tim-Philipp Müller <tim@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/check.h>
+#include <gst/app/app.h>
+
+#define ALLOCATOR_CUSTOM_SYSMEM "CustomSysMem"
+
+static GstAllocator *custom_sysmem_allocator;   /* NULL */
+
+/* Custom memory */
+
+typedef struct
+{
+  GstMemory mem;
+  guint8 *data;
+  guint8 *allocdata;
+} CustomSysmem;
+
+static CustomSysmem *
+custom_sysmem_new (GstMemoryFlags flags, gsize maxsize, gsize align,
+    gsize offset, gsize size)
+{
+  gsize aoffset, padding;
+  CustomSysmem *mem;
+
+  /* ensure configured alignment */
+  align |= gst_memory_alignment;
+  /* allocate more to compensate for alignment */
+  maxsize += align;
+
+  mem = g_new0 (CustomSysmem, 1);
+
+  mem->allocdata = g_malloc (maxsize);
+
+  mem->data = mem->allocdata;
+
+  /* do alignment */
+  if ((aoffset = ((guintptr) mem->data & align))) {
+    aoffset = (align + 1) - aoffset;
+    mem->data += aoffset;
+    maxsize -= aoffset;
+  }
+
+  if (offset && (flags & GST_MEMORY_FLAG_ZERO_PREFIXED))
+    memset (mem->data, 0, offset);
+
+  padding = maxsize - (offset + size);
+  if (padding && (flags & GST_MEMORY_FLAG_ZERO_PADDED))
+    memset (mem->data + offset + size, 0, padding);
+
+  gst_memory_init (GST_MEMORY_CAST (mem), flags, custom_sysmem_allocator,
+      NULL, maxsize, align, offset, size);
+
+  return mem;
+}
+
+static gpointer
+custom_sysmem_map (CustomSysmem * mem, gsize maxsize, GstMapFlags flags)
+{
+  return mem->data;
+}
+
+static gboolean
+custom_sysmem_unmap (CustomSysmem * mem)
+{
+  return TRUE;
+}
+
+static CustomSysmem *
+custom_sysmem_copy (CustomSysmem * mem, gssize offset, gsize size)
+{
+  g_return_val_if_reached (NULL);
+}
+
+static CustomSysmem *
+custom_sysmem_share (CustomSysmem * mem, gssize offset, gsize size)
+{
+  g_return_val_if_reached (NULL);
+}
+
+static gboolean
+custom_sysmem_is_span (CustomSysmem * mem1, CustomSysmem * mem2, gsize * offset)
+{
+  g_return_val_if_reached (FALSE);
+}
+
+/* Custom allocator */
+
+typedef struct
+{
+  GstAllocator allocator;
+} CustomSysmemAllocator;
+
+typedef struct
+{
+  GstAllocatorClass allocator_class;
+} CustomSysmemAllocatorClass;
+
+GType custom_sysmem_allocator_get_type (void);
+G_DEFINE_TYPE (CustomSysmemAllocator, custom_sysmem_allocator,
+    GST_TYPE_ALLOCATOR);
+
+static GstMemory *
+custom_sysmem_allocator_alloc (GstAllocator * allocator, gsize size,
+    GstAllocationParams * params)
+{
+  gsize maxsize = size + params->prefix + params->padding;
+
+  return (GstMemory *) custom_sysmem_new (params->flags,
+      maxsize, params->align, params->prefix, size);
+}
+
+static void
+custom_sysmem_allocator_free (GstAllocator * allocator, GstMemory * mem)
+{
+  CustomSysmem *csmem = (CustomSysmem *) mem;
+
+  g_free (csmem->allocdata);
+  g_free (csmem);
+}
+
+static void
+custom_sysmem_allocator_class_init (CustomSysmemAllocatorClass * klass)
+{
+  GstAllocatorClass *allocator_class = (GstAllocatorClass *) klass;
+
+  allocator_class->alloc = custom_sysmem_allocator_alloc;
+  allocator_class->free = custom_sysmem_allocator_free;
+}
+
+static void
+custom_sysmem_allocator_init (CustomSysmemAllocator * allocator)
+{
+  GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
+
+  alloc->mem_type = ALLOCATOR_CUSTOM_SYSMEM;
+  alloc->mem_map = (GstMemoryMapFunction) custom_sysmem_map;
+  alloc->mem_unmap = (GstMemoryUnmapFunction) custom_sysmem_unmap;
+  alloc->mem_copy = (GstMemoryCopyFunction) custom_sysmem_copy;
+  alloc->mem_share = (GstMemoryShareFunction) custom_sysmem_share;
+  alloc->mem_is_span = (GstMemoryIsSpanFunction) custom_sysmem_is_span;
+}
+
+/* AppSink subclass proposing our custom allocator to upstream */
+
+typedef struct
+{
+  GstAppSink appsink;
+} CMemAppSink;
+
+typedef struct
+{
+  GstAppSinkClass appsink;
+} CMemAppSinkClass;
+
+GType c_mem_app_sink_get_type (void);
+
+G_DEFINE_TYPE (CMemAppSink, c_mem_app_sink, GST_TYPE_APP_SINK);
+
+static void
+c_mem_app_sink_init (CMemAppSink * cmemsink)
+{
+}
+
+static gboolean
+c_mem_app_sink_propose_allocation (GstBaseSink * sink, GstQuery * query)
+{
+  gst_query_add_allocation_param (query, custom_sysmem_allocator, NULL);
+  return TRUE;
+}
+
+static void
+c_mem_app_sink_class_init (CMemAppSinkClass * klass)
+{
+  GstBaseSinkClass *basesink_class = (GstBaseSinkClass *) klass;
+
+  basesink_class->propose_allocation = c_mem_app_sink_propose_allocation;
+}
+
+#define RTP_H264_FILE GST_TEST_FILES_PATH G_DIR_SEPARATOR_S "h264.rtp"
+
+GST_START_TEST (test_rtph264depay_with_downstream_allocator)
+{
+  GstElement *pipeline, *src, *depay, *sink;
+  GstMemory *mem;
+  GstSample *sample;
+  GstBuffer *buf;
+  GstCaps *caps;
+
+  custom_sysmem_allocator =
+      g_object_new (custom_sysmem_allocator_get_type (), NULL);
+
+  pipeline = gst_pipeline_new ("pipeline");
+
+  src = gst_element_factory_make ("appsrc", NULL);
+
+  caps = gst_caps_new_simple ("application/x-rtp",
+      "media", G_TYPE_STRING, "video",
+      "payload", G_TYPE_INT, 96,
+      "clock-rate", G_TYPE_INT, 90000,
+      "encoding-name", G_TYPE_STRING, "H264",
+      "ssrc", G_TYPE_UINT, 1990683810,
+      "timestamp-offset", G_TYPE_UINT, 3697583446,
+      "seqnum-offset", G_TYPE_UINT, 15568,
+      "a-framerate", G_TYPE_STRING, "30", NULL);
+  g_object_set (src, "format", GST_FORMAT_TIME, "caps", caps, NULL);
+  gst_bin_add (GST_BIN (pipeline), src);
+  gst_caps_unref (caps);
+
+  depay = gst_element_factory_make ("rtph264depay", NULL);
+  gst_bin_add (GST_BIN (pipeline), depay);
+
+  sink = g_object_new (c_mem_app_sink_get_type (), NULL);
+  gst_bin_add (GST_BIN (pipeline), sink);
+
+  gst_element_link_many (src, depay, sink, NULL);
+
+  gst_element_set_state (pipeline, GST_STATE_PAUSED);
+
+  {
+    gchar *data, *pdata;
+    gsize len;
+
+    fail_unless (g_file_get_contents (RTP_H264_FILE, &data, &len, NULL));
+    fail_unless (len > 2);
+
+    pdata = data;
+    while (len > 2) {
+      GstFlowReturn flow;
+      guint16 packet_len;
+
+      packet_len = GST_READ_UINT16_BE (pdata);
+      GST_INFO ("rtp packet length: %u (bytes left: %u)", packet_len,
+          (guint) len);
+      fail_unless (len >= 2 + packet_len);
+
+      flow = gst_app_src_push_buffer (GST_APP_SRC (src),
+          gst_buffer_new_wrapped (g_memdup (pdata + 2, packet_len),
+              packet_len));
+
+      fail_unless_equals_int (flow, GST_FLOW_OK);
+
+      pdata += 2 + packet_len;
+      len -= 2 + packet_len;
+    }
+
+    g_free (data);
+  }
+
+  gst_app_src_end_of_stream (GST_APP_SRC (src));
+
+  sample = gst_app_sink_pull_preroll (GST_APP_SINK (sink));
+  fail_unless (sample != NULL);
+
+  buf = gst_sample_get_buffer (sample);
+
+  GST_LOG ("buffer has %u memories", gst_buffer_n_memory (buf));
+  GST_LOG ("buffer size: %u", (guint) gst_buffer_get_size (buf));
+
+  fail_unless (gst_buffer_n_memory (buf) > 0);
+  mem = gst_buffer_peek_memory (buf, 0);
+  fail_unless (mem != NULL);
+
+  GST_LOG ("buffer memory type: %s", mem->allocator->mem_type);
+  fail_unless (gst_memory_is_type (mem, ALLOCATOR_CUSTOM_SYSMEM));
+
+  gst_sample_unref (sample);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  gst_object_unref (pipeline);
+
+  g_object_unref (custom_sysmem_allocator);
+  custom_sysmem_allocator = NULL;
+}
+
+GST_END_TEST;
+
+static Suite *
+rtph264_suite (void)
+{
+  Suite *s = suite_create ("rtph264");
+  TCase *tc_chain;
+
+  tc_chain = tcase_create ("rtph264depay");
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_rtph264depay_with_downstream_allocator);
+
+  return s;
+}
+
+GST_CHECK_MAIN (rtph264);
diff --git a/tests/check/elements/rtpjitterbuffer.c b/tests/check/elements/rtpjitterbuffer.c
new file mode 100644
index 0000000..5c13a0c
--- /dev/null
+++ b/tests/check/elements/rtpjitterbuffer.c
@@ -0,0 +1,2185 @@
+/* GStreamer
+ *
+ * Copyright (C) 2009 Nokia Corporation and its subsidary(-ies)
+ *               contact: <stefan.kost@nokia.com>
+ * Copyright (C) 2012 Cisco Systems, Inc
+ *               Authors: Kelley Rogers <kelro@cisco.com>
+ *               Havard Graff <hgraff@cisco.com>
+ * Copyright (C) 2013-2016 Pexip AS
+ *               Stian Selnes <stian@pexip>
+ *               Havard Graff <havard@pexip>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/check/gsttestclock.h>
+#include <gst/check/gstharness.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+static GstPad *mysrcpad, *mysinkpad;
+/* we also have a list of src buffers */
+static GList *inbuffers = NULL;
+static gint num_dropped = 0;
+
+#define RTP_CAPS_STRING    \
+    "application/x-rtp, "               \
+    "media = (string)audio, "           \
+    "payload = (int) 0, "               \
+    "clock-rate = (int) 8000, "         \
+    "encoding-name = (string)PCMU"
+
+#define RTP_FRAME_SIZE 20
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp")
+    );
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "clock-rate = (int) [ 1, 2147483647 ]")
+    );
+
+static void
+buffer_dropped (gpointer data, GstMiniObject * obj)
+{
+  GST_DEBUG ("dropping buffer %p", obj);
+  num_dropped++;
+}
+
+static GstElement *
+setup_jitterbuffer (gint num_buffers)
+{
+  GstElement *jitterbuffer;
+  GstClock *clock;
+  GstBuffer *buffer;
+  GstCaps *caps;
+  /* a 20 sample audio block (2,5 ms) generated with
+   * gst-launch audiotestsrc wave=silence blocksize=40 num-buffers=3 !
+   *    "audio/x-raw,channels=1,rate=8000" ! mulawenc ! rtppcmupay !
+   *     fakesink dump=1
+   */
+  guint8 in[] = {
+    /* first 4 bytes are rtp-header, next 4 bytes are timestamp */
+    0x80, 0x80, 0x1c, 0x24, 0x46, 0xcd, 0xb7, 0x11, 0x3c, 0x3a, 0x7c, 0x5b,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+  };
+  GstClockTime ts = G_GUINT64_CONSTANT (0);
+  GstClockTime tso = gst_util_uint64_scale (RTP_FRAME_SIZE, GST_SECOND, 8000);
+  /*guint latency = GST_TIME_AS_MSECONDS (num_buffers * tso); */
+  gint i;
+
+  GST_DEBUG ("setup_jitterbuffer");
+  jitterbuffer = gst_check_setup_element ("rtpjitterbuffer");
+  /* we need a clock here */
+  clock = gst_system_clock_obtain ();
+  gst_element_set_clock (jitterbuffer, clock);
+  gst_object_unref (clock);
+  /* setup latency */
+  /* latency would be 7 for 3 buffers here, default is 200
+     g_object_set (G_OBJECT (jitterbuffer), "latency", latency, NULL);
+     GST_INFO_OBJECT (jitterbuffer, "set latency to %u ms", latency);
+   */
+
+  mysrcpad = gst_check_setup_src_pad (jitterbuffer, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (jitterbuffer, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  /* create n buffers */
+  caps = gst_caps_from_string (RTP_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, jitterbuffer, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  for (i = 0; i < num_buffers; i++) {
+    buffer = gst_buffer_new_and_alloc (sizeof (in));
+    gst_buffer_fill (buffer, 0, in, sizeof (in));
+    GST_BUFFER_DTS (buffer) = ts;
+    GST_BUFFER_PTS (buffer) = ts;
+    GST_BUFFER_DURATION (buffer) = tso;
+    gst_mini_object_weak_ref (GST_MINI_OBJECT (buffer), buffer_dropped, NULL);
+    GST_DEBUG ("created buffer: %p", buffer);
+
+    if (!i)
+      GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
+
+    inbuffers = g_list_append (inbuffers, buffer);
+
+    /* hackish way to update the rtp header */
+    in[1] = 0x00;
+    in[3]++;                    /* seqnumber */
+    in[7] += RTP_FRAME_SIZE;    /* inc. timestamp with framesize */
+    ts += tso;
+  }
+  num_dropped = 0;
+
+  return jitterbuffer;
+}
+
+static GstStateChangeReturn
+start_jitterbuffer (GstElement * jitterbuffer)
+{
+  GstStateChangeReturn ret;
+  GstClockTime now;
+  GstClock *clock;
+
+  clock = gst_element_get_clock (jitterbuffer);
+  now = gst_clock_get_time (clock);
+  gst_object_unref (clock);
+
+  gst_element_set_base_time (jitterbuffer, now);
+  ret = gst_element_set_state (jitterbuffer, GST_STATE_PLAYING);
+
+  return ret;
+}
+
+static void
+cleanup_jitterbuffer (GstElement * jitterbuffer)
+{
+  GST_DEBUG ("cleanup_jitterbuffer");
+
+  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  g_list_free (inbuffers);
+  inbuffers = NULL;
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (jitterbuffer);
+  gst_check_teardown_sink_pad (jitterbuffer);
+  gst_check_teardown_element (jitterbuffer);
+}
+
+static void
+check_jitterbuffer_results (GstElement * jitterbuffer, gint num_buffers)
+{
+  GstBuffer *buffer;
+  GList *node;
+  GstClockTime ts = G_GUINT64_CONSTANT (0);
+  GstClockTime tso = gst_util_uint64_scale (RTP_FRAME_SIZE, GST_SECOND, 8000);
+  GstMapInfo map;
+  guint16 prev_sn = 0, cur_sn;
+  guint32 prev_ts = 0, cur_ts;
+
+  /* sleep for twice the latency */
+  g_usleep (400 * 1000);
+
+  GST_INFO ("of %d buffer %d/%d received/dropped", num_buffers,
+      g_list_length (buffers), num_dropped);
+  /* if this fails, not all buffers have been processed */
+  fail_unless_equals_int ((g_list_length (buffers) + num_dropped), num_buffers);
+
+  /* check the buffer list */
+  fail_unless_equals_int (g_list_length (buffers), num_buffers);
+  for (node = buffers; node; node = g_list_next (node)) {
+    fail_if ((buffer = (GstBuffer *) node->data) == NULL);
+    fail_if (GST_BUFFER_PTS (buffer) != ts);
+    fail_if (GST_BUFFER_DTS (buffer) != ts);
+    gst_buffer_map (buffer, &map, GST_MAP_READ);
+    cur_sn = ((guint16) map.data[2] << 8) | map.data[3];
+    cur_ts = ((guint32) map.data[4] << 24) | ((guint32) map.data[5] << 16) |
+        ((guint32) map.data[6] << 8) | map.data[7];
+    gst_buffer_unmap (buffer, &map);
+
+    if (node != buffers) {
+      fail_unless (cur_sn > prev_sn);
+      fail_unless (cur_ts > prev_ts);
+
+      prev_sn = cur_sn;
+      prev_ts = cur_ts;
+    }
+    ts += tso;
+  }
+}
+
+GST_START_TEST (test_push_forward_seq)
+{
+  GstElement *jitterbuffer;
+  const guint num_buffers = 3;
+  GstBuffer *buffer;
+  GList *node;
+
+  jitterbuffer = setup_jitterbuffer (num_buffers);
+  fail_unless (start_jitterbuffer (jitterbuffer)
+      == GST_STATE_CHANGE_SUCCESS, "could not set to playing");
+
+  /* push buffers: 0,1,2, */
+  for (node = inbuffers; node; node = g_list_next (node)) {
+    buffer = (GstBuffer *) node->data;
+    fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+  }
+
+  /* check the buffer list */
+  check_jitterbuffer_results (jitterbuffer, num_buffers);
+
+  /* cleanup */
+  cleanup_jitterbuffer (jitterbuffer);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_push_backward_seq)
+{
+  GstElement *jitterbuffer;
+  const guint num_buffers = 4;
+  GstBuffer *buffer;
+  GList *node;
+
+  jitterbuffer = setup_jitterbuffer (num_buffers);
+  fail_unless (start_jitterbuffer (jitterbuffer)
+      == GST_STATE_CHANGE_SUCCESS, "could not set to playing");
+
+  /* push buffers: 0,3,2,1 */
+  buffer = (GstBuffer *) inbuffers->data;
+  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+  for (node = g_list_last (inbuffers); node != inbuffers;
+      node = g_list_previous (node)) {
+    buffer = (GstBuffer *) node->data;
+    fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+  }
+
+  /* check the buffer list */
+  check_jitterbuffer_results (jitterbuffer, num_buffers);
+
+  /* cleanup */
+  cleanup_jitterbuffer (jitterbuffer);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_push_unordered)
+{
+  GstElement *jitterbuffer;
+  const guint num_buffers = 4;
+  GstBuffer *buffer;
+
+  jitterbuffer = setup_jitterbuffer (num_buffers);
+  fail_unless (start_jitterbuffer (jitterbuffer)
+      == GST_STATE_CHANGE_SUCCESS, "could not set to playing");
+
+  /* push buffers; 0,2,1,3 */
+  buffer = (GstBuffer *) inbuffers->data;
+  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+  buffer = g_list_nth_data (inbuffers, 2);
+  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+  buffer = g_list_nth_data (inbuffers, 1);
+  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+  buffer = g_list_nth_data (inbuffers, 3);
+  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+
+  /* check the buffer list */
+  check_jitterbuffer_results (jitterbuffer, num_buffers);
+
+  /* cleanup */
+  cleanup_jitterbuffer (jitterbuffer);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_basetime)
+{
+  GstElement *jitterbuffer;
+  const guint num_buffers = 3;
+  GstBuffer *buffer;
+  GList *node;
+  GstClockTime tso = gst_util_uint64_scale (RTP_FRAME_SIZE, GST_SECOND, 8000);
+
+  jitterbuffer = setup_jitterbuffer (num_buffers);
+  fail_unless (start_jitterbuffer (jitterbuffer)
+      == GST_STATE_CHANGE_SUCCESS, "could not set to playing");
+
+  /* push buffers: 2,1,0 */
+  for (node = g_list_last (inbuffers); node; node = g_list_previous (node)) {
+    buffer = (GstBuffer *) node->data;
+    fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+  }
+
+  /* sleep for twice the latency */
+  g_usleep (400 * 1000);
+
+  /* if this fails, not all buffers have been processed */
+  fail_unless_equals_int ((g_list_length (buffers) + num_dropped), num_buffers);
+
+  buffer = (GstBuffer *) buffers->data;
+  fail_unless (GST_BUFFER_DTS (buffer) != (num_buffers * tso));
+  fail_unless (GST_BUFFER_PTS (buffer) != (num_buffers * tso));
+
+  /* cleanup */
+  cleanup_jitterbuffer (jitterbuffer);
+}
+
+GST_END_TEST;
+
+static GstCaps *
+request_pt_map (GstElement * jitterbuffer, guint pt)
+{
+  fail_unless (pt == 0);
+
+  return gst_caps_from_string (RTP_CAPS_STRING);
+}
+
+GST_START_TEST (test_clear_pt_map)
+{
+  GstElement *jitterbuffer;
+  const guint num_buffers = 10;
+  gint i;
+  GstBuffer *buffer;
+  GList *node;
+
+  jitterbuffer = setup_jitterbuffer (num_buffers);
+  fail_unless (start_jitterbuffer (jitterbuffer)
+      == GST_STATE_CHANGE_SUCCESS, "could not set to playing");
+
+  g_signal_connect (jitterbuffer, "request-pt-map", (GCallback)
+      request_pt_map, NULL);
+
+  /* push buffers: 0,1,2, */
+  for (node = inbuffers, i = 0; node && i < 3; node = g_list_next (node), i++) {
+    buffer = (GstBuffer *) node->data;
+    fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+  }
+
+  g_usleep (400 * 1000);
+
+  g_signal_emit_by_name (jitterbuffer, "clear-pt-map", NULL);
+
+  for (; node && i < 10; node = g_list_next (node), i++) {
+    buffer = (GstBuffer *) node->data;
+    fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+  }
+
+  /* check the buffer list */
+  check_jitterbuffer_results (jitterbuffer, num_buffers);
+
+  /* cleanup */
+  cleanup_jitterbuffer (jitterbuffer);
+}
+
+GST_END_TEST;
+
+#define TEST_BUF_CLOCK_RATE 8000
+#define TEST_BUF_PT 0
+#define TEST_BUF_SSRC 0x01BADBAD
+#define TEST_BUF_MS  20
+#define TEST_BUF_DURATION (TEST_BUF_MS * GST_MSECOND)
+#define TEST_BUF_SIZE (64000 * TEST_BUF_MS / 1000)
+#define TEST_RTP_TS_DURATION (TEST_BUF_CLOCK_RATE * TEST_BUF_MS / 1000)
+
+static GstCaps *
+generate_caps (void)
+{
+  return gst_caps_new_simple ("application/x-rtp",
+      "media", G_TYPE_STRING, "audio",
+      "clock-rate", G_TYPE_INT, TEST_BUF_CLOCK_RATE,
+      "encoding-name", G_TYPE_STRING, "TEST",
+      "payload", G_TYPE_INT, TEST_BUF_PT,
+      "ssrc", G_TYPE_UINT, TEST_BUF_SSRC, NULL);
+}
+
+static GstBuffer *
+generate_test_buffer_full (GstClockTime dts, guint seq_num, guint32 rtp_ts)
+{
+  GstBuffer *buf;
+  guint8 *payload;
+  guint i;
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+
+  buf = gst_rtp_buffer_new_allocate (TEST_BUF_SIZE, 0, 0);
+  GST_BUFFER_DTS (buf) = dts;
+
+  gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
+  gst_rtp_buffer_set_payload_type (&rtp, TEST_BUF_PT);
+  gst_rtp_buffer_set_seq (&rtp, seq_num);
+  gst_rtp_buffer_set_timestamp (&rtp, rtp_ts);
+  gst_rtp_buffer_set_ssrc (&rtp, TEST_BUF_SSRC);
+
+  payload = gst_rtp_buffer_get_payload (&rtp);
+  for (i = 0; i < TEST_BUF_SIZE; i++)
+    payload[i] = 0xff;
+
+  gst_rtp_buffer_unmap (&rtp);
+
+  return buf;
+}
+
+static GstBuffer *
+generate_test_buffer (guint seq_num)
+{
+  return generate_test_buffer_full (seq_num * TEST_BUF_DURATION,
+      seq_num, seq_num * TEST_RTP_TS_DURATION);
+}
+
+static GstBuffer *
+generate_test_buffer_rtx (GstClockTime dts, guint seq_num)
+{
+  GstBuffer *buffer = generate_test_buffer_full (dts, seq_num,
+      seq_num * TEST_RTP_TS_DURATION);
+  GST_BUFFER_FLAG_SET (buffer, GST_RTP_BUFFER_FLAG_RETRANSMISSION);
+  return buffer;
+}
+
+static void
+push_test_buffer (GstHarness * h, guint seq_num)
+{
+  gst_harness_set_time (h, seq_num * TEST_BUF_DURATION);
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer (seq_num)));
+}
+
+static gint
+get_rtp_seq_num (GstBuffer * buf)
+{
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+  gint seq;
+  gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+  seq = gst_rtp_buffer_get_seq (&rtp);
+  gst_rtp_buffer_unmap (&rtp);
+  return seq;
+}
+
+#define verify_lost_event(h, exp_seq, exp_ts, exp_dur)                         \
+  G_STMT_START {                                                               \
+    GstEvent *_event;                                                          \
+    const GstStructure *_s;                                                    \
+    const GValue *_value;                                                      \
+    guint _seq;                                                                \
+    GstClockTime _ts;                                                          \
+    GstClockTime _dur;                                                         \
+    _event = gst_harness_pull_event (h);                                       \
+    fail_unless (_event != NULL);                                              \
+    _s = gst_event_get_structure (_event);                                     \
+    fail_unless (_s != NULL);                                                  \
+    fail_unless (gst_structure_get_uint (_s, "seqnum", &_seq));                \
+    _value = gst_structure_get_value (_s, "timestamp");                        \
+    fail_unless (_value && G_VALUE_HOLDS_UINT64 (_value));                     \
+    _ts = g_value_get_uint64 (_value);                                         \
+    _value = gst_structure_get_value (_s, "duration");                         \
+    fail_unless (_value && G_VALUE_HOLDS_UINT64 (_value));                     \
+    _dur = g_value_get_uint64 (_value);                                        \
+    fail_unless_equals_int ((guint16)(exp_seq), _seq);                         \
+    fail_unless_equals_uint64 (exp_ts, _ts);                                   \
+    fail_unless_equals_uint64 (exp_dur, _dur);                                 \
+    gst_event_unref (_event);                                                  \
+  } G_STMT_END
+
+
+#define verify_rtx_event(h, exp_seq, exp_ts, exp_delay, exp_spacing)           \
+  G_STMT_START {                                                               \
+    GstEvent *_event;                                                          \
+    const GstStructure *_s;                                                    \
+    const GValue *_value;                                                      \
+    guint _seq;                                                                \
+    GstClockTime _ts;                                                          \
+    guint _delay;                                                              \
+    GstClockTime _spacing;                                                     \
+    _event = gst_harness_pull_upstream_event (h);                              \
+    fail_unless (_event != NULL);                                              \
+    _s = gst_event_get_structure (_event);                                     \
+    fail_unless (_s != NULL);                                                  \
+    fail_unless (gst_structure_get_uint (_s, "seqnum", &_seq));                \
+    _value = gst_structure_get_value (_s, "running-time");                     \
+    fail_unless (_value && G_VALUE_HOLDS_UINT64 (_value));                     \
+    _ts = g_value_get_uint64 (_value);                                         \
+    fail_unless (gst_structure_get_uint (_s, "delay", &_delay));               \
+    _value = gst_structure_get_value (_s, "packet-spacing");                   \
+    fail_unless (_value && G_VALUE_HOLDS_UINT64 (_value));                     \
+    _spacing = g_value_get_uint64 (_value);                                    \
+    fail_unless_equals_int ((guint16)(exp_seq), _seq);                         \
+    fail_unless_equals_uint64 (exp_ts, _ts);                                   \
+    fail_unless_equals_int (exp_delay, _delay);                                \
+    fail_unless_equals_uint64 (exp_spacing, _spacing);                         \
+    gst_event_unref (_event);                                                  \
+  } G_STMT_END
+
+static gboolean
+verify_jb_stats (GstElement * jb, GstStructure * expected)
+{
+  gboolean ret;
+  GstStructure *actual;
+  g_object_get (jb, "stats", &actual, NULL);
+
+  ret = gst_structure_is_subset (actual, expected);
+
+  if (!ret) {
+    gchar *e_str = gst_structure_to_string (expected);
+    gchar *a_str = gst_structure_to_string (actual);
+    fail_unless (ret, "%s is not a subset of %s", e_str, a_str);
+    g_free (e_str);
+    g_free (a_str);
+  }
+
+  gst_structure_free (expected);
+  gst_structure_free (actual);
+
+  return ret;
+}
+
+static guint
+construct_deterministic_initial_state (GstHarness * h, gint latency_ms)
+{
+  guint next_seqnum = latency_ms / TEST_BUF_MS + 1;
+  guint seqnum;
+  gint i;
+
+  g_assert (latency_ms % TEST_BUF_MS == 0);
+
+  gst_harness_set_src_caps (h, generate_caps ());
+  g_object_set (h->element, "latency", latency_ms, NULL);
+
+  /* When the first packet arrives in the jitterbuffer, it will create a
+   * timeout for this packet equal to the latency of the jitterbuffer.
+   * This is known as DEADLINE internally, and is meant to allow the stream
+   * to buffer a bit before starting to push it out, to get some ideas about
+   * the nature of the stream. (packetspacing, jitter etc.)
+   *
+   * When writing tests using the test-clock, it it hence important to know
+   * that by simply advancing the clock to this timeout, you are basically
+   * describing a stream that had one initial packet, and then nothing at all
+   * for the duration of the latency (100ms in this test), which is not a very
+   * usual scenario.
+   *
+   * Instead, a pattern used throughout this test-suite, is to keep the buffers
+   * arriving at their optimal time, until the DEADLINE is reached, and that
+   * then becomes the "starting-point" for the test, because at this time
+   * there should now be no waiting timers (unless using rtx) and we have
+   * a "clean" state to craft the test from.
+   */
+
+  /* Packet 0 arrives at time 0ms, Packet 5 arrives at time 100ms */
+  for (seqnum = 0; seqnum < next_seqnum; seqnum++) {
+    push_test_buffer (h, seqnum);
+    gst_harness_wait_for_clock_id_waits (h, 1, 60);
+  }
+
+  /* We release the DEADLINE timer for packet 0, verify the time is indeed
+   * @latency_ms (100ms) and pull out all the buffers that have been released,
+   * and verify their PTS and sequence numbers.
+   */
+  gst_harness_crank_single_clock_wait (h);
+  fail_unless_equals_int64 (latency_ms * GST_MSECOND,
+      gst_clock_get_time (GST_ELEMENT_CLOCK (h->element)));
+  for (seqnum = 0; seqnum < next_seqnum; seqnum++) {
+    GstBuffer *buf = gst_harness_pull (h);
+    fail_unless_equals_uint64 (seqnum * TEST_BUF_DURATION,
+        GST_BUFFER_PTS (buf));
+    fail_unless_equals_int (seqnum, get_rtp_seq_num (buf));
+    gst_buffer_unref (buf);
+  }
+
+  /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
+  for (i = 0; i < 3; i++)
+    gst_event_unref (gst_harness_pull_event (h));
+
+  /* drop reconfigure event */
+  gst_event_unref (gst_harness_pull_upstream_event (h));
+
+  /* Verify that at this point our queues are empty */
+  fail_unless_equals_int (0, gst_harness_buffers_in_queue (h));
+  fail_unless_equals_int (0, gst_harness_events_in_queue (h));
+
+  return next_seqnum;
+}
+
+GST_START_TEST (test_lost_event)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstBuffer *buf;
+  gint latency_ms = 100;
+  guint next_seqnum;
+  guint missing_seqnum;
+
+  g_object_set (h->element, "do-lost", TRUE, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+
+  /* We will now create a gap in the stream, by skipping one sequence-number,
+   * and push the following packet.
+   */
+  missing_seqnum = next_seqnum;
+  next_seqnum += 1;
+  push_test_buffer (h, next_seqnum);
+
+  /* This packet (@next_seqnum) will now be held back, awaiting the missing one,
+   * verify that this is the case:
+   */
+  fail_unless_equals_int (0, gst_harness_buffers_in_queue (h));
+  fail_unless_equals_int (0, gst_harness_events_in_queue (h));
+
+  /* The lost-timeout for the missing packet will now be its pts + latency, so
+   * now we will simply crank the clock to advance to this point in time, and
+   * check that we get a lost-event, as well as the last packet we pushed in.
+   */
+  gst_harness_crank_single_clock_wait (h);
+  verify_lost_event (h, missing_seqnum,
+      missing_seqnum * TEST_BUF_DURATION, TEST_BUF_DURATION);
+
+  buf = gst_harness_pull (h);
+  fail_unless_equals_uint64 (next_seqnum * TEST_BUF_DURATION,
+      GST_BUFFER_PTS (buf));
+  fail_unless_equals_int (next_seqnum, get_rtp_seq_num (buf));
+  gst_buffer_unref (buf);
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum,
+              "num-lost", G_TYPE_UINT64, (guint64) 1, NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_only_one_lost_event_on_large_gaps)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstTestClock *testclock;
+  GstBuffer *out_buf;
+  guint next_seqnum;
+  gint latency_ms = 200;
+  gint num_lost_events = latency_ms / TEST_BUF_MS;
+  gint i;
+
+  testclock = gst_harness_get_testclock (h);
+  /* Need to set max-misorder-time and max-dropout-time to 0 so the
+   * jitterbuffer does not base them on packet rate calculations.
+   * If it does, out gap is big enough to be considered a new stream and
+   * we wait for a few consecutive packets just to be sure
+   */
+  g_object_set (h->element, "do-lost", TRUE,
+      "max-misorder-time", 0, "max-dropout-time", 0, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+
+  /* move time ahead to just before 10 seconds */
+  gst_harness_set_time (h, 10 * GST_SECOND - 1);
+
+  /* check that we have no pending waits */
+  fail_unless_equals_int (0, gst_test_clock_peek_id_count (testclock));
+
+  /* a buffer now arrives perfectly on time */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (500)));
+
+  /* release the wait, advancing the clock to 10 sec */
+  fail_unless (gst_harness_crank_single_clock_wait (h));
+
+  /* we should now receive a packet-lost-event for buffers 11 through 489 ... */
+  verify_lost_event (h, next_seqnum,
+      next_seqnum * TEST_BUF_DURATION, TEST_BUF_DURATION * (490 - next_seqnum));
+
+  /* ... as well as 490 (since at 10 sec 490 is too late) */
+  verify_lost_event (h, 490, 490 * TEST_BUF_DURATION, TEST_BUF_DURATION);
+
+  /* we get as many lost events as the the number of *
+   * buffers the jitterbuffer is able to wait for */
+  for (i = 1; i < num_lost_events; i++) {
+    fail_unless (gst_harness_crank_single_clock_wait (h));
+    verify_lost_event (h, 490 + i, (490 + i) * TEST_BUF_DURATION,
+        TEST_BUF_DURATION);
+  }
+
+  /* and then the buffer is released */
+  out_buf = gst_harness_pull (h);
+  fail_unless (GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DISCONT));
+  fail_unless_equals_int (500, get_rtp_seq_num (out_buf));
+  fail_unless_equals_uint64 (10 * GST_SECOND, GST_BUFFER_DTS (out_buf));
+  fail_unless_equals_uint64 (10 * GST_SECOND, GST_BUFFER_PTS (out_buf));
+  gst_buffer_unref (out_buf);
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-lost", G_TYPE_UINT64, (guint64) 489, NULL)));
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_two_lost_one_arrives_in_time)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstTestClock *testclock;
+  GstClockID id;
+  GstBuffer *buf;
+  gint latency_ms = 100;
+  guint next_seqnum;
+  guint first_missing;
+  guint second_missing;
+  guint current_arrived;
+
+  testclock = gst_harness_get_testclock (h);
+  g_object_set (h->element, "do-lost", TRUE, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+
+  /* hop over 2 packets and make another one (gap of 2) */
+  first_missing = next_seqnum;
+  second_missing = next_seqnum + 1;
+  current_arrived = next_seqnum + 2;
+  push_test_buffer (h, current_arrived);
+
+  /* verify that the jitterbuffer now wait for the latest moment it can push the
+   * @first_missing packet out.
+   */
+  gst_test_clock_wait_for_next_pending_id (testclock, &id);
+  fail_unless_equals_uint64 (first_missing * TEST_BUF_DURATION +
+      latency_ms * GST_MSECOND, gst_clock_id_get_time (id));
+  gst_clock_id_unref (id);
+
+  /* let the time expire... */
+  fail_unless (gst_harness_crank_single_clock_wait (h));
+
+  /* we should now receive a packet-lost-event */
+  verify_lost_event (h, first_missing,
+      first_missing * TEST_BUF_DURATION, TEST_BUF_DURATION);
+
+  /* @second_missing now arrives just in time */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (second_missing)));
+
+  /* verify that @second_missing made it through! */
+  buf = gst_harness_pull (h);
+  fail_unless (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT));
+  fail_unless_equals_int (second_missing, get_rtp_seq_num (buf));
+  gst_buffer_unref (buf);
+
+  /* and see that @current_arrived now also is pushed */
+  buf = gst_harness_pull (h);
+  fail_unless (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT));
+  fail_unless_equals_int (current_arrived, get_rtp_seq_num (buf));
+  gst_buffer_unref (buf);
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum + 2,
+              "num-lost", G_TYPE_UINT64, (guint64) 1, NULL)));
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_late_packets_still_makes_lost_events)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstBuffer *out_buf;
+  gint latency_ms = 100;
+  guint next_seqnum;
+  guint seqnum;
+  GstClockTime now;
+
+  g_object_set (h->element, "do-lost", TRUE, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+
+  /* jump 10 seconds forward in time */
+  now = 10 * GST_SECOND;
+  gst_harness_set_time (h, now);
+
+  /* push a packet with a gap of 2, that now is very late */
+  seqnum = next_seqnum + 2;
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_full (now,
+              seqnum, seqnum * TEST_RTP_TS_DURATION)));
+
+  /* we should now receive packet-lost-events for the gap 
+   * FIXME: The timeout and duration here are a bit crap...
+   */
+  verify_lost_event (h, next_seqnum, 3400 * GST_MSECOND, 6500 * GST_MSECOND);
+  verify_lost_event (h, next_seqnum + 1,
+      9900 * GST_MSECOND, 3300 * GST_MSECOND);
+
+  /* verify that packet @seqnum made it through! */
+  out_buf = gst_harness_pull (h);
+  fail_unless (GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DISCONT));
+  fail_unless_equals_int (seqnum, get_rtp_seq_num (out_buf));
+  gst_buffer_unref (out_buf);
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum + 1,
+              "num-lost", G_TYPE_UINT64, (guint64) 2, NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_num_late_when_considered_lost_arrives)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gboolean do_lost = __i__ != 0;
+  gint latency_ms = 100;
+  guint next_seqnum;
+
+  g_object_set (h->element, "do-lost", do_lost, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+
+  /* gap of 1 */
+  push_test_buffer (h, next_seqnum + 1);
+
+  /* crank to trigger lost-event */
+  gst_harness_crank_single_clock_wait (h);
+
+  if (do_lost) {
+    /* we should now receive packet-lost-events for the missing packet */
+    verify_lost_event (h, next_seqnum,
+        next_seqnum * TEST_BUF_DURATION, TEST_BUF_DURATION);
+  }
+
+  /* pull out the pushed packet */
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* we have one lost packet in the stats */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum + 1,
+              "num-lost", G_TYPE_UINT64, (guint64) 1,
+              "num-late", G_TYPE_UINT64, (guint64) 0, NULL)));
+
+  /* the missing packet now arrives (too late) */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (next_seqnum)));
+
+  /* and this increments num-late */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum + 1,
+              "num-lost", G_TYPE_UINT64, (guint64) 1,
+              "num-late", G_TYPE_UINT64, (guint64) 1, NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_lost_event_uses_pts)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstClockTime now;
+  gint latency_ms = 100;
+  guint next_seqnum;
+  guint lost_seqnum;
+
+  g_object_set (h->element, "do-lost", TRUE, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+
+  /* hop over 1 packets and make another one (gap of 1), but due to
+     network delays, this packets is also grossly late */
+  lost_seqnum = next_seqnum;
+  next_seqnum += 1;
+
+  /* advance the clock to the latest time packet @next_seqnum could arrive */
+  now = next_seqnum * TEST_BUF_DURATION + latency_ms * GST_MSECOND;
+  gst_harness_set_time (h, now);
+  gst_harness_push (h, generate_test_buffer_full (now, next_seqnum,
+          next_seqnum * TEST_RTP_TS_DURATION));
+
+  /* we should now have received a packet-lost-event for buffer 3 */
+  verify_lost_event (h, lost_seqnum,
+      lost_seqnum * TEST_BUF_DURATION, TEST_BUF_DURATION);
+
+  /* and pull out packet 4 */
+  gst_buffer_unref (gst_harness_pull (h));
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum,
+              "num-lost", G_TYPE_UINT64, (guint64) 1, NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_lost_event_with_backwards_rtptime)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gint latency_ms = 40;
+
+  g_object_set (h->element, "do-lost", TRUE, NULL);
+  construct_deterministic_initial_state (h, latency_ms);
+
+  /*
+   * For video using B-frames, an expected sequence
+   * could be like this:
+   * (I = I-frame, P = P-frame, B = B-frame)
+   *               ___   ___   ___   ___   ___
+   *          ... | 3 | | 4 | | 5 | | 6 | | 7 |
+   *               –––   –––   –––   –––   –––
+   * rtptime:       3(I)  5(P)  5(P)  4(B)  6(P)
+   * arrival(dts):  3     5     5     5     6
+   *
+   * Notice here that packet 6 (the B frame) make
+   * the rtptime go backwards.
+   *
+   * But we get this:
+   *               ___   ___   _ _   ___   ___
+   *          ... | 3 | | 4 | |   | | 6 | | 7 |
+   *               –––   –––   - -   –––   –––
+   * rtptime:       3(I)  5(P)        4(B)  6(P)
+   * arrival(dts):  3     5           5     6
+   *
+   */
+
+  /* seqnum 3 */
+  push_test_buffer (h, 3);
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* seqnum 4, arriving at time 5 with rtptime 5 */
+  gst_harness_push (h,
+      generate_test_buffer_full (5 * TEST_BUF_DURATION,
+          4, 5 * TEST_RTP_TS_DURATION));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* seqnum 6, arriving at time 5 with rtptime 4,
+     making a gap for missing seqnum 5 */
+  gst_harness_push (h,
+      generate_test_buffer_full (5 * TEST_BUF_DURATION,
+          6, 4 * TEST_RTP_TS_DURATION));
+
+  /* seqnum 7, arriving at time 6 with rtptime 6 */
+  gst_harness_push (h,
+      generate_test_buffer_full (6 * TEST_BUF_DURATION,
+          7, 6 * TEST_RTP_TS_DURATION));
+
+  /* we should now have received a packet-lost-event for seqnum 5,
+     with time 5 and 0 duration */
+  gst_harness_crank_single_clock_wait (h);
+  verify_lost_event (h, 5, 5 * TEST_BUF_DURATION, 0);
+
+  /* and pull out 6 and 7 */
+  gst_buffer_unref (gst_harness_pull (h));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 7,
+              "num-lost", G_TYPE_UINT64, (guint64) 1, NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_all_packets_are_timestamped_zero)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstBuffer *out_buf;
+  gint jb_latency_ms = 100;
+  gint i, b;
+
+  gst_harness_set_src_caps (h, generate_caps ());
+  g_object_set (h->element, "do-lost", TRUE, "latency", jb_latency_ms, NULL);
+
+  /* advance the clock with 10 seconds */
+  gst_harness_set_time (h, 10 * GST_SECOND);
+
+  /* push the first buffer through */
+  gst_buffer_unref (gst_harness_push_and_pull (h, generate_test_buffer (0)));
+
+  /* push some buffers in, all timestamped 0 */
+  for (b = 1; b < 3; b++) {
+    fail_unless_equals_int (GST_FLOW_OK,
+        gst_harness_push (h,
+            generate_test_buffer_full (0 * GST_MSECOND, b, 0)));
+
+    /* check for the buffer coming out that was pushed in */
+    out_buf = gst_harness_pull (h);
+    fail_unless_equals_uint64 (0, GST_BUFFER_DTS (out_buf));
+    fail_unless_equals_uint64 (0, GST_BUFFER_PTS (out_buf));
+    gst_buffer_unref (out_buf);
+  }
+
+  /* hop over 2 packets and make another one (gap of 2) */
+  b = 5;
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer_full (0 * GST_MSECOND, b, 0)));
+
+  /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
+  for (i = 0; i < 3; i++)
+    gst_event_unref (gst_harness_pull_event (h));
+
+  /* we should now receive packet-lost-events for buffer 3 and 4 */
+  verify_lost_event (h, 3, 0, 0);
+  verify_lost_event (h, 4, 0, 0);
+
+  /* verify that buffer 5 made it through! */
+  out_buf = gst_harness_pull (h);
+  fail_unless (GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DISCONT));
+  fail_unless_equals_int (5, get_rtp_seq_num (out_buf));
+  gst_buffer_unref (out_buf);
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 4,
+              "num-lost", G_TYPE_UINT64, (guint64) 2, NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_reorder_of_non_equidistant_packets)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstTestClock *testclock;
+  gint latency_ms = 5;
+  GstClockID pending_id;
+  GstClockTime time;
+  gint seq, frame;
+  gint num_init_frames = 1;
+  const GstClockTime frame_dur = TEST_BUF_DURATION;
+  const guint32 frame_rtp_ts_dur = TEST_RTP_TS_DURATION;
+
+  gst_harness_set_src_caps (h, generate_caps ());
+  testclock = gst_harness_get_testclock (h);
+  g_object_set (h->element, "do-lost", TRUE, "latency", latency_ms, NULL);
+
+  for (frame = 0, seq = 0; frame < num_init_frames; frame++, seq += 2) {
+    /* Push a couple of packets with identical timestamp, typical for a video
+     * stream where one frame generates multiple packets. */
+    gst_harness_set_time (h, frame * frame_dur);
+    gst_harness_push (h, generate_test_buffer_full (frame * frame_dur,
+            seq, frame * frame_rtp_ts_dur));
+    gst_harness_push (h, generate_test_buffer_full (frame * frame_dur,
+            seq + 1, frame * frame_rtp_ts_dur));
+
+    if (frame == 0)
+      /* deadline for buffer 0 expires */
+      gst_harness_crank_single_clock_wait (h);
+
+    gst_buffer_unref (gst_harness_pull (h));
+    gst_buffer_unref (gst_harness_pull (h));
+  }
+
+  /* Finally push the last frame reordered */
+  gst_harness_set_time (h, frame * frame_dur);
+  gst_harness_push (h, generate_test_buffer_full (frame * frame_dur,
+          seq + 1, frame * frame_rtp_ts_dur));
+
+  /* Check the scheduled lost timer. The expected arrival of this packet
+   * should be assumed to be the same as the last packet received since we
+   * don't know wether the missing packet belonged to this or previous
+   * frame. */
+  gst_test_clock_wait_for_next_pending_id (testclock, &pending_id);
+  time = gst_clock_id_get_time (pending_id);
+  fail_unless_equals_int64 (time, frame * frame_dur + latency_ms * GST_MSECOND);
+  gst_clock_id_unref (pending_id);
+
+  /* And then missing packet arrives just in time */
+  gst_harness_set_time (h, time - 1);
+  gst_harness_push (h, generate_test_buffer_full (time - 1, seq,
+          frame * frame_rtp_ts_dur));
+
+  gst_buffer_unref (gst_harness_pull (h));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_loss_equidistant_spacing_with_parameter_packets)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gint latency_ms = 5;
+  gint seq, frame;
+  gint num_init_frames = 10;
+  gint i;
+
+  gst_harness_set_src_caps (h, generate_caps ());
+  g_object_set (h->element, "do-lost", TRUE, "latency", latency_ms, NULL);
+
+  /* drop stream-start, caps, segment */
+  for (i = 0; i < 3; i++)
+    gst_event_unref (gst_harness_pull_event (h));
+
+  for (frame = 0, seq = 0; frame < num_init_frames; frame++, seq++) {
+    gst_harness_set_time (h, frame * TEST_BUF_DURATION);
+    gst_harness_push (h, generate_test_buffer_full (frame * TEST_BUF_DURATION,
+            seq, frame * TEST_RTP_TS_DURATION));
+
+    if (frame == 0)
+      /* deadline for buffer 0 expires */
+      gst_harness_crank_single_clock_wait (h);
+
+    gst_buffer_unref (gst_harness_pull (h));
+  }
+
+  /* Push three packets with same rtptime, simulating parameter packets +
+   * frame. This should not disable equidistant mode as it is common for
+   * certain audio codecs. */
+  for (i = 0; i < 3; i++) {
+    gst_harness_set_time (h, frame * TEST_BUF_DURATION);
+    gst_harness_push (h, generate_test_buffer_full (frame * TEST_BUF_DURATION,
+            seq++, frame * TEST_RTP_TS_DURATION));
+    gst_buffer_unref (gst_harness_pull (h));
+  }
+  frame++;
+
+  /* Finally push the last packet introducing a gap */
+  gst_harness_set_time (h, frame * TEST_BUF_DURATION);
+  gst_harness_push (h, generate_test_buffer_full (frame * TEST_BUF_DURATION,
+          seq + 1, frame * TEST_RTP_TS_DURATION));
+
+  /* Check that the lost event has been generated assuming equidistant
+   * spacing. */
+  verify_lost_event (h, seq,
+      frame * TEST_BUF_DURATION - TEST_BUF_DURATION / 2, TEST_BUF_DURATION / 2);
+
+  gst_buffer_unref (gst_harness_pull (h));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+
+static void
+gst_test_clock_set_time_and_process (GstTestClock * testclock,
+    GstClockTime time)
+{
+  GstClockID id, tid;
+  gst_test_clock_wait_for_next_pending_id (testclock, &id);
+  gst_test_clock_set_time (testclock, time);
+  tid = gst_test_clock_process_next_clock_id (testclock);
+  g_assert (tid == id);
+  gst_clock_id_unref (tid);
+  gst_clock_id_unref (id);
+}
+
+GST_START_TEST (test_rtx_expected_next)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gint latency_ms = 200;
+  guint next_seqnum;
+  GstClockTime timeout;
+  gint rtx_delay_ms;
+  const GstClockTime rtx_retry_timeout_ms = 40;
+
+  g_object_set (h->element, "do-lost", TRUE, NULL);
+  g_object_set (h->element, "do-retransmission", TRUE, NULL);
+  g_object_set (h->element, "rtx-retry-period", 120, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+
+  /* At this point there is already existing a rtx-timer for @next_seqnum,
+   * that will have a timeout of the expected arrival-time for that seqnum,
+   * and a delay equal to 2*jitter==0 and 0.5*packet_spacing==10ms */
+  timeout = next_seqnum * TEST_BUF_DURATION;
+  rtx_delay_ms = 0.5 * TEST_BUF_MS;
+
+  /* We crank the clock to time-out the next scheduled timer */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h, next_seqnum, timeout, rtx_delay_ms, TEST_BUF_DURATION);
+
+  /* now we wait for the next timeout, all following timeouts 40ms in the
+   * future because this is rtx-retry-timeout */
+  rtx_delay_ms += rtx_retry_timeout_ms;
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h, next_seqnum, timeout, rtx_delay_ms, TEST_BUF_DURATION);
+
+  /* And a third time... */
+  rtx_delay_ms += rtx_retry_timeout_ms;
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h, next_seqnum, timeout, rtx_delay_ms, TEST_BUF_DURATION);
+
+  /* we should now receive a packet-lost-event for packet @next_seqnum */
+  gst_harness_crank_single_clock_wait (h);
+  verify_lost_event (h, next_seqnum, timeout, TEST_BUF_DURATION);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_two_missing)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gint latency_ms = 200;
+  guint next_seqnum;
+  GstClockTime last_rtx_request, now;
+  gint rtx_delay_ms = 0.5 * TEST_BUF_MS;
+
+  g_object_set (h->element, "do-retransmission", TRUE, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+  fail_unless_equals_int (11, next_seqnum);
+
+  /*
+   * The expected sequence of buffers is this:
+   *      ____   ____   ____   ____
+   * ... | 10 | | 11 | | 12 | | 13 |
+   *      ––––   ––––   ––––   ––––
+   *      200ms  220ms  240ms  260ms
+   *
+   * But instead we get this:
+   *      ____    _ _    _ _   ____
+   * ... | 10 |  |   |  |   | | 13 |
+   *      ––––    - -    - -   ––––
+   *      200ms                260ms
+   *
+   * Now it is important to note that the next thing that happens is that
+   * the RTX timeout for packet 11 will happen at time 230ms, so we crank
+   * the timer thread to advance the time to this:
+   */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h, 11, 11 * TEST_BUF_DURATION,
+      rtx_delay_ms, TEST_BUF_DURATION);
+  last_rtx_request = gst_clock_get_time (GST_ELEMENT_CLOCK (h->element));
+  fail_unless_equals_int64 (last_rtx_request,
+      11 * TEST_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+  gst_harness_wait_for_clock_id_waits (h, 1, 60);
+
+  /* The next scheduled RTX for packet 11 is now at 230 + 40 = 270ms,
+     so the next thing that happens is that buffer 13 arrives in perfect time: */
+  now = 13 * TEST_BUF_DURATION;
+  gst_harness_set_time (h, now);
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h,
+          generate_test_buffer_full (now, 13, 13 * TEST_RTP_TS_DURATION)));
+
+  /*
+   *
+   * This will estimate the dts on the two missing packets to:
+   *      ____   ____
+   * ... | 11 | | 12 | ...
+   *      ––––   ––––
+   *      220ms  240ms
+   *
+   * And given their regular interspacing of 20ms, it will schedule two RTX
+   * timers for them like so:
+   *
+   *      ____   ____
+   * ... | 11 | | 12 | ...
+   *      ––––   ––––
+   *      230ms  250ms
+   *
+   * There are however two problems, packet 11 we have already sent one RTX for
+   * and its timeout is currently at 270ms, so we should not tamper with that,
+   * and as for packet 12, 250ms has already expired, so we now expect to see
+   * an rtx-event being sent for packet 12 immediately:
+   */
+  verify_rtx_event (h, 12, 12 * TEST_BUF_DURATION,
+      rtx_delay_ms, TEST_BUF_DURATION);
+
+  /* and another crank will see the second RTX event being sent for packet 11 */
+  gst_harness_crank_single_clock_wait (h);
+  rtx_delay_ms += 40;
+  verify_rtx_event (h, 11, 11 * TEST_BUF_DURATION,
+      rtx_delay_ms, TEST_BUF_DURATION);
+  last_rtx_request = gst_clock_get_time (GST_ELEMENT_CLOCK (h->element));
+  fail_unless_equals_int64 (last_rtx_request,
+      11 * TEST_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_buffer_arrives_just_in_time)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gint latency_ms = 5 * TEST_BUF_MS;
+  gint next_seqnum;
+  GstBuffer *buffer;
+  GstClockTime now, last_rtx_request;
+  gint rtx_delay_ms = 0.5 * TEST_BUF_MS;
+
+  g_object_set (h->element, "do-retransmission", TRUE,
+      "rtx-max-retries", 1, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+
+  /* Crank clock to send retransmission events requesting seqnum 6 which has
+   * not arrived yet. */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h, next_seqnum,
+      next_seqnum * TEST_BUF_DURATION, rtx_delay_ms, TEST_BUF_DURATION);
+
+  last_rtx_request = gst_clock_get_time (GST_ELEMENT_CLOCK (h->element));
+  fail_unless_equals_int64 (last_rtx_request,
+      next_seqnum * TEST_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+
+  /* seqnum 6 arrives just before it times out and is considered lost */
+  now = 200 * GST_MSECOND;
+  gst_harness_set_time (h, now);
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, next_seqnum)));
+  buffer = gst_harness_pull (h);
+  fail_unless_equals_int (next_seqnum, get_rtp_seq_num (buffer));
+  gst_buffer_unref (buffer);
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum + 1,
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "rtx-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) (now - last_rtx_request),
+              NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_buffer_arrives_too_late)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gint latency_ms = 5 * TEST_BUF_MS;
+  gint next_seqnum;
+  GstClockTime now, last_rtx_request;
+  gint rtx_delay_ms = 0.5 * TEST_BUF_MS;
+
+  g_object_set (h->element, "do-retransmission", TRUE,
+      "do-lost", TRUE, "rtx-max-retries", 1, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+
+  /* Crank clock to send retransmission events requesting seqnum 6 which has
+   * not arrived yet. */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h, next_seqnum,
+      next_seqnum * TEST_BUF_DURATION, rtx_delay_ms, TEST_BUF_DURATION);
+
+  last_rtx_request = gst_clock_get_time (GST_ELEMENT_CLOCK (h->element));
+  fail_unless_equals_int64 (last_rtx_request,
+      next_seqnum * TEST_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+
+  /* packet @next_seqnum is considered lost */
+  gst_harness_crank_single_clock_wait (h);
+  verify_lost_event (h, next_seqnum,
+      next_seqnum * TEST_BUF_DURATION, TEST_BUF_DURATION);
+
+  /* packet @next_seqnum arrives too late */
+  now = gst_clock_get_time (GST_ELEMENT_CLOCK (h->element));
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, next_seqnum)));
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum,
+              "num-lost", G_TYPE_UINT64, (guint64) 1,
+              "num-late", G_TYPE_UINT64, (guint64) 1,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 0,
+              "rtx-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
+              "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) (now - last_rtx_request),
+              NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_original_buffer_does_not_update_rtx_stats)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gint latency_ms = 100;
+  gint next_seqnum;
+  GstBuffer *buffer;
+  GstClockTime now, last_rtx_request;
+  gint rtx_delay_ms = 0.5 * TEST_BUF_MS;
+
+  g_object_set (h->element, "do-retransmission", TRUE,
+      "rtx-max-retries", 1, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+  fail_unless_equals_int (6, next_seqnum);
+
+  /* Crank clock to send retransmission events requesting @next_seqnum which has
+   * not arrived yet. */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h, next_seqnum,
+      next_seqnum * TEST_BUF_DURATION, rtx_delay_ms, TEST_BUF_DURATION);
+
+  last_rtx_request = gst_clock_get_time (GST_ELEMENT_CLOCK (h->element));
+  fail_unless_equals_int64 (last_rtx_request,
+      next_seqnum * TEST_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+
+  /* ORIGINAL seqnum 6 arrives just before it times out and is considered
+   * lost. */
+  now = 200 * GST_MSECOND;
+  gst_harness_set_time (h, now);
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_full (now,
+              next_seqnum, next_seqnum * TEST_RTP_TS_DURATION)));
+  buffer = gst_harness_pull (h);
+  fail_unless_equals_int (next_seqnum, get_rtp_seq_num (buffer));
+  gst_buffer_unref (buffer);
+
+  /* due to the advance in time, we will now also have sent
+     an rtx-request for 7 */
+  next_seqnum++;
+  verify_rtx_event (h, next_seqnum,
+      next_seqnum * TEST_BUF_DURATION, rtx_delay_ms, TEST_BUF_DURATION);
+
+  /* The original buffer does not count in the RTX stats. */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum,
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "num-late", G_TYPE_UINT64, (guint64) 0,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 0,
+              "rtx-count", G_TYPE_UINT64, (guint64) 2,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
+              "rtx-per-packet", G_TYPE_DOUBLE, 0.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) 0, NULL)));
+
+  /* Now the retransmitted packet arrives and stats should be updated. Note
+   * that the buffer arrives in time and should not be considered late, but
+   * a duplicate. */
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, 6)));
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum,
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "num-late", G_TYPE_UINT64, (guint64) 0,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 1,
+              "rtx-count", G_TYPE_UINT64, (guint64) 2,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
+              "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) (now - last_rtx_request),
+              NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_duplicate_packet_updates_rtx_stats)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gint latency_ms = 100;
+  gint next_seqnum;
+  GstClockTime now, rtx_request_6, rtx_request_7;
+  gint rtx_delay_ms = 0.5 * TEST_BUF_MS;
+  gint i;
+
+  g_object_set (h->element, "do-retransmission", TRUE, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+  fail_unless_equals_int (6, next_seqnum);
+
+  /* Push packet 8 so that 6 and 7 is missing */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (8)));
+
+  /* Wait for NACKs on 6 and 7 */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h, 6, 6 * TEST_BUF_DURATION,
+      rtx_delay_ms, TEST_BUF_DURATION);
+  rtx_request_6 = gst_clock_get_time (GST_ELEMENT_CLOCK (h->element));
+  fail_unless_equals_int64 (rtx_request_6,
+      6 * TEST_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h,
+      7, 7 * TEST_BUF_DURATION, rtx_delay_ms, TEST_BUF_DURATION);
+  rtx_request_7 = gst_clock_get_time (GST_ELEMENT_CLOCK (h->element));
+  fail_unless_equals_int64 (rtx_request_7,
+      7 * TEST_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+
+  /* Original packet 7 arrives */
+  now = 150 * GST_MSECOND;
+  gst_harness_set_time (h, now);
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_full (now, 7, 7 * TEST_RTP_TS_DURATION)));
+
+  /* We're still waiting for packet 6, so 7 should not be pushed */
+  gst_harness_wait_for_clock_id_waits (h, 1, 60);
+  fail_unless_equals_int (gst_harness_buffers_in_queue (h), 0);
+
+  /* The original buffer does not count in the RTX stats. */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "num-late", G_TYPE_UINT64, (guint64) 0,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 0,
+              "rtx-count", G_TYPE_UINT64, (guint64) 2,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
+              "rtx-per-packet", G_TYPE_DOUBLE, 0.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) 0, NULL)));
+
+  /* Push RTX packet 7. Should be dropped as duplicate but update RTX stats. */
+  now = 160 * GST_MSECOND;
+  gst_harness_set_time (h, now);
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, 7)));
+  gst_harness_wait_for_clock_id_waits (h, 1, 60);
+  fail_unless_equals_int (gst_harness_buffers_in_queue (h), 0);
+
+  /* Check RTX stats with updated num-duplicates and rtx-rtt fields */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum,
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "num-late", G_TYPE_UINT64, (guint64) 0,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 1,
+              "rtx-count", G_TYPE_UINT64, (guint64) 2,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
+              "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) (now - rtx_request_7),
+              NULL)));
+
+  /* RTX packet 6 arrives, both 6, 7 and 8 is ready to be pulled */
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, 6)));
+
+  for (i = 6; i <= 8; i++) {
+    GstBuffer *buf = gst_harness_pull (h);
+    fail_unless_equals_int (i, get_rtp_seq_num (buf));
+    gst_buffer_unref (buf);
+  }
+
+  /* RTX stats is updated with success count increased. */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum + 3,
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "num-late", G_TYPE_UINT64, (guint64) 0,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 1,
+              "rtx-count", G_TYPE_UINT64, (guint64) 2,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64)
+              /* Use the rtx-rtt formula. Can be subject to change though. */
+              ((now - rtx_request_6) + 47 * (now - rtx_request_7)) / 48,
+              NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_buffer_arrives_after_lost_updates_rtx_stats)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gint latency_ms = 100;
+  gint next_seqnum;
+  GstClockTime now, last_rtx_request;
+  gint rtx_delay_ms = 0.5 * TEST_BUF_MS;
+
+  g_object_set (h->element, "do-retransmission", TRUE,
+      "do-lost", TRUE, "rtx-max-retries", 1, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+
+  /* Crank clock to send retransmission events requesting seqnum 6 which has
+   * not arrived yet. */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h, next_seqnum,
+      next_seqnum * TEST_BUF_DURATION, rtx_delay_ms, TEST_BUF_DURATION);
+
+  last_rtx_request = gst_clock_get_time (GST_ELEMENT_CLOCK (h->element));
+  fail_unless_equals_int64 (last_rtx_request,
+      next_seqnum * TEST_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+
+  /* seqnum 6 is considered lost */
+  gst_harness_crank_single_clock_wait (h);
+  verify_lost_event (h, next_seqnum,
+      next_seqnum * TEST_BUF_DURATION, TEST_BUF_DURATION);
+
+  /* seqnum 6 arrives too late */
+  now = gst_clock_get_time (GST_ELEMENT_CLOCK (h->element));
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, next_seqnum)));
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum,
+              "num-lost", G_TYPE_UINT64, (guint64) 1,
+              "num-late", G_TYPE_UINT64, (guint64) 1,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 0,
+              "rtx-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
+              "rtx-per-packet", G_TYPE_DOUBLE, 1.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) (now - last_rtx_request),
+              NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_rtt_larger_than_retry_timeout)
+{
+  /* When RTT is larger than retry period we will send two or more requests
+   * before receiving any retransmission packets */
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gint latency_ms = 100;
+  gint next_seqnum;
+  gint rtx_retry_timeout_ms = 20;
+  gint rtx_delay_ms = 0.5 * TEST_BUF_MS;
+  gint rtt = rtx_retry_timeout_ms * GST_MSECOND + 1;
+  GstClockTime now, first_request, second_request;
+
+  g_object_set (h->element, "do-retransmission", TRUE,
+      "rtx-retry-timeout", rtx_retry_timeout_ms, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+
+  /* Wait for first NACK on 6 */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h, next_seqnum,
+      next_seqnum * TEST_BUF_DURATION, rtx_delay_ms, TEST_BUF_DURATION);
+  first_request = gst_clock_get_time (GST_ELEMENT_CLOCK (h->element));
+  fail_unless_equals_int64 (first_request,
+      next_seqnum * TEST_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+
+  /* Packet @next_seqnum + 1 arrives in time (so that we avoid its EXPECTED
+   * timers to interfer with our test) */
+  push_test_buffer (h, next_seqnum + 1);
+
+  /* Simulating RTT > rtx-retry-timeout, we send a new NACK before receiving
+   * the RTX packet. Wait for second NACK on @next_seqnum */
+  gst_harness_crank_single_clock_wait (h);
+  rtx_delay_ms += rtx_retry_timeout_ms;
+  verify_rtx_event (h, next_seqnum,
+      next_seqnum * TEST_BUF_DURATION, rtx_delay_ms, TEST_BUF_DURATION);
+  second_request = gst_clock_get_time (GST_ELEMENT_CLOCK (h->element));
+  fail_unless_equals_int64 (second_request,
+      next_seqnum * TEST_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+
+  /* The first retransmitted packet arrives */
+  now = first_request + rtt;
+  gst_harness_set_time (h, now);
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, next_seqnum)));
+
+  /* Pull packets @next_seqnum and @next_seqnum + 1 */
+  gst_buffer_unref (gst_harness_pull (h));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* Stats should be updated. Note that RTT is not updated since we cannot be
+   * sure whether the RTX packet is in response to the first or second NACK. */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum + 2,
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "num-late", G_TYPE_UINT64, (guint64) 0,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 0,
+              "rtx-count", G_TYPE_UINT64, (guint64) 2,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-per-packet", G_TYPE_DOUBLE, 2.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) 0, NULL)));
+
+  /* Packet @next_seqnum + 2 arrives in time */
+  push_test_buffer (h, next_seqnum + 2);
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* Now the second retransmitted packet arrives */
+  now = second_request + rtt;
+  gst_harness_set_time (h, now);
+  fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
+          generate_test_buffer_rtx (now, next_seqnum)));
+
+  /* The stats is updated with the correct RTT. */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum + 3,
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "num-late", G_TYPE_UINT64, (guint64) 0,
+              "num-duplicates", G_TYPE_UINT64, (guint64) 1,
+              "rtx-count", G_TYPE_UINT64, (guint64) 2,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-per-packet", G_TYPE_DOUBLE, 2.0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) rtt, NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_no_request_if_time_past_retry_period)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  const gint latency_ms = 200;
+  const gint retry_period_ms = 120;
+  GstTestClock *testclock;
+  GstClockID pending_id;
+  GstClockTime time;
+  gint i;
+
+  gst_harness_set_src_caps (h, generate_caps ());
+  testclock = gst_harness_get_testclock (h);
+
+  g_object_set (h->element, "do-lost", TRUE, NULL);
+  g_object_set (h->element, "do-retransmission", TRUE, NULL);
+  g_object_set (h->element, "latency", latency_ms, NULL);
+  g_object_set (h->element, "rtx-retry-period", retry_period_ms, NULL);
+
+  /* push the first couple of buffers */
+  push_test_buffer (h, 0);
+  push_test_buffer (h, 1);
+
+  /* drop reconfigure event */
+  gst_event_unref (gst_harness_pull_upstream_event (h));
+  /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
+  for (i = 0; i < 3; i++)
+    gst_event_unref (gst_harness_pull_event (h));
+
+  /* Wait for the first EXPECTED timer to be scheduled */
+  gst_test_clock_wait_for_next_pending_id (testclock, &pending_id);
+  time = gst_clock_id_get_time (pending_id);
+  gst_clock_id_unref (pending_id);
+  fail_unless_equals_int64 (time, 2 * TEST_BUF_DURATION + 10 * GST_MSECOND);
+
+  /* Let the first EXPECTED timer time out and be sent. However, set the 'now'
+   * time to be past the retry-period simulating that the jitterbuffer has too
+   * much to do and is not able to process all timers in real-time. In this
+   * case the jitterbuffer should not schedule a new EXPECTED timer as that
+   * would just make matters worse (more unnecessary processing of a request
+   * that is already too late to be valuable). In practice this typically
+   * happens for high loss networks with low RTT. */
+  gst_test_clock_set_time_and_process (testclock,
+      2 * TEST_BUF_DURATION + retry_period_ms * GST_MSECOND + 1);
+
+  /* Verify the event. It could be argued that this request is already too
+   * late and unnecessary. However, in order to keep things simple (for now)
+   * we just keep the already scehduled EXPECTED timer, but refrain from
+   * scheduled another EXPECTED timer */
+  verify_rtx_event (h, 2, 2 * TEST_BUF_DURATION, 10, TEST_BUF_DURATION);
+
+  /* "crank" to reach the DEADLINE for packet 0 */
+  gst_harness_crank_single_clock_wait (h);
+  gst_buffer_unref (gst_harness_pull (h));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  fail_unless_equals_int (0, gst_harness_upstream_events_in_queue (h));
+  fail_unless_equals_int (0, gst_harness_events_in_queue (h));
+
+  /* "crank" to time out the LOST event */
+  gst_harness_crank_single_clock_wait (h);
+  verify_lost_event (h, 2, 2 * TEST_BUF_DURATION, TEST_BUF_DURATION);
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_same_delay_and_retry_timeout)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gint latency_ms = 5 * TEST_BUF_MS;
+  gint next_seqnum;
+  gint rtx_delay_ms = 20;
+  GstClockTime last_rtx_request;
+
+  g_object_set (h->element, "do-retransmission", TRUE,
+      "rtx-max-retries", 3, "rtx-delay", rtx_delay_ms,
+      "rtx-retry-timeout", rtx_delay_ms, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+
+  /* Crank clock to send retransmission events requesting seqnum 6 which has
+   * not arrived yet. */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h, next_seqnum,
+      next_seqnum * TEST_BUF_DURATION, rtx_delay_ms, TEST_BUF_DURATION);
+  /* first rtx for packet @next_seqnum should arrive at the right time */
+  last_rtx_request = gst_clock_get_time (GST_ELEMENT_CLOCK (h->element));
+  fail_unless_equals_int64 (last_rtx_request,
+      next_seqnum * TEST_BUF_DURATION + rtx_delay_ms * GST_MSECOND);
+
+  /* verify we have pulled out all rtx-events */
+  fail_unless_equals_int (0, gst_harness_upstream_events_in_queue (h));
+
+  /* now crank to get the second attempt at packet @next_seqnum */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h, next_seqnum,
+      next_seqnum * TEST_BUF_DURATION, rtx_delay_ms * 2, TEST_BUF_DURATION);
+
+  /* second rtx for seqnum 6 should arrive at 140 + 20ms */
+  last_rtx_request = gst_clock_get_time (GST_ELEMENT_CLOCK (h->element));
+  fail_unless_equals_int64 (last_rtx_request,
+      next_seqnum * TEST_BUF_DURATION + rtx_delay_ms * 2 * GST_MSECOND);
+
+  /* verify we have pulled out all rtx-events */
+  fail_unless_equals_int (0, gst_harness_upstream_events_in_queue (h));
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) next_seqnum,
+              "num-lost", G_TYPE_UINT64, (guint64) 0,
+              "rtx-count", G_TYPE_UINT64, (guint64) 2, NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_with_backwards_rtptime)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gint latency_ms = 40;
+
+  g_object_set (h->element, "do-retransmission", TRUE, NULL);
+  construct_deterministic_initial_state (h, latency_ms);
+
+  /*
+   * For video using B-frames, an expected sequence
+   * could be like this:
+   * (I = I-frame, P = P-frame, B = B-frame)
+   *               ___   ___   ___
+   *          ... | 3 | | 4 | | 5 |
+   *               –––   –––   –––
+   * rtptime:       3(I)  5(P)  4(B)
+   * arrival(dts):  3     5     5
+   *
+   * Notice here that packet 5 (the B frame) make
+   * the rtptime go backwards.
+   */
+
+  /* seqnum 3, arriving at time 3 with rtptime 3 */
+  push_test_buffer (h, 3);
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* seqnum 4, arriving at time 5 with rtptime 5 */
+  gst_harness_push (h, generate_test_buffer_full (5 * TEST_BUF_DURATION,
+          4, 5 * TEST_RTP_TS_DURATION));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* seqnum 5, arriving at time 5 with rtptime 4 */
+  gst_harness_push (h, generate_test_buffer_full (5 * TEST_BUF_DURATION,
+          5, 4 * TEST_RTP_TS_DURATION));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* crank to time-out the rtx-request for seqnum 6, the point here
+     being that the backwards rtptime did not mess up the timeout for
+     the rtx event */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h, 6, 5 * TEST_BUF_DURATION + 15 * GST_MSECOND,
+      17, 35 * GST_MSECOND);
+
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 6,
+              "rtx-count", G_TYPE_UINT64, (guint64) 1,
+              "num-lost", G_TYPE_UINT64, (guint64) 0, NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtx_timer_reuse)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gint latency_ms = 5 * TEST_BUF_MS;
+  gint rtx_delay_ms = 0.5 * TEST_BUF_MS;
+  guint next_seqnum;
+
+  g_object_set (h->element, "do-retransmission", TRUE,
+      "do-lost", TRUE, "rtx-max-retries", 1, NULL);
+  next_seqnum = construct_deterministic_initial_state (h, latency_ms);
+
+  /* crank to timeout the only rtx-request, and the timer will
+   * now reschedule as a lost-timer internally */
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h, next_seqnum,
+      next_seqnum * TEST_BUF_DURATION, rtx_delay_ms, TEST_BUF_DURATION);
+
+  /* but now buffer 6 arrives, and this should now reuse the lost-timer
+   * for 6, as an expected-timer for 7 */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (next_seqnum)));
+
+  /* now crank to timeout the expected-timer for 7 and verify */
+  next_seqnum++;
+  gst_harness_crank_single_clock_wait (h);
+  verify_rtx_event (h, next_seqnum,
+      next_seqnum * TEST_BUF_DURATION, rtx_delay_ms, TEST_BUF_DURATION);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_deadline_ts_offset)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstTestClock *testclock;
+  GstClockID id;
+  const gint jb_latency_ms = 10;
+
+  gst_harness_set_src_caps (h, generate_caps ());
+  testclock = gst_harness_get_testclock (h);
+
+  g_object_set (h->element, "latency", jb_latency_ms, NULL);
+
+  /* push the first buffer in */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (0)));
+
+  /* wait_next_timeout() syncs on the deadline timer */
+  gst_test_clock_wait_for_next_pending_id (testclock, &id);
+  fail_unless_equals_uint64 (jb_latency_ms * GST_MSECOND,
+      gst_clock_id_get_time (id));
+  gst_clock_id_unref (id);
+
+  /* add ts-offset while waiting */
+  g_object_set (h->element, "ts-offset", 20 * GST_MSECOND, NULL);
+
+  gst_test_clock_set_time_and_process (testclock, jb_latency_ms * GST_MSECOND);
+
+  /* wait_next_timeout() syncs on the new deadline timer */
+  gst_test_clock_wait_for_next_pending_id (testclock, &id);
+  fail_unless_equals_uint64 ((20 + jb_latency_ms) * GST_MSECOND,
+      gst_clock_id_get_time (id));
+  gst_clock_id_unref (id);
+
+  /* now make deadline timer timeout */
+  gst_test_clock_set_time_and_process (testclock,
+      (20 + jb_latency_ms) * GST_MSECOND);
+
+  gst_buffer_unref (gst_harness_pull (h));
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_push_big_gap)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstBuffer *buf;
+  const gint num_consecutive = 5;
+  gint i;
+
+  gst_harness_set_src_caps (h, generate_caps ());
+
+  for (i = 0; i < num_consecutive; i++)
+    fail_unless_equals_int (GST_FLOW_OK,
+        gst_harness_push (h, generate_test_buffer (1000 + i)));
+
+  fail_unless (gst_harness_crank_single_clock_wait (h));
+
+  for (i = 0; i < num_consecutive; i++) {
+    GstBuffer *buf = gst_harness_pull (h);
+    fail_unless_equals_int (1000 + i, get_rtp_seq_num (buf));
+    gst_buffer_unref (buf);
+  }
+
+  /* Push more packets from a different sequence number domain
+   * to trigger "big gap" logic. */
+  for (i = 0; i < num_consecutive; i++)
+    fail_unless_equals_int (GST_FLOW_OK,
+        gst_harness_push (h, generate_test_buffer (20000 + i)));
+
+  fail_unless (gst_harness_crank_single_clock_wait (h));
+
+  for (i = 0; i < num_consecutive; i++) {
+    GstBuffer *buf = gst_harness_pull (h);
+    fail_unless_equals_int (20000 + i, get_rtp_seq_num (buf));
+    gst_buffer_unref (buf);
+  }
+
+  /* Final buffer should be pushed straight through */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (20000 + num_consecutive)));
+  buf = gst_harness_pull (h);
+  fail_unless_equals_int (20000 + num_consecutive, get_rtp_seq_num (buf));
+  gst_buffer_unref (buf);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+typedef struct
+{
+  guint seqnum_offset;
+  guint late_buffer;
+} TestLateArrivalInput;
+
+static const TestLateArrivalInput
+    test_considered_lost_packet_in_large_gap_arrives_input[] = {
+  {0, 1}, {0, 2}, {65535, 1}, {65535, 2}, {65534, 1}, {65534, 2}
+};
+
+GST_START_TEST (test_considered_lost_packet_in_large_gap_arrives)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  GstTestClock *testclock;
+  GstClockID id;
+  GstBuffer *buffer;
+  gint jb_latency_ms = 20;
+  const TestLateArrivalInput *test_input =
+      &test_considered_lost_packet_in_large_gap_arrives_input[__i__];
+  guint seq_offset = test_input->seqnum_offset;
+  guint late_buffer = test_input->late_buffer;
+  gint i;
+
+  gst_harness_set_src_caps (h, generate_caps ());
+  testclock = gst_harness_get_testclock (h);
+  g_object_set (h->element, "do-lost", TRUE, "latency", jb_latency_ms, NULL);
+
+  /* first push buffer 0 */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer_full (0 * TEST_BUF_DURATION,
+              0 + seq_offset, 0 * TEST_RTP_TS_DURATION)));
+  fail_unless (gst_harness_crank_single_clock_wait (h));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
+  for (i = 0; i < 3; i++)
+    gst_event_unref (gst_harness_pull_event (h));
+
+  /* hop over 3 packets, and push buffer 4 (gap of 3) */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer_full (4 * TEST_BUF_DURATION,
+              4 + seq_offset, 4 * TEST_RTP_TS_DURATION)));
+
+  /* the jitterbuffer should be waiting for the timeout of a "large gap timer"
+   * for buffer 1 and 2 */
+  gst_test_clock_wait_for_next_pending_id (testclock, &id);
+  fail_unless_equals_uint64 (1 * TEST_BUF_DURATION +
+      jb_latency_ms * GST_MSECOND, gst_clock_id_get_time (id));
+  gst_clock_id_unref (id);
+
+  /* now buffer 1 sneaks in before the lost event for buffer 1 and 2 is
+   * processed */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h,
+          generate_test_buffer_full (late_buffer * TEST_BUF_DURATION,
+              late_buffer + seq_offset, late_buffer * TEST_RTP_TS_DURATION)));
+
+  /* time out for lost packets 1 and 2 (one event, double duration) */
+  fail_unless (gst_harness_crank_single_clock_wait (h));
+  verify_lost_event (h, 1 + seq_offset, 1 * TEST_BUF_DURATION,
+      2 * TEST_BUF_DURATION);
+
+  /* time out for lost packets 3 */
+  fail_unless (gst_harness_crank_single_clock_wait (h));
+  verify_lost_event (h, 3 + seq_offset, 3 * TEST_BUF_DURATION,
+      1 * TEST_BUF_DURATION);
+
+  /* buffer 4 is pushed as normal */
+  buffer = gst_harness_pull (h);
+  fail_unless_equals_int ((4 + seq_offset) & 0xffff, get_rtp_seq_num (buffer));
+  gst_buffer_unref (buffer);
+
+  /* we have lost 3, and one of them arrived eventually, but too late */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 2,
+              "num-lost", G_TYPE_UINT64, (guint64) 3,
+              "num-late", G_TYPE_UINT64, (guint64) 1, NULL)));
+
+  gst_object_unref (testclock);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_performance)
+{
+  GstHarness *h =
+      gst_harness_new_parse
+      ("rtpjitterbuffer do-lost=1 do-retransmission=1 latency=1000");
+  GTimer *timer = g_timer_new ();
+  const gdouble test_duration = 2.0;
+  guint buffers_pushed = 0;
+  guint buffers_received;
+
+  gst_harness_set_src_caps (h, generate_caps ());
+  gst_harness_use_systemclock (h);
+
+  while (g_timer_elapsed (timer, NULL) < test_duration) {
+    /* Simulate 1ms packets */
+    guint n = buffers_pushed * 2;       // every packet also produces a gap
+    guint16 seqnum = n & 0xffff;
+    guint32 rtp_ts = n * 8;
+    GstClockTime dts = n * GST_MSECOND;
+    gst_harness_push (h, generate_test_buffer_full (dts, seqnum, rtp_ts));
+    buffers_pushed++;
+    g_usleep (G_USEC_PER_SEC / 10000);
+  }
+  g_timer_destroy (timer);
+
+  buffers_received = gst_harness_buffers_received (h);
+  GST_INFO ("Pushed %d, received %d (%.1f%%)", buffers_pushed, buffers_received,
+      100.0 * buffers_received / buffers_pushed);
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+static Suite *
+rtpjitterbuffer_suite (void)
+{
+  Suite *s = suite_create ("rtpjitterbuffer");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_push_forward_seq);
+  tcase_add_test (tc_chain, test_push_backward_seq);
+  tcase_add_test (tc_chain, test_push_unordered);
+  tcase_add_test (tc_chain, test_basetime);
+  tcase_add_test (tc_chain, test_clear_pt_map);
+
+  tcase_add_test (tc_chain, test_lost_event);
+  tcase_add_test (tc_chain, test_only_one_lost_event_on_large_gaps);
+  tcase_add_test (tc_chain, test_two_lost_one_arrives_in_time);
+  tcase_add_test (tc_chain, test_late_packets_still_makes_lost_events);
+  tcase_add_test (tc_chain, test_lost_event_uses_pts);
+  tcase_add_test (tc_chain, test_lost_event_with_backwards_rtptime);
+
+  tcase_add_test (tc_chain, test_all_packets_are_timestamped_zero);
+  tcase_add_loop_test (tc_chain, test_num_late_when_considered_lost_arrives, 0,
+      2);
+  tcase_add_test (tc_chain, test_reorder_of_non_equidistant_packets);
+  tcase_add_test (tc_chain,
+      test_loss_equidistant_spacing_with_parameter_packets);
+
+  tcase_add_test (tc_chain, test_rtx_expected_next);
+  tcase_add_test (tc_chain, test_rtx_two_missing);
+  tcase_add_test (tc_chain, test_rtx_buffer_arrives_just_in_time);
+  tcase_add_test (tc_chain, test_rtx_buffer_arrives_too_late);
+  tcase_add_test (tc_chain, test_rtx_original_buffer_does_not_update_rtx_stats);
+  tcase_add_test (tc_chain, test_rtx_duplicate_packet_updates_rtx_stats);
+  tcase_add_test (tc_chain,
+      test_rtx_buffer_arrives_after_lost_updates_rtx_stats);
+  tcase_add_test (tc_chain, test_rtx_rtt_larger_than_retry_timeout);
+  tcase_add_test (tc_chain, test_rtx_no_request_if_time_past_retry_period);
+  tcase_add_test (tc_chain, test_rtx_same_delay_and_retry_timeout);
+  tcase_add_test (tc_chain, test_rtx_with_backwards_rtptime);
+  tcase_add_test (tc_chain, test_rtx_timer_reuse);
+
+  tcase_add_test (tc_chain, test_deadline_ts_offset);
+  tcase_add_test (tc_chain, test_push_big_gap);
+
+  tcase_add_loop_test (tc_chain,
+      test_considered_lost_packet_in_large_gap_arrives, 0,
+      G_N_ELEMENTS (test_considered_lost_packet_in_large_gap_arrives_input));
+
+  tcase_add_test (tc_chain, test_performance);
+
+  return s;
+}
+
+GST_CHECK_MAIN (rtpjitterbuffer);
diff --git a/tests/check/elements/rtpmux.c b/tests/check/elements/rtpmux.c
new file mode 100644
index 0000000..ee03887
--- /dev/null
+++ b/tests/check/elements/rtpmux.c
@@ -0,0 +1,552 @@
+/* GStreamer
+ *
+ * unit test for rtpmux elements
+ *
+ * Copyright 2009 Collabora Ltd.
+ *  @author: Olivier Crete <olivier.crete@collabora.co.uk>
+ * Copyright 2009 Nokia Corp.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/check/gstharness.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/gst.h>
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp"));
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("application/x-rtp"));
+
+typedef void (*check_cb) (GstPad * pad, int i);
+
+static gboolean
+query_func (GstPad * pad, GstObject * noparent, GstQuery * query)
+{
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps **caps = g_object_get_data (G_OBJECT (pad), "caps");
+
+      fail_unless (caps != NULL && *caps != NULL);
+      gst_query_set_caps_result (query, *caps);
+      break;
+    }
+    case GST_QUERY_ACCEPT_CAPS:
+      gst_query_set_accept_caps_result (query, TRUE);
+      break;
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+static GstCaps *
+remove_ssrc_from_caps (GstCaps * caps)
+{
+  GstCaps *copy = gst_caps_copy (caps);
+  GstStructure *s = gst_caps_get_structure (copy, 0);
+  gst_structure_remove_field (s, "ssrc");
+  return copy;
+}
+
+static gboolean
+event_func (GstPad * pad, GstObject * noparent, GstEvent * event)
+{
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+      GstCaps **caps2 = g_object_get_data (G_OBJECT (pad), "caps");
+      GstCaps *caps_no_ssrc;
+      GstCaps *caps2_no_ssrc;
+
+      gst_event_parse_caps (event, &caps);
+      caps_no_ssrc = remove_ssrc_from_caps (caps);
+      caps2_no_ssrc = remove_ssrc_from_caps (*caps2);
+
+      fail_unless (caps2 != NULL && *caps2 != NULL);
+      fail_unless (gst_caps_is_fixed (caps));
+      fail_unless (gst_caps_is_fixed (*caps2));
+
+      fail_unless (gst_caps_is_equal_fixed (caps_no_ssrc, caps2_no_ssrc));
+      gst_caps_unref (caps_no_ssrc);
+      gst_caps_unref (caps2_no_ssrc);
+      break;
+    }
+    default:
+      break;
+  }
+
+  gst_event_unref (event);
+
+  return TRUE;
+}
+
+static void
+test_basic (const gchar * elem_name, const gchar * sink2, int count,
+    check_cb cb)
+{
+  GstElement *rtpmux = NULL;
+  GstPad *reqpad1 = NULL;
+  GstPad *reqpad2 = NULL;
+  GstPad *src1 = NULL;
+  GstPad *src2 = NULL;
+  GstPad *sink = NULL;
+  GstBuffer *inbuf = NULL;
+  GstCaps *src1caps = NULL;
+  GstCaps *src2caps = NULL;
+  GstCaps *sinkcaps = NULL;
+  GstCaps *caps;
+  GstSegment segment;
+  int i;
+
+  rtpmux = gst_check_setup_element (elem_name);
+
+  reqpad1 = gst_element_get_request_pad (rtpmux, "sink_1");
+  fail_unless (reqpad1 != NULL);
+  reqpad2 = gst_element_get_request_pad (rtpmux, sink2);
+  fail_unless (reqpad2 != NULL);
+  sink = gst_check_setup_sink_pad_by_name (rtpmux, &sinktemplate, "src");
+
+  src1 = gst_pad_new_from_static_template (&srctemplate, "src");
+  src2 = gst_pad_new_from_static_template (&srctemplate, "src");
+  fail_unless (gst_pad_link (src1, reqpad1) == GST_PAD_LINK_OK);
+  fail_unless (gst_pad_link (src2, reqpad2) == GST_PAD_LINK_OK);
+  gst_pad_set_query_function (src1, query_func);
+  gst_pad_set_query_function (src2, query_func);
+  gst_pad_set_query_function (sink, query_func);
+  gst_pad_set_event_function (sink, event_func);
+  g_object_set_data (G_OBJECT (src1), "caps", &src1caps);
+  g_object_set_data (G_OBJECT (src2), "caps", &src2caps);
+  g_object_set_data (G_OBJECT (sink), "caps", &sinkcaps);
+
+  src1caps = gst_caps_new_simple ("application/x-rtp",
+      "clock-rate", G_TYPE_INT, 1, "ssrc", G_TYPE_UINT, 11, NULL);
+  src2caps = gst_caps_new_simple ("application/x-rtp",
+      "clock-rate", G_TYPE_INT, 2, "ssrc", G_TYPE_UINT, 12, NULL);
+  sinkcaps = gst_caps_new_simple ("application/x-rtp",
+      "clock-rate", G_TYPE_INT, 3, "ssrc", G_TYPE_UINT, 13, NULL);
+
+  caps = gst_pad_peer_query_caps (src1, NULL);
+  fail_unless (gst_caps_is_empty (caps));
+  gst_caps_unref (caps);
+
+  gst_caps_set_simple (src2caps, "clock-rate", G_TYPE_INT, 3, NULL);
+  caps = gst_pad_peer_query_caps (src1, NULL);
+  gst_caps_unref (caps);
+
+  g_object_set (rtpmux, "seqnum-offset", 100, "timestamp-offset", 1000,
+      "ssrc", 55, NULL);
+
+  fail_unless (gst_element_set_state (rtpmux,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
+  gst_pad_set_active (sink, TRUE);
+  gst_pad_set_active (src1, TRUE);
+  gst_pad_set_active (src2, TRUE);
+
+  fail_unless (gst_pad_push_event (src1,
+          gst_event_new_stream_start ("stream1")));
+  fail_unless (gst_pad_push_event (src2,
+          gst_event_new_stream_start ("stream2")));
+
+  gst_caps_set_simple (sinkcaps,
+      "payload", G_TYPE_INT, 98, "seqnum-offset", G_TYPE_UINT, 100,
+      "timestamp-offset", G_TYPE_UINT, 1000, "ssrc", G_TYPE_UINT, 66, NULL);
+  caps = gst_caps_new_simple ("application/x-rtp",
+      "payload", G_TYPE_INT, 98, "clock-rate", G_TYPE_INT, 3,
+      "seqnum-offset", G_TYPE_UINT, 56, "timestamp-offset", G_TYPE_UINT, 57,
+      "ssrc", G_TYPE_UINT, 66, NULL);
+  fail_unless (gst_pad_set_caps (src1, caps));
+  gst_caps_unref (caps);
+
+  caps = gst_pad_peer_query_caps (sink, NULL);
+  fail_if (gst_caps_is_empty (caps));
+
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  segment.start = 100000;
+  fail_unless (gst_pad_push_event (src1, gst_event_new_segment (&segment)));
+  segment.start = 0;
+  fail_unless (gst_pad_push_event (src2, gst_event_new_segment (&segment)));
+
+
+  for (i = 0; i < count; i++) {
+    GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
+
+    inbuf = gst_rtp_buffer_new_allocate (10, 0, 0);
+    GST_BUFFER_PTS (inbuf) = i * 1000 + 100000;
+    GST_BUFFER_DURATION (inbuf) = 1000;
+
+    gst_rtp_buffer_map (inbuf, GST_MAP_WRITE, &rtpbuffer);
+
+    gst_rtp_buffer_set_version (&rtpbuffer, 2);
+    gst_rtp_buffer_set_payload_type (&rtpbuffer, 98);
+    gst_rtp_buffer_set_ssrc (&rtpbuffer, 44);
+    gst_rtp_buffer_set_timestamp (&rtpbuffer, 200 + i);
+    gst_rtp_buffer_set_seq (&rtpbuffer, 2000 + i);
+    gst_rtp_buffer_unmap (&rtpbuffer);
+    fail_unless (gst_pad_push (src1, inbuf) == GST_FLOW_OK);
+
+    if (buffers)
+      fail_unless (GST_BUFFER_PTS (buffers->data) == i * 1000, "%lld",
+          GST_BUFFER_PTS (buffers->data));
+
+    cb (src2, i);
+
+    g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
+    g_list_free (buffers);
+    buffers = NULL;
+  }
+
+
+  gst_pad_set_active (sink, FALSE);
+  gst_pad_set_active (src1, FALSE);
+  gst_pad_set_active (src2, FALSE);
+  fail_unless (gst_element_set_state (rtpmux,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
+  gst_check_teardown_pad_by_name (rtpmux, "src");
+  gst_object_unref (reqpad1);
+  gst_object_unref (reqpad2);
+  gst_check_teardown_pad_by_name (rtpmux, "sink_1");
+  gst_check_teardown_pad_by_name (rtpmux, sink2);
+  gst_element_release_request_pad (rtpmux, reqpad1);
+  gst_element_release_request_pad (rtpmux, reqpad2);
+
+  gst_caps_unref (caps);
+  gst_caps_replace (&src1caps, NULL);
+  gst_caps_replace (&src2caps, NULL);
+  gst_caps_replace (&sinkcaps, NULL);
+
+  gst_check_teardown_element (rtpmux);
+}
+
+static void
+basic_check_cb (GstPad * pad, int i)
+{
+  GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
+  fail_unless (buffers && g_list_length (buffers) == 1);
+
+  gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer);
+  fail_unless_equals_int (66, gst_rtp_buffer_get_ssrc (&rtpbuffer));
+  fail_unless_equals_int64 (200 - 57 + 1000 + i,
+      gst_rtp_buffer_get_timestamp (&rtpbuffer));
+  fail_unless_equals_int (100 + 1 + i, gst_rtp_buffer_get_seq (&rtpbuffer));
+  gst_rtp_buffer_unmap (&rtpbuffer);
+}
+
+
+GST_START_TEST (test_rtpmux_basic)
+{
+  test_basic ("rtpmux", "sink_2", 10, basic_check_cb);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtpdtmfmux_basic)
+{
+  test_basic ("rtpdtmfmux", "sink_2", 10, basic_check_cb);
+}
+
+GST_END_TEST;
+
+static void
+lock_check_cb (GstPad * pad, int i)
+{
+  GstBuffer *inbuf;
+
+  if (i % 2) {
+    fail_unless (buffers == NULL);
+  } else {
+    GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
+
+    fail_unless (buffers && g_list_length (buffers) == 1);
+    gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer);
+    fail_unless_equals_int (66, gst_rtp_buffer_get_ssrc (&rtpbuffer));
+    fail_unless_equals_int64 (200 - 57 + 1000 + i,
+        gst_rtp_buffer_get_timestamp (&rtpbuffer));
+    fail_unless_equals_int (100 + 1 + i, gst_rtp_buffer_get_seq (&rtpbuffer));
+    gst_rtp_buffer_unmap (&rtpbuffer);
+
+    inbuf = gst_rtp_buffer_new_allocate (10, 0, 0);
+    GST_BUFFER_PTS (inbuf) = i * 1000 + 500;
+    GST_BUFFER_DURATION (inbuf) = 1000;
+    gst_rtp_buffer_map (inbuf, GST_MAP_WRITE, &rtpbuffer);
+    gst_rtp_buffer_set_version (&rtpbuffer, 2);
+    gst_rtp_buffer_set_payload_type (&rtpbuffer, 98);
+    gst_rtp_buffer_set_ssrc (&rtpbuffer, 44);
+    gst_rtp_buffer_set_timestamp (&rtpbuffer, 200 + i);
+    gst_rtp_buffer_set_seq (&rtpbuffer, 2000 + i);
+    gst_rtp_buffer_unmap (&rtpbuffer);
+    fail_unless (gst_pad_push (pad, inbuf) == GST_FLOW_OK);
+
+
+    g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
+    g_list_free (buffers);
+    buffers = NULL;
+  }
+}
+
+GST_START_TEST (test_rtpdtmfmux_lock)
+{
+  test_basic ("rtpdtmfmux", "priority_sink_2", 10, lock_check_cb);
+}
+
+GST_END_TEST;
+
+static GstBuffer *
+generate_test_buffer (guint seq_num, guint ssrc)
+{
+  GstBuffer *buf;
+  guint8 *payload;
+  guint i;
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+  gsize size = 10;
+
+  buf = gst_rtp_buffer_new_allocate (size, 0, 0);
+  GST_BUFFER_DTS (buf) = GST_MSECOND * 20 * seq_num;
+  GST_BUFFER_PTS (buf) = GST_MSECOND * 20 * seq_num;
+
+  gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
+  gst_rtp_buffer_set_payload_type (&rtp, 0);
+  gst_rtp_buffer_set_seq (&rtp, seq_num);
+  gst_rtp_buffer_set_timestamp (&rtp, 160 * seq_num);
+  gst_rtp_buffer_set_ssrc (&rtp, ssrc);
+
+  payload = gst_rtp_buffer_get_payload (&rtp);
+  for (i = 0; i < size; i++)
+    payload[i] = 0xff;
+
+  gst_rtp_buffer_unmap (&rtp);
+
+  return buf;
+}
+
+static guint32
+_rtp_buffer_get_ssrc (GstBuffer * buf)
+{
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+  guint32 ret;
+  g_assert (gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp));
+  ret = gst_rtp_buffer_get_ssrc (&rtp);
+  gst_rtp_buffer_unmap (&rtp);
+  return ret;
+}
+
+GST_START_TEST (test_rtpmux_ssrc_property)
+{
+  GstHarness *h = gst_harness_new_with_padnames ("rtpmux", NULL, "src");
+  GstHarness *h0 = gst_harness_new_with_element (h->element, "sink_0", NULL);
+  GstHarness *h1 = gst_harness_new_with_element (h->element, "sink_1", NULL);
+  GstBuffer *buf0;
+  GstBuffer *buf1;
+
+  /* set ssrc to 111111 */
+  g_object_set (h->element, "ssrc", 111111, NULL);
+
+  /* both sinkpads have their own idea of what the ssrc should be */
+  gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
+  gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");
+
+  /* push on both sinkpads with different ssrc */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h0, generate_test_buffer (0, 222222)));
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h1, generate_test_buffer (0, 333333)));
+
+  buf0 = gst_harness_pull (h);
+  buf1 = gst_harness_pull (h);
+
+  /* we expect the ssrc to be what we specified in the property */
+  fail_unless_equals_int (111111, _rtp_buffer_get_ssrc (buf0));
+  fail_unless_equals_int (111111, _rtp_buffer_get_ssrc (buf1));
+
+  gst_buffer_unref (buf0);
+  gst_buffer_unref (buf1);
+
+  gst_harness_teardown (h0);
+  gst_harness_teardown (h1);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtpmux_ssrc_property_not_set)
+{
+  GstHarness *h = gst_harness_new_with_padnames ("rtpmux", NULL, "src");
+  GstHarness *h0 = gst_harness_new_with_element (h->element, "sink_0", NULL);
+  GstHarness *h1 = gst_harness_new_with_element (h->element, "sink_1", NULL);
+  GstBuffer *buf0;
+  GstBuffer *buf1;
+
+  gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
+  gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");
+
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h0, generate_test_buffer (0, 222222)));
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h1, generate_test_buffer (0, 333333)));
+
+  buf0 = gst_harness_pull (h);
+  buf1 = gst_harness_pull (h);
+
+  /* we expect the ssrc to be the first ssrc that came in */
+  fail_unless_equals_int (222222, _rtp_buffer_get_ssrc (buf0));
+  fail_unless_equals_int (222222, _rtp_buffer_get_ssrc (buf1));
+
+  gst_buffer_unref (buf0);
+  gst_buffer_unref (buf1);
+
+  gst_harness_teardown (h0);
+  gst_harness_teardown (h1);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtpmux_ssrc_downstream_can_overrule)
+{
+  GstHarness *h = gst_harness_new_with_padnames ("rtpmux", NULL, "src");
+  GstHarness *h0 = gst_harness_new_with_element (h->element, "sink_0", NULL);
+  GstHarness *h1 = gst_harness_new_with_element (h->element, "sink_1", NULL);
+  GstBuffer *buf0;
+  GstBuffer *buf1;
+
+  /* downstream is specifying 444444 as ssrc */
+  gst_harness_set_sink_caps_str (h, "application/x-rtp, ssrc=(uint)444444");
+
+  /* rtpmux ssrc is set to 111111 */
+  g_object_set (h->element, "ssrc", 111111, NULL);
+
+  /* while upstream ssrc is 222222 and 333333 */
+  gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
+  gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");
+
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h0, generate_test_buffer (0, 222222)));
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h1, generate_test_buffer (0, 333333)));
+
+  buf0 = gst_harness_pull (h);
+  buf1 = gst_harness_pull (h);
+
+  /* we expect the ssrc to be downstream ssrc */
+  fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf0));
+  fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf1));
+
+  gst_buffer_unref (buf0);
+  gst_buffer_unref (buf1);
+
+  gst_harness_teardown (h0);
+  gst_harness_teardown (h1);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtpmux_ssrc_downstream_dynamic)
+{
+  GstHarness *h = gst_harness_new_parse ("rtpmux ! capsfilter");
+  GstElement *rtpmux = gst_harness_find_element (h, "rtpmux");
+  GstElement *capsfilter = gst_harness_find_element (h, "capsfilter");
+
+  GstHarness *h0 = gst_harness_new_with_element (rtpmux, "sink_0", NULL);
+  GstHarness *h1 = gst_harness_new_with_element (rtpmux, "sink_1", NULL);
+  GstCaps *caps;
+  GstBuffer *buf0;
+  GstBuffer *buf1;
+
+  gst_harness_play (h);
+
+  caps = gst_caps_from_string ("application/x-rtp, ssrc=(uint)444444");
+  g_object_set (capsfilter, "caps", caps, NULL);
+  gst_caps_unref (caps);
+
+  /* while upstream ssrc is 222222 and 333333 */
+  gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
+  gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");
+
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h0, generate_test_buffer (0, 222222)));
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h1, generate_test_buffer (0, 333333)));
+
+  /* we expect the ssrc to be downstream ssrc (444444) */
+  buf0 = gst_harness_pull (h);
+  buf1 = gst_harness_pull (h);
+  fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf0));
+  fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf1));
+  gst_buffer_unref (buf0);
+  gst_buffer_unref (buf1);
+
+  caps = gst_caps_from_string ("application/x-rtp, ssrc=(uint)555555");
+  g_object_set (capsfilter, "caps", caps, NULL);
+  gst_caps_unref (caps);
+
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h0, generate_test_buffer (0, 222222)));
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h1, generate_test_buffer (0, 333333)));
+
+  /* we expect the ssrc to be the new downstream ssrc (555555) */
+  buf0 = gst_harness_pull (h);
+  buf1 = gst_harness_pull (h);
+  fail_unless_equals_int (555555, _rtp_buffer_get_ssrc (buf0));
+  fail_unless_equals_int (555555, _rtp_buffer_get_ssrc (buf1));
+  gst_buffer_unref (buf0);
+  gst_buffer_unref (buf1);
+
+  gst_object_unref (rtpmux);
+  gst_object_unref (capsfilter);
+  gst_harness_teardown (h0);
+  gst_harness_teardown (h1);
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+static Suite *
+rtpmux_suite (void)
+{
+  Suite *s = suite_create ("rtpmux");
+  TCase *tc_chain;
+
+  tc_chain = tcase_create ("rtpmux_basic");
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_rtpmux_basic);
+  tcase_add_test (tc_chain, test_rtpmux_ssrc_property);
+  tcase_add_test (tc_chain, test_rtpmux_ssrc_property_not_set);
+  tcase_add_test (tc_chain, test_rtpmux_ssrc_downstream_can_overrule);
+  tcase_add_test (tc_chain, test_rtpmux_ssrc_downstream_dynamic);
+
+  tc_chain = tcase_create ("rtpdtmfmux_basic");
+  tcase_add_test (tc_chain, test_rtpdtmfmux_basic);
+  suite_add_tcase (s, tc_chain);
+
+  tc_chain = tcase_create ("rtpdtmfmux_lock");
+  tcase_add_test (tc_chain, test_rtpdtmfmux_lock);
+  suite_add_tcase (s, tc_chain);
+
+  return s;
+}
+
+GST_CHECK_MAIN (rtpmux)
diff --git a/tests/check/elements/rtprtx.c b/tests/check/elements/rtprtx.c
new file mode 100644
index 0000000..45d41c6
--- /dev/null
+++ b/tests/check/elements/rtprtx.c
@@ -0,0 +1,676 @@
+/* GStreamer
+ *
+ * Copyright (C) 2013 Collabora Ltd.
+ *   @author Julien Isorce <julien.isorce@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <gst/check/gstcheck.h>
+#include <gst/check/gstharness.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#define verify_buf(buf, is_rtx, expected_ssrc, expted_pt, expected_seqnum)       \
+  G_STMT_START {                                                                 \
+    GstRTPBuffer _rtp = GST_RTP_BUFFER_INIT;                                     \
+    fail_unless (gst_rtp_buffer_map (buf, GST_MAP_READ, &_rtp));                 \
+    fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&_rtp), expected_ssrc);     \
+    fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&_rtp), expted_pt); \
+    if (!(is_rtx)) {                                                             \
+      fail_unless_equals_int (gst_rtp_buffer_get_seq (&_rtp), expected_seqnum);  \
+    } else {                                                                     \
+      fail_unless_equals_int (GST_READ_UINT16_BE (gst_rtp_buffer_get_payload     \
+              (&_rtp)), expected_seqnum);                                        \
+    }                                                                            \
+    gst_rtp_buffer_unmap (&_rtp);                                                \
+  } G_STMT_END
+
+#define pull_and_verify(h, is_rtx, expected_ssrc, expted_pt, expected_seqnum) \
+  G_STMT_START {                                                              \
+    GstBuffer *_buf = gst_harness_pull (h);                                   \
+    verify_buf (_buf, is_rtx, expected_ssrc, expted_pt, expected_seqnum);     \
+    gst_buffer_unref (_buf);                                                  \
+  } G_STMT_END
+
+#define push_pull_and_verify(h, buf, is_rtx, expected_ssrc, expted_pt, expected_seqnum) \
+  G_STMT_START {                                                                        \
+    gst_harness_push (h, buf);                                                          \
+    pull_and_verify (h, is_rtx, expected_ssrc, expted_pt, expected_seqnum);             \
+  } G_STMT_END
+
+static GstEvent *
+create_rtx_event (guint32 ssrc, guint8 payload_type, guint16 seqnum)
+{
+  return gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+      gst_structure_new ("GstRTPRetransmissionRequest",
+          "seqnum", G_TYPE_UINT, seqnum,
+          "ssrc", G_TYPE_UINT, ssrc,
+          "payload-type", G_TYPE_UINT, payload_type, NULL));
+}
+
+static void
+compare_rtp_packets (GstBuffer * a, GstBuffer * b)
+{
+  GstRTPBuffer rtp_a = GST_RTP_BUFFER_INIT;
+  GstRTPBuffer rtp_b = GST_RTP_BUFFER_INIT;
+
+  gst_rtp_buffer_map (a, GST_MAP_READ, &rtp_a);
+  gst_rtp_buffer_map (b, GST_MAP_READ, &rtp_b);
+
+  fail_unless_equals_int (gst_rtp_buffer_get_header_len (&rtp_a),
+      gst_rtp_buffer_get_header_len (&rtp_b));
+  fail_unless_equals_int (gst_rtp_buffer_get_version (&rtp_a),
+      gst_rtp_buffer_get_version (&rtp_b));
+  fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&rtp_a),
+      gst_rtp_buffer_get_ssrc (&rtp_b));
+  fail_unless_equals_int (gst_rtp_buffer_get_seq (&rtp_a),
+      gst_rtp_buffer_get_seq (&rtp_b));
+  fail_unless_equals_int (gst_rtp_buffer_get_csrc_count (&rtp_a),
+      gst_rtp_buffer_get_csrc_count (&rtp_b));
+  fail_unless_equals_int (gst_rtp_buffer_get_marker (&rtp_a),
+      gst_rtp_buffer_get_marker (&rtp_b));
+  fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp_a),
+      gst_rtp_buffer_get_payload_type (&rtp_b));
+  fail_unless_equals_int (gst_rtp_buffer_get_timestamp (&rtp_a),
+      gst_rtp_buffer_get_timestamp (&rtp_b));
+  fail_unless_equals_int (gst_rtp_buffer_get_extension (&rtp_a),
+      gst_rtp_buffer_get_extension (&rtp_b));
+
+  fail_unless_equals_int (gst_rtp_buffer_get_payload_len (&rtp_a),
+      gst_rtp_buffer_get_payload_len (&rtp_b));
+  fail_unless_equals_int (memcmp (gst_rtp_buffer_get_payload (&rtp_a),
+          gst_rtp_buffer_get_payload (&rtp_b),
+          gst_rtp_buffer_get_payload_len (&rtp_a)), 0);
+
+  gst_rtp_buffer_unmap (&rtp_a);
+  gst_rtp_buffer_unmap (&rtp_b);
+}
+
+static GstBuffer *
+create_rtp_buffer (guint32 ssrc, guint8 payload_type, guint16 seqnum)
+{
+  GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT;
+  guint payload_size = 29;
+  guint64 timestamp = gst_util_uint64_scale_int (seqnum, 90000, 30);
+  GstBuffer *buf = gst_rtp_buffer_new_allocate (payload_size, 0, 0);
+
+  gst_rtp_buffer_map (buf, GST_MAP_WRITE, &rtpbuf);
+  gst_rtp_buffer_set_ssrc (&rtpbuf, ssrc);
+  gst_rtp_buffer_set_payload_type (&rtpbuf, payload_type);
+  gst_rtp_buffer_set_seq (&rtpbuf, seqnum);
+  gst_rtp_buffer_set_timestamp (&rtpbuf, (guint32) timestamp);
+  memset (gst_rtp_buffer_get_payload (&rtpbuf), 0x29, payload_size);
+  gst_rtp_buffer_unmap (&rtpbuf);
+  return buf;
+}
+
+static GstBuffer *
+create_rtp_buffer_with_timestamp (guint32 ssrc, guint8 payload_type,
+    guint16 seqnum, guint32 timestamp)
+{
+  GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT;
+  GstBuffer *buf = create_rtp_buffer (ssrc, payload_type, seqnum);
+  gst_rtp_buffer_map (buf, GST_MAP_WRITE, &rtpbuf);
+  gst_rtp_buffer_set_timestamp (&rtpbuf, timestamp);
+  gst_rtp_buffer_unmap (&rtpbuf);
+  return buf;
+}
+
+GST_START_TEST (test_rtxsend_rtxreceive)
+{
+  const guint packets_num = 5;
+  guint master_ssrc = 1234567;
+  guint master_pt = 96;
+  guint rtx_pt = 99;
+  GstStructure *pt_map;
+  GstBuffer *inbufs[5];
+  GstHarness *hrecv = gst_harness_new ("rtprtxreceive");
+  GstHarness *hsend = gst_harness_new ("rtprtxsend");
+  gint i;
+
+  pt_map = gst_structure_new ("application/x-rtp-pt-map",
+      "96", G_TYPE_UINT, rtx_pt, NULL);
+  g_object_set (hrecv->element, "payload-type-map", pt_map, NULL);
+  g_object_set (hsend->element, "payload-type-map", pt_map, NULL);
+
+  gst_harness_set_src_caps_str (hsend, "application/x-rtp, "
+      "media = (string)video, payload = (int)96, "
+      "ssrc = (uint)1234567, clock-rate = (int)90000, "
+      "encoding-name = (string)RAW");
+  gst_harness_set_src_caps_str (hrecv, "application/x-rtp, "
+      "media = (string)video, payload = (int)96, "
+      "ssrc = (uint)1234567, clock-rate = (int)90000, "
+      "encoding-name = (string)RAW");
+
+  /* Push 'packets_num' packets through rtxsend to rtxreceive */
+  for (i = 0; i < packets_num; ++i) {
+    inbufs[i] = create_rtp_buffer (master_ssrc, master_pt, 100 + i);
+    gst_harness_push (hsend, gst_buffer_ref (inbufs[i]));
+    gst_harness_push (hrecv, gst_harness_pull (hsend));
+    pull_and_verify (hrecv, FALSE, master_ssrc, master_pt, 100 + i);
+  }
+
+  /* Getting rid of reconfigure event. Preparation before the next step */
+  gst_event_unref (gst_harness_pull_upstream_event (hrecv));
+  fail_unless_equals_int (gst_harness_upstream_events_in_queue (hrecv), 0);
+
+  /* Push 'packets_num' RTX events through rtxreceive to rtxsend.
+     Push RTX packets from rtxsend to rtxreceive and
+     check that the packet produced out of RTX packet is the same
+     as an original packet */
+  for (i = 0; i < packets_num; ++i) {
+    GstBuffer *outbuf;
+    gst_harness_push_upstream_event (hrecv,
+        create_rtx_event (master_ssrc, master_pt, 100 + i));
+    gst_harness_push_upstream_event (hsend,
+        gst_harness_pull_upstream_event (hrecv));
+    gst_harness_push (hrecv, gst_harness_pull (hsend));
+
+    outbuf = gst_harness_pull (hrecv);
+    compare_rtp_packets (inbufs[i], outbuf);
+    gst_buffer_unref (inbufs[i]);
+    gst_buffer_unref (outbuf);
+  }
+
+  /* Check RTX stats */
+  {
+    guint rtx_requests;
+    guint rtx_packets;
+    guint rtx_assoc_packets;
+    g_object_get (G_OBJECT (hsend->element),
+        "num-rtx-requests", &rtx_requests,
+        "num-rtx-packets", &rtx_packets, NULL);
+    fail_unless_equals_int (rtx_packets, packets_num);
+    fail_unless_equals_int (rtx_requests, packets_num);
+
+    g_object_get (G_OBJECT (hrecv->element),
+        "num-rtx-requests", &rtx_requests,
+        "num-rtx-packets", &rtx_packets,
+        "num-rtx-assoc-packets", &rtx_assoc_packets, NULL);
+    fail_unless_equals_int (rtx_packets, packets_num);
+    fail_unless_equals_int (rtx_requests, packets_num);
+    fail_unless_equals_int (rtx_assoc_packets, packets_num);
+  }
+
+  gst_structure_free (pt_map);
+  gst_harness_teardown (hrecv);
+  gst_harness_teardown (hsend);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtxsend_rtxreceive_with_packet_loss)
+{
+  guint packets_num = 20;
+  guint master_ssrc = 1234567;
+  guint master_pt = 96;
+  guint rtx_pt = 99;
+  guint seqnum = 100;
+  guint expected_rtx_packets = 0;
+  GstStructure *pt_map;
+  GstHarness *hrecv = gst_harness_new ("rtprtxreceive");
+  GstHarness *hsend = gst_harness_new ("rtprtxsend");
+  gint drop_nth_packet, i;
+
+  pt_map = gst_structure_new ("application/x-rtp-pt-map",
+      "96", G_TYPE_UINT, rtx_pt, NULL);
+  g_object_set (hrecv->element, "payload-type-map", pt_map, NULL);
+  g_object_set (hsend->element, "payload-type-map", pt_map, NULL);
+
+  gst_harness_set_src_caps_str (hsend, "application/x-rtp, "
+      "media = (string)video, payload = (int)96, "
+      "ssrc = (uint)1234567, clock-rate = (int)90000, "
+      "encoding-name = (string)RAW");
+  gst_harness_set_src_caps_str (hrecv, "application/x-rtp, "
+      "media = (string)video, payload = (int)96, "
+      "ssrc = (uint)1234567, clock-rate = (int)90000, "
+      "encoding-name = (string)RAW");
+
+  /* Getting rid of reconfigure event. Making sure there is no upstream
+     events in the queue. Preparation step before the test. */
+  gst_event_unref (gst_harness_pull_upstream_event (hrecv));
+  fail_unless_equals_int (gst_harness_upstream_events_in_queue (hrecv), 0);
+
+  /* Push 'packets_num' packets through rtxsend to rtxreceive loosing every
+     'drop_every_n_packets' packet. When we loose the packet we send RTX event
+     through rtxreceive to rtxsend, and verify the packet was retransmitted */
+  for (drop_nth_packet = 2; drop_nth_packet < 10; ++drop_nth_packet) {
+    for (i = 0; i < packets_num; ++i, ++seqnum) {
+      GstBuffer *outbuf;
+      GstBuffer *inbuf = create_rtp_buffer (master_ssrc, master_pt, seqnum);
+      gboolean drop_this_packet = ((i + 1) % drop_nth_packet) == 0;
+
+      gst_harness_push (hsend, gst_buffer_ref (inbuf));
+      if (drop_this_packet) {
+        /* Dropping original packet */
+        gst_buffer_unref (gst_harness_pull (hsend));
+        /* Requesting retransmission */
+        gst_harness_push_upstream_event (hrecv,
+            create_rtx_event (master_ssrc, master_pt, seqnum));
+        gst_harness_push_upstream_event (hsend,
+            gst_harness_pull_upstream_event (hrecv));
+        /* Pushing RTX packet to rtxreceive */
+        gst_harness_push (hrecv, gst_harness_pull (hsend));
+        ++expected_rtx_packets;
+      } else {
+        gst_harness_push (hrecv, gst_harness_pull (hsend));
+      }
+
+      /* We making sure every buffer we pull is the same as original input
+         buffer */
+      outbuf = gst_harness_pull (hrecv);
+      compare_rtp_packets (inbuf, outbuf);
+      gst_buffer_unref (inbuf);
+      gst_buffer_unref (outbuf);
+
+      /*
+         We should not have any packets in the harness queue by this point. It
+         means rtxsend didn't send more packets than RTX events and rtxreceive
+         didn't produce more than one packet per RTX packet.
+       */
+      fail_unless_equals_int (gst_harness_buffers_in_queue (hsend), 0);
+      fail_unless_equals_int (gst_harness_buffers_in_queue (hrecv), 0);
+    }
+  }
+
+  /* Check RTX stats */
+  {
+    guint rtx_requests;
+    guint rtx_packets;
+    guint rtx_assoc_packets;
+    g_object_get (G_OBJECT (hsend->element),
+        "num-rtx-requests", &rtx_requests,
+        "num-rtx-packets", &rtx_packets, NULL);
+    fail_unless_equals_int (rtx_packets, expected_rtx_packets);
+    fail_unless_equals_int (rtx_requests, expected_rtx_packets);
+
+    g_object_get (G_OBJECT (hrecv->element),
+        "num-rtx-requests", &rtx_requests,
+        "num-rtx-packets", &rtx_packets,
+        "num-rtx-assoc-packets", &rtx_assoc_packets, NULL);
+    fail_unless_equals_int (rtx_packets, expected_rtx_packets);
+    fail_unless_equals_int (rtx_requests, expected_rtx_packets);
+    fail_unless_equals_int (rtx_assoc_packets, expected_rtx_packets);
+  }
+
+  gst_structure_free (pt_map);
+  gst_harness_teardown (hrecv);
+  gst_harness_teardown (hsend);
+}
+
+GST_END_TEST;
+
+typedef struct
+{
+  GstHarness *h;
+  guint master_ssrc;
+  guint master_pt;
+  guint rtx_ssrc;
+  guint rtx_pt;
+  guint seqnum;
+  guint expected_rtx_packets;
+} RtxSender;
+
+static GstStructure *
+create_rtxsenders (RtxSender * senders, guint senders_num)
+{
+  GstStructure *recv_pt_map =
+      gst_structure_new_empty ("application/x-rtp-pt-map");
+  gint i;
+
+  for (i = 0; i < senders_num; ++i) {
+    gchar *master_pt_str;
+    gchar *master_caps_str;
+    GstStructure *send_pt_map;
+
+    senders[i].h = gst_harness_new ("rtprtxsend");
+    senders[i].master_ssrc = 1234567 + i;
+    senders[i].rtx_ssrc = 7654321 + i;
+    senders[i].master_pt = 80 + i;
+    senders[i].rtx_pt = 20 + i;
+    senders[i].seqnum = i * 1000;
+    senders[i].expected_rtx_packets = 0;
+
+    master_pt_str = g_strdup_printf ("%u", senders[i].master_pt);
+    master_caps_str = g_strdup_printf ("application/x-rtp, "
+        "media = (string)video, payload = (int)%u, "
+        "ssrc = (uint)%u, clock-rate = (int)90000, "
+        "encoding-name = (string)RAW",
+        senders[i].master_pt, senders[i].master_ssrc);
+
+    send_pt_map = gst_structure_new ("application/x-rtp-pt-map",
+        master_pt_str, G_TYPE_UINT, senders[i].rtx_pt, NULL);
+    gst_structure_set (recv_pt_map,
+        master_pt_str, G_TYPE_UINT, senders[i].rtx_pt, NULL);
+
+    g_object_set (senders[i].h->element, "payload-type-map", send_pt_map, NULL);
+    gst_harness_set_src_caps_str (senders[i].h, master_caps_str);
+
+    gst_structure_free (send_pt_map);
+    g_free (master_pt_str);
+    g_free (master_caps_str);
+  }
+  return recv_pt_map;
+}
+
+static guint
+check_rtxsenders_stats_and_teardown (RtxSender * senders, guint senders_num)
+{
+  guint total_pakets_num = 0;
+  gint i;
+
+  for (i = 0; i < senders_num; ++i) {
+    guint rtx_requests;
+    guint rtx_packets;
+    g_object_get (G_OBJECT (senders[i].h->element),
+        "num-rtx-requests", &rtx_requests,
+        "num-rtx-packets", &rtx_packets, NULL);
+    fail_unless_equals_int (rtx_packets, senders[i].expected_rtx_packets);
+    fail_unless_equals_int (rtx_requests, senders[i].expected_rtx_packets);
+    total_pakets_num += rtx_packets;
+
+    gst_harness_teardown (senders[i].h);
+  }
+  return total_pakets_num;
+}
+
+GST_START_TEST (test_multi_rtxsend_rtxreceive_with_packet_loss)
+{
+  guint senders_num = 5;
+  guint packets_num = 10;
+  guint total_pakets_num = senders_num * packets_num;
+  guint total_dropped_packets = 0;
+  RtxSender senders[5];
+  GstStructure *pt_map;
+  GstHarness *hrecv = gst_harness_new ("rtprtxreceive");
+  gint drop_nth_packet, i, j;
+
+  pt_map = create_rtxsenders (senders, 5);
+  g_object_set (hrecv->element, "payload-type-map", pt_map, NULL);
+  gst_harness_set_src_caps_str (hrecv, "application/x-rtp, "
+      "media = (string)video, payload = (int)80, "
+      "ssrc = (uint)1234567, clock-rate = (int)90000, "
+      "encoding-name = (string)RAW");
+
+  /* Getting rid of reconfigure event. Making sure there is no upstream
+     events in the queue. Preparation step before the test. */
+  gst_event_unref (gst_harness_pull_upstream_event (hrecv));
+  fail_unless_equals_int (gst_harness_upstream_events_in_queue (hrecv), 0);
+
+  /* We are going to push the 1st packet from the 1st sender, 2nd from the 2nd,
+     3rd from the 3rd, etc. until all the senders will push 'packets_num' packets.
+     We will drop every 'drop_nth_packet' packet and request its retransmission
+     from all the senders. Because only one of them can produce RTX packet.
+     We need to make sure that all other senders will ignore the RTX event they
+     can't act upon.
+   */
+  for (drop_nth_packet = 2; drop_nth_packet < 5; ++drop_nth_packet) {
+    for (i = 0; i < total_pakets_num; ++i) {
+      RtxSender *sender = &senders[i % senders_num];
+      gboolean drop_this_packet = ((i + 1) % drop_nth_packet) == 0;
+      GstBuffer *outbuf, *inbuf;
+      inbuf =
+          create_rtp_buffer (sender->master_ssrc, sender->master_pt,
+          sender->seqnum);
+
+      gst_harness_push (sender->h, gst_buffer_ref (inbuf));
+      if (drop_this_packet) {
+        GstEvent *rtxevent;
+        /* Dropping original packet */
+        gst_buffer_unref (gst_harness_pull (sender->h));
+
+        /* Pushing RTX event through rtxreceive to all the senders */
+        gst_harness_push_upstream_event (hrecv,
+            create_rtx_event (sender->master_ssrc, sender->master_pt,
+                sender->seqnum));
+        rtxevent = gst_harness_pull_upstream_event (hrecv);
+
+        /* ... to all the senders */
+        for (j = 0; j < senders_num; ++j)
+          gst_harness_push_upstream_event (senders[j].h,
+              gst_event_ref (rtxevent));
+        gst_event_unref (rtxevent);
+
+        /* Pushing RTX packet to rtxreceive */
+        gst_harness_push (hrecv, gst_harness_pull (sender->h));
+        ++sender->expected_rtx_packets;
+        ++total_dropped_packets;
+      } else {
+        gst_harness_push (hrecv, gst_harness_pull (sender->h));
+      }
+
+      /* It should not matter whether the buffer was dropped (and retransmitted)
+         or it went straight through rtxsend to rtxreceive. We should always pull
+         the same buffer that was pushed */
+      outbuf = gst_harness_pull (hrecv);
+      compare_rtp_packets (inbuf, outbuf);
+      gst_buffer_unref (inbuf);
+      gst_buffer_unref (outbuf);
+
+      /*
+         We should not have any packets in the harness queue by this point. It
+         means our senders didn't produce the packets for the unknown RTX event.
+       */
+      for (j = 0; j < senders_num; ++j)
+        fail_unless_equals_int (gst_harness_buffers_in_queue (senders[j].h), 0);
+
+      ++sender->seqnum;
+    }
+  }
+
+  /* Check RTX stats */
+  {
+    guint total_rtx_packets;
+    guint rtx_requests;
+    guint rtx_packets;
+    guint rtx_assoc_packets;
+
+    total_rtx_packets =
+        check_rtxsenders_stats_and_teardown (senders, senders_num);
+    fail_unless_equals_int (total_rtx_packets, total_dropped_packets);
+
+    g_object_get (G_OBJECT (hrecv->element),
+        "num-rtx-requests", &rtx_requests,
+        "num-rtx-packets", &rtx_packets,
+        "num-rtx-assoc-packets", &rtx_assoc_packets, NULL);
+    fail_unless_equals_int (rtx_packets, total_rtx_packets);
+    fail_unless_equals_int (rtx_requests, total_rtx_packets);
+    fail_unless_equals_int (rtx_assoc_packets, total_rtx_packets);
+  }
+
+  gst_structure_free (pt_map);
+  gst_harness_teardown (hrecv);
+}
+
+GST_END_TEST;
+
+static void
+test_rtxsender_packet_retention (gboolean test_with_time)
+{
+  guint master_ssrc = 1234567;
+  guint master_pt = 96;
+  guint rtx_ssrc = 7654321;
+  guint rtx_pt = 99;
+  gint num_buffers = test_with_time ? 30 : 10;
+  gint half_buffers = num_buffers / 2;
+  guint timestamp_delta = 90000 / 30;
+  guint timestamp = G_MAXUINT32 - half_buffers * timestamp_delta;
+  GstHarness *h;
+  GstStructure *pt_map = gst_structure_new ("application/x-rtp-pt-map",
+      "96", G_TYPE_UINT, rtx_pt, NULL);
+  GstStructure *ssrc_map = gst_structure_new ("application/x-rtp-ssrc-map",
+      "1234567", G_TYPE_UINT, rtx_ssrc, NULL);
+  gint i, j;
+
+  h = gst_harness_new ("rtprtxsend");
+
+  /* In both cases we want the rtxsend queue to store 'half_buffers'
+     amount of buffers at most. In max-size-packets mode, it's trivial.
+     In max-size-time mode, we specify almost half a second, which is
+     the equivalent of 15 frames in a 30fps video stream.
+   */
+  g_object_set (h->element,
+      "max-size-packets", test_with_time ? 0 : half_buffers,
+      "max-size-time", test_with_time ? 499 : 0,
+      "payload-type-map", pt_map, "ssrc-map", ssrc_map, NULL);
+
+  gst_harness_set_src_caps_str (h, "application/x-rtp, "
+      "media = (string)video, payload = (int)96, "
+      "ssrc = (uint)1234567, clock-rate = (int)90000, "
+      "encoding-name = (string)RAW");
+
+  /* Now push all buffers and request retransmission every time for all of them */
+  for (i = 0; i < num_buffers; ++i, timestamp += timestamp_delta) {
+    /* Request to retransmit all the previous ones */
+    for (j = 0; j < i; ++j) {
+      guint rtx_seqnum = 0x100 + j;
+      gst_harness_push_upstream_event (h,
+          create_rtx_event (master_ssrc, master_pt, rtx_seqnum));
+
+      /* Pull only the ones supposed to be retransmited */
+      if (j >= i - half_buffers)
+        pull_and_verify (h, TRUE, rtx_ssrc, rtx_pt, rtx_seqnum);
+    }
+    /* Check there no extra buffers in the harness queue */
+    fail_unless_equals_int (gst_harness_buffers_in_queue (h), 0);
+
+    /* We create RTP buffers with timestamps that will eventualy wrap around 0
+       to be sure, rtprtxsend can handle it properly */
+    push_pull_and_verify (h,
+        create_rtp_buffer_with_timestamp (master_ssrc, master_pt, 0x100 + i,
+            timestamp), FALSE, master_ssrc, master_pt, 0x100 + i);
+  }
+
+  gst_structure_free (pt_map);
+  gst_structure_free (ssrc_map);
+  gst_harness_teardown (h);
+}
+
+GST_START_TEST (test_rtxsender_max_size_packets)
+{
+  test_rtxsender_packet_retention (FALSE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtxsender_max_size_time)
+{
+  test_rtxsender_packet_retention (TRUE);
+}
+
+GST_END_TEST;
+
+static void
+test_rtxqueue_packet_retention (gboolean test_with_time)
+{
+  guint ssrc = 1234567;
+  guint pt = 96;
+  gint num_buffers = test_with_time ? 30 : 10;
+  gint half_buffers = num_buffers / 2;
+  GstClockTime timestamp_delta = GST_SECOND / 30;
+  GstClockTime timestamp = 0;
+  GstBuffer *buf;
+  GstHarness *h;
+  gint i, j;
+
+  h = gst_harness_new ("rtprtxqueue");
+
+  /* In both cases we want the rtxqueue to store 'half_buffers'
+     amount of buffers at most. In max-size-packets mode, it's trivial.
+     In max-size-time mode, we specify almost half a second, which is
+     the equivalent of 15 frames in a 30fps video stream.
+   */
+  g_object_set (h->element,
+      "max-size-packets", test_with_time ? 0 : half_buffers,
+      "max-size-time", test_with_time ? 498 : 0, NULL);
+
+  gst_harness_set_src_caps_str (h, "application/x-rtp, "
+      "media = (string)video, payload = (int)96, "
+      "ssrc = (uint)1234567, clock-rate = (int)90000, "
+      "encoding-name = (string)RAW");
+
+  /* Now push all buffers and request retransmission every time for all of them.
+   * Note that rtprtxqueue sends retransmissions in chain(), just before
+   * pushing out the chained buffer, a differentiation from rtprtxsend above
+   */
+  for (i = 0; i < num_buffers; ++i, timestamp += timestamp_delta) {
+    /* Request to retransmit all the previous ones */
+    for (j = 0; j < i; ++j) {
+      guint rtx_seqnum = 0x100 + j;
+      gst_harness_push_upstream_event (h,
+          create_rtx_event (ssrc, pt, rtx_seqnum));
+    }
+
+    /* push one packet */
+    buf = create_rtp_buffer (ssrc, pt, 0x100 + i);
+    GST_BUFFER_TIMESTAMP (buf) = timestamp;
+    gst_harness_push (h, buf);
+
+    /* Pull the ones supposed to be retransmitted */
+    for (j = 0; j < i; ++j) {
+      guint rtx_seqnum = 0x100 + j;
+      if (j >= i - half_buffers)
+        pull_and_verify (h, FALSE, ssrc, pt, rtx_seqnum);
+    }
+
+    /* There should be only one packet remaining in the queue now */
+    fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1);
+
+    /* pull the one that we just pushed (comes after the retransmitted ones) */
+    pull_and_verify (h, FALSE, ssrc, pt, 0x100 + i);
+
+    /* Check there no extra buffers in the harness queue */
+    fail_unless_equals_int (gst_harness_buffers_in_queue (h), 0);
+  }
+
+  gst_harness_teardown (h);
+}
+
+GST_START_TEST (test_rtxqueue_max_size_packets)
+{
+  test_rtxqueue_packet_retention (FALSE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtxqueue_max_size_time)
+{
+  test_rtxqueue_packet_retention (TRUE);
+}
+
+GST_END_TEST;
+
+static Suite *
+rtprtx_suite (void)
+{
+  Suite *s = suite_create ("rtprtx");
+  TCase *tc_chain = tcase_create ("general");
+
+  tcase_set_timeout (tc_chain, 120);
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_rtxsend_rtxreceive);
+  tcase_add_test (tc_chain, test_rtxsend_rtxreceive_with_packet_loss);
+  tcase_add_test (tc_chain, test_multi_rtxsend_rtxreceive_with_packet_loss);
+  tcase_add_test (tc_chain, test_rtxsender_max_size_packets);
+  tcase_add_test (tc_chain, test_rtxsender_max_size_time);
+  tcase_add_test (tc_chain, test_rtxqueue_max_size_packets);
+  tcase_add_test (tc_chain, test_rtxqueue_max_size_time);
+
+  return s;
+}
+
+GST_CHECK_MAIN (rtprtx);
diff --git a/tests/check/elements/rtpsession.c b/tests/check/elements/rtpsession.c
new file mode 100644
index 0000000..94925ee
--- /dev/null
+++ b/tests/check/elements/rtpsession.c
@@ -0,0 +1,726 @@
+/* GStreamer
+ *
+ * unit test for gstrtpsession
+ *
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) 2013 Collabora Ltd.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <gst/check/gstharness.h>
+#include <gst/check/gstcheck.h>
+#include <gst/check/gsttestclock.h>
+#include <gst/check/gstharness.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/rtp/gstrtcpbuffer.h>
+#include <gst/net/gstnetaddressmeta.h>
+
+#define TEST_BUF_CLOCK_RATE 8000
+#define TEST_BUF_PT 0
+#define TEST_BUF_SSRC 0x01BADBAD
+#define TEST_BUF_MS  20
+#define TEST_BUF_DURATION (TEST_BUF_MS * GST_MSECOND)
+#define TEST_BUF_SIZE (64000 * TEST_BUF_MS / 1000)
+#define TEST_RTP_TS_DURATION (TEST_BUF_CLOCK_RATE * TEST_BUF_MS / 1000)
+
+static GstCaps *
+generate_caps (void)
+{
+  return gst_caps_new_simple ("application/x-rtp",
+      "clock-rate", G_TYPE_INT, TEST_BUF_CLOCK_RATE,
+      "payload", G_TYPE_INT, TEST_BUF_PT,
+      NULL);
+}
+
+static GstBuffer *
+generate_test_buffer_full (GstClockTime dts,
+    guint seq_num, guint32 rtp_ts, guint ssrc)
+{
+  GstBuffer *buf;
+  guint8 *payload;
+  guint i;
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+
+  buf = gst_rtp_buffer_new_allocate (TEST_BUF_SIZE, 0, 0);
+  GST_BUFFER_DTS (buf) = dts;
+
+  gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
+  gst_rtp_buffer_set_payload_type (&rtp, TEST_BUF_PT);
+  gst_rtp_buffer_set_seq (&rtp, seq_num);
+  gst_rtp_buffer_set_timestamp (&rtp, rtp_ts);
+  gst_rtp_buffer_set_ssrc (&rtp, ssrc);
+
+  payload = gst_rtp_buffer_get_payload (&rtp);
+  for (i = 0; i < TEST_BUF_SIZE; i++)
+    payload[i] = 0xff;
+
+  gst_rtp_buffer_unmap (&rtp);
+
+  return buf;
+}
+
+static GstBuffer *
+generate_test_buffer (guint seq_num, guint ssrc)
+{
+  return generate_test_buffer_full (seq_num * TEST_BUF_DURATION,
+      seq_num, seq_num * TEST_RTP_TS_DURATION, ssrc);
+}
+
+typedef struct
+{
+  GstHarness *send_rtp_h;
+  GstHarness *recv_rtp_h;
+  GstHarness *rtcp_h;
+
+  GstElement *session;
+  GObject *internal_session;
+  GstTestClock *testclock;
+  GstCaps *caps;
+} SessionHarness;
+
+static GstCaps *
+_pt_map_requested (GstElement * element, guint pt, gpointer data)
+{
+  SessionHarness *h = data;
+  return gst_caps_copy (h->caps);
+}
+
+static SessionHarness *
+session_harness_new (void)
+{
+  SessionHarness *h = g_new0 (SessionHarness, 1);
+  h->caps = generate_caps ();
+
+  h->testclock = GST_TEST_CLOCK_CAST (gst_test_clock_new ());
+  gst_system_clock_set_default (GST_CLOCK_CAST (h->testclock));
+
+  h->session = gst_element_factory_make ("rtpsession", NULL);
+  gst_element_set_clock (h->session, GST_CLOCK_CAST (h->testclock));
+
+  h->send_rtp_h = gst_harness_new_with_element (h->session,
+      "send_rtp_sink", "send_rtp_src");
+  gst_harness_set_src_caps (h->send_rtp_h, gst_caps_copy (h->caps));
+
+  h->recv_rtp_h = gst_harness_new_with_element (h->session,
+      "recv_rtp_sink", "recv_rtp_src");
+  gst_harness_set_src_caps (h->recv_rtp_h, gst_caps_copy (h->caps));
+
+  h->rtcp_h = gst_harness_new_with_element (h->session,
+      "recv_rtcp_sink", "send_rtcp_src");
+  gst_harness_set_src_caps_str (h->rtcp_h, "application/x-rtcp");
+
+  g_signal_connect (h->session, "request-pt-map",
+      (GCallback) _pt_map_requested, h);
+
+  g_object_get (h->session, "internal-session", &h->internal_session, NULL);
+
+  return h;
+}
+
+static void
+session_harness_free (SessionHarness * h)
+{
+  gst_system_clock_set_default (NULL);
+
+  gst_caps_unref (h->caps);
+  gst_object_unref (h->testclock);
+
+  gst_harness_teardown (h->rtcp_h);
+  gst_harness_teardown (h->recv_rtp_h);
+  gst_harness_teardown (h->send_rtp_h);
+
+  g_object_unref (h->internal_session);
+  gst_object_unref (h->session);
+  g_free (h);
+}
+
+static GstFlowReturn
+session_harness_send_rtp (SessionHarness * h, GstBuffer * buf)
+{
+  return gst_harness_push (h->send_rtp_h, buf);
+}
+
+static GstFlowReturn
+session_harness_recv_rtp (SessionHarness * h, GstBuffer * buf)
+{
+  return gst_harness_push (h->recv_rtp_h, buf);
+}
+
+static GstFlowReturn
+session_harness_recv_rtcp (SessionHarness * h, GstBuffer * buf)
+{
+  return gst_harness_push (h->rtcp_h, buf);
+}
+
+static GstBuffer *
+session_harness_pull_rtcp (SessionHarness * h)
+{
+  return gst_harness_pull (h->rtcp_h);
+}
+
+static void
+session_harness_crank_clock (SessionHarness * h)
+{
+  gst_test_clock_crank (h->testclock);
+}
+
+static gboolean
+session_harness_advance_and_crank (SessionHarness * h,
+    GstClockTime delta)
+{
+  GstClockID res, pending;
+  gboolean result;
+  gst_test_clock_wait_for_next_pending_id (h->testclock, &pending);
+  gst_test_clock_advance_time (h->testclock, delta);
+  res = gst_test_clock_process_next_clock_id (h->testclock);
+  if (res == pending)
+    result = TRUE;
+  else
+    result = FALSE;
+  if (res)
+    gst_clock_id_unref (res);
+  gst_clock_id_unref (pending);
+  return result;
+}
+
+static void
+session_harness_produce_rtcp (SessionHarness * h, gint num_rtcp_packets)
+{
+  /* due to randomness in rescheduling of RTCP timeout, we need to
+     keep cranking until we have the desired amount of packets */
+  while (gst_harness_buffers_in_queue (h->rtcp_h) < num_rtcp_packets)
+    session_harness_crank_clock (h);
+}
+
+GST_START_TEST (test_multiple_ssrc_rr)
+{
+  SessionHarness *h = session_harness_new ();
+  GstFlowReturn res;
+  GstBuffer *in_buf, *out_buf;
+  GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
+  GstRTCPPacket rtcp_packet;
+  gint i, j;
+
+  guint ssrcs[] = {
+    0x01BADBAD,
+    0xDEADBEEF,
+  };
+
+  /* receive buffers with multiple ssrcs */
+  for (i = 0; i < 2; i++) {
+    for (j = 0; j < G_N_ELEMENTS (ssrcs); j++) {
+      in_buf = generate_test_buffer (i, ssrcs[j]);
+      res = session_harness_recv_rtp (h, in_buf);
+      fail_unless_equals_int (GST_FLOW_OK, res);
+    }
+  }
+
+  /* crank the rtcp-thread and pull out the rtcp-packet we have generated */
+  session_harness_crank_clock (h);
+  out_buf = session_harness_pull_rtcp (h);
+
+  /* verify we have report blocks for both ssrcs */
+  g_assert (out_buf != NULL);
+  fail_unless (gst_rtcp_buffer_validate (out_buf));
+  gst_rtcp_buffer_map (out_buf, GST_MAP_READ, &rtcp);
+  g_assert (gst_rtcp_buffer_get_first_packet (&rtcp, &rtcp_packet));
+  fail_unless_equals_int (GST_RTCP_TYPE_RR,
+      gst_rtcp_packet_get_type (&rtcp_packet));
+
+  fail_unless_equals_int (G_N_ELEMENTS (ssrcs),
+      gst_rtcp_packet_get_rb_count (&rtcp_packet));
+
+  for (j = 0; j < G_N_ELEMENTS (ssrcs); j++) {
+    guint32 ssrc;
+    gst_rtcp_packet_get_rb (&rtcp_packet, j, &ssrc,
+        NULL, NULL, NULL, NULL, NULL, NULL);
+    fail_unless_equals_int (ssrcs[j], ssrc);
+  }
+
+  gst_rtcp_buffer_unmap (&rtcp);
+  gst_buffer_unref (out_buf);
+
+  session_harness_free (h);
+}
+
+GST_END_TEST;
+
+/* This verifies that rtpsession will correctly place RBs round-robin
+ * across multiple RRs when there are too many senders that their RBs
+ * do not fit in one RR */
+GST_START_TEST (test_multiple_senders_roundrobin_rbs)
+{
+  SessionHarness *h = session_harness_new ();
+  GstFlowReturn res;
+  GstBuffer *buf;
+  GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
+  GstRTCPPacket rtcp_packet;
+  gint i, j, k;
+  guint32 ssrc;
+  GHashTable *rb_ssrcs, *tmp_set;
+
+  g_object_set (h->internal_session, "internal-ssrc", 0xDEADBEEF, NULL);
+
+  for (i = 0; i < 2; i++) {     /* cycles between RR reports */
+    for (j = 0; j < 5; j++) {   /* packets per ssrc */
+      gint seq = (i * 5) + j;
+      for (k = 0; k < 35; k++) {        /* number of ssrcs */
+        buf = generate_test_buffer (seq, 10000 + k);
+        res = session_harness_recv_rtp (h, buf);
+        fail_unless_equals_int (GST_FLOW_OK, res);
+      }
+    }
+  }
+
+  rb_ssrcs = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
+      (GDestroyNotify) g_hash_table_unref);
+
+  /* verify the rtcp packets */
+  for (i = 0; i < 2; i++) {
+    guint expected_rb_count = (i < 1) ? GST_RTCP_MAX_RB_COUNT :
+        (35 - GST_RTCP_MAX_RB_COUNT);
+
+    session_harness_produce_rtcp (h, 1);
+    buf = session_harness_pull_rtcp (h);
+    g_assert (buf != NULL);
+    fail_unless (gst_rtcp_buffer_validate (buf));
+
+    gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp);
+    fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &rtcp_packet));
+    fail_unless_equals_int (GST_RTCP_TYPE_RR,
+        gst_rtcp_packet_get_type (&rtcp_packet));
+
+    ssrc = gst_rtcp_packet_rr_get_ssrc (&rtcp_packet);
+    fail_unless_equals_int (0xDEADBEEF, ssrc);
+
+    /* inspect the RBs */
+    fail_unless_equals_int (expected_rb_count,
+        gst_rtcp_packet_get_rb_count (&rtcp_packet));
+
+    if (i == 0) {
+      tmp_set = g_hash_table_new (g_direct_hash, g_direct_equal);
+      g_hash_table_insert (rb_ssrcs, GUINT_TO_POINTER (ssrc), tmp_set);
+    } else {
+      tmp_set = g_hash_table_lookup (rb_ssrcs, GUINT_TO_POINTER (ssrc));
+      g_assert (tmp_set);
+    }
+
+    for (j = 0; j < expected_rb_count; j++) {
+      gst_rtcp_packet_get_rb (&rtcp_packet, j, &ssrc, NULL, NULL,
+          NULL, NULL, NULL, NULL);
+      g_assert_cmpint (ssrc, >=, 10000);
+      g_assert_cmpint (ssrc, <=, 10035);
+      g_hash_table_add (tmp_set, GUINT_TO_POINTER (ssrc));
+    }
+
+    gst_rtcp_buffer_unmap (&rtcp);
+    gst_buffer_unref (buf);
+  }
+
+  /* now verify all received ssrcs have been reported */
+  fail_unless_equals_int (1, g_hash_table_size (rb_ssrcs));
+  tmp_set = g_hash_table_lookup (rb_ssrcs, GUINT_TO_POINTER (0xDEADBEEF));
+  g_assert (tmp_set);
+  fail_unless_equals_int (35, g_hash_table_size (tmp_set));
+
+  g_hash_table_unref (rb_ssrcs);
+  session_harness_free (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_internal_sources_timeout)
+{
+  SessionHarness *h = session_harness_new ();
+  guint internal_ssrc;
+  guint32 ssrc;
+  GstBuffer *buf;
+  GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
+  GstRTCPPacket rtcp_packet;
+  GstRTCPType rtcp_type;
+  GstFlowReturn res;
+  gint i, j;
+  GstCaps *caps;
+  gboolean seen_bye;
+
+  g_object_set (h->internal_session, "internal-ssrc", 0xDEADBEEF, NULL);
+  g_object_get (h->internal_session, "internal-ssrc", &internal_ssrc, NULL);
+  fail_unless_equals_int (0xDEADBEEF, internal_ssrc);
+
+  for (i = 1; i < 4; i++) {
+    buf = generate_test_buffer (i, 0xBEEFDEAD);
+    res = session_harness_recv_rtp (h, buf);
+    fail_unless_equals_int (GST_FLOW_OK, res);
+  }
+
+  /* verify that rtpsession has sent RR for an internally-created
+   * RTPSource that is using the internal-ssrc */
+  session_harness_produce_rtcp (h, 1);
+  buf = session_harness_pull_rtcp (h);
+
+  fail_unless (buf != NULL);
+  fail_unless (gst_rtcp_buffer_validate (buf));
+  gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp);
+  fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &rtcp_packet));
+  fail_unless_equals_int (GST_RTCP_TYPE_RR,
+      gst_rtcp_packet_get_type (&rtcp_packet));
+  ssrc = gst_rtcp_packet_rr_get_ssrc (&rtcp_packet);
+  fail_unless_equals_int (ssrc, internal_ssrc);
+  gst_rtcp_buffer_unmap (&rtcp);
+  gst_buffer_unref (buf);
+
+  /* ok, now let's push some RTP packets */
+  caps = gst_caps_new_simple ("application/x-rtp",
+      "ssrc", G_TYPE_UINT, 0x01BADBAD, NULL);
+  gst_harness_set_src_caps (h->send_rtp_h, caps);
+
+  for (i = 1; i < 4; i++) {
+    buf = generate_test_buffer (i, 0x01BADBAD);
+    res = session_harness_send_rtp (h, buf);
+    fail_unless_equals_int (GST_FLOW_OK, res);
+  }
+
+  /* internal ssrc must have changed already */
+  g_object_get (h->internal_session, "internal-ssrc", &internal_ssrc, NULL);
+  fail_unless (internal_ssrc != ssrc);
+  fail_unless_equals_int (0x01BADBAD, internal_ssrc);
+
+  /* verify SR and RR */
+  j = 0;
+  for (i = 0; i < 2; i++) {
+    session_harness_produce_rtcp (h, 1);
+    buf = session_harness_pull_rtcp (h);
+    g_assert (buf != NULL);
+    fail_unless (gst_rtcp_buffer_validate (buf));
+    gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp);
+    fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &rtcp_packet));
+    rtcp_type = gst_rtcp_packet_get_type (&rtcp_packet);
+
+    if (rtcp_type == GST_RTCP_TYPE_SR) {
+      gst_rtcp_packet_sr_get_sender_info (&rtcp_packet, &ssrc, NULL, NULL, NULL,
+          NULL);
+      fail_unless_equals_int (internal_ssrc, ssrc);
+      fail_unless_equals_int (0x01BADBAD, ssrc);
+      j |= 0x1;
+    } else if (rtcp_type == GST_RTCP_TYPE_RR) {
+      ssrc = gst_rtcp_packet_rr_get_ssrc (&rtcp_packet);
+      fail_unless (internal_ssrc != ssrc);
+      fail_unless_equals_int (0xDEADBEEF, ssrc);
+      j |= 0x2;
+    }
+    gst_rtcp_buffer_unmap (&rtcp);
+    gst_buffer_unref (buf);
+  }
+  fail_unless_equals_int (0x3, j); /* verify we got both SR and RR */
+
+  /* go 30 seconds in the future and observe both sources timing out:
+   * 0xDEADBEEF -> BYE, 0x01BADBAD -> becomes receiver only */
+  fail_unless (session_harness_advance_and_crank (h, 30 * GST_SECOND));
+
+  /* verify BYE and RR */
+  j = 0;
+  seen_bye = FALSE;
+  while (!seen_bye) {
+    session_harness_produce_rtcp (h, 1);
+    buf = session_harness_pull_rtcp (h);
+    fail_unless (buf != NULL);
+    fail_unless (gst_rtcp_buffer_validate (buf));
+    gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp);
+    fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &rtcp_packet));
+    rtcp_type = gst_rtcp_packet_get_type (&rtcp_packet);
+
+    if (rtcp_type == GST_RTCP_TYPE_RR) {
+      ssrc = gst_rtcp_packet_rr_get_ssrc (&rtcp_packet);
+      if (ssrc == 0x01BADBAD) {
+        j |= 0x1;
+        fail_unless_equals_int (internal_ssrc, ssrc);
+        /* 2 => RR, SDES. There is no BYE here */
+        fail_unless_equals_int (2, gst_rtcp_buffer_get_packet_count (&rtcp));
+      } else if (ssrc == 0xDEADBEEF) {
+        j |= 0x2;
+        g_assert_cmpint (ssrc, !=, internal_ssrc);
+        /* 3 => RR, SDES, BYE */
+        if (gst_rtcp_buffer_get_packet_count (&rtcp) == 3) {
+          fail_unless (gst_rtcp_packet_move_to_next (&rtcp_packet));
+          fail_unless (gst_rtcp_packet_move_to_next (&rtcp_packet));
+          fail_unless_equals_int (GST_RTCP_TYPE_BYE,
+              gst_rtcp_packet_get_type (&rtcp_packet));
+          seen_bye = TRUE;
+        }
+      }
+    }
+    gst_rtcp_buffer_unmap (&rtcp);
+    gst_buffer_unref (buf);
+  }
+  fail_unless_equals_int (0x3, j); /* verify we got both BYE and RR */
+
+  session_harness_free (h);
+}
+
+GST_END_TEST;
+
+typedef struct
+{
+  guint8 subtype;
+  guint32 ssrc;
+  gchar *name;
+  GstBuffer *data;
+} RTCPAppResult;
+
+static void
+on_app_rtcp_cb (GObject * session, guint subtype, guint ssrc,
+    const gchar * name, GstBuffer * data, RTCPAppResult * result)
+{
+  result->subtype = subtype;
+  result->ssrc = ssrc;
+  result->name = g_strdup (name);
+  result->data = data ? gst_buffer_ref (data) : NULL;
+}
+
+GST_START_TEST (test_receive_rtcp_app_packet)
+{
+  SessionHarness *h = session_harness_new ();
+  GstBuffer *buf;
+  GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
+  GstRTCPPacket packet;
+  RTCPAppResult result = { 0 };
+  guint8 data[] = { 0x11, 0x22, 0x33, 0x44 };
+
+  g_signal_connect (h->internal_session, "on-app-rtcp",
+      G_CALLBACK (on_app_rtcp_cb), &result);
+
+  /* Push APP buffer with no data */
+  buf = gst_rtcp_buffer_new (1000);
+  fail_unless (gst_rtcp_buffer_map (buf, GST_MAP_READWRITE, &rtcp));
+  fail_unless (gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_APP, &packet));
+  gst_rtcp_packet_app_set_subtype (&packet, 21);
+  gst_rtcp_packet_app_set_ssrc (&packet, 0x11111111);
+  gst_rtcp_packet_app_set_name (&packet, "Test");
+  gst_rtcp_buffer_unmap (&rtcp);
+
+  fail_unless_equals_int (GST_FLOW_OK, session_harness_recv_rtcp (h, buf));
+
+  fail_unless_equals_int (21, result.subtype);
+  fail_unless_equals_int (0x11111111, result.ssrc);
+  fail_unless_equals_string ("Test", result.name);
+  fail_unless_equals_pointer (NULL, result.data);
+
+  g_free (result.name);
+
+  /* Push APP buffer with data */
+  memset (&result, 0, sizeof (result));
+  buf = gst_rtcp_buffer_new (1000);
+  fail_unless (gst_rtcp_buffer_map (buf, GST_MAP_READWRITE, &rtcp));
+  fail_unless (gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_APP, &packet));
+  gst_rtcp_packet_app_set_subtype (&packet, 22);
+  gst_rtcp_packet_app_set_ssrc (&packet, 0x22222222);
+  gst_rtcp_packet_app_set_name (&packet, "Test");
+  gst_rtcp_packet_app_set_data_length (&packet, sizeof (data) / 4);
+  memcpy (gst_rtcp_packet_app_get_data (&packet), data, sizeof (data));
+  gst_rtcp_buffer_unmap (&rtcp);
+
+  fail_unless_equals_int (GST_FLOW_OK, session_harness_recv_rtcp (h, buf));
+
+  fail_unless_equals_int (22, result.subtype);
+  fail_unless_equals_int (0x22222222, result.ssrc);
+  fail_unless_equals_string ("Test", result.name);
+  fail_unless (gst_buffer_memcmp (result.data, 0, data, sizeof (data)) == 0);
+
+  g_free (result.name);
+  gst_buffer_unref (result.data);
+
+  session_harness_free (h);
+}
+
+GST_END_TEST;
+
+static void
+stats_test_cb (GObject * object, GParamSpec * spec, gpointer data)
+{
+  guint num_sources = 0;
+  gboolean *cb_called = data;
+  g_assert (*cb_called == FALSE);
+  *cb_called = TRUE;
+
+  /* We should be able to get a rtpsession property
+     without introducing the deadlock */
+  g_object_get (object, "num-sources", &num_sources, NULL);
+}
+
+GST_START_TEST (test_dont_lock_on_stats)
+{
+  GstHarness *h_rtcp;
+  GstHarness *h_send;
+  GstClock *clock = gst_test_clock_new ();
+  GstTestClock *testclock = GST_TEST_CLOCK (clock);
+  gboolean cb_called = FALSE;
+
+  /* use testclock as the systemclock to capture the rtcp thread waits */
+  gst_system_clock_set_default (GST_CLOCK (testclock));
+
+  h_rtcp =
+      gst_harness_new_with_padnames ("rtpsession", "recv_rtcp_sink",
+      "send_rtcp_src");
+  h_send =
+      gst_harness_new_with_element (h_rtcp->element, "send_rtp_sink",
+      "send_rtp_src");
+
+  /* connect to the stats-reporting */
+  g_signal_connect (h_rtcp->element, "notify::stats",
+      G_CALLBACK (stats_test_cb), &cb_called);
+
+  /* "crank" and check the stats */
+  g_assert (gst_test_clock_crank (testclock));
+  gst_buffer_unref (gst_harness_pull (h_rtcp));
+  fail_unless (cb_called);
+
+  gst_harness_teardown (h_send);
+  gst_harness_teardown (h_rtcp);
+  gst_object_unref (clock);
+}
+
+GST_END_TEST;
+
+static void
+suspicious_bye_cb (GObject * object, GParamSpec * spec, gpointer data)
+{
+  GValueArray *stats_arr;
+  GstStructure *stats, *internal_stats;
+  gboolean *cb_called = data;
+  gboolean internal = FALSE, sent_bye = TRUE;
+  guint ssrc = 0;
+  guint i;
+
+  g_assert (*cb_called == FALSE);
+  *cb_called = TRUE;
+
+  g_object_get (object, "stats", &stats, NULL);
+  stats_arr =
+      g_value_get_boxed (gst_structure_get_value (stats, "source-stats"));
+  g_assert (stats_arr != NULL);
+  fail_unless (stats_arr->n_values >= 1);
+
+  for (i = 0; i < stats_arr->n_values; i++) {
+    internal_stats = g_value_get_boxed (g_value_array_get_nth (stats_arr, i));
+    g_assert (internal_stats != NULL);
+
+    gst_structure_get (internal_stats,
+        "ssrc", G_TYPE_UINT, &ssrc,
+        "internal", G_TYPE_BOOLEAN, &internal,
+        "received-bye", G_TYPE_BOOLEAN, &sent_bye, NULL);
+
+    if (ssrc == 0xDEADBEEF) {
+      fail_unless (internal);
+      fail_unless (!sent_bye);
+      break;
+    }
+  }
+  fail_unless_equals_int (ssrc, 0xDEADBEEF);
+
+  gst_structure_free (stats);
+}
+
+static GstBuffer *
+create_bye_rtcp (guint32 ssrc)
+{
+  GstRTCPPacket packet;
+  GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
+  GSocketAddress *saddr;
+  GstBuffer *buffer = gst_rtcp_buffer_new (1000);
+
+  fail_unless (gst_rtcp_buffer_map (buffer, GST_MAP_READWRITE, &rtcp));
+  fail_unless (gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_BYE, &packet));
+  gst_rtcp_packet_bye_add_ssrc (&packet, ssrc);
+  gst_rtcp_buffer_unmap (&rtcp);
+
+  /* Need to add meta to trigger collision detection */
+  saddr = g_inet_socket_address_new_from_string ("127.0.0.1", 3490);
+  gst_buffer_add_net_address_meta (buffer, saddr);
+  g_object_unref (saddr);
+  return buffer;
+}
+
+GST_START_TEST (test_ignore_suspicious_bye)
+{
+  SessionHarness *h = session_harness_new ();
+  gboolean cb_called = FALSE;
+
+  /* connect to the stats-reporting */
+  g_signal_connect (h->session, "notify::stats",
+      G_CALLBACK (suspicious_bye_cb), &cb_called);
+
+  /* Push RTP buffer making our internal SSRC=0xDEADBEEF */
+  fail_unless_equals_int (GST_FLOW_OK,
+      session_harness_send_rtp (h, generate_test_buffer (0, 0xDEADBEEF)));
+
+  /* Receive BYE RTCP referencing our internal SSRC(!?!) (0xDEADBEEF) */
+  fail_unless_equals_int (GST_FLOW_OK,
+      session_harness_recv_rtcp (h, create_bye_rtcp (0xDEADBEEF)));
+
+  /* "crank" and check the stats */
+  session_harness_crank_clock (h);
+  gst_buffer_unref (session_harness_pull_rtcp (h));
+  fail_unless (cb_called);
+
+  session_harness_free (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_illegal_rtcp_fb_packet)
+{
+  SessionHarness *h = session_harness_new ();
+  GstBuffer *buf;
+  /* Zero length RTCP feedback packet (reduced size) */
+  const guint8 rtcp_zero_fb_pkt[] = { 0x8f, 0xce, 0x00, 0x00 };
+
+  g_object_set (h->internal_session, "internal-ssrc", 0xDEADBEEF, NULL);
+
+  buf = gst_buffer_new_and_alloc (sizeof (rtcp_zero_fb_pkt));
+  gst_buffer_fill (buf, 0, rtcp_zero_fb_pkt, sizeof (rtcp_zero_fb_pkt));
+  GST_BUFFER_DTS (buf) = GST_BUFFER_PTS (buf) = G_GUINT64_CONSTANT (0);
+
+  /* Push the packet, this did previously crash because length of packet was
+   * never validated. */
+  fail_unless_equals_int (GST_FLOW_OK, session_harness_recv_rtcp (h, buf));
+
+  session_harness_free (h);
+}
+
+GST_END_TEST;
+
+static Suite *
+rtpsession_suite (void)
+{
+  Suite *s = suite_create ("rtpsession");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_multiple_ssrc_rr);
+  tcase_add_test (tc_chain, test_multiple_senders_roundrobin_rbs);
+  tcase_add_test (tc_chain, test_internal_sources_timeout);
+  tcase_add_test (tc_chain, test_receive_rtcp_app_packet);
+  tcase_add_test (tc_chain, test_dont_lock_on_stats);
+  tcase_add_test (tc_chain, test_ignore_suspicious_bye);
+
+  tcase_add_test (tc_chain, test_illegal_rtcp_fb_packet);
+  return s;
+}
+
+GST_CHECK_MAIN (rtpsession);
diff --git a/tests/check/elements/rtpvp9.c b/tests/check/elements/rtpvp9.c
new file mode 100644
index 0000000..123069e
--- /dev/null
+++ b/tests/check/elements/rtpvp9.c
@@ -0,0 +1,114 @@
+/* GStreamer
+ *
+ * Copyright (C) 2016 Pexip AS
+ *   @author Stian Selnes <stian@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/check.h>
+#include <gst/check/gstharness.h>
+
+#define RTP_VP9_CAPS_STR \
+  "application/x-rtp,media=video,encoding-name=VP9,clock-rate=90000,payload=96"
+
+
+GST_START_TEST (test_depay_flexible_mode)
+{
+  /* b-bit, e-bit, f-bit and marker bit set */
+  /* First packet of first frame, handcrafted to also set the e-bit and marker
+   * bit in addition to changing the seqnum */
+  guint8 intra[] = {
+    0x80, 0xf4, 0x00, 0x00, 0x49, 0xb5, 0xbe, 0x32, 0xb1, 0x01, 0x64, 0xd1,
+    0xbc, 0x98, 0xbf, 0x00, 0x83, 0x49, 0x83, 0x42, 0x00, 0x77, 0xf0, 0x43,
+    0x71, 0xd8, 0xe0, 0x90, 0x70, 0x66, 0x80, 0x60, 0x0e, 0xf0, 0x5f, 0xfd,
+  };
+  /* b-bit, e-bit, p-bit, f-bit and marker bit set */
+  /* First packet of second frame, handcrafted to also set the e-bit and
+   * marker bit in addition to changing the seqnum */
+  guint8 inter[] = {
+    0x80, 0xf4, 0x00, 0x01, 0x49, 0xb6, 0x02, 0xc0, 0xb1, 0x01, 0x64, 0xd1,
+    0xfc, 0x98, 0xc0, 0x00, 0x02, 0x87, 0x01, 0x00, 0x09, 0x3f, 0x1c, 0x12,
+    0x0e, 0x0c, 0xd0, 0x1b, 0xa7, 0x80, 0x80, 0xb0, 0x18, 0x0f, 0xda, 0x11,
+  };
+
+  GstHarness *h = gst_harness_new ("rtpvp9depay");
+  gst_harness_set_src_caps_str (h, RTP_VP9_CAPS_STR);
+
+  gst_harness_push (h, gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+          intra, sizeof (intra), 0, sizeof (intra), NULL, NULL));
+  fail_unless_equals_int (1, gst_harness_buffers_received (h));
+
+  gst_harness_push (h, gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+          inter, sizeof (inter), 0, sizeof (inter), NULL, NULL));
+  fail_unless_equals_int (2, gst_harness_buffers_received (h));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_depay_non_flexible_mode)
+{
+  /* b-bit, e-bit and  marker bit set. f-bit NOT set */
+  /* First packet of first frame, handcrafted to also set the e-bit and marker
+   * bit in addition to changing the seqnum */
+  guint8 intra[] = {
+    0x80, 0xf4, 0x00, 0x00, 0x49, 0x88, 0xd9, 0xf8, 0xa0, 0x6c, 0x65, 0x6c,
+    0x8c, 0x98, 0xc0, 0x87, 0x01, 0x02, 0x49, 0x3f, 0x1c, 0x12, 0x0e, 0x0c,
+    0xd0, 0x1b, 0xb9, 0x80, 0x80, 0xb0, 0x18, 0x0f, 0xa6, 0x4d, 0x01, 0xa5
+  };
+  /* b-bit, e-bit, p-bit  and marker bit set. f-bit NOT set */
+  /* First packet of second frame, handcrafted to also set the e-bit and
+   * marker bit in addition to changing the seqnum */
+  guint8 inter[] = {
+    0x80, 0xf4, 0x00, 0x01, 0x49, 0x88, 0xe5, 0x38, 0xa0, 0x6c, 0x65, 0x6c,
+    0xcc, 0x98, 0xc1, 0x87, 0x01, 0x02, 0x49, 0x3f, 0x1c, 0x12, 0x0e, 0x0c,
+    0xd0, 0x1b, 0x97, 0x80, 0x80, 0xb0, 0x18, 0x0f, 0x8a, 0x9f, 0x01, 0xbc
+  };
+
+  GstHarness *h = gst_harness_new ("rtpvp9depay");
+  gst_harness_set_src_caps_str (h, RTP_VP9_CAPS_STR);
+
+  gst_harness_push (h, gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+          intra, sizeof (intra), 0, sizeof (intra), NULL, NULL));
+  fail_unless_equals_int (1, gst_harness_buffers_received (h));
+
+  gst_harness_push (h, gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+          inter, sizeof (inter), 0, sizeof (inter), NULL, NULL));
+  fail_unless_equals_int (2, gst_harness_buffers_received (h));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+
+
+static Suite *
+rtpvp9_suite (void)
+{
+  Suite *s = suite_create ("rtpvp9");
+  TCase *tc_chain;
+
+  suite_add_tcase (s, (tc_chain = tcase_create ("vp9depay")));
+  tcase_add_test (tc_chain, test_depay_flexible_mode);
+  tcase_add_test (tc_chain, test_depay_non_flexible_mode);
+
+  return s;
+}
+
+GST_CHECK_MAIN (rtpvp9);
diff --git a/tests/check/elements/shapewipe.c b/tests/check/elements/shapewipe.c
new file mode 100644
index 0000000..ab90084
--- /dev/null
+++ b/tests/check/elements/shapewipe.c
@@ -0,0 +1,316 @@
+/* GStreamer
+ *
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+
+gboolean have_eos = FALSE;
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *myvideosrcpad, *mymasksrcpad, *mysinkpad;
+
+
+#define SHAPEWIPE_VIDEO_CAPS_STRING    \
+    "video/x-raw, " \
+    "format = (string)AYUV, " \
+    "width = 400, " \
+    "height = 400, " \
+    "framerate = 0/1"
+
+#define SHAPEWIPE_MASK_CAPS_STRING    \
+    "video/x-raw, " \
+    "format = (string)GRAY8, " \
+    "width = 400, " \
+    "height = 400, " \
+    "framerate = 0/1"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SHAPEWIPE_VIDEO_CAPS_STRING)
+    );
+static GstStaticPadTemplate videosrctemplate =
+GST_STATIC_PAD_TEMPLATE ("videosrc",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SHAPEWIPE_VIDEO_CAPS_STRING)
+    );
+static GstStaticPadTemplate masksrctemplate =
+GST_STATIC_PAD_TEMPLATE ("masksrc",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SHAPEWIPE_MASK_CAPS_STRING)
+    );
+
+
+static GstBuffer *output = NULL;
+
+static GstFlowReturn
+on_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+  g_return_val_if_fail (output == NULL, GST_FLOW_ERROR);
+
+  output = buffer;
+  return GST_FLOW_OK;
+}
+
+GST_START_TEST (test_general)
+{
+  GstElement *shapewipe, *videosrc, *masksrc, *sink, *bin;
+  GstPad *p;
+  GstCaps *caps;
+  GstBuffer *mask, *input;
+  guint i, j;
+  guint8 *data;
+  GstMapInfo map;
+
+  bin = gst_bin_new ("myshapewipe");
+  videosrc = gst_bin_new ("myvideosrc");
+  masksrc = gst_bin_new ("mymasksrc");
+  sink = gst_bin_new ("mysink");
+  shapewipe = gst_element_factory_make ("shapewipe", NULL);
+  fail_unless (shapewipe != NULL);
+  gst_bin_add_many (GST_BIN (bin), videosrc, masksrc, shapewipe, sink, NULL);
+
+  myvideosrcpad =
+      gst_pad_new_from_static_template (&videosrctemplate, "videosrc");
+  gst_element_add_pad (videosrc, myvideosrcpad);
+
+  mymasksrcpad = gst_pad_new_from_static_template (&masksrctemplate, "masksrc");
+  gst_element_add_pad (masksrc, mymasksrcpad);
+
+  mysinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");
+  gst_element_add_pad (sink, mysinkpad);
+  gst_pad_set_chain_function (mysinkpad, on_chain);
+
+  p = gst_element_get_static_pad (shapewipe, "video_sink");
+  fail_unless (gst_pad_link (myvideosrcpad, p) == GST_PAD_LINK_OK);
+  gst_object_unref (p);
+  p = gst_element_get_static_pad (shapewipe, "mask_sink");
+  fail_unless (gst_pad_link (mymasksrcpad, p) == GST_PAD_LINK_OK);
+  gst_object_unref (p);
+  p = gst_element_get_static_pad (shapewipe, "src");
+  fail_unless (gst_pad_link (p, mysinkpad) == GST_PAD_LINK_OK);
+  gst_object_unref (p);
+
+  fail_unless (gst_element_set_state (bin,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
+
+  caps = gst_caps_from_string (SHAPEWIPE_MASK_CAPS_STRING);
+  gst_check_setup_events (mymasksrcpad, masksrc, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  caps = gst_caps_from_string (SHAPEWIPE_VIDEO_CAPS_STRING);
+  gst_check_setup_events (myvideosrcpad, videosrc, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  mask = gst_buffer_new_and_alloc (400 * 400);
+  gst_buffer_map (mask, &map, GST_MAP_WRITE);
+  data = map.data;
+  for (i = 0; i < 400; i++) {
+    for (j = 0; j < 400; j++) {
+      if (i < 100 && j < 100)
+        data[0] = 0;
+      else if (i < 200 && j < 200)
+        data[0] = 85;
+      else if (i < 300 && j < 300)
+        data[0] = 170;
+      else
+        data[0] = 254;
+      data++;
+    }
+  }
+  gst_buffer_unmap (mask, &map);
+
+  fail_unless (gst_pad_push (mymasksrcpad, mask) == GST_FLOW_OK);
+
+  input = gst_buffer_new_and_alloc (400 * 400 * 4);
+  gst_buffer_map (input, &map, GST_MAP_WRITE);
+  data = map.data;
+  for (i = 0; i < 400; i++) {
+    for (j = 0; j < 400; j++) {
+      /* This is green */
+      data[0] = 255;            /* A */
+      data[1] = 173;            /* Y */
+      data[2] = 42;             /* U */
+      data[3] = 26;             /* V */
+      data += 4;
+    }
+  }
+  gst_buffer_unmap (input, &map);
+
+  g_object_set (G_OBJECT (shapewipe), "position", 0.0, NULL);
+  output = NULL;
+  fail_unless (gst_pad_push (myvideosrcpad,
+          gst_buffer_ref (input)) == GST_FLOW_OK);
+  fail_unless (output != NULL);
+  gst_buffer_map (output, &map, GST_MAP_WRITE);
+  data = map.data;
+  for (i = 0; i < 400; i++) {
+    for (j = 0; j < 400; j++) {
+      fail_unless_equals_int (data[0], 255);    /* A */
+      fail_unless_equals_int (data[1], 173);    /* Y */
+      fail_unless_equals_int (data[2], 42);     /* U */
+      fail_unless_equals_int (data[3], 26);     /* V */
+      data += 4;
+    }
+  }
+  gst_buffer_unmap (output, &map);
+  gst_buffer_unref (output);
+  output = NULL;
+
+  g_object_set (G_OBJECT (shapewipe), "position", 0.1, NULL);
+  output = NULL;
+  fail_unless (gst_pad_push (myvideosrcpad,
+          gst_buffer_ref (input)) == GST_FLOW_OK);
+  fail_unless (output != NULL);
+  gst_buffer_map (output, &map, GST_MAP_READ);
+  data = map.data;
+  for (i = 0; i < 400; i++) {
+    for (j = 0; j < 400; j++) {
+      if (i < 100 && j < 100) {
+        fail_unless_equals_int (data[0], 0);    /* A */
+        fail_unless_equals_int (data[1], 173);  /* Y */
+        fail_unless_equals_int (data[2], 42);   /* U */
+        fail_unless_equals_int (data[3], 26);   /* V */
+      } else {
+        fail_unless_equals_int (data[0], 255);  /* A */
+        fail_unless_equals_int (data[1], 173);  /* Y */
+        fail_unless_equals_int (data[2], 42);   /* U */
+        fail_unless_equals_int (data[3], 26);   /* V */
+      }
+      data += 4;
+    }
+  }
+  gst_buffer_unmap (output, &map);
+  gst_buffer_unref (output);
+  output = NULL;
+
+  g_object_set (G_OBJECT (shapewipe), "position", 0.34, NULL);
+  output = NULL;
+  fail_unless (gst_pad_push (myvideosrcpad,
+          gst_buffer_ref (input)) == GST_FLOW_OK);
+  fail_unless (output != NULL);
+  gst_buffer_map (output, &map, GST_MAP_READ);
+  data = map.data;
+  for (i = 0; i < 400; i++) {
+    for (j = 0; j < 400; j++) {
+      if (i < 200 && j < 200) {
+        fail_unless_equals_int (data[0], 0);    /* A */
+        fail_unless_equals_int (data[1], 173);  /* Y */
+        fail_unless_equals_int (data[2], 42);   /* U */
+        fail_unless_equals_int (data[3], 26);   /* V */
+      } else {
+        fail_unless_equals_int (data[0], 255);  /* A */
+        fail_unless_equals_int (data[1], 173);  /* Y */
+        fail_unless_equals_int (data[2], 42);   /* U */
+        fail_unless_equals_int (data[3], 26);   /* V */
+      }
+      data += 4;
+    }
+  }
+  gst_buffer_unmap (output, &map);
+  gst_buffer_unref (output);
+  output = NULL;
+
+  g_object_set (G_OBJECT (shapewipe), "position", 0.67, NULL);
+  output = NULL;
+  fail_unless (gst_pad_push (myvideosrcpad,
+          gst_buffer_ref (input)) == GST_FLOW_OK);
+  fail_unless (output != NULL);
+  gst_buffer_map (output, &map, GST_MAP_READ);
+  data = map.data;
+  for (i = 0; i < 400; i++) {
+    for (j = 0; j < 400; j++) {
+      if (i < 300 && j < 300) {
+        fail_unless_equals_int (data[0], 0);    /* A */
+        fail_unless_equals_int (data[1], 173);  /* Y */
+        fail_unless_equals_int (data[2], 42);   /* U */
+        fail_unless_equals_int (data[3], 26);   /* V */
+      } else {
+        fail_unless_equals_int (data[0], 255);  /* A */
+        fail_unless_equals_int (data[1], 173);  /* Y */
+        fail_unless_equals_int (data[2], 42);   /* U */
+        fail_unless_equals_int (data[3], 26);   /* V */
+      }
+      data += 4;
+    }
+  }
+  gst_buffer_unmap (output, &map);
+  gst_buffer_unref (output);
+  output = NULL;
+
+  g_object_set (G_OBJECT (shapewipe), "position", 1.0, NULL);
+  output = NULL;
+  fail_unless (gst_pad_push (myvideosrcpad,
+          gst_buffer_ref (input)) == GST_FLOW_OK);
+  fail_unless (output != NULL);
+  gst_buffer_map (output, &map, GST_MAP_READ);
+  data = map.data;
+  for (i = 0; i < 400; i++) {
+    for (j = 0; j < 400; j++) {
+      fail_unless_equals_int (data[0], 0);      /* A */
+      fail_unless_equals_int (data[1], 173);    /* Y */
+      fail_unless_equals_int (data[2], 42);     /* U */
+      fail_unless_equals_int (data[3], 26);     /* V */
+      data += 4;
+    }
+  }
+  gst_buffer_unmap (output, &map);
+  gst_buffer_unref (output);
+  output = NULL;
+
+  gst_buffer_unref (input);
+
+  fail_unless (gst_element_set_state (bin,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
+
+  p = gst_element_get_static_pad (shapewipe, "video_sink");
+  fail_unless (gst_pad_unlink (myvideosrcpad, p));
+  gst_object_unref (p);
+  p = gst_element_get_static_pad (shapewipe, "mask_sink");
+  fail_unless (gst_pad_unlink (mymasksrcpad, p));
+  gst_object_unref (p);
+  p = gst_element_get_static_pad (shapewipe, "src");
+  fail_unless (gst_pad_unlink (p, mysinkpad));
+  gst_object_unref (p);
+
+  gst_object_unref (bin);
+}
+
+GST_END_TEST;
+
+static Suite *
+shapewipe_suite (void)
+{
+  Suite *s = suite_create ("shapewipe");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_set_timeout (tc_chain, 180);
+  tcase_add_test (tc_chain, test_general);
+
+  return s;
+}
+
+GST_CHECK_MAIN (shapewipe);
diff --git a/tests/check/elements/souphttpsrc.c b/tests/check/elements/souphttpsrc.c
new file mode 100644
index 0000000..40d4dbb
--- /dev/null
+++ b/tests/check/elements/souphttpsrc.c
@@ -0,0 +1,681 @@
+/* GStreamer unit tests for the souphttpsrc element
+ * Copyright (C) 2006-2007 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2008 Wouter Cloetens <wouter@mind.be>
+ * Copyright (C) 2001-2003, Ximian, Inc.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib/gprintf.h>
+
+#define SOUP_VERSION_MIN_REQUIRED (SOUP_VERSION_2_40)
+#include <libsoup/soup.h>
+#include <gst/check/gstcheck.h>
+
+#if !defined(SOUP_MINOR_VERSION) || SOUP_MINOR_VERSION < 44
+#define SoupStatus SoupKnownStatusCode
+#endif
+
+
+gboolean redirect = TRUE;
+
+static const char **cookies = NULL;
+
+/* Variables for authentication tests */
+static const char *user_id = NULL;
+static const char *user_pw = NULL;
+static const char *good_user = "good_user";
+static const char *bad_user = "bad_user";
+static const char *good_pw = "good_pw";
+static const char *bad_pw = "bad_pw";
+static const char *realm = "SOUPHTTPSRC_REALM";
+static const char *basic_auth_path = "/basic_auth";
+static const char *digest_auth_path = "/digest_auth";
+
+static const char *ssl_cert_file = GST_TEST_FILES_PATH "/test-cert.pem";
+static const char *ssl_key_file = GST_TEST_FILES_PATH "/test-key.pem";
+
+static guint get_port_from_server (SoupServer * server);
+static SoupServer *run_server (gboolean use_https);
+
+static void
+handoff_cb (GstElement * fakesink, GstBuffer * buf, GstPad * pad,
+    GstBuffer ** p_outbuf)
+{
+  GST_LOG ("handoff, buf = %p", buf);
+  if (*p_outbuf == NULL)
+    *p_outbuf = gst_buffer_ref (buf);
+}
+
+static gboolean
+basic_auth_cb (SoupAuthDomain * domain, SoupMessage * msg,
+    const char *username, const char *password, gpointer user_data)
+{
+  /* There is only one good login for testing */
+  return (strcmp (username, good_user) == 0)
+      && (strcmp (password, good_pw) == 0);
+}
+
+
+static char *
+digest_auth_cb (SoupAuthDomain * domain, SoupMessage * msg,
+    const char *username, gpointer user_data)
+{
+  /* There is only one good login for testing */
+  if (strcmp (username, good_user) == 0)
+    return soup_auth_domain_digest_encode_password (good_user, realm, good_pw);
+  return NULL;
+}
+
+static gboolean
+run_test (gboolean use_https, const gchar * path, gint expected)
+{
+  GstStateChangeReturn ret;
+  GstElement *pipe, *src, *sink;
+  GstBuffer *buf = NULL;
+  GstMessage *msg;
+  gchar *url;
+  gboolean res = FALSE;
+  SoupServer *server;
+  guint port;
+
+  server = run_server (use_https);
+  if (server == NULL) {
+    g_print ("Failed to start up %s server", use_https ? "HTTPS" : "HTTP");
+    /* skip this test */
+    return TRUE;
+  }
+
+  pipe = gst_pipeline_new (NULL);
+
+  src = gst_element_factory_make ("souphttpsrc", NULL);
+  fail_unless (src != NULL);
+
+  sink = gst_element_factory_make ("fakesink", NULL);
+  fail_unless (sink != NULL);
+
+  gst_bin_add (GST_BIN (pipe), src);
+  gst_bin_add (GST_BIN (pipe), sink);
+  fail_unless (gst_element_link (src, sink));
+
+  port = get_port_from_server (server);
+  url = g_strdup_printf ("%s://127.0.0.1:%u%s",
+      use_https ? "https" : "http", port, path);
+  fail_unless (url != NULL);
+  g_object_set (src, "location", url, NULL);
+  g_free (url);
+
+  if (use_https) {
+    GTlsDatabase *tlsdb;
+    GError *error = NULL;
+    gchar *path;
+
+    /* GTlsFileDatabase needs an absolute path. Using a relative one
+     * causes a warning from GLib-Net followed by a segfault in GnuTLS */
+    if (g_path_is_absolute (ssl_cert_file)) {
+      path = g_strdup (ssl_cert_file);
+    } else {
+      path = g_build_filename (g_get_current_dir (), ssl_cert_file, NULL);
+    }
+
+    tlsdb = g_tls_file_database_new (path, &error);
+    fail_unless (tlsdb, "Failed to load certificate: %s", error->message);
+
+    g_object_set (src, "tls-database", tlsdb, NULL);
+
+    g_object_unref (tlsdb);
+    g_free (path);
+  }
+
+  g_object_set (src, "automatic-redirect", redirect, NULL);
+  if (cookies != NULL)
+    g_object_set (src, "cookies", cookies, NULL);
+  g_object_set (sink, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (sink, "preroll-handoff", G_CALLBACK (handoff_cb), &buf);
+
+  if (user_id != NULL)
+    g_object_set (src, "user-id", user_id, NULL);
+  if (user_pw != NULL)
+    g_object_set (src, "user-pw", user_pw, NULL);
+
+  ret = gst_element_set_state (pipe, GST_STATE_PAUSED);
+  if (ret != GST_STATE_CHANGE_ASYNC) {
+    GST_DEBUG ("failed to start up soup http src, ret = %d", ret);
+    goto done;
+  }
+
+  gst_element_set_state (pipe, GST_STATE_PLAYING);
+  msg = gst_bus_poll (GST_ELEMENT_BUS (pipe),
+      GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
+    gchar *debug = NULL;
+    GError *err = NULL;
+    gint rc = -1;
+
+    gst_message_parse_error (msg, &err, &debug);
+    GST_INFO ("error: %s", err->message);
+    if (g_str_has_suffix (err->message, "Not Found"))
+      rc = 404;
+    else if (g_str_has_suffix (err->message, "Forbidden"))
+      rc = 403;
+    else if (g_str_has_suffix (err->message, "Unauthorized"))
+      rc = 401;
+    else if (g_str_has_suffix (err->message, "Found"))
+      rc = 302;
+    GST_INFO ("debug: %s", debug);
+    /* should not've gotten any output in case of a 40x error. Wait a bit
+     * to give the streaming thread a chance to push out a buffer and trigger
+     * our callback before shutting down the pipeline */
+    g_usleep (G_USEC_PER_SEC / 2);
+    fail_unless (buf == NULL);
+    g_error_free (err);
+    g_free (debug);
+    gst_message_unref (msg);
+    GST_DEBUG ("Got HTTP error %u, expected %u", rc, expected);
+    res = (rc == expected);
+    goto done;
+  }
+  gst_message_unref (msg);
+
+  /* don't wait for more than 10 seconds */
+  ret = gst_element_get_state (pipe, NULL, NULL, 10 * GST_SECOND);
+  GST_LOG ("ret = %u", ret);
+
+  if (buf == NULL) {
+    /* we want to test the buffer offset, nothing else; if there's a failure
+     * it might be for lots of reasons (no network connection, whatever), we're
+     * not interested in those */
+    GST_DEBUG ("didn't manage to get data within 10 seconds, skipping test");
+    res = TRUE;
+    goto done;
+  }
+
+  GST_DEBUG ("buffer offset = %" G_GUINT64_FORMAT, GST_BUFFER_OFFSET (buf));
+
+  /* first buffer should have a 0 offset */
+  fail_unless (GST_BUFFER_OFFSET (buf) == 0);
+  gst_buffer_unref (buf);
+  res = (expected == 0);
+
+done:
+
+  gst_element_set_state (pipe, GST_STATE_NULL);
+  gst_object_unref (pipe);
+  gst_object_unref (server);
+  return res;
+}
+
+GST_START_TEST (test_first_buffer_has_offset)
+{
+  fail_unless (run_test (FALSE, "/", 0));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_not_found)
+{
+  fail_unless (run_test (FALSE, "/404", 404));
+  fail_unless (run_test (FALSE, "/404-with-data", 404));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_forbidden)
+{
+  fail_unless (run_test (FALSE, "/403", 403));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_redirect_no)
+{
+  redirect = FALSE;
+  fail_unless (run_test (FALSE, "/302", 302));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_redirect_yes)
+{
+  redirect = TRUE;
+  fail_unless (run_test (FALSE, "/302", 0));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_https)
+{
+  fail_unless (run_test (TRUE, "/", 0));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_cookies)
+{
+  static const char *biscotti[] = { "delacre=yummie", "koekje=lu", NULL };
+  gboolean res;
+
+  cookies = biscotti;
+  res = run_test (FALSE, "/", 0);
+  cookies = NULL;
+  fail_unless (res);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_good_user_basic_auth)
+{
+  gboolean res;
+
+  user_id = good_user;
+  user_pw = good_pw;
+  res = run_test (FALSE, basic_auth_path, 0);
+  GST_DEBUG ("Basic Auth user %s password %s res = %d", user_id, user_pw, res);
+  user_id = user_pw = NULL;
+  fail_unless (res);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_bad_user_basic_auth)
+{
+  gboolean res;
+
+  user_id = bad_user;
+  user_pw = good_pw;
+  res = run_test (FALSE, basic_auth_path, 401);
+  GST_DEBUG ("Basic Auth user %s password %s res = %d", user_id, user_pw, res);
+  user_id = user_pw = NULL;
+  fail_unless (res);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_bad_password_basic_auth)
+{
+  gboolean res;
+
+  user_id = good_user;
+  user_pw = bad_pw;
+  res = run_test (FALSE, basic_auth_path, 401);
+  GST_DEBUG ("Basic Auth user %s password %s res = %d", user_id, user_pw, res);
+  user_id = user_pw = NULL;
+  fail_unless (res);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_good_user_digest_auth)
+{
+  gboolean res;
+
+  user_id = good_user;
+  user_pw = good_pw;
+  res = run_test (FALSE, digest_auth_path, 0);
+  GST_DEBUG ("Digest Auth user %s password %s res = %d", user_id, user_pw, res);
+  user_id = user_pw = NULL;
+  fail_unless (res);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_bad_user_digest_auth)
+{
+  gboolean res;
+
+  user_id = bad_user;
+  user_pw = good_pw;
+  res = run_test (FALSE, digest_auth_path, 401);
+  GST_DEBUG ("Digest Auth user %s password %s res = %d", user_id, user_pw, res);
+  user_id = user_pw = NULL;
+  fail_unless (res);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_bad_password_digest_auth)
+{
+  gboolean res;
+
+  user_id = good_user;
+  user_pw = bad_pw;
+  res = run_test (FALSE, digest_auth_path, 401);
+  GST_DEBUG ("Digest Auth user %s password %s res = %d", user_id, user_pw, res);
+  user_id = user_pw = NULL;
+  fail_unless (res);
+}
+
+GST_END_TEST;
+
+static gboolean icy_caps = FALSE;
+
+static void
+got_buffer (GstElement * fakesink, GstBuffer * buf, GstPad * pad,
+    gpointer user_data)
+{
+  GstStructure *s;
+  GstCaps *caps;
+
+  /* Caps can be anything if we don't except icy caps */
+  if (!icy_caps)
+    return;
+
+  /* Otherwise they _must_ be "application/x-icy" */
+  caps = gst_pad_get_current_caps (pad);
+  fail_unless (caps != NULL);
+  s = gst_caps_get_structure (caps, 0);
+  fail_unless_equals_string (gst_structure_get_name (s), "application/x-icy");
+  gst_caps_unref (caps);
+}
+
+GST_START_TEST (test_icy_stream)
+{
+  GstElement *pipe, *src, *sink;
+
+  GstMessage *msg;
+
+  pipe = gst_pipeline_new (NULL);
+
+  src = gst_element_factory_make ("souphttpsrc", NULL);
+  fail_unless (src != NULL);
+
+  sink = gst_element_factory_make ("fakesink", NULL);
+  fail_unless (sink != NULL);
+  g_object_set (sink, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (sink, "handoff", G_CALLBACK (got_buffer), NULL);
+
+  gst_bin_add (GST_BIN (pipe), src);
+  gst_bin_add (GST_BIN (pipe), sink);
+  fail_unless (gst_element_link (src, sink));
+
+  /* Radionomy Hot40Music shoutcast stream */
+  g_object_set (src, "location",
+      "http://streaming.radionomy.com:80/Hot40Music", NULL);
+
+  /* EOS after the first buffer */
+  g_object_set (src, "num-buffers", 1, NULL);
+  icy_caps = TRUE;
+  gst_element_set_state (pipe, GST_STATE_PLAYING);
+  msg = gst_bus_poll (GST_ELEMENT_BUS (pipe),
+      GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
+
+  switch (GST_MESSAGE_TYPE (msg)) {
+    case GST_MESSAGE_EOS:
+      GST_DEBUG ("success, we're done here");
+      gst_message_unref (msg);
+      break;
+    case GST_MESSAGE_ERROR:{
+      GError *err = NULL;
+
+      gst_message_parse_error (msg, &err, NULL);
+      GST_INFO ("Error with ICY mp3 shoutcast stream: %s", err->message);
+      gst_message_unref (msg);
+      g_clear_error (&err);
+      break;
+    }
+    default:
+      break;
+  }
+
+  icy_caps = FALSE;
+
+  gst_element_set_state (pipe, GST_STATE_NULL);
+  gst_object_unref (pipe);
+}
+
+GST_END_TEST;
+
+static Suite *
+souphttpsrc_suite (void)
+{
+  TCase *tc_chain, *tc_internet;
+  Suite *s;
+
+  /* we don't support exceptions from the proxy, so just unset the environment
+   * variable - in case it's set in the test environment it would otherwise
+   * prevent us from connecting to localhost (like jenkins.qa.ubuntu.com) */
+  g_unsetenv ("http_proxy");
+
+  s = suite_create ("souphttpsrc");
+  tc_chain = tcase_create ("general");
+  tc_internet = tcase_create ("internet");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_first_buffer_has_offset);
+  tcase_add_test (tc_chain, test_redirect_yes);
+  tcase_add_test (tc_chain, test_redirect_no);
+  tcase_add_test (tc_chain, test_not_found);
+  tcase_add_test (tc_chain, test_forbidden);
+  tcase_add_test (tc_chain, test_cookies);
+  tcase_add_test (tc_chain, test_good_user_basic_auth);
+  tcase_add_test (tc_chain, test_bad_user_basic_auth);
+  tcase_add_test (tc_chain, test_bad_password_basic_auth);
+  tcase_add_test (tc_chain, test_good_user_digest_auth);
+  tcase_add_test (tc_chain, test_bad_user_digest_auth);
+  tcase_add_test (tc_chain, test_bad_password_digest_auth);
+  tcase_add_test (tc_chain, test_https);
+
+  suite_add_tcase (s, tc_internet);
+  tcase_set_timeout (tc_internet, 250);
+  tcase_add_test (tc_internet, test_icy_stream);
+
+  return s;
+}
+
+GST_CHECK_MAIN (souphttpsrc);
+
+static void
+do_get (SoupMessage * msg, const char *path)
+{
+  gboolean send_error_doc = FALSE;
+  char *uri;
+
+  int buflen = 4096;
+
+  SoupStatus status = SOUP_STATUS_OK;
+
+  uri = soup_uri_to_string (soup_message_get_uri (msg), FALSE);
+  GST_DEBUG ("request: \"%s\"", uri);
+
+  if (!strcmp (path, "/301"))
+    status = SOUP_STATUS_MOVED_PERMANENTLY;
+  else if (!strcmp (path, "/302"))
+    status = SOUP_STATUS_MOVED_TEMPORARILY;
+  else if (!strcmp (path, "/307"))
+    status = SOUP_STATUS_TEMPORARY_REDIRECT;
+  else if (!strcmp (path, "/403"))
+    status = SOUP_STATUS_FORBIDDEN;
+  else if (!strcmp (path, "/404"))
+    status = SOUP_STATUS_NOT_FOUND;
+  else if (!strcmp (path, "/404-with-data")) {
+    status = SOUP_STATUS_NOT_FOUND;
+    send_error_doc = TRUE;
+  }
+
+  if (SOUP_STATUS_IS_REDIRECTION (status)) {
+    char *redir_uri;
+
+    redir_uri = g_strdup_printf ("%s-redirected", uri);
+    soup_message_headers_append (msg->response_headers, "Location", redir_uri);
+    g_free (redir_uri);
+  }
+  if (status != (SoupStatus) SOUP_STATUS_OK && !send_error_doc)
+    goto leave;
+
+  if (msg->method == SOUP_METHOD_GET) {
+    char *buf;
+
+    buf = g_malloc (buflen);
+    memset (buf, 0, buflen);
+    soup_message_body_append (msg->response_body, SOUP_MEMORY_TAKE,
+        buf, buflen);
+  } else {                      /* msg->method == SOUP_METHOD_HEAD */
+
+    char *length;
+
+    /* We could just use the same code for both GET and
+     * HEAD. But we'll optimize and avoid the extra
+     * malloc.
+     */
+    length = g_strdup_printf ("%lu", (gulong) buflen);
+    soup_message_headers_append (msg->response_headers,
+        "Content-Length", length);
+    g_free (length);
+  }
+
+leave:
+  soup_message_set_status (msg, status);
+  g_free (uri);
+}
+
+static void
+print_header (const char *name, const char *value, gpointer data)
+{
+  GST_DEBUG ("header: %s: %s", name, value);
+}
+
+static void
+server_callback (SoupServer * server, SoupMessage * msg,
+    const char *path, GHashTable * query,
+    SoupClientContext * context, gpointer data)
+{
+  GST_DEBUG ("%s %s HTTP/1.%d", msg->method, path,
+      soup_message_get_http_version (msg));
+  soup_message_headers_foreach (msg->request_headers, print_header, NULL);
+  if (msg->request_body->length)
+    GST_DEBUG ("%s", msg->request_body->data);
+
+  if (msg->method == SOUP_METHOD_GET || msg->method == SOUP_METHOD_HEAD)
+    do_get (msg, path);
+  else
+    soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
+
+  GST_DEBUG ("  -> %d %s", msg->status_code, msg->reason_phrase);
+}
+
+static guint
+get_port_from_server (SoupServer * server)
+{
+  GSList *uris;
+  guint port;
+
+  uris = soup_server_get_uris (server);
+  g_assert (g_slist_length (uris) == 1);
+  port = soup_uri_get_port (uris->data);
+  g_slist_free_full (uris, (GDestroyNotify) soup_uri_free);
+
+  return port;
+}
+
+static SoupServer *
+run_server (gboolean use_https)
+{
+  SoupServer *server = soup_server_new (NULL, NULL);
+  SoupServerListenOptions listen_flags = 0;
+  guint port;
+
+
+  if (use_https) {
+    GTlsBackend *backend = g_tls_backend_get_default ();
+    GError *err = NULL;
+
+    if (backend == NULL || !g_tls_backend_supports_tls (backend)) {
+      GST_INFO ("No TLS support");
+      g_object_unref (server);
+      return NULL;
+    }
+
+    if (!soup_server_set_ssl_cert_file (server, ssl_cert_file, ssl_key_file,
+          &err)) {
+      GST_INFO ("Failed to load certificate: %s", err->message);
+      g_object_unref (server);
+      g_error_free (err);
+      return NULL;
+    }
+
+    listen_flags |= SOUP_SERVER_LISTEN_HTTPS;
+  }
+
+  soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
+
+  {
+    SoupAuthDomain *domain;
+
+    domain = soup_auth_domain_basic_new (SOUP_AUTH_DOMAIN_REALM, realm,
+        SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK, basic_auth_cb,
+        SOUP_AUTH_DOMAIN_ADD_PATH, basic_auth_path, NULL);
+    soup_server_add_auth_domain (server, domain);
+    g_object_unref (domain);
+
+    domain = soup_auth_domain_digest_new (SOUP_AUTH_DOMAIN_REALM, realm,
+        SOUP_AUTH_DOMAIN_DIGEST_AUTH_CALLBACK, digest_auth_cb,
+        SOUP_AUTH_DOMAIN_ADD_PATH, digest_auth_path, NULL);
+    soup_server_add_auth_domain (server, domain);
+    g_object_unref (domain);
+  }
+
+  {
+    GSocketAddress *address;
+    GError *err = NULL;
+
+    address =
+        g_inet_socket_address_new_from_string ("0.0.0.0",
+        SOUP_ADDRESS_ANY_PORT);
+    soup_server_listen (server, address, listen_flags, &err);
+    g_object_unref (address);
+
+    if (err) {
+      GST_ERROR ("Failed to start %s server: %s",
+          use_https ? "HTTPS" : "HTTP", err->message);
+      g_object_unref (server);
+      g_error_free (err);
+      return NULL;
+    }
+  }
+
+  port = get_port_from_server (server);
+  GST_DEBUG ("%s server listening on port %u", use_https ? "HTTPS" : "HTTP",
+      port);
+
+  /* check if we can connect to our local http server */
+  {
+    GSocketConnection *conn;
+    GSocketClient *client;
+
+    client = g_socket_client_new ();
+    g_socket_client_set_timeout (client, 2);
+    conn =
+        g_socket_client_connect_to_host (client, "127.0.0.1", port, NULL, NULL);
+    if (conn == NULL) {
+      GST_INFO ("Couldn't connect to 127.0.0.1:%u", port);
+      g_object_unref (client);
+      g_object_unref (server);
+      return NULL;
+    }
+
+    g_object_unref (conn);
+    g_object_unref (client);
+  }
+
+  return server;
+}
diff --git a/tests/check/elements/spectrum.c b/tests/check/elements/spectrum.c
new file mode 100644
index 0000000..e97be03
--- /dev/null
+++ b/tests/check/elements/spectrum.c
@@ -0,0 +1,541 @@
+/* GStreamer
+ *
+ * unit test for spectrum
+ *
+ * Copyright (C) <2007> Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gst/audio/audio.h>
+#include <gst/check/gstcheck.h>
+
+gboolean have_eos = FALSE;
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *mysrcpad, *mysinkpad;
+
+#define SPECT_CAPS_TEMPLATE_STRING \
+    "audio/x-raw, "                                                   \
+    " rate = (int) [ 1, MAX ], "                                      \
+    " channels = (int) [ 1, MAX ], "                                  \
+    " layout = (string) interleaved, "                                \
+    " format = (string) { "                                           \
+    GST_AUDIO_NE(S16) ", "                                            \
+    GST_AUDIO_NE(S32) ", "                                            \
+    GST_AUDIO_NE(F32) ", "                                            \
+    GST_AUDIO_NE(F64) " }"
+
+#define SPECT_CAPS_STRING_S16 \
+  "audio/x-raw, " \
+    "rate = (int) 44100, " \
+    "channels = (int) 1, " \
+    "layout = (string) interleaved, " \
+    "format = (string) " GST_AUDIO_NE(S16)
+
+#define SPECT_CAPS_STRING_S32 \
+  "audio/x-raw, " \
+    "rate = (int) 44100, " \
+    "channels = (int) 1, " \
+    "layout = (string) interleaved, " \
+    "format = (string) " GST_AUDIO_NE(S32)
+
+#define SPECT_CAPS_STRING_F32 \
+    "audio/x-raw, "                                                   \
+    " rate = (int) 44100, "                                           \
+    " channels = (int) 1, "                                           \
+    " layout = (string) interleaved, " \
+    " format = (string) " GST_AUDIO_NE(F32)
+
+#define SPECT_CAPS_STRING_F64 \
+    "audio/x-raw, "                                                   \
+    " rate = (int) 44100, "                                           \
+    " channels = (int) 1, "                                           \
+    " layout = (string) interleaved, " \
+    " format = (string) " GST_AUDIO_NE(F64)
+
+#define SPECT_BANDS 256
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SPECT_CAPS_TEMPLATE_STRING)
+    );
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (SPECT_CAPS_TEMPLATE_STRING)
+    );
+
+/* takes over reference for outcaps */
+static GstElement *
+setup_spectrum (const gchar * caps_str)
+{
+  GstElement *spectrum;
+  GstCaps *caps;
+
+  GST_DEBUG ("setup_spectrum");
+  spectrum = gst_check_setup_element ("spectrum");
+  mysrcpad = gst_check_setup_src_pad (spectrum, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (spectrum, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  caps = gst_caps_from_string (caps_str);
+  gst_check_setup_events (mysrcpad, spectrum, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  return spectrum;
+}
+
+static void
+cleanup_spectrum (GstElement * spectrum)
+{
+  GST_DEBUG ("cleanup_spectrum");
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (spectrum);
+  gst_check_teardown_sink_pad (spectrum);
+  gst_check_teardown_element (spectrum);
+
+  g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+}
+
+
+GST_START_TEST (test_int16)
+{
+  GstElement *spectrum;
+  GstBuffer *inbuffer, *outbuffer;
+  GstBus *bus;
+  GstMessage *message;
+  const GstStructure *structure;
+  int i, j;
+  gint16 *data;
+  GstMapInfo map;
+  const GValue *list, *value;
+  GstClockTime endtime;
+  gfloat level;
+
+  spectrum = setup_spectrum (SPECT_CAPS_STRING_S16);
+  g_object_set (spectrum, "post-messages", TRUE, "interval", GST_SECOND / 100,
+      "bands", SPECT_BANDS, "threshold", -80, NULL);
+
+  fail_unless (gst_element_set_state (spectrum,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  /* create a 1 sec buffer with an 11025 Hz sine wave */
+  inbuffer = gst_buffer_new_allocate (NULL, 44100 * sizeof (gint16), 0);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  data = (gint16 *) map.data;
+  for (j = 0; j < 44100; j += 4) {
+    *data = 0;
+    ++data;
+    *data = 32767;
+    ++data;
+    *data = 0;
+    ++data;
+    *data = -32767;
+    ++data;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* create a bus to get the spectrum message on */
+  bus = gst_bus_new ();
+  ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
+  gst_element_set_bus (spectrum, bus);
+  ASSERT_OBJECT_REFCOUNT (bus, "bus", 2);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... but it ends up being collected on the global buffer list */
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (inbuffer == outbuffer);
+
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
+  ASSERT_OBJECT_REFCOUNT (message, "message", 1);
+
+  fail_unless (message != NULL);
+  fail_unless (GST_MESSAGE_SRC (message) == GST_OBJECT (spectrum));
+  fail_unless (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT);
+  structure = gst_message_get_structure (message);
+  fail_if (structure == NULL);
+  fail_unless_equals_string ((char *) gst_structure_get_name (structure),
+      "spectrum");
+  fail_unless (gst_structure_get_clock_time (structure, "endtime", &endtime));
+
+  list = gst_structure_get_value (structure, "magnitude");
+  for (i = 0; i < SPECT_BANDS; ++i) {
+    value = gst_value_list_get_value (list, i);
+    level = g_value_get_float (value);
+    GST_DEBUG ("band[%3d] is %.2f", i, level);
+    /* Only the bands in the middle should have a level above 60 */
+    fail_if ((i == SPECT_BANDS / 2 || i == SPECT_BANDS / 2 - 1)
+        && level < -20.0);
+    fail_if ((i != SPECT_BANDS / 2 && i != SPECT_BANDS / 2 - 1)
+        && level > -20.0);
+  }
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (inbuffer == outbuffer);
+
+  /* clean up */
+  /* flush current messages,and future state change messages */
+  gst_bus_set_flushing (bus, TRUE);
+
+  /* message has a ref to the element */
+  ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 2);
+  gst_message_unref (message);
+  ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
+
+  gst_element_set_bus (spectrum, NULL);
+  ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
+  gst_object_unref (bus);
+  fail_unless (gst_element_set_state (spectrum,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+  ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
+  cleanup_spectrum (spectrum);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_int32)
+{
+  GstElement *spectrum;
+  GstBuffer *inbuffer, *outbuffer;
+  GstBus *bus;
+  GstMessage *message;
+  const GstStructure *structure;
+  int i, j;
+  gint32 *data;
+  GstMapInfo map;
+  const GValue *list, *value;
+  GstClockTime endtime;
+  gfloat level;
+
+  spectrum = setup_spectrum (SPECT_CAPS_STRING_S32);
+  g_object_set (spectrum, "post-messages", TRUE, "interval", GST_SECOND / 100,
+      "bands", SPECT_BANDS, "threshold", -80, NULL);
+
+  fail_unless (gst_element_set_state (spectrum,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  /* create a 1 sec buffer with an 11025 Hz sine wave */
+  inbuffer = gst_buffer_new_allocate (NULL, 44100 * sizeof (gint32), 0);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  data = (gint32 *) map.data;
+  for (j = 0; j < 44100; j += 4) {
+    *data = 0;
+    ++data;
+    *data = 2147483647;
+    ++data;
+    *data = 0;
+    ++data;
+    *data = -2147483647;
+    ++data;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* create a bus to get the spectrum message on */
+  bus = gst_bus_new ();
+  ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
+  gst_element_set_bus (spectrum, bus);
+  ASSERT_OBJECT_REFCOUNT (bus, "bus", 2);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... but it ends up being collected on the global buffer list */
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (inbuffer == outbuffer);
+
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
+  ASSERT_OBJECT_REFCOUNT (message, "message", 1);
+
+  fail_unless (message != NULL);
+  fail_unless (GST_MESSAGE_SRC (message) == GST_OBJECT (spectrum));
+  fail_unless (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT);
+  structure = gst_message_get_structure (message);
+  fail_if (structure == NULL);
+  fail_unless_equals_string ((char *) gst_structure_get_name (structure),
+      "spectrum");
+  fail_unless (gst_structure_get_clock_time (structure, "endtime", &endtime));
+
+  list = gst_structure_get_value (structure, "magnitude");
+  for (i = 0; i < SPECT_BANDS; ++i) {
+    value = gst_value_list_get_value (list, i);
+    level = g_value_get_float (value);
+    GST_DEBUG ("band[%3d] is %.2f", i, level);
+    /* Only the bands in the middle should have a level above 60 */
+    fail_if ((i == SPECT_BANDS / 2 || i == SPECT_BANDS / 2 - 1)
+        && level < -20.0);
+    fail_if ((i != SPECT_BANDS / 2 && i != SPECT_BANDS / 2 - 1)
+        && level > -20.0);
+  }
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (inbuffer == outbuffer);
+
+  /* clean up */
+  /* flush current messages,and future state change messages */
+  gst_bus_set_flushing (bus, TRUE);
+
+  /* message has a ref to the element */
+  ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 2);
+  gst_message_unref (message);
+  ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
+
+  gst_element_set_bus (spectrum, NULL);
+  ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
+  gst_object_unref (bus);
+  fail_unless (gst_element_set_state (spectrum,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+  ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
+  cleanup_spectrum (spectrum);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_float32)
+{
+  GstElement *spectrum;
+  GstBuffer *inbuffer, *outbuffer;
+  GstBus *bus;
+  GstMessage *message;
+  const GstStructure *structure;
+  int i, j;
+  gfloat *data;
+  GstMapInfo map;
+  const GValue *list, *value;
+  GstClockTime endtime;
+  gfloat level;
+
+  spectrum = setup_spectrum (SPECT_CAPS_STRING_F32);
+  g_object_set (spectrum, "post-messages", TRUE, "interval", GST_SECOND / 100,
+      "bands", SPECT_BANDS, "threshold", -80, NULL);
+
+  fail_unless (gst_element_set_state (spectrum,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  /* create a 1 sec buffer with an 11025 Hz sine wave */
+  inbuffer = gst_buffer_new_allocate (NULL, 44100 * sizeof (gfloat), 0);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  data = (gfloat *) map.data;
+  for (j = 0; j < 44100; j += 4) {
+    *data = 0.0;
+    ++data;
+    *data = 1.0;
+    ++data;
+    *data = 0.0;
+    ++data;
+    *data = -1.0;
+    ++data;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* create a bus to get the spectrum message on */
+  bus = gst_bus_new ();
+  ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
+  gst_element_set_bus (spectrum, bus);
+  ASSERT_OBJECT_REFCOUNT (bus, "bus", 2);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... but it ends up being collected on the global buffer list */
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (inbuffer == outbuffer);
+
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
+  ASSERT_OBJECT_REFCOUNT (message, "message", 1);
+
+  fail_unless (message != NULL);
+  fail_unless (GST_MESSAGE_SRC (message) == GST_OBJECT (spectrum));
+  fail_unless (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT);
+  structure = gst_message_get_structure (message);
+  fail_if (structure == NULL);
+  fail_unless_equals_string ((char *) gst_structure_get_name (structure),
+      "spectrum");
+  fail_unless (gst_structure_get_clock_time (structure, "endtime", &endtime));
+
+  list = gst_structure_get_value (structure, "magnitude");
+  for (i = 0; i < SPECT_BANDS; ++i) {
+    value = gst_value_list_get_value (list, i);
+    level = g_value_get_float (value);
+    GST_DEBUG ("band[%3d] is %.2f", i, level);
+    /* Only the bands in the middle should have a level above 60 */
+    fail_if ((i == SPECT_BANDS / 2 || i == SPECT_BANDS / 2 - 1)
+        && level < -20.0);
+    fail_if ((i != SPECT_BANDS / 2 && i != SPECT_BANDS / 2 - 1)
+        && level > -20.0);
+  }
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (inbuffer == outbuffer);
+
+  /* clean up */
+  /* flush current messages,and future state change messages */
+  gst_bus_set_flushing (bus, TRUE);
+
+  /* message has a ref to the element */
+  ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 2);
+  gst_message_unref (message);
+  ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
+
+  gst_element_set_bus (spectrum, NULL);
+  ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
+  gst_object_unref (bus);
+  fail_unless (gst_element_set_state (spectrum,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+  ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
+  cleanup_spectrum (spectrum);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_float64)
+{
+  GstElement *spectrum;
+  GstBuffer *inbuffer, *outbuffer;
+  GstBus *bus;
+  GstMessage *message;
+  const GstStructure *structure;
+  int i, j;
+  gdouble *data;
+  GstMapInfo map;
+  const GValue *list, *value;
+  GstClockTime endtime;
+  gfloat level;
+
+  spectrum = setup_spectrum (SPECT_CAPS_STRING_F64);
+  g_object_set (spectrum, "post-messages", TRUE, "interval", GST_SECOND / 100,
+      "bands", SPECT_BANDS, "threshold", -80, NULL);
+
+  fail_unless (gst_element_set_state (spectrum,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  /* create a 1 sec buffer with an 11025 Hz sine wave */
+  inbuffer = gst_buffer_new_allocate (NULL, 44100 * sizeof (gdouble), 0);
+  gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
+  data = (gdouble *) map.data;
+  for (j = 0; j < 44100; j += 4) {
+    *data = 0.0;
+    ++data;
+    *data = 1.0;
+    ++data;
+    *data = 0.0;
+    ++data;
+    *data = -1.0;
+    ++data;
+  }
+  gst_buffer_unmap (inbuffer, &map);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  /* create a bus to get the spectrum message on */
+  bus = gst_bus_new ();
+  ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
+  gst_element_set_bus (spectrum, bus);
+  ASSERT_OBJECT_REFCOUNT (bus, "bus", 2);
+
+  /* pushing gives away my reference ... */
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  /* ... but it ends up being collected on the global buffer list */
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (inbuffer == outbuffer);
+
+  message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
+  ASSERT_OBJECT_REFCOUNT (message, "message", 1);
+
+  fail_unless (message != NULL);
+  fail_unless (GST_MESSAGE_SRC (message) == GST_OBJECT (spectrum));
+  fail_unless (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT);
+  structure = gst_message_get_structure (message);
+  fail_if (structure == NULL);
+  fail_unless_equals_string ((char *) gst_structure_get_name (structure),
+      "spectrum");
+  fail_unless (gst_structure_get_clock_time (structure, "endtime", &endtime));
+
+  list = gst_structure_get_value (structure, "magnitude");
+  for (i = 0; i < SPECT_BANDS; ++i) {
+    value = gst_value_list_get_value (list, i);
+    level = g_value_get_float (value);
+    GST_DEBUG ("band[%3d] is %.2f", i, level);
+    /* Only the bands in the middle should have a level above 60 */
+    fail_if ((i == SPECT_BANDS / 2 || i == SPECT_BANDS / 2 - 1)
+        && level < -20.0);
+    fail_if ((i != SPECT_BANDS / 2 && i != SPECT_BANDS / 2 - 1)
+        && level > -20.0);
+  }
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
+  fail_unless (inbuffer == outbuffer);
+
+  /* clean up */
+  /* flush current messages,and future state change messages */
+  gst_bus_set_flushing (bus, TRUE);
+
+  /* message has a ref to the element */
+  ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 2);
+  gst_message_unref (message);
+  ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
+
+  gst_element_set_bus (spectrum, NULL);
+  ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
+  gst_object_unref (bus);
+  fail_unless (gst_element_set_state (spectrum,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+  ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
+  cleanup_spectrum (spectrum);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+spectrum_suite (void)
+{
+  Suite *s = suite_create ("spectrum");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_int16);
+  tcase_add_test (tc_chain, test_int32);
+  tcase_add_test (tc_chain, test_float32);
+  tcase_add_test (tc_chain, test_float64);
+
+  return s;
+}
+
+GST_CHECK_MAIN (spectrum);
diff --git a/tests/check/elements/splitmux.c b/tests/check/elements/splitmux.c
new file mode 100644
index 0000000..5fb78d2
--- /dev/null
+++ b/tests/check/elements/splitmux.c
@@ -0,0 +1,793 @@
+/* GStreamer unit test for splitmuxsrc/sink elements
+ *
+ * Copyright (C) 2007 David A. Schleef <ds@schleef.org>
+ * Copyright (C) 2015 Jan Schmidt <jan@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <glib/gstdio.h>
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+#include <gst/app/app.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+gchar *tmpdir = NULL;
+GstClockTime first_ts;
+GstClockTime last_ts;
+gdouble current_rate;
+
+static void
+tempdir_setup (void)
+{
+  const gchar *systmp = g_get_tmp_dir ();
+  tmpdir = g_build_filename (systmp, "splitmux-test-XXXXXX", NULL);
+  /* Rewrites tmpdir template input: */
+  tmpdir = g_mkdtemp (tmpdir);
+}
+
+static void
+tempdir_cleanup (void)
+{
+  GDir *d;
+  const gchar *f;
+
+  fail_if (tmpdir == NULL);
+
+  d = g_dir_open (tmpdir, 0, NULL);
+  fail_if (d == NULL);
+
+  while ((f = g_dir_read_name (d)) != NULL) {
+    gchar *fname = g_build_filename (tmpdir, f, NULL);
+    fail_if (g_remove (fname) != 0, "Failed to remove tmp file %s", fname);
+    g_free (fname);
+  }
+  g_dir_close (d);
+
+  fail_if (g_remove (tmpdir) != 0, "Failed to delete tmpdir %s", tmpdir);
+
+  g_free (tmpdir);
+  tmpdir = NULL;
+}
+
+static guint
+count_files (const gchar * target)
+{
+  GDir *d;
+  const gchar *f;
+  guint ret = 0;
+
+  d = g_dir_open (target, 0, NULL);
+  fail_if (d == NULL);
+
+  while ((f = g_dir_read_name (d)) != NULL)
+    ret++;
+  g_dir_close (d);
+
+  return ret;
+}
+
+static void
+dump_error (GstMessage * msg)
+{
+  GError *err = NULL;
+  gchar *dbg_info;
+
+  fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR);
+
+  gst_message_parse_error (msg, &err, &dbg_info);
+
+  g_printerr ("ERROR from element %s: %s\n",
+      GST_OBJECT_NAME (msg->src), err->message);
+  g_printerr ("Debugging info: %s\n", (dbg_info) ? dbg_info : "none");
+  g_error_free (err);
+  g_free (dbg_info);
+}
+
+static GstMessage *
+run_pipeline (GstElement * pipeline)
+{
+  GstBus *bus = gst_element_get_bus (GST_ELEMENT (pipeline));
+  GstMessage *msg;
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  msg = gst_bus_poll (bus, GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  gst_object_unref (bus);
+
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR)
+    dump_error (msg);
+
+  return msg;
+}
+
+static void
+seek_pipeline (GstElement * pipeline, gdouble rate, GstClockTime start,
+    GstClockTime end)
+{
+  /* Pause the pipeline, seek to the desired range / rate, wait for PAUSED again, then
+   * clear the tracking vars for start_ts / end_ts */
+  gst_element_set_state (pipeline, GST_STATE_PAUSED);
+  gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
+
+  /* specific end time not implemented: */
+  fail_unless (end == GST_CLOCK_TIME_NONE);
+
+  gst_element_seek (pipeline, rate, GST_FORMAT_TIME,
+      GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, start,
+      GST_SEEK_TYPE_END, 0);
+
+  /* Wait for the pipeline to preroll again */
+  gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
+
+  GST_LOG ("Seeked pipeline. Rate %f time range %" GST_TIME_FORMAT " to %"
+      GST_TIME_FORMAT, rate, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
+
+  /* Clear tracking variables now that the seek is complete */
+  first_ts = last_ts = GST_CLOCK_TIME_NONE;
+  current_rate = rate;
+};
+
+static void
+receive_handoff (GstElement * object G_GNUC_UNUSED, GstBuffer * buf,
+    GstPad * arg1 G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED)
+{
+  GstClockTime start = GST_BUFFER_TIMESTAMP (buf);
+  GstClockTime end = start;
+
+  if (GST_BUFFER_DURATION_IS_VALID (buf))
+    end += GST_BUFFER_DURATION (buf);
+
+  GST_LOG ("Got buffer %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (start), GST_TIME_ARGS (end));
+
+  /* Check time is moving in the right direction */
+  if (current_rate > 0) {
+    if (GST_CLOCK_TIME_IS_VALID (first_ts))
+      fail_unless (start >= first_ts,
+          "Timestamps went backward during forward play, %" GST_TIME_FORMAT
+          " < %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
+          GST_TIME_ARGS (first_ts));
+    if (GST_CLOCK_TIME_IS_VALID (last_ts))
+      fail_unless (end >= last_ts,
+          "Timestamps went backward during forward play, %" GST_TIME_FORMAT
+          " < %" GST_TIME_FORMAT, GST_TIME_ARGS (end), GST_TIME_ARGS (last_ts));
+  } else {
+    fail_unless (start <= first_ts,
+        "Timestamps went forward during reverse play, %" GST_TIME_FORMAT " > %"
+        GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (first_ts));
+    fail_unless (end <= last_ts,
+        "Timestamps went forward during reverse play, %" GST_TIME_FORMAT " > %"
+        GST_TIME_FORMAT, GST_TIME_ARGS (end), GST_TIME_ARGS (last_ts));
+  }
+
+  /* update the range of timestamps we've encountered */
+  if (!GST_CLOCK_TIME_IS_VALID (first_ts) || start < first_ts)
+    first_ts = start;
+  if (!GST_CLOCK_TIME_IS_VALID (last_ts) || end > last_ts)
+    last_ts = end;
+}
+
+static void
+test_playback (const gchar * in_pattern, GstClockTime exp_first_time,
+    GstClockTime exp_last_time)
+{
+  GstMessage *msg;
+  GstElement *pipeline;
+  GstElement *fakesink;
+  gchar *uri;
+
+  pipeline = gst_element_factory_make ("playbin", NULL);
+  fail_if (pipeline == NULL);
+
+  fakesink = gst_element_factory_make ("fakesink", NULL);
+  fail_if (fakesink == NULL);
+  g_object_set (G_OBJECT (pipeline), "video-sink", fakesink, NULL);
+
+  uri = g_strdup_printf ("splitmux://%s", in_pattern);
+
+  g_object_set (G_OBJECT (pipeline), "uri", uri, NULL);
+  g_free (uri);
+
+  g_signal_connect (fakesink, "handoff", (GCallback) receive_handoff, NULL);
+  g_object_set (G_OBJECT (fakesink), "signal-handoffs", TRUE, NULL);
+
+  /* test forwards */
+  seek_pipeline (pipeline, 1.0, 0, -1);
+  fail_unless (first_ts == GST_CLOCK_TIME_NONE);
+  msg = run_pipeline (pipeline);
+  fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
+  gst_message_unref (msg);
+
+  /* Check we saw the entire range of values */
+  fail_unless (first_ts == exp_first_time,
+      "Expected start of playback range 0, got %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (first_ts));
+  fail_unless (last_ts == exp_last_time,
+      "Expected end of playback range 3s, got %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (last_ts));
+
+  /* Test backwards */
+  seek_pipeline (pipeline, -1.0, 0, -1);
+  msg = run_pipeline (pipeline);
+  fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
+  gst_message_unref (msg);
+  /* Check we saw the entire range of values */
+  fail_unless (first_ts == exp_first_time,
+      "Expected start of playback range %" GST_TIME_FORMAT
+      ", got %" GST_TIME_FORMAT, GST_TIME_ARGS (exp_first_time),
+      GST_TIME_ARGS (first_ts));
+  fail_unless (last_ts == exp_last_time,
+      "Expected end of playback range %" GST_TIME_FORMAT
+      ", got %" GST_TIME_FORMAT, GST_TIME_ARGS (exp_last_time),
+      GST_TIME_ARGS (last_ts));
+
+  gst_object_unref (pipeline);
+}
+
+GST_START_TEST (test_splitmuxsrc)
+{
+  gchar *in_pattern =
+      g_build_filename (GST_TEST_FILES_PATH, "splitvideo*.ogg", NULL);
+  test_playback (in_pattern, 0, 3 * GST_SECOND);
+  g_free (in_pattern);
+}
+
+GST_END_TEST;
+
+static gchar **
+src_format_location_cb (GstElement * splitmuxsrc, gpointer user_data)
+{
+  gchar **result = g_malloc0_n (4, sizeof (gchar *));
+  result[0] = g_build_filename (GST_TEST_FILES_PATH, "splitvideo00.ogg", NULL);
+  result[1] = g_build_filename (GST_TEST_FILES_PATH, "splitvideo01.ogg", NULL);
+  result[2] = g_build_filename (GST_TEST_FILES_PATH, "splitvideo02.ogg", NULL);
+  return result;
+}
+
+GST_START_TEST (test_splitmuxsrc_format_location)
+{
+  GstMessage *msg;
+  GstElement *pipeline;
+  GstElement *src;
+  GError *error = NULL;
+
+  pipeline = gst_parse_launch ("splitmuxsrc name=splitsrc ! decodebin "
+      "! fakesink", &error);
+  g_assert_no_error (error);
+  fail_if (pipeline == NULL);
+
+  src = gst_bin_get_by_name (GST_BIN (pipeline), "splitsrc");
+  g_signal_connect (src, "format-location",
+      (GCallback) src_format_location_cb, NULL);
+  g_object_unref (src);
+
+  msg = run_pipeline (pipeline);
+
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR)
+    dump_error (msg);
+  fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
+  gst_message_unref (msg);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
+static gchar *
+check_format_location (GstElement * object,
+    guint fragment_id, GstSample * first_sample)
+{
+  GstBuffer *buf = gst_sample_get_buffer (first_sample);
+
+  /* Must have a buffer */
+  fail_if (buf == NULL);
+  GST_LOG ("New file - first buffer %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+
+  return NULL;
+}
+
+GST_START_TEST (test_splitmuxsink)
+{
+  GstMessage *msg;
+  GstElement *pipeline;
+  GstElement *sink;
+  GstPad *splitmux_sink_pad;
+  GstPad *enc_src_pad;
+  gchar *dest_pattern;
+  guint count;
+  gchar *in_pattern;
+
+  /* This pipeline has a small time cutoff - it should start a new file
+   * every GOP, ie 1 second */
+  pipeline =
+      gst_parse_launch
+      ("videotestsrc num-buffers=15 ! video/x-raw,width=80,height=64,framerate=5/1 ! videoconvert !"
+      " queue ! theoraenc keyframe-force=5 ! splitmuxsink name=splitsink "
+      " max-size-time=1000000 max-size-bytes=1000000 muxer=oggmux", NULL);
+  fail_if (pipeline == NULL);
+  sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink");
+  fail_if (sink == NULL);
+  g_signal_connect (sink, "format-location-full",
+      (GCallback) check_format_location, NULL);
+  dest_pattern = g_build_filename (tmpdir, "out%05d.ogg", NULL);
+  g_object_set (G_OBJECT (sink), "location", dest_pattern, NULL);
+  g_free (dest_pattern);
+  g_object_unref (sink);
+
+  msg = run_pipeline (pipeline);
+
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR)
+    dump_error (msg);
+  fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
+  gst_message_unref (msg);
+
+  /* unlink manually and relase request pad to ensure that we *can* do that
+   * - https://bugzilla.gnome.org/show_bug.cgi?id=753622 */
+  sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink");
+  fail_if (sink == NULL);
+  splitmux_sink_pad = gst_element_get_static_pad (sink, "video");
+  fail_if (splitmux_sink_pad == NULL);
+  enc_src_pad = gst_pad_get_peer (splitmux_sink_pad);
+  fail_if (enc_src_pad == NULL);
+  fail_unless (gst_pad_unlink (enc_src_pad, splitmux_sink_pad));
+  gst_object_unref (enc_src_pad);
+  gst_element_release_request_pad (sink, splitmux_sink_pad);
+  gst_object_unref (splitmux_sink_pad);
+  /* at this point the pad must be releaased - try to find it again to verify */
+  splitmux_sink_pad = gst_element_get_static_pad (sink, "video");
+  fail_if (splitmux_sink_pad != NULL);
+  g_object_unref (sink);
+
+  gst_object_unref (pipeline);
+
+  count = count_files (tmpdir);
+  fail_unless (count == 3, "Expected 3 output files, got %d", count);
+
+  in_pattern = g_build_filename (tmpdir, "out*.ogg", NULL);
+  test_playback (in_pattern, 0, 3 * GST_SECOND);
+  g_free (in_pattern);
+}
+
+GST_END_TEST;
+
+static GstPadProbeReturn
+intercept_stream_start (GstPad * pad, GstPadProbeInfo * info,
+    gpointer user_data)
+{
+  GstEvent *event = gst_pad_probe_info_get_event (info);
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START) {
+    GstStreamFlags flags;
+    event = gst_event_make_writable (event);
+    gst_event_parse_stream_flags (event, &flags);
+    gst_event_set_stream_flags (event, flags | GST_STREAM_FLAG_SPARSE);
+    GST_PAD_PROBE_INFO_DATA (info) = event;
+  }
+
+  return GST_PAD_PROBE_OK;
+}
+
+static GstFlowReturn
+new_sample_verify_continuous_timestamps (GstAppSink * appsink,
+    gpointer user_data)
+{
+  GstSample *sample;
+  GstBuffer *buffer;
+  GstClockTime *prev_ts = user_data;
+  GstClockTime new_ts;
+
+  sample = gst_app_sink_pull_sample (appsink);
+  buffer = gst_sample_get_buffer (sample);
+
+  new_ts = GST_BUFFER_PTS (buffer);
+  if (GST_CLOCK_TIME_IS_VALID (*prev_ts)) {
+    fail_unless (*prev_ts < new_ts,
+        "%s: prev_ts (%" GST_TIME_FORMAT ") >= new_ts (%" GST_TIME_FORMAT ")",
+        GST_OBJECT_NAME (appsink), GST_TIME_ARGS (*prev_ts),
+        GST_TIME_ARGS (new_ts));
+  }
+
+  *prev_ts = new_ts;
+  gst_sample_unref (sample);
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+new_sample_verify_1sec_offset (GstAppSink * appsink, gpointer user_data)
+{
+  GstSample *sample;
+  GstBuffer *buffer;
+  GstClockTime *prev_ts = user_data;
+  GstClockTime new_ts;
+
+  sample = gst_app_sink_pull_sample (appsink);
+  buffer = gst_sample_get_buffer (sample);
+
+  new_ts = GST_BUFFER_PTS (buffer);
+  if (GST_CLOCK_TIME_IS_VALID (*prev_ts)) {
+    fail_unless (new_ts > (*prev_ts + 900 * GST_MSECOND),
+        "%s: prev_ts (%" GST_TIME_FORMAT ") + 0.9s >= new_ts (%"
+        GST_TIME_FORMAT ")", GST_OBJECT_NAME (appsink),
+        GST_TIME_ARGS (*prev_ts), GST_TIME_ARGS (new_ts));
+  }
+
+  *prev_ts = new_ts;
+  gst_sample_unref (sample);
+  return GST_FLOW_OK;
+}
+
+/* https://bugzilla.gnome.org/show_bug.cgi?id=761086 */
+GST_START_TEST (test_splitmuxsrc_sparse_streams)
+{
+  GstElement *pipeline;
+  GstElement *element;
+  gchar *dest_pattern;
+  GstElement *appsrc;
+  GstPad *appsrc_src;
+  GstBus *bus;
+  GstMessage *msg;
+  gint i;
+
+  /* generate files */
+
+  /* in this test, we have 5sec of data with files split at 1sec intervals */
+  pipeline =
+      gst_parse_launch
+      ("videotestsrc num-buffers=75 !"
+      "  video/x-raw,width=80,height=64,framerate=15/1 !"
+      "  theoraenc keyframe-force=5 ! splitmuxsink name=splitsink"
+      "    max-size-time=1000000000 muxer=matroskamux"
+      " audiotestsrc num-buffers=100 samplesperbuffer=1024 !"
+      "  audio/x-raw,rate=20000 ! vorbisenc ! splitsink.audio_%u"
+      " appsrc name=appsrc format=time caps=text/x-raw,format=utf8 !"
+      "  splitsink.subtitle_%u", NULL);
+  fail_if (pipeline == NULL);
+
+  element = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink");
+  fail_if (element == NULL);
+  dest_pattern = g_build_filename (tmpdir, "out%05d.ogg", NULL);
+  g_object_set (G_OBJECT (element), "location", dest_pattern, NULL);
+  g_clear_pointer (&dest_pattern, g_free);
+  g_clear_object (&element);
+
+  appsrc = gst_bin_get_by_name (GST_BIN (pipeline), "appsrc");
+  fail_if (appsrc == NULL);
+
+  /* add the SPARSE flag on the stream-start event of the subtitle stream */
+  appsrc_src = gst_element_get_static_pad (appsrc, "src");
+  fail_if (appsrc_src == NULL);
+  gst_pad_add_probe (appsrc_src, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
+      intercept_stream_start, NULL, NULL);
+  g_clear_object (&appsrc_src);
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  /* push subtitles, one per second, starting from t=100ms */
+  for (i = 0; i < 5; i++) {
+    GstBuffer *buffer = gst_buffer_new_allocate (NULL, 5, NULL);
+    GstMapInfo info;
+
+    gst_buffer_map (buffer, &info, GST_MAP_WRITE);
+    strcpy ((char *) info.data, "test");
+    gst_buffer_unmap (buffer, &info);
+
+    GST_BUFFER_PTS (buffer) = i * GST_SECOND + 100 * GST_MSECOND;
+    GST_BUFFER_DTS (buffer) = GST_BUFFER_PTS (buffer);
+
+    fail_if (gst_app_src_push_buffer (GST_APP_SRC (appsrc), buffer)
+        != GST_FLOW_OK);
+  }
+  fail_if (gst_app_src_end_of_stream (GST_APP_SRC (appsrc)) != GST_FLOW_OK);
+
+  msg = gst_bus_timed_pop_filtered (bus, 5 * GST_SECOND, GST_MESSAGE_EOS);
+  g_clear_pointer (&msg, gst_message_unref);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  g_clear_object (&appsrc);
+  g_clear_object (&bus);
+  g_clear_object (&pipeline);
+
+  /* read and verify */
+
+  pipeline =
+      gst_parse_launch
+      ("splitmuxsrc name=splitsrc"
+      " splitsrc. ! theoradec ! appsink name=vsink sync=false emit-signals=true"
+      " splitsrc. ! vorbisdec ! appsink name=asink sync=false emit-signals=true"
+      " splitsrc. ! text/x-raw ! appsink name=tsink sync=false emit-signals=true",
+      NULL);
+  fail_if (pipeline == NULL);
+
+  element = gst_bin_get_by_name (GST_BIN (pipeline), "splitsrc");
+  fail_if (element == NULL);
+  dest_pattern = g_build_filename (tmpdir, "out*.ogg", NULL);
+  g_object_set (G_OBJECT (element), "location", dest_pattern, NULL);
+  g_clear_pointer (&dest_pattern, g_free);
+  g_clear_object (&element);
+
+  {
+    GstClockTime vsink_prev_ts = GST_CLOCK_TIME_NONE;
+    GstClockTime asink_prev_ts = GST_CLOCK_TIME_NONE;
+    GstClockTime tsink_prev_ts = GST_CLOCK_TIME_NONE;
+
+    /* verify that timestamps are continuously increasing for audio + video.
+     * if we hit bug 761086, timestamps will jump about -900ms after switching
+     * to a new part, because this is the difference between the last subtitle
+     * pts and the last audio/video pts */
+    element = gst_bin_get_by_name (GST_BIN (pipeline), "vsink");
+    g_signal_connect (element, "new-sample",
+        (GCallback) new_sample_verify_continuous_timestamps, &vsink_prev_ts);
+    g_clear_object (&element);
+
+    element = gst_bin_get_by_name (GST_BIN (pipeline), "asink");
+    g_signal_connect (element, "new-sample",
+        (GCallback) new_sample_verify_continuous_timestamps, &asink_prev_ts);
+    g_clear_object (&element);
+
+    /* also verify that subtitle timestamps are increasing by about 1s.
+     * if we hit bug 761086, timestamps will increase by exactly 100ms instead,
+     * because this is the relative difference between a part's start time
+     * (remember a new part starts every 1sec) and the subtitle's pts in that
+     * part, which will be added to the max_ts of the previous part, which
+     * equals the last subtitle's pts (and should not!) */
+    element = gst_bin_get_by_name (GST_BIN (pipeline), "tsink");
+    g_signal_connect (element, "new-sample",
+        (GCallback) new_sample_verify_1sec_offset, &tsink_prev_ts);
+    g_clear_object (&element);
+
+    msg = run_pipeline (pipeline);
+  }
+
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR)
+    dump_error (msg);
+  fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
+
+  g_clear_pointer (&msg, gst_message_unref);
+  g_clear_object (&pipeline);
+}
+
+GST_END_TEST;
+
+struct CapsChangeData
+{
+  guint count;
+  GstElement *cf;
+};
+
+static GstPadProbeReturn
+switch_caps (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
+{
+  struct CapsChangeData *data = (struct CapsChangeData *) (user_data);
+
+  if (data->count == 4) {
+    GST_INFO ("Saw 5 buffers to the encoder. Switching caps");
+    gst_util_set_object_arg (G_OBJECT (data->cf), "caps",
+        "video/x-raw,width=160,height=128,framerate=10/1");
+  }
+  data->count++;
+  return GST_PAD_PROBE_OK;
+}
+
+GST_START_TEST (test_splitmuxsrc_caps_change)
+{
+  GstMessage *msg;
+  GstElement *pipeline;
+  GstElement *sink;
+  GstElement *cf;
+  GstPad *sinkpad;
+  gchar *dest_pattern;
+  guint count;
+  gchar *in_pattern;
+  struct CapsChangeData data;
+
+  /* This test creates a new file only by changing the caps, which
+   * qtmux will reject (for now - if qtmux starts supporting caps
+   * changes, this test will break and need fixing/disabling */
+  pipeline =
+      gst_parse_launch
+      ("videotestsrc num-buffers=10 !"
+      "  capsfilter name=c caps=video/x-raw,width=80,height=64,framerate=10/1 !"
+      "  jpegenc ! splitmuxsink name=splitsink muxer=qtmux", NULL);
+  fail_if (pipeline == NULL);
+  sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink");
+  fail_if (sink == NULL);
+  g_signal_connect (sink, "format-location-full",
+      (GCallback) check_format_location, NULL);
+  dest_pattern = g_build_filename (tmpdir, "out%05d.mp4", NULL);
+  g_object_set (G_OBJECT (sink), "location", dest_pattern, NULL);
+  g_free (dest_pattern);
+  g_object_unref (sink);
+
+  cf = gst_bin_get_by_name (GST_BIN (pipeline), "c");
+  sinkpad = gst_element_get_static_pad (cf, "sink");
+
+  data.cf = cf;
+  data.count = 0;
+
+  gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BUFFER,
+      switch_caps, &data, NULL);
+
+  gst_object_unref (sinkpad);
+  gst_object_unref (cf);
+
+  msg = run_pipeline (pipeline);
+
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR)
+    dump_error (msg);
+  fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
+  gst_message_unref (msg);
+
+  gst_object_unref (pipeline);
+
+  count = count_files (tmpdir);
+  fail_unless (count == 2, "Expected 2 output files, got %d", count);
+
+  in_pattern = g_build_filename (tmpdir, "out*.mp4", NULL);
+  test_playback (in_pattern, 0, GST_SECOND);
+  g_free (in_pattern);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_splitmuxsrc_robust_mux)
+{
+  GstMessage *msg;
+  GstElement *pipeline;
+  GstElement *sink;
+  gchar *dest_pattern;
+  gchar *in_pattern;
+
+  /* This test creates a new file only by changing the caps, which
+   * qtmux will reject (for now - if qtmux starts supporting caps
+   * changes, this test will break and need fixing/disabling */
+  pipeline =
+      gst_parse_launch
+      ("videotestsrc num-buffers=10 !"
+      "  video/x-raw,width=80,height=64,framerate=10/1 !"
+      "  jpegenc ! splitmuxsink name=splitsink muxer=\"qtmux reserved-bytes-per-sec=200 reserved-moov-update-period=100000000 \" max-size-time=500000000 use-robust-muxing=true",
+      NULL);
+  fail_if (pipeline == NULL);
+  sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink");
+  fail_if (sink == NULL);
+  g_signal_connect (sink, "format-location-full",
+      (GCallback) check_format_location, NULL);
+  dest_pattern = g_build_filename (tmpdir, "out%05d.mp4", NULL);
+  g_object_set (G_OBJECT (sink), "location", dest_pattern, NULL);
+  g_free (dest_pattern);
+  g_object_unref (sink);
+
+  msg = run_pipeline (pipeline);
+
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR)
+    dump_error (msg);
+  fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
+  gst_message_unref (msg);
+
+  gst_object_unref (pipeline);
+
+  /* Unlike other tests, we don't check an explicit file size, because the overflow detection
+   * can be racy (depends on exactly when buffers get handed to the muxer and when it updates the
+   * reserved duration property. All we care about is that the muxing didn't fail because space ran out */
+
+  in_pattern = g_build_filename (tmpdir, "out*.mp4", NULL);
+  test_playback (in_pattern, 0, GST_SECOND);
+  g_free (in_pattern);
+}
+
+GST_END_TEST;
+
+/* For verifying bug https://bugzilla.gnome.org/show_bug.cgi?id=762893 */
+GST_START_TEST (test_splitmuxsink_reuse_simple)
+{
+  GstElement *sink;
+  GstPad *pad;
+
+  sink = gst_element_factory_make ("splitmuxsink", NULL);
+  pad = gst_element_get_request_pad (sink, "video");
+  fail_unless (pad != NULL);
+  g_object_set (sink, "location", "/dev/null", NULL);
+
+  fail_unless (gst_element_set_state (sink,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_ASYNC);
+  fail_unless (gst_element_set_state (sink,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
+  fail_unless (gst_element_set_state (sink,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_ASYNC);
+  fail_unless (gst_element_set_state (sink,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
+
+  gst_element_release_request_pad (sink, pad);
+  gst_object_unref (pad);
+  gst_object_unref (sink);
+}
+
+GST_END_TEST;
+
+static Suite *
+splitmux_suite (void)
+{
+  Suite *s = suite_create ("splitmux");
+  TCase *tc_chain = tcase_create ("general");
+  TCase *tc_chain_basic = tcase_create ("basic");
+  TCase *tc_chain_complex = tcase_create ("complex");
+  TCase *tc_chain_mp4_jpeg = tcase_create ("caps_change");
+  gboolean have_theora, have_ogg, have_vorbis, have_matroska, have_qtmux,
+      have_jpeg;
+
+  /* we assume that if encoder/muxer are there, decoder/demuxer will be a well */
+  have_theora = gst_registry_check_feature_version (gst_registry_get (),
+      "theoraenc", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0);
+  have_ogg = gst_registry_check_feature_version (gst_registry_get (),
+      "oggmux", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0);
+  have_vorbis = gst_registry_check_feature_version (gst_registry_get (),
+      "vorbisenc", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0);
+  have_matroska = gst_registry_check_feature_version (gst_registry_get (),
+      "matroskamux", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0);
+  have_qtmux = gst_registry_check_feature_version (gst_registry_get (),
+      "qtmux", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0);
+  have_jpeg = gst_registry_check_feature_version (gst_registry_get (),
+      "jpegenc", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0);
+
+  suite_add_tcase (s, tc_chain);
+  suite_add_tcase (s, tc_chain_basic);
+  suite_add_tcase (s, tc_chain_complex);
+  suite_add_tcase (s, tc_chain_mp4_jpeg);
+
+  tcase_add_test (tc_chain_basic, test_splitmuxsink_reuse_simple);
+
+  if (have_theora && have_ogg) {
+    tcase_add_checked_fixture (tc_chain, tempdir_setup, tempdir_cleanup);
+
+    tcase_add_test (tc_chain, test_splitmuxsrc);
+    tcase_add_test (tc_chain, test_splitmuxsrc_format_location);
+    tcase_add_test (tc_chain, test_splitmuxsink);
+
+    if (have_matroska && have_vorbis) {
+      tcase_add_checked_fixture (tc_chain_complex, tempdir_setup,
+          tempdir_cleanup);
+
+      tcase_add_test (tc_chain_complex, test_splitmuxsrc_sparse_streams);
+    } else {
+      GST_INFO ("Skipping tests, missing plugins: matroska and/or vorbis");
+    }
+  } else {
+    GST_INFO ("Skipping tests, missing plugins: theora and/or ogg");
+  }
+
+
+  if (have_qtmux && have_jpeg) {
+    tcase_add_checked_fixture (tc_chain_mp4_jpeg, tempdir_setup,
+        tempdir_cleanup);
+    tcase_add_test (tc_chain_mp4_jpeg, test_splitmuxsrc_caps_change);
+    tcase_add_test (tc_chain_mp4_jpeg, test_splitmuxsrc_robust_mux);
+  } else {
+    GST_INFO ("Skipping tests, missing plugins: jpegenc or mp4mux");
+  }
+  return s;
+}
+
+GST_CHECK_MAIN (splitmux);
diff --git a/tests/check/elements/udpsink.c b/tests/check/elements/udpsink.c
new file mode 100644
index 0000000..ca8b722
--- /dev/null
+++ b/tests/check/elements/udpsink.c
@@ -0,0 +1,258 @@
+/* GStreamer udpsink unit tests
+ * Copyright (C) 2009 Axis Communications <dev-gstreamer@axis.com>
+ * @author Ognyan Tonchev <ognyan@axis.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <gst/check/gstcheck.h>
+#include <gst/base/gstbasesink.h>
+#include <gio/gio.h>
+#include <stdlib.h>
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+#define RTP_HEADER_SIZE 12
+#define RTP_PAYLOAD_SIZE 1024
+
+/*
+ * Number of bytes received in the render function when using buffer lists
+ */
+static guint render_list_bytes_received;
+
+/*
+ * Render function for testing udpsink with buffer lists
+ */
+static GstFlowReturn
+udpsink_render_list (GstBaseSink * sink, GstBufferList * list)
+{
+  guint i, num;
+
+  num = gst_buffer_list_length (list);
+  for (i = 0; i < num; ++i) {
+    GstBuffer *buf = gst_buffer_list_get (list, i);
+    gsize size = gst_buffer_get_size (buf);
+
+    GST_DEBUG ("rendered %" G_GSIZE_FORMAT " bytes", size);
+    render_list_bytes_received += size;
+  }
+
+  return GST_FLOW_OK;
+}
+
+static void
+set_render_list_function (GstElement * bsink)
+{
+  GstBaseSinkClass *bsclass;
+
+  bsclass = GST_BASE_SINK_GET_CLASS ((GstBaseSink *) bsink);
+
+  /* Add callback function for the buffer list tests */
+  bsclass->render_list = udpsink_render_list;
+}
+
+static GstBufferList *
+create_buffer_list (guint * data_size)
+{
+  GstBufferList *list;
+  GstBuffer *rtp_buffer;
+  GstBuffer *data_buffer;
+
+  list = gst_buffer_list_new ();
+
+  /*** First group, i.e. first packet. **/
+
+  /* Create the RTP header buffer */
+  rtp_buffer = gst_buffer_new_allocate (NULL, RTP_HEADER_SIZE, NULL);
+  gst_buffer_memset (rtp_buffer, 0, 0, RTP_HEADER_SIZE);
+
+  /* Create the buffer that holds the payload */
+  data_buffer = gst_buffer_new_allocate (NULL, RTP_PAYLOAD_SIZE, NULL);
+  gst_buffer_memset (data_buffer, 0, 0, RTP_PAYLOAD_SIZE);
+
+  /* Create a new group to hold the rtp header and the payload */
+  gst_buffer_list_add (list, gst_buffer_append (rtp_buffer, data_buffer));
+
+  /***  Second group, i.e. second packet. ***/
+
+  /* Create the RTP header buffer */
+  rtp_buffer = gst_buffer_new_allocate (NULL, RTP_HEADER_SIZE, NULL);
+  gst_buffer_memset (rtp_buffer, 0, 0, RTP_HEADER_SIZE);
+
+  /* Create the buffer that holds the payload */
+  data_buffer = gst_buffer_new_allocate (NULL, RTP_PAYLOAD_SIZE, NULL);
+  gst_buffer_memset (data_buffer, 0, 0, RTP_PAYLOAD_SIZE);
+
+  /* Create a new group to hold the rtp header and the payload */
+  gst_buffer_list_add (list, gst_buffer_append (rtp_buffer, data_buffer));
+
+  /* Calculate the size of the data */
+  *data_size = 2 * RTP_HEADER_SIZE + 2 * RTP_PAYLOAD_SIZE;
+
+  return list;
+}
+
+static void
+udpsink_test (gboolean use_buffer_lists)
+{
+  GstSegment segment;
+  GstElement *udpsink;
+  GstPad *srcpad;
+  GstBufferList *list;
+  guint data_size;
+
+  list = create_buffer_list (&data_size);
+
+  udpsink = gst_check_setup_element ("udpsink");
+  if (use_buffer_lists)
+    set_render_list_function (udpsink);
+
+  srcpad = gst_check_setup_src_pad_by_name (udpsink, &srctemplate, "sink");
+
+  gst_element_set_state (udpsink, GST_STATE_PLAYING);
+  gst_pad_set_active (srcpad, TRUE);
+
+  gst_pad_push_event (srcpad, gst_event_new_stream_start ("hey there!"));
+
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  gst_pad_push_event (srcpad, gst_event_new_segment (&segment));
+
+  fail_unless_equals_int (gst_pad_push_list (srcpad, list), GST_FLOW_OK);
+
+  gst_check_teardown_pad_by_name (udpsink, "sink");
+  gst_check_teardown_element (udpsink);
+
+  if (use_buffer_lists)
+    fail_unless_equals_int (data_size, render_list_bytes_received);
+}
+
+GST_START_TEST (test_udpsink)
+{
+  udpsink_test (FALSE);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_udpsink_bufferlist)
+{
+  udpsink_test (TRUE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_udpsink_client_add_remove)
+{
+  GstElement *udpsink;
+
+  /* Note: keep in mind that these are in addition to the client added by
+   * the host/port properties (by default 'localhost:5004' */
+
+  udpsink = gst_check_setup_element ("udpsink");
+  g_signal_emit_by_name (udpsink, "remove", "localhost", 5004, NULL);
+  gst_object_unref (udpsink);
+
+  udpsink = gst_check_setup_element ("udpsink");
+  g_signal_emit_by_name (udpsink, "add", "127.0.0.1", 5554, NULL);
+  gst_object_unref (udpsink);
+
+  udpsink = gst_check_setup_element ("udpsink");
+  g_signal_emit_by_name (udpsink, "add", "127.0.0.1", 5554, NULL);
+  g_signal_emit_by_name (udpsink, "add", "127.0.0.1", 5554, NULL);
+  gst_object_unref (udpsink);
+
+  udpsink = gst_check_setup_element ("udpsink");
+  g_signal_emit_by_name (udpsink, "add", "127.0.0.1", 5554, NULL);
+  g_signal_emit_by_name (udpsink, "remove", "127.0.0.1", 5554, NULL);
+  gst_object_unref (udpsink);
+
+  udpsink = gst_check_setup_element ("udpsink");
+  g_signal_emit_by_name (udpsink, "add", "127.0.0.1", 5554, NULL);
+  g_signal_emit_by_name (udpsink, "remove", "127.0.0.1", 5555, NULL);
+  gst_object_unref (udpsink);
+
+  udpsink = gst_check_setup_element ("udpsink");
+  g_signal_emit_by_name (udpsink, "add", "127.0.0.1", 5554, NULL);
+  g_signal_emit_by_name (udpsink, "add", "127.0.0.1", 5555, NULL);
+  gst_object_unref (udpsink);
+
+  udpsink = gst_check_setup_element ("udpsink");
+  g_signal_emit_by_name (udpsink, "add", "127.0.0.1", 5554, NULL);
+  g_signal_emit_by_name (udpsink, "add", "10.2.0.1", 5554, NULL);
+  gst_object_unref (udpsink);
+
+  udpsink = gst_check_setup_element ("udpsink");
+  g_signal_emit_by_name (udpsink, "add", "127.0.0.1", 5554, NULL);
+  g_signal_emit_by_name (udpsink, "add", "10.2.0.1", 5554, NULL);
+  g_signal_emit_by_name (udpsink, "remove", "127.0.0.1", 5554, NULL);
+  gst_object_unref (udpsink);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_udpsink_dscp)
+{
+  GstElement *udpsink;
+  GError *error = NULL;
+  GSocket *sock4, *sock6;
+
+  sock4 =
+      g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM,
+      G_SOCKET_PROTOCOL_UDP, &error);
+  fail_unless (sock4 != NULL && error == NULL);
+  sock6 =
+      g_socket_new (G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_DATAGRAM,
+      G_SOCKET_PROTOCOL_UDP, &error);
+  fail_unless (sock6 != NULL && error == NULL);
+
+  udpsink = gst_check_setup_element ("udpsink");
+  g_signal_emit_by_name (udpsink, "add", "127.0.0.1", 5554, NULL);
+  g_object_set (udpsink, "socket", sock4, NULL);
+  g_object_set (udpsink, "socket-v6", sock6, NULL);
+
+  ASSERT_SET_STATE (udpsink, GST_STATE_READY, GST_STATE_CHANGE_SUCCESS);
+
+  g_object_set (udpsink, "qos-dscp", 0, NULL);
+  g_object_set (udpsink, "qos-dscp", 63, NULL);
+
+  ASSERT_SET_STATE (udpsink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
+
+  gst_object_unref (udpsink);
+  g_object_unref (sock4);
+  g_object_unref (sock6);
+}
+
+GST_END_TEST;
+
+static Suite *
+udpsink_suite (void)
+{
+  Suite *s = suite_create ("udpsink_test");
+  TCase *tc_chain = tcase_create ("linear");
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_udpsink);
+  tcase_add_test (tc_chain, test_udpsink_bufferlist);
+  tcase_add_test (tc_chain, test_udpsink_client_add_remove);
+  tcase_add_test (tc_chain, test_udpsink_dscp);
+
+  return s;
+}
+
+GST_CHECK_MAIN (udpsink)
diff --git a/tests/check/elements/udpsrc.c b/tests/check/elements/udpsrc.c
new file mode 100644
index 0000000..699e824
--- /dev/null
+++ b/tests/check/elements/udpsrc.c
@@ -0,0 +1,263 @@
+/* GStreamer UDP source unit tests
+ * Copyright (C) 2011 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <gst/check/gstcheck.h>
+#include <gio/gio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+static gboolean
+udpsrc_setup (GstElement ** udpsrc, GSocket ** socket,
+    GstPad ** sinkpad, GSocketAddress ** sa)
+{
+  GInetAddress *ia;
+  int port = 0;
+  gchar *s;
+
+  *udpsrc = gst_check_setup_element ("udpsrc");
+  fail_unless (*udpsrc != NULL);
+  g_object_set (*udpsrc, "port", 0, NULL);
+
+  *sinkpad = gst_check_setup_sink_pad_by_name (*udpsrc, &sinktemplate, "src");
+  fail_unless (*sinkpad != NULL);
+  gst_pad_set_active (*sinkpad, TRUE);
+
+  gst_element_set_state (*udpsrc, GST_STATE_PLAYING);
+  g_object_get (*udpsrc, "port", &port, NULL);
+  GST_INFO ("udpsrc port = %d", port);
+
+  *socket = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM,
+      G_SOCKET_PROTOCOL_UDP, NULL);
+
+  if (*socket == NULL) {
+    GST_WARNING ("Could not create IPv4 UDP socket for unit test");
+    return FALSE;
+  }
+
+  ia = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
+  s = g_inet_address_to_string (ia);
+  GST_LOG ("inet address %s", s);
+  g_free (s);
+  *sa = g_inet_socket_address_new (ia, port);
+  g_object_unref (ia);
+
+  return TRUE;
+}
+
+GST_START_TEST (test_udpsrc_empty_packet)
+{
+  GSocketAddress *sa = NULL;
+  GstElement *udpsrc = NULL;
+  GSocket *socket = NULL;
+  GstPad *sinkpad = NULL;
+
+  if (!udpsrc_setup (&udpsrc, &socket, &sinkpad, &sa))
+    goto no_socket;
+
+  if (g_socket_send_to (socket, sa, "HeLL0", 0, NULL, NULL) == 0) {
+    GST_INFO ("sent 0 bytes");
+    if (g_socket_send_to (socket, sa, "HeLL0", 6, NULL, NULL) == 6) {
+      GstMapInfo map;
+      GstBuffer *buf;
+      guint len = 0;
+
+      GST_INFO ("sent 6 bytes");
+
+      g_mutex_lock (&check_mutex);
+      len = g_list_length (buffers);
+      while (len < 1) {
+        g_cond_wait (&check_cond, &check_mutex);
+        len = g_list_length (buffers);
+        GST_INFO ("%u buffers", len);
+      }
+
+      /* wait a bit more for a second buffer */
+      if (len < 2) {
+        g_cond_wait_until (&check_cond, &check_mutex,
+            g_get_monotonic_time () + G_TIME_SPAN_SECOND / 100);
+
+        len = g_list_length (buffers);
+        GST_INFO ("%u buffers", len);
+      }
+
+      fail_unless (len == 1 || len == 2);
+
+      /* last buffer should be our HeLL0 string */
+      buf = GST_BUFFER (g_list_nth_data (buffers, len - 1));
+      gst_buffer_map (buf, &map, GST_MAP_READ);
+      fail_unless_equals_int (map.size, 6);
+      fail_unless_equals_string ((gchar *) map.data, "HeLL0");
+      gst_buffer_unmap (buf, &map);
+
+      /* if there's another buffer, it should be 0 bytes */
+      if (len == 2) {
+        buf = GST_BUFFER (g_list_nth_data (buffers, 0));
+        fail_unless_equals_int (gst_buffer_get_size (buf), 0);
+      }
+      g_mutex_unlock (&check_mutex);
+    } else {
+      GST_WARNING ("send_to(6 bytes) failed");
+    }
+  } else {
+    GST_WARNING ("send_to(0 bytes) failed");
+  }
+
+no_socket:
+
+  gst_element_set_state (udpsrc, GST_STATE_NULL);
+
+  gst_check_drop_buffers ();
+  gst_check_teardown_pad_by_name (udpsrc, "src");
+  gst_check_teardown_element (udpsrc);
+
+  g_object_unref (socket);
+  g_object_unref (sa);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_udpsrc)
+{
+  GSocketAddress *sa = NULL;
+  GstElement *udpsrc = NULL;
+  GSocket *socket = NULL;
+  GstPad *sinkpad = NULL;
+  GstBuffer *buf;
+  GstMemory *mem;
+  gchar data[48000];
+  gsize max_size;
+  int i, len = 0;
+  gssize sent;
+  GError *err = NULL;
+
+  for (i = 0; i < G_N_ELEMENTS (data); ++i)
+    data[i] = i & 0xff;
+
+  if (!udpsrc_setup (&udpsrc, &socket, &sinkpad, &sa))
+    goto no_socket;
+
+  if ((sent = g_socket_send_to (socket, sa, data, 48000, NULL, &err)) == -1)
+    goto send_failure;
+  fail_unless_equals_int (sent, 48000);
+
+  if ((sent = g_socket_send_to (socket, sa, data, 21000, NULL, &err)) == -1)
+    goto send_failure;
+  fail_unless_equals_int (sent, 21000);
+
+  if ((sent = g_socket_send_to (socket, sa, data, 500, NULL, &err)) == -1)
+    goto send_failure;
+  fail_unless_equals_int (sent, 500);
+
+  if ((sent = g_socket_send_to (socket, sa, data, 1600, NULL, &err)) == -1)
+    goto send_failure;
+  fail_unless_equals_int (sent, 1600);
+
+  if ((sent = g_socket_send_to (socket, sa, data, 1400, NULL, &err)) == -1)
+    goto send_failure;
+  fail_unless_equals_int (sent, 1400);
+
+  GST_INFO ("sent some packets");
+
+  g_mutex_lock (&check_mutex);
+  len = g_list_length (buffers);
+  while (len < 5) {
+    g_cond_wait (&check_cond, &check_mutex);
+    len = g_list_length (buffers);
+    GST_INFO ("%u buffers", len);
+  }
+
+  /* check that large packets are made up of multiple memory chunks and that
+   * the first one is fairly small */
+  buf = GST_BUFFER (g_list_nth_data (buffers, 0));
+  fail_unless_equals_int (gst_buffer_get_size (buf), 48000);
+  fail_unless_equals_int (gst_buffer_n_memory (buf), 2);
+  mem = gst_buffer_peek_memory (buf, 0);
+  gst_memory_get_sizes (mem, NULL, &max_size);
+  fail_unless (max_size <= 2000);
+
+  buf = GST_BUFFER (g_list_nth_data (buffers, 1));
+  fail_unless_equals_int (gst_buffer_get_size (buf), 21000);
+  fail_unless_equals_int (gst_buffer_n_memory (buf), 2);
+  mem = gst_buffer_peek_memory (buf, 0);
+  gst_memory_get_sizes (mem, NULL, &max_size);
+  fail_unless (max_size <= 2000);
+
+  buf = GST_BUFFER (g_list_nth_data (buffers, 2));
+  fail_unless_equals_int (gst_buffer_get_size (buf), 500);
+  fail_unless_equals_int (gst_buffer_n_memory (buf), 1);
+  mem = gst_buffer_peek_memory (buf, 0);
+  gst_memory_get_sizes (mem, NULL, &max_size);
+  fail_unless (max_size <= 2000);
+
+  buf = GST_BUFFER (g_list_nth_data (buffers, 3));
+  fail_unless_equals_int (gst_buffer_get_size (buf), 1600);
+  fail_unless_equals_int (gst_buffer_n_memory (buf), 2);
+  mem = gst_buffer_peek_memory (buf, 0);
+  gst_memory_get_sizes (mem, NULL, &max_size);
+  fail_unless (max_size <= 2000);
+
+  buf = GST_BUFFER (g_list_nth_data (buffers, 4));
+  fail_unless_equals_int (gst_buffer_get_size (buf), 1400);
+  fail_unless_equals_int (gst_buffer_n_memory (buf), 1);
+  mem = gst_buffer_peek_memory (buf, 0);
+  gst_memory_get_sizes (mem, NULL, &max_size);
+  fail_unless (max_size <= 2000);
+
+  g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
+  g_list_free (buffers);
+  buffers = NULL;
+
+  g_mutex_unlock (&check_mutex);
+
+no_socket:
+send_failure:
+  if (err) {
+    GST_WARNING ("Socket send error, skipping test: %s", err->message);
+    g_clear_error (&err);
+  }
+
+  gst_element_set_state (udpsrc, GST_STATE_NULL);
+
+  gst_check_drop_buffers ();
+  gst_check_teardown_pad_by_name (udpsrc, "src");
+  gst_check_teardown_element (udpsrc);
+
+  g_object_unref (socket);
+  g_object_unref (sa);
+}
+
+GST_END_TEST;
+
+static Suite *
+udpsrc_suite (void)
+{
+  Suite *s = suite_create ("udpsrc");
+  TCase *tc_chain = tcase_create ("udpsrc");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_udpsrc_empty_packet);
+  tcase_add_test (tc_chain, test_udpsrc);
+  return s;
+}
+
+GST_CHECK_MAIN (udpsrc)
diff --git a/tests/check/elements/videobox.c b/tests/check/elements/videobox.c
new file mode 100644
index 0000000..2d26535
--- /dev/null
+++ b/tests/check/elements/videobox.c
@@ -0,0 +1,224 @@
+/* GStreamer
+ * unit test for the videobox element
+ *
+ * Copyright (C) 2006 Ravi Kiran K N <ravi.kiran@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+
+typedef struct _GstVideoBoxTestContext
+{
+  GstElement *pipeline;
+  GstElement *src;
+  GstElement *filter;
+  GstElement *box;
+  GstElement *filter2;
+  GstElement *sink;
+} GstVideoBoxTestContext;
+
+typedef struct _FormatConversion
+{
+  const gchar *in_caps;
+  const gchar *out_caps;
+  gboolean expected_result;
+} FormatConversion;
+
+
+/*
+ * Update this table as and when the conversion is supported(or unsupported) in videobox
+ */
+static const FormatConversion conversion_table[] = {
+  {"video/x-raw,format={RGBA}", "video/x-raw,format={AYUV}", TRUE},
+  {"video/x-raw,format={AYUV}", "video/x-raw,format={RGBA}", TRUE},
+  {"video/x-raw,format={I420}", "video/x-raw,format={AYUV}", TRUE},
+  {"video/x-raw,format={AYUV}", "video/x-raw,format={I420}", TRUE},
+  {"video/x-raw,format={I420}", "video/x-raw,format={YV12}", TRUE},
+  {"video/x-raw,format={YV12}", "video/x-raw,format={AYUV}", TRUE},
+  {"video/x-raw,format={YV12}", "video/x-raw,format={I420}", TRUE},
+  {"video/x-raw,format={AYUV}", "video/x-raw,format={YV12}", TRUE},
+  {"video/x-raw,format={AYUV}", "video/x-raw,format={xRGB}", TRUE},
+  {"video/x-raw,format={xRGB}", "video/x-raw,format={xRGB}", TRUE},
+  {"video/x-raw,format={xRGB}", "video/x-raw,format={AYUV}", TRUE},
+  {"video/x-raw,format={GRAY8}", "video/x-raw,format={GRAY16_LE}", FALSE},
+  {"video/x-raw,format={GRAY8}", "video/x-raw,format={GRAY16_BE}", FALSE},
+  {"video/x-raw,format={Y444}", "video/x-raw,format={Y42B}", FALSE},
+  {"video/x-raw,format={Y444}", "video/x-raw,format={Y41B}", FALSE},
+  {"video/x-raw,format={Y42B}", "video/x-raw,format={Y41B}", FALSE}
+};
+
+
+static gboolean
+bus_handler (GstBus * bus, GstMessage * message, gpointer data)
+{
+  GMainLoop *loop = (GMainLoop *) data;
+
+  switch (message->type) {
+    case GST_MESSAGE_EOS:{
+      GST_LOG ("EOS event received");
+      g_main_loop_quit (loop);
+      break;
+    }
+    case GST_MESSAGE_ERROR:{
+      GError *gerror;
+      gchar *debug;
+      gst_message_parse_error (message, &gerror, &debug);
+      g_error ("Error from %s: %s (%s)\n",
+          GST_ELEMENT_NAME (GST_MESSAGE_SRC (message)), gerror->message,
+          GST_STR_NULL (debug));
+      g_error_free (gerror);
+      g_free (debug);
+      g_main_loop_quit (loop);
+      break;
+    }
+    case GST_MESSAGE_WARNING:{
+      g_main_loop_quit (loop);
+      break;
+    }
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+static void
+videobox_test_init_context (GstVideoBoxTestContext * ctx)
+{
+  fail_unless (ctx != NULL);
+
+  ctx->pipeline = gst_pipeline_new ("pipeline");
+  fail_unless (ctx->pipeline != NULL);
+  ctx->src = gst_element_factory_make ("videotestsrc", "src");
+  fail_unless (ctx->src != NULL, "Failed to create videotestsrc element");
+  ctx->filter = gst_element_factory_make ("capsfilter", "filter");
+  fail_unless (ctx->filter != NULL, "Failed to create capsfilter element");
+  ctx->box = gst_element_factory_make ("videobox", "box");
+  fail_unless (ctx->box != NULL, "Failed to create videobox element");
+  ctx->filter2 = gst_element_factory_make ("capsfilter", "filter2");
+  fail_unless (ctx->filter2 != NULL,
+      "Failed to create second capsfilter element");
+  ctx->sink = gst_element_factory_make ("fakesink", "sink");
+  fail_unless (ctx->sink != NULL, "Failed to create fakesink element");
+
+  gst_bin_add_many (GST_BIN (ctx->pipeline), ctx->src, ctx->filter,
+      ctx->box, ctx->filter2, ctx->sink, NULL);
+  fail_unless (gst_element_link_many (ctx->src, ctx->filter, ctx->box,
+          ctx->filter2, ctx->sink, NULL) == TRUE, "Can not link elements");
+
+  fail_unless (gst_element_set_state (ctx->pipeline,
+          GST_STATE_READY) != GST_STATE_CHANGE_FAILURE,
+      "couldn't set pipeline to READY state");
+
+  GST_LOG ("videobox context inited");
+}
+
+static void
+videobox_test_deinit_context (GstVideoBoxTestContext * ctx)
+{
+  GST_LOG ("deiniting videobox context");
+
+  gst_element_set_state (ctx->pipeline, GST_STATE_NULL);
+  gst_object_unref (ctx->pipeline);
+  memset (ctx, 0x00, sizeof (GstVideoBoxTestContext));
+}
+
+GST_START_TEST (test_caps_transform)
+{
+  GstStateChangeReturn state_ret;
+  GstVideoBoxTestContext ctx;
+  guint conversions_test_size;
+  guint itr;
+  gboolean link_res;
+  GMainLoop *loop;
+  GstBus *bus;
+
+  videobox_test_init_context (&ctx);
+  gst_util_set_object_arg (G_OBJECT (ctx.src), "num-buffers", "1");
+
+  loop = g_main_loop_new (NULL, TRUE);
+  fail_unless (loop != NULL);
+
+  bus = gst_element_get_bus (ctx.pipeline);
+  fail_unless (bus != NULL);
+
+  gst_bus_add_watch (bus, bus_handler, loop);
+
+  conversions_test_size = G_N_ELEMENTS (conversion_table);
+  for (itr = 0; itr < conversions_test_size; itr++) {
+    gst_element_unlink_many (ctx.src, ctx.filter, ctx.box, ctx.filter2,
+        ctx.sink, NULL);
+    gst_util_set_object_arg (G_OBJECT (ctx.filter), "caps",
+        conversion_table[itr].in_caps);
+    gst_util_set_object_arg (G_OBJECT (ctx.filter2), "caps",
+        conversion_table[itr].out_caps);
+
+    /* Link with new input and output format from conversion table */
+    link_res =
+        gst_element_link_many (ctx.src, ctx.filter, ctx.box, ctx.filter2,
+        ctx.sink, NULL);
+
+    /* Check if the specified format conversion is supported or not by videobox */
+    fail_unless (link_res == conversion_table[itr].expected_result,
+        "videobox can not convert from '%s'' to '%s'",
+        conversion_table[itr].in_caps, conversion_table[itr].out_caps);
+
+    if (link_res == FALSE) {
+      GST_LOG ("elements linking failed");
+      continue;
+    }
+
+    state_ret = gst_element_set_state (ctx.pipeline, GST_STATE_PLAYING);
+    fail_unless (state_ret != GST_STATE_CHANGE_FAILURE,
+        "couldn't set pipeline to PLAYING state");
+
+    g_main_loop_run (loop);
+
+    state_ret = gst_element_set_state (ctx.pipeline, GST_STATE_READY);
+    fail_unless (state_ret != GST_STATE_CHANGE_FAILURE,
+        "couldn't set pipeline to READY state");
+  }
+
+  gst_bus_remove_watch (bus);
+  gst_object_unref (bus);
+  g_main_loop_unref (loop);
+
+  videobox_test_deinit_context (&ctx);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+videobox_suite (void)
+{
+  Suite *s = suite_create ("videobox");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_caps_transform);
+
+  return s;
+}
+
+GST_CHECK_MAIN (videobox);
diff --git a/tests/check/elements/videocrop.c b/tests/check/elements/videocrop.c
new file mode 100644
index 0000000..6e76e5a
--- /dev/null
+++ b/tests/check/elements/videocrop.c
@@ -0,0 +1,819 @@
+/* GStreamer unit test for the videocrop element
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_VALGRIND
+# include <valgrind/valgrind.h>
+#endif
+
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+#include <gst/video/video.h>
+#include <gst/base/gstbasetransform.h>
+
+/* return a list of caps where we only need to set
+ * width and height to get fixed caps */
+static GList *
+video_crop_get_test_caps (GstElement * videocrop)
+{
+  GstCaps *templ, *allowed_caps;
+  GstPad *srcpad;
+  GList *list = NULL;
+  guint i;
+
+  srcpad = gst_element_get_static_pad (videocrop, "src");
+  fail_unless (srcpad != NULL);
+  templ = gst_pad_get_pad_template_caps (srcpad);
+  fail_unless (templ != NULL);
+
+  allowed_caps = gst_caps_normalize (templ);
+
+  for (i = 0; i < gst_caps_get_size (allowed_caps); ++i) {
+    GstStructure *new_structure;
+    GstCaps *single_caps;
+
+    single_caps = gst_caps_new_empty ();
+    new_structure =
+        gst_structure_copy (gst_caps_get_structure (allowed_caps, i));
+    gst_structure_set (new_structure, "framerate", GST_TYPE_FRACTION,
+        1, 1, NULL);
+    gst_structure_remove_field (new_structure, "width");
+    gst_structure_remove_field (new_structure, "height");
+    gst_caps_append_structure (single_caps, new_structure);
+
+    GST_DEBUG ("have caps %" GST_PTR_FORMAT, single_caps);
+    /* should be fixed without width/height */
+    fail_unless (gst_caps_is_fixed (single_caps));
+
+    list = g_list_prepend (list, single_caps);
+  }
+
+  gst_caps_unref (allowed_caps);
+  gst_object_unref (srcpad);
+
+  return list;
+}
+
+GST_START_TEST (test_unit_sizes)
+{
+  GstBaseTransformClass *csp_klass, *vcrop_klass;
+  GstElement *videocrop, *csp;
+  GList *caps_list, *l;
+
+  videocrop = gst_element_factory_make ("videocrop", "videocrop");
+  fail_unless (videocrop != NULL, "Failed to create videocrop element");
+  vcrop_klass = GST_BASE_TRANSFORM_GET_CLASS (videocrop);
+
+  csp = gst_element_factory_make ("videoconvert", "csp");
+  fail_unless (csp != NULL, "Failed to create videoconvert element");
+  csp_klass = GST_BASE_TRANSFORM_GET_CLASS (csp);
+
+  caps_list = video_crop_get_test_caps (videocrop);
+
+  for (l = caps_list; l != NULL; l = l->next) {
+    const struct
+    {
+      gint width, height;
+    } sizes_to_try[] = {
+      {
+      160, 120}, {
+      161, 120}, {
+      160, 121}, {
+      161, 121}, {
+      159, 120}, {
+      160, 119}, {
+      159, 119}, {
+      159, 121}
+    };
+    GstStructure *s;
+    GstCaps *caps;
+    gint i;
+
+    caps = gst_caps_copy (GST_CAPS (l->data));
+    s = gst_caps_get_structure (caps, 0);
+    fail_unless (s != NULL);
+
+    for (i = 0; i < G_N_ELEMENTS (sizes_to_try); ++i) {
+      gchar *caps_str;
+      gsize csp_size = 0;
+      gsize vc_size = 0;
+
+      gst_structure_set (s, "width", G_TYPE_INT, sizes_to_try[i].width,
+          "height", G_TYPE_INT, sizes_to_try[i].height, NULL);
+
+      caps_str = gst_caps_to_string (caps);
+      GST_INFO ("Testing unit size for %s", caps_str);
+
+      /* skip if videoconvert doesn't support these caps
+       * (only works with gst-plugins-base 0.10.9.1 or later) */
+      if (!csp_klass->get_unit_size ((GstBaseTransform *) csp, caps, &csp_size)) {
+        GST_INFO ("videoconvert does not support format %s", caps_str);
+        g_free (caps_str);
+        continue;
+      }
+
+      fail_unless (vcrop_klass->get_unit_size ((GstBaseTransform *) videocrop,
+              caps, &vc_size));
+
+      fail_unless (vc_size == csp_size,
+          "videocrop and videoconvert return different unit sizes for "
+          "caps %s: vc_size=%d, csp_size=%d", caps_str, vc_size, csp_size);
+
+      g_free (caps_str);
+    }
+
+    gst_caps_unref (caps);
+  }
+
+  g_list_foreach (caps_list, (GFunc) gst_caps_unref, NULL);
+  g_list_free (caps_list);
+
+  gst_object_unref (csp);
+  gst_object_unref (videocrop);
+}
+
+GST_END_TEST;
+
+typedef struct
+{
+  GstElement *pipeline;
+  GstElement *src;
+  GstElement *filter;
+  GstElement *crop;
+  GstElement *filter2;
+  GstElement *sink;
+  GstBuffer *last_buf;
+  GstCaps *last_caps;
+} GstVideoCropTestContext;
+
+static void
+handoff_cb (GstElement * sink, GstBuffer * buf, GstPad * pad,
+    GstVideoCropTestContext * ctx)
+{
+  GstCaps *caps;
+
+  gst_buffer_replace (&ctx->last_buf, buf);
+  caps = gst_pad_get_current_caps (pad);
+  gst_caps_replace (&ctx->last_caps, caps);
+  gst_caps_unref (caps);
+}
+
+static void
+videocrop_test_cropping_init_context (GstVideoCropTestContext * ctx)
+{
+  fail_unless (ctx != NULL);
+
+  ctx->pipeline = gst_pipeline_new ("pipeline");
+  fail_unless (ctx->pipeline != NULL);
+  ctx->src = gst_element_factory_make ("videotestsrc", "src");
+  fail_unless (ctx->src != NULL, "Failed to create videotestsrc element");
+  ctx->filter = gst_element_factory_make ("capsfilter", "filter");
+  fail_unless (ctx->filter != NULL, "Failed to create capsfilter element");
+  ctx->crop = gst_element_factory_make ("videocrop", "crop");
+  fail_unless (ctx->crop != NULL, "Failed to create videocrop element");
+  ctx->filter2 = gst_element_factory_make ("capsfilter", "filter2");
+  fail_unless (ctx->filter2 != NULL,
+      "Failed to create second capsfilter element");
+  ctx->sink = gst_element_factory_make ("fakesink", "sink");
+  fail_unless (ctx->sink != NULL, "Failed to create fakesink element");
+
+  gst_bin_add_many (GST_BIN (ctx->pipeline), ctx->src, ctx->filter,
+      ctx->crop, ctx->filter2, ctx->sink, NULL);
+  gst_element_link_many (ctx->src, ctx->filter, ctx->crop, ctx->filter2,
+      ctx->sink, NULL);
+
+  /* set pattern to 'red' - for our purposes it doesn't matter anyway */
+  g_object_set (ctx->src, "pattern", 4, NULL);
+
+  g_object_set (ctx->sink, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (ctx->sink, "preroll-handoff", G_CALLBACK (handoff_cb), ctx);
+
+  ctx->last_buf = NULL;
+  ctx->last_caps = NULL;
+
+  GST_LOG ("context inited");
+}
+
+static void
+videocrop_test_cropping_deinit_context (GstVideoCropTestContext * ctx)
+{
+  GST_LOG ("deiniting context");
+
+  gst_element_set_state (ctx->pipeline, GST_STATE_NULL);
+  gst_object_unref (ctx->pipeline);
+  gst_buffer_replace (&ctx->last_buf, NULL);
+  gst_caps_replace (&ctx->last_caps, NULL);
+  memset (ctx, 0x00, sizeof (GstVideoCropTestContext));
+}
+
+typedef void (*GstVideoCropTestBufferFunc) (GstBuffer * buffer, GstCaps * caps);
+
+static void
+videocrop_test_cropping (GstVideoCropTestContext * ctx, GstCaps * in_caps,
+    GstCaps * out_caps, gint left, gint right, gint top, gint bottom,
+    GstVideoCropTestBufferFunc func)
+{
+  GST_LOG ("lrtb = %03u %03u %03u %03u, in_caps = %" GST_PTR_FORMAT
+      ", out_caps = %" GST_PTR_FORMAT, left, right, top, bottom, in_caps,
+      out_caps);
+
+  g_object_set (ctx->filter, "caps", in_caps, NULL);
+  g_object_set (ctx->filter2, "caps", out_caps, NULL);
+
+  g_object_set (ctx->crop, "left", left, "right", right, "top", top,
+      "bottom", bottom, NULL);
+
+  /* this will fail if videotestsrc doesn't support our format; we need
+   * videotestsrc from -base CVS 0.10.9.1 with RGBA and AYUV support */
+  fail_unless (gst_element_set_state (ctx->pipeline,
+          GST_STATE_PAUSED) != GST_STATE_CHANGE_FAILURE);
+  fail_unless (gst_element_get_state (ctx->pipeline, NULL, NULL,
+          -1) == GST_STATE_CHANGE_SUCCESS);
+
+  if (func != NULL) {
+    func (ctx->last_buf, ctx->last_caps);
+  }
+
+  gst_element_set_state (ctx->pipeline, GST_STATE_NULL);
+}
+
+static void
+check_1x1_buffer (GstBuffer * buf, GstCaps * caps)
+{
+  GstVideoInfo info;
+  GstVideoFrame frame;
+  /* the exact values we check for come from videotestsrc */
+  static const guint yuv_values[] = { 81, 90, 240, 255 };
+  static const guint rgb_values[] = { 0xff, 0, 0, 255 };
+  static const guint gray8_values[] = { 0x51 };
+  static const guint gray16_values[] = { 0x5151 };
+  const guint *values;
+  guint i;
+  const GstVideoFormatInfo *finfo;
+
+  fail_unless (buf != NULL);
+  fail_unless (caps != NULL);
+
+  fail_unless (gst_video_info_from_caps (&info, caps));
+  fail_unless (gst_video_frame_map (&frame, &info, buf, GST_MAP_READ));
+
+  finfo = info.finfo;
+
+  if (GST_VIDEO_INFO_IS_YUV (&info))
+    values = yuv_values;
+  else if (GST_VIDEO_INFO_IS_GRAY (&info))
+    if (GST_VIDEO_FORMAT_INFO_BITS (finfo) == 8)
+      values = gray8_values;
+    else
+      values = gray16_values;
+  else
+    values = rgb_values;
+
+  GST_MEMDUMP ("buffer", GST_VIDEO_FRAME_PLANE_DATA (&frame, 0), 8);
+
+  for (i = 0; i < GST_VIDEO_FRAME_N_COMPONENTS (&frame); i++) {
+    guint8 *data = GST_VIDEO_FRAME_COMP_DATA (&frame, i);
+
+    GST_DEBUG ("W: %d", GST_VIDEO_FORMAT_INFO_W_SUB (finfo, i));
+    GST_DEBUG ("H: %d", GST_VIDEO_FORMAT_INFO_H_SUB (finfo, i));
+
+    if (GST_VIDEO_FORMAT_INFO_W_SUB (finfo,
+            i) >= GST_VIDEO_FRAME_WIDTH (&frame))
+      continue;
+    if (GST_VIDEO_FORMAT_INFO_H_SUB (finfo,
+            i) >= GST_VIDEO_FRAME_HEIGHT (&frame))
+      continue;
+
+    if (GST_VIDEO_FORMAT_INFO_BITS (finfo) == 8) {
+      fail_unless_equals_int (data[0], values[i]);
+    } else if (GST_VIDEO_FORMAT_INFO_BITS (finfo) == 16) {
+      guint16 pixels, val;
+      gint depth;
+
+      if (GST_VIDEO_FORMAT_INFO_IS_LE (finfo))
+        pixels = GST_READ_UINT16_LE (data);
+      else
+        pixels = GST_READ_UINT16_BE (data);
+
+      depth = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, i);
+      val = pixels >> GST_VIDEO_FORMAT_INFO_SHIFT (finfo, i);
+      val = val & ((1 << depth) - 1);
+
+      GST_DEBUG ("val %08x %d : %d", pixels, i, val);
+      if (depth <= 8) {
+        fail_unless_equals_int (val, values[i] >> (8 - depth));
+      } else {
+        fail_unless_equals_int (val, values[i] >> (16 - depth));
+      }
+    } else {
+    }
+  }
+
+  gst_video_frame_unmap (&frame);
+
+  /*
+     fail_unless_equals_int ((pixel & rmask) >> rshift, 0xff);
+     fail_unless_equals_int ((pixel & gmask) >> gshift, 0x00);
+     fail_unless_equals_int ((pixel & bmask) >> bshift, 0x00);
+   */
+}
+
+GST_START_TEST (test_crop_to_1x1)
+{
+  GstVideoCropTestContext ctx;
+  GList *caps_list, *node;
+
+  videocrop_test_cropping_init_context (&ctx);
+
+  caps_list = video_crop_get_test_caps (ctx.crop);
+
+  for (node = caps_list; node != NULL; node = node->next) {
+    GstStructure *s;
+    GstCaps *caps;
+
+    caps = gst_caps_copy (GST_CAPS (node->data));
+    s = gst_caps_get_structure (caps, 0);
+    fail_unless (s != NULL);
+
+    GST_INFO ("testing format: %" GST_PTR_FORMAT, caps);
+
+    gst_structure_set (s, "width", G_TYPE_INT, 160,
+        "height", G_TYPE_INT, 160, NULL);
+
+    videocrop_test_cropping (&ctx, caps, NULL, 159, 0, 159, 0,
+        check_1x1_buffer);
+    /* commented out because they don't really add anything useful check-wise:
+       videocrop_test_cropping (&ctx, caps, NULL, 0, 159, 0, 159, check_1x1_buffer);
+       videocrop_test_cropping (&ctx, caps, NULL, 159, 0, 0, 159, check_1x1_buffer);
+       videocrop_test_cropping (&ctx, caps, NULL, 0, 159, 159, 0, check_1x1_buffer);
+     */
+    gst_caps_unref (caps);
+  }
+  g_list_foreach (caps_list, (GFunc) gst_caps_unref, NULL);
+  g_list_free (caps_list);
+
+  videocrop_test_cropping_deinit_context (&ctx);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_cropping)
+{
+  GstVideoCropTestContext ctx;
+  struct
+  {
+    gint width, height;
+  } sizes_to_try[] = {
+    {
+    160, 160}, {
+    161, 160}, {
+    160, 161}, {
+    161, 161}, {
+    159, 160}, {
+    160, 159}, {
+    159, 159}, {
+    159, 161}
+  };
+  GList *caps_list, *node;
+  gint i;
+
+  videocrop_test_cropping_init_context (&ctx);
+
+  caps_list = video_crop_get_test_caps (ctx.crop);
+  node = g_list_nth (caps_list, __i__);
+
+  if (node != NULL) {
+    GstStructure *s;
+    GstCaps *caps;
+
+    caps = gst_caps_copy (GST_CAPS (node->data));
+    s = gst_caps_get_structure (caps, 0);
+    fail_unless (s != NULL);
+
+    GST_INFO ("testing format: %" GST_PTR_FORMAT, caps);
+
+    for (i = 0; i < G_N_ELEMENTS (sizes_to_try); ++i) {
+      GstCaps *in_caps, *out_caps;
+
+      GST_INFO (" - %d x %d", sizes_to_try[i].width, sizes_to_try[i].height);
+
+      gst_structure_set (s, "width", G_TYPE_INT, sizes_to_try[i].width,
+          "height", G_TYPE_INT, sizes_to_try[i].height, NULL);
+      in_caps = gst_caps_copy (caps);
+
+      gst_structure_set (s, "width", G_TYPE_INT, 1, "height", G_TYPE_INT, 1,
+          NULL);
+      out_caps = gst_caps_copy (caps);
+
+      videocrop_test_cropping (&ctx, in_caps, NULL, 0, 0, 0, 0, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 1, 0, 0, 0, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 0, 1, 0, 0, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 0, 0, 1, 0, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 0, 0, 0, 1, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 63, 0, 0, 0, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 0, 63, 0, 0, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 0, 0, 63, 0, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 0, 0, 0, 63, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 63, 0, 0, 1, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 0, 63, 1, 0, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 0, 1, 63, 0, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 1, 0, 0, 63, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 0, 0, 0, 0, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 32, 0, 0, 128, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 0, 32, 128, 0, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 0, 128, 32, 0, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 128, 0, 0, 32, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 1, 1, 1, 1, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 63, 63, 63, 63, NULL);
+      videocrop_test_cropping (&ctx, in_caps, NULL, 64, 64, 64, 64, NULL);
+
+      /* Dynamic cropping */
+      videocrop_test_cropping (&ctx, in_caps, out_caps, -1, -1, -1, -1, NULL);
+      videocrop_test_cropping (&ctx, in_caps, out_caps, 0, -1, -1, -1, NULL);
+      videocrop_test_cropping (&ctx, in_caps, out_caps, -1, 0, -1, -1, NULL);
+      videocrop_test_cropping (&ctx, in_caps, out_caps, -1, -1, 0, -1, NULL);
+      videocrop_test_cropping (&ctx, in_caps, out_caps, -1, -1, -1, 0, NULL);
+      videocrop_test_cropping (&ctx, in_caps, out_caps, 10, -1, 10, -1, NULL);
+      videocrop_test_cropping (&ctx, in_caps, out_caps, -1, 10, -1, 10, NULL);
+      videocrop_test_cropping (&ctx, in_caps, out_caps,
+          sizes_to_try[i].width - 1, -1, -1, -1, NULL);
+      videocrop_test_cropping (&ctx, in_caps, out_caps, -1,
+          sizes_to_try[i].width - 1, -1, -1, NULL);
+      videocrop_test_cropping (&ctx, in_caps, out_caps, -1, -1,
+          sizes_to_try[i].height - 1, -1, NULL);
+      videocrop_test_cropping (&ctx, in_caps, out_caps, -1, -1, -1,
+          sizes_to_try[i].height - 1, NULL);
+
+      gst_caps_unref (in_caps);
+      gst_caps_unref (out_caps);
+    }
+
+    gst_caps_unref (caps);
+  } else {
+    GST_INFO ("no caps #%d", __i__);
+  }
+  g_list_foreach (caps_list, (GFunc) gst_caps_unref, NULL);
+  g_list_free (caps_list);
+
+  videocrop_test_cropping_deinit_context (&ctx);
+}
+
+GST_END_TEST;
+
+
+static GstPadProbeReturn
+buffer_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer data)
+{
+  GstBuffer **p_buf = data;
+  GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER (info);
+
+  gst_buffer_replace (p_buf, buf);
+
+  return GST_PAD_PROBE_OK;      /* keep data */
+}
+
+GST_START_TEST (test_passthrough)
+{
+  GstStateChangeReturn state_ret;
+  GstVideoCropTestContext ctx;
+  GstPad *srcpad;
+  GstBuffer *gen_buf = NULL;    /* buffer generated by videotestsrc */
+
+  videocrop_test_cropping_init_context (&ctx);
+
+  g_object_set (ctx.src, "num-buffers", 1, NULL);
+
+  srcpad = gst_element_get_static_pad (ctx.src, "src");
+  fail_unless (srcpad != NULL);
+  gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_BUFFER, buffer_probe_cb,
+      &gen_buf, NULL);
+  gst_object_unref (srcpad);
+
+  g_object_set (ctx.crop, "left", 0, "right", 0, "top", 0, "bottom", 0, NULL);
+
+  state_ret = gst_element_set_state (ctx.pipeline, GST_STATE_PAUSED);
+  fail_unless (state_ret != GST_STATE_CHANGE_FAILURE,
+      "couldn't set pipeline to PAUSED state");
+
+  state_ret = gst_element_get_state (ctx.pipeline, NULL, NULL, -1);
+  fail_unless (state_ret == GST_STATE_CHANGE_SUCCESS,
+      "pipeline failed to go to PAUSED state");
+
+  fail_unless (gen_buf != NULL);
+  fail_unless (ctx.last_buf != NULL);
+
+  /* pass through should do nothing */
+  fail_unless (gen_buf == ctx.last_buf);
+
+  videocrop_test_cropping_deinit_context (&ctx);
+
+  fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (gen_buf), 1);
+  gst_buffer_unref (gen_buf);
+}
+
+GST_END_TEST;
+
+static gint
+notgst_value_list_get_nth_int (const GValue * list_val, guint n)
+{
+  const GValue *v;
+
+  fail_unless (GST_VALUE_HOLDS_LIST (list_val));
+  fail_unless (n < gst_value_list_get_size (list_val));
+
+  v = gst_value_list_get_value (list_val, n);
+  fail_unless (G_VALUE_HOLDS_INT (v));
+  return g_value_get_int (v);
+}
+
+GST_START_TEST (test_caps_transform)
+{
+  GstVideoCropTestContext ctx;
+  GstBaseTransformClass *klass;
+  GstBaseTransform *crop;
+  const GValue *w_val;
+  const GValue *h_val;
+  GstCaps *caps, *adj_caps;
+
+  videocrop_test_cropping_init_context (&ctx);
+
+  crop = GST_BASE_TRANSFORM (ctx.crop);
+  klass = GST_BASE_TRANSFORM_GET_CLASS (ctx.crop);
+  fail_unless (klass != NULL);
+
+  caps = gst_caps_new_simple ("video/x-raw",
+      "format", G_TYPE_STRING, "I420",
+      "framerate", GST_TYPE_FRACTION, 1, 1,
+      "width", G_TYPE_INT, 200, "height", G_TYPE_INT, 100, NULL);
+
+  /* by default, it should be no cropping and hence passthrough */
+  adj_caps = klass->transform_caps (crop, GST_PAD_SRC, caps, NULL);
+  fail_unless (adj_caps != NULL);
+  fail_unless (gst_caps_is_equal (adj_caps, caps));
+  gst_caps_unref (adj_caps);
+
+  adj_caps = klass->transform_caps (crop, GST_PAD_SINK, caps, NULL);
+  fail_unless (adj_caps != NULL);
+  fail_unless (gst_caps_is_equal (adj_caps, caps));
+  gst_caps_unref (adj_caps);
+
+  /* make sure that's still true after changing properties back and forth */
+  g_object_set (ctx.crop, "left", 1, "right", 3, "top", 5, "bottom", 7, NULL);
+  g_object_set (ctx.crop, "left", 0, "right", 0, "top", 0, "bottom", 0, NULL);
+
+  adj_caps = klass->transform_caps (crop, GST_PAD_SRC, caps, NULL);
+  fail_unless (adj_caps != NULL);
+  fail_unless (gst_caps_is_equal (adj_caps, caps));
+  gst_caps_unref (adj_caps);
+
+  adj_caps = klass->transform_caps (crop, GST_PAD_SINK, caps, NULL);
+  fail_unless (adj_caps != NULL);
+  fail_unless (gst_caps_is_equal (adj_caps, caps));
+  gst_caps_unref (adj_caps);
+
+  /* now check adjustments made ... */
+  g_object_set (ctx.crop, "left", 1, "right", 3, "top", 5, "bottom", 7, NULL);
+
+  /* ========= (1) fixed value ============================================= */
+
+  /* sink => source, source must be bigger if we crop stuff off */
+  adj_caps = klass->transform_caps (crop, GST_PAD_SRC, caps, NULL);
+  fail_unless (adj_caps != NULL);
+  fail_unless (gst_caps_get_size (adj_caps) == 1);
+  w_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "width");
+  fail_unless (w_val != NULL);
+  fail_unless (G_VALUE_HOLDS_INT (w_val));
+  fail_unless_equals_int (g_value_get_int (w_val), 200 + (1 + 3));
+  h_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "height");
+  fail_unless (h_val != NULL);
+  fail_unless (G_VALUE_HOLDS_INT (h_val));
+  fail_unless_equals_int (g_value_get_int (h_val), 100 + (5 + 7));
+  gst_caps_unref (adj_caps);
+
+  /* source => sink becomes smaller */
+  adj_caps = klass->transform_caps (crop, GST_PAD_SINK, caps, NULL);
+  fail_unless (adj_caps != NULL);
+  fail_unless (gst_caps_get_size (adj_caps) == 1);
+  w_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "width");
+  fail_unless (w_val != NULL);
+  fail_unless (G_VALUE_HOLDS_INT (w_val));
+  fail_unless_equals_int (g_value_get_int (w_val), 200 - (1 + 3));
+  h_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "height");
+  fail_unless (h_val != NULL);
+  fail_unless (G_VALUE_HOLDS_INT (h_val));
+  fail_unless_equals_int (g_value_get_int (h_val), 100 - (5 + 7));
+  gst_caps_unref (adj_caps);
+
+  /* ========= (2) range (simple adjustment) =============================== */
+
+  gst_structure_set (gst_caps_get_structure (caps, 0),
+      "width", GST_TYPE_INT_RANGE, 1000, 2000,
+      "height", GST_TYPE_INT_RANGE, 3000, 4000, NULL);
+
+  /* sink => source, source must be bigger if we crop stuff off */
+  adj_caps = klass->transform_caps (crop, GST_PAD_SRC, caps, NULL);
+  fail_unless (adj_caps != NULL);
+  fail_unless (gst_caps_get_size (adj_caps) == 1);
+  w_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "width");
+  fail_unless (w_val != NULL);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (w_val));
+  fail_unless_equals_int (gst_value_get_int_range_min (w_val), 1000 + (1 + 3));
+  fail_unless_equals_int (gst_value_get_int_range_max (w_val), 2000 + (1 + 3));
+  h_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "height");
+  fail_unless (h_val != NULL);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (h_val));
+  fail_unless_equals_int (gst_value_get_int_range_min (h_val), 3000 + (5 + 7));
+  fail_unless_equals_int (gst_value_get_int_range_max (h_val), 4000 + (5 + 7));
+  gst_caps_unref (adj_caps);
+
+  /* source => sink becomes smaller */
+  adj_caps = klass->transform_caps (crop, GST_PAD_SINK, caps, NULL);
+  fail_unless (adj_caps != NULL);
+  fail_unless (gst_caps_get_size (adj_caps) == 1);
+  w_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "width");
+  fail_unless (w_val != NULL);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (w_val));
+  fail_unless_equals_int (gst_value_get_int_range_min (w_val), 1000 - (1 + 3));
+  fail_unless_equals_int (gst_value_get_int_range_max (w_val), 2000 - (1 + 3));
+  h_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "height");
+  fail_unless (h_val != NULL);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (h_val));
+  fail_unless_equals_int (gst_value_get_int_range_min (h_val), 3000 - (5 + 7));
+  fail_unless_equals_int (gst_value_get_int_range_max (h_val), 4000 - (5 + 7));
+  gst_caps_unref (adj_caps);
+
+  /* ========= (3) range (adjustment at boundary) ========================== */
+
+  gst_structure_set (gst_caps_get_structure (caps, 0),
+      "width", GST_TYPE_INT_RANGE, 2, G_MAXINT,
+      "height", GST_TYPE_INT_RANGE, 2, G_MAXINT, NULL);
+
+  /* sink => source, source must be bigger if we crop stuff off */
+  adj_caps = klass->transform_caps (crop, GST_PAD_SRC, caps, NULL);
+  fail_unless (adj_caps != NULL);
+  fail_unless (gst_caps_get_size (adj_caps) == 1);
+  w_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "width");
+  fail_unless (w_val != NULL);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (w_val));
+  fail_unless_equals_int (gst_value_get_int_range_min (w_val), 2 + (1 + 3));
+  fail_unless_equals_int (gst_value_get_int_range_max (w_val), G_MAXINT);
+  h_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "height");
+  fail_unless (h_val != NULL);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (h_val));
+  fail_unless_equals_int (gst_value_get_int_range_min (h_val), 2 + (5 + 7));
+  fail_unless_equals_int (gst_value_get_int_range_max (h_val), G_MAXINT);
+  gst_caps_unref (adj_caps);
+
+  /* source => sink becomes smaller */
+  adj_caps = klass->transform_caps (crop, GST_PAD_SINK, caps, NULL);
+  fail_unless (adj_caps != NULL);
+  fail_unless (gst_caps_get_size (adj_caps) == 1);
+  w_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "width");
+  fail_unless (w_val != NULL);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (w_val));
+  fail_unless_equals_int (gst_value_get_int_range_min (w_val), 1);
+  fail_unless_equals_int (gst_value_get_int_range_max (w_val),
+      G_MAXINT - (1 + 3));
+  h_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "height");
+  fail_unless (h_val != NULL);
+  fail_unless (GST_VALUE_HOLDS_INT_RANGE (h_val));
+  fail_unless_equals_int (gst_value_get_int_range_min (h_val), 1);
+  fail_unless_equals_int (gst_value_get_int_range_max (h_val),
+      G_MAXINT - (5 + 7));
+  gst_caps_unref (adj_caps);
+
+  /* ========= (4) list of values ========================================== */
+
+  {
+    GValue list = { 0, };
+    GValue ival = { 0, };
+
+    g_value_init (&ival, G_TYPE_INT);
+    g_value_init (&list, GST_TYPE_LIST);
+    g_value_set_int (&ival, 2);
+    gst_value_list_append_value (&list, &ival);
+    g_value_set_int (&ival, G_MAXINT);
+    gst_value_list_append_value (&list, &ival);
+    gst_structure_set_value (gst_caps_get_structure (caps, 0), "width", &list);
+    g_value_unset (&list);
+    g_value_unset (&ival);
+
+    g_value_init (&ival, G_TYPE_INT);
+    g_value_init (&list, GST_TYPE_LIST);
+    g_value_set_int (&ival, 5);
+    gst_value_list_append_value (&list, &ival);
+    g_value_set_int (&ival, 1000);
+    gst_value_list_append_value (&list, &ival);
+    gst_structure_set_value (gst_caps_get_structure (caps, 0), "height", &list);
+    g_value_unset (&list);
+    g_value_unset (&ival);
+  }
+
+  /* sink => source, source must be bigger if we crop stuff off */
+  adj_caps = klass->transform_caps (crop, GST_PAD_SRC, caps, NULL);
+  fail_unless (adj_caps != NULL);
+  fail_unless (gst_caps_get_size (adj_caps) == 1);
+  w_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "width");
+  fail_unless (w_val != NULL);
+  fail_unless (GST_VALUE_HOLDS_LIST (w_val));
+  fail_unless_equals_int (notgst_value_list_get_nth_int (w_val, 0),
+      2 + (1 + 3));
+  fail_unless_equals_int (notgst_value_list_get_nth_int (w_val, 1), G_MAXINT);
+  h_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "height");
+  fail_unless (h_val != NULL);
+  fail_unless (GST_VALUE_HOLDS_LIST (h_val));
+  fail_unless_equals_int (notgst_value_list_get_nth_int (h_val, 0),
+      5 + (5 + 7));
+  fail_unless_equals_int (notgst_value_list_get_nth_int (h_val, 1),
+      1000 + (5 + 7));
+  gst_caps_unref (adj_caps);
+
+  /* source => sink becomes smaller */
+  adj_caps = klass->transform_caps (crop, GST_PAD_SINK, caps, NULL);
+  fail_unless (adj_caps != NULL);
+  fail_unless (gst_caps_get_size (adj_caps) == 1);
+  w_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "width");
+  fail_unless (w_val != NULL);
+  fail_unless (GST_VALUE_HOLDS_LIST (w_val));
+  fail_unless_equals_int (notgst_value_list_get_nth_int (w_val, 0), 1);
+  fail_unless_equals_int (notgst_value_list_get_nth_int (w_val, 1),
+      G_MAXINT - (1 + 3));
+  h_val =
+      gst_structure_get_value (gst_caps_get_structure (adj_caps, 0), "height");
+  fail_unless (h_val != NULL);
+  fail_unless (GST_VALUE_HOLDS_LIST (h_val));
+  fail_unless_equals_int (notgst_value_list_get_nth_int (h_val, 0), 1);
+  fail_unless_equals_int (notgst_value_list_get_nth_int (h_val, 1),
+      1000 - (5 + 7));
+  gst_caps_unref (adj_caps);
+
+  gst_caps_unref (caps);
+  videocrop_test_cropping_deinit_context (&ctx);
+}
+
+GST_END_TEST;
+
+static Suite *
+videocrop_suite (void)
+{
+  Suite *s = suite_create ("videocrop");
+  TCase *tc_chain = tcase_create ("general");
+
+#ifdef HAVE_VALGRIND
+  if (RUNNING_ON_VALGRIND) {
+    /* our tests take quite a long time, so increase
+     * timeout (~25 minutes on my 1.6GHz AMD K7) */
+    tcase_set_timeout (tc_chain, 30 * 60);
+  } else
+#endif
+  {
+    /* increase timeout, these tests take a long time (60 secs here) */
+    tcase_set_timeout (tc_chain, 2 * 60);
+  }
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_crop_to_1x1);
+  tcase_add_test (tc_chain, test_caps_transform);
+  tcase_add_test (tc_chain, test_passthrough);
+  tcase_add_test (tc_chain, test_unit_sizes);
+  tcase_add_loop_test (tc_chain, test_cropping, 0, 25);
+
+  return s;
+}
+
+GST_CHECK_MAIN (videocrop);
diff --git a/tests/check/elements/videofilter.c b/tests/check/elements/videofilter.c
new file mode 100644
index 0000000..7cc02f7
--- /dev/null
+++ b/tests/check/elements/videofilter.c
@@ -0,0 +1,266 @@
+/* GStreamer
+ *
+ * unit test for videofilter elements
+ *
+ * Copyright (C) <2006> Mark Nauwelaerts <manauw@skynet.be>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+#include <stdarg.h>
+
+#include <gst/video/video.h>
+#include <gst/check/gstcheck.h>
+
+gboolean have_eos = FALSE;
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *mysrcpad, *mysinkpad;
+
+#define VIDEO_CAPS_TEMPLATE_STRING \
+  GST_VIDEO_CAPS_MAKE ("{ I420, AYUV, YUY2, UYVY, YVYU, xRGB }")
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (VIDEO_CAPS_TEMPLATE_STRING)
+    );
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (VIDEO_CAPS_TEMPLATE_STRING)
+    );
+
+/* takes over reference for outcaps */
+static GstElement *
+setup_filter (const gchar * name, const gchar * prop, va_list var_args)
+{
+  GstElement *element;
+
+  GST_DEBUG ("setup_element");
+  element = gst_check_setup_element (name);
+  g_object_set_valist (G_OBJECT (element), prop, var_args);
+  mysrcpad = gst_check_setup_src_pad (element, &srctemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  mysinkpad = gst_check_setup_sink_pad (element, &sinktemplate);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return element;
+}
+
+static void
+cleanup_filter (GstElement * filter)
+{
+  GST_DEBUG ("cleanup_element");
+
+  gst_check_teardown_src_pad (filter);
+  gst_check_teardown_sink_pad (filter);
+  gst_check_teardown_element (filter);
+}
+
+static void
+check_filter_caps (const gchar * name, GstEvent * event, GstCaps * caps,
+    gint size, gint num_buffers, const gchar * prop, va_list varargs)
+{
+  GstElement *filter;
+  GstBuffer *inbuffer, *outbuffer;
+  gint i;
+  GstSegment segment;
+
+  filter = setup_filter (name, prop, varargs);
+  fail_unless (gst_element_set_state (filter,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  gst_check_setup_events (mysrcpad, filter, caps, GST_FORMAT_TIME);
+
+  /* ensure segment (format) properly setup */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  if (event)
+    fail_unless (gst_pad_push_event (mysrcpad, event));
+
+  for (i = 0; i < num_buffers; ++i) {
+    inbuffer = gst_buffer_new_and_alloc (size);
+    /* makes valgrind's memcheck happier */
+    gst_buffer_memset (inbuffer, 0, 0, size);
+    GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+    ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+    fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  }
+
+  fail_unless (g_list_length (buffers) == num_buffers);
+
+  /* clean up buffers */
+  for (i = 0; i < num_buffers; ++i) {
+    outbuffer = GST_BUFFER (buffers->data);
+    fail_if (outbuffer == NULL);
+
+    switch (i) {
+      case 0:
+        fail_unless (gst_buffer_get_size (outbuffer) == size);
+        /* no check on filter operation itself */
+        break;
+      default:
+        break;
+    }
+    buffers = g_list_remove (buffers, outbuffer);
+
+    ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
+    gst_buffer_unref (outbuffer);
+    outbuffer = NULL;
+  }
+
+  cleanup_filter (filter);
+  g_list_free (buffers);
+  buffers = NULL;
+}
+
+static void
+check_filter_varargs (const gchar * name, GstEvent * event, gint num_buffers,
+    const gchar * prop, va_list varargs)
+{
+  static const struct
+  {
+    const int width, height;
+  } resolutions[] = { {
+  384, 288}, {
+  385, 289}, {
+  385, 385}};
+  gint i, n, r;
+  gint size;
+  GstCaps *allcaps, *templ = gst_caps_from_string (VIDEO_CAPS_TEMPLATE_STRING);
+
+  allcaps = gst_caps_normalize (templ);
+
+  n = gst_caps_get_size (allcaps);
+
+  for (i = 0; i < n; i++) {
+    GstStructure *s = gst_caps_get_structure (allcaps, i);
+    GstCaps *caps = gst_caps_new_empty ();
+
+    gst_caps_append_structure (caps, gst_structure_copy (s));
+
+    /* try various resolutions */
+    for (r = 0; r < G_N_ELEMENTS (resolutions); ++r) {
+      GstVideoInfo info;
+      va_list args_cp;
+
+      caps = gst_caps_make_writable (caps);
+      gst_caps_set_simple (caps, "width", G_TYPE_INT, resolutions[r].width,
+          "height", G_TYPE_INT, resolutions[r].height,
+          "framerate", GST_TYPE_FRACTION, 25, 1, NULL);
+
+      GST_DEBUG ("Testing with caps: %" GST_PTR_FORMAT, caps);
+      gst_video_info_from_caps (&info, caps);
+      size = GST_VIDEO_INFO_SIZE (&info);
+
+      if (event)
+        gst_event_ref (event);
+
+      va_copy (args_cp, varargs);
+      check_filter_caps (name, event, caps, size, num_buffers, prop, args_cp);
+      va_end (args_cp);
+    }
+
+    gst_caps_unref (caps);
+  }
+
+  gst_caps_unref (allcaps);
+  if (event)
+    gst_event_unref (event);
+}
+
+static void
+check_filter (const gchar * name, gint num_buffers, const gchar * prop, ...)
+{
+  va_list varargs;
+  va_start (varargs, prop);
+  check_filter_varargs (name, NULL, num_buffers, prop, varargs);
+  va_end (varargs);
+}
+
+static void
+check_filter_with_event (const gchar * name, GstEvent * event,
+    gint num_buffers, const gchar * prop, ...)
+{
+  va_list varargs;
+  va_start (varargs, prop);
+  check_filter_varargs (name, event, num_buffers, prop, varargs);
+  va_end (varargs);
+}
+
+GST_START_TEST (test_videobalance)
+{
+  check_filter ("videobalance", 2, NULL);
+  check_filter ("videobalance", 2, "saturation", 0.5, "hue", 0.8, NULL);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_videoflip)
+{
+  GstEvent *event;
+
+  /* these we can handle with the caps */
+  check_filter ("videoflip", 2, "method", 0, NULL);
+  check_filter ("videoflip", 2, "method", 2, NULL);
+  check_filter ("videoflip", 2, "method", 4, NULL);
+  check_filter ("videoflip", 2, "method", 5, NULL);
+
+  event = gst_event_new_tag (gst_tag_list_new_empty ());
+  check_filter_with_event ("videoflip", event, 2, "method", 8, NULL);
+
+  event = gst_event_new_tag (gst_tag_list_new (GST_TAG_IMAGE_ORIENTATION,
+          "rotate-180", NULL));
+  check_filter_with_event ("videoflip", event, 2, "method", 8, NULL);
+
+  event = gst_event_new_tag (gst_tag_list_new (GST_TAG_IMAGE_ORIENTATION,
+          "invalid", NULL));
+  check_filter_with_event ("videoflip", event, 2, "method", 8, NULL);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_gamma)
+{
+  check_filter ("gamma", 2, NULL);
+  check_filter ("gamma", 2, "gamma", 2.0, NULL);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+videofilter_suite (void)
+{
+  Suite *s = suite_create ("videofilter");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_videobalance);
+  tcase_add_test (tc_chain, test_videoflip);
+  tcase_add_test (tc_chain, test_gamma);
+
+  return s;
+}
+
+GST_CHECK_MAIN (videofilter);
diff --git a/tests/check/elements/videomixer.c b/tests/check/elements/videomixer.c
new file mode 100644
index 0000000..ff8d1fa
--- /dev/null
+++ b/tests/check/elements/videomixer.c
@@ -0,0 +1,1071 @@
+/* GStreamer
+ *
+ * unit test for videmixer
+ *
+ * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
+ * Copyright (C) <2013> Thibault Saunier <thibault.saunier@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_VALGRIND
+# include <valgrind/valgrind.h>
+#endif
+
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+#include <gst/check/gstconsistencychecker.h>
+#include <gst/base/gstbasesrc.h>
+
+#define VIDEO_CAPS_STRING               \
+    "video/x-raw, "                 \
+    "width = (int) 320, "               \
+    "height = (int) 240, "              \
+    "framerate = (fraction) 25/1 , "    \
+    "format = (string) I420"
+
+static GMainLoop *main_loop;
+
+/* make sure downstream gets a CAPS event before buffers are sent */
+GST_START_TEST (test_caps)
+{
+  GstElement *pipeline, *src, *videomixer, *sink;
+  GstStateChangeReturn state_res;
+  GstCaps *caps;
+  GstPad *pad;
+
+  /* build pipeline */
+  pipeline = gst_pipeline_new ("pipeline");
+
+  src = gst_element_factory_make ("videotestsrc", "src1");
+  videomixer = gst_element_factory_make ("videomixer", "videomixer");
+  sink = gst_element_factory_make ("fakesink", "sink");
+  gst_bin_add_many (GST_BIN (pipeline), src, videomixer, sink, NULL);
+
+  fail_unless (gst_element_link_many (src, videomixer, sink, NULL));
+
+  /* prepare playing */
+  state_res = gst_element_set_state (pipeline, GST_STATE_PAUSED);
+  fail_unless_equals_int (state_res, GST_STATE_CHANGE_ASYNC);
+
+  /* wait for preroll */
+  state_res = gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
+  fail_unless_equals_int (state_res, GST_STATE_CHANGE_SUCCESS);
+
+  /* check caps on fakesink */
+  pad = gst_element_get_static_pad (sink, "sink");
+  caps = gst_pad_get_current_caps (pad);
+  fail_unless (caps != NULL);
+  gst_caps_unref (caps);
+  gst_object_unref (pad);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
+static void
+message_received (GstBus * bus, GstMessage * message, GstPipeline * bin)
+{
+  GST_INFO ("bus message from \"%" GST_PTR_FORMAT "\": %" GST_PTR_FORMAT,
+      GST_MESSAGE_SRC (message), message);
+
+  switch (message->type) {
+    case GST_MESSAGE_EOS:
+      g_main_loop_quit (main_loop);
+      break;
+    case GST_MESSAGE_WARNING:{
+      GError *gerror;
+      gchar *debug;
+
+      gst_message_parse_warning (message, &gerror, &debug);
+      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+      g_error_free (gerror);
+      g_free (debug);
+      break;
+    }
+    case GST_MESSAGE_ERROR:{
+      GError *gerror;
+      gchar *debug;
+
+      gst_message_parse_error (message, &gerror, &debug);
+      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+      g_error_free (gerror);
+      g_free (debug);
+      g_main_loop_quit (main_loop);
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+
+static GstFormat format = GST_FORMAT_UNDEFINED;
+static gint64 position = -1;
+
+static void
+test_event_message_received (GstBus * bus, GstMessage * message,
+    GstPipeline * bin)
+{
+  GST_INFO ("bus message from \"%" GST_PTR_FORMAT "\": %" GST_PTR_FORMAT,
+      GST_MESSAGE_SRC (message), message);
+
+  switch (message->type) {
+    case GST_MESSAGE_SEGMENT_DONE:
+      gst_message_parse_segment_done (message, &format, &position);
+      GST_INFO ("received segment_done : %" G_GINT64_FORMAT, position);
+      g_main_loop_quit (main_loop);
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+
+GST_START_TEST (test_event)
+{
+  GstElement *bin, *src1, *src2, *videomixer, *sink;
+  GstBus *bus;
+  GstEvent *seek_event;
+  GstStateChangeReturn state_res;
+  gboolean res;
+  GstPad *srcpad, *sinkpad;
+  GstStreamConsistency *chk_1, *chk_2, *chk_3;
+
+  GST_INFO ("preparing test");
+
+  /* build pipeline */
+  bin = gst_pipeline_new ("pipeline");
+  bus = gst_element_get_bus (bin);
+  gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
+
+  src1 = gst_element_factory_make ("videotestsrc", "src1");
+  src2 = gst_element_factory_make ("videotestsrc", "src2");
+  videomixer = gst_element_factory_make ("videomixer", "videomixer");
+  sink = gst_element_factory_make ("fakesink", "sink");
+  gst_bin_add_many (GST_BIN (bin), src1, src2, videomixer, sink, NULL);
+
+  res = gst_element_link (src1, videomixer);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link (src2, videomixer);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link (videomixer, sink);
+  fail_unless (res == TRUE, NULL);
+
+  srcpad = gst_element_get_static_pad (videomixer, "src");
+  chk_3 = gst_consistency_checker_new (srcpad);
+  gst_object_unref (srcpad);
+
+  /* create consistency checkers for the pads */
+  srcpad = gst_element_get_static_pad (src1, "src");
+  chk_1 = gst_consistency_checker_new (srcpad);
+  sinkpad = gst_pad_get_peer (srcpad);
+  gst_consistency_checker_add_pad (chk_3, sinkpad);
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+
+  srcpad = gst_element_get_static_pad (src2, "src");
+  chk_2 = gst_consistency_checker_new (srcpad);
+  sinkpad = gst_pad_get_peer (srcpad);
+  gst_consistency_checker_add_pad (chk_3, sinkpad);
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+
+  seek_event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
+      GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH,
+      GST_SEEK_TYPE_SET, (GstClockTime) 0,
+      GST_SEEK_TYPE_SET, (GstClockTime) 2 * GST_SECOND);
+
+  format = GST_FORMAT_UNDEFINED;
+  position = -1;
+
+  main_loop = g_main_loop_new (NULL, FALSE);
+  g_signal_connect (bus, "message::segment-done",
+      (GCallback) test_event_message_received, bin);
+  g_signal_connect (bus, "message::error", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::warning", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::eos", (GCallback) message_received, bin);
+
+  GST_INFO ("starting test");
+
+  /* prepare playing */
+  state_res = gst_element_set_state (bin, GST_STATE_PAUSED);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  /* wait for completion */
+  state_res = gst_element_get_state (bin, NULL, NULL, GST_CLOCK_TIME_NONE);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  res = gst_element_send_event (bin, seek_event);
+  fail_unless (res == TRUE, NULL);
+
+  /* run pipeline */
+  state_res = gst_element_set_state (bin, GST_STATE_PLAYING);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  GST_INFO ("running main loop");
+  g_main_loop_run (main_loop);
+
+  state_res = gst_element_set_state (bin, GST_STATE_NULL);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  ck_assert_int_eq (position, 2 * GST_SECOND);
+
+  /* cleanup */
+  g_main_loop_unref (main_loop);
+  gst_consistency_checker_free (chk_1);
+  gst_consistency_checker_free (chk_2);
+  gst_consistency_checker_free (chk_3);
+  gst_bus_remove_signal_watch (bus);
+  gst_object_unref (bus);
+  gst_object_unref (bin);
+}
+
+GST_END_TEST;
+
+static guint play_count = 0;
+static GstEvent *play_seek_event = NULL;
+
+static void
+test_play_twice_message_received (GstBus * bus, GstMessage * message,
+    GstPipeline * bin)
+{
+  gboolean res;
+  GstStateChangeReturn state_res;
+
+  GST_INFO ("bus message from \"%" GST_PTR_FORMAT "\": %" GST_PTR_FORMAT,
+      GST_MESSAGE_SRC (message), message);
+
+  switch (message->type) {
+    case GST_MESSAGE_SEGMENT_DONE:
+      play_count++;
+      if (play_count == 1) {
+        state_res = gst_element_set_state (GST_ELEMENT (bin), GST_STATE_READY);
+        ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+        /* prepare playing again */
+        state_res = gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED);
+        ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+        /* wait for completion */
+        state_res =
+            gst_element_get_state (GST_ELEMENT (bin), NULL, NULL,
+            GST_CLOCK_TIME_NONE);
+        ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+        res = gst_element_send_event (GST_ELEMENT (bin),
+            gst_event_ref (play_seek_event));
+        fail_unless (res == TRUE, NULL);
+
+        state_res =
+            gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING);
+        ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+      } else {
+        g_main_loop_quit (main_loop);
+      }
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+
+GST_START_TEST (test_play_twice)
+{
+  GstElement *bin, *src1, *src2, *videomixer, *sink;
+  GstBus *bus;
+  gboolean res;
+  GstStateChangeReturn state_res;
+  GstPad *srcpad;
+  GstStreamConsistency *consist;
+
+  GST_INFO ("preparing test");
+
+  /* build pipeline */
+  bin = gst_pipeline_new ("pipeline");
+  bus = gst_element_get_bus (bin);
+  gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
+
+  src1 = gst_element_factory_make ("videotestsrc", "src1");
+  src2 = gst_element_factory_make ("videotestsrc", "src2");
+  videomixer = gst_element_factory_make ("videomixer", "videomixer");
+  sink = gst_element_factory_make ("fakesink", "sink");
+  gst_bin_add_many (GST_BIN (bin), src1, src2, videomixer, sink, NULL);
+
+  res = gst_element_link (src1, videomixer);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link (src2, videomixer);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link (videomixer, sink);
+  fail_unless (res == TRUE, NULL);
+
+  srcpad = gst_element_get_static_pad (videomixer, "src");
+  consist = gst_consistency_checker_new (srcpad);
+  gst_object_unref (srcpad);
+
+  play_seek_event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
+      GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH,
+      GST_SEEK_TYPE_SET, (GstClockTime) 0,
+      GST_SEEK_TYPE_SET, (GstClockTime) 2 * GST_SECOND);
+
+  play_count = 0;
+
+  main_loop = g_main_loop_new (NULL, FALSE);
+  g_signal_connect (bus, "message::segment-done",
+      (GCallback) test_play_twice_message_received, bin);
+  g_signal_connect (bus, "message::error", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::warning", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::eos", (GCallback) message_received, bin);
+
+  GST_INFO ("starting test");
+
+  /* prepare playing */
+  state_res = gst_element_set_state (bin, GST_STATE_PAUSED);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  /* wait for completion */
+  state_res =
+      gst_element_get_state (GST_ELEMENT (bin), NULL, NULL,
+      GST_CLOCK_TIME_NONE);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  res = gst_element_send_event (bin, gst_event_ref (play_seek_event));
+  fail_unless (res == TRUE, NULL);
+
+  GST_INFO ("seeked");
+
+  /* run pipeline */
+  state_res = gst_element_set_state (bin, GST_STATE_PLAYING);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  g_main_loop_run (main_loop);
+
+  state_res = gst_element_set_state (bin, GST_STATE_NULL);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  ck_assert_int_eq (play_count, 2);
+
+  /* cleanup */
+  g_main_loop_unref (main_loop);
+  gst_consistency_checker_free (consist);
+  gst_event_unref (play_seek_event);
+  gst_bus_remove_signal_watch (bus);
+  gst_object_unref (bus);
+  gst_object_unref (bin);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_play_twice_then_add_and_play_again)
+{
+  GstElement *bin, *src1, *src2, *src3, *videomixer, *sink;
+  GstBus *bus;
+  gboolean res;
+  GstStateChangeReturn state_res;
+  gint i;
+  GstPad *srcpad;
+  GstStreamConsistency *consist;
+
+  GST_INFO ("preparing test");
+
+  /* build pipeline */
+  bin = gst_pipeline_new ("pipeline");
+  bus = gst_element_get_bus (bin);
+  gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
+
+  src1 = gst_element_factory_make ("videotestsrc", "src1");
+  src2 = gst_element_factory_make ("videotestsrc", "src2");
+  videomixer = gst_element_factory_make ("videomixer", "videomixer");
+  sink = gst_element_factory_make ("fakesink", "sink");
+  gst_bin_add_many (GST_BIN (bin), src1, src2, videomixer, sink, NULL);
+
+  srcpad = gst_element_get_static_pad (videomixer, "src");
+  consist = gst_consistency_checker_new (srcpad);
+  gst_object_unref (srcpad);
+
+  res = gst_element_link (src1, videomixer);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link (src2, videomixer);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link (videomixer, sink);
+  fail_unless (res == TRUE, NULL);
+
+  play_seek_event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
+      GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH,
+      GST_SEEK_TYPE_SET, (GstClockTime) 0,
+      GST_SEEK_TYPE_SET, (GstClockTime) 2 * GST_SECOND);
+
+  main_loop = g_main_loop_new (NULL, FALSE);
+  g_signal_connect (bus, "message::segment-done",
+      (GCallback) test_play_twice_message_received, bin);
+  g_signal_connect (bus, "message::error", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::warning", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::eos", (GCallback) message_received, bin);
+
+  /* run it twice */
+  for (i = 0; i < 2; i++) {
+    play_count = 0;
+
+    GST_INFO ("starting test-loop %d", i);
+
+    /* prepare playing */
+    state_res = gst_element_set_state (bin, GST_STATE_PAUSED);
+    ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+    /* wait for completion */
+    state_res =
+        gst_element_get_state (GST_ELEMENT (bin), NULL, NULL,
+        GST_CLOCK_TIME_NONE);
+    ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+    res = gst_element_send_event (bin, gst_event_ref (play_seek_event));
+    fail_unless (res == TRUE, NULL);
+
+    GST_INFO ("seeked");
+
+    /* run pipeline */
+    state_res = gst_element_set_state (bin, GST_STATE_PLAYING);
+    ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+    g_main_loop_run (main_loop);
+
+    state_res = gst_element_set_state (bin, GST_STATE_READY);
+    ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+    ck_assert_int_eq (play_count, 2);
+
+    /* plug another source */
+    if (i == 0) {
+      src3 = gst_element_factory_make ("videotestsrc", "src3");
+      gst_bin_add (GST_BIN (bin), src3);
+
+      res = gst_element_link (src3, videomixer);
+      fail_unless (res == TRUE, NULL);
+    }
+
+    gst_consistency_checker_reset (consist);
+  }
+
+  state_res = gst_element_set_state (bin, GST_STATE_NULL);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  /* cleanup */
+  g_main_loop_unref (main_loop);
+  gst_event_unref (play_seek_event);
+  gst_consistency_checker_free (consist);
+  gst_bus_remove_signal_watch (bus);
+  gst_object_unref (bus);
+  gst_object_unref (bin);
+}
+
+GST_END_TEST;
+
+/* check if adding pads work as expected */
+GST_START_TEST (test_add_pad)
+{
+  GstElement *bin, *src1, *src2, *videomixer, *sink;
+  GstBus *bus;
+  GstPad *srcpad;
+  gboolean res;
+  GstStateChangeReturn state_res;
+
+  GST_INFO ("preparing test");
+
+  /* build pipeline */
+  bin = gst_pipeline_new ("pipeline");
+  bus = gst_element_get_bus (bin);
+  gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
+
+  src1 = gst_element_factory_make ("videotestsrc", "src1");
+  g_object_set (src1, "num-buffers", 4, NULL);
+  src2 = gst_element_factory_make ("videotestsrc", "src2");
+  /* one buffer less, we connect with 1 buffer of delay */
+  g_object_set (src2, "num-buffers", 3, NULL);
+  videomixer = gst_element_factory_make ("videomixer", "videomixer");
+  sink = gst_element_factory_make ("fakesink", "sink");
+  gst_bin_add_many (GST_BIN (bin), src1, videomixer, sink, NULL);
+
+  res = gst_element_link (src1, videomixer);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link (videomixer, sink);
+  fail_unless (res == TRUE, NULL);
+
+  srcpad = gst_element_get_static_pad (videomixer, "src");
+  gst_object_unref (srcpad);
+
+  main_loop = g_main_loop_new (NULL, FALSE);
+  g_signal_connect (bus, "message::segment-done", (GCallback) message_received,
+      bin);
+  g_signal_connect (bus, "message::error", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::warning", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::eos", (GCallback) message_received, bin);
+
+  GST_INFO ("starting test");
+
+  /* prepare playing */
+  state_res = gst_element_set_state (bin, GST_STATE_PAUSED);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  /* wait for completion */
+  state_res =
+      gst_element_get_state (GST_ELEMENT (bin), NULL, NULL,
+      GST_CLOCK_TIME_NONE);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  /* add other element */
+  gst_bin_add_many (GST_BIN (bin), src2, NULL);
+
+  /* now link the second element */
+  res = gst_element_link (src2, videomixer);
+  fail_unless (res == TRUE, NULL);
+
+  /* set to PAUSED as well */
+  state_res = gst_element_set_state (src2, GST_STATE_PAUSED);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  /* now play all */
+  state_res = gst_element_set_state (bin, GST_STATE_PLAYING);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  g_main_loop_run (main_loop);
+
+  state_res = gst_element_set_state (bin, GST_STATE_NULL);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  /* cleanup */
+  g_main_loop_unref (main_loop);
+  gst_bus_remove_signal_watch (bus);
+  gst_object_unref (bus);
+  gst_object_unref (bin);
+}
+
+GST_END_TEST;
+
+/* check if removing pads work as expected */
+GST_START_TEST (test_remove_pad)
+{
+  GstElement *bin, *src, *videomixer, *sink;
+  GstBus *bus;
+  GstPad *pad, *srcpad;
+  gboolean res;
+  GstStateChangeReturn state_res;
+
+  GST_INFO ("preparing test");
+
+  /* build pipeline */
+  bin = gst_pipeline_new ("pipeline");
+  bus = gst_element_get_bus (bin);
+  gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
+
+  src = gst_element_factory_make ("videotestsrc", "src");
+  g_object_set (src, "num-buffers", 4, NULL);
+  videomixer = gst_element_factory_make ("videomixer", "videomixer");
+  sink = gst_element_factory_make ("fakesink", "sink");
+  gst_bin_add_many (GST_BIN (bin), src, videomixer, sink, NULL);
+
+  res = gst_element_link (src, videomixer);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link (videomixer, sink);
+  fail_unless (res == TRUE, NULL);
+
+  /* create an unconnected sinkpad in videomixer */
+  pad = gst_element_get_request_pad (videomixer, "sink_%u");
+  fail_if (pad == NULL, NULL);
+
+  srcpad = gst_element_get_static_pad (videomixer, "src");
+  gst_object_unref (srcpad);
+
+  main_loop = g_main_loop_new (NULL, FALSE);
+  g_signal_connect (bus, "message::segment-done", (GCallback) message_received,
+      bin);
+  g_signal_connect (bus, "message::error", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::warning", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::eos", (GCallback) message_received, bin);
+
+  GST_INFO ("starting test");
+
+  /* prepare playing, this will not preroll as videomixer is waiting
+   * on the unconnected sinkpad. */
+  state_res = gst_element_set_state (bin, GST_STATE_PAUSED);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  /* wait for completion for one second, will return ASYNC */
+  state_res = gst_element_get_state (GST_ELEMENT (bin), NULL, NULL, GST_SECOND);
+  ck_assert_int_eq (state_res, GST_STATE_CHANGE_ASYNC);
+
+  /* get rid of the pad now, videomixer should stop waiting on it and
+   * continue the preroll */
+  gst_element_release_request_pad (videomixer, pad);
+  gst_object_unref (pad);
+
+  /* wait for completion, should work now */
+  state_res =
+      gst_element_get_state (GST_ELEMENT (bin), NULL, NULL,
+      GST_CLOCK_TIME_NONE);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  /* now play all */
+  state_res = gst_element_set_state (bin, GST_STATE_PLAYING);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  g_main_loop_run (main_loop);
+
+  state_res = gst_element_set_state (bin, GST_STATE_NULL);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  /* cleanup */
+  g_main_loop_unref (main_loop);
+  gst_bus_remove_signal_watch (bus);
+  gst_object_unref (G_OBJECT (bus));
+  gst_object_unref (G_OBJECT (bin));
+}
+
+GST_END_TEST;
+
+
+static GstBuffer *handoff_buffer = NULL;
+static void
+handoff_buffer_cb (GstElement * fakesink, GstBuffer * buffer, GstPad * pad,
+    gpointer user_data)
+{
+  GST_DEBUG ("got buffer %p", buffer);
+  gst_buffer_replace (&handoff_buffer, buffer);
+}
+
+/* check if clipping works as expected */
+GST_START_TEST (test_clip)
+{
+  GstSegment segment;
+  GstElement *bin, *videomixer, *sink;
+  GstBus *bus;
+  GstPad *sinkpad;
+  gboolean res;
+  GstStateChangeReturn state_res;
+  GstFlowReturn ret;
+  GstEvent *event;
+  GstBuffer *buffer;
+  GstCaps *caps;
+
+  GST_INFO ("preparing test");
+
+  /* build pipeline */
+  bin = gst_pipeline_new ("pipeline");
+  bus = gst_element_get_bus (bin);
+  gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
+
+  g_signal_connect (bus, "message::error", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::warning", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::eos", (GCallback) message_received, bin);
+
+  /* just an videomixer and a fakesink */
+  videomixer = gst_element_factory_make ("videomixer", "videomixer");
+  sink = gst_element_factory_make ("fakesink", "sink");
+  g_object_set (sink, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (sink, "handoff", (GCallback) handoff_buffer_cb, NULL);
+  gst_bin_add_many (GST_BIN (bin), videomixer, sink, NULL);
+
+  res = gst_element_link (videomixer, sink);
+  fail_unless (res == TRUE, NULL);
+
+  /* set to playing */
+  state_res = gst_element_set_state (bin, GST_STATE_PLAYING);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  /* create an unconnected sinkpad in videomixer, should also automatically activate
+   * the pad */
+  sinkpad = gst_element_get_request_pad (videomixer, "sink_%u");
+  fail_if (sinkpad == NULL, NULL);
+
+  gst_pad_send_event (sinkpad, gst_event_new_stream_start ("test"));
+
+  caps = gst_caps_from_string (VIDEO_CAPS_STRING);
+
+  gst_pad_set_caps (sinkpad, caps);
+  gst_caps_unref (caps);
+
+  /* send segment to videomixer */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  segment.start = GST_SECOND;
+  segment.stop = 2 * GST_SECOND;
+  segment.time = 0;
+  event = gst_event_new_segment (&segment);
+  gst_pad_send_event (sinkpad, event);
+
+  /* should be clipped and ok */
+  buffer = gst_buffer_new_and_alloc (115200);
+  GST_BUFFER_TIMESTAMP (buffer) = 0;
+  GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND;
+  GST_DEBUG ("pushing buffer %p", buffer);
+  ret = gst_pad_chain (sinkpad, buffer);
+  ck_assert_int_eq (ret, GST_FLOW_OK);
+  fail_unless (handoff_buffer == NULL);
+
+  /* should be partially clipped */
+  buffer = gst_buffer_new_and_alloc (115200);
+  GST_BUFFER_TIMESTAMP (buffer) = 900 * GST_MSECOND;
+  GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND;
+  GST_DEBUG ("pushing buffer %p", buffer);
+  ret = gst_pad_chain (sinkpad, buffer);
+  ck_assert_int_eq (ret, GST_FLOW_OK);
+  fail_unless (handoff_buffer != NULL);
+  gst_buffer_replace (&handoff_buffer, NULL);
+
+  /* should not be clipped */
+  buffer = gst_buffer_new_and_alloc (115200);
+  GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
+  GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND;
+  GST_DEBUG ("pushing buffer %p", buffer);
+  ret = gst_pad_chain (sinkpad, buffer);
+  ck_assert_int_eq (ret, GST_FLOW_OK);
+  fail_unless (handoff_buffer != NULL);
+  gst_buffer_replace (&handoff_buffer, NULL);
+
+  /* should be clipped and ok */
+  buffer = gst_buffer_new_and_alloc (115200);
+  GST_BUFFER_TIMESTAMP (buffer) = 2 * GST_SECOND;
+  GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND;
+  GST_DEBUG ("pushing buffer %p", buffer);
+  ret = gst_pad_chain (sinkpad, buffer);
+  ck_assert_int_eq (ret, GST_FLOW_OK);
+  fail_unless (handoff_buffer == NULL);
+
+  gst_object_unref (sinkpad);
+  gst_element_set_state (bin, GST_STATE_NULL);
+  gst_bus_remove_signal_watch (bus);
+  gst_object_unref (bus);
+  gst_object_unref (bin);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_duration_is_max)
+{
+  GstElement *bin, *src[3], *videomixer, *sink;
+  GstStateChangeReturn state_res;
+  GstFormat format = GST_FORMAT_TIME;
+  gboolean res;
+  gint64 duration;
+
+  GST_INFO ("preparing test");
+
+  /* build pipeline */
+  bin = gst_pipeline_new ("pipeline");
+
+  /* 3 sources, an videomixer and a fakesink */
+  src[0] = gst_element_factory_make ("videotestsrc", NULL);
+  src[1] = gst_element_factory_make ("videotestsrc", NULL);
+  src[2] = gst_element_factory_make ("videotestsrc", NULL);
+  videomixer = gst_element_factory_make ("videomixer", "videomixer");
+  sink = gst_element_factory_make ("fakesink", "sink");
+  gst_bin_add_many (GST_BIN (bin), src[0], src[1], src[2], videomixer, sink,
+      NULL);
+
+  gst_element_link (src[0], videomixer);
+  gst_element_link (src[1], videomixer);
+  gst_element_link (src[2], videomixer);
+  gst_element_link (videomixer, sink);
+
+  /* irks, duration is reset on basesrc */
+  state_res = gst_element_set_state (bin, GST_STATE_PAUSED);
+  fail_unless (state_res != GST_STATE_CHANGE_FAILURE, NULL);
+
+  /* set durations on src */
+  GST_BASE_SRC (src[0])->segment.duration = 1000;
+  GST_BASE_SRC (src[1])->segment.duration = 3000;
+  GST_BASE_SRC (src[2])->segment.duration = 2000;
+
+  /* set to playing */
+  state_res = gst_element_set_state (bin, GST_STATE_PLAYING);
+  fail_unless (state_res != GST_STATE_CHANGE_FAILURE, NULL);
+
+  /* wait for completion */
+  state_res =
+      gst_element_get_state (GST_ELEMENT (bin), NULL, NULL,
+      GST_CLOCK_TIME_NONE);
+  fail_unless (state_res != GST_STATE_CHANGE_FAILURE, NULL);
+
+  res = gst_element_query_duration (GST_ELEMENT (bin), format, &duration);
+  fail_unless (res, NULL);
+
+  ck_assert_int_eq (duration, 3000);
+
+  gst_element_set_state (bin, GST_STATE_NULL);
+  gst_object_unref (bin);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_duration_unknown_overrides)
+{
+  GstElement *bin, *src[3], *videomixer, *sink;
+  GstStateChangeReturn state_res;
+  GstFormat format = GST_FORMAT_TIME;
+  gboolean res;
+  gint64 duration;
+
+  GST_INFO ("preparing test");
+
+  /* build pipeline */
+  bin = gst_pipeline_new ("pipeline");
+
+  /* 3 sources, an videomixer and a fakesink */
+  src[0] = gst_element_factory_make ("videotestsrc", NULL);
+  src[1] = gst_element_factory_make ("videotestsrc", NULL);
+  src[2] = gst_element_factory_make ("videotestsrc", NULL);
+  videomixer = gst_element_factory_make ("videomixer", "videomixer");
+  sink = gst_element_factory_make ("fakesink", "sink");
+  gst_bin_add_many (GST_BIN (bin), src[0], src[1], src[2], videomixer, sink,
+      NULL);
+
+  gst_element_link (src[0], videomixer);
+  gst_element_link (src[1], videomixer);
+  gst_element_link (src[2], videomixer);
+  gst_element_link (videomixer, sink);
+
+  /* irks, duration is reset on basesrc */
+  state_res = gst_element_set_state (bin, GST_STATE_PAUSED);
+  fail_unless (state_res != GST_STATE_CHANGE_FAILURE, NULL);
+
+  /* set durations on src */
+  GST_BASE_SRC (src[0])->segment.duration = GST_CLOCK_TIME_NONE;
+  GST_BASE_SRC (src[1])->segment.duration = 3000;
+  GST_BASE_SRC (src[2])->segment.duration = 2000;
+
+  /* set to playing */
+  state_res = gst_element_set_state (bin, GST_STATE_PLAYING);
+  fail_unless (state_res != GST_STATE_CHANGE_FAILURE, NULL);
+
+  /* wait for completion */
+  state_res =
+      gst_element_get_state (GST_ELEMENT (bin), NULL, NULL,
+      GST_CLOCK_TIME_NONE);
+  fail_unless (state_res != GST_STATE_CHANGE_FAILURE, NULL);
+
+  res = gst_element_query_duration (GST_ELEMENT (bin), format, &duration);
+  fail_unless (res, NULL);
+
+  ck_assert_int_eq (duration, GST_CLOCK_TIME_NONE);
+
+  gst_element_set_state (bin, GST_STATE_NULL);
+  gst_object_unref (bin);
+}
+
+GST_END_TEST;
+
+
+static gboolean looped = FALSE;
+
+static void
+loop_segment_done (GstBus * bus, GstMessage * message, GstElement * bin)
+{
+  GST_INFO ("bus message from \"%" GST_PTR_FORMAT "\": %" GST_PTR_FORMAT,
+      GST_MESSAGE_SRC (message), message);
+
+  if (looped) {
+    g_main_loop_quit (main_loop);
+  } else {
+    GstEvent *seek_event;
+    gboolean res;
+
+    seek_event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
+        GST_SEEK_FLAG_SEGMENT,
+        GST_SEEK_TYPE_SET, (GstClockTime) 0,
+        GST_SEEK_TYPE_SET, (GstClockTime) 1 * GST_SECOND);
+
+    res = gst_element_send_event (bin, seek_event);
+    fail_unless (res == TRUE, NULL);
+    looped = TRUE;
+  }
+}
+
+GST_START_TEST (test_loop)
+{
+  GstElement *bin, *src1, *src2, *videomixer, *sink;
+  GstBus *bus;
+  GstEvent *seek_event;
+  GstStateChangeReturn state_res;
+  gboolean res;
+
+  GST_INFO ("preparing test");
+
+  /* build pipeline */
+  bin = gst_pipeline_new ("pipeline");
+  bus = gst_element_get_bus (bin);
+  gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
+
+  src1 = gst_element_factory_make ("videotestsrc", "src1");
+  src2 = gst_element_factory_make ("videotestsrc", "src2");
+  videomixer = gst_element_factory_make ("videomixer", "videomixer");
+  sink = gst_element_factory_make ("fakesink", "sink");
+  gst_bin_add_many (GST_BIN (bin), src1, src2, videomixer, sink, NULL);
+
+  res = gst_element_link (src1, videomixer);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link (src2, videomixer);
+  fail_unless (res == TRUE, NULL);
+  res = gst_element_link (videomixer, sink);
+  fail_unless (res == TRUE, NULL);
+
+  seek_event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
+      GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH,
+      GST_SEEK_TYPE_SET, (GstClockTime) 0, GST_SEEK_TYPE_SET,
+      (GstClockTime) 2 * GST_SECOND);
+
+  main_loop = g_main_loop_new (NULL, FALSE);
+  g_signal_connect (bus, "message::segment-done",
+      (GCallback) loop_segment_done, bin);
+  g_signal_connect (bus, "message::error", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::warning", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::eos", (GCallback) message_received, bin);
+
+  GST_INFO ("starting test");
+
+  /* prepare playing */
+  state_res = gst_element_set_state (bin, GST_STATE_PAUSED);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  /* wait for completion */
+  state_res =
+      gst_element_get_state (GST_ELEMENT (bin), NULL, NULL,
+      GST_CLOCK_TIME_NONE);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  res = gst_element_send_event (bin, seek_event);
+  fail_unless (res == TRUE, NULL);
+
+  /* run pipeline */
+  state_res = gst_element_set_state (bin, GST_STATE_PLAYING);
+  ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
+
+  GST_INFO ("running main loop");
+  g_main_loop_run (main_loop);
+
+  state_res = gst_element_set_state (bin, GST_STATE_NULL);
+
+  /* cleanup */
+  g_main_loop_unref (main_loop);
+  gst_bus_remove_signal_watch (bus);
+  gst_object_unref (bus);
+  gst_object_unref (bin);
+}
+
+GST_END_TEST;
+
+#if 0
+GST_START_TEST (test_flush_start_flush_stop)
+{
+  GstPadTemplate *sink_template;
+  GstPad *tmppad, *sinkpad1, *sinkpad2, *videomixer_src;
+  GstElement *pipeline, *src1, *src2, *videomixer, *sink;
+
+  GST_INFO ("preparing test");
+
+  /* build pipeline */
+  pipeline = gst_pipeline_new ("pipeline");
+  src1 = gst_element_factory_make ("videotestsrc", "src1");
+  src2 = gst_element_factory_make ("videotestsrc", "src2");
+  videomixer = gst_element_factory_make ("videomixer", "videomixer");
+  sink = gst_element_factory_make ("fakesink", "sink");
+  gst_bin_add_many (GST_BIN (pipeline), src1, src2, videomixer, sink, NULL);
+
+  sink_template =
+      gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (videomixer),
+      "sink_%u");
+  fail_unless (GST_IS_PAD_TEMPLATE (sink_template));
+  sinkpad1 = gst_element_request_pad (videomixer, sink_template, NULL, NULL);
+  tmppad = gst_element_get_static_pad (src1, "src");
+  gst_pad_link (tmppad, sinkpad1);
+  gst_object_unref (tmppad);
+
+  sinkpad2 = gst_element_request_pad (videomixer, sink_template, NULL, NULL);
+  tmppad = gst_element_get_static_pad (src2, "src");
+  gst_pad_link (tmppad, sinkpad2);
+  gst_object_unref (tmppad);
+
+  gst_element_link (videomixer, sink);
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  fail_unless (gst_element_get_state (pipeline, NULL, NULL,
+          GST_CLOCK_TIME_NONE) == GST_STATE_CHANGE_SUCCESS);
+
+  videomixer_src = gst_element_get_static_pad (videomixer, "src");
+  fail_if (GST_PAD_IS_FLUSHING (videomixer_src));
+  gst_pad_send_event (sinkpad1, gst_event_new_flush_start ());
+  fail_unless (GST_PAD_IS_FLUSHING (videomixer_src));
+  gst_pad_send_event (sinkpad1, gst_event_new_flush_stop (TRUE));
+  fail_if (GST_PAD_IS_FLUSHING (videomixer_src));
+  gst_object_unref (videomixer_src);
+
+  /* cleanup */
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (sinkpad1);
+  gst_object_unref (sinkpad2);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+#endif
+
+static Suite *
+videomixer_suite (void)
+{
+  Suite *s = suite_create ("videomixer");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_caps);
+  tcase_add_test (tc_chain, test_event);
+  tcase_add_test (tc_chain, test_play_twice);
+  tcase_add_test (tc_chain, test_play_twice_then_add_and_play_again);
+  tcase_add_test (tc_chain, test_add_pad);
+  tcase_add_test (tc_chain, test_remove_pad);
+  tcase_add_test (tc_chain, test_clip);
+  tcase_add_test (tc_chain, test_duration_is_max);
+  tcase_add_test (tc_chain, test_duration_unknown_overrides);
+  tcase_add_test (tc_chain, test_loop);
+  /* This test is racy and occasionally fails in interesting ways
+   * just like the corresponding adder test does/did, see
+   * https://bugzilla.gnome.org/show_bug.cgi?id=708891
+   * It's unlikely that it will ever be fixed for videomixer/collectpads,
+   * as it works fine with compositor */
+#if 0
+  tcase_add_test (tc_chain, test_flush_start_flush_stop);
+#endif
+
+  /* Use a longer timeout */
+#ifdef HAVE_VALGRIND
+  if (RUNNING_ON_VALGRIND) {
+    tcase_set_timeout (tc_chain, 5 * 60);
+  } else
+#endif
+  {
+    /* this is shorter than the default 60 seconds?! (tpm) */
+    /* tcase_set_timeout (tc_chain, 6); */
+  }
+
+  return s;
+}
+
+GST_CHECK_MAIN (videomixer);
diff --git a/tests/check/elements/vp8dec.c b/tests/check/elements/vp8dec.c
new file mode 100644
index 0000000..0ebd70a
--- /dev/null
+++ b/tests/check/elements/vp8dec.c
@@ -0,0 +1,266 @@
+/* GStreamer
+ *
+ * Copyright (c) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-raw, "
+        "format = (string) I420, "
+        "width = (int) [1, MAX], "
+        "height = (int) [1, MAX], " "framerate = (fraction) [0, MAX]"));
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-raw, "
+        "format = (string) I420, "
+        "width = (int) [1, MAX], "
+        "height = (int) [1, MAX], " "framerate = (fraction) [0, MAX]"));
+
+static GstPad *sinkpad, *srcpad;
+
+static GstElement *
+setup_vp8dec (const gchar * src_caps_str)
+{
+  GstElement *bin;
+  GstElement *vp8enc, *vp8dec;
+  GstCaps *srccaps = NULL;
+  GstBus *bus;
+  GstPad *ghostpad, *targetpad;
+
+  if (src_caps_str) {
+    srccaps = gst_caps_from_string (src_caps_str);
+    fail_unless (srccaps != NULL);
+  }
+
+  bin = gst_bin_new ("bin");
+
+  vp8enc = gst_check_setup_element ("vp8enc");
+  fail_unless (vp8enc != NULL);
+  vp8dec = gst_check_setup_element ("vp8dec");
+  fail_unless (vp8dec != NULL);
+
+  g_object_set (vp8enc, "name", "encoder", NULL);
+  g_object_set (vp8dec, "name", "decoder", NULL);
+
+  gst_bin_add_many (GST_BIN (bin), vp8enc, vp8dec, NULL);
+  fail_unless (gst_element_link_pads (vp8enc, "src", vp8dec, "sink"));
+
+  targetpad = gst_element_get_static_pad (vp8enc, "sink");
+  fail_unless (targetpad != NULL);
+  ghostpad = gst_ghost_pad_new ("sink", targetpad);
+  fail_unless (ghostpad != NULL);
+  gst_element_add_pad (bin, ghostpad);
+  gst_object_unref (targetpad);
+
+  targetpad = gst_element_get_static_pad (vp8dec, "src");
+  fail_unless (targetpad != NULL);
+  ghostpad = gst_ghost_pad_new ("src", targetpad);
+  fail_unless (ghostpad != NULL);
+  gst_element_add_pad (bin, ghostpad);
+  gst_object_unref (targetpad);
+
+  srcpad = gst_check_setup_src_pad (bin, &srctemplate);
+  sinkpad = gst_check_setup_sink_pad (bin, &sinktemplate);
+  gst_pad_set_active (srcpad, TRUE);
+  gst_pad_set_active (sinkpad, TRUE);
+  gst_check_setup_events (srcpad, bin, srccaps, GST_FORMAT_TIME);
+
+  bus = gst_bus_new ();
+  gst_element_set_bus (bin, bus);
+
+  fail_unless (gst_element_set_state (bin,
+          GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE,
+      "could not set to playing");
+
+  if (srccaps)
+    gst_caps_unref (srccaps);
+
+  buffers = NULL;
+  return bin;
+}
+
+static void
+cleanup_vp8dec (GstElement * bin)
+{
+  GstBus *bus;
+
+  /* Free parsed buffers */
+  gst_check_drop_buffers ();
+
+  bus = GST_ELEMENT_BUS (bin);
+  gst_bus_set_flushing (bus, TRUE);
+  gst_object_unref (bus);
+
+  gst_pad_set_active (srcpad, FALSE);
+  gst_pad_set_active (sinkpad, FALSE);
+
+  gst_check_teardown_src_pad (bin);
+  gst_check_teardown_sink_pad (bin);
+  gst_check_teardown_element (bin);
+}
+
+static void
+_gst_vp8_test_check_output_caps (gint width, gint height, gint fps_n,
+    gint fps_d)
+{
+  GstCaps *caps;
+  GstStructure *structure;
+  gint caps_w, caps_h, caps_fpsn, caps_fpsd;
+
+  caps = gst_pad_get_current_caps (sinkpad);
+  fail_unless (caps != NULL);
+  structure = gst_caps_get_structure (caps, 0);
+
+  fail_unless (gst_structure_get_int (structure, "width", &caps_w));
+  fail_unless (gst_structure_get_int (structure, "height", &caps_h));
+  fail_unless (gst_structure_get_fraction (structure, "framerate", &caps_fpsn,
+          &caps_fpsd));
+
+  fail_unless (width == caps_w);
+  fail_unless (height == caps_h);
+  fail_unless (fps_n == caps_fpsn);
+  fail_unless (fps_d == caps_fpsd);
+
+  gst_caps_unref (caps);
+}
+
+GST_START_TEST (test_decode_simple)
+{
+  GstElement *bin;
+  GstBuffer *buffer;
+  gint i;
+  GList *l;
+  GstSegment seg;
+
+  bin =
+      setup_vp8dec
+      ("video/x-raw,format=(string)I420,width=(int)320,height=(int)240,framerate=(fraction)25/1");
+
+  gst_segment_init (&seg, GST_FORMAT_TIME);
+  seg.stop = gst_util_uint64_scale (20, GST_SECOND, 25);
+  fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&seg)));
+
+  buffer = gst_buffer_new_and_alloc (320 * 240 + 2 * 160 * 120);
+  gst_buffer_memset (buffer, 0, 0, -1);
+
+  for (i = 0; i < 20; i++) {
+    GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (i, GST_SECOND, 25);
+    GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (1, GST_SECOND, 25);
+    fail_unless (gst_pad_push (srcpad, gst_buffer_ref (buffer)) == GST_FLOW_OK);
+  }
+
+  gst_buffer_unref (buffer);
+
+  fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ()));
+
+  /* All buffers must be there now */
+  fail_unless_equals_int (g_list_length (buffers), 20);
+
+  for (l = buffers, i = 0; l; l = l->next, i++) {
+    buffer = l->data;
+
+    fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buffer),
+        gst_util_uint64_scale (i, GST_SECOND, 25));
+    fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer),
+        gst_util_uint64_scale (1, GST_SECOND, 25));
+  }
+
+  cleanup_vp8dec (bin);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_decode_caps_change)
+{
+  GstElement *bin;
+  GstBuffer *buffer;
+  GstSegment seg;
+  GstElement *encoder;
+  GstCaps *caps;
+
+  bin =
+      setup_vp8dec
+      ("video/x-raw,format=(string)I420,width=(int)320,height=(int)240,framerate=(fraction)25/1");
+
+  gst_segment_init (&seg, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&seg)));
+
+  buffer = gst_buffer_new_and_alloc (320 * 240 + 2 * 160 * 120);
+  gst_buffer_memset (buffer, 0, 0, -1);
+
+  GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (0, GST_SECOND, 25);
+  GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (1, GST_SECOND, 25);
+  fail_unless (gst_pad_push (srcpad, buffer) == GST_FLOW_OK);
+
+  /* at this point, the output caps should be the same as the input */
+  _gst_vp8_test_check_output_caps (320, 240, 25, 1);
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
+  buffers = NULL;
+
+  /* now change the caps */
+  encoder = gst_bin_get_by_name (GST_BIN (bin), "encoder");
+  gst_element_set_state (encoder, GST_STATE_NULL);
+  gst_element_sync_state_with_parent (encoder);
+  gst_object_unref (encoder);
+  caps = gst_caps_from_string
+      ("video/x-raw,format=(string)I420,width=(int)64,"
+      "height=(int)32,framerate=(fraction)30/1");
+  fail_unless (gst_pad_push_event (srcpad, gst_event_new_caps (caps)));
+  fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&seg)));
+  buffer = gst_buffer_new_and_alloc (64 * 32 + 2 * 32 * 16);
+  gst_buffer_memset (buffer, 0, 0, -1);
+  gst_caps_unref (caps);
+
+  GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (0, GST_SECOND, 30);
+  GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (1, GST_SECOND, 30);
+  fail_unless (gst_pad_push (srcpad, buffer) == GST_FLOW_OK);
+
+  /* at this point, the output caps should be the same as the input */
+  _gst_vp8_test_check_output_caps (64, 32, 30, 1);
+  fail_unless_equals_int (g_list_length (buffers), 1);
+  g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
+  buffers = NULL;
+
+  cleanup_vp8dec (bin);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+vp8dec_suite (void)
+{
+  Suite *s = suite_create ("vp8dec");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_decode_simple);
+  tcase_add_test (tc_chain, test_decode_caps_change);
+
+  return s;
+}
+
+GST_CHECK_MAIN (vp8dec);
diff --git a/tests/check/elements/vp8enc.c b/tests/check/elements/vp8enc.c
new file mode 100644
index 0000000..86b1d92
--- /dev/null
+++ b/tests/check/elements/vp8enc.c
@@ -0,0 +1,168 @@
+/* GStreamer
+ *
+ * Copyright (c) 2010 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-vp8, "
+        "width = (int) [1, MAX], "
+        "height = (int) [1, MAX], " "framerate = (fraction) [0, MAX]"));
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-raw, "
+        "format = (string) I420, "
+        "width = (int) [1, MAX], "
+        "height = (int) [1, MAX], " "framerate = (fraction) [0, MAX]"));
+
+static GstPad *sinkpad, *srcpad;
+
+static GstElement *
+setup_vp8enc (const gchar * src_caps_str)
+{
+  GstElement *vp8enc;
+  GstCaps *srccaps = NULL;
+  GstBus *bus;
+
+  if (src_caps_str) {
+    srccaps = gst_caps_from_string (src_caps_str);
+    fail_unless (srccaps != NULL);
+  }
+
+  vp8enc = gst_check_setup_element ("vp8enc");
+  fail_unless (vp8enc != NULL);
+  srcpad = gst_check_setup_src_pad (vp8enc, &srctemplate);
+  sinkpad = gst_check_setup_sink_pad (vp8enc, &sinktemplate);
+  gst_pad_set_active (srcpad, TRUE);
+  gst_pad_set_active (sinkpad, TRUE);
+  gst_check_setup_events (srcpad, vp8enc, srccaps, GST_FORMAT_TIME);
+
+  bus = gst_bus_new ();
+  gst_element_set_bus (vp8enc, bus);
+
+  fail_unless (gst_element_set_state (vp8enc,
+          GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE,
+      "could not set to playing");
+
+  if (srccaps)
+    gst_caps_unref (srccaps);
+
+  buffers = NULL;
+  return vp8enc;
+}
+
+static void
+cleanup_vp8enc (GstElement * vp8enc)
+{
+  GstBus *bus;
+
+  /* Free parsed buffers */
+  gst_check_drop_buffers ();
+
+  bus = GST_ELEMENT_BUS (vp8enc);
+  gst_bus_set_flushing (bus, TRUE);
+  gst_object_unref (bus);
+
+  gst_pad_set_active (srcpad, FALSE);
+  gst_pad_set_active (sinkpad, FALSE);
+  gst_check_teardown_src_pad (vp8enc);
+  gst_check_teardown_sink_pad (vp8enc);
+  gst_check_teardown_element (vp8enc);
+}
+
+GST_START_TEST (test_encode_simple)
+{
+  GstElement *vp8enc;
+  GstBuffer *buffer;
+  gint i;
+  GList *l;
+  GstCaps *outcaps;
+  GstSegment seg;
+
+  vp8enc =
+      setup_vp8enc
+      ("video/x-raw,format=(string)I420,width=(int)320,height=(int)240,framerate=(fraction)25/1");
+
+  g_object_set (vp8enc, "lag-in-frames", 5, NULL);
+
+  gst_segment_init (&seg, GST_FORMAT_TIME);
+  seg.stop = gst_util_uint64_scale (20, GST_SECOND, 25);
+  fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&seg)));
+
+  buffer = gst_buffer_new_and_alloc (320 * 240 + 2 * 160 * 120);
+  gst_buffer_memset (buffer, 0, 0, -1);
+
+  for (i = 0; i < 20; i++) {
+    GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (i, GST_SECOND, 25);
+    GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (1, GST_SECOND, 25);
+    fail_unless (gst_pad_push (srcpad, gst_buffer_ref (buffer)) == GST_FLOW_OK);
+  }
+
+  gst_buffer_unref (buffer);
+
+  /* Only 5 buffers are allowed to be queued now */
+  fail_unless (g_list_length (buffers) > 15);
+
+  fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ()));
+
+
+  /* All buffers must be there now */
+  fail_unless_equals_int (g_list_length (buffers), 20);
+
+  outcaps =
+      gst_caps_from_string
+      ("video/x-vp8,width=(int)320,height=(int)240,framerate=(fraction)25/1");
+
+  for (l = buffers, i = 0; l; l = l->next, i++) {
+    buffer = l->data;
+
+    if (i == 0)
+      fail_if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT));
+
+    fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buffer),
+        gst_util_uint64_scale (i, GST_SECOND, 25));
+    fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer),
+        gst_util_uint64_scale (1, GST_SECOND, 25));
+  }
+
+  gst_caps_unref (outcaps);
+
+  cleanup_vp8enc (vp8enc);
+}
+
+GST_END_TEST;
+
+static Suite *
+vp8enc_suite (void)
+{
+  Suite *s = suite_create ("vp8enc");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_encode_simple);
+
+  return s;
+}
+
+GST_CHECK_MAIN (vp8enc);
diff --git a/tests/check/elements/vp9enc.c b/tests/check/elements/vp9enc.c
new file mode 100644
index 0000000..f7be0e0
--- /dev/null
+++ b/tests/check/elements/vp9enc.c
@@ -0,0 +1,78 @@
+/* GStreamer
+ *
+ * Copyright (c) 2016 Stian Selnes <stian@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <gst/check/gstharness.h>
+#include <gst/check/gstcheck.h>
+#include <gst/video/video.h>
+
+GST_START_TEST (test_encode_lag_in_frames)
+{
+  GstHarness *h = gst_harness_new_parse ("vp9enc lag-in-frames=5 cpu-used=8 "
+      "deadline=1");
+  gint i;
+
+  gst_harness_add_src_parse (h, "videotestsrc is-live=true pattern=black ! "
+      "capsfilter caps=\"video/x-raw,width=320,height=240,framerate=25/1\"",
+      TRUE);
+
+  /* Push 20 buffers into the encoder */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_src_crank_and_push_many (h, 20, 20));
+
+  /* Only 5 buffers are allowed to be queued now */
+  fail_unless (gst_harness_buffers_received (h) > 15);
+
+  /* EOS will cause the remaining buffers to be drained */
+  fail_unless (gst_harness_push_event (h, gst_event_new_eos ()));
+  fail_unless_equals_int (gst_harness_buffers_received (h), 20);
+
+  for (i = 0; i < 20; i++) {
+    GstBuffer *buffer = gst_harness_pull (h);
+
+    if (i == 0)
+      fail_if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT));
+
+    fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buffer),
+        gst_util_uint64_scale (i, GST_SECOND, 25));
+    fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer),
+        gst_util_uint64_scale (1, GST_SECOND, 25));
+
+    gst_buffer_unref (buffer);
+  }
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+vp9enc_suite (void)
+{
+  Suite *s = suite_create ("vp9enc");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_encode_lag_in_frames);
+
+  return s;
+}
+
+GST_CHECK_MAIN (vp9enc);
diff --git a/tests/check/elements/wavpackdec.c b/tests/check/elements/wavpackdec.c
new file mode 100644
index 0000000..33ed05a
--- /dev/null
+++ b/tests/check/elements/wavpackdec.c
@@ -0,0 +1,243 @@
+/* GStreamer
+ *
+ * unit test for wavpackdec
+ *
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+static GstPad *mysrcpad, *mysinkpad;
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+#define AUDIO_FORMAT "S16BE"
+#else
+#define AUDIO_FORMAT "S16LE"
+#endif
+
+guint8 test_frame[] = {
+  0x77, 0x76, 0x70, 0x6B,       /* "wvpk" */
+  0x2E, 0x00, 0x00, 0x00,       /* ckSize */
+  0x04, 0x04,                   /* version */
+  0x00,                         /* track_no */
+  0x00,                         /* index_no */
+  0x00, 0x64, 0x00, 0x00,       /* total_samples */
+  0x00, 0x00, 0x00, 0x00,       /* block_index */
+  0x00, 0x64, 0x00, 0x00,       /* block_samples */
+  0x05, 0x18, 0x80, 0x04,       /* flags */
+  0xFF, 0xAF, 0x80, 0x60,       /* crc */
+  0x02, 0x00, 0x03, 0x00,       /* data */
+  0x04, 0x00, 0x05, 0x03,
+  0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x8A, 0x02,
+  0x00, 0x00, 0xFF, 0x7F,
+  0x00, 0xE4,
+};
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " AUDIO_FORMAT ", "
+        "layout = (string) interleaved, "
+        "channels = (int) 1, " "rate = (int) 44100")
+    );
+
+#define WAVPACK_CAPS "audio/x-wavpack, " \
+        "depth = (int) 16, " \
+        "channels = (int) 1, " "rate = (int) 44100, " "framed = (boolean) true"
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (WAVPACK_CAPS)
+    );
+
+static GstElement *
+setup_wavpackdec (void)
+{
+  GstElement *wavpackdec;
+  GstCaps *caps;
+
+  GST_DEBUG ("setup_wavpackdec");
+  wavpackdec = gst_check_setup_element ("wavpackdec");
+  mysrcpad = gst_check_setup_src_pad (wavpackdec, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (wavpackdec, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  caps = gst_caps_from_string (WAVPACK_CAPS);
+  gst_check_setup_events (mysrcpad, wavpackdec, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  fail_unless (gst_element_set_state (wavpackdec,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  return wavpackdec;
+}
+
+static void
+cleanup_wavpackdec (GstElement * wavpackdec)
+{
+  GST_DEBUG ("cleanup_wavpackdec");
+  gst_element_set_state (wavpackdec, GST_STATE_NULL);
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (wavpackdec);
+  gst_check_teardown_sink_pad (wavpackdec);
+  gst_check_teardown_element (wavpackdec);
+}
+
+GST_START_TEST (test_decode_frame)
+{
+  GstElement *wavpackdec;
+  GstBuffer *inbuffer, *outbuffer;
+  GstBus *bus;
+  int i;
+  GstMapInfo map;
+
+  wavpackdec = setup_wavpackdec ();
+  bus = gst_bus_new ();
+
+  inbuffer = gst_buffer_new_and_alloc (sizeof (test_frame));
+  gst_buffer_fill (inbuffer, 0, test_frame, sizeof (test_frame));
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+
+  gst_element_set_bus (wavpackdec, bus);
+
+  /* should decode the buffer without problems */
+  fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
+
+  outbuffer = GST_BUFFER (buffers->data);
+
+  fail_if (outbuffer == NULL);
+
+  gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+
+  /* uncompressed data should be 102400 bytes */
+  fail_unless_equals_int (map.size, 51200);
+
+  /* and all bytes must be 0, i.e. silence */
+  for (i = 0; i < 51200; i++)
+    fail_unless_equals_int (map.data[i], 0);
+
+  gst_buffer_unmap (outbuffer, &map);
+
+  ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
+  gst_buffer_unref (outbuffer);
+  outbuffer = NULL;
+
+  g_list_free (buffers);
+  buffers = NULL;
+
+  gst_bus_set_flushing (bus, TRUE);
+  gst_element_set_bus (wavpackdec, NULL);
+  gst_object_unref (GST_OBJECT (bus));
+  cleanup_wavpackdec (wavpackdec);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_decode_frame_with_broken_header)
+{
+  GstElement *wavpackdec;
+  GstBuffer *inbuffer;
+  GstBus *bus;
+  GstMessage *message;
+
+  wavpackdec = setup_wavpackdec ();
+  bus = gst_bus_new ();
+
+  inbuffer = gst_buffer_new_and_alloc (sizeof (test_frame));
+  gst_buffer_fill (inbuffer, 0, test_frame, sizeof (test_frame));
+  /* break header */
+  gst_buffer_memset (inbuffer, 2, 'e', 1);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+
+  gst_element_set_bus (wavpackdec, bus);
+
+  /* should fail gracefully */
+  fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_ERROR);
+
+  fail_if ((message = gst_bus_pop (bus)) == NULL);
+  fail_unless_message_error (message, STREAM, DECODE);
+  gst_message_unref (message);
+
+  gst_element_set_bus (wavpackdec, NULL);
+  gst_object_unref (GST_OBJECT (bus));
+  cleanup_wavpackdec (wavpackdec);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_decode_frame_with_incomplete_frame)
+{
+  GstElement *wavpackdec;
+  GstBuffer *inbuffer;
+  GstBus *bus;
+  GstMessage *message;
+
+  wavpackdec = setup_wavpackdec ();
+  bus = gst_bus_new ();
+
+  inbuffer = gst_buffer_new_and_alloc (sizeof (test_frame) - 2);
+  gst_buffer_fill (inbuffer, 0, test_frame, sizeof (test_frame) - 2);
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+
+  gst_element_set_bus (wavpackdec, bus);
+
+  /* should fail gracefully */
+  fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_ERROR);
+
+  fail_if ((message = gst_bus_pop (bus)) == NULL);
+  fail_unless_message_error (message, STREAM, DECODE);
+  gst_message_unref (message);
+
+
+  gst_element_set_bus (wavpackdec, NULL);
+  gst_object_unref (GST_OBJECT (bus));
+  cleanup_wavpackdec (wavpackdec);
+}
+
+GST_END_TEST;
+
+static Suite *
+wavpackdec_suite (void)
+{
+  Suite *s = suite_create ("wavpackdec");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_decode_frame);
+  tcase_add_test (tc_chain, test_decode_frame_with_broken_header);
+  tcase_add_test (tc_chain, test_decode_frame_with_incomplete_frame);
+
+  return s;
+}
+
+GST_CHECK_MAIN (wavpackdec);
diff --git a/tests/check/elements/wavpackenc.c b/tests/check/elements/wavpackenc.c
new file mode 100644
index 0000000..6b2eea4
--- /dev/null
+++ b/tests/check/elements/wavpackenc.c
@@ -0,0 +1,182 @@
+/* GStreamer
+ *
+ * unit test for wavpackenc
+ *
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+static GstPad *mysrcpad, *mysinkpad;
+static GstBus *bus;
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+#define AUDIO_FORMAT "S32BE"
+#else
+#define AUDIO_FORMAT "S32LE"
+#endif
+
+#define RAW_CAPS_STRING "audio/x-raw, " \
+                        "format = (string) " AUDIO_FORMAT ", " \
+                        "layout = (string) interleaved, " \
+                        "channels = (int) 1, " \
+                        "rate = (int) 44100"
+
+#define WAVPACK_CAPS_STRING "audio/x-wavpack, " \
+                            "depth = (int) 32, " \
+                            "channels = (int) 1, " \
+                            "rate = (int) 44100, " \
+                            "framed = (boolean) true"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-wavpack, "
+        "depth = (int) 32, "
+        "channels = (int) 1, "
+        "rate = (int) 44100, " "framed = (boolean) true"));
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw, "
+        "format = (string) " AUDIO_FORMAT ", "
+        "layout = (string) interleaved, "
+        "channels = (int) 1, " "rate = (int) 44100"));
+
+static GstElement *
+setup_wavpackenc (void)
+{
+  GstElement *wavpackenc;
+
+  GST_DEBUG ("setup_wavpackenc");
+  wavpackenc = gst_check_setup_element ("wavpackenc");
+  mysrcpad = gst_check_setup_src_pad (wavpackenc, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (wavpackenc, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  fail_unless (gst_element_set_state (wavpackenc,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+  bus = gst_bus_new ();
+
+  gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test-silence"));
+
+  return wavpackenc;
+}
+
+static void
+cleanup_wavpackenc (GstElement * wavpackenc)
+{
+  GST_DEBUG ("cleanup_wavpackenc");
+
+  gst_bus_set_flushing (bus, TRUE);
+  gst_element_set_bus (wavpackenc, NULL);
+  gst_object_unref (GST_OBJECT (bus));
+
+  gst_element_set_state (wavpackenc, GST_STATE_NULL);
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (wavpackenc);
+  gst_check_teardown_sink_pad (wavpackenc);
+  gst_check_teardown_element (wavpackenc);
+}
+
+GST_START_TEST (test_encode_silence)
+{
+  GstSegment segment;
+  GstElement *wavpackenc;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  GstEvent *eos = gst_event_new_eos ();
+  int i, num_buffers;
+
+  wavpackenc = setup_wavpackenc ();
+
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+
+  inbuffer = gst_buffer_new_and_alloc (1000);
+  gst_buffer_memset (inbuffer, 0, 0, 1000);
+
+  caps = gst_caps_from_string (RAW_CAPS_STRING);
+  fail_unless (gst_pad_set_caps (mysrcpad, caps));
+  gst_caps_unref (caps);
+
+  gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment));
+
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+  gst_element_set_bus (wavpackenc, bus);
+
+  fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
+
+  fail_if (gst_pad_push_event (mysrcpad, eos) != TRUE);
+
+  /* check first buffer */
+  outbuffer = GST_BUFFER (buffers->data);
+
+  fail_if (outbuffer == NULL);
+
+  fail_unless_equals_int (GST_BUFFER_TIMESTAMP (outbuffer), 0);
+  fail_unless_equals_int (GST_BUFFER_DURATION (outbuffer), 5668934);
+
+  fail_unless (gst_buffer_memcmp (outbuffer, 0, "wvpk", 4) == 0,
+      "Failed to encode to valid Wavpack frames");
+
+  /* free all buffers */
+  num_buffers = g_list_length (buffers);
+
+  for (i = 0; i < num_buffers; ++i) {
+    outbuffer = GST_BUFFER (buffers->data);
+    fail_if (outbuffer == NULL);
+
+    buffers = g_list_remove (buffers, outbuffer);
+
+    gst_buffer_unref (outbuffer);
+    outbuffer = NULL;
+  }
+
+  g_list_free (buffers);
+  buffers = NULL;
+
+  cleanup_wavpackenc (wavpackenc);
+}
+
+GST_END_TEST;
+
+static Suite *
+wavpackenc_suite (void)
+{
+  Suite *s = suite_create ("wavpackenc");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_encode_silence);
+
+  return s;
+}
+
+GST_CHECK_MAIN (wavpackenc);
diff --git a/tests/check/elements/wavpackparse.c b/tests/check/elements/wavpackparse.c
new file mode 100644
index 0000000..6364ded
--- /dev/null
+++ b/tests/check/elements/wavpackparse.c
@@ -0,0 +1,234 @@
+/* GStreamer
+ *
+ * unit test for wavpackparse
+ *
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+static GstPad *mysrcpad, *mysinkpad;
+
+/* Wavpack file with 2 frames of silence */
+guint8 test_file[] = {
+  0x77, 0x76, 0x70, 0x6B, 0x62, 0x00, 0x00, 0x00,       /* first frame */
+  0x04, 0x04, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00,       /* include RIFF header */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
+  0x05, 0x18, 0x80, 0x04, 0xFF, 0xAF, 0x80, 0x60,
+  0x21, 0x16, 0x52, 0x49, 0x46, 0x46, 0x24, 0x90,
+  0x01, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D,
+  0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
+  0x01, 0x00, 0x44, 0xAC, 0x00, 0x00, 0x88, 0x58,
+  0x01, 0x00, 0x02, 0x00, 0x10, 0x00, 0x64, 0x61,
+  0x74, 0x61, 0x00, 0x90, 0x01, 0x00, 0x02, 0x00,
+  0x03, 0x00, 0x04, 0x00, 0x05, 0x03, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x65, 0x02, 0x00, 0x00,
+  0x00, 0x00, 0x8A, 0x02, 0x00, 0x00, 0xFF, 0x7F,
+  0x00, 0xE4,
+  0x77, 0x76, 0x70, 0x6B, 0x2E, 0x00, 0x00, 0x00,       /* second frame */
+  0x04, 0x04, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+  0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
+  0x05, 0x18, 0x80, 0x04, 0xFF, 0xAF, 0x80, 0x60,
+  0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x02,
+  0x00, 0x00, 0xFF, 0x7F, 0x00, 0xE4,
+};
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-wavpack, "
+        "depth = (int) 16, "
+        "channels = (int) 1, "
+        "rate = (int) 44100, " "framed = (boolean) TRUE"));
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-wavpack"));
+
+static GstElement *
+setup_wavpackparse (void)
+{
+  GstElement *wavpackparse;
+
+  GST_DEBUG ("setup_wavpackparse");
+
+  wavpackparse = gst_check_setup_element ("wavpackparse");
+  mysrcpad = gst_check_setup_src_pad (wavpackparse, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (wavpackparse, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+  gst_check_setup_events (mysrcpad, wavpackparse, NULL, GST_FORMAT_BYTES);
+
+  return wavpackparse;
+}
+
+static void
+cleanup_wavpackparse (GstElement * wavpackparse)
+{
+  GST_DEBUG ("cleanup_wavpackparse");
+  gst_element_set_state (wavpackparse, GST_STATE_NULL);
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (wavpackparse);
+  gst_check_teardown_sink_pad (wavpackparse);
+  gst_check_teardown_element (wavpackparse);
+}
+
+GST_START_TEST (test_parsing_valid_frames)
+{
+  GstElement *wavpackparse;
+  GstBuffer *inbuffer, *outbuffer;
+  int i, num_buffers;
+  GstFormat format = GST_FORMAT_TIME;
+  gint64 pos;
+
+  wavpackparse = setup_wavpackparse ();
+  fail_unless (gst_element_set_state (wavpackparse,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (sizeof (test_file));
+  gst_buffer_fill (inbuffer, 0, test_file, sizeof (test_file));
+
+  /* should decode the buffer without problems */
+  fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
+
+  /* inform of no further data */
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+
+  num_buffers = g_list_length (buffers);
+  /* should get 2 buffers, each one complete wavpack frame */
+  fail_unless_equals_int (num_buffers, 2);
+
+  for (i = 0; i < num_buffers; ++i) {
+    outbuffer = GST_BUFFER (buffers->data);
+    fail_if (outbuffer == NULL);
+
+    fail_unless (gst_buffer_memcmp (outbuffer, 0, "wvpk", 4) == 0,
+        "Buffer contains no Wavpack frame");
+    fail_unless_equals_int (GST_BUFFER_DURATION (outbuffer), 580498866);
+
+    switch (i) {
+      case 0:{
+        fail_unless_equals_int (GST_BUFFER_TIMESTAMP (outbuffer), 0);
+        break;
+      }
+      case 1:{
+        fail_unless_equals_int (GST_BUFFER_TIMESTAMP (outbuffer), 580498866);
+        break;
+      }
+    }
+
+    buffers = g_list_remove (buffers, outbuffer);
+
+    gst_buffer_unref (outbuffer);
+    outbuffer = NULL;
+  }
+
+  fail_unless (gst_element_query_position (wavpackparse, format, &pos),
+      "Position query failed");
+  fail_unless_equals_int64 (pos, 580498866 * 2);
+  fail_unless (gst_element_query_duration (wavpackparse, format, NULL),
+      "Duration query failed");
+
+  g_list_free (buffers);
+  buffers = NULL;
+
+  cleanup_wavpackparse (wavpackparse);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_parsing_invalid_first_header)
+{
+  GstElement *wavpackparse;
+  GstBuffer *inbuffer, *outbuffer;
+  int i, num_buffers;
+
+  wavpackparse = setup_wavpackparse ();
+  fail_unless (gst_element_set_state (wavpackparse,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  inbuffer = gst_buffer_new_and_alloc (sizeof (test_file));
+  gst_buffer_fill (inbuffer, 0, test_file, sizeof (test_file));
+  gst_buffer_memset (inbuffer, 0, 'k', 1);
+
+  /* should decode the buffer without problems */
+  fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
+
+  /* inform of no further data */
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+
+  num_buffers = g_list_length (buffers);
+
+  /* should get 1 buffers, the second non-broken one */
+  fail_unless_equals_int (num_buffers, 1);
+
+  for (i = 0; i < num_buffers; ++i) {
+    outbuffer = GST_BUFFER (buffers->data);
+    fail_if (outbuffer == NULL);
+
+    fail_unless (gst_buffer_memcmp (outbuffer, 0, "wvpk", 4) == 0,
+        "Buffer contains no Wavpack frame");
+    fail_unless_equals_int (GST_BUFFER_DURATION (outbuffer), 580498866);
+
+    switch (i) {
+      case 0:{
+        fail_unless_equals_int (GST_BUFFER_TIMESTAMP (outbuffer), 580498866);
+        break;
+      }
+    }
+
+    buffers = g_list_remove (buffers, outbuffer);
+
+    gst_buffer_unref (outbuffer);
+    outbuffer = NULL;
+  }
+
+  g_list_free (buffers);
+  buffers = NULL;
+
+  cleanup_wavpackparse (wavpackparse);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+wavpackparse_suite (void)
+{
+  Suite *s = suite_create ("wavpackparse");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_parsing_valid_frames);
+  tcase_add_test (tc_chain, test_parsing_invalid_first_header);
+
+  return s;
+}
+
+GST_CHECK_MAIN (wavpackparse);
diff --git a/tests/check/elements/wavparse.c b/tests/check/elements/wavparse.c
new file mode 100644
index 0000000..ac91106
--- /dev/null
+++ b/tests/check/elements/wavparse.c
@@ -0,0 +1,150 @@
+/* GStreamer WavParse unit tests
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/check/gstcheck.h>
+
+#define SIMPLE_WAV_PATH GST_TEST_FILES_PATH G_DIR_SEPARATOR_S "audiotestsrc.wav"
+
+static void
+do_test_simple_file (GstPadMode mode)
+{
+  GstStateChangeReturn ret;
+  GstElement *pipeline;
+  GstElement *src, *q = NULL;
+  GstElement *wavparse;
+  GstElement *fakesink;
+  GstMessage *msg;
+
+  pipeline = gst_pipeline_new ("testpipe");
+  src = gst_element_factory_make ("filesrc", NULL);
+  fail_if (src == NULL);
+  if (mode == GST_PAD_MODE_PUSH)
+    q = gst_element_factory_make ("queue", NULL);
+  wavparse = gst_element_factory_make ("wavparse", NULL);
+  fail_if (wavparse == NULL);
+  fakesink = gst_element_factory_make ("fakesink", NULL);
+  fail_if (fakesink == NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, wavparse, fakesink, q, NULL);
+
+  g_object_set (src, "location", SIMPLE_WAV_PATH, NULL);
+
+  if (mode == GST_PAD_MODE_PUSH)
+    fail_unless (gst_element_link_many (src, q, wavparse, fakesink, NULL));
+  else
+    fail_unless (gst_element_link_many (src, wavparse, fakesink, NULL));
+
+  ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  fail_unless_equals_int (ret, GST_STATE_CHANGE_ASYNC);
+
+  ret = gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
+  fail_unless_equals_int (ret, GST_STATE_CHANGE_SUCCESS);
+
+  msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipeline),
+      GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS | GST_MESSAGE_ERROR);
+
+  fail_unless_equals_string (GST_MESSAGE_TYPE_NAME (msg), "eos");
+
+  gst_message_unref (msg);
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+}
+
+GST_START_TEST (test_simple_file_pull)
+{
+  do_test_simple_file (TRUE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_simple_file_push)
+{
+  do_test_simple_file (FALSE);
+}
+
+GST_END_TEST;
+
+static void
+do_test_empty_file (gboolean can_activate_pull)
+{
+  GstStateChangeReturn ret1, ret2;
+  GstElement *pipeline;
+  GstElement *src;
+  GstElement *wavparse;
+  GstElement *fakesink;
+
+  /* Pull mode */
+  pipeline = gst_pipeline_new ("testpipe");
+  src = gst_element_factory_make ("fakesrc", NULL);
+  fail_if (src == NULL);
+  wavparse = gst_element_factory_make ("wavparse", NULL);
+  fail_if (wavparse == NULL);
+  fakesink = gst_element_factory_make ("fakesink", NULL);
+  fail_if (fakesink == NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, wavparse, fakesink, NULL);
+  g_object_set (src, "num-buffers", 0, "can-activate-pull", can_activate_pull,
+      NULL);
+
+  fail_unless (gst_element_link_many (src, wavparse, fakesink, NULL));
+
+  ret1 = gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  if (ret1 == GST_STATE_CHANGE_ASYNC)
+    ret2 = gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
+  else
+    ret2 = ret1;
+
+  /* should have gotten an error on the bus, no output to fakesink */
+  fail_unless_equals_int (ret2, GST_STATE_CHANGE_FAILURE);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+}
+
+GST_START_TEST (test_empty_file_pull)
+{
+  do_test_empty_file (TRUE);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_empty_file_push)
+{
+  do_test_empty_file (FALSE);
+}
+
+GST_END_TEST;
+
+static Suite *
+wavparse_suite (void)
+{
+  Suite *s = suite_create ("wavparse");
+  TCase *tc_chain = tcase_create ("wavparse");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_empty_file_pull);
+  tcase_add_test (tc_chain, test_empty_file_push);
+  tcase_add_test (tc_chain, test_simple_file_pull);
+  tcase_add_test (tc_chain, test_simple_file_push);
+  return s;
+}
+
+GST_CHECK_MAIN (wavparse)
diff --git a/tests/check/elements/y4menc.c b/tests/check/elements/y4menc.c
new file mode 100644
index 0000000..cfbdb27
--- /dev/null
+++ b/tests/check/elements/y4menc.c
@@ -0,0 +1,168 @@
+/* GStreamer
+ *
+ * unit test for y4menc
+ *
+ * Copyright (C) <2006> Mark Nauwelaerts <manauw@skynet.be>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+static GstPad *mysrcpad, *mysinkpad;
+
+#define VIDEO_CAPS_STRING "video/x-raw, " \
+                           "format = (string) I420, "\
+                           "width = (int) 384, " \
+                           "height = (int) 288, " \
+                           "framerate = (fraction) 25/1, " \
+                           "pixel-aspect-ratio = (fraction) 1/1"
+
+#define Y4M_CAPS_STRING "application/x-yuv4mpeg, " \
+                        "y4mversion = (int) 2"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (Y4M_CAPS_STRING));
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (VIDEO_CAPS_STRING));
+
+
+static GstElement *
+setup_y4menc (void)
+{
+  GstElement *y4menc;
+
+  GST_DEBUG ("setup_y4menc");
+  y4menc = gst_check_setup_element ("y4menc");
+  mysrcpad = gst_check_setup_src_pad (y4menc, &srctemplate);
+  mysinkpad = gst_check_setup_sink_pad (y4menc, &sinktemplate);
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return y4menc;
+}
+
+static void
+cleanup_y4menc (GstElement * y4menc)
+{
+  GST_DEBUG ("cleanup_y4menc");
+  gst_element_set_state (y4menc, GST_STATE_NULL);
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  gst_pad_set_active (mysinkpad, FALSE);
+  gst_check_teardown_src_pad (y4menc);
+  gst_check_teardown_sink_pad (y4menc);
+  gst_check_teardown_element (y4menc);
+}
+
+GST_START_TEST (test_y4m)
+{
+  GstElement *y4menc;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  int i, num_buffers, size;
+  const gchar *data0 = "YUV4MPEG2 W384 H288 Ip F25:1 A1:1\n";
+  const gchar *data1 = "YUV4MPEG2 C420 W384 H288 Ip F25:1 A1:1\n";
+  const gchar *data2 = "FRAME\n";
+
+  y4menc = setup_y4menc ();
+  fail_unless (gst_element_set_state (y4menc,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  /* corresponds to I420 buffer for the size mentioned in the caps */
+  size = 384 * 288 * 3 / 2;
+  inbuffer = gst_buffer_new_and_alloc (size);
+  /* makes valgrind's memcheck happier */
+  gst_buffer_memset (inbuffer, 0, 0, size);
+  caps = gst_caps_from_string (VIDEO_CAPS_STRING);
+  gst_check_setup_events (mysrcpad, y4menc, caps, GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+  GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+  ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+  fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+
+  num_buffers = g_list_length (buffers);
+  fail_unless (num_buffers == 1);
+
+  /* clean up buffers */
+  for (i = 0; i < num_buffers; ++i) {
+    GstMapInfo map;
+    gchar *data;
+    gsize outsize;
+
+    outbuffer = GST_BUFFER (buffers->data);
+    fail_if (outbuffer == NULL);
+
+    switch (i) {
+      case 0:
+        gst_buffer_map (outbuffer, &map, GST_MAP_READ);
+        outsize = map.size;
+        data = (gchar *) map.data;
+
+        fail_unless (outsize > size);
+        fail_unless (memcmp (data, data0, strlen (data0)) == 0 ||
+            memcmp (data, data1, strlen (data1)) == 0);
+        /* so we know there is a newline */
+        data = strchr (data, '\n');
+        fail_unless (data != NULL);
+        data++;
+        fail_unless (memcmp (data2, data, strlen (data2)) == 0);
+        data += strlen (data2);
+        /* remainder must be frame data */
+        fail_unless (data - (gchar *) map.data + size == outsize);
+        gst_buffer_unmap (outbuffer, &map);
+        break;
+      default:
+        break;
+    }
+    buffers = g_list_remove (buffers, outbuffer);
+
+    ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
+    gst_buffer_unref (outbuffer);
+    outbuffer = NULL;
+  }
+
+  cleanup_y4menc (y4menc);
+  g_list_free (buffers);
+  buffers = NULL;
+}
+
+GST_END_TEST;
+
+static Suite *
+y4menc_suite (void)
+{
+  Suite *s = suite_create ("y4menc");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_y4m);
+
+  return s;
+}
+
+GST_CHECK_MAIN (y4menc);
diff --git a/tests/check/generic/.gitignore b/tests/check/generic/.gitignore
new file mode 100644
index 0000000..8d9bd1f
--- /dev/null
+++ b/tests/check/generic/.gitignore
@@ -0,0 +1,3 @@
+.dirstamp
+index
+states
diff --git a/tests/check/generic/states.c b/tests/check/generic/states.c
new file mode 100644
index 0000000..f372e64
--- /dev/null
+++ b/tests/check/generic/states.c
@@ -0,0 +1,225 @@
+/* GStreamer
+ *
+ * unit test for state changes on all elements
+ *
+ * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <unistd.h>
+
+#include <gst/check/gstcheck.h>
+
+static GList *elements = NULL;
+
+static void
+setup (void)
+{
+  GList *features, *f;
+  GList *plugins, *p;
+  gchar **ignorelist = NULL;
+  const gchar *STATE_IGNORE_ELEMENTS = NULL;
+  GstRegistry *def;
+
+  GST_DEBUG ("getting elements for package %s", PACKAGE);
+  STATE_IGNORE_ELEMENTS = g_getenv ("GST_STATE_IGNORE_ELEMENTS");
+  if (!g_getenv ("GST_NO_STATE_IGNORE_ELEMENTS") && STATE_IGNORE_ELEMENTS) {
+    GST_DEBUG ("Will ignore element factories: '%s'", STATE_IGNORE_ELEMENTS);
+    ignorelist = g_strsplit (STATE_IGNORE_ELEMENTS, " ", 0);
+  }
+
+  def = gst_registry_get ();
+
+  plugins = gst_registry_get_plugin_list (def);
+
+  for (p = plugins; p; p = p->next) {
+    GstPlugin *plugin = p->data;
+
+    if (strcmp (gst_plugin_get_source (plugin), PACKAGE) != 0)
+      continue;
+
+    features =
+        gst_registry_get_feature_list_by_plugin (def,
+        gst_plugin_get_name (plugin));
+
+    for (f = features; f; f = f->next) {
+      GstPluginFeature *feature = f->data;
+      const gchar *name = gst_plugin_feature_get_name (feature);
+      gboolean ignore = FALSE;
+
+      if (!GST_IS_ELEMENT_FACTORY (feature))
+        continue;
+
+      if (ignorelist) {
+        gchar **s;
+
+        for (s = ignorelist; s && *s; ++s) {
+          if (g_str_has_prefix (name, *s)) {
+            GST_DEBUG ("ignoring element %s", name);
+            ignore = TRUE;
+          }
+        }
+        if (ignore)
+          continue;
+      }
+
+      GST_DEBUG ("adding element %s", name);
+      elements = g_list_prepend (elements, (gpointer) g_strdup (name));
+    }
+    gst_plugin_feature_list_free (features);
+  }
+  gst_plugin_list_free (plugins);
+  g_strfreev (ignorelist);
+}
+
+static void
+teardown (void)
+{
+  GList *e;
+
+  for (e = elements; e; e = e->next) {
+    g_free (e->data);
+  }
+  g_list_free (elements);
+  elements = NULL;
+}
+
+
+GST_START_TEST (test_state_changes_up_and_down_seq)
+{
+  GstElement *element;
+  GList *e;
+
+  for (e = elements; e; e = e->next) {
+    const gchar *name = e->data;
+
+    GST_INFO ("testing element %s", name);
+    element = gst_element_factory_make (name, name);
+    fail_if (element == NULL, "Could not make element from factory %s", name);
+
+    if (GST_IS_PIPELINE (element)) {
+      GST_DEBUG ("element %s is a pipeline", name);
+    }
+
+    gst_element_set_state (element, GST_STATE_READY);
+    gst_element_set_state (element, GST_STATE_PAUSED);
+    gst_element_set_state (element, GST_STATE_PLAYING);
+    gst_element_set_state (element, GST_STATE_PAUSED);
+    gst_element_set_state (element, GST_STATE_READY);
+    gst_element_set_state (element, GST_STATE_NULL);
+    gst_element_set_state (element, GST_STATE_PAUSED);
+    gst_element_set_state (element, GST_STATE_READY);
+    gst_element_set_state (element, GST_STATE_PLAYING);
+    gst_element_set_state (element, GST_STATE_PAUSED);
+    gst_element_set_state (element, GST_STATE_NULL);
+    gst_object_unref (GST_OBJECT (element));
+  }
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_state_changes_up_seq)
+{
+  GstElement *element;
+  GList *e;
+
+  for (e = elements; e; e = e->next) {
+    const gchar *name = e->data;
+
+    GST_INFO ("testing element %s", name);
+    element = gst_element_factory_make (name, name);
+    fail_if (element == NULL, "Could not make element from factory %s", name);
+
+    if (GST_IS_PIPELINE (element)) {
+      GST_DEBUG ("element %s is a pipeline", name);
+    }
+
+    gst_element_set_state (element, GST_STATE_READY);
+
+    gst_element_set_state (element, GST_STATE_PAUSED);
+    gst_element_set_state (element, GST_STATE_READY);
+
+    gst_element_set_state (element, GST_STATE_PAUSED);
+    gst_element_set_state (element, GST_STATE_PLAYING);
+    gst_element_set_state (element, GST_STATE_PAUSED);
+    gst_element_set_state (element, GST_STATE_READY);
+
+    gst_element_set_state (element, GST_STATE_NULL);
+    gst_object_unref (GST_OBJECT (element));
+  }
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_state_changes_down_seq)
+{
+  GstElement *element;
+  GList *e;
+
+  for (e = elements; e; e = e->next) {
+    const gchar *name = e->data;
+
+    GST_INFO ("testing element %s", name);
+    element = gst_element_factory_make (name, name);
+    fail_if (element == NULL, "Could not make element from factory %s", name);
+
+    if (GST_IS_PIPELINE (element)) {
+      GST_DEBUG ("element %s is a pipeline", name);
+    }
+
+    gst_element_set_state (element, GST_STATE_READY);
+    gst_element_set_state (element, GST_STATE_PAUSED);
+    gst_element_set_state (element, GST_STATE_PLAYING);
+
+    gst_element_set_state (element, GST_STATE_PAUSED);
+    gst_element_set_state (element, GST_STATE_PLAYING);
+
+    gst_element_set_state (element, GST_STATE_PAUSED);
+    gst_element_set_state (element, GST_STATE_READY);
+    gst_element_set_state (element, GST_STATE_PAUSED);
+    gst_element_set_state (element, GST_STATE_PLAYING);
+
+    gst_element_set_state (element, GST_STATE_PAUSED);
+    gst_element_set_state (element, GST_STATE_READY);
+    gst_element_set_state (element, GST_STATE_NULL);
+    gst_object_unref (GST_OBJECT (element));
+  }
+}
+
+GST_END_TEST;
+
+
+static Suite *
+states_suite (void)
+{
+  Suite *s = suite_create ("states_good");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_checked_fixture (tc_chain, setup, teardown);
+  tcase_add_test (tc_chain, test_state_changes_up_and_down_seq);
+  tcase_add_test (tc_chain, test_state_changes_up_seq);
+  tcase_add_test (tc_chain, test_state_changes_down_seq);
+
+  return s;
+}
+
+GST_CHECK_MAIN (states);
diff --git a/tests/check/gst-plugins-good.supp b/tests/check/gst-plugins-good.supp
new file mode 100644
index 0000000..a95988e
--- /dev/null
+++ b/tests/check/gst-plugins-good.supp
@@ -0,0 +1,165 @@
+{
+   <several valgrind warnings as found with libjpeg 6b on Debian>
+   Memcheck:Cond
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   fun:jpeg_finish_decompress
+}
+
+{
+   <several valgrind warnings as found with libjpeg 6b on Debian>
+   Memcheck:Cond
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   fun:jpeg_consume_input
+   fun:jpeg_read_header
+}
+
+{
+   <several valgrind warnings as found with libjpeg 6b on Debian>
+   Memcheck:Cond
+   fun:jpeg_fill_bit_buffer
+   fun:jpeg_huff_decode
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   fun:jpeg_read_raw_data
+}
+
+{
+   <several valgrind warnings as found with libjpeg 6b on Debian>
+   Memcheck:Cond
+   fun:jpeg_fill_bit_buffer
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   fun:jpeg_read_raw_data
+}
+
+{
+   <several valgrind warnings as found with libjpeg 6b on Debian>
+   Memcheck:Cond
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   fun:jpeg_consume_input
+   fun:jpeg_read_header
+}
+
+{
+   <several valgrind warnings as found with libjpeg 6b on Debian>
+   Memcheck:Cond
+   obj:/usr/lib/libjpeg.so.*
+   fun:jpeg_finish_compress
+}
+
+{
+   <several valgrind warnings as found with libjpeg 6b on Debian>
+   Memcheck:Cond
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   fun:jpeg_finish_compress
+}
+
+{
+   <several valgrind warnings as found with libjpeg 6b on Debian>
+   Memcheck:Cond
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   fun:jpeg_finish_compress
+}
+
+{
+   <several valgrind warnings as found with libjpeg 6b on Debian>
+   Memcheck:Cond
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   fun:jpeg_write_raw_data
+}
+
+{
+   <several valgrind warnings as found with libjpeg 6b on Debian>
+   Memcheck:Cond
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   fun:jpeg_write_raw_data
+}
+
+{
+   <several valgrind warnings as found with libjpeg 6b on Debian>
+   Memcheck:Cond
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   fun:jpeg_write_raw_data
+}
+
+{
+   <several valgrind warnings as found with libjpeg 6b on Debian>
+   Memcheck:Cond
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   fun:jpeg_write_raw_data
+}
+
+{
+   <several valgrind warnings as found with libjpeg 6b on Debian>
+   Memcheck:Cond
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   fun:jinit_compress_master
+   fun:jpeg_start_compress
+}
+
+{
+   <several valgrind warnings as found with libjpeg 6b on Debian>
+   Memcheck:Cond
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   obj:/usr/lib/libjpeg.so.*
+   fun:jinit_compress_master
+   fun:jpeg_start_compress
+}
+
+{
+   <well known zlib bug>
+   Memcheck:Cond
+   fun:inflateReset2
+   fun:inflateInit2_
+   fun:png_create_read_struct_2
+   fun:png_create_read_struct
+}
+
+{
+   <apparent strtod bug when trying to parse "infinity" from "interleaved">
+   Memcheck:Addr8
+   fun:__GI___strncasecmp_l
+   fun:____strtod_l_internal
+   fun:gst_value_deserialize_double
+}
+
+## lame
+
+{
+   <lame Conditional jump or move depends on uninitialised values>
+   Memcheck:Cond
+   fun:L3psycho_anal_vbr
+   fun:lame_encode_mp3_frame
+   ...
+   fun:lame_encode_flush
+   fun:gst_lamemp3enc_sink_event
+}
+
+{
+   <twolame Conditional jump or move depends on uninitialised values>
+   Memcheck:Cond
+   ...
+   fun:psycho_3
+   fun:encode_frame
+}
+
diff --git a/tests/check/meson.build b/tests/check/meson.build
new file mode 100644
index 0000000..a005326
--- /dev/null
+++ b/tests/check/meson.build
@@ -0,0 +1,215 @@
+# FIXME: use dependency('valgrind') once we have a method to get the includes
+if cc.has_header('valgrind/valgrind.h')
+  cdata.set('HAVE_VALGRIND', 1)
+endif
+
+# internal helper lib for unit testing audio parsers
+libparser = static_library('libparser', 'elements/parser.c',
+  c_args : gst_plugins_good_args + ['-DGST_USE_UNSTABLE_API'],
+  include_directories : [configinc],
+  dependencies : [gstcheck_dep],
+  install : false)
+
+libparser_dep = declare_dependency(link_with : libparser,
+  dependencies : gstcheck_dep)
+
+# name, condition when to skip the test and extra dependencies
+good_tests = [
+  [ 'elements/audioamplify' ],
+  [ 'elements/audiochebband' ],
+  [ 'elements/audiocheblimit' ],
+  [ 'elements/audiodynamic' ],
+  [ 'elements/audioecho' ],
+  [ 'elements/audiofirfilter' ],
+  [ 'elements/audioiirfilter' ],
+  [ 'elements/audioinvert' ],
+  [ 'elements/audiopanorama' ],
+  [ 'elements/audiowsincband' ],
+  [ 'elements/audiowsinclimit' ],
+  [ 'elements/alphacolor' ],
+  [ 'elements/alpha' ],
+  [ 'elements/aacparse', false, [libparser_dep] ],
+  [ 'elements/ac3parse', false, [libparser_dep] ],
+  [ 'elements/amrparse', false, [libparser_dep] ],
+  [ 'elements/flacparse', false, [libparser_dep] ],
+  [ 'elements/mpegaudioparse', false, [libparser_dep] ],
+  [ 'elements/wavpackparse' ],
+  [ 'elements/autodetect' ],
+  [ 'elements/avimux' ],
+  [ 'elements/avisubtitle' ],
+  [ 'elements/capssetter' ],
+  [ 'elements/deinterlace' ],
+  [ 'elements/dtmf' ],
+  [ 'pipelines/flacdec', not flac_dep.found() ],
+  [ 'elements/flvdemux' ],
+  [ 'elements/flvmux' ],
+  [ 'elements/qtmux' ],
+  [ 'elements/qtdemux' ],
+  [ 'elements/mulawdec' ],
+  [ 'elements/mulawenc' ],
+  [ 'elements/gdkpixbufsink', not gdkpixbuf_dep.found(), [gdkpixbuf_dep] ],
+  [ 'elements/gdkpixbufoverlay', not gdkpixbuf_dep.found() ],
+  [ 'elements/icydemux' ],
+  [ 'elements/id3demux' ],
+  [ 'elements/imagefreeze' ],
+  [ 'elements/deinterleave' ],
+  [ 'elements/interleave' ],
+  [ 'elements/jpegdec', not jpeglib.found() ],
+  [ 'elements/jpegenc', not jpeglib.found() ],
+  [ 'elements/level' ],
+  [ 'elements/matroskademux' ],
+  [ 'elements/matroskamux' ],
+  [ 'elements/matroskaparse' ],
+  [ 'elements/mpg123audiodec', not mpg123_dep.found(),  [gstfft_dep]],
+  [ 'elements/multifile' ],
+  [ 'elements/splitmux' ],
+  [ 'elements/rganalysis' ],
+  [ 'elements/rglimiter' ],
+  [ 'elements/rgvolume' ],
+  [ 'elements/rtp-payloading' ],
+  [ 'elements/rtph261' ],
+  [ 'elements/rtph263' ],
+  [ 'elements/rtpvp9' ],
+  [ 'elements/rtpaux' ],
+  [ 'elements/rtpbin' ],
+  [ 'elements/rtpbin_buffer_list' ],
+  [ 'elements/rtpbundle' ],
+  [ 'elements/rtpcollision' ],
+  [ 'elements/rtpjitterbuffer' ],
+  [ 'elements/rtpmux' ],
+  [ 'elements/rtprtx' ],
+  [ 'elements/rtpsession' ],
+  [ 'elements/souphttpsrc', not libsoup_dep.found(), [libsoup_dep] ],
+  [ 'elements/spectrum' ],
+  [ 'elements/shapewipe' ],
+  [ 'elements/id3v2mux', not taglib_dep.found() ],
+  [ 'elements/apev2mux', not taglib_dep.found() ],
+  [ 'elements/udpsink' ],
+  [ 'elements/udpsrc' ],
+  [ 'elements/videobox' ],
+  [ 'elements/aspectratiocrop' ],
+  [ 'elements/videocrop' ],
+  [ 'elements/videofilter' ],
+  [ 'elements/videomixer' ],
+  [ 'elements/vp8enc', not vpx_dep.found() or not have_vp8_encoder ],
+  [ 'elements/vp8dec', not vpx_dep.found() or not have_vp8_decoder ],
+  [ 'elements/vp9enc', not vpx_dep.found() or not have_vp9_encoder ],
+  [ 'pipelines/lame', not lame_dep.found() ],
+  [ 'pipelines/wavenc' ],
+  [ 'elements/wavpackdec', not wavpack_dep.found() ],
+  [ 'elements/wavpackenc', not wavpack_dep.found() ],
+  [ 'pipelines/wavpack', not wavpack_dep.found() ],
+  [ 'elements/wavparse' ],
+  [ 'elements/y4menc' ],
+  [ 'pipelines/effectv' ],
+  [ 'elements/equalizer' ],
+  [ 'generic/states' ],
+  [ 'pipelines/simple-launch-lines' ],
+  [ 'pipelines/tagschecking' ],
+]
+
+# FIXME: valgrind elements/rtp-payloading - needs fixing
+# elements/videocrop should be disabled since it takes way too long in valgrind
+
+foo='''
+if HAVE_ORC
+check_orc = orc/deinterlace orc/videomixer orc/videobox
+else
+check_orc =
+endif
+'''
+
+test_defines = [
+  '-UG_DISABLE_ASSERT',
+  '-UG_DISABLE_CAST_CHECKS',
+  '-DGST_CHECK_TEST_ENVIRONMENT_BEACON="GST_PLUGIN_LOADING_WHITELIST"',
+  '-DGST_TEST_FILES_PATH="' + meson.current_source_dir() + '/../files"',
+  '-DGST_USE_UNSTABLE_API',
+]
+
+pluginsdirs = []
+if gst_dep.type_name() == 'pkgconfig'
+  pbase = dependency('gstreamer-plugins-base-' + api_version, required : false)
+  pluginsdirs = [gst_dep.get_pkgconfig_variable('pluginsdir'),
+                 pbase.get_pkgconfig_variable('pluginsdir')]
+endif
+
+# fake device drivers: we could run hardware element tests against dummy drivers
+# v4l2: vivo (part of normal kernel)
+#   modprobe vivo;
+#   gst-launch v4l2src device="/dev/video1" ! xvimagesink;
+#   rmmod vivo
+#
+# alsa: snd-dummy (part of normal alsa, not removable)
+#   modprobe snd-dummy;
+#   gst-launch alsasrc device="hw:2" ! fakesink
+#   gst-launch fakesrc ! alsasink device="hw:2"
+#
+# need a way to figure out value for the device property
+state_ignore_elements = '''aasink autoaudiosrc autoaudiosink autovideosrc
+ autovideosink cacasink cairotextoverlay jackaudiosrc jackaudiosink
+ osssrc osssink osxaudiosink osxaudiosrc osxvideosrc osxvideosink
+ pulsesink pulsesrc pulsemixer v4l2src'''
+
+# FIXME: check, also + PTHREAD_CFLAGS
+test_deps = [gst_dep, gstbase_dep, gstnet_dep, gstcheck_dep, gstaudio_dep,
+  gstvideo_dep, gstpbutils_dep, gstrtp_dep, gstrtsp_dep, gsttag_dep,
+  gstapp_dep, gio_dep] + glib_deps
+
+# FIXME: add valgrind suppression common/gst.supp gst-plugins-good.supp
+foreach t : good_tests
+  fname = '@0@.c'.format(t.get(0))
+  test_name = t.get(0).underscorify()
+  extra_deps = [ ]
+  if t.length() == 3
+    extra_deps = t.get(2)
+    skip_test = t.get(1)
+  elif t.length() == 2
+    skip_test = t.get(1)
+  else
+    skip_test = false
+  endif
+  if not skip_test
+    env = environment()
+    env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '')
+    env.set('GST_STATE_IGNORE_ELEMENTS', state_ignore_elements)
+    env.set('CK_DEFAULT_TIMEOUT', '20')
+    env.set('GST_PLUGIN_LOADING_WHITELIST', 'gstreamer', 'gst-plugins-base',
+      'gst-plugins-good@' + meson.build_root(), separator: ':')
+    env.set('GST_PLUGIN_PATH_1_0', [meson.build_root()] + pluginsdirs)
+    env.set('GSETTINGS_BACKEND', 'memory')
+
+    env.set('GST_REGISTRY', '@0@/@1@.registry'.format(meson.current_build_dir(), test_name))
+    exe = executable(test_name, fname,
+      include_directories : [configinc],
+      c_args : ['-DHAVE_CONFIG_H=1' ] + test_defines,
+      dependencies : [libm] + test_deps + extra_deps,
+    )
+    test(test_name, exe, env: env, timeout: 3 * 60)
+  endif
+endforeach
+
+# FIXME: orc tests
+fixme_orc_tests='''
+orc_deinterlace_CFLAGS = $(ORC_CFLAGS)
+orc_deinterlace_LDADD = $(ORC_LIBS) -lorc-test-0.4
+nodist_orc_deinterlace_SOURCES = orc/deinterlace.c
+orc_videomixer_CFLAGS = $(ORC_CFLAGS)
+orc_videomixer_LDADD = $(ORC_LIBS) -lorc-test-0.4
+nodist_orc_videomixer_SOURCES = orc/videomixer.c
+orc_videobox_CFLAGS = $(ORC_CFLAGS)
+orc_videobox_LDADD = $(ORC_LIBS) -lorc-test-0.4
+nodist_orc_videobox_SOURCES = orc/videobox.c
+
+orc/deinterlace.c: $(top_srcdir)/gst/deinterlace/tvtime.orc
+	$(MKDIR_P) orc/
+	$(ORCC) --test -o $@ $<
+
+orc/videomixer.c: $(top_srcdir)/gst/videomixer/videomixerorc.orc
+	$(MKDIR_P) orc/
+	$(ORCC) --test -o $@ $<
+
+orc/videobox.c: $(top_srcdir)/gst/videobox/gstvideoboxorc.orc
+	$(MKDIR_P) orc/
+	$(ORCC) --test -o $@ $<
+'''
diff --git a/tests/check/pipelines/.gitignore b/tests/check/pipelines/.gitignore
new file mode 100644
index 0000000..2770eda
--- /dev/null
+++ b/tests/check/pipelines/.gitignore
@@ -0,0 +1,10 @@
+.dirstamp
+effectv
+flacdec
+lame
+twolame
+simple-launch-lines
+tagschecking
+wavenc
+wavpack
+*.check.xml
diff --git a/tests/check/pipelines/effectv.c b/tests/check/pipelines/effectv.c
new file mode 100644
index 0000000..a14806e
--- /dev/null
+++ b/tests/check/pipelines/effectv.c
@@ -0,0 +1,147 @@
+/* GStreamer
+ *
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <string.h>
+
+typedef struct
+{
+  GMainLoop *loop;
+  gboolean eos;
+} OnMessageUserData;
+
+static void
+on_message_cb (GstBus * bus, GstMessage * message, gpointer user_data)
+{
+  OnMessageUserData *d = user_data;
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_ERROR:
+    case GST_MESSAGE_WARNING:
+      g_assert_not_reached ();
+      break;
+    case GST_MESSAGE_EOS:
+      g_main_loop_quit (d->loop);
+      d->eos = TRUE;
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+run_test (const gchar * pipeline_string)
+{
+  GstElement *pipeline;
+  GstBus *bus;
+  GMainLoop *loop;
+  OnMessageUserData omud = { NULL, };
+  GstStateChangeReturn ret;
+
+  GST_DEBUG ("Testing pipeline '%s'", pipeline_string);
+
+  pipeline = gst_parse_launch (pipeline_string, NULL);
+  fail_unless (pipeline != NULL);
+  g_object_set (G_OBJECT (pipeline), "async-handling", TRUE, NULL);
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  bus = gst_element_get_bus (pipeline);
+  fail_unless (bus != NULL);
+  gst_bus_add_signal_watch (bus);
+
+  omud.loop = loop;
+  omud.eos = FALSE;
+
+  g_signal_connect (bus, "message", (GCallback) on_message_cb, &omud);
+
+
+  ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  fail_unless (ret == GST_STATE_CHANGE_SUCCESS
+      || ret == GST_STATE_CHANGE_ASYNC);
+
+  g_main_loop_run (loop);
+
+  fail_unless (gst_element_set_state (pipeline,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
+
+  fail_unless (omud.eos == TRUE);
+
+  gst_bus_remove_signal_watch (bus);
+  gst_object_unref (bus);
+  gst_object_unref (pipeline);
+  g_main_loop_unref (loop);
+}
+
+#define CREATE_TEST(element) \
+GST_START_TEST (test_##element) \
+{ \
+  gchar *pipeline; \
+  \
+  pipeline = g_strdup_printf ("videotestsrc num-buffers=100 ! " \
+      "videoconvert ! " \
+      " %s ! " \
+      " fakesink", #element); \
+  \
+  run_test (pipeline); \
+  g_free (pipeline); \
+} \
+\
+GST_END_TEST;
+
+CREATE_TEST (agingtv);
+CREATE_TEST (dicetv);
+CREATE_TEST (edgetv);
+CREATE_TEST (optv);
+CREATE_TEST (quarktv);
+CREATE_TEST (radioactv);
+CREATE_TEST (revtv);
+CREATE_TEST (rippletv);
+CREATE_TEST (shagadelictv);
+CREATE_TEST (streaktv);
+CREATE_TEST (vertigotv);
+CREATE_TEST (warptv);
+
+static Suite *
+effectv_suite (void)
+{
+  Suite *s = suite_create ("effectv");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_set_timeout (tc_chain, 180);
+
+  tcase_add_test (tc_chain, test_agingtv);
+  tcase_add_test (tc_chain, test_dicetv);
+  tcase_add_test (tc_chain, test_edgetv);
+  tcase_add_test (tc_chain, test_optv);
+  tcase_add_test (tc_chain, test_quarktv);
+  tcase_add_test (tc_chain, test_radioactv);
+  tcase_add_test (tc_chain, test_revtv);
+  tcase_add_test (tc_chain, test_rippletv);
+  tcase_add_test (tc_chain, test_shagadelictv);
+  tcase_add_test (tc_chain, test_streaktv);
+  tcase_add_test (tc_chain, test_vertigotv);
+  tcase_add_test (tc_chain, test_warptv);
+
+  return s;
+}
+
+GST_CHECK_MAIN (effectv);
diff --git a/tests/check/pipelines/flacdec.c b/tests/check/pipelines/flacdec.c
new file mode 100644
index 0000000..651d77f
--- /dev/null
+++ b/tests/check/pipelines/flacdec.c
@@ -0,0 +1,256 @@
+/* GStreamer
+ * Copyright (C) 2009 Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/audio/audio.h>
+#include <glib/gstdio.h>
+
+static guint16
+_get_first_sample (GstSample * sample)
+{
+  GstAudioInfo info;
+  GstCaps *caps;
+  GstBuffer *buf;
+  GstMapInfo map;
+  guint16 res;
+
+  fail_unless (sample != NULL, "NULL sample");
+
+  caps = gst_sample_get_caps (sample);
+  fail_unless (caps != NULL, "sample without caps");
+
+  buf = gst_sample_get_buffer (sample);
+  GST_DEBUG ("buffer with size=%" G_GSIZE_FORMAT ", caps=%" GST_PTR_FORMAT,
+      gst_buffer_get_size (buf), caps);
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  /* log buffer details */
+  GST_MEMDUMP ("buffer data from decoder", map.data, map.size);
+
+  /* make sure it's the format we expect */
+  fail_unless (gst_audio_info_from_caps (&info, caps));
+
+  fail_unless_equals_int (GST_AUDIO_INFO_WIDTH (&info), 16);
+  fail_unless_equals_int (GST_AUDIO_INFO_DEPTH (&info), 16);
+  fail_unless_equals_int (GST_AUDIO_INFO_RATE (&info), 44100);
+  fail_unless_equals_int (GST_AUDIO_INFO_CHANNELS (&info), 1);
+
+  if (GST_AUDIO_INFO_IS_LITTLE_ENDIAN (&info))
+    res = GST_READ_UINT16_LE (map.data);
+  else
+    res = GST_READ_UINT16_BE (map.data);
+
+  gst_buffer_unmap (buf, &map);
+
+  return res;
+}
+
+GST_START_TEST (test_decode)
+{
+  GstElement *pipeline;
+  GstElement *appsink;
+  GstSample *sample = NULL;
+  guint16 first_sample = 0;
+  guint size = 0;
+  gchar *path =
+      g_build_filename (GST_TEST_FILES_PATH, "audiotestsrc.flac", NULL);
+  gchar *pipe_desc =
+      g_strdup_printf
+      ("filesrc location=\"%s\" ! flacparse ! flacdec ! appsink name=sink",
+      path);
+
+  pipeline = gst_parse_launch (pipe_desc, NULL);
+  fail_unless (pipeline != NULL);
+
+  g_free (path);
+  g_free (pipe_desc);
+
+  appsink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
+  fail_unless (appsink != NULL);
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  do {
+    g_signal_emit_by_name (appsink, "pull-sample", &sample);
+    if (sample == NULL)
+      break;
+    if (first_sample == 0)
+      first_sample = _get_first_sample (sample);
+
+    size += gst_buffer_get_size (gst_sample_get_buffer (sample));
+
+    gst_sample_unref (sample);
+    sample = NULL;
+  }
+  while (TRUE);
+
+  /* audiotestsrc with samplesperbuffer 1024 and 10 num-buffers */
+  fail_unless_equals_int (size, 20480);
+  fail_unless_equals_int (first_sample, 0x066a);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  g_object_unref (pipeline);
+  g_object_unref (appsink);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_decode_seek_full)
+{
+  GstElement *pipeline;
+  GstElement *appsink;
+  GstEvent *event;
+  GstSample *sample = NULL;
+  guint16 first_sample = 0;
+  guint size = 0;
+  gchar *path =
+      g_build_filename (GST_TEST_FILES_PATH, "audiotestsrc.flac", NULL);
+  gchar *pipe_desc =
+      g_strdup_printf
+      ("filesrc location=\"%s\" ! flacparse ! flacdec ! appsink name=sink",
+      path);
+
+  pipeline = gst_parse_launch (pipe_desc, NULL);
+  fail_unless (pipeline != NULL);
+
+  g_free (pipe_desc);
+  g_free (path);
+
+  appsink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
+  fail_unless (appsink != NULL);
+
+  gst_element_set_state (pipeline, GST_STATE_PAUSED);
+  gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
+
+  /* do a seek that should give us the complete output */
+  event = gst_event_new_seek (1.0, GST_FORMAT_DEFAULT, GST_SEEK_FLAG_FLUSH,
+      GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, 20480);
+  fail_unless (gst_element_send_event (appsink, event));
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  do {
+    g_signal_emit_by_name (appsink, "pull-sample", &sample);
+    if (sample == NULL)
+      break;
+    if (first_sample == 0)
+      first_sample = _get_first_sample (sample);
+    size += gst_buffer_get_size (gst_sample_get_buffer (sample));
+
+    gst_sample_unref (sample);
+    sample = NULL;
+  }
+  while (TRUE);
+
+  /* file was generated with audiotestsrc
+   * with 1024 samplesperbuffer and 10 num-buffers in 16 bit audio */
+  fail_unless_equals_int (size, 20480);
+  fail_unless_equals_int (first_sample, 0x066a);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  g_object_unref (pipeline);
+  g_object_unref (appsink);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_decode_seek_partial)
+{
+  GstElement *pipeline;
+  GstElement *appsink;
+  GstEvent *event;
+  GstSample *sample = NULL;
+  guint size = 0;
+  guint16 first_sample = 0;
+  gchar *path =
+      g_build_filename (GST_TEST_FILES_PATH, "audiotestsrc.flac", NULL);
+  gchar *pipe_desc =
+      g_strdup_printf
+      ("filesrc location=\"%s\" ! flacparse ! flacdec ! appsink name=sink",
+      path);
+
+  pipeline = gst_parse_launch (pipe_desc, NULL);
+  fail_unless (pipeline != NULL);
+
+  g_free (path);
+  g_free (pipe_desc);
+
+  appsink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
+  fail_unless (appsink != NULL);
+
+  gst_element_set_state (pipeline, GST_STATE_PAUSED);
+  gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
+
+  /* do a partial seek to get the first 1024 samples or 2048 bytes */
+  event = gst_event_new_seek (1.0, GST_FORMAT_DEFAULT, GST_SEEK_FLAG_FLUSH,
+      GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, 1024);
+  GST_DEBUG ("seeking");
+  fail_unless (gst_element_send_event (appsink, event));
+  GST_DEBUG ("seeked");
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  do {
+    GST_DEBUG ("pulling sample");
+    g_signal_emit_by_name (appsink, "pull-sample", &sample);
+    GST_DEBUG ("pulled sample %p", sample);
+    if (sample == NULL)
+      break;
+    if (first_sample == 0) {
+      first_sample = _get_first_sample (sample);
+    }
+    size += gst_buffer_get_size (gst_sample_get_buffer (sample));
+
+    gst_sample_unref (sample);
+    sample = NULL;
+  }
+  while (TRUE);
+
+  /* allow for sample round-up clipping effect */
+  fail_unless (size == 2048 || size == 2050);
+  fail_unless_equals_int (first_sample, 0x066a);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  g_object_unref (pipeline);
+  g_object_unref (appsink);
+}
+
+GST_END_TEST;
+
+static Suite *
+flacdec_suite (void)
+{
+  Suite *s = suite_create ("flacdec");
+
+  TCase *tc_chain = tcase_create ("linear");
+
+  /* time out after 60s, not the default 3 */
+  tcase_set_timeout (tc_chain, 60);
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_decode);
+  tcase_add_test (tc_chain, test_decode_seek_full);
+  tcase_add_test (tc_chain, test_decode_seek_partial);
+
+  return s;
+}
+
+GST_CHECK_MAIN (flacdec);
diff --git a/tests/check/pipelines/lame.c b/tests/check/pipelines/lame.c
new file mode 100644
index 0000000..8bba66a
--- /dev/null
+++ b/tests/check/pipelines/lame.c
@@ -0,0 +1,131 @@
+/* GStreamer
+ *
+ * unit test for lame
+ *
+ * Copyright (C) 2007 Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/check/gstbufferstraw.h>
+
+#ifndef ENCODER
+#define ENCODER "lamemp3enc"
+#endif
+
+#ifndef GST_DISABLE_PARSE
+
+GST_START_TEST (test_format)
+{
+  GstElement *bin;
+  GstPad *pad;
+  gchar *pipe_str;
+  GstBuffer *buffer;
+  GError *error = NULL;
+
+  pipe_str = g_strdup_printf ("audiotestsrc num-buffers=1 "
+      "! audio/x-raw, rate=22050, channels=1 "
+      "! " ENCODER " bitrate=24 ! audio/mpeg,rate=22050 ! fakesink");
+
+  bin = gst_parse_launch (pipe_str, &error);
+  fail_unless (bin != NULL, "Error parsing pipeline: %s",
+      error ? error->message : "(invalid error)");
+  g_free (pipe_str);
+
+  /* get the pad */
+  {
+    GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "fakesink0");
+
+    fail_unless (sink != NULL, "Could not get fakesink out of bin");
+    pad = gst_element_get_static_pad (sink, "sink");
+    fail_unless (pad != NULL, "Could not get pad out of fakesink");
+    gst_object_unref (sink);
+  }
+
+  gst_buffer_straw_start_pipeline (bin, pad);
+
+  buffer = gst_buffer_straw_get_buffer (bin, pad);
+
+  gst_buffer_straw_stop_pipeline (bin, pad);
+
+  gst_buffer_unref (buffer);
+  gst_object_unref (pad);
+  gst_object_unref (bin);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_caps_proxy)
+{
+  GstElement *bin;
+  GstPad *pad;
+  gchar *pipe_str;
+  GstBuffer *buffer;
+  GError *error = NULL;
+
+  pipe_str = g_strdup_printf ("audiotestsrc num-buffers=1 "
+      "! audio/x-raw,rate=48000,channels=1 "
+      "! audioresample "
+      "! " ENCODER " ! audio/mpeg,rate=(int){22050,44100} ! fakesink");
+
+  bin = gst_parse_launch (pipe_str, &error);
+  fail_unless (bin != NULL, "Error parsing pipeline: %s",
+      error ? error->message : "(invalid error)");
+  g_free (pipe_str);
+
+  /* get the pad */
+  {
+    GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "fakesink0");
+
+    fail_unless (sink != NULL, "Could not get fakesink out of bin");
+    pad = gst_element_get_static_pad (sink, "sink");
+    fail_unless (pad != NULL, "Could not get pad out of fakesink");
+    gst_object_unref (sink);
+  }
+
+  gst_buffer_straw_start_pipeline (bin, pad);
+
+  buffer = gst_buffer_straw_get_buffer (bin, pad);
+
+  gst_buffer_straw_stop_pipeline (bin, pad);
+
+  gst_buffer_unref (buffer);
+  gst_object_unref (pad);
+  gst_object_unref (bin);
+}
+
+GST_END_TEST;
+
+#endif /* #ifndef GST_DISABLE_PARSE */
+
+static Suite *
+lame_suite (void)
+{
+  Suite *s = suite_create (ENCODER);
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+
+#ifndef GST_DISABLE_PARSE
+  tcase_add_test (tc_chain, test_format);
+  tcase_add_test (tc_chain, test_caps_proxy);
+#endif
+
+  return s;
+}
+
+GST_CHECK_MAIN (lame);
diff --git a/tests/check/pipelines/simple-launch-lines.c b/tests/check/pipelines/simple-launch-lines.c
new file mode 100644
index 0000000..ed83511
--- /dev/null
+++ b/tests/check/pipelines/simple-launch-lines.c
@@ -0,0 +1,332 @@
+/* GStreamer
+ * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
+ *
+ * simple_launch_lines.c: Unit test for simple pipelines
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+
+#ifndef GST_DISABLE_PARSE
+
+static GstElement *
+setup_pipeline (const gchar * pipe_descr)
+{
+  GstElement *pipeline;
+
+  pipeline = gst_parse_launch (pipe_descr, NULL);
+  g_return_val_if_fail (GST_IS_PIPELINE (pipeline), NULL);
+  return pipeline;
+}
+
+/* 
+ * run_pipeline:
+ * @pipe: the pipeline to run
+ * @desc: the description for use in messages
+ * @events: is a mask of expected events
+ * @tevent: is the expected terminal event.
+ *
+ * the poll call will time out after half a second.
+ */
+static void
+run_pipeline (GstElement * pipe, const gchar * descr,
+    GstMessageType events, GstMessageType tevent, GstState target_state)
+{
+  GstBus *bus;
+  GstMessage *message;
+  GstMessageType revent;
+  GstStateChangeReturn ret;
+
+  g_assert (pipe);
+  bus = gst_element_get_bus (pipe);
+  g_assert (bus);
+
+  fail_if (gst_element_set_state (pipe, target_state) ==
+      GST_STATE_CHANGE_FAILURE, "Could not set pipeline %s to playing", descr);
+  ret = gst_element_get_state (pipe, NULL, NULL, 10 * GST_SECOND);
+  if (ret == GST_STATE_CHANGE_ASYNC) {
+    g_critical ("Pipeline '%s' failed to go to PAUSED fast enough", descr);
+    goto done;
+  } else if ((ret != GST_STATE_CHANGE_SUCCESS)
+      && (ret != GST_STATE_CHANGE_NO_PREROLL)) {
+    g_critical ("Pipeline '%s' failed to go into PAUSED state (%s)", descr,
+        gst_element_state_change_return_get_name (ret));
+    goto done;
+  }
+
+  while (1) {
+    message = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2);
+
+    /* always have to pop the message before getting back into poll */
+    if (message) {
+      revent = GST_MESSAGE_TYPE (message);
+      gst_message_unref (message);
+    } else {
+      revent = GST_MESSAGE_UNKNOWN;
+    }
+
+    if (revent == tevent) {
+      break;
+    } else if (revent == GST_MESSAGE_UNKNOWN) {
+      g_critical ("Unexpected timeout in gst_bus_poll, looking for %d: %s",
+          tevent, descr);
+      break;
+    } else if (revent & events) {
+      continue;
+    }
+    g_critical
+        ("Unexpected message received of type %d, '%s', looking for %d: %s",
+        revent, gst_message_type_get_name (revent), tevent, descr);
+  }
+
+done:
+  fail_if (gst_element_set_state (pipe, GST_STATE_NULL) ==
+      GST_STATE_CHANGE_FAILURE, "Could not set pipeline %s to NULL", descr);
+  gst_element_get_state (pipe, NULL, NULL, GST_CLOCK_TIME_NONE);
+  gst_object_unref (pipe);
+
+  gst_bus_set_flushing (bus, TRUE);
+  gst_object_unref (bus);
+}
+
+GST_START_TEST (test_rtp_payloaders)
+{
+  const gchar *s;
+
+  /* FIXME: going to playing would be nice, but thet leads to lot of failure */
+  GstState target_state = GST_STATE_PAUSED;
+
+  /* we use is-live here to avoid preroll */
+#define PIPELINE_STRING(bufcount, bufsize, pl, dpl) "fakesrc is-live=true num-buffers=" bufcount " filltype=2 sizetype=2 sizemax=" bufsize " ! " pl " ! " dpl " ! fakesink"
+#define DEFAULT_BUFCOUNT "5"
+#define DEFAULT_BUFSIZE "16"
+
+  s = PIPELINE_STRING (DEFAULT_BUFCOUNT, DEFAULT_BUFSIZE, "rtpilbcpay",
+      "rtpilbcdepay");
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, target_state);
+
+  s = PIPELINE_STRING (DEFAULT_BUFCOUNT, DEFAULT_BUFSIZE, "rtpgsmpay",
+      "rtpgsmdepay");
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, target_state);
+
+  /* This one needs a bit different buffer size than others or it doesn't work. */
+  s = PIPELINE_STRING (DEFAULT_BUFCOUNT, "52", "rtpamrpay", "rtpamrdepay");
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, target_state);
+
+  s = PIPELINE_STRING (DEFAULT_BUFCOUNT, DEFAULT_BUFSIZE, "rtppcmapay",
+      "rtppcmadepay");
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, target_state);
+
+  s = PIPELINE_STRING (DEFAULT_BUFCOUNT, DEFAULT_BUFSIZE, "rtppcmupay",
+      "rtppcmudepay");
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, target_state);
+
+  s = PIPELINE_STRING (DEFAULT_BUFCOUNT, DEFAULT_BUFSIZE, "rtpmpapay",
+      "rtpmpadepay");
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, target_state);
+
+  s = PIPELINE_STRING (DEFAULT_BUFCOUNT, DEFAULT_BUFSIZE, "rtph263ppay",
+      "rtph263pdepay");
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, target_state);
+
+  s = PIPELINE_STRING (DEFAULT_BUFCOUNT, DEFAULT_BUFSIZE, "rtph263pay",
+      "rtph263depay");
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, target_state);
+
+  s = PIPELINE_STRING (DEFAULT_BUFCOUNT, DEFAULT_BUFSIZE, "rtph264pay",
+      "rtph264depay");
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, target_state);
+
+  s = PIPELINE_STRING (DEFAULT_BUFCOUNT, DEFAULT_BUFSIZE, "rtpL16pay",
+      "rtpL16depay");
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, target_state);
+
+  s = PIPELINE_STRING (DEFAULT_BUFCOUNT, DEFAULT_BUFSIZE, "rtpmp2tpay",
+      "rtpmp2tdepay");
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, target_state);
+
+  s = PIPELINE_STRING (DEFAULT_BUFCOUNT, DEFAULT_BUFSIZE, "rtpmp4vpay",
+      "rtpmp4vdepay");
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, target_state);
+
+  s = PIPELINE_STRING (DEFAULT_BUFCOUNT, DEFAULT_BUFSIZE, "rtpmp4gpay",
+      "rtpmp4gdepay");
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, target_state);
+
+  /* Cannot be tested with fakesrc becouse speex payloader requires a valid header?! */
+  /*
+     s = PIPELINE_STRING(DEFAULT_BUFCOUNT, DEFAULT_BUFSIZE, "rtpspeexpay", "rtpspeexdepay");
+     run_pipeline (setup_pipeline (s), s,
+     GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+     GST_MESSAGE_UNKNOWN, target_state);
+   */
+
+  s = PIPELINE_STRING (DEFAULT_BUFCOUNT, DEFAULT_BUFSIZE, "rtptheorapay",
+      "rtptheoradepay");
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, target_state);
+
+  s = PIPELINE_STRING (DEFAULT_BUFCOUNT, DEFAULT_BUFSIZE, "rtpvorbispay",
+      "rtpvorbisdepay");
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, target_state);
+
+#define J2K_TEST_FILE_PATH GST_TEST_FILES_PATH G_DIR_SEPARATOR_S "gradient.j2k"
+#define J2KCAPS "image/x-jpc,sampling=YCbCr-4:2:0,width=720,height=576,pixel-aspect-ratio=1/1,framerate=30/1"
+  {
+    GstElement *pipeline, *src;
+    GstFlowReturn flow = GST_FLOW_OK;
+    GstBuffer *buf;
+    gchar *data;
+    gsize len;
+
+    s = "appsrc caps=" J2KCAPS " name=src ! rtpj2kpay ! rtpj2kdepay ! fakesink";
+
+    fail_unless (g_file_get_contents (J2K_TEST_FILE_PATH, &data, &len, NULL));
+    buf = gst_buffer_new_wrapped (data, len);
+    pipeline = setup_pipeline (s);
+    src = gst_bin_get_by_name (GST_BIN (pipeline), "src");
+    g_object_set (src, "format", GST_FORMAT_TIME, NULL);
+    g_signal_emit_by_name (src, "push-buffer", buf, &flow);
+    gst_buffer_unref (buf);
+    fail_unless_equals_int (flow, GST_FLOW_OK);
+    g_signal_emit_by_name (src, "end-of-stream", &flow);
+    gst_object_unref (src);
+    run_pipeline (pipeline, s,
+        GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+        GST_MESSAGE_UNKNOWN, target_state);
+  }
+
+  /*s = FAKESRC " ! ! rtpac3depay ! " FAKESINK */
+  /*s = FAKESRC " ! ! asteriskh263 ! " FAKESINK; */
+  /*s = FAKESRC " ! ! rtpmpvdepay ! " FAKESINK; */
+  /*s = FAKESRC " ! ! rtpmp4adepay ! " FAKESINK; */
+  /*s = FAKESRC " ! ! rtpsv3vdepay ! " FAKESINK; */
+}
+
+GST_END_TEST;
+
+static gboolean
+have_elements (const gchar * element1, const gchar * element2)
+{
+  return gst_registry_check_feature_version (gst_registry_get (), element1,
+      GST_VERSION_MAJOR, GST_VERSION_MINOR, 0) &&
+      gst_registry_check_feature_version (gst_registry_get (), element2,
+      GST_VERSION_MAJOR, GST_VERSION_MINOR, 0);
+}
+
+GST_START_TEST (test_video_encoders_decoders)
+{
+  const gchar *s;
+  GstState target_state = GST_STATE_PLAYING;
+
+  /* no is-live on the source because we actually want to preroll since
+   * run_pipeline only goes into PAUSED */
+#define ENC_DEC_PIPELINE_STRING(bufcount, enc, dec) "videotestsrc num-buffers=" bufcount " ! " enc " ! " dec " ! fakesink"
+#define DEFAULT_BUFCOUNT "5"
+
+  if (have_elements ("jpegenc", "jpegdec")) {
+    s = ENC_DEC_PIPELINE_STRING (DEFAULT_BUFCOUNT, "jpegenc", "jpegdec");
+    run_pipeline (setup_pipeline (s), s,
+        GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+        GST_MESSAGE_UNKNOWN, target_state);
+  }
+
+  if (have_elements ("pngenc", "pngdec")) {
+    s = ENC_DEC_PIPELINE_STRING (DEFAULT_BUFCOUNT, "pngenc", "pngdec");
+    run_pipeline (setup_pipeline (s), s,
+        GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+        GST_MESSAGE_UNKNOWN, target_state);
+  }
+
+  if (have_elements ("smokeenc", "smokedec")) {
+    s = ENC_DEC_PIPELINE_STRING (DEFAULT_BUFCOUNT, "smokeenc", "smokedec");
+    run_pipeline (setup_pipeline (s), s,
+        GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+        GST_MESSAGE_UNKNOWN, target_state);
+  }
+}
+
+GST_END_TEST;
+
+#define VIDEOMIXER_PIPELINE \
+    "videomixer name=mix  background=transparent ! fakesink " \
+    "videotestsrc num-buffers=50 ! " \
+    "  video/x-raw,format=RGBA, width=200,height=200,framerate=10/1  ! " \
+    "  videoconvert ! mix.sink_1 " \
+    "videotestsrc num-buffers=50 pattern=smpte ! " \
+    "  video/x-raw,format=RGBA, width=720,height=480,framerate=10/1  ! " \
+    "  videoconvert ! mix.sink_0 "
+
+GST_START_TEST (test_videomixer)
+{
+  run_pipeline (setup_pipeline (VIDEOMIXER_PIPELINE), VIDEOMIXER_PIPELINE,
+      GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING),
+      GST_MESSAGE_UNKNOWN, GST_STATE_PLAYING);
+}
+
+GST_END_TEST;
+
+#endif /* #ifndef GST_DISABLE_PARSE */
+static Suite *
+simple_launch_lines_suite (void)
+{
+  Suite *s = suite_create ("Pipelines");
+  TCase *tc_chain = tcase_create ("linear");
+
+  /* time out after 60s, not the default 3 */
+  tcase_set_timeout (tc_chain, 60);
+
+  suite_add_tcase (s, tc_chain);
+#ifndef GST_DISABLE_PARSE
+  tcase_add_test (tc_chain, test_rtp_payloaders);
+  tcase_add_test (tc_chain, test_video_encoders_decoders);
+  /* FIXME: very rarely fails, maybe because of negotiation issues? */
+  tcase_add_test (tc_chain, test_videomixer);
+#endif
+  return s;
+}
+
+GST_CHECK_MAIN (simple_launch_lines);
diff --git a/tests/check/pipelines/tagschecking.c b/tests/check/pipelines/tagschecking.c
new file mode 100644
index 0000000..8670bf9
--- /dev/null
+++ b/tests/check/pipelines/tagschecking.c
@@ -0,0 +1,361 @@
+/* GStreamer
+ * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>)
+ * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <glib/gstdio.h>
+
+static GstTagList *received_tags = NULL;
+
+static gboolean
+bus_handler (GstBus * bus, GstMessage * message, gpointer data)
+{
+  GMainLoop *loop = (GMainLoop *) data;
+
+  switch (message->type) {
+    case GST_MESSAGE_EOS:
+      g_main_loop_quit (loop);
+      break;
+    case GST_MESSAGE_WARNING:
+    case GST_MESSAGE_ERROR:{
+      GError *gerror;
+
+      gchar *debug;
+
+      gst_message_parse_error (message, &gerror, &debug);
+      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+      g_error_free (gerror);
+      g_free (debug);
+      g_main_loop_quit (loop);
+      break;
+    }
+    case GST_MESSAGE_TAG:{
+      if (received_tags == NULL) {
+        gst_message_parse_tag (message, &received_tags);
+      } else {
+        GstTagList *tl = NULL, *ntl = NULL;
+
+        gst_message_parse_tag (message, &tl);
+        if (tl) {
+          ntl = gst_tag_list_merge (received_tags, tl, GST_TAG_MERGE_PREPEND);
+          if (ntl) {
+            GST_LOG ("taglists merged: %" GST_PTR_FORMAT, ntl);
+            gst_tag_list_unref (received_tags);
+            received_tags = ntl;
+          }
+          gst_tag_list_unref (tl);
+        }
+      }
+      break;
+    }
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+/*
+ * Creates a pipeline in the form:
+ * fakesrc num-buffers=1 ! caps ! muxer ! filesink location=file
+ *
+ * And sets the tags in tag_str into the muxer via tagsetter.
+ */
+static void
+test_mux_tags (const gchar * tag_str, const gchar * caps,
+    const gchar * muxer, const gchar * file)
+{
+  GstElement *pipeline;
+  GstBus *bus;
+  GMainLoop *loop;
+  GstTagList *sent_tags;
+  GstElement *mux;
+  GstTagSetter *setter;
+  gchar *launch_str;
+  guint bus_watch = 0;
+
+  GST_DEBUG ("testing xmp muxing on : %s", muxer);
+
+  launch_str =
+      g_strdup_printf ("fakesrc num-buffers=1 format=time datarate=100 ! "
+      "%s ! %s name=mux ! filesink location=%s name=sink", caps, muxer, file);
+  pipeline = gst_parse_launch (launch_str, NULL);
+  g_free (launch_str);
+  fail_unless (pipeline != NULL);
+
+  mux = gst_bin_get_by_name (GST_BIN (pipeline), "mux");
+  fail_unless (mux != NULL);
+
+  loop = g_main_loop_new (NULL, TRUE);
+  fail_unless (loop != NULL);
+
+  bus = gst_element_get_bus (pipeline);
+  fail_unless (bus != NULL);
+  bus_watch = gst_bus_add_watch (bus, bus_handler, loop);
+  gst_object_unref (bus);
+
+  gst_element_set_state (pipeline, GST_STATE_READY);
+
+  setter = GST_TAG_SETTER (mux);
+  fail_unless (setter != NULL);
+  sent_tags = gst_tag_list_new_from_string (tag_str);
+  fail_unless (sent_tags != NULL);
+  gst_tag_setter_merge_tags (setter, sent_tags, GST_TAG_MERGE_REPLACE);
+  gst_tag_list_unref (sent_tags);
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  g_main_loop_run (loop);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  g_main_loop_unref (loop);
+  g_object_unref (mux);
+  g_object_unref (pipeline);
+  g_source_remove (bus_watch);
+}
+
+/*
+ * Makes a pipeline in the form:
+ * filesrc location=file ! demuxer ! fakesink
+ *
+ * And gets the tags that are posted on the bus to compare
+ * with the tags in 'tag_str'
+ */
+static void
+test_demux_tags (const gchar * tag_str, const gchar * demuxer,
+    const gchar * file)
+{
+  GstElement *pipeline;
+  GstBus *bus;
+  GMainLoop *loop;
+  GstTagList *sent_tags;
+  gint i, j, k, n_recv, n_sent;
+  const gchar *name_sent, *name_recv;
+  const GValue *value_sent, *value_recv;
+  gboolean found;
+  gint comparison;
+  GstElement *demux;
+  gchar *launch_str;
+  guint bus_watch = 0;
+
+  GST_DEBUG ("testing tags : %s", tag_str);
+
+  if (received_tags) {
+    gst_tag_list_unref (received_tags);
+    received_tags = NULL;
+  }
+
+  launch_str = g_strdup_printf ("filesrc location=%s ! %s name=demux ! "
+      "fakesink", file, demuxer);
+  pipeline = gst_parse_launch (launch_str, NULL);
+  g_free (launch_str);
+  fail_unless (pipeline != NULL);
+
+  demux = gst_bin_get_by_name (GST_BIN (pipeline), "demux");
+  fail_unless (demux != NULL);
+
+  loop = g_main_loop_new (NULL, TRUE);
+  fail_unless (loop != NULL);
+
+  bus = gst_element_get_bus (pipeline);
+  fail_unless (bus != NULL);
+  bus_watch = gst_bus_add_watch (bus, bus_handler, loop);
+  gst_object_unref (bus);
+
+  sent_tags = gst_tag_list_new_from_string (tag_str);
+  fail_unless (sent_tags != NULL);
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  g_main_loop_run (loop);
+
+  GST_DEBUG ("mainloop done : %p", received_tags);
+
+  /* verify tags */
+  fail_unless (received_tags != NULL);
+  n_recv = gst_tag_list_n_tags (received_tags);
+  n_sent = gst_tag_list_n_tags (sent_tags);
+  fail_unless (n_recv >= n_sent);
+  /* FIXME: compare taglits values */
+  for (i = 0; i < n_sent; i++) {
+    name_sent = gst_tag_list_nth_tag_name (sent_tags, i);
+
+    found = FALSE;
+    for (j = 0; j < n_recv; j++) {
+      name_recv = gst_tag_list_nth_tag_name (received_tags, j);
+
+      if (!strcmp (name_sent, name_recv)) {
+        guint sent_len, recv_len;
+
+        sent_len = gst_tag_list_get_tag_size (sent_tags, name_sent);
+        recv_len = gst_tag_list_get_tag_size (received_tags, name_recv);
+
+        fail_unless (sent_len == recv_len,
+            "tag item %s has been received with different size", name_sent);
+
+        for (k = 0; k < sent_len; k++) {
+          value_sent = gst_tag_list_get_value_index (sent_tags, name_sent, k);
+          value_recv =
+              gst_tag_list_get_value_index (received_tags, name_recv, k);
+
+          comparison = gst_value_compare (value_sent, value_recv);
+          if (comparison != GST_VALUE_EQUAL) {
+            gchar *vs = g_strdup_value_contents (value_sent);
+            gchar *vr = g_strdup_value_contents (value_recv);
+            GST_DEBUG ("sent = %s:'%s', recv = %s:'%s'",
+                G_VALUE_TYPE_NAME (value_sent), vs,
+                G_VALUE_TYPE_NAME (value_recv), vr);
+            g_free (vs);
+            g_free (vr);
+          }
+          fail_unless (comparison == GST_VALUE_EQUAL,
+              "tag item %s has been received with different type or value",
+              name_sent);
+          found = TRUE;
+          break;
+        }
+      }
+    }
+    fail_unless (found, "tag item %s is lost", name_sent);
+  }
+
+  gst_tag_list_unref (received_tags);
+  received_tags = NULL;
+  gst_tag_list_unref (sent_tags);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  g_main_loop_unref (loop);
+  g_object_unref (demux);
+  g_object_unref (pipeline);
+  g_source_remove (bus_watch);
+}
+
+/*
+ * Tests if the muxer/demuxer pair can serialize the tags in 'tag_str'
+ * to a file and recover them correctly.
+ *
+ * 'caps' are used to assure the muxer accepts the fake buffer fakesrc
+ * will send to it.
+ */
+static void
+test_tags (const gchar * tag_str, const gchar * caps, const gchar * muxer,
+    const gchar * demuxer)
+{
+  gchar *tmpfile;
+  gchar *tmpdir;
+
+  tmpdir = g_dir_make_tmp ("gst-check-good-XXXXXX", NULL);
+  fail_unless (tmpdir != NULL);
+  tmpfile = g_build_filename (tmpdir, "tagschecking-xmp", NULL);
+
+  GST_DEBUG ("testing tags : %s", tag_str);
+  test_mux_tags (tag_str, caps, muxer, tmpfile);
+  test_demux_tags (tag_str, demuxer, tmpfile);
+  g_unlink (tmpfile);
+  g_rmdir (tmpdir);
+  g_free (tmpfile);
+  g_free (tmpdir);
+}
+
+#define H264_CAPS "video/x-h264, width=(int)320, height=(int)240," \
+                  " framerate=(fraction)30/1, codec_data=(buffer)" \
+                  "01401592ffe10017674d401592540a0fd8088000000300" \
+                  "8000001e478b175001000468ee3c80, "\
+                  "stream-format=(string)avc, alignment=(string)au"
+
+#define COMMON_TAGS \
+    "taglist,title=test_title,"    \
+    "artist=test_artist,"          \
+    "keywords=\"key1,key2\","      \
+    "description=test_desc"
+
+GST_START_TEST (test_common_tags)
+{
+  if (!gst_registry_check_feature_version (gst_registry_get (), "qtdemux", 0,
+          10, 23)) {
+    GST_INFO ("Skipping test, qtdemux either not available or too old");
+    return;
+  }
+  test_tags (COMMON_TAGS, H264_CAPS, "qtmux", "qtdemux");
+  test_tags (COMMON_TAGS, H264_CAPS, "mp4mux", "qtdemux");
+  test_tags (COMMON_TAGS, H264_CAPS, "3gppmux", "qtdemux");
+}
+
+GST_END_TEST;
+
+#define GEO_LOCATION_TAGS \
+    "taglist,geo-location-country=Brazil,"    \
+      "geo-location-city=\"Campina Grande\"," \
+      "geo-location-sublocation=Bodocongo,"   \
+      "geo-location-latitude=-12.125,"        \
+      "geo-location-longitude=56.75,"         \
+      "geo-location-elevation=327.5"
+
+GST_START_TEST (test_geo_location_tags)
+{
+  if (!gst_registry_check_feature_version (gst_registry_get (), "qtdemux", 0,
+          10, 23)) {
+    GST_INFO ("Skipping test, qtdemux either not available or too old");
+    return;
+  }
+  test_tags (GEO_LOCATION_TAGS, H264_CAPS, "qtmux", "qtdemux");
+  test_tags (GEO_LOCATION_TAGS, H264_CAPS, "mp4mux", "qtdemux");
+  test_tags (GEO_LOCATION_TAGS, H264_CAPS, "3gppmux", "qtdemux");
+}
+
+GST_END_TEST;
+
+
+#define USER_TAGS \
+    "taglist,user-rating=(uint)85"
+
+GST_START_TEST (test_user_tags)
+{
+  if (!gst_registry_check_feature_version (gst_registry_get (), "qtdemux", 0,
+          10, 23)) {
+    GST_INFO ("Skipping test, qtdemux either not available or too old");
+    return;
+  }
+
+  test_tags (USER_TAGS, H264_CAPS, "qtmux", "qtdemux");
+  test_tags (USER_TAGS, H264_CAPS, "mp4mux", "qtdemux");
+  test_tags (USER_TAGS, H264_CAPS, "3gppmux", "qtdemux");
+}
+
+GST_END_TEST;
+
+static Suite *
+metadata_suite (void)
+{
+  Suite *s = suite_create ("tagschecking");
+
+  TCase *tc_chain = tcase_create ("general");
+
+  /* time out after 60s, not the default 3 */
+  tcase_set_timeout (tc_chain, 60);
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_common_tags);
+  tcase_add_test (tc_chain, test_geo_location_tags);
+  tcase_add_test (tc_chain, test_user_tags);
+
+  return s;
+}
+
+GST_CHECK_MAIN (metadata);
diff --git a/tests/check/pipelines/twolame.c b/tests/check/pipelines/twolame.c
new file mode 100644
index 0000000..752dcfc
--- /dev/null
+++ b/tests/check/pipelines/twolame.c
@@ -0,0 +1,22 @@
+/* GStreamer unit test for twolame
+ * Copyright (C) 2007 Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* pretty lame, I know */
+#define ENCODER "twolamemp2enc"
+#include "lame.c"
diff --git a/tests/check/pipelines/wavenc.c b/tests/check/pipelines/wavenc.c
new file mode 100644
index 0000000..1402ea2
--- /dev/null
+++ b/tests/check/pipelines/wavenc.c
@@ -0,0 +1,206 @@
+/* GStreamer
+ *
+ * unit test for wavenc
+ *
+ * Copyright (C) <2010> Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <gst/check/gstcheck.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/audio-enumtypes.h>
+
+static gboolean
+bus_handler (GstBus * bus, GstMessage * message, gpointer data)
+{
+  GMainLoop *loop = (GMainLoop *) data;
+
+  switch (message->type) {
+    case GST_MESSAGE_EOS:
+      g_main_loop_quit (loop);
+      break;
+    case GST_MESSAGE_WARNING:
+    case GST_MESSAGE_ERROR:{
+      GError *gerror;
+      gchar *debug;
+
+      gst_message_parse_error (message, &gerror, &debug);
+      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+      gst_message_unref (message);
+      g_error_free (gerror);
+      g_free (debug);
+      g_main_loop_quit (loop);
+      break;
+    }
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+/*
+ * gst-launch-1.0 \
+ * audiotestsrc freq=440 num-buffers=100 ! interleave name=i ! audioconvert ! wavenc ! filesink location=/tmp/mc.wav \
+ * audiotestsrc freq=880 num-buffers=100 ! i.
+ * ...
+ *
+ * http://www.microsoft.com/whdc/device/audio/multichaud.mspx
+ */
+
+static void
+make_n_channel_wav (const gint channels, const GValueArray * arr)
+{
+  GstElement *pipeline;
+  GstElement **audiotestsrc, *interleave, *wavenc, *conv, *fakesink;
+  GstBus *bus;
+  GMainLoop *loop;
+  guint i;
+  guint bus_watch = 0;
+
+  audiotestsrc = g_new0 (GstElement *, channels);
+
+  pipeline = gst_pipeline_new ("pipeline");
+  fail_unless (pipeline != NULL);
+
+  interleave = gst_element_factory_make ("interleave", NULL);
+  fail_unless (interleave != NULL);
+  g_object_set (interleave, "channel-positions", arr, NULL);
+  gst_bin_add (GST_BIN (pipeline), interleave);
+
+  if (G_BYTE_ORDER == G_BIG_ENDIAN) {
+    /* we're not here to test orc; audioconvert misbehaves on ppc32 */
+    g_setenv ("ORC_CODE", "backup", 1);
+    conv = gst_element_factory_make ("audioconvert", NULL);
+  } else {
+    conv = gst_element_factory_make ("identity", NULL);
+  }
+  fail_unless (conv != NULL);
+  gst_bin_add (GST_BIN (pipeline), conv);
+  fail_unless (gst_element_link (interleave, conv));
+
+  wavenc = gst_element_factory_make ("wavenc", NULL);
+  fail_unless (wavenc != NULL);
+  gst_bin_add (GST_BIN (pipeline), wavenc);
+  fail_unless (gst_element_link (conv, wavenc));
+
+  fakesink = gst_element_factory_make ("fakesink", NULL);
+  fail_unless (fakesink != NULL);
+  gst_bin_add (GST_BIN (pipeline), fakesink);
+  fail_unless (gst_element_link (wavenc, fakesink));
+
+  for (i = 0; i < channels; i++) {
+    audiotestsrc[i] = gst_element_factory_make ("audiotestsrc", NULL);
+    fail_unless (audiotestsrc[i] != NULL);
+    g_object_set (G_OBJECT (audiotestsrc[i]), "wave", 0, "freq",
+        440.0 * (i + 1), "num-buffers", 100, NULL);
+    gst_bin_add (GST_BIN (pipeline), audiotestsrc[i]);
+    fail_unless (gst_element_link (audiotestsrc[i], interleave));
+  }
+
+  loop = g_main_loop_new (NULL, TRUE);
+  fail_unless (loop != NULL);
+
+  bus = gst_element_get_bus (pipeline);
+  fail_unless (bus != NULL);
+  bus_watch = gst_bus_add_watch (bus, bus_handler, loop);
+  gst_object_unref (bus);
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  g_main_loop_run (loop);
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  gst_object_unref (pipeline);
+  g_free (audiotestsrc);
+
+  g_main_loop_unref (loop);
+  g_source_remove (bus_watch);
+}
+
+GST_START_TEST (test_encode_stereo)
+{
+  GValueArray *arr;
+  GValue val = { 0, };
+
+  arr = g_value_array_new (2);
+  g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION);
+  g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT);
+  g_value_array_append (arr, &val);
+  g_value_reset (&val);
+  g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT);
+  g_value_array_append (arr, &val);
+  g_value_unset (&val);
+
+  make_n_channel_wav (2, arr);
+  g_value_array_free (arr);
+}
+
+GST_END_TEST;
+
+#if 0
+GST_START_TEST (test_encode_multichannel)
+{
+  GValueArray *arr;
+  GValue val = { 0, };
+
+  arr = g_value_array_new (6);
+  g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION);
+  g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT);
+  g_value_array_append (arr, &val);
+  g_value_reset (&val);
+  g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT);
+  g_value_array_append (arr, &val);
+  g_value_reset (&val);
+  g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER);
+  g_value_array_append (arr, &val);
+  g_value_reset (&val);
+  g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_LFE);
+  g_value_array_append (arr, &val);
+  g_value_reset (&val);
+  g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT);
+  g_value_array_append (arr, &val);
+  g_value_reset (&val);
+  g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT);
+  g_value_array_append (arr, &val);
+  g_value_unset (&val);
+
+  make_n_channel_wav (6);
+}
+
+GST_END_TEST;
+#endif
+
+static Suite *
+wavenc_suite (void)
+{
+  Suite *s = suite_create ("wavenc");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_encode_stereo);
+  /* FIXME: improve wavenc
+     tcase_add_test (tc_chain, test_encode_multichannel);
+   */
+
+  return s;
+}
+
+GST_CHECK_MAIN (wavenc);
diff --git a/tests/check/pipelines/wavpack.c b/tests/check/pipelines/wavpack.c
new file mode 100644
index 0000000..de087b9
--- /dev/null
+++ b/tests/check/pipelines/wavpack.c
@@ -0,0 +1,205 @@
+/* GStreamer
+ * Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/base/gstadapter.h>
+
+static gboolean
+bus_handler (GstBus * bus, GstMessage * message, gpointer data)
+{
+  GMainLoop *loop = (GMainLoop *) data;
+
+  switch (message->type) {
+    case GST_MESSAGE_EOS:
+      g_main_loop_quit (loop);
+      break;
+    case GST_MESSAGE_WARNING:
+    case GST_MESSAGE_ERROR:{
+      GError *gerror;
+      gchar *debug;
+
+      gst_message_parse_error (message, &gerror, &debug);
+      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+      gst_message_unref (message);
+      g_error_free (gerror);
+      g_free (debug);
+      g_main_loop_quit (loop);
+      break;
+    }
+    case GST_MESSAGE_ELEMENT:
+    {
+      const GstStructure *s = gst_message_get_structure (message);
+
+      const gchar *name = gst_structure_get_name (s);
+
+      fail_unless (strcmp (name, "imperfect-timestamp") != 0);
+      fail_unless (strcmp (name, "imperfect-offset") != 0);
+      break;
+    }
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+static gboolean had_first_buffer = FALSE;
+
+static void
+identity_handoff (GstElement * object, GstBuffer * buffer, gpointer user_data)
+{
+  GstAdapter *adapter = GST_ADAPTER (user_data);
+
+  gst_adapter_push (adapter, gst_buffer_ref (buffer));
+}
+
+static void
+fakesink_handoff (GstElement * object, GstBuffer * buffer, GstPad * pad,
+    gpointer user_data)
+{
+  GstAdapter *adapter = GST_ADAPTER (user_data);
+
+  /* Don't allow the second buffer with offset=0 as it's the decoded
+   * rewrite of the first
+   */
+  if (had_first_buffer == FALSE && GST_BUFFER_OFFSET (buffer) == 0)
+    had_first_buffer = TRUE;
+  else if (GST_BUFFER_OFFSET (buffer) == 0)
+    return;
+
+  gst_adapter_push (adapter, gst_buffer_ref (buffer));
+}
+
+GST_START_TEST (test_encode_decode)
+{
+  GstElement *pipeline;
+  GstElement *audiotestsrc, *identity1, *wavpackenc, *identity2, *wavpackdec,
+      *identity3, *fakesink;
+  GstAdapter *srcadapter, *sinkadapter;
+  GstBus *bus;
+  GMainLoop *loop;
+  GstBuffer *in, *out;
+  guint bus_watch = 0;
+  GstMapInfo map;
+
+  srcadapter = gst_adapter_new ();
+  fail_unless (srcadapter != NULL);
+  sinkadapter = gst_adapter_new ();
+  fail_unless (sinkadapter != NULL);
+
+  pipeline = gst_pipeline_new ("pipeline");
+  fail_unless (pipeline != NULL);
+
+  audiotestsrc = gst_element_factory_make ("audiotestsrc", "src");
+  fail_unless (audiotestsrc != NULL);
+  g_object_set (G_OBJECT (audiotestsrc), "wave", 0, "freq", 440.0,
+      "num-buffers", 200, NULL);
+
+  identity1 = gst_element_factory_make ("identity", "identity1");
+  fail_unless (identity1 != NULL);
+  g_object_set (G_OBJECT (identity1), "signal-handoffs", TRUE, NULL);
+  g_signal_connect (G_OBJECT (identity1), "handoff",
+      G_CALLBACK (identity_handoff), srcadapter);
+
+  wavpackenc = gst_element_factory_make ("wavpackenc", "enc");
+  fail_unless (wavpackenc != NULL);
+
+  identity2 = gst_element_factory_make ("identity", "identity2");
+  fail_unless (identity2 != NULL);
+  g_object_set (G_OBJECT (identity2), "check-imperfect-timestamp", TRUE,
+      "check-imperfect-offset", TRUE, NULL);
+
+  wavpackdec = gst_element_factory_make ("wavpackdec", "dec");
+  fail_unless (wavpackdec != NULL);
+
+  identity3 = gst_element_factory_make ("identity", "identity3");
+  fail_unless (identity3 != NULL);
+  g_object_set (G_OBJECT (identity3), "check-imperfect-timestamp", TRUE,
+      "check-imperfect-offset", TRUE, NULL);
+
+  fakesink = gst_element_factory_make ("fakesink", "sink");
+  fail_unless (fakesink != NULL);
+  g_object_set (G_OBJECT (fakesink), "signal-handoffs", TRUE, NULL);
+  g_signal_connect (G_OBJECT (fakesink), "handoff",
+      G_CALLBACK (fakesink_handoff), sinkadapter);
+
+  gst_bin_add_many (GST_BIN (pipeline), audiotestsrc, identity1, wavpackenc,
+      identity2, wavpackdec, identity3, fakesink, NULL);
+
+  fail_unless (gst_element_link_many (audiotestsrc, identity1, wavpackenc,
+          identity2, wavpackdec, identity3, fakesink, NULL));
+
+  loop = g_main_loop_new (NULL, TRUE);
+  fail_unless (loop != NULL);
+
+  bus = gst_element_get_bus (pipeline);
+  fail_unless (bus != NULL);
+  bus_watch = gst_bus_add_watch (bus, bus_handler, loop);
+  gst_object_unref (bus);
+
+  had_first_buffer = FALSE;
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  g_main_loop_run (loop);
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  fail_unless (had_first_buffer == TRUE);
+  fail_unless (gst_adapter_available (srcadapter) > 0);
+  fail_unless (gst_adapter_available (sinkadapter) > 0);
+  fail_unless_equals_int (gst_adapter_available (srcadapter),
+      gst_adapter_available (sinkadapter));
+
+  in = gst_adapter_take_buffer (srcadapter, gst_adapter_available (srcadapter));
+  fail_unless (in != NULL);
+  out =
+      gst_adapter_take_buffer (sinkadapter,
+      gst_adapter_available (sinkadapter));
+  fail_unless (out != NULL);
+
+  fail_unless_equals_int (gst_buffer_get_size (in), gst_buffer_get_size (out));
+  gst_buffer_map (out, &map, GST_MAP_READ);
+  fail_unless (gst_buffer_memcmp (in, 0, map.data, map.size) == 0);
+  gst_buffer_unmap (out, &map);
+
+  gst_buffer_unref (in);
+  gst_buffer_unref (out);
+  g_object_unref (pipeline);
+  g_main_loop_unref (loop);
+  g_object_unref (srcadapter);
+  g_object_unref (sinkadapter);
+  g_source_remove (bus_watch);
+}
+
+GST_END_TEST;
+
+static Suite *
+wavpack_suite (void)
+{
+  Suite *s = suite_create ("Wavpack");
+  TCase *tc_chain = tcase_create ("linear");
+
+  /* time out after 60s, not the default 3 */
+  tcase_set_timeout (tc_chain, 60);
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_encode_decode);
+
+  return s;
+}
+
+GST_CHECK_MAIN (wavpack);
diff --git a/tests/examples/Makefile.am b/tests/examples/Makefile.am
new file mode 100644
index 0000000..7c10d02
--- /dev/null
+++ b/tests/examples/Makefile.am
@@ -0,0 +1,19 @@
+if USE_JACK
+JACK_DIR=jack
+else
+JACK_DIR=
+endif
+
+if USE_CAIRO
+CAIRO_DIR=cairo
+else
+CAIRO_DIR=
+endif
+
+SUBDIRS = audiofx equalizer $(JACK_DIR) level \
+	rtp shapewipe spectrum v4l2 $(CAIRO_DIR)
+
+DIST_SUBDIRS = audiofx equalizer jack level \
+	rtp shapewipe spectrum v4l2 cairo
+
+include $(top_srcdir)/common/parallel-subdirs.mak
diff --git a/tests/examples/audiofx/.gitignore b/tests/examples/audiofx/.gitignore
new file mode 100644
index 0000000..d0d56dc
--- /dev/null
+++ b/tests/examples/audiofx/.gitignore
@@ -0,0 +1,2 @@
+firfilter-example
+iirfilter-example
diff --git a/tests/examples/audiofx/Makefile.am b/tests/examples/audiofx/Makefile.am
new file mode 100644
index 0000000..e3c42c9
--- /dev/null
+++ b/tests/examples/audiofx/Makefile.am
@@ -0,0 +1,10 @@
+noinst_PROGRAMS = firfilter-example iirfilter-example
+
+# FIXME 0.11: ignore GValueArray warnings for now until this is sorted
+ERROR_CFLAGS=
+
+firfilter_example_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS)
+firfilter_example_LDADD = $(GST_LIBS) $(GST_PLUGINS_BASE_LIBS) -lgstfft-@GST_API_VERSION@ $(LIBM)
+
+iirfilter_example_CFLAGS = $(GST_CFLAGS)
+iirfilter_example_LDADD = $(GST_LIBS) $(LIBM)
diff --git a/tests/examples/audiofx/firfilter-example.c b/tests/examples/audiofx/firfilter-example.c
new file mode 100644
index 0000000..a3a6cfe
--- /dev/null
+++ b/tests/examples/audiofx/firfilter-example.c
@@ -0,0 +1,165 @@
+/* GStreamer
+ * Copyright (C) 2009 Sebastian Droege <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* This small sample application creates a bandpass FIR filter
+ * by transforming the frequency response to the filter kernel.
+ */
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <string.h>
+#include <math.h>
+
+#include <gst/gst.h>
+#include <gst/fft/gstfftf64.h>
+
+static gboolean
+on_message (GstBus * bus, GstMessage * message, gpointer user_data)
+{
+  GMainLoop *loop = (GMainLoop *) user_data;
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_ERROR:
+      g_error ("Got ERROR");
+      g_main_loop_quit (loop);
+      break;
+    case GST_MESSAGE_WARNING:
+      g_warning ("Got WARNING");
+      g_main_loop_quit (loop);
+      break;
+    case GST_MESSAGE_EOS:
+      g_main_loop_quit (loop);
+      break;
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+static void
+on_rate_changed (GstElement * element, gint rate, gpointer user_data)
+{
+  GValueArray *va;
+  GValue v = { 0, };
+  GstFFTF64 *fft;
+  GstFFTF64Complex frequency_response[17];
+  gdouble tmp[32];
+  gdouble filter_kernel[32];
+  guint i;
+
+  /* Create the frequency response: zero outside
+   * a small frequency band */
+  for (i = 0; i < 17; i++) {
+    if (i < 5 || i > 11)
+      frequency_response[i].r = 0.0;
+    else
+      frequency_response[i].r = 1.0;
+
+    frequency_response[i].i = 0.0;
+  }
+
+  /* Calculate the inverse FT of the frequency response */
+  fft = gst_fft_f64_new (32, TRUE);
+  gst_fft_f64_inverse_fft (fft, frequency_response, tmp);
+  gst_fft_f64_free (fft);
+
+  /* Shift the inverse FT of the frequency response by 16,
+   * i.e. the half of the kernel length to get the
+   * impulse response. See http://www.dspguide.com/ch17/1.htm
+   * for more information.
+   */
+  for (i = 0; i < 32; i++)
+    filter_kernel[i] = tmp[(i + 16) % 32];
+
+  /* Apply the hamming window to the impulse response to get
+   * a better result than given from the rectangular window
+   */
+  for (i = 0; i < 32; i++)
+    filter_kernel[i] *= (0.54 - 0.46 * cos (2 * G_PI * i / 32));
+
+  va = g_value_array_new (1);
+
+  g_value_init (&v, G_TYPE_DOUBLE);
+  for (i = 0; i < 32; i++) {
+    g_value_set_double (&v, filter_kernel[i]);
+    g_value_array_append (va, &v);
+    g_value_reset (&v);
+  }
+  g_object_set (G_OBJECT (element), "kernel", va, NULL);
+  /* Latency is 1/2 of the kernel length for this method of
+   * calculating a filter kernel from the frequency response
+   */
+  g_object_set (G_OBJECT (element), "latency", (gint64) (32 / 2), NULL);
+  g_value_array_free (va);
+}
+
+gint
+main (gint argc, gchar * argv[])
+{
+  GstElement *pipeline, *src, *filter, *conv, *sink;
+  GstBus *bus;
+  GMainLoop *loop;
+
+  gst_init (NULL, NULL);
+
+  pipeline = gst_element_factory_make ("pipeline", NULL);
+
+  src = gst_element_factory_make ("audiotestsrc", NULL);
+  g_object_set (G_OBJECT (src), "wave", 5, NULL);
+
+  filter = gst_element_factory_make ("audiofirfilter", NULL);
+  g_signal_connect (G_OBJECT (filter), "rate-changed",
+      G_CALLBACK (on_rate_changed), NULL);
+
+  conv = gst_element_factory_make ("audioconvert", NULL);
+
+  sink = gst_element_factory_make ("autoaudiosink", NULL);
+  g_return_val_if_fail (sink != NULL, -1);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, filter, conv, sink, NULL);
+  if (!gst_element_link_many (src, filter, conv, sink, NULL)) {
+    g_error ("Failed to link elements");
+    return -2;
+  }
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+  gst_bus_add_signal_watch (bus);
+  g_signal_connect (G_OBJECT (bus), "message", G_CALLBACK (on_message), loop);
+  gst_object_unref (GST_OBJECT (bus));
+
+  if (gst_element_set_state (pipeline,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
+    g_error ("Failed to go into PLAYING state");
+    return -3;
+  }
+
+  g_main_loop_run (loop);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  g_main_loop_unref (loop);
+  gst_object_unref (pipeline);
+
+  return 0;
+}
diff --git a/tests/examples/audiofx/iirfilter-example.c b/tests/examples/audiofx/iirfilter-example.c
new file mode 100644
index 0000000..fc553f9
--- /dev/null
+++ b/tests/examples/audiofx/iirfilter-example.c
@@ -0,0 +1,141 @@
+/* GStreamer
+ * Copyright (C) 2009 Sebastian Droege <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* This small sample application creates a lowpass IIR filter
+ * and applies it to white noise.
+ * See http://www.dspguide.com/ch19/2.htm for a description
+ * of the IIR filter that is used.
+ */
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <string.h>
+#include <math.h>
+
+#include <gst/gst.h>
+
+/* Cutoff of 4000 Hz */
+#define CUTOFF (4000.0)
+
+static gboolean
+on_message (GstBus * bus, GstMessage * message, gpointer user_data)
+{
+  GMainLoop *loop = (GMainLoop *) user_data;
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_ERROR:
+      g_error ("Got ERROR");
+      g_main_loop_quit (loop);
+      break;
+    case GST_MESSAGE_WARNING:
+      g_warning ("Got WARNING");
+      g_main_loop_quit (loop);
+      break;
+    case GST_MESSAGE_EOS:
+      g_main_loop_quit (loop);
+      break;
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+static void
+on_rate_changed (GstElement * element, gint rate, gpointer user_data)
+{
+  GValueArray *va;
+  GValue v = { 0, };
+  gdouble x;
+
+  if (rate / 2.0 > CUTOFF)
+    x = exp (-2.0 * G_PI * (CUTOFF / rate));
+  else
+    x = 0.0;
+
+  va = g_value_array_new (1);
+
+  g_value_init (&v, G_TYPE_DOUBLE);
+  g_value_set_double (&v, 1.0 - x);
+  g_value_array_append (va, &v);
+  g_value_reset (&v);
+  g_object_set (G_OBJECT (element), "a", va, NULL);
+  g_value_array_free (va);
+
+  va = g_value_array_new (1);
+  g_value_set_double (&v, x);
+  g_value_array_append (va, &v);
+  g_value_reset (&v);
+  g_object_set (G_OBJECT (element), "b", va, NULL);
+  g_value_array_free (va);
+}
+
+gint
+main (gint argc, gchar * argv[])
+{
+  GstElement *pipeline, *src, *filter, *conv, *sink;
+  GstBus *bus;
+  GMainLoop *loop;
+
+  gst_init (NULL, NULL);
+
+  pipeline = gst_element_factory_make ("pipeline", NULL);
+
+  src = gst_element_factory_make ("audiotestsrc", NULL);
+  g_object_set (G_OBJECT (src), "wave", 5, NULL);
+
+  filter = gst_element_factory_make ("audioiirfilter", NULL);
+  g_signal_connect (G_OBJECT (filter), "rate-changed",
+      G_CALLBACK (on_rate_changed), NULL);
+
+  conv = gst_element_factory_make ("audioconvert", NULL);
+
+  sink = gst_element_factory_make ("autoaudiosink", NULL);
+  g_return_val_if_fail (sink != NULL, -1);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, filter, conv, sink, NULL);
+  if (!gst_element_link_many (src, filter, conv, sink, NULL)) {
+    g_error ("Failed to link elements");
+    return -2;
+  }
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+  gst_bus_add_signal_watch (bus);
+  g_signal_connect (G_OBJECT (bus), "message", G_CALLBACK (on_message), loop);
+  gst_object_unref (GST_OBJECT (bus));
+
+  if (gst_element_set_state (pipeline,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
+    g_error ("Failed to go into PLAYING state");
+    return -3;
+  }
+
+  g_main_loop_run (loop);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  g_main_loop_unref (loop);
+  gst_object_unref (pipeline);
+
+  return 0;
+}
diff --git a/tests/examples/audiofx/meson.build b/tests/examples/audiofx/meson.build
new file mode 100644
index 0000000..3de26ed
--- /dev/null
+++ b/tests/examples/audiofx/meson.build
@@ -0,0 +1,12 @@
+executable('firfilter-example', 'firfilter-example.c',
+  dependencies: [gstfft_dep, gst_dep, libm],
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  install: false)
+
+executable('iirfilter-example', 'iirfilter-example.c',
+  dependencies: [gst_dep, libm],
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  install: false)
+
diff --git a/tests/examples/cairo/.gitignore b/tests/examples/cairo/.gitignore
new file mode 100644
index 0000000..690585c
--- /dev/null
+++ b/tests/examples/cairo/.gitignore
@@ -0,0 +1 @@
+cairo_overlay
diff --git a/tests/examples/cairo/Makefile.am b/tests/examples/cairo/Makefile.am
new file mode 100644
index 0000000..2e833cc
--- /dev/null
+++ b/tests/examples/cairo/Makefile.am
@@ -0,0 +1,5 @@
+noinst_PROGRAMS = cairo_overlay
+
+cairo_overlay_SOURCES = cairo_overlay.c
+cairo_overlay_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(CAIRO_CFLAGS)
+cairo_overlay_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) $(GST_LIBS) $(CAIRO_LIBS)
diff --git a/tests/examples/cairo/cairo_overlay.c b/tests/examples/cairo/cairo_overlay.c
new file mode 100644
index 0000000..9e9f71a
--- /dev/null
+++ b/tests/examples/cairo/cairo_overlay.c
@@ -0,0 +1,182 @@
+/* GStreamer
+ * Copyright (C) 2011 Jon Nordby <jononor@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Example showing usage of the cairooverlay element
+ */
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include <cairo.h>
+#include <cairo-gobject.h>
+
+#include <glib.h>
+
+
+static gboolean
+on_message (GstBus * bus, GstMessage * message, gpointer user_data)
+{
+  GMainLoop *loop = (GMainLoop *) user_data;
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_ERROR:{
+      GError *err = NULL;
+      gchar *debug;
+
+      gst_message_parse_error (message, &err, &debug);
+      g_critical ("Got ERROR: %s (%s)", err->message, GST_STR_NULL (debug));
+      g_main_loop_quit (loop);
+      break;
+    }
+    case GST_MESSAGE_WARNING:{
+      GError *err = NULL;
+      gchar *debug;
+
+      gst_message_parse_warning (message, &err, &debug);
+      g_warning ("Got WARNING: %s (%s)", err->message, GST_STR_NULL (debug));
+      g_main_loop_quit (loop);
+      break;
+    }
+    case GST_MESSAGE_EOS:
+      g_main_loop_quit (loop);
+      break;
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+/* Datastructure to share the state we are interested in between
+ * prepare and render function. */
+typedef struct
+{
+  gboolean valid;
+  GstVideoInfo vinfo;
+} CairoOverlayState;
+
+/* Store the information from the caps that we are interested in. */
+static void
+prepare_overlay (GstElement * overlay, GstCaps * caps, gpointer user_data)
+{
+  CairoOverlayState *state = (CairoOverlayState *) user_data;
+
+  state->valid = gst_video_info_from_caps (&state->vinfo, caps);
+}
+
+/* Draw the overlay. 
+ * This function draws a cute "beating" heart. */
+static void
+draw_overlay (GstElement * overlay, cairo_t * cr, guint64 timestamp,
+    guint64 duration, gpointer user_data)
+{
+  CairoOverlayState *s = (CairoOverlayState *) user_data;
+  double scale;
+  int width, height;
+
+  if (!s->valid)
+    return;
+
+  width = GST_VIDEO_INFO_WIDTH (&s->vinfo);
+  height = GST_VIDEO_INFO_HEIGHT (&s->vinfo);
+
+  scale = 2 * (((timestamp / (int) 1e7) % 70) + 30) / 100.0;
+  cairo_translate (cr, width / 2, (height / 2) - 30);
+
+  /* FIXME: this assumes a pixel-aspect-ratio of 1/1 */
+  cairo_scale (cr, scale, scale);
+
+  cairo_move_to (cr, 0, 0);
+  cairo_curve_to (cr, 0, -30, -50, -30, -50, 0);
+  cairo_curve_to (cr, -50, 30, 0, 35, 0, 60);
+  cairo_curve_to (cr, 0, 35, 50, 30, 50, 0);
+  cairo_curve_to (cr, 50, -30, 0, -30, 0, 0);
+  cairo_set_source_rgba (cr, 0.9, 0.0, 0.1, 0.7);
+  cairo_fill (cr);
+}
+
+static GstElement *
+setup_gst_pipeline (CairoOverlayState * overlay_state)
+{
+  GstElement *pipeline;
+  GstElement *cairo_overlay;
+  GstElement *source, *adaptor1, *adaptor2, *sink;
+
+  pipeline = gst_pipeline_new ("cairo-overlay-example");
+
+  /* Adaptors needed because cairooverlay only supports ARGB data */
+  source = gst_element_factory_make ("videotestsrc", "source");
+  adaptor1 = gst_element_factory_make ("videoconvert", "adaptor1");
+  cairo_overlay = gst_element_factory_make ("cairooverlay", "overlay");
+  adaptor2 = gst_element_factory_make ("videoconvert", "adaptor2");
+  sink = gst_element_factory_make ("ximagesink", "sink");
+  if (sink == NULL)
+    sink = gst_element_factory_make ("autovideosink", "sink");
+
+  /* If failing, the element could not be created */
+  g_assert (cairo_overlay);
+
+  /* Hook up the neccesary signals for cairooverlay */
+  g_signal_connect (cairo_overlay, "draw",
+      G_CALLBACK (draw_overlay), overlay_state);
+  g_signal_connect (cairo_overlay, "caps-changed",
+      G_CALLBACK (prepare_overlay), overlay_state);
+
+  gst_bin_add_many (GST_BIN (pipeline), source, adaptor1,
+      cairo_overlay, adaptor2, sink, NULL);
+
+  if (!gst_element_link_many (source, adaptor1,
+          cairo_overlay, adaptor2, sink, NULL)) {
+    g_warning ("Failed to link elements!");
+  }
+
+  return pipeline;
+}
+
+int
+main (int argc, char **argv)
+{
+  GMainLoop *loop;
+  GstElement *pipeline;
+  GstBus *bus;
+  CairoOverlayState *overlay_state;
+
+  gst_init (&argc, &argv);
+  loop = g_main_loop_new (NULL, FALSE);
+
+  /* allocate on heap for pedagogical reasons, makes code easier to transfer */
+  overlay_state = g_new0 (CairoOverlayState, 1);
+
+  pipeline = setup_gst_pipeline (overlay_state);
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+  gst_bus_add_signal_watch (bus);
+  g_signal_connect (G_OBJECT (bus), "message", G_CALLBACK (on_message), loop);
+  gst_object_unref (GST_OBJECT (bus));
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  g_main_loop_run (loop);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+
+  g_free (overlay_state);
+  return 0;
+}
diff --git a/tests/examples/cairo/meson.build b/tests/examples/cairo/meson.build
new file mode 100644
index 0000000..628d2c1
--- /dev/null
+++ b/tests/examples/cairo/meson.build
@@ -0,0 +1,7 @@
+if cairo_dep.found()
+  executable('cairo_overlay', 'cairo_overlay.c',
+    dependencies: [gstvideo_dep, gst_dep, cairo_dep, libm],
+    c_args : gst_plugins_good_args,
+    include_directories : [configinc],
+    install: false)
+endif
diff --git a/tests/examples/equalizer/.gitignore b/tests/examples/equalizer/.gitignore
new file mode 100644
index 0000000..1549b67
--- /dev/null
+++ b/tests/examples/equalizer/.gitignore
@@ -0,0 +1 @@
+demo
diff --git a/tests/examples/equalizer/Makefile.am b/tests/examples/equalizer/Makefile.am
new file mode 100644
index 0000000..07f2b25
--- /dev/null
+++ b/tests/examples/equalizer/Makefile.am
@@ -0,0 +1,8 @@
+if HAVE_GTK
+noinst_PROGRAMS = demo
+endif
+
+demo_SOURCES = demo.c
+demo_CFLAGS  = $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GTK_CFLAGS)
+demo_LDADD = $(GST_BASE_LIBS) $(GST_LIBS) $(GTK_LIBS)
+
diff --git a/tests/examples/equalizer/demo.c b/tests/examples/equalizer/demo.c
new file mode 100644
index 0000000..70000e5
--- /dev/null
+++ b/tests/examples/equalizer/demo.c
@@ -0,0 +1,327 @@
+/* GStreamer
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* TODO: We use gdk_cairo_create() and others, which are deprecated */
+#define GDK_DISABLE_DEPRECATION_WARNINGS
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <gst/gst.h>
+#include <gtk/gtk.h>
+
+#define NBANDS 10
+
+static GtkWidget *drawingarea = NULL;
+static guint spect_height = 128;
+static guint spect_bands = 256;
+static gfloat height_scale = 2.0;
+
+static void
+on_window_destroy (GObject * object, gpointer user_data)
+{
+  drawingarea = NULL;
+  gtk_main_quit ();
+}
+
+static gboolean
+on_configure_event (GtkWidget * widget, GdkEventConfigure * event,
+    gpointer user_data)
+{
+  GstElement *spectrum = GST_ELEMENT (user_data);
+
+  /*GST_INFO ("%d x %d", event->width, event->height); */
+  spect_height = event->height;
+  height_scale = event->height / 64.0;
+  spect_bands = event->width;
+
+  g_object_set (G_OBJECT (spectrum), "bands", spect_bands, NULL);
+  return FALSE;
+}
+
+/* control gains */
+static void
+on_gain_changed (GtkRange * range, gpointer user_data)
+{
+  GstObject *band = GST_OBJECT (user_data);
+  gdouble value = gtk_range_get_value (range);
+
+  g_object_set (band, "gain", value, NULL);
+}
+
+/* control bandwidths */
+static void
+on_bandwidth_changed (GtkRange * range, gpointer user_data)
+{
+  GstObject *band = GST_OBJECT (user_data);
+  gdouble value = gtk_range_get_value (range);
+
+  g_object_set (band, "bandwidth", value, NULL);
+}
+
+/* control frequency */
+static void
+on_freq_changed (GtkRange * range, gpointer user_data)
+{
+  GstObject *band = GST_OBJECT (user_data);
+  gdouble value = gtk_range_get_value (range);
+
+  /* hbox */
+  GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (range));
+
+  /* frame */
+  GtkWidget *parent_parent = gtk_widget_get_parent (parent);
+  gchar *label = g_strdup_printf ("%d Hz", (int) (value + 0.5));
+
+  gtk_frame_set_label (GTK_FRAME (parent_parent), label);
+  g_free (label);
+
+  g_object_set (band, "freq", value, NULL);
+}
+
+/* draw frequency spectrum as a bunch of bars */
+static void
+draw_spectrum (gfloat * data)
+{
+  gint i;
+  GdkRectangle rect = { 0, 0, spect_bands, spect_height };
+  cairo_t *cr;
+
+  if (!drawingarea)
+    return;
+
+  gdk_window_begin_paint_rect (gtk_widget_get_window (drawingarea), &rect);
+  cr = gdk_cairo_create (gtk_widget_get_window (drawingarea));
+
+  cairo_set_source_rgb (cr, 0, 0, 0);
+  cairo_rectangle (cr, 0, 0, spect_bands, spect_height);
+  cairo_fill (cr);
+  for (i = 0; i < spect_bands; i++) {
+    cairo_set_source_rgb (cr, 1, 1, 1);
+    cairo_rectangle (cr, i, -data[i], 1, spect_height + data[i]);
+    cairo_fill (cr);
+  }
+  cairo_destroy (cr);
+
+  gdk_window_end_paint (gtk_widget_get_window (drawingarea));
+}
+
+static void
+dynamic_link (GstPadTemplate * templ, GstPad * newpad, gpointer user_data)
+{
+  GstPad *target = GST_PAD (user_data);
+
+  gst_pad_link (newpad, target);
+  gst_object_unref (target);
+}
+
+/* receive spectral data from element message */
+static gboolean
+message_handler (GstBus * bus, GstMessage * message, gpointer data)
+{
+  if (message->type == GST_MESSAGE_ELEMENT) {
+    const GstStructure *s = gst_message_get_structure (message);
+    const gchar *name = gst_structure_get_name (s);
+
+    if (strcmp (name, "spectrum") == 0) {
+      gfloat *spect = g_new (gfloat, spect_bands);
+      const GValue *list;
+      const GValue *value;
+      guint i;
+
+      list = gst_structure_get_value (s, "magnitude");
+      for (i = 0; i < spect_bands; ++i) {
+        value = gst_value_list_get_value (list, i);
+        spect[i] = height_scale * g_value_get_float (value);
+      }
+      draw_spectrum (spect);
+      g_free (spect);
+    }
+  }
+  return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+  GstElement *bin;
+  GstElement *decodebin, *decconvert;
+  GstElement *capsfilter, *equalizer, *spectrum, *sinkconvert, *sink;
+  GstCaps *caps;
+  GstBus *bus;
+  GtkWidget *appwindow, *vbox, *hbox, *scale;
+  int i, num_bands = NBANDS;
+
+  GOptionEntry options[] = {
+    {"bands", 'b', 0, G_OPTION_ARG_INT, &num_bands,
+        "Number of bands", NULL},
+    {NULL}
+  };
+  GOptionContext *ctx;
+  GError *err = NULL;
+
+  ctx = g_option_context_new ("- demo of audio equalizer");
+  g_option_context_add_main_entries (ctx, options, NULL);
+  g_option_context_add_group (ctx, gst_init_get_option_group ());
+  g_option_context_add_group (ctx, gtk_get_option_group (TRUE));
+
+  if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
+    g_print ("Error initializing: %s\n", err->message);
+    g_option_context_free (ctx);
+    g_clear_error (&err);
+    exit (1);
+  }
+  g_option_context_free (ctx);
+
+  if (argc < 2) {
+    g_print ("Usage: %s <uri to play>\n", argv[0]);
+    g_print ("    For optional arguments: --help\n");
+    exit (-1);
+  }
+
+  gst_init (&argc, &argv);
+  gtk_init (&argc, &argv);
+
+  bin = gst_pipeline_new ("bin");
+
+  /* Uri decoding */
+  decodebin = gst_element_factory_make ("uridecodebin", "decoder");
+  g_object_set (G_OBJECT (decodebin), "uri", argv[1], NULL);
+
+  /* Force float32 samples */
+  decconvert = gst_element_factory_make ("audioconvert", "decconvert");
+  capsfilter = gst_element_factory_make ("capsfilter", "capsfilter");
+  caps =
+      gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, "F32LE",
+      NULL);
+  g_object_set (capsfilter, "caps", caps, NULL);
+
+  equalizer = gst_element_factory_make ("equalizer-nbands", "equalizer");
+  g_object_set (G_OBJECT (equalizer), "num-bands", num_bands, NULL);
+
+  spectrum = gst_element_factory_make ("spectrum", "spectrum");
+  g_object_set (G_OBJECT (spectrum), "bands", spect_bands, "threshold", -80,
+      "post-messages", TRUE, "interval", 500 * GST_MSECOND, NULL);
+
+  sinkconvert = gst_element_factory_make ("audioconvert", "sinkconvert");
+
+  sink = gst_element_factory_make ("autoaudiosink", "sink");
+
+  gst_bin_add_many (GST_BIN (bin), decodebin, decconvert, capsfilter, equalizer,
+      spectrum, sinkconvert, sink, NULL);
+  if (!gst_element_link_many (decconvert, capsfilter, equalizer, spectrum,
+          sinkconvert, sink, NULL)) {
+    fprintf (stderr, "can't link elements\n");
+    exit (1);
+  }
+
+  /* Handle dynamic pads */
+  g_signal_connect (G_OBJECT (decodebin), "pad-added",
+      G_CALLBACK (dynamic_link), gst_element_get_static_pad (decconvert,
+          "sink"));
+
+  bus = gst_element_get_bus (bin);
+  gst_bus_add_watch (bus, message_handler, NULL);
+  gst_object_unref (bus);
+
+  appwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (appwindow), "Equalizer Demo");
+  g_signal_connect (G_OBJECT (appwindow), "destroy",
+      G_CALLBACK (on_window_destroy), NULL);
+  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+
+  drawingarea = gtk_drawing_area_new ();
+  gtk_widget_set_size_request (drawingarea, spect_bands, spect_height);
+  g_signal_connect (G_OBJECT (drawingarea), "configure-event",
+      G_CALLBACK (on_configure_event), (gpointer) spectrum);
+  gtk_box_pack_start (GTK_BOX (vbox), drawingarea, TRUE, TRUE, 0);
+
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 20);
+
+  for (i = 0; i < num_bands; i++) {
+    GObject *band;
+    gdouble freq;
+    gdouble bw;
+    gdouble gain;
+    gchar *label;
+    GtkWidget *frame, *scales_hbox;
+
+    band = gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (equalizer), i);
+    g_assert (band != NULL);
+    g_object_get (band, "freq", &freq, NULL);
+    g_object_get (band, "bandwidth", &bw, NULL);
+    g_object_get (band, "gain", &gain, NULL);
+
+    label = g_strdup_printf ("%d Hz", (int) (freq + 0.5));
+    frame = gtk_frame_new (label);
+    g_free (label);
+
+    scales_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+
+    /* Create gain scale */
+    scale = gtk_scale_new_with_range (GTK_ORIENTATION_VERTICAL,
+        -24.0, 12.0, 0.5);
+    gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE);
+    gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
+    gtk_range_set_value (GTK_RANGE (scale), gain);
+    gtk_widget_set_size_request (scale, 35, 150);
+    g_signal_connect (G_OBJECT (scale), "value-changed",
+        G_CALLBACK (on_gain_changed), (gpointer) band);
+    gtk_box_pack_start (GTK_BOX (scales_hbox), scale, FALSE, FALSE, 0);
+
+    /* Create bandwidth scale */
+    scale = gtk_scale_new_with_range (GTK_ORIENTATION_VERTICAL,
+        0.0, 20000.0, 5.0);
+    gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE);
+    gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
+    gtk_range_set_value (GTK_RANGE (scale), bw);
+    gtk_widget_set_size_request (scale, 45, 150);
+    g_signal_connect (G_OBJECT (scale), "value-changed",
+        G_CALLBACK (on_bandwidth_changed), (gpointer) band);
+    gtk_box_pack_start (GTK_BOX (scales_hbox), scale, TRUE, TRUE, 0);
+
+    /* Create frequency scale */
+    scale = gtk_scale_new_with_range (GTK_ORIENTATION_VERTICAL,
+        20.0, 20000.0, 5.0);
+    gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE);
+    gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
+    gtk_range_set_value (GTK_RANGE (scale), freq);
+    gtk_widget_set_size_request (scale, 45, 150);
+    g_signal_connect (G_OBJECT (scale), "value-changed",
+        G_CALLBACK (on_freq_changed), (gpointer) band);
+    gtk_box_pack_start (GTK_BOX (scales_hbox), scale, TRUE, TRUE, 0);
+
+    gtk_container_add (GTK_CONTAINER (frame), scales_hbox);
+
+    gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
+  }
+
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
+
+  gtk_container_add (GTK_CONTAINER (appwindow), vbox);
+  gtk_widget_show_all (appwindow);
+
+  gst_element_set_state (bin, GST_STATE_PLAYING);
+  gtk_main ();
+  gst_element_set_state (bin, GST_STATE_NULL);
+
+  gst_object_unref (bin);
+
+  return 0;
+}
diff --git a/tests/examples/equalizer/meson.build b/tests/examples/equalizer/meson.build
new file mode 100644
index 0000000..de68233
--- /dev/null
+++ b/tests/examples/equalizer/meson.build
@@ -0,0 +1,6 @@
+executable('equalizer-demo', 'demo.c',
+  dependencies: [gst_dep, gtk_dep],
+  c_args: gst_plugins_good_args,
+  include_directories: [configinc],
+  install: false)
+
diff --git a/tests/examples/jack/Makefile.am b/tests/examples/jack/Makefile.am
new file mode 100644
index 0000000..ad61cbd
--- /dev/null
+++ b/tests/examples/jack/Makefile.am
@@ -0,0 +1,12 @@
+if HAVE_GTK
+GTK_EXAMPLES=jack_client
+else
+GTK_EXAMPLES=
+endif
+
+noinst_PROGRAMS = $(GTK_EXAMPLES)
+
+jack_client_SOURCES = jack_client.c
+jack_client_CFLAGS = $(GST_CFLAGS) $(GTK_CFLAGS) $(JACK_CFLAGS)
+jack_client_LDFLAGS = $(GST_LIBS) $(GTK_LIBS) $(JACK_LIBS)
+
diff --git a/tests/examples/jack/jack_client.c b/tests/examples/jack/jack_client.c
new file mode 100644
index 0000000..969ceda
--- /dev/null
+++ b/tests/examples/jack/jack_client.c
@@ -0,0 +1,79 @@
+/* This app demonstrates the creation and use of a jack client in conjunction
+ * with the jack plugins. This way, an application can control the jack client
+ * directly.
+ */
+
+#include <gst/gst.h>
+#include <gtk/gtk.h>
+#include <jack/jack.h>
+
+static gboolean
+quit_cb (gpointer data)
+{
+  gtk_main_quit ();
+  return FALSE;
+}
+
+int
+main (int argc, char **argv)
+{
+  jack_client_t *src_client, *sink_client;
+  jack_status_t status;
+  GstElement *pipeline, *src, *sink;
+  GstStateChangeReturn ret;
+
+  gst_init (&argc, &argv);
+
+  /* create jack clients */
+  src_client = jack_client_open ("src_client", JackNoStartServer, &status);
+  if (src_client == NULL) {
+    if (status & JackServerFailed)
+      g_print ("JACK server not running\n");
+    else
+      g_print ("jack_client_open() failed, status = 0x%2.0x\n", status);
+    return 1;
+  }
+
+  sink_client = jack_client_open ("sink_client", JackNoStartServer, &status);
+  if (sink_client == NULL) {
+    if (status & JackServerFailed)
+      g_print ("JACK server not running\n");
+    else
+      g_print ("jack_client_open() failed, status = 0x%2.0x\n", status);
+    return 1;
+  }
+
+  /* create gst elements */
+  pipeline = gst_pipeline_new ("my_pipeline");
+
+  src = gst_element_factory_make ("jackaudiosrc", NULL);
+  sink = gst_element_factory_make ("jackaudiosink", NULL);
+
+  g_object_set (src, "client", src_client, NULL);
+  g_object_set (sink, "client", sink_client, NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
+
+  /* link everything together */
+  if (!gst_element_link (src, sink)) {
+    g_print ("Failed to link elements!\n");
+    return 1;
+  }
+
+  /* run */
+  ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  if (ret == GST_STATE_CHANGE_FAILURE) {
+    g_print ("Failed to start up pipeline!\n");
+    return 1;
+  }
+
+  /* quit after 5 seconds */
+  g_timeout_add_seconds (5, (GSourceFunc) quit_cb, NULL);
+  gtk_main ();
+
+  /* clean up */
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+
+  return 0;
+}
diff --git a/tests/examples/jack/meson.build b/tests/examples/jack/meson.build
new file mode 100644
index 0000000..25ac8a8
--- /dev/null
+++ b/tests/examples/jack/meson.build
@@ -0,0 +1,7 @@
+if libjack_dep.found()
+  executable('jack_client', 'jack_client.c',
+    dependencies: [gst_dep, gtk_dep, libjack_dep],
+    c_args: gst_plugins_good_args,
+    include_directories: [configinc],
+    install: false)
+endif
diff --git a/tests/examples/level/.gitignore b/tests/examples/level/.gitignore
new file mode 100644
index 0000000..11efff7
--- /dev/null
+++ b/tests/examples/level/.gitignore
@@ -0,0 +1 @@
+level-example
diff --git a/tests/examples/level/Makefile.am b/tests/examples/level/Makefile.am
new file mode 100644
index 0000000..67ca719
--- /dev/null
+++ b/tests/examples/level/Makefile.am
@@ -0,0 +1,4 @@
+noinst_PROGRAMS = level-example
+level_example_CFLAGS = $(GST_CFLAGS)
+level_example_LDADD = $(GST_LIBS) $(LIBM)
+
diff --git a/tests/examples/level/level-example.c b/tests/examples/level/level-example.c
new file mode 100644
index 0000000..a953176
--- /dev/null
+++ b/tests/examples/level/level-example.c
@@ -0,0 +1,140 @@
+/* GStreamer
+ * Copyright (C) 2000,2001,2002,2003,2005
+ *           Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+#include <math.h>
+
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <gst/gst.h>
+
+static gboolean
+message_handler (GstBus * bus, GstMessage * message, gpointer data)
+{
+
+  if (message->type == GST_MESSAGE_ELEMENT) {
+    const GstStructure *s = gst_message_get_structure (message);
+    const gchar *name = gst_structure_get_name (s);
+
+    if (strcmp (name, "level") == 0) {
+      gint channels;
+      GstClockTime endtime;
+      gdouble rms_dB, peak_dB, decay_dB;
+      gdouble rms;
+      const GValue *array_val;
+      const GValue *value;
+      GValueArray *rms_arr, *peak_arr, *decay_arr;
+      gint i;
+
+      if (!gst_structure_get_clock_time (s, "endtime", &endtime))
+        g_warning ("Could not parse endtime");
+
+      /* the values are packed into GValueArrays with the value per channel */
+      array_val = gst_structure_get_value (s, "rms");
+      rms_arr = (GValueArray *) g_value_get_boxed (array_val);
+
+      array_val = gst_structure_get_value (s, "peak");
+      peak_arr = (GValueArray *) g_value_get_boxed (array_val);
+
+      array_val = gst_structure_get_value (s, "decay");
+      decay_arr = (GValueArray *) g_value_get_boxed (array_val);
+
+      /* we can get the number of channels as the length of any of the value
+       * arrays */
+      channels = rms_arr->n_values;
+      g_print ("endtime: %" GST_TIME_FORMAT ", channels: %d\n",
+          GST_TIME_ARGS (endtime), channels);
+      for (i = 0; i < channels; ++i) {
+
+        g_print ("channel %d\n", i);
+        value = g_value_array_get_nth (rms_arr, i);
+        rms_dB = g_value_get_double (value);
+
+        value = g_value_array_get_nth (peak_arr, i);
+        peak_dB = g_value_get_double (value);
+
+        value = g_value_array_get_nth (decay_arr, i);
+        decay_dB = g_value_get_double (value);
+        g_print ("    RMS: %f dB, peak: %f dB, decay: %f dB\n",
+            rms_dB, peak_dB, decay_dB);
+
+        /* converting from dB to normal gives us a value between 0.0 and 1.0 */
+        rms = pow (10, rms_dB / 20);
+        g_print ("    normalized rms value: %f\n", rms);
+      }
+    }
+  }
+  /* we handled the message we want, and ignored the ones we didn't want.
+   * so the core can unref the message for us */
+  return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+  GstElement *audiotestsrc, *audioconvert, *level, *fakesink;
+  GstElement *pipeline;
+  GstCaps *caps;
+  GstBus *bus;
+  guint watch_id;
+  GMainLoop *loop;
+
+  gst_init (&argc, &argv);
+
+  caps = gst_caps_from_string ("audio/x-raw,channels=2");
+
+  pipeline = gst_pipeline_new (NULL);
+  g_assert (pipeline);
+  audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL);
+  g_assert (audiotestsrc);
+  audioconvert = gst_element_factory_make ("audioconvert", NULL);
+  g_assert (audioconvert);
+  level = gst_element_factory_make ("level", NULL);
+  g_assert (level);
+  fakesink = gst_element_factory_make ("fakesink", NULL);
+  g_assert (fakesink);
+
+  gst_bin_add_many (GST_BIN (pipeline), audiotestsrc, audioconvert, level,
+      fakesink, NULL);
+  if (!gst_element_link (audiotestsrc, audioconvert))
+    g_error ("Failed to link audiotestsrc and audioconvert");
+  if (!gst_element_link_filtered (audioconvert, level, caps))
+    g_error ("Failed to link audioconvert and level");
+  if (!gst_element_link (level, fakesink))
+    g_error ("Failed to link level and fakesink");
+
+  /* make sure we'll get messages */
+  g_object_set (G_OBJECT (level), "post-messages", TRUE, NULL);
+  /* run synced and not as fast as we can */
+  g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL);
+
+  bus = gst_element_get_bus (pipeline);
+  watch_id = gst_bus_add_watch (bus, message_handler, NULL);
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  /* we need to run a GLib main loop to get the messages */
+  loop = g_main_loop_new (NULL, FALSE);
+  g_main_loop_run (loop);
+
+  g_source_remove (watch_id);
+  g_main_loop_unref (loop);
+  return 0;
+}
diff --git a/tests/examples/level/meson.build b/tests/examples/level/meson.build
new file mode 100644
index 0000000..91e3242
--- /dev/null
+++ b/tests/examples/level/meson.build
@@ -0,0 +1,5 @@
+executable('level-example', 'level-example.c',
+  dependencies: [gst_dep, libm],
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  install: false)
diff --git a/tests/examples/meson.build b/tests/examples/meson.build
new file mode 100644
index 0000000..bf70134
--- /dev/null
+++ b/tests/examples/meson.build
@@ -0,0 +1,13 @@
+subdir('audiofx')
+subdir('cairo')
+subdir('level')
+subdir('rtp')
+subdir('shapewipe')
+subdir('v4l2')
+
+if gtk_dep.found()
+  subdir('equalizer')
+  subdir('jack')
+  subdir('spectrum')
+endif
+
diff --git a/tests/examples/rtp/.gitignore b/tests/examples/rtp/.gitignore
new file mode 100644
index 0000000..8c3c6d3
--- /dev/null
+++ b/tests/examples/rtp/.gitignore
@@ -0,0 +1,6 @@
+client-PCMA
+server-alsasrc-PCMA
+client-rtpaux
+server-rtpaux
+client-rtpbundle
+server-rtpbundle
diff --git a/tests/examples/rtp/Makefile.am b/tests/examples/rtp/Makefile.am
new file mode 100644
index 0000000..4d7f7c1
--- /dev/null
+++ b/tests/examples/rtp/Makefile.am
@@ -0,0 +1,44 @@
+noinst_PROGRAMS = server-alsasrc-PCMA client-PCMA \
+	client-rtpaux server-rtpaux client-rtpbundle server-rtpbundle
+
+# FIXME 0.11: ignore GValueArray warnings for now until this is sorted
+ERROR_CFLAGS=
+
+server_rtpaux_SOURCES = server-rtpaux.c
+server_rtpaux_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS)
+server_rtpaux_LDADD = $(GST_LIBS)
+
+client_rtpaux_SOURCES = client-rtpaux.c
+client_rtpaux_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS)
+client_rtpaux_LDADD = $(GST_LIBS)
+
+server_rtpbundle_SOURCES = server-rtpbundle.c
+server_rtpbundle_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS)
+server_rtpbundle_LDADD = $(GST_LIBS)
+
+client_rtpbundle_SOURCES = client-rtpbundle.c
+client_rtpbundle_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS)
+client_rtpbundle_LDADD = $(GST_LIBS)
+
+server_alsasrc_PCMA_SOURCES = server-alsasrc-PCMA.c
+server_alsasrc_PCMA_CFLAGS = $(GST_CFLAGS)
+server_alsasrc_PCMA_LDADD = $(GST_LIBS) $(LIBM)
+
+client_PCMA_SOURCES = client-PCMA.c
+client_PCMA_CFLAGS = $(GST_CFLAGS)
+client_PCMA_LDADD = $(GST_LIBS) $(LIBM)
+
+noinst_SCRIPTS=client-H263p-AMR.sh \
+               client-H263p-PCMA.sh \
+               client-H264-PCMA.sh \
+               client-VP8-OPUS.sh \
+               client-PCMA.sh \
+               server-alsasrc-PCMA.sh \
+               server-v4l2-H263p-alsasrc-AMR.sh \
+               server-v4l2-H264-alsasrc-PCMA.sh \
+               server-VTS-H263p-ATS-PCMA.sh \
+               server-VTS-VP8-ATS-OPUS.sh
+
+EXTRA_DIST= $(noinst_SCRIPTS) \
+	    client-H263p-PCMA.sdp \
+            client-H264-PCMA.sdp
diff --git a/tests/examples/rtp/client-H263p-AMR.sh b/tests/examples/rtp/client-H263p-AMR.sh
new file mode 100755
index 0000000..bba5154
--- /dev/null
+++ b/tests/examples/rtp/client-H263p-AMR.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# A simple RTP receiver 
+#
+
+VIDEO_CAPS="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H263-1998"
+AUDIO_CAPS="application/x-rtp,media=(string)audio,clock-rate=(int)8000,encoding-name=(string)AMR,encoding-params=(string)1,octet-align=(string)1"
+
+VIDEO_DEC="rtph263pdepay ! avdec_h263"
+AUDIO_DEC="rtpamrdepay ! amrnbdec"
+
+VIDEO_SINK="videoconvert ! autovideosink"
+AUDIO_SINK="audioconvert ! audioresample ! autoaudiosink"
+
+gst-launch-1.0 -v rtpbin name=rtpbin latency=100                                    \
+           udpsrc caps=$VIDEO_CAPS port=5000 ! rtpbin.recv_rtp_sink_0              \
+	         rtpbin. ! $VIDEO_DEC ! $VIDEO_SINK                                \
+           udpsrc port=5001 ! rtpbin.recv_rtcp_sink_0                              \
+           rtpbin.send_rtcp_src_0 ! udpsink port=5005 sync=false async=false       \
+	   udpsrc caps=$AUDIO_CAPS port=5002 ! rtpbin.recv_rtp_sink_1              \
+	         rtpbin. ! $AUDIO_DEC ! $AUDIO_SINK                                \
+           udpsrc port=5003 ! rtpbin.recv_rtcp_sink_1                              \
+           rtpbin.send_rtcp_src_1 ! udpsink port=5007 sync=false async=false
diff --git a/tests/examples/rtp/client-H263p-PCMA.sdp b/tests/examples/rtp/client-H263p-PCMA.sdp
new file mode 100644
index 0000000..8d2264f
--- /dev/null
+++ b/tests/examples/rtp/client-H263p-PCMA.sdp
@@ -0,0 +1,12 @@
+v=0
+o=- 1188340656180883 1 IN IP4 127.0.0.1
+s=Session streamed by GStreamer
+i=server.sh
+t=0 0
+a=tool:GStreamer
+a=type:broadcast
+m=video 5000 RTP/AVP 96
+c=IN IP4 127.0.0.1
+a=rtpmap:96 H263-1998/90000
+m=audio 5002 RTP/AVP 8
+c=IN IP4 127.0.0.1
diff --git a/tests/examples/rtp/client-H263p-PCMA.sh b/tests/examples/rtp/client-H263p-PCMA.sh
new file mode 100755
index 0000000..e79418d
--- /dev/null
+++ b/tests/examples/rtp/client-H263p-PCMA.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# A simple RTP receiver 
+#
+
+VIDEO_CAPS="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H263-1998"
+AUDIO_CAPS="application/x-rtp,media=(string)audio,clock-rate=(int)8000,encoding-name=(string)PCMA"
+
+#DEST=192.168.1.126
+DEST=localhost
+
+VIDEO_DEC="rtph263pdepay ! avdec_h263"
+AUDIO_DEC="rtppcmadepay ! alawdec"
+
+VIDEO_SINK="videoconvert ! autovideosink"
+AUDIO_SINK="audioconvert ! audioresample ! autoaudiosink"
+
+LATENCY=100
+
+gst-launch-1.0 -v rtpbin name=rtpbin latency=$LATENCY                                    \
+           udpsrc caps=$VIDEO_CAPS port=5000 ! rtpbin.recv_rtp_sink_0                   \
+	         rtpbin. ! $VIDEO_DEC ! $VIDEO_SINK                                     \
+           udpsrc port=5001 ! rtpbin.recv_rtcp_sink_0                                   \
+           rtpbin.send_rtcp_src_0 ! udpsink host=$DEST port=5005 sync=false async=false \
+	   udpsrc caps=$AUDIO_CAPS port=5002 ! rtpbin.recv_rtp_sink_1                   \
+	         rtpbin. ! $AUDIO_DEC ! $AUDIO_SINK                                     \
+           udpsrc port=5003 ! rtpbin.recv_rtcp_sink_1                                   \
+           rtpbin.send_rtcp_src_1 ! udpsink host=$DEST port=5007 sync=false async=false
diff --git a/tests/examples/rtp/client-H263p.sdp b/tests/examples/rtp/client-H263p.sdp
new file mode 100644
index 0000000..32d479e
--- /dev/null
+++ b/tests/examples/rtp/client-H263p.sdp
@@ -0,0 +1,10 @@
+v=0
+o=- 1188340656180883 1 IN IP4 127.0.0.1
+s=Session streamed by GStreamer
+i=server.sh
+t=0 0
+a=tool:GStreamer
+a=type:broadcast
+m=video 5000 RTP/AVP 96
+c=IN IP4 127.0.0.1
+a=rtpmap:96 H263-1998/90000
diff --git a/tests/examples/rtp/client-H263p.sh b/tests/examples/rtp/client-H263p.sh
new file mode 100755
index 0000000..6002843
--- /dev/null
+++ b/tests/examples/rtp/client-H263p.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+#
+# A simple RTP receiver 
+#
+
+VIDEO_CAPS="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H263-1998"
+
+#DEST=192.168.1.126
+DEST=localhost
+
+VIDEO_DEC="rtph263pdepay ! avdec_h263"
+
+VIDEO_SINK="videoconvert ! autovideosink"
+
+LATENCY=100
+
+gst-launch-1.0 -v rtpbin name=rtpbin latency=$LATENCY                                    \
+           udpsrc caps=$VIDEO_CAPS port=5000 ! rtpbin.recv_rtp_sink_0                   \
+	         rtpbin. ! $VIDEO_DEC ! $VIDEO_SINK                                     \
+           udpsrc port=5001 ! rtpbin.recv_rtcp_sink_0                                   \
+           rtpbin.send_rtcp_src_0 ! udpsink host=$DEST port=5005 sync=false async=false
diff --git a/tests/examples/rtp/client-H264-PCMA.sdp b/tests/examples/rtp/client-H264-PCMA.sdp
new file mode 100644
index 0000000..85aa75f
--- /dev/null
+++ b/tests/examples/rtp/client-H264-PCMA.sdp
@@ -0,0 +1,12 @@
+v=0
+o=- 1188340656180883 1 IN IP4 127.0.0.1
+s=Session streamed by GStreamer
+i=server.sh
+t=0 0
+a=tool:GStreamer
+a=type:broadcast
+m=video 5000 RTP/AVP 96
+c=IN IP4 127.0.0.1
+a=rtpmap:96 H264/90000
+m=audio 5002 RTP/AVP 8
+c=IN IP4 127.0.0.1
diff --git a/tests/examples/rtp/client-H264-PCMA.sh b/tests/examples/rtp/client-H264-PCMA.sh
new file mode 100755
index 0000000..820d4e1
--- /dev/null
+++ b/tests/examples/rtp/client-H264-PCMA.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# A simple RTP receiver
+#
+#  receives H264 encoded RTP video on port 5000, RTCP is received on  port 5001.
+#  the receiver RTCP reports are sent to port 5005
+#  receives alaw encoded RTP audio on port 5002, RTCP is received on  port 5003.
+#  the receiver RTCP reports are sent to port 5007
+#
+#             .-------.      .----------.     .---------.   .-------.   .-----------.
+#  RTP        |udpsrc |      | rtpbin   |     |h264depay|   |h264dec|   |xvimagesink|
+#  port=5000  |      src->recv_rtp recv_rtp->sink     src->sink   src->sink         |
+#             '-------'      |          |     '---------'   '-------'   '-----------'
+#                            |          |
+#                            |          |     .-------.
+#                            |          |     |udpsink|  RTCP
+#                            |    send_rtcp->sink     | port=5005
+#             .-------.      |          |     '-------' sync=false
+#  RTCP       |udpsrc |      |          |               async=false
+#  port=5001  |     src->recv_rtcp      |
+#             '-------'      |          |
+#                            |          |
+#             .-------.      |          |     .---------.   .-------.   .-------------.
+#  RTP        |udpsrc |      | rtpbin   |     |pcmadepay|   |alawdec|   |autoaudiosink|
+#  port=5002  |      src->recv_rtp recv_rtp->sink     src->sink   src->sink           |
+#             '-------'      |          |     '---------'   '-------'   '-------------'
+#                            |          |
+#                            |          |     .-------.
+#                            |          |     |udpsink|  RTCP
+#                            |    send_rtcp->sink     | port=5007
+#             .-------.      |          |     '-------' sync=false
+#  RTCP       |udpsrc |      |          |               async=false
+#  port=5003  |     src->recv_rtcp      |
+#             '-------'      '----------'
+
+# the destination machine to send RTCP to. This is the address of the sender and
+# is used to send back the RTCP reports of this receiver. If the data is sent
+# from another machine, change this address.
+DEST=127.0.0.1
+
+# this adjusts the latency in the receiver
+LATENCY=200
+
+# the caps of the sender RTP stream. This is usually negotiated out of band with
+# SDP or RTSP. normally these caps will also include SPS and PPS but we don't
+# have a mechanism to get this from the sender with a -launch line.
+VIDEO_CAPS="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H264"
+AUDIO_CAPS="application/x-rtp,media=(string)audio,clock-rate=(int)8000,encoding-name=(string)PCMA"
+
+VIDEO_DEC="rtph264depay ! avdec_h264"
+AUDIO_DEC="rtppcmadepay ! alawdec"
+
+VIDEO_SINK="videoconvert ! autovideosink"
+AUDIO_SINK="audioconvert ! audioresample ! autoaudiosink"
+
+gst-launch-1.0 -v rtpbin name=rtpbin latency=$LATENCY                                  \
+     udpsrc caps=$VIDEO_CAPS port=5000 ! rtpbin.recv_rtp_sink_0                       \
+       rtpbin. ! $VIDEO_DEC ! $VIDEO_SINK                                             \
+     udpsrc port=5001 ! rtpbin.recv_rtcp_sink_0                                       \
+         rtpbin.send_rtcp_src_0 ! udpsink port=5005 host=$DEST sync=false async=false \
+     udpsrc caps=$AUDIO_CAPS port=5002 ! rtpbin.recv_rtp_sink_1                       \
+       rtpbin. ! $AUDIO_DEC ! $AUDIO_SINK                                             \
+     udpsrc port=5003 ! rtpbin.recv_rtcp_sink_1                                       \
+         rtpbin.send_rtcp_src_1 ! udpsink port=5007 host=$DEST sync=false async=false
diff --git a/tests/examples/rtp/client-H264-rtx.sh b/tests/examples/rtp/client-H264-rtx.sh
new file mode 100755
index 0000000..fe53f60
--- /dev/null
+++ b/tests/examples/rtp/client-H264-rtx.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# A simple RTP receiver with retransmission
+#
+#  receives H264 encoded RTP video on port 5000, RTCP is received on  port 5001.
+#  the receiver RTCP reports are sent to port 5005
+#
+#             .-------.      .----------.     .---------.   .-------.   .-----------.
+#  RTP        |udpsrc |      | rtpbin   |     |h264depay|   |h264dec|   |xvimagesink|
+#  port=5000  |      src->recv_rtp recv_rtp->sink     src->sink   src->sink         |
+#             '-------'      |          |     '---------'   '-------'   '-----------'
+#                            |          |      
+#                            |          |     .-------.
+#                            |          |     |udpsink|  RTCP
+#                            |    send_rtcp->sink     | port=5005
+#             .-------.      |          |     '-------' sync=false
+#  RTCP       |udpsrc |      |          |               async=false
+#  port=5001  |     src->recv_rtcp      |                       
+#             '-------'      '----------'              
+
+
+# the caps of the sender RTP stream. This is usually negotiated out of band with
+# SDP or RTSP. normally these caps will also include SPS and PPS but we don't
+# have a mechanism to get this from the sender with a -launch line.
+VIDEO_CAPS="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H264"
+
+VIDEO_DEC="rtph264depay ! avdec_h264"
+
+VIDEO_SINK="videoconvert ! autovideosink"
+
+# the destination machine to send RTCP to. This is the address of the sender and
+# is used to send back the RTCP reports of this receiver. If the data is sent
+# from another machine, change this address.
+DEST=127.0.0.1
+
+LATENCY=200
+
+gst-launch-1.0 -v rtpbin name=rtpbin rtp-profile=avpf latency=$LATENCY do-retransmission=1 \
+    udpsrc caps=$VIDEO_CAPS port=5000 ! rtpbin.recv_rtp_sink_0                      \
+      rtpbin. ! $VIDEO_DEC ! $VIDEO_SINK                                            \
+    udpsrc port=5001 ! rtpbin.recv_rtcp_sink_0                                      \
+      rtpbin.send_rtcp_src_0 ! udpsink port=5005 host=$DEST sync=false async=false
diff --git a/tests/examples/rtp/client-H264.sdp b/tests/examples/rtp/client-H264.sdp
new file mode 100644
index 0000000..1e593b9
--- /dev/null
+++ b/tests/examples/rtp/client-H264.sdp
@@ -0,0 +1,10 @@
+v=0
+o=- 1188340656180883 1 IN IP4 127.0.0.1
+s=Session streamed by GStreamer
+i=server.sh
+t=0 0
+a=tool:GStreamer
+a=type:broadcast
+m=video 5000 RTP/AVP 96
+c=IN IP4 127.0.0.1
+a=rtpmap:96 H264/90000
diff --git a/tests/examples/rtp/client-H264.sh b/tests/examples/rtp/client-H264.sh
new file mode 100755
index 0000000..4901b4d
--- /dev/null
+++ b/tests/examples/rtp/client-H264.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# A simple RTP receiver 
+#
+#  receives H264 encoded RTP video on port 5000, RTCP is received on  port 5001.
+#  the receiver RTCP reports are sent to port 5005
+#
+#             .-------.      .----------.     .---------.   .-------.   .-----------.
+#  RTP        |udpsrc |      | rtpbin   |     |h264depay|   |h264dec|   |xvimagesink|
+#  port=5000  |      src->recv_rtp recv_rtp->sink     src->sink   src->sink         |
+#             '-------'      |          |     '---------'   '-------'   '-----------'
+#                            |          |      
+#                            |          |     .-------.
+#                            |          |     |udpsink|  RTCP
+#                            |    send_rtcp->sink     | port=5005
+#             .-------.      |          |     '-------' sync=false
+#  RTCP       |udpsrc |      |          |               async=false
+#  port=5001  |     src->recv_rtcp      |                       
+#             '-------'      '----------'              
+
+
+# the caps of the sender RTP stream. This is usually negotiated out of band with
+# SDP or RTSP. normally these caps will also include SPS and PPS but we don't
+# have a mechanism to get this from the sender with a -launch line.
+VIDEO_CAPS="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H264"
+
+VIDEO_DEC="rtph264depay ! avdec_h264"
+
+VIDEO_SINK="videoconvert ! autovideosink"
+
+# the destination machine to send RTCP to. This is the address of the sender and
+# is used to send back the RTCP reports of this receiver. If the data is sent
+# from another machine, change this address.
+DEST=127.0.0.1
+
+LATENCY=200
+
+gst-launch-1.0 -v rtpbin name=rtpbin latency=$LATENCY                                \
+    udpsrc caps=$VIDEO_CAPS port=5000 ! rtpbin.recv_rtp_sink_0                      \
+      rtpbin. ! $VIDEO_DEC ! $VIDEO_SINK                                            \
+    udpsrc port=5001 ! rtpbin.recv_rtcp_sink_0                                      \
+      rtpbin.send_rtcp_src_0 ! udpsink port=5005 host=$DEST sync=false async=false
diff --git a/tests/examples/rtp/client-PCMA.c b/tests/examples/rtp/client-PCMA.c
new file mode 100644
index 0000000..a1aa7f1
--- /dev/null
+++ b/tests/examples/rtp/client-PCMA.c
@@ -0,0 +1,243 @@
+/* GStreamer
+ * Copyright (C) 2009 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include <gst/gst.h>
+
+/*
+ * A simple RTP receiver 
+ *
+ *  receives alaw encoded RTP audio on port 5002, RTCP is received on  port 5003.
+ *  the receiver RTCP reports are sent to port 5007
+ *
+ *             .-------.      .----------.     .---------.   .-------.   .--------.
+ *  RTP        |udpsrc |      | rtpbin   |     |pcmadepay|   |alawdec|   |alsasink|
+ *  port=5002  |      src->recv_rtp recv_rtp->sink     src->sink   src->sink      |
+ *             '-------'      |          |     '---------'   '-------'   '--------'
+ *                            |          |      
+ *                            |          |     .-------.
+ *                            |          |     |udpsink|  RTCP
+ *                            |    send_rtcp->sink     | port=5007
+ *             .-------.      |          |     '-------' sync=false
+ *  RTCP       |udpsrc |      |          |               async=false
+ *  port=5003  |     src->recv_rtcp      |                       
+ *             '-------'      '----------'              
+ */
+
+/* the caps of the sender RTP stream. This is usually negotiated out of band with
+ * SDP or RTSP. */
+#define AUDIO_CAPS "application/x-rtp,media=(string)audio,clock-rate=(int)8000,encoding-name=(string)PCMA"
+
+#define AUDIO_DEPAY "rtppcmadepay"
+#define AUDIO_DEC   "alawdec"
+#define AUDIO_SINK  "autoaudiosink"
+
+/* the destination machine to send RTCP to. This is the address of the sender and
+ * is used to send back the RTCP reports of this receiver. If the data is sent
+ * from another machine, change this address. */
+#define DEST_HOST "127.0.0.1"
+
+/* print the stats of a source */
+static void
+print_source_stats (GObject * source)
+{
+  GstStructure *stats;
+  gchar *str;
+
+  g_return_if_fail (source != NULL);
+
+  /* get the source stats */
+  g_object_get (source, "stats", &stats, NULL);
+
+  /* simply dump the stats structure */
+  str = gst_structure_to_string (stats);
+  g_print ("source stats: %s\n", str);
+
+  gst_structure_free (stats);
+  g_free (str);
+}
+
+/* will be called when rtpbin signals on-ssrc-active. It means that an RTCP
+ * packet was received from another source. */
+static void
+on_ssrc_active_cb (GstElement * rtpbin, guint sessid, guint ssrc,
+    GstElement * depay)
+{
+  GObject *session, *osrc;
+
+  g_print ("got RTCP from session %u, SSRC %u\n", sessid, ssrc);
+
+  /* get the right session */
+  g_signal_emit_by_name (rtpbin, "get-internal-session", sessid, &session);
+
+#if 0
+  /* FIXME: This is broken in rtpbin */
+  /* get the internal source (the SSRC allocated to us, the receiver */
+  g_object_get (session, "internal-source", &isrc, NULL);
+  print_source_stats (isrc);
+  g_object_unref (isrc);
+#endif
+
+  /* get the remote source that sent us RTCP */
+  g_signal_emit_by_name (session, "get-source-by-ssrc", ssrc, &osrc);
+  print_source_stats (osrc);
+  g_object_unref (osrc);
+  g_object_unref (session);
+}
+
+/* will be called when rtpbin has validated a payload that we can depayload */
+static void
+pad_added_cb (GstElement * rtpbin, GstPad * new_pad, GstElement * depay)
+{
+  GstPad *sinkpad;
+  GstPadLinkReturn lres;
+
+  g_print ("new payload on pad: %s\n", GST_PAD_NAME (new_pad));
+
+  sinkpad = gst_element_get_static_pad (depay, "sink");
+  g_assert (sinkpad);
+
+  lres = gst_pad_link (new_pad, sinkpad);
+  g_assert (lres == GST_PAD_LINK_OK);
+  gst_object_unref (sinkpad);
+}
+
+/* build a pipeline equivalent to:
+ *
+ * gst-launch-1.0 -v rtpbin name=rtpbin                                                \
+ *      udpsrc caps=$AUDIO_CAPS port=5002 ! rtpbin.recv_rtp_sink_0              \
+ *        rtpbin. ! rtppcmadepay ! alawdec ! audioconvert ! audioresample ! autoaudiosink \
+ *      udpsrc port=5003 ! rtpbin.recv_rtcp_sink_0                              \
+ *        rtpbin.send_rtcp_src_0 ! udpsink port=5007 host=$DEST sync=false async=false
+ */
+int
+main (int argc, char *argv[])
+{
+  GstElement *rtpbin, *rtpsrc, *rtcpsrc, *rtcpsink;
+  GstElement *audiodepay, *audiodec, *audiores, *audioconv, *audiosink;
+  GstElement *pipeline;
+  GMainLoop *loop;
+  GstCaps *caps;
+  gboolean res;
+  GstPadLinkReturn lres;
+  GstPad *srcpad, *sinkpad;
+
+  /* always init first */
+  gst_init (&argc, &argv);
+
+  /* the pipeline to hold everything */
+  pipeline = gst_pipeline_new (NULL);
+  g_assert (pipeline);
+
+  /* the udp src and source we will use for RTP and RTCP */
+  rtpsrc = gst_element_factory_make ("udpsrc", "rtpsrc");
+  g_assert (rtpsrc);
+  g_object_set (rtpsrc, "port", 5002, NULL);
+  /* we need to set caps on the udpsrc for the RTP data */
+  caps = gst_caps_from_string (AUDIO_CAPS);
+  g_object_set (rtpsrc, "caps", caps, NULL);
+  gst_caps_unref (caps);
+
+  rtcpsrc = gst_element_factory_make ("udpsrc", "rtcpsrc");
+  g_assert (rtcpsrc);
+  g_object_set (rtcpsrc, "port", 5003, NULL);
+
+  rtcpsink = gst_element_factory_make ("udpsink", "rtcpsink");
+  g_assert (rtcpsink);
+  g_object_set (rtcpsink, "port", 5007, "host", DEST_HOST, NULL);
+  /* no need for synchronisation or preroll on the RTCP sink */
+  g_object_set (rtcpsink, "async", FALSE, "sync", FALSE, NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), rtpsrc, rtcpsrc, rtcpsink, NULL);
+
+  /* the depayloading and decoding */
+  audiodepay = gst_element_factory_make (AUDIO_DEPAY, "audiodepay");
+  g_assert (audiodepay);
+  audiodec = gst_element_factory_make (AUDIO_DEC, "audiodec");
+  g_assert (audiodec);
+  /* the audio playback and format conversion */
+  audioconv = gst_element_factory_make ("audioconvert", "audioconv");
+  g_assert (audioconv);
+  audiores = gst_element_factory_make ("audioresample", "audiores");
+  g_assert (audiores);
+  audiosink = gst_element_factory_make (AUDIO_SINK, "audiosink");
+  g_assert (audiosink);
+
+  /* add depayloading and playback to the pipeline and link */
+  gst_bin_add_many (GST_BIN (pipeline), audiodepay, audiodec, audioconv,
+      audiores, audiosink, NULL);
+
+  res = gst_element_link_many (audiodepay, audiodec, audioconv, audiores,
+      audiosink, NULL);
+  g_assert (res == TRUE);
+
+  /* the rtpbin element */
+  rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
+  g_assert (rtpbin);
+
+  gst_bin_add (GST_BIN (pipeline), rtpbin);
+
+  /* now link all to the rtpbin, start by getting an RTP sinkpad for session 0 */
+  srcpad = gst_element_get_static_pad (rtpsrc, "src");
+  sinkpad = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_0");
+  lres = gst_pad_link (srcpad, sinkpad);
+  g_assert (lres == GST_PAD_LINK_OK);
+  gst_object_unref (srcpad);
+
+  /* get an RTCP sinkpad in session 0 */
+  srcpad = gst_element_get_static_pad (rtcpsrc, "src");
+  sinkpad = gst_element_get_request_pad (rtpbin, "recv_rtcp_sink_0");
+  lres = gst_pad_link (srcpad, sinkpad);
+  g_assert (lres == GST_PAD_LINK_OK);
+  gst_object_unref (srcpad);
+  gst_object_unref (sinkpad);
+
+  /* get an RTCP srcpad for sending RTCP back to the sender */
+  srcpad = gst_element_get_request_pad (rtpbin, "send_rtcp_src_0");
+  sinkpad = gst_element_get_static_pad (rtcpsink, "sink");
+  lres = gst_pad_link (srcpad, sinkpad);
+  g_assert (lres == GST_PAD_LINK_OK);
+  gst_object_unref (sinkpad);
+
+  /* the RTP pad that we have to connect to the depayloader will be created
+   * dynamically so we connect to the pad-added signal, pass the depayloader as
+   * user_data so that we can link to it. */
+  g_signal_connect (rtpbin, "pad-added", G_CALLBACK (pad_added_cb), audiodepay);
+
+  /* give some stats when we receive RTCP */
+  g_signal_connect (rtpbin, "on-ssrc-active", G_CALLBACK (on_ssrc_active_cb),
+      audiodepay);
+
+  /* set the pipeline to playing */
+  g_print ("starting receiver pipeline\n");
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  /* we need to run a GLib main loop to get the messages */
+  loop = g_main_loop_new (NULL, FALSE);
+  g_main_loop_run (loop);
+
+  g_print ("stopping receiver pipeline\n");
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  gst_object_unref (pipeline);
+
+  return 0;
+}
diff --git a/tests/examples/rtp/client-PCMA.py b/tests/examples/rtp/client-PCMA.py
new file mode 100755
index 0000000..9d2fd42
--- /dev/null
+++ b/tests/examples/rtp/client-PCMA.py
@@ -0,0 +1,120 @@
+#! /usr/bin/env python
+
+import gi
+import sys
+gi.require_version('Gst', '1.0')
+from gi.repository import GObject, Gst
+
+#
+# A simple RTP receiver
+#
+#  receives alaw encoded RTP audio on port 5002, RTCP is received on  port 5003.
+#  the receiver RTCP reports are sent to port 5007
+#
+#             .-------.      .----------.     .---------.   .-------.   .--------.
+#  RTP        |udpsrc |      | rtpbin   |     |pcmadepay|   |alawdec|   |alsasink|
+#  port=5002  |      src->recv_rtp recv_rtp->sink     src->sink   src->sink      |
+#             '-------'      |          |     '---------'   '-------'   '--------'
+#                            |          |
+#                            |          |     .-------.
+#                            |          |     |udpsink|  RTCP
+#                            |    send_rtcp->sink     | port=5007
+#             .-------.      |          |     '-------' sync=false
+#  RTCP       |udpsrc |      |          |               async=false
+#  port=5003  |     src->recv_rtcp      |
+#             '-------'      '----------'
+
+AUDIO_CAPS = 'application/x-rtp,media=(string)audio,clock-rate=(int)8000,encoding-name=(string)PCMA'
+AUDIO_DEPAY = 'rtppcmadepay'
+AUDIO_DEC = 'alawdec'
+AUDIO_SINK = 'autoaudiosink'
+
+DEST = '127.0.0.1'
+
+RTP_RECV_PORT = 5002
+RTCP_RECV_PORT = 5003
+RTCP_SEND_PORT = 5007
+
+GObject.threads_init()
+Gst.init(sys.argv)
+
+#gst-launch -v rtpbin name=rtpbin                                                \
+#       udpsrc caps=$AUDIO_CAPS port=$RTP_RECV_PORT ! rtpbin.recv_rtp_sink_0              \
+#             rtpbin. ! rtppcmadepay ! alawdec ! audioconvert ! audioresample ! autoaudiosink \
+#           udpsrc port=$RTCP_RECV_PORT ! rtpbin.recv_rtcp_sink_0                              \
+#         rtpbin.send_rtcp_src_0 ! udpsink port=$RTCP_SEND_PORT host=$DEST sync=false async=false
+
+def pad_added_cb(rtpbin, new_pad, depay):
+    sinkpad = Gst.Element.get_static_pad(depay, 'sink')
+    lres = Gst.Pad.link(new_pad, sinkpad)
+
+# the pipeline to hold eveything
+pipeline = Gst.Pipeline('rtp_client')
+
+# the udp src and source we will use for RTP and RTCP
+rtpsrc = Gst.ElementFactory.make('udpsrc', 'rtpsrc')
+rtpsrc.set_property('port', RTP_RECV_PORT)
+
+# we need to set caps on the udpsrc for the RTP data
+caps = Gst.caps_from_string(AUDIO_CAPS)
+rtpsrc.set_property('caps', caps)
+
+rtcpsrc = Gst.ElementFactory.make('udpsrc', 'rtcpsrc')
+rtcpsrc.set_property('port', RTCP_RECV_PORT)
+
+rtcpsink = Gst.ElementFactory.make('udpsink', 'rtcpsink')
+rtcpsink.set_property('port', RTCP_SEND_PORT)
+rtcpsink.set_property('host', DEST)
+
+# no need for synchronisation or preroll on the RTCP sink
+rtcpsink.set_property('async', False)
+rtcpsink.set_property('sync', False)
+
+pipeline.add(rtpsrc, rtcpsrc, rtcpsink)
+
+# the depayloading and decoding
+audiodepay = Gst.ElementFactory.make(AUDIO_DEPAY, 'audiodepay')
+audiodec = Gst.ElementFactory.make(AUDIO_DEC, 'audiodec')
+
+# the audio playback and format conversion
+audioconv = Gst.ElementFactory.make('audioconvert', 'audioconv')
+audiores = Gst.ElementFactory.make('audioresample', 'audiores')
+audiosink = Gst.ElementFactory.make(AUDIO_SINK, 'audiosink')
+
+# add depayloading and playback to the pipeline and link
+pipeline.add(audiodepay, audiodec, audioconv, audiores, audiosink)
+
+audiodepay.link(audiodec)
+audiodec.link(audioconv)
+audioconv.link(audiores)
+audiores.link(audiosink)
+
+# the rtpbin element
+rtpbin = Gst.ElementFactory.make('rtpbin', 'rtpbin')
+
+pipeline.add(rtpbin)
+
+# now link all to the rtpbin, start by getting an RTP sinkpad for session 0
+srcpad = Gst.Element.get_static_pad(rtpsrc, 'src')
+sinkpad = Gst.Element.get_request_pad(rtpbin, 'recv_rtp_sink_0')
+lres = Gst.Pad.link(srcpad, sinkpad)
+
+# get an RTCP sinkpad in session 0
+srcpad = Gst.Element.get_static_pad(rtcpsrc, 'src')
+sinkpad = Gst.Element.get_request_pad(rtpbin, 'recv_rtcp_sink_0')
+lres = Gst.Pad.link(srcpad, sinkpad)
+
+# get an RTCP srcpad for sending RTCP back to the sender
+srcpad = Gst.Element.get_request_pad(rtpbin, 'send_rtcp_src_0')
+sinkpad = Gst.Element.get_static_pad(rtcpsink, 'sink')
+lres = Gst.Pad.link(srcpad, sinkpad)
+
+rtpbin.connect('pad-added', pad_added_cb, audiodepay)
+
+Gst.Element.set_state(pipeline, Gst.State.PLAYING)
+
+mainloop = GObject.MainLoop()
+mainloop.run()
+
+Gst.Element.set_state(pipeline, Gst.State.NULL)
+
diff --git a/tests/examples/rtp/client-PCMA.sdp b/tests/examples/rtp/client-PCMA.sdp
new file mode 100644
index 0000000..71f9d21
--- /dev/null
+++ b/tests/examples/rtp/client-PCMA.sdp
@@ -0,0 +1,9 @@
+v=0
+o=- 1188340656180883 1 IN IP4 127.0.0.1
+s=Session streamed by GStreamer
+i=server.sh
+t=0 0
+a=tool:GStreamer
+a=type:broadcast
+m=audio 5002 RTP/AVP 8
+c=IN IP4 127.0.0.1
diff --git a/tests/examples/rtp/client-PCMA.sh b/tests/examples/rtp/client-PCMA.sh
new file mode 100755
index 0000000..0e969b0
--- /dev/null
+++ b/tests/examples/rtp/client-PCMA.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+#
+# A simple RTP receiver
+#
+#  receives alaw encoded RTP audio on port 5002, RTCP is received on  port 5003.
+#  the receiver RTCP reports are sent to port 5007
+#
+#             .-------.      .----------.     .---------.   .-------.   .-------------.
+#  RTP        |udpsrc |      | rtpbin   |     |pcmadepay|   |alawdec|   |autoaudiosink|
+#  port=5002  |      src->recv_rtp recv_rtp->sink     src->sink   src->sink           |
+#             '-------'      |          |     '---------'   '-------'   '-------------'
+#                            |          |
+#                            |          |     .-------.
+#                            |          |     |udpsink|  RTCP
+#                            |    send_rtcp->sink     | port=5007
+#             .-------.      |          |     '-------' sync=false
+#  RTCP       |udpsrc |      |          |               async=false
+#  port=5003  |     src->recv_rtcp      |
+#             '-------'      '----------'
+
+
+# the caps of the sender RTP stream. This is usually negotiated out of band with
+# SDP or RTSP.
+AUDIO_CAPS="application/x-rtp,media=(string)audio,clock-rate=(int)8000,encoding-name=(string)PCMA"
+
+AUDIO_DEC="rtppcmadepay ! alawdec"
+
+AUDIO_SINK="audioconvert ! audioresample ! autoaudiosink"
+
+# the destination machine to send RTCP to. This is the address of the sender and
+# is used to send back the RTCP reports of this receiver. If the data is sent
+# from another machine, change this address.
+DEST=127.0.0.1
+
+gst-launch-1.0 -v rtpbin name=rtpbin                                                \
+	   udpsrc caps=$AUDIO_CAPS port=5002 ! rtpbin.recv_rtp_sink_0              \
+	         rtpbin. ! $AUDIO_DEC ! $AUDIO_SINK                                \
+           udpsrc port=5003 ! rtpbin.recv_rtcp_sink_0                              \
+         rtpbin.send_rtcp_src_0 ! udpsink port=5007 host=$DEST sync=false async=false
diff --git a/tests/examples/rtp/client-VP8-OPUS.sh b/tests/examples/rtp/client-VP8-OPUS.sh
new file mode 100755
index 0000000..220be71
--- /dev/null
+++ b/tests/examples/rtp/client-VP8-OPUS.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# A simple RTP receiver 
+#
+
+VIDEO_CAPS="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)VP8"
+AUDIO_CAPS="application/x-rtp,media=(string)audio,clock-rate=(int)48000,encoding-name=(string)OPUS"
+
+SRC=localhost
+DEST=localhost
+
+VIDEO_DEC="rtpvp8depay ! vp8dec"
+AUDIO_DEC="rtpopusdepay ! opusdec"
+
+VIDEO_SINK="videoconvert ! autovideosink"
+AUDIO_SINK="audioconvert ! audioresample ! autoaudiosink"
+
+LATENCY=100
+
+gst-launch-1.0 -v rtpbin name=rtpbin latency=$LATENCY                                    \
+           udpsrc caps=$VIDEO_CAPS address=$SRC port=5000 ! rtpbin.recv_rtp_sink_0                   \
+	         rtpbin. ! $VIDEO_DEC ! $VIDEO_SINK                                     \
+           udpsrc address=$SRC port=5001 ! rtpbin.recv_rtcp_sink_0                                   \
+           rtpbin.send_rtcp_src_0 ! udpsink host=$DEST port=5005 sync=false async=false \
+	   udpsrc caps=$AUDIO_CAPS address=$SRC port=5002 ! rtpbin.recv_rtp_sink_1                   \
+	         rtpbin. ! $AUDIO_DEC ! $AUDIO_SINK                                     \
+           udpsrc address=$SRC port=5003 ! rtpbin.recv_rtcp_sink_1                                   \
+           rtpbin.send_rtcp_src_1 ! udpsink host=$DEST port=5007 sync=false async=false
diff --git a/tests/examples/rtp/client-rtpaux.c b/tests/examples/rtp/client-rtpaux.c
new file mode 100644
index 0000000..890dc1a
--- /dev/null
+++ b/tests/examples/rtp/client-rtpaux.c
@@ -0,0 +1,380 @@
+/* GStreamer
+ * Copyright (C) 2013 Collabora Ltd.
+ *   @author Torrie Fischer <torrie.fischer@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <gst/gst.h>
+#include <gst/rtp/rtp.h>
+#include <stdlib.h>
+
+/*
+ * RTP receiver with RFC4588 retransmission handling enabled
+ *
+ *  In this example we have two RTP sessions, one for video and one for audio.
+ *  Video is received on port 5000, with its RTCP stream received on port 5001
+ *  and sent on port 5005. Audio is received on port 5005, with its RTCP stream
+ *  received on port 5006 and sent on port 5011.
+ *
+ *  In both sessions, we set "rtprtxreceive" as the session's "aux" element
+ *  in rtpbin, which enables RFC4588 retransmission handling for that session.
+ *
+ *             .-------.      .----------.        .-----------.   .---------.   .-------------.
+ *  RTP        |udpsrc |      | rtpbin   |        |theoradepay|   |theoradec|   |autovideosink|
+ *  port=5000  |      src->recv_rtp_0 recv_rtp_0->sink       src->sink     src->sink          |
+ *             '-------'      |          |        '-----------'   '---------'   '-------------'
+ *                            |          |
+ *                            |          |     .-------.
+ *                            |          |     |udpsink|  RTCP
+ *                            |  send_rtcp_0->sink     | port=5005
+ *             .-------.      |          |     '-------' sync=false
+ *  RTCP       |udpsrc |      |          |               async=false
+ *  port=5001  |     src->recv_rtcp_0    |
+ *             '-------'      |          |
+ *                            |          |
+ *             .-------.      |          |        .---------.   .-------.   .-------------.
+ *  RTP        |udpsrc |      |          |        |pcmadepay|   |alawdec|   |autoaudiosink|
+ *  port=5006  |      src->recv_rtp_1 recv_rtp_1->sink     src->sink   src->sink          |
+ *             '-------'      |          |        '---------'   '-------'   '-------------'
+ *                            |          |
+ *                            |          |     .-------.
+ *                            |          |     |udpsink|  RTCP
+ *                            |  send_rtcp_1->sink     | port=5011
+ *             .-------.      |          |     '-------' sync=false
+ *  RTCP       |udpsrc |      |          |               async=false
+ *  port=5007  |     src->recv_rtcp_1    |
+ *             '-------'      '----------'
+ *
+ */
+
+GMainLoop *loop = NULL;
+
+typedef struct _SessionData
+{
+  int ref;
+  GstElement *rtpbin;
+  guint sessionNum;
+  GstCaps *caps;
+  GstElement *output;
+} SessionData;
+
+static SessionData *
+session_ref (SessionData * data)
+{
+  g_atomic_int_inc (&data->ref);
+  return data;
+}
+
+static void
+session_unref (gpointer data)
+{
+  SessionData *session = (SessionData *) data;
+  if (g_atomic_int_dec_and_test (&session->ref)) {
+    g_object_unref (session->rtpbin);
+    gst_caps_unref (session->caps);
+    g_free (session);
+  }
+}
+
+static SessionData *
+session_new (guint sessionNum)
+{
+  SessionData *ret = g_new0 (SessionData, 1);
+  ret->sessionNum = sessionNum;
+  return session_ref (ret);
+}
+
+static void
+setup_ghost_sink (GstElement * sink, GstBin * bin)
+{
+  GstPad *sinkPad = gst_element_get_static_pad (sink, "sink");
+  GstPad *binPad = gst_ghost_pad_new ("sink", sinkPad);
+  gst_element_add_pad (GST_ELEMENT (bin), binPad);
+}
+
+static SessionData *
+make_audio_session (guint sessionNum)
+{
+  SessionData *ret = session_new (sessionNum);
+  GstBin *bin = GST_BIN (gst_bin_new ("audio"));
+  GstElement *queue = gst_element_factory_make ("queue", NULL);
+  GstElement *sink = gst_element_factory_make ("autoaudiosink", NULL);
+  GstElement *audioconvert = gst_element_factory_make ("audioconvert", NULL);
+  GstElement *audioresample = gst_element_factory_make ("audioresample", NULL);
+  GstElement *depayloader = gst_element_factory_make ("rtppcmadepay", NULL);
+  GstElement *decoder = gst_element_factory_make ("alawdec", NULL);
+
+  gst_bin_add_many (bin, queue, depayloader, decoder, audioconvert,
+      audioresample, sink, NULL);
+  gst_element_link_many (queue, depayloader, decoder, audioconvert,
+      audioresample, sink, NULL);
+
+  setup_ghost_sink (queue, bin);
+
+  ret->output = GST_ELEMENT (bin);
+  ret->caps = gst_caps_new_simple ("application/x-rtp",
+      "media", G_TYPE_STRING, "audio",
+      "clock-rate", G_TYPE_INT, 8000,
+      "encoding-name", G_TYPE_STRING, "PCMA", NULL);
+
+  return ret;
+}
+
+static SessionData *
+make_video_session (guint sessionNum)
+{
+  SessionData *ret = session_new (sessionNum);
+  GstBin *bin = GST_BIN (gst_bin_new ("video"));
+  GstElement *queue = gst_element_factory_make ("queue", NULL);
+  GstElement *depayloader = gst_element_factory_make ("rtptheoradepay", NULL);
+  GstElement *decoder = gst_element_factory_make ("theoradec", NULL);
+  GstElement *converter = gst_element_factory_make ("videoconvert", NULL);
+  GstElement *sink = gst_element_factory_make ("autovideosink", NULL);
+
+  gst_bin_add_many (bin, depayloader, decoder, converter, queue, sink, NULL);
+  gst_element_link_many (queue, depayloader, decoder, converter, sink, NULL);
+
+  setup_ghost_sink (queue, bin);
+
+  ret->output = GST_ELEMENT (bin);
+  ret->caps = gst_caps_new_simple ("application/x-rtp",
+      "media", G_TYPE_STRING, "video",
+      "clock-rate", G_TYPE_INT, 90000,
+      "encoding-name", G_TYPE_STRING, "THEORA", NULL);
+
+  return ret;
+}
+
+static GstCaps *
+request_pt_map (GstElement * rtpbin, guint session, guint pt,
+    gpointer user_data)
+{
+  SessionData *data = (SessionData *) user_data;
+  gchar *caps_str;
+  g_print ("Looking for caps for pt %u in session %u, have %u\n", pt, session,
+      data->sessionNum);
+  if (session == data->sessionNum) {
+    caps_str = gst_caps_to_string (data->caps);
+    g_print ("Returning %s\n", caps_str);
+    g_free (caps_str);
+    return gst_caps_ref (data->caps);
+  }
+  return NULL;
+}
+
+static void
+cb_eos (GstBus * bus, GstMessage * message, gpointer data)
+{
+  g_print ("Got EOS\n");
+  g_main_loop_quit (loop);
+}
+
+static void
+cb_state (GstBus * bus, GstMessage * message, gpointer data)
+{
+  GstObject *pipe = GST_OBJECT (data);
+  GstState old, new, pending;
+  gst_message_parse_state_changed (message, &old, &new, &pending);
+  if (message->src == pipe) {
+    g_print ("Pipeline %s changed state from %s to %s\n",
+        GST_OBJECT_NAME (message->src),
+        gst_element_state_get_name (old), gst_element_state_get_name (new));
+  }
+}
+
+static void
+cb_warning (GstBus * bus, GstMessage * message, gpointer data)
+{
+  GError *error = NULL;
+  gst_message_parse_warning (message, &error, NULL);
+  g_printerr ("Got warning from %s: %s\n", GST_OBJECT_NAME (message->src),
+      error->message);
+  g_error_free (error);
+}
+
+static void
+cb_error (GstBus * bus, GstMessage * message, gpointer data)
+{
+  GError *error = NULL;
+  gst_message_parse_error (message, &error, NULL);
+  g_printerr ("Got error from %s: %s\n", GST_OBJECT_NAME (message->src),
+      error->message);
+  g_error_free (error);
+  g_main_loop_quit (loop);
+}
+
+static void
+handle_new_stream (GstElement * element, GstPad * newPad, gpointer data)
+{
+  SessionData *session = (SessionData *) data;
+  gchar *padName;
+  gchar *myPrefix;
+
+  padName = gst_pad_get_name (newPad);
+  myPrefix = g_strdup_printf ("recv_rtp_src_%u", session->sessionNum);
+
+  g_print ("New pad: %s, looking for %s_*\n", padName, myPrefix);
+
+  if (g_str_has_prefix (padName, myPrefix)) {
+    GstPad *outputSinkPad;
+    GstElement *parent;
+
+    parent = GST_ELEMENT (gst_element_get_parent (session->rtpbin));
+    gst_bin_add (GST_BIN (parent), session->output);
+    gst_element_sync_state_with_parent (session->output);
+    gst_object_unref (parent);
+
+    outputSinkPad = gst_element_get_static_pad (session->output, "sink");
+    g_assert_cmpint (gst_pad_link (newPad, outputSinkPad), ==, GST_PAD_LINK_OK);
+    gst_object_unref (outputSinkPad);
+
+    g_print ("Linked!\n");
+  }
+  g_free (myPrefix);
+  g_free (padName);
+}
+
+static GstElement *
+request_aux_receiver (GstElement * rtpbin, guint sessid, SessionData * session)
+{
+  GstElement *rtx, *bin;
+  GstPad *pad;
+  gchar *name;
+  GstStructure *pt_map;
+
+  GST_INFO ("creating AUX receiver");
+  bin = gst_bin_new (NULL);
+  rtx = gst_element_factory_make ("rtprtxreceive", NULL);
+  pt_map = gst_structure_new ("application/x-rtp-pt-map",
+      "8", G_TYPE_UINT, 98, "96", G_TYPE_UINT, 99, NULL);
+  g_object_set (rtx, "payload-type-map", pt_map, NULL);
+  gst_structure_free (pt_map);
+  gst_bin_add (GST_BIN (bin), rtx);
+
+  pad = gst_element_get_static_pad (rtx, "src");
+  name = g_strdup_printf ("src_%u", sessid);
+  gst_element_add_pad (bin, gst_ghost_pad_new (name, pad));
+  g_free (name);
+  gst_object_unref (pad);
+
+  pad = gst_element_get_static_pad (rtx, "sink");
+  name = g_strdup_printf ("sink_%u", sessid);
+  gst_element_add_pad (bin, gst_ghost_pad_new (name, pad));
+  g_free (name);
+  gst_object_unref (pad);
+
+  return bin;
+}
+
+static void
+join_session (GstElement * pipeline, GstElement * rtpBin, SessionData * session)
+{
+  GstElement *rtpSrc;
+  GstElement *rtcpSrc;
+  GstElement *rtcpSink;
+  gchar *padName;
+  guint basePort;
+
+  g_print ("Joining session %p\n", session);
+
+  session->rtpbin = g_object_ref (rtpBin);
+
+  basePort = 5000 + (session->sessionNum * 6);
+
+  rtpSrc = gst_element_factory_make ("udpsrc", NULL);
+  rtcpSrc = gst_element_factory_make ("udpsrc", NULL);
+  rtcpSink = gst_element_factory_make ("udpsink", NULL);
+  g_object_set (rtpSrc, "port", basePort, "caps", session->caps, NULL);
+  g_object_set (rtcpSink, "port", basePort + 5, "host", "127.0.0.1", "sync",
+      FALSE, "async", FALSE, NULL);
+  g_object_set (rtcpSrc, "port", basePort + 1, NULL);
+
+  g_print ("Connecting to %i/%i/%i\n", basePort, basePort + 1, basePort + 5);
+
+  /* enable RFC4588 retransmission handling by setting rtprtxreceive
+   * as the "aux" element of rtpbin */
+  g_signal_connect (rtpBin, "request-aux-receiver",
+      (GCallback) request_aux_receiver, session);
+
+  gst_bin_add_many (GST_BIN (pipeline), rtpSrc, rtcpSrc, rtcpSink, NULL);
+
+  g_signal_connect_data (rtpBin, "pad-added", G_CALLBACK (handle_new_stream),
+      session_ref (session), (GClosureNotify) session_unref, 0);
+
+  g_signal_connect_data (rtpBin, "request-pt-map", G_CALLBACK (request_pt_map),
+      session_ref (session), (GClosureNotify) session_unref, 0);
+
+  padName = g_strdup_printf ("recv_rtp_sink_%u", session->sessionNum);
+  gst_element_link_pads (rtpSrc, "src", rtpBin, padName);
+  g_free (padName);
+
+  padName = g_strdup_printf ("recv_rtcp_sink_%u", session->sessionNum);
+  gst_element_link_pads (rtcpSrc, "src", rtpBin, padName);
+  g_free (padName);
+
+  padName = g_strdup_printf ("send_rtcp_src_%u", session->sessionNum);
+  gst_element_link_pads (rtpBin, padName, rtcpSink, "sink");
+  g_free (padName);
+
+  session_unref (session);
+}
+
+int
+main (int argc, char **argv)
+{
+  GstPipeline *pipe;
+  SessionData *videoSession;
+  SessionData *audioSession;
+  GstElement *rtpBin;
+  GstBus *bus;
+
+  gst_init (&argc, &argv);
+
+  loop = g_main_loop_new (NULL, FALSE);
+  pipe = GST_PIPELINE (gst_pipeline_new (NULL));
+
+  bus = gst_element_get_bus (GST_ELEMENT (pipe));
+  g_signal_connect (bus, "message::error", G_CALLBACK (cb_error), pipe);
+  g_signal_connect (bus, "message::warning", G_CALLBACK (cb_warning), pipe);
+  g_signal_connect (bus, "message::state-changed", G_CALLBACK (cb_state), pipe);
+  g_signal_connect (bus, "message::eos", G_CALLBACK (cb_eos), NULL);
+  gst_bus_add_signal_watch (bus);
+  gst_object_unref (bus);
+
+  rtpBin = gst_element_factory_make ("rtpbin", NULL);
+  gst_bin_add (GST_BIN (pipe), rtpBin);
+  g_object_set (rtpBin, "latency", 200, "do-retransmission", TRUE,
+      "rtp-profile", GST_RTP_PROFILE_AVPF, NULL);
+
+  videoSession = make_video_session (0);
+  audioSession = make_audio_session (1);
+
+  join_session (GST_ELEMENT (pipe), rtpBin, videoSession);
+  join_session (GST_ELEMENT (pipe), rtpBin, audioSession);
+
+  g_print ("starting client pipeline\n");
+  gst_element_set_state (GST_ELEMENT (pipe), GST_STATE_PLAYING);
+
+  g_main_loop_run (loop);
+
+  g_print ("stoping client pipeline\n");
+  gst_element_set_state (GST_ELEMENT (pipe), GST_STATE_NULL);
+
+  gst_object_unref (pipe);
+  g_main_loop_unref (loop);
+
+  return 0;
+}
diff --git a/tests/examples/rtp/client-rtpbundle.c b/tests/examples/rtp/client-rtpbundle.c
new file mode 100644
index 0000000..cd3a737
--- /dev/null
+++ b/tests/examples/rtp/client-rtpbundle.c
@@ -0,0 +1,266 @@
+/* GStreamer
+ * Copyright (C) 2016 Igalia S.L
+ *   @author Philippe Normand <philn@igalia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/gst.h>
+
+/*
+ * RTP bundle receiver
+ *
+ * In this example we initially create one RTP session but the incoming RTP
+ * and RTCP streams actually bundle 2 different media type, one audio stream
+ * and one video stream. We are notified of the discovery of the streams by
+ * the on-bundled-ssrc rtpbin signal. In the handler we decide to assign the
+ * first SSRC to the (existing) audio session and the second SSRC to a new
+ * session (id: 1).
+ *
+ *             .-------.      .----------.        .-----------.    .-------.    .-------------.
+ *  RTP        |udpsrc |      | rtpbin   |        | pcmadepay |    |alawdec|    |autoaudiosink|
+ *  port=5001  |      src->recv_rtp_0 recv_rtp_0->sink       src->sink    src->sink           |
+ *             '-------'      |          |        '-----------'    '-------'    '-------------'
+ *                            |          |
+ *                            |          |     .-------.
+ *                            |          |     |udpsink|  RTCP
+ *                            |  send_rtcp_0->sink     | port=5003
+ *             .-------.      |          |     '-------' sync=false
+ *  RTCP       |udpsrc |      |          |               async=false
+ *  port=5002  |     src->recv_rtcp_0    |
+ *             '-------'      |          |
+ *                            |          |
+ *                            |          |        .---------.    .-------------.
+ *                            |          |        |vrawdepay|    |autovideosink|
+ *                            |       recv_rtp_1->sink     src->sink           |
+ *                            |          |        '---------'    '-------------'
+ *                            |          |
+ *                            |          |     .-------.
+ *                            |          |     |udpsink|  RTCP
+ *                            |  send_rtcp_1->sink     | port=5004
+ *                            |          |     '-------' sync=false
+ *                            |          |               async=false
+ *                            |          |
+ *                            '----------'
+ *
+ */
+
+static gboolean
+plug_video_rtcp_sender (gpointer user_data)
+{
+  gint send_video_rtcp_port = 5004;
+  GstElement *rtpbin = GST_ELEMENT_CAST (user_data);
+  GstElement *send_video_rtcp_udpsink;
+  GstElement *pipeline =
+      GST_ELEMENT_CAST (gst_object_get_parent (GST_OBJECT (rtpbin)));
+
+  send_video_rtcp_udpsink = gst_element_factory_make ("udpsink", NULL);
+  g_object_set (send_video_rtcp_udpsink, "host", "127.0.0.1", NULL);
+  g_object_set (send_video_rtcp_udpsink, "port", send_video_rtcp_port, NULL);
+  g_object_set (send_video_rtcp_udpsink, "sync", FALSE, NULL);
+  g_object_set (send_video_rtcp_udpsink, "async", FALSE, NULL);
+  gst_bin_add (GST_BIN (pipeline), send_video_rtcp_udpsink);
+  gst_element_link_pads (rtpbin, "send_rtcp_src_1", send_video_rtcp_udpsink,
+      "sink");
+  gst_element_sync_state_with_parent (send_video_rtcp_udpsink);
+
+  gst_object_unref (pipeline);
+  gst_object_unref (rtpbin);
+  return G_SOURCE_REMOVE;
+}
+
+static void
+on_rtpbinreceive_pad_added (GstElement * rtpbin, GstPad * new_pad,
+    gpointer data)
+{
+  GstElement *pipeline = GST_ELEMENT (data);
+  gchar *pad_name = gst_pad_get_name (new_pad);
+
+  if (g_str_has_prefix (pad_name, "recv_rtp_src_")) {
+    GstCaps *caps = gst_pad_get_current_caps (new_pad);
+    GstStructure *s = gst_caps_get_structure (caps, 0);
+    const gchar *media_type = gst_structure_get_string (s, "media");
+    gchar *depayloader_name = g_strdup_printf ("%s_rtpdepayloader", media_type);
+    GstElement *rtpdepayloader =
+        gst_bin_get_by_name (GST_BIN (pipeline), depayloader_name);
+    GstPad *sinkpad;
+
+    g_free (depayloader_name);
+
+    sinkpad = gst_element_get_static_pad (rtpdepayloader, "sink");
+    gst_pad_link (new_pad, sinkpad);
+    gst_object_unref (sinkpad);
+    gst_object_unref (rtpdepayloader);
+
+    gst_caps_unref (caps);
+
+    if (g_str_has_prefix (pad_name, "recv_rtp_src_1")) {
+      g_timeout_add (0, plug_video_rtcp_sender, gst_object_ref (rtpbin));
+    }
+  }
+  g_free (pad_name);
+}
+
+static guint
+on_bundled_ssrc (GstElement * rtpbin, guint ssrc, gpointer user_data)
+{
+  static gboolean create_session = FALSE;
+  guint session_id = 0;
+
+  if (create_session) {
+    session_id = 1;
+  } else {
+    create_session = TRUE;
+    /* use existing session 0, a new session will be created for the next discovered bundled SSRC */
+  }
+  return session_id;
+}
+
+static GstCaps *
+on_request_pt_map (GstElement * rtpbin, guint session_id, guint pt,
+    gpointer user_data)
+{
+  GstCaps *caps = NULL;
+  if (pt == 96) {
+    caps =
+        gst_caps_from_string
+        ("application/x-rtp,media=(string)audio,encoding-name=(string)PCMA,clock-rate=(int)8000");
+  } else if (pt == 100) {
+    caps =
+        gst_caps_from_string
+        ("application/x-rtp,media=(string)video,encoding-name=(string)RAW,clock-rate=(int)90000,sampling=(string)\"YCbCr-4:2:0\",depth=(string)8,width=(string)320,height=(string)240");
+  }
+  return caps;
+}
+
+static GstElement *
+create_pipeline (void)
+{
+  GstElement *pipeline, *rtpbin, *recv_rtp_udpsrc, *recv_rtcp_udpsrc,
+      *audio_rtpdepayloader, *audio_decoder, *audio_sink, *video_rtpdepayloader,
+      *video_sink, *send_audio_rtcp_udpsink;
+  GstCaps *rtpcaps;
+  gint rtp_udp_port = 5001;
+  gint rtcp_udp_port = 5002;
+  gint send_audio_rtcp_port = 5003;
+
+  pipeline = gst_pipeline_new (NULL);
+
+  rtpbin = gst_element_factory_make ("rtpbin", NULL);
+  g_object_set (rtpbin, "latency", 200, NULL);
+
+  g_signal_connect (rtpbin, "on-bundled-ssrc",
+      G_CALLBACK (on_bundled_ssrc), NULL);
+  g_signal_connect (rtpbin, "request-pt-map",
+      G_CALLBACK (on_request_pt_map), NULL);
+
+  g_signal_connect (rtpbin, "pad-added",
+      G_CALLBACK (on_rtpbinreceive_pad_added), pipeline);
+
+  gst_bin_add (GST_BIN (pipeline), rtpbin);
+
+  recv_rtp_udpsrc = gst_element_factory_make ("udpsrc", NULL);
+  g_object_set (recv_rtp_udpsrc, "port", rtp_udp_port, NULL);
+  rtpcaps = gst_caps_from_string ("application/x-rtp");
+  g_object_set (recv_rtp_udpsrc, "caps", rtpcaps, NULL);
+  gst_caps_unref (rtpcaps);
+
+  recv_rtcp_udpsrc = gst_element_factory_make ("udpsrc", NULL);
+  g_object_set (recv_rtcp_udpsrc, "port", rtcp_udp_port, NULL);
+
+  audio_rtpdepayloader =
+      gst_element_factory_make ("rtppcmadepay", "audio_rtpdepayloader");
+  audio_decoder = gst_element_factory_make ("alawdec", NULL);
+  audio_sink = gst_element_factory_make ("autoaudiosink", NULL);
+
+  video_rtpdepayloader =
+      gst_element_factory_make ("rtpvrawdepay", "video_rtpdepayloader");
+  video_sink = gst_element_factory_make ("autovideosink", NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), recv_rtp_udpsrc, recv_rtcp_udpsrc,
+      audio_rtpdepayloader, audio_decoder, audio_sink, video_rtpdepayloader,
+      video_sink, NULL);
+
+  gst_element_link_pads (audio_rtpdepayloader, "src", audio_decoder, "sink");
+  gst_element_link (audio_decoder, audio_sink);
+
+  gst_element_link_pads (video_rtpdepayloader, "src", video_sink, "sink");
+
+  /* request a single receiving RTP session. */
+  gst_element_link_pads (recv_rtcp_udpsrc, "src", rtpbin, "recv_rtcp_sink_0");
+  gst_element_link_pads (recv_rtp_udpsrc, "src", rtpbin, "recv_rtp_sink_0");
+
+  send_audio_rtcp_udpsink = gst_element_factory_make ("udpsink", NULL);
+  g_object_set (send_audio_rtcp_udpsink, "host", "127.0.0.1", NULL);
+  g_object_set (send_audio_rtcp_udpsink, "port", send_audio_rtcp_port, NULL);
+  g_object_set (send_audio_rtcp_udpsink, "sync", FALSE, NULL);
+  g_object_set (send_audio_rtcp_udpsink, "async", FALSE, NULL);
+  gst_bin_add (GST_BIN (pipeline), send_audio_rtcp_udpsink);
+  gst_element_link_pads (rtpbin, "send_rtcp_src_0", send_audio_rtcp_udpsink,
+      "sink");
+
+  return pipeline;
+}
+
+/*
+ * Used to generate informative messages during pipeline startup
+ */
+static void
+cb_state (GstBus * bus, GstMessage * message, gpointer data)
+{
+  GstObject *pipe = GST_OBJECT (data);
+  GstState old, new, pending;
+  gst_message_parse_state_changed (message, &old, &new, &pending);
+  if (message->src == pipe) {
+    g_print ("Pipeline %s changed state from %s to %s\n",
+        GST_OBJECT_NAME (message->src),
+        gst_element_state_get_name (old), gst_element_state_get_name (new));
+    if (old == GST_STATE_PAUSED && new == GST_STATE_PLAYING)
+      GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (pipe), GST_DEBUG_GRAPH_SHOW_ALL,
+          GST_OBJECT_NAME (message->src));
+  }
+}
+
+int
+main (int argc, char **argv)
+{
+  GstElement *pipe;
+  GstBus *bus;
+  GMainLoop *loop;
+
+  gst_init (&argc, &argv);
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  pipe = create_pipeline ();
+  bus = gst_element_get_bus (pipe);
+  g_signal_connect (bus, "message::state-changed", G_CALLBACK (cb_state), pipe);
+  gst_bus_add_signal_watch (bus);
+  gst_object_unref (bus);
+
+  g_print ("starting server pipeline\n");
+  gst_element_set_state (pipe, GST_STATE_PLAYING);
+
+  g_main_loop_run (loop);
+
+  g_print ("stopping server pipeline\n");
+  gst_element_set_state (pipe, GST_STATE_NULL);
+
+  gst_object_unref (pipe);
+  g_main_loop_unref (loop);
+
+  return 0;
+}
diff --git a/tests/examples/rtp/meson.build b/tests/examples/rtp/meson.build
new file mode 100644
index 0000000..f728a12
--- /dev/null
+++ b/tests/examples/rtp/meson.build
@@ -0,0 +1,16 @@
+rtp_progs = [
+  'server-alsasrc-PCMA',
+  'client-PCMA',
+  'client-rtpaux',
+  'server-rtpaux',
+  'client-rtpbundle',
+  'server-rtpbundle',
+]
+
+foreach prog : rtp_progs
+  executable(prog, prog + '.c',
+    dependencies: [gstrtp_dep, gst_dep, libm],
+    c_args : gst_plugins_good_args,
+    include_directories : [configinc],
+    install: false)
+endforeach
diff --git a/tests/examples/rtp/server-VTS-H263p-ATS-PCMA.sh b/tests/examples/rtp/server-VTS-H263p-ATS-PCMA.sh
new file mode 100755
index 0000000..7c736fc
--- /dev/null
+++ b/tests/examples/rtp/server-VTS-H263p-ATS-PCMA.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+#
+# A simple RTP server 
+#
+
+VCAPS="video/x-raw,width=352,height=288,framerate=15/1"
+
+gst-launch-1.0 -v rtpbin name=rtpbin \
+           videotestsrc ! $VCAPS ! avenc_h263p ! rtph263ppay ! rtpbin.send_rtp_sink_0          \
+                     rtpbin.send_rtp_src_0 ! udpsink port=5000                                 \
+                     rtpbin.send_rtcp_src_0 ! udpsink port=5001 sync=false async=false         \
+                     udpsrc port=5005 ! rtpbin.recv_rtcp_sink_0                                \
+           audiotestsrc samplesperbuffer=1000 ! alawenc ! rtppcmapay ! rtpbin.send_rtp_sink_1  \
+	             rtpbin.send_rtp_src_1 ! udpsink port=5002                                 \
+	             rtpbin.send_rtcp_src_1 ! udpsink port=5003 sync=false async=false         \
+                     udpsrc port=5007 ! rtpbin.recv_rtcp_sink_1
diff --git a/tests/examples/rtp/server-VTS-H263p.sh b/tests/examples/rtp/server-VTS-H263p.sh
new file mode 100755
index 0000000..b2f9880
--- /dev/null
+++ b/tests/examples/rtp/server-VTS-H263p.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+#
+# A simple RTP server 
+#  sends the output of videotestsrc as h263+ encoded RTP on port 5000, RTCP is sent on
+#  port 5001. The destination is 127.0.0.1.
+#  the video receiver RTCP reports are received on port 5005
+#
+# .-------.    .-------.    .-------.      .----------.     .-------.
+# |vts    |    |h263enc|    |h263pay|      | rtpbin   |     |udpsink|  RTP
+# |      src->sink    src->sink    src->send_rtp send_rtp->sink     | port=5000
+# '-------'    '-------'    '-------'      |          |     '-------'
+#                                          |          |      
+#                                          |          |     .-------.
+#                                          |          |     |udpsink|  RTCP
+#                                          |    send_rtcp->sink     | port=5001
+#                           .-------.      |          |     '-------' sync=false
+#                RTCP       |udpsrc |      |          |               async=false
+#              port=5005    |     src->recv_rtcp      |                       
+#                           '-------'      '----------'              
+#
+
+# change this to send the RTP data and RTCP to another host
+DEST=127.0.0.1
+
+# tuning parameters to make the sender send the streams out of sync. Can be used
+# ot test the client RTCP synchronisation. 
+#VOFFSET=900000000
+VOFFSET=0
+AOFFSET=0
+
+# H263+ encode from the source
+VELEM="videotestsrc is-live=1"
+VCAPS="video/x-raw,width=352,height=288,framerate=15/1"
+VSOURCE="$VELEM ! $VCAPS"
+VENC="avenc_h263p ! rtph263ppay"
+
+VRTPSINK="udpsink port=5000 host=$DEST ts-offset=$VOFFSET name=vrtpsink"
+VRTCPSINK="udpsink port=5001 host=$DEST sync=false async=false name=vrtcpsink"
+VRTCPSRC="udpsrc port=5005 name=vrtpsrc"
+
+PIPELINE="rtpbin name=rtpbin
+            $VSOURCE ! $VENC ! rtpbin.send_rtp_sink_2
+	      rtpbin.send_rtp_src_2 ! $VRTPSINK 
+              rtpbin.send_rtcp_src_2 ! $VRTCPSINK
+            $VRTCPSRC ! rtpbin.recv_rtcp_sink_2"
+
+echo $PIPELINE
+
+gst-launch-1.0 -v $PIPELINE
diff --git a/tests/examples/rtp/server-VTS-H264-rtx.sh b/tests/examples/rtp/server-VTS-H264-rtx.sh
new file mode 100755
index 0000000..fdb3d20
--- /dev/null
+++ b/tests/examples/rtp/server-VTS-H264-rtx.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# A simple RTP server with retransmission
+#  sends the output of videotestsrc as h264 encoded RTP on port 5000, RTCP is sent on
+#  port 5001. The destination is 127.0.0.1.
+#  the video receiver RTCP reports are received on port 5005
+#
+#  .-------.    .-------.    .-------.      .----------.     .-------.
+#  |videots|    |h264enc|    |h264pay|      | rtpbin   |     |udpsink|  RTP
+#  |      src->sink    src->sink    src->send_rtp send_rtp->sink     | port=5000
+#  '-------'    '-------'    '-------'      |          |     '-------'
+#                                           |          |
+#                                           |          |     .-------.
+#                                           |          |     |udpsink|  RTCP
+#                                           |    send_rtcp->sink     | port=5001
+#                            .-------.      |          |     '-------' sync=false
+#                 RTCP       |udpsrc |      |          |               async=false
+#               port=5005    |     src->recv_rtcp      |
+#                            '-------'      '----------'
+#
+# ideally we should transport the properties on the RTP udpsink pads to the
+# receiver in order to transmit the SPS and PPS earlier.
+
+# change this to send the RTP data and RTCP to another host
+DEST=127.0.0.1
+
+# tuning parameters to make the sender send the streams out of sync. Can be used
+# ot test the client RTCP synchronisation.
+#VOFFSET=900000000
+VOFFSET=0
+AOFFSET=0
+
+# H264 encode from the source
+VELEM="videotestsrc is-live=1 horizontal-speed=1"
+VCAPS="video/x-raw,width=352,height=288,framerate=15/1"
+VSOURCE="$VELEM ! $VCAPS"
+VENC="x264enc tune=zerolatency bitrate=300 ! rtph264pay config-interval=2"
+
+VRTPSINK="udpsink port=5000 host=$DEST ts-offset=$VOFFSET name=vrtpsink"
+VRTCPSINK="udpsink port=5001 host=$DEST sync=false async=false name=vrtcpsink"
+VRTCPSRC="udpsrc port=5005 name=vrtpsrc"
+
+gst-launch-1.0 -v rtpbin name=rtpbin rtp-profile=avpf \
+    $VSOURCE ! $VENC ! rtprtxqueue ! rtpbin.send_rtp_sink_0                               \
+        rtpbin.send_rtp_src_0 ! identity drop-probability=0.1 ! $VRTPSINK                 \
+        rtpbin.send_rtcp_src_0 ! $VRTCPSINK                                               \
+      $VRTCPSRC ! rtpbin.recv_rtcp_sink_0
diff --git a/tests/examples/rtp/server-VTS-VP8-ATS-OPUS.sh b/tests/examples/rtp/server-VTS-VP8-ATS-OPUS.sh
new file mode 100755
index 0000000..ef87004
--- /dev/null
+++ b/tests/examples/rtp/server-VTS-VP8-ATS-OPUS.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+#
+# A simple RTP server 
+#
+
+SRC=localhost
+DEST=localhost
+VCAPS="video/x-raw,width=352,height=288,framerate=15/1"
+
+gst-launch-1.0 -v rtpbin name=rtpbin \
+           videotestsrc ! $VCAPS ! vp8enc ! rtpvp8pay ! rtpbin.send_rtp_sink_0          \
+                     rtpbin.send_rtp_src_0 ! udpsink host=$DEST port=5000                                 \
+                     rtpbin.send_rtcp_src_0 ! udpsink host=$DEST port=5001 sync=false async=false         \
+                     udpsrc address=$SRC  port=5005 ! rtpbin.recv_rtcp_sink_0                                \
+           audiotestsrc ! opusenc ! rtpopuspay ! rtpbin.send_rtp_sink_1  \
+	             rtpbin.send_rtp_src_1 ! udpsink host=$DEST port=5002                                 \
+	             rtpbin.send_rtcp_src_1 ! udpsink host=$DEST port=5003 sync=false async=false         \
+                     udpsrc address=$SRC port=5007 ! rtpbin.recv_rtcp_sink_1
diff --git a/tests/examples/rtp/server-alsasrc-PCMA.c b/tests/examples/rtp/server-alsasrc-PCMA.c
new file mode 100644
index 0000000..af8f7de
--- /dev/null
+++ b/tests/examples/rtp/server-alsasrc-PCMA.c
@@ -0,0 +1,225 @@
+/* GStreamer
+ * Copyright (C) 2009 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <string.h>
+#include <math.h>
+
+#include <gst/gst.h>
+
+/*
+ * A simple RTP server 
+ *  sends the output of alsasrc as alaw encoded RTP on port 5002, RTCP is sent on
+ *  port 5003. The destination is 127.0.0.1.
+ *  the receiver RTCP reports are received on port 5007
+ *
+ * .-------.    .-------.    .-------.      .----------.     .-------.
+ * |alsasrc|    |alawenc|    |pcmapay|      | rtpbin   |     |udpsink|  RTP
+ * |      src->sink    src->sink    src->send_rtp send_rtp->sink     | port=5002
+ * '-------'    '-------'    '-------'      |          |     '-------'
+ *                                          |          |      
+ *                                          |          |     .-------.
+ *                                          |          |     |udpsink|  RTCP
+ *                                          |    send_rtcp->sink     | port=5003
+ *                           .-------.      |          |     '-------' sync=false
+ *                RTCP       |udpsrc |      |          |               async=false
+ *              port=5007    |     src->recv_rtcp      |                       
+ *                           '-------'      '----------'              
+ */
+
+/* change this to send the RTP data and RTCP to another host */
+#define DEST_HOST "127.0.0.1"
+
+/* #define AUDIO_SRC  "alsasrc" */
+#define AUDIO_SRC  "audiotestsrc"
+
+/* the encoder and payloader elements */
+#define AUDIO_ENC  "alawenc"
+#define AUDIO_PAY  "rtppcmapay"
+
+/* print the stats of a source */
+static void
+print_source_stats (GObject * source)
+{
+  GstStructure *stats;
+  gchar *str;
+
+  /* get the source stats */
+  g_object_get (source, "stats", &stats, NULL);
+
+  /* simply dump the stats structure */
+  str = gst_structure_to_string (stats);
+  g_print ("source stats: %s\n", str);
+
+  gst_structure_free (stats);
+  g_free (str);
+}
+
+/* this function is called every second and dumps the RTP manager stats */
+static gboolean
+print_stats (GstElement * rtpbin)
+{
+  GObject *session;
+  GValueArray *arr;
+  GValue *val;
+  guint i;
+
+  g_print ("***********************************\n");
+
+  /* get session 0 */
+  g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
+
+  /* print all the sources in the session, this includes the internal source */
+  g_object_get (session, "sources", &arr, NULL);
+
+  for (i = 0; i < arr->n_values; i++) {
+    GObject *source;
+
+    val = g_value_array_get_nth (arr, i);
+    source = g_value_get_object (val);
+
+    print_source_stats (source);
+  }
+  g_value_array_free (arr);
+
+  g_object_unref (session);
+
+  return TRUE;
+}
+
+/* build a pipeline equivalent to:
+ *
+ * gst-launch-1.0 -v rtpbin name=rtpbin \
+ *    $AUDIO_SRC ! audioconvert ! audioresample ! $AUDIO_ENC ! $AUDIO_PAY ! rtpbin.send_rtp_sink_0  \
+ *           rtpbin.send_rtp_src_0 ! udpsink port=5002 host=$DEST                      \
+ *           rtpbin.send_rtcp_src_0 ! udpsink port=5003 host=$DEST sync=false async=false \
+ *        udpsrc port=5007 ! rtpbin.recv_rtcp_sink_0
+ */
+int
+main (int argc, char *argv[])
+{
+  GstElement *audiosrc, *audioconv, *audiores, *audioenc, *audiopay;
+  GstElement *rtpbin, *rtpsink, *rtcpsink, *rtcpsrc;
+  GstElement *pipeline;
+  GMainLoop *loop;
+  GstPad *srcpad, *sinkpad;
+
+  /* always init first */
+  gst_init (&argc, &argv);
+
+  /* the pipeline to hold everything */
+  pipeline = gst_pipeline_new (NULL);
+  g_assert (pipeline);
+
+  /* the audio capture and format conversion */
+  audiosrc = gst_element_factory_make (AUDIO_SRC, "audiosrc");
+  g_assert (audiosrc);
+  audioconv = gst_element_factory_make ("audioconvert", "audioconv");
+  g_assert (audioconv);
+  audiores = gst_element_factory_make ("audioresample", "audiores");
+  g_assert (audiores);
+  /* the encoding and payloading */
+  audioenc = gst_element_factory_make (AUDIO_ENC, "audioenc");
+  g_assert (audioenc);
+  audiopay = gst_element_factory_make (AUDIO_PAY, "audiopay");
+  g_assert (audiopay);
+
+  /* add capture and payloading to the pipeline and link */
+  gst_bin_add_many (GST_BIN (pipeline), audiosrc, audioconv, audiores,
+      audioenc, audiopay, NULL);
+
+  if (!gst_element_link_many (audiosrc, audioconv, audiores, audioenc,
+          audiopay, NULL)) {
+    g_error ("Failed to link audiosrc, audioconv, audioresample, "
+        "audio encoder and audio payloader");
+  }
+
+  /* the rtpbin element */
+  rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
+  g_assert (rtpbin);
+
+  gst_bin_add (GST_BIN (pipeline), rtpbin);
+
+  /* the udp sinks and source we will use for RTP and RTCP */
+  rtpsink = gst_element_factory_make ("udpsink", "rtpsink");
+  g_assert (rtpsink);
+  g_object_set (rtpsink, "port", 5002, "host", DEST_HOST, NULL);
+
+  rtcpsink = gst_element_factory_make ("udpsink", "rtcpsink");
+  g_assert (rtcpsink);
+  g_object_set (rtcpsink, "port", 5003, "host", DEST_HOST, NULL);
+  /* no need for synchronisation or preroll on the RTCP sink */
+  g_object_set (rtcpsink, "async", FALSE, "sync", FALSE, NULL);
+
+  rtcpsrc = gst_element_factory_make ("udpsrc", "rtcpsrc");
+  g_assert (rtcpsrc);
+  g_object_set (rtcpsrc, "port", 5007, NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), rtpsink, rtcpsink, rtcpsrc, NULL);
+
+  /* now link all to the rtpbin, start by getting an RTP sinkpad for session 0 */
+  sinkpad = gst_element_get_request_pad (rtpbin, "send_rtp_sink_0");
+  srcpad = gst_element_get_static_pad (audiopay, "src");
+  if (gst_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK)
+    g_error ("Failed to link audio payloader to rtpbin");
+  gst_object_unref (srcpad);
+
+  /* get the RTP srcpad that was created when we requested the sinkpad above and
+   * link it to the rtpsink sinkpad*/
+  srcpad = gst_element_get_static_pad (rtpbin, "send_rtp_src_0");
+  sinkpad = gst_element_get_static_pad (rtpsink, "sink");
+  if (gst_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK)
+    g_error ("Failed to link rtpbin to rtpsink");
+  gst_object_unref (srcpad);
+  gst_object_unref (sinkpad);
+
+  /* get an RTCP srcpad for sending RTCP to the receiver */
+  srcpad = gst_element_get_request_pad (rtpbin, "send_rtcp_src_0");
+  sinkpad = gst_element_get_static_pad (rtcpsink, "sink");
+  if (gst_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK)
+    g_error ("Failed to link rtpbin to rtcpsink");
+  gst_object_unref (sinkpad);
+
+  /* we also want to receive RTCP, request an RTCP sinkpad for session 0 and
+   * link it to the srcpad of the udpsrc for RTCP */
+  srcpad = gst_element_get_static_pad (rtcpsrc, "src");
+  sinkpad = gst_element_get_request_pad (rtpbin, "recv_rtcp_sink_0");
+  if (gst_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK)
+    g_error ("Failed to link rtcpsrc to rtpbin");
+  gst_object_unref (srcpad);
+
+  /* set the pipeline to playing */
+  g_print ("starting sender pipeline\n");
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  /* print stats every second */
+  g_timeout_add_seconds (1, (GSourceFunc) print_stats, rtpbin);
+
+  /* we need to run a GLib main loop to get the messages */
+  loop = g_main_loop_new (NULL, FALSE);
+  g_main_loop_run (loop);
+
+  g_print ("stopping sender pipeline\n");
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  return 0;
+}
diff --git a/tests/examples/rtp/server-alsasrc-PCMA.py b/tests/examples/rtp/server-alsasrc-PCMA.py
new file mode 100755
index 0000000..37276a4
--- /dev/null
+++ b/tests/examples/rtp/server-alsasrc-PCMA.py
@@ -0,0 +1,98 @@
+#! /usr/bin/env python
+
+import gi
+import sys
+gi.require_version('Gst', '1.0')
+from gi.repository import GObject, Gst
+
+
+#gst-launch -v rtpbin name=rtpbin audiotestsrc ! audioconvert ! alawenc ! rtppcmapay ! rtpbin.send_rtp_sink_0 \
+#                rtpbin.send_rtp_src_0 ! udpsink port=10000 host=xxx.xxx.xxx.xxx \
+#                rtpbin.send_rtcp_src_0 ! udpsink port=10001 host=xxx.xxx.xxx.xxx sync=false async=false \
+#                udpsrc port=10002 ! rtpbin.recv_rtcp_sink_0
+
+DEST_HOST = '127.0.0.1'
+
+AUDIO_SRC = 'audiotestsrc'
+AUDIO_ENC = 'alawenc'
+AUDIO_PAY = 'rtppcmapay'
+
+RTP_SEND_PORT = 5002
+RTCP_SEND_PORT = 5003
+RTCP_RECV_PORT = 5007
+
+GObject.threads_init()
+Gst.init(sys.argv)
+
+# the pipeline to hold everything
+pipeline = Gst.Pipeline('rtp_server')
+
+# the pipeline to hold everything
+audiosrc = Gst.ElementFactory.make(AUDIO_SRC, 'audiosrc')
+audioconv = Gst.ElementFactory.make('audioconvert', 'audioconv')
+audiores = Gst.ElementFactory.make('audioresample', 'audiores')
+
+# the pipeline to hold everything
+audioenc = Gst.ElementFactory.make(AUDIO_ENC, 'audioenc')
+audiopay = Gst.ElementFactory.make(AUDIO_PAY, 'audiopay')
+
+# add capture and payloading to the pipeline and link
+pipeline.add(audiosrc, audioconv, audiores, audioenc, audiopay)
+
+audiosrc.link(audioconv)
+audioconv.link(audiores)
+audiores.link(audioenc)
+audioenc.link(audiopay)
+
+# the rtpbin element
+rtpbin = Gst.ElementFactory.make('rtpbin', 'rtpbin')
+
+pipeline.add(rtpbin)
+
+# the udp sinks and source we will use for RTP and RTCP
+rtpsink = Gst.ElementFactory.make('udpsink', 'rtpsink')
+rtpsink.set_property('port', RTP_SEND_PORT)
+rtpsink.set_property('host', DEST_HOST)
+
+rtcpsink = Gst.ElementFactory.make('udpsink', 'rtcpsink')
+rtcpsink.set_property('port', RTCP_SEND_PORT)
+rtcpsink.set_property('host', DEST_HOST)
+# no need for synchronisation or preroll on the RTCP sink
+rtcpsink.set_property('async', False)
+rtcpsink.set_property('sync', False)
+
+rtcpsrc = Gst.ElementFactory.make('udpsrc', 'rtcpsrc')
+rtcpsrc.set_property('port', RTCP_RECV_PORT)
+
+pipeline.add(rtpsink, rtcpsink, rtcpsrc)
+
+# now link all to the rtpbin, start by getting an RTP sinkpad for session 0
+sinkpad = Gst.Element.get_request_pad(rtpbin, 'send_rtp_sink_0')
+srcpad = Gst.Element.get_static_pad(audiopay, 'src')
+lres = Gst.Pad.link(srcpad, sinkpad)
+
+# get the RTP srcpad that was created when we requested the sinkpad above and
+# link it to the rtpsink sinkpad
+srcpad = Gst.Element.get_static_pad(rtpbin, 'send_rtp_src_0')
+sinkpad = Gst.Element.get_static_pad(rtpsink, 'sink')
+lres = Gst.Pad.link(srcpad, sinkpad)
+
+# get an RTCP srcpad for sending RTCP to the receiver
+srcpad = Gst.Element.get_request_pad(rtpbin, 'send_rtcp_src_0')
+sinkpad = Gst.Element.get_static_pad(rtcpsink, 'sink')
+lres = Gst.Pad.link(srcpad, sinkpad)
+
+# we also want to receive RTCP, request an RTCP sinkpad for session 0 and
+# link it to the srcpad of the udpsrc for RTCP
+srcpad = Gst.Element.get_static_pad(rtcpsrc, 'src')
+sinkpad = Gst.Element.get_request_pad(rtpbin, 'recv_rtcp_sink_0')
+lres = Gst.Pad.link(srcpad, sinkpad)
+
+# set the pipeline to playing
+Gst.Element.set_state(pipeline, Gst.State.PLAYING)
+
+# we need to run a GLib main loop to get the messages
+mainloop = GObject.MainLoop()
+mainloop.run()
+
+Gst.Element.set_state(pipeline, Gst.State.NULL)
diff --git a/tests/examples/rtp/server-alsasrc-PCMA.sh b/tests/examples/rtp/server-alsasrc-PCMA.sh
new file mode 100755
index 0000000..aafe09b
--- /dev/null
+++ b/tests/examples/rtp/server-alsasrc-PCMA.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+# A simple RTP server
+#  sends the output of autoaudiosrc as alaw encoded RTP on port 5002, RTCP is sent on
+#  port 5003. The destination is 127.0.0.1.
+#  the receiver RTCP reports are received on port 5007
+#
+# .--------.    .-------.    .-------.      .----------.     .-------.
+# |audiosrc|    |alawenc|    |pcmapay|      | rtpbin   |     |udpsink|  RTP
+# |       src->sink    src->sink    src->send_rtp send_rtp->sink     | port=5002
+# '--------'    '-------'    '-------'      |          |     '-------'
+#                                           |          |
+#                                           |          |     .-------.
+#                                           |          |     |udpsink|  RTCP
+#                                           |    send_rtcp->sink     | port=5003
+#                            .-------.      |          |     '-------' sync=false
+#                 RTCP       |udpsrc |      |          |               async=false
+#               port=5007    |     src->recv_rtcp      |
+#                            '-------'      '----------'
+
+# change this to send the RTP data and RTCP to another host
+DEST=127.0.0.1
+
+#AELEM=autoaudiosrc
+AELEM=audiotestsrc
+
+# PCMA encode from an the source
+ASOURCE="$AELEM ! audioconvert"
+AENC="alawenc ! rtppcmapay"
+
+gst-launch-1.0 -v rtpbin name=rtpbin \
+     $ASOURCE ! $AENC ! rtpbin.send_rtp_sink_0  \
+            rtpbin.send_rtp_src_0 ! udpsink port=5002 host=$DEST                      \
+            rtpbin.send_rtcp_src_0 ! udpsink port=5003 host=$DEST sync=false async=false \
+         udpsrc port=5007 ! rtpbin.recv_rtcp_sink_0
diff --git a/tests/examples/rtp/server-decodebin-H263p-AMR.sh b/tests/examples/rtp/server-decodebin-H263p-AMR.sh
new file mode 100755
index 0000000..67e9826
--- /dev/null
+++ b/tests/examples/rtp/server-decodebin-H263p-AMR.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# A simple RTP server 
+#
+# Transcodes and streams audio and video to H263p and AMR respectively from any
+# file that is decodable by decodebin.
+#
+# use ./client-H263p-AMR.sh to receive the RTP stream.
+#
+
+# change these to change the server sync. This causes the server to send the
+# packets largly out-of-sync, the client should use the RTCP SR packets to
+# restore proper lip-sync between the streams.
+AOFFSET=0
+VOFFSET=0
+
+# encoder seems to be picky about PAR, so force one that should work
+VCAPS="video/x-raw,width=352,height=288,framerate=15/1,pixel-aspect-ratio=1/1"
+
+# video and audio encoding and payloading
+VENCPAY="avenc_h263p ! rtph263ppay"
+AENCPAY="amrnbenc ! rtpamrpay"
+
+# video conversion 
+VCONV="videoconvert ! videoscale ! videorate ! $VCAPS ! videoconvert"
+
+ACONV="audioconvert ! audioresample"
+
+#HOST=192.168.1.126
+HOST=127.0.0.1
+
+if test -z "$1"; then
+  echo "No URI argument.";
+  echo "Usage: $0 file:///path/to/video.file";
+  exit 1;
+fi
+
+gst-launch-1.0 -v rtpbin name=rtpbin \
+           uridecodebin uri="$1" name=decode \
+           decode. ! $VCONV ! $VENCPAY ! rtpbin.send_rtp_sink_0      \
+                     rtpbin.send_rtp_src_0 ! queue ! udpsink host=$HOST port=5000 ts-offset=$AOFFSET      \
+                     rtpbin.send_rtcp_src_0 ! udpsink host=$HOST port=5001 sync=false async=false         \
+                     udpsrc port=5005 ! rtpbin.recv_rtcp_sink_0                                           \
+           decode. ! $ACONV ! $AENCPAY ! rtpbin.send_rtp_sink_1                         \
+	             rtpbin.send_rtp_src_1 ! queue ! udpsink host=$HOST port=5002 ts-offset=$VOFFSET      \
+	             rtpbin.send_rtcp_src_1 ! udpsink host=$HOST port=5003 sync=false async=false         \
+                     udpsrc port=5007 ! rtpbin.recv_rtcp_sink_1
diff --git a/tests/examples/rtp/server-rtpaux.c b/tests/examples/rtp/server-rtpaux.c
new file mode 100644
index 0000000..b027f2f
--- /dev/null
+++ b/tests/examples/rtp/server-rtpaux.c
@@ -0,0 +1,297 @@
+/* GStreamer
+ * Copyright (C) 2013 Collabora Ltd.
+ *   @author Torrie Fischer <torrie.fischer@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <gst/gst.h>
+#include <gst/rtp/rtp.h>
+
+/*
+ * An RTP server
+ *  creates two sessions and streams audio on one, video on the other, with RTCP
+ *  on both sessions. The destination is 127.0.0.1.
+ *
+ *  In both sessions, we set "rtprtxsend" as the session's "aux" element
+ *  in rtpbin, which enables RFC4588 retransmission for that session.
+ *
+ *  .-------.    .-------.    .-------.      .------------.       .-------.
+ *  |audiots|    |alawenc|    |pcmapay|      | rtpbin     |       |udpsink|
+ *  |      src->sink    src->sink    src->send_rtp_0 send_rtp_0->sink     |
+ *  '-------'    '-------'    '-------'      |            |       '-------'
+ *                                           |            |     
+ *  .-------.    .---------.    .---------.  |            |       .-------.
+ *  |audiots|    |theoraenc|    |theorapay|  |            |       |udpsink|
+ *  |      src->sink      src->sink  src->send_rtp_1 send_rtp_1->sink     |
+ *  '-------'    '---------'    '---------'  |            |       '-------'
+ *                                           |            |
+ *                               .------.    |            |
+ *                               |udpsrc|    |            |       .-------.
+ *                               |     src->recv_rtcp_0   |       |udpsink|
+ *                               '------'    |       send_rtcp_0->sink    |
+ *                                           |            |       '-------'
+ *                               .------.    |            |
+ *                               |udpsrc|    |            |       .-------.
+ *                               |     src->recv_rtcp_1   |       |udpsink|
+ *                               '------'    |       send_rtcp_1->sink    |
+ *                                           '------------'       '-------'
+ *
+ * To keep the set of ports consistent across both this server and the
+ * corresponding client, a SessionData struct maps a rtpbin session number to
+ * a GstBin and is used to create the corresponding udp sinks with correct
+ * ports.
+ */
+
+typedef struct _SessionData
+{
+  int ref;
+  guint sessionNum;
+  GstElement *input;
+} SessionData;
+
+static SessionData *
+session_ref (SessionData * data)
+{
+  g_atomic_int_inc (&data->ref);
+  return data;
+}
+
+static void
+session_unref (gpointer data)
+{
+  SessionData *session = (SessionData *) data;
+  if (g_atomic_int_dec_and_test (&session->ref)) {
+    g_free (session);
+  }
+}
+
+static SessionData *
+session_new (guint sessionNum)
+{
+  SessionData *ret = g_new0 (SessionData, 1);
+  ret->sessionNum = sessionNum;
+  return session_ref (ret);
+}
+
+/*
+ * Used to generate informative messages during pipeline startup
+ */
+static void
+cb_state (GstBus * bus, GstMessage * message, gpointer data)
+{
+  GstObject *pipe = GST_OBJECT (data);
+  GstState old, new, pending;
+  gst_message_parse_state_changed (message, &old, &new, &pending);
+  if (message->src == pipe) {
+    g_print ("Pipeline %s changed state from %s to %s\n",
+        GST_OBJECT_NAME (message->src),
+        gst_element_state_get_name (old), gst_element_state_get_name (new));
+  }
+}
+
+/*
+ * Creates a GstGhostPad named "src" on the given bin, pointed at the "src" pad
+ * of the given element
+ */
+static void
+setup_ghost (GstElement * src, GstBin * bin)
+{
+  GstPad *srcPad = gst_element_get_static_pad (src, "src");
+  GstPad *binPad = gst_ghost_pad_new ("src", srcPad);
+  gst_element_add_pad (GST_ELEMENT (bin), binPad);
+}
+
+static SessionData *
+make_audio_session (guint sessionNum)
+{
+  SessionData *session;
+  GstBin *audioBin = GST_BIN (gst_bin_new (NULL));
+  GstElement *audioSrc = gst_element_factory_make ("audiotestsrc", NULL);
+  GstElement *encoder = gst_element_factory_make ("alawenc", NULL);
+  GstElement *payloader = gst_element_factory_make ("rtppcmapay", NULL);
+  g_object_set (audioSrc, "is-live", TRUE, NULL);
+
+  gst_bin_add_many (audioBin, audioSrc, encoder, payloader, NULL);
+  gst_element_link_many (audioSrc, encoder, payloader, NULL);
+
+  setup_ghost (payloader, audioBin);
+
+  session = session_new (sessionNum);
+  session->input = GST_ELEMENT (audioBin);
+
+  return session;
+}
+
+static SessionData *
+make_video_session (guint sessionNum)
+{
+  GstBin *videoBin = GST_BIN (gst_bin_new (NULL));
+  GstElement *videoSrc = gst_element_factory_make ("videotestsrc", NULL);
+  GstElement *encoder = gst_element_factory_make ("theoraenc", NULL);
+  GstElement *payloader = gst_element_factory_make ("rtptheorapay", NULL);
+  GstCaps *videoCaps;
+  SessionData *session;
+  g_object_set (videoSrc, "is-live", TRUE, "horizontal-speed", 1, NULL);
+  g_object_set (payloader, "config-interval", 2, NULL);
+
+  gst_bin_add_many (videoBin, videoSrc, encoder, payloader, NULL);
+  videoCaps = gst_caps_new_simple ("video/x-raw",
+      "width", G_TYPE_INT, 352,
+      "height", G_TYPE_INT, 288, "framerate", GST_TYPE_FRACTION, 15, 1, NULL);
+  gst_element_link_filtered (videoSrc, encoder, videoCaps);
+  gst_element_link (encoder, payloader);
+
+  setup_ghost (payloader, videoBin);
+
+  session = session_new (sessionNum);
+  session->input = GST_ELEMENT (videoBin);
+
+  return session;
+}
+
+static GstElement *
+request_aux_sender (GstElement * rtpbin, guint sessid, SessionData * session)
+{
+  GstElement *rtx, *bin;
+  GstPad *pad;
+  gchar *name;
+  GstStructure *pt_map;
+
+  GST_INFO ("creating AUX sender");
+  bin = gst_bin_new (NULL);
+  rtx = gst_element_factory_make ("rtprtxsend", NULL);
+  pt_map = gst_structure_new ("application/x-rtp-pt-map",
+      "8", G_TYPE_UINT, 98, "96", G_TYPE_UINT, 99, NULL);
+  g_object_set (rtx, "payload-type-map", pt_map, NULL);
+  gst_structure_free (pt_map);
+  gst_bin_add (GST_BIN (bin), rtx);
+
+  pad = gst_element_get_static_pad (rtx, "src");
+  name = g_strdup_printf ("src_%u", sessid);
+  gst_element_add_pad (bin, gst_ghost_pad_new (name, pad));
+  g_free (name);
+  gst_object_unref (pad);
+
+  pad = gst_element_get_static_pad (rtx, "sink");
+  name = g_strdup_printf ("sink_%u", sessid);
+  gst_element_add_pad (bin, gst_ghost_pad_new (name, pad));
+  g_free (name);
+  gst_object_unref (pad);
+
+  return bin;
+}
+
+/*
+ * This function sets up the UDP sinks and sources for RTP/RTCP, adds the
+ * given session's bin into the pipeline, and links it to the properly numbered
+ * pads on the rtpbin
+ */
+static void
+add_stream (GstPipeline * pipe, GstElement * rtpBin, SessionData * session)
+{
+  GstElement *rtpSink = gst_element_factory_make ("udpsink", NULL);
+  GstElement *rtcpSink = gst_element_factory_make ("udpsink", NULL);
+  GstElement *rtcpSrc = gst_element_factory_make ("udpsrc", NULL);
+  GstElement *identity = gst_element_factory_make ("identity", NULL);
+  int basePort;
+  gchar *padName;
+
+  basePort = 5000 + (session->sessionNum * 6);
+
+  gst_bin_add_many (GST_BIN (pipe), rtpSink, rtcpSink, rtcpSrc, identity,
+      session->input, NULL);
+
+  /* enable retransmission by setting rtprtxsend as the "aux" element of rtpbin */
+  g_signal_connect (rtpBin, "request-aux-sender",
+      (GCallback) request_aux_sender, session);
+
+  g_object_set (rtpSink, "port", basePort, "host", "127.0.0.1", NULL);
+  g_object_set (rtcpSink, "port", basePort + 1, "host", "127.0.0.1", "sync",
+      FALSE, "async", FALSE, NULL);
+  g_object_set (rtcpSrc, "port", basePort + 5, NULL);
+
+  /* this is just to drop some rtp packets at random, to demonstrate
+   * that rtprtxsend actually works */
+  g_object_set (identity, "drop-probability", 0.01, NULL);
+
+  padName = g_strdup_printf ("send_rtp_sink_%u", session->sessionNum);
+  gst_element_link_pads (session->input, "src", rtpBin, padName);
+  g_free (padName);
+
+  /* link rtpbin to udpsink directly here if you don't want
+   * artificial packet loss */
+  padName = g_strdup_printf ("send_rtp_src_%u", session->sessionNum);
+  gst_element_link_pads (rtpBin, padName, identity, "sink");
+  gst_element_link (identity, rtpSink);
+  g_free (padName);
+
+  padName = g_strdup_printf ("send_rtcp_src_%u", session->sessionNum);
+  gst_element_link_pads (rtpBin, padName, rtcpSink, "sink");
+  g_free (padName);
+
+  padName = g_strdup_printf ("recv_rtcp_sink_%u", session->sessionNum);
+  gst_element_link_pads (rtcpSrc, "src", rtpBin, padName);
+  g_free (padName);
+
+  g_print ("New RTP stream on %i/%i/%i\n", basePort, basePort + 1,
+      basePort + 5);
+
+  session_unref (session);
+}
+
+int
+main (int argc, char **argv)
+{
+  GstPipeline *pipe;
+  GstBus *bus;
+  SessionData *videoSession;
+  SessionData *audioSession;
+  GstElement *rtpBin;
+  GMainLoop *loop;
+
+  gst_init (&argc, &argv);
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  pipe = GST_PIPELINE (gst_pipeline_new (NULL));
+  bus = gst_element_get_bus (GST_ELEMENT (pipe));
+  g_signal_connect (bus, "message::state-changed", G_CALLBACK (cb_state), pipe);
+  gst_bus_add_signal_watch (bus);
+  gst_object_unref (bus);
+
+  rtpBin = gst_element_factory_make ("rtpbin", NULL);
+  g_object_set (rtpBin, "rtp-profile", GST_RTP_PROFILE_AVPF, NULL);
+
+  gst_bin_add (GST_BIN (pipe), rtpBin);
+
+  videoSession = make_video_session (0);
+  audioSession = make_audio_session (1);
+  add_stream (pipe, rtpBin, videoSession);
+  add_stream (pipe, rtpBin, audioSession);
+
+  g_print ("starting server pipeline\n");
+  gst_element_set_state (GST_ELEMENT (pipe), GST_STATE_PLAYING);
+
+  g_main_loop_run (loop);
+
+  g_print ("stopping server pipeline\n");
+  gst_element_set_state (GST_ELEMENT (pipe), GST_STATE_NULL);
+
+  gst_object_unref (pipe);
+  g_main_loop_unref (loop);
+
+  return 0;
+}
diff --git a/tests/examples/rtp/server-rtpbundle.c b/tests/examples/rtp/server-rtpbundle.c
new file mode 100644
index 0000000..1f6d01b
--- /dev/null
+++ b/tests/examples/rtp/server-rtpbundle.c
@@ -0,0 +1,179 @@
+/* GStreamer
+ * Copyright (C) 2016 Igalia S.L
+ *   @author Philippe Normand <philn@igalia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <gst/gst.h>
+
+/*
+ * An bundling RTP server
+ *  creates two sessions and streams audio on one, video on the other, with RTCP
+ *  on both sessions. The destination is 127.0.0.1.
+ *
+ *  The RTP streams are bundled to a single outgoing connection. Same for the RTCP streams.
+ *
+ *  .-------.    .-------.    .-------.      .------------.         .------.
+ *  |audiots|    |alawenc|    |pcmapay|      | rtpbin     |         |funnel|
+ *  |      src->sink    src->sink    src->send_rtp_0 send_rtp_0--->sink_0  |    .-------.
+ *  '-------'    '-------'    '-------'      |            |         |      |    |udpsink|
+ *                                           |            |         |     src->sink     |
+ *  .-------.               .---------.      |            |         |      |    '-------'
+ *  |videots|               | vrawpay |      |            |         |      |
+ *  |      src------------>sink      src->send_rtp_1 send_rtp_1--->sink_1  |
+ *  '-------'               '---------'      |            |         '------'
+ *                                           |            |
+ *                               .------.    |            |
+ *                               |udpsrc|    |            |         .------.
+ *                               |     src->recv_rtcp_0   |         |funnel|
+ *                               '------'    |       send_rtcp_0-->sink_0  |   .-------.
+ *                                           |            |         |      |   |udpsink|
+ *                               .------.    |            |         |    src->sink     |
+ *                               |udpsrc|    |            |         |      |   '-------'
+ *                               |     src->recv_rtcp_1   |         |      |
+ *                               '------'    |       send_rtcp_1-->sink_1  |
+ *                                           '------------'         '------'
+ *
+ */
+
+static GstElement *
+create_pipeline (void)
+{
+  GstElement *pipeline, *rtpbin, *audiosrc, *audio_encoder,
+      *audio_rtppayloader, *sendrtp_udpsink,
+      *send_rtcp_udpsink, *sendrtcp_funnel, *sendrtp_funnel;
+  GstElement *videosrc, *video_rtppayloader, *time_overlay;
+  gint rtp_udp_port = 5001;
+  gint rtcp_udp_port = 5002;
+  gint recv_audio_rtcp_port = 5003;
+  gint recv_video_rtcp_port = 5004;
+  GstElement *audio_rtcp_udpsrc, *video_rtcp_udpsrc;
+
+  pipeline = gst_pipeline_new (NULL);
+
+  rtpbin = gst_element_factory_make ("rtpbin", NULL);
+
+  audiosrc = gst_element_factory_make ("audiotestsrc", NULL);
+  g_object_set (audiosrc, "is-live", TRUE, NULL);
+  audio_encoder = gst_element_factory_make ("alawenc", NULL);
+  audio_rtppayloader = gst_element_factory_make ("rtppcmapay", NULL);
+  g_object_set (audio_rtppayloader, "pt", 96, NULL);
+
+  videosrc = gst_element_factory_make ("videotestsrc", NULL);
+  g_object_set (videosrc, "is-live", TRUE, NULL);
+  time_overlay = gst_element_factory_make ("timeoverlay", NULL);
+  video_rtppayloader = gst_element_factory_make ("rtpvrawpay", NULL);
+  g_object_set (video_rtppayloader, "pt", 100, NULL);
+
+  /* muxed rtcp */
+  sendrtcp_funnel = gst_element_factory_make ("funnel", "send_rtcp_funnel");
+  send_rtcp_udpsink = gst_element_factory_make ("udpsink", NULL);
+  g_object_set (send_rtcp_udpsink, "host", "127.0.0.1", NULL);
+  g_object_set (send_rtcp_udpsink, "port", rtcp_udp_port, NULL);
+  g_object_set (send_rtcp_udpsink, "sync", FALSE, NULL);
+  g_object_set (send_rtcp_udpsink, "async", FALSE, NULL);
+
+  /* outgoing bundled stream */
+  sendrtp_funnel = gst_element_factory_make ("funnel", "send_rtp_funnel");
+  sendrtp_udpsink = gst_element_factory_make ("udpsink", NULL);
+  g_object_set (sendrtp_udpsink, "host", "127.0.0.1", NULL);
+  g_object_set (sendrtp_udpsink, "port", rtp_udp_port, NULL);
+  g_object_set (sendrtp_udpsink, "sync", FALSE, NULL);
+  g_object_set (sendrtp_udpsink, "async", FALSE, NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), rtpbin, audiosrc, audio_encoder,
+      audio_rtppayloader, sendrtp_udpsink, send_rtcp_udpsink,
+      sendrtp_funnel, sendrtcp_funnel, videosrc, video_rtppayloader, NULL);
+
+  if (time_overlay)
+    gst_bin_add (GST_BIN (pipeline), time_overlay);
+
+  gst_element_link_many (audiosrc, audio_encoder, audio_rtppayloader, NULL);
+  gst_element_link_pads (audio_rtppayloader, "src", rtpbin, "send_rtp_sink_0");
+
+  if (time_overlay) {
+    gst_element_link_many (videosrc, time_overlay, video_rtppayloader, NULL);
+  } else {
+    gst_element_link (videosrc, video_rtppayloader);
+  }
+
+  gst_element_link_pads (video_rtppayloader, "src", rtpbin, "send_rtp_sink_1");
+
+  gst_element_link_pads (sendrtp_funnel, "src", sendrtp_udpsink, "sink");
+  gst_element_link_pads (rtpbin, "send_rtp_src_0", sendrtp_funnel, "sink_%u");
+  gst_element_link_pads (rtpbin, "send_rtp_src_1", sendrtp_funnel, "sink_%u");
+  gst_element_link_pads (sendrtcp_funnel, "src", send_rtcp_udpsink, "sink");
+  gst_element_link_pads (rtpbin, "send_rtcp_src_0", sendrtcp_funnel, "sink_%u");
+  gst_element_link_pads (rtpbin, "send_rtcp_src_1", sendrtcp_funnel, "sink_%u");
+
+  audio_rtcp_udpsrc = gst_element_factory_make ("udpsrc", NULL);
+  g_object_set (audio_rtcp_udpsrc, "port", recv_audio_rtcp_port, NULL);
+  video_rtcp_udpsrc = gst_element_factory_make ("udpsrc", NULL);
+  g_object_set (video_rtcp_udpsrc, "port", recv_video_rtcp_port, NULL);
+  gst_bin_add_many (GST_BIN (pipeline), audio_rtcp_udpsrc, video_rtcp_udpsrc,
+      NULL);
+  gst_element_link_pads (audio_rtcp_udpsrc, "src", rtpbin, "recv_rtcp_sink_0");
+  gst_element_link_pads (video_rtcp_udpsrc, "src", rtpbin, "recv_rtcp_sink_1");
+
+  return pipeline;
+}
+
+/*
+ * Used to generate informative messages during pipeline startup
+ */
+static void
+cb_state (GstBus * bus, GstMessage * message, gpointer data)
+{
+  GstObject *pipe = GST_OBJECT (data);
+  GstState old, new, pending;
+  gst_message_parse_state_changed (message, &old, &new, &pending);
+  if (message->src == pipe) {
+    g_print ("Pipeline %s changed state from %s to %s\n",
+        GST_OBJECT_NAME (message->src),
+        gst_element_state_get_name (old), gst_element_state_get_name (new));
+  }
+}
+
+int
+main (int argc, char **argv)
+{
+  GstElement *pipe;
+  GstBus *bus;
+  GMainLoop *loop;
+
+  gst_init (&argc, &argv);
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  pipe = create_pipeline ();
+  bus = gst_element_get_bus (pipe);
+  g_signal_connect (bus, "message::state-changed", G_CALLBACK (cb_state), pipe);
+  gst_bus_add_signal_watch (bus);
+  gst_object_unref (bus);
+
+  g_print ("starting server pipeline\n");
+  gst_element_set_state (pipe, GST_STATE_PLAYING);
+
+  g_main_loop_run (loop);
+
+  g_print ("stopping server pipeline\n");
+  gst_element_set_state (pipe, GST_STATE_NULL);
+
+  gst_object_unref (pipe);
+  g_main_loop_unref (loop);
+
+  return 0;
+}
diff --git a/tests/examples/rtp/server-v4l2-H263p-alsasrc-AMR.sh b/tests/examples/rtp/server-v4l2-H263p-alsasrc-AMR.sh
new file mode 100755
index 0000000..53ef5aa
--- /dev/null
+++ b/tests/examples/rtp/server-v4l2-H263p-alsasrc-AMR.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# A simple RTP server
+#
+
+# change these to change the server sync. This causes the server to send the
+# packets largly out-of-sync, the client should use the RTCP SR packets to
+# restore proper lip-sync between the streams.
+AOFFSET=0
+VOFFSET=0
+
+VCAPS="video/x-raw,width=352,height=288,framerate=15/1"
+
+#DEST=192.168.1.126
+DEST=localhost
+
+gst-launch-1.0 -v rtpbin name=rtpbin \
+           v4l2src ! videorate ! videoconvert ! $VCAPS ! avenc_h263p ! rtph263ppay ! rtpbin.send_rtp_sink_0      \
+                     rtpbin.send_rtp_src_0 ! queue ! udpsink host=$DEST port=5000 ts-offset=$AOFFSET      \
+                     rtpbin.send_rtcp_src_0 ! udpsink host=$DEST port=5001 sync=false async=false         \
+                     udpsrc port=5005 ! rtpbin.recv_rtcp_sink_0                                           \
+           autoaudiosrc ! audioconvert ! amrnbenc ! rtpamrpay ! rtpbin.send_rtp_sink_1                         \
+	             rtpbin.send_rtp_src_1 ! queue ! udpsink host=$DEST port=5002 ts-offset=$VOFFSET      \
+	             rtpbin.send_rtcp_src_1 ! udpsink host=$DEST port=5003 sync=false async=false         \
+                     udpsrc port=5007 ! rtpbin.recv_rtcp_sink_1
diff --git a/tests/examples/rtp/server-v4l2-H264-alsasrc-PCMA.sh b/tests/examples/rtp/server-v4l2-H264-alsasrc-PCMA.sh
new file mode 100755
index 0000000..ac727a6
--- /dev/null
+++ b/tests/examples/rtp/server-v4l2-H264-alsasrc-PCMA.sh
@@ -0,0 +1,78 @@
+#!/bin/sh
+#
+# A simple RTP server
+#  sends the output of v4l2src as h264 encoded RTP on port 5000, RTCP is sent on
+#  port 5001. The destination is 127.0.0.1.
+#  the video receiver RTCP reports are received on port 5005
+#  sends the output of autoaudiosrc as alaw encoded RTP on port 5002, RTCP is sent on
+#  port 5003. The destination is 127.0.0.1.
+#  the receiver RTCP reports are received on port 5007
+#
+#  .-------.    .-------.    .-------.      .----------.     .-------.
+#  |v4lssrc|    |h264enc|    |h264pay|      | rtpbin   |     |udpsink|  RTP
+#  |      src->sink    src->sink    src->send_rtp send_rtp->sink     | port=5000
+#  '-------'    '-------'    '-------'      |          |     '-------'
+#                                           |          |
+#                                           |          |     .-------.
+#                                           |          |     |udpsink|  RTCP
+#                                           |    send_rtcp->sink     | port=5001
+#                            .-------.      |          |     '-------' sync=false
+#                 RTCP       |udpsrc |      |          |               async=false
+#               port=5005    |     src->recv_rtcp      |
+#                            '-------'      |          |
+#                                           |          |
+# .--------.    .-------.    .-------.      |          |     .-------.
+# |audiosrc|    |alawenc|    |pcmapay|      | rtpbin   |     |udpsink|  RTP
+# |       src->sink    src->sink    src->send_rtp send_rtp->sink     | port=5002
+# '--------'    '-------'    '-------'      |          |     '-------'
+#                                           |          |
+#                                           |          |     .-------.
+#                                           |          |     |udpsink|  RTCP
+#                                           |    send_rtcp->sink     | port=5003
+#                            .-------.      |          |     '-------' sync=false
+#                 RTCP       |udpsrc |      |          |               async=false
+#               port=5007    |     src->recv_rtcp      |
+#                            '-------'      '----------'
+#
+# ideally we should transport the properties on the RTP udpsink pads to the
+# receiver in order to transmit the SPS and PPS earlier.
+
+# change this to send the RTP data and RTCP to another host
+DEST=127.0.0.1
+
+# tuning parameters to make the sender send the streams out of sync. Can be used
+# ot test the client RTCP synchronisation.
+#VOFFSET=900000000
+VOFFSET=0
+AOFFSET=0
+
+# H264 encode from the source
+VELEM="v4l2src"
+#VELEM="videotestsrc is-live=1"
+VCAPS="video/x-raw,width=352,height=288,framerate=15/1"
+VSOURCE="$VELEM ! queue ! videorate ! videoconvert ! $VCAPS"
+VENC="x264enc tune=zerolatency byte-stream=true bitrate=300 ! rtph264pay"
+
+VRTPSINK="udpsink port=5000 host=$DEST ts-offset=$VOFFSET name=vrtpsink"
+VRTCPSINK="udpsink port=5001 host=$DEST sync=false async=false name=vrtcpsink"
+VRTCPSRC="udpsrc port=5005 name=vrtpsrc"
+
+# PCMA encode from the source
+AELEM="autoaudiosrc"
+#AELEM="audiotestsrc is-live=1"
+ASOURCE="$AELEM ! queue ! audioresample ! audioconvert"
+AENC="alawenc ! rtppcmapay"
+
+ARTPSINK="udpsink port=5002 host=$DEST ts-offset=$AOFFSET name=artpsink"
+ARTCPSINK="udpsink port=5003 host=$DEST sync=false async=false name=artcpsink"
+ARTCPSRC="udpsrc port=5007 name=artpsrc"
+
+gst-launch-1.0 -v rtpbin name=rtpbin \
+    $VSOURCE ! $VENC ! rtpbin.send_rtp_sink_0                                             \
+        rtpbin.send_rtp_src_0 ! $VRTPSINK                                                 \
+        rtpbin.send_rtcp_src_0 ! $VRTCPSINK                                               \
+      $VRTCPSRC ! rtpbin.recv_rtcp_sink_0                                                 \
+    $ASOURCE ! $AENC ! rtpbin.send_rtp_sink_1                                             \
+        rtpbin.send_rtp_src_1 ! $ARTPSINK                                                 \
+        rtpbin.send_rtcp_src_1 ! $ARTCPSINK                                               \
+      $ARTCPSRC ! rtpbin.recv_rtcp_sink_1
diff --git a/tests/examples/shapewipe/.gitignore b/tests/examples/shapewipe/.gitignore
new file mode 100644
index 0000000..746bc48
--- /dev/null
+++ b/tests/examples/shapewipe/.gitignore
@@ -0,0 +1 @@
+shapewipe-example
diff --git a/tests/examples/shapewipe/Makefile.am b/tests/examples/shapewipe/Makefile.am
new file mode 100644
index 0000000..e0e9217
--- /dev/null
+++ b/tests/examples/shapewipe/Makefile.am
@@ -0,0 +1,8 @@
+noinst_PROGRAMS = shapewipe-example
+
+shapewipe_example_SOURCES = shapewipe-example.c
+shapewipe_example_CFLAGS = $(GST_CONTROLLER_CFLAGS) $(GST_CFLAGS)
+shapewipe_example_LDADD = $(GST_CONTROLLER_LIBS) $(GST_LIBS)
+
+noinst_HEADERS = 
+
diff --git a/tests/examples/shapewipe/meson.build b/tests/examples/shapewipe/meson.build
new file mode 100644
index 0000000..50d775c
--- /dev/null
+++ b/tests/examples/shapewipe/meson.build
@@ -0,0 +1,5 @@
+executable('shapewipe-example', 'shapewipe-example.c',
+  dependencies: [gstcontroller_dep, gst_dep],
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  install: false)
diff --git a/tests/examples/shapewipe/shapewipe-example.c b/tests/examples/shapewipe/shapewipe-example.c
new file mode 100644
index 0000000..98d734a
--- /dev/null
+++ b/tests/examples/shapewipe/shapewipe-example.c
@@ -0,0 +1,134 @@
+/* GStreamer
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@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
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/gst.h>
+#include <gst/controller/gstlfocontrolsource.h>
+#include <gst/controller/gstdirectcontrolbinding.h>
+
+#include <stdlib.h>
+
+static gboolean
+on_message (GstBus * bus, GstMessage * message, gpointer user_data)
+{
+  GMainLoop *loop = (GMainLoop *) user_data;
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_ERROR:{
+      GError *err = NULL;
+      gchar *debug = NULL;
+
+      g_warning ("Got ERROR");
+      gst_message_parse_error (message, &err, &debug);
+      g_warning ("%s: %s", err->message, debug);
+      g_main_loop_quit (loop);
+      break;
+    }
+    case GST_MESSAGE_WARNING:{
+      GError *err = NULL;
+      gchar *debug = NULL;
+
+      g_warning ("Got WARNING");
+      gst_message_parse_error (message, &err, &debug);
+      g_warning ("%s: %s", err->message, debug);
+      g_main_loop_quit (loop);
+      break;
+    }
+    case GST_MESSAGE_EOS:
+      g_main_loop_quit (loop);
+      break;
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+gint
+main (gint argc, gchar ** argv)
+{
+  GstElement *pipeline;
+  GstElement *shapewipe;
+  GstControlSource *cs;
+  GMainLoop *loop;
+  GstBus *bus;
+  gchar *pipeline_string;
+  gfloat border = 0.05;
+
+  if (argc < 2) {
+    g_print ("Usage: shapewipe mask.png <border>\n");
+    return -1;
+  }
+
+  gst_init (&argc, &argv);
+
+  if (argc > 2) {
+    border = atof (argv[2]);
+  }
+
+  pipeline_string =
+      g_strdup_printf
+      ("videotestsrc ! video/x-raw,format=(string)AYUV,width=640,height=480 ! shapewipe name=shape border=%f ! videomixer name=mixer ! videoconvert ! autovideosink     filesrc location=%s ! typefind ! decodebin ! videoconvert ! videoscale ! queue ! shape.mask_sink    videotestsrc pattern=snow ! video/x-raw,format=(string)AYUV,width=640,height=480 ! queue ! mixer.",
+      border, argv[1]);
+
+  pipeline = gst_parse_launch (pipeline_string, NULL);
+  g_free (pipeline_string);
+
+  if (pipeline == NULL) {
+    g_print ("Failed to create pipeline\n");
+    return -2;
+  }
+
+  shapewipe = gst_bin_get_by_name (GST_BIN (pipeline), "shape");
+
+  cs = gst_lfo_control_source_new ();
+
+  gst_object_add_control_binding (GST_OBJECT_CAST (shapewipe),
+      gst_direct_control_binding_new (GST_OBJECT_CAST (shapewipe), "position",
+          cs));
+  gst_object_unref (shapewipe);
+
+  g_object_set (cs,
+      "amplitude", 0.5,
+      "offset", 0.5, "frequency", 0.25, "timeshift", 500 * GST_MSECOND, NULL);
+
+  g_object_unref (cs);
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+  gst_bus_add_signal_watch (bus);
+  g_signal_connect (G_OBJECT (bus), "message", G_CALLBACK (on_message), loop);
+  gst_object_unref (GST_OBJECT (bus));
+
+  if (gst_element_set_state (pipeline,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
+    g_error ("Failed to go into PLAYING state");
+    return -4;
+  }
+
+  g_main_loop_run (loop);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  g_main_loop_unref (loop);
+
+  gst_object_unref (G_OBJECT (pipeline));
+
+  return 0;
+}
diff --git a/tests/examples/spectrum/.gitignore b/tests/examples/spectrum/.gitignore
new file mode 100644
index 0000000..8e5a3cf
--- /dev/null
+++ b/tests/examples/spectrum/.gitignore
@@ -0,0 +1,3 @@
+demo-audiotest
+demo-osssrc
+spectrum-example
diff --git a/tests/examples/spectrum/Makefile.am b/tests/examples/spectrum/Makefile.am
new file mode 100644
index 0000000..9ced5ea
--- /dev/null
+++ b/tests/examples/spectrum/Makefile.am
@@ -0,0 +1,18 @@
+if HAVE_GTK
+noinst_PROGRAMS = demo-osssrc demo-audiotest spectrum-example
+endif
+
+demo_osssrc_SOURCES = demo-osssrc.c
+demo_osssrc_CFLAGS  = $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GTK_CFLAGS)
+demo_osssrc_LDADD = $(GST_BASE_LIBS) $(GST_LIBS) $(GTK_LIBS)
+
+demo_audiotest_SOURCES = demo-audiotest.c
+demo_audiotest_CFLAGS  = $(GST_PLUGINS_BASE_CFLAGS) \
+   $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GTK_CFLAGS)
+demo_audiotest_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstfft-$(GST_API_VERSION) \
+   $(GST_BASE_LIBS) $(GST_LIBS) $(GTK_LIBS)
+
+spectrum_example_SOURCES = spectrum-example.c
+spectrum_example_CFLAGS  = $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GTK_CFLAGS)
+spectrum_example_LDADD = $(GST_BASE_LIBS) $(GST_LIBS) $(GTK_LIBS)
+
diff --git a/tests/examples/spectrum/demo-audiotest.c b/tests/examples/spectrum/demo-audiotest.c
new file mode 100644
index 0000000..afa90c4
--- /dev/null
+++ b/tests/examples/spectrum/demo-audiotest.c
@@ -0,0 +1,283 @@
+/* GStreamer
+ * Copyright (C) 2006 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/* TODO: add wave selection */
+/* fast vs. slow mode - see update_spectrum_bands()
+ * we are still cheating below, we only draw the first spect_bands and ignore a few :/
+ *
+ * xtime gst-launch-0.10 -q audiotestsrc num-buffers=10000 ! spectrum bands=1441 ! fakesink
+ * 2.29u 0.02s 2.14r 25504kB gst-launch-0.10 -q audiotestsrc num-buffers=10000 ! spectrum bands=1441 ! fakesink
+ * 2.20u 0.05s 2.10r 25664kB gst-launch-0.10 -q audiotestsrc num-buffers=10000 ! spectrum bands=1441 ! fakesink
+ * 2.23u 0.04s 2.10r 25664kB gst-launch-0.10 -q audiotestsrc num-buffers=10000 ! spectrum bands=1441 ! fakesink
+ * 
+ * xtime gst-launch-0.10 -q audiotestsrc num-buffers=10000 ! spectrum bands=1440 ! fakesink
+ * 25.01u 0.08s 25.00r 25552kB gst-launch-0.10 -q audiotestsrc num-buffers=10000 ! spectrum bands=1440 ! fakesink
+ * 24.96u 0.03s 24.88r 25568kB gst-launch-0.10 -q audiotestsrc num-buffers=10000 ! spectrum bands=1440 ! fakesink
+ * 25.11u 0.03s 25.03r 25536kB gst-launch-0.10 -q audiotestsrc num-buffers=10000 ! spectrum bands=1440 ! fakesink
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* TODO: We use gdk_cairo_create() and others, which are deprecated */
+#define GDK_DISABLE_DEPRECATION_WARNINGS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <gst/gst.h>
+#include <gst/fft/gstfft.h>
+#include <gtk/gtk.h>
+
+#ifndef DEFAULT_AUDIOSINK
+#define DEFAULT_AUDIOSINK "autoaudiosink"
+#endif
+
+static guint spect_height = 64;
+static guint spect_bands = 256;
+static gfloat height_scale = 1.0;
+static gboolean fast = FALSE;
+
+static GtkWidget *drawingarea = NULL;
+static GtkWidget *bands_used = NULL;
+static GstClock *sync_clock = NULL;
+
+static void
+on_window_destroy (GObject * object, gpointer user_data)
+{
+  drawingarea = NULL;
+  gtk_main_quit ();
+}
+
+/* control audiotestsrc frequency */
+static void
+on_frequency_changed (GtkRange * range, gpointer user_data)
+{
+  GstElement *machine = GST_ELEMENT (user_data);
+  gdouble value = gtk_range_get_value (range);
+
+  g_object_set (machine, "freq", value, NULL);
+}
+
+static void
+update_spectrum_bands (GstElement * spectrum)
+{
+  guint bands = spect_bands;
+  gchar str[50];
+
+  if (fast)
+    bands = ((gst_fft_next_fast_length (2 * bands - 2) + 2) / 2);
+
+  sprintf (str, "using %u bands", bands);
+
+  g_object_set (bands_used, "label", str, NULL);
+  g_object_set (G_OBJECT (spectrum), "bands", bands, NULL);
+}
+
+static gboolean
+on_configure_event (GtkWidget * widget, GdkEventConfigure * event,
+    gpointer user_data)
+{
+  /*GST_INFO ("%d x %d", event->width, event->height); */
+  spect_height = event->height;
+  height_scale = event->height / 64.0;
+  spect_bands = event->width;
+
+  update_spectrum_bands (GST_ELEMENT (user_data));
+  return FALSE;
+}
+
+static void
+on_fast_slow_mode_changed (GtkToggleButton * togglebutton, gpointer user_data)
+{
+  fast = gtk_toggle_button_get_active (togglebutton);
+  update_spectrum_bands (GST_ELEMENT (user_data));
+}
+
+/* draw frequency spectrum as a bunch of bars */
+static void
+draw_spectrum (gfloat * data)
+{
+  gint i;
+  GdkRectangle rect = { 0, 0, spect_bands, spect_height };
+  cairo_t *cr;
+
+  if (!drawingarea)
+    return;
+
+  gdk_window_begin_paint_rect (gtk_widget_get_window (drawingarea), &rect);
+  cr = gdk_cairo_create (gtk_widget_get_window (drawingarea));
+
+  cairo_set_source_rgb (cr, 0, 0, 0);
+  cairo_rectangle (cr, 0, 0, spect_bands, spect_height);
+  cairo_fill (cr);
+  cairo_set_source_rgb (cr, 1, 1, 1);
+  for (i = 0; i < spect_bands; i++) {
+    cairo_rectangle (cr, i, -data[i], 1, spect_height + data[i]);
+    cairo_fill (cr);
+  }
+  cairo_destroy (cr);
+
+  gdk_window_end_paint (gtk_widget_get_window (drawingarea));
+}
+
+/* process delayed message */
+static gboolean
+delayed_idle_spectrum_update (gpointer user_data)
+{
+  draw_spectrum ((gfloat *) user_data);
+  g_free (user_data);
+  return (FALSE);
+}
+
+static gboolean
+delayed_spectrum_update (GstClock * sync_clock, GstClockTime time,
+    GstClockID id, gpointer user_data)
+{
+  if (GST_CLOCK_TIME_IS_VALID (time))
+    g_idle_add (delayed_idle_spectrum_update, user_data);
+  else
+    g_free (user_data);
+  return (TRUE);
+}
+
+/* receive spectral data from element message */
+static gboolean
+message_handler (GstBus * bus, GstMessage * message, gpointer data)
+{
+  if (message->type == GST_MESSAGE_ELEMENT) {
+    const GstStructure *s = gst_message_get_structure (message);
+    const gchar *name = gst_structure_get_name (s);
+
+    if (strcmp (name, "spectrum") == 0) {
+      GstElement *spectrum = GST_ELEMENT (GST_MESSAGE_SRC (message));
+      GstClockTime timestamp, duration;
+      GstClockTime waittime = GST_CLOCK_TIME_NONE;
+
+      if (gst_structure_get_clock_time (s, "running-time", &timestamp) &&
+          gst_structure_get_clock_time (s, "duration", &duration)) {
+        /* wait for middle of buffer */
+        waittime = timestamp + duration / 2;
+      } else if (gst_structure_get_clock_time (s, "endtime", &timestamp)) {
+        waittime = timestamp;
+      }
+      if (GST_CLOCK_TIME_IS_VALID (waittime)) {
+        GstClockID clock_id;
+        GstClockTime basetime = gst_element_get_base_time (spectrum);
+        gfloat *spect = g_new (gfloat, spect_bands);
+        const GValue *list;
+        const GValue *value;
+        guint i;
+
+        list = gst_structure_get_value (s, "magnitude");
+        for (i = 0; i < spect_bands; ++i) {
+          value = gst_value_list_get_value (list, i);
+          spect[i] = height_scale * g_value_get_float (value);
+        }
+
+        clock_id =
+            gst_clock_new_single_shot_id (sync_clock, waittime + basetime);
+        gst_clock_id_wait_async (clock_id, delayed_spectrum_update,
+            (gpointer) spect, NULL);
+        gst_clock_id_unref (clock_id);
+      }
+    }
+  }
+  return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+  GstElement *bin;
+  GstElement *src, *spectrum, *audioconvert, *sink;
+  GstBus *bus;
+  GtkWidget *appwindow, *vbox, *hbox, *widget;
+
+  gst_init (&argc, &argv);
+  gtk_init (&argc, &argv);
+
+  bin = gst_pipeline_new ("bin");
+
+  src = gst_element_factory_make ("audiotestsrc", "src");
+  g_object_set (G_OBJECT (src), "wave", 0, NULL);
+
+  spectrum = gst_element_factory_make ("spectrum", "spectrum");
+  g_object_set (G_OBJECT (spectrum), "bands", spect_bands, "threshold", -80,
+      "post-messages", TRUE, NULL);
+
+  audioconvert = gst_element_factory_make ("audioconvert", "audioconvert");
+
+  sink = gst_element_factory_make (DEFAULT_AUDIOSINK, "sink");
+
+  gst_bin_add_many (GST_BIN (bin), src, spectrum, audioconvert, sink, NULL);
+  if (!gst_element_link_many (src, spectrum, audioconvert, sink, NULL)) {
+    fprintf (stderr, "can't link elements\n");
+    exit (1);
+  }
+
+  bus = gst_element_get_bus (bin);
+  gst_bus_add_watch (bus, message_handler, NULL);
+  gst_object_unref (bus);
+
+  sync_clock = gst_pipeline_get_clock (GST_PIPELINE (bin));
+
+  appwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  g_signal_connect (G_OBJECT (appwindow), "destroy",
+      G_CALLBACK (on_window_destroy), NULL);
+  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+  widget = gtk_check_button_new_with_label ("Fast");
+  g_signal_connect (G_OBJECT (widget), "toggled",
+      G_CALLBACK (on_fast_slow_mode_changed), (gpointer) spectrum);
+  gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+  bands_used = gtk_label_new ("");
+  gtk_box_pack_start (GTK_BOX (hbox), bands_used, FALSE, FALSE, 0);
+
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+
+  widget = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL,
+      50.0, 20000.0, 10);
+  gtk_scale_set_draw_value (GTK_SCALE (widget), TRUE);
+  gtk_scale_set_value_pos (GTK_SCALE (widget), GTK_POS_TOP);
+  gtk_range_set_value (GTK_RANGE (widget), 440.0);
+  g_signal_connect (G_OBJECT (widget), "value-changed",
+      G_CALLBACK (on_frequency_changed), (gpointer) src);
+  gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
+
+  drawingarea = gtk_drawing_area_new ();
+  gtk_widget_set_size_request (drawingarea, spect_bands, spect_height);
+  g_signal_connect (G_OBJECT (drawingarea), "configure-event",
+      G_CALLBACK (on_configure_event), (gpointer) spectrum);
+  gtk_box_pack_start (GTK_BOX (vbox), drawingarea, TRUE, TRUE, 0);
+
+  gtk_container_add (GTK_CONTAINER (appwindow), vbox);
+  gtk_widget_show_all (appwindow);
+
+  gst_element_set_state (bin, GST_STATE_PLAYING);
+  gtk_main ();
+  gst_element_set_state (bin, GST_STATE_NULL);
+
+  gst_object_unref (sync_clock);
+  gst_object_unref (bin);
+
+  return 0;
+}
diff --git a/tests/examples/spectrum/demo-osssrc.c b/tests/examples/spectrum/demo-osssrc.c
new file mode 100644
index 0000000..2e5b195
--- /dev/null
+++ b/tests/examples/spectrum/demo-osssrc.c
@@ -0,0 +1,211 @@
+/* GStreamer
+ * Copyright (C) 2006 Stefan Kost <ensonic@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* TODO: We use gdk_cairo_create() and others, which are deprecated */
+#define GDK_DISABLE_DEPRECATION_WARNINGS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <gst/gst.h>
+#include <gtk/gtk.h>
+
+#ifndef DEFAULT_AUDIOSRC
+#define DEFAULT_AUDIOSRC "alsasrc"
+#endif
+
+static guint spect_height = 64;
+static guint spect_bands = 256;
+static gfloat height_scale = 1.0;
+
+static GtkWidget *drawingarea = NULL;
+static GstClock *sync_clock = NULL;
+
+static void
+on_window_destroy (GObject * object, gpointer user_data)
+{
+  drawingarea = NULL;
+  gtk_main_quit ();
+}
+
+static gboolean
+on_configure_event (GtkWidget * widget, GdkEventConfigure * event,
+    gpointer user_data)
+{
+  GstElement *spectrum = GST_ELEMENT (user_data);
+
+  /*GST_INFO ("%d x %d", event->width, event->height); */
+  spect_height = event->height;
+  height_scale = event->height / 64.0;
+  spect_bands = event->width;
+
+  g_object_set (G_OBJECT (spectrum), "bands", spect_bands, NULL);
+  return FALSE;
+}
+
+/* draw frequency spectrum as a bunch of bars */
+static void
+draw_spectrum (gfloat * data)
+{
+  gint i;
+  GdkRectangle rect = { 0, 0, spect_bands, spect_height };
+  cairo_t *cr;
+
+  if (!drawingarea)
+    return;
+
+  gdk_window_begin_paint_rect (gtk_widget_get_window (drawingarea), &rect);
+  cr = gdk_cairo_create (gtk_widget_get_window (drawingarea));
+
+  cairo_set_source_rgb (cr, 0, 0, 0);
+  cairo_rectangle (cr, 0, 0, spect_bands, spect_height);
+  cairo_fill (cr);
+  cairo_set_source_rgb (cr, 1, 1, 1);
+  for (i = 0; i < spect_bands; i++) {
+    cairo_rectangle (cr, i, -data[i], 1, spect_height + data[i]);
+    cairo_fill (cr);
+  }
+  cairo_destroy (cr);
+
+  gdk_window_end_paint (gtk_widget_get_window (drawingarea));
+}
+
+/* process delayed message */
+static gboolean
+delayed_idle_spectrum_update (gpointer user_data)
+{
+  draw_spectrum ((gfloat *) user_data);
+  g_free (user_data);
+  return (FALSE);
+}
+
+static gboolean
+delayed_spectrum_update (GstClock * sync_clock, GstClockTime time,
+    GstClockID id, gpointer user_data)
+{
+  if (GST_CLOCK_TIME_IS_VALID (time))
+    g_idle_add (delayed_idle_spectrum_update, user_data);
+  else
+    g_free (user_data);
+  return (TRUE);
+}
+
+/* receive spectral data from element message */
+static gboolean
+message_handler (GstBus * bus, GstMessage * message, gpointer data)
+{
+  if (message->type == GST_MESSAGE_ELEMENT) {
+    const GstStructure *s = gst_message_get_structure (message);
+    const gchar *name = gst_structure_get_name (s);
+
+    if (strcmp (name, "spectrum") == 0) {
+      GstElement *spectrum = GST_ELEMENT (GST_MESSAGE_SRC (message));
+      GstClockTime timestamp, duration;
+      GstClockTime waittime = GST_CLOCK_TIME_NONE;
+
+      if (gst_structure_get_clock_time (s, "running-time", &timestamp) &&
+          gst_structure_get_clock_time (s, "duration", &duration)) {
+        /* wait for middle of buffer */
+        waittime = timestamp + duration / 2;
+      } else if (gst_structure_get_clock_time (s, "endtime", &timestamp)) {
+        waittime = timestamp;
+      }
+      if (GST_CLOCK_TIME_IS_VALID (waittime)) {
+        GstClockID clock_id;
+        GstClockTime basetime = gst_element_get_base_time (spectrum);
+        gfloat *spect = g_new (gfloat, spect_bands);
+        const GValue *list;
+        const GValue *value;
+        guint i;
+
+        list = gst_structure_get_value (s, "magnitude");
+        for (i = 0; i < spect_bands; ++i) {
+          value = gst_value_list_get_value (list, i);
+          spect[i] = height_scale * g_value_get_float (value);
+        }
+
+        clock_id =
+            gst_clock_new_single_shot_id (sync_clock, waittime + basetime);
+        gst_clock_id_wait_async (clock_id, delayed_spectrum_update,
+            (gpointer) spect, NULL);
+        gst_clock_id_unref (clock_id);
+      }
+    }
+  }
+  return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+  GstElement *bin;
+  GstElement *src, *spectrum, *sink;
+  GstBus *bus;
+  GtkWidget *appwindow;
+
+  gst_init (&argc, &argv);
+  gtk_init (&argc, &argv);
+
+  bin = gst_pipeline_new ("bin");
+
+  src = gst_element_factory_make (DEFAULT_AUDIOSRC, "src");
+
+  spectrum = gst_element_factory_make ("spectrum", "spectrum");
+  g_object_set (G_OBJECT (spectrum), "bands", spect_bands, "threshold", -80,
+      "post-messages", TRUE, NULL);
+
+  sink = gst_element_factory_make ("fakesink", "sink");
+
+  gst_bin_add_many (GST_BIN (bin), src, spectrum, sink, NULL);
+  if (!gst_element_link_many (src, spectrum, sink, NULL)) {
+    fprintf (stderr, "can't link elements\n");
+    exit (1);
+  }
+
+  bus = gst_element_get_bus (bin);
+  gst_bus_add_watch (bus, message_handler, NULL);
+  gst_object_unref (bus);
+
+  sync_clock = gst_pipeline_get_clock (GST_PIPELINE (bin));
+
+  appwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  g_signal_connect (G_OBJECT (appwindow), "destroy",
+      G_CALLBACK (on_window_destroy), NULL);
+
+  drawingarea = gtk_drawing_area_new ();
+  gtk_widget_set_size_request (drawingarea, spect_bands, spect_height);
+  g_signal_connect (G_OBJECT (drawingarea), "configure-event",
+      G_CALLBACK (on_configure_event), (gpointer) spectrum);
+  gtk_container_add (GTK_CONTAINER (appwindow), drawingarea);
+  gtk_widget_show_all (appwindow);
+
+  gst_element_set_state (bin, GST_STATE_PLAYING);
+  gtk_main ();
+  gst_element_set_state (bin, GST_STATE_NULL);
+
+  gst_object_unref (sync_clock);
+  gst_object_unref (bin);
+
+  return 0;
+}
diff --git a/tests/examples/spectrum/meson.build b/tests/examples/spectrum/meson.build
new file mode 100644
index 0000000..c9eecd8
--- /dev/null
+++ b/tests/examples/spectrum/meson.build
@@ -0,0 +1,17 @@
+executable('demo-audiotest', 'demo-audiotest.c',
+  dependencies: [gstfft_dep, gst_dep, gtk_dep],
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  install: false)
+
+executable('demo-osssrc', 'demo-osssrc.c',
+  dependencies: [gst_dep, gtk_dep],
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  install: false)
+
+executable('spectrum-example', 'spectrum-example.c',
+  dependencies: [gst_dep, gtk_dep],
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  install: false)
diff --git a/tests/examples/spectrum/spectrum-example.c b/tests/examples/spectrum/spectrum-example.c
new file mode 100644
index 0000000..1052b4e
--- /dev/null
+++ b/tests/examples/spectrum/spectrum-example.c
@@ -0,0 +1,124 @@
+/* GStreamer
+ * Copyright (C) 2006 Stefan Kost <ensonic@users.sf.net>
+ * Copyright (C) 2008 Jan Schmidt <jan.schmidt@sun.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gst/gst.h>
+
+static guint spect_bands = 20;
+
+#define AUDIOFREQ 32000
+
+/* receive spectral data from element message */
+static gboolean
+message_handler (GstBus * bus, GstMessage * message, gpointer data)
+{
+  if (message->type == GST_MESSAGE_ELEMENT) {
+    const GstStructure *s = gst_message_get_structure (message);
+    const gchar *name = gst_structure_get_name (s);
+    GstClockTime endtime;
+
+    if (strcmp (name, "spectrum") == 0) {
+      const GValue *magnitudes;
+      const GValue *phases;
+      const GValue *mag, *phase;
+      gdouble freq;
+      guint i;
+
+      if (!gst_structure_get_clock_time (s, "endtime", &endtime))
+        endtime = GST_CLOCK_TIME_NONE;
+
+      g_print ("New spectrum message, endtime %" GST_TIME_FORMAT "\n",
+          GST_TIME_ARGS (endtime));
+
+      magnitudes = gst_structure_get_value (s, "magnitude");
+      phases = gst_structure_get_value (s, "phase");
+
+      for (i = 0; i < spect_bands; ++i) {
+        freq = (gdouble) ((AUDIOFREQ / 2) * i + AUDIOFREQ / 4) / spect_bands;
+        mag = gst_value_list_get_value (magnitudes, i);
+        phase = gst_value_list_get_value (phases, i);
+
+        if (mag != NULL && phase != NULL) {
+          g_print ("band %d (freq %g): magnitude %f dB phase %f\n", i, freq,
+              g_value_get_float (mag), g_value_get_float (phase));
+        }
+      }
+      g_print ("\n");
+    }
+  }
+  return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+  GstElement *bin;
+  GstElement *src, *audioconvert, *spectrum, *sink;
+  GstBus *bus;
+  GstCaps *caps;
+  GMainLoop *loop;
+
+  gst_init (&argc, &argv);
+
+  bin = gst_pipeline_new ("bin");
+
+  src = gst_element_factory_make ("audiotestsrc", "src");
+  g_object_set (G_OBJECT (src), "wave", 0, "freq", 6000.0, NULL);
+  audioconvert = gst_element_factory_make ("audioconvert", NULL);
+  g_assert (audioconvert);
+
+  spectrum = gst_element_factory_make ("spectrum", "spectrum");
+  g_object_set (G_OBJECT (spectrum), "bands", spect_bands, "threshold", -80,
+      "post-messages", TRUE, "message-phase", TRUE, NULL);
+
+  sink = gst_element_factory_make ("fakesink", "sink");
+  g_object_set (G_OBJECT (sink), "sync", TRUE, NULL);
+
+  gst_bin_add_many (GST_BIN (bin), src, audioconvert, spectrum, sink, NULL);
+
+  caps = gst_caps_new_simple ("audio/x-raw",
+      "rate", G_TYPE_INT, AUDIOFREQ, NULL);
+
+  if (!gst_element_link (src, audioconvert) ||
+      !gst_element_link_filtered (audioconvert, spectrum, caps) ||
+      !gst_element_link (spectrum, sink)) {
+    fprintf (stderr, "can't link elements\n");
+    exit (1);
+  }
+  gst_caps_unref (caps);
+
+  bus = gst_element_get_bus (bin);
+  gst_bus_add_watch (bus, message_handler, NULL);
+  gst_object_unref (bus);
+
+  gst_element_set_state (bin, GST_STATE_PLAYING);
+
+  /* we need to run a GLib main loop to get the messages */
+  loop = g_main_loop_new (NULL, FALSE);
+  g_main_loop_run (loop);
+
+  gst_element_set_state (bin, GST_STATE_NULL);
+
+  gst_object_unref (bin);
+
+  return 0;
+}
diff --git a/tests/examples/v4l2/.gitignore b/tests/examples/v4l2/.gitignore
new file mode 100644
index 0000000..094dbfe
--- /dev/null
+++ b/tests/examples/v4l2/.gitignore
@@ -0,0 +1,3 @@
+camctrl
+probe
+v4l2src-renegotiate
diff --git a/tests/examples/v4l2/Makefile.am b/tests/examples/v4l2/Makefile.am
new file mode 100644
index 0000000..1fb4165
--- /dev/null
+++ b/tests/examples/v4l2/Makefile.am
@@ -0,0 +1,9 @@
+noinst_PROGRAMS = camctrl v4l2src-renegotiate
+
+camctrl_SOURCES = camctrl.c
+camctrl_CFLAGS  = $(GST_BASE_CFLAGS) $(GST_CONTROLLER_CFLAGS) $(GST_CFLAGS)
+camctrl_LDADD = $(GST_BASE_LIBS) $(GST_CONTROLLER_LIBS) $(GST_LIBS)
+
+v4l2src_renegotiate_SOURCES = v4l2src-renegotiate.c
+v4l2src_renegotiate_CFLAGS  = $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+v4l2src_renegotiate_LDADD = $(GST_BASE_LIBS) $(GST_LIBS)
diff --git a/tests/examples/v4l2/camctrl.c b/tests/examples/v4l2/camctrl.c
new file mode 100644
index 0000000..bb61721
--- /dev/null
+++ b/tests/examples/v4l2/camctrl.c
@@ -0,0 +1,201 @@
+/* GStreamer
+ * Copyright (C) 2010 Stefan Kost <stefan.kost@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/* demo for using gstcontroler with camera capture for e.g. bracketing
+ *
+ * gcc `pkg-config --cflags --libs gstreamer-0.10 gstreamer-controller-0.10` camctrl.c -o camctrl
+ *
+ * TODO:
+ * - handle stream status and switch capture thread to SCHED_RR/FIFO
+ * - we want some feedback about how precisely a program can be realized
+ *   - we might want to adjust the framerate to handle hardware limmits
+ * - we e.g. can't change resolution per frame right now
+ */
+
+#include <gst/gst.h>
+#include <gst/controller/gstinterpolationcontrolsource.h>
+#include <gst/controller/gstdirectcontrolbinding.h>
+
+static void
+event_loop (GstElement * bin)
+{
+  GstBus *bus;
+  GstMessage *message = NULL;
+
+  bus = gst_element_get_bus (GST_ELEMENT (bin));
+
+  while (TRUE) {
+    message = gst_bus_poll (bus, GST_MESSAGE_ANY, -1);
+
+    switch (message->type) {
+      case GST_MESSAGE_EOS:
+        gst_message_unref (message);
+        return;
+      case GST_MESSAGE_WARNING:
+      case GST_MESSAGE_ERROR:{
+        GError *gerror;
+        gchar *debug;
+
+        gst_message_parse_error (message, &gerror, &debug);
+        gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+        gst_message_unref (message);
+        g_error_free (gerror);
+        g_free (debug);
+        return;
+      }
+      default:
+        gst_message_unref (message);
+        break;
+    }
+  }
+}
+
+static void
+set_program (GstObject * elem, GstStructure * prog)
+{
+  const GstStructure *s;
+  GstControlSource *cs;
+  GstClockTime ts, dur;
+  gdouble v;
+  const GValue *frame;
+  GHashTable *css;
+  gint i, j;
+  const gchar *name;
+
+  css = g_hash_table_new (g_str_hash, g_str_equal);
+
+  ts = 0;
+  dur = gst_util_uint64_scale_int (GST_SECOND, 1, 15);
+
+  /* loop over each image in prog */
+  for (i = 0; i < gst_structure_n_fields (prog); i++) {
+    GST_DEBUG ("ctrl on %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
+
+    frame =
+        gst_structure_get_value (prog, gst_structure_nth_field_name (prog, i));
+    s = gst_value_get_structure (frame);
+    for (j = 0; j < gst_structure_n_fields (s); j++) {
+      name = gst_structure_nth_field_name (s, j);
+      cs = g_hash_table_lookup (css, name);
+      if (!cs) {
+        cs = gst_interpolation_control_source_new ();
+        gst_object_add_control_binding (elem,
+            gst_direct_control_binding_new (elem, name, cs));
+        g_object_set (cs, "mode", GST_INTERPOLATION_MODE_NONE, NULL);
+        g_hash_table_insert (css, (gpointer) name, cs);
+        gst_object_unref (cs);
+      }
+      gst_structure_get_double (s, name, &v);
+      gst_timed_value_control_source_set ((GstTimedValueControlSource *) cs, ts,
+          v);
+      GST_DEBUG ("  %s = %lf", name, v);
+    }
+    ts += dur;
+  }
+
+  g_hash_table_unref (css);
+}
+
+gint
+main (gint argc, gchar ** argv)
+{
+  GstElement *bin;
+  GstElement *src, *cvt, *fmt, *enc, *sink;
+  GstCaps *caps;
+  GstStructure *prog;
+
+  /* init gstreamer */
+  gst_init (&argc, &argv);
+
+  /* create a new bin to hold the elements */
+  bin = gst_pipeline_new ("camera");
+
+  /* create elements */
+  if (!(sink = gst_element_factory_make ("multifilesink", NULL))) {
+    GST_WARNING ("Can't create element \"multifilesink\"");
+    return -1;
+  }
+  g_object_set (sink, "location", "image%02d.jpg", NULL);
+
+  if (!(enc = gst_element_factory_make ("jpegenc", NULL))) {
+    GST_WARNING ("Can't create element \"jpegenc\"");
+    return -1;
+  }
+
+  if (!(fmt = gst_element_factory_make ("capsfilter", NULL))) {
+    GST_WARNING ("Can't create element \"capsfilter\"");
+    return -1;
+  }
+  caps =
+      gst_caps_from_string
+      ("video/x-raw, width=640, height=480, framerate=(fraction)15/1");
+  g_object_set (fmt, "caps", caps, NULL);
+
+  if (!(cvt = gst_element_factory_make ("videoconvert", NULL))) {
+    GST_WARNING ("Can't create element \"videoconvert\"");
+    return -1;
+  }
+
+  if (!(src = gst_element_factory_make ("v4l2src", NULL))) {
+    GST_WARNING ("Can't create element \"v4l2src\"");
+    return -1;
+  }
+
+  /* add objects to the main bin */
+  gst_bin_add_many (GST_BIN (bin), src, cvt, fmt, enc, sink, NULL);
+
+  /* link elements */
+  if (!gst_element_link_many (src, cvt, fmt, enc, sink, NULL)) {
+    GST_WARNING ("Can't link elements");
+    return -1;
+  }
+
+  /* programm a pattern of events */
+#if 0
+  prog = gst_structure_from_string ("program"
+      ", image00=(structure)\"image\\,contrast\\=0.0\\;\""
+      ", image01=(structure)\"image\\,contrast\\=0.3\\;\""
+      ", image02=(structure)\"image\\,contrast\\=1.0\\;\""
+      ", image03=(structure)\"image\\,contrast\\=0.05\\;\";", NULL);
+#endif
+#if 1
+  prog = gst_structure_from_string ("program"
+      ", image00=(structure)\"image\\,brightness\\=1.0\\,contrast\\=0.0\\;\""
+      ", image01=(structure)\"image\\,brightness\\=0.5\\,contrast\\=0.3\\;\""
+      ", image02=(structure)\"image\\,brightness\\=0.25\\,contrast\\=1.0\\;\""
+      ", image03=(structure)\"image\\,brightness\\=0.0\\,contrast\\=0.05\\;\";",
+      NULL);
+#endif
+  set_program (GST_OBJECT (src), prog);
+  g_object_set (src, "num-buffers", gst_structure_n_fields (prog),
+      "device", argv[1] ? argv[1] : "/dev/video0", NULL);
+
+  /* prepare playback */
+  gst_element_set_state (bin, GST_STATE_PAUSED);
+
+  /* play and wait */
+  gst_element_set_state (bin, GST_STATE_PLAYING);
+
+  /* mainloop and wait for eos */
+  event_loop (bin);
+
+  /* stop and cleanup */
+  gst_element_set_state (bin, GST_STATE_NULL);
+  gst_object_unref (GST_OBJECT (bin));
+  return 0;
+}
diff --git a/tests/examples/v4l2/meson.build b/tests/examples/v4l2/meson.build
new file mode 100644
index 0000000..d59d000
--- /dev/null
+++ b/tests/examples/v4l2/meson.build
@@ -0,0 +1,11 @@
+executable('camctrl', 'camctrl.c',
+  dependencies: [gstcontroller_dep, gst_dep],
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  install: false)
+
+executable('v4l2src-renegotiate', 'v4l2src-renegotiate.c',
+  dependencies: [gst_dep],
+  c_args : gst_plugins_good_args,
+  include_directories : [configinc],
+  install: false)
diff --git a/tests/examples/v4l2/v4l2src-renegotiate.c b/tests/examples/v4l2/v4l2src-renegotiate.c
new file mode 100644
index 0000000..cae28d2
--- /dev/null
+++ b/tests/examples/v4l2/v4l2src-renegotiate.c
@@ -0,0 +1,173 @@
+/* GStreamer
+ *
+ * Copyright (C) 2015 Samsung Electronics. All rights reserved.
+ *   Author: Thiago Santos <thiagoss@osg.samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/* demo for showing v4l2src renegotiating */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+/* Options */
+static const gchar *device = "/dev/video0";
+static const gchar *videosink = "autovideosink";
+static const gchar *io_mode = "mmap";
+static const gchar *def_resolutions[] = {
+  "320x240",
+  "1280x720",
+  "640x480",
+  NULL
+};
+
+static const gchar **resolutions = def_resolutions;
+
+static GOptionEntry entries[] = {
+  {"device", 'd', 0, G_OPTION_ARG_STRING, &device, "V4L2 Camera Device",
+      NULL},
+  {"videosink", 's', 0, G_OPTION_ARG_STRING, &videosink, "Video Sink to use",
+      NULL},
+  {"io-mode", 'z', 0, G_OPTION_ARG_STRING, &io_mode,
+      "Configure the \"io-mode\" property on v4l2scr", NULL},
+  {"resolution", 'r', 0, G_OPTION_ARG_STRING_ARRAY, &resolutions,
+      "Add a resolution to the list", NULL},
+  {NULL}
+};
+
+static GMainLoop *loop;
+static GstElement *pipeline;
+static GstElement *src, *capsfilter;
+static gint resolution_index = 0;
+
+static gboolean
+bus_callback (GstBus * bus, GstMessage * message, gpointer data)
+{
+  switch (message->type) {
+    case GST_MESSAGE_EOS:
+      g_main_loop_quit (loop);
+      break;
+    case GST_MESSAGE_ERROR:{
+      GError *gerror;
+      gchar *debug;
+
+      gst_message_parse_error (message, &gerror, &debug);
+      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+      g_error_free (gerror);
+      g_free (debug);
+      g_main_loop_quit (loop);
+      break;
+    }
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+change_caps (gpointer data)
+{
+  GstCaps *caps;
+  GStrv res;
+  gchar *caps_str;
+
+  if (!resolutions[resolution_index]) {
+    gst_element_send_event (pipeline, gst_event_new_eos ());
+    return FALSE;
+  }
+
+  g_print ("Setting resolution to '%s'\n", resolutions[resolution_index]);
+
+  res = g_strsplit (resolutions[resolution_index++], "x", 2);
+  if (!res[0] || !res[1]) {
+    g_warning ("Can't parse resolution: %s", resolutions[resolution_index - 1]);
+    g_strfreev (res);
+    return TRUE;
+  }
+
+  caps_str = g_strdup_printf ("video/x-raw,width=%s,height=%s", res[0], res[1]);
+  caps = gst_caps_from_string (caps_str);
+  g_object_set (capsfilter, "caps", caps, NULL);
+
+  g_strfreev (res);
+  g_free (caps_str);
+  gst_caps_unref (caps);
+
+  return TRUE;
+}
+
+gint
+main (gint argc, gchar ** argv)
+{
+  GstBus *bus;
+  GError *error = NULL;
+  GOptionContext *context;
+  gchar *desc;
+  gboolean ret;
+
+  context = g_option_context_new ("- test v4l2src live renegotition");
+  g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
+  g_option_context_add_group (context, gst_init_get_option_group ());
+  ret = g_option_context_parse (context, &argc, &argv, &error);
+  g_option_context_free (context);
+
+  if (!ret) {
+    g_print ("option parsing failed: %s\n", error->message);
+    g_error_free (error);
+    return 1;
+  }
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  desc = g_strdup_printf ("v4l2src name=src device=\"%s\" io-mode=\"%s\" "
+      "! capsfilter name=cf ! %s", device, io_mode, videosink);
+  pipeline = gst_parse_launch (desc, &error);
+  g_free (desc);
+  if (!pipeline) {
+    g_print ("failed to create pipeline: %s", error->message);
+    g_error_free (error);
+    return 1;
+  }
+
+  src = gst_bin_get_by_name (GST_BIN (pipeline), "src");
+  capsfilter = gst_bin_get_by_name (GST_BIN (pipeline), "cf");
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+  gst_bus_add_watch (bus, bus_callback, NULL);
+  gst_object_unref (bus);
+
+  change_caps (NULL);
+
+  /* play and wait */
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  g_timeout_add_seconds (3, change_caps, NULL);
+
+  /* mainloop and wait for eos */
+  g_main_loop_run (loop);
+
+  /* stop and cleanup */
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (src);
+  gst_object_unref (capsfilter);
+  gst_object_unref (GST_OBJECT (pipeline));
+  g_main_loop_unref (loop);
+  return 0;
+}
diff --git a/tests/files/Makefile.am b/tests/files/Makefile.am
new file mode 100644
index 0000000..7b3b4dc
--- /dev/null
+++ b/tests/files/Makefile.am
@@ -0,0 +1,21 @@
+
+EXTRA_DIST = \
+	audiotestsrc.flac \
+	audiotestsrc.wav \
+	gradient.j2k \
+	h264.rtp \
+	id3-407349-1.tag \
+	id3-407349-2.tag \
+	id3-447000-wcop.tag \
+	id3-577468-unsynced-tag.tag \
+	id3-588148-unsynced-v24.tag \
+	image.jpg \
+	pcm16sine.flv \
+	pinknoise-vorbis.mkv \
+	stream.mp2 \
+	cbr_stream.mp3 \
+	vbr_stream.mp3 \
+	test-cert.pem \
+	test-key.pem \
+	splitvideo00.ogg splitvideo01.ogg \
+	splitvideo02.ogg
diff --git a/tests/files/audiotestsrc.flac b/tests/files/audiotestsrc.flac
new file mode 100644
index 0000000..2f12c3f
--- /dev/null
+++ b/tests/files/audiotestsrc.flac
Binary files differ
diff --git a/tests/files/audiotestsrc.wav b/tests/files/audiotestsrc.wav
new file mode 100644
index 0000000..5a7f02e
--- /dev/null
+++ b/tests/files/audiotestsrc.wav
Binary files differ
diff --git a/tests/files/cbr_stream.mp3 b/tests/files/cbr_stream.mp3
new file mode 100644
index 0000000..b1a5c43
--- /dev/null
+++ b/tests/files/cbr_stream.mp3
Binary files differ
diff --git a/tests/files/gradient.j2k b/tests/files/gradient.j2k
new file mode 100644
index 0000000..ad2c94a
--- /dev/null
+++ b/tests/files/gradient.j2k
Binary files differ
diff --git a/tests/files/h264.rtp b/tests/files/h264.rtp
new file mode 100644
index 0000000..53ad97e
--- /dev/null
+++ b/tests/files/h264.rtp
Binary files differ
diff --git a/tests/files/id3-407349-1.tag b/tests/files/id3-407349-1.tag
new file mode 100644
index 0000000..05cd4f6
--- /dev/null
+++ b/tests/files/id3-407349-1.tag
Binary files differ
diff --git a/tests/files/id3-407349-2.tag b/tests/files/id3-407349-2.tag
new file mode 100644
index 0000000..b16a42a
--- /dev/null
+++ b/tests/files/id3-407349-2.tag
Binary files differ
diff --git a/tests/files/id3-447000-wcop.tag b/tests/files/id3-447000-wcop.tag
new file mode 100644
index 0000000..27109ce
--- /dev/null
+++ b/tests/files/id3-447000-wcop.tag
Binary files differ
diff --git a/tests/files/id3-577468-unsynced-tag.tag b/tests/files/id3-577468-unsynced-tag.tag
new file mode 100644
index 0000000..a5880e8
--- /dev/null
+++ b/tests/files/id3-577468-unsynced-tag.tag
Binary files differ
diff --git a/tests/files/id3-588148-unsynced-v24.tag b/tests/files/id3-588148-unsynced-v24.tag
new file mode 100644
index 0000000..099d930
--- /dev/null
+++ b/tests/files/id3-588148-unsynced-v24.tag
Binary files differ
diff --git a/tests/files/image.jpg b/tests/files/image.jpg
new file mode 100644
index 0000000..c92fd79
--- /dev/null
+++ b/tests/files/image.jpg
Binary files differ
diff --git a/tests/files/pcm16sine.flv b/tests/files/pcm16sine.flv
new file mode 100644
index 0000000..2925a2a
--- /dev/null
+++ b/tests/files/pcm16sine.flv
Binary files differ
diff --git a/tests/files/pinknoise-vorbis.mkv b/tests/files/pinknoise-vorbis.mkv
new file mode 100644
index 0000000..f83006c
--- /dev/null
+++ b/tests/files/pinknoise-vorbis.mkv
Binary files differ
diff --git a/tests/files/splitvideo00.ogg b/tests/files/splitvideo00.ogg
new file mode 100644
index 0000000..66efb7f
--- /dev/null
+++ b/tests/files/splitvideo00.ogg
Binary files differ
diff --git a/tests/files/splitvideo01.ogg b/tests/files/splitvideo01.ogg
new file mode 100644
index 0000000..641f534
--- /dev/null
+++ b/tests/files/splitvideo01.ogg
Binary files differ
diff --git a/tests/files/splitvideo02.ogg b/tests/files/splitvideo02.ogg
new file mode 100644
index 0000000..0a235d1
--- /dev/null
+++ b/tests/files/splitvideo02.ogg
Binary files differ
diff --git a/tests/files/stream.mp2 b/tests/files/stream.mp2
new file mode 100644
index 0000000..ab6e900
--- /dev/null
+++ b/tests/files/stream.mp2
Binary files differ
diff --git a/tests/files/test-cert.pem b/tests/files/test-cert.pem
new file mode 100644
index 0000000..ff863b4
--- /dev/null
+++ b/tests/files/test-cert.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2zCCAcOgAwIBAgIJALRbg2WnuAAqMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
+BAMMCTEyNy4wLjAuMTAeFw0xNzA2MjAxNDI3MzBaFw0yNzA2MTgxNDI3MzBaMBQx
+EjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAKs4fuRuW77nORhOT9kbbU6BsjKW3GEsMc+ZSmXjINQWpfkES2hV+DQyzhm5
+qh4OLi1vYtXoSbdQNDCbA8ybZJqR8m9F3ed8vobdSSQGxWpPdXTgz27x+TpiAc9P
+w83UuPvlu/0AxHJBFXVAg+id0yFu3wmGWYJHoAtvFi2xeRtAXurNuPtjZyO+gfM9
+BKTRCkGsRSmPpJyGbU2Q96fjxnVfV9oYvQXeugUcSx/pTUCM/kDgD9QZCxG2rflX
+NWcqDFY3uO6ZR68Qwi/KouOa8rzrgAcwhFUI6Wz0Zwi1rzRtWK5WqC24aBUYz/tK
+hl8i88UDXSMh7spChdYDBGLhZyUCAwEAAaMwMC4wLAYDVR0RBCUwI4IJbG9jYWxo
+b3N0hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMA0GCSqGSIb3DQEBCwUAA4IBAQBj
++U8tebwg5/pof5Rht6TMHqeg6Fcr4OJkL2ph2g+T/AMTS7kEGeFIKJN5AZ+S/qIY
+cdoDKHwc8+bCK/mG6DPmJ4z/2Eamb85YhplOLVrLRwfxRebTK9CtnjcjnflAiU9H
+7vPVwXIvkwebhBSQNKTdkBlPXKaTNWXuygeFG2OVQkPf/KAxSdtg2R+owv/s802Z
+HISk26wY9oFIQz6AiXWdrY1QqNOltZ7rlU5iofAH7X+9ryZlxPWj/gHg2YQRvvLl
+dq6nCF+ED0ke7h0lg5nU0beKEygwli8DlLVbu0JK0PkARFp5t7wUtzC9DCjzvfOc
+gxR44PyZX7/2oaTDm4PS
+-----END CERTIFICATE-----
diff --git a/tests/files/test-key.pem b/tests/files/test-key.pem
new file mode 100644
index 0000000..36bbcc2
--- /dev/null
+++ b/tests/files/test-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAqzh+5G5bvuc5GE5P2RttToGyMpbcYSwxz5lKZeMg1Bal+QRL
+aFX4NDLOGbmqHg4uLW9i1ehJt1A0MJsDzJtkmpHyb0Xd53y+ht1JJAbFak91dODP
+bvH5OmIBz0/DzdS4++W7/QDEckEVdUCD6J3TIW7fCYZZgkegC28WLbF5G0Be6s24
++2NnI76B8z0EpNEKQaxFKY+knIZtTZD3p+PGdV9X2hi9Bd66BRxLH+lNQIz+QOAP
+1BkLEbat+Vc1ZyoMVje47plHrxDCL8qi45ryvOuABzCEVQjpbPRnCLWvNG1Yrlao
+LbhoFRjP+0qGXyLzxQNdIyHuykKF1gMEYuFnJQIDAQABAoIBABh+MXC99LPfYcR/
+V17IVJ+ZYANqn0XrS4jV9dWTYxvTzZRMr/jR63qUFfWKILLB9osbVvkgjIMDnyOg
+2S9Iv2B5JkQSq4a0ypCCUTctHMpzaWr5ydKmHK/kWzvrvifQmVG3cGfl1zQ86TPn
+sbbx9MTglllHdcB0PInGL1cD/z4NgEbRr1B6aBcq0AHqJJIIHvQNPmH6HGASg48j
+hVAZ2sYjp9DSK97HKSABpBCsRN8XrMgYOAsu5a1rtXhjtMUZo6LpEwEwH94rDOgv
+ZvJLGrpSvKKWPGcyANyK1a5nzO8INcXY+X54a8VB1YAjymzDy/WM1OX/jBfZem53
+HwC7m5UCgYEA3crcBI9f3aDgCYEUDWZ8hTQUVhvN3pi8QWr7QubMJmIyxBj394wm
+hTo8woYxNqy9VkO0X+jxHA0rzN1KvS9j2CAzJ+tYNhEsRc6onjEXKGLhO/1gHbkT
+rRx2J1uA2HQTbZNGhws9Qdl3A7syw6fFw9T/5rooWbiv5SDqSCRFzlcCgYEAxaDj
+JYyLLl+Jbsltkv71th5TvLi14q6KlZJGEUeSsymUx9evBS7s/h62Boe9/7Y63Zkl
+dR3IvxX7HNqW/fGjuQr9jQvMMduil8L218lChuR/4HEsXrSvyw8MIMlDtjTWajB6
+c8eiU+z/5zrlhzooKk2LaQHTUrrbxk9rN0raEOMCgYEA2Klz1wyMVL/0O7SZdyG3
+4JPojdmpeZrwxGMSwt8dbR2ehAv0KCID+z/R3SEj8Eo8x4lqKgsvhfyj3gQLH9as
+jZOfBY8U4/RQsHzaIXbJLY2yg1zYSRDkVMap8Xak3k4+MFufmQp0s+ARMFbtl05M
+lip8NdOC2WregVFvLDwq6Q8CgYBy3gyoqoPLNGRhLFqv8dlHPWFWc9XkJ6cNQLPR
+H1S5JhYAAfEMhjXhjmAmc4ePtY+JdZY7+E/SISiPoM3aVDThPO4aqRzKbeqXYw6u
+ZaBxXyakgaNUeJkk4V4fQFxG73cgyYSi/wnu1fX3pFf8vWTTEbdSFWmK0GklXsvm
+m28cGQKBgGvG//W8NGfXWL/komyKXw8GJ41Ip0sa20KNkNZwAaA1BVTaHIYT+rxo
+SgVQPHmzP8J9p4U0d9lQ5BW0LWERVkFHOg8k0evDsSm3FVbeRCBjlKqVUOLoo4Hk
+A+fSYWWWl1j9E9urpiT/d4AQY1bFUxcUebDSK9XT6ZPOusyX0fSe
+-----END RSA PRIVATE KEY-----
diff --git a/tests/files/vbr_stream.mp3 b/tests/files/vbr_stream.mp3
new file mode 100644
index 0000000..81fc38b
--- /dev/null
+++ b/tests/files/vbr_stream.mp3
Binary files differ
diff --git a/tests/icles/.gitignore b/tests/icles/.gitignore
new file mode 100644
index 0000000..9c975a3
--- /dev/null
+++ b/tests/icles/.gitignore
@@ -0,0 +1,12 @@
+equalizer-test
+gdkpixbufsink-test
+test-accurate-seek
+gdkpixbufoverlay-test
+test-segment-seeks
+test-oss4
+ximagesrc-test
+v4l2src-test
+videobox-test
+videocrop-test
+videocrop2-test
+
diff --git a/tests/icles/Makefile.am b/tests/icles/Makefile.am
new file mode 100644
index 0000000..5afe841
--- /dev/null
+++ b/tests/icles/Makefile.am
@@ -0,0 +1,77 @@
+if HAVE_GTK
+GTK_TESTS = gdkpixbufsink-test gdkpixbufoverlay-test
+
+gdkpixbufsink_test_SOURCES = gdkpixbufsink-test.c
+gdkpixbufsink_test_CFLAGS  = $(GST_CFLAGS) $(GTK_CFLAGS)
+gdkpixbufsink_test_LDADD   = $(GST_LIBS) $(GTK_LIBS)
+
+gdkpixbufoverlay_test_SOURCES = gdkpixbufoverlay-test.c
+gdkpixbufoverlay_test_CFLAGS  = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \
+	$(GDK_PIXBUF_CFLAGS) $(GIO_CFLAGS)
+gdkpixbufoverlay_test_LDADD   = $(GST_LIBS) $(GDK_PIXBUF_LIBS) $(GIO_LIBS) \
+	$(LIBM)
+else
+GTK_TESTS =
+endif
+
+V4L2_TESTS = v4l2src-test
+
+v4l2src_test_SOURCES = v4l2src-test.c
+v4l2src_test_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+v4l2src_test_LDADD = $(GST_PLUGINS_BASE_LIBS) \
+		     -lgstvideo-$(GST_API_VERSION)
+
+if USE_OSS4
+OSS4_TESTS=test-oss4
+
+test_oss4_SOURCES = test-oss4.c
+test_oss4_CFLAGS  = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+test_oss4_LDADD   = $(GST_PLUGINS_BASE_LIBS) $(GST_LIBS)
+test_oss4_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+else
+OSS4_TESTS=
+endif
+
+if USE_X
+X_TESTS = ximagesrc-test
+
+ximagesrc_test_SOURCES = ximagesrc-test.c
+ximagesrc_test_CFLAGS = $(GST_CFLAGS)
+ximagesrc_test_LDADD = $(GST_LIBS)
+else
+X_TESTS =
+endif
+
+equalizer_test_SOURCES = equalizer-test.c
+equalizer_test_CFLAGS  = $(GST_CFLAGS)
+equalizer_test_LDADD   = $(GST_LIBS)
+
+test_accurate_seek_SOURCES = test-accurate-seek.c
+test_accurate_seek_CFLAGS  = $(GST_PLUGINS_BASE_CFLAGS) \
+	$(GST_BASE_CFLAGS) $(GST_CFLAGS)
+test_accurate_seek_LDADD   = $(GST_PLUGINS_BASE_LIBS) -lgstapp-$(GST_API_VERSION) \
+	$(GST_BASE_LIBS) $(GST_LIBS)
+
+test_segment_seeks_SOURCES = test-segment-seeks.c
+test_segment_seeks_CFLAGS  = $(GST_CFLAGS)
+test_segment_seeks_LDADD   = $(GST_LIBS)
+
+videocrop_test_SOURCES = videocrop-test.c
+videocrop_test_CFLAGS  = $(GST_CFLAGS)
+videocrop_test_LDADD   = $(GST_LIBS)
+
+videobox_test_SOURCES = videobox-test.c
+videobox_test_CFLAGS  = $(GST_CFLAGS)
+videobox_test_LDADD   = $(GST_LIBS)
+
+videocrop2_test_SOURCES = videocrop2-test.c
+videocrop2_test_CFLAGS  = $(GST_CFLAGS)
+videocrop2_test_LDADD   = $(GST_LIBS)
+
+noinst_PROGRAMS = $(GTK_TESTS) $(OSS4_TESTS) $(V4L2_TESTS) $(X_TESTS) \
+	equalizer-test \
+	test-accurate-seek \
+	test-segment-seeks \
+	videocrop-test \
+	videobox-test \
+	videocrop2-test
diff --git a/tests/icles/equalizer-test.c b/tests/icles/equalizer-test.c
new file mode 100644
index 0000000..883ba33
--- /dev/null
+++ b/tests/icles/equalizer-test.c
@@ -0,0 +1,289 @@
+/* GStreamer test for the equalizer element
+ * Copyright (C) 2007 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Will tests the equalizer by fading all bands in and out one by one and
+ * finaly all together.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include <stdlib.h>
+#include <math.h>
+
+GST_DEBUG_CATEGORY_STATIC (equalizer_test_debug);
+#define GST_CAT_DEFAULT equalizer_test_debug
+
+static GstBus *pipeline_bus;
+
+static gboolean
+check_bus (GstClockTime max_wait_time)
+{
+  GstMessage *msg;
+
+  msg = gst_bus_poll (pipeline_bus, GST_MESSAGE_ERROR | GST_MESSAGE_EOS,
+      max_wait_time);
+
+  if (msg == NULL)
+    return FALSE;
+
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
+    GError *err = NULL;
+    gchar *debug = NULL;
+
+    g_assert (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR);
+    gst_message_parse_error (msg, &err, &debug);
+    GST_ERROR ("ERROR: %s [%s]", err->message, debug);
+    g_print ("\n===========> ERROR: %s\n%s\n\n", err->message, debug);
+    g_clear_error (&err);
+    g_free (debug);
+  }
+
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) {
+    g_print ("\n === EOS ===\n\n");
+  }
+
+  gst_message_unref (msg);
+  return TRUE;
+}
+
+// fix below
+
+static void
+equalizer_set_band_value (GstElement * eq, guint band, gdouble val)
+{
+  GObject *child;
+
+  child = gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (eq), band);
+  g_object_set (child, "gain", val, NULL);
+  g_object_unref (child);
+  g_print ("Band %2d: %.2f\n", band, val);
+}
+
+static void
+equalizer_set_all_band_values (GstElement * eq, guint num, gdouble val)
+{
+  gint i;
+  GObject *child;
+
+  for (i = 0; i < num; i++) {
+    child = gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (eq), i);
+    g_object_set (child, "gain", val, NULL);
+    g_object_unref (child);
+  }
+  g_print ("All bands: %.2f\n", val);
+}
+
+// fix above
+
+static gboolean
+equalizer_set_band_value_and_wait (GstElement * eq, guint band, gdouble val)
+{
+  equalizer_set_band_value (eq, band, val);
+  return check_bus (100 * GST_MSECOND);
+}
+
+static gboolean
+equalizer_set_all_band_values_and_wait (GstElement * eq, guint num, gdouble val)
+{
+  equalizer_set_all_band_values (eq, num, val);
+  return check_bus (100 * GST_MSECOND);
+}
+
+static void
+do_slider_fiddling (GstElement * playbin, GstElement * eq)
+{
+  gboolean stop;
+  guint num_bands, i;
+  gdouble d, step = 0.5;
+
+  stop = FALSE;
+
+  g_object_get (eq, "num-bands", &num_bands, NULL);
+
+  g_print ("%u bands.\n", num_bands);
+
+  while (!stop) {
+    for (i = 0; !stop && i < num_bands; ++i) {
+      d = -24.0;
+      while (!stop && d <= 12.0) {
+        stop = equalizer_set_band_value_and_wait (eq, i, d);
+        d += step;
+      }
+      d = 12.0;
+      while (!stop && d >= -24.0) {
+        stop = equalizer_set_band_value_and_wait (eq, i, d);
+        d -= step;
+      }
+      d = -24.0;
+      while (!stop && d <= 12.0) {
+        stop = equalizer_set_band_value_and_wait (eq, i, d);
+        d += step;
+      }
+    }
+
+    d = 0.0;
+    while (!stop && d <= 12.0) {
+      stop = equalizer_set_all_band_values_and_wait (eq, num_bands, d);
+      d += step;
+    }
+    d = 12.0;
+    while (!stop && d >= -24.0) {
+      stop = equalizer_set_all_band_values_and_wait (eq, num_bands, d);
+      d -= step;
+    }
+    d = -24.0;
+    while (!stop && d <= 0.0) {
+      stop = equalizer_set_all_band_values_and_wait (eq, num_bands, d);
+      d += step;
+    }
+  }
+}
+
+int
+main (int argc, char **argv)
+{
+  gchar *opt_audiosink_str = NULL;
+  gchar **filenames = NULL;
+  const GOptionEntry test_goptions[] = {
+    {"audiosink", '\0', 0, G_OPTION_ARG_STRING, &opt_audiosink_str,
+        "audiosink to use (default: autoaudiosink)", NULL},
+    {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL},
+    {NULL, '\0', 0, 0, NULL, NULL, NULL}
+  };
+  GOptionContext *ctx;
+  GError *opt_err = NULL;
+
+  GstStateChangeReturn ret;
+  GstElement *playbin, *sink, *bin, *eq, *auconv;
+  GstPad *eq_sinkpad;
+  gchar *uri;
+
+  /* command line option parsing */
+  ctx = g_option_context_new ("FILENAME");
+  g_option_context_add_group (ctx, gst_init_get_option_group ());
+  g_option_context_add_main_entries (ctx, test_goptions, NULL);
+
+  if (!g_option_context_parse (ctx, &argc, &argv, &opt_err)) {
+    g_error ("Error parsing command line options: %s", opt_err->message);
+    g_option_context_free (ctx);
+    g_clear_error (&opt_err);
+    return -1;
+  }
+  g_option_context_free (ctx);
+
+  GST_DEBUG_CATEGORY_INIT (equalizer_test_debug, "equalizertest", 0, "eqtest");
+
+  if (filenames == NULL || *filenames == NULL) {
+    g_printerr ("Please specify a file to play back\n");
+    return -1;
+  }
+
+  playbin = gst_element_factory_make ("playbin", "playbin");
+  if (playbin == NULL) {
+    g_error ("Couldn't create 'playbin' element");
+    return -1;
+  }
+
+  if (opt_audiosink_str) {
+    g_print ("Trying audiosink '%s' ...", opt_audiosink_str);
+    sink = gst_element_factory_make (opt_audiosink_str, "sink");
+    g_print ("%s\n", (sink) ? "ok" : "element couldn't be created");
+  } else {
+    sink = NULL;
+  }
+  if (sink == NULL) {
+    g_print ("Trying audiosink '%s' ...", "autoaudiosink");
+    sink = gst_element_factory_make ("autoaudiosink", "sink");
+    g_print ("%s\n", (sink) ? "ok" : "element couldn't be created");
+  }
+  if (sink == NULL) {
+    g_print ("Trying audiosink '%s' ...", "alsasink");
+    sink = gst_element_factory_make ("alsasink", "sink");
+    g_print ("%s\n", (sink) ? "ok" : "element couldn't be created");
+  }
+  if (sink == NULL) {
+    g_print ("Trying audiosink '%s' ...", "osssink");
+    sink = gst_element_factory_make ("osssink", "sink");
+    g_print ("%s\n", (sink) ? "ok" : "element couldn't be created");
+  }
+
+  g_assert (sink != NULL);
+
+  bin = gst_bin_new ("ausinkbin");
+  g_assert (bin != NULL);
+
+  eq = gst_element_factory_make ("equalizer-nbands", "equalizer");
+  g_assert (eq != NULL);
+
+  auconv = gst_element_factory_make ("audioconvert", "eqauconv");
+  g_assert (auconv != NULL);
+
+  gst_bin_add_many (GST_BIN (bin), eq, auconv, sink, NULL);
+
+  if (!gst_element_link (eq, auconv))
+    g_error ("Failed to link equalizer to audioconvert");
+
+  if (!gst_element_link (auconv, sink))
+    g_error ("Failed to link audioconvert to audio sink");
+
+  eq_sinkpad = gst_element_get_static_pad (eq, "sink");
+  g_assert (eq_sinkpad != NULL);
+
+  gst_element_add_pad (bin, gst_ghost_pad_new (NULL, eq_sinkpad));
+  gst_object_unref (eq_sinkpad);
+
+  g_object_set (playbin, "audio-sink", bin, NULL);
+
+  /* won't work: uri = gst_uri_construct ("file", filenames[0]); */
+  uri = g_strdup_printf ("file://%s", filenames[0]);
+  g_object_set (playbin, "uri", uri, NULL);
+  g_free (uri);
+
+  pipeline_bus = GST_ELEMENT_BUS (playbin);
+
+  ret = gst_element_set_state (playbin, GST_STATE_PLAYING);
+  if (ret == GST_STATE_CHANGE_FAILURE) {
+    g_printerr ("Failed to set playbin to PLAYING\n");
+    check_bus (1 * GST_SECOND);
+    return -1;
+  }
+
+  ret = gst_element_get_state (playbin, NULL, NULL, 5 * GST_SECOND);
+  if (ret == GST_STATE_CHANGE_ASYNC) {
+    g_printerr ("Failed to go to PLAYING in 5 seconds, bailing out\n");
+    return -1;
+  } else if (ret != GST_STATE_CHANGE_SUCCESS) {
+    g_printerr ("State change to PLAYING failed\n");
+    check_bus (1 * GST_SECOND);
+    return -1;
+  }
+
+  g_print ("Playing ...\n");
+  do_slider_fiddling (playbin, eq);
+
+  gst_element_set_state (playbin, GST_STATE_NULL);
+  gst_object_unref (playbin);
+
+  return 0;
+}
diff --git a/tests/icles/gdkpixbufoverlay-test.c b/tests/icles/gdkpixbufoverlay-test.c
new file mode 100644
index 0000000..45276ee
--- /dev/null
+++ b/tests/icles/gdkpixbufoverlay-test.c
@@ -0,0 +1,278 @@
+/* GStreamer gdkpixbufoverlay test app
+ * Copyright (C) 2014 Tim-Philipp Müller <tim centricular com>
+
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gio/gio.h>
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include <math.h>
+
+#define VIDEO_WIDTH 720
+#define VIDEO_HEIGHT 480
+#define VIDEO_FPS 50
+
+/* GdkPixbuf RGBA C-Source image dump from gdk-pixbuf-csource --raw,
+ * gzipped and then base64 encoded */
+const gchar gzipped_pixdata_base64[] =
+    "H4sICPX/Z1QAA2xvZ28ucGl4AO2dsZHrNhCG+ewK2II64ClyrhmnTtSBh4kLUOLQAUuwEhSgFtiA"
+    "A7agwA2wBT5AXJ5w4P5LgKLEO97ezDf2SCAIAftjFwuQ7/c///ojy/77+8eP7Jcs+/WfLMv+t/zW"
+    "dV32pSmK3HK6sXZbFOXV9PZfWipLbWksHdHQZxVpZP+Ee7u62/d7rt0fivIqimJnOX+w/zhauq68"
+    "aWjevfdUR1h3vXq/KMqzufueFN1J1FE+stf8KfCzobZ3q/ePojyT3v8gDSyB09GFND7g/N014rpl"
+    "41xF+Wz0/i817nwFjepP+Rb0PnDwOUOehePyQq1eurlrSkXZOkVx7OblbGK43upf+zcqyldhOT22"
+    "5GvV9ynKXIriQDpKye242Ldcve2KskX6deaRWVeebnpdu32Koryc4t/iaKksmm9Vvg3W3neWk+Vs"
+    "qS2tpSOu9NmZtLG4f7R15paS7jXct1q7XxTl2ZDd157dp1A/6q9I+1Wg+QH1g8pmcb7M0szUHseV"
+    "/KTTtJg39XyudH/NASmbhfzOUtqTNHmhew1cglhT9ad8O16kv7m4eFT3/pVNQ77IX8shLgW/RnsW"
+    "Li7V5y4UJaDo9wnOT9Sjq1fzn4oSQXHft4tZ00Vpr5jI3yiKwmO1sy/63GZKzNpS+dVyLsaYneVk"
+    "Ud+rbIqi32M/kC7DtaXzn6vt9Vm95ZbS0lg64rx2nynKdyHQ3oC+A06ZxdtbkztWundpqS1fKo5j"
+    "9OfQ8+jKJNbW987eye47QGO5WE6u/BPakJP2rt4927X7JhanNaBBzQUpEMbmU2hJk66O2ftt7lrS"
+    "f8vc4yl+0P7llspyWapOl3th9Hdde4yVz4m17eMD2pP8ZBXjI0l3J7oG1Rf1DlH7dyBOpKuB2+dB"
+    "2ZzKXS3ugw9+lnKZB49oH2bL1owGH9K4vX5P7Yg+0+O1/Uj/XSRm8ep9Ws6LclrRfe+N1+xYIxjz"
+    "49Jrh6D+m68inSypPeQja7pXRZp3/z1P6M7XM+xX+7eznElHc3E63Hv2xWmoo89H4yLEnpDg+orq"
+    "DsnJFq7oWqYtLhd7sbTg3i3dL2VO2Xlt5Oo7DzY1Uc8VtOng9eMZtP0ctpnmJa787Tcm/jbUtmHc"
+    "xfmG+p0bwz0R9t1hYr33WTgj/ZEfe1R7HfnJ3NNCjIbKoP8f1SBn2w2Nq3htYI9o7uBopnRI9nmO"
+    "rM/ZveijhWulee+DFrx2xZSHe0Gmn99ix5sd96A+1E97w88pB8bX1ABubfYK4DxG+msYPbWWksqU"
+    "gu5a0u/O68PQ3t99hWF8kW9vC2gQaWTyWtD2sB5UVzOhGeRLJR2y/pB0k9RHgCqxXaP2kP5Qn9TU"
+    "n+He7rumwO/j5oSr0FanQZf/jIp33+650qXXjSj2FP2+y58AbYVrPs5PjuyOxsTvq5H+yYb8Mofg"
+    "u8rgmKb2vq/C+lPtMLj2KOjBbyPSqTS3N9T2Y/D5SbAtdt1r4uapoZ9ife+VroHzlQn2ZCf0dw7K"
+    "7rk2Cn2VMo6z15pP1KPzt5N72LT+4/Q36hv7d+R8INN/oR2zdunZEcyvANuEPj3SNlkNmvHcIY6x"
+    "4eeHWbkiSfugvBT3jeLYifKdCdaHggbC+Q7Vi+YOriznW5PG8BENAj3G5FYQTsslWvcxuqqABke6"
+    "oXzoqGyEfcC1kunnXRRvcfOm2N9mOo4szX1df/DnB4P9BbsOMmANNXf8F9TgaB1p5LlppBehfr+/"
+    "0PiwuhJ+Y+hbpXpbGsNbLtTcc66LPzP31u+rDznPesJPDnnS5Ny2oMGRnSdoEOVERjpE2qTvTmAc"
+    "pGuQ7Yg5EyP7QDY3gjQozREzNIhiNXTv1Ni1BeOCyvvxOJqzUJtzUD6MWaX1wKd4P9HbgmfdhFwL"
+    "p0FOr9x6EOngmtKHpt8TGNUxcQ2yTXGeNLL/lHz4Qxo09/0tNN8gH4zainIcyK7ZuF7Q4D6iDal1"
+    "1kE5ZD+bfD+DsB48BuXy7L7//mEvgulrKWd3iyUi7ZPzS+J6C1wz+XyFkfMWB0D02tHrl2FfMDYX"
+    "yfUvitXg2QvBrlHMyM4JEW3oqC+5/orymwbEUWtr5ck65PKidVCGy4leh71AZgwlv9JN6VDQsZSP"
+    "QddM+iUw7nM5BHWn7jWKbRf6VsrJcjEFtGug2dr7HvntOYQa5OanTT8jY//2tMcXauxCuVBOo+9n"
+    "YYRxnNIhvN7g2AnGI+iamD4w6bnwqN810QctaUM6V8LlDJFPk9a7qfllzmdVEW2Yg18vmkc/xTrw"
+    "yTqU9uDD/fgK+b9EHcK1nTDGcF0Hrok6Gyu00c33KBZlifztYY6fPbcG2poUqwl2LeWXuXv4OVEp"
+    "95XUX/6Yoj5bWx8v0F8OfN3g72rS3TFWewk6RHuHXOwkjoXhfVnsOcdFc5xUJ/Jto7gKlEX5xUlN"
+    "x/T/RNvFvhA0GDXnCfedPY9+ZUhjvu4Wfy5P0CHKoXGaEMci1TYj7sfqJbI+uBfwSNuFelPPXkp+"
+    "k823BGXQWuGh3AmYRzf9zpKMOfvyYB8uEiuC8ZXO00zuZ020G83rs8Y/xU8gmwcaRPVKa+uk/LLh"
+    "8y1NUEbKfc+aww3eP/xS73xIBez5XbKPzwuW3H4h6Ec3j6E9ba6PkR9MGgvBNmPbLeXa58TfKRqM"
+    "brtJPJuTom/vGm4dwJ2lQXmsWe/cM4l7mFtBOCcjPR+B9iMGW4LnGWLHa4bdzNqbj6wj2QYEXYX+"
+    "JPWMKlcOvpdEaIcUu0blUA1eX7Bnbx7os02/N4iLRSMY7QuacWwSc24YjhXQgxQ/sT4s0QbQs2kO"
+    "dl1o+hiYs09p/8x/7kPaqw/3GZGfkPbmka9C5wiQ30RzJdp3R2cTh3MKozk6ta1bgfYGUzU42sMX"
+    "xsP1q4ttuLxfci7Ps18/RwfPI6f2x4QOG087/m8arRlN2vN9yP+G5yiTcpETbUBxCpo7kGZzof3D"
+    "OwGG56ca7/NwDkdrwc1qUNiXT4Hrx9hn1WLOj0n7wDF7Vcka9Gw39lyL9Gz51P78ebAv1G9BfWiv"
+    "A2kQ+mKhzbP2aEz8s8DsmWGDfbxjc/+OENDfib4b3uNUejmZqGd8g/5EY3k1CWt2cz9nONR380XM"
+    "+HPvHlnivU/ce19aA96FA/TsP2984q6jcpeg/f75kTyoxwfFiSW6ZkJLHDHvt8np93Hv3xliCLT2"
+    "OIEx3OTeILMf2EztCYKYNcYG2fMQivKdYbQUpY1s/M6ZTcbpivJMMv5Zpdhn7mdpV1GUO1l/NjTU"
+    "Usx7Z8Iz3ZuM0xXlFWT8s4CsDkmzJZPD0ThUUWaSye8THZ6RqOj/uf2L1f79T0XZCpn8vJJ0Pkb9"
+    "n6IsCOVoBp/HvS+moe83+T4dRVEUZRmyn2F9swl9yAAA";
+
+static GdkPixbuf *logo_pixbuf;
+
+static GMainLoop *main_loop;
+static gint count;
+
+static GdkPixbuf *
+create_overlay_pixbuf (void)
+{
+  GZlibDecompressor *decompress;
+  GConverterResult decomp_res;
+  guchar *gzipped_pixdata, *pixdata, *pixels_copy;
+  gsize gzipped_size, bytes_read, pixdata_size;
+  guint stride, width, height;
+  GdkPixbuf *pixbuf;
+
+  gzipped_pixdata = g_base64_decode (gzipped_pixdata_base64, &gzipped_size);
+  g_assert (gzipped_pixdata != NULL);
+
+  pixdata = g_malloc (64 * 1024);
+
+  decompress = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
+  decomp_res = g_converter_convert (G_CONVERTER (decompress),
+      gzipped_pixdata, gzipped_size, pixdata, 64 * 1024,
+      G_CONVERTER_INPUT_AT_END, &bytes_read, &pixdata_size, NULL);
+  g_assert (decomp_res == G_CONVERTER_FINISHED);
+  g_assert (bytes_read == gzipped_size);
+  g_free (gzipped_pixdata);
+  g_object_unref (decompress);
+
+  /* 0: Pixbuf magic (0x47646b50) */
+  g_assert (GST_READ_UINT32_BE (pixdata) == 0x47646b50);
+
+  /* pixdata length */
+  pixdata_size = GST_READ_UINT32_BE (pixdata + 4);
+  g_assert (pixdata_size > 4 + 4 + 4 + 4 + 4 + 4);
+
+  /* raw, 8-bit depth, RGBA */
+  g_assert (GST_READ_UINT32_BE (pixdata + 8) == 0x01010002);
+
+  stride = GST_READ_UINT32_BE (pixdata + 12);
+  width = GST_READ_UINT32_BE (pixdata + 16);
+  height = GST_READ_UINT32_BE (pixdata + 20);
+
+  g_assert (pixdata_size == 24 + height * stride);
+
+  pixels_copy = g_memdup (pixdata + 24, height * stride);
+
+  pixbuf =
+      gdk_pixbuf_new_from_data (pixels_copy, GDK_COLORSPACE_RGB, TRUE, 8,
+      width, height, stride, (GdkPixbufDestroyNotify) g_free, pixels_copy);
+
+  g_assert (pixbuf != NULL);
+
+  g_free (pixdata);
+
+  return pixbuf;
+}
+
+static gboolean
+bus_cb (GstBus * bus, GstMessage * msg, gpointer user_data)
+{
+  GMainLoop *loop = user_data;
+
+  switch (GST_MESSAGE_TYPE (msg)) {
+    case GST_MESSAGE_ERROR:{
+      GError *err = NULL;
+      gchar *dbg;
+
+      gst_message_parse_error (msg, &err, &dbg);
+      gst_object_default_error (msg->src, err, dbg);
+      g_clear_error (&err);
+      g_free (dbg);
+      g_main_loop_quit (loop);
+      break;
+    }
+    default:
+      break;
+  }
+  return TRUE;
+}
+
+#define SPEED_SCALE_FACTOR (VIDEO_FPS * 4)
+
+/* nicked from videotestsrc's ball pattern renderer */
+static void
+calculate_position (gint * x, gint * y, guint logo_w, guint logo_h, guint n)
+{
+  guint r_x = logo_w / 2;
+  guint r_y = logo_h / 2;
+  guint w = VIDEO_WIDTH + logo_w;
+  guint h = VIDEO_HEIGHT + logo_h;
+
+  *x = r_x + (0.5 + 0.5 * sin (2 * G_PI * n / SPEED_SCALE_FACTOR))
+      * (w - 2 * r_x);
+  *y = r_y + (0.5 + 0.5 * sin (2 * G_PI * sqrt (2) * n / SPEED_SCALE_FACTOR))
+      * (h - 2 * r_y);
+
+  *x -= logo_w;
+  *y -= logo_h;
+}
+
+static GstPadProbeReturn
+buffer_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
+{
+  GstElement *overlay = GST_PAD_PARENT (pad);
+  gint x, y, w, h;
+
+  w = gdk_pixbuf_get_width (logo_pixbuf);
+  h = gdk_pixbuf_get_height (logo_pixbuf);
+
+  calculate_position (&x, &y, w, h, ++count);
+
+  GST_LOG ("%3d, %3d", x, y);
+
+  g_object_set (overlay, "offset-x", x, "offset-y", y, NULL);
+
+  return GST_PAD_PROBE_OK;
+}
+
+int
+main (int argc, char **argv)
+{
+  GOptionEntry options[] = {
+    {NULL}
+  };
+  GOptionContext *ctx;
+  GError *err = NULL;
+  GstElement *src, *q, *capsfilter, *overlay, *sink;
+  GstElement *pipeline;
+  GstPad *sink_pad;
+  GstCaps *filter_caps;
+
+  ctx = g_option_context_new ("");
+  g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
+  g_option_context_add_group (ctx, gst_init_get_option_group ());
+  if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
+    g_print ("Error initializing: %s\n", err->message);
+    g_option_context_free (ctx);
+    g_clear_error (&err);
+    return 1;
+  }
+  g_option_context_free (ctx);
+
+  logo_pixbuf = create_overlay_pixbuf ();
+
+  main_loop = g_main_loop_new (NULL, FALSE);
+
+  pipeline = gst_pipeline_new ("pipeline");
+
+  src = gst_element_factory_make ("videotestsrc", NULL);
+  gst_util_set_object_arg (G_OBJECT (src), "pattern", "white");
+
+  overlay = gst_element_factory_make ("gdkpixbufoverlay", NULL);
+
+  /* set positioning-mode to absolute so we can set negative positions */
+  g_object_set (overlay, "pixbuf", logo_pixbuf, "positioning-mode", 1, NULL);
+
+  sink_pad = gst_element_get_static_pad (overlay, "sink");
+  gst_pad_add_probe (sink_pad, GST_PAD_PROBE_TYPE_BUFFER, buffer_cb, NULL,
+      NULL);
+  gst_object_unref (sink_pad);
+
+  q = gst_element_factory_make ("queue", NULL);
+
+  capsfilter = gst_element_factory_make ("capsfilter", NULL);
+  filter_caps = gst_caps_from_string ("video/x-raw, format = "
+      GST_VIDEO_OVERLAY_COMPOSITION_BLEND_FORMATS);
+  gst_caps_set_simple (filter_caps,
+      "width", G_TYPE_INT, VIDEO_WIDTH,
+      "height", G_TYPE_INT, VIDEO_HEIGHT,
+      "framerate", GST_TYPE_FRACTION, VIDEO_FPS, 1, NULL);
+  g_object_set (capsfilter, "caps", filter_caps, NULL);
+  gst_caps_unref (filter_caps);
+
+  sink = gst_element_factory_make ("ximagesink", NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, q, overlay, capsfilter, sink,
+      NULL);
+
+  gst_element_link_many (src, q, overlay, capsfilter, sink, NULL);
+
+  count = 0;
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  gst_bus_add_watch (GST_ELEMENT_BUS (pipeline), bus_cb, main_loop);
+
+  g_main_loop_run (main_loop);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+  g_object_unref (logo_pixbuf);
+
+  return 0;
+}
diff --git a/tests/icles/gdkpixbufsink-test.c b/tests/icles/gdkpixbufsink-test.c
new file mode 100644
index 0000000..6c2825a
--- /dev/null
+++ b/tests/icles/gdkpixbufsink-test.c
@@ -0,0 +1,364 @@
+/* GStreamer interactive test for the gdkpixbufsink element
+ * Copyright (C) 2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gtk/gtk.h>
+
+typedef struct
+{
+  GstElement *pipe;
+  GstElement *sink;
+  gboolean got_video;
+
+  GtkWidget *win;
+  GtkWidget *img;
+  GtkWidget *slider;
+  GtkWidget *accurate_cb;
+
+  gboolean accurate;            /* whether to try accurate seeks */
+
+  gint64 cur_pos;
+  gboolean prerolled;
+} AppInfo;
+
+static void seek_to (AppInfo * info, gdouble percent);
+
+static GstElement *
+create_element (const gchar * factory_name)
+{
+  GstElement *element;
+
+  element = gst_element_factory_make (factory_name, NULL);
+
+  if (element == NULL)
+    g_error ("Failed to create '%s' element", factory_name);
+
+  return element;
+}
+
+static void
+new_decoded_pad (GstElement * dec, GstPad * new_pad, AppInfo * info)
+{
+  const gchar *sname;
+  GstElement *csp, *scale, *filter;
+  GstStructure *s;
+  GstCaps *caps;
+  GstPad *sinkpad;
+
+  /* already found a video stream? */
+  if (info->got_video)
+    return;
+
+  /* FIXME: is this racy or does decodebin make sure caps are always
+   * negotiated at this point? */
+  caps = gst_pad_query_caps (new_pad, NULL);
+  g_return_if_fail (caps != NULL);
+
+  s = gst_caps_get_structure (caps, 0);
+  sname = gst_structure_get_name (s);
+  if (!g_str_has_prefix (sname, "video/x-raw"))
+    goto not_video;
+
+  csp = create_element ("videoconvert");
+  scale = create_element ("videoscale");
+  filter = create_element ("capsfilter");
+  info->sink = create_element ("gdkpixbufsink");
+  g_object_set (info->sink, "qos", FALSE, "max-lateness", (gint64) - 1, NULL);
+
+  gst_bin_add_many (GST_BIN (info->pipe), csp, scale, filter, info->sink, NULL);
+
+  sinkpad = gst_element_get_static_pad (csp, "sink");
+  if (GST_PAD_LINK_FAILED (gst_pad_link (new_pad, sinkpad)))
+    g_error ("Can't link new decoded pad to videoconvert's sink pad");
+  gst_object_unref (sinkpad);
+
+  if (!gst_element_link (csp, scale))
+    g_error ("Can't link videoconvert to videoscale");
+  if (!gst_element_link (scale, filter))
+    g_error ("Can't link videoscale to capsfilter");
+  if (!gst_element_link (filter, info->sink))
+    g_error ("Can't link capsfilter to gdkpixbufsink");
+
+  gst_element_set_state (info->sink, GST_STATE_PAUSED);
+  gst_element_set_state (filter, GST_STATE_PAUSED);
+  gst_element_set_state (scale, GST_STATE_PAUSED);
+  gst_element_set_state (csp, GST_STATE_PAUSED);
+
+  info->got_video = TRUE;
+  return;
+
+not_video:
+  return;
+}
+
+static void
+no_more_pads (GstElement * decodebin, AppInfo * info)
+{
+  if (!info->got_video) {
+    g_error ("This file does not contain a video track, or you do not have "
+        "the necessary decoder(s) installed");
+  }
+}
+
+static void
+bus_message_cb (GstBus * bus, GstMessage * msg, AppInfo * info)
+{
+  switch (GST_MESSAGE_TYPE (msg)) {
+    case GST_MESSAGE_ASYNC_DONE:{
+      /* only interested in async-done messages from the top-level pipeline */
+      if (msg->src != GST_OBJECT_CAST (info->pipe))
+        break;
+
+      if (!info->prerolled) {
+        /* make slider visible if it's not visible already */
+        gtk_widget_show (info->slider);
+
+        /* initial frame is often black, so seek to beginning plus a bit */
+        seek_to (info, 0.001);
+        info->prerolled = TRUE;
+      }
+
+      /* update position */
+      if (!gst_element_query_position (info->pipe, GST_FORMAT_TIME,
+              &info->cur_pos))
+        info->cur_pos = -1;
+      break;
+    }
+    case GST_MESSAGE_ELEMENT:{
+      const GValue *val;
+      GdkPixbuf *pixbuf = NULL;
+      const GstStructure *structure;
+
+      /* only interested in element messages from our gdkpixbufsink */
+      if (msg->src != GST_OBJECT_CAST (info->sink))
+        break;
+
+      /* only interested in these two messages */
+      if (!gst_message_has_name (msg, "preroll-pixbuf") &&
+          !gst_message_has_name (msg, "pixbuf")) {
+        break;
+      }
+
+      g_print ("pixbuf\n");
+      structure = gst_message_get_structure (msg);
+      val = gst_structure_get_value (structure, "pixbuf");
+      g_return_if_fail (val != NULL);
+
+      pixbuf = GDK_PIXBUF (g_value_dup_object (val));
+      gtk_image_set_from_pixbuf (GTK_IMAGE (info->img), pixbuf);
+      g_object_unref (pixbuf);
+      break;
+    }
+    case GST_MESSAGE_ERROR:{
+      GError *err = NULL;
+      gchar *dbg = NULL;
+
+      gst_message_parse_error (msg, &err, &dbg);
+      g_error ("Error: %s\n%s\n", err->message, (dbg) ? dbg : "");
+      g_clear_error (&err);
+      g_free (dbg);
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+static gboolean
+create_pipeline (AppInfo * info, const gchar * filename)
+{
+  GstElement *src, *dec;
+  GstBus *bus;
+
+  info->pipe = gst_pipeline_new ("pipeline");
+  src = create_element ("filesrc");
+  g_object_set (src, "location", filename, NULL);
+
+  dec = create_element ("decodebin");
+
+  gst_bin_add_many (GST_BIN (info->pipe), src, dec, NULL);
+  if (!gst_element_link (src, dec))
+    g_error ("Can't link filesrc to decodebin");
+
+  g_signal_connect (dec, "pad-added", G_CALLBACK (new_decoded_pad), info);
+
+  g_signal_connect (dec, "no-more-pads", G_CALLBACK (no_more_pads), info);
+
+  /* set up bus */
+  bus = gst_element_get_bus (info->pipe);
+  gst_bus_add_signal_watch (bus);
+  g_signal_connect (bus, "message", G_CALLBACK (bus_message_cb), info);
+  gst_object_unref (bus);
+
+  return TRUE;
+}
+
+static void
+seek_to (AppInfo * info, gdouble percent)
+{
+  GstSeekFlags seek_flags;
+  gint64 seek_pos, dur = -1;
+
+  if (!gst_element_query_duration (info->pipe, GST_FORMAT_TIME, &dur)
+      || dur <= 0) {
+    g_printerr ("Could not query duration\n");
+    return;
+  }
+
+  seek_pos = gst_gdouble_to_guint64 (gst_guint64_to_gdouble (dur) * percent);
+  g_print ("Seeking to %" GST_TIME_FORMAT ", accurate: %d\n",
+      GST_TIME_ARGS (seek_pos), info->accurate);
+
+  seek_flags = GST_SEEK_FLAG_FLUSH;
+
+  if (info->accurate)
+    seek_flags |= GST_SEEK_FLAG_ACCURATE;
+  else
+    seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
+
+  if (!gst_element_seek_simple (info->pipe, GST_FORMAT_TIME, seek_flags,
+          seek_pos)) {
+    g_printerr ("Seek failed.\n");
+    return;
+  }
+}
+
+static void
+slider_cb (GtkRange * range, AppInfo * info)
+{
+  gdouble val;
+
+  val = gtk_range_get_value (range);
+  seek_to (info, val);
+}
+
+static gchar *
+slider_format_value_cb (GtkScale * scale, gdouble value, AppInfo * info)
+{
+  gchar s[64];
+
+  if (info->cur_pos < 0)
+    return g_strdup_printf ("%0.1g%%", value * 100.0);
+
+  g_snprintf (s, 64, "%" GST_TIME_FORMAT, GST_TIME_ARGS (info->cur_pos));
+  s[10] = '\0';
+  return g_strdup (s);
+}
+
+static void
+accurate_toggled_cb (GtkToggleButton * toggle, AppInfo * info)
+{
+  info->accurate = gtk_toggle_button_get_active (toggle);
+}
+
+static void
+run_gui (const gchar * filename)
+{
+  GtkWidget *vbox, *hbox;
+  AppInfo *info;
+
+  info = g_new0 (AppInfo, 1);
+
+  /* create pipeline */
+  if (!create_pipeline (info, filename))
+    goto done;
+
+  /* create window */
+  info->win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  g_signal_connect (info->win, "delete-event", G_CALLBACK (gtk_main_quit),
+      NULL);
+
+  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
+  gtk_container_add (GTK_CONTAINER (info->win), vbox);
+
+  info->img = gtk_image_new ();
+  gtk_box_pack_start (GTK_BOX (vbox), info->img, FALSE, FALSE, 6);
+
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 6);
+
+  info->accurate_cb = gtk_check_button_new_with_label ("accurate seek "
+      "(might not work reliably with all demuxers)");
+  gtk_box_pack_start (GTK_BOX (hbox), info->accurate_cb, FALSE, FALSE, 6);
+  g_signal_connect (info->accurate_cb, "toggled",
+      G_CALLBACK (accurate_toggled_cb), info);
+
+  info->slider = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL,
+      0.0, 1.0, 0.001);
+  gtk_box_pack_start (GTK_BOX (vbox), info->slider, FALSE, FALSE, 6);
+  g_signal_connect (info->slider, "value-changed",
+      G_CALLBACK (slider_cb), info);
+  g_signal_connect (info->slider, "format-value",
+      G_CALLBACK (slider_format_value_cb), info);
+
+  /* and go! */
+  gst_element_set_state (info->pipe, GST_STATE_PAUSED);
+
+  gtk_widget_show_all (info->win);
+  gtk_widget_hide (info->slider);       /* hide until we're prerolled */
+  gtk_main ();
+
+done:
+
+  g_free (info);
+}
+
+static gchar **filenames = NULL;
+
+int
+main (int argc, char **argv)
+{
+  static const GOptionEntry test_goptions[] = {
+    {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL},
+    {NULL, '\0', 0, 0, NULL, NULL, NULL}
+  };
+  GOptionContext *ctx;
+  GError *opt_err = NULL;
+
+  gtk_init (&argc, &argv);
+
+  /* command line option parsing */
+  ctx = g_option_context_new (" VIDEOFILE");
+  g_option_context_add_group (ctx, gst_init_get_option_group ());
+  g_option_context_add_main_entries (ctx, test_goptions, NULL);
+
+  if (!g_option_context_parse (ctx, &argc, &argv, &opt_err)) {
+    g_error ("Error parsing command line options: %s", opt_err->message);
+    g_option_context_free (ctx);
+    g_clear_error (&opt_err);
+    return -1;
+  }
+
+  if (filenames == NULL || filenames[0] == NULL || filenames[0][0] == '\0') {
+    g_printerr ("Please specify a path to a video file\n\n");
+    return -1;
+  }
+
+  run_gui (filenames[0]);
+
+  g_free (filenames);
+  g_option_context_free (ctx);
+
+  return 0;
+}
diff --git a/tests/icles/meson.build b/tests/icles/meson.build
new file mode 100644
index 0000000..0769706
--- /dev/null
+++ b/tests/icles/meson.build
@@ -0,0 +1,38 @@
+tests = [
+  ['equalizer-test'],
+  ['test-accurate-seek', gstapp_dep],
+  ['test-segment-seeks'],
+  ['videocrop-test'],
+  ['videobox-test'],
+  ['videocrop2-test'],
+]
+
+gtk_dep = dependency('gtk+-3.0', version : '>= 3.0.0', required : false)
+if gtk_dep.found()
+  tests += [
+    ['gdkpixbufsink-test', gtk_dep],
+    ['gdkpixbufoverlay-test', [gstvideo_dep, gtk_dep]],
+  ]
+endif
+
+if cdata.has('HAVE_GST_V4L2')
+  tests += [['v4l2src-test', gstvideo_dep]]
+endif
+
+if get_variable('have_oss4', false)
+  tests += [['test-oss4']]
+endif
+
+if get_variable('x11_dep', dependency('', required: false)).found()
+  tests += [['ximagesrc-test']]
+endif
+
+foreach t : tests
+  test_name = t.get(0)
+  extra_deps = t.get(1, [])
+  executable(test_name, test_name + '.c',
+    dependencies: [gst_dep, libm, extra_deps],
+    c_args : gst_plugins_good_args,
+    include_directories : [configinc],
+    install: false)
+endforeach
diff --git a/tests/icles/test-accurate-seek.c b/tests/icles/test-accurate-seek.c
new file mode 100644
index 0000000..5489d5c
--- /dev/null
+++ b/tests/icles/test-accurate-seek.c
@@ -0,0 +1,299 @@
+/* GStreamer interactive test for accurate seeking
+ * Copyright (C) 2014 Tim-Philipp Müller <tim centricular com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Based on python script by Kibeom Kim <kkb110@gmail.com>
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/gst.h>
+#include <gst/base/base.h>
+#include <gst/audio/audio.h>
+#include <gst/app/app.h>
+
+#define SAMPLE_FREQ 44100
+
+static const guint8 *
+_memmem (const guint8 * haystack, gsize hlen, const guint8 * needle, gsize nlen)
+{
+  const guint8 *p = haystack;
+  int needle_first;
+  gsize plen = hlen;
+
+  if (!nlen)
+    return NULL;
+
+  needle_first = *(unsigned char *) needle;
+
+  while (plen >= nlen && (p = memchr (p, needle_first, plen - nlen + 1))) {
+    if (!memcmp (p, needle, nlen))
+      return (guint8 *) p;
+
+    p++;
+    plen = hlen - (p - haystack);
+  }
+
+  return NULL;
+}
+
+static GstClockTime
+sample_to_nanotime (guint sample)
+{
+  return (guint64) ((1.0 * sample * GST_SECOND / SAMPLE_FREQ) + 0.5);
+}
+
+static guint
+nanotime_to_sample (GstClockTime nanotime)
+{
+  return gst_util_uint64_scale_round (nanotime, SAMPLE_FREQ, GST_SECOND);
+}
+
+static GstBuffer *
+generate_test_data (guint N)
+{
+  gint16 *left, *right, *stereo;
+  guint largeN, i, j;
+
+  /* 32767 = (2 ** 15) - 1 */
+  /* 32768 = (2 ** 15) */
+  largeN = ((N + 32767) / 32768) * 32768;
+  left = g_new0 (gint16, largeN);
+  right = g_new0 (gint16, largeN);
+  stereo = g_new0 (gint16, 2 * largeN);
+
+  for (i = 0; i < (largeN / 32768); ++i) {
+    gint c = 0;
+
+    for (j = i * 32768; j < ((i + 1) * 32768); ++j) {
+      left[j] = i;
+
+      if (i % 2 == 0) {
+        right[j] = c;
+      } else {
+        right[j] = 32767 - c;
+      }
+      ++c;
+    }
+  }
+
+  /* could just fill stereo directly from the start, but keeping original code for now */
+  for (i = 0; i < largeN; ++i) {
+    stereo[(2 * i) + 0] = left[i];
+    stereo[(2 * i) + 1] = right[i];
+  }
+  g_free (left);
+  g_free (right);
+
+  return gst_buffer_new_wrapped (stereo, 2 * largeN * sizeof (gint16));
+}
+
+static void
+generate_test_sound (const gchar * fn, const gchar * launch_string,
+    guint num_samples)
+{
+  GstElement *pipeline, *src, *parse, *enc_bin, *sink;
+  GstFlowReturn flow;
+  GstMessage *msg;
+  GstBuffer *buf;
+  GstCaps *caps;
+
+  pipeline = gst_pipeline_new (NULL);
+
+  src = gst_element_factory_make ("appsrc", NULL);
+
+  caps = gst_caps_new_simple ("audio/x-raw",
+      "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
+      "rate", G_TYPE_INT, SAMPLE_FREQ, "channels", G_TYPE_INT, 2,
+      "layout", G_TYPE_STRING, "interleaved",
+      "channel-mask", GST_TYPE_BITMASK, (guint64) 3, NULL);
+  g_object_set (src, "caps", caps, "format", GST_FORMAT_TIME, NULL);
+  gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
+  gst_caps_unref (caps);
+
+  /* audioparse to put proper timestamps on buffers for us, without which
+   * vorbisenc in particular is unhappy (or oggmux, rather) */
+  parse = gst_element_factory_make ("audioparse", NULL);
+  if (parse != NULL) {
+    g_object_set (parse, "use-sink-caps", TRUE, NULL);
+  } else {
+    parse = gst_element_factory_make ("identity", NULL);
+    g_warning ("audioparse element not available, vorbis/ogg might not work\n");
+  }
+
+  enc_bin = gst_parse_bin_from_description (launch_string, TRUE, NULL);
+
+  sink = gst_element_factory_make ("filesink", NULL);
+  g_object_set (sink, "location", fn, NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, parse, enc_bin, sink, NULL);
+
+  gst_element_link_many (src, parse, enc_bin, sink, NULL);
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  buf = generate_test_data (num_samples);
+  flow = gst_app_src_push_buffer (GST_APP_SRC (src), buf);
+  g_assert (flow == GST_FLOW_OK);
+
+  gst_app_src_end_of_stream (GST_APP_SRC (src));
+
+  /*g_print ("generating test sound %s, waiting for EOS..\n", fn); */
+
+  msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipeline),
+      GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS | GST_MESSAGE_ERROR);
+
+  g_assert (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
+  gst_message_unref (msg);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+
+  /* g_print ("Done %s\n", fn); */
+}
+
+static void
+test_seek_FORMAT_TIME_by_sample (const gchar * fn, GList * seek_positions)
+{
+  GstElement *pipeline, *src, *sink;
+  GstAdapter *adapter;
+  GstSample *sample;
+  GstCaps *caps;
+  gconstpointer answer;
+  guint answer_size;
+
+  pipeline = gst_parse_launch ("filesrc name=src ! decodebin ! "
+      "audioconvert dithering=0 ! appsink name=sink", NULL);
+
+  src = gst_bin_get_by_name (GST_BIN (pipeline), "src");
+  g_object_set (src, "location", fn, NULL);
+  gst_object_unref (src);
+
+  sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
+  caps = gst_caps_new_simple ("audio/x-raw",
+      "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
+      "rate", G_TYPE_INT, SAMPLE_FREQ, "channels", G_TYPE_INT, 2, NULL);
+  g_object_set (sink, "caps", caps, "sync", FALSE, NULL);
+  gst_caps_unref (caps);
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  /* wait for preroll, so we can seek */
+  gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipeline), GST_CLOCK_TIME_NONE,
+      GST_MESSAGE_ASYNC_DONE);
+
+  /* first, read entire file to end */
+  adapter = gst_adapter_new ();
+  while ((sample = gst_app_sink_pull_sample (GST_APP_SINK (sink)))) {
+    gst_adapter_push (adapter, gst_buffer_ref (gst_sample_get_buffer (sample)));
+    gst_sample_unref (sample);
+  }
+  answer_size = gst_adapter_available (adapter);
+  answer = gst_adapter_map (adapter, answer_size);
+  /* g_print ("%s: read %u bytes\n", fn, answer_size); */
+
+  g_print ("%10s\t%10s\t%10s\n", "requested", "sample per ts", "actual(data)");
+
+  while (seek_positions != NULL) {
+    gconstpointer found;
+    GstMapInfo map;
+    GstBuffer *buf;
+    gboolean ret;
+    guint actual_position, buffer_timestamp_position;
+    guint seek_sample;
+
+    seek_sample = GPOINTER_TO_UINT (seek_positions->data);
+
+    ret = gst_element_seek_simple (pipeline, GST_FORMAT_TIME,
+        GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
+        sample_to_nanotime (seek_sample));
+
+    g_assert (ret);
+
+    sample = gst_app_sink_pull_sample (GST_APP_SINK (sink));
+
+    buf = gst_sample_get_buffer (sample);
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    GST_MEMDUMP ("answer", answer, answer_size);
+    GST_MEMDUMP ("buffer", map.data, map.size);
+    found = _memmem (answer, answer_size, map.data, map.size);
+    gst_buffer_unmap (buf, &map);
+
+    g_assert (found != NULL);
+    actual_position = ((goffset) ((guint8 *) found - (guint8 *) answer)) / 4;
+    buffer_timestamp_position = nanotime_to_sample (GST_BUFFER_PTS (buf));
+    g_print ("%10u\t%10u\t%10u\n", seek_sample, buffer_timestamp_position,
+        actual_position);
+    gst_sample_unref (sample);
+
+    seek_positions = seek_positions->next;
+  }
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (sink);
+  gst_object_unref (pipeline);
+  g_object_unref (adapter);
+}
+
+static GList *
+create_test_samples (guint from, guint to, guint step)
+{
+  GQueue q = G_QUEUE_INIT;
+  guint i;
+
+  for (i = from; i < to; i += step)
+    g_queue_push_tail (&q, GUINT_TO_POINTER (i));
+
+  return q.head;
+}
+
+#define SECS 10
+
+int
+main (int argc, char **argv)
+{
+  GList *test_samples;
+
+  gst_init (&argc, &argv);
+
+  test_samples = create_test_samples (SAMPLE_FREQ, SAMPLE_FREQ * 2, 5000);
+
+  g_print ("\nwav:\n");
+  generate_test_sound ("test.wav", "wavenc", SAMPLE_FREQ * SECS);
+  test_seek_FORMAT_TIME_by_sample ("test.wav", test_samples);
+
+  g_print ("\nflac:\n");
+  generate_test_sound ("test.flac", "flacenc", SAMPLE_FREQ * SECS);
+  test_seek_FORMAT_TIME_by_sample ("test.flac", test_samples);
+
+  g_print ("\nogg:\n");
+  generate_test_sound ("test.ogg",
+      "audioconvert dithering=0 ! vorbisenc quality=1 ! oggmux",
+      SAMPLE_FREQ * SECS);
+  test_seek_FORMAT_TIME_by_sample ("test.ogg", test_samples);
+
+  g_print ("\nmp3:\n");
+  generate_test_sound ("test.mp3", "lamemp3enc bitrate=320",
+      SAMPLE_FREQ * SECS);
+  test_seek_FORMAT_TIME_by_sample ("test.mp3", test_samples);
+
+  g_list_free (test_samples);
+  return 0;
+}
diff --git a/tests/icles/test-oss4.c b/tests/icles/test-oss4.c
new file mode 100644
index 0000000..adbe442
--- /dev/null
+++ b/tests/icles/test-oss4.c
@@ -0,0 +1,128 @@
+/* GStreamer OSS4 audio tests
+ * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/gst.h>
+
+static gboolean opt_show_mixer_messages = FALSE;
+
+#define WAIT_TIME  60.0         /* in seconds */
+
+static void
+probe_pad (GstElement * element, const gchar * pad_name)
+{
+  GstCaps *caps = NULL;
+  GstPad *pad;
+  guint i;
+
+  pad = gst_element_get_static_pad (element, pad_name);
+  if (pad == NULL)
+    return;
+
+  caps = gst_pad_query_caps (pad, NULL);
+  g_return_if_fail (caps != NULL);
+
+  for (i = 0; i < gst_caps_get_size (caps); ++i) {
+    gchar *s;
+
+    s = gst_structure_to_string (gst_caps_get_structure (caps, i));
+    g_print ("  %4s[%d]: %s\n", GST_PAD_NAME (pad), i, s);
+    g_free (s);
+  }
+  gst_caps_unref (caps);
+  gst_object_unref (pad);
+}
+
+static void
+probe_details (GstElement * element)
+{
+  GstStateChangeReturn ret;
+
+  ret = gst_element_set_state (element, GST_STATE_READY);
+  if (ret == GST_STATE_CHANGE_FAILURE) {
+    g_print ("Could not set element %s to READY.", GST_ELEMENT_NAME (element));
+    return;
+  }
+
+  probe_pad (element, "sink");
+  probe_pad (element, "src");
+
+  gst_element_set_state (element, GST_STATE_NULL);
+}
+
+static void
+probe_element (const gchar * name)
+{
+  GstElement *element;
+  gchar *devname = NULL;
+
+  element = gst_element_factory_make (name, name);
+
+  /* make sure we don't deadlock on GST_ELEMENT_ERROR or do other silly things
+   * if we try to query the "device-name" property when the device isn't open */
+  g_object_set (element, "device", "/dev/does/not/exist", NULL);
+  g_object_get (element, "device-name", &devname, NULL);
+  GST_LOG ("devname: '%s'", GST_STR_NULL (devname));
+  g_assert (devname == NULL || *devname == '\0');
+
+  /* and now for real */
+
+  probe_details (element);
+
+  gst_object_unref (element);
+}
+
+int
+main (int argc, char **argv)
+{
+  GOptionEntry options[] = {
+    {"show-mixer-messages", 'm', 0, G_OPTION_ARG_NONE, &opt_show_mixer_messages,
+        "For mixer elements, wait 60 seconds and show any mixer messages "
+          "(for debugging auto-notifications)", NULL},
+    {NULL,}
+  };
+  GOptionContext *ctx;
+  GError *err = NULL;
+
+  ctx = g_option_context_new ("");
+  g_option_context_add_main_entries (ctx, options, NULL);
+  g_option_context_add_group (ctx, gst_init_get_option_group ());
+  if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
+    g_print ("Error initializing: %s\n", err->message);
+    g_option_context_free (ctx);
+    g_clear_error (&err);
+    exit (1);
+  }
+  g_option_context_free (ctx);
+
+  probe_element ("oss4sink");
+  probe_element ("oss4src");
+
+  return 0;
+}
diff --git a/tests/icles/test-segment-seeks.c b/tests/icles/test-segment-seeks.c
new file mode 100644
index 0000000..4c9b670
--- /dev/null
+++ b/tests/icles/test-segment-seeks.c
@@ -0,0 +1,146 @@
+/* GStreamer interactive test for accurate segment seeking
+ * Copyright (C) 2014 Tim-Philipp Müller <tim centricular com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+/* Plays the provided file one second at a time using segment seeks.
+ * Theoretically this should be just as smooth as if we played the
+ * file from start to stop in one go, certainly without hickups.
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#define SEGMENT_DURATION (1 * GST_SECOND)
+
+int
+main (int argc, char **argv)
+{
+  GstElement *playbin;
+  GstMessage *msg;
+  gchar *uri;
+  gint64 dur, start, stop;
+  gboolean prerolled = FALSE;
+
+  if (argc < 2) {
+    g_printerr ("Usage: %s FILENAME\n", argv[0]);
+    return -1;
+  }
+
+  gst_init (&argc, &argv);
+
+  if (gst_uri_is_valid (argv[1]))
+    uri = g_strdup (argv[1]);
+  else
+    uri = gst_filename_to_uri (argv[1], NULL);
+
+  g_print ("uri: %s\n", uri);
+
+  playbin = gst_element_factory_make ("playbin", NULL);
+  g_object_set (playbin, "uri", uri, NULL);
+
+#if 0
+  {
+    GstElement *src;
+
+    playbin = gst_parse_launch ("uridecodebin name=d ! queue ! "
+        "filesink location=/tmp/raw1.data", NULL);
+    src = gst_bin_get_by_name (GST_BIN (playbin), "d");
+    g_object_set (src, "uri", uri, NULL);
+    gst_object_unref (src);
+  }
+#endif
+
+  gst_element_set_state (playbin, GST_STATE_PAUSED);
+
+  /* wait for preroll */
+  msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (playbin),
+      GST_CLOCK_TIME_NONE, GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR);
+
+  g_assert (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ERROR);
+  prerolled = TRUE;
+
+  gst_message_unref (msg);
+
+  if (!gst_element_query_duration (playbin, GST_FORMAT_TIME, &dur))
+    g_error ("Failed to query duration!\n");
+
+  g_print ("Duration: %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (dur));
+
+  start = 0;
+  do {
+    GstSeekFlags seek_flags;
+    gboolean ret;
+    gboolean segment_done = FALSE;
+
+    seek_flags = GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT;
+
+    if (start == 0) {
+      prerolled = FALSE;
+      seek_flags |= GST_SEEK_FLAG_FLUSH;
+    }
+
+    stop = start + SEGMENT_DURATION;
+
+    g_print ("Segment: %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT "\n",
+        GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
+
+    ret = gst_element_seek (playbin, 1.0, GST_FORMAT_TIME, seek_flags,
+        GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_SET, stop);
+
+    g_assert (ret);
+
+    if (!prerolled) {
+      while (!prerolled) {
+        /* wait for preroll again */
+        msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (playbin),
+            GST_CLOCK_TIME_NONE, GST_MESSAGE_SEGMENT_DONE |
+            GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR);
+
+        g_assert (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ERROR);
+        if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_SEGMENT_DONE) {
+          segment_done = TRUE;
+        } else {
+          prerolled = TRUE;
+        }
+        gst_message_unref (msg);
+      }
+
+      gst_element_set_state (playbin, GST_STATE_PLAYING);
+    }
+
+    /* wait for end of segment if we didn't get it above already */
+    if (!segment_done) {
+      msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (playbin),
+          GST_CLOCK_TIME_NONE, GST_MESSAGE_SEGMENT_DONE | GST_MESSAGE_ERROR);
+
+      g_assert (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ERROR);
+
+      gst_message_unref (msg);
+    }
+
+    start = stop;
+  }
+  while (start < dur);
+
+  gst_element_set_state (playbin, GST_STATE_NULL);
+  gst_object_unref (playbin);
+  return 0;
+}
diff --git a/tests/icles/v4l2src-test.c b/tests/icles/v4l2src-test.c
new file mode 100644
index 0000000..2162e5c
--- /dev/null
+++ b/tests/icles/v4l2src-test.c
@@ -0,0 +1,514 @@
+/* GStreamer
+ *
+ * Copyright (C) 2006 Edgard Lima <edgard dot lima at indt dot org dot br>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <gst/gst.h>
+#include <gst/video/colorbalance.h>
+#include <gst/video/videoorientation.h>
+
+GstElement *pipeline, *source, *sink;
+GMainLoop *loop;
+volatile int exit_read = 0;
+
+static void
+print_options (void)
+{
+  printf ("\nf - to change the fequency\n");
+  printf ("i - to change the input\n");
+  printf ("n - to change the norm\n");
+  printf ("c - list color balance\n");
+  printf ("v - change video orientarion\n");
+  printf ("e - to exit\n");
+}
+
+static void
+run_options (char opt)
+{
+  int res;
+
+  switch (opt) {
+#if 0
+    case 'f':
+    {
+      GstTuner *tuner = GST_TUNER (source);
+      GstTunerChannel *channel;
+      guint freq;
+
+      channel = gst_tuner_get_channel (tuner);
+
+      freq = gst_tuner_get_frequency (tuner, channel);
+
+      printf ("\ntype the new frequency (current = %u) (-1 to cancel): ", freq);
+      res = scanf ("%u", &freq);
+      if (res != 1 || freq != -1)
+        gst_tuner_set_frequency (tuner, channel, freq);
+    }
+      break;
+    case 'n':
+    {
+      GstTuner *tuner = GST_TUNER (source);
+      const GList *item, *list;
+      const GstTunerNorm *current_norm;
+      GstTunerNorm *norm = NULL;
+      gint index, next_norm;
+
+
+      list = gst_tuner_list_norms (tuner);
+
+      current_norm = gst_tuner_get_norm (tuner);
+
+      printf ("\nlist of norms:\n");
+      for (item = list, index = 0; item != NULL; item = item->next, ++index) {
+        norm = item->data;
+        if (current_norm == norm) {
+          printf (" * %u - %s\n", index, norm->label);
+        } else {
+          printf ("   %u - %s\n", index, norm->label);
+        }
+      }
+      printf ("\ntype the number of norm you want (-1 to cancel): ");
+      res = scanf ("%d", &next_norm);
+      if (res != 1 || next_norm < 0) {
+        break;
+      }
+      if (index <= next_norm) {
+        printf ("Norm %d not available\n", next_norm);
+        break;
+      }
+      for (item = list, index = 0; item != NULL && index <= next_norm;
+          item = item->next, ++index) {
+        norm = item->data;
+      }
+      if (norm)
+        gst_tuner_set_norm (tuner, norm);
+    }
+      break;
+    case 'i':
+    {
+      GstTuner *tuner = GST_TUNER (source);
+      const GList *item, *list;
+      const GstTunerChannel *current_channel;
+      GstTunerChannel *channel = NULL;
+      gint index, next_channel;
+
+
+      list = gst_tuner_list_channels (tuner);
+
+      current_channel = gst_tuner_get_channel (tuner);
+
+      printf ("\nlist of inputs:\n");
+      for (item = list, index = 0; item != NULL; item = item->next, ++index) {
+        channel = item->data;
+        if (current_channel == channel) {
+          printf (" * %u - %s\n", index, channel->label);
+        } else {
+          printf ("   %u - %s\n", index, channel->label);
+        }
+      }
+      printf ("\ntype the number of input you want (-1 to cancel): ");
+      res = scanf ("%d", &next_channel);
+      if (res != 1 || next_channel < 0) {
+        break;
+      }
+      if (index <= next_channel) {
+        printf ("Input %d not available\n", next_channel);
+        break;
+      }
+      for (item = list, index = 0; item != NULL && index <= next_channel;
+          item = item->next, ++index) {
+        channel = item->data;
+      }
+      if (channel)
+        gst_tuner_set_channel (tuner, channel);
+    }
+      break;
+#endif
+    case 'e':
+      gst_element_set_state (pipeline, GST_STATE_NULL);
+      g_main_loop_quit (loop);
+      printf ("Bye\n");
+      g_thread_exit (0);
+      break;
+    case 'c':
+    {
+      GstColorBalance *balance = GST_COLOR_BALANCE (source);
+      const GList *controls;
+      GstColorBalanceChannel *channel;
+      const GList *item;
+      gint index, new_value;
+
+      controls = gst_color_balance_list_channels (balance);
+
+      printf ("\n");
+
+      if (controls == NULL) {
+        printf ("There is no list of colorbalance controls\n");
+        goto done;
+      }
+
+      if (controls) {
+        printf ("list of controls:\n");
+        for (item = controls, index = 0; item != NULL;
+            item = item->next, ++index) {
+          channel = item->data;
+          printf ("   %u - %s (%d - %d) = %d\n", index, channel->label,
+              channel->min_value, channel->max_value,
+              gst_color_balance_get_value (balance, channel));
+        }
+        printf ("\ntype the number of color control you want (-1 to cancel): ");
+        res = scanf ("%d", &new_value);
+        if (res != 1 || new_value == -1)
+          break;
+        for (item = controls, index = 0; item != NULL && index <= new_value;
+            item = item->next, ++index) {
+          channel = item->data;
+        }
+        printf ("   %u - %s (%d - %d) = %d, type the new value: ", index - 1,
+            channel->label, channel->min_value, channel->max_value,
+            gst_color_balance_get_value (balance, channel));
+        res = scanf ("%d", &new_value);
+        if (res != 1 || new_value == -1)
+          break;
+        gst_color_balance_set_value (balance, channel, new_value);
+      }
+    }
+    case 'v':
+    {
+      GstVideoOrientation *vidorient = GST_VIDEO_ORIENTATION (source);
+      gboolean flip = FALSE;
+      gint center = 0;
+
+      printf ("\n");
+
+      if (gst_video_orientation_get_hflip (vidorient, &flip)) {
+        gint new_value;
+
+        printf ("Horizontal flip is %s\n", flip ? "on" : "off");
+        printf ("\ntype 1 to toggle (-1 to cancel): ");
+        res = scanf ("%d", &new_value);
+        if (res != 1 || new_value == 1) {
+          flip = !flip;
+          if (gst_video_orientation_set_hflip (vidorient, flip)) {
+            gst_video_orientation_get_hflip (vidorient, &flip);
+            printf ("Now horizontal flip is %s\n", flip ? "on" : "off");
+          } else {
+            printf ("Error toggling horizontal flip\n");
+          }
+        } else {
+        }
+      } else {
+        printf ("Horizontal flip control not available\n");
+      }
+
+      if (gst_video_orientation_get_vflip (vidorient, &flip)) {
+        gint new_value;
+
+        printf ("\nVertical flip is %s\n", flip ? "on" : "off");
+        printf ("\ntype 1 to toggle (-1 to cancel): ");
+        res = scanf ("%d", &new_value);
+        if (res != 1 || new_value == 1) {
+          flip = !flip;
+          if (gst_video_orientation_set_vflip (vidorient, flip)) {
+            gst_video_orientation_get_vflip (vidorient, &flip);
+            printf ("Now vertical flip is %s\n", flip ? "on" : "off");
+          } else {
+            printf ("Error toggling vertical flip\n");
+          }
+        } else {
+        }
+      } else {
+        printf ("Vertical flip control not available\n");
+      }
+
+      if (gst_video_orientation_get_hcenter (vidorient, &center)) {
+        printf ("Horizontal center is %d\n", center);
+        printf ("\ntype the new horizontal center value (-1 to cancel): ");
+        res = scanf ("%d", &center);
+        if (res != 1 || center != -1) {
+          if (gst_video_orientation_set_hcenter (vidorient, center)) {
+            gst_video_orientation_get_hcenter (vidorient, &center);
+            printf ("Now horizontal center is %d\n", center);
+          } else {
+            printf ("Error setting horizontal center\n");
+          }
+        } else {
+        }
+      } else {
+        printf ("Horizontal center control not available\n");
+      }
+
+      if (gst_video_orientation_get_vcenter (vidorient, &center)) {
+        printf ("Vertical center is %d\n", center);
+        printf ("\ntype the new vertical center value (-1 to cancel): ");
+        res = scanf ("%d", &center);
+        if (res != 1 || center != -1) {
+          if (gst_video_orientation_set_vcenter (vidorient, center)) {
+            gst_video_orientation_get_vcenter (vidorient, &center);
+            printf ("Now vertical center is %d\n", center);
+          } else {
+            printf ("Error setting vertical center\n");
+          }
+        } else {
+        }
+      } else {
+        printf ("Vertical center control not available\n");
+      }
+
+    }
+      break;
+      break;
+    default:
+      if (opt != 10)
+        printf ("error: invalid option %c", opt);
+      break;
+  }
+
+done:
+
+  return;
+
+}
+
+static gpointer
+read_user (gpointer data)
+{
+
+  char opt;
+
+  while (!exit_read) {
+
+    print_options ();
+
+    do {
+      opt = getchar ();
+      if (exit_read) {
+        break;
+      }
+    } while (opt == '\n');
+
+    run_options (opt);
+
+  }
+
+  return NULL;
+
+}
+
+static gboolean
+my_bus_callback (GstBus * bus, GstMessage * message, gpointer data)
+{
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_ERROR:{
+      GError *err;
+      gchar *debug;
+      gchar *str;
+
+      gst_message_parse_error (message, &err, &debug);
+      str = gst_element_get_name (message->src);
+      g_print ("%s error: %s\n", str, err->message);
+      g_free (str);
+      g_print ("Debug: %s\n", debug);
+
+      g_error_free (err);
+      g_free (debug);
+
+      printf ("presse <ENTER> key to exit\n");
+      exit_read = 1;
+      g_main_loop_quit (loop);
+      break;
+    case GST_MESSAGE_EOS:
+      /* end-of-stream */
+      printf ("presse any key to exit\n");
+      exit_read = 1;
+      g_main_loop_quit (loop);
+      break;
+    default:
+      break;
+    }
+  }
+  return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+
+  GThread *input_thread;
+  gint numbuffers = -1;
+  gchar device[128] = { '\0' };
+  gchar input[128] = { '\0' };
+  gulong frequency = 0;
+  GstBus *bus;
+
+  /* see for input option */
+
+  int c;
+
+  while (1) {
+    static char long_options_desc[][64] = {
+      {"Number of buffers to output before sending EOS"},
+      {"Device location. Common in /dev/video0"},
+      {"input/output (channel) to switch to"},
+      {"frequency to tune to (in Hz)"},
+      {0, 0, 0, 0}
+    };
+    static struct option long_options[] = {
+      {"numbuffers", 1, 0, 'n'},
+      {"device", 1, 0, 'd'},
+      {"input", 1, 0, 'i'},
+      {"frequency", 1, 0, 'f'},
+      {0, 0, 0, 0}
+    };
+    /* getopt_long stores the option index here. */
+    int option_index = 0;
+
+    c = getopt_long (argc, argv, "n:d:i:f:h", long_options, &option_index);
+
+    /* Detect the end of the options. */
+    if (c == -1) {
+      printf ("tip: use -h to see help message.\n");
+      break;
+    }
+
+    switch (c) {
+      case 0:
+        /* If this option set a flag, do nothing else now. */
+        if (long_options[option_index].flag != 0)
+          break;
+        printf ("option %s", long_options[option_index].name);
+        if (optarg)
+          printf (" with arg %s", optarg);
+        printf ("\n");
+        break;
+
+      case 'n':
+        numbuffers = atoi (optarg);
+        break;
+
+      case 'd':
+        strncpy (device, optarg, sizeof (device) / sizeof (device[0]));
+        break;
+
+      case 'i':
+        strncpy (input, optarg, sizeof (input) / sizeof (input[0]));
+        break;
+
+      case 'f':
+        frequency = atol (optarg);
+        break;
+
+      case 'h':
+        printf ("Usage: v4l2src-test [OPTION]...\n");
+        for (c = 0; long_options[c].name; ++c) {
+          printf ("-%c, --%s\r\t\t\t\t%s\n", long_options[c].val,
+              long_options[c].name, long_options_desc[c]);
+        }
+        exit (0);
+        break;
+
+      case '?':
+        /* getopt_long already printed an error message. */
+        printf ("Use -h to see help message.\n");
+        break;
+
+      default:
+        abort ();
+    }
+  }
+
+  /* Print any remaining command line arguments (not options). */
+  if (optind < argc) {
+    printf ("Use -h to see help message.\n" "non-option ARGV-elements: ");
+    while (optind < argc)
+      printf ("%s ", argv[optind++]);
+    putchar ('\n');
+  }
+
+  /* init */
+  gst_init (&argc, &argv);
+
+  /* create elements */
+  if (!(pipeline = gst_pipeline_new ("my_pipeline"))) {
+    fprintf (stderr, "error: gst_pipeline_new return NULL");
+    return -1;
+  }
+
+  if (!(source = gst_element_factory_make ("v4l2src", NULL))) {
+    fprintf (stderr,
+        "error: gst_element_factory_make (\"v4l2src\", NULL) return NULL");
+    return -1;
+  }
+
+  if (!(sink = gst_element_factory_make ("xvimagesink", NULL))) {
+    fprintf (stderr,
+        "error: gst_element_factory_make (\"xvimagesink\", NULL) return NULL");
+    return -1;
+  }
+
+  if (numbuffers > -1) {
+    g_object_set (source, "num-buffers", numbuffers, NULL);
+  }
+  if (device[0]) {
+    g_object_set (source, "device", device, NULL);
+  }
+  if (input[0]) {
+    g_object_set (source, "input", input, NULL);
+  }
+  if (frequency) {
+    g_object_set (source, "frequency", frequency, NULL);
+  }
+
+  /* you would normally check that the elements were created properly */
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+  gst_bus_add_watch (bus, my_bus_callback, NULL);
+
+  /* put together a pipeline */
+  gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
+  gst_element_link_pads (source, "src", sink, "sink");
+
+  /* start the pipeline */
+  gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
+  loop = g_main_loop_new (NULL, FALSE);
+
+  input_thread = g_thread_try_new ("v4l2src-test", read_user, source, NULL);
+
+  if (input_thread == NULL) {
+    fprintf (stderr, "error: g_thread_try_new() failed");
+    return -1;
+  }
+
+  g_main_loop_run (loop);
+  g_thread_join (input_thread);
+
+  gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
+
+  gst_object_unref (bus);
+  gst_object_unref (pipeline);
+
+  gst_deinit ();
+
+  return 0;
+
+}
diff --git a/tests/icles/videobox-test.c b/tests/icles/videobox-test.c
new file mode 100644
index 0000000..0c85a35
--- /dev/null
+++ b/tests/icles/videobox-test.c
@@ -0,0 +1,141 @@
+/* GStreamer interactive videobox test
+ *
+ * Copyright (C) 2008 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include <gst/gst.h>
+
+static GstElement *
+make_pipeline (gint type)
+{
+  GstElement *result;
+  gchar *pstr;
+
+  switch (type) {
+    case 0:
+      pstr = g_strdup_printf ("videotestsrc ! videobox name=box ! "
+          "xvimagesink");
+      break;
+    default:
+      return NULL;
+  }
+
+  result = gst_parse_launch_full (pstr, NULL, GST_PARSE_FLAG_NONE, NULL);
+  g_print ("created test %d: \"%s\"\n", type, pstr);
+  g_free (pstr);
+
+  return result;
+}
+
+#define MAX_ROUND 500
+
+int
+main (int argc, char **argv)
+{
+  GstElement *pipe, *box;
+  gint left, right;
+  gint top, bottom;
+  gint ldir, rdir;
+  gint tdir, bdir;
+  gint round, type, stop;
+
+  gst_init (&argc, &argv);
+
+  type = 0;
+  stop = -1;
+
+  if (argc > 1) {
+    type = atoi (argv[1]);
+    stop = type + 1;
+  }
+
+  while (TRUE) {
+    GstMessage *message;
+
+    pipe = make_pipeline (type);
+    if (pipe == NULL)
+      break;
+
+    box = gst_bin_get_by_name (GST_BIN (pipe), "box");
+    g_assert (box);
+
+    top = bottom = left = right = 0;
+    tdir = bdir = -10;
+    ldir = rdir = 10;
+
+    for (round = 0; round < MAX_ROUND; round++) {
+      g_print ("box to %4d %4d %4d %4d (%d/%d)   \r", top, bottom, left, right,
+          round, MAX_ROUND);
+
+      g_object_set (box, "top", top, "bottom", bottom, "left", left, "right",
+          right, NULL);
+
+      if (round == 0)
+        gst_element_set_state (pipe, GST_STATE_PLAYING);
+
+      top += tdir;
+      if (top >= 50)
+        tdir = -10;
+      else if (top < -50)
+        tdir = 10;
+
+      bottom += bdir;
+      if (bottom >= 40)
+        bdir = -10;
+      else if (bottom < -60)
+        bdir = 10;
+
+      left += ldir;
+      if (left >= 60)
+        ldir = -10;
+      else if (left < -80)
+        ldir = 10;
+
+      right += rdir;
+      if (right >= 80)
+        rdir = -10;
+      else if (right < -90)
+        rdir = 10;
+
+      message =
+          gst_bus_poll (GST_ELEMENT_BUS (pipe), GST_MESSAGE_ERROR,
+          50 * GST_MSECOND);
+      if (message) {
+        g_print ("got error           \n");
+
+        gst_message_unref (message);
+      }
+    }
+    g_print ("test %d done                    \n", type);
+
+    gst_object_unref (box);
+    gst_element_set_state (pipe, GST_STATE_NULL);
+    gst_object_unref (pipe);
+
+    type++;
+    if (type == stop)
+      break;
+  }
+  return 0;
+}
diff --git a/tests/icles/videocrop-test.c b/tests/icles/videocrop-test.c
new file mode 100644
index 0000000..2acfa33
--- /dev/null
+++ b/tests/icles/videocrop-test.c
@@ -0,0 +1,356 @@
+/* GStreamer interactive test for the videocrop element
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include <stdlib.h>
+#include <math.h>
+
+GST_DEBUG_CATEGORY_STATIC (videocrop_test_debug);
+#define GST_CAT_DEFAULT videocrop_test_debug
+
+#define OUT_WIDTH      640
+#define OUT_HEIGHT     480
+#define TIME_PER_TEST   10      /* seconds each format is tested */
+#define FRAMERATE       15      /* frames per second             */
+
+#ifndef DEFAULT_VIDEOSINK
+#define DEFAULT_VIDEOSINK "xvimagesink"
+#endif
+
+static gboolean
+check_bus_for_errors (GstBus * bus, GstClockTime max_wait_time)
+{
+  GstMessage *msg;
+
+  msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, max_wait_time);
+
+  if (msg) {
+    GError *err = NULL;
+    gchar *debug = NULL;
+
+    g_assert (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR);
+    gst_message_parse_error (msg, &err, &debug);
+    GST_ERROR ("ERROR: %s [%s]", err->message, debug);
+    g_print ("\n===========> ERROR: %s\n%s\n\n", err->message, debug);
+    g_clear_error (&err);
+    g_free (debug);
+    gst_message_unref (msg);
+  }
+
+  return (msg != NULL);
+}
+
+static void
+test_with_caps (GstElement * src, GstElement * videocrop, GstCaps * caps)
+{
+  GstClockTime time_run;
+  GstElement *pipeline;
+  GTimer *timer;
+  GstBus *bus;
+  GstPad *pad;
+  guint hcrop;
+  guint vcrop;
+
+  /* caps must be writable, we can't check that here though */
+  g_assert (GST_CAPS_REFCOUNT_VALUE (caps) == 1);
+
+  timer = g_timer_new ();
+  vcrop = 0;
+  hcrop = 0;
+
+  pipeline = GST_ELEMENT (gst_element_get_parent (videocrop));
+  g_assert (GST_IS_PIPELINE (pipeline));
+
+  /* at this point the pipeline is in PLAYING state; we only want to capture
+   * errors resulting from our on-the-fly changing of the filtercaps */
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+
+  /* pad to block */
+  pad = gst_element_get_static_pad (src, "src");
+
+  time_run = 0;
+  do {
+    GstClockTime wait_time, waited_for_block;
+
+    if (check_bus_for_errors (bus, 0))
+      break;
+
+    wait_time = GST_SECOND / FRAMERATE;
+
+    GST_LOG ("hcrop = %3d, vcrop = %3d", vcrop, hcrop);
+
+    g_timer_reset (timer);
+
+    /* need to block the streaming thread while changing these properties,
+     * otherwise we might get random not-negotiated errors (when caps are
+     * changed in between upstream calling pad_alloc_buffer() and pushing
+     * the processed buffer?)  FIXME should not be needed */
+    /* gst_pad_set_blocked (pad, TRUE); */
+    g_object_set (videocrop, "left", hcrop, "top", vcrop, NULL);
+    /* gst_pad_set_blocked (pad, FALSE); */
+
+    waited_for_block = g_timer_elapsed (timer, NULL) * (double) GST_SECOND;
+    /* GST_LOG ("waited: %" GST_TIME_FORMAT ", frame len: %" GST_TIME_FORMAT,
+       GST_TIME_ARGS (waited_for_block), GST_TIME_ARGS (wait_time)); */
+    ++vcrop;
+    ++hcrop;
+
+    if (wait_time > waited_for_block) {
+      g_usleep ((wait_time - waited_for_block) / GST_MSECOND);
+    }
+
+    time_run += wait_time;
+  }
+  while (time_run < (TIME_PER_TEST * GST_SECOND));
+
+  g_timer_destroy (timer);
+  gst_object_unref (bus);
+  gst_object_unref (pad);
+  gst_object_unref (pipeline);
+}
+
+/* return a list of caps where we only need to set
+ * width and height to get fixed caps */
+static GList *
+video_crop_get_test_caps (GstElement * videocrop)
+{
+  const GstCaps *allowed_caps;
+  GstPad *srcpad;
+  GList *list = NULL;
+  guint i;
+
+  srcpad = gst_element_get_static_pad (videocrop, "src");
+  g_assert (srcpad != NULL);
+  allowed_caps = gst_pad_get_pad_template_caps (srcpad);
+  g_assert (allowed_caps != NULL);
+
+  for (i = 0; i < gst_caps_get_size (allowed_caps); ++i) {
+    GstStructure *new_structure;
+    GstCaps *single_caps;
+
+    single_caps = gst_caps_new_empty ();
+    new_structure =
+        gst_structure_copy (gst_caps_get_structure (allowed_caps, i));
+    gst_structure_set (new_structure, "framerate", GST_TYPE_FRACTION,
+        FRAMERATE, 1, NULL);
+    gst_structure_remove_field (new_structure, "width");
+    gst_structure_remove_field (new_structure, "height");
+    gst_caps_append_structure (single_caps, new_structure);
+
+    /* should be fixed without width/height */
+    g_assert (gst_caps_is_fixed (single_caps));
+
+    list = g_list_prepend (list, single_caps);
+  }
+
+  gst_object_unref (srcpad);
+
+  return list;
+}
+
+static gchar *opt_videosink_str;        /* NULL */
+static gchar *opt_filtercaps_str;       /* NULL */
+static gboolean opt_with_videoconvert;  /* FALSE */
+
+int
+main (int argc, char **argv)
+{
+  static const GOptionEntry test_goptions[] = {
+    {"videosink", '\0', 0, G_OPTION_ARG_STRING, &opt_videosink_str,
+        "videosink to use (default: " DEFAULT_VIDEOSINK ")", NULL},
+    {"caps", '\0', 0, G_OPTION_ARG_STRING, &opt_filtercaps_str,
+        "filter caps to narrow down formats to test", NULL},
+    {"with-videoconvert", '\0', 0, G_OPTION_ARG_NONE,
+          &opt_with_videoconvert,
+          "whether to add an videoconvert element in front of the sink",
+        NULL},
+    {NULL, '\0', 0, 0, NULL, NULL, NULL}
+  };
+  GOptionContext *ctx;
+  GError *opt_err = NULL;
+
+  GstElement *pipeline, *src, *filter1, *crop, *scale, *filter2, *csp, *sink;
+  GstCaps *filter_caps = NULL;
+  GList *caps_list, *l;
+
+  /* command line option parsing */
+  ctx = g_option_context_new ("");
+  g_option_context_add_group (ctx, gst_init_get_option_group ());
+  g_option_context_add_main_entries (ctx, test_goptions, NULL);
+
+  if (!g_option_context_parse (ctx, &argc, &argv, &opt_err)) {
+    g_error ("Error parsing command line options: %s", opt_err->message);
+    g_option_context_free (ctx);
+    g_clear_error (&opt_err);
+    return -1;
+  }
+  g_option_context_free (ctx);
+
+  GST_DEBUG_CATEGORY_INIT (videocrop_test_debug, "videocroptest", 0, "vctest");
+
+  pipeline = gst_pipeline_new ("pipeline");
+  src = gst_element_factory_make ("videotestsrc", "videotestsrc");
+  g_assert (src != NULL);
+  filter1 = gst_element_factory_make ("capsfilter", "capsfilter1");
+  g_assert (filter1 != NULL);
+  crop = gst_element_factory_make ("videocrop", "videocrop");
+  g_assert (crop != NULL);
+  scale = gst_element_factory_make ("videoscale", "videoscale");
+  g_assert (scale != NULL);
+  filter2 = gst_element_factory_make ("capsfilter", "capsfilter2");
+  g_assert (filter2 != NULL);
+
+  if (opt_with_videoconvert) {
+    g_print ("Adding videoconvert\n");
+    csp = gst_element_factory_make ("videoconvert", "colorspace");
+  } else {
+    csp = gst_element_factory_make ("identity", "colorspace");
+  }
+  g_assert (csp != NULL);
+
+  if (opt_filtercaps_str) {
+    filter_caps = gst_caps_from_string (opt_filtercaps_str);
+    if (filter_caps == NULL) {
+      g_error ("Invalid filter caps string '%s'", opt_filtercaps_str);
+    } else {
+      g_print ("Using filter caps '%s'\n", opt_filtercaps_str);
+    }
+  }
+
+  if (opt_videosink_str) {
+    g_print ("Trying videosink '%s' ...", opt_videosink_str);
+    sink = gst_element_factory_make (opt_videosink_str, "sink");
+    g_print ("%s\n", (sink) ? "ok" : "element couldn't be created");
+  } else {
+    sink = NULL;
+  }
+
+  if (sink == NULL) {
+    g_print ("Trying videosink '%s' ...", DEFAULT_VIDEOSINK);
+    sink = gst_element_factory_make (DEFAULT_VIDEOSINK, "sink");
+    g_print ("%s\n", (sink) ? "ok" : "element couldn't be created");
+  }
+  if (sink == NULL) {
+    g_print ("Trying videosink '%s' ...", "xvimagesink");
+    sink = gst_element_factory_make ("xvimagesink", "sink");
+    g_print ("%s\n", (sink) ? "ok" : "element couldn't be created");
+  }
+  if (sink == NULL) {
+    g_print ("Trying videosink '%s' ...", "ximagesink");
+    sink = gst_element_factory_make ("ximagesink", "sink");
+    g_print ("%s\n", (sink) ? "ok" : "element couldn't be created");
+  }
+
+  g_assert (sink != NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, filter1, crop, scale, filter2,
+      csp, sink, NULL);
+
+  if (!gst_element_link (src, filter1))
+    g_error ("Failed to link videotestsrc to capsfilter1");
+
+  if (!gst_element_link (filter1, crop))
+    g_error ("Failed to link capsfilter1 to videocrop");
+
+  if (!gst_element_link (crop, scale))
+    g_error ("Failed to link videocrop to videoscale");
+
+  if (!gst_element_link (scale, filter2))
+    g_error ("Failed to link videoscale to capsfilter2");
+
+  if (!gst_element_link (filter2, csp))
+    g_error ("Failed to link capsfilter2 to videoconvert");
+
+  if (!gst_element_link (csp, sink))
+    g_error ("Failed to link videoconvert to video sink");
+
+  caps_list = video_crop_get_test_caps (crop);
+  for (l = caps_list; l != NULL; l = l->next) {
+    GstStateChangeReturn ret;
+    GstCaps *caps, *out_caps;
+    gboolean skip = FALSE;
+    gchar *s;
+
+    if (filter_caps) {
+      GstCaps *icaps;
+
+      icaps = gst_caps_intersect (filter_caps, GST_CAPS (l->data));
+      skip = gst_caps_is_empty (icaps);
+      gst_caps_unref (icaps);
+    }
+
+    /* this is the size of our window (stays fixed) */
+    out_caps = gst_caps_copy (GST_CAPS (l->data));
+    gst_structure_set (gst_caps_get_structure (out_caps, 0), "width",
+        G_TYPE_INT, OUT_WIDTH, "height", G_TYPE_INT, OUT_HEIGHT, NULL);
+
+    g_object_set (filter2, "caps", out_caps, NULL);
+
+    /* filter1 gets these too to prevent videotestsrc from renegotiating */
+    g_object_set (filter1, "caps", out_caps, NULL);
+    gst_caps_unref (out_caps);
+
+    caps = gst_caps_copy (GST_CAPS (l->data));
+    GST_INFO ("testing format: %" GST_PTR_FORMAT, caps);
+
+    s = gst_caps_to_string (caps);
+
+    if (skip) {
+      g_print ("Skipping format: %s\n", s);
+      g_free (s);
+      continue;
+    }
+
+    g_print ("Format: %s\n", s);
+
+    caps = gst_caps_make_writable (caps);
+
+    /* FIXME: check return values */
+    ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
+    if (ret != GST_STATE_CHANGE_FAILURE) {
+      ret = gst_element_get_state (pipeline, NULL, NULL, -1);
+
+      if (ret != GST_STATE_CHANGE_FAILURE) {
+        test_with_caps (src, crop, caps);
+      } else {
+        g_print ("Format: %s not supported (failed to go to PLAYING)\n", s);
+      }
+    } else {
+      g_print ("Format: %s not supported\n", s);
+    }
+
+    gst_element_set_state (pipeline, GST_STATE_NULL);
+
+    gst_caps_unref (caps);
+    g_free (s);
+  }
+
+  g_list_foreach (caps_list, (GFunc) gst_caps_unref, NULL);
+  g_list_free (caps_list);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+
+  return 0;
+}
diff --git a/tests/icles/videocrop2-test.c b/tests/icles/videocrop2-test.c
new file mode 100644
index 0000000..2c6801f
--- /dev/null
+++ b/tests/icles/videocrop2-test.c
@@ -0,0 +1,141 @@
+/* GStreamer interactive videocrop test
+ *
+ * Copyright (C) 2008 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include <gst/gst.h>
+
+static GstElement *
+make_pipeline (gint type)
+{
+  GstElement *result;
+  gchar *pstr;
+
+  switch (type) {
+    case 0:
+      pstr = g_strdup_printf ("videotestsrc ! videocrop name=crop ! "
+          "xvimagesink");
+      break;
+    default:
+      return NULL;
+  }
+
+  result = gst_parse_launch_full (pstr, NULL, GST_PARSE_FLAG_NONE, NULL);
+  g_print ("created test %d: \"%s\"\n", type, pstr);
+  g_free (pstr);
+
+  return result;
+}
+
+#define MAX_ROUND 500
+
+int
+main (int argc, char **argv)
+{
+  GstElement *pipe, *crop;
+  gint left, right;
+  gint top, bottom;
+  gint ldir, rdir;
+  gint tdir, bdir;
+  gint round, type, stop;
+
+  gst_init (&argc, &argv);
+
+  type = 0;
+  stop = -1;
+
+  if (argc > 1) {
+    type = atoi (argv[1]);
+    stop = type + 1;
+  }
+
+  while (TRUE) {
+    GstMessage *message;
+
+    pipe = make_pipeline (type);
+    if (pipe == NULL)
+      break;
+
+    crop = gst_bin_get_by_name (GST_BIN (pipe), "crop");
+    g_assert (crop);
+
+    top = bottom = left = right = 0;
+    tdir = bdir = 10;
+    ldir = rdir = 10;
+
+    for (round = 0; round < MAX_ROUND; round++) {
+      g_print ("crop to %4d %4d %4d %4d (%d/%d)   \r", top, bottom, left, right,
+          round, MAX_ROUND);
+
+      g_object_set (crop, "top", top, "bottom", bottom, "left", left, "right",
+          right, NULL);
+
+      if (round == 0)
+        gst_element_set_state (pipe, GST_STATE_PLAYING);
+
+      top += tdir;
+      if (top >= 80)
+        tdir = -10;
+      else if (top < 10)
+        tdir = 10;
+
+      bottom += bdir;
+      if (bottom >= 60)
+        bdir = -10;
+      else if (bottom < 10)
+        bdir = 10;
+
+      left += ldir;
+      if (left >= 100)
+        ldir = -10;
+      else if (left < 10)
+        ldir = 10;
+
+      right += rdir;
+      if (right >= 80)
+        rdir = -10;
+      else if (right < 10)
+        rdir = 10;
+
+      message =
+          gst_bus_poll (GST_ELEMENT_BUS (pipe), GST_MESSAGE_ERROR,
+          50 * GST_MSECOND);
+      if (message) {
+        g_print ("got error           \n");
+
+        gst_message_unref (message);
+      }
+    }
+    g_print ("test %d done                    \n", type);
+
+    gst_object_unref (crop);
+    gst_element_set_state (pipe, GST_STATE_NULL);
+    gst_object_unref (pipe);
+
+    type++;
+    if (type == stop)
+      break;
+  }
+  return 0;
+}
diff --git a/tests/icles/ximagesrc-test.c b/tests/icles/ximagesrc-test.c
new file mode 100644
index 0000000..fdcc580
--- /dev/null
+++ b/tests/icles/ximagesrc-test.c
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) <2006> Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+static GMainLoop *loop;
+
+static gboolean
+terminate_playback (GstElement * pipeline)
+{
+  g_print ("Terminating playback\n");
+  g_main_loop_quit (loop);
+  return FALSE;
+}
+
+int
+main (int argc, char **argv)
+{
+  GstElement *pipeline;
+  GstState state;
+  GError *error = NULL;
+
+  gst_init (&argc, &argv);
+
+  pipeline = gst_parse_launch ("ximagesrc ! fakesink", &error);
+  if (error) {
+    g_print ("Error while parsing pipeline description: %s\n", error->message);
+    return -1;
+  }
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  /* lets check it gets to PLAYING */
+  if (gst_element_get_state (pipeline, &state, NULL,
+          GST_CLOCK_TIME_NONE) == GST_STATE_CHANGE_FAILURE ||
+      state != GST_STATE_PLAYING) {
+    g_warning ("State change to playing failed");
+  }
+
+  /* We want to get out after 5 seconds */
+  g_timeout_add_seconds (5, (GSourceFunc) terminate_playback, pipeline);
+
+  g_main_loop_run (loop);
+
+  g_main_loop_unref (loop);
+
+  return 0;
+}
diff --git a/tests/meson.build b/tests/meson.build
new file mode 100644
index 0000000..f7f0e5b
--- /dev/null
+++ b/tests/meson.build
@@ -0,0 +1,7 @@
+# FIXME: make check work on windows
+if host_machine.system() != 'windows'
+subdir('check')
+endif
+
+subdir('icles')
+subdir('examples')